-- cgit v1.2.3 From 31e31b8a248ffa216223dad49f75efbdfca5df23 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Feb 2003 22:55:36 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r2, which included commits to RCS files with non-trunk default branches. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3 c046a42c-6fe2-441c-8c8c-71466251a162 --- COPYING.LIB | 504 +++++++++++++++++ Makefile | 37 ++ TODO | 2 + elf.h | 425 ++++++++++++++ i386.ld | 130 +++++ linux-user/elfload.c | 973 ++++++++++++++++++++++++++++++++ linux-user/ioctls.h | 282 +++++++++ linux-user/main.c | 310 ++++++++++ linux-user/qemu.h | 57 ++ linux-user/signal.c | 105 ++++ linux-user/syscall.c | 1349 ++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 283 ++++++++++ linux-user/syscall_types.h | 64 +++ syscall-i386.h | 760 +++++++++++++++++++++++++ thunk.c | 315 +++++++++++ thunk.h | 195 +++++++ 16 files changed, 5791 insertions(+) create mode 100644 COPYING.LIB create mode 100644 Makefile create mode 100644 TODO create mode 100644 elf.h create mode 100644 i386.ld create mode 100644 linux-user/elfload.c create mode 100644 linux-user/ioctls.h create mode 100644 linux-user/main.c create mode 100644 linux-user/qemu.h create mode 100644 linux-user/signal.c create mode 100644 linux-user/syscall.c create mode 100644 linux-user/syscall_defs.h create mode 100644 linux-user/syscall_types.h create mode 100644 syscall-i386.h create mode 100644 thunk.c create mode 100644 thunk.h diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 000000000..8d4919ee9 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,504 @@ +------------------------------------------------------------------------------ +NOTE: +Some code of the Twin package was modified for DOSEMU by the DOSEMU-team. +The original is 'Copyright 1997 Willows Software, Inc.' and generously +was put under the GNU Library General Public License. +( for more information see http://www.willows.com/ ) + +We make use of section 3 of the GNU Library General Public License +('...opt to apply the terms of the ordinary GNU General Public License...'), +because the resulting product is an integrated part of DOSEMU and +can not be considered to be a 'library' in the terms of Library License. + +Therefore, the below GNU LIBRARY GENERAL PUBLIC LICENSE applies only to the +_unchanged_ Twin package from Willows. For the DOSEMU-changed parts the normal +GNU GENERAL PUBLIC LICENSE applies. This GPL (file COPYING) can be found in +the root directory of the DOSEMU distribution. + +The act of transformation to GPL was indicated to the maintainer of the Twin +package (Rob Penrose ) and he acknowledge agreement. + +Nov. 1 1997, The DOSEMU team. + +------------------------------------------------------------------------------ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + 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 compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +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) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +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 to +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 Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +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 + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +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. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..4e5689a64 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +CFLAGS=-Wall -O2 -g +LDFLAGS=-g +DEFINES=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS + +OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ + i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ + i386/dis8086.o i386/emu-ldt.o +OBJS+= elfload.o main.o thunk.o syscall.o + +SRCS = $(OBJS:.o=.c) + +all: gemu + +gemu: $(OBJS) + $(CC) -Wl,-T,i386.ld $(LDFLAGS) -o $@ $(OBJS) + +depend: $(SRCS) + $(CC) -MM $(CFLAGS) $^ 1>.depend + +%.o: %.c + $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + +clean: + rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS + +hello: hello.c + $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< + +test1: test1.c + $(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $< + +test2: test2.c + $(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $< + +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/TODO b/TODO new file mode 100644 index 000000000..045f877f4 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +- swap all elf paramters +- fix printf for doubles (fp87.c bug ?) diff --git a/elf.h b/elf.h new file mode 100644 index 000000000..f9108c536 --- /dev/null +++ b/elf.h @@ -0,0 +1,425 @@ +/* + * ELF register definitions.. + */ + +#include + +typedef uint32_t elf_greg_t; + +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_i387_struct elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB; +#define ELF_ARCH EM_386 + + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts %edx contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ +#define ELF_PLAT_INIT(_r) _r->edx = 0 + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 5 +#define ET_HIPROC 6 + +/* These constants define the various ELF target machines */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_486 6 /* Perhaps disused */ +#define EM_860 7 + +#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ + +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ + +#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */ + +#define EM_PARISC 15 /* HPPA */ + +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ + +#define EM_PPC 20 /* PowerPC */ + +/* + * This is an interim value that we will use until the committee comes + * up with a final number. + */ +#define EM_ALPHA 0x9026 + + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) + +/* Symbolic values for the entries in the auxiliary table + put on the initial stack */ +#define AT_NULL 0 /* end of vector */ +#define AT_IGNORE 1 /* entry should be ignored */ +#define AT_EXECFD 2 /* file descriptor of program */ +#define AT_PHDR 3 /* program headers for program */ +#define AT_PHENT 4 /* size of program header entry */ +#define AT_PHNUM 5 /* number of program headers */ +#define AT_PAGESZ 6 /* system page size */ +#define AT_BASE 7 /* base address of interpreter */ +#define AT_FLAGS 8 /* flags */ +#define AT_ENTRY 9 /* entry point of program */ +#define AT_NOTELF 10 /* program is not ELF */ +#define AT_UID 11 /* real uid */ +#define AT_EUID 12 /* effective uid */ +#define AT_GID 13 /* real gid */ +#define AT_EGID 14 /* effective gid */ + + +typedef struct dynamic{ + Elf32_Sword d_tag; + union{ + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + unsigned long long d_tag; /* entry tag value */ + union { + unsigned long long d_val; + unsigned long long d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xff) + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +typedef struct elf32_rel { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel { + unsigned long long r_offset; /* Location at which to apply the action */ + unsigned long long r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela { + unsigned long long r_offset; /* Location at which to apply the action */ + unsigned long long r_info; /* index and type of relocation */ + unsigned long long r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym { + unsigned int st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + unsigned short st_shndx; /* Associated section index */ + unsigned long long st_value; /* Value of the symbol */ + unsigned long long st_size; /* Associated symbol size */ +} Elf64_Sym; + + +#define EI_NIDENT 16 + +typedef struct elf32_hdr{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr { + unsigned char e_ident[16]; /* ELF "magic number" */ + short int e_type; + short unsigned int e_machine; + int e_version; + unsigned long long e_entry; /* Entry point virtual address */ + unsigned long long e_phoff; /* Program header table file offset */ + unsigned long long e_shoff; /* Section header table file offset */ + int e_flags; + short int e_ehsize; + short int e_phentsize; + short int e_phnum; + short int e_shentsize; + short int e_shnum; + short int e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr { + int p_type; + int p_flags; + unsigned long long p_offset; /* Segment file offset */ + unsigned long long p_vaddr; /* Segment virtual address */ + unsigned long long p_paddr; /* Segment physical address */ + unsigned long long p_filesz; /* Segment size in file */ + unsigned long long p_memsz; /* Segment size in memory */ + unsigned long long p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr { + unsigned int sh_name; /* Section name, index in string tbl */ + unsigned int sh_type; /* Type of section */ + unsigned long long sh_flags; /* Miscellaneous section attributes */ + unsigned long long sh_addr; /* Section virtual addr at execution */ + unsigned long long sh_offset; /* Section file offset */ + unsigned long long sh_size; /* Size of section in bytes */ + unsigned int sh_link; /* Index of another section */ + unsigned int sh_info; /* Additional section information */ + unsigned long long sh_addralign; /* Section alignment */ + unsigned long long sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +/* Notes used in ET_CORE */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note { + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +/* + * For now we use the 32 bit version of the structure until we figure + * out whether we need anything better. Note - on the Alpha, "unsigned int" + * is only 32 bits. + */ +typedef struct elf64_note { + unsigned int n_namesz; /* Name size */ + unsigned int n_descsz; /* Content size */ + unsigned int n_type; /* Content type */ +} Elf64_Nhdr; + +#define ELF_START_MMAP 0x80000000 + +#if ELF_CLASS == ELFCLASS32 + +extern Elf32_Dyn _DYNAMIC []; +#define elfhdr elf32_hdr +#define elf_phdr elf32_phdr +#define elf_note elf32_note + +#else + +extern Elf64_Dyn _DYNAMIC []; +#define elfhdr elf64_hdr +#define elf_phdr elf64_phdr +#define elf_note elf64_note + +#endif + + diff --git a/i386.ld b/i386.ld new file mode 100644 index 000000000..a64ec2f87 --- /dev/null +++ b/i386.ld @@ -0,0 +1,130 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 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 . */ +} diff --git a/linux-user/elfload.c b/linux-user/elfload.c new file mode 100644 index 000000000..0ee4f1365 --- /dev/null +++ b/linux-user/elfload.c @@ -0,0 +1,973 @@ +/* This is the Linux kernel elf-loading code, ported into user space */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gemu.h" + +#include "linux_bin.h" +#include "elf.h" +#include "segment.h" + +/* Necessary parameters */ +#define ALPHA_PAGE_SIZE 4096 +#define X86_PAGE_SIZE 4096 + +#define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1)) +#define X86_PAGE_MASK (~(X86_PAGE_SIZE-1)) + +#define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK) +#define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK) + +#define NGROUPS 32 + +#define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE +#define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1)) +#define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1)) + +#define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1)) +#define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1)) + +#define INTERPRETER_NONE 0 +#define INTERPRETER_AOUT 1 +#define INTERPRETER_ELF 2 + +#define DLINFO_ITEMS 12 + +/* Where we find X86 libraries... */ +//#define X86_DEFAULT_LIB_DIR "/usr/x86/" +#define X86_DEFAULT_LIB_DIR "/" + +//extern void * mmap4k(); +#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) + +extern unsigned long x86_stack_size; + +static int load_aout_interp(void * exptr, int interp_fd); + +#ifdef BSWAP_NEEDED +static void bswap_ehdr(Elf32_Ehdr *ehdr) +{ + bswap16s(&ehdr->e_type); /* Object file type */ + bswap16s(&ehdr->e_machine); /* Architecture */ + bswap32s(&ehdr->e_version); /* Object file version */ + bswap32s(&ehdr->e_entry); /* Entry point virtual address */ + bswap32s(&ehdr->e_phoff); /* Program header table file offset */ + bswap32s(&ehdr->e_shoff); /* Section header table file offset */ + bswap32s(&ehdr->e_flags); /* Processor-specific flags */ + bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ + bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ +} + +static void bswap_phdr(Elf32_Phdr *phdr) +{ + bswap32s(&phdr->p_type); /* Segment type */ + bswap32s(&phdr->p_offset); /* Segment file offset */ + bswap32s(&phdr->p_vaddr); /* Segment virtual address */ + bswap32s(&phdr->p_paddr); /* Segment physical address */ + bswap32s(&phdr->p_filesz); /* Segment size in file */ + bswap32s(&phdr->p_memsz); /* Segment size in memory */ + bswap32s(&phdr->p_flags); /* Segment flags */ + bswap32s(&phdr->p_align); /* Segment alignment */ +} +#endif + +static void * get_free_page(void) +{ + void * retval; + + /* User-space version of kernel get_free_page. Returns a page-aligned + * page-sized chunk of memory. + */ + retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + + if((long)retval == -1) { + perror("get_free_page"); + exit(-1); + } + else { + return(retval); + } +} + +static void free_page(void * pageaddr) +{ + (void)munmap(pageaddr, ALPHA_PAGE_SIZE); +} + +/* + * 'copy_string()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + * + */ +static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p) +{ + char *tmp, *tmp1, *pag = NULL; + int len, offset = 0; + + if (!p) { + return 0; /* bullet-proofing */ + } + while (argc-- > 0) { + if (!(tmp1 = tmp = get_user(argv+argc))) { + fprintf(stderr, "VFS: argc is wrong"); + exit(-1); + } + while (get_user(tmp++)); + len = tmp - tmp1; + if (p < len) { /* this shouldn't happen - 128kB */ + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % X86_PAGE_SIZE; + if (!(pag = (char *) page[p/X86_PAGE_SIZE]) && + !(pag = (char *) page[p/X86_PAGE_SIZE] = + (unsigned long *) get_free_page())) { + return 0; + } + } + if (len == 0 || offset == 0) { + *(pag + offset) = get_user(tmp); + } + else { + int bytes_to_copy = (len > offset) ? offset : len; + tmp -= bytes_to_copy; + p -= bytes_to_copy; + offset -= bytes_to_copy; + len -= bytes_to_copy; + memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); + } + } + } + return p; +} + +static int in_group_p(gid_t g) +{ + /* return TRUE if we're in the specified group, FALSE otherwise */ + int ngroup; + int i; + gid_t grouplist[NGROUPS]; + + ngroup = getgroups(NGROUPS, grouplist); + for(i = 0; i < ngroup; i++) { + if(grouplist[i] == g) { + return 1; + } + } + return 0; +} + +static int count(char ** vec) +{ + int i; + + for(i = 0; *vec; i++) { + vec++; + } + + return(i); +} + +static int prepare_binprm(struct linux_binprm *bprm) +{ + struct stat st; + int mode; + int retval, id_change; + + if(fstat(bprm->fd, &st) < 0) { + return(-errno); + } + + mode = st.st_mode; + if(!S_ISREG(mode)) { /* Must be regular file */ + return(-EACCES); + } + if(!(mode & 0111)) { /* Must have at least one execute bit set */ + return(-EACCES); + } + + bprm->e_uid = geteuid(); + bprm->e_gid = getegid(); + id_change = 0; + + /* Set-uid? */ + if(mode & S_ISUID) { + bprm->e_uid = st.st_uid; + if(bprm->e_uid != geteuid()) { + id_change = 1; + } + } + + /* Set-gid? */ + /* + * If setgid is set but no group execute bit then this + * is a candidate for mandatory locking, not a setgid + * executable. + */ + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { + bprm->e_gid = st.st_gid; + if (!in_group_p(bprm->e_gid)) { + id_change = 1; + } + } + + memset(bprm->buf, 0, sizeof(bprm->buf)); + retval = lseek(bprm->fd, 0L, SEEK_SET); + if(retval >= 0) { + retval = read(bprm->fd, bprm->buf, 128); + } + if(retval < 0) { + perror("prepare_binprm"); + exit(-1); + /* return(-errno); */ + } + else { + return(retval); + } +} + +unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, + struct image_info * info) +{ + unsigned long stack_base; + int i; + extern unsigned long stktop; + + stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE; + + p += stack_base; + if (bprm->loader) { + bprm->loader += stack_base; + } + bprm->exec += stack_base; + + /* Create enough stack to hold everything. If we don't use + * it for args, we'll use it for something else... + */ + if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) { + if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { + perror("stk mmap"); + exit(-1); + } + } + else { + if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { + perror("stk mmap"); + exit(-1); + } + } + + stktop = stack_base; + + for (i = 0 ; i < MAX_ARG_PAGES ; i++) { + if (bprm->page[i]) { + info->rss++; + + memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE); + free_page((void *)bprm->page[i]); + } + stack_base += X86_PAGE_SIZE; + } + return p; +} + +static void set_brk(unsigned long start, unsigned long end) +{ + /* page-align the start and end addresses... */ + start = ALPHA_PAGE_ALIGN(start); + end = ALPHA_PAGE_ALIGN(end); + if (end <= start) + return; + if((long)mmap4k(start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { + perror("cannot mmap brk"); + exit(-1); + } +} + + +/* We need to explicitly zero any fractional pages + after the data section (i.e. bss). This would + contain the junk from the file that should not + be in memory */ + + +static void padzero(unsigned long elf_bss) +{ + unsigned long nbyte; + char * fpnt; + + nbyte = elf_bss & (ALPHA_PAGE_SIZE-1); /* was X86_PAGE_SIZE - JRP */ + if (nbyte) { + nbyte = ALPHA_PAGE_SIZE - nbyte; + fpnt = (char *) elf_bss; + do { + *fpnt++ = 0; + } while (--nbyte); + } +} + +static unsigned int * create_elf_tables(char *p, int argc, int envc, + struct elfhdr * exec, + unsigned long load_addr, + unsigned long interp_load_addr, int ibcs, + struct image_info *info) +{ + unsigned int *argv, *envp, *dlinfo; + unsigned int *sp; + char **alpha_envp; + + /* + * Force 16 byte alignment here for generality. + */ + sp = (unsigned int *) (~15UL & (unsigned long) p); + sp -= exec ? DLINFO_ITEMS*2 : 2; + dlinfo = sp; + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + if (!ibcs) { + put_user(envp,--sp); + put_user(argv,--sp); + } + alpha_envp = (char **)malloc((envc+1) * sizeof(char *)); + +#define NEW_AUX_ENT(id, val) \ + put_user ((id), dlinfo++); \ + put_user ((val), dlinfo++) + + if (exec) { /* Put this here for an ELF program interpreter */ + struct elf_phdr * eppnt; + eppnt = (struct elf_phdr *)((unsigned long)exec->e_phoff); + + NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff)); + NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr))); + NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum)); + NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE)); + NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr)); + NEW_AUX_ENT (AT_FLAGS, (unsigned int)0); + NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry); + NEW_AUX_ENT (AT_UID, (unsigned int) getuid()); + NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid()); + NEW_AUX_ENT (AT_GID, (unsigned int) getgid()); + NEW_AUX_ENT (AT_EGID, (unsigned int) getegid()); + } + NEW_AUX_ENT (AT_NULL, 0); +#undef NEW_AUX_ENT + put_user((unsigned int)argc,--sp); + info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); + while (argc-->0) { + put_user(p,argv++); + while (get_user(p++)) /* nothing */ ; + } + put_user(0,argv); + info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); + __environ = alpha_envp; + while (envc-->0) { + *alpha_envp++ = (char *)p; + put_user(p,envp++); + while (get_user(p++)) /* nothing */ ; + } + put_user(0,envp); + *alpha_envp = 0; + info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); + return sp; +} + + + +static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, + int interpreter_fd, + unsigned long *interp_load_addr) +{ + struct elf_phdr *elf_phdata = NULL; + struct elf_phdr *eppnt; + unsigned long load_addr; + int load_addr_set = 0; + int retval; + unsigned long last_bss, elf_bss; + unsigned long error; + int i; + + elf_bss = 0; + last_bss = 0; + error = 0; + + /* We put this here so that mmap will search for the *first* + * available memory... + */ + load_addr = INTERP_LOADADDR; + + /* First of all, some simple consistency checks */ + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine)) { + return ~0UL; + } + + /* Now read in all of the header information */ + + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE) + return ~0UL; + + elf_phdata = (struct elf_phdr *) + malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + + if (!elf_phdata) + return ~0UL; + + /* + * If the size of this structure has changed, then punt, since + * we will be doing the wrong thing. + */ + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) + { + free(elf_phdata); + return ~0UL; + } + + retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); + if(retval >= 0) { + retval = read(interpreter_fd, + (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + } + + if (retval < 0) { + perror("load_elf_interp"); + exit(-1); + free (elf_phdata); + return retval; + } +#ifdef BSWAP_NEEDED + eppnt = elf_phdata; + for (i=0; ie_phnum; i++, eppnt++) { + bswap_phdr(eppnt); + } +#endif + eppnt = elf_phdata; + for(i=0; ie_phnum; i++, eppnt++) + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + unsigned long vaddr = 0; + unsigned long k; + + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { + elf_type |= MAP_FIXED; + vaddr = eppnt->p_vaddr; + } + error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr), + eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr), + elf_prot, + elf_type, + interpreter_fd, + eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr)); + + if (error > -1024UL) { + /* Real error */ + close(interpreter_fd); + free(elf_phdata); + return ~0UL; + } + + if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { + load_addr = error; + load_addr_set = 1; + } + + /* + * Find the end of the file mapping for this phdr, and keep + * track of the largest address we see for this. + */ + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) elf_bss = k; + + /* + * Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) last_bss = k; + } + + /* Now use mmap to map the library into memory. */ + + close(interpreter_fd); + + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zeromapped pages up to and including the last + * bss page. + */ + padzero(elf_bss); + elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > elf_bss) { + mmap4k(elf_bss, last_bss-elf_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + } + free(elf_phdata); + + *interp_load_addr = load_addr; + return ((unsigned long) interp_elf_ex->e_entry) + load_addr; +} + + + +static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs, + struct image_info * info) +{ + struct elfhdr elf_ex; + struct elfhdr interp_elf_ex; + struct exec interp_ex; + int interpreter_fd = -1; /* avoid warning */ + unsigned long load_addr; + int load_addr_set = 0; + unsigned int interpreter_type = INTERPRETER_NONE; + unsigned char ibcs2_interpreter; + int i; + void * mapped_addr; + struct elf_phdr * elf_ppnt; + struct elf_phdr *elf_phdata; + unsigned long elf_bss, k, elf_brk; + int retval; + char * elf_interpreter; + unsigned long elf_entry, interp_load_addr = 0; + int status; + unsigned long start_code, end_code, end_data; + unsigned long elf_stack; + char passed_fileno[6]; + + ibcs2_interpreter = 0; + status = 0; + load_addr = 0; + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ +#ifdef BSWAP_NEEDED + bswap_ehdr(&elf_ex); +#endif + + if (elf_ex.e_ident[0] != 0x7f || + strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { + return -ENOEXEC; + } + + + /* First of all, some simple consistency checks */ + if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || + (! elf_check_arch(elf_ex.e_machine))) { + return -ENOEXEC; + } + + /* Now read in all of the header information */ + + elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); + if (elf_phdata == NULL) { + return -ENOMEM; + } + + retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); + if(retval > 0) { + retval = read(bprm->fd, (char *) elf_phdata, + elf_ex.e_phentsize * elf_ex.e_phnum); + } + + if (retval < 0) { + perror("load_elf_binary"); + exit(-1); + free (elf_phdata); + return -errno; + } + + elf_ppnt = elf_phdata; + + elf_bss = 0; + elf_brk = 0; + + + elf_stack = ~0UL; + elf_interpreter = NULL; + start_code = ~0UL; + end_code = 0; + end_data = 0; + + for(i=0;i < elf_ex.e_phnum; i++) { + if (elf_ppnt->p_type == PT_INTERP) { + if ( elf_interpreter != NULL ) + { + free (elf_phdata); + free(elf_interpreter); + close(bprm->fd); + return -EINVAL; + } + + /* This is the program interpreter used for + * shared libraries - for now assume that this + * is an a.out format binary + */ + + elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+strlen(X86_DEFAULT_LIB_DIR)); + + if (elf_interpreter == NULL) { + free (elf_phdata); + close(bprm->fd); + return -ENOMEM; + } + + strcpy(elf_interpreter, X86_DEFAULT_LIB_DIR); + retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); + if(retval >= 0) { + retval = read(bprm->fd, + elf_interpreter+strlen(X86_DEFAULT_LIB_DIR), + elf_ppnt->p_filesz); + } + if(retval < 0) { + perror("load_elf_binary2"); + exit(-1); + } + + /* If the program interpreter is one of these two, + then assume an iBCS2 image. Otherwise assume + a native linux image. */ + + /* JRP - Need to add X86 lib dir stuff here... */ + + if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || + strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { + ibcs2_interpreter = 1; + } + +#if 0 + printf("Using ELF interpreter %s\n", elf_interpreter); +#endif + if (retval >= 0) { + retval = open(elf_interpreter, O_RDONLY); + if(retval >= 0) { + interpreter_fd = retval; + } + else { + perror(elf_interpreter); + exit(-1); + /* retval = -errno; */ + } + } + + if (retval >= 0) { + retval = lseek(interpreter_fd, 0, SEEK_SET); + if(retval >= 0) { + retval = read(interpreter_fd,bprm->buf,128); + } + } + if (retval >= 0) { + interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ + interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ + } + if (retval < 0) { + perror("load_elf_binary3"); + exit(-1); + free (elf_phdata); + free(elf_interpreter); + close(bprm->fd); + return retval; + } + } + elf_ppnt++; + } + + /* Some simple consistency checks for the interpreter */ + if (elf_interpreter){ + interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; + + /* Now figure out which format our binary is */ + if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && + (N_MAGIC(interp_ex) != QMAGIC)) { + interpreter_type = INTERPRETER_ELF; + } + + if (interp_elf_ex.e_ident[0] != 0x7f || + strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { + interpreter_type &= ~INTERPRETER_ELF; + } + + if (!interpreter_type) { + free(elf_interpreter); + free(elf_phdata); + close(bprm->fd); + return -ELIBBAD; + } + } + + /* OK, we are done with that, now set up the arg stuff, + and then start this sucker up */ + + if (!bprm->sh_bang) { + char * passed_p; + + if (interpreter_type == INTERPRETER_AOUT) { + sprintf(passed_fileno, "%d", bprm->fd); + passed_p = passed_fileno; + + if (elf_interpreter) { + bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p); + bprm->argc++; + } + } + if (!bprm->p) { + if (elf_interpreter) { + free(elf_interpreter); + } + free (elf_phdata); + close(bprm->fd); + return -E2BIG; + } + } + + /* OK, This is the point of no return */ + info->end_data = 0; + info->end_code = 0; + info->start_mmap = (unsigned long)ELF_START_MMAP; + info->mmap = 0; + elf_entry = (unsigned long) elf_ex.e_entry; + + /* Do this so that we can load the interpreter, if need be. We will + change some of these later */ + info->rss = 0; + bprm->p = setup_arg_pages(bprm->p, bprm, info); + info->start_stack = bprm->p; + + /* Now we do a little grungy work by mmaping the ELF image into + * the correct location in memory. At this point, we assume that + * the image should be loaded at fixed address, not at a variable + * address. + */ + + + + for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + if (elf_ppnt->p_type == PT_LOAD) { + int elf_prot = 0; + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; + if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + + mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), + bprm->fd, + (elf_ppnt->p_offset - + X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + + if((unsigned long)mapped_addr == 0xffffffffffffffff) { + perror("mmap"); + exit(-1); + } + + + +#ifdef LOW_ELF_STACK + if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); +#endif + + if (!load_addr_set) { + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; + load_addr_set = 1; + } + k = elf_ppnt->p_vaddr; + if (k < start_code) start_code = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + if (k > elf_bss) elf_bss = k; +#if 1 + if ((elf_ppnt->p_flags & PF_X) && end_code < k) +#else + if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) +#endif + end_code = k; + if (end_data < k) end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + if (k > elf_brk) elf_brk = k; + } + } + + if (elf_interpreter) { + if (interpreter_type & 1) { + elf_entry = load_aout_interp(&interp_ex, interpreter_fd); + } + else if (interpreter_type & 2) { + elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, + &interp_load_addr); + } + + close(interpreter_fd); + free(elf_interpreter); + + if (elf_entry == ~0UL) { + printf("Unable to load interpreter\n"); + free(elf_phdata); + exit(-1); + return 0; + } + } + + free(elf_phdata); + + if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); + info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); + +#ifdef LOW_ELF_STACK + info->start_stack = bprm->p = elf_stack - 4; +#endif + bprm->p = (unsigned long) + create_elf_tables((char *)bprm->p, + bprm->argc, + bprm->envc, + (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), + load_addr, + interp_load_addr, + (interpreter_type == INTERPRETER_AOUT ? 0 : 1), + info); + if (interpreter_type == INTERPRETER_AOUT) + info->arg_start += strlen(passed_fileno) + 1; + info->start_brk = info->brk = elf_brk; + info->end_code = end_code; + info->start_code = start_code; + info->end_data = end_data; + info->start_stack = bprm->p; + + /* Calling set_brk effectively mmaps the pages that we need for the bss and break + sections */ + set_brk(elf_bss, elf_brk); + + padzero(elf_bss); + +#if 0 + printf("(start_brk) %x\n" , info->start_brk); + printf("(end_code) %x\n" , info->end_code); + printf("(start_code) %x\n" , info->start_code); + printf("(end_data) %x\n" , info->end_data); + printf("(start_stack) %x\n" , info->start_stack); + printf("(brk) %x\n" , info->brk); +#endif + + if ( info->personality == PER_SVR4 ) + { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. + Since we do not have the power to recompile these, we + emulate the SVr4 behavior. Sigh. */ + mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, -1, 0); + } + +#ifdef ELF_PLAT_INIT + /* + * The ABI may specify that certain registers be set up in special + * ways (on i386 %edx is the address of a DT_FINI function, for + * example. This macro performs whatever initialization to + * the regs structure is required. + */ + ELF_PLAT_INIT(regs); +#endif + + + info->entry = elf_entry; + + return 0; +} + + + +int elf_exec(const char * filename, char ** argv, char ** envp, + struct pt_regs * regs, struct image_info *infop) +{ + struct linux_binprm bprm; + int retval; + int i; + + bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); + for (i=0 ; i=0) { + bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p); + bprm.exec = bprm.p; + bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p); + bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p); + if (!bprm.p) { + retval = -E2BIG; + } + } + + if(retval>=0) { + retval = load_elf_binary(&bprm,regs,infop); + } + if(retval>=0) { + /* success. Initialize important registers */ + regs->esp = infop->start_stack; + regs->eip = infop->entry; + return retval; + } + + /* Something went wrong, return the inode and free the argument pages*/ + for (i=0 ; i +#include +#include +#include +#include +#include + +#include "gemu.h" + +#include "i386/hsw_interp.h" + +unsigned long x86_stack_size; +unsigned long stktop; + +void gemu_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +/* virtual x86 CPU stuff */ + +extern int invoke_code16(Interp_ENV *, int, int); +extern int invoke_code32(Interp_ENV *, int); +extern char *e_print_cpuemu_regs(ENVPARAMS, int is32); +extern char *e_emu_disasm(ENVPARAMS, unsigned char *org, int is32); +extern void init_npu(void); + +Interp_ENV env_global; +Interp_ENV *envp_global; + +QWORD EMUtime = 0; + +int CEmuStat = 0; + +long instr_count; + +/* who will initialize this? */ +unsigned long io_bitmap[IO_BITMAP_SIZE+1]; + +/* debug flag, 0=disable 1..9=level */ +int d_emu = 0; + +unsigned long CRs[5] = +{ + 0x00000013, /* valid bits: 0xe005003f */ + 0x00000000, /* invalid */ + 0x00000000, + 0x00000000, + 0x00000000 +}; + +/* + * DR0-3 = linear address of breakpoint 0-3 + * DR4=5 = reserved + * DR6 b0-b3 = BP active + * b13 = BD + * b14 = BS + * b15 = BT + * DR7 b0-b1 = G:L bp#0 + * b2-b3 = G:L bp#1 + * b4-b5 = G:L bp#2 + * b6-b7 = G:L bp#3 + * b8-b9 = GE:LE + * b13 = GD + * b16-19= LLRW bp#0 LL=00(1),01(2),11(4) + * b20-23= LLRW bp#1 RW=00(x),01(w),11(rw) + * b24-27= LLRW bp#2 + * b28-31= LLRW bp#3 + */ +unsigned long DRs[8] = +{ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xffff1ff0, + 0x00000400, + 0xffff1ff0, + 0x00000400 +}; + +unsigned long TRs[2] = +{ + 0x00000000, + 0x00000000 +}; + +void FatalAppExit(UINT wAction, LPCSTR lpText) +{ + fprintf(stderr, "Fatal error '%s' in CPU\n", lpText); + exit(1); +} + +int e_debug_check(unsigned char *PC) +{ + register unsigned long d7 = DRs[7]; + + if (d7&0x03) { + if (d7&0x30000) return 0; /* only execute(00) bkp */ + if ((long)PC==DRs[0]) { + e_printf("DBRK: DR0 hit at %p\n",PC); + DRs[6] |= 1; + return 1; + } + } + if (d7&0x0c) { + if (d7&0x300000) return 0; + if ((long)PC==DRs[1]) { + e_printf("DBRK: DR1 hit at %p\n",PC); + DRs[6] |= 2; + return 1; + } + } + if (d7&0x30) { + if (d7&0x3000000) return 0; + if ((long)PC==DRs[2]) { + e_printf("DBRK: DR2 hit at %p\n",PC); + DRs[6] |= 4; + return 1; + } + } + if (d7&0xc0) { + if (d7&0x30000000) return 0; + if ((long)PC==DRs[3]) { + e_printf("DBRK: DR3 hit at %p\n",PC); + DRs[6] |= 8; + return 1; + } + } + return 0; +} + +/* Debug stuff */ +void logstr(unsigned long mask, const char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +/* unconditional message into debug log and stderr */ +#undef error +void error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +int PortIO(DWORD port, DWORD value, UINT size, BOOL is_write) +{ + fprintf(stderr, "IO: %s port=0x%lx value=0x%lx size=%d", + is_write ? "write" : "read", port, value, size); + return value; +} + +void LogProcName(WORD wSel, WORD wOff, WORD wAction) +{ + +} + +void INT_handler(int num, void *env) +{ + fprintf(stderr, "EM86: int %d\n", num); +} + +/***********************************************************/ + +/* XXX: currently we use LDT entries */ +#define __USER_CS (0x23|4) +#define __USER_DS (0x2B|4) + +void usage(void) +{ + printf("gemu version 0.1, Copyright (c) 2003 Fabrice Bellard\n" + "usage: gemu program [arguments...]\n" + "Linux x86 emulator\n" + ); + exit(1); +} + +int main(int argc, char **argv) +{ + const char *filename; + struct pt_regs regs1, *regs = ®s1; + struct image_info info1, *info = &info1; + Interp_ENV *env; + + if (argc <= 1) + usage(); + + filename = argv[1]; + + /* Zero out regs */ + memset(regs, 0, sizeof(struct pt_regs)); + + /* Zero out image_info */ + memset(info, 0, sizeof(struct image_info)); + + if(elf_exec(filename, argv+1, __environ, regs, info) != 0) { + printf("Error loading %s\n", filename); + exit(1); + } + +#if 0 + printf("start_brk 0x%08lx\n" , info->start_brk); + printf("end_code 0x%08lx\n" , info->end_code); + printf("start_code 0x%08lx\n" , info->start_code); + printf("end_data 0x%08lx\n" , info->end_data); + printf("start_stack 0x%08lx\n" , info->start_stack); + printf("brk 0x%08lx\n" , info->brk); + printf("esp 0x%08lx\n" , regs->esp); + printf("eip 0x%08lx\n" , regs->eip); +#endif + + target_set_brk((char *)info->brk); + syscall_init(); + + env = &env_global; + envp_global = env; + memset(env, 0, sizeof(Interp_ENV)); + + env->rax.e = regs->eax; + env->rbx.e = regs->ebx; + env->rcx.e = regs->ecx; + env->rdx.e = regs->edx; + env->rsi.esi = regs->esi; + env->rdi.edi = regs->edi; + env->rbp.ebp = regs->ebp; + env->rsp.esp = regs->esp; + env->cs.cs = __USER_CS; + env->ds.ds = __USER_DS; + env->es.es = __USER_DS; + env->ss.ss = __USER_DS; + env->fs.fs = __USER_DS; + env->gs.gs = __USER_DS; + env->trans_addr = regs->eip; + + LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; + LDT[__USER_CS >> 3].dwSelLimit = 0xfffff; + LDT[__USER_CS >> 3].lpSelBase = NULL; + + LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; + LDT[__USER_DS >> 3].dwSelLimit = 0xfffff; + LDT[__USER_DS >> 3].lpSelBase = NULL; + init_npu(); + + for(;;) { + int err; + uint8_t *pc; + + err = invoke_code32(env, -1); + env->trans_addr = env->return_addr; + pc = env->seg_regs[0] + env->trans_addr; + switch(err) { + case EXCP0D_GPF: + if (pc[0] == 0xcd && pc[1] == 0x80) { + /* syscall */ + env->trans_addr += 2; + env->rax.e = do_syscall(env->rax.e, + env->rbx.e, + env->rcx.e, + env->rdx.e, + env->rsi.esi, + env->rdi.edi, + env->rbp.ebp); + } else { + goto trap_error; + } + break; + default: + trap_error: + fprintf(stderr, "GEMU: Unknown error %d, aborting\n", err); + d_emu = 9; + fprintf(stderr, "%s\n%s\n", + e_print_cpuemu_regs(env, 1), + e_emu_disasm(env,pc,1)); + abort(); + } + } + return 0; +} diff --git a/linux-user/qemu.h b/linux-user/qemu.h new file mode 100644 index 000000000..fa40d4d84 --- /dev/null +++ b/linux-user/qemu.h @@ -0,0 +1,57 @@ +#ifndef GEMU_H +#define GEMU_H + +#include "thunk.h" + +struct pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + int xds; + int xes; + long orig_eax; + long eip; + int xcs; + long eflags; + long esp; + int xss; +}; + +/* This struct is used to hold certain information about the image. + * Basically, it replicates in user space what would be certain + * task_struct fields in the kernel + */ +struct image_info { + unsigned long start_code; + unsigned long end_code; + unsigned long end_data; + unsigned long start_brk; + unsigned long brk; + unsigned long start_mmap; + unsigned long mmap; + unsigned long rss; + unsigned long start_stack; + unsigned long arg_start; + unsigned long arg_end; + unsigned long env_start; + unsigned long env_end; + unsigned long entry; + int personality; +}; + +int elf_exec(const char * filename, char ** argv, char ** envp, + struct pt_regs * regs, struct image_info *infop); + +void target_set_brk(char *new_brk); +void syscall_init(void); +long do_syscall(int num, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6); +void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); + + + +#endif diff --git a/linux-user/signal.c b/linux-user/signal.c new file mode 100644 index 000000000..2e0d59955 --- /dev/null +++ b/linux-user/signal.c @@ -0,0 +1,105 @@ +/* + * Emulation of Linux signal handling + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include + +/* Algorithm strongly inspired from em86 : we queue the signals so + that we can handle them at precise points in the emulated code. */ + +struct emulated_sigaction { + struct target_sigaction sa; + int nb_pending; + struct target_siginfo info; +}; + +struct emulated_sigaction sigact_table[NSIG]; +int signal_pending; + +static inline int host_to_target_signal(int sig) +{ + return sig; +} + +static inline int target_to_host_signal(int sig) +{ + return sig; +} + +void signal_init(void) +{ + struct sigaction act; + int i; + + /* set all host signal handlers */ + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = host_signal_handler; + for(i = 1; i < NSIG; i++) { + sigaction(i, &sa, NULL); + } + + memset(sigact_table, 0, sizeof(sigact_table)); +} + +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc) +{ + struct ucontext *uc = puc; + int signum; + /* get target signal number */ + signum = host_to_target(host_signum); + if (signum >= TARGET_NSIG) + return; + /* we save the old mask */ + + +} + + +void process_pending_signals(void) +{ + int signum; + target_ulong _sa_handler; + + struct emulated_sigaction *esig; + + if (!signal_pending) + return; + + esig = sigact_table; + for(signum = 1; signum < TARGET_NSIG; signum++) { + if (esig->nb_pending != 0) + goto handle_signal; + esig++; + } + /* if no signal is pending, just return */ + signal_pending = 0; + return; + handle_signal: + _sa_handler = esig->sa._sa_handler; + if (_sa_handler == TARGET_SIG_DFL) { + /* default handling + } + + +} diff --git a/linux-user/syscall.c b/linux-user/syscall.c new file mode 100644 index 000000000..d5909b221 --- /dev/null +++ b/linux-user/syscall.c @@ -0,0 +1,1349 @@ +/* + * Linux syscalls + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define termios host_termios +#define winsize host_winsize +#define termio host_termio + +#include +#include +#include +#include +#include +#include + +#include "gemu.h" + +#define DEBUG + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#define PAGE_MASK ~(PAGE_SIZE - 1) +#endif + +struct dirent { + long d_ino; + long d_off; + unsigned short d_reclen; + char d_name[256]; /* We must not include limits.h! */ +}; + +#include "syscall_defs.h" + +#ifdef TARGET_I386 +#include "syscall-i386.h" +#endif + +#define __NR_sys_uname __NR_uname +#define __NR_sys_getcwd __NR_getcwd +#define __NR_sys_statfs __NR_statfs +#define __NR_sys_fstatfs __NR_fstatfs + +_syscall0(int, gettid) +_syscall1(int,sys_uname,struct new_utsname *,buf) +_syscall2(int,sys_getcwd,char *,buf,size_t,size) +_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count); +_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, + loff_t *, res, uint, wh); +_syscall2(int,sys_statfs,const char *,path,struct statfs *,buf) +_syscall2(int,sys_fstatfs,int,fd,struct statfs *,buf) + +static inline long get_errno(long ret) +{ + if (ret == -1) + return -errno; + else + return ret; +} + +static inline int is_error(long ret) +{ + return (unsigned long)ret >= (unsigned long)(-4096); +} + +static char *target_brk; +static char *target_original_brk; + +void target_set_brk(char *new_brk) +{ + target_brk = new_brk; + target_original_brk = new_brk; +} + +static long do_brk(char *new_brk) +{ + char *brk_page; + long mapped_addr; + int new_alloc_size; + + if (!new_brk) + return (long)target_brk; + if (new_brk < target_original_brk) + return -ENOMEM; + + brk_page = (char *)(((unsigned long)target_brk + PAGE_SIZE - 1) & PAGE_MASK); + + /* If the new brk is less than this, set it and we're done... */ + if (new_brk < brk_page) { + target_brk = new_brk; + return (long)target_brk; + } + + /* We need to allocate more memory after the brk... */ + new_alloc_size = ((new_brk - brk_page + 1)+(PAGE_SIZE-1)) & PAGE_MASK; + mapped_addr = get_errno((long)mmap((caddr_t)brk_page, new_alloc_size, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); + + if (is_error(mapped_addr)) { + return mapped_addr; + } else { + target_brk = new_brk; + return (long)target_brk; + } +} + +static inline fd_set *target_to_host_fds(fd_set *fds, + target_long *target_fds, int n) +{ +#if !defined(BSWP_NEEDED) && !defined(WORD_BIGENDIAN) + return (fd_set *)target_fds; +#else + int i, b; + if (target_fds) { + FD_ZERO(fds); + for(i = 0;i < n; i++) { + b = (tswapl(target_fds[i / TARGET_LONG_BITS]) >> + (i & (TARGET_LONG_BITS - 1))) & 1; + if (b) + FD_SET(i, fds); + } + return fds; + } else { + return NULL; + } +#endif +} + +static inline void host_to_target_fds(target_long *target_fds, + fd_set *fds, int n) +{ +#if !defined(BSWP_NEEDED) && !defined(WORD_BIGENDIAN) + /* nothing to do */ +#else + int i, nw, j, k; + target_long v; + + if (target_fds) { + nw = n / TARGET_LONG_BITS; + k = 0; + for(i = 0;i < nw; i++) { + v = 0; + for(j = 0; j < TARGET_LONG_BITS; j++) { + v |= ((FD_ISSET(k, fds) != 0) << j); + k++; + } + target_fds[i] = tswapl(v); + } + } +#endif +} + +/* XXX: incorrect for some archs */ +static void host_to_target_old_sigset(target_ulong *old_sigset, + const sigset_t *sigset) +{ + *old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff); +} + +static void target_to_host_old_sigset(sigset_t *sigset, + const target_ulong *old_sigset) +{ + sigemptyset(sigset); + *(unsigned long *)sigset = tswapl(*old_sigset); +} + + +static long do_select(long n, + target_long *target_rfds, target_long *target_wfds, + target_long *target_efds, struct target_timeval *target_tv) +{ + fd_set rfds, wfds, efds; + fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; + struct timeval tv, *tv_ptr; + long ret; + + rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); + wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); + efds_ptr = target_to_host_fds(&efds, target_efds, n); + + if (target_tv) { + tv.tv_sec = tswapl(target_tv->tv_sec); + tv.tv_usec = tswapl(target_tv->tv_usec); + tv_ptr = &tv; + } else { + tv_ptr = NULL; + } + ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); + if (!is_error(ret)) { + host_to_target_fds(target_rfds, rfds_ptr, n); + host_to_target_fds(target_wfds, wfds_ptr, n); + host_to_target_fds(target_efds, efds_ptr, n); + + if (target_tv) { + target_tv->tv_sec = tswapl(tv.tv_sec); + target_tv->tv_usec = tswapl(tv.tv_usec); + } + } + return ret; +} + +static long do_socketcall(int num, long *vptr) +{ + long ret; + + switch(num) { + case SOCKOP_socket: + ret = get_errno(socket(vptr[0], vptr[1], vptr[2])); + break; + case SOCKOP_bind: + ret = get_errno(bind(vptr[0], (struct sockaddr *)vptr[1], vptr[2])); + break; + case SOCKOP_connect: + ret = get_errno(connect(vptr[0], (struct sockaddr *)vptr[1], vptr[2])); + break; + case SOCKOP_listen: + ret = get_errno(listen(vptr[0], vptr[1])); + break; + case SOCKOP_accept: + { + socklen_t size; + size = tswap32(*(int32_t *)vptr[2]); + ret = get_errno(accept(vptr[0], (struct sockaddr *)vptr[1], &size)); + if (!is_error(ret)) + *(int32_t *)vptr[2] = size; + } + break; + case SOCKOP_getsockname: + { + socklen_t size; + size = tswap32(*(int32_t *)vptr[2]); + ret = get_errno(getsockname(vptr[0], (struct sockaddr *)vptr[1], &size)); + if (!is_error(ret)) + *(int32_t *)vptr[2] = size; + } + break; + case SOCKOP_getpeername: + { + socklen_t size; + size = tswap32(*(int32_t *)vptr[2]); + ret = get_errno(getpeername(vptr[0], (struct sockaddr *)vptr[1], &size)); + if (!is_error(ret)) + *(int32_t *)vptr[2] = size; + } + break; + case SOCKOP_socketpair: + { + int tab[2]; + int32_t *target_tab = (int32_t *)vptr[3]; + ret = get_errno(socketpair(vptr[0], vptr[1], vptr[2], tab)); + if (!is_error(ret)) { + target_tab[0] = tswap32(tab[0]); + target_tab[1] = tswap32(tab[1]); + } + } + break; + case SOCKOP_send: + ret = get_errno(send(vptr[0], (void *)vptr[1], vptr[2], vptr[3])); + break; + case SOCKOP_recv: + ret = get_errno(recv(vptr[0], (void *)vptr[1], vptr[2], vptr[3])); + break; + case SOCKOP_sendto: + ret = get_errno(sendto(vptr[0], (void *)vptr[1], vptr[2], vptr[3], + (struct sockaddr *)vptr[4], vptr[5])); + break; + case SOCKOP_recvfrom: + { + socklen_t size; + size = tswap32(*(int32_t *)vptr[5]); + ret = get_errno(recvfrom(vptr[0], (void *)vptr[1], vptr[2], + vptr[3], (struct sockaddr *)vptr[4], &size)); + if (!is_error(ret)) + *(int32_t *)vptr[5] = size; + } + break; + case SOCKOP_shutdown: + ret = get_errno(shutdown(vptr[0], vptr[1])); + break; + case SOCKOP_sendmsg: + case SOCKOP_recvmsg: + case SOCKOP_setsockopt: + case SOCKOP_getsockopt: + default: + gemu_log("Unsupported socketcall: %d\n", num); + ret = -ENOSYS; + break; + } + return ret; +} + +/* kernel structure types definitions */ +#define IFNAMSIZ 16 + +#define STRUCT(name, list...) STRUCT_ ## name, +#define STRUCT_SPECIAL(name) STRUCT_ ## name, +enum { +#include "syscall_types.h" +}; +#undef STRUCT +#undef STRUCT_SPECIAL + +#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL }; +#define STRUCT_SPECIAL(name) +#include "syscall_types.h" +#undef STRUCT +#undef STRUCT_SPECIAL + +typedef struct IOCTLEntry { + int target_cmd; + int host_cmd; + const char *name; + int access; + const argtype arg_type[3]; +} IOCTLEntry; + +#define IOC_R 0x0001 +#define IOC_W 0x0002 +#define IOC_RW (IOC_R | IOC_W) + +#define MAX_STRUCT_SIZE 4096 + +const IOCTLEntry ioctl_entries[] = { +#define IOCTL(cmd, access, types...) \ + { TARGET_ ## cmd, cmd, #cmd, access, { types } }, +#include "ioctls.h" + { 0, 0, }, +}; + +static long do_ioctl(long fd, long cmd, long arg) +{ + const IOCTLEntry *ie; + const argtype *arg_type; + long ret; + uint8_t buf_temp[MAX_STRUCT_SIZE]; + + ie = ioctl_entries; + for(;;) { + if (ie->target_cmd == 0) { + gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd); + return -ENOSYS; + } + if (ie->target_cmd == cmd) + break; + ie++; + } + arg_type = ie->arg_type; + // gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); + switch(arg_type[0]) { + case TYPE_NULL: + /* no argument */ + ret = get_errno(ioctl(fd, ie->host_cmd)); + break; + case TYPE_PTRVOID: + case TYPE_INT: + /* int argment */ + ret = get_errno(ioctl(fd, ie->host_cmd, arg)); + break; + case TYPE_PTR: + arg_type++; + switch(ie->access) { + case IOC_R: + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + thunk_convert((void *)arg, buf_temp, arg_type, THUNK_TARGET); + } + break; + case IOC_W: + thunk_convert(buf_temp, (void *)arg, arg_type, THUNK_HOST); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + break; + default: + case IOC_RW: + thunk_convert(buf_temp, (void *)arg, arg_type, THUNK_HOST); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + thunk_convert((void *)arg, buf_temp, arg_type, THUNK_TARGET); + } + break; + } + break; + default: + gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]); + ret = -ENOSYS; + break; + } + return ret; +} + +bitmask_transtbl iflag_tbl[] = { + { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK }, + { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT }, + { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR }, + { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK }, + { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK }, + { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP }, + { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR }, + { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR }, + { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL }, + { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC }, + { TARGET_IXON, TARGET_IXON, IXON, IXON }, + { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY }, + { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF }, + { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL }, + { 0, 0, 0, 0 } +}; + +bitmask_transtbl oflag_tbl[] = { + { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST }, + { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC }, + { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR }, + { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL }, + { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR }, + { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET }, + { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL }, + { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL }, + { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 }, + { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 }, + { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 }, + { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 }, + { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 }, + { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 }, + { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 }, + { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 }, + { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 }, + { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 }, + { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 }, + { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 }, + { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 }, + { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 }, + { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 }, + { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 }, + { 0, 0, 0, 0 } +}; + +bitmask_transtbl cflag_tbl[] = { + { TARGET_CBAUD, TARGET_B0, CBAUD, B0 }, + { TARGET_CBAUD, TARGET_B50, CBAUD, B50 }, + { TARGET_CBAUD, TARGET_B75, CBAUD, B75 }, + { TARGET_CBAUD, TARGET_B110, CBAUD, B110 }, + { TARGET_CBAUD, TARGET_B134, CBAUD, B134 }, + { TARGET_CBAUD, TARGET_B150, CBAUD, B150 }, + { TARGET_CBAUD, TARGET_B200, CBAUD, B200 }, + { TARGET_CBAUD, TARGET_B300, CBAUD, B300 }, + { TARGET_CBAUD, TARGET_B600, CBAUD, B600 }, + { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 }, + { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 }, + { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 }, + { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 }, + { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 }, + { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 }, + { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 }, + { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 }, + { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 }, + { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 }, + { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 }, + { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 }, + { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 }, + { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 }, + { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 }, + { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB }, + { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD }, + { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB }, + { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD }, + { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL }, + { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL }, + { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS }, + { 0, 0, 0, 0 } +}; + +bitmask_transtbl lflag_tbl[] = { + { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG }, + { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON }, + { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE }, + { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO }, + { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE }, + { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK }, + { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL }, + { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH }, + { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP }, + { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL }, + { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT }, + { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE }, + { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO }, + { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN }, + { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN }, + { 0, 0, 0, 0 } +}; + +static void target_to_host_termios (void *dst, const void *src) +{ + struct host_termios *host = dst; + const struct target_termios *target = src; + + host->c_iflag = + target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl); + host->c_oflag = + target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl); + host->c_cflag = + target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl); + host->c_lflag = + target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl); + host->c_line = target->c_line; + + host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; + host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; + host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; + host->c_cc[VKILL] = target->c_cc[TARGET_VKILL]; + host->c_cc[VEOF] = target->c_cc[TARGET_VEOF]; + host->c_cc[VTIME] = target->c_cc[TARGET_VTIME]; + host->c_cc[VMIN] = target->c_cc[TARGET_VMIN]; + host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC]; + host->c_cc[VSTART] = target->c_cc[TARGET_VSTART]; + host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP]; + host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP]; + host->c_cc[VEOL] = target->c_cc[TARGET_VEOL]; + host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT]; + host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD]; + host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE]; + host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT]; + host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2]; +} + +static void host_to_target_termios (void *dst, const void *src) +{ + struct target_termios *target = dst; + const struct host_termios *host = src; + + target->c_iflag = + tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl)); + target->c_oflag = + tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl)); + target->c_cflag = + tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl)); + target->c_lflag = + tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl)); + target->c_line = host->c_line; + + target->c_cc[TARGET_VINTR] = host->c_cc[VINTR]; + target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT]; + target->c_cc[TARGET_VERASE] = host->c_cc[VERASE]; + target->c_cc[TARGET_VKILL] = host->c_cc[VKILL]; + target->c_cc[TARGET_VEOF] = host->c_cc[VEOF]; + target->c_cc[TARGET_VTIME] = host->c_cc[VTIME]; + target->c_cc[TARGET_VMIN] = host->c_cc[VMIN]; + target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC]; + target->c_cc[TARGET_VSTART] = host->c_cc[VSTART]; + target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP]; + target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP]; + target->c_cc[TARGET_VEOL] = host->c_cc[VEOL]; + target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT]; + target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD]; + target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE]; + target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT]; + target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2]; +} + +StructEntry struct_termios_def = { + .convert = { host_to_target_termios, target_to_host_termios }, + .size = { sizeof(struct target_termios), sizeof(struct host_termios) }, + .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, +}; + +void syscall_init(void) +{ +#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); +#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); +#include "syscall_types.h" +#undef STRUCT +#undef STRUCT_SPECIAL +} + +long do_syscall(int num, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) +{ + long ret; + struct stat st; + struct statfs *stfs; + + // gemu_log("syscall %d\n", num); + switch(num) { + case TARGET_NR_exit: + _exit(arg1); + ret = 0; /* avoid warning */ + break; + case TARGET_NR_read: + ret = get_errno(read(arg1, (void *)arg2, arg3)); + break; + case TARGET_NR_write: + ret = get_errno(write(arg1, (void *)arg2, arg3)); + break; + case TARGET_NR_open: + ret = get_errno(open((const char *)arg1, arg2, arg3)); + break; + case TARGET_NR_close: + ret = get_errno(close(arg1)); + break; + case TARGET_NR_brk: + ret = do_brk((char *)arg1); + break; + case TARGET_NR_fork: + ret = get_errno(fork()); + break; + case TARGET_NR_waitpid: + { + int *status = (int *)arg2; + ret = get_errno(waitpid(arg1, status, arg3)); + if (!is_error(ret) && status) + tswapls((long *)&status); + } + break; + case TARGET_NR_creat: + ret = get_errno(creat((const char *)arg1, arg2)); + break; + case TARGET_NR_link: + ret = get_errno(link((const char *)arg1, (const char *)arg2)); + break; + case TARGET_NR_unlink: + ret = get_errno(unlink((const char *)arg1)); + break; + case TARGET_NR_execve: + ret = get_errno(execve((const char *)arg1, (void *)arg2, (void *)arg3)); + break; + case TARGET_NR_chdir: + ret = get_errno(chdir((const char *)arg1)); + break; + case TARGET_NR_time: + { + int *time_ptr = (int *)arg1; + ret = get_errno(time((time_t *)time_ptr)); + if (!is_error(ret) && time_ptr) + tswap32s(time_ptr); + } + break; + case TARGET_NR_mknod: + ret = get_errno(mknod((const char *)arg1, arg2, arg3)); + break; + case TARGET_NR_chmod: + ret = get_errno(chmod((const char *)arg1, arg2)); + break; + case TARGET_NR_lchown: + ret = get_errno(chown((const char *)arg1, arg2, arg3)); + break; + case TARGET_NR_break: + goto unimplemented; + case TARGET_NR_oldstat: + goto unimplemented; + case TARGET_NR_lseek: + ret = get_errno(lseek(arg1, arg2, arg3)); + break; + case TARGET_NR_getpid: + ret = get_errno(getpid()); + break; + case TARGET_NR_mount: + /* need to look at the data field */ + goto unimplemented; + case TARGET_NR_umount: + ret = get_errno(umount((const char *)arg1)); + break; + case TARGET_NR_setuid: + ret = get_errno(setuid(arg1)); + break; + case TARGET_NR_getuid: + ret = get_errno(getuid()); + break; + case TARGET_NR_stime: + { + int *time_ptr = (int *)arg1; + if (time_ptr) + tswap32s(time_ptr); + ret = get_errno(stime((time_t *)time_ptr)); + } + break; + case TARGET_NR_ptrace: + goto unimplemented; + case TARGET_NR_alarm: + ret = alarm(arg1); + break; + case TARGET_NR_oldfstat: + goto unimplemented; + case TARGET_NR_pause: + ret = get_errno(pause()); + break; + case TARGET_NR_utime: + goto unimplemented; + case TARGET_NR_stty: + goto unimplemented; + case TARGET_NR_gtty: + goto unimplemented; + case TARGET_NR_access: + ret = get_errno(access((const char *)arg1, arg2)); + break; + case TARGET_NR_nice: + ret = get_errno(nice(arg1)); + break; + case TARGET_NR_ftime: + goto unimplemented; + case TARGET_NR_sync: + ret = get_errno(sync()); + break; + case TARGET_NR_kill: + ret = get_errno(kill(arg1, arg2)); + break; + case TARGET_NR_rename: + ret = get_errno(rename((const char *)arg1, (const char *)arg2)); + break; + case TARGET_NR_mkdir: + ret = get_errno(mkdir((const char *)arg1, arg2)); + break; + case TARGET_NR_rmdir: + ret = get_errno(rmdir((const char *)arg1)); + break; + case TARGET_NR_dup: + ret = get_errno(dup(arg1)); + break; + case TARGET_NR_pipe: + { + int *pipe_ptr = (int *)arg1; + ret = get_errno(pipe(pipe_ptr)); + if (!is_error(ret)) { + tswap32s(&pipe_ptr[0]); + tswap32s(&pipe_ptr[1]); + } + } + break; + case TARGET_NR_times: + goto unimplemented; + case TARGET_NR_prof: + goto unimplemented; + case TARGET_NR_setgid: + ret = get_errno(setgid(arg1)); + break; + case TARGET_NR_getgid: + ret = get_errno(getgid()); + break; + case TARGET_NR_signal: + goto unimplemented; + case TARGET_NR_geteuid: + ret = get_errno(geteuid()); + break; + case TARGET_NR_getegid: + ret = get_errno(getegid()); + break; + case TARGET_NR_acct: + goto unimplemented; + case TARGET_NR_umount2: + ret = get_errno(umount2((const char *)arg1, arg2)); + break; + case TARGET_NR_lock: + goto unimplemented; + case TARGET_NR_ioctl: + ret = do_ioctl(arg1, arg2, arg3); + break; + case TARGET_NR_fcntl: + switch(arg2) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + goto unimplemented; + default: + ret = get_errno(fcntl(arg1, arg2, arg3)); + break; + } + break; + case TARGET_NR_mpx: + goto unimplemented; + case TARGET_NR_setpgid: + ret = get_errno(setpgid(arg1, arg2)); + break; + case TARGET_NR_ulimit: + goto unimplemented; + case TARGET_NR_oldolduname: + goto unimplemented; + case TARGET_NR_umask: + ret = get_errno(umask(arg1)); + break; + case TARGET_NR_chroot: + ret = get_errno(chroot((const char *)arg1)); + break; + case TARGET_NR_ustat: + goto unimplemented; + case TARGET_NR_dup2: + ret = get_errno(dup2(arg1, arg2)); + break; + case TARGET_NR_getppid: + ret = get_errno(getppid()); + break; + case TARGET_NR_getpgrp: + ret = get_errno(getpgrp()); + break; + case TARGET_NR_setsid: + ret = get_errno(setsid()); + break; + case TARGET_NR_sigaction: +#if 0 + { + int signum = arg1; + struct target_old_sigaction *tact = arg2, *toldact = arg3; + ret = get_errno(setsid()); + + + } + break; +#else + goto unimplemented; +#endif + case TARGET_NR_sgetmask: + goto unimplemented; + case TARGET_NR_ssetmask: + goto unimplemented; + case TARGET_NR_setreuid: + ret = get_errno(setreuid(arg1, arg2)); + break; + case TARGET_NR_setregid: + ret = get_errno(setregid(arg1, arg2)); + break; + case TARGET_NR_sigsuspend: + goto unimplemented; + case TARGET_NR_sigpending: + goto unimplemented; + case TARGET_NR_sethostname: + ret = get_errno(sethostname((const char *)arg1, arg2)); + break; + case TARGET_NR_setrlimit: + goto unimplemented; + case TARGET_NR_getrlimit: + goto unimplemented; + case TARGET_NR_getrusage: + goto unimplemented; + case TARGET_NR_gettimeofday: + { + struct target_timeval *target_tv = (void *)arg1; + struct timeval tv; + ret = get_errno(gettimeofday(&tv, NULL)); + if (!is_error(ret)) { + target_tv->tv_sec = tswapl(tv.tv_sec); + target_tv->tv_usec = tswapl(tv.tv_usec); + } + } + break; + case TARGET_NR_settimeofday: + { + struct target_timeval *target_tv = (void *)arg1; + struct timeval tv; + tv.tv_sec = tswapl(target_tv->tv_sec); + tv.tv_usec = tswapl(target_tv->tv_usec); + ret = get_errno(settimeofday(&tv, NULL)); + } + break; + case TARGET_NR_getgroups: + goto unimplemented; + case TARGET_NR_setgroups: + goto unimplemented; + case TARGET_NR_select: + goto unimplemented; + case TARGET_NR_symlink: + ret = get_errno(symlink((const char *)arg1, (const char *)arg2)); + break; + case TARGET_NR_oldlstat: + goto unimplemented; + case TARGET_NR_readlink: + ret = get_errno(readlink((const char *)arg1, (char *)arg2, arg3)); + break; + case TARGET_NR_uselib: + goto unimplemented; + case TARGET_NR_swapon: + ret = get_errno(swapon((const char *)arg1, arg2)); + break; + case TARGET_NR_reboot: + goto unimplemented; + case TARGET_NR_readdir: + goto unimplemented; +#ifdef TARGET_I386 + case TARGET_NR_mmap: + { + uint32_t v1, v2, v3, v4, v5, v6, *vptr; + vptr = (uint32_t *)arg1; + v1 = tswap32(vptr[0]); + v2 = tswap32(vptr[1]); + v3 = tswap32(vptr[2]); + v4 = tswap32(vptr[3]); + v5 = tswap32(vptr[4]); + v6 = tswap32(vptr[5]); + ret = get_errno((long)mmap((void *)v1, v2, v3, v4, v5, v6)); + } + break; +#endif +#ifdef TARGET_I386 + case TARGET_NR_mmap2: +#else + case TARGET_NR_mmap: +#endif + ret = get_errno((long)mmap((void *)arg1, arg2, arg3, arg4, arg5, arg6)); + break; + case TARGET_NR_munmap: + ret = get_errno(munmap((void *)arg1, arg2)); + break; + case TARGET_NR_truncate: + ret = get_errno(truncate((const char *)arg1, arg2)); + break; + case TARGET_NR_ftruncate: + ret = get_errno(ftruncate(arg1, arg2)); + break; + case TARGET_NR_fchmod: + ret = get_errno(fchmod(arg1, arg2)); + break; + case TARGET_NR_fchown: + ret = get_errno(fchown(arg1, arg2, arg3)); + break; + case TARGET_NR_getpriority: + ret = get_errno(getpriority(arg1, arg2)); + break; + case TARGET_NR_setpriority: + ret = get_errno(setpriority(arg1, arg2, arg3)); + break; + case TARGET_NR_profil: + goto unimplemented; + case TARGET_NR_statfs: + stfs = (void *)arg2; + ret = get_errno(sys_statfs((const char *)arg1, stfs)); + convert_statfs: + if (!is_error(ret)) { + tswap32s(&stfs->f_type); + tswap32s(&stfs->f_bsize); + tswap32s(&stfs->f_blocks); + tswap32s(&stfs->f_bfree); + tswap32s(&stfs->f_bavail); + tswap32s(&stfs->f_files); + tswap32s(&stfs->f_ffree); + tswap32s(&stfs->f_fsid.val[0]); + tswap32s(&stfs->f_fsid.val[1]); + tswap32s(&stfs->f_namelen); + } + break; + case TARGET_NR_fstatfs: + stfs = (void *)arg2; + ret = get_errno(sys_fstatfs(arg1, stfs)); + goto convert_statfs; + case TARGET_NR_ioperm: + goto unimplemented; + case TARGET_NR_socketcall: + ret = do_socketcall(arg1, (long *)arg2); + break; + case TARGET_NR_syslog: + goto unimplemented; + case TARGET_NR_setitimer: + goto unimplemented; + case TARGET_NR_getitimer: + goto unimplemented; + case TARGET_NR_stat: + ret = get_errno(stat((const char *)arg1, &st)); + goto do_stat; + case TARGET_NR_lstat: + ret = get_errno(lstat((const char *)arg1, &st)); + goto do_stat; + case TARGET_NR_fstat: + { + ret = get_errno(fstat(arg1, &st)); + do_stat: + if (!is_error(ret)) { + struct target_stat *target_st = (void *)arg2; + target_st->st_dev = tswap16(st.st_dev); + target_st->st_ino = tswapl(st.st_ino); + target_st->st_mode = tswap16(st.st_mode); + target_st->st_nlink = tswap16(st.st_nlink); + target_st->st_uid = tswap16(st.st_uid); + target_st->st_gid = tswap16(st.st_gid); + target_st->st_rdev = tswap16(st.st_rdev); + target_st->st_size = tswapl(st.st_size); + target_st->st_blksize = tswapl(st.st_blksize); + target_st->st_blocks = tswapl(st.st_blocks); + target_st->st_atime = tswapl(st.st_atime); + target_st->st_mtime = tswapl(st.st_mtime); + target_st->st_ctime = tswapl(st.st_ctime); + } + } + break; + case TARGET_NR_olduname: + goto unimplemented; + case TARGET_NR_iopl: + goto unimplemented; + case TARGET_NR_vhangup: + ret = get_errno(vhangup()); + break; + case TARGET_NR_idle: + goto unimplemented; + case TARGET_NR_vm86old: + goto unimplemented; + case TARGET_NR_wait4: + { + int status; + target_long *status_ptr = (void *)arg2; + struct rusage rusage, *rusage_ptr; + struct target_rusage *target_rusage = (void *)arg4; + if (target_rusage) + rusage_ptr = &rusage; + else + rusage_ptr = NULL; + ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); + if (!is_error(ret)) { + if (status_ptr) + *status_ptr = tswap32(status); + if (target_rusage) { + target_rusage->ru_utime.tv_sec = tswapl(rusage.ru_utime.tv_sec); + target_rusage->ru_utime.tv_usec = tswapl(rusage.ru_utime.tv_usec); + target_rusage->ru_stime.tv_sec = tswapl(rusage.ru_stime.tv_sec); + target_rusage->ru_stime.tv_usec = tswapl(rusage.ru_stime.tv_usec); + target_rusage->ru_maxrss = tswapl(rusage.ru_maxrss); + target_rusage->ru_ixrss = tswapl(rusage.ru_ixrss); + target_rusage->ru_idrss = tswapl(rusage.ru_idrss); + target_rusage->ru_isrss = tswapl(rusage.ru_isrss); + target_rusage->ru_minflt = tswapl(rusage.ru_minflt); + target_rusage->ru_majflt = tswapl(rusage.ru_majflt); + target_rusage->ru_nswap = tswapl(rusage.ru_nswap); + target_rusage->ru_inblock = tswapl(rusage.ru_inblock); + target_rusage->ru_oublock = tswapl(rusage.ru_oublock); + target_rusage->ru_msgsnd = tswapl(rusage.ru_msgsnd); + target_rusage->ru_msgrcv = tswapl(rusage.ru_msgrcv); + target_rusage->ru_nsignals = tswapl(rusage.ru_nsignals); + target_rusage->ru_nvcsw = tswapl(rusage.ru_nvcsw); + target_rusage->ru_nivcsw = tswapl(rusage.ru_nivcsw); + } + } + } + break; + case TARGET_NR_swapoff: + ret = get_errno(swapoff((const char *)arg1)); + break; + case TARGET_NR_sysinfo: + goto unimplemented; + case TARGET_NR_ipc: + goto unimplemented; + case TARGET_NR_fsync: + ret = get_errno(fsync(arg1)); + break; + case TARGET_NR_sigreturn: + goto unimplemented; + case TARGET_NR_clone: + goto unimplemented; + case TARGET_NR_setdomainname: + ret = get_errno(setdomainname((const char *)arg1, arg2)); + break; + case TARGET_NR_uname: + /* no need to transcode because we use the linux syscall */ + ret = get_errno(sys_uname((struct new_utsname *)arg1)); + break; + case TARGET_NR_modify_ldt: + goto unimplemented; + case TARGET_NR_adjtimex: + goto unimplemented; + case TARGET_NR_mprotect: + ret = get_errno(mprotect((void *)arg1, arg2, arg3)); + break; + case TARGET_NR_sigprocmask: + { + int how = arg1; + sigset_t set, oldset, *set_ptr; + target_ulong *pset = (void *)arg2, *poldset = (void *)arg3; + + switch(how) { + case TARGET_SIG_BLOCK: + how = SIG_BLOCK; + break; + case TARGET_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + case TARGET_SIG_SETMASK: + how = SIG_SETMASK; + break; + default: + ret = -EINVAL; + goto fail; + } + + if (pset) { + target_to_host_old_sigset(&set, pset); + set_ptr = &set; + } else { + set_ptr = NULL; + } + ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); + if (!is_error(ret) && poldset) { + host_to_target_old_sigset(poldset, &oldset); + } + } + break; + case TARGET_NR_create_module: + case TARGET_NR_init_module: + case TARGET_NR_delete_module: + case TARGET_NR_get_kernel_syms: + goto unimplemented; + case TARGET_NR_quotactl: + goto unimplemented; + case TARGET_NR_getpgid: + ret = get_errno(getpgid(arg1)); + break; + case TARGET_NR_fchdir: + ret = get_errno(fchdir(arg1)); + break; + case TARGET_NR_bdflush: + goto unimplemented; + case TARGET_NR_sysfs: + goto unimplemented; + case TARGET_NR_personality: + ret = get_errno(mprotect((void *)arg1, arg2, arg3)); + break; + case TARGET_NR_afs_syscall: + goto unimplemented; + case TARGET_NR_setfsuid: + goto unimplemented; + case TARGET_NR_setfsgid: + goto unimplemented; + case TARGET_NR__llseek: + { + int64_t res; + ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5)); + *(int64_t *)arg4 = tswap64(res); + } + break; + case TARGET_NR_getdents: +#if TARGET_LONG_SIZE != 4 +#error not supported +#endif + { + struct dirent *dirp = (void *)arg2; + long count = arg3; + ret = get_errno(getdents(arg1, dirp, count)); + if (!is_error(ret)) { + struct dirent *de; + int len = ret; + int reclen; + de = dirp; + while (len > 0) { + reclen = tswap16(de->d_reclen); + if (reclen > len) + break; + de->d_reclen = reclen; + tswapls(&de->d_ino); + tswapls(&de->d_off); + de = (struct dirent *)((char *)de + reclen); + len -= reclen; + } + } + } + break; + case TARGET_NR__newselect: + ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, + (void *)arg5); + break; + case TARGET_NR_flock: + goto unimplemented; + case TARGET_NR_msync: + ret = get_errno(msync((void *)arg1, arg2, arg3)); + break; + case TARGET_NR_readv: + { + int count = arg3; + int i; + struct iovec *vec; + struct target_iovec *target_vec = (void *)arg2; + + vec = alloca(count * sizeof(struct iovec)); + for(i = 0;i < count; i++) { + vec[i].iov_base = (void *)tswapl(target_vec[i].iov_base); + vec[i].iov_len = tswapl(target_vec[i].iov_len); + } + ret = get_errno(readv(arg1, vec, count)); + } + break; + case TARGET_NR_writev: + { + int count = arg3; + int i; + struct iovec *vec; + struct target_iovec *target_vec = (void *)arg2; + + vec = alloca(count * sizeof(struct iovec)); + for(i = 0;i < count; i++) { + vec[i].iov_base = (void *)tswapl(target_vec[i].iov_base); + vec[i].iov_len = tswapl(target_vec[i].iov_len); + } + ret = get_errno(writev(arg1, vec, count)); + } + break; + case TARGET_NR_getsid: + ret = get_errno(getsid(arg1)); + break; + case TARGET_NR_fdatasync: + goto unimplemented; + case TARGET_NR__sysctl: + goto unimplemented; + case TARGET_NR_mlock: + ret = get_errno(mlock((void *)arg1, arg2)); + break; + case TARGET_NR_munlock: + ret = get_errno(munlock((void *)arg1, arg2)); + break; + case TARGET_NR_mlockall: + ret = get_errno(mlockall(arg1)); + break; + case TARGET_NR_munlockall: + ret = get_errno(munlockall()); + break; + case TARGET_NR_sched_setparam: + goto unimplemented; + case TARGET_NR_sched_getparam: + goto unimplemented; + case TARGET_NR_sched_setscheduler: + goto unimplemented; + case TARGET_NR_sched_getscheduler: + goto unimplemented; + case TARGET_NR_sched_yield: + ret = get_errno(sched_yield()); + break; + case TARGET_NR_sched_get_priority_max: + case TARGET_NR_sched_get_priority_min: + case TARGET_NR_sched_rr_get_interval: + case TARGET_NR_nanosleep: + case TARGET_NR_mremap: + case TARGET_NR_setresuid: + case TARGET_NR_getresuid: + case TARGET_NR_vm86: + case TARGET_NR_query_module: + case TARGET_NR_poll: + case TARGET_NR_nfsservctl: + case TARGET_NR_setresgid: + case TARGET_NR_getresgid: + case TARGET_NR_prctl: + case TARGET_NR_rt_sigreturn: + case TARGET_NR_rt_sigaction: + case TARGET_NR_rt_sigprocmask: + case TARGET_NR_rt_sigpending: + case TARGET_NR_rt_sigtimedwait: + case TARGET_NR_rt_sigqueueinfo: + case TARGET_NR_rt_sigsuspend: + case TARGET_NR_pread: + case TARGET_NR_pwrite: + goto unimplemented; + case TARGET_NR_chown: + ret = get_errno(chown((const char *)arg1, arg2, arg3)); + break; + case TARGET_NR_getcwd: + ret = get_errno(sys_getcwd((char *)arg1, arg2)); + break; + case TARGET_NR_capget: + case TARGET_NR_capset: + case TARGET_NR_sigaltstack: + case TARGET_NR_sendfile: + case TARGET_NR_getpmsg: + case TARGET_NR_putpmsg: + case TARGET_NR_vfork: + ret = get_errno(vfork()); + break; + case TARGET_NR_ugetrlimit: + case TARGET_NR_truncate64: + case TARGET_NR_ftruncate64: + case TARGET_NR_stat64: + case TARGET_NR_lstat64: + case TARGET_NR_fstat64: + case TARGET_NR_lchown32: + case TARGET_NR_getuid32: + case TARGET_NR_getgid32: + case TARGET_NR_geteuid32: + case TARGET_NR_getegid32: + case TARGET_NR_setreuid32: + case TARGET_NR_setregid32: + case TARGET_NR_getgroups32: + case TARGET_NR_setgroups32: + case TARGET_NR_fchown32: + case TARGET_NR_setresuid32: + case TARGET_NR_getresuid32: + case TARGET_NR_setresgid32: + case TARGET_NR_getresgid32: + case TARGET_NR_chown32: + case TARGET_NR_setuid32: + case TARGET_NR_setgid32: + case TARGET_NR_setfsuid32: + case TARGET_NR_setfsgid32: + case TARGET_NR_pivot_root: + case TARGET_NR_mincore: + case TARGET_NR_madvise: + case TARGET_NR_getdents64: + case TARGET_NR_fcntl64: + case TARGET_NR_security: + goto unimplemented; + case TARGET_NR_gettid: + ret = get_errno(gettid()); + break; + case TARGET_NR_readahead: + case TARGET_NR_setxattr: + case TARGET_NR_lsetxattr: + case TARGET_NR_fsetxattr: + case TARGET_NR_getxattr: + case TARGET_NR_lgetxattr: + case TARGET_NR_fgetxattr: + case TARGET_NR_listxattr: + case TARGET_NR_llistxattr: + case TARGET_NR_flistxattr: + case TARGET_NR_removexattr: + case TARGET_NR_lremovexattr: + case TARGET_NR_fremovexattr: + goto unimplemented; + default: + unimplemented: + gemu_log("Unsupported syscall: %d\n", num); + ret = -ENOSYS; + break; + } + fail: + return ret; +} + diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h new file mode 100644 index 000000000..c8f25bb5b --- /dev/null +++ b/linux-user/syscall_defs.h @@ -0,0 +1,283 @@ + +/* common syscall defines for all architectures */ + +#define SOCKOP_socket 1 +#define SOCKOP_bind 2 +#define SOCKOP_connect 3 +#define SOCKOP_listen 4 +#define SOCKOP_accept 5 +#define SOCKOP_getsockname 6 +#define SOCKOP_getpeername 7 +#define SOCKOP_socketpair 8 +#define SOCKOP_send 9 +#define SOCKOP_recv 10 +#define SOCKOP_sendto 11 +#define SOCKOP_recvfrom 12 +#define SOCKOP_shutdown 13 +#define SOCKOP_setsockopt 14 +#define SOCKOP_getsockopt 15 +#define SOCKOP_sendmsg 16 +#define SOCKOP_recvmsg 17 + +struct target_timeval { + target_long tv_sec; + target_long tv_usec; +}; + +struct target_iovec { + target_long iov_base; /* Starting address */ + target_long iov_len; /* Number of bytes */ +}; + +struct target_rusage { + struct target_timeval ru_utime; /* user time used */ + struct target_timeval ru_stime; /* system time used */ + target_long ru_maxrss; /* maximum resident set size */ + target_long ru_ixrss; /* integral shared memory size */ + target_long ru_idrss; /* integral unshared data size */ + target_long ru_isrss; /* integral unshared stack size */ + target_long ru_minflt; /* page reclaims */ + target_long ru_majflt; /* page faults */ + target_long ru_nswap; /* swaps */ + target_long ru_inblock; /* block input operations */ + target_long ru_oublock; /* block output operations */ + target_long ru_msgsnd; /* messages sent */ + target_long ru_msgrcv; /* messages received */ + target_long ru_nsignals; /* signals received */ + target_long ru_nvcsw; /* voluntary context switches */ + target_long ru_nivcsw; /* involuntary " */ +}; + +typedef struct { + int val[2]; +} kernel_fsid_t; + +struct statfs { + int f_type; + int f_bsize; + int f_blocks; + int f_bfree; + int f_bavail; + int f_files; + int f_ffree; + kernel_fsid_t f_fsid; + int f_namelen; + int f_spare[6]; +}; + +/* mostly generic signal stuff */ +#define TARGET_SIG_DFL ((target_long)0) /* default signal handling */ +#define TARGET_SIG_IGN ((target_long)1) /* ignore signal */ +#define TARGET_SIG_ERR ((target_long)-1) /* error return from signal */ + +#ifdef TARGET_MIPS +#define TARGET_NSIG 128 +#else +#define TARGET_NSIG 64 +#endif +#define TARGET_NSIG_BPW TARGET_LONG_BITS +#define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) + +typedef struct { + target_ulong sig[TARGET_NSIG_WORDS]; +} target_sigset_t; + +/* Networking ioctls */ +#define TARGET_SIOCADDRT 0x890B /* add routing table entry */ +#define TARGET_SIOCDELRT 0x890C /* delete routing table entry */ +#define TARGET_SIOCGIFNAME 0x8910 /* get iface name */ +#define TARGET_SIOCSIFLINK 0x8911 /* set iface channel */ +#define TARGET_SIOCGIFCONF 0x8912 /* get iface list */ +#define TARGET_SIOCGIFFLAGS 0x8913 /* get flags */ +#define TARGET_SIOCSIFFLAGS 0x8914 /* set flags */ +#define TARGET_SIOCGIFADDR 0x8915 /* get PA address */ +#define TARGET_SIOCSIFADDR 0x8916 /* set PA address */ +#define TARGET_SIOCGIFDSTADDR 0x8917 /* get remote PA address */ +#define TARGET_SIOCSIFDSTADDR 0x8918 /* set remote PA address */ +#define TARGET_SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ +#define TARGET_SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ +#define TARGET_SIOCGIFNETMASK 0x891b /* get network PA mask */ +#define TARGET_SIOCSIFNETMASK 0x891c /* set network PA mask */ +#define TARGET_SIOCGIFMETRIC 0x891d /* get metric */ +#define TARGET_SIOCSIFMETRIC 0x891e /* set metric */ +#define TARGET_SIOCGIFMEM 0x891f /* get memory address (BSD) */ +#define TARGET_SIOCSIFMEM 0x8920 /* set memory address (BSD) */ +#define TARGET_SIOCGIFMTU 0x8921 /* get MTU size */ +#define TARGET_SIOCSIFMTU 0x8922 /* set MTU size */ +#define TARGET_SIOCSIFHWADDR 0x8924 /* set hardware address (NI) */ +#define TARGET_SIOCGIFENCAP 0x8925 /* get/set slip encapsulation */ +#define TARGET_SIOCSIFENCAP 0x8926 +#define TARGET_SIOCGIFHWADDR 0x8927 /* Get hardware address */ +#define TARGET_SIOCGIFSLAVE 0x8929 /* Driver slaving support */ +#define TARGET_SIOCSIFSLAVE 0x8930 +#define TARGET_SIOCADDMULTI 0x8931 /* Multicast address lists */ +#define TARGET_SIOCDELMULTI 0x8932 + +/* Bridging control calls */ +#define TARGET_SIOCGIFBR 0x8940 /* Bridging support */ +#define TARGET_SIOCSIFBR 0x8941 /* Set bridging options */ + +#define TARGET_SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */ +#define TARGET_SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */ + +/* ARP cache control calls. */ +#define TARGET_OLD_SIOCDARP 0x8950 /* old delete ARP table entry */ +#define TARGET_OLD_SIOCGARP 0x8951 /* old get ARP table entry */ +#define TARGET_OLD_SIOCSARP 0x8952 /* old set ARP table entry */ +#define TARGET_SIOCDARP 0x8953 /* delete ARP table entry */ +#define TARGET_SIOCGARP 0x8954 /* get ARP table entry */ +#define TARGET_SIOCSARP 0x8955 /* set ARP table entry */ + +/* RARP cache control calls. */ +#define TARGET_SIOCDRARP 0x8960 /* delete RARP table entry */ +#define TARGET_SIOCGRARP 0x8961 /* get RARP table entry */ +#define TARGET_SIOCSRARP 0x8962 /* set RARP table entry */ + +/* Driver configuration calls */ +#define TARGET_SIOCGIFMAP 0x8970 /* Get device parameters */ +#define TARGET_SIOCSIFMAP 0x8971 /* Set device parameters */ + +/* DLCI configuration calls */ +#define TARGET_SIOCADDDLCI 0x8980 /* Create new DLCI device */ +#define TARGET_SIOCDELDLCI 0x8981 /* Delete DLCI device */ + + +/* From */ + +#define TARGET_BLKROSET TARGET_IO(0x12,93) /* set device read-only (0 = read-write) */ +#define TARGET_BLKROGET TARGET_IO(0x12,94) /* get read-only status (0 = read_write) */ +#define TARGET_BLKRRPART TARGET_IO(0x12,95) /* re-read partition table */ +#define TARGET_BLKGETSIZE TARGET_IO(0x12,96) /* return device size /512 (long *arg) */ +#define TARGET_BLKFLSBUF TARGET_IO(0x12,97) /* flush buffer cache */ +#define TARGET_BLKRASET TARGET_IO(0x12,98) /* Set read ahead for block device */ +#define TARGET_BLKRAGET TARGET_IO(0x12,99) /* get current read ahead setting */ +#define TARGET_BLKFRASET TARGET_IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */ +#define TARGET_BLKFRAGET TARGET_IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */ +#define TARGET_BLKSECTSET TARGET_IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */ +#define TARGET_BLKSECTGET TARGET_IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */ +#define TARGET_BLKSSZGET TARGET_IO(0x12,104)/* get block device sector size */ +/* A jump here: 108-111 have been used for various private purposes. */ +#define TARGET_BLKBSZGET TARGET_IOR(0x12,112,sizeof(int)) +#define TARGET_BLKBSZSET TARGET_IOW(0x12,113,sizeof(int)) +#define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */ +#define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ +#define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ + +/* cdrom commands */ +#define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */ +#define TARGET_CDROMRESUME 0x5302 /* Resume paused Audio Operation */ +#define TARGET_CDROMPLAYMSF 0x5303 /* Play Audio MSF (struct cdrom_msf) */ +#define TARGET_CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index + (struct cdrom_ti) */ +#define TARGET_CDROMREADTOCHDR 0x5305 /* Read TOC header + (struct cdrom_tochdr) */ +#define TARGET_CDROMREADTOCENTRY 0x5306 /* Read TOC entry + (struct cdrom_tocentry) */ +#define TARGET_CDROMSTOP 0x5307 /* Stop the cdrom drive */ +#define TARGET_CDROMSTART 0x5308 /* Start the cdrom drive */ +#define TARGET_CDROMEJECT 0x5309 /* Ejects the cdrom media */ +#define TARGET_CDROMVOLCTRL 0x530a /* Control output volume + (struct cdrom_volctrl) */ +#define TARGET_CDROMSUBCHNL 0x530b /* Read subchannel data + (struct cdrom_subchnl) */ +#define TARGET_CDROMREADMODE2 0x530c /* Read TARGET_CDROM mode 2 data (2336 Bytes) + (struct cdrom_read) */ +#define TARGET_CDROMREADMODE1 0x530d /* Read TARGET_CDROM mode 1 data (2048 Bytes) + (struct cdrom_read) */ +#define TARGET_CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ +#define TARGET_CDROMEJECT_SW 0x530f /* enable(1)/disable(0) auto-ejecting */ +#define TARGET_CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session + address of multi session disks + (struct cdrom_multisession) */ +#define TARGET_CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code" + if available (struct cdrom_mcn) */ +#define TARGET_CDROM_GET_UPC TARGET_CDROM_GET_MCN /* This one is depricated, + but here anyway for compatability */ +#define TARGET_CDROMRESET 0x5312 /* hard-reset the drive */ +#define TARGET_CDROMVOLREAD 0x5313 /* Get the drive's volume setting + (struct cdrom_volctrl) */ +#define TARGET_CDROMREADRAW 0x5314 /* read data in raw mode (2352 Bytes) + (struct cdrom_read) */ +/* + * These ioctls are used only used in aztcd.c and optcd.c + */ +#define TARGET_CDROMREADCOOKED 0x5315 /* read data in cooked mode */ +#define TARGET_CDROMSEEK 0x5316 /* seek msf address */ + +/* + * This ioctl is only used by the scsi-cd driver. + It is for playing audio in logical block addressing mode. + */ +#define TARGET_CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */ + +/* + * These ioctls are only used in optcd.c + */ +#define TARGET_CDROMREADALL 0x5318 /* read all 2646 bytes */ + +/* + * These ioctls are (now) only in ide-cd.c for controlling + * drive spindown time. They should be implemented in the + * Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10, + * GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE... + * -Erik + */ +#define TARGET_CDROMGETSPINDOWN 0x531d +#define TARGET_CDROMSETSPINDOWN 0x531e + +/* + * These ioctls are implemented through the uniform CD-ROM driver + * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM + * drivers are eventually ported to the uniform CD-ROM driver interface. + */ +#define TARGET_CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */ +#define TARGET_CDROM_SET_OPTIONS 0x5320 /* Set behavior options */ +#define TARGET_CDROM_CLEAR_OPTIONS 0x5321 /* Clear behavior options */ +#define TARGET_CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */ +#define TARGET_CDROM_SELECT_DISC 0x5323 /* Select disc (for juke-boxes) */ +#define TARGET_CDROM_MEDIA_CHANGED 0x5325 /* Check is media changed */ +#define TARGET_CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */ +#define TARGET_CDROM_DISC_STATUS 0x5327 /* Get disc type, etc. */ +#define TARGET_CDROM_CHANGER_NSLOTS 0x5328 /* Get number of slots */ +#define TARGET_CDROM_LOCKDOOR 0x5329 /* lock or unlock door */ +#define TARGET_CDROM_DEBUG 0x5330 /* Turn debug messages on/off */ +#define TARGET_CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ + +/* Note that scsi/scsi_ioctl.h also uses 0x5382 - 0x5386. + * Future CDROM ioctls should be kept below 0x537F + */ + +/* This ioctl is only used by sbpcd at the moment */ +#define TARGET_CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ + /* conflict with SCSI_IOCTL_GET_IDLUN */ + +/* DVD-ROM Specific ioctls */ +#define TARGET_DVD_READ_STRUCT 0x5390 /* Read structure */ +#define TARGET_DVD_WRITE_STRUCT 0x5391 /* Write structure */ +#define TARGET_DVD_AUTH 0x5392 /* Authentication */ + +#define TARGET_CDROM_SEND_PACKET 0x5393 /* send a packet to the drive */ +#define TARGET_CDROM_NEXT_WRITABLE 0x5394 /* get next writable block */ +#define TARGET_CDROM_LAST_WRITTEN 0x5395 /* get last block written on disc */ + +/* HD commands */ + +/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */ +#define TARGET_HDIO_GETGEO 0x0301 /* get device geometry */ +#define TARGET_HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ +#define TARGET_HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */ +#define TARGET_HDIO_GET_IDENTITY 0x0307 /* get IDE identification info */ +#define TARGET_HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ +#define TARGET_HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ +#define TARGET_HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */ +#define TARGET_HDIO_GET_DMA 0x030b /* get use-dma flag */ +#define TARGET_HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ + +/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */ +#define TARGET_HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */ +#define TARGET_HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */ +#define TARGET_HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */ +#define TARGET_HDIO_SET_32BIT 0x0324 /* change io_32bit flags */ +#define TARGET_HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */ +#define TARGET_HDIO_SET_DMA 0x0326 /* change use-dma flag */ +#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h new file mode 100644 index 000000000..63852d3af --- /dev/null +++ b/linux-user/syscall_types.h @@ -0,0 +1,64 @@ +STRUCT_SPECIAL(termios) + +STRUCT(winsize, + TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT) + +STRUCT(serial_multiport_struct, + TYPE_INT, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, + TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, + MK_ARRAY(TYPE_INT, 32)) + +STRUCT(serial_icounter_struct, + TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_INT, 16)) + +STRUCT(sockaddr, + TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14)) + +STRUCT(rtentry, + TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), + TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID, + TYPE_ULONG, TYPE_ULONG, TYPE_SHORT) + +STRUCT(ifmap, + TYPE_ULONG, TYPE_ULONG, TYPE_SHORT, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, + /* Spare 3 bytes */ + TYPE_CHAR, TYPE_CHAR, TYPE_CHAR) + +/* The *_ifreq_list arrays deal with the fact that struct ifreq has unions */ + +STRUCT(sockaddr_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_sockaddr)) + +STRUCT(short_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_SHORT) + +STRUCT(int_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT) + +STRUCT(ifmap_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_ifmap)) + +STRUCT(char_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), + MK_ARRAY(TYPE_CHAR, IFNAMSIZ)) + +STRUCT(ptr_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_PTRVOID) + +STRUCT(ifconf, + TYPE_INT, TYPE_PTRVOID) + +STRUCT(arpreq, + MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr), + MK_ARRAY(TYPE_CHAR, 16)) + +STRUCT(arpreq_old, + MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr)) + +STRUCT(cdrom_read_audio, + TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_PTRVOID, + TYPE_NULL) + +STRUCT(hd_geometry, + TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG) + diff --git a/syscall-i386.h b/syscall-i386.h new file mode 100644 index 000000000..312edc684 --- /dev/null +++ b/syscall-i386.h @@ -0,0 +1,760 @@ +/* from linux/unistd.h */ + +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86old 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_vm86 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread 180 +#define TARGET_NR_pwrite 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 +#define TARGET_NR_getpmsg 188 /* some people actually want streams */ +#define TARGET_NR_putpmsg 189 /* some people actually want streams */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_pivot_root 217 +#define TARGET_NR_mincore 218 +#define TARGET_NR_madvise 219 +#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */ +#define TARGET_NR_getdents64 220 +#define TARGET_NR_fcntl64 221 +#define TARGET_NR_security 223 /* syscall for security modules */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_readahead 225 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 + +#define TARGET_SIG_BLOCK 0 /* for blocking signals */ +#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */ +#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */ + +struct target_stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct target_stat64 { + unsigned short st_dev; + unsigned char __pad0[10]; + +#define STAT64_HAS_BROKEN_ST_INO 1 + unsigned long __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned short st_rdev; + unsigned char __pad3[10]; + + long long st_size; + unsigned long st_blksize; + + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long __pad4; /* future possible st_blocks high bits */ + + unsigned long st_atime; + unsigned long __pad5; + + unsigned long st_mtime; + unsigned long __pad6; + + unsigned long st_ctime; + unsigned long __pad7; /* will be high 32 bits of ctime someday */ + + unsigned long long st_ino; +}; + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +struct target_old_sigaction { + target_ulong _sa_handler; + target_ulong sa_mask; + target_ulong sa_flags; + void (*sa_restorer)(void); +}; + +struct target_sigaction { + target_ulong _sa_handler; + target_sigset_t sa_mask; + target_ulong sa_flags; + target_ulong sa_restorer; +}; + +typedef union target_sigval { + int sival_int; + void *sival_ptr; +} target_sigval_t; + +#define TARGET_SI_MAX_SIZE 128 +#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3) + +typedef struct target_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[TARGET_SI_PAD_SIZE]; + + /* kill() */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + unsigned int _timer1; + unsigned int _timer2; + } _timer; + + /* POSIX.1b signals */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + pid_t _pid; /* which child */ + uid_t _uid; /* sender's uid */ + int _status; /* exit code */ + clock_t _utime; + clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + void *_addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} target_siginfo_t; + +/* ioctls */ + +/* + * The following is for compatibility across the various Linux + * platforms. The i386 ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define TARGET_IOC_NRBITS 8 +#define TARGET_IOC_TYPEBITS 8 +#define TARGET_IOC_SIZEBITS 14 +#define TARGET_IOC_DIRBITS 2 + +#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1) +#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1) +#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1) +#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1) + +#define TARGET_IOC_NRSHIFT 0 +#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS) +#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS) +#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS) + +/* + * Direction bits. + */ +#define TARGET_IOC_NONE 0U +#define TARGET_IOC_WRITE 1U +#define TARGET_IOC_READ 2U + +#define TARGET_IOC(dir,type,nr,size) \ + (((dir) << TARGET_IOC_DIRSHIFT) | \ + ((type) << TARGET_IOC_TYPESHIFT) | \ + ((nr) << TARGET_IOC_NRSHIFT) | \ + ((size) << TARGET_IOC_SIZESHIFT)) + +/* used to create numbers */ +#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0) +#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size)) +#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size)) +#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size)) + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* soundcard defines (XXX: move them to generic file syscall_defs.h) */ + +#define TARGET_SNDCTL_COPR_HALT 0xc0144307 +#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301 +#define TARGET_SNDCTL_COPR_RCODE 0xc0144303 +#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309 +#define TARGET_SNDCTL_COPR_RDATA 0xc0144302 +#define TARGET_SNDCTL_COPR_RESET 0x00004300 +#define TARGET_SNDCTL_COPR_RUN 0xc0144306 +#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308 +#define TARGET_SNDCTL_COPR_WCODE 0x40144305 +#define TARGET_SNDCTL_COPR_WDATA 0x40144304 +#define TARGET_SNDCTL_DSP_CHANNELS 0xc0045006 +#define TARGET_SNDCTL_DSP_GETBLKSIZE 0xc0045004 +#define TARGET_SNDCTL_DSP_GETCAPS 0x8004500f +#define TARGET_SNDCTL_DSP_GETFMTS 0x8004500b +#define TARGET_SNDCTL_DSP_GETIPTR 0x800c5011 +#define TARGET_SNDCTL_DSP_GETISPACE 0x8010500d +#define TARGET_SNDCTL_DSP_GETOPTR 0x800c5012 +#define TARGET_SNDCTL_DSP_GETOSPACE 0x8010500c +#define TARGET_SNDCTL_DSP_GETTRIGGER 0x80045010 +#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013 +#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014 +#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e +#define TARGET_SNDCTL_DSP_POST 0x00005008 +#define TARGET_SNDCTL_DSP_RESET 0x00005000 +#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005 +#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016 +#define TARGET_SNDCTL_DSP_SETFMT 0xc0045005 +#define TARGET_SNDCTL_DSP_SETFRAGMENT 0xc004500a +#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015 +#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010 +#define TARGET_SNDCTL_DSP_SPEED 0xc0045002 +#define TARGET_SNDCTL_DSP_STEREO 0xc0045003 +#define TARGET_SNDCTL_DSP_SUBDIVIDE 0xc0045009 +#define TARGET_SNDCTL_DSP_SYNC 0x00005001 +#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f +#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107 +#define TARGET_SNDCTL_MIDI_INFO 0xc074510c +#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02 +#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01 +#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00 +#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110 +#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001 +#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103 +#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105 +#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104 +#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b +#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a +#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112 +#define TARGET_SNDCTL_SEQ_PANIC 0x00005111 +#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106 +#define TARGET_SNDCTL_SEQ_RESET 0x00005100 +#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109 +#define TARGET_SNDCTL_SEQ_SYNC 0x00005101 +#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108 +#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d +#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d +#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102 +#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e +#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404 +#define TARGET_SNDCTL_TMR_METRONOME 0x40045407 +#define TARGET_SNDCTL_TMR_SELECT 0x40045408 +#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406 +#define TARGET_SNDCTL_TMR_START 0x00005402 +#define TARGET_SNDCTL_TMR_STOP 0x00005403 +#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405 +#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401 +#define TARGET_SOUND_PCM_WRITE_FILTER 0xc0045007 +#define TARGET_SOUND_PCM_READ_RATE 0x80045002 +#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006 +#define TARGET_SOUND_PCM_READ_BITS 0x80045005 +#define TARGET_SOUND_PCM_READ_FILTER 0x80045007 +#define TARGET_SOUND_MIXER_INFO 0x80304d65 +#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66 +#define TARGET_SOUND_MIXER_PRIVATE1 0xc0044d6f +#define TARGET_SOUND_MIXER_PRIVATE2 0xc0044d70 +#define TARGET_SOUND_MIXER_PRIVATE3 0xc0044d71 +#define TARGET_SOUND_MIXER_PRIVATE4 0xc0044d72 +#define TARGET_SOUND_MIXER_PRIVATE5 0xc0044d73 +#define TARGET_SOUND_MIXER_READ_VOLUME 0x80044d00 +#define TARGET_SOUND_MIXER_READ_BASS 0x80044d01 +#define TARGET_SOUND_MIXER_READ_TREBLE 0x80044d02 +#define TARGET_SOUND_MIXER_READ_SYNTH 0x80044d03 +#define TARGET_SOUND_MIXER_READ_PCM 0x80044d04 +#define TARGET_SOUND_MIXER_READ_SPEAKER 0x80044d05 +#define TARGET_SOUND_MIXER_READ_LINE 0x80044d06 +#define TARGET_SOUND_MIXER_READ_MIC 0x80044d07 +#define TARGET_SOUND_MIXER_READ_CD 0x80044d08 +#define TARGET_SOUND_MIXER_READ_IMIX 0x80044d09 +#define TARGET_SOUND_MIXER_READ_ALTPCM 0x80044d0a +#define TARGET_SOUND_MIXER_READ_RECLEV 0x80044d0b +#define TARGET_SOUND_MIXER_READ_IGAIN 0x80044d0c +#define TARGET_SOUND_MIXER_READ_OGAIN 0x80044d0d +#define TARGET_SOUND_MIXER_READ_LINE1 0x80044d0e +#define TARGET_SOUND_MIXER_READ_LINE2 0x80044d0f +#define TARGET_SOUND_MIXER_READ_LINE3 0x80044d10 +#define TARGET_SOUND_MIXER_READ_MUTE 0x80044d1f +#define TARGET_SOUND_MIXER_READ_ENHANCE 0x80044d1f +#define TARGET_SOUND_MIXER_READ_LOUD 0x80044d1f +#define TARGET_SOUND_MIXER_READ_RECSRC 0x80044dff +#define TARGET_SOUND_MIXER_READ_DEVMASK 0x80044dfe +#define TARGET_SOUND_MIXER_READ_RECMASK 0x80044dfd +#define TARGET_SOUND_MIXER_READ_STEREODEVS 0x80044dfb +#define TARGET_SOUND_MIXER_READ_CAPS 0x80044dfc +#define TARGET_SOUND_MIXER_WRITE_VOLUME 0xc0044d00 +#define TARGET_SOUND_MIXER_WRITE_BASS 0xc0044d01 +#define TARGET_SOUND_MIXER_WRITE_TREBLE 0xc0044d02 +#define TARGET_SOUND_MIXER_WRITE_SYNTH 0xc0044d03 +#define TARGET_SOUND_MIXER_WRITE_PCM 0xc0044d04 +#define TARGET_SOUND_MIXER_WRITE_SPEAKER 0xc0044d05 +#define TARGET_SOUND_MIXER_WRITE_LINE 0xc0044d06 +#define TARGET_SOUND_MIXER_WRITE_MIC 0xc0044d07 +#define TARGET_SOUND_MIXER_WRITE_CD 0xc0044d08 +#define TARGET_SOUND_MIXER_WRITE_IMIX 0xc0044d09 +#define TARGET_SOUND_MIXER_WRITE_ALTPCM 0xc0044d0a +#define TARGET_SOUND_MIXER_WRITE_RECLEV 0xc0044d0b +#define TARGET_SOUND_MIXER_WRITE_IGAIN 0xc0044d0c +#define TARGET_SOUND_MIXER_WRITE_OGAIN 0xc0044d0d +#define TARGET_SOUND_MIXER_WRITE_LINE1 0xc0044d0e +#define TARGET_SOUND_MIXER_WRITE_LINE2 0xc0044d0f +#define TARGET_SOUND_MIXER_WRITE_LINE3 0xc0044d10 +#define TARGET_SOUND_MIXER_WRITE_MUTE 0xc0044d1f +#define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f +#define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f +#define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff diff --git a/thunk.c b/thunk.c new file mode 100644 index 000000000..62520a297 --- /dev/null +++ b/thunk.c @@ -0,0 +1,315 @@ +/* + * Generic thunking code to convert data between host and target CPU + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include + +#include "gemu.h" +#include "thunk.h" + +//#define DEBUG + +#define MAX_STRUCTS 128 + +/* XXX: make it dynamic */ +static StructEntry struct_entries[MAX_STRUCTS]; + +static inline int thunk_type_size(const argtype *type_ptr, int is_host) +{ + int type, size; + const StructEntry *se; + + type = *type_ptr; + switch(type) { + case TYPE_CHAR: + return 1; + case TYPE_SHORT: + return 2; + case TYPE_INT: + return 4; + case TYPE_LONGLONG: + case TYPE_ULONGLONG: + return 8; + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + case TYPE_PTR: + if (is_host) { + return HOST_LONG_SIZE; + } else { + return TARGET_LONG_SIZE; + } + break; + case TYPE_ARRAY: + size = type_ptr[1]; + return size * thunk_type_size(type_ptr + 2, is_host); + case TYPE_STRUCT: + se = struct_entries + type_ptr[1]; + return se->size[is_host]; + default: + return -1; + } +} + +static inline int thunk_type_align(const argtype *type_ptr, int is_host) +{ + int type; + const StructEntry *se; + + type = *type_ptr; + switch(type) { + case TYPE_CHAR: + return 1; + case TYPE_SHORT: + return 2; + case TYPE_INT: + return 4; + case TYPE_LONGLONG: + case TYPE_ULONGLONG: + return 8; + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + case TYPE_PTR: + if (is_host) { + return HOST_LONG_SIZE; + } else { + return TARGET_LONG_SIZE; + } + break; + case TYPE_ARRAY: + return thunk_type_align(type_ptr + 2, is_host); + case TYPE_STRUCT: + se = struct_entries + type_ptr[1]; + return se->align[is_host]; + default: + return -1; + } +} + +static inline const argtype *thunk_type_next(const argtype *type_ptr) +{ + int type; + + type = *type_ptr++; + switch(type) { + case TYPE_CHAR: + case TYPE_SHORT: + case TYPE_INT: + case TYPE_LONGLONG: + case TYPE_ULONGLONG: + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + return type_ptr; + case TYPE_PTR: + return thunk_type_next(type_ptr); + case TYPE_ARRAY: + return thunk_type_next(type_ptr + 1); + case TYPE_STRUCT: + return type_ptr + 1; + default: + return NULL; + } +} + +void thunk_register_struct(int id, const char *name, const argtype *types) +{ + const argtype *type_ptr; + StructEntry *se; + int nb_fields, offset, max_align, align, size, i, j; + + se = struct_entries + id; + + /* first we count the number of fields */ + type_ptr = types; + nb_fields = 0; + while (*type_ptr != TYPE_NULL) { + type_ptr = thunk_type_next(type_ptr); + nb_fields++; + } + se->field_types = types; + se->nb_fields = nb_fields; + se->name = name; +#ifdef DEBUG + printf("struct %s: id=%d nb_fields=%d\n", + se->name, id, se->nb_fields); +#endif + /* now we can alloc the data */ + + for(i = 0;i < 2; i++) { + offset = 0; + max_align = 1; + se->field_offsets[i] = malloc(nb_fields * sizeof(int)); + type_ptr = se->field_types; + for(j = 0;j < nb_fields; j++) { + size = thunk_type_size(type_ptr, i); + align = thunk_type_align(type_ptr, i); + offset = (offset + align - 1) & ~(align - 1); + se->field_offsets[i][j] = offset; + offset += size; + if (align > max_align) + max_align = align; + } + offset = (offset + max_align - 1) & ~(max_align - 1); + se->size[i] = offset; + se->align[i] = max_align; +#ifdef DEBUG + printf("%s: size=%d align=%d\n", + i == THUNK_HOST ? "host" : "target", offset, max_align); +#endif + } +} + +void thunk_register_struct_direct(int id, const char *name, StructEntry *se1) +{ + StructEntry *se; + se = struct_entries + id; + *se = *se1; + se->name = name; +} + + +/* now we can define the main conversion functions */ +const argtype *thunk_convert(void *dst, const void *src, + const argtype *type_ptr, int to_host) +{ + int type; + + type = *type_ptr++; + switch(type) { + case TYPE_CHAR: + *(uint8_t *)dst = *(uint8_t *)src; + break; + case TYPE_SHORT: + *(uint16_t *)dst = tswap16(*(uint16_t *)src); + break; + case TYPE_INT: + *(uint32_t *)dst = tswap32(*(uint32_t *)src); + break; + case TYPE_LONGLONG: + case TYPE_ULONGLONG: + *(uint64_t *)dst = tswap64(*(uint64_t *)src); + break; +#if HOST_LONG_BITS == 32 && TARGET_LONG_BITS == 32 + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + *(uint32_t *)dst = tswap32(*(uint32_t *)src); + break; +#elif HOST_LONG_BITS == 64 && TARGET_LONG_BITS == 32 + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + if (target_to_host) { + *(uint64_t *)dst = tswap32(*(uint32_t *)src); + } else { + *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff); + } + break; +#else +#error unsupported conversion +#endif + case TYPE_ARRAY: + { + int array_length, i, dst_size, src_size; + const uint8_t *s; + uint8_t *d; + + array_length = *type_ptr++; + dst_size = thunk_type_size(type_ptr, to_host); + src_size = thunk_type_size(type_ptr, 1 - to_host); + d = dst; + s = src; + for(i = 0;i < array_length; i++) { + thunk_convert(d, s, type_ptr, to_host); + d += dst_size; + s += src_size; + } + type_ptr = thunk_type_next(type_ptr); + } + break; + case TYPE_STRUCT: + { + int i; + const StructEntry *se; + const uint8_t *s; + uint8_t *d; + const argtype *field_types; + const int *dst_offsets, *src_offsets; + + se = struct_entries + *type_ptr++; + if (se->convert[0] != NULL) { + /* specific conversion is needed */ + (*se->convert[to_host])(dst, src); + } else { + /* standard struct conversion */ + field_types = se->field_types; + dst_offsets = se->field_offsets[to_host]; + src_offsets = se->field_offsets[1 - to_host]; + d = dst; + s = src; + for(i = 0;i < se->nb_fields; i++) { + field_types = thunk_convert(d + dst_offsets[i], + s + src_offsets[i], + field_types, to_host); + } + } + } + break; + default: + fprintf(stderr, "Invalid type 0x%x\n", type); + break; + } + return type_ptr; +} + +/* from em86 */ + +/* Utility function: Table-driven functions to translate bitmasks + * between X86 and Alpha formats... + */ +unsigned int target_to_host_bitmask(unsigned int x86_mask, + bitmask_transtbl * trans_tbl) +{ + bitmask_transtbl * btp; + unsigned int alpha_mask = 0; + + for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) { + if((x86_mask & btp->x86_mask) == btp->x86_bits) { + alpha_mask |= btp->alpha_bits; + } + } + return(alpha_mask); +} + +unsigned int host_to_target_bitmask(unsigned int alpha_mask, + bitmask_transtbl * trans_tbl) +{ + bitmask_transtbl * btp; + unsigned int x86_mask = 0; + + for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) { + if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) { + x86_mask |= btp->x86_mask; + } + } + return(x86_mask); +} diff --git a/thunk.h b/thunk.h new file mode 100644 index 000000000..932bbcf0d --- /dev/null +++ b/thunk.h @@ -0,0 +1,195 @@ +#ifndef THUNK_H +#define THUNK_H + +#include +#include + +#undef WORDS_BIGENDIAN +#if __BYTE_ORDER == __BIG_ENDIAN +#define WORDS_BIGENDIAN +#endif + +#ifdef WORD_BIGENDIAN +#define BSWAP_NEEDED +#endif + +/* XXX: auto autoconf */ +#define TARGET_I386 +#define TARGET_LONG_BITS 32 + + +#if defined(__alpha__) +#define HOST_LONG_BITS 64 +#else +#define HOST_LONG_BITS 32 +#endif + +#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8) +#define HOST_LONG_SIZE (TARGET_LONG_BITS / 8) + +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 void inline bswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static void inline bswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static void inline bswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#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 void inline tswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static void inline tswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static void inline 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 void inline tswap16s(uint16_t *s) +{ +} + +static void inline tswap32s(uint32_t *s) +{ +} + +static void inline tswap64s(uint64_t *s) +{ +} + +#endif + +#if TARGET_LONG_SIZE == 4 +#define tswapl(s) tswap32(s) +#define tswapls(s) tswap32s((uint32_t *)(s)) +#else +#define tswapl(s) tswap64(s) +#define tswapls(s) tswap64s((uint64_t *)(s)) +#endif + +#if TARGET_LONG_SIZE == 4 +typedef int32_t target_long; +typedef uint32_t target_ulong; +#elif TARGET_LONG_SIZE == 8 +typedef int64_t target_long; +typedef uint64_t target_ulong; +#else +#error TARGET_LONG_SIZE undefined +#endif + +/* types enums definitions */ + +typedef enum argtype { + TYPE_NULL, + TYPE_CHAR, + TYPE_SHORT, + TYPE_INT, + TYPE_LONG, + TYPE_ULONG, + TYPE_PTRVOID, /* pointer on unknown data */ + TYPE_LONGLONG, + TYPE_ULONGLONG, + TYPE_PTR, + TYPE_ARRAY, + TYPE_STRUCT, +} argtype; + +#define MK_PTR(type) TYPE_PTR, type +#define MK_ARRAY(type, size) TYPE_ARRAY, size, type +#define MK_STRUCT(id) TYPE_STRUCT, id + +#define THUNK_TARGET 0 +#define THUNK_HOST 1 + +typedef struct { + /* standard struct handling */ + const argtype *field_types; + int nb_fields; + int *field_offsets[2]; + /* special handling */ + void (*convert[2])(void *dst, const void *src); + int size[2]; + int align[2]; + const char *name; +} StructEntry; + +/* Translation table for bitmasks... */ +typedef struct bitmask_transtbl { + unsigned int x86_mask; + unsigned int x86_bits; + unsigned int alpha_mask; + unsigned int alpha_bits; +} bitmask_transtbl; + +void thunk_register_struct(int id, const char *name, const argtype *types); +void thunk_register_struct_direct(int id, const char *name, StructEntry *se1); +const argtype *thunk_convert(void *dst, const void *src, + const argtype *type_ptr, int to_host); + +unsigned int target_to_host_bitmask(unsigned int x86_mask, + bitmask_transtbl * trans_tbl); +unsigned int host_to_target_bitmask(unsigned int alpha_mask, + bitmask_transtbl * trans_tbl); + +#endif -- cgit v1.2.3 From 01ffc75bc95e2a7ea7c00dc3d7637b20f02efdef Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Feb 2003 23:00:51 +0000 Subject: avoid pt_regs clash git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf.h | 2 +- linux-user/main.c | 8 +++----- linux-user/qemu.h | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/elf.h b/elf.h index f9108c536..03f98a348 100644 --- a/elf.h +++ b/elf.h @@ -6,7 +6,7 @@ typedef uint32_t elf_greg_t; -#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t)) typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef struct user_i387_struct elf_fpregset_t; diff --git a/linux-user/main.c b/linux-user/main.c index e3950835e..09e22fef2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include "gemu.h" @@ -210,7 +208,7 @@ void usage(void) int main(int argc, char **argv) { const char *filename; - struct pt_regs regs1, *regs = ®s1; + struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; Interp_ENV *env; @@ -220,12 +218,12 @@ int main(int argc, char **argv) filename = argv[1]; /* Zero out regs */ - memset(regs, 0, sizeof(struct pt_regs)); + memset(regs, 0, sizeof(struct target_pt_regs)); /* Zero out image_info */ memset(info, 0, sizeof(struct image_info)); - if(elf_exec(filename, argv+1, __environ, regs, info) != 0) { + if(elf_exec(filename, argv+1, environ, regs, info) != 0) { printf("Error loading %s\n", filename); exit(1); } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index fa40d4d84..0b9de6b3f 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -3,7 +3,7 @@ #include "thunk.h" -struct pt_regs { +struct target_pt_regs { long ebx; long ecx; long edx; @@ -44,7 +44,7 @@ struct image_info { }; int elf_exec(const char * filename, char ** argv, char ** envp, - struct pt_regs * regs, struct image_info *infop); + struct target_pt_regs * regs, struct image_info *infop); void target_set_brk(char *new_brk); void syscall_init(void); -- cgit v1.2.3 From 3431395696562c63d7bcec10e1307ef6feac31aa Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Feb 2003 23:03:03 +0000 Subject: fixed endianness git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6 c046a42c-6fe2-441c-8c8c-71466251a162 --- thunk.h | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/thunk.h b/thunk.h index 932bbcf0d..0b83d202a 100644 --- a/thunk.h +++ b/thunk.h @@ -2,14 +2,52 @@ #define THUNK_H #include +#include + +#ifdef HAVE_BYTESWAP_H #include +#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) \ +({ \ + __u64 __x = (x); \ + ((__u64)( \ + (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \ + (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \ + (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \ + (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \ + (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \ + (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ + (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \ + (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \ +}) + +#endif #undef WORDS_BIGENDIAN #if __BYTE_ORDER == __BIG_ENDIAN #define WORDS_BIGENDIAN #endif -#ifdef WORD_BIGENDIAN +#ifdef WORDS_BIGENDIAN #define BSWAP_NEEDED #endif -- cgit v1.2.3 From b17780d52186c8bd94c722f6fc00d6d6b9fdcc5f Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Feb 2003 23:32:15 +0000 Subject: endianness fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 0ee4f1365..43d989e9a 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -335,9 +335,8 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, unsigned long interp_load_addr, int ibcs, struct image_info *info) { - unsigned int *argv, *envp, *dlinfo; - unsigned int *sp; - char **alpha_envp; + target_ulong *argv, *envp, *dlinfo; + target_ulong *sp; /* * Force 16 byte alignment here for generality. @@ -350,14 +349,13 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, sp -= argc+1; argv = sp; if (!ibcs) { - put_user(envp,--sp); - put_user(argv,--sp); + put_user(tswapl((target_ulong)envp),--sp); + put_user(tswapl((target_ulong)argv),--sp); } - alpha_envp = (char **)malloc((envc+1) * sizeof(char *)); #define NEW_AUX_ENT(id, val) \ - put_user ((id), dlinfo++); \ - put_user ((val), dlinfo++) + put_user (tswapl(id), dlinfo++); \ + put_user (tswapl(val), dlinfo++) if (exec) { /* Put this here for an ELF program interpreter */ struct elf_phdr * eppnt; @@ -377,22 +375,19 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, } NEW_AUX_ENT (AT_NULL, 0); #undef NEW_AUX_ENT - put_user((unsigned int)argc,--sp); + put_user(tswapl(argc),--sp); info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); while (argc-->0) { - put_user(p,argv++); + put_user(tswapl((target_ulong)p),argv++); while (get_user(p++)) /* nothing */ ; } put_user(0,argv); info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); - __environ = alpha_envp; while (envc-->0) { - *alpha_envp++ = (char *)p; - put_user(p,envp++); + put_user(tswapl((target_ulong)p),envp++); while (get_user(p++)) /* nothing */ ; } put_user(0,envp); - *alpha_envp = 0; info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); return sp; } @@ -544,8 +539,8 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, -static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs, - struct image_info * info) +static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; @@ -581,7 +576,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs, return -ENOEXEC; } - /* First of all, some simple consistency checks */ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || (! elf_check_arch(elf_ex.e_machine))) { @@ -608,6 +602,12 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs, return -errno; } +#ifdef BSWAP_NEEDED + elf_ppnt = elf_phdata; + for (i=0; i Date: Tue, 18 Feb 2003 23:33:18 +0000 Subject: suppressed clashes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@8 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 35 +++++++++++++++++++++++------------ linux-user/syscall_defs.h | 2 +- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d5909b221..f800fa219 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -37,7 +37,7 @@ #include #include #include -#include +//#include #define termios host_termios #define winsize host_winsize @@ -52,7 +52,7 @@ #include "gemu.h" -#define DEBUG +//#define DEBUG #ifndef PAGE_SIZE #define PAGE_SIZE 4096 @@ -73,18 +73,25 @@ struct dirent { #endif #define __NR_sys_uname __NR_uname -#define __NR_sys_getcwd __NR_getcwd +#define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_statfs __NR_statfs #define __NR_sys_fstatfs __NR_fstatfs +#define __NR_sys_getdents __NR_getdents +#ifdef __NR_gettid _syscall0(int, gettid) +#else +static int gettid(void) { + return -ENOSYS; +} +#endif _syscall1(int,sys_uname,struct new_utsname *,buf) -_syscall2(int,sys_getcwd,char *,buf,size_t,size) -_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count); +_syscall2(int,sys_getcwd1,char *,buf,size_t,size) +_syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); -_syscall2(int,sys_statfs,const char *,path,struct statfs *,buf) -_syscall2(int,sys_fstatfs,int,fd,struct statfs *,buf) +_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf) +_syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf) static inline long get_errno(long ret) { @@ -382,7 +389,9 @@ static long do_ioctl(long fd, long cmd, long arg) ie++; } arg_type = ie->arg_type; - // gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); +#ifdef DEBUG + gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); +#endif switch(arg_type[0]) { case TYPE_NULL: /* no argument */ @@ -612,9 +621,11 @@ long do_syscall(int num, long arg1, long arg2, long arg3, { long ret; struct stat st; - struct statfs *stfs; + struct kernel_statfs *stfs; - // gemu_log("syscall %d\n", num); +#ifdef DEBUG + gemu_log("syscall %d\n", num); +#endif switch(num) { case TARGET_NR_exit: _exit(arg1); @@ -1161,7 +1172,7 @@ long do_syscall(int num, long arg1, long arg2, long arg3, { struct dirent *dirp = (void *)arg2; long count = arg3; - ret = get_errno(getdents(arg1, dirp, count)); + ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { struct dirent *de; int len = ret; @@ -1277,7 +1288,7 @@ long do_syscall(int num, long arg1, long arg2, long arg3, ret = get_errno(chown((const char *)arg1, arg2, arg3)); break; case TARGET_NR_getcwd: - ret = get_errno(sys_getcwd((char *)arg1, arg2)); + ret = get_errno(sys_getcwd1((char *)arg1, arg2)); break; case TARGET_NR_capget: case TARGET_NR_capset: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index c8f25bb5b..e8357dff3 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -52,7 +52,7 @@ typedef struct { int val[2]; } kernel_fsid_t; -struct statfs { +struct kernel_statfs { int f_type; int f_bsize; int f_blocks; -- cgit v1.2.3 From 766a487abf4c006b8f1e2b997c0b39b8646e898b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Feb 2003 23:35:48 +0000 Subject: ppc build git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@9 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 32 +++++++++++++++- ppc.ld | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 ppc.ld diff --git a/Makefile b/Makefile index 4e5689a64..9f7121133 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,34 @@ +ARCH=i386 +#ARCH=ppc + +ifeq ($(ARCH),i386) CFLAGS=-Wall -O2 -g LDFLAGS=-g -DEFINES=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS +LIBS= +CC=gcc +DEFINES=-DHAVE_BYTESWAP_H +endif + +ifeq ($(ARCH),ppc) +GCC_LIBS_DIR=/usr/netgem/tools/lib/gcc-lib/powerpc-linux/2.95.2 +DIST=/home/fbe/nsv/dist/hw/n6-dtt +CC=powerpc-linux-gcc -msoft-float +CFLAGS=-Wall -pipe -O2 -mcpu=405 -mbig -nostdinc -g -I$(GCC_LIBS_DIR)/include -I$(DIST)/include +LIBS_DIR=$(DIST)/lib +CRT1=$(LIBS_DIR)/crt1.o +CRTI=$(LIBS_DIR)/crti.o +CRTN=$(LIBS_DIR)/crtn.o +CRTBEGIN=$(GCC_LIBS_DIR)/crtbegin.o +CRTEND=$(GCC_LIBS_DIR)/crtend.o +LDFLAGS=-static -g -nostdlib $(CRT1) $(CRTI) $(CRTBEGIN) +LIBS=-L$(LIBS_DIR) -ltinyc -lgcc $(CRTEND) $(CRTN) +DEFINES=-Dsocklen_t=int +endif + +######################################################### + +DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS +LDSCRIPT=$(ARCH).ld OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ @@ -12,7 +40,7 @@ SRCS = $(OBJS:.o=.c) all: gemu gemu: $(OBJS) - $(CC) -Wl,-T,i386.ld $(LDFLAGS) -o $@ $(OBJS) + $(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend diff --git a/ppc.ld b/ppc.ld new file mode 100644 index 000000000..d95b93cce --- /dev/null +++ b/ppc.ld @@ -0,0 +1,130 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} -- cgit v1.2.3 From 5147f5aac0e725ce73ee04d0f1ca39284acf456c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 Feb 2003 15:48:43 +0000 Subject: added NO_TRACE_MSGS ifdef git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@10 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 09e22fef2..544953eb2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -297,10 +297,12 @@ int main(int argc, char **argv) default: trap_error: fprintf(stderr, "GEMU: Unknown error %d, aborting\n", err); +#ifndef NO_TRACE_MSGS d_emu = 9; fprintf(stderr, "%s\n%s\n", e_print_cpuemu_regs(env, 1), e_emu_disasm(env,pc,1)); +#endif abort(); } } -- cgit v1.2.3 From 4d1135e486fcdd3b00caf524f01af7f0d56a0af7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Feb 2003 20:14:06 +0000 Subject: i386 emulator test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@11 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 38 ++++++++ tests/hello.c | 26 ++++++ tests/test-i386.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+) create mode 100644 tests/Makefile create mode 100644 tests/hello.c create mode 100644 tests/test-i386.c diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 000000000..cbe80e297 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,38 @@ +CC=gcc +CFLAGS=-Wall -O2 -g +LDFLAGS= + +TESTS=hello test1 test2 sha1 test-i386 +GEMU=../gemu + +all: $(TESTS) + +hello: hello.c + $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< + +test1: test1.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +test2: test2.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +# i386 emulation test (dump various opcodes) */ +test-i386: test-i386.c test-i386.h + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +test: test-i386 + ./test-i386 > test-i386.ref + $(GEMU) test-i386 > test-i386.out + @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi + +# speed test +sha1: sha1.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +speed: sha1 + time ./sha1 + time $(GEMU) sha1 + +# interpreter test +interp: interp.c interploop.c + $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -o $@ $^ diff --git a/tests/hello.c b/tests/hello.c new file mode 100644 index 000000000..89bd15b82 --- /dev/null +++ b/tests/hello.c @@ -0,0 +1,26 @@ +#include + +extern inline volatile void exit(int status) +{ + int __res; + __asm__ volatile ("movl %%ecx,%%ebx\n"\ + "int $0x80" \ + : "=a" (__res) : "0" (__NR_exit),"c" ((long)(status))); +} + +extern inline int write(int fd, const char * buf, int len) +{ + int status; + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%esi,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (status) \ + : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len))); +} + +void _startup(void) +{ + write(1, "Hello World\n", 12); + exit(0); +} diff --git a/tests/test-i386.c b/tests/test-i386.c new file mode 100644 index 000000000..943bbf07b --- /dev/null +++ b/tests/test-i386.c @@ -0,0 +1,261 @@ +#include +#include +#include + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s + +#define CC_C 0x0001 +#define CC_P 0x0004 +#define CC_A 0x0010 +#define CC_Z 0x0040 +#define CC_S 0x0080 +#define CC_O 0x0800 + +/* XXX: currently no A flag */ +#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O) + +#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) + +static void *call_start __init_call = NULL; + +#define OP add +#include "test-i386.h" + +#define OP sub +#include "test-i386.h" + +#define OP xor +#include "test-i386.h" + +#define OP and +#include "test-i386.h" + +#define OP or +#include "test-i386.h" + +#define OP cmp +#include "test-i386.h" + +#define OP adc +#define OP_CC +#include "test-i386.h" + +#define OP sbb +#define OP_CC +#include "test-i386.h" + +#define OP inc +#define OP_CC +#define OP1 +#include "test-i386.h" + +#define OP dec +#define OP_CC +#define OP1 +#include "test-i386.h" + +#define OP neg +#define OP_CC +#define OP1 +#include "test-i386.h" + +#define OP not +#define OP_CC +#define OP1 +#include "test-i386.h" + +/* lea test (modrm support) */ +#define TEST_LEA(STR)\ +{\ + asm("leal " STR ", %0"\ + : "=r" (res)\ + : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ + printf("lea %s = %08x\n", STR, res);\ +} + +#define TEST_LEA16(STR)\ +{\ + asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\ + : "=wq" (res)\ + : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ + printf("lea %s = %08x\n", STR, res);\ +} + + +void test_lea(void) +{ + int eax, ebx, ecx, edx, esi, edi, res; + eax = 0x0001; + ebx = 0x0002; + ecx = 0x0004; + edx = 0x0008; + esi = 0x0010; + edi = 0x0020; + + TEST_LEA("0x4000"); + + TEST_LEA("(%%eax)"); + TEST_LEA("(%%ebx)"); + TEST_LEA("(%%ecx)"); + TEST_LEA("(%%edx)"); + TEST_LEA("(%%esi)"); + TEST_LEA("(%%edi)"); + + TEST_LEA("0x40(%%eax)"); + TEST_LEA("0x40(%%ebx)"); + TEST_LEA("0x40(%%ecx)"); + TEST_LEA("0x40(%%edx)"); + TEST_LEA("0x40(%%esi)"); + TEST_LEA("0x40(%%edi)"); + + TEST_LEA("0x4000(%%eax)"); + TEST_LEA("0x4000(%%ebx)"); + TEST_LEA("0x4000(%%ecx)"); + TEST_LEA("0x4000(%%edx)"); + TEST_LEA("0x4000(%%esi)"); + TEST_LEA("0x4000(%%edi)"); + + TEST_LEA("(%%eax, %%ecx)"); + TEST_LEA("(%%ebx, %%edx)"); + TEST_LEA("(%%ecx, %%ecx)"); + TEST_LEA("(%%edx, %%ecx)"); + TEST_LEA("(%%esi, %%ecx)"); + TEST_LEA("(%%edi, %%ecx)"); + + TEST_LEA("0x40(%%eax, %%ecx)"); + TEST_LEA("0x4000(%%ebx, %%edx)"); + + TEST_LEA("(%%ecx, %%ecx, 2)"); + TEST_LEA("(%%edx, %%ecx, 4)"); + TEST_LEA("(%%esi, %%ecx, 8)"); + + TEST_LEA("(,%%eax, 2)"); + TEST_LEA("(,%%ebx, 4)"); + TEST_LEA("(,%%ecx, 8)"); + + TEST_LEA("0x40(,%%eax, 2)"); + TEST_LEA("0x40(,%%ebx, 4)"); + TEST_LEA("0x40(,%%ecx, 8)"); + + + TEST_LEA("-10(%%ecx, %%ecx, 2)"); + TEST_LEA("-10(%%edx, %%ecx, 4)"); + TEST_LEA("-10(%%esi, %%ecx, 8)"); + + TEST_LEA("0x4000(%%ecx, %%ecx, 2)"); + TEST_LEA("0x4000(%%edx, %%ecx, 4)"); + TEST_LEA("0x4000(%%esi, %%ecx, 8)"); + + /* limited 16 bit addressing test */ + TEST_LEA16("0x4000"); + TEST_LEA16("(%%bx)"); + TEST_LEA16("(%%si)"); + TEST_LEA16("(%%di)"); + TEST_LEA16("0x40(%%bx)"); + TEST_LEA16("0x40(%%si)"); + TEST_LEA16("0x40(%%di)"); + TEST_LEA16("0x4000(%%bx)"); + TEST_LEA16("0x4000(%%si)"); + TEST_LEA16("(%%bx,%%si)"); + TEST_LEA16("(%%bx,%%di)"); + TEST_LEA16("0x40(%%bx,%%si)"); + TEST_LEA16("0x40(%%bx,%%di)"); + TEST_LEA16("0x4000(%%bx,%%si)"); + TEST_LEA16("0x4000(%%bx,%%di)"); +} + +#define TEST_JCC(JCC, v1, v2)\ +{\ + asm("movl $1, %0\n\t"\ + "cmpl %2, %1\n\t"\ + JCC " 1f\n\t"\ + "movl $0, %0\n\t"\ + "1:\n\t"\ + : "=r" (res)\ + : "r" (v1), "r" (v2));\ + printf("%-10s %d\n", JCC, res);\ +} + +/* various jump tests */ +void test_jcc(void) +{ + int res; + + TEST_JCC("jne", 1, 1); + TEST_JCC("jne", 1, 0); + + TEST_JCC("je", 1, 1); + TEST_JCC("je", 1, 0); + + TEST_JCC("jl", 1, 1); + TEST_JCC("jl", 1, 0); + TEST_JCC("jl", 1, -1); + + TEST_JCC("jle", 1, 1); + TEST_JCC("jle", 1, 0); + TEST_JCC("jle", 1, -1); + + TEST_JCC("jge", 1, 1); + TEST_JCC("jge", 1, 0); + TEST_JCC("jge", -1, 1); + + TEST_JCC("jg", 1, 1); + TEST_JCC("jg", 1, 0); + TEST_JCC("jg", 1, -1); + + TEST_JCC("jb", 1, 1); + TEST_JCC("jb", 1, 0); + TEST_JCC("jb", 1, -1); + + TEST_JCC("jbe", 1, 1); + TEST_JCC("jbe", 1, 0); + TEST_JCC("jbe", 1, -1); + + TEST_JCC("jae", 1, 1); + TEST_JCC("jae", 1, 0); + TEST_JCC("jae", 1, -1); + + TEST_JCC("ja", 1, 1); + TEST_JCC("ja", 1, 0); + TEST_JCC("ja", 1, -1); + + + TEST_JCC("jp", 1, 1); + TEST_JCC("jp", 1, 0); + + TEST_JCC("jnp", 1, 1); + TEST_JCC("jnp", 1, 0); + + TEST_JCC("jo", 0x7fffffff, 0); + TEST_JCC("jo", 0x7fffffff, -1); + + TEST_JCC("jno", 0x7fffffff, 0); + TEST_JCC("jno", 0x7fffffff, -1); + + TEST_JCC("js", 0, 1); + TEST_JCC("js", 0, -1); + TEST_JCC("js", 0, 0); + + TEST_JCC("jns", 0, 1); + TEST_JCC("jns", 0, -1); + TEST_JCC("jns", 0, 0); +} + +static void *call_end __init_call = NULL; + +int main(int argc, char **argv) +{ + void **ptr; + void (*func)(void); + ptr = &call_start + 1; + while (*ptr != NULL) { + func = *ptr++; + func(); + } + test_lea(); + test_jcc(); + return 0; +} -- cgit v1.2.3 From 379ca80d34d685c038800be58d2314933619d78b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Feb 2003 23:43:02 +0000 Subject: added shift tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@12 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- tests/test-i386-shift.h | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/test-i386.c | 24 +++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 tests/test-i386-shift.h diff --git a/tests/Makefile b/tests/Makefile index cbe80e297..c6347edfc 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -17,7 +17,7 @@ test2: test2.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< # i386 emulation test (dump various opcodes) */ -test-i386: test-i386.c test-i386.h +test-i386: test-i386.c test-i386.h test-i386-shift.h $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< test: test-i386 diff --git a/tests/test-i386-shift.h b/tests/test-i386-shift.h new file mode 100644 index 000000000..af892f6c7 --- /dev/null +++ b/tests/test-i386-shift.h @@ -0,0 +1,79 @@ + +#define exec_op glue(exec_, OP) +#define exec_opl glue(glue(exec_, OP), l) +#define exec_opw glue(glue(exec_, OP), w) +#define exec_opb glue(glue(exec_, OP), b) + +#define EXECSHIFT(size, res, s1, flags) \ + asm ("push %4\n\t"\ + "popf\n\t"\ + stringify(OP) size " %%cl, %" size "0\n\t" \ + "pushf\n\t"\ + "popl %1\n\t"\ + : "=q" (res), "=g" (flags)\ + : "c" (s1), "0" (res), "1" (flags)); + +void exec_opl(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECSHIFT("", res, s1, flags); + /* overflow is undefined if count != 1 */ + if (s1 != 1) + flags &= ~CC_O; + printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK); +} + +void exec_opw(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECSHIFT("w", res, s1, flags); + /* overflow is undefined if count != 1 */ + if (s1 != 1) + flags &= ~CC_O; + printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK); +} + +void exec_opb(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECSHIFT("b", res, s1, flags); + /* overflow is undefined if count != 1 */ + if (s1 != 1) + flags &= ~CC_O; + printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK); +} + +void exec_op(int s0, int s1) +{ + exec_opl(s0, s1, 0); + exec_opw(s0, s1, 0); + exec_opb(s0, s1, 0); +#ifdef OP_CC + exec_opl(s0, s1, CC_C); + exec_opw(s0, s1, CC_C); + exec_opb(s0, s1, CC_C); +#endif +} + +void glue(test_, OP)(void) +{ + int i; + for(i = 0; i < 32; i++) + exec_op(0x12345678, i); + for(i = 0; i < 32; i++) + exec_op(0x82345678, i); +} + +void *glue(_test_, OP) __init_call = glue(test_, OP); + +#undef OP +#undef OP_CC diff --git a/tests/test-i386.c b/tests/test-i386.c index 943bbf07b..5fb9c5cd0 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -67,6 +67,30 @@ static void *call_start __init_call = NULL; #define OP1 #include "test-i386.h" +#define OP shl +#include "test-i386-shift.h" + +#define OP shr +#include "test-i386-shift.h" + +#define OP sar +#include "test-i386-shift.h" + +#define OP rol +#include "test-i386-shift.h" + +#define OP ror +#include "test-i386-shift.h" + +#define OP rcr +#define OP_CC +#include "test-i386-shift.h" + +#define OP rcl +#define OP_CC +#include "test-i386-shift.h" + + /* lea test (modrm support) */ #define TEST_LEA(STR)\ {\ -- cgit v1.2.3 From 7bfdb6d18c7bb5792c896a0bf6cf1ad7431630cb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 1 Mar 2003 14:27:54 +0000 Subject: new i386 emulator core git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@13 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 1097 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ opreg_template.h | 103 +++++ 2 files changed, 1200 insertions(+) create mode 100644 op-i386.c create mode 100644 opreg_template.h diff --git a/op-i386.c b/op-i386.c new file mode 100644 index 000000000..fdd2fa5ad --- /dev/null +++ b/op-i386.c @@ -0,0 +1,1097 @@ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +#ifdef __i386__ +register int T0 asm("esi"); +register int T1 asm("ebx"); +register int A0 asm("edi"); +register struct CPU86State *env asm("ebp"); +#define FORCE_RET() asm volatile ("ret"); +#endif +#ifdef __powerpc__ +register int T0 asm("r24"); +register int T1 asm("r25"); +register int A0 asm("r26"); +register struct CPU86State *env asm("r27"); +#define FORCE_RET() asm volatile ("blr"); +#endif +#ifdef __arm__ +register int T0 asm("r4"); +register int T1 asm("r5"); +register int A0 asm("r6"); +register struct CPU86State *env asm("r7"); +#define FORCE_RET() asm volatile ("mov pc, lr"); +#endif +#ifdef __mips__ +register int T0 asm("s0"); +register int T1 asm("s1"); +register int A0 asm("s2"); +register struct CPU86State *env asm("s3"); +#define FORCE_RET() asm volatile ("jr $31"); +#endif +#ifdef __sparc__ +register int T0 asm("l0"); +register int T1 asm("l1"); +register int A0 asm("l2"); +register struct CPU86State *env asm("l3"); +#define FORCE_RET() asm volatile ("retl ; nop"); +#endif + +#ifndef OPPROTO +#define OPPROTO +#endif + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) + +#define EAX (env->regs[R_EAX]) +#define ECX (env->regs[R_ECX]) +#define EDX (env->regs[R_EDX]) +#define EBX (env->regs[R_EBX]) +#define ESP (env->regs[R_ESP]) +#define EBP (env->regs[R_EBP]) +#define ESI (env->regs[R_ESI]) +#define EDI (env->regs[R_EDI]) +#define PC (env->pc) +#define DF (env->df) + +#define CC_SRC (env->cc_src) +#define CC_DST (env->cc_dst) +#define CC_OP (env->cc_op) + +extern int __op_param1, __op_param2, __op_param3; +#define PARAM1 ((long)(&__op_param1)) +#define PARAM2 ((long)(&__op_param2)) +#define PARAM3 ((long)(&__op_param3)) + +#include "cpu-i386.h" + +typedef struct CCTable { + int (*compute_c)(void); /* return the C flag */ + int (*compute_z)(void); /* return the Z flag */ + int (*compute_s)(void); /* return the S flag */ + int (*compute_o)(void); /* return the O flag */ + int (*compute_all)(void); /* return all the flags */ +} CCTable; + +uint8_t parity_table[256] = { + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +}; + +static int compute_eflags_all(void) +{ + return CC_SRC; +} + +static int compute_eflags_addb(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_DST - CC_SRC; + cf = (uint8_t)CC_DST < (uint8_t)src1; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_subb(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + cf = (uint8_t)src1 < (uint8_t)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_logicb(void) +{ + cf = 0; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = 0; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_incb(void) +{ + int cf, pf, af, zf, sf, of; + int src2; + src1 = CC_DST - 1; + src2 = 1; + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_decb(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_DST + 1; + src2 = 1; + cf = (uint8_t)src1 < (uint8_t)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_shlb(void) +{ + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = 0; /* undefined */ + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_shrb(void) +{ + cf = CC_SRC & 1; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = sf << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_mul(void) +{ + cf = (CC_SRC != 0); + pf = 0; /* undefined */ + af = 0; /* undefined */ + zf = 0; /* undefined */ + sf = 0; /* undefined */ + of = cf << 11; + return cf | pf | af | zf | sf | of; +} + +CTable cc_table[CC_OP_NB] = { + [CC_OP_DYNAMIC] = { NULL, NULL, NULL }, + [CC_OP_EFLAGS] = { NULL, NULL, NULL }, + +}; + +/* we define the various pieces of code used by the JIT */ + +#define REG EAX +#define REGNAME _EAX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ECX +#define REGNAME _ECX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EDX +#define REGNAME _EDX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EBX +#define REGNAME _EBX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ESP +#define REGNAME _ESP +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EBP +#define REGNAME _EBP +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ESI +#define REGNAME _ESI +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EDI +#define REGNAME _EDI +#include "opreg_template.h" +#undef REG +#undef REGNAME + +/* operations */ + +void OPPROTO op_addl_T0_T1_cc(void) +{ + CC_SRC = T0; + T0 += T1; + CC_DST = T0; +} + +void OPPROTO op_orl_T0_T1_cc(void) +{ + T0 |= T1; + CC_DST = T0; +} + +void OPPROTO op_adcl_T0_T1_cc(void) +{ + CC_SRC = T0; + T0 = T0 + T1 + cc_table[CC_OP].compute_c(); + CC_DST = T0; +} + +void OPPROTO op_sbbl_T0_T1_cc(void) +{ + CC_SRC = T0; + T0 = T0 - T1 - cc_table[CC_OP].compute_c(); + CC_DST = T0; +} + +void OPPROTO op_andl_T0_T1_cc(void) +{ + T0 &= T1; + CC_DST = T0; +} + +void OPPROTO op_subl_T0_T1_cc(void) +{ + CC_SRC = T0; + T0 -= T1; + CC_DST = T0; +} + +void OPPROTO op_xorl_T0_T1_cc(void) +{ + T0 ^= T1; + CC_DST = T0; +} + +void OPPROTO op_cmpl_T0_T1_cc(void) +{ + CC_SRC = T0; + CC_DST = T0 - T1; +} + +void OPPROTO op_notl_T0(void) +{ + T0 = ~T0; +} + +void OPPROTO op_negl_T0_cc(void) +{ + CC_SRC = 0; + T0 = -T0; + CC_DST = T0; +} + +void OPPROTO op_incl_T0_cc(void) +{ + T0++; + CC_DST = T0; +} + +void OPPROTO op_decl_T0_cc(void) +{ + T0--; + CC_DST = T0; +} + +void OPPROTO op_testl_T0_T1_cc(void) +{ + CC_SRC = T0; + CC_DST = T0 & T1; +} + +/* shifts */ + +void OPPROTO op_roll_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = T0; + T0 = (T0 << count) | (T0 >> (32 - count)); + CC_DST = T0; + CC_OP = CC_OP_ROLL; + } +} + +void OPPROTO op_rolw_T0_T1_cc(void) +{ + int count; + count = T1 & 0xf; + if (count) { + T0 = T0 & 0xffff; + CC_SRC = T0; + T0 = (T0 << count) | (T0 >> (16 - count)); + CC_DST = T0; + CC_OP = CC_OP_ROLW; + } +} + +void OPPROTO op_rolb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x7; + if (count) { + T0 = T0 & 0xff; + CC_SRC = T0; + T0 = (T0 << count) | (T0 >> (8 - count)); + CC_DST = T0; + CC_OP = CC_OP_ROLB; + } +} + +void OPPROTO op_rorl_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = T0; + T0 = (T0 >> count) | (T0 << (32 - count)); + CC_DST = T0; + CC_OP = CC_OP_RORB; + } +} + +void OPPROTO op_rorw_T0_T1_cc(void) +{ + int count; + count = T1 & 0xf; + if (count) { + CC_SRC = T0; + T0 = (T0 >> count) | (T0 << (16 - count)); + CC_DST = T0; + CC_OP = CC_OP_RORW; + } +} + +void OPPROTO op_rorb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x7; + if (count) { + CC_SRC = T0; + T0 = (T0 >> count) | (T0 << (8 - count)); + CC_DST = T0; + CC_OP = CC_OP_RORL; + } +} + +/* modulo 17 table */ +const uint8_t rclw_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, +}; + +/* modulo 9 table */ +const uint8_t rclb_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 0, 1, 2, 3, 4, +}; + +void helper_rcll_T0_T1_cc(void) +{ + int count, res; + + count = T1 & 0x1f; + if (count) { + CC_SRC = T0; + res = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)); + if (count > 1) + res |= T0 >> (33 - count); + T0 = res; + CC_DST = T0 ^ CC_SRC; /* O is in bit 31 */ + CC_SRC >>= (32 - count); /* CC is in bit 0 */ + CC_OP = CC_OP_RCLL; + } +} + +void OPPROTO op_rcll_T0_T1_cc(void) +{ + helper_rcll_T0_T1_cc(); +} + +void OPPROTO op_rclw_T0_T1_cc(void) +{ + int count; + count = rclw_table[T1 & 0x1f]; + if (count) { + T0 = T0 & 0xffff; + CC_SRC = T0; + T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) | + (T0 >> (17 - count)); + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (16 - count); + CC_OP = CC_OP_RCLW; + } +} + +void OPPROTO op_rclb_T0_T1_cc(void) +{ + int count; + count = rclb_table[T1 & 0x1f]; + if (count) { + T0 = T0 & 0xff; + CC_SRC = T0; + T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) | + (T0 >> (9 - count)); + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (8 - count); + CC_OP = CC_OP_RCLB; + } +} + +void OPPROTO op_rcrl_T0_T1_cc(void) +{ + int count, res; + count = T1 & 0x1f; + if (count) { + CC_SRC = T0; + res = (T0 >> count) | (cc_table[CC_OP].compute_c() << (32 - count)); + if (count > 1) + res |= T0 << (33 - count); + T0 = res; + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (count - 1); + CC_OP = CC_OP_RCLL; + } +} + +void OPPROTO op_rcrw_T0_T1_cc(void) +{ + int count; + count = rclw_table[T1 & 0x1f]; + if (count) { + T0 = T0 & 0xffff; + CC_SRC = T0; + T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (16 - count)) | + (T0 << (17 - count)); + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (count - 1); + CC_OP = CC_OP_RCLW; + } +} + +void OPPROTO op_rcrb_T0_T1_cc(void) +{ + int count; + count = rclb_table[T1 & 0x1f]; + if (count) { + T0 = T0 & 0xff; + CC_SRC = T0; + T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (8 - count)) | + (T0 << (9 - count)); + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (count - 1); + CC_OP = CC_OP_RCLB; + } +} + +void OPPROTO op_shll_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 << 1; + CC_DST = T0; + CC_OP = CC_OP_ADDL; + } else if (count) { + CC_SRC = T0 >> (32 - count); + T0 = T0 << count; + CC_DST = T0; + CC_OP = CC_OP_SHLL; + } +} + +void OPPROTO op_shlw_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 << 1; + CC_DST = T0; + CC_OP = CC_OP_ADDW; + } else if (count) { + CC_SRC = T0 >> (16 - count); + T0 = T0 << count; + CC_DST = T0; + CC_OP = CC_OP_SHLW; + } +} + +void OPPROTO op_shlb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 << 1; + CC_DST = T0; + CC_OP = CC_OP_ADDB; + } else if (count) { + CC_SRC = T0 >> (8 - count); + T0 = T0 << count; + CC_DST = T0; + CC_OP = CC_OP_SHLB; + } +} + +void OPPROTO op_shrl_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 >> 1; + CC_DST = T0; + CC_OP = CC_OP_SHRL; + } else if (count) { + CC_SRC = T0 >> (count - 1); + T0 = T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLL; + } +} + +void OPPROTO op_shrw_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + T0 = T0 & 0xffff; + CC_SRC = T0; + T0 = T0 >> 1; + CC_DST = T0; + CC_OP = CC_OP_SHRW; + } else if (count) { + T0 = T0 & 0xffff; + CC_SRC = T0 >> (count - 1); + T0 = T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLW; + } +} + +void OPPROTO op_shrb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + T0 = T0 & 0xff; + CC_SRC = T0; + T0 = T0 >> 1; + CC_DST = T0; + CC_OP = CC_OP_SHRB; + } else if (count) { + T0 = T0 & 0xff; + CC_SRC = T0 >> (count - 1); + T0 = T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLB; + } +} + +void OPPROTO op_sarl_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = (int32_t)T0 >> (count - 1); + T0 = (int32_t)T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLL; + } +} + +void OPPROTO op_sarw_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = (int16_t)T0 >> (count - 1); + T0 = (int16_t)T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLW; + } +} + +void OPPROTO op_sarb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = (int8_t)T0 >> (count - 1); + T0 = (int8_t)T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLB; + } +} + +/* multiply/divide */ +void OPPROTO op_mulb_AL_T0(void) +{ + unsigned int res; + res = (uint8_t)EAX * (uint8_t)T0; + EAX = (EAX & 0xffff0000) | res; + CC_SRC = (res & 0xff00); +} + +void OPPROTO op_imulb_AL_T0(void) +{ + int res; + res = (int8_t)EAX * (int8_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + CC_SRC = (res != (int8_t)res); +} + +void OPPROTO op_mulw_AX_T0(void) +{ + unsigned int res; + res = (uint16_t)EAX * (uint16_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + CC_SRC = res >> 16; +} + +void OPPROTO op_imulw_AX_T0(void) +{ + int res; + res = (int16_t)EAX * (int16_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + CC_SRC = (res != (int16_t)res); +} + +void OPPROTO op_mull_EAX_T0(void) +{ + uint64_t res; + res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0); + EAX = res; + EDX = res >> 32; + CC_SRC = res >> 32; +} + +void OPPROTO op_imull_EAX_T0(void) +{ + int64_t res; + res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0); + EAX = res; + EDX = res >> 32; + CC_SRC = (res != (int32_t)res); +} + +void OPPROTO op_imulw_T0_T1(void) +{ + int res; + res = (int16_t)T0 * (int16_t)T1; + T0 = res; + CC_SRC = (res != (int16_t)res); +} + +void OPPROTO op_imull_T0_T1(void) +{ + int64_t res; + res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T1); + T0 = res; + CC_SRC = (res != (int32_t)res); +} + +/* division, flags are undefined */ +/* XXX: add exceptions for overflow & div by zero */ +void OPPROTO op_divb_AL_T0(void) +{ + unsigned int num, den, q, r; + + num = (EAX & 0xffff); + den = (T0 & 0xff); + q = (num / den) & 0xff; + r = (num % den) & 0xff; + EAX = (EAX & 0xffff0000) | (r << 8) | q; +} + +void OPPROTO op_idivb_AL_T0(void) +{ + int num, den, q, r; + + num = (int16_t)EAX; + den = (int8_t)T0; + q = (num / den) & 0xff; + r = (num % den) & 0xff; + EAX = (EAX & 0xffff0000) | (r << 8) | q; +} + +void OPPROTO op_divw_AX_T0(void) +{ + unsigned int num, den, q, r; + + num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); + den = (T0 & 0xffff); + q = (num / den) & 0xffff; + r = (num % den) & 0xffff; + EAX = (EAX & 0xffff0000) | q; + EDX = (EDX & 0xffff0000) | r; +} + +void OPPROTO op_idivw_AX_T0(void) +{ + int num, den, q, r; + + num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); + den = (int16_t)T0; + q = (num / den) & 0xffff; + r = (num % den) & 0xffff; + EAX = (EAX & 0xffff0000) | q; + EDX = (EDX & 0xffff0000) | r; +} + +void OPPROTO op_divl_EAX_T0(void) +{ + unsigned int den, q, r; + uint64_t num; + + num = EAX | ((uint64_t)EDX << 32); + den = T0; + q = (num / den); + r = (num % den); + EAX = q; + EDX = r; +} + +void OPPROTO op_idivl_EAX_T0(void) +{ + int den, q, r; + int16_t num; + + num = EAX | ((uint64_t)EDX << 32); + den = (int16_t)T0; + q = (num / den); + r = (num % den); + EAX = q; + EDX = r; +} + +/* constant load */ + +void OPPROTO op1_movl_T0_im(void) +{ + T0 = PARAM1; +} + +void OPPROTO op1_movl_T1_im(void) +{ + T1 = PARAM1; +} + +void OPPROTO op1_movl_A0_im(void) +{ + A0 = PARAM1; +} + +/* memory access */ + +void OPPROTO op_ldub_T0_A0(void) +{ + T0 = ldub((uint8_t *)A0); +} + +void OPPROTO op_ldsb_T0_A0(void) +{ + T0 = ldsb((int8_t *)A0); +} + +void OPPROTO op_lduw_T0_A0(void) +{ + T0 = lduw((uint8_t *)A0); +} + +void OPPROTO op_ldsw_T0_A0(void) +{ + T0 = ldsw((int8_t *)A0); +} + +void OPPROTO op_ldl_T0_A0(void) +{ + T0 = ldl((uint8_t *)A0); +} + +void OPPROTO op_ldub_T1_A0(void) +{ + T1 = ldub((uint8_t *)A0); +} + +void OPPROTO op_ldsb_T1_A0(void) +{ + T1 = ldsb((int8_t *)A0); +} + +void OPPROTO op_lduw_T1_A0(void) +{ + T1 = lduw((uint8_t *)A0); +} + +void OPPROTO op_ldsw_T1_A0(void) +{ + T1 = ldsw((int8_t *)A0); +} + +void OPPROTO op_ldl_T1_A0(void) +{ + T1 = ldl((uint8_t *)A0); +} + +void OPPROTO op_stb_T0_A0(void) +{ + stb((uint8_t *)A0, T0); +} + +void OPPROTO op_stw_T0_A0(void) +{ + stw((uint8_t *)A0, T0); +} + +void OPPROTO op_stl_T0_A0(void) +{ + stl((uint8_t *)A0, T0); +} + +/* flags */ + +void OPPROTO op_set_cc_op(void) +{ + CC_OP = PARAM1; +} + +void OPPROTO op_movl_eflags_T0(void) +{ + CC_SRC = T0; + DF = (T0 & DIRECTION_FLAG) ? -1 : 1; +} + +void OPPROTO op_movb_eflags_T0(void) +{ + int cc_o; + cc_o = cc_table[CC_OP].compute_o(); + CC_SRC = T0 | (cc_o << 11); +} + +void OPPROTO op_movl_T0_eflags(void) +{ + cc_table[CC_OP].compute_eflags(); +} + +void OPPROTO op_cld(void) +{ + DF = 1; +} + +void OPPROTO op_std(void) +{ + DF = -1; +} + +/* jumps */ + +/* indirect jump */ +void OPPROTO op_jmp_T0(void) +{ + PC = T0; +} + +void OPPROTO op_jmp_im(void) +{ + PC = PARAM1; +} + +void OPPROTO op_jne_b(void) +{ + if ((uint8_t)CC_DST != 0) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO op_jne_w(void) +{ + if ((uint16_t)CC_DST != 0) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO op_jne_l(void) +{ + if (CC_DST != 0) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); /* generate a return so that gcc does not generate an + early function return */ +} + +/* string ops */ + +#define ldul ldl + +#define SUFFIX b +#define SHIFT 0 +#include "opstring_template.h" +#undef SUFFIX +#undef SHIFT + +#define SUFFIX w +#define SHIFT 1 +#include "opstring_template.h" +#undef SUFFIX +#undef SHIFT + +#define SUFFIX l +#define SHIFT 2 +#include "opstring_template.h" +#undef SUFFIX +#undef SHIFT + +/* sign extend */ + +void OPPROTO op_movsbl_T0_T0(void) +{ + T0 = (int8_t)T0; +} + +void OPPROTO op_movzbl_T0_T0(void) +{ + T0 = (uint8_t)T0; +} + +void OPPROTO op_movswl_T0_T0(void) +{ + T0 = (int16_t)T0; +} + +void OPPROTO op_movzwl_T0_T0(void) +{ + T0 = (uint16_t)T0; +} + +void OPPROTO op_movswl_EAX_AX(void) +{ + EAX = (int16_t)EAX; +} + +void OPPROTO op_movsbw_AX_AL(void) +{ + EAX = (EAX & 0xffff0000) | ((int8_t)EAX & 0xffff); +} + +void OPPROTO op_movslq_EDX_EAX(void) +{ + EDX = (int32_t)EAX >> 31; +} + +void OPPROTO op_movswl_DX_AX(void) +{ + EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff); +} + +/* push/pop */ +/* XXX: add 16 bit operand/16 bit seg variants */ + +void op_pushl_T0(void) +{ + uint32_t offset; + offset = ESP - 4; + stl((void *)offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_pushl_T1(void) +{ + uint32_t offset; + offset = ESP - 4; + stl((void *)offset, T1); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_popl_T0(void) +{ + T0 = ldl((void *)ESP); + ESP += 4; +} + +void op_addl_ESP_im(void) +{ + ESP += PARAM1; +} diff --git a/opreg_template.h b/opreg_template.h new file mode 100644 index 000000000..6cf188ffe --- /dev/null +++ b/opreg_template.h @@ -0,0 +1,103 @@ +/* templates for various register related operations */ + +void OPPROTO glue(op_movl_A0,REGNAME)(void) +{ + A0 = REG; +} + +void OPPROTO glue(op_addl_A0,REGNAME)(void) +{ + A0 += REG; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void) +{ + A0 += REG << 1; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void) +{ + A0 += REG << 2; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void) +{ + A0 += REG << 3; +} + +void OPPROTO glue(op_movl_T0,REGNAME)(void) +{ + T0 = REG; +} + +void OPPROTO glue(op_movl_T1,REGNAME)(void) +{ + T1 = REG; +} + +void OPPROTO glue(op_movh_T0,REGNAME)(void) +{ + T0 = REG >> 8; +} + +void OPPROTO glue(op_movh_T1,REGNAME)(void) +{ + T1 = REG >> 8; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void) +{ + REG = T0; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void) +{ + REG = T1; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) +{ + REG = A0; +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) +{ + REG = (REG & 0xffff0000) | (T0 & 0xffff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void) +{ + REG = (REG & 0xffff0000) | (T1 & 0xffff); +} + +/* NOTE: A0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void) +{ + REG = (REG & 0xffff0000) | (A0 & 0xffff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void) +{ + REG = (REG & 0xffffff00) | (T0 & 0xff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void) +{ + REG = (REG & 0xffff00ff) | ((T0 & 0xff) << 8); +} + +/* NOTE: T1 high order bits are ignored */ +void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void) +{ + REG = (REG & 0xffffff00) | (T1 & 0xff); +} + +/* NOTE: T1 high order bits are ignored */ +void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void) +{ + REG = (REG & 0xffff00ff) | ((T1 & 0xff) << 8); +} -- cgit v1.2.3 From 367e86e8476d6373a00d0e56a29b03c4b8f3e2ee Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 1 Mar 2003 17:13:26 +0000 Subject: new x86 CPU core git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@14 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 46 +- TODO | 5 +- cpu-i386.h | 148 ++++ dyngen.c | 521 +++++++++++++ gen-i386.h | 8 + linux-user/main.c | 36 + op-i386.c | 807 ++++++++------------ ops_template.h | 628 ++++++++++++++++ tests/Makefile | 20 +- thunk.h | 22 +- translate-i386.c | 2133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 3831 insertions(+), 543 deletions(-) create mode 100644 cpu-i386.h create mode 100644 dyngen.c create mode 100644 gen-i386.h create mode 100644 ops_template.h create mode 100644 translate-i386.c diff --git a/Makefile b/Makefile index 9f7121133..397ddf134 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ ARCH=i386 #ARCH=ppc +HOST_CC=gcc ifeq ($(ARCH),i386) -CFLAGS=-Wall -O2 -g +CFLAGS=-Wall -O2 -g -fomit-frame-pointer LDFLAGS=-g LIBS= CC=gcc @@ -27,38 +28,59 @@ endif ######################################################### -DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU #-DNO_TRACE_MSGS +DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU -DNO_TRACE_MSGS +DEFINES+=-DCONFIG_PREFIX=\"/usr/local\" LDSCRIPT=$(ARCH).ld +LIBS+=-ldl OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ i386/dis8086.o i386/emu-ldt.o +OBJS+=translate-i386.o op-i386.o OBJS+= elfload.o main.o thunk.o syscall.o - SRCS = $(OBJS:.o=.c) all: gemu gemu: $(OBJS) - $(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + $(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend +# old i386 emulator +i386/interp_32_32.o: i386/interp_32_32.c i386/interp_gen.h + +i386/interp_gen.h: i386/gencode + ./i386/gencode > $@ + +i386/gencode: i386/gencode.c + $(CC) -O2 -Wall -g $< -o $@ + +# new i386 emulator +dyngen: dyngen.c + $(HOST_CC) -O2 -Wall -g $< -o $@ + +translate-i386.o: translate-i386.c op-i386.h cpu-i386.h + +op-i386.h: op-i386.o dyngen + ./dyngen -o $@ $< + +op-i386.o: op-i386.c opreg_template.h ops_template.h + $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< clean: - rm -f *.o *~ i386/*.o i386/*~ gemu hello test1 test2 TAGS - -hello: hello.c - $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< + rm -f *.o *~ i386/*.o i386/*~ gemu TAGS -test1: test1.c - $(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $< +# various test targets +test speed: gemu + make -C tests $@ -test2: test2.c - $(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $< +TAGS: + etags *.[ch] i386/*.[ch] ifneq ($(wildcard .depend),) include .depend diff --git a/TODO b/TODO index 045f877f4..7ba6ab4a7 100644 --- a/TODO +++ b/TODO @@ -1,2 +1,5 @@ -- swap all elf paramters +- tests +- signals +- threads - fix printf for doubles (fp87.c bug ?) +- make it self runnable (use same trick as ld.so : include its own relocator and libc) diff --git a/cpu-i386.h b/cpu-i386.h new file mode 100644 index 000000000..a857efb7d --- /dev/null +++ b/cpu-i386.h @@ -0,0 +1,148 @@ +#ifndef CPU_I386_H +#define CPU_I386_H + +#define R_EAX 0 +#define R_ECX 1 +#define R_EDX 2 +#define R_EBX 3 +#define R_ESP 4 +#define R_EBP 5 +#define R_ESI 6 +#define R_EDI 7 + +#define R_AL 0 +#define R_CL 1 +#define R_DL 2 +#define R_BL 3 +#define R_AH 4 +#define R_CH 5 +#define R_DH 6 +#define R_BH 7 + +#define R_ES 0 +#define R_CS 1 +#define R_SS 2 +#define R_DS 3 +#define R_FS 4 +#define R_GS 5 + +#define CC_C 0x0001 +#define CC_P 0x0004 +#define CC_A 0x0010 +#define CC_Z 0x0040 +#define CC_S 0x0080 +#define CC_O 0x0800 + +#define TRAP_FLAG 0x0100 +#define INTERRUPT_FLAG 0x0200 +#define DIRECTION_FLAG 0x0400 +#define IOPL_FLAG_MASK 0x3000 +#define NESTED_FLAG 0x4000 +#define BYTE_FL 0x8000 /* Intel reserved! */ +#define RF_FLAG 0x10000 +#define VM_FLAG 0x20000 +/* AC 0x40000 */ + +enum { + CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ + CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ + CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */ + + CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ + CC_OP_ADDW, + CC_OP_ADDL, + + CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ + CC_OP_SUBW, + CC_OP_SUBL, + + CC_OP_LOGICB, /* modify all flags, CC_DST = res */ + CC_OP_LOGICW, + CC_OP_LOGICL, + + CC_OP_INCB, /* modify all flags except, CC_DST = res */ + CC_OP_INCW, + CC_OP_INCL, + + CC_OP_DECB, /* modify all flags except, CC_DST = res */ + CC_OP_DECW, + CC_OP_DECL, + + CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ + CC_OP_SHLW, + CC_OP_SHLL, + + CC_OP_NB, +}; + +typedef struct CPU86State { + /* standard registers */ + uint32_t regs[8]; + uint32_t pc; /* cs_case + eip value */ + + /* eflags handling */ + uint32_t eflags; + uint32_t cc_src; + uint32_t cc_dst; + uint32_t cc_op; + int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ + + /* segments */ + uint8_t *segs_base[6]; + uint32_t segs[6]; + + /* emulator internal variables */ + uint32_t t0; /* temporary t0 storage */ + uint32_t t1; /* temporary t1 storage */ + uint32_t a0; /* temporary a0 storage (address) */ +} CPU86State; + +static inline int ldub(void *ptr) +{ + return *(uint8_t *)ptr; +} + +static inline int ldsb(void *ptr) +{ + return *(int8_t *)ptr; +} + +static inline int lduw(void *ptr) +{ + return *(uint16_t *)ptr; +} + +static inline int ldsw(void *ptr) +{ + return *(int16_t *)ptr; +} + +static inline int ldl(void *ptr) +{ + return *(uint32_t *)ptr; +} + + +static inline void stb(void *ptr, int v) +{ + *(uint8_t *)ptr = v; +} + +static inline void stw(void *ptr, int v) +{ + *(uint16_t *)ptr = v; +} + +static inline void stl(void *ptr, int v) +{ + *(uint32_t *)ptr = v; +} + +void port_outb(int addr, int val); +void port_outw(int addr, int val); +void port_outl(int addr, int val); +int port_inb(int addr); +int port_inw(int addr); +int port_inl(int addr); + +#endif /* CPU_I386_H */ diff --git a/dyngen.c b/dyngen.c new file mode 100644 index 000000000..ff10891b9 --- /dev/null +++ b/dyngen.c @@ -0,0 +1,521 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "thunk.h" + +/* all dynamically generated functions begin with this code */ +#define OP_PREFIX "op" + +int elf_must_swap(Elf32_Ehdr *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 swab16s(uint16_t *p) +{ + *p = bswap16(*p); +} + +void swab32s(uint32_t *p) +{ + *p = bswap32(*p); +} + +void swab64s(uint32_t *p) +{ + *p = bswap64(*p); +} + +void elf_swap_ehdr(Elf32_Ehdr *h) +{ + swab16s(&h->e_type); /* Object file type */ + swab16s(&h-> e_machine); /* Architecture */ + swab32s(&h-> e_version); /* Object file version */ + swab32s(&h-> e_entry); /* Entry point virtual address */ + swab32s(&h-> e_phoff); /* Program header table file offset */ + swab32s(&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(Elf32_Shdr *h) +{ + swab32s(&h-> sh_name); /* Section name (string tbl index) */ + swab32s(&h-> sh_type); /* Section type */ + swab32s(&h-> sh_flags); /* Section flags */ + swab32s(&h-> sh_addr); /* Section virtual addr at execution */ + swab32s(&h-> sh_offset); /* Section file offset */ + swab32s(&h-> sh_size); /* Section size in bytes */ + swab32s(&h-> sh_link); /* Link to another section */ + swab32s(&h-> sh_info); /* Additional section information */ + swab32s(&h-> sh_addralign); /* Section alignment */ + swab32s(&h-> sh_entsize); /* Entry size if section holds table */ +} + +void elf_swap_phdr(Elf32_Phdr *h) +{ + swab32s(&h->p_type); /* Segment type */ + swab32s(&h->p_offset); /* Segment file offset */ + swab32s(&h->p_vaddr); /* Segment virtual address */ + swab32s(&h->p_paddr); /* Segment physical address */ + swab32s(&h->p_filesz); /* Segment size in file */ + swab32s(&h->p_memsz); /* Segment size in memory */ + swab32s(&h->p_flags); /* Segment flags */ + swab32s(&h->p_align); /* Segment alignment */ +} + +int do_swap; +int e_machine; + +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; +} + +void __attribute__((noreturn)) 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); +} + + +Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr, + const char *name) +{ + int i; + const char *shname; + Elf32_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; +} + +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; +} + +#define MAX_ARGS 3 + +/* generate op code */ +void gen_code(const char *name, unsigned long offset, unsigned long size, + FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type, + Elf32_Sym *symtab, char *strtab) +{ + int copy_size = 0; + uint8_t *p_start, *p_end; + int nb_args, i; + uint8_t args_present[MAX_ARGS]; + const char *sym_name, *p; + + /* compute exact size excluding return instruction */ + p_start = text + offset; + p_end = p_start + size; + switch(e_machine) { + case EM_386: + { + uint8_t *p; + p = p_end - 1; + /* find ret */ + while (p > p_start && *p != 0xc3) + p--; + /* skip double ret */ + if (p > p_start && p[-1] == 0xc3) + p--; + if (p == p_start) + error("empty code for %s", name); + copy_size = p - p_start; + } + break; + case EM_PPC: + { + uint8_t *p; + p = (void *)(p_end - 4); + /* find ret */ + while (p > p_start && get32((uint32_t *)p) != 0x4e800020) + p -= 4; + /* skip double ret */ + if (p > p_start && get32((uint32_t *)(p - 4)) == 0x4e800020) + p -= 4; + if (p == p_start) + error("empty code for %s", name); + copy_size = p - p_start; + } + break; + default: + error("unsupported CPU (%d)", e_machine); + } + + /* compute the number of arguments by looking at the relocations */ + for(i = 0;i < MAX_ARGS; i++) + args_present[i] = 0; + + if (reloc_sh_type == SHT_REL) { + Elf32_Rel *rel; + int n; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + n = strtoul(p, NULL, 10); + if (n >= MAX_ARGS) + error("too many arguments in %s", name); + args_present[n - 1] = 1; + } + } + } + } else { + Elf32_Rela *rel; + int n; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + 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); + } + + /* output C code */ + fprintf(outfile, "extern void %s();\n", name); + 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"); + fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size); + + /* patch relocations */ + switch(e_machine) { + case EM_386: + { + Elf32_Rel *rel; + char name[256]; + int type; + long addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = get32((uint32_t *)(text + rel->r_offset)); + switch(type) { + case R_386_32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + rel->r_offset - offset, name, addend); + break; + case R_386_PC32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s - (long)(gen_code_ptr + %ld) + %ld;\n", + rel->r_offset - offset, name, rel->r_offset - offset, addend); + break; + default: + error("unsupported i386 relocation (%d)", type); + } + } + } + } + break; + default: + error("unsupported CPU for relocations (%d)", e_machine); + } + + + fprintf(outfile, " gen_code_ptr += %d;\n", copy_size); + fprintf(outfile, "}\n\n"); +} + +/* load an elf object file */ +int load_elf(const char *filename, FILE *outfile) +{ + int fd; + Elf32_Ehdr ehdr; + Elf32_Shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec; + int i, j, nb_syms; + Elf32_Sym *symtab, *sym; + const char *cpu_name; + char *shstr, *strtab; + uint8_t *text; + void *relocs; + int nb_relocs, reloc_sh_type; + + 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_CLASS] != ELFCLASS32 + || 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_type != ET_REL) + error("ELF object file expected"); + if (ehdr.e_version != EV_CURRENT) + error("Invalid ELF version"); + e_machine = ehdr.e_machine; + + /* read section headers */ + shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(Elf32_Shdr)); + if (do_swap) { + for(i = 0; i < ehdr.e_shnum; i++) { + elf_swap_shdr(&shdr[i]); + } + } + + sec = &shdr[ehdr.e_shstrndx]; + shstr = load_data(fd, sec->sh_offset, sec->sh_size); + + /* text section */ + + text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text"); + if (!text_sec) + error("could not find .text section"); + text = load_data(fd, text_sec->sh_offset, text_sec->sh_size); + + /* find text relocations, if any */ + nb_relocs = 0; + relocs = NULL; + reloc_sh_type = 0; + for(i = 0; i < ehdr.e_shnum; i++) { + sec = &shdr[i]; + if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) && + sec->sh_info == (text_sec - shdr)) { + reloc_sh_type = sec->sh_type; + relocs = load_data(fd, sec->sh_offset, sec->sh_size); + nb_relocs = sec->sh_size / sec->sh_entsize; + if (do_swap) { + if (sec->sh_type == SHT_REL) { + Elf32_Rel *rel = relocs; + for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { + swab32s(&rel->r_offset); + swab32s(&rel->r_info); + } + } else { + Elf32_Rela *rel = relocs; + for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { + swab32s(&rel->r_offset); + swab32s(&rel->r_info); + swab32s(&rel->r_addend); + } + } + } + break; + } + } + + 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 = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size); + strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size); + + nb_syms = symtab_sec->sh_size / sizeof(Elf32_Sym); + if (do_swap) { + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + swab32s(&sym->st_name); + swab32s(&sym->st_value); + swab32s(&sym->st_size); + swab16s(&sym->st_shndx); + } + } + + switch(e_machine) { + case EM_386: + cpu_name = "i386"; + break; + case EM_PPC: + cpu_name = "ppc"; + break; + case EM_MIPS: + cpu_name = "mips"; + break; + case EM_ARM: + cpu_name = "arm"; + break; + case EM_SPARC: + cpu_name = "sparc"; + break; + default: + error("unsupported CPU (e_machine=%d)", e_machine); + } + + fprintf(outfile, "#include \"gen-%s.h\"\n\n", cpu_name); + + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + const char *name; + name = strtab + sym->st_name; + if (strstart(name, "op_", NULL) || + strstart(name, "op1_", NULL) || + strstart(name, "op2_", NULL) || + strstart(name, "op3_", NULL)) { +#if 0 + printf("%4d: %s pos=0x%08x len=%d\n", + i, name, sym->st_value, sym->st_size); +#endif + if (sym->st_shndx != (text_sec - shdr)) + error("invalid section for opcode (0x%x)", sym->st_shndx); + gen_code(name, sym->st_value, sym->st_size, outfile, + text, relocs, nb_relocs, reloc_sh_type, symtab, strtab); + } + } + + close(fd); + return 0; +} + +void usage(void) +{ + printf("dyngen (c) 2003 Fabrice Bellard\n" + "usage: dyngen [-o outfile] objfile\n" + "Generate a dynamic code generator from an object file\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int c; + const char *filename, *outfilename; + FILE *outfile; + + outfilename = "out.c"; + for(;;) { + c = getopt(argc, argv, "ho:"); + if (c == -1) + break; + switch(c) { + case 'h': + usage(); + break; + case 'o': + outfilename = optarg; + break; + } + } + if (optind >= argc) + usage(); + filename = argv[optind]; + outfile = fopen(outfilename, "w"); + if (!outfile) + error("could not open '%s'", outfilename); + load_elf(filename, outfile); + fclose(outfile); + return 0; +} diff --git a/gen-i386.h b/gen-i386.h new file mode 100644 index 000000000..a5d7f5989 --- /dev/null +++ b/gen-i386.h @@ -0,0 +1,8 @@ +static inline void gen_start(void) +{ +} + +static inline void gen_end(void) +{ + *gen_code_ptr++ = 0xc3; /* ret */ +} diff --git a/linux-user/main.c b/linux-user/main.c index 544953eb2..1d76d4d7c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -191,6 +191,41 @@ void INT_handler(int num, void *env) } /***********************************************************/ +/* new CPU core */ + +void port_outb(int addr, int val) +{ + fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); +} + +void port_outw(int addr, int val) +{ + fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); +} + +void port_outl(int addr, int val) +{ + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); +} + +int port_inb(int addr) +{ + fprintf(stderr, "inb: port=0x%04x\n", addr); + return 0; +} + +int port_inw(int addr) +{ + fprintf(stderr, "inw: port=0x%04x\n", addr); + return 0; +} + +int port_inl(int addr) +{ + fprintf(stderr, "inl: port=0x%04x\n", addr); + return 0; +} + /* XXX: currently we use LDT entries */ #define __USER_CS (0x23|4) @@ -270,6 +305,7 @@ int main(int argc, char **argv) LDT[__USER_DS >> 3].dwSelLimit = 0xfffff; LDT[__USER_DS >> 3].lpSelBase = NULL; init_npu(); + build_decode_tables(); for(;;) { int err; diff --git a/op-i386.c b/op-i386.c index fdd2fa5ad..8607cf455 100644 --- a/op-i386.c +++ b/op-i386.c @@ -8,6 +8,8 @@ typedef signed short int16_t; typedef signed int int32_t; typedef signed long long int64_t; +#define NULL 0 + #ifdef __i386__ register int T0 asm("esi"); register int T1 asm("ebx"); @@ -74,13 +76,12 @@ extern int __op_param1, __op_param2, __op_param3; #include "cpu-i386.h" typedef struct CCTable { - int (*compute_c)(void); /* return the C flag */ - int (*compute_z)(void); /* return the Z flag */ - int (*compute_s)(void); /* return the S flag */ - int (*compute_o)(void); /* return the O flag */ int (*compute_all)(void); /* return all the flags */ + int (*compute_c)(void); /* return the C flag */ } CCTable; +extern CCTable cc_table[]; + uint8_t parity_table[256] = { CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, @@ -116,120 +117,30 @@ uint8_t parity_table[256] = { 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, }; -static int compute_eflags_all(void) -{ - return CC_SRC; -} - -static int compute_eflags_addb(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_SRC; - src2 = CC_DST - CC_SRC; - cf = (uint8_t)CC_DST < (uint8_t)src1; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((uint8_t)CC_DST != 0) << 6; - sf = CC_DST & 0x80; - of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; - return cf | pf | af | zf | sf | of; -} - -static int compute_eflags_subb(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; - cf = (uint8_t)src1 < (uint8_t)src2; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((uint8_t)CC_DST != 0) << 6; - sf = CC_DST & 0x80; - of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; - return cf | pf | af | zf | sf | of; -} - -static int compute_eflags_logicb(void) -{ - cf = 0; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; - zf = ((uint8_t)CC_DST != 0) << 6; - sf = CC_DST & 0x80; - of = 0; - return cf | pf | af | zf | sf | of; -} - -static int compute_eflags_incb(void) -{ - int cf, pf, af, zf, sf, of; - int src2; - src1 = CC_DST - 1; - src2 = 1; - cf = CC_SRC; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((uint8_t)CC_DST != 0) << 6; - sf = CC_DST & 0x80; - of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; - return cf | pf | af | zf | sf | of; -} - -static int compute_eflags_decb(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_DST + 1; - src2 = 1; - cf = (uint8_t)src1 < (uint8_t)src2; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((uint8_t)CC_DST != 0) << 6; - sf = CC_DST & 0x80; - of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; - return cf | pf | af | zf | sf | of; -} - -static int compute_eflags_shlb(void) -{ - cf = CC_SRC; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; /* undefined */ - zf = ((uint8_t)CC_DST != 0) << 6; - sf = CC_DST & 0x80; - of = 0; /* undefined */ - return cf | pf | af | zf | sf | of; -} +/* modulo 17 table */ +const uint8_t rclw_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, +}; -static int compute_eflags_shrb(void) -{ - cf = CC_SRC & 1; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; /* undefined */ - zf = ((uint8_t)CC_DST != 0) << 6; - sf = CC_DST & 0x80; - of = sf << 4; - return cf | pf | af | zf | sf | of; -} +/* modulo 9 table */ +const uint8_t rclb_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 0, 1, 2, 3, 4, +}; -static int compute_eflags_mul(void) +/* n must be a constant to be efficient */ +static inline int lshift(int x, int n) { - cf = (CC_SRC != 0); - pf = 0; /* undefined */ - af = 0; /* undefined */ - zf = 0; /* undefined */ - sf = 0; /* undefined */ - of = cf << 11; - return cf | pf | af | zf | sf | of; + if (n >= 0) + return x << n; + else + return x >> (-n); } - -CTable cc_table[CC_OP_NB] = { - [CC_OP_DYNAMIC] = { NULL, NULL, NULL }, - [CC_OP_EFLAGS] = { NULL, NULL, NULL }, - -}; /* we define the various pieces of code used by the JIT */ @@ -365,338 +276,6 @@ void OPPROTO op_testl_T0_T1_cc(void) CC_DST = T0 & T1; } -/* shifts */ - -void OPPROTO op_roll_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - CC_SRC = T0; - T0 = (T0 << count) | (T0 >> (32 - count)); - CC_DST = T0; - CC_OP = CC_OP_ROLL; - } -} - -void OPPROTO op_rolw_T0_T1_cc(void) -{ - int count; - count = T1 & 0xf; - if (count) { - T0 = T0 & 0xffff; - CC_SRC = T0; - T0 = (T0 << count) | (T0 >> (16 - count)); - CC_DST = T0; - CC_OP = CC_OP_ROLW; - } -} - -void OPPROTO op_rolb_T0_T1_cc(void) -{ - int count; - count = T1 & 0x7; - if (count) { - T0 = T0 & 0xff; - CC_SRC = T0; - T0 = (T0 << count) | (T0 >> (8 - count)); - CC_DST = T0; - CC_OP = CC_OP_ROLB; - } -} - -void OPPROTO op_rorl_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - CC_SRC = T0; - T0 = (T0 >> count) | (T0 << (32 - count)); - CC_DST = T0; - CC_OP = CC_OP_RORB; - } -} - -void OPPROTO op_rorw_T0_T1_cc(void) -{ - int count; - count = T1 & 0xf; - if (count) { - CC_SRC = T0; - T0 = (T0 >> count) | (T0 << (16 - count)); - CC_DST = T0; - CC_OP = CC_OP_RORW; - } -} - -void OPPROTO op_rorb_T0_T1_cc(void) -{ - int count; - count = T1 & 0x7; - if (count) { - CC_SRC = T0; - T0 = (T0 >> count) | (T0 << (8 - count)); - CC_DST = T0; - CC_OP = CC_OP_RORL; - } -} - -/* modulo 17 table */ -const uint8_t rclw_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9,10,11,12,13,14,15, - 16, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9,10,11,12,13,14, -}; - -/* modulo 9 table */ -const uint8_t rclb_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 0, 1, 2, 3, 4, -}; - -void helper_rcll_T0_T1_cc(void) -{ - int count, res; - - count = T1 & 0x1f; - if (count) { - CC_SRC = T0; - res = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)); - if (count > 1) - res |= T0 >> (33 - count); - T0 = res; - CC_DST = T0 ^ CC_SRC; /* O is in bit 31 */ - CC_SRC >>= (32 - count); /* CC is in bit 0 */ - CC_OP = CC_OP_RCLL; - } -} - -void OPPROTO op_rcll_T0_T1_cc(void) -{ - helper_rcll_T0_T1_cc(); -} - -void OPPROTO op_rclw_T0_T1_cc(void) -{ - int count; - count = rclw_table[T1 & 0x1f]; - if (count) { - T0 = T0 & 0xffff; - CC_SRC = T0; - T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) | - (T0 >> (17 - count)); - CC_DST = T0 ^ CC_SRC; - CC_SRC >>= (16 - count); - CC_OP = CC_OP_RCLW; - } -} - -void OPPROTO op_rclb_T0_T1_cc(void) -{ - int count; - count = rclb_table[T1 & 0x1f]; - if (count) { - T0 = T0 & 0xff; - CC_SRC = T0; - T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) | - (T0 >> (9 - count)); - CC_DST = T0 ^ CC_SRC; - CC_SRC >>= (8 - count); - CC_OP = CC_OP_RCLB; - } -} - -void OPPROTO op_rcrl_T0_T1_cc(void) -{ - int count, res; - count = T1 & 0x1f; - if (count) { - CC_SRC = T0; - res = (T0 >> count) | (cc_table[CC_OP].compute_c() << (32 - count)); - if (count > 1) - res |= T0 << (33 - count); - T0 = res; - CC_DST = T0 ^ CC_SRC; - CC_SRC >>= (count - 1); - CC_OP = CC_OP_RCLL; - } -} - -void OPPROTO op_rcrw_T0_T1_cc(void) -{ - int count; - count = rclw_table[T1 & 0x1f]; - if (count) { - T0 = T0 & 0xffff; - CC_SRC = T0; - T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (16 - count)) | - (T0 << (17 - count)); - CC_DST = T0 ^ CC_SRC; - CC_SRC >>= (count - 1); - CC_OP = CC_OP_RCLW; - } -} - -void OPPROTO op_rcrb_T0_T1_cc(void) -{ - int count; - count = rclb_table[T1 & 0x1f]; - if (count) { - T0 = T0 & 0xff; - CC_SRC = T0; - T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (8 - count)) | - (T0 << (9 - count)); - CC_DST = T0 ^ CC_SRC; - CC_SRC >>= (count - 1); - CC_OP = CC_OP_RCLB; - } -} - -void OPPROTO op_shll_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count == 1) { - CC_SRC = T0; - T0 = T0 << 1; - CC_DST = T0; - CC_OP = CC_OP_ADDL; - } else if (count) { - CC_SRC = T0 >> (32 - count); - T0 = T0 << count; - CC_DST = T0; - CC_OP = CC_OP_SHLL; - } -} - -void OPPROTO op_shlw_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count == 1) { - CC_SRC = T0; - T0 = T0 << 1; - CC_DST = T0; - CC_OP = CC_OP_ADDW; - } else if (count) { - CC_SRC = T0 >> (16 - count); - T0 = T0 << count; - CC_DST = T0; - CC_OP = CC_OP_SHLW; - } -} - -void OPPROTO op_shlb_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count == 1) { - CC_SRC = T0; - T0 = T0 << 1; - CC_DST = T0; - CC_OP = CC_OP_ADDB; - } else if (count) { - CC_SRC = T0 >> (8 - count); - T0 = T0 << count; - CC_DST = T0; - CC_OP = CC_OP_SHLB; - } -} - -void OPPROTO op_shrl_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count == 1) { - CC_SRC = T0; - T0 = T0 >> 1; - CC_DST = T0; - CC_OP = CC_OP_SHRL; - } else if (count) { - CC_SRC = T0 >> (count - 1); - T0 = T0 >> count; - CC_DST = T0; - CC_OP = CC_OP_SHLL; - } -} - -void OPPROTO op_shrw_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count == 1) { - T0 = T0 & 0xffff; - CC_SRC = T0; - T0 = T0 >> 1; - CC_DST = T0; - CC_OP = CC_OP_SHRW; - } else if (count) { - T0 = T0 & 0xffff; - CC_SRC = T0 >> (count - 1); - T0 = T0 >> count; - CC_DST = T0; - CC_OP = CC_OP_SHLW; - } -} - -void OPPROTO op_shrb_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count == 1) { - T0 = T0 & 0xff; - CC_SRC = T0; - T0 = T0 >> 1; - CC_DST = T0; - CC_OP = CC_OP_SHRB; - } else if (count) { - T0 = T0 & 0xff; - CC_SRC = T0 >> (count - 1); - T0 = T0 >> count; - CC_DST = T0; - CC_OP = CC_OP_SHLB; - } -} - -void OPPROTO op_sarl_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - CC_SRC = (int32_t)T0 >> (count - 1); - T0 = (int32_t)T0 >> count; - CC_DST = T0; - CC_OP = CC_OP_SHLL; - } -} - -void OPPROTO op_sarw_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - CC_SRC = (int16_t)T0 >> (count - 1); - T0 = (int16_t)T0 >> count; - CC_DST = T0; - CC_OP = CC_OP_SHLW; - } -} - -void OPPROTO op_sarb_T0_T1_cc(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - CC_SRC = (int8_t)T0 >> (count - 1); - T0 = (int8_t)T0 >> count; - CC_DST = T0; - CC_OP = CC_OP_SHLB; - } -} - /* multiply/divide */ void OPPROTO op_mulb_AL_T0(void) { @@ -924,41 +503,6 @@ void OPPROTO op_stl_T0_A0(void) stl((uint8_t *)A0, T0); } -/* flags */ - -void OPPROTO op_set_cc_op(void) -{ - CC_OP = PARAM1; -} - -void OPPROTO op_movl_eflags_T0(void) -{ - CC_SRC = T0; - DF = (T0 & DIRECTION_FLAG) ? -1 : 1; -} - -void OPPROTO op_movb_eflags_T0(void) -{ - int cc_o; - cc_o = cc_table[CC_OP].compute_o(); - CC_SRC = T0 | (cc_o << 11); -} - -void OPPROTO op_movl_T0_eflags(void) -{ - cc_table[CC_OP].compute_eflags(); -} - -void OPPROTO op_cld(void) -{ - DF = 1; -} - -void OPPROTO op_std(void) -{ - DF = -1; -} - /* jumps */ /* indirect jump */ @@ -972,54 +516,20 @@ void OPPROTO op_jmp_im(void) PC = PARAM1; } -void OPPROTO op_jne_b(void) -{ - if ((uint8_t)CC_DST != 0) - PC += PARAM1; - else - PC += PARAM2; - FORCE_RET(); -} - -void OPPROTO op_jne_w(void) -{ - if ((uint16_t)CC_DST != 0) - PC += PARAM1; - else - PC += PARAM2; - FORCE_RET(); -} - -void OPPROTO op_jne_l(void) -{ - if (CC_DST != 0) - PC += PARAM1; - else - PC += PARAM2; - FORCE_RET(); /* generate a return so that gcc does not generate an - early function return */ -} - /* string ops */ #define ldul ldl -#define SUFFIX b #define SHIFT 0 -#include "opstring_template.h" -#undef SUFFIX +#include "ops_template.h" #undef SHIFT -#define SUFFIX w #define SHIFT 1 -#include "opstring_template.h" -#undef SUFFIX +#include "ops_template.h" #undef SHIFT -#define SUFFIX l #define SHIFT 2 -#include "opstring_template.h" -#undef SUFFIX +#include "ops_template.h" #undef SHIFT /* sign extend */ @@ -1095,3 +605,264 @@ void op_addl_ESP_im(void) { ESP += PARAM1; } + +/* flags handling */ + +/* slow jumps cases (compute x86 flags) */ +void OPPROTO op_jo_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_O) + PC += PARAM1; + else + PC += PARAM2; +} + +void OPPROTO op_jb_cc(void) +{ + if (cc_table[CC_OP].compute_c()) + PC += PARAM1; + else + PC += PARAM2; +} + +void OPPROTO op_jz_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_Z) + PC += PARAM1; + else + PC += PARAM2; +} + +void OPPROTO op_jbe_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & (CC_Z | CC_C)) + PC += PARAM1; + else + PC += PARAM2; +} + +void OPPROTO op_js_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_S) + PC += PARAM1; + else + PC += PARAM2; +} + +void OPPROTO op_jp_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_P) + PC += PARAM1; + else + PC += PARAM2; +} + +void OPPROTO op_jl_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if ((eflags ^ (eflags >> 4)) & 0x80) + PC += PARAM1; + else + PC += PARAM2; +} + +void OPPROTO op_jle_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) + PC += PARAM1; + else + PC += PARAM2; +} + +/* slow set cases (compute x86 flags) */ +void OPPROTO op_seto_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags >> 11) & 1; +} + +void OPPROTO op_setb_T0_cc(void) +{ + T0 = cc_table[CC_OP].compute_c(); +} + +void OPPROTO op_setz_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags >> 6) & 1; +} + +void OPPROTO op_setbe_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags & (CC_Z | CC_C)) != 0; +} + +void OPPROTO op_sets_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags >> 7) & 1; +} + +void OPPROTO op_setp_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags >> 2) & 1; +} + +void OPPROTO op_setl_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = ((eflags ^ (eflags >> 4)) >> 7) & 1; +} + +void OPPROTO op_setle_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) != 0; +} + +void OPPROTO op_xor_T0_1(void) +{ + T0 ^= 1; +} + +void OPPROTO op_set_cc_op(void) +{ + CC_OP = PARAM1; +} + +void OPPROTO op_movl_eflags_T0(void) +{ + CC_SRC = T0; + DF = 1 - (2 * ((T0 >> 10) & 1)); +} + +/* XXX: compute only O flag */ +void OPPROTO op_movb_eflags_T0(void) +{ + int of; + of = cc_table[CC_OP].compute_all() & CC_O; + CC_SRC = T0 | of; +} + +void OPPROTO op_movl_T0_eflags(void) +{ + T0 = cc_table[CC_OP].compute_all(); + T0 |= (DF & DIRECTION_FLAG); +} + +void OPPROTO op_cld(void) +{ + DF = 1; +} + +void OPPROTO op_std(void) +{ + DF = -1; +} + +void OPPROTO op_clc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags &= ~CC_C; + CC_SRC = eflags; +} + +void OPPROTO op_stc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= CC_C; + CC_SRC = eflags; +} + +void OPPROTO op_cmc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags ^= CC_C; + CC_SRC = eflags; +} + +static int compute_all_eflags(void) +{ + return CC_SRC; +} + +static int compute_c_eflags(void) +{ + return CC_SRC & CC_C; +} + +static int compute_c_mul(void) +{ + int cf; + cf = (CC_SRC != 0); + return cf; +} + +static int compute_all_mul(void) +{ + int cf, pf, af, zf, sf, of; + cf = (CC_SRC != 0); + pf = 0; /* undefined */ + af = 0; /* undefined */ + zf = 0; /* undefined */ + sf = 0; /* undefined */ + of = cf << 11; + return cf | pf | af | zf | sf | of; +} + +CCTable cc_table[CC_OP_NB] = { + [CC_OP_DYNAMIC] = { /* should never happen */ }, + + [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags }, + + [CC_OP_MUL] = { compute_all_mul, compute_c_mul }, + + [CC_OP_ADDB] = { compute_all_addb, compute_c_addb }, + [CC_OP_ADDW] = { compute_all_addw, compute_c_addw }, + [CC_OP_ADDL] = { compute_all_addl, compute_c_addl }, + + [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, + [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, + [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, + + [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, + [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, + [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, + + [CC_OP_INCB] = { compute_all_incb, compute_c_incb }, + [CC_OP_INCW] = { compute_all_incw, compute_c_incw }, + [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, + + [CC_OP_DECB] = { compute_all_decb, compute_c_incb }, + [CC_OP_DECW] = { compute_all_decw, compute_c_incw }, + [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, + + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, + [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, + [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, +}; diff --git a/ops_template.h b/ops_template.h new file mode 100644 index 000000000..403247294 --- /dev/null +++ b/ops_template.h @@ -0,0 +1,628 @@ + +#define DATA_BITS (1 << (3 + SHIFT)) +#define SHIFT_MASK (DATA_BITS - 1) +#define SIGN_MASK (1 << (DATA_BITS - 1)) + +#if DATA_BITS == 8 +#define SUFFIX b +#define DATA_TYPE uint8_t +#define DATA_STYPE int8_t +#define DATA_MASK 0xff +#elif DATA_BITS == 16 +#define SUFFIX w +#define DATA_TYPE uint16_t +#define DATA_STYPE int16_t +#define DATA_MASK 0xffff +#elif DATA_BITS == 32 +#define SUFFIX l +#define DATA_TYPE uint32_t +#define DATA_STYPE int32_t +#define DATA_MASK 0xffffffff +#else +#error unhandled operand size +#endif + +/* dynamic flags computation */ + +static int glue(compute_all_add, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_DST - CC_SRC; + cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST != 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_add, SUFFIX)(void) +{ + int src1, cf; + src1 = CC_SRC; + cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; + return cf; +} + +static int glue(compute_all_sub, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST != 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_sub, SUFFIX)(void) +{ + int src1, src2, cf; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + cf = (DATA_TYPE)src1 < (DATA_TYPE)src1; + return cf; +} + +static int glue(compute_all_logic, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = 0; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; + zf = ((DATA_TYPE)CC_DST != 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = 0; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_logic, SUFFIX)(void) +{ + return 0; +} + +static int glue(compute_all_inc, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_DST - 1; + src2 = 1; + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST != 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_inc, SUFFIX)(void) +{ + return CC_SRC; +} + +static int glue(compute_all_dec, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_DST + 1; + src2 = 1; + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST != 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_all_shl, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = CC_SRC & 1; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((DATA_TYPE)CC_DST != 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = sf << 4; /* only meaniful for shr with count == 1 */ + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_shl, SUFFIX)(void) +{ + return CC_SRC & 1; +} + +/* various optimized jumps cases */ + +void OPPROTO glue(op_jb_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + + if ((DATA_TYPE)src1 < (DATA_TYPE)src2) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_jz_sub, SUFFIX)(void) +{ + if ((DATA_TYPE)CC_DST != 0) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_jbe_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + + if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_js_sub, SUFFIX)(void) +{ + if (CC_DST & SIGN_MASK) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_jl_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + + if ((DATA_STYPE)src1 < (DATA_STYPE)src2) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_jle_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + + if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +/* various optimized set cases */ + +void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + + T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2); +} + +void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) +{ + T0 = ((DATA_TYPE)CC_DST != 0); +} + +void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + + T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2); +} + +void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void) +{ + T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1; +} + +void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + + T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2); +} + +void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + + T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2); +} + +/* shifts */ + +void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & SHIFT_MASK; + if (count) { + CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); + src = T0; + T0 &= DATA_MASK; + T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); + CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + (T0 & CC_C); + CC_OP = CC_OP_EFLAGS; + } +} + +void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & SHIFT_MASK; + if (count) { + CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); + src = T0; + T0 &= DATA_MASK; + T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); + CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((T0 >> (DATA_BITS - 1)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } +} + +void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) +{ + int count, res, eflags; + unsigned int src; + + count = T1 & 0x1f; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + src = T0; + res = (T0 << count) | ((eflags & CC_C) << (count - 1)); + if (count > 1) + res |= T0 >> (DATA_BITS + 1 - count); + T0 = res; + CC_SRC = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (DATA_BITS - count)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } +} + +void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) +{ + int count, res, eflags; + unsigned int src; + + count = T1 & 0x1f; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + src = T0; + res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); + if (count > 1) + res |= T0 << (DATA_BITS + 1 - count); + T0 = res; + CC_SRC = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (count - 1)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } +} + +void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 << 1; + CC_DST = T0; + CC_OP = CC_OP_ADDB + SHIFT; + } else if (count) { + CC_SRC = T0 >> (DATA_BITS - count); + T0 = T0 << count; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } +} + +void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + T0 &= DATA_MASK; + CC_SRC = T0 >> (count - 1); + T0 = T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } +} + +void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + src = (DATA_STYPE)T0; + CC_SRC = src >> (count - 1); + T0 = src >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } +} + +/* string operations */ +/* XXX: maybe use lower level instructions to ease exception handling */ + +void OPPROTO glue(op_movs, SUFFIX)(void) +{ + int v; + v = glue(ldu, SUFFIX)((void *)ESI); + glue(st, SUFFIX)((void *)EDI, v); + ESI += (DF << SHIFT); + EDI += (DF << SHIFT); +} + +void OPPROTO glue(op_rep_movs, SUFFIX)(void) +{ + int v, inc; + inc = (DF << SHIFT); + while (ECX != 0) { + v = glue(ldu, SUFFIX)((void *)ESI); + glue(st, SUFFIX)((void *)EDI, v); + ESI += inc; + EDI += inc; + ECX--; + } +} + +void OPPROTO glue(op_stos, SUFFIX)(void) +{ + glue(st, SUFFIX)((void *)EDI, EAX); + EDI += (DF << SHIFT); +} + +void OPPROTO glue(op_rep_stos, SUFFIX)(void) +{ + int inc; + inc = (DF << SHIFT); + while (ECX != 0) { + glue(st, SUFFIX)((void *)EDI, EAX); + EDI += inc; + ECX--; + } +} + +void OPPROTO glue(op_lods, SUFFIX)(void) +{ + int v; + v = glue(ldu, SUFFIX)((void *)ESI); +#if SHIFT == 0 + EAX = (EAX & ~0xff) | v; +#elif SHIFT == 1 + EAX = (EAX & ~0xffff) | v; +#else + EAX = v; +#endif + ESI += (DF << SHIFT); +} + +/* don't know if it is used */ +void OPPROTO glue(op_rep_lods, SUFFIX)(void) +{ + int v, inc; + inc = (DF << SHIFT); + while (ECX != 0) { + v = glue(ldu, SUFFIX)((void *)ESI); +#if SHIFT == 0 + EAX = (EAX & ~0xff) | v; +#elif SHIFT == 1 + EAX = (EAX & ~0xffff) | v; +#else + EAX = v; +#endif + ESI += inc; + ECX--; + } +} + +void OPPROTO glue(op_scas, SUFFIX)(void) +{ + int v; + + v = glue(ldu, SUFFIX)((void *)ESI); + ESI += (DF << SHIFT); + CC_SRC = EAX; + CC_DST = EAX - v; +} + +void OPPROTO glue(op_repz_scas, SUFFIX)(void) +{ + int v1, v2, inc; + + if (ECX != 0) { + /* NOTE: the flags are not modified if ECX == 0 */ +#if SHIFT == 0 + v1 = EAX & 0xff; +#elif SHIFT == 1 + v1 = EAX & 0xffff; +#else + v1 = EAX; +#endif + inc = (DF << SHIFT); + do { + v2 = glue(ldu, SUFFIX)((void *)ESI); + if (v1 != v2) + break; + ESI += inc; + ECX--; + } while (ECX != 0); + CC_SRC = v1; + CC_DST = v1 - v2; + CC_OP = CC_OP_SUBB + SHIFT; + } +} + +void OPPROTO glue(op_repnz_scas, SUFFIX)(void) +{ + int v1, v2, inc; + + if (ECX != 0) { + /* NOTE: the flags are not modified if ECX == 0 */ +#if SHIFT == 0 + v1 = EAX & 0xff; +#elif SHIFT == 1 + v1 = EAX & 0xffff; +#else + v1 = EAX; +#endif + inc = (DF << SHIFT); + do { + v2 = glue(ldu, SUFFIX)((void *)ESI); + if (v1 == v2) + break; + ESI += inc; + ECX--; + } while (ECX != 0); + CC_SRC = v1; + CC_DST = v1 - v2; + CC_OP = CC_OP_SUBB + SHIFT; + } +} + +void OPPROTO glue(op_cmps, SUFFIX)(void) +{ + int v1, v2; + v1 = glue(ldu, SUFFIX)((void *)ESI); + v2 = glue(ldu, SUFFIX)((void *)EDI); + ESI += (DF << SHIFT); + EDI += (DF << SHIFT); + CC_SRC = v1; + CC_DST = v1 - v2; +} + +void OPPROTO glue(op_repz_cmps, SUFFIX)(void) +{ + int v1, v2, inc; + if (ECX != 0) { + inc = (DF << SHIFT); + do { + v1 = glue(ldu, SUFFIX)((void *)ESI); + v2 = glue(ldu, SUFFIX)((void *)EDI); + if (v1 != v2) + break; + ESI += inc; + EDI += inc; + ECX--; + } while (ECX != 0); + CC_SRC = v1; + CC_DST = v1 - v2; + CC_OP = CC_OP_SUBB + SHIFT; + } +} + +void OPPROTO glue(op_repnz_cmps, SUFFIX)(void) +{ + int v1, v2, inc; + if (ECX != 0) { + inc = (DF << SHIFT); + do { + v1 = glue(ldu, SUFFIX)((void *)ESI); + v2 = glue(ldu, SUFFIX)((void *)EDI); + if (v1 == v2) + break; + ESI += inc; + EDI += inc; + ECX--; + } while (ECX != 0); + CC_SRC = v1; + CC_DST = v1 - v2; + CC_OP = CC_OP_SUBB + SHIFT; + } +} + +void OPPROTO glue(op_outs, SUFFIX)(void) +{ + int v, dx; + dx = EDX & 0xffff; + v = glue(ldu, SUFFIX)((void *)ESI); + glue(port_out, SUFFIX)(dx, v); + ESI += (DF << SHIFT); +} + +void OPPROTO glue(op_rep_outs, SUFFIX)(void) +{ + int v, dx, inc; + inc = (DF << SHIFT); + dx = EDX & 0xffff; + while (ECX != 0) { + v = glue(ldu, SUFFIX)((void *)ESI); + glue(port_out, SUFFIX)(dx, v); + ESI += inc; + ECX--; + } +} + +void OPPROTO glue(op_ins, SUFFIX)(void) +{ + int v, dx; + dx = EDX & 0xffff; + v = glue(port_in, SUFFIX)(dx); + glue(st, SUFFIX)((void *)EDI, v); + EDI += (DF << SHIFT); +} + +void OPPROTO glue(op_rep_ins, SUFFIX)(void) +{ + int v, dx, inc; + inc = (DF << SHIFT); + dx = EDX & 0xffff; + while (ECX != 0) { + v = glue(port_in, SUFFIX)(dx); + glue(st, SUFFIX)((void *)EDI, v); + EDI += (DF << SHIFT); + ECX--; + } +} + +#undef DATA_BITS +#undef SHIFT_MASK +#undef SIGN_MASK +#undef DATA_TYPE +#undef DATA_STYPE +#undef DATA_MASK +#undef SUFFIX diff --git a/tests/Makefile b/tests/Makefile index c6347edfc..2c2b059df 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -2,7 +2,9 @@ CC=gcc CFLAGS=-Wall -O2 -g LDFLAGS= -TESTS=hello test1 test2 sha1 test-i386 +TESTS=hello test1 test2 sha1 test-i386 +TESTS+=op-i386.o #op-i386.o op-ppc.o op-arm.o op-mips.o op-sparc.o + GEMU=../gemu all: $(TESTS) @@ -25,6 +27,22 @@ test: test-i386 $(GEMU) test-i386 > test-i386.out @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi +# dyngen tests +op-i386.o: op.c + gcc $(CFLAGS) -c -o $@ $< + +op-ppc.o: op.c + powerpc-linux-gcc $(CFLAGS) -c -o $@ $< + +op-arm.o: op.c + arm-linux-gcc $(CFLAGS) -c -o $@ $< + +op-mips.o: op.c + mips-linux-gcc $(CFLAGS) -mno-abicalls -c -o $@ $< + +op-sparc.o: op.c + sparc-linux-gcc $(CFLAGS) -mflat -c -o $@ $< + # speed test sha1: sha1.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< diff --git a/thunk.h b/thunk.h index 0b83d202a..5e5d9dd18 100644 --- a/thunk.h +++ b/thunk.h @@ -28,16 +28,16 @@ #define bswap_64(x) \ ({ \ - __u64 __x = (x); \ - ((__u64)( \ - (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \ - (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \ - (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \ - (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \ - (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \ - (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ - (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \ - (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \ + 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 @@ -51,7 +51,7 @@ #define BSWAP_NEEDED #endif -/* XXX: auto autoconf */ +/* XXX: autoconf */ #define TARGET_I386 #define TARGET_LONG_BITS 32 diff --git a/translate-i386.c b/translate-i386.c new file mode 100644 index 000000000..0c1b95a92 --- /dev/null +++ b/translate-i386.c @@ -0,0 +1,2133 @@ +#include +#include +#include +#include +#include +#include + +#include "cpu-i386.h" + +static uint8_t *gen_code_ptr; +int __op_param1, __op_param2, __op_param3; + +/* supress that */ +static void error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 + +typedef struct DisasContext { + /* current insn context */ + int prefix; + int aflag, dflag; + uint8_t *pc; /* current pc */ + uint8_t *runtime_pc; /* current pc in the runtime generated code */ + int cc_op; /* current CC operation */ + int f_st; +} DisasContext; + +/* i386 arith/logic operations */ +enum { + OP_ADDL, + OP_ORL, + OP_ADCL, + OP_SBBL, + OP_ANDL, + OP_SUBL, + OP_XORL, + OP_CMPL, +}; + +/* i386 shift ops */ +enum { + OP_ROL, + OP_ROR, + OP_RCL, + OP_RCR, + OP_SHL, + OP_SHR, + OP_SHL1, /* undocumented */ + OP_SAR = 7, +}; + + +static const int fp_ops[8] = { +#if 0 + OP_FADDQ, OP_FMULQ, OP_CMP, OP_CMP, + OP_FSUBQ, OP_FSUBQ, OP_FDIVQ, OP_FDIVQ +#endif +}; + +extern char cc_table, rclw_table, rclb_table; +extern char helper_rcll_T0_T1_cc; +extern char __udivdi3, __umoddi3; + +#include "op-i386.h" + +/* operand size */ +enum { + OT_BYTE = 0, + OT_WORD, + OT_LONG, + OT_QUAD, +}; + +enum { + /* I386 int registers */ + OR_EAX, /* MUST be even numbered */ + OR_ECX, + OR_EDX, + OR_EBX, + OR_ESP, + OR_EBP, + OR_ESI, + OR_EDI, + + /* I386 float registers */ + OR_ST0, + OR_ST1, + OR_ST2, + OR_ST3, + OR_ST4, + OR_ST5, + OR_ST6, + OR_ST7, + OR_TMP0, /* temporary operand register */ + OR_TMP1, + OR_A0, /* temporary register used when doing address evaluation */ + OR_EFLAGS, /* cpu flags */ + OR_ITMP0, /* used for byte/word insertion */ + OR_ITMP1, /* used for byte/word insertion */ + OR_ITMP2, /* used for byte/word insertion */ + OR_FTMP0, /* float temporary */ + OR_DF, /* D flag, for string ops */ + OR_ZERO, /* fixed zero register */ + OR_IM, /* dummy immediate value register */ + NB_OREGS, +}; + +#if 0 +static const double tab_const[7] = { + 1.0, + 3.32192809488736234789, /* log2(10) */ + M_LOG2E, + M_PI, + 0.30102999566398119521, /* log10(2) */ + M_LN2, + 0.0 +}; +#endif + +typedef void (GenOpFunc)(void); +typedef void (GenOpFunc1)(long); +typedef void (GenOpFunc2)(long, long); + +static GenOpFunc *gen_op_mov_reg_T0[3][8] = { + [OT_BYTE] = { + gen_op_movb_EAX_T0, + gen_op_movb_ECX_T0, + gen_op_movb_EDX_T0, + gen_op_movb_EBX_T0, + gen_op_movh_EAX_T0, + gen_op_movh_ECX_T0, + gen_op_movh_EDX_T0, + gen_op_movh_EBX_T0, + }, + [OT_WORD] = { + gen_op_movw_EAX_T0, + gen_op_movw_ECX_T0, + gen_op_movw_EDX_T0, + gen_op_movw_EBX_T0, + gen_op_movw_ESP_T0, + gen_op_movw_EBP_T0, + gen_op_movw_ESI_T0, + gen_op_movw_EDI_T0, + }, + [OT_LONG] = { + gen_op_movl_EAX_T0, + gen_op_movl_ECX_T0, + gen_op_movl_EDX_T0, + gen_op_movl_EBX_T0, + gen_op_movl_ESP_T0, + gen_op_movl_EBP_T0, + gen_op_movl_ESI_T0, + gen_op_movl_EDI_T0, + }, +}; + +static GenOpFunc *gen_op_mov_reg_T1[3][8] = { + [OT_BYTE] = { + gen_op_movb_EAX_T1, + gen_op_movb_ECX_T1, + gen_op_movb_EDX_T1, + gen_op_movb_EBX_T1, + gen_op_movh_EAX_T1, + gen_op_movh_ECX_T1, + gen_op_movh_EDX_T1, + gen_op_movh_EBX_T1, + }, + [OT_WORD] = { + gen_op_movw_EAX_T1, + gen_op_movw_ECX_T1, + gen_op_movw_EDX_T1, + gen_op_movw_EBX_T1, + gen_op_movw_ESP_T1, + gen_op_movw_EBP_T1, + gen_op_movw_ESI_T1, + gen_op_movw_EDI_T1, + }, + [OT_LONG] = { + gen_op_movl_EAX_T1, + gen_op_movl_ECX_T1, + gen_op_movl_EDX_T1, + gen_op_movl_EBX_T1, + gen_op_movl_ESP_T1, + gen_op_movl_EBP_T1, + gen_op_movl_ESI_T1, + gen_op_movl_EDI_T1, + }, +}; + +static GenOpFunc *gen_op_mov_reg_A0[2][8] = { + [0] = { + gen_op_movw_EAX_A0, + gen_op_movw_ECX_A0, + gen_op_movw_EDX_A0, + gen_op_movw_EBX_A0, + gen_op_movw_ESP_A0, + gen_op_movw_EBP_A0, + gen_op_movw_ESI_A0, + gen_op_movw_EDI_A0, + }, + [1] = { + gen_op_movl_EAX_A0, + gen_op_movl_ECX_A0, + gen_op_movl_EDX_A0, + gen_op_movl_EBX_A0, + gen_op_movl_ESP_A0, + gen_op_movl_EBP_A0, + gen_op_movl_ESI_A0, + gen_op_movl_EDI_A0, + }, +}; + +static GenOpFunc *gen_op_mov_TN_reg[3][2][8] = +{ + [OT_BYTE] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movh_T0_EAX, + gen_op_movh_T0_ECX, + gen_op_movh_T0_EDX, + gen_op_movh_T0_EBX, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movh_T1_EAX, + gen_op_movh_T1_ECX, + gen_op_movh_T1_EDX, + gen_op_movh_T1_EBX, + }, + }, + [OT_WORD] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movl_T0_ESP, + gen_op_movl_T0_EBP, + gen_op_movl_T0_ESI, + gen_op_movl_T0_EDI, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movl_T1_ESP, + gen_op_movl_T1_EBP, + gen_op_movl_T1_ESI, + gen_op_movl_T1_EDI, + }, + }, + [OT_LONG] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movl_T0_ESP, + gen_op_movl_T0_EBP, + gen_op_movl_T0_ESI, + gen_op_movl_T0_EDI, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movl_T1_ESP, + gen_op_movl_T1_EBP, + gen_op_movl_T1_ESI, + gen_op_movl_T1_EDI, + }, + }, +}; + +static GenOpFunc *gen_op_movl_A0_reg[8] = { + gen_op_movl_A0_EAX, + gen_op_movl_A0_ECX, + gen_op_movl_A0_EDX, + gen_op_movl_A0_EBX, + gen_op_movl_A0_ESP, + gen_op_movl_A0_EBP, + gen_op_movl_A0_ESI, + gen_op_movl_A0_EDI, +}; + +static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { + [0] = { + gen_op_addl_A0_EAX, + gen_op_addl_A0_ECX, + gen_op_addl_A0_EDX, + gen_op_addl_A0_EBX, + gen_op_addl_A0_ESP, + gen_op_addl_A0_EBP, + gen_op_addl_A0_ESI, + gen_op_addl_A0_EDI, + }, + [1] = { + gen_op_addl_A0_EAX_s1, + gen_op_addl_A0_ECX_s1, + gen_op_addl_A0_EDX_s1, + gen_op_addl_A0_EBX_s1, + gen_op_addl_A0_ESP_s1, + gen_op_addl_A0_EBP_s1, + gen_op_addl_A0_ESI_s1, + gen_op_addl_A0_EDI_s1, + }, + [2] = { + gen_op_addl_A0_EAX_s2, + gen_op_addl_A0_ECX_s2, + gen_op_addl_A0_EDX_s2, + gen_op_addl_A0_EBX_s2, + gen_op_addl_A0_ESP_s2, + gen_op_addl_A0_EBP_s2, + gen_op_addl_A0_ESI_s2, + gen_op_addl_A0_EDI_s2, + }, + [3] = { + gen_op_addl_A0_EAX_s3, + gen_op_addl_A0_ECX_s3, + gen_op_addl_A0_EDX_s3, + gen_op_addl_A0_EBX_s3, + gen_op_addl_A0_ESP_s3, + gen_op_addl_A0_EBP_s3, + gen_op_addl_A0_ESI_s3, + gen_op_addl_A0_EDI_s3, + }, +}; + +static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { + gen_op_addl_T0_T1_cc, + gen_op_orl_T0_T1_cc, + gen_op_adcl_T0_T1_cc, + gen_op_sbbl_T0_T1_cc, + gen_op_andl_T0_T1_cc, + gen_op_subl_T0_T1_cc, + gen_op_xorl_T0_T1_cc, + gen_op_cmpl_T0_T1_cc, +}; + +static const int cc_op_arithb[8] = { + CC_OP_ADDB, + CC_OP_LOGICB, + CC_OP_ADDB, + CC_OP_SUBB, + CC_OP_LOGICB, + CC_OP_SUBB, + CC_OP_LOGICB, + CC_OP_SUBB, +}; + +static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { + [OT_BYTE] = { + gen_op_rolb_T0_T1_cc, + gen_op_rorb_T0_T1_cc, + gen_op_rclb_T0_T1_cc, + gen_op_rcrb_T0_T1_cc, + gen_op_shlb_T0_T1_cc, + gen_op_shrb_T0_T1_cc, + gen_op_shlb_T0_T1_cc, + gen_op_sarb_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_rolw_T0_T1_cc, + gen_op_rorw_T0_T1_cc, + gen_op_rclw_T0_T1_cc, + gen_op_rcrw_T0_T1_cc, + gen_op_shlw_T0_T1_cc, + gen_op_shrw_T0_T1_cc, + gen_op_shlw_T0_T1_cc, + gen_op_sarw_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_roll_T0_T1_cc, + gen_op_rorl_T0_T1_cc, + gen_op_rcll_T0_T1_cc, + gen_op_rcrl_T0_T1_cc, + gen_op_shll_T0_T1_cc, + gen_op_shrl_T0_T1_cc, + gen_op_shll_T0_T1_cc, + gen_op_sarl_T0_T1_cc, + }, +}; + +static GenOpFunc *gen_op_lds_T0_A0[3] = { + gen_op_ldsb_T0_A0, + gen_op_ldsw_T0_A0, +}; + +static GenOpFunc *gen_op_ldu_T0_A0[3] = { + gen_op_ldub_T0_A0, + gen_op_lduw_T0_A0, +}; + +/* sign does not matter */ +static GenOpFunc *gen_op_ld_T0_A0[3] = { + gen_op_ldub_T0_A0, + gen_op_lduw_T0_A0, + gen_op_ldl_T0_A0, +}; + +static GenOpFunc *gen_op_ld_T1_A0[3] = { + gen_op_ldub_T1_A0, + gen_op_lduw_T1_A0, + gen_op_ldl_T1_A0, +}; + +static GenOpFunc *gen_op_st_T0_A0[3] = { + gen_op_stb_T0_A0, + gen_op_stw_T0_A0, + gen_op_stl_T0_A0, +}; + +static GenOpFunc *gen_op_movs[6] = { + gen_op_movsb, + gen_op_movsw, + gen_op_movsl, + gen_op_rep_movsb, + gen_op_rep_movsw, + gen_op_rep_movsl, +}; + +static GenOpFunc *gen_op_stos[6] = { + gen_op_stosb, + gen_op_stosw, + gen_op_stosl, + gen_op_rep_stosb, + gen_op_rep_stosw, + gen_op_rep_stosl, +}; + +static GenOpFunc *gen_op_lods[6] = { + gen_op_lodsb, + gen_op_lodsw, + gen_op_lodsl, + gen_op_rep_lodsb, + gen_op_rep_lodsw, + gen_op_rep_lodsl, +}; + +static GenOpFunc *gen_op_scas[9] = { + gen_op_scasb, + gen_op_scasw, + gen_op_scasl, + gen_op_repz_scasb, + gen_op_repz_scasw, + gen_op_repz_scasl, + gen_op_repnz_scasb, + gen_op_repnz_scasw, + gen_op_repnz_scasl, +}; + +static GenOpFunc *gen_op_cmps[9] = { + gen_op_cmpsb, + gen_op_cmpsw, + gen_op_cmpsl, + gen_op_repz_cmpsb, + gen_op_repz_cmpsw, + gen_op_repz_cmpsl, + gen_op_repnz_cmpsb, + gen_op_repnz_cmpsw, + gen_op_repnz_cmpsl, +}; + +static GenOpFunc *gen_op_ins[6] = { + gen_op_insb, + gen_op_insw, + gen_op_insl, + gen_op_rep_insb, + gen_op_rep_insw, + gen_op_rep_insl, +}; + + +static GenOpFunc *gen_op_outs[6] = { + gen_op_outsb, + gen_op_outsw, + gen_op_outsl, + gen_op_rep_outsb, + gen_op_rep_outsw, + gen_op_rep_outsl, +}; + +enum { + JCC_O, + JCC_B, + JCC_Z, + JCC_BE, + JCC_S, + JCC_P, + JCC_L, + JCC_LE, +}; + +static GenOpFunc2 *gen_jcc_slow[8] = { + gen_op_jo_cc, + gen_op_jb_cc, + gen_op_jz_cc, + gen_op_jbe_cc, + gen_op_js_cc, + gen_op_jp_cc, + gen_op_jl_cc, + gen_op_jle_cc, +}; + +static GenOpFunc2 *gen_jcc_sub[3][8] = { + [OT_BYTE] = { + NULL, + gen_op_jb_subb, + gen_op_jz_subb, + gen_op_jbe_subb, + gen_op_js_subb, + NULL, + gen_op_jl_subb, + gen_op_jle_subb, + }, + [OT_WORD] = { + NULL, + gen_op_jb_subw, + gen_op_jz_subw, + gen_op_jbe_subw, + gen_op_js_subw, + NULL, + gen_op_jl_subw, + gen_op_jle_subw, + }, + [OT_LONG] = { + NULL, + gen_op_jb_subl, + gen_op_jz_subl, + gen_op_jbe_subl, + gen_op_js_subl, + NULL, + gen_op_jl_subl, + gen_op_jle_subl, + }, +}; + +static GenOpFunc *gen_setcc_slow[8] = { + gen_op_seto_T0_cc, + gen_op_setb_T0_cc, + gen_op_setz_T0_cc, + gen_op_setbe_T0_cc, + gen_op_sets_T0_cc, + gen_op_setp_T0_cc, + gen_op_setl_T0_cc, + gen_op_setle_T0_cc, +}; + +static GenOpFunc *gen_setcc_sub[3][8] = { + [OT_BYTE] = { + NULL, + gen_op_setb_T0_subb, + gen_op_setz_T0_subb, + gen_op_setbe_T0_subb, + gen_op_sets_T0_subb, + NULL, + gen_op_setl_T0_subb, + gen_op_setle_T0_subb, + }, + [OT_WORD] = { + NULL, + gen_op_setb_T0_subw, + gen_op_setz_T0_subw, + gen_op_setbe_T0_subw, + gen_op_sets_T0_subw, + NULL, + gen_op_setl_T0_subw, + gen_op_setle_T0_subw, + }, + [OT_LONG] = { + NULL, + gen_op_setb_T0_subl, + gen_op_setz_T0_subl, + gen_op_setbe_T0_subl, + gen_op_sets_T0_subl, + NULL, + gen_op_setl_T0_subl, + gen_op_setle_T0_subl, + }, +}; + +static void gen_op(DisasContext *s1, int op, int ot, int d, int s) +{ + if (d != OR_TMP0) + gen_op_mov_TN_reg[ot][0][d](); + if (s != OR_TMP1) + gen_op_mov_TN_reg[ot][1][s](); + if ((op == OP_ADCL || op == OP_SBBL) && s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + gen_op_arith_T0_T1_cc[op](); + if (d != OR_TMP0 && op != OP_CMPL) + gen_op_mov_reg_T0[ot][d](); + s1->cc_op = cc_op_arithb[op] + ot; +} + +static void gen_opi(DisasContext *s1, int op, int ot, int d, int c) +{ + gen_op1_movl_T1_im(c); + gen_op(s1, op, ot, d, OR_TMP0); +} + +static void gen_inc(DisasContext *s1, int ot, int d, int c) +{ + if (d != OR_TMP0) + gen_op_mov_TN_reg[ot][0][d](); + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + if (c > 0) + gen_op_incl_T0_cc(); + else + gen_op_decl_T0_cc(); + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); +} + +static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) +{ + if (d != OR_TMP0) + gen_op_mov_TN_reg[ot][0][d](); + if (s != OR_TMP1) + gen_op_mov_TN_reg[ot][1][s](); + switch(op) { + case OP_ROL: + case OP_ROR: + case OP_RCL: + case OP_RCR: + /* only C and O are modified, so we must update flags dynamically */ + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + gen_op_shift_T0_T1_cc[ot][op](); + break; + default: + gen_op_shift_T0_T1_cc[ot][op](); + break; + } + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); + s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ +} + +static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) +{ + /* currently not optimized */ + gen_op1_movl_T1_im(c); + gen_shift(s1, op, ot, d, OR_TMP1); +} + +static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) +{ + int havesib; + int havebase; + int base, disp; + int index = 0; + int scale = 0; + int reg1, reg2, opreg; + int mod, rm, code; + + mod = (modrm >> 6) & 3; + rm = modrm & 7; + + if (s->aflag) { + + havesib = 0; + havebase = 1; + base = rm; + + if (base == 4) { + havesib = 1; + code = ldub(s->pc++); + scale = (code >> 6) & 3; + index = (code >> 3) & 7; + base = code & 7; + } + + switch (mod) { + case 0: + if (base == 5) { + havebase = 0; + disp = ldl(s->pc); + s->pc += 4; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub(s->pc++); + break; + default: + case 2: + disp = ldl(s->pc); + s->pc += 4; + break; + } + + reg1 = OR_ZERO; + reg2 = OR_ZERO; + + if (havebase || (havesib && (index != 4 || scale != 0))) { + if (havebase) + reg1 = OR_EAX + base; + if (havesib && index != 4) { + if (havebase) + reg2 = index + OR_EAX; + else + reg1 = index + OR_EAX; + } + } + /* XXX: disp only ? */ + if (reg2 == OR_ZERO) { + /* op: disp + (reg1 << scale) */ + if (reg1 == OR_ZERO) { + gen_op1_movl_A0_im(disp); + } else if (scale == 0 && disp == 0) { + gen_op_movl_A0_reg[reg1](); + } else { + gen_op_addl_A0_reg_sN[scale][reg1](); + } + } else { + /* op: disp + reg1 + (reg2 << scale) */ + if (disp != 0) { + gen_op1_movl_A0_im(disp); + gen_op_addl_A0_reg_sN[0][reg1](); + } else { + gen_op_movl_A0_reg[reg1](); + } + gen_op_addl_A0_reg_sN[scale][reg2](); + } + opreg = OR_A0; + } else { + fprintf(stderr, "16 bit addressing not supported\n"); + disp = 0; + opreg = 0; + } + *reg_ptr = opreg; + *offset_ptr = disp; +} + +/* generate modrm memory load or store of 'reg'. TMP0 is used if reg != + OR_TMP0 */ +static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store) +{ + int mod, rm, opreg, disp; + + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod == 3) { + if (is_store) { + if (reg != OR_TMP0) + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_reg_T0[ot][rm](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + if (reg != OR_TMP0) + gen_op_mov_reg_T0[ot][reg](); + } + } else { + gen_lea_modrm(s, modrm, &opreg, &disp); + if (is_store) { + if (reg != OR_TMP0) + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_st_T0_A0[ot](); + } else { + gen_op_ld_T0_A0[ot](); + if (reg != OR_TMP0) + gen_op_mov_reg_T0[ot][reg](); + } + } +} + +static inline uint32_t insn_get(DisasContext *s, int ot) +{ + uint32_t ret; + + switch(ot) { + case OT_BYTE: + ret = ldub(s->pc); + s->pc++; + break; + case OT_WORD: + ret = lduw(s->pc); + s->pc += 2; + break; + default: + case OT_LONG: + ret = ldl(s->pc); + s->pc += 4; + break; + } + return ret; +} + +static void gen_jcc(DisasContext *s, int b, int val) +{ + int inv, jcc_op; + GenOpFunc2 *func; + + inv = b & 1; + jcc_op = (b >> 1) & 7; + switch(s->cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; + if (!func) + goto slow_jcc; + break; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + switch(jcc_op) { + case JCC_Z: + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + case JCC_S: + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + default: + goto slow_jcc; + } + break; + default: + slow_jcc: + if (s->cc_op != CC_OP_DYNAMIC) + op_set_cc_op(s->cc_op); + func = gen_jcc_slow[jcc_op]; + break; + } + if (!inv) { + func(val, (long)s->pc); + } else { + func((long)s->pc, val); + } +} + +static void gen_setcc(DisasContext *s, int b) +{ + int inv, jcc_op; + GenOpFunc *func; + + inv = b & 1; + jcc_op = (b >> 1) & 7; + switch(s->cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; + if (!func) + goto slow_jcc; + break; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + switch(jcc_op) { + case JCC_Z: + func = gen_setcc_sub[s->cc_op - CC_OP_ADDB][jcc_op]; + break; + case JCC_S: + func = gen_setcc_sub[s->cc_op - CC_OP_ADDB][jcc_op]; + break; + default: + goto slow_jcc; + } + break; + default: + slow_jcc: + if (s->cc_op != CC_OP_DYNAMIC) + op_set_cc_op(s->cc_op); + func = gen_setcc_slow[jcc_op]; + break; + } + func(); + if (inv) { + gen_op_xor_T0_1(); + } +} + +/* return the size of the intruction. Return -1 if no insn found */ +int disas_insn(DisasContext *s, uint8_t *pc_start) +{ + int b, prefixes, aflag, dflag; + int shift, ot; + int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; + + s->pc = pc_start; + prefixes = 0; + aflag = 1; + dflag = 1; + // cur_pc = s->pc; /* for insn generation */ + next_byte: + b = ldub(s->pc); + if (b < 0) + return -1; + s->pc++; + /* check prefixes */ + switch (b) { + case 0xf3: + prefixes |= PREFIX_REPZ; + goto next_byte; + case 0xf2: + prefixes |= PREFIX_REPNZ; + goto next_byte; + case 0xf0: + prefixes |= PREFIX_LOCK; + goto next_byte; + case 0x2e: + prefixes |= PREFIX_CS; + goto next_byte; + case 0x36: + prefixes |= PREFIX_SS; + goto next_byte; + case 0x3e: + prefixes |= PREFIX_DS; + goto next_byte; + case 0x26: + prefixes |= PREFIX_ES; + goto next_byte; + case 0x64: + prefixes |= PREFIX_FS; + goto next_byte; + case 0x65: + prefixes |= PREFIX_GS; + goto next_byte; + case 0x66: + prefixes |= PREFIX_DATA; + goto next_byte; + case 0x67: + prefixes |= PREFIX_ADR; + goto next_byte; + case 0x9b: + prefixes |= PREFIX_FWAIT; + goto next_byte; + } + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + if (prefixes & PREFIX_ADR) + aflag ^= 1; + + s->prefix = prefixes; + s->aflag = aflag; + s->dflag = dflag; + + /* now check op code */ + reswitch: + switch(b) { + case 0x0f: + /**************************/ + /* extended op code */ + b = ldub(s->pc++) | 0x100; + goto reswitch; + + /**************************/ + /* arith & logic */ + case 0x00 ... 0x05: + case 0x08 ... 0x0d: + case 0x10 ... 0x15: + case 0x18 ... 0x1d: + case 0x20 ... 0x25: + case 0x28 ... 0x2d: + case 0x30 ... 0x35: + case 0x38 ... 0x3d: + { + int op, f, val; + op = (b >> 3) & 7; + f = (b >> 1) & 3; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + switch(f) { + case 0: /* OP Ev, Gv */ + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7) + OR_EAX; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + opreg = OR_TMP0; + } else { + opreg = OR_EAX + rm; + } + gen_op(s, op, ot, opreg, reg); + if (mod != 3 && op != 7) { + gen_op_st_T0_A0[ot](); + } + break; + case 1: /* OP Gv, Ev */ + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + reg = ((modrm >> 3) & 7) + OR_EAX; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[ot](); + opreg = OR_TMP1; + } else { + opreg = OR_EAX + rm; + } + gen_op(s, op, ot, reg, opreg); + break; + case 2: /* OP A, Iv */ + val = insn_get(s, ot); + gen_opi(s, op, ot, OR_EAX, val); + break; + } + } + break; + + case 0x80: /* GRP1 */ + case 0x81: + case 0x83: + { + int val; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + opreg = OR_TMP0; + } else { + opreg = rm + OR_EAX; + } + + switch(b) { + default: + case 0x80: + case 0x81: + val = insn_get(s, ot); + break; + case 0x83: + val = (int8_t)insn_get(s, OT_BYTE); + break; + } + + gen_opi(s, op, ot, opreg, val); + if (op != 7 && mod != 3) { + gen_op_st_T0_A0[ot](); + } + } + break; + + /**************************/ + /* inc, dec, and other misc arith */ + case 0x40 ... 0x47: /* inc Gv */ + ot = dflag ? OT_LONG : OT_WORD; + gen_inc(s, ot, OR_EAX + (b & 7), 1); + break; + case 0x48 ... 0x4f: /* dec Gv */ + ot = dflag ? OT_LONG : OT_WORD; + gen_inc(s, ot, OR_EAX + (b & 7), -1); + break; + case 0xf6: /* GRP3 */ + case 0xf7: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + + switch(op) { + case 0: /* test */ + val = insn_get(s, ot); + gen_op1_movl_T1_im(val); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + case 2: /* not */ + gen_op_notl_T0(); + if (mod != 3) { + gen_op_st_T0_A0[ot](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + break; + case 3: /* neg */ + gen_op_negl_T0_cc(); + if (mod != 3) { + gen_op_st_T0_A0[ot](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + s->cc_op = CC_OP_SUBB + ot; + break; + case 4: /* mul */ + switch(ot) { + case OT_BYTE: + gen_op_mulb_AL_T0(); + break; + case OT_WORD: + gen_op_mulw_AX_T0(); + break; + default: + case OT_LONG: + gen_op_mull_EAX_T0(); + break; + } + break; + case 5: /* imul */ + switch(ot) { + case OT_BYTE: + gen_op_imulb_AL_T0(); + break; + case OT_WORD: + gen_op_imulw_AX_T0(); + break; + default: + case OT_LONG: + gen_op_imull_EAX_T0(); + break; + } + break; + case 6: /* div */ + switch(ot) { + case OT_BYTE: + gen_op_divb_AL_T0(); + break; + case OT_WORD: + gen_op_divw_AX_T0(); + break; + default: + case OT_LONG: + gen_op_divl_EAX_T0(); + break; + } + break; + case 7: /* idiv */ + switch(ot) { + case OT_BYTE: + gen_op_idivb_AL_T0(); + break; + case OT_WORD: + gen_op_idivw_AX_T0(); + break; + default: + case OT_LONG: + gen_op_idivl_EAX_T0(); + break; + } + break; + default: + error("GRP3: bad instruction"); + return -1; + } + break; + + case 0xfe: /* GRP4 */ + case 0xff: /* GRP5 */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + if (op >= 2 && b == 0xfe) { + error("GRP4: bad instruction"); + return -1; + } + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + + switch(op) { + case 0: /* inc Ev */ + gen_inc(s, ot, OR_TMP0, 1); + if (mod != 3) + gen_op_st_T0_A0[ot](); + break; + case 1: /* dec Ev */ + gen_inc(s, ot, OR_TMP0, -1); + if (mod != 3) + gen_op_st_T0_A0[ot](); + break; + case 2: /* call Ev */ + gen_op1_movl_T1_im((long)s->pc); + gen_op_pushl_T1(); + gen_op_jmp_T0(); + break; + case 4: /* jmp Ev */ + gen_op_jmp_T0(); + break; + case 6: /* push Ev */ + gen_op_pushl_T0(); + break; + default: + error("GRP5: bad instruction"); + return -1; + } + break; + + case 0x84: /* test Ev, Gv */ + case 0x85: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_TN_reg[ot][1][reg + OR_EAX](); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + + case 0xa8: /* test eAX, Iv */ + case 0xa9: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + + gen_op_mov_TN_reg[ot][0][OR_EAX](); + gen_op1_movl_T1_im(val); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + + case 0x98: /* CWDE/CBW */ + if (dflag) + gen_op_movswl_EAX_AX(); + else + gen_op_movsbw_AX_AL(); + break; + case 0x99: /* CDQ/CWD */ + if (dflag) + gen_op_movslq_EDX_EAX(); + else + gen_op_movswl_DX_AX(); + break; + case 0x1af: /* imul Gv, Ev */ + case 0x69: /* imul Gv, Ev, I */ + case 0x6b: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7) + OR_EAX; + + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + if (b == 0x69) { + val = insn_get(s, ot); + gen_op1_movl_T1_im(val); + } else if (b == 0x6b) { + val = insn_get(s, OT_BYTE); + gen_op1_movl_T1_im(val); + } else { + gen_op_mov_TN_reg[ot][1][reg](); + } + + if (ot == OT_LONG) { + op_imull_T0_T1(); + } else { + op_imulw_T0_T1(); + } + gen_op_mov_reg_T0[ot][reg](); + break; + + /**************************/ + /* push/pop */ + case 0x50 ... 0x57: /* push */ + gen_op_mov_TN_reg[OT_LONG][0][(b & 7)](); + gen_op_pushl_T0(); + break; + case 0x58 ... 0x5f: /* pop */ + gen_op_popl_T0(); + gen_op_mov_reg_T0[OT_LONG][reg](); + break; + case 0x68: /* push Iv */ + case 0x6a: + ot = dflag ? OT_LONG : OT_WORD; + if (b == 0x68) + val = insn_get(s, ot); + else + val = (int8_t)insn_get(s, OT_BYTE); + gen_op1_movl_T0_im(val); + gen_op_pushl_T0(); + break; + case 0x8f: /* pop Ev */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + gen_op_popl_T0(); + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 0xc9: /* leave */ + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_mov_reg_T0[OT_LONG][R_ESP](); + gen_op_popl_T0(); + gen_op_mov_reg_T0[OT_LONG][R_EBP](); + break; + /**************************/ + /* mov */ + case 0x88: + case 0x89: /* mov Gv, Ev */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + + /* generate a generic store */ + gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1); + break; + case 0xc6: + case 0xc7: /* mov Ev, Iv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + + val = insn_get(s, ot); + gen_op1_movl_T0_im(val); + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 0x8a: + case 0x8b: /* mov Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_reg_T0[ot][reg](); + break; + + case 0x1b6: /* movzbS Gv, Eb */ + case 0x1b7: /* movzwS Gv, Eb */ + case 0x1be: /* movsbS Gv, Eb */ + case 0x1bf: /* movswS Gv, Eb */ + { + int d_ot; + /* d_ot is the size of destination */ + d_ot = dflag + OT_WORD; + /* ot is the size of source */ + ot = (b & 1) + OT_BYTE; + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7) + OR_EAX; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + + if (mod == 3) { + gen_op_mov_TN_reg[ot][0][rm](); + switch(ot | (b & 8)) { + case OT_BYTE: + gen_op_movzbl_T0_T0(); + break; + case OT_BYTE | 8: + gen_op_movsbl_T0_T0(); + break; + case OT_WORD: + gen_op_movzwl_T0_T0(); + break; + default: + case OT_WORD | 8: + gen_op_movswl_T0_T0(); + break; + } + gen_op_mov_reg_T0[d_ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (b & 8) { + gen_op_lds_T0_A0[ot](); + } else { + gen_op_ldu_T0_A0[ot](); + } + gen_op_mov_reg_T0[d_ot][reg](); + } + } + break; + + case 0x8d: /* lea */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_mov_reg_A0[ot - OT_WORD][reg](); + break; + + case 0xa0: /* mov EAX, Ov */ + case 0xa1: + case 0xa2: /* mov Ov, EAX */ + case 0xa3: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (s->aflag) + offset_addr = insn_get(s, OT_LONG); + else + offset_addr = insn_get(s, OT_WORD); + + if ((b & 2) == 0) { + gen_op_ld_T0_A0[ot](); + gen_op_mov_reg_T0[ot][R_EAX](); + } else { + gen_op_mov_TN_reg[ot][0][R_EAX](); + gen_op_st_T0_A0[ot](); + } + break; + + case 0xb0 ... 0xb7: /* mov R, Ib */ + val = insn_get(s, OT_BYTE); + gen_op1_movl_T0_im(val); + gen_op_mov_reg_T0[OT_BYTE][b & 7](); + break; + case 0xb8 ... 0xbf: /* mov R, Iv */ + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + reg = OR_EAX + (b & 7); + gen_op1_movl_T0_im(val); + gen_op_mov_reg_T0[ot][reg](); + break; + + case 0x91 ... 0x97: /* xchg R, EAX */ + ot = dflag ? OT_LONG : OT_WORD; + reg = b & 7; + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_mov_reg_T0[ot][R_EAX](); + gen_op_mov_reg_T1[ot][reg](); + break; + case 0x86: + case 0x87: /* xchg Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_ld_T1_A0[ot](); + gen_op_st_T0_A0[ot](); + gen_op_mov_reg_T1[ot][reg](); + break; + + /************************/ + /* shifts */ + case 0xc0: + case 0xc1: + /* shift Ev,Ib */ + shift = 2; + grp2: + { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + opreg = OR_TMP0; + } else { + opreg = rm + OR_EAX; + } + + /* simpler op */ + if (shift == 0) { + gen_shift(s, op, ot, opreg, OR_ECX); + } else { + if (shift == 2) { + shift = ldub(s->pc++); + } + gen_shifti(s, op, ot, opreg, shift); + } + + if (mod != 3) { + gen_op_st_T0_A0[ot](); + } + } + break; + case 0xd0: + case 0xd1: + /* shift Ev,1 */ + shift = 1; + goto grp2; + case 0xd2: + case 0xd3: + /* shift Ev,cl */ + shift = 0; + goto grp2; + + /************************/ + /* floats */ +#if 0 + case 0xd8 ... 0xdf: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = ((b & 7) << 3) | ((modrm >> 3) & 7); + + if (mod != 3) { + /* memory op */ + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + switch(op) { + case 0x00 ... 0x07: /* fxxxs */ + case 0x10 ... 0x17: /* fixxxl */ + case 0x20 ... 0x27: /* fxxxl */ + case 0x30 ... 0x37: /* fixxx */ + { + int op1, swap; + op1 = fp_ops[op & 7]; + + swap = 0; + if ((op & 7) == 5 || (op & 7) == 7) + swap = 1; + + switch(op >> 4) { + case 0: + ot = OT_LONG; + is_int = 0; + break; + case 1: + ot = OT_LONG; + is_int = 1; + break; + case 2: + ot = OT_QUAD; + is_int = 0; + break; + case 3: + default: + ot = OT_WORD; + is_int = 1; + break; + } + + /* if integer, needs to convert to float */ + if (is_int) { + /* XXX: potential loss of precision if large integer */ + gen_ld(OP_LDUB + ot, OR_TMP0, reg_addr, offset_addr); + gen_insn2(OP_I2FL, OR_FTMP0, OR_TMP0); + } else { + gen_ld(OP_LDUB + ot, OR_FTMP0, reg_addr, offset_addr); + } + if (ot != OT_QUAD) + op1 += OP_FADDL - OP_FADDQ; + + if (!swap) + gen_insn3(op1, OR_ST0, OR_ST0, OR_FTMP0); + else + gen_insn3(op1, OR_ST0, OR_FTMP0, OR_ST0); + + if ((op & 7) == 3) { + /* fcomp needs pop */ + gen_insn0(OP_FPOP); + } + } + break; + case 0x08: /* flds */ + case 0x0a: /* fsts */ + case 0x0b: /* fstps */ + case 0x18: /* fildl */ + case 0x1a: /* fistl */ + case 0x1b: /* fistpl */ + case 0x28: /* fldl */ + case 0x2a: /* fstl */ + case 0x2b: /* fstpl */ + case 0x38: /* filds */ + case 0x3a: /* fists */ + case 0x3b: /* fistps */ + + switch(op >> 4) { + case 0: + ot = OT_LONG; + is_int = 0; + break; + case 1: + ot = OT_LONG; + is_int = 1; + break; + case 2: + ot = OT_QUAD; + is_int = 0; + break; + case 3: + default: + ot = OT_WORD; + is_int = 1; + break; + } + + switch(op & 7) { + case 0: + gen_insn0(OP_FPUSH); + if (is_int) { + /* XXX: potential loss of precision */ + gen_ld(OP_LDUB + ot, OR_TMP0, reg_addr, offset_addr); + gen_insn2(OP_I2FL, OR_ST0, OR_TMP0); + } else { + gen_ld(OP_LDUB + ot, OR_ST0, reg_addr, offset_addr); + } + break; + default: + if (is_int) { + gen_insn2(OP_F2IL, OR_TMP0, OR_ST0); + gen_st(OP_STB + ot, OR_TMP0, reg_addr, offset_addr); + } else { + gen_st(OP_STB + ot, OR_ST0, reg_addr, offset_addr); + } + if ((op & 7) == 3) + gen_insn0(OP_FPOP); + break; + } + break; + case 0x2f: /* fnstsw mem */ + gen_insn3(OP_FNSTS, OR_TMP0, OR_ZERO, OR_ZERO); + gen_st(OP_STW, OR_TMP0, reg_addr, offset_addr); + break; + + case 0x3c: /* fbld */ + case 0x3e: /* fbstp */ + error("float BCD not hanlded"); + return -1; + case 0x3d: /* fildll */ + gen_insn0(OP_FPUSH); + gen_ld(OP_LDQ, OR_TMP0, reg_addr, offset_addr); + gen_insn2(OP_I2FQ, OR_ST0, OR_TMP0); + break; + case 0x3f: /* fistpll */ + gen_insn2(OP_F2IQ, OR_TMP0, OR_ST0); + gen_st(OP_STQ, OR_TMP0, reg_addr, offset_addr); + gen_insn0(OP_FPOP); + break; + default: + error("unhandled memory FP\n"); + return -1; + } + } else { + /* register float ops */ + opreg = rm + OR_ST0; + + switch(op) { + case 0x08: /* fld sti */ + gen_insn0(OP_FPUSH); + gen_mov(OR_ST0, OR_ST0 + ((rm + 1) & 7)); + break; + case 0x09: /* fxchg sti */ + gen_mov(OR_TMP0, OR_ST0); + gen_mov(OR_ST0, opreg); + gen_mov(opreg, OR_TMP0); + break; + case 0x0a: /* grp d9/2 */ + switch(rm) { + case 0: /* fnop */ + gen_insn0(OP_NOP); + break; + default: + error("unhandled FP GRP d9/2\n"); + return -1; + } + break; + case 0x0c: /* grp d9/4 */ + switch(rm) { + case 0: /* fchs */ + gen_insn3(OP_FSUBQ, OR_ST0, OR_ZERO, OR_ST0); + break; + case 1: /* fabs */ + gen_insn2(OP_FABSQ, OR_ST0, OR_ST0); + break; + case 4: /* ftst */ + gen_insn3(OP_CMP, OR_ZERO, OR_ST0, OR_ZERO); + break; + case 5: /* fxam */ + gen_insn3(OP_FSPECIAL, OR_ZERO, OR_ST0, OR_ZERO); + break; + default: + return -1; + } + break; + case 0x0d: /* grp d9/5 */ + { + if (rm == 7) { + error("bad GRP d9/5"); + return -1; + } + /* XXX: needs constant load or symbol table */ + gen_insn0(OP_FPUSH); + gen_ld(OP_LDQ, OR_ST0, OR_ZERO, + (rm * 8) + FLOAT_CONST_ADDR); + } + break; + case 0x0e: /* grp d9/6 */ + switch(rm) { + case 0: /* f2xm1 */ + gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO); + break; + case 1: /* fyl2x */ + gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); + gen_insn0(OP_FPOP); + break; + case 2: /* fptan */ + gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO); + gen_insn0(OP_FPUSH); + /* load one */ + gen_ld(OP_LDQ, OR_ST0, OR_ZERO, + (0 * 8) + FLOAT_CONST_ADDR); + break; + case 3: /* fpatan */ + gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); + gen_insn0(OP_FPOP); + break; + case 4: /* fxtract */ + gen_insn0(OP_FPUSH); + gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST1, OR_ZERO); + gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST1, OR_ZERO); + break; + case 5: /* fprem1 */ + gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1); + break; + case 6: /* fdecstp */ + gen_insn0(OP_FPUSH); + break; + default: + case 7: /* fdecstp */ + gen_insn0(OP_FPOP); + break; + } + break; + case 0x0f: /* grp d9/7 */ + switch(rm) { + case 0: /* fprem */ + gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1); + break; + case 1: /* fyl2xp1 */ + gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); + gen_insn0(OP_FPOP); + break; + case 3: /* fsincos */ + gen_insn0(OP_FPUSH); + gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST1, OR_ZERO); + gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST1, OR_ZERO); + break; + case 5: /* fscale */ + gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1); + break; + case 2: /* fsqrt */ + case 4: /* frndint */ + case 6: /* fsin */ + default: + case 7: /* fcos */ + gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO); + break; + } + break; + case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ + case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ + case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ + { + int op1, swap; + + op1 = fp_ops[op & 7]; + swap = 0; + if ((op & 7) == 5 || (op & 7) == 7) + swap = 1; + if (op >= 0x20) { + if (swap) + gen_insn3(op1, opreg, OR_ST0, opreg); + else + gen_insn3(op1, opreg, opreg, OR_ST0); + } else { + if (swap) + gen_insn3(op1, OR_ST0, opreg, OR_ST0); + else + gen_insn3(op1, OR_ST0, OR_ST0, opreg); + } + if (op >= 0x30) + gen_insn0(OP_FPOP); + } + break; + case 0x02: /* fcom */ + gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); + break; + case 0x03: /* fcomp */ + gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); + gen_insn0(OP_FPOP); + break; + case 0x15: /* da/5 */ + switch(rm) { + case 1: /* fucompp */ + gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); + gen_insn0(OP_FPOP); + gen_insn0(OP_FPOP); + break; + default: + return -1; + } + break; + case 0x2a: /* fst sti */ + gen_mov(opreg, OR_ST0); + break; + case 0x2b: /* fstp sti */ + gen_mov(opreg, OR_ST0); + gen_insn0(OP_FPOP); + break; + case 0x33: /* de/3 */ + switch(rm) { + case 1: /* fcompp */ + gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); + gen_insn0(OP_FPOP); + gen_insn0(OP_FPOP); + break; + default: + return -1; + } + break; + case 0x3c: /* df/4 */ + switch(rm) { + case 0: + gen_insn3(OP_FNSTS, OR_EAX, OR_ZERO, OR_ZERO); + break; + default: + return -1; + } + break; + default: + error("unhandled FP\n"); + return -1; + } + } + break; +#endif + /************************/ + /* string ops */ + case 0xa4: /* movsS */ + case 0xa5: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_op_movs[3 + ot](); + } else { + gen_op_movs[ot](); + } + break; + + case 0xaa: /* stosS */ + case 0xab: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_op_stos[3 + ot](); + } else { + gen_op_stos[ot](); + } + break; + case 0xac: /* lodsS */ + case 0xad: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_op_lods[3 + ot](); + } else { + gen_op_lods[ot](); + } + break; + case 0xae: /* scasS */ + case 0xaf: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPNZ) { + gen_op_scas[6 + ot](); + } else if (prefixes & PREFIX_REPZ) { + gen_op_scas[3 + ot](); + } else { + gen_op_scas[ot](); + } + break; + + case 0xa6: /* cmpsS */ + case 0xa7: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPNZ) { + gen_op_cmps[6 + ot](); + } else if (prefixes & PREFIX_REPZ) { + gen_op_cmps[3 + ot](); + } else { + gen_op_cmps[ot](); + } + break; + + case 0x6c: /* insS */ + case 0x6d: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_op_ins[3 + ot](); + } else { + gen_op_ins[ot](); + } + break; + case 0x6e: /* outsS */ + case 0x6f: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_op_outs[3 + ot](); + } else { + gen_op_outs[ot](); + } + break; + + /************************/ + /* control */ + case 0xc2: /* ret im */ + /* XXX: handle stack pop ? */ + val = ldsw(s->pc); + s->pc += 2; + gen_op_popl_T0(); + gen_op_addl_ESP_im(val); + gen_op_jmp_T0(); + break; + case 0xc3: /* ret */ + gen_op_popl_T0(); + gen_op_jmp_T0(); + break; + case 0xe8: /* call */ + val = insn_get(s, OT_LONG); + val += (long)s->pc; + gen_op1_movl_T1_im((long)s->pc); + gen_op_pushl_T1(); + gen_op_jmp_im(val); + break; + case 0xe9: /* jmp */ + val = insn_get(s, OT_LONG); + val += (long)s->pc; + gen_op_jmp_im(val); + break; + case 0xeb: /* jmp Jb */ + val = (int8_t)insn_get(s, OT_BYTE); + val += (long)s->pc; + gen_op_jmp_im(val); + break; + case 0x70 ... 0x7f: /* jcc Jb */ + val = (int8_t)insn_get(s, OT_BYTE); + val += (long)s->pc; + goto do_jcc; + case 0x180 ... 0x18f: /* jcc Jv */ + if (dflag) { + val = insn_get(s, OT_LONG); + } else { + val = (int16_t)insn_get(s, OT_WORD); + } + val += (long)s->pc; /* XXX: fix 16 bit wrap */ + do_jcc: + gen_jcc(s, b, val); + break; + + case 0x190 ... 0x19f: + modrm = ldub(s->pc++); + gen_setcc(s, b); + gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); + break; + + /************************/ + /* flags */ + case 0x9c: /* pushf */ + gen_op_movl_T0_eflags(); + gen_op_pushl_T0(); + break; + case 0x9d: /* popf */ + gen_op_popl_T0(); + gen_op_movl_eflags_T0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x9e: /* sahf */ + gen_op_mov_TN_reg[OT_BYTE][0][R_AH](); + if (s->cc_op != CC_OP_DYNAMIC) + op_set_cc_op(s->cc_op); + gen_op_movb_eflags_T0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x9f: /* lahf */ + if (s->cc_op != CC_OP_DYNAMIC) + op_set_cc_op(s->cc_op); + gen_op_movl_T0_eflags(); + gen_op_mov_reg_T0[OT_BYTE][R_AH](); + break; + case 0xf5: /* cmc */ + if (s->cc_op != CC_OP_DYNAMIC) + op_set_cc_op(s->cc_op); + gen_op_cmc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xf8: /* clc */ + if (s->cc_op != CC_OP_DYNAMIC) + op_set_cc_op(s->cc_op); + gen_op_clc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xf9: /* stc */ + if (s->cc_op != CC_OP_DYNAMIC) + op_set_cc_op(s->cc_op); + gen_op_stc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xfc: /* cld */ + gen_op_cld(); + break; + case 0xfd: /* std */ + gen_op_std(); + break; + + /************************/ + /* misc */ + case 0x90: /* nop */ + break; + +#if 0 + case 0x1a2: /* cpuid */ + gen_insn0(OP_ASM); + break; +#endif + default: + error("unknown opcode %x", b); + return -1; + } + return (long)s->pc; +} + -- cgit v1.2.3 From 927f621e7960d3fcf51eecf65ee19b1aafc102ae Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 2 Mar 2003 19:39:42 +0000 Subject: added float support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@15 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 6 +- TODO | 1 + cpu-i386.h | 51 ++++ dyngen.c | 4 + op-i386.c | 728 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- translate-i386.c | 304 +++++++++++------------ 6 files changed, 934 insertions(+), 160 deletions(-) diff --git a/Makefile b/Makefile index 397ddf134..a61ab4a76 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ LDFLAGS=-g LIBS= CC=gcc DEFINES=-DHAVE_BYTESWAP_H +OP_CFLAGS=$(CFLAGS) -malign-functions=0 -mpreferred-stack-boundary=2 endif ifeq ($(ARCH),ppc) @@ -24,6 +25,7 @@ CRTEND=$(GCC_LIBS_DIR)/crtend.o LDFLAGS=-static -g -nostdlib $(CRT1) $(CRTI) $(CRTBEGIN) LIBS=-L$(LIBS_DIR) -ltinyc -lgcc $(CRTEND) $(CRTN) DEFINES=-Dsocklen_t=int +OP_CFLAGS=$(CFLAGS) endif ######################################################### @@ -31,7 +33,7 @@ endif DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU -DNO_TRACE_MSGS DEFINES+=-DCONFIG_PREFIX=\"/usr/local\" LDSCRIPT=$(ARCH).ld -LIBS+=-ldl +LIBS+=-ldl -lm OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ @@ -67,7 +69,7 @@ op-i386.h: op-i386.o dyngen ./dyngen -o $@ $< op-i386.o: op-i386.c opreg_template.h ops_template.h - $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $< %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< diff --git a/TODO b/TODO index 7ba6ab4a7..24eb3863f 100644 --- a/TODO +++ b/TODO @@ -3,3 +3,4 @@ - threads - fix printf for doubles (fp87.c bug ?) - make it self runnable (use same trick as ld.so : include its own relocator and libc) +- better FPU comparisons (ucom/com) diff --git a/cpu-i386.h b/cpu-i386.h index a857efb7d..c056a4677 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -75,6 +75,16 @@ enum { CC_OP_NB, }; +#ifdef __i386__ +#define USE_X86LDOUBLE +#endif + +#ifdef USE_X86LDOUBLE +typedef long double CPU86_LDouble; +#else +typedef double CPU86_LDouble; +#endif + typedef struct CPU86State { /* standard registers */ uint32_t regs[8]; @@ -91,10 +101,18 @@ typedef struct CPU86State { uint8_t *segs_base[6]; uint32_t segs[6]; + /* FPU state */ + CPU86_LDouble fpregs[8]; + uint8_t fptags[8]; /* 0 = valid, 1 = empty */ + unsigned int fpstt; /* top of stack index */ + unsigned int fpus; + unsigned int fpuc; + /* emulator internal variables */ uint32_t t0; /* temporary t0 storage */ uint32_t t1; /* temporary t1 storage */ uint32_t a0; /* temporary a0 storage (address) */ + CPU86_LDouble ft0; } CPU86State; static inline int ldub(void *ptr) @@ -122,6 +140,10 @@ static inline int ldl(void *ptr) return *(uint32_t *)ptr; } +static inline uint64_t ldq(void *ptr) +{ + return *(uint64_t *)ptr; +} static inline void stb(void *ptr, int v) { @@ -138,11 +160,40 @@ static inline void stl(void *ptr, int v) *(uint32_t *)ptr = v; } +static inline void stq(void *ptr, int v) +{ + *(uint64_t *)ptr = v; +} + +/* float access */ + +static inline float ldfl(void *ptr) +{ + return *(float *)ptr; +} + +static inline double ldfq(void *ptr) +{ + return *(double *)ptr; +} + +static inline void stfl(void *ptr, float v) +{ + *(float *)ptr = v; +} + +static inline void stfq(void *ptr, double v) +{ + *(double *)ptr = v; +} + +#ifndef IN_OP_I386 void port_outb(int addr, int val); void port_outw(int addr, int val); void port_outl(int addr, int val); int port_inb(int addr); int port_inw(int addr); int port_inl(int addr); +#endif #endif /* CPU_I386_H */ diff --git a/dyngen.c b/dyngen.c index ff10891b9..ce38dcaec 100644 --- a/dyngen.c +++ b/dyngen.c @@ -243,6 +243,8 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, if (n >= MAX_ARGS) error("too many arguments in %s", name); args_present[n - 1] = 1; + } else { + fprintf(outfile, "extern char %s;\n", sym_name); } } } @@ -257,6 +259,8 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, if (n >= MAX_ARGS) error("too many arguments in %s", name); args_present[n - 1] = 1; + } else { + fprintf(outfile, "extern char %s;\n", sym_name); } } } diff --git a/op-i386.c b/op-i386.c index 8607cf455..9fd4accd5 100644 --- a/op-i386.c +++ b/op-i386.c @@ -66,7 +66,13 @@ register struct CPU86State *env asm("l3"); #define CC_SRC (env->cc_src) #define CC_DST (env->cc_dst) -#define CC_OP (env->cc_op) +#define CC_OP (env->cc_op) + +/* float macros */ +#define FT0 (env->ft0) +#define ST0 (env->fpregs[env->fpstt]) +#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) +#define ST1 ST(1) extern int __op_param1, __op_param2, __op_param3; #define PARAM1 ((long)(&__op_param1)) @@ -133,6 +139,44 @@ const uint8_t rclb_table[32] = { 6, 7, 8, 0, 1, 2, 3, 4, }; +#ifdef USE_X86LDOUBLE +/* an array of Intel 80-bit FP constants, to be loaded via integer ops */ +typedef unsigned short f15ld[5]; +const f15ld f15rk[] = +{ +/*0*/ {0x0000,0x0000,0x0000,0x0000,0x0000}, +/*1*/ {0x0000,0x0000,0x0000,0x8000,0x3fff}, +/*pi*/ {0xc235,0x2168,0xdaa2,0xc90f,0x4000}, +/*lg2*/ {0xf799,0xfbcf,0x9a84,0x9a20,0x3ffd}, +/*ln2*/ {0x79ac,0xd1cf,0x17f7,0xb172,0x3ffe}, +/*l2e*/ {0xf0bc,0x5c17,0x3b29,0xb8aa,0x3fff}, +/*l2t*/ {0x8afe,0xcd1b,0x784b,0xd49a,0x4000} +}; +#else +/* the same, 64-bit version */ +typedef unsigned short f15ld[4]; +const f15ld f15rk[] = +{ +#ifndef WORDS_BIGENDIAN +/*0*/ {0x0000,0x0000,0x0000,0x0000}, +/*1*/ {0x0000,0x0000,0x0000,0x3ff0}, +/*pi*/ {0x2d18,0x5444,0x21fb,0x4009}, +/*lg2*/ {0x79ff,0x509f,0x4413,0x3fd3}, +/*ln2*/ {0x39ef,0xfefa,0x2e42,0x3fe6}, +/*l2e*/ {0x82fe,0x652b,0x1547,0x3ff7}, +/*l2t*/ {0xa371,0x0979,0x934f,0x400a} +#else +/*0*/ {0x0000,0x0000,0x0000,0x0000}, +/*1*/ {0x3ff0,0x0000,0x0000,0x0000}, +/*pi*/ {0x4009,0x21fb,0x5444,0x2d18}, +/*lg2*/ {0x3fd3,0x4413,0x509f,0x79ff}, +/*ln2*/ {0x3fe6,0x2e42,0xfefa,0x39ef}, +/*l2e*/ {0x3ff7,0x1547,0x652b,0x82fe}, +/*l2t*/ {0x400a,0x934f,0x0979,0xa371} +#endif +}; +#endif + /* n must be a constant to be efficient */ static inline int lshift(int x, int n) { @@ -866,3 +910,685 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, }; + +/* floating point support */ + +#ifdef USE_X86LDOUBLE +/* use long double functions */ +#define lrint lrintl +#define llrint llrintl +#define fabs fabsl +#define sin sinl +#define cos cosl +#define sqrt sqrtl +#define pow powl +#define log logl +#define tan tanl +#define atan2 atan2l +#define floor floorl +#define ceil ceill +#define rint rintl +#endif + +extern int lrint(CPU86_LDouble x); +extern int64_t llrint(CPU86_LDouble x); +extern CPU86_LDouble fabs(CPU86_LDouble x); +extern CPU86_LDouble sin(CPU86_LDouble x); +extern CPU86_LDouble cos(CPU86_LDouble x); +extern CPU86_LDouble sqrt(CPU86_LDouble x); +extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); +extern CPU86_LDouble log(CPU86_LDouble x); +extern CPU86_LDouble tan(CPU86_LDouble x); +extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); +extern CPU86_LDouble floor(CPU86_LDouble x); +extern CPU86_LDouble ceil(CPU86_LDouble x); +extern CPU86_LDouble rint(CPU86_LDouble x); + +#define RC_MASK 0xc00 +#define RC_NEAR 0x000 +#define RC_DOWN 0x400 +#define RC_UP 0x800 +#define RC_CHOP 0xc00 + +#define MAXTAN 9223372036854775808.0 + +#ifdef USE_X86LDOUBLE + +/* only for x86 */ +typedef union { + long double d; + struct { + unsigned long long lower; + unsigned short upper; + } l; +} CPU86_LDoubleU; + +/* the following deal with x86 long double-precision numbers */ +#define MAXEXPD 0x7fff +#define EXPBIAS 16383 +#define EXPD(fp) (fp.l.upper & 0x7fff) +#define SIGND(fp) ((fp.l.upper) & 0x8000) +#define MANTD(fp) (fp.l.lower) +#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS + +#else + +typedef { + double d; +#ifndef WORDS_BIGENDIAN + struct { + unsigned long lower; + long upper; + } l; +#else + struct { + long upper; + unsigned long lower; + } l; +#endif + long long ll; +} CPU86_LDoubleU; + +/* the following deal with IEEE double-precision numbers */ +#define MAXEXPD 0x7ff +#define EXPBIAS 1023 +#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) +#define SIGND(fp) ((fp.l.upper) & 0x80000000) +#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) +#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) +#endif + +/* fp load FT0 */ + +void OPPROTO op_flds_FT0_A0(void) +{ + FT0 = ldfl((void *)A0); +} + +void OPPROTO op_fldl_FT0_A0(void) +{ + FT0 = ldfq((void *)A0); +} + +void OPPROTO op_fild_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)ldsw((void *)A0); +} + +void OPPROTO op_fildl_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +} + +void OPPROTO op_fildll_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +} + +/* fp load ST0 */ + +void OPPROTO op_flds_ST0_A0(void) +{ + ST0 = ldfl((void *)A0); +} + +void OPPROTO op_fldl_ST0_A0(void) +{ + ST0 = ldfq((void *)A0); +} + +void OPPROTO op_fild_ST0_A0(void) +{ + ST0 = (CPU86_LDouble)ldsw((void *)A0); +} + +void OPPROTO op_fildl_ST0_A0(void) +{ + ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +} + +void OPPROTO op_fildll_ST0_A0(void) +{ + ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +} + +/* fp store */ + +void OPPROTO op_fsts_ST0_A0(void) +{ + stfl((void *)A0, (float)ST0); +} + +void OPPROTO op_fstl_ST0_A0(void) +{ + ST0 = ldfq((void *)A0); +} + +void OPPROTO op_fist_ST0_A0(void) +{ + int val; + val = lrint(ST0); + stw((void *)A0, val); +} + +void OPPROTO op_fistl_ST0_A0(void) +{ + int val; + val = lrint(ST0); + stl((void *)A0, val); +} + +void OPPROTO op_fistll_ST0_A0(void) +{ + int64_t val; + val = llrint(ST0); + stq((void *)A0, val); +} + +/* FPU move */ + +static inline void fpush(void) +{ + env->fpstt = (env->fpstt - 1) & 7; + env->fptags[env->fpstt] = 0; /* validate stack entry */ +} + +static inline void fpop(void) +{ + env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ + env->fpstt = (env->fpstt + 1) & 7; +} + +void OPPROTO op_fpush(void) +{ + fpush(); +} + +void OPPROTO op_fpop(void) +{ + fpop(); +} + +void OPPROTO op_fdecstp(void) +{ + env->fpstt = (env->fpstt - 1) & 7; + env->fpus &= (~0x4700); +} + +void OPPROTO op_fincstp(void) +{ + env->fpstt = (env->fpstt + 1) & 7; + env->fpus &= (~0x4700); +} + +void OPPROTO op_fmov_ST0_FT0(void) +{ + ST0 = FT0; +} + +void OPPROTO op_fmov_FT0_STN(void) +{ + FT0 = ST(PARAM1); +} + +void OPPROTO op_fmov_ST0_STN(void) +{ + ST0 = ST(PARAM1); +} + +void OPPROTO op_fmov_STN_ST0(void) +{ + ST(PARAM1) = ST0; +} + +void OPPROTO op_fxchg_ST0_STN(void) +{ + CPU86_LDouble tmp; + tmp = ST(PARAM1); + ST(PARAM1) = ST0; + ST0 = tmp; +} + +/* FPU operations */ + +/* XXX: handle nans */ +void OPPROTO op_fcom_ST0_FT0(void) +{ + env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ + if (ST0 < FT0) + env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ + else if (ST0 == FT0) + env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ + FORCE_RET(); +} + +void OPPROTO op_fadd_ST0_FT0(void) +{ + ST0 += FT0; +} + +void OPPROTO op_fmul_ST0_FT0(void) +{ + ST0 *= FT0; +} + +void OPPROTO op_fsub_ST0_FT0(void) +{ + ST0 -= FT0; +} + +void OPPROTO op_fsubr_ST0_FT0(void) +{ + ST0 = FT0 - ST0; +} + +void OPPROTO op_fdiv_ST0_FT0(void) +{ + ST0 /= FT0; +} + +void OPPROTO op_fdivr_ST0_FT0(void) +{ + ST0 = FT0 / ST0; +} + +/* fp operations between STN and ST0 */ + +void OPPROTO op_fadd_STN_ST0(void) +{ + ST(PARAM1) += ST0; +} + +void OPPROTO op_fmul_STN_ST0(void) +{ + ST(PARAM1) *= ST0; +} + +void OPPROTO op_fsub_STN_ST0(void) +{ + ST(PARAM1) -= ST0; +} + +void OPPROTO op_fsubr_STN_ST0(void) +{ + CPU86_LDouble *p; + p = &ST(PARAM1); + *p = ST0 - *p; +} + +void OPPROTO op_fdiv_STN_ST0(void) +{ + ST(PARAM1) /= ST0; +} + +void OPPROTO op_fdivr_STN_ST0(void) +{ + CPU86_LDouble *p; + p = &ST(PARAM1); + *p = ST0 / *p; +} + +/* misc FPU operations */ +void OPPROTO op_fchs_ST0(void) +{ + ST0 = -ST0; +} + +void OPPROTO op_fabs_ST0(void) +{ + ST0 = fabs(ST0); +} + +void OPPROTO op_fxam_ST0(void) +{ + CPU86_LDoubleU temp; + int expdif; + + temp.d = ST0; + + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + if (SIGND(temp)) + env->fpus |= 0x200; /* C1 <-- 1 */ + + expdif = EXPD(temp); + if (expdif == MAXEXPD) { + if (MANTD(temp) == 0) + env->fpus |= 0x500 /*Infinity*/; + else + env->fpus |= 0x100 /*NaN*/; + } else if (expdif == 0) { + if (MANTD(temp) == 0) + env->fpus |= 0x4000 /*Zero*/; + else + env->fpus |= 0x4400 /*Denormal*/; + } else { + env->fpus |= 0x400; + } + FORCE_RET(); +} + +void OPPROTO op_fld1_ST0(void) +{ + ST0 = *(CPU86_LDouble *)&f15rk[1]; +} + +void OPPROTO op_fld2t_ST0(void) +{ + ST0 = *(CPU86_LDouble *)&f15rk[6]; +} + +void OPPROTO op_fld2e_ST0(void) +{ + ST0 = *(CPU86_LDouble *)&f15rk[5]; +} + +void OPPROTO op_fldpi_ST0(void) +{ + ST0 = *(CPU86_LDouble *)&f15rk[2]; +} + +void OPPROTO op_fldlg2_ST0(void) +{ + ST0 = *(CPU86_LDouble *)&f15rk[3]; +} + +void OPPROTO op_fldln2_ST0(void) +{ + ST0 = *(CPU86_LDouble *)&f15rk[4]; +} + +void OPPROTO op_fldz_ST0(void) +{ + ST0 = *(CPU86_LDouble *)&f15rk[0]; +} + +void OPPROTO op_fldz_FT0(void) +{ + ST0 = *(CPU86_LDouble *)&f15rk[0]; +} + +void helper_f2xm1(void) +{ + ST0 = pow(2.0,ST0) - 1.0; +} + +void helper_fyl2x(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp>0.0){ + fptemp = log(fptemp)/log(2.0); /* log2(ST) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +void helper_fptan(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = tan(fptemp); + fpush(); + ST0 = 1.0; + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**52 only */ + } +} + +void helper_fpatan(void) +{ + CPU86_LDouble fptemp, fpsrcop; + + fpsrcop = ST1; + fptemp = ST0; + ST1 = atan2(fpsrcop,fptemp); + fpop(); +} + +void helper_fxtract(void) +{ + CPU86_LDoubleU temp; + unsigned int expdif; + + temp.d = ST0; + expdif = EXPD(temp) - EXPBIAS; + /*DP exponent bias*/ + ST0 = expdif; + fpush(); + BIASEXPONENT(temp); + ST0 = temp.d; +} + +void helper_fprem1(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + int q; + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + if (expdif < 53) { + dblq = fpsrcop / fptemp; + dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); + ST0 = fpsrcop - fptemp*dblq; + q = (int)dblq; /* cutting off top bits is assumed here */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C1,C3) <-- (q2,q1,q0) */ + env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ + env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ + env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif-50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by rounding to the nearest */ + fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? + floor(fpsrcop): ceil(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +void helper_fprem(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + int q; + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + if ( expdif < 53 ) { + dblq = fpsrcop / fptemp; + dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); + ST0 = fpsrcop - fptemp*dblq; + q = (int)dblq; /* cutting off top bits is assumed here */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C1,C3) <-- (q2,q1,q0) */ + env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ + env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ + env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif-50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by chopping */ + fpsrcop = (fpsrcop < 0.0)? + -(floor(fabs(fpsrcop))): floor(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +void helper_fyl2xp1(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp+1.0)>0.0) { + fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +void helper_fsqrt(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp<0.0) { + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + env->fpus |= 0x400; + } + ST0 = sqrt(fptemp); +} + +void helper_fsincos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + fpush(); + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**63 only */ + } +} + +void helper_frndint(void) +{ + ST0 = rint(ST0); +} + +void helper_fscale(void) +{ + CPU86_LDouble fpsrcop, fptemp; + + fpsrcop = 2.0; + fptemp = pow(fpsrcop,ST1); + ST0 *= fptemp; +} + +void helper_fsin(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**53 only */ + } +} + +void helper_fcos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg5 < 2**63 only */ + } +} + +/* associated heplers to reduce generated code length and to simplify + relocation (FP constants are usually stored in .rodata section) */ + +void OPPROTO op_f2xm1(void) +{ + helper_f2xm1(); +} + +void OPPROTO op_fyl2x(void) +{ + helper_fyl2x(); +} + +void OPPROTO op_fptan(void) +{ + helper_fptan(); +} + +void OPPROTO op_fpatan(void) +{ + helper_fpatan(); +} + +void OPPROTO op_fxtract(void) +{ + helper_fxtract(); +} + +void OPPROTO op_fprem1(void) +{ + helper_fprem1(); +} + + +void OPPROTO op_fprem(void) +{ + helper_fprem(); +} + +void OPPROTO op_fyl2xp1(void) +{ + helper_fyl2xp1(); +} + +void OPPROTO op_fsqrt(void) +{ + helper_fsqrt(); +} + +void OPPROTO op_fsincos(void) +{ + helper_fsincos(); +} + +void OPPROTO op_frndint(void) +{ + helper_frndint(); +} + +void OPPROTO op_fscale(void) +{ + helper_fscale(); +} + +void OPPROTO op_fsin(void) +{ + helper_fsin(); +} + +void OPPROTO op_fcos(void) +{ + helper_fcos(); +} + diff --git a/translate-i386.c b/translate-i386.c index 0c1b95a92..0ad24e3a4 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -5,6 +5,7 @@ #include #include +#define IN_OP_I386 #include "cpu-i386.h" static uint8_t *gen_code_ptr; @@ -39,7 +40,6 @@ typedef struct DisasContext { int prefix; int aflag, dflag; uint8_t *pc; /* current pc */ - uint8_t *runtime_pc; /* current pc in the runtime generated code */ int cc_op; /* current CC operation */ int f_st; } DisasContext; @@ -68,18 +68,6 @@ enum { OP_SAR = 7, }; - -static const int fp_ops[8] = { -#if 0 - OP_FADDQ, OP_FMULQ, OP_CMP, OP_CMP, - OP_FSUBQ, OP_FSUBQ, OP_FDIVQ, OP_FDIVQ -#endif -}; - -extern char cc_table, rclw_table, rclb_table; -extern char helper_rcll_T0_T1_cc; -extern char __udivdi3, __umoddi3; - #include "op-i386.h" /* operand size */ @@ -606,6 +594,28 @@ static GenOpFunc *gen_setcc_sub[3][8] = { }, }; +static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { + gen_op_fadd_ST0_FT0, + gen_op_fmul_ST0_FT0, + gen_op_fcom_ST0_FT0, + gen_op_fcom_ST0_FT0, + gen_op_fsub_ST0_FT0, + gen_op_fsubr_ST0_FT0, + gen_op_fdiv_ST0_FT0, + gen_op_fdivr_ST0_FT0, +}; + +static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { + gen_op_fadd_STN_ST0, + gen_op_fmul_STN_ST0, + NULL, + NULL, + gen_op_fsub_STN_ST0, + gen_op_fsubr_STN_ST0, + gen_op_fdiv_STN_ST0, + gen_op_fdivr_STN_ST0, +}; + static void gen_op(DisasContext *s1, int op, int ot, int d, int s) { if (d != OR_TMP0) @@ -1345,12 +1355,12 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ - gen_op_mov_TN_reg[OT_LONG][0][(b & 7)](); + gen_op_mov_TN_reg[OT_LONG][0][b & 7](); gen_op_pushl_T0(); break; case 0x58 ... 0x5f: /* pop */ gen_op_popl_T0(); - gen_op_mov_reg_T0[OT_LONG][reg](); + gen_op_mov_reg_T0[OT_LONG][b & 7](); break; case 0x68: /* push Iv */ case 0x6a: @@ -1581,7 +1591,6 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* floats */ -#if 0 case 0xd8 ... 0xdf: modrm = ldub(s->pc++); mod = (modrm >> 6) & 3; @@ -1597,52 +1606,29 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) case 0x20 ... 0x27: /* fxxxl */ case 0x30 ... 0x37: /* fixxx */ { - int op1, swap; - op1 = fp_ops[op & 7]; - - swap = 0; - if ((op & 7) == 5 || (op & 7) == 7) - swap = 1; + int op1; + op1 = op & 7; switch(op >> 4) { case 0: - ot = OT_LONG; - is_int = 0; + gen_op_flds_FT0_A0(); break; case 1: - ot = OT_LONG; - is_int = 1; + gen_op_fildl_FT0_A0(); break; case 2: - ot = OT_QUAD; - is_int = 0; + gen_op_fldl_FT0_A0(); break; case 3: default: - ot = OT_WORD; - is_int = 1; + gen_op_fild_FT0_A0(); break; } - /* if integer, needs to convert to float */ - if (is_int) { - /* XXX: potential loss of precision if large integer */ - gen_ld(OP_LDUB + ot, OR_TMP0, reg_addr, offset_addr); - gen_insn2(OP_I2FL, OR_FTMP0, OR_TMP0); - } else { - gen_ld(OP_LDUB + ot, OR_FTMP0, reg_addr, offset_addr); - } - if (ot != OT_QUAD) - op1 += OP_FADDL - OP_FADDQ; - - if (!swap) - gen_insn3(op1, OR_ST0, OR_ST0, OR_FTMP0); - else - gen_insn3(op1, OR_ST0, OR_FTMP0, OR_ST0); - - if ((op & 7) == 3) { + gen_op_fp_arith_ST0_FT0[op1](); + if (op1 == 3) { /* fcomp needs pop */ - gen_insn0(OP_FPOP); + gen_op_fpop(); } } break; @@ -1659,49 +1645,47 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) case 0x3a: /* fists */ case 0x3b: /* fistps */ - switch(op >> 4) { - case 0: - ot = OT_LONG; - is_int = 0; - break; - case 1: - ot = OT_LONG; - is_int = 1; - break; - case 2: - ot = OT_QUAD; - is_int = 0; - break; - case 3: - default: - ot = OT_WORD; - is_int = 1; - break; - } - switch(op & 7) { case 0: - gen_insn0(OP_FPUSH); - if (is_int) { - /* XXX: potential loss of precision */ - gen_ld(OP_LDUB + ot, OR_TMP0, reg_addr, offset_addr); - gen_insn2(OP_I2FL, OR_ST0, OR_TMP0); - } else { - gen_ld(OP_LDUB + ot, OR_ST0, reg_addr, offset_addr); + gen_op_fpush(); + switch(op >> 4) { + case 0: + gen_op_flds_ST0_A0(); + break; + case 1: + gen_op_fildl_ST0_A0(); + break; + case 2: + gen_op_fldl_ST0_A0(); + break; + case 3: + default: + gen_op_fild_ST0_A0(); + break; } break; default: - if (is_int) { - gen_insn2(OP_F2IL, OR_TMP0, OR_ST0); - gen_st(OP_STB + ot, OR_TMP0, reg_addr, offset_addr); - } else { - gen_st(OP_STB + ot, OR_ST0, reg_addr, offset_addr); + switch(op >> 4) { + case 0: + gen_op_fsts_ST0_A0(); + break; + case 1: + gen_op_fistl_ST0_A0(); + break; + case 2: + gen_op_fstl_ST0_A0(); + break; + case 3: + default: + gen_op_fist_ST0_A0(); + break; } if ((op & 7) == 3) - gen_insn0(OP_FPOP); + gen_op_fpop(); break; } break; +#if 0 case 0x2f: /* fnstsw mem */ gen_insn3(OP_FNSTS, OR_TMP0, OR_ZERO, OR_ZERO); gen_st(OP_STW, OR_TMP0, reg_addr, offset_addr); @@ -1711,15 +1695,14 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) case 0x3e: /* fbstp */ error("float BCD not hanlded"); return -1; +#endif case 0x3d: /* fildll */ - gen_insn0(OP_FPUSH); - gen_ld(OP_LDQ, OR_TMP0, reg_addr, offset_addr); - gen_insn2(OP_I2FQ, OR_ST0, OR_TMP0); + gen_op_fpush(); + gen_op_fildll_ST0_A0(); break; case 0x3f: /* fistpll */ - gen_insn2(OP_F2IQ, OR_TMP0, OR_ST0); - gen_st(OP_STQ, OR_TMP0, reg_addr, offset_addr); - gen_insn0(OP_FPOP); + gen_op_fistll_ST0_A0(); + gen_op_fpop(); break; default: error("unhandled memory FP\n"); @@ -1727,22 +1710,19 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) } } else { /* register float ops */ - opreg = rm + OR_ST0; + opreg = rm; switch(op) { case 0x08: /* fld sti */ - gen_insn0(OP_FPUSH); - gen_mov(OR_ST0, OR_ST0 + ((rm + 1) & 7)); + gen_op_fpush(); + gen_op_fmov_ST0_STN((opreg + 1) & 7); break; case 0x09: /* fxchg sti */ - gen_mov(OR_TMP0, OR_ST0); - gen_mov(OR_ST0, opreg); - gen_mov(opreg, OR_TMP0); + gen_op_fxchg_ST0_STN((opreg + 1) & 7); break; case 0x0a: /* grp d9/2 */ switch(rm) { case 0: /* fnop */ - gen_insn0(OP_NOP); break; default: error("unhandled FP GRP d9/2\n"); @@ -1752,16 +1732,17 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) case 0x0c: /* grp d9/4 */ switch(rm) { case 0: /* fchs */ - gen_insn3(OP_FSUBQ, OR_ST0, OR_ZERO, OR_ST0); + gen_op_fchs_ST0(); break; case 1: /* fabs */ - gen_insn2(OP_FABSQ, OR_ST0, OR_ST0); + gen_op_fabs_ST0(); break; case 4: /* ftst */ - gen_insn3(OP_CMP, OR_ZERO, OR_ST0, OR_ZERO); + gen_op_fldz_FT0(); + gen_op_fcom_ST0_FT0(); break; case 5: /* fxam */ - gen_insn3(OP_FSPECIAL, OR_ZERO, OR_ST0, OR_ZERO); + gen_op_fxam_ST0(); break; default: return -1; @@ -1769,76 +1750,88 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x0d: /* grp d9/5 */ { - if (rm == 7) { - error("bad GRP d9/5"); + switch(rm) { + case 0: + gen_op_fld1_ST0(); + break; + case 1: + gen_op_fld2t_ST0(); + break; + case 2: + gen_op_fld2e_ST0(); + break; + case 3: + gen_op_fldpi_ST0(); + break; + case 4: + gen_op_fldlg2_ST0(); + break; + case 5: + gen_op_fldln2_ST0(); + break; + case 6: + gen_op_fldz_ST0(); + break; + default: return -1; } - /* XXX: needs constant load or symbol table */ - gen_insn0(OP_FPUSH); - gen_ld(OP_LDQ, OR_ST0, OR_ZERO, - (rm * 8) + FLOAT_CONST_ADDR); } break; case 0x0e: /* grp d9/6 */ switch(rm) { case 0: /* f2xm1 */ - gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO); + gen_op_f2xm1(); break; case 1: /* fyl2x */ - gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); - gen_insn0(OP_FPOP); + gen_op_fyl2x(); break; case 2: /* fptan */ - gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO); - gen_insn0(OP_FPUSH); - /* load one */ - gen_ld(OP_LDQ, OR_ST0, OR_ZERO, - (0 * 8) + FLOAT_CONST_ADDR); + gen_op_fptan(); break; case 3: /* fpatan */ - gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); - gen_insn0(OP_FPOP); + gen_op_fpatan(); break; case 4: /* fxtract */ - gen_insn0(OP_FPUSH); - gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST1, OR_ZERO); - gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST1, OR_ZERO); + gen_op_fxtract(); break; case 5: /* fprem1 */ - gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1); + gen_op_fprem1(); break; case 6: /* fdecstp */ - gen_insn0(OP_FPUSH); + gen_op_fdecstp(); break; default: - case 7: /* fdecstp */ - gen_insn0(OP_FPOP); + case 7: /* fincstp */ + gen_op_fincstp(); break; } break; case 0x0f: /* grp d9/7 */ switch(rm) { case 0: /* fprem */ - gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1); + gen_op_fprem(); break; case 1: /* fyl2xp1 */ - gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1); - gen_insn0(OP_FPOP); + gen_op_fyl2xp1(); + break; + case 2: /* fsqrt */ + gen_op_fsqrt(); break; case 3: /* fsincos */ - gen_insn0(OP_FPUSH); - gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST1, OR_ZERO); - gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST1, OR_ZERO); + gen_op_fsincos(); break; case 5: /* fscale */ - gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1); + gen_op_fscale(); break; - case 2: /* fsqrt */ case 4: /* frndint */ + gen_op_frndint(); + break; case 6: /* fsin */ + gen_op_fsin(); + break; default: case 7: /* fcos */ - gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO); + gen_op_fcos(); break; } break; @@ -1846,58 +1839,54 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ { - int op1, swap; + int op1; - op1 = fp_ops[op & 7]; - swap = 0; - if ((op & 7) == 5 || (op & 7) == 7) - swap = 1; + op1 = op & 7; if (op >= 0x20) { - if (swap) - gen_insn3(op1, opreg, OR_ST0, opreg); - else - gen_insn3(op1, opreg, opreg, OR_ST0); + gen_op_fp_arith_STN_ST0[op1](opreg); } else { - if (swap) - gen_insn3(op1, OR_ST0, opreg, OR_ST0); - else - gen_insn3(op1, OR_ST0, OR_ST0, opreg); + gen_op_fmov_FT0_STN(opreg); + gen_op_fp_arith_ST0_FT0[op1](); } if (op >= 0x30) - gen_insn0(OP_FPOP); + gen_op_fpop(); } break; case 0x02: /* fcom */ - gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcom_ST0_FT0(); break; case 0x03: /* fcomp */ - gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); - gen_insn0(OP_FPOP); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); break; case 0x15: /* da/5 */ switch(rm) { case 1: /* fucompp */ - gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); - gen_insn0(OP_FPOP); - gen_insn0(OP_FPOP); + gen_op_fmov_FT0_STN(1); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); + gen_op_fpop(); break; default: return -1; } break; case 0x2a: /* fst sti */ - gen_mov(opreg, OR_ST0); + gen_op_fmov_STN_ST0(opreg); break; case 0x2b: /* fstp sti */ - gen_mov(opreg, OR_ST0); - gen_insn0(OP_FPOP); + gen_op_fmov_STN_ST0(opreg); + gen_op_fpop(); break; case 0x33: /* de/3 */ switch(rm) { case 1: /* fcompp */ - gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg); - gen_insn0(OP_FPOP); - gen_insn0(OP_FPOP); + gen_op_fmov_FT0_STN(1); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); + gen_op_fpop(); break; default: return -1; @@ -1905,9 +1894,11 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x3c: /* df/4 */ switch(rm) { +#if 0 case 0: gen_insn3(OP_FNSTS, OR_EAX, OR_ZERO, OR_ZERO); break; +#endif default: return -1; } @@ -1918,7 +1909,6 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) } } break; -#endif /************************/ /* string ops */ case 0xa4: /* movsS */ -- cgit v1.2.3 From ba1c6e37fc5efc0f3d1e50d0760f9f4a1061187b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Mar 2003 11:58:28 +0000 Subject: test infrastructure git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@16 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 27 +++++++----- linux-user/main.c | 12 +++--- op-i386.c | 53 +++++++++++++++++++---- ops_template.h | 20 +++++++-- translate-i386.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 194 insertions(+), 43 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index c056a4677..4eac51fb5 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -85,7 +85,7 @@ typedef long double CPU86_LDouble; typedef double CPU86_LDouble; #endif -typedef struct CPU86State { +typedef struct CPUX86State { /* standard registers */ uint32_t regs[8]; uint32_t pc; /* cs_case + eip value */ @@ -109,11 +109,8 @@ typedef struct CPU86State { unsigned int fpuc; /* emulator internal variables */ - uint32_t t0; /* temporary t0 storage */ - uint32_t t1; /* temporary t1 storage */ - uint32_t a0; /* temporary a0 storage (address) */ CPU86_LDouble ft0; -} CPU86State; +} CPUX86State; static inline int ldub(void *ptr) { @@ -188,12 +185,20 @@ static inline void stfq(void *ptr, double v) } #ifndef IN_OP_I386 -void port_outb(int addr, int val); -void port_outw(int addr, int val); -void port_outl(int addr, int val); -int port_inb(int addr); -int port_inw(int addr); -int port_inl(int addr); +void cpu_x86_outb(int addr, int val); +void cpu_x86_outw(int addr, int val); +void cpu_x86_outl(int addr, int val); +int cpu_x86_inb(int addr); +int cpu_x86_inw(int addr); +int cpu_x86_inl(int addr); #endif +CPUX86State *cpu_x86_init(void); +int cpu_x86_exec(CPUX86State *s); +void cpu_x86_close(CPUX86State *s); + +/* internal functions */ +int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, + uint8_t *pc_start); + #endif /* CPU_I386_H */ diff --git a/linux-user/main.c b/linux-user/main.c index 1d76d4d7c..552ce006c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -193,34 +193,34 @@ void INT_handler(int num, void *env) /***********************************************************/ /* new CPU core */ -void port_outb(int addr, int val) +void cpu_x86_outb(int addr, int val) { fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); } -void port_outw(int addr, int val) +void cpu_x86_outw(int addr, int val) { fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); } -void port_outl(int addr, int val) +void cpu_x86_outl(int addr, int val) { fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); } -int port_inb(int addr) +int cpu_x86_inb(int addr) { fprintf(stderr, "inb: port=0x%04x\n", addr); return 0; } -int port_inw(int addr) +int cpu_x86_inw(int addr) { fprintf(stderr, "inw: port=0x%04x\n", addr); return 0; } -int port_inl(int addr) +int cpu_x86_inl(int addr) { fprintf(stderr, "inl: port=0x%04x\n", addr); return 0; diff --git a/op-i386.c b/op-i386.c index 9fd4accd5..9443e172c 100644 --- a/op-i386.c +++ b/op-i386.c @@ -10,39 +10,44 @@ typedef signed long long int64_t; #define NULL 0 +typedef struct FILE FILE; + +extern FILE *stderr; +extern int fprintf(FILE *, const char *, ...); + #ifdef __i386__ register int T0 asm("esi"); register int T1 asm("ebx"); register int A0 asm("edi"); -register struct CPU86State *env asm("ebp"); +register struct CPUX86State *env asm("ebp"); #define FORCE_RET() asm volatile ("ret"); #endif #ifdef __powerpc__ register int T0 asm("r24"); register int T1 asm("r25"); register int A0 asm("r26"); -register struct CPU86State *env asm("r27"); +register struct CPUX86State *env asm("r27"); #define FORCE_RET() asm volatile ("blr"); #endif #ifdef __arm__ register int T0 asm("r4"); register int T1 asm("r5"); register int A0 asm("r6"); -register struct CPU86State *env asm("r7"); +register struct CPUX86State *env asm("r7"); #define FORCE_RET() asm volatile ("mov pc, lr"); #endif #ifdef __mips__ register int T0 asm("s0"); register int T1 asm("s1"); register int A0 asm("s2"); -register struct CPU86State *env asm("s3"); +register struct CPUX86State *env asm("s3"); #define FORCE_RET() asm volatile ("jr $31"); #endif #ifdef __sparc__ register int T0 asm("l0"); register int T1 asm("l1"); register int A0 asm("l2"); -register struct CPU86State *env asm("l3"); +register struct CPUX86State *env asm("l3"); #define FORCE_RET() asm volatile ("retl ; nop"); #endif @@ -465,17 +470,17 @@ void OPPROTO op_idivl_EAX_T0(void) /* constant load */ -void OPPROTO op1_movl_T0_im(void) +void OPPROTO op_movl_T0_im(void) { T0 = PARAM1; } -void OPPROTO op1_movl_T1_im(void) +void OPPROTO op_movl_T1_im(void) { T1 = PARAM1; } -void OPPROTO op1_movl_A0_im(void) +void OPPROTO op_movl_A0_im(void) { A0 = PARAM1; } @@ -1592,3 +1597,35 @@ void OPPROTO op_fcos(void) helper_fcos(); } +/* main execution loop */ +uint8_t code_gen_buffer[65536]; + + +int cpu_x86_exec(CPUX86State *env1) +{ + int saved_T0, saved_T1, saved_A0; + CPUX86State *saved_env; + int code_gen_size; + void (*gen_func)(void); + + /* first we save global registers */ + saved_T0 = T0; + saved_T1 = T1; + saved_A0 = A0; + saved_env = env; + env = env1; + + for(;;) { + cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); + /* execute the generated code */ + gen_func = (void *)code_gen_buffer; + gen_func(); + } + + /* restore global registers */ + T0 = saved_T0; + T1 = saved_T1; + A0 = saved_A0; + env = saved_env; + return 0; +} diff --git a/ops_template.h b/ops_template.h index 403247294..18b2ffb49 100644 --- a/ops_template.h +++ b/ops_template.h @@ -575,12 +575,14 @@ void OPPROTO glue(op_repnz_cmps, SUFFIX)(void) } } +/* port I/O */ + void OPPROTO glue(op_outs, SUFFIX)(void) { int v, dx; dx = EDX & 0xffff; v = glue(ldu, SUFFIX)((void *)ESI); - glue(port_out, SUFFIX)(dx, v); + glue(cpu_x86_out, SUFFIX)(dx, v); ESI += (DF << SHIFT); } @@ -591,7 +593,7 @@ void OPPROTO glue(op_rep_outs, SUFFIX)(void) dx = EDX & 0xffff; while (ECX != 0) { v = glue(ldu, SUFFIX)((void *)ESI); - glue(port_out, SUFFIX)(dx, v); + glue(cpu_x86_out, SUFFIX)(dx, v); ESI += inc; ECX--; } @@ -601,7 +603,7 @@ void OPPROTO glue(op_ins, SUFFIX)(void) { int v, dx; dx = EDX & 0xffff; - v = glue(port_in, SUFFIX)(dx); + v = glue(cpu_x86_in, SUFFIX)(dx); glue(st, SUFFIX)((void *)EDI, v); EDI += (DF << SHIFT); } @@ -612,13 +614,23 @@ void OPPROTO glue(op_rep_ins, SUFFIX)(void) inc = (DF << SHIFT); dx = EDX & 0xffff; while (ECX != 0) { - v = glue(port_in, SUFFIX)(dx); + v = glue(cpu_x86_in, SUFFIX)(dx); glue(st, SUFFIX)((void *)EDI, v); EDI += (DF << SHIFT); ECX--; } } +void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) +{ + glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK); +} + +void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) +{ + T1 = glue(cpu_x86_in, SUFFIX)(T0 & 0xffff); +} + #undef DATA_BITS #undef SHIFT_MASK #undef SIGN_MASK diff --git a/translate-i386.c b/translate-i386.c index 0ad24e3a4..9ebc81e2c 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -495,6 +495,18 @@ static GenOpFunc *gen_op_outs[6] = { gen_op_rep_outsl, }; +static GenOpFunc *gen_op_in[3] = { + gen_op_inb_T0_T1, + gen_op_inw_T0_T1, + gen_op_inl_T0_T1, +}; + +static GenOpFunc *gen_op_out[3] = { + gen_op_outb_T0_T1, + gen_op_outw_T0_T1, + gen_op_outl_T0_T1, +}; + enum { JCC_O, JCC_B, @@ -632,7 +644,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d, int s) static void gen_opi(DisasContext *s1, int op, int ot, int d, int c) { - gen_op1_movl_T1_im(c); + gen_op_movl_T1_im(c); gen_op(s1, op, ot, d, OR_TMP0); } @@ -678,7 +690,7 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) { /* currently not optimized */ - gen_op1_movl_T1_im(c); + gen_op_movl_T1_im(c); gen_shift(s1, op, ot, d, OR_TMP1); } @@ -746,7 +758,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ if (reg2 == OR_ZERO) { /* op: disp + (reg1 << scale) */ if (reg1 == OR_ZERO) { - gen_op1_movl_A0_im(disp); + gen_op_movl_A0_im(disp); } else if (scale == 0 && disp == 0) { gen_op_movl_A0_reg[reg1](); } else { @@ -755,7 +767,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ } else { /* op: disp + reg1 + (reg2 << scale) */ if (disp != 0) { - gen_op1_movl_A0_im(disp); + gen_op_movl_A0_im(disp); gen_op_addl_A0_reg_sN[0][reg1](); } else { gen_op_movl_A0_reg[reg1](); @@ -1149,7 +1161,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) switch(op) { case 0: /* test */ val = insn_get(s, ot); - gen_op1_movl_T1_im(val); + gen_op_movl_T1_im(val); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; @@ -1266,7 +1278,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_st_T0_A0[ot](); break; case 2: /* call Ev */ - gen_op1_movl_T1_im((long)s->pc); + gen_op_movl_T1_im((long)s->pc); gen_op_pushl_T1(); gen_op_jmp_T0(); break; @@ -1309,7 +1321,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) val = insn_get(s, ot); gen_op_mov_TN_reg[ot][0][OR_EAX](); - gen_op1_movl_T1_im(val); + gen_op_movl_T1_im(val); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; @@ -1336,10 +1348,10 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); if (b == 0x69) { val = insn_get(s, ot); - gen_op1_movl_T1_im(val); + gen_op_movl_T1_im(val); } else if (b == 0x6b) { val = insn_get(s, OT_BYTE); - gen_op1_movl_T1_im(val); + gen_op_movl_T1_im(val); } else { gen_op_mov_TN_reg[ot][1][reg](); } @@ -1369,7 +1381,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) val = insn_get(s, ot); else val = (int8_t)insn_get(s, OT_BYTE); - gen_op1_movl_T0_im(val); + gen_op_movl_T0_im(val); gen_op_pushl_T0(); break; case 0x8f: /* pop Ev */ @@ -1408,7 +1420,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) mod = (modrm >> 6) & 3; val = insn_get(s, ot); - gen_op1_movl_T0_im(val); + gen_op_movl_T0_im(val); gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; case 0x8a: @@ -1502,14 +1514,14 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) case 0xb0 ... 0xb7: /* mov R, Ib */ val = insn_get(s, OT_BYTE); - gen_op1_movl_T0_im(val); + gen_op_movl_T0_im(val); gen_op_mov_reg_T0[OT_BYTE][b & 7](); break; case 0xb8 ... 0xbf: /* mov R, Iv */ ot = dflag ? OT_LONG : OT_WORD; val = insn_get(s, ot); reg = OR_EAX + (b & 7); - gen_op1_movl_T0_im(val); + gen_op_movl_T0_im(val); gen_op_mov_reg_T0[ot][reg](); break; @@ -1978,6 +1990,8 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) } break; + /************************/ + /* port I/O */ case 0x6c: /* insS */ case 0x6d: if ((b & 1) == 0) @@ -2002,6 +2016,48 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_outs[ot](); } break; + case 0xe4: + case 0xe5: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + break; + case 0xe6: + case 0xe7: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + break; + case 0xec: + case 0xed: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + break; + case 0xee: + case 0xef: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + break; /************************/ /* control */ @@ -2020,7 +2076,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) case 0xe8: /* call */ val = insn_get(s, OT_LONG); val += (long)s->pc; - gen_op1_movl_T1_im((long)s->pc); + gen_op_movl_T1_im((long)s->pc); gen_op_pushl_T1(); gen_op_jmp_im(val); break; @@ -2121,3 +2177,44 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) return (long)s->pc; } +/* return the next pc */ +int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, + uint8_t *pc_start) +{ + DisasContext dc1, *dc = &dc1; + long ret; + dc->cc_op = CC_OP_DYNAMIC; + gen_code_ptr = gen_code_buf; + gen_start(); + ret = disas_insn(dc, pc_start); + if (ret == -1) + error("unknown instruction at PC=0x%x", pc_start); + gen_end(); + *gen_code_size_ptr = gen_code_ptr - gen_code_buf; + printf("0x%08lx: code_size = %d\n", (long)pc_start, *gen_code_size_ptr); + return 0; +} + +CPUX86State *cpu_x86_init(void) +{ + CPUX86State *env; + int i; + + env = malloc(sizeof(CPUX86State)); + if (!env) + return NULL; + memset(env, 0, sizeof(CPUX86State)); + /* basic FPU init */ + for(i = 0;i < 8; i++) + env->fptags[i] = 1; + env->fpuc = 0x37f; + /* flags setup */ + env->cc_op = CC_OP_EFLAGS; + env->df = 1; + return env; +} + +void cpu_x86_close(CPUX86State *env) +{ + free(env); +} -- cgit v1.2.3 From 0ecfa9930c7615503ba629a61f7b94a0c3305af5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Mar 2003 14:32:43 +0000 Subject: prints hello world git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@17 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 11 ++- cpu-i386.h | 45 +++++++++-- linux-user/main.c | 231 +++++++++--------------------------------------------- op-i386.c | 103 ++++++++++++++++-------- ops_template.h | 24 +++--- translate-i386.c | 132 +++++++++++++++++++++++++++++-- 6 files changed, 289 insertions(+), 257 deletions(-) diff --git a/Makefile b/Makefile index a61ab4a76..b007f40dd 100644 --- a/Makefile +++ b/Makefile @@ -30,16 +30,19 @@ endif ######################################################### -DEFINES+=-D_GNU_SOURCE -DGEMU -DDOSEMU -DNO_TRACE_MSGS +DEFINES+=-D_GNU_SOURCE DEFINES+=-DCONFIG_PREFIX=\"/usr/local\" LDSCRIPT=$(ARCH).ld LIBS+=-ldl -lm -OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ - i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ - i386/dis8086.o i386/emu-ldt.o +#DEFINES+= -DGEMU -DDOSEMU -DNO_TRACE_MSGS +#OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ +# i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ +# i386/dis8086.o i386/emu-ldt.o OBJS+=translate-i386.o op-i386.o OBJS+= elfload.o main.o thunk.o syscall.o +# NOTE: the disassembler code is only needed for debugging +OBJS+=i386-dis.o dis-buf.o SRCS = $(OBJS:.o=.c) all: gemu diff --git a/cpu-i386.h b/cpu-i386.h index 4eac51fb5..9add4175d 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -1,6 +1,11 @@ +/* NOTE: this header is included in op-i386.c where global register + variable are used. Care must be used when including glibc headers. + */ #ifndef CPU_I386_H #define CPU_I386_H +#include + #define R_EAX 0 #define R_ECX 1 #define R_EDX 2 @@ -43,6 +48,27 @@ #define VM_FLAG 0x20000 /* AC 0x40000 */ +#define EXCP00_DIVZ 1 +#define EXCP01_SSTP 2 +#define EXCP02_NMI 3 +#define EXCP03_INT3 4 +#define EXCP04_INTO 5 +#define EXCP05_BOUND 6 +#define EXCP06_ILLOP 7 +#define EXCP07_PREX 8 +#define EXCP08_DBLE 9 +#define EXCP09_XERR 10 +#define EXCP0A_TSS 11 +#define EXCP0B_NOSEG 12 +#define EXCP0C_STACK 13 +#define EXCP0D_GPF 14 +#define EXCP0E_PAGE 15 +#define EXCP10_COPR 17 +#define EXCP11_ALGN 18 +#define EXCP12_MCHK 19 + +#define EXCP_SIGNAL 256 /* async signal */ + enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ @@ -89,27 +115,34 @@ typedef struct CPUX86State { /* standard registers */ uint32_t regs[8]; uint32_t pc; /* cs_case + eip value */ - - /* eflags handling */ uint32_t eflags; + + /* emulator internal eflags handling */ uint32_t cc_src; uint32_t cc_dst; uint32_t cc_op; int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ - + /* segments */ uint8_t *segs_base[6]; - uint32_t segs[6]; /* FPU state */ - CPU86_LDouble fpregs[8]; - uint8_t fptags[8]; /* 0 = valid, 1 = empty */ unsigned int fpstt; /* top of stack index */ unsigned int fpus; unsigned int fpuc; + uint8_t fptags[8]; /* 0 = valid, 1 = empty */ + CPU86_LDouble fpregs[8]; + + /* segments */ + uint32_t segs[6]; /* emulator internal variables */ + CPU86_LDouble ft0; + + /* exception handling */ + jmp_buf jmp_env; + int exception_index; } CPUX86State; static inline int ldub(void *ptr) diff --git a/linux-user/main.c b/linux-user/main.c index 552ce006c..68858daf4 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -21,10 +21,11 @@ #include #include #include +#include #include "gemu.h" -#include "i386/hsw_interp.h" +#include "cpu-i386.h" unsigned long x86_stack_size; unsigned long stktop; @@ -38,160 +39,8 @@ void gemu_log(const char *fmt, ...) va_end(ap); } -/* virtual x86 CPU stuff */ - -extern int invoke_code16(Interp_ENV *, int, int); -extern int invoke_code32(Interp_ENV *, int); -extern char *e_print_cpuemu_regs(ENVPARAMS, int is32); -extern char *e_emu_disasm(ENVPARAMS, unsigned char *org, int is32); -extern void init_npu(void); - -Interp_ENV env_global; -Interp_ENV *envp_global; - -QWORD EMUtime = 0; - -int CEmuStat = 0; - -long instr_count; - -/* who will initialize this? */ -unsigned long io_bitmap[IO_BITMAP_SIZE+1]; - -/* debug flag, 0=disable 1..9=level */ -int d_emu = 0; - -unsigned long CRs[5] = -{ - 0x00000013, /* valid bits: 0xe005003f */ - 0x00000000, /* invalid */ - 0x00000000, - 0x00000000, - 0x00000000 -}; - -/* - * DR0-3 = linear address of breakpoint 0-3 - * DR4=5 = reserved - * DR6 b0-b3 = BP active - * b13 = BD - * b14 = BS - * b15 = BT - * DR7 b0-b1 = G:L bp#0 - * b2-b3 = G:L bp#1 - * b4-b5 = G:L bp#2 - * b6-b7 = G:L bp#3 - * b8-b9 = GE:LE - * b13 = GD - * b16-19= LLRW bp#0 LL=00(1),01(2),11(4) - * b20-23= LLRW bp#1 RW=00(x),01(w),11(rw) - * b24-27= LLRW bp#2 - * b28-31= LLRW bp#3 - */ -unsigned long DRs[8] = -{ - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0xffff1ff0, - 0x00000400, - 0xffff1ff0, - 0x00000400 -}; - -unsigned long TRs[2] = -{ - 0x00000000, - 0x00000000 -}; - -void FatalAppExit(UINT wAction, LPCSTR lpText) -{ - fprintf(stderr, "Fatal error '%s' in CPU\n", lpText); - exit(1); -} - -int e_debug_check(unsigned char *PC) -{ - register unsigned long d7 = DRs[7]; - - if (d7&0x03) { - if (d7&0x30000) return 0; /* only execute(00) bkp */ - if ((long)PC==DRs[0]) { - e_printf("DBRK: DR0 hit at %p\n",PC); - DRs[6] |= 1; - return 1; - } - } - if (d7&0x0c) { - if (d7&0x300000) return 0; - if ((long)PC==DRs[1]) { - e_printf("DBRK: DR1 hit at %p\n",PC); - DRs[6] |= 2; - return 1; - } - } - if (d7&0x30) { - if (d7&0x3000000) return 0; - if ((long)PC==DRs[2]) { - e_printf("DBRK: DR2 hit at %p\n",PC); - DRs[6] |= 4; - return 1; - } - } - if (d7&0xc0) { - if (d7&0x30000000) return 0; - if ((long)PC==DRs[3]) { - e_printf("DBRK: DR3 hit at %p\n",PC); - DRs[6] |= 8; - return 1; - } - } - return 0; -} - -/* Debug stuff */ -void logstr(unsigned long mask, const char *fmt,...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - -/* unconditional message into debug log and stderr */ -#undef error -void error(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(1); -} - -int PortIO(DWORD port, DWORD value, UINT size, BOOL is_write) -{ - fprintf(stderr, "IO: %s port=0x%lx value=0x%lx size=%d", - is_write ? "write" : "read", port, value, size); - return value; -} - -void LogProcName(WORD wSel, WORD wOff, WORD wAction) -{ - -} - -void INT_handler(int num, void *env) -{ - fprintf(stderr, "EM86: int %d\n", num); -} - /***********************************************************/ -/* new CPU core */ +/* CPUX86 core interface */ void cpu_x86_outb(int addr, int val) { @@ -245,7 +94,7 @@ int main(int argc, char **argv) const char *filename; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; - Interp_ENV *env; + CPUX86State *env; if (argc <= 1) usage(); @@ -277,26 +126,25 @@ int main(int argc, char **argv) target_set_brk((char *)info->brk); syscall_init(); - env = &env_global; - envp_global = env; - memset(env, 0, sizeof(Interp_ENV)); - - env->rax.e = regs->eax; - env->rbx.e = regs->ebx; - env->rcx.e = regs->ecx; - env->rdx.e = regs->edx; - env->rsi.esi = regs->esi; - env->rdi.edi = regs->edi; - env->rbp.ebp = regs->ebp; - env->rsp.esp = regs->esp; - env->cs.cs = __USER_CS; - env->ds.ds = __USER_DS; - env->es.es = __USER_DS; - env->ss.ss = __USER_DS; - env->fs.fs = __USER_DS; - env->gs.gs = __USER_DS; - env->trans_addr = regs->eip; + env = cpu_x86_init(); + + env->regs[R_EAX] = regs->eax; + env->regs[R_EBX] = regs->ebx; + env->regs[R_ECX] = regs->ecx; + env->regs[R_EDX] = regs->edx; + env->regs[R_ESI] = regs->esi; + env->regs[R_EDI] = regs->edi; + env->regs[R_EBP] = regs->ebp; + env->regs[R_ESP] = regs->esp; + env->segs[R_CS] = __USER_CS; + env->segs[R_DS] = __USER_DS; + env->segs[R_ES] = __USER_DS; + env->segs[R_SS] = __USER_DS; + env->segs[R_FS] = __USER_DS; + env->segs[R_GS] = __USER_DS; + env->pc = regs->eip; +#if 0 LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; LDT[__USER_CS >> 3].dwSelLimit = 0xfffff; LDT[__USER_CS >> 3].lpSelBase = NULL; @@ -304,41 +152,34 @@ int main(int argc, char **argv) LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; LDT[__USER_DS >> 3].dwSelLimit = 0xfffff; LDT[__USER_DS >> 3].lpSelBase = NULL; - init_npu(); - build_decode_tables(); +#endif for(;;) { int err; uint8_t *pc; - - err = invoke_code32(env, -1); - env->trans_addr = env->return_addr; - pc = env->seg_regs[0] + env->trans_addr; + + err = cpu_x86_exec(env); switch(err) { case EXCP0D_GPF: + pc = (uint8_t *)env->pc; if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ - env->trans_addr += 2; - env->rax.e = do_syscall(env->rax.e, - env->rbx.e, - env->rcx.e, - env->rdx.e, - env->rsi.esi, - env->rdi.edi, - env->rbp.ebp); + env->pc += 2; + env->regs[R_EAX] = do_syscall(env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP]); } else { goto trap_error; } break; default: trap_error: - fprintf(stderr, "GEMU: Unknown error %d, aborting\n", err); -#ifndef NO_TRACE_MSGS - d_emu = 9; - fprintf(stderr, "%s\n%s\n", - e_print_cpuemu_regs(env, 1), - e_emu_disasm(env,pc,1)); -#endif + fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", + (long)env->pc, err); abort(); } } diff --git a/op-i386.c b/op-i386.c index 9443e172c..451318af7 100644 --- a/op-i386.c +++ b/op-i386.c @@ -10,11 +10,6 @@ typedef signed long long int64_t; #define NULL 0 -typedef struct FILE FILE; - -extern FILE *stderr; -extern int fprintf(FILE *, const char *, ...); - #ifdef __i386__ register int T0 asm("esi"); register int T1 asm("ebx"); @@ -91,6 +86,7 @@ typedef struct CCTable { int (*compute_c)(void); /* return the C flag */ } CCTable; +/* NOTE: data are not static to force relocation generation by GCC */ extern CCTable cc_table[]; uint8_t parity_table[256] = { @@ -191,6 +187,14 @@ static inline int lshift(int x, int n) return x >> (-n); } +/* exception support */ +/* NOTE: not static to force relocation generation by GCC */ +void raise_exception(int exception_index) +{ + env->exception_index = exception_index; + longjmp(env->jmp_env, 1); +} + /* we define the various pieces of code used by the JIT */ #define REG EAX @@ -321,7 +325,6 @@ void OPPROTO op_decl_T0_cc(void) void OPPROTO op_testl_T0_T1_cc(void) { - CC_SRC = T0; CC_DST = T0 & T1; } @@ -555,6 +558,7 @@ void OPPROTO op_stl_T0_A0(void) /* jumps */ /* indirect jump */ + void OPPROTO op_jmp_T0(void) { PC = T0; @@ -565,6 +569,30 @@ void OPPROTO op_jmp_im(void) PC = PARAM1; } +void OPPROTO op_int_im(void) +{ + PC = PARAM1; + raise_exception(EXCP0D_GPF); +} + +void OPPROTO op_int3(void) +{ + PC = PARAM1; + raise_exception(EXCP03_INT3); +} + +void OPPROTO op_into(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_O) { + PC = PARAM1; + raise_exception(EXCP04_INTO); + } else { + PC = PARAM2; + } +} + /* string ops */ #define ldul ldl @@ -663,17 +691,19 @@ void OPPROTO op_jo_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_O) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jb_cc(void) { if (cc_table[CC_OP].compute_c()) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jz_cc(void) @@ -681,9 +711,10 @@ void OPPROTO op_jz_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_Z) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jbe_cc(void) @@ -691,9 +722,10 @@ void OPPROTO op_jbe_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & (CC_Z | CC_C)) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_js_cc(void) @@ -701,9 +733,10 @@ void OPPROTO op_js_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_S) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jp_cc(void) @@ -711,9 +744,10 @@ void OPPROTO op_jp_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_P) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jl_cc(void) @@ -721,9 +755,10 @@ void OPPROTO op_jl_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if ((eflags ^ (eflags >> 4)) & 0x80) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } void OPPROTO op_jle_cc(void) @@ -731,9 +766,10 @@ void OPPROTO op_jle_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; + FORCE_RET(); } /* slow set cases (compute x86 flags) */ @@ -1600,14 +1636,13 @@ void OPPROTO op_fcos(void) /* main execution loop */ uint8_t code_gen_buffer[65536]; - int cpu_x86_exec(CPUX86State *env1) { int saved_T0, saved_T1, saved_A0; CPUX86State *saved_env; - int code_gen_size; + int code_gen_size, ret; void (*gen_func)(void); - + /* first we save global registers */ saved_T0 = T0; saved_T1 = T1; @@ -1615,17 +1650,21 @@ int cpu_x86_exec(CPUX86State *env1) saved_env = env; env = env1; - for(;;) { - cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); - /* execute the generated code */ - gen_func = (void *)code_gen_buffer; - gen_func(); + /* prepare setjmp context for exception handling */ + if (setjmp(env->jmp_env) == 0) { + for(;;) { + cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); + /* execute the generated code */ + gen_func = (void *)code_gen_buffer; + gen_func(); + } } - + ret = env->exception_index; + /* restore global registers */ T0 = saved_T0; T1 = saved_T1; A0 = saved_A0; env = saved_env; - return 0; + return ret; } diff --git a/ops_template.h b/ops_template.h index 18b2ffb49..c67fe0fd4 100644 --- a/ops_template.h +++ b/ops_template.h @@ -149,18 +149,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_TYPE)src1 < (DATA_TYPE)src2) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } void OPPROTO glue(op_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST != 0) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } @@ -171,18 +171,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } void OPPROTO glue(op_js_sub, SUFFIX)(void) { if (CC_DST & SIGN_MASK) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } @@ -193,9 +193,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_STYPE)src1 < (DATA_STYPE)src2) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } @@ -206,9 +206,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) - PC += PARAM1; + PC = PARAM1; else - PC += PARAM2; + PC = PARAM2; FORCE_RET(); } diff --git a/translate-i386.c b/translate-i386.c index 9ebc81e2c..eb621c3e7 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -5,12 +5,24 @@ #include #include +/* dump all code */ +#define DEBUG_DISAS +#define DEBUG_LOGFILE "/tmp/gemu.log" + +#ifdef DEBUG_DISAS +#include "dis-asm.h" +#endif + #define IN_OP_I386 #include "cpu-i386.h" static uint8_t *gen_code_ptr; int __op_param1, __op_param2, __op_param3; +#ifdef DEBUG_DISAS +static FILE *logfile = NULL; +#endif + /* supress that */ static void error(const char *fmt, ...) { @@ -704,6 +716,9 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ int reg1, reg2, opreg; int mod, rm, code; +#ifdef DEBUG_DISAS + fprintf(logfile, "modrm=0x%x\n", modrm); +#endif mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -716,6 +731,9 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ if (base == 4) { havesib = 1; code = ldub(s->pc++); +#ifdef DEBUG_DISAS + fprintf(logfile, "sib=0x%x\n", code); +#endif scale = (code >> 6) & 3; index = (code >> 3) & 7; base = code & 7; @@ -762,6 +780,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ } else if (scale == 0 && disp == 0) { gen_op_movl_A0_reg[reg1](); } else { + gen_op_movl_A0_im(disp); gen_op_addl_A0_reg_sN[scale][reg1](); } } else { @@ -953,8 +972,10 @@ static void gen_setcc(DisasContext *s, int b) } } -/* return the size of the intruction. Return -1 if no insn found */ -int disas_insn(DisasContext *s, uint8_t *pc_start) +/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr + is set to true if the instruction sets the PC (last instruction of + a basic block) */ +long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) { int b, prefixes, aflag, dflag; int shift, ot; @@ -967,6 +988,9 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) // cur_pc = s->pc; /* for insn generation */ next_byte: b = ldub(s->pc); +#ifdef DEBUG_DISAS + fprintf(logfile, "ib=0x%02x\n", b); +#endif if (b < 0) return -1; s->pc++; @@ -1195,6 +1219,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mull_EAX_T0(); break; } + s->cc_op = CC_OP_MUL; break; case 5: /* imul */ switch(ot) { @@ -1209,6 +1234,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_imull_EAX_T0(); break; } + s->cc_op = CC_OP_MUL; break; case 6: /* div */ switch(ot) { @@ -1281,9 +1307,11 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_movl_T1_im((long)s->pc); gen_op_pushl_T1(); gen_op_jmp_T0(); + *is_jmp_ptr = 1; break; case 4: /* jmp Ev */ gen_op_jmp_T0(); + *is_jmp_ptr = 1; break; case 6: /* push Ev */ gen_op_pushl_T0(); @@ -1362,6 +1390,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) op_imulw_T0_T1(); } gen_op_mov_reg_T0[ot][reg](); + s->cc_op = CC_OP_MUL; break; /**************************/ @@ -1418,10 +1447,14 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); mod = (modrm >> 6) & 3; - + if (mod != 3) + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); val = insn_get(s, ot); gen_op_movl_T0_im(val); - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + if (mod != 3) + gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][modrm & 7](); break; case 0x8a: case 0x8b: /* mov Ev, Gv */ @@ -2068,10 +2101,12 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_popl_T0(); gen_op_addl_ESP_im(val); gen_op_jmp_T0(); + *is_jmp_ptr = 1; break; case 0xc3: /* ret */ gen_op_popl_T0(); gen_op_jmp_T0(); + *is_jmp_ptr = 1; break; case 0xe8: /* call */ val = insn_get(s, OT_LONG); @@ -2079,16 +2114,19 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_movl_T1_im((long)s->pc); gen_op_pushl_T1(); gen_op_jmp_im(val); + *is_jmp_ptr = 1; break; case 0xe9: /* jmp */ val = insn_get(s, OT_LONG); val += (long)s->pc; gen_op_jmp_im(val); + *is_jmp_ptr = 1; break; case 0xeb: /* jmp Jb */ val = (int8_t)insn_get(s, OT_BYTE); val += (long)s->pc; gen_op_jmp_im(val); + *is_jmp_ptr = 1; break; case 0x70 ... 0x7f: /* jcc Jb */ val = (int8_t)insn_get(s, OT_BYTE); @@ -2103,6 +2141,7 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) val += (long)s->pc; /* XXX: fix 16 bit wrap */ do_jcc: gen_jcc(s, b, val); + *is_jmp_ptr = 1; break; case 0x190 ... 0x19f: @@ -2164,8 +2203,23 @@ int disas_insn(DisasContext *s, uint8_t *pc_start) /* misc */ case 0x90: /* nop */ break; - -#if 0 + case 0xcc: /* int3 */ + gen_op_int3((long)pc_start); + *is_jmp_ptr = 1; + break; + case 0xcd: /* int N */ + val = ldub(s->pc++); + /* XXX: currently we ignore the interrupt number */ + gen_op_int_im((long)pc_start); + *is_jmp_ptr = 1; + break; + case 0xce: /* into */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_into((long)pc_start, (long)s->pc); + *is_jmp_ptr = 1; + break; +#if 0 case 0x1a2: /* cpuid */ gen_insn0(OP_ASM); break; @@ -2182,16 +2236,78 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, uint8_t *pc_start) { DisasContext dc1, *dc = &dc1; + int is_jmp; long ret; +#ifdef DEBUG_DISAS + struct disassemble_info disasm_info; +#endif + dc->cc_op = CC_OP_DYNAMIC; gen_code_ptr = gen_code_buf; gen_start(); - ret = disas_insn(dc, pc_start); + +#ifdef DEBUG_DISAS + if (!logfile) { + logfile = fopen(DEBUG_LOGFILE, "w"); + if (!logfile) { + perror(DEBUG_LOGFILE); + exit(1); + } + setvbuf(logfile, NULL, _IOLBF, 0); + } + + INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); + disasm_info.buffer = pc_start; + disasm_info.buffer_vma = (unsigned long)pc_start; + disasm_info.buffer_length = 15; +#if 0 + disasm_info.flavour = bfd_get_flavour (abfd); + disasm_info.arch = bfd_get_arch (abfd); + disasm_info.mach = bfd_get_mach (abfd); +#endif +#ifdef WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif + fprintf(logfile, "IN:\n"); + fprintf(logfile, "0x%08lx: ", (long)pc_start); + print_insn_i386((unsigned long)pc_start, &disasm_info); + fprintf(logfile, "\n\n"); +#endif + is_jmp = 0; + ret = disas_insn(dc, pc_start, &is_jmp); if (ret == -1) error("unknown instruction at PC=0x%x", pc_start); + /* we must store the eflags state if it is not already done */ + if (dc->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(dc->cc_op); + if (!is_jmp) { + /* we add an additionnal jmp to update the simulated PC */ + gen_op_jmp_im(ret); + } gen_end(); *gen_code_size_ptr = gen_code_ptr - gen_code_buf; - printf("0x%08lx: code_size = %d\n", (long)pc_start, *gen_code_size_ptr); + +#ifdef DEBUG_DISAS + { + uint8_t *pc; + int count; + + pc = gen_code_buf; + disasm_info.buffer = pc; + disasm_info.buffer_vma = (unsigned long)pc; + disasm_info.buffer_length = *gen_code_size_ptr; + fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); + while (pc < gen_code_ptr) { + fprintf(logfile, "0x%08lx: ", (long)pc); + count = print_insn_i386((unsigned long)pc, &disasm_info); + fprintf(logfile, "\n"); + pc += count; + } + fprintf(logfile, "\n"); + } +#endif return 0; } -- cgit v1.2.3 From 586314f2aa62990dead8144e780c4c8c498eece6 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Mar 2003 15:02:29 +0000 Subject: better debug support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@18 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 38 ++++++++++++++++++++------------- linux-user/main.c | 27 ++++++++++++++++++++--- op-i386.c | 44 ++++++++++++++++++++++++++++++++++++++ translate-i386.c | 64 +++++++++++++++++++------------------------------------ 4 files changed, 113 insertions(+), 60 deletions(-) diff --git a/Makefile b/Makefile index b007f40dd..066f30cbe 100644 --- a/Makefile +++ b/Makefile @@ -34,13 +34,10 @@ DEFINES+=-D_GNU_SOURCE DEFINES+=-DCONFIG_PREFIX=\"/usr/local\" LDSCRIPT=$(ARCH).ld LIBS+=-ldl -lm +VERSION=0.1 -#DEFINES+= -DGEMU -DDOSEMU -DNO_TRACE_MSGS -#OBJS= i386/fp87.o i386/interp_main.o i386/interp_modrm.o i386/interp_16_32.o \ -# i386/interp_32_16.o i386/interp_32_32.o i386/emu-utils.o \ -# i386/dis8086.o i386/emu-ldt.o +OBJS= elfload.o main.o thunk.o syscall.o OBJS+=translate-i386.o op-i386.o -OBJS+= elfload.o main.o thunk.o syscall.o # NOTE: the disassembler code is only needed for debugging OBJS+=i386-dis.o dis-buf.o SRCS = $(OBJS:.o=.c) @@ -53,15 +50,6 @@ gemu: $(OBJS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend -# old i386 emulator -i386/interp_32_32.o: i386/interp_32_32.c i386/interp_gen.h - -i386/interp_gen.h: i386/gencode - ./i386/gencode > $@ - -i386/gencode: i386/gencode.c - $(CC) -O2 -Wall -g $< -o $@ - # new i386 emulator dyngen: dyngen.c $(HOST_CC) -O2 -Wall -g $< -o $@ @@ -78,7 +66,7 @@ op-i386.o: op-i386.c opreg_template.h ops_template.h $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< clean: - rm -f *.o *~ i386/*.o i386/*~ gemu TAGS + rm -f *.o *~ gemu dyngen TAGS # various test targets test speed: gemu @@ -87,6 +75,26 @@ test speed: gemu TAGS: etags *.[ch] i386/*.[ch] +FILES= \ +COPYING.LIB dyngen.c ioctls.h ops_template.h syscall_types.h\ +Makefile elf.h linux_bin.h segment.h thunk.c\ +TODO elfload.c main.c signal.c thunk.h\ +cpu-i386.h gemu.h op-i386.c syscall-i386.h translate-i386.c\ +dis-asm.h gen-i386.h op-i386.h syscall.c\ +dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ +i386.ld ppc.ld\ +tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ +tests/test2.c tests/hello.c tests/sha1.c tests/test1.c + +FILE=gemu-$(VERSION) + +tar: + rm -rf /tmp/$(FILE) + mkdir -p /tmp/$(FILE) + cp -P $(FILES) /tmp/$(FILE) + ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) ) + rm -rf /tmp/$(FILE) + ifneq ($(wildcard .depend),) include .depend endif diff --git a/linux-user/main.c b/linux-user/main.c index 68858daf4..cdd118f36 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -27,6 +27,11 @@ #include "cpu-i386.h" +#define DEBUG_LOGFILE "/tmp/gemu.log" + +FILE *logfile = NULL; +int loglevel; + unsigned long x86_stack_size; unsigned long stktop; @@ -83,7 +88,7 @@ int cpu_x86_inl(int addr) void usage(void) { printf("gemu version 0.1, Copyright (c) 2003 Fabrice Bellard\n" - "usage: gemu program [arguments...]\n" + "usage: gemu [-d] program [arguments...]\n" "Linux x86 emulator\n" ); exit(1); @@ -95,11 +100,27 @@ int main(int argc, char **argv) struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; CPUX86State *env; + int optind; if (argc <= 1) usage(); - - filename = argv[1]; + loglevel = 0; + optind = 1; + if (argv[optind] && !strcmp(argv[optind], "-d")) { + loglevel = 1; + optind++; + } + filename = argv[optind]; + + /* init debug */ + if (loglevel) { + logfile = fopen(DEBUG_LOGFILE, "w"); + if (!logfile) { + perror(DEBUG_LOGFILE); + exit(1); + } + setvbuf(logfile, NULL, _IOLBF, 0); + } /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); diff --git a/op-i386.c b/op-i386.c index 451318af7..849e508e2 100644 --- a/op-i386.c +++ b/op-i386.c @@ -1,3 +1,5 @@ +#define DEBUG_EXEC + typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; @@ -10,6 +12,11 @@ typedef signed long long int64_t; #define NULL 0 +typedef struct FILE FILE; +extern FILE *logfile; +extern int loglevel; +extern int fprintf(FILE *, const char *, ...); + #ifdef __i386__ register int T0 asm("esi"); register int T1 asm("ebx"); @@ -1636,6 +1643,32 @@ void OPPROTO op_fcos(void) /* main execution loop */ uint8_t code_gen_buffer[65536]; +#ifdef DEBUG_EXEC +static const char *cc_op_str[] = { + "DYNAMIC", + "EFLAGS", + "MUL", + "ADDB", + "ADDW", + "ADDL", + "SUBB", + "SUBW", + "SUBL", + "LOGICB", + "LOGICW", + "LOGICL", + "INCB", + "INCW", + "INCL", + "DECB", + "DECW", + "DECL", + "SHLB", + "SHLW", + "SHLL", +}; +#endif + int cpu_x86_exec(CPUX86State *env1) { int saved_T0, saved_T1, saved_A0; @@ -1653,6 +1686,17 @@ int cpu_x86_exec(CPUX86State *env1) /* prepare setjmp context for exception handling */ if (setjmp(env->jmp_env) == 0) { for(;;) { +#ifdef DEBUG_EXEC + if (loglevel) { + fprintf(logfile, + "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" + "ESI=%08x ESI=%08X EBP=%08x ESP=%08x\n" + "CCS=%08x CCD=%08x CCOP=%s\n", + env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], + env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], + env->cc_src, env->cc_dst, cc_op_str[env->cc_op]); + } +#endif cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); /* execute the generated code */ gen_func = (void *)code_gen_buffer; diff --git a/translate-i386.c b/translate-i386.c index eb621c3e7..20a803904 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -5,23 +5,21 @@ #include #include -/* dump all code */ #define DEBUG_DISAS -#define DEBUG_LOGFILE "/tmp/gemu.log" +#define IN_OP_I386 +#include "cpu-i386.h" + +/* dump all code */ #ifdef DEBUG_DISAS #include "dis-asm.h" #endif -#define IN_OP_I386 -#include "cpu-i386.h" - static uint8_t *gen_code_ptr; int __op_param1, __op_param2, __op_param3; -#ifdef DEBUG_DISAS -static FILE *logfile = NULL; -#endif +extern FILE *logfile; +extern int loglevel; /* supress that */ static void error(const char *fmt, ...) @@ -716,9 +714,6 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ int reg1, reg2, opreg; int mod, rm, code; -#ifdef DEBUG_DISAS - fprintf(logfile, "modrm=0x%x\n", modrm); -#endif mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -731,9 +726,6 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ if (base == 4) { havesib = 1; code = ldub(s->pc++); -#ifdef DEBUG_DISAS - fprintf(logfile, "sib=0x%x\n", code); -#endif scale = (code >> 6) & 3; index = (code >> 3) & 7; base = code & 7; @@ -988,11 +980,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) // cur_pc = s->pc; /* for insn generation */ next_byte: b = ldub(s->pc); -#ifdef DEBUG_DISAS - fprintf(logfile, "ib=0x%02x\n", b); -#endif - if (b < 0) - return -1; s->pc++; /* check prefixes */ switch (b) { @@ -2247,33 +2234,26 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, gen_start(); #ifdef DEBUG_DISAS - if (!logfile) { - logfile = fopen(DEBUG_LOGFILE, "w"); - if (!logfile) { - perror(DEBUG_LOGFILE); - exit(1); - } - setvbuf(logfile, NULL, _IOLBF, 0); - } - - INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); - disasm_info.buffer = pc_start; - disasm_info.buffer_vma = (unsigned long)pc_start; - disasm_info.buffer_length = 15; + if (loglevel) { + INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); + disasm_info.buffer = pc_start; + disasm_info.buffer_vma = (unsigned long)pc_start; + disasm_info.buffer_length = 15; #if 0 - disasm_info.flavour = bfd_get_flavour (abfd); - disasm_info.arch = bfd_get_arch (abfd); - disasm_info.mach = bfd_get_mach (abfd); + disasm_info.flavour = bfd_get_flavour (abfd); + disasm_info.arch = bfd_get_arch (abfd); + disasm_info.mach = bfd_get_mach (abfd); #endif #ifdef WORDS_BIGENDIAN - disasm_info.endian = BFD_ENDIAN_BIG; + disasm_info.endian = BFD_ENDIAN_BIG; #else - disasm_info.endian = BFD_ENDIAN_LITTLE; + disasm_info.endian = BFD_ENDIAN_LITTLE; #endif - fprintf(logfile, "IN:\n"); - fprintf(logfile, "0x%08lx: ", (long)pc_start); - print_insn_i386((unsigned long)pc_start, &disasm_info); - fprintf(logfile, "\n\n"); + fprintf(logfile, "IN:\n"); + fprintf(logfile, "0x%08lx: ", (long)pc_start); + print_insn_i386((unsigned long)pc_start, &disasm_info); + fprintf(logfile, "\n\n"); + } #endif is_jmp = 0; ret = disas_insn(dc, pc_start, &is_jmp); @@ -2290,7 +2270,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, *gen_code_size_ptr = gen_code_ptr - gen_code_buf; #ifdef DEBUG_DISAS - { + if (loglevel) { uint8_t *pc; int count; -- cgit v1.2.3 From 4b74fe1f0013c622693b26141c0ed031a284a45a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Mar 2003 23:23:09 +0000 Subject: many fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@19 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 16 ++- dyngen.c | 8 +- linux-user/main.c | 22 ++--- op-i386.c | 183 +++++++++++++++++++++++++--------- ops_template.h | 200 +++++++++++++++++++++++++++++-------- tests/Makefile | 2 +- tests/test-i386.c | 140 +++++++++++++++++++++++++- translate-i386.c | 291 +++++++++++++++++++++++++++++++++++++++++------------- 8 files changed, 684 insertions(+), 178 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index 9add4175d..e528f6198 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -78,19 +78,27 @@ enum { CC_OP_ADDW, CC_OP_ADDL, + CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ + CC_OP_ADCW, + CC_OP_ADCL, + CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ CC_OP_SUBW, CC_OP_SUBL, + CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ + CC_OP_SBBW, + CC_OP_SBBL, + CC_OP_LOGICB, /* modify all flags, CC_DST = res */ CC_OP_LOGICW, CC_OP_LOGICL, - CC_OP_INCB, /* modify all flags except, CC_DST = res */ + CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */ CC_OP_INCW, CC_OP_INCL, - CC_OP_DECB, /* modify all flags except, CC_DST = res */ + CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */ CC_OP_DECW, CC_OP_DECL, @@ -98,6 +106,10 @@ enum { CC_OP_SHLW, CC_OP_SHLL, + CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ + CC_OP_SARW, + CC_OP_SARL, + CC_OP_NB, }; diff --git a/dyngen.c b/dyngen.c index ce38dcaec..f6b102fef 100644 --- a/dyngen.c +++ b/dyngen.c @@ -198,14 +198,10 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, { uint8_t *p; p = p_end - 1; - /* find ret */ - while (p > p_start && *p != 0xc3) - p--; - /* skip double ret */ - if (p > p_start && p[-1] == 0xc3) - p--; if (p == p_start) error("empty code for %s", name); + if (p[0] != 0xc3) + error("ret expected at the end of %s", name); copy_size = p - p_start; } break; diff --git a/linux-user/main.c b/linux-user/main.c index cdd118f36..356d980f0 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -128,21 +128,21 @@ int main(int argc, char **argv) /* Zero out image_info */ memset(info, 0, sizeof(struct image_info)); - if(elf_exec(filename, argv+1, environ, regs, info) != 0) { + if(elf_exec(filename, argv+optind, environ, regs, info) != 0) { printf("Error loading %s\n", filename); exit(1); } -#if 0 - printf("start_brk 0x%08lx\n" , info->start_brk); - printf("end_code 0x%08lx\n" , info->end_code); - printf("start_code 0x%08lx\n" , info->start_code); - printf("end_data 0x%08lx\n" , info->end_data); - printf("start_stack 0x%08lx\n" , info->start_stack); - printf("brk 0x%08lx\n" , info->brk); - printf("esp 0x%08lx\n" , regs->esp); - printf("eip 0x%08lx\n" , regs->eip); -#endif + if (loglevel) { + fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); + fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); + fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); + fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); + fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); + fprintf(logfile, "brk 0x%08lx\n" , info->brk); + fprintf(logfile, "esp 0x%08lx\n" , regs->esp); + fprintf(logfile, "eip 0x%08lx\n" , regs->eip); + } target_set_brk((char *)info->brk); syscall_init(); diff --git a/op-i386.c b/op-i386.c index 849e508e2..f7f1a9849 100644 --- a/op-i386.c +++ b/op-i386.c @@ -10,7 +10,18 @@ typedef signed short int16_t; typedef signed int int32_t; typedef signed long long int64_t; +#define bswap32(x) \ +({ \ + uint32_t __x = (x); \ + ((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ +}) + #define NULL 0 +#include typedef struct FILE FILE; extern FILE *logfile; @@ -18,41 +29,39 @@ extern int loglevel; extern int fprintf(FILE *, const char *, ...); #ifdef __i386__ -register int T0 asm("esi"); -register int T1 asm("ebx"); -register int A0 asm("edi"); +register unsigned int T0 asm("ebx"); +register unsigned int T1 asm("esi"); +register unsigned int A0 asm("edi"); register struct CPUX86State *env asm("ebp"); -#define FORCE_RET() asm volatile ("ret"); #endif #ifdef __powerpc__ -register int T0 asm("r24"); -register int T1 asm("r25"); -register int A0 asm("r26"); +register unsigned int T0 asm("r24"); +register unsigned int T1 asm("r25"); +register unsigned int A0 asm("r26"); register struct CPUX86State *env asm("r27"); -#define FORCE_RET() asm volatile ("blr"); #endif #ifdef __arm__ -register int T0 asm("r4"); -register int T1 asm("r5"); -register int A0 asm("r6"); +register unsigned int T0 asm("r4"); +register unsigned int T1 asm("r5"); +register unsigned int A0 asm("r6"); register struct CPUX86State *env asm("r7"); -#define FORCE_RET() asm volatile ("mov pc, lr"); #endif #ifdef __mips__ -register int T0 asm("s0"); -register int T1 asm("s1"); -register int A0 asm("s2"); +register unsigned int T0 asm("s0"); +register unsigned int T1 asm("s1"); +register unsigned int A0 asm("s2"); register struct CPUX86State *env asm("s3"); -#define FORCE_RET() asm volatile ("jr $31"); #endif #ifdef __sparc__ -register int T0 asm("l0"); -register int T1 asm("l1"); -register int A0 asm("l2"); +register unsigned int T0 asm("l0"); +register unsigned int T1 asm("l1"); +register unsigned int A0 asm("l2"); register struct CPUX86State *env asm("l3"); -#define FORCE_RET() asm volatile ("retl ; nop"); #endif +/* force GCC to generate only one epilog at the end of the function */ +#define FORCE_RET() asm volatile (""); + #ifndef OPPROTO #define OPPROTO #endif @@ -267,20 +276,6 @@ void OPPROTO op_orl_T0_T1_cc(void) CC_DST = T0; } -void OPPROTO op_adcl_T0_T1_cc(void) -{ - CC_SRC = T0; - T0 = T0 + T1 + cc_table[CC_OP].compute_c(); - CC_DST = T0; -} - -void OPPROTO op_sbbl_T0_T1_cc(void) -{ - CC_SRC = T0; - T0 = T0 - T1 - cc_table[CC_OP].compute_c(); - CC_DST = T0; -} - void OPPROTO op_andl_T0_T1_cc(void) { T0 &= T1; @@ -320,12 +315,14 @@ void OPPROTO op_negl_T0_cc(void) void OPPROTO op_incl_T0_cc(void) { + CC_SRC = cc_table[CC_OP].compute_c(); T0++; CC_DST = T0; } void OPPROTO op_decl_T0_cc(void) { + CC_SRC = cc_table[CC_OP].compute_c(); T0--; CC_DST = T0; } @@ -335,6 +332,11 @@ void OPPROTO op_testl_T0_T1_cc(void) CC_DST = T0 & T1; } +void OPPROTO op_bswapl_T0(void) +{ + T0 = bswap32(T0); +} + /* multiply/divide */ void OPPROTO op_mulb_AL_T0(void) { @@ -399,7 +401,7 @@ void OPPROTO op_imulw_T0_T1(void) void OPPROTO op_imull_T0_T1(void) { int64_t res; - res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T1); + res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); T0 = res; CC_SRC = (res != (int32_t)res); } @@ -468,10 +470,10 @@ void OPPROTO op_divl_EAX_T0(void) void OPPROTO op_idivl_EAX_T0(void) { int den, q, r; - int16_t num; + int64_t num; num = EAX | ((uint64_t)EDX << 32); - den = (int16_t)T0; + den = T0; q = (num / den); r = (num % den); EAX = q; @@ -495,6 +497,16 @@ void OPPROTO op_movl_A0_im(void) A0 = PARAM1; } +void OPPROTO op_addl_A0_im(void) +{ + A0 += PARAM1; +} + +void OPPROTO op_andl_A0_ffff(void) +{ + A0 = A0 & 0xffff; +} + /* memory access */ void OPPROTO op_ldub_T0_A0(void) @@ -562,7 +574,17 @@ void OPPROTO op_stl_T0_A0(void) stl((uint8_t *)A0, T0); } -/* jumps */ +/* used for bit operations */ + +void OPPROTO op_add_bitw_A0_T1(void) +{ + A0 += ((int32_t)T1 >> 4) << 1; +} + +void OPPROTO op_add_bitl_A0_T1(void) +{ + A0 += ((int32_t)T1 >> 5) << 2; +} /* indirect jump */ @@ -938,25 +960,37 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_ADDW] = { compute_all_addw, compute_c_addw }, [CC_OP_ADDL] = { compute_all_addl, compute_c_addl }, + [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb }, + [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw }, + [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl }, + [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, + [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb }, + [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw }, + [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl }, + [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, - [CC_OP_INCB] = { compute_all_incb, compute_c_incb }, - [CC_OP_INCW] = { compute_all_incw, compute_c_incw }, + [CC_OP_INCB] = { compute_all_incb, compute_c_incl }, + [CC_OP_INCW] = { compute_all_incw, compute_c_incl }, [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, - [CC_OP_DECB] = { compute_all_decb, compute_c_incb }, - [CC_OP_DECW] = { compute_all_decw, compute_c_incw }, + [CC_OP_DECB] = { compute_all_decb, compute_c_incl }, + [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, - [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, - [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shll }, + [CC_OP_SHLW] = { compute_all_shlw, compute_c_shll }, [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, + + [CC_OP_SARB] = { compute_all_sarb, compute_c_shll }, + [CC_OP_SARW] = { compute_all_sarw, compute_c_shll }, + [CC_OP_SARL] = { compute_all_sarl, compute_c_shll }, }; /* floating point support */ @@ -1640,6 +1674,41 @@ void OPPROTO op_fcos(void) helper_fcos(); } +void OPPROTO op_fnstsw_A0(void) +{ + int fpus; + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + stw((void *)A0, fpus); +} + +void OPPROTO op_fnstcw_A0(void) +{ + stw((void *)A0, env->fpuc); +} + +void OPPROTO op_fldcw_A0(void) +{ + int rnd_type; + env->fpuc = lduw((void *)A0); + /* set rounding mode */ + switch(env->fpuc & RC_MASK) { + default: + case RC_NEAR: + rnd_type = FE_TONEAREST; + break; + case RC_DOWN: + rnd_type = FE_DOWNWARD; + break; + case RC_UP: + rnd_type = FE_UPWARD; + break; + case RC_CHOP: + rnd_type = FE_TOWARDZERO; + break; + } + fesetround(rnd_type); +} + /* main execution loop */ uint8_t code_gen_buffer[65536]; @@ -1651,9 +1720,15 @@ static const char *cc_op_str[] = { "ADDB", "ADDW", "ADDL", + "ADCB", + "ADCW", + "ADCL", "SUBB", "SUBW", "SUBL", + "SBBB", + "SBBW", + "SBBL", "LOGICB", "LOGICW", "LOGICL", @@ -1666,6 +1741,9 @@ static const char *cc_op_str[] = { "SHLB", "SHLW", "SHLL", + "SARB", + "SARW", + "SARL", }; #endif @@ -1688,13 +1766,24 @@ int cpu_x86_exec(CPUX86State *env1) for(;;) { #ifdef DEBUG_EXEC if (loglevel) { + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DIRECTION_FLAG); fprintf(logfile, "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" - "ESI=%08x ESI=%08X EBP=%08x ESP=%08x\n" - "CCS=%08x CCD=%08x CCOP=%s\n", + "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" + "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], - env->cc_src, env->cc_dst, cc_op_str[env->cc_op]); + env->cc_src, env->cc_dst, cc_op_str[env->cc_op], + eflags & DIRECTION_FLAG ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-' + ); } #endif cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); diff --git a/ops_template.h b/ops_template.h index c67fe0fd4..e7317eae6 100644 --- a/ops_template.h +++ b/ops_template.h @@ -33,7 +33,7 @@ static int glue(compute_all_add, SUFFIX)(void) cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; pf = parity_table[(uint8_t)CC_DST]; af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST != 0) << 6; + zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; @@ -47,6 +47,29 @@ static int glue(compute_c_add, SUFFIX)(void) return cf; } +static int glue(compute_all_adc, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_DST - CC_SRC - 1; + cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_adc, SUFFIX)(void) +{ + int src1, cf; + src1 = CC_SRC; + cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; + return cf; +} + static int glue(compute_all_sub, SUFFIX)(void) { int cf, pf, af, zf, sf, of; @@ -56,9 +79,9 @@ static int glue(compute_all_sub, SUFFIX)(void) cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; pf = parity_table[(uint8_t)CC_DST]; af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST != 0) << 6; + zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } @@ -67,7 +90,31 @@ static int glue(compute_c_sub, SUFFIX)(void) int src1, src2, cf; src1 = CC_SRC; src2 = CC_SRC - CC_DST; - cf = (DATA_TYPE)src1 < (DATA_TYPE)src1; + cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; + return cf; +} + +static int glue(compute_all_sbb, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST - 1; + cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_sbb, SUFFIX)(void) +{ + int src1, src2, cf; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST - 1; + cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; return cf; } @@ -77,7 +124,7 @@ static int glue(compute_all_logic, SUFFIX)(void) cf = 0; pf = parity_table[(uint8_t)CC_DST]; af = 0; - zf = ((DATA_TYPE)CC_DST != 0) << 6; + zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; of = 0; return cf | pf | af | zf | sf | of; @@ -97,16 +144,18 @@ static int glue(compute_all_inc, SUFFIX)(void) cf = CC_SRC; pf = parity_table[(uint8_t)CC_DST]; af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST != 0) << 6; + zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; return cf | pf | af | zf | sf | of; } +#if DATA_BITS == 32 static int glue(compute_c_inc, SUFFIX)(void) { return CC_SRC; } +#endif static int glue(compute_all_dec, SUFFIX)(void) { @@ -117,9 +166,9 @@ static int glue(compute_all_dec, SUFFIX)(void) cf = CC_SRC; pf = parity_table[(uint8_t)CC_DST]; af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST != 0) << 6; + zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11; return cf | pf | af | zf | sf | of; } @@ -129,16 +178,30 @@ static int glue(compute_all_shl, SUFFIX)(void) cf = CC_SRC & 1; pf = parity_table[(uint8_t)CC_DST]; af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST != 0) << 6; + zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = sf << 4; /* only meaniful for shr with count == 1 */ + of = lshift(CC_SRC, 12 - DATA_BITS) & CC_O; /* only meaniful for shr with count == 1 */ return cf | pf | af | zf | sf | of; } +#if DATA_BITS == 32 static int glue(compute_c_shl, SUFFIX)(void) { return CC_SRC & 1; } +#endif + +static int glue(compute_all_sar, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = CC_SRC & 1; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = 0; /* only meaniful for shr with count == 1 */ + return cf | pf | af | zf | sf | of; +} /* various optimized jumps cases */ @@ -157,7 +220,7 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void) void OPPROTO glue(op_jz_sub, SUFFIX)(void) { - if ((DATA_TYPE)CC_DST != 0) + if ((DATA_TYPE)CC_DST == 0) PC = PARAM1; else PC = PARAM2; @@ -225,7 +288,7 @@ void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) { - T0 = ((DATA_TYPE)CC_DST != 0); + T0 = ((DATA_TYPE)CC_DST == 0); } void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) @@ -275,6 +338,7 @@ void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) (T0 & CC_C); CC_OP = CC_OP_EFLAGS; } + FORCE_RET(); } void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) @@ -290,6 +354,7 @@ void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) ((T0 >> (DATA_BITS - 1)) & CC_C); CC_OP = CC_OP_EFLAGS; } + FORCE_RET(); } void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) @@ -305,6 +370,7 @@ void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) #endif if (count) { eflags = cc_table[CC_OP].compute_all(); + T0 &= DATA_MASK; src = T0; res = (T0 << count) | ((eflags & CC_C) << (count - 1)); if (count > 1) @@ -315,6 +381,7 @@ void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) ((src >> (DATA_BITS - count)) & CC_C); CC_OP = CC_OP_EFLAGS; } + FORCE_RET(); } void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) @@ -330,6 +397,7 @@ void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) #endif if (count) { eflags = cc_table[CC_OP].compute_all(); + T0 &= DATA_MASK; src = T0; res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); if (count > 1) @@ -340,6 +408,7 @@ void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) ((src >> (count - 1)) & CC_C); CC_OP = CC_OP_EFLAGS; } + FORCE_RET(); } void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) @@ -352,11 +421,12 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) CC_DST = T0; CC_OP = CC_OP_ADDB + SHIFT; } else if (count) { - CC_SRC = T0 >> (DATA_BITS - count); + CC_SRC = (DATA_TYPE)T0 >> (DATA_BITS - count); T0 = T0 << count; CC_DST = T0; CC_OP = CC_OP_SHLB + SHIFT; } + FORCE_RET(); } void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) @@ -370,6 +440,7 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) CC_DST = T0; CC_OP = CC_OP_SHLB + SHIFT; } + FORCE_RET(); } void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) @@ -381,10 +452,69 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) CC_SRC = src >> (count - 1); T0 = src >> count; CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; + CC_OP = CC_OP_SARB + SHIFT; } + FORCE_RET(); } +/* carry add/sub (we only need to set CC_OP differently) */ + +void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + CC_SRC = T0; + T0 = T0 + T1 + cf; + CC_DST = T0; + CC_OP = CC_OP_ADDB + SHIFT + cf * 3; +} + +void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + CC_SRC = T0; + T0 = T0 - T1 - cf; + CC_DST = T0; + CC_OP = CC_OP_SUBB + SHIFT + cf * 3; +} + +/* bit operations */ +#if DATA_BITS >= 16 + +void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & SHIFT_MASK; + CC_SRC = T0 >> count; +} + +void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & SHIFT_MASK; + CC_SRC = T0 >> count; + T0 |= (1 << count); +} + +void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & SHIFT_MASK; + CC_SRC = T0 >> count; + T0 &= ~(1 << count); +} + +void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & SHIFT_MASK; + CC_SRC = T0 >> count; + T0 ^= (1 << count); +} + +#endif + /* string operations */ /* XXX: maybe use lower level instructions to ease exception handling */ @@ -464,8 +594,8 @@ void OPPROTO glue(op_scas, SUFFIX)(void) { int v; - v = glue(ldu, SUFFIX)((void *)ESI); - ESI += (DF << SHIFT); + v = glue(ldu, SUFFIX)((void *)EDI); + EDI += (DF << SHIFT); CC_SRC = EAX; CC_DST = EAX - v; } @@ -476,20 +606,14 @@ void OPPROTO glue(op_repz_scas, SUFFIX)(void) if (ECX != 0) { /* NOTE: the flags are not modified if ECX == 0 */ -#if SHIFT == 0 - v1 = EAX & 0xff; -#elif SHIFT == 1 - v1 = EAX & 0xffff; -#else - v1 = EAX; -#endif + v1 = EAX & DATA_MASK; inc = (DF << SHIFT); do { - v2 = glue(ldu, SUFFIX)((void *)ESI); + v2 = glue(ldu, SUFFIX)((void *)EDI); + EDI += inc; + ECX--; if (v1 != v2) break; - ESI += inc; - ECX--; } while (ECX != 0); CC_SRC = v1; CC_DST = v1 - v2; @@ -503,20 +627,14 @@ void OPPROTO glue(op_repnz_scas, SUFFIX)(void) if (ECX != 0) { /* NOTE: the flags are not modified if ECX == 0 */ -#if SHIFT == 0 - v1 = EAX & 0xff; -#elif SHIFT == 1 - v1 = EAX & 0xffff; -#else - v1 = EAX; -#endif + v1 = EAX & DATA_MASK; inc = (DF << SHIFT); do { - v2 = glue(ldu, SUFFIX)((void *)ESI); + v2 = glue(ldu, SUFFIX)((void *)EDI); + EDI += inc; + ECX--; if (v1 == v2) break; - ESI += inc; - ECX--; } while (ECX != 0); CC_SRC = v1; CC_DST = v1 - v2; @@ -543,11 +661,11 @@ void OPPROTO glue(op_repz_cmps, SUFFIX)(void) do { v1 = glue(ldu, SUFFIX)((void *)ESI); v2 = glue(ldu, SUFFIX)((void *)EDI); - if (v1 != v2) - break; ESI += inc; EDI += inc; ECX--; + if (v1 != v2) + break; } while (ECX != 0); CC_SRC = v1; CC_DST = v1 - v2; @@ -563,11 +681,11 @@ void OPPROTO glue(op_repnz_cmps, SUFFIX)(void) do { v1 = glue(ldu, SUFFIX)((void *)ESI); v2 = glue(ldu, SUFFIX)((void *)EDI); - if (v1 == v2) - break; ESI += inc; EDI += inc; ECX--; + if (v1 == v2) + break; } while (ECX != 0); CC_SRC = v1; CC_DST = v1 - v2; diff --git a/tests/Makefile b/tests/Makefile index 2c2b059df..489e6b557 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -20,7 +20,7 @@ test2: test2.c # i386 emulation test (dump various opcodes) */ test-i386: test-i386.c test-i386.h test-i386-shift.h - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< test: test-i386 ./test-i386 > test-i386.ref diff --git a/tests/test-i386.c b/tests/test-i386.c index 5fb9c5cd0..55dd9eb2c 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -14,13 +14,12 @@ #define CC_S 0x0080 #define CC_O 0x0800 -/* XXX: currently no A flag */ -#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O) - #define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) static void *call_start __init_call = NULL; +#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) + #define OP add #include "test-i386.h" @@ -67,6 +66,9 @@ static void *call_start __init_call = NULL; #define OP1 #include "test-i386.h" +#undef CC_MASK +#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O) + #define OP shl #include "test-i386-shift.h" @@ -268,18 +270,148 @@ void test_jcc(void) TEST_JCC("jns", 0, 0); } +#undef CC_MASK +#define CC_MASK (CC_O | CC_C) + +#define OP mul +#include "test-i386-muldiv.h" + +#define OP imul +#include "test-i386-muldiv.h" + +#undef CC_MASK +#define CC_MASK (0) + +#define OP div +#include "test-i386-muldiv.h" + +#define OP idiv +#include "test-i386-muldiv.h" + +void test_imulw2(int op0, int op1) +{ + int res, s1, s0, flags; + s0 = op0; + s1 = op1; + res = s0; + flags = 0; + asm ("push %4\n\t" + "popf\n\t" + "imulw %w2, %w0\n\t" + "pushf\n\t" + "popl %1\n\t" + : "=q" (res), "=g" (flags) + : "q" (s1), "0" (res), "1" (flags)); + printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", + "imulw", s0, s1, res, flags & CC_MASK); +} + +void test_imull2(int op0, int op1) +{ + int res, s1, s0, flags; + s0 = op0; + s1 = op1; + res = s0; + flags = 0; + asm ("push %4\n\t" + "popf\n\t" + "imull %2, %0\n\t" + "pushf\n\t" + "popl %1\n\t" + : "=q" (res), "=g" (flags) + : "q" (s1), "0" (res), "1" (flags)); + printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", + "imull", s0, s1, res, flags & CC_MASK); +} + +void test_mul(void) +{ + test_imulb(0x1234561d, 4); + test_imulb(3, -4); + test_imulb(0x80, 0x80); + test_imulb(0x10, 0x10); + + test_imulw(0, 0x1234001d, 45); + test_imulw(0, 23, -45); + test_imulw(0, 0x8000, 0x8000); + test_imulw(0, 0x100, 0x100); + + test_imull(0, 0x1234001d, 45); + test_imull(0, 23, -45); + test_imull(0, 0x80000000, 0x80000000); + test_imull(0, 0x10000, 0x10000); + + test_mulb(0x1234561d, 4); + test_mulb(3, -4); + test_mulb(0x80, 0x80); + test_mulb(0x10, 0x10); + + test_mulw(0, 0x1234001d, 45); + test_mulw(0, 23, -45); + test_mulw(0, 0x8000, 0x8000); + test_mulw(0, 0x100, 0x100); + + test_mull(0, 0x1234001d, 45); + test_mull(0, 23, -45); + test_mull(0, 0x80000000, 0x80000000); + test_mull(0, 0x10000, 0x10000); + + test_imulw2(0x1234001d, 45); + test_imulw2(23, -45); + test_imulw2(0x8000, 0x8000); + test_imulw2(0x100, 0x100); + + test_imull2(0x1234001d, 45); + test_imull2(23, -45); + test_imull2(0x80000000, 0x80000000); + test_imull2(0x10000, 0x10000); + + test_idivb(0x12341678, 0x127e); + test_idivb(0x43210123, -5); + test_idivb(0x12340004, -1); + + test_idivw(0, 0x12345678, 12347); + test_idivw(0, -23223, -45); + test_idivw(0, 0x12348000, -1); + test_idivw(0x12343, 0x12345678, 0x81238567); + + test_idivl(0, 0x12345678, 12347); + test_idivl(0, -233223, -45); + test_idivl(0, 0x80000000, -1); + test_idivl(0x12343, 0x12345678, 0x81234567); + + test_divb(0x12341678, 0x127e); + test_divb(0x43210123, -5); + test_divb(0x12340004, -1); + + test_divw(0, 0x12345678, 12347); + test_divw(0, -23223, -45); + test_divw(0, 0x12348000, -1); + test_divw(0x12343, 0x12345678, 0x81238567); + + test_divl(0, 0x12345678, 12347); + test_divl(0, -233223, -45); + test_divl(0, 0x80000000, -1); + test_divl(0x12343, 0x12345678, 0x81234567); +} + + static void *call_end __init_call = NULL; int main(int argc, char **argv) { void **ptr; void (*func)(void); + + test_mul(); +#if 0 ptr = &call_start + 1; while (*ptr != NULL) { func = *ptr++; func(); } - test_lea(); test_jcc(); + test_lea(); +#endif return 0; } diff --git a/translate-i386.c b/translate-i386.c index 20a803904..f145a5406 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -27,7 +27,9 @@ static void error(const char *fmt, ...) va_list ap; va_start(ap, fmt); + fprintf(stderr, "\n"); vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); va_end(ap); exit(1); } @@ -98,42 +100,13 @@ enum { OR_EBP, OR_ESI, OR_EDI, - - /* I386 float registers */ - OR_ST0, - OR_ST1, - OR_ST2, - OR_ST3, - OR_ST4, - OR_ST5, - OR_ST6, - OR_ST7, OR_TMP0, /* temporary operand register */ OR_TMP1, OR_A0, /* temporary register used when doing address evaluation */ - OR_EFLAGS, /* cpu flags */ - OR_ITMP0, /* used for byte/word insertion */ - OR_ITMP1, /* used for byte/word insertion */ - OR_ITMP2, /* used for byte/word insertion */ - OR_FTMP0, /* float temporary */ - OR_DF, /* D flag, for string ops */ OR_ZERO, /* fixed zero register */ - OR_IM, /* dummy immediate value register */ NB_OREGS, }; -#if 0 -static const double tab_const[7] = { - 1.0, - 3.32192809488736234789, /* log2(10) */ - M_LOG2E, - M_PI, - 0.30102999566398119521, /* log10(2) */ - M_LN2, - 0.0 -}; -#endif - typedef void (GenOpFunc)(void); typedef void (GenOpFunc1)(long); typedef void (GenOpFunc2)(long, long); @@ -354,14 +327,29 @@ static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { gen_op_addl_T0_T1_cc, gen_op_orl_T0_T1_cc, - gen_op_adcl_T0_T1_cc, - gen_op_sbbl_T0_T1_cc, + NULL, + NULL, gen_op_andl_T0_T1_cc, gen_op_subl_T0_T1_cc, gen_op_xorl_T0_T1_cc, gen_op_cmpl_T0_T1_cc, }; +static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { + [OT_BYTE] = { + gen_op_adcb_T0_T1_cc, + gen_op_sbbb_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_adcw_T0_T1_cc, + gen_op_sbbw_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_adcl_T0_T1_cc, + gen_op_sbbl_T0_T1_cc, + }, +}; + static const int cc_op_arithb[8] = { CC_OP_ADDB, CC_OP_LOGICB, @@ -406,6 +394,21 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { }, }; +static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { + [0] = { + gen_op_btw_T0_T1_cc, + gen_op_btsw_T0_T1_cc, + gen_op_btrw_T0_T1_cc, + gen_op_btcw_T0_T1_cc, + }, + [1] = { + gen_op_btl_T0_T1_cc, + gen_op_btsl_T0_T1_cc, + gen_op_btrl_T0_T1_cc, + gen_op_btcl_T0_T1_cc, + }, +}; + static GenOpFunc *gen_op_lds_T0_A0[3] = { gen_op_ldsb_T0_A0, gen_op_ldsw_T0_A0, @@ -644,18 +647,23 @@ static void gen_op(DisasContext *s1, int op, int ot, int d, int s) gen_op_mov_TN_reg[ot][0][d](); if (s != OR_TMP1) gen_op_mov_TN_reg[ot][1][s](); - if ((op == OP_ADCL || op == OP_SBBL) && s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - gen_op_arith_T0_T1_cc[op](); + if (op == OP_ADCL || op == OP_SBBL) { + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + s1->cc_op = CC_OP_DYNAMIC; + } else { + gen_op_arith_T0_T1_cc[op](); + s1->cc_op = cc_op_arithb[op] + ot; + } if (d != OR_TMP0 && op != OP_CMPL) gen_op_mov_reg_T0[ot][d](); - s1->cc_op = cc_op_arithb[op] + ot; } static void gen_opi(DisasContext *s1, int op, int ot, int d, int c) { gen_op_movl_T1_im(c); - gen_op(s1, op, ot, d, OR_TMP0); + gen_op(s1, op, ot, d, OR_TMP1); } static void gen_inc(DisasContext *s1, int ot, int d, int c) @@ -664,10 +672,13 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) gen_op_mov_TN_reg[ot][0][d](); if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); - if (c > 0) + if (c > 0) { gen_op_incl_T0_cc(); - else + s1->cc_op = CC_OP_INCB + ot; + } else { gen_op_decl_T0_cc(); + s1->cc_op = CC_OP_DECB + ot; + } if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); } @@ -678,20 +689,12 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) gen_op_mov_TN_reg[ot][0][d](); if (s != OR_TMP1) gen_op_mov_TN_reg[ot][1][s](); - switch(op) { - case OP_ROL: - case OP_ROR: - case OP_RCL: - case OP_RCR: - /* only C and O are modified, so we must update flags dynamically */ - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - gen_op_shift_T0_T1_cc[ot][op](); - break; - default: - gen_op_shift_T0_T1_cc[ot][op](); - break; - } + /* for zero counts, flags are not updated, so must do it dynamically */ + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + + gen_op_shift_T0_T1_cc[ot][op](); + if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ @@ -785,12 +788,65 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ } gen_op_addl_A0_reg_sN[scale][reg2](); } - opreg = OR_A0; } else { - fprintf(stderr, "16 bit addressing not supported\n"); - disp = 0; - opreg = 0; + switch (mod) { + case 0: + if (rm == 6) { + disp = lduw(s->pc); + s->pc += 2; + gen_op_movl_A0_im(disp); + goto no_rm; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub(s->pc++); + break; + default: + case 2: + disp = lduw(s->pc); + s->pc += 2; + break; + } + switch(rm) { + case 0: + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_reg_sN[0][R_ESI](); + break; + case 1: + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_reg_sN[0][R_EDI](); + break; + case 2: + gen_op_movl_A0_reg[R_EBP](); + gen_op_addl_A0_reg_sN[0][R_ESI](); + break; + case 3: + gen_op_movl_A0_reg[R_EBP](); + gen_op_addl_A0_reg_sN[0][R_EDI](); + break; + case 4: + gen_op_movl_A0_reg[R_ESI](); + break; + case 5: + gen_op_movl_A0_reg[R_EDI](); + break; + case 6: + gen_op_movl_A0_reg[R_EBP](); + break; + default: + case 7: + gen_op_movl_A0_reg[R_EBX](); + break; + } + if (disp != 0) + gen_op_addl_A0_im(disp); + gen_op_andl_A0_ffff(); + no_rm: ; } + opreg = OR_A0; + disp = 0; *reg_ptr = opreg; *offset_ptr = disp; } @@ -870,6 +926,12 @@ static void gen_jcc(DisasContext *s, int b, int val) case CC_OP_ADDB: case CC_OP_ADDW: case CC_OP_ADDL: + case CC_OP_ADCB: + case CC_OP_ADCW: + case CC_OP_ADCL: + case CC_OP_SBBB: + case CC_OP_SBBW: + case CC_OP_SBBL: case CC_OP_LOGICB: case CC_OP_LOGICW: case CC_OP_LOGICL: @@ -882,6 +944,9 @@ static void gen_jcc(DisasContext *s, int b, int val) case CC_OP_SHLB: case CC_OP_SHLW: case CC_OP_SHLL: + case CC_OP_SARB: + case CC_OP_SARW: + case CC_OP_SARL: switch(jcc_op) { case JCC_Z: func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; @@ -1284,11 +1349,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_inc(s, ot, OR_TMP0, 1); if (mod != 3) gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][rm](); break; case 1: /* dec Ev */ gen_inc(s, ot, OR_TMP0, -1); if (mod != 3) gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][rm](); break; case 2: /* call Ev */ gen_op_movl_T1_im((long)s->pc); @@ -1359,7 +1428,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); reg = ((modrm >> 3) & 7) + OR_EAX; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); if (b == 0x69) { val = insn_get(s, ot); @@ -1372,9 +1440,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) } if (ot == OT_LONG) { - op_imull_T0_T1(); + gen_op_imull_T0_T1(); } else { - op_imulw_T0_T1(); + gen_op_imulw_T0_T1(); } gen_op_mov_reg_T0[ot][reg](); s->cc_op = CC_OP_MUL; @@ -1522,7 +1590,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) offset_addr = insn_get(s, OT_LONG); else offset_addr = insn_get(s, OT_WORD); - + gen_op_movl_A0_im(offset_addr); if ((b & 2) == 0) { gen_op_ld_T0_A0[ot](); gen_op_mov_reg_T0[ot][R_EAX](); @@ -1717,17 +1785,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) break; } break; -#if 0 + case 0x0d: /* fldcw mem */ + gen_op_fldcw_A0(); + break; + case 0x0f: /* fnstcw mem */ + gen_op_fnstcw_A0(); + break; case 0x2f: /* fnstsw mem */ - gen_insn3(OP_FNSTS, OR_TMP0, OR_ZERO, OR_ZERO); - gen_st(OP_STW, OR_TMP0, reg_addr, offset_addr); + gen_op_fnstsw_A0(); break; - case 0x3c: /* fbld */ case 0x3e: /* fbstp */ error("float BCD not hanlded"); return -1; -#endif case 0x3d: /* fildll */ gen_op_fpush(); gen_op_fildll_ST0_A0(); @@ -1737,7 +1807,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_fpop(); break; default: - error("unhandled memory FP\n"); + error("unhandled memory FP [op=0x%02x]\n", op); return -1; } } else { @@ -1987,11 +2057,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPNZ) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_scas[6 + ot](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_scas[3 + ot](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { gen_op_scas[ot](); + s->cc_op = CC_OP_SUBB + ot; } break; @@ -2002,11 +2079,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPNZ) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_cmps[6 + ot](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_cmps[3 + ot](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { gen_op_cmps[ot](); + s->cc_op = CC_OP_SUBB + ot; } break; @@ -2186,6 +2270,74 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_std(); break; + /************************/ + /* bit operations */ + case 0x1ba: /* bt/bts/btr/btc Gv, im */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + op = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + /* load shift */ + val = ldub(s->pc++); + gen_op_movl_T1_im(val); + if (op < 4) + return -1; + op -= 4; + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_SHLB + ot; + if (op != 0) { + if (mod != 3) + gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][rm](); + } + break; + case 0x1a3: /* bt Gv, Ev */ + op = 0; + goto do_btx; + case 0x1ab: /* bts */ + op = 1; + goto do_btx; + case 0x1b3: /* btr */ + op = 2; + goto do_btx; + case 0x1bb: /* btc */ + op = 3; + do_btx: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + gen_op_mov_TN_reg[OT_LONG][1][reg](); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* specific case: we need to add a displacement */ + if (ot == OT_WORD) + gen_op_add_bitw_A0_T1(); + else + gen_op_add_bitl_A0_T1(); + gen_op_ld_T0_A0[ot](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_SHLB + ot; + if (op != 0) { + if (mod != 3) + gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][rm](); + } + break; + /************************/ /* misc */ case 0x90: /* nop */ @@ -2206,6 +2358,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_into((long)pc_start, (long)s->pc); *is_jmp_ptr = 1; break; + case 0x1c8 ... 0x1cf: /* bswap reg */ + reg = b & 7; + gen_op_mov_TN_reg[OT_LONG][0][reg](); + gen_op_bswapl_T0(); + gen_op_mov_reg_T0[OT_LONG][reg](); + break; + #if 0 case 0x1a2: /* cpuid */ gen_insn0(OP_ASM); -- cgit v1.2.3 From d57c4e01206ebc8b21702c243e7a19638f783b43 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Mar 2003 01:14:13 +0000 Subject: added shiftd support - improved auto test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@20 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 + cpu-i386.h | 3 +- ops_template.h | 144 +++++++++++++++++++++++++++++++++++++++++++---- tests/Makefile | 2 +- tests/test-i386-muldiv.h | 56 ++++++++++++++++++ tests/test-i386-shift.h | 85 +++++++++++++++++++++++----- tests/test-i386.c | 33 ++++++++++- tests/test-i386.h | 131 ++++++++++++++++++++++++++++++++++++++++++ translate-i386.c | 83 ++++++++++++++++++++++++++- 9 files changed, 504 insertions(+), 34 deletions(-) create mode 100644 tests/test-i386-muldiv.h create mode 100644 tests/test-i386.h diff --git a/Makefile b/Makefile index 066f30cbe..a2498001a 100644 --- a/Makefile +++ b/Makefile @@ -84,6 +84,7 @@ dis-asm.h gen-i386.h op-i386.h syscall.c\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ i386.ld ppc.ld\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ +tests/test-i386-muldiv.h\ tests/test2.c tests/hello.c tests/sha1.c tests/test1.c FILE=gemu-$(VERSION) diff --git a/cpu-i386.h b/cpu-i386.h index e528f6198..c24546663 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -149,9 +149,8 @@ typedef struct CPUX86State { uint32_t segs[6]; /* emulator internal variables */ - CPU86_LDouble ft0; - + /* exception handling */ jmp_buf jmp_env; int exception_index; diff --git a/ops_template.h b/ops_template.h index e7317eae6..ce92db097 100644 --- a/ops_template.h +++ b/ops_template.h @@ -175,12 +175,13 @@ static int glue(compute_all_dec, SUFFIX)(void) static int glue(compute_all_shl, SUFFIX)(void) { int cf, pf, af, zf, sf, of; - cf = CC_SRC & 1; + cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C; pf = parity_table[(uint8_t)CC_DST]; af = 0; /* undefined */ zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift(CC_SRC, 12 - DATA_BITS) & CC_O; /* only meaniful for shr with count == 1 */ + /* of is defined if shift count == 1 */ + of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } @@ -199,7 +200,8 @@ static int glue(compute_all_sar, SUFFIX)(void) af = 0; /* undefined */ zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = 0; /* only meaniful for shr with count == 1 */ + /* of is defined if shift count == 1 */ + of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } @@ -415,13 +417,8 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) { int count; count = T1 & 0x1f; - if (count == 1) { - CC_SRC = T0; - T0 = T0 << 1; - CC_DST = T0; - CC_OP = CC_OP_ADDB + SHIFT; - } else if (count) { - CC_SRC = (DATA_TYPE)T0 >> (DATA_BITS - count); + if (count) { + CC_SRC = (DATA_TYPE)T0 << (count - 1); T0 = T0 << count; CC_DST = T0; CC_OP = CC_OP_SHLB + SHIFT; @@ -438,7 +435,7 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) CC_SRC = T0 >> (count - 1); T0 = T0 >> count; CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; + CC_OP = CC_OP_SARB + SHIFT; } FORCE_RET(); } @@ -449,7 +446,7 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) count = T1 & 0x1f; if (count) { src = (DATA_STYPE)T0; - CC_SRC = src >> (count - 1); + CC_SRC = src >> (count - 1); T0 = src >> count; CC_DST = T0; CC_OP = CC_OP_SARB + SHIFT; @@ -457,6 +454,129 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) FORCE_RET(); } +#if DATA_BITS == 16 +/* XXX: overflow flag might be incorrect in some cases in shldw */ +void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + unsigned int res; + count = PARAM1; + T1 &= 0xffff; + res = T1 | (T0 << 16); + CC_SRC = res >> (32 - count); + res <<= count; + if (count > 16) + res |= T1 << (count - 16); + T0 = res >> 16; + CC_DST = T0; +} + +void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + unsigned int res; + count = ECX & 0x1f; + if (count) { + T1 &= 0xffff; + res = T1 | (T0 << 16); + CC_SRC = res >> (32 - count); + res <<= count; + if (count > 16) + res |= T1 << (count - 16); + T0 = res >> 16; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } +} + +void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + unsigned int res; + + count = PARAM1; + res = (T0 & 0xffff) | (T1 << 16); + CC_SRC = res >> (count - 1); + res >>= count; + if (count > 16) + res |= T1 << (32 - count); + T0 = res; + CC_DST = T0; +} + + +void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + unsigned int res; + + count = ECX & 0x1f; + if (count) { + res = (T0 & 0xffff) | (T1 << 16); + CC_SRC = res >> (count - 1); + res >>= count; + if (count > 16) + res |= T1 << (32 - count); + T0 = res; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } +} +#endif + +#if DATA_BITS == 32 +void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + count = PARAM1; + T0 &= DATA_MASK; + T1 &= DATA_MASK; + CC_SRC = T0 << (count - 1); + T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); + CC_DST = T0; +} + +void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + count = ECX & 0x1f; + if (count) { + T0 &= DATA_MASK; + T1 &= DATA_MASK; + CC_SRC = T0 << (count - 1); + T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } +} + +void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + count = PARAM1; + T0 &= DATA_MASK; + T1 &= DATA_MASK; + CC_SRC = T0 >> (count - 1); + T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); + CC_DST = T0; +} + + +void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + count = ECX & 0x1f; + if (count) { + T0 &= DATA_MASK; + T1 &= DATA_MASK; + CC_SRC = T0 >> (count - 1); + T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } +} +#endif + /* carry add/sub (we only need to set CC_OP differently) */ void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void) diff --git a/tests/Makefile b/tests/Makefile index 489e6b557..30022b19a 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -19,7 +19,7 @@ test2: test2.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< # i386 emulation test (dump various opcodes) */ -test-i386: test-i386.c test-i386.h test-i386-shift.h +test-i386: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< test: test-i386 diff --git a/tests/test-i386-muldiv.h b/tests/test-i386-muldiv.h new file mode 100644 index 000000000..5dba315c2 --- /dev/null +++ b/tests/test-i386-muldiv.h @@ -0,0 +1,56 @@ + +void glue(glue(test_, OP), b)(int op0, int op1) +{ + int res, s1, s0, flags; + s0 = op0; + s1 = op1; + res = s0; + flags = 0; + asm ("push %4\n\t" + "popf\n\t" + stringify(OP)"b %b2\n\t" + "pushf\n\t" + "popl %1\n\t" + : "=a" (res), "=g" (flags) + : "q" (s1), "0" (res), "1" (flags)); + printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", + stringify(OP) "b", s0, s1, res, flags & CC_MASK); +} + +void glue(glue(test_, OP), w)(int op0h, int op0, int op1) +{ + int res, s1, flags, resh; + s1 = op1; + resh = op0h; + res = op0; + flags = 0; + asm ("push %5\n\t" + "popf\n\t" + stringify(OP) "w %w3\n\t" + "pushf\n\t" + "popl %1\n\t" + : "=a" (res), "=g" (flags), "=d" (resh) + : "q" (s1), "0" (res), "1" (flags), "2" (resh)); + printf("%-10s AH=%08x AL=%08x B=%08x RH=%08x RL=%08x CC=%04x\n", + stringify(OP) "w", op0h, op0, s1, resh, res, flags & CC_MASK); +} + +void glue(glue(test_, OP), l)(int op0h, int op0, int op1) +{ + int res, s1, flags, resh; + s1 = op1; + resh = op0h; + res = op0; + flags = 0; + asm ("push %5\n\t" + "popf\n\t" + stringify(OP) "l %3\n\t" + "pushf\n\t" + "popl %1\n\t" + : "=a" (res), "=g" (flags), "=d" (resh) + : "q" (s1), "0" (res), "1" (flags), "2" (resh)); + printf("%-10s AH=%08x AL=%08x B=%08x RH=%08x RL=%08x CC=%04x\n", + stringify(OP) "l", op0h, op0, s1, resh, res, flags & CC_MASK); +} + +#undef OP diff --git a/tests/test-i386-shift.h b/tests/test-i386-shift.h index af892f6c7..f3795d9f3 100644 --- a/tests/test-i386-shift.h +++ b/tests/test-i386-shift.h @@ -4,7 +4,19 @@ #define exec_opw glue(glue(exec_, OP), w) #define exec_opb glue(glue(exec_, OP), b) -#define EXECSHIFT(size, res, s1, flags) \ +#ifndef OP_SHIFTD + +#ifdef OP_NOBYTE +#define EXECSHIFT(size, res, s1, s2, flags) \ + asm ("push %4\n\t"\ + "popf\n\t"\ + stringify(OP) size " %" size "2, %" size "0\n\t" \ + "pushf\n\t"\ + "popl %1\n\t"\ + : "=g" (res), "=g" (flags)\ + : "r" (s1), "0" (res), "1" (flags)); +#else +#define EXECSHIFT(size, res, s1, s2, flags) \ asm ("push %4\n\t"\ "popf\n\t"\ stringify(OP) size " %%cl, %" size "0\n\t" \ @@ -12,13 +24,14 @@ "popl %1\n\t"\ : "=q" (res), "=g" (flags)\ : "c" (s1), "0" (res), "1" (flags)); +#endif -void exec_opl(int s0, int s1, int iflags) +void exec_opl(int s2, int s0, int s1, int iflags) { int res, flags; res = s0; flags = iflags; - EXECSHIFT("", res, s1, flags); + EXECSHIFT("", res, s1, s2, flags); /* overflow is undefined if count != 1 */ if (s1 != 1) flags &= ~CC_O; @@ -26,12 +39,12 @@ void exec_opl(int s0, int s1, int iflags) stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK); } -void exec_opw(int s0, int s1, int iflags) +void exec_opw(int s2, int s0, int s1, int iflags) { int res, flags; res = s0; flags = iflags; - EXECSHIFT("w", res, s1, flags); + EXECSHIFT("w", res, s1, s2, flags); /* overflow is undefined if count != 1 */ if (s1 != 1) flags &= ~CC_O; @@ -39,27 +52,69 @@ void exec_opw(int s0, int s1, int iflags) stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK); } +#else +#define EXECSHIFT(size, res, s1, s2, flags) \ + asm ("push %4\n\t"\ + "popf\n\t"\ + stringify(OP) size " %%cl, %" size "5, %" size "0\n\t" \ + "pushf\n\t"\ + "popl %1\n\t"\ + : "=g" (res), "=g" (flags)\ + : "c" (s1), "0" (res), "1" (flags), "r" (s2)); + +void exec_opl(int s2, int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECSHIFT("", res, s1, s2, flags); + /* overflow is undefined if count != 1 */ + if (s1 != 1) + flags &= ~CC_O; + printf("%-10s A=%08x B=%08x C=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "l", s0, s2, s1, res, iflags, flags & CC_MASK); +} + +void exec_opw(int s2, int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECSHIFT("w", res, s1, s2, flags); + /* overflow is undefined if count != 1 */ + if (s1 != 1) + flags &= ~CC_O; + printf("%-10s A=%08x B=%08x C=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "w", s0, s2, s1, res, iflags, flags & CC_MASK); +} + +#endif + +#ifndef OP_NOBYTE void exec_opb(int s0, int s1, int iflags) { int res, flags; res = s0; flags = iflags; - EXECSHIFT("b", res, s1, flags); + EXECSHIFT("b", res, s1, 0, flags); /* overflow is undefined if count != 1 */ if (s1 != 1) flags &= ~CC_O; printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK); } +#endif -void exec_op(int s0, int s1) +void exec_op(int s2, int s0, int s1) { - exec_opl(s0, s1, 0); - exec_opw(s0, s1, 0); + exec_opl(s2, s0, s1, 0); + exec_opw(s2, s0, s1, 0); +#ifndef OP_NOBYTE exec_opb(s0, s1, 0); +#endif #ifdef OP_CC - exec_opl(s0, s1, CC_C); - exec_opw(s0, s1, CC_C); + exec_opl(s2, s0, s1, CC_C); + exec_opw(s2, s0, s1, CC_C); exec_opb(s0, s1, CC_C); #endif } @@ -68,12 +123,16 @@ void glue(test_, OP)(void) { int i; for(i = 0; i < 32; i++) - exec_op(0x12345678, i); + exec_op(0x21ad3d34, 0x12345678, i); for(i = 0; i < 32; i++) - exec_op(0x82345678, i); + exec_op(0x813f3421, 0x82345678, i); } void *glue(_test_, OP) __init_call = glue(test_, OP); #undef OP #undef OP_CC +#undef OP_SHIFTD +#undef OP_NOBYTE +#undef EXECSHIFT + diff --git a/tests/test-i386.c b/tests/test-i386.c index 55dd9eb2c..b3438ebbf 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -92,6 +92,35 @@ static void *call_start __init_call = NULL; #define OP_CC #include "test-i386-shift.h" +#define OP shld +#define OP_SHIFTD +#define OP_NOBYTE +#include "test-i386-shift.h" + +#define OP shrd +#define OP_SHIFTD +#define OP_NOBYTE +#include "test-i386-shift.h" + +/* XXX: should be more precise ? */ +#undef CC_MASK +#define CC_MASK (CC_C) + +#define OP bt +#define OP_NOBYTE +#include "test-i386-shift.h" + +#define OP bts +#define OP_NOBYTE +#include "test-i386-shift.h" + +#define OP btr +#define OP_NOBYTE +#include "test-i386-shift.h" + +#define OP btc +#define OP_NOBYTE +#include "test-i386-shift.h" /* lea test (modrm support) */ #define TEST_LEA(STR)\ @@ -403,15 +432,13 @@ int main(int argc, char **argv) void **ptr; void (*func)(void); - test_mul(); -#if 0 ptr = &call_start + 1; while (*ptr != NULL) { func = *ptr++; func(); } + test_mul(); test_jcc(); test_lea(); -#endif return 0; } diff --git a/tests/test-i386.h b/tests/test-i386.h new file mode 100644 index 000000000..7d1812c88 --- /dev/null +++ b/tests/test-i386.h @@ -0,0 +1,131 @@ + +#define exec_op glue(exec_, OP) +#define exec_opl glue(glue(exec_, OP), l) +#define exec_opw glue(glue(exec_, OP), w) +#define exec_opb glue(glue(exec_, OP), b) + +#define EXECOP2(size, res, s1, flags) \ + asm ("push %4\n\t"\ + "popf\n\t"\ + stringify(OP) size " %" size "2, %" size "0\n\t" \ + "pushf\n\t"\ + "popl %1\n\t"\ + : "=q" (res), "=g" (flags)\ + : "q" (s1), "0" (res), "1" (flags)); + +#define EXECOP1(size, res, flags) \ + asm ("push %3\n\t"\ + "popf\n\t"\ + stringify(OP) size " %" size "0\n\t" \ + "pushf\n\t"\ + "popl %1\n\t"\ + : "=q" (res), "=g" (flags)\ + : "0" (res), "1" (flags)); + +#ifdef OP1 +void exec_opl(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECOP1("", res, flags); + printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "l", s0, res, iflags, flags & CC_MASK); +} + +void exec_opw(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECOP1("w", res, flags); + printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "w", s0, res, iflags, flags & CC_MASK); +} + +void exec_opb(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECOP1("b", res, flags); + printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "b", s0, res, iflags, flags & CC_MASK); +} +#else +void exec_opl(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECOP2("", res, s1, flags); + printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK); +} + +void exec_opw(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECOP2("w", res, s1, flags); + printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK); +} + +void exec_opb(int s0, int s1, int iflags) +{ + int res, flags; + res = s0; + flags = iflags; + EXECOP2("b", res, s1, flags); + printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK); +} +#endif + +void exec_op(int s0, int s1) +{ + exec_opl(s0, s1, 0); + exec_opw(s0, s1, 0); + exec_opb(s0, s1, 0); +#ifdef OP_CC + exec_opl(s0, s1, CC_C); + exec_opw(s0, s1, CC_C); + exec_opb(s0, s1, CC_C); +#endif +} + +void glue(test_, OP)(void) +{ + exec_op(0x12345678, 0x812FADA); + exec_op(0x12341, 0x12341); + exec_op(0x12341, -0x12341); + exec_op(0xffffffff, 0); + exec_op(0xffffffff, -1); + exec_op(0xffffffff, 1); + exec_op(0xffffffff, 2); + exec_op(0x7fffffff, 0); + exec_op(0x7fffffff, 1); + exec_op(0x7fffffff, -1); + exec_op(0x80000000, -1); + exec_op(0x80000000, 1); + exec_op(0x80000000, -2); + exec_op(0x12347fff, 0); + exec_op(0x12347fff, 1); + exec_op(0x12347fff, -1); + exec_op(0x12348000, -1); + exec_op(0x12348000, 1); + exec_op(0x12348000, -2); + exec_op(0x12347f7f, 0); + exec_op(0x12347f7f, 1); + exec_op(0x12347f7f, -1); + exec_op(0x12348080, -1); + exec_op(0x12348080, 1); + exec_op(0x12348080, -2); +} + +void *glue(_test_, OP) __init_call = glue(test_, OP); + +#undef OP +#undef OP_CC diff --git a/translate-i386.c b/translate-i386.c index f145a5406..69c769c19 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -394,6 +394,28 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { }, }; +static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = { + [0] = { + gen_op_shldw_T0_T1_im_cc, + gen_op_shrdw_T0_T1_im_cc, + }, + [1] = { + gen_op_shldl_T0_T1_im_cc, + gen_op_shrdl_T0_T1_im_cc, + }, +}; + +static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = { + [0] = { + gen_op_shldw_T0_T1_ECX_cc, + gen_op_shrdw_T0_T1_ECX_cc, + }, + [1] = { + gen_op_shldl_T0_T1_ECX_cc, + gen_op_shrdl_T0_T1_ECX_cc, + }, +}; + static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { [0] = { gen_op_btw_T0_T1_cc, @@ -1689,6 +1711,59 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) shift = 0; goto grp2; + case 0x1a4: /* shld imm */ + op = 0; + shift = 1; + goto do_shiftd; + case 0x1a5: /* shld cl */ + op = 0; + shift = 0; + goto do_shiftd; + case 0x1ac: /* shrd imm */ + op = 1; + shift = 1; + goto do_shiftd; + case 0x1ad: /* shrd cl */ + op = 1; + shift = 0; + do_shiftd: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + gen_op_mov_TN_reg[ot][1][reg](); + + if (shift) { + val = ldub(s->pc++); + val &= 0x1f; + if (val) { + gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); + if (op == 0 && ot != OT_WORD) + s->cc_op = CC_OP_SHLB + ot; + else + s->cc_op = CC_OP_SARB + ot; + } + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + } + if (mod != 3) { + gen_op_st_T0_A0[ot](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + break; + /************************/ /* floats */ case 0xd8 ... 0xdf: @@ -2002,6 +2077,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) break; #endif default: + error("unhandled FP df/4\n"); return -1; } break; @@ -2291,7 +2367,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) return -1; op -= 4; gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); - s->cc_op = CC_OP_SHLB + ot; + s->cc_op = CC_OP_SARB + ot; if (op != 0) { if (mod != 3) gen_op_st_T0_A0[ot](); @@ -2329,7 +2405,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_mov_TN_reg[ot][0][rm](); } gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); - s->cc_op = CC_OP_SHLB + ot; + s->cc_op = CC_OP_SARB + ot; if (op != 0) { if (mod != 3) gen_op_st_T0_A0[ot](); @@ -2417,7 +2493,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, is_jmp = 0; ret = disas_insn(dc, pc_start, &is_jmp); if (ret == -1) - error("unknown instruction at PC=0x%x", pc_start); + error("unknown instruction at PC=0x%x B=%02x %02x", + pc_start, pc_start[0], pc_start[1]); /* we must store the eflags state if it is not already done */ if (dc->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(dc->cc_op); -- cgit v1.2.3 From 9d8e9c09932455a21c57559925def82361b23a09 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 5 Mar 2003 20:57:02 +0000 Subject: bsx/float tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@21 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 4 +-- tests/test-i386.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 30022b19a..7decbf542 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -13,14 +13,14 @@ hello: hello.c $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< test1: test1.c - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + $(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $< test2: test2.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< # i386 emulation test (dump various opcodes) */ test-i386: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< -lm test: test-i386 ./test-i386 > test-i386.ref diff --git a/tests/test-i386.c b/tests/test-i386.c index b3438ebbf..bef997a1a 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -424,6 +424,105 @@ void test_mul(void) test_divl(0x12343, 0x12345678, 0x81234567); } +#define TEST_BSX(op, size, op0)\ +{\ + int res, val, resz;\ + val = op0;\ + asm("xorl %1, %1 ; " #op " %" size "2, %" size "0 ; setz %b1" \ + : "=r" (res), "=q" (resz)\ + : "g" (val));\ + printf("%-10s A=%08x R=%08x %d\n", #op, val, resz ? 0 : res, resz);\ +} + +void test_bsx(void) +{ + TEST_BSX(bsrw, "w", 0); + TEST_BSX(bsrw, "w", 0x12340128); + TEST_BSX(bsrl, "", 0); + TEST_BSX(bsrl, "", 0x00340128); + TEST_BSX(bsfw, "w", 0); + TEST_BSX(bsfw, "w", 0x12340128); + TEST_BSX(bsfl, "", 0); + TEST_BSX(bsfl, "", 0x00340128); +} + +void test_fops(double a, double b) +{ + printf("a=%f b=%f a+b=%f\n", a, b, a + b); + printf("a=%f b=%f a-b=%f\n", a, b, a - b); + printf("a=%f b=%f a*b=%f\n", a, b, a * b); + printf("a=%f b=%f a/b=%f\n", a, b, a / b); + printf("a=%f b=%f fmod(a, b)=%f\n", a, b, fmod(a, b)); + printf("a=%f sqrt(a)=%f\n", a, sqrt(a)); + printf("a=%f sin(a)=%f\n", a, sin(a)); + printf("a=%f cos(a)=%f\n", a, cos(a)); + printf("a=%f tan(a)=%f\n", a, tan(a)); + printf("a=%f log(a)=%f\n", a, log(a)); + printf("a=%f exp(a)=%f\n", a, exp(a)); + printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b)); + /* just to test some op combining */ + printf("a=%f asin(sin(a))=%f\n", a, asin(sin(a))); + printf("a=%f acos(cos(a))=%f\n", a, acos(cos(a))); + printf("a=%f atan(tan(a))=%f\n", a, atan(tan(a))); + +} + +void test_fcmp(double a, double b) +{ + printf("(%f<%f)=%d\n", + a, b, a < b); + printf("(%f<=%f)=%d\n", + a, b, a <= b); + printf("(%f==%f)=%d\n", + a, b, a == b); + printf("(%f>%f)=%d\n", + a, b, a > b); + printf("(%f<=%f)=%d\n", + a, b, a >= b); +} + +void test_fcvt(double a) +{ + float fa; + long double la; + + fa = a; + la = a; + printf("(float)%f = %f\n", a, fa); + printf("(long double)%f = %Lf\n", a, la); + printf("a=%f floor(a)=%f\n", a, floor(a)); + printf("a=%f ceil(a)=%f\n", a, ceil(a)); + printf("a=%f rint(a)=%f\n", a, rint(a)); +} + +#define TEST(N) \ + asm("fld" #N : "=t" (a)); \ + printf("fld" #N "= %f\n", a); + +void test_fconst(void) +{ + double a; + TEST(1); + TEST(l2t); + TEST(l2e); + TEST(pi); + TEST(lg2); + TEST(ln2); + TEST(z); +} + +void test_floats(void) +{ + test_fops(2, 3); + test_fops(1.4, -5); + test_fcmp(2, -1); + test_fcmp(2, 2); + test_fcmp(2, 3); + test_fcvt(1.0/7.0); + test_fcvt(-1.0/9.0); + test_fcvt(1e30); + test_fconst(); +} static void *call_end __init_call = NULL; @@ -437,8 +536,10 @@ int main(int argc, char **argv) func = *ptr++; func(); } + test_bsx(); test_mul(); test_jcc(); test_lea(); + test_floats(); return 0; } -- cgit v1.2.3 From c5e9815da4e67d42d2a0f8dce4282e8e6d691b88 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 5 Mar 2003 22:24:26 +0000 Subject: added bcd tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@22 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 5 +---- tests/test-i386.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 7decbf542..5fc813c23 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -2,7 +2,7 @@ CC=gcc CFLAGS=-Wall -O2 -g LDFLAGS= -TESTS=hello test1 test2 sha1 test-i386 +TESTS=hello test2 sha1 test-i386 TESTS+=op-i386.o #op-i386.o op-ppc.o op-arm.o op-mips.o op-sparc.o GEMU=../gemu @@ -12,9 +12,6 @@ all: $(TESTS) hello: hello.c $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< -test1: test1.c - $(CC) $(CFLAGS) -static $(LDFLAGS) -o $@ $< - test2: test2.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< diff --git a/tests/test-i386.c b/tests/test-i386.c index bef997a1a..86a070935 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -490,6 +490,9 @@ void test_fcvt(double a) la = a; printf("(float)%f = %f\n", a, fa); printf("(long double)%f = %Lf\n", a, la); + printf("a=%016Lx\n", *(long long *)&a); + printf("la=%016Lx %04x\n", *(long long *)&la, + *(unsigned short *)((char *)(&la) + 8)); printf("a=%f floor(a)=%f\n", a, floor(a)); printf("a=%f ceil(a)=%f\n", a, ceil(a)); printf("a=%f rint(a)=%f\n", a, rint(a)); @@ -511,6 +514,17 @@ void test_fconst(void) TEST(z); } +void test_fbcd(double a) +{ + unsigned short bcd[5]; + double b; + + asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st"); + asm("fbld %1" : "=t" (b) : "m" (bcd[0])); + printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", + a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); +} + void test_floats(void) { test_fops(2, 3); @@ -522,6 +536,8 @@ void test_floats(void) test_fcvt(-1.0/9.0); test_fcvt(1e30); test_fconst(); + test_fbcd(1234567890123456); + test_fbcd(-123451234567890); } static void *call_end __init_call = NULL; -- cgit v1.2.3 From 77f8dd5add8f02253dcea1454c9d2c76d7c788a7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 5 Mar 2003 22:24:48 +0000 Subject: float fixes - added bsr/bsf support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@23 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 + TODO | 2 +- cpu-i386.h | 4 +- op-i386.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- ops_template.h | 36 +++++++++++ translate-i386.c | 83 ++++++++++++++++++++----- 6 files changed, 285 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index a2498001a..c0a2915be 100644 --- a/Makefile +++ b/Makefile @@ -83,6 +83,7 @@ cpu-i386.h gemu.h op-i386.c syscall-i386.h translate-i386.c\ dis-asm.h gen-i386.h op-i386.h syscall.c\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ i386.ld ppc.ld\ +tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h\ tests/test2.c tests/hello.c tests/sha1.c tests/test1.c diff --git a/TODO b/TODO index 24eb3863f..a12c38467 100644 --- a/TODO +++ b/TODO @@ -3,4 +3,4 @@ - threads - fix printf for doubles (fp87.c bug ?) - make it self runnable (use same trick as ld.so : include its own relocator and libc) -- better FPU comparisons (ucom/com) +- fix FPU exceptions (in particular: gen_op_fpush not before mem load) diff --git a/cpu-i386.h b/cpu-i386.h index c24546663..ae49fffd0 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -114,7 +114,7 @@ enum { }; #ifdef __i386__ -#define USE_X86LDOUBLE +//#define USE_X86LDOUBLE #endif #ifdef USE_X86LDOUBLE @@ -201,7 +201,7 @@ static inline void stl(void *ptr, int v) *(uint32_t *)ptr = v; } -static inline void stq(void *ptr, int v) +static inline void stq(void *ptr, uint64_t v) { *(uint64_t *)ptr = v; } diff --git a/op-i386.c b/op-i386.c index f7f1a9849..88bdb0a41 100644 --- a/op-i386.c +++ b/op-i386.c @@ -1055,7 +1055,7 @@ typedef union { #else -typedef { +typedef union { double d; #ifndef WORDS_BIGENDIAN struct { @@ -1119,6 +1119,31 @@ void OPPROTO op_fldl_ST0_A0(void) ST0 = ldfq((void *)A0); } +#ifdef USE_X86LDOUBLE +void OPPROTO op_fldt_ST0_A0(void) +{ + ST0 = *(long double *)A0; +} +#else +void helper_fldt_ST0_A0(void) +{ + CPU86_LDoubleU temp; + int upper, e; + /* mantissa */ + upper = lduw((uint8_t *)A0 + 8); + /* XXX: handle overflow ? */ + e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ + e |= (upper >> 4) & 0x800; /* sign */ + temp.ll = ((ldq((void *)A0) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); + ST0 = temp.d; +} + +void OPPROTO op_fldt_ST0_A0(void) +{ + helper_fldt_ST0_A0(); +} +#endif + void OPPROTO op_fild_ST0_A0(void) { ST0 = (CPU86_LDouble)ldsw((void *)A0); @@ -1143,9 +1168,34 @@ void OPPROTO op_fsts_ST0_A0(void) void OPPROTO op_fstl_ST0_A0(void) { - ST0 = ldfq((void *)A0); + stfq((void *)A0, (double)ST0); } +#ifdef USE_X86LDOUBLE +void OPPROTO op_fstt_ST0_A0(void) +{ + *(long double *)A0 = ST0; +} +#else +void helper_fstt_ST0_A0(void) +{ + CPU86_LDoubleU temp; + int e; + temp.d = ST0; + /* mantissa */ + stq((void *)A0, (MANTD(temp) << 11) | (1LL << 63)); + /* exponent + sign */ + e = EXPD(temp) - EXPBIAS + 16383; + e |= SIGND(temp) >> 16; + stw((uint8_t *)A0 + 8, e); +} + +void OPPROTO op_fstt_ST0_A0(void) +{ + helper_fstt_ST0_A0(); +} +#endif + void OPPROTO op_fist_ST0_A0(void) { int val; @@ -1167,6 +1217,103 @@ void OPPROTO op_fistll_ST0_A0(void) stq((void *)A0, val); } +/* BCD ops */ + +#define MUL10(iv) ( iv + iv + (iv << 3) ) + +void helper_fbld_ST0_A0(void) +{ + uint8_t *seg; + CPU86_LDouble fpsrcop; + int m32i; + unsigned int v; + + /* in this code, seg/m32i will be used as temporary ptr/int */ + seg = (uint8_t *)A0 + 8; + v = ldub(seg--); + /* XXX: raise exception */ + if (v != 0) + return; + v = ldub(seg--); + /* XXX: raise exception */ + if ((v & 0xf0) != 0) + return; + m32i = v; /* <-- d14 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */ + fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0; + + v = ldub(seg--); + m32i = (v >> 4); /* <-- d7 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */ + v = ldub(seg); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */ + fpsrcop += ((CPU86_LDouble)m32i); + if ( ldub(seg+9) & 0x80 ) + fpsrcop = -fpsrcop; + ST0 = fpsrcop; +} + +void OPPROTO op_fbld_ST0_A0(void) +{ + helper_fbld_ST0_A0(); +} + +void helper_fbst_ST0_A0(void) +{ + CPU86_LDouble fptemp; + CPU86_LDouble fpsrcop; + int v; + uint8_t *mem_ref, *mem_end; + + fpsrcop = rint(ST0); + mem_ref = (uint8_t *)A0; + mem_end = mem_ref + 8; + if ( fpsrcop < 0.0 ) { + stw(mem_end, 0x8000); + fpsrcop = -fpsrcop; + } else { + stw(mem_end, 0x0000); + } + while (mem_ref < mem_end) { + if (fpsrcop == 0.0) + break; + fptemp = floor(fpsrcop/10.0); + v = ((int)(fpsrcop - fptemp*10.0)); + if (fptemp == 0.0) { + stb(mem_ref++, v); + break; + } + fpsrcop = fptemp; + fptemp = floor(fpsrcop/10.0); + v |= (((int)(fpsrcop - fptemp*10.0)) << 4); + stb(mem_ref++, v); + fpsrcop = fptemp; + } + while (mem_ref < mem_end) { + stb(mem_ref++, 0); + } +} + +void OPPROTO op_fbst_ST0_A0(void) +{ + helper_fbst_ST0_A0(); +} + /* FPU move */ static inline void fpush(void) @@ -1244,6 +1391,17 @@ void OPPROTO op_fcom_ST0_FT0(void) FORCE_RET(); } +/* XXX: handle nans */ +void OPPROTO op_fucom_ST0_FT0(void) +{ + env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ + if (ST0 < FT0) + env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ + else if (ST0 == FT0) + env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ + FORCE_RET(); +} + void OPPROTO op_fadd_ST0_FT0(void) { ST0 += FT0; @@ -1321,7 +1479,7 @@ void OPPROTO op_fabs_ST0(void) ST0 = fabs(ST0); } -void OPPROTO op_fxam_ST0(void) +void helper_fxam_ST0(void) { CPU86_LDoubleU temp; int expdif; @@ -1346,7 +1504,11 @@ void OPPROTO op_fxam_ST0(void) } else { env->fpus |= 0x400; } - FORCE_RET(); +} + +void OPPROTO op_fxam_ST0(void) +{ + helper_fxam_ST0(); } void OPPROTO op_fld1_ST0(void) @@ -1354,12 +1516,12 @@ void OPPROTO op_fld1_ST0(void) ST0 = *(CPU86_LDouble *)&f15rk[1]; } -void OPPROTO op_fld2t_ST0(void) +void OPPROTO op_fldl2t_ST0(void) { ST0 = *(CPU86_LDouble *)&f15rk[6]; } -void OPPROTO op_fld2e_ST0(void) +void OPPROTO op_fldl2e_ST0(void) { ST0 = *(CPU86_LDouble *)&f15rk[5]; } @@ -1681,6 +1843,13 @@ void OPPROTO op_fnstsw_A0(void) stw((void *)A0, fpus); } +void OPPROTO op_fnstsw_EAX(void) +{ + int fpus; + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + EAX = (EAX & 0xffff0000) | fpus; +} + void OPPROTO op_fnstcw_A0(void) { stw((void *)A0, env->fpuc); @@ -1784,6 +1953,10 @@ int cpu_x86_exec(CPUX86State *env1) eflags & CC_P ? 'P' : '-', eflags & CC_C ? 'C' : '-' ); +#if 1 + fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n", + (double)ST0, (double)ST1, (double)ST(2), (double)ST(3)); +#endif } #endif cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); diff --git a/ops_template.h b/ops_template.h index ce92db097..745c27d7e 100644 --- a/ops_template.h +++ b/ops_template.h @@ -633,6 +633,42 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) T0 ^= (1 << count); } +void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) +{ + int res, count; + res = T0 & DATA_MASK; + if (res != 0) { + count = 0; + while ((res & 1) == 0) { + count++; + res >>= 1; + } + T0 = count; + CC_DST = 1; /* ZF = 1 */ + } else { + CC_DST = 0; /* ZF = 1 */ + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) +{ + int res, count; + res = T0 & DATA_MASK; + if (res != 0) { + count = DATA_BITS - 1; + while ((res & SIGN_MASK) == 0) { + count--; + res <<= 1; + } + T0 = count; + CC_DST = 1; /* ZF = 1 */ + } else { + CC_DST = 0; /* ZF = 1 */ + } + FORCE_RET(); +} + #endif /* string operations */ diff --git a/translate-i386.c b/translate-i386.c index 69c769c19..5c1fc3dd7 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -431,6 +431,17 @@ static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { }, }; +static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { + [0] = { + gen_op_bsfw_T0_cc, + gen_op_bsrw_T0_cc, + }, + [1] = { + gen_op_bsfl_T0_cc, + gen_op_bsrl_T0_cc, + }, +}; + static GenOpFunc *gen_op_lds_T0_A0[3] = { gen_op_ldsb_T0_A0, gen_op_ldsw_T0_A0, @@ -652,15 +663,16 @@ static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { gen_op_fdivr_ST0_FT0, }; +/* NOTE the exception in "r" op ordering */ static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { gen_op_fadd_STN_ST0, gen_op_fmul_STN_ST0, NULL, NULL, - gen_op_fsub_STN_ST0, gen_op_fsubr_STN_ST0, - gen_op_fdiv_STN_ST0, + gen_op_fsub_STN_ST0, gen_op_fdivr_STN_ST0, + gen_op_fdiv_STN_ST0, }; static void gen_op(DisasContext *s1, int op, int ot, int d, int s) @@ -1866,13 +1878,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) case 0x0f: /* fnstcw mem */ gen_op_fnstcw_A0(); break; + case 0x1d: /* fldt mem */ + gen_op_fpush(); + gen_op_fldt_ST0_A0(); + break; + case 0x1f: /* fstpt mem */ + gen_op_fstt_ST0_A0(); + gen_op_fpop(); + break; case 0x2f: /* fnstsw mem */ gen_op_fnstsw_A0(); break; case 0x3c: /* fbld */ + gen_op_fpush(); + op_fbld_ST0_A0(); + break; case 0x3e: /* fbstp */ - error("float BCD not hanlded"); - return -1; + gen_op_fbst_ST0_A0(); + gen_op_fpop(); + break; case 0x3d: /* fildll */ gen_op_fpush(); gen_op_fildll_ST0_A0(); @@ -1882,7 +1906,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_fpop(); break; default: - error("unhandled memory FP [op=0x%02x]\n", op); + error("unhandled FPm [op=0x%02x]\n", op); return -1; } } else { @@ -1895,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_fmov_ST0_STN((opreg + 1) & 7); break; case 0x09: /* fxchg sti */ - gen_op_fxchg_ST0_STN((opreg + 1) & 7); + gen_op_fxchg_ST0_STN(opreg); break; case 0x0a: /* grp d9/2 */ switch(rm) { @@ -1929,24 +1953,31 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) { switch(rm) { case 0: + gen_op_fpush(); gen_op_fld1_ST0(); break; case 1: - gen_op_fld2t_ST0(); + gen_op_fpush(); + gen_op_fldl2t_ST0(); break; case 2: - gen_op_fld2e_ST0(); + gen_op_fpush(); + gen_op_fldl2e_ST0(); break; case 3: + gen_op_fpush(); gen_op_fldpi_ST0(); break; case 4: + gen_op_fpush(); gen_op_fldlg2_ST0(); break; case 5: + gen_op_fpush(); gen_op_fldln2_ST0(); break; case 6: + gen_op_fpush(); gen_op_fldz_ST0(); break; default: @@ -2021,12 +2052,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) op1 = op & 7; if (op >= 0x20) { gen_op_fp_arith_STN_ST0[op1](opreg); + if (op >= 0x30) + gen_op_fpop(); } else { gen_op_fmov_FT0_STN(opreg); gen_op_fp_arith_ST0_FT0[op1](); } - if (op >= 0x30) - gen_op_fpop(); } break; case 0x02: /* fcom */ @@ -2042,7 +2073,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) switch(rm) { case 1: /* fucompp */ gen_op_fmov_FT0_STN(1); - gen_op_fcom_ST0_FT0(); + gen_op_fucom_ST0_FT0(); gen_op_fpop(); gen_op_fpop(); break; @@ -2057,6 +2088,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_fmov_STN_ST0(opreg); gen_op_fpop(); break; + case 0x2c: /* fucom st(i) */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fucom_ST0_FT0(); + break; + case 0x2d: /* fucomp st(i) */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fucom_ST0_FT0(); + gen_op_fpop(); + break; case 0x33: /* de/3 */ switch(rm) { case 1: /* fcompp */ @@ -2071,18 +2111,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) break; case 0x3c: /* df/4 */ switch(rm) { -#if 0 case 0: - gen_insn3(OP_FNSTS, OR_EAX, OR_ZERO, OR_ZERO); + gen_op_fnstsw_EAX(); break; -#endif default: - error("unhandled FP df/4\n"); + error("unhandled FP %x df/4\n", rm); return -1; } break; default: - error("unhandled FP\n"); + error("unhandled FPr [op=0x%x]\n", op); return -1; } } @@ -2413,7 +2451,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_mov_reg_T0[ot][rm](); } break; - + case 0x1bc: /* bsf */ + case 0x1bd: /* bsr */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_bsx_T0_cc[ot - OT_WORD][b & 1](); + /* NOTE: we always write back the result. Intel doc says it is + undefined if T0 == 0 */ + gen_op_mov_reg_T0[ot][reg](); + s->cc_op = CC_OP_LOGICB + ot; + break; /************************/ /* misc */ case 0x90: /* nop */ -- cgit v1.2.3 From 1017ebe9cb38ae034b0e7c6c449abe2c9b5284fb Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 5 Mar 2003 23:26:16 +0000 Subject: convert several x86 instructions at the same time git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@24 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- cpu-i386.h | 4 +-- op-i386.c | 3 +- translate-i386.c | 86 +++++++++++++++++++++++++++++++------------------------- 4 files changed, 53 insertions(+), 42 deletions(-) diff --git a/Makefile b/Makefile index c0a2915be..57d2ba1ba 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ i386.ld ppc.ld\ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h\ -tests/test2.c tests/hello.c tests/sha1.c tests/test1.c +tests/test2.c tests/hello.c tests/sha1.c FILE=gemu-$(VERSION) diff --git a/cpu-i386.h b/cpu-i386.h index ae49fffd0..4d06d9206 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -242,7 +242,7 @@ int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); /* internal functions */ -int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, - uint8_t *pc_start); +int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, + int *gen_code_size_ptr, uint8_t *pc_start); #endif /* CPU_I386_H */ diff --git a/op-i386.c b/op-i386.c index 88bdb0a41..2cca6a672 100644 --- a/op-i386.c +++ b/op-i386.c @@ -1959,7 +1959,8 @@ int cpu_x86_exec(CPUX86State *env1) #endif } #endif - cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); + cpu_x86_gen_code(code_gen_buffer, sizeof(code_gen_buffer), + &code_gen_size, (uint8_t *)env->pc); /* execute the generated code */ gen_func = (void *)code_gen_buffer; gen_func(); diff --git a/translate-i386.c b/translate-i386.c index 5c1fc3dd7..d13d5d744 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -995,7 +995,7 @@ static void gen_jcc(DisasContext *s, int b, int val) default: slow_jcc: if (s->cc_op != CC_OP_DYNAMIC) - op_set_cc_op(s->cc_op); + gen_op_set_cc_op(s->cc_op); func = gen_jcc_slow[jcc_op]; break; } @@ -1041,10 +1041,10 @@ static void gen_setcc(DisasContext *s, int b) case CC_OP_SHLL: switch(jcc_op) { case JCC_Z: - func = gen_setcc_sub[s->cc_op - CC_OP_ADDB][jcc_op]; + func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; break; case JCC_S: - func = gen_setcc_sub[s->cc_op - CC_OP_ADDB][jcc_op]; + func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; break; default: goto slow_jcc; @@ -1053,7 +1053,7 @@ static void gen_setcc(DisasContext *s, int b) default: slow_jcc: if (s->cc_op != CC_OP_DYNAMIC) - op_set_cc_op(s->cc_op); + gen_op_set_cc_op(s->cc_op); func = gen_setcc_slow[jcc_op]; break; } @@ -1891,7 +1891,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) break; case 0x3c: /* fbld */ gen_op_fpush(); - op_fbld_ST0_A0(); + gen_op_fbld_ST0_A0(); break; case 0x3e: /* fbstp */ gen_op_fbst_ST0_A0(); @@ -2338,6 +2338,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) /************************/ /* flags */ case 0x9c: /* pushf */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_movl_T0_eflags(); gen_op_pushl_T0(); break; @@ -2349,31 +2351,31 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) case 0x9e: /* sahf */ gen_op_mov_TN_reg[OT_BYTE][0][R_AH](); if (s->cc_op != CC_OP_DYNAMIC) - op_set_cc_op(s->cc_op); + gen_op_set_cc_op(s->cc_op); gen_op_movb_eflags_T0(); s->cc_op = CC_OP_EFLAGS; break; case 0x9f: /* lahf */ if (s->cc_op != CC_OP_DYNAMIC) - op_set_cc_op(s->cc_op); + gen_op_set_cc_op(s->cc_op); gen_op_movl_T0_eflags(); gen_op_mov_reg_T0[OT_BYTE][R_AH](); break; case 0xf5: /* cmc */ if (s->cc_op != CC_OP_DYNAMIC) - op_set_cc_op(s->cc_op); + gen_op_set_cc_op(s->cc_op); gen_op_cmc(); s->cc_op = CC_OP_EFLAGS; break; case 0xf8: /* clc */ if (s->cc_op != CC_OP_DYNAMIC) - op_set_cc_op(s->cc_op); + gen_op_set_cc_op(s->cc_op); gen_op_clc(); s->cc_op = CC_OP_EFLAGS; break; case 0xf9: /* stc */ if (s->cc_op != CC_OP_DYNAMIC) - op_set_cc_op(s->cc_op); + gen_op_set_cc_op(s->cc_op); gen_op_stc(); s->cc_op = CC_OP_EFLAGS; break; @@ -2503,10 +2505,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) } /* return the next pc */ -int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, - uint8_t *pc_start) +int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, + int *gen_code_size_ptr, uint8_t *pc_start) { DisasContext dc1, *dc = &dc1; + uint8_t *gen_code_end, *pc_ptr; int is_jmp; long ret; #ifdef DEBUG_DISAS @@ -2515,35 +2518,18 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, dc->cc_op = CC_OP_DYNAMIC; gen_code_ptr = gen_code_buf; + gen_code_end = gen_code_buf + max_code_size - 4096; gen_start(); -#ifdef DEBUG_DISAS - if (loglevel) { - INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); - disasm_info.buffer = pc_start; - disasm_info.buffer_vma = (unsigned long)pc_start; - disasm_info.buffer_length = 15; -#if 0 - disasm_info.flavour = bfd_get_flavour (abfd); - disasm_info.arch = bfd_get_arch (abfd); - disasm_info.mach = bfd_get_mach (abfd); -#endif -#ifdef WORDS_BIGENDIAN - disasm_info.endian = BFD_ENDIAN_BIG; -#else - disasm_info.endian = BFD_ENDIAN_LITTLE; -#endif - fprintf(logfile, "IN:\n"); - fprintf(logfile, "0x%08lx: ", (long)pc_start); - print_insn_i386((unsigned long)pc_start, &disasm_info); - fprintf(logfile, "\n\n"); - } -#endif is_jmp = 0; - ret = disas_insn(dc, pc_start, &is_jmp); - if (ret == -1) - error("unknown instruction at PC=0x%x B=%02x %02x", - pc_start, pc_start[0], pc_start[1]); + pc_ptr = pc_start; + do { + ret = disas_insn(dc, pc_ptr, &is_jmp); + if (ret == -1) + error("unknown instruction at PC=0x%x B=%02x %02x", + pc_ptr, pc_ptr[0], pc_ptr[1]); + pc_ptr = (void *)ret; + } while (!is_jmp && gen_code_ptr < gen_code_end); /* we must store the eflags state if it is not already done */ if (dc->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(dc->cc_op); @@ -2559,6 +2545,30 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int *gen_code_size_ptr, uint8_t *pc; int count; + INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); +#if 0 + disasm_info.flavour = bfd_get_flavour (abfd); + disasm_info.arch = bfd_get_arch (abfd); + disasm_info.mach = bfd_get_mach (abfd); +#endif +#ifdef WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif + fprintf(logfile, "IN:\n"); + disasm_info.buffer = pc_start; + disasm_info.buffer_vma = (unsigned long)pc_start; + disasm_info.buffer_length = pc_ptr - pc_start; + pc = pc_start; + while (pc < pc_ptr) { + fprintf(logfile, "0x%08lx: ", (long)pc); + count = print_insn_i386((unsigned long)pc, &disasm_info); + fprintf(logfile, "\n"); + pc += count; + } + fprintf(logfile, "\n"); + pc = gen_code_buf; disasm_info.buffer = pc; disasm_info.buffer_vma = (unsigned long)pc; -- cgit v1.2.3 From 7d13299d07a9c3c42277207ae7a691f0501a70b2 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 6 Mar 2003 23:23:54 +0000 Subject: added translation cache git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@25 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 40 ++++----- TODO | 6 +- configure | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++ cpu-i386.h | 1 + dyngen.c | 19 ++++ exec-i386.c | 213 +++++++++++++++++++++++++++++++++++++++++++++ exec-i386.h | 105 ++++++++++++++++++++++ linux-user/main.c | 2 +- linux-user/syscall.c | 3 + op-i386.c | 221 +++++------------------------------------------ tests/Makefile | 27 ++---- thunk.h | 7 +- translate-i386.c | 21 +++++ 13 files changed, 651 insertions(+), 254 deletions(-) create mode 100755 configure create mode 100644 exec-i386.c create mode 100644 exec-i386.h diff --git a/Makefile b/Makefile index 57d2ba1ba..0f0b22db7 100644 --- a/Makefile +++ b/Makefile @@ -1,43 +1,33 @@ -ARCH=i386 -#ARCH=ppc -HOST_CC=gcc +include config.mak -ifeq ($(ARCH),i386) -CFLAGS=-Wall -O2 -g -fomit-frame-pointer +CFLAGS=-Wall -O2 -g LDFLAGS=-g LIBS= -CC=gcc DEFINES=-DHAVE_BYTESWAP_H + +ifeq ($(ARCH),i386) +CFLAGS+=-fomit-frame-pointer OP_CFLAGS=$(CFLAGS) -malign-functions=0 -mpreferred-stack-boundary=2 endif ifeq ($(ARCH),ppc) -GCC_LIBS_DIR=/usr/netgem/tools/lib/gcc-lib/powerpc-linux/2.95.2 -DIST=/home/fbe/nsv/dist/hw/n6-dtt -CC=powerpc-linux-gcc -msoft-float -CFLAGS=-Wall -pipe -O2 -mcpu=405 -mbig -nostdinc -g -I$(GCC_LIBS_DIR)/include -I$(DIST)/include -LIBS_DIR=$(DIST)/lib -CRT1=$(LIBS_DIR)/crt1.o -CRTI=$(LIBS_DIR)/crti.o -CRTN=$(LIBS_DIR)/crtn.o -CRTBEGIN=$(GCC_LIBS_DIR)/crtbegin.o -CRTEND=$(GCC_LIBS_DIR)/crtend.o -LDFLAGS=-static -g -nostdlib $(CRT1) $(CRTI) $(CRTBEGIN) -LIBS=-L$(LIBS_DIR) -ltinyc -lgcc $(CRTEND) $(CRTN) -DEFINES=-Dsocklen_t=int OP_CFLAGS=$(CFLAGS) endif ######################################################### DEFINES+=-D_GNU_SOURCE -DEFINES+=-DCONFIG_PREFIX=\"/usr/local\" LDSCRIPT=$(ARCH).ld LIBS+=-ldl -lm -VERSION=0.1 + +# profiling code +ifdef TARGET_GPROF +LDFLAGS+=-p +CFLAGS+=-p +endif OBJS= elfload.o main.o thunk.o syscall.o -OBJS+=translate-i386.o op-i386.o +OBJS+=translate-i386.o op-i386.o exec-i386.o # NOTE: the disassembler code is only needed for debugging OBJS+=i386-dis.o dis-buf.o SRCS = $(OBJS:.o=.c) @@ -66,8 +56,12 @@ op-i386.o: op-i386.c opreg_template.h ops_template.h $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< clean: + $(MAKE) -C tests clean rm -f *.o *~ gemu dyngen TAGS +distclean: clean + rm -f config.mak config.h + # various test targets test speed: gemu make -C tests $@ @@ -82,7 +76,7 @@ TODO elfload.c main.c signal.c thunk.h\ cpu-i386.h gemu.h op-i386.c syscall-i386.h translate-i386.c\ dis-asm.h gen-i386.h op-i386.h syscall.c\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ -i386.ld ppc.ld\ +i386.ld ppc.ld exec-i386.h exec-i386.c configure VERSION \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h\ diff --git a/TODO b/TODO index a12c38467..3b04b7dce 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,8 @@ -- tests +- optimize translated cache chaining (DLL PLT like system) +- optimize inverse flags propagation (easy by generating intermediate + micro operation array). - signals - threads -- fix printf for doubles (fp87.c bug ?) - make it self runnable (use same trick as ld.so : include its own relocator and libc) - fix FPU exceptions (in particular: gen_op_fpush not before mem load) +- tests diff --git a/configure b/configure new file mode 100755 index 000000000..16252c4dc --- /dev/null +++ b/configure @@ -0,0 +1,240 @@ +#!/bin/sh +# +# gemu 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}/qemacs-conf-${RANDOM}-$$-${RANDOM}.c" +TMPO="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.o" +TMPS="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.S" +TMPH="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.h" + +# default parameters +prefix="/usr/local" +cross_prefix="" +cc="gcc" +host_cc="gcc" +ar="ar" +make="make" +strip="strip" +cpu=`uname -m` +case "$cpu" in + i386|i486|i586|i686|i86pc|BePC) + cpu="x86" + ;; + armv4l) + cpu="armv4l" + ;; + alpha) + cpu="alpha" + ;; + "Power Macintosh"|ppc) + cpu="powerpc" + ;; + mips) + cpu="mips" + ;; + *) + cpu="unknown" + ;; +esac +gprof="no" +bigendian="no" + +# OS specific +targetos=`uname -s` +case $targetos in +BeOS) +prefix="/boot/home/config" +# helps building libavcodec +CFLAGS="-O2 -DPIC" +# no need for libm, but the inet stuff +# Check for BONE +if (echo $BEINCLUDES|grep 'headers/be/bone' >/dev/null); then +extralibs="-lbind -lsocket" +else +echo "Not sure building for net_server will succeed... good luck." +extralibs="-lsocket" +fi ;; +BSD/OS) +extralibs="-lpoll -lgnugetopt -lm" +make="gmake" +;; +*) ;; +esac + +# find source path +# XXX: we assume an absolute path is given when launching configure, +# except in './configure' case. +source_path=${0%configure} +source_path=${source_path%/} +source_path_used="yes" +if test -z "$source_path" -o "$source_path" = "." ; then + source_path=`pwd` + source_path_used="no" +fi + +for opt do + case "$opt" in + --prefix=*) prefix=`echo $opt | cut -d '=' -f 2` + ;; + --source-path=*) source_path=`echo $opt | cut -d '=' -f 2` + ;; + --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` + ;; + --cc=*) cc=`echo $opt | cut -d '=' -f 2` + ;; + --make=*) make=`echo $opt | cut -d '=' -f 2` + ;; + --extra-cflags=*) CFLAGS="${opt#--extra-cflags=}" + ;; + --extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}" + ;; + --extra-libs=*) extralibs=${opt#--extra-libs=} + ;; + --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` + ;; + --enable-gprof) gprof="yes" + ;; + esac +done + +# Checking for CFLAGS +if test -z "$CFLAGS"; then + CFLAGS="-O2" +fi + +cc="${cross_prefix}${cc}" +ar="${cross_prefix}${ar}" +strip="${cross_prefix}${strip}" + +if test -z "$cross_prefix" ; then + +# --- +# big/little endian test +cat > $TMPC << EOF +#include +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" ; then + bigendian="yes" +fi + +fi + +if test x"$1" = x"-h" -o x"$1" = x"--help" ; then +cat << EOF + +Usage: configure [options] +Options: [defaults in brackets after descriptions] + +EOF +echo "Standard options:" +echo " --help print this message" +echo " --prefix=PREFIX install in PREFIX [$prefix]" +echo " for audio/video/image 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 " --make=MAKE use specified make [$make]" +echo "" +echo "NOTE: The object files are build at the place where configure is launched" +exit 1 +fi + +echo "Install prefix $prefix" +echo "Source path $source_path" +echo "C compiler $cc" +echo "make $make" +echo "CPU $cpu" +echo "Big Endian $bigendian" +echo "gprof enabled $gprof" + +echo "Creating config.mak and config.h" + +echo "# Automatically generated by configure - do not modify" > config.mak +echo "/* Automatically generated by configure - do not modify */" > $TMPH + +echo "prefix=$prefix" >> config.mak +echo "#define CONFIG_GEMU_PREFIX \"$prefix\"" >> $TMPH +echo "MAKE=$make" >> config.mak +echo "CC=$cc" >> config.mak +echo "HOST_CC=$host_cc" >> config.mak +echo "AR=$ar" >> config.mak +echo "STRIP=$strip -s -R .comment -R .note" >> config.mak +echo "CFLAGS=$CFLAGS" >> config.mak +echo "LDFLAGS=$LDFLAGS" >> config.mak +if test "$cpu" = "x86" ; then + echo "ARCH=i386" >> config.mak +elif test "$cpu" = "armv4l" ; then + echo "ARCH=arm" >> config.mak +elif test "$cpu" = "powerpc" ; then + echo "ARCH=ppc" > config.mak +elif test "$cpu" = "mips" ; then + echo "ARCH=mips" > config.mak +else + echo "Unsupported CPU" + exit 1 +fi +if test "$bigendian" = "yes" ; then + echo "WORDS_BIGENDIAN=yes" >> config.mak + echo "#define WORDS_BIGENDIAN 1" >> $TMPH +fi +if test "$gprof" = "yes" ; then + echo "TARGET_GPROF=yes" >> config.mak + echo "#define HAVE_GPROF 1" >> $TMPH +fi +echo -n "VERSION=" >>config.mak +head $source_path/VERSION >>config.mak +echo "" >>config.mak +echo -n "#define GEMU_VERSION \"" >> $TMPH +head $source_path/VERSION >> $TMPH +echo "\"" >> $TMPH +if test "$network" = "yes" ; then + echo "#define CONFIG_NETWORK 1" >> $TMPH + echo "CONFIG_NETWORK=yes" >> config.mak +fi + +# build tree in object directory if source path is different from current one +if test "$source_path_used" = "yes" ; then + DIRS="tests" + FILES="Makefile tests/Makefile" + for dir in $DIRS ; do + mkdir -p $dir + done + for f in $FILES ; do + ln -sf $source_path/$f $f + done +fi +echo "SRC_PATH=$source_path" >> config.mak + +diff $TMPH config.h >/dev/null 2>&1 +if test $? -ne 0 ; then + mv -f $TMPH config.h +else + echo "config.h is unchanged" +fi + +rm -f $TMPH diff --git a/cpu-i386.h b/cpu-i386.h index 4d06d9206..a6464efca 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -244,5 +244,6 @@ void cpu_x86_close(CPUX86State *s); /* internal functions */ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, uint8_t *pc_start); +void cpu_x86_tblocks_init(void); #endif /* CPU_I386_H */ diff --git a/dyngen.c b/dyngen.c index f6b102fef..40a7fc695 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1,3 +1,22 @@ +/* + * Generic Dynamic compiler generator + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include #include #include diff --git a/exec-i386.c b/exec-i386.c new file mode 100644 index 000000000..c06768509 --- /dev/null +++ b/exec-i386.c @@ -0,0 +1,213 @@ +/* + * i386 emulator main execution loop + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "exec-i386.h" + +#define DEBUG_EXEC +#define DEBUG_FLUSH + +/* main execution loop */ + +/* maximum total translate dcode allocated */ +#define CODE_GEN_BUFFER_SIZE (2048 * 1024) +//#define CODE_GEN_BUFFER_SIZE (128 * 1024) +#define CODE_GEN_MAX_SIZE 65536 +#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ + +/* threshold to flush the translated code buffer */ +#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) + +#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64) +#define CODE_GEN_HASH_BITS 15 +#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) +typedef struct TranslationBlock { + unsigned long pc; /* simulated PC corresponding to this block */ + uint8_t *tc_ptr; /* pointer to the translated code */ + struct TranslationBlock *hash_next; /* next matching block */ +} TranslationBlock; + +TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; +TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; +int nb_tbs; + +uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; +uint8_t *code_gen_ptr; + +#ifdef DEBUG_EXEC +static const char *cc_op_str[] = { + "DYNAMIC", + "EFLAGS", + "MUL", + "ADDB", + "ADDW", + "ADDL", + "ADCB", + "ADCW", + "ADCL", + "SUBB", + "SUBW", + "SUBL", + "SBBB", + "SBBW", + "SBBL", + "LOGICB", + "LOGICW", + "LOGICL", + "INCB", + "INCW", + "INCL", + "DECB", + "DECW", + "DECL", + "SHLB", + "SHLW", + "SHLL", + "SARB", + "SARW", + "SARL", +}; + +static void cpu_x86_dump_state(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DIRECTION_FLAG); + fprintf(logfile, + "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" + "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n", + env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], + env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], + env->cc_src, env->cc_dst, cc_op_str[env->cc_op], + eflags & DIRECTION_FLAG ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-' + ); +#if 1 + fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n", + (double)ST0, (double)ST1, (double)ST(2), (double)ST(3)); +#endif +} + +#endif + +void cpu_x86_tblocks_init(void) +{ + if (!code_gen_ptr) { + code_gen_ptr = code_gen_buffer; + } +} + +/* flush all the translation blocks */ +static void tb_flush(void) +{ + int i; +#ifdef DEBUG_FLUSH + printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", + code_gen_ptr - code_gen_buffer, + nb_tbs, + (code_gen_ptr - code_gen_buffer) / nb_tbs); +#endif + nb_tbs = 0; + for(i = 0;i < CODE_GEN_HASH_SIZE; i++) + tb_hash[i] = NULL; + code_gen_ptr = code_gen_buffer; + /* XXX: flush processor icache at this point */ +} + +/* find a translation block in the translation cache. If not found, + allocate a new one */ +static inline TranslationBlock *tb_find_and_alloc(unsigned long pc) +{ + TranslationBlock **ptb, *tb; + unsigned int h; + + h = pc & (CODE_GEN_HASH_SIZE - 1); + ptb = &tb_hash[h]; + for(;;) { + tb = *ptb; + if (!tb) + break; + if (tb->pc == pc) + return tb; + ptb = &tb->hash_next; + } + if (nb_tbs >= CODE_GEN_MAX_BLOCKS || + (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) + tb_flush(); + tb = &tbs[nb_tbs++]; + *ptb = tb; + tb->pc = pc; + tb->tc_ptr = NULL; + tb->hash_next = NULL; + return tb; +} + +int cpu_x86_exec(CPUX86State *env1) +{ + int saved_T0, saved_T1, saved_A0; + CPUX86State *saved_env; + int code_gen_size, ret; + void (*gen_func)(void); + TranslationBlock *tb; + uint8_t *tc_ptr; + + /* first we save global registers */ + saved_T0 = T0; + saved_T1 = T1; + saved_A0 = A0; + saved_env = env; + env = env1; + + /* prepare setjmp context for exception handling */ + if (setjmp(env->jmp_env) == 0) { + for(;;) { +#ifdef DEBUG_EXEC + if (loglevel) { + cpu_x86_dump_state(); + } +#endif + tb = tb_find_and_alloc((unsigned long)env->pc); + tc_ptr = tb->tc_ptr; + if (!tb->tc_ptr) { + /* if no translated code available, then translate it now */ + tc_ptr = code_gen_ptr; + cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, + &code_gen_size, (uint8_t *)env->pc); + tb->tc_ptr = tc_ptr; + code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); + } + /* execute the generated code */ + gen_func = (void *)tc_ptr; + gen_func(); + } + } + ret = env->exception_index; + + /* restore global registers */ + T0 = saved_T0; + T1 = saved_T1; + A0 = saved_A0; + env = saved_env; + return ret; +} diff --git a/exec-i386.h b/exec-i386.h new file mode 100644 index 000000000..62f681bc1 --- /dev/null +++ b/exec-i386.h @@ -0,0 +1,105 @@ +/* i386 execution defines */ + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +#define bswap32(x) \ +({ \ + uint32_t __x = (x); \ + ((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ +}) + +#define NULL 0 +#include + +typedef struct FILE FILE; +extern FILE *logfile; +extern int loglevel; +extern int fprintf(FILE *, const char *, ...); + +#ifdef __i386__ +register unsigned int T0 asm("ebx"); +register unsigned int T1 asm("esi"); +register unsigned int A0 asm("edi"); +register struct CPUX86State *env asm("ebp"); +#endif +#ifdef __powerpc__ +register unsigned int T0 asm("r24"); +register unsigned int T1 asm("r25"); +register unsigned int A0 asm("r26"); +register struct CPUX86State *env asm("r27"); +#endif +#ifdef __arm__ +register unsigned int T0 asm("r4"); +register unsigned int T1 asm("r5"); +register unsigned int A0 asm("r6"); +register struct CPUX86State *env asm("r7"); +#endif +#ifdef __mips__ +register unsigned int T0 asm("s0"); +register unsigned int T1 asm("s1"); +register unsigned int A0 asm("s2"); +register struct CPUX86State *env asm("s3"); +#endif +#ifdef __sparc__ +register unsigned int T0 asm("l0"); +register unsigned int T1 asm("l1"); +register unsigned int A0 asm("l2"); +register struct CPUX86State *env asm("l3"); +#endif + +/* force GCC to generate only one epilog at the end of the function */ +#define FORCE_RET() asm volatile (""); + +#ifndef OPPROTO +#define OPPROTO +#endif + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) + +#define EAX (env->regs[R_EAX]) +#define ECX (env->regs[R_ECX]) +#define EDX (env->regs[R_EDX]) +#define EBX (env->regs[R_EBX]) +#define ESP (env->regs[R_ESP]) +#define EBP (env->regs[R_EBP]) +#define ESI (env->regs[R_ESI]) +#define EDI (env->regs[R_EDI]) +#define PC (env->pc) +#define DF (env->df) + +#define CC_SRC (env->cc_src) +#define CC_DST (env->cc_dst) +#define CC_OP (env->cc_op) + +/* float macros */ +#define FT0 (env->ft0) +#define ST0 (env->fpregs[env->fpstt]) +#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) +#define ST1 ST(1) + +extern int __op_param1, __op_param2, __op_param3; +#define PARAM1 ((long)(&__op_param1)) +#define PARAM2 ((long)(&__op_param2)) +#define PARAM3 ((long)(&__op_param3)) + +#include "cpu-i386.h" + +typedef struct CCTable { + int (*compute_all)(void); /* return all the flags */ + int (*compute_c)(void); /* return the C flag */ +} CCTable; + +extern CCTable cc_table[]; diff --git a/linux-user/main.c b/linux-user/main.c index 356d980f0..9927b8256 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -87,7 +87,7 @@ int cpu_x86_inl(int addr) void usage(void) { - printf("gemu version 0.1, Copyright (c) 2003 Fabrice Bellard\n" + printf("gemu version" GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" "usage: gemu [-d] program [arguments...]\n" "Linux x86 emulator\n" ); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f800fa219..ac40cf19e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -628,6 +628,9 @@ long do_syscall(int num, long arg1, long arg2, long arg3, #endif switch(num) { case TARGET_NR_exit: +#ifdef HAVE_GPROF + _mcleanup(); +#endif _exit(arg1); ret = 0; /* avoid warning */ break; diff --git a/op-i386.c b/op-i386.c index 2cca6a672..6bd9de015 100644 --- a/op-i386.c +++ b/op-i386.c @@ -1,109 +1,25 @@ -#define DEBUG_EXEC - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; - -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef signed long long int64_t; - -#define bswap32(x) \ -({ \ - uint32_t __x = (x); \ - ((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ -}) - -#define NULL 0 -#include - -typedef struct FILE FILE; -extern FILE *logfile; -extern int loglevel; -extern int fprintf(FILE *, const char *, ...); - -#ifdef __i386__ -register unsigned int T0 asm("ebx"); -register unsigned int T1 asm("esi"); -register unsigned int A0 asm("edi"); -register struct CPUX86State *env asm("ebp"); -#endif -#ifdef __powerpc__ -register unsigned int T0 asm("r24"); -register unsigned int T1 asm("r25"); -register unsigned int A0 asm("r26"); -register struct CPUX86State *env asm("r27"); -#endif -#ifdef __arm__ -register unsigned int T0 asm("r4"); -register unsigned int T1 asm("r5"); -register unsigned int A0 asm("r6"); -register struct CPUX86State *env asm("r7"); -#endif -#ifdef __mips__ -register unsigned int T0 asm("s0"); -register unsigned int T1 asm("s1"); -register unsigned int A0 asm("s2"); -register struct CPUX86State *env asm("s3"); -#endif -#ifdef __sparc__ -register unsigned int T0 asm("l0"); -register unsigned int T1 asm("l1"); -register unsigned int A0 asm("l2"); -register struct CPUX86State *env asm("l3"); -#endif - -/* force GCC to generate only one epilog at the end of the function */ -#define FORCE_RET() asm volatile (""); - -#ifndef OPPROTO -#define OPPROTO -#endif - -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) - -#define EAX (env->regs[R_EAX]) -#define ECX (env->regs[R_ECX]) -#define EDX (env->regs[R_EDX]) -#define EBX (env->regs[R_EBX]) -#define ESP (env->regs[R_ESP]) -#define EBP (env->regs[R_EBP]) -#define ESI (env->regs[R_ESI]) -#define EDI (env->regs[R_EDI]) -#define PC (env->pc) -#define DF (env->df) - -#define CC_SRC (env->cc_src) -#define CC_DST (env->cc_dst) -#define CC_OP (env->cc_op) - -/* float macros */ -#define FT0 (env->ft0) -#define ST0 (env->fpregs[env->fpstt]) -#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) -#define ST1 ST(1) - -extern int __op_param1, __op_param2, __op_param3; -#define PARAM1 ((long)(&__op_param1)) -#define PARAM2 ((long)(&__op_param2)) -#define PARAM3 ((long)(&__op_param3)) - -#include "cpu-i386.h" - -typedef struct CCTable { - int (*compute_all)(void); /* return all the flags */ - int (*compute_c)(void); /* return the C flag */ -} CCTable; +/* + * i386 micro operations + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "exec-i386.h" /* NOTE: data are not static to force relocation generation by GCC */ -extern CCTable cc_table[]; uint8_t parity_table[256] = { CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, @@ -1878,100 +1794,3 @@ void OPPROTO op_fldcw_A0(void) fesetround(rnd_type); } -/* main execution loop */ -uint8_t code_gen_buffer[65536]; - -#ifdef DEBUG_EXEC -static const char *cc_op_str[] = { - "DYNAMIC", - "EFLAGS", - "MUL", - "ADDB", - "ADDW", - "ADDL", - "ADCB", - "ADCW", - "ADCL", - "SUBB", - "SUBW", - "SUBL", - "SBBB", - "SBBW", - "SBBL", - "LOGICB", - "LOGICW", - "LOGICL", - "INCB", - "INCW", - "INCL", - "DECB", - "DECW", - "DECL", - "SHLB", - "SHLW", - "SHLL", - "SARB", - "SARW", - "SARL", -}; -#endif - -int cpu_x86_exec(CPUX86State *env1) -{ - int saved_T0, saved_T1, saved_A0; - CPUX86State *saved_env; - int code_gen_size, ret; - void (*gen_func)(void); - - /* first we save global registers */ - saved_T0 = T0; - saved_T1 = T1; - saved_A0 = A0; - saved_env = env; - env = env1; - - /* prepare setjmp context for exception handling */ - if (setjmp(env->jmp_env) == 0) { - for(;;) { -#ifdef DEBUG_EXEC - if (loglevel) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags |= (DF & DIRECTION_FLAG); - fprintf(logfile, - "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" - "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n", - env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], - env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], - env->cc_src, env->cc_dst, cc_op_str[env->cc_op], - eflags & DIRECTION_FLAG ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-' - ); -#if 1 - fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n", - (double)ST0, (double)ST1, (double)ST(2), (double)ST(3)); -#endif - } -#endif - cpu_x86_gen_code(code_gen_buffer, sizeof(code_gen_buffer), - &code_gen_size, (uint8_t *)env->pc); - /* execute the generated code */ - gen_func = (void *)code_gen_buffer; - gen_func(); - } - } - ret = env->exception_index; - - /* restore global registers */ - T0 = saved_T0; - T1 = saved_T1; - A0 = saved_A0; - env = saved_env; - return ret; -} diff --git a/tests/Makefile b/tests/Makefile index 5fc813c23..c7d1154c0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,9 +1,11 @@ -CC=gcc +include ../config.mak + CFLAGS=-Wall -O2 -g LDFLAGS= +ifeq ($(ARCH),i386) TESTS=hello test2 sha1 test-i386 -TESTS+=op-i386.o #op-i386.o op-ppc.o op-arm.o op-mips.o op-sparc.o +endif GEMU=../gemu @@ -24,22 +26,6 @@ test: test-i386 $(GEMU) test-i386 > test-i386.out @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi -# dyngen tests -op-i386.o: op.c - gcc $(CFLAGS) -c -o $@ $< - -op-ppc.o: op.c - powerpc-linux-gcc $(CFLAGS) -c -o $@ $< - -op-arm.o: op.c - arm-linux-gcc $(CFLAGS) -c -o $@ $< - -op-mips.o: op.c - mips-linux-gcc $(CFLAGS) -mno-abicalls -c -o $@ $< - -op-sparc.o: op.c - sparc-linux-gcc $(CFLAGS) -mflat -c -o $@ $< - # speed test sha1: sha1.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< @@ -48,6 +34,5 @@ speed: sha1 time ./sha1 time $(GEMU) sha1 -# interpreter test -interp: interp.c interploop.c - $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -o $@ $^ +clean: + rm -f *~ *.o $(TESTS) diff --git a/thunk.h b/thunk.h index 5e5d9dd18..a7338ad76 100644 --- a/thunk.h +++ b/thunk.h @@ -2,7 +2,7 @@ #define THUNK_H #include -#include +#include "config.h" #ifdef HAVE_BYTESWAP_H #include @@ -42,11 +42,6 @@ #endif -#undef WORDS_BIGENDIAN -#if __BYTE_ORDER == __BIG_ENDIAN -#define WORDS_BIGENDIAN -#endif - #ifdef WORDS_BIGENDIAN #define BSWAP_NEEDED #endif diff --git a/translate-i386.c b/translate-i386.c index d13d5d744..ad46e1373 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1,3 +1,22 @@ +/* + * i386 translation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include #include #include @@ -2591,6 +2610,8 @@ CPUX86State *cpu_x86_init(void) CPUX86State *env; int i; + cpu_x86_tblocks_init(); + env = malloc(sizeof(CPUX86State)); if (!env) return NULL; -- cgit v1.2.3 From 55480af80e9ed58b11e9a99da25602468b17ff45 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Mar 2003 11:29:17 +0000 Subject: added bcd test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@26 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 86a070935..b43ca59d9 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -446,6 +446,8 @@ void test_bsx(void) TEST_BSX(bsfl, "", 0x00340128); } +/**********************************************/ + void test_fops(double a, double b) { printf("a=%f b=%f a+b=%f\n", a, b, a + b); @@ -540,6 +542,77 @@ void test_floats(void) test_fbcd(-123451234567890); } +/**********************************************/ + +#define TEST_BCD(op, op0, cc_in, cc_mask)\ +{\ + int res, flags;\ + res = op0;\ + flags = cc_in;\ + asm ("push %3\n\t"\ + "popf\n\t"\ + #op "\n\t"\ + "pushf\n\t"\ + "popl %1\n\t"\ + : "=a" (res), "=g" (flags)\ + : "0" (res), "1" (flags));\ + printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\ + #op, op0, res, cc_in, flags & cc_mask);\ +} + +void test_bcd(void) +{ + TEST_BCD(daa, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(daa, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + + TEST_BCD(das, 0x12340503, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340506, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340507, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340559, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340560, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x1234059f, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x123405a0, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340503, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340506, 0, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340503, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340506, CC_C, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340503, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + TEST_BCD(das, 0x12340506, CC_C | CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_A)); + + TEST_BCD(aaa, 0x12340205, CC_A, (CC_C | CC_A)); + TEST_BCD(aaa, 0x12340306, CC_A, (CC_C | CC_A)); + TEST_BCD(aaa, 0x1234040a, CC_A, (CC_C | CC_A)); + TEST_BCD(aaa, 0x123405fa, CC_A, (CC_C | CC_A)); + TEST_BCD(aaa, 0x12340205, 0, (CC_C | CC_A)); + TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A)); + TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A)); + TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A)); + + TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A)); + TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A)); + TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A)); + TEST_BCD(aas, 0x123405fa, CC_A, (CC_C | CC_A)); + TEST_BCD(aas, 0x12340205, 0, (CC_C | CC_A)); + TEST_BCD(aas, 0x12340306, 0, (CC_C | CC_A)); + TEST_BCD(aas, 0x1234040a, 0, (CC_C | CC_A)); + TEST_BCD(aas, 0x123405fa, 0, (CC_C | CC_A)); + + TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); + TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); +} + + static void *call_end __init_call = NULL; int main(int argc, char **argv) @@ -557,5 +630,6 @@ int main(int argc, char **argv) test_jcc(); test_lea(); test_floats(); + test_bcd(); return 0; } -- cgit v1.2.3 From 27362c82e9df7770554943ceda36ec4e5638c49d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Mar 2003 11:29:31 +0000 Subject: added pusha/popa/rdtsc/bcd ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@27 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 3 + cpu-i386.h | 2 +- linux-user/main.c | 2 +- op-i386.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ translate-i386.c | 79 ++++++++++++++++-- 5 files changed, 314 insertions(+), 9 deletions(-) diff --git a/TODO b/TODO index 3b04b7dce..caeb64d56 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,7 @@ +- daa/das - optimize translated cache chaining (DLL PLT like system) +- segment ops (minimal LDT/GDT support for wine) +- improved 16 bit support - optimize inverse flags propagation (easy by generating intermediate micro operation array). - signals diff --git a/cpu-i386.h b/cpu-i386.h index a6464efca..40542f283 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -114,7 +114,7 @@ enum { }; #ifdef __i386__ -//#define USE_X86LDOUBLE +#define USE_X86LDOUBLE #endif #ifdef USE_X86LDOUBLE diff --git a/linux-user/main.c b/linux-user/main.c index 9927b8256..6aefe3afb 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -87,7 +87,7 @@ int cpu_x86_inl(int addr) void usage(void) { - printf("gemu version" GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" "usage: gemu [-d] program [arguments...]\n" "Linux x86 emulator\n" ); diff --git a/op-i386.c b/op-i386.c index 6bd9de015..6d695ff90 100644 --- a/op-i386.c +++ b/op-i386.c @@ -628,6 +628,236 @@ void op_addl_ESP_im(void) ESP += PARAM1; } +void op_pushal(void) +{ + uint8_t *sp; + sp = (void *)(ESP - 32); + stl(sp, EDI); + stl(sp + 4, ESI); + stl(sp + 8, EBP); + stl(sp + 12, ESP); + stl(sp + 16, EBX); + stl(sp + 20, EDX); + stl(sp + 24, ECX); + stl(sp + 28, EAX); + ESP = (unsigned long)sp; +} + +void op_pushaw(void) +{ + uint8_t *sp; + sp = (void *)(ESP - 16); + stw(sp, EDI); + stw(sp + 2, ESI); + stw(sp + 4, EBP); + stw(sp + 6, ESP); + stw(sp + 8, EBX); + stw(sp + 10, EDX); + stw(sp + 12, ECX); + stw(sp + 14, EAX); + ESP = (unsigned long)sp; +} + +void op_popal(void) +{ + uint8_t *sp; + sp = (void *)ESP; + EDI = ldl(sp); + ESI = ldl(sp + 4); + EBP = ldl(sp + 8); + EBX = ldl(sp + 16); + EDX = ldl(sp + 20); + ECX = ldl(sp + 24); + EAX = ldl(sp + 28); + ESP = (unsigned long)sp + 32; +} + +void op_popaw(void) +{ + uint8_t *sp; + sp = (void *)ESP; + EDI = ldl(sp); + ESI = ldl(sp + 2); + EBP = ldl(sp + 4); + EBX = ldl(sp + 8); + EDX = ldl(sp + 10); + ECX = ldl(sp + 12); + EAX = ldl(sp + 14); + ESP = (unsigned long)sp + 16; +} + +void op_enterl(void) +{ + unsigned int bp, frame_temp, level; + uint8_t *sp; + + sp = (void *)ESP; + bp = EBP; + sp -= 4; + stl(sp, bp); + frame_temp = (unsigned int)sp; + level = PARAM2; + if (level) { + while (level--) { + bp -= 4; + sp -= 4; + stl(sp, bp); + } + sp -= 4; + stl(sp, frame_temp); + } + EBP = frame_temp; + sp -= PARAM1; + ESP = (int)sp; +} + +/* rdtsc */ +#ifndef __i386__ +uint64_t emu_time; +#endif +void op_rdtsc(void) +{ + uint64_t val; +#ifdef __i386__ + asm("rdtsc" : "=A" (val)); +#else + /* better than nothing: the time increases */ + val = emu_time++; +#endif + EAX = val; + EDX = val >> 32; +} + +/* bcd */ + +/* XXX: exception */ +void OPPROTO op_aam(void) +{ + int base = PARAM1; + int al, ah; + al = EAX & 0xff; + ah = al / base; + al = al % base; + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_DST = al; +} + +void OPPROTO op_aad(void) +{ + int base = PARAM1; + int al, ah; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + al = ((ah * base) + al) & 0xff; + EAX = (EAX & ~0xffff) | al; + CC_DST = al; +} + +void OPPROTO op_aaa(void) +{ + int icarry; + int al, ah, af; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + af = eflags & CC_A; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + + icarry = (al > 0xf9); + if (((al & 0x0f) > 9 ) || af) { + al = (al + 6) & 0x0f; + ah = (ah + 1 + icarry) & 0xff; + eflags |= CC_C | CC_A; + } else { + eflags &= ~(CC_C | CC_A); + al &= 0x0f; + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; +} + +void OPPROTO op_aas(void) +{ + int icarry; + int al, ah, af; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + af = eflags & CC_A; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + + icarry = (al < 6); + if (((al & 0x0f) > 9 ) || af) { + al = (al - 6) & 0x0f; + ah = (ah - 1 - icarry) & 0xff; + eflags |= CC_C | CC_A; + } else { + eflags &= ~(CC_C | CC_A); + al &= 0x0f; + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; +} + +void OPPROTO op_daa(void) +{ + int al, af, cf; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + cf = eflags & CC_C; + af = eflags & CC_A; + al = EAX & 0xff; + + eflags = 0; + if (((al & 0x0f) > 9 ) || af) { + al = (al + 6) & 0xff; + eflags |= CC_A; + } + if ((al > 0x9f) || cf) { + al = (al + 0x60) & 0xff; + eflags |= CC_C; + } + EAX = (EAX & ~0xff) | al; + /* well, speed is not an issue here, so we compute the flags by hand */ + eflags |= (al == 0) << 6; /* zf */ + eflags |= parity_table[al]; /* pf */ + eflags |= (al & 0x80); /* sf */ + CC_SRC = eflags; +} + +void OPPROTO op_das(void) +{ + int al, al1, af, cf; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + cf = eflags & CC_C; + af = eflags & CC_A; + al = EAX & 0xff; + + eflags = 0; + al1 = al; + if (((al & 0x0f) > 9 ) || af) { + eflags |= CC_A; + if (al < 6 || cf) + eflags |= CC_C; + al = (al - 6) & 0xff; + } + if ((al1 > 0x99) || cf) { + al = (al - 0x60) & 0xff; + eflags |= CC_C; + } + EAX = (EAX & ~0xff) | al; + /* well, speed is not an issue here, so we compute the flags by hand */ + eflags |= (al == 0) << 6; /* zf */ + eflags |= parity_table[al]; /* pf */ + eflags |= (al & 0x80); /* sf */ + CC_SRC = eflags; +} + /* flags handling */ /* slow jumps cases (compute x86 flags) */ @@ -836,6 +1066,13 @@ void OPPROTO op_cmc(void) CC_SRC = eflags; } +void OPPROTO op_salc(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + EAX = (EAX & ~0xff) | ((-cf) & 0xff); +} + static int compute_all_eflags(void) { return CC_SRC; diff --git a/translate-i386.c b/translate-i386.c index ad46e1373..0dbaa99d9 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1511,6 +1511,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_popl_T0(); gen_op_mov_reg_T0[OT_LONG][b & 7](); break; + case 0x60: /* pusha */ + if (s->dflag) + gen_op_pushal(); + else + gen_op_pushaw(); + break; + case 0x61: /* popa */ + if (s->dflag) + gen_op_popal(); + else + gen_op_popaw(); + break; case 0x68: /* push Iv */ case 0x6a: ot = dflag ? OT_LONG : OT_WORD; @@ -1527,6 +1539,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_popl_T0(); gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; + case 0xc8: /* enter */ + { + int level; + val = lduw(s->pc); + s->pc += 2; + level = ldub(s->pc++); + level &= 0x1f; + gen_op_enterl(val, level); + } + break; case 0xc9: /* leave */ gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); gen_op_mov_reg_T0[OT_LONG][R_ESP](); @@ -2485,6 +2507,42 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) s->cc_op = CC_OP_LOGICB + ot; break; /************************/ + /* bcd */ + case 0x27: /* daa */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_daa(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x2f: /* das */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_das(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x37: /* aaa */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_aaa(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x3f: /* aas */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_aas(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xd4: /* aam */ + val = ldub(s->pc++); + gen_op_aam(val); + s->cc_op = CC_OP_LOGICB; + break; + case 0xd5: /* aad */ + val = ldub(s->pc++); + gen_op_aad(val); + s->cc_op = CC_OP_LOGICB; + break; + /************************/ /* misc */ case 0x90: /* nop */ break; @@ -2505,19 +2563,26 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) *is_jmp_ptr = 1; break; case 0x1c8 ... 0x1cf: /* bswap reg */ - reg = b & 7; - gen_op_mov_TN_reg[OT_LONG][0][reg](); - gen_op_bswapl_T0(); - gen_op_mov_reg_T0[OT_LONG][reg](); - break; - + reg = b & 7; + gen_op_mov_TN_reg[OT_LONG][0][reg](); + gen_op_bswapl_T0(); + gen_op_mov_reg_T0[OT_LONG][reg](); + break; + case 0xd6: /* salc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_salc(); + break; + case 0x1a2: /* rdtsc */ + gen_op_rdtsc(); + break; #if 0 case 0x1a2: /* cpuid */ gen_insn0(OP_ASM); break; #endif default: - error("unknown opcode %x", b); + error("unknown opcode 0x%x", b); return -1; } return (long)s->pc; -- cgit v1.2.3 From 6dbad63eef5947c6c8750e44f408138779b6d0bb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Mar 2003 18:05:05 +0000 Subject: added minimal segment support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@28 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 3 +- cpu-i386.h | 40 ++++++-- exec-i386.c | 32 +++++- exec-i386.h | 3 + linux-user/main.c | 58 +++++++---- linux-user/qemu.h | 2 +- linux-user/syscall.c | 126 ++++++++++++++++++++++- linux-user/syscall_types.h | 1 - op-i386.c | 54 ++++++++++ syscall-i386.h | 11 ++ tests/test-i386.c | 79 ++++++++++++++- translate-i386.c | 244 +++++++++++++++++++++++++++++++++------------ 12 files changed, 550 insertions(+), 103 deletions(-) diff --git a/TODO b/TODO index caeb64d56..5602097b8 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ -- daa/das -- optimize translated cache chaining (DLL PLT like system) - segment ops (minimal LDT/GDT support for wine) +- optimize translated cache chaining (DLL PLT like system) - improved 16 bit support - optimize inverse flags propagation (easy by generating intermediate micro operation array). diff --git a/cpu-i386.h b/cpu-i386.h index 40542f283..fc68a91d9 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -123,6 +123,20 @@ typedef long double CPU86_LDouble; typedef double CPU86_LDouble; #endif +typedef struct SegmentCache { + uint8_t *base; + unsigned long limit; + uint8_t seg_32bit; +} SegmentCache; + +typedef struct SegmentDescriptorTable { + uint8_t *base; + unsigned long limit; + /* this is the returned base when reading the register, just to + avoid that the emulated program modifies it */ + unsigned long emu_base; +} SegmentDescriptorTable; + typedef struct CPUX86State { /* standard registers */ uint32_t regs[8]; @@ -135,9 +149,6 @@ typedef struct CPUX86State { uint32_t cc_op; int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ - /* segments */ - uint8_t *segs_base[6]; - /* FPU state */ unsigned int fpstt; /* top of stack index */ unsigned int fpus; @@ -145,12 +156,19 @@ typedef struct CPUX86State { uint8_t fptags[8]; /* 0 = valid, 1 = empty */ CPU86_LDouble fpregs[8]; - /* segments */ - uint32_t segs[6]; - /* emulator internal variables */ CPU86_LDouble ft0; + /* segments */ + uint32_t segs[6]; /* selector values */ + SegmentCache seg_cache[6]; /* info taken from LDT/GDT */ + SegmentDescriptorTable gdt; + SegmentDescriptorTable ldt; + SegmentDescriptorTable idt; + + /* various CPU modes */ + int vm86; + /* exception handling */ jmp_buf jmp_env; int exception_index; @@ -241,9 +259,17 @@ CPUX86State *cpu_x86_init(void); int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); +/* needed to load some predefinied segment registers */ +void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); + /* internal functions */ + +#define GEN_FLAG_CODE32_SHIFT 0 +#define GEN_FLAG_ADDSEG_SHIFT 1 +#define GEN_FLAG_ST_SHIFT 2 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, - int *gen_code_size_ptr, uint8_t *pc_start); + int *gen_code_size_ptr, uint8_t *pc_start, + int flags); void cpu_x86_tblocks_init(void); #endif /* CPU_I386_H */ diff --git a/exec-i386.c b/exec-i386.c index c06768509..8144add7b 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -36,8 +36,10 @@ #define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64) #define CODE_GEN_HASH_BITS 15 #define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) + typedef struct TranslationBlock { unsigned long pc; /* simulated PC corresponding to this block */ + unsigned int flags; /* flags defining in which context the code was generated */ uint8_t *tc_ptr; /* pointer to the translated code */ struct TranslationBlock *hash_next; /* next matching block */ } TranslationBlock; @@ -137,7 +139,8 @@ static void tb_flush(void) /* find a translation block in the translation cache. If not found, allocate a new one */ -static inline TranslationBlock *tb_find_and_alloc(unsigned long pc) +static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, + unsigned int flags) { TranslationBlock **ptb, *tb; unsigned int h; @@ -148,7 +151,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc) tb = *ptb; if (!tb) break; - if (tb->pc == pc) + if (tb->pc == pc && tb->flags == flags) return tb; ptb = &tb->hash_next; } @@ -158,6 +161,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc) tb = &tbs[nb_tbs++]; *ptb = tb; tb->pc = pc; + tb->flags = flags; tb->tc_ptr = NULL; tb->hash_next = NULL; return tb; @@ -171,7 +175,8 @@ int cpu_x86_exec(CPUX86State *env1) void (*gen_func)(void); TranslationBlock *tb; uint8_t *tc_ptr; - + unsigned int flags; + /* first we save global registers */ saved_T0 = T0; saved_T1 = T1; @@ -187,13 +192,20 @@ int cpu_x86_exec(CPUX86State *env1) cpu_x86_dump_state(); } #endif - tb = tb_find_and_alloc((unsigned long)env->pc); + /* we compute the CPU state. We assume it will not + change during the whole generated block. */ + flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; + flags |= (((unsigned long)env->seg_cache[R_DS].base | + (unsigned long)env->seg_cache[R_ES].base | + (unsigned long)env->seg_cache[R_SS].base) != 0) << + GEN_FLAG_ADDSEG_SHIFT; + tb = tb_find_and_alloc((unsigned long)env->pc, flags); tc_ptr = tb->tc_ptr; if (!tb->tc_ptr) { /* if no translated code available, then translate it now */ tc_ptr = code_gen_ptr; cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, - &code_gen_size, (uint8_t *)env->pc); + &code_gen_size, (uint8_t *)env->pc, flags); tb->tc_ptr = tc_ptr; code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); } @@ -211,3 +223,13 @@ int cpu_x86_exec(CPUX86State *env1) env = saved_env; return ret; } + +void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + load_seg(seg_reg, selector); + env = saved_env; +} diff --git a/exec-i386.h b/exec-i386.h index 62f681bc1..0e0cae275 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -27,6 +27,7 @@ typedef struct FILE FILE; extern FILE *logfile; extern int loglevel; extern int fprintf(FILE *, const char *, ...); +extern int printf(const char *, ...); #ifdef __i386__ register unsigned int T0 asm("ebx"); @@ -103,3 +104,5 @@ typedef struct CCTable { } CCTable; extern CCTable cc_table[]; + +void load_seg(int seg_reg, int selector); diff --git a/linux-user/main.c b/linux-user/main.c index 6aefe3afb..b59c85d9c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1,5 +1,5 @@ /* - * emu main + * gemu main * * Copyright (c) 2003 Fabrice Bellard * @@ -80,10 +80,28 @@ int cpu_x86_inl(int addr) return 0; } +/* default linux values for the selectors */ +#define __USER_CS (0x23) +#define __USER_DS (0x2B) -/* XXX: currently we use LDT entries */ -#define __USER_CS (0x23|4) -#define __USER_DS (0x2B|4) +void write_dt(void *ptr, unsigned long addr, unsigned long limit, + int seg32_bit) +{ + unsigned int e1, e2, limit_in_pages; + limit_in_pages = 0; + if (limit > 0xffff) { + limit = limit >> 12; + limit_in_pages = 1; + } + e1 = (addr << 16) | (limit & 0xffff); + e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); + e2 |= limit_in_pages << 23; /* byte granularity */ + e2 |= seg32_bit << 22; /* 32 bit segment */ + stl((uint8_t *)ptr, e1); + stl((uint8_t *)ptr + 4, e2); +} + +uint64_t gdt_table[6]; void usage(void) { @@ -94,6 +112,8 @@ void usage(void) exit(1); } + + int main(int argc, char **argv) { const char *filename; @@ -149,6 +169,7 @@ int main(int argc, char **argv) env = cpu_x86_init(); + /* linux register setup */ env->regs[R_EAX] = regs->eax; env->regs[R_EBX] = regs->ebx; env->regs[R_ECX] = regs->ecx; @@ -157,23 +178,19 @@ int main(int argc, char **argv) env->regs[R_EDI] = regs->edi; env->regs[R_EBP] = regs->ebp; env->regs[R_ESP] = regs->esp; - env->segs[R_CS] = __USER_CS; - env->segs[R_DS] = __USER_DS; - env->segs[R_ES] = __USER_DS; - env->segs[R_SS] = __USER_DS; - env->segs[R_FS] = __USER_DS; - env->segs[R_GS] = __USER_DS; env->pc = regs->eip; -#if 0 - LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; - LDT[__USER_CS >> 3].dwSelLimit = 0xfffff; - LDT[__USER_CS >> 3].lpSelBase = NULL; - - LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; - LDT[__USER_DS >> 3].dwSelLimit = 0xfffff; - LDT[__USER_DS >> 3].lpSelBase = NULL; -#endif + /* linux segment setup */ + env->gdt.base = (void *)gdt_table; + env->gdt.limit = sizeof(gdt_table) - 1; + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1); + write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1); + cpu_x86_load_seg(env, R_CS, __USER_CS); + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_FS, __USER_DS); + cpu_x86_load_seg(env, R_GS, __USER_DS); for(;;) { int err; @@ -186,7 +203,8 @@ int main(int argc, char **argv) if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ env->pc += 2; - env->regs[R_EAX] = do_syscall(env->regs[R_EAX], + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 0b9de6b3f..4f09e6fde 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -48,7 +48,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, void target_set_brk(char *new_brk); void syscall_init(void); -long do_syscall(int num, long arg1, long arg2, long arg3, +long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ac40cf19e..9ed8daa0f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -69,6 +69,7 @@ struct dirent { #include "syscall_defs.h" #ifdef TARGET_I386 +#include "cpu-i386.h" #include "syscall-i386.h" #endif @@ -607,6 +608,124 @@ StructEntry struct_termios_def = { .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, }; +#ifdef TARGET_I386 + +/* NOTE: there is really one LDT for all the threads */ +uint8_t *ldt_table; + +static int read_ldt(void *ptr, unsigned long bytecount) +{ + int size; + + if (!ldt_table) + return 0; + size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE; + if (size > bytecount) + size = bytecount; + memcpy(ptr, ldt_table, size); + return size; +} + +/* XXX: add locking support */ +static int write_ldt(CPUX86State *env, + void *ptr, unsigned long bytecount, int oldmode) +{ + struct target_modify_ldt_ldt_s ldt_info; + int seg_32bit, contents, read_exec_only, limit_in_pages; + int seg_not_present, useable; + uint32_t *lp, entry_1, entry_2; + + if (bytecount != sizeof(ldt_info)) + return -EINVAL; + memcpy(&ldt_info, ptr, sizeof(ldt_info)); + tswap32s(&ldt_info.entry_number); + tswapls((long *)&ldt_info.base_addr); + tswap32s(&ldt_info.limit); + tswap32s(&ldt_info.flags); + + if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) + return -EINVAL; + seg_32bit = ldt_info.flags & 1; + contents = (ldt_info.flags >> 1) & 3; + read_exec_only = (ldt_info.flags >> 3) & 1; + limit_in_pages = (ldt_info.flags >> 4) & 1; + seg_not_present = (ldt_info.flags >> 5) & 1; + useable = (ldt_info.flags >> 6) & 1; + + if (contents == 3) { + if (oldmode) + return -EINVAL; + if (seg_not_present == 0) + return -EINVAL; + } + /* allocate the LDT */ + if (!ldt_table) { + ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); + if (!ldt_table) + return -ENOMEM; + memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); + env->ldt.base = ldt_table; + env->ldt.limit = 0xffff; + } + + /* NOTE: same code as Linux kernel */ + /* Allow LDTs to be cleared by the user. */ + if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { + if (oldmode || + (contents == 0 && + read_exec_only == 1 && + seg_32bit == 0 && + limit_in_pages == 0 && + seg_not_present == 1 && + useable == 0 )) { + entry_1 = 0; + entry_2 = 0; + goto install; + } + } + + entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | + (ldt_info.limit & 0x0ffff); + entry_2 = (ldt_info.base_addr & 0xff000000) | + ((ldt_info.base_addr & 0x00ff0000) >> 16) | + (ldt_info.limit & 0xf0000) | + ((read_exec_only ^ 1) << 9) | + (contents << 10) | + ((seg_not_present ^ 1) << 15) | + (seg_32bit << 22) | + (limit_in_pages << 23) | + 0x7000; + if (!oldmode) + entry_2 |= (useable << 20); + + /* Install the new entry ... */ +install: + lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3)); + lp[0] = tswap32(entry_1); + lp[1] = tswap32(entry_2); + return 0; +} + +/* specific and weird i386 syscalls */ +int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount) +{ + int ret = -ENOSYS; + + switch (func) { + case 0: + ret = read_ldt(ptr, bytecount); + break; + case 1: + ret = write_ldt(env, ptr, bytecount, 1); + break; + case 0x11: + ret = write_ldt(env, ptr, bytecount, 0); + break; + } + return ret; +} +#endif + void syscall_init(void) { #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); @@ -616,7 +735,7 @@ void syscall_init(void) #undef STRUCT_SPECIAL } -long do_syscall(int num, long arg1, long arg2, long arg3, +long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { long ret; @@ -1095,8 +1214,11 @@ long do_syscall(int num, long arg1, long arg2, long arg3, /* no need to transcode because we use the linux syscall */ ret = get_errno(sys_uname((struct new_utsname *)arg1)); break; +#ifdef TARGET_I386 case TARGET_NR_modify_ldt: - goto unimplemented; + ret = get_errno(gemu_modify_ldt(cpu_env, arg1, (void *)arg2, arg3)); + break; +#endif case TARGET_NR_adjtimex: goto unimplemented; case TARGET_NR_mprotect: diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 63852d3af..540114430 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -61,4 +61,3 @@ STRUCT(cdrom_read_audio, STRUCT(hd_geometry, TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG) - diff --git a/op-i386.c b/op-i386.c index 6d695ff90..503fb88ed 100644 --- a/op-i386.c +++ b/op-i386.c @@ -858,6 +858,60 @@ void OPPROTO op_das(void) CC_SRC = eflags; } +/* segment handling */ + +void load_seg(int seg_reg, int selector) +{ + SegmentCache *sc; + SegmentDescriptorTable *dt; + int index; + uint32_t e1, e2; + uint8_t *ptr; + + env->segs[seg_reg] = selector; + sc = &env->seg_cache[seg_reg]; + if (env->vm86) { + sc->base = (void *)(selector << 4); + sc->limit = 0xffff; + sc->seg_32bit = 0; + } else { + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + raise_exception(EXCP0D_GPF); + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); + sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & (1 << 23)) + sc->limit = (sc->limit << 12) | 0xfff; + sc->seg_32bit = (e2 >> 22) & 1; +#if 0 + fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", + selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); +#endif + } +} + +void OPPROTO op_movl_seg_T0(void) +{ + load_seg(PARAM1, T0 & 0xffff); +} + +void OPPROTO op_movl_T0_seg(void) +{ + T0 = env->segs[PARAM1]; +} + +void OPPROTO op_addl_A0_seg(void) +{ + A0 += *(unsigned long *)((char *)env + PARAM1); +} + /* flags handling */ /* slow jumps cases (compute x86 flags) */ diff --git a/syscall-i386.h b/syscall-i386.h index 312edc684..a54064a05 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -758,3 +758,14 @@ struct target_termios { #define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f #define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f #define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff + +#define TARGET_LDT_ENTRIES 8192 +#define TARGET_LDT_ENTRY_SIZE 8 + +struct target_modify_ldt_ldt_s { + unsigned int entry_number; + target_ulong base_addr; + unsigned int limit; + unsigned int flags; +}; + diff --git a/tests/test-i386.c b/tests/test-i386.c index b43ca59d9..95ec5d150 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1,5 +1,6 @@ #include #include +#include #include #define xglue(x, y) x ## y @@ -612,6 +613,81 @@ void test_bcd(void) TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); } +/**********************************************/ +/* segmentation tests */ + +#include +#include + +_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) + +uint8_t seg_data1[4096]; +uint8_t seg_data2[4096]; + +#define MK_SEL(n) (((n) << 3) | 4) + +/* NOTE: we use Linux modify_ldt syscall */ +void test_segs(void) +{ + struct modify_ldt_ldt_s ldt; + long long ldt_table[3]; + int i, res, res2; + char tmp; + + ldt.entry_number = 1; + ldt.base_addr = (unsigned long)&seg_data1; + ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; + ldt.seg_32bit = 1; + ldt.contents = MODIFY_LDT_CONTENTS_DATA; + ldt.read_exec_only = 0; + ldt.limit_in_pages = 1; + ldt.seg_not_present = 0; + ldt.useable = 1; + modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ + + ldt.entry_number = 2; + ldt.base_addr = (unsigned long)&seg_data2; + ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12; + ldt.seg_32bit = 1; + ldt.contents = MODIFY_LDT_CONTENTS_DATA; + ldt.read_exec_only = 0; + ldt.limit_in_pages = 1; + ldt.seg_not_present = 0; + ldt.useable = 1; + modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ + + modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */ + for(i=0;i<3;i++) + printf("%d: %016Lx\n", i, ldt_table[i]); + + /* do some tests with fs or gs */ + asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); + asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2))); + + seg_data1[1] = 0xaa; + seg_data2[1] = 0x55; + + asm volatile ("fs movzbl 0x1, %0" : "=r" (res)); + printf("FS[1] = %02x\n", res); + + asm volatile ("gs movzbl 0x1, %0" : "=r" (res)); + printf("GS[1] = %02x\n", res); + + /* tests with ds/ss (implicit segment case) */ + tmp = 0xa5; + asm volatile ("pushl %%ebp\n\t" + "pushl %%ds\n\t" + "movl %2, %%ds\n\t" + "movl %3, %%ebp\n\t" + "movzbl 0x1, %0\n\t" + "movzbl (%%ebp), %1\n\t" + "popl %%ds\n\t" + "popl %%ebp\n\t" + : "=r" (res), "=r" (res2) + : "r" (MK_SEL(1)), "r" (&tmp)); + printf("DS[1] = %02x\n", res); + printf("SS[tmp] = %02x\n", res2); +} static void *call_end __init_call = NULL; @@ -628,8 +704,9 @@ int main(int argc, char **argv) test_bsx(); test_mul(); test_jcc(); - test_lea(); test_floats(); test_bcd(); + test_lea(); + test_segs(); return 0; } diff --git a/translate-i386.c b/translate-i386.c index 0dbaa99d9..5146242c6 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -34,6 +34,10 @@ #include "dis-asm.h" #endif +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif + static uint8_t *gen_code_ptr; int __op_param1, __op_param2, __op_param3; @@ -71,8 +75,13 @@ typedef struct DisasContext { int prefix; int aflag, dflag; uint8_t *pc; /* current pc */ - int cc_op; /* current CC operation */ - int f_st; + int is_jmp; /* 1 = means jump (stop translation), 2 means CPU + static state change (stop translation) */ + /* current block context */ + int code32; /* 32 bit code segment */ + int cc_op; /* current CC operation */ + int addseg; /* non zero if either DS/ES/SS have a non zero base */ + int f_st; /* currently unused */ } DisasContext; /* i386 arith/logic operations */ @@ -763,12 +772,32 @@ static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) { int havesib; - int havebase; int base, disp; - int index = 0; - int scale = 0; - int reg1, reg2, opreg; - int mod, rm, code; + int index; + int scale; + int opreg; + int mod, rm, code, override, must_add_seg; + + /* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */ + /* XXX: fix lea case */ + override = -1; + must_add_seg = s->addseg; + if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | + PREFIX_ES | PREFIX_FS | PREFIX_GS)) { + if (s->prefix & PREFIX_ES) + override = R_ES; + else if (s->prefix & PREFIX_CS) + override = R_CS; + else if (s->prefix & PREFIX_SS) + override = R_SS; + else if (s->prefix & PREFIX_DS) + override = R_DS; + else if (s->prefix & PREFIX_FS) + override = R_FS; + else + override = R_GS; + must_add_seg = 1; + } mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -776,8 +805,9 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ if (s->aflag) { havesib = 0; - havebase = 1; base = rm; + index = 0; + scale = 0; if (base == 4) { havesib = 1; @@ -790,7 +820,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ switch (mod) { case 0: if (base == 5) { - havebase = 0; + base = -1; disp = ldl(s->pc); s->pc += 4; } else { @@ -806,40 +836,25 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ s->pc += 4; break; } - - reg1 = OR_ZERO; - reg2 = OR_ZERO; - - if (havebase || (havesib && (index != 4 || scale != 0))) { - if (havebase) - reg1 = OR_EAX + base; - if (havesib && index != 4) { - if (havebase) - reg2 = index + OR_EAX; - else - reg1 = index + OR_EAX; - } - } - /* XXX: disp only ? */ - if (reg2 == OR_ZERO) { - /* op: disp + (reg1 << scale) */ - if (reg1 == OR_ZERO) { - gen_op_movl_A0_im(disp); - } else if (scale == 0 && disp == 0) { - gen_op_movl_A0_reg[reg1](); - } else { - gen_op_movl_A0_im(disp); - gen_op_addl_A0_reg_sN[scale][reg1](); - } + + if (base >= 0) { + gen_op_movl_A0_reg[base](); + if (disp != 0) + gen_op_addl_A0_im(disp); } else { - /* op: disp + reg1 + (reg2 << scale) */ - if (disp != 0) { - gen_op_movl_A0_im(disp); - gen_op_addl_A0_reg_sN[0][reg1](); - } else { - gen_op_movl_A0_reg[reg1](); + gen_op_movl_A0_im(disp); + } + if (havesib && (index != 4 || scale != 0)) { + gen_op_addl_A0_reg_sN[scale][index](); + } + if (must_add_seg) { + if (override < 0) { + if (base == R_EBP || base == R_ESP) + override = R_SS; + else + override = R_DS; } - gen_op_addl_A0_reg_sN[scale][reg2](); + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); } } else { switch (mod) { @@ -848,6 +863,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ disp = lduw(s->pc); s->pc += 2; gen_op_movl_A0_im(disp); + rm = 0; /* avoid SS override */ goto no_rm; } else { disp = 0; @@ -896,8 +912,18 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ if (disp != 0) gen_op_addl_A0_im(disp); gen_op_andl_A0_ffff(); - no_rm: ; + no_rm: + if (must_add_seg) { + if (override < 0) { + if (rm == 2 || rm == 3 || rm == 6) + override = R_SS; + else + override = R_DS; + } + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + } } + opreg = OR_A0; disp = 0; *reg_ptr = opreg; @@ -1082,10 +1108,19 @@ static void gen_setcc(DisasContext *s, int b) } } +/* move T0 to seg_reg and compute if the CPU state may change */ +void gen_movl_seg_T0(DisasContext *s, int seg_reg) +{ + gen_op_movl_seg_T0(seg_reg); + if (!s->addseg && seg_reg < R_FS) + s->is_jmp = 2; /* abort translation because the register may + have a non zero base */ +} + /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr is set to true if the instruction sets the PC (last instruction of a basic block) */ -long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) +long disas_insn(DisasContext *s, uint8_t *pc_start) { int b, prefixes, aflag, dflag; int shift, ot; @@ -1093,8 +1128,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) s->pc = pc_start; prefixes = 0; - aflag = 1; - dflag = 1; + aflag = s->code32; + dflag = s->code32; // cur_pc = s->pc; /* for insn generation */ next_byte: b = ldub(s->pc); @@ -1416,11 +1451,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_movl_T1_im((long)s->pc); gen_op_pushl_T1(); gen_op_jmp_T0(); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 4: /* jmp Ev */ gen_op_jmp_T0(); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 6: /* push Ev */ gen_op_pushl_T0(); @@ -1555,6 +1590,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_popl_T0(); gen_op_mov_reg_T0[OT_LONG][R_EBP](); break; + case 0x06: /* push es */ + case 0x0e: /* push cs */ + case 0x16: /* push ss */ + case 0x1e: /* push ds */ + gen_op_movl_T0_seg(b >> 3); + gen_op_pushl_T0(); + break; + case 0x1a0: /* push fs */ + case 0x1a8: /* push gs */ + gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS); + gen_op_pushl_T0(); + break; + case 0x07: /* pop es */ + case 0x17: /* pop ss */ + case 0x1f: /* pop ds */ + gen_op_popl_T0(); + gen_movl_seg_T0(s, b >> 3); + break; + case 0x1a1: /* pop fs */ + case 0x1a9: /* pop gs */ + gen_op_popl_T0(); + gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS); + break; + /**************************/ /* mov */ case 0x88: @@ -1598,6 +1657,24 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_reg_T0[ot][reg](); break; + case 0x8e: /* mov seg, Gv */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + if (reg >= 6) + goto illegal_op; + gen_movl_seg_T0(s, reg); + break; + case 0x8c: /* mov Gv, seg */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + if (reg >= 6) + goto illegal_op; + gen_op_movl_T0_seg(reg); + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; case 0x1b6: /* movzbS Gv, Eb */ case 0x1b7: /* movzwS Gv, Eb */ @@ -1648,8 +1725,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); reg = (modrm >> 3) & 7; - + /* we must ensure that no segment is added */ + s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS | + PREFIX_ES | PREFIX_FS | PREFIX_GS); + val = s->addseg; + s->addseg = 0; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + s->addseg = val; gen_op_mov_reg_A0[ot - OT_WORD][reg](); break; @@ -1711,6 +1793,35 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_st_T0_A0[ot](); gen_op_mov_reg_T1[ot][reg](); break; + case 0xc4: /* les Gv */ + op = R_ES; + goto do_lxx; + case 0xc5: /* lds Gv */ + op = R_DS; + goto do_lxx; + case 0x1b2: /* lss Gv */ + op = R_SS; + goto do_lxx; + case 0x1b4: /* lfs Gv */ + op = R_FS; + goto do_lxx; + case 0x1b5: /* lgs Gv */ + op = R_GS; + do_lxx: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + gen_op_ld_T1_A0[ot](); + op_addl_A0_im(1 << (ot - OT_WORD + 1)); + /* load the segment first to handle exceptions properly */ + gen_op_lduw_T0_A0(); + gen_movl_seg_T0(s, op); + /* then put the data */ + gen_op_mov_reg_T1[ot][reg](); + break; /************************/ /* shifts */ @@ -2327,12 +2438,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_popl_T0(); gen_op_addl_ESP_im(val); gen_op_jmp_T0(); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0xc3: /* ret */ gen_op_popl_T0(); gen_op_jmp_T0(); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0xe8: /* call */ val = insn_get(s, OT_LONG); @@ -2340,19 +2451,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_movl_T1_im((long)s->pc); gen_op_pushl_T1(); gen_op_jmp_im(val); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0xe9: /* jmp */ val = insn_get(s, OT_LONG); val += (long)s->pc; gen_op_jmp_im(val); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0xeb: /* jmp Jb */ val = (int8_t)insn_get(s, OT_BYTE); val += (long)s->pc; gen_op_jmp_im(val); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0x70 ... 0x7f: /* jcc Jb */ val = (int8_t)insn_get(s, OT_BYTE); @@ -2367,7 +2478,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) val += (long)s->pc; /* XXX: fix 16 bit wrap */ do_jcc: gen_jcc(s, b, val); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0x190 ... 0x19f: @@ -2548,19 +2659,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) break; case 0xcc: /* int3 */ gen_op_int3((long)pc_start); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0xcd: /* int N */ val = ldub(s->pc++); /* XXX: currently we ignore the interrupt number */ gen_op_int_im((long)pc_start); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0xce: /* into */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_into((long)pc_start, (long)s->pc); - *is_jmp_ptr = 1; + s->is_jmp = 1; break; case 0x1c8 ... 0x1cf: /* bswap reg */ reg = b & 7; @@ -2586,38 +2697,43 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) return -1; } return (long)s->pc; + illegal_op: + error("illegal opcode pc=0x%08Lx", (long)pc_start); + return -1; } /* return the next pc */ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, - int *gen_code_size_ptr, uint8_t *pc_start) + int *gen_code_size_ptr, uint8_t *pc_start, + int flags) { DisasContext dc1, *dc = &dc1; uint8_t *gen_code_end, *pc_ptr; - int is_jmp; long ret; #ifdef DEBUG_DISAS struct disassemble_info disasm_info; #endif - + dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; + dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; + dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; dc->cc_op = CC_OP_DYNAMIC; gen_code_ptr = gen_code_buf; gen_code_end = gen_code_buf + max_code_size - 4096; gen_start(); - is_jmp = 0; + dc->is_jmp = 0; pc_ptr = pc_start; do { - ret = disas_insn(dc, pc_ptr, &is_jmp); + ret = disas_insn(dc, pc_ptr); if (ret == -1) error("unknown instruction at PC=0x%x B=%02x %02x", pc_ptr, pc_ptr[0], pc_ptr[1]); pc_ptr = (void *)ret; - } while (!is_jmp && gen_code_ptr < gen_code_end); + } while (!dc->is_jmp && gen_code_ptr < gen_code_end); /* we must store the eflags state if it is not already done */ if (dc->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(dc->cc_op); - if (!is_jmp) { + if (dc->is_jmp != 1) { /* we add an additionnal jmp to update the simulated PC */ gen_op_jmp_im(ret); } -- cgit v1.2.3 From 1a9353d258aba69afd8a389bf5fb705caab12ce0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Mar 2003 20:28:50 +0000 Subject: added loop/xadd/cmpxchg support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@29 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ioctls.h | 3 + linux-user/syscall.c | 45 ++++++++++- linux-user/syscall_defs.h | 10 +++ linux-user/syscall_types.h | 3 + op-i386.c | 19 +++++ ops_template.h | 67 ++++++++++++++++ syscall-i386.h | 22 +++--- tests/test-i386.c | 32 ++++++++ translate-i386.c | 191 ++++++++++++++++++++++++++++++++++++--------- 9 files changed, 341 insertions(+), 51 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 49deb09da..eeefcac3e 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -280,3 +280,6 @@ IOCTL(HDIO_SET_DMA, 0, TYPE_INT) IOCTL(HDIO_SET_32BIT, 0, TYPE_INT) IOCTL(HDIO_SET_PIO_MODE, 0, TYPE_INT) + + IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) + IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9ed8daa0f..caaea1aae 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -66,6 +66,10 @@ struct dirent { char d_name[256]; /* We must not include limits.h! */ }; +//#include +#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) +#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) + #include "syscall_defs.h" #ifdef TARGET_I386 @@ -324,6 +328,40 @@ static long do_socketcall(int num, long *vptr) break; case SOCKOP_sendmsg: case SOCKOP_recvmsg: + { + int fd; + struct target_msghdr *msgp; + struct msghdr msg; + int flags, count, i; + struct iovec *vec; + struct target_iovec *target_vec; + + msgp = (void *)vptr[1]; + msg.msg_name = (void *)tswapl(msgp->msg_name); + msg.msg_namelen = tswapl(msgp->msg_namelen); + msg.msg_control = (void *)tswapl(msgp->msg_control); + msg.msg_controllen = tswapl(msgp->msg_controllen); + msg.msg_flags = tswap32(msgp->msg_flags); + + count = tswapl(msgp->msg_iovlen); + vec = alloca(count * sizeof(struct iovec)); + target_vec = (void *)tswapl(msgp->msg_iov); + for(i = 0;i < count; i++) { + vec[i].iov_base = (void *)tswapl(target_vec[i].iov_base); + vec[i].iov_len = tswapl(target_vec[i].iov_len); + } + msg.msg_iovlen = count; + msg.msg_iov = vec; + + fd = vptr[0]; + flags = vptr[2]; + if (num == SOCKOP_sendmsg) + ret = sendmsg(fd, &msg, flags); + else + ret = recvmsg(fd, &msg, flags); + ret = get_errno(ret); + } + break; case SOCKOP_setsockopt: case SOCKOP_getsockopt: default: @@ -356,7 +394,7 @@ typedef struct IOCTLEntry { int host_cmd; const char *name; int access; - const argtype arg_type[3]; + const argtype arg_type[5]; } IOCTLEntry; #define IOC_R 0x0001 @@ -962,12 +1000,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(setsid()); break; case TARGET_NR_sigaction: -#if 0 +#if 1 { int signum = arg1; struct target_old_sigaction *tact = arg2, *toldact = arg3; - ret = get_errno(setsid()); - + ret = 0; } break; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index e8357dff3..dc44272db 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -29,6 +29,16 @@ struct target_iovec { target_long iov_len; /* Number of bytes */ }; +struct target_msghdr { + target_long msg_name; /* Socket name */ + int msg_namelen; /* Length of name */ + target_long msg_iov; /* Data blocks */ + target_long msg_iovlen; /* Number of blocks */ + target_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ + target_long msg_controllen; /* Length of cmsg list */ + unsigned int msg_flags; +}; + struct target_rusage { struct target_timeval ru_utime; /* user time used */ struct target_timeval ru_stime; /* system time used */ diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 540114430..e9ec14816 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -61,3 +61,6 @@ STRUCT(cdrom_read_audio, STRUCT(hd_geometry, TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG) + +STRUCT(dirent, + TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256)) diff --git a/op-i386.c b/op-i386.c index 503fb88ed..f8188e3ea 100644 --- a/op-i386.c +++ b/op-i386.c @@ -2085,3 +2085,22 @@ void OPPROTO op_fldcw_A0(void) fesetround(rnd_type); } +void OPPROTO op_fclex(void) +{ + env->fpus &= 0x7f00; +} + +void OPPROTO op_fninit(void) +{ + env->fpus = 0; + env->fpstt = 0; + env->fpuc = 0x37f; + env->fptags[0] = 1; + env->fptags[1] = 1; + env->fptags[2] = 1; + env->fptags[3] = 1; + env->fptags[4] = 1; + env->fptags[5] = 1; + env->fptags[6] = 1; + env->fptags[7] = 1; +} diff --git a/ops_template.h b/ops_template.h index 745c27d7e..60bdbe509 100644 --- a/ops_template.h +++ b/ops_template.h @@ -277,6 +277,61 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) FORCE_RET(); } +/* oldies */ + +#if DATA_BITS >= 16 + +void OPPROTO glue(op_loopnz, SUFFIX)(void) +{ + unsigned int tmp; + int eflags; + eflags = cc_table[CC_OP].compute_all(); + tmp = (ECX - 1) & DATA_MASK; + ECX = (ECX & ~DATA_MASK) | tmp; + if (tmp != 0 && !(eflags & CC_Z)) + PC = PARAM1; + else + PC = PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_loopz, SUFFIX)(void) +{ + unsigned int tmp; + int eflags; + eflags = cc_table[CC_OP].compute_all(); + tmp = (ECX - 1) & DATA_MASK; + ECX = (ECX & ~DATA_MASK) | tmp; + if (tmp != 0 && (eflags & CC_Z)) + PC = PARAM1; + else + PC = PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_loop, SUFFIX)(void) +{ + unsigned int tmp; + tmp = (ECX - 1) & DATA_MASK; + ECX = (ECX & ~DATA_MASK) | tmp; + if (tmp != 0) + PC = PARAM1; + else + PC = PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_jecxz, SUFFIX)(void) +{ + if ((DATA_TYPE)ECX == 0) + PC = PARAM1; + else + PC = PARAM2; + FORCE_RET(); +} + +#endif + /* various optimized set cases */ void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) @@ -599,6 +654,18 @@ void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void) CC_OP = CC_OP_SUBB + SHIFT + cf * 3; } +void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void) +{ + CC_SRC = EAX; + CC_DST = EAX - T0; + if ((DATA_TYPE)CC_DST == 0) { + T0 = T1; + } else { + EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); + } + FORCE_RET(); +} + /* bit operations */ #if DATA_BITS >= 16 diff --git a/syscall-i386.h b/syscall-i386.h index a54064a05..fa84d9a55 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -632,6 +632,16 @@ struct target_termios { #define TARGET_VLNEXT 15 #define TARGET_VEOL2 16 +#define TARGET_LDT_ENTRIES 8192 +#define TARGET_LDT_ENTRY_SIZE 8 + +struct target_modify_ldt_ldt_s { + unsigned int entry_number; + target_ulong base_addr; + unsigned int limit; + unsigned int flags; +}; + /* soundcard defines (XXX: move them to generic file syscall_defs.h) */ #define TARGET_SNDCTL_COPR_HALT 0xc0144307 @@ -759,13 +769,5 @@ struct target_termios { #define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f #define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff -#define TARGET_LDT_ENTRIES 8192 -#define TARGET_LDT_ENTRY_SIZE 8 - -struct target_modify_ldt_ldt_s { - unsigned int entry_number; - target_ulong base_addr; - unsigned int limit; - unsigned int flags; -}; - +#define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201 +#define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202 diff --git a/tests/test-i386.c b/tests/test-i386.c index 95ec5d150..4d68ae212 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -689,6 +689,37 @@ void test_segs(void) printf("SS[tmp] = %02x\n", res2); } +#define TEST_XCHG(op, size, opconst)\ +{\ + int op0, op1;\ + op0 = 0x12345678;\ + op1 = 0xfbca7654;\ + asm(#op " %" size "0, %" size "1" \ + : "=q" (op0), opconst (op1) \ + : "0" (op0), "1" (op1));\ + printf("%-10s A=%08x B=%08x\n",\ + #op, op0, op1);\ +} + +void test_xchg(void) +{ + TEST_XCHG(xchgl, "", "=q"); + TEST_XCHG(xchgw, "w", "=q"); + TEST_XCHG(xchgb, "b", "=q"); + + TEST_XCHG(xchgl, "", "=m"); + TEST_XCHG(xchgw, "w", "=m"); + TEST_XCHG(xchgb, "b", "=m"); + + TEST_XCHG(xaddl, "", "=q"); + TEST_XCHG(xaddw, "w", "=q"); + TEST_XCHG(xaddb, "b", "=q"); + + TEST_XCHG(xaddl, "", "=m"); + TEST_XCHG(xaddw, "w", "=m"); + TEST_XCHG(xaddb, "b", "=m"); +} + static void *call_end __init_call = NULL; int main(int argc, char **argv) @@ -706,6 +737,7 @@ int main(int argc, char **argv) test_jcc(); test_floats(); test_bcd(); + test_xchg(); test_lea(); test_segs(); return 0; diff --git a/translate-i386.c b/translate-i386.c index 5146242c6..7737dc121 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -389,6 +389,12 @@ static const int cc_op_arithb[8] = { CC_OP_SUBB, }; +static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { + gen_op_cmpxchgb_T0_T1_EAX_cc, + gen_op_cmpxchgw_T0_T1_EAX_cc, + gen_op_cmpxchgl_T0_T1_EAX_cc, +}; + static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { [OT_BYTE] = { gen_op_rolb_T0_T1_cc, @@ -635,6 +641,20 @@ static GenOpFunc2 *gen_jcc_sub[3][8] = { gen_op_jle_subl, }, }; +static GenOpFunc2 *gen_op_loop[2][4] = { + [0] = { + gen_op_loopnzw, + gen_op_loopzw, + gen_op_loopw, + gen_op_jecxzw, + }, + [1] = { + gen_op_loopnzl, + gen_op_loopzl, + gen_op_loopl, + gen_op_jecxzl, + }, +}; static GenOpFunc *gen_setcc_slow[8] = { gen_op_seto_T0_cc, @@ -779,7 +799,6 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ int mod, rm, code, override, must_add_seg; /* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */ - /* XXX: fix lea case */ override = -1; must_add_seg = s->addseg; if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | @@ -1405,8 +1424,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } break; default: - error("GRP3: bad instruction"); - return -1; + goto illegal_op; } break; @@ -1422,8 +1440,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) rm = modrm & 7; op = (modrm >> 3) & 7; if (op >= 2 && b == 0xfe) { - error("GRP4: bad instruction"); - return -1; + goto illegal_op; } if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); @@ -1461,8 +1478,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_pushl_T0(); break; default: - error("GRP5: bad instruction"); - return -1; + goto illegal_op; } break; @@ -1535,6 +1551,55 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_reg_T0[ot][reg](); s->cc_op = CC_OP_MUL; break; + case 0x1c0: + case 0x1c1: /* xadd Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg[ot][1][rm](); + gen_op_addl_T0_T1_cc(); + gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T1[ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_ld_T1_A0[ot](); + gen_op_addl_T0_T1_cc(); + gen_op_st_T0_A0[ot](); + gen_op_mov_reg_T1[ot][reg](); + } + s->cc_op = CC_OP_ADDB + ot; + break; + case 0x1b0: + case 0x1b1: /* cmpxchg Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + gen_op_mov_TN_reg[ot][1][reg](); + if (mod == 3) { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][0][rm](); + gen_op_cmpxchg_T0_T1_EAX_cc[ot](); + gen_op_mov_reg_T0[ot][rm](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + gen_op_cmpxchg_T0_T1_EAX_cc[ot](); + gen_op_st_T0_A0[ot](); + } + s->cc_op = CC_OP_SUBB + ot; + break; /**************************/ /* push/pop */ @@ -1748,6 +1813,32 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else offset_addr = insn_get(s, OT_WORD); gen_op_movl_A0_im(offset_addr); + /* handle override */ + /* XXX: factorize that */ + { + int override, must_add_seg; + override = R_DS; + must_add_seg = s->addseg; + if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | + PREFIX_ES | PREFIX_FS | PREFIX_GS)) { + if (s->prefix & PREFIX_ES) + override = R_ES; + else if (s->prefix & PREFIX_CS) + override = R_CS; + else if (s->prefix & PREFIX_SS) + override = R_SS; + else if (s->prefix & PREFIX_DS) + override = R_DS; + else if (s->prefix & PREFIX_FS) + override = R_FS; + else + override = R_GS; + must_add_seg = 1; + } + if (must_add_seg) { + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + } + } if ((b & 2) == 0) { gen_op_ld_T0_A0[ot](); gen_op_mov_reg_T0[ot][R_EAX](); @@ -1773,11 +1864,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x91 ... 0x97: /* xchg R, EAX */ ot = dflag ? OT_LONG : OT_WORD; reg = b & 7; - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_mov_reg_T0[ot][R_EAX](); - gen_op_mov_reg_T1[ot][reg](); - break; + rm = R_EAX; + goto do_xchg_reg; case 0x86: case 0x87: /* xchg Ev, Gv */ if ((b & 1) == 0) @@ -1786,12 +1874,21 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); reg = (modrm >> 3) & 7; - - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_ld_T1_A0[ot](); - gen_op_st_T0_A0[ot](); - gen_op_mov_reg_T1[ot][reg](); + mod = (modrm >> 6) & 3; + if (mod == 3) { + rm = modrm & 7; + do_xchg_reg: + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg[ot][1][rm](); + gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T1[ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_ld_T1_A0[ot](); + gen_op_st_T0_A0[ot](); + gen_op_mov_reg_T1[ot][reg](); + } break; case 0xc4: /* les Gv */ op = R_ES; @@ -2058,8 +2155,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fpop(); break; default: - error("unhandled FPm [op=0x%02x]\n", op); - return -1; + goto illegal_op; } } else { /* register float ops */ @@ -2078,8 +2174,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0: /* fnop */ break; default: - error("unhandled FP GRP d9/2\n"); - return -1; + goto illegal_op; } break; case 0x0c: /* grp d9/4 */ @@ -2098,7 +2193,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fxam_ST0(); break; default: - return -1; + goto illegal_op; } break; case 0x0d: /* grp d9/5 */ @@ -2133,7 +2228,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fldz_ST0(); break; default: - return -1; + goto illegal_op; } } break; @@ -2230,7 +2325,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fpop(); break; default: - return -1; + goto illegal_op; + } + break; + case 0x1c: + switch(rm) { + case 2: /* fclex */ + gen_op_fclex(); + break; + case 3: /* fninit */ + gen_op_fninit(); + break; + default: + goto illegal_op; } break; case 0x2a: /* fst sti */ @@ -2258,7 +2365,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fpop(); break; default: - return -1; + goto illegal_op; } break; case 0x3c: /* df/4 */ @@ -2267,13 +2374,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fnstsw_EAX(); break; default: - error("unhandled FP %x df/4\n", rm); - return -1; + goto illegal_op; } break; default: - error("unhandled FPr [op=0x%x]\n", op); - return -1; + goto illegal_op; } } break; @@ -2556,7 +2661,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = ldub(s->pc++); gen_op_movl_T1_im(val); if (op < 4) - return -1; + goto illegal_op; op -= 4; gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); s->cc_op = CC_OP_SARB + ot; @@ -2684,6 +2789,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_set_cc_op(s->cc_op); gen_op_salc(); break; + case 0xe0: /* loopnz */ + case 0xe1: /* loopz */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + /* FALL THRU */ + case 0xe2: /* loop */ + case 0xe3: /* jecxz */ + val = (int8_t)insn_get(s, OT_BYTE); + val += (long)s->pc; + gen_op_loop[s->aflag][b & 3](val, (long)s->pc); + s->is_jmp = 1; + break; case 0x1a2: /* rdtsc */ gen_op_rdtsc(); break; @@ -2693,12 +2810,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; #endif default: - error("unknown opcode 0x%x", b); - return -1; + goto illegal_op; } return (long)s->pc; illegal_op: - error("illegal opcode pc=0x%08Lx", (long)pc_start); return -1; } @@ -2725,9 +2840,11 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, pc_ptr = pc_start; do { ret = disas_insn(dc, pc_ptr); - if (ret == -1) - error("unknown instruction at PC=0x%x B=%02x %02x", - pc_ptr, pc_ptr[0], pc_ptr[1]); + if (ret == -1) { + error("unknown instruction at PC=0x%x B=%02x %02x %02x", + pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]); + abort(); + } pc_ptr = (void *)ret; } while (!dc->is_jmp && gen_code_ptr < gen_code_end); /* we must store the eflags state if it is not already done */ -- cgit v1.2.3 From a300e69170319f9736b67cfcb9dc0c05cf175769 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Mar 2003 20:34:20 +0000 Subject: cmpxchg test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@30 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 4d68ae212..907c44ec9 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -701,6 +701,18 @@ void test_segs(void) #op, op0, op1);\ } +#define TEST_CMPXCHG(op, size, opconst, eax)\ +{\ + int op0, op1;\ + op0 = 0x12345678;\ + op1 = 0xfbca7654;\ + asm(#op " %" size "0, %" size "1" \ + : "=q" (op0), opconst (op1) \ + : "0" (op0), "1" (op1), "a" (eax));\ + printf("%-10s EAX=%08x A=%08x C=%08x\n",\ + #op, eax, op0, op1);\ +} + void test_xchg(void) { TEST_XCHG(xchgl, "", "=q"); @@ -718,6 +730,22 @@ void test_xchg(void) TEST_XCHG(xaddl, "", "=m"); TEST_XCHG(xaddw, "w", "=m"); TEST_XCHG(xaddb, "b", "=m"); + + TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfbca7654); + TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654); + TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654); + + TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc); + + TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfbca7654); + TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654); + TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654); + + TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc); } static void *call_end __init_call = NULL; -- cgit v1.2.3 From 60cd49d5d7e6dd3858f72916fbcf462ba60bbd6e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Mar 2003 22:53:56 +0000 Subject: added stat64 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@31 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 44 +++++++++++++++++++++++++++++++++++++++++--- syscall-i386.h | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 65 insertions(+), 27 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index caaea1aae..1e7dcedbd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1002,10 +1002,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_sigaction: #if 1 { - int signum = arg1; - struct target_old_sigaction *tact = arg2, *toldact = arg3; ret = 0; - } break; #else @@ -1464,9 +1461,37 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_ugetrlimit: case TARGET_NR_truncate64: case TARGET_NR_ftruncate64: + goto unimplemented; case TARGET_NR_stat64: + ret = get_errno(stat((const char *)arg1, &st)); + goto do_stat64; case TARGET_NR_lstat64: + ret = get_errno(lstat((const char *)arg1, &st)); + goto do_stat64; case TARGET_NR_fstat64: + { + ret = get_errno(fstat(arg1, &st)); + do_stat64: + if (!is_error(ret)) { + struct target_stat64 *target_st = (void *)arg2; + target_st->st_dev = tswap16(st.st_dev); + target_st->st_ino = tswapl(st.st_ino); + target_st->st_mode = tswap16(st.st_mode); + target_st->st_nlink = tswap16(st.st_nlink); + target_st->st_uid = tswap16(st.st_uid); + target_st->st_gid = tswap16(st.st_gid); + target_st->st_rdev = tswap16(st.st_rdev); + /* XXX: better use of kernel struct */ + target_st->st_size = tswapl(st.st_size); + target_st->st_blksize = tswapl(st.st_blksize); + target_st->st_blocks = tswapl(st.st_blocks); + target_st->st_atime = tswapl(st.st_atime); + target_st->st_mtime = tswapl(st.st_mtime); + target_st->st_ctime = tswapl(st.st_ctime); + } + } + break; + case TARGET_NR_lchown32: case TARGET_NR_getuid32: case TARGET_NR_getgid32: @@ -1490,7 +1515,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_mincore: case TARGET_NR_madvise: case TARGET_NR_getdents64: + goto unimplemented; +#if TARGET_LONG_BITS == 32 case TARGET_NR_fcntl64: + switch(arg2) { + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + goto unimplemented; + default: + ret = get_errno(fcntl(arg1, arg2, arg3)); + break; + } + break; +#endif case TARGET_NR_security: goto unimplemented; case TARGET_NR_gettid: diff --git a/syscall-i386.h b/syscall-i386.h index fa84d9a55..3d270d775 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -245,24 +245,24 @@ struct target_stat { unsigned short st_dev; unsigned short __pad1; - unsigned long st_ino; + target_ulong st_ino; unsigned short st_mode; unsigned short st_nlink; unsigned short st_uid; unsigned short st_gid; unsigned short st_rdev; unsigned short __pad2; - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - unsigned long st_atime; - unsigned long __unused1; - unsigned long st_mtime; - unsigned long __unused2; - unsigned long st_ctime; - unsigned long __unused3; - unsigned long __unused4; - unsigned long __unused5; + target_ulong st_size; + target_ulong st_blksize; + target_ulong st_blocks; + target_ulong st_atime; + target_ulong __unused1; + target_ulong st_mtime; + target_ulong __unused2; + target_ulong st_ctime; + target_ulong __unused3; + target_ulong __unused4; + target_ulong __unused5; }; /* This matches struct stat64 in glibc2.1, hence the absolutely @@ -273,31 +273,31 @@ struct target_stat64 { unsigned char __pad0[10]; #define STAT64_HAS_BROKEN_ST_INO 1 - unsigned long __st_ino; + target_ulong __st_ino; unsigned int st_mode; unsigned int st_nlink; - unsigned long st_uid; - unsigned long st_gid; + target_ulong st_uid; + target_ulong st_gid; unsigned short st_rdev; unsigned char __pad3[10]; long long st_size; - unsigned long st_blksize; + target_ulong st_blksize; - unsigned long st_blocks; /* Number 512-byte blocks allocated. */ - unsigned long __pad4; /* future possible st_blocks high bits */ + target_ulong st_blocks; /* Number 512-byte blocks allocated. */ + target_ulong __pad4; /* future possible st_blocks high bits */ - unsigned long st_atime; - unsigned long __pad5; + target_ulong st_atime; + target_ulong __pad5; - unsigned long st_mtime; - unsigned long __pad6; + target_ulong st_mtime; + target_ulong __pad6; - unsigned long st_ctime; - unsigned long __pad7; /* will be high 32 bits of ctime someday */ + target_ulong st_ctime; + target_ulong __pad7; /* will be high 32 bits of ctime someday */ unsigned long long st_ino; }; -- cgit v1.2.3 From 5dd9488c09081a76ff86e0d74e56a9d98d666d64 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Mar 2003 22:54:06 +0000 Subject: added cmov instruction git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@32 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 1 - opreg_template.h | 13 +++++++ ops_template.h | 1 + tests/test-i386.c | 114 ++++++++++++++++++++++++++++++++---------------------- translate-i386.c | 61 ++++++++++++++++++++--------- 5 files changed, 125 insertions(+), 65 deletions(-) diff --git a/TODO b/TODO index 5602097b8..1a7bac513 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,3 @@ -- segment ops (minimal LDT/GDT support for wine) - optimize translated cache chaining (DLL PLT like system) - improved 16 bit support - optimize inverse flags propagation (easy by generating intermediate diff --git a/opreg_template.h b/opreg_template.h index 6cf188ffe..d6453f954 100644 --- a/opreg_template.h +++ b/opreg_template.h @@ -60,6 +60,19 @@ void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) REG = A0; } +/* mov T1 to REG if T0 is true */ +void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void) +{ + if (T0) + REG = (REG & 0xffff0000) | (T1 & 0xffff); +} + +void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void) +{ + if (T0) + REG = T1; +} + /* NOTE: T0 high order bits are ignored */ void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) { diff --git a/ops_template.h b/ops_template.h index 60bdbe509..8905d9084 100644 --- a/ops_template.h +++ b/ops_template.h @@ -385,6 +385,7 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) { int count, src; + /* XXX: testing */ count = T1 & SHIFT_MASK; if (count) { CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); diff --git a/tests/test-i386.c b/tests/test-i386.c index 907c44ec9..86aa94915 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -3,6 +3,8 @@ #include #include +#define TEST_CMOV 0 + #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) #define stringify(s) tostring(s) @@ -225,79 +227,99 @@ void test_lea(void) #define TEST_JCC(JCC, v1, v2)\ {\ + int res;\ asm("movl $1, %0\n\t"\ "cmpl %2, %1\n\t"\ - JCC " 1f\n\t"\ + "j" JCC " 1f\n\t"\ "movl $0, %0\n\t"\ "1:\n\t"\ : "=r" (res)\ : "r" (v1), "r" (v2));\ - printf("%-10s %d\n", JCC, res);\ + printf("%-10s %d\n", "j" JCC, res);\ +\ + asm("movl $0, %0\n\t"\ + "cmpl %2, %1\n\t"\ + "set" JCC " %b0\n\t"\ + : "=r" (res)\ + : "r" (v1), "r" (v2));\ + printf("%-10s %d\n", "set" JCC, res);\ + if (TEST_CMOV) {\ + asm("movl $0x12345678, %0\n\t"\ + "cmpl %2, %1\n\t"\ + "cmov" JCC "l %3, %0\n\t"\ + : "=r" (res)\ + : "r" (v1), "r" (v2), "m" (1));\ + printf("%-10s R=0x%08x\n", "cmov" JCC "l", res);\ + asm("movl $0x12345678, %0\n\t"\ + "cmpl %2, %1\n\t"\ + "cmov" JCC "w %w3, %w0\n\t"\ + : "=r" (res)\ + : "r" (v1), "r" (v2), "r" (1));\ + printf("%-10s R=0x%08x\n", "cmov" JCC "w", res);\ + } \ } /* various jump tests */ void test_jcc(void) { - int res; - - TEST_JCC("jne", 1, 1); - TEST_JCC("jne", 1, 0); + TEST_JCC("ne", 1, 1); + TEST_JCC("ne", 1, 0); - TEST_JCC("je", 1, 1); - TEST_JCC("je", 1, 0); + TEST_JCC("e", 1, 1); + TEST_JCC("e", 1, 0); - TEST_JCC("jl", 1, 1); - TEST_JCC("jl", 1, 0); - TEST_JCC("jl", 1, -1); + TEST_JCC("l", 1, 1); + TEST_JCC("l", 1, 0); + TEST_JCC("l", 1, -1); - TEST_JCC("jle", 1, 1); - TEST_JCC("jle", 1, 0); - TEST_JCC("jle", 1, -1); + TEST_JCC("le", 1, 1); + TEST_JCC("le", 1, 0); + TEST_JCC("le", 1, -1); - TEST_JCC("jge", 1, 1); - TEST_JCC("jge", 1, 0); - TEST_JCC("jge", -1, 1); + TEST_JCC("ge", 1, 1); + TEST_JCC("ge", 1, 0); + TEST_JCC("ge", -1, 1); - TEST_JCC("jg", 1, 1); - TEST_JCC("jg", 1, 0); - TEST_JCC("jg", 1, -1); + TEST_JCC("g", 1, 1); + TEST_JCC("g", 1, 0); + TEST_JCC("g", 1, -1); - TEST_JCC("jb", 1, 1); - TEST_JCC("jb", 1, 0); - TEST_JCC("jb", 1, -1); + TEST_JCC("b", 1, 1); + TEST_JCC("b", 1, 0); + TEST_JCC("b", 1, -1); - TEST_JCC("jbe", 1, 1); - TEST_JCC("jbe", 1, 0); - TEST_JCC("jbe", 1, -1); + TEST_JCC("be", 1, 1); + TEST_JCC("be", 1, 0); + TEST_JCC("be", 1, -1); - TEST_JCC("jae", 1, 1); - TEST_JCC("jae", 1, 0); - TEST_JCC("jae", 1, -1); + TEST_JCC("ae", 1, 1); + TEST_JCC("ae", 1, 0); + TEST_JCC("ae", 1, -1); - TEST_JCC("ja", 1, 1); - TEST_JCC("ja", 1, 0); - TEST_JCC("ja", 1, -1); + TEST_JCC("a", 1, 1); + TEST_JCC("a", 1, 0); + TEST_JCC("a", 1, -1); - TEST_JCC("jp", 1, 1); - TEST_JCC("jp", 1, 0); + TEST_JCC("p", 1, 1); + TEST_JCC("p", 1, 0); - TEST_JCC("jnp", 1, 1); - TEST_JCC("jnp", 1, 0); + TEST_JCC("np", 1, 1); + TEST_JCC("np", 1, 0); - TEST_JCC("jo", 0x7fffffff, 0); - TEST_JCC("jo", 0x7fffffff, -1); + TEST_JCC("o", 0x7fffffff, 0); + TEST_JCC("o", 0x7fffffff, -1); - TEST_JCC("jno", 0x7fffffff, 0); - TEST_JCC("jno", 0x7fffffff, -1); + TEST_JCC("no", 0x7fffffff, 0); + TEST_JCC("no", 0x7fffffff, -1); - TEST_JCC("js", 0, 1); - TEST_JCC("js", 0, -1); - TEST_JCC("js", 0, 0); + TEST_JCC("s", 0, 1); + TEST_JCC("s", 0, -1); + TEST_JCC("s", 0, 0); - TEST_JCC("jns", 0, 1); - TEST_JCC("jns", 0, -1); - TEST_JCC("jns", 0, 0); + TEST_JCC("ns", 0, 1); + TEST_JCC("ns", 0, -1); + TEST_JCC("ns", 0, 0); } #undef CC_MASK diff --git a/translate-i386.c b/translate-i386.c index 7737dc121..9bf7f5607 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -44,19 +44,6 @@ int __op_param1, __op_param2, __op_param3; extern FILE *logfile; extern int loglevel; -/* supress that */ -static void error(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "\n"); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(1); -} - #define PREFIX_REPZ 1 #define PREFIX_REPNZ 2 #define PREFIX_LOCK 4 @@ -352,6 +339,29 @@ static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { }, }; +static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = { + [0] = { + gen_op_cmovw_EAX_T1_T0, + gen_op_cmovw_ECX_T1_T0, + gen_op_cmovw_EDX_T1_T0, + gen_op_cmovw_EBX_T1_T0, + gen_op_cmovw_ESP_T1_T0, + gen_op_cmovw_EBP_T1_T0, + gen_op_cmovw_ESI_T1_T0, + gen_op_cmovw_EDI_T1_T0, + }, + [1] = { + gen_op_cmovl_EAX_T1_T0, + gen_op_cmovl_ECX_T1_T0, + gen_op_cmovl_EDX_T1_T0, + gen_op_cmovl_EBX_T1_T0, + gen_op_cmovl_ESP_T1_T0, + gen_op_cmovl_EBP_T1_T0, + gen_op_cmovl_ESI_T1_T0, + gen_op_cmovl_EDI_T1_T0, + }, +}; + static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { gen_op_addl_T0_T1_cc, gen_op_orl_T0_T1_cc, @@ -2586,12 +2596,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->is_jmp = 1; break; - case 0x190 ... 0x19f: + case 0x190 ... 0x19f: /* setcc Gv */ modrm = ldub(s->pc++); gen_setcc(s, b); gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); break; - + case 0x140 ... 0x14f: /* cmov Gv, Ev */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + gen_setcc(s, b); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[ot](); + } else { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][1][rm](); + } + gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); + break; + /************************/ /* flags */ case 0x9c: /* pushf */ @@ -2801,7 +2826,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_loop[s->aflag][b & 3](val, (long)s->pc); s->is_jmp = 1; break; - case 0x1a2: /* rdtsc */ + case 0x131: /* rdtsc */ gen_op_rdtsc(); break; #if 0 @@ -2841,8 +2866,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, do { ret = disas_insn(dc, pc_ptr); if (ret == -1) { - error("unknown instruction at PC=0x%x B=%02x %02x %02x", - pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]); + fprintf(stderr, "unknown instruction at PC=0x%08lx B=%02x %02x %02x", + (long)pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]); abort(); } pc_ptr = (void *)ret; -- cgit v1.2.3 From ca735206e0f223d75894260fb98c0c605f590817 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Mar 2003 20:41:34 +0000 Subject: gcc 3.x fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@33 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 12 +++++++++++- configure | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0f0b22db7..f922a3ea3 100644 --- a/Makefile +++ b/Makefile @@ -7,13 +7,23 @@ DEFINES=-DHAVE_BYTESWAP_H ifeq ($(ARCH),i386) CFLAGS+=-fomit-frame-pointer -OP_CFLAGS=$(CFLAGS) -malign-functions=0 -mpreferred-stack-boundary=2 +OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2 +ifeq ($(GCC_MAJOR),3) +OP_CFLAGS+= -falign-functions=0 +else +OP_CFLAGS+= -malign-functions=0 +endif endif ifeq ($(ARCH),ppc) OP_CFLAGS=$(CFLAGS) endif +ifeq ($(GCC_MAJOR),3) +# very important to generate a return at the end of every operation +OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls +endif + ######################################################### DEFINES+=-D_GNU_SOURCE diff --git a/configure b/configure index 16252c4dc..62b1e7122 100755 --- a/configure +++ b/configure @@ -13,6 +13,7 @@ fi TMPC="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.c" TMPO="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.o" +TMPE="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}" TMPS="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.S" TMPH="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.h" @@ -142,6 +143,14 @@ fi fi +# check gcc version +gcc_major="2" +gcc_version="$($cc -v 2>&1 | grep version | cut -d ' ' -f3-)" +case "$gcc_version" in +3.*) gcc_major="3"; +;; +esac + if test x"$1" = x"-h" -o x"$1" = x"--help" ; then cat << EOF @@ -181,6 +190,7 @@ echo "prefix=$prefix" >> config.mak echo "#define CONFIG_GEMU_PREFIX \"$prefix\"" >> $TMPH echo "MAKE=$make" >> config.mak echo "CC=$cc" >> config.mak +echo "GCC_MAJOR=$gcc_major" >> config.mak echo "HOST_CC=$host_cc" >> config.mak echo "AR=$ar" >> config.mak echo "STRIP=$strip -s -R .comment -R .note" >> config.mak -- cgit v1.2.3 From dc99065b5f97cc0410f88e3f90c7440531a55f9f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Mar 2003 00:00:28 +0000 Subject: added flags computation optimization git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@34 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- TODO | 8 +- dis-asm.h | 237 ++++++ dis-buf.c | 79 ++ dyngen.c | 210 +++-- exec-i386.c | 2 +- gen-i386.h | 8 - i386-dis.c | 2299 ++++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 2 +- op-i386.c | 54 +- opc-i386.h | 518 ++++++++++++ ops_template.h | 49 +- translate-i386.c | 387 ++++++++- 13 files changed, 3767 insertions(+), 88 deletions(-) create mode 100644 dis-asm.h create mode 100644 dis-buf.c create mode 100644 i386-dis.c create mode 100644 opc-i386.h diff --git a/Makefile b/Makefile index f922a3ea3..8b92f0e5f 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ LIBS+=-ldl -lm # profiling code ifdef TARGET_GPROF LDFLAGS+=-p -CFLAGS+=-p +main.o: CFLAGS+=-p endif OBJS= elfload.o main.o thunk.o syscall.o diff --git a/TODO b/TODO index 1a7bac513..ad3c76593 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,7 @@ -- optimize translated cache chaining (DLL PLT like system) -- improved 16 bit support -- optimize inverse flags propagation (easy by generating intermediate - micro operation array). +- optimize translated cache chaining (DLL PLT-like system) +- 64 bit syscalls - signals - threads - make it self runnable (use same trick as ld.so : include its own relocator and libc) +- improved 16 bit support - fix FPU exceptions (in particular: gen_op_fpush not before mem load) -- tests diff --git a/dis-asm.h b/dis-asm.h new file mode 100644 index 000000000..bd7e47844 --- /dev/null +++ b/dis-asm.h @@ -0,0 +1,237 @@ +/* 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 +#include "bfd.h" + +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 */ + +} 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_big_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_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*)); + +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler PARAMS ((bfd *)); + + +/* 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).insn_info_valid = 0 + +#endif /* ! defined (DIS_ASM_H) */ diff --git a/dis-buf.c b/dis-buf.c new file mode 100644 index 000000000..cdb8e9b19 --- /dev/null +++ b/dis-buf.c @@ -0,0 +1,79 @@ +/* Disassemble from a buffer, for GNU. + Copyright (C) 1993, 1994 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "dis-asm.h" +#include + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +int +buffer_read_memory (memaddr, myaddr, length, info) + bfd_vma memaddr; + bfd_byte *myaddr; + int length; + struct disassemble_info *info; +{ + if (memaddr < info->buffer_vma + || memaddr + length > info->buffer_vma + info->buffer_length) + /* Out of bounds. Use EIO because GDB uses it. */ + return EIO; + memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); + return 0; +} + +/* Print an error message. We can assume that this is in response to + an error return from buffer_read_memory. */ +void +perror_memory (status, memaddr, info) + int status; + bfd_vma memaddr; + struct disassemble_info *info; +{ + if (status != EIO) + /* Can't happen. */ + (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); + else + /* Actually, address between memaddr and memaddr + len was + out of bounds. */ + (*info->fprintf_func) (info->stream, + "Address 0x%x is out of bounds.\n", memaddr); +} + +/* This could be in a separate file, to save miniscule amounts of space + in statically linked executables. */ + +/* Just print the address is hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ + +void +generic_print_address (addr, info) + bfd_vma addr; + struct disassemble_info *info; +{ + (*info->fprintf_func) (info->stream, "0x%x", addr); +} + +/* Just return the given address. */ + +int +generic_symbol_at_address (addr, info) + bfd_vma addr; + struct disassemble_info * info; +{ + return 1; +} diff --git a/dyngen.c b/dyngen.c index 40a7fc695..9b2889b67 100644 --- a/dyngen.c +++ b/dyngen.c @@ -28,7 +28,7 @@ #include "thunk.h" /* all dynamically generated functions begin with this code */ -#define OP_PREFIX "op" +#define OP_PREFIX "op_" int elf_must_swap(Elf32_Ehdr *h) { @@ -201,7 +201,7 @@ int strstart(const char *str, const char *val, const char **ptr) /* generate op code */ void gen_code(const char *name, unsigned long offset, unsigned long size, FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type, - Elf32_Sym *symtab, char *strtab) + Elf32_Sym *symtab, char *strtab, int gen_switch) { int copy_size = 0; uint8_t *p_start, *p_end; @@ -258,8 +258,6 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, if (n >= MAX_ARGS) error("too many arguments in %s", name); args_present[n - 1] = 1; - } else { - fprintf(outfile, "extern char %s;\n", sym_name); } } } @@ -274,8 +272,6 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, if (n >= MAX_ARGS) error("too many arguments in %s", name); args_present[n - 1] = 1; - } else { - fprintf(outfile, "extern char %s;\n", sym_name); } } } @@ -289,31 +285,57 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, error("inconsistent argument numbering in %s", name); } - /* output C code */ - fprintf(outfile, "extern void %s();\n", name); - 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); + if (gen_switch) { + + /* 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"); } - } - fprintf(outfile, ")\n"); - fprintf(outfile, "{\n"); - fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size); - - /* patch relocations */ - switch(e_machine) { - case EM_386: - { + fprintf(outfile, " extern void %s();\n", name); + + if (reloc_sh_type == SHT_REL) { Elf32_Rel *rel; - char name[256]; - int type; - long addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (!strstart(sym_name, "__op_param", &p)) { + fprintf(outfile, "extern char %s;\n", sym_name); + } + } + } + } else { + Elf32_Rela *rel; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (!strstart(sym_name, "__op_param", &p)) { + fprintf(outfile, "extern char %s;\n", sym_name); + } + } + } + } + + fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size); + for(i = 0; i < nb_args; i++) { + fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1); + } + + /* patch relocations */ + switch(e_machine) { + case EM_386: + { + Elf32_Rel *rel; + char name[256]; + int type; + long addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { @@ -336,20 +358,38 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, error("unsupported i386 relocation (%d)", type); } } + } + } + break; + default: + error("unsupported CPU for relocations (%d)", e_machine); + } + 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); } } - break; - default: - error("unsupported CPU for relocations (%d)", e_machine); + 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"); } - - - fprintf(outfile, " gen_code_ptr += %d;\n", copy_size); - fprintf(outfile, "}\n\n"); } /* load an elf object file */ -int load_elf(const char *filename, FILE *outfile) +int load_elf(const char *filename, FILE *outfile, int do_print_enum) { int fd; Elf32_Ehdr ehdr; @@ -476,23 +516,77 @@ int load_elf(const char *filename, FILE *outfile) error("unsupported CPU (e_machine=%d)", e_machine); } - fprintf(outfile, "#include \"gen-%s.h\"\n\n", cpu_name); + if (do_print_enum) { + fprintf(outfile, "DEF(end)\n"); + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + const char *name, *p; + name = strtab + sym->st_name; + if (strstart(name, OP_PREFIX, &p)) { + fprintf(outfile, "DEF(%s)\n", p); + } + } + } else { + /* generate big code generation switch */ +fprintf(outfile, +"int dyngen_code(uint8_t *gen_code_buf,\n" +" const uint16_t *opc_buf, const uint32_t *opparam_buf)\n" +"{\n" +" uint8_t *gen_code_ptr;\n" +" const uint16_t *opc_ptr;\n" +" const uint32_t *opparam_ptr;\n" +" gen_code_ptr = gen_code_buf;\n" +" opc_ptr = opc_buf;\n" +" opparam_ptr = opparam_buf;\n" +" for(;;) {\n" +" switch(*opc_ptr++) {\n" +); - for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { - const char *name; - name = strtab + sym->st_name; - if (strstart(name, "op_", NULL) || - strstart(name, "op1_", NULL) || - strstart(name, "op2_", NULL) || - strstart(name, "op3_", NULL)) { + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + const char *name; + name = strtab + sym->st_name; + 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); + printf("%4d: %s pos=0x%08x len=%d\n", + i, name, sym->st_value, sym->st_size); #endif - if (sym->st_shndx != (text_sec - shdr)) - error("invalid section for opcode (0x%x)", sym->st_shndx); - gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, reloc_sh_type, symtab, strtab); + if (sym->st_shndx != (text_sec - shdr)) + error("invalid section for opcode (0x%x)", sym->st_shndx); + gen_code(name, sym->st_value, sym->st_size, outfile, + text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 1); + } + } + +fprintf(outfile, +" default:\n" +" goto the_end;\n" +" }\n" +" }\n" +" the_end:\n" +); + +/* generate a return */ + switch(e_machine) { + case EM_386: + fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n"); + break; + default: + error("no return generation for cpu '%s'", cpu_name); + } + + fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n"); + fprintf(outfile, "}\n\n"); + +/* generate gen_xxx functions */ +/* XXX: suppress the use of these functions to simplify code */ + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + const char *name; + name = strtab + sym->st_name; + if (strstart(name, OP_PREFIX, NULL)) { + if (sym->st_shndx != (text_sec - shdr)) + error("invalid section for opcode (0x%x)", sym->st_shndx); + gen_code(name, sym->st_value, sym->st_size, outfile, + text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 0); + } } } @@ -503,20 +597,23 @@ int load_elf(const char *filename, FILE *outfile) void usage(void) { printf("dyngen (c) 2003 Fabrice Bellard\n" - "usage: dyngen [-o outfile] objfile\n" - "Generate a dynamic code generator from an object file\n"); + "usage: dyngen [-o outfile] [-c] objfile\n" + "Generate a dynamic code generator from an object file\n" + "-c output enum of operations\n" + ); exit(1); } int main(int argc, char **argv) { - int c; + int c, do_print_enum; const char *filename, *outfilename; FILE *outfile; outfilename = "out.c"; + do_print_enum = 0; for(;;) { - c = getopt(argc, argv, "ho:"); + c = getopt(argc, argv, "ho:c"); if (c == -1) break; switch(c) { @@ -526,6 +623,9 @@ int main(int argc, char **argv) case 'o': outfilename = optarg; break; + case 'c': + do_print_enum = 1; + break; } } if (optind >= argc) @@ -534,7 +634,7 @@ int main(int argc, char **argv) outfile = fopen(outfilename, "w"); if (!outfile) error("could not open '%s'", outfilename); - load_elf(filename, outfile); + load_elf(filename, outfile, do_print_enum); fclose(outfile); return 0; } diff --git a/exec-i386.c b/exec-i386.c index 8144add7b..538ebe0d6 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -19,7 +19,7 @@ */ #include "exec-i386.h" -#define DEBUG_EXEC +//#define DEBUG_EXEC #define DEBUG_FLUSH /* main execution loop */ diff --git a/gen-i386.h b/gen-i386.h index a5d7f5989..e69de29bb 100644 --- a/gen-i386.h +++ b/gen-i386.h @@ -1,8 +0,0 @@ -static inline void gen_start(void) -{ -} - -static inline void gen_end(void) -{ - *gen_code_ptr++ = 0xc3; /* ret */ -} diff --git a/i386-dis.c b/i386-dis.c new file mode 100644 index 000000000..0a63294f7 --- /dev/null +++ b/i386-dis.c @@ -0,0 +1,2299 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 97, 1998 + Free Software Foundation, Inc. + +This file is part of GDB. + +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. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * modified by John Hassey (hassey@dg-rtp.dg.com) + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#include "dis-asm.h" + +#define MAXLEN 20 + +#include + +static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); + +struct dis_private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + jmp_buf bailout; +}; + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct dis_private *)(info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (info, addr) + struct disassemble_info *info; + bfd_byte *addr; +{ + int status; + struct dis_private *priv = (struct dis_private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 +#define Mp OP_E, 0 /* ? */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rw OP_rm, w_mode +#define Rd OP_rm, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#if 0 +#define ONE OP_ONE, 0 +#endif +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, lptr +#define Av OP_DIR, v_mode +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSSI, b_mode +#define Xv OP_DSSI, v_mode +#define Yb OP_ESDI, b_mode +#define Yv OP_ESDI, v_mode + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +#define MX OP_MMX, 0 +#define EM OP_EM, v_mode +#define MS OP_MS, b_mode + +typedef int (*op_rtn) PARAMS ((int bytemode, int aflag, int dflag)); + +static int OP_E PARAMS ((int, int, int)); +static int OP_G PARAMS ((int, int, int)); +static int OP_I PARAMS ((int, int, int)); +static int OP_indirE PARAMS ((int, int, int)); +static int OP_sI PARAMS ((int, int, int)); +static int OP_REG PARAMS ((int, int, int)); +static int OP_J PARAMS ((int, int, int)); +static int OP_DIR PARAMS ((int, int, int)); +static int OP_OFF PARAMS ((int, int, int)); +static int OP_ESDI PARAMS ((int, int, int)); +static int OP_DSSI PARAMS ((int, int, int)); +static int OP_SEG PARAMS ((int, int, int)); +static int OP_C PARAMS ((int, int, int)); +static int OP_D PARAMS ((int, int, int)); +static int OP_T PARAMS ((int, int, int)); +static int OP_rm PARAMS ((int, int, int)); +static int OP_ST PARAMS ((int, int, int)); +static int OP_STi PARAMS ((int, int, int)); +#if 0 +static int OP_ONE PARAMS ((int, int, int)); +#endif +static int OP_MMX PARAMS ((int, int, int)); +static int OP_EM PARAMS ((int, int, int)); +static int OP_MS PARAMS ((int, int, int)); + +static void append_prefix PARAMS ((void)); +static void set_op PARAMS ((int op)); +static void putop PARAMS ((char *template, int aflag, int dflag)); +static void dofloat PARAMS ((int aflag, int dflag)); +static int get16 PARAMS ((void)); +static int get32 PARAMS ((void)); +static void ckprefix PARAMS ((void)); + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 +#define eAX_reg 107 +#define eCX_reg 108 +#define eDX_reg 109 +#define eBX_reg 110 +#define eSP_reg 111 +#define eBP_reg 112 +#define eSI_reg 113 +#define eDI_reg 114 + +#define lptr 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define GRP1b NULL, NULL, 0 +#define GRP1S NULL, NULL, 1 +#define GRP1Ss NULL, NULL, 2 +#define GRP2b NULL, NULL, 3 +#define GRP2S NULL, NULL, 4 +#define GRP2b_one NULL, NULL, 5 +#define GRP2S_one NULL, NULL, 6 +#define GRP2b_cl NULL, NULL, 7 +#define GRP2S_cl NULL, NULL, 8 +#define GRP3b NULL, NULL, 9 +#define GRP3S NULL, NULL, 10 +#define GRP4 NULL, NULL, 11 +#define GRP5 NULL, NULL, 12 +#define GRP6 NULL, NULL, 13 +#define GRP7 NULL, NULL, 14 +#define GRP8 NULL, NULL, 15 +#define GRP9 NULL, NULL, 16 +#define GRP10 NULL, NULL, 17 +#define GRP11 NULL, NULL, 18 +#define GRP12 NULL, NULL, 19 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE + +struct dis386 { + char *name; + op_rtn op1; + int bytemode1; + op_rtn op2; + int bytemode2; + op_rtn op3; + int bytemode3; +}; + +static struct dis386 dis386[] = { + /* 00 */ + { "addb", Eb, Gb }, + { "addS", Ev, Gv }, + { "addb", Gb, Eb }, + { "addS", Gv, Ev }, + { "addb", AL, Ib }, + { "addS", eAX, Iv }, + { "pushS", es }, + { "popS", es }, + /* 08 */ + { "orb", Eb, Gb }, + { "orS", Ev, Gv }, + { "orb", Gb, Eb }, + { "orS", Gv, Ev }, + { "orb", AL, Ib }, + { "orS", eAX, Iv }, + { "pushS", cs }, + { "(bad)" }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcb", Eb, Gb }, + { "adcS", Ev, Gv }, + { "adcb", Gb, Eb }, + { "adcS", Gv, Ev }, + { "adcb", AL, Ib }, + { "adcS", eAX, Iv }, + { "pushS", ss }, + { "popS", ss }, + /* 18 */ + { "sbbb", Eb, Gb }, + { "sbbS", Ev, Gv }, + { "sbbb", Gb, Eb }, + { "sbbS", Gv, Ev }, + { "sbbb", AL, Ib }, + { "sbbS", eAX, Iv }, + { "pushS", ds }, + { "popS", ds }, + /* 20 */ + { "andb", Eb, Gb }, + { "andS", Ev, Gv }, + { "andb", Gb, Eb }, + { "andS", Gv, Ev }, + { "andb", AL, Ib }, + { "andS", eAX, Iv }, + { "(bad)" }, /* SEG ES prefix */ + { "daa" }, + /* 28 */ + { "subb", Eb, Gb }, + { "subS", Ev, Gv }, + { "subb", Gb, Eb }, + { "subS", Gv, Ev }, + { "subb", AL, Ib }, + { "subS", eAX, Iv }, + { "(bad)" }, /* SEG CS prefix */ + { "das" }, + /* 30 */ + { "xorb", Eb, Gb }, + { "xorS", Ev, Gv }, + { "xorb", Gb, Eb }, + { "xorS", Gv, Ev }, + { "xorb", AL, Ib }, + { "xorS", eAX, Iv }, + { "(bad)" }, /* SEG SS prefix */ + { "aaa" }, + /* 38 */ + { "cmpb", Eb, Gb }, + { "cmpS", Ev, Gv }, + { "cmpb", Gb, Eb }, + { "cmpS", Gv, Ev }, + { "cmpb", AL, Ib }, + { "cmpS", eAX, Iv }, + { "(bad)" }, /* SEG DS prefix */ + { "aas" }, + /* 40 */ + { "incS", eAX }, + { "incS", eCX }, + { "incS", eDX }, + { "incS", eBX }, + { "incS", eSP }, + { "incS", eBP }, + { "incS", eSI }, + { "incS", eDI }, + /* 48 */ + { "decS", eAX }, + { "decS", eCX }, + { "decS", eDX }, + { "decS", eBX }, + { "decS", eSP }, + { "decS", eBP }, + { "decS", eSI }, + { "decS", eDI }, + /* 50 */ + { "pushS", eAX }, + { "pushS", eCX }, + { "pushS", eDX }, + { "pushS", eBX }, + { "pushS", eSP }, + { "pushS", eBP }, + { "pushS", eSI }, + { "pushS", eDI }, + /* 58 */ + { "popS", eAX }, + { "popS", eCX }, + { "popS", eDX }, + { "popS", eBX }, + { "popS", eSP }, + { "popS", eBP }, + { "popS", eSI }, + { "popS", eDI }, + /* 60 */ + { "pusha" }, + { "popa" }, + { "boundS", Gv, Ma }, + { "arpl", Ew, Gw }, + { "(bad)" }, /* seg fs */ + { "(bad)" }, /* seg gs */ + { "(bad)" }, /* op size prefix */ + { "(bad)" }, /* adr size prefix */ + /* 68 */ + { "pushS", Iv }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushS", sIb }, /* push of byte really pushes 2 or 4 bytes */ + { "imulS", Gv, Ev, Ib }, + { "insb", Yb, indirDX }, + { "insS", Yv, indirDX }, + { "outsb", indirDX, Xb }, + { "outsS", indirDX, Xv }, + /* 70 */ + { "jo", Jb }, + { "jno", Jb }, + { "jb", Jb }, + { "jae", Jb }, + { "je", Jb }, + { "jne", Jb }, + { "jbe", Jb }, + { "ja", Jb }, + /* 78 */ + { "js", Jb }, + { "jns", Jb }, + { "jp", Jb }, + { "jnp", Jb }, + { "jl", Jb }, + { "jnl", Jb }, + { "jle", Jb }, + { "jg", Jb }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)" }, + { GRP1Ss }, + { "testb", Eb, Gb }, + { "testS", Ev, Gv }, + { "xchgb", Eb, Gb }, + { "xchgS", Ev, Gv }, + /* 88 */ + { "movb", Eb, Gb }, + { "movS", Ev, Gv }, + { "movb", Gb, Eb }, + { "movS", Gv, Ev }, + { "movS", Ev, Sw }, + { "leaS", Gv, M }, + { "movS", Sw, Ev }, + { "popS", Ev }, + /* 90 */ + { "nop" }, + { "xchgS", eCX, eAX }, + { "xchgS", eDX, eAX }, + { "xchgS", eBX, eAX }, + { "xchgS", eSP, eAX }, + { "xchgS", eBP, eAX }, + { "xchgS", eSI, eAX }, + { "xchgS", eDI, eAX }, + /* 98 */ + { "cWtS" }, + { "cStd" }, + { "lcall", Ap }, + { "(bad)" }, /* fwait */ + { "pushf" }, + { "popf" }, + { "sahf" }, + { "lahf" }, + /* a0 */ + { "movb", AL, Ob }, + { "movS", eAX, Ov }, + { "movb", Ob, AL }, + { "movS", Ov, eAX }, + { "movsb", Yb, Xb }, + { "movsS", Yv, Xv }, + { "cmpsb", Yb, Xb }, + { "cmpsS", Yv, Xv }, + /* a8 */ + { "testb", AL, Ib }, + { "testS", eAX, Iv }, + { "stosb", Yb, AL }, + { "stosS", Yv, eAX }, + { "lodsb", AL, Xb }, + { "lodsS", eAX, Xv }, + { "scasb", AL, Yb }, + { "scasS", eAX, Yv }, + /* b0 */ + { "movb", AL, Ib }, + { "movb", CL, Ib }, + { "movb", DL, Ib }, + { "movb", BL, Ib }, + { "movb", AH, Ib }, + { "movb", CH, Ib }, + { "movb", DH, Ib }, + { "movb", BH, Ib }, + /* b8 */ + { "movS", eAX, Iv }, + { "movS", eCX, Iv }, + { "movS", eDX, Iv }, + { "movS", eBX, Iv }, + { "movS", eSP, Iv }, + { "movS", eBP, Iv }, + { "movS", eSI, Iv }, + { "movS", eDI, Iv }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw }, + { "ret" }, + { "lesS", Gv, Mp }, + { "ldsS", Gv, Mp }, + { "movb", Eb, Ib }, + { "movS", Ev, Iv }, + /* c8 */ + { "enter", Iw, Ib }, + { "leave" }, + { "lret", Iw }, + { "lret" }, + { "int3" }, + { "int", Ib }, + { "into" }, + { "iret" }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", Ib }, + { "aad", Ib }, + { "(bad)" }, + { "xlat" }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb }, + { "loope", Jb }, + { "loop", Jb }, + { "jCcxz", Jb }, + { "inb", AL, Ib }, + { "inS", eAX, Ib }, + { "outb", Ib, AL }, + { "outS", Ib, eAX }, + /* e8 */ + { "call", Av }, + { "jmp", Jv }, + { "ljmp", Ap }, + { "jmp", Jb }, + { "inb", AL, indirDX }, + { "inS", eAX, indirDX }, + { "outb", indirDX, AL }, + { "outS", indirDX, eAX }, + /* f0 */ + { "(bad)" }, /* lock prefix */ + { "(bad)" }, + { "(bad)" }, /* repne */ + { "(bad)" }, /* repz */ + { "hlt" }, + { "cmc" }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc" }, + { "stc" }, + { "cli" }, + { "sti" }, + { "cld" }, + { "std" }, + { GRP4 }, + { GRP5 }, +}; + +static struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew }, + { "lslS", Gv, Ew }, + { "(bad)" }, + { "(bad)" }, + { "clts" }, + { "(bad)" }, + /* 08 */ + { "invd" }, + { "wbinvd" }, + { "(bad)" }, { "ud2a" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 10 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 18 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movl", Rd, Cd }, + { "movl", Rd, Dd }, + { "movl", Cd, Rd }, + { "movl", Dd, Rd }, + { "movl", Rd, Td }, + { "(bad)" }, + { "movl", Td, Rd }, + { "(bad)" }, + /* 28 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 30 */ + { "wrmsr" }, { "rdtsc" }, { "rdmsr" }, { "rdpmc" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 38 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 40 */ + { "cmovo", Gv,Ev }, { "cmovno", Gv,Ev }, { "cmovb", Gv,Ev }, { "cmovae", Gv,Ev }, + { "cmove", Gv,Ev }, { "cmovne", Gv,Ev }, { "cmovbe", Gv,Ev }, { "cmova", Gv,Ev }, + /* 48 */ + { "cmovs", Gv,Ev }, { "cmovns", Gv,Ev }, { "cmovp", Gv,Ev }, { "cmovnp", Gv,Ev }, + { "cmovl", Gv,Ev }, { "cmovge", Gv,Ev }, { "cmovle", Gv,Ev }, { "cmovg", Gv,Ev }, + /* 50 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 58 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 60 */ + { "punpcklbw", MX, EM }, + { "punpcklwd", MX, EM }, + { "punpckldq", MX, EM }, + { "packsswb", MX, EM }, + { "pcmpgtb", MX, EM }, + { "pcmpgtw", MX, EM }, + { "pcmpgtd", MX, EM }, + { "packuswb", MX, EM }, + /* 68 */ + { "punpckhbw", MX, EM }, + { "punpckhwd", MX, EM }, + { "punpckhdq", MX, EM }, + { "packssdw", MX, EM }, + { "(bad)" }, { "(bad)" }, + { "movd", MX, Ev }, + { "movq", MX, EM }, + /* 70 */ + { "(bad)" }, + { GRP10 }, + { GRP11 }, + { GRP12 }, + { "pcmpeqb", MX, EM }, + { "pcmpeqw", MX, EM }, + { "pcmpeqd", MX, EM }, + { "emms" }, + /* 78 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, + { "movd", Ev, MX }, + { "movq", EM, MX }, + /* 80 */ + { "jo", Jv }, + { "jno", Jv }, + { "jb", Jv }, + { "jae", Jv }, + { "je", Jv }, + { "jne", Jv }, + { "jbe", Jv }, + { "ja", Jv }, + /* 88 */ + { "js", Jv }, + { "jns", Jv }, + { "jp", Jv }, + { "jnp", Jv }, + { "jl", Jv }, + { "jge", Jv }, + { "jle", Jv }, + { "jg", Jv }, + /* 90 */ + { "seto", Eb }, + { "setno", Eb }, + { "setb", Eb }, + { "setae", Eb }, + { "sete", Eb }, + { "setne", Eb }, + { "setbe", Eb }, + { "seta", Eb }, + /* 98 */ + { "sets", Eb }, + { "setns", Eb }, + { "setp", Eb }, + { "setnp", Eb }, + { "setl", Eb }, + { "setge", Eb }, + { "setle", Eb }, + { "setg", Eb }, + /* a0 */ + { "pushS", fs }, + { "popS", fs }, + { "cpuid" }, + { "btS", Ev, Gv }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)" }, + { "(bad)" }, + /* a8 */ + { "pushS", gs }, + { "popS", gs }, + { "rsm" }, + { "btsS", Ev, Gv }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { "(bad)" }, + { "imulS", Gv, Ev }, + /* b0 */ + { "cmpxchgb", Eb, Gb }, + { "cmpxchgS", Ev, Gv }, + { "lssS", Gv, Mp }, /* 386 lists only Mp */ + { "btrS", Ev, Gv }, + { "lfsS", Gv, Mp }, /* 386 lists only Mp */ + { "lgsS", Gv, Mp }, /* 386 lists only Mp */ + { "movzbS", Gv, Eb }, + { "movzwS", Gv, Ew }, + /* b8 */ + { "ud2b" }, + { "(bad)" }, + { GRP8 }, + { "btcS", Ev, Gv }, + { "bsfS", Gv, Ev }, + { "bsrS", Gv, Ev }, + { "movsbS", Gv, Eb }, + { "movswS", Gv, Ew }, + /* c0 */ + { "xaddb", Eb, Gb }, + { "xaddS", Ev, Gv }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { GRP9 }, + /* c8 */ + { "bswap", eAX }, + { "bswap", eCX }, + { "bswap", eDX }, + { "bswap", eBX }, + { "bswap", eSP }, + { "bswap", eBP }, + { "bswap", eSI }, + { "bswap", eDI }, + /* d0 */ + { "(bad)" }, + { "psrlw", MX, EM }, + { "psrld", MX, EM }, + { "psrlq", MX, EM }, + { "(bad)" }, + { "pmullw", MX, EM }, + { "(bad)" }, { "(bad)" }, + /* d8 */ + { "psubusb", MX, EM }, + { "psubusw", MX, EM }, + { "(bad)" }, + { "pand", MX, EM }, + { "paddusb", MX, EM }, + { "paddusw", MX, EM }, + { "(bad)" }, + { "pandn", MX, EM }, + /* e0 */ + { "(bad)" }, + { "psraw", MX, EM }, + { "psrad", MX, EM }, + { "(bad)" }, + { "(bad)" }, + { "pmulhw", MX, EM }, + { "(bad)" }, { "(bad)" }, + /* e8 */ + { "psubsb", MX, EM }, + { "psubsw", MX, EM }, + { "(bad)" }, + { "por", MX, EM }, + { "paddsb", MX, EM }, + { "paddsw", MX, EM }, + { "(bad)" }, + { "pxor", MX, EM }, + /* f0 */ + { "(bad)" }, + { "psllw", MX, EM }, + { "pslld", MX, EM }, + { "psllq", MX, EM }, + { "(bad)" }, + { "pmaddwd", MX, EM }, + { "(bad)" }, { "(bad)" }, + /* f8 */ + { "psubb", MX, EM }, + { "psubw", MX, EM }, + { "psubd", MX, EM }, + { "(bad)" }, + { "paddb", MX, EM }, + { "paddw", MX, EM }, + { "paddd", MX, EM }, + { "(bad)" } +}; + +static const unsigned char onebyte_has_modrm[256] = { + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 +}; + +static const unsigned char twobyte_has_modrm[256] = { + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, /* 6f */ + /* 70 */ 0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ + /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ + /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ + /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1, /* df */ + /* e0 */ 0,1,1,0,0,1,0,0,1,1,0,1,1,1,0,1, /* ef */ + /* f0 */ 0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0 /* ff */ +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static int mod; +static int rm; +static int reg; +static void oappend PARAMS ((char *s)); + +static char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; +static char *index16[] = { + "bx+si","bx+di","bp+si","bp+di","si","di","bp","bx" +}; + +static struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addb", Eb, Ib }, + { "orb", Eb, Ib }, + { "adcb", Eb, Ib }, + { "sbbb", Eb, Ib }, + { "andb", Eb, Ib }, + { "subb", Eb, Ib }, + { "xorb", Eb, Ib }, + { "cmpb", Eb, Ib } + }, + /* GRP1S */ + { + { "addS", Ev, Iv }, + { "orS", Ev, Iv }, + { "adcS", Ev, Iv }, + { "sbbS", Ev, Iv }, + { "andS", Ev, Iv }, + { "subS", Ev, Iv }, + { "xorS", Ev, Iv }, + { "cmpS", Ev, Iv } + }, + /* GRP1Ss */ + { + { "addS", Ev, sIb }, + { "orS", Ev, sIb }, + { "adcS", Ev, sIb }, + { "sbbS", Ev, sIb }, + { "andS", Ev, sIb }, + { "subS", Ev, sIb }, + { "xorS", Ev, sIb }, + { "cmpS", Ev, sIb } + }, + /* GRP2b */ + { + { "rolb", Eb, Ib }, + { "rorb", Eb, Ib }, + { "rclb", Eb, Ib }, + { "rcrb", Eb, Ib }, + { "shlb", Eb, Ib }, + { "shrb", Eb, Ib }, + { "(bad)" }, + { "sarb", Eb, Ib }, + }, + /* GRP2S */ + { + { "rolS", Ev, Ib }, + { "rorS", Ev, Ib }, + { "rclS", Ev, Ib }, + { "rcrS", Ev, Ib }, + { "shlS", Ev, Ib }, + { "shrS", Ev, Ib }, + { "(bad)" }, + { "sarS", Ev, Ib }, + }, + /* GRP2b_one */ + { + { "rolb", Eb }, + { "rorb", Eb }, + { "rclb", Eb }, + { "rcrb", Eb }, + { "shlb", Eb }, + { "shrb", Eb }, + { "(bad)" }, + { "sarb", Eb }, + }, + /* GRP2S_one */ + { + { "rolS", Ev }, + { "rorS", Ev }, + { "rclS", Ev }, + { "rcrS", Ev }, + { "shlS", Ev }, + { "shrS", Ev }, + { "(bad)" }, + { "sarS", Ev }, + }, + /* GRP2b_cl */ + { + { "rolb", Eb, CL }, + { "rorb", Eb, CL }, + { "rclb", Eb, CL }, + { "rcrb", Eb, CL }, + { "shlb", Eb, CL }, + { "shrb", Eb, CL }, + { "(bad)" }, + { "sarb", Eb, CL }, + }, + /* GRP2S_cl */ + { + { "rolS", Ev, CL }, + { "rorS", Ev, CL }, + { "rclS", Ev, CL }, + { "rcrS", Ev, CL }, + { "shlS", Ev, CL }, + { "shrS", Ev, CL }, + { "(bad)" }, + { "sarS", Ev, CL } + }, + /* GRP3b */ + { + { "testb", Eb, Ib }, + { "(bad)", Eb }, + { "notb", Eb }, + { "negb", Eb }, + { "mulb", AL, Eb }, + { "imulb", AL, Eb }, + { "divb", AL, Eb }, + { "idivb", AL, Eb } + }, + /* GRP3S */ + { + { "testS", Ev, Iv }, + { "(bad)" }, + { "notS", Ev }, + { "negS", Ev }, + { "mulS", eAX, Ev }, + { "imulS", eAX, Ev }, + { "divS", eAX, Ev }, + { "idivS", eAX, Ev }, + }, + /* GRP4 */ + { + { "incb", Eb }, + { "decb", Eb }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP5 */ + { + { "incS", Ev }, + { "decS", Ev }, + { "call", indirEv }, + { "lcall", indirEv }, + { "jmp", indirEv }, + { "ljmp", indirEv }, + { "pushS", Ev }, + { "(bad)" }, + }, + /* GRP6 */ + { + { "sldt", Ew }, + { "str", Ew }, + { "lldt", Ew }, + { "ltr", Ew }, + { "verr", Ew }, + { "verw", Ew }, + { "(bad)" }, + { "(bad)" } + }, + /* GRP7 */ + { + { "sgdt", Ew }, + { "sidt", Ew }, + { "lgdt", Ew }, + { "lidt", Ew }, + { "smsw", Ew }, + { "(bad)" }, + { "lmsw", Ew }, + { "invlpg", Ew }, + }, + /* GRP8 */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "btS", Ev, Ib }, + { "btsS", Ev, Ib }, + { "btrS", Ev, Ib }, + { "btcS", Ev, Ib }, + }, + /* GRP9 */ + { + { "(bad)" }, + { "cmpxchg8b", Ev }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP10 */ + { + { "(bad)" }, + { "(bad)" }, + { "psrlw", MS, Ib }, + { "(bad)" }, + { "psraw", MS, Ib }, + { "(bad)" }, + { "psllw", MS, Ib }, + { "(bad)" }, + }, + /* GRP11 */ + { + { "(bad)" }, + { "(bad)" }, + { "psrld", MS, Ib }, + { "(bad)" }, + { "psrad", MS, Ib }, + { "(bad)" }, + { "pslld", MS, Ib }, + { "(bad)" }, + }, + /* GRP12 */ + { + { "(bad)" }, + { "(bad)" }, + { "psrlq", MS, Ib }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "psllq", MS, Ib }, + { "(bad)" }, + } +}; + +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 + +static int prefixes; + +static void +ckprefix () +{ + prefixes = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADR; + break; + case 0x9b: + prefixes |= PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +static char op1out[100], op2out[100], op3out[100]; +static int op_address[3], op_ad, op_index[3]; +static int start_pc; + + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +int print_insn_x86 PARAMS ((bfd_vma pc, disassemble_info *info, int aflag, + int dflag)); +int +print_insn_i386 (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + if (info->mach == bfd_mach_i386_i386) + return print_insn_x86 (pc, info, 1, 1); + else if (info->mach == bfd_mach_i386_i8086) + return print_insn_x86 (pc, info, 0, 0); + else + abort (); +} + +int +print_insn_x86 (pc, info, aflag, dflag) + bfd_vma pc; + disassemble_info *info; + int aflag; + int dflag; +{ + struct dis386 *dp; + int i; + int enter_instruction; + char *first, *second, *third; + int needcomma; + unsigned char need_modrm; + + struct dis_private priv; + bfd_byte *inbuf = priv.the_buffer; + + /* The output looks better if we put 5 bytes on a line, since that + puts long word instructions on a single line. */ + info->bytes_per_line = 5; + + info->private_data = (PTR) &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + the_info = info; + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + + ckprefix (); + + FETCH_DATA (info, codep + 1); + if (*codep == 0xc8) + enter_instruction = 1; + else + enter_instruction = 0; + + obufp = obuf; + + if (prefixes & PREFIX_REPZ) + oappend ("repz "); + if (prefixes & PREFIX_REPNZ) + oappend ("repnz "); + if (prefixes & PREFIX_LOCK) + oappend ("lock "); + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + /* fwait not followed by floating point instruction */ + (*info->fprintf_func) (info->stream, "fwait"); + return (1); + } + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + + if (prefixes & PREFIX_ADR) + { + aflag ^= 1; + if (aflag) + oappend ("addr32 "); + else + oappend ("addr16 "); + } + + if (*codep == 0x0f) + { + FETCH_DATA (info, codep + 2); + dp = &dis386_twobyte[*++codep]; + need_modrm = twobyte_has_modrm[*codep]; + } + else + { + dp = &dis386[*codep]; + need_modrm = onebyte_has_modrm[*codep]; + } + codep++; + + if (need_modrm) + { + FETCH_DATA (info, codep + 1); + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + } + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (aflag, dflag); + } + else + { + if (dp->name == NULL) + dp = &grps[dp->bytemode1][reg]; + + putop (dp->name, aflag, dflag); + + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1)(dp->bytemode1, aflag, dflag); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2)(dp->bytemode2, aflag, dflag); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3, aflag, dflag); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* enter instruction is printed with operands in the + * same order as the intel book; everything else + * is printed in reverse order + */ + if (enter_instruction) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1) + (*info->print_address_func) (op_address[op_index[0]], info); + else + (*info->fprintf_func) (info->stream, "%s", first); + needcomma = 1; + } + if (*second) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[1] != -1) + (*info->print_address_func) (op_address[op_index[1]], info); + else + (*info->fprintf_func) (info->stream, "%s", second); + needcomma = 1; + } + if (*third) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[2] != -1) + (*info->print_address_func) (op_address[op_index[2]], info); + else + (*info->fprintf_func) (info->stream, "%s", third); + } + return (codep - inbuf); +} + +static char *float_mem[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 + +#define FGRPd9_2 NULL, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1 +#define FGRPd9_5 NULL, NULL, 2 +#define FGRPd9_6 NULL, NULL, 3 +#define FGRPd9_7 NULL, NULL, 4 +#define FGRPda_5 NULL, NULL, 5 +#define FGRPdb_4 NULL, NULL, 6 +#define FGRPde_3 NULL, NULL, 7 +#define FGRPdf_4 NULL, NULL, 8 + +static struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi }, + { "fmul", ST, STi }, + { "fcom", STi }, + { "fcomp", STi }, + { "fsub", ST, STi }, + { "fsubr", ST, STi }, + { "fdiv", ST, STi }, + { "fdivr", ST, STi }, + }, + /* d9 */ + { + { "fld", STi }, + { "fxch", STi }, + { FGRPd9_2 }, + { "(bad)" }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "fcmovb", ST, STi }, + { "fcmove", ST, STi }, + { "fcmovbe",ST, STi }, + { "fcmovu", ST, STi }, + { "(bad)" }, + { FGRPda_5 }, + { "(bad)" }, + { "(bad)" }, + }, + /* db */ + { + { "fcmovnb",ST, STi }, + { "fcmovne",ST, STi }, + { "fcmovnbe",ST, STi }, + { "fcmovnu",ST, STi }, + { FGRPdb_4 }, + { "fucomi", ST, STi }, + { "fcomi", ST, STi }, + { "(bad)" }, + }, + /* dc */ + { + { "fadd", STi, ST }, + { "fmul", STi, ST }, + { "(bad)" }, + { "(bad)" }, + { "fsub", STi, ST }, + { "fsubr", STi, ST }, + { "fdiv", STi, ST }, + { "fdivr", STi, ST }, + }, + /* dd */ + { + { "ffree", STi }, + { "(bad)" }, + { "fst", STi }, + { "fstp", STi }, + { "fucom", STi }, + { "fucomp", STi }, + { "(bad)" }, + { "(bad)" }, + }, + /* de */ + { + { "faddp", STi, ST }, + { "fmulp", STi, ST }, + { "(bad)" }, + { FGRPde_3 }, + { "fsubp", STi, ST }, + { "fsubrp", STi, ST }, + { "fdivp", STi, ST }, + { "fdivrp", STi, ST }, + }, + /* df */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdf_4 }, + { "fucomip",ST, STi }, + { "fcomip", ST, STi }, + { "(bad)" }, + }, +}; + + +static char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat (aflag, dflag) + int aflag; + int dflag; +{ + struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + putop (float_mem[(floatop - 0xd8) * 8 + reg], aflag, dflag); + obufp = op1out; + OP_E (v_mode, aflag, dflag); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm], aflag, dflag); + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf + && FETCH_DATA (the_info, codep + 1) + && *codep == 0xe0) + strcpy (op1out, "%eax"); + } + else + { + putop (dp->name, aflag, dflag); + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1, aflag, dflag); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2, aflag, dflag); + } +} + +/* ARGSUSED */ +static int +OP_ST (ignore, aflag, dflag) + int ignore; + int aflag; + int dflag; +{ + oappend ("%st"); + return (0); +} + +/* ARGSUSED */ +static int +OP_STi (ignore, aflag, dflag) + int ignore; + int aflag; + int dflag; +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); + return (0); +} + + +/* capital letters in template are macros */ +static void +putop (template, aflag, dflag) + char *template; + int aflag; + int dflag; +{ + char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'C': /* For jcxz/jecxz */ + if (aflag) + *obufp++ = 'e'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + break; + case 'S': + /* operand size flag */ + if (dflag) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + break; + case 'W': + /* operand size flag for cwtl, cbtw */ + if (dflag) + *obufp++ = 'w'; + else + *obufp++ = 'b'; + break; + } + } + *obufp = 0; +} + +static void +oappend (s) + char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); + *obufp = 0; +} + +static void +append_prefix () +{ + if (prefixes & PREFIX_CS) + oappend ("%cs:"); + if (prefixes & PREFIX_DS) + oappend ("%ds:"); + if (prefixes & PREFIX_SS) + oappend ("%ss:"); + if (prefixes & PREFIX_ES) + oappend ("%es:"); + if (prefixes & PREFIX_FS) + oappend ("%fs:"); + if (prefixes & PREFIX_GS) + oappend ("%gs:"); +} + +static int +OP_indirE (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + oappend ("*"); + return OP_E (bytemode, aflag, dflag); +} + +static int +OP_E (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int disp; + + /* skip mod/rm byte */ + codep++; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case v_mode: + if (dflag) + oappend (names32[rm]); + else + oappend (names16[rm]); + break; + default: + oappend (""); + break; + } + return 0; + } + + disp = 0; + append_prefix (); + + if (aflag) /* 32 bit address mode */ + { + int havesib; + int havebase; + int base; + int index = 0; + int scale = 0; + + havesib = 0; + havebase = 1; + base = rm; + + if (base == 4) + { + havesib = 1; + FETCH_DATA (the_info, codep + 1); + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + if (base == 5) + { + havebase = 0; + disp = get32 (); + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get32 (); + break; + } + + if (mod != 0 || base == 5) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (havebase || (havesib && (index != 4 || scale != 0))) + { + oappend ("("); + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + sprintf (scratchbuf, ",%d", 1 << scale); + oappend (scratchbuf); + } + oappend (")"); + } + } + else + { /* 16 bit address mode */ + switch (mod) + { + case 0: + if (rm == 6) + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + break; + } + + if (mod != 0 || rm == 6) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (mod != 0 || rm != 6) + { + oappend ("("); + oappend (index16[rm]); + oappend (")"); + } + } + return 0; +} + +static int +OP_G (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (dflag) + oappend (names32[reg]); + else + oappend (names16[reg]); + break; + default: + oappend (""); + break; + } + return (0); +} + +static int +get32 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return (x); +} + +static int +get16 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return (x); +} + +static void +set_op (op) + int op; +{ + op_index[op_ad] = op_ad; + op_address[op_ad] = op; +} + +static int +OP_REG (code, aflag, dflag) + int code; + int aflag; + int dflag; +{ + char *s; + + switch (code) + { + case indir_dx_reg: s = "(%dx)"; break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (dflag) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + break; + default: + s = ""; + break; + } + oappend (s); + return (0); +} + +static int +OP_I (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++ & 0xff; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = get16 (); + break; + case w_mode: + op = get16 (); + break; + default: + oappend (""); + return (0); + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + return (0); +} + +static int +OP_sI (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + if ((op & 0x80) != 0) + op -= 0x100; + break; + case v_mode: + if (dflag) + op = get32 (); + else + { + op = get16(); + if ((op & 0x8000) != 0) + op -= 0x10000; + } + break; + case w_mode: + op = get16 (); + if ((op & 0x8000) != 0) + op -= 0x10000; + break; + default: + oappend (""); + return (0); + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + return (0); +} + +static int +OP_J (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case v_mode: + if (dflag) + disp = get32 (); + else + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + break; + default: + oappend (""); + return (0); + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp); + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +static int +OP_SEG (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); + return (0); +} + +static int +OP_DIR (size, aflag, dflag) + int size; + int aflag; + int dflag; +{ + int seg, offset; + + switch (size) + { + case lptr: + if (aflag) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + oappend (scratchbuf); + break; + case v_mode: + if (aflag) + offset = get32 (); + else + { + offset = get16 (); + if ((offset & 0x8000) != 0) + offset -= 0x10000; + } + + offset = start_pc + codep - start_codep + offset; + set_op (offset); + sprintf (scratchbuf, "0x%x", offset); + oappend (scratchbuf); + break; + default: + oappend (""); + break; + } + return (0); +} + +/* ARGSUSED */ +static int +OP_OFF (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int off; + + append_prefix (); + + if (aflag) + off = get32 (); + else + off = get16 (); + + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +static int +OP_ESDI (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + oappend ("%es:("); + oappend (aflag ? "%edi" : "%di"); + oappend (")"); + return (0); +} + +/* ARGSUSED */ +static int +OP_DSSI (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + if ((prefixes + & (PREFIX_CS + | PREFIX_DS + | PREFIX_SS + | PREFIX_ES + | PREFIX_FS + | PREFIX_GS)) == 0) + prefixes |= PREFIX_DS; + append_prefix (); + oappend ("("); + oappend (aflag ? "%esi" : "%si"); + oappend (")"); + return (0); +} + +#if 0 +/* Not used. */ + +/* ARGSUSED */ +static int +OP_ONE (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + oappend ("1"); + return (0); +} + +#endif + +/* ARGSUSED */ +static int +OP_C (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +static int +OP_D (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +static int +OP_T (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); + return (0); +} + +static int +OP_rm (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + switch (bytemode) + { + case d_mode: + oappend (names32[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + } + return (0); +} + +static int +OP_MMX (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + sprintf (scratchbuf, "%%mm%d", reg); + oappend (scratchbuf); + return 0; +} + +static int +OP_EM (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + if (mod != 3) + return OP_E (bytemode, aflag, dflag); + + codep++; + sprintf (scratchbuf, "%%mm%d", rm); + oappend (scratchbuf); + return 0; +} + +static int +OP_MS (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + ++codep; + sprintf (scratchbuf, "%%mm%d", rm); + oappend (scratchbuf); + return 0; +} diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1e7dcedbd..e6f04a840 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1000,7 +1000,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(setsid()); break; case TARGET_NR_sigaction: -#if 1 +#if 0 { ret = 0; } diff --git a/op-i386.c b/op-i386.c index f8188e3ea..002ce9692 100644 --- a/op-i386.c +++ b/op-i386.c @@ -177,7 +177,7 @@ void raise_exception(int exception_index) #undef REG #undef REGNAME -/* operations */ +/* operations with flags */ void OPPROTO op_addl_T0_T1_cc(void) { @@ -217,11 +217,6 @@ void OPPROTO op_cmpl_T0_T1_cc(void) CC_DST = T0 - T1; } -void OPPROTO op_notl_T0(void) -{ - T0 = ~T0; -} - void OPPROTO op_negl_T0_cc(void) { CC_SRC = 0; @@ -248,6 +243,53 @@ void OPPROTO op_testl_T0_T1_cc(void) CC_DST = T0 & T1; } +/* operations without flags */ + +void OPPROTO op_addl_T0_T1(void) +{ + T0 += T1; +} + +void OPPROTO op_orl_T0_T1(void) +{ + T0 |= T1; +} + +void OPPROTO op_andl_T0_T1(void) +{ + T0 &= T1; +} + +void OPPROTO op_subl_T0_T1(void) +{ + T0 -= T1; +} + +void OPPROTO op_xorl_T0_T1(void) +{ + T0 ^= T1; +} + +void OPPROTO op_negl_T0(void) +{ + T0 = -T0; +} + +void OPPROTO op_incl_T0(void) +{ + T0++; +} + +void OPPROTO op_decl_T0(void) +{ + T0--; +} + +void OPPROTO op_notl_T0(void) +{ + T0 = ~T0; +} + void OPPROTO op_bswapl_T0(void) { T0 = bswap32(T0); diff --git a/opc-i386.h b/opc-i386.h new file mode 100644 index 000000000..aae289419 --- /dev/null +++ b/opc-i386.h @@ -0,0 +1,518 @@ +DEF(end) +DEF(movl_A0_EAX) +DEF(addl_A0_EAX) +DEF(addl_A0_EAX_s1) +DEF(addl_A0_EAX_s2) +DEF(addl_A0_EAX_s3) +DEF(movl_T0_EAX) +DEF(movl_T1_EAX) +DEF(movh_T0_EAX) +DEF(movh_T1_EAX) +DEF(movl_EAX_T0) +DEF(movl_EAX_T1) +DEF(movl_EAX_A0) +DEF(cmovw_EAX_T1_T0) +DEF(cmovl_EAX_T1_T0) +DEF(movw_EAX_T0) +DEF(movw_EAX_T1) +DEF(movw_EAX_A0) +DEF(movb_EAX_T0) +DEF(movh_EAX_T0) +DEF(movb_EAX_T1) +DEF(movh_EAX_T1) +DEF(movl_A0_ECX) +DEF(addl_A0_ECX) +DEF(addl_A0_ECX_s1) +DEF(addl_A0_ECX_s2) +DEF(addl_A0_ECX_s3) +DEF(movl_T0_ECX) +DEF(movl_T1_ECX) +DEF(movh_T0_ECX) +DEF(movh_T1_ECX) +DEF(movl_ECX_T0) +DEF(movl_ECX_T1) +DEF(movl_ECX_A0) +DEF(cmovw_ECX_T1_T0) +DEF(cmovl_ECX_T1_T0) +DEF(movw_ECX_T0) +DEF(movw_ECX_T1) +DEF(movw_ECX_A0) +DEF(movb_ECX_T0) +DEF(movh_ECX_T0) +DEF(movb_ECX_T1) +DEF(movh_ECX_T1) +DEF(movl_A0_EDX) +DEF(addl_A0_EDX) +DEF(addl_A0_EDX_s1) +DEF(addl_A0_EDX_s2) +DEF(addl_A0_EDX_s3) +DEF(movl_T0_EDX) +DEF(movl_T1_EDX) +DEF(movh_T0_EDX) +DEF(movh_T1_EDX) +DEF(movl_EDX_T0) +DEF(movl_EDX_T1) +DEF(movl_EDX_A0) +DEF(cmovw_EDX_T1_T0) +DEF(cmovl_EDX_T1_T0) +DEF(movw_EDX_T0) +DEF(movw_EDX_T1) +DEF(movw_EDX_A0) +DEF(movb_EDX_T0) +DEF(movh_EDX_T0) +DEF(movb_EDX_T1) +DEF(movh_EDX_T1) +DEF(movl_A0_EBX) +DEF(addl_A0_EBX) +DEF(addl_A0_EBX_s1) +DEF(addl_A0_EBX_s2) +DEF(addl_A0_EBX_s3) +DEF(movl_T0_EBX) +DEF(movl_T1_EBX) +DEF(movh_T0_EBX) +DEF(movh_T1_EBX) +DEF(movl_EBX_T0) +DEF(movl_EBX_T1) +DEF(movl_EBX_A0) +DEF(cmovw_EBX_T1_T0) +DEF(cmovl_EBX_T1_T0) +DEF(movw_EBX_T0) +DEF(movw_EBX_T1) +DEF(movw_EBX_A0) +DEF(movb_EBX_T0) +DEF(movh_EBX_T0) +DEF(movb_EBX_T1) +DEF(movh_EBX_T1) +DEF(movl_A0_ESP) +DEF(addl_A0_ESP) +DEF(addl_A0_ESP_s1) +DEF(addl_A0_ESP_s2) +DEF(addl_A0_ESP_s3) +DEF(movl_T0_ESP) +DEF(movl_T1_ESP) +DEF(movh_T0_ESP) +DEF(movh_T1_ESP) +DEF(movl_ESP_T0) +DEF(movl_ESP_T1) +DEF(movl_ESP_A0) +DEF(cmovw_ESP_T1_T0) +DEF(cmovl_ESP_T1_T0) +DEF(movw_ESP_T0) +DEF(movw_ESP_T1) +DEF(movw_ESP_A0) +DEF(movb_ESP_T0) +DEF(movh_ESP_T0) +DEF(movb_ESP_T1) +DEF(movh_ESP_T1) +DEF(movl_A0_EBP) +DEF(addl_A0_EBP) +DEF(addl_A0_EBP_s1) +DEF(addl_A0_EBP_s2) +DEF(addl_A0_EBP_s3) +DEF(movl_T0_EBP) +DEF(movl_T1_EBP) +DEF(movh_T0_EBP) +DEF(movh_T1_EBP) +DEF(movl_EBP_T0) +DEF(movl_EBP_T1) +DEF(movl_EBP_A0) +DEF(cmovw_EBP_T1_T0) +DEF(cmovl_EBP_T1_T0) +DEF(movw_EBP_T0) +DEF(movw_EBP_T1) +DEF(movw_EBP_A0) +DEF(movb_EBP_T0) +DEF(movh_EBP_T0) +DEF(movb_EBP_T1) +DEF(movh_EBP_T1) +DEF(movl_A0_ESI) +DEF(addl_A0_ESI) +DEF(addl_A0_ESI_s1) +DEF(addl_A0_ESI_s2) +DEF(addl_A0_ESI_s3) +DEF(movl_T0_ESI) +DEF(movl_T1_ESI) +DEF(movh_T0_ESI) +DEF(movh_T1_ESI) +DEF(movl_ESI_T0) +DEF(movl_ESI_T1) +DEF(movl_ESI_A0) +DEF(cmovw_ESI_T1_T0) +DEF(cmovl_ESI_T1_T0) +DEF(movw_ESI_T0) +DEF(movw_ESI_T1) +DEF(movw_ESI_A0) +DEF(movb_ESI_T0) +DEF(movh_ESI_T0) +DEF(movb_ESI_T1) +DEF(movh_ESI_T1) +DEF(movl_A0_EDI) +DEF(addl_A0_EDI) +DEF(addl_A0_EDI_s1) +DEF(addl_A0_EDI_s2) +DEF(addl_A0_EDI_s3) +DEF(movl_T0_EDI) +DEF(movl_T1_EDI) +DEF(movh_T0_EDI) +DEF(movh_T1_EDI) +DEF(movl_EDI_T0) +DEF(movl_EDI_T1) +DEF(movl_EDI_A0) +DEF(cmovw_EDI_T1_T0) +DEF(cmovl_EDI_T1_T0) +DEF(movw_EDI_T0) +DEF(movw_EDI_T1) +DEF(movw_EDI_A0) +DEF(movb_EDI_T0) +DEF(movh_EDI_T0) +DEF(movb_EDI_T1) +DEF(movh_EDI_T1) +DEF(addl_T0_T1_cc) +DEF(orl_T0_T1_cc) +DEF(andl_T0_T1_cc) +DEF(subl_T0_T1_cc) +DEF(xorl_T0_T1_cc) +DEF(cmpl_T0_T1_cc) +DEF(negl_T0_cc) +DEF(incl_T0_cc) +DEF(decl_T0_cc) +DEF(testl_T0_T1_cc) +DEF(addl_T0_T1) +DEF(orl_T0_T1) +DEF(andl_T0_T1) +DEF(subl_T0_T1) +DEF(xorl_T0_T1) +DEF(negl_T0) +DEF(incl_T0) +DEF(decl_T0) +DEF(notl_T0) +DEF(bswapl_T0) +DEF(mulb_AL_T0) +DEF(imulb_AL_T0) +DEF(mulw_AX_T0) +DEF(imulw_AX_T0) +DEF(mull_EAX_T0) +DEF(imull_EAX_T0) +DEF(imulw_T0_T1) +DEF(imull_T0_T1) +DEF(divb_AL_T0) +DEF(idivb_AL_T0) +DEF(divw_AX_T0) +DEF(idivw_AX_T0) +DEF(divl_EAX_T0) +DEF(idivl_EAX_T0) +DEF(movl_T0_im) +DEF(movl_T1_im) +DEF(movl_A0_im) +DEF(addl_A0_im) +DEF(andl_A0_ffff) +DEF(ldub_T0_A0) +DEF(ldsb_T0_A0) +DEF(lduw_T0_A0) +DEF(ldsw_T0_A0) +DEF(ldl_T0_A0) +DEF(ldub_T1_A0) +DEF(ldsb_T1_A0) +DEF(lduw_T1_A0) +DEF(ldsw_T1_A0) +DEF(ldl_T1_A0) +DEF(stb_T0_A0) +DEF(stw_T0_A0) +DEF(stl_T0_A0) +DEF(add_bitw_A0_T1) +DEF(add_bitl_A0_T1) +DEF(jmp_T0) +DEF(jmp_im) +DEF(int_im) +DEF(int3) +DEF(into) +DEF(jb_subb) +DEF(jz_subb) +DEF(jbe_subb) +DEF(js_subb) +DEF(jl_subb) +DEF(jle_subb) +DEF(setb_T0_subb) +DEF(setz_T0_subb) +DEF(setbe_T0_subb) +DEF(sets_T0_subb) +DEF(setl_T0_subb) +DEF(setle_T0_subb) +DEF(rolb_T0_T1_cc) +DEF(rolb_T0_T1) +DEF(rorb_T0_T1_cc) +DEF(rorb_T0_T1) +DEF(rclb_T0_T1_cc) +DEF(rcrb_T0_T1_cc) +DEF(shlb_T0_T1_cc) +DEF(shlb_T0_T1) +DEF(shrb_T0_T1_cc) +DEF(shrb_T0_T1) +DEF(sarb_T0_T1_cc) +DEF(sarb_T0_T1) +DEF(adcb_T0_T1_cc) +DEF(sbbb_T0_T1_cc) +DEF(cmpxchgb_T0_T1_EAX_cc) +DEF(movsb) +DEF(rep_movsb) +DEF(stosb) +DEF(rep_stosb) +DEF(lodsb) +DEF(rep_lodsb) +DEF(scasb) +DEF(repz_scasb) +DEF(repnz_scasb) +DEF(cmpsb) +DEF(repz_cmpsb) +DEF(repnz_cmpsb) +DEF(outsb) +DEF(rep_outsb) +DEF(insb) +DEF(rep_insb) +DEF(outb_T0_T1) +DEF(inb_T0_T1) +DEF(jb_subw) +DEF(jz_subw) +DEF(jbe_subw) +DEF(js_subw) +DEF(jl_subw) +DEF(jle_subw) +DEF(loopnzw) +DEF(loopzw) +DEF(loopw) +DEF(jecxzw) +DEF(setb_T0_subw) +DEF(setz_T0_subw) +DEF(setbe_T0_subw) +DEF(sets_T0_subw) +DEF(setl_T0_subw) +DEF(setle_T0_subw) +DEF(rolw_T0_T1_cc) +DEF(rolw_T0_T1) +DEF(rorw_T0_T1_cc) +DEF(rorw_T0_T1) +DEF(rclw_T0_T1_cc) +DEF(rcrw_T0_T1_cc) +DEF(shlw_T0_T1_cc) +DEF(shlw_T0_T1) +DEF(shrw_T0_T1_cc) +DEF(shrw_T0_T1) +DEF(sarw_T0_T1_cc) +DEF(sarw_T0_T1) +DEF(shldw_T0_T1_im_cc) +DEF(shldw_T0_T1_ECX_cc) +DEF(shrdw_T0_T1_im_cc) +DEF(shrdw_T0_T1_ECX_cc) +DEF(adcw_T0_T1_cc) +DEF(sbbw_T0_T1_cc) +DEF(cmpxchgw_T0_T1_EAX_cc) +DEF(btw_T0_T1_cc) +DEF(btsw_T0_T1_cc) +DEF(btrw_T0_T1_cc) +DEF(btcw_T0_T1_cc) +DEF(bsfw_T0_cc) +DEF(bsrw_T0_cc) +DEF(movsw) +DEF(rep_movsw) +DEF(stosw) +DEF(rep_stosw) +DEF(lodsw) +DEF(rep_lodsw) +DEF(scasw) +DEF(repz_scasw) +DEF(repnz_scasw) +DEF(cmpsw) +DEF(repz_cmpsw) +DEF(repnz_cmpsw) +DEF(outsw) +DEF(rep_outsw) +DEF(insw) +DEF(rep_insw) +DEF(outw_T0_T1) +DEF(inw_T0_T1) +DEF(jb_subl) +DEF(jz_subl) +DEF(jbe_subl) +DEF(js_subl) +DEF(jl_subl) +DEF(jle_subl) +DEF(loopnzl) +DEF(loopzl) +DEF(loopl) +DEF(jecxzl) +DEF(setb_T0_subl) +DEF(setz_T0_subl) +DEF(setbe_T0_subl) +DEF(sets_T0_subl) +DEF(setl_T0_subl) +DEF(setle_T0_subl) +DEF(roll_T0_T1_cc) +DEF(roll_T0_T1) +DEF(rorl_T0_T1_cc) +DEF(rorl_T0_T1) +DEF(rcll_T0_T1_cc) +DEF(rcrl_T0_T1_cc) +DEF(shll_T0_T1_cc) +DEF(shll_T0_T1) +DEF(shrl_T0_T1_cc) +DEF(shrl_T0_T1) +DEF(sarl_T0_T1_cc) +DEF(sarl_T0_T1) +DEF(shldl_T0_T1_im_cc) +DEF(shldl_T0_T1_ECX_cc) +DEF(shrdl_T0_T1_im_cc) +DEF(shrdl_T0_T1_ECX_cc) +DEF(adcl_T0_T1_cc) +DEF(sbbl_T0_T1_cc) +DEF(cmpxchgl_T0_T1_EAX_cc) +DEF(btl_T0_T1_cc) +DEF(btsl_T0_T1_cc) +DEF(btrl_T0_T1_cc) +DEF(btcl_T0_T1_cc) +DEF(bsfl_T0_cc) +DEF(bsrl_T0_cc) +DEF(movsl) +DEF(rep_movsl) +DEF(stosl) +DEF(rep_stosl) +DEF(lodsl) +DEF(rep_lodsl) +DEF(scasl) +DEF(repz_scasl) +DEF(repnz_scasl) +DEF(cmpsl) +DEF(repz_cmpsl) +DEF(repnz_cmpsl) +DEF(outsl) +DEF(rep_outsl) +DEF(insl) +DEF(rep_insl) +DEF(outl_T0_T1) +DEF(inl_T0_T1) +DEF(movsbl_T0_T0) +DEF(movzbl_T0_T0) +DEF(movswl_T0_T0) +DEF(movzwl_T0_T0) +DEF(movswl_EAX_AX) +DEF(movsbw_AX_AL) +DEF(movslq_EDX_EAX) +DEF(movswl_DX_AX) +DEF(pushl_T0) +DEF(pushl_T1) +DEF(popl_T0) +DEF(addl_ESP_im) +DEF(pushal) +DEF(pushaw) +DEF(popal) +DEF(popaw) +DEF(enterl) +DEF(rdtsc) +DEF(aam) +DEF(aad) +DEF(aaa) +DEF(aas) +DEF(daa) +DEF(das) +DEF(movl_seg_T0) +DEF(movl_T0_seg) +DEF(addl_A0_seg) +DEF(jo_cc) +DEF(jb_cc) +DEF(jz_cc) +DEF(jbe_cc) +DEF(js_cc) +DEF(jp_cc) +DEF(jl_cc) +DEF(jle_cc) +DEF(seto_T0_cc) +DEF(setb_T0_cc) +DEF(setz_T0_cc) +DEF(setbe_T0_cc) +DEF(sets_T0_cc) +DEF(setp_T0_cc) +DEF(setl_T0_cc) +DEF(setle_T0_cc) +DEF(xor_T0_1) +DEF(set_cc_op) +DEF(movl_eflags_T0) +DEF(movb_eflags_T0) +DEF(movl_T0_eflags) +DEF(cld) +DEF(std) +DEF(clc) +DEF(stc) +DEF(cmc) +DEF(salc) +DEF(flds_FT0_A0) +DEF(fldl_FT0_A0) +DEF(fild_FT0_A0) +DEF(fildl_FT0_A0) +DEF(fildll_FT0_A0) +DEF(flds_ST0_A0) +DEF(fldl_ST0_A0) +DEF(fldt_ST0_A0) +DEF(fild_ST0_A0) +DEF(fildl_ST0_A0) +DEF(fildll_ST0_A0) +DEF(fsts_ST0_A0) +DEF(fstl_ST0_A0) +DEF(fstt_ST0_A0) +DEF(fist_ST0_A0) +DEF(fistl_ST0_A0) +DEF(fistll_ST0_A0) +DEF(fbld_ST0_A0) +DEF(fbst_ST0_A0) +DEF(fpush) +DEF(fpop) +DEF(fdecstp) +DEF(fincstp) +DEF(fmov_ST0_FT0) +DEF(fmov_FT0_STN) +DEF(fmov_ST0_STN) +DEF(fmov_STN_ST0) +DEF(fxchg_ST0_STN) +DEF(fcom_ST0_FT0) +DEF(fucom_ST0_FT0) +DEF(fadd_ST0_FT0) +DEF(fmul_ST0_FT0) +DEF(fsub_ST0_FT0) +DEF(fsubr_ST0_FT0) +DEF(fdiv_ST0_FT0) +DEF(fdivr_ST0_FT0) +DEF(fadd_STN_ST0) +DEF(fmul_STN_ST0) +DEF(fsub_STN_ST0) +DEF(fsubr_STN_ST0) +DEF(fdiv_STN_ST0) +DEF(fdivr_STN_ST0) +DEF(fchs_ST0) +DEF(fabs_ST0) +DEF(fxam_ST0) +DEF(fld1_ST0) +DEF(fldl2t_ST0) +DEF(fldl2e_ST0) +DEF(fldpi_ST0) +DEF(fldlg2_ST0) +DEF(fldln2_ST0) +DEF(fldz_ST0) +DEF(fldz_FT0) +DEF(f2xm1) +DEF(fyl2x) +DEF(fptan) +DEF(fpatan) +DEF(fxtract) +DEF(fprem1) +DEF(fprem) +DEF(fyl2xp1) +DEF(fsqrt) +DEF(fsincos) +DEF(frndint) +DEF(fscale) +DEF(fsin) +DEF(fcos) +DEF(fnstsw_A0) +DEF(fnstsw_EAX) +DEF(fnstcw_A0) +DEF(fldcw_A0) +DEF(fclex) +DEF(fninit) diff --git a/ops_template.h b/ops_template.h index 8905d9084..f8cd5e54c 100644 --- a/ops_template.h +++ b/ops_template.h @@ -385,7 +385,6 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) { int count, src; - /* XXX: testing */ count = T1 & SHIFT_MASK; if (count) { CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); @@ -399,6 +398,17 @@ void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) FORCE_RET(); } +void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & SHIFT_MASK; + if (count) { + T0 &= DATA_MASK; + T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); + } + FORCE_RET(); +} + void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) { int count, src; @@ -415,6 +425,17 @@ void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) FORCE_RET(); } +void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & SHIFT_MASK; + if (count) { + T0 &= DATA_MASK; + T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); + } + FORCE_RET(); +} + void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) { int count, res, eflags; @@ -482,6 +503,14 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) FORCE_RET(); } +void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & 0x1f; + T0 = T0 << count; + FORCE_RET(); +} + void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) { int count; @@ -496,6 +525,15 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) FORCE_RET(); } +void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & 0x1f; + T0 &= DATA_MASK; + T0 = T0 >> count; + FORCE_RET(); +} + void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) { int count, src; @@ -510,6 +548,15 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) FORCE_RET(); } +void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) +{ + int count, src; + count = T1 & 0x1f; + src = (DATA_STYPE)T0; + T0 = src >> count; + FORCE_RET(); +} + #if DATA_BITS == 16 /* XXX: overflow flag might be incorrect in some cases in shldw */ void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) diff --git a/translate-i386.c b/translate-i386.c index 9bf7f5607..f02c5ea67 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -38,7 +38,8 @@ #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif -static uint8_t *gen_code_ptr; +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; int __op_param1, __op_param2, __op_param3; extern FILE *logfile; @@ -95,6 +96,13 @@ enum { OP_SAR = 7, }; +enum { +#define DEF(s) INDEX_op_ ## s, +#include "opc-i386.h" +#undef DEF + NB_OPS, +}; + #include "op-i386.h" /* operand size */ @@ -1922,7 +1930,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (mod == 3) goto illegal_op; gen_op_ld_T1_A0[ot](); - op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ gen_op_lduw_T0_A0(); gen_movl_seg_T0(s, op); @@ -2842,24 +2850,350 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) return -1; } +#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) +#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P) + +/* flags read by an operation */ +static uint16_t opc_read_flags[NB_OPS] = { + [INDEX_op_aas] = CC_A, + [INDEX_op_aaa] = CC_A, + [INDEX_op_das] = CC_A | CC_C, + [INDEX_op_daa] = CC_A | CC_C, + + [INDEX_op_adcb_T0_T1_cc] = CC_C, + [INDEX_op_adcw_T0_T1_cc] = CC_C, + [INDEX_op_adcl_T0_T1_cc] = CC_C, + [INDEX_op_sbbb_T0_T1_cc] = CC_C, + [INDEX_op_sbbw_T0_T1_cc] = CC_C, + [INDEX_op_sbbl_T0_T1_cc] = CC_C, + + [INDEX_op_into] = CC_O, + + [INDEX_op_jo_cc] = CC_O, + [INDEX_op_jb_cc] = CC_C, + [INDEX_op_jz_cc] = CC_Z, + [INDEX_op_jbe_cc] = CC_Z | CC_C, + [INDEX_op_js_cc] = CC_S, + [INDEX_op_jp_cc] = CC_P, + [INDEX_op_jl_cc] = CC_O | CC_S, + [INDEX_op_jle_cc] = CC_O | CC_S | CC_Z, + + [INDEX_op_jb_subb] = CC_C, + [INDEX_op_jb_subw] = CC_C, + [INDEX_op_jb_subl] = CC_C, + + [INDEX_op_jz_subb] = CC_Z, + [INDEX_op_jz_subw] = CC_Z, + [INDEX_op_jz_subl] = CC_Z, + + [INDEX_op_jbe_subb] = CC_Z | CC_C, + [INDEX_op_jbe_subw] = CC_Z | CC_C, + [INDEX_op_jbe_subl] = CC_Z | CC_C, + + [INDEX_op_js_subb] = CC_S, + [INDEX_op_js_subw] = CC_S, + [INDEX_op_js_subl] = CC_S, + + [INDEX_op_jl_subb] = CC_O | CC_S, + [INDEX_op_jl_subw] = CC_O | CC_S, + [INDEX_op_jl_subl] = CC_O | CC_S, + + [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z, + [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z, + [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z, + + [INDEX_op_loopnzw] = CC_Z, + [INDEX_op_loopnzl] = CC_Z, + [INDEX_op_loopzw] = CC_Z, + [INDEX_op_loopzl] = CC_Z, + + [INDEX_op_seto_T0_cc] = CC_O, + [INDEX_op_setb_T0_cc] = CC_C, + [INDEX_op_setz_T0_cc] = CC_Z, + [INDEX_op_setbe_T0_cc] = CC_Z | CC_C, + [INDEX_op_sets_T0_cc] = CC_S, + [INDEX_op_setp_T0_cc] = CC_P, + [INDEX_op_setl_T0_cc] = CC_O | CC_S, + [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z, + + [INDEX_op_setb_T0_subb] = CC_C, + [INDEX_op_setb_T0_subw] = CC_C, + [INDEX_op_setb_T0_subl] = CC_C, + + [INDEX_op_setz_T0_subb] = CC_Z, + [INDEX_op_setz_T0_subw] = CC_Z, + [INDEX_op_setz_T0_subl] = CC_Z, + + [INDEX_op_setbe_T0_subb] = CC_Z | CC_C, + [INDEX_op_setbe_T0_subw] = CC_Z | CC_C, + [INDEX_op_setbe_T0_subl] = CC_Z | CC_C, + + [INDEX_op_sets_T0_subb] = CC_S, + [INDEX_op_sets_T0_subw] = CC_S, + [INDEX_op_sets_T0_subl] = CC_S, + + [INDEX_op_setl_T0_subb] = CC_O | CC_S, + [INDEX_op_setl_T0_subw] = CC_O | CC_S, + [INDEX_op_setl_T0_subl] = CC_O | CC_S, + + [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z, + [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z, + [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, + + [INDEX_op_movl_T0_eflags] = CC_OSZAPC, + [INDEX_op_cmc] = CC_C, + [INDEX_op_salc] = CC_C, + + [INDEX_op_rclb_T0_T1_cc] = CC_C, + [INDEX_op_rclw_T0_T1_cc] = CC_C, + [INDEX_op_rcll_T0_T1_cc] = CC_C, + [INDEX_op_rcrb_T0_T1_cc] = CC_C, + [INDEX_op_rcrw_T0_T1_cc] = CC_C, + [INDEX_op_rcrl_T0_T1_cc] = CC_C, +}; + +/* flags written by an operation */ +static uint16_t opc_write_flags[NB_OPS] = { + [INDEX_op_addl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_orl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_andl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_subl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_negl_T0_cc] = CC_OSZAPC, + [INDEX_op_incl_T0_cc] = CC_OSZAP, + [INDEX_op_decl_T0_cc] = CC_OSZAP, + [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_mulb_AL_T0] = CC_OSZAPC, + [INDEX_op_imulb_AL_T0] = CC_OSZAPC, + [INDEX_op_mulw_AX_T0] = CC_OSZAPC, + [INDEX_op_imulw_AX_T0] = CC_OSZAPC, + [INDEX_op_mull_EAX_T0] = CC_OSZAPC, + [INDEX_op_imull_EAX_T0] = CC_OSZAPC, + [INDEX_op_imulw_T0_T1] = CC_OSZAPC, + [INDEX_op_imull_T0_T1] = CC_OSZAPC, + + /* bcd */ + [INDEX_op_aam] = CC_OSZAPC, + [INDEX_op_aad] = CC_OSZAPC, + [INDEX_op_aas] = CC_OSZAPC, + [INDEX_op_aaa] = CC_OSZAPC, + [INDEX_op_das] = CC_OSZAPC, + [INDEX_op_daa] = CC_OSZAPC, + + [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, + [INDEX_op_movl_eflags_T0] = CC_OSZAPC, + [INDEX_op_clc] = CC_C, + [INDEX_op_stc] = CC_C, + [INDEX_op_cmc] = CC_C, + + [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_bsfw_T0_cc] = CC_OSZAPC, + [INDEX_op_bsfl_T0_cc] = CC_OSZAPC, + [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, + [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, + + [INDEX_op_scasb] = CC_OSZAPC, + [INDEX_op_scasw] = CC_OSZAPC, + [INDEX_op_scasl] = CC_OSZAPC, + [INDEX_op_repz_scasb] = CC_OSZAPC, + [INDEX_op_repz_scasw] = CC_OSZAPC, + [INDEX_op_repz_scasl] = CC_OSZAPC, + [INDEX_op_repnz_scasb] = CC_OSZAPC, + [INDEX_op_repnz_scasw] = CC_OSZAPC, + [INDEX_op_repnz_scasl] = CC_OSZAPC, + + [INDEX_op_cmpsb] = CC_OSZAPC, + [INDEX_op_cmpsw] = CC_OSZAPC, + [INDEX_op_cmpsl] = CC_OSZAPC, + [INDEX_op_repz_cmpsb] = CC_OSZAPC, + [INDEX_op_repz_cmpsw] = CC_OSZAPC, + [INDEX_op_repz_cmpsl] = CC_OSZAPC, + [INDEX_op_repnz_cmpsb] = CC_OSZAPC, + [INDEX_op_repnz_cmpsw] = CC_OSZAPC, + [INDEX_op_repnz_cmpsl] = CC_OSZAPC, + + [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, +}; + +/* simpler form of an operation if no flags need to be generated */ +static uint16_t opc_simpler[NB_OPS] = { + [INDEX_op_addl_T0_T1_cc] = INDEX_op_addl_T0_T1, + [INDEX_op_orl_T0_T1_cc] = INDEX_op_orl_T0_T1, + [INDEX_op_andl_T0_T1_cc] = INDEX_op_andl_T0_T1, + [INDEX_op_subl_T0_T1_cc] = INDEX_op_subl_T0_T1, + [INDEX_op_xorl_T0_T1_cc] = INDEX_op_xorl_T0_T1, + [INDEX_op_negl_T0_cc] = INDEX_op_negl_T0, + [INDEX_op_incl_T0_cc] = INDEX_op_incl_T0, + [INDEX_op_decl_T0_cc] = INDEX_op_decl_T0, + + [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1, + [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1, + [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1, + + [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1, + [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1, + [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1, + + [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, + [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, + [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1, + + [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1, + [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1, + [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1, + + [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1, + [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1, + [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, +}; + +static void optimize_flags_init(void) +{ + int i; + /* put default values in arrays */ + for(i = 0; i < NB_OPS; i++) { + if (opc_simpler[i] == 0) + opc_simpler[i] = i; + } +} + +/* CPU flags computation optimization: we move backward thru the + generated code to see which flags are needed. The operation is + modified if suitable */ +static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) +{ + uint16_t *opc_ptr; + int live_flags, write_flags, op; + + opc_ptr = opc_buf + opc_buf_len; + /* live_flags contains the flags needed by the next instructions + in the code. At the end of the bloc, we consider that all the + flags are live. */ + live_flags = CC_OSZAPC; + while (opc_ptr > opc_buf) { + op = *--opc_ptr; + /* if none of the flags written by the instruction is used, + then we can try to find a simpler instruction */ + write_flags = opc_write_flags[op]; + if ((live_flags & write_flags) == 0) { + *opc_ptr = opc_simpler[op]; + } + /* compute the live flags before the instruction */ + live_flags &= ~write_flags; + live_flags |= opc_read_flags[op]; + } +} + + +#ifdef DEBUG_DISAS +static const char *op_str[] = { +#define DEF(s) #s, +#include "opc-i386.h" +#undef DEF +}; + +static void dump_ops(const uint16_t *opc_buf) +{ + const uint16_t *opc_ptr; + int c; + opc_ptr = opc_buf; + for(;;) { + c = *opc_ptr++; + fprintf(logfile, "0x%04x: %s\n", opc_ptr - opc_buf - 1, op_str[c]); + if (c == INDEX_op_end) + break; + } +} + +#endif + +/* XXX: make this buffer thread safe */ +/* XXX: make safe guess about sizes */ +#define MAX_OP_PER_INSTR 32 +#define OPC_BUF_SIZE 512 +#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) + +#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3) + +static uint16_t gen_opc_buf[OPC_BUF_SIZE]; +static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; + /* return the next pc */ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, uint8_t *pc_start, int flags) { DisasContext dc1, *dc = &dc1; - uint8_t *gen_code_end, *pc_ptr; + uint8_t *pc_ptr; + uint16_t *gen_opc_end; long ret; #ifdef DEBUG_DISAS struct disassemble_info disasm_info; #endif + + /* generate intermediate code */ + dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; dc->cc_op = CC_OP_DYNAMIC; - gen_code_ptr = gen_code_buf; - gen_code_end = gen_code_buf + max_code_size - 4096; - gen_start(); + + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; dc->is_jmp = 0; pc_ptr = pc_start; @@ -2871,7 +3205,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, abort(); } pc_ptr = (void *)ret; - } while (!dc->is_jmp && gen_code_ptr < gen_code_end); + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end); /* we must store the eflags state if it is not already done */ if (dc->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(dc->cc_op); @@ -2879,9 +3213,9 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, /* we add an additionnal jmp to update the simulated PC */ gen_op_jmp_im(ret); } - gen_end(); - *gen_code_size_ptr = gen_code_ptr - gen_code_buf; + *gen_opc_ptr = INDEX_op_end; + /* optimize flag computations */ #ifdef DEBUG_DISAS if (loglevel) { uint8_t *pc; @@ -2898,6 +3232,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, #else disasm_info.endian = BFD_ENDIAN_LITTLE; #endif + fprintf(logfile, "----------------\n"); fprintf(logfile, "IN:\n"); disasm_info.buffer = pc_start; disasm_info.buffer_vma = (unsigned long)pc_start; @@ -2911,12 +3246,37 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, } fprintf(logfile, "\n"); + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf); + fprintf(logfile, "\n"); + } +#endif + + /* optimize flag computations */ + optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf); + +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "AFTER FLAGS OPT:\n"); + dump_ops(gen_opc_buf); + fprintf(logfile, "\n"); + } +#endif + + /* generate machine code */ + *gen_code_size_ptr = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf); + +#ifdef DEBUG_DISAS + if (loglevel) { + uint8_t *pc; + int count; + pc = gen_code_buf; disasm_info.buffer = pc; disasm_info.buffer_vma = (unsigned long)pc; disasm_info.buffer_length = *gen_code_size_ptr; fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); - while (pc < gen_code_ptr) { + while (pc < gen_code_buf + *gen_code_size_ptr) { fprintf(logfile, "0x%08lx: ", (long)pc); count = print_insn_i386((unsigned long)pc, &disasm_info); fprintf(logfile, "\n"); @@ -2932,6 +3292,7 @@ CPUX86State *cpu_x86_init(void) { CPUX86State *env; int i; + static int inited; cpu_x86_tblocks_init(); @@ -2946,6 +3307,12 @@ CPUX86State *cpu_x86_init(void) /* flags setup */ env->cc_op = CC_OP_EFLAGS; env->df = 1; + + /* init various static tables */ + if (!inited) { + inited = 1; + optimize_flags_init(); + } return env; } -- cgit v1.2.3 From 68decc7c7f438497fc8f8ef913054df6c1ab5ed6 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Mar 2003 00:05:32 +0000 Subject: added file git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@35 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8b92f0e5f..0d7ded3fa 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ FILES= \ COPYING.LIB dyngen.c ioctls.h ops_template.h syscall_types.h\ Makefile elf.h linux_bin.h segment.h thunk.c\ TODO elfload.c main.c signal.c thunk.h\ -cpu-i386.h gemu.h op-i386.c syscall-i386.h translate-i386.c\ +cpu-i386.h gemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ dis-asm.h gen-i386.h op-i386.h syscall.c\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ i386.ld ppc.ld exec-i386.h exec-i386.c configure VERSION \ -- cgit v1.2.3 From 04369ff2f525ea510b6ddeaa2e3ed6aedde8bbb4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 Mar 2003 22:33:23 +0000 Subject: ppc port git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@36 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- configure | 32 +++++++----- cpu-i386.h | 136 +++++++++++++++++++++++++++++++++++++++++++++++++-- dis-asm.h | 1 + dyngen.c | 57 ++++++++++++++++++--- exec-i386.c | 80 ++++++++++++++++++++++++++++++ exec-i386.h | 33 +++++++++++++ linux-user/main.c | 1 + linux-user/syscall.c | 7 ++- op-i386.c | 99 +++++++++++++++++++++++++++++++++++++ ops_template.h | 9 ++++ tests/Makefile | 17 +++++-- tests/test-i386.c | 12 +++-- translate-i386.c | 35 ++++++++++++- 14 files changed, 486 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 0d7ded3fa..7f0f8be2b 100644 --- a/Makefile +++ b/Makefile @@ -90,7 +90,7 @@ i386.ld ppc.ld exec-i386.h exec-i386.c configure VERSION \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h\ -tests/test2.c tests/hello.c tests/sha1.c +tests/test2.c tests/hello.c tests/hello tests/sha1.c FILE=gemu-$(VERSION) diff --git a/configure b/configure index 62b1e7122..d9053cf76 100755 --- a/configure +++ b/configure @@ -11,11 +11,11 @@ else TMPDIR1="/tmp" fi -TMPC="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.c" -TMPO="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.o" -TMPE="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}" -TMPS="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.S" -TMPH="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.h" +TMPC="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.c" +TMPO="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.o" +TMPE="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}" +TMPS="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.S" +TMPH="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.h" # default parameters prefix="/usr/local" @@ -144,12 +144,20 @@ fi fi # check gcc version +cat > $TMPC < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) +return 0; +#else +#error gcc < 3.2 +#endif +} +EOF + gcc_major="2" -gcc_version="$($cc -v 2>&1 | grep version | cut -d ' ' -f3-)" -case "$gcc_version" in -3.*) gcc_major="3"; -;; -esac +if $cc -o $TMPO $TMPC 2> /dev/null ; then + gcc_major="3" +fi if test x"$1" = x"-h" -o x"$1" = x"--help" ; then cat << EOF @@ -201,9 +209,9 @@ if test "$cpu" = "x86" ; then elif test "$cpu" = "armv4l" ; then echo "ARCH=arm" >> config.mak elif test "$cpu" = "powerpc" ; then - echo "ARCH=ppc" > config.mak + echo "ARCH=ppc" >> config.mak elif test "$cpu" = "mips" ; then - echo "ARCH=mips" > config.mak + echo "ARCH=mips" >> config.mak else echo "Unsupported CPU" exit 1 diff --git a/cpu-i386.h b/cpu-i386.h index fc68a91d9..550e18387 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -4,6 +4,7 @@ #ifndef CPU_I386_H #define CPU_I386_H +#include "config.h" #include #define R_EAX 0 @@ -174,6 +175,7 @@ typedef struct CPUX86State { int exception_index; } CPUX86State; +/* all CPU memory access use these macros */ static inline int ldub(void *ptr) { return *(uint8_t *)ptr; @@ -184,6 +186,134 @@ static inline int ldsb(void *ptr) return *(int8_t *)ptr; } +static inline void stb(void *ptr, int v) +{ + *(uint8_t *)ptr = v; +} + +#ifdef WORDS_BIGENDIAN + +/* conservative code for little endian unaligned accesses */ +static inline int lduw(void *ptr) +{ +#ifdef __powerpc__ + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; +#else + uint8_t *p = ptr; + return p[0] | (p[1] << 8); +#endif +} + +static inline int ldsw(void *ptr) +{ +#ifdef __powerpc__ + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return (int16_t)val; +#else + uint8_t *p = ptr; + return (int16_t)(p[0] | (p[1] << 8)); +#endif +} + +static inline int ldl(void *ptr) +{ +#ifdef __powerpc__ + int val; + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; +#else + uint8_t *p = ptr; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +#endif +} + +static inline uint64_t ldq(void *ptr) +{ + uint8_t *p = ptr; + uint32_t v1, v2; + v1 = ldl(p); + v2 = ldl(p + 4); + return v1 | ((uint64_t)v2 << 32); +} + +static inline void stw(void *ptr, int v) +{ +#ifdef __powerpc__ + __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); +#else + uint8_t *p = ptr; + p[0] = v; + p[1] = v >> 8; +#endif +} + +static inline void stl(void *ptr, int v) +{ +#ifdef __powerpc__ + __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); +#else + uint8_t *p = ptr; + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +#endif +} + +static inline void stq(void *ptr, uint64_t v) +{ + uint8_t *p = ptr; + stl(p, (uint32_t)v); + stl(p + 4, v >> 32); +} + +/* float access */ + +static inline float ldfl(void *ptr) +{ + union { + float f; + uint32_t i; + } u; + u.i = ldl(ptr); + return u.f; +} + +static inline double ldfq(void *ptr) +{ + union { + double d; + uint64_t i; + } u; + u.i = ldq(ptr); + return u.d; +} + +static inline void stfl(void *ptr, float v) +{ + union { + float f; + uint32_t i; + } u; + u.f = v; + stl(ptr, u.i); +} + +static inline void stfq(void *ptr, double v) +{ + union { + double d; + uint64_t i; + } u; + u.d = v; + stq(ptr, u.i); +} + +#else + static inline int lduw(void *ptr) { return *(uint16_t *)ptr; @@ -204,11 +334,6 @@ static inline uint64_t ldq(void *ptr) return *(uint64_t *)ptr; } -static inline void stb(void *ptr, int v) -{ - *(uint8_t *)ptr = v; -} - static inline void stw(void *ptr, int v) { *(uint16_t *)ptr = v; @@ -245,6 +370,7 @@ static inline void stfq(void *ptr, double v) { *(double *)ptr = v; } +#endif #ifndef IN_OP_I386 void cpu_x86_outb(int addr, int val); diff --git a/dis-asm.h b/dis-asm.h index bd7e47844..20ca8e26a 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -10,6 +10,7 @@ #define DIS_ASM_H #include +#include #include "bfd.h" typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...)); diff --git a/dyngen.c b/dyngen.c index 9b2889b67..ed6861063 100644 --- a/dyngen.c +++ b/dyngen.c @@ -19,6 +19,7 @@ */ #include #include +#include #include #include #include @@ -228,14 +229,10 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, { uint8_t *p; p = (void *)(p_end - 4); - /* find ret */ - while (p > p_start && get32((uint32_t *)p) != 0x4e800020) - p -= 4; - /* skip double ret */ - if (p > p_start && get32((uint32_t *)(p - 4)) == 0x4e800020) - p -= 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; } break; @@ -361,6 +358,51 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, } } break; + case EM_PPC: + { + Elf32_Rela *rel; + char name[256]; + int type; + long addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", 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 + %ld) = %s + %ld;\n", + rel->r_offset - offset, name, addend); + break; + case R_PPC_ADDR16_LO: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld);\n", + rel->r_offset - offset, name, addend); + break; + case R_PPC_ADDR16_HI: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld) >> 16;\n", + rel->r_offset - offset, name, addend); + break; + case R_PPC_ADDR16_HA: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld + 0x8000) >> 16;\n", + rel->r_offset - offset, name, addend); + break; + case R_PPC_REL24: + /* warning: must be at 32 MB distancy */ + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = (*(uint32_t *)(gen_code_ptr + %ld) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %ld) + %ld) & 0x03fffffc);\n", + rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend); + break; + default: + error("unsupported powerpc relocation (%d)", type); + } + } + } + } + break; default: error("unsupported CPU for relocations (%d)", e_machine); } @@ -569,6 +611,9 @@ fprintf(outfile, case EM_386: fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n"); break; + case EM_PPC: + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n"); + break; default: error("no return generation for cpu '%s'", cpu_name); } diff --git a/exec-i386.c b/exec-i386.c index 538ebe0d6..0dbaccc83 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -171,6 +171,30 @@ int cpu_x86_exec(CPUX86State *env1) { int saved_T0, saved_T1, saved_A0; CPUX86State *saved_env; +#ifdef reg_EAX + int saved_EAX; +#endif +#ifdef reg_ECX + int saved_ECX; +#endif +#ifdef reg_EDX + int saved_EDX; +#endif +#ifdef reg_EBX + int saved_EBX; +#endif +#ifdef reg_ESP + int saved_ESP; +#endif +#ifdef reg_EBP + int saved_EBP; +#endif +#ifdef reg_ESI + int saved_ESI; +#endif +#ifdef reg_EDI + int saved_EDI; +#endif int code_gen_size, ret; void (*gen_func)(void); TranslationBlock *tb; @@ -183,6 +207,38 @@ int cpu_x86_exec(CPUX86State *env1) saved_A0 = A0; saved_env = env; env = env1; +#ifdef reg_EAX + saved_EAX = EAX; + EAX = env->regs[R_EAX]; +#endif +#ifdef reg_ECX + saved_ECX = ECX; + ECX = env->regs[R_ECX]; +#endif +#ifdef reg_EDX + saved_EDX = EDX; + EDX = env->regs[R_EDX]; +#endif +#ifdef reg_EBX + saved_EBX = EBX; + EBX = env->regs[R_EBX]; +#endif +#ifdef reg_ESP + saved_ESP = ESP; + ESP = env->regs[R_ESP]; +#endif +#ifdef reg_EBP + saved_EBP = EBP; + EBP = env->regs[R_EBP]; +#endif +#ifdef reg_ESI + saved_ESI = ESI; + ESI = env->regs[R_ESI]; +#endif +#ifdef reg_EDI + saved_EDI = EDI; + EDI = env->regs[R_EDI]; +#endif /* prepare setjmp context for exception handling */ if (setjmp(env->jmp_env) == 0) { @@ -217,6 +273,30 @@ int cpu_x86_exec(CPUX86State *env1) ret = env->exception_index; /* restore global registers */ +#ifdef reg_EAX + EAX = saved_EAX; +#endif +#ifdef reg_ECX + ECX = saved_ECX; +#endif +#ifdef reg_EDX + EDX = saved_EDX; +#endif +#ifdef reg_EBX + EBX = saved_EBX; +#endif +#ifdef reg_ESP + ESP = saved_ESP; +#endif +#ifdef reg_EBP + EBP = saved_EBP; +#endif +#ifdef reg_ESI + ESI = saved_ESI; +#endif +#ifdef reg_EDI + EDI = saved_EDI; +#endif T0 = saved_T0; T1 = saved_T1; A0 = saved_A0; diff --git a/exec-i386.h b/exec-i386.h index 0e0cae275..0384d0bf2 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -36,10 +36,27 @@ register unsigned int A0 asm("edi"); register struct CPUX86State *env asm("ebp"); #endif #ifdef __powerpc__ +register unsigned int EAX asm("r16"); +register unsigned int ECX asm("r17"); +register unsigned int EDX asm("r18"); +register unsigned int EBX asm("r19"); +register unsigned int ESP asm("r20"); +register unsigned int EBP asm("r21"); +register unsigned int ESI asm("r22"); +register unsigned int EDI asm("r23"); register unsigned int T0 asm("r24"); register unsigned int T1 asm("r25"); register unsigned int A0 asm("r26"); register struct CPUX86State *env asm("r27"); +#define USE_INT_TO_FLOAT_HELPERS +#define reg_EAX +#define reg_ECX +#define reg_EDX +#define reg_EBX +#define reg_ESP +#define reg_EBP +#define reg_ESI +#define reg_EDI #endif #ifdef __arm__ register unsigned int T0 asm("r4"); @@ -70,14 +87,30 @@ register struct CPUX86State *env asm("l3"); #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) +#ifndef reg_EAX #define EAX (env->regs[R_EAX]) +#endif +#ifndef reg_ECX #define ECX (env->regs[R_ECX]) +#endif +#ifndef reg_EDX #define EDX (env->regs[R_EDX]) +#endif +#ifndef reg_EBX #define EBX (env->regs[R_EBX]) +#endif +#ifndef reg_ESP #define ESP (env->regs[R_ESP]) +#endif +#ifndef reg_EBP #define EBP (env->regs[R_EBP]) +#endif +#ifndef reg_ESI #define ESI (env->regs[R_ESI]) +#endif +#ifndef reg_EDI #define EDI (env->regs[R_EDI]) +#endif #define PC (env->pc) #define DF (env->df) diff --git a/linux-user/main.c b/linux-user/main.c index b59c85d9c..45e81b207 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e6f04a840..c0bee47f7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,9 @@ #define termios host_termios #define winsize host_winsize #define termio host_termio +#define sgttyb host_sgttyb /* same as target */ +#define tchars host_tchars /* same as target */ +#define ltchars host_ltchars /* same as target */ #include #include @@ -904,7 +908,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_ftime: goto unimplemented; case TARGET_NR_sync: - ret = get_errno(sync()); + sync(); + ret = 0; break; case TARGET_NR_kill: ret = get_errno(kill(arg1, arg2)); diff --git a/op-i386.c b/op-i386.c index 002ce9692..70b1d7449 100644 --- a/op-i386.c +++ b/op-i386.c @@ -123,6 +123,32 @@ static inline int lshift(int x, int n) /* NOTE: not static to force relocation generation by GCC */ void raise_exception(int exception_index) { + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ +#ifdef reg_EAX + env->regs[R_EAX] = EAX; +#endif +#ifdef reg_ECX + env->regs[R_ECX] = ECX; +#endif +#ifdef reg_EDX + env->regs[R_EDX] = EDX; +#endif +#ifdef reg_EBX + env->regs[R_EBX] = EBX; +#endif +#ifdef reg_ESP + env->regs[R_ESP] = ESP; +#endif +#ifdef reg_EBP + env->regs[R_EBP] = EBP; +#endif +#ifdef reg_ESI + env->regs[R_ESI] = ESI; +#endif +#ifdef reg_EDI + env->regs[R_EDI] = EDI; +#endif env->exception_index = exception_index; longjmp(env->jmp_env, 1); } @@ -1341,6 +1367,41 @@ void OPPROTO op_fldl_FT0_A0(void) FT0 = ldfq((void *)A0); } +/* helpers are needed to avoid static constant reference. XXX: find a better way */ +#ifdef USE_INT_TO_FLOAT_HELPERS + +void helper_fild_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)ldsw((void *)A0); +} + +void helper_fildl_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +} + +void helper_fildll_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +} + +void OPPROTO op_fild_FT0_A0(void) +{ + helper_fild_FT0_A0(); +} + +void OPPROTO op_fildl_FT0_A0(void) +{ + helper_fildl_FT0_A0(); +} + +void OPPROTO op_fildll_FT0_A0(void) +{ + helper_fildll_FT0_A0(); +} + +#else + void OPPROTO op_fild_FT0_A0(void) { FT0 = (CPU86_LDouble)ldsw((void *)A0); @@ -1355,6 +1416,7 @@ void OPPROTO op_fildll_FT0_A0(void) { FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); } +#endif /* fp load ST0 */ @@ -1393,6 +1455,41 @@ void OPPROTO op_fldt_ST0_A0(void) } #endif +/* helpers are needed to avoid static constant reference. XXX: find a better way */ +#ifdef USE_INT_TO_FLOAT_HELPERS + +void helper_fild_ST0_A0(void) +{ + ST0 = (CPU86_LDouble)ldsw((void *)A0); +} + +void helper_fildl_ST0_A0(void) +{ + ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +} + +void helper_fildll_ST0_A0(void) +{ + ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +} + +void OPPROTO op_fild_ST0_A0(void) +{ + helper_fild_ST0_A0(); +} + +void OPPROTO op_fildl_ST0_A0(void) +{ + helper_fildl_ST0_A0(); +} + +void OPPROTO op_fildll_ST0_A0(void) +{ + helper_fildll_ST0_A0(); +} + +#else + void OPPROTO op_fild_ST0_A0(void) { ST0 = (CPU86_LDouble)ldsw((void *)A0); @@ -1408,6 +1505,8 @@ void OPPROTO op_fildll_ST0_A0(void) ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); } +#endif + /* fp store */ void OPPROTO op_fsts_ST0_A0(void) diff --git a/ops_template.h b/ops_template.h index f8cd5e54c..bc96f651a 100644 --- a/ops_template.h +++ b/ops_template.h @@ -809,6 +809,7 @@ void OPPROTO glue(op_rep_movs, SUFFIX)(void) EDI += inc; ECX--; } + FORCE_RET(); } void OPPROTO glue(op_stos, SUFFIX)(void) @@ -826,6 +827,7 @@ void OPPROTO glue(op_rep_stos, SUFFIX)(void) EDI += inc; ECX--; } + FORCE_RET(); } void OPPROTO glue(op_lods, SUFFIX)(void) @@ -859,6 +861,7 @@ void OPPROTO glue(op_rep_lods, SUFFIX)(void) ESI += inc; ECX--; } + FORCE_RET(); } void OPPROTO glue(op_scas, SUFFIX)(void) @@ -890,6 +893,7 @@ void OPPROTO glue(op_repz_scas, SUFFIX)(void) CC_DST = v1 - v2; CC_OP = CC_OP_SUBB + SHIFT; } + FORCE_RET(); } void OPPROTO glue(op_repnz_scas, SUFFIX)(void) @@ -911,6 +915,7 @@ void OPPROTO glue(op_repnz_scas, SUFFIX)(void) CC_DST = v1 - v2; CC_OP = CC_OP_SUBB + SHIFT; } + FORCE_RET(); } void OPPROTO glue(op_cmps, SUFFIX)(void) @@ -942,6 +947,7 @@ void OPPROTO glue(op_repz_cmps, SUFFIX)(void) CC_DST = v1 - v2; CC_OP = CC_OP_SUBB + SHIFT; } + FORCE_RET(); } void OPPROTO glue(op_repnz_cmps, SUFFIX)(void) @@ -962,6 +968,7 @@ void OPPROTO glue(op_repnz_cmps, SUFFIX)(void) CC_DST = v1 - v2; CC_OP = CC_OP_SUBB + SHIFT; } + FORCE_RET(); } /* port I/O */ @@ -986,6 +993,7 @@ void OPPROTO glue(op_rep_outs, SUFFIX)(void) ESI += inc; ECX--; } + FORCE_RET(); } void OPPROTO glue(op_ins, SUFFIX)(void) @@ -1008,6 +1016,7 @@ void OPPROTO glue(op_rep_ins, SUFFIX)(void) EDI += (DF << SHIFT); ECX--; } + FORCE_RET(); } void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) diff --git a/tests/Makefile b/tests/Makefile index c7d1154c0..72b559dfd 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -4,8 +4,9 @@ CFLAGS=-Wall -O2 -g LDFLAGS= ifeq ($(ARCH),i386) -TESTS=hello test2 sha1 test-i386 +TESTS=test2 sha1-i386 test-i386 endif +TESTS+=sha1 GEMU=../gemu @@ -13,26 +14,32 @@ all: $(TESTS) hello: hello.c $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< + strip hello test2: test2.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -# i386 emulation test (dump various opcodes) */ +# i386 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< -lm test: test-i386 +ifeq ($(ARCH),i386) ./test-i386 > test-i386.ref +endif $(GEMU) test-i386 > test-i386.out @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi # speed test -sha1: sha1.c +sha1-i386: sha1.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -speed: sha1 +sha1: sha1.c + $(HOST_CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +speed: sha1 sha1-i386 time ./sha1 - time $(GEMU) sha1 + time $(GEMU) ./sha1-i386 clean: rm -f *~ *.o $(TESTS) diff --git a/tests/test-i386.c b/tests/test-i386.c index 86aa94915..f9a599186 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -653,7 +653,7 @@ void test_segs(void) { struct modify_ldt_ldt_s ldt; long long ldt_table[3]; - int i, res, res2; + int res, res2; char tmp; ldt.entry_number = 1; @@ -679,9 +679,13 @@ void test_segs(void) modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */ - for(i=0;i<3;i++) - printf("%d: %016Lx\n", i, ldt_table[i]); - +#if 0 + { + int i; + for(i=0;i<3;i++) + printf("%d: %016Lx\n", i, ldt_table[i]); + } +#endif /* do some tests with fs or gs */ asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2))); diff --git a/translate-i386.c b/translate-i386.c index f02c5ea67..4c052a4e4 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -38,10 +38,40 @@ #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif +/* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; int __op_param1, __op_param2, __op_param3; +#ifdef __i386__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} +#endif + +#ifdef __powerpc__ + +#define MIN_CACHE_LINE_SIZE 8 /* conservative value */ + +static void inline flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + p = start & ~(MIN_CACHE_LINE_SIZE - 1); + stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); + + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm ("dcbst 0,%0;" : : "r"(p) : "memory"); + } + asm ("sync"); + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm ("icbi 0,%0; sync;" : : "r"(p) : "memory"); + } + asm ("sync"); + asm ("isync"); +} +#endif + extern FILE *logfile; extern int loglevel; @@ -3179,6 +3209,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; uint16_t *gen_opc_end; + int gen_code_size; long ret; #ifdef DEBUG_DISAS struct disassemble_info disasm_info; @@ -3264,7 +3295,9 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, #endif /* generate machine code */ - *gen_code_size_ptr = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf); + gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf); + flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); + *gen_code_size_ptr = gen_code_size; #ifdef DEBUG_DISAS if (loglevel) { -- cgit v1.2.3 From e591824733ec698d92d1f09c2ffb9b86b799d6da Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 Mar 2003 15:20:50 +0000 Subject: added code16 tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@37 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 5 +- tests/test-i386-code16.S | 80 +++++++++++++++++++++++++ tests/test-i386.c | 148 ++++++++++++++++++++++++++++++----------------- 3 files changed, 177 insertions(+), 56 deletions(-) create mode 100644 tests/test-i386-code16.S diff --git a/tests/Makefile b/tests/Makefile index 72b559dfd..3cc205d5b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -20,8 +20,9 @@ test2: test2.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< # i386 emulation test (test various opcodes) */ -test-i386: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< -lm +test-i386: test-i386.c test-i386-code16.S \ + test-i386.h test-i386-shift.h test-i386-muldiv.h + $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm test: test-i386 ifeq ($(ARCH),i386) diff --git a/tests/test-i386-code16.S b/tests/test-i386-code16.S new file mode 100644 index 000000000..446f0d7bf --- /dev/null +++ b/tests/test-i386-code16.S @@ -0,0 +1,80 @@ + .code16 + .globl code16_start + .globl code16_end + +CS_SEG = 0xf + +code16_start: + + .globl code16_func1 + + /* basic test */ +code16_func1 = . - code16_start + mov $1, %eax + data32 lret + +/* test push/pop in 16 bit mode */ + .globl code16_func2 +code16_func2 = . - code16_start + xor %eax, %eax + mov $0x12345678, %ebx + movl %esp, %ecx + push %bx + subl %esp, %ecx + pop %ax + data32 lret + +/* test various jmp opcodes */ + .globl code16_func3 +code16_func3 = . - code16_start + jmp 1f + nop +1: + mov $4, %eax + mov $0x12345678, %ebx + xor %bx, %bx + jz 2f + add $2, %ax +2: + + call myfunc + + lcall $CS_SEG, $(myfunc2 - code16_start) + + ljmp $CS_SEG, $(myjmp1 - code16_start) +myjmp1_next: + + cs lcall myfunc2_addr - code16_start + + cs ljmp myjmp2_addr - code16_start +myjmp2_next: + + data32 lret + +myfunc2_addr: + .short myfunc2 - code16_start + .short CS_SEG + +myjmp2_addr: + .short myjmp2 - code16_start + .short CS_SEG + +myjmp1: + add $8, %ax + jmp myjmp1_next + +myjmp2: + add $16, %ax + jmp myjmp2_next + +myfunc: + add $1, %ax + ret + +myfunc2: + add $4, %ax + lret + + +code16_end: + \ No newline at end of file diff --git a/tests/test-i386.c b/tests/test-i386.c index f9a599186..866c769e4 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -635,6 +635,65 @@ void test_bcd(void) TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); } +#define TEST_XCHG(op, size, opconst)\ +{\ + int op0, op1;\ + op0 = 0x12345678;\ + op1 = 0xfbca7654;\ + asm(#op " %" size "0, %" size "1" \ + : "=q" (op0), opconst (op1) \ + : "0" (op0), "1" (op1));\ + printf("%-10s A=%08x B=%08x\n",\ + #op, op0, op1);\ +} + +#define TEST_CMPXCHG(op, size, opconst, eax)\ +{\ + int op0, op1;\ + op0 = 0x12345678;\ + op1 = 0xfbca7654;\ + asm(#op " %" size "0, %" size "1" \ + : "=q" (op0), opconst (op1) \ + : "0" (op0), "1" (op1), "a" (eax));\ + printf("%-10s EAX=%08x A=%08x C=%08x\n",\ + #op, eax, op0, op1);\ +} + +void test_xchg(void) +{ + TEST_XCHG(xchgl, "", "=q"); + TEST_XCHG(xchgw, "w", "=q"); + TEST_XCHG(xchgb, "b", "=q"); + + TEST_XCHG(xchgl, "", "=m"); + TEST_XCHG(xchgw, "w", "=m"); + TEST_XCHG(xchgb, "b", "=m"); + + TEST_XCHG(xaddl, "", "=q"); + TEST_XCHG(xaddw, "w", "=q"); + TEST_XCHG(xaddb, "b", "=q"); + + TEST_XCHG(xaddl, "", "=m"); + TEST_XCHG(xaddw, "w", "=m"); + TEST_XCHG(xaddb, "b", "=m"); + + TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfbca7654); + TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654); + TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654); + + TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc); + + TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfbca7654); + TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654); + TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654); + + TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc); + TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc); +} + /**********************************************/ /* segmentation tests */ @@ -646,7 +705,7 @@ _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) uint8_t seg_data1[4096]; uint8_t seg_data2[4096]; -#define MK_SEL(n) (((n) << 3) | 4) +#define MK_SEL(n) (((n) << 3) | 7) /* NOTE: we use Linux modify_ldt syscall */ void test_segs(void) @@ -715,65 +774,45 @@ void test_segs(void) printf("SS[tmp] = %02x\n", res2); } -#define TEST_XCHG(op, size, opconst)\ -{\ - int op0, op1;\ - op0 = 0x12345678;\ - op1 = 0xfbca7654;\ - asm(#op " %" size "0, %" size "1" \ - : "=q" (op0), opconst (op1) \ - : "0" (op0), "1" (op1));\ - printf("%-10s A=%08x B=%08x\n",\ - #op, op0, op1);\ -} - -#define TEST_CMPXCHG(op, size, opconst, eax)\ -{\ - int op0, op1;\ - op0 = 0x12345678;\ - op1 = 0xfbca7654;\ - asm(#op " %" size "0, %" size "1" \ - : "=q" (op0), opconst (op1) \ - : "0" (op0), "1" (op1), "a" (eax));\ - printf("%-10s EAX=%08x A=%08x C=%08x\n",\ - #op, eax, op0, op1);\ -} +/* 16 bit code test */ +extern char code16_start, code16_end; +extern char code16_func1; +extern char code16_func2; +extern char code16_func3; -void test_xchg(void) +void test_code16(void) { - TEST_XCHG(xchgl, "", "=q"); - TEST_XCHG(xchgw, "w", "=q"); - TEST_XCHG(xchgb, "b", "=q"); - - TEST_XCHG(xchgl, "", "=m"); - TEST_XCHG(xchgw, "w", "=m"); - TEST_XCHG(xchgb, "b", "=m"); - - TEST_XCHG(xaddl, "", "=q"); - TEST_XCHG(xaddw, "w", "=q"); - TEST_XCHG(xaddb, "b", "=q"); - - TEST_XCHG(xaddl, "", "=m"); - TEST_XCHG(xaddw, "w", "=m"); - TEST_XCHG(xaddb, "b", "=m"); - - TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfbca7654); - TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654); - TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654); - - TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc); + struct modify_ldt_ldt_s ldt; + int res, res2; - TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfbca7654); - TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654); - TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654); + /* build a code segment */ + ldt.entry_number = 1; + ldt.base_addr = (unsigned long)&code16_start; + ldt.limit = &code16_end - &code16_start; + ldt.seg_32bit = 0; + ldt.contents = MODIFY_LDT_CONTENTS_CODE; + ldt.read_exec_only = 0; + ldt.limit_in_pages = 0; + ldt.seg_not_present = 0; + ldt.useable = 1; + modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc); + /* call the first function */ + asm volatile ("lcall %1, %2" + : "=a" (res) + : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc"); + printf("func1() = 0x%08x\n", res); + asm volatile ("lcall %2, %3" + : "=a" (res), "=c" (res2) + : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc"); + printf("func2() = 0x%08x spdec=%d\n", res, res2); + asm volatile ("lcall %1, %2" + : "=a" (res) + : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc"); + printf("func3() = 0x%08x\n", res); } + static void *call_end __init_call = NULL; int main(int argc, char **argv) @@ -794,5 +833,6 @@ int main(int argc, char **argv) test_xchg(); test_lea(); test_segs(); + test_code16(); return 0; } -- cgit v1.2.3 From dab2ed991a49678fbd4d45ff1b328340a77057df Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 Mar 2003 15:23:14 +0000 Subject: better 16 bit code support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@38 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 1 + cpu-i386.h | 10 +- exec-i386.c | 17 +- exec-i386.h | 2 +- linux-user/main.c | 8 +- linux-user/syscall.c | 37 ++++- linux-user/syscall_defs.h | 16 ++ op-i386.c | 241 +++++++++++++++------------ opc-i386.h | 26 ++- ops_template.h | 40 ++--- translate-i386.c | 413 +++++++++++++++++++++++++++++++++++++++------- 11 files changed, 595 insertions(+), 216 deletions(-) diff --git a/TODO b/TODO index ad3c76593..36efe4e9e 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ +- overrides/16bit for string ops - optimize translated cache chaining (DLL PLT-like system) - 64 bit syscalls - signals diff --git a/cpu-i386.h b/cpu-i386.h index 550e18387..9125ecadc 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -141,7 +141,7 @@ typedef struct SegmentDescriptorTable { typedef struct CPUX86State { /* standard registers */ uint32_t regs[8]; - uint32_t pc; /* cs_case + eip value */ + uint32_t eip; uint32_t eflags; /* emulator internal eflags handling */ @@ -392,10 +392,12 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); #define GEN_FLAG_CODE32_SHIFT 0 #define GEN_FLAG_ADDSEG_SHIFT 1 -#define GEN_FLAG_ST_SHIFT 2 +#define GEN_FLAG_SS32_SHIFT 2 +#define GEN_FLAG_ST_SHIFT 3 + int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, - int *gen_code_size_ptr, uint8_t *pc_start, - int flags); + int *gen_code_size_ptr, + uint8_t *pc_start, uint8_t *cs_base, int flags); void cpu_x86_tblocks_init(void); #endif /* CPU_I386_H */ diff --git a/exec-i386.c b/exec-i386.c index 0dbaccc83..e83d22036 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -38,7 +38,8 @@ #define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) typedef struct TranslationBlock { - unsigned long pc; /* simulated PC corresponding to this block */ + unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ + unsigned long cs_base; /* CS base for this block */ unsigned int flags; /* flags defining in which context the code was generated */ uint8_t *tc_ptr; /* pointer to the translated code */ struct TranslationBlock *hash_next; /* next matching block */ @@ -140,6 +141,7 @@ static void tb_flush(void) /* find a translation block in the translation cache. If not found, allocate a new one */ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, + unsigned long cs_base, unsigned int flags) { TranslationBlock **ptb, *tb; @@ -151,7 +153,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, tb = *ptb; if (!tb) break; - if (tb->pc == pc && tb->flags == flags) + if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) return tb; ptb = &tb->hash_next; } @@ -161,6 +163,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, tb = &tbs[nb_tbs++]; *ptb = tb; tb->pc = pc; + tb->cs_base = cs_base; tb->flags = flags; tb->tc_ptr = NULL; tb->hash_next = NULL; @@ -198,7 +201,7 @@ int cpu_x86_exec(CPUX86State *env1) int code_gen_size, ret; void (*gen_func)(void); TranslationBlock *tb; - uint8_t *tc_ptr; + uint8_t *tc_ptr, *cs_base, *pc; unsigned int flags; /* first we save global registers */ @@ -251,17 +254,21 @@ int cpu_x86_exec(CPUX86State *env1) /* we compute the CPU state. We assume it will not change during the whole generated block. */ flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; + flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT; flags |= (((unsigned long)env->seg_cache[R_DS].base | (unsigned long)env->seg_cache[R_ES].base | (unsigned long)env->seg_cache[R_SS].base) != 0) << GEN_FLAG_ADDSEG_SHIFT; - tb = tb_find_and_alloc((unsigned long)env->pc, flags); + cs_base = env->seg_cache[R_CS].base; + pc = cs_base + env->eip; + tb = tb_find_and_alloc((unsigned long)pc, (unsigned long)cs_base, + flags); tc_ptr = tb->tc_ptr; if (!tb->tc_ptr) { /* if no translated code available, then translate it now */ tc_ptr = code_gen_ptr; cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, - &code_gen_size, (uint8_t *)env->pc, flags); + &code_gen_size, pc, cs_base, flags); tb->tc_ptr = tc_ptr; code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); } diff --git a/exec-i386.h b/exec-i386.h index 0384d0bf2..f2e1386b5 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -111,7 +111,7 @@ register struct CPUX86State *env asm("l3"); #ifndef reg_EDI #define EDI (env->regs[R_EDI]) #endif -#define PC (env->pc) +#define EIP (env->eip) #define DF (env->df) #define CC_SRC (env->cc_src) diff --git a/linux-user/main.c b/linux-user/main.c index 45e81b207..3222629b2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -179,7 +179,7 @@ int main(int argc, char **argv) env->regs[R_EDI] = regs->edi; env->regs[R_EBP] = regs->ebp; env->regs[R_ESP] = regs->esp; - env->pc = regs->eip; + env->eip = regs->eip; /* linux segment setup */ env->gdt.base = (void *)gdt_table; @@ -198,12 +198,12 @@ int main(int argc, char **argv) uint8_t *pc; err = cpu_x86_exec(env); + pc = env->seg_cache[R_CS].base + env->eip; switch(err) { case EXCP0D_GPF: - pc = (uint8_t *)env->pc; if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ - env->pc += 2; + env->eip += 2; env->regs[R_EAX] = do_syscall(env, env->regs[R_EAX], env->regs[R_EBX], @@ -219,7 +219,7 @@ int main(int argc, char **argv) default: trap_error: fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", - (long)env->pc, err); + (long)pc, err); abort(); } } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c0bee47f7..afdf18967 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -53,6 +53,7 @@ #include #include #include +#include #include "gemu.h" @@ -63,13 +64,6 @@ #define PAGE_MASK ~(PAGE_SIZE - 1) #endif -struct dirent { - long d_ino; - long d_off; - unsigned short d_reclen; - char d_name[256]; /* We must not include limits.h! */ -}; - //#include #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) @@ -86,6 +80,7 @@ struct dirent { #define __NR_sys_statfs __NR_statfs #define __NR_sys_fstatfs __NR_fstatfs #define __NR_sys_getdents __NR_getdents +#define __NR_sys_getdents64 __NR_getdents64 #ifdef __NR_gettid _syscall0(int, gettid) @@ -97,6 +92,7 @@ static int gettid(void) { _syscall1(int,sys_uname,struct new_utsname *,buf) _syscall2(int,sys_getcwd1,char *,buf,size_t,size) _syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); +_syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); _syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf) @@ -1005,7 +1001,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(setsid()); break; case TARGET_NR_sigaction: -#if 0 +#if 1 { ret = 0; } @@ -1336,6 +1332,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { struct dirent *dirp = (void *)arg2; long count = arg3; + ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { struct dirent *de; @@ -1355,6 +1352,29 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; + case TARGET_NR_getdents64: + { + struct dirent64 *dirp = (void *)arg2; + long count = arg3; + ret = get_errno(sys_getdents64(arg1, dirp, count)); + if (!is_error(ret)) { + struct dirent64 *de; + int len = ret; + int reclen; + de = dirp; + while (len > 0) { + reclen = tswap16(de->d_reclen); + if (reclen > len) + break; + de->d_reclen = reclen; + tswap64s(&de->d_ino); + tswap64s(&de->d_off); + de = (struct dirent64 *)((char *)de + reclen); + len -= reclen; + } + } + } + break; case TARGET_NR__newselect: ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, (void *)arg5); @@ -1519,7 +1539,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_pivot_root: case TARGET_NR_mincore: case TARGET_NR_madvise: - case TARGET_NR_getdents64: goto unimplemented; #if TARGET_LONG_BITS == 32 case TARGET_NR_fcntl64: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index dc44272db..8b2d6bd75 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -75,6 +75,22 @@ struct kernel_statfs { int f_spare[6]; }; +struct target_dirent { + target_long d_ino; + target_long d_off; + unsigned short d_reclen; + char d_name[256]; /* We must not include limits.h! */ +}; + +struct target_dirent64 { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + + /* mostly generic signal stuff */ #define TARGET_SIG_DFL ((target_long)0) /* default signal handling */ #define TARGET_SIG_IGN ((target_long)1) /* ignore signal */ diff --git a/op-i386.c b/op-i386.c index 70b1d7449..a9583ecf3 100644 --- a/op-i386.c +++ b/op-i386.c @@ -464,18 +464,43 @@ void OPPROTO op_idivl_EAX_T0(void) EDX = r; } -/* constant load */ +/* constant load & misc op */ void OPPROTO op_movl_T0_im(void) { T0 = PARAM1; } +void OPPROTO op_addl_T0_im(void) +{ + T0 += PARAM1; +} + +void OPPROTO op_andl_T0_ffff(void) +{ + T0 = T0 & 0xffff; +} + +void OPPROTO op_movl_T0_T1(void) +{ + T0 = T1; +} + void OPPROTO op_movl_T1_im(void) { T1 = PARAM1; } +void OPPROTO op_addl_T1_im(void) +{ + T1 += PARAM1; +} + +void OPPROTO op_movl_T1_A0(void) +{ + T1 = A0; +} + void OPPROTO op_movl_A0_im(void) { A0 = PARAM1; @@ -574,23 +599,23 @@ void OPPROTO op_add_bitl_A0_T1(void) void OPPROTO op_jmp_T0(void) { - PC = T0; + EIP = T0; } void OPPROTO op_jmp_im(void) { - PC = PARAM1; + EIP = PARAM1; } void OPPROTO op_int_im(void) { - PC = PARAM1; + EIP = PARAM1; raise_exception(EXCP0D_GPF); } void OPPROTO op_int3(void) { - PC = PARAM1; + EIP = PARAM1; raise_exception(EXCP03_INT3); } @@ -599,10 +624,10 @@ void OPPROTO op_into(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_O) { - PC = PARAM1; + EIP = PARAM1; raise_exception(EXCP04_INTO); } else { - PC = PARAM2; + EIP = PARAM2; } } @@ -665,7 +690,6 @@ void OPPROTO op_movswl_DX_AX(void) } /* push/pop */ -/* XXX: add 16 bit operand/16 bit seg variants */ void op_pushl_T0(void) { @@ -676,107 +700,110 @@ void op_pushl_T0(void) ESP = offset; } -void op_pushl_T1(void) +void op_pushw_T0(void) +{ + uint32_t offset; + offset = ESP - 2; + stw((void *)offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_pushl_ss32_T0(void) { uint32_t offset; offset = ESP - 4; - stl((void *)offset, T1); + stl(env->seg_cache[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = offset; } +void op_pushw_ss32_T0(void) +{ + uint32_t offset; + offset = ESP - 2; + stw(env->seg_cache[R_SS].base + offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_pushl_ss16_T0(void) +{ + uint32_t offset; + offset = (ESP - 4) & 0xffff; + stl(env->seg_cache[R_SS].base + offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = (ESP & ~0xffff) | offset; +} + +void op_pushw_ss16_T0(void) +{ + uint32_t offset; + offset = (ESP - 2) & 0xffff; + stw(env->seg_cache[R_SS].base + offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = (ESP & ~0xffff) | offset; +} + +/* NOTE: ESP update is done after */ void op_popl_T0(void) { T0 = ldl((void *)ESP); +} + +void op_popw_T0(void) +{ + T0 = lduw((void *)ESP); +} + +void op_popl_ss32_T0(void) +{ + T0 = ldl(env->seg_cache[R_SS].base + ESP); +} + +void op_popw_ss32_T0(void) +{ + T0 = lduw(env->seg_cache[R_SS].base + ESP); +} + +void op_popl_ss16_T0(void) +{ + T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff)); +} + +void op_popw_ss16_T0(void) +{ + T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff)); +} + +void op_addl_ESP_4(void) +{ ESP += 4; } +void op_addl_ESP_2(void) +{ + ESP += 2; +} + +void op_addw_ESP_4(void) +{ + ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff); +} + +void op_addw_ESP_2(void) +{ + ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff); +} + void op_addl_ESP_im(void) { ESP += PARAM1; } -void op_pushal(void) -{ - uint8_t *sp; - sp = (void *)(ESP - 32); - stl(sp, EDI); - stl(sp + 4, ESI); - stl(sp + 8, EBP); - stl(sp + 12, ESP); - stl(sp + 16, EBX); - stl(sp + 20, EDX); - stl(sp + 24, ECX); - stl(sp + 28, EAX); - ESP = (unsigned long)sp; -} - -void op_pushaw(void) -{ - uint8_t *sp; - sp = (void *)(ESP - 16); - stw(sp, EDI); - stw(sp + 2, ESI); - stw(sp + 4, EBP); - stw(sp + 6, ESP); - stw(sp + 8, EBX); - stw(sp + 10, EDX); - stw(sp + 12, ECX); - stw(sp + 14, EAX); - ESP = (unsigned long)sp; -} - -void op_popal(void) -{ - uint8_t *sp; - sp = (void *)ESP; - EDI = ldl(sp); - ESI = ldl(sp + 4); - EBP = ldl(sp + 8); - EBX = ldl(sp + 16); - EDX = ldl(sp + 20); - ECX = ldl(sp + 24); - EAX = ldl(sp + 28); - ESP = (unsigned long)sp + 32; -} - -void op_popaw(void) -{ - uint8_t *sp; - sp = (void *)ESP; - EDI = ldl(sp); - ESI = ldl(sp + 2); - EBP = ldl(sp + 4); - EBX = ldl(sp + 8); - EDX = ldl(sp + 10); - ECX = ldl(sp + 12); - EAX = ldl(sp + 14); - ESP = (unsigned long)sp + 16; -} - -void op_enterl(void) -{ - unsigned int bp, frame_temp, level; - uint8_t *sp; - - sp = (void *)ESP; - bp = EBP; - sp -= 4; - stl(sp, bp); - frame_temp = (unsigned int)sp; - level = PARAM2; - if (level) { - while (level--) { - bp -= 4; - sp -= 4; - stl(sp, bp); - } - sp -= 4; - stl(sp, frame_temp); - } - EBP = frame_temp; - sp -= PARAM1; - ESP = (int)sp; +void op_addw_ESP_im(void) +{ + ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff); } /* rdtsc */ @@ -988,18 +1015,18 @@ void OPPROTO op_jo_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_O) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } void OPPROTO op_jb_cc(void) { if (cc_table[CC_OP].compute_c()) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -1008,9 +1035,9 @@ void OPPROTO op_jz_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_Z) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -1019,9 +1046,9 @@ void OPPROTO op_jbe_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & (CC_Z | CC_C)) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -1030,9 +1057,9 @@ void OPPROTO op_js_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_S) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -1041,9 +1068,9 @@ void OPPROTO op_jp_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_P) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -1052,9 +1079,9 @@ void OPPROTO op_jl_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if ((eflags ^ (eflags >> 4)) & 0x80) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -1063,9 +1090,9 @@ void OPPROTO op_jle_cc(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } diff --git a/opc-i386.h b/opc-i386.h index aae289419..092904468 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -202,7 +202,12 @@ DEF(idivw_AX_T0) DEF(divl_EAX_T0) DEF(idivl_EAX_T0) DEF(movl_T0_im) +DEF(addl_T0_im) +DEF(andl_T0_ffff) +DEF(movl_T0_T1) DEF(movl_T1_im) +DEF(addl_T1_im) +DEF(movl_T1_A0) DEF(movl_A0_im) DEF(addl_A0_im) DEF(andl_A0_ffff) @@ -398,14 +403,23 @@ DEF(movsbw_AX_AL) DEF(movslq_EDX_EAX) DEF(movswl_DX_AX) DEF(pushl_T0) -DEF(pushl_T1) +DEF(pushw_T0) +DEF(pushl_ss32_T0) +DEF(pushw_ss32_T0) +DEF(pushl_ss16_T0) +DEF(pushw_ss16_T0) DEF(popl_T0) +DEF(popw_T0) +DEF(popl_ss32_T0) +DEF(popw_ss32_T0) +DEF(popl_ss16_T0) +DEF(popw_ss16_T0) +DEF(addl_ESP_4) +DEF(addl_ESP_2) +DEF(addw_ESP_4) +DEF(addw_ESP_2) DEF(addl_ESP_im) -DEF(pushal) -DEF(pushaw) -DEF(popal) -DEF(popaw) -DEF(enterl) +DEF(addw_ESP_im) DEF(rdtsc) DEF(aam) DEF(aad) diff --git a/ops_template.h b/ops_template.h index bc96f651a..70ee9f355 100644 --- a/ops_template.h +++ b/ops_template.h @@ -214,18 +214,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_TYPE)src1 < (DATA_TYPE)src2) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } void OPPROTO glue(op_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST == 0) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -236,18 +236,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } void OPPROTO glue(op_js_sub, SUFFIX)(void) { if (CC_DST & SIGN_MASK) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -258,9 +258,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_STYPE)src1 < (DATA_STYPE)src2) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -271,9 +271,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -289,9 +289,9 @@ void OPPROTO glue(op_loopnz, SUFFIX)(void) tmp = (ECX - 1) & DATA_MASK; ECX = (ECX & ~DATA_MASK) | tmp; if (tmp != 0 && !(eflags & CC_Z)) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -303,9 +303,9 @@ void OPPROTO glue(op_loopz, SUFFIX)(void) tmp = (ECX - 1) & DATA_MASK; ECX = (ECX & ~DATA_MASK) | tmp; if (tmp != 0 && (eflags & CC_Z)) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } @@ -315,18 +315,18 @@ void OPPROTO glue(op_loop, SUFFIX)(void) tmp = (ECX - 1) & DATA_MASK; ECX = (ECX & ~DATA_MASK) | tmp; if (tmp != 0) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } void OPPROTO glue(op_jecxz, SUFFIX)(void) { if ((DATA_TYPE)ECX == 0) - PC = PARAM1; + EIP = PARAM1; else - PC = PARAM2; + EIP = PARAM2; FORCE_RET(); } diff --git a/translate-i386.c b/translate-i386.c index 4c052a4e4..5cbaa813c 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -92,11 +92,13 @@ typedef struct DisasContext { /* current insn context */ int prefix; int aflag, dflag; - uint8_t *pc; /* current pc */ + uint8_t *pc; /* pc = eip + cs_base */ int is_jmp; /* 1 = means jump (stop translation), 2 means CPU static state change (stop translation) */ /* current block context */ + uint8_t *cs_base; /* base of CS segment */ int code32; /* 32 bit code segment */ + int ss32; /* 32 bit stack segment */ int cc_op; /* current CC operation */ int addseg; /* non zero if either DS/ES/SS have a non zero base */ int f_st; /* currently unused */ @@ -1051,7 +1053,7 @@ static inline uint32_t insn_get(DisasContext *s, int ot) return ret; } -static void gen_jcc(DisasContext *s, int b, int val) +static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) { int inv, jcc_op; GenOpFunc2 *func; @@ -1112,9 +1114,9 @@ static void gen_jcc(DisasContext *s, int b, int val) break; } if (!inv) { - func(val, (long)s->pc); + func(val, next_eip); } else { - func((long)s->pc, val); + func(next_eip, val); } } @@ -1176,7 +1178,7 @@ static void gen_setcc(DisasContext *s, int b) } /* move T0 to seg_reg and compute if the CPU state may change */ -void gen_movl_seg_T0(DisasContext *s, int seg_reg) +static void gen_movl_seg_T0(DisasContext *s, int seg_reg) { gen_op_movl_seg_T0(seg_reg); if (!s->addseg && seg_reg < R_FS) @@ -1184,6 +1186,148 @@ void gen_movl_seg_T0(DisasContext *s, int seg_reg) have a non zero base */ } +/* generate a push. It depends on ss32, addseg and dflag */ +static void gen_push_T0(DisasContext *s) +{ + if (s->ss32) { + if (!s->addseg) { + if (s->dflag) + gen_op_pushl_T0(); + else + gen_op_pushw_T0(); + } else { + if (s->dflag) + gen_op_pushl_ss32_T0(); + else + gen_op_pushw_ss32_T0(); + } + } else { + if (s->dflag) + gen_op_pushl_ss16_T0(); + else + gen_op_pushw_ss16_T0(); + } +} + +/* two step pop is necessary for precise exceptions */ +static void gen_pop_T0(DisasContext *s) +{ + if (s->ss32) { + if (!s->addseg) { + if (s->dflag) + gen_op_popl_T0(); + else + gen_op_popw_T0(); + } else { + if (s->dflag) + gen_op_popl_ss32_T0(); + else + gen_op_popw_ss32_T0(); + } + } else { + if (s->dflag) + gen_op_popl_ss16_T0(); + else + gen_op_popw_ss16_T0(); + } +} + +static void gen_pop_update(DisasContext *s) +{ + if (s->ss32) { + if (s->dflag) + gen_op_addl_ESP_4(); + else + gen_op_addl_ESP_2(); + } else { + if (s->dflag) + gen_op_addw_ESP_4(); + else + gen_op_addw_ESP_2(); + } +} + +/* NOTE: wrap around in 16 bit not fully handled */ +static void gen_pusha(DisasContext *s) +{ + int i; + gen_op_movl_A0_ESP(); + gen_op_addl_A0_im(-16 << s->dflag); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); + for(i = 0;i < 8; i++) { + gen_op_mov_TN_reg[OT_LONG][0][7 - i](); + gen_op_st_T0_A0[OT_WORD + s->dflag](); + gen_op_addl_A0_im(2 << s->dflag); + } + gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); +} + +/* NOTE: wrap around in 16 bit not fully handled */ +static void gen_popa(DisasContext *s) +{ + int i; + gen_op_movl_A0_ESP(); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + gen_op_addl_T1_im(16 << s->dflag); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); + for(i = 0;i < 8; i++) { + /* ESP is not reloaded */ + if (i != 3) { + gen_op_ld_T0_A0[OT_WORD + s->dflag](); + gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); + } + gen_op_addl_A0_im(2 << s->dflag); + } + gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); +} + +/* NOTE: wrap around in 16 bit not fully handled */ +/* XXX: check this */ +static void gen_enter(DisasContext *s, int esp_addend, int level) +{ + int ot, level1, addend, opsize; + + ot = s->dflag + OT_WORD; + level &= 0x1f; + level1 = level; + opsize = 2 << s->dflag; + + gen_op_movl_A0_ESP(); + gen_op_addl_A0_im(-opsize); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); + /* push bp */ + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_st_T0_A0[ot](); + if (level) { + while (level--) { + gen_op_addl_A0_im(-opsize); + gen_op_addl_T0_im(-opsize); + gen_op_st_T0_A0[ot](); + } + gen_op_addl_A0_im(-opsize); + /* XXX: add st_T1_A0 ? */ + gen_op_movl_T0_T1(); + gen_op_st_T0_A0[ot](); + } + gen_op_mov_reg_T1[ot][R_EBP](); + addend = -esp_addend; + if (level1) + addend -= opsize * (level1 + 1); + gen_op_addl_T1_im(addend); + gen_op_mov_reg_T1[ot][R_ESP](); +} + /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr is set to true if the instruction sets the PC (last instruction of a basic block) */ @@ -1192,6 +1336,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) int b, prefixes, aflag, dflag; int shift, ot; int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; + unsigned int next_eip; s->pc = pc_start; prefixes = 0; @@ -1492,7 +1637,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); + if (op != 3 && op != 5) + gen_op_ld_T0_A0[ot](); } else { gen_op_mov_TN_reg[ot][0][rm](); } @@ -1513,17 +1659,48 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_reg_T0[ot][rm](); break; case 2: /* call Ev */ - gen_op_movl_T1_im((long)s->pc); - gen_op_pushl_T1(); + /* XXX: optimize if memory (no and is necessary) */ + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + next_eip = s->pc - s->cs_base; + gen_op_movl_T0_im(next_eip); + gen_push_T0(s); + s->is_jmp = 1; + break; + case 3: /* lcall Ev */ + /* push return segment + offset */ + gen_op_movl_T0_seg(R_CS); + gen_push_T0(s); + next_eip = s->pc - s->cs_base; + gen_op_movl_T0_im(next_eip); + gen_push_T0(s); + + gen_op_ld_T1_A0[ot](); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_op_lduw_T0_A0(); + gen_movl_seg_T0(s, R_CS); + gen_op_movl_T0_T1(); gen_op_jmp_T0(); s->is_jmp = 1; break; case 4: /* jmp Ev */ + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + s->is_jmp = 1; + break; + case 5: /* ljmp Ev */ + gen_op_ld_T1_A0[ot](); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_op_lduw_T0_A0(); + gen_movl_seg_T0(s, R_CS); + gen_op_movl_T0_T1(); gen_op_jmp_T0(); s->is_jmp = 1; break; case 6: /* push Ev */ - gen_op_pushl_T0(); + gen_push_T0(s); break; default: goto illegal_op; @@ -1653,23 +1830,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* push/pop */ case 0x50 ... 0x57: /* push */ gen_op_mov_TN_reg[OT_LONG][0][b & 7](); - gen_op_pushl_T0(); + gen_push_T0(s); break; case 0x58 ... 0x5f: /* pop */ - gen_op_popl_T0(); - gen_op_mov_reg_T0[OT_LONG][b & 7](); + ot = dflag ? OT_LONG : OT_WORD; + gen_pop_T0(s); + gen_op_mov_reg_T0[ot][b & 7](); + gen_pop_update(s); break; case 0x60: /* pusha */ - if (s->dflag) - gen_op_pushal(); - else - gen_op_pushaw(); + gen_pusha(s); break; case 0x61: /* popa */ - if (s->dflag) - gen_op_popal(); - else - gen_op_popaw(); + gen_popa(s); break; case 0x68: /* push Iv */ case 0x6a: @@ -1679,13 +1852,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else val = (int8_t)insn_get(s, OT_BYTE); gen_op_movl_T0_im(val); - gen_op_pushl_T0(); + gen_push_T0(s); break; case 0x8f: /* pop Ev */ ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); - gen_op_popl_T0(); + gen_pop_T0(s); gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + gen_pop_update(s); break; case 0xc8: /* enter */ { @@ -1693,38 +1867,47 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = lduw(s->pc); s->pc += 2; level = ldub(s->pc++); - level &= 0x1f; - gen_op_enterl(val, level); + gen_enter(s, val, level); } break; case 0xc9: /* leave */ - gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_mov_reg_T0[OT_LONG][R_ESP](); - gen_op_popl_T0(); - gen_op_mov_reg_T0[OT_LONG][R_EBP](); + /* XXX: exception not precise (ESP is update before potential exception) */ + if (s->ss32) { + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_mov_reg_T0[OT_LONG][R_ESP](); + } else { + gen_op_mov_TN_reg[OT_WORD][0][R_EBP](); + gen_op_mov_reg_T0[OT_WORD][R_ESP](); + } + gen_pop_T0(s); + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_reg_T0[ot][R_EBP](); + gen_pop_update(s); break; case 0x06: /* push es */ case 0x0e: /* push cs */ case 0x16: /* push ss */ case 0x1e: /* push ds */ gen_op_movl_T0_seg(b >> 3); - gen_op_pushl_T0(); + gen_push_T0(s); break; case 0x1a0: /* push fs */ case 0x1a8: /* push gs */ gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS); - gen_op_pushl_T0(); + gen_push_T0(s); break; case 0x07: /* pop es */ case 0x17: /* pop ss */ case 0x1f: /* pop ds */ - gen_op_popl_T0(); + gen_pop_T0(s); gen_movl_seg_T0(s, b >> 3); + gen_pop_update(s); break; case 0x1a1: /* pop fs */ case 0x1a9: /* pop gs */ - gen_op_popl_T0(); + gen_pop_T0(s); gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS); + gen_pop_update(s); break; /**************************/ @@ -1775,7 +1958,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) modrm = ldub(s->pc++); reg = (modrm >> 3) & 7; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - if (reg >= 6) + if (reg >= 6 || reg == R_CS) goto illegal_op; gen_movl_seg_T0(s, reg); break; @@ -2585,42 +2768,130 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* control */ case 0xc2: /* ret im */ - /* XXX: handle stack pop ? */ val = ldsw(s->pc); s->pc += 2; - gen_op_popl_T0(); - gen_op_addl_ESP_im(val); + gen_pop_T0(s); + if (s->ss32) + gen_op_addl_ESP_im(val + (2 << s->dflag)); + else + gen_op_addw_ESP_im(val + (2 << s->dflag)); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); gen_op_jmp_T0(); s->is_jmp = 1; break; case 0xc3: /* ret */ - gen_op_popl_T0(); + gen_pop_T0(s); + gen_pop_update(s); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); gen_op_jmp_T0(); s->is_jmp = 1; break; - case 0xe8: /* call */ - val = insn_get(s, OT_LONG); - val += (long)s->pc; - gen_op_movl_T1_im((long)s->pc); - gen_op_pushl_T1(); - gen_op_jmp_im(val); + case 0xca: /* lret im */ + val = ldsw(s->pc); + s->pc += 2; + /* pop offset */ + gen_pop_T0(s); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_pop_update(s); + /* pop selector */ + gen_pop_T0(s); + gen_movl_seg_T0(s, R_CS); + gen_pop_update(s); + /* add stack offset */ + if (s->ss32) + gen_op_addl_ESP_im(val + (2 << s->dflag)); + else + gen_op_addw_ESP_im(val + (2 << s->dflag)); + s->is_jmp = 1; + break; + case 0xcb: /* lret */ + /* pop offset */ + gen_pop_T0(s); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_pop_update(s); + /* pop selector */ + gen_pop_T0(s); + gen_movl_seg_T0(s, R_CS); + gen_pop_update(s); s->is_jmp = 1; break; + case 0xe8: /* call im */ + { + unsigned int next_eip; + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_op_movl_T0_im(next_eip); + gen_push_T0(s); + gen_op_jmp_im(val); + s->is_jmp = 1; + } + break; + case 0x9a: /* lcall im */ + { + unsigned int selector, offset; + + ot = dflag ? OT_LONG : OT_WORD; + offset = insn_get(s, ot); + selector = insn_get(s, OT_WORD); + + /* push return segment + offset */ + gen_op_movl_T0_seg(R_CS); + gen_push_T0(s); + next_eip = s->pc - s->cs_base; + gen_op_movl_T0_im(next_eip); + gen_push_T0(s); + + /* change cs and pc */ + gen_op_movl_T0_im(selector); + gen_movl_seg_T0(s, R_CS); + gen_op_jmp_im((unsigned long)offset); + s->is_jmp = 1; + } + break; case 0xe9: /* jmp */ - val = insn_get(s, OT_LONG); - val += (long)s->pc; + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + val += s->pc - s->cs_base; + if (s->dflag == 0) + val = val & 0xffff; gen_op_jmp_im(val); s->is_jmp = 1; break; + case 0xea: /* ljmp im */ + { + unsigned int selector, offset; + + ot = dflag ? OT_LONG : OT_WORD; + offset = insn_get(s, ot); + selector = insn_get(s, OT_WORD); + + /* change cs and pc */ + gen_op_movl_T0_im(selector); + gen_movl_seg_T0(s, R_CS); + gen_op_jmp_im((unsigned long)offset); + s->is_jmp = 1; + } + break; case 0xeb: /* jmp Jb */ val = (int8_t)insn_get(s, OT_BYTE); - val += (long)s->pc; + val += s->pc - s->cs_base; + if (s->dflag == 0) + val = val & 0xffff; gen_op_jmp_im(val); s->is_jmp = 1; break; case 0x70 ... 0x7f: /* jcc Jb */ val = (int8_t)insn_get(s, OT_BYTE); - val += (long)s->pc; goto do_jcc; case 0x180 ... 0x18f: /* jcc Jv */ if (dflag) { @@ -2628,9 +2899,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { val = (int16_t)insn_get(s, OT_WORD); } - val += (long)s->pc; /* XXX: fix 16 bit wrap */ do_jcc: - gen_jcc(s, b, val); + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_jcc(s, b, val, next_eip); s->is_jmp = 1; break; @@ -2661,11 +2935,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_movl_T0_eflags(); - gen_op_pushl_T0(); + gen_push_T0(s); break; case 0x9d: /* popf */ - gen_op_popl_T0(); + gen_pop_T0(s); gen_op_movl_eflags_T0(); + gen_pop_update(s); s->cc_op = CC_OP_EFLAGS; break; case 0x9e: /* sahf */ @@ -2860,8 +3135,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xe2: /* loop */ case 0xe3: /* jecxz */ val = (int8_t)insn_get(s, OT_BYTE); - val += (long)s->pc; - gen_op_loop[s->aflag][b & 3](val, (long)s->pc); + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_op_loop[s->aflag][b & 3](val, next_eip); s->is_jmp = 1; break; case 0x131: /* rdtsc */ @@ -3203,8 +3481,8 @@ static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; /* return the next pc */ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, - int *gen_code_size_ptr, uint8_t *pc_start, - int flags) + int *gen_code_size_ptr, + uint8_t *pc_start, uint8_t *cs_base, int flags) { DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; @@ -3218,9 +3496,11 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, /* generate intermediate code */ dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; + dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; dc->cc_op = CC_OP_DYNAMIC; + dc->cs_base = cs_base; gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; @@ -3242,7 +3522,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, gen_op_set_cc_op(dc->cc_op); if (dc->is_jmp != 1) { /* we add an additionnal jmp to update the simulated PC */ - gen_op_jmp_im(ret); + gen_op_jmp_im(ret - (unsigned long)dc->cs_base); } *gen_opc_ptr = INDEX_op_end; @@ -3258,11 +3538,11 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, disasm_info.arch = bfd_get_arch (abfd); disasm_info.mach = bfd_get_mach (abfd); #endif -#ifdef WORDS_BIGENDIAN - disasm_info.endian = BFD_ENDIAN_BIG; -#else disasm_info.endian = BFD_ENDIAN_LITTLE; -#endif + if (dc->code32) + disasm_info.mach = bfd_mach_i386_i386; + else + disasm_info.mach = bfd_mach_i386_i8086; fprintf(logfile, "----------------\n"); fprintf(logfile, "IN:\n"); disasm_info.buffer = pc_start; @@ -3304,6 +3584,19 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, uint8_t *pc; int count; + INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); +#if 0 + disasm_info.flavour = bfd_get_flavour (abfd); + disasm_info.arch = bfd_get_arch (abfd); + disasm_info.mach = bfd_get_mach (abfd); +#endif +#ifdef WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif + disasm_info.mach = bfd_mach_i386_i386; + pc = gen_code_buf; disasm_info.buffer = pc; disasm_info.buffer_vma = (unsigned long)pc; -- cgit v1.2.3 From 612384d77146639cebdc9b71c87ee4a94bf44501 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 Mar 2003 17:31:19 +0000 Subject: added libgemu.a build git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@39 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 7f0f8be2b..ea67590c3 100644 --- a/Makefile +++ b/Makefile @@ -36,21 +36,27 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o thunk.o syscall.o -OBJS+=translate-i386.o op-i386.o exec-i386.o +OBJS= elfload.o main.o thunk.o syscall.o libgemu.a + +LIBOBJS+=translate-i386.o op-i386.o exec-i386.o # NOTE: the disassembler code is only needed for debugging -OBJS+=i386-dis.o dis-buf.o +LIBOBJS+=i386-dis.o dis-buf.o SRCS = $(OBJS:.o=.c) all: gemu gemu: $(OBJS) - $(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS) + $(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend -# new i386 emulator +# libgemu + +libgemu.a: $(LIBOBJS) + rm -f $@ + $(AR) rcs $@ $(LIBOBJS) + dyngen: dyngen.c $(HOST_CC) -O2 -Wall -g $< -o $@ @@ -67,11 +73,14 @@ op-i386.o: op-i386.c opreg_template.h ops_template.h clean: $(MAKE) -C tests clean - rm -f *.o *~ gemu dyngen TAGS + rm -f *.o *.a *~ gemu dyngen TAGS distclean: clean rm -f config.mak config.h +install: gemu + install -m755 -s gemu $(prefix)/bin + # various test targets test speed: gemu make -C tests $@ @@ -89,8 +98,9 @@ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ i386.ld ppc.ld exec-i386.h exec-i386.c configure VERSION \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ -tests/test-i386-muldiv.h\ -tests/test2.c tests/hello.c tests/hello tests/sha1.c +tests/test-i386-muldiv.h tests/test-i386-code16.S\ +tests/hello.c tests/hello tests/sha1.c \ +tests/testsig.c tests/testclone.c tests/testthread.c FILE=gemu-$(VERSION) -- cgit v1.2.3 From 1b6b029e40c4297ce9c27e0f8b8ae177085c990a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 Mar 2003 17:31:38 +0000 Subject: basic clone() support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@40 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 9 ++++--- exec-i386.c | 50 ++++++++++++++++++++++++++++++++++ exec-i386.h | 2 ++ linux-user/main.c | 68 +++++++++++++++++++++++++---------------------- linux-user/qemu.h | 4 +-- linux-user/syscall.c | 66 ++++++++++++++++++++++++++++++++++++++++++--- linux-user/syscall_defs.h | 5 ++++ op-i386.c | 11 ++++++++ opc-i386.h | 2 ++ tests/Makefile | 10 +++++-- tests/testclone.c | 61 ++++++++++++++++++++++++++++++++++++++++++ tests/testsig.c | 24 +++++++++++++++++ tests/testthread.c | 50 ++++++++++++++++++++++++++++++++++ translate-i386.c | 9 +++++++ 14 files changed, 327 insertions(+), 44 deletions(-) create mode 100644 tests/testclone.c create mode 100644 tests/testsig.c create mode 100644 tests/testthread.c diff --git a/TODO b/TODO index 36efe4e9e..5c7c963df 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,9 @@ -- overrides/16bit for string ops -- optimize translated cache chaining (DLL PLT-like system) -- 64 bit syscalls +- verify thread support (clone() and various locks) - signals -- threads +- optimize translated cache chaining (DLL PLT-like system) +- vm86 syscall support +- overrides/16bit for string ops +- more syscalls (in particular all 64 bit ones) - make it self runnable (use same trick as ld.so : include its own relocator and libc) - improved 16 bit support - fix FPU exceptions (in particular: gen_op_fpush not before mem load) diff --git a/exec-i386.c b/exec-i386.c index e83d22036..573ba0a8c 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -52,6 +52,52 @@ int nb_tbs; uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; uint8_t *code_gen_ptr; +/* thread support */ + +#ifdef __powerpc__ +static inline int testandset (int *p) +{ + int ret; + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r" (ret) + : "r" (p), "r" (1), "r" (0) + : "cr0", "memory"); + return ret; +} +#endif + +#ifdef __i386__ +static inline int testandset (int *p) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (1), "m" (*p), "a" (0) + : "memory"); + return ret; +} +#endif + +int global_cpu_lock = 0; + +void cpu_lock(void) +{ + while (testandset(&global_cpu_lock)); +} + +void cpu_unlock(void) +{ + global_cpu_lock = 0; +} + #ifdef DEBUG_EXEC static const char *cc_op_str[] = { "DYNAMIC", @@ -266,11 +312,15 @@ int cpu_x86_exec(CPUX86State *env1) tc_ptr = tb->tc_ptr; if (!tb->tc_ptr) { /* if no translated code available, then translate it now */ + /* XXX: very inefficient: we lock all the cpus when + generating code */ + cpu_lock(); tc_ptr = code_gen_ptr; cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, &code_gen_size, pc, cs_base, flags); tb->tc_ptr = tc_ptr; code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); + cpu_unlock(); } /* execute the generated code */ gen_func = (void *)tc_ptr; diff --git a/exec-i386.h b/exec-i386.h index f2e1386b5..0bcfd22df 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -139,3 +139,5 @@ typedef struct CCTable { extern CCTable cc_table[]; void load_seg(int seg_reg, int selector); +void cpu_lock(void); +void cpu_unlock(void); diff --git a/linux-user/main.c b/linux-user/main.c index 3222629b2..cd08c474c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -104,6 +104,40 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit, uint64_t gdt_table[6]; +void cpu_loop(struct CPUX86State *env) +{ + for(;;) { + int err; + uint8_t *pc; + + err = cpu_x86_exec(env); + pc = env->seg_cache[R_CS].base + env->eip; + switch(err) { + case EXCP0D_GPF: + if (pc[0] == 0xcd && pc[1] == 0x80) { + /* syscall */ + env->eip += 2; + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP]); + } else { + goto trap_error; + } + break; + default: + trap_error: + fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", + (long)pc, err); + abort(); + } + } +} + void usage(void) { printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" @@ -113,8 +147,6 @@ void usage(void) exit(1); } - - int main(int argc, char **argv) { const char *filename; @@ -193,35 +225,7 @@ int main(int argc, char **argv) cpu_x86_load_seg(env, R_FS, __USER_DS); cpu_x86_load_seg(env, R_GS, __USER_DS); - for(;;) { - int err; - uint8_t *pc; - - err = cpu_x86_exec(env); - pc = env->seg_cache[R_CS].base + env->eip; - switch(err) { - case EXCP0D_GPF: - if (pc[0] == 0xcd && pc[1] == 0x80) { - /* syscall */ - env->eip += 2; - env->regs[R_EAX] = do_syscall(env, - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP]); - } else { - goto trap_error; - } - break; - default: - trap_error: - fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", - (long)pc, err); - abort(); - } - } + cpu_loop(env); + /* never exits */ return 0; } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 4f09e6fde..ae86176c3 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -51,7 +51,7 @@ void syscall_init(void); long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); - - +struct CPUX86State; +void cpu_loop(struct CPUX86State *env); #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index afdf18967..da54a0a18 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -762,8 +762,48 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou } return ret; } + +/* this stack is the equivalent of the kernel stack associated with a + thread/process */ +#define NEW_STACK_SIZE 8192 + +static int clone_func(void *arg) +{ + CPUX86State *env = arg; + cpu_loop(env); + /* never exits */ + return 0; +} + +int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) +{ + int ret; + uint8_t *new_stack; + CPUX86State *new_env; + + if (flags & CLONE_VM) { + if (!newsp) + newsp = env->regs[R_ESP]; + new_stack = malloc(NEW_STACK_SIZE); + + /* we create a new CPU instance. */ + new_env = cpu_x86_init(); + memcpy(new_env, env, sizeof(CPUX86State)); + new_env->regs[R_ESP] = newsp; + new_env->regs[R_EAX] = 0; + ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); + } else { + /* if no CLONE_VM, we consider it is a fork */ + if ((flags & ~CSIGNAL) != 0) + return -EINVAL; + ret = fork(); + } + return ret; +} + #endif + void syscall_init(void) { #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); @@ -788,6 +828,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef HAVE_GPROF _mcleanup(); #endif + /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ break; @@ -807,7 +848,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = do_brk((char *)arg1); break; case TARGET_NR_fork: - ret = get_errno(fork()); + ret = get_errno(do_fork(cpu_env, SIGCHLD, 0)); break; case TARGET_NR_waitpid: { @@ -1241,7 +1282,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_sigreturn: goto unimplemented; case TARGET_NR_clone: - goto unimplemented; + ret = get_errno(do_fork(cpu_env, arg1, arg2)); + break; case TARGET_NR_setdomainname: ret = get_errno(setdomainname((const char *)arg1, arg2)); break; @@ -1310,7 +1352,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_sysfs: goto unimplemented; case TARGET_NR_personality: - ret = get_errno(mprotect((void *)arg1, arg2, arg3)); + ret = get_errno(personality(arg1)); break; case TARGET_NR_afs_syscall: goto unimplemented; @@ -1447,7 +1489,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_sched_get_priority_max: case TARGET_NR_sched_get_priority_min: case TARGET_NR_sched_rr_get_interval: + goto unimplemented; + case TARGET_NR_nanosleep: + { + struct target_timespec *target_req = (void *)arg1; + struct target_timespec *target_rem = (void *)arg2; + struct timespec req, rem; + req.tv_sec = tswapl(target_req->tv_sec); + req.tv_nsec = tswapl(target_req->tv_nsec); + ret = get_errno(nanosleep(&req, &rem)); + if (target_rem) { + target_rem->tv_sec = tswapl(rem.tv_sec); + target_rem->tv_nsec = tswapl(rem.tv_nsec); + } + } + break; + case TARGET_NR_mremap: case TARGET_NR_setresuid: case TARGET_NR_getresuid: @@ -1481,7 +1539,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getpmsg: case TARGET_NR_putpmsg: case TARGET_NR_vfork: - ret = get_errno(vfork()); + ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); break; case TARGET_NR_ugetrlimit: case TARGET_NR_truncate64: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 8b2d6bd75..6b0a714cb 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -24,6 +24,11 @@ struct target_timeval { target_long tv_usec; }; +struct target_timespec { + target_long tv_sec; + target_long tv_nsec; +}; + struct target_iovec { target_long iov_base; /* Starting address */ target_long iov_len; /* Number of bytes */ diff --git a/op-i386.c b/op-i386.c index a9583ecf3..835a1ed51 100644 --- a/op-i386.c +++ b/op-i386.c @@ -2272,3 +2272,14 @@ void OPPROTO op_fninit(void) env->fptags[6] = 1; env->fptags[7] = 1; } + +/* threading support */ +void OPPROTO op_lock(void) +{ + cpu_lock(); +} + +void OPPROTO op_unlock(void) +{ + cpu_unlock(); +} diff --git a/opc-i386.h b/opc-i386.h index 092904468..9d9f8471b 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -530,3 +530,5 @@ DEF(fnstcw_A0) DEF(fldcw_A0) DEF(fclex) DEF(fninit) +DEF(lock) +DEF(unlock) diff --git a/tests/Makefile b/tests/Makefile index 3cc205d5b..33623843d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -4,7 +4,7 @@ CFLAGS=-Wall -O2 -g LDFLAGS= ifeq ($(ARCH),i386) -TESTS=test2 sha1-i386 test-i386 +TESTS=testclone testsig testthread sha1-i386 test-i386 endif TESTS+=sha1 @@ -16,9 +16,15 @@ hello: hello.c $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< strip hello -test2: test2.c +testclone: testclone.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< +testsig: testsig.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +testthread: testthread.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread + # i386 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h diff --git a/tests/testclone.c b/tests/testclone.c new file mode 100644 index 000000000..2152dfcf2 --- /dev/null +++ b/tests/testclone.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int thread1_func(void *arg) +{ + int i; + char buf[512]; + + for(i=0;i<10;i++) { + snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg); + write(1, buf, strlen(buf)); + usleep(100 * 1000); + } + return 0; +} + +int thread2_func(void *arg) +{ + int i; + char buf[512]; + for(i=0;i<20;i++) { + snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg); + write(1, buf, strlen(buf)); + usleep(120 * 1000); + } + return 0; +} + +#define STACK_SIZE 16384 + +void test_clone(void) +{ + uint8_t *stack1, *stack2; + int pid1, pid2, status1, status2; + + stack1 = malloc(STACK_SIZE); + pid1 = clone(thread1_func, stack1 + STACK_SIZE, + CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"); + + stack2 = malloc(STACK_SIZE); + pid2 = clone(thread2_func, stack2 + STACK_SIZE, + CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"); + + while (waitpid(pid1, &status1, 0) != pid1); + while (waitpid(pid2, &status2, 0) != pid2); + printf("status1=0x%x\n", status1); + printf("status2=0x%x\n", status2); + printf("End of clone test.\n"); +} + +int main(int argc, char **argv) +{ + test_clone(); + return 0; +} diff --git a/tests/testsig.c b/tests/testsig.c new file mode 100644 index 000000000..59af54fc8 --- /dev/null +++ b/tests/testsig.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +void alarm_handler(int sig) +{ + printf("alarm signal=%d\n", sig); + alarm(1); +} + +int main(int argc, char **argv) +{ + struct sigaction act; + act.sa_handler = alarm_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGALRM, &act, NULL); + alarm(1); + for(;;) { + sleep(1); + } + return 0; +} diff --git a/tests/testthread.c b/tests/testthread.c new file mode 100644 index 000000000..9a590dbd4 --- /dev/null +++ b/tests/testthread.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void *thread1_func(void *arg) +{ + int i; + char buf[512]; + + for(i=0;i<10;i++) { + snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg); + write(1, buf, strlen(buf)); + usleep(100 * 1000); + } + return NULL; +} + +void *thread2_func(void *arg) +{ + int i; + char buf[512]; + for(i=0;i<20;i++) { + snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg); + write(1, buf, strlen(buf)); + usleep(150 * 1000); + } + return NULL; +} + +void test_pthread(void) +{ + pthread_t tid1, tid2; + + pthread_create(&tid1, NULL, thread1_func, "hello1"); + pthread_create(&tid2, NULL, thread2_func, "hello2"); + pthread_join(tid1, NULL); + pthread_join(tid2, NULL); + printf("End of pthread test.\n"); +} + +int main(int argc, char **argv) +{ + test_pthread(); + return 0; +} diff --git a/translate-i386.c b/translate-i386.c index 5cbaa813c..b7a7cdc20 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1395,6 +1395,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->aflag = aflag; s->dflag = dflag; + /* lock generation */ + if (prefixes & PREFIX_LOCK) + gen_op_lock(); + /* now check op code */ reswitch: switch(b) { @@ -3153,8 +3157,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) default: goto illegal_op; } + /* lock generation */ + if (s->prefix & PREFIX_LOCK) + gen_op_unlock(); return (long)s->pc; illegal_op: + /* XXX: ensure that no lock was generated */ return -1; } @@ -3609,6 +3617,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, pc += count; } fprintf(logfile, "\n"); + fflush(logfile); } #endif return 0; -- cgit v1.2.3 From 66fb9763af9cd743158957e8c9c2559d922b1c22 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Mar 2003 01:06:05 +0000 Subject: basic signal handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@41 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- TODO | 4 +- linux-user/main.c | 6 +- linux-user/qemu.h | 10 + linux-user/signal.c | 739 ++++++++++++++++++++++++++++++++++++++++++++-- linux-user/syscall.c | 294 ++++++++++++++---- linux-user/syscall_defs.h | 37 +++ ops_template.h | 20 ++ syscall-i386.h | 45 ++- 9 files changed, 1058 insertions(+), 99 deletions(-) diff --git a/Makefile b/Makefile index ea67590c3..9f1d31c36 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o thunk.o syscall.o libgemu.a +OBJS= elfload.o main.o thunk.o syscall.o signal.o libgemu.a LIBOBJS+=translate-i386.o op-i386.o exec-i386.o # NOTE: the disassembler code is only needed for debugging diff --git a/TODO b/TODO index 5c7c963df..64384834a 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,7 @@ +- asynchronous signal interrupt / clear synchronous signal handling +- add eflags restore in emulator +- finish signal handing (fp87 state) - verify thread support (clone() and various locks) -- signals - optimize translated cache chaining (DLL PLT-like system) - vm86 syscall support - overrides/16bit for string ops diff --git a/linux-user/main.c b/linux-user/main.c index cd08c474c..bcaa4be16 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -81,10 +81,6 @@ int cpu_x86_inl(int addr) return 0; } -/* default linux values for the selectors */ -#define __USER_CS (0x23) -#define __USER_DS (0x2B) - void write_dt(void *ptr, unsigned long addr, unsigned long limit, int seg32_bit) { @@ -135,6 +131,7 @@ void cpu_loop(struct CPUX86State *env) (long)pc, err); abort(); } + process_pending_signals(env); } } @@ -199,6 +196,7 @@ int main(int argc, char **argv) target_set_brk((char *)info->brk); syscall_init(); + signal_init(); env = cpu_x86_init(); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index ae86176c3..77e9ecadd 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -3,6 +3,12 @@ #include "thunk.h" +#ifdef TARGET_I386 + +/* default linux values for the selectors */ +#define __USER_CS (0x23) +#define __USER_DS (0x2B) + struct target_pt_regs { long ebx; long ecx; @@ -21,6 +27,8 @@ struct target_pt_regs { int xss; }; +#endif + /* This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain * task_struct fields in the kernel @@ -53,5 +61,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); struct CPUX86State; void cpu_loop(struct CPUX86State *env); +void process_pending_signals(void *cpu_env); +void signal_init(void); #endif diff --git a/linux-user/signal.c b/linux-user/signal.c index 2e0d59955..61baf995a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1,5 +1,5 @@ /* - * Emulation of Linux signal handling + * Emulation of Linux signals * * Copyright (c) 2003 Fabrice Bellard * @@ -19,22 +19,49 @@ */ #include #include +#include #include #include +#include #include -/* Algorithm strongly inspired from em86 : we queue the signals so - that we can handle them at precise points in the emulated code. */ +#include "gemu.h" + +#include "syscall_defs.h" + +#ifdef TARGET_I386 +#include "cpu-i386.h" +#include "syscall-i386.h" +#endif + +/* signal handling inspired from em86. */ + +//#define DEBUG_SIGNAL + +#define MAX_SIGQUEUE_SIZE 1024 + +struct sigqueue { + struct sigqueue *next; + siginfo_t info; +}; struct emulated_sigaction { struct target_sigaction sa; - int nb_pending; - struct target_siginfo info; + int pending; /* true if signal is pending */ + struct sigqueue *first; + struct sigqueue info; /* in order to always have memory for the + first signal, we put it here */ }; -struct emulated_sigaction sigact_table[NSIG]; -int signal_pending; +static struct emulated_sigaction sigact_table[TARGET_NSIG]; +static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ +static struct sigqueue *first_free; /* first free siginfo queue entry */ +static int signal_pending; /* non zero if a signal may be pending */ +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc); + +/* XXX: do it properly */ static inline int host_to_target_signal(int sig) { return sig; @@ -45,6 +72,51 @@ static inline int target_to_host_signal(int sig) return sig; } +void host_to_target_sigset(target_sigset_t *d, sigset_t *s) +{ + int i; + for(i = 0;i < TARGET_NSIG_WORDS; i++) { + d->sig[i] = tswapl(((unsigned long *)s)[i]); + } +} + +void target_to_host_sigset(sigset_t *d, target_sigset_t *s) +{ + int i; + for(i = 0;i < TARGET_NSIG_WORDS; i++) { + ((unsigned long *)d)[i] = tswapl(s->sig[i]); + } +} + +void host_to_target_old_sigset(target_ulong *old_sigset, + const sigset_t *sigset) +{ + *old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff); +} + +void target_to_host_old_sigset(sigset_t *sigset, + const target_ulong *old_sigset) +{ + sigemptyset(sigset); + *(unsigned long *)sigset = tswapl(*old_sigset); +} + +/* XXX: finish it */ +void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info) +{ + tinfo->si_signo = tswap32(info->si_signo); + tinfo->si_errno = tswap32(info->si_errno); + tinfo->si_code = tswap32(info->si_code); +} + +/* XXX: finish it */ +void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo) +{ + info->si_signo = tswap32(tinfo->si_signo); + info->si_errno = tswap32(tinfo->si_errno); + info->si_code = tswap32(tinfo->si_code); +} + void signal_init(void) { struct sigaction act; @@ -55,51 +127,664 @@ void signal_init(void) act.sa_flags = SA_SIGINFO; act.sa_sigaction = host_signal_handler; for(i = 1; i < NSIG; i++) { - sigaction(i, &sa, NULL); + sigaction(i, &act, NULL); } memset(sigact_table, 0, sizeof(sigact_table)); + + first_free = &sigqueue_table[0]; + for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) + sigqueue_table[i].next = &sigqueue_table[i + 1]; + sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; +} + +/* signal queue handling */ + +static inline struct sigqueue *alloc_sigqueue(void) +{ + struct sigqueue *q = first_free; + if (!q) + return NULL; + first_free = q->next; + return q; } +static inline void free_sigqueue(struct sigqueue *q) +{ + q->next = first_free; + first_free = q; +} + +static int queue_signal(struct emulated_sigaction *k, int sig, siginfo_t *info) +{ + struct sigqueue *q, **pq; + + pq = &k->first; + if (!k->pending || sig < TARGET_SIGRTMIN) { + /* first signal or non real time signal */ + q = &k->info; + } else { + q = alloc_sigqueue(); + if (!q) + return -EAGAIN; + while (*pq != NULL) + pq = &(*pq)->next; + } + *pq = q; + q->info = *info; + q->next = NULL; + k->pending = 1; + /* signal that a new signal is pending */ + signal_pending = 1; + return 0; +} + +void force_sig(int sig) +{ + int host_sig; + /* abort execution with signal */ + host_sig = target_to_host_signal(sig); + fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n", + sig, strsignal(host_sig)); + _exit(-host_sig); +} + + static void host_signal_handler(int host_signum, siginfo_t *info, void *puc) { - struct ucontext *uc = puc; - int signum; + struct emulated_sigaction *k; + int sig; + target_ulong handler; + /* get target signal number */ - signum = host_to_target(host_signum); - if (signum >= TARGET_NSIG) + sig = host_to_target_signal(host_signum); + if (sig < 1 || sig > TARGET_NSIG) return; - /* we save the old mask */ - - + k = &sigact_table[sig - 1]; +#ifdef DEBUG_SIGNAL + fprintf(stderr, "gemu: got signal %d\n", sig); +#endif + handler = k->sa._sa_handler; + if (handler == TARGET_SIG_DFL) { + /* default handler : ignore some signal. The other are fatal */ + if (sig != TARGET_SIGCHLD && + sig != TARGET_SIGURG && + sig != TARGET_SIGWINCH) { + force_sig(sig); + } + } else if (handler == TARGET_SIG_IGN) { + /* ignore signal */ + } else if (handler == TARGET_SIG_ERR) { + force_sig(sig); + } else { + queue_signal(k, sig, info); + } +} + +int do_sigaction(int sig, const struct target_sigaction *act, + struct target_sigaction *oact) +{ + struct emulated_sigaction *k; + + if (sig < 1 || sig > TARGET_NSIG) + return -EINVAL; + k = &sigact_table[sig - 1]; +#if defined(DEBUG_SIGNAL) && 0 + fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n", + sig, (int)act, (int)oact); +#endif + if (oact) { + oact->_sa_handler = tswapl(k->sa._sa_handler); + oact->sa_flags = tswapl(k->sa.sa_flags); + oact->sa_restorer = tswapl(k->sa.sa_restorer); + oact->sa_mask = k->sa.sa_mask; + } + if (act) { + k->sa._sa_handler = tswapl(act->_sa_handler); + k->sa.sa_flags = tswapl(act->sa_flags); + k->sa.sa_restorer = tswapl(act->sa_restorer); + k->sa.sa_mask = act->sa_mask; + } + return 0; +} + +#ifdef TARGET_I386 + +/* from the Linux kernel */ + +struct target_fpreg { + uint16_t significand[4]; + uint16_t exponent; +}; + +struct target_fpxreg { + uint16_t significand[4]; + uint16_t exponent; + uint16_t padding[3]; +}; + +struct target_xmmreg { + target_ulong element[4]; +}; + +struct target_fpstate { + /* Regular FPU environment */ + target_ulong cw; + target_ulong sw; + target_ulong tag; + target_ulong ipoff; + target_ulong cssel; + target_ulong dataoff; + target_ulong datasel; + struct target_fpreg _st[8]; + uint16_t status; + uint16_t magic; /* 0xffff = regular FPU data only */ + + /* FXSR FPU environment */ + target_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */ + target_ulong mxcsr; + target_ulong reserved; + struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ + struct target_xmmreg _xmm[8]; + target_ulong padding[56]; +}; + +#define X86_FXSR_MAGIC 0x0000 + +struct target_sigcontext { + uint16_t gs, __gsh; + uint16_t fs, __fsh; + uint16_t es, __esh; + uint16_t ds, __dsh; + target_ulong edi; + target_ulong esi; + target_ulong ebp; + target_ulong esp; + target_ulong ebx; + target_ulong edx; + target_ulong ecx; + target_ulong eax; + target_ulong trapno; + target_ulong err; + target_ulong eip; + uint16_t cs, __csh; + target_ulong eflags; + target_ulong esp_at_signal; + uint16_t ss, __ssh; + target_ulong fpstate; /* pointer */ + target_ulong oldmask; + target_ulong cr2; +}; + +typedef struct target_sigaltstack { + target_ulong ss_sp; + int ss_flags; + target_ulong ss_size; +} target_stack_t; + +struct target_ucontext { + target_ulong uc_flags; + target_ulong uc_link; + target_stack_t uc_stack; + struct target_sigcontext uc_mcontext; + target_sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +struct sigframe +{ + target_ulong pretcode; + int sig; + struct target_sigcontext sc; + struct target_fpstate fpstate; + target_ulong extramask[TARGET_NSIG_WORDS-1]; + char retcode[8]; +}; + +struct rt_sigframe +{ + target_ulong pretcode; + int sig; + target_ulong pinfo; + target_ulong puc; + struct target_siginfo info; + struct target_ucontext uc; + struct target_fpstate fpstate; + char retcode[8]; +}; + +/* + * Set up a signal frame. + */ + +#define __put_user(x,ptr)\ +({\ + int size = sizeof(*ptr);\ + switch(size) {\ + case 1:\ + stb(ptr, (typeof(*ptr))(x));\ + break;\ + case 2:\ + stw(ptr, (typeof(*ptr))(x));\ + break;\ + case 4:\ + stl(ptr, (typeof(*ptr))(x));\ + break;\ + case 8:\ + stq(ptr, (typeof(*ptr))(x));\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) + +#define get_user(val, ptr) (typeof(*ptr))(*(ptr)) + + +#define __copy_to_user(dst, src, size)\ +({\ + memcpy(dst, src, size);\ + 0;\ +}) + +static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, siginfo_t *info) +{ + host_to_target_siginfo(tinfo, info); + return 0; +} + +/* XXX: save x87 state */ +static int +setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, + CPUX86State *env, unsigned long mask) +{ + int err = 0; + + err |= __put_user(env->segs[R_GS], (unsigned int *)&sc->gs); + err |= __put_user(env->segs[R_FS], (unsigned int *)&sc->fs); + err |= __put_user(env->segs[R_ES], (unsigned int *)&sc->es); + err |= __put_user(env->segs[R_DS], (unsigned int *)&sc->ds); + err |= __put_user(env->regs[R_EDI], &sc->edi); + err |= __put_user(env->regs[R_ESI], &sc->esi); + err |= __put_user(env->regs[R_EBP], &sc->ebp); + err |= __put_user(env->regs[R_ESP], &sc->esp); + err |= __put_user(env->regs[R_EBX], &sc->ebx); + err |= __put_user(env->regs[R_EDX], &sc->edx); + err |= __put_user(env->regs[R_ECX], &sc->ecx); + err |= __put_user(env->regs[R_EAX], &sc->eax); + err |= __put_user(/*current->thread.trap_no*/ 0, &sc->trapno); + err |= __put_user(/*current->thread.error_code*/ 0, &sc->err); + err |= __put_user(env->eip, &sc->eip); + err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs); + err |= __put_user(env->eflags, &sc->eflags); + err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal); + err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss); +#if 0 + tmp = save_i387(fpstate); + if (tmp < 0) + err = 1; + else + err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); +#else + err |= __put_user(0, &sc->fpstate); +#endif + /* non-iBCS2 extensions.. */ + err |= __put_user(mask, &sc->oldmask); + err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2); + + return err; } +/* + * Determine which stack to use.. + */ -void process_pending_signals(void) +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) { - int signum; - target_ulong _sa_handler; + unsigned long esp; + + /* Default to using normal stack */ + esp = env->regs[R_ESP]; +#if 0 + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (sas_ss_flags(esp) == 0) + esp = current->sas_ss_sp + current->sas_ss_size; + } + + /* This is the legacy signal stack switching. */ + else if ((regs->xss & 0xffff) != __USER_DS && + !(ka->sa.sa_flags & SA_RESTORER) && + ka->sa.sa_restorer) { + esp = (unsigned long) ka->sa.sa_restorer; + } +#endif + return (void *)((esp - frame_size) & -8ul); +} + +#define TF_MASK TRAP_FLAG + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUX86State *env) +{ + struct sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, env, sizeof(*frame)); + +#if 0 + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; +#endif + err |= __put_user((/*current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : */ sig), + &frame->sig); + if (err) + goto give_sigsegv; + + setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0]); + if (err) + goto give_sigsegv; + + if (TARGET_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + } else { + err |= __put_user(frame->retcode, &frame->pretcode); + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + err |= __put_user(0xb858, (short *)(frame->retcode+0)); + err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); + err |= __put_user(0x80cd, (short *)(frame->retcode+6)); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + env->regs[R_ESP] = (unsigned long) frame; + env->eip = (unsigned long) ka->sa._sa_handler; + + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_CS, __USER_CS); + env->eflags &= ~TF_MASK; + + return; + +give_sigsegv: + if (sig == TARGET_SIGSEGV) + ka->sa._sa_handler = TARGET_SIG_DFL; + force_sig(TARGET_SIGSEGV /* , current */); +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, siginfo_t *info, + target_sigset_t *set, CPUX86State *env) +{ + struct rt_sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, env, sizeof(*frame)); + +#if 0 + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; +#endif + + err |= __put_user((/*current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : */sig), + &frame->sig); + err |= __put_user((target_ulong)&frame->info, &frame->pinfo); + err |= __put_user((target_ulong)&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + if (err) + goto give_sigsegv; - struct emulated_sigaction *esig; + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(/*current->sas_ss_sp*/ 0, &frame->uc.uc_stack.ss_sp); + err |= __put_user(/* sas_ss_flags(regs->esp) */ 0, + &frame->uc.uc_stack.ss_flags); + err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, + env, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + } else { + err |= __put_user(frame->retcode, &frame->pretcode); + /* This is movl $,%eax ; int $0x80 */ + err |= __put_user(0xb8, (char *)(frame->retcode+0)); + err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + env->regs[R_ESP] = (unsigned long) frame; + env->eip = (unsigned long) ka->sa._sa_handler; + + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_CS, __USER_CS); + env->eflags &= ~TF_MASK; + + return; + +give_sigsegv: + if (sig == TARGET_SIGSEGV) + ka->sa._sa_handler = TARGET_SIG_DFL; + force_sig(TARGET_SIGSEGV /* , current */); +} + +static int +restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax) +{ + unsigned int err = 0; + + + +#define COPY(x) err |= __get_user(regs->x, &sc->x) + +#define COPY_SEG(seg) \ + { unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + regs->x##seg = tmp; } + +#define COPY_SEG_STRICT(seg) \ + { unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + regs->x##seg = tmp|3; } + +#define GET_SEG(seg) \ + { unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + loadsegment(seg,tmp); } + + cpu_x86_load_seg(env, R_GS, lduw(&sc->gs)); + cpu_x86_load_seg(env, R_FS, lduw(&sc->fs)); + cpu_x86_load_seg(env, R_ES, lduw(&sc->es)); + cpu_x86_load_seg(env, R_DS, lduw(&sc->ds)); + + env->regs[R_EDI] = ldl(&sc->edi); + env->regs[R_ESI] = ldl(&sc->esi); + env->regs[R_EBP] = ldl(&sc->ebp); + env->regs[R_ESP] = ldl(&sc->esp); + env->regs[R_EBX] = ldl(&sc->ebx); + env->regs[R_EDX] = ldl(&sc->edx); + env->regs[R_ECX] = ldl(&sc->ecx); + env->eip = ldl(&sc->eip); + + cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3); + cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3); + + { + unsigned int tmpflags; + tmpflags = ldl(&sc->eflags); + env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); + // regs->orig_eax = -1; /* disable syscall checks */ + } + +#if 0 + { + struct _fpstate * buf; + err |= __get_user(buf, &sc->fpstate); + if (buf) { + if (verify_area(VERIFY_READ, buf, sizeof(*buf))) + goto badframe; + err |= restore_i387(buf); + } + } +#endif + *peax = ldl(&sc->eax); + return err; +#if 0 +badframe: + return 1; +#endif +} + +long do_sigreturn(CPUX86State *env) +{ + struct sigframe *frame = (struct sigframe *)(env->regs[R_ESP] - 8); + target_sigset_t target_set; + sigset_t set; + int eax, i; + + /* set blocked signals */ + target_set.sig[0] = frame->sc.oldmask; + for(i = 1; i < TARGET_NSIG_WORDS; i++) + target_set.sig[i] = frame->extramask[i - 1]; + + target_to_host_sigset(&set, &target_set); + sigprocmask(SIG_SETMASK, &set, NULL); + + /* restore registers */ + if (restore_sigcontext(env, &frame->sc, &eax)) + goto badframe; + return eax; + +badframe: + force_sig(TARGET_SIGSEGV); + return 0; +} + +long do_rt_sigreturn(CPUX86State *env) +{ + struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4); + target_sigset_t target_set; + sigset_t set; + // stack_t st; + int eax; + +#if 0 + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; +#endif + memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t)); + + target_to_host_sigset(&set, &target_set); + sigprocmask(SIG_SETMASK, &set, NULL); + + if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax)) + goto badframe; + +#if 0 + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs->esp); +#endif + return eax; + +badframe: + force_sig(TARGET_SIGSEGV); + return 0; +} + +#endif + +void process_pending_signals(void *cpu_env) +{ + int sig; + target_ulong handler; + target_sigset_t set; + struct emulated_sigaction *k; + struct sigqueue *q; + if (!signal_pending) return; - esig = sigact_table; - for(signum = 1; signum < TARGET_NSIG; signum++) { - if (esig->nb_pending != 0) + k = sigact_table; + for(sig = 1; sig <= TARGET_NSIG; sig++) { + if (k->pending) goto handle_signal; - esig++; + k++; } /* if no signal is pending, just return */ signal_pending = 0; return; + handle_signal: - _sa_handler = esig->sa._sa_handler; - if (_sa_handler == TARGET_SIG_DFL) { - /* default handling +#ifdef DEBUG_SIGNAL + fprintf(stderr, "gemu: process signal %d\n", sig); +#endif + /* dequeue signal */ + q = k->first; + k->first = q->next; + if (!k->first) + k->pending = 0; + + handler = k->sa._sa_handler; + if (handler == TARGET_SIG_DFL) { + /* default handler : ignore some signal. The other are fatal */ + if (sig != TARGET_SIGCHLD && + sig != TARGET_SIGURG && + sig != TARGET_SIGWINCH) { + force_sig(sig); + } + } else if (handler == TARGET_SIG_IGN) { + /* ignore sig */ + } else if (handler == TARGET_SIG_ERR) { + force_sig(sig); + } else { + set = k->sa.sa_mask; + /* send the signal to the CPU */ + if (k->sa.sa_flags & TARGET_SA_SIGINFO) + setup_rt_frame(sig, k, &q->info, &set, cpu_env); + else + setup_frame(sig, k, &set, cpu_env); + if (k->sa.sa_flags & TARGET_SA_RESETHAND) + k->sa._sa_handler = TARGET_SIG_DFL; } + if (q != &k->info) + free_sigqueue(q); +} -} diff --git a/linux-user/syscall.c b/linux-user/syscall.c index da54a0a18..dbe3de3fd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -75,12 +75,18 @@ #include "syscall-i386.h" #endif +void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info); +void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo); +long do_sigreturn(CPUX86State *env); +long do_rt_sigreturn(CPUX86State *env); + #define __NR_sys_uname __NR_uname #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_statfs __NR_statfs #define __NR_sys_fstatfs __NR_fstatfs #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 +#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo #ifdef __NR_gettid _syscall0(int, gettid) @@ -97,6 +103,9 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); _syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf) _syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf) +_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) + +extern int personality(int); static inline long get_errno(long ret) { @@ -199,18 +208,18 @@ static inline void host_to_target_fds(target_long *target_fds, #endif } -/* XXX: incorrect for some archs */ -static void host_to_target_old_sigset(target_ulong *old_sigset, - const sigset_t *sigset) +static inline void target_to_host_timeval(struct timeval *tv, + struct target_timeval *target_tv) { - *old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff); + tv->tv_sec = tswapl(target_tv->tv_sec); + tv->tv_usec = tswapl(target_tv->tv_usec); } -static void target_to_host_old_sigset(sigset_t *sigset, - const target_ulong *old_sigset) +static inline void host_to_target_timeval(struct target_timeval *target_tv, + struct timeval *tv) { - sigemptyset(sigset); - *(unsigned long *)sigset = tswapl(*old_sigset); + target_tv->tv_sec = tswapl(tv->tv_sec); + target_tv->tv_usec = tswapl(tv->tv_usec); } @@ -1042,28 +1051,195 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(setsid()); break; case TARGET_NR_sigaction: -#if 1 { - ret = 0; + struct target_old_sigaction *old_act = (void *)arg2; + struct target_old_sigaction *old_oact = (void *)arg3; + struct target_sigaction act, oact, *pact; + if (old_act) { + act._sa_handler = old_act->_sa_handler; + target_siginitset(&act.sa_mask, old_act->sa_mask); + act.sa_flags = old_act->sa_flags; + act.sa_restorer = old_act->sa_restorer; + pact = &act; + } else { + pact = NULL; + } + ret = get_errno(do_sigaction(arg1, pact, &oact)); + if (!is_error(ret) && old_oact) { + old_oact->_sa_handler = oact._sa_handler; + old_oact->sa_mask = oact.sa_mask.sig[0]; + old_oact->sa_flags = oact.sa_flags; + old_oact->sa_restorer = oact.sa_restorer; + } } break; -#else - goto unimplemented; -#endif + case TARGET_NR_rt_sigaction: + ret = get_errno(do_sigaction(arg1, (void *)arg2, (void *)arg3)); + break; case TARGET_NR_sgetmask: - goto unimplemented; + { + sigset_t cur_set; + target_ulong target_set; + sigprocmask(0, NULL, &cur_set); + host_to_target_old_sigset(&target_set, &cur_set); + ret = target_set; + } + break; case TARGET_NR_ssetmask: - goto unimplemented; + { + sigset_t set, oset, cur_set; + target_ulong target_set = arg1; + sigprocmask(0, NULL, &cur_set); + target_to_host_old_sigset(&set, &target_set); + sigorset(&set, &set, &cur_set); + sigprocmask(SIG_SETMASK, &set, &oset); + host_to_target_old_sigset(&target_set, &oset); + ret = target_set; + } + break; + case TARGET_NR_sigprocmask: + { + int how = arg1; + sigset_t set, oldset, *set_ptr; + target_ulong *pset = (void *)arg2, *poldset = (void *)arg3; + + if (pset) { + switch(how) { + case TARGET_SIG_BLOCK: + how = SIG_BLOCK; + break; + case TARGET_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + case TARGET_SIG_SETMASK: + how = SIG_SETMASK; + break; + default: + ret = -EINVAL; + goto fail; + } + target_to_host_old_sigset(&set, pset); + set_ptr = &set; + } else { + how = 0; + set_ptr = NULL; + } + ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); + if (!is_error(ret) && poldset) { + host_to_target_old_sigset(poldset, &oldset); + } + } + break; + case TARGET_NR_rt_sigprocmask: + { + int how = arg1; + sigset_t set, oldset, *set_ptr; + target_sigset_t *pset = (void *)arg2; + target_sigset_t *poldset = (void *)arg3; + + if (pset) { + switch(how) { + case TARGET_SIG_BLOCK: + how = SIG_BLOCK; + break; + case TARGET_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + case TARGET_SIG_SETMASK: + how = SIG_SETMASK; + break; + default: + ret = -EINVAL; + goto fail; + } + target_to_host_sigset(&set, pset); + set_ptr = &set; + } else { + how = 0; + set_ptr = NULL; + } + ret = get_errno(sigprocmask(how, set_ptr, &oldset)); + if (!is_error(ret) && poldset) { + host_to_target_sigset(poldset, &oldset); + } + } + break; + case TARGET_NR_sigpending: + { + sigset_t set; + ret = get_errno(sigpending(&set)); + if (!is_error(ret)) { + host_to_target_old_sigset((target_ulong *)arg1, &set); + } + } + break; + case TARGET_NR_rt_sigpending: + { + sigset_t set; + ret = get_errno(sigpending(&set)); + if (!is_error(ret)) { + host_to_target_sigset((target_sigset_t *)arg1, &set); + } + } + break; + case TARGET_NR_sigsuspend: + { + sigset_t set; + target_to_host_old_sigset(&set, (target_ulong *)arg1); + ret = get_errno(sigsuspend(&set)); + } + break; + case TARGET_NR_rt_sigsuspend: + { + sigset_t set; + target_to_host_sigset(&set, (target_sigset_t *)arg1); + ret = get_errno(sigsuspend(&set)); + } + break; + case TARGET_NR_rt_sigtimedwait: + { + target_sigset_t *target_set = (void *)arg1; + target_siginfo_t *target_uinfo = (void *)arg2; + struct target_timespec *target_uts = (void *)arg3; + sigset_t set; + struct timespec uts, *puts; + siginfo_t uinfo; + + target_to_host_sigset(&set, target_set); + if (target_uts) { + puts = &uts; + puts->tv_sec = tswapl(target_uts->tv_sec); + puts->tv_nsec = tswapl(target_uts->tv_nsec); + } else { + puts = NULL; + } + ret = get_errno(sigtimedwait(&set, &uinfo, puts)); + if (!is_error(ret) && target_uinfo) { + host_to_target_siginfo(target_uinfo, &uinfo); + } + } + break; + case TARGET_NR_rt_sigqueueinfo: + { + siginfo_t uinfo; + target_to_host_siginfo(&uinfo, (target_siginfo_t *)arg3); + ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); + } + break; + case TARGET_NR_sigreturn: + /* NOTE: ret is eax, so not transcoding must be done */ + ret = do_sigreturn(cpu_env); + break; + case TARGET_NR_rt_sigreturn: + /* NOTE: ret is eax, so not transcoding must be done */ + ret = do_rt_sigreturn(cpu_env); + break; case TARGET_NR_setreuid: ret = get_errno(setreuid(arg1, arg2)); break; case TARGET_NR_setregid: ret = get_errno(setregid(arg1, arg2)); break; - case TARGET_NR_sigsuspend: - goto unimplemented; - case TARGET_NR_sigpending: - goto unimplemented; case TARGET_NR_sethostname: ret = get_errno(sethostname((const char *)arg1, arg2)); break; @@ -1190,9 +1366,43 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_syslog: goto unimplemented; case TARGET_NR_setitimer: - goto unimplemented; + { + struct target_itimerval *target_value = (void *)arg2; + struct target_itimerval *target_ovalue = (void *)arg3; + struct itimerval value, ovalue, *pvalue; + + if (target_value) { + pvalue = &value; + target_to_host_timeval(&pvalue->it_interval, + &target_value->it_interval); + target_to_host_timeval(&pvalue->it_value, + &target_value->it_value); + } else { + pvalue = NULL; + } + ret = get_errno(setitimer(arg1, pvalue, &ovalue)); + if (!is_error(ret) && target_ovalue) { + host_to_target_timeval(&target_ovalue->it_interval, + &ovalue.it_interval); + host_to_target_timeval(&target_ovalue->it_value, + &ovalue.it_value); + } + } + break; case TARGET_NR_getitimer: - goto unimplemented; + { + struct target_itimerval *target_value = (void *)arg2; + struct itimerval value; + + ret = get_errno(getitimer(arg1, &value)); + if (!is_error(ret) && target_value) { + host_to_target_timeval(&target_value->it_interval, + &value.it_interval); + host_to_target_timeval(&target_value->it_value, + &value.it_value); + } + } + break; case TARGET_NR_stat: ret = get_errno(stat((const char *)arg1, &st)); goto do_stat; @@ -1279,8 +1489,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_fsync: ret = get_errno(fsync(arg1)); break; - case TARGET_NR_sigreturn: - goto unimplemented; case TARGET_NR_clone: ret = get_errno(do_fork(cpu_env, arg1, arg2)); break; @@ -1301,39 +1509,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_mprotect: ret = get_errno(mprotect((void *)arg1, arg2, arg3)); break; - case TARGET_NR_sigprocmask: - { - int how = arg1; - sigset_t set, oldset, *set_ptr; - target_ulong *pset = (void *)arg2, *poldset = (void *)arg3; - - switch(how) { - case TARGET_SIG_BLOCK: - how = SIG_BLOCK; - break; - case TARGET_SIG_UNBLOCK: - how = SIG_UNBLOCK; - break; - case TARGET_SIG_SETMASK: - how = SIG_SETMASK; - break; - default: - ret = -EINVAL; - goto fail; - } - - if (pset) { - target_to_host_old_sigset(&set, pset); - set_ptr = &set; - } else { - set_ptr = NULL; - } - ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); - if (!is_error(ret) && poldset) { - host_to_target_old_sigset(poldset, &oldset); - } - } - break; case TARGET_NR_create_module: case TARGET_NR_init_module: case TARGET_NR_delete_module: @@ -1516,13 +1691,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_setresgid: case TARGET_NR_getresgid: case TARGET_NR_prctl: - case TARGET_NR_rt_sigreturn: - case TARGET_NR_rt_sigaction: - case TARGET_NR_rt_sigprocmask: - case TARGET_NR_rt_sigpending: - case TARGET_NR_rt_sigtimedwait: - case TARGET_NR_rt_sigqueueinfo: - case TARGET_NR_rt_sigsuspend: case TARGET_NR_pread: case TARGET_NR_pwrite: goto unimplemented; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 6b0a714cb..b83aeaceb 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -29,6 +29,11 @@ struct target_timespec { target_long tv_nsec; }; +struct target_itimerval { + struct target_timeval it_interval; + struct target_timeval it_value; +}; + struct target_iovec { target_long iov_base; /* Starting address */ target_long iov_len; /* Number of bytes */ @@ -113,6 +118,38 @@ typedef struct { target_ulong sig[TARGET_NSIG_WORDS]; } target_sigset_t; +#ifdef BSWAP_NEEDED +static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s) +{ + int i; + for(i = 0;i < TARGET_NSIG_WORDS; i++) + d->sig[i] = tswapl(s->sig[i]); +} +#else +static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s) +{ + *d = *s; +} +#endif + +static inline void target_siginitset(target_sigset_t *d, target_ulong set) +{ + int i; + d->sig[0] = set; + for(i = 1;i < TARGET_NSIG_WORDS; i++) + d->sig[i] = 0; +} + +void host_to_target_sigset(target_sigset_t *d, sigset_t *s); +void target_to_host_sigset(sigset_t *d, target_sigset_t *s); +void host_to_target_old_sigset(target_ulong *old_sigset, + const sigset_t *sigset); +void target_to_host_old_sigset(sigset_t *sigset, + const target_ulong *old_sigset); +struct target_sigaction; +int do_sigaction(int sig, const struct target_sigaction *act, + struct target_sigaction *oact); + /* Networking ioctls */ #define TARGET_SIOCADDRT 0x890B /* add routing table entry */ #define TARGET_SIOCDELRT 0x890C /* delete routing table entry */ diff --git a/ops_template.h b/ops_template.h index 70ee9f355..1a2380041 100644 --- a/ops_template.h +++ b/ops_template.h @@ -1,3 +1,23 @@ +/* + * i386 micro operations (included several times to generate + * different operand sizes) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #define DATA_BITS (1 << (3 + SHIFT)) #define SHIFT_MASK (DATA_BITS - 1) diff --git a/syscall-i386.h b/syscall-i386.h index 3d270d775..39bba1a49 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -302,20 +302,59 @@ struct target_stat64 { unsigned long long st_ino; }; -typedef unsigned long old_sigset_t; /* at least 32 bits */ +#define TARGET_SA_NOCLDSTOP 0x00000001 +#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define TARGET_SA_SIGINFO 0x00000004 +#define TARGET_SA_ONSTACK 0x08000000 +#define TARGET_SA_RESTART 0x10000000 +#define TARGET_SA_NODEFER 0x40000000 +#define TARGET_SA_RESETHAND 0x80000000 +#define TARGET_SA_RESTORER 0x04000000 + +#define TARGET_SIGHUP 1 +#define TARGET_SIGINT 2 +#define TARGET_SIGQUIT 3 +#define TARGET_SIGILL 4 +#define TARGET_SIGTRAP 5 +#define TARGET_SIGABRT 6 +#define TARGET_SIGIOT 6 +#define TARGET_SIGBUS 7 +#define TARGET_SIGFPE 8 +#define TARGET_SIGKILL 9 +#define TARGET_SIGUSR1 10 +#define TARGET_SIGSEGV 11 +#define TARGET_SIGUSR2 12 +#define TARGET_SIGPIPE 13 +#define TARGET_SIGALRM 14 +#define TARGET_SIGTERM 15 +#define TARGET_SIGSTKFLT 16 +#define TARGET_SIGCHLD 17 +#define TARGET_SIGCONT 18 +#define TARGET_SIGSTOP 19 +#define TARGET_SIGTSTP 20 +#define TARGET_SIGTTIN 21 +#define TARGET_SIGTTOU 22 +#define TARGET_SIGURG 23 +#define TARGET_SIGXCPU 24 +#define TARGET_SIGXFSZ 25 +#define TARGET_SIGVTALRM 26 +#define TARGET_SIGPROF 27 +#define TARGET_SIGWINCH 28 +#define TARGET_SIGIO 29 +#define TARGET_SIGRTMIN 32 struct target_old_sigaction { target_ulong _sa_handler; target_ulong sa_mask; target_ulong sa_flags; - void (*sa_restorer)(void); + target_ulong sa_restorer; }; struct target_sigaction { target_ulong _sa_handler; - target_sigset_t sa_mask; target_ulong sa_flags; target_ulong sa_restorer; + target_sigset_t sa_mask; }; typedef union target_sigval { -- cgit v1.2.3 From 9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Mar 2003 16:49:39 +0000 Subject: better signal/exception support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@42 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 8 +- cpu-i386.h | 13 ++- exec-i386.c | 173 +++++++++++++++++++++++++++----- exec-i386.h | 4 + linux-user/elfload.c | 3 + linux-user/ioctls.h | 6 +- linux-user/main.c | 52 ++++++++-- linux-user/qemu.h | 33 ++----- linux-user/signal.c | 244 ++++++++++++++++++++++++++++++++++------------ linux-user/syscall.c | 115 +++++++++++++++------- linux-user/syscall_defs.h | 11 +++ op-i386.c | 48 +++------ syscall-i386.h | 46 ++++++++- tests/testsig.c | 75 +++++++++++++- translate-i386.c | 17 ++-- 15 files changed, 642 insertions(+), 206 deletions(-) diff --git a/TODO b/TODO index 64384834a..1a9e51f31 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,9 @@ -- asynchronous signal interrupt / clear synchronous signal handling -- add eflags restore in emulator -- finish signal handing (fp87 state) -- verify thread support (clone() and various locks) - optimize translated cache chaining (DLL PLT-like system) +- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues) +- finish signal handing (fp87 state, more siginfo conversions) +- verify thread support (clone() and various locks) - vm86 syscall support - overrides/16bit for string ops -- more syscalls (in particular all 64 bit ones) - make it self runnable (use same trick as ld.so : include its own relocator and libc) - improved 16 bit support - fix FPU exceptions (in particular: gen_op_fpush not before mem load) diff --git a/cpu-i386.h b/cpu-i386.h index 9125ecadc..dbe18519b 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -68,7 +68,7 @@ #define EXCP11_ALGN 18 #define EXCP12_MCHK 19 -#define EXCP_SIGNAL 256 /* async signal */ +#define EXCP_INTERRUPT 256 /* async interruption */ enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ @@ -170,9 +170,10 @@ typedef struct CPUX86State { /* various CPU modes */ int vm86; - /* exception handling */ + /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; + int interrupt_request; } CPUX86State; /* all CPU memory access use these macros */ @@ -383,11 +384,19 @@ int cpu_x86_inl(int addr); CPUX86State *cpu_x86_init(void); int cpu_x86_exec(CPUX86State *s); +void cpu_x86_interrupt(CPUX86State *s); void cpu_x86_close(CPUX86State *s); /* needed to load some predefinied segment registers */ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); +/* you can call these signal handler from you SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +struct siginfo; +int cpu_x86_signal_handler(int host_signum, struct siginfo *info, + void *puc); + /* internal functions */ #define GEN_FLAG_CODE32_SHIFT 0 diff --git a/exec-i386.c b/exec-i386.c index 573ba0a8c..269a1e42f 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -21,6 +21,7 @@ //#define DEBUG_EXEC #define DEBUG_FLUSH +//#define DEBUG_SIGNAL /* main execution loop */ @@ -98,7 +99,41 @@ void cpu_unlock(void) global_cpu_lock = 0; } -#ifdef DEBUG_EXEC +/* exception support */ +/* NOTE: not static to force relocation generation by GCC */ +void raise_exception(int exception_index) +{ + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ +#ifdef reg_EAX + env->regs[R_EAX] = EAX; +#endif +#ifdef reg_ECX + env->regs[R_ECX] = ECX; +#endif +#ifdef reg_EDX + env->regs[R_EDX] = EDX; +#endif +#ifdef reg_EBX + env->regs[R_EBX] = EBX; +#endif +#ifdef reg_ESP + env->regs[R_ESP] = ESP; +#endif +#ifdef reg_EBP + env->regs[R_EBP] = EBP; +#endif +#ifdef reg_ESI + env->regs[R_ESI] = ESI; +#endif +#ifdef reg_EDI + env->regs[R_EDI] = EDI; +#endif + env->exception_index = exception_index; + longjmp(env->jmp_env, 1); +} + +#if defined(DEBUG_EXEC) static const char *cc_op_str[] = { "DYNAMIC", "EFLAGS", @@ -132,15 +167,16 @@ static const char *cc_op_str[] = { "SARL", }; -static void cpu_x86_dump_state(void) +static void cpu_x86_dump_state(FILE *f) { int eflags; eflags = cc_table[CC_OP].compute_all(); eflags |= (DF & DIRECTION_FLAG); - fprintf(logfile, + fprintf(f, "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" - "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n", + "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n" + "EIP=%08x\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], env->cc_src, env->cc_dst, cc_op_str[env->cc_op], @@ -150,10 +186,10 @@ static void cpu_x86_dump_state(void) eflags & CC_Z ? 'Z' : '-', eflags & CC_A ? 'A' : '-', eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-' - ); + eflags & CC_C ? 'C' : '-', + env->eip); #if 1 - fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n", + fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", (double)ST0, (double)ST1, (double)ST(2), (double)ST(3)); #endif } @@ -185,10 +221,11 @@ static void tb_flush(void) } /* find a translation block in the translation cache. If not found, - allocate a new one */ -static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, - unsigned long cs_base, - unsigned int flags) + return NULL and the pointer to the last element of the list in pptb */ +static inline TranslationBlock *tb_find(TranslationBlock ***pptb, + unsigned long pc, + unsigned long cs_base, + unsigned int flags) { TranslationBlock **ptb, *tb; unsigned int h; @@ -203,16 +240,19 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, return tb; ptb = &tb->hash_next; } + *pptb = ptb; + return NULL; +} + +/* allocate a new translation block. flush the translation buffer if + too many translation blocks or too much generated code */ +static inline TranslationBlock *tb_alloc(void) +{ + TranslationBlock *tb; if (nb_tbs >= CODE_GEN_MAX_BLOCKS || (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) tb_flush(); tb = &tbs[nb_tbs++]; - *ptb = tb; - tb->pc = pc; - tb->cs_base = cs_base; - tb->flags = flags; - tb->tc_ptr = NULL; - tb->hash_next = NULL; return tb; } @@ -246,7 +286,7 @@ int cpu_x86_exec(CPUX86State *env1) #endif int code_gen_size, ret; void (*gen_func)(void); - TranslationBlock *tb; + TranslationBlock *tb, **ptb; uint8_t *tc_ptr, *cs_base, *pc; unsigned int flags; @@ -289,12 +329,21 @@ int cpu_x86_exec(CPUX86State *env1) EDI = env->regs[R_EDI]; #endif + /* put eflags in CPU temporary format */ + T0 = env->eflags; + op_movl_eflags_T0(); + CC_OP = CC_OP_EFLAGS; + env->interrupt_request = 0; + /* prepare setjmp context for exception handling */ if (setjmp(env->jmp_env) == 0) { for(;;) { + if (env->interrupt_request) { + raise_exception(EXCP_INTERRUPT); + } #ifdef DEBUG_EXEC if (loglevel) { - cpu_x86_dump_state(); + cpu_x86_dump_state(logfile); } #endif /* we compute the CPU state. We assume it will not @@ -307,28 +356,43 @@ int cpu_x86_exec(CPUX86State *env1) GEN_FLAG_ADDSEG_SHIFT; cs_base = env->seg_cache[R_CS].base; pc = cs_base + env->eip; - tb = tb_find_and_alloc((unsigned long)pc, (unsigned long)cs_base, - flags); - tc_ptr = tb->tc_ptr; - if (!tb->tc_ptr) { + tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, + flags); + if (!tb) { /* if no translated code available, then translate it now */ /* XXX: very inefficient: we lock all the cpus when generating code */ cpu_lock(); tc_ptr = code_gen_ptr; - cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, - &code_gen_size, pc, cs_base, flags); + ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, + &code_gen_size, pc, cs_base, flags); + /* if invalid instruction, signal it */ + if (ret != 0) { + cpu_unlock(); + raise_exception(EXCP06_ILLOP); + } + tb = tb_alloc(); + *ptb = tb; + tb->pc = (unsigned long)pc; + tb->cs_base = (unsigned long)cs_base; + tb->flags = flags; tb->tc_ptr = tc_ptr; + tb->hash_next = NULL; code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); cpu_unlock(); } /* execute the generated code */ + tc_ptr = tb->tc_ptr; gen_func = (void *)tc_ptr; gen_func(); } } ret = env->exception_index; + /* restore flags in standard format */ + op_movl_T0_eflags(); + env->eflags = T0; + /* restore global registers */ #ifdef reg_EAX EAX = saved_EAX; @@ -361,6 +425,12 @@ int cpu_x86_exec(CPUX86State *env1) return ret; } +void cpu_x86_interrupt(CPUX86State *s) +{ + s->interrupt_request = 1; +} + + void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) { CPUX86State *saved_env; @@ -370,3 +440,56 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) load_seg(seg_reg, selector); env = saved_env; } + +#undef EAX +#undef ECX +#undef EDX +#undef EBX +#undef ESP +#undef EBP +#undef ESI +#undef EDI +#undef EIP +#include +#include + +static inline int handle_cpu_signal(unsigned long pc, + sigset_t *old_set) +{ +#ifdef DEBUG_SIGNAL + printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", + pc, *(unsigned long *)old_set); +#endif + if (pc >= (unsigned long)code_gen_buffer && + pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + /* we restore the process signal mask as the sigreturn should + do it */ + sigprocmask(SIG_SETMASK, old_set, NULL); + /* XXX: need to compute virtual pc position by retranslating + code. The rest of the CPU state should be correct. */ + raise_exception(EXCP0D_GPF); + /* never comes here */ + return 1; + } else { + return 0; + } +} + +int cpu_x86_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ +#if defined(__i386__) + struct ucontext *uc = puc; + unsigned long pc; + sigset_t *pold_set; + + pc = uc->uc_mcontext.gregs[EIP]; + pold_set = &uc->uc_sigmask; + return handle_cpu_signal(pc, pold_set); +#else +#warning No CPU specific signal handler: cannot handle target SIGSEGV events + return 0; +#endif +} diff --git a/exec-i386.h b/exec-i386.h index 0bcfd22df..d6cac3ba0 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -141,3 +141,7 @@ extern CCTable cc_table[]; void load_seg(int seg_reg, int selector); void cpu_lock(void); void cpu_unlock(void); +void raise_exception(int exception_index); + +void OPPROTO op_movl_eflags_T0(void); +void OPPROTO op_movl_T0_eflags(void); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 43d989e9a..285d8f5c7 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -261,6 +261,9 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, /* Create enough stack to hold everything. If we don't use * it for args, we'll use it for something else... */ + /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so + we allocate a bigger stack. Need a better solution, for example + by remapping the process stack directly at the right place */ if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) { if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE, PROT_READ | PROT_WRITE, diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index eeefcac3e..f075aff4d 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -1,7 +1,7 @@ /* emulated ioctl list */ IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) - IOCTL(TCGETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize))) @@ -199,8 +199,12 @@ IOCTL(SNDCTL_TMR_METRONOME, IOC_W, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_TMR_SELECT, IOC_W, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_TMR_SOURCE, IOC_RW, MK_PTR(TYPE_INT)) +#if 0 + /* we invalidate these defines because they have a same number as + termios ioctls */ IOCTL(SNDCTL_TMR_START, 0, TYPE_NULL) IOCTL(SNDCTL_TMR_STOP, 0, TYPE_NULL) +#endif IOCTL(SNDCTL_TMR_TEMPO, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_TMR_TIMEBASE, IOC_RW, MK_PTR(TYPE_INT)) diff --git a/linux-user/main.c b/linux-user/main.c index bcaa4be16..fba23a013 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -33,7 +33,10 @@ FILE *logfile = NULL; int loglevel; -unsigned long x86_stack_size; +/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so + we allocate a bigger stack. Need a better solution, for example + by remapping the process stack directly at the right place */ +unsigned long x86_stack_size = 512 * 1024; unsigned long stktop; void gemu_log(const char *fmt, ...) @@ -102,10 +105,11 @@ uint64_t gdt_table[6]; void cpu_loop(struct CPUX86State *env) { + int err; + uint8_t *pc; + target_siginfo_t info; + for(;;) { - int err; - uint8_t *pc; - err = cpu_x86_exec(env); pc = env->seg_cache[R_CS].base + env->eip; switch(err) { @@ -122,12 +126,42 @@ void cpu_loop(struct CPUX86State *env) env->regs[R_EDI], env->regs[R_EBP]); } else { - goto trap_error; + /* XXX: more precise info */ + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = 0; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); } break; + case EXCP00_DIVZ: + /* division by zero */ + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_INTDIV; + info._sifields._sigfault._addr = env->eip; + queue_signal(info.si_signo, &info); + break; + case EXCP04_INTO: + case EXCP05_BOUND: + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = 0; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); + break; + case EXCP06_ILLOP: + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->eip; + queue_signal(info.si_signo, &info); + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; default: - trap_error: - fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", + fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n", (long)pc, err); abort(); } @@ -144,6 +178,9 @@ void usage(void) exit(1); } +/* XXX: currently only used for async signals (see signal.c) */ +CPUX86State *global_env; + int main(int argc, char **argv) { const char *filename; @@ -199,6 +236,7 @@ int main(int argc, char **argv) signal_init(); env = cpu_x86_init(); + global_env = env; /* linux register setup */ env->regs[R_EAX] = regs->eax; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 77e9ecadd..862695511 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -3,30 +3,12 @@ #include "thunk.h" -#ifdef TARGET_I386 - -/* default linux values for the selectors */ -#define __USER_CS (0x23) -#define __USER_DS (0x2B) - -struct target_pt_regs { - long ebx; - long ecx; - long edx; - long esi; - long edi; - long ebp; - long eax; - int xds; - int xes; - long orig_eax; - long eip; - int xcs; - long eflags; - long esp; - int xss; -}; +#include +#include "syscall_defs.h" +#ifdef TARGET_I386 +#include "cpu-i386.h" +#include "syscall-i386.h" #endif /* This struct is used to hold certain information about the image. @@ -59,9 +41,10 @@ void syscall_init(void); long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); -struct CPUX86State; -void cpu_loop(struct CPUX86State *env); +extern CPUX86State *global_env; +void cpu_loop(CPUX86State *env); void process_pending_signals(void *cpu_env); void signal_init(void); +int queue_signal(int sig, target_siginfo_t *info); #endif diff --git a/linux-user/signal.c b/linux-user/signal.c index 61baf995a..3e792ae69 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -27,13 +27,6 @@ #include "gemu.h" -#include "syscall_defs.h" - -#ifdef TARGET_I386 -#include "cpu-i386.h" -#include "syscall-i386.h" -#endif - /* signal handling inspired from em86. */ //#define DEBUG_SIGNAL @@ -42,7 +35,7 @@ struct sigqueue { struct sigqueue *next; - siginfo_t info; + target_siginfo_t info; }; struct emulated_sigaction { @@ -101,20 +94,66 @@ void target_to_host_old_sigset(sigset_t *sigset, *(unsigned long *)sigset = tswapl(*old_sigset); } -/* XXX: finish it */ -void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info) +/* siginfo conversion */ + +static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, + const siginfo_t *info) { - tinfo->si_signo = tswap32(info->si_signo); + int sig; + sig = host_to_target_signal(info->si_signo); + tinfo->si_signo = sig; + tinfo->si_errno = 0; + tinfo->si_code = 0; + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) { + /* should never come here, but who knows. The information for + the target is irrelevant */ + tinfo->_sifields._sigfault._addr = 0; + } else if (sig >= TARGET_SIGRTMIN) { + tinfo->_sifields._rt._pid = info->si_pid; + tinfo->_sifields._rt._uid = info->si_uid; + /* XXX: potential problem if 64 bit */ + tinfo->_sifields._rt._sigval.sival_ptr = + (target_ulong)info->si_value.sival_ptr; + } +} + +static void tswap_siginfo(target_siginfo_t *tinfo, + const target_siginfo_t *info) +{ + int sig; + sig = info->si_signo; + tinfo->si_signo = tswap32(sig); tinfo->si_errno = tswap32(info->si_errno); tinfo->si_code = tswap32(info->si_code); + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) { + tinfo->_sifields._sigfault._addr = + tswapl(info->_sifields._sigfault._addr); + } else if (sig >= TARGET_SIGRTMIN) { + tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); + tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); + tinfo->_sifields._rt._sigval.sival_ptr = + tswapl(info->_sifields._rt._sigval.sival_ptr); + } +} + + +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) +{ + host_to_target_siginfo_noswap(tinfo, info); + tswap_siginfo(tinfo, tinfo); } -/* XXX: finish it */ -void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo) +/* XXX: we support only POSIX RT signals are used. */ +/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */ +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) { info->si_signo = tswap32(tinfo->si_signo); info->si_errno = tswap32(tinfo->si_errno); info->si_code = tswap32(tinfo->si_code); + info->si_pid = tswap32(tinfo->_sifields._rt._pid); + info->si_uid = tswap32(tinfo->_sifields._rt._uid); + info->si_value.sival_ptr = + (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); } void signal_init(void) @@ -122,8 +161,9 @@ void signal_init(void) struct sigaction act; int i; - /* set all host signal handlers */ - sigemptyset(&act.sa_mask); + /* set all host signal handlers. ALL signals are blocked during + the handlers to serialize them. */ + sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; act.sa_sigaction = host_signal_handler; for(i = 1; i < NSIG; i++) { @@ -155,56 +195,40 @@ static inline void free_sigqueue(struct sigqueue *q) first_free = q; } -static int queue_signal(struct emulated_sigaction *k, int sig, siginfo_t *info) -{ - struct sigqueue *q, **pq; - - pq = &k->first; - if (!k->pending || sig < TARGET_SIGRTMIN) { - /* first signal or non real time signal */ - q = &k->info; - } else { - q = alloc_sigqueue(); - if (!q) - return -EAGAIN; - while (*pq != NULL) - pq = &(*pq)->next; - } - *pq = q; - q->info = *info; - q->next = NULL; - k->pending = 1; - /* signal that a new signal is pending */ - signal_pending = 1; - return 0; -} - -void force_sig(int sig) +/* abort execution with signal */ +void __attribute((noreturn)) force_sig(int sig) { int host_sig; - /* abort execution with signal */ host_sig = target_to_host_signal(sig); fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n", sig, strsignal(host_sig)); +#if 1 _exit(-host_sig); +#else + { + struct sigaction act; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = SIG_DFL; + sigaction(SIGABRT, &act, NULL); + abort(); + } +#endif } - -static void host_signal_handler(int host_signum, siginfo_t *info, - void *puc) +/* queue a signal so that it will be send to the virtual CPU as soon + as possible */ +int queue_signal(int sig, target_siginfo_t *info) { struct emulated_sigaction *k; - int sig; + struct sigqueue *q, **pq; target_ulong handler; - /* get target signal number */ - sig = host_to_target_signal(host_signum); - if (sig < 1 || sig > TARGET_NSIG) - return; - k = &sigact_table[sig - 1]; -#ifdef DEBUG_SIGNAL - fprintf(stderr, "gemu: got signal %d\n", sig); +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "queue_sigal: sig=%d\n", + sig); #endif + k = &sigact_table[sig - 1]; handler = k->sa._sa_handler; if (handler == TARGET_SIG_DFL) { /* default handler : ignore some signal. The other are fatal */ @@ -212,13 +236,96 @@ static void host_signal_handler(int host_signum, siginfo_t *info, sig != TARGET_SIGURG && sig != TARGET_SIGWINCH) { force_sig(sig); + } else { + return 0; /* indicate ignored */ } } else if (handler == TARGET_SIG_IGN) { /* ignore signal */ + return 0; } else if (handler == TARGET_SIG_ERR) { force_sig(sig); } else { - queue_signal(k, sig, info); + pq = &k->first; + if (sig < TARGET_SIGRTMIN) { + /* if non real time signal, we queue exactly one signal */ + if (!k->pending) + q = &k->info; + else + return 0; + } else { + if (!k->pending) { + /* first signal */ + q = &k->info; + } else { + q = alloc_sigqueue(); + if (!q) + return -EAGAIN; + while (*pq != NULL) + pq = &(*pq)->next; + } + } + *pq = q; + q->info = *info; + q->next = NULL; + k->pending = 1; + /* signal that a new signal is pending */ + signal_pending = 1; + return 1; /* indicates that the signal was queued */ + } +} + +#if defined(DEBUG_SIGNAL) +#ifdef __i386__ +static void dump_regs(struct ucontext *uc) +{ + fprintf(stderr, + "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "EFL=%08x EIP=%08x\n", + uc->uc_mcontext.gregs[EAX], + uc->uc_mcontext.gregs[EBX], + uc->uc_mcontext.gregs[ECX], + uc->uc_mcontext.gregs[EDX], + uc->uc_mcontext.gregs[ESI], + uc->uc_mcontext.gregs[EDI], + uc->uc_mcontext.gregs[EBP], + uc->uc_mcontext.gregs[ESP], + uc->uc_mcontext.gregs[EFL], + uc->uc_mcontext.gregs[EIP]); +} +#else +static void dump_regs(struct ucontext *uc) +{ +} +#endif + +#endif + +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc) +{ + int sig; + target_siginfo_t tinfo; + + /* the CPU emulator uses some host signals to detect exceptions, + we we forward to it some signals */ + if (host_signum == SIGSEGV || host_signum == SIGBUS) { + if (cpu_x86_signal_handler(host_signum, info, puc)) + return; + } + + /* get target signal number */ + sig = host_to_target_signal(host_signum); + if (sig < 1 || sig > TARGET_NSIG) + return; +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "gemu: got signal %d\n", sig); + dump_regs(puc); +#endif + host_to_target_siginfo_noswap(&tinfo, info); + if (queue_signal(sig, &tinfo) == 1) { + /* interrupt the virtual CPU as soon as possible */ + cpu_x86_interrupt(global_env); } } @@ -388,9 +495,10 @@ struct rt_sigframe 0;\ }) -static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, siginfo_t *info) +static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, + const target_siginfo_t *info) { - host_to_target_siginfo(tinfo, info); + tswap_siginfo(tinfo, info); return 0; } @@ -531,7 +639,8 @@ give_sigsegv: force_sig(TARGET_SIGSEGV /* , current */); } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, siginfo_t *info, +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, target_sigset_t *set, CPUX86State *env) { struct rt_sigframe *frame; @@ -734,7 +843,8 @@ void process_pending_signals(void *cpu_env) { int sig; target_ulong handler; - target_sigset_t set; + sigset_t set, old_set; + target_sigset_t target_old_set; struct emulated_sigaction *k; struct sigqueue *q; @@ -774,12 +884,24 @@ void process_pending_signals(void *cpu_env) } else if (handler == TARGET_SIG_ERR) { force_sig(sig); } else { - set = k->sa.sa_mask; - /* send the signal to the CPU */ + /* compute the blocked signals during the handler execution */ + target_to_host_sigset(&set, &k->sa.sa_mask); + /* SA_NODEFER indicates that the current signal should not be + blocked during the handler */ + if (!(k->sa.sa_flags & TARGET_SA_NODEFER)) + sigaddset(&set, target_to_host_signal(sig)); + + /* block signals in the handler using Linux */ + sigprocmask(SIG_BLOCK, &set, &old_set); + /* save the previous blocked signal state to restore it at the + end of the signal execution (see do_sigreturn) */ + host_to_target_sigset(&target_old_set, &old_set); + + /* prepare the stack frame of the virtual CPU */ if (k->sa.sa_flags & TARGET_SA_SIGINFO) - setup_rt_frame(sig, k, &q->info, &set, cpu_env); + setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env); else - setup_frame(sig, k, &set, cpu_env); + setup_frame(sig, k, &target_old_set, cpu_env); if (k->sa.sa_flags & TARGET_SA_RESETHAND) k->sa._sa_handler = TARGET_SIG_DFL; } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dbe3de3fd..ab78fbb0d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -38,6 +38,7 @@ #include #include #include +#include //#include #define termios host_termios @@ -68,15 +69,8 @@ #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) -#include "syscall_defs.h" - -#ifdef TARGET_I386 -#include "cpu-i386.h" -#include "syscall-i386.h" -#endif - -void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info); -void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo); +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); long do_sigreturn(CPUX86State *env); long do_rt_sigreturn(CPUX86State *env); @@ -106,6 +100,9 @@ _syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf) _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) extern int personality(int); +extern int flock(int, int); +extern int setfsuid(int); +extern int setfsgid(int); static inline long get_errno(long ret) { @@ -437,7 +434,7 @@ static long do_ioctl(long fd, long cmd, long arg) ie++; } arg_type = ie->arg_type; -#ifdef DEBUG +#if defined(DEBUG) gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); #endif switch(arg_type[0]) { @@ -1244,9 +1241,30 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(sethostname((const char *)arg1, arg2)); break; case TARGET_NR_setrlimit: - goto unimplemented; + { + /* XXX: convert resource ? */ + int resource = arg1; + struct target_rlimit *target_rlim = (void *)arg2; + struct rlimit rlim; + rlim.rlim_cur = tswapl(target_rlim->rlim_cur); + rlim.rlim_max = tswapl(target_rlim->rlim_max); + ret = get_errno(setrlimit(resource, &rlim)); + } + break; case TARGET_NR_getrlimit: - goto unimplemented; + { + /* XXX: convert resource ? */ + int resource = arg1; + struct target_rlimit *target_rlim = (void *)arg2; + struct rlimit rlim; + + ret = get_errno(getrlimit(resource, &rlim)); + if (!is_error(ret)) { + target_rlim->rlim_cur = tswapl(rlim.rlim_cur); + target_rlim->rlim_max = tswapl(rlim.rlim_max); + } + } + break; case TARGET_NR_getrusage: goto unimplemented; case TARGET_NR_gettimeofday: @@ -1317,6 +1335,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_munmap: ret = get_errno(munmap((void *)arg1, arg2)); break; + case TARGET_NR_mprotect: + ret = get_errno(mprotect((void *)arg1, arg2, arg3)); + break; + case TARGET_NR_mremap: + ret = get_errno((long)mremap((void *)arg1, arg2, arg3, arg4)); + break; + case TARGET_NR_msync: + ret = get_errno(msync((void *)arg1, arg2, arg3)); + break; + case TARGET_NR_mlock: + ret = get_errno(mlock((void *)arg1, arg2)); + break; + case TARGET_NR_munlock: + ret = get_errno(munlock((void *)arg1, arg2)); + break; + case TARGET_NR_mlockall: + ret = get_errno(mlockall(arg1)); + break; + case TARGET_NR_munlockall: + ret = get_errno(munlockall()); + break; case TARGET_NR_truncate: ret = get_errno(truncate((const char *)arg1, arg2)); break; @@ -1506,9 +1545,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif case TARGET_NR_adjtimex: goto unimplemented; - case TARGET_NR_mprotect: - ret = get_errno(mprotect((void *)arg1, arg2, arg3)); - break; case TARGET_NR_create_module: case TARGET_NR_init_module: case TARGET_NR_delete_module: @@ -1532,9 +1568,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_afs_syscall: goto unimplemented; case TARGET_NR_setfsuid: - goto unimplemented; + ret = get_errno(setfsuid(arg1)); + break; case TARGET_NR_setfsgid: - goto unimplemented; + ret = get_errno(setfsgid(arg1)); + break; case TARGET_NR__llseek: { int64_t res; @@ -1596,10 +1634,31 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, (void *)arg5); break; + case TARGET_NR_poll: + { + struct target_pollfd *target_pfd = (void *)arg1; + unsigned int nfds = arg2; + int timeout = arg3; + struct pollfd *pfd; + int i; + + pfd = alloca(sizeof(struct pollfd) * nfds); + for(i = 0; i < nfds; i++) { + pfd->fd = tswap32(target_pfd->fd); + pfd->events = tswap16(target_pfd->events); + } + ret = get_errno(poll(pfd, nfds, timeout)); + if (!is_error(ret)) { + for(i = 0; i < nfds; i++) { + target_pfd->revents = tswap16(pfd->revents); + } + } + } + break; case TARGET_NR_flock: - goto unimplemented; - case TARGET_NR_msync: - ret = get_errno(msync((void *)arg1, arg2, arg3)); + /* NOTE: the flock constant seems to be the same for every + Linux platform */ + ret = get_errno(flock(arg1, arg2)); break; case TARGET_NR_readv: { @@ -1638,18 +1697,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; case TARGET_NR__sysctl: goto unimplemented; - case TARGET_NR_mlock: - ret = get_errno(mlock((void *)arg1, arg2)); - break; - case TARGET_NR_munlock: - ret = get_errno(munlock((void *)arg1, arg2)); - break; - case TARGET_NR_mlockall: - ret = get_errno(mlockall(arg1)); - break; - case TARGET_NR_munlockall: - ret = get_errno(munlockall()); - break; case TARGET_NR_sched_setparam: goto unimplemented; case TARGET_NR_sched_getparam: @@ -1681,12 +1728,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; - case TARGET_NR_mremap: case TARGET_NR_setresuid: case TARGET_NR_getresuid: case TARGET_NR_vm86: case TARGET_NR_query_module: - case TARGET_NR_poll: case TARGET_NR_nfsservctl: case TARGET_NR_setresgid: case TARGET_NR_getresgid: @@ -1800,7 +1845,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; default: unimplemented: - gemu_log("Unsupported syscall: %d\n", num); + gemu_log("gemu: Unsupported syscall: %d\n", num); ret = -ENOSYS; break; } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index b83aeaceb..9b2f42a73 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -150,6 +150,17 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); +struct target_rlimit { + target_ulong rlim_cur; + target_ulong rlim_max; +}; + +struct target_pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; + /* Networking ioctls */ #define TARGET_SIOCADDRT 0x890B /* add routing table entry */ #define TARGET_SIOCDELRT 0x890C /* delete routing table entry */ diff --git a/op-i386.c b/op-i386.c index 835a1ed51..48cfe9f03 100644 --- a/op-i386.c +++ b/op-i386.c @@ -119,40 +119,6 @@ static inline int lshift(int x, int n) return x >> (-n); } -/* exception support */ -/* NOTE: not static to force relocation generation by GCC */ -void raise_exception(int exception_index) -{ - /* NOTE: the register at this point must be saved by hand because - longjmp restore them */ -#ifdef reg_EAX - env->regs[R_EAX] = EAX; -#endif -#ifdef reg_ECX - env->regs[R_ECX] = ECX; -#endif -#ifdef reg_EDX - env->regs[R_EDX] = EDX; -#endif -#ifdef reg_EBX - env->regs[R_EBX] = EBX; -#endif -#ifdef reg_ESP - env->regs[R_ESP] = ESP; -#endif -#ifdef reg_EBP - env->regs[R_EBP] = EBP; -#endif -#ifdef reg_ESI - env->regs[R_ESI] = ESI; -#endif -#ifdef reg_EDI - env->regs[R_EDI] = EDI; -#endif - env->exception_index = exception_index; - longjmp(env->jmp_env, 1); -} - /* we define the various pieces of code used by the JIT */ #define REG EAX @@ -391,13 +357,15 @@ void OPPROTO op_imull_T0_T1(void) } /* division, flags are undefined */ -/* XXX: add exceptions for overflow & div by zero */ +/* XXX: add exceptions for overflow */ void OPPROTO op_divb_AL_T0(void) { unsigned int num, den, q, r; num = (EAX & 0xffff); den = (T0 & 0xff); + if (den == 0) + raise_exception(EXCP00_DIVZ); q = (num / den) & 0xff; r = (num % den) & 0xff; EAX = (EAX & 0xffff0000) | (r << 8) | q; @@ -409,6 +377,8 @@ void OPPROTO op_idivb_AL_T0(void) num = (int16_t)EAX; den = (int8_t)T0; + if (den == 0) + raise_exception(EXCP00_DIVZ); q = (num / den) & 0xff; r = (num % den) & 0xff; EAX = (EAX & 0xffff0000) | (r << 8) | q; @@ -420,6 +390,8 @@ void OPPROTO op_divw_AX_T0(void) num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); den = (T0 & 0xffff); + if (den == 0) + raise_exception(EXCP00_DIVZ); q = (num / den) & 0xffff; r = (num % den) & 0xffff; EAX = (EAX & 0xffff0000) | q; @@ -432,6 +404,8 @@ void OPPROTO op_idivw_AX_T0(void) num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); den = (int16_t)T0; + if (den == 0) + raise_exception(EXCP00_DIVZ); q = (num / den) & 0xffff; r = (num % den) & 0xffff; EAX = (EAX & 0xffff0000) | q; @@ -445,6 +419,8 @@ void OPPROTO op_divl_EAX_T0(void) num = EAX | ((uint64_t)EDX << 32); den = T0; + if (den == 0) + raise_exception(EXCP00_DIVZ); q = (num / den); r = (num % den); EAX = q; @@ -458,6 +434,8 @@ void OPPROTO op_idivl_EAX_T0(void) num = EAX | ((uint64_t)EDX << 32); den = T0; + if (den == 0) + raise_exception(EXCP00_DIVZ); q = (num / den); r = (num % den); EAX = q; diff --git a/syscall-i386.h b/syscall-i386.h index 39bba1a49..5878ccdd9 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -359,7 +359,7 @@ struct target_sigaction { typedef union target_sigval { int sival_int; - void *sival_ptr; + target_ulong sival_ptr; } target_sigval_t; #define TARGET_SI_MAX_SIZE 128 @@ -389,7 +389,7 @@ typedef struct target_siginfo { struct { pid_t _pid; /* sender's pid */ uid_t _uid; /* sender's uid */ - sigval_t _sigval; + target_sigval_t _sigval; } _rt; /* SIGCHLD */ @@ -403,7 +403,7 @@ typedef struct target_siginfo { /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ struct { - void *_addr; /* faulting insn/memory ref. */ + target_ulong _addr; /* faulting insn/memory ref. */ } _sigfault; /* SIGPOLL */ @@ -414,6 +414,46 @@ typedef struct target_siginfo { } _sifields; } target_siginfo_t; +/* + * SIGILL si_codes + */ +#define TARGET_ILL_ILLOPN (2) /* illegal operand */ + +/* + * SIGFPE si_codes + */ +#define TARGET_FPE_INTDIV (1) /* integer divide by zero */ +#define TARGET_FPE_INTOVF (2) /* integer overflow */ +#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */ +#define TARGET_FPE_FLTOVF (4) /* floating point overflow */ +#define TARGET_FPE_FLTUND (5) /* floating point underflow */ +#define TARGET_FPE_FLTRES (6) /* floating point inexact result */ +#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */ +#define TARGET_FPE_FLTSUB (8) /* subscript out of range */ +#define TARGET_NSIGFPE 8 + +/* default linux values for the selectors */ +#define __USER_CS (0x23) +#define __USER_DS (0x2B) + +struct target_pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + int xds; + int xes; + long orig_eax; + long eip; + int xcs; + long eflags; + long esp; + int xss; +}; + /* ioctls */ /* diff --git a/tests/testsig.c b/tests/testsig.c index 59af54fc8..d93f42806 100644 --- a/tests/testsig.c +++ b/tests/testsig.c @@ -1,7 +1,13 @@ +#define _GNU_SOURCE #include #include +#include #include #include +#include +#include + +jmp_buf jmp_env; void alarm_handler(int sig) { @@ -9,15 +15,82 @@ void alarm_handler(int sig) alarm(1); } +void dump_regs(struct ucontext *uc) +{ + printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "EFL=%08x EIP=%08x\n", + uc->uc_mcontext.gregs[EAX], + uc->uc_mcontext.gregs[EBX], + uc->uc_mcontext.gregs[ECX], + uc->uc_mcontext.gregs[EDX], + uc->uc_mcontext.gregs[ESI], + uc->uc_mcontext.gregs[EDI], + uc->uc_mcontext.gregs[EBP], + uc->uc_mcontext.gregs[ESP], + uc->uc_mcontext.gregs[EFL], + uc->uc_mcontext.gregs[EIP]); +} + +void sig_handler(int sig, siginfo_t *info, void *puc) +{ + struct ucontext *uc = puc; + + printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n", + strsignal(info->si_signo), + info->si_signo, info->si_errno, info->si_code, + (unsigned long)info->si_addr); + dump_regs(uc); + longjmp(jmp_env, 1); +} + +int v1; + int main(int argc, char **argv) { struct sigaction act; + int i; + + /* test division by zero reporting */ + if (setjmp(jmp_env) == 0) { + act.sa_sigaction = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO | SA_ONESHOT; + sigaction(SIGFPE, &act, NULL); + + /* now divide by zero */ + v1 = 0; + v1 = 2 / v1; + } + + /* test illegal instruction reporting */ + if (setjmp(jmp_env) == 0) { + act.sa_sigaction = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO | SA_ONESHOT; + sigaction(SIGILL, &act, NULL); + + /* now execute an invalid instruction */ + asm volatile("ud2"); + } + + /* test SEGV reporting */ + if (setjmp(jmp_env) == 0) { + act.sa_sigaction = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO | SA_ONESHOT; + sigaction(SIGSEGV, &act, NULL); + + /* now store in an invalid address */ + *(char *)0x1234 = 1; + } + act.sa_handler = alarm_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGALRM, &act, NULL); alarm(1); - for(;;) { + for(i = 0;i < 2; i++) { sleep(1); } return 0; diff --git a/translate-i386.c b/translate-i386.c index b7a7cdc20..e7e91f54f 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #define DEBUG_DISAS @@ -3487,7 +3488,8 @@ static void dump_ops(const uint16_t *opc_buf) static uint16_t gen_opc_buf[OPC_BUF_SIZE]; static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; -/* return the next pc */ +/* return non zero if the very first instruction is invalid so that + the virtual CPU can trigger an exception. */ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, uint8_t *pc_start, uint8_t *cs_base, int flags) @@ -3519,9 +3521,13 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, do { ret = disas_insn(dc, pc_ptr); if (ret == -1) { - fprintf(stderr, "unknown instruction at PC=0x%08lx B=%02x %02x %02x", - (long)pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]); - abort(); + /* we trigger an illegal instruction operation only if it + is the first instruction. Otherwise, we simply stop + generating the code just before it */ + if (pc_ptr == pc_start) + return -1; + else + break; } pc_ptr = (void *)ret; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end); @@ -3640,8 +3646,7 @@ CPUX86State *cpu_x86_init(void) env->fptags[i] = 1; env->fpuc = 0x37f; /* flags setup */ - env->cc_op = CC_OP_EFLAGS; - env->df = 1; + env->eflags = 0; /* init various static tables */ if (!inited) { -- cgit v1.2.3 From b03c60f35194db4ba1f53673ab02ade29f54701e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Mar 2003 17:19:56 +0000 Subject: more syscalls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@43 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 3 +- linux-user/syscall.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/TODO b/TODO index 1a9e51f31..6616d62d5 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,6 @@ - optimize translated cache chaining (DLL PLT-like system) -- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues) +- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit + issues, fix 16 bit uid issues) - finish signal handing (fp87 state, more siginfo conversions) - verify thread support (clone() and various locks) - vm86 syscall support diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ab78fbb0d..8050e29a0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -103,6 +103,10 @@ extern int personality(int); extern int flock(int, int); extern int setfsuid(int); extern int setfsgid(int); +extern int setresuid(int,int,int); +extern int getresuid(int *,int *,int *); +extern int setresgid(int,int,int); +extern int getresgid(int *,int *,int *); static inline long get_errno(long ret) { @@ -809,6 +813,10 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) #endif +#define high2lowuid(x) (x) +#define high2lowgid(x) (x) +#define low2highuid(x) (x) +#define low2highgid(x) (x) void syscall_init(void) { @@ -913,7 +921,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(umount((const char *)arg1)); break; case TARGET_NR_setuid: - ret = get_errno(setuid(arg1)); + ret = get_errno(setuid(low2highuid(arg1))); break; case TARGET_NR_getuid: ret = get_errno(getuid()); @@ -984,7 +992,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_prof: goto unimplemented; case TARGET_NR_setgid: - ret = get_errno(setgid(arg1)); + ret = get_errno(setgid(low2highgid(arg1))); break; case TARGET_NR_getgid: ret = get_errno(getgid()); @@ -1727,14 +1735,41 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; - case TARGET_NR_setresuid: + ret = get_errno(setresuid(low2highuid(arg1), + low2highuid(arg2), + low2highuid(arg3))); + break; case TARGET_NR_getresuid: + { + int ruid, euid, suid; + ret = get_errno(getresuid(&ruid, &euid, &suid)); + if (!is_error(ret)) { + *(uint16_t *)arg1 = tswap16(high2lowuid(ruid)); + *(uint16_t *)arg2 = tswap16(high2lowuid(euid)); + *(uint16_t *)arg3 = tswap16(high2lowuid(suid)); + } + } + break; + case TARGET_NR_setresgid: + ret = get_errno(setresgid(low2highgid(arg1), + low2highgid(arg2), + low2highgid(arg3))); + break; + case TARGET_NR_getresgid: + { + int rgid, egid, sgid; + ret = get_errno(getresgid(&rgid, &egid, &sgid)); + if (!is_error(ret)) { + *(uint16_t *)arg1 = high2lowgid(tswap16(rgid)); + *(uint16_t *)arg2 = high2lowgid(tswap16(egid)); + *(uint16_t *)arg3 = high2lowgid(tswap16(sgid)); + } + } + break; case TARGET_NR_vm86: case TARGET_NR_query_module: case TARGET_NR_nfsservctl: - case TARGET_NR_setresgid: - case TARGET_NR_getresgid: case TARGET_NR_prctl: case TARGET_NR_pread: case TARGET_NR_pwrite: @@ -1789,26 +1824,80 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_lchown32: + ret = get_errno(lchown((const char *)arg1, arg2, arg3)); + break; case TARGET_NR_getuid32: + ret = get_errno(getuid()); + break; case TARGET_NR_getgid32: + ret = get_errno(getgid()); + break; case TARGET_NR_geteuid32: + ret = get_errno(geteuid()); + break; case TARGET_NR_getegid32: + ret = get_errno(getegid()); + break; case TARGET_NR_setreuid32: + ret = get_errno(setreuid(arg1, arg2)); + break; case TARGET_NR_setregid32: + ret = get_errno(setregid(arg1, arg2)); + break; case TARGET_NR_getgroups32: + goto unimplemented; case TARGET_NR_setgroups32: + goto unimplemented; case TARGET_NR_fchown32: + ret = get_errno(fchown(arg1, arg2, arg3)); + break; case TARGET_NR_setresuid32: + ret = get_errno(setresuid(arg1, arg2, arg3)); + break; case TARGET_NR_getresuid32: + { + int ruid, euid, suid; + ret = get_errno(getresuid(&ruid, &euid, &suid)); + if (!is_error(ret)) { + *(uint32_t *)arg1 = tswap32(ruid); + *(uint32_t *)arg2 = tswap32(euid); + *(uint32_t *)arg3 = tswap32(suid); + } + } + break; case TARGET_NR_setresgid32: + ret = get_errno(setresgid(arg1, arg2, arg3)); + break; case TARGET_NR_getresgid32: + { + int rgid, egid, sgid; + ret = get_errno(getresgid(&rgid, &egid, &sgid)); + if (!is_error(ret)) { + *(uint32_t *)arg1 = tswap32(rgid); + *(uint32_t *)arg2 = tswap32(egid); + *(uint32_t *)arg3 = tswap32(sgid); + } + } + break; case TARGET_NR_chown32: + ret = get_errno(chown((const char *)arg1, arg2, arg3)); + break; case TARGET_NR_setuid32: + ret = get_errno(setuid(arg1)); + break; case TARGET_NR_setgid32: + ret = get_errno(setgid(arg1)); + break; case TARGET_NR_setfsuid32: + ret = get_errno(setfsuid(arg1)); + break; case TARGET_NR_setfsgid32: + ret = get_errno(setfsgid(arg1)); + break; case TARGET_NR_pivot_root: + goto unimplemented; case TARGET_NR_mincore: + goto unimplemented; case TARGET_NR_madvise: goto unimplemented; #if TARGET_LONG_BITS == 32 -- cgit v1.2.3 From 3ef693a03205217a5def9318b443c8cb6de17217 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Mar 2003 20:17:16 +0000 Subject: distribution patches git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@44 c046a42c-6fe2-441c-8c8c-71466251a162 --- COPYING | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++ Changelog | 3 + Makefile | 43 ++++--- README | 27 ++++ VERSION | 1 + configure | 16 +-- cpu-i386.h | 20 ++- exec-i386.c | 22 ++-- exec-i386.h | 21 +++- linux-user/elfload.c | 2 +- linux-user/main.c | 10 +- linux-user/signal.c | 4 +- linux-user/syscall.c | 2 +- op-i386.c | 22 ++-- tests/Makefile | 6 +- thunk.c | 24 ++-- thunk.h | 19 +++ translate-i386.c | 22 ++-- 18 files changed, 515 insertions(+), 88 deletions(-) create mode 100644 COPYING create mode 100644 Changelog create mode 100644 README create mode 100644 VERSION diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..e77696ae8 --- /dev/null +++ b/COPYING @@ -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. + + + Copyright (C) 19yy + + 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. + + , 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. diff --git a/Changelog b/Changelog new file mode 100644 index 000000000..783eb1d7a --- /dev/null +++ b/Changelog @@ -0,0 +1,3 @@ +version 0.1: + + - initial public release. diff --git a/Makefile b/Makefile index 9f1d31c36..cce9c7e82 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ endif DEFINES+=-D_GNU_SOURCE LDSCRIPT=$(ARCH).ld -LIBS+=-ldl -lm +LIBS+=-lm # profiling code ifdef TARGET_GPROF @@ -36,24 +36,25 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o thunk.o syscall.o signal.o libgemu.a +OBJS= elfload.o main.o syscall.o signal.o +SRCS:= $(OBJS:.o=.c) +OBJS+= libqemu.a -LIBOBJS+=translate-i386.o op-i386.o exec-i386.o +LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o # NOTE: the disassembler code is only needed for debugging LIBOBJS+=i386-dis.o dis-buf.o -SRCS = $(OBJS:.o=.c) -all: gemu +all: qemu qemu-doc.html -gemu: $(OBJS) +qemu: $(OBJS) $(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend -# libgemu +# libqemu -libgemu.a: $(LIBOBJS) +libqemu.a: $(LIBOBJS) rm -f $@ $(AR) rcs $@ $(LIBOBJS) @@ -73,36 +74,42 @@ op-i386.o: op-i386.c opreg_template.h ops_template.h clean: $(MAKE) -C tests clean - rm -f *.o *.a *~ gemu dyngen TAGS + rm -f *.o *.a *~ qemu dyngen TAGS distclean: clean rm -f config.mak config.h -install: gemu - install -m755 -s gemu $(prefix)/bin +install: qemu + install -m 755 -s qemu $(prefix)/bin # various test targets -test speed: gemu +test speed: qemu make -C tests $@ TAGS: etags *.[ch] i386/*.[ch] +# documentation +qemu-doc.html: qemu-doc.texi + texi2html -monolithic -number $< + FILES= \ -COPYING.LIB dyngen.c ioctls.h ops_template.h syscall_types.h\ +README COPYING COPYING.LIB TODO Changelog VERSION \ +dyngen.c ioctls.h ops_template.h syscall_types.h\ Makefile elf.h linux_bin.h segment.h thunk.c\ -TODO elfload.c main.c signal.c thunk.h\ -cpu-i386.h gemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ +elfload.c main.c signal.c thunk.h\ +cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ dis-asm.h gen-i386.h op-i386.h syscall.c\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ -i386.ld ppc.ld exec-i386.h exec-i386.c configure VERSION \ +i386.ld ppc.ld exec-i386.h exec-i386.c configure \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h tests/test-i386-code16.S\ tests/hello.c tests/hello tests/sha1.c \ -tests/testsig.c tests/testclone.c tests/testthread.c +tests/testsig.c tests/testclone.c tests/testthread.c \ +qemu-doc.texi qemu-doc.html -FILE=gemu-$(VERSION) +FILE=qemu-$(VERSION) tar: rm -rf /tmp/$(FILE) diff --git a/README b/README new file mode 100644 index 000000000..52294323e --- /dev/null +++ b/README @@ -0,0 +1,27 @@ +The QEMU x86 emulator +--------------------- + +INSTALLATION +------------ + +Type + + ./configure + make + +to build qemu and libqemu.a. + +Type + + make install + +to install qemu in /usr/local/bin + + +Documentation +------------- + +Read the documentation in qemu-doc.html. + + +Fabrice Bellard. \ No newline at end of file diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..ceab6e11e --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1 \ No newline at end of file diff --git a/configure b/configure index d9053cf76..d58c46079 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #!/bin/sh # -# gemu configure script (c) 2003 Fabrice Bellard +# qemu configure script (c) 2003 Fabrice Bellard # # set temporary file name if test ! -z "$TMPDIR" ; then @@ -11,11 +11,11 @@ else TMPDIR1="/tmp" fi -TMPC="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.c" -TMPO="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.o" -TMPE="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}" -TMPS="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.S" -TMPH="${TMPDIR1}/gemu-conf-${RANDOM}-$$-${RANDOM}.h" +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" +TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h" # default parameters prefix="/usr/local" @@ -195,7 +195,7 @@ echo "# Automatically generated by configure - do not modify" > config.mak echo "/* Automatically generated by configure - do not modify */" > $TMPH echo "prefix=$prefix" >> config.mak -echo "#define CONFIG_GEMU_PREFIX \"$prefix\"" >> $TMPH +echo "#define CONFIG_QEMU_PREFIX \"$prefix\"" >> $TMPH echo "MAKE=$make" >> config.mak echo "CC=$cc" >> config.mak echo "GCC_MAJOR=$gcc_major" >> config.mak @@ -227,7 +227,7 @@ fi echo -n "VERSION=" >>config.mak head $source_path/VERSION >>config.mak echo "" >>config.mak -echo -n "#define GEMU_VERSION \"" >> $TMPH +echo -n "#define QEMU_VERSION \"" >> $TMPH head $source_path/VERSION >> $TMPH echo "\"" >> $TMPH if test "$network" = "yes" ; then diff --git a/cpu-i386.h b/cpu-i386.h index dbe18519b..dbd71c425 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -1,5 +1,21 @@ -/* NOTE: this header is included in op-i386.c where global register - variable are used. Care must be used when including glibc headers. +/* + * i386 virtual CPU header + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CPU_I386_H #define CPU_I386_H diff --git a/exec-i386.c b/exec-i386.c index 269a1e42f..ec14ca090 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -3,19 +3,19 @@ * * Copyright (c) 2003 Fabrice Bellard * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This 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 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. + * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec-i386.h" diff --git a/exec-i386.h b/exec-i386.h index d6cac3ba0..7a6f74b92 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -1,5 +1,22 @@ -/* i386 execution defines */ - +/* + * i386 execution defines + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 285d8f5c7..44ac577c0 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -10,7 +10,7 @@ #include #include -#include "gemu.h" +#include "qemu.h" #include "linux_bin.h" #include "elf.h" diff --git a/linux-user/main.c b/linux-user/main.c index fba23a013..289993426 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1,5 +1,5 @@ /* - * gemu main + * qemu main * * Copyright (c) 2003 Fabrice Bellard * @@ -24,11 +24,11 @@ #include #include -#include "gemu.h" +#include "qemu.h" #include "cpu-i386.h" -#define DEBUG_LOGFILE "/tmp/gemu.log" +#define DEBUG_LOGFILE "/tmp/qemu.log" FILE *logfile = NULL; int loglevel; @@ -171,8 +171,8 @@ void cpu_loop(struct CPUX86State *env) void usage(void) { - printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: gemu [-d] program [arguments...]\n" + printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + "usage: qemu [-d] program [arguments...]\n" "Linux x86 emulator\n" ); exit(1); diff --git a/linux-user/signal.c b/linux-user/signal.c index 3e792ae69..72b2f7992 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -25,9 +25,7 @@ #include #include -#include "gemu.h" - -/* signal handling inspired from em86. */ +#include "qemu.h" //#define DEBUG_SIGNAL diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8050e29a0..5f02fb72e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -56,7 +56,7 @@ #include #include -#include "gemu.h" +#include "qemu.h" //#define DEBUG diff --git a/op-i386.c b/op-i386.c index 48cfe9f03..fb3ff1d59 100644 --- a/op-i386.c +++ b/op-i386.c @@ -3,19 +3,19 @@ * * Copyright (c) 2003 Fabrice Bellard * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This 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 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. + * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec-i386.h" diff --git a/tests/Makefile b/tests/Makefile index 33623843d..495dbf3f4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -8,7 +8,7 @@ TESTS=testclone testsig testthread sha1-i386 test-i386 endif TESTS+=sha1 -GEMU=../gemu +QEMU=../qemu all: $(TESTS) @@ -34,7 +34,7 @@ test: test-i386 ifeq ($(ARCH),i386) ./test-i386 > test-i386.ref endif - $(GEMU) test-i386 > test-i386.out + $(QEMU) test-i386 > test-i386.out @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi # speed test @@ -46,7 +46,7 @@ sha1: sha1.c speed: sha1 sha1-i386 time ./sha1 - time $(GEMU) ./sha1-i386 + time $(QEMU) ./sha1-i386 clean: rm -f *~ *.o $(TESTS) diff --git a/thunk.c b/thunk.c index 62520a297..c2fd44cae 100644 --- a/thunk.c +++ b/thunk.c @@ -3,25 +3,25 @@ * * Copyright (c) 2003 Fabrice Bellard * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This 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 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. + * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include -#include "gemu.h" +#include "qemu.h" #include "thunk.h" //#define DEBUG diff --git a/thunk.h b/thunk.h index a7338ad76..017cfe357 100644 --- a/thunk.h +++ b/thunk.h @@ -1,3 +1,22 @@ +/* + * Generic thunking code to convert data between host and target CPU + * + * 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 THUNK_H #define THUNK_H diff --git a/translate-i386.c b/translate-i386.c index e7e91f54f..afe7f3543 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -3,19 +3,19 @@ * * Copyright (c) 2003 Fabrice Bellard * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This 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 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. + * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include -- cgit v1.2.3 From 386405f78661e0a4f82087196c7b084b8c612b48 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Mar 2003 21:28:45 +0000 Subject: documentation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@45 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 qemu-doc.texi diff --git a/qemu-doc.texi b/qemu-doc.texi new file mode 100644 index 000000000..a7b0ce9f7 --- /dev/null +++ b/qemu-doc.texi @@ -0,0 +1,305 @@ +\input texinfo @c -*- texinfo -*- + +@settitle QEMU x86 Emulator Reference Documentation +@titlepage +@sp 7 +@center @titlefont{QEMU x86 Emulator Reference Documentation} +@sp 3 +@end titlepage + +@chapter Introduction + +QEMU is an x86 processor emulator. Its purpose is to run x86 Linux +processes on non-x86 Linux architectures such as PowerPC or ARM. By +using dynamic translation it achieves a reasonnable speed while being +easy to port on new host CPUs. An obviously interesting x86 only process +is 'wine' (Windows emulation). + +QEMU features: + +@itemize + +@item User space only x86 emulator. + +@item Currently ported on i386 and PowerPC. + +@item Using dynamic translation for reasonnable speed. + +@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. +User space LDT and GDT are emulated. + +@item Generic Linux system call converter, including most ioctls. + +@item clone() emulation using native CPU clone() to use Linux scheduler for threads. + +@item Accurate signal handling by remapping host signals to virtual x86 signals. + +@item The virtual x86 CPU is a library (@code{libqemu}) which can be used +in other projects. + +@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}. +It can be used to test other x86 virtual CPUs. + +@end itemize + +Current QEMU Limitations: + +@itemize + +@item Not all x86 exceptions are precise (yet). [Very few programs need that]. + +@item Not self virtualizable (yet). [You cannot launch qemu with qemu on the same CPU]. + +@item No support for self modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !]. + +@item No VM86 mode (yet), althought the virtual +CPU has support for most of it. [VM86 support is useful to launch old 16 +bit DOS programs with dosemu or wine]. + +@item No SSE/MMX support (yet). + +@item No x86-64 support. + +@item Some Linux syscalls are missing. + +@item The x86 segment limits and access rights are not tested at every +memory access (and will never be to have good performances). + +@item On non x86 host CPUs, @code{double}s are used instead of the non standard +10 byte @code{long double}s of x86 for floating point emulation to get +maximum performances. + +@end itemize + +@chapter Invocation + +In order to launch a Linux process, QEMU needs the process executable +itself and all the target (x86) dynamic libraries used by it. Currently, +QEMU is not distributed with the necessary packages so that you can test +it easily on non x86 CPUs. + +However, the statically x86 binary 'tests/hello' can be used to do a +first test: + +@example +qemu tests/hello +@end example + +@code{Hello world} should be printed on the terminal. + +If you are testing it on a x86 CPU, then you can test it on any process: + +@example +qemu /bin/ls -l +@end example + +@chapter QEMU Internals + +@section QEMU compared to other emulators + +Unlike bochs [3], QEMU emulates only a user space x86 CPU. It means that +you cannot launch an operating system with it. The benefit is that it is +simpler and faster due to the fact that some of the low level CPU state +can be ignored (in particular, no virtual memory needs to be emulated). + +Like Valgrind [2], QEMU does user space emulation and dynamic +translation. Valgrind is mainly a memory debugger while QEMU has no +support for it (QEMU could be used to detect out of bound memory accesses +as Valgrind, but it has no support to track uninitialised data as +Valgrind does). Valgrind dynamic translator generates better code than +QEMU (in particular it does register allocation) but it is closely tied +to an x86 host. + +EM86 [4] is the closest project to QEMU (and QEMU still uses some of its +code, in particular the ELF file loader). EM86 was limited to an alpha +host and used a proprietary and slow interpreter (the interpreter part +of the FX!32 Digital Win32 code translator [5]). + +@section Portable dynamic translation + +QEMU is a dynamic translator. When it first encounters a piece of code, +it converts it to the host instruction set. Usually dynamic translators +are very complicated and highly CPU dependant. QEMU uses some tricks +which make it relatively easily portable and simple while achieving good +performances. + +The basic idea is to split every x86 instruction into fewer simpler +instructions. Each simple instruction is implemented by a piece of C +code (see @file{op-i386.c}). Then a compile time tool (@file{dyngen}) +takes the corresponding object file (@file{op-i386.o}) to generate a +dynamic code generator which concatenates the simple instructions to +build a function (see @file{op-i386.h:dyngen_code()}). + +In essence, the process is similar to [1], but more work is done at +compile time. + +A key idea to get optimal performances is that constant parameters can +be passed to the simple operations. For that purpose, dummy ELF +relocations are generated with gcc for each constant parameter. Then, +the tool (@file{dyngen}) can locate the relocations and generate the +appriopriate C code to resolve them when building the dynamic code. + +That way, QEMU is no more difficult to port than a dynamic linker. + +To go even faster, GCC static register variables are used to keep the +state of the virtual CPU. + +@section Register allocation + +Since QEMU uses fixed simple instructions, no efficient register +allocation can be done. However, because RISC CPUs have a lot of +register, most of the virtual CPU state can be put in registers without +doing complicated register allocation. + +@section Condition code optimisations + +Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a +critical point to get good performances. QEMU uses lazy condition code +evaluation: instead of computing the condition codes after each x86 +instruction, it store justs one operand (called @code{CC_CRC}), the +result (called @code{CC_DST}) and the type of operation (called +@code{CC_OP}). + +@code{CC_OP} is almost never explicitely set in the generated code +because it is known at translation time. + +In order to increase performances, a backward pass is performed on the +generated simple instructions (see +@code{translate-i386.c:optimize_flags()}). When it can be proved that +the condition codes are not needed by the next instructions, no +condition codes are computed at all. + +@section Translation CPU state optimisations + +The x86 CPU has many internal states which change the way it evaluates +instructions. In order to achieve a good speed, the translation phase +considers that some state information of the virtual x86 CPU cannot +change in it. For example, if the SS, DS and ES segments have a zero +base, then the translator does not even generate an addition for the +segment base. + +[The FPU stack pointer register is not handled that way yet]. + +@section Translation cache + +A 2MByte cache holds the most recently used translations. For +simplicity, it is completely flushed when it is full. A translation unit +contains just a single basic block (a block of x86 instructions +terminated by a jump or by a virtual CPU state change which the +translator cannot deduce statically). + +[Currently, the translated code is not patched if it jumps to another +translated code]. + +@section Exception support + +longjmp() is used when an exception such as division by zero is +encountered. The host SIGSEGV and SIGBUS signal handlers are used to get +invalid memory accesses. + +[Currently, the virtual CPU cannot retrieve the exact CPU state in some +exceptions, although it could except for the @code{EFLAGS} register]. + +@section Linux system call translation + +QEMU includes a generic system call translator for Linux. It means that +the parameters of the system calls can be converted to fix the +endianness and 32/64 bit issues. The IOCTLs are converted with a generic +type description system (see @file{ioctls.h} and @file{thunk.c}). + +@section Linux signals + +Normal and real-time signals are queued along with their information +(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt +request is done to the virtual CPU. When it is interrupted, one queued +signal is handled by generating a stack frame in the virtual CPU as the +Linux kernel does. The @code{sigreturn()} system call is emulated to return +from the virtual signal handler. + +Some signals (such as SIGALRM) directly come from the host. Other +signals are synthetized from the virtual CPU exceptions such as SIGFPE +when a division by zero is done (see @code{main.c:cpu_loop()}). + +The blocked signal mask is still handled by the host Linux kernel so +that most signal system calls can be redirected directly to the host +Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system +calls need to be fully emulated (see @file{signal.c}). + +@section clone() system call and threads + +The Linux clone() system call is usually used to create a thread. QEMU +uses the host clone() system call so that real host threads are created +for each emulated thread. One virtual CPU instance is created for each +thread. + +The virtual x86 CPU atomic operations are emulated with a global lock so +that their semantic is preserved. + +@section Bibliography + +@table @asis + +@item [1] +@url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing +direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio +Riccardi. + +@item [2] +@url{http://developer.kde.org/~sewardj/}, Valgrind, an open-source +memory debugger for x86-GNU/Linux, by Julian Seward. + +@item [3] +@url{http://bochs.sourceforge.net/}, the Bochs IA-32 Emulator Project, +by Kevin Lawton et al. + +@item [4] +@url{http://www.cs.rose-hulman.edu/~donaldlf/em86/index.html}, the EM86 +x86 emulator on Alpha-Linux. + +@item [5] +@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/full_papers/chernoff/chernoff.pdf}, +DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton +Chernoff and Ray Hookway. + +@end table + +@chapter Regression Tests + +In the directory @file{tests/}, various interesting x86 testing programs +are available. There are used for regression testing. + +@section @file{hello} + +Very simple statically linked x86 program, just to test QEMU during a +port to a new host CPU. + +@section @file{test-i386} + +This program executes most of the 16 bit and 32 bit x86 instructions and +generates a text output. It can be compared with the output obtained with +a real CPU or another emulator. The target @code{make test} runs this +program and a @code{diff} on the generated output. + +The Linux system call @code{modify_ldt()} is used to create x86 selectors +to test some 16 bit addressing and 32 bit with segmentation cases. + +@section @file{testsig} + +This program tests various signal cases, including SIGFPE, SIGSEGV and +SIGILL. + +@section @file{testclone} + +Tests the @code{clone()} system call (basic test). + +@section @file{testthread} + +Tests the glibc threads (more complicated than @code{clone()} because signals +are also used). + +@section @file{sha1} + +It is a simple benchmark. Care must be taken to interpret the results +because it mostly tests the ability of the virtual CPU to optimize the +@code{rol} x86 instruction and the condition code computations. + -- cgit v1.2.3 From d691f66983c0b36689400e9e9137d72bd3be8e72 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Mar 2003 21:58:34 +0000 Subject: glibc2.2 fixes - more command line options - misc doc fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@46 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 6 ++++++ Makefile | 9 +++++++++ README | 16 +++++++++++++++- VERSION | 2 +- cpu-i386.h | 2 +- exec-i386.c | 4 ++++ linux-user/elfload.c | 14 ++++++++------ linux-user/main.c | 46 ++++++++++++++++++++++++++++++++++++++++------ linux-user/qemu.h | 3 ++- opreg_template.h | 22 ++++++++++++++++++++-- ops_template.h | 23 +++++++++++------------ qemu-doc.texi | 47 +++++++++++++++++++++++++++++++++++++---------- tests/Makefile | 2 +- tests/testsig.c | 33 +++++++++++++++++++++++---------- 14 files changed, 178 insertions(+), 51 deletions(-) diff --git a/Changelog b/Changelog index 783eb1d7a..574ae5e60 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +version 0.1.1: + + - glibc 2.2 compilation fixes + - added -s and -L options + - binary distribution of x86 glibc and wine + version 0.1: - initial public release. diff --git a/Makefile b/Makefile index cce9c7e82..169f9def8 100644 --- a/Makefile +++ b/Makefile @@ -118,6 +118,15 @@ tar: ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) ) rm -rf /tmp/$(FILE) +# generate a binary distribution including the test binary environnment +BINPATH=/usr/local/qemu-i386 + +tarbin: + tar zcvf /tmp/qemu-i386-glibc21.tar.gz \ + $(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin + tar zcvf /tmp/qemu-i386-wine.tar.gz \ + $(BINPATH)/X11R6 $(BINPATH)/wine + ifneq ($(wildcard .depend),) include .depend endif diff --git a/README b/README index 52294323e..34061434a 100644 --- a/README +++ b/README @@ -15,8 +15,22 @@ Type make install -to install qemu in /usr/local/bin +to install QEMU in /usr/local/bin +* On x86 you should be able to launch any program by using the +libraries installed on your PC. For example: + + ./qemu -L / /bin/ls + +* On non x86 CPUs, you need first to download at least an x86 glibc +(qemu-i386-glibc21.tar.gz on the qemu web page). Then you can launch +the precompiled 'ls' x86 executable: + + ./qemu /usr/local/qemu-i386/bin/ls + +You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is +automatically launched by the Linux kernel when you try to launch x86 +executables. Documentation ------------- diff --git a/VERSION b/VERSION index ceab6e11e..17e51c385 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1 \ No newline at end of file +0.1.1 diff --git a/cpu-i386.h b/cpu-i386.h index dbd71c425..700370e71 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -406,7 +406,7 @@ void cpu_x86_close(CPUX86State *s); /* needed to load some predefinied segment registers */ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); -/* you can call these signal handler from you SIGBUS and SIGSEGV +/* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ struct siginfo; diff --git a/exec-i386.c b/exec-i386.c index ec14ca090..5dbe7fa53 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -485,6 +485,10 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, unsigned long pc; sigset_t *pold_set; +#ifndef REG_EIP +/* for glibc 2.1 */ +#define REG_EIP EIP +#endif pc = uc->uc_mcontext.gregs[EIP]; pold_set = &uc->uc_sigmask; return handle_cpu_signal(pc, pold_set); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 44ac577c0..817913df4 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -42,8 +42,7 @@ #define DLINFO_ITEMS 12 /* Where we find X86 libraries... */ -//#define X86_DEFAULT_LIB_DIR "/usr/x86/" -#define X86_DEFAULT_LIB_DIR "/" + //extern void * mmap4k(); #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) @@ -638,7 +637,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r * is an a.out format binary */ - elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+strlen(X86_DEFAULT_LIB_DIR)); + elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+ + strlen(bprm->interp_prefix)); if (elf_interpreter == NULL) { free (elf_phdata); @@ -646,11 +646,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r return -ENOMEM; } - strcpy(elf_interpreter, X86_DEFAULT_LIB_DIR); + strcpy(elf_interpreter, bprm->interp_prefix); retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); if(retval >= 0) { retval = read(bprm->fd, - elf_interpreter+strlen(X86_DEFAULT_LIB_DIR), + elf_interpreter+strlen(bprm->interp_prefix), elf_ppnt->p_filesz); } if(retval < 0) { @@ -911,7 +911,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r -int elf_exec(const char * filename, char ** argv, char ** envp, +int elf_exec(const char *interp_prefix, + const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop) { struct linux_binprm bprm; @@ -930,6 +931,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, else { bprm.fd = retval; } + bprm.interp_prefix = (char *)interp_prefix; bprm.filename = (char *)filename; bprm.sh_bang = 0; bprm.loader = 0; diff --git a/linux-user/main.c b/linux-user/main.c index 289993426..31743253b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -32,6 +32,7 @@ FILE *logfile = NULL; int loglevel; +const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386"; /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example @@ -172,9 +173,16 @@ void cpu_loop(struct CPUX86State *env) void usage(void) { printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: qemu [-d] program [arguments...]\n" + "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n" "Linux x86 emulator\n" - ); + "\n" + "-h print this help\n" + "-d activate log (logfile=%s)\n" + "-L path set the x86 elf interpreter prefix (default=%s)\n" + "-s size set the x86 stack size in bytes (default=%ld)\n", + DEBUG_LOGFILE, + interp_prefix, + x86_stack_size); exit(1); } @@ -188,15 +196,41 @@ int main(int argc, char **argv) struct image_info info1, *info = &info1; CPUX86State *env; int optind; - + const char *r; + if (argc <= 1) usage(); loglevel = 0; optind = 1; - if (argv[optind] && !strcmp(argv[optind], "-d")) { - loglevel = 1; + for(;;) { + if (optind >= argc) + break; + r = argv[optind]; + if (r[0] != '-') + break; optind++; + r++; + if (!strcmp(r, "-")) { + break; + } else if (!strcmp(r, "d")) { + loglevel = 1; + } else if (!strcmp(r, "s")) { + r = argv[optind++]; + x86_stack_size = strtol(r, (char **)&r, 0); + if (x86_stack_size <= 0) + usage(); + if (*r == 'M') + x86_stack_size *= 1024 * 1024; + else if (*r == 'k' || *r == 'K') + x86_stack_size *= 1024; + } else if (!strcmp(r, "L")) { + interp_prefix = argv[optind++]; + } else { + usage(); + } } + if (optind >= argc) + usage(); filename = argv[optind]; /* init debug */ @@ -215,7 +249,7 @@ int main(int argc, char **argv) /* Zero out image_info */ memset(info, 0, sizeof(struct image_info)); - if(elf_exec(filename, argv+optind, environ, regs, info) != 0) { + if(elf_exec(interp_prefix, filename, argv+optind, environ, regs, info) != 0) { printf("Error loading %s\n", filename); exit(1); } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 862695511..d4d93a429 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -33,7 +33,8 @@ struct image_info { int personality; }; -int elf_exec(const char * filename, char ** argv, char ** envp, +int elf_exec(const char *interp_prefix, + const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); void target_set_brk(char *new_brk); diff --git a/opreg_template.h b/opreg_template.h index d6453f954..f35a1bbc9 100644 --- a/opreg_template.h +++ b/opreg_template.h @@ -1,5 +1,23 @@ -/* templates for various register related operations */ - +/* + * i386 micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ void OPPROTO glue(op_movl_A0,REGNAME)(void) { A0 = REG; diff --git a/ops_template.h b/ops_template.h index 1a2380041..34f10cdf9 100644 --- a/ops_template.h +++ b/ops_template.h @@ -4,21 +4,20 @@ * * Copyright (c) 2003 Fabrice Bellard * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This 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 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. + * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #define DATA_BITS (1 << (3 + SHIFT)) #define SHIFT_MASK (DATA_BITS - 1) #define SIGN_MASK (1 << (DATA_BITS - 1)) diff --git a/qemu-doc.texi b/qemu-doc.texi index a7b0ce9f7..fb9ed0ae9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -73,26 +73,53 @@ maximum performances. @chapter Invocation +@section Quick Start + In order to launch a Linux process, QEMU needs the process executable -itself and all the target (x86) dynamic libraries used by it. Currently, -QEMU is not distributed with the necessary packages so that you can test -it easily on non x86 CPUs. +itself and all the target (x86) dynamic libraries used by it. + +@itemize -However, the statically x86 binary 'tests/hello' can be used to do a -first test: +@item On x86, you can just try to launch any process by using the native +libraries: @example -qemu tests/hello +qemu -L / /bin/ls @end example -@code{Hello world} should be printed on the terminal. +@code{-L /} tells that the x86 dynamic linker must be searched with a +@file{/} prefix. -If you are testing it on a x86 CPU, then you can test it on any process: -@example -qemu /bin/ls -l +@item On non x86 CPUs, you need first to download at least an x86 glibc +(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Then you can +launch the precompiled @file{ls} x86 executable: +@example +qemu /usr/local/qemu-i386/bin/ls +@end example +You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that QEMU is automatically +launched by the Linux kernel when you try to launch x86 executables. It +requires the @code{binfmt_misc} module in the Linux kernel. + +@end itemize + +@section Command line options + +@example +usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...] @end example +@table @samp +@item -h +Print the help +@item -d +Activate log (logfile=/tmp/qemu.log) +@item -L path +Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) +@item -s size +Set the x86 stack size in bytes (default=524288) +@end table + @chapter QEMU Internals @section QEMU compared to other emulators diff --git a/tests/Makefile b/tests/Makefile index 495dbf3f4..0d0fb9b95 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -28,7 +28,7 @@ testthread: testthread.c # i386 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c test-i386-code16.S -lm test: test-i386 ifeq ($(ARCH),i386) diff --git a/tests/testsig.c b/tests/testsig.c index d93f42806..27ea78c6a 100644 --- a/tests/testsig.c +++ b/tests/testsig.c @@ -15,21 +15,34 @@ void alarm_handler(int sig) alarm(1); } +#ifndef REG_EAX +#define REG_EAX EAX +#define REG_EBX EBX +#define REG_ECX ECX +#define REG_EDX EDX +#define REG_ESI ESI +#define REG_EDI EDI +#define REG_EBP EBP +#define REG_ESP ESP +#define REG_EIP EIP +#define REG_EFL EFL +#endif + void dump_regs(struct ucontext *uc) { printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" "EFL=%08x EIP=%08x\n", - uc->uc_mcontext.gregs[EAX], - uc->uc_mcontext.gregs[EBX], - uc->uc_mcontext.gregs[ECX], - uc->uc_mcontext.gregs[EDX], - uc->uc_mcontext.gregs[ESI], - uc->uc_mcontext.gregs[EDI], - uc->uc_mcontext.gregs[EBP], - uc->uc_mcontext.gregs[ESP], - uc->uc_mcontext.gregs[EFL], - uc->uc_mcontext.gregs[EIP]); + uc->uc_mcontext.gregs[REG_EAX], + uc->uc_mcontext.gregs[REG_EBX], + uc->uc_mcontext.gregs[REG_ECX], + uc->uc_mcontext.gregs[REG_EDX], + uc->uc_mcontext.gregs[REG_ESI], + uc->uc_mcontext.gregs[REG_EDI], + uc->uc_mcontext.gregs[REG_EBP], + uc->uc_mcontext.gregs[REG_ESP], + uc->uc_mcontext.gregs[REG_EFL], + uc->uc_mcontext.gregs[REG_EIP]); } void sig_handler(int sig, siginfo_t *info, void *puc) -- cgit v1.2.3 From 644c433cb3759599aa1440b412964f8e49cc0b71 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Mar 2003 23:00:36 +0000 Subject: ld.so load fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@47 c046a42c-6fe2-441c-8c8c-71466251a162 --- README | 8 ++++++-- linux-user/elfload.c | 8 ++++---- qemu-doc.texi | 11 +++++++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/README b/README index 34061434a..64fe7e937 100644 --- a/README +++ b/README @@ -23,8 +23,12 @@ libraries installed on your PC. For example: ./qemu -L / /bin/ls * On non x86 CPUs, you need first to download at least an x86 glibc -(qemu-i386-glibc21.tar.gz on the qemu web page). Then you can launch -the precompiled 'ls' x86 executable: +(qemu-i386-glibc21.tar.gz on the qemu web page). Ensure that +LD_LIBRARY_PATH is not set: + + unset LD_LIBRARY_PATH + +Then you can launch the precompiled 'ls' x86 executable: ./qemu /usr/local/qemu-i386/bin/ls diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 817913df4..386991a49 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -360,9 +360,6 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, put_user (tswapl(val), dlinfo++) if (exec) { /* Put this here for an ELF program interpreter */ - struct elf_phdr * eppnt; - eppnt = (struct elf_phdr *)((unsigned long)exec->e_phoff); - NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff)); NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr))); NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum)); @@ -418,6 +415,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, */ load_addr = INTERP_LOADADDR; +#ifdef BSWAP_NEEDED + bswap_ehdr(interp_elf_ex); +#endif /* First of all, some simple consistency checks */ if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || @@ -425,6 +425,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, return ~0UL; } + /* Now read in all of the header information */ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE) @@ -452,7 +453,6 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); } - if (retval < 0) { perror("load_elf_interp"); exit(-1); diff --git a/qemu-doc.texi b/qemu-doc.texi index fb9ed0ae9..8afdbe0b9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -92,8 +92,15 @@ qemu -L / /bin/ls @item On non x86 CPUs, you need first to download at least an x86 glibc -(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Then you can -launch the precompiled @file{ls} x86 executable: +(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Ensure that +@code{LD_LIBRARY_PATH} is not set: + +@example +unset LD_LIBRARY_PATH +@end example + +Then you can launch the precompiled @file{ls} x86 executable: + @example qemu /usr/local/qemu-i386/bin/ls @end example -- cgit v1.2.3 From 8083a3e50895abb6070d9f339363d05d2c5e0017 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Mar 2003 23:12:16 +0000 Subject: dirent fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@48 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5f02fb72e..f0f790f5f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1603,10 +1603,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, int reclen; de = dirp; while (len > 0) { - reclen = tswap16(de->d_reclen); + reclen = de->d_reclen; if (reclen > len) break; - de->d_reclen = reclen; + de->d_reclen = tswap16(reclen); tswapls(&de->d_ino); tswapls(&de->d_off); de = (struct dirent *)((char *)de + reclen); @@ -1626,10 +1626,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, int reclen; de = dirp; while (len > 0) { - reclen = tswap16(de->d_reclen); + reclen = de->d_reclen; if (reclen > len) break; - de->d_reclen = reclen; + de->d_reclen = tswap16(reclen); tswap64s(&de->d_ino); tswap64s(&de->d_off); de = (struct dirent64 *)((char *)de + reclen); -- cgit v1.2.3 From 31bb950be6d1f144d349d9793c88fbb28ca5fb58 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 Mar 2003 22:33:47 +0000 Subject: xchg lock, xlat instr git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@49 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 5 +++++ opc-i386.h | 1 + translate-i386.c | 40 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/op-i386.c b/op-i386.c index fb3ff1d59..eac73ed93 100644 --- a/op-i386.c +++ b/op-i386.c @@ -489,6 +489,11 @@ void OPPROTO op_addl_A0_im(void) A0 += PARAM1; } +void OPPROTO op_addl_A0_AL(void) +{ + A0 += (EAX & 0xff); +} + void OPPROTO op_andl_A0_ffff(void) { A0 = A0 & 0xffff; diff --git a/opc-i386.h b/opc-i386.h index 9d9f8471b..eceecf41b 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -210,6 +210,7 @@ DEF(addl_T1_im) DEF(movl_T1_A0) DEF(movl_A0_im) DEF(addl_A0_im) +DEF(addl_A0_AL) DEF(andl_A0_ffff) DEF(ldub_T0_A0) DEF(ldsb_T0_A0) diff --git a/translate-i386.c b/translate-i386.c index afe7f3543..d7f6520e8 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -2083,7 +2083,40 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_st_T0_A0[ot](); } break; - + case 0xd7: /* xlat */ + /* handle override */ + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_AL(); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + /* XXX: factorize that */ + { + int override, must_add_seg; + override = R_DS; + must_add_seg = s->addseg; + if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | + PREFIX_ES | PREFIX_FS | PREFIX_GS)) { + if (s->prefix & PREFIX_ES) + override = R_ES; + else if (s->prefix & PREFIX_CS) + override = R_CS; + else if (s->prefix & PREFIX_SS) + override = R_SS; + else if (s->prefix & PREFIX_DS) + override = R_DS; + else if (s->prefix & PREFIX_FS) + override = R_FS; + else + override = R_GS; + must_add_seg = 1; + } + if (must_add_seg) { + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + } + } + gen_op_ldub_T0_A0(); + gen_op_mov_reg_T0[OT_BYTE][R_EAX](); + break; case 0xb0 ... 0xb7: /* mov R, Ib */ val = insn_get(s, OT_BYTE); gen_op_movl_T0_im(val); @@ -2121,8 +2154,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_mov_TN_reg[ot][0][reg](); + /* for xchg, lock is implicit */ + if (!(prefixes & PREFIX_LOCK)) + gen_op_lock(); gen_op_ld_T1_A0[ot](); gen_op_st_T0_A0[ot](); + if (!(prefixes & PREFIX_LOCK)) + gen_op_unlock(); gen_op_mov_reg_T1[ot][reg](); } break; -- cgit v1.2.3 From c3c7c29246a03afda6eb4c777b0f5d125e80669c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:44:42 +0000 Subject: added runcom git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@50 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 0d0fb9b95..14521fad6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -4,7 +4,7 @@ CFLAGS=-Wall -O2 -g LDFLAGS= ifeq ($(ARCH),i386) -TESTS=testclone testsig testthread sha1-i386 test-i386 +TESTS=testclone testsig testthread sha1-i386 test-i386 runcom endif TESTS+=sha1 @@ -48,5 +48,9 @@ speed: sha1 sha1-i386 time ./sha1 time $(QEMU) ./sha1-i386 +# vm86 test +runcom: runcom.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + clean: rm -f *~ *.o $(TESTS) -- cgit v1.2.3 From e1d4294a4534ef0c14fa83e958f352f5f783e931 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:45:07 +0000 Subject: more tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@51 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 866c769e4..2130bfcab 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -714,6 +714,10 @@ void test_segs(void) long long ldt_table[3]; int res, res2; char tmp; + struct { + uint32_t offset; + uint16_t seg; + } __attribute__((packed)) segoff; ldt.entry_number = 1; ldt.base_addr = (unsigned long)&seg_data1; @@ -772,6 +776,14 @@ void test_segs(void) : "r" (MK_SEL(1)), "r" (&tmp)); printf("DS[1] = %02x\n", res); printf("SS[tmp] = %02x\n", res2); + + segoff.seg = MK_SEL(2); + segoff.offset = 0xabcdef12; + asm volatile("lfs %2, %0\n\t" + "movl %%fs, %1\n\t" + : "=r" (res), "=g" (res2) + : "m" (segoff)); + printf("FS:reg = %04x:%08x\n", res2, res); } /* 16 bit code test */ @@ -812,6 +824,71 @@ void test_code16(void) printf("func3() = 0x%08x\n", res); } +void test_misc(void) +{ + char table[256]; + int res, i; + + for(i=0;i<256;i++) table[i] = 256 - i; + res = 0x12345678; + asm ("xlat" : "=a" (res) : "b" (table), "0" (res)); + printf("xlat: EAX=%08x\n", res); +} + +uint8_t str_buffer[4096]; + +#define TEST_STRING1(OP, size, DF, REP)\ +{\ + int esi, edi, eax, ecx, eflags;\ +\ + esi = (long)(str_buffer + sizeof(str_buffer) / 2);\ + edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\ + eax = 0x12345678;\ + ecx = 17;\ +\ + asm volatile ("pushl $0\n\t"\ + "popf\n\t"\ + DF "\n\t"\ + REP #OP size "\n\t"\ + "cld\n\t"\ + "pushf\n\t"\ + "popl %4\n\t"\ + : "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\ + : "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\ + printf("%-10s ESI=%08x EDI=%08x EAX=%08x ECX=%08x EFL=%04x\n",\ + REP #OP size, esi, edi, eax, ecx,\ + eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\ +} + +#define TEST_STRING(OP, REP)\ + TEST_STRING1(OP, "b", "", REP);\ + TEST_STRING1(OP, "w", "", REP);\ + TEST_STRING1(OP, "l", "", REP);\ + TEST_STRING1(OP, "b", "std", REP);\ + TEST_STRING1(OP, "w", "std", REP);\ + TEST_STRING1(OP, "l", "std", REP) + +void test_string(void) +{ + int i; + for(i = 0;i < sizeof(str_buffer); i++) + str_buffer[i] = i + 0x56; + TEST_STRING(stos, ""); + TEST_STRING(stos, "rep "); + TEST_STRING(lods, ""); /* to verify stos */ + TEST_STRING(lods, "rep "); + TEST_STRING(movs, ""); + TEST_STRING(movs, "rep "); + TEST_STRING(lods, ""); /* to verify stos */ + + /* XXX: better tests */ + TEST_STRING(scas, ""); + TEST_STRING(scas, "repz "); + TEST_STRING(scas, "repnz "); + TEST_STRING(cmps, ""); + TEST_STRING(cmps, "repz "); + TEST_STRING(cmps, "repnz "); +} static void *call_end __init_call = NULL; @@ -831,6 +908,8 @@ int main(int argc, char **argv) test_floats(); test_bcd(); test_xchg(); + test_string(); + test_misc(); test_lea(); test_segs(); test_code16(); -- cgit v1.2.3 From 0ea00c9a3c5e69ca30007f982fb7f2163ab8116c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:47:34 +0000 Subject: added number of arguments git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@52 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 9 +- opc-i386.h | 1171 +++++++++++++++++++++++++++++++++--------------------------- 2 files changed, 642 insertions(+), 538 deletions(-) diff --git a/dyngen.c b/dyngen.c index ed6861063..5cd59cb9d 100644 --- a/dyngen.c +++ b/dyngen.c @@ -282,7 +282,9 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, error("inconsistent argument numbering in %s", name); } - if (gen_switch) { + if (gen_switch == 2) { + fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args); + } else if (gen_switch == 1) { /* output C code */ fprintf(outfile, "case INDEX_%s: {\n", name); @@ -559,12 +561,13 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) } if (do_print_enum) { - fprintf(outfile, "DEF(end)\n"); + fprintf(outfile, "DEF(end, 0)\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name, *p; name = strtab + sym->st_name; if (strstart(name, OP_PREFIX, &p)) { - fprintf(outfile, "DEF(%s)\n", p); + gen_code(name, sym->st_value, sym->st_size, outfile, + text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 2); } } } else { diff --git a/opc-i386.h b/opc-i386.h index eceecf41b..2a50e26a7 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -1,535 +1,636 @@ -DEF(end) -DEF(movl_A0_EAX) -DEF(addl_A0_EAX) -DEF(addl_A0_EAX_s1) -DEF(addl_A0_EAX_s2) -DEF(addl_A0_EAX_s3) -DEF(movl_T0_EAX) -DEF(movl_T1_EAX) -DEF(movh_T0_EAX) -DEF(movh_T1_EAX) -DEF(movl_EAX_T0) -DEF(movl_EAX_T1) -DEF(movl_EAX_A0) -DEF(cmovw_EAX_T1_T0) -DEF(cmovl_EAX_T1_T0) -DEF(movw_EAX_T0) -DEF(movw_EAX_T1) -DEF(movw_EAX_A0) -DEF(movb_EAX_T0) -DEF(movh_EAX_T0) -DEF(movb_EAX_T1) -DEF(movh_EAX_T1) -DEF(movl_A0_ECX) -DEF(addl_A0_ECX) -DEF(addl_A0_ECX_s1) -DEF(addl_A0_ECX_s2) -DEF(addl_A0_ECX_s3) -DEF(movl_T0_ECX) -DEF(movl_T1_ECX) -DEF(movh_T0_ECX) -DEF(movh_T1_ECX) -DEF(movl_ECX_T0) -DEF(movl_ECX_T1) -DEF(movl_ECX_A0) -DEF(cmovw_ECX_T1_T0) -DEF(cmovl_ECX_T1_T0) -DEF(movw_ECX_T0) -DEF(movw_ECX_T1) -DEF(movw_ECX_A0) -DEF(movb_ECX_T0) -DEF(movh_ECX_T0) -DEF(movb_ECX_T1) -DEF(movh_ECX_T1) -DEF(movl_A0_EDX) -DEF(addl_A0_EDX) -DEF(addl_A0_EDX_s1) -DEF(addl_A0_EDX_s2) -DEF(addl_A0_EDX_s3) -DEF(movl_T0_EDX) -DEF(movl_T1_EDX) -DEF(movh_T0_EDX) -DEF(movh_T1_EDX) -DEF(movl_EDX_T0) -DEF(movl_EDX_T1) -DEF(movl_EDX_A0) -DEF(cmovw_EDX_T1_T0) -DEF(cmovl_EDX_T1_T0) -DEF(movw_EDX_T0) -DEF(movw_EDX_T1) -DEF(movw_EDX_A0) -DEF(movb_EDX_T0) -DEF(movh_EDX_T0) -DEF(movb_EDX_T1) -DEF(movh_EDX_T1) -DEF(movl_A0_EBX) -DEF(addl_A0_EBX) -DEF(addl_A0_EBX_s1) -DEF(addl_A0_EBX_s2) -DEF(addl_A0_EBX_s3) -DEF(movl_T0_EBX) -DEF(movl_T1_EBX) -DEF(movh_T0_EBX) -DEF(movh_T1_EBX) -DEF(movl_EBX_T0) -DEF(movl_EBX_T1) -DEF(movl_EBX_A0) -DEF(cmovw_EBX_T1_T0) -DEF(cmovl_EBX_T1_T0) -DEF(movw_EBX_T0) -DEF(movw_EBX_T1) -DEF(movw_EBX_A0) -DEF(movb_EBX_T0) -DEF(movh_EBX_T0) -DEF(movb_EBX_T1) -DEF(movh_EBX_T1) -DEF(movl_A0_ESP) -DEF(addl_A0_ESP) -DEF(addl_A0_ESP_s1) -DEF(addl_A0_ESP_s2) -DEF(addl_A0_ESP_s3) -DEF(movl_T0_ESP) -DEF(movl_T1_ESP) -DEF(movh_T0_ESP) -DEF(movh_T1_ESP) -DEF(movl_ESP_T0) -DEF(movl_ESP_T1) -DEF(movl_ESP_A0) -DEF(cmovw_ESP_T1_T0) -DEF(cmovl_ESP_T1_T0) -DEF(movw_ESP_T0) -DEF(movw_ESP_T1) -DEF(movw_ESP_A0) -DEF(movb_ESP_T0) -DEF(movh_ESP_T0) -DEF(movb_ESP_T1) -DEF(movh_ESP_T1) -DEF(movl_A0_EBP) -DEF(addl_A0_EBP) -DEF(addl_A0_EBP_s1) -DEF(addl_A0_EBP_s2) -DEF(addl_A0_EBP_s3) -DEF(movl_T0_EBP) -DEF(movl_T1_EBP) -DEF(movh_T0_EBP) -DEF(movh_T1_EBP) -DEF(movl_EBP_T0) -DEF(movl_EBP_T1) -DEF(movl_EBP_A0) -DEF(cmovw_EBP_T1_T0) -DEF(cmovl_EBP_T1_T0) -DEF(movw_EBP_T0) -DEF(movw_EBP_T1) -DEF(movw_EBP_A0) -DEF(movb_EBP_T0) -DEF(movh_EBP_T0) -DEF(movb_EBP_T1) -DEF(movh_EBP_T1) -DEF(movl_A0_ESI) -DEF(addl_A0_ESI) -DEF(addl_A0_ESI_s1) -DEF(addl_A0_ESI_s2) -DEF(addl_A0_ESI_s3) -DEF(movl_T0_ESI) -DEF(movl_T1_ESI) -DEF(movh_T0_ESI) -DEF(movh_T1_ESI) -DEF(movl_ESI_T0) -DEF(movl_ESI_T1) -DEF(movl_ESI_A0) -DEF(cmovw_ESI_T1_T0) -DEF(cmovl_ESI_T1_T0) -DEF(movw_ESI_T0) -DEF(movw_ESI_T1) -DEF(movw_ESI_A0) -DEF(movb_ESI_T0) -DEF(movh_ESI_T0) -DEF(movb_ESI_T1) -DEF(movh_ESI_T1) -DEF(movl_A0_EDI) -DEF(addl_A0_EDI) -DEF(addl_A0_EDI_s1) -DEF(addl_A0_EDI_s2) -DEF(addl_A0_EDI_s3) -DEF(movl_T0_EDI) -DEF(movl_T1_EDI) -DEF(movh_T0_EDI) -DEF(movh_T1_EDI) -DEF(movl_EDI_T0) -DEF(movl_EDI_T1) -DEF(movl_EDI_A0) -DEF(cmovw_EDI_T1_T0) -DEF(cmovl_EDI_T1_T0) -DEF(movw_EDI_T0) -DEF(movw_EDI_T1) -DEF(movw_EDI_A0) -DEF(movb_EDI_T0) -DEF(movh_EDI_T0) -DEF(movb_EDI_T1) -DEF(movh_EDI_T1) -DEF(addl_T0_T1_cc) -DEF(orl_T0_T1_cc) -DEF(andl_T0_T1_cc) -DEF(subl_T0_T1_cc) -DEF(xorl_T0_T1_cc) -DEF(cmpl_T0_T1_cc) -DEF(negl_T0_cc) -DEF(incl_T0_cc) -DEF(decl_T0_cc) -DEF(testl_T0_T1_cc) -DEF(addl_T0_T1) -DEF(orl_T0_T1) -DEF(andl_T0_T1) -DEF(subl_T0_T1) -DEF(xorl_T0_T1) -DEF(negl_T0) -DEF(incl_T0) -DEF(decl_T0) -DEF(notl_T0) -DEF(bswapl_T0) -DEF(mulb_AL_T0) -DEF(imulb_AL_T0) -DEF(mulw_AX_T0) -DEF(imulw_AX_T0) -DEF(mull_EAX_T0) -DEF(imull_EAX_T0) -DEF(imulw_T0_T1) -DEF(imull_T0_T1) -DEF(divb_AL_T0) -DEF(idivb_AL_T0) -DEF(divw_AX_T0) -DEF(idivw_AX_T0) -DEF(divl_EAX_T0) -DEF(idivl_EAX_T0) -DEF(movl_T0_im) -DEF(addl_T0_im) -DEF(andl_T0_ffff) -DEF(movl_T0_T1) -DEF(movl_T1_im) -DEF(addl_T1_im) -DEF(movl_T1_A0) -DEF(movl_A0_im) -DEF(addl_A0_im) -DEF(addl_A0_AL) -DEF(andl_A0_ffff) -DEF(ldub_T0_A0) -DEF(ldsb_T0_A0) -DEF(lduw_T0_A0) -DEF(ldsw_T0_A0) -DEF(ldl_T0_A0) -DEF(ldub_T1_A0) -DEF(ldsb_T1_A0) -DEF(lduw_T1_A0) -DEF(ldsw_T1_A0) -DEF(ldl_T1_A0) -DEF(stb_T0_A0) -DEF(stw_T0_A0) -DEF(stl_T0_A0) -DEF(add_bitw_A0_T1) -DEF(add_bitl_A0_T1) -DEF(jmp_T0) -DEF(jmp_im) -DEF(int_im) -DEF(int3) -DEF(into) -DEF(jb_subb) -DEF(jz_subb) -DEF(jbe_subb) -DEF(js_subb) -DEF(jl_subb) -DEF(jle_subb) -DEF(setb_T0_subb) -DEF(setz_T0_subb) -DEF(setbe_T0_subb) -DEF(sets_T0_subb) -DEF(setl_T0_subb) -DEF(setle_T0_subb) -DEF(rolb_T0_T1_cc) -DEF(rolb_T0_T1) -DEF(rorb_T0_T1_cc) -DEF(rorb_T0_T1) -DEF(rclb_T0_T1_cc) -DEF(rcrb_T0_T1_cc) -DEF(shlb_T0_T1_cc) -DEF(shlb_T0_T1) -DEF(shrb_T0_T1_cc) -DEF(shrb_T0_T1) -DEF(sarb_T0_T1_cc) -DEF(sarb_T0_T1) -DEF(adcb_T0_T1_cc) -DEF(sbbb_T0_T1_cc) -DEF(cmpxchgb_T0_T1_EAX_cc) -DEF(movsb) -DEF(rep_movsb) -DEF(stosb) -DEF(rep_stosb) -DEF(lodsb) -DEF(rep_lodsb) -DEF(scasb) -DEF(repz_scasb) -DEF(repnz_scasb) -DEF(cmpsb) -DEF(repz_cmpsb) -DEF(repnz_cmpsb) -DEF(outsb) -DEF(rep_outsb) -DEF(insb) -DEF(rep_insb) -DEF(outb_T0_T1) -DEF(inb_T0_T1) -DEF(jb_subw) -DEF(jz_subw) -DEF(jbe_subw) -DEF(js_subw) -DEF(jl_subw) -DEF(jle_subw) -DEF(loopnzw) -DEF(loopzw) -DEF(loopw) -DEF(jecxzw) -DEF(setb_T0_subw) -DEF(setz_T0_subw) -DEF(setbe_T0_subw) -DEF(sets_T0_subw) -DEF(setl_T0_subw) -DEF(setle_T0_subw) -DEF(rolw_T0_T1_cc) -DEF(rolw_T0_T1) -DEF(rorw_T0_T1_cc) -DEF(rorw_T0_T1) -DEF(rclw_T0_T1_cc) -DEF(rcrw_T0_T1_cc) -DEF(shlw_T0_T1_cc) -DEF(shlw_T0_T1) -DEF(shrw_T0_T1_cc) -DEF(shrw_T0_T1) -DEF(sarw_T0_T1_cc) -DEF(sarw_T0_T1) -DEF(shldw_T0_T1_im_cc) -DEF(shldw_T0_T1_ECX_cc) -DEF(shrdw_T0_T1_im_cc) -DEF(shrdw_T0_T1_ECX_cc) -DEF(adcw_T0_T1_cc) -DEF(sbbw_T0_T1_cc) -DEF(cmpxchgw_T0_T1_EAX_cc) -DEF(btw_T0_T1_cc) -DEF(btsw_T0_T1_cc) -DEF(btrw_T0_T1_cc) -DEF(btcw_T0_T1_cc) -DEF(bsfw_T0_cc) -DEF(bsrw_T0_cc) -DEF(movsw) -DEF(rep_movsw) -DEF(stosw) -DEF(rep_stosw) -DEF(lodsw) -DEF(rep_lodsw) -DEF(scasw) -DEF(repz_scasw) -DEF(repnz_scasw) -DEF(cmpsw) -DEF(repz_cmpsw) -DEF(repnz_cmpsw) -DEF(outsw) -DEF(rep_outsw) -DEF(insw) -DEF(rep_insw) -DEF(outw_T0_T1) -DEF(inw_T0_T1) -DEF(jb_subl) -DEF(jz_subl) -DEF(jbe_subl) -DEF(js_subl) -DEF(jl_subl) -DEF(jle_subl) -DEF(loopnzl) -DEF(loopzl) -DEF(loopl) -DEF(jecxzl) -DEF(setb_T0_subl) -DEF(setz_T0_subl) -DEF(setbe_T0_subl) -DEF(sets_T0_subl) -DEF(setl_T0_subl) -DEF(setle_T0_subl) -DEF(roll_T0_T1_cc) -DEF(roll_T0_T1) -DEF(rorl_T0_T1_cc) -DEF(rorl_T0_T1) -DEF(rcll_T0_T1_cc) -DEF(rcrl_T0_T1_cc) -DEF(shll_T0_T1_cc) -DEF(shll_T0_T1) -DEF(shrl_T0_T1_cc) -DEF(shrl_T0_T1) -DEF(sarl_T0_T1_cc) -DEF(sarl_T0_T1) -DEF(shldl_T0_T1_im_cc) -DEF(shldl_T0_T1_ECX_cc) -DEF(shrdl_T0_T1_im_cc) -DEF(shrdl_T0_T1_ECX_cc) -DEF(adcl_T0_T1_cc) -DEF(sbbl_T0_T1_cc) -DEF(cmpxchgl_T0_T1_EAX_cc) -DEF(btl_T0_T1_cc) -DEF(btsl_T0_T1_cc) -DEF(btrl_T0_T1_cc) -DEF(btcl_T0_T1_cc) -DEF(bsfl_T0_cc) -DEF(bsrl_T0_cc) -DEF(movsl) -DEF(rep_movsl) -DEF(stosl) -DEF(rep_stosl) -DEF(lodsl) -DEF(rep_lodsl) -DEF(scasl) -DEF(repz_scasl) -DEF(repnz_scasl) -DEF(cmpsl) -DEF(repz_cmpsl) -DEF(repnz_cmpsl) -DEF(outsl) -DEF(rep_outsl) -DEF(insl) -DEF(rep_insl) -DEF(outl_T0_T1) -DEF(inl_T0_T1) -DEF(movsbl_T0_T0) -DEF(movzbl_T0_T0) -DEF(movswl_T0_T0) -DEF(movzwl_T0_T0) -DEF(movswl_EAX_AX) -DEF(movsbw_AX_AL) -DEF(movslq_EDX_EAX) -DEF(movswl_DX_AX) -DEF(pushl_T0) -DEF(pushw_T0) -DEF(pushl_ss32_T0) -DEF(pushw_ss32_T0) -DEF(pushl_ss16_T0) -DEF(pushw_ss16_T0) -DEF(popl_T0) -DEF(popw_T0) -DEF(popl_ss32_T0) -DEF(popw_ss32_T0) -DEF(popl_ss16_T0) -DEF(popw_ss16_T0) -DEF(addl_ESP_4) -DEF(addl_ESP_2) -DEF(addw_ESP_4) -DEF(addw_ESP_2) -DEF(addl_ESP_im) -DEF(addw_ESP_im) -DEF(rdtsc) -DEF(aam) -DEF(aad) -DEF(aaa) -DEF(aas) -DEF(daa) -DEF(das) -DEF(movl_seg_T0) -DEF(movl_T0_seg) -DEF(addl_A0_seg) -DEF(jo_cc) -DEF(jb_cc) -DEF(jz_cc) -DEF(jbe_cc) -DEF(js_cc) -DEF(jp_cc) -DEF(jl_cc) -DEF(jle_cc) -DEF(seto_T0_cc) -DEF(setb_T0_cc) -DEF(setz_T0_cc) -DEF(setbe_T0_cc) -DEF(sets_T0_cc) -DEF(setp_T0_cc) -DEF(setl_T0_cc) -DEF(setle_T0_cc) -DEF(xor_T0_1) -DEF(set_cc_op) -DEF(movl_eflags_T0) -DEF(movb_eflags_T0) -DEF(movl_T0_eflags) -DEF(cld) -DEF(std) -DEF(clc) -DEF(stc) -DEF(cmc) -DEF(salc) -DEF(flds_FT0_A0) -DEF(fldl_FT0_A0) -DEF(fild_FT0_A0) -DEF(fildl_FT0_A0) -DEF(fildll_FT0_A0) -DEF(flds_ST0_A0) -DEF(fldl_ST0_A0) -DEF(fldt_ST0_A0) -DEF(fild_ST0_A0) -DEF(fildl_ST0_A0) -DEF(fildll_ST0_A0) -DEF(fsts_ST0_A0) -DEF(fstl_ST0_A0) -DEF(fstt_ST0_A0) -DEF(fist_ST0_A0) -DEF(fistl_ST0_A0) -DEF(fistll_ST0_A0) -DEF(fbld_ST0_A0) -DEF(fbst_ST0_A0) -DEF(fpush) -DEF(fpop) -DEF(fdecstp) -DEF(fincstp) -DEF(fmov_ST0_FT0) -DEF(fmov_FT0_STN) -DEF(fmov_ST0_STN) -DEF(fmov_STN_ST0) -DEF(fxchg_ST0_STN) -DEF(fcom_ST0_FT0) -DEF(fucom_ST0_FT0) -DEF(fadd_ST0_FT0) -DEF(fmul_ST0_FT0) -DEF(fsub_ST0_FT0) -DEF(fsubr_ST0_FT0) -DEF(fdiv_ST0_FT0) -DEF(fdivr_ST0_FT0) -DEF(fadd_STN_ST0) -DEF(fmul_STN_ST0) -DEF(fsub_STN_ST0) -DEF(fsubr_STN_ST0) -DEF(fdiv_STN_ST0) -DEF(fdivr_STN_ST0) -DEF(fchs_ST0) -DEF(fabs_ST0) -DEF(fxam_ST0) -DEF(fld1_ST0) -DEF(fldl2t_ST0) -DEF(fldl2e_ST0) -DEF(fldpi_ST0) -DEF(fldlg2_ST0) -DEF(fldln2_ST0) -DEF(fldz_ST0) -DEF(fldz_FT0) -DEF(f2xm1) -DEF(fyl2x) -DEF(fptan) -DEF(fpatan) -DEF(fxtract) -DEF(fprem1) -DEF(fprem) -DEF(fyl2xp1) -DEF(fsqrt) -DEF(fsincos) -DEF(frndint) -DEF(fscale) -DEF(fsin) -DEF(fcos) -DEF(fnstsw_A0) -DEF(fnstsw_EAX) -DEF(fnstcw_A0) -DEF(fldcw_A0) -DEF(fclex) -DEF(fninit) -DEF(lock) -DEF(unlock) +DEF(end, 0) +DEF(movl_A0_EAX, 0) +DEF(addl_A0_EAX, 0) +DEF(addl_A0_EAX_s1, 0) +DEF(addl_A0_EAX_s2, 0) +DEF(addl_A0_EAX_s3, 0) +DEF(movl_T0_EAX, 0) +DEF(movl_T1_EAX, 0) +DEF(movh_T0_EAX, 0) +DEF(movh_T1_EAX, 0) +DEF(movl_EAX_T0, 0) +DEF(movl_EAX_T1, 0) +DEF(movl_EAX_A0, 0) +DEF(cmovw_EAX_T1_T0, 0) +DEF(cmovl_EAX_T1_T0, 0) +DEF(movw_EAX_T0, 0) +DEF(movw_EAX_T1, 0) +DEF(movw_EAX_A0, 0) +DEF(movb_EAX_T0, 0) +DEF(movh_EAX_T0, 0) +DEF(movb_EAX_T1, 0) +DEF(movh_EAX_T1, 0) +DEF(movl_A0_ECX, 0) +DEF(addl_A0_ECX, 0) +DEF(addl_A0_ECX_s1, 0) +DEF(addl_A0_ECX_s2, 0) +DEF(addl_A0_ECX_s3, 0) +DEF(movl_T0_ECX, 0) +DEF(movl_T1_ECX, 0) +DEF(movh_T0_ECX, 0) +DEF(movh_T1_ECX, 0) +DEF(movl_ECX_T0, 0) +DEF(movl_ECX_T1, 0) +DEF(movl_ECX_A0, 0) +DEF(cmovw_ECX_T1_T0, 0) +DEF(cmovl_ECX_T1_T0, 0) +DEF(movw_ECX_T0, 0) +DEF(movw_ECX_T1, 0) +DEF(movw_ECX_A0, 0) +DEF(movb_ECX_T0, 0) +DEF(movh_ECX_T0, 0) +DEF(movb_ECX_T1, 0) +DEF(movh_ECX_T1, 0) +DEF(movl_A0_EDX, 0) +DEF(addl_A0_EDX, 0) +DEF(addl_A0_EDX_s1, 0) +DEF(addl_A0_EDX_s2, 0) +DEF(addl_A0_EDX_s3, 0) +DEF(movl_T0_EDX, 0) +DEF(movl_T1_EDX, 0) +DEF(movh_T0_EDX, 0) +DEF(movh_T1_EDX, 0) +DEF(movl_EDX_T0, 0) +DEF(movl_EDX_T1, 0) +DEF(movl_EDX_A0, 0) +DEF(cmovw_EDX_T1_T0, 0) +DEF(cmovl_EDX_T1_T0, 0) +DEF(movw_EDX_T0, 0) +DEF(movw_EDX_T1, 0) +DEF(movw_EDX_A0, 0) +DEF(movb_EDX_T0, 0) +DEF(movh_EDX_T0, 0) +DEF(movb_EDX_T1, 0) +DEF(movh_EDX_T1, 0) +DEF(movl_A0_EBX, 0) +DEF(addl_A0_EBX, 0) +DEF(addl_A0_EBX_s1, 0) +DEF(addl_A0_EBX_s2, 0) +DEF(addl_A0_EBX_s3, 0) +DEF(movl_T0_EBX, 0) +DEF(movl_T1_EBX, 0) +DEF(movh_T0_EBX, 0) +DEF(movh_T1_EBX, 0) +DEF(movl_EBX_T0, 0) +DEF(movl_EBX_T1, 0) +DEF(movl_EBX_A0, 0) +DEF(cmovw_EBX_T1_T0, 0) +DEF(cmovl_EBX_T1_T0, 0) +DEF(movw_EBX_T0, 0) +DEF(movw_EBX_T1, 0) +DEF(movw_EBX_A0, 0) +DEF(movb_EBX_T0, 0) +DEF(movh_EBX_T0, 0) +DEF(movb_EBX_T1, 0) +DEF(movh_EBX_T1, 0) +DEF(movl_A0_ESP, 0) +DEF(addl_A0_ESP, 0) +DEF(addl_A0_ESP_s1, 0) +DEF(addl_A0_ESP_s2, 0) +DEF(addl_A0_ESP_s3, 0) +DEF(movl_T0_ESP, 0) +DEF(movl_T1_ESP, 0) +DEF(movh_T0_ESP, 0) +DEF(movh_T1_ESP, 0) +DEF(movl_ESP_T0, 0) +DEF(movl_ESP_T1, 0) +DEF(movl_ESP_A0, 0) +DEF(cmovw_ESP_T1_T0, 0) +DEF(cmovl_ESP_T1_T0, 0) +DEF(movw_ESP_T0, 0) +DEF(movw_ESP_T1, 0) +DEF(movw_ESP_A0, 0) +DEF(movb_ESP_T0, 0) +DEF(movh_ESP_T0, 0) +DEF(movb_ESP_T1, 0) +DEF(movh_ESP_T1, 0) +DEF(movl_A0_EBP, 0) +DEF(addl_A0_EBP, 0) +DEF(addl_A0_EBP_s1, 0) +DEF(addl_A0_EBP_s2, 0) +DEF(addl_A0_EBP_s3, 0) +DEF(movl_T0_EBP, 0) +DEF(movl_T1_EBP, 0) +DEF(movh_T0_EBP, 0) +DEF(movh_T1_EBP, 0) +DEF(movl_EBP_T0, 0) +DEF(movl_EBP_T1, 0) +DEF(movl_EBP_A0, 0) +DEF(cmovw_EBP_T1_T0, 0) +DEF(cmovl_EBP_T1_T0, 0) +DEF(movw_EBP_T0, 0) +DEF(movw_EBP_T1, 0) +DEF(movw_EBP_A0, 0) +DEF(movb_EBP_T0, 0) +DEF(movh_EBP_T0, 0) +DEF(movb_EBP_T1, 0) +DEF(movh_EBP_T1, 0) +DEF(movl_A0_ESI, 0) +DEF(addl_A0_ESI, 0) +DEF(addl_A0_ESI_s1, 0) +DEF(addl_A0_ESI_s2, 0) +DEF(addl_A0_ESI_s3, 0) +DEF(movl_T0_ESI, 0) +DEF(movl_T1_ESI, 0) +DEF(movh_T0_ESI, 0) +DEF(movh_T1_ESI, 0) +DEF(movl_ESI_T0, 0) +DEF(movl_ESI_T1, 0) +DEF(movl_ESI_A0, 0) +DEF(cmovw_ESI_T1_T0, 0) +DEF(cmovl_ESI_T1_T0, 0) +DEF(movw_ESI_T0, 0) +DEF(movw_ESI_T1, 0) +DEF(movw_ESI_A0, 0) +DEF(movb_ESI_T0, 0) +DEF(movh_ESI_T0, 0) +DEF(movb_ESI_T1, 0) +DEF(movh_ESI_T1, 0) +DEF(movl_A0_EDI, 0) +DEF(addl_A0_EDI, 0) +DEF(addl_A0_EDI_s1, 0) +DEF(addl_A0_EDI_s2, 0) +DEF(addl_A0_EDI_s3, 0) +DEF(movl_T0_EDI, 0) +DEF(movl_T1_EDI, 0) +DEF(movh_T0_EDI, 0) +DEF(movh_T1_EDI, 0) +DEF(movl_EDI_T0, 0) +DEF(movl_EDI_T1, 0) +DEF(movl_EDI_A0, 0) +DEF(cmovw_EDI_T1_T0, 0) +DEF(cmovl_EDI_T1_T0, 0) +DEF(movw_EDI_T0, 0) +DEF(movw_EDI_T1, 0) +DEF(movw_EDI_A0, 0) +DEF(movb_EDI_T0, 0) +DEF(movh_EDI_T0, 0) +DEF(movb_EDI_T1, 0) +DEF(movh_EDI_T1, 0) +DEF(addl_T0_T1_cc, 0) +DEF(orl_T0_T1_cc, 0) +DEF(andl_T0_T1_cc, 0) +DEF(subl_T0_T1_cc, 0) +DEF(xorl_T0_T1_cc, 0) +DEF(cmpl_T0_T1_cc, 0) +DEF(negl_T0_cc, 0) +DEF(incl_T0_cc, 0) +DEF(decl_T0_cc, 0) +DEF(testl_T0_T1_cc, 0) +DEF(addl_T0_T1, 0) +DEF(orl_T0_T1, 0) +DEF(andl_T0_T1, 0) +DEF(subl_T0_T1, 0) +DEF(xorl_T0_T1, 0) +DEF(negl_T0, 0) +DEF(incl_T0, 0) +DEF(decl_T0, 0) +DEF(notl_T0, 0) +DEF(bswapl_T0, 0) +DEF(mulb_AL_T0, 0) +DEF(imulb_AL_T0, 0) +DEF(mulw_AX_T0, 0) +DEF(imulw_AX_T0, 0) +DEF(mull_EAX_T0, 0) +DEF(imull_EAX_T0, 0) +DEF(imulw_T0_T1, 0) +DEF(imull_T0_T1, 0) +DEF(divb_AL_T0, 0) +DEF(idivb_AL_T0, 0) +DEF(divw_AX_T0, 0) +DEF(idivw_AX_T0, 0) +DEF(divl_EAX_T0, 0) +DEF(idivl_EAX_T0, 0) +DEF(movl_T0_im, 1) +DEF(addl_T0_im, 1) +DEF(andl_T0_ffff, 0) +DEF(movl_T0_T1, 0) +DEF(movl_T1_im, 1) +DEF(addl_T1_im, 1) +DEF(movl_T1_A0, 0) +DEF(movl_A0_im, 1) +DEF(addl_A0_im, 1) +DEF(addl_A0_AL, 0) +DEF(andl_A0_ffff, 0) +DEF(ldub_T0_A0, 0) +DEF(ldsb_T0_A0, 0) +DEF(lduw_T0_A0, 0) +DEF(ldsw_T0_A0, 0) +DEF(ldl_T0_A0, 0) +DEF(ldub_T1_A0, 0) +DEF(ldsb_T1_A0, 0) +DEF(lduw_T1_A0, 0) +DEF(ldsw_T1_A0, 0) +DEF(ldl_T1_A0, 0) +DEF(stb_T0_A0, 0) +DEF(stw_T0_A0, 0) +DEF(stl_T0_A0, 0) +DEF(add_bitw_A0_T1, 0) +DEF(add_bitl_A0_T1, 0) +DEF(jmp_T0, 0) +DEF(jmp_im, 1) +DEF(int_im, 1) +DEF(int3, 1) +DEF(into, 0) +DEF(boundw, 0) +DEF(boundl, 0) +DEF(cmpxchg8b, 0) +DEF(jb_subb, 2) +DEF(jz_subb, 2) +DEF(jbe_subb, 2) +DEF(js_subb, 2) +DEF(jl_subb, 2) +DEF(jle_subb, 2) +DEF(setb_T0_subb, 0) +DEF(setz_T0_subb, 0) +DEF(setbe_T0_subb, 0) +DEF(sets_T0_subb, 0) +DEF(setl_T0_subb, 0) +DEF(setle_T0_subb, 0) +DEF(rolb_T0_T1_cc, 0) +DEF(rolb_T0_T1, 0) +DEF(rorb_T0_T1_cc, 0) +DEF(rorb_T0_T1, 0) +DEF(rclb_T0_T1_cc, 0) +DEF(rcrb_T0_T1_cc, 0) +DEF(shlb_T0_T1_cc, 0) +DEF(shlb_T0_T1, 0) +DEF(shrb_T0_T1_cc, 0) +DEF(shrb_T0_T1, 0) +DEF(sarb_T0_T1_cc, 0) +DEF(sarb_T0_T1, 0) +DEF(adcb_T0_T1_cc, 0) +DEF(sbbb_T0_T1_cc, 0) +DEF(cmpxchgb_T0_T1_EAX_cc, 0) +DEF(movsb_fast, 0) +DEF(rep_movsb_fast, 0) +DEF(stosb_fast, 0) +DEF(rep_stosb_fast, 0) +DEF(lodsb_fast, 0) +DEF(rep_lodsb_fast, 0) +DEF(scasb_fast, 0) +DEF(repz_scasb_fast, 0) +DEF(repnz_scasb_fast, 0) +DEF(cmpsb_fast, 0) +DEF(repz_cmpsb_fast, 0) +DEF(repnz_cmpsb_fast, 0) +DEF(outsb_fast, 0) +DEF(rep_outsb_fast, 0) +DEF(insb_fast, 0) +DEF(rep_insb_fast, 0) +DEF(movsb_a32, 0) +DEF(rep_movsb_a32, 0) +DEF(stosb_a32, 0) +DEF(rep_stosb_a32, 0) +DEF(lodsb_a32, 0) +DEF(rep_lodsb_a32, 0) +DEF(scasb_a32, 0) +DEF(repz_scasb_a32, 0) +DEF(repnz_scasb_a32, 0) +DEF(cmpsb_a32, 0) +DEF(repz_cmpsb_a32, 0) +DEF(repnz_cmpsb_a32, 0) +DEF(outsb_a32, 0) +DEF(rep_outsb_a32, 0) +DEF(insb_a32, 0) +DEF(rep_insb_a32, 0) +DEF(movsb_a16, 0) +DEF(rep_movsb_a16, 0) +DEF(stosb_a16, 0) +DEF(rep_stosb_a16, 0) +DEF(lodsb_a16, 0) +DEF(rep_lodsb_a16, 0) +DEF(scasb_a16, 0) +DEF(repz_scasb_a16, 0) +DEF(repnz_scasb_a16, 0) +DEF(cmpsb_a16, 0) +DEF(repz_cmpsb_a16, 0) +DEF(repnz_cmpsb_a16, 0) +DEF(outsb_a16, 0) +DEF(rep_outsb_a16, 0) +DEF(insb_a16, 0) +DEF(rep_insb_a16, 0) +DEF(outb_T0_T1, 0) +DEF(inb_T0_T1, 0) +DEF(jb_subw, 2) +DEF(jz_subw, 2) +DEF(jbe_subw, 2) +DEF(js_subw, 2) +DEF(jl_subw, 2) +DEF(jle_subw, 2) +DEF(loopnzw, 2) +DEF(loopzw, 2) +DEF(loopw, 2) +DEF(jecxzw, 2) +DEF(setb_T0_subw, 0) +DEF(setz_T0_subw, 0) +DEF(setbe_T0_subw, 0) +DEF(sets_T0_subw, 0) +DEF(setl_T0_subw, 0) +DEF(setle_T0_subw, 0) +DEF(rolw_T0_T1_cc, 0) +DEF(rolw_T0_T1, 0) +DEF(rorw_T0_T1_cc, 0) +DEF(rorw_T0_T1, 0) +DEF(rclw_T0_T1_cc, 0) +DEF(rcrw_T0_T1_cc, 0) +DEF(shlw_T0_T1_cc, 0) +DEF(shlw_T0_T1, 0) +DEF(shrw_T0_T1_cc, 0) +DEF(shrw_T0_T1, 0) +DEF(sarw_T0_T1_cc, 0) +DEF(sarw_T0_T1, 0) +DEF(shldw_T0_T1_im_cc, 1) +DEF(shldw_T0_T1_ECX_cc, 0) +DEF(shrdw_T0_T1_im_cc, 1) +DEF(shrdw_T0_T1_ECX_cc, 0) +DEF(adcw_T0_T1_cc, 0) +DEF(sbbw_T0_T1_cc, 0) +DEF(cmpxchgw_T0_T1_EAX_cc, 0) +DEF(btw_T0_T1_cc, 0) +DEF(btsw_T0_T1_cc, 0) +DEF(btrw_T0_T1_cc, 0) +DEF(btcw_T0_T1_cc, 0) +DEF(bsfw_T0_cc, 0) +DEF(bsrw_T0_cc, 0) +DEF(movsw_fast, 0) +DEF(rep_movsw_fast, 0) +DEF(stosw_fast, 0) +DEF(rep_stosw_fast, 0) +DEF(lodsw_fast, 0) +DEF(rep_lodsw_fast, 0) +DEF(scasw_fast, 0) +DEF(repz_scasw_fast, 0) +DEF(repnz_scasw_fast, 0) +DEF(cmpsw_fast, 0) +DEF(repz_cmpsw_fast, 0) +DEF(repnz_cmpsw_fast, 0) +DEF(outsw_fast, 0) +DEF(rep_outsw_fast, 0) +DEF(insw_fast, 0) +DEF(rep_insw_fast, 0) +DEF(movsw_a32, 0) +DEF(rep_movsw_a32, 0) +DEF(stosw_a32, 0) +DEF(rep_stosw_a32, 0) +DEF(lodsw_a32, 0) +DEF(rep_lodsw_a32, 0) +DEF(scasw_a32, 0) +DEF(repz_scasw_a32, 0) +DEF(repnz_scasw_a32, 0) +DEF(cmpsw_a32, 0) +DEF(repz_cmpsw_a32, 0) +DEF(repnz_cmpsw_a32, 0) +DEF(outsw_a32, 0) +DEF(rep_outsw_a32, 0) +DEF(insw_a32, 0) +DEF(rep_insw_a32, 0) +DEF(movsw_a16, 0) +DEF(rep_movsw_a16, 0) +DEF(stosw_a16, 0) +DEF(rep_stosw_a16, 0) +DEF(lodsw_a16, 0) +DEF(rep_lodsw_a16, 0) +DEF(scasw_a16, 0) +DEF(repz_scasw_a16, 0) +DEF(repnz_scasw_a16, 0) +DEF(cmpsw_a16, 0) +DEF(repz_cmpsw_a16, 0) +DEF(repnz_cmpsw_a16, 0) +DEF(outsw_a16, 0) +DEF(rep_outsw_a16, 0) +DEF(insw_a16, 0) +DEF(rep_insw_a16, 0) +DEF(outw_T0_T1, 0) +DEF(inw_T0_T1, 0) +DEF(jb_subl, 2) +DEF(jz_subl, 2) +DEF(jbe_subl, 2) +DEF(js_subl, 2) +DEF(jl_subl, 2) +DEF(jle_subl, 2) +DEF(loopnzl, 2) +DEF(loopzl, 2) +DEF(loopl, 2) +DEF(jecxzl, 2) +DEF(setb_T0_subl, 0) +DEF(setz_T0_subl, 0) +DEF(setbe_T0_subl, 0) +DEF(sets_T0_subl, 0) +DEF(setl_T0_subl, 0) +DEF(setle_T0_subl, 0) +DEF(roll_T0_T1_cc, 0) +DEF(roll_T0_T1, 0) +DEF(rorl_T0_T1_cc, 0) +DEF(rorl_T0_T1, 0) +DEF(rcll_T0_T1_cc, 0) +DEF(rcrl_T0_T1_cc, 0) +DEF(shll_T0_T1_cc, 0) +DEF(shll_T0_T1, 0) +DEF(shrl_T0_T1_cc, 0) +DEF(shrl_T0_T1, 0) +DEF(sarl_T0_T1_cc, 0) +DEF(sarl_T0_T1, 0) +DEF(shldl_T0_T1_im_cc, 1) +DEF(shldl_T0_T1_ECX_cc, 0) +DEF(shrdl_T0_T1_im_cc, 1) +DEF(shrdl_T0_T1_ECX_cc, 0) +DEF(adcl_T0_T1_cc, 0) +DEF(sbbl_T0_T1_cc, 0) +DEF(cmpxchgl_T0_T1_EAX_cc, 0) +DEF(btl_T0_T1_cc, 0) +DEF(btsl_T0_T1_cc, 0) +DEF(btrl_T0_T1_cc, 0) +DEF(btcl_T0_T1_cc, 0) +DEF(bsfl_T0_cc, 0) +DEF(bsrl_T0_cc, 0) +DEF(movsl_fast, 0) +DEF(rep_movsl_fast, 0) +DEF(stosl_fast, 0) +DEF(rep_stosl_fast, 0) +DEF(lodsl_fast, 0) +DEF(rep_lodsl_fast, 0) +DEF(scasl_fast, 0) +DEF(repz_scasl_fast, 0) +DEF(repnz_scasl_fast, 0) +DEF(cmpsl_fast, 0) +DEF(repz_cmpsl_fast, 0) +DEF(repnz_cmpsl_fast, 0) +DEF(outsl_fast, 0) +DEF(rep_outsl_fast, 0) +DEF(insl_fast, 0) +DEF(rep_insl_fast, 0) +DEF(movsl_a32, 0) +DEF(rep_movsl_a32, 0) +DEF(stosl_a32, 0) +DEF(rep_stosl_a32, 0) +DEF(lodsl_a32, 0) +DEF(rep_lodsl_a32, 0) +DEF(scasl_a32, 0) +DEF(repz_scasl_a32, 0) +DEF(repnz_scasl_a32, 0) +DEF(cmpsl_a32, 0) +DEF(repz_cmpsl_a32, 0) +DEF(repnz_cmpsl_a32, 0) +DEF(outsl_a32, 0) +DEF(rep_outsl_a32, 0) +DEF(insl_a32, 0) +DEF(rep_insl_a32, 0) +DEF(movsl_a16, 0) +DEF(rep_movsl_a16, 0) +DEF(stosl_a16, 0) +DEF(rep_stosl_a16, 0) +DEF(lodsl_a16, 0) +DEF(rep_lodsl_a16, 0) +DEF(scasl_a16, 0) +DEF(repz_scasl_a16, 0) +DEF(repnz_scasl_a16, 0) +DEF(cmpsl_a16, 0) +DEF(repz_cmpsl_a16, 0) +DEF(repnz_cmpsl_a16, 0) +DEF(outsl_a16, 0) +DEF(rep_outsl_a16, 0) +DEF(insl_a16, 0) +DEF(rep_insl_a16, 0) +DEF(outl_T0_T1, 0) +DEF(inl_T0_T1, 0) +DEF(movsbl_T0_T0, 0) +DEF(movzbl_T0_T0, 0) +DEF(movswl_T0_T0, 0) +DEF(movzwl_T0_T0, 0) +DEF(movswl_EAX_AX, 0) +DEF(movsbw_AX_AL, 0) +DEF(movslq_EDX_EAX, 0) +DEF(movswl_DX_AX, 0) +DEF(pushl_T0, 0) +DEF(pushw_T0, 0) +DEF(pushl_ss32_T0, 0) +DEF(pushw_ss32_T0, 0) +DEF(pushl_ss16_T0, 0) +DEF(pushw_ss16_T0, 0) +DEF(popl_T0, 0) +DEF(popw_T0, 0) +DEF(popl_ss32_T0, 0) +DEF(popw_ss32_T0, 0) +DEF(popl_ss16_T0, 0) +DEF(popw_ss16_T0, 0) +DEF(addl_ESP_4, 0) +DEF(addl_ESP_2, 0) +DEF(addw_ESP_4, 0) +DEF(addw_ESP_2, 0) +DEF(addl_ESP_im, 1) +DEF(addw_ESP_im, 1) +DEF(rdtsc, 0) +DEF(cpuid, 0) +DEF(aam, 1) +DEF(aad, 1) +DEF(aaa, 0) +DEF(aas, 0) +DEF(daa, 0) +DEF(das, 0) +DEF(movl_seg_T0, 1) +DEF(movl_T0_seg, 1) +DEF(movl_A0_seg, 1) +DEF(addl_A0_seg, 1) +DEF(jo_cc, 2) +DEF(jb_cc, 2) +DEF(jz_cc, 2) +DEF(jbe_cc, 2) +DEF(js_cc, 2) +DEF(jp_cc, 2) +DEF(jl_cc, 2) +DEF(jle_cc, 2) +DEF(seto_T0_cc, 0) +DEF(setb_T0_cc, 0) +DEF(setz_T0_cc, 0) +DEF(setbe_T0_cc, 0) +DEF(sets_T0_cc, 0) +DEF(setp_T0_cc, 0) +DEF(setl_T0_cc, 0) +DEF(setle_T0_cc, 0) +DEF(xor_T0_1, 0) +DEF(set_cc_op, 1) +DEF(movl_eflags_T0, 0) +DEF(movb_eflags_T0, 0) +DEF(movl_T0_eflags, 0) +DEF(cld, 0) +DEF(std, 0) +DEF(clc, 0) +DEF(stc, 0) +DEF(cmc, 0) +DEF(salc, 0) +DEF(flds_FT0_A0, 0) +DEF(fldl_FT0_A0, 0) +DEF(fild_FT0_A0, 0) +DEF(fildl_FT0_A0, 0) +DEF(fildll_FT0_A0, 0) +DEF(flds_ST0_A0, 0) +DEF(fldl_ST0_A0, 0) +DEF(fldt_ST0_A0, 0) +DEF(fild_ST0_A0, 0) +DEF(fildl_ST0_A0, 0) +DEF(fildll_ST0_A0, 0) +DEF(fsts_ST0_A0, 0) +DEF(fstl_ST0_A0, 0) +DEF(fstt_ST0_A0, 0) +DEF(fist_ST0_A0, 0) +DEF(fistl_ST0_A0, 0) +DEF(fistll_ST0_A0, 0) +DEF(fbld_ST0_A0, 0) +DEF(fbst_ST0_A0, 0) +DEF(fpush, 0) +DEF(fpop, 0) +DEF(fdecstp, 0) +DEF(fincstp, 0) +DEF(fmov_ST0_FT0, 0) +DEF(fmov_FT0_STN, 1) +DEF(fmov_ST0_STN, 1) +DEF(fmov_STN_ST0, 1) +DEF(fxchg_ST0_STN, 1) +DEF(fcom_ST0_FT0, 0) +DEF(fucom_ST0_FT0, 0) +DEF(fadd_ST0_FT0, 0) +DEF(fmul_ST0_FT0, 0) +DEF(fsub_ST0_FT0, 0) +DEF(fsubr_ST0_FT0, 0) +DEF(fdiv_ST0_FT0, 0) +DEF(fdivr_ST0_FT0, 0) +DEF(fadd_STN_ST0, 1) +DEF(fmul_STN_ST0, 1) +DEF(fsub_STN_ST0, 1) +DEF(fsubr_STN_ST0, 1) +DEF(fdiv_STN_ST0, 1) +DEF(fdivr_STN_ST0, 1) +DEF(fchs_ST0, 0) +DEF(fabs_ST0, 0) +DEF(fxam_ST0, 0) +DEF(fld1_ST0, 0) +DEF(fldl2t_ST0, 0) +DEF(fldl2e_ST0, 0) +DEF(fldpi_ST0, 0) +DEF(fldlg2_ST0, 0) +DEF(fldln2_ST0, 0) +DEF(fldz_ST0, 0) +DEF(fldz_FT0, 0) +DEF(f2xm1, 0) +DEF(fyl2x, 0) +DEF(fptan, 0) +DEF(fpatan, 0) +DEF(fxtract, 0) +DEF(fprem1, 0) +DEF(fprem, 0) +DEF(fyl2xp1, 0) +DEF(fsqrt, 0) +DEF(fsincos, 0) +DEF(frndint, 0) +DEF(fscale, 0) +DEF(fsin, 0) +DEF(fcos, 0) +DEF(fnstsw_A0, 0) +DEF(fnstsw_EAX, 0) +DEF(fnstcw_A0, 0) +DEF(fldcw_A0, 0) +DEF(fclex, 0) +DEF(fninit, 0) +DEF(lock, 0) +DEF(unlock, 0) -- cgit v1.2.3 From a4a0ffdb2be25b381df38758b1b0a32ae04491d0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:49:21 +0000 Subject: added cmpxchg8b, cpuid, bound, eflags support, vm86 mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@53 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 9 deletions(-) diff --git a/op-i386.c b/op-i386.c index eac73ed93..dbf70bb59 100644 --- a/op-i386.c +++ b/op-i386.c @@ -607,11 +607,49 @@ void OPPROTO op_into(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_O) { - EIP = PARAM1; raise_exception(EXCP04_INTO); + } +} + +void OPPROTO op_boundw(void) +{ + int low, high, v; + low = ldsw((uint8_t *)A0); + high = ldsw((uint8_t *)A0 + 2); + v = (int16_t)T0; + if (v < low || v > high) + raise_exception(EXCP05_BOUND); + FORCE_RET(); +} + +void OPPROTO op_boundl(void) +{ + int low, high, v; + low = ldl((uint8_t *)A0); + high = ldl((uint8_t *)A0 + 4); + v = T0; + if (v < low || v > high) + raise_exception(EXCP05_BOUND); + FORCE_RET(); +} + +void OPPROTO op_cmpxchg8b(void) +{ + uint64_t d; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + d = ldq((uint8_t *)A0); + if (d == (((uint64_t)EDX << 32) | EAX)) { + stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); + eflags |= CC_Z; } else { - EIP = PARAM2; + EDX = d >> 32; + EAX = d; + eflags &= ~CC_Z; } + CC_SRC = eflags; + FORCE_RET(); } /* string ops */ @@ -793,7 +831,8 @@ void op_addw_ESP_im(void) #ifndef __i386__ uint64_t emu_time; #endif -void op_rdtsc(void) + +void OPPROTO op_rdtsc(void) { uint64_t val; #ifdef __i386__ @@ -806,6 +845,51 @@ void op_rdtsc(void) EDX = val >> 32; } +/* We simulate a pre-MMX pentium as in valgrind */ +#define CPUID_FP87 (1 << 0) +#define CPUID_VME (1 << 1) +#define CPUID_DE (1 << 2) +#define CPUID_PSE (1 << 3) +#define CPUID_TSC (1 << 4) +#define CPUID_MSR (1 << 5) +#define CPUID_PAE (1 << 6) +#define CPUID_MCE (1 << 7) +#define CPUID_CX8 (1 << 8) +#define CPUID_APIC (1 << 9) +#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ +#define CPUID_MTRR (1 << 12) +#define CPUID_PGE (1 << 13) +#define CPUID_MCA (1 << 14) +#define CPUID_CMOV (1 << 15) +/* ... */ +#define CPUID_MMX (1 << 23) +#define CPUID_FXSR (1 << 24) +#define CPUID_SSE (1 << 25) +#define CPUID_SSE2 (1 << 26) + +void helper_cpuid(void) +{ + if (EAX == 0) { + EAX = 1; /* max EAX index supported */ + EBX = 0x756e6547; + ECX = 0x6c65746e; + EDX = 0x49656e69; + } else { + /* EAX = 1 info */ + EAX = 0x52b; + EBX = 0; + ECX = 0; + EDX = CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | + CPUID_TSC | CPUID_MSR | CPUID_MCE | + CPUID_CX8; + } +} + +void OPPROTO op_cpuid(void) +{ + helper_cpuid(); +} + /* bcd */ /* XXX: exception */ @@ -938,6 +1022,7 @@ void OPPROTO op_das(void) /* segment handling */ +/* XXX: use static VM86 information */ void load_seg(int seg_reg, int selector) { SegmentCache *sc; @@ -948,7 +1033,7 @@ void load_seg(int seg_reg, int selector) env->segs[seg_reg] = selector; sc = &env->seg_cache[seg_reg]; - if (env->vm86) { + if (env->eflags & VM_MASK) { sc->base = (void *)(selector << 4); sc->limit = 0xffff; sc->seg_32bit = 0; @@ -985,6 +1070,11 @@ void OPPROTO op_movl_T0_seg(void) T0 = env->segs[PARAM1]; } +void OPPROTO op_movl_A0_seg(void) +{ + A0 = *(unsigned long *)((char *)env + PARAM1); +} + void OPPROTO op_addl_A0_seg(void) { A0 += *(unsigned long *)((char *)env + PARAM1); @@ -1144,10 +1234,16 @@ void OPPROTO op_set_cc_op(void) CC_OP = PARAM1; } +#define FL_UPDATE_MASK (TF_MASK | AC_MASK | ID_MASK) + void OPPROTO op_movl_eflags_T0(void) { - CC_SRC = T0; - DF = 1 - (2 * ((T0 >> 10) & 1)); + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~FL_UPDATE_MASK) | (eflags & FL_UPDATE_MASK); } /* XXX: compute only O flag */ @@ -1155,13 +1251,16 @@ void OPPROTO op_movb_eflags_T0(void) { int of; of = cc_table[CC_OP].compute_all() & CC_O; - CC_SRC = T0 | of; + CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of; } void OPPROTO op_movl_T0_eflags(void) { - T0 = cc_table[CC_OP].compute_all(); - T0 |= (DF & DIRECTION_FLAG); + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DF_MASK); + eflags |= env->eflags & ~(VM_MASK | RF_MASK); + T0 = eflags; } void OPPROTO op_cld(void) -- cgit v1.2.3 From 24f9e90b0e183d501ff77c6851cbe11e7d7254a1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:50:40 +0000 Subject: 16bit/override support in string operations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@54 c046a42c-6fe2-441c-8c8c-71466251a162 --- op_string.h | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ops_template.h | 257 +++++++-------------------------------------------------- 2 files changed, 273 insertions(+), 229 deletions(-) create mode 100644 op_string.h diff --git a/op_string.h b/op_string.h new file mode 100644 index 000000000..9d0b454c3 --- /dev/null +++ b/op_string.h @@ -0,0 +1,245 @@ + +void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void) +{ + int v, inc; + inc = (DF << SHIFT); + v = glue(ldu, SUFFIX)(SI_ADDR); + glue(st, SUFFIX)(DI_ADDR, v); + inc = (DF << SHIFT); + INC_SI(); + INC_DI(); +} + +void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void) +{ + int v, inc; + inc = (DF << SHIFT); + while (CX != 0) { + v = glue(ldu, SUFFIX)(SI_ADDR); + glue(st, SUFFIX)(DI_ADDR, v); + INC_SI(); + INC_DI(); + DEC_CX(); + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void) +{ + int inc; + glue(st, SUFFIX)(DI_ADDR, EAX); + inc = (DF << SHIFT); + INC_DI(); +} + +void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void) +{ + int inc; + inc = (DF << SHIFT); + while (CX != 0) { + glue(st, SUFFIX)(DI_ADDR, EAX); + INC_DI(); + DEC_CX(); + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void) +{ + int v, inc; + v = glue(ldu, SUFFIX)(SI_ADDR); +#if SHIFT == 0 + EAX = (EAX & ~0xff) | v; +#elif SHIFT == 1 + EAX = (EAX & ~0xffff) | v; +#else + EAX = v; +#endif + inc = (DF << SHIFT); + INC_SI(); +} + +/* don't know if it is used */ +void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void) +{ + int v, inc; + inc = (DF << SHIFT); + while (CX != 0) { + v = glue(ldu, SUFFIX)(SI_ADDR); +#if SHIFT == 0 + EAX = (EAX & ~0xff) | v; +#elif SHIFT == 1 + EAX = (EAX & ~0xffff) | v; +#else + EAX = v; +#endif + INC_SI(); + DEC_CX(); + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void) +{ + int v, inc; + + v = glue(ldu, SUFFIX)(DI_ADDR); + inc = (DF << SHIFT); + INC_DI(); + CC_SRC = EAX; + CC_DST = EAX - v; +} + +void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void) +{ + int v1, v2, inc; + + if (CX != 0) { + /* NOTE: the flags are not modified if CX == 0 */ + v1 = EAX & DATA_MASK; + inc = (DF << SHIFT); + do { + v2 = glue(ldu, SUFFIX)(DI_ADDR); + INC_DI(); + DEC_CX(); + if (v1 != v2) + break; + } while (CX != 0); + CC_SRC = v1; + CC_DST = v1 - v2; + CC_OP = CC_OP_SUBB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void) +{ + int v1, v2, inc; + + if (CX != 0) { + /* NOTE: the flags are not modified if CX == 0 */ + v1 = EAX & DATA_MASK; + inc = (DF << SHIFT); + do { + v2 = glue(ldu, SUFFIX)(DI_ADDR); + INC_DI(); + DEC_CX(); + if (v1 == v2) + break; + } while (CX != 0); + CC_SRC = v1; + CC_DST = v1 - v2; + CC_OP = CC_OP_SUBB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void) +{ + int v1, v2, inc; + v1 = glue(ldu, SUFFIX)(SI_ADDR); + v2 = glue(ldu, SUFFIX)(DI_ADDR); + inc = (DF << SHIFT); + INC_SI(); + INC_DI(); + CC_SRC = v1; + CC_DST = v1 - v2; +} + +void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void) +{ + int v1, v2, inc; + if (CX != 0) { + inc = (DF << SHIFT); + do { + v1 = glue(ldu, SUFFIX)(SI_ADDR); + v2 = glue(ldu, SUFFIX)(DI_ADDR); + INC_SI(); + INC_DI(); + DEC_CX(); + if (v1 != v2) + break; + } while (CX != 0); + CC_SRC = v1; + CC_DST = v1 - v2; + CC_OP = CC_OP_SUBB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void) +{ + int v1, v2, inc; + if (CX != 0) { + inc = (DF << SHIFT); + do { + v1 = glue(ldu, SUFFIX)(SI_ADDR); + v2 = glue(ldu, SUFFIX)(DI_ADDR); + INC_SI(); + INC_DI(); + DEC_CX(); + if (v1 == v2) + break; + } while (CX != 0); + CC_SRC = v1; + CC_DST = v1 - v2; + CC_OP = CC_OP_SUBB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void) +{ + int v, dx, inc; + dx = EDX & 0xffff; + v = glue(ldu, SUFFIX)(SI_ADDR); + glue(cpu_x86_out, SUFFIX)(dx, v); + inc = (DF << SHIFT); + INC_SI(); +} + +void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void) +{ + int v, dx, inc; + inc = (DF << SHIFT); + dx = EDX & 0xffff; + while (CX != 0) { + v = glue(ldu, SUFFIX)(SI_ADDR); + glue(cpu_x86_out, SUFFIX)(dx, v); + INC_SI(); + DEC_CX(); + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void) +{ + int v, dx, inc; + dx = EDX & 0xffff; + v = glue(cpu_x86_in, SUFFIX)(dx); + glue(st, SUFFIX)(DI_ADDR, v); + inc = (DF << SHIFT); + INC_DI(); +} + +void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void) +{ + int v, dx, inc; + inc = (DF << SHIFT); + dx = EDX & 0xffff; + while (CX != 0) { + v = glue(cpu_x86_in, SUFFIX)(dx); + glue(st, SUFFIX)(DI_ADDR, v); + INC_DI(); + DEC_CX(); + } + FORCE_RET(); +} + +#undef STRING_SUFFIX +#undef SI_ADDR +#undef DI_ADDR +#undef INC_SI +#undef INC_DI +#undef CX +#undef DEC_CX diff --git a/ops_template.h b/ops_template.h index 34f10cdf9..60223fb2f 100644 --- a/ops_template.h +++ b/ops_template.h @@ -806,238 +806,37 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) #endif /* string operations */ -/* XXX: maybe use lower level instructions to ease exception handling */ - -void OPPROTO glue(op_movs, SUFFIX)(void) -{ - int v; - v = glue(ldu, SUFFIX)((void *)ESI); - glue(st, SUFFIX)((void *)EDI, v); - ESI += (DF << SHIFT); - EDI += (DF << SHIFT); -} - -void OPPROTO glue(op_rep_movs, SUFFIX)(void) -{ - int v, inc; - inc = (DF << SHIFT); - while (ECX != 0) { - v = glue(ldu, SUFFIX)((void *)ESI); - glue(st, SUFFIX)((void *)EDI, v); - ESI += inc; - EDI += inc; - ECX--; - } - FORCE_RET(); -} - -void OPPROTO glue(op_stos, SUFFIX)(void) -{ - glue(st, SUFFIX)((void *)EDI, EAX); - EDI += (DF << SHIFT); -} - -void OPPROTO glue(op_rep_stos, SUFFIX)(void) -{ - int inc; - inc = (DF << SHIFT); - while (ECX != 0) { - glue(st, SUFFIX)((void *)EDI, EAX); - EDI += inc; - ECX--; - } - FORCE_RET(); -} - -void OPPROTO glue(op_lods, SUFFIX)(void) -{ - int v; - v = glue(ldu, SUFFIX)((void *)ESI); -#if SHIFT == 0 - EAX = (EAX & ~0xff) | v; -#elif SHIFT == 1 - EAX = (EAX & ~0xffff) | v; -#else - EAX = v; -#endif - ESI += (DF << SHIFT); -} - -/* don't know if it is used */ -void OPPROTO glue(op_rep_lods, SUFFIX)(void) -{ - int v, inc; - inc = (DF << SHIFT); - while (ECX != 0) { - v = glue(ldu, SUFFIX)((void *)ESI); -#if SHIFT == 0 - EAX = (EAX & ~0xff) | v; -#elif SHIFT == 1 - EAX = (EAX & ~0xffff) | v; -#else - EAX = v; -#endif - ESI += inc; - ECX--; - } - FORCE_RET(); -} - -void OPPROTO glue(op_scas, SUFFIX)(void) -{ - int v; - - v = glue(ldu, SUFFIX)((void *)EDI); - EDI += (DF << SHIFT); - CC_SRC = EAX; - CC_DST = EAX - v; -} - -void OPPROTO glue(op_repz_scas, SUFFIX)(void) -{ - int v1, v2, inc; - - if (ECX != 0) { - /* NOTE: the flags are not modified if ECX == 0 */ - v1 = EAX & DATA_MASK; - inc = (DF << SHIFT); - do { - v2 = glue(ldu, SUFFIX)((void *)EDI); - EDI += inc; - ECX--; - if (v1 != v2) - break; - } while (ECX != 0); - CC_SRC = v1; - CC_DST = v1 - v2; - CC_OP = CC_OP_SUBB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(op_repnz_scas, SUFFIX)(void) -{ - int v1, v2, inc; - - if (ECX != 0) { - /* NOTE: the flags are not modified if ECX == 0 */ - v1 = EAX & DATA_MASK; - inc = (DF << SHIFT); - do { - v2 = glue(ldu, SUFFIX)((void *)EDI); - EDI += inc; - ECX--; - if (v1 == v2) - break; - } while (ECX != 0); - CC_SRC = v1; - CC_DST = v1 - v2; - CC_OP = CC_OP_SUBB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(op_cmps, SUFFIX)(void) -{ - int v1, v2; - v1 = glue(ldu, SUFFIX)((void *)ESI); - v2 = glue(ldu, SUFFIX)((void *)EDI); - ESI += (DF << SHIFT); - EDI += (DF << SHIFT); - CC_SRC = v1; - CC_DST = v1 - v2; -} - -void OPPROTO glue(op_repz_cmps, SUFFIX)(void) -{ - int v1, v2, inc; - if (ECX != 0) { - inc = (DF << SHIFT); - do { - v1 = glue(ldu, SUFFIX)((void *)ESI); - v2 = glue(ldu, SUFFIX)((void *)EDI); - ESI += inc; - EDI += inc; - ECX--; - if (v1 != v2) - break; - } while (ECX != 0); - CC_SRC = v1; - CC_DST = v1 - v2; - CC_OP = CC_OP_SUBB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(op_repnz_cmps, SUFFIX)(void) -{ - int v1, v2, inc; - if (ECX != 0) { - inc = (DF << SHIFT); - do { - v1 = glue(ldu, SUFFIX)((void *)ESI); - v2 = glue(ldu, SUFFIX)((void *)EDI); - ESI += inc; - EDI += inc; - ECX--; - if (v1 == v2) - break; - } while (ECX != 0); - CC_SRC = v1; - CC_DST = v1 - v2; - CC_OP = CC_OP_SUBB + SHIFT; - } - FORCE_RET(); -} +/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */ + +#define STRING_SUFFIX _fast +#define SI_ADDR (void *)ESI +#define DI_ADDR (void *)EDI +#define INC_SI() ESI += inc +#define INC_DI() EDI += inc +#define CX ECX +#define DEC_CX() ECX-- +#include "op_string.h" + +#define STRING_SUFFIX _a32 +#define SI_ADDR (uint8_t *)A0 + ESI +#define DI_ADDR env->seg_cache[R_ES].base + EDI +#define INC_SI() ESI += inc +#define INC_DI() EDI += inc +#define CX ECX +#define DEC_CX() ECX-- +#include "op_string.h" + +#define STRING_SUFFIX _a16 +#define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff) +#define DI_ADDR env->seg_cache[R_ES].base + (EDI & 0xffff) +#define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff) +#define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff) +#define CX (ECX & 0xffff) +#define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff) +#include "op_string.h" /* port I/O */ -void OPPROTO glue(op_outs, SUFFIX)(void) -{ - int v, dx; - dx = EDX & 0xffff; - v = glue(ldu, SUFFIX)((void *)ESI); - glue(cpu_x86_out, SUFFIX)(dx, v); - ESI += (DF << SHIFT); -} - -void OPPROTO glue(op_rep_outs, SUFFIX)(void) -{ - int v, dx, inc; - inc = (DF << SHIFT); - dx = EDX & 0xffff; - while (ECX != 0) { - v = glue(ldu, SUFFIX)((void *)ESI); - glue(cpu_x86_out, SUFFIX)(dx, v); - ESI += inc; - ECX--; - } - FORCE_RET(); -} - -void OPPROTO glue(op_ins, SUFFIX)(void) -{ - int v, dx; - dx = EDX & 0xffff; - v = glue(cpu_x86_in, SUFFIX)(dx); - glue(st, SUFFIX)((void *)EDI, v); - EDI += (DF << SHIFT); -} - -void OPPROTO glue(op_rep_ins, SUFFIX)(void) -{ - int v, dx, inc; - inc = (DF << SHIFT); - dx = EDX & 0xffff; - while (ECX != 0) { - v = glue(cpu_x86_in, SUFFIX)(dx); - glue(st, SUFFIX)((void *)EDI, v); - EDI += (DF << SHIFT); - ECX--; - } - FORCE_RET(); -} - void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) { glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK); -- cgit v1.2.3 From 9c605cb13547a5faa5cb1092e3e44ac8b0d0b841 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:51:35 +0000 Subject: added cmpxchg8b, cpuid, bound, eflags support, vm86 mode, 16bit/override string ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@55 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 388 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 206 insertions(+), 182 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index d7f6520e8..730398e97 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -76,21 +76,16 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) extern FILE *logfile; extern int loglevel; -#define PREFIX_REPZ 1 -#define PREFIX_REPNZ 2 -#define PREFIX_LOCK 4 -#define PREFIX_CS 8 -#define PREFIX_SS 0x10 -#define PREFIX_DS 0x20 -#define PREFIX_ES 0x40 -#define PREFIX_FS 0x80 -#define PREFIX_GS 0x100 -#define PREFIX_DATA 0x200 -#define PREFIX_ADR 0x400 -#define PREFIX_FWAIT 0x800 +#define PREFIX_REPZ 0x01 +#define PREFIX_REPNZ 0x02 +#define PREFIX_LOCK 0x04 +#define PREFIX_DATA 0x08 +#define PREFIX_ADR 0x10 +#define PREFIX_FWAIT 0x20 typedef struct DisasContext { /* current insn context */ + int override; /* -1 if no override */ int prefix; int aflag, dflag; uint8_t *pc; /* pc = eip + cs_base */ @@ -103,6 +98,7 @@ typedef struct DisasContext { int cc_op; /* current CC operation */ int addseg; /* non zero if either DS/ES/SS have a non zero base */ int f_st; /* currently unused */ + int vm86; /* vm86 mode */ } DisasContext; /* i386 arith/logic operations */ @@ -130,7 +126,7 @@ enum { }; enum { -#define DEF(s) INDEX_op_ ## s, +#define DEF(s, n) INDEX_op_ ## s, #include "opc-i386.h" #undef DEF NB_OPS, @@ -556,76 +552,100 @@ static GenOpFunc *gen_op_st_T0_A0[3] = { gen_op_stl_T0_A0, }; -static GenOpFunc *gen_op_movs[6] = { - gen_op_movsb, - gen_op_movsw, - gen_op_movsl, - gen_op_rep_movsb, - gen_op_rep_movsw, - gen_op_rep_movsl, +/* the _a32 and _a16 string operations use A0 as the base register. */ + +#define STRINGOP(x) \ + gen_op_ ## x ## b_fast, \ + gen_op_ ## x ## w_fast, \ + gen_op_ ## x ## l_fast, \ + gen_op_ ## x ## b_a32, \ + gen_op_ ## x ## w_a32, \ + gen_op_ ## x ## l_a32, \ + gen_op_ ## x ## b_a16, \ + gen_op_ ## x ## w_a16, \ + gen_op_ ## x ## l_a16, + +static GenOpFunc *gen_op_movs[9 * 2] = { + STRINGOP(movs) + STRINGOP(rep_movs) }; -static GenOpFunc *gen_op_stos[6] = { - gen_op_stosb, - gen_op_stosw, - gen_op_stosl, - gen_op_rep_stosb, - gen_op_rep_stosw, - gen_op_rep_stosl, +static GenOpFunc *gen_op_stos[9 * 2] = { + STRINGOP(stos) + STRINGOP(rep_stos) }; -static GenOpFunc *gen_op_lods[6] = { - gen_op_lodsb, - gen_op_lodsw, - gen_op_lodsl, - gen_op_rep_lodsb, - gen_op_rep_lodsw, - gen_op_rep_lodsl, +static GenOpFunc *gen_op_lods[9 * 2] = { + STRINGOP(lods) + STRINGOP(rep_lods) }; -static GenOpFunc *gen_op_scas[9] = { - gen_op_scasb, - gen_op_scasw, - gen_op_scasl, - gen_op_repz_scasb, - gen_op_repz_scasw, - gen_op_repz_scasl, - gen_op_repnz_scasb, - gen_op_repnz_scasw, - gen_op_repnz_scasl, +static GenOpFunc *gen_op_scas[9 * 3] = { + STRINGOP(scas) + STRINGOP(repz_scas) + STRINGOP(repnz_scas) }; -static GenOpFunc *gen_op_cmps[9] = { - gen_op_cmpsb, - gen_op_cmpsw, - gen_op_cmpsl, - gen_op_repz_cmpsb, - gen_op_repz_cmpsw, - gen_op_repz_cmpsl, - gen_op_repnz_cmpsb, - gen_op_repnz_cmpsw, - gen_op_repnz_cmpsl, +static GenOpFunc *gen_op_cmps[9 * 3] = { + STRINGOP(cmps) + STRINGOP(repz_cmps) + STRINGOP(repnz_cmps) }; -static GenOpFunc *gen_op_ins[6] = { - gen_op_insb, - gen_op_insw, - gen_op_insl, - gen_op_rep_insb, - gen_op_rep_insw, - gen_op_rep_insl, +static GenOpFunc *gen_op_ins[9 * 2] = { + STRINGOP(ins) + STRINGOP(rep_ins) }; -static GenOpFunc *gen_op_outs[6] = { - gen_op_outsb, - gen_op_outsw, - gen_op_outsl, - gen_op_rep_outsb, - gen_op_rep_outsw, - gen_op_rep_outsl, +static GenOpFunc *gen_op_outs[9 * 2] = { + STRINGOP(outs) + STRINGOP(rep_outs) }; + +static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) +{ + int index, override; + + override = s->override; + if (s->aflag) { + /* 32 bit address */ + if (s->addseg && override < 0) + override = R_DS; + if (override >= 0) { + gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + index = 3 + ot; + } else { + index = ot; + } + } else { + if (override < 0) + override = R_DS; + gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + /* 16 address, always override */ + index = 6 + ot; + } + func[index](); +} + +static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func) +{ + int index; + + if (s->aflag) { + if (s->addseg) { + index = 3 + ot; + } else { + index = ot; + } + } else { + index = 6 + ot; + } + func[index](); +} + + static GenOpFunc *gen_op_in[3] = { gen_op_inb_T0_T1, gen_op_inw_T0_T1, @@ -849,26 +869,10 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ int opreg; int mod, rm, code, override, must_add_seg; - /* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */ - override = -1; + override = s->override; must_add_seg = s->addseg; - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { - if (s->prefix & PREFIX_ES) - override = R_ES; - else if (s->prefix & PREFIX_CS) - override = R_CS; - else if (s->prefix & PREFIX_SS) - override = R_SS; - else if (s->prefix & PREFIX_DS) - override = R_DS; - else if (s->prefix & PREFIX_FS) - override = R_FS; - else - override = R_GS; + if (override >= 0) must_add_seg = 1; - } - mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -1343,7 +1347,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) prefixes = 0; aflag = s->code32; dflag = s->code32; - // cur_pc = s->pc; /* for insn generation */ + s->override = -1; next_byte: b = ldub(s->pc); s->pc++; @@ -1359,22 +1363,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) prefixes |= PREFIX_LOCK; goto next_byte; case 0x2e: - prefixes |= PREFIX_CS; + s->override = R_CS; goto next_byte; case 0x36: - prefixes |= PREFIX_SS; + s->override = R_SS; goto next_byte; case 0x3e: - prefixes |= PREFIX_DS; + s->override = R_DS; goto next_byte; case 0x26: - prefixes |= PREFIX_ES; + s->override = R_ES; goto next_byte; case 0x64: - prefixes |= PREFIX_FS; + s->override = R_FS; goto next_byte; case 0x65: - prefixes |= PREFIX_GS; + s->override = R_GS; goto next_byte; case 0x66: prefixes |= PREFIX_DATA; @@ -1830,6 +1834,17 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } s->cc_op = CC_OP_SUBB + ot; break; + case 0x1c7: /* cmpxchg8b */ + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_cmpxchg8b(); + s->cc_op = CC_OP_EFLAGS; + break; /**************************/ /* push/pop */ @@ -2027,8 +2042,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) modrm = ldub(s->pc++); reg = (modrm >> 3) & 7; /* we must ensure that no segment is added */ - s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS | - PREFIX_ES | PREFIX_FS | PREFIX_GS); + s->override = -1; val = s->addseg; s->addseg = 0; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); @@ -2050,26 +2064,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) offset_addr = insn_get(s, OT_WORD); gen_op_movl_A0_im(offset_addr); /* handle override */ - /* XXX: factorize that */ { int override, must_add_seg; - override = R_DS; must_add_seg = s->addseg; - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { - if (s->prefix & PREFIX_ES) - override = R_ES; - else if (s->prefix & PREFIX_CS) - override = R_CS; - else if (s->prefix & PREFIX_SS) - override = R_SS; - else if (s->prefix & PREFIX_DS) - override = R_DS; - else if (s->prefix & PREFIX_FS) - override = R_FS; - else - override = R_GS; + if (s->override >= 0) { + override = s->override; must_add_seg = 1; + } else { + override = R_DS; } if (must_add_seg) { gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); @@ -2084,31 +2086,20 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0xd7: /* xlat */ - /* handle override */ gen_op_movl_A0_reg[R_EBX](); gen_op_addl_A0_AL(); if (s->aflag == 0) gen_op_andl_A0_ffff(); - /* XXX: factorize that */ + /* handle override */ { int override, must_add_seg; - override = R_DS; must_add_seg = s->addseg; - if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | - PREFIX_ES | PREFIX_FS | PREFIX_GS)) { - if (s->prefix & PREFIX_ES) - override = R_ES; - else if (s->prefix & PREFIX_CS) - override = R_CS; - else if (s->prefix & PREFIX_SS) - override = R_SS; - else if (s->prefix & PREFIX_DS) - override = R_DS; - else if (s->prefix & PREFIX_FS) - override = R_FS; - else - override = R_GS; + override = R_DS; + if (s->override >= 0) { + override = s->override; must_add_seg = 1; + } else { + override = R_DS; } if (must_add_seg) { gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); @@ -2185,6 +2176,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[ot](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ @@ -2658,16 +2650,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; /************************/ /* string ops */ + case 0xa4: /* movsS */ case 0xa5: if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { - gen_op_movs[3 + ot](); + gen_string_ds(s, ot, gen_op_movs + 9); } else { - gen_op_movs[ot](); + gen_string_ds(s, ot, gen_op_movs); } break; @@ -2677,10 +2671,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { - gen_op_stos[3 + ot](); + gen_string_es(s, ot, gen_op_stos + 9); } else { - gen_op_stos[ot](); + gen_string_es(s, ot, gen_op_stos); } break; case 0xac: /* lodsS */ @@ -2690,9 +2685,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPZ) { - gen_op_lods[3 + ot](); + gen_string_ds(s, ot, gen_op_lods + 9); } else { - gen_op_lods[ot](); + gen_string_ds(s, ot, gen_op_lods); } break; case 0xae: /* scasS */ @@ -2700,19 +2695,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPNZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_scas[6 + ot](); + gen_string_es(s, ot, gen_op_scas + 9 * 2); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_scas[3 + ot](); + gen_string_es(s, ot, gen_op_scas + 9); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { - gen_op_scas[ot](); + gen_string_es(s, ot, gen_op_scas); s->cc_op = CC_OP_SUBB + ot; } break; @@ -2726,21 +2721,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (prefixes & PREFIX_REPNZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_cmps[6 + ot](); + gen_string_ds(s, ot, gen_op_cmps + 9 * 2); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_cmps[3 + ot](); + gen_string_ds(s, ot, gen_op_cmps + 9); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { - gen_op_cmps[ot](); + gen_string_ds(s, ot, gen_op_cmps); s->cc_op = CC_OP_SUBB + ot; } break; - - /************************/ - /* port I/O */ case 0x6c: /* insS */ case 0x6d: if ((b & 1) == 0) @@ -2748,9 +2740,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPZ) { - gen_op_ins[3 + ot](); + gen_string_es(s, ot, gen_op_ins + 9); } else { - gen_op_ins[ot](); + gen_string_es(s, ot, gen_op_ins); } break; case 0x6e: /* outsS */ @@ -2760,11 +2752,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPZ) { - gen_op_outs[3 + ot](); + gen_string_ds(s, ot, gen_op_outs + 9); } else { - gen_op_outs[ot](); + gen_string_ds(s, ot, gen_op_outs); } break; + + /************************/ + /* port I/O */ case 0xe4: case 0xe5: if ((b & 1) == 0) @@ -3150,14 +3145,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xcd: /* int N */ val = ldub(s->pc++); /* XXX: currently we ignore the interrupt number */ - gen_op_int_im((long)pc_start); + gen_op_int_im(pc_start - s->cs_base); s->is_jmp = 1; break; case 0xce: /* into */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_into((long)pc_start, (long)s->pc); - s->is_jmp = 1; + gen_op_into(); + break; + case 0x62: /* bound */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + gen_op_mov_reg_T0[ot][reg](); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (ot == OT_WORD) + gen_op_boundw(); + else + gen_op_boundl(); break; case 0x1c8 ... 0x1cf: /* bswap reg */ reg = b & 7; @@ -3188,11 +3196,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x131: /* rdtsc */ gen_op_rdtsc(); break; -#if 0 case 0x1a2: /* cpuid */ - gen_insn0(OP_ASM); + gen_op_cpuid(); break; -#endif default: goto illegal_op; } @@ -3399,28 +3405,30 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, - [INDEX_op_scasb] = CC_OSZAPC, - [INDEX_op_scasw] = CC_OSZAPC, - [INDEX_op_scasl] = CC_OSZAPC, - [INDEX_op_repz_scasb] = CC_OSZAPC, - [INDEX_op_repz_scasw] = CC_OSZAPC, - [INDEX_op_repz_scasl] = CC_OSZAPC, - [INDEX_op_repnz_scasb] = CC_OSZAPC, - [INDEX_op_repnz_scasw] = CC_OSZAPC, - [INDEX_op_repnz_scasl] = CC_OSZAPC, - - [INDEX_op_cmpsb] = CC_OSZAPC, - [INDEX_op_cmpsw] = CC_OSZAPC, - [INDEX_op_cmpsl] = CC_OSZAPC, - [INDEX_op_repz_cmpsb] = CC_OSZAPC, - [INDEX_op_repz_cmpsw] = CC_OSZAPC, - [INDEX_op_repz_cmpsl] = CC_OSZAPC, - [INDEX_op_repnz_cmpsb] = CC_OSZAPC, - [INDEX_op_repnz_cmpsw] = CC_OSZAPC, - [INDEX_op_repnz_cmpsl] = CC_OSZAPC, - +#undef STRINGOP +#define STRINGOP(x) \ + [INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \ + [INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \ + [INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \ + [INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \ + [INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \ + [INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \ + [INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \ + [INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ + [INDEX_op_ ## x ## l_a16] = CC_OSZAPC, + + STRINGOP(scas) + STRINGOP(repz_scas) + STRINGOP(repnz_scas) + STRINGOP(cmps) + STRINGOP(repz_cmps) + STRINGOP(repnz_cmps) + + [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, + + [INDEX_op_cmpxchg8b] = CC_Z, }; /* simpler form of an operation if no flags need to be generated */ @@ -3495,21 +3503,36 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) #ifdef DEBUG_DISAS static const char *op_str[] = { -#define DEF(s) #s, +#define DEF(s, n) #s, +#include "opc-i386.h" +#undef DEF +}; + +static uint8_t op_nb_args[] = { +#define DEF(s, n) n, #include "opc-i386.h" #undef DEF }; -static void dump_ops(const uint16_t *opc_buf) +static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) { const uint16_t *opc_ptr; - int c; + const uint32_t *opparam_ptr; + int c, n, i; + opc_ptr = opc_buf; + opparam_ptr = opparam_buf; for(;;) { c = *opc_ptr++; - fprintf(logfile, "0x%04x: %s\n", opc_ptr - opc_buf - 1, op_str[c]); + n = op_nb_args[c]; + fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]); + for(i = 0; i < n; i++) { + fprintf(logfile, " 0x%x", opparam_ptr[i]); + } + fprintf(logfile, "\n"); if (c == INDEX_op_end) break; + opparam_ptr += n; } } @@ -3547,6 +3570,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; + dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; @@ -3610,7 +3634,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, fprintf(logfile, "\n"); fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf); + dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); } #endif @@ -3621,7 +3645,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "AFTER FLAGS OPT:\n"); - dump_ops(gen_opc_buf); + dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); } #endif @@ -3683,8 +3707,8 @@ CPUX86State *cpu_x86_init(void) for(i = 0;i < 8; i++) env->fptags[i] = 1; env->fpuc = 0x37f; - /* flags setup */ - env->eflags = 0; + /* flags setup : we activate the IRQs by default as in user mode */ + env->eflags = 0x2 | IF_MASK; /* init various static tables */ if (!inited) { -- cgit v1.2.3 From fc2b4c4879955829430f33bf262e7eab93c6173a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:52:44 +0000 Subject: eflags update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@56 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 34 ++++++++++++++++++++-------------- exec-i386.c | 11 ++++++----- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index 700370e71..4eeb6be88 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -48,6 +48,7 @@ #define R_FS 4 #define R_GS 5 +/* eflags masks */ #define CC_C 0x0001 #define CC_P 0x0004 #define CC_A 0x0010 @@ -55,15 +56,17 @@ #define CC_S 0x0080 #define CC_O 0x0800 -#define TRAP_FLAG 0x0100 -#define INTERRUPT_FLAG 0x0200 -#define DIRECTION_FLAG 0x0400 -#define IOPL_FLAG_MASK 0x3000 -#define NESTED_FLAG 0x4000 -#define BYTE_FL 0x8000 /* Intel reserved! */ -#define RF_FLAG 0x10000 -#define VM_FLAG 0x20000 -/* AC 0x40000 */ +#define TF_MASK 0x00000100 +#define IF_MASK 0x00000200 +#define DF_MASK 0x00000400 +#define IOPL_MASK 0x00003000 +#define NT_MASK 0x00004000 +#define RF_MASK 0x00010000 +#define VM_MASK 0x00020000 +#define AC_MASK 0x00040000 +#define VIF_MASK 0x00080000 +#define VIP_MASK 0x00100000 +#define ID_MASK 0x00200000 #define EXCP00_DIVZ 1 #define EXCP01_SSTP 2 @@ -158,7 +161,9 @@ typedef struct CPUX86State { /* standard registers */ uint32_t regs[8]; uint32_t eip; - uint32_t eflags; + uint32_t eflags; /* eflags register. During CPU emulation, CC + flags and DF are set to zero because they are + store elsewhere */ /* emulator internal eflags handling */ uint32_t cc_src; @@ -183,13 +188,13 @@ typedef struct CPUX86State { SegmentDescriptorTable ldt; SegmentDescriptorTable idt; - /* various CPU modes */ - int vm86; - /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; int interrupt_request; + + /* user data */ + void *opaque; } CPUX86State; /* all CPU memory access use these macros */ @@ -418,7 +423,8 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, #define GEN_FLAG_CODE32_SHIFT 0 #define GEN_FLAG_ADDSEG_SHIFT 1 #define GEN_FLAG_SS32_SHIFT 2 -#define GEN_FLAG_ST_SHIFT 3 +#define GEN_FLAG_VM_SHIFT 3 +#define GEN_FLAG_ST_SHIFT 4 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, diff --git a/exec-i386.c b/exec-i386.c index 5dbe7fa53..f59e1ccec 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -330,9 +330,10 @@ int cpu_x86_exec(CPUX86State *env1) #endif /* put eflags in CPU temporary format */ - T0 = env->eflags; - op_movl_eflags_T0(); + CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((env->eflags >> 10) & 1)); CC_OP = CC_OP_EFLAGS; + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); env->interrupt_request = 0; /* prepare setjmp context for exception handling */ @@ -354,6 +355,7 @@ int cpu_x86_exec(CPUX86State *env1) (unsigned long)env->seg_cache[R_ES].base | (unsigned long)env->seg_cache[R_SS].base) != 0) << GEN_FLAG_ADDSEG_SHIFT; + flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT); cs_base = env->seg_cache[R_CS].base; pc = cs_base + env->eip; tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, @@ -390,8 +392,7 @@ int cpu_x86_exec(CPUX86State *env1) ret = env->exception_index; /* restore flags in standard format */ - op_movl_T0_eflags(); - env->eflags = T0; + env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); /* restore global registers */ #ifdef reg_EAX @@ -489,7 +490,7 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, /* for glibc 2.1 */ #define REG_EIP EIP #endif - pc = uc->uc_mcontext.gregs[EIP]; + pc = uc->uc_mcontext.gregs[REG_EIP]; pold_set = &uc->uc_sigmask; return handle_cpu_signal(pc, pold_set); #else -- cgit v1.2.3 From 851e67a1b46ff7999a7585d682f8add983e82fc9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:53:14 +0000 Subject: primitive vm86 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@57 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 108 +++++++++++++++++++++++++++++++++++++++++++++--------- linux-user/qemu.h | 27 ++++++++++++++ 2 files changed, 117 insertions(+), 18 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 31743253b..c12ef0f18 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -104,35 +104,99 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit, uint64_t gdt_table[6]; +//#define DEBUG_VM86 + void cpu_loop(struct CPUX86State *env) { int err; uint8_t *pc; target_siginfo_t info; - + for(;;) { err = cpu_x86_exec(env); pc = env->seg_cache[R_CS].base + env->eip; switch(err) { case EXCP0D_GPF: - if (pc[0] == 0xcd && pc[1] == 0x80) { - /* syscall */ - env->eip += 2; - env->regs[R_EAX] = do_syscall(env, - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP]); + if (env->eflags & VM_MASK) { + TaskState *ts; + int ret; +#ifdef DEBUG_VM86 + printf("VM86 exception %04x:%08x %02x\n", + env->segs[R_CS], env->eip, pc[0]); +#endif + /* VM86 mode */ + ts = env->opaque; + + /* XXX: add all cases */ + switch(pc[0]) { + case 0xcd: /* int */ + env->eip += 2; + ret = TARGET_VM86_INTx | (pc[1] << 8); + break; + default: + /* real VM86 GPF exception */ + ret = TARGET_VM86_UNKNOWN; + break; + } +#ifdef DEBUG_VM86 + printf("ret=0x%x\n", ret); +#endif + /* put the VM86 registers in the userspace register structure */ + ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); + ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); + ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); + ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); + ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); + ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); + ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); + ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); + ts->target_v86->regs.eip = tswap32(env->eip); + ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); + ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); + ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); + ts->target_v86->regs.es = tswap16(env->segs[R_ES]); + ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); + ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); + + /* restore 32 bit registers */ + env->regs[R_EBX] = ts->vm86_saved_regs.ebx; + env->regs[R_ECX] = ts->vm86_saved_regs.ecx; + env->regs[R_EDX] = ts->vm86_saved_regs.edx; + env->regs[R_ESI] = ts->vm86_saved_regs.esi; + env->regs[R_EDI] = ts->vm86_saved_regs.edi; + env->regs[R_EBP] = ts->vm86_saved_regs.ebp; + env->regs[R_ESP] = ts->vm86_saved_regs.esp; + env->eflags = ts->vm86_saved_regs.eflags; + env->eip = ts->vm86_saved_regs.eip; + + cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); + cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); + cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); + cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); + cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); + cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); + + env->regs[R_EAX] = ret; } else { - /* XXX: more precise info */ - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = 0; - info._sifields._sigfault._addr = 0; - queue_signal(info.si_signo, &info); + if (pc[0] == 0xcd && pc[1] == 0x80) { + /* syscall */ + env->eip += 2; + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP]); + } else { + /* XXX: more precise info */ + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = 0; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); + } } break; case EXCP00_DIVZ: @@ -188,12 +252,15 @@ void usage(void) /* XXX: currently only used for async signals (see signal.c) */ CPUX86State *global_env; +/* used to free thread contexts */ +TaskState *first_task_state; int main(int argc, char **argv) { const char *filename; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; + TaskState ts1, *ts = &ts1; CPUX86State *env; int optind; const char *r; @@ -272,6 +339,11 @@ int main(int argc, char **argv) env = cpu_x86_init(); global_env = env; + /* build Task State */ + memset(ts, 0, sizeof(TaskState)); + env->opaque = ts; + ts->used = 1; + /* linux register setup */ env->regs[R_EAX] = regs->eax; env->regs[R_EBX] = regs->ebx; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index d4d93a429..54b38e70e 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -33,6 +33,33 @@ struct image_info { int personality; }; +/* Information about the current linux thread */ +struct vm86_saved_state { + uint32_t eax; /* return code */ + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t esp; + uint32_t eflags; + uint32_t eip; + uint16_t cs, ss, ds, es, fs, gs; +}; + +/* NOTE: we force a big alignment so that the stack stored after is + aligned too */ +typedef struct TaskState { + struct TaskState *next; + struct target_vm86plus_struct *target_v86; + struct vm86_saved_state vm86_saved_regs; + int used; /* non zero if used */ + uint8_t stack[0]; +} __attribute__((aligned(16))) TaskState; + +extern TaskState *first_task_state; + int elf_exec(const char *interp_prefix, const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); -- cgit v1.2.3 From d1f2367bc00099e9782891fd57cab2ebcf977fda Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:53:34 +0000 Subject: changed flag names git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@58 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 72b2f7992..04779c82c 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -570,8 +570,6 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) return (void *)((esp - frame_size) & -8ul); } -#define TF_MASK TRAP_FLAG - static void setup_frame(int sig, struct emulated_sigaction *ka, target_sigset_t *set, CPUX86State *env) { -- cgit v1.2.3 From 7ed601b782cbcaf0cddff6c5725712e47972f26d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:54:05 +0000 Subject: more syscalls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@59 c046a42c-6fe2-441c-8c8c-71466251a162 --- syscall-i386.h | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/syscall-i386.h b/syscall-i386.h index 5878ccdd9..dc769b7ed 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -237,6 +237,36 @@ #define TARGET_NR_removexattr 235 #define TARGET_NR_lremovexattr 236 #define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_set_thread_area 243 +#define TARGET_NR_get_thread_area 244 +#define TARGET_NR_io_setup 245 +#define TARGET_NR_io_destroy 246 +#define TARGET_NR_io_getevents 247 +#define TARGET_NR_io_submit 248 +#define TARGET_NR_io_cancel 249 +#define TARGET_NR_fadvise64 250 + +#define TARGET_NR_exit_group 252 +#define TARGET_NR_lookup_dcookie 253 +#define TARGET_NR_epoll_create 254 +#define TARGET_NR_epoll_ctl 255 +#define TARGET_NR_epoll_wait 256 +#define TARGET_NR_remap_file_pages 257 +#define TARGET_NR_set_tid_address 258 +#define TARGET_NR_timer_create 259 +#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) +#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) +#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) +#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) +#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) +#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) +#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) +#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) #define TARGET_SIG_BLOCK 0 /* for blocking signals */ #define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */ @@ -714,6 +744,10 @@ struct target_termios { #define TARGET_LDT_ENTRIES 8192 #define TARGET_LDT_ENTRY_SIZE 8 +#define TARGET_GDT_ENTRY_TLS_ENTRIES 3 +#define TARGET_GDT_ENTRY_TLS_MIN 6 +#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1) + struct target_modify_ldt_ldt_s { unsigned int entry_number; target_ulong base_addr; @@ -721,6 +755,182 @@ struct target_modify_ldt_ldt_s { unsigned int flags; }; +#define TARGET_VM86_SIGNAL 0 /* return due to signal */ +#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ +#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */ +#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */ + +/* + * Additional return values when invoking new vm86() + */ +#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */ +#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */ + +/* + * function codes when invoking new vm86() + */ +#define TARGET_VM86_PLUS_INSTALL_CHECK 0 +#define TARGET_VM86_ENTER 1 +#define TARGET_VM86_ENTER_NO_BYPASS 2 +#define TARGET_VM86_REQUEST_IRQ 3 +#define TARGET_VM86_FREE_IRQ 4 +#define TARGET_VM86_GET_IRQ_BITS 5 +#define TARGET_VM86_GET_AND_RESET_IRQ 6 + +/* + * This is the stack-layout seen by the user space program when we have + * done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout + * is 'kernel_vm86_regs' (see below). + */ + +struct target_vm86_regs { +/* + * normal regs, with special meaning for the segment descriptors.. + */ + target_long ebx; + target_long ecx; + target_long edx; + target_long esi; + target_long edi; + target_long ebp; + target_long eax; + target_long __null_ds; + target_long __null_es; + target_long __null_fs; + target_long __null_gs; + target_long orig_eax; + target_long eip; + unsigned short cs, __csh; + target_long eflags; + target_long esp; + unsigned short ss, __ssh; +/* + * these are specific to v86 mode: + */ + unsigned short es, __esh; + unsigned short ds, __dsh; + unsigned short fs, __fsh; + unsigned short gs, __gsh; +}; + +struct target_revectored_struct { + target_ulong __map[8]; /* 256 bits */ +}; + +struct target_vm86_struct { + struct target_vm86_regs regs; + target_ulong flags; + target_ulong screen_bitmap; + target_ulong cpu_type; + struct target_revectored_struct int_revectored; + struct target_revectored_struct int21_revectored; +}; + +/* + * flags masks + */ +#define TARGET_VM86_SCREEN_BITMAP 0x0001 + +struct target_vm86plus_info_struct { + target_ulong flags; +#define TARGET_force_return_for_pic (1 << 0) +#define TARGET_vm86dbg_active (1 << 1) /* for debugger */ +#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */ +#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */ + unsigned char vm86dbg_intxxtab[32]; /* for debugger */ +}; + +struct target_vm86plus_struct { + struct target_vm86_regs regs; + target_ulong flags; + target_ulong screen_bitmap; + target_ulong cpu_type; + struct target_revectored_struct int_revectored; + struct target_revectored_struct int21_revectored; + struct target_vm86plus_info_struct vm86plus; +}; + +/* ipcs */ + +#define TARGET_SEMOP 1 +#define TARGET_SEMGET 2 +#define TARGET_SEMCTL 3 +#define TARGET_MSGSND 11 +#define TARGET_MSGRCV 12 +#define TARGET_MSGGET 13 +#define TARGET_MSGCTL 14 +#define TARGET_SHMAT 21 +#define TARGET_SHMDT 22 +#define TARGET_SHMGET 23 +#define TARGET_SHMCTL 24 + +struct target_msgbuf { + int mtype; + char mtext[1]; +}; + +struct target_ipc_kludge { + unsigned int msgp; /* Really (struct msgbuf *) */ + int msgtyp; +}; + +struct alpha_msgbuf { + long mtype; + char mtext[4096]; +}; + +struct target_ipc_perm { + int key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +struct target_msqid_ds { + struct target_ipc_perm msg_perm; + unsigned int msg_first; /* really struct target_msg* */ + unsigned int msg_last; /* really struct target_msg* */ + unsigned int msg_stime; /* really target_time_t */ + unsigned int msg_rtime; /* really target_time_t */ + unsigned int msg_ctime; /* really target_time_t */ + unsigned int wwait; /* really struct wait_queue* */ + unsigned int rwait; /* really struct wait_queue* */ + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + unsigned short msg_lspid; + unsigned short msg_lrpid; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; + int shm_segsz; + unsigned int shm_atime; /* really target_time_t */ + unsigned int shm_dtime; /* really target_time_t */ + unsigned int shm_ctime; /* really target_time_t */ + unsigned short shm_cpid; + unsigned short shm_lpid; + short shm_nattch; + unsigned short shm_npages; + unsigned long *shm_pages; + void *attaches; /* really struct shm_desc * */ +}; + +#define TARGET_IPC_RMID 0 +#define TARGET_IPC_SET 1 +#define TARGET_IPC_STAT 2 + +union target_semun { + int val; + unsigned int buf; /* really struct semid_ds * */ + unsigned int array; /* really unsigned short * */ + unsigned int __buf; /* really struct seminfo * */ + unsigned int __pad; /* really void* */ +}; + /* soundcard defines (XXX: move them to generic file syscall_defs.h) */ #define TARGET_SNDCTL_COPR_HALT 0xc0144307 -- cgit v1.2.3 From 5cd4393b14b68a4e80a3ffa74c04efff2b9590a5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:54:36 +0000 Subject: first vm86 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@60 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 195 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 162 insertions(+), 33 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f0f790f5f..2d8804e12 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -103,10 +103,10 @@ extern int personality(int); extern int flock(int, int); extern int setfsuid(int); extern int setfsgid(int); -extern int setresuid(int,int,int); -extern int getresuid(int *,int *,int *); -extern int setresgid(int,int,int); -extern int getresgid(int *,int *,int *); +extern int setresuid(uid_t, uid_t, uid_t); +extern int getresuid(uid_t *, uid_t *, uid_t *); +extern int setresgid(gid_t, gid_t, gid_t); +extern int getresgid(gid_t *, gid_t *, gid_t *); static inline long get_errno(long ret) { @@ -210,14 +210,14 @@ static inline void host_to_target_fds(target_long *target_fds, } static inline void target_to_host_timeval(struct timeval *tv, - struct target_timeval *target_tv) + const struct target_timeval *target_tv) { tv->tv_sec = tswapl(target_tv->tv_sec); tv->tv_usec = tswapl(target_tv->tv_usec); } static inline void host_to_target_timeval(struct target_timeval *target_tv, - struct timeval *tv) + const struct timeval *tv) { target_tv->tv_sec = tswapl(tv->tv_sec); target_tv->tv_usec = tswapl(tv->tv_usec); @@ -238,8 +238,7 @@ static long do_select(long n, efds_ptr = target_to_host_fds(&efds, target_efds, n); if (target_tv) { - tv.tv_sec = tswapl(target_tv->tv_sec); - tv.tv_usec = tswapl(target_tv->tv_usec); + target_to_host_timeval(&tv, target_tv); tv_ptr = &tv; } else { tv_ptr = NULL; @@ -251,8 +250,7 @@ static long do_select(long n, host_to_target_fds(target_efds, efds_ptr, n); if (target_tv) { - target_tv->tv_sec = tswapl(tv.tv_sec); - target_tv->tv_usec = tswapl(tv.tv_usec); + host_to_target_timeval(target_tv, &tv); } } return ret; @@ -755,7 +753,7 @@ install: } /* specific and weird i386 syscalls */ -int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount) +int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount) { int ret = -ENOSYS; @@ -773,6 +771,79 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou return ret; } +/* vm86 emulation */ + +#define SAFE_MASK (0xDD5) + +int do_vm86(CPUX86State *env, long subfunction, + struct target_vm86plus_struct * target_v86) +{ + TaskState *ts = env->opaque; + int ret; + + switch (subfunction) { + case TARGET_VM86_REQUEST_IRQ: + case TARGET_VM86_FREE_IRQ: + case TARGET_VM86_GET_IRQ_BITS: + case TARGET_VM86_GET_AND_RESET_IRQ: + gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction); + ret = -EINVAL; + goto out; + case TARGET_VM86_PLUS_INSTALL_CHECK: + /* NOTE: on old vm86 stuff this will return the error + from verify_area(), because the subfunction is + interpreted as (invalid) address to vm86_struct. + So the installation check works. + */ + ret = 0; + goto out; + } + + ts->target_v86 = target_v86; + + /* save current CPU regs */ + ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ + ts->vm86_saved_regs.ebx = env->regs[R_EBX]; + ts->vm86_saved_regs.ecx = env->regs[R_ECX]; + ts->vm86_saved_regs.edx = env->regs[R_EDX]; + ts->vm86_saved_regs.esi = env->regs[R_ESI]; + ts->vm86_saved_regs.edi = env->regs[R_EDI]; + ts->vm86_saved_regs.ebp = env->regs[R_EBP]; + ts->vm86_saved_regs.esp = env->regs[R_ESP]; + ts->vm86_saved_regs.eflags = env->eflags; + ts->vm86_saved_regs.eip = env->eip; + ts->vm86_saved_regs.cs = env->segs[R_CS]; + ts->vm86_saved_regs.ss = env->segs[R_SS]; + ts->vm86_saved_regs.ds = env->segs[R_DS]; + ts->vm86_saved_regs.es = env->segs[R_ES]; + ts->vm86_saved_regs.fs = env->segs[R_FS]; + ts->vm86_saved_regs.gs = env->segs[R_GS]; + + /* build vm86 CPU state */ + env->eflags = (env->eflags & ~SAFE_MASK) | + (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; + + env->regs[R_EBX] = tswap32(target_v86->regs.ebx); + env->regs[R_ECX] = tswap32(target_v86->regs.ecx); + env->regs[R_EDX] = tswap32(target_v86->regs.edx); + env->regs[R_ESI] = tswap32(target_v86->regs.esi); + env->regs[R_EDI] = tswap32(target_v86->regs.edi); + env->regs[R_EBP] = tswap32(target_v86->regs.ebp); + env->regs[R_ESP] = tswap32(target_v86->regs.esp); + env->eip = tswap32(target_v86->regs.eip); + cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs)); + cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss)); + cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds)); + cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es)); + cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs)); + cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); + ret = tswap32(target_v86->regs.eax); /* eax will be restored at + the end of the syscall */ + /* now the virtual CPU is ready for vm86 execution ! */ + out: + return ret; +} + /* this stack is the equivalent of the kernel stack associated with a thread/process */ #define NEW_STACK_SIZE 8192 @@ -788,19 +859,26 @@ static int clone_func(void *arg) int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) { int ret; + TaskState *ts; uint8_t *new_stack; CPUX86State *new_env; if (flags & CLONE_VM) { if (!newsp) newsp = env->regs[R_ESP]; - new_stack = malloc(NEW_STACK_SIZE); - + ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); + memset(ts, 0, sizeof(TaskState)); + new_stack = ts->stack; + ts->used = 1; + /* add in task state list */ + ts->next = first_task_state; + first_task_state = ts; /* we create a new CPU instance. */ new_env = cpu_x86_init(); memcpy(new_env, env, sizeof(CPUX86State)); new_env->regs[R_ESP] = newsp; new_env->regs[R_EAX] = 0; + new_env->opaque = ts; ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); } else { /* if no CLONE_VM, we consider it is a fork */ @@ -1281,8 +1359,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct timeval tv; ret = get_errno(gettimeofday(&tv, NULL)); if (!is_error(ret)) { - target_tv->tv_sec = tswapl(tv.tv_sec); - target_tv->tv_usec = tswapl(tv.tv_usec); + host_to_target_timeval(target_tv, &tv); } } break; @@ -1290,8 +1367,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { struct target_timeval *target_tv = (void *)arg1; struct timeval tv; - tv.tv_sec = tswapl(target_tv->tv_sec); - tv.tv_usec = tswapl(target_tv->tv_usec); + target_to_host_timeval(&tv, target_tv); ret = get_errno(settimeofday(&tv, NULL)); } break; @@ -1487,8 +1563,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_idle: goto unimplemented; - case TARGET_NR_vm86old: - goto unimplemented; case TARGET_NR_wait4: { int status; @@ -1548,7 +1622,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #ifdef TARGET_I386 case TARGET_NR_modify_ldt: - ret = get_errno(gemu_modify_ldt(cpu_env, arg1, (void *)arg2, arg3)); + ret = get_errno(do_modify_ldt(cpu_env, arg1, (void *)arg2, arg3)); + break; + case TARGET_NR_vm86old: + goto unimplemented; + case TARGET_NR_vm86: + ret = do_vm86(cpu_env, arg1, (void *)arg2); break; #endif case TARGET_NR_adjtimex: @@ -1652,13 +1731,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, pfd = alloca(sizeof(struct pollfd) * nfds); for(i = 0; i < nfds; i++) { - pfd->fd = tswap32(target_pfd->fd); - pfd->events = tswap16(target_pfd->events); + pfd[i].fd = tswap32(target_pfd[i].fd); + pfd[i].events = tswap16(target_pfd[i].events); } ret = get_errno(poll(pfd, nfds, timeout)); if (!is_error(ret)) { for(i = 0; i < nfds; i++) { - target_pfd->revents = tswap16(pfd->revents); + target_pfd[i].revents = tswap16(pfd[i].revents); } } } @@ -1702,25 +1781,59 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(getsid(arg1)); break; case TARGET_NR_fdatasync: - goto unimplemented; + ret = get_errno(fdatasync(arg1)); + break; case TARGET_NR__sysctl: goto unimplemented; case TARGET_NR_sched_setparam: - goto unimplemented; + { + struct sched_param *target_schp = (void *)arg2; + struct sched_param schp; + schp.sched_priority = tswap32(target_schp->sched_priority); + ret = get_errno(sched_setparam(arg1, &schp)); + } + break; case TARGET_NR_sched_getparam: - goto unimplemented; + { + struct sched_param *target_schp = (void *)arg2; + struct sched_param schp; + ret = get_errno(sched_getparam(arg1, &schp)); + if (!is_error(ret)) { + target_schp->sched_priority = tswap32(schp.sched_priority); + } + } + break; case TARGET_NR_sched_setscheduler: - goto unimplemented; + { + struct sched_param *target_schp = (void *)arg3; + struct sched_param schp; + schp.sched_priority = tswap32(target_schp->sched_priority); + ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); + } + break; case TARGET_NR_sched_getscheduler: - goto unimplemented; + ret = get_errno(sched_getscheduler(arg1)); + break; case TARGET_NR_sched_yield: ret = get_errno(sched_yield()); break; case TARGET_NR_sched_get_priority_max: + ret = get_errno(sched_get_priority_max(arg1)); + break; case TARGET_NR_sched_get_priority_min: + ret = get_errno(sched_get_priority_min(arg1)); + break; case TARGET_NR_sched_rr_get_interval: - goto unimplemented; - + { + struct target_timespec *target_ts = (void *)arg2; + struct timespec ts; + ret = get_errno(sched_rr_get_interval(arg1, &ts)); + if (!is_error(ret)) { + target_ts->tv_sec = tswapl(ts.tv_sec); + target_ts->tv_nsec = tswapl(ts.tv_nsec); + } + } + break; case TARGET_NR_nanosleep: { struct target_timespec *target_req = (void *)arg1; @@ -1767,11 +1880,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; - case TARGET_NR_vm86: case TARGET_NR_query_module: + goto unimplemented; case TARGET_NR_nfsservctl: + goto unimplemented; case TARGET_NR_prctl: + goto unimplemented; case TARGET_NR_pread: + goto unimplemented; case TARGET_NR_pwrite: goto unimplemented; case TARGET_NR_chown: @@ -1781,16 +1897,24 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(sys_getcwd1((char *)arg1, arg2)); break; case TARGET_NR_capget: + goto unimplemented; case TARGET_NR_capset: + goto unimplemented; case TARGET_NR_sigaltstack: + goto unimplemented; case TARGET_NR_sendfile: + goto unimplemented; case TARGET_NR_getpmsg: + goto unimplemented; case TARGET_NR_putpmsg: + goto unimplemented; case TARGET_NR_vfork: ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); break; case TARGET_NR_ugetrlimit: + goto unimplemented; case TARGET_NR_truncate64: + goto unimplemented; case TARGET_NR_ftruncate64: goto unimplemented; case TARGET_NR_stat64: @@ -1919,6 +2043,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(gettid()); break; case TARGET_NR_readahead: + goto unimplemented; case TARGET_NR_setxattr: case TARGET_NR_lsetxattr: case TARGET_NR_fsetxattr: @@ -1931,10 +2056,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_removexattr: case TARGET_NR_lremovexattr: case TARGET_NR_fremovexattr: - goto unimplemented; + goto unimplemented_nowarn; + case TARGET_NR_set_thread_area: + case TARGET_NR_get_thread_area: + goto unimplemented_nowarn; default: unimplemented: - gemu_log("gemu: Unsupported syscall: %d\n", num); + gemu_log("qemu: Unsupported syscall: %d\n", num); + unimplemented_nowarn: ret = -ENOSYS; break; } -- cgit v1.2.3 From 168485b75bfa0bd543412039c37967de93cf06b1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:57:34 +0000 Subject: wine help git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@61 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 8afdbe0b9..3bb043be4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -102,11 +102,39 @@ unset LD_LIBRARY_PATH Then you can launch the precompiled @file{ls} x86 executable: @example -qemu /usr/local/qemu-i386/bin/ls +qemu /usr/local/qemu-i386/bin/ls-i386 +@end example +You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that +QEMU is automatically launched by the Linux kernel when you try to +launch x86 executables. It requires the @code{binfmt_misc} module in the +Linux kernel. + +@end itemize + +@section Wine launch (Currently only tested when emulating x86 on x86) + +@itemize + +@item Ensure that you have a working QEMU with the x86 glibc +distribution (see previous section). In order to verify it, you must be +able to do: + +@example +qemu /usr/local/qemu-i386/bin/ls-i386 +@end example + +@item Download the binary x86 wine install +(@file{qemu-i386-wine.tar.gz} on the QEMU web page). + +@item Configure wine on your account. Look at the provided script +@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous +@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}. + +@item Then you can try the example @file{putty.exe}: + +@example +qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe @end example -You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that QEMU is automatically -launched by the Linux kernel when you try to launch x86 executables. It -requires the @code{binfmt_misc} module in the Linux kernel. @end itemize -- cgit v1.2.3 From f6630e791b96ea97e65e2a265892310c2bde93ce Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:57:48 +0000 Subject: version git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@62 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 17e51c385..7693c96bf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.1 +0.1.3 \ No newline at end of file -- cgit v1.2.3 From 500dab07e88b471f4ab4cb69330a5c6738182de4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 16:58:09 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@63 c046a42c-6fe2-441c-8c8c-71466251a162 --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 64fe7e937..dfd137f41 100644 --- a/README +++ b/README @@ -30,7 +30,7 @@ LD_LIBRARY_PATH is not set: Then you can launch the precompiled 'ls' x86 executable: - ./qemu /usr/local/qemu-i386/bin/ls + ./qemu /usr/local/qemu-i386/bin/ls-i386 You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is automatically launched by the Linux kernel when you try to launch x86 -- cgit v1.2.3 From 7854b05654b49c2197faef358e3ec1a7559797b9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 17:22:23 +0000 Subject: endian fixes by Ulrich weigand git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@64 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 405 +++++++++++++++++++++++++++++++++++++++------- linux-user/syscall_defs.h | 42 +++++ syscall-i386.h | 12 +- 3 files changed, 399 insertions(+), 60 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2d8804e12..befc08dd3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include //#include +#include #define termios host_termios #define winsize host_winsize @@ -166,7 +168,7 @@ static long do_brk(char *new_brk) static inline fd_set *target_to_host_fds(fd_set *fds, target_long *target_fds, int n) { -#if !defined(BSWP_NEEDED) && !defined(WORD_BIGENDIAN) +#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) return (fd_set *)target_fds; #else int i, b; @@ -188,7 +190,7 @@ static inline fd_set *target_to_host_fds(fd_set *fds, static inline void host_to_target_fds(target_long *target_fds, fd_set *fds, int n) { -#if !defined(BSWP_NEEDED) && !defined(WORD_BIGENDIAN) +#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) /* nothing to do */ #else int i, nw, j, k; @@ -256,55 +258,267 @@ static long do_select(long n, return ret; } -static long do_socketcall(int num, long *vptr) +static inline void target_to_host_sockaddr(struct sockaddr *addr, + struct target_sockaddr *target_addr, + socklen_t len) +{ + memcpy(addr, target_addr, len); + addr->sa_family = tswap16(target_addr->sa_family); +} + +static inline void host_to_target_sockaddr(struct target_sockaddr *target_addr, + struct sockaddr *addr, + socklen_t len) +{ + memcpy(target_addr, addr, len); + target_addr->sa_family = tswap16(addr->sa_family); +} + +static inline void target_to_host_cmsg(struct msghdr *msgh, + struct target_msghdr *target_msgh) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); + struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); + socklen_t space = 0; + + while (cmsg && target_cmsg) { + void *data = CMSG_DATA(cmsg); + void *target_data = TARGET_CMSG_DATA(target_cmsg); + + int len = tswapl(target_cmsg->cmsg_len) + - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr)); + + space += CMSG_SPACE(len); + if (space > msgh->msg_controllen) { + space -= CMSG_SPACE(len); + gemu_log("Host cmsg overflow"); + break; + } + + cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level); + cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type); + cmsg->cmsg_len = CMSG_LEN(len); + + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(data, target_data, len); + } else { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); + + for (i = 0; i < numfds; i++) + fd[i] = tswap32(target_fd[i]); + } + + cmsg = CMSG_NXTHDR(msgh, cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + } + + msgh->msg_controllen = space; +} + +static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, + struct msghdr *msgh) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); + struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); + socklen_t space = 0; + + while (cmsg && target_cmsg) { + void *data = CMSG_DATA(cmsg); + void *target_data = TARGET_CMSG_DATA(target_cmsg); + + int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr)); + + space += TARGET_CMSG_SPACE(len); + if (space > tswapl(target_msgh->msg_controllen)) { + space -= TARGET_CMSG_SPACE(len); + gemu_log("Target cmsg overflow"); + break; + } + + target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level); + target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); + target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len)); + + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(target_data, data, len); + } else { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); + + for (i = 0; i < numfds; i++) + target_fd[i] = tswap32(fd[i]); + } + + cmsg = CMSG_NXTHDR(msgh, cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + } + + msgh->msg_controllen = tswapl(space); +} + +static long do_setsockopt(int sockfd, int level, int optname, + void *optval, socklen_t optlen) +{ + if (level == SOL_TCP) { + /* TCP options all take an 'int' value. */ + int val; + + if (optlen < sizeof(uint32_t)) + return -EINVAL; + + val = tswap32(*(uint32_t *)optval); + return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + } + + else if (level != SOL_SOCKET) { + gemu_log("Unsupported setsockopt level: %d\n", level); + return -ENOSYS; + } + + switch (optname) { + /* Options with 'int' argument. */ + case SO_DEBUG: + case SO_REUSEADDR: + case SO_TYPE: + case SO_ERROR: + case SO_DONTROUTE: + case SO_BROADCAST: + case SO_SNDBUF: + case SO_RCVBUF: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case SO_NO_CHECK: + case SO_PRIORITY: + case SO_BSDCOMPAT: + case SO_PASSCRED: + case SO_TIMESTAMP: + case SO_RCVLOWAT: + case SO_RCVTIMEO: + case SO_SNDTIMEO: + { + int val; + if (optlen < sizeof(uint32_t)) + return -EINVAL; + val = tswap32(*(uint32_t *)optval); + return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + } + + default: + gemu_log("Unsupported setsockopt SOL_SOCKET option: %d\n", optname); + return -ENOSYS; + } +} + +static long do_getsockopt(int sockfd, int level, int optname, + void *optval, socklen_t *optlen) +{ + gemu_log("getsockopt not yet supported\n"); + return -ENOSYS; +} + +static long do_socketcall(int num, int32_t *vptr) { long ret; switch(num) { case SOCKOP_socket: - ret = get_errno(socket(vptr[0], vptr[1], vptr[2])); + { + int domain = tswap32(vptr[0]); + int type = tswap32(vptr[1]); + int protocol = tswap32(vptr[2]); + + ret = get_errno(socket(domain, type, protocol)); + } break; case SOCKOP_bind: - ret = get_errno(bind(vptr[0], (struct sockaddr *)vptr[1], vptr[2])); + { + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + socklen_t addrlen = tswap32(vptr[2]); + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(bind(sockfd, addr, addrlen)); + } break; case SOCKOP_connect: - ret = get_errno(connect(vptr[0], (struct sockaddr *)vptr[1], vptr[2])); + { + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + socklen_t addrlen = tswap32(vptr[2]); + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(connect(sockfd, addr, addrlen)); + } break; case SOCKOP_listen: - ret = get_errno(listen(vptr[0], vptr[1])); + { + int sockfd = tswap32(vptr[0]); + int backlog = tswap32(vptr[1]); + + ret = get_errno(listen(sockfd, backlog)); + } break; case SOCKOP_accept: { - socklen_t size; - size = tswap32(*(int32_t *)vptr[2]); - ret = get_errno(accept(vptr[0], (struct sockaddr *)vptr[1], &size)); - if (!is_error(ret)) - *(int32_t *)vptr[2] = size; + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + uint32_t *target_addrlen = (void *)tswap32(vptr[2]); + socklen_t addrlen = tswap32(*target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(accept(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + *target_addrlen = tswap32(addrlen); + } } break; case SOCKOP_getsockname: { - socklen_t size; - size = tswap32(*(int32_t *)vptr[2]); - ret = get_errno(getsockname(vptr[0], (struct sockaddr *)vptr[1], &size)); - if (!is_error(ret)) - *(int32_t *)vptr[2] = size; + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + uint32_t *target_addrlen = (void *)tswap32(vptr[2]); + socklen_t addrlen = tswap32(*target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(getsockname(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + *target_addrlen = tswap32(addrlen); + } } break; case SOCKOP_getpeername: { - socklen_t size; - size = tswap32(*(int32_t *)vptr[2]); - ret = get_errno(getpeername(vptr[0], (struct sockaddr *)vptr[1], &size)); - if (!is_error(ret)) - *(int32_t *)vptr[2] = size; + int sockfd = tswap32(vptr[0]); + void *target_addr = (void *)tswap32(vptr[1]); + uint32_t *target_addrlen = (void *)tswap32(vptr[2]); + socklen_t addrlen = tswap32(*target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(getpeername(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + *target_addrlen = tswap32(addrlen); + } } break; case SOCKOP_socketpair: { + int domain = tswap32(vptr[0]); + int type = tswap32(vptr[1]); + int protocol = tswap32(vptr[2]); + int32_t *target_tab = (void *)tswap32(vptr[3]); int tab[2]; - int32_t *target_tab = (int32_t *)vptr[3]; - ret = get_errno(socketpair(vptr[0], vptr[1], vptr[2], tab)); + + ret = get_errno(socketpair(domain, type, protocol, tab)); if (!is_error(ret)) { target_tab[0] = tswap32(tab[0]); target_tab[1] = tswap32(tab[1]); @@ -312,27 +526,64 @@ static long do_socketcall(int num, long *vptr) } break; case SOCKOP_send: - ret = get_errno(send(vptr[0], (void *)vptr[1], vptr[2], vptr[3])); + { + int sockfd = tswap32(vptr[0]); + void *msg = (void *)tswap32(vptr[1]); + size_t len = tswap32(vptr[2]); + int flags = tswap32(vptr[3]); + + ret = get_errno(send(sockfd, msg, len, flags)); + } break; case SOCKOP_recv: - ret = get_errno(recv(vptr[0], (void *)vptr[1], vptr[2], vptr[3])); + { + int sockfd = tswap32(vptr[0]); + void *msg = (void *)tswap32(vptr[1]); + size_t len = tswap32(vptr[2]); + int flags = tswap32(vptr[3]); + + ret = get_errno(recv(sockfd, msg, len, flags)); + } break; case SOCKOP_sendto: - ret = get_errno(sendto(vptr[0], (void *)vptr[1], vptr[2], vptr[3], - (struct sockaddr *)vptr[4], vptr[5])); + { + int sockfd = tswap32(vptr[0]); + void *msg = (void *)tswap32(vptr[1]); + size_t len = tswap32(vptr[2]); + int flags = tswap32(vptr[3]); + void *target_addr = (void *)tswap32(vptr[4]); + socklen_t addrlen = tswap32(vptr[5]); + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(sendto(sockfd, msg, len, flags, addr, addrlen)); + } break; case SOCKOP_recvfrom: { - socklen_t size; - size = tswap32(*(int32_t *)vptr[5]); - ret = get_errno(recvfrom(vptr[0], (void *)vptr[1], vptr[2], - vptr[3], (struct sockaddr *)vptr[4], &size)); - if (!is_error(ret)) - *(int32_t *)vptr[5] = size; + int sockfd = tswap32(vptr[0]); + void *msg = (void *)tswap32(vptr[1]); + size_t len = tswap32(vptr[2]); + int flags = tswap32(vptr[3]); + void *target_addr = (void *)tswap32(vptr[4]); + uint32_t *target_addrlen = (void *)tswap32(vptr[5]); + socklen_t addrlen = tswap32(*target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(recvfrom(sockfd, msg, len, flags, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + *target_addrlen = tswap32(addrlen); + } } break; case SOCKOP_shutdown: - ret = get_errno(shutdown(vptr[0], vptr[1])); + { + int sockfd = tswap32(vptr[0]); + int how = tswap32(vptr[1]); + + ret = get_errno(shutdown(sockfd, how)); + } break; case SOCKOP_sendmsg: case SOCKOP_recvmsg: @@ -344,11 +595,11 @@ static long do_socketcall(int num, long *vptr) struct iovec *vec; struct target_iovec *target_vec; - msgp = (void *)vptr[1]; + msgp = (void *)tswap32(vptr[1]); msg.msg_name = (void *)tswapl(msgp->msg_name); msg.msg_namelen = tswapl(msgp->msg_namelen); - msg.msg_control = (void *)tswapl(msgp->msg_control); - msg.msg_controllen = tswapl(msgp->msg_controllen); + msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); + msg.msg_control = alloca(msg.msg_controllen); msg.msg_flags = tswap32(msgp->msg_flags); count = tswapl(msgp->msg_iovlen); @@ -361,17 +612,43 @@ static long do_socketcall(int num, long *vptr) msg.msg_iovlen = count; msg.msg_iov = vec; - fd = vptr[0]; - flags = vptr[2]; - if (num == SOCKOP_sendmsg) - ret = sendmsg(fd, &msg, flags); - else - ret = recvmsg(fd, &msg, flags); - ret = get_errno(ret); + fd = tswap32(vptr[0]); + flags = tswap32(vptr[2]); + if (num == SOCKOP_sendmsg) { + target_to_host_cmsg(&msg, msgp); + ret = get_errno(sendmsg(fd, &msg, flags)); + } else { + ret = get_errno(recvmsg(fd, &msg, flags)); + if (!is_error(ret)) + host_to_target_cmsg(msgp, &msg); + } } break; case SOCKOP_setsockopt: + { + int sockfd = tswap32(vptr[0]); + int level = tswap32(vptr[1]); + int optname = tswap32(vptr[2]); + void *optval = (void *)tswap32(vptr[3]); + socklen_t optlen = tswap32(vptr[4]); + + ret = do_setsockopt(sockfd, level, optname, optval, optlen); + } + break; case SOCKOP_getsockopt: + { + int sockfd = tswap32(vptr[0]); + int level = tswap32(vptr[1]); + int optname = tswap32(vptr[2]); + void *optval = (void *)tswap32(vptr[3]); + uint32_t *target_len = (void *)tswap32(vptr[4]); + socklen_t optlen = tswap32(*target_len); + + ret = do_getsockopt(sockfd, level, optname, optval, &optlen); + if (!is_error(ret)) + *target_len = tswap32(optlen); + } + break; default: gemu_log("Unsupported socketcall: %d\n", num); ret = -ENOSYS; @@ -960,7 +1237,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(unlink((const char *)arg1)); break; case TARGET_NR_execve: - ret = get_errno(execve((const char *)arg1, (void *)arg2, (void *)arg3)); + { + char **argp, **envp; + int argc = 0, envc = 0; + uint32_t *p; + char **q; + + for (p = (void *)arg2; *p; p++) + argc++; + for (p = (void *)arg3; *p; p++) + envc++; + + argp = alloca(argc * sizeof(void *)); + envp = alloca(envc * sizeof(void *)); + + for (p = (void *)arg2, q = argp; *p; p++, q++) + *q = (void *)tswap32(*p); + for (p = (void *)arg3, q = envp; *p; p++, q++) + *q = (void *)tswap32(*p); + + ret = get_errno(execve((const char *)arg1, argp, envp)); + } break; case TARGET_NR_chdir: ret = get_errno(chdir((const char *)arg1)); @@ -1484,7 +1781,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_ioperm: goto unimplemented; case TARGET_NR_socketcall: - ret = do_socketcall(arg1, (long *)arg2); + ret = do_socketcall(arg1, (int32_t *)arg2); break; case TARGET_NR_syslog: goto unimplemented; @@ -1548,9 +1845,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, target_st->st_size = tswapl(st.st_size); target_st->st_blksize = tswapl(st.st_blksize); target_st->st_blocks = tswapl(st.st_blocks); - target_st->st_atime = tswapl(st.st_atime); - target_st->st_mtime = tswapl(st.st_mtime); - target_st->st_ctime = tswapl(st.st_ctime); + target_st->target_st_atime = tswapl(st.st_atime); + target_st->target_st_mtime = tswapl(st.st_mtime); + target_st->target_st_ctime = tswapl(st.st_ctime); } } break; @@ -1727,7 +2024,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unsigned int nfds = arg2; int timeout = arg3; struct pollfd *pfd; - int i; + unsigned int i; pfd = alloca(sizeof(struct pollfd) * nfds); for(i = 0; i < nfds; i++) { @@ -1940,9 +2237,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, target_st->st_size = tswapl(st.st_size); target_st->st_blksize = tswapl(st.st_blksize); target_st->st_blocks = tswapl(st.st_blocks); - target_st->st_atime = tswapl(st.st_atime); - target_st->st_mtime = tswapl(st.st_mtime); - target_st->st_ctime = tswapl(st.st_ctime); + target_st->target_st_atime = tswapl(st.st_atime); + target_st->target_st_mtime = tswapl(st.st_mtime); + target_st->target_st_ctime = tswapl(st.st_ctime); } } break; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 9b2f42a73..2c442d8aa 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -19,6 +19,11 @@ #define SOCKOP_sendmsg 16 #define SOCKOP_recvmsg 17 +struct target_sockaddr { + uint16_t sa_family; + uint8_t sa_data[14]; +}; + struct target_timeval { target_long tv_sec; target_long tv_usec; @@ -49,6 +54,43 @@ struct target_msghdr { unsigned int msg_flags; }; +struct target_cmsghdr { + target_long cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +#define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1)) +#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg) +#define TARGET_CMSG_FIRSTHDR(mhdr) \ + ((size_t) tswapl((mhdr)->msg_controllen) >= sizeof (struct target_cmsghdr) \ + ? (struct target_cmsghdr *) tswapl((mhdr)->msg_control) : (struct target_cmsghdr *) NULL) +#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (target_long) - 1) \ + & (size_t) ~(sizeof (target_long) - 1)) +#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \ + + TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr))) +#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len)) + +static __inline__ struct target_cmsghdr * +__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg) +{ + if (tswapl(__cmsg->cmsg_len) < sizeof (struct target_cmsghdr)) + /* The kernel header does this so there may be a reason. */ + return 0; + + __cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg + + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))); + if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) tswapl(__mhdr->msg_control) + + tswapl(__mhdr->msg_controllen)) + || ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)) + > ((unsigned char *) tswapl(__mhdr->msg_control) + + tswapl(__mhdr->msg_controllen)))) + /* No more entries. */ + return 0; + return __cmsg; +} + + struct target_rusage { struct target_timeval ru_utime; /* user time used */ struct target_timeval ru_stime; /* system time used */ diff --git a/syscall-i386.h b/syscall-i386.h index dc769b7ed..847404fe1 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -285,11 +285,11 @@ struct target_stat { target_ulong st_size; target_ulong st_blksize; target_ulong st_blocks; - target_ulong st_atime; + target_ulong target_st_atime; target_ulong __unused1; - target_ulong st_mtime; + target_ulong target_st_mtime; target_ulong __unused2; - target_ulong st_ctime; + target_ulong target_st_ctime; target_ulong __unused3; target_ulong __unused4; target_ulong __unused5; @@ -320,13 +320,13 @@ struct target_stat64 { target_ulong st_blocks; /* Number 512-byte blocks allocated. */ target_ulong __pad4; /* future possible st_blocks high bits */ - target_ulong st_atime; + target_ulong target_st_atime; target_ulong __pad5; - target_ulong st_mtime; + target_ulong target_st_mtime; target_ulong __pad6; - target_ulong st_ctime; + target_ulong target_st_ctime; target_ulong __pad7; /* will be high 32 bits of ctime someday */ unsigned long long st_ino; -- cgit v1.2.3 From fb3e5849bb139e8213b7afb5abd7ef5cc985d10b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Mar 2003 17:32:36 +0000 Subject: s390 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@65 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 7 ++++++- dyngen.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ exec-i386.c | 14 +++++++++++++ exec-i386.h | 6 ++++++ translate-i386.c | 6 ++++++ 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/configure b/configure index d58c46079..c8d06adaa 100755 --- a/configure +++ b/configure @@ -42,6 +42,9 @@ case "$cpu" in mips) cpu="mips" ;; + s390) + cpu="s390" + ;; *) cpu="unknown" ;; @@ -137,7 +140,7 @@ fi else # if cross compiling, cannot launch a program, so make a static guess -if test "$cpu" = "powerpc" -o "$cpu" = "mips" ; then +if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then bigendian="yes" fi @@ -212,6 +215,8 @@ elif test "$cpu" = "powerpc" ; then echo "ARCH=ppc" >> config.mak elif test "$cpu" = "mips" ; then echo "ARCH=mips" >> config.mak +elif test "$cpu" = "s390" ; then + echo "ARCH=s390" >> config.mak else echo "Unsupported CPU" exit 1 diff --git a/dyngen.c b/dyngen.c index 5cd59cb9d..52cabcfab 100644 --- a/dyngen.c +++ b/dyngen.c @@ -28,6 +28,15 @@ #include "thunk.h" +/* temporary fix to make it compile with old elf headers (XXX: use + included elf.h in all cases) */ +#ifndef EM_390 +#define EM_S390 22 /* IBM S390 */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#endif + /* all dynamically generated functions begin with this code */ #define OP_PREFIX "op_" @@ -236,6 +245,17 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, copy_size = p - p_start; } break; + case EM_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; + } + break; default: error("unsupported CPU (%d)", e_machine); } @@ -405,6 +425,42 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, } } break; + case EM_S390: + { + Elf32_Rela *rel; + char name[256]; + int type; + long addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_390_32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + rel->r_offset - offset, name, addend); + break; + case R_390_16: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + rel->r_offset - offset, name, addend); + break; + case R_390_8: + fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + rel->r_offset - offset, name, addend); + break; + default: + error("unsupported s390 relocation (%d)", type); + } + } + } + } + break; default: error("unsupported CPU for relocations (%d)", e_machine); } @@ -556,6 +612,9 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) case EM_SPARC: cpu_name = "sparc"; break; + case EM_S390: + cpu_name = "s390"; + break; default: error("unsupported CPU (e_machine=%d)", e_machine); } @@ -617,6 +676,9 @@ fprintf(outfile, case EM_PPC: fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n"); break; + case EM_S390: + fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n"); + break; default: error("no return generation for cpu '%s'", cpu_name); } diff --git a/exec-i386.c b/exec-i386.c index f59e1ccec..dedcbfabd 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -87,6 +87,20 @@ static inline int testandset (int *p) } #endif +#ifdef __s390__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" + " jl 0b" + : "=&d" (ret) + : "r" (1), "a" (p), "0" (*p) + : "cc", "memory" ); + return ret; +} +#endif + int global_cpu_lock = 0; void cpu_lock(void) diff --git a/exec-i386.h b/exec-i386.h index 7a6f74b92..28da51def 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -93,6 +93,12 @@ register unsigned int T1 asm("l1"); register unsigned int A0 asm("l2"); register struct CPUX86State *env asm("l3"); #endif +#ifdef __s390__ +register unsigned int T0 asm("r7"); +register unsigned int T1 asm("r8"); +register unsigned int A0 asm("r9"); +register struct CPUX86State *env asm("r10"); +#endif /* force GCC to generate only one epilog at the end of the function */ #define FORCE_RET() asm volatile (""); diff --git a/translate-i386.c b/translate-i386.c index 730398e97..55e8a8dde 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -50,6 +50,12 @@ 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 __powerpc__ #define MIN_CACHE_LINE_SIZE 8 /* conservative value */ -- cgit v1.2.3 From fd429f2f6cbc77dc5440725ede80df614787ece3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Mar 2003 20:59:46 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@66 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 13 +++++++++---- VERSION | 2 +- qemu-doc.texi | 41 ++++++++++++++++++++++++++++------------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 169f9def8..e6d1dedc2 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,10 @@ ifeq ($(ARCH),ppc) OP_CFLAGS=$(CFLAGS) endif +ifeq ($(ARCH),s390) +OP_CFLAGS=$(CFLAGS) +endif + ifeq ($(GCC_MAJOR),3) # very important to generate a return at the end of every operation OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls @@ -94,19 +98,20 @@ qemu-doc.html: qemu-doc.texi texi2html -monolithic -number $< FILES= \ -README COPYING COPYING.LIB TODO Changelog VERSION \ -dyngen.c ioctls.h ops_template.h syscall_types.h\ +README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ +dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ Makefile elf.h linux_bin.h segment.h thunk.c\ elfload.c main.c signal.c thunk.h\ -cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ +cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ dis-asm.h gen-i386.h op-i386.h syscall.c\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ -i386.ld ppc.ld exec-i386.h exec-i386.c configure \ +i386.ld ppc.ld s390.ld exec-i386.h exec-i386.c configure \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h tests/test-i386-code16.S\ tests/hello.c tests/hello tests/sha1.c \ tests/testsig.c tests/testclone.c tests/testthread.c \ +tests/runcom.c tests/pi_10.com \ qemu-doc.texi qemu-doc.html FILE=qemu-$(VERSION) diff --git a/VERSION b/VERSION index 7693c96bf..446ba66e7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.3 \ No newline at end of file +0.1.4 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index 3bb043be4..c29dc22ad 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -12,8 +12,9 @@ QEMU is an x86 processor emulator. Its purpose is to run x86 Linux processes on non-x86 Linux architectures such as PowerPC or ARM. By using dynamic translation it achieves a reasonnable speed while being -easy to port on new host CPUs. An obviously interesting x86 only process -is 'wine' (Windows emulation). +easy to port on new host CPUs. Its main goal is to be able to launch the +@code{Wine} Windows API emulator (@url{http://www.winehq.org}) on +non-x86 CPUs. QEMU features: @@ -21,12 +22,13 @@ QEMU features: @item User space only x86 emulator. -@item Currently ported on i386 and PowerPC. +@item Currently ported on i386, PowerPC and S390. -@item Using dynamic translation for reasonnable speed. +@item Using dynamic translation to native code for reasonnable speed. @item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. -User space LDT and GDT are emulated. +User space LDT and GDT are emulated. VM86 mode is also supported +(experimental). @item Generic Linux system call converter, including most ioctls. @@ -52,10 +54,6 @@ Current QEMU Limitations: @item No support for self modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !]. -@item No VM86 mode (yet), althought the virtual -CPU has support for most of it. [VM86 support is useful to launch old 16 -bit DOS programs with dosemu or wine]. - @item No SSE/MMX support (yet). @item No x86-64 support. @@ -123,10 +121,10 @@ able to do: qemu /usr/local/qemu-i386/bin/ls-i386 @end example -@item Download the binary x86 wine install +@item Download the binary x86 Wine install (@file{qemu-i386-wine.tar.gz} on the QEMU web page). -@item Configure wine on your account. Look at the provided script +@item Configure Wine on your account. Look at the provided script @file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous @code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}. @@ -177,6 +175,13 @@ code, in particular the ELF file loader). EM86 was limited to an alpha host and used a proprietary and slow interpreter (the interpreter part of the FX!32 Digital Win32 code translator [5]). +TWIN [6] is a Windows API emulator like Wine. It is less accurate than +Wine but includes a protected mode x86 interpreter to launch x86 Windows +executables. Such an approach as greater potential because most of the +Windows API is executed natively but it is far more difficult to develop +because all the data structures and function parameters exchanged +between the API and the x86 code must be converted. + @section Portable dynamic translation QEMU is a dynamic translator. When it first encounters a piece of code, @@ -218,7 +223,7 @@ doing complicated register allocation. Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a critical point to get good performances. QEMU uses lazy condition code evaluation: instead of computing the condition codes after each x86 -instruction, it store justs one operand (called @code{CC_CRC}), the +instruction, it just stores one operand (called @code{CC_SRC}), the result (called @code{CC_DST}) and the type of operation (called @code{CC_OP}). @@ -231,7 +236,7 @@ generated simple instructions (see the condition codes are not needed by the next instructions, no condition codes are computed at all. -@section Translation CPU state optimisations +@section CPU state optimisations The x86 CPU has many internal states which change the way it evaluates instructions. In order to achieve a good speed, the translation phase @@ -323,6 +328,10 @@ x86 emulator on Alpha-Linux. DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton Chernoff and Ray Hookway. +@item [6] +@url{http://www.willows.com/}, Windows API library emulation from +Willows Software. + @end table @chapter Regression Tests @@ -365,3 +374,9 @@ It is a simple benchmark. Care must be taken to interpret the results because it mostly tests the ability of the virtual CPU to optimize the @code{rol} x86 instruction and the condition code computations. +@section @file{runcom} + +A very simple MSDOS emulator to test the Linux vm86() system call +emulation. The excellent 54 byte @file{pi_10.com} PI number calculator +can be launched with it. @file{pi_10.com} was written by Bertram +Felgenhauer (more information at @url{http://www.boo.net/~jasonp/pipage.html}). -- cgit v1.2.3 From f7341ff4006dd90ffc6560bb9db761b9d2950aaf Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Mar 2003 21:00:25 +0000 Subject: fixed execve bug git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@67 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index befc08dd3..898dbcdf0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1077,7 +1077,6 @@ int do_vm86(CPUX86State *env, long subfunction, } ts->target_v86 = target_v86; - /* save current CPU regs */ ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ ts->vm86_saved_regs.ebx = env->regs[R_EBX]; @@ -1239,22 +1238,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_execve: { char **argp, **envp; - int argc = 0, envc = 0; + int argc, envc; uint32_t *p; char **q; + argc = 0; for (p = (void *)arg2; *p; p++) argc++; + envc = 0; for (p = (void *)arg3; *p; p++) envc++; - argp = alloca(argc * sizeof(void *)); - envp = alloca(envc * sizeof(void *)); + argp = alloca((argc + 1) * sizeof(void *)); + envp = alloca((envc + 1) * sizeof(void *)); for (p = (void *)arg2, q = argp; *p; p++, q++) *q = (void *)tswap32(*p); + *q = NULL; + for (p = (void *)arg3, q = envp; *p; p++, q++) *q = (void *)tswap32(*p); + *q = NULL; ret = get_errno(execve((const char *)arg1, argp, envp)); } -- cgit v1.2.3 From f631ef9bd262796779dd2b18741cf924831dab54 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Mar 2003 21:01:16 +0000 Subject: better vm86 support - added iret - fixed push/pop fs/gs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@68 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- opc-i386.h | 8 +++++ translate-i386.c | 68 +++++++++++++++++++++++++++++++++++--- 3 files changed, 168 insertions(+), 7 deletions(-) diff --git a/op-i386.c b/op-i386.c index dbf70bb59..43303784d 100644 --- a/op-i386.c +++ b/op-i386.c @@ -611,6 +611,35 @@ void OPPROTO op_into(void) } } +/* XXX: add IOPL/CPL tests */ +void OPPROTO op_cli(void) +{ + raise_exception(EXCP0D_GPF); +} + +/* XXX: add IOPL/CPL tests */ +void OPPROTO op_sti(void) +{ + raise_exception(EXCP0D_GPF); +} + +/* vm86plus instructions */ + +void OPPROTO op_cli_vm(void) +{ + env->eflags &= ~VIF_MASK; +} + +void OPPROTO op_sti_vm(void) +{ + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + FORCE_RET(); +} + void OPPROTO op_boundw(void) { int low, high, v; @@ -1234,7 +1263,8 @@ void OPPROTO op_set_cc_op(void) CC_OP = PARAM1; } -#define FL_UPDATE_MASK (TF_MASK | AC_MASK | ID_MASK) +#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) +#define FL_UPDATE_MASK16 (TF_MASK) void OPPROTO op_movl_eflags_T0(void) { @@ -1243,7 +1273,56 @@ void OPPROTO op_movl_eflags_T0(void) CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); DF = 1 - (2 * ((eflags >> 10) & 1)); /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~FL_UPDATE_MASK) | (eflags & FL_UPDATE_MASK); + env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | (eflags & FL_UPDATE_MASK32); +} + +void OPPROTO op_movw_eflags_T0(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16); +} + +/* vm86 version */ +void OPPROTO op_movw_eflags_T0_vm(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) | + (eflags & FL_UPDATE_MASK16); + if (eflags & IF_MASK) { + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + } + FORCE_RET(); +} + +void OPPROTO op_movl_eflags_T0_vm(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) | + (eflags & FL_UPDATE_MASK32); + if (eflags & IF_MASK) { + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + } + FORCE_RET(); } /* XXX: compute only O flag */ @@ -1263,6 +1342,18 @@ void OPPROTO op_movl_T0_eflags(void) T0 = eflags; } +/* vm86 version */ +void OPPROTO op_movl_T0_eflags_vm(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DF_MASK); + eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); + if (env->eflags & VIF_MASK) + eflags |= IF_MASK; + T0 = eflags; +} + void OPPROTO op_cld(void) { DF = 1; @@ -1377,7 +1468,9 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_SARL] = { compute_all_sarl, compute_c_shll }, }; -/* floating point support */ +/* floating point support. Some of the code for complicated x87 + functions comes from the LGPL'ed x86 emulator found in the Willows + TWIN windows emulator. */ #ifdef USE_X86LDOUBLE /* use long double functions */ diff --git a/opc-i386.h b/opc-i386.h index 2a50e26a7..84e41440f 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -232,6 +232,10 @@ DEF(jmp_im, 1) DEF(int_im, 1) DEF(int3, 1) DEF(into, 0) +DEF(cli, 0) +DEF(sti, 0) +DEF(cli_vm, 0) +DEF(sti_vm, 1) DEF(boundw, 0) DEF(boundl, 0) DEF(cmpxchg8b, 0) @@ -551,8 +555,12 @@ DEF(setle_T0_cc, 0) DEF(xor_T0_1, 0) DEF(set_cc_op, 1) DEF(movl_eflags_T0, 0) +DEF(movw_eflags_T0, 0) +DEF(movw_eflags_T0_vm, 1) +DEF(movl_eflags_T0_vm, 1) DEF(movb_eflags_T0, 0) DEF(movl_T0_eflags, 0) +DEF(movl_T0_eflags_vm, 0) DEF(cld, 0) DEF(std, 0) DEF(clc, 0) diff --git a/translate-i386.c b/translate-i386.c index 55e8a8dde..4d8cbf391 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1919,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x1a0: /* push fs */ case 0x1a8: /* push gs */ - gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS); + gen_op_movl_T0_seg((b >> 3) & 7); gen_push_T0(s); break; case 0x07: /* pop es */ @@ -1932,7 +1932,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x1a1: /* pop fs */ case 0x1a9: /* pop gs */ gen_pop_T0(s); - gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS); + gen_movl_seg_T0(s, (b >> 3) & 7); gen_pop_update(s); break; @@ -2833,6 +2833,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->is_jmp = 1; break; case 0xca: /* lret im */ + /* XXX: not restartable */ val = ldsw(s->pc); s->pc += 2; /* pop offset */ @@ -2853,6 +2854,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->is_jmp = 1; break; case 0xcb: /* lret */ + /* XXX: not restartable */ /* pop offset */ gen_pop_T0(s); if (s->dflag == 0) @@ -2865,6 +2867,35 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_pop_update(s); s->is_jmp = 1; break; + case 0xcf: /* iret */ + /* XXX: not restartable */ + /* pop offset */ + gen_pop_T0(s); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_pop_update(s); + /* pop selector */ + gen_pop_T0(s); + gen_movl_seg_T0(s, R_CS); + gen_pop_update(s); + /* pop eflags */ + gen_pop_T0(s); + if (s->dflag) { + if (s->vm86) + gen_op_movl_eflags_T0_vm(pc_start - s->cs_base); + else + gen_op_movl_eflags_T0(); + } else { + if (s->vm86) + gen_op_movw_eflags_T0_vm(pc_start - s->cs_base); + else + gen_op_movw_eflags_T0(); + } + gen_pop_update(s); + s->cc_op = CC_OP_EFLAGS; + s->is_jmp = 1; + break; case 0xe8: /* call im */ { unsigned int next_eip; @@ -2978,12 +3009,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x9c: /* pushf */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_movl_T0_eflags(); + if (s->vm86) + gen_op_movl_T0_eflags_vm(); + else + gen_op_movl_T0_eflags(); gen_push_T0(s); break; case 0x9d: /* popf */ gen_pop_T0(s); - gen_op_movl_eflags_T0(); + if (s->dflag) { + if (s->vm86) + gen_op_movl_eflags_T0_vm(pc_start - s->cs_base); + else + gen_op_movl_eflags_T0(); + } else { + if (s->vm86) + gen_op_movw_eflags_T0_vm(pc_start - s->cs_base); + else + gen_op_movw_eflags_T0(); + } gen_pop_update(s); s->cc_op = CC_OP_EFLAGS; break; @@ -3159,6 +3203,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_set_cc_op(s->cc_op); gen_op_into(); break; + case 0xfa: /* cli */ + if (s->vm86) + gen_op_cli_vm(); + else + gen_op_cli(); + break; + case 0xfb: /* sti */ + if (s->vm86) + gen_op_sti_vm(pc_start - s->cs_base); + else + gen_op_sti(); + break; case 0x62: /* bound */ ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); @@ -3308,6 +3364,7 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, [INDEX_op_movl_T0_eflags] = CC_OSZAPC, + [INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC, [INDEX_op_cmc] = CC_C, [INDEX_op_salc] = CC_C, @@ -3356,7 +3413,10 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_daa] = CC_OSZAPC, [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, + [INDEX_op_movw_eflags_T0] = CC_OSZAPC, + [INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC, [INDEX_op_movl_eflags_T0] = CC_OSZAPC, + [INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC, [INDEX_op_clc] = CC_C, [INDEX_op_stc] = CC_C, [INDEX_op_cmc] = CC_C, -- cgit v1.2.3 From bc8a22cc307ebd9a2577c8fffcb90000724f72f3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Mar 2003 21:02:40 +0000 Subject: better vm86 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@69 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 33 ++++++++ TODO | 5 +- cpu-i386.h | 36 ++++---- linux-user/main.c | 231 +++++++++++++++++++++++++++++++++++++--------------- linux-user/qemu.h | 1 + linux-user/signal.c | 17 ++-- syscall-i386.h | 5 ++ 7 files changed, 239 insertions(+), 89 deletions(-) diff --git a/Changelog b/Changelog index 574ae5e60..2a76e092a 100644 --- a/Changelog +++ b/Changelog @@ -1,8 +1,41 @@ +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. + +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: diff --git a/TODO b/TODO index 6616d62d5..9f266514b 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,11 @@ +- fix thread locks +- fix thread stack liberation +- fix x86 stack allocation - optimize translated cache chaining (DLL PLT-like system) - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues, fix 16 bit uid issues) - finish signal handing (fp87 state, more siginfo conversions) - verify thread support (clone() and various locks) -- vm86 syscall support - overrides/16bit for string ops - make it self runnable (use same trick as ld.so : include its own relocator and libc) -- improved 16 bit support - fix FPU exceptions (in particular: gen_op_fpush not before mem load) diff --git a/cpu-i386.h b/cpu-i386.h index 4eeb6be88..76db7a616 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -68,24 +68,24 @@ #define VIP_MASK 0x00100000 #define ID_MASK 0x00200000 -#define EXCP00_DIVZ 1 -#define EXCP01_SSTP 2 -#define EXCP02_NMI 3 -#define EXCP03_INT3 4 -#define EXCP04_INTO 5 -#define EXCP05_BOUND 6 -#define EXCP06_ILLOP 7 -#define EXCP07_PREX 8 -#define EXCP08_DBLE 9 -#define EXCP09_XERR 10 -#define EXCP0A_TSS 11 -#define EXCP0B_NOSEG 12 -#define EXCP0C_STACK 13 -#define EXCP0D_GPF 14 -#define EXCP0E_PAGE 15 -#define EXCP10_COPR 17 -#define EXCP11_ALGN 18 -#define EXCP12_MCHK 19 +#define EXCP00_DIVZ 0 +#define EXCP01_SSTP 1 +#define EXCP02_NMI 2 +#define EXCP03_INT3 3 +#define EXCP04_INTO 4 +#define EXCP05_BOUND 5 +#define EXCP06_ILLOP 6 +#define EXCP07_PREX 7 +#define EXCP08_DBLE 8 +#define EXCP09_XERR 9 +#define EXCP0A_TSS 10 +#define EXCP0B_NOSEG 11 +#define EXCP0C_STACK 12 +#define EXCP0D_GPF 13 +#define EXCP0E_PAGE 14 +#define EXCP10_COPR 16 +#define EXCP11_ALGN 17 +#define EXCP12_MCHK 18 #define EXCP_INTERRUPT 256 /* async interruption */ diff --git a/linux-user/main.c b/linux-user/main.c index c12ef0f18..5acfdde41 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -106,77 +106,172 @@ uint64_t gdt_table[6]; //#define DEBUG_VM86 +static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) +{ + return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1; +} + +static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) +{ + return (uint8_t *)((seg << 4) + (reg & 0xffff)); +} + +static inline void pushw(CPUX86State *env, int val) +{ + env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | + ((env->regs[R_ESP] - 2) & 0xffff); + *(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val; +} + +static inline unsigned int get_vflags(CPUX86State *env) +{ + unsigned int eflags; + eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); + if (eflags & VIF_MASK) + eflags |= IF_MASK; + return eflags; +} + +void save_v86_state(CPUX86State *env) +{ + TaskState *ts = env->opaque; +#ifdef DEBUG_VM86 + printf("save_v86_state\n"); +#endif + + /* put the VM86 registers in the userspace register structure */ + ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); + ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); + ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); + ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); + ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); + ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); + ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); + ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); + ts->target_v86->regs.eip = tswap32(env->eip); + ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); + ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); + ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); + ts->target_v86->regs.es = tswap16(env->segs[R_ES]); + ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); + ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); + ts->target_v86->regs.eflags = tswap32(env->eflags); + + /* restore 32 bit registers */ + env->regs[R_EAX] = ts->vm86_saved_regs.eax; + env->regs[R_EBX] = ts->vm86_saved_regs.ebx; + env->regs[R_ECX] = ts->vm86_saved_regs.ecx; + env->regs[R_EDX] = ts->vm86_saved_regs.edx; + env->regs[R_ESI] = ts->vm86_saved_regs.esi; + env->regs[R_EDI] = ts->vm86_saved_regs.edi; + env->regs[R_EBP] = ts->vm86_saved_regs.ebp; + env->regs[R_ESP] = ts->vm86_saved_regs.esp; + env->eflags = ts->vm86_saved_regs.eflags; + env->eip = ts->vm86_saved_regs.eip; + + cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); + cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); + cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); + cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); + cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); + cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); +} + +/* return from vm86 mode to 32 bit. The vm86() syscall will return + 'retval' */ +static inline void return_to_32bit(CPUX86State *env, int retval) +{ +#ifdef DEBUG_VM86 + printf("return_to_32bit: ret=0x%x\n", retval); +#endif + save_v86_state(env); + env->regs[R_EAX] = retval; +} + +/* handle VM86 interrupt (NOTE: the CPU core currently does not + support TSS interrupt revectoring, so this code is always executed) */ +static void do_int(CPUX86State *env, int intno) +{ + TaskState *ts = env->opaque; + uint32_t *int_ptr, segoffs; + + if (env->segs[R_CS] == TARGET_BIOSSEG) + goto cannot_handle; /* XXX: I am not sure this is really useful */ + if (is_revectored(intno, &ts->target_v86->int_revectored)) + goto cannot_handle; + if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, + &ts->target_v86->int21_revectored)) + goto cannot_handle; + int_ptr = (uint32_t *)(intno << 2); + segoffs = tswap32(*int_ptr); + if ((segoffs >> 16) == TARGET_BIOSSEG) + goto cannot_handle; +#ifdef DEBUG_VM86 + printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", + intno, segoffs >> 16, segoffs & 0xffff); +#endif + /* save old state */ + pushw(env, get_vflags(env)); + pushw(env, env->segs[R_CS]); + pushw(env, env->eip); + /* goto interrupt handler */ + env->eip = segoffs & 0xffff; + cpu_x86_load_seg(env, R_CS, segoffs >> 16); + env->eflags &= ~(VIF_MASK | TF_MASK); + return; + cannot_handle: +#ifdef DEBUG_VM86 + printf("VM86: return to 32 bits int 0x%x\n", intno); +#endif + return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); +} + void cpu_loop(struct CPUX86State *env) { - int err; + int trapnr; uint8_t *pc; target_siginfo_t info; for(;;) { - err = cpu_x86_exec(env); + trapnr = cpu_x86_exec(env); pc = env->seg_cache[R_CS].base + env->eip; - switch(err) { + switch(trapnr) { case EXCP0D_GPF: if (env->eflags & VM_MASK) { - TaskState *ts; - int ret; #ifdef DEBUG_VM86 - printf("VM86 exception %04x:%08x %02x\n", - env->segs[R_CS], env->eip, pc[0]); + printf("VM86 exception %04x:%08x %02x %02x\n", + env->segs[R_CS], env->eip, pc[0], pc[1]); #endif /* VM86 mode */ - ts = env->opaque; - - /* XXX: add all cases */ switch(pc[0]) { case 0xcd: /* int */ env->eip += 2; - ret = TARGET_VM86_INTx | (pc[1] << 8); + do_int(env, pc[1]); + break; + case 0x66: + switch(pc[1]) { + case 0xfb: /* sti */ + case 0x9d: /* popf */ + case 0xcf: /* iret */ + env->eip += 2; + return_to_32bit(env, TARGET_VM86_STI); + break; + default: + goto vm86_gpf; + } + break; + case 0xfb: /* sti */ + case 0x9d: /* popf */ + case 0xcf: /* iret */ + env->eip++; + return_to_32bit(env, TARGET_VM86_STI); break; default: + vm86_gpf: /* real VM86 GPF exception */ - ret = TARGET_VM86_UNKNOWN; + return_to_32bit(env, TARGET_VM86_UNKNOWN); break; } -#ifdef DEBUG_VM86 - printf("ret=0x%x\n", ret); -#endif - /* put the VM86 registers in the userspace register structure */ - ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); - ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); - ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); - ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); - ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); - ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); - ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); - ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); - ts->target_v86->regs.eip = tswap32(env->eip); - ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); - ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); - ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); - ts->target_v86->regs.es = tswap16(env->segs[R_ES]); - ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); - ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); - - /* restore 32 bit registers */ - env->regs[R_EBX] = ts->vm86_saved_regs.ebx; - env->regs[R_ECX] = ts->vm86_saved_regs.ecx; - env->regs[R_EDX] = ts->vm86_saved_regs.edx; - env->regs[R_ESI] = ts->vm86_saved_regs.esi; - env->regs[R_EDI] = ts->vm86_saved_regs.edi; - env->regs[R_EBP] = ts->vm86_saved_regs.ebp; - env->regs[R_ESP] = ts->vm86_saved_regs.esp; - env->eflags = ts->vm86_saved_regs.eflags; - env->eip = ts->vm86_saved_regs.eip; - - cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); - cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); - cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); - cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); - cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); - cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); - - env->regs[R_EAX] = ret; } else { if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ @@ -200,20 +295,28 @@ void cpu_loop(struct CPUX86State *env) } break; case EXCP00_DIVZ: - /* division by zero */ - info.si_signo = SIGFPE; - info.si_errno = 0; - info.si_code = TARGET_FPE_INTDIV; - info._sifields._sigfault._addr = env->eip; - queue_signal(info.si_signo, &info); + if (env->eflags & VM_MASK) { + do_int(env, trapnr); + } else { + /* division by zero */ + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_INTDIV; + info._sifields._sigfault._addr = env->eip; + queue_signal(info.si_signo, &info); + } break; case EXCP04_INTO: case EXCP05_BOUND: - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = 0; - info._sifields._sigfault._addr = 0; - queue_signal(info.si_signo, &info); + if (env->eflags & VM_MASK) { + do_int(env, trapnr); + } else { + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = 0; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); + } break; case EXCP06_ILLOP: info.si_signo = SIGILL; @@ -226,8 +329,8 @@ void cpu_loop(struct CPUX86State *env) /* just indicate that signals should be handled asap */ break; default: - fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n", - (long)pc, err); + fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", + (long)pc, trapnr); abort(); } process_pending_signals(env); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 54b38e70e..882c3c039 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -74,5 +74,6 @@ void cpu_loop(CPUX86State *env); void process_pending_signals(void *cpu_env); void signal_init(void); int queue_signal(int sig, target_siginfo_t *info); +void save_v86_state(CPUX86State *env); #endif diff --git a/linux-user/signal.c b/linux-user/signal.c index 04779c82c..6a81b11cd 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -198,7 +198,7 @@ void __attribute((noreturn)) force_sig(int sig) { int host_sig; host_sig = target_to_host_signal(sig); - fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n", + fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", sig, strsignal(host_sig)); #if 1 _exit(-host_sig); @@ -223,7 +223,7 @@ int queue_signal(int sig, target_siginfo_t *info) target_ulong handler; #if defined(DEBUG_SIGNAL) - fprintf(stderr, "queue_sigal: sig=%d\n", + fprintf(stderr, "queue_signal: sig=%d\n", sig); #endif k = &sigact_table[sig - 1]; @@ -317,7 +317,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, if (sig < 1 || sig > TARGET_NSIG) return; #if defined(DEBUG_SIGNAL) - fprintf(stderr, "gemu: got signal %d\n", sig); + fprintf(stderr, "qemu: got signal %d\n", sig); dump_regs(puc); #endif host_to_target_siginfo_noswap(&tinfo, info); @@ -538,7 +538,6 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2); - return err; } @@ -859,7 +858,7 @@ void process_pending_signals(void *cpu_env) handle_signal: #ifdef DEBUG_SIGNAL - fprintf(stderr, "gemu: process signal %d\n", sig); + fprintf(stderr, "qemu: process signal %d\n", sig); #endif /* dequeue signal */ q = k->first; @@ -893,6 +892,14 @@ void process_pending_signals(void *cpu_env) end of the signal execution (see do_sigreturn) */ host_to_target_sigset(&target_old_set, &old_set); + /* if the CPU is in VM86 mode, we restore the 32 bit values */ +#ifdef TARGET_I386 + { + CPUX86State *env = cpu_env; + if (env->eflags & VM_MASK) + save_v86_state(env); + } +#endif /* prepare the stack frame of the virtual CPU */ if (k->sa.sa_flags & TARGET_SA_SIGINFO) setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env); diff --git a/syscall-i386.h b/syscall-i386.h index 847404fe1..0fb57ce16 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -755,6 +755,11 @@ struct target_modify_ldt_ldt_s { unsigned int flags; }; + +/* vm86 defines */ + +#define TARGET_BIOSSEG 0x0f000 + #define TARGET_VM86_SIGNAL 0 /* return due to signal */ #define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ #define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */ -- cgit v1.2.3 From 32f36bcefcd5710a00bb168bc40c407ae899b630 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Mar 2003 21:29:48 +0000 Subject: added SIOCATMARK and times() syscall git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@70 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ioctls.h | 1 + linux-user/syscall.c | 14 +++++++++++++- linux-user/syscall_defs.h | 9 +++++++++ syscall-i386.h | 2 ++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index f075aff4d..b9aadb7a5 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -66,6 +66,7 @@ IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG)) #endif + IOCTL(SIOCATMARK, 0, TYPE_NULL) IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 898dbcdf0..16958be80 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -40,6 +40,7 @@ #include #include #include +#include //#include #include @@ -1367,7 +1368,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_times: - goto unimplemented; + { + struct target_tms *tmsp = (void *)arg1; + struct tms tms; + ret = get_errno(times(&tms)); + if (tmsp) { + tmsp->tms_utime = tswapl(tms.tms_utime); + tmsp->tms_stime = tswapl(tms.tms_stime); + tmsp->tms_cutime = tswapl(tms.tms_cutime); + tmsp->tms_cstime = tswapl(tms.tms_cstime); + } + } + break; case TARGET_NR_prof: goto unimplemented; case TARGET_NR_setgid: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 2c442d8aa..a442683b6 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -39,6 +39,15 @@ struct target_itimerval { struct target_timeval it_value; }; +typedef target_long target_clock_t; + +struct target_tms { + target_clock_t tms_utime; + target_clock_t tms_stime; + target_clock_t tms_cutime; + target_clock_t tms_cstime; +}; + struct target_iovec { target_long iov_base; /* Starting address */ target_long iov_len; /* Number of bytes */ diff --git a/syscall-i386.h b/syscall-i386.h index 0fb57ce16..9bc35f1ca 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -1065,3 +1065,5 @@ union target_semun { #define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201 #define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202 + +#define TARGET_SIOCATMARK 0x8905 -- cgit v1.2.3 From 62296fe3510d1f72b219223c36f11f3a4cf23107 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Mar 2003 21:41:51 +0000 Subject: added runcom test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@71 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/runcom.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 tests/runcom.c diff --git a/tests/runcom.c b/tests/runcom.c new file mode 100644 index 000000000..2d41341c5 --- /dev/null +++ b/tests/runcom.c @@ -0,0 +1,188 @@ +/* + * Simple example of use of vm86: launch a basic .com DOS executable + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//#define SIGTEST + +_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86) + +#define COM_BASE_ADDR 0x10100 + +void usage(void) +{ + printf("runcom version 0.1 (c) 2003 Fabrice Bellard\n" + "usage: runcom file.com\n" + "VM86 Run simple .com DOS executables (linux vm86 test mode)\n"); + exit(1); +} + +static inline void set_bit(uint8_t *a, unsigned int bit) +{ + a[bit / 8] |= (1 << (bit % 8)); +} + +static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) +{ + return (uint8_t *)((seg << 4) + (reg & 0xffff)); +} + +static inline void pushw(struct vm86_regs *r, int val) +{ + r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff); + *(uint16_t *)seg_to_linear(r->ss, r->esp) = val; +} + +void dump_regs(struct vm86_regs *r) +{ + fprintf(stderr, + "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n" + "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n" + "EIP=%08lx EFL=%08lx\n" + "CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n", + r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp, + r->eip, r->eflags, + r->cs, r->ds, r->es, r->ss, r->fs, r->gs); +} + +#ifdef SIGTEST +void alarm_handler(int sig) +{ + fprintf(stderr, "alarm signal=%d\n", sig); + alarm(1); +} +#endif + +int main(int argc, char **argv) +{ + uint8_t *vm86_mem; + const char *filename; + int fd, ret, seg; + struct vm86plus_struct ctx; + struct vm86_regs *r; + + if (argc != 2) + usage(); + filename = argv[1]; + + vm86_mem = mmap((void *)0x00000000, 0x110000, + PROT_WRITE | PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); + if (vm86_mem == MAP_FAILED) { + perror("mmap"); + exit(1); + } +#ifdef SIGTEST + { + struct sigaction act; + + act.sa_handler = alarm_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGALRM, &act, NULL); + alarm(1); + } +#endif + + /* load the MSDOS .com executable */ + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(1); + } + ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256); + if (ret < 0) { + perror("read"); + exit(1); + } + close(fd); + + memset(&ctx, 0, sizeof(ctx)); + /* init basic registers */ + r = &ctx.regs; + r->eip = 0x100; + r->esp = 0xfffe; + seg = (COM_BASE_ADDR - 0x100) >> 4; + r->cs = seg; + r->ss = seg; + r->ds = seg; + r->es = seg; + r->fs = seg; + r->gs = seg; + r->eflags = (IF_MASK | IOPL_MASK); + + /* put return code */ + set_bit((uint8_t *)&ctx.int_revectored, 0x21); + *seg_to_linear(r->cs, 0) = 0xb4; /* mov ah, $0 */ + *seg_to_linear(r->cs, 1) = 0x00; + *seg_to_linear(r->cs, 2) = 0xcd; /* int $0x21 */ + *seg_to_linear(r->cs, 3) = 0x21; + pushw(&ctx.regs, 0x0000); + + /* the value of these registers seem to be assumed by pi_10.com */ + r->esi = 0x100; + r->ecx = 0xff; + r->ebp = 0x0900; + r->edi = 0xfffe; + + for(;;) { + ret = vm86(VM86_ENTER, &ctx); + switch(VM86_TYPE(ret)) { + case VM86_INTx: + { + int int_num, ah; + + int_num = VM86_ARG(ret); + if (int_num != 0x21) + goto unknown_int; + ah = (r->eax >> 8) & 0xff; + switch(ah) { + case 0x00: /* exit */ + exit(0); + case 0x02: /* write char */ + { + uint8_t c = r->edx; + write(1, &c, 1); + } + break; + case 0x09: /* write string */ + { + uint8_t c; + for(;;) { + c = *seg_to_linear(r->ds, r->edx); + if (c == '$') + break; + write(1, &c, 1); + } + r->eax = (r->eax & ~0xff) | '$'; + } + break; + default: + unknown_int: + fprintf(stderr, "unsupported int 0x%02x\n", int_num); + dump_regs(&ctx.regs); + // exit(1); + } + } + break; + case VM86_SIGNAL: + /* a signal came, we just ignore that */ + break; + case VM86_STI: + break; + default: + fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret); + dump_regs(&ctx.regs); + exit(1); + } + } +} -- cgit v1.2.3 From f48c3dd51a0013850abe119353f6717978a4aac4 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:30:39 +0000 Subject: -statis for test-i386 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@72 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 14521fad6..8a5ed4cfc 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -28,7 +28,7 @@ testthread: testthread.c # i386 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c test-i386-code16.S -lm + $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm test: test-i386 ifeq ($(ARCH),i386) -- cgit v1.2.3 From f801f97e049b3cd832f50b9743184d0e87155193 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:31:06 +0000 Subject: personality fix - i386 interpreter fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@73 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 5acfdde41..d7c68a9cd 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -23,6 +23,9 @@ #include #include #include +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +#include +#endif #include "qemu.h" @@ -34,6 +37,12 @@ FILE *logfile = NULL; int loglevel; const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386"; +#ifdef __i386__ +/* Force usage of an ELF interpreter even if it is an ELF shared + object ! */ +const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; +#endif + /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example by remapping the process stack directly at the right place */ @@ -370,6 +379,13 @@ int main(int argc, char **argv) if (argc <= 1) usage(); + + /* Set personality to X86_LINUX. May fail on unpatched kernels: + if so, they need to have munged paths themselves (eg. chroot, + hacked ld.so, whatever). */ + if (personality(0x11) >= 0) + interp_prefix = ""; + loglevel = 0; optind = 1; for(;;) { -- cgit v1.2.3 From 295defa5f1fc5f270727e128f95e561a1d47858c Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:31:29 +0000 Subject: alpha addition git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@74 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configure b/configure index c8d06adaa..f3f725b48 100755 --- a/configure +++ b/configure @@ -36,7 +36,7 @@ case "$cpu" in alpha) cpu="alpha" ;; - "Power Macintosh"|ppc) + "Power Macintosh"|ppc|ppc64) cpu="powerpc" ;; mips) @@ -209,14 +209,22 @@ echo "CFLAGS=$CFLAGS" >> config.mak echo "LDFLAGS=$LDFLAGS" >> config.mak if test "$cpu" = "x86" ; then echo "ARCH=i386" >> config.mak + echo "#define HOST_I386 1" >> $TMPH elif test "$cpu" = "armv4l" ; then echo "ARCH=arm" >> config.mak + echo "#define HOST_ARM 1" >> $TMPH elif test "$cpu" = "powerpc" ; then echo "ARCH=ppc" >> config.mak + echo "#define HOST_PPC 1" >> $TMPH elif test "$cpu" = "mips" ; then echo "ARCH=mips" >> config.mak + echo "#define HOST_MIPS 1" >> $TMPH elif test "$cpu" = "s390" ; then echo "ARCH=s390" >> config.mak + echo "#define HOST_S390 1" >> $TMPH +elif test "$cpu" = "alpha" ; then + echo "ARCH=alpha" >> config.mak + echo "#define HOST_ALPHA 1" >> $TMPH else echo "Unsupported CPU" exit 1 -- cgit v1.2.3 From 43d4145a986d97197eb56fd0858175823ad9d96e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:31:44 +0000 Subject: bfd.h dependancy removed git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@75 c046a42c-6fe2-441c-8c8c-71466251a162 --- dis-asm.h | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/dis-asm.h b/dis-asm.h index 20ca8e26a..5a10c5e93 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -11,7 +11,152 @@ #include #include -#include "bfd.h" +#include + +#define PARAMS(x) x +typedef void *PTR; +typedef uint64_t bfd_vma; +typedef uint8_t bfd_byte; + +enum bfd_flavour { + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_ihex_flavour, + bfd_target_som_flavour, + bfd_target_os9k_flavour, + bfd_target_versados_flavour, + bfd_target_msdos_flavour, + bfd_target_evax_flavour +}; + +enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; + +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known */ + bfd_arch_obscure, /* Arch known, not one of these */ + bfd_arch_m68k, /* Motorola 68xxx */ +#define bfd_mach_m68000 1 +#define bfd_mach_m68008 2 +#define bfd_mach_m68010 3 +#define bfd_mach_m68020 4 +#define bfd_mach_m68030 5 +#define bfd_mach_m68040 6 +#define bfd_mach_m68060 7 + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 +#define bfd_mach_i960_jx 7 +#define bfd_mach_i960_hx 8 + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ +#define bfd_mach_sparc 1 + /* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ +#define bfd_mach_sparc_sparclet 2 +#define bfd_mach_sparc_sparclite 3 +#define bfd_mach_sparc_v8plus 4 +#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */ +#define bfd_mach_sparc_v9 6 +#define bfd_mach_sparc_v9a 7 /* with ultrasparc add'ns */ + /* Nonzero if MACH has the v9 instruction set. */ +#define bfd_mach_sparc_v9_p(mach) \ + ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a) + 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 + 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 */ + bfd_arch_rs6000, /* IBM RS/6000 */ + bfd_arch_hppa, /* HP PA RISC */ + bfd_arch_d10v, /* Mitsubishi D10V */ + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Hitachi H8/500 */ + bfd_arch_sh, /* Hitachi SH */ +#define bfd_mach_sh 0 +#define bfd_mach_sh3 0x30 +#define bfd_mach_sh3e 0x3e +#define bfd_mach_sh4 0x40 + bfd_arch_alpha, /* Dec Alpha */ + bfd_arch_arm, /* Advanced Risc Machines ARM */ +#define bfd_mach_arm_2 1 +#define bfd_mach_arm_2a 2 +#define bfd_mach_arm_3 3 +#define bfd_mach_arm_3M 4 +#define bfd_mach_arm_4 5 +#define bfd_mach_arm_4T 6 + bfd_arch_ns32k, /* National Semiconductors ns32000 */ + bfd_arch_w65, /* WDC 65816 */ + bfd_arch_tic30, /* Texas Instruments TMS320C30 */ + bfd_arch_v850, /* NEC V850 */ +#define bfd_mach_v850 0 + bfd_arch_arc, /* Argonaut RISC Core */ +#define bfd_mach_arc_base 0 + bfd_arch_m32r, /* Mitsubishi M32R/D */ +#define bfd_mach_m32r 0 /* backwards compatibility */ + bfd_arch_mn10200, /* Matsushita MN10200 */ + bfd_arch_mn10300, /* Matsushita MN10300 */ + bfd_arch_last + }; + +typedef struct symbol_cache_entry +{ + const char *name; + union + { + PTR p; + bfd_vma i; + } udata; +} asymbol; typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...)); @@ -176,8 +321,10 @@ 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*)); +#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 -- cgit v1.2.3 From ce11fedc6ecb6c6bedcff28e2a5ab3a864267245 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:32:22 +0000 Subject: 64 bit support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@76 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 269 +++++++++++++++++++++++++++++---------------------------------- 1 file changed, 124 insertions(+), 145 deletions(-) diff --git a/dyngen.c b/dyngen.c index 52cabcfab..1eb80328f 100644 --- a/dyngen.c +++ b/dyngen.c @@ -22,25 +22,62 @@ #include #include #include -#include #include #include -#include "thunk.h" +#include "config.h" + +/* 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_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 -/* temporary fix to make it compile with old elf headers (XXX: use - included elf.h in all cases) */ -#ifndef EM_390 -#define EM_S390 22 /* IBM S390 */ -#define R_390_8 1 /* Direct 8 bit. */ -#define R_390_16 3 /* Direct 16 bit. */ -#define R_390_32 4 /* Direct 32 bit. */ +#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 + +#else +#error unsupported CPU - please update the code +#endif + +#if ELF_CLASS == ELFCLASS32 +typedef int32_t host_long; +typedef uint32_t host_ulong; +#else +typedef int64_t host_long; +typedef uint64_t host_ulong; #endif +#include "elf.h" + +#include "thunk.h" + /* all dynamically generated functions begin with this code */ #define OP_PREFIX "op_" -int elf_must_swap(Elf32_Ehdr *h) +int elf_must_swap(struct elfhdr *h) { union { uint32_t i; @@ -62,19 +99,25 @@ void swab32s(uint32_t *p) *p = bswap32(*p); } -void swab64s(uint32_t *p) +void swab64s(uint64_t *p) { *p = bswap64(*p); } -void elf_swap_ehdr(Elf32_Ehdr *h) +#if ELF_CLASS == ELFCLASS32 +#define swabls(x) swab32s(x) +#else +#define swabls(x) swab64s(x) +#endif + +void elf_swap_ehdr(struct elfhdr *h) { swab16s(&h->e_type); /* Object file type */ swab16s(&h-> e_machine); /* Architecture */ swab32s(&h-> e_version); /* Object file version */ - swab32s(&h-> e_entry); /* Entry point virtual address */ - swab32s(&h-> e_phoff); /* Program header table file offset */ - swab32s(&h-> e_shoff); /* Section header table file offset */ + 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 */ @@ -84,34 +127,33 @@ void elf_swap_ehdr(Elf32_Ehdr *h) swab16s(&h-> e_shstrndx); /* Section header string table index */ } -void elf_swap_shdr(Elf32_Shdr *h) +void elf_swap_shdr(struct elf_shdr *h) { swab32s(&h-> sh_name); /* Section name (string tbl index) */ swab32s(&h-> sh_type); /* Section type */ - swab32s(&h-> sh_flags); /* Section flags */ - swab32s(&h-> sh_addr); /* Section virtual addr at execution */ - swab32s(&h-> sh_offset); /* Section file offset */ - swab32s(&h-> sh_size); /* Section size in bytes */ + 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 */ - swab32s(&h-> sh_addralign); /* Section alignment */ - swab32s(&h-> sh_entsize); /* Entry size if section holds table */ + swabls(&h-> sh_addralign); /* Section alignment */ + swabls(&h-> sh_entsize); /* Entry size if section holds table */ } -void elf_swap_phdr(Elf32_Phdr *h) +void elf_swap_phdr(struct elf_phdr *h) { swab32s(&h->p_type); /* Segment type */ - swab32s(&h->p_offset); /* Segment file offset */ - swab32s(&h->p_vaddr); /* Segment virtual address */ - swab32s(&h->p_paddr); /* Segment physical address */ - swab32s(&h->p_filesz); /* Segment size in file */ - swab32s(&h->p_memsz); /* Segment size in memory */ + 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 */ - swab32s(&h->p_align); /* Segment alignment */ + swabls(&h->p_align); /* Segment alignment */ } int do_swap; -int e_machine; uint16_t get16(uint16_t *p) { @@ -157,12 +199,12 @@ void __attribute__((noreturn)) error(const char *fmt, ...) } -Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr, - const char *name) +struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, + const char *name) { int i; const char *shname; - Elf32_Shdr *sec; + struct elf_shdr *sec; for(i = 0; i < shnum; i++) { sec = &shdr[i]; @@ -209,20 +251,21 @@ int strstart(const char *str, const char *val, const char **ptr) #define MAX_ARGS 3 /* generate op code */ -void gen_code(const char *name, unsigned long offset, unsigned long size, - FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type, - Elf32_Sym *symtab, char *strtab, int gen_switch) +void gen_code(const char *name, host_ulong offset, host_ulong size, + FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type, + ElfW(Sym) *symtab, char *strtab, int gen_switch) { int copy_size = 0; uint8_t *p_start, *p_end; - int nb_args, i; + int nb_args, i, n; uint8_t args_present[MAX_ARGS]; const char *sym_name, *p; + ELF_RELOC *rel; /* compute exact size excluding return instruction */ p_start = text + offset; p_end = p_start + size; - switch(e_machine) { + switch(ELF_ARCH) { case EM_386: { uint8_t *p; @@ -256,40 +299,20 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, copy_size = p - p_start; } break; - default: - error("unsupported CPU (%d)", e_machine); } /* compute the number of arguments by looking at the relocations */ for(i = 0;i < MAX_ARGS; i++) args_present[i] = 0; - if (reloc_sh_type == SHT_REL) { - Elf32_Rel *rel; - int n; - for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { - sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; - if (strstart(sym_name, "__op_param", &p)) { - n = strtoul(p, NULL, 10); - if (n >= MAX_ARGS) - error("too many arguments in %s", name); - args_present[n - 1] = 1; - } - } - } - } else { - Elf32_Rela *rel; - int n; - for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { - sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; - if (strstart(sym_name, "__op_param", &p)) { - n = strtoul(p, NULL, 10); - if (n >= MAX_ARGS) - error("too many arguments in %s", name); - args_present[n - 1] = 1; - } + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + n = strtoul(p, NULL, 10); + if (n >= MAX_ARGS) + error("too many arguments in %s", name); + args_present[n - 1] = 1; } } } @@ -319,24 +342,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, } fprintf(outfile, " extern void %s();\n", name); - if (reloc_sh_type == SHT_REL) { - Elf32_Rel *rel; - for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { - sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; - if (!strstart(sym_name, "__op_param", &p)) { - fprintf(outfile, "extern char %s;\n", sym_name); - } - } - } - } else { - Elf32_Rela *rel; - for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { - sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; - if (!strstart(sym_name, "__op_param", &p)) { - fprintf(outfile, "extern char %s;\n", sym_name); - } + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (!strstart(sym_name, "__op_param", &p)) { + fprintf(outfile, "extern char %s;\n", sym_name); } } } @@ -347,13 +357,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, } /* patch relocations */ - switch(e_machine) { - case EM_386: +#if defined(HOST_I386) { - Elf32_Rel *rel; char name[256]; int type; - long addend; + int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; @@ -366,11 +374,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, addend = get32((uint32_t *)(text + rel->r_offset)); switch(type) { case R_386_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", rel->r_offset - offset, name, addend); break; case R_386_PC32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s - (long)(gen_code_ptr + %ld) + %ld;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", rel->r_offset - offset, name, rel->r_offset - offset, addend); break; default: @@ -379,13 +387,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, } } } - break; - case EM_PPC: +#elif defined(HOST_PPC) { - Elf32_Rela *rel; char name[256]; int type; - long addend; + int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; @@ -398,24 +404,24 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, addend = rel->r_addend; switch(type) { case R_PPC_ADDR32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", rel->r_offset - offset, name, addend); break; case R_PPC_ADDR16_LO: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld);\n", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", rel->r_offset - offset, name, addend); break; case R_PPC_ADDR16_HI: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld) >> 16;\n", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", rel->r_offset - offset, name, addend); break; case R_PPC_ADDR16_HA: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld + 0x8000) >> 16;\n", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", rel->r_offset - offset, name, addend); break; case R_PPC_REL24: /* warning: must be at 32 MB distancy */ - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = (*(uint32_t *)(gen_code_ptr + %ld) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %ld) + %ld) & 0x03fffffc);\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend); break; default: @@ -424,13 +430,11 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, } } } - break; - case EM_S390: +#elif defined(HOST_S390) { - Elf32_Rela *rel; char name[256]; int type; - long addend; + int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; @@ -443,15 +447,15 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, addend = rel->r_addend; switch(type) { case R_390_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", rel->r_offset - offset, name, addend); break; case R_390_16: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", rel->r_offset - offset, name, addend); break; case R_390_8: - fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %ld) = %s + %ld;\n", + fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", rel->r_offset - offset, name, addend); break; default: @@ -460,10 +464,9 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, } } } - break; - default: - error("unsupported CPU for relocations (%d)", e_machine); - } +#else +#error unsupported CPU +#endif fprintf(outfile, " gen_code_ptr += %d;\n", copy_size); fprintf(outfile, "}\n"); fprintf(outfile, "break;\n\n"); @@ -492,11 +495,10 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, int load_elf(const char *filename, FILE *outfile, int do_print_enum) { int fd; - Elf32_Ehdr ehdr; - Elf32_Shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec; + struct elfhdr ehdr; + struct elf_shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec; int i, j, nb_syms; - Elf32_Sym *symtab, *sym; - const char *cpu_name; + ElfW(Sym) *symtab, *sym; char *shstr, *strtab; uint8_t *text; void *relocs; @@ -515,7 +517,6 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) || ehdr.e_ident[EI_MAG1] != ELFMAG1 || ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3 - || ehdr.e_ident[EI_CLASS] != ELFCLASS32 || ehdr.e_ident[EI_VERSION] != EV_CURRENT) { error("bad ELF header"); } @@ -523,14 +524,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) 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"); - e_machine = ehdr.e_machine; + 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(Elf32_Shdr)); + 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]); @@ -590,35 +594,12 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) if (do_swap) { for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { swab32s(&sym->st_name); - swab32s(&sym->st_value); - swab32s(&sym->st_size); + swabls(&sym->st_value); + swabls(&sym->st_size); swab16s(&sym->st_shndx); } } - switch(e_machine) { - case EM_386: - cpu_name = "i386"; - break; - case EM_PPC: - cpu_name = "ppc"; - break; - case EM_MIPS: - cpu_name = "mips"; - break; - case EM_ARM: - cpu_name = "arm"; - break; - case EM_SPARC: - cpu_name = "sparc"; - break; - case EM_S390: - cpu_name = "s390"; - break; - default: - error("unsupported CPU (e_machine=%d)", e_machine); - } - if (do_print_enum) { fprintf(outfile, "DEF(end, 0)\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { @@ -669,7 +650,7 @@ fprintf(outfile, ); /* generate a return */ - switch(e_machine) { + switch(ELF_ARCH) { case EM_386: fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n"); break; @@ -679,8 +660,6 @@ fprintf(outfile, case EM_S390: fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n"); break; - default: - error("no return generation for cpu '%s'", cpu_name); } fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n"); -- cgit v1.2.3 From 885705205502e9b9668aa7c38daf54ea1ab0a072 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:32:32 +0000 Subject: more cpu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@77 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf.h | 809 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 708 insertions(+), 101 deletions(-) diff --git a/elf.h b/elf.h index 03f98a348..d87526a7d 100644 --- a/elf.h +++ b/elf.h @@ -1,47 +1,25 @@ -/* - * ELF register definitions.. - */ +#ifndef _ELF_H +#define _ELF_H #include -typedef uint32_t elf_greg_t; - -#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t)) -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -typedef struct user_i387_struct elf_fpregset_t; - -/* - * This is used to ensure we don't load something for the wrong architecture. - */ -#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) - -/* - * These are used to set parameters in the core dumps. - */ -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB; -#define ELF_ARCH EM_386 - - /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program - starts %edx contains a pointer to a function which might be - registered using `atexit'. This provides a mean for the - dynamic linker to call DT_FINI functions for shared libraries - that have been loaded before the code runs. - - A value of 0 tells we have no such handler. */ -#define ELF_PLAT_INIT(_r) _r->edx = 0 - -#define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE 4096 - - -typedef uint32_t Elf32_Addr; +/* 32-bit ELF base types. */ +typedef uint32_t Elf32_Addr; typedef uint16_t Elf32_Half; typedef uint32_t Elf32_Off; typedef int32_t Elf32_Sword; typedef uint32_t Elf32_Word; +/* 64-bit ELF base types. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + /* These constants are for the segment types stored in the image headers */ #define PT_NULL 0 #define PT_LOAD 1 @@ -52,6 +30,13 @@ typedef uint32_t Elf32_Word; #define PT_PHDR 6 #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff +#define PT_MIPS_REGINFO 0x70000000 + +/* Flags in the e_flags field of the header */ +#define EF_MIPS_NOREORDER 0x00000001 +#define EF_MIPS_PIC 0x00000002 +#define EF_MIPS_CPIC 0x00000004 +#define EF_MIPS_ARCH 0xf0000000 /* These constants define the different elf file types */ #define ET_NONE 0 @@ -59,8 +44,8 @@ typedef uint32_t Elf32_Word; #define ET_EXEC 2 #define ET_DYN 3 #define ET_CORE 4 -#define ET_LOPROC 5 -#define ET_HIPROC 6 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff /* These constants define the various ELF target machines */ #define EM_NONE 0 @@ -76,13 +61,31 @@ typedef uint32_t Elf32_Word; #define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ -#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */ - #define EM_PARISC 15 /* HPPA */ #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ #define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC64 */ + +#define EM_ARM 40 /* ARM */ + +#define EM_SH 42 /* SuperH */ + +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ + +#define EM_IA_64 50 /* HP/Intel IA-64 */ + +#define EM_X86_64 62 /* AMD x86-64 */ + +#define EM_S390 22 /* IBM S/390 */ + +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ + +#define EM_V850 87 /* NEC v850 */ + +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ /* * This is an interim value that we will use until the committee comes @@ -90,6 +93,13 @@ typedef uint32_t Elf32_Word; */ #define EM_ALPHA 0x9026 +/* Bogus old v850 magic number, used by old tools. */ +#define EM_CYGNUS_V850 0x9080 + +/* + * This is the old interim value for S/390 architecture + */ +#define EM_S390_OLD 0xA390 /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 @@ -118,6 +128,25 @@ typedef uint32_t Elf32_Word; #define DT_JMPREL 23 #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7fffffff +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 + #define RHF_NONE 0 + #define RHF_HARDWAY 1 + #define RHF_NOTPOT 2 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 /* This info is needed when parsing the symbol table */ #define STB_LOCAL 0 @@ -130,8 +159,12 @@ typedef uint32_t Elf32_Word; #define STT_SECTION 3 #define STT_FILE 4 -#define ELF32_ST_BIND(x) ((x) >> 4) -#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) /* Symbolic values for the entries in the auxiliary table put on the initial stack */ @@ -150,7 +183,9 @@ typedef uint32_t Elf32_Word; #define AT_EUID 12 /* effective uid */ #define AT_GID 13 /* real gid */ #define AT_EGID 14 /* effective gid */ - +#define AT_PLATFORM 15 /* string identifying CPU for optimizations */ +#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ +#define AT_CLKTCK 17 /* frequency at which times() increments */ typedef struct dynamic{ Elf32_Sword d_tag; @@ -161,10 +196,10 @@ typedef struct dynamic{ } Elf32_Dyn; typedef struct { - unsigned long long d_tag; /* entry tag value */ + Elf64_Sxword d_tag; /* entry tag value */ union { - unsigned long long d_val; - unsigned long long d_ptr; + Elf64_Xword d_val; + Elf64_Addr d_ptr; } d_un; } Elf64_Dyn; @@ -172,6 +207,9 @@ typedef struct { #define ELF32_R_SYM(x) ((x) >> 8) #define ELF32_R_TYPE(x) ((x) & 0xff) +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) + #define R_386_NONE 0 #define R_386_32 1 #define R_386_PC32 2 @@ -185,14 +223,559 @@ typedef struct { #define R_386_GOTPC 10 #define R_386_NUM 11 +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 +/* The remaining relocs are defined on Irix, although they are not + in the MIPS ELF ABI. */ +#define R_MIPS_UNUSED1 13 +#define R_MIPS_UNUSED2 14 +#define R_MIPS_UNUSED3 15 +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_GOTHI16 22 +#define R_MIPS_GOTLO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_CALLHI16 30 +#define R_MIPS_CALLLO16 31 +/* + * This range is reserved for vendor specific relocations. + */ +#define R_MIPS_LOVENDOR 100 +#define R_MIPS_HIVENDOR 127 + + +/* + * Sparc ELF relocation types + */ +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 +#define HWCAP_SPARC_ULTRA3 32 + +/* + * 68k ELF relocation types + */ +#define R_68K_NONE 0 +#define R_68K_32 1 +#define R_68K_16 2 +#define R_68K_8 3 +#define R_68K_PC32 4 +#define R_68K_PC16 5 +#define R_68K_PC8 6 +#define R_68K_GOT32 7 +#define R_68K_GOT16 8 +#define R_68K_GOT8 9 +#define R_68K_GOT32O 10 +#define R_68K_GOT16O 11 +#define R_68K_GOT8O 12 +#define R_68K_PLT32 13 +#define R_68K_PLT16 14 +#define R_68K_PLT8 15 +#define R_68K_PLT32O 16 +#define R_68K_PLT16O 17 +#define R_68K_PLT8O 18 +#define R_68K_COPY 19 +#define R_68K_GLOB_DAT 20 +#define R_68K_JMP_SLOT 21 +#define R_68K_RELATIVE 22 + +/* + * Alpha ELF relocation types + */ +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_BRSGP 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 + +#define SHF_ALPHA_GPREL 0x10000000 + + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#define R_PPC_NUM 37 + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_NEW_ABI 0x80 +#define EF_OLD_ABI 0x100 + +/* Additional symbol types for Thumb */ +#define STT_ARM_TFUNC 0xd + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base */ + +/* ARM relocs. */ +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* s390 relocations defined by the ABIs */ +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC rel. offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LD code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LD code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negate offset in static TLS + block. */ +/* Keep this the last entry. */ +#define R_390_NUM 57 + +/* x86-64 relocation types */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + typedef struct elf32_rel { Elf32_Addr r_offset; Elf32_Word r_info; } Elf32_Rel; typedef struct elf64_rel { - unsigned long long r_offset; /* Location at which to apply the action */ - unsigned long long r_info; /* index and type of relocation */ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ } Elf64_Rel; typedef struct elf32_rela{ @@ -202,9 +785,9 @@ typedef struct elf32_rela{ } Elf32_Rela; typedef struct elf64_rela { - unsigned long long r_offset; /* Location at which to apply the action */ - unsigned long long r_info; /* index and type of relocation */ - unsigned long long r_addend; /* Constant addend used to compute value */ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ } Elf64_Rela; typedef struct elf32_sym{ @@ -217,12 +800,12 @@ typedef struct elf32_sym{ } Elf32_Sym; typedef struct elf64_sym { - unsigned int st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Type and binding attributes */ - unsigned char st_other; /* No defined meaning, 0 */ - unsigned short st_shndx; /* Associated section index */ - unsigned long long st_value; /* Value of the symbol */ - unsigned long long st_size; /* Associated symbol size */ + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ } Elf64_Sym; @@ -247,19 +830,19 @@ typedef struct elf32_hdr{ typedef struct elf64_hdr { unsigned char e_ident[16]; /* ELF "magic number" */ - short int e_type; - short unsigned int e_machine; - int e_version; - unsigned long long e_entry; /* Entry point virtual address */ - unsigned long long e_phoff; /* Program header table file offset */ - unsigned long long e_shoff; /* Section header table file offset */ - int e_flags; - short int e_ehsize; - short int e_phentsize; - short int e_phnum; - short int e_shentsize; - short int e_shnum; - short int e_shstrndx; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; } Elf64_Ehdr; /* These constants define the permissions on sections in the program @@ -280,14 +863,14 @@ typedef struct elf32_phdr{ } Elf32_Phdr; typedef struct elf64_phdr { - int p_type; - int p_flags; - unsigned long long p_offset; /* Segment file offset */ - unsigned long long p_vaddr; /* Segment virtual address */ - unsigned long long p_paddr; /* Segment physical address */ - unsigned long long p_filesz; /* Segment size in file */ - unsigned long long p_memsz; /* Segment size in memory */ - unsigned long long p_align; /* Segment alignment, file & memory */ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ } Elf64_Phdr; /* sh_type */ @@ -308,12 +891,17 @@ typedef struct elf64_phdr { #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 #define SHT_HIUSER 0xffffffff +#define SHT_MIPS_LIST 0x70000000 +#define SHT_MIPS_CONFLICT 0x70000002 +#define SHT_MIPS_GPTAB 0x70000003 +#define SHT_MIPS_UCODE 0x70000004 /* sh_flags */ #define SHF_WRITE 0x1 #define SHF_ALLOC 0x2 #define SHF_EXECINSTR 0x4 #define SHF_MASKPROC 0xf0000000 +#define SHF_MIPS_GPREL 0x10000000 /* special section indexes */ #define SHN_UNDEF 0 @@ -323,8 +911,9 @@ typedef struct elf64_phdr { #define SHN_ABS 0xfff1 #define SHN_COMMON 0xfff2 #define SHN_HIRESERVE 0xffff +#define SHN_MIPS_ACCOMON 0xff00 -typedef struct { +typedef struct elf32_shdr { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; @@ -338,16 +927,16 @@ typedef struct { } Elf32_Shdr; typedef struct elf64_shdr { - unsigned int sh_name; /* Section name, index in string tbl */ - unsigned int sh_type; /* Type of section */ - unsigned long long sh_flags; /* Miscellaneous section attributes */ - unsigned long long sh_addr; /* Section virtual addr at execution */ - unsigned long long sh_offset; /* Section file offset */ - unsigned long long sh_size; /* Size of section in bytes */ - unsigned int sh_link; /* Index of another section */ - unsigned int sh_info; /* Additional section information */ - unsigned long long sh_addralign; /* Section alignment */ - unsigned long long sh_entsize; /* Entry size if section holds table */ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; #define EI_MAG0 0 /* e_ident[] indexes */ @@ -384,6 +973,8 @@ typedef struct elf64_shdr { #define NT_PRFPREG 2 #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ + /* Note header in a PT_NOTE section */ typedef struct elf32_note { @@ -393,33 +984,49 @@ typedef struct elf32_note { } Elf32_Nhdr; /* Note header in a PT_NOTE section */ -/* - * For now we use the 32 bit version of the structure until we figure - * out whether we need anything better. Note - on the Alpha, "unsigned int" - * is only 32 bits. - */ typedef struct elf64_note { - unsigned int n_namesz; /* Name size */ - unsigned int n_descsz; /* Content size */ - unsigned int n_type; /* Content type */ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ } Elf64_Nhdr; -#define ELF_START_MMAP 0x80000000 - #if ELF_CLASS == ELFCLASS32 -extern Elf32_Dyn _DYNAMIC []; #define elfhdr elf32_hdr #define elf_phdr elf32_phdr #define elf_note elf32_note +#define elf_shdr elf32_shdr + +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf32_Rela +#else +# define ELF_RELOC Elf32_Rel +#endif #else -extern Elf64_Dyn _DYNAMIC []; #define elfhdr elf64_hdr #define elf_phdr elf64_phdr #define elf_note elf64_note +#define elf_shdr elf64_shdr + +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf64_Rela +#else +# define ELF_RELOC Elf64_Rel +#endif + +#endif /* ELF_CLASS */ +#ifndef ElfW +# if ELF_CLASS == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif #endif +#endif /* _ELF_H */ -- cgit v1.2.3 From 30ac07d4f044975c324933eccc56bbd28a9a8a19 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:33:03 +0000 Subject: moved i386 specific stuff outside elf.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@78 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 386991a49..78d477c03 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -12,6 +12,43 @@ #include "qemu.h" +#ifdef TARGET_I386 + +#define ELF_START_MMAP 0x80000000 + +typedef uint32_t elf_greg_t; + +#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_i387_struct elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts %edx contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ +#define ELF_PLAT_INIT(_r) _r->edx = 0 + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + #include "linux_bin.h" #include "elf.h" #include "segment.h" -- cgit v1.2.3 From d03cda592359edeeb3cfb044071b4107f5e26070 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:33:21 +0000 Subject: alpha fix - powerpc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@79 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/exec-i386.h b/exec-i386.h index 28da51def..b85457704 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -66,6 +66,7 @@ register unsigned int T1 asm("r25"); register unsigned int A0 asm("r26"); register struct CPUX86State *env asm("r27"); #define USE_INT_TO_FLOAT_HELPERS +#define BUGGY_GCC_DIV64 #define reg_EAX #define reg_ECX #define reg_EDX @@ -99,6 +100,12 @@ register unsigned int T1 asm("r8"); register unsigned int A0 asm("r9"); register struct CPUX86State *env asm("r10"); #endif +#ifdef __alpha__ +register unsigned int T0 asm("$9"); +register unsigned int T1 asm("$10"); +register unsigned int A0 asm("$11"); +register struct CPUX86State *env asm("$12"); +#endif /* force GCC to generate only one epilog at the end of the function */ #define FORCE_RET() asm volatile (""); -- cgit v1.2.3 From 7fe70ecc567c8cd51d512a879485ab1048734d5f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:33:40 +0000 Subject: powerpc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@80 c046a42c-6fe2-441c-8c8c-71466251a162 --- ops_template.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ops_template.h b/ops_template.h index 60223fb2f..b734d0f45 100644 --- a/ops_template.h +++ b/ops_template.h @@ -609,6 +609,7 @@ void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) CC_DST = T0; CC_OP = CC_OP_SARB + SHIFT; } + FORCE_RET(); } void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) @@ -643,6 +644,7 @@ void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) CC_DST = T0; CC_OP = CC_OP_SARB + SHIFT; } + FORCE_RET(); } #endif @@ -670,6 +672,7 @@ void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) CC_DST = T0; CC_OP = CC_OP_SHLB + SHIFT; } + FORCE_RET(); } void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) @@ -696,6 +699,7 @@ void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) CC_DST = T0; CC_OP = CC_OP_SARB + SHIFT; } + FORCE_RET(); } #endif -- cgit v1.2.3 From 51fe68905b7638799d32668776a589b546c5fb38 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:34:14 +0000 Subject: powerpc div and rint fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@81 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/op-i386.c b/op-i386.c index 43303784d..323fce33d 100644 --- a/op-i386.c +++ b/op-i386.c @@ -412,6 +412,22 @@ void OPPROTO op_idivw_AX_T0(void) EDX = (EDX & 0xffff0000) | r; } +#ifdef BUGGY_GCC_DIV64 +/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we + call it from another function */ +uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) +{ + *q_ptr = num / den; + return num % den; +} + +int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) +{ + *q_ptr = num / den; + return num % den; +} +#endif + void OPPROTO op_divl_EAX_T0(void) { unsigned int den, q, r; @@ -421,8 +437,12 @@ void OPPROTO op_divl_EAX_T0(void) den = T0; if (den == 0) raise_exception(EXCP00_DIVZ); +#ifdef BUGGY_GCC_DIV64 + r = div64(&q, num, den); +#else q = (num / den); r = (num % den); +#endif EAX = q; EDX = r; } @@ -436,8 +456,12 @@ void OPPROTO op_idivl_EAX_T0(void) den = T0; if (den == 0) raise_exception(EXCP00_DIVZ); +#ifdef BUGGY_GCC_DIV64 + r = idiv64(&q, num, den); +#else q = (num / den); r = (num % den); +#endif EAX = q; EDX = r; } @@ -1503,6 +1527,26 @@ extern CPU86_LDouble floor(CPU86_LDouble x); extern CPU86_LDouble ceil(CPU86_LDouble x); extern CPU86_LDouble rint(CPU86_LDouble x); +#if defined(__powerpc__) +extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble); + +/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ +double qemu_rint(double x) +{ + double y = 4503599627370496.0; + if (fabs(x) >= y) + return x; + if (x < 0) + y = -y; + y = (x + y) - y; + if (y == 0.0) + y = copysign(y, x); + return y; +} + +#define rint qemu_rint +#endif + #define RC_MASK 0xc00 #define RC_NEAR 0x000 #define RC_DOWN 0x400 -- cgit v1.2.3 From 8c8f42f76c3393ca23553fa025357e20c73744f2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:34:27 +0000 Subject: clock_t fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@82 c046a42c-6fe2-441c-8c8c-71466251a162 --- syscall-i386.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/syscall-i386.h b/syscall-i386.h index 9bc35f1ca..dae9be4e1 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -427,8 +427,8 @@ typedef struct target_siginfo { pid_t _pid; /* which child */ uid_t _uid; /* sender's uid */ int _status; /* exit code */ - clock_t _utime; - clock_t _stime; + target_clock_t _utime; + target_clock_t _stime; } _sigchld; /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ -- cgit v1.2.3 From 9af9eaaa76b9b1613d84cb3c0b7276984e441f83 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:34:41 +0000 Subject: endian fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@83 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 16958be80..484291410 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -85,6 +85,10 @@ long do_rt_sigreturn(CPUX86State *env); #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo +#ifdef __alpha__ +#define __NR__llseek __NR_lseek +#endif + #ifdef __NR_gettid _syscall0(int, gettid) #else @@ -1853,7 +1857,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct target_stat *target_st = (void *)arg2; target_st->st_dev = tswap16(st.st_dev); target_st->st_ino = tswapl(st.st_ino); - target_st->st_mode = tswap16(st.st_mode); + target_st->st_mode = tswap32(st.st_mode); target_st->st_nlink = tswap16(st.st_nlink); target_st->st_uid = tswap16(st.st_uid); target_st->st_gid = tswap16(st.st_gid); @@ -2244,7 +2248,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct target_stat64 *target_st = (void *)arg2; target_st->st_dev = tswap16(st.st_dev); target_st->st_ino = tswapl(st.st_ino); - target_st->st_mode = tswap16(st.st_mode); + target_st->st_mode = tswap32(st.st_mode); target_st->st_nlink = tswap16(st.st_nlink); target_st->st_uid = tswap16(st.st_uid); target_st->st_gid = tswap16(st.st_gid); -- cgit v1.2.3 From d0cd3b8d84172d6a7a365e41806e37868067b2aa Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:35:13 +0000 Subject: 64 bit fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@84 c046a42c-6fe2-441c-8c8c-71466251a162 --- thunk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thunk.c b/thunk.c index c2fd44cae..f28a976cd 100644 --- a/thunk.c +++ b/thunk.c @@ -218,7 +218,7 @@ const argtype *thunk_convert(void *dst, const void *src, case TYPE_LONG: case TYPE_ULONG: case TYPE_PTRVOID: - if (target_to_host) { + if (to_host) { *(uint64_t *)dst = tswap32(*(uint32_t *)src); } else { *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff); -- cgit v1.2.3 From 27c75a9a906e4ae2b362a35501a88a3e70fe773e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Apr 2003 21:35:21 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@85 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 9 +++++++++ Makefile | 13 +++++++++---- TODO | 6 +++--- VERSION | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Changelog b/Changelog index 2a76e092a..18176c87c 100644 --- a/Changelog +++ b/Changelog @@ -1,9 +1,18 @@ +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: diff --git a/Makefile b/Makefile index e6d1dedc2..96810cae3 100644 --- a/Makefile +++ b/Makefile @@ -13,14 +13,20 @@ OP_CFLAGS+= -falign-functions=0 else OP_CFLAGS+= -malign-functions=0 endif +# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object +# that the kernel ELF loader considers as an executable. I think this +# is the simplest way to make it self virtualizable! +LDFLAGS+=-Wl,-shared endif ifeq ($(ARCH),ppc) OP_CFLAGS=$(CFLAGS) +LDFLAGS+=-Wl,-T,ppc.ld endif ifeq ($(ARCH),s390) OP_CFLAGS=$(CFLAGS) +LDFLAGS+=-Wl,-T,s390.ld endif ifeq ($(GCC_MAJOR),3) @@ -31,7 +37,6 @@ endif ######################################################### DEFINES+=-D_GNU_SOURCE -LDSCRIPT=$(ARCH).ld LIBS+=-lm # profiling code @@ -51,7 +56,7 @@ LIBOBJS+=i386-dis.o dis-buf.o all: qemu qemu-doc.html qemu: $(OBJS) - $(CC) -Wl,-T,$(LDSCRIPT) $(LDFLAGS) -o $@ $^ $(LIBS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend @@ -103,9 +108,9 @@ dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ Makefile elf.h linux_bin.h segment.h thunk.c\ elfload.c main.c signal.c thunk.h\ cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ -dis-asm.h gen-i386.h op-i386.h syscall.c\ +dis-asm.h gen-i386.h syscall.c\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ -i386.ld ppc.ld s390.ld exec-i386.h exec-i386.c configure \ +ppc.ld s390.ld exec-i386.h exec-i386.c configure \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h tests/test-i386-code16.S\ diff --git a/TODO b/TODO index 9f266514b..eb79f2b48 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,11 @@ - fix thread locks -- fix thread stack liberation -- fix x86 stack allocation - optimize translated cache chaining (DLL PLT-like system) +- fix thread stack liberation (use kernel 2.5.xxx CLONE_CHILD_CLEARTID) +- fix x86 stack allocation +- fix iret/lret restarting - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues, fix 16 bit uid issues) - finish signal handing (fp87 state, more siginfo conversions) - verify thread support (clone() and various locks) -- overrides/16bit for string ops - make it self runnable (use same trick as ld.so : include its own relocator and libc) - fix FPU exceptions (in particular: gen_op_fpush not before mem load) diff --git a/VERSION b/VERSION index 446ba66e7..def9a0154 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.4 \ No newline at end of file +0.1.5 \ No newline at end of file -- cgit v1.2.3 From bb0ebb1f2dc4b7f48027f622db2b58d27dcd5055 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Apr 2003 00:02:33 +0000 Subject: ISO C fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@86 c046a42c-6fe2-441c-8c8c-71466251a162 --- i386-dis.c | 5 +++-- thunk.h | 18 +++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/i386-dis.c b/i386-dis.c index 0a63294f7..a11bdf11d 100644 --- a/i386-dis.c +++ b/i386-dis.c @@ -33,12 +33,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ * the Intel manual for details. */ +#include +#include + #include "dis-asm.h" #define MAXLEN 20 -#include - static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); struct dis_private diff --git a/thunk.h b/thunk.h index 017cfe357..2fa3f63ac 100644 --- a/thunk.h +++ b/thunk.h @@ -94,17 +94,17 @@ static inline uint64_t bswap64(uint64_t x) return bswap_64(x); } -static void inline bswap16s(uint16_t *s) +static inline void bswap16s(uint16_t *s) { *s = bswap16(*s); } -static void inline bswap32s(uint32_t *s) +static inline void bswap32s(uint32_t *s) { *s = bswap32(*s); } -static void inline bswap64s(uint64_t *s) +static inline void bswap64s(uint64_t *s) { *s = bswap64(*s); } @@ -126,17 +126,17 @@ static inline uint64_t tswap64(uint64_t s) return bswap64(s); } -static void inline tswap16s(uint16_t *s) +static inline void tswap16s(uint16_t *s) { *s = bswap16(*s); } -static void inline tswap32s(uint32_t *s) +static inline void tswap32s(uint32_t *s) { *s = bswap32(*s); } -static void inline tswap64s(uint64_t *s) +static inline void tswap64s(uint64_t *s) { *s = bswap64(*s); } @@ -158,15 +158,15 @@ static inline uint64_t tswap64(uint64_t s) return s; } -static void inline tswap16s(uint16_t *s) +static inline void tswap16s(uint16_t *s) { } -static void inline tswap32s(uint32_t *s) +static inline void tswap32s(uint32_t *s) { } -static void inline tswap64s(uint64_t *s) +static inline void tswap64s(uint64_t *s) { } -- cgit v1.2.3 From 66cd58461daa688d0639c83c960e4b871a09f005 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Apr 2003 00:02:58 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@87 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changelog b/Changelog index 18176c87c..a451cfa6d 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +version 0.1.6: + + - ISO C warning fixes (Alistair Strachan) + - first self-virtualizable version (works only as long as the icache + is not flushed) + version 0.1.5: - ppc64 support + personality() patch (Rusty Russell) -- cgit v1.2.3 From 2677e107e69b0533356ba833f04a826e8589f383 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Apr 2003 00:03:27 +0000 Subject: warning fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@88 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-user/signal.c b/linux-user/signal.c index 6a81b11cd..5ed1d8532 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 09bfb054fb4d7a72b4989141de157cdeda6704bd Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Apr 2003 00:03:40 +0000 Subject: first self virtualizable version git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@89 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- TODO | 3 +- linux-user/elfload.c | 316 ++++++++++++++++++++++++++++++++++----------------- linux-user/main.c | 1 - 4 files changed, 217 insertions(+), 105 deletions(-) diff --git a/Makefile b/Makefile index 96810cae3..f6d1e2715 100644 --- a/Makefile +++ b/Makefile @@ -105,7 +105,7 @@ qemu-doc.html: qemu-doc.texi FILES= \ README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ -Makefile elf.h linux_bin.h segment.h thunk.c\ +Makefile elf.h thunk.c\ elfload.c main.c signal.c thunk.h\ cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ dis-asm.h gen-i386.h syscall.c\ diff --git a/TODO b/TODO index eb79f2b48..66ecfea39 100644 --- a/TODO +++ b/TODO @@ -7,5 +7,6 @@ issues, fix 16 bit uid issues) - finish signal handing (fp87 state, more siginfo conversions) - verify thread support (clone() and various locks) -- make it self runnable (use same trick as ld.so : include its own relocator and libc) +- make it self runnable (handle self modifying code, relocate stack + and dyn loader) - fix FPU exceptions (in particular: gen_op_fpush not before mem load) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 78d477c03..c692ea371 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -49,9 +49,78 @@ typedef struct user_i387_struct elf_fpregset_t; #endif -#include "linux_bin.h" #include "elf.h" -#include "segment.h" + +/* + * MAX_ARG_PAGES defines the number of pages allocated for arguments + * and envelope for the new program. 32 should suffice, this gives + * a maximum env+arg of 128kB w/4KB pages! + */ +#define MAX_ARG_PAGES 32 + +/* + * This structure is used to hold the arguments that are + * used when loading binaries. + */ +struct linux_binprm { + char buf[128]; + unsigned long page[MAX_ARG_PAGES]; + unsigned long p; + int sh_bang; + int fd; + int e_uid, e_gid; + int argc, envc; + char * interp_prefix; /* prefix for interpreter */ + char * filename; /* Name of binary */ + unsigned long loader, exec; + int dont_iput; /* binfmt handler has put inode */ +}; + +struct exec +{ + unsigned int a_info; /* Use macros N_MAGIC, etc for access */ + unsigned int a_text; /* length of text, in bytes */ + unsigned int a_data; /* length of data, in bytes */ + unsigned int a_bss; /* length of uninitialized data area, in bytes */ + unsigned int a_syms; /* length of symbol table data in file, in bytes */ + unsigned int a_entry; /* start address */ + unsigned int a_trsize; /* length of relocation info for text, in bytes */ + unsigned int a_drsize; /* length of relocation info for data, in bytes */ +}; + + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 + +#define X86_STACK_TOP 0x7d000000 + +/* max code+data+bss space allocated to elf interpreter */ +#define INTERP_MAP_SIZE (32 * 1024 * 1024) + +/* max code+data+bss+brk space allocated to ET_DYN executables */ +#define ET_DYN_MAP_SIZE (128 * 1024 * 1024) + +/* from personality.h */ + +/* Flags for bug emulation. These occupy the top three bytes. */ +#define STICKY_TIMEOUTS 0x4000000 +#define WHOLE_SECONDS 0x2000000 + +/* Personality types. These go in the low byte. Avoid using the top bit, + * it will conflict with error returns. + */ +#define PER_MASK (0x00ff) +#define PER_LINUX (0x0000) +#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) +#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) +#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) +#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) +#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) +#define PER_BSD (0x0006) +#define PER_XENIX (0x0007 | STICKY_TIMEOUTS) /* Necessary parameters */ #define ALPHA_PAGE_SIZE 4096 @@ -78,8 +147,18 @@ typedef struct user_i387_struct elf_fpregset_t; #define DLINFO_ITEMS 12 -/* Where we find X86 libraries... */ +#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) +#define get_user(ptr) (typeof(*ptr))(*(ptr)) + +static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) +{ + memcpy(to, from, n); +} +static inline void memcpy_tofs(void * to, const void * from, unsigned long n) +{ + memcpy(to, from, n); +} //extern void * mmap4k(); #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) @@ -282,43 +361,35 @@ static int prepare_binprm(struct linux_binprm *bprm) unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, struct image_info * info) { - unsigned long stack_base; + unsigned long stack_base, size, error; int i; - extern unsigned long stktop; - stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE; + /* Create enough stack to hold everything. If we don't use + * it for args, we'll use it for something else... + */ + size = x86_stack_size; + if (size < MAX_ARG_PAGES*X86_PAGE_SIZE) + size = MAX_ARG_PAGES*X86_PAGE_SIZE; + error = (unsigned long)mmap4k(NULL, + size + X86_PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (error == -1) { + perror("stk mmap"); + exit(-1); + } + /* we reserve one extra page at the top of the stack as guard */ + mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE); + stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE; p += stack_base; + if (bprm->loader) { bprm->loader += stack_base; } bprm->exec += stack_base; - /* Create enough stack to hold everything. If we don't use - * it for args, we'll use it for something else... - */ - /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so - we allocate a bigger stack. Need a better solution, for example - by remapping the process stack directly at the right place */ - if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) { - if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { - perror("stk mmap"); - exit(-1); - } - } - else { - if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { - perror("stk mmap"); - exit(-1); - } - } - - stktop = stack_base; - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { info->rss++; @@ -369,10 +440,11 @@ static void padzero(unsigned long elf_bss) } static unsigned int * create_elf_tables(char *p, int argc, int envc, - struct elfhdr * exec, - unsigned long load_addr, - unsigned long interp_load_addr, int ibcs, - struct image_info *info) + struct elfhdr * exec, + unsigned long load_addr, + unsigned long load_bias, + unsigned long interp_load_addr, int ibcs, + struct image_info *info) { target_ulong *argv, *envp, *dlinfo; target_ulong *sp; @@ -397,17 +469,17 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, put_user (tswapl(val), dlinfo++) if (exec) { /* Put this here for an ELF program interpreter */ - NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff)); - NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr))); - NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum)); - NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE)); - NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr)); - NEW_AUX_ENT (AT_FLAGS, (unsigned int)0); - NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry); - NEW_AUX_ENT (AT_UID, (unsigned int) getuid()); - NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid()); - NEW_AUX_ENT (AT_GID, (unsigned int) getgid()); - NEW_AUX_ENT (AT_EGID, (unsigned int) getegid()); + NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); + NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); + NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE)); + NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); + NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); + NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT (AT_UID, (target_ulong) getuid()); + NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid()); + NEW_AUX_ENT (AT_GID, (target_ulong) getgid()); + NEW_AUX_ENT (AT_EGID, (target_ulong) getegid()); } NEW_AUX_ENT (AT_NULL, 0); #undef NEW_AUX_ENT @@ -436,7 +508,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, { struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; - unsigned long load_addr; + unsigned long load_addr = 0; int load_addr_set = 0; int retval; unsigned long last_bss, elf_bss; @@ -447,17 +519,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, last_bss = 0; error = 0; - /* We put this here so that mmap will search for the *first* - * available memory... - */ - load_addr = INTERP_LOADADDR; - #ifdef BSWAP_NEEDED bswap_ehdr(interp_elf_ex); #endif /* First of all, some simple consistency checks */ if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || + interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine)) { return ~0UL; } @@ -478,11 +545,10 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, * If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) - { + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { free(elf_phdata); return ~0UL; - } + } retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); if(retval >= 0) { @@ -502,6 +568,21 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, bswap_phdr(eppnt); } #endif + + if (interp_elf_ex->e_type == ET_DYN) { + /* in order to avoid harcoding the interpreter load + address in qemu, we allocate a big enough memory zone */ + error = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); + } + load_addr = error; + load_addr_set = 1; + } + eppnt = elf_phdata; for(i=0; ie_phnum; i++, eppnt++) if (eppnt->p_type == PT_LOAD) { @@ -585,7 +666,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r struct elfhdr interp_elf_ex; struct exec interp_ex; int interpreter_fd = -1; /* avoid warning */ - unsigned long load_addr; + unsigned long load_addr, load_bias; int load_addr_set = 0; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; @@ -605,6 +686,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r ibcs2_interpreter = 0; status = 0; load_addr = 0; + load_bias = 0; elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ #ifdef BSWAP_NEEDED bswap_ehdr(&elf_ex); @@ -810,56 +892,86 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r * address. */ - - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { - if (elf_ppnt->p_type == PT_LOAD) { - int elf_prot = 0; - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - - mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr), - (elf_ppnt->p_filesz + - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), - elf_prot, - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), - bprm->fd, - (elf_ppnt->p_offset - - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - - if((unsigned long)mapped_addr == 0xffffffffffffffff) { - perror("mmap"); - exit(-1); - } - - + int elf_prot = 0; + int elf_flags = 0; + unsigned long error; + + if (elf_ppnt->p_type != PT_LOAD) + continue; + + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; + if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + elf_flags = MAP_PRIVATE | MAP_DENYWRITE; + if (elf_ex.e_type == ET_EXEC || load_addr_set) { + elf_flags |= MAP_FIXED; + } else if (elf_ex.e_type == ET_DYN) { + /* Try and get dynamic programs out of the way of the default mmap + base, as well as whatever program they might try to exec. This + is because the brk will follow the loader, and is not movable. */ + /* NOTE: for qemu, we do a big mmap to get enough space + without harcoding any address */ + error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); + } + load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr); + } + + error = (unsigned long)mmap4k( + X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), + bprm->fd, + (elf_ppnt->p_offset - + X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + if (error == -1) { + perror("mmap"); + exit(-1); + } #ifdef LOW_ELF_STACK - if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) - elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); + if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); #endif - - if (!load_addr_set) { - load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; - load_addr_set = 1; - } - k = elf_ppnt->p_vaddr; - if (k < start_code) start_code = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if (k > elf_bss) elf_bss = k; -#if 1 - if ((elf_ppnt->p_flags & PF_X) && end_code < k) -#else - if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) -#endif - end_code = k; - if (end_data < k) end_data = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) elf_brk = k; - } + + if (!load_addr_set) { + load_addr_set = 1; + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; + if (elf_ex.e_type == ET_DYN) { + load_bias += error - + X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); + load_addr += load_bias; + } + } + k = elf_ppnt->p_vaddr; + if (k < start_code) + start_code = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + if ((elf_ppnt->p_flags & PF_X) && end_code < k) + end_code = k; + if (end_data < k) + end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + if (k > elf_brk) elf_brk = k; } + elf_entry += load_bias; + elf_bss += load_bias; + elf_brk += load_bias; + start_code += load_bias; + end_code += load_bias; + // start_data += load_bias; + end_data += load_bias; + if (elf_interpreter) { if (interpreter_type & 1) { elf_entry = load_aout_interp(&interp_ex, interpreter_fd); @@ -893,7 +1005,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r bprm->argc, bprm->envc, (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), - load_addr, + load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1), info); diff --git a/linux-user/main.c b/linux-user/main.c index d7c68a9cd..0c8480dff 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -47,7 +47,6 @@ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; we allocate a bigger stack. Need a better solution, for example by remapping the process stack directly at the right place */ unsigned long x86_stack_size = 512 * 1024; -unsigned long stktop; void gemu_log(const char *fmt, ...) { -- cgit v1.2.3 From f29042b5312f7ec97ec7ca678ccbea8997a817c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Apr 2003 00:12:45 +0000 Subject: TIOCGPTN and TIOCSPTLCK ioctls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@90 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ioctls.h | 2 ++ syscall-i386.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index b9aadb7a5..b4bfb3ab6 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -37,6 +37,8 @@ IOCTL(TIOCNOTTY, 0, TYPE_NULL) IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT)) IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT)) IOCTL(FIOCLEX, 0, TYPE_NULL) IOCTL(FIONCLEX, 0, TYPE_NULL) IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT)) diff --git a/syscall-i386.h b/syscall-i386.h index dae9be4e1..f77b55b0a 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -572,8 +572,8 @@ struct target_pt_regs { #define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ #define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ #define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ #define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define TARGET_FIOCLEX 0x5451 -- cgit v1.2.3 From afeb6ee3772edd18ad4b2b17abf57578ee91a9a3 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Apr 2003 00:12:54 +0000 Subject: suppressed undefined shldw shrdw git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@91 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386-shift.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test-i386-shift.h b/tests/test-i386-shift.h index f3795d9f3..c3d8793b8 100644 --- a/tests/test-i386-shift.h +++ b/tests/test-i386-shift.h @@ -108,7 +108,12 @@ void exec_opb(int s0, int s1, int iflags) void exec_op(int s2, int s0, int s1) { exec_opl(s2, s0, s1, 0); +#ifdef OP_SHIFTD + if (s1 <= 15) + exec_opw(s2, s0, s1, 0); +#else exec_opw(s2, s0, s1, 0); +#endif #ifndef OP_NOBYTE exec_opb(s0, s1, 0); #endif -- cgit v1.2.3 From 7fb9a24e3925cecc4b6e4a47a27c2caba077b2f6 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Apr 2003 00:13:04 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@92 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/.cvsignore | 28 ++++++++++ tests/Makefile | 6 ++- tests/runcom.c | 7 +++ tests/test_path.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/testclone.c | 1 + tests/testthread.c | 1 + 6 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 tests/.cvsignore create mode 100644 tests/test_path.c diff --git a/tests/.cvsignore b/tests/.cvsignore new file mode 100644 index 000000000..9b6d5179c --- /dev/null +++ b/tests/.cvsignore @@ -0,0 +1,28 @@ + gmon.out + testsig + hello + sha1.test.c + sha1.c + op.c + test-i386 + sha1 + testclone + interp.h + interploop.c + .gdb_history + cachegrind.out + interp.c + interp + testthread + test-i386.s + test-i386.ref + sha1-i386 + runcom + debug.com + test-i386.out + speed.txt + test-i386.ref.P3 + pi_10.com + test-i386.ref.P4 + ldso.c + test_path diff --git a/tests/Makefile b/tests/Makefile index 8a5ed4cfc..386cb3c16 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -6,7 +6,7 @@ LDFLAGS= ifeq ($(ARCH),i386) TESTS=testclone testsig testthread sha1-i386 test-i386 runcom endif -TESTS+=sha1 +TESTS+=sha1 test_path QEMU=../qemu @@ -25,6 +25,10 @@ testsig: testsig.c testthread: testthread.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread +test_path: test_path.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + ./$@ || { rm $@; exit 1; } + # i386 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h diff --git a/tests/runcom.c b/tests/runcom.c index 2d41341c5..4c83de069 100644 --- a/tests/runcom.c +++ b/tests/runcom.c @@ -3,6 +3,7 @@ */ #include #include +#include #include #include #include @@ -14,6 +15,12 @@ //#define SIGTEST +#undef __syscall_return +#define __syscall_return(type, res) \ +do { \ + return (type) (res); \ +} while (0) + _syscall2(int, vm86, int, func, struct vm86plus_struct *, v86) #define COM_BASE_ADDR 0x10100 diff --git a/tests/test_path.c b/tests/test_path.c new file mode 100644 index 000000000..a9b52de37 --- /dev/null +++ b/tests/test_path.c @@ -0,0 +1,152 @@ +/* Test path override code */ +#define _GNU_SOURCE +#include "../path.c" +#include +#include +#include + +/* Any log message kills the test. */ +void gemu_log(const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "FATAL: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +#define NO_CHANGE(_path) \ + do { \ + if (strcmp(path(_path), _path) != 0) return __LINE__; \ + } while(0) + +#define CHANGE_TO(_path, _newpath) \ + do { \ + if (strcmp(path(_path), _newpath) != 0) return __LINE__; \ + } while(0) + +static void cleanup(void) +{ + unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE"); + unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE2"); + unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE3"); + unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE4"); + unlink("/tmp/qemu-test_path/DIR1/DIR2/FILE5"); + rmdir("/tmp/qemu-test_path/DIR1/DIR2"); + rmdir("/tmp/qemu-test_path/DIR1/DIR3"); + rmdir("/tmp/qemu-test_path/DIR1"); + rmdir("/tmp/qemu-test_path"); +} + +static unsigned int do_test(void) +{ + if (mkdir("/tmp/qemu-test_path", 0700) != 0) + return __LINE__; + + if (mkdir("/tmp/qemu-test_path/DIR1", 0700) != 0) + return __LINE__; + + if (mkdir("/tmp/qemu-test_path/DIR1/DIR2", 0700) != 0) + return __LINE__; + + if (mkdir("/tmp/qemu-test_path/DIR1/DIR3", 0700) != 0) + return __LINE__; + + if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE", 0600)) != 0) + return __LINE__; + + if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE2", 0600)) != 0) + return __LINE__; + + if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE3", 0600)) != 0) + return __LINE__; + + if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE4", 0600)) != 0) + return __LINE__; + + if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE5", 0600)) != 0) + return __LINE__; + + init_paths("/tmp/qemu-test_path"); + + NO_CHANGE("/tmp"); + NO_CHANGE("/tmp/"); + NO_CHANGE("/tmp/qemu-test_path"); + NO_CHANGE("/tmp/qemu-test_path/"); + NO_CHANGE("/tmp/qemu-test_path/D"); + NO_CHANGE("/tmp/qemu-test_path/DI"); + NO_CHANGE("/tmp/qemu-test_path/DIR"); + NO_CHANGE("/tmp/qemu-test_path/DIR1"); + NO_CHANGE("/tmp/qemu-test_path/DIR1/"); + + NO_CHANGE("/D"); + NO_CHANGE("/DI"); + NO_CHANGE("/DIR"); + NO_CHANGE("/DIR2"); + NO_CHANGE("/DIR1."); + + CHANGE_TO("/DIR1", "/tmp/qemu-test_path/DIR1"); + CHANGE_TO("/DIR1/", "/tmp/qemu-test_path/DIR1"); + + NO_CHANGE("/DIR1/D"); + NO_CHANGE("/DIR1/DI"); + NO_CHANGE("/DIR1/DIR"); + NO_CHANGE("/DIR1/DIR1"); + + CHANGE_TO("/DIR1/DIR2", "/tmp/qemu-test_path/DIR1/DIR2"); + CHANGE_TO("/DIR1/DIR2/", "/tmp/qemu-test_path/DIR1/DIR2"); + + CHANGE_TO("/DIR1/DIR3", "/tmp/qemu-test_path/DIR1/DIR3"); + CHANGE_TO("/DIR1/DIR3/", "/tmp/qemu-test_path/DIR1/DIR3"); + + NO_CHANGE("/DIR1/DIR2/F"); + NO_CHANGE("/DIR1/DIR2/FI"); + NO_CHANGE("/DIR1/DIR2/FIL"); + NO_CHANGE("/DIR1/DIR2/FIL."); + + CHANGE_TO("/DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + CHANGE_TO("/DIR1/DIR2/FILE2", "/tmp/qemu-test_path/DIR1/DIR2/FILE2"); + CHANGE_TO("/DIR1/DIR2/FILE3", "/tmp/qemu-test_path/DIR1/DIR2/FILE3"); + CHANGE_TO("/DIR1/DIR2/FILE4", "/tmp/qemu-test_path/DIR1/DIR2/FILE4"); + CHANGE_TO("/DIR1/DIR2/FILE5", "/tmp/qemu-test_path/DIR1/DIR2/FILE5"); + + NO_CHANGE("/DIR1/DIR2/FILE6"); + NO_CHANGE("/DIR1/DIR2/FILE/X"); + + CHANGE_TO("/DIR1/../DIR1", "/tmp/qemu-test_path/DIR1"); + CHANGE_TO("/DIR1/../DIR1/", "/tmp/qemu-test_path/DIR1"); + CHANGE_TO("/../DIR1", "/tmp/qemu-test_path/DIR1"); + CHANGE_TO("/../DIR1/", "/tmp/qemu-test_path/DIR1"); + CHANGE_TO("/DIR1/DIR2/../DIR2", "/tmp/qemu-test_path/DIR1/DIR2"); + CHANGE_TO("/DIR1/DIR2/../DIR2/../../DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + CHANGE_TO("/DIR1/DIR2/../DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + + NO_CHANGE("/DIR1/DIR2/../DIR1"); + NO_CHANGE("/DIR1/DIR2/../FILE"); + + CHANGE_TO("/./DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + CHANGE_TO("/././DIR1/DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + CHANGE_TO("/DIR1/./DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + CHANGE_TO("/DIR1/././DIR2/FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + CHANGE_TO("/DIR1/DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + CHANGE_TO("/DIR1/DIR2/././FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + CHANGE_TO("/./DIR1/./DIR2/./FILE", "/tmp/qemu-test_path/DIR1/DIR2/FILE"); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret; + + ret = do_test(); + cleanup(); + if (ret) { + fprintf(stderr, "test_path: failed on line %i\n", ret); + return 1; + } + return 0; +} + diff --git a/tests/testclone.c b/tests/testclone.c index 2152dfcf2..531bd5c61 100644 --- a/tests/testclone.c +++ b/tests/testclone.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/tests/testthread.c b/tests/testthread.c index 9a590dbd4..27e4825bc 100644 --- a/tests/testthread.c +++ b/tests/testthread.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From 74cd30b811cc2fe4b376bc1c0fa2cf48810d5103 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Apr 2003 00:13:41 +0000 Subject: RH9 fix - path patch git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@93 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 0c8480dff..5c1dd8ce9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -23,9 +23,6 @@ #include #include #include -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) -#include -#endif #include "qemu.h" @@ -35,12 +32,22 @@ FILE *logfile = NULL; int loglevel; -const char *interp_prefix = CONFIG_QEMU_PREFIX "/qemu-i386"; +static const char *interp_prefix = CONFIG_QEMU_PREFIX; #ifdef __i386__ /* Force usage of an ELF interpreter even if it is an ELF shared object ! */ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; + +/* for recent libc, we add these dummies symbol which are not declared + when generating a linked object (bug in ld ?) */ +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +long __init_array_start[0]; +long __init_array_end[0]; +long __fini_array_start[0]; +long __fini_array_end[0]; +#endif + #endif /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so @@ -358,7 +365,7 @@ void usage(void) DEBUG_LOGFILE, interp_prefix, x86_stack_size); - exit(1); + _exit(1); } /* XXX: currently only used for async signals (see signal.c) */ @@ -379,12 +386,6 @@ int main(int argc, char **argv) if (argc <= 1) usage(); - /* Set personality to X86_LINUX. May fail on unpatched kernels: - if so, they need to have munged paths themselves (eg. chroot, - hacked ld.so, whatever). */ - if (personality(0x11) >= 0) - interp_prefix = ""; - loglevel = 0; optind = 1; for(;;) { @@ -423,7 +424,7 @@ int main(int argc, char **argv) logfile = fopen(DEBUG_LOGFILE, "w"); if (!logfile) { perror(DEBUG_LOGFILE); - exit(1); + _exit(1); } setvbuf(logfile, NULL, _IOLBF, 0); } @@ -434,9 +435,12 @@ int main(int argc, char **argv) /* Zero out image_info */ memset(info, 0, sizeof(struct image_info)); - if(elf_exec(interp_prefix, filename, argv+optind, environ, regs, info) != 0) { + /* Scan interp_prefix dir for replacement files. */ + init_paths(interp_prefix); + + if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { printf("Error loading %s\n", filename); - exit(1); + _exit(1); } if (loglevel) { -- cgit v1.2.3 From 1d346ae63a2d132c5fa5f7576553abf4e58eb85f Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Apr 2003 00:14:24 +0000 Subject: added prefix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@94 c046a42c-6fe2-441c-8c8c-71466251a162 --- syscall-i386.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syscall-i386.h b/syscall-i386.h index f77b55b0a..d8fa444c9 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -302,7 +302,7 @@ struct target_stat64 { unsigned short st_dev; unsigned char __pad0[10]; -#define STAT64_HAS_BROKEN_ST_INO 1 +#define TARGET_STAT64_HAS_BROKEN_ST_INO 1 target_ulong __st_ino; unsigned int st_mode; -- cgit v1.2.3 From ec86b0fb3aa854ea8cec28df15cbd43f30d21519 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Apr 2003 00:15:04 +0000 Subject: stat patches - path patches - added exit_group() syscall git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@95 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 484291410..ca52eb4e9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -105,6 +105,9 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, _syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf) _syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf) _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) +#ifdef __NR_exit_group +_syscall1(int,exit_group,int,error_code) +#endif extern int personality(int); extern int flock(int, int); @@ -1212,7 +1215,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(write(arg1, (void *)arg2, arg3)); break; case TARGET_NR_open: - ret = get_errno(open((const char *)arg1, arg2, arg3)); + ret = get_errno(open(path((const char *)arg1), arg2, arg3)); break; case TARGET_NR_close: ret = get_errno(close(arg1)); @@ -1700,7 +1703,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_oldlstat: goto unimplemented; case TARGET_NR_readlink: - ret = get_errno(readlink((const char *)arg1, (char *)arg2, arg3)); + ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3)); break; case TARGET_NR_uselib: goto unimplemented; @@ -1779,7 +1782,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; case TARGET_NR_statfs: stfs = (void *)arg2; - ret = get_errno(sys_statfs((const char *)arg1, stfs)); + ret = get_errno(sys_statfs(path((const char *)arg1), stfs)); convert_statfs: if (!is_error(ret)) { tswap32s(&stfs->f_type); @@ -1844,10 +1847,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_stat: - ret = get_errno(stat((const char *)arg1, &st)); + ret = get_errno(stat(path((const char *)arg1), &st)); goto do_stat; case TARGET_NR_lstat: - ret = get_errno(lstat((const char *)arg1, &st)); + ret = get_errno(lstat(path((const char *)arg1), &st)); goto do_stat; case TARGET_NR_fstat: { @@ -1857,7 +1860,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct target_stat *target_st = (void *)arg2; target_st->st_dev = tswap16(st.st_dev); target_st->st_ino = tswapl(st.st_ino); - target_st->st_mode = tswap32(st.st_mode); + target_st->st_mode = tswap16(st.st_mode); target_st->st_nlink = tswap16(st.st_nlink); target_st->st_uid = tswap16(st.st_uid); target_st->st_gid = tswap16(st.st_gid); @@ -1930,6 +1933,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_clone: ret = get_errno(do_fork(cpu_env, arg1, arg2)); break; +#ifdef __NR_exit_group + /* new thread calls */ + case TARGET_NR_exit_group: + ret = get_errno(exit_group(arg1)); + break; +#endif case TARGET_NR_setdomainname: ret = get_errno(setdomainname((const char *)arg1, arg2)); break; @@ -2235,10 +2244,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_ftruncate64: goto unimplemented; case TARGET_NR_stat64: - ret = get_errno(stat((const char *)arg1, &st)); + ret = get_errno(stat(path((const char *)arg1), &st)); goto do_stat64; case TARGET_NR_lstat64: - ret = get_errno(lstat((const char *)arg1, &st)); + ret = get_errno(lstat(path((const char *)arg1), &st)); goto do_stat64; case TARGET_NR_fstat64: { @@ -2246,15 +2255,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, do_stat64: if (!is_error(ret)) { struct target_stat64 *target_st = (void *)arg2; + memset(target_st, 0, sizeof(struct target_stat64)); target_st->st_dev = tswap16(st.st_dev); target_st->st_ino = tswapl(st.st_ino); +#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO + target_st->__st_ino = tswapl(st.st_ino); +#endif target_st->st_mode = tswap32(st.st_mode); - target_st->st_nlink = tswap16(st.st_nlink); - target_st->st_uid = tswap16(st.st_uid); - target_st->st_gid = tswap16(st.st_gid); + target_st->st_nlink = tswap32(st.st_nlink); + target_st->st_uid = tswapl(st.st_uid); + target_st->st_gid = tswapl(st.st_gid); target_st->st_rdev = tswap16(st.st_rdev); /* XXX: better use of kernel struct */ - target_st->st_size = tswapl(st.st_size); + target_st->st_size = tswap64(st.st_size); target_st->st_blksize = tswapl(st.st_blksize); target_st->st_blocks = tswapl(st.st_blocks); target_st->target_st_atime = tswapl(st.st_atime); -- cgit v1.2.3 From 32ce63371a6b4d7ad8786ac5d2f95a1e6cdd1af4 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Apr 2003 00:16:16 +0000 Subject: path patch git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@96 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 7 ++- linux-user/elfload.c | 15 ++---- linux-user/path.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/qemu.h | 6 +-- 4 files changed, 154 insertions(+), 16 deletions(-) create mode 100644 linux-user/path.c diff --git a/configure b/configure index f3f725b48..ae639a13a 100755 --- a/configure +++ b/configure @@ -19,6 +19,7 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h" # default parameters prefix="/usr/local" +interp_prefix="/usr/gnemul/qemu-i386" cross_prefix="" cc="gcc" host_cc="gcc" @@ -89,6 +90,8 @@ for opt do case "$opt" in --prefix=*) prefix=`echo $opt | cut -d '=' -f 2` ;; + --interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2` + ;; --source-path=*) source_path=`echo $opt | cut -d '=' -f 2` ;; --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` @@ -172,7 +175,7 @@ EOF echo "Standard options:" echo " --help print this message" echo " --prefix=PREFIX install in PREFIX [$prefix]" -echo " for audio/video/image support" +echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]" echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]" @@ -198,7 +201,7 @@ echo "# Automatically generated by configure - do not modify" > config.mak echo "/* Automatically generated by configure - do not modify */" > $TMPH echo "prefix=$prefix" >> config.mak -echo "#define CONFIG_QEMU_PREFIX \"$prefix\"" >> $TMPH +echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH echo "MAKE=$make" >> config.mak echo "CC=$cc" >> config.mak echo "GCC_MAJOR=$gcc_major" >> config.mak diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c692ea371..2974c01fe 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -70,7 +70,6 @@ struct linux_binprm { int fd; int e_uid, e_gid; int argc, envc; - char * interp_prefix; /* prefix for interpreter */ char * filename; /* Name of binary */ unsigned long loader, exec; int dont_iput; /* binfmt handler has put inode */ @@ -756,8 +755,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r * is an a.out format binary */ - elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+ - strlen(bprm->interp_prefix)); + elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); if (elf_interpreter == NULL) { free (elf_phdata); @@ -765,12 +763,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r return -ENOMEM; } - strcpy(elf_interpreter, bprm->interp_prefix); retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); if(retval >= 0) { - retval = read(bprm->fd, - elf_interpreter+strlen(bprm->interp_prefix), - elf_ppnt->p_filesz); + retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); } if(retval < 0) { perror("load_elf_binary2"); @@ -792,7 +787,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r printf("Using ELF interpreter %s\n", elf_interpreter); #endif if (retval >= 0) { - retval = open(elf_interpreter, O_RDONLY); + retval = open(path(elf_interpreter), O_RDONLY); if(retval >= 0) { interpreter_fd = retval; } @@ -1060,8 +1055,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r -int elf_exec(const char *interp_prefix, - const char * filename, char ** argv, char ** envp, +int elf_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop) { struct linux_binprm bprm; @@ -1080,7 +1074,6 @@ int elf_exec(const char *interp_prefix, else { bprm.fd = retval; } - bprm.interp_prefix = (char *)interp_prefix; bprm.filename = (char *)filename; bprm.sh_bang = 0; bprm.loader = 0; diff --git a/linux-user/path.c b/linux-user/path.c new file mode 100644 index 000000000..9e49076dc --- /dev/null +++ b/linux-user/path.c @@ -0,0 +1,142 @@ +/* Code to mangle pathnames into those matching a given prefix. + eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so"); + + The assumption is that this area does not change. +*/ +#include +#include +#include +#include +#include +#include +#include +#include "qemu.h" + +struct pathelem +{ + /* Name of this, eg. lib */ + char *name; + /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ + char *pathname; + struct pathelem *parent; + /* Children */ + unsigned int num_entries; + struct pathelem *entries[0]; +}; + +static struct pathelem *base; + +/* First N chars of S1 match S2, and S2 is N chars long. */ +static int strneq(const char *s1, unsigned int n, const char *s2) +{ + unsigned int i; + + for (i = 0; i < n; i++) + if (s1[i] != s2[i]) + return 0; + return s2[i] == 0; +} + +static struct pathelem *add_entry(struct pathelem *root, const char *name); + +static struct pathelem *new_entry(const char *root, + struct pathelem *parent, + const char *name) +{ + struct pathelem *new = malloc(sizeof(*new)); + new->name = strdup(name); + asprintf(&new->pathname, "%s/%s", root, name); + new->num_entries = 0; + return new; +} + +#define streq(a,b) (strcmp((a), (b)) == 0) + +static struct pathelem *add_dir_maybe(struct pathelem *path) +{ + DIR *dir; + + if ((dir = opendir(path->pathname)) != NULL) { + struct dirent *dirent; + + while ((dirent = readdir(dir)) != NULL) { + if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){ + path = add_entry(path, dirent->d_name); + } + } + closedir(dir); + } + return path; +} + +static struct pathelem *add_entry(struct pathelem *root, const char *name) +{ + root->num_entries++; + + root = realloc(root, sizeof(*root) + + sizeof(root->entries[0])*root->num_entries); + + root->entries[root->num_entries-1] = new_entry(root->pathname, root, name); + root->entries[root->num_entries-1] + = add_dir_maybe(root->entries[root->num_entries-1]); + return root; +} + +/* This needs to be done after tree is stabalized (ie. no more reallocs!). */ +static void set_parents(struct pathelem *child, struct pathelem *parent) +{ + unsigned int i; + + child->parent = parent; + for (i = 0; i < child->num_entries; i++) + set_parents(child->entries[i], child); +} + +void init_paths(const char *prefix) +{ + if (prefix[0] != '/' || + prefix[0] == '\0' || + !strcmp(prefix, "/")) + return; + + base = new_entry("", NULL, prefix+1); + base = add_dir_maybe(base); + set_parents(base, base); +} + +/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ +static const char * +follow_path(const struct pathelem *cursor, const char *name) +{ + unsigned int i, namelen; + + name += strspn(name, "/"); + namelen = strcspn(name, "/"); + + if (namelen == 0) + return cursor->pathname; + + if (strneq(name, namelen, "..")) + return follow_path(cursor->parent, name + namelen); + + if (strneq(name, namelen, ".")) + return follow_path(cursor, name + namelen); + + for (i = 0; i < cursor->num_entries; i++) + if (strneq(name, namelen, cursor->entries[i]->name)) + return follow_path(cursor->entries[i], name + namelen); + + /* Not found */ + return NULL; +} + +/* Look for path in emulation dir, otherwise return name. */ +const char *path(const char *name) +{ + /* Only do absolute paths: quick and dirty, but should mostly be OK. + Could do relative by tracking cwd. */ + if (!base || name[0] != '/') + return name; + + return follow_path(base, name) ?: name; +} diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 882c3c039..dddc7ad4c 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -60,8 +60,7 @@ typedef struct TaskState { extern TaskState *first_task_state; -int elf_exec(const char *interp_prefix, - const char * filename, char ** argv, char ** envp, +int elf_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); void target_set_brk(char *new_brk); @@ -75,5 +74,6 @@ void process_pending_signals(void *cpu_env); void signal_init(void); int queue_signal(int sig, target_siginfo_t *info); void save_v86_state(CPUX86State *env); - +void init_paths(const char *prefix); +const char *path(const char *pathname); #endif -- cgit v1.2.3 From 1eb87257dae084166f0a007a9bfa8052e1784108 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Apr 2003 01:12:28 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@97 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 +++++-- Makefile | 13 +++++++------ README | 4 ++-- VERSION | 2 +- configure | 2 +- qemu-doc.texi | 35 ++++++++++++++++++++++++++++++----- 6 files changed, 46 insertions(+), 17 deletions(-) diff --git a/Changelog b/Changelog index a451cfa6d..03158ccb5 100644 --- a/Changelog +++ b/Changelog @@ -1,8 +1,11 @@ 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 icache - is not flushed) + - first self-virtualizable version (works only as long as the + translation cache is not flushed) + - RH9 fixes version 0.1.5: diff --git a/Makefile b/Makefile index f6d1e2715..50c51020a 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o signal.o +OBJS= elfload.o main.o syscall.o signal.o path.o SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a @@ -110,13 +110,14 @@ elfload.c main.c signal.c thunk.h\ cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ dis-asm.h gen-i386.h syscall.c\ dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ -ppc.ld s390.ld exec-i386.h exec-i386.c configure \ +ppc.ld s390.ld exec-i386.h exec-i386.c path.c configure \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h tests/test-i386-code16.S\ tests/hello.c tests/hello tests/sha1.c \ tests/testsig.c tests/testclone.c tests/testthread.c \ tests/runcom.c tests/pi_10.com \ +tests/test_path.c \ qemu-doc.texi qemu-doc.html FILE=qemu-$(VERSION) @@ -132,10 +133,10 @@ tar: BINPATH=/usr/local/qemu-i386 tarbin: - tar zcvf /tmp/qemu-i386-glibc21.tar.gz \ - $(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin - tar zcvf /tmp/qemu-i386-wine.tar.gz \ - $(BINPATH)/X11R6 $(BINPATH)/wine + tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \ + $(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr + tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \ + $(BINPATH)/wine ifneq ($(wildcard .depend),) include .depend diff --git a/README b/README index dfd137f41..7efa98f56 100644 --- a/README +++ b/README @@ -6,7 +6,7 @@ INSTALLATION Type - ./configure + ./configure --interp-prefix=/usr/local/qemu-i386 make to build qemu and libqemu.a. @@ -23,7 +23,7 @@ libraries installed on your PC. For example: ./qemu -L / /bin/ls * On non x86 CPUs, you need first to download at least an x86 glibc -(qemu-i386-glibc21.tar.gz on the qemu web page). Ensure that +(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that LD_LIBRARY_PATH is not set: unset LD_LIBRARY_PATH diff --git a/VERSION b/VERSION index def9a0154..a19223320 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.5 \ No newline at end of file +0.1.6 \ No newline at end of file diff --git a/configure b/configure index ae639a13a..d5ec79f5b 100755 --- a/configure +++ b/configure @@ -271,4 +271,4 @@ else echo "config.h is unchanged" fi -rm -f $TMPH +rm -f $TMPO $TMPC $TMPE $TMPS $TMPH diff --git a/qemu-doc.texi b/qemu-doc.texi index c29dc22ad..2c7249ff9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -36,6 +36,8 @@ User space LDT and GDT are emulated. VM86 mode is also supported @item Accurate signal handling by remapping host signals to virtual x86 signals. +@item QEMU can emulate itself on x86 (experimental). + @item The virtual x86 CPU is a library (@code{libqemu}) which can be used in other projects. @@ -50,9 +52,7 @@ Current QEMU Limitations: @item Not all x86 exceptions are precise (yet). [Very few programs need that]. -@item Not self virtualizable (yet). [You cannot launch qemu with qemu on the same CPU]. - -@item No support for self modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !]. +@item No support for self-modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !]. @item No SSE/MMX support (yet). @@ -88,9 +88,14 @@ qemu -L / /bin/ls @code{-L /} tells that the x86 dynamic linker must be searched with a @file{/} prefix. +@item Since QEMU is also a linux process, you can launch qemu with qemu: + +@example +qemu -L / qemu -L / /bin/ls +@end example @item On non x86 CPUs, you need first to download at least an x86 glibc -(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Ensure that +(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that @code{LD_LIBRARY_PATH} is not set: @example @@ -107,6 +112,11 @@ QEMU is automatically launched by the Linux kernel when you try to launch x86 executables. It requires the @code{binfmt_misc} module in the Linux kernel. +@item The x86 version of QEMU is also included. You can try weird things such as: +@example +qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386 +@end example + @end itemize @section Wine launch (Currently only tested when emulating x86 on x86) @@ -122,7 +132,7 @@ qemu /usr/local/qemu-i386/bin/ls-i386 @end example @item Download the binary x86 Wine install -(@file{qemu-i386-wine.tar.gz} on the QEMU web page). +(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page). @item Configure Wine on your account. Look at the provided script @file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous @@ -302,6 +312,21 @@ thread. The virtual x86 CPU atomic operations are emulated with a global lock so that their semantic is preserved. +@section Self-virtualization + +QEMU was conceived so that ultimately it can emulate itself. Althought +it is not very useful, it is an important test to show the power of the +emulator. + +Achieving self-virtualization is not easy because there may be address +space conflicts. QEMU solves this problem by being an ELF shared object +as the ld-linux.so ELF interpreter. That way, it can be relocated at +load time. + +Since self-modifying code is not supported yet, QEMU cannot self +virtualize itself in case of translation cache flush. This limitation +will be suppressed soon. + @section Bibliography @table @asis -- cgit v1.2.3 From f644caa51a84d59177af61c46bf32dc60e7e2333 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Apr 2003 01:17:32 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@98 c046a42c-6fe2-441c-8c8c-71466251a162 --- README.distrib | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 README.distrib diff --git a/README.distrib b/README.distrib new file mode 100644 index 000000000..35dff250b --- /dev/null +++ b/README.distrib @@ -0,0 +1,16 @@ +Information about the various packages used to build the current qemu +x86 binary distribution: + +* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution + was used to get most of the binary packages. + +* wine-20020411 tarball + + ./configure --prefix=/usr/local/qemu-i386/wine + + All exe and libs were stripped. Some compile time tools and the + includes were deleted. + +* ldconfig was launched to build the library links: + + ./qemu /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache -- cgit v1.2.3 From d9c4d1cc1a60c73ad2403d80366b52dcf862eed2 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:37:14 +0000 Subject: cleanup git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@99 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/configure b/configure index d5ec79f5b..9bae7b437 100755 --- a/configure +++ b/configure @@ -56,22 +56,6 @@ bigendian="no" # OS specific targetos=`uname -s` case $targetos in -BeOS) -prefix="/boot/home/config" -# helps building libavcodec -CFLAGS="-O2 -DPIC" -# no need for libm, but the inet stuff -# Check for BONE -if (echo $BEINCLUDES|grep 'headers/be/bone' >/dev/null); then -extralibs="-lbind -lsocket" -else -echo "Not sure building for net_server will succeed... good luck." -extralibs="-lsocket" -fi ;; -BSD/OS) -extralibs="-lpoll -lgnugetopt -lm" -make="gmake" -;; *) ;; esac @@ -246,10 +230,6 @@ echo "" >>config.mak echo -n "#define QEMU_VERSION \"" >> $TMPH head $source_path/VERSION >> $TMPH echo "\"" >> $TMPH -if test "$network" = "yes" ; then - echo "#define CONFIG_NETWORK 1" >> $TMPH - echo "CONFIG_NETWORK=yes" >> config.mak -fi # build tree in object directory if source path is different from current one if test "$source_path_used" = "yes" ; then -- cgit v1.2.3 From d34720fd7ddfe88ea99da0c06bcd60d6aa1a55cd Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:37:44 +0000 Subject: comment git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@100 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-i386.h b/cpu-i386.h index 76db7a616..ca3379135 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -163,7 +163,7 @@ typedef struct CPUX86State { uint32_t eip; uint32_t eflags; /* eflags register. During CPU emulation, CC flags and DF are set to zero because they are - store elsewhere */ + stored elsewhere */ /* emulator internal eflags handling */ uint32_t cc_src; -- cgit v1.2.3 From 77e4672d8d3f0cca922b5d288ef227023777caf1 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:39:06 +0000 Subject: flock support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@101 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ca52eb4e9..01e943b70 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1414,16 +1414,42 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = do_ioctl(arg1, arg2, arg3); break; case TARGET_NR_fcntl: + { + struct flock fl; + struct target_flock *target_fl = (void *)arg3; + switch(arg2) { case F_GETLK: + ret = get_errno(fcntl(arg1, arg2, &fl)); + if (ret == 0) { + target_fl->l_type = tswap16(fl.l_type); + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswapl(fl.l_start); + target_fl->l_len = tswapl(fl.l_len); + target_fl->l_pid = tswapl(fl.l_pid); + } + break; + case F_SETLK: case F_SETLKW: + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswapl(target_fl->l_start); + fl.l_len = tswapl(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + ret = get_errno(fcntl(arg1, arg2, &fl)); + break; + + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: goto unimplemented; default: ret = get_errno(fcntl(arg1, arg2, arg3)); break; } break; + } case TARGET_NR_mpx: goto unimplemented; case TARGET_NR_setpgid: @@ -2356,16 +2382,37 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; #if TARGET_LONG_BITS == 32 case TARGET_NR_fcntl64: + { + struct flock64 fl; + struct target_flock64 *target_fl = (void *)arg3; + switch(arg2) { case F_GETLK64: + ret = get_errno(fcntl(arg1, arg2, &fl)); + if (ret == 0) { + target_fl->l_type = tswap16(fl.l_type); + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswap64(fl.l_start); + target_fl->l_len = tswap64(fl.l_len); + target_fl->l_pid = tswapl(fl.l_pid); + } + break; + case F_SETLK64: case F_SETLKW64: - goto unimplemented; + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswap64(target_fl->l_start); + fl.l_len = tswap64(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + ret = get_errno(fcntl(arg1, arg2, &fl)); + break; default: ret = get_errno(fcntl(arg1, arg2, arg3)); break; } - break; + break; + } #endif case TARGET_NR_security: goto unimplemented; -- cgit v1.2.3 From 6977fbfd8bff90f4dbe4e79c2f77921ce0ba34ff Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:39:23 +0000 Subject: loglevel export git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@102 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index dddc7ad4c..300a18856 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -76,4 +76,6 @@ int queue_signal(int sig, target_siginfo_t *info); void save_v86_state(CPUX86State *env); void init_paths(const char *prefix); const char *path(const char *pathname); + +extern int loglevel; #endif -- cgit v1.2.3 From 689f936f7ea68c0539f73246d582e5c85ae50f12 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:40:07 +0000 Subject: symbol fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@103 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf.h | 8 +++--- linux-user/elfload.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/elf.h b/elf.h index d87526a7d..fcd3fecb4 100644 --- a/elf.h +++ b/elf.h @@ -1,5 +1,5 @@ -#ifndef _ELF_H -#define _ELF_H +#ifndef _QEMU_ELF_H +#define _QEMU_ELF_H #include @@ -996,6 +996,7 @@ typedef struct elf64_note { #define elf_phdr elf32_phdr #define elf_note elf32_note #define elf_shdr elf32_shdr +#define elf_sym elf32_sym #ifdef ELF_USES_RELOCA # define ELF_RELOC Elf32_Rela @@ -1009,6 +1010,7 @@ typedef struct elf64_note { #define elf_phdr elf64_phdr #define elf_note elf64_note #define elf_shdr elf64_shdr +#define elf_sym elf64_sym #ifdef ELF_USES_RELOCA # define ELF_RELOC Elf64_Rela @@ -1029,4 +1031,4 @@ typedef struct elf64_note { #endif -#endif /* _ELF_H */ +#endif /* _QEMU_ELF_H */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 2974c01fe..edb3176bc 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -11,6 +11,7 @@ #include #include "qemu.h" +#include "disas.h" #ifdef TARGET_I386 @@ -195,6 +196,28 @@ static void bswap_phdr(Elf32_Phdr *phdr) bswap32s(&phdr->p_flags); /* Segment flags */ bswap32s(&phdr->p_align); /* Segment alignment */ } + +static void bswap_shdr(Elf32_Shdr *shdr) +{ + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswap32s(&shdr->sh_flags); + bswap32s(&shdr->sh_addr); + bswap32s(&shdr->sh_offset); + bswap32s(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswap32s(&shdr->sh_addralign); + bswap32s(&shdr->sh_entsize); +} + +static void bswap_sym(Elf32_Sym *sym) +{ + bswap32s(&sym->st_name); + bswap32s(&sym->st_value); + bswap32s(&sym->st_size); + bswap16s(&sym->st_shndx); +} #endif static void * get_free_page(void) @@ -656,7 +679,56 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, return ((unsigned long) interp_elf_ex->e_entry) + load_addr; } +/* Best attempt to load symbols from this ELF object. */ +static void load_symbols(struct elfhdr *hdr, int fd) +{ + unsigned int i; + struct elf_shdr sechdr, symtab, strtab; + char *strings; + + lseek(fd, hdr->e_shoff, SEEK_SET); + for (i = 0; i < hdr->e_shnum; i++) { + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&sechdr); +#endif + if (sechdr.sh_type == SHT_SYMTAB) { + symtab = sechdr; + lseek(fd, hdr->e_shoff + + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); + if (read(fd, &strtab, sizeof(strtab)) + != sizeof(strtab)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&strtab); +#endif + goto found; + } + } + return; /* Shouldn't happen... */ + + found: + /* Now know where the strtab and symtab are. Snarf them. */ + disas_symtab = malloc(symtab.sh_size); + disas_strtab = strings = malloc(strtab.sh_size); + if (!disas_symtab || !disas_strtab) + return; + + lseek(fd, symtab.sh_offset, SEEK_SET); + if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) + return; +#ifdef BSWAP_NEEDED + for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) + bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); +#endif + + lseek(fd, strtab.sh_offset, SEEK_SET); + if (read(fd, strings, strtab.sh_size) != strtab.sh_size) + return; + disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); +} static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info) @@ -989,6 +1061,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r free(elf_phdata); + if (loglevel) + load_symbols(&elf_ex, bprm->fd); + if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); -- cgit v1.2.3 From 6cd9f35b9bb0a59697a981e3f9e4eafd9e68ff97 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:40:35 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@104 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 2c7249ff9..2e324ca98 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -319,13 +319,13 @@ it is not very useful, it is an important test to show the power of the emulator. Achieving self-virtualization is not easy because there may be address -space conflicts. QEMU solves this problem by being an ELF shared object -as the ld-linux.so ELF interpreter. That way, it can be relocated at -load time. +space conflicts. QEMU solves this problem by being an executable ELF +shared object as the ld-linux.so ELF interpreter. That way, it can be +relocated at load time. -Since self-modifying code is not supported yet, QEMU cannot self -virtualize itself in case of translation cache flush. This limitation -will be suppressed soon. +Since self-modifying code is not supported yet, QEMU cannot emulate +itself in case of translation cache flush. This limitation will be +suppressed soon. @section Bibliography -- cgit v1.2.3 From 956034d7e5370c26f8ef58a11e940ffa4f3d8d70 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:40:53 +0000 Subject: log fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@105 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/exec-i386.c b/exec-i386.c index dedcbfabd..b75c6c70a 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec-i386.h" +#include "disas.h" //#define DEBUG_EXEC #define DEBUG_FLUSH @@ -185,7 +186,7 @@ static void cpu_x86_dump_state(FILE *f) { int eflags; eflags = cc_table[CC_OP].compute_all(); - eflags |= (DF & DIRECTION_FLAG); + eflags |= (DF & DF_MASK); fprintf(f, "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" @@ -194,7 +195,7 @@ static void cpu_x86_dump_state(FILE *f) env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], env->cc_src, env->cc_dst, cc_op_str[env->cc_op], - eflags & DIRECTION_FLAG ? 'D' : '-', + eflags & DF_MASK ? 'D' : '-', eflags & CC_O ? 'O' : '-', eflags & CC_S ? 'S' : '-', eflags & CC_Z ? 'Z' : '-', @@ -397,6 +398,12 @@ int cpu_x86_exec(CPUX86State *env1) code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); cpu_unlock(); } + if (loglevel) { + fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", + (long)tb->tc_ptr, (long)tb->pc, + lookup_symbol((void *)tb->pc)); + fflush(logfile); + } /* execute the generated code */ tc_ptr = tb->tc_ptr; gen_func = (void *)tc_ptr; -- cgit v1.2.3 From ae48a07313d76b9097ba80a6e0d338acc2201c2e Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:41:02 +0000 Subject: flock git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@106 c046a42c-6fe2-441c-8c8c-71466251a162 --- syscall-i386.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/syscall-i386.h b/syscall-i386.h index d8fa444c9..a2fb03dea 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -936,6 +936,22 @@ union target_semun { unsigned int __pad; /* really void* */ }; +struct target_flock { + short l_type; + short l_whence; + target_ulong l_start; + target_ulong l_len; + int l_pid; +}; + +struct target_flock64 { + short l_type; + short l_whence; + unsigned long long l_start; + unsigned long long l_len; + int l_pid; +}; + /* soundcard defines (XXX: move them to generic file syscall_defs.h) */ #define TARGET_SNDCTL_COPR_HALT 0xc0144307 -- cgit v1.2.3 From b9adb4a6bcf3d2511b6c65aa2e9c6866d03fc88a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:41:16 +0000 Subject: PowerPC disas code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@107 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 6 +- dis-asm.h | 1 + disas.c | 79 ++ disas.h | 20 + ppc-dis.c | 3231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ translate-i386.c | 66 +- 6 files changed, 3340 insertions(+), 63 deletions(-) create mode 100644 disas.c create mode 100644 disas.h create mode 100644 ppc-dis.c diff --git a/Makefile b/Makefile index 50c51020a..9008dc95b 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ OBJS+= libqemu.a LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o # NOTE: the disassembler code is only needed for debugging -LIBOBJS+=i386-dis.o dis-buf.o +LIBOBJS+=disas.o ppc-dis.o i386-dis.o dis-buf.o all: qemu qemu-doc.html @@ -96,7 +96,7 @@ test speed: qemu make -C tests $@ TAGS: - etags *.[ch] i386/*.[ch] + etags *.[ch] tests/*.[ch] # documentation qemu-doc.html: qemu-doc.texi @@ -109,7 +109,7 @@ Makefile elf.h thunk.c\ elfload.c main.c signal.c thunk.h\ cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ dis-asm.h gen-i386.h syscall.c\ -dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ +dis-buf.c disas.c disas.h ppc-dis.c i386-dis.c opreg_template.h syscall_defs.h\ ppc.ld s390.ld exec-i386.h exec-i386.c path.c configure \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ diff --git a/dis-asm.h b/dis-asm.h index 5a10c5e93..533307d97 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -320,6 +320,7 @@ extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*)); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/disas.c b/disas.c new file mode 100644 index 000000000..d3dcdffd1 --- /dev/null +++ b/disas.c @@ -0,0 +1,79 @@ +/* General "disassemble this chunk" code. Used for debugging. */ +#include "dis-asm.h" +#include "disas.h" +#include "elf.h" + +/* Filled in by elfload.c. Simplistic, but will do for now. */ +unsigned int disas_num_syms; +void *disas_symtab; +const char *disas_strtab; + +/* Disassemble this for me please... (debugging). */ +void disas(FILE *out, void *code, unsigned long size, enum disas_type type) +{ + uint8_t *pc; + int count; + struct disassemble_info disasm_info; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); + + disasm_info.buffer = code; + disasm_info.buffer_vma = (unsigned long)code; + disasm_info.buffer_length = size; + + if (type == DISAS_TARGET) { +#ifdef WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif +#ifdef __i386__ + disasm_info.mach = bfd_mach_i386_i386; + print_insn = print_insn_i386; +#elif defined(__powerpc__) + print_insn = print_insn_ppc; +#else + fprintf(out, "Asm output not supported on this arch\n"); + return; +#endif + } else { + /* Currently only source supported in x86. */ + disasm_info.endian = BFD_ENDIAN_LITTLE; + if (type == DISAS_I386_I386) + disasm_info.mach = bfd_mach_i386_i386; + else + disasm_info.mach = bfd_mach_i386_i8086; + print_insn = print_insn_i386; + } + + for (pc = code; pc < (uint8_t *)code + size; pc += count) { + fprintf(out, "0x%08lx: ", (long)pc); + count = print_insn((long)pc, &disasm_info); + fprintf(out, "\n"); + if (count < 0) + break; + } +} + +/* Look up symbol for debugging purpose. Returns "" if unknown. */ +const char *lookup_symbol(void *orig_addr) +{ + unsigned int i; + /* Hack, because we know this is x86. */ + Elf32_Sym *sym = disas_symtab; + + for (i = 0; i < disas_num_syms; i++) { + if (sym[i].st_shndx == SHN_UNDEF + || sym[i].st_shndx >= SHN_LORESERVE) + continue; + + if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) + continue; + + if ((long)orig_addr >= sym[i].st_value + && (long)orig_addr < sym[i].st_value + sym[i].st_size) + return disas_strtab + sym[i].st_name; + } + return ""; +} diff --git a/disas.h b/disas.h new file mode 100644 index 000000000..b7db47829 --- /dev/null +++ b/disas.h @@ -0,0 +1,20 @@ +#ifndef _QEMU_DISAS_H +#define _QEMU_DISAS_H + +enum disas_type { + DISAS_I386_I386, + DISAS_I386_I8086, + DISAS_TARGET, /* whatever host is. */ +}; + +/* Disassemble this for me please... (debugging). */ +void disas(FILE *out, void *code, unsigned long size, enum disas_type type); + +/* Look up symbol for debugging purpose. Returns "" if unknown. */ +const char *lookup_symbol(void *orig_addr); + +/* Filled in by elfload.c. Simplistic, but will do for now. */ +extern unsigned int disas_num_syms; +extern void *disas_symtab; /* FIXME: includes are a mess --RR */ +extern const char *disas_strtab; +#endif /* _QEMU_DISAS_H */ diff --git a/ppc-dis.c b/ppc-dis.c new file mode 100644 index 000000000..86e384f34 --- /dev/null +++ b/ppc-dis.c @@ -0,0 +1,3231 @@ +/* ppc-dis.c -- Disassemble PowerPC instructions + Copyright 1994 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +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 "dis-asm.h" + +/* ppc.h -- Header file for PowerPC opcode table + Copyright 1994 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +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 +1, 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. */ + +/* The opcode table is an array of struct powerpc_opcode. */ + +struct powerpc_opcode +{ + /* The opcode name. */ + const char *name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned long 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 long mask; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The defined values + are listed below. */ + unsigned long 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[8]; +}; + +/* 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 powerpc_opcode powerpc_opcodes[]; +extern const int powerpc_num_opcodes; + +/* Values defined for the flags field of a struct powerpc_opcode. */ + +/* Opcode is defined for the PowerPC architecture. */ +#define PPC_OPCODE_PPC (01) + +/* Opcode is defined for the POWER (RS/6000) architecture. */ +#define PPC_OPCODE_POWER (02) + +/* Opcode is defined for the POWER2 (Rios 2) architecture. */ +#define PPC_OPCODE_POWER2 (04) + +/* Opcode is only defined on 32 bit architectures. */ +#define PPC_OPCODE_32 (010) + +/* Opcode is only defined on 64 bit architectures. */ +#define PPC_OPCODE_64 (020) + +/* Opcode is supported by the Motorola PowerPC 601 processor. The 601 + is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions, + but it also supports many additional POWER instructions. */ +#define PPC_OPCODE_601 (040) + +/* A macro to extract the major opcode from an instruction. */ +#define PPC_OP(i) (((i) >> 26) & 0x3f) + +/* The operands table is an array of struct powerpc_operand. */ + +struct powerpc_operand +{ + /* The number of bits in the operand. */ + int bits; + + /* How far the operand is left shifted in the instruction. */ + int shift; + + /* 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 long (*insert)(unsigned long instruction, long 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 & PPC_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. */ + long (*extract) (unsigned long instruction, int *invalid); + + /* One bit syntax flags. */ + unsigned long flags; +}; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the powerpc_opcodes table. */ + +extern const struct powerpc_operand powerpc_operands[]; + +/* Values defined for the flags field of a struct powerpc_operand. */ + +/* This operand takes signed values. */ +#define PPC_OPERAND_SIGNED (01) + +/* This operand takes signed values, but also accepts a full positive + range of values when running in 32 bit mode. That is, if bits is + 16, it takes any value from -0x8000 to 0xffff. In 64 bit mode, + this flag is ignored. */ +#define PPC_OPERAND_SIGNOPT (02) + +/* This operand does not actually exist in the assembler input. This + is used to support extended mnemonics such as mr, 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 valid argument. */ +#define PPC_OPERAND_FAKE (04) + +/* The next operand should be wrapped in parentheses rather than + separated from this one by a comma. This is used for the load and + store instructions which want their operands to look like + reg,displacement(reg) + */ +#define PPC_OPERAND_PARENS (010) + +/* This operand may use the symbolic names for the CR fields, which + are + lt 0 gt 1 eq 2 so 3 un 3 + cr0 0 cr1 1 cr2 2 cr3 3 + cr4 4 cr5 5 cr6 6 cr7 7 + These may be combined arithmetically, as in cr2*4+gt. These are + only supported on the PowerPC, not the POWER. */ +#define PPC_OPERAND_CR (020) + +/* This operand names a register. The disassembler uses this to print + register names with a leading 'r'. */ +#define PPC_OPERAND_GPR (040) + +/* This operand names a floating point register. The disassembler + prints these with a leading 'f'. */ +#define PPC_OPERAND_FPR (0100) + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_RELATIVE (0200) + +/* This operand is an absolute branch address. The disassembler + prints these symbolically if possible. */ +#define PPC_OPERAND_ABSOLUTE (0400) + +/* This operand is optional, and is zero if omitted. This is used for + the optional BF and L fields in the comparison instructions. The + assembler must count the number of operands remaining on the line, + and the number of operands remaining for the opcode, and decide + whether this operand is present or not. The disassembler should + print this operand out only if it is not zero. */ +#define PPC_OPERAND_OPTIONAL (01000) + +/* This flag is only used with PPC_OPERAND_OPTIONAL. If this operand + is omitted, then for the next operand use this operand value plus + 1, ignoring the next operand field for the opcode. This wretched + hack is needed because the Power rotate instructions can take + either 4 or 5 operands. The disassembler should print this operand + out regardless of the PPC_OPERAND_OPTIONAL field. */ +#define PPC_OPERAND_NEXT (02000) + +/* This operand should be regarded as a negative number for the + purposes of overflow checking (i.e., the normal most negative + number is disallowed and one more than the normal most positive + number is allowed). This flag will only be set for a signed + operand. */ +#define PPC_OPERAND_NEGATIVE (04000) + +/* The POWER and PowerPC assemblers use a few macros. We keep them + with the operands table for simplicity. The macro table is an + array of struct powerpc_macro. */ + +struct powerpc_macro +{ + /* The macro name. */ + const char *name; + + /* The number of operands the macro takes. */ + unsigned int operands; + + /* One bit flags for the opcode. These are used to indicate which + specific processors support the instructions. The values are the + same as those for the struct powerpc_opcode flags field. */ + unsigned long flags; + + /* A format string to turn the macro into a normal instruction. + Each %N in the string is replaced with operand number N (zero + based). */ + const char *format; +}; + +extern const struct powerpc_macro powerpc_macros[]; +extern const int powerpc_num_macros; + +/* ppc-opc.c -- PowerPC opcode list + Copyright 1994 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support + +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. */ + +/* This file holds the PowerPC 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 section. + + This file also holds the operand table. All knowledge about + inserting operands into instructions and vice-versa is kept in this + file. */ + +/* Local insertion and extraction functions. */ + +static unsigned long insert_bat (unsigned long, long, const char **); +static long extract_bat(unsigned long, int *); +static unsigned long insert_bba(unsigned long, long, const char **); +static long extract_bba(unsigned long, int *); +static unsigned long insert_bd(unsigned long, long, const char **); +static long extract_bd(unsigned long, int *); +static unsigned long insert_bdm(unsigned long, long, const char **); +static long extract_bdm(unsigned long, int *); +static unsigned long insert_bdp(unsigned long, long, const char **); +static long extract_bdp(unsigned long, int *); +static unsigned long insert_bo(unsigned long, long, const char **); +static long extract_bo(unsigned long, int *); +static unsigned long insert_boe(unsigned long, long, const char **); +static long extract_boe(unsigned long, int *); +static unsigned long insert_ds(unsigned long, long, const char **); +static long extract_ds(unsigned long, int *); +static unsigned long insert_li(unsigned long, long, const char **); +static long extract_li(unsigned long, int *); +static unsigned long insert_mbe(unsigned long, long, const char **); +static long extract_mbe(unsigned long, int *); +static unsigned long insert_mb6(unsigned long, long, const char **); +static long extract_mb6(unsigned long, int *); +static unsigned long insert_nb(unsigned long, long, const char **); +static long extract_nb(unsigned long, int *); +static unsigned long insert_nsi(unsigned long, long, const char **); +static long extract_nsi(unsigned long, int *); +static unsigned long insert_ral(unsigned long, long, const char **); +static unsigned long insert_ram(unsigned long, long, const char **); +static unsigned long insert_ras(unsigned long, long, const char **); +static unsigned long insert_rbs(unsigned long, long, const char **); +static long extract_rbs(unsigned long, int *); +static unsigned long insert_sh6(unsigned long, long, const char **); +static long extract_sh6(unsigned long, int *); +static unsigned long insert_spr(unsigned long, long, const char **); +static long extract_spr(unsigned long, int *); +static unsigned long insert_tbr(unsigned long, long, const char **); +static long extract_tbr(unsigned long, int *); + +/* The operands table. + + The fields are bits, shift, signed, insert, extract, flags. */ + +const struct powerpc_operand powerpc_operands[] = +{ + /* The zero index is used to indicate the end of the list of + operands. */ +#define UNUSED (0) + { 0, 0, 0, 0, 0 }, + + /* The BA field in an XL form instruction. */ +#define BA (1) +#define BA_MASK (0x1f << 16) + { 5, 16, 0, 0, PPC_OPERAND_CR }, + + /* The BA field in an XL form instruction when it must be the same + as the BT field in the same instruction. */ +#define BAT (2) + { 5, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE }, + + /* The BB field in an XL form instruction. */ +#define BB (3) +#define BB_MASK (0x1f << 11) + { 5, 11, 0, 0, PPC_OPERAND_CR }, + + /* The BB field in an XL form instruction when it must be the same + as the BA field in the same instruction. */ +#define BBA (4) + { 5, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE }, + + /* The BD field in a B form instruction. The lower two bits are + forced to zero. */ +#define BD (5) + { 16, 0, insert_bd, extract_bd, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when absolute addressing is + used. */ +#define BDA (6) + { 16, 0, insert_bd, extract_bd, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the - modifier is used. + This sets the y bit of the BO field appropriately. */ +#define BDM (7) + { 16, 0, insert_bdm, extract_bdm, + PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the - modifier is used + and absolute address is used. */ +#define BDMA (8) + { 16, 0, insert_bdm, extract_bdm, + PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the + modifier is used. + This sets the y bit of the BO field appropriately. */ +#define BDP (9) + { 16, 0, insert_bdp, extract_bdp, + PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The BD field in a B form instruction when the + modifier is used + and absolute addressing is used. */ +#define BDPA (10) + { 16, 0, insert_bdp, extract_bdp, + PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The BF field in an X or XL form instruction. */ +#define BF (11) + { 3, 23, 0, 0, PPC_OPERAND_CR }, + + /* An optional BF field. This is used for comparison instructions, + in which an omitted BF field is taken as zero. */ +#define OBF (12) + { 3, 23, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + + /* The BFA field in an X or XL form instruction. */ +#define BFA (13) + { 3, 18, 0, 0, PPC_OPERAND_CR }, + + /* The BI field in a B form or XL form instruction. */ +#define BI (14) +#define BI_MASK (0x1f << 16) + { 5, 16, 0, 0, PPC_OPERAND_CR }, + + /* The BO field in a B form instruction. Certain values are + illegal. */ +#define BO (15) +#define BO_MASK (0x1f << 21) + { 5, 21, insert_bo, extract_bo, 0 }, + + /* The BO field in a B form instruction when the + or - modifier is + used. This is like the BO field, but it must be even. */ +#define BOE (16) + { 5, 21, insert_boe, extract_boe, 0 }, + + /* The BT field in an X or XL form instruction. */ +#define BT (17) + { 5, 21, 0, 0, PPC_OPERAND_CR }, + + /* The condition register number portion of the BI field in a B form + or XL form instruction. This is used for the extended + conditional branch mnemonics, which set the lower two bits of the + BI field. This field is optional. */ +#define CR (18) + { 3, 18, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL }, + + /* The D field in a D form instruction. This is a displacement off + a register, and implies that the next operand is a register in + parentheses. */ +#define D (19) + { 16, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The DS field in a DS form instruction. This is like D, but the + lower two bits are forced to zero. */ +#define DS (20) + { 16, 0, insert_ds, extract_ds, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED }, + + /* The FL1 field in a POWER SC form instruction. */ +#define FL1 (21) + { 4, 12, 0, 0, 0 }, + + /* The FL2 field in a POWER SC form instruction. */ +#define FL2 (22) + { 3, 2, 0, 0, 0 }, + + /* The FLM field in an XFL form instruction. */ +#define FLM (23) + { 8, 17, 0, 0, 0 }, + + /* The FRA field in an X or A form instruction. */ +#define FRA (24) +#define FRA_MASK (0x1f << 16) + { 5, 16, 0, 0, PPC_OPERAND_FPR }, + + /* The FRB field in an X or A form instruction. */ +#define FRB (25) +#define FRB_MASK (0x1f << 11) + { 5, 11, 0, 0, PPC_OPERAND_FPR }, + + /* The FRC field in an A form instruction. */ +#define FRC (26) +#define FRC_MASK (0x1f << 6) + { 5, 6, 0, 0, PPC_OPERAND_FPR }, + + /* The FRS field in an X form instruction or the FRT field in a D, X + or A form instruction. */ +#define FRS (27) +#define FRT (FRS) + { 5, 21, 0, 0, PPC_OPERAND_FPR }, + + /* The FXM field in an XFX instruction. */ +#define FXM (28) +#define FXM_MASK (0xff << 12) + { 8, 12, 0, 0, 0 }, + + /* The L field in a D or X form instruction. */ +#define L (29) + { 1, 21, 0, 0, PPC_OPERAND_OPTIONAL }, + + /* The LEV field in a POWER SC form instruction. */ +#define LEV (30) + { 7, 5, 0, 0, 0 }, + + /* The LI field in an I form instruction. The lower two bits are + forced to zero. */ +#define LI (31) + { 26, 0, insert_li, extract_li, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED }, + + /* The LI field in an I form instruction when used as an absolute + address. */ +#define LIA (32) + { 26, 0, insert_li, extract_li, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED }, + + /* The MB field in an M form instruction. */ +#define MB (33) +#define MB_MASK (0x1f << 6) + { 5, 6, 0, 0, 0 }, + + /* The ME field in an M form instruction. */ +#define ME (34) +#define ME_MASK (0x1f << 1) + { 5, 1, 0, 0, 0 }, + + /* The MB and ME fields in an M form instruction expressed a single + operand which is a bitmask indicating which bits to select. This + is a two operand form using PPC_OPERAND_NEXT. See the + description in opcode/ppc.h for what this means. */ +#define MBE (35) + { 5, 6, 0, 0, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT }, + { 32, 0, insert_mbe, extract_mbe, 0 }, + + /* The MB or ME field in an MD or MDS form instruction. The high + bit is wrapped to the low end. */ +#define MB6 (37) +#define ME6 (MB6) +#define MB6_MASK (0x3f << 5) + { 6, 5, insert_mb6, extract_mb6, 0 }, + + /* The NB field in an X form instruction. The value 32 is stored as + 0. */ +#define NB (38) + { 6, 11, insert_nb, extract_nb, 0 }, + + /* The NSI field in a D form instruction. This is the same as the + SI field, only negated. */ +#define NSI (39) + { 16, 0, insert_nsi, extract_nsi, + PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED }, + + /* The RA field in an D, DS, X, XO, M, or MDS form instruction. */ +#define RA (40) +#define RA_MASK (0x1f << 16) + { 5, 16, 0, 0, PPC_OPERAND_GPR }, + + /* The RA field in a D or X form instruction which is an updating + load, which means that the RA field may not be zero and may not + equal the RT field. */ +#define RAL (41) + { 5, 16, insert_ral, 0, PPC_OPERAND_GPR }, + + /* The RA field in an lmw instruction, which has special value + restrictions. */ +#define RAM (42) + { 5, 16, insert_ram, 0, PPC_OPERAND_GPR }, + + /* The RA field in a D or X form instruction which is an updating + store or an updating floating point load, which means that the RA + field may not be zero. */ +#define RAS (43) + { 5, 16, insert_ras, 0, PPC_OPERAND_GPR }, + + /* The RB field in an X, XO, M, or MDS form instruction. */ +#define RB (44) +#define RB_MASK (0x1f << 11) + { 5, 11, 0, 0, PPC_OPERAND_GPR }, + + /* The RB field in an X form instruction when it must be the same as + the RS field in the instruction. This is used for extended + mnemonics like mr. */ +#define RBS (45) + { 5, 1, insert_rbs, extract_rbs, PPC_OPERAND_FAKE }, + + /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form + instruction or the RT field in a D, DS, X, XFX or XO form + instruction. */ +#define RS (46) +#define RT (RS) +#define RT_MASK (0x1f << 21) + { 5, 21, 0, 0, PPC_OPERAND_GPR }, + + /* The SH field in an X or M form instruction. */ +#define SH (47) +#define SH_MASK (0x1f << 11) + { 5, 11, 0, 0, 0 }, + + /* The SH field in an MD form instruction. This is split. */ +#define SH6 (48) +#define SH6_MASK ((0x1f << 11) | (1 << 1)) + { 6, 1, insert_sh6, extract_sh6, 0 }, + + /* The SI field in a D form instruction. */ +#define SI (49) + { 16, 0, 0, 0, PPC_OPERAND_SIGNED }, + + /* The SI field in a D form instruction when we accept a wide range + of positive values. */ +#define SISIGNOPT (50) + { 16, 0, 0, 0, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT }, + + /* The SPR field in an XFX form instruction. This is flipped--the + lower 5 bits are stored in the upper 5 and vice- versa. */ +#define SPR (51) +#define SPR_MASK (0x3ff << 11) + { 10, 11, insert_spr, extract_spr, 0 }, + + /* The BAT index number in an XFX form m[ft]ibat[lu] instruction. */ +#define SPRBAT (52) +#define SPRBAT_MASK (0x3 << 17) + { 2, 17, 0, 0, 0 }, + + /* The SPRG register number in an XFX form m[ft]sprg instruction. */ +#define SPRG (53) +#define SPRG_MASK (0x3 << 16) + { 2, 16, 0, 0, 0 }, + + /* The SR field in an X form instruction. */ +#define SR (54) + { 4, 16, 0, 0, 0 }, + + /* The SV field in a POWER SC form instruction. */ +#define SV (55) + { 14, 2, 0, 0, 0 }, + + /* The TBR field in an XFX form instruction. This is like the SPR + field, but it is optional. */ +#define TBR (56) + { 10, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL }, + + /* The TO field in a D or X form instruction. */ +#define TO (57) +#define TO_MASK (0x1f << 21) + { 5, 21, 0, 0, 0 }, + + /* The U field in an X form instruction. */ +#define U (58) + { 4, 12, 0, 0, 0 }, + + /* The UI field in a D form instruction. */ +#define UI (59) + { 16, 0, 0, 0, 0 }, +}; + +/* The functions used to insert and extract complicated operands. */ + +/* The BA field in an XL form instruction when it must be the same as + the BT field in the same instruction. This operand is marked FAKE. + The insertion function just copies the BT field into the BA field, + and the extraction function just checks that the fields are the + same. */ + +/*ARGSUSED*/ +static unsigned long +insert_bat (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (((insn >> 21) & 0x1f) << 16); +} + +static long +extract_bat (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The BB field in an XL form instruction when it must be the same as + the BA field in the same instruction. This operand is marked FAKE. + The insertion function just copies the BA field into the BB field, + and the extraction function just checks that the fields are the + same. */ + +/*ARGSUSED*/ +static unsigned long +insert_bba (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (((insn >> 16) & 0x1f) << 11); +} + +static long +extract_bba (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The BD field in a B form instruction. The lower two bits are + forced to zero. */ + +/*ARGSUSED*/ +static unsigned long +insert_bd (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (value & 0xfffc); +} + +/*ARGSUSED*/ +static long +extract_bd (insn, invalid) + unsigned long insn; + int *invalid; +{ + if ((insn & 0x8000) != 0) + return (insn & 0xfffc) - 0x10000; + else + return insn & 0xfffc; +} + +/* The BD field in a B form instruction when the - modifier is used. + This modifier means that the branch is not expected to be taken. + We must set the y bit of the BO field to 1 if the offset is + negative. When extracting, we require that the y bit be 1 and that + the offset be positive, since if the y bit is 0 we just want to + print the normal form of the instruction. */ + +/*ARGSUSED*/ +static unsigned long +insert_bdm (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if ((value & 0x8000) != 0) + insn |= 1 << 21; + return insn | (value & 0xfffc); +} + +static long +extract_bdm (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn & (1 << 21)) == 0 + || (insn & (1 << 15)) == 0)) + *invalid = 1; + if ((insn & 0x8000) != 0) + return (insn & 0xfffc) - 0x10000; + else + return insn & 0xfffc; +} + +/* The BD field in a B form instruction when the + modifier is used. + This is like BDM, above, except that the branch is expected to be + taken. */ + +/*ARGSUSED*/ +static unsigned long +insert_bdp (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if ((value & 0x8000) == 0) + insn |= 1 << 21; + return insn | (value & 0xfffc); +} + +static long +extract_bdp (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn & (1 << 21)) == 0 + || (insn & (1 << 15)) != 0)) + *invalid = 1; + if ((insn & 0x8000) != 0) + return (insn & 0xfffc) - 0x10000; + else + return insn & 0xfffc; +} + +/* Check for legal values of a BO field. */ + +static int +valid_bo (long value) +{ + /* Certain encodings have bits that are required to be zero. These + are (z must be zero, y may be anything): + 001zy + 011zy + 1z00y + 1z01y + 1z1zz + */ + switch (value & 0x14) + { + default: + case 0: + return 1; + case 0x4: + return (value & 0x2) == 0; + case 0x10: + return (value & 0x8) == 0; + case 0x14: + return value == 0x14; + } +} + +/* The BO field in a B form instruction. Warn about attempts to set + the field to an illegal value. */ + +static unsigned long +insert_bo (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (errmsg != (const char **) NULL + && ! valid_bo (value)) + *errmsg = "invalid conditional option"; + return insn | ((value & 0x1f) << 21); +} + +static long +extract_bo (insn, invalid) + unsigned long insn; + int *invalid; +{ + long value; + + value = (insn >> 21) & 0x1f; + if (invalid != (int *) NULL + && ! valid_bo (value)) + *invalid = 1; + return value; +} + +/* The BO field in a B form instruction when the + or - modifier is + used. This is like the BO field, but it must be even. When + extracting it, we force it to be even. */ + +static unsigned long +insert_boe (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (errmsg != (const char **) NULL) + { + if (! valid_bo (value)) + *errmsg = "invalid conditional option"; + else if ((value & 1) != 0) + *errmsg = "attempt to set y bit when using + or - modifier"; + } + return insn | ((value & 0x1f) << 21); +} + +static long +extract_boe (insn, invalid) + unsigned long insn; + int *invalid; +{ + long value; + + value = (insn >> 21) & 0x1f; + if (invalid != (int *) NULL + && ! valid_bo (value)) + *invalid = 1; + return value & 0x1e; +} + +/* The DS field in a DS form instruction. This is like D, but the + lower two bits are forced to zero. */ + +/*ARGSUSED*/ +static unsigned long +insert_ds (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (value & 0xfffc); +} + +/*ARGSUSED*/ +static long +extract_ds (insn, invalid) + unsigned long insn; + int *invalid; +{ + if ((insn & 0x8000) != 0) + return (insn & 0xfffc) - 0x10000; + else + return insn & 0xfffc; +} + +/* The LI field in an I form instruction. The lower two bits are + forced to zero. */ + +/*ARGSUSED*/ +static unsigned long +insert_li (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (value & 0x3fffffc); +} + +/*ARGSUSED*/ +static long +extract_li (insn, invalid) + unsigned long insn; + int *invalid; +{ + if ((insn & 0x2000000) != 0) + return (insn & 0x3fffffc) - 0x4000000; + else + return insn & 0x3fffffc; +} + +/* The MB and ME fields in an M form instruction expressed as a single + operand which is itself a bitmask. The extraction function always + marks it as invalid, since we never want to recognize an + instruction which uses a field of this type. */ + +static unsigned long +insert_mbe (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + unsigned long uval; + int mb, me; + + uval = value; + + if (uval == 0) + { + if (errmsg != (const char **) NULL) + *errmsg = "illegal bitmask"; + return insn; + } + + me = 31; + while ((uval & 1) == 0) + { + uval >>= 1; + --me; + } + + mb = me; + uval >>= 1; + while ((uval & 1) != 0) + { + uval >>= 1; + --mb; + } + + if (uval != 0) + { + if (errmsg != (const char **) NULL) + *errmsg = "illegal bitmask"; + } + + return insn | (mb << 6) | (me << 1); +} + +static long +extract_mbe (insn, invalid) + unsigned long insn; + int *invalid; +{ + long ret; + int mb, me; + int i; + + if (invalid != (int *) NULL) + *invalid = 1; + + ret = 0; + mb = (insn >> 6) & 0x1f; + me = (insn >> 1) & 0x1f; + for (i = mb; i < me; i++) + ret |= 1 << (31 - i); + return ret; +} + +/* The MB or ME field in an MD or MDS form instruction. The high bit + is wrapped to the low end. */ + +/*ARGSUSED*/ +static unsigned long +insert_mb6 (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | ((value & 0x1f) << 6) | (value & 0x20); +} + +/*ARGSUSED*/ +static long +extract_mb6 (insn, invalid) + unsigned long insn; + int *invalid; +{ + return ((insn >> 6) & 0x1f) | (insn & 0x20); +} + +/* The NB field in an X form instruction. The value 32 is stored as + 0. */ + +static unsigned long +insert_nb (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value < 0 || value > 32) + *errmsg = "value out of range"; + if (value == 32) + value = 0; + return insn | ((value & 0x1f) << 11); +} + +/*ARGSUSED*/ +static long +extract_nb (insn, invalid) + unsigned long insn; + int *invalid; +{ + long ret; + + ret = (insn >> 11) & 0x1f; + if (ret == 0) + ret = 32; + return ret; +} + +/* The NSI field in a D form instruction. This is the same as the SI + field, only negated. The extraction function always marks it as + invalid, since we never want to recognize an instruction which uses + a field of this type. */ + +/*ARGSUSED*/ +static unsigned long +insert_nsi (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | ((- value) & 0xffff); +} + +static long +extract_nsi (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL) + *invalid = 1; + if ((insn & 0x8000) != 0) + return - ((insn & 0xffff) - 0x10000); + else + return - (insn & 0xffff); +} + +/* The RA field in a D or X form instruction which is an updating + load, which means that the RA field may not be zero and may not + equal the RT field. */ + +static unsigned long +insert_ral (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value == 0 + || value == ((insn >> 21) & 0x1f)) + *errmsg = "invalid register operand when updating"; + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in an lmw instruction, which has special value + restrictions. */ + +static unsigned long +insert_ram (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value >= ((insn >> 21) & 0x1f)) + *errmsg = "index register in load range"; + return insn | ((value & 0x1f) << 16); +} + +/* The RA field in a D or X form instruction which is an updating + store or an updating floating point load, which means that the RA + field may not be zero. */ + +static unsigned long +insert_ras (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value == 0) + *errmsg = "invalid register operand when updating"; + return insn | ((value & 0x1f) << 16); +} + +/* The RB field in an X form instruction when it must be the same as + the RS field in the instruction. This is used for extended + mnemonics like mr. This operand is marked FAKE. The insertion + function just copies the BT field into the BA field, and the + extraction function just checks that the fields are the same. */ + +/*ARGSUSED*/ +static unsigned long +insert_rbs (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | (((insn >> 21) & 0x1f) << 11); +} + +static long +extract_rbs (insn, invalid) + unsigned long insn; + int *invalid; +{ + if (invalid != (int *) NULL + && ((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f)) + *invalid = 1; + return 0; +} + +/* The SH field in an MD form instruction. This is split. */ + +/*ARGSUSED*/ +static unsigned long +insert_sh6 (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4); +} + +/*ARGSUSED*/ +static long +extract_sh6 (insn, invalid) + unsigned long insn; + int *invalid; +{ + return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20); +} + +/* The SPR field in an XFX form instruction. This is flipped--the + lower 5 bits are stored in the upper 5 and vice- versa. */ + +static unsigned long +insert_spr (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); +} + +static long +extract_spr (insn, invalid) + unsigned long insn; + int *invalid; +{ + return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); +} + +/* The TBR field in an XFX instruction. This is just like SPR, but it + is optional. When TBR is omitted, it must be inserted as 268 (the + magic number of the TB register). These functions treat 0 + (indicating an omitted optional operand) as 268. This means that + ``mftb 4,0'' is not handled correctly. This does not matter very + much, since the architecture manual does not define mftb as + accepting any values other than 268 or 269. */ + +#define TB (268) + +static unsigned long +insert_tbr (insn, value, errmsg) + unsigned long insn; + long value; + const char **errmsg; +{ + if (value == 0) + value = TB; + return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); +} + +static long +extract_tbr (insn, invalid) + unsigned long insn; + int *invalid; +{ + long ret; + + ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); + if (ret == TB) + ret = 0; + return ret; +} + +/* Macros used to form opcodes. */ + +/* The main opcode. */ +#define OP(x) (((x) & 0x3f) << 26) +#define OP_MASK OP (0x3f) + +/* The main opcode combined with a trap code in the TO field of a D + form instruction. Used for extended mnemonics for the trap + instructions. */ +#define OPTO(x,to) (OP (x) | (((to) & 0x1f) << 21)) +#define OPTO_MASK (OP_MASK | TO_MASK) + +/* The main opcode combined with a comparison size bit in the L field + of a D form or X form instruction. Used for extended mnemonics for + the comparison instructions. */ +#define OPL(x,l) (OP (x) | (((l) & 1) << 21)) +#define OPL_MASK OPL (0x3f,1) + +/* An A form instruction. */ +#define A(op, xop, rc) (OP (op) | (((xop) & 0x1f) << 1) | ((rc) & 1)) +#define A_MASK A (0x3f, 0x1f, 1) + +/* An A_MASK with the FRB field fixed. */ +#define AFRB_MASK (A_MASK | FRB_MASK) + +/* An A_MASK with the FRC field fixed. */ +#define AFRC_MASK (A_MASK | FRC_MASK) + +/* An A_MASK with the FRA and FRC fields fixed. */ +#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK) + +/* A B form instruction. */ +#define B(op, aa, lk) (OP (op) | (((aa) & 1) << 1) | ((lk) & 1)) +#define B_MASK B (0x3f, 1, 1) + +/* A B form instruction setting the BO field. */ +#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | (((bo) & 0x1f) << 21)) +#define BBO_MASK BBO (0x3f, 0x1f, 1, 1) + +/* A BBO_MASK with the y bit of the BO field removed. This permits + matching a conditional branch regardless of the setting of the y + bit. */ +#define Y_MASK (1 << 21) +#define BBOY_MASK (BBO_MASK &~ Y_MASK) + +/* A B form instruction setting the BO field and the condition bits of + the BI field. */ +#define BBOCB(op, bo, cb, aa, lk) \ + (BBO ((op), (bo), (aa), (lk)) | (((cb) & 0x3) << 16)) +#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1) + +/* A BBOCB_MASK with the y bit of the BO field removed. */ +#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK) + +/* A BBOYCB_MASK in which the BI field is fixed. */ +#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK) + +/* The main opcode mask with the RA field clear. */ +#define DRA_MASK (OP_MASK | RA_MASK) + +/* A DS form instruction. */ +#define DSO(op, xop) (OP (op) | ((xop) & 0x3)) +#define DS_MASK DSO (0x3f, 3) + +/* An M form instruction. */ +#define M(op, rc) (OP (op) | ((rc) & 1)) +#define M_MASK M (0x3f, 1) + +/* An M form instruction with the ME field specified. */ +#define MME(op, me, rc) (M ((op), (rc)) | (((me) & 0x1f) << 1)) + +/* An M_MASK with the MB and ME fields fixed. */ +#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK) + +/* An M_MASK with the SH and ME fields fixed. */ +#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK) + +/* An MD form instruction. */ +#define MD(op, xop, rc) (OP (op) | (((xop) & 0x7) << 2) | ((rc) & 1)) +#define MD_MASK MD (0x3f, 0x7, 1) + +/* An MD_MASK with the MB field fixed. */ +#define MDMB_MASK (MD_MASK | MB6_MASK) + +/* An MD_MASK with the SH field fixed. */ +#define MDSH_MASK (MD_MASK | SH6_MASK) + +/* An MDS form instruction. */ +#define MDS(op, xop, rc) (OP (op) | (((xop) & 0xf) << 1) | ((rc) & 1)) +#define MDS_MASK MDS (0x3f, 0xf, 1) + +/* An MDS_MASK with the MB field fixed. */ +#define MDSMB_MASK (MDS_MASK | MB6_MASK) + +/* An SC form instruction. */ +#define SC(op, sa, lk) (OP (op) | (((sa) & 1) << 1) | ((lk) & 1)) +#define SC_MASK (OP_MASK | (0x3ff << 16) | (1 << 1) | 1) + +/* An X form instruction. */ +#define X(op, xop) (OP (op) | (((xop) & 0x3ff) << 1)) + +/* An X form instruction with the RC bit specified. */ +#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1)) + +/* The mask for an X form instruction. */ +#define X_MASK XRC (0x3f, 0x3ff, 1) + +/* An X_MASK with the RA field fixed. */ +#define XRA_MASK (X_MASK | RA_MASK) + +/* An X_MASK with the RB field fixed. */ +#define XRB_MASK (X_MASK | RB_MASK) + +/* An X_MASK with the RT field fixed. */ +#define XRT_MASK (X_MASK | RT_MASK) + +/* An X_MASK with the RA and RB fields fixed. */ +#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK) + +/* An X_MASK with the RT and RA fields fixed. */ +#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK) + +/* An X form comparison instruction. */ +#define XCMPL(op, xop, l) (X ((op), (xop)) | (((l) & 1) << 21)) + +/* The mask for an X form comparison instruction. */ +#define XCMP_MASK (X_MASK | (1 << 22)) + +/* The mask for an X form comparison instruction with the L field + fixed. */ +#define XCMPL_MASK (XCMP_MASK | (1 << 21)) + +/* An X form trap instruction with the TO field specified. */ +#define XTO(op, xop, to) (X ((op), (xop)) | (((to) & 0x1f) << 21)) +#define XTO_MASK (X_MASK | TO_MASK) + +/* An XFL form instruction. */ +#define XFL(op, xop, rc) (OP (op) | (((xop) & 0x3ff) << 1) | ((rc) & 1)) +#define XFL_MASK (XFL (0x3f, 0x3ff, 1) | (1 << 25) | (1 << 16)) + +/* An XL form instruction with the LK field set to 0. */ +#define XL(op, xop) (OP (op) | (((xop) & 0x3ff) << 1)) + +/* An XL form instruction which uses the LK field. */ +#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1)) + +/* The mask for an XL form instruction. */ +#define XL_MASK XLLK (0x3f, 0x3ff, 1) + +/* An XL form instruction which explicitly sets the BO field. */ +#define XLO(op, bo, xop, lk) \ + (XLLK ((op), (xop), (lk)) | (((bo) & 0x1f) << 21)) +#define XLO_MASK (XL_MASK | BO_MASK) + +/* An XL form instruction which explicitly sets the y bit of the BO + field. */ +#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | (((y) & 1) << 21)) +#define XLYLK_MASK (XL_MASK | Y_MASK) + +/* An XL form instruction which sets the BO field and the condition + bits of the BI field. */ +#define XLOCB(op, bo, cb, xop, lk) \ + (XLO ((op), (bo), (xop), (lk)) | (((cb) & 3) << 16)) +#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1) + +/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed. */ +#define XLBB_MASK (XL_MASK | BB_MASK) +#define XLYBB_MASK (XLYLK_MASK | BB_MASK) +#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK) + +/* An XL_MASK with the BO and BB fields fixed. */ +#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK) + +/* An XL_MASK with the BO, BI and BB fields fixed. */ +#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK) + +/* An XO form instruction. */ +#define XO(op, xop, oe, rc) \ + (OP (op) | (((xop) & 0x1ff) << 1) | (((oe) & 1) << 10) | ((rc) & 1)) +#define XO_MASK XO (0x3f, 0x1ff, 1, 1) + +/* An XO_MASK with the RB field fixed. */ +#define XORB_MASK (XO_MASK | RB_MASK) + +/* An XS form instruction. */ +#define XS(op, xop, rc) (OP (op) | (((xop) & 0x1ff) << 2) | ((rc) & 1)) +#define XS_MASK XS (0x3f, 0x1ff, 1) + +/* A mask for the FXM version of an XFX form instruction. */ +#define XFXFXM_MASK (X_MASK | (1 << 20) | (1 << 11)) + +/* An XFX form instruction with the FXM field filled in. */ +#define XFXM(op, xop, fxm) \ + (X ((op), (xop)) | (((fxm) & 0xff) << 12)) + +/* An XFX form instruction with the SPR field filled in. */ +#define XSPR(op, xop, spr) \ + (X ((op), (xop)) | (((spr) & 0x1f) << 16) | (((spr) & 0x3e0) << 6)) +#define XSPR_MASK (X_MASK | SPR_MASK) + +/* An XFX form instruction with the SPR field filled in except for the + SPRBAT field. */ +#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK) + +/* An XFX form instruction with the SPR field filled in except for the + SPRG field. */ +#define XSPRG_MASK (XSPR_MASK &~ SPRG_MASK) + +/* The BO encodings used in extended conditional branch mnemonics. */ +#define BODNZF (0x0) +#define BODNZFP (0x1) +#define BODZF (0x2) +#define BODZFP (0x3) +#define BOF (0x4) +#define BOFP (0x5) +#define BODNZT (0x8) +#define BODNZTP (0x9) +#define BODZT (0xa) +#define BODZTP (0xb) +#define BOT (0xc) +#define BOTP (0xd) +#define BODNZ (0x10) +#define BODNZP (0x11) +#define BODZ (0x12) +#define BODZP (0x13) +#define BOU (0x14) + +/* The BI condition bit encodings used in extended conditional branch + mnemonics. */ +#define CBLT (0) +#define CBGT (1) +#define CBEQ (2) +#define CBSO (3) + +/* The TO encodings used in extended trap mnemonics. */ +#define TOLGT (0x1) +#define TOLLT (0x2) +#define TOEQ (0x4) +#define TOLGE (0x5) +#define TOLNL (0x5) +#define TOLLE (0x6) +#define TOLNG (0x6) +#define TOGT (0x8) +#define TOGE (0xc) +#define TONL (0xc) +#define TOLT (0x10) +#define TOLE (0x14) +#define TONG (0x14) +#define TONE (0x18) +#define TOU (0x1f) + +/* Smaller names for the flags so each entry in the opcodes table will + fit on a single line. */ +#undef PPC +#define PPC PPC_OPCODE_PPC +#define POWER PPC_OPCODE_POWER +#define POWER2 PPC_OPCODE_POWER2 +#define B32 PPC_OPCODE_32 +#define B64 PPC_OPCODE_64 +#define M601 PPC_OPCODE_601 + +/* The opcode table. + + The format of the opcode table is: + + NAME OPCODE MASK FLAGS { 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. + FLAGS are flags indicated what processors support the instruction. + OPERANDS is the list of operands. + + 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. It is also + sorted by major opcode. */ + +const struct powerpc_opcode powerpc_opcodes[] = { +{ "tdlgti", OPTO(2,TOLGT), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdllti", OPTO(2,TOLLT), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdeqi", OPTO(2,TOEQ), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlgei", OPTO(2,TOLGE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlnli", OPTO(2,TOLNL), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdllei", OPTO(2,TOLLE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlngi", OPTO(2,TOLNG), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdgti", OPTO(2,TOGT), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdgei", OPTO(2,TOGE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdnli", OPTO(2,TONL), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlti", OPTO(2,TOLT), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdlei", OPTO(2,TOLE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdngi", OPTO(2,TONG), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdnei", OPTO(2,TONE), OPTO_MASK, PPC|B64, { RA, SI } }, +{ "tdi", OP(2), OP_MASK, PPC|B64, { TO, RA, SI } }, + +{ "twlgti", OPTO(3,TOLGT), OPTO_MASK, PPC, { RA, SI } }, +{ "tlgti", OPTO(3,TOLGT), OPTO_MASK, POWER, { RA, SI } }, +{ "twllti", OPTO(3,TOLLT), OPTO_MASK, PPC, { RA, SI } }, +{ "tllti", OPTO(3,TOLLT), OPTO_MASK, POWER, { RA, SI } }, +{ "tweqi", OPTO(3,TOEQ), OPTO_MASK, PPC, { RA, SI } }, +{ "teqi", OPTO(3,TOEQ), OPTO_MASK, POWER, { RA, SI } }, +{ "twlgei", OPTO(3,TOLGE), OPTO_MASK, PPC, { RA, SI } }, +{ "tlgei", OPTO(3,TOLGE), OPTO_MASK, POWER, { RA, SI } }, +{ "twlnli", OPTO(3,TOLNL), OPTO_MASK, PPC, { RA, SI } }, +{ "tlnli", OPTO(3,TOLNL), OPTO_MASK, POWER, { RA, SI } }, +{ "twllei", OPTO(3,TOLLE), OPTO_MASK, PPC, { RA, SI } }, +{ "tllei", OPTO(3,TOLLE), OPTO_MASK, POWER, { RA, SI } }, +{ "twlngi", OPTO(3,TOLNG), OPTO_MASK, PPC, { RA, SI } }, +{ "tlngi", OPTO(3,TOLNG), OPTO_MASK, POWER, { RA, SI } }, +{ "twgti", OPTO(3,TOGT), OPTO_MASK, PPC, { RA, SI } }, +{ "tgti", OPTO(3,TOGT), OPTO_MASK, POWER, { RA, SI } }, +{ "twgei", OPTO(3,TOGE), OPTO_MASK, PPC, { RA, SI } }, +{ "tgei", OPTO(3,TOGE), OPTO_MASK, POWER, { RA, SI } }, +{ "twnli", OPTO(3,TONL), OPTO_MASK, PPC, { RA, SI } }, +{ "tnli", OPTO(3,TONL), OPTO_MASK, POWER, { RA, SI } }, +{ "twlti", OPTO(3,TOLT), OPTO_MASK, PPC, { RA, SI } }, +{ "tlti", OPTO(3,TOLT), OPTO_MASK, POWER, { RA, SI } }, +{ "twlei", OPTO(3,TOLE), OPTO_MASK, PPC, { RA, SI } }, +{ "tlei", OPTO(3,TOLE), OPTO_MASK, POWER, { RA, SI } }, +{ "twngi", OPTO(3,TONG), OPTO_MASK, PPC, { RA, SI } }, +{ "tngi", OPTO(3,TONG), OPTO_MASK, POWER, { RA, SI } }, +{ "twnei", OPTO(3,TONE), OPTO_MASK, PPC, { RA, SI } }, +{ "tnei", OPTO(3,TONE), OPTO_MASK, POWER, { RA, SI } }, +{ "twi", OP(3), OP_MASK, PPC, { TO, RA, SI } }, +{ "ti", OP(3), OP_MASK, POWER, { TO, RA, SI } }, + +{ "mulli", OP(7), OP_MASK, PPC, { RT, RA, SI } }, +{ "muli", OP(7), OP_MASK, POWER, { RT, RA, SI } }, + +{ "subfic", OP(8), OP_MASK, PPC, { RT, RA, SI } }, +{ "sfi", OP(8), OP_MASK, POWER, { RT, RA, SI } }, + +{ "dozi", OP(9), OP_MASK, POWER|M601, { RT, RA, SI } }, + +{ "cmplwi", OPL(10,0), OPL_MASK, PPC, { OBF, RA, UI } }, +{ "cmpldi", OPL(10,1), OPL_MASK, PPC|B64, { OBF, RA, UI } }, +{ "cmpli", OP(10), OP_MASK, PPC, { BF, L, RA, UI } }, +{ "cmpli", OP(10), OP_MASK, POWER, { BF, RA, UI } }, + +{ "cmpwi", OPL(11,0), OPL_MASK, PPC, { OBF, RA, SI } }, +{ "cmpdi", OPL(11,1), OPL_MASK, PPC|B64, { OBF, RA, SI } }, +{ "cmpi", OP(11), OP_MASK, PPC, { BF, L, RA, SI } }, +{ "cmpi", OP(11), OP_MASK, POWER, { BF, RA, SI } }, + +{ "addic", OP(12), OP_MASK, PPC, { RT, RA, SI } }, +{ "ai", OP(12), OP_MASK, POWER, { RT, RA, SI } }, +{ "subic", OP(12), OP_MASK, PPC, { RT, RA, NSI } }, + +{ "addic.", OP(13), OP_MASK, PPC, { RT, RA, SI } }, +{ "ai.", OP(13), OP_MASK, POWER, { RT, RA, SI } }, +{ "subic.", OP(13), OP_MASK, PPC, { RT, RA, NSI } }, + +{ "li", OP(14), DRA_MASK, PPC, { RT, SI } }, +{ "lil", OP(14), DRA_MASK, POWER, { RT, SI } }, +{ "addi", OP(14), OP_MASK, PPC, { RT, RA, SI } }, +{ "cal", OP(14), OP_MASK, POWER, { RT, D, RA } }, +{ "subi", OP(14), OP_MASK, PPC, { RT, RA, NSI } }, +{ "la", OP(14), OP_MASK, PPC, { RT, D, RA } }, + +{ "lis", OP(15), DRA_MASK, PPC, { RT, SISIGNOPT } }, +{ "liu", OP(15), DRA_MASK, POWER, { RT, SISIGNOPT } }, +{ "addis", OP(15), OP_MASK, PPC, { RT,RA,SISIGNOPT } }, +{ "cau", OP(15), OP_MASK, POWER, { RT,RA,SISIGNOPT } }, +{ "subis", OP(15), OP_MASK, PPC, { RT, RA, NSI } }, + +{ "bdnz-", BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC, { BDM } }, +{ "bdnz+", BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC, { BDP } }, +{ "bdnz", BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC, { BD } }, +{ "bdn", BBO(16,BODNZ,0,0), BBOYBI_MASK, POWER, { BD } }, +{ "bdnzl-", BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC, { BDM } }, +{ "bdnzl+", BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC, { BDP } }, +{ "bdnzl", BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC, { BD } }, +{ "bdnl", BBO(16,BODNZ,0,1), BBOYBI_MASK, POWER, { BD } }, +{ "bdnza-", BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC, { BDMA } }, +{ "bdnza+", BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC, { BDPA } }, +{ "bdnza", BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC, { BDA } }, +{ "bdna", BBO(16,BODNZ,1,0), BBOYBI_MASK, POWER, { BDA } }, +{ "bdnzla-", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC, { BDMA } }, +{ "bdnzla+", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC, { BDPA } }, +{ "bdnzla", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC, { BDA } }, +{ "bdnla", BBO(16,BODNZ,1,1), BBOYBI_MASK, POWER, { BDA } }, +{ "bdz-", BBO(16,BODZ,0,0), BBOYBI_MASK, PPC, { BDM } }, +{ "bdz+", BBO(16,BODZ,0,0), BBOYBI_MASK, PPC, { BDP } }, +{ "bdz", BBO(16,BODZ,0,0), BBOYBI_MASK, PPC|POWER, { BD } }, +{ "bdzl-", BBO(16,BODZ,0,1), BBOYBI_MASK, PPC, { BDM } }, +{ "bdzl+", BBO(16,BODZ,0,1), BBOYBI_MASK, PPC, { BDP } }, +{ "bdzl", BBO(16,BODZ,0,1), BBOYBI_MASK, PPC|POWER, { BD } }, +{ "bdza-", BBO(16,BODZ,1,0), BBOYBI_MASK, PPC, { BDMA } }, +{ "bdza+", BBO(16,BODZ,1,0), BBOYBI_MASK, PPC, { BDPA } }, +{ "bdza", BBO(16,BODZ,1,0), BBOYBI_MASK, PPC|POWER, { BDA } }, +{ "bdzla-", BBO(16,BODZ,1,1), BBOYBI_MASK, PPC, { BDMA } }, +{ "bdzla+", BBO(16,BODZ,1,1), BBOYBI_MASK, PPC, { BDPA } }, +{ "bdzla", BBO(16,BODZ,1,1), BBOYBI_MASK, PPC|POWER, { BDA } }, +{ "blt-", BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "blt+", BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "blt", BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bltl-", BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bltl+", BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bltl", BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "blta-", BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "blta+", BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "blta", BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bltla-", BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bltla+", BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bltla", BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bgt-", BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bgt+", BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bgt", BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bgtl-", BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bgtl+", BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bgtl", BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bgta-", BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bgta+", BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bgta", BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bgtla-", BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bgtla+", BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bgtla", BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "beq-", BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "beq+", BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "beq", BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "beql-", BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "beql+", BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "beql", BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "beqa-", BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "beqa+", BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "beqa", BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "beqla-", BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "beqla+", BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "beqla", BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bso-", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bso+", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bso", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bsol-", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bsol+", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bsol", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bsoa-", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bsoa+", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bsoa", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bsola-", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bsola+", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bsola", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bun-", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bun+", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bun", BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BD } }, +{ "bunl-", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bunl+", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bunl", BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BD } }, +{ "buna-", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "buna+", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "buna", BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDA } }, +{ "bunla-", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bunla+", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bunla", BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDA } }, +{ "bge-", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bge+", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bge", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bgel-", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bgel+", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bgel", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bgea-", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bgea+", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bgea", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bgela-", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bgela+", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bgela", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnl-", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnl+", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnl", BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnll-", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnll+", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnll", BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnla-", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnla+", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnla", BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnlla-", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnlla+", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnlla", BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "ble-", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "ble+", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "ble", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "blel-", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "blel+", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "blel", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "blea-", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "blea+", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "blea", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "blela-", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "blela+", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "blela", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bng-", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bng+", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bng", BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bngl-", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bngl+", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bngl", BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnga-", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnga+", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnga", BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bngla-", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bngla+", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bngla", BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bne-", BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bne+", BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bne", BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnel-", BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnel+", BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnel", BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnea-", BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnea+", BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnea", BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnela-", BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnela+", BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnela", BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bns-", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bns+", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bns", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnsl-", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnsl+", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnsl", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } }, +{ "bnsa-", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnsa+", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnsa", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnsla-", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnsla+", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnsla", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } }, +{ "bnu-", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnu+", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnu", BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BD } }, +{ "bnul-", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } }, +{ "bnul+", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } }, +{ "bnul", BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BD } }, +{ "bnua-", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnua+", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnua", BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDA } }, +{ "bnula-", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } }, +{ "bnula+", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } }, +{ "bnula", BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDA } }, +{ "bdnzt-", BBO(16,BODNZT,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdnzt+", BBO(16,BODNZT,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdnzt", BBO(16,BODNZT,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdnztl", BBO(16,BODNZT,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdnzta", BBO(16,BODNZT,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdnzf-", BBO(16,BODNZF,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdnzf+", BBO(16,BODNZF,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdnzf", BBO(16,BODNZF,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdnzfl", BBO(16,BODNZF,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdnzfa", BBO(16,BODNZF,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bt-", BBO(16,BOT,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bt+", BBO(16,BOT,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bt", BBO(16,BOT,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bbt", BBO(16,BOT,0,0), BBOY_MASK, POWER, { BI, BD } }, +{ "btl-", BBO(16,BOT,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "btl+", BBO(16,BOT,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "btl", BBO(16,BOT,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bbtl", BBO(16,BOT,0,1), BBOY_MASK, POWER, { BI, BD } }, +{ "bta-", BBO(16,BOT,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bta+", BBO(16,BOT,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bta", BBO(16,BOT,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bbta", BBO(16,BOT,1,0), BBOY_MASK, POWER, { BI, BDA } }, +{ "btla-", BBO(16,BOT,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "btla+", BBO(16,BOT,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "btla", BBO(16,BOT,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bbtla", BBO(16,BOT,1,1), BBOY_MASK, POWER, { BI, BDA } }, +{ "bf-", BBO(16,BOF,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bf+", BBO(16,BOF,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bf", BBO(16,BOF,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bbf", BBO(16,BOF,0,0), BBOY_MASK, POWER, { BI, BD } }, +{ "bfl-", BBO(16,BOF,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bfl+", BBO(16,BOF,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bfl", BBO(16,BOF,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bbfl", BBO(16,BOF,0,1), BBOY_MASK, POWER, { BI, BD } }, +{ "bfa-", BBO(16,BOF,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bfa+", BBO(16,BOF,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bfa", BBO(16,BOF,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bbfa", BBO(16,BOF,1,0), BBOY_MASK, POWER, { BI, BDA } }, +{ "bfla-", BBO(16,BOF,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bfla+", BBO(16,BOF,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bfla", BBO(16,BOF,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bbfla", BBO(16,BOF,1,1), BBOY_MASK, POWER, { BI, BDA } }, +{ "bdzt-", BBO(16,BODZT,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdzt+", BBO(16,BODZT,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdzt", BBO(16,BODZT,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bdztl-", BBO(16,BODZT,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdztl+", BBO(16,BODZT,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdztl", BBO(16,BODZT,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bdzta-", BBO(16,BODZT,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdzta+", BBO(16,BODZT,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdzta", BBO(16,BODZT,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdztla", BBO(16,BODZT,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdzf-", BBO(16,BODZF,0,0), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdzf+", BBO(16,BODZF,0,0), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdzf", BBO(16,BODZF,0,0), BBOY_MASK, PPC, { BI, BD } }, +{ "bdzfl-", BBO(16,BODZF,0,1), BBOY_MASK, PPC, { BI, BDM } }, +{ "bdzfl+", BBO(16,BODZF,0,1), BBOY_MASK, PPC, { BI, BDP } }, +{ "bdzfl", BBO(16,BODZF,0,1), BBOY_MASK, PPC, { BI, BD } }, +{ "bdzfa-", BBO(16,BODZF,1,0), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdzfa+", BBO(16,BODZF,1,0), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdzfa", BBO(16,BODZF,1,0), BBOY_MASK, PPC, { BI, BDA } }, +{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, PPC, { BI, BDMA } }, +{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, PPC, { BI, BDPA } }, +{ "bdzfla", BBO(16,BODZF,1,1), BBOY_MASK, PPC, { BI, BDA } }, +{ "bc-", B(16,0,0), B_MASK, PPC, { BOE, BI, BDM } }, +{ "bc+", B(16,0,0), B_MASK, PPC, { BOE, BI, BDP } }, +{ "bc", B(16,0,0), B_MASK, PPC|POWER, { BO, BI, BD } }, +{ "bcl-", B(16,0,1), B_MASK, PPC, { BOE, BI, BDM } }, +{ "bcl+", B(16,0,1), B_MASK, PPC, { BOE, BI, BDP } }, +{ "bcl", B(16,0,1), B_MASK, PPC|POWER, { BO, BI, BD } }, +{ "bca-", B(16,1,0), B_MASK, PPC, { BOE, BI, BDMA } }, +{ "bca+", B(16,1,0), B_MASK, PPC, { BOE, BI, BDPA } }, +{ "bca", B(16,1,0), B_MASK, PPC|POWER, { BO, BI, BDA } }, +{ "bcla-", B(16,1,1), B_MASK, PPC, { BOE, BI, BDMA } }, +{ "bcla+", B(16,1,1), B_MASK, PPC, { BOE, BI, BDPA } }, +{ "bcla", B(16,1,1), B_MASK, PPC|POWER, { BO, BI, BDA } }, + +{ "sc", SC(17,1,0), 0xffffffff, PPC, { 0 } }, +{ "svc", SC(17,0,0), SC_MASK, POWER, { LEV, FL1, FL2 } }, +{ "svcl", SC(17,0,1), SC_MASK, POWER, { LEV, FL1, FL2 } }, +{ "svca", SC(17,1,0), SC_MASK, POWER, { SV } }, +{ "svcla", SC(17,1,1), SC_MASK, POWER, { SV } }, + +{ "b", B(18,0,0), B_MASK, PPC|POWER, { LI } }, +{ "bl", B(18,0,1), B_MASK, PPC|POWER, { LI } }, +{ "ba", B(18,1,0), B_MASK, PPC|POWER, { LIA } }, +{ "bla", B(18,1,1), B_MASK, PPC|POWER, { LIA } }, + +{ "mcrf", XL(19,0), XLBB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } }, + +{ "blr", XLO(19,BOU,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "br", XLO(19,BOU,16,0), XLBOBIBB_MASK, POWER, { 0 } }, +{ "blrl", XLO(19,BOU,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "brl", XLO(19,BOU,16,1), XLBOBIBB_MASK, POWER, { 0 } }, +{ "bdnzlr", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlr", XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlr-", XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlr+", XLO(19,BODZP,16,0), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlrl", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, PPC, { 0 } }, +{ "bltlr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltlr-", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltlr+", XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltr", XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bltlrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltrl", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bgtlr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtlr-", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtlr+", XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtr", XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bgtlrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtrl", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "beqlr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqlr-", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqlr+", XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqr", XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "beqlrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqrl", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bsolr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsolr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsolr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsor", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bsolrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsorl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bunlr", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlr-", XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlr+", XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlrl", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bger", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bgelrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgerl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnllr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnllr-", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnllr+", XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlr", XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnllrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlrl", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "blelr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blelr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blelr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bler", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "blelrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blerl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnglr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnglr-", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnglr+", XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngr", XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnglrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngrl", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnelr", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnelr-", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnelr+", XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bner", XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnelrl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnerl", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnslr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnslr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnslr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnslrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } }, +{ "bnulr", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulr-", XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulr+", XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulrl", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "btlr", XLO(19,BOT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "btlr-", XLO(19,BOT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "btlr+", XLO(19,BOTP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bbtr", XLO(19,BOT,16,0), XLBOBB_MASK, POWER, { BI } }, +{ "btlrl", XLO(19,BOT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "btlrl-", XLO(19,BOT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "btlrl+", XLO(19,BOTP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bbtrl", XLO(19,BOT,16,1), XLBOBB_MASK, POWER, { BI } }, +{ "bflr", XLO(19,BOF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bflr-", XLO(19,BOF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bflr+", XLO(19,BOFP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bbfr", XLO(19,BOF,16,0), XLBOBB_MASK, POWER, { BI } }, +{ "bflrl", XLO(19,BOF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bflrl-", XLO(19,BOF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bflrl+", XLO(19,BOFP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bbfrl", XLO(19,BOF,16,1), XLBOBB_MASK, POWER, { BI } }, +{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlr", XLO(19,BODZT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflr", XLO(19,BODZF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, PPC, { BI } }, +{ "bclr", XLLK(19,16,0), XLYBB_MASK, PPC, { BO, BI } }, +{ "bclrl", XLLK(19,16,1), XLYBB_MASK, PPC, { BO, BI } }, +{ "bclr+", XLYLK(19,16,1,0), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bclrl+", XLYLK(19,16,1,1), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bclr-", XLYLK(19,16,0,0), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bclrl-", XLYLK(19,16,0,1), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcr", XLLK(19,16,0), XLBB_MASK, POWER, { BO, BI } }, +{ "bcrl", XLLK(19,16,1), XLBB_MASK, POWER, { BO, BI } }, + +{ "crnot", XL(19,33), XL_MASK, PPC, { BT, BA, BBA } }, +{ "crnor", XL(19,33), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "rfi", XL(19,50), 0xffffffff, PPC|POWER, { 0 } }, +{ "rfci", XL(19,51), 0xffffffff, PPC, { 0 } }, + +{ "rfsvc", XL(19,82), 0xffffffff, POWER, { 0 } }, + +{ "crandc", XL(19,129), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "isync", XL(19,150), 0xffffffff, PPC, { 0 } }, +{ "ics", XL(19,150), 0xffffffff, POWER, { 0 } }, + +{ "crclr", XL(19,193), XL_MASK, PPC, { BT, BAT, BBA } }, +{ "crxor", XL(19,193), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crnand", XL(19,225), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crand", XL(19,257), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crset", XL(19,289), XL_MASK, PPC, { BT, BAT, BBA } }, +{ "creqv", XL(19,289), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crorc", XL(19,417), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "crmove", XL(19,449), XL_MASK, PPC, { BT, BA, BBA } }, +{ "cror", XL(19,449), XL_MASK, PPC|POWER, { BT, BA, BB } }, + +{ "bctr", XLO(19,BOU,528,0), XLBOBIBB_MASK, PPC|POWER, { 0 } }, +{ "bctrl", XLO(19,BOU,528,1), XLBOBIBB_MASK, PPC|POWER, { 0 } }, +{ "bltctr", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctr", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctr", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctr", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctr", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctr", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectr", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctr", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } }, +{ "btctr", XLO(19,BOT,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "btctr-", XLO(19,BOT,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "btctr+", XLO(19,BOTP,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "btctrl", XLO(19,BOT,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "bfctr", XLO(19,BOF,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "bfctr-", XLO(19,BOF,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "bfctr+", XLO(19,BOFP,528,0), XLBOBB_MASK, PPC, { BI } }, +{ "bfctrl", XLO(19,BOF,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, PPC, { BI } }, +{ "bcctr", XLLK(19,528,0), XLYBB_MASK, PPC, { BO, BI } }, +{ "bcctr-", XLYLK(19,528,0,0), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcctr+", XLYLK(19,528,1,0), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcctrl", XLLK(19,528,1), XLYBB_MASK, PPC, { BO, BI } }, +{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPC, { BOE, BI } }, +{ "bcc", XLLK(19,528,0), XLBB_MASK, POWER, { BO, BI } }, +{ "bccl", XLLK(19,528,1), XLBB_MASK, POWER, { BO, BI } }, + +{ "rlwimi", M(20,0), M_MASK, PPC, { RA,RS,SH,MBE,ME } }, +{ "rlimi", M(20,0), M_MASK, POWER, { RA,RS,SH,MBE,ME } }, + +{ "rlwimi.", M(20,1), M_MASK, PPC, { RA,RS,SH,MBE,ME } }, +{ "rlimi.", M(20,1), M_MASK, POWER, { RA,RS,SH,MBE,ME } }, + +{ "rotlwi", MME(21,31,0), MMBME_MASK, PPC, { RA, RS, SH } }, +{ "clrlwi", MME(21,31,0), MSHME_MASK, PPC, { RA, RS, MB } }, +{ "rlwinm", M(21,0), M_MASK, PPC, { RA,RS,SH,MBE,ME } }, +{ "rlinm", M(21,0), M_MASK, POWER, { RA,RS,SH,MBE,ME } }, +{ "rotlwi.", MME(21,31,1), MMBME_MASK, PPC, { RA,RS,SH } }, +{ "clrlwi.", MME(21,31,1), MSHME_MASK, PPC, { RA, RS, MB } }, +{ "rlwinm.", M(21,1), M_MASK, PPC, { RA,RS,SH,MBE,ME } }, +{ "rlinm.", M(21,1), M_MASK, POWER, { RA,RS,SH,MBE,ME } }, + +{ "rlmi", M(22,0), M_MASK, POWER|M601, { RA,RS,RB,MBE,ME } }, +{ "rlmi.", M(22,1), M_MASK, POWER|M601, { RA,RS,RB,MBE,ME } }, + +{ "rotlw", MME(23,31,0), MMBME_MASK, PPC, { RA, RS, RB } }, +{ "rlwnm", M(23,0), M_MASK, PPC, { RA,RS,RB,MBE,ME } }, +{ "rlnm", M(23,0), M_MASK, POWER, { RA,RS,RB,MBE,ME } }, +{ "rotlw.", MME(23,31,1), MMBME_MASK, PPC, { RA, RS, RB } }, +{ "rlwnm.", M(23,1), M_MASK, PPC, { RA,RS,RB,MBE,ME } }, +{ "rlnm.", M(23,1), M_MASK, POWER, { RA,RS,RB,MBE,ME } }, + +{ "nop", OP(24), 0xffffffff, PPC, { 0 } }, +{ "ori", OP(24), OP_MASK, PPC, { RA, RS, UI } }, +{ "oril", OP(24), OP_MASK, POWER, { RA, RS, UI } }, + +{ "oris", OP(25), OP_MASK, PPC, { RA, RS, UI } }, +{ "oriu", OP(25), OP_MASK, POWER, { RA, RS, UI } }, + +{ "xori", OP(26), OP_MASK, PPC, { RA, RS, UI } }, +{ "xoril", OP(26), OP_MASK, POWER, { RA, RS, UI } }, + +{ "xoris", OP(27), OP_MASK, PPC, { RA, RS, UI } }, +{ "xoriu", OP(27), OP_MASK, POWER, { RA, RS, UI } }, + +{ "andi.", OP(28), OP_MASK, PPC, { RA, RS, UI } }, +{ "andil.", OP(28), OP_MASK, POWER, { RA, RS, UI } }, + +{ "andis.", OP(29), OP_MASK, PPC, { RA, RS, UI } }, +{ "andiu.", OP(29), OP_MASK, POWER, { RA, RS, UI } }, + +{ "rotldi", MD(30,0,0), MDMB_MASK, PPC|B64, { RA, RS, SH6 } }, +{ "clrldi", MD(30,0,0), MDSH_MASK, PPC|B64, { RA, RS, MB6 } }, +{ "rldicl", MD(30,0,0), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, +{ "rotldi.", MD(30,0,1), MDMB_MASK, PPC|B64, { RA, RS, SH6 } }, +{ "clrldi.", MD(30,0,1), MDSH_MASK, PPC|B64, { RA, RS, MB6 } }, +{ "rldicl.", MD(30,0,1), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, + +{ "rldicr", MD(30,1,0), MD_MASK, PPC|B64, { RA, RS, SH6, ME6 } }, +{ "rldicr.", MD(30,1,1), MD_MASK, PPC|B64, { RA, RS, SH6, ME6 } }, + +{ "rldic", MD(30,2,0), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, +{ "rldic.", MD(30,2,1), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, + +{ "rldimi", MD(30,3,0), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, +{ "rldimi.", MD(30,3,1), MD_MASK, PPC|B64, { RA, RS, SH6, MB6 } }, + +{ "rotld", MDS(30,8,0), MDSMB_MASK, PPC|B64, { RA, RS, RB } }, +{ "rldcl", MDS(30,8,0), MDS_MASK, PPC|B64, { RA, RS, RB, MB6 } }, +{ "rotld.", MDS(30,8,1), MDSMB_MASK, PPC|B64, { RA, RS, RB } }, +{ "rldcl.", MDS(30,8,1), MDS_MASK, PPC|B64, { RA, RS, RB, MB6 } }, + +{ "rldcr", MDS(30,9,0), MDS_MASK, PPC|B64, { RA, RS, RB, ME6 } }, +{ "rldcr.", MDS(30,9,1), MDS_MASK, PPC|B64, { RA, RS, RB, ME6 } }, + +{ "cmpw", XCMPL(31,0,0), XCMPL_MASK, PPC, { OBF, RA, RB } }, +{ "cmpd", XCMPL(31,0,1), XCMPL_MASK, PPC|B64, { OBF, RA, RB } }, +{ "cmp", X(31,0), XCMP_MASK, PPC, { BF, L, RA, RB } }, +{ "cmp", X(31,0), XCMPL_MASK, POWER, { BF, RA, RB } }, + +{ "twlgt", XTO(31,4,TOLGT), XTO_MASK, PPC, { RA, RB } }, +{ "tlgt", XTO(31,4,TOLGT), XTO_MASK, POWER, { RA, RB } }, +{ "twllt", XTO(31,4,TOLLT), XTO_MASK, PPC, { RA, RB } }, +{ "tllt", XTO(31,4,TOLLT), XTO_MASK, POWER, { RA, RB } }, +{ "tweq", XTO(31,4,TOEQ), XTO_MASK, PPC, { RA, RB } }, +{ "teq", XTO(31,4,TOEQ), XTO_MASK, POWER, { RA, RB } }, +{ "twlge", XTO(31,4,TOLGE), XTO_MASK, PPC, { RA, RB } }, +{ "tlge", XTO(31,4,TOLGE), XTO_MASK, POWER, { RA, RB } }, +{ "twlnl", XTO(31,4,TOLNL), XTO_MASK, PPC, { RA, RB } }, +{ "tlnl", XTO(31,4,TOLNL), XTO_MASK, POWER, { RA, RB } }, +{ "twlle", XTO(31,4,TOLLE), XTO_MASK, PPC, { RA, RB } }, +{ "tlle", XTO(31,4,TOLLE), XTO_MASK, POWER, { RA, RB } }, +{ "twlng", XTO(31,4,TOLNG), XTO_MASK, PPC, { RA, RB } }, +{ "tlng", XTO(31,4,TOLNG), XTO_MASK, POWER, { RA, RB } }, +{ "twgt", XTO(31,4,TOGT), XTO_MASK, PPC, { RA, RB } }, +{ "tgt", XTO(31,4,TOGT), XTO_MASK, POWER, { RA, RB } }, +{ "twge", XTO(31,4,TOGE), XTO_MASK, PPC, { RA, RB } }, +{ "tge", XTO(31,4,TOGE), XTO_MASK, POWER, { RA, RB } }, +{ "twnl", XTO(31,4,TONL), XTO_MASK, PPC, { RA, RB } }, +{ "tnl", XTO(31,4,TONL), XTO_MASK, POWER, { RA, RB } }, +{ "twlt", XTO(31,4,TOLT), XTO_MASK, PPC, { RA, RB } }, +{ "tlt", XTO(31,4,TOLT), XTO_MASK, POWER, { RA, RB } }, +{ "twle", XTO(31,4,TOLE), XTO_MASK, PPC, { RA, RB } }, +{ "tle", XTO(31,4,TOLE), XTO_MASK, POWER, { RA, RB } }, +{ "twng", XTO(31,4,TONG), XTO_MASK, PPC, { RA, RB } }, +{ "tng", XTO(31,4,TONG), XTO_MASK, POWER, { RA, RB } }, +{ "twne", XTO(31,4,TONE), XTO_MASK, PPC, { RA, RB } }, +{ "tne", XTO(31,4,TONE), XTO_MASK, POWER, { RA, RB } }, +{ "trap", XTO(31,4,TOU), 0xffffffff, PPC, { 0 } }, +{ "tw", X(31,4), X_MASK, PPC, { TO, RA, RB } }, +{ "t", X(31,4), X_MASK, POWER, { TO, RA, RB } }, + +{ "subfc", XO(31,8,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sf", XO(31,8,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "subc", XO(31,8,0,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfc.", XO(31,8,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sf.", XO(31,8,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "subc.", XO(31,8,0,1), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfco", XO(31,8,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfo", XO(31,8,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "subco", XO(31,8,1,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfco.", XO(31,8,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfo.", XO(31,8,1,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "subco.", XO(31,8,1,1), XO_MASK, PPC, { RT, RB, RA } }, + +{ "mulhdu", XO(31,9,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulhdu.", XO(31,9,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "addc", XO(31,10,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "a", XO(31,10,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "addc.", XO(31,10,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "a.", XO(31,10,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "addco", XO(31,10,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "ao", XO(31,10,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "addco.", XO(31,10,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "ao.", XO(31,10,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "mulhwu", XO(31,11,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulhwu.", XO(31,11,0,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "mfcr", X(31,19), XRARB_MASK, POWER|PPC, { RT } }, + +{ "lwarx", X(31,20), X_MASK, PPC, { RT, RA, RB } }, + +{ "ldx", X(31,21), X_MASK, PPC|B64, { RT, RA, RB } }, + +{ "lwzx", X(31,23), X_MASK, PPC, { RT, RA, RB } }, +{ "lx", X(31,23), X_MASK, POWER, { RT, RA, RB } }, + +{ "slw", XRC(31,24,0), X_MASK, PPC, { RA, RS, RB } }, +{ "sl", XRC(31,24,0), X_MASK, POWER, { RA, RS, RB } }, +{ "slw.", XRC(31,24,1), X_MASK, PPC, { RA, RS, RB } }, +{ "sl.", XRC(31,24,1), X_MASK, POWER, { RA, RS, RB } }, + +{ "cntlzw", XRC(31,26,0), XRB_MASK, PPC, { RA, RS } }, +{ "cntlz", XRC(31,26,0), XRB_MASK, POWER, { RA, RS } }, +{ "cntlzw.", XRC(31,26,1), XRB_MASK, PPC, { RA, RS } }, +{ "cntlz.", XRC(31,26,1), XRB_MASK, POWER, { RA, RS } }, + +{ "sld", XRC(31,27,0), X_MASK, PPC|B64, { RA, RS, RB } }, +{ "sld.", XRC(31,27,1), X_MASK, PPC|B64, { RA, RS, RB } }, + +{ "and", XRC(31,28,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "and.", XRC(31,28,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "maskg", XRC(31,29,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "maskg.", XRC(31,29,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "cmplw", XCMPL(31,32,0), XCMPL_MASK, PPC, { OBF, RA, RB } }, +{ "cmpld", XCMPL(31,32,1), XCMPL_MASK, PPC|B64, { OBF, RA, RB } }, +{ "cmpl", X(31,32), XCMP_MASK, PPC, { BF, L, RA, RB } }, +{ "cmpl", X(31,32), XCMPL_MASK, POWER, { BF, RA, RB } }, + +{ "subf", XO(31,40,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sub", XO(31,40,0,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subf.", XO(31,40,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sub.", XO(31,40,0,1), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfo", XO(31,40,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "subo", XO(31,40,1,0), XO_MASK, PPC, { RT, RB, RA } }, +{ "subfo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "subo.", XO(31,40,1,1), XO_MASK, PPC, { RT, RB, RA } }, + +{ "ldux", X(31,53), X_MASK, PPC|B64, { RT, RAL, RB } }, + +{ "dcbst", X(31,54), XRT_MASK, PPC, { RA, RB } }, + +{ "lwzux", X(31,55), X_MASK, PPC, { RT, RAL, RB } }, +{ "lux", X(31,55), X_MASK, POWER, { RT, RA, RB } }, + +{ "cntlzd", XRC(31,58,0), XRB_MASK, PPC|B64, { RA, RS } }, +{ "cntlzd.", XRC(31,58,1), XRB_MASK, PPC|B64, { RA, RS } }, + +{ "andc", XRC(31,60,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "andc.", XRC(31,60,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "tdlgt", XTO(31,68,TOLGT), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdllt", XTO(31,68,TOLLT), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdeq", XTO(31,68,TOEQ), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlge", XTO(31,68,TOLGE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlnl", XTO(31,68,TOLNL), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlle", XTO(31,68,TOLLE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlng", XTO(31,68,TOLNG), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdgt", XTO(31,68,TOGT), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdge", XTO(31,68,TOGE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdnl", XTO(31,68,TONL), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdlt", XTO(31,68,TOLT), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdle", XTO(31,68,TOLE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdng", XTO(31,68,TONG), XTO_MASK, PPC|B64, { RA, RB } }, +{ "tdne", XTO(31,68,TONE), XTO_MASK, PPC|B64, { RA, RB } }, +{ "td", X(31,68), X_MASK, PPC|B64, { TO, RA, RB } }, + +{ "mulhd", XO(31,73,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulhd.", XO(31,73,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "mulhw", XO(31,75,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulhw.", XO(31,75,0,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "mfmsr", X(31,83), XRARB_MASK, PPC|POWER, { RT } }, + +{ "ldarx", X(31,84), X_MASK, PPC|B64, { RT, RA, RB } }, + +{ "dcbf", X(31,86), XRT_MASK, PPC, { RA, RB } }, + +{ "lbzx", X(31,87), X_MASK, PPC|POWER, { RT, RA, RB } }, + +{ "neg", XO(31,104,0,0), XORB_MASK, PPC|POWER, { RT, RA } }, +{ "neg.", XO(31,104,0,1), XORB_MASK, PPC|POWER, { RT, RA } }, +{ "nego", XO(31,104,1,0), XORB_MASK, PPC|POWER, { RT, RA } }, +{ "nego.", XO(31,104,1,1), XORB_MASK, PPC|POWER, { RT, RA } }, + +{ "mul", XO(31,107,0,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "mul.", XO(31,107,0,1), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "mulo", XO(31,107,1,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "mulo.", XO(31,107,1,1), XO_MASK, POWER|M601, { RT, RA, RB } }, + +{ "clf", X(31,118), XRB_MASK, POWER, { RT, RA } }, + +{ "lbzux", X(31,119), X_MASK, PPC|POWER, { RT, RAL, RB } }, + +{ "not", XRC(31,124,0), X_MASK, PPC|POWER, { RA, RS, RBS } }, +{ "nor", XRC(31,124,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "not.", XRC(31,124,1), X_MASK, PPC|POWER, { RA, RS, RBS } }, +{ "nor.", XRC(31,124,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "subfe", XO(31,136,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfe", XO(31,136,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "subfe.", XO(31,136,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfe.", XO(31,136,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "subfeo", XO(31,136,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfeo", XO(31,136,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "subfeo.", XO(31,136,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "sfeo.", XO(31,136,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "adde", XO(31,138,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "ae", XO(31,138,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "adde.", XO(31,138,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "ae.", XO(31,138,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "addeo", XO(31,138,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "aeo", XO(31,138,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "addeo.", XO(31,138,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "aeo.", XO(31,138,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "mtcr", XFXM(31,144,0xff), XFXFXM_MASK|FXM_MASK, PPC|POWER, { RS }}, +{ "mtcrf", X(31,144), XFXFXM_MASK, PPC|POWER, { FXM, RS } }, + +{ "mtmsr", X(31,146), XRARB_MASK, PPC|POWER, { RS } }, + +{ "stdx", X(31,149), X_MASK, PPC|B64, { RS, RA, RB } }, + +{ "stwcx.", XRC(31,150,1), X_MASK, PPC, { RS, RA, RB } }, + +{ "stwx", X(31,151), X_MASK, PPC, { RS, RA, RB } }, +{ "stx", X(31,151), X_MASK, POWER, { RS, RA, RB } }, + +{ "slq", XRC(31,152,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "slq.", XRC(31,152,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "sle", XRC(31,153,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sle.", XRC(31,153,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "stdux", X(31,181), X_MASK, PPC|B64, { RS, RAS, RB } }, + +{ "stwux", X(31,183), X_MASK, PPC, { RS, RAS, RB } }, +{ "stux", X(31,183), X_MASK, POWER, { RS, RA, RB } }, + +{ "sliq", XRC(31,184,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "sliq.", XRC(31,184,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "subfze", XO(31,200,0,0), XORB_MASK, PPC, { RT, RA } }, +{ "sfze", XO(31,200,0,0), XORB_MASK, POWER, { RT, RA } }, +{ "subfze.", XO(31,200,0,1), XORB_MASK, PPC, { RT, RA } }, +{ "sfze.", XO(31,200,0,1), XORB_MASK, POWER, { RT, RA } }, +{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPC, { RT, RA } }, +{ "sfzeo", XO(31,200,1,0), XORB_MASK, POWER, { RT, RA } }, +{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPC, { RT, RA } }, +{ "sfzeo.", XO(31,200,1,1), XORB_MASK, POWER, { RT, RA } }, + +{ "addze", XO(31,202,0,0), XORB_MASK, PPC, { RT, RA } }, +{ "aze", XO(31,202,0,0), XORB_MASK, POWER, { RT, RA } }, +{ "addze.", XO(31,202,0,1), XORB_MASK, PPC, { RT, RA } }, +{ "aze.", XO(31,202,0,1), XORB_MASK, POWER, { RT, RA } }, +{ "addzeo", XO(31,202,1,0), XORB_MASK, PPC, { RT, RA } }, +{ "azeo", XO(31,202,1,0), XORB_MASK, POWER, { RT, RA } }, +{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPC, { RT, RA } }, +{ "azeo.", XO(31,202,1,1), XORB_MASK, POWER, { RT, RA } }, + +{ "mtsr", X(31,210), XRB_MASK|(1<<20), PPC|POWER|B32, { SR, RS } }, + +{ "stdcx.", XRC(31,214,1), X_MASK, PPC|B64, { RS, RA, RB } }, + +{ "stbx", X(31,215), X_MASK, PPC|POWER, { RS, RA, RB } }, + +{ "sllq", XRC(31,216,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sllq.", XRC(31,216,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "sleq", XRC(31,217,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sleq.", XRC(31,217,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "subfme", XO(31,232,0,0), XORB_MASK, PPC, { RT, RA } }, +{ "sfme", XO(31,232,0,0), XORB_MASK, POWER, { RT, RA } }, +{ "subfme.", XO(31,232,0,1), XORB_MASK, PPC, { RT, RA } }, +{ "sfme.", XO(31,232,0,1), XORB_MASK, POWER, { RT, RA } }, +{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPC, { RT, RA } }, +{ "sfmeo", XO(31,232,1,0), XORB_MASK, POWER, { RT, RA } }, +{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPC, { RT, RA } }, +{ "sfmeo.", XO(31,232,1,1), XORB_MASK, POWER, { RT, RA } }, + +{ "mulld", XO(31,233,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulld.", XO(31,233,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulldo", XO(31,233,1,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "mulldo.", XO(31,233,1,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "addme", XO(31,234,0,0), XORB_MASK, PPC, { RT, RA } }, +{ "ame", XO(31,234,0,0), XORB_MASK, POWER, { RT, RA } }, +{ "addme.", XO(31,234,0,1), XORB_MASK, PPC, { RT, RA } }, +{ "ame.", XO(31,234,0,1), XORB_MASK, POWER, { RT, RA } }, +{ "addmeo", XO(31,234,1,0), XORB_MASK, PPC, { RT, RA } }, +{ "ameo", XO(31,234,1,0), XORB_MASK, POWER, { RT, RA } }, +{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPC, { RT, RA } }, +{ "ameo.", XO(31,234,1,1), XORB_MASK, POWER, { RT, RA } }, + +{ "mullw", XO(31,235,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "muls", XO(31,235,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "mullw.", XO(31,235,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "muls.", XO(31,235,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "mullwo", XO(31,235,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulso", XO(31,235,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "mullwo.", XO(31,235,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "mulso.", XO(31,235,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "mtsrin", X(31,242), XRA_MASK, PPC|B32, { RS, RB } }, +{ "mtsri", X(31,242), XRA_MASK, POWER|B32, { RS, RB } }, + +{ "dcbtst", X(31,246), XRT_MASK, PPC, { RA, RB } }, + +{ "stbux", X(31,247), X_MASK, PPC|POWER, { RS, RAS, RB } }, + +{ "slliq", XRC(31,248,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "slliq.", XRC(31,248,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "doz", XO(31,264,0,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "doz.", XO(31,264,0,1), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "dozo", XO(31,264,1,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "dozo.", XO(31,264,1,1), XO_MASK, POWER|M601, { RT, RA, RB } }, + +{ "add", XO(31,266,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "cax", XO(31,266,0,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "add.", XO(31,266,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "cax.", XO(31,266,0,1), XO_MASK, POWER, { RT, RA, RB } }, +{ "addo", XO(31,266,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "caxo", XO(31,266,1,0), XO_MASK, POWER, { RT, RA, RB } }, +{ "addo.", XO(31,266,1,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "caxo.", XO(31,266,1,1), XO_MASK, POWER, { RT, RA, RB } }, + +{ "lscbx", XRC(31,277,0), X_MASK, POWER|M601, { RT, RA, RB } }, +{ "lscbx.", XRC(31,277,1), X_MASK, POWER|M601, { RT, RA, RB } }, + +{ "dcbt", X(31,278), XRT_MASK, PPC, { RA, RB } }, + +{ "lhzx", X(31,279), X_MASK, PPC|POWER, { RT, RA, RB } }, + +{ "icbt", X(31,262), XRT_MASK, PPC, { RA, RB } }, + +{ "eqv", XRC(31,284,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "eqv.", XRC(31,284,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "tlbie", X(31,306), XRTRA_MASK, PPC, { RB } }, +{ "tlbi", X(31,306), XRTRA_MASK, POWER, { RB } }, + +{ "eciwx", X(31,310), X_MASK, PPC, { RT, RA, RB } }, + +{ "lhzux", X(31,311), X_MASK, PPC|POWER, { RT, RAL, RB } }, + +{ "xor", XRC(31,316,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "xor.", XRC(31,316,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "mfdcr", X(31,323), X_MASK, PPC, { RT, SPR } }, + +{ "div", XO(31,331,0,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "div.", XO(31,331,0,1), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divo", XO(31,331,1,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divo.", XO(31,331,1,1), XO_MASK, POWER|M601, { RT, RA, RB } }, + +{ "mfmq", XSPR(31,339,0), XSPR_MASK, POWER|M601, { RT } }, +{ "mfxer", XSPR(31,339,1), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfrtcu", XSPR(31,339,4), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfrtcl", XSPR(31,339,5), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfdec", XSPR(31,339,6), XSPR_MASK, POWER|M601, { RT } }, +{ "mflr", XSPR(31,339,8), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfctr", XSPR(31,339,9), XSPR_MASK, PPC|POWER, { RT } }, +{ "mftid", XSPR(31,339,17), XSPR_MASK, POWER, { RT } }, +{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfdar", XSPR(31,339,19), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfdec", XSPR(31,339,22), XSPR_MASK, PPC, { RT } }, +{ "mfsdr0", XSPR(31,339,24), XSPR_MASK, POWER, { RT } }, +{ "mfsdr1", XSPR(31,339,25), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfsrr0", XSPR(31,339,26), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfsrr1", XSPR(31,339,27), XSPR_MASK, PPC|POWER, { RT } }, +{ "mfsprg", XSPR(31,339,272), XSPRG_MASK, PPC, { RT, SPRG } }, +{ "mfasr", XSPR(31,339,280), XSPR_MASK, PPC|B64, { RT } }, +{ "mfear", XSPR(31,339,282), XSPR_MASK, PPC, { RT } }, +{ "mfpvr", XSPR(31,339,287), XSPR_MASK, PPC, { RT } }, +{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC, { RT, SPRBAT } }, +{ "mfspr", X(31,339), X_MASK, PPC|POWER, { RT, SPR } }, + +{ "lwax", X(31,341), X_MASK, PPC|B64, { RT, RA, RB } }, + +{ "lhax", X(31,343), X_MASK, PPC|POWER, { RT, RA, RB } }, + +{ "dccci", X(31,454), XRT_MASK, PPC, { RA, RB } }, + +{ "abs", XO(31,360,0,0), XORB_MASK, POWER|M601, { RT, RA } }, +{ "abs.", XO(31,360,0,1), XORB_MASK, POWER|M601, { RT, RA } }, +{ "abso", XO(31,360,1,0), XORB_MASK, POWER|M601, { RT, RA } }, +{ "abso.", XO(31,360,1,1), XORB_MASK, POWER|M601, { RT, RA } }, + +{ "divs", XO(31,363,0,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divs.", XO(31,363,0,1), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divso", XO(31,363,1,0), XO_MASK, POWER|M601, { RT, RA, RB } }, +{ "divso.", XO(31,363,1,1), XO_MASK, POWER|M601, { RT, RA, RB } }, + +{ "tlbia", X(31,370), 0xffffffff, PPC, { 0 } }, + +{ "mftbu", XSPR(31,371,269), XSPR_MASK, PPC, { RT } }, +{ "mftb", X(31,371), X_MASK, PPC, { RT, TBR } }, + +{ "lwaux", X(31,373), X_MASK, PPC|B64, { RT, RAL, RB } }, + +{ "lhaux", X(31,375), X_MASK, PPC|POWER, { RT, RAL, RB } }, + +{ "sthx", X(31,407), X_MASK, PPC|POWER, { RS, RA, RB } }, + +{ "lfqx", X(31,791), X_MASK, POWER2, { FRT, RA, RB } }, + +{ "lfqux", X(31,823), X_MASK, POWER2, { FRT, RA, RB } }, + +{ "stfqx", X(31,919), X_MASK, POWER2, { FRS, RA, RB } }, + +{ "stfqux", X(31,951), X_MASK, POWER2, { FRS, RA, RB } }, + +{ "orc", XRC(31,412,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "orc.", XRC(31,412,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "sradi", XS(31,413,0), XS_MASK, PPC|B64, { RA, RS, SH6 } }, +{ "sradi.", XS(31,413,1), XS_MASK, PPC|B64, { RA, RS, SH6 } }, + +{ "slbie", X(31,434), XRTRA_MASK, PPC|B64, { RB } }, + +{ "ecowx", X(31,438), X_MASK, PPC, { RT, RA, RB } }, + +{ "sthux", X(31,439), X_MASK, PPC|POWER, { RS, RAS, RB } }, + +{ "mr", XRC(31,444,0), X_MASK, PPC|POWER, { RA, RS, RBS } }, +{ "or", XRC(31,444,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "mr.", XRC(31,444,1), X_MASK, PPC|POWER, { RA, RS, RBS } }, +{ "or.", XRC(31,444,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "mtdcr", X(31,451), X_MASK, PPC, { SPR, RS } }, + +{ "divdu", XO(31,457,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divdu.", XO(31,457,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divduo", XO(31,457,1,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divduo.", XO(31,457,1,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "divwu", XO(31,459,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwu.", XO(31,459,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwuo", XO(31,459,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwuo.", XO(31,459,1,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "mtmq", XSPR(31,467,0), XSPR_MASK, POWER|M601, { RS } }, +{ "mtxer", XSPR(31,467,1), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtlr", XSPR(31,467,8), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtctr", XSPR(31,467,9), XSPR_MASK, PPC|POWER, { RS } }, +{ "mttid", XSPR(31,467,17), XSPR_MASK, POWER, { RS } }, +{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtdar", XSPR(31,467,19), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtrtcu", XSPR(31,467,20), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtrtcl", XSPR(31,467,21), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtdec", XSPR(31,467,22), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtsdr0", XSPR(31,467,24), XSPR_MASK, POWER, { RS } }, +{ "mtsdr1", XSPR(31,467,25), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtsrr0", XSPR(31,467,26), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtsrr1", XSPR(31,467,27), XSPR_MASK, PPC|POWER, { RS } }, +{ "mtsprg", XSPR(31,467,272), XSPRG_MASK, PPC, { SPRG, RS } }, +{ "mtasr", XSPR(31,467,280), XSPR_MASK, PPC|B64, { RS } }, +{ "mtear", XSPR(31,467,282), XSPR_MASK, PPC, { RS } }, +{ "mttbl", XSPR(31,467,284), XSPR_MASK, PPC, { RS } }, +{ "mttbu", XSPR(31,467,285), XSPR_MASK, PPC, { RS } }, +{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC, { SPRBAT, RS } }, +{ "mtspr", X(31,467), X_MASK, PPC|POWER, { SPR, RS } }, + +{ "dcbi", X(31,470), XRT_MASK, PPC, { RA, RB } }, + +{ "nand", XRC(31,476,0), X_MASK, PPC|POWER, { RA, RS, RB } }, +{ "nand.", XRC(31,476,1), X_MASK, PPC|POWER, { RA, RS, RB } }, + +{ "nabs", XO(31,488,0,0), XORB_MASK, POWER|M601, { RT, RA } }, +{ "nabs.", XO(31,488,0,1), XORB_MASK, POWER|M601, { RT, RA } }, +{ "nabso", XO(31,488,1,0), XORB_MASK, POWER|M601, { RT, RA } }, +{ "nabso.", XO(31,488,1,1), XORB_MASK, POWER|M601, { RT, RA } }, + +{ "divd", XO(31,489,0,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divd.", XO(31,489,0,1), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divdo", XO(31,489,1,0), XO_MASK, PPC|B64, { RT, RA, RB } }, +{ "divdo.", XO(31,489,1,1), XO_MASK, PPC|B64, { RT, RA, RB } }, + +{ "divw", XO(31,491,0,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divw.", XO(31,491,0,1), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwo", XO(31,491,1,0), XO_MASK, PPC, { RT, RA, RB } }, +{ "divwo.", XO(31,491,1,1), XO_MASK, PPC, { RT, RA, RB } }, + +{ "slbia", X(31,498), 0xffffffff, PPC|B64, { 0 } }, + +{ "cli", X(31,502), XRB_MASK, POWER, { RT, RA } }, + +{ "mcrxr", X(31,512), XRARB_MASK|(3<<21), PPC|POWER, { BF } }, + +{ "clcs", X(31,531), XRB_MASK, POWER|M601, { RT, RA } }, + +{ "lswx", X(31,533), X_MASK, PPC, { RT, RA, RB } }, +{ "lsx", X(31,533), X_MASK, POWER, { RT, RA, RB } }, + +{ "lwbrx", X(31,534), X_MASK, PPC, { RT, RA, RB } }, +{ "lbrx", X(31,534), X_MASK, POWER, { RT, RA, RB } }, + +{ "lfsx", X(31,535), X_MASK, PPC|POWER, { FRT, RA, RB } }, + +{ "srw", XRC(31,536,0), X_MASK, PPC, { RA, RS, RB } }, +{ "sr", XRC(31,536,0), X_MASK, POWER, { RA, RS, RB } }, +{ "srw.", XRC(31,536,1), X_MASK, PPC, { RA, RS, RB } }, +{ "sr.", XRC(31,536,1), X_MASK, POWER, { RA, RS, RB } }, + +{ "rrib", XRC(31,537,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "rrib.", XRC(31,537,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "srd", XRC(31,539,0), X_MASK, PPC|B64, { RA, RS, RB } }, +{ "srd.", XRC(31,539,1), X_MASK, PPC|B64, { RA, RS, RB } }, + +{ "maskir", XRC(31,541,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "maskir.", XRC(31,541,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "tlbsync", X(31,566), 0xffffffff, PPC, { 0 } }, + +{ "lfsux", X(31,567), X_MASK, PPC|POWER, { FRT, RAS, RB } }, + +{ "mfsr", X(31,595), XRB_MASK|(1<<20), PPC|POWER|B32, { RT, SR } }, + +{ "lswi", X(31,597), X_MASK, PPC, { RT, RA, NB } }, +{ "lsi", X(31,597), X_MASK, POWER, { RT, RA, NB } }, + +{ "sync", X(31,598), 0xffffffff, PPC, { 0 } }, +{ "dcs", X(31,598), 0xffffffff, POWER, { 0 } }, + +{ "lfdx", X(31,599), X_MASK, PPC|POWER, { FRT, RA, RB } }, + +{ "mfsri", X(31,627), X_MASK, POWER, { RT, RA, RB } }, + +{ "dclst", X(31,630), XRB_MASK, POWER, { RS, RA } }, + +{ "lfdux", X(31,631), X_MASK, PPC|POWER, { FRT, RAS, RB } }, + +{ "mfsrin", X(31,659), XRA_MASK, PPC|B32, { RT, RB } }, + +{ "stswx", X(31,661), X_MASK, PPC, { RS, RA, RB } }, +{ "stsx", X(31,661), X_MASK, POWER, { RS, RA, RB } }, + +{ "stwbrx", X(31,662), X_MASK, PPC, { RS, RA, RB } }, +{ "stbrx", X(31,662), X_MASK, POWER, { RS, RA, RB } }, + +{ "stfsx", X(31,663), X_MASK, PPC|POWER, { FRS, RA, RB } }, + +{ "srq", XRC(31,664,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "srq.", XRC(31,664,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "sre", XRC(31,665,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sre.", XRC(31,665,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "stfsux", X(31,695), X_MASK, PPC|POWER, { FRS, RAS, RB } }, + +{ "sriq", XRC(31,696,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "sriq.", XRC(31,696,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "stswi", X(31,725), X_MASK, PPC, { RS, RA, NB } }, +{ "stsi", X(31,725), X_MASK, POWER, { RS, RA, NB } }, + +{ "stfdx", X(31,727), X_MASK, PPC|POWER, { FRS, RA, RB } }, + +{ "srlq", XRC(31,728,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "srlq.", XRC(31,728,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "sreq", XRC(31,729,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sreq.", XRC(31,729,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "stfdux", X(31,759), X_MASK, PPC|POWER, { FRS, RAS, RB } }, + +{ "srliq", XRC(31,760,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "srliq.", XRC(31,760,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "lhbrx", X(31,790), X_MASK, PPC|POWER, { RT, RA, RB } }, + +{ "sraw", XRC(31,792,0), X_MASK, PPC, { RA, RS, RB } }, +{ "sra", XRC(31,792,0), X_MASK, POWER, { RA, RS, RB } }, +{ "sraw.", XRC(31,792,1), X_MASK, PPC, { RA, RS, RB } }, +{ "sra.", XRC(31,792,1), X_MASK, POWER, { RA, RS, RB } }, + +{ "srad", XRC(31,794,0), X_MASK, PPC|B64, { RA, RS, RB } }, +{ "srad.", XRC(31,794,1), X_MASK, PPC|B64, { RA, RS, RB } }, + +{ "rac", X(31,818), X_MASK, POWER, { RT, RA, RB } }, + +{ "srawi", XRC(31,824,0), X_MASK, PPC, { RA, RS, SH } }, +{ "srai", XRC(31,824,0), X_MASK, POWER, { RA, RS, SH } }, +{ "srawi.", XRC(31,824,1), X_MASK, PPC, { RA, RS, SH } }, +{ "srai.", XRC(31,824,1), X_MASK, POWER, { RA, RS, SH } }, + +{ "eieio", X(31,854), 0xffffffff, PPC, { 0 } }, + +{ "sthbrx", X(31,918), X_MASK, PPC|POWER, { RS, RA, RB } }, + +{ "sraq", XRC(31,920,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "sraq.", XRC(31,920,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "srea", XRC(31,921,0), X_MASK, POWER|M601, { RA, RS, RB } }, +{ "srea.", XRC(31,921,1), X_MASK, POWER|M601, { RA, RS, RB } }, + +{ "extsh", XRC(31,922,0), XRB_MASK, PPC, { RA, RS } }, +{ "exts", XRC(31,922,0), XRB_MASK, POWER, { RA, RS } }, +{ "extsh.", XRC(31,922,1), XRB_MASK, PPC, { RA, RS } }, +{ "exts.", XRC(31,922,1), XRB_MASK, POWER, { RA, RS } }, + +{ "sraiq", XRC(31,952,0), X_MASK, POWER|M601, { RA, RS, SH } }, +{ "sraiq.", XRC(31,952,1), X_MASK, POWER|M601, { RA, RS, SH } }, + +{ "extsb", XRC(31,954,0), XRB_MASK, PPC, { RA, RS} }, +{ "extsb.", XRC(31,954,1), XRB_MASK, PPC, { RA, RS} }, + +{ "iccci", X(31,966), XRT_MASK, PPC, { RA, RB } }, + +{ "icbi", X(31,982), XRT_MASK, PPC, { RA, RB } }, + +{ "stfiwx", X(31,983), X_MASK, PPC, { FRS, RA, RB } }, + +{ "extsw", XRC(31,986,0), XRB_MASK, PPC, { RA, RS } }, +{ "extsw.", XRC(31,986,1), XRB_MASK, PPC, { RA, RS } }, + +{ "dcbz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, +{ "dclz", X(31,1014), XRT_MASK, PPC, { RA, RB } }, + +{ "lwz", OP(32), OP_MASK, PPC, { RT, D, RA } }, +{ "l", OP(32), OP_MASK, POWER, { RT, D, RA } }, + +{ "lwzu", OP(33), OP_MASK, PPC, { RT, D, RAL } }, +{ "lu", OP(33), OP_MASK, POWER, { RT, D, RA } }, + +{ "lbz", OP(34), OP_MASK, PPC|POWER, { RT, D, RA } }, + +{ "lbzu", OP(35), OP_MASK, PPC|POWER, { RT, D, RAL } }, + +{ "stw", OP(36), OP_MASK, PPC, { RS, D, RA } }, +{ "st", OP(36), OP_MASK, POWER, { RS, D, RA } }, + +{ "stwu", OP(37), OP_MASK, PPC, { RS, D, RAS } }, +{ "stu", OP(37), OP_MASK, POWER, { RS, D, RA } }, + +{ "stb", OP(38), OP_MASK, PPC|POWER, { RS, D, RA } }, + +{ "stbu", OP(39), OP_MASK, PPC|POWER, { RS, D, RAS } }, + +{ "lhz", OP(40), OP_MASK, PPC|POWER, { RT, D, RA } }, + +{ "lhzu", OP(41), OP_MASK, PPC|POWER, { RT, D, RAL } }, + +{ "lha", OP(42), OP_MASK, PPC|POWER, { RT, D, RA } }, + +{ "lhau", OP(43), OP_MASK, PPC|POWER, { RT, D, RAL } }, + +{ "sth", OP(44), OP_MASK, PPC|POWER, { RS, D, RA } }, + +{ "sthu", OP(45), OP_MASK, PPC|POWER, { RS, D, RAS } }, + +{ "lmw", OP(46), OP_MASK, PPC, { RT, D, RAM } }, +{ "lm", OP(46), OP_MASK, POWER, { RT, D, RA } }, + +{ "stmw", OP(47), OP_MASK, PPC, { RS, D, RA } }, +{ "stm", OP(47), OP_MASK, POWER, { RS, D, RA } }, + +{ "lfs", OP(48), OP_MASK, PPC|POWER, { FRT, D, RA } }, + +{ "lfsu", OP(49), OP_MASK, PPC|POWER, { FRT, D, RAS } }, + +{ "lfd", OP(50), OP_MASK, PPC|POWER, { FRT, D, RA } }, + +{ "lfdu", OP(51), OP_MASK, PPC|POWER, { FRT, D, RAS } }, + +{ "stfs", OP(52), OP_MASK, PPC|POWER, { FRS, D, RA } }, + +{ "stfsu", OP(53), OP_MASK, PPC|POWER, { FRS, D, RAS } }, + +{ "stfd", OP(54), OP_MASK, PPC|POWER, { FRS, D, RA } }, + +{ "stfdu", OP(55), OP_MASK, PPC|POWER, { FRS, D, RAS } }, + +{ "lfq", OP(56), OP_MASK, POWER2, { FRT, D, RA } }, + +{ "lfqu", OP(57), OP_MASK, POWER2, { FRT, D, RA } }, + +{ "ld", DSO(58,0), DS_MASK, PPC|B64, { RT, DS, RA } }, + +{ "ldu", DSO(58,1), DS_MASK, PPC|B64, { RT, DS, RAL } }, + +{ "lwa", DSO(58,2), DS_MASK, PPC|B64, { RT, DS, RA } }, + +{ "fdivs", A(59,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fdivs.", A(59,18,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fsubs", A(59,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fsubs.", A(59,20,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fadds", A(59,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fadds.", A(59,21,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, + +{ "fsqrts", A(59,22,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, +{ "fsqrts.", A(59,22,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, + +{ "fres", A(59,24,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, +{ "fres.", A(59,24,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, + +{ "fmuls", A(59,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } }, +{ "fmuls.", A(59,25,1), AFRB_MASK, PPC, { FRT, FRA, FRC } }, + +{ "fmsubs", A(59,28,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fmsubs.", A(59,28,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fmadds", A(59,29,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fmadds.", A(59,29,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fnmsubs", A(59,30,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnmsubs.",A(59,30,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fnmadds", A(59,31,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnmadds.",A(59,31,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "stfq", OP(60), OP_MASK, POWER2, { FRS, D, RA } }, + +{ "stfqu", OP(61), OP_MASK, POWER2, { FRS, D, RA } }, + +{ "std", DSO(62,0), DS_MASK, PPC|B64, { RS, DS, RA } }, + +{ "stdu", DSO(62,1), DS_MASK, PPC|B64, { RS, DS, RAS } }, + +{ "fcmpu", X(63,0), X_MASK|(3<<21), PPC|POWER, { BF, FRA, FRB } }, + +{ "frsp", XRC(63,12,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "frsp.", XRC(63,12,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "fctiw", XRC(63,14,0), XRA_MASK, PPC, { FRT, FRB } }, +{ "fcir", XRC(63,14,0), XRA_MASK, POWER2, { FRT, FRB } }, +{ "fctiw.", XRC(63,14,1), XRA_MASK, PPC, { FRT, FRB } }, +{ "fcir.", XRC(63,14,1), XRA_MASK, POWER2, { FRT, FRB } }, + +{ "fctiwz", XRC(63,15,0), XRA_MASK, PPC, { FRT, FRB } }, +{ "fcirz", XRC(63,15,0), XRA_MASK, POWER2, { FRT, FRB } }, +{ "fctiwz.", XRC(63,15,1), XRA_MASK, PPC, { FRT, FRB } }, +{ "fcirz.", XRC(63,15,1), XRA_MASK, POWER2, { FRT, FRB } }, + +{ "fdiv", A(63,18,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fd", A(63,18,0), AFRC_MASK, POWER, { FRT, FRA, FRB } }, +{ "fdiv.", A(63,18,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fd.", A(63,18,1), AFRC_MASK, POWER, { FRT, FRA, FRB } }, + +{ "fsub", A(63,20,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fs", A(63,20,0), AFRC_MASK, POWER, { FRT, FRA, FRB } }, +{ "fsub.", A(63,20,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fs.", A(63,20,1), AFRC_MASK, POWER, { FRT, FRA, FRB } }, + +{ "fadd", A(63,21,0), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fa", A(63,21,0), AFRC_MASK, POWER, { FRT, FRA, FRB } }, +{ "fadd.", A(63,21,1), AFRC_MASK, PPC, { FRT, FRA, FRB } }, +{ "fa.", A(63,21,1), AFRC_MASK, POWER, { FRT, FRA, FRB } }, + +{ "fsqrt", A(63,22,0), AFRAFRC_MASK, PPC|POWER2, { FRT, FRB } }, +{ "fsqrt.", A(63,22,1), AFRAFRC_MASK, PPC|POWER2, { FRT, FRB } }, + +{ "fsel", A(63,23,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fsel.", A(63,23,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, + +{ "fmul", A(63,25,0), AFRB_MASK, PPC, { FRT, FRA, FRC } }, +{ "fm", A(63,25,0), AFRB_MASK, POWER, { FRT, FRA, FRC } }, +{ "fmul.", A(63,25,1), AFRB_MASK, PPC, { FRT, FRA, FRC } }, +{ "fm.", A(63,25,1), AFRB_MASK, POWER, { FRT, FRA, FRC } }, + +{ "frsqrte", A(63,26,0), AFRAFRC_MASK, PPC, { FRT, FRB } }, +{ "frsqrte.",A(63,26,1), AFRAFRC_MASK, PPC, { FRT, FRB } }, + +{ "fmsub", A(63,28,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fms", A(63,28,0), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, +{ "fmsub.", A(63,28,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fms.", A(63,28,1), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, + +{ "fmadd", A(63,29,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fma", A(63,29,0), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, +{ "fmadd.", A(63,29,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fma.", A(63,29,1), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, + +{ "fnmsub", A(63,30,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnms", A(63,30,0), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, +{ "fnmsub.", A(63,30,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnms.", A(63,30,1), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, + +{ "fnmadd", A(63,31,0), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnma", A(63,31,0), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, +{ "fnmadd.", A(63,31,1), A_MASK, PPC, { FRT,FRA,FRC,FRB } }, +{ "fnma.", A(63,31,1), A_MASK, POWER, { FRT,FRA,FRC,FRB } }, + +{ "fcmpo", X(63,30), X_MASK|(3<<21), PPC|POWER, { BF, FRA, FRB } }, + +{ "mtfsb1", XRC(63,38,0), XRARB_MASK, PPC|POWER, { BT } }, +{ "mtfsb1.", XRC(63,38,1), XRARB_MASK, PPC|POWER, { BT } }, + +{ "fneg", XRC(63,40,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "fneg.", XRC(63,40,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "mcrfs", X(63,64), XRB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } }, + +{ "mtfsb0", XRC(63,70,0), XRARB_MASK, PPC|POWER, { BT } }, +{ "mtfsb0.", XRC(63,70,1), XRARB_MASK, PPC|POWER, { BT } }, + +{ "fmr", XRC(63,72,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "fmr.", XRC(63,72,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "mtfsfi", XRC(63,134,0), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } }, +{ "mtfsfi.", XRC(63,134,1), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } }, + +{ "fnabs", XRC(63,136,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "fnabs.", XRC(63,136,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "fabs", XRC(63,264,0), XRA_MASK, PPC|POWER, { FRT, FRB } }, +{ "fabs.", XRC(63,264,1), XRA_MASK, PPC|POWER, { FRT, FRB } }, + +{ "mffs", XRC(63,583,0), XRARB_MASK, PPC|POWER, { FRT } }, +{ "mffs.", XRC(63,583,1), XRARB_MASK, PPC|POWER, { FRT } }, + +{ "mtfsf", XFL(63,711,0), XFL_MASK, PPC|POWER, { FLM, FRB } }, +{ "mtfsf.", XFL(63,711,1), XFL_MASK, PPC|POWER, { FLM, FRB } }, + +{ "fctid", XRC(63,814,0), XRA_MASK, PPC|B64, { FRT, FRB } }, +{ "fctid.", XRC(63,814,1), XRA_MASK, PPC|B64, { FRT, FRB } }, + +{ "fctidz", XRC(63,815,0), XRA_MASK, PPC|B64, { FRT, FRB } }, +{ "fctidz.", XRC(63,815,1), XRA_MASK, PPC|B64, { FRT, FRB } }, + +{ "fcfid", XRC(63,846,0), XRA_MASK, PPC|B64, { FRT, FRB } }, +{ "fcfid.", XRC(63,846,1), XRA_MASK, PPC|B64, { FRT, FRB } }, + +}; + +const int powerpc_num_opcodes = + sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]); + +/* The macro table. This is only used by the assembler. */ + +const struct powerpc_macro powerpc_macros[] = { +{ "extldi", 4, PPC|B64, "rldicr %0,%1,%3,(%2)-1" }, +{ "extldi.", 4, PPC|B64, "rldicr. %0,%1,%3,(%2)-1" }, +{ "extrdi", 4, PPC|B64, "rldicl %0,%1,(%2)+(%3),64-(%2)" }, +{ "extrdi.", 4, PPC|B64, "rldicl. %0,%1,(%2)+(%3),64-(%2)" }, +{ "insrdi", 4, PPC|B64, "rldimi %0,%1,64-((%2)+(%3)),%3" }, +{ "insrdi.", 4, PPC|B64, "rldimi. %0,%1,64-((%2)+(%3)),%3" }, +{ "rotrdi", 3, PPC|B64, "rldicl %0,%1,64-(%2),0" }, +{ "rotrdi.", 3, PPC|B64, "rldicl. %0,%1,64-(%2),0" }, +{ "sldi", 3, PPC|B64, "rldicr %0,%1,%2,63-(%2)" }, +{ "sldi.", 3, PPC|B64, "rldicr. %0,%1,%2,63-(%2)" }, +{ "srdi", 3, PPC|B64, "rldicl %0,%1,64-(%2),%2" }, +{ "srdi.", 3, PPC|B64, "rldicl. %0,%1,64-(%2),%2" }, +{ "clrrdi", 3, PPC|B64, "rldicr %0,%1,0,63-(%2)" }, +{ "clrrdi.", 3, PPC|B64, "rldicr. %0,%1,0,63-(%2)" }, +{ "clrlsldi",4, PPC|B64, "rldic %0,%1,%3,(%2)-(%3)" }, +{ "clrlsldi.",4, PPC|B64, "rldic. %0,%1,%3,(%2)-(%3)" }, + +{ "extlwi", 4, PPC, "rlwinm %0,%1,%3,0,(%2)-1" }, +{ "extlwi.", 4, PPC, "rlwinm. %0,%1,%3,0,(%2)-1" }, +{ "extrwi", 4, PPC, "rlwinm %0,%1,(%2)+(%3),32-(%2),31" }, +{ "extrwi.", 4, PPC, "rlwinm. %0,%1,(%2)+(%3),32-(%2),31" }, +{ "inslwi", 4, PPC, "rlwimi %0,%1,32-(%3),%3,(%2)+(%3)-1" }, +{ "inslwi.", 4, PPC, "rlwimi. %0,%1,32-(%3),%3,(%2)+(%3)-1" }, +{ "insrwi", 4, PPC, "rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" }, +{ "insrwi.", 4, PPC, "rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"}, +{ "rotrwi", 3, PPC, "rlwinm %0,%1,32-(%2),0,31" }, +{ "rotrwi.", 3, PPC, "rlwinm. %0,%1,32-(%2),0,31" }, +{ "slwi", 3, PPC, "rlwinm %0,%1,%2,0,31-(%2)" }, +{ "sli", 3, POWER, "rlinm %0,%1,%2,0,31-(%2)" }, +{ "slwi.", 3, PPC, "rlwinm. %0,%1,%2,0,31-(%2)" }, +{ "sli.", 3, POWER, "rlinm. %0,%1,%2,0,31-(%2)" }, +{ "srwi", 3, PPC, "rlwinm %0,%1,32-(%2),%2,31" }, +{ "sri", 3, POWER, "rlinm %0,%1,32-(%2),%2,31" }, +{ "srwi.", 3, PPC, "rlwinm. %0,%1,32-(%2),%2,31" }, +{ "sri.", 3, POWER, "rlinm. %0,%1,32-(%2),%2,31" }, +{ "clrrwi", 3, PPC, "rlwinm %0,%1,0,0,31-(%2)" }, +{ "clrrwi.", 3, PPC, "rlwinm. %0,%1,0,0,31-(%2)" }, +{ "clrlslwi",4, PPC, "rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" }, +{ "clrlslwi.",4, PPC, "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" }, + +}; + +const int powerpc_num_macros = + sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); + +static int print_insn_powerpc(FILE *, unsigned long insn, unsigned memaddr, int dialect); + +/* Print a big endian PowerPC instruction. For convenience, also + disassemble instructions supported by the Motorola PowerPC 601. */ + +int print_insn_ppc (bfd_vma pc, disassemble_info *info) +{ + return print_insn_powerpc (info->stream, *(unsigned *)(long)pc, pc, + PPC_OPCODE_PPC | PPC_OPCODE_601); +} + +/* Print a PowerPC or POWER instruction. */ + +static int +print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, + int dialect) +{ + const struct powerpc_opcode *opcode; + const struct powerpc_opcode *opcode_end; + unsigned long op; + + /* Get the major opcode of the instruction. */ + op = PPC_OP (insn); + + /* Find the first match in the opcode table. We could speed this up + a bit by doing a binary search on the major opcode. */ + opcode_end = powerpc_opcodes + powerpc_num_opcodes; + for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) + { + unsigned long table_op; + const unsigned char *opindex; + const struct powerpc_operand *operand; + int invalid; + int need_comma; + int need_paren; + + table_op = PPC_OP (opcode->opcode); + if (op < table_op) + break; + if (op > table_op) + continue; + + if ((insn & opcode->mask) != opcode->opcode + || (opcode->flags & dialect) == 0) + 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. */ + invalid = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + operand = powerpc_operands + *opindex; + if (operand->extract) + (*operand->extract) (insn, &invalid); + } + if (invalid) + continue; + + /* The instruction is valid. */ + fprintf(out, "%s", opcode->name); + if (opcode->operands[0] != 0) + fprintf(out, "\t"); + + /* Now extract and print the operands. */ + need_comma = 0; + need_paren = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + long value; + + operand = powerpc_operands + *opindex; + + /* 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 & PPC_OPERAND_FAKE) != 0) + continue; + + /* Extract the value from the instruction. */ + if (operand->extract) + value = (*operand->extract) (insn, (int *) 0); + else + { + value = (insn >> operand->shift) & ((1 << operand->bits) - 1); + if ((operand->flags & PPC_OPERAND_SIGNED) != 0 + && (value & (1 << (operand->bits - 1))) != 0) + value -= 1 << operand->bits; + } + + /* If the operand is optional, and the value is zero, don't + print anything. */ + if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 + && (operand->flags & PPC_OPERAND_NEXT) == 0 + && value == 0) + continue; + + if (need_comma) + { + fprintf(out, ","); + need_comma = 0; + } + + /* Print the operand as directed by the flags. */ + if ((operand->flags & PPC_OPERAND_GPR) != 0) + fprintf(out, "r%ld", value); + else if ((operand->flags & PPC_OPERAND_FPR) != 0) + fprintf(out, "f%ld", value); + else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) + fprintf(out, "%08lX", memaddr + value); + else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) + fprintf(out, "%08lX", value & 0xffffffff); + else if ((operand->flags & PPC_OPERAND_CR) == 0 + || (dialect & PPC_OPCODE_PPC) == 0) + fprintf(out, "%ld", value); + else + { + if (operand->bits == 3) + fprintf(out, "cr%ld", value); + else + { + static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; + int cr; + int cc; + + cr = value >> 2; + if (cr != 0) + fprintf(out, "4*cr%d", cr); + cc = value & 3; + if (cc != 0) + { + if (cr != 0) + fprintf(out, "+"); + fprintf(out, "%s", cbnames[cc]); + } + } + } + + if (need_paren) + { + fprintf(out, ")"); + need_paren = 0; + } + + if ((operand->flags & PPC_OPERAND_PARENS) == 0) + need_comma = 1; + else + { + fprintf(out, "("); + need_paren = 1; + } + } + + /* We have found and printed an instruction; return. */ + return 4; + } + + /* We could not find a match. */ + fprintf(out, ".long 0x%lx", insn); + + return 4; +} diff --git a/translate-i386.c b/translate-i386.c index 4d8cbf391..b5894b787 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -25,16 +25,13 @@ #include #include +#include "disas.h" + #define DEBUG_DISAS #define IN_OP_I386 #include "cpu-i386.h" -/* dump all code */ -#ifdef DEBUG_DISAS -#include "dis-asm.h" -#endif - #ifndef offsetof #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif @@ -3626,9 +3623,6 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, uint16_t *gen_opc_end; int gen_code_size; long ret; -#ifdef DEBUG_DISAS - struct disassemble_info disasm_info; -#endif /* generate intermediate code */ @@ -3668,35 +3662,12 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, } *gen_opc_ptr = INDEX_op_end; - /* optimize flag computations */ #ifdef DEBUG_DISAS if (loglevel) { - uint8_t *pc; - int count; - - INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); -#if 0 - disasm_info.flavour = bfd_get_flavour (abfd); - disasm_info.arch = bfd_get_arch (abfd); - disasm_info.mach = bfd_get_mach (abfd); -#endif - disasm_info.endian = BFD_ENDIAN_LITTLE; - if (dc->code32) - disasm_info.mach = bfd_mach_i386_i386; - else - disasm_info.mach = bfd_mach_i386_i8086; fprintf(logfile, "----------------\n"); - fprintf(logfile, "IN:\n"); - disasm_info.buffer = pc_start; - disasm_info.buffer_vma = (unsigned long)pc_start; - disasm_info.buffer_length = pc_ptr - pc_start; - pc = pc_start; - while (pc < pc_ptr) { - fprintf(logfile, "0x%08lx: ", (long)pc); - count = print_insn_i386((unsigned long)pc, &disasm_info); - fprintf(logfile, "\n"); - pc += count; - } + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + disas(logfile, pc_start, pc_ptr - pc_start, + dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086); fprintf(logfile, "\n"); fprintf(logfile, "OP:\n"); @@ -3723,33 +3694,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, #ifdef DEBUG_DISAS if (loglevel) { - uint8_t *pc; - int count; - - INIT_DISASSEMBLE_INFO(disasm_info, logfile, fprintf); -#if 0 - disasm_info.flavour = bfd_get_flavour (abfd); - disasm_info.arch = bfd_get_arch (abfd); - disasm_info.mach = bfd_get_mach (abfd); -#endif -#ifdef WORDS_BIGENDIAN - disasm_info.endian = BFD_ENDIAN_BIG; -#else - disasm_info.endian = BFD_ENDIAN_LITTLE; -#endif - disasm_info.mach = bfd_mach_i386_i386; - - pc = gen_code_buf; - disasm_info.buffer = pc; - disasm_info.buffer_vma = (unsigned long)pc; - disasm_info.buffer_length = *gen_code_size_ptr; fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); - while (pc < gen_code_buf + *gen_code_size_ptr) { - fprintf(logfile, "0x%08lx: ", (long)pc); - count = print_insn_i386((unsigned long)pc, &disasm_info); - fprintf(logfile, "\n"); - pc += count; - } + disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET); fprintf(logfile, "\n"); fflush(logfile); } -- cgit v1.2.3 From 728584be27b95c95fece7740b5e0b80930b5cc45 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:43:36 +0000 Subject: fstat64 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@108 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 13 +++++++++++-- syscall-i386.h | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 01e943b70..e4b543f81 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2264,7 +2264,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); break; case TARGET_NR_ugetrlimit: - goto unimplemented; + { + struct rlimit rlim; + ret = get_errno(getrlimit(arg1, &rlim)); + if (!is_error(ret)) { + struct target_rlimit *target_rlim = (void *)arg2; + target_rlim->rlim_cur = tswapl(rlim.rlim_cur); + target_rlim->rlim_max = tswapl(rlim.rlim_max); + } + break; + } case TARGET_NR_truncate64: goto unimplemented; case TARGET_NR_ftruncate64: @@ -2283,7 +2292,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct target_stat64 *target_st = (void *)arg2; memset(target_st, 0, sizeof(struct target_stat64)); target_st->st_dev = tswap16(st.st_dev); - target_st->st_ino = tswapl(st.st_ino); + target_st->st_ino = tswap64(st.st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO target_st->__st_ino = tswapl(st.st_ino); #endif diff --git a/syscall-i386.h b/syscall-i386.h index a2fb03dea..a38dd32d6 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -330,7 +330,7 @@ struct target_stat64 { target_ulong __pad7; /* will be high 32 bits of ctime someday */ unsigned long long st_ino; -}; +} __attribute__((packed)); #define TARGET_SA_NOCLDSTOP 0x00000001 #define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ -- cgit v1.2.3 From a8baa8c555dca3b48662d5f2ffeda9b791668b48 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:53:31 +0000 Subject: ia64 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@109 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure b/configure index 9bae7b437..bc0663034 100755 --- a/configure +++ b/configure @@ -46,6 +46,9 @@ case "$cpu" in s390) cpu="s390" ;; + ia64) + cpu="ia64" + ;; *) cpu="unknown" ;; @@ -212,6 +215,9 @@ elif test "$cpu" = "s390" ; then elif test "$cpu" = "alpha" ; then echo "ARCH=alpha" >> config.mak echo "#define HOST_ALPHA 1" >> $TMPH +elif test "$cpu" = "ia64" ; then + echo "ARCH=ia64" >> config.mak + echo "#define HOST_IA64 1" >> $TMPH else echo "Unsupported CPU" exit 1 -- cgit v1.2.3 From 43f04c233cb7d1731613bd6399c32ed09db01c16 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 20:53:42 +0000 Subject: alpha support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@110 c046a42c-6fe2-441c-8c8c-71466251a162 --- alpha.ld | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 alpha.ld diff --git a/alpha.ld b/alpha.ld new file mode 100644 index 000000000..097544306 --- /dev/null +++ b/alpha.ld @@ -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 . */ +} -- cgit v1.2.3 From e026db5893aeff66bbc1153002b5285bc361c0a2 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:07:28 +0000 Subject: alpha support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@111 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/exec-i386.c b/exec-i386.c index b75c6c70a..508d06882 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -102,6 +102,25 @@ static inline int testandset (int *p) } #endif +#ifdef __alpha__ +int testandset (int *p) +{ + int ret; + unsigned long one; + + __asm__ __volatile__ ("0: mov 1,%2\n" + " ldl_l %0,%1\n" + " stl_c %2,%1\n" + " beq %2,1f\n" + ".subsection 2\n" + "1: br 0b\n" + ".previous" + : "=r" (ret), "=m" (*p), "=r" (one) + : "m" (*p)); + return ret; +} +#endif + int global_cpu_lock = 0; void cpu_lock(void) -- cgit v1.2.3 From 27725c1d74a6dc754830ecccbc19c3d4cd63678c Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:08:18 +0000 Subject: ia64 support - fcntl uses TARGET_ constants git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@112 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e4b543f81..7561ed161 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -85,7 +85,7 @@ long do_rt_sigreturn(CPUX86State *env); #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo -#ifdef __alpha__ +#if defined(__alpha__) || defined (__ia64__) #define __NR__llseek __NR_lseek #endif @@ -1163,7 +1163,11 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) new_env->regs[R_ESP] = newsp; new_env->regs[R_EAX] = 0; new_env->opaque = ts; - ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); +#ifdef __ia64__ + ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); +#else + ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); +#endif } else { /* if no CLONE_VM, we consider it is a fork */ if ((flags & ~CSIGNAL) != 0) @@ -1419,7 +1423,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct target_flock *target_fl = (void *)arg3; switch(arg2) { - case F_GETLK: + case TARGET_F_GETLK: ret = get_errno(fcntl(arg1, arg2, &fl)); if (ret == 0) { target_fl->l_type = tswap16(fl.l_type); @@ -1430,8 +1434,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; - case F_SETLK: - case F_SETLKW: + case TARGET_F_SETLK: + case TARGET_F_SETLKW: fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -1440,9 +1444,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(fcntl(arg1, arg2, &fl)); break; - case F_GETLK64: - case F_SETLK64: - case F_SETLKW64: + case TARGET_F_GETLK64: + case TARGET_F_SETLK64: + case TARGET_F_SETLKW64: goto unimplemented; default: ret = get_errno(fcntl(arg1, arg2, arg3)); -- cgit v1.2.3 From bb326a37493de7c88dbdcb139676957bab691f25 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:08:48 +0000 Subject: fix _start routine name git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@113 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/hello.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hello.c b/tests/hello.c index 89bd15b82..e00245d3f 100644 --- a/tests/hello.c +++ b/tests/hello.c @@ -19,7 +19,7 @@ extern inline int write(int fd, const char * buf, int len) : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len))); } -void _startup(void) +void _start(void) { write(1, "Hello World\n", 12); exit(0); -- cgit v1.2.3 From fe1e3ce3e97f08d9b18b3444831a69b4666eb6b5 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:09:46 +0000 Subject: fcntl constants git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@114 c046a42c-6fe2-441c-8c8c-71466251a162 --- syscall-i386.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/syscall-i386.h b/syscall-i386.h index a38dd32d6..2d0e91dd3 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -936,6 +936,24 @@ union target_semun { unsigned int __pad; /* really void* */ }; +#define TARGET_F_DUPFD 0 /* dup */ +#define TARGET_F_GETFD 1 /* get close_on_exec */ +#define TARGET_F_SETFD 2 /* set/clear close_on_exec */ +#define TARGET_F_GETFL 3 /* get file->f_flags */ +#define TARGET_F_SETFL 4 /* set file->f_flags */ +#define TARGET_F_GETLK 5 +#define TARGET_F_SETLK 6 +#define TARGET_F_SETLKW 7 + +#define TARGET_F_SETOWN 8 /* for sockets. */ +#define TARGET_F_GETOWN 9 /* for sockets. */ +#define TARGET_F_SETSIG 10 /* for sockets. */ +#define TARGET_F_GETSIG 11 /* for sockets. */ + +#define TARGET_F_GETLK64 12 /* using 'struct flock64' */ +#define TARGET_F_SETLK64 13 +#define TARGET_F_SETLKW64 14 + struct target_flock { short l_type; short l_whence; -- cgit v1.2.3 From 0d3301964df6d36c72dfa95ba5ae5e3b789cd1f8 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:10:09 +0000 Subject: ia64 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@115 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++ exec-i386.h | 6 +++ ia64-syscall.S | 32 ++++++++++++++++ linux-user/signal.c | 7 ++++ thunk.h | 2 +- 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 ia64-syscall.S diff --git a/elf.h b/elf.h index fcd3fecb4..b5dca4b11 100644 --- a/elf.h +++ b/elf.h @@ -767,6 +767,114 @@ typedef struct { #define PF_HP_LAZYSWAP 0x04000000 #define PF_HP_SBP 0x08000000 +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ typedef struct elf32_rel { Elf32_Addr r_offset; diff --git a/exec-i386.h b/exec-i386.h index b85457704..b4f5a0013 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -106,6 +106,12 @@ register unsigned int T1 asm("$10"); register unsigned int A0 asm("$11"); register struct CPUX86State *env asm("$12"); #endif +#ifdef __ia64__ +register unsigned int T0 asm("r24"); +register unsigned int T1 asm("r25"); +register unsigned int A0 asm("r26"); +register struct CPUX86State *env asm("r27"); +#endif /* force GCC to generate only one epilog at the end of the function */ #define FORCE_RET() asm volatile (""); diff --git a/ia64-syscall.S b/ia64-syscall.S new file mode 100644 index 000000000..ab073f22b --- /dev/null +++ b/ia64-syscall.S @@ -0,0 +1,32 @@ +/* derived from glibc sysdeps/unix/sysv/linux/ia64/sysdep.S */ + +#define __ASSEMBLY__ + +#include +#include + +ENTRY(__syscall_error) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0) + alloc r33=ar.pfs, 0, 4, 0, 0 + mov r32=rp + .body + mov r35=r8 + mov r34=r1 + ;; + br.call.sptk.many b0 = __errno_location +.Lret0: /* force new bundle */ + st4 [r8]=r35 + mov r1=r34 + mov rp=r32 + mov r8=-1 + mov ar.pfs=r33 + br.ret.sptk.few b0 +END(__syscall_error) + +GLOBAL_ENTRY(__ia64_syscall) + mov r15=r37 /* syscall number */ + break __BREAK_SYSCALL + cmp.eq p6,p0=-1,r10 /* r10 = -1 on error */ +(p6) br.cond.spnt.few __syscall_error + br.ret.sptk.few b0 +.endp __ia64_syscall diff --git a/linux-user/signal.c b/linux-user/signal.c index 5ed1d8532..1f779f912 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -26,6 +26,13 @@ #include #include +#ifdef __ia64__ +#undef uc_mcontext +#undef uc_sigmask +#undef uc_stack +#undef uc_link +#endif + #include "qemu.h" //#define DEBUG_SIGNAL diff --git a/thunk.h b/thunk.h index 2fa3f63ac..97b441a0b 100644 --- a/thunk.h +++ b/thunk.h @@ -70,7 +70,7 @@ #define TARGET_LONG_BITS 32 -#if defined(__alpha__) +#if defined(__alpha__) || defined (__ia64__) #define HOST_LONG_BITS 64 #else #define HOST_LONG_BITS 32 -- cgit v1.2.3 From efdea7bf193bb5f00737022f8a6efeab3e4d5ff4 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:12:28 +0000 Subject: ia64 support - alpha support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@116 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++--------- translate-i386.c | 13 +++++ 2 files changed, 136 insertions(+), 22 deletions(-) diff --git a/dyngen.c b/dyngen.c index 1eb80328f..66f735bee 100644 --- a/dyngen.c +++ b/dyngen.c @@ -58,20 +58,29 @@ #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 + #else #error unsupported CPU - please update the code #endif +#include "elf.h" + #if ELF_CLASS == ELFCLASS32 typedef int32_t host_long; typedef uint32_t host_ulong; +#define swabls(x) swab32s(x) #else typedef int64_t host_long; typedef uint64_t host_ulong; +#define swabls(x) swab64s(x) #endif -#include "elf.h" - #include "thunk.h" /* all dynamically generated functions begin with this code */ @@ -104,12 +113,6 @@ void swab64s(uint64_t *p) *p = bswap64(*p); } -#if ELF_CLASS == ELFCLASS32 -#define swabls(x) swab32s(x) -#else -#define swabls(x) swab64s(x) -#endif - void elf_swap_ehdr(struct elfhdr *h) { swab16s(&h->e_type); /* Object file type */ @@ -187,7 +190,7 @@ void put32(uint32_t *p, uint32_t val) *p = val; } -void __attribute__((noreturn)) error(const char *fmt, ...) +void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -295,10 +298,36 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (p == p_start) error("empty code for %s", name); if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4) - error("br %r14 expected at the end of %s", name); + error("br %%r14 expected at the end of %s", name); copy_size = p - p_start; } break; + case EM_ALPHA: + { + uint8_t *p; + p = p_end - 4; + if (p == p_start) + error("empty code for %s", name); + if (get32((uint32_t *)p) != 0x6bfa8001) + error("ret expected at the end of %s", name); + copy_size = p - p_start; + } + break; + case EM_IA_64: + { + uint8_t *p; + p = (void *)(p_end - 4); + if (p == p_start) + error("empty code for %s", name); + /* br.ret.sptk.many b0;; */ + /* 08 00 84 00 */ + if (get32((uint32_t *)p) != 0x00840008) + error("br.ret.sptk.many b0;; expected at the end of %s", name); + copy_size = p - p_start; + } + break; + default: + error("unknown ELF architecture"); } /* compute the number of arguments by looking at the relocations */ @@ -344,7 +373,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { - sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (!strstart(sym_name, "__op_param", &p)) { fprintf(outfile, "extern char %s;\n", sym_name); } @@ -364,7 +393,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { - sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); } else { @@ -394,7 +423,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { - sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); } else { @@ -437,7 +466,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { - sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); } else { @@ -464,6 +493,67 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#elif defined(HOST_ALPHA) + { + for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + int type; + sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; + + type = ELF64_R_TYPE(rel->r_info); + switch (type) { + case R_ALPHA_GPDISP: + /* Instructions to set up the gp can be nopped, since we keep it current + all the time. FIXME assert that target is really gp */ + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = 0x2ffe0000; /* unop */\n", + rel->r_offset - offset); + 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. Need to patch the + 16-bit immediate offset. */ + fprintf(outfile, " *(int16_t *)(gen_code_ptr + %d) = gp - (long)(&%s);\n", + rel->r_offset - offset, name); + break; + default: + error("unsupported Alpha relocation (%d)", type); + } + } + } + } +#elif defined(HOST_IA64) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF64_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_IA64_LTOFF22: + error("must implemnt R_IA64_LTOFF22 relocation"); + case R_IA64_PCREL21B: + error("must implemnt R_IA64_PCREL21B relocation"); + default: + error("unsupported ia64 relocation (%d)", type); + } + } + } + } #else #error unsupported CPU #endif @@ -564,17 +654,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) nb_relocs = sec->sh_size / sec->sh_entsize; if (do_swap) { if (sec->sh_type == SHT_REL) { - Elf32_Rel *rel = relocs; + ElfW(Rel) *rel = relocs; for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { - swab32s(&rel->r_offset); - swab32s(&rel->r_info); + swabls(&rel->r_offset); + swabls(&rel->r_info); } } else { - Elf32_Rela *rel = relocs; + ElfW(Rela) *rel = relocs; for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { - swab32s(&rel->r_offset); - swab32s(&rel->r_info); - swab32s(&rel->r_addend); + swabls(&rel->r_offset); + swabls(&rel->r_info); + swabls(&rel->r_addend); } } } @@ -590,7 +680,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size); strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size); - nb_syms = symtab_sec->sh_size / sizeof(Elf32_Sym); + nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); if (do_swap) { for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { swab32s(&sym->st_name); @@ -612,6 +702,9 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) } } else { /* generate big code generation switch */ +#ifdef HOST_ALPHA + fprintf(outfile, "register long gp asm(\"%%$29\");\n"); +#endif fprintf(outfile, "int dyngen_code(uint8_t *gen_code_buf,\n" " const uint16_t *opc_buf, const uint32_t *opparam_buf)\n" @@ -660,6 +753,14 @@ fprintf(outfile, case EM_S390: fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n"); break; + case EM_ALPHA: + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x6bfa8001; /* ret */\n"); + break; + case EM_IA_64: + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n"); + break; + default: + error("unknown ELF architecture"); } fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n"); diff --git a/translate-i386.c b/translate-i386.c index b5894b787..e23ff6777 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -53,6 +53,12 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) } #endif +#ifdef __ia64__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} +#endif + #ifdef __powerpc__ #define MIN_CACHE_LINE_SIZE 8 /* conservative value */ @@ -76,6 +82,13 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) } #endif +#ifdef __alpha__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + asm ("imb"); +} +#endif + extern FILE *logfile; extern int loglevel; -- cgit v1.2.3 From d6cdca958e00c476998a37d50885085a072d90bd Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:24:00 +0000 Subject: alpha support - ia64 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@117 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Makefile b/Makefile index 9008dc95b..49f26fcf6 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,18 @@ OP_CFLAGS=$(CFLAGS) LDFLAGS+=-Wl,-T,s390.ld endif +ifeq ($(ARCH),alpha) +# Ensure there's only a single GP +CFLAGS += -msmall-data -msmall-text +# FIXME Too lazy to deal with gprelhigh/gprellow for now, inhibit them +OP_CFLAGS=$(CFLAGS) -mno-explicit-relocs +LDFLAGS+=-Wl,-T,alpha.ld +endif + +ifeq ($(ARCH),ia64) +OP_CFLAGS=$(CFLAGS) +endif + ifeq ($(GCC_MAJOR),3) # very important to generate a return at the end of every operation OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls @@ -53,6 +65,10 @@ LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ppc-dis.o i386-dis.o dis-buf.o +ifeq ($(ARCH),ia64) +OBJS += ia64-syscall.o +endif + all: qemu qemu-doc.html qemu: $(OBJS) -- cgit v1.2.3 From a98fd896cdcab506e734de7555304da16e775277 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:24:12 +0000 Subject: target cpu definition git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@118 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure b/configure index bc0663034..ea595533e 100755 --- a/configure +++ b/configure @@ -26,6 +26,7 @@ host_cc="gcc" ar="ar" make="make" strip="strip" +target_cpu="x86" cpu=`uname -m` case "$cpu" in i386|i486|i586|i686|i86pc|BePC) @@ -178,8 +179,9 @@ echo "Install prefix $prefix" echo "Source path $source_path" echo "C compiler $cc" echo "make $make" -echo "CPU $cpu" +echo "host CPU $cpu" echo "Big Endian $bigendian" +echo "target CPU $target_cpu" echo "gprof enabled $gprof" echo "Creating config.mak and config.h" -- cgit v1.2.3 From d014c98c8dce88c3b6cc19bd2e0e558900f5c1d0 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:26:53 +0000 Subject: sparc support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@119 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 6 ++ dyngen.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ exec-i386.c | 14 ++++ exec-i386.h | 5 ++ op-i386.c | 82 +++++++++++++++++++++++- translate-i386.c | 15 +++++ 6 files changed, 310 insertions(+), 3 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index ca3379135..4b8aef12a 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -180,6 +180,12 @@ typedef struct CPUX86State { /* emulator internal variables */ CPU86_LDouble ft0; + union { + float f; + double d; + int i32; + int64_t i64; + } fp_convert; /* segments */ uint32_t segs[6]; /* selector values */ diff --git a/dyngen.c b/dyngen.c index 66f735bee..6d06c73fd 100644 --- a/dyngen.c +++ b/dyngen.c @@ -65,6 +65,20 @@ #define elf_check_arch(x) ((x) == EM_IA_64) #define ELF_USES_RELOCA +#elif defined(HOST_SPARC) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_SPARC +#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS) +#define ELF_USES_RELOCA + +#elif defined(HOST_SPARC64) + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_SPARCV9 +#define elf_check_arch(x) ((x) == EM_SPARCV9) +#define ELF_USES_RELOCA + #else #error unsupported CPU - please update the code #endif @@ -326,6 +340,47 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, copy_size = p - p_start; } break; + case EM_SPARC: + case EM_SPARC32PLUS: + { + uint8_t *p; + p = (void *)(p_end - 8); + if (p <= p_start) + error("empty code for %s", name); + if (get32((uint32_t *)(p_start + 0x0)) != 0x9de3bf98) + error("save %%sp,-104,%%sp expected at the start of %s " + "found [%08x]", + name, get32((uint32_t *)(p_start + 0x0))); + if (get32((uint32_t *)(p + 0x0)) != 0x81c7e008 || + get32((uint32_t *)(p + 0x4)) != 0x81e80000) + error("ret; restore; expected at the end of %s found [%08x:%08x]", + name, + get32((uint32_t *)(p + 0x0)), + get32((uint32_t *)(p + 0x4))); + + copy_size = p - p_start; + } + break; + case EM_SPARCV9: + { + uint8_t *p; + p = (void *)(p_end - 8); + if (p <= p_start) + error("empty code for %s", name); + if (get32((uint32_t *)(p_start + 0x0)) != 0x9de3bf40) + error("save %%sp,-192,%%sp expected at the start of %s " + "found [%08x]", + name, get32((uint32_t *)(p_start + 0x0))); + if (get32((uint32_t *)(p + 0x0)) != 0x81cfe008 || + get32((uint32_t *)(p + 0x4)) != 0x01000000) + error("rett %%i7+8; nop; expected at the end of %s " + "found [%08x:%08x]", + name, + get32((uint32_t *)(p + 0x0)), + get32((uint32_t *)(p + 0x4))); + copy_size = p - p_start; + } + break; default: error("unknown ELF architecture"); } @@ -375,6 +430,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (!strstart(sym_name, "__op_param", &p)) { +#if defined(HOST_SPARC) + if (sym_name[0] == '.') { + fprintf(outfile, + "extern char __dot_%s __asm__(\"%s\");\n", + sym_name+1, sym_name); + continue; + } +#endif fprintf(outfile, "extern char %s;\n", sym_name); } } @@ -554,6 +617,126 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#elif defined(HOST_SPARC) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + if (sym_name[0] == '.') + snprintf(name, sizeof(name), + "(long)(&__dot_%s)", + sym_name + 1); + else + snprintf(name, sizeof(name), + "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_SPARC_32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + rel->r_offset - 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) & 0x3fffff);\n", + rel->r_offset - offset, + rel->r_offset - offset, + name, addend); + break; + case R_SPARC_LO10: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x3ff) " + " | ((%s + %d) & 0x3ff);\n", + rel->r_offset - offset, + rel->r_offset - 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)>>2) " + " & 0x3fffffff);\n", + rel->r_offset - offset, + rel->r_offset - offset, + name, addend); + break; + default: + error("unsupported sparc relocation (%d)", type); + } + } + } + } +#elif defined(HOST_SPARC64) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF64_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_SPARC_32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + rel->r_offset - 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) & 0x3fffff);\n", + rel->r_offset - offset, + rel->r_offset - offset, + name, addend); + break; + case R_SPARC_LO10: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x3ff) " + " | ((%s + %d) & 0x3ff);\n", + rel->r_offset - offset, + rel->r_offset - 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)>>2) " + " & 0x3fffffff);\n", + rel->r_offset - offset, + rel->r_offset - offset, + name, addend); + break; + default: + error("unsupported sparc64 relocation (%d)", type); + } + } + } + } #else #error unsupported CPU #endif @@ -759,6 +942,14 @@ fprintf(outfile, case EM_IA_64: fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n"); break; + case EM_SPARC: + case EM_SPARC32PLUS: + case EM_SPARCV9: + /* Fill the delay slot. */ + fprintf(outfile, "*((uint32_t *)gen_code_ptr) = *((uint32_t *)gen_code_ptr - 1); /* delay slot */\n"); + fprintf(outfile, "*((uint32_t *)gen_code_ptr - 1) = 0x81c3e008; /* retl */\n"); + fprintf(outfile, "gen_code_ptr++;\n"); + break; default: error("unknown ELF architecture"); } diff --git a/exec-i386.c b/exec-i386.c index 508d06882..ecb7adc9d 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -121,6 +121,20 @@ int testandset (int *p) } #endif +#ifdef __sparc__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (ret) + : "r" (p) + : "memory"); + + return (ret ? 1 : 0); +} +#endif + int global_cpu_lock = 0; void cpu_lock(void) diff --git a/exec-i386.h b/exec-i386.h index b4f5a0013..4f7f4ceb3 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -93,6 +93,7 @@ register unsigned int T0 asm("l0"); register unsigned int T1 asm("l1"); register unsigned int A0 asm("l2"); register struct CPUX86State *env asm("l3"); +#define USE_FP_CONVERT #endif #ifdef __s390__ register unsigned int T0 asm("r7"); @@ -160,6 +161,10 @@ register struct CPUX86State *env asm("r27"); #define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) #define ST1 ST(1) +#ifdef USE_FP_CONVERT +#define FP_CONVERT (env->fp_convert) +#endif + extern int __op_param1, __op_param2, __op_param3; #define PARAM1 ((long)(&__op_param1)) #define PARAM2 ((long)(&__op_param2)) diff --git a/op-i386.c b/op-i386.c index 323fce33d..ede63eabd 100644 --- a/op-i386.c +++ b/op-i386.c @@ -1605,12 +1605,22 @@ typedef union { void OPPROTO op_flds_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldl((void *)A0); + FT0 = FP_CONVERT.f; +#else FT0 = ldfl((void *)A0); +#endif } void OPPROTO op_fldl_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = ldq((void *)A0); + FT0 = FP_CONVERT.d; +#else FT0 = ldfq((void *)A0); +#endif } /* helpers are needed to avoid static constant reference. XXX: find a better way */ @@ -1650,17 +1660,32 @@ void OPPROTO op_fildll_FT0_A0(void) void OPPROTO op_fild_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldsw((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i32; +#else FT0 = (CPU86_LDouble)ldsw((void *)A0); +#endif } void OPPROTO op_fildl_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = (int32_t) ldl((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i32; +#else FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +#endif } void OPPROTO op_fildll_FT0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = (int64_t) ldq((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i64; +#else FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +#endif } #endif @@ -1668,12 +1693,22 @@ void OPPROTO op_fildll_FT0_A0(void) void OPPROTO op_flds_ST0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldl((void *)A0); + ST0 = FP_CONVERT.f; +#else ST0 = ldfl((void *)A0); +#endif } void OPPROTO op_fldl_ST0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = ldq((void *)A0); + ST0 = FP_CONVERT.d; +#else ST0 = ldfq((void *)A0); +#endif } #ifdef USE_X86LDOUBLE @@ -1738,17 +1773,32 @@ void OPPROTO op_fildll_ST0_A0(void) void OPPROTO op_fild_ST0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldsw((void *)A0); + ST0 = (CPU86_LDouble)FP_CONVERT.i32; +#else ST0 = (CPU86_LDouble)ldsw((void *)A0); +#endif } void OPPROTO op_fildl_ST0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = (int32_t) ldl((void *)A0); + ST0 = (CPU86_LDouble)FP_CONVERT.i32; +#else ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +#endif } void OPPROTO op_fildll_ST0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = (int64_t) ldq((void *)A0); + ST0 = (CPU86_LDouble)FP_CONVERT.i64; +#else ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +#endif } #endif @@ -1757,7 +1807,12 @@ void OPPROTO op_fildll_ST0_A0(void) void OPPROTO op_fsts_ST0_A0(void) { +#ifdef USE_FP_CONVERT + FP_CONVERT.d = ST0; + stfl((void *)A0, FP_CONVERT.f); +#else stfl((void *)A0, (float)ST0); +#endif } void OPPROTO op_fstl_ST0_A0(void) @@ -1792,22 +1847,43 @@ void OPPROTO op_fstt_ST0_A0(void) void OPPROTO op_fist_ST0_A0(void) { +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif int val; - val = lrint(ST0); + + d = ST0; + val = lrint(d); stw((void *)A0, val); } void OPPROTO op_fistl_ST0_A0(void) { +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif int val; - val = lrint(ST0); + + d = ST0; + val = lrint(d); stl((void *)A0, val); } void OPPROTO op_fistll_ST0_A0(void) { +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif int64_t val; - val = llrint(ST0); + + d = ST0; + val = llrint(d); stq((void *)A0, val); } diff --git a/translate-i386.c b/translate-i386.c index e23ff6777..1cdad2d90 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -89,6 +89,21 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) } #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 + extern FILE *logfile; extern int loglevel; -- cgit v1.2.3 From 3c51961e0e9e0e20415825af8e9babc2f086ebe0 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Apr 2003 21:34:02 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@120 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 10 +++ TODO | 11 +-- s390.ld | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/.cvsignore | 6 -- tests/Makefile | 2 +- 5 files changed, 222 insertions(+), 11 deletions(-) create mode 100644 s390.ld diff --git a/Changelog b/Changelog index 03158ccb5..bff66fdbc 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,13 @@ +version 0.2: + + - PowerPC disassembly and ELF symbols output (Rusty Russel) + - flock support (Rusty Russel) + - ugetrlimit support (Rusty Russel) + - fstat64 fix (Rusty Russel) + - initial Alpha port (Falk Hueffner) + - initial IA64 port (Matt Wilson) + - initial Sparc and Sparc64 port (David S. Miller) + version 0.1.6: - automatic library search system. QEMU can now work with unpatched diff --git a/TODO b/TODO index 66ecfea39..f27a94335 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,15 @@ +- fix gcc 2.96 compile bug - fix thread locks - optimize translated cache chaining (DLL PLT-like system) -- fix thread stack liberation (use kernel 2.5.xxx CLONE_CHILD_CLEARTID) +- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID) - fix x86 stack allocation - fix iret/lret restarting - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues, fix 16 bit uid issues) - finish signal handing (fp87 state, more siginfo conversions) -- verify thread support (clone() and various locks) -- make it self runnable (handle self modifying code, relocate stack - and dyn loader) - fix FPU exceptions (in particular: gen_op_fpush not before mem load) +- handle self-modifying code (track mmap and mark all pages containing + translated code as readonly. use a custom signal handler to flush + parts of the translation cache if write access to a readonly page + containing translated code). +- use gcc to compile to static code diff --git a/s390.ld b/s390.ld new file mode 100644 index 000000000..7f14ea919 --- /dev/null +++ b/s390.ld @@ -0,0 +1,204 @@ +OUTPUT_FORMAT("elf32-s390", "elf32-s390", + "elf32-s390") +OUTPUT_ARCH(s390:31-bit) +ENTRY(_start) +SEARCH_DIR("/usr/s390-redhat-linux/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) + *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x07070707 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x07070707 + .fini : + { + KEEP (*(.fini)) + } =0x07070707 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} + diff --git a/tests/.cvsignore b/tests/.cvsignore index 9b6d5179c..b70d47bd6 100644 --- a/tests/.cvsignore +++ b/tests/.cvsignore @@ -3,16 +3,10 @@ hello sha1.test.c sha1.c - op.c test-i386 sha1 testclone - interp.h - interploop.c .gdb_history - cachegrind.out - interp.c - interp testthread test-i386.s test-i386.ref diff --git a/tests/Makefile b/tests/Makefile index 386cb3c16..6a55d20d7 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -32,7 +32,7 @@ test_path: test_path.c # i386 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c test-i386-code16.S -lm + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c test-i386-code16.S -lm test: test-i386 ifeq ($(ARCH),i386) -- cgit v1.2.3 From 86840ae241441c64d2e6e8bcaac7c6dfa5c16cdf Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:30:27 +0000 Subject: update (test) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@121 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index bff66fdbc..394b3e38e 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,9 @@ version 0.2: - initial Alpha port (Falk Hueffner) - initial IA64 port (Matt Wilson) - initial Sparc and Sparc64 port (David S. Miller) + - better exception support for dosemu + - added HLT instruction + - added GPF generation for I/Os version 0.1.6: -- cgit v1.2.3 From a69d83b60b9923784eaceccdb2dc07ca1e599494 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:32:33 +0000 Subject: systematic exception test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@122 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/testsig.c | 118 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 93 insertions(+), 25 deletions(-) diff --git a/tests/testsig.c b/tests/testsig.c index 27ea78c6a..5f6d3705e 100644 --- a/tests/testsig.c +++ b/tests/testsig.c @@ -26,13 +26,15 @@ void alarm_handler(int sig) #define REG_ESP ESP #define REG_EIP EIP #define REG_EFL EFL +#define REG_TRAPNO TRAPNO +#define REG_ERR ERR #endif void dump_regs(struct ucontext *uc) { printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EFL=%08x EIP=%08x\n", + "EFL=%08x EIP=%08x trapno=%02x err=%08x\n", uc->uc_mcontext.gregs[REG_EAX], uc->uc_mcontext.gregs[REG_EBX], uc->uc_mcontext.gregs[REG_ECX], @@ -42,7 +44,9 @@ void dump_regs(struct ucontext *uc) uc->uc_mcontext.gregs[REG_EBP], uc->uc_mcontext.gregs[REG_ESP], uc->uc_mcontext.gregs[REG_EFL], - uc->uc_mcontext.gregs[REG_EIP]); + uc->uc_mcontext.gregs[REG_EIP], + uc->uc_mcontext.gregs[REG_TRAPNO], + uc->uc_mcontext.gregs[REG_ERR]); } void sig_handler(int sig, siginfo_t *info, void *puc) @@ -58,19 +62,22 @@ void sig_handler(int sig, siginfo_t *info, void *puc) } int v1; +int tab[2]; int main(int argc, char **argv) { struct sigaction act; - int i; + int val; + act.sa_sigaction = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + sigaction(SIGFPE, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + /* test division by zero reporting */ if (setjmp(jmp_env) == 0) { - act.sa_sigaction = sig_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO | SA_ONESHOT; - sigaction(SIGFPE, &act, NULL); - /* now divide by zero */ v1 = 0; v1 = 2 / v1; @@ -78,33 +85,94 @@ int main(int argc, char **argv) /* test illegal instruction reporting */ if (setjmp(jmp_env) == 0) { - act.sa_sigaction = sig_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO | SA_ONESHOT; - sigaction(SIGILL, &act, NULL); - /* now execute an invalid instruction */ asm volatile("ud2"); } /* test SEGV reporting */ if (setjmp(jmp_env) == 0) { - act.sa_sigaction = sig_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO | SA_ONESHOT; - sigaction(SIGSEGV, &act, NULL); - /* now store in an invalid address */ *(char *)0x1234 = 1; } + + /* test SEGV reporting */ + if (setjmp(jmp_env) == 0) { + /* read from an invalid address */ + v1 = *(char *)0x1234; + } - act.sa_handler = alarm_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - sigaction(SIGALRM, &act, NULL); - alarm(1); - for(i = 0;i < 2; i++) { - sleep(1); + printf("segment GPF exception:\n"); + if (setjmp(jmp_env) == 0) { + /* load an invalid segment */ + asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0)); + } + + printf("INT exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("int $0xfd"); + } + + printf("CLI exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("cli"); + } + + printf("STI exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("cli"); + } + + printf("INTO exception:\n"); + if (setjmp(jmp_env) == 0) { + /* overflow exception */ + asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff)); + } + + printf("BOUND exception:\n"); + if (setjmp(jmp_env) == 0) { + /* bound exception */ + tab[0] = 1; + tab[1] = 10; + asm volatile ("bound %0, %1" : : "r" (11), "m" (tab)); + } + + printf("OUTB exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0)); + } + + printf("INB exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321)); } + + printf("REP OUTSB exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1)); + } + + printf("REP INSB exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1)); + } + + printf("HLT exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("hlt" : : "d" (0x4321), "D" (tab), "c" (1)); + } + +#if 0 + { + int i; + act.sa_handler = alarm_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + sigaction(SIGALRM, &act, NULL); + alarm(1); + for(i = 0;i < 2; i++) { + sleep(1); + } + } +#endif return 0; } -- cgit v1.2.3 From b689bc57d62dca9c48d8be15914d3dd53e33443e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:33:33 +0000 Subject: more accurate signal handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@123 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 5c1dd8ce9..825c0b264 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -67,34 +67,34 @@ void gemu_log(const char *fmt, ...) /***********************************************************/ /* CPUX86 core interface */ -void cpu_x86_outb(int addr, int val) +void cpu_x86_outb(CPUX86State *env, int addr, int val) { fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); } -void cpu_x86_outw(int addr, int val) +void cpu_x86_outw(CPUX86State *env, int addr, int val) { fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); } -void cpu_x86_outl(int addr, int val) +void cpu_x86_outl(CPUX86State *env, int addr, int val) { fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); } -int cpu_x86_inb(int addr) +int cpu_x86_inb(CPUX86State *env, int addr) { fprintf(stderr, "inb: port=0x%04x\n", addr); return 0; } -int cpu_x86_inw(int addr) +int cpu_x86_inw(CPUX86State *env, int addr) { fprintf(stderr, "inw: port=0x%04x\n", addr); return 0; } -int cpu_x86_inl(int addr) +int cpu_x86_inl(CPUX86State *env, int addr) { fprintf(stderr, "inl: port=0x%04x\n", addr); return 0; @@ -303,12 +303,22 @@ void cpu_loop(struct CPUX86State *env) /* XXX: more precise info */ info.si_signo = SIGSEGV; info.si_errno = 0; - info.si_code = 0; + info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; queue_signal(info.si_signo, &info); } } break; + case EXCP0E_PAGE: + info.si_signo = SIGSEGV; + info.si_errno = 0; + if (!(env->error_code & 1)) + info.si_code = TARGET_SEGV_MAPERR; + else + info.si_code = TARGET_SEGV_ACCERR; + info._sifields._sigfault._addr = env->cr2; + queue_signal(info.si_signo, &info); + break; case EXCP00_DIVZ: if (env->eflags & VM_MASK) { do_int(env, trapnr); @@ -328,7 +338,7 @@ void cpu_loop(struct CPUX86State *env) } else { info.si_signo = SIGSEGV; info.si_errno = 0; - info.si_code = 0; + info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; queue_signal(info.si_signo, &info); } -- cgit v1.2.3 From 66099dd9af853e0504c975f7ac6416cc82b95903 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:34:02 +0000 Subject: added trapno and error_code report in ucontext git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@124 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 1f779f912..987307139 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -527,8 +527,8 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, err |= __put_user(env->regs[R_EDX], &sc->edx); err |= __put_user(env->regs[R_ECX], &sc->ecx); err |= __put_user(env->regs[R_EAX], &sc->eax); - err |= __put_user(/*current->thread.trap_no*/ 0, &sc->trapno); - err |= __put_user(/*current->thread.error_code*/ 0, &sc->err); + err |= __put_user(env->exception_index, &sc->trapno); + err |= __put_user(env->error_code, &sc->err); err |= __put_user(env->eip, &sc->eip); err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs); err |= __put_user(env->eflags, &sc->eflags); -- cgit v1.2.3 From 9ba5695ce5c995437efce0462dd9b8631daba0c0 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:35:34 +0000 Subject: added CPL and IOPL as translation time constants - changed I/O function prototype to include emulator state - added error_code and cr2 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@125 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index 4b8aef12a..1ec719377 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -197,6 +197,8 @@ typedef struct CPUX86State { /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; + int error_code; + uint32_t cr2; int interrupt_request; /* user data */ @@ -401,12 +403,12 @@ static inline void stfq(void *ptr, double v) #endif #ifndef IN_OP_I386 -void cpu_x86_outb(int addr, int val); -void cpu_x86_outw(int addr, int val); -void cpu_x86_outl(int addr, int val); -int cpu_x86_inb(int addr); -int cpu_x86_inw(int addr); -int cpu_x86_inl(int addr); +void cpu_x86_outb(CPUX86State *env, int addr, int val); +void cpu_x86_outw(CPUX86State *env, int addr, int val); +void cpu_x86_outl(CPUX86State *env, int addr, int val); +int cpu_x86_inb(CPUX86State *env, int addr); +int cpu_x86_inw(CPUX86State *env, int addr); +int cpu_x86_inl(CPUX86State *env, int addr); #endif CPUX86State *cpu_x86_init(void); @@ -431,6 +433,8 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, #define GEN_FLAG_SS32_SHIFT 2 #define GEN_FLAG_VM_SHIFT 3 #define GEN_FLAG_ST_SHIFT 4 +#define GEN_FLAG_CPL_SHIFT 7 +#define GEN_FLAG_IOPL_SHIFT 9 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, -- cgit v1.2.3 From b56dad1c7bde3bdf53895fe6eff13bfb47e3ae9e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:38:04 +0000 Subject: added raise_exception_err() - added cr2 update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@126 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/exec-i386.c b/exec-i386.c index ecb7adc9d..ec738faad 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -149,7 +149,7 @@ void cpu_unlock(void) /* exception support */ /* NOTE: not static to force relocation generation by GCC */ -void raise_exception(int exception_index) +void raise_exception_err(int exception_index, int error_code) { /* NOTE: the register at this point must be saved by hand because longjmp restore them */ @@ -178,9 +178,16 @@ void raise_exception(int exception_index) env->regs[R_EDI] = EDI; #endif env->exception_index = exception_index; + env->error_code = error_code; longjmp(env->jmp_env, 1); } +/* short cut if error_code is 0 or not present */ +void raise_exception(int exception_index) +{ + raise_exception_err(exception_index, 0); +} + #if defined(DEBUG_EXEC) static const char *cc_op_str[] = { "DYNAMIC", @@ -218,8 +225,13 @@ static const char *cc_op_str[] = { static void cpu_x86_dump_state(FILE *f) { int eflags; + char cc_op_name[32]; eflags = cc_table[CC_OP].compute_all(); eflags |= (DF & DF_MASK); + if ((unsigned)env->cc_op < CC_OP_NB) + strcpy(cc_op_name, cc_op_str[env->cc_op]); + else + snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); fprintf(f, "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" @@ -227,7 +239,7 @@ static void cpu_x86_dump_state(FILE *f) "EIP=%08x\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], - env->cc_src, env->cc_dst, cc_op_str[env->cc_op], + env->cc_src, env->cc_dst, cc_op_name, eflags & DF_MASK ? 'D' : '-', eflags & CC_O ? 'O' : '-', eflags & CC_S ? 'S' : '-', @@ -280,14 +292,18 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, h = pc & (CODE_GEN_HASH_SIZE - 1); ptb = &tb_hash[h]; - for(;;) { - tb = *ptb; - if (!tb) - break; - if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) +#if 0 + /* XXX: hack to handle 16 bit modyfing code */ + if (flags & (1 << GEN_FLAG_CODE32_SHIFT)) +#endif + for(;;) { + tb = *ptb; + if (!tb) + break; + if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) return tb; - ptb = &tb->hash_next; - } + ptb = &tb->hash_next; + } *pptb = ptb; return NULL; } @@ -404,6 +420,8 @@ int cpu_x86_exec(CPUX86State *env1) (unsigned long)env->seg_cache[R_SS].base) != 0) << GEN_FLAG_ADDSEG_SHIFT; flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT); + flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT); + flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT; cs_base = env->seg_cache[R_CS].base; pc = cs_base + env->eip; tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, @@ -508,7 +526,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) #include #include +/* 'pc' is the host PC at which the exception was raised. 'address' is + the effective address of the memory exception */ static inline int handle_cpu_signal(unsigned long pc, + unsigned long address, sigset_t *old_set) { #ifdef DEBUG_SIGNAL @@ -524,7 +545,9 @@ static inline int handle_cpu_signal(unsigned long pc, sigprocmask(SIG_SETMASK, old_set, NULL); /* XXX: need to compute virtual pc position by retranslating code. The rest of the CPU state should be correct. */ - raise_exception(EXCP0D_GPF); + env->cr2 = address; + /* XXX: more precise exception code */ + raise_exception_err(EXCP0E_PAGE, 4); /* never comes here */ return 1; } else { @@ -546,7 +569,7 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, #endif pc = uc->uc_mcontext.gregs[REG_EIP]; pold_set = &uc->uc_sigmask; - return handle_cpu_signal(pc, pold_set); + return handle_cpu_signal(pc, (unsigned long)info->si_addr, pold_set); #else #warning No CPU specific signal handler: cannot handle target SIGSEGV events return 0; -- cgit v1.2.3 From 455b761956a656b378eab3dc1612268decf93fe3 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:38:21 +0000 Subject: added raise_exception_err() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@127 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.h | 1 + 1 file changed, 1 insertion(+) diff --git a/exec-i386.h b/exec-i386.h index 4f7f4ceb3..1fa86f414 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -182,6 +182,7 @@ extern CCTable cc_table[]; void load_seg(int seg_reg, int selector); void cpu_lock(void); void cpu_unlock(void); +void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); void OPPROTO op_movl_eflags_T0(void); -- cgit v1.2.3 From 504e56ebdca53bf8e8d379aa994e90a2e3b0d564 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:39:48 +0000 Subject: more accurate GPF generation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@128 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/op-i386.c b/op-i386.c index ede63eabd..10dfd8472 100644 --- a/op-i386.c +++ b/op-i386.c @@ -616,8 +616,10 @@ void OPPROTO op_jmp_im(void) void OPPROTO op_int_im(void) { - EIP = PARAM1; - raise_exception(EXCP0D_GPF); + int intno; + intno = PARAM1; + EIP = PARAM2; + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); } void OPPROTO op_int3(void) @@ -633,18 +635,23 @@ void OPPROTO op_into(void) if (eflags & CC_O) { raise_exception(EXCP04_INTO); } + FORCE_RET(); } -/* XXX: add IOPL/CPL tests */ -void OPPROTO op_cli(void) +void OPPROTO op_gpf(void) { + EIP = PARAM1; raise_exception(EXCP0D_GPF); } -/* XXX: add IOPL/CPL tests */ +void OPPROTO op_cli(void) +{ + env->eflags &= ~IF_MASK; +} + void OPPROTO op_sti(void) { - raise_exception(EXCP0D_GPF); + env->eflags |= IF_MASK; } /* vm86plus instructions */ @@ -1097,7 +1104,7 @@ void load_seg(int seg_reg, int selector) dt = &env->gdt; index = selector & ~7; if ((index + 7) > dt->limit) - raise_exception(EXCP0D_GPF); + raise_exception_err(EXCP0D_GPF, selector); ptr = dt->base + index; e1 = ldl(ptr); e2 = ldl(ptr + 4); -- cgit v1.2.3 From 082391983efbbf95ccecccce13b849926a929c2c Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:40:45 +0000 Subject: added op_gpf git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@129 c046a42c-6fe2-441c-8c8c-71466251a162 --- opc-i386.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opc-i386.h b/opc-i386.h index 84e41440f..2e48eb6eb 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -229,9 +229,10 @@ DEF(add_bitw_A0_T1, 0) DEF(add_bitl_A0_T1, 0) DEF(jmp_T0, 0) DEF(jmp_im, 1) -DEF(int_im, 1) +DEF(int_im, 2) DEF(int3, 1) DEF(into, 0) +DEF(gpf, 1) DEF(cli, 0) DEF(sti, 0) DEF(cli_vm, 0) -- cgit v1.2.3 From 08fc60898b2dba14f81fd8b7e5143c4d672a2c2c Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:41:15 +0000 Subject: more siginfo constants git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@130 c046a42c-6fe2-441c-8c8c-71466251a162 --- syscall-i386.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/syscall-i386.h b/syscall-i386.h index 2d0e91dd3..30e8bc3da 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -444,6 +444,18 @@ typedef struct target_siginfo { } _sifields; } target_siginfo_t; +/* + * si_code values + * Digital reserves positive values for kernel-generated signals. + */ +#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */ +#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */ +#define TARGET_SI_QUEUE -1 /* sent by sigqueue */ +#define TARGET_SI_TIMER -2 /* sent by timer expiration */ +#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */ +#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */ +#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */ + /* * SIGILL si_codes */ @@ -462,6 +474,12 @@ typedef struct target_siginfo { #define TARGET_FPE_FLTSUB (8) /* subscript out of range */ #define TARGET_NSIGFPE 8 +/* + * SIGSEGV si_codes + */ +#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */ +#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */ + /* default linux values for the selectors */ #define __USER_CS (0x23) #define __USER_DS (0x2B) -- cgit v1.2.3 From 19b84f3c35d7c8e9d4743cdeb93534f7640001e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:41:49 +0000 Subject: added setgroups and getgroups syscalls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@131 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7561ed161..3f6084d05 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "qemu.h" @@ -117,6 +118,7 @@ extern int setresuid(uid_t, uid_t, uid_t); extern int getresuid(uid_t *, uid_t *, uid_t *); extern int setresgid(gid_t, gid_t, gid_t); extern int getresgid(gid_t *, gid_t *, gid_t *); +extern int setgroups(int, gid_t *); static inline long get_errno(long ret) { @@ -1722,9 +1724,33 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_getgroups: - goto unimplemented; + { + int gidsetsize = arg1; + uint16_t *target_grouplist = (void *)arg2; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + ret = get_errno(getgroups(gidsetsize, grouplist)); + if (!is_error(ret)) { + for(i = 0;i < gidsetsize; i++) + target_grouplist[i] = tswap16(grouplist[i]); + } + } + break; case TARGET_NR_setgroups: - goto unimplemented; + { + int gidsetsize = arg1; + uint16_t *target_grouplist = (void *)arg2; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + for(i = 0;i < gidsetsize; i++) + grouplist[i] = tswap16(target_grouplist[i]); + ret = get_errno(setgroups(gidsetsize, grouplist)); + } + break; case TARGET_NR_select: goto unimplemented; case TARGET_NR_symlink: -- cgit v1.2.3 From 8e5a0667f8ef206773250f9b9dd5a4759369096e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:42:10 +0000 Subject: added KDGKBTYPE git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@132 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ioctls.h | 2 ++ linux-user/syscall_defs.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index b4bfb3ab6..68f248d63 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -51,6 +51,8 @@ IOCTL(TIOCMIWAIT, 0, TYPE_INT) IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct))) + IOCTL(KDGKBTYPE, IOC_W, MK_PTR(TYPE_CHAR)) + IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT)) IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT)) IOCTL(BLKRRPART, 0, TYPE_NULL) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index a442683b6..4dbc66333 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -212,6 +212,9 @@ struct target_pollfd { short revents; /* returned events */ }; +/* virtual terminal ioctls */ +#define TARGET_KDGKBTYPE 0x4b33 + /* Networking ioctls */ #define TARGET_SIOCADDRT 0x890B /* add routing table entry */ #define TARGET_SIOCDELRT 0x890C /* delete routing table entry */ -- cgit v1.2.3 From bf7c65bdf482923f34c3cbb42bd93f10416e3025 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:42:38 +0000 Subject: changed I/O function prototype to include emulator state git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@133 c046a42c-6fe2-441c-8c8c-71466251a162 --- op_string.h | 8 ++++---- ops_template.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/op_string.h b/op_string.h index 9d0b454c3..c7ff74c05 100644 --- a/op_string.h +++ b/op_string.h @@ -193,7 +193,7 @@ void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void) int v, dx, inc; dx = EDX & 0xffff; v = glue(ldu, SUFFIX)(SI_ADDR); - glue(cpu_x86_out, SUFFIX)(dx, v); + glue(cpu_x86_out, SUFFIX)(env, dx, v); inc = (DF << SHIFT); INC_SI(); } @@ -205,7 +205,7 @@ void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void) dx = EDX & 0xffff; while (CX != 0) { v = glue(ldu, SUFFIX)(SI_ADDR); - glue(cpu_x86_out, SUFFIX)(dx, v); + glue(cpu_x86_out, SUFFIX)(env, dx, v); INC_SI(); DEC_CX(); } @@ -216,7 +216,7 @@ void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void) { int v, dx, inc; dx = EDX & 0xffff; - v = glue(cpu_x86_in, SUFFIX)(dx); + v = glue(cpu_x86_in, SUFFIX)(env, dx); glue(st, SUFFIX)(DI_ADDR, v); inc = (DF << SHIFT); INC_DI(); @@ -228,7 +228,7 @@ void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void) inc = (DF << SHIFT); dx = EDX & 0xffff; while (CX != 0) { - v = glue(cpu_x86_in, SUFFIX)(dx); + v = glue(cpu_x86_in, SUFFIX)(env, dx); glue(st, SUFFIX)(DI_ADDR, v); INC_DI(); DEC_CX(); diff --git a/ops_template.h b/ops_template.h index b734d0f45..4cada782c 100644 --- a/ops_template.h +++ b/ops_template.h @@ -843,12 +843,12 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) { - glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK); + glue(cpu_x86_out, SUFFIX)(env, T0 & 0xffff, T1 & DATA_MASK); } void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) { - T1 = glue(cpu_x86_in, SUFFIX)(T0 & 0xffff); + T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff); } #undef DATA_BITS -- cgit v1.2.3 From 982b431579c926712633f3d8254bae24b34a4d83 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 May 2003 15:44:24 +0000 Subject: added CPL/IOPL support - fixed subtle inc/dec flag optimisation bug - added HLT instruction git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@134 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 169 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 57 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index 1cdad2d90..8ddf14e72 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -130,6 +130,8 @@ typedef struct DisasContext { int addseg; /* non zero if either DS/ES/SS have a non zero base */ int f_st; /* currently unused */ int vm86; /* vm86 mode */ + int cpl; + int iopl; } DisasContext; /* i386 arith/logic operations */ @@ -2766,26 +2768,36 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x6c: /* insS */ case 0x6d: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { - gen_string_es(s, ot, gen_op_ins + 9); + if (s->cpl > s->iopl || s->vm86) { + /* NOTE: even for (E)CX = 0 the exception is raised */ + gen_op_gpf(pc_start - s->cs_base); } else { - gen_string_es(s, ot, gen_op_ins); + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_string_es(s, ot, gen_op_ins + 9); + } else { + gen_string_es(s, ot, gen_op_ins); + } } break; case 0x6e: /* outsS */ case 0x6f: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { - gen_string_ds(s, ot, gen_op_outs + 9); + if (s->cpl > s->iopl || s->vm86) { + /* NOTE: even for (E)CX = 0 the exception is raised */ + gen_op_gpf(pc_start - s->cs_base); } else { - gen_string_ds(s, ot, gen_op_outs); + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_string_ds(s, ot, gen_op_outs + 9); + } else { + gen_string_ds(s, ot, gen_op_outs); + } } break; @@ -2793,45 +2805,61 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* port I/O */ case 0xe4: case 0xe5: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = ldub(s->pc++); - gen_op_movl_T0_im(val); - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); + if (s->cpl > s->iopl || s->vm86) { + gen_op_gpf(pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + } break; case 0xe6: case 0xe7: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = ldub(s->pc++); - gen_op_movl_T0_im(val); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); + if (s->cpl > s->iopl || s->vm86) { + gen_op_gpf(pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + } break; case 0xec: case 0xed: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); + if (s->cpl > s->iopl || s->vm86) { + gen_op_gpf(pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + } break; case 0xee: case 0xef: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); + if (s->cpl > s->iopl || s->vm86) { + gen_op_gpf(pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + } break; /************************/ @@ -3219,8 +3247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xcd: /* int N */ val = ldub(s->pc++); - /* XXX: currently we ignore the interrupt number */ - gen_op_int_im(pc_start - s->cs_base); + gen_op_int_im(val, pc_start - s->cs_base); s->is_jmp = 1; break; case 0xce: /* into */ @@ -3229,16 +3256,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_into(); break; case 0xfa: /* cli */ - if (s->vm86) - gen_op_cli_vm(); - else - gen_op_cli(); + if (!s->vm86) { + if (s->cpl <= s->iopl) + gen_op_cli(); + else + gen_op_gpf(pc_start - s->cs_base); + } else { + if (s->iopl == 3) + gen_op_cli(); + else + gen_op_cli_vm(); + } break; case 0xfb: /* sti */ - if (s->vm86) - gen_op_sti_vm(pc_start - s->cs_base); - else - gen_op_sti(); + if (!s->vm86) { + if (s->cpl <= s->iopl) + gen_op_sti(); + else + gen_op_gpf(pc_start - s->cs_base); + } else { + if (s->iopl == 3) + gen_op_sti(); + else + gen_op_sti_vm(pc_start - s->cs_base); + } break; case 0x62: /* bound */ ot = dflag ? OT_LONG : OT_WORD; @@ -3286,6 +3327,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x1a2: /* cpuid */ gen_op_cpuid(); break; + case 0xf4: /* hlt */ + if (s->cpl == 0) { + /* ignored */ + } else { + gen_op_gpf(pc_start - s->cs_base); + } + break; default: goto illegal_op; } @@ -3315,6 +3363,10 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_sbbw_T0_T1_cc] = CC_C, [INDEX_op_sbbl_T0_T1_cc] = CC_C, + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_incl_T0_cc] = CC_C, + [INDEX_op_decl_T0_cc] = CC_C, + [INDEX_op_into] = CC_O, [INDEX_op_jo_cc] = CC_O, @@ -3416,8 +3468,9 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_negl_T0_cc] = CC_OSZAPC, - [INDEX_op_incl_T0_cc] = CC_OSZAP, - [INDEX_op_decl_T0_cc] = CC_OSZAP, + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_incl_T0_cc] = CC_OSZAPC, + [INDEX_op_decl_T0_cc] = CC_OSZAPC, [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_mulb_AL_T0] = CC_OSZAPC, @@ -3659,6 +3712,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; + dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; + dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; @@ -3697,7 +3752,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, disas(logfile, pc_start, pc_ptr - pc_start, dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086); fprintf(logfile, "\n"); - + fprintf(logfile, "OP:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); -- cgit v1.2.3 From 89e957e7a292aa698fac77b53b5d80c7760161a8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 12:33:15 +0000 Subject: moved vm86 stuff to vm86.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@135 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 162 ++---------------------------------------------------- 1 file changed, 4 insertions(+), 158 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 825c0b264..c9d0c9860 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -119,129 +119,7 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit, uint64_t gdt_table[6]; -//#define DEBUG_VM86 - -static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) -{ - return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1; -} - -static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) -{ - return (uint8_t *)((seg << 4) + (reg & 0xffff)); -} - -static inline void pushw(CPUX86State *env, int val) -{ - env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | - ((env->regs[R_ESP] - 2) & 0xffff); - *(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val; -} - -static inline unsigned int get_vflags(CPUX86State *env) -{ - unsigned int eflags; - eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); - if (eflags & VIF_MASK) - eflags |= IF_MASK; - return eflags; -} - -void save_v86_state(CPUX86State *env) -{ - TaskState *ts = env->opaque; -#ifdef DEBUG_VM86 - printf("save_v86_state\n"); -#endif - - /* put the VM86 registers in the userspace register structure */ - ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); - ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); - ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); - ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); - ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); - ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); - ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); - ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); - ts->target_v86->regs.eip = tswap32(env->eip); - ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); - ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); - ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); - ts->target_v86->regs.es = tswap16(env->segs[R_ES]); - ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); - ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); - ts->target_v86->regs.eflags = tswap32(env->eflags); - - /* restore 32 bit registers */ - env->regs[R_EAX] = ts->vm86_saved_regs.eax; - env->regs[R_EBX] = ts->vm86_saved_regs.ebx; - env->regs[R_ECX] = ts->vm86_saved_regs.ecx; - env->regs[R_EDX] = ts->vm86_saved_regs.edx; - env->regs[R_ESI] = ts->vm86_saved_regs.esi; - env->regs[R_EDI] = ts->vm86_saved_regs.edi; - env->regs[R_EBP] = ts->vm86_saved_regs.ebp; - env->regs[R_ESP] = ts->vm86_saved_regs.esp; - env->eflags = ts->vm86_saved_regs.eflags; - env->eip = ts->vm86_saved_regs.eip; - - cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); - cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); - cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); - cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); - cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); - cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); -} - -/* return from vm86 mode to 32 bit. The vm86() syscall will return - 'retval' */ -static inline void return_to_32bit(CPUX86State *env, int retval) -{ -#ifdef DEBUG_VM86 - printf("return_to_32bit: ret=0x%x\n", retval); -#endif - save_v86_state(env); - env->regs[R_EAX] = retval; -} - -/* handle VM86 interrupt (NOTE: the CPU core currently does not - support TSS interrupt revectoring, so this code is always executed) */ -static void do_int(CPUX86State *env, int intno) -{ - TaskState *ts = env->opaque; - uint32_t *int_ptr, segoffs; - - if (env->segs[R_CS] == TARGET_BIOSSEG) - goto cannot_handle; /* XXX: I am not sure this is really useful */ - if (is_revectored(intno, &ts->target_v86->int_revectored)) - goto cannot_handle; - if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, - &ts->target_v86->int21_revectored)) - goto cannot_handle; - int_ptr = (uint32_t *)(intno << 2); - segoffs = tswap32(*int_ptr); - if ((segoffs >> 16) == TARGET_BIOSSEG) - goto cannot_handle; -#ifdef DEBUG_VM86 - printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", - intno, segoffs >> 16, segoffs & 0xffff); -#endif - /* save old state */ - pushw(env, get_vflags(env)); - pushw(env, env->segs[R_CS]); - pushw(env, env->eip); - /* goto interrupt handler */ - env->eip = segoffs & 0xffff; - cpu_x86_load_seg(env, R_CS, segoffs >> 16); - env->eflags &= ~(VIF_MASK | TF_MASK); - return; - cannot_handle: -#ifdef DEBUG_VM86 - printf("VM86: return to 32 bits int 0x%x\n", intno); -#endif - return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); -} - -void cpu_loop(struct CPUX86State *env) +void cpu_loop(CPUX86State *env) { int trapnr; uint8_t *pc; @@ -249,45 +127,12 @@ void cpu_loop(struct CPUX86State *env) for(;;) { trapnr = cpu_x86_exec(env); - pc = env->seg_cache[R_CS].base + env->eip; switch(trapnr) { case EXCP0D_GPF: if (env->eflags & VM_MASK) { -#ifdef DEBUG_VM86 - printf("VM86 exception %04x:%08x %02x %02x\n", - env->segs[R_CS], env->eip, pc[0], pc[1]); -#endif - /* VM86 mode */ - switch(pc[0]) { - case 0xcd: /* int */ - env->eip += 2; - do_int(env, pc[1]); - break; - case 0x66: - switch(pc[1]) { - case 0xfb: /* sti */ - case 0x9d: /* popf */ - case 0xcf: /* iret */ - env->eip += 2; - return_to_32bit(env, TARGET_VM86_STI); - break; - default: - goto vm86_gpf; - } - break; - case 0xfb: /* sti */ - case 0x9d: /* popf */ - case 0xcf: /* iret */ - env->eip++; - return_to_32bit(env, TARGET_VM86_STI); - break; - default: - vm86_gpf: - /* real VM86 GPF exception */ - return_to_32bit(env, TARGET_VM86_UNKNOWN); - break; - } + handle_vm86_fault(env); } else { + pc = env->seg_cache[R_CS].base + env->eip; if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ env->eip += 2; @@ -354,6 +199,7 @@ void cpu_loop(struct CPUX86State *env) /* just indicate that signals should be handled asap */ break; default: + pc = env->seg_cache[R_CS].base + env->eip; fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", (long)pc, trapnr); abort(); -- cgit v1.2.3 From 46ddf5511d31101d83e38db17056f4178ac14bc9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 12:36:41 +0000 Subject: vm86 emulation closer to Linux kernel code - added correct IRQ emulation for dosemu git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@136 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/vm86.c | 407 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 linux-user/vm86.c diff --git a/linux-user/vm86.c b/linux-user/vm86.c new file mode 100644 index 000000000..8316117e4 --- /dev/null +++ b/linux-user/vm86.c @@ -0,0 +1,407 @@ +/* + * vm86 linux syscall support + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +//#define DEBUG_VM86 + +#define set_flags(X,new,mask) \ +((X) = ((X) & ~(mask)) | ((new) & (mask))) + +#define SAFE_MASK (0xDD5) +#define RETURN_MASK (0xDFF) + +static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) +{ + return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1; +} + +static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val) +{ + *(uint16_t *)(segptr + (reg16 & 0xffff)) = tswap16(val); +} + +static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val) +{ + *(uint32_t *)(segptr + (reg16 & 0xffff)) = tswap32(val); +} + +static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16) +{ + return tswap16(*(uint16_t *)(segptr + (reg16 & 0xffff))); +} + +static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16) +{ + return tswap32(*(uint16_t *)(segptr + (reg16 & 0xffff))); +} + +void save_v86_state(CPUX86State *env) +{ + TaskState *ts = env->opaque; + + /* put the VM86 registers in the userspace register structure */ + ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); + ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); + ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); + ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); + ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); + ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); + ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); + ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); + ts->target_v86->regs.eip = tswap32(env->eip); + ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); + ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); + ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); + ts->target_v86->regs.es = tswap16(env->segs[R_ES]); + ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); + ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); + set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask); + ts->target_v86->regs.eflags = tswap32(env->eflags); +#ifdef DEBUG_VM86 + fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n", + env->eflags, env->segs[R_CS], env->eip); +#endif + + /* restore 32 bit registers */ + env->regs[R_EAX] = ts->vm86_saved_regs.eax; + env->regs[R_EBX] = ts->vm86_saved_regs.ebx; + env->regs[R_ECX] = ts->vm86_saved_regs.ecx; + env->regs[R_EDX] = ts->vm86_saved_regs.edx; + env->regs[R_ESI] = ts->vm86_saved_regs.esi; + env->regs[R_EDI] = ts->vm86_saved_regs.edi; + env->regs[R_EBP] = ts->vm86_saved_regs.ebp; + env->regs[R_ESP] = ts->vm86_saved_regs.esp; + env->eflags = ts->vm86_saved_regs.eflags; + env->eip = ts->vm86_saved_regs.eip; + + cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); + cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); + cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); + cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); + cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); + cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); +} + +/* return from vm86 mode to 32 bit. The vm86() syscall will return + 'retval' */ +static inline void return_to_32bit(CPUX86State *env, int retval) +{ +#ifdef DEBUG_VM86 + fprintf(logfile, "return_to_32bit: ret=0x%x\n", retval); +#endif + save_v86_state(env); + env->regs[R_EAX] = retval; +} + +static inline int set_IF(CPUX86State *env) +{ + TaskState *ts = env->opaque; + + ts->v86flags |= VIF_MASK; + if (ts->v86flags & VIP_MASK) { + return_to_32bit(env, TARGET_VM86_STI); + return 1; + } + return 0; +} + +static inline void clear_IF(CPUX86State *env) +{ + TaskState *ts = env->opaque; + + ts->v86flags &= ~VIF_MASK; +} + +static inline void clear_TF(CPUX86State *env) +{ + env->eflags &= ~TF_MASK; +} + +static inline int set_vflags_long(unsigned long eflags, CPUX86State *env) +{ + TaskState *ts = env->opaque; + + set_flags(ts->v86flags, eflags, ts->v86mask); + set_flags(env->eflags, eflags, SAFE_MASK); + if (eflags & IF_MASK) + return set_IF(env); + return 0; +} + +static inline int set_vflags_short(unsigned short flags, CPUX86State *env) +{ + TaskState *ts = env->opaque; + + set_flags(ts->v86flags, flags, ts->v86mask & 0xffff); + set_flags(env->eflags, flags, SAFE_MASK); + if (flags & IF_MASK) + return set_IF(env); + return 0; +} + +static inline unsigned int get_vflags(CPUX86State *env) +{ + TaskState *ts = env->opaque; + unsigned int flags; + + flags = env->eflags & RETURN_MASK; + if (ts->v86flags & VIF_MASK) + flags |= IF_MASK; + return flags | (ts->v86flags & ts->v86mask); +} + +#define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff) + +/* handle VM86 interrupt (NOTE: the CPU core currently does not + support TSS interrupt revectoring, so this code is always executed) */ +void do_int(CPUX86State *env, int intno) +{ + TaskState *ts = env->opaque; + uint32_t *int_ptr, segoffs; + uint8_t *ssp; + unsigned int sp; + +#if 1 + if (intno == 0xe6 && (env->regs[R_EAX] & 0xffff) == 0x00c0) + loglevel = 1; +#endif + + if (env->segs[R_CS] == TARGET_BIOSSEG) + goto cannot_handle; + if (is_revectored(intno, &ts->target_v86->int_revectored)) + goto cannot_handle; + if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, + &ts->target_v86->int21_revectored)) + goto cannot_handle; + int_ptr = (uint32_t *)(intno << 2); + segoffs = tswap32(*int_ptr); + if ((segoffs >> 16) == TARGET_BIOSSEG) + goto cannot_handle; +#if defined(DEBUG_VM86) + fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", + intno, segoffs >> 16, segoffs & 0xffff); +#endif + /* save old state */ + ssp = (uint8_t *)(env->segs[R_SS] << 4); + sp = env->regs[R_ESP] & 0xffff; + vm_putw(ssp, sp - 2, get_vflags(env)); + vm_putw(ssp, sp - 4, env->segs[R_CS]); + vm_putw(ssp, sp - 6, env->eip); + ADD16(env->regs[R_ESP], -6); + /* goto interrupt handler */ + env->eip = segoffs & 0xffff; + cpu_x86_load_seg(env, R_CS, segoffs >> 16); + clear_TF(env); + clear_IF(env); + return; + cannot_handle: +#if defined(DEBUG_VM86) + fprintf(logfile, "VM86: return to 32 bits int 0x%x\n", intno); +#endif + return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); +} + +#define CHECK_IF_IN_TRAP(disp) \ + if ((tswap32(ts->target_v86->vm86plus.flags) & TARGET_vm86dbg_active) && \ + (tswap32(ts->target_v86->vm86plus.flags) & TARGET_vm86dbg_TFpendig)) \ + vm_putw(ssp,sp + disp,vm_getw(ssp,sp + disp) | TF_MASK) + +#define VM86_FAULT_RETURN \ + if ((tswap32(ts->target_v86->vm86plus.flags) & TARGET_force_return_for_pic) && \ + (ts->v86flags & (IF_MASK | VIF_MASK))) \ + return_to_32bit(env, TARGET_VM86_PICRETURN); \ + return + +void handle_vm86_fault(CPUX86State *env) +{ + TaskState *ts = env->opaque; + uint8_t *csp, *pc, *ssp; + unsigned int ip, sp; + + csp = (uint8_t *)(env->segs[R_CS] << 4); + ip = env->eip & 0xffff; + pc = csp + ip; + + ssp = (uint8_t *)(env->segs[R_SS] << 4); + sp = env->regs[R_ESP] & 0xffff; + +#if defined(DEBUG_VM86) + fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n", + env->segs[R_CS], env->eip, pc[0], pc[1]); +#endif + + /* VM86 mode */ + switch(pc[0]) { + case 0x66: + switch(pc[1]) { + case 0x9c: /* pushfd */ + ADD16(env->eip, 2); + ADD16(env->regs[R_ESP], -4); + vm_putl(ssp, sp - 4, get_vflags(env)); + VM86_FAULT_RETURN; + + case 0x9d: /* popfd */ + ADD16(env->eip, 2); + ADD16(env->regs[R_ESP], 4); + CHECK_IF_IN_TRAP(0); + if (set_vflags_long(vm_getl(ssp, sp), env)) + return; + VM86_FAULT_RETURN; + + case 0xcf: /* iretd */ + ADD16(env->regs[R_ESP], 12); + env->eip = vm_getl(ssp, sp) & 0xffff; + cpu_x86_load_seg(env, R_CS, vm_getl(ssp, sp + 4) & 0xffff); + CHECK_IF_IN_TRAP(8); + if (set_vflags_long(vm_getl(ssp, sp + 8), env)) + return; + VM86_FAULT_RETURN; + + default: + goto vm86_gpf; + } + break; + case 0x9c: /* pushf */ + ADD16(env->eip, 1); + ADD16(env->regs[R_ESP], -2); + vm_putw(ssp, sp - 2, get_vflags(env)); + VM86_FAULT_RETURN; + + case 0x9d: /* popf */ + ADD16(env->eip, 1); + ADD16(env->regs[R_ESP], 2); + CHECK_IF_IN_TRAP(0); + if (set_vflags_short(vm_getw(ssp, sp), env)) + return; + VM86_FAULT_RETURN; + + case 0xcd: /* int */ + ADD16(env->eip, 2); + do_int(env, pc[1]); + break; + + case 0xcf: /* iret */ + ADD16(env->regs[R_ESP], 6); + env->eip = vm_getw(ssp, sp); + cpu_x86_load_seg(env, R_CS, vm_getw(ssp, sp + 2)); + CHECK_IF_IN_TRAP(4); + if (set_vflags_short(vm_getw(ssp, sp + 4), env)) + return; + VM86_FAULT_RETURN; + + case 0xfa: /* cli */ + ADD16(env->eip, 1); + clear_IF(env); + VM86_FAULT_RETURN; + + case 0xfb: /* sti */ + ADD16(env->eip, 1); + if (set_IF(env)) + return; + VM86_FAULT_RETURN; + + default: + vm86_gpf: + /* real VM86 GPF exception */ + return_to_32bit(env, TARGET_VM86_UNKNOWN); + break; + } +} + +int do_vm86(CPUX86State *env, long subfunction, + struct target_vm86plus_struct * target_v86) +{ + TaskState *ts = env->opaque; + int ret; + + switch (subfunction) { + case TARGET_VM86_REQUEST_IRQ: + case TARGET_VM86_FREE_IRQ: + case TARGET_VM86_GET_IRQ_BITS: + case TARGET_VM86_GET_AND_RESET_IRQ: + gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction); + ret = -EINVAL; + goto out; + case TARGET_VM86_PLUS_INSTALL_CHECK: + /* NOTE: on old vm86 stuff this will return the error + from verify_area(), because the subfunction is + interpreted as (invalid) address to vm86_struct. + So the installation check works. + */ + ret = 0; + goto out; + } + + ts->target_v86 = target_v86; + /* save current CPU regs */ + ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ + ts->vm86_saved_regs.ebx = env->regs[R_EBX]; + ts->vm86_saved_regs.ecx = env->regs[R_ECX]; + ts->vm86_saved_regs.edx = env->regs[R_EDX]; + ts->vm86_saved_regs.esi = env->regs[R_ESI]; + ts->vm86_saved_regs.edi = env->regs[R_EDI]; + ts->vm86_saved_regs.ebp = env->regs[R_EBP]; + ts->vm86_saved_regs.esp = env->regs[R_ESP]; + ts->vm86_saved_regs.eflags = env->eflags; + ts->vm86_saved_regs.eip = env->eip; + ts->vm86_saved_regs.cs = env->segs[R_CS]; + ts->vm86_saved_regs.ss = env->segs[R_SS]; + ts->vm86_saved_regs.ds = env->segs[R_DS]; + ts->vm86_saved_regs.es = env->segs[R_ES]; + ts->vm86_saved_regs.fs = env->segs[R_FS]; + ts->vm86_saved_regs.gs = env->segs[R_GS]; + + /* build vm86 CPU state */ + ts->v86flags = tswap32(target_v86->regs.eflags); + env->eflags = (env->eflags & ~SAFE_MASK) | + (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; + ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; + + env->regs[R_EBX] = tswap32(target_v86->regs.ebx); + env->regs[R_ECX] = tswap32(target_v86->regs.ecx); + env->regs[R_EDX] = tswap32(target_v86->regs.edx); + env->regs[R_ESI] = tswap32(target_v86->regs.esi); + env->regs[R_EDI] = tswap32(target_v86->regs.edi); + env->regs[R_EBP] = tswap32(target_v86->regs.ebp); + env->regs[R_ESP] = tswap32(target_v86->regs.esp); + env->eip = tswap32(target_v86->regs.eip); + cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs)); + cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss)); + cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds)); + cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es)); + cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs)); + cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); + ret = tswap32(target_v86->regs.eax); /* eax will be restored at + the end of the syscall */ +#ifdef DEBUG_VM86 + fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS], env->eip); +#endif + /* now the virtual CPU is ready for vm86 execution ! */ + out: + return ret; +} + -- cgit v1.2.3 From e84be9dbcac84b6550c93167ac72fed984dce8ff Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 12:37:12 +0000 Subject: added vm86.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@137 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 49f26fcf6..c640bf8eb 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o signal.o path.o +OBJS= elfload.o main.o syscall.o signal.o vm86.o path.o SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a -- cgit v1.2.3 From f351077efb1febb4c32dc92acc680a26037dc5f2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 12:37:32 +0000 Subject: added dump function git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@138 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpu-i386.h b/cpu-i386.h index 1ec719377..dae88fba6 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -426,6 +426,11 @@ struct siginfo; int cpu_x86_signal_handler(int host_signum, struct siginfo *info, void *puc); +/* used to debug */ +#define X86_DUMP_FPU 0x0001 /* dump FPU state too */ +#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ +void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); + /* internal functions */ #define GEN_FLAG_CODE32_SHIFT 0 -- cgit v1.2.3 From 0221cfcd719f7f37566048e2a90cdfa5c3136148 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 12:38:16 +0000 Subject: more console ioctls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@139 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ioctls.h | 6 +++++- linux-user/syscall_defs.h | 4 ++++ linux-user/syscall_types.h | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 68f248d63..dc1a37805 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -51,7 +51,11 @@ IOCTL(TIOCMIWAIT, 0, TYPE_INT) IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct))) - IOCTL(KDGKBTYPE, IOC_W, MK_PTR(TYPE_CHAR)) + IOCTL(KIOCSOUND, 0, TYPE_INT) + IOCTL(KDMKTONE, 0, TYPE_INT) + IOCTL(KDGKBTYPE, IOC_R, MK_PTR(TYPE_CHAR)) + IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry))) + IOCTL(KDGKBSENT, IOC_RW, TYPE_PTRVOID) IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT)) IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT)) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 4dbc66333..bad9bd848 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -213,7 +213,11 @@ struct target_pollfd { }; /* virtual terminal ioctls */ +#define TARGET_KIOCSOUND 0x4B2F /* start sound generation (0 for off) */ +#define TARGET_KDMKTONE 0x4B30 /* generate tone */ #define TARGET_KDGKBTYPE 0x4b33 +#define TARGET_KDGKBENT 0x4B46 /* gets one entry in translation table */ +#define TARGET_KDGKBSENT 0x4B48 /* gets one function key string entry */ /* Networking ioctls */ #define TARGET_SIOCADDRT 0x890B /* add routing table entry */ diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index e9ec14816..093a12207 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -64,3 +64,6 @@ STRUCT(hd_geometry, STRUCT(dirent, TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256)) + +STRUCT(kbentry, + TYPE_CHAR, TYPE_CHAR, TYPE_SHORT) -- cgit v1.2.3 From 3acace1333d6b75628fe6e6786ad3cd2db766f0e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 12:39:11 +0000 Subject: removed unnecessary VME support - fixed selector GPF exception git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@140 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/op-i386.c b/op-i386.c index 10dfd8472..fe1f7eb9d 100644 --- a/op-i386.c +++ b/op-i386.c @@ -654,8 +654,8 @@ void OPPROTO op_sti(void) env->eflags |= IF_MASK; } +#if 0 /* vm86plus instructions */ - void OPPROTO op_cli_vm(void) { env->eflags &= ~VIF_MASK; @@ -670,6 +670,7 @@ void OPPROTO op_sti_vm(void) } FORCE_RET(); } +#endif void OPPROTO op_boundw(void) { @@ -939,7 +940,7 @@ void helper_cpuid(void) EAX = 0x52b; EBX = 0; ECX = 0; - EDX = CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | + EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CX8; } @@ -1091,7 +1092,6 @@ void load_seg(int seg_reg, int selector) uint32_t e1, e2; uint8_t *ptr; - env->segs[seg_reg] = selector; sc = &env->seg_cache[seg_reg]; if (env->eflags & VM_MASK) { sc->base = (void *)(selector << 4); @@ -1118,6 +1118,7 @@ void load_seg(int seg_reg, int selector) selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); #endif } + env->segs[seg_reg] = selector; } void OPPROTO op_movl_seg_T0(void) @@ -1317,7 +1318,8 @@ void OPPROTO op_movw_eflags_T0(void) env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16); } -/* vm86 version */ +#if 0 +/* vm86plus version */ void OPPROTO op_movw_eflags_T0_vm(void) { int eflags; @@ -1355,6 +1357,7 @@ void OPPROTO op_movl_eflags_T0_vm(void) } FORCE_RET(); } +#endif /* XXX: compute only O flag */ void OPPROTO op_movb_eflags_T0(void) @@ -1373,7 +1376,8 @@ void OPPROTO op_movl_T0_eflags(void) T0 = eflags; } -/* vm86 version */ +/* vm86plus version */ +#if 0 void OPPROTO op_movl_T0_eflags_vm(void) { int eflags; @@ -1384,6 +1388,7 @@ void OPPROTO op_movl_T0_eflags_vm(void) eflags |= IF_MASK; T0 = eflags; } +#endif void OPPROTO op_cld(void) { -- cgit v1.2.3 From 148dfc2a8be0b237ef80b4d421f549464aa6a3d0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 13:09:33 +0000 Subject: fixed GPF generation - fixed 'lret im' instruction (main fix for dosemu) - fixed HLT instruction git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@141 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 207 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 150 insertions(+), 57 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index 8ddf14e72..ba36bedf9 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -2771,6 +2771,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl > s->iopl || s->vm86) { /* NOTE: even for (E)CX = 0 the exception is raised */ gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2788,6 +2789,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl > s->iopl || s->vm86) { /* NOTE: even for (E)CX = 0 the exception is raised */ gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2807,6 +2809,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xe5: if (s->cpl > s->iopl || s->vm86) { gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2822,6 +2825,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xe7: if (s->cpl > s->iopl || s->vm86) { gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2837,6 +2841,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xed: if (s->cpl > s->iopl || s->vm86) { gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2851,6 +2856,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xef: if (s->cpl > s->iopl || s->vm86) { gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2901,9 +2907,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_pop_update(s); /* add stack offset */ if (s->ss32) - gen_op_addl_ESP_im(val + (2 << s->dflag)); + gen_op_addl_ESP_im(val); else - gen_op_addw_ESP_im(val + (2 << s->dflag)); + gen_op_addw_ESP_im(val); s->is_jmp = 1; break; case 0xcb: /* lret */ @@ -2921,32 +2927,31 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->is_jmp = 1; break; case 0xcf: /* iret */ - /* XXX: not restartable */ - /* pop offset */ - gen_pop_T0(s); - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); - gen_pop_update(s); - /* pop selector */ - gen_pop_T0(s); - gen_movl_seg_T0(s, R_CS); - gen_pop_update(s); - /* pop eflags */ - gen_pop_T0(s); - if (s->dflag) { - if (s->vm86) - gen_op_movl_eflags_T0_vm(pc_start - s->cs_base); - else - gen_op_movl_eflags_T0(); + if (s->vm86 && s->iopl != 3) { + gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; } else { - if (s->vm86) - gen_op_movw_eflags_T0_vm(pc_start - s->cs_base); - else + /* XXX: not restartable */ + /* pop offset */ + gen_pop_T0(s); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_pop_update(s); + /* pop selector */ + gen_pop_T0(s); + gen_movl_seg_T0(s, R_CS); + gen_pop_update(s); + /* pop eflags */ + gen_pop_T0(s); + if (s->dflag) { + gen_op_movl_eflags_T0(); + } else { gen_op_movw_eflags_T0(); + } + gen_pop_update(s); + s->cc_op = CC_OP_EFLAGS; } - gen_pop_update(s); - s->cc_op = CC_OP_EFLAGS; s->is_jmp = 1; break; case 0xe8: /* call im */ @@ -3060,29 +3065,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* flags */ case 0x9c: /* pushf */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - if (s->vm86) - gen_op_movl_T0_eflags_vm(); - else + if (s->vm86 && s->iopl != 3) { + gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_movl_T0_eflags(); - gen_push_T0(s); + gen_push_T0(s); + } break; case 0x9d: /* popf */ - gen_pop_T0(s); - if (s->dflag) { - if (s->vm86) - gen_op_movl_eflags_T0_vm(pc_start - s->cs_base); - else - gen_op_movl_eflags_T0(); + if (s->vm86 && s->iopl != 3) { + gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; } else { - if (s->vm86) - gen_op_movw_eflags_T0_vm(pc_start - s->cs_base); - else + gen_pop_T0(s); + if (s->dflag) { + gen_op_movl_eflags_T0(); + } else { gen_op_movw_eflags_T0(); + } + gen_pop_update(s); + s->cc_op = CC_OP_EFLAGS; } - gen_pop_update(s); - s->cc_op = CC_OP_EFLAGS; break; case 0x9e: /* sahf */ gen_op_mov_TN_reg[OT_BYTE][0][R_AH](); @@ -3257,28 +3263,36 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xfa: /* cli */ if (!s->vm86) { - if (s->cpl <= s->iopl) + if (s->cpl <= s->iopl) { gen_op_cli(); - else + } else { gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; + } } else { - if (s->iopl == 3) + if (s->iopl == 3) { gen_op_cli(); - else - gen_op_cli_vm(); + } else { + gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; + } } break; case 0xfb: /* sti */ if (!s->vm86) { - if (s->cpl <= s->iopl) + if (s->cpl <= s->iopl) { gen_op_sti(); - else + } else { gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; + } } else { - if (s->iopl == 3) + if (s->iopl == 3) { gen_op_sti(); - else - gen_op_sti_vm(pc_start - s->cs_base); + } else { + gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; + } } break; case 0x62: /* bound */ @@ -3328,11 +3342,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_cpuid(); break; case 0xf4: /* hlt */ - if (s->cpl == 0) { - /* ignored */ - } else { - gen_op_gpf(pc_start - s->cs_base); - } + /* XXX: if cpl == 0, then should do something else */ + gen_op_gpf(pc_start - s->cs_base); + s->is_jmp = 1; break; default: goto illegal_op; @@ -3817,3 +3829,84 @@ void cpu_x86_close(CPUX86State *env) { free(env); } + +static const char *cc_op_str[] = { + "DYNAMIC", + "EFLAGS", + "MUL", + "ADDB", + "ADDW", + "ADDL", + "ADCB", + "ADCW", + "ADCL", + "SUBB", + "SUBW", + "SUBL", + "SBBB", + "SBBW", + "SBBL", + "LOGICB", + "LOGICW", + "LOGICL", + "INCB", + "INCW", + "INCL", + "DECB", + "DECW", + "DECL", + "SHLB", + "SHLW", + "SHLL", + "SARB", + "SARW", + "SARL", +}; + +void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) +{ + int eflags; + char cc_op_name[32]; + + eflags = env->eflags; + fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", + env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], + env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], + env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-'); + fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", + env->segs[R_CS], + env->segs[R_SS], + env->segs[R_DS], + env->segs[R_ES], + env->segs[R_FS], + env->segs[R_GS]); + if (flags & X86_DUMP_CCOP) { + if ((unsigned)env->cc_op < CC_OP_NB) + strcpy(cc_op_name, cc_op_str[env->cc_op]); + else + snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); + fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", + env->cc_src, env->cc_dst, cc_op_name); + } + if (flags & X86_DUMP_FPU) { + fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", + (double)env->fpregs[0], + (double)env->fpregs[1], + (double)env->fpregs[2], + (double)env->fpregs[3]); + fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", + (double)env->fpregs[4], + (double)env->fpregs[5], + (double)env->fpregs[7], + (double)env->fpregs[8]); + } +} -- cgit v1.2.3 From 9d27abd94fe2c48281a77112d58422b392a80f7b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 13:13:54 +0000 Subject: fixed invalid CPL logic in vm86 mode - use generic CPU dump state function git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@142 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 96 +++++++++++++++---------------------------------------------- 1 file changed, 23 insertions(+), 73 deletions(-) diff --git a/exec-i386.c b/exec-i386.c index ec738faad..10a10d7e6 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -188,74 +188,6 @@ void raise_exception(int exception_index) raise_exception_err(exception_index, 0); } -#if defined(DEBUG_EXEC) -static const char *cc_op_str[] = { - "DYNAMIC", - "EFLAGS", - "MUL", - "ADDB", - "ADDW", - "ADDL", - "ADCB", - "ADCW", - "ADCL", - "SUBB", - "SUBW", - "SUBL", - "SBBB", - "SBBW", - "SBBL", - "LOGICB", - "LOGICW", - "LOGICL", - "INCB", - "INCW", - "INCL", - "DECB", - "DECW", - "DECL", - "SHLB", - "SHLW", - "SHLL", - "SARB", - "SARW", - "SARL", -}; - -static void cpu_x86_dump_state(FILE *f) -{ - int eflags; - char cc_op_name[32]; - eflags = cc_table[CC_OP].compute_all(); - eflags |= (DF & DF_MASK); - if ((unsigned)env->cc_op < CC_OP_NB) - strcpy(cc_op_name, cc_op_str[env->cc_op]); - else - snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); - fprintf(f, - "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" - "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n" - "EIP=%08x\n", - env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], - env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], - env->cc_src, env->cc_dst, cc_op_name, - eflags & DF_MASK ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-', - env->eip); -#if 1 - fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", - (double)ST0, (double)ST1, (double)ST(2), (double)ST(3)); -#endif -} - -#endif - void cpu_x86_tblocks_init(void) { if (!code_gen_ptr) { @@ -399,7 +331,7 @@ int cpu_x86_exec(CPUX86State *env1) CC_OP = CC_OP_EFLAGS; env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); env->interrupt_request = 0; - + /* prepare setjmp context for exception handling */ if (setjmp(env->jmp_env) == 0) { for(;;) { @@ -408,7 +340,19 @@ int cpu_x86_exec(CPUX86State *env1) } #ifdef DEBUG_EXEC if (loglevel) { - cpu_x86_dump_state(logfile); + /* XXX: save all volatile state in cpu state */ + /* restore flags in standard format */ + env->regs[R_EAX] = EAX; + env->regs[R_EBX] = EBX; + env->regs[R_ECX] = ECX; + env->regs[R_EDX] = EDX; + env->regs[R_ESI] = ESI; + env->regs[R_EDI] = EDI; + env->regs[R_EBP] = EBP; + env->regs[R_ESP] = ESP; + env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); + cpu_x86_dump_state(env, logfile, 0); + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); } #endif /* we compute the CPU state. We assume it will not @@ -419,9 +363,14 @@ int cpu_x86_exec(CPUX86State *env1) (unsigned long)env->seg_cache[R_ES].base | (unsigned long)env->seg_cache[R_SS].base) != 0) << GEN_FLAG_ADDSEG_SHIFT; - flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT); + if (!(env->eflags & VM_MASK)) { + flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT; + } else { + /* NOTE: a dummy CPL is kept */ + flags |= (1 << GEN_FLAG_VM_SHIFT); + flags |= (3 << GEN_FLAG_CPL_SHIFT); + } flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT); - flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT; cs_base = env->seg_cache[R_CS].base; pc = cs_base + env->eip; tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, @@ -449,12 +398,13 @@ int cpu_x86_exec(CPUX86State *env1) code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); cpu_unlock(); } +#ifdef DEBUG_EXEC if (loglevel) { fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", (long)tb->tc_ptr, (long)tb->pc, lookup_symbol((void *)tb->pc)); - fflush(logfile); } +#endif /* execute the generated code */ tc_ptr = tb->tc_ptr; gen_func = (void *)tc_ptr; -- cgit v1.2.3 From 631271d7164f8209c044988b6a02e1153391c4f9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 13:14:52 +0000 Subject: added vm86.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@143 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 12 ++++++++- linux-user/syscall.c | 72 ---------------------------------------------------- 2 files changed, 11 insertions(+), 73 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 300a18856..5613c3ed9 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -54,6 +54,8 @@ typedef struct TaskState { struct TaskState *next; struct target_vm86plus_struct *target_v86; struct vm86_saved_state vm86_saved_regs; + uint32_t v86flags; + uint32_t v86mask; int used; /* non zero if used */ uint8_t stack[0]; } __attribute__((aligned(16))) TaskState; @@ -73,9 +75,17 @@ void cpu_loop(CPUX86State *env); void process_pending_signals(void *cpu_env); void signal_init(void); int queue_signal(int sig, target_siginfo_t *info); -void save_v86_state(CPUX86State *env); void init_paths(const char *prefix); const char *path(const char *pathname); extern int loglevel; +extern FILE *logfile; + +/* vm86.c */ +void save_v86_state(CPUX86State *env); +void do_int(CPUX86State *env, int intno); +void handle_vm86_fault(CPUX86State *env); +int do_vm86(CPUX86State *env, long subfunction, + struct target_vm86plus_struct * target_v86); + #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3f6084d05..38e242b48 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1058,78 +1058,6 @@ int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount return ret; } -/* vm86 emulation */ - -#define SAFE_MASK (0xDD5) - -int do_vm86(CPUX86State *env, long subfunction, - struct target_vm86plus_struct * target_v86) -{ - TaskState *ts = env->opaque; - int ret; - - switch (subfunction) { - case TARGET_VM86_REQUEST_IRQ: - case TARGET_VM86_FREE_IRQ: - case TARGET_VM86_GET_IRQ_BITS: - case TARGET_VM86_GET_AND_RESET_IRQ: - gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction); - ret = -EINVAL; - goto out; - case TARGET_VM86_PLUS_INSTALL_CHECK: - /* NOTE: on old vm86 stuff this will return the error - from verify_area(), because the subfunction is - interpreted as (invalid) address to vm86_struct. - So the installation check works. - */ - ret = 0; - goto out; - } - - ts->target_v86 = target_v86; - /* save current CPU regs */ - ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ - ts->vm86_saved_regs.ebx = env->regs[R_EBX]; - ts->vm86_saved_regs.ecx = env->regs[R_ECX]; - ts->vm86_saved_regs.edx = env->regs[R_EDX]; - ts->vm86_saved_regs.esi = env->regs[R_ESI]; - ts->vm86_saved_regs.edi = env->regs[R_EDI]; - ts->vm86_saved_regs.ebp = env->regs[R_EBP]; - ts->vm86_saved_regs.esp = env->regs[R_ESP]; - ts->vm86_saved_regs.eflags = env->eflags; - ts->vm86_saved_regs.eip = env->eip; - ts->vm86_saved_regs.cs = env->segs[R_CS]; - ts->vm86_saved_regs.ss = env->segs[R_SS]; - ts->vm86_saved_regs.ds = env->segs[R_DS]; - ts->vm86_saved_regs.es = env->segs[R_ES]; - ts->vm86_saved_regs.fs = env->segs[R_FS]; - ts->vm86_saved_regs.gs = env->segs[R_GS]; - - /* build vm86 CPU state */ - env->eflags = (env->eflags & ~SAFE_MASK) | - (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; - - env->regs[R_EBX] = tswap32(target_v86->regs.ebx); - env->regs[R_ECX] = tswap32(target_v86->regs.ecx); - env->regs[R_EDX] = tswap32(target_v86->regs.edx); - env->regs[R_ESI] = tswap32(target_v86->regs.esi); - env->regs[R_EDI] = tswap32(target_v86->regs.edi); - env->regs[R_EBP] = tswap32(target_v86->regs.ebp); - env->regs[R_ESP] = tswap32(target_v86->regs.esp); - env->eip = tswap32(target_v86->regs.eip); - cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs)); - cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss)); - cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds)); - cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es)); - cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs)); - cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); - ret = tswap32(target_v86->regs.eax); /* eax will be restored at - the end of the syscall */ - /* now the virtual CPU is ready for vm86 execution ! */ - out: - return ret; -} - /* this stack is the equivalent of the kernel stack associated with a thread/process */ #define NEW_STACK_SIZE 8192 -- cgit v1.2.3 From cabb4d616d47300a65062eb07142738b1cd35563 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 15:07:00 +0000 Subject: TF flag support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@144 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 1 + exec-i386.c | 1 + 2 files changed, 2 insertions(+) diff --git a/cpu-i386.h b/cpu-i386.h index dae88fba6..e5bbf45a8 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -440,6 +440,7 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); #define GEN_FLAG_ST_SHIFT 4 #define GEN_FLAG_CPL_SHIFT 7 #define GEN_FLAG_IOPL_SHIFT 9 +#define GEN_FLAG_TF_SHIFT 11 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, diff --git a/exec-i386.c b/exec-i386.c index 10a10d7e6..5b9030505 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -371,6 +371,7 @@ int cpu_x86_exec(CPUX86State *env1) flags |= (3 << GEN_FLAG_CPL_SHIFT); } flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT); + flags |= (env->eflags & TF_MASK) << (GEN_FLAG_TF_SHIFT - 8); cs_base = env->seg_cache[R_CS].base; pc = cs_base + env->eip; tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, -- cgit v1.2.3 From c50c0c3fbf65ce7a1cf42a2ea8974a930be7b667 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 15:07:51 +0000 Subject: TF flag support - fixed eflags computation before exception git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@145 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 69 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index ba36bedf9..da58a052e 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -132,6 +132,7 @@ typedef struct DisasContext { int vm86; /* vm86 mode */ int cpl; int iopl; + int tf; /* TF cpu flag */ } DisasContext; /* i386 arith/logic operations */ @@ -1366,6 +1367,15 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_mov_reg_T1[ot][R_ESP](); } +static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_raise_exception(trapno); + s->is_jmp = 1; +} + /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr is set to true if the instruction sets the PC (last instruction of a basic block) */ @@ -2770,8 +2780,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x6d: if (s->cpl > s->iopl || s->vm86) { /* NOTE: even for (E)CX = 0 the exception is raised */ - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2788,8 +2797,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x6f: if (s->cpl > s->iopl || s->vm86) { /* NOTE: even for (E)CX = 0 the exception is raised */ - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2808,8 +2816,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xe4: case 0xe5: if (s->cpl > s->iopl || s->vm86) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2824,8 +2831,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xe6: case 0xe7: if (s->cpl > s->iopl || s->vm86) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2840,8 +2846,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xec: case 0xed: if (s->cpl > s->iopl || s->vm86) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2855,8 +2860,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xee: case 0xef: if (s->cpl > s->iopl || s->vm86) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2928,8 +2932,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xcf: /* iret */ if (s->vm86 && s->iopl != 3) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { /* XXX: not restartable */ /* pop offset */ @@ -3066,8 +3069,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* flags */ case 0x9c: /* pushf */ if (s->vm86 && s->iopl != 3) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); @@ -3077,8 +3079,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x9d: /* popf */ if (s->vm86 && s->iopl != 3) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_pop_T0(s); if (s->dflag) { @@ -3248,11 +3249,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x90: /* nop */ break; case 0xcc: /* int3 */ - gen_op_int3((long)pc_start); - s->is_jmp = 1; + gen_exception(s, EXCP03_INT3, pc_start - s->cs_base); break; case 0xcd: /* int N */ val = ldub(s->pc++); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_int_im(val, pc_start - s->cs_base); s->is_jmp = 1; break; @@ -3266,15 +3268,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl <= s->iopl) { gen_op_cli(); } else { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { gen_op_cli(); } else { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } break; @@ -3283,15 +3283,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl <= s->iopl) { gen_op_sti(); } else { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { gen_op_sti(); } else { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } break; @@ -3343,8 +3341,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xf4: /* hlt */ /* XXX: if cpl == 0, then should do something else */ - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; default: goto illegal_op; @@ -3453,7 +3450,6 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, [INDEX_op_movl_T0_eflags] = CC_OSZAPC, - [INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC, [INDEX_op_cmc] = CC_C, [INDEX_op_salc] = CC_C, @@ -3504,9 +3500,7 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, [INDEX_op_movw_eflags_T0] = CC_OSZAPC, - [INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC, [INDEX_op_movl_eflags_T0] = CC_OSZAPC, - [INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC, [INDEX_op_clc] = CC_C, [INDEX_op_stc] = CC_C, [INDEX_op_cmc] = CC_C, @@ -3726,6 +3720,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3; + dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; @@ -3747,6 +3742,10 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, break; } pc_ptr = (void *)ret; + /* if single step mode, we generate only one instruction and + generate an exception */ + if (dc->tf) + break; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end); /* we must store the eflags state if it is not already done */ if (dc->cc_op != CC_OP_DYNAMIC) @@ -3755,6 +3754,10 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, /* we add an additionnal jmp to update the simulated PC */ gen_op_jmp_im(ret - (unsigned long)dc->cs_base); } + if (dc->tf) { + gen_op_raise_exception(EXCP01_SSTP); + } + *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS -- cgit v1.2.3 From 564c8f9978499a12fc8efd8d3c4af54060d1adcf Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 15:10:02 +0000 Subject: simplified exception support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@146 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 13 ++++--------- opc-i386.h | 8 +------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/op-i386.c b/op-i386.c index fe1f7eb9d..dac870035 100644 --- a/op-i386.c +++ b/op-i386.c @@ -622,10 +622,11 @@ void OPPROTO op_int_im(void) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); } -void OPPROTO op_int3(void) +void OPPROTO op_raise_exception(void) { - EIP = PARAM1; - raise_exception(EXCP03_INT3); + int exception_index; + exception_index = PARAM1; + raise_exception(exception_index); } void OPPROTO op_into(void) @@ -638,12 +639,6 @@ void OPPROTO op_into(void) FORCE_RET(); } -void OPPROTO op_gpf(void) -{ - EIP = PARAM1; - raise_exception(EXCP0D_GPF); -} - void OPPROTO op_cli(void) { env->eflags &= ~IF_MASK; diff --git a/opc-i386.h b/opc-i386.h index 2e48eb6eb..de54d9c1d 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -230,13 +230,10 @@ DEF(add_bitl_A0_T1, 0) DEF(jmp_T0, 0) DEF(jmp_im, 1) DEF(int_im, 2) -DEF(int3, 1) +DEF(raise_exception, 2) DEF(into, 0) -DEF(gpf, 1) DEF(cli, 0) DEF(sti, 0) -DEF(cli_vm, 0) -DEF(sti_vm, 1) DEF(boundw, 0) DEF(boundl, 0) DEF(cmpxchg8b, 0) @@ -557,11 +554,8 @@ DEF(xor_T0_1, 0) DEF(set_cc_op, 1) DEF(movl_eflags_T0, 0) DEF(movw_eflags_T0, 0) -DEF(movw_eflags_T0_vm, 1) -DEF(movl_eflags_T0_vm, 1) DEF(movb_eflags_T0, 0) DEF(movl_T0_eflags, 0) -DEF(movl_T0_eflags_vm, 0) DEF(cld, 0) DEF(std, 0) DEF(clc, 0) -- cgit v1.2.3 From 447db2139a6f6883183a7a750c5849145fd29899 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 15:10:36 +0000 Subject: sigtrap support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@147 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 21 +++++++++++++++++++-- linux-user/qemu.h | 2 +- linux-user/signal.c | 9 +++++++-- linux-user/vm86.c | 11 ++++++++++- syscall-i386.h | 6 ++++++ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index c9d0c9860..00dc27177 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -166,7 +166,7 @@ void cpu_loop(CPUX86State *env) break; case EXCP00_DIVZ: if (env->eflags & VM_MASK) { - do_int(env, trapnr); + handle_vm86_trap(env, trapnr); } else { /* division by zero */ info.si_signo = SIGFPE; @@ -176,10 +176,27 @@ void cpu_loop(CPUX86State *env) queue_signal(info.si_signo, &info); } break; + case EXCP01_SSTP: + case EXCP03_INT3: + if (env->eflags & VM_MASK) { + handle_vm86_trap(env, trapnr); + } else { + info.si_signo = SIGTRAP; + info.si_errno = 0; + if (trapnr == EXCP01_SSTP) { + info.si_code = TARGET_TRAP_BRKPT; + info._sifields._sigfault._addr = env->eip; + } else { + info.si_code = TARGET_SI_KERNEL; + info._sifields._sigfault._addr = 0; + } + queue_signal(info.si_signo, &info); + } + break; case EXCP04_INTO: case EXCP05_BOUND: if (env->eflags & VM_MASK) { - do_int(env, trapnr); + handle_vm86_trap(env, trapnr); } else { info.si_signo = SIGSEGV; info.si_errno = 0; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 5613c3ed9..0f004ffa5 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -83,7 +83,7 @@ extern FILE *logfile; /* vm86.c */ void save_v86_state(CPUX86State *env); -void do_int(CPUX86State *env, int intno); +void handle_vm86_trap(CPUX86State *env, int trapno); void handle_vm86_fault(CPUX86State *env); int do_vm86(CPUX86State *env, long subfunction, struct target_vm86plus_struct * target_v86); diff --git a/linux-user/signal.c b/linux-user/signal.c index 987307139..145dc2992 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -110,7 +110,8 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, tinfo->si_signo = sig; tinfo->si_errno = 0; tinfo->si_code = 0; - if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) { + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || + sig == SIGBUS || sig == SIGTRAP) { /* should never come here, but who knows. The information for the target is irrelevant */ tinfo->_sifields._sigfault._addr = 0; @@ -131,7 +132,8 @@ static void tswap_siginfo(target_siginfo_t *tinfo, tinfo->si_signo = tswap32(sig); tinfo->si_errno = tswap32(info->si_errno); tinfo->si_code = tswap32(info->si_code); - if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) { + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || + sig == SIGBUS || sig == SIGTRAP) { tinfo->_sifields._sigfault._addr = tswapl(info->_sifields._sigfault._addr); } else if (sig >= TARGET_SIGRTMIN) { @@ -788,6 +790,9 @@ long do_sigreturn(CPUX86State *env) sigset_t set; int eax, i; +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "do_sigreturn\n"); +#endif /* set blocked signals */ target_set.sig[0] = frame->sc.oldmask; for(i = 1; i < TARGET_NSIG_WORDS; i++) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 8316117e4..f243af877 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -178,7 +178,7 @@ static inline unsigned int get_vflags(CPUX86State *env) /* handle VM86 interrupt (NOTE: the CPU core currently does not support TSS interrupt revectoring, so this code is always executed) */ -void do_int(CPUX86State *env, int intno) +static void do_int(CPUX86State *env, int intno) { TaskState *ts = env->opaque; uint32_t *int_ptr, segoffs; @@ -225,6 +225,15 @@ void do_int(CPUX86State *env, int intno) return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); } +void handle_vm86_trap(CPUX86State *env, int trapno) +{ + if (trapno == 1 || trapno == 3) { + return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8)); + } else { + do_int(env, trapno); + } +} + #define CHECK_IF_IN_TRAP(disp) \ if ((tswap32(ts->target_v86->vm86plus.flags) & TARGET_vm86dbg_active) && \ (tswap32(ts->target_v86->vm86plus.flags) & TARGET_vm86dbg_TFpendig)) \ diff --git a/syscall-i386.h b/syscall-i386.h index 30e8bc3da..fbe86109e 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -480,6 +480,12 @@ typedef struct target_siginfo { #define TARGET_SEGV_MAPERR (1) /* address not mapped to object */ #define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */ +/* + * SIGTRAP si_codes + */ +#define TARGET_TRAP_BRKPT (1) /* process breakpoint */ +#define TARGET_TRAP_TRACE (2) /* process trace trap */ + /* default linux values for the selectors */ #define __USER_CS (0x23) #define __USER_DS (0x2B) -- cgit v1.2.3 From 2792c4f2afda061645ef122dc179f0d058a43484 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 21:35:30 +0000 Subject: added EIP return to INTO - fixed SHL C flag computation - added LAR/LSL git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@148 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/op-i386.c b/op-i386.c index dac870035..64cbe708a 100644 --- a/op-i386.c +++ b/op-i386.c @@ -634,6 +634,7 @@ void OPPROTO op_into(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_O) { + EIP = PARAM1; raise_exception(EXCP04_INTO); } FORCE_RET(); @@ -1136,6 +1137,66 @@ void OPPROTO op_addl_A0_seg(void) A0 += *(unsigned long *)((char *)env + PARAM1); } +void helper_lsl(void) +{ + unsigned int selector, limit; + SegmentDescriptorTable *dt; + int index; + uint32_t e1, e2; + uint8_t *ptr; + + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + selector = T0 & 0xffff; + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + return; + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & (1 << 23)) + limit = (limit << 12) | 0xfff; + T1 = limit; + CC_SRC |= CC_Z; +} + +void OPPROTO op_lsl(void) +{ + helper_lsl(); +} + +void helper_lar(void) +{ + unsigned int selector; + SegmentDescriptorTable *dt; + int index; + uint32_t e2; + uint8_t *ptr; + + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + selector = T0 & 0xffff; + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + return; + ptr = dt->base + index; + e2 = ldl(ptr + 4); + T1 = e2 & 0x00f0ff00; + CC_SRC |= CC_Z; +} + +void OPPROTO op_lar(void) +{ + helper_lar(); +} + /* flags handling */ /* slow jumps cases (compute x86 flags) */ @@ -1490,13 +1551,13 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, - [CC_OP_SHLB] = { compute_all_shlb, compute_c_shll }, - [CC_OP_SHLW] = { compute_all_shlw, compute_c_shll }, + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, + [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, - [CC_OP_SARB] = { compute_all_sarb, compute_c_shll }, - [CC_OP_SARW] = { compute_all_sarw, compute_c_shll }, - [CC_OP_SARL] = { compute_all_sarl, compute_c_shll }, + [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl }, + [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl }, + [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl }, }; /* floating point support. Some of the code for complicated x87 -- cgit v1.2.3 From 78c34e98cd8fad091f480e31c36c5c533d9f77eb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 21:37:05 +0000 Subject: added LAR/LSL - fixed INT3 and INTO EIP computation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@149 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index da58a052e..0dd376b81 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -3249,7 +3249,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x90: /* nop */ break; case 0xcc: /* int3 */ - gen_exception(s, EXCP03_INT3, pc_start - s->cs_base); + gen_exception(s, EXCP03_INT3, s->pc - s->cs_base); break; case 0xcd: /* int N */ val = ldub(s->pc++); @@ -3261,7 +3261,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xce: /* into */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_into(); + gen_op_into(s->pc - s->cs_base); break; case 0xfa: /* cli */ if (!s->vm86) { @@ -3343,6 +3343,24 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* XXX: if cpl == 0, then should do something else */ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; + case 0x102: /* lar */ + case 0x103: /* lsl */ + if (s->vm86) + goto illegal_op; + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_TN_reg[ot][1][reg](); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (b == 0x102) + gen_op_lar(); + else + gen_op_lsl(); + s->cc_op = CC_OP_EFLAGS; + gen_op_mov_reg_T1[ot][reg](); + break; default: goto illegal_op; } @@ -3579,6 +3597,8 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchg8b] = CC_Z, + [INDEX_op_lar] = CC_Z, + [INDEX_op_lsl] = CC_Z, }; /* simpler form of an operation if no flags need to be generated */ -- cgit v1.2.3 From 378180d8dc18b04af998cdff65a2c65975520a2f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 21:37:51 +0000 Subject: added LAR/LSL git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@150 c046a42c-6fe2-441c-8c8c-71466251a162 --- opc-i386.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/opc-i386.h b/opc-i386.h index de54d9c1d..6cfb42e88 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -230,7 +230,7 @@ DEF(add_bitl_A0_T1, 0) DEF(jmp_T0, 0) DEF(jmp_im, 1) DEF(int_im, 2) -DEF(raise_exception, 2) +DEF(raise_exception, 1) DEF(into, 0) DEF(cli, 0) DEF(sti, 0) @@ -534,6 +534,8 @@ DEF(movl_seg_T0, 1) DEF(movl_T0_seg, 1) DEF(movl_A0_seg, 1) DEF(addl_A0_seg, 1) +DEF(lsl, 0) +DEF(lar, 0) DEF(jo_cc, 2) DEF(jb_cc, 2) DEF(jz_cc, 2) -- cgit v1.2.3 From 72cc3881048edcb70912318ea9574baa4c7bf902 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 21:38:19 +0000 Subject: fixed SHL C flag computation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@151 c046a42c-6fe2-441c-8c8c-71466251a162 --- ops_template.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ops_template.h b/ops_template.h index 4cada782c..7adf7be6a 100644 --- a/ops_template.h +++ b/ops_template.h @@ -204,8 +204,13 @@ static int glue(compute_all_shl, SUFFIX)(void) return cf | pf | af | zf | sf | of; } -#if DATA_BITS == 32 static int glue(compute_c_shl, SUFFIX)(void) +{ + return (CC_SRC >> (DATA_BITS - 1)) & CC_C; +} + +#if DATA_BITS == 32 +static int glue(compute_c_sar, SUFFIX)(void) { return CC_SRC & 1; } -- cgit v1.2.3 From 288426fe3c50857752ca6e2d24d035a6ecc877d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 21:39:12 +0000 Subject: added LAR/LSL tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@152 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 2130bfcab..1b63a5b38 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -707,6 +707,19 @@ uint8_t seg_data2[4096]; #define MK_SEL(n) (((n) << 3) | 7) +#define TEST_LR(op, size, seg, mask)\ +{\ + int res, res2;\ + res = 0x12345678;\ + asm (op " %" size "2, %" size "0\n" \ + "movl $0, %1\n"\ + "jnz 1f\n"\ + "movl $1, %1\n"\ + "1:\n"\ + : "=r" (res), "=r" (res2) : "m" (seg), "0" (res));\ + printf(op ": Z=%d %08x\n", res2, res & ~(mask));\ +} + /* NOTE: we use Linux modify_ldt syscall */ void test_segs(void) { @@ -784,6 +797,16 @@ void test_segs(void) : "=r" (res), "=g" (res2) : "m" (segoff)); printf("FS:reg = %04x:%08x\n", res2, res); + + TEST_LR("larw", "w", MK_SEL(2), 0x0100); + TEST_LR("larl", "", MK_SEL(2), 0x0100); + TEST_LR("lslw", "w", MK_SEL(2), 0); + TEST_LR("lsll", "", MK_SEL(2), 0); + + TEST_LR("larw", "w", 0xfff8, 0); + TEST_LR("larl", "", 0xfff8, 0); + TEST_LR("lslw", "w", 0xfff8, 0); + TEST_LR("lsll", "", 0xfff8, 0); } /* 16 bit code test */ -- cgit v1.2.3 From b8bf3e3aacdd721f4ec0c125ff59bc32b8322e3b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 21:39:42 +0000 Subject: eflags fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@153 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/runcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runcom.c b/tests/runcom.c index 4c83de069..43deeca09 100644 --- a/tests/runcom.c +++ b/tests/runcom.c @@ -125,7 +125,7 @@ int main(int argc, char **argv) r->es = seg; r->fs = seg; r->gs = seg; - r->eflags = (IF_MASK | IOPL_MASK); + r->eflags = VIF_MASK; /* put return code */ set_bit((uint8_t *)&ctx.int_revectored, 0x21); -- cgit v1.2.3 From 226c91327d1eebf9a70b670830c181a46c6c454b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 21:41:47 +0000 Subject: fixed from 2.4.20 kernel git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@154 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/vm86.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index f243af877..d9b4ea63b 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -141,6 +141,11 @@ static inline void clear_TF(CPUX86State *env) env->eflags &= ~TF_MASK; } +static inline void clear_AC(CPUX86State *env) +{ + env->eflags &= ~AC_MASK; +} + static inline int set_vflags_long(unsigned long eflags, CPUX86State *env) { TaskState *ts = env->opaque; @@ -149,6 +154,8 @@ static inline int set_vflags_long(unsigned long eflags, CPUX86State *env) set_flags(env->eflags, eflags, SAFE_MASK); if (eflags & IF_MASK) return set_IF(env); + else + clear_IF(env); return 0; } @@ -160,6 +167,8 @@ static inline int set_vflags_short(unsigned short flags, CPUX86State *env) set_flags(env->eflags, flags, SAFE_MASK); if (flags & IF_MASK) return set_IF(env); + else + clear_IF(env); return 0; } @@ -217,6 +226,7 @@ static void do_int(CPUX86State *env, int intno) cpu_x86_load_seg(env, R_CS, segoffs >> 16); clear_TF(env); clear_IF(env); + clear_AC(env); return; cannot_handle: #if defined(DEBUG_VM86) -- cgit v1.2.3 From a993ba85cf50932cca8d697e2d45145fb21afafe Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 May 2003 12:25:45 +0000 Subject: alpha disas (Falk Hueffner) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@155 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 12 +- alpha-dis.c | 1976 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ disas.c | 2 + 3 files changed, 1987 insertions(+), 3 deletions(-) create mode 100644 alpha-dis.c diff --git a/Makefile b/Makefile index c640bf8eb..db25e8099 100644 --- a/Makefile +++ b/Makefile @@ -30,10 +30,11 @@ LDFLAGS+=-Wl,-T,s390.ld endif ifeq ($(ARCH),alpha) +# -msmall-data is not used because we want two-instruction relocations +# for the constant constructions +OP_CFLAGS=-Wall -O2 -g # Ensure there's only a single GP CFLAGS += -msmall-data -msmall-text -# FIXME Too lazy to deal with gprelhigh/gprellow for now, inhibit them -OP_CFLAGS=$(CFLAGS) -mno-explicit-relocs LDFLAGS+=-Wl,-T,alpha.ld endif @@ -63,7 +64,7 @@ OBJS+= libqemu.a LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o # NOTE: the disassembler code is only needed for debugging -LIBOBJS+=disas.o ppc-dis.o i386-dis.o dis-buf.o +LIBOBJS+=disas.o ppc-dis.o i386-dis.o alpha-dis.o dis-buf.o ifeq ($(ARCH),ia64) OBJS += ia64-syscall.o @@ -73,6 +74,11 @@ all: qemu qemu-doc.html qemu: $(OBJS) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) +ifeq ($(ARCH),alpha) +# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of +# the address space (31 bit so sign extending doesn't matter) + echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc +endif depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend diff --git a/alpha-dis.c b/alpha-dis.c new file mode 100644 index 000000000..ebda048e7 --- /dev/null +++ b/alpha-dis.c @@ -0,0 +1,1976 @@ +/* alpha-dis.c -- Disassemble Alpha AXP instructions + Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by Richard Henderson , + 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 +#include "dis-asm.h" + +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#define _(x) x + +/* 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 +}; + +bfd_vma +bfd_getl32 (addr) + register 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; +} + +/* 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; +} diff --git a/disas.c b/disas.c index d3dcdffd1..b62644886 100644 --- a/disas.c +++ b/disas.c @@ -33,6 +33,8 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type) print_insn = print_insn_i386; #elif defined(__powerpc__) print_insn = print_insn_ppc; +#elif defined(__alpha__) + print_insn = print_insn_alpha; #else fprintf(out, "Asm output not supported on this arch\n"); return; -- cgit v1.2.3 From 366c1b8bfa701705079ee2c7a786d76de37f4735 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 May 2003 12:27:02 +0000 Subject: warning fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@156 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/translate-i386.c b/translate-i386.c index 0dd376b81..ffdada7aa 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -3695,7 +3695,8 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) for(;;) { c = *opc_ptr++; n = op_nb_args[c]; - fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]); + fprintf(logfile, "0x%04x: %s", + (int)(opc_ptr - opc_buf - 1), op_str[c]); for(i = 0; i < n; i++) { fprintf(logfile, " 0x%x", opparam_ptr[i]); } -- cgit v1.2.3 From 74c95119f2bceb73c1695ffee08a934cddabe830 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 May 2003 12:27:31 +0000 Subject: Alpha fixes (Falk Hueffner) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@157 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++----------- exec-i386.h | 22 +++++++++++++++++++++- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/dyngen.c b/dyngen.c index 6d06c73fd..68a0c3c19 100644 --- a/dyngen.c +++ b/dyngen.c @@ -429,7 +429,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - if (!strstart(sym_name, "__op_param", &p)) { + if (*sym_name && !strstart(sym_name, "__op_param", &p)) { #if defined(HOST_SPARC) if (sym_name[0] == '.') { fprintf(outfile, @@ -561,15 +561,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { int type; - sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; - + type = ELF64_R_TYPE(rel->r_info); + sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; switch (type) { case R_ALPHA_GPDISP: - /* Instructions to set up the gp can be nopped, since we keep it current - all the time. FIXME assert that target is really gp */ - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = 0x2ffe0000; /* unop */\n", + /* The gp is just 32 bit, and never changes, so it's easiest to emit it + as an immediate instead of constructing it from the pv or ra. */ + fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n", rel->r_offset - offset); + fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n", + rel->r_offset - offset + rel->r_addend); break; case R_ALPHA_LITUSE: /* jsr to literal hint. Could be used to optimize to bsr. Ignore for @@ -580,10 +582,27 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, correct for in-function jumps. */ break; case R_ALPHA_LITERAL: - /* Load a literal from the GOT relative to the gp. Need to patch the - 16-bit immediate offset. */ - fprintf(outfile, " *(int16_t *)(gen_code_ptr + %d) = gp - (long)(&%s);\n", - rel->r_offset - offset, name); + /* Load a literal from the GOT relative to the gp. Since there's only a + single gp, nothing is to be done. */ + break; + case R_ALPHA_GPRELHIGH: + /* Handle fake relocations against __op_param symbol. Need to emit the + high part of the immediate value instead. Other symbols need no + special treatment. */ + if (strstart(sym_name, "__op_param", &p)) + fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n", + rel->r_offset - offset, p); + break; + case R_ALPHA_GPRELLOW: + if (strstart(sym_name, "__op_param", &p)) + fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n", + rel->r_offset - offset, p); + break; + case R_ALPHA_BRSGP: + /* PC-relative jump. Tweak offset to skip the two instructions that try to + set up the gp from the pv. */ + fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld) + 4);\n", + rel->r_offset - offset, sym_name, rel->r_offset - offset); break; default: error("unsupported Alpha relocation (%d)", type); @@ -886,7 +905,24 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) } else { /* generate big code generation switch */ #ifdef HOST_ALPHA - fprintf(outfile, "register long gp asm(\"%%$29\");\n"); +fprintf(outfile, +"register int gp asm(\"$29\");\n" +"static inline void immediate_ldah(void *p, int val) {\n" +" uint32_t *dest = p;\n" +" long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;\n" +"\n" +" *dest &= ~0xffff;\n" +" *dest |= high;\n" +" *dest |= 31 << 16;\n" +"}\n" +"static inline void immediate_lda(void *dest, int val) {\n" +" *(uint16_t *) dest = val;\n" +"}\n" +"void fix_bsr(void *p, int offset) {\n" +" uint32_t *dest = p;\n" +" *dest &= ~((1 << 21) - 1);\n" +" *dest |= (offset >> 2) & ((1 << 21) - 1);\n" +"}\n"); #endif fprintf(outfile, "int dyngen_code(uint8_t *gen_code_buf,\n" diff --git a/exec-i386.h b/exec-i386.h index 1fa86f414..fbeb98b79 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -105,7 +105,13 @@ register struct CPUX86State *env asm("r10"); register unsigned int T0 asm("$9"); register unsigned int T1 asm("$10"); register unsigned int A0 asm("$11"); -register struct CPUX86State *env asm("$12"); +register unsigned int EAX asm("$12"); +register unsigned int ESP asm("$13"); +register unsigned int EBP asm("$14"); +register struct CPUX86State *env asm("$15"); +#define reg_EAX +#define reg_ESP +#define reg_EBP #endif #ifdef __ia64__ register unsigned int T0 asm("r24"); @@ -165,10 +171,24 @@ register struct CPUX86State *env asm("r27"); #define FP_CONVERT (env->fp_convert) #endif +#ifdef __alpha__ +/* Suggested by Richard Henderson. This will result in code like + ldah $0,__op_param1($29) !gprelhigh + lda $0,__op_param1($0) !gprellow + We can then conveniently change $29 to $31 and adapt the offsets to + emit the appropriate constant. */ +extern int __op_param1 __attribute__((visibility("hidden"))); +extern int __op_param2 __attribute__((visibility("hidden"))); +extern int __op_param3 __attribute__((visibility("hidden"))); +#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; }) +#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; }) +#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; }) +#else extern int __op_param1, __op_param2, __op_param3; #define PARAM1 ((long)(&__op_param1)) #define PARAM2 ((long)(&__op_param2)) #define PARAM3 ((long)(&__op_param3)) +#endif #include "cpu-i386.h" -- cgit v1.2.3 From 54936004fddc52c321cb3f9a9a51140e782bed5d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 May 2003 00:25:15 +0000 Subject: mmap emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@158 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 +- cpu-i386.h | 25 ++++ exec.c | 148 +++++++++++++++++++++ linux-user/elfload.c | 134 ++++++++----------- linux-user/main.c | 29 +++- linux-user/mmap.c | 370 +++++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/qemu.h | 10 ++ linux-user/syscall.c | 26 ++-- translate-i386.c | 1 + 9 files changed, 646 insertions(+), 101 deletions(-) create mode 100644 exec.c create mode 100644 linux-user/mmap.c diff --git a/Makefile b/Makefile index db25e8099..c1b3d560d 100644 --- a/Makefile +++ b/Makefile @@ -58,11 +58,11 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o signal.o vm86.o path.o +OBJS= elfload.o main.o syscall.o mmap.o signal.o vm86.o path.o SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a -LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o +LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ppc-dis.o i386-dis.o alpha-dis.o dis-buf.o diff --git a/cpu-i386.h b/cpu-i386.h index e5bbf45a8..605825286 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -431,6 +431,30 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); +/* page related stuff */ +#define TARGET_PAGE_BITS 12 +#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) +#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1) +#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK) + +extern unsigned long real_host_page_size; +extern unsigned long host_page_bits; +extern unsigned long host_page_size; +extern unsigned long host_page_mask; + +#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask) + +/* same as PROT_xxx */ +#define PAGE_READ 0x0001 +#define PAGE_WRITE 0x0002 +#define PAGE_EXEC 0x0004 +#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) +#define PAGE_VALID 0x0008 + +void page_dump(FILE *f); +int page_get_flags(unsigned long address); +void page_set_flags(unsigned long start, unsigned long end, int flags); + /* internal functions */ #define GEN_FLAG_CODE32_SHIFT 0 @@ -446,5 +470,6 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, uint8_t *pc_start, uint8_t *cs_base, int flags); void cpu_x86_tblocks_init(void); +void page_init(void); #endif /* CPU_I386_H */ diff --git a/exec.c b/exec.c new file mode 100644 index 000000000..a917143d6 --- /dev/null +++ b/exec.c @@ -0,0 +1,148 @@ +/* + * virtual page mapping + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#include "cpu-i386.h" + +/* XXX: pack the flags in the low bits of the pointer ? */ +typedef struct PageDesc { + struct TranslationBlock *first_tb; + unsigned long flags; +} PageDesc; + +#define L2_BITS 10 +#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) + +#define L1_SIZE (1 << L1_BITS) +#define L2_SIZE (1 << L2_BITS) + +unsigned long real_host_page_size; +unsigned long host_page_bits; +unsigned long host_page_size; +unsigned long host_page_mask; + +static PageDesc *l1_map[L1_SIZE]; + +void page_init(void) +{ + /* NOTE: we can always suppose that host_page_size >= + TARGET_PAGE_SIZE */ + real_host_page_size = getpagesize(); + if (host_page_size == 0) + host_page_size = real_host_page_size; + if (host_page_size < TARGET_PAGE_SIZE) + host_page_size = TARGET_PAGE_SIZE; + host_page_bits = 0; + while ((1 << host_page_bits) < host_page_size) + host_page_bits++; + host_page_mask = ~(host_page_size - 1); +} + +/* dump memory mappings */ +void page_dump(FILE *f) +{ + unsigned long start, end; + int i, j, prot, prot1; + PageDesc *p; + + fprintf(f, "%-8s %-8s %-8s %s\n", + "start", "end", "size", "prot"); + start = -1; + end = -1; + prot = 0; + for(i = 0; i <= L1_SIZE; i++) { + if (i < L1_SIZE) + p = l1_map[i]; + else + p = NULL; + for(j = 0;j < L2_SIZE; j++) { + if (!p) + prot1 = 0; + else + prot1 = p[j].flags; + if (prot1 != prot) { + end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); + if (start != -1) { + fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", + start, end, end - start, + prot & PAGE_READ ? 'r' : '-', + prot & PAGE_WRITE ? 'w' : '-', + prot & PAGE_EXEC ? 'x' : '-'); + } + if (prot1 != 0) + start = end; + else + start = -1; + prot = prot1; + } + if (!p) + break; + } + } +} + + +static inline PageDesc *page_find_alloc(unsigned long address) +{ + unsigned int index; + PageDesc **lp, *p; + + index = address >> TARGET_PAGE_BITS; + lp = &l1_map[index >> L2_BITS]; + p = *lp; + if (!p) { + /* allocate if not found */ + p = malloc(sizeof(PageDesc) * L2_SIZE); + memset(p, 0, sizeof(sizeof(PageDesc) * L2_SIZE)); + *lp = p; + } + return p + (index & (L2_SIZE - 1)); +} + +int page_get_flags(unsigned long address) +{ + unsigned int index; + PageDesc *p; + + index = address >> TARGET_PAGE_BITS; + p = l1_map[index >> L2_BITS]; + if (!p) + return 0; + return p[index & (L2_SIZE - 1)].flags; +} + +void page_set_flags(unsigned long start, unsigned long end, int flags) +{ + PageDesc *p; + unsigned long addr; + + start = start & TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find_alloc(addr); + p->flags = flags; + } +} diff --git a/linux-user/elfload.c b/linux-user/elfload.c index edb3176bc..5186e5562 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -95,8 +95,6 @@ struct exec #define ZMAGIC 0413 #define QMAGIC 0314 -#define X86_STACK_TOP 0x7d000000 - /* max code+data+bss space allocated to elf interpreter */ #define INTERP_MAP_SIZE (32 * 1024 * 1024) @@ -123,23 +121,11 @@ struct exec #define PER_XENIX (0x0007 | STICKY_TIMEOUTS) /* Necessary parameters */ -#define ALPHA_PAGE_SIZE 4096 -#define X86_PAGE_SIZE 4096 - -#define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1)) -#define X86_PAGE_MASK (~(X86_PAGE_SIZE-1)) - -#define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK) -#define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK) - #define NGROUPS 32 -#define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE -#define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1)) -#define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1)) - -#define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1)) -#define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1)) +#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE +#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) #define INTERPRETER_NONE 0 #define INTERPRETER_AOUT 1 @@ -160,9 +146,6 @@ static inline void memcpy_tofs(void * to, const void * from, unsigned long n) memcpy(to, from, n); } -//extern void * mmap4k(); -#define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f) - extern unsigned long x86_stack_size; static int load_aout_interp(void * exptr, int interp_fd); @@ -227,8 +210,8 @@ static void * get_free_page(void) /* User-space version of kernel get_free_page. Returns a page-aligned * page-sized chunk of memory. */ - retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if((long)retval == -1) { perror("get_free_page"); @@ -241,7 +224,7 @@ static void * get_free_page(void) static void free_page(void * pageaddr) { - (void)munmap(pageaddr, ALPHA_PAGE_SIZE); + target_munmap((unsigned long)pageaddr, host_page_size); } /* @@ -272,9 +255,9 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, while (len) { --p; --tmp; --len; if (--offset < 0) { - offset = p % X86_PAGE_SIZE; - if (!(pag = (char *) page[p/X86_PAGE_SIZE]) && - !(pag = (char *) page[p/X86_PAGE_SIZE] = + offset = p % TARGET_PAGE_SIZE; + if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) && + !(pag = (char *) page[p/TARGET_PAGE_SIZE] = (unsigned long *) get_free_page())) { return 0; } @@ -390,21 +373,21 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, * it for args, we'll use it for something else... */ size = x86_stack_size; - if (size < MAX_ARG_PAGES*X86_PAGE_SIZE) - size = MAX_ARG_PAGES*X86_PAGE_SIZE; - error = (unsigned long)mmap4k(NULL, - size + X86_PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); + if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) + size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; + error = target_mmap(0, + size + host_page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); if (error == -1) { perror("stk mmap"); exit(-1); } /* we reserve one extra page at the top of the stack as guard */ - mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE); + target_mprotect(error + size, host_page_size, PROT_NONE); - stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE; + stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; p += stack_base; if (bprm->loader) { @@ -416,10 +399,10 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, if (bprm->page[i]) { info->rss++; - memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE); + memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE); free_page((void *)bprm->page[i]); } - stack_base += X86_PAGE_SIZE; + stack_base += TARGET_PAGE_SIZE; } return p; } @@ -427,13 +410,13 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, static void set_brk(unsigned long start, unsigned long end) { /* page-align the start and end addresses... */ - start = ALPHA_PAGE_ALIGN(start); - end = ALPHA_PAGE_ALIGN(end); + start = HOST_PAGE_ALIGN(start); + end = HOST_PAGE_ALIGN(end); if (end <= start) return; - if((long)mmap4k(start, end - start, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { + if(target_mmap(start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { perror("cannot mmap brk"); exit(-1); } @@ -451,9 +434,9 @@ static void padzero(unsigned long elf_bss) unsigned long nbyte; char * fpnt; - nbyte = elf_bss & (ALPHA_PAGE_SIZE-1); /* was X86_PAGE_SIZE - JRP */ + nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */ if (nbyte) { - nbyte = ALPHA_PAGE_SIZE - nbyte; + nbyte = host_page_size - nbyte; fpnt = (char *) elf_bss; do { *fpnt++ = 0; @@ -494,7 +477,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); - NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE)); + NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); @@ -554,7 +537,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, /* Now read in all of the header information */ - if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE) + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) return ~0UL; elf_phdata = (struct elf_phdr *) @@ -594,9 +577,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, if (interp_elf_ex->e_type == ET_DYN) { /* in order to avoid harcoding the interpreter load address in qemu, we allocate a big enough memory zone */ - error = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, - -1, 0); + error = target_mmap(0, INTERP_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); if (error == -1) { perror("mmap"); exit(-1); @@ -620,12 +603,12 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr; } - error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr), - eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr), + error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), + eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), elf_prot, elf_type, interpreter_fd, - eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr)); + eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); if (error > -1024UL) { /* Real error */ @@ -665,13 +648,13 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, * bss page. */ padzero(elf_bss); - elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */ + elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ if (last_bss > elf_bss) { - mmap4k(elf_bss, last_bss-elf_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + target_mmap(elf_bss, last_bss-elf_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); } free(elf_phdata); @@ -742,7 +725,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; - void * mapped_addr; + unsigned long mapped_addr; struct elf_phdr * elf_ppnt; struct elf_phdr *elf_phdata; unsigned long elf_bss, k, elf_brk; @@ -979,33 +962,32 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r is because the brk will follow the loader, and is not movable. */ /* NOTE: for qemu, we do a big mmap to get enough space without harcoding any address */ - error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, - -1, 0); + error = target_mmap(0, ET_DYN_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); if (error == -1) { perror("mmap"); exit(-1); } - load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr); + load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); } - error = (unsigned long)mmap4k( - X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), - (elf_ppnt->p_filesz + - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), - elf_prot, - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), - bprm->fd, - (elf_ppnt->p_offset - - X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), + bprm->fd, + (elf_ppnt->p_offset - + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); if (error == -1) { perror("mmap"); exit(-1); } #ifdef LOW_ELF_STACK - if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) - elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr); + if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); #endif if (!load_addr_set) { @@ -1013,7 +995,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; if (elf_ex.e_type == ET_DYN) { load_bias += error - - X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); + TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); load_addr += load_bias; } } @@ -1108,8 +1090,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ - mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, -1, 0); + mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, -1, 0); } #ifdef ELF_PLAT_INIT @@ -1137,7 +1119,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, int retval; int i; - bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); + bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); for (i=0 ; istart_brk); fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); @@ -331,7 +347,6 @@ int main(int argc, char **argv) syscall_init(); signal_init(); - env = cpu_x86_init(); global_env = env; /* build Task State */ diff --git a/linux-user/mmap.c b/linux-user/mmap.c new file mode 100644 index 000000000..4c4d9100d --- /dev/null +++ b/linux-user/mmap.c @@ -0,0 +1,370 @@ +/* + * mmap support for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +//#define DEBUG_MMAP + +/* NOTE: all the constants are the HOST ones */ +int target_mprotect(unsigned long start, unsigned long len, int prot) +{ + unsigned long end, host_start, host_end, addr; + int prot1, ret; + +#ifdef DEBUG_MMAP + printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); +#endif + + if ((start & ~TARGET_PAGE_MASK) != 0) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return -EINVAL; + if (len == 0) + return 0; + + host_start = start & host_page_mask; + host_end = HOST_PAGE_ALIGN(end); + if (start > host_start) { + /* handle host page containing start */ + prot1 = prot; + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS); + if (ret != 0) + return ret; + host_start += host_page_size; + } + if (end < host_end) { + /* handle host page containing end (can be the same as first page) */ + prot1 = prot; + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + ret = mprotect((void *)(host_end - host_page_size), host_page_size, + prot1 & PAGE_BITS); + if (ret != 0) + return ret; + host_end -= host_page_size; + } + + /* handle the pages in the middle */ + if (host_start < host_end) { + ret = mprotect((void *)host_start, host_end - host_start, prot); + if (ret != 0) + return ret; + } + + page_set_flags(start, start + len, prot | PAGE_VALID); + return 0; +} + +/* map an incomplete host page */ +int mmap_frag(unsigned long host_start, + unsigned long start, unsigned long end, + int prot, int flags, int fd, unsigned long offset) +{ + unsigned long host_end, ret, addr; + int prot1, prot_new; + + host_end = host_start + host_page_size; + + /* get the protection of the target pages outside the mapping */ + prot1 = 0; + for(addr = host_start; addr < host_end; addr++) { + if (addr < start || addr >= end) + prot1 |= page_get_flags(addr); + } + + if (prot1 == 0) { + /* no page was there, so we allocate one */ + ret = (long)mmap((void *)host_start, host_page_size, prot, + flags | MAP_ANONYMOUS, -1, 0); + if (ret == -1) + return ret; + } + prot1 &= PAGE_BITS; + + prot_new = prot | prot1; + if (!(flags & MAP_ANONYMOUS)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ + if ((flags & MAP_TYPE) == MAP_SHARED && + (prot & PROT_WRITE)) + return -EINVAL; + + /* adjust protection to be able to read */ + if (!(prot1 & PROT_WRITE)) + mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE); + + /* read the corresponding file data */ + pread(fd, (void *)start, end - start, offset); + + /* put final protection */ + if (prot_new != (prot1 | PROT_WRITE)) + mprotect((void *)host_start, host_page_size, prot_new); + } else { + /* just update the protection */ + if (prot_new != prot1) { + mprotect((void *)host_start, host_page_size, prot_new); + } + } + return 0; +} + +/* NOTE: all the constants are the HOST ones */ +long target_mmap(unsigned long start, unsigned long len, int prot, + int flags, int fd, unsigned long offset) +{ + unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; + +#ifdef DEBUG_MMAP + { + printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", + start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); + if (flags & MAP_FIXED) + printf("MAP_FIXED "); + if (flags & MAP_ANONYMOUS) + printf("MAP_ANON "); + switch(flags & MAP_TYPE) { + case MAP_PRIVATE: + printf("MAP_PRIVATE "); + break; + case MAP_SHARED: + printf("MAP_SHARED "); + break; + default: + printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); + break; + } + printf("fd=%d offset=%lx\n", fd, offset); + } +#endif + + if (offset & ~TARGET_PAGE_MASK) + return -EINVAL; + + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return start; + host_start = start & host_page_mask; + + if (!(flags & MAP_FIXED)) { + if (host_page_size != real_host_page_size) { + /* NOTE: this code is only for debugging with '-p' option */ + /* reserve a memory area */ + host_len = HOST_PAGE_ALIGN(len) + host_page_size - TARGET_PAGE_SIZE; + host_start = (long)mmap((void *)host_start, host_len, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (host_start == -1) + return host_start; + host_end = host_start + host_len; + start = HOST_PAGE_ALIGN(host_start); + end = start + HOST_PAGE_ALIGN(len); + if (start > host_start) + munmap((void *)host_start, start - host_start); + if (end < host_end) + munmap((void *)end, host_end - end); + /* use it as a fixed mapping */ + flags |= MAP_FIXED; + } else { + /* if not fixed, no need to do anything */ + host_offset = offset & host_page_mask; + host_len = len + offset - host_offset; + start = (long)mmap((void *)host_start, host_len, + prot, flags, fd, host_offset); + if (start == -1) + return start; + /* update start so that it points to the file position at 'offset' */ + if (!(flags & MAP_ANONYMOUS)) + start += offset - host_offset; + goto the_end1; + } + } + + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + end = start + len; + host_end = HOST_PAGE_ALIGN(end); + + /* worst case: we cannot map the file because the offset is not + aligned, so we read it */ + if (!(flags & MAP_ANONYMOUS) && + (offset & ~host_page_mask) != (start & ~host_page_mask)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ + if ((flags & MAP_TYPE) == MAP_SHARED && + (prot & PROT_WRITE)) + return -EINVAL; + retaddr = target_mmap(start, len, prot | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (retaddr == -1) + return retaddr; + pread(fd, (void *)start, len, offset); + if (!(prot & PROT_WRITE)) { + ret = target_mprotect(start, len, prot); + if (ret != 0) + return ret; + } + goto the_end; + } + + /* handle the start of the mapping */ + if (start > host_start) { + if (host_end == host_start + host_page_size) { + /* one single host page */ + ret = mmap_frag(host_start, start, end, + prot, flags, fd, offset); + if (ret == -1) + return ret; + goto the_end1; + } + ret = mmap_frag(host_start, start, host_start + host_page_size, + prot, flags, fd, offset); + if (ret == -1) + return ret; + host_start += host_page_size; + } + /* handle the end of the mapping */ + if (end < host_end) { + ret = mmap_frag(host_end - host_page_size, + host_end - host_page_size, host_end, + prot, flags, fd, + offset + host_end - host_page_size - start); + if (ret == -1) + return ret; + host_end -= host_page_size; + } + + /* map the middle (easier) */ + if (host_start < host_end) { + ret = (long)mmap((void *)host_start, host_end - host_start, + prot, flags, fd, offset + host_start - start); + if (ret == -1) + return ret; + } + the_end1: + page_set_flags(start, start + len, prot | PAGE_VALID); + the_end: +#ifdef DEBUG_MMAP + page_dump(stdout); + printf("\n"); +#endif + return start; +} + +int target_munmap(unsigned long start, unsigned long len) +{ + unsigned long end, host_start, host_end, addr; + int prot, ret; + +#ifdef DEBUG_MMAP + printf("munmap: start=0x%lx len=0x%lx\n", start, len); +#endif + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return -EINVAL; + end = start + len; + host_start = start & host_page_mask; + host_end = HOST_PAGE_ALIGN(end); + + if (start > host_start) { + /* handle host page containing start */ + prot = 0; + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (prot != 0) + host_start += host_page_size; + } + if (end < host_end) { + /* handle host page containing end (can be the same as first page) */ + prot = 0; + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (prot != 0) + host_end -= host_page_size; + } + + /* unmap what we can */ + if (host_start < host_end) { + ret = munmap((void *)host_start, host_end - host_start); + if (ret != 0) + return ret; + } + + page_set_flags(start, start + len, 0); + return 0; +} + +/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED + blocks which have been allocated starting on a host page */ +long target_mremap(unsigned long old_addr, unsigned long old_size, + unsigned long new_size, unsigned long flags, + unsigned long new_addr) +{ + int prot; + + /* XXX: use 5 args syscall */ + new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags); + if (new_addr == -1) + return new_addr; + prot = page_get_flags(old_addr); + page_set_flags(old_addr, old_addr + old_size, 0); + page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); + return new_addr; +} + +int target_msync(unsigned long start, unsigned long len, int flags) +{ + unsigned long end; + + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return 0; + end = start + len; + + start &= host_page_mask; + return msync((void *)start, len, flags); +} + diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 0f004ffa5..7e23f2791 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -88,4 +88,14 @@ void handle_vm86_fault(CPUX86State *env); int do_vm86(CPUX86State *env, long subfunction, struct target_vm86plus_struct * target_v86); +/* mmap.c */ +int target_mprotect(unsigned long start, unsigned long len, int prot); +long target_mmap(unsigned long start, unsigned long len, int prot, + int flags, int fd, unsigned long offset); +int target_munmap(unsigned long start, unsigned long len); +long target_mremap(unsigned long old_addr, unsigned long old_size, + unsigned long new_size, unsigned long flags, + unsigned long new_addr); +int target_msync(unsigned long start, unsigned long len, int flags); + #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 38e242b48..ac7a11192 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -64,11 +64,6 @@ //#define DEBUG -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#define PAGE_MASK ~(PAGE_SIZE - 1) -#endif - //#include #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) @@ -153,7 +148,7 @@ static long do_brk(char *new_brk) if (new_brk < target_original_brk) return -ENOMEM; - brk_page = (char *)(((unsigned long)target_brk + PAGE_SIZE - 1) & PAGE_MASK); + brk_page = (char *)HOST_PAGE_ALIGN((unsigned long)target_brk); /* If the new brk is less than this, set it and we're done... */ if (new_brk < brk_page) { @@ -162,11 +157,10 @@ static long do_brk(char *new_brk) } /* We need to allocate more memory after the brk... */ - new_alloc_size = ((new_brk - brk_page + 1)+(PAGE_SIZE-1)) & PAGE_MASK; - mapped_addr = get_errno((long)mmap((caddr_t)brk_page, new_alloc_size, - PROT_READ|PROT_WRITE, - MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); - + new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); + mapped_addr = get_errno(target_mmap((unsigned long)brk_page, new_alloc_size, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); if (is_error(mapped_addr)) { return mapped_addr; } else { @@ -1709,7 +1703,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, v4 = tswap32(vptr[3]); v5 = tswap32(vptr[4]); v6 = tswap32(vptr[5]); - ret = get_errno((long)mmap((void *)v1, v2, v3, v4, v5, v6)); + ret = get_errno(target_mmap(v1, v2, v3, v4, v5, v6)); } break; #endif @@ -1718,16 +1712,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #else case TARGET_NR_mmap: #endif - ret = get_errno((long)mmap((void *)arg1, arg2, arg3, arg4, arg5, arg6)); + ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5, arg6)); break; case TARGET_NR_munmap: - ret = get_errno(munmap((void *)arg1, arg2)); + ret = get_errno(target_munmap(arg1, arg2)); break; case TARGET_NR_mprotect: - ret = get_errno(mprotect((void *)arg1, arg2, arg3)); + ret = get_errno(target_mprotect(arg1, arg2, arg3)); break; case TARGET_NR_mremap: - ret = get_errno((long)mremap((void *)arg1, arg2, arg3, arg4)); + ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5)); break; case TARGET_NR_msync: ret = get_errno(msync((void *)arg1, arg2, arg3)); diff --git a/translate-i386.c b/translate-i386.c index ffdada7aa..0c171cf31 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -3845,6 +3845,7 @@ CPUX86State *cpu_x86_init(void) if (!inited) { inited = 1; optimize_flags_init(); + page_init(); } return env; } -- cgit v1.2.3 From 2a29ca73c9101ae46e85077178d3fcd1b38cfa0c Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 May 2003 00:29:04 +0000 Subject: more exception tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@159 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/testsig.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tests/testsig.c b/tests/testsig.c index 5f6d3705e..2eb2bfc4a 100644 --- a/tests/testsig.c +++ b/tests/testsig.c @@ -67,7 +67,7 @@ int tab[2]; int main(int argc, char **argv) { struct sigaction act; - int val; + volatile int val; act.sa_sigaction = sig_handler; sigemptyset(&act.sa_mask); @@ -75,6 +75,7 @@ int main(int argc, char **argv) sigaction(SIGFPE, &act, NULL); sigaction(SIGILL, &act, NULL); sigaction(SIGSEGV, &act, NULL); + sigaction(SIGTRAP, &act, NULL); /* test division by zero reporting */ if (setjmp(jmp_env) == 0) { @@ -112,6 +113,11 @@ int main(int argc, char **argv) asm volatile ("int $0xfd"); } + printf("INT3 exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("int3"); + } + printf("CLI exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("cli"); @@ -158,10 +164,20 @@ int main(int argc, char **argv) printf("HLT exception:\n"); if (setjmp(jmp_env) == 0) { - asm volatile ("hlt" : : "d" (0x4321), "D" (tab), "c" (1)); + asm volatile ("hlt"); } -#if 0 + printf("single step exception:\n"); + val = 0; + if (setjmp(jmp_env) == 0) { + asm volatile ("pushf\n" + "orl $0x00100, (%%esp)\n" + "popf\n" + "movl $0xabcd, %0\n" : "=m" (val) : : "cc", "memory"); + } + printf("val=0x%x\n", val); + +#if 1 { int i; act.sa_handler = alarm_handler; -- cgit v1.2.3 From d418c81eff3ca1b7cdb3c6d09b9b7ecc9becdd41 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 May 2003 00:57:50 +0000 Subject: fixed small page handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@160 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mmap.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 4c4d9100d..afbc16988 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -61,13 +61,18 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } + if (host_end == host_start + host_page_size) { + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + end = host_end; + } ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS); if (ret != 0) return ret; host_start += host_page_size; } if (end < host_end) { - /* handle host page containing end (can be the same as first page) */ prot1 = prot; for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); @@ -85,7 +90,6 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) if (ret != 0) return ret; } - page_set_flags(start, start + len, prot | PAGE_VALID); return 0; } @@ -311,11 +315,16 @@ int target_munmap(unsigned long start, unsigned long len) for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } + if (host_end == host_start + host_page_size) { + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + end = host_end; + } if (prot != 0) host_start += host_page_size; } if (end < host_end) { - /* handle host page containing end (can be the same as first page) */ prot = 0; for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); @@ -360,11 +369,13 @@ int target_msync(unsigned long start, unsigned long len, int flags) if (start & ~TARGET_PAGE_MASK) return -EINVAL; len = TARGET_PAGE_ALIGN(len); - if (len == 0) - return 0; end = start + len; + if (end < start) + return -EINVAL; + if (end == start) + return 0; start &= host_page_mask; - return msync((void *)start, len, flags); + return msync((void *)start, end - start, flags); } -- cgit v1.2.3 From ae2285314189c0ea32fc73d38c1e9b8051d213ab Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 May 2003 18:59:59 +0000 Subject: Sparc update (David S. Miller) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@161 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 12 ++++ configure | 14 ++++- dyngen.c | 200 ++++++++++++++++++++++++++++++++++++++---------------------- exec-i386.c | 15 +++++ exec-i386.h | 24 ++++++-- 5 files changed, 187 insertions(+), 78 deletions(-) diff --git a/Makefile b/Makefile index c1b3d560d..b1e92c5f8 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,18 @@ OP_CFLAGS=$(CFLAGS) LDFLAGS+=-Wl,-T,s390.ld endif +ifeq ($(ARCH),sparc) +CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +LDFLAGS+=-m32 +OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 +endif + +ifeq ($(ARCH),sparc64) +CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +LDFLAGS+=-m64 +OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 +endif + ifeq ($(ARCH),alpha) # -msmall-data is not used because we want two-instruction relocations # for the constant constructions diff --git a/configure b/configure index ea595533e..60256215b 100755 --- a/configure +++ b/configure @@ -47,6 +47,12 @@ case "$cpu" in s390) cpu="s390" ;; + sparc) + cpu="sparc" + ;; + sparc64) + cpu="sparc64" + ;; ia64) cpu="ia64" ;; @@ -131,7 +137,7 @@ fi else # if cross compiling, cannot launch a program, so make a static guess -if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then +if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64"; then bigendian="yes" fi @@ -217,6 +223,12 @@ elif test "$cpu" = "s390" ; then elif test "$cpu" = "alpha" ; then echo "ARCH=alpha" >> config.mak echo "#define HOST_ALPHA 1" >> $TMPH +elif test "$cpu" = "sparc" ; then + echo "ARCH=sparc" >> config.mak + echo "#define HOST_SPARC 1" >> $TMPH +elif test "$cpu" = "sparc64" ; then + echo "ARCH=sparc64" >> config.mak + echo "#define HOST_SPARC64 1" >> $TMPH elif test "$cpu" = "ia64" ; then echo "ARCH=ia64" >> config.mak echo "#define HOST_IA64 1" >> $TMPH diff --git a/dyngen.c b/dyngen.c index 68a0c3c19..f037d8759 100644 --- a/dyngen.c +++ b/dyngen.c @@ -274,14 +274,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { int copy_size = 0; uint8_t *p_start, *p_end; + host_ulong start_offset; int nb_args, i, n; uint8_t args_present[MAX_ARGS]; const char *sym_name, *p; ELF_RELOC *rel; - /* compute exact size excluding return instruction */ + /* Compute exact size excluding prologue and epilogue instructions. + * Increment start_offset to skip epilogue instructions, then compute + * copy_size the indicate the size of the remaining instructions (in + * bytes). + */ p_start = text + offset; p_end = p_start + size; + start_offset = offset; switch(ELF_ARCH) { case EM_386: { @@ -343,41 +349,63 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, case EM_SPARC: case EM_SPARC32PLUS: { + uint32_t start_insn, end_insn1, end_insn2, skip_insn; uint8_t *p; p = (void *)(p_end - 8); if (p <= p_start) error("empty code for %s", name); - if (get32((uint32_t *)(p_start + 0x0)) != 0x9de3bf98) - error("save %%sp,-104,%%sp expected at the start of %s " - "found [%08x]", - name, get32((uint32_t *)(p_start + 0x0))); - if (get32((uint32_t *)(p + 0x0)) != 0x81c7e008 || - get32((uint32_t *)(p + 0x4)) != 0x81e80000) - error("ret; restore; expected at the end of %s found [%08x:%08x]", - name, - get32((uint32_t *)(p + 0x0)), - get32((uint32_t *)(p + 0x4))); + start_insn = get32((uint32_t *)(p_start + 0x0)); + end_insn1 = get32((uint32_t *)(p + 0x0)); + end_insn2 = get32((uint32_t *)(p + 0x4)); + if ((start_insn & ~0x1fff) == 0x9de3a000) { + p_start += 0x4; + start_offset += 0x4; + if ((int)(start_insn | ~0x1fff) < -128) + error("Found bogus save at the start of %s", name); + if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + error("ret; restore; not found at end of %s", name); + } else { + error("No save at the beginning of %s", name); + } + + /* Skip a preceeding nop, if present. */ + if (p > p_start) { + skip_insn = get32((uint32_t *)(p - 0x4)); + if (skip_insn == 0x01000000) + p -= 4; + } copy_size = p - p_start; } break; case EM_SPARCV9: { + uint32_t start_insn, end_insn1, end_insn2, skip_insn; uint8_t *p; p = (void *)(p_end - 8); if (p <= p_start) error("empty code for %s", name); - if (get32((uint32_t *)(p_start + 0x0)) != 0x9de3bf40) - error("save %%sp,-192,%%sp expected at the start of %s " - "found [%08x]", - name, get32((uint32_t *)(p_start + 0x0))); - if (get32((uint32_t *)(p + 0x0)) != 0x81cfe008 || - get32((uint32_t *)(p + 0x4)) != 0x01000000) - error("rett %%i7+8; nop; expected at the end of %s " - "found [%08x:%08x]", - name, - get32((uint32_t *)(p + 0x0)), - get32((uint32_t *)(p + 0x4))); + start_insn = get32((uint32_t *)(p_start + 0x0)); + end_insn1 = get32((uint32_t *)(p + 0x0)); + end_insn2 = get32((uint32_t *)(p + 0x4)); + if ((start_insn & ~0x1fff) == 0x9de3a000) { + p_start += 0x4; + start_offset += 0x4; + if ((int)(start_insn | ~0x1fff) < -256) + error("Found bogus save at the start of %s", name); + if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + error("ret; restore; not found at end of %s", name); + } else { + error("No save at the beginning of %s", name); + } + + /* Skip a preceeding nop, if present. */ + if (p > p_start) { + skip_insn = get32((uint32_t *)(p - 0x4)); + if (skip_insn == 0x01000000) + p -= 4; + } + copy_size = p - p_start; } break; @@ -390,7 +418,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, args_present[i] = 0; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { n = strtoul(p, NULL, 10); @@ -427,7 +456,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, fprintf(outfile, " extern void %s();\n", name); for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (*sym_name && !strstart(sym_name, "__op_param", &p)) { #if defined(HOST_SPARC) @@ -443,7 +473,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } - fprintf(outfile, " memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size); + fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, start_offset - offset, copy_size); for(i = 0; i < nb_args; i++) { fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1); } @@ -455,7 +485,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int type; int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); @@ -467,11 +498,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case R_386_32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_386_PC32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", - rel->r_offset - offset, name, rel->r_offset - offset, addend); + rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); break; default: error("unsupported i386 relocation (%d)", type); @@ -485,7 +516,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int type; int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); @@ -497,24 +529,24 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case R_PPC_ADDR32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_PPC_ADDR16_LO: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_PPC_ADDR16_HI: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_PPC_ADDR16_HA: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_PPC_REL24: /* warning: must be at 32 MB distancy */ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", - rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend); + rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); break; default: error("unsupported powerpc relocation (%d)", type); @@ -528,7 +560,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int type; int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); @@ -540,15 +573,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case R_390_32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_390_16: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_390_8: fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; default: error("unsupported s390 relocation (%d)", type); @@ -559,7 +592,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #elif defined(HOST_ALPHA) { for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { int type; type = ELF64_R_TYPE(rel->r_info); @@ -569,9 +602,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* The gp is just 32 bit, and never changes, so it's easiest to emit it as an immediate instead of constructing it from the pv or ra. */ fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n", - rel->r_offset - offset); + rel->r_offset - start_offset); fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n", - rel->r_offset - offset + rel->r_addend); + rel->r_offset - start_offset + rel->r_addend); break; case R_ALPHA_LITUSE: /* jsr to literal hint. Could be used to optimize to bsr. Ignore for @@ -591,18 +624,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, special treatment. */ if (strstart(sym_name, "__op_param", &p)) fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n", - rel->r_offset - offset, p); + rel->r_offset - start_offset, p); break; case R_ALPHA_GPRELLOW: if (strstart(sym_name, "__op_param", &p)) fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n", - rel->r_offset - offset, p); + rel->r_offset - start_offset, p); break; case R_ALPHA_BRSGP: /* PC-relative jump. Tweak offset to skip the two instructions that try to set up the gp from the pv. */ fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld) + 4);\n", - rel->r_offset - offset, sym_name, rel->r_offset - offset); + rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset); break; default: error("unsupported Alpha relocation (%d)", type); @@ -616,7 +649,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int type; int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); @@ -642,7 +675,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int type; int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); @@ -660,16 +694,16 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case R_SPARC_32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_SPARC_HI22: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = " "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffff) " - " | ((%s + %d) & 0x3fffff);\n", - rel->r_offset - offset, - rel->r_offset - offset, + " | (((%s + %d) >> 10) & 0x3fffff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, name, addend); break; case R_SPARC_LO10: @@ -678,8 +712,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - rel->r_offset - offset, - rel->r_offset - offset, + rel->r_offset - start_offset, + rel->r_offset - start_offset, name, addend); break; case R_SPARC_WDISP30: @@ -687,11 +721,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " *(uint32_t *)(gen_code_ptr + %d) = " "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffffff) " - " | ((((%s + %d) - (long)gen_code_ptr)>>2) " + " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffffff);\n", - rel->r_offset - offset, - rel->r_offset - offset, - name, addend); + 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); @@ -705,7 +740,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int type; int addend; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); @@ -717,16 +753,16 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case R_SPARC_32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - offset, name, addend); + rel->r_offset - start_offset, name, addend); break; case R_SPARC_HI22: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = " "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffff) " - " | ((%s + %d) & 0x3fffff);\n", - rel->r_offset - offset, - rel->r_offset - offset, + " | (((%s + %d) >> 10) & 0x3fffff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, name, addend); break; case R_SPARC_LO10: @@ -735,8 +771,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - rel->r_offset - offset, - rel->r_offset - offset, + rel->r_offset - start_offset, + rel->r_offset - start_offset, name, addend); break; case R_SPARC_WDISP30: @@ -744,11 +780,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " *(uint32_t *)(gen_code_ptr + %d) = " "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffffff) " - " | ((((%s + %d) - (long)gen_code_ptr)>>2) " + " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffffff);\n", - rel->r_offset - offset, - rel->r_offset - offset, - name, addend); + rel->r_offset - start_offset, + rel->r_offset - start_offset, + name, addend, + rel->r_offset - start_offset); break; default: error("unsupported sparc64 relocation (%d)", type); @@ -933,7 +970,22 @@ fprintf(outfile, " const uint32_t *opparam_ptr;\n" " gen_code_ptr = gen_code_buf;\n" " opc_ptr = opc_buf;\n" -" opparam_ptr = opparam_buf;\n" +" opparam_ptr = opparam_buf;\n"); + + /* Generate prologue, if needed. */ + switch(ELF_ARCH) { + case EM_SPARC: + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n"); + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n"); + break; + + case EM_SPARCV9: + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n"); + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n"); + break; + }; + +fprintf(outfile, " for(;;) {\n" " switch(*opc_ptr++) {\n" ); @@ -961,7 +1013,7 @@ fprintf(outfile, " the_end:\n" ); -/* generate a return */ +/* generate epilogue */ switch(ELF_ARCH) { case EM_386: fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n"); @@ -980,11 +1032,13 @@ fprintf(outfile, break; case EM_SPARC: case EM_SPARC32PLUS: + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n"); + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n"); + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\n"); + break; case EM_SPARCV9: - /* Fill the delay slot. */ - fprintf(outfile, "*((uint32_t *)gen_code_ptr) = *((uint32_t *)gen_code_ptr - 1); /* delay slot */\n"); - fprintf(outfile, "*((uint32_t *)gen_code_ptr - 1) = 0x81c3e008; /* retl */\n"); - fprintf(outfile, "gen_code_ptr++;\n"); + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n"); + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n"); break; default: error("unknown ELF architecture"); diff --git a/exec-i386.c b/exec-i386.c index 5b9030505..8a20718e2 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -153,6 +153,13 @@ void raise_exception_err(int exception_index, int error_code) { /* NOTE: the register at this point must be saved by hand because longjmp restore them */ +#ifdef __sparc__ + /* We have to stay in the same register window as our caller, + * thus this trick. + */ + __asm__ __volatile__("restore\n\t" + "mov\t%o0, %i0"); +#endif #ifdef reg_EAX env->regs[R_EAX] = EAX; #endif @@ -409,7 +416,15 @@ int cpu_x86_exec(CPUX86State *env1) /* execute the generated code */ tc_ptr = tb->tc_ptr; gen_func = (void *)tc_ptr; +#ifdef __sparc__ + __asm__ __volatile__("call %0\n\t" + " mov %%o7,%%i0" + : /* no outputs */ + : "r" (gen_func) + : "i0", "i1", "i2", "i3", "i4", "i5"); +#else gen_func(); +#endif } } ret = env->exception_index; diff --git a/exec-i386.h b/exec-i386.h index fbeb98b79..322b7f3d1 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -89,11 +89,27 @@ register unsigned int A0 asm("s2"); register struct CPUX86State *env asm("s3"); #endif #ifdef __sparc__ -register unsigned int T0 asm("l0"); -register unsigned int T1 asm("l1"); -register unsigned int A0 asm("l2"); -register struct CPUX86State *env asm("l3"); +register unsigned int EAX asm("l0"); +register unsigned int ECX asm("l1"); +register unsigned int EDX asm("l2"); +register unsigned int EBX asm("l3"); +register unsigned int ESP asm("l4"); +register unsigned int EBP asm("l5"); +register unsigned int ESI asm("l6"); +register unsigned int EDI asm("l7"); +register unsigned int T0 asm("g1"); +register unsigned int T1 asm("g2"); +register unsigned int A0 asm("g3"); +register struct CPUX86State *env asm("g6"); #define USE_FP_CONVERT +#define reg_EAX +#define reg_ECX +#define reg_EDX +#define reg_EBX +#define reg_ESP +#define reg_EBP +#define reg_ESI +#define reg_EDI #endif #ifdef __s390__ register unsigned int T0 asm("r7"); -- cgit v1.2.3 From 727d01d4f6846708f0f32dcf9b086a2fba15bd8c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 18:58:05 +0000 Subject: return code size git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@162 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index 0c171cf31..086d74a4f 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -32,10 +32,6 @@ #define IN_OP_I386 #include "cpu-i386.h" -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - /* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; @@ -3721,10 +3717,19 @@ static uint16_t gen_opc_buf[OPC_BUF_SIZE]; static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; /* return non zero if the very first instruction is invalid so that - the virtual CPU can trigger an exception. */ + the virtual CPU can trigger an exception. + + '*code_size_ptr' contains the target code size including the + instruction which triggered an exception, except in case of invalid + illegal opcode. It must never exceed one target page. + + '*gen_code_size_ptr' contains the size of the generated code (host + code). +*/ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, - uint8_t *pc_start, uint8_t *cs_base, int flags) + uint8_t *pc_start, uint8_t *cs_base, int flags, + int *code_size_ptr) { DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; @@ -3767,7 +3772,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, generate an exception */ if (dc->tf) break; - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end); + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); /* we must store the eflags state if it is not already done */ if (dc->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(dc->cc_op); @@ -3810,7 +3816,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf); flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); *gen_code_size_ptr = gen_code_size; - + *code_size_ptr = pc_ptr - pc_start; #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); -- cgit v1.2.3 From fd6ce8f6604359e60283e6d4dfc935ca57c556e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 19:00:11 +0000 Subject: self-modifying code support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@163 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 82 ++++++++++++++-- exec-i386.c | 128 +++++-------------------- exec.c | 313 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 400 insertions(+), 123 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index 605825286..44411b0ca 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -445,16 +445,21 @@ extern unsigned long host_page_mask; #define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask) /* same as PROT_xxx */ -#define PAGE_READ 0x0001 -#define PAGE_WRITE 0x0002 -#define PAGE_EXEC 0x0004 -#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) -#define PAGE_VALID 0x0008 +#define PAGE_READ 0x0001 +#define PAGE_WRITE 0x0002 +#define PAGE_EXEC 0x0004 +#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) +#define PAGE_VALID 0x0008 +/* original state of the write flag (used when tracking self-modifying + code */ +#define PAGE_WRITE_ORG 0x0010 void page_dump(FILE *f); int page_get_flags(unsigned long address); void page_set_flags(unsigned long start, unsigned long end, int flags); +void page_unprotect_range(uint8_t *data, unsigned long data_size); +/***************************************************/ /* internal functions */ #define GEN_FLAG_CODE32_SHIFT 0 @@ -468,8 +473,73 @@ void page_set_flags(unsigned long start, unsigned long end, int flags); int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, - uint8_t *pc_start, uint8_t *cs_base, int flags); + uint8_t *pc_start, uint8_t *cs_base, int flags, + int *code_size_ptr); void cpu_x86_tblocks_init(void); void page_init(void); +int page_unprotect(unsigned long address); + +#define CODE_GEN_MAX_SIZE 65536 +#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ + +#define CODE_GEN_HASH_BITS 15 +#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) + +/* maximum total translate dcode allocated */ +#define CODE_GEN_BUFFER_SIZE (2048 * 1024) +//#define CODE_GEN_BUFFER_SIZE (128 * 1024) + +typedef struct TranslationBlock { + unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ + unsigned long cs_base; /* CS base for this block */ + unsigned int flags; /* flags defining in which context the code was generated */ + uint16_t size; /* size of target code for this block (1 <= + size <= TARGET_PAGE_SIZE) */ + uint8_t *tc_ptr; /* pointer to the translated code */ + struct TranslationBlock *hash_next; /* next matching block */ + struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */ +} TranslationBlock; + +static inline unsigned int tb_hash_func(unsigned long pc) +{ + return pc & (CODE_GEN_HASH_SIZE - 1); +} + +void tb_flush(void); +TranslationBlock *tb_alloc(unsigned long pc, + unsigned long size); + +extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; + +extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; +extern uint8_t *code_gen_ptr; + +/* find a translation block in the translation cache. If not found, + return NULL and the pointer to the last element of the list in pptb */ +static inline TranslationBlock *tb_find(TranslationBlock ***pptb, + unsigned long pc, + unsigned long cs_base, + unsigned int flags) +{ + TranslationBlock **ptb, *tb; + unsigned int h; + + h = tb_hash_func(pc); + ptb = &tb_hash[h]; + for(;;) { + tb = *ptb; + if (!tb) + break; + if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) + return tb; + ptb = &tb->hash_next; + } + *pptb = ptb; + return NULL; +} + +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif #endif /* CPU_I386_H */ diff --git a/exec-i386.c b/exec-i386.c index 8a20718e2..abc06b494 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -21,39 +21,10 @@ #include "disas.h" //#define DEBUG_EXEC -#define DEBUG_FLUSH //#define DEBUG_SIGNAL /* main execution loop */ -/* maximum total translate dcode allocated */ -#define CODE_GEN_BUFFER_SIZE (2048 * 1024) -//#define CODE_GEN_BUFFER_SIZE (128 * 1024) -#define CODE_GEN_MAX_SIZE 65536 -#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ - -/* threshold to flush the translated code buffer */ -#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) - -#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64) -#define CODE_GEN_HASH_BITS 15 -#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) - -typedef struct TranslationBlock { - unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ - unsigned long cs_base; /* CS base for this block */ - unsigned int flags; /* flags defining in which context the code was generated */ - uint8_t *tc_ptr; /* pointer to the translated code */ - struct TranslationBlock *hash_next; /* next matching block */ -} TranslationBlock; - -TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; -TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; -int nb_tbs; - -uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; -uint8_t *code_gen_ptr; - /* thread support */ #ifdef __powerpc__ @@ -195,70 +166,6 @@ void raise_exception(int exception_index) raise_exception_err(exception_index, 0); } -void cpu_x86_tblocks_init(void) -{ - if (!code_gen_ptr) { - code_gen_ptr = code_gen_buffer; - } -} - -/* flush all the translation blocks */ -static void tb_flush(void) -{ - int i; -#ifdef DEBUG_FLUSH - printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", - code_gen_ptr - code_gen_buffer, - nb_tbs, - (code_gen_ptr - code_gen_buffer) / nb_tbs); -#endif - nb_tbs = 0; - for(i = 0;i < CODE_GEN_HASH_SIZE; i++) - tb_hash[i] = NULL; - code_gen_ptr = code_gen_buffer; - /* XXX: flush processor icache at this point */ -} - -/* find a translation block in the translation cache. If not found, - return NULL and the pointer to the last element of the list in pptb */ -static inline TranslationBlock *tb_find(TranslationBlock ***pptb, - unsigned long pc, - unsigned long cs_base, - unsigned int flags) -{ - TranslationBlock **ptb, *tb; - unsigned int h; - - h = pc & (CODE_GEN_HASH_SIZE - 1); - ptb = &tb_hash[h]; -#if 0 - /* XXX: hack to handle 16 bit modyfing code */ - if (flags & (1 << GEN_FLAG_CODE32_SHIFT)) -#endif - for(;;) { - tb = *ptb; - if (!tb) - break; - if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) - return tb; - ptb = &tb->hash_next; - } - *pptb = ptb; - return NULL; -} - -/* allocate a new translation block. flush the translation buffer if - too many translation blocks or too much generated code */ -static inline TranslationBlock *tb_alloc(void) -{ - TranslationBlock *tb; - if (nb_tbs >= CODE_GEN_MAX_BLOCKS || - (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) - tb_flush(); - tb = &tbs[nb_tbs++]; - return tb; -} - int cpu_x86_exec(CPUX86State *env1) { int saved_T0, saved_T1, saved_A0; @@ -287,7 +194,7 @@ int cpu_x86_exec(CPUX86State *env1) #ifdef reg_EDI int saved_EDI; #endif - int code_gen_size, ret; + int code_gen_size, ret, code_size; void (*gen_func)(void); TranslationBlock *tb, **ptb; uint8_t *tc_ptr, *cs_base, *pc; @@ -390,15 +297,15 @@ int cpu_x86_exec(CPUX86State *env1) cpu_lock(); tc_ptr = code_gen_ptr; ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, - &code_gen_size, pc, cs_base, flags); + &code_gen_size, pc, cs_base, flags, + &code_size); /* if invalid instruction, signal it */ if (ret != 0) { cpu_unlock(); raise_exception(EXCP06_ILLOP); } - tb = tb_alloc(); + tb = tb_alloc((unsigned long)pc, code_size); *ptb = tb; - tb->pc = (unsigned long)pc; tb->cs_base = (unsigned long)cs_base; tb->flags = flags; tb->tc_ptr = tc_ptr; @@ -493,15 +400,22 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) #include /* 'pc' is the host PC at which the exception was raised. 'address' is - the effective address of the memory exception */ + the effective address of the memory exception. 'is_write' is 1 if a + write caused the exception and otherwise 0'. 'old_set' is the + signal set which should be restored */ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set) { -#ifdef DEBUG_SIGNAL - printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", - pc, *(unsigned long *)old_set); +#if defined(DEBUG_SIGNAL) + printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", + pc, address, is_write, *(unsigned long *)old_set); #endif + if (is_write && page_unprotect(address)) { + sigprocmask(SIG_SETMASK, old_set, NULL); + return 1; + } if (pc >= (unsigned long)code_gen_buffer && pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { /* the PC is inside the translated code. It means that we have @@ -512,8 +426,7 @@ static inline int handle_cpu_signal(unsigned long pc, /* XXX: need to compute virtual pc position by retranslating code. The rest of the CPU state should be correct. */ env->cr2 = address; - /* XXX: more precise exception code */ - raise_exception_err(EXCP0E_PAGE, 4); + raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); /* never comes here */ return 1; } else { @@ -531,11 +444,16 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, #ifndef REG_EIP /* for glibc 2.1 */ -#define REG_EIP EIP +#define REG_EIP EIP +#define REG_ERR ERR +#define REG_TRAPNO TRAPNO #endif pc = uc->uc_mcontext.gregs[REG_EIP]; pold_set = &uc->uc_sigmask; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, pold_set); + 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, + pold_set); #else #warning No CPU specific signal handler: cannot handle target SIGSEGV events return 0; diff --git a/exec.c b/exec.c index a917143d6..0ed49c695 100644 --- a/exec.c +++ b/exec.c @@ -1,5 +1,5 @@ /* - * virtual page mapping + * virtual page mapping and translated block handling * * Copyright (c) 2003 Fabrice Bellard * @@ -24,13 +24,32 @@ #include #include #include +#include #include "cpu-i386.h" +//#define DEBUG_TB_INVALIDATE +#define DEBUG_FLUSH + +/* make various TB consistency checks */ +//#define DEBUG_TB_CHECK + +/* threshold to flush the translated code buffer */ +#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) + +#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64) + +TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; +TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; +int nb_tbs; + +uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; +uint8_t *code_gen_ptr; + /* XXX: pack the flags in the low bits of the pointer ? */ typedef struct PageDesc { - struct TranslationBlock *first_tb; unsigned long flags; + TranslationBlock *first_tb; } PageDesc; #define L2_BITS 10 @@ -39,6 +58,8 @@ typedef struct PageDesc { #define L1_SIZE (1 << L1_BITS) #define L2_SIZE (1 << L2_BITS) +static void tb_invalidate_page(unsigned long address); + unsigned long real_host_page_size; unsigned long host_page_bits; unsigned long host_page_size; @@ -104,36 +125,44 @@ void page_dump(FILE *f) } } - -static inline PageDesc *page_find_alloc(unsigned long address) +static inline PageDesc *page_find_alloc(unsigned int index) { - unsigned int index; PageDesc **lp, *p; - index = address >> TARGET_PAGE_BITS; lp = &l1_map[index >> L2_BITS]; p = *lp; if (!p) { /* allocate if not found */ p = malloc(sizeof(PageDesc) * L2_SIZE); - memset(p, 0, sizeof(sizeof(PageDesc) * L2_SIZE)); + memset(p, 0, sizeof(PageDesc) * L2_SIZE); *lp = p; } return p + (index & (L2_SIZE - 1)); } -int page_get_flags(unsigned long address) +static inline PageDesc *page_find(unsigned int index) { - unsigned int index; PageDesc *p; - index = address >> TARGET_PAGE_BITS; p = l1_map[index >> L2_BITS]; if (!p) return 0; - return p[index & (L2_SIZE - 1)].flags; + return p + (index & (L2_SIZE - 1)); +} + +int page_get_flags(unsigned long address) +{ + PageDesc *p; + + p = page_find(address >> TARGET_PAGE_BITS); + if (!p) + return 0; + return p->flags; } +/* modify the flags of a page and invalidate the code if + necessary. The flag PAGE_WRITE_ORG is positionned automatically + depending on PAGE_WRITE */ void page_set_flags(unsigned long start, unsigned long end, int flags) { PageDesc *p; @@ -141,8 +170,268 @@ void page_set_flags(unsigned long start, unsigned long end, int flags) start = start & TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); + if (flags & PAGE_WRITE) + flags |= PAGE_WRITE_ORG; for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { - p = page_find_alloc(addr); + p = page_find_alloc(addr >> TARGET_PAGE_BITS); + /* if the write protection is set, then we invalidate the code + inside */ + if (!(p->flags & PAGE_WRITE) && + (flags & PAGE_WRITE) && + p->first_tb) { + tb_invalidate_page(addr); + } p->flags = flags; } } + +void cpu_x86_tblocks_init(void) +{ + if (!code_gen_ptr) { + code_gen_ptr = code_gen_buffer; + } +} + +/* set to NULL all the 'first_tb' fields in all PageDescs */ +static void page_flush_tb(void) +{ + int i, j; + PageDesc *p; + + for(i = 0; i < L1_SIZE; i++) { + p = l1_map[i]; + if (p) { + for(j = 0; j < L2_SIZE; j++) + p[j].first_tb = NULL; + } + } +} + +/* flush all the translation blocks */ +void tb_flush(void) +{ + int i; +#ifdef DEBUG_FLUSH + printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", + code_gen_ptr - code_gen_buffer, + nb_tbs, + (code_gen_ptr - code_gen_buffer) / nb_tbs); +#endif + nb_tbs = 0; + for(i = 0;i < CODE_GEN_HASH_SIZE; i++) + tb_hash[i] = NULL; + page_flush_tb(); + code_gen_ptr = code_gen_buffer; + /* XXX: flush processor icache at this point */ +} + +#ifdef DEBUG_TB_CHECK + +static void tb_invalidate_check(unsigned long address) +{ + TranslationBlock *tb; + int i; + address &= TARGET_PAGE_MASK; + for(i = 0;i < CODE_GEN_HASH_SIZE; i++) { + for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) { + if (!(address + TARGET_PAGE_SIZE <= tb->pc || + address >= tb->pc + tb->size)) { + printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n", + address, tb->pc, tb->size); + } + } + } +} + +/* verify that all the pages have correct rights for code */ +static void tb_page_check(void) +{ + TranslationBlock *tb; + int i, flags1, flags2; + + for(i = 0;i < CODE_GEN_HASH_SIZE; i++) { + for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) { + flags1 = page_get_flags(tb->pc); + flags2 = page_get_flags(tb->pc + tb->size - 1); + if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { + printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n", + tb->pc, tb->size, flags1, flags2); + } + } + } +} + +#endif + +/* invalidate one TB */ +static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb, + int next_offset) +{ + TranslationBlock *tb1; + for(;;) { + tb1 = *ptb; + if (tb1 == tb) { + *ptb = *(TranslationBlock **)((char *)tb1 + next_offset); + break; + } + ptb = (TranslationBlock **)((char *)tb1 + next_offset); + } +} + +static inline void tb_invalidate(TranslationBlock *tb, int parity) +{ + PageDesc *p; + unsigned int page_index1, page_index2; + unsigned int h; + + /* remove the TB from the hash list */ + h = tb_hash_func(tb->pc); + tb_remove(&tb_hash[h], tb, + offsetof(TranslationBlock, hash_next)); + /* remove the TB from the page list */ + page_index1 = tb->pc >> TARGET_PAGE_BITS; + if ((page_index1 & 1) == parity) { + p = page_find(page_index1); + tb_remove(&p->first_tb, tb, + offsetof(TranslationBlock, page_next[page_index1 & 1])); + } + page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS; + if ((page_index2 & 1) == parity) { + p = page_find(page_index2); + tb_remove(&p->first_tb, tb, + offsetof(TranslationBlock, page_next[page_index2 & 1])); + } +} + +/* invalidate all TBs which intersect with the target page starting at addr */ +static void tb_invalidate_page(unsigned long address) +{ + TranslationBlock *tb_next, *tb; + unsigned int page_index; + int parity1, parity2; + PageDesc *p; +#ifdef DEBUG_TB_INVALIDATE + printf("tb_invalidate_page: %lx\n", address); +#endif + + page_index = address >> TARGET_PAGE_BITS; + p = page_find(page_index); + if (!p) + return; + tb = p->first_tb; + parity1 = page_index & 1; + parity2 = parity1 ^ 1; + while (tb != NULL) { + tb_next = tb->page_next[parity1]; + tb_invalidate(tb, parity2); + tb = tb_next; + } + p->first_tb = NULL; +} + +/* add the tb in the target page and protect it if necessary */ +static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index) +{ + PageDesc *p; + unsigned long host_start, host_end, addr, page_addr; + int prot; + + p = page_find_alloc(page_index); + tb->page_next[page_index & 1] = p->first_tb; + p->first_tb = tb; + if (p->flags & PAGE_WRITE) { + /* force the host page as non writable (writes will have a + page fault + mprotect overhead) */ + page_addr = (page_index << TARGET_PAGE_BITS); + host_start = page_addr & host_page_mask; + host_end = host_start + host_page_size; + prot = 0; + for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) + prot |= page_get_flags(addr); + mprotect((void *)host_start, host_page_size, + (prot & PAGE_BITS) & ~PAGE_WRITE); +#ifdef DEBUG_TB_INVALIDATE + printf("protecting code page: 0x%08lx\n", + host_start); +#endif + p->flags &= ~PAGE_WRITE; +#ifdef DEBUG_TB_CHECK + tb_page_check(); +#endif + } +} + +/* Allocate a new translation block. Flush the translation buffer if + too many translation blocks or too much generated code. */ +TranslationBlock *tb_alloc(unsigned long pc, + unsigned long size) +{ + TranslationBlock *tb; + unsigned int page_index1, page_index2; + + if (nb_tbs >= CODE_GEN_MAX_BLOCKS || + (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) + tb_flush(); + tb = &tbs[nb_tbs++]; + tb->pc = pc; + tb->size = size; + + /* add in the page list */ + page_index1 = pc >> TARGET_PAGE_BITS; + tb_alloc_page(tb, page_index1); + page_index2 = (pc + size - 1) >> TARGET_PAGE_BITS; + if (page_index2 != page_index1) { + tb_alloc_page(tb, page_index2); + } + return tb; +} + +/* called from signal handler: invalidate the code and unprotect the + page. Return TRUE if the fault was succesfully handled. */ +int page_unprotect(unsigned long address) +{ + unsigned int page_index, prot; + PageDesc *p; + unsigned long host_start, host_end, addr; + + page_index = address >> TARGET_PAGE_BITS; + p = page_find(page_index); + if (!p) + return 0; + if ((p->flags & (PAGE_WRITE_ORG | PAGE_WRITE)) == PAGE_WRITE_ORG) { + /* if the page was really writable, then we change its + protection back to writable */ + host_start = address & host_page_mask; + host_end = host_start + host_page_size; + prot = 0; + for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) + prot |= page_get_flags(addr); + mprotect((void *)host_start, host_page_size, + (prot & PAGE_BITS) | PAGE_WRITE); + p->flags |= PAGE_WRITE; + + /* and since the content will be modified, we must invalidate + the corresponding translated code. */ + tb_invalidate_page(address); +#ifdef DEBUG_TB_CHECK + tb_invalidate_check(address); +#endif + return 1; + } else { + return 0; + } +} + +/* call this function when system calls directly modify a memory area */ +void page_unprotect_range(uint8_t *data, unsigned long data_size) +{ + unsigned long start, end, addr; + + start = (unsigned long)data; + end = start + data_size; + start &= TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + page_unprotect(addr); + } +} -- cgit v1.2.3 From 206f0fa7598242e3e3b742e72d4743e9ea4eefd0 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 19:01:56 +0000 Subject: pread/pwrite syscalls - use page_unprotect_range() in vital cases to avoid problems if the kernel writes data in protected page (needed for self-modifying code support) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@164 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ac7a11192..34599d0f0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1137,6 +1137,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = 0; /* avoid warning */ break; case TARGET_NR_read: + page_unprotect_range((void *)arg2, arg3); ret = get_errno(read(arg1, (void *)arg2, arg3)); break; case TARGET_NR_write: @@ -2191,9 +2192,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_prctl: goto unimplemented; case TARGET_NR_pread: - goto unimplemented; + page_unprotect_range((void *)arg2, arg3); + ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4)); + break; case TARGET_NR_pwrite: - goto unimplemented; + ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4)); + break; case TARGET_NR_chown: ret = get_errno(chown((const char *)arg1, arg2, arg3)); break; -- cgit v1.2.3 From 70e198602bb4b254e506a0ea68de4ff1de56a3bd Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 19:02:49 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@165 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 394b3e38e..0cfa8ff6d 100644 --- a/Changelog +++ b/Changelog @@ -7,9 +7,14 @@ version 0.2: - initial Alpha port (Falk Hueffner) - initial IA64 port (Matt Wilson) - initial Sparc and Sparc64 port (David S. Miller) - - better exception support for dosemu - added HLT instruction - - added GPF generation for I/Os + - 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 begins to work) version 0.1.6: -- cgit v1.2.3 From 76c8b7710baf447468d71dcad935af5ed0084ca8 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 19:48:46 +0000 Subject: file list update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@166 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 6 +++--- gen-i386.h | 0 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 gen-i386.h diff --git a/Makefile b/Makefile index b1e92c5f8..3aa42f19b 100644 --- a/Makefile +++ b/Makefile @@ -142,9 +142,9 @@ dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ Makefile elf.h thunk.c\ elfload.c main.c signal.c thunk.h\ cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ -dis-asm.h gen-i386.h syscall.c\ -dis-buf.c disas.c disas.h ppc-dis.c i386-dis.c opreg_template.h syscall_defs.h\ -ppc.ld s390.ld exec-i386.h exec-i386.c path.c configure \ +syscall.c opreg_template.h syscall_defs.h vm86.c\ +dis-asm.h dis-buf.c disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c\ +ppc.ld s390.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h tests/test-i386-code16.S\ diff --git a/gen-i386.h b/gen-i386.h deleted file mode 100644 index e69de29bb..000000000 -- cgit v1.2.3 From b333af066655c15031820a109b651c45adb7eccf Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 21:48:51 +0000 Subject: removed trace - merged 2.4.20 vm86 patches git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@167 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 1 + linux-user/vm86.c | 176 +++++++++++++++++++++++++++++++++++------------------- syscall-i386.h | 7 +++ 3 files changed, 121 insertions(+), 63 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 7e23f2791..d6e615e0a 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -54,6 +54,7 @@ typedef struct TaskState { struct TaskState *next; struct target_vm86plus_struct *target_v86; struct vm86_saved_state vm86_saved_regs; + struct target_vm86plus_struct vm86plus; uint32_t v86flags; uint32_t v86mask; int used; /* non zero if used */ diff --git a/linux-user/vm86.c b/linux-user/vm86.c index d9b4ea63b..a958c624d 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -36,7 +36,7 @@ static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) { - return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1; + return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1; } static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val) @@ -194,17 +194,12 @@ static void do_int(CPUX86State *env, int intno) uint8_t *ssp; unsigned int sp; -#if 1 - if (intno == 0xe6 && (env->regs[R_EAX] & 0xffff) == 0x00c0) - loglevel = 1; -#endif - if (env->segs[R_CS] == TARGET_BIOSSEG) goto cannot_handle; - if (is_revectored(intno, &ts->target_v86->int_revectored)) + if (is_revectored(intno, &ts->vm86plus.int_revectored)) goto cannot_handle; if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, - &ts->target_v86->int21_revectored)) + &ts->vm86plus.int21_revectored)) goto cannot_handle; int_ptr = (uint32_t *)(intno << 2); segoffs = tswap32(*int_ptr); @@ -244,13 +239,13 @@ void handle_vm86_trap(CPUX86State *env, int trapno) } } -#define CHECK_IF_IN_TRAP(disp) \ - if ((tswap32(ts->target_v86->vm86plus.flags) & TARGET_vm86dbg_active) && \ - (tswap32(ts->target_v86->vm86plus.flags) & TARGET_vm86dbg_TFpendig)) \ - vm_putw(ssp,sp + disp,vm_getw(ssp,sp + disp) | TF_MASK) +#define CHECK_IF_IN_TRAP() \ + if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \ + (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \ + newflags |= TF_MASK #define VM86_FAULT_RETURN \ - if ((tswap32(ts->target_v86->vm86plus.flags) & TARGET_force_return_for_pic) && \ + if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \ (ts->v86flags & (IF_MASK | VIF_MASK))) \ return_to_32bit(env, TARGET_VM86_PICRETURN); \ return @@ -259,7 +254,8 @@ void handle_vm86_fault(CPUX86State *env) { TaskState *ts = env->opaque; uint8_t *csp, *pc, *ssp; - unsigned int ip, sp; + unsigned int ip, sp, newflags, newip, newcs, opcode, intno; + int data32, pref_done; csp = (uint8_t *)(env->segs[R_CS] << 4); ip = env->eip & 0xffff; @@ -273,78 +269,109 @@ void handle_vm86_fault(CPUX86State *env) env->segs[R_CS], env->eip, pc[0], pc[1]); #endif + data32 = 0; + pref_done = 0; + do { + opcode = csp[ip]; + ADD16(ip, 1); + switch (opcode) { + case 0x66: /* 32-bit data */ data32=1; break; + case 0x67: /* 32-bit address */ break; + case 0x2e: /* CS */ break; + case 0x3e: /* DS */ break; + case 0x26: /* ES */ break; + case 0x36: /* SS */ break; + case 0x65: /* GS */ break; + case 0x64: /* FS */ break; + case 0xf2: /* repnz */ break; + case 0xf3: /* rep */ break; + default: pref_done = 1; + } + } while (!pref_done); + /* VM86 mode */ - switch(pc[0]) { - case 0x66: - switch(pc[1]) { - case 0x9c: /* pushfd */ - ADD16(env->eip, 2); - ADD16(env->regs[R_ESP], -4); + switch(opcode) { + case 0x9c: /* pushf */ + ADD16(env->eip, 2); + if (data32) { vm_putl(ssp, sp - 4, get_vflags(env)); - VM86_FAULT_RETURN; + ADD16(env->regs[R_ESP], -4); + } else { + vm_putw(ssp, sp - 2, get_vflags(env)); + ADD16(env->regs[R_ESP], -2); + } + env->eip = ip; + VM86_FAULT_RETURN; - case 0x9d: /* popfd */ - ADD16(env->eip, 2); + case 0x9d: /* popf */ + if (data32) { + newflags = vm_getl(ssp, sp); ADD16(env->regs[R_ESP], 4); - CHECK_IF_IN_TRAP(0); - if (set_vflags_long(vm_getl(ssp, sp), env)) + } else { + newflags = vm_getw(ssp, sp); + ADD16(env->regs[R_ESP], 2); + } + env->eip = ip; + CHECK_IF_IN_TRAP(); + if (data32) { + if (set_vflags_long(newflags, env)) return; - VM86_FAULT_RETURN; - - case 0xcf: /* iretd */ - ADD16(env->regs[R_ESP], 12); - env->eip = vm_getl(ssp, sp) & 0xffff; - cpu_x86_load_seg(env, R_CS, vm_getl(ssp, sp + 4) & 0xffff); - CHECK_IF_IN_TRAP(8); - if (set_vflags_long(vm_getl(ssp, sp + 8), env)) + } else { + if (set_vflags_short(newflags, env)) return; - VM86_FAULT_RETURN; - - default: - goto vm86_gpf; } - break; - case 0x9c: /* pushf */ - ADD16(env->eip, 1); - ADD16(env->regs[R_ESP], -2); - vm_putw(ssp, sp - 2, get_vflags(env)); - VM86_FAULT_RETURN; - - case 0x9d: /* popf */ - ADD16(env->eip, 1); - ADD16(env->regs[R_ESP], 2); - CHECK_IF_IN_TRAP(0); - if (set_vflags_short(vm_getw(ssp, sp), env)) - return; VM86_FAULT_RETURN; case 0xcd: /* int */ - ADD16(env->eip, 2); - do_int(env, pc[1]); + intno = csp[ip]; + ADD16(ip, 1); + env->eip = ip; + if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) { + if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >> + (intno &7)) & 1) { + return_to_32bit(env, TARGET_VM86_INTx + (intno << 8)); + return; + } + } + do_int(env, intno); break; case 0xcf: /* iret */ - ADD16(env->regs[R_ESP], 6); - env->eip = vm_getw(ssp, sp); - cpu_x86_load_seg(env, R_CS, vm_getw(ssp, sp + 2)); - CHECK_IF_IN_TRAP(4); - if (set_vflags_short(vm_getw(ssp, sp + 4), env)) - return; + if (data32) { + newip = vm_getl(ssp, sp) & 0xffff; + newcs = vm_getl(ssp, sp + 4) & 0xffff; + newflags = vm_getl(ssp, sp + 8); + ADD16(env->regs[R_ESP], 12); + } else { + newip = vm_getw(ssp, sp); + newcs = vm_getw(ssp, sp + 2); + newflags = vm_getw(ssp, sp + 4); + ADD16(env->regs[R_ESP], 6); + } + env->eip = newip; + cpu_x86_load_seg(env, R_CS, newcs); + CHECK_IF_IN_TRAP(); + if (data32) { + if (set_vflags_long(newflags, env)) + return; + } else { + if (set_vflags_short(newflags, env)) + return; + } VM86_FAULT_RETURN; - + case 0xfa: /* cli */ - ADD16(env->eip, 1); + env->eip = ip; clear_IF(env); VM86_FAULT_RETURN; case 0xfb: /* sti */ - ADD16(env->eip, 1); + env->eip = ip; if (set_IF(env)) return; VM86_FAULT_RETURN; default: - vm86_gpf: /* real VM86 GPF exception */ return_to_32bit(env, TARGET_VM86_UNKNOWN); break; @@ -398,7 +425,22 @@ int do_vm86(CPUX86State *env, long subfunction, ts->v86flags = tswap32(target_v86->regs.eflags); env->eflags = (env->eflags & ~SAFE_MASK) | (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; - ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; + + ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type); + switch (ts->vm86plus.cpu_type) { + case TARGET_CPU_286: + ts->v86mask = 0; + break; + case TARGET_CPU_386: + ts->v86mask = NT_MASK | IOPL_MASK; + break; + case TARGET_CPU_486: + ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK; + break; + default: + ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; + break; + } env->regs[R_EBX] = tswap32(target_v86->regs.ebx); env->regs[R_ECX] = tswap32(target_v86->regs.ecx); @@ -416,6 +458,14 @@ int do_vm86(CPUX86State *env, long subfunction, cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); ret = tswap32(target_v86->regs.eax); /* eax will be restored at the end of the syscall */ + memcpy(&ts->vm86plus.int_revectored, + &target_v86->int_revectored, 32); + memcpy(&ts->vm86plus.int21_revectored, + &target_v86->int21_revectored, 32); + ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags); + memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, + target_v86->vm86plus.vm86dbg_intxxtab, 32); + #ifdef DEBUG_VM86 fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS], env->eip); #endif diff --git a/syscall-i386.h b/syscall-i386.h index fbe86109e..178b638c7 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -784,6 +784,13 @@ struct target_modify_ldt_ldt_s { #define TARGET_BIOSSEG 0x0f000 +#define TARGET_CPU_086 0 +#define TARGET_CPU_186 1 +#define TARGET_CPU_286 2 +#define TARGET_CPU_386 3 +#define TARGET_CPU_486 4 +#define TARGET_CPU_586 5 + #define TARGET_VM86_SIGNAL 0 /* return due to signal */ #define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ #define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */ -- cgit v1.2.3 From 25eb44841e4125da67338320d8af0b4859c672de Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 21:50:54 +0000 Subject: better locking - added PowerPC signal handler (add it for the other archs too because it needed for full exception support) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@168 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 118 ++++++++++++++++-------------------------------------------- 1 file changed, 30 insertions(+), 88 deletions(-) diff --git a/exec-i386.c b/exec-i386.c index abc06b494..cde3da7ca 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -27,95 +27,16 @@ /* thread support */ -#ifdef __powerpc__ -static inline int testandset (int *p) -{ - int ret; - __asm__ __volatile__ ( - "0: lwarx %0,0,%1 ;" - " xor. %0,%3,%0;" - " bne 1f;" - " stwcx. %2,0,%1;" - " bne- 0b;" - "1: " - : "=&r" (ret) - : "r" (p), "r" (1), "r" (0) - : "cr0", "memory"); - return ret; -} -#endif - -#ifdef __i386__ -static inline int testandset (int *p) -{ - char ret; - long int readval; - - __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" - : "=q" (ret), "=m" (*p), "=a" (readval) - : "r" (1), "m" (*p), "a" (0) - : "memory"); - return ret; -} -#endif - -#ifdef __s390__ -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" - " jl 0b" - : "=&d" (ret) - : "r" (1), "a" (p), "0" (*p) - : "cc", "memory" ); - return ret; -} -#endif - -#ifdef __alpha__ -int testandset (int *p) -{ - int ret; - unsigned long one; - - __asm__ __volatile__ ("0: mov 1,%2\n" - " ldl_l %0,%1\n" - " stl_c %2,%1\n" - " beq %2,1f\n" - ".subsection 2\n" - "1: br 0b\n" - ".previous" - : "=r" (ret), "=m" (*p), "=r" (one) - : "m" (*p)); - return ret; -} -#endif - -#ifdef __sparc__ -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__("ldstub [%1], %0" - : "=r" (ret) - : "r" (p) - : "memory"); - - return (ret ? 1 : 0); -} -#endif - -int global_cpu_lock = 0; +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; void cpu_lock(void) { - while (testandset(&global_cpu_lock)); + spin_lock(&global_cpu_lock); } void cpu_unlock(void) { - global_cpu_lock = 0; + spin_unlock(&global_cpu_lock); } /* exception support */ @@ -292,16 +213,16 @@ int cpu_x86_exec(CPUX86State *env1) flags); if (!tb) { /* if no translated code available, then translate it now */ - /* XXX: very inefficient: we lock all the cpus when - generating code */ - cpu_lock(); + /* very inefficient but safe: we lock all the cpus + when generating code */ + spin_lock(&tb_lock); tc_ptr = code_gen_ptr; ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, &code_gen_size, pc, cs_base, flags, &code_size); /* if invalid instruction, signal it */ if (ret != 0) { - cpu_unlock(); + spin_unlock(&tb_lock); raise_exception(EXCP06_ILLOP); } tb = tb_alloc((unsigned long)pc, code_size); @@ -311,7 +232,7 @@ int cpu_x86_exec(CPUX86State *env1) tb->tc_ptr = tc_ptr; tb->hash_next = NULL; code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); - cpu_unlock(); + spin_unlock(&tb_lock); } #ifdef DEBUG_EXEC if (loglevel) { @@ -412,6 +333,7 @@ static inline int handle_cpu_signal(unsigned long pc, printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", pc, address, is_write, *(unsigned long *)old_set); #endif + /* XXX: locking issue */ if (is_write && page_unprotect(address)) { sigprocmask(SIG_SETMASK, old_set, NULL); return 1; @@ -454,8 +376,28 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, pold_set); +#elif defined(__powerpc) + struct ucontext *uc = puc; + struct pt_regs *regs = uc->uc_mcontext.regs; + unsigned long pc; + sigset_t *pold_set; + int is_write; + + pc = regs->nip; + pold_set = &uc->uc_sigmask; + is_write = 0; +#if 0 + /* ppc 4xx case */ + if (regs->dsisr & 0x00800000) + is_write = 1; +#else + if (regs->trap != 0x400 && (regs->dsisr & 0x02000000)) + is_write = 1; +#endif + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, pold_set); #else -#warning No CPU specific signal handler: cannot handle target SIGSEGV events +#error CPU specific signal handler needed return 0; #endif } -- cgit v1.2.3 From eb51d102bbd541963ac5cb98d5a8c7c2fe9453d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 21:51:13 +0000 Subject: better locks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@169 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ exec.c | 4 +++ 2 files changed, 104 insertions(+) diff --git a/cpu-i386.h b/cpu-i386.h index 44411b0ca..008ff8cd2 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -542,4 +542,104 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif +#ifdef __powerpc__ +static inline int testandset (int *p) +{ + int ret; + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r" (ret) + : "r" (p), "r" (1), "r" (0) + : "cr0", "memory"); + return ret; +} +#endif + +#ifdef __i386__ +static inline int testandset (int *p) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (1), "m" (*p), "a" (0) + : "memory"); + return ret; +} +#endif + +#ifdef __s390__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" + " jl 0b" + : "=&d" (ret) + : "r" (1), "a" (p), "0" (*p) + : "cc", "memory" ); + return ret; +} +#endif + +#ifdef __alpha__ +int testandset (int *p) +{ + int ret; + unsigned long one; + + __asm__ __volatile__ ("0: mov 1,%2\n" + " ldl_l %0,%1\n" + " stl_c %2,%1\n" + " beq %2,1f\n" + ".subsection 2\n" + "1: br 0b\n" + ".previous" + : "=r" (ret), "=m" (*p), "=r" (one) + : "m" (*p)); + return ret; +} +#endif + +#ifdef __sparc__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (ret) + : "r" (p) + : "memory"); + + return (ret ? 1 : 0); +} +#endif + +typedef int spinlock_t; + +#define SPIN_LOCK_UNLOCKED 0 + +static inline void spin_lock(spinlock_t *lock) +{ + while (testandset(lock)); +} + +static inline void spin_unlock(spinlock_t *lock) +{ + *lock = 0; +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return !testandset(lock); +} + +extern spinlock_t tb_lock; + #endif /* CPU_I386_H */ diff --git a/exec.c b/exec.c index 0ed49c695..8804bfab7 100644 --- a/exec.c +++ b/exec.c @@ -42,6 +42,8 @@ TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; int nb_tbs; +/* any access to the tbs or the page table must use this lock */ +spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; uint8_t *code_gen_ptr; @@ -172,6 +174,7 @@ void page_set_flags(unsigned long start, unsigned long end, int flags) end = TARGET_PAGE_ALIGN(end); if (flags & PAGE_WRITE) flags |= PAGE_WRITE_ORG; + spin_lock(&tb_lock); for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { p = page_find_alloc(addr >> TARGET_PAGE_BITS); /* if the write protection is set, then we invalidate the code @@ -183,6 +186,7 @@ void page_set_flags(unsigned long start, unsigned long end, int flags) } p->flags = flags; } + spin_unlock(&tb_lock); } void cpu_x86_tblocks_init(void) -- cgit v1.2.3 From 03d843ddf271e96b6f8b2cd8a58f7a2004fcfaf9 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 22:41:55 +0000 Subject: fixed invalid signal masking git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@170 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 1 - 1 file changed, 1 deletion(-) diff --git a/exec-i386.c b/exec-i386.c index cde3da7ca..18ea18888 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -335,7 +335,6 @@ static inline int handle_cpu_signal(unsigned long pc, #endif /* XXX: locking issue */ if (is_write && page_unprotect(address)) { - sigprocmask(SIG_SETMASK, old_set, NULL); return 1; } if (pc >= (unsigned long)code_gen_buffer && -- cgit v1.2.3 From 7775e9ecc264eb3780901a10d786391b5ae955b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 22:46:48 +0000 Subject: added do_fcntl() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@171 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 81 +++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 34599d0f0..b0a4652f0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1103,6 +1103,49 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) #endif +static long do_fcntl(int fd, int cmd, unsigned long arg) +{ + struct flock fl; + struct target_flock *target_fl = (void *)arg; + long ret; + + switch(cmd) { + case TARGET_F_GETLK: + ret = fcntl(fd, cmd, &fl); + if (ret == 0) { + target_fl->l_type = tswap16(fl.l_type); + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswapl(fl.l_start); + target_fl->l_len = tswapl(fl.l_len); + target_fl->l_pid = tswapl(fl.l_pid); + } + break; + + case TARGET_F_SETLK: + case TARGET_F_SETLKW: + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswapl(target_fl->l_start); + fl.l_len = tswapl(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + ret = fcntl(fd, cmd, &fl); + break; + + case TARGET_F_GETLK64: + case TARGET_F_SETLK64: + case TARGET_F_SETLKW64: + ret = -1; + errno = EINVAL; + break; + + default: + ret = fcntl(fd, cmd, arg); + break; + } + return ret; +} + + #define high2lowuid(x) (x) #define high2lowgid(x) (x) #define low2highuid(x) (x) @@ -1343,42 +1386,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = do_ioctl(arg1, arg2, arg3); break; case TARGET_NR_fcntl: - { - struct flock fl; - struct target_flock *target_fl = (void *)arg3; - - switch(arg2) { - case TARGET_F_GETLK: - ret = get_errno(fcntl(arg1, arg2, &fl)); - if (ret == 0) { - target_fl->l_type = tswap16(fl.l_type); - target_fl->l_whence = tswap16(fl.l_whence); - target_fl->l_start = tswapl(fl.l_start); - target_fl->l_len = tswapl(fl.l_len); - target_fl->l_pid = tswapl(fl.l_pid); - } - break; - - case TARGET_F_SETLK: - case TARGET_F_SETLKW: - fl.l_type = tswap16(target_fl->l_type); - fl.l_whence = tswap16(target_fl->l_whence); - fl.l_start = tswapl(target_fl->l_start); - fl.l_len = tswapl(target_fl->l_len); - fl.l_pid = tswapl(target_fl->l_pid); - ret = get_errno(fcntl(arg1, arg2, &fl)); - break; - - case TARGET_F_GETLK64: - case TARGET_F_SETLK64: - case TARGET_F_SETLKW64: - goto unimplemented; - default: - ret = get_errno(fcntl(arg1, arg2, arg3)); - break; - } + ret = get_errno(do_fcntl(arg1, arg2, arg3)); break; - } case TARGET_NR_mpx: goto unimplemented; case TARGET_NR_setpgid: @@ -2373,7 +2382,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(fcntl(arg1, arg2, &fl)); break; default: - ret = get_errno(fcntl(arg1, arg2, arg3)); + ret = get_errno(do_fcntl(arg1, arg2, arg3)); break; } break; -- cgit v1.2.3 From 3ebcc707d20643e9fefa24a4396de577b1163755 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 22:47:15 +0000 Subject: removed invalid eip update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@172 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/vm86.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index a958c624d..e4f9b85c8 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -292,7 +292,6 @@ void handle_vm86_fault(CPUX86State *env) /* VM86 mode */ switch(opcode) { case 0x9c: /* pushf */ - ADD16(env->eip, 2); if (data32) { vm_putl(ssp, sp - 4, get_vflags(env)); ADD16(env->regs[R_ESP], -4); -- cgit v1.2.3 From 2b413144dcb22ff1852c46d3be7aa4bd9095723f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 May 2003 23:01:10 +0000 Subject: cosmetics git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@173 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/exec-i386.c b/exec-i386.c index 18ea18888..7575123ec 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -324,10 +324,8 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) 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) +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set) { #if defined(DEBUG_SIGNAL) printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", @@ -355,13 +353,13 @@ static inline int handle_cpu_signal(unsigned long pc, } } +#if defined(__i386__) + int cpu_x86_signal_handler(int host_signum, struct siginfo *info, void *puc) { -#if defined(__i386__) struct ucontext *uc = puc; unsigned long pc; - sigset_t *pold_set; #ifndef REG_EIP /* for glibc 2.1 */ @@ -370,20 +368,23 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, #define REG_TRAPNO TRAPNO #endif pc = uc->uc_mcontext.gregs[REG_EIP]; - pold_set = &uc->uc_sigmask; 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, - pold_set); + &uc->uc_sigmask); +} + #elif defined(__powerpc) + +int cpu_x86_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ struct ucontext *uc = puc; struct pt_regs *regs = uc->uc_mcontext.regs; unsigned long pc; - sigset_t *pold_set; int is_write; pc = regs->nip; - pold_set = &uc->uc_sigmask; is_write = 0; #if 0 /* ppc 4xx case */ @@ -394,9 +395,11 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, is_write = 1; #endif return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, pold_set); + is_write, &uc->uc_sigmask); +} + #else + #error CPU specific signal handler needed - return 0; + #endif -} -- cgit v1.2.3 From 3a27ad0b57f5ac1dc5aaf1805d8caa4be2deb2dd Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 May 2003 13:43:31 +0000 Subject: added vm86, exceptions and self modifying regression tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@174 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386-vm86.S | 104 ++++++++++++++++ tests/test-i386.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 423 insertions(+) create mode 100644 tests/test-i386-vm86.S diff --git a/tests/test-i386-vm86.S b/tests/test-i386-vm86.S new file mode 100644 index 000000000..a972f1b81 --- /dev/null +++ b/tests/test-i386-vm86.S @@ -0,0 +1,104 @@ + .code16 + .globl vm86_code_start + .globl vm86_code_end + +#define GET_OFFSET(x) ((x) - vm86_code_start + 0x100) + +vm86_code_start: + movw $GET_OFFSET(hello_world), %dx + movb $0x09, %ah + int $0x21 + + /* prepare int 0x90 vector */ + xorw %ax, %ax + movw %ax, %es + es movw $GET_OFFSET(int90_test), 0x90 * 4 + es movw %cs, 0x90 * 4 + 2 + + /* launch int 0x90 */ + + int $0x90 + + /* test IF support */ + movw $GET_OFFSET(IF_msg), %dx + movb $0x09, %ah + int $0x21 + + pushf + popw %dx + movb $0xff, %ah + int $0x21 + + cli + pushf + popw %dx + movb $0xff, %ah + int $0x21 + + sti + pushfl + popl %edx + movb $0xff, %ah + int $0x21 + +#if 0 + movw $GET_OFFSET(IF_msg1), %dx + movb $0x09, %ah + int $0x21 + + pushf + movw %sp, %bx + andw $~0x200, (%bx) + popf +#else + cli +#endif + + pushf + popw %dx + movb $0xff, %ah + int $0x21 + + pushfl + movw %sp, %bx + orw $0x200, (%bx) + popfl + + pushfl + popl %edx + movb $0xff, %ah + int $0x21 + + movb $0x00, %ah + int $0x21 + +int90_test: + pushf + pop %dx + movb $0xff, %ah + int $0x21 + + movw %sp, %bx + movw 4(%bx), %dx + movb $0xff, %ah + int $0x21 + + movw $GET_OFFSET(int90_msg), %dx + movb $0x09, %ah + int $0x21 + iret + +int90_msg: + .string "INT90 started\n$" + +hello_world: + .string "Hello VM86 world\n$" + +IF_msg: + .string "VM86 IF test\n$" + +IF_msg1: + .string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$" + +vm86_code_end: + \ No newline at end of file diff --git a/tests/test-i386.c b/tests/test-i386.c index 1b63a5b38..50c2d5b2c 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1,7 +1,13 @@ +#define _GNU_SOURCE #include #include #include #include +#include +#include +#include +#include +#include #define TEST_CMOV 0 @@ -913,6 +919,316 @@ void test_string(void) TEST_STRING(cmps, "repnz "); } +/* VM86 test */ + +static inline void set_bit(uint8_t *a, unsigned int bit) +{ + a[bit / 8] |= (1 << (bit % 8)); +} + +static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) +{ + return (uint8_t *)((seg << 4) + (reg & 0xffff)); +} + +static inline void pushw(struct vm86_regs *r, int val) +{ + r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff); + *(uint16_t *)seg_to_linear(r->ss, r->esp) = val; +} + +#undef __syscall_return +#define __syscall_return(type, res) \ +do { \ + return (type) (res); \ +} while (0) + +_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86) + +extern char vm86_code_start; +extern char vm86_code_end; + +#define VM86_CODE_CS 0x100 +#define VM86_CODE_IP 0x100 + +void test_vm86(void) +{ + struct vm86plus_struct ctx; + struct vm86_regs *r; + uint8_t *vm86_mem; + int seg, ret; + + vm86_mem = mmap((void *)0x00000000, 0x110000, + PROT_WRITE | PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); + if (vm86_mem == MAP_FAILED) { + printf("ERROR: could not map vm86 memory"); + return; + } + memset(&ctx, 0, sizeof(ctx)); + + /* init basic registers */ + r = &ctx.regs; + r->eip = VM86_CODE_IP; + r->esp = 0xfffe; + seg = VM86_CODE_CS; + r->cs = seg; + r->ss = seg; + r->ds = seg; + r->es = seg; + r->fs = seg; + r->gs = seg; + r->eflags = VIF_MASK; + + /* move code to proper address. We use the same layout as a .com + dos program. */ + memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP, + &vm86_code_start, &vm86_code_end - &vm86_code_start); + + /* mark int 0x21 as being emulated */ + set_bit((uint8_t *)&ctx.int_revectored, 0x21); + + for(;;) { + ret = vm86(VM86_ENTER, &ctx); + switch(VM86_TYPE(ret)) { + case VM86_INTx: + { + int int_num, ah; + + int_num = VM86_ARG(ret); + if (int_num != 0x21) + goto unknown_int; + ah = (r->eax >> 8) & 0xff; + switch(ah) { + case 0x00: /* exit */ + goto the_end; + case 0x02: /* write char */ + { + uint8_t c = r->edx; + putchar(c); + } + break; + case 0x09: /* write string */ + { + uint8_t c, *ptr; + ptr = seg_to_linear(r->ds, r->edx); + for(;;) { + c = *ptr++; + if (c == '$') + break; + putchar(c); + } + r->eax = (r->eax & ~0xff) | '$'; + } + break; + case 0xff: /* extension: write hex number in edx */ + printf("%08x\n", (int)r->edx); + break; + default: + unknown_int: + printf("unsupported int 0x%02x\n", int_num); + goto the_end; + } + } + break; + case VM86_SIGNAL: + /* a signal came, we just ignore that */ + break; + case VM86_STI: + break; + default: + printf("ERROR: unhandled vm86 return code (0x%x)\n", ret); + goto the_end; + } + } + the_end: + printf("VM86 end\n"); + munmap(vm86_mem, 0x110000); +} + +/* exception tests */ +#ifndef REG_EAX +#define REG_EAX EAX +#define REG_EBX EBX +#define REG_ECX ECX +#define REG_EDX EDX +#define REG_ESI ESI +#define REG_EDI EDI +#define REG_EBP EBP +#define REG_ESP ESP +#define REG_EIP EIP +#define REG_EFL EFL +#define REG_TRAPNO TRAPNO +#define REG_ERR ERR +#endif + +jmp_buf jmp_env; +int dump_eip; +int dump_si_addr; +int v1; +int tab[2]; + +void sig_handler(int sig, siginfo_t *info, void *puc) +{ + struct ucontext *uc = puc; + + printf("si_signo=%d si_errno=%d si_code=%d", + info->si_signo, info->si_errno, info->si_code); + if (dump_si_addr) { + printf(" si_addr=0x%08lx", + (unsigned long)info->si_addr); + } + printf("\n"); + + printf("trapno=0x%02x err=0x%08x", + uc->uc_mcontext.gregs[REG_TRAPNO], + uc->uc_mcontext.gregs[REG_ERR]); + if (dump_eip) + printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]); + printf("\n"); + longjmp(jmp_env, 1); +} + +void test_exceptions(void) +{ + struct sigaction act; + volatile int val; + + act.sa_sigaction = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + sigaction(SIGFPE, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGTRAP, &act, NULL); + + /* test division by zero reporting */ + dump_eip = 0; + dump_si_addr = 0; + printf("DIVZ exception (currently imprecise):\n"); + if (setjmp(jmp_env) == 0) { + /* now divide by zero */ + v1 = 0; + v1 = 2 / v1; + } + + dump_si_addr = 1; + printf("BOUND exception (currently imprecise):\n"); + if (setjmp(jmp_env) == 0) { + /* bound exception */ + tab[0] = 1; + tab[1] = 10; + asm volatile ("bound %0, %1" : : "r" (11), "m" (tab)); + } + + /* test SEGV reporting */ + printf("PF exception (currently imprecise):\n"); + if (setjmp(jmp_env) == 0) { + /* now store in an invalid address */ + *(char *)0x1234 = 1; + } + + /* test SEGV reporting */ + printf("PF exception (currently imprecise):\n"); + if (setjmp(jmp_env) == 0) { + /* read from an invalid address */ + v1 = *(char *)0x1234; + } + + printf("segment GPF exception (currently imprecise):\n"); + if (setjmp(jmp_env) == 0) { + /* load an invalid segment */ + asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0)); + } + + dump_eip = 1; + /* test illegal instruction reporting */ + printf("UD2 exception:\n"); + if (setjmp(jmp_env) == 0) { + /* now execute an invalid instruction */ + asm volatile("ud2"); + } + + printf("INT exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("int $0xfd"); + } + + printf("INT3 exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("int3"); + } + + printf("CLI exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("cli"); + } + + printf("STI exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("cli"); + } + + printf("INTO exception:\n"); + if (setjmp(jmp_env) == 0) { + /* overflow exception */ + asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff)); + } + + printf("OUTB exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0)); + } + + printf("INB exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321)); + } + + printf("REP OUTSB exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1)); + } + + printf("REP INSB exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1)); + } + + printf("HLT exception:\n"); + if (setjmp(jmp_env) == 0) { + asm volatile ("hlt"); + } + + printf("single step exception:\n"); + val = 0; + if (setjmp(jmp_env) == 0) { + asm volatile ("pushf\n" + "orl $0x00100, (%%esp)\n" + "popf\n" + "movl $0xabcd, %0\n" + "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory"); + } + printf("val=0x%x\n", val); +} + +/* self modifying code test */ +uint8_t code[] = { + 0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */ + 0xc3, /* ret */ +}; + +void test_self_modifying_code(void) +{ + int (*func)(void); + + func = (void *)code; + printf("self modifying code:\n"); + printf("func1 = 0x%x\n", func()); + code[1] = 0x2; + printf("func1 = 0x%x\n", func()); +} + static void *call_end __init_call = NULL; int main(int argc, char **argv) @@ -936,5 +1252,8 @@ int main(int argc, char **argv) test_lea(); test_segs(); test_code16(); + test_vm86(); + test_exceptions(); + test_self_modifying_code(); return 0; } -- cgit v1.2.3 From c0ad5542a8cc68d1d9b18ed5e2d43de6b6fc60bf Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 May 2003 13:46:28 +0000 Subject: fixed popf TF flag bug (should never hapen in user code except in test-i386!) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@175 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 1 + 1 file changed, 1 insertion(+) diff --git a/translate-i386.c b/translate-i386.c index 086d74a4f..32e188bbb 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -3085,6 +3085,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } gen_pop_update(s); s->cc_op = CC_OP_EFLAGS; + s->is_jmp = 2; /* abort translation because TF flag may change */ } break; case 0x9e: /* sahf */ -- cgit v1.2.3 From 5132455efe7555d707041fecb48be5bdcba7acf5 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 May 2003 13:58:37 +0000 Subject: test-i386 update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@176 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 6a55d20d7..5f6479e20 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -30,9 +30,10 @@ test_path: test_path.c ./$@ || { rm $@; exit 1; } # i386 emulation test (test various opcodes) */ -test-i386: test-i386.c test-i386-code16.S \ +test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c test-i386-code16.S -lm + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \ + test-i386-code16.S test-i386-vm86.S -lm test: test-i386 ifeq ($(ARCH),i386) -- cgit v1.2.3 From 418a97afa1017a49b60dae3abb9c46d8dde1f8df Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 May 2003 15:12:51 +0000 Subject: fixed 32 bit popf/iret emulation in vm86 mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@177 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/vm86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index e4f9b85c8..885762c06 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -56,7 +56,7 @@ static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16) static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16) { - return tswap32(*(uint16_t *)(segptr + (reg16 & 0xffff))); + return tswap32(*(uint32_t *)(segptr + (reg16 & 0xffff))); } void save_v86_state(CPUX86State *env) -- cgit v1.2.3 From b409186b8db0b11f6e5b0f014909df6fea81531f Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 May 2003 15:39:34 +0000 Subject: added getrusage git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@178 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 52 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b0a4652f0..90fb9dcd3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -215,6 +215,29 @@ static inline void host_to_target_fds(target_long *target_fds, #endif } +static inline void host_to_target_rusage(struct target_rusage *target_rusage, + const struct rusage *rusage) +{ + target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec); + target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec); + target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec); + target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec); + target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss); + target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss); + target_rusage->ru_idrss = tswapl(rusage->ru_idrss); + target_rusage->ru_isrss = tswapl(rusage->ru_isrss); + target_rusage->ru_minflt = tswapl(rusage->ru_minflt); + target_rusage->ru_majflt = tswapl(rusage->ru_majflt); + target_rusage->ru_nswap = tswapl(rusage->ru_nswap); + target_rusage->ru_inblock = tswapl(rusage->ru_inblock); + target_rusage->ru_oublock = tswapl(rusage->ru_oublock); + target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd); + target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv); + target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals); + target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw); + target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw); +} + static inline void target_to_host_timeval(struct timeval *tv, const struct target_timeval *target_tv) { @@ -1636,7 +1659,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_getrusage: - goto unimplemented; + { + struct rusage rusage; + struct target_rusage *target_rusage = (void *)arg2; + ret = get_errno(getrusage(arg1, &rusage)); + if (!is_error(ret)) { + host_to_target_rusage(target_rusage, &rusage); + } + } + break; case TARGET_NR_gettimeofday: { struct target_timeval *target_tv = (void *)arg1; @@ -1886,24 +1917,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, if (status_ptr) *status_ptr = tswap32(status); if (target_rusage) { - target_rusage->ru_utime.tv_sec = tswapl(rusage.ru_utime.tv_sec); - target_rusage->ru_utime.tv_usec = tswapl(rusage.ru_utime.tv_usec); - target_rusage->ru_stime.tv_sec = tswapl(rusage.ru_stime.tv_sec); - target_rusage->ru_stime.tv_usec = tswapl(rusage.ru_stime.tv_usec); - target_rusage->ru_maxrss = tswapl(rusage.ru_maxrss); - target_rusage->ru_ixrss = tswapl(rusage.ru_ixrss); - target_rusage->ru_idrss = tswapl(rusage.ru_idrss); - target_rusage->ru_isrss = tswapl(rusage.ru_isrss); - target_rusage->ru_minflt = tswapl(rusage.ru_minflt); - target_rusage->ru_majflt = tswapl(rusage.ru_majflt); - target_rusage->ru_nswap = tswapl(rusage.ru_nswap); - target_rusage->ru_inblock = tswapl(rusage.ru_inblock); - target_rusage->ru_oublock = tswapl(rusage.ru_oublock); - target_rusage->ru_msgsnd = tswapl(rusage.ru_msgsnd); - target_rusage->ru_msgrcv = tswapl(rusage.ru_msgrcv); - target_rusage->ru_nsignals = tswapl(rusage.ru_nsignals); - target_rusage->ru_nvcsw = tswapl(rusage.ru_nvcsw); - target_rusage->ru_nivcsw = tswapl(rusage.ru_nivcsw); + host_to_target_rusage(target_rusage, &rusage); } } } -- cgit v1.2.3 From 1565b7bcd79c5253fd400cc0ef8b398da788e965 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 May 2003 16:07:10 +0000 Subject: fixed page_unprotect() if host_page_size > TARGET_PAGE_SIZE git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@179 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/exec.c b/exec.c index 8804bfab7..936424ad8 100644 --- a/exec.c +++ b/exec.c @@ -394,26 +394,29 @@ TranslationBlock *tb_alloc(unsigned long pc, page. Return TRUE if the fault was succesfully handled. */ int page_unprotect(unsigned long address) { - unsigned int page_index, prot; - PageDesc *p; + unsigned int page_index, prot, pindex; + PageDesc *p, *p1; unsigned long host_start, host_end, addr; - page_index = address >> TARGET_PAGE_BITS; - p = page_find(page_index); - if (!p) + host_start = address & host_page_mask; + page_index = host_start >> TARGET_PAGE_BITS; + p1 = page_find(page_index); + if (!p1) return 0; - if ((p->flags & (PAGE_WRITE_ORG | PAGE_WRITE)) == PAGE_WRITE_ORG) { - /* if the page was really writable, then we change its - protection back to writable */ - host_start = address & host_page_mask; - host_end = host_start + host_page_size; - prot = 0; - for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) - prot |= page_get_flags(addr); + host_end = host_start + host_page_size; + p = p1; + prot = 0; + for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= p->flags; + p++; + } + /* if the page was really writable, then we change its + protection back to writable */ + if (prot & PAGE_WRITE_ORG) { mprotect((void *)host_start, host_page_size, (prot & PAGE_BITS) | PAGE_WRITE); - p->flags |= PAGE_WRITE; - + pindex = (address - host_start) >> TARGET_PAGE_BITS; + p1[pindex].flags |= PAGE_WRITE; /* and since the content will be modified, we must invalidate the corresponding translated code. */ tb_invalidate_page(address); -- cgit v1.2.3 From aa05ae6fecba7c4d86d5d02b2f02b07d21b1750f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 May 2003 16:41:18 +0000 Subject: added exec.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@180 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3aa42f19b..a5d4556f4 100644 --- a/Makefile +++ b/Makefile @@ -75,8 +75,15 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o + # NOTE: the disassembler code is only needed for debugging -LIBOBJS+=disas.o ppc-dis.o i386-dis.o alpha-dis.o dis-buf.o +LIBOBJS+=disas.o i386-dis.o dis-buf.o +ifeq ($(ARCH),alpha) +LIBOBJS+=alpha-dis.o +endif +ifeq ($(ARCH),ppc) +LIBOBJS+=ppc-dis.o +endif ifeq ($(ARCH),ia64) OBJS += ia64-syscall.o @@ -140,7 +147,7 @@ FILES= \ README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ Makefile elf.h thunk.c\ -elfload.c main.c signal.c thunk.h\ +elfload.c main.c signal.c thunk.h exec.h\ cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ syscall.c opreg_template.h syscall_defs.h vm86.c\ dis-asm.h dis-buf.c disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c\ -- cgit v1.2.3 From 85e53d4108ea1ea0179706ae59e9b573c14dd549 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 May 2003 16:41:52 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@181 c046a42c-6fe2-441c-8c8c-71466251a162 --- COPYING.LIB | 234 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/COPYING.LIB b/COPYING.LIB index 8d4919ee9..223ede7de 100644 --- a/COPYING.LIB +++ b/COPYING.LIB @@ -1,36 +1,14 @@ ------------------------------------------------------------------------------- -NOTE: -Some code of the Twin package was modified for DOSEMU by the DOSEMU-team. -The original is 'Copyright 1997 Willows Software, Inc.' and generously -was put under the GNU Library General Public License. -( for more information see http://www.willows.com/ ) - -We make use of section 3 of the GNU Library General Public License -('...opt to apply the terms of the ordinary GNU General Public License...'), -because the resulting product is an integrated part of DOSEMU and -can not be considered to be a 'library' in the terms of Library License. - -Therefore, the below GNU LIBRARY GENERAL PUBLIC LICENSE applies only to the -_unchanged_ Twin package from Willows. For the DOSEMU-changed parts the normal -GNU GENERAL PUBLIC LICENSE applies. This GPL (file COPYING) can be found in -the root directory of the DOSEMU distribution. - -The act of transformation to GPL was indicated to the maintainer of the Twin -package (Rob Penrose ) and he acknowledge agreement. - -Nov. 1 1997, The DOSEMU team. - ------------------------------------------------------------------------------- - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 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 library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] Preamble @@ -39,97 +17,109 @@ freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - 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. + 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 -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. + 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, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. - GNU LIBRARY GENERAL PUBLIC LICENSE + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs @@ -278,7 +268,7 @@ distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - 6. As an exception to the Sections above, you may also compile or + 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit @@ -305,23 +295,31 @@ of these things: Library will not necessarily be able to recompile the application to use the modified definitions.) - b) Accompany the work with a written offer, valid for at + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. - c) If distribution of the work is made by offering access to copy + d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. - d) Verify that the user has already received a copy of these + e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. @@ -370,7 +368,7 @@ Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to +You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent @@ -413,7 +411,7 @@ excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. +versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. @@ -459,7 +457,7 @@ DAMAGES. END OF TERMS AND CONDITIONS - Appendix: How to Apply These Terms to Your New Libraries + How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that @@ -476,18 +474,18 @@ convey the exclusion of warranty; and each file should have at least the Copyright (C) This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public + modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. @@ -502,3 +500,5 @@ necessary. Here is a sample; alter the names: Ty Coon, President of Vice That's all there is to it! + + -- cgit v1.2.3 From 08351fb37ae0abe0d0a025ad67709f1f1fd63d59 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 May 2003 16:42:20 +0000 Subject: fixed cast git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@182 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disas.c b/disas.c index b62644886..4b44e0678 100644 --- a/disas.c +++ b/disas.c @@ -51,7 +51,7 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type) for (pc = code; pc < (uint8_t *)code + size; pc += count) { fprintf(out, "0x%08lx: ", (long)pc); - count = print_insn((long)pc, &disasm_info); + count = print_insn((unsigned long)pc, &disasm_info); fprintf(out, "\n"); if (count < 0) break; -- cgit v1.2.3 From d4e8164f7e9342d692c1d6f1c848ed05f8007ece Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 May 2003 16:46:15 +0000 Subject: direct chaining for PowerPC and i386 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@183 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 96 ++++++++++++++++---- exec-i386.c | 38 +++++--- exec-i386.h | 2 + exec.c | 111 ++++++++++++++++++++--- exec.h | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ op-i386.c | 128 ++++++++++----------------- opc-i386.h | 49 +++++------ ops_template.h | 24 ++--- translate-i386.c | 118 ++++++++++++++----------- 9 files changed, 620 insertions(+), 210 deletions(-) create mode 100644 exec.h diff --git a/dyngen.c b/dyngen.c index f037d8759..96a47c8ed 100644 --- a/dyngen.c +++ b/dyngen.c @@ -170,7 +170,16 @@ void elf_swap_phdr(struct elf_phdr *h) swabls(&h->p_align); /* Segment alignment */ } +/* ELF file info */ int do_swap; +struct elf_shdr *shdr; +struct elfhdr ehdr; +ElfW(Sym) *symtab; +int nb_syms; +char *strtab; +/* data section */ +uint8_t *data_data; +int data_shndx; uint16_t get16(uint16_t *p) { @@ -270,7 +279,7 @@ int strstart(const char *str, const char *val, const char **ptr) /* generate op code */ void gen_code(const char *name, host_ulong offset, host_ulong size, FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type, - ElfW(Sym) *symtab, char *strtab, int gen_switch) + int gen_switch) { int copy_size = 0; uint8_t *p_start, *p_end; @@ -291,13 +300,16 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(ELF_ARCH) { case EM_386: { - uint8_t *p; - p = p_end - 1; - if (p == p_start) + int len; + len = p_end - p_start; + if (len == 0) error("empty code for %s", name); - if (p[0] != 0xc3) - error("ret expected at the end of %s", name); - copy_size = p - p_start; + if (p_end[-1] == 0xc3) { + len--; + } else { + error("ret or jmp expected at the end of %s", name); + } + copy_size = len; } break; case EM_PPC: @@ -423,7 +435,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { n = strtoul(p, NULL, 10); - if (n >= MAX_ARGS) + if (n > MAX_ARGS) error("too many arguments in %s", name); args_present[n - 1] = 1; } @@ -459,7 +471,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - if (*sym_name && !strstart(sym_name, "__op_param", &p)) { + if (*sym_name && + !strstart(sym_name, "__op_param", NULL) && + !strstart(sym_name, "__op_jmp", NULL)) { #if defined(HOST_SPARC) if (sym_name[0] == '.') { fprintf(outfile, @@ -474,6 +488,31 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, start_offset - offset, copy_size); + + /* emit code offset information */ + { + ElfW(Sym) *sym; + const char *sym_name, *p; + target_ulong val; + int n; + + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + sym_name = strtab + sym->st_name; + if (strstart(sym_name, "__op_label", &p)) { + /* test if the variable refers to a label inside + the code we are generating */ + if (sym->st_shndx != data_shndx) + error("__op_labelN symbols must be in .data or .sdata section"); + val = *(target_ulong *)(data_data + sym->st_value); + if (val >= start_offset && val < start_offset + copy_size) { + n = strtol(p, NULL, 10); + fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); + } + } + } + } + + /* load parameres in variables */ for(i = 0; i < nb_args; i++) { fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1); } @@ -519,6 +558,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_jmp", &p)) { + int n; + n = strtol(p, NULL, 10); + /* __op_jmp relocations are done at + runtime to do translated block + chaining: the offset of the instruction + needs to be stored */ + fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", + n, rel->r_offset - start_offset); + continue; + } + if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); } else { @@ -824,11 +875,10 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int load_elf(const char *filename, FILE *outfile, int do_print_enum) { int fd; - struct elfhdr ehdr; - struct elf_shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec; - int i, j, nb_syms; - ElfW(Sym) *symtab, *sym; - char *shstr, *strtab; + struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec; + int i, j; + ElfW(Sym) *sym; + char *shstr, *data_name; uint8_t *text; void *relocs; int nb_relocs, reloc_sh_type; @@ -880,6 +930,17 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) error("could not find .text section"); text = load_data(fd, text_sec->sh_offset, text_sec->sh_size); +#if defined(HOST_PPC) + data_name = ".sdata"; +#else + data_name = ".data"; +#endif + sec = find_elf_section(shdr, ehdr.e_shnum, shstr, data_name); + if (!sec) + error("could not find %s section", data_name); + data_shndx = sec - shdr; + data_data = load_data(fd, sec->sh_offset, sec->sh_size); + /* find text relocations, if any */ nb_relocs = 0; relocs = NULL; @@ -936,7 +997,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) name = strtab + sym->st_name; if (strstart(name, OP_PREFIX, &p)) { gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 2); + text, relocs, nb_relocs, reloc_sh_type, 2); } } } else { @@ -963,6 +1024,7 @@ fprintf(outfile, #endif fprintf(outfile, "int dyngen_code(uint8_t *gen_code_buf,\n" +" uint16_t *label_offsets, uint16_t *jmp_offsets,\n" " const uint16_t *opc_buf, const uint32_t *opparam_buf)\n" "{\n" " uint8_t *gen_code_ptr;\n" @@ -1001,7 +1063,7 @@ fprintf(outfile, if (sym->st_shndx != (text_sec - shdr)) error("invalid section for opcode (0x%x)", sym->st_shndx); gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 1); + text, relocs, nb_relocs, reloc_sh_type, 1); } } @@ -1056,7 +1118,7 @@ fprintf(outfile, if (sym->st_shndx != (text_sec - shdr)) error("invalid section for opcode (0x%x)", sym->st_shndx); gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 0); + text, relocs, nb_relocs, reloc_sh_type, 0); } } } diff --git a/exec-i386.c b/exec-i386.c index 7575123ec..978b1da9d 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -120,7 +120,7 @@ int cpu_x86_exec(CPUX86State *env1) TranslationBlock *tb, **ptb; uint8_t *tc_ptr, *cs_base, *pc; unsigned int flags; - + /* first we save global registers */ saved_T0 = T0; saved_T1 = T1; @@ -169,6 +169,7 @@ int cpu_x86_exec(CPUX86State *env1) /* prepare setjmp context for exception handling */ if (setjmp(env->jmp_env) == 0) { + T0 = 0; /* force lookup of first TB */ for(;;) { if (env->interrupt_request) { raise_exception(EXCP_INTERRUPT); @@ -209,30 +210,40 @@ int cpu_x86_exec(CPUX86State *env1) flags |= (env->eflags & TF_MASK) << (GEN_FLAG_TF_SHIFT - 8); cs_base = env->seg_cache[R_CS].base; pc = cs_base + env->eip; + spin_lock(&tb_lock); tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, flags); if (!tb) { /* if no translated code available, then translate it now */ - /* very inefficient but safe: we lock all the cpus - when generating code */ - spin_lock(&tb_lock); + tb = tb_alloc((unsigned long)pc); + if (!tb) { + /* flush must be done */ + tb_flush(); + /* cannot fail at this point */ + tb = tb_alloc((unsigned long)pc); + /* don't forget to invalidate previous TB info */ + ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; + T0 = 0; + } tc_ptr = code_gen_ptr; + tb->tc_ptr = tc_ptr; ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, &code_gen_size, pc, cs_base, flags, - &code_size); + &code_size, tb); /* if invalid instruction, signal it */ if (ret != 0) { + /* NOTE: the tb is allocated but not linked, so we + can leave it */ spin_unlock(&tb_lock); raise_exception(EXCP06_ILLOP); } - tb = tb_alloc((unsigned long)pc, code_size); *ptb = tb; + tb->size = code_size; tb->cs_base = (unsigned long)cs_base; tb->flags = flags; - tb->tc_ptr = tc_ptr; tb->hash_next = NULL; + tb_link(tb); code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); - spin_unlock(&tb_lock); } #ifdef DEBUG_EXEC if (loglevel) { @@ -241,14 +252,21 @@ int cpu_x86_exec(CPUX86State *env1) lookup_symbol((void *)tb->pc)); } #endif - /* execute the generated code */ + + /* see if we can patch the calling TB */ + if (T0 != 0 && !(env->eflags & TF_MASK)) { + tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); + } tc_ptr = tb->tc_ptr; + spin_unlock(&tb_lock); + + /* execute the generated code */ gen_func = (void *)tc_ptr; #ifdef __sparc__ __asm__ __volatile__("call %0\n\t" " mov %%o7,%%i0" : /* no outputs */ - : "r" (gen_func) + : "r" (gen_func) : "i0", "i1", "i2", "i3", "i4", "i5"); #else gen_func(); diff --git a/exec-i386.h b/exec-i386.h index 322b7f3d1..938680d1e 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -205,8 +205,10 @@ extern int __op_param1, __op_param2, __op_param3; #define PARAM2 ((long)(&__op_param2)) #define PARAM3 ((long)(&__op_param3)) #endif +extern int __op_jmp0, __op_jmp1; #include "cpu-i386.h" +#include "exec.h" typedef struct CCTable { int (*compute_all)(void); /* return all the flags */ diff --git a/exec.c b/exec.c index 936424ad8..8f332c9ae 100644 --- a/exec.c +++ b/exec.c @@ -27,6 +27,7 @@ #include #include "cpu-i386.h" +#include "exec.h" //#define DEBUG_TB_INVALIDATE #define DEBUG_FLUSH @@ -212,6 +213,7 @@ static void page_flush_tb(void) } /* flush all the translation blocks */ +/* XXX: tb_flush is currently not thread safe */ void tb_flush(void) { int i; @@ -226,7 +228,8 @@ void tb_flush(void) tb_hash[i] = NULL; page_flush_tb(); code_gen_ptr = code_gen_buffer; - /* XXX: flush processor icache at this point */ + /* XXX: flush processor icache at this point if cache flush is + expensive */ } #ifdef DEBUG_TB_CHECK @@ -265,6 +268,26 @@ static void tb_page_check(void) } } +void tb_jmp_check(TranslationBlock *tb) +{ + TranslationBlock *tb1; + unsigned int n1; + + /* suppress any remaining jumps to this TB */ + tb1 = tb->jmp_first; + for(;;) { + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == 2) + break; + tb1 = tb1->jmp_next[n1]; + } + /* check end of list */ + if (tb1 != tb) { + printf("ERROR: jmp_list from 0x%08lx\n", (long)tb); + } +} + #endif /* invalidate one TB */ @@ -282,12 +305,48 @@ static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb, } } +static inline void tb_jmp_remove(TranslationBlock *tb, int n) +{ + TranslationBlock *tb1, **ptb; + unsigned int n1; + + ptb = &tb->jmp_next[n]; + tb1 = *ptb; + if (tb1) { + /* find tb(n) in circular list */ + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == n && tb1 == tb) + break; + if (n1 == 2) { + ptb = &tb1->jmp_first; + } else { + ptb = &tb1->jmp_next[n1]; + } + } + /* now we can suppress tb(n) from the list */ + *ptb = tb->jmp_next[n]; + + tb->jmp_next[n] = NULL; + } +} + +/* reset the jump entry 'n' of a TB so that it is not chained to + another TB */ +static inline void tb_reset_jump(TranslationBlock *tb, int n) +{ + tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); +} + static inline void tb_invalidate(TranslationBlock *tb, int parity) { PageDesc *p; unsigned int page_index1, page_index2; - unsigned int h; - + unsigned int h, n1; + TranslationBlock *tb1, *tb2; + /* remove the TB from the hash list */ h = tb_hash_func(tb->pc); tb_remove(&tb_hash[h], tb, @@ -305,6 +364,24 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity) tb_remove(&p->first_tb, tb, offsetof(TranslationBlock, page_next[page_index2 & 1])); } + + /* suppress this TB from the two jump lists */ + tb_jmp_remove(tb, 0); + tb_jmp_remove(tb, 1); + + /* suppress any remaining jumps to this TB */ + tb1 = tb->jmp_first; + for(;;) { + n1 = (long)tb1 & 3; + if (n1 == 2) + break; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + tb2 = tb1->jmp_next[n1]; + tb_reset_jump(tb1, n1); + tb1->jmp_next[n1] = NULL; + tb1 = tb2; + } + tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ } /* invalidate all TBs which intersect with the target page starting at addr */ @@ -367,27 +444,39 @@ static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index) /* Allocate a new translation block. Flush the translation buffer if too many translation blocks or too much generated code. */ -TranslationBlock *tb_alloc(unsigned long pc, - unsigned long size) +TranslationBlock *tb_alloc(unsigned long pc) { TranslationBlock *tb; - unsigned int page_index1, page_index2; if (nb_tbs >= CODE_GEN_MAX_BLOCKS || (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) - tb_flush(); + return NULL; tb = &tbs[nb_tbs++]; tb->pc = pc; - tb->size = size; + return tb; +} + +/* link the tb with the other TBs */ +void tb_link(TranslationBlock *tb) +{ + unsigned int page_index1, page_index2; /* add in the page list */ - page_index1 = pc >> TARGET_PAGE_BITS; + page_index1 = tb->pc >> TARGET_PAGE_BITS; tb_alloc_page(tb, page_index1); - page_index2 = (pc + size - 1) >> TARGET_PAGE_BITS; + page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS; if (page_index2 != page_index1) { tb_alloc_page(tb, page_index2); } - return tb; + tb->jmp_first = (TranslationBlock *)((long)tb | 2); + tb->jmp_next[0] = NULL; + tb->jmp_next[1] = NULL; + + /* init original jump addresses */ + if (tb->tb_next_offset[0] != 0xffff) + tb_reset_jump(tb, 0); + if (tb->tb_next_offset[1] != 0xffff) + tb_reset_jump(tb, 1); } /* called from signal handler: invalidate the code and unprotect the diff --git a/exec.h b/exec.h new file mode 100644 index 000000000..c6a6d1b23 --- /dev/null +++ b/exec.h @@ -0,0 +1,264 @@ +/* + * internal execution defines for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define GEN_FLAG_CODE32_SHIFT 0 +#define GEN_FLAG_ADDSEG_SHIFT 1 +#define GEN_FLAG_SS32_SHIFT 2 +#define GEN_FLAG_VM_SHIFT 3 +#define GEN_FLAG_ST_SHIFT 4 +#define GEN_FLAG_CPL_SHIFT 7 +#define GEN_FLAG_IOPL_SHIFT 9 +#define GEN_FLAG_TF_SHIFT 11 + +struct TranslationBlock; +int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, + int *gen_code_size_ptr, + uint8_t *pc_start, uint8_t *cs_base, int flags, + int *code_size_ptr, struct TranslationBlock *tb); +void cpu_x86_tblocks_init(void); +void page_init(void); +int page_unprotect(unsigned long address); + +#define CODE_GEN_MAX_SIZE 65536 +#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ + +#define CODE_GEN_HASH_BITS 15 +#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) + +/* maximum total translate dcode allocated */ +#define CODE_GEN_BUFFER_SIZE (2048 * 1024) +//#define CODE_GEN_BUFFER_SIZE (128 * 1024) + +#if defined(__powerpc__) +#define USE_DIRECT_JUMP +#endif + +typedef struct TranslationBlock { + unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ + unsigned long cs_base; /* CS base for this block */ + unsigned int flags; /* flags defining in which context the code was generated */ + uint16_t size; /* size of target code for this block (1 <= + size <= TARGET_PAGE_SIZE) */ + uint8_t *tc_ptr; /* pointer to the translated code */ + struct TranslationBlock *hash_next; /* next matching block */ + struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */ + /* the following data are used to directly call another TB from + the code of this one. */ + uint16_t tb_next_offset[2]; /* offset of original jump target */ +#ifdef USE_DIRECT_JUMP + uint16_t tb_jmp_offset[2]; /* offset of jump instruction */ +#else + uint8_t *tb_next[2]; /* address of jump generated code */ +#endif + /* list of TBs jumping to this one. This is a circular list using + the two least significant bits of the pointers to tell what is + the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 = + jmp_first */ + struct TranslationBlock *jmp_next[2]; + struct TranslationBlock *jmp_first; +} TranslationBlock; + +static inline unsigned int tb_hash_func(unsigned long pc) +{ + return pc & (CODE_GEN_HASH_SIZE - 1); +} + +TranslationBlock *tb_alloc(unsigned long pc); +void tb_flush(void); +void tb_link(TranslationBlock *tb); + +extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; + +extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; +extern uint8_t *code_gen_ptr; + +/* find a translation block in the translation cache. If not found, + return NULL and the pointer to the last element of the list in pptb */ +static inline TranslationBlock *tb_find(TranslationBlock ***pptb, + unsigned long pc, + unsigned long cs_base, + unsigned int flags) +{ + TranslationBlock **ptb, *tb; + unsigned int h; + + h = tb_hash_func(pc); + ptb = &tb_hash[h]; + for(;;) { + tb = *ptb; + if (!tb) + break; + if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) + return tb; + ptb = &tb->hash_next; + } + *pptb = ptb; + return NULL; +} + +#if defined(__powerpc__) + +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + uint32_t val, *ptr; + unsigned long offset; + + offset = (unsigned long)(tb->tc_ptr + tb->tb_jmp_offset[n]); + + /* patch the branch destination */ + ptr = (uint32_t *)offset; + val = *ptr; + val = (val & ~0x03fffffc) | ((addr - offset) & 0x03fffffc); + *ptr = val; + /* flush icache */ + asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory"); + asm volatile ("sync" : : : "memory"); + asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory"); + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} + +#else + +/* set the jump target */ +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + tb->tb_next[n] = (void *)addr; +} + +#endif + +static inline void tb_add_jump(TranslationBlock *tb, int n, + TranslationBlock *tb_next) +{ + /* patch the native jump address */ + tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); + + /* add in TB jmp circular list */ + tb->jmp_next[n] = tb_next->jmp_first; + tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); +} + +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif + +#ifdef __powerpc__ +static inline int testandset (int *p) +{ + int ret; + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r" (ret) + : "r" (p), "r" (1), "r" (0) + : "cr0", "memory"); + return ret; +} +#endif + +#ifdef __i386__ +static inline int testandset (int *p) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (1), "m" (*p), "a" (0) + : "memory"); + return ret; +} +#endif + +#ifdef __s390__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" + " jl 0b" + : "=&d" (ret) + : "r" (1), "a" (p), "0" (*p) + : "cc", "memory" ); + return ret; +} +#endif + +#ifdef __alpha__ +int testandset (int *p) +{ + int ret; + unsigned long one; + + __asm__ __volatile__ ("0: mov 1,%2\n" + " ldl_l %0,%1\n" + " stl_c %2,%1\n" + " beq %2,1f\n" + ".subsection 2\n" + "1: br 0b\n" + ".previous" + : "=r" (ret), "=m" (*p), "=r" (one) + : "m" (*p)); + return ret; +} +#endif + +#ifdef __sparc__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (ret) + : "r" (p) + : "memory"); + + return (ret ? 1 : 0); +} +#endif + +typedef int spinlock_t; + +#define SPIN_LOCK_UNLOCKED 0 + +static inline void spin_lock(spinlock_t *lock) +{ + while (testandset(lock)); +} + +static inline void spin_unlock(spinlock_t *lock) +{ + *lock = 0; +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return !testandset(lock); +} + +extern spinlock_t tb_lock; + diff --git a/op-i386.c b/op-i386.c index 64cbe708a..cfae10363 100644 --- a/op-i386.c +++ b/op-i386.c @@ -709,7 +709,44 @@ void OPPROTO op_cmpxchg8b(void) FORCE_RET(); } -/* string ops */ +#if defined(__powerpc__) + +/* on PowerPC we patch the jump instruction directly */ +#define JUMP_TB(tbparam, n, eip)\ +do {\ + static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ + asm volatile ("b %0" : : "i" (&__op_jmp ## n));\ +label ## n:\ + T0 = (long)(tbparam) + (n);\ + EIP = eip;\ +} while (0) + +#else + +/* jump to next block operations (more portable code, does not need + cache flushing, but slower because of indirect jump) */ +#define JUMP_TB(tbparam, n, eip)\ +do {\ + static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ + goto *((TranslationBlock *)tbparam)->tb_next[n];\ +label ## n:\ + T0 = (long)(tbparam) + (n);\ + EIP = eip;\ +} while (0) + +#endif + +void OPPROTO op_jmp_tb_next(void) +{ + JUMP_TB(PARAM1, 0, PARAM2); +} + +void OPPROTO op_movl_T0_0(void) +{ + T0 = 0; +} + +/* multiple size ops */ #define ldul ldl @@ -1199,90 +1236,15 @@ void OPPROTO op_lar(void) /* flags handling */ -/* slow jumps cases (compute x86 flags) */ -void OPPROTO op_jo_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_O) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO op_jb_cc(void) -{ - if (cc_table[CC_OP].compute_c()) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO op_jz_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_Z) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO op_jbe_cc(void) +/* slow jumps cases : in order to avoid calling a function with a + pointer (which can generate a stack frame on PowerPC), we use + op_setcc to set T0 and then call op_jcc. */ +void OPPROTO op_jcc(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & (CC_Z | CC_C)) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO op_js_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_S) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO op_jp_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_P) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO op_jl_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if ((eflags ^ (eflags >> 4)) & 0x80) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO op_jle_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) - EIP = PARAM1; + if (T0) + JUMP_TB(PARAM1, 0, PARAM2); else - EIP = PARAM2; + JUMP_TB(PARAM1, 1, PARAM3); FORCE_RET(); } diff --git a/opc-i386.h b/opc-i386.h index 6cfb42e88..e658d4f79 100644 --- a/opc-i386.h +++ b/opc-i386.h @@ -231,18 +231,20 @@ DEF(jmp_T0, 0) DEF(jmp_im, 1) DEF(int_im, 2) DEF(raise_exception, 1) -DEF(into, 0) +DEF(into, 1) DEF(cli, 0) DEF(sti, 0) DEF(boundw, 0) DEF(boundl, 0) DEF(cmpxchg8b, 0) -DEF(jb_subb, 2) -DEF(jz_subb, 2) -DEF(jbe_subb, 2) -DEF(js_subb, 2) -DEF(jl_subb, 2) -DEF(jle_subb, 2) +DEF(jmp_tb_next, 2) +DEF(movl_T0_0, 0) +DEF(jb_subb, 3) +DEF(jz_subb, 3) +DEF(jbe_subb, 3) +DEF(js_subb, 3) +DEF(jl_subb, 3) +DEF(jle_subb, 3) DEF(setb_T0_subb, 0) DEF(setz_T0_subb, 0) DEF(setbe_T0_subb, 0) @@ -314,12 +316,12 @@ DEF(insb_a16, 0) DEF(rep_insb_a16, 0) DEF(outb_T0_T1, 0) DEF(inb_T0_T1, 0) -DEF(jb_subw, 2) -DEF(jz_subw, 2) -DEF(jbe_subw, 2) -DEF(js_subw, 2) -DEF(jl_subw, 2) -DEF(jle_subw, 2) +DEF(jb_subw, 3) +DEF(jz_subw, 3) +DEF(jbe_subw, 3) +DEF(js_subw, 3) +DEF(jl_subw, 3) +DEF(jle_subw, 3) DEF(loopnzw, 2) DEF(loopzw, 2) DEF(loopw, 2) @@ -405,12 +407,12 @@ DEF(insw_a16, 0) DEF(rep_insw_a16, 0) DEF(outw_T0_T1, 0) DEF(inw_T0_T1, 0) -DEF(jb_subl, 2) -DEF(jz_subl, 2) -DEF(jbe_subl, 2) -DEF(js_subl, 2) -DEF(jl_subl, 2) -DEF(jle_subl, 2) +DEF(jb_subl, 3) +DEF(jz_subl, 3) +DEF(jbe_subl, 3) +DEF(js_subl, 3) +DEF(jl_subl, 3) +DEF(jle_subl, 3) DEF(loopnzl, 2) DEF(loopzl, 2) DEF(loopl, 2) @@ -536,14 +538,7 @@ DEF(movl_A0_seg, 1) DEF(addl_A0_seg, 1) DEF(lsl, 0) DEF(lar, 0) -DEF(jo_cc, 2) -DEF(jb_cc, 2) -DEF(jz_cc, 2) -DEF(jbe_cc, 2) -DEF(js_cc, 2) -DEF(jp_cc, 2) -DEF(jl_cc, 2) -DEF(jle_cc, 2) +DEF(jcc, 3) DEF(seto_T0_cc, 0) DEF(setb_T0_cc, 0) DEF(setz_T0_cc, 0) diff --git a/ops_template.h b/ops_template.h index 7adf7be6a..ff28086f3 100644 --- a/ops_template.h +++ b/ops_template.h @@ -238,18 +238,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_TYPE)src1 < (DATA_TYPE)src2) - EIP = PARAM1; + JUMP_TB(PARAM1, 0, PARAM2); else - EIP = PARAM2; + JUMP_TB(PARAM1, 1, PARAM3); FORCE_RET(); } void OPPROTO glue(op_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST == 0) - EIP = PARAM1; + JUMP_TB(PARAM1, 0, PARAM2); else - EIP = PARAM2; + JUMP_TB(PARAM1, 1, PARAM3); FORCE_RET(); } @@ -260,18 +260,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) - EIP = PARAM1; + JUMP_TB(PARAM1, 0, PARAM2); else - EIP = PARAM2; + JUMP_TB(PARAM1, 1, PARAM3); FORCE_RET(); } void OPPROTO glue(op_js_sub, SUFFIX)(void) { if (CC_DST & SIGN_MASK) - EIP = PARAM1; + JUMP_TB(PARAM1, 0, PARAM2); else - EIP = PARAM2; + JUMP_TB(PARAM1, 1, PARAM3); FORCE_RET(); } @@ -282,9 +282,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_STYPE)src1 < (DATA_STYPE)src2) - EIP = PARAM1; + JUMP_TB(PARAM1, 0, PARAM2); else - EIP = PARAM2; + JUMP_TB(PARAM1, 1, PARAM3); FORCE_RET(); } @@ -295,9 +295,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) src2 = CC_SRC - CC_DST; if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) - EIP = PARAM1; + JUMP_TB(PARAM1, 0, PARAM2); else - EIP = PARAM2; + JUMP_TB(PARAM1, 1, PARAM3); FORCE_RET(); } diff --git a/translate-i386.c b/translate-i386.c index 32e188bbb..9ef7a3b05 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -31,11 +31,15 @@ #define IN_OP_I386 #include "cpu-i386.h" +#include "exec.h" /* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; int __op_param1, __op_param2, __op_param3; +#ifdef USE_DIRECT_JUMP +int __op_jmp0, __op_jmp1; +#endif #ifdef __i386__ static inline void flush_icache_range(unsigned long start, unsigned long stop) @@ -67,14 +71,14 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { - asm ("dcbst 0,%0;" : : "r"(p) : "memory"); + asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); } - asm ("sync"); + asm volatile ("sync" : : : "memory"); for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { - asm ("icbi 0,%0; sync;" : : "r"(p) : "memory"); + asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); } - asm ("sync"); - asm ("isync"); + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); } #endif @@ -129,6 +133,7 @@ typedef struct DisasContext { int cpl; int iopl; int tf; /* TF cpu flag */ + TranslationBlock *tb; } DisasContext; /* i386 arith/logic operations */ @@ -192,6 +197,7 @@ enum { typedef void (GenOpFunc)(void); typedef void (GenOpFunc1)(long); typedef void (GenOpFunc2)(long, long); +typedef void (GenOpFunc3)(long, long, long); static GenOpFunc *gen_op_mov_reg_T0[3][8] = { [OT_BYTE] = { @@ -699,18 +705,7 @@ enum { JCC_LE, }; -static GenOpFunc2 *gen_jcc_slow[8] = { - gen_op_jo_cc, - gen_op_jb_cc, - gen_op_jz_cc, - gen_op_jbe_cc, - gen_op_js_cc, - gen_op_jp_cc, - gen_op_jl_cc, - gen_op_jle_cc, -}; - -static GenOpFunc2 *gen_jcc_sub[3][8] = { +static GenOpFunc3 *gen_jcc_sub[3][8] = { [OT_BYTE] = { NULL, gen_op_jb_subb, @@ -1090,8 +1085,9 @@ static inline uint32_t insn_get(DisasContext *s, int ot) static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) { + TranslationBlock *tb; int inv, jcc_op; - GenOpFunc2 *func; + GenOpFunc3 *func; inv = b & 1; jcc_op = (b >> 1) & 7; @@ -1101,8 +1097,6 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) case CC_OP_SUBW: case CC_OP_SUBL: func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; - if (!func) - goto slow_jcc; break; /* some jumps are easy to compute */ @@ -1138,21 +1132,30 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; break; default: - goto slow_jcc; + func = NULL; + break; } break; default: - slow_jcc: - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - func = gen_jcc_slow[jcc_op]; + func = NULL; break; } + + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + + if (!func) { + gen_setcc_slow[jcc_op](); + func = gen_op_jcc; + } + + tb = s->tb; if (!inv) { - func(val, next_eip); + func((long)tb, val, next_eip); } else { - func(next_eip, val); + func((long)tb, next_eip, val); } + s->is_jmp = 3; } static void gen_setcc(DisasContext *s, int b) @@ -1372,6 +1375,18 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) s->is_jmp = 1; } +/* generate a jump to eip. No segment change must happen before as a + direct call to the next block may occur */ +static void gen_jmp(DisasContext *s, unsigned int eip) +{ + TranslationBlock *tb = s->tb; + + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_tb_next((long)tb, eip); + s->is_jmp = 3; +} + /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr is set to true if the instruction sets the PC (last instruction of a basic block) */ @@ -2964,8 +2979,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val &= 0xffff; gen_op_movl_T0_im(next_eip); gen_push_T0(s); - gen_op_jmp_im(val); - s->is_jmp = 1; + gen_jmp(s, val); } break; case 0x9a: /* lcall im */ @@ -2996,8 +3010,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val += s->pc - s->cs_base; if (s->dflag == 0) val = val & 0xffff; - gen_op_jmp_im(val); - s->is_jmp = 1; + gen_jmp(s, val); break; case 0xea: /* ljmp im */ { @@ -3019,8 +3032,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val += s->pc - s->cs_base; if (s->dflag == 0) val = val & 0xffff; - gen_op_jmp_im(val); - s->is_jmp = 1; + gen_jmp(s, val); break; case 0x70 ... 0x7f: /* jcc Jb */ val = (int8_t)insn_get(s, OT_BYTE); @@ -3037,7 +3049,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->dflag == 0) val &= 0xffff; gen_jcc(s, b, val, next_eip); - s->is_jmp = 1; break; case 0x190 ... 0x19f: /* setcc Gv */ @@ -3393,15 +3404,6 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_into] = CC_O, - [INDEX_op_jo_cc] = CC_O, - [INDEX_op_jb_cc] = CC_C, - [INDEX_op_jz_cc] = CC_Z, - [INDEX_op_jbe_cc] = CC_Z | CC_C, - [INDEX_op_js_cc] = CC_S, - [INDEX_op_jp_cc] = CC_P, - [INDEX_op_jl_cc] = CC_O | CC_S, - [INDEX_op_jle_cc] = CC_O | CC_S | CC_Z, - [INDEX_op_jb_subb] = CC_C, [INDEX_op_jb_subw] = CC_C, [INDEX_op_jb_subl] = CC_C, @@ -3730,7 +3732,7 @@ static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int *gen_code_size_ptr, uint8_t *pc_start, uint8_t *cs_base, int flags, - int *code_size_ptr) + int *code_size_ptr, TranslationBlock *tb) { DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; @@ -3750,6 +3752,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; + dc->tb = tb; gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; @@ -3776,15 +3779,21 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); /* we must store the eflags state if it is not already done */ - if (dc->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(dc->cc_op); - if (dc->is_jmp != 1) { - /* we add an additionnal jmp to update the simulated PC */ - gen_op_jmp_im(ret - (unsigned long)dc->cs_base); + if (dc->is_jmp != 3) { + if (dc->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(dc->cc_op); + if (dc->is_jmp != 1) { + /* we add an additionnal jmp to update the simulated PC */ + gen_op_jmp_im(ret - (unsigned long)dc->cs_base); + } } if (dc->tf) { gen_op_raise_exception(EXCP01_SSTP); } + if (dc->is_jmp != 3) { + /* indicate that the hash table must be used to find the next TB */ + gen_op_movl_T0_0(); + } *gen_opc_ptr = INDEX_op_end; @@ -3814,8 +3823,17 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, #endif /* generate machine code */ - gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf); + tb->tb_next_offset[0] = 0xffff; + tb->tb_next_offset[1] = 0xffff; + gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, +#ifdef USE_DIRECT_JUMP + tb->tb_jmp_offset, +#else + NULL, +#endif + gen_opc_buf, gen_opparam_buf); flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); + *gen_code_size_ptr = gen_code_size; *code_size_ptr = pc_ptr - pc_start; #ifdef DEBUG_DISAS -- cgit v1.2.3 From d1fe2b245910d42715e556458afe7d975d9417ef Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 May 2003 16:47:16 +0000 Subject: self modifying code also tests translation block chaining invalidation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@184 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 50c2d5b2c..4629105c7 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1218,15 +1218,18 @@ uint8_t code[] = { 0xc3, /* ret */ }; +typedef int FuncType(void); + void test_self_modifying_code(void) { - int (*func)(void); + int i; - func = (void *)code; printf("self modifying code:\n"); - printf("func1 = 0x%x\n", func()); - code[1] = 0x2; - printf("func1 = 0x%x\n", func()); + printf("func1 = 0x%x\n", ((FuncType *)code)()); + for(i = 2; i <= 4; i++) { + code[1] = i; + printf("func%d = 0x%x\n", i, ((FuncType *)code)()); + } } static void *call_end __init_call = NULL; -- cgit v1.2.3 From 0ca790b92e1912b7d465deddaef31d9a783da4b9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 May 2003 16:51:57 +0000 Subject: direct chaining for PowerPC and i386 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@185 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 183 ------------------------------------------------------------- 1 file changed, 183 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index 008ff8cd2..fbe7965b4 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -459,187 +459,4 @@ int page_get_flags(unsigned long address); void page_set_flags(unsigned long start, unsigned long end, int flags); void page_unprotect_range(uint8_t *data, unsigned long data_size); -/***************************************************/ -/* internal functions */ - -#define GEN_FLAG_CODE32_SHIFT 0 -#define GEN_FLAG_ADDSEG_SHIFT 1 -#define GEN_FLAG_SS32_SHIFT 2 -#define GEN_FLAG_VM_SHIFT 3 -#define GEN_FLAG_ST_SHIFT 4 -#define GEN_FLAG_CPL_SHIFT 7 -#define GEN_FLAG_IOPL_SHIFT 9 -#define GEN_FLAG_TF_SHIFT 11 - -int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, - int *gen_code_size_ptr, - uint8_t *pc_start, uint8_t *cs_base, int flags, - int *code_size_ptr); -void cpu_x86_tblocks_init(void); -void page_init(void); -int page_unprotect(unsigned long address); - -#define CODE_GEN_MAX_SIZE 65536 -#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ - -#define CODE_GEN_HASH_BITS 15 -#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) - -/* maximum total translate dcode allocated */ -#define CODE_GEN_BUFFER_SIZE (2048 * 1024) -//#define CODE_GEN_BUFFER_SIZE (128 * 1024) - -typedef struct TranslationBlock { - unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ - unsigned long cs_base; /* CS base for this block */ - unsigned int flags; /* flags defining in which context the code was generated */ - uint16_t size; /* size of target code for this block (1 <= - size <= TARGET_PAGE_SIZE) */ - uint8_t *tc_ptr; /* pointer to the translated code */ - struct TranslationBlock *hash_next; /* next matching block */ - struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */ -} TranslationBlock; - -static inline unsigned int tb_hash_func(unsigned long pc) -{ - return pc & (CODE_GEN_HASH_SIZE - 1); -} - -void tb_flush(void); -TranslationBlock *tb_alloc(unsigned long pc, - unsigned long size); - -extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; - -extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; -extern uint8_t *code_gen_ptr; - -/* find a translation block in the translation cache. If not found, - return NULL and the pointer to the last element of the list in pptb */ -static inline TranslationBlock *tb_find(TranslationBlock ***pptb, - unsigned long pc, - unsigned long cs_base, - unsigned int flags) -{ - TranslationBlock **ptb, *tb; - unsigned int h; - - h = tb_hash_func(pc); - ptb = &tb_hash[h]; - for(;;) { - tb = *ptb; - if (!tb) - break; - if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) - return tb; - ptb = &tb->hash_next; - } - *pptb = ptb; - return NULL; -} - -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - -#ifdef __powerpc__ -static inline int testandset (int *p) -{ - int ret; - __asm__ __volatile__ ( - "0: lwarx %0,0,%1 ;" - " xor. %0,%3,%0;" - " bne 1f;" - " stwcx. %2,0,%1;" - " bne- 0b;" - "1: " - : "=&r" (ret) - : "r" (p), "r" (1), "r" (0) - : "cr0", "memory"); - return ret; -} -#endif - -#ifdef __i386__ -static inline int testandset (int *p) -{ - char ret; - long int readval; - - __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" - : "=q" (ret), "=m" (*p), "=a" (readval) - : "r" (1), "m" (*p), "a" (0) - : "memory"); - return ret; -} -#endif - -#ifdef __s390__ -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" - " jl 0b" - : "=&d" (ret) - : "r" (1), "a" (p), "0" (*p) - : "cc", "memory" ); - return ret; -} -#endif - -#ifdef __alpha__ -int testandset (int *p) -{ - int ret; - unsigned long one; - - __asm__ __volatile__ ("0: mov 1,%2\n" - " ldl_l %0,%1\n" - " stl_c %2,%1\n" - " beq %2,1f\n" - ".subsection 2\n" - "1: br 0b\n" - ".previous" - : "=r" (ret), "=m" (*p), "=r" (one) - : "m" (*p)); - return ret; -} -#endif - -#ifdef __sparc__ -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__("ldstub [%1], %0" - : "=r" (ret) - : "r" (p) - : "memory"); - - return (ret ? 1 : 0); -} -#endif - -typedef int spinlock_t; - -#define SPIN_LOCK_UNLOCKED 0 - -static inline void spin_lock(spinlock_t *lock) -{ - while (testandset(lock)); -} - -static inline void spin_unlock(spinlock_t *lock) -{ - *lock = 0; -} - -static inline int spin_trylock(spinlock_t *lock) -{ - return !testandset(lock); -} - -extern spinlock_t tb_lock; - #endif /* CPU_I386_H */ -- cgit v1.2.3 From cf25629d1eafe17cc789b2c5ce73e5c9ef986435 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 May 2003 19:20:31 +0000 Subject: more efficient locking git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@186 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 11 ++++++----- exec.h | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/exec-i386.c b/exec-i386.c index 978b1da9d..68e0371cc 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -206,14 +206,13 @@ int cpu_x86_exec(CPUX86State *env1) flags |= (1 << GEN_FLAG_VM_SHIFT); flags |= (3 << GEN_FLAG_CPL_SHIFT); } - flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT); - flags |= (env->eflags & TF_MASK) << (GEN_FLAG_TF_SHIFT - 8); + flags |= (env->eflags & (IOPL_MASK | TF_MASK)); cs_base = env->seg_cache[R_CS].base; pc = cs_base + env->eip; - spin_lock(&tb_lock); tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, flags); if (!tb) { + spin_lock(&tb_lock); /* if no translated code available, then translate it now */ tb = tb_alloc((unsigned long)pc); if (!tb) { @@ -244,6 +243,7 @@ int cpu_x86_exec(CPUX86State *env1) tb->hash_next = NULL; tb_link(tb); code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); + spin_unlock(&tb_lock); } #ifdef DEBUG_EXEC if (loglevel) { @@ -252,13 +252,14 @@ int cpu_x86_exec(CPUX86State *env1) lookup_symbol((void *)tb->pc)); } #endif - /* see if we can patch the calling TB */ if (T0 != 0 && !(env->eflags & TF_MASK)) { + spin_lock(&tb_lock); tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); + spin_unlock(&tb_lock); } + tc_ptr = tb->tc_ptr; - spin_unlock(&tb_lock); /* execute the generated code */ gen_func = (void *)tc_ptr; diff --git a/exec.h b/exec.h index c6a6d1b23..29a7ab1fd 100644 --- a/exec.h +++ b/exec.h @@ -23,9 +23,9 @@ #define GEN_FLAG_SS32_SHIFT 2 #define GEN_FLAG_VM_SHIFT 3 #define GEN_FLAG_ST_SHIFT 4 -#define GEN_FLAG_CPL_SHIFT 7 -#define GEN_FLAG_IOPL_SHIFT 9 -#define GEN_FLAG_TF_SHIFT 11 +#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */ +#define GEN_FLAG_CPL_SHIFT 9 +#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ struct TranslationBlock; int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, @@ -150,12 +150,15 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, static inline void tb_add_jump(TranslationBlock *tb, int n, TranslationBlock *tb_next) { - /* patch the native jump address */ - tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); - - /* add in TB jmp circular list */ - tb->jmp_next[n] = tb_next->jmp_first; - tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); + /* NOTE: this test is only needed for thread safety */ + if (!tb->jmp_next[n]) { + /* patch the native jump address */ + tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); + + /* add in TB jmp circular list */ + tb->jmp_next[n] = tb_next->jmp_first; + tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); + } } #ifndef offsetof -- cgit v1.2.3 From a37904dd8676be177d9303733a7f0b19a859bf38 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 May 2003 23:10:30 +0000 Subject: fwait fix (aka DOS Navigator fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@187 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index 9ef7a3b05..359fe61e3 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -112,7 +112,6 @@ extern int loglevel; #define PREFIX_LOCK 0x04 #define PREFIX_DATA 0x08 #define PREFIX_ADR 0x10 -#define PREFIX_FWAIT 0x20 typedef struct DisasContext { /* current insn context */ @@ -1440,9 +1439,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x67: prefixes |= PREFIX_ADR; goto next_byte; - case 0x9b: - prefixes |= PREFIX_FWAIT; - goto next_byte; } if (prefixes & PREFIX_DATA) @@ -3256,6 +3252,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* misc */ case 0x90: /* nop */ break; + case 0x9b: /* fwait */ + break; case 0xcc: /* int3 */ gen_exception(s, EXCP03_INT3, s->pc - s->cs_base); break; -- cgit v1.2.3 From e3b32540dfca281e3981f1a429cac203bcb89287 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 May 2003 23:23:22 +0000 Subject: more exception tests - support for precise exceptions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@188 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 73 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 4629105c7..39c7a55a7 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1063,8 +1063,6 @@ void test_vm86(void) #endif jmp_buf jmp_env; -int dump_eip; -int dump_si_addr; int v1; int tab[2]; @@ -1074,23 +1072,21 @@ void sig_handler(int sig, siginfo_t *info, void *puc) printf("si_signo=%d si_errno=%d si_code=%d", info->si_signo, info->si_errno, info->si_code); - if (dump_si_addr) { - printf(" si_addr=0x%08lx", - (unsigned long)info->si_addr); - } + printf(" si_addr=0x%08lx", + (unsigned long)info->si_addr); printf("\n"); printf("trapno=0x%02x err=0x%08x", uc->uc_mcontext.gregs[REG_TRAPNO], uc->uc_mcontext.gregs[REG_ERR]); - if (dump_eip) - printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]); + printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]); printf("\n"); longjmp(jmp_env, 1); } void test_exceptions(void) { + struct modify_ldt_ldt_s ldt; struct sigaction act; volatile int val; @@ -1100,20 +1096,18 @@ void test_exceptions(void) sigaction(SIGFPE, &act, NULL); sigaction(SIGILL, &act, NULL); sigaction(SIGSEGV, &act, NULL); + sigaction(SIGBUS, &act, NULL); sigaction(SIGTRAP, &act, NULL); /* test division by zero reporting */ - dump_eip = 0; - dump_si_addr = 0; - printf("DIVZ exception (currently imprecise):\n"); + printf("DIVZ exception:\n"); if (setjmp(jmp_env) == 0) { /* now divide by zero */ v1 = 0; v1 = 2 / v1; } - dump_si_addr = 1; - printf("BOUND exception (currently imprecise):\n"); + printf("BOUND exception:\n"); if (setjmp(jmp_env) == 0) { /* bound exception */ tab[0] = 1; @@ -1121,27 +1115,50 @@ void test_exceptions(void) asm volatile ("bound %0, %1" : : "r" (11), "m" (tab)); } + printf("segment exceptions:\n"); + if (setjmp(jmp_env) == 0) { + /* load an invalid segment */ + asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 1)); + } + if (setjmp(jmp_env) == 0) { + /* null data segment is valid */ + asm volatile ("movl %0, %%fs" : : "r" (3)); + /* null stack segment */ + asm volatile ("movl %0, %%ss" : : "r" (3)); + } + + ldt.entry_number = 1; + ldt.base_addr = (unsigned long)&seg_data1; + ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; + ldt.seg_32bit = 1; + ldt.contents = MODIFY_LDT_CONTENTS_DATA; + ldt.read_exec_only = 0; + ldt.limit_in_pages = 1; + ldt.seg_not_present = 1; + ldt.useable = 1; + modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ + + if (setjmp(jmp_env) == 0) { + /* segment not present */ + asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); + } + /* test SEGV reporting */ - printf("PF exception (currently imprecise):\n"); + printf("PF exception:\n"); if (setjmp(jmp_env) == 0) { + val = 1; /* now store in an invalid address */ *(char *)0x1234 = 1; } /* test SEGV reporting */ - printf("PF exception (currently imprecise):\n"); + printf("PF exception:\n"); if (setjmp(jmp_env) == 0) { + val = 1; /* read from an invalid address */ v1 = *(char *)0x1234; } - printf("segment GPF exception (currently imprecise):\n"); - if (setjmp(jmp_env) == 0) { - /* load an invalid segment */ - asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0)); - } - - dump_eip = 1; /* test illegal instruction reporting */ printf("UD2 exception:\n"); if (setjmp(jmp_env) == 0) { @@ -1153,6 +1170,18 @@ void test_exceptions(void) if (setjmp(jmp_env) == 0) { asm volatile ("int $0xfd"); } + if (setjmp(jmp_env) == 0) { + asm volatile ("int $0x01"); + } + if (setjmp(jmp_env) == 0) { + asm volatile (".byte 0xcd, 0x03"); + } + if (setjmp(jmp_env) == 0) { + asm volatile ("int $0x04"); + } + if (setjmp(jmp_env) == 0) { + asm volatile ("int $0x05"); + } printf("INT3 exception:\n"); if (setjmp(jmp_env) == 0) { -- cgit v1.2.3 From 5a91de8c902e8de43d80df2db6f056710d414e56 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 May 2003 23:24:27 +0000 Subject: precise exception support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@189 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 186 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 137 insertions(+), 49 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index 359fe61e3..e682d8139 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -160,7 +160,7 @@ enum { }; enum { -#define DEF(s, n) INDEX_op_ ## s, +#define DEF(s, n, copy_size) INDEX_op_ ## s, #include "opc-i386.h" #undef DEF NB_OPS, @@ -1215,9 +1215,13 @@ static void gen_setcc(DisasContext *s, int b) } /* move T0 to seg_reg and compute if the CPU state may change */ -static void gen_movl_seg_T0(DisasContext *s, int seg_reg) +static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) { - gen_op_movl_seg_T0(seg_reg); + if (!s->vm86) + gen_op_movl_seg_T0(seg_reg, cur_eip); + else + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]), + offsetof(CPUX86State,seg_cache[seg_reg].base)); if (!s->addseg && seg_reg < R_FS) s->is_jmp = 2; /* abort translation because the register may have a non zero base */ @@ -1374,6 +1378,18 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) s->is_jmp = 1; } +/* an interrupt is different from an exception because of the + priviledge checks */ +static void gen_interrupt(DisasContext *s, int intno, + unsigned int cur_eip, unsigned int next_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_raise_interrupt(intno, next_eip); + s->is_jmp = 1; +} + /* generate a jump to eip. No segment change must happen before as a direct call to the next block may occur */ static void gen_jmp(DisasContext *s, unsigned int eip) @@ -1650,28 +1666,28 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 6: /* div */ switch(ot) { case OT_BYTE: - gen_op_divb_AL_T0(); + gen_op_divb_AL_T0(pc_start - s->cs_base); break; case OT_WORD: - gen_op_divw_AX_T0(); + gen_op_divw_AX_T0(pc_start - s->cs_base); break; default: case OT_LONG: - gen_op_divl_EAX_T0(); + gen_op_divl_EAX_T0(pc_start - s->cs_base); break; } break; case 7: /* idiv */ switch(ot) { case OT_BYTE: - gen_op_idivb_AL_T0(); + gen_op_idivb_AL_T0(pc_start - s->cs_base); break; case OT_WORD: - gen_op_idivw_AX_T0(); + gen_op_idivw_AX_T0(pc_start - s->cs_base); break; default: case OT_LONG: - gen_op_idivl_EAX_T0(); + gen_op_idivl_EAX_T0(pc_start - s->cs_base); break; } break; @@ -1738,7 +1754,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_ld_T1_A0[ot](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_lduw_T0_A0(); - gen_movl_seg_T0(s, R_CS); + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); gen_op_movl_T0_T1(); gen_op_jmp_T0(); s->is_jmp = 1; @@ -1753,7 +1769,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_ld_T1_A0[ot](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_lduw_T0_A0(); - gen_movl_seg_T0(s, R_CS); + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); gen_op_movl_T0_T1(); gen_op_jmp_T0(); s->is_jmp = 1; @@ -1970,13 +1986,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x17: /* pop ss */ case 0x1f: /* pop ds */ gen_pop_T0(s); - gen_movl_seg_T0(s, b >> 3); + gen_movl_seg_T0(s, b >> 3, pc_start - s->cs_base); gen_pop_update(s); break; case 0x1a1: /* pop fs */ case 0x1a9: /* pop gs */ gen_pop_T0(s); - gen_movl_seg_T0(s, (b >> 3) & 7); + gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); gen_pop_update(s); break; @@ -2030,7 +2046,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); if (reg >= 6 || reg == R_CS) goto illegal_op; - gen_movl_seg_T0(s, reg); + gen_movl_seg_T0(s, reg, pc_start - s->cs_base); break; case 0x8c: /* mov Gv, seg */ ot = dflag ? OT_LONG : OT_WORD; @@ -2231,7 +2247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ gen_op_lduw_T0_A0(); - gen_movl_seg_T0(s, op); + gen_movl_seg_T0(s, op, pc_start - s->cs_base); /* then put the data */ gen_op_mov_reg_T1[ot][reg](); break; @@ -2914,7 +2930,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_pop_update(s); /* pop selector */ gen_pop_T0(s); - gen_movl_seg_T0(s, R_CS); + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); gen_pop_update(s); /* add stack offset */ if (s->ss32) @@ -2933,7 +2949,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_pop_update(s); /* pop selector */ gen_pop_T0(s); - gen_movl_seg_T0(s, R_CS); + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); gen_pop_update(s); s->is_jmp = 1; break; @@ -2950,7 +2966,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_pop_update(s); /* pop selector */ gen_pop_T0(s); - gen_movl_seg_T0(s, R_CS); + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); gen_pop_update(s); /* pop eflags */ gen_pop_T0(s); @@ -2995,7 +3011,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* change cs and pc */ gen_op_movl_T0_im(selector); - gen_movl_seg_T0(s, R_CS); + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); gen_op_jmp_im((unsigned long)offset); s->is_jmp = 1; } @@ -3018,7 +3034,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* change cs and pc */ gen_op_movl_T0_im(selector); - gen_movl_seg_T0(s, R_CS); + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); gen_op_jmp_im((unsigned long)offset); s->is_jmp = 1; } @@ -3255,14 +3271,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x9b: /* fwait */ break; case 0xcc: /* int3 */ - gen_exception(s, EXCP03_INT3, s->pc - s->cs_base); + gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); break; case 0xcd: /* int N */ val = ldub(s->pc++); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_int_im(val, pc_start - s->cs_base); - s->is_jmp = 1; + /* XXX: add error code for vm86 GPF */ + if (!s->vm86) + gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); + else + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; case 0xce: /* into */ if (s->cc_op != CC_OP_DYNAMIC) @@ -3309,9 +3326,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_reg_T0[ot][reg](); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (ot == OT_WORD) - gen_op_boundw(); + gen_op_boundw(pc_start - s->cs_base); else - gen_op_boundl(); + gen_op_boundl(pc_start - s->cs_base); break; case 0x1c8 ... 0x1cf: /* bswap reg */ reg = b & 7; @@ -3670,13 +3687,13 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) #ifdef DEBUG_DISAS static const char *op_str[] = { -#define DEF(s, n) #s, +#define DEF(s, n, copy_size) #s, #include "opc-i386.h" #undef DEF }; static uint8_t op_nb_args[] = { -#define DEF(s, n) n, +#define DEF(s, n, copy_size) n, #include "opc-i386.h" #undef DEF }; @@ -3706,7 +3723,6 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) #endif -/* XXX: make this buffer thread safe */ /* XXX: make safe guess about sizes */ #define MAX_OP_PER_INSTR 32 #define OPC_BUF_SIZE 512 @@ -3716,30 +3732,27 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) static uint16_t gen_opc_buf[OPC_BUF_SIZE]; static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; +static uint32_t gen_opc_pc[OPC_BUF_SIZE]; +static uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; -/* return non zero if the very first instruction is invalid so that - the virtual CPU can trigger an exception. - - '*code_size_ptr' contains the target code size including the - instruction which triggered an exception, except in case of invalid - illegal opcode. It must never exceed one target page. - - '*gen_code_size_ptr' contains the size of the generated code (host - code). -*/ -int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, - int *gen_code_size_ptr, - uint8_t *pc_start, uint8_t *cs_base, int flags, - int *code_size_ptr, TranslationBlock *tb) +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc) { DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; uint16_t *gen_opc_end; - int gen_code_size; + int flags, j, lj; long ret; + uint8_t *pc_start; + uint8_t *cs_base; /* generate intermediate code */ - + pc_start = (uint8_t *)tb->pc; + cs_base = (uint8_t *)tb->cs_base; + flags = tb->flags; + dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; @@ -3758,7 +3771,18 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, dc->is_jmp = 0; pc_ptr = pc_start; + lj = -1; do { + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + gen_opc_pc[lj] = (uint32_t)pc_ptr; + gen_opc_instr_start[lj] = 1; + } + } ret = disas_insn(dc, pc_ptr); if (ret == -1) { /* we trigger an illegal instruction operation only if it @@ -3819,10 +3843,31 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, fprintf(logfile, "\n"); } #endif + if (!search_pc) + tb->size = pc_ptr - pc_start; + return 0; +} + + +/* return non zero if the very first instruction is invalid so that + the virtual CPU can trigger an exception. + + '*gen_code_size_ptr' contains the size of the generated code (host + code). +*/ +int cpu_x86_gen_code(TranslationBlock *tb, + int max_code_size, int *gen_code_size_ptr) +{ + uint8_t *gen_code_buf; + int gen_code_size; + + if (gen_intermediate_code(tb, 0) < 0) + return -1; /* generate machine code */ tb->tb_next_offset[0] = 0xffff; tb->tb_next_offset[1] = 0xffff; + gen_code_buf = tb->tc_ptr; gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, #ifdef USE_DIRECT_JUMP tb->tb_jmp_offset, @@ -3831,13 +3876,12 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, #endif gen_opc_buf, gen_opparam_buf); flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); - + *gen_code_size_ptr = gen_code_size; - *code_size_ptr = pc_ptr - pc_start; #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); - disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET); + disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET); fprintf(logfile, "\n"); fflush(logfile); } @@ -3845,6 +3889,50 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, return 0; } +static const unsigned short opc_copy_size[] = { +#define DEF(s, n, copy_size) copy_size, +#include "opc-i386.h" +#undef DEF +}; + +/* The simulated PC corresponding to + 'searched_pc' in the generated code is searched. 0 is returned if + found. *found_pc contains the found PC. + */ +int cpu_x86_search_pc(TranslationBlock *tb, + uint32_t *found_pc, unsigned long searched_pc) +{ + int j, c; + unsigned long tc_ptr; + uint16_t *opc_ptr; + + if (gen_intermediate_code(tb, 1) < 0) + return -1; + + /* find opc index corresponding to search_pc */ + tc_ptr = (unsigned long)tb->tc_ptr; + if (searched_pc < tc_ptr) + return -1; + j = 0; + opc_ptr = gen_opc_buf; + for(;;) { + c = *opc_ptr; + if (c == INDEX_op_end) + return -1; + tc_ptr += opc_copy_size[c]; + if (searched_pc < tc_ptr) + break; + opc_ptr++; + } + j = opc_ptr - gen_opc_buf; + /* now find start of instruction before */ + while (gen_opc_instr_start[j] == 0) + j--; + *found_pc = gen_opc_pc[j]; + return 0; +} + + CPUX86State *cpu_x86_init(void) { CPUX86State *env; -- cgit v1.2.3 From 14ae3ba7f94f962669e3274cad28dcabb5185287 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 May 2003 23:25:06 +0000 Subject: mmap2 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@190 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 90fb9dcd3..329fb0f3a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1047,7 +1047,7 @@ static int write_ldt(CPUX86State *env, 0x7000; if (!oldmode) entry_2 |= (useable << 20); - + /* Install the new entry ... */ install: lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3)); @@ -1753,7 +1753,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #else case TARGET_NR_mmap: #endif - ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5, arg6)); + ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5, + arg6 << TARGET_PAGE_BITS)); break; case TARGET_NR_munmap: ret = get_errno(target_munmap(arg1, arg2)); -- cgit v1.2.3 From c9087c2a6068b23207517f7d7ff796e68290358b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 May 2003 23:25:41 +0000 Subject: cr2 update (dosemu VGA support fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@191 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 145dc2992..0601a34f0 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -175,7 +175,7 @@ void signal_init(void) act.sa_flags = SA_SIGINFO; act.sa_sigaction = host_signal_handler; for(i = 1; i < NSIG; i++) { - sigaction(i, &act, NULL); + sigaction(i, &act, NULL); } memset(sigact_table, 0, sizeof(sigact_table)); @@ -547,7 +547,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, #endif /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); - err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2); + err |= __put_user(env->cr2, &sc->cr2); return err; } -- cgit v1.2.3 From d731dae8e3c9591727073f6e54af08c1ee960540 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 May 2003 23:26:25 +0000 Subject: currently generated git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@192 c046a42c-6fe2-441c-8c8c-71466251a162 --- opc-i386.h | 636 ------------------------------------------------------------- 1 file changed, 636 deletions(-) delete mode 100644 opc-i386.h diff --git a/opc-i386.h b/opc-i386.h deleted file mode 100644 index e658d4f79..000000000 --- a/opc-i386.h +++ /dev/null @@ -1,636 +0,0 @@ -DEF(end, 0) -DEF(movl_A0_EAX, 0) -DEF(addl_A0_EAX, 0) -DEF(addl_A0_EAX_s1, 0) -DEF(addl_A0_EAX_s2, 0) -DEF(addl_A0_EAX_s3, 0) -DEF(movl_T0_EAX, 0) -DEF(movl_T1_EAX, 0) -DEF(movh_T0_EAX, 0) -DEF(movh_T1_EAX, 0) -DEF(movl_EAX_T0, 0) -DEF(movl_EAX_T1, 0) -DEF(movl_EAX_A0, 0) -DEF(cmovw_EAX_T1_T0, 0) -DEF(cmovl_EAX_T1_T0, 0) -DEF(movw_EAX_T0, 0) -DEF(movw_EAX_T1, 0) -DEF(movw_EAX_A0, 0) -DEF(movb_EAX_T0, 0) -DEF(movh_EAX_T0, 0) -DEF(movb_EAX_T1, 0) -DEF(movh_EAX_T1, 0) -DEF(movl_A0_ECX, 0) -DEF(addl_A0_ECX, 0) -DEF(addl_A0_ECX_s1, 0) -DEF(addl_A0_ECX_s2, 0) -DEF(addl_A0_ECX_s3, 0) -DEF(movl_T0_ECX, 0) -DEF(movl_T1_ECX, 0) -DEF(movh_T0_ECX, 0) -DEF(movh_T1_ECX, 0) -DEF(movl_ECX_T0, 0) -DEF(movl_ECX_T1, 0) -DEF(movl_ECX_A0, 0) -DEF(cmovw_ECX_T1_T0, 0) -DEF(cmovl_ECX_T1_T0, 0) -DEF(movw_ECX_T0, 0) -DEF(movw_ECX_T1, 0) -DEF(movw_ECX_A0, 0) -DEF(movb_ECX_T0, 0) -DEF(movh_ECX_T0, 0) -DEF(movb_ECX_T1, 0) -DEF(movh_ECX_T1, 0) -DEF(movl_A0_EDX, 0) -DEF(addl_A0_EDX, 0) -DEF(addl_A0_EDX_s1, 0) -DEF(addl_A0_EDX_s2, 0) -DEF(addl_A0_EDX_s3, 0) -DEF(movl_T0_EDX, 0) -DEF(movl_T1_EDX, 0) -DEF(movh_T0_EDX, 0) -DEF(movh_T1_EDX, 0) -DEF(movl_EDX_T0, 0) -DEF(movl_EDX_T1, 0) -DEF(movl_EDX_A0, 0) -DEF(cmovw_EDX_T1_T0, 0) -DEF(cmovl_EDX_T1_T0, 0) -DEF(movw_EDX_T0, 0) -DEF(movw_EDX_T1, 0) -DEF(movw_EDX_A0, 0) -DEF(movb_EDX_T0, 0) -DEF(movh_EDX_T0, 0) -DEF(movb_EDX_T1, 0) -DEF(movh_EDX_T1, 0) -DEF(movl_A0_EBX, 0) -DEF(addl_A0_EBX, 0) -DEF(addl_A0_EBX_s1, 0) -DEF(addl_A0_EBX_s2, 0) -DEF(addl_A0_EBX_s3, 0) -DEF(movl_T0_EBX, 0) -DEF(movl_T1_EBX, 0) -DEF(movh_T0_EBX, 0) -DEF(movh_T1_EBX, 0) -DEF(movl_EBX_T0, 0) -DEF(movl_EBX_T1, 0) -DEF(movl_EBX_A0, 0) -DEF(cmovw_EBX_T1_T0, 0) -DEF(cmovl_EBX_T1_T0, 0) -DEF(movw_EBX_T0, 0) -DEF(movw_EBX_T1, 0) -DEF(movw_EBX_A0, 0) -DEF(movb_EBX_T0, 0) -DEF(movh_EBX_T0, 0) -DEF(movb_EBX_T1, 0) -DEF(movh_EBX_T1, 0) -DEF(movl_A0_ESP, 0) -DEF(addl_A0_ESP, 0) -DEF(addl_A0_ESP_s1, 0) -DEF(addl_A0_ESP_s2, 0) -DEF(addl_A0_ESP_s3, 0) -DEF(movl_T0_ESP, 0) -DEF(movl_T1_ESP, 0) -DEF(movh_T0_ESP, 0) -DEF(movh_T1_ESP, 0) -DEF(movl_ESP_T0, 0) -DEF(movl_ESP_T1, 0) -DEF(movl_ESP_A0, 0) -DEF(cmovw_ESP_T1_T0, 0) -DEF(cmovl_ESP_T1_T0, 0) -DEF(movw_ESP_T0, 0) -DEF(movw_ESP_T1, 0) -DEF(movw_ESP_A0, 0) -DEF(movb_ESP_T0, 0) -DEF(movh_ESP_T0, 0) -DEF(movb_ESP_T1, 0) -DEF(movh_ESP_T1, 0) -DEF(movl_A0_EBP, 0) -DEF(addl_A0_EBP, 0) -DEF(addl_A0_EBP_s1, 0) -DEF(addl_A0_EBP_s2, 0) -DEF(addl_A0_EBP_s3, 0) -DEF(movl_T0_EBP, 0) -DEF(movl_T1_EBP, 0) -DEF(movh_T0_EBP, 0) -DEF(movh_T1_EBP, 0) -DEF(movl_EBP_T0, 0) -DEF(movl_EBP_T1, 0) -DEF(movl_EBP_A0, 0) -DEF(cmovw_EBP_T1_T0, 0) -DEF(cmovl_EBP_T1_T0, 0) -DEF(movw_EBP_T0, 0) -DEF(movw_EBP_T1, 0) -DEF(movw_EBP_A0, 0) -DEF(movb_EBP_T0, 0) -DEF(movh_EBP_T0, 0) -DEF(movb_EBP_T1, 0) -DEF(movh_EBP_T1, 0) -DEF(movl_A0_ESI, 0) -DEF(addl_A0_ESI, 0) -DEF(addl_A0_ESI_s1, 0) -DEF(addl_A0_ESI_s2, 0) -DEF(addl_A0_ESI_s3, 0) -DEF(movl_T0_ESI, 0) -DEF(movl_T1_ESI, 0) -DEF(movh_T0_ESI, 0) -DEF(movh_T1_ESI, 0) -DEF(movl_ESI_T0, 0) -DEF(movl_ESI_T1, 0) -DEF(movl_ESI_A0, 0) -DEF(cmovw_ESI_T1_T0, 0) -DEF(cmovl_ESI_T1_T0, 0) -DEF(movw_ESI_T0, 0) -DEF(movw_ESI_T1, 0) -DEF(movw_ESI_A0, 0) -DEF(movb_ESI_T0, 0) -DEF(movh_ESI_T0, 0) -DEF(movb_ESI_T1, 0) -DEF(movh_ESI_T1, 0) -DEF(movl_A0_EDI, 0) -DEF(addl_A0_EDI, 0) -DEF(addl_A0_EDI_s1, 0) -DEF(addl_A0_EDI_s2, 0) -DEF(addl_A0_EDI_s3, 0) -DEF(movl_T0_EDI, 0) -DEF(movl_T1_EDI, 0) -DEF(movh_T0_EDI, 0) -DEF(movh_T1_EDI, 0) -DEF(movl_EDI_T0, 0) -DEF(movl_EDI_T1, 0) -DEF(movl_EDI_A0, 0) -DEF(cmovw_EDI_T1_T0, 0) -DEF(cmovl_EDI_T1_T0, 0) -DEF(movw_EDI_T0, 0) -DEF(movw_EDI_T1, 0) -DEF(movw_EDI_A0, 0) -DEF(movb_EDI_T0, 0) -DEF(movh_EDI_T0, 0) -DEF(movb_EDI_T1, 0) -DEF(movh_EDI_T1, 0) -DEF(addl_T0_T1_cc, 0) -DEF(orl_T0_T1_cc, 0) -DEF(andl_T0_T1_cc, 0) -DEF(subl_T0_T1_cc, 0) -DEF(xorl_T0_T1_cc, 0) -DEF(cmpl_T0_T1_cc, 0) -DEF(negl_T0_cc, 0) -DEF(incl_T0_cc, 0) -DEF(decl_T0_cc, 0) -DEF(testl_T0_T1_cc, 0) -DEF(addl_T0_T1, 0) -DEF(orl_T0_T1, 0) -DEF(andl_T0_T1, 0) -DEF(subl_T0_T1, 0) -DEF(xorl_T0_T1, 0) -DEF(negl_T0, 0) -DEF(incl_T0, 0) -DEF(decl_T0, 0) -DEF(notl_T0, 0) -DEF(bswapl_T0, 0) -DEF(mulb_AL_T0, 0) -DEF(imulb_AL_T0, 0) -DEF(mulw_AX_T0, 0) -DEF(imulw_AX_T0, 0) -DEF(mull_EAX_T0, 0) -DEF(imull_EAX_T0, 0) -DEF(imulw_T0_T1, 0) -DEF(imull_T0_T1, 0) -DEF(divb_AL_T0, 0) -DEF(idivb_AL_T0, 0) -DEF(divw_AX_T0, 0) -DEF(idivw_AX_T0, 0) -DEF(divl_EAX_T0, 0) -DEF(idivl_EAX_T0, 0) -DEF(movl_T0_im, 1) -DEF(addl_T0_im, 1) -DEF(andl_T0_ffff, 0) -DEF(movl_T0_T1, 0) -DEF(movl_T1_im, 1) -DEF(addl_T1_im, 1) -DEF(movl_T1_A0, 0) -DEF(movl_A0_im, 1) -DEF(addl_A0_im, 1) -DEF(addl_A0_AL, 0) -DEF(andl_A0_ffff, 0) -DEF(ldub_T0_A0, 0) -DEF(ldsb_T0_A0, 0) -DEF(lduw_T0_A0, 0) -DEF(ldsw_T0_A0, 0) -DEF(ldl_T0_A0, 0) -DEF(ldub_T1_A0, 0) -DEF(ldsb_T1_A0, 0) -DEF(lduw_T1_A0, 0) -DEF(ldsw_T1_A0, 0) -DEF(ldl_T1_A0, 0) -DEF(stb_T0_A0, 0) -DEF(stw_T0_A0, 0) -DEF(stl_T0_A0, 0) -DEF(add_bitw_A0_T1, 0) -DEF(add_bitl_A0_T1, 0) -DEF(jmp_T0, 0) -DEF(jmp_im, 1) -DEF(int_im, 2) -DEF(raise_exception, 1) -DEF(into, 1) -DEF(cli, 0) -DEF(sti, 0) -DEF(boundw, 0) -DEF(boundl, 0) -DEF(cmpxchg8b, 0) -DEF(jmp_tb_next, 2) -DEF(movl_T0_0, 0) -DEF(jb_subb, 3) -DEF(jz_subb, 3) -DEF(jbe_subb, 3) -DEF(js_subb, 3) -DEF(jl_subb, 3) -DEF(jle_subb, 3) -DEF(setb_T0_subb, 0) -DEF(setz_T0_subb, 0) -DEF(setbe_T0_subb, 0) -DEF(sets_T0_subb, 0) -DEF(setl_T0_subb, 0) -DEF(setle_T0_subb, 0) -DEF(rolb_T0_T1_cc, 0) -DEF(rolb_T0_T1, 0) -DEF(rorb_T0_T1_cc, 0) -DEF(rorb_T0_T1, 0) -DEF(rclb_T0_T1_cc, 0) -DEF(rcrb_T0_T1_cc, 0) -DEF(shlb_T0_T1_cc, 0) -DEF(shlb_T0_T1, 0) -DEF(shrb_T0_T1_cc, 0) -DEF(shrb_T0_T1, 0) -DEF(sarb_T0_T1_cc, 0) -DEF(sarb_T0_T1, 0) -DEF(adcb_T0_T1_cc, 0) -DEF(sbbb_T0_T1_cc, 0) -DEF(cmpxchgb_T0_T1_EAX_cc, 0) -DEF(movsb_fast, 0) -DEF(rep_movsb_fast, 0) -DEF(stosb_fast, 0) -DEF(rep_stosb_fast, 0) -DEF(lodsb_fast, 0) -DEF(rep_lodsb_fast, 0) -DEF(scasb_fast, 0) -DEF(repz_scasb_fast, 0) -DEF(repnz_scasb_fast, 0) -DEF(cmpsb_fast, 0) -DEF(repz_cmpsb_fast, 0) -DEF(repnz_cmpsb_fast, 0) -DEF(outsb_fast, 0) -DEF(rep_outsb_fast, 0) -DEF(insb_fast, 0) -DEF(rep_insb_fast, 0) -DEF(movsb_a32, 0) -DEF(rep_movsb_a32, 0) -DEF(stosb_a32, 0) -DEF(rep_stosb_a32, 0) -DEF(lodsb_a32, 0) -DEF(rep_lodsb_a32, 0) -DEF(scasb_a32, 0) -DEF(repz_scasb_a32, 0) -DEF(repnz_scasb_a32, 0) -DEF(cmpsb_a32, 0) -DEF(repz_cmpsb_a32, 0) -DEF(repnz_cmpsb_a32, 0) -DEF(outsb_a32, 0) -DEF(rep_outsb_a32, 0) -DEF(insb_a32, 0) -DEF(rep_insb_a32, 0) -DEF(movsb_a16, 0) -DEF(rep_movsb_a16, 0) -DEF(stosb_a16, 0) -DEF(rep_stosb_a16, 0) -DEF(lodsb_a16, 0) -DEF(rep_lodsb_a16, 0) -DEF(scasb_a16, 0) -DEF(repz_scasb_a16, 0) -DEF(repnz_scasb_a16, 0) -DEF(cmpsb_a16, 0) -DEF(repz_cmpsb_a16, 0) -DEF(repnz_cmpsb_a16, 0) -DEF(outsb_a16, 0) -DEF(rep_outsb_a16, 0) -DEF(insb_a16, 0) -DEF(rep_insb_a16, 0) -DEF(outb_T0_T1, 0) -DEF(inb_T0_T1, 0) -DEF(jb_subw, 3) -DEF(jz_subw, 3) -DEF(jbe_subw, 3) -DEF(js_subw, 3) -DEF(jl_subw, 3) -DEF(jle_subw, 3) -DEF(loopnzw, 2) -DEF(loopzw, 2) -DEF(loopw, 2) -DEF(jecxzw, 2) -DEF(setb_T0_subw, 0) -DEF(setz_T0_subw, 0) -DEF(setbe_T0_subw, 0) -DEF(sets_T0_subw, 0) -DEF(setl_T0_subw, 0) -DEF(setle_T0_subw, 0) -DEF(rolw_T0_T1_cc, 0) -DEF(rolw_T0_T1, 0) -DEF(rorw_T0_T1_cc, 0) -DEF(rorw_T0_T1, 0) -DEF(rclw_T0_T1_cc, 0) -DEF(rcrw_T0_T1_cc, 0) -DEF(shlw_T0_T1_cc, 0) -DEF(shlw_T0_T1, 0) -DEF(shrw_T0_T1_cc, 0) -DEF(shrw_T0_T1, 0) -DEF(sarw_T0_T1_cc, 0) -DEF(sarw_T0_T1, 0) -DEF(shldw_T0_T1_im_cc, 1) -DEF(shldw_T0_T1_ECX_cc, 0) -DEF(shrdw_T0_T1_im_cc, 1) -DEF(shrdw_T0_T1_ECX_cc, 0) -DEF(adcw_T0_T1_cc, 0) -DEF(sbbw_T0_T1_cc, 0) -DEF(cmpxchgw_T0_T1_EAX_cc, 0) -DEF(btw_T0_T1_cc, 0) -DEF(btsw_T0_T1_cc, 0) -DEF(btrw_T0_T1_cc, 0) -DEF(btcw_T0_T1_cc, 0) -DEF(bsfw_T0_cc, 0) -DEF(bsrw_T0_cc, 0) -DEF(movsw_fast, 0) -DEF(rep_movsw_fast, 0) -DEF(stosw_fast, 0) -DEF(rep_stosw_fast, 0) -DEF(lodsw_fast, 0) -DEF(rep_lodsw_fast, 0) -DEF(scasw_fast, 0) -DEF(repz_scasw_fast, 0) -DEF(repnz_scasw_fast, 0) -DEF(cmpsw_fast, 0) -DEF(repz_cmpsw_fast, 0) -DEF(repnz_cmpsw_fast, 0) -DEF(outsw_fast, 0) -DEF(rep_outsw_fast, 0) -DEF(insw_fast, 0) -DEF(rep_insw_fast, 0) -DEF(movsw_a32, 0) -DEF(rep_movsw_a32, 0) -DEF(stosw_a32, 0) -DEF(rep_stosw_a32, 0) -DEF(lodsw_a32, 0) -DEF(rep_lodsw_a32, 0) -DEF(scasw_a32, 0) -DEF(repz_scasw_a32, 0) -DEF(repnz_scasw_a32, 0) -DEF(cmpsw_a32, 0) -DEF(repz_cmpsw_a32, 0) -DEF(repnz_cmpsw_a32, 0) -DEF(outsw_a32, 0) -DEF(rep_outsw_a32, 0) -DEF(insw_a32, 0) -DEF(rep_insw_a32, 0) -DEF(movsw_a16, 0) -DEF(rep_movsw_a16, 0) -DEF(stosw_a16, 0) -DEF(rep_stosw_a16, 0) -DEF(lodsw_a16, 0) -DEF(rep_lodsw_a16, 0) -DEF(scasw_a16, 0) -DEF(repz_scasw_a16, 0) -DEF(repnz_scasw_a16, 0) -DEF(cmpsw_a16, 0) -DEF(repz_cmpsw_a16, 0) -DEF(repnz_cmpsw_a16, 0) -DEF(outsw_a16, 0) -DEF(rep_outsw_a16, 0) -DEF(insw_a16, 0) -DEF(rep_insw_a16, 0) -DEF(outw_T0_T1, 0) -DEF(inw_T0_T1, 0) -DEF(jb_subl, 3) -DEF(jz_subl, 3) -DEF(jbe_subl, 3) -DEF(js_subl, 3) -DEF(jl_subl, 3) -DEF(jle_subl, 3) -DEF(loopnzl, 2) -DEF(loopzl, 2) -DEF(loopl, 2) -DEF(jecxzl, 2) -DEF(setb_T0_subl, 0) -DEF(setz_T0_subl, 0) -DEF(setbe_T0_subl, 0) -DEF(sets_T0_subl, 0) -DEF(setl_T0_subl, 0) -DEF(setle_T0_subl, 0) -DEF(roll_T0_T1_cc, 0) -DEF(roll_T0_T1, 0) -DEF(rorl_T0_T1_cc, 0) -DEF(rorl_T0_T1, 0) -DEF(rcll_T0_T1_cc, 0) -DEF(rcrl_T0_T1_cc, 0) -DEF(shll_T0_T1_cc, 0) -DEF(shll_T0_T1, 0) -DEF(shrl_T0_T1_cc, 0) -DEF(shrl_T0_T1, 0) -DEF(sarl_T0_T1_cc, 0) -DEF(sarl_T0_T1, 0) -DEF(shldl_T0_T1_im_cc, 1) -DEF(shldl_T0_T1_ECX_cc, 0) -DEF(shrdl_T0_T1_im_cc, 1) -DEF(shrdl_T0_T1_ECX_cc, 0) -DEF(adcl_T0_T1_cc, 0) -DEF(sbbl_T0_T1_cc, 0) -DEF(cmpxchgl_T0_T1_EAX_cc, 0) -DEF(btl_T0_T1_cc, 0) -DEF(btsl_T0_T1_cc, 0) -DEF(btrl_T0_T1_cc, 0) -DEF(btcl_T0_T1_cc, 0) -DEF(bsfl_T0_cc, 0) -DEF(bsrl_T0_cc, 0) -DEF(movsl_fast, 0) -DEF(rep_movsl_fast, 0) -DEF(stosl_fast, 0) -DEF(rep_stosl_fast, 0) -DEF(lodsl_fast, 0) -DEF(rep_lodsl_fast, 0) -DEF(scasl_fast, 0) -DEF(repz_scasl_fast, 0) -DEF(repnz_scasl_fast, 0) -DEF(cmpsl_fast, 0) -DEF(repz_cmpsl_fast, 0) -DEF(repnz_cmpsl_fast, 0) -DEF(outsl_fast, 0) -DEF(rep_outsl_fast, 0) -DEF(insl_fast, 0) -DEF(rep_insl_fast, 0) -DEF(movsl_a32, 0) -DEF(rep_movsl_a32, 0) -DEF(stosl_a32, 0) -DEF(rep_stosl_a32, 0) -DEF(lodsl_a32, 0) -DEF(rep_lodsl_a32, 0) -DEF(scasl_a32, 0) -DEF(repz_scasl_a32, 0) -DEF(repnz_scasl_a32, 0) -DEF(cmpsl_a32, 0) -DEF(repz_cmpsl_a32, 0) -DEF(repnz_cmpsl_a32, 0) -DEF(outsl_a32, 0) -DEF(rep_outsl_a32, 0) -DEF(insl_a32, 0) -DEF(rep_insl_a32, 0) -DEF(movsl_a16, 0) -DEF(rep_movsl_a16, 0) -DEF(stosl_a16, 0) -DEF(rep_stosl_a16, 0) -DEF(lodsl_a16, 0) -DEF(rep_lodsl_a16, 0) -DEF(scasl_a16, 0) -DEF(repz_scasl_a16, 0) -DEF(repnz_scasl_a16, 0) -DEF(cmpsl_a16, 0) -DEF(repz_cmpsl_a16, 0) -DEF(repnz_cmpsl_a16, 0) -DEF(outsl_a16, 0) -DEF(rep_outsl_a16, 0) -DEF(insl_a16, 0) -DEF(rep_insl_a16, 0) -DEF(outl_T0_T1, 0) -DEF(inl_T0_T1, 0) -DEF(movsbl_T0_T0, 0) -DEF(movzbl_T0_T0, 0) -DEF(movswl_T0_T0, 0) -DEF(movzwl_T0_T0, 0) -DEF(movswl_EAX_AX, 0) -DEF(movsbw_AX_AL, 0) -DEF(movslq_EDX_EAX, 0) -DEF(movswl_DX_AX, 0) -DEF(pushl_T0, 0) -DEF(pushw_T0, 0) -DEF(pushl_ss32_T0, 0) -DEF(pushw_ss32_T0, 0) -DEF(pushl_ss16_T0, 0) -DEF(pushw_ss16_T0, 0) -DEF(popl_T0, 0) -DEF(popw_T0, 0) -DEF(popl_ss32_T0, 0) -DEF(popw_ss32_T0, 0) -DEF(popl_ss16_T0, 0) -DEF(popw_ss16_T0, 0) -DEF(addl_ESP_4, 0) -DEF(addl_ESP_2, 0) -DEF(addw_ESP_4, 0) -DEF(addw_ESP_2, 0) -DEF(addl_ESP_im, 1) -DEF(addw_ESP_im, 1) -DEF(rdtsc, 0) -DEF(cpuid, 0) -DEF(aam, 1) -DEF(aad, 1) -DEF(aaa, 0) -DEF(aas, 0) -DEF(daa, 0) -DEF(das, 0) -DEF(movl_seg_T0, 1) -DEF(movl_T0_seg, 1) -DEF(movl_A0_seg, 1) -DEF(addl_A0_seg, 1) -DEF(lsl, 0) -DEF(lar, 0) -DEF(jcc, 3) -DEF(seto_T0_cc, 0) -DEF(setb_T0_cc, 0) -DEF(setz_T0_cc, 0) -DEF(setbe_T0_cc, 0) -DEF(sets_T0_cc, 0) -DEF(setp_T0_cc, 0) -DEF(setl_T0_cc, 0) -DEF(setle_T0_cc, 0) -DEF(xor_T0_1, 0) -DEF(set_cc_op, 1) -DEF(movl_eflags_T0, 0) -DEF(movw_eflags_T0, 0) -DEF(movb_eflags_T0, 0) -DEF(movl_T0_eflags, 0) -DEF(cld, 0) -DEF(std, 0) -DEF(clc, 0) -DEF(stc, 0) -DEF(cmc, 0) -DEF(salc, 0) -DEF(flds_FT0_A0, 0) -DEF(fldl_FT0_A0, 0) -DEF(fild_FT0_A0, 0) -DEF(fildl_FT0_A0, 0) -DEF(fildll_FT0_A0, 0) -DEF(flds_ST0_A0, 0) -DEF(fldl_ST0_A0, 0) -DEF(fldt_ST0_A0, 0) -DEF(fild_ST0_A0, 0) -DEF(fildl_ST0_A0, 0) -DEF(fildll_ST0_A0, 0) -DEF(fsts_ST0_A0, 0) -DEF(fstl_ST0_A0, 0) -DEF(fstt_ST0_A0, 0) -DEF(fist_ST0_A0, 0) -DEF(fistl_ST0_A0, 0) -DEF(fistll_ST0_A0, 0) -DEF(fbld_ST0_A0, 0) -DEF(fbst_ST0_A0, 0) -DEF(fpush, 0) -DEF(fpop, 0) -DEF(fdecstp, 0) -DEF(fincstp, 0) -DEF(fmov_ST0_FT0, 0) -DEF(fmov_FT0_STN, 1) -DEF(fmov_ST0_STN, 1) -DEF(fmov_STN_ST0, 1) -DEF(fxchg_ST0_STN, 1) -DEF(fcom_ST0_FT0, 0) -DEF(fucom_ST0_FT0, 0) -DEF(fadd_ST0_FT0, 0) -DEF(fmul_ST0_FT0, 0) -DEF(fsub_ST0_FT0, 0) -DEF(fsubr_ST0_FT0, 0) -DEF(fdiv_ST0_FT0, 0) -DEF(fdivr_ST0_FT0, 0) -DEF(fadd_STN_ST0, 1) -DEF(fmul_STN_ST0, 1) -DEF(fsub_STN_ST0, 1) -DEF(fsubr_STN_ST0, 1) -DEF(fdiv_STN_ST0, 1) -DEF(fdivr_STN_ST0, 1) -DEF(fchs_ST0, 0) -DEF(fabs_ST0, 0) -DEF(fxam_ST0, 0) -DEF(fld1_ST0, 0) -DEF(fldl2t_ST0, 0) -DEF(fldl2e_ST0, 0) -DEF(fldpi_ST0, 0) -DEF(fldlg2_ST0, 0) -DEF(fldln2_ST0, 0) -DEF(fldz_ST0, 0) -DEF(fldz_FT0, 0) -DEF(f2xm1, 0) -DEF(fyl2x, 0) -DEF(fptan, 0) -DEF(fpatan, 0) -DEF(fxtract, 0) -DEF(fprem1, 0) -DEF(fprem, 0) -DEF(fyl2xp1, 0) -DEF(fsqrt, 0) -DEF(fsincos, 0) -DEF(frndint, 0) -DEF(fscale, 0) -DEF(fsin, 0) -DEF(fcos, 0) -DEF(fnstsw_A0, 0) -DEF(fnstsw_EAX, 0) -DEF(fnstcw_A0, 0) -DEF(fldcw_A0, 0) -DEF(fclex, 0) -DEF(fninit, 0) -DEF(lock, 0) -DEF(unlock, 0) -- cgit v1.2.3 From f4beb510a41980e119f787746442ca1b87c06754 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 May 2003 23:28:08 +0000 Subject: precise exceptions - more accurate interrupt semantics git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@193 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 108 +++++++++++++++++++++--------- op-i386.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 250 insertions(+), 54 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index a6a84e536..eeea342d2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -100,24 +100,35 @@ int cpu_x86_inl(CPUX86State *env, int addr) return 0; } -void write_dt(void *ptr, unsigned long addr, unsigned long limit, - int seg32_bit) +static void write_dt(void *ptr, unsigned long addr, unsigned long limit, + int flags) { - unsigned int e1, e2, limit_in_pages; - limit_in_pages = 0; - if (limit > 0xffff) { - limit = limit >> 12; - limit_in_pages = 1; - } + unsigned int e1, e2; e1 = (addr << 16) | (limit & 0xffff); e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); - e2 |= limit_in_pages << 23; /* byte granularity */ - e2 |= seg32_bit << 22; /* 32 bit segment */ + e2 |= flags; + stl((uint8_t *)ptr, e1); + stl((uint8_t *)ptr + 4, e2); +} + +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, + unsigned long addr, unsigned int sel) +{ + unsigned int e1, e2; + e1 = (addr & 0xffff) | (sel << 16); + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); stl((uint8_t *)ptr, e1); stl((uint8_t *)ptr + 4, e2); } uint64_t gdt_table[6]; +uint64_t idt_table[256]; + +/* only dpl matters as we do only user space emulation */ +static void set_idt(int n, unsigned int dpl) +{ + set_gate(idt_table + n, 0, dpl, 0, 0); +} void cpu_loop(CPUX86State *env) { @@ -128,30 +139,34 @@ void cpu_loop(CPUX86State *env) for(;;) { trapnr = cpu_x86_exec(env); switch(trapnr) { + case 0x80: + /* linux syscall */ + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP]); + break; + case EXCP0B_NOSEG: + case EXCP0C_STACK: + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); + break; case EXCP0D_GPF: if (env->eflags & VM_MASK) { handle_vm86_fault(env); } else { - pc = env->seg_cache[R_CS].base + env->eip; - if (pc[0] == 0xcd && pc[1] == 0x80) { - /* syscall */ - env->eip += 2; - env->regs[R_EAX] = do_syscall(env, - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP]); - } else { - /* XXX: more precise info */ - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - queue_signal(info.si_signo, &info); - } + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); } break; case EXCP0E_PAGE: @@ -365,11 +380,40 @@ int main(int argc, char **argv) env->regs[R_ESP] = regs->esp; env->eip = regs->eip; + /* linux interrupt setup */ + env->idt.base = (void *)idt_table; + env->idt.limit = sizeof(idt_table) - 1; + set_idt(0, 0); + set_idt(1, 0); + set_idt(2, 0); + set_idt(3, 3); + set_idt(4, 3); + set_idt(5, 3); + set_idt(6, 0); + set_idt(7, 0); + set_idt(8, 0); + set_idt(9, 0); + set_idt(10, 0); + set_idt(11, 0); + set_idt(12, 0); + set_idt(13, 0); + set_idt(14, 0); + set_idt(15, 0); + set_idt(16, 0); + set_idt(17, 0); + set_idt(18, 0); + set_idt(19, 0); + set_idt(0x80, 3); + /* linux segment setup */ env->gdt.base = (void *)gdt_table; env->gdt.limit = sizeof(gdt_table) - 1; - write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1); - write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1); + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); + write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); cpu_x86_load_seg(env, R_CS, __USER_CS); cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS); diff --git a/op-i386.c b/op-i386.c index cfae10363..69bd4cffc 100644 --- a/op-i386.c +++ b/op-i386.c @@ -364,8 +364,10 @@ void OPPROTO op_divb_AL_T0(void) num = (EAX & 0xffff); den = (T0 & 0xff); - if (den == 0) + if (den == 0) { + EIP = PARAM1; raise_exception(EXCP00_DIVZ); + } q = (num / den) & 0xff; r = (num % den) & 0xff; EAX = (EAX & 0xffff0000) | (r << 8) | q; @@ -377,8 +379,10 @@ void OPPROTO op_idivb_AL_T0(void) num = (int16_t)EAX; den = (int8_t)T0; - if (den == 0) + if (den == 0) { + EIP = PARAM1; raise_exception(EXCP00_DIVZ); + } q = (num / den) & 0xff; r = (num % den) & 0xff; EAX = (EAX & 0xffff0000) | (r << 8) | q; @@ -390,8 +394,10 @@ void OPPROTO op_divw_AX_T0(void) num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); den = (T0 & 0xffff); - if (den == 0) + if (den == 0) { + EIP = PARAM1; raise_exception(EXCP00_DIVZ); + } q = (num / den) & 0xffff; r = (num % den) & 0xffff; EAX = (EAX & 0xffff0000) | q; @@ -404,8 +410,10 @@ void OPPROTO op_idivw_AX_T0(void) num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); den = (int16_t)T0; - if (den == 0) + if (den == 0) { + EIP = PARAM1; raise_exception(EXCP00_DIVZ); + } q = (num / den) & 0xffff; r = (num % den) & 0xffff; EAX = (EAX & 0xffff0000) | q; @@ -435,8 +443,10 @@ void OPPROTO op_divl_EAX_T0(void) num = EAX | ((uint64_t)EDX << 32); den = T0; - if (den == 0) + if (den == 0) { + EIP = PARAM1; raise_exception(EXCP00_DIVZ); + } #ifdef BUGGY_GCC_DIV64 r = div64(&q, num, den); #else @@ -454,8 +464,10 @@ void OPPROTO op_idivl_EAX_T0(void) num = EAX | ((uint64_t)EDX << 32); den = T0; - if (den == 0) + if (den == 0) { + EIP = PARAM1; raise_exception(EXCP00_DIVZ); + } #ifdef BUGGY_GCC_DIV64 r = idiv64(&q, num, den); #else @@ -614,12 +626,102 @@ void OPPROTO op_jmp_im(void) EIP = PARAM1; } -void OPPROTO op_int_im(void) +#if 0 +/* full interrupt support (only useful for real CPU emulation, not + finished) - I won't do it any time soon, finish it if you want ! */ +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentDescriptorTable *dt; + uint8_t *ptr; + int type, dpl, cpl; + uint32_t e1, e2; + + dt = &env->idt; + if (intno * 8 + 7 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + ptr = dt->base + intno * 8; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + switch(type) { + case 5: /* task gate */ + case 6: /* 286 interrupt gate */ + case 7: /* 286 trap gate */ + case 14: /* 386 interrupt gate */ + case 15: /* 386 trap gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + break; + } + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->segs[R_CS] & 3; + /* check privledge if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); +} + +#else + +/* + * is_int is TRUE if coming from the int instruction. next_eip is the + * EIP value AFTER the interrupt instruction. It is only relevant if + * is_int is TRUE. + */ +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentDescriptorTable *dt; + uint8_t *ptr; + int dpl, cpl; + uint32_t e2; + + dt = &env->idt; + ptr = dt->base + (intno * 8); + e2 = ldl(ptr + 4); + + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = 3; + /* check privledge if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + + /* Since we emulate only user space, we cannot do more than + exiting the emulation with the suitable exception and error + code */ + if (is_int) + EIP = next_eip; + env->exception_index = intno; + env->error_code = error_code; + + cpu_loop_exit(); +} + +#endif + +/* shortcuts to generate exceptions */ +void raise_exception_err(int exception_index, int error_code) +{ + raise_interrupt(exception_index, 0, error_code, 0); +} + +void raise_exception(int exception_index) +{ + raise_interrupt(exception_index, 0, 0, 0); +} + +void OPPROTO op_raise_interrupt(void) { int intno; + unsigned int next_eip; intno = PARAM1; - EIP = PARAM2; - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + next_eip = PARAM2; + raise_interrupt(intno, 1, 0, next_eip); } void OPPROTO op_raise_exception(void) @@ -634,8 +736,7 @@ void OPPROTO op_into(void) int eflags; eflags = cc_table[CC_OP].compute_all(); if (eflags & CC_O) { - EIP = PARAM1; - raise_exception(EXCP04_INTO); + raise_interrupt(EXCP04_INTO, 1, 0, PARAM1); } FORCE_RET(); } @@ -674,8 +775,10 @@ void OPPROTO op_boundw(void) low = ldsw((uint8_t *)A0); high = ldsw((uint8_t *)A0 + 2); v = (int16_t)T0; - if (v < low || v > high) + if (v < low || v > high) { + EIP = PARAM1; raise_exception(EXCP05_BOUND); + } FORCE_RET(); } @@ -685,8 +788,10 @@ void OPPROTO op_boundl(void) low = ldl((uint8_t *)A0); high = ldl((uint8_t *)A0 + 4); v = T0; - if (v < low || v > high) + if (v < low || v > high) { + EIP = PARAM1; raise_exception(EXCP05_BOUND); + } FORCE_RET(); } @@ -1116,8 +1221,8 @@ void OPPROTO op_das(void) /* segment handling */ -/* XXX: use static VM86 information */ -void load_seg(int seg_reg, int selector) +/* only works if protected mode and not VM86 */ +void load_seg(int seg_reg, int selector, unsigned cur_eip) { SegmentCache *sc; SegmentDescriptorTable *dt; @@ -1126,21 +1231,56 @@ void load_seg(int seg_reg, int selector) uint8_t *ptr; sc = &env->seg_cache[seg_reg]; - if (env->eflags & VM_MASK) { - sc->base = (void *)(selector << 4); - sc->limit = 0xffff; - sc->seg_32bit = 0; + if ((selector & 0xfffc) == 0) { + /* null selector case */ + if (seg_reg == R_SS) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } else { + /* XXX: each access should trigger an exception */ + sc->base = NULL; + sc->limit = 0; + sc->seg_32bit = 1; + } } else { if (selector & 0x4) dt = &env->ldt; else dt = &env->gdt; index = selector & ~7; - if ((index + 7) > dt->limit) - raise_exception_err(EXCP0D_GPF, selector); + if ((index + 7) > dt->limit) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } ptr = dt->base + index; e1 = ldl(ptr); e2 = ldl(ptr + 4); + if (!(e2 & DESC_S_MASK) || + (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + + if (seg_reg == R_SS) { + if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + } else { + if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + } + + if (!(e2 & DESC_P_MASK)) { + EIP = cur_eip; + if (seg_reg == R_SS) + raise_exception_err(EXCP0C_STACK, selector & 0xfffc); + else + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + } + sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); if (e2 & (1 << 23)) @@ -1156,7 +1296,19 @@ void load_seg(int seg_reg, int selector) void OPPROTO op_movl_seg_T0(void) { - load_seg(PARAM1, T0 & 0xffff); + load_seg(PARAM1, T0 & 0xffff, PARAM2); +} + +/* faster VM86 version */ +void OPPROTO op_movl_seg_T0_vm(void) +{ + int selector; + + selector = T0 & 0xffff; + /* env->segs[] access */ + *(uint32_t *)((char *)env + PARAM1) = selector; + /* env->seg_cache[] access */ + ((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4); } void OPPROTO op_movl_T0_seg(void) -- cgit v1.2.3 From a513fe19ac4896a09c6c338204d76c39e652451f Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 May 2003 23:29:48 +0000 Subject: precise exceptions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@194 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 4 ++-- exec-i386.c | 58 ++++++++++++++++++++++++++++++++-------------------------- exec-i386.h | 5 ++++- exec.c | 31 +++++++++++++++++++++++++++++++ exec.h | 10 ++++++---- 5 files changed, 75 insertions(+), 33 deletions(-) diff --git a/dyngen.c b/dyngen.c index 96a47c8ed..4ed8b4b8b 100644 --- a/dyngen.c +++ b/dyngen.c @@ -451,7 +451,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } if (gen_switch == 2) { - fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args); + fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size); } else if (gen_switch == 1) { /* output C code */ @@ -991,7 +991,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) } if (do_print_enum) { - fprintf(outfile, "DEF(end, 0)\n"); + fprintf(outfile, "DEF(end, 0, 0)\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name, *p; name = strtab + sym->st_name; diff --git a/exec-i386.c b/exec-i386.c index 68e0371cc..002f00bdc 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -39,9 +39,7 @@ void cpu_unlock(void) spin_unlock(&global_cpu_lock); } -/* exception support */ -/* NOTE: not static to force relocation generation by GCC */ -void raise_exception_err(int exception_index, int error_code) +void cpu_loop_exit(void) { /* NOTE: the register at this point must be saved by hand because longjmp restore them */ @@ -76,17 +74,9 @@ void raise_exception_err(int exception_index, int error_code) #ifdef reg_EDI env->regs[R_EDI] = EDI; #endif - env->exception_index = exception_index; - env->error_code = error_code; longjmp(env->jmp_env, 1); } -/* short cut if error_code is 0 or not present */ -void raise_exception(int exception_index) -{ - raise_exception_err(exception_index, 0); -} - int cpu_x86_exec(CPUX86State *env1) { int saved_T0, saved_T1, saved_A0; @@ -115,7 +105,7 @@ int cpu_x86_exec(CPUX86State *env1) #ifdef reg_EDI int saved_EDI; #endif - int code_gen_size, ret, code_size; + int code_gen_size, ret; void (*gen_func)(void); TranslationBlock *tb, **ptb; uint8_t *tc_ptr, *cs_base, *pc; @@ -172,7 +162,8 @@ int cpu_x86_exec(CPUX86State *env1) T0 = 0; /* force lookup of first TB */ for(;;) { if (env->interrupt_request) { - raise_exception(EXCP_INTERRUPT); + env->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(); } #ifdef DEBUG_EXEC if (loglevel) { @@ -226,9 +217,9 @@ int cpu_x86_exec(CPUX86State *env1) } tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; - ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, - &code_gen_size, pc, cs_base, flags, - &code_size, tb); + tb->cs_base = (unsigned long)cs_base; + tb->flags = flags; + ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); /* if invalid instruction, signal it */ if (ret != 0) { /* NOTE: the tb is allocated but not linked, so we @@ -237,9 +228,6 @@ int cpu_x86_exec(CPUX86State *env1) raise_exception(EXCP06_ILLOP); } *ptb = tb; - tb->size = code_size; - tb->cs_base = (unsigned long)cs_base; - tb->flags = flags; tb->hash_next = NULL; tb_link(tb); code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); @@ -323,7 +311,19 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) saved_env = env; env = s; - load_seg(seg_reg, selector); + if (env->eflags & VM_MASK) { + SegmentCache *sc; + selector &= 0xffff; + sc = &env->seg_cache[seg_reg]; + /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded, + so we must load them here */ + sc->base = (void *)(selector << 4); + sc->limit = 0xffff; + sc->seg_32bit = 0; + env->segs[seg_reg] = selector; + } else { + load_seg(seg_reg, selector, 0); + } env = saved_env; } @@ -346,6 +346,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, int is_write, sigset_t *old_set) { + TranslationBlock *tb; + int ret; + uint32_t found_pc; + #if defined(DEBUG_SIGNAL) printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", pc, address, is_write, *(unsigned long *)old_set); @@ -354,16 +358,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, if (is_write && page_unprotect(address)) { return 1; } - if (pc >= (unsigned long)code_gen_buffer && - pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { + tb = tb_find_pc(pc); + if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ + ret = cpu_x86_search_pc(tb, &found_pc, pc); + if (ret < 0) + return 0; + env->eip = found_pc - tb->cs_base; + env->cr2 = address; /* we restore the process signal mask as the sigreturn should - do it */ + do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); - /* XXX: need to compute virtual pc position by retranslating - code. The rest of the CPU state should be correct. */ - env->cr2 = address; raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); /* never comes here */ return 1; diff --git a/exec-i386.h b/exec-i386.h index 938680d1e..ba5ea1a9a 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -217,11 +217,14 @@ typedef struct CCTable { extern CCTable cc_table[]; -void load_seg(int seg_reg, int selector); +void load_seg(int seg_reg, int selector, unsigned cur_eip); void cpu_lock(void); void cpu_unlock(void); +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip); void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); +void cpu_loop_exit(void); void OPPROTO op_movl_eflags_T0(void); void OPPROTO op_movl_T0_eflags(void); diff --git a/exec.c b/exec.c index 8f332c9ae..2e84f557b 100644 --- a/exec.c +++ b/exec.c @@ -531,3 +531,34 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size) page_unprotect(addr); } } + +/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < + tb[1].tc_ptr. Return NULL if not found */ +TranslationBlock *tb_find_pc(unsigned long tc_ptr) +{ + int m_min, m_max, m; + unsigned long v; + TranslationBlock *tb; + + if (nb_tbs <= 0) + return NULL; + if (tc_ptr < (unsigned long)code_gen_buffer || + tc_ptr >= (unsigned long)code_gen_ptr) + return NULL; + /* binary search (cf Knuth) */ + m_min = 0; + m_max = nb_tbs - 1; + while (m_min <= m_max) { + m = (m_min + m_max) >> 1; + tb = &tbs[m]; + v = (unsigned long)tb->tc_ptr; + if (v == tc_ptr) + return tb; + else if (tc_ptr < v) { + m_max = m - 1; + } else { + m_min = m + 1; + } + } + return &tbs[m_max]; +} diff --git a/exec.h b/exec.h index 29a7ab1fd..18e75e67b 100644 --- a/exec.h +++ b/exec.h @@ -28,10 +28,10 @@ #define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ struct TranslationBlock; -int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, - int *gen_code_size_ptr, - uint8_t *pc_start, uint8_t *cs_base, int flags, - int *code_size_ptr, struct TranslationBlock *tb); +int cpu_x86_gen_code(struct TranslationBlock *tb, + int max_code_size, int *gen_code_size_ptr); +int cpu_x86_search_pc(struct TranslationBlock *tb, + uint32_t *found_pc, unsigned long searched_pc); void cpu_x86_tblocks_init(void); void page_init(void); int page_unprotect(unsigned long address); @@ -161,6 +161,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, } } +TranslationBlock *tb_find_pc(unsigned long pc_ptr); + #ifndef offsetof #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif -- cgit v1.2.3 From aad13cd1311ad099a0471c062a2a38597e1742d6 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 May 2003 23:30:06 +0000 Subject: segment defines git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@195 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cpu-i386.h b/cpu-i386.h index fbe7965b4..51b175394 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -48,6 +48,23 @@ #define R_FS 4 #define R_GS 5 +/* segment descriptor fields */ +#define DESC_G_MASK (1 << 23) +#define DESC_B_MASK (1 << 22) +#define DESC_AVL_MASK (1 << 20) +#define DESC_P_MASK (1 << 15) +#define DESC_DPL_SHIFT 13 +#define DESC_S_MASK (1 << 12) +#define DESC_TYPE_SHIFT 8 +#define DESC_A_MASK (1 << 8) + +#define DESC_CS_MASK (1 << 11) +#define DESC_C_MASK (1 << 10) +#define DESC_R_MASK (1 << 9) + +#define DESC_E_MASK (1 << 10) +#define DESC_W_MASK (1 << 9) + /* eflags masks */ #define CC_C 0x0001 #define CC_P 0x0004 -- cgit v1.2.3 From 2d92f0b8f006fdd4ed2a2fdd6ada54761fe3ea56 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 28 May 2003 00:24:44 +0000 Subject: autogen opc-i386.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@196 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a5d4556f4..e52d484b7 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,15 @@ OP_CFLAGS+= -falign-functions=0 else OP_CFLAGS+= -malign-functions=0 endif +ifdef TARGET_GPROF +LDFLAGS+=-Wl,-T,i386.ld +else # WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object # that the kernel ELF loader considers as an executable. I think this # is the simplest way to make it self virtualizable! LDFLAGS+=-Wl,-shared endif +endif ifeq ($(ARCH),ppc) OP_CFLAGS=$(CFLAGS) @@ -111,11 +115,14 @@ libqemu.a: $(LIBOBJS) dyngen: dyngen.c $(HOST_CC) -O2 -Wall -g $< -o $@ -translate-i386.o: translate-i386.c op-i386.h cpu-i386.h +translate-i386.o: translate-i386.c op-i386.h opc-i386.h cpu-i386.h op-i386.h: op-i386.o dyngen ./dyngen -o $@ $< +opc-i386.h: op-i386.o dyngen + ./dyngen -c -o $@ $< + op-i386.o: op-i386.c opreg_template.h ops_template.h $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $< @@ -148,7 +155,7 @@ README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ Makefile elf.h thunk.c\ elfload.c main.c signal.c thunk.h exec.h\ -cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\ +cpu-i386.h qemu.h op-i386.c syscall-i386.h translate-i386.c\ syscall.c opreg_template.h syscall_defs.h vm86.c\ dis-asm.h dis-buf.c disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c\ ppc.ld s390.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \ -- cgit v1.2.3 From df0f11a03b5bda2a16b8fd9530b1feeef93da8e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 28 May 2003 00:27:57 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@197 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 6 ++- TODO | 31 +++++++------ VERSION | 2 +- qemu-doc.texi | 136 +++++++++++++++++++++++++++++++++++++--------------------- 4 files changed, 113 insertions(+), 62 deletions(-) diff --git a/Changelog b/Changelog index 0cfa8ff6d..567997d42 100644 --- a/Changelog +++ b/Changelog @@ -14,7 +14,11 @@ version 0.2: - SHL instruction C flag fix. - mmap emulation for host page size > 4KB - self-modifying code support - - better VM86 support (dosemu begins to work) + - 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: diff --git a/TODO b/TODO index f27a94335..85cdba755 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,22 @@ -- fix gcc 2.96 compile bug -- fix thread locks -- optimize translated cache chaining (DLL PLT-like system) + +- fix iret/lret/fpush not before mem load restarting +- fix all remaining thread lock issues (must put TBs in a specific invalid + state, find a solution for tb_flush()). +- handle fp87 state in signals +- add gcc 2.96 test configure (some gcc3 flags are needed) +- optimize FPU operations (evaluate x87 stack pointer statically) +- add IPC syscalls +- submit a patch to fix DOSEMU coopthreads + +lower priority: +-------------- +- handle rare page fault cases (in particular if page fault in heplers or + in syscall emulation code). - fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID) -- fix x86 stack allocation -- fix iret/lret restarting - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues, fix 16 bit uid issues) -- finish signal handing (fp87 state, more siginfo conversions) -- fix FPU exceptions (in particular: gen_op_fpush not before mem load) -- handle self-modifying code (track mmap and mark all pages containing - translated code as readonly. use a custom signal handler to flush - parts of the translation cache if write access to a readonly page - containing translated code). -- use gcc to compile to static code +- use page_unprotect_range in every suitable syscall to handle all + cases of self modifying code. +- use gcc as a backend to generate better code (easy to do by using + op-i386.c operations as local inline functions). +- add SSE2/MMX operations diff --git a/VERSION b/VERSION index a19223320..2f4536184 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.6 \ No newline at end of file +0.2 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index 2e324ca98..f63a17ac0 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -10,11 +10,11 @@ @chapter Introduction QEMU is an x86 processor emulator. Its purpose is to run x86 Linux -processes on non-x86 Linux architectures such as PowerPC or ARM. By -using dynamic translation it achieves a reasonnable speed while being -easy to port on new host CPUs. Its main goal is to be able to launch the -@code{Wine} Windows API emulator (@url{http://www.winehq.org}) on -non-x86 CPUs. +processes on non-x86 Linux architectures such as PowerPC. By using +dynamic translation it achieves a reasonnable speed while being easy to +port on new host CPUs. Its main goal is to be able to launch the +@code{Wine} Windows API emulator (@url{http://www.winehq.org}) or +@code{DOSEMU} (@url{http://www.dosemu.org}) on non-x86 CPUs. QEMU features: @@ -22,21 +22,26 @@ QEMU features: @item User space only x86 emulator. -@item Currently ported on i386, PowerPC and S390. +@item Currently ported on i386, PowerPC. Work in progress for S390, Alpha and Sparc. @item Using dynamic translation to native code for reasonnable speed. @item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. -User space LDT and GDT are emulated. VM86 mode is also supported -(experimental). +User space LDT and GDT are emulated. VM86 mode is also supported. @item Generic Linux system call converter, including most ioctls. @item clone() emulation using native CPU clone() to use Linux scheduler for threads. -@item Accurate signal handling by remapping host signals to virtual x86 signals. +@item Accurate signal handling by remapping host signals to virtual x86 signals. -@item QEMU can emulate itself on x86 (experimental). +@item Precise user space x86 exceptions. + +@item Self-modifying code support. + +@item Support of host page sizes bigger than 4KB. + +@item QEMU can emulate itself on x86. @item The virtual x86 CPU is a library (@code{libqemu}) which can be used in other projects. @@ -46,19 +51,15 @@ It can be used to test other x86 virtual CPUs. @end itemize -Current QEMU Limitations: +Current QEMU limitations: @itemize -@item Not all x86 exceptions are precise (yet). [Very few programs need that]. - -@item No support for self-modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !]. - @item No SSE/MMX support (yet). @item No x86-64 support. -@item Some Linux syscalls are missing. +@item IPC syscalls are missing. @item The x86 segment limits and access rights are not tested at every memory access (and will never be to have good performances). @@ -119,7 +120,7 @@ qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386 @end itemize -@section Wine launch (Currently only tested when emulating x86 on x86) +@section Wine launch @itemize @@ -152,17 +153,24 @@ qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Fil usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...] @end example -@table @samp +@table @option @item -h Print the help -@item -d -Activate log (logfile=/tmp/qemu.log) @item -L path Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) @item -s size Set the x86 stack size in bytes (default=524288) @end table +Debug options: + +@table @option +@item -d +Activate log (logfile=/tmp/qemu.log) +@item -p pagesize +Act as if the host page size was 'pagesize' bytes +@end table + @chapter QEMU Internals @section QEMU compared to other emulators @@ -265,17 +273,59 @@ contains just a single basic block (a block of x86 instructions terminated by a jump or by a virtual CPU state change which the translator cannot deduce statically). -[Currently, the translated code is not patched if it jumps to another -translated code]. +@section Direct block chaining + +After each translated basic block is executed, QEMU uses the simulated +Program Counter (PC) and other cpu state informations (such as the CS +segment base value) to find the next basic block. + +In order to accelerate the most common cases where the new simulated PC +is known, QEMU can patch a basic block so that it jumps directly to the +next one. + +The most portable code uses an indirect jump. An indirect jump makes it +easier to make the jump target modification atomic. On some +architectures (such as PowerPC), the @code{JUMP} opcode is directly +patched so that the block chaining has no overhead. + +@section Self-modifying code and translated code invalidation + +Self-modifying code is a special challenge in x86 emulation because no +instruction cache invalidation is signaled by the application when code +is modified. + +When translated code is generated for a basic block, the corresponding +host page is write protected if it is not already read-only (with the +system call @code{mprotect()}). Then, if a write access is done to the +page, Linux raises a SEGV signal. QEMU then invalidates all the +translated code in the page and enables write accesses to the page. + +Correct translated code invalidation is done efficiently by maintaining +a linked list of every translated block contained in a given page. Other +linked lists are also maintained to undo direct block chaining. + +Althought the overhead of doing @code{mprotect()} calls is important, +most MSDOS programs can be emulated at reasonnable speed with QEMU and +DOSEMU. + +Note that QEMU also invalidates pages of translated code when it detects +that memory mappings are modified with @code{mmap()} or @code{munmap()}. @section Exception support longjmp() is used when an exception such as division by zero is -encountered. The host SIGSEGV and SIGBUS signal handlers are used to get -invalid memory accesses. +encountered. -[Currently, the virtual CPU cannot retrieve the exact CPU state in some -exceptions, although it could except for the @code{EFLAGS} register]. +The host SIGSEGV and SIGBUS signal handlers are used to get invalid +memory accesses. The exact CPU state can be retrieved because all the +x86 registers are stored in fixed host registers. The simulated program +counter is found by retranslating the corresponding basic block and by +looking where the host program counter was at the exception point. + +The virtual CPU cannot retrieve the exact @code{EFLAGS} register because +in some cases it is not computed because of condition code +optimisations. It is not a big concern because the emulated code can +still be restarted in any cases. @section Linux system call translation @@ -284,6 +334,11 @@ the parameters of the system calls can be converted to fix the endianness and 32/64 bit issues. The IOCTLs are converted with a generic type description system (see @file{ioctls.h} and @file{thunk.c}). +QEMU supports host CPUs which have pages bigger than 4KB. It records all +the mappings the process does and try to emulated the @code{mmap()} +system calls in cases where the host @code{mmap()} call would fail +because of bad page alignment. + @section Linux signals Normal and real-time signals are queued along with their information @@ -312,6 +367,10 @@ thread. The virtual x86 CPU atomic operations are emulated with a global lock so that their semantic is preserved. +Note that currently there are still some locking issues in QEMU. In +particular, the translated cache flush is not protected yet against +reentrancy. + @section Self-virtualization QEMU was conceived so that ultimately it can emulate itself. Althought @@ -323,10 +382,6 @@ space conflicts. QEMU solves this problem by being an executable ELF shared object as the ld-linux.so ELF interpreter. That way, it can be relocated at load time. -Since self-modifying code is not supported yet, QEMU cannot emulate -itself in case of translation cache flush. This limitation will be -suppressed soon. - @section Bibliography @table @asis @@ -379,19 +434,10 @@ program and a @code{diff} on the generated output. The Linux system call @code{modify_ldt()} is used to create x86 selectors to test some 16 bit addressing and 32 bit with segmentation cases. -@section @file{testsig} - -This program tests various signal cases, including SIGFPE, SIGSEGV and -SIGILL. - -@section @file{testclone} +The Linux system call @code{vm86()} is used to test vm86 emulation. -Tests the @code{clone()} system call (basic test). - -@section @file{testthread} - -Tests the glibc threads (more complicated than @code{clone()} because signals -are also used). +Various exceptions are raised to test most of the x86 user space +exception reporting. @section @file{sha1} @@ -399,9 +445,3 @@ It is a simple benchmark. Care must be taken to interpret the results because it mostly tests the ability of the virtual CPU to optimize the @code{rol} x86 instruction and the condition code computations. -@section @file{runcom} - -A very simple MSDOS emulator to test the Linux vm86() system call -emulation. The excellent 54 byte @file{pi_10.com} PI number calculator -can be launched with it. @file{pi_10.com} was written by Bertram -Felgenhauer (more information at @url{http://www.boo.net/~jasonp/pipage.html}). -- cgit v1.2.3 From d0a1ffc9573b15997ecdfbc9ec5ec2fc1403d0f1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 May 2003 20:04:28 +0000 Subject: added fsave/frstor/fstenv/fldenv/fcomi - fixed cpuid - make lret/iret restartable git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@198 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 4 ++ exec-i386.c | 24 +++++++ exec-i386.h | 2 + op-i386.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- translate-i386.c | 135 +++++++++++++++++++++++++------------ 5 files changed, 315 insertions(+), 50 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index 51b175394..d277144b6 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -436,6 +436,10 @@ void cpu_x86_close(CPUX86State *s); /* needed to load some predefinied segment registers */ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); +/* simulate fsave/frstor */ +void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); +void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); + /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ diff --git a/exec-i386.c b/exec-i386.c index 002f00bdc..2114d656d 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -327,6 +327,30 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int 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(ptr, data32); + + env = saved_env; +} + +void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_frstor(ptr, data32); + + env = saved_env; +} + #undef EAX #undef ECX #undef EDX diff --git a/exec-i386.h b/exec-i386.h index ba5ea1a9a..00da9b8a3 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -225,6 +225,8 @@ void raise_interrupt(int intno, int is_int, int error_code, void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); void cpu_loop_exit(void); +void helper_fsave(uint8_t *ptr, int data32); +void helper_frstor(uint8_t *ptr, int data32); void OPPROTO op_movl_eflags_T0(void); void OPPROTO op_movl_T0_eflags(void); diff --git a/op-i386.c b/op-i386.c index 69bd4cffc..befa39f4d 100644 --- a/op-i386.c +++ b/op-i386.c @@ -1073,7 +1073,7 @@ void helper_cpuid(void) EBX = 0x756e6547; ECX = 0x6c65746e; EDX = 0x49656e69; - } else { + } else if (EAX == 1) { /* EAX = 1 info */ EAX = 0x52b; EBX = 0; @@ -1899,17 +1899,22 @@ void OPPROTO op_fldt_ST0_A0(void) ST0 = *(long double *)A0; } #else -void helper_fldt_ST0_A0(void) +static inline CPU86_LDouble helper_fldt(uint8_t *ptr) { CPU86_LDoubleU temp; int upper, e; /* mantissa */ - upper = lduw((uint8_t *)A0 + 8); + upper = lduw(ptr + 8); /* XXX: handle overflow ? */ e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ e |= (upper >> 4) & 0x800; /* sign */ - temp.ll = ((ldq((void *)A0) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); - ST0 = temp.d; + temp.ll = ((ldq(ptr) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); + return temp.d; +} + +void helper_fldt_ST0_A0(void) +{ + ST0 = helper_fldt((uint8_t *)A0); } void OPPROTO op_fldt_ST0_A0(void) @@ -2008,17 +2013,23 @@ void OPPROTO op_fstt_ST0_A0(void) *(long double *)A0 = ST0; } #else -void helper_fstt_ST0_A0(void) + +static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) { CPU86_LDoubleU temp; int e; - temp.d = ST0; + temp.d = f; /* mantissa */ - stq((void *)A0, (MANTD(temp) << 11) | (1LL << 63)); + stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); /* exponent + sign */ e = EXPD(temp) - EXPBIAS + 16383; e |= SIGND(temp) >> 16; - stw((uint8_t *)A0 + 8, e); + stw(ptr + 8, e); +} + +void helper_fstt_ST0_A0(void) +{ + helper_fstt(ST0, (uint8_t *)A0); } void OPPROTO op_fstt_ST0_A0(void) @@ -2254,6 +2265,34 @@ void OPPROTO op_fucom_ST0_FT0(void) FORCE_RET(); } +/* XXX: handle nans */ +void OPPROTO op_fcomi_ST0_FT0(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags &= ~(CC_Z | CC_P | CC_C); + if (ST0 < FT0) + eflags |= CC_C; + else if (ST0 == FT0) + eflags |= CC_Z; + CC_SRC = eflags; + FORCE_RET(); +} + +/* XXX: handle nans */ +void OPPROTO op_fucomi_ST0_FT0(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags &= ~(CC_Z | CC_P | CC_C); + if (ST0 < FT0) + eflags |= CC_C; + else if (ST0 == FT0) + eflags |= CC_Z; + CC_SRC = eflags; + FORCE_RET(); +} + void OPPROTO op_fadd_ST0_FT0(void) { ST0 += FT0; @@ -2750,6 +2789,149 @@ void OPPROTO op_fninit(void) env->fptags[7] = 1; } +void helper_fstenv(uint8_t *ptr, int data32) +{ + int fpus, fptag, exp, i; + uint64_t mant; + CPU86_LDoubleU tmp; + + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for (i=7; i>=0; i--) { + fptag <<= 2; + if (env->fptags[i]) { + fptag |= 3; + } else { + tmp.d = env->fpregs[i]; + exp = EXPD(tmp); + mant = MANTD(tmp); + if (exp == 0 && mant == 0) { + /* zero */ + fptag |= 1; + } else if (exp == 0 || exp == MAXEXPD +#ifdef USE_X86LDOUBLE + || (mant & (1LL << 63)) == 0 +#endif + ) { + /* NaNs, infinity, denormal */ + fptag |= 2; + } + } + } + if (data32) { + /* 32 bit */ + stl(ptr, env->fpuc); + stl(ptr + 4, fpus); + stl(ptr + 8, fptag); + stl(ptr + 12, 0); + stl(ptr + 16, 0); + stl(ptr + 20, 0); + stl(ptr + 24, 0); + } else { + /* 16 bit */ + stw(ptr, env->fpuc); + stw(ptr + 2, fpus); + stw(ptr + 4, fptag); + stw(ptr + 6, 0); + stw(ptr + 8, 0); + stw(ptr + 10, 0); + stw(ptr + 12, 0); + } +} + +void helper_fldenv(uint8_t *ptr, int data32) +{ + int i, fpus, fptag; + + if (data32) { + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 4); + fptag = lduw(ptr + 8); + } + else { + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 2); + fptag = lduw(ptr + 4); + } + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + for(i = 0;i < 7; i++) { + env->fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } +} + +void helper_fsave(uint8_t *ptr, int data32) +{ + CPU86_LDouble tmp; + int i; + + helper_fstenv(ptr, data32); + + ptr += (14 << data32); + for(i = 0;i < 8; i++) { + tmp = ST(i); +#ifdef USE_X86LDOUBLE + *(long double *)ptr = tmp; +#else + helper_fstt(tmp, ptr); +#endif + ptr += 10; + } + + /* fninit */ + env->fpus = 0; + env->fpstt = 0; + env->fpuc = 0x37f; + env->fptags[0] = 1; + env->fptags[1] = 1; + env->fptags[2] = 1; + env->fptags[3] = 1; + env->fptags[4] = 1; + env->fptags[5] = 1; + env->fptags[6] = 1; + env->fptags[7] = 1; +} + +void helper_frstor(uint8_t *ptr, int data32) +{ + CPU86_LDouble tmp; + int i; + + helper_fldenv(ptr, data32); + ptr += (14 << data32); + + for(i = 0;i < 8; i++) { +#ifdef USE_X86LDOUBLE + tmp = *(long double *)ptr; +#else + tmp = helper_fldt(ptr); +#endif + ST(i) = tmp; + ptr += 10; + } +} + +void OPPROTO op_fnstenv_A0(void) +{ + helper_fstenv((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_fldenv_A0(void) +{ + helper_fldenv((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_fnsave_A0(void) +{ + helper_fsave((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_frstor_A0(void) +{ + helper_frstor((uint8_t *)A0, PARAM1); +} + /* threading support */ void OPPROTO op_lock(void) { diff --git a/translate-i386.c b/translate-i386.c index e682d8139..3802c5e92 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1273,21 +1273,40 @@ static void gen_pop_T0(DisasContext *s) } } -static void gen_pop_update(DisasContext *s) +static inline void gen_stack_update(DisasContext *s, int addend) { if (s->ss32) { - if (s->dflag) - gen_op_addl_ESP_4(); - else + if (addend == 2) gen_op_addl_ESP_2(); + else if (addend == 4) + gen_op_addl_ESP_4(); + else + gen_op_addl_ESP_im(addend); } else { - if (s->dflag) + if (addend == 2) + gen_op_addw_ESP_2(); + else if (addend == 4) gen_op_addw_ESP_4(); else - gen_op_addw_ESP_2(); + gen_op_addw_ESP_im(addend); } } +static void gen_pop_update(DisasContext *s) +{ + gen_stack_update(s, 2 << s->dflag); +} + +static void gen_stack_A0(DisasContext *s) +{ + gen_op_movl_A0_ESP(); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); +} + /* NOTE: wrap around in 16 bit not fully handled */ static void gen_pusha(DisasContext *s) { @@ -1957,7 +1976,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0xc9: /* leave */ - /* XXX: exception not precise (ESP is update before potential exception) */ + /* XXX: exception not precise (ESP is updated before potential exception) */ if (s->ss32) { gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); gen_op_mov_reg_T0[OT_LONG][R_ESP](); @@ -2453,9 +2472,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; } break; + case 0x0c: /* fldenv mem */ + gen_op_fldenv_A0(s->dflag); + break; case 0x0d: /* fldcw mem */ gen_op_fldcw_A0(); break; + case 0x0e: /* fnstenv mem */ + gen_op_fnstenv_A0(s->dflag); + break; case 0x0f: /* fnstcw mem */ gen_op_fnstcw_A0(); break; @@ -2467,6 +2492,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fstt_ST0_A0(); gen_op_fpop(); break; + case 0x2c: /* frstor mem */ + gen_op_frstor_A0(s->dflag); + break; + case 0x2e: /* fnsave mem */ + gen_op_fnsave_A0(s->dflag); + break; case 0x2f: /* fnstsw mem */ gen_op_fnstsw_A0(); break; @@ -2672,6 +2703,20 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; } break; + case 0x1d: /* fucomi */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fucomi_ST0_FT0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x1e: /* fcomi */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcomi_ST0_FT0(); + s->cc_op = CC_OP_EFLAGS; + break; case 0x2a: /* fst sti */ gen_op_fmov_STN_ST0(opreg); break; @@ -2709,6 +2754,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; } break; + case 0x3d: /* fucomip */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fucomi_ST0_FT0(); + gen_op_fpop(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x3e: /* fcomip */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcomi_ST0_FT0(); + gen_op_fpop(); + s->cc_op = CC_OP_EFLAGS; + break; default: goto illegal_op; } @@ -2901,10 +2962,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = ldsw(s->pc); s->pc += 2; gen_pop_T0(s); - if (s->ss32) - gen_op_addl_ESP_im(val + (2 << s->dflag)); - else - gen_op_addw_ESP_im(val + (2 << s->dflag)); + gen_stack_update(s, val + (2 << s->dflag)); if (s->dflag == 0) gen_op_andl_T0_ffff(); gen_op_jmp_T0(); @@ -2919,63 +2977,55 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->is_jmp = 1; break; case 0xca: /* lret im */ - /* XXX: not restartable */ val = ldsw(s->pc); s->pc += 2; + do_lret: + gen_stack_A0(s); /* pop offset */ - gen_pop_T0(s); + gen_op_ld_T0_A0[1 + s->dflag](); if (s->dflag == 0) gen_op_andl_T0_ffff(); + /* NOTE: keeping EIP updated is not a problem in case of + exception */ gen_op_jmp_T0(); - gen_pop_update(s); /* pop selector */ - gen_pop_T0(s); + gen_op_addl_A0_im(2 << s->dflag); + gen_op_ld_T0_A0[1 + s->dflag](); gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - gen_pop_update(s); /* add stack offset */ - if (s->ss32) - gen_op_addl_ESP_im(val); - else - gen_op_addw_ESP_im(val); + gen_stack_update(s, val + (4 << s->dflag)); s->is_jmp = 1; break; case 0xcb: /* lret */ - /* XXX: not restartable */ - /* pop offset */ - gen_pop_T0(s); - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); - gen_pop_update(s); - /* pop selector */ - gen_pop_T0(s); - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - gen_pop_update(s); - s->is_jmp = 1; - break; + val = 0; + goto do_lret; case 0xcf: /* iret */ if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { /* XXX: not restartable */ + gen_stack_A0(s); /* pop offset */ - gen_pop_T0(s); + gen_op_ld_T0_A0[1 + s->dflag](); if (s->dflag == 0) gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); - gen_pop_update(s); + /* NOTE: keeping EIP updated is not a problem in case of + exception */ + gen_op_jmp_T0(); /* pop selector */ - gen_pop_T0(s); - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - gen_pop_update(s); + gen_op_addl_A0_im(2 << s->dflag); + gen_op_ld_T0_A0[1 + s->dflag](); /* pop eflags */ - gen_pop_T0(s); + gen_op_addl_A0_im(2 << s->dflag); + gen_op_ld_T1_A0[1 + s->dflag](); + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); + gen_op_movl_T0_T1(); if (s->dflag) { gen_op_movl_eflags_T0(); } else { gen_op_movw_eflags_T0(); } - gen_pop_update(s); + gen_stack_update(s, (6 << s->dflag)); s->cc_op = CC_OP_EFLAGS; } s->is_jmp = 1; @@ -2997,6 +3047,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x9a: /* lcall im */ { unsigned int selector, offset; + /* XXX: not restartable */ ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); @@ -3613,6 +3664,8 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_cmpxchg8b] = CC_Z, [INDEX_op_lar] = CC_Z, [INDEX_op_lsl] = CC_Z, + [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, + [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, }; /* simpler form of an operation if no flags need to be generated */ -- cgit v1.2.3 From c1e42a13975f671e9c31422eb43dfc737c0a6ab6 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 May 2003 20:05:18 +0000 Subject: search data in both .data and .sdata git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@199 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/dyngen.c b/dyngen.c index 4ed8b4b8b..bfc1540c3 100644 --- a/dyngen.c +++ b/dyngen.c @@ -178,8 +178,8 @@ ElfW(Sym) *symtab; int nb_syms; char *strtab; /* data section */ -uint8_t *data_data; -int data_shndx; +uint8_t *data_data, *sdata_data; +int data_shndx, sdata_shndx; uint16_t get16(uint16_t *p) { @@ -499,11 +499,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { sym_name = strtab + sym->st_name; if (strstart(sym_name, "__op_label", &p)) { + uint8_t *ptr; + /* test if the variable refers to a label inside the code we are generating */ - if (sym->st_shndx != data_shndx) + if (sym->st_shndx == data_shndx) + ptr = data_data; + else if (sym->st_shndx == sdata_shndx) + ptr = sdata_data; + else error("__op_labelN symbols must be in .data or .sdata section"); - val = *(target_ulong *)(data_data + sym->st_value); + val = *(target_ulong *)(ptr + sym->st_value); if (val >= start_offset && val < start_offset + copy_size) { n = strtol(p, NULL, 10); fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); @@ -878,7 +884,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec; int i, j; ElfW(Sym) *sym; - char *shstr, *data_name; + char *shstr; uint8_t *text; void *relocs; int nb_relocs, reloc_sh_type; @@ -930,16 +936,18 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) error("could not find .text section"); text = load_data(fd, text_sec->sh_offset, text_sec->sh_size); -#if defined(HOST_PPC) - data_name = ".sdata"; -#else - data_name = ".data"; -#endif - sec = find_elf_section(shdr, ehdr.e_shnum, shstr, data_name); - if (!sec) - error("could not find %s section", data_name); - data_shndx = sec - shdr; - data_data = load_data(fd, sec->sh_offset, sec->sh_size); + data_shndx = -1; + sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".data"); + if (sec) { + data_shndx = sec - shdr; + data_data = load_data(fd, sec->sh_offset, sec->sh_size); + } + sdata_shndx = -1; + sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".sdata"); + if (sec) { + sdata_shndx = sec - shdr; + sdata_data = load_data(fd, sec->sh_offset, sec->sh_size); + } /* find text relocations, if any */ nb_relocs = 0; -- cgit v1.2.3 From 4304763ba281f805684fb41e7b2cde8b401980df Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 May 2003 20:05:35 +0000 Subject: misplaced #endif git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@200 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index eeea342d2..6c03d6f92 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -38,6 +38,7 @@ static const char *interp_prefix = CONFIG_QEMU_PREFIX; /* Force usage of an ELF interpreter even if it is an ELF shared object ! */ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; +#endif /* for recent libc, we add these dummies symbol which are not declared when generating a linked object (bug in ld ?) */ @@ -48,8 +49,6 @@ long __fini_array_start[0]; long __fini_array_end[0]; #endif -#endif - /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example by remapping the process stack directly at the right place */ -- cgit v1.2.3 From ed2dcdf68e73348764850251443fd0c32dd33e81 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 May 2003 20:06:27 +0000 Subject: save FPU state in signal handler git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@201 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 43 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 0601a34f0..2aad2ab5f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -536,15 +536,12 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, err |= __put_user(env->eflags, &sc->eflags); err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal); err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss); -#if 0 - tmp = save_i387(fpstate); - if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); -#else - err |= __put_user(0, &sc->fpstate); -#endif + + cpu_x86_fsave(env, (void *)fpstate, 1); + fpstate->status = fpstate->sw; + err |= __put_user(0xffff, &fpstate->magic); + err |= __put_user(fpstate, &sc->fpstate); + /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); err |= __put_user(env->cr2, &sc->cr2); @@ -721,25 +718,6 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax) { unsigned int err = 0; - - -#define COPY(x) err |= __get_user(regs->x, &sc->x) - -#define COPY_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ - regs->x##seg = tmp; } - -#define COPY_SEG_STRICT(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ - regs->x##seg = tmp|3; } - -#define GET_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ - loadsegment(seg,tmp); } - cpu_x86_load_seg(env, R_GS, lduw(&sc->gs)); cpu_x86_load_seg(env, R_FS, lduw(&sc->fs)); cpu_x86_load_seg(env, R_ES, lduw(&sc->es)); @@ -764,17 +742,18 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax) // regs->orig_eax = -1; /* disable syscall checks */ } -#if 0 { struct _fpstate * buf; - err |= __get_user(buf, &sc->fpstate); + buf = (void *)ldl(&sc->fpstate); if (buf) { +#if 0 if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; - err |= restore_i387(buf); +#endif + cpu_x86_frstor(env, (void *)buf, 1); } } -#endif + *peax = ldl(&sc->eax); return err; #if 0 -- cgit v1.2.3 From 03bfca946a9fdf7a437f28183be36b4bf89b51e9 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 May 2003 20:06:57 +0000 Subject: more FPU tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@202 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 39c7a55a7..56dc6af93 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -9,7 +9,8 @@ #include #include -#define TEST_CMOV 0 +#define TEST_CMOV 0 +#define TEST_FCOMI 0 #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) @@ -510,6 +511,16 @@ void test_fcmp(double a, double b) a, b, a > b); printf("(%f<=%f)=%d\n", a, b, a >= b); + if (TEST_FCOMI) { + unsigned int eflags; + /* test f(u)comi instruction */ + asm("fcomi %2, %1\n" + "pushf\n" + "pop %0\n" + : "=r" (eflags) + : "t" (a), "u" (b)); + printf("fcomi(%f %f)=%08x\n", a, b, eflags & (CC_Z | CC_P | CC_C)); + } } void test_fcvt(double a) @@ -556,6 +567,57 @@ void test_fbcd(double a) a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); } +#define TEST_ENV(env, prefix)\ +{\ + memset((env), 0xaa, sizeof(*(env)));\ + asm("fld1\n"\ + prefix "fnstenv %1\n"\ + prefix "fldenv %1\n"\ + : "=t" (res) : "m" (*(env)) : "st");\ + printf("res=%f\n", res);\ + printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ + (env)->fpuc,\ + (env)->fpus & 0xff00,\ + (env)->fptag);\ + memset((env), 0xaa, sizeof(*(env)));\ + asm("fld1\n"\ + prefix "fnsave %1\n"\ + prefix "frstor %1\n"\ + : "=t" (res) : "m" (*(env)) : "st");\ + printf("res=%f\n", res);\ + printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ + (env)->fpuc,\ + (env)->fpus & 0xff00,\ + (env)->fptag);\ + printf("ST(0) = %Lf\n",\ + (env)->fpregs[0]);\ +} + +void test_fenv(void) +{ + struct __attribute__((packed)) { + uint16_t fpuc; + uint16_t dummy1; + uint16_t fpus; + uint16_t dummy2; + uint16_t fptag; + uint16_t dummy3; + uint32_t ignored[4]; + long double fpregs[8]; + } float_env32; + struct __attribute__((packed)) { + uint16_t fpuc; + uint16_t fpus; + uint16_t fptag; + uint16_t ignored[4]; + long double fpregs[8]; + } float_env16; + double res; + + TEST_ENV(&float_env16, "data16 "); + TEST_ENV(&float_env32, ""); +} + void test_floats(void) { test_fops(2, 3); @@ -569,6 +631,7 @@ void test_floats(void) test_fconst(); test_fbcd(1234567890123456); test_fbcd(-123451234567890); + test_fenv(); } /**********************************************/ -- cgit v1.2.3 From 2f87c60799042f6c9936040cedf6ea8dc690ca22 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 2 Jun 2003 20:38:09 +0000 Subject: Alpha update (Falk Hueffner) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@203 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 2 +- exec-i386.c | 28 ++++++++++++++++++++++++++++ exec-i386.h | 2 ++ exec.h | 2 +- op-i386.c | 10 +++++----- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/dyngen.c b/dyngen.c index bfc1540c3..225d2bab8 100644 --- a/dyngen.c +++ b/dyngen.c @@ -691,7 +691,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, case R_ALPHA_BRSGP: /* PC-relative jump. Tweak offset to skip the two instructions that try to set up the gp from the pv. */ - fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld) + 4);\n", + fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n", rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset); break; default: diff --git a/exec-i386.c b/exec-i386.c index 2114d656d..5bd69d4a5 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -447,6 +447,34 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, is_write, &uc->uc_sigmask); } +#elif defined(__alpha__) + +int cpu_x86_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; + + 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); +} #else #error CPU specific signal handler needed diff --git a/exec-i386.h b/exec-i386.h index 00da9b8a3..af8237003 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -124,6 +124,8 @@ register unsigned int A0 asm("$11"); register unsigned int EAX asm("$12"); register unsigned int ESP asm("$13"); register unsigned int EBP asm("$14"); +/* Note $15 is the frame pointer, so anything in op-i386.c that would + require a frame pointer, like alloca, would probably loose. */ register struct CPUX86State *env asm("$15"); #define reg_EAX #define reg_ESP diff --git a/exec.h b/exec.h index 18e75e67b..0098ad83a 100644 --- a/exec.h +++ b/exec.h @@ -214,7 +214,7 @@ static inline int testandset (int *p) #endif #ifdef __alpha__ -int testandset (int *p) +static inline int testandset (int *p) { int ret; unsigned long one; diff --git a/op-i386.c b/op-i386.c index befa39f4d..df841cec6 100644 --- a/op-i386.c +++ b/op-i386.c @@ -1762,16 +1762,16 @@ typedef union { double d; #ifndef WORDS_BIGENDIAN struct { - unsigned long lower; - long upper; + uint32_t lower; + int32_t upper; } l; #else struct { - long upper; - unsigned long lower; + int32_t upper; + uint32_t lower; } l; #endif - long long ll; + int64_t ll; } CPU86_LDoubleU; /* the following deal with IEEE double-precision numbers */ -- cgit v1.2.3 From 3ec9c4fcc649d6a32c3a9fba6add43a996248937 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 00:54:09 +0000 Subject: separated helpers from micro operations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@204 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.h | 177 ++++++++++++- helper-i386.c | 735 +++++++++++++++++++++++++++++++++++++++++++++++++++ op-i386.c | 837 +--------------------------------------------------------- 3 files changed, 908 insertions(+), 841 deletions(-) create mode 100644 helper-i386.c diff --git a/exec-i386.h b/exec-i386.h index af8237003..d89a318cc 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -189,15 +189,22 @@ register struct CPUX86State *env asm("r27"); #define FP_CONVERT (env->fp_convert) #endif +#ifdef __alpha__ +/* the symbols are considered non exported so a br immediate is generated */ +#define __hidden __attribute__((visibility("hidden"))) +#else +#define __hidden +#endif + #ifdef __alpha__ /* Suggested by Richard Henderson. This will result in code like ldah $0,__op_param1($29) !gprelhigh lda $0,__op_param1($0) !gprellow We can then conveniently change $29 to $31 and adapt the offsets to emit the appropriate constant. */ -extern int __op_param1 __attribute__((visibility("hidden"))); -extern int __op_param2 __attribute__((visibility("hidden"))); -extern int __op_param3 __attribute__((visibility("hidden"))); +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; }) @@ -220,15 +227,173 @@ typedef struct CCTable { extern CCTable cc_table[]; void load_seg(int seg_reg, int selector, unsigned cur_eip); -void cpu_lock(void); -void cpu_unlock(void); +void __hidden cpu_lock(void); +void __hidden cpu_unlock(void); void raise_interrupt(int intno, int is_int, int error_code, unsigned int next_eip); void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); -void cpu_loop_exit(void); +void __hidden cpu_loop_exit(void); void helper_fsave(uint8_t *ptr, int data32); void helper_frstor(uint8_t *ptr, int data32); void OPPROTO op_movl_eflags_T0(void); void OPPROTO op_movl_T0_eflags(void); +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip); +void raise_exception_err(int exception_index, int error_code); +void raise_exception(int exception_index); +void helper_cpuid(void); +void helper_lsl(void); +void helper_lar(void); + + +#ifdef USE_X86LDOUBLE +/* use long double functions */ +#define lrint lrintl +#define llrint llrintl +#define fabs fabsl +#define sin sinl +#define cos cosl +#define sqrt sqrtl +#define pow powl +#define log logl +#define tan tanl +#define atan2 atan2l +#define floor floorl +#define ceil ceill +#define rint rintl +#endif + +extern int lrint(CPU86_LDouble x); +extern int64_t llrint(CPU86_LDouble x); +extern CPU86_LDouble fabs(CPU86_LDouble x); +extern CPU86_LDouble sin(CPU86_LDouble x); +extern CPU86_LDouble cos(CPU86_LDouble x); +extern CPU86_LDouble sqrt(CPU86_LDouble x); +extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); +extern CPU86_LDouble log(CPU86_LDouble x); +extern CPU86_LDouble tan(CPU86_LDouble x); +extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); +extern CPU86_LDouble floor(CPU86_LDouble x); +extern CPU86_LDouble ceil(CPU86_LDouble x); +extern CPU86_LDouble rint(CPU86_LDouble x); + +#define RC_MASK 0xc00 +#define RC_NEAR 0x000 +#define RC_DOWN 0x400 +#define RC_UP 0x800 +#define RC_CHOP 0xc00 + +#define MAXTAN 9223372036854775808.0 + +#ifdef USE_X86LDOUBLE + +/* only for x86 */ +typedef union { + long double d; + struct { + unsigned long long lower; + unsigned short upper; + } l; +} CPU86_LDoubleU; + +/* the following deal with x86 long double-precision numbers */ +#define MAXEXPD 0x7fff +#define EXPBIAS 16383 +#define EXPD(fp) (fp.l.upper & 0x7fff) +#define SIGND(fp) ((fp.l.upper) & 0x8000) +#define MANTD(fp) (fp.l.lower) +#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS + +#else + +typedef union { + double d; +#ifndef WORDS_BIGENDIAN + struct { + uint32_t lower; + int32_t upper; + } l; +#else + struct { + int32_t upper; + uint32_t lower; + } l; +#endif + int64_t ll; +} CPU86_LDoubleU; + +/* the following deal with IEEE double-precision numbers */ +#define MAXEXPD 0x7ff +#define EXPBIAS 1023 +#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) +#define SIGND(fp) ((fp.l.upper) & 0x80000000) +#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) +#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) +#endif + +static inline void fpush(void) +{ + env->fpstt = (env->fpstt - 1) & 7; + env->fptags[env->fpstt] = 0; /* validate stack entry */ +} + +static inline void fpop(void) +{ + env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ + env->fpstt = (env->fpstt + 1) & 7; +} + +#ifndef USE_X86LDOUBLE +static inline CPU86_LDouble helper_fldt(uint8_t *ptr) +{ + CPU86_LDoubleU temp; + int upper, e; + /* mantissa */ + upper = lduw(ptr + 8); + /* XXX: handle overflow ? */ + e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ + e |= (upper >> 4) & 0x800; /* sign */ + temp.ll = ((ldq(ptr) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); + return temp.d; +} + +static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) +{ + CPU86_LDoubleU temp; + int e; + temp.d = f; + /* mantissa */ + stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); + /* exponent + sign */ + e = EXPD(temp) - EXPBIAS + 16383; + e |= SIGND(temp) >> 16; + stw(ptr + 8, e); +} +#endif + +void helper_fldt_ST0_A0(void); +void helper_fstt_ST0_A0(void); +void helper_fbld_ST0_A0(void); +void helper_fbst_ST0_A0(void); +void helper_f2xm1(void); +void helper_fyl2x(void); +void helper_fptan(void); +void helper_fpatan(void); +void helper_fxtract(void); +void helper_fprem1(void); +void helper_fprem(void); +void helper_fyl2xp1(void); +void helper_fsqrt(void); +void helper_fsincos(void); +void helper_frndint(void); +void helper_fscale(void); +void helper_fsin(void); +void helper_fcos(void); +void helper_fxam_ST0(void); +void helper_fstenv(uint8_t *ptr, int data32); +void helper_fldenv(uint8_t *ptr, int data32); +void helper_fsave(uint8_t *ptr, int data32); +void helper_frstor(uint8_t *ptr, int data32); + diff --git a/helper-i386.c b/helper-i386.c new file mode 100644 index 000000000..5f3040bf2 --- /dev/null +++ b/helper-i386.c @@ -0,0 +1,735 @@ +/* + * i386 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 + */ +#include "exec-i386.h" + +#if 0 +/* full interrupt support (only useful for real CPU emulation, not + finished) - I won't do it any time soon, finish it if you want ! */ +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentDescriptorTable *dt; + uint8_t *ptr; + int type, dpl, cpl; + uint32_t e1, e2; + + dt = &env->idt; + if (intno * 8 + 7 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + ptr = dt->base + intno * 8; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + switch(type) { + case 5: /* task gate */ + case 6: /* 286 interrupt gate */ + case 7: /* 286 trap gate */ + case 14: /* 386 interrupt gate */ + case 15: /* 386 trap gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + break; + } + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->segs[R_CS] & 3; + /* check privledge if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); +} + +#else + +/* + * is_int is TRUE if coming from the int instruction. next_eip is the + * EIP value AFTER the interrupt instruction. It is only relevant if + * is_int is TRUE. + */ +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentDescriptorTable *dt; + uint8_t *ptr; + int dpl, cpl; + uint32_t e2; + + dt = &env->idt; + ptr = dt->base + (intno * 8); + e2 = ldl(ptr + 4); + + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = 3; + /* check privledge if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + + /* Since we emulate only user space, we cannot do more than + exiting the emulation with the suitable exception and error + code */ + if (is_int) + EIP = next_eip; + env->exception_index = intno; + env->error_code = error_code; + + cpu_loop_exit(); +} + +#endif + +/* shortcuts to generate exceptions */ +void raise_exception_err(int exception_index, int error_code) +{ + raise_interrupt(exception_index, 0, error_code, 0); +} + +void raise_exception(int exception_index) +{ + raise_interrupt(exception_index, 0, 0, 0); +} + +/* We simulate a pre-MMX pentium as in valgrind */ +#define CPUID_FP87 (1 << 0) +#define CPUID_VME (1 << 1) +#define CPUID_DE (1 << 2) +#define CPUID_PSE (1 << 3) +#define CPUID_TSC (1 << 4) +#define CPUID_MSR (1 << 5) +#define CPUID_PAE (1 << 6) +#define CPUID_MCE (1 << 7) +#define CPUID_CX8 (1 << 8) +#define CPUID_APIC (1 << 9) +#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ +#define CPUID_MTRR (1 << 12) +#define CPUID_PGE (1 << 13) +#define CPUID_MCA (1 << 14) +#define CPUID_CMOV (1 << 15) +/* ... */ +#define CPUID_MMX (1 << 23) +#define CPUID_FXSR (1 << 24) +#define CPUID_SSE (1 << 25) +#define CPUID_SSE2 (1 << 26) + +void helper_cpuid(void) +{ + if (EAX == 0) { + EAX = 1; /* max EAX index supported */ + EBX = 0x756e6547; + ECX = 0x6c65746e; + EDX = 0x49656e69; + } else if (EAX == 1) { + /* EAX = 1 info */ + EAX = 0x52b; + EBX = 0; + ECX = 0; + EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | + CPUID_TSC | CPUID_MSR | CPUID_MCE | + CPUID_CX8; + } +} + +/* only works if protected mode and not VM86 */ +void load_seg(int seg_reg, int selector, unsigned cur_eip) +{ + SegmentCache *sc; + SegmentDescriptorTable *dt; + int index; + uint32_t e1, e2; + uint8_t *ptr; + + sc = &env->seg_cache[seg_reg]; + if ((selector & 0xfffc) == 0) { + /* null selector case */ + if (seg_reg == R_SS) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } else { + /* XXX: each access should trigger an exception */ + sc->base = NULL; + sc->limit = 0; + sc->seg_32bit = 1; + } + } else { + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + if (!(e2 & DESC_S_MASK) || + (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + + if (seg_reg == R_SS) { + if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + } else { + if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + } + + if (!(e2 & DESC_P_MASK)) { + EIP = cur_eip; + if (seg_reg == R_SS) + raise_exception_err(EXCP0C_STACK, selector & 0xfffc); + else + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + } + + sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); + sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & (1 << 23)) + sc->limit = (sc->limit << 12) | 0xfff; + sc->seg_32bit = (e2 >> 22) & 1; +#if 0 + fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", + selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); +#endif + } + env->segs[seg_reg] = selector; +} + +void helper_lsl(void) +{ + unsigned int selector, limit; + SegmentDescriptorTable *dt; + int index; + uint32_t e1, e2; + uint8_t *ptr; + + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + selector = T0 & 0xffff; + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + return; + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & (1 << 23)) + limit = (limit << 12) | 0xfff; + T1 = limit; + CC_SRC |= CC_Z; +} + +void helper_lar(void) +{ + unsigned int selector; + SegmentDescriptorTable *dt; + int index; + uint32_t e2; + uint8_t *ptr; + + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + selector = T0 & 0xffff; + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + return; + ptr = dt->base + index; + e2 = ldl(ptr + 4); + T1 = e2 & 0x00f0ff00; + CC_SRC |= CC_Z; +} + +/* FPU helpers */ + +#ifndef USE_X86LDOUBLE +void helper_fldt_ST0_A0(void) +{ + ST0 = helper_fldt((uint8_t *)A0); +} + +void helper_fstt_ST0_A0(void) +{ + helper_fstt(ST0, (uint8_t *)A0); +} +#endif + +/* BCD ops */ + +#define MUL10(iv) ( iv + iv + (iv << 3) ) + +void helper_fbld_ST0_A0(void) +{ + uint8_t *seg; + CPU86_LDouble fpsrcop; + int m32i; + unsigned int v; + + /* in this code, seg/m32i will be used as temporary ptr/int */ + seg = (uint8_t *)A0 + 8; + v = ldub(seg--); + /* XXX: raise exception */ + if (v != 0) + return; + v = ldub(seg--); + /* XXX: raise exception */ + if ((v & 0xf0) != 0) + return; + m32i = v; /* <-- d14 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */ + fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0; + + v = ldub(seg--); + m32i = (v >> 4); /* <-- d7 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */ + v = ldub(seg--); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */ + v = ldub(seg); + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */ + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */ + fpsrcop += ((CPU86_LDouble)m32i); + if ( ldub(seg+9) & 0x80 ) + fpsrcop = -fpsrcop; + ST0 = fpsrcop; +} + +void helper_fbst_ST0_A0(void) +{ + CPU86_LDouble fptemp; + CPU86_LDouble fpsrcop; + int v; + uint8_t *mem_ref, *mem_end; + + fpsrcop = rint(ST0); + mem_ref = (uint8_t *)A0; + mem_end = mem_ref + 8; + if ( fpsrcop < 0.0 ) { + stw(mem_end, 0x8000); + fpsrcop = -fpsrcop; + } else { + stw(mem_end, 0x0000); + } + while (mem_ref < mem_end) { + if (fpsrcop == 0.0) + break; + fptemp = floor(fpsrcop/10.0); + v = ((int)(fpsrcop - fptemp*10.0)); + if (fptemp == 0.0) { + stb(mem_ref++, v); + break; + } + fpsrcop = fptemp; + fptemp = floor(fpsrcop/10.0); + v |= (((int)(fpsrcop - fptemp*10.0)) << 4); + stb(mem_ref++, v); + fpsrcop = fptemp; + } + while (mem_ref < mem_end) { + stb(mem_ref++, 0); + } +} + +void helper_f2xm1(void) +{ + ST0 = pow(2.0,ST0) - 1.0; +} + +void helper_fyl2x(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp>0.0){ + fptemp = log(fptemp)/log(2.0); /* log2(ST) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +void helper_fptan(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = tan(fptemp); + fpush(); + ST0 = 1.0; + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**52 only */ + } +} + +void helper_fpatan(void) +{ + CPU86_LDouble fptemp, fpsrcop; + + fpsrcop = ST1; + fptemp = ST0; + ST1 = atan2(fpsrcop,fptemp); + fpop(); +} + +void helper_fxtract(void) +{ + CPU86_LDoubleU temp; + unsigned int expdif; + + temp.d = ST0; + expdif = EXPD(temp) - EXPBIAS; + /*DP exponent bias*/ + ST0 = expdif; + fpush(); + BIASEXPONENT(temp); + ST0 = temp.d; +} + +void helper_fprem1(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + int q; + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + if (expdif < 53) { + dblq = fpsrcop / fptemp; + dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); + ST0 = fpsrcop - fptemp*dblq; + q = (int)dblq; /* cutting off top bits is assumed here */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C1,C3) <-- (q2,q1,q0) */ + env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ + env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ + env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif-50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by rounding to the nearest */ + fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? + floor(fpsrcop): ceil(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +void helper_fprem(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + int q; + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + if ( expdif < 53 ) { + dblq = fpsrcop / fptemp; + dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); + ST0 = fpsrcop - fptemp*dblq; + q = (int)dblq; /* cutting off top bits is assumed here */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C1,C3) <-- (q2,q1,q0) */ + env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ + env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ + env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif-50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by chopping */ + fpsrcop = (fpsrcop < 0.0)? + -(floor(fabs(fpsrcop))): floor(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +void helper_fyl2xp1(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp+1.0)>0.0) { + fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +void helper_fsqrt(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp<0.0) { + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + env->fpus |= 0x400; + } + ST0 = sqrt(fptemp); +} + +void helper_fsincos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + fpush(); + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**63 only */ + } +} + +void helper_frndint(void) +{ + ST0 = rint(ST0); +} + +void helper_fscale(void) +{ + CPU86_LDouble fpsrcop, fptemp; + + fpsrcop = 2.0; + fptemp = pow(fpsrcop,ST1); + ST0 *= fptemp; +} + +void helper_fsin(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**53 only */ + } +} + +void helper_fcos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg5 < 2**63 only */ + } +} + +void helper_fxam_ST0(void) +{ + CPU86_LDoubleU temp; + int expdif; + + temp.d = ST0; + + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + if (SIGND(temp)) + env->fpus |= 0x200; /* C1 <-- 1 */ + + expdif = EXPD(temp); + if (expdif == MAXEXPD) { + if (MANTD(temp) == 0) + env->fpus |= 0x500 /*Infinity*/; + else + env->fpus |= 0x100 /*NaN*/; + } else if (expdif == 0) { + if (MANTD(temp) == 0) + env->fpus |= 0x4000 /*Zero*/; + else + env->fpus |= 0x4400 /*Denormal*/; + } else { + env->fpus |= 0x400; + } +} + +void helper_fstenv(uint8_t *ptr, int data32) +{ + int fpus, fptag, exp, i; + uint64_t mant; + CPU86_LDoubleU tmp; + + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for (i=7; i>=0; i--) { + fptag <<= 2; + if (env->fptags[i]) { + fptag |= 3; + } else { + tmp.d = env->fpregs[i]; + exp = EXPD(tmp); + mant = MANTD(tmp); + if (exp == 0 && mant == 0) { + /* zero */ + fptag |= 1; + } else if (exp == 0 || exp == MAXEXPD +#ifdef USE_X86LDOUBLE + || (mant & (1LL << 63)) == 0 +#endif + ) { + /* NaNs, infinity, denormal */ + fptag |= 2; + } + } + } + if (data32) { + /* 32 bit */ + stl(ptr, env->fpuc); + stl(ptr + 4, fpus); + stl(ptr + 8, fptag); + stl(ptr + 12, 0); + stl(ptr + 16, 0); + stl(ptr + 20, 0); + stl(ptr + 24, 0); + } else { + /* 16 bit */ + stw(ptr, env->fpuc); + stw(ptr + 2, fpus); + stw(ptr + 4, fptag); + stw(ptr + 6, 0); + stw(ptr + 8, 0); + stw(ptr + 10, 0); + stw(ptr + 12, 0); + } +} + +void helper_fldenv(uint8_t *ptr, int data32) +{ + int i, fpus, fptag; + + if (data32) { + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 4); + fptag = lduw(ptr + 8); + } + else { + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 2); + fptag = lduw(ptr + 4); + } + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + for(i = 0;i < 7; i++) { + env->fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } +} + +void helper_fsave(uint8_t *ptr, int data32) +{ + CPU86_LDouble tmp; + int i; + + helper_fstenv(ptr, data32); + + ptr += (14 << data32); + for(i = 0;i < 8; i++) { + tmp = ST(i); +#ifdef USE_X86LDOUBLE + *(long double *)ptr = tmp; +#else + helper_fstt(tmp, ptr); +#endif + ptr += 10; + } + + /* fninit */ + env->fpus = 0; + env->fpstt = 0; + env->fpuc = 0x37f; + env->fptags[0] = 1; + env->fptags[1] = 1; + env->fptags[2] = 1; + env->fptags[3] = 1; + env->fptags[4] = 1; + env->fptags[5] = 1; + env->fptags[6] = 1; + env->fptags[7] = 1; +} + +void helper_frstor(uint8_t *ptr, int data32) +{ + CPU86_LDouble tmp; + int i; + + helper_fldenv(ptr, data32); + ptr += (14 << data32); + + for(i = 0;i < 8; i++) { +#ifdef USE_X86LDOUBLE + tmp = *(long double *)ptr; +#else + tmp = helper_fldt(ptr); +#endif + ST(i) = tmp; + ptr += 10; + } +} + diff --git a/op-i386.c b/op-i386.c index df841cec6..4c7b3804d 100644 --- a/op-i386.c +++ b/op-i386.c @@ -626,95 +626,6 @@ void OPPROTO op_jmp_im(void) EIP = PARAM1; } -#if 0 -/* full interrupt support (only useful for real CPU emulation, not - finished) - I won't do it any time soon, finish it if you want ! */ -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - SegmentDescriptorTable *dt; - uint8_t *ptr; - int type, dpl, cpl; - uint32_t e1, e2; - - dt = &env->idt; - if (intno * 8 + 7 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - ptr = dt->base + intno * 8; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - /* check gate type */ - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; - switch(type) { - case 5: /* task gate */ - case 6: /* 286 interrupt gate */ - case 7: /* 286 trap gate */ - case 14: /* 386 interrupt gate */ - case 15: /* 386 trap gate */ - break; - default: - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - break; - } - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->segs[R_CS] & 3; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - /* check valid bit */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); -} - -#else - -/* - * is_int is TRUE if coming from the int instruction. next_eip is the - * EIP value AFTER the interrupt instruction. It is only relevant if - * is_int is TRUE. - */ -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - SegmentDescriptorTable *dt; - uint8_t *ptr; - int dpl, cpl; - uint32_t e2; - - dt = &env->idt; - ptr = dt->base + (intno * 8); - e2 = ldl(ptr + 4); - - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = 3; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - - /* Since we emulate only user space, we cannot do more than - exiting the emulation with the suitable exception and error - code */ - if (is_int) - EIP = next_eip; - env->exception_index = intno; - env->error_code = error_code; - - cpu_loop_exit(); -} - -#endif - -/* shortcuts to generate exceptions */ -void raise_exception_err(int exception_index, int error_code) -{ - raise_interrupt(exception_index, 0, error_code, 0); -} - -void raise_exception(int exception_index) -{ - raise_interrupt(exception_index, 0, 0, 0); -} - void OPPROTO op_raise_interrupt(void) { int intno; @@ -833,7 +744,7 @@ label ## n:\ #define JUMP_TB(tbparam, n, eip)\ do {\ static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ - goto *((TranslationBlock *)tbparam)->tb_next[n];\ + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ label ## n:\ T0 = (long)(tbparam) + (n);\ EIP = eip;\ @@ -1044,46 +955,6 @@ void OPPROTO op_rdtsc(void) EDX = val >> 32; } -/* We simulate a pre-MMX pentium as in valgrind */ -#define CPUID_FP87 (1 << 0) -#define CPUID_VME (1 << 1) -#define CPUID_DE (1 << 2) -#define CPUID_PSE (1 << 3) -#define CPUID_TSC (1 << 4) -#define CPUID_MSR (1 << 5) -#define CPUID_PAE (1 << 6) -#define CPUID_MCE (1 << 7) -#define CPUID_CX8 (1 << 8) -#define CPUID_APIC (1 << 9) -#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ -#define CPUID_MTRR (1 << 12) -#define CPUID_PGE (1 << 13) -#define CPUID_MCA (1 << 14) -#define CPUID_CMOV (1 << 15) -/* ... */ -#define CPUID_MMX (1 << 23) -#define CPUID_FXSR (1 << 24) -#define CPUID_SSE (1 << 25) -#define CPUID_SSE2 (1 << 26) - -void helper_cpuid(void) -{ - if (EAX == 0) { - EAX = 1; /* max EAX index supported */ - EBX = 0x756e6547; - ECX = 0x6c65746e; - EDX = 0x49656e69; - } else if (EAX == 1) { - /* EAX = 1 info */ - EAX = 0x52b; - EBX = 0; - ECX = 0; - EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | - CPUID_TSC | CPUID_MSR | CPUID_MCE | - CPUID_CX8; - } -} - void OPPROTO op_cpuid(void) { helper_cpuid(); @@ -1221,79 +1092,6 @@ void OPPROTO op_das(void) /* segment handling */ -/* only works if protected mode and not VM86 */ -void load_seg(int seg_reg, int selector, unsigned cur_eip) -{ - SegmentCache *sc; - SegmentDescriptorTable *dt; - int index; - uint32_t e1, e2; - uint8_t *ptr; - - sc = &env->seg_cache[seg_reg]; - if ((selector & 0xfffc) == 0) { - /* null selector case */ - if (seg_reg == R_SS) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } else { - /* XXX: each access should trigger an exception */ - sc->base = NULL; - sc->limit = 0; - sc->seg_32bit = 1; - } - } else { - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - if (!(e2 & DESC_S_MASK) || - (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - - if (seg_reg == R_SS) { - if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - } else { - if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - } - - if (!(e2 & DESC_P_MASK)) { - EIP = cur_eip; - if (seg_reg == R_SS) - raise_exception_err(EXCP0C_STACK, selector & 0xfffc); - else - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - } - - sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); - sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & (1 << 23)) - sc->limit = (sc->limit << 12) | 0xfff; - sc->seg_32bit = (e2 >> 22) & 1; -#if 0 - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", - selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); -#endif - } - env->segs[seg_reg] = selector; -} - void OPPROTO op_movl_seg_T0(void) { load_seg(PARAM1, T0 & 0xffff, PARAM2); @@ -1326,61 +1124,11 @@ void OPPROTO op_addl_A0_seg(void) A0 += *(unsigned long *)((char *)env + PARAM1); } -void helper_lsl(void) -{ - unsigned int selector, limit; - SegmentDescriptorTable *dt; - int index; - uint32_t e1, e2; - uint8_t *ptr; - - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; - selector = T0 & 0xffff; - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - return; - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & (1 << 23)) - limit = (limit << 12) | 0xfff; - T1 = limit; - CC_SRC |= CC_Z; -} - void OPPROTO op_lsl(void) { helper_lsl(); } -void helper_lar(void) -{ - unsigned int selector; - SegmentDescriptorTable *dt; - int index; - uint32_t e2; - uint8_t *ptr; - - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; - selector = T0 & 0xffff; - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - return; - ptr = dt->base + index; - e2 = ldl(ptr + 4); - T1 = e2 & 0x00f0ff00; - CC_SRC |= CC_Z; -} - void OPPROTO op_lar(void) { helper_lar(); @@ -1678,37 +1426,6 @@ CCTable cc_table[CC_OP_NB] = { functions comes from the LGPL'ed x86 emulator found in the Willows TWIN windows emulator. */ -#ifdef USE_X86LDOUBLE -/* use long double functions */ -#define lrint lrintl -#define llrint llrintl -#define fabs fabsl -#define sin sinl -#define cos cosl -#define sqrt sqrtl -#define pow powl -#define log logl -#define tan tanl -#define atan2 atan2l -#define floor floorl -#define ceil ceill -#define rint rintl -#endif - -extern int lrint(CPU86_LDouble x); -extern int64_t llrint(CPU86_LDouble x); -extern CPU86_LDouble fabs(CPU86_LDouble x); -extern CPU86_LDouble sin(CPU86_LDouble x); -extern CPU86_LDouble cos(CPU86_LDouble x); -extern CPU86_LDouble sqrt(CPU86_LDouble x); -extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); -extern CPU86_LDouble log(CPU86_LDouble x); -extern CPU86_LDouble tan(CPU86_LDouble x); -extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); -extern CPU86_LDouble floor(CPU86_LDouble x); -extern CPU86_LDouble ceil(CPU86_LDouble x); -extern CPU86_LDouble rint(CPU86_LDouble x); - #if defined(__powerpc__) extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble); @@ -1729,60 +1446,6 @@ double qemu_rint(double x) #define rint qemu_rint #endif -#define RC_MASK 0xc00 -#define RC_NEAR 0x000 -#define RC_DOWN 0x400 -#define RC_UP 0x800 -#define RC_CHOP 0xc00 - -#define MAXTAN 9223372036854775808.0 - -#ifdef USE_X86LDOUBLE - -/* only for x86 */ -typedef union { - long double d; - struct { - unsigned long long lower; - unsigned short upper; - } l; -} CPU86_LDoubleU; - -/* the following deal with x86 long double-precision numbers */ -#define MAXEXPD 0x7fff -#define EXPBIAS 16383 -#define EXPD(fp) (fp.l.upper & 0x7fff) -#define SIGND(fp) ((fp.l.upper) & 0x8000) -#define MANTD(fp) (fp.l.lower) -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS - -#else - -typedef union { - double d; -#ifndef WORDS_BIGENDIAN - struct { - uint32_t lower; - int32_t upper; - } l; -#else - struct { - int32_t upper; - uint32_t lower; - } l; -#endif - int64_t ll; -} CPU86_LDoubleU; - -/* the following deal with IEEE double-precision numbers */ -#define MAXEXPD 0x7ff -#define EXPBIAS 1023 -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define SIGND(fp) ((fp.l.upper) & 0x80000000) -#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) -#endif - /* fp load FT0 */ void OPPROTO op_flds_FT0_A0(void) @@ -1899,24 +1562,6 @@ void OPPROTO op_fldt_ST0_A0(void) ST0 = *(long double *)A0; } #else -static inline CPU86_LDouble helper_fldt(uint8_t *ptr) -{ - CPU86_LDoubleU temp; - int upper, e; - /* mantissa */ - upper = lduw(ptr + 8); - /* XXX: handle overflow ? */ - e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ - e |= (upper >> 4) & 0x800; /* sign */ - temp.ll = ((ldq(ptr) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); - return temp.d; -} - -void helper_fldt_ST0_A0(void) -{ - ST0 = helper_fldt((uint8_t *)A0); -} - void OPPROTO op_fldt_ST0_A0(void) { helper_fldt_ST0_A0(); @@ -2013,25 +1658,6 @@ void OPPROTO op_fstt_ST0_A0(void) *(long double *)A0 = ST0; } #else - -static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) -{ - CPU86_LDoubleU temp; - int e; - temp.d = f; - /* mantissa */ - stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); - /* exponent + sign */ - e = EXPD(temp) - EXPBIAS + 16383; - e |= SIGND(temp) >> 16; - stw(ptr + 8, e); -} - -void helper_fstt_ST0_A0(void) -{ - helper_fstt(ST0, (uint8_t *)A0); -} - void OPPROTO op_fstt_ST0_A0(void) { helper_fstt_ST0_A0(); @@ -2080,98 +1706,11 @@ void OPPROTO op_fistll_ST0_A0(void) stq((void *)A0, val); } -/* BCD ops */ - -#define MUL10(iv) ( iv + iv + (iv << 3) ) - -void helper_fbld_ST0_A0(void) -{ - uint8_t *seg; - CPU86_LDouble fpsrcop; - int m32i; - unsigned int v; - - /* in this code, seg/m32i will be used as temporary ptr/int */ - seg = (uint8_t *)A0 + 8; - v = ldub(seg--); - /* XXX: raise exception */ - if (v != 0) - return; - v = ldub(seg--); - /* XXX: raise exception */ - if ((v & 0xf0) != 0) - return; - m32i = v; /* <-- d14 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */ - fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0; - - v = ldub(seg--); - m32i = (v >> 4); /* <-- d7 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */ - v = ldub(seg); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */ - fpsrcop += ((CPU86_LDouble)m32i); - if ( ldub(seg+9) & 0x80 ) - fpsrcop = -fpsrcop; - ST0 = fpsrcop; -} - void OPPROTO op_fbld_ST0_A0(void) { helper_fbld_ST0_A0(); } -void helper_fbst_ST0_A0(void) -{ - CPU86_LDouble fptemp; - CPU86_LDouble fpsrcop; - int v; - uint8_t *mem_ref, *mem_end; - - fpsrcop = rint(ST0); - mem_ref = (uint8_t *)A0; - mem_end = mem_ref + 8; - if ( fpsrcop < 0.0 ) { - stw(mem_end, 0x8000); - fpsrcop = -fpsrcop; - } else { - stw(mem_end, 0x0000); - } - while (mem_ref < mem_end) { - if (fpsrcop == 0.0) - break; - fptemp = floor(fpsrcop/10.0); - v = ((int)(fpsrcop - fptemp*10.0)); - if (fptemp == 0.0) { - stb(mem_ref++, v); - break; - } - fpsrcop = fptemp; - fptemp = floor(fpsrcop/10.0); - v |= (((int)(fpsrcop - fptemp*10.0)) << 4); - stb(mem_ref++, v); - fpsrcop = fptemp; - } - while (mem_ref < mem_end) { - stb(mem_ref++, 0); - } -} - void OPPROTO op_fbst_ST0_A0(void) { helper_fbst_ST0_A0(); @@ -2179,18 +1718,6 @@ void OPPROTO op_fbst_ST0_A0(void) /* FPU move */ -static inline void fpush(void) -{ - env->fpstt = (env->fpstt - 1) & 7; - env->fptags[env->fpstt] = 0; /* validate stack entry */ -} - -static inline void fpop(void) -{ - env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ - env->fpstt = (env->fpstt + 1) & 7; -} - void OPPROTO op_fpush(void) { fpush(); @@ -2370,33 +1897,6 @@ void OPPROTO op_fabs_ST0(void) ST0 = fabs(ST0); } -void helper_fxam_ST0(void) -{ - CPU86_LDoubleU temp; - int expdif; - - temp.d = ST0; - - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - if (SIGND(temp)) - env->fpus |= 0x200; /* C1 <-- 1 */ - - expdif = EXPD(temp); - if (expdif == MAXEXPD) { - if (MANTD(temp) == 0) - env->fpus |= 0x500 /*Infinity*/; - else - env->fpus |= 0x100 /*NaN*/; - } else if (expdif == 0) { - if (MANTD(temp) == 0) - env->fpus |= 0x4000 /*Zero*/; - else - env->fpus |= 0x4400 /*Denormal*/; - } else { - env->fpus |= 0x400; - } -} - void OPPROTO op_fxam_ST0(void) { helper_fxam_ST0(); @@ -2442,217 +1942,6 @@ void OPPROTO op_fldz_FT0(void) ST0 = *(CPU86_LDouble *)&f15rk[0]; } -void helper_f2xm1(void) -{ - ST0 = pow(2.0,ST0) - 1.0; -} - -void helper_fyl2x(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp>0.0){ - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fptan(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = tan(fptemp); - fpush(); - ST0 = 1.0; - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**52 only */ - } -} - -void helper_fpatan(void) -{ - CPU86_LDouble fptemp, fpsrcop; - - fpsrcop = ST1; - fptemp = ST0; - ST1 = atan2(fpsrcop,fptemp); - fpop(); -} - -void helper_fxtract(void) -{ - CPU86_LDoubleU temp; - unsigned int expdif; - - temp.d = ST0; - expdif = EXPD(temp) - EXPBIAS; - /*DP exponent bias*/ - ST0 = expdif; - fpush(); - BIASEXPONENT(temp); - ST0 = temp.d; -} - -void helper_fprem1(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - if (expdif < 53) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by rounding to the nearest */ - fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? - floor(fpsrcop): ceil(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fprem(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - if ( expdif < 53 ) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0)? - -(floor(fabs(fpsrcop))): floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fyl2xp1(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp+1.0)>0.0) { - fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fsqrt(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp<0.0) { - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - env->fpus |= 0x400; - } - ST0 = sqrt(fptemp); -} - -void helper_fsincos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - fpush(); - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**63 only */ - } -} - -void helper_frndint(void) -{ - ST0 = rint(ST0); -} - -void helper_fscale(void) -{ - CPU86_LDouble fpsrcop, fptemp; - - fpsrcop = 2.0; - fptemp = pow(fpsrcop,ST1); - ST0 *= fptemp; -} - -void helper_fsin(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**53 only */ - } -} - -void helper_fcos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg5 < 2**63 only */ - } -} - /* associated heplers to reduce generated code length and to simplify relocation (FP constants are usually stored in .rodata section) */ @@ -2789,129 +2078,6 @@ void OPPROTO op_fninit(void) env->fptags[7] = 1; } -void helper_fstenv(uint8_t *ptr, int data32) -{ - int fpus, fptag, exp, i; - uint64_t mant; - CPU86_LDoubleU tmp; - - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - fptag = 0; - for (i=7; i>=0; i--) { - fptag <<= 2; - if (env->fptags[i]) { - fptag |= 3; - } else { - tmp.d = env->fpregs[i]; - exp = EXPD(tmp); - mant = MANTD(tmp); - if (exp == 0 && mant == 0) { - /* zero */ - fptag |= 1; - } else if (exp == 0 || exp == MAXEXPD -#ifdef USE_X86LDOUBLE - || (mant & (1LL << 63)) == 0 -#endif - ) { - /* NaNs, infinity, denormal */ - fptag |= 2; - } - } - } - if (data32) { - /* 32 bit */ - stl(ptr, env->fpuc); - stl(ptr + 4, fpus); - stl(ptr + 8, fptag); - stl(ptr + 12, 0); - stl(ptr + 16, 0); - stl(ptr + 20, 0); - stl(ptr + 24, 0); - } else { - /* 16 bit */ - stw(ptr, env->fpuc); - stw(ptr + 2, fpus); - stw(ptr + 4, fptag); - stw(ptr + 6, 0); - stw(ptr + 8, 0); - stw(ptr + 10, 0); - stw(ptr + 12, 0); - } -} - -void helper_fldenv(uint8_t *ptr, int data32) -{ - int i, fpus, fptag; - - if (data32) { - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 4); - fptag = lduw(ptr + 8); - } - else { - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 2); - fptag = lduw(ptr + 4); - } - env->fpstt = (fpus >> 11) & 7; - env->fpus = fpus & ~0x3800; - for(i = 0;i < 7; i++) { - env->fptags[i] = ((fptag & 3) == 3); - fptag >>= 2; - } -} - -void helper_fsave(uint8_t *ptr, int data32) -{ - CPU86_LDouble tmp; - int i; - - helper_fstenv(ptr, data32); - - ptr += (14 << data32); - for(i = 0;i < 8; i++) { - tmp = ST(i); -#ifdef USE_X86LDOUBLE - *(long double *)ptr = tmp; -#else - helper_fstt(tmp, ptr); -#endif - ptr += 10; - } - - /* fninit */ - env->fpus = 0; - env->fpstt = 0; - env->fpuc = 0x37f; - env->fptags[0] = 1; - env->fptags[1] = 1; - env->fptags[2] = 1; - env->fptags[3] = 1; - env->fptags[4] = 1; - env->fptags[5] = 1; - env->fptags[6] = 1; - env->fptags[7] = 1; -} - -void helper_frstor(uint8_t *ptr, int data32) -{ - CPU86_LDouble tmp; - int i; - - helper_fldenv(ptr, data32); - ptr += (14 << data32); - - for(i = 0;i < 8; i++) { -#ifdef USE_X86LDOUBLE - tmp = *(long double *)ptr; -#else - tmp = helper_fldt(ptr); -#endif - ST(i) = tmp; - ptr += 10; - } -} - void OPPROTO op_fnstenv_A0(void) { helper_fstenv((uint8_t *)A0, PARAM1); @@ -2942,3 +2108,4 @@ void OPPROTO op_unlock(void) { cpu_unlock(); } + -- cgit v1.2.3 From 95f7652d65ccd2d67efa3180259a39cbbdb8c6a1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 00:54:44 +0000 Subject: use 32 bit pointer for tb_next even on 64 bit archs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@205 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exec.h b/exec.h index 0098ad83a..d8fc640b6 100644 --- a/exec.h +++ b/exec.h @@ -65,7 +65,7 @@ typedef struct TranslationBlock { #ifdef USE_DIRECT_JUMP uint16_t tb_jmp_offset[2]; /* offset of jump instruction */ #else - uint8_t *tb_next[2]; /* address of jump generated code */ + uint32_t tb_next[2]; /* address of jump generated code */ #endif /* list of TBs jumping to this one. This is a circular list using the two least significant bits of the pointers to tell what is @@ -142,7 +142,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, static inline void tb_set_jmp_target(TranslationBlock *tb, int n, unsigned long addr) { - tb->tb_next[n] = (void *)addr; + tb->tb_next[n] = addr; } #endif -- cgit v1.2.3 From fe319756924992f836531957fd680065a0136296 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 00:56:05 +0000 Subject: fixed __op_label handling if RELA relocations are used git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@206 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 160 +++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 99 insertions(+), 61 deletions(-) diff --git a/dyngen.c b/dyngen.c index 225d2bab8..d5b00a159 100644 --- a/dyngen.c +++ b/dyngen.c @@ -95,6 +95,12 @@ typedef uint64_t host_ulong; #define swabls(x) swab64s(x) #endif +#ifdef ELF_USES_RELOCA +#define SHT_RELOC SHT_RELA +#else +#define SHT_RELOC SHT_REL +#endif + #include "thunk.h" /* all dynamically generated functions begin with this code */ @@ -170,16 +176,24 @@ void elf_swap_phdr(struct elf_phdr *h) 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 + swabls(&rel->r_addend); +#endif +} + /* ELF file info */ int do_swap; struct elf_shdr *shdr; +uint8_t **sdata; struct elfhdr ehdr; ElfW(Sym) *symtab; int nb_syms; char *strtab; -/* data section */ -uint8_t *data_data, *sdata_data; -int data_shndx, sdata_shndx; +int text_shndx; uint16_t get16(uint16_t *p) { @@ -243,6 +257,19 @@ struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char * 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; +} + void *load_data(int fd, long offset, unsigned int size) { char *data; @@ -278,7 +305,7 @@ int strstart(const char *str, const char *val, const char **ptr) /* generate op code */ void gen_code(const char *name, host_ulong offset, host_ulong size, - FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type, + FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int gen_switch) { int copy_size = 0; @@ -500,16 +527,39 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, sym_name = strtab + sym->st_name; if (strstart(sym_name, "__op_label", &p)) { uint8_t *ptr; - + int addend; + unsigned long offset; + /* test if the variable refers to a label inside the code we are generating */ - if (sym->st_shndx == data_shndx) - ptr = data_data; - else if (sym->st_shndx == sdata_shndx) - ptr = sdata_data; - else - error("__op_labelN symbols must be in .data or .sdata section"); - val = *(target_ulong *)(ptr + sym->st_value); + ptr = sdata[sym->st_shndx]; + if (!ptr) + error("__op_labelN in invalid section"); + offset = sym->st_value; + addend = 0; +#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) { + addend = rel->r_addend; + break; + } + rel++; + } + } + } +#endif + val = *(target_ulong *)(ptr + offset); + val += addend; + if (val >= start_offset && val < start_offset + copy_size) { n = strtol(p, NULL, 10); fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); @@ -886,8 +936,9 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) ElfW(Sym) *sym; char *shstr; uint8_t *text; - void *relocs; - int nb_relocs, reloc_sh_type; + ELF_RELOC *relocs; + int nb_relocs; + ELF_RELOC *rel; fd = open(filename, O_RDONLY); if (fd < 0) @@ -926,58 +977,45 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) } } + /* 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 = load_data(fd, sec->sh_offset, sec->sh_size); + shstr = 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 = load_data(fd, text_sec->sh_offset, text_sec->sh_size); + text_shndx = text_sec - shdr; + text = sdata[text_shndx]; - data_shndx = -1; - sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".data"); - if (sec) { - data_shndx = sec - shdr; - data_data = load_data(fd, sec->sh_offset, sec->sh_size); - } - sdata_shndx = -1; - sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".sdata"); - if (sec) { - sdata_shndx = sec - shdr; - sdata_data = load_data(fd, sec->sh_offset, sec->sh_size); - } - /* find text relocations, if any */ - nb_relocs = 0; relocs = NULL; - reloc_sh_type = 0; - for(i = 0; i < ehdr.e_shnum; i++) { - sec = &shdr[i]; - if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) && - sec->sh_info == (text_sec - shdr)) { - reloc_sh_type = sec->sh_type; - relocs = load_data(fd, sec->sh_offset, sec->sh_size); - nb_relocs = sec->sh_size / sec->sh_entsize; - if (do_swap) { - if (sec->sh_type == SHT_REL) { - ElfW(Rel) *rel = relocs; - for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { - swabls(&rel->r_offset); - swabls(&rel->r_info); - } - } else { - ElfW(Rela) *rel = relocs; - for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { - swabls(&rel->r_offset); - swabls(&rel->r_info); - swabls(&rel->r_addend); - } - } - } - break; - } + 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"); @@ -985,8 +1023,8 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) error("could not find .symtab section"); strtab_sec = &shdr[symtab_sec->sh_link]; - symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size); - strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size); + symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr]; + strtab = sdata[symtab_sec->sh_link]; nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); if (do_swap) { @@ -1005,7 +1043,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) name = strtab + sym->st_name; if (strstart(name, OP_PREFIX, &p)) { gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, reloc_sh_type, 2); + text, relocs, nb_relocs, 2); } } } else { @@ -1071,7 +1109,7 @@ fprintf(outfile, if (sym->st_shndx != (text_sec - shdr)) error("invalid section for opcode (0x%x)", sym->st_shndx); gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, reloc_sh_type, 1); + text, relocs, nb_relocs, 1); } } @@ -1126,7 +1164,7 @@ fprintf(outfile, if (sym->st_shndx != (text_sec - shdr)) error("invalid section for opcode (0x%x)", sym->st_shndx); gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, reloc_sh_type, 0); + text, relocs, nb_relocs, 0); } } } -- cgit v1.2.3 From 917f95fd4d3e88b2813a3ff00050d63cf7d59307 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 00:56:37 +0000 Subject: alpha fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@207 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mmap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index afbc16988..1c3eb35f2 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -188,6 +188,11 @@ long target_mmap(unsigned long start, unsigned long len, int prot, host_start = start & host_page_mask; if (!(flags & MAP_FIXED)) { +#ifdef __alpha__ + /* tell the kenel to search at the same place as i386 */ + if (host_start == 0) + host_start = 0x40000000; +#endif if (host_page_size != real_host_page_size) { /* NOTE: this code is only for debugging with '-p' option */ /* reserve a memory area */ @@ -286,6 +291,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, page_set_flags(start, start + len, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP + printf("ret=0x%lx\n", (long)start); page_dump(stdout); printf("\n"); #endif -- cgit v1.2.3 From 5286db75a80d4a4bcee3d0b0790daf85ce460d13 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 00:57:30 +0000 Subject: convert mmap flags (alpha fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@208 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 20 ++++++++++++++++++-- syscall-i386.h | 12 ++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 329fb0f3a..4a4a4f7cb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -958,6 +958,18 @@ StructEntry struct_termios_def = { .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, }; +static bitmask_transtbl mmap_flags_tbl[] = { + { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED }, + { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE }, + { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED }, + { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS }, + { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN }, + { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE }, + { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE }, + { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED }, + { 0, 0, 0, 0 } +}; + #ifdef TARGET_I386 /* NOTE: there is really one LDT for all the threads */ @@ -1744,7 +1756,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, v4 = tswap32(vptr[3]); v5 = tswap32(vptr[4]); v6 = tswap32(vptr[5]); - ret = get_errno(target_mmap(v1, v2, v3, v4, v5, v6)); + ret = get_errno(target_mmap(v1, v2, v3, + target_to_host_bitmask(v4, mmap_flags_tbl), + v5, v6)); } break; #endif @@ -1753,7 +1767,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #else case TARGET_NR_mmap: #endif - ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5, + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, arg6 << TARGET_PAGE_BITS)); break; case TARGET_NR_munmap: diff --git a/syscall-i386.h b/syscall-i386.h index 178b638c7..ea482bbbb 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -780,6 +780,18 @@ struct target_modify_ldt_ldt_s { }; +#define TARGET_MAP_SHARED 0x01 /* Share changes */ +#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */ +#define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */ +#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ +#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ + +#define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ +#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ + /* vm86 defines */ #define TARGET_BIOSSEG 0x0f000 -- cgit v1.2.3 From 82d19dafe451c96cc5944b283228fb539bdf4b8b Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 00:58:28 +0000 Subject: added helper-i386.c - alpha fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@209 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e52d484b7..1da34c636 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ ifeq ($(ARCH),alpha) # for the constant constructions OP_CFLAGS=-Wall -O2 -g # Ensure there's only a single GP -CFLAGS += -msmall-data -msmall-text +CFLAGS += -msmall-data LDFLAGS+=-Wl,-T,alpha.ld endif @@ -78,7 +78,7 @@ OBJS= elfload.o main.o syscall.o mmap.o signal.o vm86.o path.o SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a -LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o +LIBOBJS+=thunk.o translate-i386.o op-i386.o helper-i386.o exec-i386.o exec.o # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o i386-dis.o dis-buf.o @@ -155,10 +155,10 @@ README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ Makefile elf.h thunk.c\ elfload.c main.c signal.c thunk.h exec.h\ -cpu-i386.h qemu.h op-i386.c syscall-i386.h translate-i386.c\ +cpu-i386.h qemu.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c\ syscall.c opreg_template.h syscall_defs.h vm86.c\ dis-asm.h dis-buf.c disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c\ -ppc.ld s390.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \ +ppc.ld alpha.ld s390.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h tests/test-i386-code16.S\ -- cgit v1.2.3 From c1db2eb8c3941ed498c7cd4b4baeff972c604a42 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 01:05:11 +0000 Subject: tested tools git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@210 c046a42c-6fe2-441c-8c8c-71466251a162 --- README | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README b/README index 7efa98f56..a70af3cfb 100644 --- a/README +++ b/README @@ -36,6 +36,26 @@ You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is automatically launched by the Linux kernel when you try to launch x86 executables. +Tested tool versions +-------------------- + +In order to compile QEMU succesfully, it is very important that you +have the right tools. The most important one is gcc. I cannot guaranty +that QEMU works if you do not use a tested gcc version. Look at +'configure' and 'Makefile' if you want to make a different gcc +version. + +host gcc binutils glibc linux +------------------------------------------------------- +x86 2.95.2 2.13.2 2.1.3 2.4.18 + +PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 + +Alpha 3.3 [1] 2.14.90.0.4 2.2.5 xxx + + +[1] QEMU cannot work for gcc version < 3.3 on Alpha. + Documentation ------------- -- cgit v1.2.3 From 4f101ad7ff41d1b5f21c4042040c9be7b7817ca0 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 01:52:19 +0000 Subject: 64 bit fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@211 c046a42c-6fe2-441c-8c8c-71466251a162 --- thunk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thunk.h b/thunk.h index 97b441a0b..9a06847b6 100644 --- a/thunk.h +++ b/thunk.h @@ -77,7 +77,7 @@ #endif #define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8) -#define HOST_LONG_SIZE (TARGET_LONG_BITS / 8) +#define HOST_LONG_SIZE (HOST_LONG_BITS / 8) static inline uint16_t bswap16(uint16_t x) { -- cgit v1.2.3 From 4add45b4f6695c2a2d61b5da0f750519fa400630 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 5 Jun 2003 01:52:59 +0000 Subject: getdents for 64 bit cpus git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@212 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 4a4a4f7cb..9b02d5eaf 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2015,7 +2015,47 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getdents: #if TARGET_LONG_SIZE != 4 #error not supported -#endif +#elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8 + { + struct target_dirent *target_dirp = (void *)arg2; + struct dirent *dirp; + long count = arg3; + + dirp = malloc(count); + if (!dirp) + return -ENOMEM; + + ret = get_errno(sys_getdents(arg1, dirp, count)); + if (!is_error(ret)) { + struct dirent *de; + struct target_dirent *tde; + int len = ret; + int reclen, treclen; + int count1, tnamelen; + + count1 = 0; + de = dirp; + tde = target_dirp; + while (len > 0) { + reclen = de->d_reclen; + treclen = reclen - (2 * (sizeof(long) - sizeof(target_long))); + tde->d_reclen = tswap16(treclen); + tde->d_ino = tswapl(de->d_ino); + tde->d_off = tswapl(de->d_off); + tnamelen = treclen - (2 * sizeof(target_long) + 2); + if (tnamelen > 256) + tnamelen = 256; + strncpy(tde->d_name, de->d_name, tnamelen); + de = (struct dirent *)((char *)de + reclen); + len -= reclen; + tde = (struct dirent *)((char *)tde + treclen); + count1 += treclen; + } + ret = count1; + } + free(dirp); + } +#else { struct dirent *dirp = (void *)arg2; long count = arg3; @@ -2038,6 +2078,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } } +#endif break; case TARGET_NR_getdents64: { -- cgit v1.2.3 From 84fa15d854673859736f16e92ee8c3f622f16a8b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:20:55 +0000 Subject: big endian/unaligned fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@213 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/vm86.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 885762c06..8b512df62 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -41,22 +41,22 @@ static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val) { - *(uint16_t *)(segptr + (reg16 & 0xffff)) = tswap16(val); + stw(segptr + (reg16 & 0xffff), val); } static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val) { - *(uint32_t *)(segptr + (reg16 & 0xffff)) = tswap32(val); + stl(segptr + (reg16 & 0xffff), val); } static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16) { - return tswap16(*(uint16_t *)(segptr + (reg16 & 0xffff))); + return lduw(segptr + (reg16 & 0xffff)); } static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16) { - return tswap32(*(uint32_t *)(segptr + (reg16 & 0xffff))); + return ldl(segptr + (reg16 & 0xffff)); } void save_v86_state(CPUX86State *env) -- cgit v1.2.3 From aa0aa4fa31054a9488fd49c29c6ab12e2e85be58 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:23:31 +0000 Subject: added ARM and Sparc disassemblers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@214 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm-dis.c | 1675 +++++++++++++++++++++++++++++++ dis-asm.h | 31 +- dis-buf.c | 79 -- disas.c | 94 ++ i386-dis.c | 4 +- sparc-dis.c | 3214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 5008 insertions(+), 89 deletions(-) create mode 100644 arm-dis.c delete mode 100644 dis-buf.c create mode 100644 sparc-dis.c diff --git a/arm-dis.c b/arm-dis.c new file mode 100644 index 000000000..adacd898b --- /dev/null +++ b/arm-dis.c @@ -0,0 +1,1675 @@ +/* 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@pegasus.esprit.ec.org) + Modification by James G. Smith (jsmith@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 : + + %% % + %d print the bitfield in decimal + %x print the bitfield in hex + %X print the bitfield as 1 hex digit without leading "0x" + %r print as an ARM register + %f print a floating point constant if >7 else a + floating point register + %y print a single precision VFP reg. + Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair + %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 + %'c print specified char iff bit is one + %`c print specified char iff bit is zero + %?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) + %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 + %B print Thumb branch destination (signed displacement) + %W print (bitfield * 4) as a decimal + %H print (bitfield * 2) as a decimal + %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, "}, + {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, %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 + 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,=" */ + /* 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 GCC register name set. */ +static unsigned int regname_selected = 1; + +#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, _("")); + 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 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"); +} diff --git a/dis-asm.h b/dis-asm.h index 533307d97..3e6982f23 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -73,16 +73,20 @@ enum bfd_architecture bfd_arch_a29k, /* AMD 29000 */ bfd_arch_sparc, /* SPARC */ #define bfd_mach_sparc 1 - /* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ +/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ #define bfd_mach_sparc_sparclet 2 #define bfd_mach_sparc_sparclite 3 #define bfd_mach_sparc_v8plus 4 -#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */ -#define bfd_mach_sparc_v9 6 -#define bfd_mach_sparc_v9a 7 /* with ultrasparc add'ns */ - /* Nonzero if MACH has the v9 instruction set. */ +#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ +#define bfd_mach_sparc_sparclite_le 6 +#define bfd_mach_sparc_v9 7 +#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ +#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ +#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ +/* Nonzero if MACH has the v9 instruction set. */ #define bfd_mach_sparc_v9_p(mach) \ - ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a) + ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ + && (mach) != bfd_mach_sparc_sparclite_le) bfd_arch_mips, /* MIPS Rxxxx */ #define bfd_mach_mips3000 3000 #define bfd_mach_mips3900 3900 @@ -279,6 +283,9 @@ typedef struct disassemble_info { zero if unknown. */ bfd_vma target2; /* Second target address for dref2 */ + /* Command line options specific to the target disassembler. */ + char * disassembler_options; + } disassemble_info; @@ -299,8 +306,7 @@ extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); extern disassembler_ftype arc_get_disassembler PARAMS ((int, int)); -extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*)); -extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_arm PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); @@ -381,6 +387,15 @@ extern int generic_symbol_at_address (INFO).bytes_per_line = 0, \ (INFO).bytes_per_chunk = 0, \ (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).disassembler_options = NULL, \ (INFO).insn_info_valid = 0 +#define _(x) x + +/* from libbfd */ + +bfd_vma bfd_getl32 (const bfd_byte *addr); +bfd_vma bfd_getb32 (const bfd_byte *addr); +typedef enum bfd_boolean {false, true} boolean; + #endif /* ! defined (DIS_ASM_H) */ diff --git a/dis-buf.c b/dis-buf.c deleted file mode 100644 index cdb8e9b19..000000000 --- a/dis-buf.c +++ /dev/null @@ -1,79 +0,0 @@ -/* Disassemble from a buffer, for GNU. - Copyright (C) 1993, 1994 Free Software Foundation, Inc. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "dis-asm.h" -#include - -/* Get LENGTH bytes from info's buffer, at target address memaddr. - Transfer them to myaddr. */ -int -buffer_read_memory (memaddr, myaddr, length, info) - bfd_vma memaddr; - bfd_byte *myaddr; - int length; - struct disassemble_info *info; -{ - if (memaddr < info->buffer_vma - || memaddr + length > info->buffer_vma + info->buffer_length) - /* Out of bounds. Use EIO because GDB uses it. */ - return EIO; - memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); - return 0; -} - -/* Print an error message. We can assume that this is in response to - an error return from buffer_read_memory. */ -void -perror_memory (status, memaddr, info) - int status; - bfd_vma memaddr; - struct disassemble_info *info; -{ - if (status != EIO) - /* Can't happen. */ - (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); - else - /* Actually, address between memaddr and memaddr + len was - out of bounds. */ - (*info->fprintf_func) (info->stream, - "Address 0x%x is out of bounds.\n", memaddr); -} - -/* This could be in a separate file, to save miniscule amounts of space - in statically linked executables. */ - -/* Just print the address is hex. This is included for completeness even - though both GDB and objdump provide their own (to print symbolic - addresses). */ - -void -generic_print_address (addr, info) - bfd_vma addr; - struct disassemble_info *info; -{ - (*info->fprintf_func) (info->stream, "0x%x", addr); -} - -/* Just return the given address. */ - -int -generic_symbol_at_address (addr, info) - bfd_vma addr; - struct disassemble_info * info; -{ - return 1; -} diff --git a/disas.c b/disas.c index 4b44e0678..97c4a23a3 100644 --- a/disas.c +++ b/disas.c @@ -2,12 +2,95 @@ #include "dis-asm.h" #include "disas.h" #include "elf.h" +#include /* Filled in by elfload.c. Simplistic, but will do for now. */ unsigned int disas_num_syms; void *disas_symtab; const char *disas_strtab; +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +int +buffer_read_memory (memaddr, myaddr, length, info) + bfd_vma memaddr; + bfd_byte *myaddr; + int length; + struct disassemble_info *info; +{ + if (memaddr < info->buffer_vma + || memaddr + length > info->buffer_vma + info->buffer_length) + /* Out of bounds. Use EIO because GDB uses it. */ + return EIO; + memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); + return 0; +} + +/* Print an error message. We can assume that this is in response to + an error return from buffer_read_memory. */ +void +perror_memory (status, memaddr, info) + int status; + bfd_vma memaddr; + struct disassemble_info *info; +{ + if (status != EIO) + /* Can't happen. */ + (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); + else + /* Actually, address between memaddr and memaddr + len was + out of bounds. */ + (*info->fprintf_func) (info->stream, + "Address 0x%x is out of bounds.\n", memaddr); +} + +/* This could be in a separate file, to save miniscule amounts of space + in statically linked executables. */ + +/* Just print the address is hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ + +void +generic_print_address (addr, info) + bfd_vma addr; + struct disassemble_info *info; +{ + (*info->fprintf_func) (info->stream, "0x%x", addr); +} + +/* Just return the given address. */ + +int +generic_symbol_at_address (addr, info) + bfd_vma addr; + struct disassemble_info * info; +{ + return 1; +} + +bfd_vma bfd_getl32 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + return (bfd_vma) v; +} + +bfd_vma bfd_getb32 (const bfd_byte *addr) +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + v |= (unsigned long) addr[2] << 8; + v |= (unsigned long) addr[3]; + return (bfd_vma) v; +} + /* Disassemble this for me please... (debugging). */ void disas(FILE *out, void *code, unsigned long size, enum disas_type type) { @@ -35,6 +118,10 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type) print_insn = print_insn_ppc; #elif defined(__alpha__) print_insn = print_insn_alpha; +#elif defined(__sparc__) + print_insn = print_insn_sparc; +#elif defined(__arm__) + print_insn = print_insn_arm; #else fprintf(out, "Asm output not supported on this arch\n"); return; @@ -51,6 +138,13 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type) for (pc = code; pc < (uint8_t *)code + size; pc += count) { fprintf(out, "0x%08lx: ", (long)pc); +#ifdef __arm__ + /* since data are included in the code, it is better to + display code data too */ + if (type == DISAS_TARGET) { + fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); + } +#endif count = print_insn((unsigned long)pc, &disasm_info); fprintf(out, "\n"); if (count < 0) diff --git a/i386-dis.c b/i386-dis.c index a11bdf11d..f9e907298 100644 --- a/i386-dis.c +++ b/i386-dis.c @@ -1164,8 +1164,8 @@ int print_insn_x86 (pc, info, aflag, dflag) bfd_vma pc; disassemble_info *info; - int aflag; - int dflag; + int volatile aflag; + int volatile dflag; { struct dis386 *dp; int i; diff --git a/sparc-dis.c b/sparc-dis.c new file mode 100644 index 000000000..956597c79 --- /dev/null +++ b/sparc-dis.c @@ -0,0 +1,3214 @@ +/* Print SPARC instructions. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2002 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include "dis-asm.h" + +/* The SPARC opcode table (and other related data) is defined in + the opcodes library in sparc-opc.c. If you change anything here, make + sure you fix up that file, and vice versa. */ + + /* FIXME-someday: perhaps the ,a's and such should be embedded in the + instruction's name rather than the args. This would make gas faster, pinsn + slower, but would mess up some macros a bit. xoxorich. */ + +/* List of instruction sets variations. + These values are such that each element is either a superset of a + preceding each one or they conflict in which case SPARC_OPCODE_CONFLICT_P + returns non-zero. + The values are indices into `sparc_opcode_archs' defined in sparc-opc.c. + Don't change this without updating sparc-opc.c. */ + +enum sparc_opcode_arch_val { + SPARC_OPCODE_ARCH_V6 = 0, + SPARC_OPCODE_ARCH_V7, + SPARC_OPCODE_ARCH_V8, + SPARC_OPCODE_ARCH_SPARCLET, + SPARC_OPCODE_ARCH_SPARCLITE, + /* v9 variants must appear last */ + SPARC_OPCODE_ARCH_V9, + SPARC_OPCODE_ARCH_V9A, /* v9 with ultrasparc additions */ + SPARC_OPCODE_ARCH_V9B, /* v9 with ultrasparc and cheetah additions */ + SPARC_OPCODE_ARCH_BAD /* error return from sparc_opcode_lookup_arch */ +}; + +/* The highest architecture in the table. */ +#define SPARC_OPCODE_ARCH_MAX (SPARC_OPCODE_ARCH_BAD - 1) + +/* Given an enum sparc_opcode_arch_val, return the bitmask to use in + insn encoding/decoding. */ +#define SPARC_OPCODE_ARCH_MASK(arch) (1 << (arch)) + +/* Given a valid sparc_opcode_arch_val, return non-zero if it's v9. */ +#define SPARC_OPCODE_ARCH_V9_P(arch) ((arch) >= SPARC_OPCODE_ARCH_V9) + +/* Table of cpu variants. */ + +struct sparc_opcode_arch { + const char *name; + /* Mask of sparc_opcode_arch_val's supported. + EG: For v7 this would be + (SPARC_OPCODE_ARCH_MASK (..._V6) | SPARC_OPCODE_ARCH_MASK (..._V7)). + These are short's because sparc_opcode.architecture is. */ + short supported; +}; + +extern const struct sparc_opcode_arch sparc_opcode_archs[]; + +/* Given architecture name, look up it's sparc_opcode_arch_val value. */ +extern enum sparc_opcode_arch_val sparc_opcode_lookup_arch + PARAMS ((const char *)); + +/* Return the bitmask of supported architectures for ARCH. */ +#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported) + +/* Non-zero if ARCH1 conflicts with ARCH2. + IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa. */ +#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \ +(((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH1)) \ + && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \ + != SPARC_OPCODE_SUPPORTED (ARCH2))) + +/* Structure of an opcode table entry. */ + +struct sparc_opcode { + const char *name; + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ + const char *args; + /* This was called "delayed" in versions before the flags. */ + char flags; + short architecture; /* Bitmask of sparc_opcode_arch_val's. */ +}; + +#define F_DELAYED 1 /* Delayed branch */ +#define F_ALIAS 2 /* Alias for a "real" instruction */ +#define F_UNBR 4 /* Unconditional branch */ +#define F_CONDBR 8 /* Conditional branch */ +#define F_JSR 16 /* Subroutine call */ +#define F_FLOAT 32 /* Floating point instruction (not a branch) */ +#define F_FBR 64 /* Floating point branch */ +/* FIXME: Add F_ANACHRONISTIC flag for v9. */ + +/* + +All sparc opcodes are 32 bits, except for the `set' instruction (really a +macro), which is 64 bits. It is handled as a special case. + +The match component is a mask saying which bits must match a particular +opcode in order for an instruction to be an instance of that opcode. + +The args component is a string containing one character for each operand of the +instruction. + +Kinds of operands: + # Number used by optimizer. It is ignored. + 1 rs1 register. + 2 rs2 register. + d rd register. + e frs1 floating point register. + v frs1 floating point register (double/even). + V frs1 floating point register (quad/multiple of 4). + f frs2 floating point register. + B frs2 floating point register (double/even). + R frs2 floating point register (quad/multiple of 4). + g frsd floating point register. + H frsd floating point register (double/even). + J frsd floating point register (quad/multiple of 4). + b crs1 coprocessor register + c crs2 coprocessor register + D crsd coprocessor register + m alternate space register (asr) in rd + M alternate space register (asr) in rs1 + h 22 high bits. + X 5 bit unsigned immediate + Y 6 bit unsigned immediate + 3 SIAM mode (3 bits). (v9b) + K MEMBAR mask (7 bits). (v9) + j 10 bit Immediate. (v9) + I 11 bit Immediate. (v9) + i 13 bit Immediate. + n 22 bit immediate. + k 2+14 bit PC relative immediate. (v9) + G 19 bit PC relative immediate. (v9) + l 22 bit PC relative immediate. + L 30 bit PC relative immediate. + a Annul. The annul bit is set. + A Alternate address space. Stored as 8 bits. + C Coprocessor state register. + F floating point state register. + p Processor state register. + N Branch predict clear ",pn" (v9) + T Branch predict set ",pt" (v9) + z %icc. (v9) + Z %xcc. (v9) + q Floating point queue. + r Single register that is both rs1 and rd. + O Single register that is both rs2 and rd. + Q Coprocessor queue. + S Special case. + t Trap base register. + w Window invalid mask register. + y Y register. + u sparclet coprocessor registers in rd position + U sparclet coprocessor registers in rs1 position + E %ccr. (v9) + s %fprs. (v9) + P %pc. (v9) + W %tick. (v9) + o %asi. (v9) + 6 %fcc0. (v9) + 7 %fcc1. (v9) + 8 %fcc2. (v9) + 9 %fcc3. (v9) + ! Privileged Register in rd (v9) + ? Privileged Register in rs1 (v9) + * Prefetch function constant. (v9) + x OPF field (v9 impdep). + 0 32/64 bit immediate for set or setx (v9) insns + _ Ancillary state register in rd (v9a) + / Ancillary state register in rs1 (v9a) + +The following chars are unused: (note: ,[] are used as punctuation) +[45] + +*/ + +#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */ +#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */ +#define OP(x) ((unsigned)((x)&0x3) << 30) /* op field of all insns */ +#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */ +#define OPF_LOW5(x) OPF((x)&0x1f) /* v9 */ +#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */ +#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */ +#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */ +#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */ +#define F1(x) (OP(x)) +#define DISP30(x) ((x)&0x3fffffff) +#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */ +#define RS2(x) ((x)&0x1f) /* rs2 field */ +#define SIMM13(x) ((x)&0x1fff) /* simm13 field */ +#define RD(x) (((x)&0x1f) << 25) /* destination register field */ +#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */ +#define ASI_RS2(x) (SIMM13(x)) +#define MEMBAR(x) ((x)&0x7f) +#define SLCPOP(x) (((x)&0x7f) << 6) /* sparclet cpop */ + +#define ANNUL (1<<29) +#define BPRED (1<<19) /* v9 */ +#define IMMED F3I(1) +#define RD_G0 RD(~0) +#define RS1_G0 RS1(~0) +#define RS2_G0 RS2(~0) + +extern const struct sparc_opcode sparc_opcodes[]; +extern const int sparc_num_opcodes; + +extern int sparc_encode_asi PARAMS ((const char *)); +extern const char *sparc_decode_asi PARAMS ((int)); +extern int sparc_encode_membar PARAMS ((const char *)); +extern const char *sparc_decode_membar PARAMS ((int)); +extern int sparc_encode_prefetch PARAMS ((const char *)); +extern const char *sparc_decode_prefetch PARAMS ((int)); +extern int sparc_encode_sparclet_cpreg PARAMS ((const char *)); +extern const char *sparc_decode_sparclet_cpreg PARAMS ((int)); + +/* Some defines to make life easy. */ +#define MASK_V6 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6) +#define MASK_V7 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V7) +#define MASK_V8 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8) +#define MASK_SPARCLET SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET) +#define MASK_SPARCLITE SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) +#define MASK_V9 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9) +#define MASK_V9A SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A) +#define MASK_V9B SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B) + +/* Bit masks of architectures supporting the insn. */ + +#define v6 (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +/* v6 insns not supported on the sparclet */ +#define v6notlet (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +#define v7 (MASK_V7 | MASK_V8 | MASK_SPARCLET \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +/* Although not all insns are implemented in hardware, sparclite is defined + to be a superset of v8. Unimplemented insns trap and are then theoretically + implemented in software. + It's not clear that the same is true for sparclet, although the docs + suggest it is. Rather than complicating things, the sparclet assembler + recognizes all v8 insns. */ +#define v8 (MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE \ + | MASK_V9 | MASK_V9A | MASK_V9B) +#define sparclet (MASK_SPARCLET) +#define sparclite (MASK_SPARCLITE) +#define v9 (MASK_V9 | MASK_V9A | MASK_V9B) +#define v9a (MASK_V9A | MASK_V9B) +#define v9b (MASK_V9B) +/* v6 insns not supported by v9 */ +#define v6notv9 (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLET | MASK_SPARCLITE) +/* v9a instructions which would appear to be aliases to v9's impdep's + otherwise */ +#define v9notv9a (MASK_V9) + +/* Table of opcode architectures. + The order is defined in opcode/sparc.h. */ + +const struct sparc_opcode_arch sparc_opcode_archs[] = { + { "v6", MASK_V6 }, + { "v7", MASK_V6 | MASK_V7 }, + { "v8", MASK_V6 | MASK_V7 | MASK_V8 }, + { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET }, + { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE }, + /* ??? Don't some v8 priviledged insns conflict with v9? */ + { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 }, + /* v9 with ultrasparc additions */ + { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A }, + /* v9 with cheetah additions */ + { "v9b", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A | MASK_V9B }, + { NULL, 0 } +}; + +/* Given NAME, return it's architecture entry. */ + +enum sparc_opcode_arch_val +sparc_opcode_lookup_arch (name) + const char *name; +{ + const struct sparc_opcode_arch *p; + + for (p = &sparc_opcode_archs[0]; p->name; ++p) + { + if (strcmp (name, p->name) == 0) + return (enum sparc_opcode_arch_val) (p - &sparc_opcode_archs[0]); + } + + return SPARC_OPCODE_ARCH_BAD; +} + +/* Branch condition field. */ +#define COND(x) (((x)&0xf)<<25) + +/* v9: Move (MOVcc and FMOVcc) condition field. */ +#define MCOND(x,i_or_f) ((((i_or_f)&1)<<18)|(((x)>>11)&(0xf<<14))) /* v9 */ + +/* v9: Move register (MOVRcc and FMOVRcc) condition field. */ +#define RCOND(x) (((x)&0x7)<<10) /* v9 */ + +#define CONDA (COND(0x8)) +#define CONDCC (COND(0xd)) +#define CONDCS (COND(0x5)) +#define CONDE (COND(0x1)) +#define CONDG (COND(0xa)) +#define CONDGE (COND(0xb)) +#define CONDGU (COND(0xc)) +#define CONDL (COND(0x3)) +#define CONDLE (COND(0x2)) +#define CONDLEU (COND(0x4)) +#define CONDN (COND(0x0)) +#define CONDNE (COND(0x9)) +#define CONDNEG (COND(0x6)) +#define CONDPOS (COND(0xe)) +#define CONDVC (COND(0xf)) +#define CONDVS (COND(0x7)) + +#define CONDNZ CONDNE +#define CONDZ CONDE +#define CONDGEU CONDCC +#define CONDLU CONDCS + +#define FCONDA (COND(0x8)) +#define FCONDE (COND(0x9)) +#define FCONDG (COND(0x6)) +#define FCONDGE (COND(0xb)) +#define FCONDL (COND(0x4)) +#define FCONDLE (COND(0xd)) +#define FCONDLG (COND(0x2)) +#define FCONDN (COND(0x0)) +#define FCONDNE (COND(0x1)) +#define FCONDO (COND(0xf)) +#define FCONDU (COND(0x7)) +#define FCONDUE (COND(0xa)) +#define FCONDUG (COND(0x5)) +#define FCONDUGE (COND(0xc)) +#define FCONDUL (COND(0x3)) +#define FCONDULE (COND(0xe)) + +#define FCONDNZ FCONDNE +#define FCONDZ FCONDE + +#define ICC (0) /* v9 */ +#define XCC (1<<12) /* v9 */ +#define FCC(x) (((x)&0x3)<<11) /* v9 */ +#define FBFCC(x) (((x)&0x3)<<20) /* v9 */ + +/* The order of the opcodes in the table is significant: + + * The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler will bomb at runtime. + + * The disassembler should not care about the order of the opcodes. + +*/ + +/* Entries for commutative arithmetic operations. */ +/* ??? More entries can make use of this. */ +#define COMMUTEOP(opcode, op3, arch_mask) \ +{ opcode, F3(2, op3, 0), F3(~2, ~op3, ~0)|ASI(~0), "1,2,d", 0, arch_mask }, \ +{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "1,i,d", 0, arch_mask }, \ +{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "i,1,d", 0, arch_mask } + +const struct sparc_opcode sparc_opcodes[] = { + +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 }, +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 }, +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */ + +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RD(~0), "[1+2],F", 0, v6 }, +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[1+i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[i+1],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~0),"[i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+0],d */ + +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1],D", 0, v6notv9 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0), "[1+2],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0, "[1],C", 0, v6notv9 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[1+i],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[i+1],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0, "[i],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0), "[1],C", 0, v6notv9 }, /* ld [rs1+0],d */ + +/* The v9 LDUW is the same as the old 'ld' opcode, it is not the same as the + 'ld' pseudo-op in v9. */ +{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", F_ALIAS, v9 }, /* ld [rs1+%g0],d */ +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", F_ALIAS, v9 }, /* ld [rs1+0],d */ + +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[1+i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[i+1],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldd [rs1+0],d */ +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0), "[1+2],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0), "[1],H", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[1+i],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[i+1],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0, "[i],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0), "[1],H", 0, v6 }, /* ldd [rs1+0],d */ + +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0), "[1+2],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+0],d */ + +{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI(~0), "[1+2],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI_RS2(~0), "[1],J", 0, v9 }, /* ldd [rs1+%g0],d */ +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[1+i],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[i+1],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|RS1_G0, "[i],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|SIMM13(~0), "[1],J", 0, v9 }, /* ldd [rs1+0],d */ + +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */ +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[1+i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[i+1],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsb [rs1+0],d */ + +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */ +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[1+i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[i+1],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsh [rs1+0],d */ + +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */ +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[1+i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[i+1],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldstub [rs1+0],d */ + +{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI(~0), "[1+2],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldsw [rs1+%g0],d */ +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[1+i],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[i+1],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|RS1_G0, "[i],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldsw [rs1+0],d */ + +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */ +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[1+i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[i+1],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldub [rs1+0],d */ + +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */ +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[1+i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[i+1],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* lduh [rs1+0],d */ + +{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI(~0), "[1+2],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldx [rs1+%g0],d */ +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[1+i],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[i+1],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|RS1_G0, "[i],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldx [rs1+0],d */ + +{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RD(~1), "[1+2],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RS2_G0|RD(~1), "[1],F", 0, v9 }, /* ld [rs1+%g0],d */ +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[1+i],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[i+1],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~1), "[i],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~1),"[1],F", 0, v9 }, /* ld [rs1+0],d */ + +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", 0, v6 }, +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */ +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ +{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2]A,g", 0, v9 }, +{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1]A,g", 0, v9 }, /* lda [rs1+%g0],d */ +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1]o,g", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0), "[1+2]A,d", 0, v6 }, +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */ +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[1+i]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[i+1]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0), "[1+2]A,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|RS2_G0, "[1]A,H", 0, v9 }, /* ldda [rs1+%g0],d */ +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1]o,H", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0), "[1+2]A,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0)|RS2_G0, "[1]A,J", 0, v9 }, /* ldd [rs1+%g0],d */ +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[1+i]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[i+1]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|RS1_G0, "[i]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|SIMM13(~0), "[1]o,J", 0, v9 }, /* ldd [rs1+0],d */ + +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */ +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[1+i]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[i+1]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */ +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[1+i]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[i+1]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0), "[1+2]A,d", 0, v6 }, +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */ +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[1+i]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[i+1]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0), "[1+2]A,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[1+i]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[i+1]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0), "[1+2]A,d", 0, v6 }, +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */ +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[1+i]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[i+1]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0), "[1+2]A,d", 0, v6 }, +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */ +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[1+i]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[i+1]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", F_ALIAS, v9 }, /* lduwa === lda */ +{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", F_ALIAS, v9 }, /* lda [rs1+%g0],d */ +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", F_ALIAS, v9 }, /* ld [rs1+0],d */ + +{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0), "[1+2]A,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[1+i]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[i+1]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0), "g,[1+2]", 0, v6 }, +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* st d[rs1+%g0] */ +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[1+i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[i+1]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0, "g,[i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[1+i]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[i+1]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0), "C,[1+2]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[1+i]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[i+1]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0, "C,[i]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0), "F,[1+2]", 0, v6 }, +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0), "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[1+i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[i+1]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0, "F,[i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|SIMM13(~0), "F,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ + +{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+%g0] */ +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+0] */ + +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", 0, v6 }, +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */ +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* st d,[rs1+0] */ + +{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0), "g,[1+2]A", 0, v9 }, +{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|RS2(~0), "g,[1]A", 0, v9 }, /* sta d,[rs1+%g0] */ +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[1+i]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[i+1]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "g,[i]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "g,[1]o", 0, v9 }, /* st d,[rs1+0] */ + +{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ + +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */ +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+0] */ + +{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ +{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ + +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", 0, v6 }, +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */ +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stb d,[rs1+0] */ + +{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ +{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ + +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "q,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "q,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0), "H,[1+2]", 0, v6 }, +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0), "H,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[1+i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[i+1]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0, "H,[i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0), "H,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "Q,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "Q,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ + +{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+%g0] */ +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+0] */ + +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0), "d,[1+2]A", 0, v6 }, +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */ +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[1+i]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[i+1]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* std d,[rs1+0] */ +{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0), "H,[1+2]A", 0, v9 }, +{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|RS2(~0), "H,[1]A", 0, v9 }, /* stda d,[rs1+%g0] */ +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[1+i]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[i+1]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "H,[i]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "H,[1]o", 0, v9 }, /* std d,[rs1+0] */ + +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */ +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+0] */ + +{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ +{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ + +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", 0, v6 }, +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stha ,[rs1+%g0] */ +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* sth d,[rs1+0] */ + +{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ +{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ + +{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI(~0), "d,[1+2]", 0, v9 }, +{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI_RS2(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[1+i]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[i+1]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RS1_G0, "d,[i]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|SIMM13(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI(~0)|RD(~1), "F,[1+2]", 0, v9 }, +{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI_RS2(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[1+i]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[i+1]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RS1_G0|RD(~1), "F,[i]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|SIMM13(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0), "d,[1+2]A", 0, v9 }, +{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0)|RS2(~0), "d,[1]A", 0, v9 }, /* stxa d,[rs1+%g0] */ +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[1+i]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[i+1]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "J,[1+2]", 0, v9 }, +{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "J,[1]", 0, v9 }, /* stq [rs1+%g0] */ +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[1+i]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[i+1]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "J,[i]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "J,[1]", 0, v9 }, /* stq [rs1+0] */ + +{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "J,[1+2]A", 0, v9 }, +{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "J,[1]A", 0, v9 }, /* stqa [rs1+%g0] */ +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[1+i]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[i+1]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "J,[i]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "J,[1]o", 0, v9 }, /* stqa [rs1+0] */ + +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0), "[1+2],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0), "[1],d", 0, v7 }, /* swap [rs1+%g0],d */ +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[1+i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[i+1],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0, "[i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0), "[1],d", 0, v7 }, /* swap [rs1+0],d */ + +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0), "[1+2]A,d", 0, v7 }, +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0), "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */ +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[1+i]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[i+1]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* swap [rs1+0],d */ + +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v6 }, /* restore %g0,%g0,%g0 */ +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1), "1,i,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0), "", 0, v6 }, /* restore %g0,0,%g0 */ + +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* rett rs1+rs2 */ +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1,%g0 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* rett rs1+X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1+0 */ + +{ "save", F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "save", F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1), "1,i,d", 0, v6 }, +{ "save", 0x81e00000, ~0x81e00000, "", F_ALIAS, v6 }, + +{ "ret", F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */ +{ "retl", F3(2, 0x38, 1)|RS1(0x0f)|SIMM13(8), F3(~2, ~0x38, ~1)|RS1(~0x0f)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %o7+8,%g0 */ + +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0), "1+2,d", F_JSR|F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "1+i,d", F_JSR|F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "i+1,d", F_JSR|F_DELAYED, v6 }, + +{ "done", F3(2, 0x3e, 0)|RD(0), F3(~2, ~0x3e, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "retry", F3(2, 0x3e, 0)|RD(1), F3(~2, ~0x3e, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "saved", F3(2, 0x31, 0)|RD(0), F3(~2, ~0x31, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "restored", F3(2, 0x31, 0)|RD(1), F3(~2, ~0x31, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "sir", F3(2, 0x30, 1)|RD(0xf), F3(~2, ~0x30, ~1)|RD(~0xf)|RS1_G0, "i", 0, v9 }, + +{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v8 }, +{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", 0, v8 }, /* flush rs1+%g0 */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", 0, v8 }, /* flush rs1+0 */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", 0, v8 }, /* flush %g0+i */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", 0, v8 }, +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", 0, v8 }, + +/* IFLUSH was renamed to FLUSH in v8. */ +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", F_ALIAS, v6 }, /* flush rs1+%g0 */ +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", F_ALIAS, v6 }, /* flush rs1+0 */ +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", F_ALIAS, v6 }, + +{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI(~0), "1+2", 0, v9 }, +{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI_RS2(~0), "1", 0, v9 }, /* return rs1+%g0 */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|SIMM13(~0), "1", 0, v9 }, /* return rs1+0 */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RS1_G0, "i", 0, v9 }, /* return %g0+i */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "1+i", 0, v9 }, +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "i+1", 0, v9 }, + +{ "flushw", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v9 }, + +{ "membar", F3(2, 0x28, 1)|RS1(0xf), F3(~2, ~0x28, ~1)|RD_G0|RS1(~0xf)|SIMM13(~127), "K", 0, v9 }, +{ "stbar", F3(2, 0x28, 0)|RS1(0xf), F3(~2, ~0x28, ~0)|RD_G0|RS1(~0xf)|SIMM13(~0), "", 0, v8 }, + +{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0), "[1+2],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0)|RS2_G0, "[1],*", 0, v9 }, /* prefetch [rs1+%g0],prefetch_fcn */ +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[1+i],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[i+1],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|RS1_G0, "[i],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|SIMM13(~0), "[1],*", 0, v9 }, /* prefetch [rs1+0],prefetch_fcn */ +{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0), "[1+2]A,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0)|RS2_G0, "[1]A,*", 0, v9 }, /* prefetcha [rs1+%g0],prefetch_fcn */ +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[1+i]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[i+1]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|RS1_G0, "[i]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|SIMM13(~0), "[1]o,*", 0, v9 }, /* prefetcha [rs1+0],d */ + +{ "sll", F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "sll", F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, +{ "sra", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "sra", F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, +{ "srl", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "srl", F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, + +{ "sllx", F3(2, 0x25, 0)|(1<<12), F3(~2, ~0x25, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "sllx", F3(2, 0x25, 1)|(1<<12), F3(~2, ~0x25, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, +{ "srax", F3(2, 0x27, 0)|(1<<12), F3(~2, ~0x27, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "srax", F3(2, 0x27, 1)|(1<<12), F3(~2, ~0x27, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, +{ "srlx", F3(2, 0x26, 0)|(1<<12), F3(~2, ~0x26, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "srlx", F3(2, 0x26, 1)|(1<<12), F3(~2, ~0x26, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, + +{ "mulscc", F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "mulscc", F3(2, 0x24, 1), F3(~2, ~0x24, ~1), "1,i,d", 0, v6 }, + +{ "divscc", F3(2, 0x1d, 0), F3(~2, ~0x1d, ~0)|ASI(~0), "1,2,d", 0, sparclite }, +{ "divscc", F3(2, 0x1d, 1), F3(~2, ~0x1d, ~1), "1,i,d", 0, sparclite }, + +{ "scan", F3(2, 0x2c, 0), F3(~2, ~0x2c, ~0)|ASI(~0), "1,2,d", 0, sparclet|sparclite }, +{ "scan", F3(2, 0x2c, 1), F3(~2, ~0x2c, ~1), "1,i,d", 0, sparclet|sparclite }, + +{ "popc", F3(2, 0x2e, 0), F3(~2, ~0x2e, ~0)|RS1_G0|ASI(~0),"2,d", 0, v9 }, +{ "popc", F3(2, 0x2e, 1), F3(~2, ~0x2e, ~1)|RS1_G0, "i,d", 0, v9 }, + +{ "clr", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "d", F_ALIAS, v6 }, /* or %g0,%g0,d */ +{ "clr", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0), "d", F_ALIAS, v6 }, /* or %g0,0,d */ +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */ +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */ + +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */ +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+0] */ + +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */ +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+0] */ + +{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+%g0] */ +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[1+i]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[i+1]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+0] */ + +{ "orcc", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "1,i,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "i,1,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "orncc", F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "1,i,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "orn", F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "1,i,d", 0, v6 }, + +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0), "1", 0, v6 }, /* orcc rs1, %g0, %g0 */ +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */ +{ "tst", F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0), "1", 0, v6 }, /* orcc rs1, 0, %g0 */ + +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", 0, v8 }, /* wr r,r,%asrX */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", 0, v8 }, /* wr r,i,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", 0, v6 }, /* wr r,r,%y */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", 0, v6 }, /* wr r,i,%y */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", 0, v6notv9 }, /* wr r,r,%psr */ +{ "wr", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", 0, v6notv9 }, /* wr r,i,%psr */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", 0, v6notv9 }, /* wr r,r,%wim */ +{ "wr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", 0, v6notv9 }, /* wr r,i,%wim */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", 0, v6notv9 }, /* wr r,r,%tbr */ +{ "wr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", 0, v6notv9 }, /* wr r,i,%tbr */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ + +{ "wr", F3(2, 0x30, 0)|RD(2), F3(~2, ~0x30, ~0)|RD(~2)|ASI(~0), "1,2,E", 0, v9 }, /* wr r,r,%ccr */ +{ "wr", F3(2, 0x30, 1)|RD(2), F3(~2, ~0x30, ~1)|RD(~2), "1,i,E", 0, v9 }, /* wr r,i,%ccr */ +{ "wr", F3(2, 0x30, 0)|RD(3), F3(~2, ~0x30, ~0)|RD(~3)|ASI(~0), "1,2,o", 0, v9 }, /* wr r,r,%asi */ +{ "wr", F3(2, 0x30, 1)|RD(3), F3(~2, ~0x30, ~1)|RD(~3), "1,i,o", 0, v9 }, /* wr r,i,%asi */ +{ "wr", F3(2, 0x30, 0)|RD(6), F3(~2, ~0x30, ~0)|RD(~6)|ASI(~0), "1,2,s", 0, v9 }, /* wr r,r,%fprs */ +{ "wr", F3(2, 0x30, 1)|RD(6), F3(~2, ~0x30, ~1)|RD(~6), "1,i,s", 0, v9 }, /* wr r,i,%fprs */ + +{ "wr", F3(2, 0x30, 0)|RD(16), F3(~2, ~0x30, ~0)|RD(~16)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pcr */ +{ "wr", F3(2, 0x30, 1)|RD(16), F3(~2, ~0x30, ~1)|RD(~16), "1,i,_", 0, v9a }, /* wr r,i,%pcr */ +{ "wr", F3(2, 0x30, 0)|RD(17), F3(~2, ~0x30, ~0)|RD(~17)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pic */ +{ "wr", F3(2, 0x30, 1)|RD(17), F3(~2, ~0x30, ~1)|RD(~17), "1,i,_", 0, v9a }, /* wr r,i,%pic */ +{ "wr", F3(2, 0x30, 0)|RD(18), F3(~2, ~0x30, ~0)|RD(~18)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%dcr */ +{ "wr", F3(2, 0x30, 1)|RD(18), F3(~2, ~0x30, ~1)|RD(~18), "1,i,_", 0, v9a }, /* wr r,i,%dcr */ +{ "wr", F3(2, 0x30, 0)|RD(19), F3(~2, ~0x30, ~0)|RD(~19)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%gsr */ +{ "wr", F3(2, 0x30, 1)|RD(19), F3(~2, ~0x30, ~1)|RD(~19), "1,i,_", 0, v9a }, /* wr r,i,%gsr */ +{ "wr", F3(2, 0x30, 0)|RD(20), F3(~2, ~0x30, ~0)|RD(~20)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%set_softint */ +{ "wr", F3(2, 0x30, 1)|RD(20), F3(~2, ~0x30, ~1)|RD(~20), "1,i,_", 0, v9a }, /* wr r,i,%set_softint */ +{ "wr", F3(2, 0x30, 0)|RD(21), F3(~2, ~0x30, ~0)|RD(~21)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%clear_softint */ +{ "wr", F3(2, 0x30, 1)|RD(21), F3(~2, ~0x30, ~1)|RD(~21), "1,i,_", 0, v9a }, /* wr r,i,%clear_softint */ +{ "wr", F3(2, 0x30, 0)|RD(22), F3(~2, ~0x30, ~0)|RD(~22)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%softint */ +{ "wr", F3(2, 0x30, 1)|RD(22), F3(~2, ~0x30, ~1)|RD(~22), "1,i,_", 0, v9a }, /* wr r,i,%softint */ +{ "wr", F3(2, 0x30, 0)|RD(23), F3(~2, ~0x30, ~0)|RD(~23)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%tick_cmpr */ +{ "wr", F3(2, 0x30, 1)|RD(23), F3(~2, ~0x30, ~1)|RD(~23), "1,i,_", 0, v9a }, /* wr r,i,%tick_cmpr */ +{ "wr", F3(2, 0x30, 0)|RD(24), F3(~2, ~0x30, ~0)|RD(~24)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick */ +{ "wr", F3(2, 0x30, 1)|RD(24), F3(~2, ~0x30, ~1)|RD(~24), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick */ +{ "wr", F3(2, 0x30, 0)|RD(25), F3(~2, ~0x30, ~0)|RD(~25)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick_cmpr */ +{ "wr", F3(2, 0x30, 1)|RD(25), F3(~2, ~0x30, ~1)|RD(~25), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick_cmpr */ + +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", 0, v8 }, /* rd %asrX,r */ +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", 0, v6 }, /* rd %y,r */ +{ "rd", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", 0, v6notv9 }, /* rd %psr,r */ +{ "rd", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", 0, v6notv9 }, /* rd %wim,r */ +{ "rd", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", 0, v6notv9 }, /* rd %tbr,r */ + +{ "rd", F3(2, 0x28, 0)|RS1(2), F3(~2, ~0x28, ~0)|RS1(~2)|SIMM13(~0), "E,d", 0, v9 }, /* rd %ccr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(3), F3(~2, ~0x28, ~0)|RS1(~3)|SIMM13(~0), "o,d", 0, v9 }, /* rd %asi,r */ +{ "rd", F3(2, 0x28, 0)|RS1(4), F3(~2, ~0x28, ~0)|RS1(~4)|SIMM13(~0), "W,d", 0, v9 }, /* rd %tick,r */ +{ "rd", F3(2, 0x28, 0)|RS1(5), F3(~2, ~0x28, ~0)|RS1(~5)|SIMM13(~0), "P,d", 0, v9 }, /* rd %pc,r */ +{ "rd", F3(2, 0x28, 0)|RS1(6), F3(~2, ~0x28, ~0)|RS1(~6)|SIMM13(~0), "s,d", 0, v9 }, /* rd %fprs,r */ + +{ "rd", F3(2, 0x28, 0)|RS1(16), F3(~2, ~0x28, ~0)|RS1(~16)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pcr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(17), F3(~2, ~0x28, ~0)|RS1(~17)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pic,r */ +{ "rd", F3(2, 0x28, 0)|RS1(18), F3(~2, ~0x28, ~0)|RS1(~18)|SIMM13(~0), "/,d", 0, v9a }, /* rd %dcr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(19), F3(~2, ~0x28, ~0)|RS1(~19)|SIMM13(~0), "/,d", 0, v9a }, /* rd %gsr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(22), F3(~2, ~0x28, ~0)|RS1(~22)|SIMM13(~0), "/,d", 0, v9a }, /* rd %softint,r */ +{ "rd", F3(2, 0x28, 0)|RS1(23), F3(~2, ~0x28, ~0)|RS1(~23)|SIMM13(~0), "/,d", 0, v9a }, /* rd %tick_cmpr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(24), F3(~2, ~0x28, ~0)|RS1(~24)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick,r */ +{ "rd", F3(2, 0x28, 0)|RS1(25), F3(~2, ~0x28, ~0)|RS1(~25)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick_cmpr,r */ + +{ "rdpr", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|SIMM13(~0), "?,d", 0, v9 }, /* rdpr %priv,r */ +{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0), "1,2,!", 0, v9 }, /* wrpr r1,r2,%priv */ +{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|SIMM13(~0), "1,!", 0, v9 }, /* wrpr r1,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "1,i,!", 0, v9 }, /* wrpr r1,i,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,1,!", F_ALIAS, v9 }, /* wrpr i,r1,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RS1(~0), "i,!", 0, v9 }, /* wrpr i,%priv */ + +/* ??? This group seems wrong. A three operand move? */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", F_ALIAS, v6notv9 }, /* wr r,r,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", F_ALIAS, v6notv9 }, /* wr r,i,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", F_ALIAS, v6notv9 }, /* wr r,r,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", F_ALIAS, v6notv9 }, /* wr r,i,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", F_ALIAS, v6notv9 }, /* wr r,r,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", F_ALIAS, v6notv9 }, /* wr r,i,%tbr */ + +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", F_ALIAS, v8 }, /* rd %asr1,r */ +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", F_ALIAS, v6 }, /* rd %y,r */ +{ "mov", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", F_ALIAS, v6notv9 }, /* rd %psr,r */ +{ "mov", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", F_ALIAS, v6notv9 }, /* rd %wim,r */ +{ "mov", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", F_ALIAS, v6notv9 }, /* rd %tbr,r */ + +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "i,m", F_ALIAS, v8 }, /* wr %g0,i,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,0,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "i,y", F_ALIAS, v6 }, /* wr %g0,i,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0|SIMM13(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "i,p", F_ALIAS, v6notv9 }, /* wr %g0,i,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0|SIMM13(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,0,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "i,w", F_ALIAS, v6notv9 }, /* wr %g0,i,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0|SIMM13(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,0,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "i,t", F_ALIAS, v6notv9 }, /* wr %g0,i,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0|SIMM13(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,0,%tbr */ + +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0), "2,d", 0, v6 }, /* or %g0,rs2,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0, "i,d", 0, v6 }, /* or %g0,i,d */ +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0), "1,d", 0, v6 }, /* or rs1,%g0,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0), "1,d", 0, v6 }, /* or rs1,0,d */ + +{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "1,i,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,1,d", 0, v6 }, + +{ "bset", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* or rd,rs2,rd */ +{ "bset", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,r", F_ALIAS, v6 }, /* or rd,i,rd */ + +/* This is not a commutative instruction. */ +{ "andn", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "1,i,d", 0, v6 }, + +/* This is not a commutative instruction. */ +{ "andncc", F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "1,i,d", 0, v6 }, + +{ "bclr", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* andn rd,rs2,rd */ +{ "bclr", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,r", F_ALIAS, v6 }, /* andn rd,i,rd */ + +{ "cmp", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0), "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */ +{ "cmp", F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0, "1,i", 0, v6 }, /* subcc rs1,i,%g0 */ + +{ "sub", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "sub", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "1,i,d", 0, v6 }, + +{ "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 }, + +{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6notv9 }, +{ "subc", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "subc", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v9 }, + +{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6notv9 }, +{ "subccc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "subccc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v9 }, + +{ "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "i,1,d", 0, v6 }, + +{ "andcc", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "1,i,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "i,1,d", 0, v6 }, + +{ "dec", F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* sub rd,1,rd */ +{ "dec", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "i,r", F_ALIAS, v8 }, /* sub rd,imm,rd */ +{ "deccc", F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* subcc rd,1,rd */ +{ "deccc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "i,r", F_ALIAS, v8 }, /* subcc rd,imm,rd */ +{ "inc", F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* add rd,1,rd */ +{ "inc", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,r", F_ALIAS, v8 }, /* add rd,imm,rd */ +{ "inccc", F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* addcc rd,1,rd */ +{ "inccc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,r", F_ALIAS, v8 }, /* addcc rd,imm,rd */ + +{ "btst", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 }, /* andcc rs1,rs2,%g0 */ +{ "btst", F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 }, /* andcc rs1,i,%g0 */ + +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */ +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "O", F_ALIAS, v6 }, /* sub %g0,rd,rd */ + +{ "add", F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "1,i,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,1,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 }, + +{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6notv9 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6notv9 }, +{ "addc", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v9 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v9 }, + +{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6notv9 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6notv9 }, +{ "addccc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v9 }, + +{ "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "i,1,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "1,i,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "i,1,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "1,i,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "i,1,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "1,i,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "i,1,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "1,i,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "i,1,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "1,i,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "i,1,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "1,i,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "i,1,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "1,i,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "i,1,d", 0, v8 }, + +{ "mulx", F3(2, 0x09, 0), F3(~2, ~0x09, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "mulx", F3(2, 0x09, 1), F3(~2, ~0x09, ~1), "1,i,d", 0, v9 }, +{ "sdivx", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "sdivx", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, v9 }, +{ "udivx", F3(2, 0x0d, 0), F3(~2, ~0x0d, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "udivx", F3(2, 0x0d, 1), F3(~2, ~0x0d, ~1), "1,i,d", 0, v9 }, + +{ "call", F1(0x1), F1(~0x1), "L", F_JSR|F_DELAYED, v6 }, +{ "call", F1(0x1), F1(~0x1), "L,#", F_JSR|F_DELAYED, v6 }, + +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1", F_JSR|F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1,#", F_JSR|F_DELAYED, v6 }, + + +/* Conditional instructions. + + Because this part of the table was such a mess earlier, I have + macrofied it so that all the branches and traps are generated from + a single-line description of each condition value. John Gilmore. */ + +/* Define branches -- one annulled, one without, etc. */ +#define br(opcode, mask, lose, flags) \ + { opcode, (mask)|ANNUL, (lose), ",a l", (flags), v6 }, \ + { opcode, (mask) , (lose)|ANNUL, "l", (flags), v6 } + +#define brx(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), "Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), ",T Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a,T Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20), ANNUL|BPRED|(lose), ",N Z,G", (flags), v9 }, \ + { opcode, (mask)|(2<<20)|ANNUL, BPRED|(lose), ",a,N Z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), "z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), ",T z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a z,G", (flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a,T z,G", (flags), v9 }, \ + { opcode, (mask), ANNUL|BPRED|(lose)|(2<<20), ",N z,G", (flags), v9 }, \ + { opcode, (mask)|ANNUL, BPRED|(lose)|(2<<20), ",a,N z,G", (flags), v9 } + +/* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */ +#define tr(opcode, mask, lose, flags) \ + { opcode, (mask)|(2<<11)|IMMED, (lose)|RS1_G0, "Z,i", (flags), v9 }, /* %g0 + imm */ \ + { opcode, (mask)|(2<<11)|IMMED, (lose), "Z,1+i", (flags), v9 }, /* rs1 + imm */ \ + { opcode, (mask)|(2<<11), IMMED|(lose), "Z,1+2", (flags), v9 }, /* rs1 + rs2 */ \ + { opcode, (mask)|(2<<11), IMMED|(lose)|RS2_G0, "Z,1", (flags), v9 }, /* rs1 + %g0 */ \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "z,i", (flags)|F_ALIAS, v9 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "z,1+i", (flags)|F_ALIAS, v9 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "z,1+2", (flags)|F_ALIAS, v9 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "z,1", (flags)|F_ALIAS, v9 }, /* rs1 + %g0 */ \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "i", (flags), v6 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "1+i", (flags), v6 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "1+2", (flags), v6 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "1", (flags), v6 } /* rs1 + %g0 */ + +/* v9: We must put `brx' before `br', to ensure that we never match something + v9: against an expression unless it is an expression. Otherwise, we end + v9: up with undefined symbol tables entries, because they get added, but + v9: are not deleted if the pattern fails to match. */ + +/* Define both branches and traps based on condition mask */ +#define cond(bop, top, mask, flags) \ + brx(bop, F2(0, 1)|(mask), F2(~0, ~1)|((~mask)&COND(~0)), F_DELAYED|(flags)), /* v9 */ \ + br(bop, F2(0, 2)|(mask), F2(~0, ~2)|((~mask)&COND(~0)), F_DELAYED|(flags)), \ + tr(top, F3(2, 0x3a, 0)|(mask), F3(~2, ~0x3a, 0)|((~mask)&COND(~0)), ((flags) & ~(F_UNBR|F_CONDBR))) + +/* Define all the conditions, all the branches, all the traps. */ + +/* Standard branch, trap mnemonics */ +cond ("b", "ta", CONDA, F_UNBR), +/* Alternative form (just for assembly, not for disassembly) */ +cond ("ba", "t", CONDA, F_UNBR|F_ALIAS), + +cond ("bcc", "tcc", CONDCC, F_CONDBR), +cond ("bcs", "tcs", CONDCS, F_CONDBR), +cond ("be", "te", CONDE, F_CONDBR), +cond ("beq", "teq", CONDE, F_CONDBR|F_ALIAS), +cond ("bg", "tg", CONDG, F_CONDBR), +cond ("bgt", "tgt", CONDG, F_CONDBR|F_ALIAS), +cond ("bge", "tge", CONDGE, F_CONDBR), +cond ("bgeu", "tgeu", CONDGEU, F_CONDBR|F_ALIAS), /* for cc */ +cond ("bgu", "tgu", CONDGU, F_CONDBR), +cond ("bl", "tl", CONDL, F_CONDBR), +cond ("blt", "tlt", CONDL, F_CONDBR|F_ALIAS), +cond ("ble", "tle", CONDLE, F_CONDBR), +cond ("bleu", "tleu", CONDLEU, F_CONDBR), +cond ("blu", "tlu", CONDLU, F_CONDBR|F_ALIAS), /* for cs */ +cond ("bn", "tn", CONDN, F_CONDBR), +cond ("bne", "tne", CONDNE, F_CONDBR), +cond ("bneg", "tneg", CONDNEG, F_CONDBR), +cond ("bnz", "tnz", CONDNZ, F_CONDBR|F_ALIAS), /* for ne */ +cond ("bpos", "tpos", CONDPOS, F_CONDBR), +cond ("bvc", "tvc", CONDVC, F_CONDBR), +cond ("bvs", "tvs", CONDVS, F_CONDBR), +cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ + +#undef cond +#undef br +#undef brr /* v9 */ +#undef tr + +#define brr(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask)|BPRED, ANNUL|(lose), "1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED, ANNUL|(lose), ",T 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose), ",a 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|BPRED|ANNUL, (lose), ",a,T 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask), ANNUL|BPRED|(lose), ",N 1,k", F_DELAYED|(flags), v9 }, \ + { opcode, (mask)|ANNUL, BPRED|(lose), ",a,N 1,k", F_DELAYED|(flags), v9 } + +#define condr(bop, mask, flags) /* v9 */ \ + brr(bop, F2(0, 3)|COND(mask), F2(~0, ~3)|COND(~(mask)), (flags)) /* v9 */ + +/* v9 */ condr("brnz", 0x5, F_CONDBR), +/* v9 */ condr("brz", 0x1, F_CONDBR), +/* v9 */ condr("brgez", 0x7, F_CONDBR), +/* v9 */ condr("brlz", 0x3, F_CONDBR), +/* v9 */ condr("brlez", 0x2, F_CONDBR), +/* v9 */ condr("brgz", 0x6, F_CONDBR), + +#undef condr /* v9 */ +#undef brr /* v9 */ + +#define movr(opcode, mask, flags) /* v9 */ \ + { opcode, F3(2, 0x2f, 0)|RCOND(mask), F3(~2, ~0x2f, ~0)|RCOND(~(mask)), "1,2,d", (flags), v9 }, \ + { opcode, F3(2, 0x2f, 1)|RCOND(mask), F3(~2, ~0x2f, ~1)|RCOND(~(mask)), "1,j,d", (flags), v9 } + +#define fmrrs(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,f,g", (flags) | F_FLOAT, v9 } +#define fmrrd(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,B,H", (flags) | F_FLOAT, v9 } +#define fmrrq(opcode, mask, lose, flags) /* v9 */ \ + { opcode, (mask), (lose), "1,R,J", (flags) | F_FLOAT, v9 } + +#define fmovrs(mop, mask, flags) /* v9 */ \ + fmrrs(mop, F3(2, 0x35, 0)|OPF_LOW5(5)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~5)|RCOND(~(mask)), (flags)) /* v9 */ +#define fmovrd(mop, mask, flags) /* v9 */ \ + fmrrd(mop, F3(2, 0x35, 0)|OPF_LOW5(6)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~6)|RCOND(~(mask)), (flags)) /* v9 */ +#define fmovrq(mop, mask, flags) /* v9 */ \ + fmrrq(mop, F3(2, 0x35, 0)|OPF_LOW5(7)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~7)|RCOND(~(mask)), (flags)) /* v9 */ + +/* v9 */ movr("movrne", 0x5, 0), +/* v9 */ movr("movre", 0x1, 0), +/* v9 */ movr("movrgez", 0x7, 0), +/* v9 */ movr("movrlz", 0x3, 0), +/* v9 */ movr("movrlez", 0x2, 0), +/* v9 */ movr("movrgz", 0x6, 0), +/* v9 */ movr("movrnz", 0x5, F_ALIAS), +/* v9 */ movr("movrz", 0x1, F_ALIAS), + +/* v9 */ fmovrs("fmovrsne", 0x5, 0), +/* v9 */ fmovrs("fmovrse", 0x1, 0), +/* v9 */ fmovrs("fmovrsgez", 0x7, 0), +/* v9 */ fmovrs("fmovrslz", 0x3, 0), +/* v9 */ fmovrs("fmovrslez", 0x2, 0), +/* v9 */ fmovrs("fmovrsgz", 0x6, 0), +/* v9 */ fmovrs("fmovrsnz", 0x5, F_ALIAS), +/* v9 */ fmovrs("fmovrsz", 0x1, F_ALIAS), + +/* v9 */ fmovrd("fmovrdne", 0x5, 0), +/* v9 */ fmovrd("fmovrde", 0x1, 0), +/* v9 */ fmovrd("fmovrdgez", 0x7, 0), +/* v9 */ fmovrd("fmovrdlz", 0x3, 0), +/* v9 */ fmovrd("fmovrdlez", 0x2, 0), +/* v9 */ fmovrd("fmovrdgz", 0x6, 0), +/* v9 */ fmovrd("fmovrdnz", 0x5, F_ALIAS), +/* v9 */ fmovrd("fmovrdz", 0x1, F_ALIAS), + +/* v9 */ fmovrq("fmovrqne", 0x5, 0), +/* v9 */ fmovrq("fmovrqe", 0x1, 0), +/* v9 */ fmovrq("fmovrqgez", 0x7, 0), +/* v9 */ fmovrq("fmovrqlz", 0x3, 0), +/* v9 */ fmovrq("fmovrqlez", 0x2, 0), +/* v9 */ fmovrq("fmovrqgz", 0x6, 0), +/* v9 */ fmovrq("fmovrqnz", 0x5, F_ALIAS), +/* v9 */ fmovrq("fmovrqz", 0x1, F_ALIAS), + +#undef movr /* v9 */ +#undef fmovr /* v9 */ +#undef fmrr /* v9 */ + +#define movicc(opcode, cond, flags) /* v9 */ \ + { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|XCC|(1<<11), "z,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|XCC|(1<<11), "z,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|(1<<11), "Z,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|(1<<11), "Z,I,d", flags, v9 } + +#define movfcc(opcode, fcond, flags) /* v9 */ \ + { opcode, F3(2, 0x2c, 0)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~0), "6,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~1), "6,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~0), "7,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~1), "7,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~0), "8,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~1), "8,I,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 0)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~0), "9,2,d", flags, v9 }, \ + { opcode, F3(2, 0x2c, 1)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~1), "9,I,d", flags, v9 } + +#define movcc(opcode, cond, fcond, flags) /* v9 */ \ + movfcc (opcode, fcond, flags), /* v9 */ \ + movicc (opcode, cond, flags) /* v9 */ + +/* v9 */ movcc ("mova", CONDA, FCONDA, 0), +/* v9 */ movicc ("movcc", CONDCC, 0), +/* v9 */ movicc ("movgeu", CONDGEU, F_ALIAS), +/* v9 */ movicc ("movcs", CONDCS, 0), +/* v9 */ movicc ("movlu", CONDLU, F_ALIAS), +/* v9 */ movcc ("move", CONDE, FCONDE, 0), +/* v9 */ movcc ("movg", CONDG, FCONDG, 0), +/* v9 */ movcc ("movge", CONDGE, FCONDGE, 0), +/* v9 */ movicc ("movgu", CONDGU, 0), +/* v9 */ movcc ("movl", CONDL, FCONDL, 0), +/* v9 */ movcc ("movle", CONDLE, FCONDLE, 0), +/* v9 */ movicc ("movleu", CONDLEU, 0), +/* v9 */ movfcc ("movlg", FCONDLG, 0), +/* v9 */ movcc ("movn", CONDN, FCONDN, 0), +/* v9 */ movcc ("movne", CONDNE, FCONDNE, 0), +/* v9 */ movicc ("movneg", CONDNEG, 0), +/* v9 */ movcc ("movnz", CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ movfcc ("movo", FCONDO, 0), +/* v9 */ movicc ("movpos", CONDPOS, 0), +/* v9 */ movfcc ("movu", FCONDU, 0), +/* v9 */ movfcc ("movue", FCONDUE, 0), +/* v9 */ movfcc ("movug", FCONDUG, 0), +/* v9 */ movfcc ("movuge", FCONDUGE, 0), +/* v9 */ movfcc ("movul", FCONDUL, 0), +/* v9 */ movfcc ("movule", FCONDULE, 0), +/* v9 */ movicc ("movvc", CONDVC, 0), +/* v9 */ movicc ("movvs", CONDVS, 0), +/* v9 */ movcc ("movz", CONDZ, FCONDZ, F_ALIAS), + +#undef movicc /* v9 */ +#undef movfcc /* v9 */ +#undef movcc /* v9 */ + +#define FM_SF 1 /* v9 - values for fpsize */ +#define FM_DF 2 /* v9 */ +#define FM_QF 3 /* v9 */ + +#define fmovicc(opcode, fpsize, cond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z,f,g", flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z,f,g", flags, v9 } + +#define fmovfcc(opcode, fpsize, fcond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6,f,g", flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7,f,g", flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8,f,g", flags, v9 }, \ +{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9,f,g", flags, v9 } + +/* FIXME: use fmovicc/fmovfcc? */ /* v9 */ +#define fmovcc(opcode, fpsize, cond, fcond, flags) /* v9 */ \ +{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z,f,g", flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6,f,g", flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z,f,g", flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7,f,g", flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8,f,g", flags | F_FLOAT, v9 }, \ +{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9,f,g", flags | F_FLOAT, v9 } + +/* v9 */ fmovcc ("fmovda", FM_DF, CONDA, FCONDA, 0), +/* v9 */ fmovcc ("fmovqa", FM_QF, CONDA, FCONDA, 0), +/* v9 */ fmovcc ("fmovsa", FM_SF, CONDA, FCONDA, 0), +/* v9 */ fmovicc ("fmovdcc", FM_DF, CONDCC, 0), +/* v9 */ fmovicc ("fmovqcc", FM_QF, CONDCC, 0), +/* v9 */ fmovicc ("fmovscc", FM_SF, CONDCC, 0), +/* v9 */ fmovicc ("fmovdcs", FM_DF, CONDCS, 0), +/* v9 */ fmovicc ("fmovqcs", FM_QF, CONDCS, 0), +/* v9 */ fmovicc ("fmovscs", FM_SF, CONDCS, 0), +/* v9 */ fmovcc ("fmovde", FM_DF, CONDE, FCONDE, 0), +/* v9 */ fmovcc ("fmovqe", FM_QF, CONDE, FCONDE, 0), +/* v9 */ fmovcc ("fmovse", FM_SF, CONDE, FCONDE, 0), +/* v9 */ fmovcc ("fmovdg", FM_DF, CONDG, FCONDG, 0), +/* v9 */ fmovcc ("fmovqg", FM_QF, CONDG, FCONDG, 0), +/* v9 */ fmovcc ("fmovsg", FM_SF, CONDG, FCONDG, 0), +/* v9 */ fmovcc ("fmovdge", FM_DF, CONDGE, FCONDGE, 0), +/* v9 */ fmovcc ("fmovqge", FM_QF, CONDGE, FCONDGE, 0), +/* v9 */ fmovcc ("fmovsge", FM_SF, CONDGE, FCONDGE, 0), +/* v9 */ fmovicc ("fmovdgeu", FM_DF, CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("fmovqgeu", FM_QF, CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("fmovsgeu", FM_SF, CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("fmovdgu", FM_DF, CONDGU, 0), +/* v9 */ fmovicc ("fmovqgu", FM_QF, CONDGU, 0), +/* v9 */ fmovicc ("fmovsgu", FM_SF, CONDGU, 0), +/* v9 */ fmovcc ("fmovdl", FM_DF, CONDL, FCONDL, 0), +/* v9 */ fmovcc ("fmovql", FM_QF, CONDL, FCONDL, 0), +/* v9 */ fmovcc ("fmovsl", FM_SF, CONDL, FCONDL, 0), +/* v9 */ fmovcc ("fmovdle", FM_DF, CONDLE, FCONDLE, 0), +/* v9 */ fmovcc ("fmovqle", FM_QF, CONDLE, FCONDLE, 0), +/* v9 */ fmovcc ("fmovsle", FM_SF, CONDLE, FCONDLE, 0), +/* v9 */ fmovicc ("fmovdleu", FM_DF, CONDLEU, 0), +/* v9 */ fmovicc ("fmovqleu", FM_QF, CONDLEU, 0), +/* v9 */ fmovicc ("fmovsleu", FM_SF, CONDLEU, 0), +/* v9 */ fmovfcc ("fmovdlg", FM_DF, FCONDLG, 0), +/* v9 */ fmovfcc ("fmovqlg", FM_QF, FCONDLG, 0), +/* v9 */ fmovfcc ("fmovslg", FM_SF, FCONDLG, 0), +/* v9 */ fmovicc ("fmovdlu", FM_DF, CONDLU, F_ALIAS), +/* v9 */ fmovicc ("fmovqlu", FM_QF, CONDLU, F_ALIAS), +/* v9 */ fmovicc ("fmovslu", FM_SF, CONDLU, F_ALIAS), +/* v9 */ fmovcc ("fmovdn", FM_DF, CONDN, FCONDN, 0), +/* v9 */ fmovcc ("fmovqn", FM_QF, CONDN, FCONDN, 0), +/* v9 */ fmovcc ("fmovsn", FM_SF, CONDN, FCONDN, 0), +/* v9 */ fmovcc ("fmovdne", FM_DF, CONDNE, FCONDNE, 0), +/* v9 */ fmovcc ("fmovqne", FM_QF, CONDNE, FCONDNE, 0), +/* v9 */ fmovcc ("fmovsne", FM_SF, CONDNE, FCONDNE, 0), +/* v9 */ fmovicc ("fmovdneg", FM_DF, CONDNEG, 0), +/* v9 */ fmovicc ("fmovqneg", FM_QF, CONDNEG, 0), +/* v9 */ fmovicc ("fmovsneg", FM_SF, CONDNEG, 0), +/* v9 */ fmovcc ("fmovdnz", FM_DF, CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovcc ("fmovqnz", FM_QF, CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovcc ("fmovsnz", FM_SF, CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovfcc ("fmovdo", FM_DF, FCONDO, 0), +/* v9 */ fmovfcc ("fmovqo", FM_QF, FCONDO, 0), +/* v9 */ fmovfcc ("fmovso", FM_SF, FCONDO, 0), +/* v9 */ fmovicc ("fmovdpos", FM_DF, CONDPOS, 0), +/* v9 */ fmovicc ("fmovqpos", FM_QF, CONDPOS, 0), +/* v9 */ fmovicc ("fmovspos", FM_SF, CONDPOS, 0), +/* v9 */ fmovfcc ("fmovdu", FM_DF, FCONDU, 0), +/* v9 */ fmovfcc ("fmovqu", FM_QF, FCONDU, 0), +/* v9 */ fmovfcc ("fmovsu", FM_SF, FCONDU, 0), +/* v9 */ fmovfcc ("fmovdue", FM_DF, FCONDUE, 0), +/* v9 */ fmovfcc ("fmovque", FM_QF, FCONDUE, 0), +/* v9 */ fmovfcc ("fmovsue", FM_SF, FCONDUE, 0), +/* v9 */ fmovfcc ("fmovdug", FM_DF, FCONDUG, 0), +/* v9 */ fmovfcc ("fmovqug", FM_QF, FCONDUG, 0), +/* v9 */ fmovfcc ("fmovsug", FM_SF, FCONDUG, 0), +/* v9 */ fmovfcc ("fmovduge", FM_DF, FCONDUGE, 0), +/* v9 */ fmovfcc ("fmovquge", FM_QF, FCONDUGE, 0), +/* v9 */ fmovfcc ("fmovsuge", FM_SF, FCONDUGE, 0), +/* v9 */ fmovfcc ("fmovdul", FM_DF, FCONDUL, 0), +/* v9 */ fmovfcc ("fmovqul", FM_QF, FCONDUL, 0), +/* v9 */ fmovfcc ("fmovsul", FM_SF, FCONDUL, 0), +/* v9 */ fmovfcc ("fmovdule", FM_DF, FCONDULE, 0), +/* v9 */ fmovfcc ("fmovqule", FM_QF, FCONDULE, 0), +/* v9 */ fmovfcc ("fmovsule", FM_SF, FCONDULE, 0), +/* v9 */ fmovicc ("fmovdvc", FM_DF, CONDVC, 0), +/* v9 */ fmovicc ("fmovqvc", FM_QF, CONDVC, 0), +/* v9 */ fmovicc ("fmovsvc", FM_SF, CONDVC, 0), +/* v9 */ fmovicc ("fmovdvs", FM_DF, CONDVS, 0), +/* v9 */ fmovicc ("fmovqvs", FM_QF, CONDVS, 0), +/* v9 */ fmovicc ("fmovsvs", FM_SF, CONDVS, 0), +/* v9 */ fmovcc ("fmovdz", FM_DF, CONDZ, FCONDZ, F_ALIAS), +/* v9 */ fmovcc ("fmovqz", FM_QF, CONDZ, FCONDZ, F_ALIAS), +/* v9 */ fmovcc ("fmovsz", FM_SF, CONDZ, FCONDZ, F_ALIAS), + +#undef fmovicc /* v9 */ +#undef fmovfcc /* v9 */ +#undef fmovcc /* v9 */ +#undef FM_DF /* v9 */ +#undef FM_QF /* v9 */ +#undef FM_SF /* v9 */ + +/* Coprocessor branches. */ +#define CBR(opcode, mask, lose, flags, arch) \ + { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED, arch }, \ + { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED, arch } + +/* Floating point branches. */ +#define FBR(opcode, mask, lose, flags) \ + { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED|F_FBR, v6 }, \ + { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED|F_FBR, v6 } + +/* V9 extended floating point branches. */ +#define FBRX(opcode, mask, lose, flags) /* v9 */ \ + { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), "6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), ",T 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a,T 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask), ANNUL|BPRED|FBFCC(~0)|(lose), ",N 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(0)|(mask)|ANNUL, BPRED|FBFCC(~0)|(lose), ",a,N 6,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), "7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), ",T 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a,T 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask), ANNUL|BPRED|FBFCC(~1)|(lose), ",N 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(1)|(mask)|ANNUL, BPRED|FBFCC(~1)|(lose), ",a,N 7,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), "8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), ",T 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a,T 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask), ANNUL|BPRED|FBFCC(~2)|(lose), ",N 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(2)|(mask)|ANNUL, BPRED|FBFCC(~2)|(lose), ",a,N 8,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), "9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), ",T 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a,T 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask), ANNUL|BPRED|FBFCC(~3)|(lose), ",N 9,G", flags|F_DELAYED|F_FBR, v9 }, \ + { opcode, FBFCC(3)|(mask)|ANNUL, BPRED|FBFCC(~3)|(lose), ",a,N 9,G", flags|F_DELAYED|F_FBR, v9 } + +/* v9: We must put `FBRX' before `FBR', to ensure that we never match + v9: something against an expression unless it is an expression. Otherwise, + v9: we end up with undefined symbol tables entries, because they get added, + v9: but are not deleted if the pattern fails to match. */ + +#define CONDFC(fop, cop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6notlet) + +#define CONDFCL(fop, cop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \ + CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6) + +#define CONDF(fop, mask, flags) \ + FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \ + FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags) + +CONDFC ("fb", "cb", 0x8, F_UNBR), +CONDFCL ("fba", "cba", 0x8, F_UNBR|F_ALIAS), +CONDFC ("fbe", "cb0", 0x9, F_CONDBR), +CONDF ("fbz", 0x9, F_CONDBR|F_ALIAS), +CONDFC ("fbg", "cb2", 0x6, F_CONDBR), +CONDFC ("fbge", "cb02", 0xb, F_CONDBR), +CONDFC ("fbl", "cb1", 0x4, F_CONDBR), +CONDFC ("fble", "cb01", 0xd, F_CONDBR), +CONDFC ("fblg", "cb12", 0x2, F_CONDBR), +CONDFCL ("fbn", "cbn", 0x0, F_UNBR), +CONDFC ("fbne", "cb123", 0x1, F_CONDBR), +CONDF ("fbnz", 0x1, F_CONDBR|F_ALIAS), +CONDFC ("fbo", "cb012", 0xf, F_CONDBR), +CONDFC ("fbu", "cb3", 0x7, F_CONDBR), +CONDFC ("fbue", "cb03", 0xa, F_CONDBR), +CONDFC ("fbug", "cb23", 0x5, F_CONDBR), +CONDFC ("fbuge", "cb023", 0xc, F_CONDBR), +CONDFC ("fbul", "cb13", 0x3, F_CONDBR), +CONDFC ("fbule", "cb013", 0xe, F_CONDBR), + +#undef CONDFC +#undef CONDFCL +#undef CONDF +#undef CBR +#undef FBR +#undef FBRX /* v9 */ + +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */ +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+0,%g0 */ + +{ "nop", F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */ + +{ "set", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v6 }, +{ "setuw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, +{ "setsw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, +{ "setx", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,1,d", F_ALIAS, v9 }, + +{ "sethi", F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 }, + +{ "taddcc", F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "1,i,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "i,1,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "1,i,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "i,1,d", 0, v6 }, + +{ "tsubcc", F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcc", F3(2, 0x21, 1), F3(~2, ~0x21, ~1), "1,i,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 1), F3(~2, ~0x23, ~1), "1,i,d", 0, v6 }, + +{ "unimp", F2(0x0, 0x0), 0xffc00000, "n", 0, v6notv9 }, +{ "illtrap", F2(0, 0), F2(~0, ~0)|RD_G0, "n", 0, v9 }, + +/* This *is* a commutative instruction. */ +{ "xnor", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "1,i,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "i,1,d", 0, v6 }, +/* This *is* a commutative instruction. */ +{ "xnorcc", F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "1,i,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "i,1,d", 0, v6 }, +{ "xor", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "1,i,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,1,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "1,i,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "i,1,d", 0, v6 }, + +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */ +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */ + +{ "btog", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */ +{ "btog", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */ + +/* FPop1 and FPop2 are not instructions. Don't accept them. */ + +{ "fdtoi", F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", F_FLOAT, v6 }, +{ "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", F_FLOAT, v8 }, + +{ "fdtox", F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,g", F_FLOAT, v9 }, +{ "fstox", F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,g", F_FLOAT, v9 }, +{ "fqtox", F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,g", F_FLOAT, v9 }, + +{ "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", F_FLOAT, v6 }, +{ "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", F_FLOAT, v8 }, + +{ "fxtod", F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "f,H", F_FLOAT, v9 }, +{ "fxtos", F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "f,g", F_FLOAT, v9 }, +{ "fxtoq", F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "f,J", F_FLOAT, v9 }, + +{ "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", F_FLOAT, v8 }, +{ "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", F_FLOAT, v6 }, +{ "fqtod", F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", F_FLOAT, v8 }, +{ "fqtos", F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", F_FLOAT, v8 }, +{ "fstod", F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", F_FLOAT, v6 }, +{ "fstoq", F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", F_FLOAT, v8 }, + +{ "fdivd", F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", F_FLOAT, v6 }, +{ "fdivq", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT, v8 }, +{ "fdivx", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fdivs", F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", F_FLOAT, v6 }, +{ "fmuld", F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", F_FLOAT, v6 }, +{ "fmulq", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT, v8 }, +{ "fmulx", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fmuls", F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", F_FLOAT, v6 }, + +{ "fdmulq", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT, v8 }, +{ "fdmulx", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsmuld", F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", F_FLOAT, v8 }, + +{ "fsqrtd", F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", F_FLOAT, v7 }, +{ "fsqrtq", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT, v8 }, +{ "fsqrtx", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsqrts", F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", F_FLOAT, v7 }, + +{ "fabsd", F3F(2, 0x34, 0x00a), F3F(~2, ~0x34, ~0x00a)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fabsq", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fabsx", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fabss", F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fmovd", F3F(2, 0x34, 0x002), F3F(~2, ~0x34, ~0x002)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fmovq", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fmovx", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fmovs", F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fnegd", F3F(2, 0x34, 0x006), F3F(~2, ~0x34, ~0x006)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fnegq", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fnegx", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fnegs", F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", F_FLOAT, v6 }, + +{ "faddd", F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", F_FLOAT, v6 }, +{ "faddq", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT, v8 }, +{ "faddx", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fadds", F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", F_FLOAT, v6 }, +{ "fsubd", F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", F_FLOAT, v6 }, +{ "fsubq", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT, v8 }, +{ "fsubx", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsubs", F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", F_FLOAT, v6 }, + +#define CMPFCC(x) (((x)&0x3)<<25) + +{ "fcmpd", F3F(2, 0x35, 0x052), F3F(~2, ~0x35, ~0x052)|RD_G0, "v,B", F_FLOAT, v6 }, +{ "fcmpd", CMPFCC(0)|F3F(2, 0x35, 0x052), CMPFCC(~0)|F3F(~2, ~0x35, ~0x052), "6,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(1)|F3F(2, 0x35, 0x052), CMPFCC(~1)|F3F(~2, ~0x35, ~0x052), "7,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(2)|F3F(2, 0x35, 0x052), CMPFCC(~2)|F3F(~2, ~0x35, ~0x052), "8,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(3)|F3F(2, 0x35, 0x052), CMPFCC(~3)|F3F(~2, ~0x35, ~0x052), "9,v,B", F_FLOAT, v9 }, +{ "fcmped", F3F(2, 0x35, 0x056), F3F(~2, ~0x35, ~0x056)|RD_G0, "v,B", F_FLOAT, v6 }, +{ "fcmped", CMPFCC(0)|F3F(2, 0x35, 0x056), CMPFCC(~0)|F3F(~2, ~0x35, ~0x056), "6,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(1)|F3F(2, 0x35, 0x056), CMPFCC(~1)|F3F(~2, ~0x35, ~0x056), "7,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(2)|F3F(2, 0x35, 0x056), CMPFCC(~2)|F3F(~2, ~0x35, ~0x056), "8,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(3)|F3F(2, 0x35, 0x056), CMPFCC(~3)|F3F(~2, ~0x35, ~0x056), "9,v,B", F_FLOAT, v9 }, +{ "fcmpq", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT, v8 }, +{ "fcmpq", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT, v9 }, +{ "fcmpeq", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT, v8 }, +{ "fcmpeq", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT, v9 }, +{ "fcmpx", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, +{ "fcmpx", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, +{ "fcmpex", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmps", F3F(2, 0x35, 0x051), F3F(~2, ~0x35, ~0x051)|RD_G0, "e,f", F_FLOAT, v6 }, +{ "fcmps", CMPFCC(0)|F3F(2, 0x35, 0x051), CMPFCC(~0)|F3F(~2, ~0x35, ~0x051), "6,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(1)|F3F(2, 0x35, 0x051), CMPFCC(~1)|F3F(~2, ~0x35, ~0x051), "7,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(2)|F3F(2, 0x35, 0x051), CMPFCC(~2)|F3F(~2, ~0x35, ~0x051), "8,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(3)|F3F(2, 0x35, 0x051), CMPFCC(~3)|F3F(~2, ~0x35, ~0x051), "9,e,f", F_FLOAT, v9 }, +{ "fcmpes", F3F(2, 0x35, 0x055), F3F(~2, ~0x35, ~0x055)|RD_G0, "e,f", F_FLOAT, v6 }, +{ "fcmpes", CMPFCC(0)|F3F(2, 0x35, 0x055), CMPFCC(~0)|F3F(~2, ~0x35, ~0x055), "6,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(1)|F3F(2, 0x35, 0x055), CMPFCC(~1)|F3F(~2, ~0x35, ~0x055), "7,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(2)|F3F(2, 0x35, 0x055), CMPFCC(~2)|F3F(~2, ~0x35, ~0x055), "8,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(3)|F3F(2, 0x35, 0x055), CMPFCC(~3)|F3F(~2, ~0x35, ~0x055), "9,e,f", F_FLOAT, v9 }, + +/* These Extended FPop (FIFO) instructions are new in the Fujitsu + MB86934, replacing the CPop instructions from v6 and later + processors. */ + +#define EFPOP1_2(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op)|RS1_G0, args, 0, sparclite } +#define EFPOP1_3(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op), args, 0, sparclite } +#define EFPOP2_2(name, op, args) { name, F3F(2, 0x37, op), F3F(~2, ~0x37, ~op)|RD_G0, args, 0, sparclite } + +EFPOP1_2 ("efitod", 0x0c8, "f,H"), +EFPOP1_2 ("efitos", 0x0c4, "f,g"), +EFPOP1_2 ("efdtoi", 0x0d2, "B,g"), +EFPOP1_2 ("efstoi", 0x0d1, "f,g"), +EFPOP1_2 ("efstod", 0x0c9, "f,H"), +EFPOP1_2 ("efdtos", 0x0c6, "B,g"), +EFPOP1_2 ("efmovs", 0x001, "f,g"), +EFPOP1_2 ("efnegs", 0x005, "f,g"), +EFPOP1_2 ("efabss", 0x009, "f,g"), +EFPOP1_2 ("efsqrtd", 0x02a, "B,H"), +EFPOP1_2 ("efsqrts", 0x029, "f,g"), +EFPOP1_3 ("efaddd", 0x042, "v,B,H"), +EFPOP1_3 ("efadds", 0x041, "e,f,g"), +EFPOP1_3 ("efsubd", 0x046, "v,B,H"), +EFPOP1_3 ("efsubs", 0x045, "e,f,g"), +EFPOP1_3 ("efdivd", 0x04e, "v,B,H"), +EFPOP1_3 ("efdivs", 0x04d, "e,f,g"), +EFPOP1_3 ("efmuld", 0x04a, "v,B,H"), +EFPOP1_3 ("efmuls", 0x049, "e,f,g"), +EFPOP1_3 ("efsmuld", 0x069, "e,f,H"), +EFPOP2_2 ("efcmpd", 0x052, "v,B"), +EFPOP2_2 ("efcmped", 0x056, "v,B"), +EFPOP2_2 ("efcmps", 0x051, "e,f"), +EFPOP2_2 ("efcmpes", 0x055, "e,f"), + +#undef EFPOP1_2 +#undef EFPOP1_3 +#undef EFPOP2_2 + +/* These are marked F_ALIAS, so that they won't conflict with sparclite insns + present. Otherwise, the F_ALIAS flag is ignored. */ +{ "cpop1", F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", F_ALIAS, v6notv9 }, +{ "cpop2", F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", F_ALIAS, v6notv9 }, + +/* sparclet specific insns */ + +COMMUTEOP ("umac", 0x3e, sparclet), +COMMUTEOP ("smac", 0x3f, sparclet), +COMMUTEOP ("umacd", 0x2e, sparclet), +COMMUTEOP ("smacd", 0x2f, sparclet), +COMMUTEOP ("umuld", 0x09, sparclet), +COMMUTEOP ("smuld", 0x0d, sparclet), + +{ "shuffle", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, sparclet }, +{ "shuffle", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, sparclet }, + +/* The manual isn't completely accurate on these insns. The `rs2' field is + treated as being 6 bits to account for 6 bit immediates to cpush. It is + assumed that it is intended that bit 5 is 0 when rs2 contains a reg. */ +#define BIT5 (1<<5) +{ "crdcxt", F3(2, 0x36, 0)|SLCPOP(4), F3(~2, ~0x36, ~0)|SLCPOP(~4)|BIT5|RS2(~0), "U,d", 0, sparclet }, +{ "cwrcxt", F3(2, 0x36, 0)|SLCPOP(3), F3(~2, ~0x36, ~0)|SLCPOP(~3)|BIT5|RS2(~0), "1,u", 0, sparclet }, +{ "cpush", F3(2, 0x36, 0)|SLCPOP(0), F3(~2, ~0x36, ~0)|SLCPOP(~0)|BIT5|RD(~0), "1,2", 0, sparclet }, +{ "cpush", F3(2, 0x36, 1)|SLCPOP(0), F3(~2, ~0x36, ~1)|SLCPOP(~0)|RD(~0), "1,Y", 0, sparclet }, +{ "cpusha", F3(2, 0x36, 0)|SLCPOP(1), F3(~2, ~0x36, ~0)|SLCPOP(~1)|BIT5|RD(~0), "1,2", 0, sparclet }, +{ "cpusha", F3(2, 0x36, 1)|SLCPOP(1), F3(~2, ~0x36, ~1)|SLCPOP(~1)|RD(~0), "1,Y", 0, sparclet }, +{ "cpull", F3(2, 0x36, 0)|SLCPOP(2), F3(~2, ~0x36, ~0)|SLCPOP(~2)|BIT5|RS1(~0)|RS2(~0), "d", 0, sparclet }, +#undef BIT5 + +/* sparclet coprocessor branch insns */ +#define SLCBCC2(opcode, mask, lose) \ + { opcode, (mask), ANNUL|(lose), "l", F_DELAYED|F_CONDBR, sparclet }, \ + { opcode, (mask)|ANNUL, (lose), ",a l", F_DELAYED|F_CONDBR, sparclet } +#define SLCBCC(opcode, mask) \ + SLCBCC2(opcode, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask))) + +/* cbn,cba can't be defined here because they're defined elsewhere and GAS + requires all mnemonics of the same name to be consecutive. */ +/*SLCBCC("cbn", 0), - already defined */ +SLCBCC("cbe", 1), +SLCBCC("cbf", 2), +SLCBCC("cbef", 3), +SLCBCC("cbr", 4), +SLCBCC("cber", 5), +SLCBCC("cbfr", 6), +SLCBCC("cbefr", 7), +/*SLCBCC("cba", 8), - already defined */ +SLCBCC("cbne", 9), +SLCBCC("cbnf", 10), +SLCBCC("cbnef", 11), +SLCBCC("cbnr", 12), +SLCBCC("cbner", 13), +SLCBCC("cbnfr", 14), +SLCBCC("cbnefr", 15), + +#undef SLCBCC2 +#undef SLCBCC + +{ "casa", F3(3, 0x3c, 0), F3(~3, ~0x3c, ~0), "[1]A,2,d", 0, v9 }, +{ "casa", F3(3, 0x3c, 1), F3(~3, ~0x3c, ~1), "[1]o,2,d", 0, v9 }, +{ "casxa", F3(3, 0x3e, 0), F3(~3, ~0x3e, ~0), "[1]A,2,d", 0, v9 }, +{ "casxa", F3(3, 0x3e, 1), F3(~3, ~0x3e, ~1), "[1]o,2,d", 0, v9 }, + +/* v9 synthetic insns */ +{ "iprefetch", F2(0, 1)|(2<<20)|BPRED, F2(~0, ~1)|(1<<20)|ANNUL|COND(~0), "G", 0, v9 }, /* bn,a,pt %xcc,label */ +{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* sra rs1,%g0,rd */ +{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* sra rd,%g0,rd */ +{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* srl rs1,%g0,rd */ +{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* srl rd,%g0,rd */ +{ "cas", F3(3, 0x3c, 0)|ASI(0x80), F3(~3, ~0x3c, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P,rs2,rd */ +{ "casl", F3(3, 0x3c, 0)|ASI(0x88), F3(~3, ~0x3c, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P_L,rs2,rd */ +{ "casx", F3(3, 0x3e, 0)|ASI(0x80), F3(~3, ~0x3e, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P,rs2,rd */ +{ "casxl", F3(3, 0x3e, 0)|ASI(0x88), F3(~3, ~0x3e, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P_L,rs2,rd */ + +/* Ultrasparc extensions */ +{ "shutdown", F3F(2, 0x36, 0x080), F3F(~2, ~0x36, ~0x080)|RD_G0|RS1_G0|RS2_G0, "", 0, v9a }, + +/* FIXME: Do we want to mark these as F_FLOAT, or something similar? */ +{ "fpadd16", F3F(2, 0x36, 0x050), F3F(~2, ~0x36, ~0x050), "v,B,H", 0, v9a }, +{ "fpadd16s", F3F(2, 0x36, 0x051), F3F(~2, ~0x36, ~0x051), "e,f,g", 0, v9a }, +{ "fpadd32", F3F(2, 0x36, 0x052), F3F(~2, ~0x36, ~0x052), "v,B,H", 0, v9a }, +{ "fpadd32s", F3F(2, 0x36, 0x053), F3F(~2, ~0x36, ~0x053), "e,f,g", 0, v9a }, +{ "fpsub16", F3F(2, 0x36, 0x054), F3F(~2, ~0x36, ~0x054), "v,B,H", 0, v9a }, +{ "fpsub16s", F3F(2, 0x36, 0x055), F3F(~2, ~0x36, ~0x055), "e,f,g", 0, v9a }, +{ "fpsub32", F3F(2, 0x36, 0x056), F3F(~2, ~0x36, ~0x056), "v,B,H", 0, v9a }, +{ "fpsub32s", F3F(2, 0x36, 0x057), F3F(~2, ~0x36, ~0x057), "e,f,g", 0, v9a }, + +{ "fpack32", F3F(2, 0x36, 0x03a), F3F(~2, ~0x36, ~0x03a), "v,B,H", 0, v9a }, +{ "fpack16", F3F(2, 0x36, 0x03b), F3F(~2, ~0x36, ~0x03b)|RS1_G0, "B,g", 0, v9a }, +{ "fpackfix", F3F(2, 0x36, 0x03d), F3F(~2, ~0x36, ~0x03d)|RS1_G0, "B,g", 0, v9a }, +{ "fexpand", F3F(2, 0x36, 0x04d), F3F(~2, ~0x36, ~0x04d)|RS1_G0, "f,H", 0, v9a }, +{ "fpmerge", F3F(2, 0x36, 0x04b), F3F(~2, ~0x36, ~0x04b), "e,f,H", 0, v9a }, + +/* Note that the mixing of 32/64 bit regs is intentional. */ +{ "fmul8x16", F3F(2, 0x36, 0x031), F3F(~2, ~0x36, ~0x031), "e,B,H", 0, v9a }, +{ "fmul8x16au", F3F(2, 0x36, 0x033), F3F(~2, ~0x36, ~0x033), "e,f,H", 0, v9a }, +{ "fmul8x16al", F3F(2, 0x36, 0x035), F3F(~2, ~0x36, ~0x035), "e,f,H", 0, v9a }, +{ "fmul8sux16", F3F(2, 0x36, 0x036), F3F(~2, ~0x36, ~0x036), "v,B,H", 0, v9a }, +{ "fmul8ulx16", F3F(2, 0x36, 0x037), F3F(~2, ~0x36, ~0x037), "v,B,H", 0, v9a }, +{ "fmuld8sux16", F3F(2, 0x36, 0x038), F3F(~2, ~0x36, ~0x038), "e,f,H", 0, v9a }, +{ "fmuld8ulx16", F3F(2, 0x36, 0x039), F3F(~2, ~0x36, ~0x039), "e,f,H", 0, v9a }, + +{ "alignaddr", F3F(2, 0x36, 0x018), F3F(~2, ~0x36, ~0x018), "1,2,d", 0, v9a }, +{ "alignaddrl", F3F(2, 0x36, 0x01a), F3F(~2, ~0x36, ~0x01a), "1,2,d", 0, v9a }, +{ "faligndata", F3F(2, 0x36, 0x048), F3F(~2, ~0x36, ~0x048), "v,B,H", 0, v9a }, + +{ "fzero", F3F(2, 0x36, 0x060), F3F(~2, ~0x36, ~0x060), "H", 0, v9a }, +{ "fzeros", F3F(2, 0x36, 0x061), F3F(~2, ~0x36, ~0x061), "g", 0, v9a }, +{ "fone", F3F(2, 0x36, 0x07e), F3F(~2, ~0x36, ~0x07e), "H", 0, v9a }, +{ "fones", F3F(2, 0x36, 0x07f), F3F(~2, ~0x36, ~0x07f), "g", 0, v9a }, +{ "fsrc1", F3F(2, 0x36, 0x074), F3F(~2, ~0x36, ~0x074), "v,H", 0, v9a }, +{ "fsrc1s", F3F(2, 0x36, 0x075), F3F(~2, ~0x36, ~0x075), "e,g", 0, v9a }, +{ "fsrc2", F3F(2, 0x36, 0x078), F3F(~2, ~0x36, ~0x078), "B,H", 0, v9a }, +{ "fsrc2s", F3F(2, 0x36, 0x079), F3F(~2, ~0x36, ~0x079), "f,g", 0, v9a }, +{ "fnot1", F3F(2, 0x36, 0x06a), F3F(~2, ~0x36, ~0x06a), "v,H", 0, v9a }, +{ "fnot1s", F3F(2, 0x36, 0x06b), F3F(~2, ~0x36, ~0x06b), "e,g", 0, v9a }, +{ "fnot2", F3F(2, 0x36, 0x066), F3F(~2, ~0x36, ~0x066), "B,H", 0, v9a }, +{ "fnot2s", F3F(2, 0x36, 0x067), F3F(~2, ~0x36, ~0x067), "f,g", 0, v9a }, +{ "for", F3F(2, 0x36, 0x07c), F3F(~2, ~0x36, ~0x07c), "v,B,H", 0, v9a }, +{ "fors", F3F(2, 0x36, 0x07d), F3F(~2, ~0x36, ~0x07d), "e,f,g", 0, v9a }, +{ "fnor", F3F(2, 0x36, 0x062), F3F(~2, ~0x36, ~0x062), "v,B,H", 0, v9a }, +{ "fnors", F3F(2, 0x36, 0x063), F3F(~2, ~0x36, ~0x063), "e,f,g", 0, v9a }, +{ "fand", F3F(2, 0x36, 0x070), F3F(~2, ~0x36, ~0x070), "v,B,H", 0, v9a }, +{ "fands", F3F(2, 0x36, 0x071), F3F(~2, ~0x36, ~0x071), "e,f,g", 0, v9a }, +{ "fnand", F3F(2, 0x36, 0x06e), F3F(~2, ~0x36, ~0x06e), "v,B,H", 0, v9a }, +{ "fnands", F3F(2, 0x36, 0x06f), F3F(~2, ~0x36, ~0x06f), "e,f,g", 0, v9a }, +{ "fxor", F3F(2, 0x36, 0x06c), F3F(~2, ~0x36, ~0x06c), "v,B,H", 0, v9a }, +{ "fxors", F3F(2, 0x36, 0x06d), F3F(~2, ~0x36, ~0x06d), "e,f,g", 0, v9a }, +{ "fxnor", F3F(2, 0x36, 0x072), F3F(~2, ~0x36, ~0x072), "v,B,H", 0, v9a }, +{ "fxnors", F3F(2, 0x36, 0x073), F3F(~2, ~0x36, ~0x073), "e,f,g", 0, v9a }, +{ "fornot1", F3F(2, 0x36, 0x07a), F3F(~2, ~0x36, ~0x07a), "v,B,H", 0, v9a }, +{ "fornot1s", F3F(2, 0x36, 0x07b), F3F(~2, ~0x36, ~0x07b), "e,f,g", 0, v9a }, +{ "fornot2", F3F(2, 0x36, 0x076), F3F(~2, ~0x36, ~0x076), "v,B,H", 0, v9a }, +{ "fornot2s", F3F(2, 0x36, 0x077), F3F(~2, ~0x36, ~0x077), "e,f,g", 0, v9a }, +{ "fandnot1", F3F(2, 0x36, 0x068), F3F(~2, ~0x36, ~0x068), "v,B,H", 0, v9a }, +{ "fandnot1s", F3F(2, 0x36, 0x069), F3F(~2, ~0x36, ~0x069), "e,f,g", 0, v9a }, +{ "fandnot2", F3F(2, 0x36, 0x064), F3F(~2, ~0x36, ~0x064), "v,B,H", 0, v9a }, +{ "fandnot2s", F3F(2, 0x36, 0x065), F3F(~2, ~0x36, ~0x065), "e,f,g", 0, v9a }, + +{ "fcmpgt16", F3F(2, 0x36, 0x028), F3F(~2, ~0x36, ~0x028), "v,B,d", 0, v9a }, +{ "fcmpgt32", F3F(2, 0x36, 0x02c), F3F(~2, ~0x36, ~0x02c), "v,B,d", 0, v9a }, +{ "fcmple16", F3F(2, 0x36, 0x020), F3F(~2, ~0x36, ~0x020), "v,B,d", 0, v9a }, +{ "fcmple32", F3F(2, 0x36, 0x024), F3F(~2, ~0x36, ~0x024), "v,B,d", 0, v9a }, +{ "fcmpne16", F3F(2, 0x36, 0x022), F3F(~2, ~0x36, ~0x022), "v,B,d", 0, v9a }, +{ "fcmpne32", F3F(2, 0x36, 0x026), F3F(~2, ~0x36, ~0x026), "v,B,d", 0, v9a }, +{ "fcmpeq16", F3F(2, 0x36, 0x02a), F3F(~2, ~0x36, ~0x02a), "v,B,d", 0, v9a }, +{ "fcmpeq32", F3F(2, 0x36, 0x02e), F3F(~2, ~0x36, ~0x02e), "v,B,d", 0, v9a }, + +{ "edge8", F3F(2, 0x36, 0x000), F3F(~2, ~0x36, ~0x000), "1,2,d", 0, v9a }, +{ "edge8l", F3F(2, 0x36, 0x002), F3F(~2, ~0x36, ~0x002), "1,2,d", 0, v9a }, +{ "edge16", F3F(2, 0x36, 0x004), F3F(~2, ~0x36, ~0x004), "1,2,d", 0, v9a }, +{ "edge16l", F3F(2, 0x36, 0x006), F3F(~2, ~0x36, ~0x006), "1,2,d", 0, v9a }, +{ "edge32", F3F(2, 0x36, 0x008), F3F(~2, ~0x36, ~0x008), "1,2,d", 0, v9a }, +{ "edge32l", F3F(2, 0x36, 0x00a), F3F(~2, ~0x36, ~0x00a), "1,2,d", 0, v9a }, + +{ "pdist", F3F(2, 0x36, 0x03e), F3F(~2, ~0x36, ~0x03e), "v,B,H", 0, v9a }, + +{ "array8", F3F(2, 0x36, 0x010), F3F(~2, ~0x36, ~0x010), "1,2,d", 0, v9a }, +{ "array16", F3F(2, 0x36, 0x012), F3F(~2, ~0x36, ~0x012), "1,2,d", 0, v9a }, +{ "array32", F3F(2, 0x36, 0x014), F3F(~2, ~0x36, ~0x014), "1,2,d", 0, v9a }, + +/* Cheetah instructions */ +{ "edge8n", F3F(2, 0x36, 0x001), F3F(~2, ~0x36, ~0x001), "1,2,d", 0, v9b }, +{ "edge8ln", F3F(2, 0x36, 0x003), F3F(~2, ~0x36, ~0x003), "1,2,d", 0, v9b }, +{ "edge16n", F3F(2, 0x36, 0x005), F3F(~2, ~0x36, ~0x005), "1,2,d", 0, v9b }, +{ "edge16ln", F3F(2, 0x36, 0x007), F3F(~2, ~0x36, ~0x007), "1,2,d", 0, v9b }, +{ "edge32n", F3F(2, 0x36, 0x009), F3F(~2, ~0x36, ~0x009), "1,2,d", 0, v9b }, +{ "edge32ln", F3F(2, 0x36, 0x00b), F3F(~2, ~0x36, ~0x00b), "1,2,d", 0, v9b }, + +{ "bmask", F3F(2, 0x36, 0x019), F3F(~2, ~0x36, ~0x019), "1,2,d", 0, v9b }, +{ "bshuffle", F3F(2, 0x36, 0x04c), F3F(~2, ~0x36, ~0x04c), "v,B,H", 0, v9b }, + +{ "siam", F3F(2, 0x36, 0x081), F3F(~2, ~0x36, ~0x081)|RD_G0|RS1_G0|RS2(~7), "3", 0, v9b }, + +/* More v9 specific insns, these need to come last so they do not clash + with v9a instructions such as "edge8" which looks like impdep1. */ + +#define IMPDEP(name, code) \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0)|ASI(~0), "1,2,d", 0, v9notv9a }, \ +{ name, F3(2, code, 1), F3(~2, ~code, ~1), "1,i,d", 0, v9notv9a }, \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0), "x,1,2,d", 0, v9notv9a }, \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0), "x,e,f,g", 0, v9notv9a } + +IMPDEP ("impdep1", 0x36), +IMPDEP ("impdep2", 0x37), + +#undef IMPDEP + +}; + +const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])); + +/* Utilities for argument parsing. */ + +typedef struct +{ + int value; + const char *name; +} arg; + +/* Look up NAME in TABLE. */ + +static int lookup_name PARAMS ((const arg *, const char *)); +static const char *lookup_value PARAMS ((const arg *, int)); + +static int +lookup_name (table, name) + const arg *table; + const char *name; +{ + const arg *p; + + for (p = table; p->name; ++p) + if (strcmp (name, p->name) == 0) + return p->value; + + return -1; +} + +/* Look up VALUE in TABLE. */ + +static const char * +lookup_value (table, value) + const arg *table; + int value; +{ + const arg *p; + + for (p = table; p->name; ++p) + if (value == p->value) + return p->name; + + return (char *) 0; +} + +/* Handle ASI's. */ + +static arg asi_table[] = +{ + /* These are in the v9 architecture manual. */ + /* The shorter versions appear first, they're here because Sun's as has them. + Sun's as uses #ASI_P_L instead of #ASI_PL (which appears in the + UltraSPARC architecture manual). */ + { 0x04, "#ASI_N" }, + { 0x0c, "#ASI_N_L" }, + { 0x10, "#ASI_AIUP" }, + { 0x11, "#ASI_AIUS" }, + { 0x18, "#ASI_AIUP_L" }, + { 0x19, "#ASI_AIUS_L" }, + { 0x80, "#ASI_P" }, + { 0x81, "#ASI_S" }, + { 0x82, "#ASI_PNF" }, + { 0x83, "#ASI_SNF" }, + { 0x88, "#ASI_P_L" }, + { 0x89, "#ASI_S_L" }, + { 0x8a, "#ASI_PNF_L" }, + { 0x8b, "#ASI_SNF_L" }, + { 0x04, "#ASI_NUCLEUS" }, + { 0x0c, "#ASI_NUCLEUS_LITTLE" }, + { 0x10, "#ASI_AS_IF_USER_PRIMARY" }, + { 0x11, "#ASI_AS_IF_USER_SECONDARY" }, + { 0x18, "#ASI_AS_IF_USER_PRIMARY_LITTLE" }, + { 0x19, "#ASI_AS_IF_USER_SECONDARY_LITTLE" }, + { 0x80, "#ASI_PRIMARY" }, + { 0x81, "#ASI_SECONDARY" }, + { 0x82, "#ASI_PRIMARY_NOFAULT" }, + { 0x83, "#ASI_SECONDARY_NOFAULT" }, + { 0x88, "#ASI_PRIMARY_LITTLE" }, + { 0x89, "#ASI_SECONDARY_LITTLE" }, + { 0x8a, "#ASI_PRIMARY_NOFAULT_LITTLE" }, + { 0x8b, "#ASI_SECONDARY_NOFAULT_LITTLE" }, + /* These are UltraSPARC extensions. */ + /* FIXME: There are dozens of them. Not sure we want them all. + Most are for kernel building but some are for vis type stuff. */ + { 0, 0 } +}; + +/* Return the value for ASI NAME, or -1 if not found. */ + +int +sparc_encode_asi (name) + const char *name; +{ + return lookup_name (asi_table, name); +} + +/* Return the name for ASI value VALUE or NULL if not found. */ + +const char * +sparc_decode_asi (value) + int value; +{ + return lookup_value (asi_table, value); +} + +/* Handle membar masks. */ + +static arg membar_table[] = +{ + { 0x40, "#Sync" }, + { 0x20, "#MemIssue" }, + { 0x10, "#Lookaside" }, + { 0x08, "#StoreStore" }, + { 0x04, "#LoadStore" }, + { 0x02, "#StoreLoad" }, + { 0x01, "#LoadLoad" }, + { 0, 0 } +}; + +/* Return the value for membar arg NAME, or -1 if not found. */ + +int +sparc_encode_membar (name) + const char *name; +{ + return lookup_name (membar_table, name); +} + +/* Return the name for membar value VALUE or NULL if not found. */ + +const char * +sparc_decode_membar (value) + int value; +{ + return lookup_value (membar_table, value); +} + +/* Handle prefetch args. */ + +static arg prefetch_table[] = +{ + { 0, "#n_reads" }, + { 1, "#one_read" }, + { 2, "#n_writes" }, + { 3, "#one_write" }, + { 4, "#page" }, + { 16, "#invalidate" }, + { 0, 0 } +}; + +/* Return the value for prefetch arg NAME, or -1 if not found. */ + +int +sparc_encode_prefetch (name) + const char *name; +{ + return lookup_name (prefetch_table, name); +} + +/* Return the name for prefetch value VALUE or NULL if not found. */ + +const char * +sparc_decode_prefetch (value) + int value; +{ + return lookup_value (prefetch_table, value); +} + +/* Handle sparclet coprocessor registers. */ + +static arg sparclet_cpreg_table[] = +{ + { 0, "%ccsr" }, + { 1, "%ccfr" }, + { 2, "%cccrcr" }, + { 3, "%ccpr" }, + { 4, "%ccsr2" }, + { 5, "%cccrr" }, + { 6, "%ccrstr" }, + { 0, 0 } +}; + +/* Return the value for sparclet cpreg arg NAME, or -1 if not found. */ + +int +sparc_encode_sparclet_cpreg (name) + const char *name; +{ + return lookup_name (sparclet_cpreg_table, name); +} + +/* Return the name for sparclet cpreg value VALUE or NULL if not found. */ + +const char * +sparc_decode_sparclet_cpreg (value) + int value; +{ + return lookup_value (sparclet_cpreg_table, value); +} + +#undef MASK_V9 + +/* Bitmask of v9 architectures. */ +#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \ + | (1 << SPARC_OPCODE_ARCH_V9A) \ + | (1 << SPARC_OPCODE_ARCH_V9B)) +/* 1 if INSN is for v9 only. */ +#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9)) +/* 1 if INSN is for v9. */ +#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0) + +/* The sorted opcode table. */ +static const struct sparc_opcode **sorted_opcodes; + +/* For faster lookup, after insns are sorted they are hashed. */ +/* ??? I think there is room for even more improvement. */ + +#define HASH_SIZE 256 +/* It is important that we only look at insn code bits as that is how the + opcode table is hashed. OPCODE_BITS is a table of valid bits for each + of the main types (0,1,2,3). */ +static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 }; +#define HASH_INSN(INSN) \ + ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19)) +struct opcode_hash { + struct opcode_hash *next; + const struct sparc_opcode *opcode; +}; +static struct opcode_hash *opcode_hash_table[HASH_SIZE]; + +static void build_hash_table + PARAMS ((const struct sparc_opcode **, struct opcode_hash **, int)); +static int is_delayed_branch PARAMS ((unsigned long)); +static int compare_opcodes PARAMS ((const void *, const void *)); +static int compute_arch_mask PARAMS ((unsigned long)); + +/* Sign-extend a value which is N bits long. */ +#define SEX(value, bits) \ + ((((int)(value)) << ((8 * sizeof (int)) - bits)) \ + >> ((8 * sizeof (int)) - bits) ) + +static char *reg_names[] = +{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", + "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", + "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", + "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", + "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", + "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", + "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", + "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63", +/* psr, wim, tbr, fpsr, cpsr are v8 only. */ + "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" +}; + +#define freg_names (®_names[4 * 8]) + +/* These are ordered according to there register number in + rdpr and wrpr insns. */ +static char *v9_priv_reg_names[] = +{ + "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl", + "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin", + "wstate", "fq" + /* "ver" - special cased */ +}; + +/* These are ordered according to there register number in + rd and wr insns (-16). */ +static char *v9a_asr_reg_names[] = +{ + "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint", + "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr" +}; + +/* Macros used to extract instruction fields. Not all fields have + macros defined here, only those which are actually used. */ + +#define X_RD(i) (((i) >> 25) & 0x1f) +#define X_RS1(i) (((i) >> 14) & 0x1f) +#define X_LDST_I(i) (((i) >> 13) & 1) +#define X_ASI(i) (((i) >> 5) & 0xff) +#define X_RS2(i) (((i) >> 0) & 0x1f) +#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1)) +#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n)) +#define X_DISP22(i) (((i) >> 0) & 0x3fffff) +#define X_IMM22(i) X_DISP22 (i) +#define X_DISP30(i) (((i) >> 0) & 0x3fffffff) + +/* These are for v9. */ +#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff)) +#define X_DISP19(i) (((i) >> 0) & 0x7ffff) +#define X_MEMBAR(i) ((i) & 0x7f) + +/* Here is the union which was used to extract instruction fields + before the shift and mask macros were written. + + union sparc_insn + { + unsigned long int code; + struct + { + unsigned int anop:2; + #define op ldst.anop + unsigned int anrd:5; + #define rd ldst.anrd + unsigned int op3:6; + unsigned int anrs1:5; + #define rs1 ldst.anrs1 + unsigned int i:1; + unsigned int anasi:8; + #define asi ldst.anasi + unsigned int anrs2:5; + #define rs2 ldst.anrs2 + #define shcnt rs2 + } ldst; + struct + { + unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1; + unsigned int IMM13:13; + #define imm13 IMM13.IMM13 + } IMM13; + struct + { + unsigned int anop:2; + unsigned int a:1; + unsigned int cond:4; + unsigned int op2:3; + unsigned int DISP22:22; + #define disp22 branch.DISP22 + #define imm22 disp22 + } branch; + struct + { + unsigned int anop:2; + unsigned int a:1; + unsigned int z:1; + unsigned int rcond:3; + unsigned int op2:3; + unsigned int DISP16HI:2; + unsigned int p:1; + unsigned int _rs1:5; + unsigned int DISP16LO:14; + } branch16; + struct + { + unsigned int anop:2; + unsigned int adisp30:30; + #define disp30 call.adisp30 + } call; + }; + + */ + +/* Nonzero if INSN is the opcode for a delayed branch. */ +static int +is_delayed_branch (insn) + unsigned long insn; +{ + struct opcode_hash *op; + + for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) + { + const struct sparc_opcode *opcode = op->opcode; + if ((opcode->match & insn) == opcode->match + && (opcode->lose & insn) == 0) + return (opcode->flags & F_DELAYED); + } + return 0; +} + +/* extern void qsort (); */ + +/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value + to compare_opcodes. */ +static unsigned int current_arch_mask; + +/* Print one instruction from MEMADDR on INFO->STREAM. + + We suffix the instruction with a comment that gives the absolute + address involved, as well as its symbolic form, if the instruction + is preceded by a findable `sethi' and it either adds an immediate + displacement to that register, or it is an `add' or `or' instruction + on that register. */ + +int +print_insn_sparc (memaddr, info) + bfd_vma memaddr; + disassemble_info *info; +{ + FILE *stream = info->stream; + bfd_byte buffer[4]; + unsigned long insn; + register struct opcode_hash *op; + /* Nonzero of opcode table has been initialized. */ + static int opcodes_initialized = 0; + /* bfd mach number of last call. */ + static unsigned long current_mach = 0; + bfd_vma (*getword) PARAMS ((const unsigned char *)); + + if (!opcodes_initialized + || info->mach != current_mach) + { + int i; + + current_arch_mask = compute_arch_mask (info->mach); + + if (!opcodes_initialized) + sorted_opcodes = (const struct sparc_opcode **) + malloc (sparc_num_opcodes * sizeof (struct sparc_opcode *)); + /* Reset the sorted table so we can resort it. */ + for (i = 0; i < sparc_num_opcodes; ++i) + sorted_opcodes[i] = &sparc_opcodes[i]; + qsort ((char *) sorted_opcodes, sparc_num_opcodes, + sizeof (sorted_opcodes[0]), compare_opcodes); + + build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes); + current_mach = info->mach; + opcodes_initialized = 1; + } + + { + int status = + (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + } + + /* On SPARClite variants such as DANlite (sparc86x), instructions + are always big-endian even when the machine is in little-endian mode. */ + if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite) + getword = bfd_getb32; + else + getword = bfd_getl32; + + insn = getword (buffer); + + info->insn_info_valid = 1; /* We do return this info */ + info->insn_type = dis_nonbranch; /* Assume non branch insn */ + info->branch_delay_insns = 0; /* Assume no delay */ + info->target = 0; /* Assume no target known */ + + for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) + { + const struct sparc_opcode *opcode = op->opcode; + + /* If the insn isn't supported by the current architecture, skip it. */ + if (! (opcode->architecture & current_arch_mask)) + continue; + + if ((opcode->match & insn) == opcode->match + && (opcode->lose & insn) == 0) + { + /* Nonzero means that we have found an instruction which has + the effect of adding or or'ing the imm13 field to rs1. */ + int imm_added_to_rs1 = 0; + int imm_ored_to_rs1 = 0; + + /* Nonzero means that we have found a plus sign in the args + field of the opcode table. */ + int found_plus = 0; + + /* Nonzero means we have an annulled branch. */ + int is_annulled = 0; + + /* Do we have an `add' or `or' instruction combining an + immediate with rs1? */ + if (opcode->match == 0x80102000) /* or */ + imm_ored_to_rs1 = 1; + if (opcode->match == 0x80002000) /* add */ + imm_added_to_rs1 = 1; + + if (X_RS1 (insn) != X_RD (insn) + && strchr (opcode->args, 'r') != 0) + /* Can't do simple format if source and dest are different. */ + continue; + if (X_RS2 (insn) != X_RD (insn) + && strchr (opcode->args, 'O') != 0) + /* Can't do simple format if source and dest are different. */ + continue; + + (*info->fprintf_func) (stream, opcode->name); + + { + register const char *s; + + if (opcode->args[0] != ',') + (*info->fprintf_func) (stream, " "); + for (s = opcode->args; *s != '\0'; ++s) + { + while (*s == ',') + { + (*info->fprintf_func) (stream, ","); + ++s; + switch (*s) { + case 'a': + (*info->fprintf_func) (stream, "a"); + is_annulled = 1; + ++s; + continue; + case 'N': + (*info->fprintf_func) (stream, "pn"); + ++s; + continue; + + case 'T': + (*info->fprintf_func) (stream, "pt"); + ++s; + continue; + + default: + break; + } /* switch on arg */ + } /* while there are comma started args */ + + (*info->fprintf_func) (stream, " "); + + switch (*s) + { + case '+': + found_plus = 1; + + /* note fall-through */ + default: + (*info->fprintf_func) (stream, "%c", *s); + break; + + case '#': + (*info->fprintf_func) (stream, "0"); + break; + +#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n]) + case '1': + case 'r': + reg (X_RS1 (insn)); + break; + + case '2': + case 'O': + reg (X_RS2 (insn)); + break; + + case 'd': + reg (X_RD (insn)); + break; +#undef reg + +#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n]) +#define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)]) + case 'e': + freg (X_RS1 (insn)); + break; + case 'v': /* double/even */ + case 'V': /* quad/multiple of 4 */ + fregx (X_RS1 (insn)); + break; + + case 'f': + freg (X_RS2 (insn)); + break; + case 'B': /* double/even */ + case 'R': /* quad/multiple of 4 */ + fregx (X_RS2 (insn)); + break; + + case 'g': + freg (X_RD (insn)); + break; + case 'H': /* double/even */ + case 'J': /* quad/multiple of 4 */ + fregx (X_RD (insn)); + break; +#undef freg +#undef fregx + +#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n)) + case 'b': + creg (X_RS1 (insn)); + break; + + case 'c': + creg (X_RS2 (insn)); + break; + + case 'D': + creg (X_RD (insn)); + break; +#undef creg + + case 'h': + (*info->fprintf_func) (stream, "%%hi(%#x)", + ((unsigned) 0xFFFFFFFF + & ((int) X_IMM22 (insn) << 10))); + break; + + case 'i': /* 13 bit immediate */ + case 'I': /* 11 bit immediate */ + case 'j': /* 10 bit immediate */ + { + int imm; + + if (*s == 'i') + imm = X_SIMM (insn, 13); + else if (*s == 'I') + imm = X_SIMM (insn, 11); + else + imm = X_SIMM (insn, 10); + + /* Check to see whether we have a 1+i, and take + note of that fact. + + Note: because of the way we sort the table, + we will be matching 1+i rather than i+1, + so it is OK to assume that i is after +, + not before it. */ + if (found_plus) + imm_added_to_rs1 = 1; + + if (imm <= 9) + (*info->fprintf_func) (stream, "%d", imm); + else + (*info->fprintf_func) (stream, "%#x", imm); + } + break; + + case 'X': /* 5 bit unsigned immediate */ + case 'Y': /* 6 bit unsigned immediate */ + { + int imm = X_IMM (insn, *s == 'X' ? 5 : 6); + + if (imm <= 9) + (info->fprintf_func) (stream, "%d", imm); + else + (info->fprintf_func) (stream, "%#x", (unsigned) imm); + } + break; + + case '3': + (info->fprintf_func) (stream, "%d", X_IMM (insn, 3)); + break; + + case 'K': + { + int mask = X_MEMBAR (insn); + int bit = 0x40, printed_one = 0; + const char *name; + + if (mask == 0) + (info->fprintf_func) (stream, "0"); + else + while (bit) + { + if (mask & bit) + { + if (printed_one) + (info->fprintf_func) (stream, "|"); + name = sparc_decode_membar (bit); + (info->fprintf_func) (stream, "%s", name); + printed_one = 1; + } + bit >>= 1; + } + break; + } + + case 'k': + info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'G': + info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4; + (*info->print_address_func) (info->target, info); + break; + + case '6': + case '7': + case '8': + case '9': + (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0'); + break; + + case 'z': + (*info->fprintf_func) (stream, "%%icc"); + break; + + case 'Z': + (*info->fprintf_func) (stream, "%%xcc"); + break; + + case 'E': + (*info->fprintf_func) (stream, "%%ccr"); + break; + + case 's': + (*info->fprintf_func) (stream, "%%fprs"); + break; + + case 'o': + (*info->fprintf_func) (stream, "%%asi"); + break; + + case 'W': + (*info->fprintf_func) (stream, "%%tick"); + break; + + case 'P': + (*info->fprintf_func) (stream, "%%pc"); + break; + + case '?': + if (X_RS1 (insn) == 31) + (*info->fprintf_func) (stream, "%%ver"); + else if ((unsigned) X_RS1 (insn) < 16) + (*info->fprintf_func) (stream, "%%%s", + v9_priv_reg_names[X_RS1 (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '!': + if ((unsigned) X_RD (insn) < 15) + (*info->fprintf_func) (stream, "%%%s", + v9_priv_reg_names[X_RD (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '/': + if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25) + (*info->fprintf_func) (stream, "%%reserved"); + else + (*info->fprintf_func) (stream, "%%%s", + v9a_asr_reg_names[X_RS1 (insn)-16]); + break; + + case '_': + if (X_RD (insn) < 16 || X_RD (insn) > 25) + (*info->fprintf_func) (stream, "%%reserved"); + else + (*info->fprintf_func) (stream, "%%%s", + v9a_asr_reg_names[X_RD (insn)-16]); + break; + + case '*': + { + const char *name = sparc_decode_prefetch (X_RD (insn)); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "%d", X_RD (insn)); + break; + } + + case 'M': + (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn)); + break; + + case 'm': + (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn)); + break; + + case 'L': + info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'n': + (*info->fprintf_func) + (stream, "%#x", SEX (X_DISP22 (insn), 22)); + break; + + case 'l': + info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'A': + { + const char *name = sparc_decode_asi (X_ASI (insn)); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "(%d)", X_ASI (insn)); + break; + } + + case 'C': + (*info->fprintf_func) (stream, "%%csr"); + break; + + case 'F': + (*info->fprintf_func) (stream, "%%fsr"); + break; + + case 'p': + (*info->fprintf_func) (stream, "%%psr"); + break; + + case 'q': + (*info->fprintf_func) (stream, "%%fq"); + break; + + case 'Q': + (*info->fprintf_func) (stream, "%%cq"); + break; + + case 't': + (*info->fprintf_func) (stream, "%%tbr"); + break; + + case 'w': + (*info->fprintf_func) (stream, "%%wim"); + break; + + case 'x': + (*info->fprintf_func) (stream, "%d", + ((X_LDST_I (insn) << 8) + + X_ASI (insn))); + break; + + case 'y': + (*info->fprintf_func) (stream, "%%y"); + break; + + case 'u': + case 'U': + { + int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn); + const char *name = sparc_decode_sparclet_cpreg (val); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "%%cpreg(%d)", val); + break; + } + } + } + } + + /* If we are adding or or'ing something to rs1, then + check to see whether the previous instruction was + a sethi to the same register as in the sethi. + If so, attempt to print the result of the add or + or (in this context add and or do the same thing) + and its symbolic value. */ + if (imm_ored_to_rs1 || imm_added_to_rs1) + { + unsigned long prev_insn; + int errcode; + + errcode = + (*info->read_memory_func) + (memaddr - 4, buffer, sizeof (buffer), info); + prev_insn = getword (buffer); + + if (errcode == 0) + { + /* If it is a delayed branch, we need to look at the + instruction before the delayed branch. This handles + sequences such as + + sethi %o1, %hi(_foo), %o1 + call _printf + or %o1, %lo(_foo), %o1 + */ + + if (is_delayed_branch (prev_insn)) + { + errcode = (*info->read_memory_func) + (memaddr - 8, buffer, sizeof (buffer), info); + prev_insn = getword (buffer); + } + } + + /* If there was a problem reading memory, then assume + the previous instruction was not sethi. */ + if (errcode == 0) + { + /* Is it sethi to the same register? */ + if ((prev_insn & 0xc1c00000) == 0x01000000 + && X_RD (prev_insn) == X_RS1 (insn)) + { + (*info->fprintf_func) (stream, "\t! "); + info->target = + ((unsigned) 0xFFFFFFFF + & ((int) X_IMM22 (prev_insn) << 10)); + if (imm_added_to_rs1) + info->target += X_SIMM (insn, 13); + else + info->target |= X_SIMM (insn, 13); + (*info->print_address_func) (info->target, info); + info->insn_type = dis_dref; + info->data_size = 4; /* FIXME!!! */ + } + } + } + + if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR)) + { + /* FIXME -- check is_annulled flag */ + if (opcode->flags & F_UNBR) + info->insn_type = dis_branch; + if (opcode->flags & F_CONDBR) + info->insn_type = dis_condbranch; + if (opcode->flags & F_JSR) + info->insn_type = dis_jsr; + if (opcode->flags & F_DELAYED) + info->branch_delay_insns = 1; + } + + return sizeof (buffer); + } + } + + info->insn_type = dis_noninsn; /* Mark as non-valid instruction */ + (*info->fprintf_func) (stream, _("unknown")); + return sizeof (buffer); +} + +/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */ + +static int +compute_arch_mask (mach) + unsigned long mach; +{ + switch (mach) + { + case 0 : + case bfd_mach_sparc : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8); + case bfd_mach_sparc_sparclet : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET); + case bfd_mach_sparc_sparclite : + case bfd_mach_sparc_sparclite_le : + /* sparclites insns are recognized by default (because that's how + they've always been treated, for better or worse). Kludge this by + indicating generic v8 is also selected. */ + return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) + | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); + case bfd_mach_sparc_v8plus : + case bfd_mach_sparc_v9 : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9); + case bfd_mach_sparc_v8plusa : + case bfd_mach_sparc_v9a : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A); + case bfd_mach_sparc_v8plusb : + case bfd_mach_sparc_v9b : + return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B); + } + abort (); +} + +/* Compare opcodes A and B. */ + +static int +compare_opcodes (const void *a, const void *b) +{ + struct sparc_opcode *op0 = * (struct sparc_opcode **) a; + struct sparc_opcode *op1 = * (struct sparc_opcode **) b; + unsigned long int match0 = op0->match, match1 = op1->match; + unsigned long int lose0 = op0->lose, lose1 = op1->lose; + register unsigned int i; + + /* If one (and only one) insn isn't supported by the current architecture, + prefer the one that is. If neither are supported, but they're both for + the same architecture, continue processing. Otherwise (both unsupported + and for different architectures), prefer lower numbered arch's (fudged + by comparing the bitmasks). */ + if (op0->architecture & current_arch_mask) + { + if (! (op1->architecture & current_arch_mask)) + return -1; + } + else + { + if (op1->architecture & current_arch_mask) + return 1; + else if (op0->architecture != op1->architecture) + return op0->architecture - op1->architecture; + } + + /* If a bit is set in both match and lose, there is something + wrong with the opcode table. */ + if (match0 & lose0) + { + fprintf + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op0->name, match0, lose0); + op0->lose &= ~op0->match; + lose0 = op0->lose; + } + + if (match1 & lose1) + { + fprintf + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op1->name, match1, lose1); + op1->lose &= ~op1->match; + lose1 = op1->lose; + } + + /* Because the bits that are variable in one opcode are constant in + another, it is important to order the opcodes in the right order. */ + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (match0 & x) != 0; + int x1 = (match1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (lose0 & x) != 0; + int x1 = (lose1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + /* They are functionally equal. So as long as the opcode table is + valid, we can put whichever one first we want, on aesthetic grounds. */ + + /* Our first aesthetic ground is that aliases defer to real insns. */ + { + int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS); + if (alias_diff != 0) + /* Put the one that isn't an alias first. */ + return alias_diff; + } + + /* Except for aliases, two "identical" instructions had + better have the same opcode. This is a sanity check on the table. */ + i = strcmp (op0->name, op1->name); + if (i) + { + if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */ + return i; + else + fprintf (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), + op0->name, op1->name); + } + + /* Fewer arguments are preferred. */ + { + int length_diff = strlen (op0->args) - strlen (op1->args); + if (length_diff != 0) + /* Put the one with fewer arguments first. */ + return length_diff; + } + + /* Put 1+i before i+1. */ + { + char *p0 = (char *) strchr (op0->args, '+'); + char *p1 = (char *) strchr (op1->args, '+'); + + if (p0 && p1) + { + /* There is a plus in both operands. Note that a plus + sign cannot be the first character in args, + so the following [-1]'s are valid. */ + if (p0[-1] == 'i' && p1[1] == 'i') + /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ + return 1; + if (p0[1] == 'i' && p1[-1] == 'i') + /* op0 is 1+i and op1 is i+1, so op0 goes first. */ + return -1; + } + } + + /* Put 1,i before i,1. */ + { + int i0 = strncmp (op0->args, "i,1", 3) == 0; + int i1 = strncmp (op1->args, "i,1", 3) == 0; + + if (i0 ^ i1) + return i0 - i1; + } + + /* They are, as far as we can tell, identical. + Since qsort may have rearranged the table partially, there is + no way to tell which one was first in the opcode table as + written, so just say there are equal. */ + /* ??? This is no longer true now that we sort a vector of pointers, + not the table itself. */ + return 0; +} + +/* Build a hash table from the opcode table. + OPCODE_TABLE is a sorted list of pointers into the opcode table. */ + +static void +build_hash_table (opcode_table, hash_table, num_opcodes) + const struct sparc_opcode **opcode_table; + struct opcode_hash **hash_table; + int num_opcodes; +{ + register int i; + int hash_count[HASH_SIZE]; + static struct opcode_hash *hash_buf = NULL; + + /* Start at the end of the table and work backwards so that each + chain is sorted. */ + + memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0])); + memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0])); + if (hash_buf != NULL) + free (hash_buf); + hash_buf = (struct opcode_hash *) malloc (sizeof (struct opcode_hash) * num_opcodes); + for (i = num_opcodes - 1; i >= 0; --i) + { + register int hash = HASH_INSN (opcode_table[i]->match); + register struct opcode_hash *h = &hash_buf[i]; + h->next = hash_table[hash]; + h->opcode = opcode_table[i]; + hash_table[hash] = h; + ++hash_count[hash]; + } + +#if 0 /* for debugging */ + { + int min_count = num_opcodes, max_count = 0; + int total; + + for (i = 0; i < HASH_SIZE; ++i) + { + if (hash_count[i] < min_count) + min_count = hash_count[i]; + if (hash_count[i] > max_count) + max_count = hash_count[i]; + total += hash_count[i]; + } + + printf ("Opcode hash table stats: min %d, max %d, ave %f\n", + min_count, max_count, (double) total / HASH_SIZE); + } +#endif +} -- cgit v1.2.3 From 4a585ccb2f45446a127a9f7a5147b033ac02bd5f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:24:18 +0000 Subject: avoid unaligned file offset in anonymous mapping git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@215 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mmap.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 1c3eb35f2..0c2fe8dc1 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -188,7 +188,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, host_start = start & host_page_mask; if (!(flags & MAP_FIXED)) { -#ifdef __alpha__ +#if defined(__alpha__) || defined(__sparc__) /* tell the kenel to search at the same place as i386 */ if (host_start == 0) host_start = 0x40000000; @@ -282,8 +282,13 @@ long target_mmap(unsigned long start, unsigned long len, int prot, /* map the middle (easier) */ if (host_start < host_end) { + unsigned long offset1; + if (flags & MAP_ANONYMOUS) + offset1 = 0; + else + offset1 = offset + host_start - start; ret = (long)mmap((void *)host_start, host_end - host_start, - prot, flags, fd, offset + host_start - start); + prot, flags, fd, offset1); if (ret == -1) return ret; } -- cgit v1.2.3 From 87f4827e1dc49d5d4d26ffca9ef15a33a325c676 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:24:58 +0000 Subject: more code moved to helpers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@216 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 142 +++++++------------------------------------------------------- 1 file changed, 14 insertions(+), 128 deletions(-) diff --git a/op-i386.c b/op-i386.c index 4c7b3804d..e3f26b4e0 100644 --- a/op-i386.c +++ b/op-i386.c @@ -19,8 +19,6 @@ */ #include "exec-i386.h" -/* NOTE: data are not static to force relocation generation by GCC */ - uint8_t parity_table[256] = { CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, @@ -72,44 +70,6 @@ const uint8_t rclb_table[32] = { 6, 7, 8, 0, 1, 2, 3, 4, }; -#ifdef USE_X86LDOUBLE -/* an array of Intel 80-bit FP constants, to be loaded via integer ops */ -typedef unsigned short f15ld[5]; -const f15ld f15rk[] = -{ -/*0*/ {0x0000,0x0000,0x0000,0x0000,0x0000}, -/*1*/ {0x0000,0x0000,0x0000,0x8000,0x3fff}, -/*pi*/ {0xc235,0x2168,0xdaa2,0xc90f,0x4000}, -/*lg2*/ {0xf799,0xfbcf,0x9a84,0x9a20,0x3ffd}, -/*ln2*/ {0x79ac,0xd1cf,0x17f7,0xb172,0x3ffe}, -/*l2e*/ {0xf0bc,0x5c17,0x3b29,0xb8aa,0x3fff}, -/*l2t*/ {0x8afe,0xcd1b,0x784b,0xd49a,0x4000} -}; -#else -/* the same, 64-bit version */ -typedef unsigned short f15ld[4]; -const f15ld f15rk[] = -{ -#ifndef WORDS_BIGENDIAN -/*0*/ {0x0000,0x0000,0x0000,0x0000}, -/*1*/ {0x0000,0x0000,0x0000,0x3ff0}, -/*pi*/ {0x2d18,0x5444,0x21fb,0x4009}, -/*lg2*/ {0x79ff,0x509f,0x4413,0x3fd3}, -/*ln2*/ {0x39ef,0xfefa,0x2e42,0x3fe6}, -/*l2e*/ {0x82fe,0x652b,0x1547,0x3ff7}, -/*l2t*/ {0xa371,0x0979,0x934f,0x400a} -#else -/*0*/ {0x0000,0x0000,0x0000,0x0000}, -/*1*/ {0x3ff0,0x0000,0x0000,0x0000}, -/*pi*/ {0x4009,0x21fb,0x5444,0x2d18}, -/*lg2*/ {0x3fd3,0x4413,0x509f,0x79ff}, -/*ln2*/ {0x3fe6,0x2e42,0xfefa,0x39ef}, -/*l2e*/ {0x3ff7,0x1547,0x652b,0x82fe}, -/*l2t*/ {0x400a,0x934f,0x0979,0xa371} -#endif -}; -#endif - /* n must be a constant to be efficient */ static inline int lshift(int x, int n) { @@ -358,6 +318,7 @@ void OPPROTO op_imull_T0_T1(void) /* division, flags are undefined */ /* XXX: add exceptions for overflow */ + void OPPROTO op_divb_AL_T0(void) { unsigned int num, den, q, r; @@ -420,62 +381,14 @@ void OPPROTO op_idivw_AX_T0(void) EDX = (EDX & 0xffff0000) | r; } -#ifdef BUGGY_GCC_DIV64 -/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we - call it from another function */ -uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) -{ - *q_ptr = num / den; - return num % den; -} - -int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) -{ - *q_ptr = num / den; - return num % den; -} -#endif - void OPPROTO op_divl_EAX_T0(void) { - unsigned int den, q, r; - uint64_t num; - - num = EAX | ((uint64_t)EDX << 32); - den = T0; - if (den == 0) { - EIP = PARAM1; - raise_exception(EXCP00_DIVZ); - } -#ifdef BUGGY_GCC_DIV64 - r = div64(&q, num, den); -#else - q = (num / den); - r = (num % den); -#endif - EAX = q; - EDX = r; + helper_divl_EAX_T0(PARAM1); } void OPPROTO op_idivl_EAX_T0(void) { - int den, q, r; - int64_t num; - - num = EAX | ((uint64_t)EDX << 32); - den = T0; - if (den == 0) { - EIP = PARAM1; - raise_exception(EXCP00_DIVZ); - } -#ifdef BUGGY_GCC_DIV64 - r = idiv64(&q, num, den); -#else - q = (num / den); - r = (num % den); -#endif - EAX = q; - EDX = r; + helper_idivl_EAX_T0(PARAM1); } /* constant load & misc op */ @@ -708,21 +621,7 @@ void OPPROTO op_boundl(void) void OPPROTO op_cmpxchg8b(void) { - uint64_t d; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - d = ldq((uint8_t *)A0); - if (d == (((uint64_t)EDX << 32) | EAX)) { - stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); - eflags |= CC_Z; - } else { - EDX = d >> 32; - EAX = d; - eflags &= ~CC_Z; - } - CC_SRC = eflags; - FORCE_RET(); + helper_cmpxchg8b(); } #if defined(__powerpc__) @@ -937,22 +836,9 @@ void op_addw_ESP_im(void) ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff); } -/* rdtsc */ -#ifndef __i386__ -uint64_t emu_time; -#endif - void OPPROTO op_rdtsc(void) { - uint64_t val; -#ifdef __i386__ - asm("rdtsc" : "=A" (val)); -#else - /* better than nothing: the time increases */ - val = emu_time++; -#endif - EAX = val; - EDX = val >> 32; + helper_rdtsc(); } void OPPROTO op_cpuid(void) @@ -1640,7 +1526,7 @@ void OPPROTO op_fildll_ST0_A0(void) void OPPROTO op_fsts_ST0_A0(void) { #ifdef USE_FP_CONVERT - FP_CONVERT.d = ST0; + FP_CONVERT.f = (float)ST0; stfl((void *)A0, FP_CONVERT.f); #else stfl((void *)A0, (float)ST0); @@ -1904,42 +1790,42 @@ void OPPROTO op_fxam_ST0(void) void OPPROTO op_fld1_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[1]; + ST0 = f15rk[1]; } void OPPROTO op_fldl2t_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[6]; + ST0 = f15rk[6]; } void OPPROTO op_fldl2e_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[5]; + ST0 = f15rk[5]; } void OPPROTO op_fldpi_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[2]; + ST0 = f15rk[2]; } void OPPROTO op_fldlg2_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[3]; + ST0 = f15rk[3]; } void OPPROTO op_fldln2_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[4]; + ST0 = f15rk[4]; } void OPPROTO op_fldz_ST0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[0]; + ST0 = f15rk[0]; } void OPPROTO op_fldz_FT0(void) { - ST0 = *(CPU86_LDouble *)&f15rk[0]; + ST0 = f15rk[0]; } /* associated heplers to reduce generated code length and to simplify -- cgit v1.2.3 From 2d0e9143e2d6fc705cba6c27c221c5c9a7c81a29 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:25:54 +0000 Subject: more code moved to helpers - sipmplified x86 float constants definitions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@217 c046a42c-6fe2-441c-8c8c-71466251a162 --- helper-i386.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/helper-i386.c b/helper-i386.c index 5f3040bf2..293d46af8 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -19,6 +19,62 @@ */ #include "exec-i386.h" +const CPU86_LDouble f15rk[7] = +{ + 0.00000000000000000000L, + 1.00000000000000000000L, + 3.14159265358979323851L, /*pi*/ + 0.30102999566398119523L, /*lg2*/ + 0.69314718055994530943L, /*ln2*/ + 1.44269504088896340739L, /*l2e*/ + 3.32192809488736234781L, /*l2t*/ +}; + +/* thread support */ + +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void cpu_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void cpu_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + +void cpu_loop_exit(void) +{ + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ +#ifdef reg_EAX + env->regs[R_EAX] = EAX; +#endif +#ifdef reg_ECX + env->regs[R_ECX] = ECX; +#endif +#ifdef reg_EDX + env->regs[R_EDX] = EDX; +#endif +#ifdef reg_EBX + env->regs[R_EBX] = EBX; +#endif +#ifdef reg_ESP + env->regs[R_ESP] = ESP; +#endif +#ifdef reg_EBP + env->regs[R_EBP] = EBP; +#endif +#ifdef reg_ESI + env->regs[R_ESI] = ESI; +#endif +#ifdef reg_EDI + env->regs[R_EDI] = EDI; +#endif + longjmp(env->jmp_env, 1); +} + #if 0 /* full interrupt support (only useful for real CPU emulation, not finished) - I won't do it any time soon, finish it if you want ! */ @@ -108,6 +164,82 @@ void raise_exception(int exception_index) raise_interrupt(exception_index, 0, 0, 0); } +#ifdef BUGGY_GCC_DIV64 +/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we + call it from another function */ +uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) +{ + *q_ptr = num / den; + return num % den; +} + +int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) +{ + *q_ptr = num / den; + return num % den; +} +#endif + +void helper_divl_EAX_T0(uint32_t eip) +{ + unsigned int den, q, r; + uint64_t num; + + num = EAX | ((uint64_t)EDX << 32); + den = T0; + if (den == 0) { + EIP = eip; + raise_exception(EXCP00_DIVZ); + } +#ifdef BUGGY_GCC_DIV64 + r = div64(&q, num, den); +#else + q = (num / den); + r = (num % den); +#endif + EAX = q; + EDX = r; +} + +void helper_idivl_EAX_T0(uint32_t eip) +{ + int den, q, r; + int64_t num; + + num = EAX | ((uint64_t)EDX << 32); + den = T0; + if (den == 0) { + EIP = eip; + raise_exception(EXCP00_DIVZ); + } +#ifdef BUGGY_GCC_DIV64 + r = idiv64(&q, num, den); +#else + q = (num / den); + r = (num % den); +#endif + EAX = q; + EDX = r; +} + +void helper_cmpxchg8b(void) +{ + uint64_t d; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + d = ldq((uint8_t *)A0); + if (d == (((uint64_t)EDX << 32) | EAX)) { + stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); + eflags |= CC_Z; + } else { + EDX = d >> 32; + EAX = d; + eflags &= ~CC_Z; + } + CC_SRC = eflags; +} + /* We simulate a pre-MMX pentium as in valgrind */ #define CPUID_FP87 (1 << 0) #define CPUID_VME (1 << 1) @@ -221,6 +353,24 @@ void load_seg(int seg_reg, int selector, unsigned cur_eip) env->segs[seg_reg] = selector; } +/* rdtsc */ +#ifndef __i386__ +uint64_t emu_time; +#endif + +void helper_rdtsc(void) +{ + uint64_t val; +#ifdef __i386__ + asm("rdtsc" : "=A" (val)); +#else + /* better than nothing: the time increases */ + val = emu_time++; +#endif + EAX = val; + EDX = val >> 32; +} + void helper_lsl(void) { unsigned int selector, limit; -- cgit v1.2.3 From 8c6939c0b010003cd3e66a240c3d5867ebd8044e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:28:00 +0000 Subject: arm support - modified sparc to work with direct chaining git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@218 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.c | 134 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 78 insertions(+), 56 deletions(-) diff --git a/exec-i386.c b/exec-i386.c index 5bd69d4a5..c285eb450 100644 --- a/exec-i386.c +++ b/exec-i386.c @@ -25,58 +25,6 @@ /* main execution loop */ -/* thread support */ - -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; - -void cpu_lock(void) -{ - spin_lock(&global_cpu_lock); -} - -void cpu_unlock(void) -{ - spin_unlock(&global_cpu_lock); -} - -void cpu_loop_exit(void) -{ - /* NOTE: the register at this point must be saved by hand because - longjmp restore them */ -#ifdef __sparc__ - /* We have to stay in the same register window as our caller, - * thus this trick. - */ - __asm__ __volatile__("restore\n\t" - "mov\t%o0, %i0"); -#endif -#ifdef reg_EAX - env->regs[R_EAX] = EAX; -#endif -#ifdef reg_ECX - env->regs[R_ECX] = ECX; -#endif -#ifdef reg_EDX - env->regs[R_EDX] = EDX; -#endif -#ifdef reg_EBX - env->regs[R_EBX] = EBX; -#endif -#ifdef reg_ESP - env->regs[R_ESP] = ESP; -#endif -#ifdef reg_EBP - env->regs[R_EBP] = EBP; -#endif -#ifdef reg_ESI - env->regs[R_ESI] = ESI; -#endif -#ifdef reg_EDI - env->regs[R_EDI] = EDI; -#endif - longjmp(env->jmp_env, 1); -} - int cpu_x86_exec(CPUX86State *env1) { int saved_T0, saved_T1, saved_A0; @@ -104,13 +52,16 @@ int cpu_x86_exec(CPUX86State *env1) #endif #ifdef reg_EDI int saved_EDI; +#endif +#ifdef __sparc__ + int saved_i7, tmp_T0; #endif int code_gen_size, ret; void (*gen_func)(void); TranslationBlock *tb, **ptb; uint8_t *tc_ptr, *cs_base, *pc; unsigned int flags; - + /* first we save global registers */ saved_T0 = T0; saved_T1 = T1; @@ -149,6 +100,10 @@ int cpu_x86_exec(CPUX86State *env1) saved_EDI = EDI; EDI = env->regs[R_EDI]; #endif +#ifdef __sparc__ + /* we also save i7 because longjmp may not restore it */ + asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); +#endif /* put eflags in CPU temporary format */ CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); @@ -161,6 +116,10 @@ int cpu_x86_exec(CPUX86State *env1) if (setjmp(env->jmp_env) == 0) { T0 = 0; /* force lookup of first TB */ for(;;) { +#ifdef __sparc__ + /* g1 can be modified by some libc? functions */ + tmp_T0 = T0; +#endif if (env->interrupt_request) { env->exception_index = EXCP_INTERRUPT; cpu_loop_exit(); @@ -240,23 +199,32 @@ int cpu_x86_exec(CPUX86State *env1) lookup_symbol((void *)tb->pc)); } #endif +#ifdef __sparc__ + T0 = tmp_T0; +#endif /* see if we can patch the calling TB */ if (T0 != 0 && !(env->eflags & TF_MASK)) { spin_lock(&tb_lock); tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); spin_unlock(&tb_lock); } - tc_ptr = tb->tc_ptr; /* execute the generated code */ gen_func = (void *)tc_ptr; -#ifdef __sparc__ +#if defined(__sparc__) __asm__ __volatile__("call %0\n\t" - " mov %%o7,%%i0" + "mov %%o7,%%i0" : /* no outputs */ : "r" (gen_func) : "i0", "i1", "i2", "i3", "i4", "i5"); +#elif defined(__arm__) + asm volatile ("mov pc, %0\n\t" + ".global exec_loop\n\t" + "exec_loop:\n\t" + : /* no outputs */ + : "r" (gen_func) + : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); #else gen_func(); #endif @@ -291,6 +259,9 @@ int cpu_x86_exec(CPUX86State *env1) #endif #ifdef reg_EDI EDI = saved_EDI; +#endif +#ifdef __sparc__ + asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); #endif T0 = saved_T0; T1 = saved_T1; @@ -457,6 +428,7 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 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 @@ -475,6 +447,56 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, &uc->uc_sigmask); } +#elif defined(__sparc__) + +int cpu_x86_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + uint32_t *regs = (uint32_t *)(info + 1); + void *sigmask = (regs + 20); + unsigned long pc; + int is_write; + uint32_t insn; + + /* XXX: is there a standard glibc define ? */ + pc = regs[1]; + /* XXX: need kernel patch to get write flag faster */ + is_write = 0; + insn = *(uint32_t *)pc; + if ((insn >> 30) == 3) { + switch((insn >> 19) & 0x3f) { + case 0x05: // stb + case 0x06: // sth + case 0x04: // st + case 0x07: // std + case 0x24: // stf + case 0x27: // stdf + case 0x25: // stfsr + is_write = 1; + break; + } + } + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, sigmask); +} + +#elif defined(__arm__) + +int cpu_x86_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.gregs[R15]; + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask); +} + #else #error CPU specific signal handler needed -- cgit v1.2.3 From e163bca720425289b812e5e2c049e6139608c2ea Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:28:45 +0000 Subject: weird arm double format support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@219 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.h | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/exec-i386.h b/exec-i386.h index d89a318cc..4232973f0 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -243,11 +243,14 @@ void raise_interrupt(int intno, int is_int, int error_code, unsigned int next_eip); void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); +void helper_divl_EAX_T0(uint32_t eip); +void helper_idivl_EAX_T0(uint32_t eip); +void helper_cmpxchg8b(void); void helper_cpuid(void); +void helper_rdtsc(void); void helper_lsl(void); void helper_lar(void); - #ifdef USE_X86LDOUBLE /* use long double functions */ #define lrint lrintl @@ -287,6 +290,13 @@ extern CPU86_LDouble rint(CPU86_LDouble x); #define MAXTAN 9223372036854775808.0 +#ifdef __arm__ +/* we have no way to do correct rounding - a FPU emulator is needed */ +#define FE_DOWNWARD FE_TONEAREST +#define FE_UPWARD FE_TONEAREST +#define FE_TOWARDZERO FE_TONEAREST +#endif + #ifdef USE_X86LDOUBLE /* only for x86 */ @@ -308,9 +318,10 @@ typedef union { #else +/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ typedef union { double d; -#ifndef WORDS_BIGENDIAN +#if !defined(WORDS_BIGENDIAN) && !defined(__arm__) struct { uint32_t lower; int32_t upper; @@ -321,7 +332,9 @@ typedef union { uint32_t lower; } l; #endif +#ifndef __arm__ int64_t ll; +#endif } CPU86_LDoubleU; /* the following deal with IEEE double-precision numbers */ @@ -329,7 +342,11 @@ typedef union { #define EXPBIAS 1023 #define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) #define SIGND(fp) ((fp.l.upper) & 0x80000000) +#ifdef __arm__ +#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32)) +#else #define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) +#endif #define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) #endif @@ -350,12 +367,20 @@ static inline CPU86_LDouble helper_fldt(uint8_t *ptr) { CPU86_LDoubleU temp; int upper, e; + uint64_t ll; + /* mantissa */ upper = lduw(ptr + 8); /* XXX: handle overflow ? */ e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ e |= (upper >> 4) & 0x800; /* sign */ - temp.ll = ((ldq(ptr) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); + ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1); +#ifdef __arm__ + temp.l.upper = (e << 20) | (ll >> 32); + temp.l.lower = ll; +#else + temp.ll = ll | ((uint64_t)e << 52); +#endif return temp.d; } @@ -363,6 +388,7 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) { CPU86_LDoubleU temp; int e; + temp.d = f; /* mantissa */ stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); @@ -373,6 +399,8 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) } #endif +const CPU86_LDouble f15rk[7]; + void helper_fldt_ST0_A0(void); void helper_fstt_ST0_A0(void); void helper_fbld_ST0_A0(void); -- cgit v1.2.3 From 0f533160c7f7ccd1ae421d5bce3850a1a5400bc1 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:29:20 +0000 Subject: removed unused code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@220 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5186e5562..2afde77a8 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -17,13 +17,6 @@ #define ELF_START_MMAP 0x80000000 -typedef uint32_t elf_greg_t; - -#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t)) -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -typedef struct user_i387_struct elf_fpregset_t; - /* * This is used to ensure we don't load something for the wrong architecture. */ @@ -758,7 +751,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r } /* Now read in all of the header information */ - elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); if (elf_phdata == NULL) { return -ENOMEM; -- cgit v1.2.3 From a95c67907cce5b03269581b77f014ec51b98da36 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:29:55 +0000 Subject: arm support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@221 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 46 ++++++++++++++++++++++++++++++++++++++-------- exec.h | 12 ++++++++++++ translate-i386.c | 11 +++++++++++ 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index d277144b6..8d7e1d612 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -238,7 +238,10 @@ static inline void stb(void *ptr, int v) *(uint8_t *)ptr = v; } -#ifdef WORDS_BIGENDIAN +/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the + kernel handles unaligned load/stores may give better results, but + it is a system wide setting : bad */ +#if defined(WORDS_BIGENDIAN) || defined(__arm__) /* conservative code for little endian unaligned accesses */ static inline int lduw(void *ptr) @@ -329,24 +332,50 @@ static inline float ldfl(void *ptr) return u.f; } +static inline void stfl(void *ptr, float v) +{ + union { + float f; + uint32_t i; + } u; + u.f = v; + stl(ptr, u.i); +} + +#if defined(__arm__) && !defined(WORDS_BIGENDIAN) + +/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ static inline double ldfq(void *ptr) { union { double d; - uint64_t i; + uint32_t tab[2]; } u; - u.i = ldq(ptr); + u.tab[1] = ldl(ptr); + u.tab[0] = ldl(ptr + 4); return u.d; } -static inline void stfl(void *ptr, float v) +static inline void stfq(void *ptr, double v) { union { - float f; - uint32_t i; + double d; + uint32_t tab[2]; } u; - u.f = v; - stl(ptr, u.i); + u.d = v; + stl(ptr, u.tab[1]); + stl(ptr + 4, u.tab[0]); +} + +#else +static inline double ldfq(void *ptr) +{ + union { + double d; + uint64_t i; + } u; + u.i = ldq(ptr); + return u.d; } static inline void stfq(void *ptr, double v) @@ -358,6 +387,7 @@ static inline void stfq(void *ptr, double v) u.d = v; stq(ptr, u.i); } +#endif #else diff --git a/exec.h b/exec.h index d8fc640b6..b6ba66364 100644 --- a/exec.h +++ b/exec.h @@ -246,6 +246,18 @@ static inline int testandset (int *p) } #endif +#ifdef __arm__ +static inline int testandset (int *spinlock) +{ + register unsigned int ret; + __asm__ __volatile__("swp %0, %1, [%2]" + : "=r"(ret) + : "0"(1), "r"(spinlock)); + + return ret; +} +#endif + typedef int spinlock_t; #define SPIN_LOCK_UNLOCKED 0 diff --git a/translate-i386.c b/translate-i386.c index 3802c5e92..c7d34b60a 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -104,6 +104,16 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) #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 + extern FILE *logfile; extern int loglevel; @@ -166,6 +176,7 @@ enum { NB_OPS, }; +#include "dyngen.h" #include "op-i386.h" /* operand size */ -- cgit v1.2.3 From d30329297bf76338326edd8ee39342d0fd37d0df Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:30:37 +0000 Subject: removed unused dependancy if non x86 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@222 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 5f6479e20..4b58c197e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -35,9 +35,11 @@ test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \ test-i386-code16.S test-i386-vm86.S -lm -test: test-i386 ifeq ($(ARCH),i386) +test: test-i386 ./test-i386 > test-i386.ref +else +test: endif $(QEMU) test-i386 > test-i386.out @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi -- cgit v1.2.3 From 8dd7cb06218b7962258f25114ac627c05b71d951 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:31:02 +0000 Subject: moved to disas.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@223 c046a42c-6fe2-441c-8c8c-71466251a162 --- alpha-dis.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/alpha-dis.c b/alpha-dis.c index ebda048e7..e7a4fb402 100644 --- a/alpha-dis.c +++ b/alpha-dis.c @@ -248,19 +248,6 @@ enum bfd_reloc_code_real { BFD_RELOC_ALPHA_HINT }; -bfd_vma -bfd_getl32 (addr) - register 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; -} - /* 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 -- cgit v1.2.3 From 9c5d1246c7b3da2e625a2257b9680c4d34fbc1fc Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:33:05 +0000 Subject: use -mflat for helper-i386.c on sparc - use custom ld script on sparc to free zero memory addresses for vm86 emulation - arm support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@224 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 1da34c636..53f8f1be8 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ CFLAGS=-Wall -O2 -g LDFLAGS=-g LIBS= DEFINES=-DHAVE_BYTESWAP_H +HELPER_CFLAGS=$(CFLAGS) ifeq ($(ARCH),i386) CFLAGS+=-fomit-frame-pointer @@ -37,6 +38,8 @@ ifeq ($(ARCH),sparc) CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 LDFLAGS+=-m32 OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 +HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat +LDFLAGS+=-Wl,-T,sparc.ld endif ifeq ($(ARCH),sparc64) @@ -58,6 +61,11 @@ ifeq ($(ARCH),ia64) OP_CFLAGS=$(CFLAGS) endif +ifeq ($(ARCH),arm) +OP_CFLAGS=$(CFLAGS) -mno-sched-prolog +LDFLAGS+=-Wl,-T,arm.ld +endif + ifeq ($(GCC_MAJOR),3) # very important to generate a return at the end of every operation OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls @@ -81,13 +89,19 @@ OBJS+= libqemu.a LIBOBJS+=thunk.o translate-i386.o op-i386.o helper-i386.o exec-i386.o exec.o # NOTE: the disassembler code is only needed for debugging -LIBOBJS+=disas.o i386-dis.o dis-buf.o +LIBOBJS+=disas.o i386-dis.o ifeq ($(ARCH),alpha) LIBOBJS+=alpha-dis.o endif ifeq ($(ARCH),ppc) LIBOBJS+=ppc-dis.o endif +ifeq ($(ARCH),sparc) +LIBOBJS+=sparc-dis.o +endif +ifeq ($(ARCH),arm) +LIBOBJS+=arm-dis.o +endif ifeq ($(ARCH),ia64) OBJS += ia64-syscall.o @@ -126,6 +140,9 @@ opc-i386.h: op-i386.o dyngen op-i386.o: op-i386.c opreg_template.h ops_template.h $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $< +helper-i386.o: helper-i386.c + $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< @@ -152,13 +169,13 @@ qemu-doc.html: qemu-doc.texi FILES= \ README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ -dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\ +dyngen.c dyngen.h ioctls.h ops_template.h op_string.h syscall_types.h\ Makefile elf.h thunk.c\ elfload.c main.c signal.c thunk.h exec.h\ cpu-i386.h qemu.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c\ syscall.c opreg_template.h syscall_defs.h vm86.c\ -dis-asm.h dis-buf.c disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c\ -ppc.ld alpha.ld s390.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \ +dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c arm-dis.c\ +ppc.ld alpha.ld s390.ld sparc.ld arm.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \ tests/Makefile\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386-muldiv.h tests/test-i386-code16.S\ -- cgit v1.2.3 From ff1f20a3ee3fe484bcf5147a124c4e4e878907ba Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:34:19 +0000 Subject: arm support - suppressed possibly unsafe sparc nop deletion git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@225 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ dyngen.h | 122 ++++++++++++++++++++++++++++++++++++ 2 files changed, 316 insertions(+), 20 deletions(-) create mode 100644 dyngen.h diff --git a/dyngen.c b/dyngen.c index d5b00a159..de32756e6 100644 --- a/dyngen.c +++ b/dyngen.c @@ -79,6 +79,13 @@ #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 + #else #error unsupported CPU - please update the code #endif @@ -301,6 +308,106 @@ int strstart(const char *str, const char *val, const char **ptr) return 1; } +#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; + uint8_t data_allocated[1024]; + unsigned int data_index; + + memset(data_allocated, 0, sizeof(data_allocated)); + + p = p_start; + min_offset = p_end - p_start; + while (p < p_start + min_offset) { + insn = get32((uint32_t *)p); + if ((insn & 0x0d5f0000) == 0x051f0000) { + /* ldr reg, [pc, #im] */ + offset = insn & 0xfff; + if (!(insn & 0x00800000)) + offset = -offset; + if ((offset & 3) !=0) + error("%s:%04x: ldr pc offset must be 32 bit aligned", + 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: ldr 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) { + /* ldr position */ + fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", + p - p_start); + /* ldr data index */ + data_index = ((p_end - p_start) - pc_offset - 4) >> 2; + fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", + data_index); + fprintf(outfile, " arm_ldr_ptr++;\n"); + if (data_index >= sizeof(data_allocated)) + error("%s: too many data", name); + if (!data_allocated[data_index]) { + ELF_RELOC *rel; + int i, addend, type; + const char *sym_name, *p; + char relname[1024]; + + data_allocated[data_index] = 1; + + /* 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 = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + /* the compiler leave some unnecessary references to the code */ + if (strstart(sym_name, "__op_param", &p)) { + snprintf(relname, sizeof(relname), "param%s", p); + } else { + snprintf(relname, sizeof(relname), "(long)(&%s)", 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"); + } + } + } + p += 4; + } + data_size = (p_end - p_start) - min_offset; + if (data_size > 0 && outfile) { + fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2); + } + + /* the last instruction must be a mov pc, lr */ + if (p == p_start) + goto arm_ret_error; + p -= 4; + insn = get32((uint32_t *)p); + if ((insn & 0xffff0000) != 0xe91b0000) { + arm_ret_error: + if (!outfile) + printf("%s: invalid epilog\n", name); + } + return p - p_start; +} +#endif + + #define MAX_ARGS 3 /* generate op code */ @@ -388,7 +495,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, case EM_SPARC: case EM_SPARC32PLUS: { - uint32_t start_insn, end_insn1, end_insn2, skip_insn; + uint32_t start_insn, end_insn1, end_insn2; uint8_t *p; p = (void *)(p_end - 8); if (p <= p_start) @@ -406,14 +513,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } 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 == 0x01000000) p -= 4; } - +#endif copy_size = p - p_start; } break; @@ -448,6 +555,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, copy_size = p - p_start; } break; +#ifdef HOST_ARM + case EM_ARM: + 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; + copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, + relocs, nb_relocs); + break; +#endif default: error("unknown ELF architecture"); } @@ -458,7 +579,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && - rel->r_offset < start_offset + copy_size) { + rel->r_offset < start_offset + (p_end - p_start)) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (strstart(sym_name, "__op_param", &p)) { n = strtoul(p, NULL, 10); @@ -496,7 +617,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && - rel->r_offset < start_offset + copy_size) { + rel->r_offset < start_offset + (p_end - p_start)) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; if (*sym_name && !strstart(sym_name, "__op_param", NULL) && @@ -900,6 +1021,44 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#elif defined(HOST_ARM) + { + char name[256]; + int type; + int addend; + + 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; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = get32((uint32_t *)(text + rel->r_offset)); + switch(type) { + case R_ARM_ABS32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_ARM_PC24: + fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", + rel->r_offset - start_offset, addend, name); + break; + default: + error("unsupported arm relocation (%d)", type); + } + } + } + } #else #error unsupported CPU #endif @@ -1075,23 +1234,22 @@ fprintf(outfile, "{\n" " uint8_t *gen_code_ptr;\n" " const uint16_t *opc_ptr;\n" -" const uint32_t *opparam_ptr;\n" +" const uint32_t *opparam_ptr;\n"); + +#ifdef HOST_ARM +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;\n"); +#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. */ - switch(ELF_ARCH) { - case EM_SPARC: - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n"); - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n"); - break; - - case EM_SPARCV9: - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n"); - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n"); - break; - }; fprintf(outfile, " for(;;) {\n" @@ -1116,7 +1274,21 @@ fprintf(outfile, fprintf(outfile, " default:\n" " goto the_end;\n" -" }\n" +" }\n"); + +#ifdef HOST_ARM +/* generate constant table if needed */ +fprintf(outfile, +" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n" +" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n" +" last_gen_code_ptr = gen_code_ptr;\n" +" arm_ldr_ptr = arm_ldr_table;\n" +" arm_data_ptr = arm_data_table;\n" +" }\n"); +#endif + + +fprintf(outfile, " }\n" " the_end:\n" ); @@ -1140,14 +1312,16 @@ fprintf(outfile, break; case EM_SPARC: case EM_SPARC32PLUS: - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n"); fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n"); - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\n"); + fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x01000000; /* nop */\n"); break; case EM_SPARCV9: fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n"); fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n"); break; + case EM_ARM: + fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n"); + break; default: error("unknown ELF architecture"); } diff --git a/dyngen.h b/dyngen.h new file mode 100644 index 000000000..cafa4f5a3 --- /dev/null +++ b/dyngen.h @@ -0,0 +1,122 @@ +/* + * 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 + */ + +#ifdef __alpha__ + +register int gp asm("$29"); + +static inline void immediate_ldah(void *p, int val) { + uint32_t *dest = p; + long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff; + + *dest &= ~0xffff; + *dest |= high; + *dest |= 31 << 16; +} +static inline void immediate_lda(void *dest, int val) { + *(uint16_t *) dest = val; +} +void fix_bsr(void *p, int offset) { + uint32_t *dest = p; + *dest &= ~((1 << 21) - 1); + *dest |= (offset >> 2) & ((1 << 21) - 1); +} + +#endif /* __alpha__ */ + +#ifdef __arm__ + +#define MAX_OP_SIZE (128 * 4) /* in bytes */ +/* max size of the code that can be generated without calling arm_flush_ldr */ +#define MAX_FRAG_SIZE (1024 * 4) +//#define MAX_FRAG_SIZE (135 * 4) /* for testing */ + +typedef struct LDREntry { + uint8_t *ptr; + uint32_t *data_ptr; +} LDREntry; + +static LDREntry arm_ldr_table[1024]; +static uint32_t arm_data_table[1024]; + +extern char exec_loop; + +static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val) +{ + *ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff); +} + +static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, + LDREntry *ldr_start, LDREntry *ldr_end, + uint32_t *data_start, uint32_t *data_end, + int gen_jmp) +{ + LDREntry *le; + uint32_t *ptr; + int offset, data_size, target; + uint8_t *data_ptr; + uint32_t insn; + + data_size = (uint8_t *)data_end - (uint8_t *)data_start; + + if (!gen_jmp) { + /* b exec_loop */ + arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, (long)(&exec_loop)); + gen_code_ptr += 4; + } else { + /* generate branch to skip the data */ + if (data_size == 0) + return gen_code_ptr; + target = (long)gen_code_ptr + data_size + 4; + arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target); + gen_code_ptr += 4; + } + + /* copy the data */ + data_ptr = gen_code_ptr; + memcpy(gen_code_ptr, data_start, data_size); + gen_code_ptr += data_size; + + /* patch the ldr to point to the data */ + for(le = ldr_start; le < ldr_end; le++) { + ptr = (uint32_t *)le->ptr; + offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + + (unsigned long)data_ptr - + (unsigned long)ptr - 8; + insn = *ptr & ~(0xfff | 0x00800000); + if (offset < 0) { + offset = - offset; + } else { + insn |= 0x00800000; + } + if (offset > 0xfff) { + fprintf(stderr, "Error ldr offset\n"); + abort(); + } + insn |= offset; + *ptr = insn; + } + return gen_code_ptr; +} + +#endif /* __arm__ */ + + + -- cgit v1.2.3 From 411bffc41cad1298637b67eaa532b22a7b0099cf Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 15:38:23 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@226 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 5 +++++ README | 12 +++++++++--- TODO | 9 ++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Changelog b/Changelog index 567997d42..013555e84 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,8 @@ +version 0.3: + - added fnsave, frstor, fnstenv, fldenv FPU instructions + - added FPU register save in signal emulation + - ARM port + version 0.2: - PowerPC disassembly and ELF symbols output (Rusty Russel) diff --git a/README b/README index a70af3cfb..76c4df032 100644 --- a/README +++ b/README @@ -43,7 +43,7 @@ In order to compile QEMU succesfully, it is very important that you have the right tools. The most important one is gcc. I cannot guaranty that QEMU works if you do not use a tested gcc version. Look at 'configure' and 'Makefile' if you want to make a different gcc -version. +version work. host gcc binutils glibc linux ------------------------------------------------------- @@ -51,10 +51,16 @@ x86 2.95.2 2.13.2 2.1.3 2.4.18 PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 -Alpha 3.3 [1] 2.14.90.0.4 2.2.5 xxx +Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] +Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 -[1] QEMU cannot work for gcc version < 3.3 on Alpha. +ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9-ac10-rmk2-np1-cerf2 + +[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available + for gcc version >= 3.3. +[2] Linux >= 2.4.20 is necessary for precise exception support + (untested). Documentation ------------- diff --git a/TODO b/TODO index 85cdba755..93c1ec207 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,18 @@ -- fix iret/lret/fpush not before mem load restarting +- fix arm fpu rounding (at least for float->integer conversions) +- fix CCOP optimisation +- optimize FPU operations (evaluate x87 stack pointer statically) +- fpush not before mem load restarting - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). -- handle fp87 state in signals - add gcc 2.96 test configure (some gcc3 flags are needed) -- optimize FPU operations (evaluate x87 stack pointer statically) - add IPC syscalls - submit a patch to fix DOSEMU coopthreads lower priority: -------------- +- use -msoft-float on ARM +- use kernel traps for unaligned accesses on ARM ? - handle rare page fault cases (in particular if page fault in heplers or in syscall emulation code). - fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID) -- cgit v1.2.3 From 5bbe92995c0bc63eeb45a7bf44eadb051df4aada Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 19:38:38 +0000 Subject: disas endian fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@227 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 1 + 1 file changed, 1 insertion(+) diff --git a/disas.c b/disas.c index 97c4a23a3..2a8a533b0 100644 --- a/disas.c +++ b/disas.c @@ -1,4 +1,5 @@ /* General "disassemble this chunk" code. Used for debugging. */ +#include "config.h" #include "dis-asm.h" #include "disas.h" #include "elf.h" -- cgit v1.2.3 From ebc06f87cac28301bf30e8d23a069691a8db3635 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 19:46:12 +0000 Subject: alpha fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@228 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/dyngen.c b/dyngen.c index de32756e6..c2f9d120e 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1207,26 +1207,6 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) } } else { /* generate big code generation switch */ -#ifdef HOST_ALPHA -fprintf(outfile, -"register int gp asm(\"$29\");\n" -"static inline void immediate_ldah(void *p, int val) {\n" -" uint32_t *dest = p;\n" -" long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;\n" -"\n" -" *dest &= ~0xffff;\n" -" *dest |= high;\n" -" *dest |= 31 << 16;\n" -"}\n" -"static inline void immediate_lda(void *dest, int val) {\n" -" *(uint16_t *) dest = val;\n" -"}\n" -"void fix_bsr(void *p, int offset) {\n" -" uint32_t *dest = p;\n" -" *dest &= ~((1 << 21) - 1);\n" -" *dest |= (offset >> 2) & ((1 << 21) - 1);\n" -"}\n"); -#endif fprintf(outfile, "int dyngen_code(uint8_t *gen_code_buf,\n" " uint16_t *label_offsets, uint16_t *jmp_offsets,\n" -- cgit v1.2.3 From 43ce4dfe9efd48694cc7e9312f4e845304b2e532 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 9 Jun 2003 19:53:12 +0000 Subject: added static build option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@229 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++++ configure | 25 +++++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 53f8f1be8..12cba2927 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,10 @@ LIBS= DEFINES=-DHAVE_BYTESWAP_H HELPER_CFLAGS=$(CFLAGS) +ifdef CONFIG_STATIC +LDFLAGS+=-static +endif + ifeq ($(ARCH),i386) CFLAGS+=-fomit-frame-pointer OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2 diff --git a/configure b/configure index 60256215b..9a7a5f908 100755 --- a/configure +++ b/configure @@ -20,6 +20,7 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h" # default parameters prefix="/usr/local" interp_prefix="/usr/gnemul/qemu-i386" +static="no" cross_prefix="" cc="gcc" host_cc="gcc" @@ -104,6 +105,8 @@ for opt do ;; --enable-gprof) gprof="yes" ;; + --static) static="yes" + ;; esac done @@ -176,19 +179,22 @@ echo " --source-path=PATH path of source code [$source_path]" echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" echo " --cc=CC use C compiler CC [$cc]" echo " --make=MAKE use specified make [$make]" +echo " --static enable static build [$static]" echo "" echo "NOTE: The object files are build at the place where configure is launched" exit 1 fi -echo "Install prefix $prefix" -echo "Source path $source_path" -echo "C compiler $cc" -echo "make $make" -echo "host CPU $cpu" -echo "Big Endian $bigendian" -echo "target CPU $target_cpu" -echo "gprof enabled $gprof" +echo "Install prefix $prefix" +echo "Source path $source_path" +echo "ELF interp prefix $interp_prefix" +echo "C compiler $cc" +echo "make $make" +echo "host CPU $cpu" +echo "Big Endian $bigendian" +echo "target CPU $target_cpu" +echo "gprof enabled $gprof" +echo "static build $static" echo "Creating config.mak and config.h" @@ -244,6 +250,9 @@ if test "$gprof" = "yes" ; then echo "TARGET_GPROF=yes" >> config.mak echo "#define HAVE_GPROF 1" >> $TMPH fi +if test "$static" = "yes" ; then + echo "CONFIG_STATIC=yes" >> config.mak +fi echo -n "VERSION=" >>config.mak head $source_path/VERSION >>config.mak echo "" >>config.mak -- cgit v1.2.3 From ea76864009c3d7458b466123ae7cf10daafde53b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:36:33 +0000 Subject: more precise float rounding tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@230 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 56dc6af93..c2c332394 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -527,6 +527,12 @@ void test_fcvt(double a) { float fa; long double la; + int16_t fpuc; + int i; + int64_t lla; + int ia; + int16_t wa; + double ra; fa = a; la = a; @@ -535,9 +541,21 @@ void test_fcvt(double a) printf("a=%016Lx\n", *(long long *)&a); printf("la=%016Lx %04x\n", *(long long *)&la, *(unsigned short *)((char *)(&la) + 8)); - printf("a=%f floor(a)=%f\n", a, floor(a)); - printf("a=%f ceil(a)=%f\n", a, ceil(a)); - printf("a=%f rint(a)=%f\n", a, rint(a)); + + /* test all roundings */ + asm volatile ("fstcw %0" : "=m" (fpuc)); + for(i=0;i<4;i++) { + asm volatile ("fldcw %0" : : "m" ((fpuc & ~0x0c00) | (i << 10))); + asm volatile ("fist %0" : "=m" (wa) : "t" (a)); + asm volatile ("fistl %0" : "=m" (ia) : "t" (a)); + asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st"); + asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a)); + asm volatile ("fldcw %0" : : "m" (fpuc)); + printf("(short)a = %d\n", wa); + printf("(int)a = %d\n", ia); + printf("(int64_t)a = %Ld\n", lla); + printf("rint(a) = %f\n", ra); + } } #define TEST(N) \ @@ -625,9 +643,12 @@ void test_floats(void) test_fcmp(2, -1); test_fcmp(2, 2); test_fcmp(2, 3); + test_fcvt(0.5); + test_fcvt(-0.5); test_fcvt(1.0/7.0); test_fcvt(-1.0/9.0); - test_fcvt(1e30); + test_fcvt(32768); + test_fcvt(-1e20); test_fconst(); test_fbcd(1234567890123456); test_fbcd(-123451234567890); -- cgit v1.2.3 From 394411ac7442f6c3803b7f60379697b750b2ab3f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:37:07 +0000 Subject: added hello world for ARM git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@231 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/.cvsignore | 1 + tests/Makefile | 7 ++++ tests/hello-arm.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 tests/hello-arm.c diff --git a/tests/.cvsignore b/tests/.cvsignore index b70d47bd6..5e5781e20 100644 --- a/tests/.cvsignore +++ b/tests/.cvsignore @@ -1,6 +1,7 @@ gmon.out testsig hello + hello-arm sha1.test.c sha1.c test-i386 diff --git a/tests/Makefile b/tests/Makefile index 4b58c197e..364e39730 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -59,5 +59,12 @@ speed: sha1 sha1-i386 runcom: runcom.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< +# arm test +hello-arm: hello-arm.o + arm-linux-ld -o $@ $< + +hello-arm.o: hello-arm.c + arm-linux-gcc -Wall -g -O2 -c -o $@ $< + clean: rm -f *~ *.o $(TESTS) diff --git a/tests/hello-arm.c b/tests/hello-arm.c new file mode 100644 index 000000000..f84e6cb36 --- /dev/null +++ b/tests/hello-arm.c @@ -0,0 +1,113 @@ +#define __NR_SYSCALL_BASE 0x900000 +#define __NR_exit1 (__NR_SYSCALL_BASE+ 1) +#define __NR_write (__NR_SYSCALL_BASE+ 4) + +#define __sys2(x) #x +#define __sys1(x) __sys2(x) + +#ifndef __syscall +#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t" +#endif + +#define __syscall_return(type, res) \ +do { \ + return (type) (res); \ +} while (0) + +#define _syscall0(type,name) \ +type name(void) { \ + long __res; \ + __asm__ __volatile__ ( \ + __syscall(name) \ + "mov %0,r0" \ + :"=r" (__res) : : "r0","lr"); \ + __syscall_return(type,__res); \ +} + +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + __syscall(name) \ + "mov %0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)) \ + : "r0","lr"); \ + __syscall_return(type,__res); \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + "mov\tr1,%2\n\t" \ + __syscall(name) \ + "mov\t%0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)),"r" ((long)(arg2)) \ + : "r0","r1","lr"); \ + __syscall_return(type,__res); \ +} + + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2,type3 arg3) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + "mov\tr1,%2\n\t" \ + "mov\tr2,%3\n\t" \ + __syscall(name) \ + "mov\t%0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)) \ + : "r0","r1","r2","lr"); \ + __syscall_return(type,__res); \ +} + + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + "mov\tr1,%2\n\t" \ + "mov\tr2,%3\n\t" \ + "mov\tr3,%4\n\t" \ + __syscall(name) \ + "mov\t%0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \ + : "r0","r1","r2","r3","lr"); \ + __syscall_return(type,__res); \ +} + + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + "mov\tr1,%2\n\t" \ + "mov\tr2,%3\n\t" \ + "mov\tr3,%4\n\t" \ + "mov\tr4,%5\n\t" \ + __syscall(name) \ + "mov\t%0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \ + "r" ((long)(arg5)) \ + : "r0","r1","r2","r3","r4","lr"); \ + __syscall_return(type,__res); \ +} + +_syscall1(int,exit1,int,status); +_syscall3(int,write,int,fd,const char *,buf, int, len); + +void _start(void) +{ + write(1, "Hello World\n", 12); + exit1(0); +} -- cgit v1.2.3 From 5898e816840dd7cb2492c4cce85525e7383f8def Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:42:24 +0000 Subject: ARM emulation support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@232 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-arm.h | 64 +++++ exec-arm.h | 32 +++ op-arm-template.h | 48 ++++ op-arm.c | 665 +++++++++++++++++++++++++++++++++++++++++++++++ syscall-arm.h | 27 ++ translate-arm.c | 750 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1586 insertions(+) create mode 100644 cpu-arm.h create mode 100644 exec-arm.h create mode 100644 op-arm-template.h create mode 100644 op-arm.c create mode 100644 syscall-arm.h create mode 100644 translate-arm.c diff --git a/cpu-arm.h b/cpu-arm.h new file mode 100644 index 000000000..c3850eb40 --- /dev/null +++ b/cpu-arm.h @@ -0,0 +1,64 @@ +/* + * ARM virtual CPU header + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef CPU_ARM_H +#define CPU_ARM_H + +#include "config.h" +#include + +#define EXCP_UDEF 1 /* undefined instruction */ +#define EXCP_SWI 2 /* software interrupt */ +#define EXCP_INTERRUPT 256 /* async interruption */ + +typedef struct CPUARMState { + uint32_t regs[16]; + uint32_t cpsr; + + /* cpsr flag cache for faster execution */ + uint32_t CF; /* 0 or 1 */ + uint32_t VF; /* V is the bit 31. All other bits are undefined */ + uint32_t NZF; /* N is bit 31. Z is computed from NZF */ + + /* exception/interrupt handling */ + jmp_buf jmp_env; + int exception_index; + int interrupt_request; + + /* user data */ + void *opaque; +} CPUARMState; + +CPUARMState *cpu_arm_init(void); +int cpu_arm_exec(CPUARMState *s); +void cpu_arm_interrupt(CPUARMState *s); +void cpu_arm_close(CPUARMState *s); +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +struct siginfo; +int cpu_arm_signal_handler(int host_signum, struct siginfo *info, + void *puc); + +void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags); + +#define TARGET_PAGE_BITS 12 +#include "cpu-all.h" + +#endif diff --git a/exec-arm.h b/exec-arm.h new file mode 100644 index 000000000..8da263672 --- /dev/null +++ b/exec-arm.h @@ -0,0 +1,32 @@ +/* + * ARM execution defines + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "dyngen-exec.h" + +register struct CPUARMState *env asm(AREG0); +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +register uint32_t T2 asm(AREG3); + +#include "cpu-arm.h" +#include "exec.h" + +void cpu_lock(void); +void cpu_unlock(void); +void cpu_loop_exit(void); diff --git a/op-arm-template.h b/op-arm-template.h new file mode 100644 index 000000000..00e9d51fe --- /dev/null +++ b/op-arm-template.h @@ -0,0 +1,48 @@ +/* + * ARM micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void OPPROTO glue(op_movl_T0_, REGNAME)(void) +{ + T0 = REG; +} + +void OPPROTO glue(op_movl_T1_, REGNAME)(void) +{ + T1 = REG; +} + +void OPPROTO glue(op_movl_T2_, REGNAME)(void) +{ + T2 = REG; +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) +{ + REG = T0; +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) +{ + REG = T1; +} + +#undef REG +#undef REGNAME diff --git a/op-arm.c b/op-arm.c new file mode 100644 index 000000000..40cf3cd25 --- /dev/null +++ b/op-arm.c @@ -0,0 +1,665 @@ +/* + * ARM micro operations + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "exec-arm.h" + +#define REGNAME r0 +#define REG (env->regs[0]) +#include "op-arm-template.h" + +#define REGNAME r1 +#define REG (env->regs[1]) +#include "op-arm-template.h" + +#define REGNAME r2 +#define REG (env->regs[2]) +#include "op-arm-template.h" + +#define REGNAME r3 +#define REG (env->regs[3]) +#include "op-arm-template.h" + +#define REGNAME r4 +#define REG (env->regs[4]) +#include "op-arm-template.h" + +#define REGNAME r5 +#define REG (env->regs[5]) +#include "op-arm-template.h" + +#define REGNAME r6 +#define REG (env->regs[6]) +#include "op-arm-template.h" + +#define REGNAME r7 +#define REG (env->regs[7]) +#include "op-arm-template.h" + +#define REGNAME r8 +#define REG (env->regs[8]) +#include "op-arm-template.h" + +#define REGNAME r9 +#define REG (env->regs[9]) +#include "op-arm-template.h" + +#define REGNAME r10 +#define REG (env->regs[10]) +#include "op-arm-template.h" + +#define REGNAME r11 +#define REG (env->regs[11]) +#include "op-arm-template.h" + +#define REGNAME r12 +#define REG (env->regs[12]) +#include "op-arm-template.h" + +#define REGNAME r13 +#define REG (env->regs[13]) +#include "op-arm-template.h" + +#define REGNAME r14 +#define REG (env->regs[14]) +#include "op-arm-template.h" + +#define REGNAME r15 +#define REG (env->regs[15]) +#include "op-arm-template.h" + +void OPPROTO op_movl_T0_0(void) +{ + T0 = 0; +} + +void OPPROTO op_movl_T0_im(void) +{ + T0 = PARAM1; +} + +void OPPROTO op_movl_T1_im(void) +{ + T1 = PARAM1; +} + +void OPPROTO op_movl_T2_im(void) +{ + T2 = PARAM1; +} + +void OPPROTO op_addl_T1_im(void) +{ + T1 += PARAM1; +} + +void OPPROTO op_addl_T1_T2(void) +{ + T1 += T2; +} + +void OPPROTO op_subl_T1_T2(void) +{ + T1 -= T2; +} + +void OPPROTO op_addl_T0_T1(void) +{ + T0 += T1; +} + +void OPPROTO op_addl_T0_T1_cc(void) +{ + unsigned int src1; + src1 = T0; + T0 += T1; + env->NZF = T0; + env->CF = T0 < src1; + env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); +} + +void OPPROTO op_adcl_T0_T1(void) +{ + T0 += T1 + env->CF; +} + +void OPPROTO op_adcl_T0_T1_cc(void) +{ + unsigned int src1; + src1 = T0; + if (!env->CF) { + T0 += T1; + env->CF = T0 < src1; + } else { + T0 += T1 + 1; + env->CF = T0 <= src1; + } + env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); + env->NZF = T0; + FORCE_RET(); +} + +#define OPSUB(sub, sbc, T0, T1) \ + \ +void OPPROTO op_ ## sub ## l_T0_T1(void) \ +{ \ + T0 -= T1; \ +} \ + \ +void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ +{ \ + unsigned int src1; \ + src1 = T0; \ + T0 -= T1; \ + env->NZF = T0; \ + env->CF = src1 < T1; \ + env->VF = (src1 ^ T1) & (src1 ^ T0); \ +} \ + \ +void OPPROTO op_ ## sbc ## l_T0_T1(void) \ +{ \ + T0 = T0 - T1 + env->CF - 1; \ +} \ + \ +void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ +{ \ + unsigned int src1; \ + src1 = T0; \ + if (!env->CF) { \ + T0 = T0 - T1 - 1; \ + T0 += T1; \ + env->CF = src1 < T1; \ + } else { \ + T0 = T0 - T1; \ + env->CF = src1 <= T1; \ + } \ + env->VF = (src1 ^ T1) & (src1 ^ T0); \ + env->NZF = T0; \ + FORCE_RET(); \ +} + +OPSUB(sub, sbc, T0, T1) + +OPSUB(rsb, rsc, T1, T0) + +void OPPROTO op_andl_T0_T1(void) +{ + T0 &= T1; +} + +void OPPROTO op_xorl_T0_T1(void) +{ + T0 ^= T1; +} + +void OPPROTO op_orl_T0_T1(void) +{ + T0 |= T1; +} + +void OPPROTO op_bicl_T0_T1(void) +{ + T0 &= ~T1; +} + +void OPPROTO op_notl_T1(void) +{ + T1 = ~T1; +} + +void OPPROTO op_logic_cc(void) +{ + env->NZF = T0; +} + +#define EIP (env->regs[15]) + +void OPPROTO op_test_eq(void) +{ + if (env->NZF == 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_ne(void) +{ + if (env->NZF != 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_cs(void) +{ + if (env->CF != 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_cc(void) +{ + if (env->CF == 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_mi(void) +{ + if ((env->NZF & 0x80000000) != 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_pl(void) +{ + if ((env->NZF & 0x80000000) == 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_vs(void) +{ + if ((env->VF & 0x80000000) != 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_vc(void) +{ + if ((env->VF & 0x80000000) == 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_hi(void) +{ + if (env->CF != 0 && env->NZF != 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_ls(void) +{ + if (env->CF == 0 || env->NZF == 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_ge(void) +{ + if (((env->VF ^ env->NZF) & 0x80000000) == 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_lt(void) +{ + if (((env->VF ^ env->NZF) & 0x80000000) != 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_gt(void) +{ + if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_le(void) +{ + if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) + JUMP_TB(PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_jmp(void) +{ + JUMP_TB(PARAM1, 1, PARAM2); +} + +void OPPROTO op_movl_T0_psr(void) +{ + int ZF; + ZF = (env->NZF == 0); + T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); +} + +/* NOTE: N = 1 and Z = 1 cannot be stored currently */ +void OPPROTO op_movl_psr_T0(void) +{ + unsigned int psr; + psr = T0; + env->CF = (psr >> 29) & 1; + env->NZF = (psr & 0xc0000000) ^ 0x40000000; + env->VF = (psr << 3) & 0x80000000; + /* for user mode we do not update other state info */ +} + +void OPPROTO op_mul_T0_T1(void) +{ + T0 = T0 * T1; +} + +/* 64 bit unsigned mul */ +void OPPROTO op_mull_T0_T1(void) +{ + uint64_t res; + res = T0 * T1; + T1 = res >> 32; + T0 = res; +} + +/* 64 bit signed mul */ +void OPPROTO op_imull_T0_T1(void) +{ + uint64_t res; + res = (int32_t)T0 * (int32_t)T1; + T1 = res >> 32; + T0 = res; +} + +void OPPROTO op_addq_T0_T1(void) +{ + uint64_t res; + res = ((uint64_t)T1 << 32) | T0; + res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); + T1 = res >> 32; + T0 = res; +} + +void OPPROTO op_logicq_cc(void) +{ + env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); +} + +/* memory access */ + +void OPPROTO op_ldub_T0_T1(void) +{ + T0 = ldub((void *)T1); +} + +void OPPROTO op_ldsb_T0_T1(void) +{ + T0 = ldsb((void *)T1); +} + +void OPPROTO op_lduw_T0_T1(void) +{ + T0 = lduw((void *)T1); +} + +void OPPROTO op_ldsw_T0_T1(void) +{ + T0 = ldsw((void *)T1); +} + +void OPPROTO op_ldl_T0_T1(void) +{ + T0 = ldl((void *)T1); +} + +void OPPROTO op_stb_T0_T1(void) +{ + stb((void *)T1, T0); +} + +void OPPROTO op_stw_T0_T1(void) +{ + stw((void *)T1, T0); +} + +void OPPROTO op_stl_T0_T1(void) +{ + stl((void *)T1, T0); +} + +void OPPROTO op_swpb_T0_T1(void) +{ + int tmp; + + cpu_lock(); + tmp = ldub((void *)T1); + stb((void *)T1, T0); + T0 = tmp; + cpu_unlock(); +} + +void OPPROTO op_swpl_T0_T1(void) +{ + int tmp; + + cpu_lock(); + tmp = ldl((void *)T1); + stl((void *)T1, T0); + T0 = tmp; + cpu_unlock(); +} + +/* shifts */ + +/* T1 based */ +void OPPROTO op_shll_T1_im(void) +{ + T1 = T1 << PARAM1; +} + +void OPPROTO op_shrl_T1_im(void) +{ + T1 = (uint32_t)T1 >> PARAM1; +} + +void OPPROTO op_sarl_T1_im(void) +{ + T1 = (int32_t)T1 >> PARAM1; +} + +void OPPROTO op_rorl_T1_im(void) +{ + int shift; + shift = PARAM1; + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); +} + +/* T1 based, set C flag */ +void OPPROTO op_shll_T1_im_cc(void) +{ + env->CF = (T1 >> (32 - PARAM1)) & 1; + T1 = T1 << PARAM1; +} + +void OPPROTO op_shrl_T1_im_cc(void) +{ + env->CF = (T1 >> (PARAM1 - 1)) & 1; + T1 = (uint32_t)T1 >> PARAM1; +} + +void OPPROTO op_sarl_T1_im_cc(void) +{ + env->CF = (T1 >> (PARAM1 - 1)) & 1; + T1 = (int32_t)T1 >> PARAM1; +} + +void OPPROTO op_rorl_T1_im_cc(void) +{ + int shift; + shift = PARAM1; + env->CF = (T1 >> (shift - 1)) & 1; + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); +} + +/* T2 based */ +void OPPROTO op_shll_T2_im(void) +{ + T2 = T2 << PARAM1; +} + +void OPPROTO op_shrl_T2_im(void) +{ + T2 = (uint32_t)T2 >> PARAM1; +} + +void OPPROTO op_sarl_T2_im(void) +{ + T2 = (int32_t)T2 >> PARAM1; +} + +void OPPROTO op_rorl_T2_im(void) +{ + int shift; + shift = PARAM1; + T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); +} + +/* T1 based, use T0 as shift count */ + +void OPPROTO op_shll_T1_T0(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) + T1 = 0; + else + T1 = T1 << shift; + FORCE_RET(); +} + +void OPPROTO op_shrl_T1_T0(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) + T1 = 0; + else + T1 = (uint32_t)T1 >> shift; + FORCE_RET(); +} + +void OPPROTO op_sarl_T1_T0(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) + shift = 31; + T1 = (int32_t)T1 >> shift; +} + +void OPPROTO op_rorl_T1_T0(void) +{ + int shift; + shift = T0 & 0x1f; + if (shift) { + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); + } + FORCE_RET(); +} + +/* T1 based, use T0 as shift count and compute CF */ + +void OPPROTO op_shll_T1_T0_cc(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = T1 & 1; + else + env->CF = 0; + T1 = 0; + } else if (shift != 0) { + env->CF = (T1 >> (32 - shift)) & 1; + T1 = T1 << shift; + } + FORCE_RET(); +} + +void OPPROTO op_shrl_T1_T0_cc(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = (T1 >> 31) & 1; + else + env->CF = 0; + T1 = 0; + } else if (shift != 0) { + env->CF = (T1 >> (shift - 1)) & 1; + T1 = (uint32_t)T1 >> shift; + } + FORCE_RET(); +} + +void OPPROTO op_sarl_T1_T0_cc(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) { + env->CF = (T1 >> 31) & 1; + T1 = (int32_t)T1 >> 31; + } else { + env->CF = (T1 >> (shift - 1)) & 1; + T1 = (int32_t)T1 >> shift; + } + FORCE_RET(); +} + +void OPPROTO op_rorl_T1_T0_cc(void) +{ + int shift1, shift; + shift1 = T0 & 0xff; + shift = shift1 & 0x1f; + if (shift == 0) { + if (shift1 != 0) + env->CF = (T1 >> 31) & 1; + } else { + env->CF = (T1 >> (shift - 1)) & 1; + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); + } + FORCE_RET(); +} + +/* exceptions */ + +void OPPROTO op_swi(void) +{ + env->exception_index = EXCP_SWI; + cpu_loop_exit(); +} + +void OPPROTO op_undef_insn(void) +{ + env->exception_index = EXCP_UDEF; + cpu_loop_exit(); +} + +/* thread support */ + +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void cpu_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void cpu_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + diff --git a/syscall-arm.h b/syscall-arm.h new file mode 100644 index 000000000..e5977106b --- /dev/null +++ b/syscall-arm.h @@ -0,0 +1,27 @@ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { + target_long uregs[18]; +}; + +#define ARM_cpsr uregs[16] +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[17] + diff --git a/translate-arm.c b/translate-arm.c new file mode 100644 index 000000000..9b85b6851 --- /dev/null +++ b/translate-arm.c @@ -0,0 +1,750 @@ +/* + * ARM translation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include "cpu-arm.h" +#include "exec.h" +#include "disas.h" + +/* internal defines */ +typedef struct DisasContext { + uint8_t *pc; + int is_jmp; + struct TranslationBlock *tb; +} DisasContext; + +/* XXX: move that elsewhere */ +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; +extern FILE *logfile; +extern int loglevel; + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc-arm.h" +#undef DEF + NB_OPS, +}; + +#include "gen-op-arm.h" + +typedef void (GenOpFunc)(void); +typedef void (GenOpFunc1)(long); +typedef void (GenOpFunc2)(long, long); +typedef void (GenOpFunc3)(long, long, long); + +static GenOpFunc2 *gen_test_cc[14] = { + gen_op_test_eq, + gen_op_test_ne, + gen_op_test_cs, + gen_op_test_cc, + gen_op_test_mi, + gen_op_test_pl, + gen_op_test_vs, + gen_op_test_vc, + gen_op_test_hi, + gen_op_test_ls, + gen_op_test_ge, + gen_op_test_lt, + gen_op_test_gt, + gen_op_test_le, +}; + +const uint8_t table_logic_cc[16] = { + 1, /* and */ + 1, /* xor */ + 0, /* sub */ + 0, /* rsb */ + 0, /* add */ + 0, /* adc */ + 0, /* sbc */ + 0, /* rsc */ + 1, /* andl */ + 1, /* xorl */ + 0, /* cmp */ + 0, /* cmn */ + 1, /* orr */ + 1, /* mov */ + 1, /* bic */ + 1, /* mvn */ +}; + +static GenOpFunc1 *gen_shift_T1_im[4] = { + gen_op_shll_T1_im, + gen_op_shrl_T1_im, + gen_op_sarl_T1_im, + gen_op_rorl_T1_im, +}; + +static GenOpFunc1 *gen_shift_T2_im[4] = { + gen_op_shll_T2_im, + gen_op_shrl_T2_im, + gen_op_sarl_T2_im, + gen_op_rorl_T2_im, +}; + +static GenOpFunc1 *gen_shift_T1_im_cc[4] = { + gen_op_shll_T1_im_cc, + gen_op_shrl_T1_im_cc, + gen_op_sarl_T1_im_cc, + gen_op_rorl_T1_im_cc, +}; + +static GenOpFunc *gen_shift_T1_T0[4] = { + gen_op_shll_T1_T0, + gen_op_shrl_T1_T0, + gen_op_sarl_T1_T0, + gen_op_rorl_T1_T0, +}; + +static GenOpFunc *gen_shift_T1_T0_cc[4] = { + gen_op_shll_T1_T0_cc, + gen_op_shrl_T1_T0_cc, + gen_op_sarl_T1_T0_cc, + gen_op_rorl_T1_T0_cc, +}; + +static GenOpFunc *gen_op_movl_TN_reg[3][16] = { + { + gen_op_movl_T0_r0, + gen_op_movl_T0_r1, + gen_op_movl_T0_r2, + gen_op_movl_T0_r3, + gen_op_movl_T0_r4, + gen_op_movl_T0_r5, + gen_op_movl_T0_r6, + gen_op_movl_T0_r7, + gen_op_movl_T0_r8, + gen_op_movl_T0_r9, + gen_op_movl_T0_r10, + gen_op_movl_T0_r11, + gen_op_movl_T0_r12, + gen_op_movl_T0_r13, + gen_op_movl_T0_r14, + gen_op_movl_T0_r15, + }, + { + gen_op_movl_T1_r0, + gen_op_movl_T1_r1, + gen_op_movl_T1_r2, + gen_op_movl_T1_r3, + gen_op_movl_T1_r4, + gen_op_movl_T1_r5, + gen_op_movl_T1_r6, + gen_op_movl_T1_r7, + gen_op_movl_T1_r8, + gen_op_movl_T1_r9, + gen_op_movl_T1_r10, + gen_op_movl_T1_r11, + gen_op_movl_T1_r12, + gen_op_movl_T1_r13, + gen_op_movl_T1_r14, + gen_op_movl_T1_r15, + }, + { + gen_op_movl_T2_r0, + gen_op_movl_T2_r1, + gen_op_movl_T2_r2, + gen_op_movl_T2_r3, + gen_op_movl_T2_r4, + gen_op_movl_T2_r5, + gen_op_movl_T2_r6, + gen_op_movl_T2_r7, + gen_op_movl_T2_r8, + gen_op_movl_T2_r9, + gen_op_movl_T2_r10, + gen_op_movl_T2_r11, + gen_op_movl_T2_r12, + gen_op_movl_T2_r13, + gen_op_movl_T2_r14, + gen_op_movl_T2_r15, + }, +}; + +static GenOpFunc *gen_op_movl_reg_TN[2][16] = { + { + gen_op_movl_r0_T0, + gen_op_movl_r1_T0, + gen_op_movl_r2_T0, + gen_op_movl_r3_T0, + gen_op_movl_r4_T0, + gen_op_movl_r5_T0, + gen_op_movl_r6_T0, + gen_op_movl_r7_T0, + gen_op_movl_r8_T0, + gen_op_movl_r9_T0, + gen_op_movl_r10_T0, + gen_op_movl_r11_T0, + gen_op_movl_r12_T0, + gen_op_movl_r13_T0, + gen_op_movl_r14_T0, + gen_op_movl_r15_T0, + }, + { + gen_op_movl_r0_T1, + gen_op_movl_r1_T1, + gen_op_movl_r2_T1, + gen_op_movl_r3_T1, + gen_op_movl_r4_T1, + gen_op_movl_r5_T1, + gen_op_movl_r6_T1, + gen_op_movl_r7_T1, + gen_op_movl_r8_T1, + gen_op_movl_r9_T1, + gen_op_movl_r10_T1, + gen_op_movl_r11_T1, + gen_op_movl_r12_T1, + gen_op_movl_r13_T1, + gen_op_movl_r14_T1, + gen_op_movl_r15_T1, + }, +}; + +static GenOpFunc1 *gen_op_movl_TN_im[3] = { + gen_op_movl_T0_im, + gen_op_movl_T1_im, + gen_op_movl_T2_im, +}; + +static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) +{ + int val; + + if (reg == 15) { + /* normaly, since we updated PC, we need only to add 4 */ + val = (long)s->pc + 4; + gen_op_movl_TN_im[t](val); + } else { + gen_op_movl_TN_reg[t][reg](); + } +} + +static inline void gen_movl_T0_reg(DisasContext *s, int reg) +{ + gen_movl_TN_reg(s, reg, 0); +} + +static inline void gen_movl_T1_reg(DisasContext *s, int reg) +{ + gen_movl_TN_reg(s, reg, 1); +} + +static inline void gen_movl_T2_reg(DisasContext *s, int reg) +{ + gen_movl_TN_reg(s, reg, 2); +} + +static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t) +{ + gen_op_movl_reg_TN[t][reg](); + if (reg == 15) { + s->is_jmp = DISAS_JUMP; + } +} + +static inline void gen_movl_reg_T0(DisasContext *s, int reg) +{ + gen_movl_reg_TN(s, reg, 0); +} + +static inline void gen_movl_reg_T1(DisasContext *s, int reg) +{ + gen_movl_reg_TN(s, reg, 1); +} + +static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) +{ + int val, rm, shift; + + if (!(insn & (1 << 25))) { + /* immediate */ + val = insn & 0xfff; + if (!(insn & (1 << 23))) + val = -val; + gen_op_addl_T1_im(val); + } else { + /* shift/register */ + rm = (insn) & 0xf; + shift = (insn >> 7) & 0x1f; + gen_movl_T2_reg(s, rm); + if (shift != 0) { + gen_shift_T2_im[(insn >> 5) & 3](shift); + } + if (!(insn & (1 << 23))) + gen_op_subl_T1_T2(); + else + gen_op_addl_T1_T2(); + } +} + +static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn) +{ + int val, rm; + + if (insn & (1 << 22)) { + /* immediate */ + val = (insn & 0xf) | ((insn >> 4) & 0xf0); + if (!(insn & (1 << 23))) + val = -val; + gen_op_addl_T1_im(val); + } else { + /* register */ + rm = (insn) & 0xf; + gen_movl_T2_reg(s, rm); + if (!(insn & (1 << 23))) + gen_op_subl_T1_T2(); + else + gen_op_addl_T1_T2(); + } +} + +static void disas_arm_insn(DisasContext *s) +{ + unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; + + insn = ldl(s->pc); + s->pc += 4; + + cond = insn >> 28; + if (cond == 0xf) + goto illegal_op; + if (cond != 0xe) { + /* if not always execute, we generate a conditional jump to + next instruction */ + gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); + s->is_jmp = 1; + } + if ((insn & 0x0c000000) == 0 && + (insn & 0x00000090) != 0x90) { + int set_cc, logic_cc, shiftop; + + op1 = (insn >> 21) & 0xf; + set_cc = (insn >> 20) & 1; + logic_cc = table_logic_cc[op1] & set_cc; + + /* data processing instruction */ + if (insn & (1 << 25)) { + /* immediate operand */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) + val = (val >> shift) | (val << (32 - shift)); + gen_op_movl_T1_im(val); + /* XXX: is CF modified ? */ + } else { + /* register */ + rm = (insn) & 0xf; + gen_movl_T1_reg(s, rm); + shiftop = (insn >> 5) & 3; + if (!(insn & (1 << 4))) { + shift = (insn >> 7) & 0x1f; + if (shift != 0) { + if (logic_cc) { + gen_shift_T1_im_cc[shiftop](shift); + } else { + gen_shift_T1_im[shiftop](shift); + } + } + } else { + rs = (insn >> 16) & 0xf; + gen_movl_T0_reg(s, rs); + if (logic_cc) { + gen_shift_T1_T0_cc[shiftop](); + } else { + gen_shift_T1_T0[shiftop](); + } + } + } + if (op1 != 0x0f && op1 != 0x0d) { + rn = (insn >> 16) & 0xf; + gen_movl_T0_reg(s, rn); + } + rd = (insn >> 12) & 0xf; + switch(op1) { + case 0x00: + gen_op_andl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x01: + gen_op_xorl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x02: + if (set_cc) + gen_op_subl_T0_T1_cc(); + else + gen_op_subl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x03: + if (set_cc) + gen_op_rsbl_T0_T1_cc(); + else + gen_op_rsbl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x04: + if (set_cc) + gen_op_addl_T0_T1_cc(); + else + gen_op_addl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x05: + if (set_cc) + gen_op_adcl_T0_T1_cc(); + else + gen_op_adcl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x06: + if (set_cc) + gen_op_sbcl_T0_T1_cc(); + else + gen_op_sbcl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x07: + if (set_cc) + gen_op_rscl_T0_T1_cc(); + else + gen_op_rscl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x08: + if (set_cc) { + gen_op_andl_T0_T1(); + } + break; + case 0x09: + if (set_cc) { + gen_op_xorl_T0_T1(); + } + break; + case 0x0a: + if (set_cc) { + gen_op_subl_T0_T1_cc(); + } + break; + case 0x0b: + if (set_cc) { + gen_op_addl_T0_T1_cc(); + } + break; + case 0x0c: + gen_op_orl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x0d: + gen_movl_reg_T1(s, rd); + break; + case 0x0e: + gen_op_bicl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + default: + case 0x0f: + gen_op_notl_T1(); + gen_movl_reg_T1(s, rd); + break; + } + if (logic_cc) + gen_op_logic_cc(); + } else { + /* other instructions */ + op1 = (insn >> 24) & 0xf; + switch(op1) { + case 0x0: + case 0x1: + sh = (insn >> 5) & 3; + if (sh == 0) { + if (op1 == 0x0) { + rd = (insn >> 16) & 0xf; + rn = (insn >> 12) & 0xf; + rs = (insn >> 8) & 0xf; + rm = (insn) & 0xf; + if (!(insn & (1 << 23))) { + /* 32 bit mul */ + gen_movl_T0_reg(s, rs); + gen_movl_T1_reg(s, rm); + gen_op_mul_T0_T1(); + if (insn & (1 << 21)) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1(); + } + if (insn & (1 << 20)) + gen_op_logic_cc(); + gen_movl_reg_T0(s, rd); + } else { + /* 64 bit mul */ + gen_movl_T0_reg(s, rs); + gen_movl_T1_reg(s, rm); + if (insn & (1 << 22)) + gen_op_mull_T0_T1(); + else + gen_op_imull_T0_T1(); + if (insn & (1 << 21)) + gen_op_addq_T0_T1(rn, rd); + if (insn & (1 << 20)) + gen_op_logicq_cc(); + gen_movl_reg_T0(s, rn); + gen_movl_reg_T1(s, rd); + } + } else { + /* SWP instruction */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + rm = (insn) & 0xf; + + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if (insn & (1 << 22)) { + gen_op_swpb_T0_T1(); + } else { + gen_op_swpl_T0_T1(); + } + gen_movl_reg_T0(s, rd); + } + } else { + /* load/store half word */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + gen_movl_T1_reg(s, rn); + if (insn & (1 << 25)) + gen_add_datah_offset(s, insn); + if (insn & (1 << 20)) { + /* load */ + switch(sh) { + case 1: + gen_op_lduw_T0_T1(); + break; + case 2: + gen_op_ldsb_T0_T1(); + break; + default: + case 3: + gen_op_ldsw_T0_T1(); + break; + } + } else { + /* store */ + gen_op_stw_T0_T1(); + } + if (!(insn & (1 << 24))) + gen_add_datah_offset(s, insn); + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + } + break; + case 0x4: + case 0x5: + case 0x6: + case 0x7: + /* load/store byte/word */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + gen_movl_T1_reg(s, rn); + if (insn & (1 << 24)) + gen_add_data_offset(s, insn); + if (insn & (1 << 20)) { + /* load */ + if (insn & (1 << 22)) + gen_op_ldub_T0_T1(); + else + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd); + } else { + /* store */ + gen_movl_T0_reg(s, rd); + if (insn & (1 << 22)) + gen_op_stb_T0_T1(); + else + gen_op_stl_T0_T1(); + } + if (!(insn & (1 << 24))) + gen_add_data_offset(s, insn); + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + break; + case 0x08: + case 0x09: + /* load/store multiple words */ + if (insn & (1 << 22)) + goto illegal_op; /* only usable in supervisor mode */ + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + val = 4; + if (!(insn & (1 << 23))) + val = -val; + for(i=0;i<16;i++) { + if (insn & (1 << i)) { + if (insn & (1 << 24)) + gen_op_addl_T1_im(val); + if (insn & (1 << 20)) { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, i); + } else { + /* store */ + gen_movl_T0_reg(s, i); + gen_op_stl_T0_T1(); + } + if (!(insn & (1 << 24))) + gen_op_addl_T1_im(val); + } + } + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + break; + case 0xa: + case 0xb: + { + int offset; + + /* branch (and link) */ + val = (int)s->pc; + if (insn & (1 << 24)) { + gen_op_movl_T0_im(val); + gen_op_movl_reg_TN[0][14](); + } + offset = (((int)insn << 8) >> 8); + val += (offset << 2) + 4; + gen_op_jmp((long)s->tb, val); + s->is_jmp = DISAS_TB_JUMP; + } + break; + case 0xf: + /* swi */ + gen_op_movl_T0_im((long)s->pc); + gen_op_movl_reg_TN[0][15](); + gen_op_swi(); + s->is_jmp = DISAS_JUMP; + break; + default: + illegal_op: + gen_op_movl_T0_im((long)s->pc - 4); + gen_op_movl_reg_TN[0][15](); + gen_op_undef_insn(); + s->is_jmp = DISAS_JUMP; + break; + } + } +} + +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +int gen_intermediate_code(TranslationBlock *tb, int search_pc) +{ + DisasContext dc1, *dc = &dc1; + uint16_t *gen_opc_end; + int j, lj; + uint8_t *pc_start; + + /* generate intermediate code */ + pc_start = (uint8_t *)tb->pc; + + dc->tb = tb; + + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + + dc->is_jmp = DISAS_NEXT; + dc->pc = pc_start; + lj = -1; + do { + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + gen_opc_pc[lj] = (uint32_t)dc->pc; + gen_opc_instr_start[lj] = 1; + } + } + disas_arm_insn(dc); + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + /* we must store the eflags state if it is not already done */ + if (dc->is_jmp != DISAS_TB_JUMP && + dc->is_jmp != DISAS_JUMP) { + gen_op_movl_T0_im((long)dc->pc - 4); + gen_op_movl_reg_TN[0][15](); + } + if (dc->is_jmp != DISAS_TB_JUMP) { + /* indicate that the hash table must be used to find the next TB */ + gen_op_movl_T0_0(); + } + *gen_opc_ptr = INDEX_op_end; + +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "----------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + disas(logfile, pc_start, dc->pc - pc_start, 0, 0); + fprintf(logfile, "\n"); + + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + if (!search_pc) + tb->size = dc->pc - pc_start; + return 0; +} + +CPUARMState *cpu_arm_init(void) +{ + CPUARMState *env; + + cpu_exec_init(); + + env = malloc(sizeof(CPUARMState)); + if (!env) + return NULL; + memset(env, 0, sizeof(CPUARMState)); + return env; +} + +void cpu_arm_close(CPUARMState *env) +{ + free(env); +} + +void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) +{ + int i; + + for(i=0;i<16;i++) { + fprintf(f, "R%02d=%08x", i, env->regs[i]); + if ((i % 4) == 3) + fprintf(f, "\n"); + else + fprintf(f, " "); + } + fprintf(f, "CPSR=%08x", env->cpsr); +} -- cgit v1.2.3 From 95cbfc643dd8e0c4dd3690fbbbbc20f2a8af5998 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:44:10 +0000 Subject: changed disas() prototype for multi target support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@233 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 23 +++++++++++++++++------ disas.h | 8 +------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/disas.c b/disas.c index 2a8a533b0..dc1957b96 100644 --- a/disas.c +++ b/disas.c @@ -92,8 +92,9 @@ bfd_vma bfd_getb32 (const bfd_byte *addr) return (bfd_vma) v; } -/* Disassemble this for me please... (debugging). */ -void disas(FILE *out, void *code, unsigned long size, enum disas_type type) +/* Disassemble this for me please... (debugging). 'flags' is only used + for i386: non zero means 16 bit code */ +void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) { uint8_t *pc; int count; @@ -106,7 +107,7 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type) disasm_info.buffer_vma = (unsigned long)code; disasm_info.buffer_length = size; - if (type == DISAS_TARGET) { + if (is_host) { #ifdef WORDS_BIGENDIAN disasm_info.endian = BFD_ENDIAN_BIG; #else @@ -128,13 +129,23 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type) return; #endif } else { - /* Currently only source supported in x86. */ +#ifdef TARGET_WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else disasm_info.endian = BFD_ENDIAN_LITTLE; - if (type == DISAS_I386_I386) +#endif +#if defined(TARGET_I386) + if (!flags) disasm_info.mach = bfd_mach_i386_i386; else disasm_info.mach = bfd_mach_i386_i8086; print_insn = print_insn_i386; +#elif defined(TARGET_ARM) + print_insn = print_insn_arm; +#else + fprintf(out, "Asm output not supported on this arch\n"); + return; +#endif } for (pc = code; pc < (uint8_t *)code + size; pc += count) { @@ -142,7 +153,7 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type) #ifdef __arm__ /* since data are included in the code, it is better to display code data too */ - if (type == DISAS_TARGET) { + if (is_host) { fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); } #endif diff --git a/disas.h b/disas.h index b7db47829..916b1357a 100644 --- a/disas.h +++ b/disas.h @@ -1,14 +1,8 @@ #ifndef _QEMU_DISAS_H #define _QEMU_DISAS_H -enum disas_type { - DISAS_I386_I386, - DISAS_I386_I8086, - DISAS_TARGET, /* whatever host is. */ -}; - /* Disassemble this for me please... (debugging). */ -void disas(FILE *out, void *code, unsigned long size, enum disas_type type); +void disas(FILE *out, void *code, unsigned long size, int is_host, int flags); /* Look up symbol for debugging purpose. Returns "" if unknown. */ const char *lookup_symbol(void *orig_addr); -- cgit v1.2.3 From d219f7e7edf7874ae1572d9c6a8e9283c6f36bbc Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:44:49 +0000 Subject: output gen_op_xxx() in a separate file git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@234 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 54 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/dyngen.c b/dyngen.c index c2f9d120e..be790d705 100644 --- a/dyngen.c +++ b/dyngen.c @@ -110,6 +110,12 @@ typedef uint64_t host_ulong; #include "thunk.h" +enum { + OUT_GEN_OP, + OUT_CODE, + OUT_INDEX_OP, +}; + /* all dynamically generated functions begin with this code */ #define OP_PREFIX "op_" @@ -1087,7 +1093,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } /* load an elf object file */ -int load_elf(const char *filename, FILE *outfile, int do_print_enum) +int load_elf(const char *filename, FILE *outfile, int out_type) { int fd; struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec; @@ -1195,7 +1201,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) } } - if (do_print_enum) { + if (out_type == OUT_INDEX_OP) { fprintf(outfile, "DEF(end, 0, 0)\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name, *p; @@ -1205,6 +1211,20 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) text, relocs, nb_relocs, 2); } } + } else if (out_type == OUT_GEN_OP) { + /* generate gen_xxx functions */ + + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + const char *name; + name = strtab + sym->st_name; + if (strstart(name, OP_PREFIX, NULL)) { + if (sym->st_shndx != (text_sec - shdr)) + error("invalid section for opcode (0x%x)", sym->st_shndx); + gen_code(name, sym->st_value, sym->st_size, outfile, + text, relocs, nb_relocs, 0); + } + } + } else { /* generate big code generation switch */ fprintf(outfile, @@ -1305,22 +1325,12 @@ fprintf(outfile, default: error("unknown ELF architecture"); } - + /* 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"); -/* generate gen_xxx functions */ -/* XXX: suppress the use of these functions to simplify code */ - for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { - const char *name; - name = strtab + sym->st_name; - if (strstart(name, OP_PREFIX, NULL)) { - if (sym->st_shndx != (text_sec - shdr)) - error("invalid section for opcode (0x%x)", sym->st_shndx); - gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, 0); - } - } } close(fd); @@ -1333,20 +1343,21 @@ void usage(void) "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, do_print_enum; + int c, out_type; const char *filename, *outfilename; FILE *outfile; outfilename = "out.c"; - do_print_enum = 0; + out_type = OUT_CODE; for(;;) { - c = getopt(argc, argv, "ho:c"); + c = getopt(argc, argv, "ho:cg"); if (c == -1) break; switch(c) { @@ -1357,7 +1368,10 @@ int main(int argc, char **argv) outfilename = optarg; break; case 'c': - do_print_enum = 1; + out_type = OUT_INDEX_OP; + break; + case 'g': + out_type = OUT_GEN_OP; break; } } @@ -1367,7 +1381,7 @@ int main(int argc, char **argv) outfile = fopen(outfilename, "w"); if (!outfile) error("could not open '%s'", outfilename); - load_elf(filename, outfile, do_print_enum); + load_elf(filename, outfile, out_type); fclose(outfile); return 0; } -- cgit v1.2.3 From 03daf0e361d58eb5a6d8ea9963ca63f919c15f85 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:45:20 +0000 Subject: moved cache flush to dyngen header git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@235 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/dyngen.h b/dyngen.h index cafa4f5a3..645ce4197 100644 --- a/dyngen.h +++ b/dyngen.h @@ -18,6 +18,82 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +int __op_param1, __op_param2, __op_param3; +int __op_jmp0, __op_jmp1; + +#ifdef __i386__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} +#endif + +#ifdef __s390__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} +#endif + +#ifdef __ia64__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ +} +#endif + +#ifdef __powerpc__ + +#define MIN_CACHE_LINE_SIZE 8 /* conservative value */ + +static void inline flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + p = start & ~(MIN_CACHE_LINE_SIZE - 1); + stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); + + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { + asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); + } + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} +#endif + +#ifdef __alpha__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + asm ("imb"); +} +#endif + +#ifdef __sparc__ + +static void inline flush_icache_range(unsigned long start, unsigned long stop) +{ + unsigned long p; + + p = start & ~(8UL - 1UL); + stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); + + for (; p < stop; p += 8) + __asm__ __volatile__("flush\t%0" : : "r" (p)); +} + +#endif + +#ifdef __arm__ +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + register unsigned long _beg __asm ("a1") = start; + register unsigned long _end __asm ("a2") = stop; + register unsigned long _flg __asm ("a3") = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); +} +#endif + #ifdef __alpha__ register int gp asm("$29"); -- cgit v1.2.3 From 79638566e5b87058e92f537b989df0dbc23f8b41 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:46:57 +0000 Subject: moved dyngen generic code to dyngen-exec.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@236 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 155 +++++++++++++++++++++++++++++++++++++++++++++++ exec-i386.h | 189 ++++++++++++++-------------------------------------------- 2 files changed, 199 insertions(+), 145 deletions(-) create mode 100644 dyngen-exec.h diff --git a/dyngen-exec.h b/dyngen-exec.h new file mode 100644 index 000000000..f588ef0f3 --- /dev/null +++ b/dyngen-exec.h @@ -0,0 +1,155 @@ +/* + * dyngen defines for micro operation code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +#define bswap32(x) \ +({ \ + uint32_t __x = (x); \ + ((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ +}) + +typedef struct FILE FILE; +extern int fprintf(FILE *, const char *, ...); +extern int printf(const char *, ...); +#define NULL 0 +#include + +#ifdef __i386__ +#define AREG0 "ebp" +#define AREG1 "ebx" +#define AREG2 "esi" +#define AREG3 "edi" +#endif +#ifdef __powerpc__ +#define AREG0 "r27" +#define AREG1 "r24" +#define AREG2 "r25" +#define AREG3 "r26" +#define AREG4 "r16" +#define AREG5 "r17" +#define AREG6 "r18" +#define AREG7 "r19" +#define AREG8 "r20" +#define AREG9 "r21" +#define AREG10 "r22" +#define AREG11 "r23" +#define USE_INT_TO_FLOAT_HELPERS +#define BUGGY_GCC_DIV64 +#endif +#ifdef __arm__ +#define AREG0 "r7" +#define AREG1 "r4" +#define AREG2 "r5" +#define AREG3 "r6" +#endif +#ifdef __mips__ +#define AREG0 "s3" +#define AREG1 "s0" +#define AREG2 "s1" +#define AREG3 "s2" +#endif +#ifdef __sparc__ +#define AREG0 "g6" +#define AREG1 "g1" +#define AREG2 "g2" +#define AREG3 "g3" +#define AREG4 "l0" +#define AREG5 "l1" +#define AREG6 "l2" +#define AREG7 "l3" +#define AREG8 "l4" +#define AREG9 "l5" +#define AREG10 "l6" +#define AREG11 "l7" +#define USE_FP_CONVERT +#endif +#ifdef __s390__ +#define AREG0 "r10" +#define AREG1 "r7" +#define AREG2 "r8" +#define AREG3 "r9" +#endif +#ifdef __alpha__ +/* Note $15 is the frame pointer, so anything in op-i386.c that would + require a frame pointer, like alloca, would probably loose. */ +#define AREG0 "$15" +#define AREG1 "$9" +#define AREG2 "$10" +#define AREG3 "$11" +#define AREG4 "$12" +#define AREG5 "$13" +#define AREG6 "$14" +#endif +#ifdef __ia64__ +#define AREG0 "r27" +#define AREG1 "r24" +#define AREG2 "r25" +#define AREG3 "r26" +#endif + +/* force GCC to generate only one epilog at the end of the function */ +#define FORCE_RET() asm volatile (""); + +#ifndef OPPROTO +#define OPPROTO +#endif + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) + +#ifdef __alpha__ +/* the symbols are considered non exported so a br immediate is generated */ +#define __hidden __attribute__((visibility("hidden"))) +#else +#define __hidden +#endif + +#ifdef __alpha__ +/* Suggested by Richard Henderson. This will result in code like + ldah $0,__op_param1($29) !gprelhigh + lda $0,__op_param1($0) !gprellow + We can then conveniently change $29 to $31 and adapt the offsets to + emit the appropriate constant. */ +extern int __op_param1 __hidden; +extern int __op_param2 __hidden; +extern int __op_param3 __hidden; +#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; }) +#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; }) +#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; }) +#else +extern int __op_param1, __op_param2, __op_param3; +#define PARAM1 ((long)(&__op_param1)) +#define PARAM2 ((long)(&__op_param2)) +#define PARAM3 ((long)(&__op_param3)) +#endif + +extern int __op_jmp0, __op_jmp1; diff --git a/exec-i386.h b/exec-i386.h index 4232973f0..a490f266e 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -17,136 +17,59 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; - -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef signed long long int64_t; - -#define bswap32(x) \ -({ \ - uint32_t __x = (x); \ - ((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ -}) - -#define NULL 0 -#include - -typedef struct FILE FILE; -extern FILE *logfile; -extern int loglevel; -extern int fprintf(FILE *, const char *, ...); -extern int printf(const char *, ...); - -#ifdef __i386__ -register unsigned int T0 asm("ebx"); -register unsigned int T1 asm("esi"); -register unsigned int A0 asm("edi"); -register struct CPUX86State *env asm("ebp"); -#endif -#ifdef __powerpc__ -register unsigned int EAX asm("r16"); -register unsigned int ECX asm("r17"); -register unsigned int EDX asm("r18"); -register unsigned int EBX asm("r19"); -register unsigned int ESP asm("r20"); -register unsigned int EBP asm("r21"); -register unsigned int ESI asm("r22"); -register unsigned int EDI asm("r23"); -register unsigned int T0 asm("r24"); -register unsigned int T1 asm("r25"); -register unsigned int A0 asm("r26"); -register struct CPUX86State *env asm("r27"); -#define USE_INT_TO_FLOAT_HELPERS -#define BUGGY_GCC_DIV64 +#include "dyngen-exec.h" + +/* at least 4 register variables are defines */ +register struct CPUX86State *env asm(AREG0); +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +register uint32_t T2 asm(AREG3); + +#define A0 T2 + +/* if more registers are available, we define some registers too */ +#ifdef AREG4 +register uint32_t EAX asm(AREG4); #define reg_EAX -#define reg_ECX -#define reg_EDX -#define reg_EBX -#define reg_ESP -#define reg_EBP -#define reg_ESI -#define reg_EDI -#endif -#ifdef __arm__ -register unsigned int T0 asm("r4"); -register unsigned int T1 asm("r5"); -register unsigned int A0 asm("r6"); -register struct CPUX86State *env asm("r7"); #endif -#ifdef __mips__ -register unsigned int T0 asm("s0"); -register unsigned int T1 asm("s1"); -register unsigned int A0 asm("s2"); -register struct CPUX86State *env asm("s3"); -#endif -#ifdef __sparc__ -register unsigned int EAX asm("l0"); -register unsigned int ECX asm("l1"); -register unsigned int EDX asm("l2"); -register unsigned int EBX asm("l3"); -register unsigned int ESP asm("l4"); -register unsigned int EBP asm("l5"); -register unsigned int ESI asm("l6"); -register unsigned int EDI asm("l7"); -register unsigned int T0 asm("g1"); -register unsigned int T1 asm("g2"); -register unsigned int A0 asm("g3"); -register struct CPUX86State *env asm("g6"); -#define USE_FP_CONVERT -#define reg_EAX -#define reg_ECX -#define reg_EDX -#define reg_EBX + +#ifdef AREG5 +register uint32_t ESP asm(AREG5); #define reg_ESP +#endif + +#ifdef AREG6 +register uint32_t EBP asm(AREG6); #define reg_EBP -#define reg_ESI -#define reg_EDI #endif -#ifdef __s390__ -register unsigned int T0 asm("r7"); -register unsigned int T1 asm("r8"); -register unsigned int A0 asm("r9"); -register struct CPUX86State *env asm("r10"); + +#ifdef AREG7 +register uint32_t ECX asm(AREG7); +#define reg_ECX #endif -#ifdef __alpha__ -register unsigned int T0 asm("$9"); -register unsigned int T1 asm("$10"); -register unsigned int A0 asm("$11"); -register unsigned int EAX asm("$12"); -register unsigned int ESP asm("$13"); -register unsigned int EBP asm("$14"); -/* Note $15 is the frame pointer, so anything in op-i386.c that would - require a frame pointer, like alloca, would probably loose. */ -register struct CPUX86State *env asm("$15"); -#define reg_EAX -#define reg_ESP -#define reg_EBP + +#ifdef AREG8 +register uint32_t EDX asm(AREG8); +#define reg_EDX #endif -#ifdef __ia64__ -register unsigned int T0 asm("r24"); -register unsigned int T1 asm("r25"); -register unsigned int A0 asm("r26"); -register struct CPUX86State *env asm("r27"); + +#ifdef AREG9 +register uint32_t EBX asm(AREG9); +#define reg_EBX #endif -/* force GCC to generate only one epilog at the end of the function */ -#define FORCE_RET() asm volatile (""); +#ifdef AREG10 +register uint32_t ESI asm(AREG10); +#define reg_ESI +#endif -#ifndef OPPROTO -#define OPPROTO +#ifdef AREG11 +register uint32_t EDI asm(AREG11); +#define reg_EDI #endif -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) +extern FILE *logfile; +extern int loglevel; #ifndef reg_EAX #define EAX (env->regs[R_EAX]) @@ -189,33 +112,6 @@ register struct CPUX86State *env asm("r27"); #define FP_CONVERT (env->fp_convert) #endif -#ifdef __alpha__ -/* the symbols are considered non exported so a br immediate is generated */ -#define __hidden __attribute__((visibility("hidden"))) -#else -#define __hidden -#endif - -#ifdef __alpha__ -/* Suggested by Richard Henderson. This will result in code like - ldah $0,__op_param1($29) !gprelhigh - lda $0,__op_param1($0) !gprellow - We can then conveniently change $29 to $31 and adapt the offsets to - emit the appropriate constant. */ -extern int __op_param1 __hidden; -extern int __op_param2 __hidden; -extern int __op_param3 __hidden; -#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; }) -#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; }) -#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; }) -#else -extern int __op_param1, __op_param2, __op_param3; -#define PARAM1 ((long)(&__op_param1)) -#define PARAM2 ((long)(&__op_param2)) -#define PARAM3 ((long)(&__op_param3)) -#endif -extern int __op_jmp0, __op_jmp1; - #include "cpu-i386.h" #include "exec.h" @@ -425,3 +321,6 @@ void helper_fldenv(uint8_t *ptr, int data32); void helper_fsave(uint8_t *ptr, int data32); void helper_frstor(uint8_t *ptr, int data32); +const uint8_t parity_table[256]; +const uint8_t rclw_table[32]; +const uint8_t rclb_table[32]; -- cgit v1.2.3 From 1e5ffbedded7ded797f5042d82b70109a712b4c0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:49:16 +0000 Subject: fixed float to int overflow bug - added ARM host correct roundings for float rounding git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@237 c046a42c-6fe2-441c-8c8c-71466251a162 --- helper-i386.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- op-i386.c | 80 ++--------------------------------------------------------- 2 files changed, 76 insertions(+), 79 deletions(-) diff --git a/helper-i386.c b/helper-i386.c index 293d46af8..1182be8ce 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -19,6 +19,57 @@ */ #include "exec-i386.h" +const uint8_t parity_table[256] = { + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +}; + +/* modulo 17 table */ +const uint8_t rclw_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, +}; + +/* modulo 9 table */ +const uint8_t rclb_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 0, 1, 2, 3, 4, +}; + const CPU86_LDouble f15rk[7] = { 0.00000000000000000000L, @@ -693,7 +744,29 @@ void helper_fsincos(void) void helper_frndint(void) { - ST0 = rint(ST0); + CPU86_LDouble a; + + a = ST0; +#ifdef __arm__ + switch(env->fpuc & RC_MASK) { + default: + case RC_NEAR: + asm("rndd %0, %1" : "=f" (a) : "f"(a)); + break; + case RC_DOWN: + asm("rnddm %0, %1" : "=f" (a) : "f"(a)); + break; + case RC_UP: + asm("rnddp %0, %1" : "=f" (a) : "f"(a)); + break; + case RC_CHOP: + asm("rnddz %0, %1" : "=f" (a) : "f"(a)); + break; + } +#else + a = rint(a); +#endif + ST0 = a; } void helper_fscale(void) diff --git a/op-i386.c b/op-i386.c index e3f26b4e0..c2f92638b 100644 --- a/op-i386.c +++ b/op-i386.c @@ -19,57 +19,6 @@ */ #include "exec-i386.h" -uint8_t parity_table[256] = { - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, -}; - -/* modulo 17 table */ -const uint8_t rclw_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9,10,11,12,13,14,15, - 16, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9,10,11,12,13,14, -}; - -/* modulo 9 table */ -const uint8_t rclb_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 0, 1, 2, 3, 4, -}; - /* n must be a constant to be efficient */ static inline int lshift(int x, int n) { @@ -624,33 +573,6 @@ void OPPROTO op_cmpxchg8b(void) helper_cmpxchg8b(); } -#if defined(__powerpc__) - -/* on PowerPC we patch the jump instruction directly */ -#define JUMP_TB(tbparam, n, eip)\ -do {\ - static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ - asm volatile ("b %0" : : "i" (&__op_jmp ## n));\ -label ## n:\ - T0 = (long)(tbparam) + (n);\ - EIP = eip;\ -} while (0) - -#else - -/* jump to next block operations (more portable code, does not need - cache flushing, but slower because of indirect jump) */ -#define JUMP_TB(tbparam, n, eip)\ -do {\ - static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ -label ## n:\ - T0 = (long)(tbparam) + (n);\ - EIP = eip;\ -} while (0) - -#endif - void OPPROTO op_jmp_tb_next(void) { JUMP_TB(PARAM1, 0, PARAM2); @@ -1561,6 +1483,8 @@ void OPPROTO op_fist_ST0_A0(void) d = ST0; val = lrint(d); + if (val != (int16_t)val) + val = -32768; stw((void *)A0, val); } -- cgit v1.2.3 From e4533c7a8cdcc79ccdf695f0aaa2e23a5b926ed0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:51:39 +0000 Subject: main cpu loop is target independent git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@238 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 575 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ exec-i386.c | 504 ---------------------------------------------------- 2 files changed, 575 insertions(+), 504 deletions(-) create mode 100644 cpu-exec.c delete mode 100644 exec-i386.c diff --git a/cpu-exec.c b/cpu-exec.c new file mode 100644 index 000000000..8d9ffa678 --- /dev/null +++ b/cpu-exec.c @@ -0,0 +1,575 @@ +/* + * i386 emulator main execution loop + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" +#ifdef TARGET_I386 +#include "exec-i386.h" +#endif +#ifdef TARGET_ARM +#include "exec-arm.h" +#endif + +#include "disas.h" + +//#define DEBUG_EXEC +//#define DEBUG_SIGNAL + +#if defined(TARGET_ARM) +/* XXX: unify with i386 target */ +void cpu_loop_exit(void) +{ + longjmp(env->jmp_env, 1); +} +#endif + +/* main execution loop */ + +int cpu_exec(CPUState *env1) +{ + int saved_T0, saved_T1, saved_T2; + CPUState *saved_env; +#ifdef reg_EAX + int saved_EAX; +#endif +#ifdef reg_ECX + int saved_ECX; +#endif +#ifdef reg_EDX + int saved_EDX; +#endif +#ifdef reg_EBX + int saved_EBX; +#endif +#ifdef reg_ESP + int saved_ESP; +#endif +#ifdef reg_EBP + int saved_EBP; +#endif +#ifdef reg_ESI + int saved_ESI; +#endif +#ifdef reg_EDI + int saved_EDI; +#endif +#ifdef __sparc__ + int saved_i7, tmp_T0; +#endif + int code_gen_size, ret; + void (*gen_func)(void); + TranslationBlock *tb, **ptb; + uint8_t *tc_ptr, *cs_base, *pc; + unsigned int flags; + + /* first we save global registers */ + saved_T0 = T0; + saved_T1 = T1; + saved_T2 = T2; + saved_env = env; + env = env1; +#ifdef __sparc__ + /* we also save i7 because longjmp may not restore it */ + asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); +#endif + +#if defined(TARGET_I386) +#ifdef reg_EAX + saved_EAX = EAX; + EAX = env->regs[R_EAX]; +#endif +#ifdef reg_ECX + saved_ECX = ECX; + ECX = env->regs[R_ECX]; +#endif +#ifdef reg_EDX + saved_EDX = EDX; + EDX = env->regs[R_EDX]; +#endif +#ifdef reg_EBX + saved_EBX = EBX; + EBX = env->regs[R_EBX]; +#endif +#ifdef reg_ESP + saved_ESP = ESP; + ESP = env->regs[R_ESP]; +#endif +#ifdef reg_EBP + saved_EBP = EBP; + EBP = env->regs[R_EBP]; +#endif +#ifdef reg_ESI + saved_ESI = ESI; + ESI = env->regs[R_ESI]; +#endif +#ifdef reg_EDI + saved_EDI = EDI; + EDI = env->regs[R_EDI]; +#endif + + /* put eflags in CPU temporary format */ + CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((env->eflags >> 10) & 1)); + CC_OP = CC_OP_EFLAGS; + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); +#elif defined(TARGET_ARM) + { + unsigned int psr; + psr = env->cpsr; + env->CF = (psr >> 29) & 1; + env->NZF = (psr & 0xc0000000) ^ 0x40000000; + env->VF = (psr << 3) & 0x80000000; + env->cpsr = psr & ~0xf0000000; + } +#else +#error unsupported target CPU +#endif + env->interrupt_request = 0; + + /* prepare setjmp context for exception handling */ + if (setjmp(env->jmp_env) == 0) { + T0 = 0; /* force lookup of first TB */ + for(;;) { +#ifdef __sparc__ + /* g1 can be modified by some libc? functions */ + tmp_T0 = T0; +#endif + if (env->interrupt_request) { + env->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(); + } +#ifdef DEBUG_EXEC + if (loglevel) { +#if defined(TARGET_I386) + /* restore flags in standard format */ + env->regs[R_EAX] = EAX; + env->regs[R_EBX] = EBX; + env->regs[R_ECX] = ECX; + env->regs[R_EDX] = EDX; + env->regs[R_ESI] = ESI; + env->regs[R_EDI] = EDI; + env->regs[R_EBP] = EBP; + env->regs[R_ESP] = ESP; + env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); + cpu_x86_dump_state(env, logfile, 0); + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); +#elif defined(TARGET_ARM) + cpu_arm_dump_state(env, logfile, 0); +#else +#error unsupported target CPU +#endif + } +#endif + /* we compute the CPU state. We assume it will not + change during the whole generated block. */ +#if defined(TARGET_I386) + flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; + flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT; + flags |= (((unsigned long)env->seg_cache[R_DS].base | + (unsigned long)env->seg_cache[R_ES].base | + (unsigned long)env->seg_cache[R_SS].base) != 0) << + GEN_FLAG_ADDSEG_SHIFT; + if (!(env->eflags & VM_MASK)) { + flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT; + } else { + /* NOTE: a dummy CPL is kept */ + flags |= (1 << GEN_FLAG_VM_SHIFT); + flags |= (3 << GEN_FLAG_CPL_SHIFT); + } + flags |= (env->eflags & (IOPL_MASK | TF_MASK)); + cs_base = env->seg_cache[R_CS].base; + pc = cs_base + env->eip; +#elif defined(TARGET_ARM) + flags = 0; + cs_base = 0; + pc = (uint8_t *)env->regs[15]; +#else +#error unsupported CPU +#endif + tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, + flags); + if (!tb) { + spin_lock(&tb_lock); + /* if no translated code available, then translate it now */ + tb = tb_alloc((unsigned long)pc); + if (!tb) { + /* flush must be done */ + tb_flush(); + /* cannot fail at this point */ + tb = tb_alloc((unsigned long)pc); + /* don't forget to invalidate previous TB info */ + ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; + T0 = 0; + } + tc_ptr = code_gen_ptr; + tb->tc_ptr = tc_ptr; + tb->cs_base = (unsigned long)cs_base; + tb->flags = flags; + ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); +#if defined(TARGET_I386) + /* XXX: suppress that, this is incorrect */ + /* if invalid instruction, signal it */ + if (ret != 0) { + /* NOTE: the tb is allocated but not linked, so we + can leave it */ + spin_unlock(&tb_lock); + raise_exception(EXCP06_ILLOP); + } +#endif + *ptb = tb; + tb->hash_next = NULL; + tb_link(tb); + code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); + spin_unlock(&tb_lock); + } +#ifdef DEBUG_EXEC + if (loglevel) { + fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", + (long)tb->tc_ptr, (long)tb->pc, + lookup_symbol((void *)tb->pc)); + } +#endif +#ifdef __sparc__ + T0 = tmp_T0; +#endif + /* see if we can patch the calling TB. XXX: remove TF test */ + if (T0 != 0 +#if defined(TARGET_I386) + && !(env->eflags & TF_MASK) +#endif + ) { + spin_lock(&tb_lock); + tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); + spin_unlock(&tb_lock); + } + tc_ptr = tb->tc_ptr; + + /* execute the generated code */ + gen_func = (void *)tc_ptr; +#if defined(__sparc__) + __asm__ __volatile__("call %0\n\t" + "mov %%o7,%%i0" + : /* no outputs */ + : "r" (gen_func) + : "i0", "i1", "i2", "i3", "i4", "i5"); +#elif defined(__arm__) + asm volatile ("mov pc, %0\n\t" + ".global exec_loop\n\t" + "exec_loop:\n\t" + : /* no outputs */ + : "r" (gen_func) + : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); +#else + gen_func(); +#endif + } + } + ret = env->exception_index; + +#if defined(TARGET_I386) + /* restore flags in standard format */ + env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); + + /* restore global registers */ +#ifdef reg_EAX + EAX = saved_EAX; +#endif +#ifdef reg_ECX + ECX = saved_ECX; +#endif +#ifdef reg_EDX + EDX = saved_EDX; +#endif +#ifdef reg_EBX + EBX = saved_EBX; +#endif +#ifdef reg_ESP + ESP = saved_ESP; +#endif +#ifdef reg_EBP + EBP = saved_EBP; +#endif +#ifdef reg_ESI + ESI = saved_ESI; +#endif +#ifdef reg_EDI + EDI = saved_EDI; +#endif +#elif defined(TARGET_ARM) + { + int ZF; + ZF = (env->NZF == 0); + env->cpsr = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); + } +#else +#error unsupported target CPU +#endif +#ifdef __sparc__ + asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); +#endif + T0 = saved_T0; + T1 = saved_T1; + T2 = saved_T2; + env = saved_env; + return ret; +} + +void cpu_interrupt(CPUState *s) +{ + s->interrupt_request = 1; +} + + +#if defined(TARGET_I386) + +void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + if (env->eflags & VM_MASK) { + SegmentCache *sc; + selector &= 0xffff; + sc = &env->seg_cache[seg_reg]; + /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded, + so we must load them here */ + sc->base = (void *)(selector << 4); + sc->limit = 0xffff; + sc->seg_32bit = 0; + env->segs[seg_reg] = selector; + } else { + load_seg(seg_reg, selector, 0); + } + env = saved_env; +} + +void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_fsave(ptr, data32); + + env = saved_env; +} + +void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) +{ + CPUX86State *saved_env; + + saved_env = env; + env = s; + + helper_frstor(ptr, data32); + + env = saved_env; +} + +#endif /* TARGET_I386 */ + +#undef EAX +#undef ECX +#undef EDX +#undef EBX +#undef ESP +#undef EBP +#undef ESI +#undef EDI +#undef EIP +#include +#include + +/* 'pc' is the host PC at which the exception was raised. 'address' is + the effective address of the memory exception. 'is_write' is 1 if a + write caused the exception and otherwise 0'. 'old_set' is the + signal set which should be restored */ +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set) +{ + TranslationBlock *tb; + int ret; + uint32_t found_pc; + +#if defined(DEBUG_SIGNAL) + printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", + pc, address, is_write, *(unsigned long *)old_set); +#endif + /* XXX: locking issue */ + if (is_write && page_unprotect(address)) { + return 1; + } + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + ret = cpu_search_pc(tb, &found_pc, pc); + if (ret < 0) + return 0; +#if defined(TARGET_I386) + env->eip = found_pc - tb->cs_base; + env->cr2 = address; + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); +#elif defined(TARGET_ARM) + env->regs[15] = found_pc; + /* XXX: do more */ +#else +#error unsupported target CPU +#endif + /* never comes here */ + return 1; + } else { + return 0; + } +} + +#if defined(__i386__) + +int cpu_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + struct ucontext *uc = puc; + unsigned long pc; + +#ifndef REG_EIP +/* for glibc 2.1 */ +#define REG_EIP EIP +#define REG_ERR ERR +#define REG_TRAPNO TRAPNO +#endif + pc = uc->uc_mcontext.gregs[REG_EIP]; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? + (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, + &uc->uc_sigmask); +} + +#elif defined(__powerpc) + +int cpu_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + struct ucontext *uc = puc; + struct pt_regs *regs = uc->uc_mcontext.regs; + unsigned long pc; + int is_write; + + pc = regs->nip; + is_write = 0; +#if 0 + /* ppc 4xx case */ + if (regs->dsisr & 0x00800000) + is_write = 1; +#else + if (regs->trap != 0x400 && (regs->dsisr & 0x02000000)) + is_write = 1; +#endif + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask); +} + +#elif defined(__alpha__) + +int cpu_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + struct ucontext *uc = puc; + uint32_t *pc = uc->uc_mcontext.sc_pc; + uint32_t insn = *pc; + int is_write = 0; + + /* XXX: need kernel patch to get write flag faster */ + switch (insn >> 26) { + case 0x0d: // stw + case 0x0e: // stb + case 0x0f: // stq_u + case 0x24: // stf + case 0x25: // stg + case 0x26: // sts + case 0x27: // stt + case 0x2c: // stl + case 0x2d: // stq + case 0x2e: // stl_c + case 0x2f: // stq_c + is_write = 1; + } + + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask); +} +#elif defined(__sparc__) + +int cpu_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + uint32_t *regs = (uint32_t *)(info + 1); + void *sigmask = (regs + 20); + unsigned long pc; + int is_write; + uint32_t insn; + + /* XXX: is there a standard glibc define ? */ + pc = regs[1]; + /* XXX: need kernel patch to get write flag faster */ + is_write = 0; + insn = *(uint32_t *)pc; + if ((insn >> 30) == 3) { + switch((insn >> 19) & 0x3f) { + case 0x05: // stb + case 0x06: // sth + case 0x04: // st + case 0x07: // std + case 0x24: // stf + case 0x27: // stdf + case 0x25: // stfsr + is_write = 1; + break; + } + } + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, sigmask); +} + +#elif defined(__arm__) + +int cpu_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + struct ucontext *uc = puc; + unsigned long pc; + int is_write; + + pc = uc->uc_mcontext.gregs[R15]; + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, + &uc->uc_sigmask); +} + +#else + +#error CPU specific signal handler needed + +#endif diff --git a/exec-i386.c b/exec-i386.c deleted file mode 100644 index c285eb450..000000000 --- a/exec-i386.c +++ /dev/null @@ -1,504 +0,0 @@ -/* - * i386 emulator main execution loop - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "exec-i386.h" -#include "disas.h" - -//#define DEBUG_EXEC -//#define DEBUG_SIGNAL - -/* main execution loop */ - -int cpu_x86_exec(CPUX86State *env1) -{ - int saved_T0, saved_T1, saved_A0; - CPUX86State *saved_env; -#ifdef reg_EAX - int saved_EAX; -#endif -#ifdef reg_ECX - int saved_ECX; -#endif -#ifdef reg_EDX - int saved_EDX; -#endif -#ifdef reg_EBX - int saved_EBX; -#endif -#ifdef reg_ESP - int saved_ESP; -#endif -#ifdef reg_EBP - int saved_EBP; -#endif -#ifdef reg_ESI - int saved_ESI; -#endif -#ifdef reg_EDI - int saved_EDI; -#endif -#ifdef __sparc__ - int saved_i7, tmp_T0; -#endif - int code_gen_size, ret; - void (*gen_func)(void); - TranslationBlock *tb, **ptb; - uint8_t *tc_ptr, *cs_base, *pc; - unsigned int flags; - - /* first we save global registers */ - saved_T0 = T0; - saved_T1 = T1; - saved_A0 = A0; - saved_env = env; - env = env1; -#ifdef reg_EAX - saved_EAX = EAX; - EAX = env->regs[R_EAX]; -#endif -#ifdef reg_ECX - saved_ECX = ECX; - ECX = env->regs[R_ECX]; -#endif -#ifdef reg_EDX - saved_EDX = EDX; - EDX = env->regs[R_EDX]; -#endif -#ifdef reg_EBX - saved_EBX = EBX; - EBX = env->regs[R_EBX]; -#endif -#ifdef reg_ESP - saved_ESP = ESP; - ESP = env->regs[R_ESP]; -#endif -#ifdef reg_EBP - saved_EBP = EBP; - EBP = env->regs[R_EBP]; -#endif -#ifdef reg_ESI - saved_ESI = ESI; - ESI = env->regs[R_ESI]; -#endif -#ifdef reg_EDI - saved_EDI = EDI; - EDI = env->regs[R_EDI]; -#endif -#ifdef __sparc__ - /* we also save i7 because longjmp may not restore it */ - asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); -#endif - - /* put eflags in CPU temporary format */ - CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((env->eflags >> 10) & 1)); - CC_OP = CC_OP_EFLAGS; - env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - env->interrupt_request = 0; - - /* prepare setjmp context for exception handling */ - if (setjmp(env->jmp_env) == 0) { - T0 = 0; /* force lookup of first TB */ - for(;;) { -#ifdef __sparc__ - /* g1 can be modified by some libc? functions */ - tmp_T0 = T0; -#endif - if (env->interrupt_request) { - env->exception_index = EXCP_INTERRUPT; - cpu_loop_exit(); - } -#ifdef DEBUG_EXEC - if (loglevel) { - /* XXX: save all volatile state in cpu state */ - /* restore flags in standard format */ - env->regs[R_EAX] = EAX; - env->regs[R_EBX] = EBX; - env->regs[R_ECX] = ECX; - env->regs[R_EDX] = EDX; - env->regs[R_ESI] = ESI; - env->regs[R_EDI] = EDI; - env->regs[R_EBP] = EBP; - env->regs[R_ESP] = ESP; - env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); - cpu_x86_dump_state(env, logfile, 0); - env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - } -#endif - /* we compute the CPU state. We assume it will not - change during the whole generated block. */ - flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; - flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT; - flags |= (((unsigned long)env->seg_cache[R_DS].base | - (unsigned long)env->seg_cache[R_ES].base | - (unsigned long)env->seg_cache[R_SS].base) != 0) << - GEN_FLAG_ADDSEG_SHIFT; - if (!(env->eflags & VM_MASK)) { - flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT; - } else { - /* NOTE: a dummy CPL is kept */ - flags |= (1 << GEN_FLAG_VM_SHIFT); - flags |= (3 << GEN_FLAG_CPL_SHIFT); - } - flags |= (env->eflags & (IOPL_MASK | TF_MASK)); - cs_base = env->seg_cache[R_CS].base; - pc = cs_base + env->eip; - tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, - flags); - if (!tb) { - spin_lock(&tb_lock); - /* if no translated code available, then translate it now */ - tb = tb_alloc((unsigned long)pc); - if (!tb) { - /* flush must be done */ - tb_flush(); - /* cannot fail at this point */ - tb = tb_alloc((unsigned long)pc); - /* don't forget to invalidate previous TB info */ - ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; - T0 = 0; - } - tc_ptr = code_gen_ptr; - tb->tc_ptr = tc_ptr; - tb->cs_base = (unsigned long)cs_base; - tb->flags = flags; - ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); - /* if invalid instruction, signal it */ - if (ret != 0) { - /* NOTE: the tb is allocated but not linked, so we - can leave it */ - spin_unlock(&tb_lock); - raise_exception(EXCP06_ILLOP); - } - *ptb = tb; - tb->hash_next = NULL; - tb_link(tb); - code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); - spin_unlock(&tb_lock); - } -#ifdef DEBUG_EXEC - if (loglevel) { - fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", - (long)tb->tc_ptr, (long)tb->pc, - lookup_symbol((void *)tb->pc)); - } -#endif -#ifdef __sparc__ - T0 = tmp_T0; -#endif - /* see if we can patch the calling TB */ - if (T0 != 0 && !(env->eflags & TF_MASK)) { - spin_lock(&tb_lock); - tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); - spin_unlock(&tb_lock); - } - tc_ptr = tb->tc_ptr; - - /* execute the generated code */ - gen_func = (void *)tc_ptr; -#if defined(__sparc__) - __asm__ __volatile__("call %0\n\t" - "mov %%o7,%%i0" - : /* no outputs */ - : "r" (gen_func) - : "i0", "i1", "i2", "i3", "i4", "i5"); -#elif defined(__arm__) - asm volatile ("mov pc, %0\n\t" - ".global exec_loop\n\t" - "exec_loop:\n\t" - : /* no outputs */ - : "r" (gen_func) - : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); -#else - gen_func(); -#endif - } - } - ret = env->exception_index; - - /* restore flags in standard format */ - env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); - - /* restore global registers */ -#ifdef reg_EAX - EAX = saved_EAX; -#endif -#ifdef reg_ECX - ECX = saved_ECX; -#endif -#ifdef reg_EDX - EDX = saved_EDX; -#endif -#ifdef reg_EBX - EBX = saved_EBX; -#endif -#ifdef reg_ESP - ESP = saved_ESP; -#endif -#ifdef reg_EBP - EBP = saved_EBP; -#endif -#ifdef reg_ESI - ESI = saved_ESI; -#endif -#ifdef reg_EDI - EDI = saved_EDI; -#endif -#ifdef __sparc__ - asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); -#endif - T0 = saved_T0; - T1 = saved_T1; - A0 = saved_A0; - env = saved_env; - return ret; -} - -void cpu_x86_interrupt(CPUX86State *s) -{ - s->interrupt_request = 1; -} - - -void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) -{ - CPUX86State *saved_env; - - saved_env = env; - env = s; - if (env->eflags & VM_MASK) { - SegmentCache *sc; - selector &= 0xffff; - sc = &env->seg_cache[seg_reg]; - /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded, - so we must load them here */ - sc->base = (void *)(selector << 4); - sc->limit = 0xffff; - sc->seg_32bit = 0; - env->segs[seg_reg] = selector; - } else { - load_seg(seg_reg, selector, 0); - } - env = saved_env; -} - -void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) -{ - CPUX86State *saved_env; - - saved_env = env; - env = s; - - helper_fsave(ptr, data32); - - env = saved_env; -} - -void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) -{ - CPUX86State *saved_env; - - saved_env = env; - env = s; - - helper_frstor(ptr, data32); - - env = saved_env; -} - -#undef EAX -#undef ECX -#undef EDX -#undef EBX -#undef ESP -#undef EBP -#undef ESI -#undef EDI -#undef EIP -#include -#include - -/* 'pc' is the host PC at which the exception was raised. 'address' is - the effective address of the memory exception. 'is_write' is 1 if a - write caused the exception and otherwise 0'. 'old_set' is the - signal set which should be restored */ -static inline int handle_cpu_signal(unsigned long pc, unsigned long address, - int is_write, sigset_t *old_set) -{ - TranslationBlock *tb; - int ret; - uint32_t found_pc; - -#if defined(DEBUG_SIGNAL) - printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", - pc, address, is_write, *(unsigned long *)old_set); -#endif - /* XXX: locking issue */ - if (is_write && page_unprotect(address)) { - return 1; - } - tb = tb_find_pc(pc); - if (tb) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - ret = cpu_x86_search_pc(tb, &found_pc, pc); - if (ret < 0) - return 0; - env->eip = found_pc - tb->cs_base; - env->cr2 = address; - /* we restore the process signal mask as the sigreturn should - do it (XXX: use sigsetjmp) */ - sigprocmask(SIG_SETMASK, old_set, NULL); - raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); - /* never comes here */ - return 1; - } else { - return 0; - } -} - -#if defined(__i386__) - -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, - void *puc) -{ - struct ucontext *uc = puc; - unsigned long pc; - -#ifndef REG_EIP -/* for glibc 2.1 */ -#define REG_EIP EIP -#define REG_ERR ERR -#define REG_TRAPNO TRAPNO -#endif - pc = uc->uc_mcontext.gregs[REG_EIP]; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? - (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, - &uc->uc_sigmask); -} - -#elif defined(__powerpc) - -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, - void *puc) -{ - struct ucontext *uc = puc; - struct pt_regs *regs = uc->uc_mcontext.regs; - unsigned long pc; - int is_write; - - pc = regs->nip; - is_write = 0; -#if 0 - /* ppc 4xx case */ - if (regs->dsisr & 0x00800000) - is_write = 1; -#else - if (regs->trap != 0x400 && (regs->dsisr & 0x02000000)) - is_write = 1; -#endif - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask); -} - -#elif defined(__alpha__) - -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, - void *puc) -{ - struct ucontext *uc = puc; - uint32_t *pc = uc->uc_mcontext.sc_pc; - uint32_t insn = *pc; - int is_write = 0; - - /* XXX: need kernel patch to get write flag faster */ - switch (insn >> 26) { - case 0x0d: // stw - case 0x0e: // stb - case 0x0f: // stq_u - case 0x24: // stf - case 0x25: // stg - case 0x26: // sts - case 0x27: // stt - case 0x2c: // stl - case 0x2d: // stq - case 0x2e: // stl_c - case 0x2f: // stq_c - is_write = 1; - } - - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask); -} -#elif defined(__sparc__) - -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, - void *puc) -{ - uint32_t *regs = (uint32_t *)(info + 1); - void *sigmask = (regs + 20); - unsigned long pc; - int is_write; - uint32_t insn; - - /* XXX: is there a standard glibc define ? */ - pc = regs[1]; - /* XXX: need kernel patch to get write flag faster */ - is_write = 0; - insn = *(uint32_t *)pc; - if ((insn >> 30) == 3) { - switch((insn >> 19) & 0x3f) { - case 0x05: // stb - case 0x06: // sth - case 0x04: // st - case 0x07: // std - case 0x24: // stf - case 0x27: // stdf - case 0x25: // stfsr - is_write = 1; - break; - } - } - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, sigmask); -} - -#elif defined(__arm__) - -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, - void *puc) -{ - struct ucontext *uc = puc; - unsigned long pc; - int is_write; - - pc = uc->uc_mcontext.gregs[R15]; - /* XXX: compute is_write */ - is_write = 0; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, - &uc->uc_sigmask); -} - -#else - -#error CPU specific signal handler needed - -#endif -- cgit v1.2.3 From 24374901004c774e8b932a3526bda6c627942a88 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:52:54 +0000 Subject: fixed serious ioctl parameter conversion issue - exported type size and align functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@239 c046a42c-6fe2-441c-8c8c-71466251a162 --- thunk.c | 76 ++------------------------------------------------------------ thunk.h | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 77 deletions(-) diff --git a/thunk.c b/thunk.c index f28a976cd..b14fb1777 100644 --- a/thunk.c +++ b/thunk.c @@ -29,80 +29,7 @@ #define MAX_STRUCTS 128 /* XXX: make it dynamic */ -static StructEntry struct_entries[MAX_STRUCTS]; - -static inline int thunk_type_size(const argtype *type_ptr, int is_host) -{ - int type, size; - const StructEntry *se; - - type = *type_ptr; - switch(type) { - case TYPE_CHAR: - return 1; - case TYPE_SHORT: - return 2; - case TYPE_INT: - return 4; - case TYPE_LONGLONG: - case TYPE_ULONGLONG: - return 8; - case TYPE_LONG: - case TYPE_ULONG: - case TYPE_PTRVOID: - case TYPE_PTR: - if (is_host) { - return HOST_LONG_SIZE; - } else { - return TARGET_LONG_SIZE; - } - break; - case TYPE_ARRAY: - size = type_ptr[1]; - return size * thunk_type_size(type_ptr + 2, is_host); - case TYPE_STRUCT: - se = struct_entries + type_ptr[1]; - return se->size[is_host]; - default: - return -1; - } -} - -static inline int thunk_type_align(const argtype *type_ptr, int is_host) -{ - int type; - const StructEntry *se; - - type = *type_ptr; - switch(type) { - case TYPE_CHAR: - return 1; - case TYPE_SHORT: - return 2; - case TYPE_INT: - return 4; - case TYPE_LONGLONG: - case TYPE_ULONGLONG: - return 8; - case TYPE_LONG: - case TYPE_ULONG: - case TYPE_PTRVOID: - case TYPE_PTR: - if (is_host) { - return HOST_LONG_SIZE; - } else { - return TARGET_LONG_SIZE; - } - break; - case TYPE_ARRAY: - return thunk_type_align(type_ptr + 2, is_host); - case TYPE_STRUCT: - se = struct_entries + type_ptr[1]; - return se->align[is_host]; - default: - return -1; - } -} +StructEntry struct_entries[MAX_STRUCTS]; static inline const argtype *thunk_type_next(const argtype *type_ptr) { @@ -167,6 +94,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types) offset += size; if (align > max_align) max_align = align; + type_ptr = thunk_type_next(type_ptr); } offset = (offset + max_align - 1) & ~(max_align - 1); se->size[i] = offset; diff --git a/thunk.h b/thunk.h index 9a06847b6..929e47f46 100644 --- a/thunk.h +++ b/thunk.h @@ -61,15 +61,13 @@ #endif -#ifdef WORDS_BIGENDIAN +#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) #define BSWAP_NEEDED #endif /* XXX: autoconf */ -#define TARGET_I386 #define TARGET_LONG_BITS 32 - #if defined(__alpha__) || defined (__ia64__) #define HOST_LONG_BITS 64 #else @@ -239,6 +237,81 @@ void thunk_register_struct_direct(int id, const char *name, StructEntry *se1); const argtype *thunk_convert(void *dst, const void *src, const argtype *type_ptr, int to_host); +extern StructEntry struct_entries[]; + +static inline int thunk_type_size(const argtype *type_ptr, int is_host) +{ + int type, size; + const StructEntry *se; + + type = *type_ptr; + switch(type) { + case TYPE_CHAR: + return 1; + case TYPE_SHORT: + return 2; + case TYPE_INT: + return 4; + case TYPE_LONGLONG: + case TYPE_ULONGLONG: + return 8; + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + case TYPE_PTR: + if (is_host) { + return HOST_LONG_SIZE; + } else { + return TARGET_LONG_SIZE; + } + break; + case TYPE_ARRAY: + size = type_ptr[1]; + return size * thunk_type_size(type_ptr + 2, is_host); + case TYPE_STRUCT: + se = struct_entries + type_ptr[1]; + return se->size[is_host]; + default: + return -1; + } +} + +static inline int thunk_type_align(const argtype *type_ptr, int is_host) +{ + int type; + const StructEntry *se; + + type = *type_ptr; + switch(type) { + case TYPE_CHAR: + return 1; + case TYPE_SHORT: + return 2; + case TYPE_INT: + return 4; + case TYPE_LONGLONG: + case TYPE_ULONGLONG: + return 8; + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + case TYPE_PTR: + if (is_host) { + return HOST_LONG_SIZE; + } else { + return TARGET_LONG_SIZE; + } + break; + case TYPE_ARRAY: + return thunk_type_align(type_ptr + 2, is_host); + case TYPE_STRUCT: + se = struct_entries + type_ptr[1]; + return se->align[is_host]; + default: + return -1; + } +} + unsigned int target_to_host_bitmask(unsigned int x86_mask, bitmask_transtbl * trans_tbl); unsigned int host_to_target_bitmask(unsigned int alpha_mask, -- cgit v1.2.3 From 2ab83ea7849c2a113ab3ebf0c973435117ddf2d0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:56:46 +0000 Subject: automatic ioctl number conversion - minimum ARM fork() support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@240 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 72 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9b02d5eaf..b22642910 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -68,11 +68,6 @@ #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) -void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); -void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); -long do_sigreturn(CPUX86State *env); -long do_rt_sigreturn(CPUX86State *env); - #define __NR_sys_uname __NR_uname #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_statfs __NR_statfs @@ -702,8 +697,8 @@ enum { #undef STRUCT_SPECIAL typedef struct IOCTLEntry { - int target_cmd; - int host_cmd; + unsigned int target_cmd; + unsigned int host_cmd; const char *name; int access; const argtype arg_type[5]; @@ -715,7 +710,7 @@ typedef struct IOCTLEntry { #define MAX_STRUCT_SIZE 4096 -const IOCTLEntry ioctl_entries[] = { +IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, types...) \ { TARGET_ ## cmd, cmd, #cmd, access, { types } }, #include "ioctls.h" @@ -970,7 +965,7 @@ static bitmask_transtbl mmap_flags_tbl[] = { { 0, 0, 0, 0 } }; -#ifdef TARGET_I386 +#if defined(TARGET_I386) /* NOTE: there is really one LDT for all the threads */ uint8_t *ldt_table; @@ -1087,28 +1082,28 @@ int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount return ret; } +#endif /* defined(TARGET_I386) */ + /* this stack is the equivalent of the kernel stack associated with a thread/process */ #define NEW_STACK_SIZE 8192 static int clone_func(void *arg) { - CPUX86State *env = arg; + CPUState *env = arg; cpu_loop(env); /* never exits */ return 0; } -int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) +int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) { int ret; TaskState *ts; uint8_t *new_stack; - CPUX86State *new_env; + CPUState *new_env; if (flags & CLONE_VM) { - if (!newsp) - newsp = env->regs[R_ESP]; ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); memset(ts, 0, sizeof(TaskState)); new_stack = ts->stack; @@ -1117,10 +1112,21 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) ts->next = first_task_state; first_task_state = ts; /* we create a new CPU instance. */ - new_env = cpu_x86_init(); - memcpy(new_env, env, sizeof(CPUX86State)); + new_env = cpu_init(); + memcpy(new_env, env, sizeof(CPUState)); +#if defined(TARGET_I386) + if (!newsp) + newsp = env->regs[R_ESP]; new_env->regs[R_ESP] = newsp; new_env->regs[R_EAX] = 0; +#elif defined(TARGET_ARM) + if (!newsp) + newsp = env->regs[13]; + new_env->regs[13] = newsp; + new_env->regs[0] = 0; +#else +#error unsupported target CPU +#endif new_env->opaque = ts; #ifdef __ia64__ ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); @@ -1136,8 +1142,6 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) return ret; } -#endif - static long do_fcntl(int fd, int cmd, unsigned long arg) { struct flock fl; @@ -1188,11 +1192,43 @@ static long do_fcntl(int fd, int cmd, unsigned long arg) void syscall_init(void) { + IOCTLEntry *ie; + const argtype *arg_type; + int size; + #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); #define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); #include "syscall_types.h" #undef STRUCT #undef STRUCT_SPECIAL + + /* we patch the ioctl size if necessary. We rely on the fact that + no ioctl has all the bits at '1' in the size field */ + ie = ioctl_entries; + while (ie->target_cmd != 0) { + if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) == + TARGET_IOC_SIZEMASK) { + arg_type = ie->arg_type; + if (arg_type[0] != TYPE_PTR) { + fprintf(stderr, "cannot patch size for ioctl 0x%x\n", + ie->target_cmd); + exit(1); + } + arg_type++; + size = thunk_type_size(arg_type, 0); + ie->target_cmd = (ie->target_cmd & + ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) | + (size << TARGET_IOC_SIZESHIFT); + } + /* automatic consistency check if same arch */ +#if defined(__i386__) && defined(TARGET_I386) + if (ie->target_cmd != ie->host_cmd) { + fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n", + ie->target_cmd, ie->host_cmd); + } +#endif + ie++; + } } long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, -- cgit v1.2.3 From 2521d69883285d0bb001036de64e68482ea6f826 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:58:13 +0000 Subject: factorized more definitions - suppressed broken sound ioctls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@241 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ioctls.h | 12 +- linux-user/syscall_defs.h | 987 ++++++++++++++++++++++++++++++++++++++++++++- linux-user/syscall_types.h | 9 + syscall-i386.h | 926 ------------------------------------------ 4 files changed, 1002 insertions(+), 932 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index dc1a37805..daefaec6f 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -150,6 +150,7 @@ IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL) IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT) +#if 0 IOCTL(SNDCTL_COPR_HALT, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_COPR_LOAD, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_COPR_RCODE, IOC_RW, MK_PTR(TYPE_INT)) @@ -160,14 +161,15 @@ IOCTL(SNDCTL_COPR_SENDMSG, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_COPR_WCODE, IOC_W, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_COPR_WDATA, IOC_W, MK_PTR(TYPE_INT)) +#endif IOCTL(SNDCTL_DSP_CHANNELS, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_DSP_GETBLKSIZE, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_DSP_GETCAPS, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_DSP_GETFMTS, IOC_R, MK_PTR(TYPE_INT)) - IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(TYPE_INT)) - IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(TYPE_INT)) - IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(TYPE_INT)) - IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info))) + IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info))) + IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info))) + IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info))) IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT)) @@ -183,6 +185,7 @@ IOCTL(SNDCTL_DSP_STEREO, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_DSP_SUBDIVIDE, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_DSP_SYNC, 0, TYPE_NULL) +#if 0 IOCTL(SNDCTL_FM_4OP_ENABLE, IOC_W, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_FM_LOAD_INSTR, IOC_W, MK_PTR(TYPE_INT)) IOCTL(SNDCTL_MIDI_INFO, IOC_RW, MK_PTR(TYPE_INT)) @@ -222,6 +225,7 @@ IOCTL(SOUND_PCM_READ_CHANNELS, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SOUND_PCM_READ_BITS, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SOUND_PCM_READ_FILTER, IOC_R, MK_PTR(TYPE_INT)) +#endif IOCTL(SOUND_MIXER_INFO, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SOUND_MIXER_ACCESS, 0, TYPE_PTRVOID) IOCTL(SOUND_MIXER_PRIVATE1, IOC_RW, MK_PTR(TYPE_INT)) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index bad9bd848..3826c1290 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1,6 +1,288 @@ - /* common syscall defines for all architectures */ +/* Note: although the syscall numbers change between architectures, + most of them stay the same, so we handle it by puting ifdefs if + necessary */ + +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86old 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_vm86 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread 180 +#define TARGET_NR_pwrite 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 +#define TARGET_NR_getpmsg 188 /* some people actually want streams */ +#define TARGET_NR_putpmsg 189 /* some people actually want streams */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 + +#if defined(TARGET_I386) +#define TARGET_NR_pivot_root 217 +#define TARGET_NR_mincore 218 +#define TARGET_NR_madvise 219 +#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */ +#define TARGET_NR_getdents64 220 +#endif + +#if defined(TARGET_ARM) +#define TARGET_NR_getdents64 217 +#define TARGET_NR_pivot_root 218 +#define TARGET_NR_mincore 219 +#define TARGET_NR_madvise 220 +#endif + +#define TARGET_NR_fcntl64 221 +#define TARGET_NR_security 223 /* syscall for security modules */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_readahead 225 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_set_thread_area 243 +#define TARGET_NR_get_thread_area 244 +#define TARGET_NR_io_setup 245 +#define TARGET_NR_io_destroy 246 +#define TARGET_NR_io_getevents 247 +#define TARGET_NR_io_submit 248 +#define TARGET_NR_io_cancel 249 +#define TARGET_NR_fadvise64 250 + +#define TARGET_NR_exit_group 252 +#define TARGET_NR_lookup_dcookie 253 +#define TARGET_NR_epoll_create 254 +#define TARGET_NR_epoll_ctl 255 +#define TARGET_NR_epoll_wait 256 +#define TARGET_NR_remap_file_pages 257 +#define TARGET_NR_set_tid_address 258 +#define TARGET_NR_timer_create 259 +#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) +#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) +#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) +#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) +#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) +#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) +#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) +#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) + #define SOCKOP_socket 1 #define SOCKOP_bind 2 #define SOCKOP_connect 3 @@ -19,6 +301,66 @@ #define SOCKOP_sendmsg 16 #define SOCKOP_recvmsg 17 +/* + * The following is for compatibility across the various Linux + * platforms. The i386 ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define TARGET_IOC_NRBITS 8 +#define TARGET_IOC_TYPEBITS 8 + +#if defined(TARGET_I386) || defined(TARGET_ARM) + +#define TARGET_IOC_SIZEBITS 14 +#define TARGET_IOC_DIRBITS 2 + +#define TARGET_IOC_NONE 0U +#define TARGET_IOC_WRITE 1U +#define TARGET_IOC_READ 2U + +#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) + +#define TARGET_IOC_SIZEBITS 13 +#define TARGET_IOC_DIRBITS 3 + +#define TARGET_IOC_NONE 1U +#define TARGET_IOC_READ 2U +#define TARGET_IOC_WRITE 4U + +#else +#error unsupported CPU +#endif + +#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1) +#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1) +#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1) +#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1) + +#define TARGET_IOC_NRSHIFT 0 +#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS) +#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS) +#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS) + +#define TARGET_IOC(dir,type,nr,size) \ + (((dir) << TARGET_IOC_DIRSHIFT) | \ + ((type) << TARGET_IOC_TYPESHIFT) | \ + ((nr) << TARGET_IOC_NRSHIFT) | \ + ((size) << TARGET_IOC_SIZESHIFT)) + +/* used to create numbers */ +#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0) +#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size)) +#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size)) +#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size)) + +/* the size is automatically computed for these defines */ +#define TARGET_IORU(type,nr) TARGET_IOC(TARGET_IOC_READ,(type),(nr),TARGET_IOC_SIZEMASK) +#define TARGET_IOWU(type,nr) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK) +#define TARGET_IOWRU(type,nr) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK) + struct target_sockaddr { uint16_t sa_family; uint8_t sa_data[14]; @@ -201,6 +543,168 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); +#if defined(TARGET_I386) || defined(TARGET_ARM) + +#define TARGET_SA_NOCLDSTOP 0x00000001 +#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define TARGET_SA_SIGINFO 0x00000004 +#define TARGET_SA_ONSTACK 0x08000000 +#define TARGET_SA_RESTART 0x10000000 +#define TARGET_SA_NODEFER 0x40000000 +#define TARGET_SA_RESETHAND 0x80000000 +#define TARGET_SA_RESTORER 0x04000000 + +#define TARGET_SIGHUP 1 +#define TARGET_SIGINT 2 +#define TARGET_SIGQUIT 3 +#define TARGET_SIGILL 4 +#define TARGET_SIGTRAP 5 +#define TARGET_SIGABRT 6 +#define TARGET_SIGIOT 6 +#define TARGET_SIGBUS 7 +#define TARGET_SIGFPE 8 +#define TARGET_SIGKILL 9 +#define TARGET_SIGUSR1 10 +#define TARGET_SIGSEGV 11 +#define TARGET_SIGUSR2 12 +#define TARGET_SIGPIPE 13 +#define TARGET_SIGALRM 14 +#define TARGET_SIGTERM 15 +#define TARGET_SIGSTKFLT 16 +#define TARGET_SIGCHLD 17 +#define TARGET_SIGCONT 18 +#define TARGET_SIGSTOP 19 +#define TARGET_SIGTSTP 20 +#define TARGET_SIGTTIN 21 +#define TARGET_SIGTTOU 22 +#define TARGET_SIGURG 23 +#define TARGET_SIGXCPU 24 +#define TARGET_SIGXFSZ 25 +#define TARGET_SIGVTALRM 26 +#define TARGET_SIGPROF 27 +#define TARGET_SIGWINCH 28 +#define TARGET_SIGIO 29 +#define TARGET_SIGRTMIN 32 + +#define TARGET_SIG_BLOCK 0 /* for blocking signals */ +#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */ +#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */ + +struct target_old_sigaction { + target_ulong _sa_handler; + target_ulong sa_mask; + target_ulong sa_flags; + target_ulong sa_restorer; +}; + +struct target_sigaction { + target_ulong _sa_handler; + target_ulong sa_flags; + target_ulong sa_restorer; + target_sigset_t sa_mask; +}; + +typedef union target_sigval { + int sival_int; + target_ulong sival_ptr; +} target_sigval_t; + +#define TARGET_SI_MAX_SIZE 128 +#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3) + +typedef struct target_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[TARGET_SI_PAD_SIZE]; + + /* kill() */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + unsigned int _timer1; + unsigned int _timer2; + } _timer; + + /* POSIX.1b signals */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + target_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + pid_t _pid; /* which child */ + uid_t _uid; /* sender's uid */ + int _status; /* exit code */ + target_clock_t _utime; + target_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + target_ulong _addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} target_siginfo_t; + +/* + * si_code values + * Digital reserves positive values for kernel-generated signals. + */ +#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */ +#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */ +#define TARGET_SI_QUEUE -1 /* sent by sigqueue */ +#define TARGET_SI_TIMER -2 /* sent by timer expiration */ +#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */ +#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */ +#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */ + +/* + * SIGILL si_codes + */ +#define TARGET_ILL_ILLOPN (2) /* illegal operand */ + +/* + * SIGFPE si_codes + */ +#define TARGET_FPE_INTDIV (1) /* integer divide by zero */ +#define TARGET_FPE_INTOVF (2) /* integer overflow */ +#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */ +#define TARGET_FPE_FLTOVF (4) /* floating point overflow */ +#define TARGET_FPE_FLTUND (5) /* floating point underflow */ +#define TARGET_FPE_FLTRES (6) /* floating point inexact result */ +#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */ +#define TARGET_FPE_FLTSUB (8) /* subscript out of range */ +#define TARGET_NSIGFPE 8 + +/* + * SIGSEGV si_codes + */ +#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */ +#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */ + +/* + * SIGTRAP si_codes + */ +#define TARGET_TRAP_BRKPT (1) /* process breakpoint */ +#define TARGET_TRAP_TRACE (2) /* process trace trap */ + +#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */ + struct target_rlimit { target_ulong rlim_cur; target_ulong rlim_max; @@ -219,6 +723,8 @@ struct target_pollfd { #define TARGET_KDGKBENT 0x4B46 /* gets one entry in translation table */ #define TARGET_KDGKBSENT 0x4B48 /* gets one function key string entry */ +#define TARGET_SIOCATMARK 0x8905 + /* Networking ioctls */ #define TARGET_SIOCADDRT 0x890B /* add routing table entry */ #define TARGET_SIOCDELRT 0x890C /* delete routing table entry */ @@ -403,11 +909,11 @@ struct target_pollfd { #define TARGET_HDIO_GETGEO 0x0301 /* get device geometry */ #define TARGET_HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ #define TARGET_HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */ -#define TARGET_HDIO_GET_IDENTITY 0x0307 /* get IDE identification info */ #define TARGET_HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ #define TARGET_HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ #define TARGET_HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */ #define TARGET_HDIO_GET_DMA 0x030b /* get use-dma flag */ +#define TARGET_HDIO_GET_IDENTITY 0x030d /* get IDE identification info */ #define TARGET_HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */ @@ -418,3 +924,480 @@ struct target_pollfd { #define TARGET_HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */ #define TARGET_HDIO_SET_DMA 0x0326 /* change use-dma flag */ #define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ + + +#if defined(TARGET_I386) || defined(TARGET_ARM) + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +#define TARGET_MAP_SHARED 0x01 /* Share changes */ +#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */ +#define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */ +#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ +#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ + +#define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ +#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ + +struct target_stat { + unsigned short st_dev; + unsigned short __pad1; + target_ulong st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + target_ulong st_size; + target_ulong st_blksize; + target_ulong st_blocks; + target_ulong target_st_atime; + target_ulong __unused1; + target_ulong target_st_mtime; + target_ulong __unused2; + target_ulong target_st_ctime; + target_ulong __unused3; + target_ulong __unused4; + target_ulong __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct target_stat64 { + unsigned short st_dev; + unsigned char __pad0[10]; + +#define TARGET_STAT64_HAS_BROKEN_ST_INO 1 + target_ulong __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + target_ulong st_uid; + target_ulong st_gid; + + unsigned short st_rdev; + unsigned char __pad3[10]; + + long long st_size; + target_ulong st_blksize; + + target_ulong st_blocks; /* Number 512-byte blocks allocated. */ + target_ulong __pad4; /* future possible st_blocks high bits */ + + target_ulong target_st_atime; + target_ulong __pad5; + + target_ulong target_st_mtime; + target_ulong __pad6; + + target_ulong target_st_ctime; + target_ulong __pad7; /* will be high 32 bits of ctime someday */ + + unsigned long long st_ino; +} __attribute__((packed)); + +#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */ + +#define TARGET_F_DUPFD 0 /* dup */ +#define TARGET_F_GETFD 1 /* get close_on_exec */ +#define TARGET_F_SETFD 2 /* set/clear close_on_exec */ +#define TARGET_F_GETFL 3 /* get file->f_flags */ +#define TARGET_F_SETFL 4 /* set file->f_flags */ + +#if defined(TARGET_ALPHA) +#define TARGET_F_GETLK 7 +#define TARGET_F_SETLK 8 +#define TARGET_F_SETLKW 9 +#define TARGET_F_SETOWN 5 /* for sockets. */ +#define TARGET_F_GETOWN 6 /* for sockets. */ +#else +#define TARGET_F_GETLK 5 +#define TARGET_F_SETLK 6 +#define TARGET_F_SETLKW 7 +#define TARGET_F_SETOWN 8 /* for sockets. */ +#define TARGET_F_GETOWN 9 /* for sockets. */ +#endif + +#define TARGET_F_SETSIG 10 /* for sockets. */ +#define TARGET_F_GETSIG 11 /* for sockets. */ + +#define TARGET_F_GETLK64 12 /* using 'struct flock64' */ +#define TARGET_F_SETLK64 13 +#define TARGET_F_SETLKW64 14 + +struct target_flock { + short l_type; + short l_whence; + target_ulong l_start; + target_ulong l_len; + int l_pid; +}; + +struct target_flock64 { + short l_type; + short l_whence; + unsigned long long l_start; + unsigned long long l_len; + int l_pid; +}; + + +/* soundcard defines */ +/* XXX: convert them all to arch indepedent entries */ +#define TARGET_SNDCTL_COPR_HALT TARGET_IOWR('C', 7, int); +#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301 +#define TARGET_SNDCTL_COPR_RCODE 0xc0144303 +#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309 +#define TARGET_SNDCTL_COPR_RDATA 0xc0144302 +#define TARGET_SNDCTL_COPR_RESET 0x00004300 +#define TARGET_SNDCTL_COPR_RUN 0xc0144306 +#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308 +#define TARGET_SNDCTL_COPR_WCODE 0x40144305 +#define TARGET_SNDCTL_COPR_WDATA 0x40144304 +#define TARGET_SNDCTL_DSP_RESET TARGET_IO('P', 0) +#define TARGET_SNDCTL_DSP_SYNC TARGET_IO('P', 1) +#define TARGET_SNDCTL_DSP_SPEED TARGET_IOWR('P', 2, int) +#define TARGET_SNDCTL_DSP_STEREO TARGET_IOWR('P', 3, int) +#define TARGET_SNDCTL_DSP_GETBLKSIZE TARGET_IOWR('P', 4, int) +#define TARGET_SNDCTL_DSP_SETFMT TARGET_IOWR('P', 5, int) +#define TARGET_SNDCTL_DSP_CHANNELS TARGET_IOWR('P', 6, int) +#define TARGET_SOUND_PCM_WRITE_FILTER TARGET_IOWR('P', 7, int) +#define TARGET_SNDCTL_DSP_POST TARGET_IO('P', 8) +#define TARGET_SNDCTL_DSP_SUBDIVIDE TARGET_IOWR('P', 9, int) +#define TARGET_SNDCTL_DSP_SETFRAGMENT TARGET_IOWR('P',10, int) +#define TARGET_SNDCTL_DSP_GETFMTS TARGET_IOR('P', 11, int) +#define TARGET_SNDCTL_DSP_GETOSPACE TARGET_IORU('P',12) +#define TARGET_SNDCTL_DSP_GETISPACE TARGET_IORU('P',13) +#define TARGET_SNDCTL_DSP_GETCAPS TARGET_IOR('P', 15, int) +#define TARGET_SNDCTL_DSP_GETTRIGGER TARGET_IOR('P',16, int) +#define TARGET_SNDCTL_DSP_GETIPTR TARGET_IORU('P',17) +#define TARGET_SNDCTL_DSP_GETOPTR TARGET_IORU('P',18) +#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013 +#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014 +#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e +#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005 +#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016 +#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015 +#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010 +#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f +#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107 +#define TARGET_SNDCTL_MIDI_INFO 0xc074510c +#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02 +#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01 +#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00 +#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110 +#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001 +#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103 +#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105 +#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104 +#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b +#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a +#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112 +#define TARGET_SNDCTL_SEQ_PANIC 0x00005111 +#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106 +#define TARGET_SNDCTL_SEQ_RESET 0x00005100 +#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109 +#define TARGET_SNDCTL_SEQ_SYNC 0x00005101 +#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108 +#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d +#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d +#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102 +#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e +#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404 +#define TARGET_SNDCTL_TMR_METRONOME 0x40045407 +#define TARGET_SNDCTL_TMR_SELECT 0x40045408 +#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406 +#define TARGET_SNDCTL_TMR_START 0x00005402 +#define TARGET_SNDCTL_TMR_STOP 0x00005403 +#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405 +#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401 +#define TARGET_SOUND_PCM_READ_RATE 0x80045002 +#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006 +#define TARGET_SOUND_PCM_READ_BITS 0x80045005 +#define TARGET_SOUND_PCM_READ_FILTER 0x80045007 +#define TARGET_SOUND_MIXER_INFO TARGET_IOR ('M', 101, mixer_info) +#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66 +#define TARGET_SOUND_MIXER_PRIVATE1 TARGET_IOWR('M', 111, int) +#define TARGET_SOUND_MIXER_PRIVATE2 TARGET_IOWR('M', 112, int) +#define TARGET_SOUND_MIXER_PRIVATE3 TARGET_IOWR('M', 113, int) +#define TARGET_SOUND_MIXER_PRIVATE4 TARGET_IOWR('M', 114, int) +#define TARGET_SOUND_MIXER_PRIVATE5 TARGET_IOWR('M', 115, int) + +#define TARGET_MIXER_READ(dev) TARGET_IOR('M', dev, int) + +#define TARGET_SOUND_MIXER_READ_VOLUME TARGET_MIXER_READ(SOUND_MIXER_VOLUME) +#define TARGET_SOUND_MIXER_READ_BASS TARGET_MIXER_READ(SOUND_MIXER_BASS) +#define TARGET_SOUND_MIXER_READ_TREBLE TARGET_MIXER_READ(SOUND_MIXER_TREBLE) +#define TARGET_SOUND_MIXER_READ_SYNTH TARGET_MIXER_READ(SOUND_MIXER_SYNTH) +#define TARGET_SOUND_MIXER_READ_PCM TARGET_MIXER_READ(SOUND_MIXER_PCM) +#define TARGET_SOUND_MIXER_READ_SPEAKER TARGET_MIXER_READ(SOUND_MIXER_SPEAKER) +#define TARGET_SOUND_MIXER_READ_LINE TARGET_MIXER_READ(SOUND_MIXER_LINE) +#define TARGET_SOUND_MIXER_READ_MIC TARGET_MIXER_READ(SOUND_MIXER_MIC) +#define TARGET_SOUND_MIXER_READ_CD TARGET_MIXER_READ(SOUND_MIXER_CD) +#define TARGET_SOUND_MIXER_READ_IMIX TARGET_MIXER_READ(SOUND_MIXER_IMIX) +#define TARGET_SOUND_MIXER_READ_ALTPCM TARGET_MIXER_READ(SOUND_MIXER_ALTPCM) +#define TARGET_SOUND_MIXER_READ_RECLEV TARGET_MIXER_READ(SOUND_MIXER_RECLEV) +#define TARGET_SOUND_MIXER_READ_IGAIN TARGET_MIXER_READ(SOUND_MIXER_IGAIN) +#define TARGET_SOUND_MIXER_READ_OGAIN TARGET_MIXER_READ(SOUND_MIXER_OGAIN) +#define TARGET_SOUND_MIXER_READ_LINE1 TARGET_MIXER_READ(SOUND_MIXER_LINE1) +#define TARGET_SOUND_MIXER_READ_LINE2 TARGET_MIXER_READ(SOUND_MIXER_LINE2) +#define TARGET_SOUND_MIXER_READ_LINE3 TARGET_MIXER_READ(SOUND_MIXER_LINE3) + +/* Obsolete macros */ +#define TARGET_SOUND_MIXER_READ_MUTE TARGET_MIXER_READ(SOUND_MIXER_MUTE) +#define TARGET_SOUND_MIXER_READ_ENHANCE TARGET_MIXER_READ(SOUND_MIXER_ENHANCE) +#define TARGET_SOUND_MIXER_READ_LOUD TARGET_MIXER_READ(SOUND_MIXER_LOUD) + +#define TARGET_SOUND_MIXER_READ_RECSRC TARGET_MIXER_READ(SOUND_MIXER_RECSRC) +#define TARGET_SOUND_MIXER_READ_DEVMASK TARGET_MIXER_READ(SOUND_MIXER_DEVMASK) +#define TARGET_SOUND_MIXER_READ_RECMASK TARGET_MIXER_READ(SOUND_MIXER_RECMASK) +#define TARGET_SOUND_MIXER_READ_STEREODEVS TARGET_MIXER_READ(SOUND_MIXER_STEREODEVS) +#define TARGET_SOUND_MIXER_READ_CAPS TARGET_MIXER_READ(SOUND_MIXER_CAPS) + +#define TARGET_MIXER_WRITE(dev) TARGET_IOWR('M', dev, int) + +#define TARGET_SOUND_MIXER_WRITE_VOLUME TARGET_MIXER_WRITE(SOUND_MIXER_VOLUME) +#define TARGET_SOUND_MIXER_WRITE_BASS TARGET_MIXER_WRITE(SOUND_MIXER_BASS) +#define TARGET_SOUND_MIXER_WRITE_TREBLE TARGET_MIXER_WRITE(SOUND_MIXER_TREBLE) +#define TARGET_SOUND_MIXER_WRITE_SYNTH TARGET_MIXER_WRITE(SOUND_MIXER_SYNTH) +#define TARGET_SOUND_MIXER_WRITE_PCM TARGET_MIXER_WRITE(SOUND_MIXER_PCM) +#define TARGET_SOUND_MIXER_WRITE_SPEAKER TARGET_MIXER_WRITE(SOUND_MIXER_SPEAKER) +#define TARGET_SOUND_MIXER_WRITE_LINE TARGET_MIXER_WRITE(SOUND_MIXER_LINE) +#define TARGET_SOUND_MIXER_WRITE_MIC TARGET_MIXER_WRITE(SOUND_MIXER_MIC) +#define TARGET_SOUND_MIXER_WRITE_CD TARGET_MIXER_WRITE(SOUND_MIXER_CD) +#define TARGET_SOUND_MIXER_WRITE_IMIX TARGET_MIXER_WRITE(SOUND_MIXER_IMIX) +#define TARGET_SOUND_MIXER_WRITE_ALTPCM TARGET_MIXER_WRITE(SOUND_MIXER_ALTPCM) +#define TARGET_SOUND_MIXER_WRITE_RECLEV TARGET_MIXER_WRITE(SOUND_MIXER_RECLEV) +#define TARGET_SOUND_MIXER_WRITE_IGAIN TARGET_MIXER_WRITE(SOUND_MIXER_IGAIN) +#define TARGET_SOUND_MIXER_WRITE_OGAIN TARGET_MIXER_WRITE(SOUND_MIXER_OGAIN) +#define TARGET_SOUND_MIXER_WRITE_LINE1 TARGET_MIXER_WRITE(SOUND_MIXER_LINE1) +#define TARGET_SOUND_MIXER_WRITE_LINE2 TARGET_MIXER_WRITE(SOUND_MIXER_LINE2) +#define TARGET_SOUND_MIXER_WRITE_LINE3 TARGET_MIXER_WRITE(SOUND_MIXER_LINE3) + +/* Obsolete macros */ +#define TARGET_SOUND_MIXER_WRITE_MUTE TARGET_MIXER_WRITE(SOUND_MIXER_MUTE) +#define TARGET_SOUND_MIXER_WRITE_ENHANCE TARGET_MIXER_WRITE(SOUND_MIXER_ENHANCE) +#define TARGET_SOUND_MIXER_WRITE_LOUD TARGET_MIXER_WRITE(SOUND_MIXER_LOUD) + +#define TARGET_SOUND_MIXER_WRITE_RECSRC TARGET_MIXER_WRITE(SOUND_MIXER_RECSRC) + +/* vfat ioctls */ +#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1) +#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2) diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 093a12207..4db47da0f 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -67,3 +67,12 @@ STRUCT(dirent, STRUCT(kbentry, TYPE_CHAR, TYPE_CHAR, TYPE_SHORT) + +STRUCT(audio_buf_info, + TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT) + +STRUCT(count_info, + TYPE_INT, TYPE_INT, TYPE_INT) + +STRUCT(mixer_info, + MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10)) diff --git a/syscall-i386.h b/syscall-i386.h index ea482bbbb..e1f470d78 100644 --- a/syscall-i386.h +++ b/syscall-i386.h @@ -1,491 +1,3 @@ -/* from linux/unistd.h */ - -#define TARGET_NR_exit 1 -#define TARGET_NR_fork 2 -#define TARGET_NR_read 3 -#define TARGET_NR_write 4 -#define TARGET_NR_open 5 -#define TARGET_NR_close 6 -#define TARGET_NR_waitpid 7 -#define TARGET_NR_creat 8 -#define TARGET_NR_link 9 -#define TARGET_NR_unlink 10 -#define TARGET_NR_execve 11 -#define TARGET_NR_chdir 12 -#define TARGET_NR_time 13 -#define TARGET_NR_mknod 14 -#define TARGET_NR_chmod 15 -#define TARGET_NR_lchown 16 -#define TARGET_NR_break 17 -#define TARGET_NR_oldstat 18 -#define TARGET_NR_lseek 19 -#define TARGET_NR_getpid 20 -#define TARGET_NR_mount 21 -#define TARGET_NR_umount 22 -#define TARGET_NR_setuid 23 -#define TARGET_NR_getuid 24 -#define TARGET_NR_stime 25 -#define TARGET_NR_ptrace 26 -#define TARGET_NR_alarm 27 -#define TARGET_NR_oldfstat 28 -#define TARGET_NR_pause 29 -#define TARGET_NR_utime 30 -#define TARGET_NR_stty 31 -#define TARGET_NR_gtty 32 -#define TARGET_NR_access 33 -#define TARGET_NR_nice 34 -#define TARGET_NR_ftime 35 -#define TARGET_NR_sync 36 -#define TARGET_NR_kill 37 -#define TARGET_NR_rename 38 -#define TARGET_NR_mkdir 39 -#define TARGET_NR_rmdir 40 -#define TARGET_NR_dup 41 -#define TARGET_NR_pipe 42 -#define TARGET_NR_times 43 -#define TARGET_NR_prof 44 -#define TARGET_NR_brk 45 -#define TARGET_NR_setgid 46 -#define TARGET_NR_getgid 47 -#define TARGET_NR_signal 48 -#define TARGET_NR_geteuid 49 -#define TARGET_NR_getegid 50 -#define TARGET_NR_acct 51 -#define TARGET_NR_umount2 52 -#define TARGET_NR_lock 53 -#define TARGET_NR_ioctl 54 -#define TARGET_NR_fcntl 55 -#define TARGET_NR_mpx 56 -#define TARGET_NR_setpgid 57 -#define TARGET_NR_ulimit 58 -#define TARGET_NR_oldolduname 59 -#define TARGET_NR_umask 60 -#define TARGET_NR_chroot 61 -#define TARGET_NR_ustat 62 -#define TARGET_NR_dup2 63 -#define TARGET_NR_getppid 64 -#define TARGET_NR_getpgrp 65 -#define TARGET_NR_setsid 66 -#define TARGET_NR_sigaction 67 -#define TARGET_NR_sgetmask 68 -#define TARGET_NR_ssetmask 69 -#define TARGET_NR_setreuid 70 -#define TARGET_NR_setregid 71 -#define TARGET_NR_sigsuspend 72 -#define TARGET_NR_sigpending 73 -#define TARGET_NR_sethostname 74 -#define TARGET_NR_setrlimit 75 -#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ -#define TARGET_NR_getrusage 77 -#define TARGET_NR_gettimeofday 78 -#define TARGET_NR_settimeofday 79 -#define TARGET_NR_getgroups 80 -#define TARGET_NR_setgroups 81 -#define TARGET_NR_select 82 -#define TARGET_NR_symlink 83 -#define TARGET_NR_oldlstat 84 -#define TARGET_NR_readlink 85 -#define TARGET_NR_uselib 86 -#define TARGET_NR_swapon 87 -#define TARGET_NR_reboot 88 -#define TARGET_NR_readdir 89 -#define TARGET_NR_mmap 90 -#define TARGET_NR_munmap 91 -#define TARGET_NR_truncate 92 -#define TARGET_NR_ftruncate 93 -#define TARGET_NR_fchmod 94 -#define TARGET_NR_fchown 95 -#define TARGET_NR_getpriority 96 -#define TARGET_NR_setpriority 97 -#define TARGET_NR_profil 98 -#define TARGET_NR_statfs 99 -#define TARGET_NR_fstatfs 100 -#define TARGET_NR_ioperm 101 -#define TARGET_NR_socketcall 102 -#define TARGET_NR_syslog 103 -#define TARGET_NR_setitimer 104 -#define TARGET_NR_getitimer 105 -#define TARGET_NR_stat 106 -#define TARGET_NR_lstat 107 -#define TARGET_NR_fstat 108 -#define TARGET_NR_olduname 109 -#define TARGET_NR_iopl 110 -#define TARGET_NR_vhangup 111 -#define TARGET_NR_idle 112 -#define TARGET_NR_vm86old 113 -#define TARGET_NR_wait4 114 -#define TARGET_NR_swapoff 115 -#define TARGET_NR_sysinfo 116 -#define TARGET_NR_ipc 117 -#define TARGET_NR_fsync 118 -#define TARGET_NR_sigreturn 119 -#define TARGET_NR_clone 120 -#define TARGET_NR_setdomainname 121 -#define TARGET_NR_uname 122 -#define TARGET_NR_modify_ldt 123 -#define TARGET_NR_adjtimex 124 -#define TARGET_NR_mprotect 125 -#define TARGET_NR_sigprocmask 126 -#define TARGET_NR_create_module 127 -#define TARGET_NR_init_module 128 -#define TARGET_NR_delete_module 129 -#define TARGET_NR_get_kernel_syms 130 -#define TARGET_NR_quotactl 131 -#define TARGET_NR_getpgid 132 -#define TARGET_NR_fchdir 133 -#define TARGET_NR_bdflush 134 -#define TARGET_NR_sysfs 135 -#define TARGET_NR_personality 136 -#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ -#define TARGET_NR_setfsuid 138 -#define TARGET_NR_setfsgid 139 -#define TARGET_NR__llseek 140 -#define TARGET_NR_getdents 141 -#define TARGET_NR__newselect 142 -#define TARGET_NR_flock 143 -#define TARGET_NR_msync 144 -#define TARGET_NR_readv 145 -#define TARGET_NR_writev 146 -#define TARGET_NR_getsid 147 -#define TARGET_NR_fdatasync 148 -#define TARGET_NR__sysctl 149 -#define TARGET_NR_mlock 150 -#define TARGET_NR_munlock 151 -#define TARGET_NR_mlockall 152 -#define TARGET_NR_munlockall 153 -#define TARGET_NR_sched_setparam 154 -#define TARGET_NR_sched_getparam 155 -#define TARGET_NR_sched_setscheduler 156 -#define TARGET_NR_sched_getscheduler 157 -#define TARGET_NR_sched_yield 158 -#define TARGET_NR_sched_get_priority_max 159 -#define TARGET_NR_sched_get_priority_min 160 -#define TARGET_NR_sched_rr_get_interval 161 -#define TARGET_NR_nanosleep 162 -#define TARGET_NR_mremap 163 -#define TARGET_NR_setresuid 164 -#define TARGET_NR_getresuid 165 -#define TARGET_NR_vm86 166 -#define TARGET_NR_query_module 167 -#define TARGET_NR_poll 168 -#define TARGET_NR_nfsservctl 169 -#define TARGET_NR_setresgid 170 -#define TARGET_NR_getresgid 171 -#define TARGET_NR_prctl 172 -#define TARGET_NR_rt_sigreturn 173 -#define TARGET_NR_rt_sigaction 174 -#define TARGET_NR_rt_sigprocmask 175 -#define TARGET_NR_rt_sigpending 176 -#define TARGET_NR_rt_sigtimedwait 177 -#define TARGET_NR_rt_sigqueueinfo 178 -#define TARGET_NR_rt_sigsuspend 179 -#define TARGET_NR_pread 180 -#define TARGET_NR_pwrite 181 -#define TARGET_NR_chown 182 -#define TARGET_NR_getcwd 183 -#define TARGET_NR_capget 184 -#define TARGET_NR_capset 185 -#define TARGET_NR_sigaltstack 186 -#define TARGET_NR_sendfile 187 -#define TARGET_NR_getpmsg 188 /* some people actually want streams */ -#define TARGET_NR_putpmsg 189 /* some people actually want streams */ -#define TARGET_NR_vfork 190 -#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ -#define TARGET_NR_mmap2 192 -#define TARGET_NR_truncate64 193 -#define TARGET_NR_ftruncate64 194 -#define TARGET_NR_stat64 195 -#define TARGET_NR_lstat64 196 -#define TARGET_NR_fstat64 197 -#define TARGET_NR_lchown32 198 -#define TARGET_NR_getuid32 199 -#define TARGET_NR_getgid32 200 -#define TARGET_NR_geteuid32 201 -#define TARGET_NR_getegid32 202 -#define TARGET_NR_setreuid32 203 -#define TARGET_NR_setregid32 204 -#define TARGET_NR_getgroups32 205 -#define TARGET_NR_setgroups32 206 -#define TARGET_NR_fchown32 207 -#define TARGET_NR_setresuid32 208 -#define TARGET_NR_getresuid32 209 -#define TARGET_NR_setresgid32 210 -#define TARGET_NR_getresgid32 211 -#define TARGET_NR_chown32 212 -#define TARGET_NR_setuid32 213 -#define TARGET_NR_setgid32 214 -#define TARGET_NR_setfsuid32 215 -#define TARGET_NR_setfsgid32 216 -#define TARGET_NR_pivot_root 217 -#define TARGET_NR_mincore 218 -#define TARGET_NR_madvise 219 -#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */ -#define TARGET_NR_getdents64 220 -#define TARGET_NR_fcntl64 221 -#define TARGET_NR_security 223 /* syscall for security modules */ -#define TARGET_NR_gettid 224 -#define TARGET_NR_readahead 225 -#define TARGET_NR_setxattr 226 -#define TARGET_NR_lsetxattr 227 -#define TARGET_NR_fsetxattr 228 -#define TARGET_NR_getxattr 229 -#define TARGET_NR_lgetxattr 230 -#define TARGET_NR_fgetxattr 231 -#define TARGET_NR_listxattr 232 -#define TARGET_NR_llistxattr 233 -#define TARGET_NR_flistxattr 234 -#define TARGET_NR_removexattr 235 -#define TARGET_NR_lremovexattr 236 -#define TARGET_NR_fremovexattr 237 -#define TARGET_NR_tkill 238 -#define TARGET_NR_sendfile64 239 -#define TARGET_NR_futex 240 -#define TARGET_NR_sched_setaffinity 241 -#define TARGET_NR_sched_getaffinity 242 -#define TARGET_NR_set_thread_area 243 -#define TARGET_NR_get_thread_area 244 -#define TARGET_NR_io_setup 245 -#define TARGET_NR_io_destroy 246 -#define TARGET_NR_io_getevents 247 -#define TARGET_NR_io_submit 248 -#define TARGET_NR_io_cancel 249 -#define TARGET_NR_fadvise64 250 - -#define TARGET_NR_exit_group 252 -#define TARGET_NR_lookup_dcookie 253 -#define TARGET_NR_epoll_create 254 -#define TARGET_NR_epoll_ctl 255 -#define TARGET_NR_epoll_wait 256 -#define TARGET_NR_remap_file_pages 257 -#define TARGET_NR_set_tid_address 258 -#define TARGET_NR_timer_create 259 -#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) -#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) -#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) -#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) -#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) -#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) -#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) -#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) - -#define TARGET_SIG_BLOCK 0 /* for blocking signals */ -#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */ -#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */ - -struct target_stat { - unsigned short st_dev; - unsigned short __pad1; - target_ulong st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - unsigned short st_rdev; - unsigned short __pad2; - target_ulong st_size; - target_ulong st_blksize; - target_ulong st_blocks; - target_ulong target_st_atime; - target_ulong __unused1; - target_ulong target_st_mtime; - target_ulong __unused2; - target_ulong target_st_ctime; - target_ulong __unused3; - target_ulong __unused4; - target_ulong __unused5; -}; - -/* This matches struct stat64 in glibc2.1, hence the absolutely - * insane amounts of padding around dev_t's. - */ -struct target_stat64 { - unsigned short st_dev; - unsigned char __pad0[10]; - -#define TARGET_STAT64_HAS_BROKEN_ST_INO 1 - target_ulong __st_ino; - - unsigned int st_mode; - unsigned int st_nlink; - - target_ulong st_uid; - target_ulong st_gid; - - unsigned short st_rdev; - unsigned char __pad3[10]; - - long long st_size; - target_ulong st_blksize; - - target_ulong st_blocks; /* Number 512-byte blocks allocated. */ - target_ulong __pad4; /* future possible st_blocks high bits */ - - target_ulong target_st_atime; - target_ulong __pad5; - - target_ulong target_st_mtime; - target_ulong __pad6; - - target_ulong target_st_ctime; - target_ulong __pad7; /* will be high 32 bits of ctime someday */ - - unsigned long long st_ino; -} __attribute__((packed)); - -#define TARGET_SA_NOCLDSTOP 0x00000001 -#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ -#define TARGET_SA_SIGINFO 0x00000004 -#define TARGET_SA_ONSTACK 0x08000000 -#define TARGET_SA_RESTART 0x10000000 -#define TARGET_SA_NODEFER 0x40000000 -#define TARGET_SA_RESETHAND 0x80000000 -#define TARGET_SA_RESTORER 0x04000000 - -#define TARGET_SIGHUP 1 -#define TARGET_SIGINT 2 -#define TARGET_SIGQUIT 3 -#define TARGET_SIGILL 4 -#define TARGET_SIGTRAP 5 -#define TARGET_SIGABRT 6 -#define TARGET_SIGIOT 6 -#define TARGET_SIGBUS 7 -#define TARGET_SIGFPE 8 -#define TARGET_SIGKILL 9 -#define TARGET_SIGUSR1 10 -#define TARGET_SIGSEGV 11 -#define TARGET_SIGUSR2 12 -#define TARGET_SIGPIPE 13 -#define TARGET_SIGALRM 14 -#define TARGET_SIGTERM 15 -#define TARGET_SIGSTKFLT 16 -#define TARGET_SIGCHLD 17 -#define TARGET_SIGCONT 18 -#define TARGET_SIGSTOP 19 -#define TARGET_SIGTSTP 20 -#define TARGET_SIGTTIN 21 -#define TARGET_SIGTTOU 22 -#define TARGET_SIGURG 23 -#define TARGET_SIGXCPU 24 -#define TARGET_SIGXFSZ 25 -#define TARGET_SIGVTALRM 26 -#define TARGET_SIGPROF 27 -#define TARGET_SIGWINCH 28 -#define TARGET_SIGIO 29 -#define TARGET_SIGRTMIN 32 - -struct target_old_sigaction { - target_ulong _sa_handler; - target_ulong sa_mask; - target_ulong sa_flags; - target_ulong sa_restorer; -}; - -struct target_sigaction { - target_ulong _sa_handler; - target_ulong sa_flags; - target_ulong sa_restorer; - target_sigset_t sa_mask; -}; - -typedef union target_sigval { - int sival_int; - target_ulong sival_ptr; -} target_sigval_t; - -#define TARGET_SI_MAX_SIZE 128 -#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3) - -typedef struct target_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[TARGET_SI_PAD_SIZE]; - - /* kill() */ - struct { - pid_t _pid; /* sender's pid */ - uid_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - unsigned int _timer1; - unsigned int _timer2; - } _timer; - - /* POSIX.1b signals */ - struct { - pid_t _pid; /* sender's pid */ - uid_t _uid; /* sender's uid */ - target_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - pid_t _pid; /* which child */ - uid_t _uid; /* sender's uid */ - int _status; /* exit code */ - target_clock_t _utime; - target_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - target_ulong _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} target_siginfo_t; - -/* - * si_code values - * Digital reserves positive values for kernel-generated signals. - */ -#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */ -#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */ -#define TARGET_SI_QUEUE -1 /* sent by sigqueue */ -#define TARGET_SI_TIMER -2 /* sent by timer expiration */ -#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */ -#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */ -#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */ - -/* - * SIGILL si_codes - */ -#define TARGET_ILL_ILLOPN (2) /* illegal operand */ - -/* - * SIGFPE si_codes - */ -#define TARGET_FPE_INTDIV (1) /* integer divide by zero */ -#define TARGET_FPE_INTOVF (2) /* integer overflow */ -#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */ -#define TARGET_FPE_FLTOVF (4) /* floating point overflow */ -#define TARGET_FPE_FLTUND (5) /* floating point underflow */ -#define TARGET_FPE_FLTRES (6) /* floating point inexact result */ -#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */ -#define TARGET_FPE_FLTSUB (8) /* subscript out of range */ -#define TARGET_NSIGFPE 8 - -/* - * SIGSEGV si_codes - */ -#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */ -#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */ - -/* - * SIGTRAP si_codes - */ -#define TARGET_TRAP_BRKPT (1) /* process breakpoint */ -#define TARGET_TRAP_TRACE (2) /* process trace trap */ - /* default linux values for the selectors */ #define __USER_CS (0x23) #define __USER_DS (0x2B) @@ -510,261 +22,6 @@ struct target_pt_regs { /* ioctls */ -/* - * The following is for compatibility across the various Linux - * platforms. The i386 ioctl numbering scheme doesn't really enforce - * a type field. De facto, however, the top 8 bits of the lower 16 - * bits are indeed used as a type field, so we might just as well make - * this explicit here. Please be sure to use the decoding macros - * below from now on. - */ -#define TARGET_IOC_NRBITS 8 -#define TARGET_IOC_TYPEBITS 8 -#define TARGET_IOC_SIZEBITS 14 -#define TARGET_IOC_DIRBITS 2 - -#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1) -#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1) -#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1) -#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1) - -#define TARGET_IOC_NRSHIFT 0 -#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS) -#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS) -#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS) - -/* - * Direction bits. - */ -#define TARGET_IOC_NONE 0U -#define TARGET_IOC_WRITE 1U -#define TARGET_IOC_READ 2U - -#define TARGET_IOC(dir,type,nr,size) \ - (((dir) << TARGET_IOC_DIRSHIFT) | \ - ((type) << TARGET_IOC_TYPESHIFT) | \ - ((nr) << TARGET_IOC_NRSHIFT) | \ - ((size) << TARGET_IOC_SIZESHIFT)) - -/* used to create numbers */ -#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0) -#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size)) -#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size)) -#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size)) - -/* 0x54 is just a magic number to make these relatively unique ('T') */ - -#define TARGET_TCGETS 0x5401 -#define TARGET_TCSETS 0x5402 -#define TARGET_TCSETSW 0x5403 -#define TARGET_TCSETSF 0x5404 -#define TARGET_TCGETA 0x5405 -#define TARGET_TCSETA 0x5406 -#define TARGET_TCSETAW 0x5407 -#define TARGET_TCSETAF 0x5408 -#define TARGET_TCSBRK 0x5409 -#define TARGET_TCXONC 0x540A -#define TARGET_TCFLSH 0x540B -#define TARGET_TIOCEXCL 0x540C -#define TARGET_TIOCNXCL 0x540D -#define TARGET_TIOCSCTTY 0x540E -#define TARGET_TIOCGPGRP 0x540F -#define TARGET_TIOCSPGRP 0x5410 -#define TARGET_TIOCOUTQ 0x5411 -#define TARGET_TIOCSTI 0x5412 -#define TARGET_TIOCGWINSZ 0x5413 -#define TARGET_TIOCSWINSZ 0x5414 -#define TARGET_TIOCMGET 0x5415 -#define TARGET_TIOCMBIS 0x5416 -#define TARGET_TIOCMBIC 0x5417 -#define TARGET_TIOCMSET 0x5418 -#define TARGET_TIOCGSOFTCAR 0x5419 -#define TARGET_TIOCSSOFTCAR 0x541A -#define TARGET_FIONREAD 0x541B -#define TARGET_TIOCINQ FIONREAD -#define TARGET_TIOCLINUX 0x541C -#define TARGET_TIOCCONS 0x541D -#define TARGET_TIOCGSERIAL 0x541E -#define TARGET_TIOCSSERIAL 0x541F -#define TARGET_TIOCPKT 0x5420 -#define TARGET_FIONBIO 0x5421 -#define TARGET_TIOCNOTTY 0x5422 -#define TARGET_TIOCSETD 0x5423 -#define TARGET_TIOCGETD 0x5424 -#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ -#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ -#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ -#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ - -#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ -#define TARGET_FIOCLEX 0x5451 -#define TARGET_FIOASYNC 0x5452 -#define TARGET_TIOCSERCONFIG 0x5453 -#define TARGET_TIOCSERGWILD 0x5454 -#define TARGET_TIOCSERSWILD 0x5455 -#define TARGET_TIOCGLCKTRMIOS 0x5456 -#define TARGET_TIOCSLCKTRMIOS 0x5457 -#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ - -#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ - -/* Used for packet mode */ -#define TARGET_TIOCPKT_DATA 0 -#define TARGET_TIOCPKT_FLUSHREAD 1 -#define TARGET_TIOCPKT_FLUSHWRITE 2 -#define TARGET_TIOCPKT_STOP 4 -#define TARGET_TIOCPKT_START 8 -#define TARGET_TIOCPKT_NOSTOP 16 -#define TARGET_TIOCPKT_DOSTOP 32 - -#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ - -/* from asm/termbits.h */ - -#define TARGET_NCCS 19 - -struct target_termios { - unsigned int c_iflag; /* input mode flags */ - unsigned int c_oflag; /* output mode flags */ - unsigned int c_cflag; /* control mode flags */ - unsigned int c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[TARGET_NCCS]; /* control characters */ -}; - -/* c_iflag bits */ -#define TARGET_IGNBRK 0000001 -#define TARGET_BRKINT 0000002 -#define TARGET_IGNPAR 0000004 -#define TARGET_PARMRK 0000010 -#define TARGET_INPCK 0000020 -#define TARGET_ISTRIP 0000040 -#define TARGET_INLCR 0000100 -#define TARGET_IGNCR 0000200 -#define TARGET_ICRNL 0000400 -#define TARGET_IUCLC 0001000 -#define TARGET_IXON 0002000 -#define TARGET_IXANY 0004000 -#define TARGET_IXOFF 0010000 -#define TARGET_IMAXBEL 0020000 - -/* c_oflag bits */ -#define TARGET_OPOST 0000001 -#define TARGET_OLCUC 0000002 -#define TARGET_ONLCR 0000004 -#define TARGET_OCRNL 0000010 -#define TARGET_ONOCR 0000020 -#define TARGET_ONLRET 0000040 -#define TARGET_OFILL 0000100 -#define TARGET_OFDEL 0000200 -#define TARGET_NLDLY 0000400 -#define TARGET_NL0 0000000 -#define TARGET_NL1 0000400 -#define TARGET_CRDLY 0003000 -#define TARGET_CR0 0000000 -#define TARGET_CR1 0001000 -#define TARGET_CR2 0002000 -#define TARGET_CR3 0003000 -#define TARGET_TABDLY 0014000 -#define TARGET_TAB0 0000000 -#define TARGET_TAB1 0004000 -#define TARGET_TAB2 0010000 -#define TARGET_TAB3 0014000 -#define TARGET_XTABS 0014000 -#define TARGET_BSDLY 0020000 -#define TARGET_BS0 0000000 -#define TARGET_BS1 0020000 -#define TARGET_VTDLY 0040000 -#define TARGET_VT0 0000000 -#define TARGET_VT1 0040000 -#define TARGET_FFDLY 0100000 -#define TARGET_FF0 0000000 -#define TARGET_FF1 0100000 - -/* c_cflag bit meaning */ -#define TARGET_CBAUD 0010017 -#define TARGET_B0 0000000 /* hang up */ -#define TARGET_B50 0000001 -#define TARGET_B75 0000002 -#define TARGET_B110 0000003 -#define TARGET_B134 0000004 -#define TARGET_B150 0000005 -#define TARGET_B200 0000006 -#define TARGET_B300 0000007 -#define TARGET_B600 0000010 -#define TARGET_B1200 0000011 -#define TARGET_B1800 0000012 -#define TARGET_B2400 0000013 -#define TARGET_B4800 0000014 -#define TARGET_B9600 0000015 -#define TARGET_B19200 0000016 -#define TARGET_B38400 0000017 -#define TARGET_EXTA B19200 -#define TARGET_EXTB B38400 -#define TARGET_CSIZE 0000060 -#define TARGET_CS5 0000000 -#define TARGET_CS6 0000020 -#define TARGET_CS7 0000040 -#define TARGET_CS8 0000060 -#define TARGET_CSTOPB 0000100 -#define TARGET_CREAD 0000200 -#define TARGET_PARENB 0000400 -#define TARGET_PARODD 0001000 -#define TARGET_HUPCL 0002000 -#define TARGET_CLOCAL 0004000 -#define TARGET_CBAUDEX 0010000 -#define TARGET_B57600 0010001 -#define TARGET_B115200 0010002 -#define TARGET_B230400 0010003 -#define TARGET_B460800 0010004 -#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -#define TARGET_CRTSCTS 020000000000 /* flow control */ - -/* c_lflag bits */ -#define TARGET_ISIG 0000001 -#define TARGET_ICANON 0000002 -#define TARGET_XCASE 0000004 -#define TARGET_ECHO 0000010 -#define TARGET_ECHOE 0000020 -#define TARGET_ECHOK 0000040 -#define TARGET_ECHONL 0000100 -#define TARGET_NOFLSH 0000200 -#define TARGET_TOSTOP 0000400 -#define TARGET_ECHOCTL 0001000 -#define TARGET_ECHOPRT 0002000 -#define TARGET_ECHOKE 0004000 -#define TARGET_FLUSHO 0010000 -#define TARGET_PENDIN 0040000 -#define TARGET_IEXTEN 0100000 - -/* c_cc character offsets */ -#define TARGET_VINTR 0 -#define TARGET_VQUIT 1 -#define TARGET_VERASE 2 -#define TARGET_VKILL 3 -#define TARGET_VEOF 4 -#define TARGET_VTIME 5 -#define TARGET_VMIN 6 -#define TARGET_VSWTC 7 -#define TARGET_VSTART 8 -#define TARGET_VSTOP 9 -#define TARGET_VSUSP 10 -#define TARGET_VEOL 11 -#define TARGET_VREPRINT 12 -#define TARGET_VDISCARD 13 -#define TARGET_VWERASE 14 -#define TARGET_VLNEXT 15 -#define TARGET_VEOL2 16 - #define TARGET_LDT_ENTRIES 8192 #define TARGET_LDT_ENTRY_SIZE 8 @@ -779,19 +36,6 @@ struct target_modify_ldt_ldt_s { unsigned int flags; }; - -#define TARGET_MAP_SHARED 0x01 /* Share changes */ -#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */ -#define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */ -#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ -#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ - -#define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ -#define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ -#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ -#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ - /* vm86 defines */ #define TARGET_BIOSSEG 0x0f000 @@ -922,11 +166,6 @@ struct target_ipc_kludge { int msgtyp; }; -struct alpha_msgbuf { - long mtype; - char mtext[4096]; -}; - struct target_ipc_perm { int key; unsigned short uid; @@ -979,168 +218,3 @@ union target_semun { unsigned int __pad; /* really void* */ }; -#define TARGET_F_DUPFD 0 /* dup */ -#define TARGET_F_GETFD 1 /* get close_on_exec */ -#define TARGET_F_SETFD 2 /* set/clear close_on_exec */ -#define TARGET_F_GETFL 3 /* get file->f_flags */ -#define TARGET_F_SETFL 4 /* set file->f_flags */ -#define TARGET_F_GETLK 5 -#define TARGET_F_SETLK 6 -#define TARGET_F_SETLKW 7 - -#define TARGET_F_SETOWN 8 /* for sockets. */ -#define TARGET_F_GETOWN 9 /* for sockets. */ -#define TARGET_F_SETSIG 10 /* for sockets. */ -#define TARGET_F_GETSIG 11 /* for sockets. */ - -#define TARGET_F_GETLK64 12 /* using 'struct flock64' */ -#define TARGET_F_SETLK64 13 -#define TARGET_F_SETLKW64 14 - -struct target_flock { - short l_type; - short l_whence; - target_ulong l_start; - target_ulong l_len; - int l_pid; -}; - -struct target_flock64 { - short l_type; - short l_whence; - unsigned long long l_start; - unsigned long long l_len; - int l_pid; -}; - -/* soundcard defines (XXX: move them to generic file syscall_defs.h) */ - -#define TARGET_SNDCTL_COPR_HALT 0xc0144307 -#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301 -#define TARGET_SNDCTL_COPR_RCODE 0xc0144303 -#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309 -#define TARGET_SNDCTL_COPR_RDATA 0xc0144302 -#define TARGET_SNDCTL_COPR_RESET 0x00004300 -#define TARGET_SNDCTL_COPR_RUN 0xc0144306 -#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308 -#define TARGET_SNDCTL_COPR_WCODE 0x40144305 -#define TARGET_SNDCTL_COPR_WDATA 0x40144304 -#define TARGET_SNDCTL_DSP_CHANNELS 0xc0045006 -#define TARGET_SNDCTL_DSP_GETBLKSIZE 0xc0045004 -#define TARGET_SNDCTL_DSP_GETCAPS 0x8004500f -#define TARGET_SNDCTL_DSP_GETFMTS 0x8004500b -#define TARGET_SNDCTL_DSP_GETIPTR 0x800c5011 -#define TARGET_SNDCTL_DSP_GETISPACE 0x8010500d -#define TARGET_SNDCTL_DSP_GETOPTR 0x800c5012 -#define TARGET_SNDCTL_DSP_GETOSPACE 0x8010500c -#define TARGET_SNDCTL_DSP_GETTRIGGER 0x80045010 -#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013 -#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014 -#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e -#define TARGET_SNDCTL_DSP_POST 0x00005008 -#define TARGET_SNDCTL_DSP_RESET 0x00005000 -#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005 -#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016 -#define TARGET_SNDCTL_DSP_SETFMT 0xc0045005 -#define TARGET_SNDCTL_DSP_SETFRAGMENT 0xc004500a -#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015 -#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010 -#define TARGET_SNDCTL_DSP_SPEED 0xc0045002 -#define TARGET_SNDCTL_DSP_STEREO 0xc0045003 -#define TARGET_SNDCTL_DSP_SUBDIVIDE 0xc0045009 -#define TARGET_SNDCTL_DSP_SYNC 0x00005001 -#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f -#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107 -#define TARGET_SNDCTL_MIDI_INFO 0xc074510c -#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02 -#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01 -#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00 -#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110 -#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001 -#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103 -#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105 -#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104 -#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b -#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a -#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112 -#define TARGET_SNDCTL_SEQ_PANIC 0x00005111 -#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106 -#define TARGET_SNDCTL_SEQ_RESET 0x00005100 -#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109 -#define TARGET_SNDCTL_SEQ_SYNC 0x00005101 -#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108 -#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d -#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d -#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102 -#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e -#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404 -#define TARGET_SNDCTL_TMR_METRONOME 0x40045407 -#define TARGET_SNDCTL_TMR_SELECT 0x40045408 -#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406 -#define TARGET_SNDCTL_TMR_START 0x00005402 -#define TARGET_SNDCTL_TMR_STOP 0x00005403 -#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405 -#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401 -#define TARGET_SOUND_PCM_WRITE_FILTER 0xc0045007 -#define TARGET_SOUND_PCM_READ_RATE 0x80045002 -#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006 -#define TARGET_SOUND_PCM_READ_BITS 0x80045005 -#define TARGET_SOUND_PCM_READ_FILTER 0x80045007 -#define TARGET_SOUND_MIXER_INFO 0x80304d65 -#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66 -#define TARGET_SOUND_MIXER_PRIVATE1 0xc0044d6f -#define TARGET_SOUND_MIXER_PRIVATE2 0xc0044d70 -#define TARGET_SOUND_MIXER_PRIVATE3 0xc0044d71 -#define TARGET_SOUND_MIXER_PRIVATE4 0xc0044d72 -#define TARGET_SOUND_MIXER_PRIVATE5 0xc0044d73 -#define TARGET_SOUND_MIXER_READ_VOLUME 0x80044d00 -#define TARGET_SOUND_MIXER_READ_BASS 0x80044d01 -#define TARGET_SOUND_MIXER_READ_TREBLE 0x80044d02 -#define TARGET_SOUND_MIXER_READ_SYNTH 0x80044d03 -#define TARGET_SOUND_MIXER_READ_PCM 0x80044d04 -#define TARGET_SOUND_MIXER_READ_SPEAKER 0x80044d05 -#define TARGET_SOUND_MIXER_READ_LINE 0x80044d06 -#define TARGET_SOUND_MIXER_READ_MIC 0x80044d07 -#define TARGET_SOUND_MIXER_READ_CD 0x80044d08 -#define TARGET_SOUND_MIXER_READ_IMIX 0x80044d09 -#define TARGET_SOUND_MIXER_READ_ALTPCM 0x80044d0a -#define TARGET_SOUND_MIXER_READ_RECLEV 0x80044d0b -#define TARGET_SOUND_MIXER_READ_IGAIN 0x80044d0c -#define TARGET_SOUND_MIXER_READ_OGAIN 0x80044d0d -#define TARGET_SOUND_MIXER_READ_LINE1 0x80044d0e -#define TARGET_SOUND_MIXER_READ_LINE2 0x80044d0f -#define TARGET_SOUND_MIXER_READ_LINE3 0x80044d10 -#define TARGET_SOUND_MIXER_READ_MUTE 0x80044d1f -#define TARGET_SOUND_MIXER_READ_ENHANCE 0x80044d1f -#define TARGET_SOUND_MIXER_READ_LOUD 0x80044d1f -#define TARGET_SOUND_MIXER_READ_RECSRC 0x80044dff -#define TARGET_SOUND_MIXER_READ_DEVMASK 0x80044dfe -#define TARGET_SOUND_MIXER_READ_RECMASK 0x80044dfd -#define TARGET_SOUND_MIXER_READ_STEREODEVS 0x80044dfb -#define TARGET_SOUND_MIXER_READ_CAPS 0x80044dfc -#define TARGET_SOUND_MIXER_WRITE_VOLUME 0xc0044d00 -#define TARGET_SOUND_MIXER_WRITE_BASS 0xc0044d01 -#define TARGET_SOUND_MIXER_WRITE_TREBLE 0xc0044d02 -#define TARGET_SOUND_MIXER_WRITE_SYNTH 0xc0044d03 -#define TARGET_SOUND_MIXER_WRITE_PCM 0xc0044d04 -#define TARGET_SOUND_MIXER_WRITE_SPEAKER 0xc0044d05 -#define TARGET_SOUND_MIXER_WRITE_LINE 0xc0044d06 -#define TARGET_SOUND_MIXER_WRITE_MIC 0xc0044d07 -#define TARGET_SOUND_MIXER_WRITE_CD 0xc0044d08 -#define TARGET_SOUND_MIXER_WRITE_IMIX 0xc0044d09 -#define TARGET_SOUND_MIXER_WRITE_ALTPCM 0xc0044d0a -#define TARGET_SOUND_MIXER_WRITE_RECLEV 0xc0044d0b -#define TARGET_SOUND_MIXER_WRITE_IGAIN 0xc0044d0c -#define TARGET_SOUND_MIXER_WRITE_OGAIN 0xc0044d0d -#define TARGET_SOUND_MIXER_WRITE_LINE1 0xc0044d0e -#define TARGET_SOUND_MIXER_WRITE_LINE2 0xc0044d0f -#define TARGET_SOUND_MIXER_WRITE_LINE3 0xc0044d10 -#define TARGET_SOUND_MIXER_WRITE_MUTE 0xc0044d1f -#define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f -#define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f -#define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff - -#define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201 -#define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202 - -#define TARGET_SIOCATMARK 0x8905 -- cgit v1.2.3 From d19893dab57d29507ebec946f822a5894e873863 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 19:58:51 +0000 Subject: extracted generic code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@242 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 242 +++---------------------------------------------------- translate.c | 167 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 233 deletions(-) create mode 100644 translate.c diff --git a/translate-i386.c b/translate-i386.c index c7d34b60a..eb31c6d10 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -25,97 +25,13 @@ #include #include -#include "disas.h" - -#define DEBUG_DISAS - -#define IN_OP_I386 #include "cpu-i386.h" #include "exec.h" +#include "disas.h" /* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; -int __op_param1, __op_param2, __op_param3; -#ifdef USE_DIRECT_JUMP -int __op_jmp0, __op_jmp1; -#endif - -#ifdef __i386__ -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ -} -#endif - -#ifdef __s390__ -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ -} -#endif - -#ifdef __ia64__ -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ -} -#endif - -#ifdef __powerpc__ - -#define MIN_CACHE_LINE_SIZE 8 /* conservative value */ - -static void inline flush_icache_range(unsigned long start, unsigned long stop) -{ - unsigned long p; - - p = start & ~(MIN_CACHE_LINE_SIZE - 1); - stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); - - for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { - asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); - } - asm volatile ("sync" : : : "memory"); - for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { - asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); - } - asm volatile ("sync" : : : "memory"); - asm volatile ("isync" : : : "memory"); -} -#endif - -#ifdef __alpha__ -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - asm ("imb"); -} -#endif - -#ifdef __sparc__ - -static void inline flush_icache_range(unsigned long start, unsigned long stop) -{ - unsigned long p; - - p = start & ~(8UL - 1UL); - stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); - - for (; p < stop; p += 8) - __asm__ __volatile__("flush\t%0" : : "r" (p)); -} - -#endif - -#ifdef __arm__ -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - register unsigned long _beg __asm ("a1") = start; - register unsigned long _end __asm ("a2") = stop; - register unsigned long _flg __asm ("a3") = 0; - __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); -} -#endif - -extern FILE *logfile; -extern int loglevel; #define PREFIX_REPZ 0x01 #define PREFIX_REPNZ 0x02 @@ -142,7 +58,7 @@ typedef struct DisasContext { int cpl; int iopl; int tf; /* TF cpu flag */ - TranslationBlock *tb; + struct TranslationBlock *tb; } DisasContext; /* i386 arith/logic operations */ @@ -176,8 +92,7 @@ enum { NB_OPS, }; -#include "dyngen.h" -#include "op-i386.h" +#include "gen-op-i386.h" /* operand size */ enum { @@ -3748,61 +3663,10 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) } } - -#ifdef DEBUG_DISAS -static const char *op_str[] = { -#define DEF(s, n, copy_size) #s, -#include "opc-i386.h" -#undef DEF -}; - -static uint8_t op_nb_args[] = { -#define DEF(s, n, copy_size) n, -#include "opc-i386.h" -#undef DEF -}; - -static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) -{ - const uint16_t *opc_ptr; - const uint32_t *opparam_ptr; - int c, n, i; - - opc_ptr = opc_buf; - opparam_ptr = opparam_buf; - for(;;) { - c = *opc_ptr++; - n = op_nb_args[c]; - fprintf(logfile, "0x%04x: %s", - (int)(opc_ptr - opc_buf - 1), op_str[c]); - for(i = 0; i < n; i++) { - fprintf(logfile, " 0x%x", opparam_ptr[i]); - } - fprintf(logfile, "\n"); - if (c == INDEX_op_end) - break; - opparam_ptr += n; - } -} - -#endif - -/* XXX: make safe guess about sizes */ -#define MAX_OP_PER_INSTR 32 -#define OPC_BUF_SIZE 512 -#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) - -#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3) - -static uint16_t gen_opc_buf[OPC_BUF_SIZE]; -static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; -static uint32_t gen_opc_pc[OPC_BUF_SIZE]; -static uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; - /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc) +int gen_intermediate_code(TranslationBlock *tb, int search_pc) { DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; @@ -3833,7 +3697,7 @@ static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc) gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; - dc->is_jmp = 0; + dc->is_jmp = DISAS_NEXT; pc_ptr = pc_start; lj = -1; do { @@ -3865,10 +3729,10 @@ static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc) } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); /* we must store the eflags state if it is not already done */ - if (dc->is_jmp != 3) { + if (dc->is_jmp != DISAS_TB_JUMP) { if (dc->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(dc->cc_op); - if (dc->is_jmp != 1) { + if (dc->is_jmp != DISAS_JUMP) { /* we add an additionnal jmp to update the simulated PC */ gen_op_jmp_im(ret - (unsigned long)dc->cs_base); } @@ -3880,15 +3744,13 @@ static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc) /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); } - *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "----------------\n"); fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - disas(logfile, pc_start, pc_ptr - pc_start, - dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086); + disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32); fprintf(logfile, "\n"); fprintf(logfile, "OP:\n"); @@ -3912,98 +3774,13 @@ static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc) return 0; } - -/* return non zero if the very first instruction is invalid so that - the virtual CPU can trigger an exception. - - '*gen_code_size_ptr' contains the size of the generated code (host - code). -*/ -int cpu_x86_gen_code(TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr) -{ - uint8_t *gen_code_buf; - int gen_code_size; - - if (gen_intermediate_code(tb, 0) < 0) - return -1; - - /* generate machine code */ - tb->tb_next_offset[0] = 0xffff; - tb->tb_next_offset[1] = 0xffff; - gen_code_buf = tb->tc_ptr; - gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, -#ifdef USE_DIRECT_JUMP - tb->tb_jmp_offset, -#else - NULL, -#endif - gen_opc_buf, gen_opparam_buf); - flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); - - *gen_code_size_ptr = gen_code_size; -#ifdef DEBUG_DISAS - if (loglevel) { - fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); - disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET); - fprintf(logfile, "\n"); - fflush(logfile); - } -#endif - return 0; -} - -static const unsigned short opc_copy_size[] = { -#define DEF(s, n, copy_size) copy_size, -#include "opc-i386.h" -#undef DEF -}; - -/* The simulated PC corresponding to - 'searched_pc' in the generated code is searched. 0 is returned if - found. *found_pc contains the found PC. - */ -int cpu_x86_search_pc(TranslationBlock *tb, - uint32_t *found_pc, unsigned long searched_pc) -{ - int j, c; - unsigned long tc_ptr; - uint16_t *opc_ptr; - - if (gen_intermediate_code(tb, 1) < 0) - return -1; - - /* find opc index corresponding to search_pc */ - tc_ptr = (unsigned long)tb->tc_ptr; - if (searched_pc < tc_ptr) - return -1; - j = 0; - opc_ptr = gen_opc_buf; - for(;;) { - c = *opc_ptr; - if (c == INDEX_op_end) - return -1; - tc_ptr += opc_copy_size[c]; - if (searched_pc < tc_ptr) - break; - opc_ptr++; - } - j = opc_ptr - gen_opc_buf; - /* now find start of instruction before */ - while (gen_opc_instr_start[j] == 0) - j--; - *found_pc = gen_opc_pc[j]; - return 0; -} - - CPUX86State *cpu_x86_init(void) { CPUX86State *env; int i; static int inited; - cpu_x86_tblocks_init(); + cpu_exec_init(); env = malloc(sizeof(CPUX86State)); if (!env) @@ -4020,7 +3797,6 @@ CPUX86State *cpu_x86_init(void) if (!inited) { inited = 1; optimize_flags_init(); - page_init(); } return env; } diff --git a/translate.c b/translate.c new file mode 100644 index 000000000..6ed6f190b --- /dev/null +++ b/translate.c @@ -0,0 +1,167 @@ +/* + * Host code generation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include "config.h" +#define IN_OP_I386 +#include "cpu-" TARGET_ARCH ".h" +#include "exec.h" +#include "disas.h" + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc-" TARGET_ARCH ".h" +#undef DEF + NB_OPS, +}; + +#include "dyngen.h" +#include "op-" TARGET_ARCH ".h" + +uint16_t gen_opc_buf[OPC_BUF_SIZE]; +uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; +uint32_t gen_opc_pc[OPC_BUF_SIZE]; +uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; + + +#ifdef DEBUG_DISAS +static const char *op_str[] = { +#define DEF(s, n, copy_size) #s, +#include "opc-" TARGET_ARCH ".h" +#undef DEF +}; + +static uint8_t op_nb_args[] = { +#define DEF(s, n, copy_size) n, +#include "opc-" TARGET_ARCH ".h" +#undef DEF +}; + +void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) +{ + const uint16_t *opc_ptr; + const uint32_t *opparam_ptr; + int c, n, i; + + opc_ptr = opc_buf; + opparam_ptr = opparam_buf; + for(;;) { + c = *opc_ptr++; + n = op_nb_args[c]; + fprintf(logfile, "0x%04x: %s", + (int)(opc_ptr - opc_buf - 1), op_str[c]); + for(i = 0; i < n; i++) { + fprintf(logfile, " 0x%x", opparam_ptr[i]); + } + fprintf(logfile, "\n"); + if (c == INDEX_op_end) + break; + opparam_ptr += n; + } +} + +#endif + +/* return non zero if the very first instruction is invalid so that + the virtual CPU can trigger an exception. + + '*gen_code_size_ptr' contains the size of the generated code (host + code). +*/ +int cpu_gen_code(TranslationBlock *tb, + int max_code_size, int *gen_code_size_ptr) +{ + uint8_t *gen_code_buf; + int gen_code_size; + + if (gen_intermediate_code(tb, 0) < 0) + return -1; + + /* generate machine code */ + tb->tb_next_offset[0] = 0xffff; + tb->tb_next_offset[1] = 0xffff; + gen_code_buf = tb->tc_ptr; + gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, +#ifdef USE_DIRECT_JUMP + tb->tb_jmp_offset, +#else + NULL, +#endif + gen_opc_buf, gen_opparam_buf); + *gen_code_size_ptr = gen_code_size; +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); + disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0); + fprintf(logfile, "\n"); + fflush(logfile); + } +#endif + return 0; +} + +static const unsigned short opc_copy_size[] = { +#define DEF(s, n, copy_size) copy_size, +#include "opc-i386.h" +#undef DEF +}; + +/* The simulated PC corresponding to + 'searched_pc' in the generated code is searched. 0 is returned if + found. *found_pc contains the found PC. + */ +int cpu_search_pc(TranslationBlock *tb, + uint32_t *found_pc, unsigned long searched_pc) +{ + int j, c; + unsigned long tc_ptr; + uint16_t *opc_ptr; + + if (gen_intermediate_code(tb, 1) < 0) + return -1; + + /* find opc index corresponding to search_pc */ + tc_ptr = (unsigned long)tb->tc_ptr; + if (searched_pc < tc_ptr) + return -1; + j = 0; + opc_ptr = gen_opc_buf; + for(;;) { + c = *opc_ptr; + if (c == INDEX_op_end) + return -1; + tc_ptr += opc_copy_size[c]; + if (searched_pc < tc_ptr) + break; + opc_ptr++; + } + j = opc_ptr - gen_opc_buf; + /* now find start of instruction before */ + while (gen_opc_instr_start[j] == 0) + j--; + *found_pc = gen_opc_pc[j]; + return 0; +} + + -- cgit v1.2.3 From 5a9fdfec7eff4f053705cf160be87ebf01a57833 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 20:02:25 +0000 Subject: factorized cpu defines git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@243 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cpu-i386.h | 254 +------------------------------------------------- 2 files changed, 308 insertions(+), 253 deletions(-) create mode 100644 cpu-all.h diff --git a/cpu-all.h b/cpu-all.h new file mode 100644 index 000000000..e8cb0756d --- /dev/null +++ b/cpu-all.h @@ -0,0 +1,307 @@ +/* + * defines common to all virtual CPUs + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef CPU_ALL_H +#define CPU_ALL_H + +/* all CPU memory access use these macros */ +static inline int ldub(void *ptr) +{ + return *(uint8_t *)ptr; +} + +static inline int ldsb(void *ptr) +{ + return *(int8_t *)ptr; +} + +static inline void stb(void *ptr, int v) +{ + *(uint8_t *)ptr = v; +} + +/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the + kernel handles unaligned load/stores may give better results, but + it is a system wide setting : bad */ +#if defined(WORDS_BIGENDIAN) || defined(__arm__) + +/* conservative code for little endian unaligned accesses */ +static inline int lduw(void *ptr) +{ +#ifdef __powerpc__ + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; +#else + uint8_t *p = ptr; + return p[0] | (p[1] << 8); +#endif +} + +static inline int ldsw(void *ptr) +{ +#ifdef __powerpc__ + int val; + __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return (int16_t)val; +#else + uint8_t *p = ptr; + return (int16_t)(p[0] | (p[1] << 8)); +#endif +} + +static inline int ldl(void *ptr) +{ +#ifdef __powerpc__ + int val; + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); + return val; +#else + uint8_t *p = ptr; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +#endif +} + +static inline uint64_t ldq(void *ptr) +{ + uint8_t *p = ptr; + uint32_t v1, v2; + v1 = ldl(p); + v2 = ldl(p + 4); + return v1 | ((uint64_t)v2 << 32); +} + +static inline void stw(void *ptr, int v) +{ +#ifdef __powerpc__ + __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); +#else + uint8_t *p = ptr; + p[0] = v; + p[1] = v >> 8; +#endif +} + +static inline void stl(void *ptr, int v) +{ +#ifdef __powerpc__ + __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); +#else + uint8_t *p = ptr; + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +#endif +} + +static inline void stq(void *ptr, uint64_t v) +{ + uint8_t *p = ptr; + stl(p, (uint32_t)v); + stl(p + 4, v >> 32); +} + +/* float access */ + +static inline float ldfl(void *ptr) +{ + union { + float f; + uint32_t i; + } u; + u.i = ldl(ptr); + return u.f; +} + +static inline void stfl(void *ptr, float v) +{ + union { + float f; + uint32_t i; + } u; + u.f = v; + stl(ptr, u.i); +} + +#if defined(__arm__) && !defined(WORDS_BIGENDIAN) + +/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ +static inline double ldfq(void *ptr) +{ + union { + double d; + uint32_t tab[2]; + } u; + u.tab[1] = ldl(ptr); + u.tab[0] = ldl(ptr + 4); + return u.d; +} + +static inline void stfq(void *ptr, double v) +{ + union { + double d; + uint32_t tab[2]; + } u; + u.d = v; + stl(ptr, u.tab[1]); + stl(ptr + 4, u.tab[0]); +} + +#else +static inline double ldfq(void *ptr) +{ + union { + double d; + uint64_t i; + } u; + u.i = ldq(ptr); + return u.d; +} + +static inline void stfq(void *ptr, double v) +{ + union { + double d; + uint64_t i; + } u; + u.d = v; + stq(ptr, u.i); +} +#endif + +#else + +static inline int lduw(void *ptr) +{ + return *(uint16_t *)ptr; +} + +static inline int ldsw(void *ptr) +{ + return *(int16_t *)ptr; +} + +static inline int ldl(void *ptr) +{ + return *(uint32_t *)ptr; +} + +static inline uint64_t ldq(void *ptr) +{ + return *(uint64_t *)ptr; +} + +static inline void stw(void *ptr, int v) +{ + *(uint16_t *)ptr = v; +} + +static inline void stl(void *ptr, int v) +{ + *(uint32_t *)ptr = v; +} + +static inline void stq(void *ptr, uint64_t v) +{ + *(uint64_t *)ptr = v; +} + +/* float access */ + +static inline float ldfl(void *ptr) +{ + return *(float *)ptr; +} + +static inline double ldfq(void *ptr) +{ + return *(double *)ptr; +} + +static inline void stfl(void *ptr, float v) +{ + *(float *)ptr = v; +} + +static inline void stfq(void *ptr, double v) +{ + *(double *)ptr = v; +} +#endif + +/* page related stuff */ + +#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) +#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1) +#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK) + +extern unsigned long real_host_page_size; +extern unsigned long host_page_bits; +extern unsigned long host_page_size; +extern unsigned long host_page_mask; + +#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask) + +/* same as PROT_xxx */ +#define PAGE_READ 0x0001 +#define PAGE_WRITE 0x0002 +#define PAGE_EXEC 0x0004 +#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) +#define PAGE_VALID 0x0008 +/* original state of the write flag (used when tracking self-modifying + code */ +#define PAGE_WRITE_ORG 0x0010 + +void page_dump(FILE *f); +int page_get_flags(unsigned long address); +void page_set_flags(unsigned long start, unsigned long end, int flags); +void page_unprotect_range(uint8_t *data, unsigned long data_size); + +#define SINGLE_CPU_DEFINES +#ifdef SINGLE_CPU_DEFINES + +#if defined(TARGET_I386) + +#define CPUState CPUX86State +#define cpu_init cpu_x86_init +#define cpu_exec cpu_x86_exec +#define cpu_gen_code cpu_x86_gen_code +#define cpu_interrupt cpu_x86_interrupt +#define cpu_signal_handler cpu_x86_signal_handler + +#elif defined(TARGET_ARM) + +#define CPUState CPUARMState +#define cpu_init cpu_arm_init +#define cpu_exec cpu_arm_exec +#define cpu_gen_code cpu_arm_gen_code +#define cpu_interrupt cpu_arm_interrupt +#define cpu_signal_handler cpu_arm_signal_handler + +#else + +#error unsupported target CPU + +#endif + +#endif + +#endif /* CPU_ALL_H */ diff --git a/cpu-i386.h b/cpu-i386.h index 8d7e1d612..92178b98c 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -222,233 +222,6 @@ typedef struct CPUX86State { void *opaque; } CPUX86State; -/* all CPU memory access use these macros */ -static inline int ldub(void *ptr) -{ - return *(uint8_t *)ptr; -} - -static inline int ldsb(void *ptr) -{ - return *(int8_t *)ptr; -} - -static inline void stb(void *ptr, int v) -{ - *(uint8_t *)ptr = v; -} - -/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the - kernel handles unaligned load/stores may give better results, but - it is a system wide setting : bad */ -#if defined(WORDS_BIGENDIAN) || defined(__arm__) - -/* conservative code for little endian unaligned accesses */ -static inline int lduw(void *ptr) -{ -#ifdef __powerpc__ - int val; - __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return val; -#else - uint8_t *p = ptr; - return p[0] | (p[1] << 8); -#endif -} - -static inline int ldsw(void *ptr) -{ -#ifdef __powerpc__ - int val; - __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return (int16_t)val; -#else - uint8_t *p = ptr; - return (int16_t)(p[0] | (p[1] << 8)); -#endif -} - -static inline int ldl(void *ptr) -{ -#ifdef __powerpc__ - int val; - __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return val; -#else - uint8_t *p = ptr; - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -#endif -} - -static inline uint64_t ldq(void *ptr) -{ - uint8_t *p = ptr; - uint32_t v1, v2; - v1 = ldl(p); - v2 = ldl(p + 4); - return v1 | ((uint64_t)v2 << 32); -} - -static inline void stw(void *ptr, int v) -{ -#ifdef __powerpc__ - __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); -#else - uint8_t *p = ptr; - p[0] = v; - p[1] = v >> 8; -#endif -} - -static inline void stl(void *ptr, int v) -{ -#ifdef __powerpc__ - __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); -#else - uint8_t *p = ptr; - p[0] = v; - p[1] = v >> 8; - p[2] = v >> 16; - p[3] = v >> 24; -#endif -} - -static inline void stq(void *ptr, uint64_t v) -{ - uint8_t *p = ptr; - stl(p, (uint32_t)v); - stl(p + 4, v >> 32); -} - -/* float access */ - -static inline float ldfl(void *ptr) -{ - union { - float f; - uint32_t i; - } u; - u.i = ldl(ptr); - return u.f; -} - -static inline void stfl(void *ptr, float v) -{ - union { - float f; - uint32_t i; - } u; - u.f = v; - stl(ptr, u.i); -} - -#if defined(__arm__) && !defined(WORDS_BIGENDIAN) - -/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ -static inline double ldfq(void *ptr) -{ - union { - double d; - uint32_t tab[2]; - } u; - u.tab[1] = ldl(ptr); - u.tab[0] = ldl(ptr + 4); - return u.d; -} - -static inline void stfq(void *ptr, double v) -{ - union { - double d; - uint32_t tab[2]; - } u; - u.d = v; - stl(ptr, u.tab[1]); - stl(ptr + 4, u.tab[0]); -} - -#else -static inline double ldfq(void *ptr) -{ - union { - double d; - uint64_t i; - } u; - u.i = ldq(ptr); - return u.d; -} - -static inline void stfq(void *ptr, double v) -{ - union { - double d; - uint64_t i; - } u; - u.d = v; - stq(ptr, u.i); -} -#endif - -#else - -static inline int lduw(void *ptr) -{ - return *(uint16_t *)ptr; -} - -static inline int ldsw(void *ptr) -{ - return *(int16_t *)ptr; -} - -static inline int ldl(void *ptr) -{ - return *(uint32_t *)ptr; -} - -static inline uint64_t ldq(void *ptr) -{ - return *(uint64_t *)ptr; -} - -static inline void stw(void *ptr, int v) -{ - *(uint16_t *)ptr = v; -} - -static inline void stl(void *ptr, int v) -{ - *(uint32_t *)ptr = v; -} - -static inline void stq(void *ptr, uint64_t v) -{ - *(uint64_t *)ptr = v; -} - -/* float access */ - -static inline float ldfl(void *ptr) -{ - return *(float *)ptr; -} - -static inline double ldfq(void *ptr) -{ - return *(double *)ptr; -} - -static inline void stfl(void *ptr, float v) -{ - *(float *)ptr = v; -} - -static inline void stfq(void *ptr, double v) -{ - *(double *)ptr = v; -} -#endif - #ifndef IN_OP_I386 void cpu_x86_outb(CPUX86State *env, int addr, int val); void cpu_x86_outw(CPUX86State *env, int addr, int val); @@ -482,32 +255,7 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); -/* page related stuff */ #define TARGET_PAGE_BITS 12 -#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) -#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1) -#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK) - -extern unsigned long real_host_page_size; -extern unsigned long host_page_bits; -extern unsigned long host_page_size; -extern unsigned long host_page_mask; - -#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask) - -/* same as PROT_xxx */ -#define PAGE_READ 0x0001 -#define PAGE_WRITE 0x0002 -#define PAGE_EXEC 0x0004 -#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC) -#define PAGE_VALID 0x0008 -/* original state of the write flag (used when tracking self-modifying - code */ -#define PAGE_WRITE_ORG 0x0010 - -void page_dump(FILE *f); -int page_get_flags(unsigned long address); -void page_set_flags(unsigned long start, unsigned long end, int flags); -void page_unprotect_range(uint8_t *data, unsigned long data_size); +#include "cpu-all.h" #endif /* CPU_I386_H */ -- cgit v1.2.3 From b346ff468efed71e42e9f306c6bf975809cd2c0f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 20:05:50 +0000 Subject: ARM emulation support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@244 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 5 ++-- exec.h | 71 +++++++++++++++++++++++++++++++++++++++----- linux-user/elfload.c | 42 ++++++++++++++++++++++++-- linux-user/main.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++----- linux-user/qemu.h | 28 ++++++++++++------ linux-user/signal.c | 31 +++++++++++++++++-- 6 files changed, 231 insertions(+), 30 deletions(-) diff --git a/exec.c b/exec.c index 2e84f557b..16213dcf8 100644 --- a/exec.c +++ b/exec.c @@ -70,7 +70,7 @@ unsigned long host_page_mask; static PageDesc *l1_map[L1_SIZE]; -void page_init(void) +static void page_init(void) { /* NOTE: we can always suppose that host_page_size >= TARGET_PAGE_SIZE */ @@ -190,10 +190,11 @@ void page_set_flags(unsigned long start, unsigned long end, int flags) spin_unlock(&tb_lock); } -void cpu_x86_tblocks_init(void) +void cpu_exec_init(void) { if (!code_gen_ptr) { code_gen_ptr = code_gen_buffer; + page_init(); } } diff --git a/exec.h b/exec.h index b6ba66364..5ab3589b1 100644 --- a/exec.h +++ b/exec.h @@ -18,6 +18,31 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* allow to see translation results - the slowdown should be negligible, so we leave it */ +#define DEBUG_DISAS + +/* is_jmp field values */ +#define DISAS_NEXT 0 /* next instruction can be analyzed */ +#define DISAS_JUMP 1 /* only pc was modified dynamically */ +#define DISAS_UPDATE 2 /* cpu state was modified dynamically */ +#define DISAS_TB_JUMP 3 /* only pc was modified statically */ + +struct TranslationBlock; + +/* XXX: make safe guess about sizes */ +#define MAX_OP_PER_INSTR 32 +#define OPC_BUF_SIZE 512 +#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) + +#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3) + +extern uint16_t gen_opc_buf[OPC_BUF_SIZE]; +extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; +extern uint32_t gen_opc_pc[OPC_BUF_SIZE]; +extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; + +#if defined(TARGET_I386) + #define GEN_FLAG_CODE32_SHIFT 0 #define GEN_FLAG_ADDSEG_SHIFT 1 #define GEN_FLAG_SS32_SHIFT 2 @@ -27,13 +52,18 @@ #define GEN_FLAG_CPL_SHIFT 9 #define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ -struct TranslationBlock; -int cpu_x86_gen_code(struct TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr); -int cpu_x86_search_pc(struct TranslationBlock *tb, - uint32_t *found_pc, unsigned long searched_pc); -void cpu_x86_tblocks_init(void); -void page_init(void); +#endif + +extern FILE *logfile; +extern int loglevel; + +int gen_intermediate_code(struct TranslationBlock *tb, int search_pc); +void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); +int cpu_gen_code(struct TranslationBlock *tb, + int max_code_size, int *gen_code_size_ptr); +int cpu_search_pc(struct TranslationBlock *tb, + uint32_t *found_pc, unsigned long searched_pc); +void cpu_exec_init(void); int page_unprotect(unsigned long address); #define CODE_GEN_MAX_SIZE 65536 @@ -167,6 +197,33 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif +#if defined(__powerpc__) + +/* on PowerPC we patch the jump instruction directly */ +#define JUMP_TB(tbparam, n, eip)\ +do {\ + static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ + asm volatile ("b %0" : : "i" (&__op_jmp ## n));\ +label ## n:\ + T0 = (long)(tbparam) + (n);\ + EIP = eip;\ +} while (0) + +#else + +/* jump to next block operations (more portable code, does not need + cache flushing, but slower because of indirect jump) */ +#define JUMP_TB(tbparam, n, eip)\ +do {\ + static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ +label ## n:\ + T0 = (long)(tbparam) + (n);\ + EIP = eip;\ +} while (0) + +#endif + #ifdef __powerpc__ static inline int testandset (int *p) { diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 2afde77a8..94059917c 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -38,6 +38,45 @@ A value of 0 tells we have no such handler. */ #define ELF_PLAT_INIT(_r) _r->edx = 0 +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->esp = infop->start_stack; + regs->eip = infop->entry; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_ARM + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_ARM ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_ARM + +#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + target_long *stack = (void *)infop->start_stack; + memset(regs, 0, sizeof(*regs)); + regs->ARM_cpsr = 0x10; + regs->ARM_pc = infop->entry; + regs->ARM_sp = infop->start_stack; + regs->ARM_r2 = tswapl(stack[2]); /* envp */ + regs->ARM_r1 = tswapl(stack[1]); /* argv */ + regs->ARM_r0 = tswapl(stack[0]); /* argc */ +} + #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 @@ -1148,8 +1187,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, } if(retval>=0) { /* success. Initialize important registers */ - regs->esp = infop->start_stack; - regs->eip = infop->entry; + init_thread(regs, infop); return retval; } diff --git a/linux-user/main.c b/linux-user/main.c index 6c03d6f92..889958b31 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -63,6 +63,7 @@ void gemu_log(const char *fmt, ...) va_end(ap); } +#ifdef TARGET_I386 /***********************************************************/ /* CPUX86 core interface */ @@ -238,20 +239,76 @@ void cpu_loop(CPUX86State *env) process_pending_signals(env); } } +#endif + +#ifdef TARGET_ARM + +#define ARM_SYSCALL_BASE 0x900000 + +void cpu_loop(CPUARMState *env) +{ + int trapnr; + unsigned int n, insn; + target_siginfo_t info; + + for(;;) { + trapnr = cpu_arm_exec(env); + switch(trapnr) { + case EXCP_UDEF: + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->regs[15]; + queue_signal(info.si_signo, &info); + break; + case EXCP_SWI: + { + /* system call */ + insn = ldl((void *)(env->regs[15] - 4)); + n = insn & 0xffffff; + if (n >= ARM_SYSCALL_BASE) { + /* linux syscall */ + n -= ARM_SYSCALL_BASE; + env->regs[0] = do_syscall(env, + n, + env->regs[0], + env->regs[1], + env->regs[2], + env->regs[3], + env->regs[4], + 0); + } else { + goto error; + } + } + break; + default: + error: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + cpu_arm_dump_state(env, stderr, 0); + abort(); + } + process_pending_signals(env); + } +} + +#endif void usage(void) { printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n" - "Linux x86 emulator\n" + "Linux CPU emulator (compiled for %s emulation)\n" "\n" "-h print this help\n" - "-L path set the x86 elf interpreter prefix (default=%s)\n" - "-s size set the x86 stack size in bytes (default=%ld)\n" + "-L path set the elf interpreter prefix (default=%s)\n" + "-s size set the stack size in bytes (default=%ld)\n" "\n" "debug options:\n" "-d activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n", + TARGET_ARCH, interp_prefix, x86_stack_size, DEBUG_LOGFILE); @@ -259,7 +316,7 @@ void usage(void) } /* XXX: currently only used for async signals (see signal.c) */ -CPUX86State *global_env; +CPUState *global_env; /* used to free thread contexts */ TaskState *first_task_state; @@ -269,7 +326,7 @@ int main(int argc, char **argv) struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; TaskState ts1, *ts = &ts1; - CPUX86State *env; + CPUState *env; int optind; const char *r; @@ -337,7 +394,7 @@ int main(int argc, char **argv) /* NOTE: we need to init the CPU at this stage to get the host_page_size */ - env = cpu_x86_init(); + env = cpu_init(); if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { printf("Error loading %s\n", filename); @@ -353,8 +410,7 @@ int main(int argc, char **argv) fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); fprintf(logfile, "brk 0x%08lx\n" , info->brk); - fprintf(logfile, "esp 0x%08lx\n" , regs->esp); - fprintf(logfile, "eip 0x%08lx\n" , regs->eip); + fprintf(logfile, "entry 0x%08lx\n" , info->entry); } target_set_brk((char *)info->brk); @@ -368,6 +424,7 @@ int main(int argc, char **argv) env->opaque = ts; ts->used = 1; +#if defined(TARGET_I386) /* linux register setup */ env->regs[R_EAX] = regs->eax; env->regs[R_EBX] = regs->ebx; @@ -419,6 +476,17 @@ int main(int argc, char **argv) cpu_x86_load_seg(env, R_SS, __USER_DS); cpu_x86_load_seg(env, R_FS, __USER_DS); cpu_x86_load_seg(env, R_GS, __USER_DS); +#elif defined(TARGET_ARM) + { + int i; + for(i = 0; i < 16; i++) { + env->regs[i] = regs->uregs[i]; + } + env->cpsr = regs->uregs[16]; + } +#else +#error unsupported target CPU +#endif cpu_loop(env); /* never exits */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index d6e615e0a..d0a96e6e1 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -6,10 +6,8 @@ #include #include "syscall_defs.h" -#ifdef TARGET_I386 -#include "cpu-i386.h" -#include "syscall-i386.h" -#endif +#include "cpu-" TARGET_ARCH ".h" +#include "syscall-" TARGET_ARCH ".h" /* This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain @@ -33,6 +31,7 @@ struct image_info { int personality; }; +#ifdef TARGET_I386 /* Information about the current linux thread */ struct vm86_saved_state { uint32_t eax; /* return code */ @@ -47,16 +46,19 @@ struct vm86_saved_state { uint32_t eip; uint16_t cs, ss, ds, es, fs, gs; }; +#endif /* NOTE: we force a big alignment so that the stack stored after is aligned too */ typedef struct TaskState { struct TaskState *next; +#ifdef TARGET_I386 struct target_vm86plus_struct *target_v86; struct vm86_saved_state vm86_saved_regs; struct target_vm86plus_struct vm86plus; uint32_t v86flags; uint32_t v86mask; +#endif int used; /* non zero if used */ uint8_t stack[0]; } __attribute__((aligned(16))) TaskState; @@ -71,23 +73,31 @@ void syscall_init(void); long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); -extern CPUX86State *global_env; -void cpu_loop(CPUX86State *env); -void process_pending_signals(void *cpu_env); -void signal_init(void); -int queue_signal(int sig, target_siginfo_t *info); +extern CPUState *global_env; +void cpu_loop(CPUState *env); void init_paths(const char *prefix); const char *path(const char *pathname); extern int loglevel; extern FILE *logfile; +/* signal.c */ +void process_pending_signals(void *cpu_env); +void signal_init(void); +int queue_signal(int sig, target_siginfo_t *info); +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +long do_sigreturn(CPUState *env); +long do_rt_sigreturn(CPUState *env); + +#ifdef TARGET_I386 /* vm86.c */ void save_v86_state(CPUX86State *env); void handle_vm86_trap(CPUX86State *env, int trapno); void handle_vm86_fault(CPUX86State *env); int do_vm86(CPUX86State *env, long subfunction, struct target_vm86plus_struct * target_v86); +#endif /* mmap.c */ int target_mprotect(unsigned long start, unsigned long len, int prot); diff --git a/linux-user/signal.c b/linux-user/signal.c index 2aad2ab5f..8c8bc0b26 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -318,7 +318,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, /* the CPU emulator uses some host signals to detect exceptions, we we forward to it some signals */ if (host_signum == SIGSEGV || host_signum == SIGBUS) { - if (cpu_x86_signal_handler(host_signum, info, puc)) + if (cpu_signal_handler(host_signum, info, puc)) return; } @@ -333,7 +333,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, host_to_target_siginfo_noswap(&tinfo, info); if (queue_signal(sig, &tinfo) == 1) { /* interrupt the virtual CPU as soon as possible */ - cpu_x86_interrupt(global_env); + cpu_interrupt(global_env); } } @@ -824,6 +824,33 @@ badframe: return 0; } +#else + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_frame: not implemented\n"); +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_sigreturn: not implemented\n"); + return -ENOSYS; +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + #endif void process_pending_signals(void *cpu_env) -- cgit v1.2.3 From 6380ab5e26f721ddb1d95a247b20b05fbabc667a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 20:25:04 +0000 Subject: added missing link scripts git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@245 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm.ld | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sparc.ld | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 arm.ld create mode 100644 sparc.ld diff --git a/arm.ld b/arm.ld new file mode 100644 index 000000000..61f4c3486 --- /dev/null +++ b/arm.ld @@ -0,0 +1,128 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", + "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/sparc.ld b/sparc.ld new file mode 100644 index 000000000..6333928ad --- /dev/null +++ b/sparc.ld @@ -0,0 +1,128 @@ +OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", + "elf32-sparc") +OUTPUT_ARCH(sparc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x100000) + (. & (0x100000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .plt : { *(.plt) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} -- cgit v1.2.3 From de83cd02e0124536e05e6ad1fd5e4dc783156dab Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 20:25:43 +0000 Subject: arm emulation support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@246 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 5 ++++ Makefile | 76 ++++++++++++++++++++++++++++++++++++++++++------------------- VERSION | 2 +- configure | 39 ++++++++++++++++++++++++++++++- translate.c | 2 +- 5 files changed, 98 insertions(+), 26 deletions(-) diff --git a/Changelog b/Changelog index 013555e84..df93b2805 100644 --- a/Changelog +++ b/Changelog @@ -1,7 +1,12 @@ version 0.3: + + - initial support for ARM emulation - added fnsave, frstor, fnstenv, fldenv FPU instructions - added FPU register save in signal emulation - ARM port + - Sparc and Alpha ports work on the regression test + - generic ioctl number conversion + - fixed ioctl type conversion version 0.2: diff --git a/Makefile b/Makefile index 12cba2927..df17f599a 100644 --- a/Makefile +++ b/Makefile @@ -86,24 +86,38 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o mmap.o signal.o vm86.o path.o +OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o +ifeq ($(TARGET_ARCH), i386) +OBJS+= vm86.o +endif SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a -LIBOBJS+=thunk.o translate-i386.o op-i386.o helper-i386.o exec-i386.o exec.o +# cpu emulator library +LIBOBJS=thunk.o exec.o translate.o cpu-exec.o + +ifeq ($(TARGET_ARCH), i386) +LIBOBJS+=translate-i386.o op-i386.o helper-i386.o +endif +ifeq ($(TARGET_ARCH), arm) +LIBOBJS+=translate-arm.o op-arm.o +endif # NOTE: the disassembler code is only needed for debugging -LIBOBJS+=disas.o i386-dis.o -ifeq ($(ARCH),alpha) +LIBOBJS+=disas.o +ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) +LIBOBJS+=i386-dis.o +endif +ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha) LIBOBJS+=alpha-dis.o endif -ifeq ($(ARCH),ppc) +ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc) LIBOBJS+=ppc-dis.o endif -ifeq ($(ARCH),sparc) +ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc) LIBOBJS+=sparc-dis.o endif -ifeq ($(ARCH),arm) +ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm) LIBOBJS+=arm-dis.o endif @@ -133,20 +147,29 @@ libqemu.a: $(LIBOBJS) dyngen: dyngen.c $(HOST_CC) -O2 -Wall -g $< -o $@ -translate-i386.o: translate-i386.c op-i386.h opc-i386.h cpu-i386.h +translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h + +translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h -op-i386.h: op-i386.o dyngen +op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen ./dyngen -o $@ $< -opc-i386.h: op-i386.o dyngen +opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen ./dyngen -c -o $@ $< -op-i386.o: op-i386.c opreg_template.h ops_template.h +gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen + ./dyngen -g -o $@ $< + +op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $< -helper-i386.o: helper-i386.c +helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< +op-i386.o: op-i386.c opreg_template.h ops_template.h + +op-arm.o: op-arm.c op-arm-template.h + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< @@ -173,17 +196,24 @@ qemu-doc.html: qemu-doc.texi FILES= \ README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ -dyngen.c dyngen.h ioctls.h ops_template.h op_string.h syscall_types.h\ -Makefile elf.h thunk.c\ -elfload.c main.c signal.c thunk.h exec.h\ -cpu-i386.h qemu.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c\ -syscall.c opreg_template.h syscall_defs.h vm86.c\ -dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c arm-dis.c\ -ppc.ld alpha.ld s390.ld sparc.ld arm.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \ -tests/Makefile\ -tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ -tests/test-i386-muldiv.h tests/test-i386-code16.S\ -tests/hello.c tests/hello tests/sha1.c \ +configure \ +dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \ +Makefile elf.h elfload.c main.c signal.c qemu.h \ +syscall.c syscall_defs.h vm86.c path.c mmap.c \ +ppc.ld alpha.ld s390.ld sparc.ld arm.ld\ +thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\ +exec.c cpu-exec.c\ +cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \ +exec-i386.h ops_template.h op_string.h opreg_template.h \ +cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \ +dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \ +arm-dis.c \ +tests/Makefile \ +tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \ +tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \ +tests/hello.c tests/hello \ +tests/hello-arm.c tests/hello-arm \ +tests/sha1.c \ tests/testsig.c tests/testclone.c tests/testthread.c \ tests/runcom.c tests/pi_10.com \ tests/test_path.c \ diff --git a/VERSION b/VERSION index 2f4536184..1d71ef974 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2 \ No newline at end of file +0.3 \ No newline at end of file diff --git a/configure b/configure index 9a7a5f908..b09487de9 100755 --- a/configure +++ b/configure @@ -28,6 +28,7 @@ ar="ar" make="make" strip="strip" target_cpu="x86" +target_bigendian="default" cpu=`uname -m` case "$cpu" in i386|i486|i586|i686|i86pc|BePC) @@ -103,6 +104,12 @@ for opt do ;; --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` ;; + --target-cpu=*) target_cpu=`echo $opt | cut -d '=' -f 2` + ;; + --target-big-endian) target_bigendian="yes" + ;; + --target-little-endian) target_bigendian="no" + ;; --enable-gprof) gprof="yes" ;; --static) static="yes" @@ -162,6 +169,16 @@ if $cc -o $TMPO $TMPC 2> /dev/null ; then gcc_major="3" fi +if test "$target_bigendian" = "default" ; then + if test "$target_cpu" = "x86" ; then + target_bigendian="no" + elif test "$target_cpu" = "arm" ; then + target_bigendian="no" + else + target_bigendian="no" + fi +fi + if test x"$1" = x"-h" -o x"$1" = x"--help" ; then cat << EOF @@ -173,6 +190,7 @@ 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. [$interp_prefix]" +echo " --target_cpu=CPU set target cpu (x86 or arm) [$target_cpu]" echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]" @@ -191,8 +209,9 @@ echo "ELF interp prefix $interp_prefix" echo "C compiler $cc" echo "make $make" echo "host CPU $cpu" -echo "Big Endian $bigendian" +echo "host big endian $bigendian" echo "target CPU $target_cpu" +echo "target big endian $target_bigendian" echo "gprof enabled $gprof" echo "static build $static" @@ -246,6 +265,24 @@ if test "$bigendian" = "yes" ; then echo "WORDS_BIGENDIAN=yes" >> config.mak echo "#define WORDS_BIGENDIAN 1" >> $TMPH fi + +if test "$target_cpu" = "x86" ; then + echo "TARGET_ARCH=i386" >> config.mak + echo "#define TARGET_ARCH \"i386\"" >> $TMPH + echo "#define TARGET_I386 1" >> $TMPH +elif test "$target_cpu" = "arm" ; then + echo "TARGET_ARCH=arm" >> config.mak + echo "#define TARGET_ARCH \"arm\"" >> $TMPH + echo "#define TARGET_ARM 1" >> $TMPH +else + echo "Unsupported target CPU" + exit 1 +fi +if test "$target_bigendian" = "yes" ; then + echo "TARGET_WORDS_BIGENDIAN=yes" >> config.mak + echo "#define TARGET_WORDS_BIGENDIAN 1" >> $TMPH +fi + if test "$gprof" = "yes" ; then echo "TARGET_GPROF=yes" >> config.mak echo "#define HAVE_GPROF 1" >> $TMPH diff --git a/translate.c b/translate.c index 6ed6f190b..1309d17c5 100644 --- a/translate.c +++ b/translate.c @@ -123,7 +123,7 @@ int cpu_gen_code(TranslationBlock *tb, static const unsigned short opc_copy_size[] = { #define DEF(s, n, copy_size) copy_size, -#include "opc-i386.h" +#include "opc-" TARGET_ARCH ".h" #undef DEF }; -- cgit v1.2.3 From 144c345daf6275a4dd8c75a0cc888679805464da Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 20:42:31 +0000 Subject: consistent hello naming git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@247 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/.cvsignore | 2 +- tests/Makefile | 4 ++-- tests/hello-i386.c | 26 ++++++++++++++++++++++++++ tests/hello.c | 26 -------------------------- 4 files changed, 29 insertions(+), 29 deletions(-) create mode 100644 tests/hello-i386.c delete mode 100644 tests/hello.c diff --git a/tests/.cvsignore b/tests/.cvsignore index 5e5781e20..18a82986c 100644 --- a/tests/.cvsignore +++ b/tests/.cvsignore @@ -1,6 +1,6 @@ gmon.out testsig - hello + hello-i386 hello-arm sha1.test.c sha1.c diff --git a/tests/Makefile b/tests/Makefile index 364e39730..52e81297a 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -12,9 +12,9 @@ QEMU=../qemu all: $(TESTS) -hello: hello.c +hello-i386: hello-i386.c $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< - strip hello + strip $@ testclone: testclone.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< diff --git a/tests/hello-i386.c b/tests/hello-i386.c new file mode 100644 index 000000000..e00245d3f --- /dev/null +++ b/tests/hello-i386.c @@ -0,0 +1,26 @@ +#include + +extern inline volatile void exit(int status) +{ + int __res; + __asm__ volatile ("movl %%ecx,%%ebx\n"\ + "int $0x80" \ + : "=a" (__res) : "0" (__NR_exit),"c" ((long)(status))); +} + +extern inline int write(int fd, const char * buf, int len) +{ + int status; + __asm__ volatile ("pushl %%ebx\n"\ + "movl %%esi,%%ebx\n"\ + "int $0x80\n" \ + "popl %%ebx\n"\ + : "=a" (status) \ + : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len))); +} + +void _start(void) +{ + write(1, "Hello World\n", 12); + exit(0); +} diff --git a/tests/hello.c b/tests/hello.c deleted file mode 100644 index e00245d3f..000000000 --- a/tests/hello.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - -extern inline volatile void exit(int status) -{ - int __res; - __asm__ volatile ("movl %%ecx,%%ebx\n"\ - "int $0x80" \ - : "=a" (__res) : "0" (__NR_exit),"c" ((long)(status))); -} - -extern inline int write(int fd, const char * buf, int len) -{ - int status; - __asm__ volatile ("pushl %%ebx\n"\ - "movl %%esi,%%ebx\n"\ - "int $0x80\n" \ - "popl %%ebx\n"\ - : "=a" (status) \ - : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len))); -} - -void _start(void) -{ - write(1, "Hello World\n", 12); - exit(0); -} -- cgit v1.2.3 From 039de852ec1640ff65db641d27caaf2a88d0a10c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 22:50:44 +0000 Subject: fixed op_label computation on ppc git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@248 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dyngen.c b/dyngen.c index be790d705..7fac4033e 100644 --- a/dyngen.c +++ b/dyngen.c @@ -654,7 +654,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, sym_name = strtab + sym->st_name; if (strstart(sym_name, "__op_label", &p)) { uint8_t *ptr; - int addend; unsigned long offset; /* test if the variable refers to a label inside @@ -663,7 +662,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (!ptr) error("__op_labelN in invalid section"); offset = sym->st_value; - addend = 0; + val = *(target_ulong *)(ptr + offset); #ifdef ELF_USES_RELOCA { int reloc_shndx, nb_relocs1, j; @@ -676,7 +675,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, rel = (ELF_RELOC *)sdata[reloc_shndx]; for(j = 0; j < nb_relocs1; j++) { if (rel->r_offset == offset) { - addend = rel->r_addend; + val = rel->r_addend; break; } rel++; @@ -684,8 +683,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } #endif - val = *(target_ulong *)(ptr + offset); - val += addend; if (val >= start_offset && val < start_offset + copy_size) { n = strtol(p, NULL, 10); -- cgit v1.2.3 From 2054396a044c86521d08e666e5b0c1d20446cf3b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 23:28:43 +0000 Subject: fixed include macro pb git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@249 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 11 +++++++++-- translate.c | 28 ++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index d0a96e6e1..a68e8f4b4 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -6,8 +6,15 @@ #include #include "syscall_defs.h" -#include "cpu-" TARGET_ARCH ".h" -#include "syscall-" TARGET_ARCH ".h" +#if defined(TARGET_I386) +#include "cpu-i386.h" +#include "syscall-i386.h" +#elif defined(TARGET_ARM) +#include "cpu-arm.h" +#include "syscall-arm.h" +#else +#error unsupported target CPU +#endif /* This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain diff --git a/translate.c b/translate.c index 1309d17c5..5ccb45e0e 100644 --- a/translate.c +++ b/translate.c @@ -24,20 +24,36 @@ #include #include "config.h" + #define IN_OP_I386 -#include "cpu-" TARGET_ARCH ".h" +#if defined(TARGET_I386) +#include "cpu-i386.h" +#define OPC_CPU_H "opc-i386.h" +#elif defined(TARGET_ARM) +#include "cpu-arm.h" +#define OPC_CPU_H "opc-arm.h" +#else +#error unsupported target CPU +#endif + #include "exec.h" #include "disas.h" enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc-" TARGET_ARCH ".h" +#include OPC_CPU_H #undef DEF NB_OPS, }; #include "dyngen.h" -#include "op-" TARGET_ARCH ".h" +#if defined(TARGET_I386) +#include "op-i386.h" +#elif defined(TARGET_ARM) +#include "op-arm.h" +#else +#error unsupported target CPU +#endif uint16_t gen_opc_buf[OPC_BUF_SIZE]; uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; @@ -48,13 +64,13 @@ uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #ifdef DEBUG_DISAS static const char *op_str[] = { #define DEF(s, n, copy_size) #s, -#include "opc-" TARGET_ARCH ".h" +#include OPC_CPU_H #undef DEF }; static uint8_t op_nb_args[] = { #define DEF(s, n, copy_size) n, -#include "opc-" TARGET_ARCH ".h" +#include OPC_CPU_H #undef DEF }; @@ -123,7 +139,7 @@ int cpu_gen_code(TranslationBlock *tb, static const unsigned short opc_copy_size[] = { #define DEF(s, n, copy_size) copy_size, -#include "opc-" TARGET_ARCH ".h" +#include OPC_CPU_H #undef DEF }; -- cgit v1.2.3 From 322d0c6657ce6fe82eb042c045117fb3888c5c53 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Jun 2003 23:29:28 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@250 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 +- Makefile | 2 +- qemu-doc.texi | 80 +++++++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/Changelog b/Changelog index df93b2805..492fa1a83 100644 --- a/Changelog +++ b/Changelog @@ -3,7 +3,7 @@ version 0.3: - initial support for ARM emulation - added fnsave, frstor, fnstenv, fldenv FPU instructions - added FPU register save in signal emulation - - ARM port + - initial ARM port - Sparc and Alpha ports work on the regression test - generic ioctl number conversion - fixed ioctl type conversion diff --git a/Makefile b/Makefile index df17f599a..848c70774 100644 --- a/Makefile +++ b/Makefile @@ -211,7 +211,7 @@ arm-dis.c \ tests/Makefile \ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \ tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \ -tests/hello.c tests/hello \ +tests/hello-i386.c tests/hello-i386 \ tests/hello-arm.c tests/hello-arm \ tests/sha1.c \ tests/testsig.c tests/testclone.c tests/testthread.c \ diff --git a/qemu-doc.texi b/qemu-doc.texi index f63a17ac0..1b27f7fe4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1,51 +1,62 @@ \input texinfo @c -*- texinfo -*- -@settitle QEMU x86 Emulator Reference Documentation +@settitle QEMU CPU Emulator Reference Documentation @titlepage @sp 7 -@center @titlefont{QEMU x86 Emulator Reference Documentation} +@center @titlefont{QEMU CPU Emulator Reference Documentation} @sp 3 @end titlepage @chapter Introduction -QEMU is an x86 processor emulator. Its purpose is to run x86 Linux -processes on non-x86 Linux architectures such as PowerPC. By using -dynamic translation it achieves a reasonnable speed while being easy to -port on new host CPUs. Its main goal is to be able to launch the -@code{Wine} Windows API emulator (@url{http://www.winehq.org}) or -@code{DOSEMU} (@url{http://www.dosemu.org}) on non-x86 CPUs. +@section Features -QEMU features: +QEMU is a FAST! processor emulator. Its purpose is to run Linux executables +compiled for one architecture on another. For example, x86 Linux +processes can be ran on PowerPC Linux architectures. By using dynamic +translation it achieves a reasonnable speed while being easy to port on +new host CPUs. Its main goal is to be able to launch the @code{Wine} +Windows API emulator (@url{http://www.winehq.org}) or @code{DOSEMU} +(@url{http://www.dosemu.org}) on non-x86 CPUs. + +QEMU generic features: @itemize -@item User space only x86 emulator. +@item User space only emulation. -@item Currently ported on i386, PowerPC. Work in progress for S390, Alpha and Sparc. +@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390. @item Using dynamic translation to native code for reasonnable speed. -@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. -User space LDT and GDT are emulated. VM86 mode is also supported. - @item Generic Linux system call converter, including most ioctls. @item clone() emulation using native CPU clone() to use Linux scheduler for threads. -@item Accurate signal handling by remapping host signals to virtual x86 signals. - -@item Precise user space x86 exceptions. +@item Accurate signal handling by remapping host signals to target signals. @item Self-modifying code support. +@item The virtual CPU is a library (@code{libqemu}) which can be used +in other projects. + +@end itemize + +@section x86 emulation + +QEMU x86 target features: + +@itemize + +@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. +User space LDT and GDT are emulated. VM86 mode is also supported to run DOSEMU. + +@item Precise user space x86 exceptions. + @item Support of host page sizes bigger than 4KB. @item QEMU can emulate itself on x86. -@item The virtual x86 CPU is a library (@code{libqemu}) which can be used -in other projects. - @item An extensive Linux x86 CPU test program is included @file{tests/test-i386}. It can be used to test other x86 virtual CPUs. @@ -70,10 +81,26 @@ maximum performances. @end itemize +@section ARM emulation + +@itemize + +@item ARM emulation can currently launch small programs while using the +generic dynamic code generation architecture of QEMU. + +@item No FPU support (yet). + +@item No automatic regression testing (yet). + +@end itemize + @chapter Invocation @section Quick Start +If you need to compile QEMU, please read the @file{README} which gives +the related information. + In order to launch a Linux process, QEMU needs the process executable itself and all the target (x86) dynamic libraries used by it. @@ -186,7 +213,7 @@ support for it (QEMU could be used to detect out of bound memory accesses as Valgrind, but it has no support to track uninitialised data as Valgrind does). Valgrind dynamic translator generates better code than QEMU (in particular it does register allocation) but it is closely tied -to an x86 host. +to an x86 host and target. EM86 [4] is the closest project to QEMU (and QEMU still uses some of its code, in particular the ELF file loader). EM86 was limited to an alpha @@ -204,7 +231,7 @@ between the API and the x86 code must be converted. QEMU is a dynamic translator. When it first encounters a piece of code, it converts it to the host instruction set. Usually dynamic translators -are very complicated and highly CPU dependant. QEMU uses some tricks +are very complicated and highly CPU dependent. QEMU uses some tricks which make it relatively easily portable and simple while achieving good performances. @@ -416,14 +443,19 @@ Willows Software. @chapter Regression Tests -In the directory @file{tests/}, various interesting x86 testing programs +In the directory @file{tests/}, various interesting testing programs are available. There are used for regression testing. -@section @file{hello} +@section @file{hello-i386} Very simple statically linked x86 program, just to test QEMU during a port to a new host CPU. +@section @file{hello-arm} + +Very simple statically linked ARM program, just to test QEMU during a +port to a new host CPU. + @section @file{test-i386} This program executes most of the 16 bit and 32 bit x86 instructions and -- cgit v1.2.3 From 972ddf7840c88bcb7405cbcc1a9660f8c0da8a62 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Jun 2003 13:08:39 +0000 Subject: added cpu_abort() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@251 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index e8cb0756d..3eacfa89a 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -302,6 +302,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #endif -#endif +#endif /* SINGLE_CPU_DEFINES */ + +void cpu_abort(CPUState *env, const char *fmt, ...); #endif /* CPU_ALL_H */ -- cgit v1.2.3 From 13b55754afd94ad10124955ec67f8206f57960de Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Jun 2003 13:09:53 +0000 Subject: ring 0 data structures git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@252 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index 92178b98c..c4d6006d9 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -85,6 +85,17 @@ #define VIP_MASK 0x00100000 #define ID_MASK 0x00200000 +#define CR0_PE_MASK (1 << 0) +#define CR0_TS_MASK (1 << 3) +#define CR0_WP_MASK (1 << 16) +#define CR0_AM_MASK (1 << 18) +#define CR0_PG_MASK (1 << 31) + +#define CR4_VME_MASK (1 << 0) +#define CR4_PVI_MASK (1 << 1) +#define CR4_TSD_MASK (1 << 2) +#define CR4_DE_MASK (1 << 3) + #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 #define EXCP02_NMI 2 @@ -161,19 +172,12 @@ typedef double CPU86_LDouble; #endif typedef struct SegmentCache { + uint32_t selector; uint8_t *base; unsigned long limit; uint8_t seg_32bit; } SegmentCache; -typedef struct SegmentDescriptorTable { - uint8_t *base; - unsigned long limit; - /* this is the returned base when reading the register, just to - avoid that the emulated program modifies it */ - unsigned long emu_base; -} SegmentDescriptorTable; - typedef struct CPUX86State { /* standard registers */ uint32_t regs[8]; @@ -205,17 +209,18 @@ typedef struct CPUX86State { } fp_convert; /* segments */ - uint32_t segs[6]; /* selector values */ - SegmentCache seg_cache[6]; /* info taken from LDT/GDT */ - SegmentDescriptorTable gdt; - SegmentDescriptorTable ldt; - SegmentDescriptorTable idt; + SegmentCache segs[6]; /* selector values */ + SegmentCache ldt; + SegmentCache tr; + SegmentCache gdt; /* only base and limit are used */ + SegmentCache idt; /* only base and limit are used */ /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; int error_code; - uint32_t cr2; + uint32_t cr[5]; /* NOTE: cr1 is unused */ + uint32_t dr[8]; /* debug registers */ int interrupt_request; /* user data */ -- cgit v1.2.3 From 7501267e2210788f548edd8adf1704731b235d3f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Jun 2003 13:11:07 +0000 Subject: cpu_abort() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@253 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/exec.c b/exec.c index 16213dcf8..79c2bd0b6 100644 --- a/exec.c +++ b/exec.c @@ -563,3 +563,19 @@ TranslationBlock *tb_find_pc(unsigned long tc_ptr) } return &tbs[m_max]; } + +void cpu_abort(CPUState *env, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "qemu: fatal: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); +#ifdef TARGET_I386 + cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP); +#endif + va_end(ap); + abort(); +} + -- cgit v1.2.3 From d8bc1fd0aeb0423074b5063c8dc94dddd7285321 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Jun 2003 13:13:13 +0000 Subject: ring 0 ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.h | 5 ++ helper-i386.c | 184 +++++++++++++++++++++++++++++++++++++---- op-i386.c | 85 ++++++++++++++++--- translate-i386.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 469 insertions(+), 51 deletions(-) diff --git a/exec-i386.h b/exec-i386.h index a490f266e..20bc8a25c 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -123,6 +123,11 @@ typedef struct CCTable { extern CCTable cc_table[]; void load_seg(int seg_reg, int selector, unsigned cur_eip); +void jmp_seg(int selector, unsigned int new_eip); +void helper_lldt_T0(void); +void helper_ltr_T0(void); +void helper_movl_crN_T0(int reg); +void helper_movl_drN_T0(int reg); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); void raise_interrupt(int intno, int is_int, int error_code, diff --git a/helper-i386.c b/helper-i386.c index 1182be8ce..66121ff96 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -157,7 +157,7 @@ void raise_interrupt(int intno, int is_int, int error_code, break; } dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->segs[R_CS] & 3; + cpl = env->segs[R_CS].selector & 3; /* check privledge if software int */ if (is_int && dpl < cpl) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); @@ -176,7 +176,7 @@ void raise_interrupt(int intno, int is_int, int error_code, void raise_interrupt(int intno, int is_int, int error_code, unsigned int next_eip) { - SegmentDescriptorTable *dt; + SegmentCache *dt; uint8_t *ptr; int dpl, cpl; uint32_t e2; @@ -331,21 +331,98 @@ void helper_cpuid(void) } } +static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2) +{ + sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); + sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & (1 << 23)) + sc->limit = (sc->limit << 12) | 0xfff; + sc->seg_32bit = (e2 >> 22) & 1; +} + +void helper_lldt_T0(void) +{ + int selector; + SegmentCache *dt; + uint32_t e1, e2; + int index; + uint8_t *ptr; + + selector = T0 & 0xffff; + if ((selector & 0xfffc) == 0) { + /* XXX: NULL selector case: invalid LDT */ + env->ldt.base = NULL; + env->ldt.limit = 0; + } else { + if (selector & 0x4) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + load_seg_cache(&env->ldt, e1, e2); + } + env->ldt.selector = selector; +} + +void helper_ltr_T0(void) +{ + int selector; + SegmentCache *dt; + uint32_t e1, e2; + int index, type; + uint8_t *ptr; + + selector = T0 & 0xffff; + if ((selector & 0xfffc) == 0) { + /* XXX: NULL selector case: invalid LDT */ + env->tr.base = NULL; + env->tr.limit = 0; + } else { + if (selector & 0x4) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + if ((e2 & DESC_S_MASK) || + (type != 2 && type != 9)) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + load_seg_cache(&env->tr, e1, e2); + e2 |= 0x00000200; /* set the busy bit */ + stl(ptr + 4, e2); + } + env->tr.selector = selector; +} + /* only works if protected mode and not VM86 */ -void load_seg(int seg_reg, int selector, unsigned cur_eip) +void load_seg(int seg_reg, int selector, unsigned int cur_eip) { SegmentCache *sc; - SegmentDescriptorTable *dt; + SegmentCache *dt; int index; uint32_t e1, e2; uint8_t *ptr; - - sc = &env->seg_cache[seg_reg]; + + sc = &env->segs[seg_reg]; if ((selector & 0xfffc) == 0) { /* null selector case */ if (seg_reg == R_SS) { EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_exception_err(EXCP0D_GPF, 0); } else { /* XXX: each access should trigger an exception */ sc->base = NULL; @@ -390,18 +467,93 @@ void load_seg(int seg_reg, int selector, unsigned cur_eip) else raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); } - - sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); - sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & (1 << 23)) - sc->limit = (sc->limit << 12) | 0xfff; - sc->seg_32bit = (e2 >> 22) & 1; + load_seg_cache(sc, e1, e2); #if 0 fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); #endif } - env->segs[seg_reg] = selector; + sc->selector = selector; +} + +/* protected mode jump */ +void jmp_seg(int selector, unsigned int new_eip) +{ + SegmentCache sc1; + SegmentCache *dt; + int index; + uint32_t e1, e2, cpl, dpl, rpl; + uint8_t *ptr; + + if ((selector & 0xfffc) == 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + cpl = env->segs[R_CS].selector & 3; + if (e2 & DESC_S_MASK) { + if (!(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_CS_MASK) { + /* conforming code segment */ + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } else { + /* non conforming code segment */ + rpl = selector & 3; + if (rpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (dpl != cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + load_seg_cache(&sc1, e1, e2); + if (new_eip > sc1.limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + env->segs[R_CS] = sc1; + env->segs[R_CS].selector = (selector & 0xfffc) | cpl; + EIP = new_eip; + } else { + cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", + selector, new_eip); + } +} + +/* XXX: do more */ +void helper_movl_crN_T0(int reg) +{ + switch(reg) { + case 0: + default: + env->cr[0] = reg; + break; + case 2: + env->cr[2] = reg; + break; + case 3: + env->cr[3] = reg; + break; + case 4: + env->cr[4] = reg; + break; + } +} + +/* XXX: do more */ +void helper_movl_drN_T0(int reg) +{ + env->dr[reg] = T0; } /* rdtsc */ @@ -425,7 +577,7 @@ void helper_rdtsc(void) void helper_lsl(void) { unsigned int selector, limit; - SegmentDescriptorTable *dt; + SegmentCache *dt; int index; uint32_t e1, e2; uint8_t *ptr; @@ -452,7 +604,7 @@ void helper_lsl(void) void helper_lar(void) { unsigned int selector; - SegmentDescriptorTable *dt; + SegmentCache *dt; int index; uint32_t e2; uint8_t *ptr; diff --git a/op-i386.c b/op-i386.c index c2f92638b..5836b1a1c 100644 --- a/op-i386.c +++ b/op-i386.c @@ -357,6 +357,11 @@ void OPPROTO op_andl_T0_ffff(void) T0 = T0 & 0xffff; } +void OPPROTO op_andl_T0_im(void) +{ + T0 = T0 & PARAM1; +} + void OPPROTO op_movl_T0_T1(void) { T0 = T1; @@ -665,7 +670,7 @@ void op_pushl_ss32_T0(void) { uint32_t offset; offset = ESP - 4; - stl(env->seg_cache[R_SS].base + offset, T0); + stl(env->segs[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = offset; } @@ -674,7 +679,7 @@ void op_pushw_ss32_T0(void) { uint32_t offset; offset = ESP - 2; - stw(env->seg_cache[R_SS].base + offset, T0); + stw(env->segs[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = offset; } @@ -683,7 +688,7 @@ void op_pushl_ss16_T0(void) { uint32_t offset; offset = (ESP - 4) & 0xffff; - stl(env->seg_cache[R_SS].base + offset, T0); + stl(env->segs[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = (ESP & ~0xffff) | offset; } @@ -692,7 +697,7 @@ void op_pushw_ss16_T0(void) { uint32_t offset; offset = (ESP - 2) & 0xffff; - stw(env->seg_cache[R_SS].base + offset, T0); + stw(env->segs[R_SS].base + offset, T0); /* modify ESP after to handle exceptions correctly */ ESP = (ESP & ~0xffff) | offset; } @@ -710,22 +715,22 @@ void op_popw_T0(void) void op_popl_ss32_T0(void) { - T0 = ldl(env->seg_cache[R_SS].base + ESP); + T0 = ldl(env->segs[R_SS].base + ESP); } void op_popw_ss32_T0(void) { - T0 = lduw(env->seg_cache[R_SS].base + ESP); + T0 = lduw(env->segs[R_SS].base + ESP); } void op_popl_ss16_T0(void) { - T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff)); + T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff)); } void op_popw_ss16_T0(void) { - T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff)); + T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff)); } void op_addl_ESP_4(void) @@ -909,17 +914,18 @@ void OPPROTO op_movl_seg_T0(void) void OPPROTO op_movl_seg_T0_vm(void) { int selector; + SegmentCache *sc; selector = T0 & 0xffff; /* env->segs[] access */ - *(uint32_t *)((char *)env + PARAM1) = selector; - /* env->seg_cache[] access */ - ((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4); + sc = (SegmentCache *)((char *)env + PARAM1); + sc->selector = selector; + sc->base = (void *)(selector << 4); } void OPPROTO op_movl_T0_seg(void) { - T0 = env->segs[PARAM1]; + T0 = env->segs[PARAM1].selector; } void OPPROTO op_movl_A0_seg(void) @@ -942,6 +948,61 @@ void OPPROTO op_lar(void) helper_lar(); } +/* T0: segment, T1:eip */ +void OPPROTO op_ljmp_T0_T1(void) +{ + jmp_seg(T0 & 0xffff, T1); +} + +void OPPROTO op_lldt_T0(void) +{ + helper_lldt_T0(); +} + +void OPPROTO op_ltr_T0(void) +{ + helper_ltr_T0(); +} + +/* CR registers access */ +void OPPROTO op_movl_crN_T0(void) +{ + helper_movl_crN_T0(PARAM1); +} + +/* DR registers access */ +void OPPROTO op_movl_drN_T0(void) +{ + helper_movl_drN_T0(PARAM1); +} + +void OPPROTO op_lmsw_T0(void) +{ + /* only 4 lower bits of CR0 are modified */ + T0 = (env->cr[0] & ~0xf) | (T0 & 0xf); + helper_movl_crN_T0(0); +} + +void OPPROTO op_movl_T0_env(void) +{ + T0 = *(uint32_t *)((char *)env + PARAM1); +} + +void OPPROTO op_movl_env_T0(void) +{ + *(uint32_t *)((char *)env + PARAM1) = T0; +} + +void OPPROTO op_movl_env_T1(void) +{ + *(uint32_t *)((char *)env + PARAM1) = T1; +} + +void OPPROTO op_clts(void) +{ + env->cr[0] &= ~CR0_TS_MASK; +} + /* flags handling */ /* slow jumps cases : in order to avoid calling a function with a diff --git a/translate-i386.c b/translate-i386.c index eb31c6d10..cfff1debe 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -575,7 +575,7 @@ static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) if (s->addseg && override < 0) override = R_DS; if (override >= 0) { - gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); index = 3 + ot; } else { index = ot; @@ -583,7 +583,7 @@ static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) } else { if (override < 0) override = R_DS; - gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); /* 16 address, always override */ index = 6 + ot; } @@ -878,7 +878,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ else override = R_DS; } - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); } } else { switch (mod) { @@ -944,7 +944,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ else override = R_DS; } - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); } } @@ -1146,8 +1146,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) if (!s->vm86) gen_op_movl_seg_T0(seg_reg, cur_eip); else - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]), - offsetof(CPUX86State,seg_cache[seg_reg].base)); + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); if (!s->addseg && seg_reg < R_FS) s->is_jmp = 2; /* abort translation because the register may have a non zero base */ @@ -1230,7 +1229,7 @@ static void gen_stack_A0(DisasContext *s) gen_op_andl_A0_ffff(); gen_op_movl_T1_A0(); if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); } /* NOTE: wrap around in 16 bit not fully handled */ @@ -1243,7 +1242,7 @@ static void gen_pusha(DisasContext *s) gen_op_andl_A0_ffff(); gen_op_movl_T1_A0(); if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); for(i = 0;i < 8; i++) { gen_op_mov_TN_reg[OT_LONG][0][7 - i](); gen_op_st_T0_A0[OT_WORD + s->dflag](); @@ -1262,7 +1261,7 @@ static void gen_popa(DisasContext *s) gen_op_movl_T1_A0(); gen_op_addl_T1_im(16 << s->dflag); if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); for(i = 0;i < 8; i++) { /* ESP is not reloaded */ if (i != 3) { @@ -1291,7 +1290,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_andl_A0_ffff(); gen_op_movl_T1_A0(); if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); /* push bp */ gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); gen_op_st_T0_A0[ot](); @@ -1714,9 +1713,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_ld_T1_A0[ot](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_lduw_T0_A0(); - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - gen_op_movl_T0_T1(); - gen_op_jmp_T0(); + if (!s->vm86) { + /* we compute EIP to handle the exception case */ + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_ljmp_T0_T1(); + } else { + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + gen_op_movl_T0_T1(); + gen_op_jmp_T0(); + } s->is_jmp = 1; break; case 6: /* push Ev */ @@ -2085,7 +2090,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) override = R_DS; } if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); } } if ((b & 2) == 0) { @@ -2113,7 +2118,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) override = R_DS; } if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); } } gen_op_ldub_T0_A0(); @@ -2619,12 +2624,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x1c: switch(rm) { + case 0: /* feni (287 only, just do nop here) */ + break; + case 1: /* fdisi (287 only, just do nop here) */ + break; case 2: /* fclex */ gen_op_fclex(); break; case 3: /* fninit */ gen_op_fninit(); break; + case 4: /* fsetpm (287 only, just do nop here) */ + break; default: goto illegal_op; } @@ -3011,8 +3022,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* change cs and pc */ gen_op_movl_T0_im(selector); - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - gen_op_jmp_im((unsigned long)offset); + if (!s->vm86) { + /* we compute EIP to handle the exception case */ + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_movl_T1_im(offset); + gen_op_ljmp_T0_T1(); + } else { + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + gen_op_jmp_im((unsigned long)offset); + } s->is_jmp = 1; } break; @@ -3343,6 +3361,111 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* XXX: if cpl == 0, then should do something else */ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; + case 0x100: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* sldt */ + gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); + ot = OT_WORD; + if (mod == 3) + ot += s->dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 2: /* lldt */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lldt_T0(); + } + break; + case 1: /* str */ + gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); + ot = OT_WORD; + if (mod == 3) + ot += s->dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 3: /* ltr */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_ltr_T0(); + } + break; + case 4: /* verr */ + case 5: /* verw */ + default: + goto illegal_op; + } + break; + case 0x101: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* sgdt */ + case 1: /* sidt */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (op == 0) + gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); + else + gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); + gen_op_stw_T0_A0(); + gen_op_addl_A0_im(2); + if (op == 0) + gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); + else + gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + gen_op_stl_T0_A0(); + break; + case 2: /* lgdt */ + case 3: /* lidt */ + if (mod == 3) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_lduw_T1_A0(); + gen_op_addl_A0_im(2); + gen_op_ldl_T0_A0(); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + if (op == 2) { + gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base)); + gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit)); + } else { + gen_op_movl_env_T0(offsetof(CPUX86State,idt.base)); + gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit)); + } + } + break; + case 4: /* smsw */ + gen_op_movl_T0_env(offsetof(CPUX86State,cr[0])); + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); + break; + case 6: /* lmsw */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_lmsw_T0(); + } + break; + default: + goto illegal_op; + } + break; case 0x102: /* lar */ case 0x103: /* lsl */ if (s->vm86) @@ -3361,6 +3484,83 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->cc_op = CC_OP_EFLAGS; gen_op_mov_reg_T1[ot][reg](); break; + case 0x118: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* prefetchnta */ + case 1: /* prefetchnt0 */ + case 2: /* prefetchnt0 */ + case 3: /* prefetchnt0 */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* nothing more to do */ + break; + default: + goto illegal_op; + } + break; + case 0x120: /* mov reg, crN */ + case 0x122: /* mov crN, reg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + modrm = ldub(s->pc++); + if ((modrm & 0xc0) != 0xc0) + goto illegal_op; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + switch(reg) { + case 0: + case 2: + case 3: + case 4: + if (b & 2) { + gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_movl_crN_T0(reg); + s->is_jmp = 2; + } else { + gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); + gen_op_mov_reg_T0[OT_LONG][rm](); + } + break; + default: + goto illegal_op; + } + } + break; + case 0x121: /* mov reg, drN */ + case 0x123: /* mov drN, reg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + modrm = ldub(s->pc++); + if ((modrm & 0xc0) != 0xc0) + goto illegal_op; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + /* XXX: do it dynamically with CR4.DE bit */ + if (reg == 4 || reg == 5) + goto illegal_op; + if (b & 2) { + gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_movl_drN_T0(reg); + s->is_jmp = 2; + } else { + gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); + gen_op_mov_reg_T0[OT_LONG][rm](); + } + } + break; + case 0x106: /* clts */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_op_clts(); + } + break; default: goto illegal_op; } @@ -3859,12 +4059,12 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) eflags & CC_P ? 'P' : '-', eflags & CC_C ? 'C' : '-'); fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", - env->segs[R_CS], - env->segs[R_SS], - env->segs[R_DS], - env->segs[R_ES], - env->segs[R_FS], - env->segs[R_GS]); + env->segs[R_CS].selector, + env->segs[R_SS].selector, + env->segs[R_DS].selector, + env->segs[R_ES].selector, + env->segs[R_FS].selector, + env->segs[R_GS].selector); if (flags & X86_DUMP_CCOP) { if ((unsigned)env->cc_op < CC_OP_NB) strcpy(cc_op_name, cc_op_str[env->cc_op]); -- cgit v1.2.3 From 970a87a6bb8dd0ac304a55aeed219e225fbbea38 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Jun 2003 13:13:25 +0000 Subject: new segment access git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@255 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 20 ++++++++++---------- linux-user/main.c | 4 ++-- ops_template.h | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 8d9ffa678..c5e530c93 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -178,21 +178,21 @@ int cpu_exec(CPUState *env1) /* we compute the CPU state. We assume it will not change during the whole generated block. */ #if defined(TARGET_I386) - flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; - flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT; - flags |= (((unsigned long)env->seg_cache[R_DS].base | - (unsigned long)env->seg_cache[R_ES].base | - (unsigned long)env->seg_cache[R_SS].base) != 0) << + flags = env->segs[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; + flags |= env->segs[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT; + flags |= (((unsigned long)env->segs[R_DS].base | + (unsigned long)env->segs[R_ES].base | + (unsigned long)env->segs[R_SS].base) != 0) << GEN_FLAG_ADDSEG_SHIFT; if (!(env->eflags & VM_MASK)) { - flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT; + flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT; } else { /* NOTE: a dummy CPL is kept */ flags |= (1 << GEN_FLAG_VM_SHIFT); flags |= (3 << GEN_FLAG_CPL_SHIFT); } flags |= (env->eflags & (IOPL_MASK | TF_MASK)); - cs_base = env->seg_cache[R_CS].base; + cs_base = env->segs[R_CS].base; pc = cs_base + env->eip; #elif defined(TARGET_ARM) flags = 0; @@ -347,13 +347,13 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) if (env->eflags & VM_MASK) { SegmentCache *sc; selector &= 0xffff; - sc = &env->seg_cache[seg_reg]; + sc = &env->segs[seg_reg]; /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded, so we must load them here */ sc->base = (void *)(selector << 4); sc->limit = 0xffff; sc->seg_32bit = 0; - env->segs[seg_reg] = selector; + sc->selector = selector; } else { load_seg(seg_reg, selector, 0); } @@ -426,7 +426,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 0; #if defined(TARGET_I386) env->eip = found_pc - tb->cs_base; - env->cr2 = address; + env->cr[2] = address; /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); diff --git a/linux-user/main.c b/linux-user/main.c index 889958b31..df01a1c77 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -176,7 +176,7 @@ void cpu_loop(CPUX86State *env) info.si_code = TARGET_SEGV_MAPERR; else info.si_code = TARGET_SEGV_ACCERR; - info._sifields._sigfault._addr = env->cr2; + info._sifields._sigfault._addr = env->cr[2]; queue_signal(info.si_signo, &info); break; case EXCP00_DIVZ: @@ -231,7 +231,7 @@ void cpu_loop(CPUX86State *env) /* just indicate that signals should be handled asap */ break; default: - pc = env->seg_cache[R_CS].base + env->eip; + pc = env->segs[R_CS].base + env->eip; fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", (long)pc, trapnr); abort(); diff --git a/ops_template.h b/ops_template.h index ff28086f3..784c27805 100644 --- a/ops_template.h +++ b/ops_template.h @@ -828,7 +828,7 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) #define STRING_SUFFIX _a32 #define SI_ADDR (uint8_t *)A0 + ESI -#define DI_ADDR env->seg_cache[R_ES].base + EDI +#define DI_ADDR env->segs[R_ES].base + EDI #define INC_SI() ESI += inc #define INC_DI() EDI += inc #define CX ECX @@ -837,7 +837,7 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) #define STRING_SUFFIX _a16 #define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff) -#define DI_ADDR env->seg_cache[R_ES].base + (EDI & 0xffff) +#define DI_ADDR env->segs[R_ES].base + (EDI & 0xffff) #define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff) #define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff) #define CX (ECX & 0xffff) -- cgit v1.2.3 From a52c757c9f98311c3ba22744d609caa767b899e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Jun 2003 13:14:12 +0000 Subject: fixed case where SS != USER_DS (fixes dosemu DPMI emulation) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@256 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 8c8bc0b26..8c757dd4a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -517,10 +517,10 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, { int err = 0; - err |= __put_user(env->segs[R_GS], (unsigned int *)&sc->gs); - err |= __put_user(env->segs[R_FS], (unsigned int *)&sc->fs); - err |= __put_user(env->segs[R_ES], (unsigned int *)&sc->es); - err |= __put_user(env->segs[R_DS], (unsigned int *)&sc->ds); + err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs); + err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs); + err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es); + err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds); err |= __put_user(env->regs[R_EDI], &sc->edi); err |= __put_user(env->regs[R_ESI], &sc->esi); err |= __put_user(env->regs[R_EBP], &sc->ebp); @@ -532,10 +532,10 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, err |= __put_user(env->exception_index, &sc->trapno); err |= __put_user(env->error_code, &sc->err); err |= __put_user(env->eip, &sc->eip); - err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs); + err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs); err |= __put_user(env->eflags, &sc->eflags); err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal); - err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss); + err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss); cpu_x86_fsave(env, (void *)fpstate, 1); fpstate->status = fpstate->sw; @@ -544,7 +544,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); - err |= __put_user(env->cr2, &sc->cr2); + err |= __put_user(env->cr[2], &sc->cr2); return err; } @@ -567,13 +567,14 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) } /* This is the legacy signal stack switching. */ - else if ((regs->xss & 0xffff) != __USER_DS && - !(ka->sa.sa_flags & SA_RESTORER) && - ka->sa.sa_restorer) { - esp = (unsigned long) ka->sa.sa_restorer; - } + else #endif - return (void *)((esp - frame_size) & -8ul); + if ((env->segs[R_SS].selector & 0xffff) != __USER_DS && + !(ka->sa.sa_flags & TARGET_SA_RESTORER) && + ka->sa.sa_restorer) { + esp = (unsigned long) ka->sa.sa_restorer; + } + return (void *)((esp - frame_size) & -8ul); } static void setup_frame(int sig, struct emulated_sigaction *ka, -- cgit v1.2.3 From c05bab779e16f39b78e133797937114512f3c132 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Jun 2003 13:14:43 +0000 Subject: force IOPL=3 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@257 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/vm86.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 8b512df62..360d52592 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -73,17 +73,17 @@ void save_v86_state(CPUX86State *env) ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); ts->target_v86->regs.eip = tswap32(env->eip); - ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); - ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); - ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); - ts->target_v86->regs.es = tswap16(env->segs[R_ES]); - ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); - ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); + ts->target_v86->regs.cs = tswap16(env->segs[R_CS].selector); + ts->target_v86->regs.ss = tswap16(env->segs[R_SS].selector); + ts->target_v86->regs.ds = tswap16(env->segs[R_DS].selector); + ts->target_v86->regs.es = tswap16(env->segs[R_ES].selector); + ts->target_v86->regs.fs = tswap16(env->segs[R_FS].selector); + ts->target_v86->regs.gs = tswap16(env->segs[R_GS].selector); set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask); ts->target_v86->regs.eflags = tswap32(env->eflags); #ifdef DEBUG_VM86 fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n", - env->eflags, env->segs[R_CS], env->eip); + env->eflags, env->segs[R_CS].selector, env->eip); #endif /* restore 32 bit registers */ @@ -180,6 +180,7 @@ static inline unsigned int get_vflags(CPUX86State *env) flags = env->eflags & RETURN_MASK; if (ts->v86flags & VIF_MASK) flags |= IF_MASK; + flags |= IOPL_MASK; return flags | (ts->v86flags & ts->v86mask); } @@ -194,7 +195,7 @@ static void do_int(CPUX86State *env, int intno) uint8_t *ssp; unsigned int sp; - if (env->segs[R_CS] == TARGET_BIOSSEG) + if (env->segs[R_CS].selector == TARGET_BIOSSEG) goto cannot_handle; if (is_revectored(intno, &ts->vm86plus.int_revectored)) goto cannot_handle; @@ -210,10 +211,10 @@ static void do_int(CPUX86State *env, int intno) intno, segoffs >> 16, segoffs & 0xffff); #endif /* save old state */ - ssp = (uint8_t *)(env->segs[R_SS] << 4); + ssp = (uint8_t *)(env->segs[R_SS].selector << 4); sp = env->regs[R_ESP] & 0xffff; vm_putw(ssp, sp - 2, get_vflags(env)); - vm_putw(ssp, sp - 4, env->segs[R_CS]); + vm_putw(ssp, sp - 4, env->segs[R_CS].selector); vm_putw(ssp, sp - 6, env->eip); ADD16(env->regs[R_ESP], -6); /* goto interrupt handler */ @@ -257,16 +258,16 @@ void handle_vm86_fault(CPUX86State *env) unsigned int ip, sp, newflags, newip, newcs, opcode, intno; int data32, pref_done; - csp = (uint8_t *)(env->segs[R_CS] << 4); + csp = (uint8_t *)(env->segs[R_CS].selector << 4); ip = env->eip & 0xffff; pc = csp + ip; - ssp = (uint8_t *)(env->segs[R_SS] << 4); + ssp = (uint8_t *)(env->segs[R_SS].selector << 4); sp = env->regs[R_ESP] & 0xffff; #if defined(DEBUG_VM86) fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n", - env->segs[R_CS], env->eip, pc[0], pc[1]); + env->segs[R_CS].selector, env->eip, pc[0], pc[1]); #endif data32 = 0; @@ -413,12 +414,12 @@ int do_vm86(CPUX86State *env, long subfunction, ts->vm86_saved_regs.esp = env->regs[R_ESP]; ts->vm86_saved_regs.eflags = env->eflags; ts->vm86_saved_regs.eip = env->eip; - ts->vm86_saved_regs.cs = env->segs[R_CS]; - ts->vm86_saved_regs.ss = env->segs[R_SS]; - ts->vm86_saved_regs.ds = env->segs[R_DS]; - ts->vm86_saved_regs.es = env->segs[R_ES]; - ts->vm86_saved_regs.fs = env->segs[R_FS]; - ts->vm86_saved_regs.gs = env->segs[R_GS]; + ts->vm86_saved_regs.cs = env->segs[R_CS].selector; + ts->vm86_saved_regs.ss = env->segs[R_SS].selector; + ts->vm86_saved_regs.ds = env->segs[R_DS].selector; + ts->vm86_saved_regs.es = env->segs[R_ES].selector; + ts->vm86_saved_regs.fs = env->segs[R_FS].selector; + ts->vm86_saved_regs.gs = env->segs[R_GS].selector; /* build vm86 CPU state */ ts->v86flags = tswap32(target_v86->regs.eflags); @@ -466,7 +467,8 @@ int do_vm86(CPUX86State *env, long subfunction, target_v86->vm86plus.vm86dbg_intxxtab, 32); #ifdef DEBUG_VM86 - fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS], env->eip); + fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", + env->segs[R_CS].selector, env->eip); #endif /* now the virtual CPU is ready for vm86 execution ! */ out: -- cgit v1.2.3 From 717fc2ad8dbedcb19ec939b752489d2d1a21647b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:20:53 +0000 Subject: more ring 0 instructions - full x86 MMU emulation based on mmap() syscall - fixed popl (%esp) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@258 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 249 insertions(+), 30 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index cfff1debe..79d6eed63 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -24,11 +24,14 @@ #include #include #include +#include #include "cpu-i386.h" #include "exec.h" #include "disas.h" +//#define DEBUG_MMU + /* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; @@ -59,6 +62,7 @@ typedef struct DisasContext { int iopl; int tf; /* TF cpu flag */ struct TranslationBlock *tb; + int popl_esp_hack; /* for correct popl with esp base handling */ } DisasContext; /* i386 arith/logic operations */ @@ -862,12 +866,16 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ } if (base >= 0) { + /* for correct popl handling with esp */ + if (base == 4 && s->popl_esp_hack) + disp += 4; gen_op_movl_A0_reg[base](); if (disp != 0) gen_op_addl_A0_im(disp); } else { gen_op_movl_A0_im(disp); } + /* XXX: index == 4 is always invalid */ if (havesib && (index != 4 || scale != 0)) { gen_op_addl_A0_reg_sN[scale][index](); } @@ -1894,7 +1902,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); gen_pop_T0(s); + s->popl_esp_hack = 1; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + s->popl_esp_hack = 0; gen_pop_update(s); break; case 0xc8: /* enter */ @@ -2940,29 +2950,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - /* XXX: not restartable */ - gen_stack_A0(s); - /* pop offset */ - gen_op_ld_T0_A0[1 + s->dflag](); - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - /* NOTE: keeping EIP updated is not a problem in case of - exception */ - gen_op_jmp_T0(); - /* pop selector */ - gen_op_addl_A0_im(2 << s->dflag); - gen_op_ld_T0_A0[1 + s->dflag](); - /* pop eflags */ - gen_op_addl_A0_im(2 << s->dflag); - gen_op_ld_T1_A0[1 + s->dflag](); - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - gen_op_movl_T0_T1(); - if (s->dflag) { - gen_op_movl_eflags_T0(); - } else { - gen_op_movw_eflags_T0(); - } - gen_stack_update(s, (6 << s->dflag)); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_iret_protected(s->dflag); s->cc_op = CC_OP_EFLAGS; } s->is_jmp = 1; @@ -3096,10 +3087,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_pop_T0(s); - if (s->dflag) { - gen_op_movl_eflags_T0(); + if (s->cpl == 0) { + if (s->dflag) { + gen_op_movl_eflags_T0_cpl0(); + } else { + gen_op_movw_eflags_T0_cpl0(); + } } else { - gen_op_movw_eflags_T0(); + if (s->dflag) { + gen_op_movl_eflags_T0(); + } else { + gen_op_movw_eflags_T0(); + } } gen_pop_update(s); s->cc_op = CC_OP_EFLAGS; @@ -3358,8 +3357,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_cpuid(); break; case 0xf4: /* hlt */ - /* XXX: if cpl == 0, then should do something else */ - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(s->pc - s->cs_base); + gen_op_hlt(); + s->is_jmp = 1; + } break; case 0x100: modrm = ldub(s->pc++); @@ -3462,6 +3468,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_lmsw_T0(); } break; + case 7: /* invlpg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_invlpg_A0(); + } + break; default: goto illegal_op; } @@ -3866,7 +3882,7 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -int gen_intermediate_code(TranslationBlock *tb, int search_pc) +static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc) { DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; @@ -3892,7 +3908,8 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc) dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; dc->tb = tb; - + dc->popl_esp_hack = 0; + gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; @@ -3908,6 +3925,7 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc) while (lj < j) gen_opc_instr_start[lj++] = 0; gen_opc_pc[lj] = (uint32_t)pc_ptr; + gen_opc_cc_op[lj] = dc->cc_op; gen_opc_instr_start[lj] = 1; } } @@ -3974,6 +3992,16 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc) return 0; } +int gen_intermediate_code(TranslationBlock *tb) +{ + return gen_intermediate_code_internal(tb, 0); +} + +int gen_intermediate_code_pc(TranslationBlock *tb) +{ + return gen_intermediate_code_internal(tb, 1); +} + CPUX86State *cpu_x86_init(void) { CPUX86State *env; @@ -4006,6 +4034,197 @@ void cpu_x86_close(CPUX86State *env) free(env); } +/***********************************************************/ +/* x86 mmu */ + +/* called when cr3 or PG bit are modified */ +static int last_pg_state = -1; +int phys_ram_size; +int phys_ram_fd; +uint8_t *phys_ram_base; + +void cpu_x86_update_cr0(CPUX86State *env) +{ + int pg_state; + void *map_addr; + +#ifdef DEBUG_MMU + printf("CR0 update: CR0=0x%08x\n", env->cr[0]); +#endif + pg_state = env->cr[0] & CR0_PG_MASK; + if (pg_state != last_pg_state) { + if (!pg_state) { + /* we map the physical memory at address 0 */ + + map_addr = mmap((void *)0, phys_ram_size, PROT_WRITE | PROT_READ, + MAP_SHARED | MAP_FIXED, phys_ram_fd, 0); + if (map_addr == MAP_FAILED) { + fprintf(stderr, + "Could not map physical memory at host address 0x%08x\n", + 0); + exit(1); + } + page_set_flags(0, phys_ram_size, + PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC); + } else { + /* we unmap the physical memory */ + munmap((void *)0, phys_ram_size); + page_set_flags(0, phys_ram_size, 0); + } + last_pg_state = pg_state; + } +} + +void cpu_x86_update_cr3(CPUX86State *env) +{ + if (env->cr[0] & CR0_PG_MASK) { +#ifdef DEBUG_MMU + printf("CR3 update: CR3=%08x\n", env->cr[3]); +#endif + page_unmap(); + } +} + +void cpu_x86_init_mmu(CPUX86State *env) +{ + last_pg_state = -1; + cpu_x86_update_cr0(env); +} + +void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) +{ +} + +/* return value: + -1 = cannot handle fault + 0 = nothing more to do + 1 = generate PF fault +*/ +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) +{ + uint8_t *pde_ptr, *pte_ptr; + uint32_t pde, pte, virt_addr; + int cpl, error_code, is_dirty, is_user, prot, page_size; + void *map_addr; + + cpl = env->segs[R_CS].selector & 3; + is_user = (cpl == 3); + +#ifdef DEBUG_MMU + printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", + addr, is_write, is_user, env->eip); +#endif + + if (env->user_mode_only) { + /* user mode only emulation */ + error_code = 0; + goto do_fault; + } + + if (!(env->cr[0] & CR0_PG_MASK)) + return -1; + + /* page directory entry */ + pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); + pde = ldl(pde_ptr); + if (!(pde & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (is_user) { + if (!(pde & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && + is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } + /* if PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + is_dirty = is_write && !(pde & PG_DIRTY_MASK); + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_DIRTY_MASK; + stl(pde_ptr, pde); + } + + pte = pde & ~0x003ff000; /* align to 4MB */ + page_size = 4096 * 1024; + virt_addr = addr & ~0x003fffff; + } else { + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl(pde_ptr, pde); + } + + /* page directory entry */ + pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); + pte = ldl(pte_ptr); + if (!(pte & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (is_user) { + if (!(pte & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pte & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && + is_write && !(pte & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) + pte |= PG_DIRTY_MASK; + stl(pte_ptr, pte); + } + page_size = 4096; + virt_addr = addr & ~0xfff; + } + /* the page can be put in the TLB */ + prot = PROT_READ; + if (is_user) { + if (pte & PG_RW_MASK) + prot |= PROT_WRITE; + } else { + if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || + (pte & PG_RW_MASK)) + prot |= PROT_WRITE; + } + map_addr = mmap((void *)virt_addr, page_size, prot, + MAP_SHARED | MAP_FIXED, phys_ram_fd, pte & ~0xfff); + if (map_addr == MAP_FAILED) { + fprintf(stderr, + "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", + pte & ~0xfff, virt_addr); + exit(1); + } + page_set_flags(virt_addr, virt_addr + page_size, + PAGE_VALID | PAGE_EXEC | prot); +#ifdef DEBUG_MMU + printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", + pte & ~0xfff, virt_addr, (page_size != 4096)); +#endif + return 0; + do_fault_protect: + error_code = PG_ERROR_P_MASK; + do_fault: + env->cr[2] = addr; + env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; + if (is_user) + env->error_code |= PG_ERROR_U_MASK; + return 1; +} + +/***********************************************************/ +/* x86 debug */ + static const char *cc_op_str[] = { "DYNAMIC", "EFLAGS", -- cgit v1.2.3 From f76af4b3f38aa0e0bbf9ac695339bd3eb87c09eb Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:21:23 +0000 Subject: correct restoring of CC_OP in case of exception git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@259 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/translate.c b/translate.c index 5ccb45e0e..2f11dfc03 100644 --- a/translate.c +++ b/translate.c @@ -59,7 +59,9 @@ uint16_t gen_opc_buf[OPC_BUF_SIZE]; uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; uint32_t gen_opc_pc[OPC_BUF_SIZE]; uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; - +#if defined(TARGET_I386) +uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; +#endif #ifdef DEBUG_DISAS static const char *op_str[] = { @@ -111,7 +113,7 @@ int cpu_gen_code(TranslationBlock *tb, uint8_t *gen_code_buf; int gen_code_size; - if (gen_intermediate_code(tb, 0) < 0) + if (gen_intermediate_code(tb) < 0) return -1; /* generate machine code */ @@ -143,18 +145,16 @@ static const unsigned short opc_copy_size[] = { #undef DEF }; -/* The simulated PC corresponding to - 'searched_pc' in the generated code is searched. 0 is returned if - found. *found_pc contains the found PC. +/* The cpu state corresponding to 'searched_pc' is restored. */ -int cpu_search_pc(TranslationBlock *tb, - uint32_t *found_pc, unsigned long searched_pc) +int cpu_restore_state(TranslationBlock *tb, + CPUState *env, unsigned long searched_pc) { int j, c; unsigned long tc_ptr; uint16_t *opc_ptr; - if (gen_intermediate_code(tb, 1) < 0) + if (gen_intermediate_code_pc(tb) < 0) return -1; /* find opc index corresponding to search_pc */ @@ -176,7 +176,18 @@ int cpu_search_pc(TranslationBlock *tb, /* now find start of instruction before */ while (gen_opc_instr_start[j] == 0) j--; - *found_pc = gen_opc_pc[j]; +#if defined(TARGET_I386) + { + int cc_op; + + env->eip = gen_opc_pc[j] - tb->cs_base; + cc_op = gen_opc_cc_op[j]; + if (cc_op != CC_OP_DYNAMIC) + env->cc_op = cc_op; + } +#elif defined(TARGET_ARM) + env->regs[15] = gen_opc_pc[j]; +#endif return 0; } -- cgit v1.2.3 From 3fb2ded1d501287c10be6cad76bd0adc109ba2b0 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:22:59 +0000 Subject: hardware interrupt support - support forfull ring 0 exception simulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@260 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 326 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 195 insertions(+), 131 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index c5e530c93..615915c13 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -29,6 +29,8 @@ //#define DEBUG_EXEC //#define DEBUG_SIGNAL +/* enable it to have a fully working x86 emulator for ring 0 */ +//#define RING0_HACKS #if defined(TARGET_ARM) /* XXX: unify with i386 target */ @@ -140,146 +142,195 @@ int cpu_exec(CPUState *env1) #error unsupported target CPU #endif env->interrupt_request = 0; + env->exception_index = -1; /* prepare setjmp context for exception handling */ - if (setjmp(env->jmp_env) == 0) { - T0 = 0; /* force lookup of first TB */ - for(;;) { + for(;;) { + if (setjmp(env->jmp_env) == 0) { + /* if an exception is pending, we execute it here */ + if (env->exception_index >= 0) { + if (env->exception_index >= EXCP_INTERRUPT) { + /* exit request from the cpu execution loop */ + ret = env->exception_index; + break; + } else if (env->user_mode_only) { + /* if user mode only, we simulate a fake exception + which will be hanlded outside the cpu execution + loop */ + do_interrupt_user(env->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip); + ret = env->exception_index; + break; + } else { + /* 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); + } + env->exception_index = -1; + } +#if defined(TARGET_I386) + /* if hardware interrupt pending, we execute it */ + if (env->hard_interrupt_request && + (env->eflags & IF_MASK)) { + int intno; + intno = cpu_x86_get_pic_interrupt(env); + if (loglevel) { + fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); + } + do_interrupt(intno, 0, 0, 0); + env->hard_interrupt_request = 0; + } +#endif + T0 = 0; /* force lookup of first TB */ + for(;;) { #ifdef __sparc__ - /* g1 can be modified by some libc? functions */ - tmp_T0 = T0; + /* g1 can be modified by some libc? functions */ + tmp_T0 = T0; #endif - if (env->interrupt_request) { - env->exception_index = EXCP_INTERRUPT; - cpu_loop_exit(); - } + if (env->interrupt_request) { + env->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(); + } #ifdef DEBUG_EXEC - if (loglevel) { + if (loglevel) { #if defined(TARGET_I386) - /* restore flags in standard format */ - env->regs[R_EAX] = EAX; - env->regs[R_EBX] = EBX; - env->regs[R_ECX] = ECX; - env->regs[R_EDX] = EDX; - env->regs[R_ESI] = ESI; - env->regs[R_EDI] = EDI; - env->regs[R_EBP] = EBP; - env->regs[R_ESP] = ESP; - env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); - cpu_x86_dump_state(env, logfile, 0); - env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + /* restore flags in standard format */ + env->regs[R_EAX] = EAX; + env->regs[R_EBX] = EBX; + env->regs[R_ECX] = ECX; + env->regs[R_EDX] = EDX; + env->regs[R_ESI] = ESI; + env->regs[R_EDI] = EDI; + env->regs[R_EBP] = EBP; + env->regs[R_ESP] = ESP; + env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); + cpu_x86_dump_state(env, logfile, 0); + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_ARM) - cpu_arm_dump_state(env, logfile, 0); + cpu_arm_dump_state(env, logfile, 0); #else #error unsupported target CPU #endif - } + } #endif - /* we compute the CPU state. We assume it will not - change during the whole generated block. */ + /* we compute the CPU state. We assume it will not + change during the whole generated block. */ #if defined(TARGET_I386) - flags = env->segs[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; - flags |= env->segs[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT; - flags |= (((unsigned long)env->segs[R_DS].base | - (unsigned long)env->segs[R_ES].base | - (unsigned long)env->segs[R_SS].base) != 0) << - GEN_FLAG_ADDSEG_SHIFT; - if (!(env->eflags & VM_MASK)) { - flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT; - } else { - /* NOTE: a dummy CPL is kept */ - flags |= (1 << GEN_FLAG_VM_SHIFT); - flags |= (3 << GEN_FLAG_CPL_SHIFT); - } - flags |= (env->eflags & (IOPL_MASK | TF_MASK)); - cs_base = env->segs[R_CS].base; - pc = cs_base + env->eip; + flags = (env->segs[R_CS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT); + flags |= (env->segs[R_SS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT); + flags |= (((unsigned long)env->segs[R_DS].base | + (unsigned long)env->segs[R_ES].base | + (unsigned long)env->segs[R_SS].base) != 0) << + GEN_FLAG_ADDSEG_SHIFT; + if (!(env->eflags & VM_MASK)) { + flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT; + } else { + /* NOTE: a dummy CPL is kept */ + flags |= (1 << GEN_FLAG_VM_SHIFT); + flags |= (3 << GEN_FLAG_CPL_SHIFT); + } + flags |= (env->eflags & (IOPL_MASK | TF_MASK)); + cs_base = env->segs[R_CS].base; + pc = cs_base + env->eip; #elif defined(TARGET_ARM) - flags = 0; - cs_base = 0; - pc = (uint8_t *)env->regs[15]; + flags = 0; + cs_base = 0; + pc = (uint8_t *)env->regs[15]; #else #error unsupported CPU #endif - tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, - flags); - if (!tb) { - spin_lock(&tb_lock); - /* if no translated code available, then translate it now */ - tb = tb_alloc((unsigned long)pc); + tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, + flags); if (!tb) { - /* flush must be done */ - tb_flush(); - /* cannot fail at this point */ + spin_lock(&tb_lock); + /* if no translated code available, then translate it now */ tb = tb_alloc((unsigned long)pc); - /* don't forget to invalidate previous TB info */ - ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; - T0 = 0; - } - tc_ptr = code_gen_ptr; - tb->tc_ptr = tc_ptr; - tb->cs_base = (unsigned long)cs_base; - tb->flags = flags; - ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); + if (!tb) { + /* flush must be done */ + tb_flush(); + /* cannot fail at this point */ + tb = tb_alloc((unsigned long)pc); + /* don't forget to invalidate previous TB info */ + ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; + T0 = 0; + } + tc_ptr = code_gen_ptr; + tb->tc_ptr = tc_ptr; + tb->cs_base = (unsigned long)cs_base; + tb->flags = flags; + ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); #if defined(TARGET_I386) - /* XXX: suppress that, this is incorrect */ - /* if invalid instruction, signal it */ - if (ret != 0) { - /* NOTE: the tb is allocated but not linked, so we - can leave it */ + /* XXX: suppress that, this is incorrect */ + /* if invalid instruction, signal it */ + if (ret != 0) { + /* NOTE: the tb is allocated but not linked, so we + can leave it */ + spin_unlock(&tb_lock); + raise_exception(EXCP06_ILLOP); + } +#endif + *ptb = tb; + tb->hash_next = NULL; + tb_link(tb); + code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); spin_unlock(&tb_lock); - raise_exception(EXCP06_ILLOP); } -#endif - *ptb = tb; - tb->hash_next = NULL; - tb_link(tb); - code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); - spin_unlock(&tb_lock); - } #ifdef DEBUG_EXEC - if (loglevel) { - fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", - (long)tb->tc_ptr, (long)tb->pc, - lookup_symbol((void *)tb->pc)); - } + if (loglevel) { + fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", + (long)tb->tc_ptr, (long)tb->pc, + lookup_symbol((void *)tb->pc)); + } #endif #ifdef __sparc__ - T0 = tmp_T0; + T0 = tmp_T0; #endif - /* see if we can patch the calling TB. XXX: remove TF test */ - if (T0 != 0 + /* see if we can patch the calling TB. XXX: remove TF test */ +#ifndef RING0_HACKS + + if (T0 != 0 #if defined(TARGET_I386) - && !(env->eflags & TF_MASK) + && !(env->eflags & TF_MASK) #endif - ) { - spin_lock(&tb_lock); - tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); - spin_unlock(&tb_lock); - } - tc_ptr = tb->tc_ptr; - - /* execute the generated code */ - gen_func = (void *)tc_ptr; + ) { + spin_lock(&tb_lock); + tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); + spin_unlock(&tb_lock); + } +#endif + tc_ptr = tb->tc_ptr; + + /* 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"); + __asm__ __volatile__("call %0\n\t" + "mov %%o7,%%i0" + : /* no outputs */ + : "r" (gen_func) + : "i0", "i1", "i2", "i3", "i4", "i5"); #elif defined(__arm__) - asm volatile ("mov pc, %0\n\t" - ".global exec_loop\n\t" - "exec_loop:\n\t" - : /* no outputs */ - : "r" (gen_func) - : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); + asm volatile ("mov pc, %0\n\t" + ".global exec_loop\n\t" + "exec_loop:\n\t" + : /* no outputs */ + : "r" (gen_func) + : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); #else - gen_func(); + gen_func(); #endif + } + } else { } - } - ret = env->exception_index; + } /* for(;;) */ + #if defined(TARGET_I386) /* restore flags in standard format */ @@ -348,11 +399,11 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) SegmentCache *sc; selector &= 0xffff; sc = &env->segs[seg_reg]; - /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded, + /* NOTE: in VM86 mode, limit and flags are never reloaded, so we must load them here */ sc->base = (void *)(selector << 4); sc->limit = 0xffff; - sc->seg_32bit = 0; + sc->flags = 0; sc->selector = selector; } else { load_seg(seg_reg, selector, 0); @@ -398,6 +449,8 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) #include #include +#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 @@ -407,42 +460,53 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { TranslationBlock *tb; int ret; - uint32_t found_pc; +#ifdef RING0_HACKS + env = global_env; /* XXX: find a better solution */ +#endif #if defined(DEBUG_SIGNAL) - printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", + printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ if (is_write && page_unprotect(address)) { return 1; } + /* see if it is an MMU fault */ + ret = cpu_x86_handle_mmu_fault(env, address, is_write); + if (ret < 0) + return 0; /* not an MMU fault */ + if (ret == 0) + return 1; /* the MMU fault was handled without causing real CPU fault */ + /* now we have a real cpu fault */ tb = tb_find_pc(pc); if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - ret = cpu_search_pc(tb, &found_pc, pc); - if (ret < 0) - return 0; -#if defined(TARGET_I386) - env->eip = found_pc - tb->cs_base; - env->cr[2] = address; - /* we restore the process signal mask as the sigreturn should - do it (XXX: use sigsetjmp) */ - sigprocmask(SIG_SETMASK, old_set, NULL); - raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); + cpu_restore_state(tb, env, pc); + } +#if 0 + printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", + env->eip, env->cr[2], env->error_code); +#endif + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + raise_exception_err(EXCP0E_PAGE, env->error_code); + /* never comes here */ + return 1; +} + #elif defined(TARGET_ARM) - env->regs[15] = found_pc; - /* XXX: do more */ +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set) +{ + /* XXX: do more */ + return 0; +} #else #error unsupported target CPU #endif - /* never comes here */ - return 1; - } else { - return 0; - } -} #if defined(__i386__) @@ -570,6 +634,6 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #else -#error CPU specific signal handler needed +#error host CPU specific signal handler needed #endif -- cgit v1.2.3 From 90a9fdae1f1acc791abc2c20731eddf01ba73ae6 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:27:18 +0000 Subject: more ring 0 operations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@261 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.h | 29 ++++ helper-i386.c | 501 ++++++++++++++++++++++++++++++++++++++++++++++++---------- op-i386.c | 35 +++- 3 files changed, 478 insertions(+), 87 deletions(-) diff --git a/exec-i386.h b/exec-i386.h index 20bc8a25c..12e22bb41 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -124,12 +124,22 @@ extern CCTable cc_table[]; void load_seg(int seg_reg, int selector, unsigned cur_eip); void jmp_seg(int selector, unsigned int new_eip); +void helper_iret_protected(int shift); void helper_lldt_T0(void); void helper_ltr_T0(void); void helper_movl_crN_T0(int reg); void helper_movl_drN_T0(int reg); +void helper_invlpg(unsigned int addr); +void cpu_x86_update_cr0(CPUX86State *env); +void cpu_x86_update_cr3(CPUX86State *env); +void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); +void do_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip); +void do_interrupt_user(int intno, int is_int, int error_code, + unsigned int next_eip); void raise_interrupt(int intno, int is_int, int error_code, unsigned int next_eip); void raise_exception_err(int exception_index, int error_code); @@ -329,3 +339,22 @@ void helper_frstor(uint8_t *ptr, int data32); const uint8_t parity_table[256]; const uint8_t rclw_table[32]; const uint8_t rclb_table[32]; + +static inline uint32_t compute_eflags(void) +{ + return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); +} + +#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) + +#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \ + RF_MASK | AC_MASK | ID_MASK) + +/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */ +static inline void load_eflags(int eflags, int update_mask) +{ + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + env->eflags = (env->eflags & ~update_mask) | + (eflags & update_mask); +} diff --git a/helper-i386.c b/helper-i386.c index 66121ff96..9fc40181a 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -126,17 +126,74 @@ void cpu_loop_exit(void) longjmp(env->jmp_env, 1); } +static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, + uint32_t *esp_ptr, int dpl) +{ + int type, index, shift; + #if 0 -/* full interrupt support (only useful for real CPU emulation, not - finished) - I won't do it any time soon, finish it if you want ! */ -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip) + { + int i; + printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); + for(i=0;itr.limit;i++) { + printf("%02x ", env->tr.base[i]); + if ((i & 7) == 7) printf("\n"); + } + printf("\n"); + } +#endif + + if (!(env->tr.flags & DESC_P_MASK)) + cpu_abort(env, "invalid tss"); + type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; + if ((type & 7) != 1) + cpu_abort(env, "invalid tss type"); + shift = type >> 3; + index = (dpl * 4 + 2) << shift; + if (index + (4 << shift) - 1 > env->tr.limit) + raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); + if (shift == 0) { + *esp_ptr = lduw(env->tr.base + index); + *ss_ptr = lduw(env->tr.base + index + 2); + } else { + *esp_ptr = ldl(env->tr.base + index); + *ss_ptr = lduw(env->tr.base + index + 4); + } +} + +/* return non zero if error */ +static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, + int selector) { - SegmentDescriptorTable *dt; + SegmentCache *dt; + int index; uint8_t *ptr; - int type, dpl, cpl; - uint32_t e1, e2; - + + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + return -1; + ptr = dt->base + index; + *e1_ptr = ldl(ptr); + *e2_ptr = ldl(ptr + 4); + return 0; +} + + +/* protected mode interrupt */ +static void do_interrupt_protected(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentCache *dt; + uint8_t *ptr, *ssp; + int type, dpl, cpl, selector, ss_dpl; + int has_error_code, new_stack, shift; + uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; + uint32_t old_cs, old_ss, old_esp, old_eip; + dt = &env->idt; if (intno * 8 + 7 > dt->limit) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); @@ -147,6 +204,8 @@ void raise_interrupt(int intno, int is_int, int error_code, type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; switch(type) { case 5: /* task gate */ + cpu_abort(env, "task gate not supported"); + break; case 6: /* 286 interrupt gate */ case 7: /* 286 trap gate */ case 14: /* 386 interrupt gate */ @@ -164,17 +223,184 @@ void raise_interrupt(int intno, int is_int, int error_code, /* check valid bit */ if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); + selector = e1 >> 16; + offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); + if ((selector & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + if (!(e2 & DESC_C_MASK) && dpl < cpl) { + /* to inner priviledge */ + get_ss_esp_from_tss(&ss, &esp, dpl); + if ((ss & 0xfffc) == 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if ((ss & 3) != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, ss) != 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (ss_dpl != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + new_stack = 1; + } else if ((e2 & DESC_C_MASK) || dpl == cpl) { + /* to same priviledge */ + new_stack = 0; + } else { + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + new_stack = 0; /* avoid warning */ + } + + shift = type >> 3; + has_error_code = 0; + if (!is_int) { + switch(intno) { + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 17: + has_error_code = 1; + break; + } + } + push_size = 6 + (new_stack << 2) + (has_error_code << 1); + if (env->eflags & VM_MASK) + push_size += 8; + push_size <<= shift; + + /* XXX: check that enough room is available */ + if (new_stack) { + old_esp = env->regs[R_ESP]; + old_ss = env->segs[R_SS].selector; + load_seg(R_SS, ss, env->eip); + } else { + old_esp = 0; + old_ss = 0; + esp = env->regs[R_ESP]; + } + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; + old_cs = env->segs[R_CS].selector; + load_seg(R_CS, selector, env->eip); + env->eip = offset; + env->regs[R_ESP] = esp - push_size; + ssp = env->segs[R_SS].base + esp; + if (shift == 1) { + int old_eflags; + if (env->eflags & VM_MASK) { + ssp -= 4; + stl(ssp, env->segs[R_GS].selector); + ssp -= 4; + stl(ssp, env->segs[R_FS].selector); + ssp -= 4; + stl(ssp, env->segs[R_DS].selector); + ssp -= 4; + stl(ssp, env->segs[R_ES].selector); + } + if (new_stack) { + ssp -= 4; + stl(ssp, old_ss); + ssp -= 4; + stl(ssp, old_esp); + } + ssp -= 4; + old_eflags = compute_eflags(); + stl(ssp, old_eflags); + ssp -= 4; + stl(ssp, old_cs); + ssp -= 4; + stl(ssp, old_eip); + if (has_error_code) { + ssp -= 4; + stl(ssp, error_code); + } + } else { + if (new_stack) { + ssp -= 2; + stw(ssp, old_ss); + ssp -= 2; + stw(ssp, old_esp); + } + ssp -= 2; + stw(ssp, compute_eflags()); + ssp -= 2; + stw(ssp, old_cs); + ssp -= 2; + stw(ssp, old_eip); + if (has_error_code) { + ssp -= 2; + stw(ssp, error_code); + } + } + + /* interrupt gate clear IF mask */ + if ((type & 1) == 0) { + env->eflags &= ~IF_MASK; + } + env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); } -#else +/* real mode interrupt */ +static void do_interrupt_real(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentCache *dt; + uint8_t *ptr, *ssp; + int selector; + uint32_t offset, esp; + uint32_t old_cs, old_eip; -/* - * is_int is TRUE if coming from the int instruction. next_eip is the - * EIP value AFTER the interrupt instruction. It is only relevant if - * is_int is TRUE. - */ -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip) + /* real mode (simpler !) */ + dt = &env->idt; + if (intno * 4 + 3 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + ptr = dt->base + intno * 4; + offset = lduw(ptr); + selector = lduw(ptr + 2); + esp = env->regs[R_ESP] & 0xffff; + ssp = env->segs[R_SS].base + esp; + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; + old_cs = env->segs[R_CS].selector; + ssp -= 2; + stw(ssp, compute_eflags()); + ssp -= 2; + stw(ssp, old_cs); + ssp -= 2; + stw(ssp, old_eip); + esp -= 6; + + /* update processor state */ + env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); + env->eip = offset; + env->segs[R_CS].selector = selector; + env->segs[R_CS].base = (uint8_t *)(selector << 4); + env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); +} + +/* fake user mode interrupt */ +void do_interrupt_user(int intno, int is_int, int error_code, + unsigned int next_eip) { SegmentCache *dt; uint8_t *ptr; @@ -196,14 +422,39 @@ void raise_interrupt(int intno, int is_int, int error_code, code */ if (is_int) EIP = next_eip; +} + +/* + * Begin excution of an interruption. is_int is TRUE if coming from + * the int instruction. next_eip is the EIP value AFTER the interrupt + * instruction. It is only relevant if is_int is TRUE. + */ +void do_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + if (env->cr[0] & CR0_PE_MASK) { + do_interrupt_protected(intno, is_int, error_code, next_eip); + } else { + do_interrupt_real(intno, is_int, error_code, next_eip); + } +} + +/* + * Signal an interruption. It is executed in the main CPU loop. + * is_int is TRUE if coming from the int instruction. next_eip is the + * EIP value AFTER the interrupt instruction. It is only relevant if + * is_int is TRUE. + */ +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip) +{ env->exception_index = intno; env->error_code = error_code; - + env->exception_is_int = is_int; + env->exception_next_eip = next_eip; cpu_loop_exit(); } -#endif - /* shortcuts to generate exceptions */ void raise_exception_err(int exception_index, int error_code) { @@ -335,9 +586,9 @@ static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2) { sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & (1 << 23)) + if (e2 & DESC_G_MASK) sc->limit = (sc->limit << 12) | 0xfff; - sc->seg_32bit = (e2 >> 22) & 1; + sc->flags = e2; } void helper_lldt_T0(void) @@ -382,9 +633,10 @@ void helper_ltr_T0(void) selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) { - /* XXX: NULL selector case: invalid LDT */ + /* NULL selector case: invalid LDT */ env->tr.base = NULL; env->tr.limit = 0; + env->tr.flags = 0; } else { if (selector & 0x4) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); @@ -412,10 +664,7 @@ void helper_ltr_T0(void) void load_seg(int seg_reg, int selector, unsigned int cur_eip) { SegmentCache *sc; - SegmentCache *dt; - int index; uint32_t e1, e2; - uint8_t *ptr; sc = &env->segs[seg_reg]; if ((selector & 0xfffc) == 0) { @@ -427,21 +676,13 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) /* XXX: each access should trigger an exception */ sc->base = NULL; sc->limit = 0; - sc->seg_32bit = 1; + sc->flags = 0; } } else { - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) { + if (load_segment(&e1, &e2, selector) != 0) { EIP = cur_eip; raise_exception_err(EXCP0D_GPF, selector & 0xfffc); } - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); if (!(e2 & DESC_S_MASK) || (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { EIP = cur_eip; @@ -469,8 +710,8 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) } load_seg_cache(sc, e1, e2); #if 0 - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", - selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); + fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", + selector, (unsigned long)sc->base, sc->limit, sc->flags); #endif } sc->selector = selector; @@ -480,25 +721,14 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) void jmp_seg(int selector, unsigned int new_eip) { SegmentCache sc1; - SegmentCache *dt; - int index; uint32_t e1, e2, cpl, dpl, rpl; - uint8_t *ptr; if ((selector & 0xfffc) == 0) { raise_exception_err(EXCP0D_GPF, 0); } - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) + if (load_segment(&e1, &e2, selector) != 0) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); cpl = env->segs[R_CS].selector & 3; if (e2 & DESC_S_MASK) { if (!(e2 & DESC_CS_MASK)) @@ -530,22 +760,143 @@ void jmp_seg(int selector, unsigned int new_eip) } } -/* XXX: do more */ +/* init the segment cache in vm86 mode */ +static inline void load_seg_vm(int seg, int selector) +{ + SegmentCache *sc = &env->segs[seg]; + selector &= 0xffff; + sc->base = (uint8_t *)(selector << 4); + sc->selector = selector; + sc->flags = 0; + sc->limit = 0xffff; +} + +/* protected mode iret */ +void helper_iret_protected(int shift) +{ + uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; + uint32_t new_es, new_ds, new_fs, new_gs; + uint32_t e1, e2; + int cpl, dpl, rpl, eflags_mask; + uint8_t *ssp; + + sp = env->regs[R_ESP]; + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + sp &= 0xffff; + ssp = env->segs[R_SS].base + sp; + if (shift == 1) { + /* 32 bits */ + new_eflags = ldl(ssp + 8); + new_cs = ldl(ssp + 4) & 0xffff; + new_eip = ldl(ssp); + if (new_eflags & VM_MASK) + goto return_to_vm86; + } else { + /* 16 bits */ + new_eflags = lduw(ssp + 4); + new_cs = lduw(ssp + 2); + new_eip = lduw(ssp); + } + if ((new_cs & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (!(e2 & DESC_S_MASK) || + !(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpl = env->segs[R_CS].selector & 3; + rpl = new_cs & 3; + if (rpl < cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_CS_MASK) { + if (dpl > rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } else { + if (dpl != rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + + if (rpl == cpl) { + /* return to same priledge level */ + load_seg(R_CS, new_cs, env->eip); + new_esp = sp + (6 << shift); + } else { + /* return to differentr priviledge level */ + if (shift == 1) { + /* 32 bits */ + new_esp = ldl(ssp + 12); + new_ss = ldl(ssp + 16) & 0xffff; + } else { + /* 16 bits */ + new_esp = lduw(ssp + 6); + new_ss = lduw(ssp + 8); + } + + if ((new_ss & 3) != rpl) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (load_segment(&e1, &e2, new_ss) != 0) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (!(e2 & DESC_S_MASK) || + (e2 & DESC_CS_MASK) || + !(e2 & DESC_W_MASK)) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl != rpl) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); + + load_seg(R_CS, new_cs, env->eip); + load_seg(R_SS, new_ss, env->eip); + } + if (env->segs[R_SS].flags & DESC_B_MASK) + env->regs[R_ESP] = new_esp; + else + env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | + (new_esp & 0xffff); + env->eip = new_eip; + if (cpl == 0) + eflags_mask = FL_UPDATE_CPL0_MASK; + else + eflags_mask = FL_UPDATE_MASK32; + if (shift == 0) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); + return; + + return_to_vm86: + new_esp = ldl(ssp + 12); + new_ss = ldl(ssp + 16); + new_es = ldl(ssp + 20); + new_ds = ldl(ssp + 24); + new_fs = ldl(ssp + 28); + new_gs = ldl(ssp + 32); + + /* modify processor state */ + load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); + load_seg_vm(R_CS, new_cs); + load_seg_vm(R_SS, new_ss); + load_seg_vm(R_ES, new_es); + load_seg_vm(R_DS, new_ds); + load_seg_vm(R_FS, new_fs); + load_seg_vm(R_GS, new_gs); + + env->eip = new_eip; + env->regs[R_ESP] = new_esp; +} + void helper_movl_crN_T0(int reg) { + env->cr[reg] = T0; switch(reg) { case 0: - default: - env->cr[0] = reg; - break; - case 2: - env->cr[2] = reg; + cpu_x86_update_cr0(env); break; case 3: - env->cr[3] = reg; - break; - case 4: - env->cr[4] = reg; + cpu_x86_update_cr3(env); break; } } @@ -556,6 +907,11 @@ void helper_movl_drN_T0(int reg) env->dr[reg] = T0; } +void helper_invlpg(unsigned int addr) +{ + cpu_x86_flush_tlb(env, addr); +} + /* rdtsc */ #ifndef __i386__ uint64_t emu_time; @@ -577,23 +933,12 @@ void helper_rdtsc(void) void helper_lsl(void) { unsigned int selector, limit; - SegmentCache *dt; - int index; uint32_t e1, e2; - uint8_t *ptr; CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; selector = T0 & 0xffff; - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) + if (load_segment(&e1, &e2, selector) != 0) return; - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); limit = (e1 & 0xffff) | (e2 & 0x000f0000); if (e2 & (1 << 23)) limit = (limit << 12) | 0xfff; @@ -604,22 +949,12 @@ void helper_lsl(void) void helper_lar(void) { unsigned int selector; - SegmentCache *dt; - int index; - uint32_t e2; - uint8_t *ptr; + uint32_t e1, e2; CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; selector = T0 & 0xffff; - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) + if (load_segment(&e1, &e2, selector) != 0) return; - ptr = dt->base + index; - e2 = ldl(ptr + 4); T1 = e2 & 0x00f0ff00; CC_SRC |= CC_Z; } diff --git a/op-i386.c b/op-i386.c index 5836b1a1c..77f3303e3 100644 --- a/op-i386.c +++ b/op-i386.c @@ -493,6 +493,12 @@ void OPPROTO op_jmp_im(void) EIP = PARAM1; } +void OPPROTO op_hlt(void) +{ + env->exception_index = EXCP_HLT; + cpu_loop_exit(); +} + void OPPROTO op_raise_interrupt(void) { int intno; @@ -954,6 +960,11 @@ void OPPROTO op_ljmp_T0_T1(void) jmp_seg(T0 & 0xffff, T1); } +void OPPROTO op_iret_protected(void) +{ + helper_iret_protected(PARAM1); +} + void OPPROTO op_lldt_T0(void) { helper_lldt_T0(); @@ -983,6 +994,11 @@ void OPPROTO op_lmsw_T0(void) helper_movl_crN_T0(0); } +void OPPROTO op_invlpg_A0(void) +{ + helper_invlpg(A0); +} + void OPPROTO op_movl_T0_env(void) { T0 = *(uint32_t *)((char *)env + PARAM1); @@ -1082,8 +1098,7 @@ void OPPROTO op_set_cc_op(void) CC_OP = PARAM1; } -#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) -#define FL_UPDATE_MASK16 (TF_MASK) +#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff) void OPPROTO op_movl_eflags_T0(void) { @@ -1092,7 +1107,8 @@ void OPPROTO op_movl_eflags_T0(void) CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); DF = 1 - (2 * ((eflags >> 10) & 1)); /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | (eflags & FL_UPDATE_MASK32); + env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | + (eflags & FL_UPDATE_MASK32); } void OPPROTO op_movw_eflags_T0(void) @@ -1102,7 +1118,18 @@ void OPPROTO op_movw_eflags_T0(void) CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); DF = 1 - (2 * ((eflags >> 10) & 1)); /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16); + env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | + (eflags & FL_UPDATE_MASK16); +} + +void OPPROTO op_movl_eflags_T0_cpl0(void) +{ + load_eflags(T0, FL_UPDATE_CPL0_MASK); +} + +void OPPROTO op_movw_eflags_T0_cpl0(void) +{ + load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff); } #if 0 -- cgit v1.2.3 From 66e85a21c7f65540ac1976ed29ed9973089fe1f1 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:28:12 +0000 Subject: MMU support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@262 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++---- exec.c | 32 +++++++++++++++++++++++++++++++- exec.h | 9 ++++++--- 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index c4d6006d9..abbb03723 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -50,7 +50,8 @@ /* segment descriptor fields */ #define DESC_G_MASK (1 << 23) -#define DESC_B_MASK (1 << 22) +#define DESC_B_SHIFT 22 +#define DESC_B_MASK (1 << DESC_B_SHIFT) #define DESC_AVL_MASK (1 << 20) #define DESC_P_MASK (1 << 15) #define DESC_DPL_SHIFT 13 @@ -95,6 +96,34 @@ #define CR4_PVI_MASK (1 << 1) #define CR4_TSD_MASK (1 << 2) #define CR4_DE_MASK (1 << 3) +#define CR4_PSE_MASK (1 << 4) + +#define PG_PRESENT_BIT 0 +#define PG_RW_BIT 1 +#define PG_USER_BIT 2 +#define PG_PWT_BIT 3 +#define PG_PCD_BIT 4 +#define PG_ACCESSED_BIT 5 +#define PG_DIRTY_BIT 6 +#define PG_PSE_BIT 7 +#define PG_GLOBAL_BIT 8 + +#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT) +#define PG_RW_MASK (1 << PG_RW_BIT) +#define PG_USER_MASK (1 << PG_USER_BIT) +#define PG_PWT_MASK (1 << PG_PWT_BIT) +#define PG_PCD_MASK (1 << PG_PCD_BIT) +#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT) +#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT) +#define PG_PSE_MASK (1 << PG_PSE_BIT) +#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT) + +#define PG_ERROR_W_BIT 1 + +#define PG_ERROR_P_MASK 0x01 +#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT) +#define PG_ERROR_U_MASK 0x04 +#define PG_ERROR_RSVD_MASK 0x08 #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 @@ -116,6 +145,7 @@ #define EXCP12_MCHK 18 #define EXCP_INTERRUPT 256 /* async interruption */ +#define EXCP_HLT 257 /* hlt instruction reached */ enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ @@ -174,8 +204,8 @@ typedef double CPU86_LDouble; typedef struct SegmentCache { uint32_t selector; uint8_t *base; - unsigned long limit; - uint8_t seg_32bit; + uint32_t limit; + uint32_t flags; } SegmentCache; typedef struct CPUX86State { @@ -219,9 +249,16 @@ typedef struct CPUX86State { jmp_buf jmp_env; int exception_index; int error_code; + int exception_is_int; + int exception_next_eip; + uint32_t cr[5]; /* NOTE: cr1 is unused */ uint32_t dr[8]; /* debug registers */ - int interrupt_request; + int interrupt_request; /* if true, will exit from cpu_exec() ASAP */ + /* if true, will call cpu_x86_get_pic_interrupt() ASAP to get the + request interrupt number */ + int hard_interrupt_request; + int user_mode_only; /* user mode only simulation */ /* user data */ void *opaque; @@ -240,6 +277,7 @@ CPUX86State *cpu_x86_init(void); int cpu_x86_exec(CPUX86State *s); void cpu_x86_interrupt(CPUX86State *s); void cpu_x86_close(CPUX86State *s); +int cpu_x86_get_pic_interrupt(CPUX86State *s); /* needed to load some predefinied segment registers */ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); @@ -255,6 +293,13 @@ struct siginfo; int cpu_x86_signal_handler(int host_signum, struct siginfo *info, void *puc); +/* MMU defines */ +void cpu_x86_init_mmu(CPUX86State *env); +extern CPUX86State *global_env; +extern int phys_ram_size; +extern int phys_ram_fd; +extern uint8_t *phys_ram_base; + /* used to debug */ #define X86_DUMP_FPU 0x0001 /* dump FPU state too */ #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ diff --git a/exec.c b/exec.c index 79c2bd0b6..f7fdc0359 100644 --- a/exec.c +++ b/exec.c @@ -30,7 +30,7 @@ #include "exec.h" //#define DEBUG_TB_INVALIDATE -#define DEBUG_FLUSH +//#define DEBUG_FLUSH /* make various TB consistency checks */ //#define DEBUG_TB_CHECK @@ -579,3 +579,33 @@ void cpu_abort(CPUState *env, const char *fmt, ...) abort(); } +#ifdef TARGET_I386 +/* unmap all maped pages and flush all associated code */ +void page_unmap(void) +{ + PageDesc *p, *pmap; + unsigned long addr; + int i, j, ret; + + for(i = 0; i < L1_SIZE; i++) { + pmap = l1_map[i]; + if (pmap) { + p = pmap; + for(j = 0;j < L2_SIZE; j++) { + if (p->flags & PAGE_VALID) { + addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); + ret = munmap((void *)addr, TARGET_PAGE_SIZE); + if (ret != 0) { + fprintf(stderr, "Could not unmap page 0x%08lx\n", addr); + exit(1); + } + } + p++; + } + free(pmap); + l1_map[i] = NULL; + } + } + tb_flush(); +} +#endif diff --git a/exec.h b/exec.h index 5ab3589b1..bd36453ba 100644 --- a/exec.h +++ b/exec.h @@ -39,6 +39,7 @@ struct TranslationBlock; extern uint16_t gen_opc_buf[OPC_BUF_SIZE]; extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; extern uint32_t gen_opc_pc[OPC_BUF_SIZE]; +extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #if defined(TARGET_I386) @@ -57,14 +58,16 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; extern FILE *logfile; extern int loglevel; -int gen_intermediate_code(struct TranslationBlock *tb, int search_pc); +int gen_intermediate_code(struct TranslationBlock *tb); +int gen_intermediate_code_pc(struct TranslationBlock *tb); void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); int cpu_gen_code(struct TranslationBlock *tb, int max_code_size, int *gen_code_size_ptr); -int cpu_search_pc(struct TranslationBlock *tb, - uint32_t *found_pc, unsigned long searched_pc); +int cpu_restore_state(struct TranslationBlock *tb, + CPUState *env, unsigned long searched_pc); void cpu_exec_init(void); int page_unprotect(unsigned long address); +void page_unmap(void); #define CODE_GEN_MAX_SIZE 65536 #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ -- cgit v1.2.3 From 7d83131cc5ea95d7bb98658ac958a901ba4269de Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:28:48 +0000 Subject: use inline function git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@263 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-arm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/translate-arm.c b/translate-arm.c index 9b85b6851..2413f02a5 100644 --- a/translate-arm.c +++ b/translate-arm.c @@ -655,7 +655,7 @@ static void disas_arm_insn(DisasContext *s) /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -int gen_intermediate_code(TranslationBlock *tb, int search_pc) +static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc) { DisasContext dc1, *dc = &dc1; uint16_t *gen_opc_end; @@ -717,6 +717,16 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc) return 0; } +int gen_intermediate_code(TranslationBlock *tb) +{ + return gen_intermediate_code_internal(tb, 0); +} + +int gen_intermediate_code_pc(TranslationBlock *tb) +{ + return gen_intermediate_code_internal(tb, 1); +} + CPUARMState *cpu_arm_init(void) { CPUARMState *env; -- cgit v1.2.3 From dd3587f38e5c0745896da6b7b058d0f88fff86a0 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:29:40 +0000 Subject: iret and popl (%esp) tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@264 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386-code16.S | 17 +++++++++++++++++ tests/test-i386.c | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/test-i386-code16.S b/tests/test-i386-code16.S index 446f0d7bf..78ecc1f77 100644 --- a/tests/test-i386-code16.S +++ b/tests/test-i386-code16.S @@ -77,4 +77,21 @@ myfunc2: code16_end: + + +/* other 32 bits tests */ + .code32 + + .globl func_lret32 +func_lret32: + movl $0x87654321, %eax + lret + + .globl func_iret32 +func_iret32: + movl $0xabcd4321, %eax + iret + + + \ No newline at end of file diff --git a/tests/test-i386.c b/tests/test-i386.c index c2c332394..d5fe1c402 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -937,6 +937,9 @@ void test_code16(void) printf("func3() = 0x%08x\n", res); } +extern char func_lret32; +extern char func_iret32; + void test_misc(void) { char table[256]; @@ -946,6 +949,21 @@ void test_misc(void) res = 0x12345678; asm ("xlat" : "=a" (res) : "b" (table), "0" (res)); printf("xlat: EAX=%08x\n", res); + + asm volatile ("pushl %%cs ; call %1" + : "=a" (res) + : "m" (func_lret32): "memory", "cc"); + printf("func_lret32=%x\n", res); + + asm volatile ("pushfl ; pushl %%cs ; call %1" + : "=a" (res) + : "m" (func_iret32): "memory", "cc"); + printf("func_iret32=%x\n", res); + + /* specific popl test */ + asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0" + : "=g" (res)); + printf("popl esp=%x\n", res); } uint8_t str_buffer[4096]; -- cgit v1.2.3 From 92ccca6aa801f1ddb8d35f3812357c24a502d682 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:30:31 +0000 Subject: declare user mode only simulation for QEMU git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@265 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index df01a1c77..a8ae9c75a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -100,6 +100,11 @@ int cpu_x86_inl(CPUX86State *env, int addr) return 0; } +int cpu_x86_get_pic_interrupt(CPUX86State *env) +{ + return -1; +} + static void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags) { @@ -395,7 +400,7 @@ int main(int argc, char **argv) /* NOTE: we need to init the CPU at this stage to get the host_page_size */ env = cpu_init(); - + if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { printf("Error loading %s\n", filename); _exit(1); @@ -476,6 +481,8 @@ int main(int argc, char **argv) cpu_x86_load_seg(env, R_SS, __USER_DS); cpu_x86_load_seg(env, R_FS, __USER_DS); cpu_x86_load_seg(env, R_GS, __USER_DS); + env->user_mode_only = 1; + #elif defined(TARGET_ARM) { int i; -- cgit v1.2.3 From 6c0372d30be01e2a4664def829ed9682c2846d29 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:40:52 +0000 Subject: updated git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@266 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Changelog b/Changelog index 492fa1a83..ac743cb6c 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,10 @@ +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 + version 0.3: - initial support for ARM emulation -- cgit v1.2.3 From 0824d6fc674084519c856c433887221be099c549 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 13:42:40 +0000 Subject: for hard core developpers only: a new user mode linux project :-) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@267 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 + vl.c | 1383 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1387 insertions(+) create mode 100644 vl.c diff --git a/Makefile b/Makefile index 848c70774..859bd4529 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,10 @@ ifeq ($(ARCH),alpha) echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc endif +# must use static linking to avoid leaving stuff in virtual address space +vl: vl.o libqemu.a + $(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) + depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend diff --git a/vl.c b/vl.c new file mode 100644 index 000000000..35d0081d9 --- /dev/null +++ b/vl.c @@ -0,0 +1,1383 @@ +/* + * QEMU based User Mode Linux + * + * This file is part of proprietary software - it is published here + * only for demonstration and information purposes. + * + * Copyright (c) 2003 Fabrice Bellard + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu-i386.h" +#include "disas.h" + +#define DEBUG_LOGFILE "/tmp/vl.log" +//#define DEBUG_UNUSED_IOPORT + +#define PHYS_RAM_BASE 0xa8000000 +#define KERNEL_LOAD_ADDR 0x00100000 +#define INITRD_LOAD_ADDR 0x00400000 +#define KERNEL_PARAMS_ADDR 0x00090000 + +/* from plex86 (BSD license) */ +struct __attribute__ ((packed)) linux_params { + // For 0x00..0x3f, see 'struct screen_info' in linux/include/linux/tty.h. + // I just padded out the VESA parts, rather than define them. + + /* 0x000 */ uint8_t orig_x; + /* 0x001 */ uint8_t orig_y; + /* 0x002 */ uint16_t ext_mem_k; + /* 0x004 */ uint16_t orig_video_page; + /* 0x006 */ uint8_t orig_video_mode; + /* 0x007 */ uint8_t orig_video_cols; + /* 0x008 */ uint16_t unused1; + /* 0x00a */ uint16_t orig_video_ega_bx; + /* 0x00c */ uint16_t unused2; + /* 0x00e */ uint8_t orig_video_lines; + /* 0x00f */ uint8_t orig_video_isVGA; + /* 0x010 */ uint16_t orig_video_points; + /* 0x012 */ uint8_t pad0[0x20 - 0x12]; // VESA info. + /* 0x020 */ uint16_t cl_magic; // Commandline magic number (0xA33F) + /* 0x022 */ uint16_t cl_offset; // Commandline offset. Address of commandline + // is calculated as 0x90000 + cl_offset, bu + // only if cl_magic == 0xA33F. + /* 0x024 */ uint8_t pad1[0x40 - 0x24]; // VESA info. + + /* 0x040 */ uint8_t apm_bios_info[20]; // struct apm_bios_info + /* 0x054 */ uint8_t pad2[0x80 - 0x54]; + + // Following 2 from 'struct drive_info_struct' in drivers/block/cciss.h. + // Might be truncated? + /* 0x080 */ uint8_t hd0_info[16]; // hd0-disk-parameter from intvector 0x41 + /* 0x090 */ uint8_t hd1_info[16]; // hd1-disk-parameter from intvector 0x46 + + // System description table truncated to 16 bytes + // From 'struct sys_desc_table_struct' in linux/arch/i386/kernel/setup.c. + /* 0x0a0 */ uint16_t sys_description_len; + /* 0x0a2 */ uint8_t sys_description_table[14]; + // [0] machine id + // [1] machine submodel id + // [2] BIOS revision + // [3] bit1: MCA bus + + /* 0x0b0 */ uint8_t pad3[0x1e0 - 0xb0]; + /* 0x1e0 */ uint32_t alt_mem_k; + /* 0x1e4 */ uint8_t pad4[4]; + /* 0x1e8 */ uint8_t e820map_entries; + /* 0x1e9 */ uint8_t eddbuf_entries; // EDD_NR + /* 0x1ea */ uint8_t pad5[0x1f1 - 0x1ea]; + /* 0x1f1 */ uint8_t setup_sects; // size of setup.S, number of sectors + /* 0x1f2 */ uint16_t mount_root_rdonly; // MOUNT_ROOT_RDONLY (if !=0) + /* 0x1f4 */ uint16_t sys_size; // size of compressed kernel-part in the + // (b)zImage-file (in 16 byte units, rounded up) + /* 0x1f6 */ uint16_t swap_dev; // (unused AFAIK) + /* 0x1f8 */ uint16_t ramdisk_flags; + /* 0x1fa */ uint16_t vga_mode; // (old one) + /* 0x1fc */ uint16_t orig_root_dev; // (high=Major, low=minor) + /* 0x1fe */ uint8_t pad6[1]; + /* 0x1ff */ uint8_t aux_device_info; + /* 0x200 */ uint16_t jump_setup; // Jump to start of setup code, + // aka "reserved" field. + /* 0x202 */ uint8_t setup_signature[4]; // Signature for SETUP-header, ="HdrS" + /* 0x206 */ uint16_t header_format_version; // Version number of header format; + /* 0x208 */ uint8_t setup_S_temp0[8]; // Used by setup.S for communication with + // boot loaders, look there. + /* 0x210 */ uint8_t loader_type; + // 0 for old one. + // else 0xTV: + // T=0: LILO + // T=1: Loadlin + // T=2: bootsect-loader + // T=3: SYSLINUX + // T=4: ETHERBOOT + // V=version + /* 0x211 */ uint8_t loadflags; + // bit0 = 1: kernel is loaded high (bzImage) + // bit7 = 1: Heap and pointer (see below) set by boot + // loader. + /* 0x212 */ uint16_t setup_S_temp1; + /* 0x214 */ uint32_t kernel_start; + /* 0x218 */ uint32_t initrd_start; + /* 0x21c */ uint32_t initrd_size; + /* 0x220 */ uint8_t setup_S_temp2[4]; + /* 0x224 */ uint16_t setup_S_heap_end_pointer; + /* 0x226 */ uint8_t pad7[0x2d0 - 0x226]; + + /* 0x2d0 : Int 15, ax=e820 memory map. */ + // (linux/include/asm-i386/e820.h, 'struct e820entry') +#define E820MAX 32 +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ +#define E820_NVS 4 + struct { + uint64_t addr; + uint64_t size; + uint32_t type; + } e820map[E820MAX]; + + /* 0x550 */ uint8_t pad8[0x600 - 0x550]; + + // BIOS Enhanced Disk Drive Services. + // (From linux/include/asm-i386/edd.h, 'struct edd_info') + // Each 'struct edd_info is 78 bytes, times a max of 6 structs in array. + /* 0x600 */ uint8_t eddbuf[0x7d4 - 0x600]; + + /* 0x7d4 */ uint8_t pad9[0x800 - 0x7d4]; + /* 0x800 */ uint8_t commandline[0x800]; + + /* 0x1000 */ + uint64_t gdt_table[256]; + uint64_t idt_table[48]; +}; + +#define KERNEL_CS 0x10 +#define KERNEL_DS 0x18 + +typedef void (IOPortWriteFunc)(CPUX86State *env, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address); + +#define MAX_IOPORTS 1024 + +char phys_ram_file[1024]; +CPUX86State *global_env; +FILE *logfile = NULL; +int loglevel; +IOPortReadFunc *ioport_readb_table[MAX_IOPORTS]; +IOPortWriteFunc *ioport_writeb_table[MAX_IOPORTS]; +IOPortReadFunc *ioport_readw_table[MAX_IOPORTS]; +IOPortWriteFunc *ioport_writew_table[MAX_IOPORTS]; + +/***********************************************************/ +/* x86 io ports */ + +uint32_t default_ioport_readb(CPUX86State *env, uint32_t address) +{ +#ifdef DEBUG_UNUSED_IOPORT + fprintf(stderr, "inb: port=0x%04x\n", address); +#endif + return 0; +} + +void default_ioport_writeb(CPUX86State *env, uint32_t address, uint32_t data) +{ +#ifdef DEBUG_UNUSED_IOPORT + fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data); +#endif +} + +/* default is to make two byte accesses */ +uint32_t default_ioport_readw(CPUX86State *env, uint32_t address) +{ + uint32_t data; + data = ioport_readb_table[address](env, address); + data |= ioport_readb_table[address + 1](env, address + 1) << 8; + return data; +} + +void default_ioport_writew(CPUX86State *env, uint32_t address, uint32_t data) +{ + ioport_writeb_table[address](env, address, data & 0xff); + ioport_writeb_table[address + 1](env, address + 1, (data >> 8) & 0xff); +} + +void init_ioports(void) +{ + int i; + + for(i = 0; i < MAX_IOPORTS; i++) { + ioport_readb_table[i] = default_ioport_readb; + ioport_writeb_table[i] = default_ioport_writeb; + ioport_readw_table[i] = default_ioport_readw; + ioport_writew_table[i] = default_ioport_writew; + } +} + +int register_ioport_readb(int start, int length, IOPortReadFunc *func) +{ + int i; + + for(i = start; i < start + length; i++) + ioport_readb_table[i] = func; + return 0; +} + +int register_ioport_writeb(int start, int length, IOPortWriteFunc *func) +{ + int i; + + for(i = start; i < start + length; i++) + ioport_writeb_table[i] = func; + return 0; +} + +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 load_kernel(const char *filename, uint8_t *addr) +{ + int fd, size, setup_sects; + uint8_t bootsect[512]; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + if (read(fd, bootsect, 512) != 512) + goto fail; + setup_sects = bootsect[0x1F1]; + if (!setup_sects) + setup_sects = 4; + /* skip 16 bit setup code */ + lseek(fd, (setup_sects + 1) * 512, SEEK_SET); + size = read(fd, addr, 16 * 1024 * 1024); + if (size < 0) + goto fail; + close(fd); + return size; + fail: + close(fd); + return -1; +} + +/* return the size or -1 if error */ +int load_image(const char *filename, uint8_t *addr) +{ + int fd, size; + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + if (read(fd, addr, size) != size) { + close(fd); + return -1; + } + close(fd); + return size; +} + +void cpu_x86_outb(CPUX86State *env, int addr, int val) +{ + ioport_writeb_table[addr & (MAX_IOPORTS - 1)](env, addr, val); +} + +void cpu_x86_outw(CPUX86State *env, int addr, int val) +{ + ioport_writew_table[addr & (MAX_IOPORTS - 1)](env, addr, val); +} + +void cpu_x86_outl(CPUX86State *env, int addr, int val) +{ + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); +} + +int cpu_x86_inb(CPUX86State *env, int addr) +{ + return ioport_readb_table[addr & (MAX_IOPORTS - 1)](env, addr); +} + +int cpu_x86_inw(CPUX86State *env, int addr) +{ + return ioport_readw_table[addr & (MAX_IOPORTS - 1)](env, addr); +} + +int cpu_x86_inl(CPUX86State *env, int addr) +{ + fprintf(stderr, "inl: port=0x%04x\n", addr); + return 0; +} + +/***********************************************************/ +void ioport80_write(CPUX86State *env, uint32_t addr, uint32_t data) +{ +} + +void hw_error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "qemu: hardware error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); +#ifdef TARGET_I386 + cpu_x86_dump_state(global_env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP); +#endif + va_end(ap); + abort(); +} + +/***********************************************************/ +/* vga emulation */ +static uint8_t vga_index; +static uint8_t vga_regs[256]; +static int last_cursor_pos; + +void update_console_messages(void) +{ + int c, i, cursor_pos, eol; + + cursor_pos = vga_regs[0x0f] | (vga_regs[0x0e] << 8); + eol = 0; + for(i = last_cursor_pos; i < cursor_pos; i++) { + c = phys_ram_base[0xb8000 + (i) * 2]; + if (c >= ' ') { + putchar(c); + eol = 0; + } else { + if (!eol) + putchar('\n'); + eol = 1; + } + } + fflush(stdout); + last_cursor_pos = cursor_pos; +} + +/* just to see first Linux console messages, we intercept cursor position */ +void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) +{ + switch(addr) { + case 0x3d4: + vga_index = data; + break; + case 0x3d5: + vga_regs[vga_index] = data; + if (vga_index == 0x0f) + update_console_messages(); + break; + } + +} + +/***********************************************************/ +/* cmos emulation */ + +#define RTC_SECONDS 0 +#define RTC_SECONDS_ALARM 1 +#define RTC_MINUTES 2 +#define RTC_MINUTES_ALARM 3 +#define RTC_HOURS 4 +#define RTC_HOURS_ALARM 5 +#define RTC_ALARM_DONT_CARE 0xC0 + +#define RTC_DAY_OF_WEEK 6 +#define RTC_DAY_OF_MONTH 7 +#define RTC_MONTH 8 +#define RTC_YEAR 9 + +#define RTC_REG_A 10 +#define RTC_REG_B 11 +#define RTC_REG_C 12 +#define RTC_REG_D 13 + +/* PC cmos mappings */ +#define REG_EQUIPMENT_BYTE 0x14 + +uint8_t cmos_data[128]; +uint8_t cmos_index; + +void cmos_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) +{ + if (addr == 0x70) { + cmos_index = data & 0x7f; + } +} + +uint32_t cmos_ioport_read(CPUX86State *env, uint32_t addr) +{ + int ret; + + if (addr == 0x70) { + return 0xff; + } else { + /* toggle update-in-progress bit for Linux (same hack as + plex86) */ + ret = cmos_data[cmos_index]; + if (cmos_index == RTC_REG_A) + cmos_data[RTC_REG_A] ^= 0x80; + else if (cmos_index == RTC_REG_C) + cmos_data[RTC_REG_C] = 0x00; + return ret; + } +} + + +static inline int to_bcd(int a) +{ + return ((a / 10) << 4) | (a % 10); +} + +void cmos_init(void) +{ + struct tm *tm; + time_t ti; + + ti = time(NULL); + tm = gmtime(&ti); + cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); + cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); + cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); + cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); + cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); + cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon); + cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); + + cmos_data[RTC_REG_A] = 0x26; + cmos_data[RTC_REG_B] = 0x02; + cmos_data[RTC_REG_C] = 0x00; + cmos_data[RTC_REG_D] = 0x80; + + cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ + + register_ioport_writeb(0x70, 2, cmos_ioport_write); + register_ioport_readb(0x70, 2, cmos_ioport_read); +} + +/***********************************************************/ +/* 8259 pic emulation */ + +typedef struct PicState { + uint8_t last_irr; /* edge detection */ + uint8_t irr; /* interrupt request register */ + uint8_t imr; /* interrupt mask register */ + uint8_t isr; /* interrupt service register */ + uint8_t priority_add; /* used to compute irq priority */ + uint8_t irq_base; + uint8_t read_reg_select; + uint8_t special_mask; + uint8_t init_state; + uint8_t auto_eoi; + uint8_t rotate_on_autoeoi; + uint8_t init4; /* true if 4 byte init */ +} PicState; + +/* 0 is master pic, 1 is slave pic */ +PicState pics[2]; +int pic_irq_requested; + +/* set irq level. If an edge is detected, then the IRR is set to 1 */ +static inline void pic_set_irq1(PicState *s, int irq, int level) +{ + int mask; + mask = 1 << irq; + if (level) { + if ((s->last_irr & mask) == 0) + s->irr |= mask; + s->last_irr |= mask; + } else { + s->last_irr &= ~mask; + } +} + +static inline int get_priority(PicState *s, int mask) +{ + int priority; + if (mask == 0) + return -1; + priority = 7; + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) + priority--; + return priority; +} + +/* return the pic wanted interrupt. return -1 if none */ +static int pic_get_irq(PicState *s) +{ + int mask, cur_priority, priority; + + mask = s->irr & ~s->imr; + priority = get_priority(s, mask); + if (priority < 0) + return -1; + /* compute current priority */ + cur_priority = get_priority(s, s->isr); + if (priority > cur_priority) { + /* higher priority found: an irq should be generated */ + return priority; + } else { + return -1; + } +} + +void pic_set_irq(int irq, int level) +{ + pic_set_irq1(&pics[irq >> 3], irq & 7, level); +} + +/* can be called at any time outside cpu_exec() to raise irqs if + necessary */ +void pic_handle_irq(void) +{ + int irq2, irq; + + /* first look at slave pic */ + irq2 = pic_get_irq(&pics[1]); + if (irq2 >= 0) { + /* if irq request by slave pic, signal master PIC */ + pic_set_irq1(&pics[0], 2, 1); + pic_set_irq1(&pics[0], 2, 0); + } + /* look at requested irq */ + irq = pic_get_irq(&pics[0]); + if (irq >= 0) { + if (irq == 2) { + /* from slave pic */ + pic_irq_requested = 8 + irq2; + } else { + /* from master pic */ + pic_irq_requested = irq; + } + global_env->hard_interrupt_request = 1; + } +} + +int cpu_x86_get_pic_interrupt(CPUX86State *env) +{ + int irq, irq2, intno; + + /* signal the pic that the irq was acked by the CPU */ + irq = pic_irq_requested; + if (irq >= 8) { + irq2 = irq & 7; + pics[1].isr |= (1 << irq2); + pics[1].irr &= ~(1 << irq2); + irq = 2; + intno = pics[1].irq_base + irq2; + } else { + intno = pics[0].irq_base + irq; + } + pics[0].isr |= (1 << irq); + pics[0].irr &= ~(1 << irq); + return intno; +} + +void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + PicState *s; + int priority; + + s = &pics[addr >> 7]; + addr &= 1; + if (addr == 0) { + if (val & 0x10) { + /* init */ + memset(s, 0, sizeof(PicState)); + s->init_state = 1; + s->init4 = val & 1; + if (val & 0x02) + hw_error("single mode not supported"); + if (val & 0x08) + hw_error("level sensitive irq not supported"); + } else if (val & 0x08) { + if (val & 0x02) + s->read_reg_select = val & 1; + if (val & 0x40) + s->special_mask = (val >> 5) & 1; + } else { + switch(val) { + case 0x00: + case 0x80: + s->rotate_on_autoeoi = val >> 7; + break; + case 0x20: /* end of interrupt */ + case 0xa0: + priority = get_priority(s, s->isr); + if (priority >= 0) { + s->isr &= ~(1 << ((priority + s->priority_add) & 7)); + } + if (val == 0xa0) + s->priority_add = (s->priority_add + 1) & 7; + break; + case 0x60 ... 0x67: + priority = val & 7; + s->isr &= ~(1 << priority); + break; + case 0xc0 ... 0xc7: + s->priority_add = (val + 1) & 7; + break; + case 0xe0 ... 0xe7: + priority = val & 7; + s->isr &= ~(1 << priority); + s->priority_add = (priority + 1) & 7; + break; + } + } + } else { + switch(s->init_state) { + case 0: + /* normal mode */ + s->imr = val; + break; + case 1: + s->irq_base = val & 0xf8; + s->init_state = 2; + break; + case 2: + if (s->init4) { + s->init_state = 3; + } else { + s->init_state = 0; + } + break; + case 3: + s->auto_eoi = (val >> 1) & 1; + s->init_state = 0; + break; + } + } +} + +uint32_t pic_ioport_read(CPUX86State *env, uint32_t addr) +{ + PicState *s; + s = &pics[addr >> 7]; + addr &= 1; + if (addr == 0) { + if (s->read_reg_select) + return s->isr; + else + return s->irr; + } else { + return s->imr; + } +} + +void pic_init(void) +{ + register_ioport_writeb(0x20, 2, pic_ioport_write); + register_ioport_readb(0x20, 2, pic_ioport_read); + register_ioport_writeb(0xa0, 2, pic_ioport_write); + register_ioport_readb(0xa0, 2, pic_ioport_read); +} + +/***********************************************************/ +/* 8253 PIT emulation */ + +#define PIT_FREQ 1193182 + +#define RW_STATE_LSB 0 +#define RW_STATE_MSB 1 +#define RW_STATE_WORD0 2 +#define RW_STATE_WORD1 3 +#define RW_STATE_LATCHED_WORD0 4 +#define RW_STATE_LATCHED_WORD1 5 + +typedef struct PITChannelState { + uint16_t count; + uint16_t latched_count; + uint8_t rw_state; + uint8_t mode; + uint8_t bcd; /* not supported */ + uint8_t gate; /* timer start */ + int64_t count_load_time; +} PITChannelState; + +PITChannelState pit_channels[3]; +int speaker_data_on; + +int64_t ticks_per_sec; + +int64_t get_clock(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000LL + tv.tv_usec; +} + +int64_t cpu_get_ticks(void) +{ + int64_t val; + asm("rdtsc" : "=A" (val)); + return val; +} + +void cpu_calibrate_ticks(void) +{ + int64_t usec, ticks; + + usec = get_clock(); + ticks = cpu_get_ticks(); + usleep(50 * 1000); + usec = get_clock() - usec; + ticks = cpu_get_ticks() - ticks; + ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; +} + +static int pit_get_count(PITChannelState *s) +{ + int64_t d; + int counter; + + d = ((cpu_get_ticks() - s->count_load_time) * PIT_FREQ) / + ticks_per_sec; + switch(s->mode) { + case 0: + case 1: + case 4: + case 5: + counter = (s->count - d) & 0xffff; + break; + default: + counter = s->count - (d % s->count); + break; + } + return counter; +} + +/* get pit output bit */ +static int pit_get_out(PITChannelState *s) +{ + int64_t d; + int out; + + d = ((cpu_get_ticks() - s->count_load_time) * PIT_FREQ) / + ticks_per_sec; + switch(s->mode) { + default: + case 0: + out = (d >= s->count); + break; + case 1: + out = (d < s->count); + break; + case 2: + if ((d % s->count) == 0 && d != 0) + out = 1; + else + out = 0; + break; + case 3: + out = (d % s->count) < (s->count >> 1); + break; + case 4: + case 5: + out = (d == s->count); + break; + } + return out; +} + +void pit_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + int channel, access; + PITChannelState *s; + + addr &= 3; + if (addr == 3) { + channel = val >> 6; + if (channel == 3) + return; + s = &pit_channels[channel]; + access = (val >> 4) & 3; + switch(access) { + case 0: + s->latched_count = pit_get_count(s); + s->rw_state = RW_STATE_LATCHED_WORD0; + break; + default: + s->rw_state = access - 1 + RW_STATE_LSB; + break; + } + s->mode = (val >> 1) & 7; + s->bcd = val & 1; + } else { + s = &pit_channels[addr]; + switch(s->rw_state) { + case RW_STATE_LSB: + s->count_load_time = cpu_get_ticks(); + s->count = val; + break; + case RW_STATE_MSB: + s->count_load_time = cpu_get_ticks(); + s->count = (val << 8); + break; + case RW_STATE_WORD0: + case RW_STATE_WORD1: + if (s->rw_state & 1) { + s->count_load_time = cpu_get_ticks(); + s->count = (s->latched_count & 0xff) | (val << 8); + } else { + s->latched_count = val; + } + s->rw_state ^= 1; + break; + } + } +} + +uint32_t pit_ioport_read(CPUX86State *env, uint32_t addr) +{ + int ret, count; + PITChannelState *s; + + addr &= 3; + s = &pit_channels[addr]; + switch(s->rw_state) { + case RW_STATE_LSB: + case RW_STATE_MSB: + case RW_STATE_WORD0: + case RW_STATE_WORD1: + count = pit_get_count(s); + if (s->rw_state & 1) + ret = (count >> 8) & 0xff; + else + ret = count & 0xff; + if (s->rw_state & 2) + s->rw_state ^= 1; + break; + default: + case RW_STATE_LATCHED_WORD0: + case RW_STATE_LATCHED_WORD1: + if (s->rw_state & 1) + ret = s->latched_count >> 8; + else + ret = s->latched_count & 0xff; + s->rw_state ^= 1; + break; + } + return ret; +} + +void speaker_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + speaker_data_on = (val >> 1) & 1; + pit_channels[2].gate = val & 1; +} + +uint32_t speaker_ioport_read(CPUX86State *env, uint32_t addr) +{ + int out; + out = pit_get_out(&pit_channels[2]); + return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5); +} + +void pit_init(void) +{ + pit_channels[0].gate = 1; + pit_channels[1].gate = 1; + pit_channels[2].gate = 0; + + register_ioport_writeb(0x40, 4, pit_ioport_write); + register_ioport_readb(0x40, 3, pit_ioport_read); + + register_ioport_readb(0x61, 1, speaker_ioport_read); + register_ioport_writeb(0x61, 1, speaker_ioport_write); + cpu_calibrate_ticks(); +} + +/***********************************************************/ +/* serial port emulation */ + +#define UART_IRQ 4 + +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ + +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ + +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ + +#define UART_IIR_MSI 0x00 /* Modem status interrupt */ +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ + +#define UART_LSR_TEMT 0x40 /* Transmitter empty */ +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ +#define UART_LSR_BI 0x10 /* Break interrupt indicator */ +#define UART_LSR_FE 0x08 /* Frame error indicator */ +#define UART_LSR_PE 0x04 /* Parity error indicator */ +#define UART_LSR_OE 0x02 /* Overrun error indicator */ +#define UART_LSR_DR 0x01 /* Receiver data ready */ + +typedef struct SerialState { + uint8_t divider; + uint8_t rbr; /* receive register */ + uint8_t ier; + uint8_t iir; /* read only */ + uint8_t lcr; + uint8_t mcr; + uint8_t lsr; /* read only */ + uint8_t msr; + uint8_t scr; +} SerialState; + +SerialState serial_ports[1]; + +void serial_update_irq(void) +{ + SerialState *s = &serial_ports[0]; + + if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { + s->iir = UART_IIR_RDI; + } else if ((s->lsr & UART_LSR_THRE) && (s->ier & UART_IER_THRI)) { + s->iir = UART_IIR_THRI; + } else { + s->iir = UART_IIR_NO_INT; + } + if (s->iir != UART_IIR_NO_INT) { + pic_set_irq(UART_IRQ, 1); + } else { + pic_set_irq(UART_IRQ, 0); + } +} + +void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + SerialState *s = &serial_ports[0]; + unsigned char ch; + int ret; + + addr &= 7; + switch(addr) { + default: + case 0: + if (s->lcr & UART_LCR_DLAB) { + s->divider = (s->divider & 0xff00) | val; + } else { + s->lsr &= ~UART_LSR_THRE; + serial_update_irq(); + + ch = val; + do { + ret = write(1, &ch, 1); + } while (ret != 1); + s->lsr |= UART_LSR_THRE; + s->lsr |= UART_LSR_TEMT; + serial_update_irq(); + } + break; + case 1: + if (s->lcr & UART_LCR_DLAB) { + s->divider = (s->divider & 0x00ff) | (val << 8); + } else { + s->ier = val; + serial_update_irq(); + } + break; + case 2: + break; + case 3: + s->lcr = val; + break; + case 4: + s->mcr = val; + break; + case 5: + break; + case 6: + s->msr = val; + break; + case 7: + s->scr = val; + break; + } +} + +uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr) +{ + SerialState *s = &serial_ports[0]; + uint32_t ret; + + addr &= 7; + switch(addr) { + default: + case 0: + if (s->lcr & UART_LCR_DLAB) { + ret = s->divider & 0xff; + } else { + ret = s->rbr; + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); + serial_update_irq(); + } + break; + case 1: + if (s->lcr & UART_LCR_DLAB) { + ret = (s->divider >> 8) & 0xff; + } else { + ret = s->ier; + } + break; + case 2: + ret = s->iir; + break; + case 3: + ret = s->lcr; + break; + case 4: + ret = s->mcr; + break; + case 5: + ret = s->lsr; + break; + case 6: + ret = s->msr; + break; + case 7: + ret = s->scr; + break; + } + return ret; +} + +#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ +static int term_got_escape; + +void term_print_help(void) +{ + printf("\n" + "C-a h print this help\n" + "C-a x exit emulatior\n" + "C-a b send break (magic sysrq)\n" + "C-a C-a send C-a\n" + ); +} + +/* called when a char is received */ +void serial_received_byte(SerialState *s, int ch) +{ + if (term_got_escape) { + term_got_escape = 0; + switch(ch) { + case 'h': + term_print_help(); + break; + case 'x': + exit(0); + break; + case 'b': + /* send break */ + s->rbr = 0; + s->lsr |= UART_LSR_BI | UART_LSR_DR; + serial_update_irq(); + break; + case TERM_ESCAPE: + goto send_char; + } + } else if (ch == TERM_ESCAPE) { + term_got_escape = 1; + } else { + send_char: + s->rbr = ch; + s->lsr |= UART_LSR_DR; + serial_update_irq(); + } +} + +/* init terminal so that we can grab keys */ +static struct termios oldtty; + +static void term_exit(void) +{ + tcsetattr (0, TCSANOW, &oldtty); +} + +static void term_init(void) +{ + struct termios tty; + + tcgetattr (0, &tty); + oldtty = tty; + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + tcsetattr (0, TCSANOW, &tty); + + atexit(term_exit); + + fcntl(0, F_SETFL, O_NONBLOCK); +} + +void serial_init(void) +{ + SerialState *s = &serial_ports[0]; + + s->lsr = UART_LSR_TEMT | UART_LSR_THRE; + + register_ioport_writeb(0x3f8, 8, serial_ioport_write); + register_ioport_readb(0x3f8, 8, serial_ioport_read); + + term_init(); +} + +/* cpu signal handler */ +static void host_segv_handler(int host_signum, siginfo_t *info, + void *puc) +{ + if (cpu_signal_handler(host_signum, info, puc)) + return; + term_exit(); + abort(); +} + +static int timer_irq_pending; + +static void host_alarm_handler(int host_signum, siginfo_t *info, + void *puc) +{ + /* just exit from the cpu to have a change to handle timers */ + cpu_x86_interrupt(global_env); + timer_irq_pending = 1; +} + +void help(void) +{ + printf("Virtual Linux version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + "usage: vl [-h] bzImage initrd [kernel parameters...]\n" + "\n" + "'bzImage' is a Linux kernel image (PAGE_OFFSET must be defined\n" + "to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n" + "'initrd' is an initrd image\n" + "-m megs set virtual RAM size to megs MB\n" + "-d output log in /tmp/vl.log\n" + "\n" + "During emulation, use C-a h to get terminal commands:\n" + ); + term_print_help(); + exit(1); +} + +int main(int argc, char **argv) +{ + int c, ret, initrd_size, i; + struct linux_params *params; + struct sigaction act; + struct itimerval itv; + CPUX86State *env; + + /* we never want that malloc() uses mmap() */ + mallopt(M_MMAP_THRESHOLD, 4096 * 1024); + + phys_ram_size = 32 * 1024 * 1024; + for(;;) { + c = getopt(argc, argv, "hm:d"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 'm': + phys_ram_size = atoi(optarg) * 1024 * 1024; + if (phys_ram_size <= 0) + help(); + break; + case 'd': + loglevel = 1; + break; + } + } + if (optind + 1 >= argc) + help(); + + /* init debug */ + if (loglevel) { + logfile = fopen(DEBUG_LOGFILE, "w"); + if (!logfile) { + perror(DEBUG_LOGFILE); + _exit(1); + } + setvbuf(logfile, NULL, _IOLBF, 0); + } + + /* init the memory */ + strcpy(phys_ram_file, "/tmp/vlXXXXXX"); + if (mkstemp(phys_ram_file) < 0) { + fprintf(stderr, "Could not create temporary memory file\n"); + exit(1); + } + phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); + if (phys_ram_fd < 0) { + fprintf(stderr, "Could not open temporary memory file\n"); + exit(1); + } + ftruncate(phys_ram_fd, phys_ram_size); + unlink(phys_ram_file); + phys_ram_base = mmap((void *)PHYS_RAM_BASE, phys_ram_size, + PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, + phys_ram_fd, 0); + if (phys_ram_base == MAP_FAILED) { + fprintf(stderr, "Could not map physical memory\n"); + exit(1); + } + + /* now we can load the kernel */ + ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) { + fprintf(stderr, "%s: could not load kernel\n", argv[optind]); + exit(1); + } + + /* load initrd */ + initrd_size = load_image(argv[optind + 1], phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "%s: could not load initrd\n", argv[optind + 1]); + exit(1); + } + + /* init kernel params */ + params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR); + memset(params, 0, sizeof(struct linux_params)); + params->mount_root_rdonly = 0; + params->cl_magic = 0xA33F; + params->cl_offset = params->commandline - (uint8_t *)params; + params->ext_mem_k = (phys_ram_size / 1024) - 1024; + for(i = optind + 2; i < argc; i++) { + if (i != optind + 2) + pstrcat(params->commandline, sizeof(params->commandline), " "); + pstrcat(params->commandline, sizeof(params->commandline), argv[i]); + } + params->loader_type = 0x01; + if (initrd_size > 0) { + params->initrd_start = INITRD_LOAD_ADDR; + params->initrd_size = initrd_size; + } + params->orig_video_lines = 25; + params->orig_video_cols = 80; + + /* init basic PC hardware */ + init_ioports(); + register_ioport_writeb(0x80, 1, ioport80_write); + + register_ioport_writeb(0x3d4, 2, vga_ioport_write); + + cmos_init(); + pic_init(); + pit_init(); + serial_init(); + + /* setup cpu signal handlers for MMU / self modifying code handling */ + sigfillset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = host_segv_handler; + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGBUS, &act, NULL); + + act.sa_sigaction = host_alarm_handler; + sigaction(SIGALRM, &act, NULL); + + /* init CPU state */ + env = cpu_init(); + global_env = env; + + /* setup basic memory access */ + env->cr[0] = 0x00000033; + cpu_x86_init_mmu(env); + + memset(params->idt_table, 0, sizeof(params->idt_table)); + + params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ + params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */ + + env->idt.base = (void *)params->idt_table; + env->idt.limit = sizeof(params->idt_table) - 1; + env->gdt.base = (void *)params->gdt_table; + env->gdt.limit = sizeof(params->gdt_table) - 1; + + cpu_x86_load_seg(env, R_CS, KERNEL_CS); + cpu_x86_load_seg(env, R_DS, KERNEL_DS); + cpu_x86_load_seg(env, R_ES, KERNEL_DS); + cpu_x86_load_seg(env, R_SS, KERNEL_DS); + cpu_x86_load_seg(env, R_FS, KERNEL_DS); + cpu_x86_load_seg(env, R_GS, KERNEL_DS); + + env->eip = KERNEL_LOAD_ADDR; + env->regs[R_ESI] = KERNEL_PARAMS_ADDR; + env->eflags = 0x2; + + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 10 * 1000; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 10 * 1000; + setitimer(ITIMER_REAL, &itv, NULL); + + for(;;) { + struct pollfd ufds[1], *pf; + int ret, n, timeout; + uint8_t ch; + + ret = cpu_x86_exec(env); + + /* if hlt instruction, we wait until the next IRQ */ + if (ret == EXCP_HLT) + timeout = 10; + else + timeout = 0; + /* poll any events */ + pf = ufds; + if (!(serial_ports[0].lsr & UART_LSR_DR)) { + pf->fd = 0; + pf->events = POLLIN; + pf++; + } + ret = poll(ufds, pf - ufds, timeout); + if (ret > 0) { + if (ufds[0].revents & POLLIN) { + n = read(0, &ch, 1); + if (n == 1) { + serial_received_byte(&serial_ports[0], ch); + } + } + } + + /* just for testing */ + if (timer_irq_pending) { + pic_set_irq(0, 1); + pic_set_irq(0, 0); + timer_irq_pending = 0; + } + + pic_handle_irq(); + } + + return 0; +} -- cgit v1.2.3 From 357a94326c335d061aed6ea297b80c046875e0a9 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Jun 2003 14:39:12 +0000 Subject: added link script for vl git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@268 c046a42c-6fe2-441c-8c8c-71466251a162 --- i386-vl.ld | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 i386-vl.ld diff --git a/i386-vl.ld b/i386-vl.ld new file mode 100644 index 000000000..86696f4d0 --- /dev/null +++ b/i386-vl.ld @@ -0,0 +1,130 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0xa0000000 + 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 . */ +} -- cgit v1.2.3 From f1510b2cc3529b1bf26107c3d3890a4efb793afe Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 00:07:40 +0000 Subject: added NE2000 emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@269 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 534 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 529 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index 35d0081d9..b97f74fef 100644 --- a/vl.c +++ b/vl.c @@ -21,11 +21,19 @@ #include #include #include +#include + +#include +#include +#include +#include #include "cpu-i386.h" #include "disas.h" #define DEBUG_LOGFILE "/tmp/vl.log" +#define DEFAULT_NETWORK_SCRIPT "/etc/vl-ifup" + //#define DEBUG_UNUSED_IOPORT #define PHYS_RAM_BASE 0xa8000000 @@ -225,6 +233,24 @@ int register_ioport_writeb(int start, int length, IOPortWriteFunc *func) return 0; } +int register_ioport_readw(int start, int length, IOPortReadFunc *func) +{ + int i; + + for(i = start; i < start + length; i += 2) + ioport_readw_table[i] = func; + return 0; +} + +int register_ioport_writew(int start, int length, IOPortWriteFunc *func) +{ + int i; + + for(i = start; i < start + length; i += 2) + ioport_writew_table[i] = func; + return 0; +} + void pstrcpy(char *buf, int buf_size, const char *str) { int c; @@ -1149,6 +1175,474 @@ void serial_init(void) term_init(); } +/***********************************************************/ +/* ne2000 emulation */ + +//#define DEBUG_NE2000 + +#define NE2000_IOPORT 0x300 +#define NE2000_IRQ 9 + +#define MAX_ETH_FRAME_SIZE 1514 + +#define E8390_CMD 0x00 /* The command register (for all pages) */ +/* Page 0 register offsets. */ +#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ +#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ +#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ +#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ +#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ +#define EN0_TSR 0x04 /* Transmit status reg RD */ +#define EN0_TPSR 0x04 /* Transmit starting page WR */ +#define EN0_NCR 0x05 /* Number of collision reg RD */ +#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ +#define EN0_FIFO 0x06 /* FIFO RD */ +#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ +#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ +#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ +#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ +#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ +#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ +#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ +#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ +#define EN0_RSR 0x0c /* rx status reg RD */ +#define EN0_RXCR 0x0c /* RX configuration reg WR */ +#define EN0_TXCR 0x0d /* TX configuration reg WR */ +#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ +#define EN0_DCFG 0x0e /* Data configuration reg WR */ +#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ +#define EN0_IMR 0x0f /* Interrupt mask reg WR */ +#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ + +#define EN1_PHYS 0x11 +#define EN1_CURPAG 0x17 +#define EN1_MULT 0x18 + +/* Register accessed at EN_CMD, the 8390 base addr. */ +#define E8390_STOP 0x01 /* Stop and reset the chip */ +#define E8390_START 0x02 /* Start the chip, clear reset */ +#define E8390_TRANS 0x04 /* Transmit a frame */ +#define E8390_RREAD 0x08 /* Remote read */ +#define E8390_RWRITE 0x10 /* Remote write */ +#define E8390_NODMA 0x20 /* Remote DMA */ +#define E8390_PAGE0 0x00 /* Select page chip registers */ +#define E8390_PAGE1 0x40 /* using the two high-order bits */ +#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ + +/* Bits in EN0_ISR - Interrupt status register */ +#define ENISR_RX 0x01 /* Receiver, no error */ +#define ENISR_TX 0x02 /* Transmitter, no error */ +#define ENISR_RX_ERR 0x04 /* Receiver, with error */ +#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ +#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ +#define ENISR_COUNTERS 0x20 /* Counters need emptying */ +#define ENISR_RDC 0x40 /* remote dma complete */ +#define ENISR_RESET 0x80 /* Reset completed */ +#define ENISR_ALL 0x3f /* Interrupts we will enable */ + +/* Bits in received packet status byte and EN0_RSR*/ +#define ENRSR_RXOK 0x01 /* Received a good packet */ +#define ENRSR_CRC 0x02 /* CRC error */ +#define ENRSR_FAE 0x04 /* frame alignment error */ +#define ENRSR_FO 0x08 /* FIFO overrun */ +#define ENRSR_MPA 0x10 /* missed pkt */ +#define ENRSR_PHY 0x20 /* physical/multicast address */ +#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ +#define ENRSR_DEF 0x80 /* deferring */ + +/* Transmitted packet status, EN0_TSR. */ +#define ENTSR_PTX 0x01 /* Packet transmitted without error */ +#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ +#define ENTSR_COL 0x04 /* The transmit collided at least once. */ +#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ +#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ +#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ +#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ +#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ + +#define NE2000_MEM_SIZE 32768 + +typedef struct NE2000State { + uint8_t cmd; + uint32_t start; + uint32_t stop; + uint8_t boundary; + uint8_t tsr; + uint8_t tpsr; + uint16_t tcnt; + uint16_t rcnt; + uint32_t rsar; + uint8_t isr; + uint8_t dcfg; + uint8_t imr; + uint8_t phys[6]; /* mac address */ + uint8_t curpag; + uint8_t mult[8]; /* multicast mask array */ + uint8_t mem[NE2000_MEM_SIZE]; +} NE2000State; + +NE2000State ne2000_state; +int net_fd = -1; +char network_script[1024]; + +void ne2000_reset(void) +{ + NE2000State *s = &ne2000_state; + int i; + + s->isr = ENISR_RESET; + s->mem[0] = 0x52; + s->mem[1] = 0x54; + s->mem[2] = 0x00; + s->mem[3] = 0x12; + s->mem[4] = 0x34; + s->mem[5] = 0x56; + s->mem[14] = 0x57; + s->mem[15] = 0x57; + + /* duplicate prom data */ + for(i = 15;i >= 0; i--) { + s->mem[2 * i] = s->mem[i]; + s->mem[2 * i + 1] = s->mem[i]; + } +} + +void ne2000_update_irq(NE2000State *s) +{ + int isr; + isr = s->isr & s->imr; + if (isr) + pic_set_irq(NE2000_IRQ, 1); + else + pic_set_irq(NE2000_IRQ, 0); +} + +int net_init(void) +{ + struct ifreq ifr; + int fd, ret, pid, status; + + fd = open("/dev/net/tun", O_RDWR); + if (fd < 0) { + fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); + return -1; + } + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d"); + ret = ioctl(fd, TUNSETIFF, (void *) &ifr); + if (ret != 0) { + fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); + close(fd); + return -1; + } + printf("connected to host network interface: %s\n", ifr.ifr_name); + fcntl(fd, F_SETFL, O_NONBLOCK); + net_fd = fd; + + /* try to launch network init script */ + pid = fork(); + if (pid >= 0) { + if (pid == 0) { + execl(network_script, network_script, ifr.ifr_name, NULL); + exit(1); + } + while (waitpid(pid, &status, 0) != pid); + if (!WIFEXITED(status) || + WEXITSTATUS(status) != 0) { + fprintf(stderr, "%s: could not launch network script for '%s'\n", + network_script, ifr.ifr_name); + } + } + return 0; +} + +void net_send_packet(NE2000State *s, const uint8_t *buf, int size) +{ +#ifdef DEBUG_NE2000 + printf("NE2000: sending packet size=%d\n", size); +#endif + write(net_fd, buf, size); +} + +/* return true if the NE2000 can receive more data */ +int ne2000_can_receive(NE2000State *s) +{ + int avail, index, boundary; + + if (s->cmd & E8390_STOP) + return 0; + index = s->curpag << 8; + boundary = s->boundary << 8; + if (index < boundary) + avail = boundary - index; + else + avail = (s->stop - s->start) - (index - boundary); + if (avail < (MAX_ETH_FRAME_SIZE + 4)) + return 0; + return 1; +} + +void ne2000_receive(NE2000State *s, uint8_t *buf, int size) +{ + uint8_t *p; + int total_len, next, avail, len, index; + +#if defined(DEBUG_NE2000) + printf("NE2000: received len=%d\n", size); +#endif + + index = s->curpag << 8; + /* 4 bytes for header */ + total_len = size + 4; + /* address for next packet (4 bytes for CRC) */ + next = index + ((total_len + 4 + 255) & ~0xff); + if (next >= s->stop) + next -= (s->stop - s->start); + /* prepare packet header */ + p = s->mem + index; + p[0] = ENRSR_RXOK; /* receive status */ + p[1] = next >> 8; + p[2] = total_len; + p[3] = total_len >> 8; + index += 4; + + /* write packet data */ + while (size > 0) { + avail = s->stop - index; + len = size; + if (len > avail) + len = avail; + memcpy(s->mem + index, buf, len); + buf += len; + index += len; + if (index == s->stop) + index = s->start; + size -= len; + } + s->curpag = next >> 8; + + /* now we can signal we have receive something */ + s->isr |= ENISR_RX; + ne2000_update_irq(s); +} + +void ne2000_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + NE2000State *s = &ne2000_state; + int offset, page; + + addr &= 0xf; +#ifdef DEBUG_NE2000 + printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val); +#endif + if (addr == E8390_CMD) { + /* control register */ + s->cmd = val; + if (val & E8390_START) { + /* test specific case: zero length transfert */ + if ((val & (E8390_RREAD | E8390_RWRITE)) && + s->rcnt == 0) { + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } + if (val & E8390_TRANS) { + net_send_packet(s, s->mem + (s->tpsr << 8), s->tcnt); + /* signal end of transfert */ + s->tsr = ENTSR_PTX; + s->isr |= ENISR_TX; + ne2000_update_irq(s); + } + } + } else { + page = s->cmd >> 6; + offset = addr | (page << 4); + switch(offset) { + case EN0_STARTPG: + s->start = val << 8; + break; + case EN0_STOPPG: + s->stop = val << 8; + break; + case EN0_BOUNDARY: + s->boundary = val; + break; + case EN0_IMR: + s->imr = val; + ne2000_update_irq(s); + break; + case EN0_TPSR: + s->tpsr = val; + break; + case EN0_TCNTLO: + s->tcnt = (s->tcnt & 0xff00) | val; + break; + case EN0_TCNTHI: + s->tcnt = (s->tcnt & 0x00ff) | (val << 8); + break; + case EN0_RSARLO: + s->rsar = (s->rsar & 0xff00) | val; + break; + case EN0_RSARHI: + s->rsar = (s->rsar & 0x00ff) | (val << 8); + break; + case EN0_RCNTLO: + s->rcnt = (s->rcnt & 0xff00) | val; + break; + case EN0_RCNTHI: + s->rcnt = (s->rcnt & 0x00ff) | (val << 8); + break; + case EN0_DCFG: + s->dcfg = val; + break; + case EN0_ISR: + s->isr &= ~val; + ne2000_update_irq(s); + break; + case EN1_PHYS ... EN1_PHYS + 5: + s->phys[offset - EN1_PHYS] = val; + break; + case EN1_CURPAG: + s->curpag = val; + break; + case EN1_MULT ... EN1_MULT + 7: + s->mult[offset - EN1_MULT] = val; + break; + } + } +} + +uint32_t ne2000_ioport_read(CPUX86State *env, uint32_t addr) +{ + NE2000State *s = &ne2000_state; + int offset, page, ret; + + addr &= 0xf; + if (addr == E8390_CMD) { + ret = s->cmd; + } else { + page = s->cmd >> 6; + offset = addr | (page << 4); + switch(offset) { + case EN0_TSR: + ret = s->tsr; + break; + case EN0_BOUNDARY: + ret = s->boundary; + break; + case EN0_ISR: + ret = s->isr; + break; + case EN1_PHYS ... EN1_PHYS + 5: + ret = s->phys[offset - EN1_PHYS]; + break; + case EN1_CURPAG: + ret = s->curpag; + break; + case EN1_MULT ... EN1_MULT + 7: + ret = s->mult[offset - EN1_MULT]; + break; + default: + ret = 0x00; + break; + } + } +#ifdef DEBUG_NE2000 + printf("NE2000: read addr=0x%x val=%02x\n", addr, ret); +#endif + return ret; +} + +void ne2000_asic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + NE2000State *s = &ne2000_state; + uint8_t *p; + +#ifdef DEBUG_NE2000 + printf("NE2000: asic write val=0x%04x\n", val); +#endif + p = s->mem + s->rsar; + if (s->dcfg & 0x01) { + /* 16 bit access */ + p[0] = val; + p[1] = val >> 8; + s->rsar += 2; + s->rcnt -= 2; + } else { + /* 8 bit access */ + p[0] = val; + s->rsar++; + s->rcnt--; + } + /* wrap */ + if (s->rsar == s->stop) + s->rsar = s->start; + if (s->rcnt == 0) { + /* signal end of transfert */ + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } +} + +uint32_t ne2000_asic_ioport_read(CPUX86State *env, uint32_t addr) +{ + NE2000State *s = &ne2000_state; + uint8_t *p; + int ret; + + p = s->mem + s->rsar; + if (s->dcfg & 0x01) { + /* 16 bit access */ + ret = p[0] | (p[1] << 8); + s->rsar += 2; + s->rcnt -= 2; + } else { + /* 8 bit access */ + ret = p[0]; + s->rsar++; + s->rcnt--; + } + /* wrap */ + if (s->rsar == s->stop) + s->rsar = s->start; + if (s->rcnt == 0) { + /* signal end of transfert */ + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } +#ifdef DEBUG_NE2000 + printf("NE2000: asic read val=0x%04x\n", ret); +#endif + return ret; +} + +void ne2000_reset_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + /* nothing to do (end of reset pulse) */ +} + +uint32_t ne2000_reset_ioport_read(CPUX86State *env, uint32_t addr) +{ + ne2000_reset(); + return 0; +} + +void ne2000_init(void) +{ + register_ioport_writeb(NE2000_IOPORT, 16, ne2000_ioport_write); + register_ioport_readb(NE2000_IOPORT, 16, ne2000_ioport_read); + + register_ioport_writeb(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_write); + register_ioport_readb(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_read); + register_ioport_writew(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_write); + register_ioport_readw(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_read); + + register_ioport_writeb(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_write); + register_ioport_readb(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_read); + ne2000_reset(); +} + +/***********************************************************/ /* cpu signal handler */ static void host_segv_handler(int host_signum, siginfo_t *info, void *puc) @@ -1178,10 +1672,11 @@ void help(void) "to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n" "'initrd' is an initrd image\n" "-m megs set virtual RAM size to megs MB\n" + "-n script set network init script [default=%s]\n" "-d output log in /tmp/vl.log\n" "\n" - "During emulation, use C-a h to get terminal commands:\n" - ); + "During emulation, use C-a h to get terminal commands:\n", + DEFAULT_NETWORK_SCRIPT); term_print_help(); exit(1); } @@ -1198,8 +1693,9 @@ int main(int argc, char **argv) mallopt(M_MMAP_THRESHOLD, 4096 * 1024); phys_ram_size = 32 * 1024 * 1024; + pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); for(;;) { - c = getopt(argc, argv, "hm:d"); + c = getopt(argc, argv, "hm:dn:"); if (c == -1) break; switch(c) { @@ -1214,6 +1710,9 @@ int main(int argc, char **argv) case 'd': loglevel = 1; break; + case 'n': + pstrcpy(network_script, sizeof(network_script), optarg); + break; } } if (optind + 1 >= argc) @@ -1229,6 +1728,9 @@ int main(int argc, char **argv) setvbuf(logfile, NULL, _IOLBF, 0); } + /* init network tun interface */ + net_init(); + /* init the memory */ strcpy(phys_ram_file, "/tmp/vlXXXXXX"); if (mkstemp(phys_ram_file) < 0) { @@ -1294,6 +1796,7 @@ int main(int argc, char **argv) pic_init(); pit_init(); serial_init(); + ne2000_init(); /* setup cpu signal handlers for MMU / self modifying code handling */ sigfillset(&act.sa_mask); @@ -1341,7 +1844,7 @@ int main(int argc, char **argv) setitimer(ITIMER_REAL, &itv, NULL); for(;;) { - struct pollfd ufds[1], *pf; + struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd; int ret, n, timeout; uint8_t ch; @@ -1353,20 +1856,41 @@ int main(int argc, char **argv) else timeout = 0; /* poll any events */ + serial_ufd = NULL; + net_ufd = NULL; pf = ufds; if (!(serial_ports[0].lsr & UART_LSR_DR)) { + serial_ufd = pf; pf->fd = 0; pf->events = POLLIN; pf++; } + if (net_fd > 0 && ne2000_can_receive(&ne2000_state)) { + net_ufd = pf; + pf->fd = net_fd; + pf->events = POLLIN; + pf++; + } ret = poll(ufds, pf - ufds, timeout); if (ret > 0) { - if (ufds[0].revents & POLLIN) { + if (serial_ufd && (serial_ufd->revents & POLLIN)) { n = read(0, &ch, 1); if (n == 1) { serial_received_byte(&serial_ports[0], ch); } } + if (net_ufd && (net_ufd->revents & POLLIN)) { + uint8_t buf[MAX_ETH_FRAME_SIZE]; + + n = read(net_fd, buf, MAX_ETH_FRAME_SIZE); + if (n > 0) { + if (n < 60) { + memset(buf + n, 0, 60 - n); + n = 60; + } + ne2000_receive(&ne2000_state, buf, n); + } + } } /* just for testing */ -- cgit v1.2.3 From 7c2d6a781cb806fdb99837015c773398f582caf1 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 00:08:13 +0000 Subject: faster task switch git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@270 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/exec.c b/exec.c index f7fdc0359..636fe25b8 100644 --- a/exec.c +++ b/exec.c @@ -585,22 +585,32 @@ void page_unmap(void) { PageDesc *p, *pmap; unsigned long addr; - int i, j, ret; + int i, j, ret, j1; for(i = 0; i < L1_SIZE; i++) { pmap = l1_map[i]; if (pmap) { p = pmap; - for(j = 0;j < L2_SIZE; j++) { + for(j = 0;j < L2_SIZE;) { if (p->flags & PAGE_VALID) { addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); - ret = munmap((void *)addr, TARGET_PAGE_SIZE); + /* we try to find a range to make less syscalls */ + j1 = j; + p++; + j++; + while (j < L2_SIZE && (p->flags & PAGE_VALID)) { + p++; + j++; + } + ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS); if (ret != 0) { fprintf(stderr, "Could not unmap page 0x%08lx\n", addr); exit(1); } + } else { + p++; + j++; } - p++; } free(pmap); l1_map[i] = NULL; -- cgit v1.2.3 From e8cd23de30a6c818a3fb1360c2b94549c25ef8fc Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:08:13 +0000 Subject: fixed compilation for gcc 2.96 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@271 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/configure b/configure index b09487de9..e56c603d0 100755 --- a/configure +++ b/configure @@ -153,20 +153,15 @@ fi fi -# check gcc version +# check gcc options support cat > $TMPC < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) -return 0; -#else -#error gcc < 3.2 -#endif } EOF -gcc_major="2" -if $cc -o $TMPO $TMPC 2> /dev/null ; then - gcc_major="3" +have_gcc3_options="no" +if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then + have_gcc3_options="yes" fi if test "$target_bigendian" = "default" ; then @@ -224,7 +219,9 @@ echo "prefix=$prefix" >> config.mak echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH echo "MAKE=$make" >> config.mak echo "CC=$cc" >> config.mak -echo "GCC_MAJOR=$gcc_major" >> config.mak +if test "$have_gcc3_options" = "yes" ; then + echo "HAVE_GCC3_OPTIONS=yes" >> config.mak +fi echo "HOST_CC=$host_cc" >> config.mak echo "AR=$ar" >> config.mak echo "STRIP=$strip -s -R .comment -R .note" >> config.mak -- cgit v1.2.3 From 6b1534cc67242352b0d200b7b468e503955d3b3a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:08:39 +0000 Subject: fixed compilation for gcc 2.96 - added QEMU system emulator git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@272 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 859bd4529..40089eedb 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ LDFLAGS=-g LIBS= DEFINES=-DHAVE_BYTESWAP_H HELPER_CFLAGS=$(CFLAGS) +PROGS=qemu ifdef CONFIG_STATIC LDFLAGS+=-static @@ -13,7 +14,7 @@ endif ifeq ($(ARCH),i386) CFLAGS+=-fomit-frame-pointer OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2 -ifeq ($(GCC_MAJOR),3) +ifeq ($(HAVE_GCC3_OPTIONS),yes) OP_CFLAGS+= -falign-functions=0 else OP_CFLAGS+= -malign-functions=0 @@ -26,6 +27,9 @@ else # is the simplest way to make it self virtualizable! LDFLAGS+=-Wl,-shared endif +ifeq ($(TARGET_ARCH), i386) +PROGS+=vl +endif endif ifeq ($(ARCH),ppc) @@ -70,7 +74,7 @@ OP_CFLAGS=$(CFLAGS) -mno-sched-prolog LDFLAGS+=-Wl,-T,arm.ld endif -ifeq ($(GCC_MAJOR),3) +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 @@ -125,7 +129,7 @@ ifeq ($(ARCH),ia64) OBJS += ia64-syscall.o endif -all: qemu qemu-doc.html +all: $(PROGS) qemu-doc.html qemu: $(OBJS) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) @@ -184,8 +188,8 @@ clean: distclean: clean rm -f config.mak config.h -install: qemu - install -m 755 -s qemu $(prefix)/bin +install: $(PROGS) + install -m 755 -s $(PROGS) $(prefix)/bin # various test targets test speed: qemu @@ -204,7 +208,8 @@ configure \ dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \ Makefile elf.h elfload.c main.c signal.c qemu.h \ syscall.c syscall_defs.h vm86.c path.c mmap.c \ -ppc.ld alpha.ld s390.ld sparc.ld arm.ld\ +i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\ +vl.c i386-vl.ld\ thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\ exec.c cpu-exec.c\ cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \ -- cgit v1.2.3 From 844c72ecccc8ca67d9eee10300ad819c63f0fb28 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:09:14 +0000 Subject: more compiler tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@273 c046a42c-6fe2-441c-8c8c-71466251a162 --- README | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README b/README index 76c4df032..44a470c92 100644 --- a/README +++ b/README @@ -45,22 +45,25 @@ that QEMU works if you do not use a tested gcc version. Look at 'configure' and 'Makefile' if you want to make a different gcc version work. -host gcc binutils glibc linux -------------------------------------------------------- -x86 2.95.2 2.13.2 2.1.3 2.4.18 +host gcc binutils glibc linux distribution +---------------------------------------------------------------------- +x86 2.95.2 2.13.2 2.1.3 2.4.18 + 3.2 2.13.2 2.1.3 2.4.18 + 2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3 -PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 +PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 Debian 3.0 -Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] +Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0 -Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 +Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0 -ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9-ac10-rmk2-np1-cerf2 +ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0 [1] On Alpha, QEMU needs the gcc 'visibility' attribute only available for gcc version >= 3.3. [2] Linux >= 2.4.20 is necessary for precise exception support (untested). +[3] 2.4.9-ac10-rmk2-np1-cerf2 Documentation ------------- -- cgit v1.2.3 From e2f2289897a99d9b38011be5a41a68ee48d22ac6 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:09:48 +0000 Subject: arm fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@274 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + cpu-arm.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index 3eacfa89a..13af7c208 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -305,5 +305,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #endif /* SINGLE_CPU_DEFINES */ void cpu_abort(CPUState *env, const char *fmt, ...); +extern CPUState *cpu_single_env; #endif /* CPU_ALL_H */ diff --git a/cpu-arm.h b/cpu-arm.h index c3850eb40..e3720886a 100644 --- a/cpu-arm.h +++ b/cpu-arm.h @@ -40,6 +40,8 @@ typedef struct CPUARMState { jmp_buf jmp_env; int exception_index; int interrupt_request; + struct TranslationBlock *current_tb; + int user_mode_only; /* user data */ void *opaque; -- cgit v1.2.3 From 83479e770d31e171232a82f4eee7dab06d3b219c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:12:37 +0000 Subject: suppressed ring 0 hacks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@275 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 615915c13..aa2ee3a9e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -29,8 +29,6 @@ //#define DEBUG_EXEC //#define DEBUG_SIGNAL -/* enable it to have a fully working x86 emulator for ring 0 */ -//#define RING0_HACKS #if defined(TARGET_ARM) /* XXX: unify with i386 target */ @@ -157,13 +155,16 @@ int cpu_exec(CPUState *env1) /* if user mode only, we simulate a fake exception which will be hanlded outside the cpu execution loop */ +#if defined(TARGET_I386) do_interrupt_user(env->exception_index, env->exception_is_int, env->error_code, env->exception_next_eip); +#endif ret = env->exception_index; break; } else { +#if defined(TARGET_I386) /* simulate a real cpu exception. On i386, it can trigger new exceptions, but we do not handle double or triple faults yet. */ @@ -171,6 +172,7 @@ int cpu_exec(CPUState *env1) env->exception_is_int, env->error_code, env->exception_next_eip); +#endif } env->exception_index = -1; } @@ -294,8 +296,6 @@ int cpu_exec(CPUState *env1) T0 = tmp_T0; #endif /* see if we can patch the calling TB. XXX: remove TF test */ -#ifndef RING0_HACKS - if (T0 != 0 #if defined(TARGET_I386) && !(env->eflags & TF_MASK) @@ -305,9 +305,8 @@ int cpu_exec(CPUState *env1) tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); spin_unlock(&tb_lock); } -#endif tc_ptr = tb->tc_ptr; - + env->current_tb = tb; /* execute the generated code */ gen_func = (void *)tc_ptr; #if defined(__sparc__) @@ -326,6 +325,7 @@ int cpu_exec(CPUState *env1) #else gen_func(); #endif + env->current_tb = NULL; } } else { } @@ -381,12 +381,6 @@ int cpu_exec(CPUState *env1) return ret; } -void cpu_interrupt(CPUState *s) -{ - s->interrupt_request = 1; -} - - #if defined(TARGET_I386) void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) @@ -461,9 +455,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, TranslationBlock *tb; int ret; -#ifdef RING0_HACKS - env = global_env; /* XXX: find a better solution */ -#endif + 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); -- cgit v1.2.3 From ea041c0e3375801694610250a8cc3e1240e2ad87 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:16:50 +0000 Subject: more precise cpu_interrupt() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@276 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 5 ++--- exec.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index abbb03723..6c7afbf6e 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -251,7 +251,7 @@ typedef struct CPUX86State { int error_code; int exception_is_int; int exception_next_eip; - + struct TranslationBlock *current_tb; /* currently executing TB */ uint32_t cr[5]; /* NOTE: cr1 is unused */ uint32_t dr[8]; /* debug registers */ int interrupt_request; /* if true, will exit from cpu_exec() ASAP */ @@ -259,7 +259,7 @@ typedef struct CPUX86State { request interrupt number */ int hard_interrupt_request; int user_mode_only; /* user mode only simulation */ - + /* user data */ void *opaque; } CPUX86State; @@ -295,7 +295,6 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, /* MMU defines */ void cpu_x86_init_mmu(CPUX86State *env); -extern CPUX86State *global_env; extern int phys_ram_size; extern int phys_ram_fd; extern uint8_t *phys_ram_base; diff --git a/exec.c b/exec.c index 636fe25b8..4de0c60f1 100644 --- a/exec.c +++ b/exec.c @@ -26,7 +26,13 @@ #include #include +#include "config.h" +#ifdef TARGET_I386 #include "cpu-i386.h" +#endif +#ifdef TARGET_ARM +#include "cpu-arm.h" +#endif #include "exec.h" //#define DEBUG_TB_INVALIDATE @@ -564,6 +570,67 @@ TranslationBlock *tb_find_pc(unsigned long tc_ptr) return &tbs[m_max]; } +static void tb_reset_jump_recursive(TranslationBlock *tb); + +static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) +{ + TranslationBlock *tb1, *tb_next, **ptb; + unsigned int n1; + + tb1 = tb->jmp_next[n]; + if (tb1 != NULL) { + /* find head of list */ + for(;;) { + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == 2) + break; + tb1 = tb1->jmp_next[n1]; + } + /* we are now sure now that tb jumps to tb1 */ + tb_next = tb1; + + /* remove tb from the jmp_first list */ + ptb = &tb_next->jmp_first; + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (n1 == n && tb1 == tb) + break; + ptb = &tb1->jmp_next[n1]; + } + *ptb = tb->jmp_next[n]; + tb->jmp_next[n] = NULL; + + /* suppress the jump to next tb in generated code */ + tb_reset_jump(tb, n); + + /* suppress jumps in the tb on which we could have jump */ + tb_reset_jump_recursive(tb_next); + } +} + +static void tb_reset_jump_recursive(TranslationBlock *tb) +{ + tb_reset_jump_recursive2(tb, 0); + tb_reset_jump_recursive2(tb, 1); +} + +void cpu_interrupt(CPUState *env) +{ + TranslationBlock *tb; + + env->interrupt_request = 1; + /* if the cpu is currently executing code, we must unlink it and + all the potentially executing TB */ + tb = env->current_tb; + if (tb) { + tb_reset_jump_recursive(tb); + } +} + + void cpu_abort(CPUState *env, const char *fmt, ...) { va_list ap; -- cgit v1.2.3 From a363e34cc51220a31691d54e576fb0e29ec02646 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:18:05 +0000 Subject: fixed VM86 support in Virtual Linux - fixed compilation issues with gcc 2.96 - cpuid returns now pentium pro in order to avoid F00F bug workaround in Linux kernel git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@277 c046a42c-6fe2-441c-8c8c-71466251a162 --- helper-i386.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/helper-i386.c b/helper-i386.c index 9fc40181a..f47252ac1 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -216,7 +216,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, break; } dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->segs[R_CS].selector & 3; + if (env->eflags & VM_MASK) + cpl = 3; + else + cpl = env->segs[R_CS].selector & 3; /* check privledge if software int */ if (is_int && dpl < cpl) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); @@ -572,13 +575,25 @@ void helper_cpuid(void) ECX = 0x6c65746e; EDX = 0x49656e69; } else if (EAX == 1) { + int family, model, stepping; /* EAX = 1 info */ - EAX = 0x52b; +#if 0 + /* pentium 75-200 */ + family = 5; + model = 2; + stepping = 11; +#else + /* pentium pro */ + family = 6; + model = 1; + stepping = 3; +#endif + EAX = (family << 8) | (model << 4) | stepping; EBX = 0; ECX = 0; EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | - CPUID_CX8; + CPUID_CX8 | CPUID_PGE | CPUID_CMOV; } } @@ -751,7 +766,9 @@ void jmp_seg(int selector, unsigned int new_eip) load_seg_cache(&sc1, e1, e2); if (new_eip > sc1.limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - env->segs[R_CS] = sc1; + env->segs[R_CS].base = sc1.base; + env->segs[R_CS].limit = sc1.limit; + env->segs[R_CS].flags = sc1.flags; env->segs[R_CS].selector = (selector & 0xfffc) | cpl; EIP = new_eip; } else { -- cgit v1.2.3 From 725af7d46041eafd0b95a7550172dd39d39bb815 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:18:32 +0000 Subject: untested RH9 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@278 c046a42c-6fe2-441c-8c8c-71466251a162 --- i386-vl.ld | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/i386-vl.ld b/i386-vl.ld index 86696f4d0..e666ed83f 100644 --- a/i386-vl.ld +++ b/i386-vl.ld @@ -56,6 +56,16 @@ SECTIONS .rodata : { *(.rodata) *(.gnu.linkonce.r*) } .rodata1 : { *(.rodata1) } .reginfo : { *(.reginfo) } + __preinit_array_start = .; + .preinit_array : { *(.preinit_array) } + __preinit_array_end = .; + __init_array_start = .; + .init_array : { *(.init_array) } + __init_array_end = .; + __fini_array_start = .; + .fini_array : { *(.fini_array) } + __fini_array_end = .; + /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN(0x100000) + (. & (0x100000 - 1)); -- cgit v1.2.3 From 59faf6d6a6a239fcd1fa283ef8b558299fb37325 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:18:50 +0000 Subject: compile fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@279 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index a8ae9c75a..56cba6189 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -26,8 +26,6 @@ #include "qemu.h" -#include "cpu-i386.h" - #define DEBUG_LOGFILE "/tmp/qemu.log" FILE *logfile = NULL; @@ -322,6 +320,9 @@ void usage(void) /* XXX: currently only used for async signals (see signal.c) */ CPUState *global_env; +/* used only if single thread */ +CPUState *cpu_single_env = NULL; + /* used to free thread contexts */ TaskState *first_task_state; @@ -428,6 +429,7 @@ int main(int argc, char **argv) memset(ts, 0, sizeof(TaskState)); env->opaque = ts; ts->used = 1; + env->user_mode_only = 1; #if defined(TARGET_I386) /* linux register setup */ @@ -481,7 +483,6 @@ int main(int argc, char **argv) cpu_x86_load_seg(env, R_SS, __USER_DS); cpu_x86_load_seg(env, R_FS, __USER_DS); cpu_x86_load_seg(env, R_GS, __USER_DS); - env->user_mode_only = 1; #elif defined(TARGET_ARM) { -- cgit v1.2.3 From 435183235567e0d942829bcf0507cbd34fdcf8a7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:19:50 +0000 Subject: added invlpg emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@280 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/translate-i386.c b/translate-i386.c index 79d6eed63..d986752da 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -4036,6 +4036,7 @@ void cpu_x86_close(CPUX86State *env) /***********************************************************/ /* x86 mmu */ +/* XXX: add PGE support */ /* called when cr3 or PG bit are modified */ static int last_pg_state = -1; @@ -4091,8 +4092,18 @@ void cpu_x86_init_mmu(CPUX86State *env) cpu_x86_update_cr0(env); } +/* XXX: also flush 4MB pages */ void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) { + int flags; + unsigned long virt_addr; + + flags = page_get_flags(addr); + if (flags & PAGE_VALID) { + virt_addr = addr & ~0xfff; + munmap((void *)virt_addr, 4096); + page_set_flags(virt_addr, virt_addr + 4096, 0); + } } /* return value: -- cgit v1.2.3 From 1df912cf9e3dc0c3352fca1200c4bdc3477bf9f4 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:20:35 +0000 Subject: VL license of the day is MIT/BSD git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@281 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/vl.c b/vl.c index b97f74fef..fe0525497 100644 --- a/vl.c +++ b/vl.c @@ -1,13 +1,29 @@ /* - * QEMU based User Mode Linux + * QEMU PC System Emulator * - * This file is part of proprietary software - it is published here - * only for demonstration and information purposes. + * Copyright (c) 2003 Fabrice Bellard * - * 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 #include +#include #include #include #include @@ -163,6 +179,7 @@ typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address); char phys_ram_file[1024]; CPUX86State *global_env; +CPUX86State *cpu_single_env; FILE *logfile = NULL; int loglevel; IOPortReadFunc *ioport_readb_table[MAX_IOPORTS]; @@ -1658,7 +1675,7 @@ static int timer_irq_pending; static void host_alarm_handler(int host_signum, siginfo_t *info, void *puc) { - /* just exit from the cpu to have a change to handle timers */ + /* just exit from the cpu to have a chance to handle timers */ cpu_x86_interrupt(global_env); timer_irq_pending = 1; } @@ -1811,6 +1828,7 @@ int main(int argc, char **argv) /* init CPU state */ env = cpu_init(); global_env = env; + cpu_single_env = env; /* setup basic memory access */ env->cr[0] = 0x00000033; @@ -1893,7 +1911,7 @@ int main(int argc, char **argv) } } - /* just for testing */ + /* timer IRQ */ if (timer_irq_pending) { pic_set_irq(0, 1); pic_set_irq(0, 0); -- cgit v1.2.3 From e3e86d56c46d37418f4e20645d51731666bf903f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:21:11 +0000 Subject: gcc3 compile fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@282 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index d5fe1c402..cb35f2125 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1,6 +1,7 @@ #define _GNU_SOURCE #include #include +#include #include #include #include @@ -591,7 +592,7 @@ void test_fbcd(double a) asm("fld1\n"\ prefix "fnstenv %1\n"\ prefix "fldenv %1\n"\ - : "=t" (res) : "m" (*(env)) : "st");\ + : "=t" (res) : "m" (*(env)));\ printf("res=%f\n", res);\ printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ (env)->fpuc,\ @@ -601,7 +602,7 @@ void test_fbcd(double a) asm("fld1\n"\ prefix "fnsave %1\n"\ prefix "frstor %1\n"\ - : "=t" (res) : "m" (*(env)) : "st");\ + : "=t" (res) : "m" (*(env)));\ printf("res=%f\n", res);\ printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ (env)->fpuc,\ -- cgit v1.2.3 From 1eb20527c88ff596e761574e6615c8f2272882b8 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 16:21:49 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@283 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 9 +- TODO | 2 +- VERSION | 2 +- qemu-doc.texi | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 268 insertions(+), 40 deletions(-) diff --git a/Changelog b/Changelog index ac743cb6c..185bd1d72 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ version 0.4: - 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: @@ -17,10 +18,10 @@ version 0.3: version 0.2: - - PowerPC disassembly and ELF symbols output (Rusty Russel) - - flock support (Rusty Russel) - - ugetrlimit support (Rusty Russel) - - fstat64 fix (Rusty Russel) + - 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) diff --git a/TODO b/TODO index 93c1ec207..2f65f7d4e 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,5 @@ +- finish segment ops (call far, ret far, load_seg suppressed) - fix arm fpu rounding (at least for float->integer conversions) - fix CCOP optimisation - optimize FPU operations (evaluate x87 stack pointer statically) @@ -7,7 +8,6 @@ state, find a solution for tb_flush()). - add gcc 2.96 test configure (some gcc3 flags are needed) - add IPC syscalls -- submit a patch to fix DOSEMU coopthreads lower priority: -------------- diff --git a/VERSION b/VERSION index 1d71ef974..e6adf3fc7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3 \ No newline at end of file +0.4 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index 1b27f7fe4..a113a23d2 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -11,35 +11,62 @@ @section Features -QEMU is a FAST! processor emulator. Its purpose is to run Linux executables -compiled for one architecture on another. For example, x86 Linux -processes can be ran on PowerPC Linux architectures. By using dynamic -translation it achieves a reasonnable speed while being easy to port on -new host CPUs. Its main goal is to be able to launch the @code{Wine} -Windows API emulator (@url{http://www.winehq.org}) or @code{DOSEMU} -(@url{http://www.dosemu.org}) on non-x86 CPUs. +QEMU is a FAST! processor emulator. By using dynamic translation it +achieves a reasonnable speed while being easy to port on new host +CPUs. + +QEMU has two operating modes: +@itemize +@item User mode emulation. In this mode, QEMU can launch Linux processes +compiled for one CPU on another CPU. Linux system calls are converted +because of endianness and 32/64 bit mismatches. The Wine Windows API +emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator +(@url{www.dosemu.org}) are the main targets for QEMU. + +@item Full system emulation. In this mode, QEMU emulates a full +system, including a processor and various peripherials. Currently, it +is only used to launch an x86 Linux kernel on an x86 Linux system. It +enables easier testing and debugging of system code. It can also be +used to provide virtual hosting of several virtual PCs on a single +server. + +@end itemize + +As QEMU requires no host kernel patches to run, it is very safe and +easy to use. QEMU generic features: @itemize -@item User space only emulation. +@item User space only or full system emulation. + +@item Using dynamic translation to native code for reasonnable speed. @item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390. -@item Using dynamic translation to native code for reasonnable speed. +@item Self-modifying code support. + +@item Precise exception support. +@item The virtual CPU is a library (@code{libqemu}) which can be used +in other projects. + +@end itemize + +QEMU user mode emulation features: +@itemize @item Generic Linux system call converter, including most ioctls. @item clone() emulation using native CPU clone() to use Linux scheduler for threads. @item Accurate signal handling by remapping host signals to target signals. +@end itemize +@end itemize -@item Self-modifying code support. - -@item The virtual CPU is a library (@code{libqemu}) which can be used -in other projects. - +QEMU full system emulation features: +@itemize +@item Using mmap() system calls to simulate the MMU @end itemize @section x86 emulation @@ -49,11 +76,9 @@ QEMU x86 target features: @itemize @item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. -User space LDT and GDT are emulated. VM86 mode is also supported to run DOSEMU. - -@item Precise user space x86 exceptions. +LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU. -@item Support of host page sizes bigger than 4KB. +@item Support of host page sizes bigger than 4KB in user mode emulation. @item QEMU can emulate itself on x86. @@ -73,12 +98,21 @@ Current QEMU limitations: @item IPC syscalls are missing. @item The x86 segment limits and access rights are not tested at every -memory access (and will never be to have good performances). +memory access. @item On non x86 host CPUs, @code{double}s are used instead of the non standard 10 byte @code{long double}s of x86 for floating point emulation to get maximum performances. +@item Full system emulation only works if no data are mapped above the virtual address +0xc0000000 (yet). + +@item Some priviledged instructions or behaviors are missing. Only the ones +needed for proper Linux kernel operation are emulated. + +@item No memory separation between the kernel and the user processes is done. +It will be implemented very soon. + @end itemize @section ARM emulation @@ -94,7 +128,7 @@ generic dynamic code generation architecture of QEMU. @end itemize -@chapter Invocation +@chapter QEMU User space emulation invocation @section Quick Start @@ -198,27 +232,188 @@ Activate log (logfile=/tmp/qemu.log) Act as if the host page size was 'pagesize' bytes @end table +@chapter QEMU System emulator invocation + +@section Quick Start + +This section explains how to launch a Linux kernel inside QEMU. + +@enumerate +@item +Download the archive @file{vl-test-xxx.tar.gz} containing a Linux kernel +and an initrd (initial Ram Disk). The archive also contains a +precompiled version of @file{vl}, the QEMU System emulator. + +@item Optional: If you want network support (for example to launch X11 examples), you +must copy the script @file{vl-ifup} in @file{/etc} and configure +properly @code{sudo} so that the command @code{ifconfig} contained in +@file{vl-ifup} can be executed as root. You must verify that your host +kernel supports the TUN/TAP network interfaces: the device +@file{/dev/net/tun} must be present. + +When network is enabled, there is a virtual network connection between +the host kernel and the emulated kernel. The emulated kernel is seen +from the host kernel at IP address 172.20.0.2 and the host kernel is +seen from the emulated kernel at IP address 172.20.0.1. + +@item Launch @code{vl.sh}. You should have the following output: + +@example +> ./vl.sh +connected to host network interface: tun0 +Uncompressing Linux... Ok, booting the kernel. +Linux version 2.4.20 (bellard@voyager) (gcc version 2.95.2 20000220 (Debian GNU/Linux)) #42 Wed Jun 25 14:16:12 CEST 2003 +BIOS-provided physical RAM map: + BIOS-88: 0000000000000000 - 000000000009f000 (usable) + BIOS-88: 0000000000100000 - 0000000002000000 (usable) +32MB LOWMEM available. +On node 0 totalpages: 8192 +zone(0): 4096 pages. +zone(1): 4096 pages. +zone(2): 0 pages. +Kernel command line: root=/dev/ram ramdisk_size=6144 +Initializing CPU#0 +Detected 501.785 MHz processor. +Calibrating delay loop... 973.20 BogoMIPS +Memory: 24776k/32768k available (725k kernel code, 7604k reserved, 151k data, 48k init, 0k highmem) +Dentry cache hash table entries: 4096 (order: 3, 32768 bytes) +Inode cache hash table entries: 2048 (order: 2, 16384 bytes) +Mount-cache hash table entries: 512 (order: 0, 4096 bytes) +Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes) +Page-cache hash table entries: 8192 (order: 3, 32768 bytes) +CPU: Intel Pentium Pro stepping 03 +Checking 'hlt' instruction... OK. +POSIX conformance testing by UNIFIX +Linux NET4.0 for Linux 2.4 +Based upon Swansea University Computer Society NET3.039 +Initializing RT netlink socket +apm: BIOS not found. +Starting kswapd +pty: 256 Unix98 ptys configured +Serial driver version 5.05c (2001-07-08) with no serial options enabled +ttyS00 at 0x03f8 (irq = 4) is a 16450 +ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com) +Last modified Nov 1, 2000 by Paul Gortmaker +NE*000 ethercard probe at 0x300: 52 54 00 12 34 56 +eth0: NE2000 found at 0x300, using IRQ 9. +RAMDISK driver initialized: 16 RAM disks of 6144K size 1024 blocksize +NET4: Linux TCP/IP 1.0 for NET4.0 +IP Protocols: ICMP, UDP, TCP, IGMP +IP: routing cache hash table of 512 buckets, 4Kbytes +TCP: Hash tables configured (established 2048 bind 2048) +NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. +RAMDISK: ext2 filesystem found at block 0 +RAMDISK: Loading 6144 blocks [1 disk] into ram disk... done. +Freeing initrd memory: 6144k freed +VFS: Mounted root (ext2 filesystem). +Freeing unused kernel memory: 48k freed +sh: can't access tty; job control turned off +# +@end example + +@item +Then you can play with the kernel inside the virtual serial console. You +can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help +about the keys you can type inside the virtual serial console. In +particular @key{Ctrl-a b} is the Magic SysRq key. + +@item +If the network is enabled, launch the script @file{/etc/linuxrc} in the +emulator (don't forget the leading dot): +@example +. /etc/linuxrc +@end example + +Then enable X11 connections on your PC from the emulated Linux: +@example +xhost +172.20.0.2 +@end example + +You can now launch @file{xterm} or @file{xlogo} and verify that you have +a real Virtual Linux system ! + +@end enumerate + +NOTE: the example initrd is a modified version of the one made by Kevin +Lawton for the plex86 Project (@url{www.plex86.org}). + +@section Kernel Compilation + +You can use any Linux kernel within QEMU provided it is mapped at +address 0x90000000 (the default is 0xc0000000). You must modify only two +lines in the kernel source: + +In asm/page.h, replace +@example +#define __PAGE_OFFSET (0xc0000000) +@end example +by +@example +#define __PAGE_OFFSET (0x90000000) +@end example + +And in arch/i386/vmlinux.lds, replace +@example + . = 0xc0000000 + 0x100000; +@end example +by +@example + . = 0x90000000 + 0x100000; +@end example + +The file config-2.4.20 gives the configuration of the example kernel. + +Just type +@example +make bzImage +@end example + +As you would do to make a real kernel. Then you can use with QEMU +exactly the same kernel as you would boot on your PC (in +@file{arch/i386/boot/bzImage}). + +@section PC Emulation + +QEMU emulates the following PC peripherials: + +@itemize +@item +PIC (interrupt controler) +@item +PIT (timers) +@item +CMOS memory +@item +Serial port (port=0x3f8, irq=4) +@item +NE2000 network adapter (port=0x300, irq=9) +@item +Dumb VGA (to print the @code{uncompressing Linux kernel} message) +@end itemize + @chapter QEMU Internals @section QEMU compared to other emulators -Unlike bochs [3], QEMU emulates only a user space x86 CPU. It means that -you cannot launch an operating system with it. The benefit is that it is -simpler and faster due to the fact that some of the low level CPU state -can be ignored (in particular, no virtual memory needs to be emulated). +Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than +bochs as it uses dynamic compilation and because it uses the host MMU to +simulate the x86 MMU. The downside is that currently the emulation is +not as accurate as bochs (for example, you cannot currently run Windows +inside QEMU). Like Valgrind [2], QEMU does user space emulation and dynamic translation. Valgrind is mainly a memory debugger while QEMU has no -support for it (QEMU could be used to detect out of bound memory accesses -as Valgrind, but it has no support to track uninitialised data as -Valgrind does). Valgrind dynamic translator generates better code than -QEMU (in particular it does register allocation) but it is closely tied -to an x86 host and target. - -EM86 [4] is the closest project to QEMU (and QEMU still uses some of its -code, in particular the ELF file loader). EM86 was limited to an alpha -host and used a proprietary and slow interpreter (the interpreter part -of the FX!32 Digital Win32 code translator [5]). +support for it (QEMU could be used to detect out of bound memory +accesses as Valgrind, but it has no support to track uninitialised data +as Valgrind does). Valgrind dynamic translator generates better code +than QEMU (in particular it does register allocation) but it is closely +tied to an x86 host and target and has no support for precise exception +and system emulation. + +EM86 [4] is the closest project to user space QEMU (and QEMU still uses +some of its code, in particular the ELF file loader). EM86 was limited +to an alpha host and used a proprietary and slow interpreter (the +interpreter part of the FX!32 Digital Win32 code translator [5]). TWIN [6] is a Windows API emulator like Wine. It is less accurate than Wine but includes a protected mode x86 interpreter to launch x86 Windows @@ -227,6 +422,20 @@ Windows API is executed natively but it is far more difficult to develop because all the data structures and function parameters exchanged between the API and the x86 code must be converted. +User mode Linux [7] was the only solution before QEMU to launch a Linux +kernel as a process while not needing any host kernel patches. However, +user mode Linux requires heavy kernel patches while QEMU accepts +unpatched Linux kernels. It would be interesting to compare the +performance of the two approaches. + +The new Plex86 [8] PC virtualizer is done in the same spirit as the QEMU +system emulator. It requires a patched Linux kernel to work (you cannot +launch the same kernel on your PC), but the patches are really small. As +it is a PC virtualizer (no emulation is done except for some priveledged +instructions), it has the potential of being faster than QEMU. The +downside is that a complicated (and potentially unsafe) kernel patch is +needed. + @section Portable dynamic translation QEMU is a dynamic translator. When it first encounters a piece of code, @@ -409,6 +618,16 @@ space conflicts. QEMU solves this problem by being an executable ELF shared object as the ld-linux.so ELF interpreter. That way, it can be relocated at load time. +@section MMU emulation + +For system emulation, QEMU uses the mmap() system call to emulate the +target CPU MMU. It works as long the emulated OS does not use an area +reserved by the host OS (such as the area above 0xc0000000 on x86 +Linux). + +It is planned to add a slower but more precise MMU emulation +with a software MMU. + @section Bibliography @table @asis @@ -439,6 +658,14 @@ Chernoff and Ray Hookway. @url{http://www.willows.com/}, Windows API library emulation from Willows Software. +@item [7] +@url{http://user-mode-linux.sourceforge.net/}, +The User-mode Linux Kernel. + +@item [8] +@url{http://www.plex86.org/}, +The new Plex86 project. + @end table @chapter Regression Tests -- cgit v1.2.3 From 0ad041d47692326f4c7f472d396ebdbfe92e1664 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Jun 2003 22:11:41 +0000 Subject: fixed inline pb git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@284 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 1 + thunk.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/dyngen.c b/dyngen.c index 7fac4033e..0266196ad 100644 --- a/dyngen.c +++ b/dyngen.c @@ -108,6 +108,7 @@ typedef uint64_t host_ulong; #define SHT_RELOC SHT_REL #endif +#define NO_THUNK_TYPE_SIZE #include "thunk.h" enum { diff --git a/thunk.h b/thunk.h index 929e47f46..90586fc67 100644 --- a/thunk.h +++ b/thunk.h @@ -236,6 +236,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types); void thunk_register_struct_direct(int id, const char *name, StructEntry *se1); const argtype *thunk_convert(void *dst, const void *src, const argtype *type_ptr, int to_host); +#ifndef NO_THUNK_TYPE_SIZE extern StructEntry struct_entries[]; @@ -312,6 +313,8 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host) } } +#endif /* NO_THUNK_TYPE_SIZE */ + unsigned int target_to_host_bitmask(unsigned int x86_mask, bitmask_transtbl * trans_tbl); unsigned int host_to_target_bitmask(unsigned int alpha_mask, -- cgit v1.2.3 From a6f816d697f7d47611980d9bbf74f003698eff77 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 26 Jun 2003 17:09:07 +0000 Subject: fixed endianness (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@285 c046a42c-6fe2-441c-8c8c-71466251a162 --- ppc-dis.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ppc-dis.c b/ppc-dis.c index 86e384f34..d01dcd6d1 100644 --- a/ppc-dis.c +++ b/ppc-dis.c @@ -3074,7 +3074,8 @@ static int print_insn_powerpc(FILE *, unsigned long insn, unsigned memaddr, int int print_insn_ppc (bfd_vma pc, disassemble_info *info) { - return print_insn_powerpc (info->stream, *(unsigned *)(long)pc, pc, + return print_insn_powerpc (info->stream, + (unsigned int)bfd_getb32((bfd_byte *)pc), pc, PPC_OPCODE_PPC | PPC_OPCODE_601); } -- cgit v1.2.3 From 87858c89ca89bd1bb2044de0c8a9406bd6367ab7 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 27 Jun 2003 12:01:39 +0000 Subject: more precise timer emulation - fixed NE2000 probe problems - added VLTMPDIR support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@286 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 143 insertions(+), 29 deletions(-) diff --git a/vl.c b/vl.c index fe0525497..6cd238b88 100644 --- a/vl.c +++ b/vl.c @@ -745,17 +745,19 @@ void pic_init(void) #define RW_STATE_LATCHED_WORD1 5 typedef struct PITChannelState { - uint16_t count; + int count; /* can be 65536 */ uint16_t latched_count; uint8_t rw_state; uint8_t mode; uint8_t bcd; /* not supported */ uint8_t gate; /* timer start */ int64_t count_load_time; + int64_t count_last_edge_check_time; } PITChannelState; PITChannelState pit_channels[3]; int speaker_data_on; +int pit_min_timer_count = 0; int64_t ticks_per_sec; @@ -785,13 +787,36 @@ void cpu_calibrate_ticks(void) ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; } +/* compute with 96 bit intermediate result: (a*b)/c */ +static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +{ + union { + uint64_t ll; + struct { +#ifdef WORDS_BIGENDIAN + uint32_t high, low; +#else + uint32_t low, high; +#endif + } l; + } u, res; + uint64_t rl, rh; + + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; +} + static int pit_get_count(PITChannelState *s) { - int64_t d; + uint64_t d; int counter; - d = ((cpu_get_ticks() - s->count_load_time) * PIT_FREQ) / - ticks_per_sec; + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { case 0: case 1: @@ -809,11 +834,10 @@ static int pit_get_count(PITChannelState *s) /* get pit output bit */ static int pit_get_out(PITChannelState *s) { - int64_t d; + uint64_t d; int out; - d = ((cpu_get_ticks() - s->count_load_time) * PIT_FREQ) / - ticks_per_sec; + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { default: case 0: @@ -839,11 +863,74 @@ static int pit_get_out(PITChannelState *s) return out; } +/* get the number of 0 to 1 transitions we had since we call this + function */ +/* XXX: maybe better to use ticks precision to avoid getting edges + twice if checks are done at very small intervals */ +static int pit_get_out_edges(PITChannelState *s) +{ + uint64_t d1, d2; + int64_t ticks; + int ret, v; + + ticks = cpu_get_ticks(); + d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, + PIT_FREQ, ticks_per_sec); + d2 = muldiv64(ticks - s->count_load_time, + PIT_FREQ, ticks_per_sec); + s->count_last_edge_check_time = ticks; + switch(s->mode) { + default: + case 0: + if (d1 < s->count && d2 >= s->count) + ret = 1; + else + ret = 0; + break; + case 1: + ret = 0; + break; + case 2: + d1 /= s->count; + d2 /= s->count; + ret = d2 - d1; + break; + case 3: + v = s->count - (s->count >> 1); + d1 = (d1 + v) / s->count; + d2 = (d2 + v) / s->count; + ret = d2 - d1; + break; + case 4: + case 5: + if (d1 < s->count && d2 >= s->count) + ret = 1; + else + ret = 0; + break; + } + return ret; +} + +static inline void pit_load_count(PITChannelState *s, int val) +{ + if (val == 0) + val = 0x10000; + s->count_load_time = cpu_get_ticks(); + s->count_last_edge_check_time = s->count_load_time; + s->count = val; + if (s == &pit_channels[0] && val <= pit_min_timer_count) { + fprintf(stderr, + "\nWARNING: vl: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.5.xx Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", + PIT_FREQ / pit_min_timer_count); + } +} + void pit_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) { int channel, access; PITChannelState *s; - + addr &= 3; if (addr == 3) { channel = val >> 6; @@ -857,27 +944,24 @@ void pit_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) s->rw_state = RW_STATE_LATCHED_WORD0; break; default: + s->mode = (val >> 1) & 7; + s->bcd = val & 1; s->rw_state = access - 1 + RW_STATE_LSB; break; } - s->mode = (val >> 1) & 7; - s->bcd = val & 1; } else { s = &pit_channels[addr]; switch(s->rw_state) { case RW_STATE_LSB: - s->count_load_time = cpu_get_ticks(); - s->count = val; + pit_load_count(s, val); break; case RW_STATE_MSB: - s->count_load_time = cpu_get_ticks(); - s->count = (val << 8); + pit_load_count(s, val << 8); break; case RW_STATE_WORD0: case RW_STATE_WORD1: if (s->rw_state & 1) { - s->count_load_time = cpu_get_ticks(); - s->count = (s->latched_count & 0xff) | (val << 8); + pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); } else { s->latched_count = val; } @@ -935,16 +1019,23 @@ uint32_t speaker_ioport_read(CPUX86State *env, uint32_t addr) void pit_init(void) { - pit_channels[0].gate = 1; - pit_channels[1].gate = 1; - pit_channels[2].gate = 0; - + PITChannelState *s; + int i; + + cpu_calibrate_ticks(); + + for(i = 0;i < 3; i++) { + s = &pit_channels[i]; + s->mode = 3; + s->gate = (i != 2); + pit_load_count(s, 0); + } + register_ioport_writeb(0x40, 4, pit_ioport_write); register_ioport_readb(0x40, 3, pit_ioport_read); register_ioport_readb(0x61, 1, speaker_ioport_read); register_ioport_writeb(0x61, 1, speaker_ioport_write); - cpu_calibrate_ticks(); } /***********************************************************/ @@ -1462,6 +1553,8 @@ void ne2000_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) s->rcnt == 0) { s->isr |= ENISR_RDC; ne2000_update_irq(s); + /* XXX: find a better solution for irqs */ + cpu_x86_interrupt(global_env); } if (val & E8390_TRANS) { net_send_packet(s, s->mem + (s->tpsr << 8), s->tcnt); @@ -1671,13 +1764,23 @@ static void host_segv_handler(int host_signum, siginfo_t *info, } static int timer_irq_pending; +static int timer_irq_count; static void host_alarm_handler(int host_signum, siginfo_t *info, void *puc) { - /* just exit from the cpu to have a chance to handle timers */ - cpu_x86_interrupt(global_env); - timer_irq_pending = 1; + /* NOTE: since usually the OS asks a 100 Hz clock, there can be + some drift between cpu_get_ticks() and the interrupt time. So + we queue some interrupts to avoid missing some */ + timer_irq_count += pit_get_out_edges(&pit_channels[0]); + if (timer_irq_count) { + if (timer_irq_count > 2) + timer_irq_count = 2; + timer_irq_count--; + /* just exit from the cpu to have a chance to handle timers */ + cpu_x86_interrupt(global_env); + timer_irq_pending = 1; + } } void help(void) @@ -1705,7 +1808,8 @@ int main(int argc, char **argv) struct sigaction act; struct itimerval itv; CPUX86State *env; - + const char *tmpdir; + /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); @@ -1749,14 +1853,19 @@ int main(int argc, char **argv) net_init(); /* init the memory */ - strcpy(phys_ram_file, "/tmp/vlXXXXXX"); + tmpdir = getenv("VLTMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir); if (mkstemp(phys_ram_file) < 0) { - fprintf(stderr, "Could not create temporary memory file\n"); + fprintf(stderr, "Could not create temporary memory file '%s'\n", + phys_ram_file); exit(1); } phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); if (phys_ram_fd < 0) { - fprintf(stderr, "Could not open temporary memory file\n"); + fprintf(stderr, "Could not open temporary memory file '%s'\n", + phys_ram_file); exit(1); } ftruncate(phys_ram_fd, phys_ram_size); @@ -1856,10 +1965,15 @@ int main(int argc, char **argv) env->eflags = 0x2; itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 10 * 1000; + itv.it_interval.tv_usec = 1000; itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 10 * 1000; setitimer(ITIMER_REAL, &itv, NULL); + /* we probe the tick duration of the kernel to inform the user if + the emulated kernel requested a too high timer frequency */ + getitimer(ITIMER_REAL, &itv); + pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / + 1000000; for(;;) { struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd; -- cgit v1.2.3 From d5a0b50c6f51cd783c5216806fe01deb0bc0b03a Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 27 Jun 2003 12:02:03 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@287 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 +++++++ Makefile | 1 + VERSION | 2 +- qemu-doc.texi | 48 +++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/Changelog b/Changelog index 185bd1d72..5d92f07e4 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,10 @@ +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 diff --git a/Makefile b/Makefile index 40089eedb..a83bd7404 100644 --- a/Makefile +++ b/Makefile @@ -189,6 +189,7 @@ distclean: clean rm -f config.mak config.h install: $(PROGS) + mkdir -p $(prefix)/bin install -m 755 -s $(PROGS) $(prefix)/bin # various test targets diff --git a/VERSION b/VERSION index e6adf3fc7..44bb5d1f7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4 \ No newline at end of file +0.4.1 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index a113a23d2..3242c6bd8 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -47,7 +47,7 @@ QEMU generic features: @item Self-modifying code support. -@item Precise exception support. +@item Precise exceptions support. @item The virtual CPU is a library (@code{libqemu}) which can be used in other projects. @@ -128,7 +128,7 @@ generic dynamic code generation architecture of QEMU. @end itemize -@chapter QEMU User space emulation invocation +@chapter QEMU User space emulator invocation @section Quick Start @@ -315,7 +315,8 @@ sh: can't access tty; job control turned off Then you can play with the kernel inside the virtual serial console. You can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help about the keys you can type inside the virtual serial console. In -particular @key{Ctrl-a b} is the Magic SysRq key. +particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as +the Magic SysRq key. @item If the network is enabled, launch the script @file{/etc/linuxrc} in the @@ -334,9 +335,24 @@ a real Virtual Linux system ! @end enumerate -NOTE: the example initrd is a modified version of the one made by Kevin +NOTES: +@enumerate +@item +A 2.5.66 kernel is also included in the vl-test archive. Just +replace the bzImage in vl.sh to try it. + +@item +vl creates a temporary file in @var{$VLTMPDIR} (@file{/tmp} is the +default) containing all the simulated PC memory. If possible, try to use +a temporary directory using the tmpfs filesystem to avoid too many +unnecessary disk accesses. + +@item +The example initrd is a modified version of the one made by Kevin Lawton for the plex86 Project (@url{www.plex86.org}). +@end enumerate + @section Kernel Compilation You can use any Linux kernel within QEMU provided it is mapped at @@ -372,6 +388,20 @@ As you would do to make a real kernel. Then you can use with QEMU exactly the same kernel as you would boot on your PC (in @file{arch/i386/boot/bzImage}). +If you are not using a 2.5 kernel as host kernel but if you use a target +2.5 kernel, you must also ensure that the 'HZ' define is set to 100 +(1000 is the default) as QEMU cannot currently emulate timers at +frequencies greater than 100 Hz on host Linux systems < 2.5. In +asm/param.h, replace: + +@example +# define HZ 1000 /* Internal kernel timer frequency */ +@end example +by +@example +# define HZ 100 /* Internal kernel timer frequency */ +@end example + @section PC Emulation QEMU emulates the following PC peripherials: @@ -388,7 +418,7 @@ Serial port (port=0x3f8, irq=4) @item NE2000 network adapter (port=0x300, irq=9) @item -Dumb VGA (to print the @code{uncompressing Linux kernel} message) +Dumb VGA (to print the @code{Uncompressing Linux} message) @end itemize @chapter QEMU Internals @@ -405,9 +435,9 @@ Like Valgrind [2], QEMU does user space emulation and dynamic translation. Valgrind is mainly a memory debugger while QEMU has no support for it (QEMU could be used to detect out of bound memory accesses as Valgrind, but it has no support to track uninitialised data -as Valgrind does). Valgrind dynamic translator generates better code +as Valgrind does). The Valgrind dynamic translator generates better code than QEMU (in particular it does register allocation) but it is closely -tied to an x86 host and target and has no support for precise exception +tied to an x86 host and target and has no support for precise exceptions and system emulation. EM86 [4] is the closest project to user space QEMU (and QEMU still uses @@ -433,8 +463,8 @@ system emulator. It requires a patched Linux kernel to work (you cannot launch the same kernel on your PC), but the patches are really small. As it is a PC virtualizer (no emulation is done except for some priveledged instructions), it has the potential of being faster than QEMU. The -downside is that a complicated (and potentially unsafe) kernel patch is -needed. +downside is that a complicated (and potentially unsafe) host kernel +patch is needed. @section Portable dynamic translation -- cgit v1.2.3 From b4608c0455a410994b31888b458a552d640b9765 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 27 Jun 2003 17:34:32 +0000 Subject: added gdb support to vl git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@288 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- gdbstub.c | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 170 ++++++++++++++++----------- 3 files changed, 497 insertions(+), 65 deletions(-) create mode 100644 gdbstub.c diff --git a/Makefile b/Makefile index a83bd7404..e3b18f32e 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a # cpu emulator library -LIBOBJS=thunk.o exec.o translate.o cpu-exec.o +LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o ifeq ($(TARGET_ARCH), i386) LIBOBJS+=translate-i386.o op-i386.o helper-i386.o diff --git a/gdbstub.c b/gdbstub.c new file mode 100644 index 000000000..2d1f4784a --- /dev/null +++ b/gdbstub.c @@ -0,0 +1,390 @@ +/* + * gdb server stub + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#ifdef TARGET_I386 +#include "cpu-i386.h" +#endif +#ifdef TARGET_ARM +#include "cpu-arm.h" +#endif +#include "thunk.h" +#include "exec.h" + +//#define DEBUG_GDB + +int gdbstub_fd = -1; + +/* return 0 if OK */ +static int gdbstub_open(int port) +{ + struct sockaddr_in sockaddr; + socklen_t len; + int fd, val, ret; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + + /* allow fast reuse */ + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(port); + sockaddr.sin_addr.s_addr = 0; + ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); + if (ret < 0) { + perror("bind"); + return -1; + } + ret = listen(fd, 0); + if (ret < 0) { + perror("listen"); + return -1; + } + + /* now wait for one connection */ + for(;;) { + len = sizeof(sockaddr); + gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len); + if (gdbstub_fd < 0 && errno != EINTR) { + perror("accept"); + return -1; + } else if (gdbstub_fd >= 0) { + break; + } + } + + /* set short latency */ + val = 1; + setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); + return 0; +} + +static int get_char(void) +{ + uint8_t ch; + int ret; + + for(;;) { + ret = read(gdbstub_fd, &ch, 1); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) + return -1; + } else if (ret == 0) { + return -1; + } else { + break; + } + } + return ch; +} + +static void put_buffer(const uint8_t *buf, int len) +{ + int ret; + + while (len > 0) { + ret = write(gdbstub_fd, buf, len); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) + return; + } else { + buf += ret; + len -= ret; + } + } +} + +static inline int fromhex(int v) +{ + if (v >= '0' && v <= '9') + return v - '0'; + else if (v >= 'A' && v <= 'F') + return v - 'A' + 10; + else if (v >= 'a' && v <= 'f') + return v - 'a' + 10; + else + return 0; +} + +static inline int tohex(int v) +{ + if (v < 10) + return v + '0'; + else + return v - 10 + 'a'; +} + +static void memtohex(char *buf, const uint8_t *mem, int len) +{ + int i, c; + char *q; + q = buf; + for(i = 0; i < len; i++) { + c = mem[i]; + *q++ = tohex(c >> 4); + *q++ = tohex(c & 0xf); + } + *q = '\0'; +} + +static void hextomem(uint8_t *mem, const char *buf, int len) +{ + int i; + + for(i = 0; i < len; i++) { + mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]); + buf += 2; + } +} + +/* return -1 if error or EOF */ +static int get_packet(char *buf, int buf_size) +{ + int ch, len, csum, csum1; + char reply[1]; + + for(;;) { + for(;;) { + ch = get_char(); + if (ch < 0) + return -1; + if (ch == '$') + break; + } + len = 0; + csum = 0; + for(;;) { + ch = get_char(); + if (ch < 0) + return -1; + if (ch == '#') + break; + if (len > buf_size - 1) + return -1; + buf[len++] = ch; + csum += ch; + } + buf[len] = '\0'; + ch = get_char(); + if (ch < 0) + return -1; + csum1 = fromhex(ch) << 4; + ch = get_char(); + if (ch < 0) + return -1; + csum1 |= fromhex(ch); + if ((csum & 0xff) != csum1) { + reply[0] = '-'; + put_buffer(reply, 1); + } else { + reply[0] = '+'; + put_buffer(reply, 1); + break; + } + } +#ifdef DEBUG_GDB + printf("command='%s'\n", buf); +#endif + return len; +} + +/* return -1 if error, 0 if OK */ +static int put_packet(char *buf) +{ + char buf1[3]; + int len, csum, ch, i; + +#ifdef DEBUG_GDB + printf("reply='%s'\n", buf); +#endif + + for(;;) { + buf1[0] = '$'; + put_buffer(buf1, 1); + len = strlen(buf); + put_buffer(buf, len); + csum = 0; + for(i = 0; i < len; i++) { + csum += buf[i]; + } + buf1[0] = '#'; + buf1[1] = tohex((csum >> 4) & 0xf); + buf1[2] = tohex((csum) & 0xf); + + put_buffer(buf1, 3); + + ch = get_char(); + if (ch < 0) + return -1; + if (ch == '+') + break; + } + return 0; +} + +static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) +{ + int l, flags; + uint32_t page; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + flags = page_get_flags(page); + if (!(flags & PAGE_VALID)) + return -1; + if (is_write) { + if (!(flags & PAGE_WRITE)) + return -1; + memcpy((uint8_t *)addr, buf, l); + } else { + if (!(flags & PAGE_READ)) + return -1; + memcpy(buf, (uint8_t *)addr, l); + } + len -= l; + buf += l; + addr += l; + } + return 0; +} + +/* port = 0 means default port */ +int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) +{ + CPUState *env; + const char *p; + int ret, ch, nb_regs, i; + char buf[4096]; + uint8_t mem_buf[2000]; + uint32_t *registers; + uint32_t addr, len; + + printf("Waiting gdb connection on port %d\n", port); + if (gdbstub_open(port) < 0) + return -1; + printf("Connected\n"); + for(;;) { + ret = get_packet(buf, sizeof(buf)); + if (ret < 0) + break; + p = buf; + ch = *p++; + switch(ch) { + case '?': + snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); + put_packet(buf); + break; + case 'c': + main_loop(opaque); + snprintf(buf, sizeof(buf), "S%02x", 0); + put_packet(buf); + break; + case 'g': + env = cpu_gdbstub_get_env(opaque); + registers = (void *)mem_buf; +#if defined(TARGET_I386) + for(i = 0; i < 8; i++) { + registers[i] = tswapl(env->regs[i]); + } + registers[8] = env->eip; + registers[9] = env->eflags; + registers[10] = env->segs[R_CS].selector; + registers[11] = env->segs[R_SS].selector; + registers[12] = env->segs[R_DS].selector; + registers[13] = env->segs[R_ES].selector; + registers[14] = env->segs[R_FS].selector; + registers[15] = env->segs[R_GS].selector; + nb_regs = 16; +#endif + memtohex(buf, (const uint8_t *)registers, + sizeof(registers[0]) * nb_regs); + put_packet(buf); + break; + case 'G': + env = cpu_gdbstub_get_env(opaque); + registers = (void *)mem_buf; +#if defined(TARGET_I386) + hextomem((uint8_t *)registers, p, 16 * 4); + for(i = 0; i < 8; i++) { + env->regs[i] = tswapl(registers[i]); + } + env->eip = registers[8]; + env->eflags = registers[9]; +#define LOAD_SEG(index, sreg)\ + if (tswapl(registers[index]) != env->segs[sreg].selector)\ + cpu_x86_load_seg(env, sreg, tswapl(registers[index])); + LOAD_SEG(10, R_CS); + LOAD_SEG(11, R_SS); + LOAD_SEG(12, R_DS); + LOAD_SEG(13, R_ES); + LOAD_SEG(14, R_FS); + LOAD_SEG(15, R_GS); +#endif + put_packet("OK"); + break; + case 'm': + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, NULL, 16); + if (memory_rw(mem_buf, addr, len, 0) != 0) + memset(mem_buf, 0, len); + memtohex(buf, mem_buf, len); + put_packet(buf); + break; + case 'M': + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + hextomem(mem_buf, p, len); + if (memory_rw(mem_buf, addr, len, 1) != 0) + put_packet("ENN"); + else + put_packet("OK"); + break; + default: + /* put empty packet */ + buf[0] = '\0'; + put_packet(buf); + break; + } + } + return 0; +} diff --git a/vl.c b/vl.c index 6cd238b88..c9196e534 100644 --- a/vl.c +++ b/vl.c @@ -1783,27 +1783,116 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, } } +/* main execution loop */ + +CPUState *cpu_gdbstub_get_env(void *opaque) +{ + return global_env; +} + +void main_loop(void *opaque) +{ + struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd, *gdb_ufd; + int ret, n, timeout; + uint8_t ch; + CPUState *env = global_env; + + for(;;) { + + ret = cpu_x86_exec(env); + + /* if hlt instruction, we wait until the next IRQ */ + if (ret == EXCP_HLT) + timeout = 10; + else + timeout = 0; + /* poll any events */ + serial_ufd = NULL; + pf = ufds; + if (!(serial_ports[0].lsr & UART_LSR_DR)) { + serial_ufd = pf; + pf->fd = 0; + pf->events = POLLIN; + pf++; + } + net_ufd = NULL; + if (net_fd > 0 && ne2000_can_receive(&ne2000_state)) { + net_ufd = pf; + pf->fd = net_fd; + pf->events = POLLIN; + pf++; + } + gdb_ufd = NULL; + if (gdbstub_fd > 0) { + gdb_ufd = pf; + pf->fd = gdbstub_fd; + pf->events = POLLIN; + pf++; + } + + ret = poll(ufds, pf - ufds, timeout); + if (ret > 0) { + if (serial_ufd && (serial_ufd->revents & POLLIN)) { + n = read(0, &ch, 1); + if (n == 1) { + serial_received_byte(&serial_ports[0], ch); + } + } + if (net_ufd && (net_ufd->revents & POLLIN)) { + uint8_t buf[MAX_ETH_FRAME_SIZE]; + + n = read(net_fd, buf, MAX_ETH_FRAME_SIZE); + if (n > 0) { + if (n < 60) { + memset(buf + n, 0, 60 - n); + n = 60; + } + ne2000_receive(&ne2000_state, buf, n); + } + } + if (gdb_ufd && (gdb_ufd->revents & POLLIN)) { + uint8_t buf[1]; + /* stop emulation if requested by gdb */ + n = read(gdbstub_fd, buf, 1); + if (n == 1) + break; + } + } + + /* timer IRQ */ + if (timer_irq_pending) { + pic_set_irq(0, 1); + pic_set_irq(0, 0); + timer_irq_pending = 0; + } + + pic_handle_irq(); + } +} + void help(void) { printf("Virtual Linux version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: vl [-h] bzImage initrd [kernel parameters...]\n" + "usage: vl [options] bzImage initrd [kernel parameters...]\n" "\n" "'bzImage' is a Linux kernel image (PAGE_OFFSET must be defined\n" "to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n" "'initrd' is an initrd image\n" "-m megs set virtual RAM size to megs MB\n" "-n script set network init script [default=%s]\n" + "-s wait gdb connection to port %d\n" + "-p port change gdb connection port\n" "-d output log in /tmp/vl.log\n" "\n" "During emulation, use C-a h to get terminal commands:\n", - DEFAULT_NETWORK_SCRIPT); + DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT); term_print_help(); exit(1); } int main(int argc, char **argv) { - int c, ret, initrd_size, i; + int c, ret, initrd_size, i, use_gdbstub, gdbstub_port; struct linux_params *params; struct sigaction act; struct itimerval itv; @@ -1815,8 +1904,10 @@ int main(int argc, char **argv) phys_ram_size = 32 * 1024 * 1024; pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); + use_gdbstub = 0; + gdbstub_port = DEFAULT_GDBSTUB_PORT; for(;;) { - c = getopt(argc, argv, "hm:dn:"); + c = getopt(argc, argv, "hm:dn:sp:"); if (c == -1) break; switch(c) { @@ -1834,6 +1925,12 @@ int main(int argc, char **argv) case 'n': pstrcpy(network_script, sizeof(network_script), optarg); break; + case 's': + use_gdbstub = 1; + break; + case 'p': + gdbstub_port = atoi(optarg); + break; } } if (optind + 1 >= argc) @@ -1974,66 +2071,11 @@ int main(int argc, char **argv) getitimer(ITIMER_REAL, &itv); pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / 1000000; - - for(;;) { - struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd; - int ret, n, timeout; - uint8_t ch; - - ret = cpu_x86_exec(env); - - /* if hlt instruction, we wait until the next IRQ */ - if (ret == EXCP_HLT) - timeout = 10; - else - timeout = 0; - /* poll any events */ - serial_ufd = NULL; - net_ufd = NULL; - pf = ufds; - if (!(serial_ports[0].lsr & UART_LSR_DR)) { - serial_ufd = pf; - pf->fd = 0; - pf->events = POLLIN; - pf++; - } - if (net_fd > 0 && ne2000_can_receive(&ne2000_state)) { - net_ufd = pf; - pf->fd = net_fd; - pf->events = POLLIN; - pf++; - } - ret = poll(ufds, pf - ufds, timeout); - if (ret > 0) { - if (serial_ufd && (serial_ufd->revents & POLLIN)) { - n = read(0, &ch, 1); - if (n == 1) { - serial_received_byte(&serial_ports[0], ch); - } - } - if (net_ufd && (net_ufd->revents & POLLIN)) { - uint8_t buf[MAX_ETH_FRAME_SIZE]; - - n = read(net_fd, buf, MAX_ETH_FRAME_SIZE); - if (n > 0) { - if (n < 60) { - memset(buf + n, 0, 60 - n); - n = 60; - } - ne2000_receive(&ne2000_state, buf, n); - } - } - } - - /* timer IRQ */ - if (timer_irq_pending) { - pic_set_irq(0, 1); - pic_set_irq(0, 0); - timer_irq_pending = 0; - } - - pic_handle_irq(); + + if (use_gdbstub) { + cpu_gdbstub(NULL, main_loop, gdbstub_port); + } else { + main_loop(NULL); } - return 0; } -- cgit v1.2.3 From da415d54bfea85f6321f5b03c953b48cbbd5d217 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 27 Jun 2003 18:50:50 +0000 Subject: gdb usage information git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@289 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 3242c6bd8..0c062f5fa 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -402,6 +402,9 @@ by # define HZ 100 /* Internal kernel timer frequency */ @end example +If you have problems running your kernel, verify that neither the SMP nor +HIGHMEM configuration options are activated. + @section PC Emulation QEMU emulates the following PC peripherials: @@ -421,6 +424,36 @@ NE2000 network adapter (port=0x300, irq=9) Dumb VGA (to print the @code{Uncompressing Linux} message) @end itemize +@section GDB usage + +QEMU has a primitive support to work with gdb, so that you can do +'Ctrl-C' while the kernel is running and inspect its state. + +In order to use gdb, launch vl with the '-s' option. It will wait for a +gdb connection: +@example +> vl -s arch/i386/boot/bzImage initrd-2.4.20.img root=/dev/ram0 ramdisk_size=6144 +Connected to host network interface: tun0 +Waiting gdb connection on port 1234 +@end example + +Then launch gdb on the 'vmlinux' executable: +@example +> gdb vmlinux +@end example + +In gdb, connect to QEMU: +@example +(gdb) target remote locahost:1234 +@end example + +Then you can use gdb normally. For example, type 'c' to launch the kernel: +@example +(gdb) c +@end example + +WARNING: breakpoints and single stepping are not yet supported. + @chapter QEMU Internals @section QEMU compared to other emulators -- cgit v1.2.3 From 3b0dca51b0cefb662f1d2757fcccfd563c58b2b9 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 27 Jun 2003 18:52:23 +0000 Subject: gdb stub defines git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@290 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index 13af7c208..cc0a4ea33 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -304,7 +304,14 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #endif /* SINGLE_CPU_DEFINES */ +#define DEFAULT_GDBSTUB_PORT 1234 + void cpu_abort(CPUState *env, const char *fmt, ...); extern CPUState *cpu_single_env; +/* gdb stub API */ +extern int gdbstub_fd; +CPUState *cpu_gdbstub_get_env(void *opaque); +int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port); + #endif /* CPU_ALL_H */ -- cgit v1.2.3 From fc01f7e7f902ce96d985f44dc16f7c020b94f02b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 10:03:06 +0000 Subject: IDE emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@291 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 107 +++++++++ vl.c | 840 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- vl.h | 39 +++ 3 files changed, 900 insertions(+), 86 deletions(-) create mode 100644 block.c create mode 100644 vl.h diff --git a/block.c b/block.c new file mode 100644 index 000000000..1ac8210e0 --- /dev/null +++ b/block.c @@ -0,0 +1,107 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vl.h" + +struct BlockDriverState { + int fd; + int64_t total_sectors; +}; + +BlockDriverState *bdrv_open(const char *filename) +{ + BlockDriverState *bs; + int fd; + int64_t size; + + bs = malloc(sizeof(BlockDriverState)); + if(!bs) + return NULL; + fd = open(filename, O_RDWR); + if (fd < 0) { + close(fd); + free(bs); + return NULL; + } + size = lseek64(fd, 0, SEEK_END); + bs->total_sectors = size / 512; + bs->fd = fd; + return bs; +} + +void bdrv_close(BlockDriverState *bs) +{ + close(bs->fd); + free(bs); +} + +/* return -1 if error */ +int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + int ret; + + lseek64(bs->fd, sector_num * 512, SEEK_SET); + ret = read(bs->fd, buf, nb_sectors * 512); + if (ret != nb_sectors * 512) + return -1; + else + return 0; +} + +/* return -1 if error */ +int bdrv_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + int ret; + + lseek64(bs->fd, sector_num * 512, SEEK_SET); + ret = write(bs->fd, buf, nb_sectors * 512); + if (ret != nb_sectors * 512) + return -1; + else + return 0; +} + +void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) +{ + *nb_sectors_ptr = bs->total_sectors; +} diff --git a/vl.c b/vl.c index c9196e534..01378e258 100644 --- a/vl.c +++ b/vl.c @@ -46,6 +46,9 @@ #include "cpu-i386.h" #include "disas.h" +#include "thunk.h" + +#include "vl.h" #define DEBUG_LOGFILE "/tmp/vl.log" #define DEFAULT_NETWORK_SCRIPT "/etc/vl-ifup" @@ -175,17 +178,15 @@ struct __attribute__ ((packed)) linux_params { typedef void (IOPortWriteFunc)(CPUX86State *env, uint32_t address, uint32_t data); typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address); -#define MAX_IOPORTS 1024 +#define MAX_IOPORTS 4096 char phys_ram_file[1024]; CPUX86State *global_env; CPUX86State *cpu_single_env; FILE *logfile = NULL; int loglevel; -IOPortReadFunc *ioport_readb_table[MAX_IOPORTS]; -IOPortWriteFunc *ioport_writeb_table[MAX_IOPORTS]; -IOPortReadFunc *ioport_readw_table[MAX_IOPORTS]; -IOPortWriteFunc *ioport_writew_table[MAX_IOPORTS]; +IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; +IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; /***********************************************************/ /* x86 io ports */ @@ -195,7 +196,7 @@ uint32_t default_ioport_readb(CPUX86State *env, uint32_t address) #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "inb: port=0x%04x\n", address); #endif - return 0; + return 0xff; } void default_ioport_writeb(CPUX86State *env, uint32_t address, uint32_t data) @@ -209,62 +210,79 @@ void default_ioport_writeb(CPUX86State *env, uint32_t address, uint32_t data) uint32_t default_ioport_readw(CPUX86State *env, uint32_t address) { uint32_t data; - data = ioport_readb_table[address](env, address); - data |= ioport_readb_table[address + 1](env, address + 1) << 8; + data = ioport_read_table[0][address](env, address); + data |= ioport_read_table[0][address + 1](env, address + 1) << 8; return data; } void default_ioport_writew(CPUX86State *env, uint32_t address, uint32_t data) { - ioport_writeb_table[address](env, address, data & 0xff); - ioport_writeb_table[address + 1](env, address + 1, (data >> 8) & 0xff); + ioport_write_table[0][address](env, address, data & 0xff); + ioport_write_table[0][address + 1](env, address + 1, (data >> 8) & 0xff); } -void init_ioports(void) +uint32_t default_ioport_readl(CPUX86State *env, uint32_t address) { - int i; - - for(i = 0; i < MAX_IOPORTS; i++) { - ioport_readb_table[i] = default_ioport_readb; - ioport_writeb_table[i] = default_ioport_writeb; - ioport_readw_table[i] = default_ioport_readw; - ioport_writew_table[i] = default_ioport_writew; - } +#ifdef DEBUG_UNUSED_IOPORT + fprintf(stderr, "inl: port=0x%04x\n", address); +#endif + return 0xffffffff; } -int register_ioport_readb(int start, int length, IOPortReadFunc *func) +void default_ioport_writel(CPUX86State *env, uint32_t address, uint32_t data) { - int i; - - for(i = start; i < start + length; i++) - ioport_readb_table[i] = func; - return 0; +#ifdef DEBUG_UNUSED_IOPORT + fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data); +#endif } -int register_ioport_writeb(int start, int length, IOPortWriteFunc *func) +void init_ioports(void) { int i; - for(i = start; i < start + length; i++) - ioport_writeb_table[i] = func; - return 0; + for(i = 0; i < MAX_IOPORTS; i++) { + ioport_read_table[0][i] = default_ioport_readb; + ioport_write_table[0][i] = default_ioport_writeb; + ioport_read_table[1][i] = default_ioport_readw; + ioport_write_table[1][i] = default_ioport_writew; + ioport_read_table[2][i] = default_ioport_readl; + ioport_write_table[2][i] = default_ioport_writel; + } } -int register_ioport_readw(int start, int length, IOPortReadFunc *func) +/* size is the word size in byte */ +int register_ioport_read(int start, int length, IOPortReadFunc *func, int size) { - int i; + int i, bsize; - for(i = start; i < start + length; i += 2) - ioport_readw_table[i] = func; + if (size == 1) + bsize = 0; + else if (size == 2) + bsize = 1; + else if (size == 4) + bsize = 2; + else + return -1; + for(i = start; i < start + length; i += size) + ioport_read_table[bsize][i] = func; return 0; } -int register_ioport_writew(int start, int length, IOPortWriteFunc *func) +/* size is the word size in byte */ +int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size) { - int i; + int i, bsize; - for(i = start; i < start + length; i += 2) - ioport_writew_table[i] = func; + if (size == 1) + bsize = 0; + else if (size == 2) + bsize = 1; + else if (size == 4) + bsize = 2; + else + return -1; + for(i = start; i < start + length; i += size) + ioport_write_table[bsize][i] = func; return 0; } @@ -339,33 +357,32 @@ int load_image(const char *filename, uint8_t *addr) void cpu_x86_outb(CPUX86State *env, int addr, int val) { - ioport_writeb_table[addr & (MAX_IOPORTS - 1)](env, addr, val); + ioport_write_table[0][addr & (MAX_IOPORTS - 1)](env, addr, val); } void cpu_x86_outw(CPUX86State *env, int addr, int val) { - ioport_writew_table[addr & (MAX_IOPORTS - 1)](env, addr, val); + ioport_write_table[1][addr & (MAX_IOPORTS - 1)](env, addr, val); } void cpu_x86_outl(CPUX86State *env, int addr, int val) { - fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); + ioport_write_table[2][addr & (MAX_IOPORTS - 1)](env, addr, val); } int cpu_x86_inb(CPUX86State *env, int addr) { - return ioport_readb_table[addr & (MAX_IOPORTS - 1)](env, addr); + return ioport_read_table[0][addr & (MAX_IOPORTS - 1)](env, addr); } int cpu_x86_inw(CPUX86State *env, int addr) { - return ioport_readw_table[addr & (MAX_IOPORTS - 1)](env, addr); + return ioport_read_table[1][addr & (MAX_IOPORTS - 1)](env, addr); } int cpu_x86_inl(CPUX86State *env, int addr) { - fprintf(stderr, "inl: port=0x%04x\n", addr); - return 0; + return ioport_read_table[2][addr & (MAX_IOPORTS - 1)](env, addr); } /***********************************************************/ @@ -511,8 +528,8 @@ void cmos_init(void) cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ - register_ioport_writeb(0x70, 2, cmos_ioport_write); - register_ioport_readb(0x70, 2, cmos_ioport_read); + register_ioport_write(0x70, 2, cmos_ioport_write, 1); + register_ioport_read(0x70, 2, cmos_ioport_read, 1); } /***********************************************************/ @@ -726,10 +743,10 @@ uint32_t pic_ioport_read(CPUX86State *env, uint32_t addr) void pic_init(void) { - register_ioport_writeb(0x20, 2, pic_ioport_write); - register_ioport_readb(0x20, 2, pic_ioport_read); - register_ioport_writeb(0xa0, 2, pic_ioport_write); - register_ioport_readb(0xa0, 2, pic_ioport_read); + register_ioport_write(0x20, 2, pic_ioport_write, 1); + register_ioport_read(0x20, 2, pic_ioport_read, 1); + register_ioport_write(0xa0, 2, pic_ioport_write, 1); + register_ioport_read(0xa0, 2, pic_ioport_read, 1); } /***********************************************************/ @@ -1031,11 +1048,11 @@ void pit_init(void) pit_load_count(s, 0); } - register_ioport_writeb(0x40, 4, pit_ioport_write); - register_ioport_readb(0x40, 3, pit_ioport_read); + register_ioport_write(0x40, 4, pit_ioport_write, 1); + register_ioport_read(0x40, 3, pit_ioport_read, 1); - register_ioport_readb(0x61, 1, speaker_ioport_read); - register_ioport_writeb(0x61, 1, speaker_ioport_write); + register_ioport_read(0x61, 1, speaker_ioport_read, 1); + register_ioport_write(0x61, 1, speaker_ioport_write, 1); } /***********************************************************/ @@ -1277,8 +1294,8 @@ void serial_init(void) s->lsr = UART_LSR_TEMT | UART_LSR_THRE; - register_ioport_writeb(0x3f8, 8, serial_ioport_write); - register_ioport_readb(0x3f8, 8, serial_ioport_read); + register_ioport_write(0x3f8, 8, serial_ioport_write, 1); + register_ioport_read(0x3f8, 8, serial_ioport_read, 1); term_init(); } @@ -1444,7 +1461,7 @@ int net_init(void) close(fd); return -1; } - printf("connected to host network interface: %s\n", ifr.ifr_name); + printf("Connected to host network interface: %s\n", ifr.ifr_name); fcntl(fd, F_SETFL, O_NONBLOCK); net_fd = fd; @@ -1739,19 +1756,624 @@ uint32_t ne2000_reset_ioport_read(CPUX86State *env, uint32_t addr) void ne2000_init(void) { - register_ioport_writeb(NE2000_IOPORT, 16, ne2000_ioport_write); - register_ioport_readb(NE2000_IOPORT, 16, ne2000_ioport_read); + register_ioport_write(NE2000_IOPORT, 16, ne2000_ioport_write, 1); + register_ioport_read(NE2000_IOPORT, 16, ne2000_ioport_read, 1); - register_ioport_writeb(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_write); - register_ioport_readb(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_read); - register_ioport_writew(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_write); - register_ioport_readw(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_read); + register_ioport_write(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_write, 1); + register_ioport_read(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_read, 1); + register_ioport_write(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_write, 2); + register_ioport_read(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_read, 2); - register_ioport_writeb(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_write); - register_ioport_readb(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_read); + register_ioport_write(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_write, 1); + register_ioport_read(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_read, 1); ne2000_reset(); } +/***********************************************************/ +/* ide emulation */ + +//#define DEBUG_IDE + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define SRV_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +/* Bits of HD_NSECTOR */ +#define CD 0x01 +#define IO 0x02 +#define REL 0x04 +#define TAG_MASK 0xf8 + +#define IDE_CMD_RESET 0x04 +#define IDE_CMD_DISABLE_IRQ 0x02 + +/* ATA/ATAPI Commands pre T13 Spec */ +#define WIN_NOP 0x00 +/* + * 0x01->0x02 Reserved + */ +#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ +/* + * 0x04->0x07 Reserved + */ +#define WIN_SRST 0x08 /* ATAPI soft reset command */ +#define WIN_DEVICE_RESET 0x08 +/* + * 0x09->0x0F Reserved + */ +#define WIN_RECAL 0x10 +#define WIN_RESTORE WIN_RECAL +/* + * 0x10->0x1F Reserved + */ +#define WIN_READ 0x20 /* 28-Bit */ +#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */ +#define WIN_READ_LONG 0x22 /* 28-Bit */ +#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */ +#define WIN_READ_EXT 0x24 /* 48-Bit */ +#define WIN_READDMA_EXT 0x25 /* 48-Bit */ +#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ +#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ +/* + * 0x28 + */ +#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ +/* + * 0x2A->0x2F Reserved + */ +#define WIN_WRITE 0x30 /* 28-Bit */ +#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */ +#define WIN_WRITE_LONG 0x32 /* 28-Bit */ +#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */ +#define WIN_WRITE_EXT 0x34 /* 48-Bit */ +#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ +#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ +#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ +#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ +#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ +/* + * 0x3A->0x3B Reserved + */ +#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ +/* + * 0x3D->0x3F Reserved + */ +#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ +#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */ +#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ +/* + * 0x43->0x4F Reserved + */ +#define WIN_FORMAT 0x50 +/* + * 0x51->0x5F Reserved + */ +#define WIN_INIT 0x60 +/* + * 0x61->0x5F Reserved + */ +#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */ +#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 /* set drive geometry translation */ +#define WIN_DOWNLOAD_MICROCODE 0x92 +#define WIN_STANDBYNOW2 0x94 +#define WIN_STANDBY2 0x96 +#define WIN_SETIDLE2 0x97 +#define WIN_CHECKPOWERMODE2 0x98 +#define WIN_SLEEPNOW2 0x99 +/* + * 0x9A VENDOR + */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ +#define WIN_QUEUED_SERVICE 0xA2 +#define WIN_SMART 0xB0 /* self-monitoring and reporting */ +#define CFA_ERASE_SECTORS 0xC0 +#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ +#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ +#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ +#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ +#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ +#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */ +#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ +#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ +#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ +#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ +#define WIN_GETMEDIASTATUS 0xDA +#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */ +#define WIN_POSTBOOT 0xDC +#define WIN_PREBOOT 0xDD +#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ +#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ +#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ +#define WIN_SETIDLE1 0xE3 +#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEPNOW1 0xE6 +#define WIN_FLUSH_CACHE 0xE7 +#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ +#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */ + /* SET_FEATURES 0x22 or 0xDD */ +#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ +#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ +#define WIN_MEDIAEJECT 0xED +#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ +#define WIN_SETFEATURES 0xEF /* set special drive features */ +#define EXABYTE_ENABLE_NEST 0xF0 +#define WIN_SECURITY_SET_PASS 0xF1 +#define WIN_SECURITY_UNLOCK 0xF2 +#define WIN_SECURITY_ERASE_PREPARE 0xF3 +#define WIN_SECURITY_ERASE_UNIT 0xF4 +#define WIN_SECURITY_FREEZE_LOCK 0xF5 +#define WIN_SECURITY_DISABLE 0xF6 +#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ +#define WIN_SET_MAX 0xF9 +#define DISABLE_SEAGATE 0xFB + +#define MAX_MULT_SECTORS 16 + +#define MAX_DISKS 2 + +struct IDEState; + +typedef void EndTransferFunc(struct IDEState *); + +typedef struct IDEState { + /* ide config */ + int cylinders, heads, sectors; + int64_t nb_sectors; + int mult_sectors; + int irq; + /* ide regs */ + uint8_t feature; + uint8_t error; + uint8_t nsector; + uint8_t sector; + uint8_t lcyl; + uint8_t hcyl; + uint8_t select; + uint8_t status; + /* 0x3f6 command, only meaningful for drive 0 */ + uint8_t cmd; + /* depends on bit 4 in select, only meaningful for drive 0 */ + struct IDEState *cur_drive; + BlockDriverState *bs; + EndTransferFunc *end_transfer_func; + uint8_t *data_ptr; + uint8_t *data_end; + uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; +} IDEState; + +BlockDriverState *bs_table[MAX_DISKS]; +IDEState ide_state[MAX_DISKS]; + +static void padstr(char *str, const char *src, int len) +{ + int i, v; + for(i = 0; i < len; i++) { + if (*src) + v = *src++; + else + v = ' '; + *(char *)((long)str ^ 1) = v; + str++; + } +} + +static void ide_identify(IDEState *s) +{ + uint16_t *p; + unsigned int oldsize; + + memset(s->io_buffer, 0, 512); + p = (uint16_t *)s->io_buffer; + stw(p + 0, 0x0040); + stw(p + 1, s->cylinders); + stw(p + 3, s->heads); + stw(p + 4, 512 * s->sectors); /* sectors */ + stw(p + 5, 512); /* sector size */ + stw(p + 6, s->sectors); + stw(p + 20, 3); /* buffer type */ + stw(p + 21, 512); /* cache size in sectors */ + stw(p + 22, 4); /* ecc bytes */ + padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); + // stw(p + 47, MAX_MULT_SECTORS); + stw(p + 48, 1); /* dword I/O */ + stw(p + 49, 1 << 9); /* LBA supported, no DMA */ + stw(p + 51, 0x200); /* PIO transfer cycle */ + stw(p + 52, 0x200); /* DMA transfer cycle */ + stw(p + 54, s->cylinders); + stw(p + 55, s->heads); + stw(p + 56, s->sectors); + oldsize = s->cylinders * s->heads * s->sectors; + stw(p + 57, oldsize); + stw(p + 58, oldsize >> 16); + if (s->mult_sectors) + stw(p + 59, 0x100 | s->mult_sectors); + stw(p + 60, s->nb_sectors); + stw(p + 61, s->nb_sectors >> 16); + stw(p + 80, (1 << 1) | (1 << 2)); + stw(p + 82, (1 << 14)); + stw(p + 83, (1 << 14)); + stw(p + 84, (1 << 14)); + stw(p + 85, (1 << 14)); + stw(p + 86, 0); + stw(p + 87, (1 << 14)); +} + +static inline void ide_abort_command(IDEState *s) +{ + s->status = READY_STAT | ERR_STAT; + s->error = ABRT_ERR; +} + +static inline void ide_set_irq(IDEState *s) +{ + if (!(ide_state[0].cmd & IDE_CMD_DISABLE_IRQ)) { + pic_set_irq(s->irq, 1); + cpu_x86_interrupt(global_env); + } +} + +/* prepare data transfer and tell what to do after */ +static void ide_transfer_start(IDEState *s, int size, + EndTransferFunc *end_transfer_func) +{ + s->end_transfer_func = end_transfer_func; + s->data_ptr = s->io_buffer; + s->data_end = s->io_buffer + size; + s->status |= DRQ_STAT; +} + +static void ide_transfer_stop(IDEState *s) +{ + s->end_transfer_func = ide_transfer_stop; + s->data_ptr = s->io_buffer; + s->data_end = s->io_buffer; + s->status &= ~DRQ_STAT; +} + +static int64_t ide_get_sector(IDEState *s) +{ + int64_t sector_num; + if (s->select & 0x40) { + /* lba */ + sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | + (s->lcyl << 8) | s->sector; + } else { + sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors + + (s->select & 0x0f) * s->sectors + + (s->sector - 1); + } + return sector_num; +} + +static void ide_set_sector(IDEState *s, int64_t sector_num) +{ + unsigned int cyl, r; + if (s->select & 0x40) { + s->select = (s->select & 0xf0) | (sector_num >> 24); + s->hcyl = (sector_num >> 16); + s->lcyl = (sector_num >> 8); + s->sector = (sector_num); + } else { + cyl = sector_num / (s->heads * s->sectors); + r = sector_num % (s->heads * s->sectors); + s->hcyl = cyl >> 8; + s->lcyl = cyl; + s->select = (s->select & 0xf0) | (r / s->sectors); + s->sector = (r % s->sectors) + 1; + } +} + +static void ide_sector_read(IDEState *s) +{ + int64_t sector_num; + int ret; + + s->status = READY_STAT | SEEK_STAT; + sector_num = ide_get_sector(s); + s->nsector--; + if (s->nsector == 0xff) { + /* no more sector to read from disk */ + ide_transfer_stop(s); + } else { +#if defined(DEBUG_IDE) + printf("read sector=%Ld\n", sector_num); +#endif + ret = bdrv_read(s->bs, sector_num, s->io_buffer, 1); + ide_transfer_start(s, 512, ide_sector_read); + ide_set_irq(s); + } + ide_set_sector(s, sector_num + 1); +} + +static void ide_sector_write(IDEState *s) +{ + int64_t sector_num; + int ret; + + s->status = READY_STAT | SEEK_STAT; + sector_num = ide_get_sector(s); +#if defined(DEBUG_IDE) + printf("write sector=%Ld\n", sector_num); +#endif + ret = bdrv_write(s->bs, sector_num, s->io_buffer, 1); + s->nsector--; + if (s->nsector == 0) { + /* no more sector to write */ + ide_transfer_stop(s); + } else { + ide_transfer_start(s, 512, ide_sector_write); + } + ide_set_sector(s, sector_num + 1); + ide_set_irq(s); +} + +void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + IDEState *s = ide_state[0].cur_drive; + int unit; + + addr &= 7; +#ifdef DEBUG_IDE + printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); +#endif + switch(addr) { + case 0: + break; + case 1: + s->feature = val; + break; + case 2: + s->nsector = val; + break; + case 3: + s->sector = val; + break; + case 4: + s->lcyl = val; + break; + case 5: + s->hcyl = val; + break; + case 6: + /* select drive */ + unit = (val >> 4) & 1; + s = &ide_state[unit]; + ide_state[0].cur_drive = s; + s->select = val; + break; + default: + case 7: + /* command */ +#if defined(DEBUG_IDE) + printf("ide: CMD=%02x\n", val); +#endif + switch(val) { + case WIN_PIDENTIFY: + case WIN_IDENTIFY: + if (s->bs) { + ide_identify(s); + s->status = READY_STAT; + ide_transfer_start(s, 512, ide_transfer_stop); + } else { + ide_abort_command(s); + } + ide_set_irq(s); + break; + case WIN_SPECIFY: + case WIN_RECAL: + s->status = READY_STAT; + ide_set_irq(s); + break; + case WIN_SETMULT: + if (s->nsector > MAX_MULT_SECTORS || + s->nsector == 0 || + (s->nsector & (s->nsector - 1)) != 0) { + ide_abort_command(s); + } else { + s->mult_sectors = s->nsector; + s->status = READY_STAT; + } + ide_set_irq(s); + break; + case WIN_READ: + case WIN_READ_ONCE: + ide_sector_read(s); + break; + case WIN_WRITE: + case WIN_WRITE_ONCE: + s->status = SEEK_STAT; + ide_transfer_start(s, 512, ide_sector_write); + break; + default: + ide_abort_command(s); + ide_set_irq(s); + break; + } + } +} + +uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr) +{ + IDEState *s = ide_state[0].cur_drive; + int ret; + + addr &= 7; + switch(addr) { + case 0: + ret = 0xff; + break; + case 1: + ret = s->error; + break; + case 2: + ret = s->nsector; + break; + case 3: + ret = s->sector; + break; + case 4: + ret = s->lcyl; + break; + case 5: + ret = s->hcyl; + break; + case 6: + ret = s->select; + break; + default: + case 7: + ret = s->status; + pic_set_irq(s->irq, 0); + break; + } +#ifdef DEBUG_IDE + printf("ide: read addr=0x%x val=%02x\n", addr, ret); +#endif + return ret; +} + +uint32_t ide_status_read(CPUX86State *env, uint32_t addr) +{ + IDEState *s = ide_state[0].cur_drive; + int ret; + ret = s->status; +#ifdef DEBUG_IDE + printf("ide: read addr=0x%x val=%02x\n", addr, ret); +#endif + return ret; +} + +void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + IDEState *s = &ide_state[0]; + /* common for both drives */ + s->cmd = val; +} + +void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) +{ + IDEState *s = ide_state[0].cur_drive; + uint8_t *p; + + p = s->data_ptr; + *(uint16_t *)p = tswap16(val); + p += 2; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); +} + +uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) +{ + IDEState *s = ide_state[0].cur_drive; + uint8_t *p; + int ret; + + p = s->data_ptr; + ret = tswap16(*(uint16_t *)p); + p += 2; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); + return ret; +} + +void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) +{ + IDEState *s = ide_state[0].cur_drive; + uint8_t *p; + + p = s->data_ptr; + *(uint32_t *)p = tswap32(val); + p += 4; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); +} + +uint32_t ide_data_readl(CPUX86State *env, uint32_t addr) +{ + IDEState *s = ide_state[0].cur_drive; + uint8_t *p; + int ret; + + p = s->data_ptr; + ret = tswap32(*(uint32_t *)p); + p += 4; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); + return ret; +} + +void ide_reset(IDEState *s) +{ + s->mult_sectors = MAX_MULT_SECTORS; + s->status = READY_STAT; + s->cur_drive = s; + s->select = 0xa0; +} + +void ide_init(void) +{ + IDEState *s; + int i, cylinders; + int64_t nb_sectors; + + for(i = 0; i < MAX_DISKS; i++) { + s = &ide_state[i]; + s->bs = bs_table[i]; + if (s->bs) { + bdrv_get_geometry(s->bs, &nb_sectors); + cylinders = nb_sectors / (16 * 63); + if (cylinders > 16383) + cylinders = 16383; + else if (cylinders < 2) + cylinders = 2; + s->cylinders = cylinders; + s->heads = 16; + s->sectors = 63; + s->nb_sectors = nb_sectors; + } + s->irq = 14; + ide_reset(s); + } + register_ioport_write(0x1f0, 8, ide_ioport_write, 1); + register_ioport_read(0x1f0, 8, ide_ioport_read, 1); + register_ioport_read(0x3f6, 1, ide_status_read, 1); + register_ioport_write(0x3f6, 1, ide_cmd_write, 1); + + /* data ports */ + register_ioport_write(0x1f0, 2, ide_data_writew, 2); + register_ioport_read(0x1f0, 2, ide_data_readw, 2); + register_ioport_write(0x1f0, 4, ide_data_writel, 4); + register_ioport_read(0x1f0, 4, ide_data_readl, 4); +} + /***********************************************************/ /* cpu signal handler */ static void host_segv_handler(int host_signum, siginfo_t *info, @@ -1873,16 +2495,22 @@ void main_loop(void *opaque) void help(void) { printf("Virtual Linux version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: vl [options] bzImage initrd [kernel parameters...]\n" + "usage: vl [options] bzImage [kernel parameters...]\n" "\n" "'bzImage' is a Linux kernel image (PAGE_OFFSET must be defined\n" "to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n" - "'initrd' is an initrd image\n" - "-m megs set virtual RAM size to megs MB\n" - "-n script set network init script [default=%s]\n" - "-s wait gdb connection to port %d\n" - "-p port change gdb connection port\n" - "-d output log in /tmp/vl.log\n" + "\n" + "General options:\n" + "-initrd file use 'file' as initial ram disk\n" + "-hda file use 'file' as hard disk 0 image\n" + "-hdb file use 'file' as hard disk 1 image\n" + "-m megs set virtual RAM size to megs MB\n" + "-n script set network init script [default=%s]\n" + "\n" + "Debug options:\n" + "-s wait gdb connection to port %d\n" + "-p port change gdb connection port\n" + "-d output log in /tmp/vl.log\n" "\n" "During emulation, use C-a h to get terminal commands:\n", DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT); @@ -1890,27 +2518,50 @@ void help(void) exit(1); } +struct option long_options[] = { + { "initrd", 1, NULL, 0, }, + { "hda", 1, NULL, 0, }, + { "hdb", 1, NULL, 0, }, + { NULL, 0, NULL, 0 }, +}; + int main(int argc, char **argv) { - int c, ret, initrd_size, i, use_gdbstub, gdbstub_port; + int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; struct linux_params *params; struct sigaction act; struct itimerval itv; CPUX86State *env; - const char *tmpdir; + const char *tmpdir, *initrd_filename; + const char *hd_filename[MAX_DISKS]; /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); - + initrd_filename = NULL; + for(i = 0; i < MAX_DISKS; i++) + hd_filename[i] = NULL; phys_ram_size = 32 * 1024 * 1024; pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; for(;;) { - c = getopt(argc, argv, "hm:dn:sp:"); + c = getopt_long_only(argc, argv, "hm:dn:sp:", long_options, &long_index); if (c == -1) break; switch(c) { + case 0: + switch(long_index) { + case 0: + initrd_filename = optarg; + break; + case 1: + hd_filename[0] = optarg; + break; + case 2: + hd_filename[1] = optarg; + break; + } + break; case 'h': help(); break; @@ -1933,7 +2584,7 @@ int main(int argc, char **argv) break; } } - if (optind + 1 >= argc) + if (optind >= argc) help(); /* init debug */ @@ -1946,6 +2597,18 @@ int main(int argc, char **argv) setvbuf(logfile, NULL, _IOLBF, 0); } + /* open the virtual block devices */ + for(i = 0; i < MAX_DISKS; i++) { + if (hd_filename[i]) { + bs_table[i] = bdrv_open(hd_filename[i]); + if (!bs_table[i]) { + fprintf(stderr, "vl: could not open hard disk image '%s\n", + hd_filename[i]); + exit(1); + } + } + } + /* init network tun interface */ net_init(); @@ -1978,15 +2641,19 @@ int main(int argc, char **argv) /* now we can load the kernel */ ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); if (ret < 0) { - fprintf(stderr, "%s: could not load kernel\n", argv[optind]); + fprintf(stderr, "vl: could not load kernel '%s'\n", argv[optind]); exit(1); } /* load initrd */ - initrd_size = load_image(argv[optind + 1], phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "%s: could not load initrd\n", argv[optind + 1]); - exit(1); + initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "vl: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } } /* init kernel params */ @@ -1996,8 +2663,8 @@ int main(int argc, char **argv) params->cl_magic = 0xA33F; params->cl_offset = params->commandline - (uint8_t *)params; params->ext_mem_k = (phys_ram_size / 1024) - 1024; - for(i = optind + 2; i < argc; i++) { - if (i != optind + 2) + for(i = optind + 1; i < argc; i++) { + if (i != optind + 1) pstrcat(params->commandline, sizeof(params->commandline), " "); pstrcat(params->commandline, sizeof(params->commandline), argv[i]); } @@ -2011,15 +2678,16 @@ int main(int argc, char **argv) /* init basic PC hardware */ init_ioports(); - register_ioport_writeb(0x80, 1, ioport80_write); + register_ioport_write(0x80, 1, ioport80_write, 1); - register_ioport_writeb(0x3d4, 2, vga_ioport_write); + register_ioport_write(0x3d4, 2, vga_ioport_write, 1); cmos_init(); pic_init(); pit_init(); serial_init(); ne2000_init(); + ide_init(); /* setup cpu signal handlers for MMU / self modifying code handling */ sigfillset(&act.sa_mask); diff --git a/vl.h b/vl.h new file mode 100644 index 000000000..87b569d0f --- /dev/null +++ b/vl.h @@ -0,0 +1,39 @@ +/* + * QEMU System Emulator header + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef VL_H +#define VL_H + +/* block.c */ +typedef struct BlockDriverState BlockDriverState; + +BlockDriverState *bdrv_open(const char *filename); +void bdrv_close(BlockDriverState *bs); +int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); +int bdrv_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); + + +#endif /* VL_H */ -- cgit v1.2.3 From 8ef9a8ece3aa8c92eccf998aaac5f38d74acb757 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 10:04:47 +0000 Subject: added nop operations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@292 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dyngen.c b/dyngen.c index 0266196ad..3e846232b 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1200,6 +1200,10 @@ int load_elf(const char *filename, FILE *outfile, int out_type) } if (out_type == OUT_INDEX_OP) { + fprintf(outfile, "DEF(nop1, 0, 0)\n"); + fprintf(outfile, "DEF(nop2, 0, 0)\n"); + fprintf(outfile, "DEF(nop3, 0, 0)\n"); + fprintf(outfile, "DEF(nop, 0, 0)\n"); fprintf(outfile, "DEF(end, 0, 0)\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name, *p; @@ -1270,6 +1274,17 @@ fprintf(outfile, } 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"); -- cgit v1.2.3 From 5797fa5d7ef49ce4beec9586af0cc9c63f7a4b3a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 10:11:50 +0000 Subject: first step to fix precise eflags update in case of exception git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@293 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 46 ++++------------- op_string.h | 12 ++--- ops_template.h | 54 +++++++++---------- translate-i386.c | 155 ++++++++++++++++++++++++++++++++----------------------- 4 files changed, 129 insertions(+), 138 deletions(-) diff --git a/op-i386.c b/op-i386.c index 77f3303e3..a7e057bdd 100644 --- a/op-i386.c +++ b/op-i386.c @@ -80,62 +80,34 @@ static inline int lshift(int x, int n) /* operations with flags */ -void OPPROTO op_addl_T0_T1_cc(void) +/* update flags with T0 and T1 (add/sub case) */ +void OPPROTO op_update2_cc(void) { - CC_SRC = T0; - T0 += T1; + CC_SRC = T1; CC_DST = T0; } -void OPPROTO op_orl_T0_T1_cc(void) +/* update flags with T0 (logic operation case) */ +void OPPROTO op_update1_cc(void) { - T0 |= T1; - CC_DST = T0; -} - -void OPPROTO op_andl_T0_T1_cc(void) -{ - T0 &= T1; CC_DST = T0; } -void OPPROTO op_subl_T0_T1_cc(void) +void OPPROTO op_update_neg_cc(void) { - CC_SRC = T0; - T0 -= T1; - CC_DST = T0; -} - -void OPPROTO op_xorl_T0_T1_cc(void) -{ - T0 ^= T1; + CC_SRC = -T0; CC_DST = T0; } void OPPROTO op_cmpl_T0_T1_cc(void) { - CC_SRC = T0; + CC_SRC = T1; CC_DST = T0 - T1; } -void OPPROTO op_negl_T0_cc(void) -{ - CC_SRC = 0; - T0 = -T0; - CC_DST = T0; -} - -void OPPROTO op_incl_T0_cc(void) -{ - CC_SRC = cc_table[CC_OP].compute_c(); - T0++; - CC_DST = T0; -} - -void OPPROTO op_decl_T0_cc(void) +void OPPROTO op_update_inc_cc(void) { CC_SRC = cc_table[CC_OP].compute_c(); - T0--; CC_DST = T0; } diff --git a/op_string.h b/op_string.h index c7ff74c05..66945b92e 100644 --- a/op_string.h +++ b/op_string.h @@ -86,7 +86,7 @@ void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void) v = glue(ldu, SUFFIX)(DI_ADDR); inc = (DF << SHIFT); INC_DI(); - CC_SRC = EAX; + CC_SRC = v; CC_DST = EAX - v; } @@ -105,7 +105,7 @@ void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void) if (v1 != v2) break; } while (CX != 0); - CC_SRC = v1; + CC_SRC = v2; CC_DST = v1 - v2; CC_OP = CC_OP_SUBB + SHIFT; } @@ -127,7 +127,7 @@ void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void) if (v1 == v2) break; } while (CX != 0); - CC_SRC = v1; + CC_SRC = v2; CC_DST = v1 - v2; CC_OP = CC_OP_SUBB + SHIFT; } @@ -142,7 +142,7 @@ void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void) inc = (DF << SHIFT); INC_SI(); INC_DI(); - CC_SRC = v1; + CC_SRC = v2; CC_DST = v1 - v2; } @@ -160,7 +160,7 @@ void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void) if (v1 != v2) break; } while (CX != 0); - CC_SRC = v1; + CC_SRC = v2; CC_DST = v1 - v2; CC_OP = CC_OP_SUBB + SHIFT; } @@ -181,7 +181,7 @@ void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void) if (v1 == v2) break; } while (CX != 0); - CC_SRC = v1; + CC_SRC = v2; CC_DST = v1 - v2; CC_OP = CC_OP_SUBB + SHIFT; } diff --git a/ops_template.h b/ops_template.h index 784c27805..c6e2b6b97 100644 --- a/ops_template.h +++ b/ops_template.h @@ -93,8 +93,8 @@ static int glue(compute_all_sub, SUFFIX)(void) { int cf, pf, af, zf, sf, of; int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; pf = parity_table[(uint8_t)CC_DST]; af = (CC_DST ^ src1 ^ src2) & 0x10; @@ -107,8 +107,8 @@ static int glue(compute_all_sub, SUFFIX)(void) static int glue(compute_c_sub, SUFFIX)(void) { int src1, src2, cf; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; return cf; } @@ -117,8 +117,8 @@ static int glue(compute_all_sbb, SUFFIX)(void) { int cf, pf, af, zf, sf, of; int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST - 1; + src1 = CC_DST + CC_SRC + 1; + src2 = CC_SRC; cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; pf = parity_table[(uint8_t)CC_DST]; af = (CC_DST ^ src1 ^ src2) & 0x10; @@ -131,8 +131,8 @@ static int glue(compute_all_sbb, SUFFIX)(void) static int glue(compute_c_sbb, SUFFIX)(void) { int src1, src2, cf; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST - 1; + src1 = CC_DST + CC_SRC + 1; + src2 = CC_SRC; cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; return cf; } @@ -234,8 +234,8 @@ static int glue(compute_all_sar, SUFFIX)(void) void OPPROTO glue(op_jb_sub, SUFFIX)(void) { int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; if ((DATA_TYPE)src1 < (DATA_TYPE)src2) JUMP_TB(PARAM1, 0, PARAM2); @@ -256,8 +256,8 @@ void OPPROTO glue(op_jz_sub, SUFFIX)(void) void OPPROTO glue(op_jbe_sub, SUFFIX)(void) { int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) JUMP_TB(PARAM1, 0, PARAM2); @@ -278,8 +278,8 @@ void OPPROTO glue(op_js_sub, SUFFIX)(void) void OPPROTO glue(op_jl_sub, SUFFIX)(void) { int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; if ((DATA_STYPE)src1 < (DATA_STYPE)src2) JUMP_TB(PARAM1, 0, PARAM2); @@ -291,8 +291,8 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void) void OPPROTO glue(op_jle_sub, SUFFIX)(void) { int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) JUMP_TB(PARAM1, 0, PARAM2); @@ -361,8 +361,8 @@ void OPPROTO glue(op_jecxz, SUFFIX)(void) void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) { int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2); } @@ -375,8 +375,8 @@ void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) { int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2); } @@ -389,8 +389,8 @@ void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void) void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) { int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2); } @@ -398,8 +398,8 @@ void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) { int src1, src2; - src1 = CC_SRC; - src2 = CC_SRC - CC_DST; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2); } @@ -714,9 +714,7 @@ void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void) { int cf; cf = cc_table[CC_OP].compute_c(); - CC_SRC = T0; T0 = T0 + T1 + cf; - CC_DST = T0; CC_OP = CC_OP_ADDB + SHIFT + cf * 3; } @@ -724,15 +722,13 @@ void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void) { int cf; cf = cc_table[CC_OP].compute_c(); - CC_SRC = T0; T0 = T0 - T1 - cf; - CC_DST = T0; CC_OP = CC_OP_SUBB + SHIFT + cf * 3; } void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void) { - CC_SRC = EAX; + CC_SRC = T0; CC_DST = EAX - T0; if ((DATA_TYPE)CC_DST == 0) { T0 = T1; diff --git a/translate-i386.c b/translate-i386.c index d986752da..b477ac4ad 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -365,14 +365,14 @@ static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = { }; static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { - gen_op_addl_T0_T1_cc, - gen_op_orl_T0_T1_cc, NULL, + gen_op_orl_T0_T1, + NULL, + NULL, + gen_op_andl_T0_T1, + NULL, + gen_op_xorl_T0_T1, NULL, - gen_op_andl_T0_T1_cc, - gen_op_subl_T0_T1_cc, - gen_op_xorl_T0_T1_cc, - gen_op_cmpl_T0_T1_cc, }; static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { @@ -748,46 +748,83 @@ static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { gen_op_fdiv_STN_ST0, }; -static void gen_op(DisasContext *s1, int op, int ot, int d, int s) +/* if d == OR_TMP0, it means memory operand (address in A0) */ +static void gen_op(DisasContext *s1, int op, int ot, int d) { - if (d != OR_TMP0) + GenOpFunc *gen_update_cc; + + if (d != OR_TMP0) { gen_op_mov_TN_reg[ot][0][d](); - if (s != OR_TMP1) - gen_op_mov_TN_reg[ot][1][s](); - if (op == OP_ADCL || op == OP_SBBL) { + } else { + gen_op_ld_T0_A0[ot](); + } + switch(op) { + case OP_ADCL: + case OP_SBBL: if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); s1->cc_op = CC_OP_DYNAMIC; - } else { + /* XXX: incorrect: CC_OP must also be modified AFTER memory access */ + gen_update_cc = gen_op_update2_cc; + break; + case OP_ADDL: + gen_op_addl_T0_T1(); + s1->cc_op = CC_OP_ADDB + ot; + gen_update_cc = gen_op_update2_cc; + break; + case OP_SUBL: + gen_op_subl_T0_T1(); + s1->cc_op = CC_OP_SUBB + ot; + gen_update_cc = gen_op_update2_cc; + break; + default: + case OP_ANDL: + case OP_ORL: + case OP_XORL: gen_op_arith_T0_T1_cc[op](); - s1->cc_op = cc_op_arithb[op] + ot; + s1->cc_op = CC_OP_LOGICB + ot; + gen_update_cc = gen_op_update1_cc; + break; + case OP_CMPL: + gen_op_cmpl_T0_T1_cc(); + s1->cc_op = CC_OP_SUBB + ot; + gen_update_cc = NULL; + break; } - if (d != OR_TMP0 && op != OP_CMPL) - gen_op_mov_reg_T0[ot][d](); -} - -static void gen_opi(DisasContext *s1, int op, int ot, int d, int c) -{ - gen_op_movl_T1_im(c); - gen_op(s1, op, ot, d, OR_TMP1); + if (op != OP_CMPL) { + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); + else + gen_op_st_T0_A0[ot](); + } + /* the flags update must happen after the memory write (precise + exception support) */ + if (gen_update_cc) + gen_update_cc(); } +/* if d == OR_TMP0, it means memory operand (address in A0) */ static void gen_inc(DisasContext *s1, int ot, int d, int c) { if (d != OR_TMP0) gen_op_mov_TN_reg[ot][0][d](); + else + gen_op_ld_T0_A0[ot](); if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); if (c > 0) { - gen_op_incl_T0_cc(); + gen_op_incl_T0(); s1->cc_op = CC_OP_INCB + ot; } else { - gen_op_decl_T0_cc(); + gen_op_decl_T0(); s1->cc_op = CC_OP_DECB + ot; } if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); + else + gen_op_st_T0_A0[ot](); + gen_op_update_inc_cc(); } static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) @@ -1459,15 +1496,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) rm = modrm & 7; if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); opreg = OR_TMP0; } else { opreg = OR_EAX + rm; } - gen_op(s, op, ot, opreg, reg); - if (mod != 3 && op != 7) { - gen_op_st_T0_A0[ot](); - } + gen_op_mov_TN_reg[ot][1][reg](); + gen_op(s, op, ot, opreg); break; case 1: /* OP Gv, Ev */ modrm = ldub(s->pc++); @@ -1477,15 +1511,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[ot](); - opreg = OR_TMP1; } else { - opreg = OR_EAX + rm; + gen_op_mov_TN_reg[ot][1][rm](); } - gen_op(s, op, ot, reg, opreg); + gen_op(s, op, ot, reg); break; case 2: /* OP A, Iv */ val = insn_get(s, ot); - gen_opi(s, op, ot, OR_EAX, val); + gen_op_movl_T1_im(val); + gen_op(s, op, ot, OR_EAX); break; } } @@ -1509,7 +1543,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); opreg = OR_TMP0; } else { opreg = rm + OR_EAX; @@ -1525,11 +1558,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = (int8_t)insn_get(s, OT_BYTE); break; } - - gen_opi(s, op, ot, opreg, val); - if (op != 7 && mod != 3) { - gen_op_st_T0_A0[ot](); - } + gen_op_movl_T1_im(val); + gen_op(s, op, ot, opreg); } break; @@ -1577,12 +1607,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 3: /* neg */ - gen_op_negl_T0_cc(); + gen_op_negl_T0(); if (mod != 3) { gen_op_st_T0_A0[ot](); } else { gen_op_mov_reg_T0[ot][rm](); } + gen_op_update_neg_cc(); s->cc_op = CC_OP_SUBB + ot; break; case 4: /* mul */ @@ -1664,7 +1695,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (op != 3 && op != 5) + if (op >= 2 && op != 3 && op != 5) gen_op_ld_T0_A0[ot](); } else { gen_op_mov_TN_reg[ot][0][rm](); @@ -1672,18 +1703,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) switch(op) { case 0: /* inc Ev */ - gen_inc(s, ot, OR_TMP0, 1); if (mod != 3) - gen_op_st_T0_A0[ot](); + opreg = OR_TMP0; else - gen_op_mov_reg_T0[ot][rm](); + opreg = rm; + gen_inc(s, ot, opreg, 1); break; case 1: /* dec Ev */ - gen_inc(s, ot, OR_TMP0, -1); if (mod != 3) - gen_op_st_T0_A0[ot](); + opreg = OR_TMP0; else - gen_op_mov_reg_T0[ot][rm](); + opreg = rm; + gen_inc(s, ot, opreg, -1); break; case 2: /* call Ev */ /* XXX: optimize if memory (no and is necessary) */ @@ -1822,17 +1853,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) rm = modrm & 7; gen_op_mov_TN_reg[ot][0][reg](); gen_op_mov_TN_reg[ot][1][rm](); - gen_op_addl_T0_T1_cc(); + gen_op_addl_T0_T1(); gen_op_mov_reg_T0[ot][rm](); gen_op_mov_reg_T1[ot][reg](); } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_mov_TN_reg[ot][0][reg](); gen_op_ld_T1_A0[ot](); - gen_op_addl_T0_T1_cc(); + gen_op_addl_T0_T1(); gen_op_st_T0_A0[ot](); gen_op_mov_reg_T1[ot][reg](); } + gen_op_update2_cc(); s->cc_op = CC_OP_ADDB + ot; break; case 0x1b0: @@ -3607,8 +3639,7 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_sbbl_T0_T1_cc] = CC_C, /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_incl_T0_cc] = CC_C, - [INDEX_op_decl_T0_cc] = CC_C, + [INDEX_op_update_inc_cc] = CC_C, [INDEX_op_into] = CC_O, @@ -3688,22 +3719,18 @@ static uint16_t opc_read_flags[NB_OPS] = { /* flags written by an operation */ static uint16_t opc_write_flags[NB_OPS] = { - [INDEX_op_addl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_orl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_update2_cc] = CC_OSZAPC, + [INDEX_op_update1_cc] = CC_OSZAPC, [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC, [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_andl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_subl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_negl_T0_cc] = CC_OSZAPC, + [INDEX_op_update_neg_cc] = CC_OSZAPC, /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_incl_T0_cc] = CC_OSZAPC, - [INDEX_op_decl_T0_cc] = CC_OSZAPC, + [INDEX_op_update_inc_cc] = CC_OSZAPC, [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_mulb_AL_T0] = CC_OSZAPC, @@ -3812,14 +3839,10 @@ static uint16_t opc_write_flags[NB_OPS] = { /* simpler form of an operation if no flags need to be generated */ static uint16_t opc_simpler[NB_OPS] = { - [INDEX_op_addl_T0_T1_cc] = INDEX_op_addl_T0_T1, - [INDEX_op_orl_T0_T1_cc] = INDEX_op_orl_T0_T1, - [INDEX_op_andl_T0_T1_cc] = INDEX_op_andl_T0_T1, - [INDEX_op_subl_T0_T1_cc] = INDEX_op_subl_T0_T1, - [INDEX_op_xorl_T0_T1_cc] = INDEX_op_xorl_T0_T1, - [INDEX_op_negl_T0_cc] = INDEX_op_negl_T0, - [INDEX_op_incl_T0_cc] = INDEX_op_incl_T0, - [INDEX_op_decl_T0_cc] = INDEX_op_decl_T0, + [INDEX_op_update2_cc] = INDEX_op_nop, + [INDEX_op_update1_cc] = INDEX_op_nop, + [INDEX_op_update_neg_cc] = INDEX_op_nop, + [INDEX_op_update_inc_cc] = INDEX_op_nop, [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1, [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1, -- cgit v1.2.3 From 8c9b861e749a8ca90441e2caa93033ad5dc4ae1e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 10:12:19 +0000 Subject: added block.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@294 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e3b18f32e..6d6458eb5 100644 --- a/Makefile +++ b/Makefile @@ -140,7 +140,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -vl: vl.o libqemu.a +vl: vl.o block.o libqemu.a $(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) depend: $(SRCS) @@ -210,7 +210,7 @@ dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \ Makefile elf.h elfload.c main.c signal.c qemu.h \ syscall.c syscall_defs.h vm86.c path.c mmap.c \ i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\ -vl.c i386-vl.ld\ +vl.c i386-vl.ld vl.h block.c\ thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\ exec.c cpu-exec.c\ cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \ -- cgit v1.2.3 From c9159e5321628a29bcc26216f0166e9cdd7e4b26 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 13:06:39 +0000 Subject: added IDE mult support - reduced irq latency (IDE should have good performances now) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@295 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 31 deletions(-) diff --git a/vl.c b/vl.c index 01378e258..23a4b5979 100644 --- a/vl.c +++ b/vl.c @@ -54,6 +54,7 @@ #define DEFAULT_NETWORK_SCRIPT "/etc/vl-ifup" //#define DEBUG_UNUSED_IOPORT +//#define DEBUG_IRQ_LATENCY #define PHYS_RAM_BASE 0xa8000000 #define KERNEL_LOAD_ADDR 0x00100000 @@ -598,14 +599,9 @@ static int pic_get_irq(PicState *s) } } -void pic_set_irq(int irq, int level) -{ - pic_set_irq1(&pics[irq >> 3], irq & 7, level); -} - -/* can be called at any time outside cpu_exec() to raise irqs if - necessary */ -void pic_handle_irq(void) +/* raise irq to CPU if necessary. must be called every time the active + irq may change */ +static void pic_update_irq(void) { int irq2, irq; @@ -626,16 +622,36 @@ void pic_handle_irq(void) /* from master pic */ pic_irq_requested = irq; } - global_env->hard_interrupt_request = 1; + cpu_x86_interrupt(global_env, CPU_INTERRUPT_HARD); } } +#ifdef DEBUG_IRQ_LATENCY +int64_t irq_time[16]; +int64_t cpu_get_ticks(void); +#endif + +void pic_set_irq(int irq, int level) +{ +#ifdef DEBUG_IRQ_LATENCY + if (level) { + irq_time[irq] = cpu_get_ticks(); + } +#endif + pic_set_irq1(&pics[irq >> 3], irq & 7, level); + pic_update_irq(); +} + int cpu_x86_get_pic_interrupt(CPUX86State *env) { int irq, irq2, intno; /* signal the pic that the irq was acked by the CPU */ irq = pic_irq_requested; +#ifdef DEBUG_IRQ_LATENCY + printf("IRQ%d latency=%Ld\n", irq, cpu_get_ticks() - irq_time[irq]); +#endif + if (irq >= 8) { irq2 = irq & 7; pics[1].isr |= (1 << irq2); @@ -706,6 +722,7 @@ void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) case 0: /* normal mode */ s->imr = val; + pic_update_irq(); break; case 1: s->irq_base = val & 0xf8; @@ -1570,8 +1587,6 @@ void ne2000_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) s->rcnt == 0) { s->isr |= ENISR_RDC; ne2000_update_irq(s); - /* XXX: find a better solution for irqs */ - cpu_x86_interrupt(global_env); } if (val & E8390_TRANS) { net_send_packet(s, s->mem + (s->tpsr << 8), s->tcnt); @@ -1931,7 +1946,8 @@ void ne2000_init(void) #define WIN_SET_MAX 0xF9 #define DISABLE_SEAGATE 0xFB -#define MAX_MULT_SECTORS 16 +/* set to 1 set disable mult support */ +#define MAX_MULT_SECTORS 8 #define MAX_DISKS 2 @@ -1948,7 +1964,7 @@ typedef struct IDEState { /* ide regs */ uint8_t feature; uint8_t error; - uint8_t nsector; + uint16_t nsector; /* 0 is 256 to ease computations */ uint8_t sector; uint8_t lcyl; uint8_t hcyl; @@ -1959,6 +1975,7 @@ typedef struct IDEState { /* depends on bit 4 in select, only meaningful for drive 0 */ struct IDEState *cur_drive; BlockDriverState *bs; + int req_nb_sectors; /* number of sectors per interrupt */ EndTransferFunc *end_transfer_func; uint8_t *data_ptr; uint8_t *data_end; @@ -1998,7 +2015,9 @@ static void ide_identify(IDEState *s) stw(p + 21, 512); /* cache size in sectors */ stw(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); - // stw(p + 47, MAX_MULT_SECTORS); +#if MAX_MULT_SECTORS > 1 + stw(p + 47, MAX_MULT_SECTORS); +#endif stw(p + 48, 1); /* dword I/O */ stw(p + 49, 1 << 9); /* LBA supported, no DMA */ stw(p + 51, 0x200); /* PIO transfer cycle */ @@ -2032,7 +2051,6 @@ static inline void ide_set_irq(IDEState *s) { if (!(ide_state[0].cmd & IDE_CMD_DISABLE_IRQ)) { pic_set_irq(s->irq, 1); - cpu_x86_interrupt(global_env); } } @@ -2090,51 +2108,60 @@ static void ide_set_sector(IDEState *s, int64_t sector_num) static void ide_sector_read(IDEState *s) { int64_t sector_num; - int ret; + int ret, n; s->status = READY_STAT | SEEK_STAT; sector_num = ide_get_sector(s); - s->nsector--; - if (s->nsector == 0xff) { + n = s->nsector; + if (n == 0) { /* no more sector to read from disk */ ide_transfer_stop(s); } else { #if defined(DEBUG_IDE) printf("read sector=%Ld\n", sector_num); #endif - ret = bdrv_read(s->bs, sector_num, s->io_buffer, 1); - ide_transfer_start(s, 512, ide_sector_read); + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); + ide_transfer_start(s, 512 * n, ide_sector_read); ide_set_irq(s); + ide_set_sector(s, sector_num + n); + s->nsector -= n; } - ide_set_sector(s, sector_num + 1); } static void ide_sector_write(IDEState *s) { int64_t sector_num; - int ret; + int ret, n, n1; s->status = READY_STAT | SEEK_STAT; sector_num = ide_get_sector(s); #if defined(DEBUG_IDE) printf("write sector=%Ld\n", sector_num); #endif - ret = bdrv_write(s->bs, sector_num, s->io_buffer, 1); - s->nsector--; + n = s->nsector; + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); + s->nsector -= n; if (s->nsector == 0) { /* no more sector to write */ ide_transfer_stop(s); } else { - ide_transfer_start(s, 512, ide_sector_write); + n1 = s->nsector; + if (n1 > s->req_nb_sectors) + n1 = s->req_nb_sectors; + ide_transfer_start(s, 512 * n1, ide_sector_write); } - ide_set_sector(s, sector_num + 1); + ide_set_sector(s, sector_num + n); ide_set_irq(s); } void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) { IDEState *s = ide_state[0].cur_drive; - int unit; + int unit, n; addr &= 7; #ifdef DEBUG_IDE @@ -2147,6 +2174,8 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) s->feature = val; break; case 2: + if (val == 0) + val = 256; s->nsector = val; break; case 3: @@ -2201,14 +2230,33 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) break; case WIN_READ: case WIN_READ_ONCE: + s->req_nb_sectors = 1; ide_sector_read(s); break; case WIN_WRITE: case WIN_WRITE_ONCE: s->status = SEEK_STAT; + s->req_nb_sectors = 1; ide_transfer_start(s, 512, ide_sector_write); break; + case WIN_MULTREAD: + if (!s->mult_sectors) + goto abort_cmd; + s->req_nb_sectors = s->mult_sectors; + ide_sector_read(s); + break; + case WIN_MULTWRITE: + if (!s->mult_sectors) + goto abort_cmd; + s->status = SEEK_STAT; + s->req_nb_sectors = s->mult_sectors; + n = s->nsector; + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ide_transfer_start(s, 512 * n, ide_sector_write); + break; default: + abort_cmd: ide_abort_command(s); ide_set_irq(s); break; @@ -2230,7 +2278,7 @@ uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr) ret = s->error; break; case 2: - ret = s->nsector; + ret = s->nsector & 0xff; break; case 3: ret = s->sector; @@ -2400,7 +2448,7 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, timer_irq_count = 2; timer_irq_count--; /* just exit from the cpu to have a chance to handle timers */ - cpu_x86_interrupt(global_env); + cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); timer_irq_pending = 1; } } @@ -2487,8 +2535,6 @@ void main_loop(void *opaque) pic_set_irq(0, 0); timer_irq_pending = 0; } - - pic_handle_irq(); } } -- cgit v1.2.3 From 68a7931591fca65ac5dc2e1b23688e08d1c328a6 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 13:12:32 +0000 Subject: reduced irq latency git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@296 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 4 ++++ cpu-exec.c | 43 +++++++++++++++++++++++-------------------- cpu-i386.h | 6 +----- exec.c | 7 ++++--- linux-user/signal.c | 2 +- translate-i386.c | 2 ++ 6 files changed, 35 insertions(+), 29 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index cc0a4ea33..5c414e805 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -309,6 +309,10 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); void cpu_abort(CPUState *env, const char *fmt, ...); extern CPUState *cpu_single_env; +#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ +#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ +void cpu_interrupt(CPUX86State *s, int mask); + /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); diff --git a/cpu-exec.c b/cpu-exec.c index aa2ee3a9e..4da3641e6 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -71,7 +71,7 @@ int cpu_exec(CPUState *env1) #ifdef __sparc__ int saved_i7, tmp_T0; #endif - int code_gen_size, ret; + int code_gen_size, ret, interrupt_request; void (*gen_func)(void); TranslationBlock *tb, **ptb; uint8_t *tc_ptr, *cs_base, *pc; @@ -139,7 +139,6 @@ int cpu_exec(CPUState *env1) #else #error unsupported target CPU #endif - env->interrupt_request = 0; env->exception_index = -1; /* prepare setjmp context for exception handling */ @@ -176,28 +175,32 @@ int cpu_exec(CPUState *env1) } env->exception_index = -1; } -#if defined(TARGET_I386) - /* if hardware interrupt pending, we execute it */ - if (env->hard_interrupt_request && - (env->eflags & IF_MASK)) { - int intno; - intno = cpu_x86_get_pic_interrupt(env); - if (loglevel) { - fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); - } - do_interrupt(intno, 0, 0, 0); - env->hard_interrupt_request = 0; - } -#endif T0 = 0; /* force lookup of first TB */ for(;;) { #ifdef __sparc__ /* g1 can be modified by some libc? functions */ tmp_T0 = T0; #endif - if (env->interrupt_request) { - env->exception_index = EXCP_INTERRUPT; - cpu_loop_exit(); + interrupt_request = env->interrupt_request; + if (interrupt_request) { +#if defined(TARGET_I386) + /* if hardware interrupt pending, we execute it */ + if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) { + int intno; + intno = cpu_x86_get_pic_interrupt(env); + if (loglevel) { + fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); + } + do_interrupt(intno, 0, 0, 0); + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + } +#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) { @@ -212,7 +215,7 @@ int cpu_exec(CPUState *env1) env->regs[R_EBP] = EBP; env->regs[R_ESP] = ESP; env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); - cpu_x86_dump_state(env, logfile, 0); + cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_ARM) cpu_arm_dump_state(env, logfile, 0); @@ -454,7 +457,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { TranslationBlock *tb; int ret; - + if (cpu_single_env) env = cpu_single_env; /* XXX: find a correct solution for multithread */ #if defined(DEBUG_SIGNAL) diff --git a/cpu-i386.h b/cpu-i386.h index 6c7afbf6e..4029746c8 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -254,10 +254,7 @@ typedef struct CPUX86State { struct TranslationBlock *current_tb; /* currently executing TB */ uint32_t cr[5]; /* NOTE: cr1 is unused */ uint32_t dr[8]; /* debug registers */ - int interrupt_request; /* if true, will exit from cpu_exec() ASAP */ - /* if true, will call cpu_x86_get_pic_interrupt() ASAP to get the - request interrupt number */ - int hard_interrupt_request; + int interrupt_request; int user_mode_only; /* user mode only simulation */ /* user data */ @@ -275,7 +272,6 @@ int cpu_x86_inl(CPUX86State *env, int addr); CPUX86State *cpu_x86_init(void); int cpu_x86_exec(CPUX86State *s); -void cpu_x86_interrupt(CPUX86State *s); void cpu_x86_close(CPUX86State *s); int cpu_x86_get_pic_interrupt(CPUX86State *s); diff --git a/exec.c b/exec.c index 4de0c60f1..e7f5081d0 100644 --- a/exec.c +++ b/exec.c @@ -617,11 +617,12 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } -void cpu_interrupt(CPUState *env) +/* mask must never be zero */ +void cpu_interrupt(CPUState *env, int mask) { TranslationBlock *tb; - - env->interrupt_request = 1; + + env->interrupt_request |= mask; /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ tb = env->current_tb; diff --git a/linux-user/signal.c b/linux-user/signal.c index 8c757dd4a..74aaeea68 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -333,7 +333,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, host_to_target_siginfo_noswap(&tinfo, info); if (queue_signal(sig, &tinfo) == 1) { /* interrupt the virtual CPU as soon as possible */ - cpu_interrupt(global_env); + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); } } diff --git a/translate-i386.c b/translate-i386.c index b477ac4ad..8a7147c55 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -3331,12 +3331,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (!s->vm86) { if (s->cpl <= s->iopl) { gen_op_sti(); + s->is_jmp = 2; /* give a chance to handle pending irqs */ } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { gen_op_sti(); + s->is_jmp = 2; /* give a chance to handle pending irqs */ } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } -- cgit v1.2.3 From ec410fc9ce03e775284602e304d60c78fa63619b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 23:16:33 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@297 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 0c062f5fa..466363d78 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -353,6 +353,61 @@ Lawton for the plex86 Project (@url{www.plex86.org}). @end enumerate +@section Invocation + +@example +usage: vl [options] bzImage [kernel parameters...] +@end example + +@file{bzImage} is a Linux kernel image. + +General options: +@table @option +@item -initrd file +Use 'file' as initial ram disk. + +@item -hda file +@item -hdb file +Use 'file' as hard disk 0 or 1 image. The disk images are simply raw +images of the hard disk. You can create them with the command: +@example +dd if=/dev/zero of=myimage bs=1024 count=mysize +@end example +where @var{myimage} is the image filename and @var{mysize} is its size +in kilobytes. + +@item -m megs +Set virtual RAM size to @var{megs} megabytes. + +@item -n script +Set network init script [default=/etc/vl-ifup]. This script is +launched to configure the host network interface (usually tun0) +corresponding to the virtual NE2000 card. +@end table + +Debug options: +@table @option +@item -s +Wait gdb connection to port 1234. +@item -p port +Change gdb connection port. +@item -d +Output log in /tmp/vl.log +@end table + +During emulation, use @key{C-a h} to get terminal commands: + +@table @key +@item C-a h +Print this help +@item C-a x +Exit emulatior +@item C-a b +Send break (magic sysrq) +@item C-a C-a +Send C-a +@end table + @section Kernel Compilation You can use any Linux kernel within QEMU provided it is mapped at @@ -417,11 +472,13 @@ PIT (timers) @item CMOS memory @item +Dumb VGA (to print the @code{Uncompressing Linux} message) +@item Serial port (port=0x3f8, irq=4) @item NE2000 network adapter (port=0x300, irq=9) -@item -Dumb VGA (to print the @code{Uncompressing Linux} message) +@item +IDE disk interface (port=0x1f0, irq=14) @end itemize @section GDB usage -- cgit v1.2.3 From 305034817d3ee36bd40895b72234e80a32d06f16 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 23:17:08 +0000 Subject: removed unused assignment git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@298 c046a42c-6fe2-441c-8c8c-71466251a162 --- op_string.h | 1 - 1 file changed, 1 deletion(-) diff --git a/op_string.h b/op_string.h index 66945b92e..79bc11e1a 100644 --- a/op_string.h +++ b/op_string.h @@ -2,7 +2,6 @@ void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void) { int v, inc; - inc = (DF << SHIFT); v = glue(ldu, SUFFIX)(SI_ADDR); glue(st, SUFFIX)(DI_ADDR, v); inc = (DF << SHIFT); -- cgit v1.2.3 From 0849bf0821fc174621d6b91a3c0a5709639ddab4 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 23:17:31 +0000 Subject: allow read only images git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@299 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 1ac8210e0..c687ff792 100644 --- a/block.c +++ b/block.c @@ -44,6 +44,7 @@ struct BlockDriverState { int fd; int64_t total_sectors; + int read_only; }; BlockDriverState *bdrv_open(const char *filename) @@ -55,11 +56,16 @@ BlockDriverState *bdrv_open(const char *filename) bs = malloc(sizeof(BlockDriverState)); if(!bs) return NULL; + bs->read_only = 0; fd = open(filename, O_RDWR); if (fd < 0) { - close(fd); - free(bs); - return NULL; + fd = open(filename, O_RDONLY); + if (fd < 0) { + close(fd); + free(bs); + return NULL; + } + bs->read_only = 1; } size = lseek64(fd, 0, SEEK_END); bs->total_sectors = size / 512; @@ -93,6 +99,9 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, { int ret; + if (bs->read_only) + return -1; + lseek64(bs->fd, sector_num * 512, SEEK_SET); ret = write(bs->fd, buf, nb_sectors * 512); if (ret != nb_sectors * 512) -- cgit v1.2.3 From 907a5b26903d593d53abbe6b52a7c72453625e71 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 23:18:22 +0000 Subject: fixed invalid irq jump chaining git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@300 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cpu-exec.c b/cpu-exec.c index 4da3641e6..ddbeb2ce9 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -194,6 +194,13 @@ int cpu_exec(CPUState *env1) } do_interrupt(intno, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_HARD; + /* ensure that no TB jump will be modified as + the program flow was changed */ +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif } #endif if (interrupt_request & CPU_INTERRUPT_EXIT) { -- cgit v1.2.3 From 2f62b397b5603f39deb9bdb170206e4e9e525139 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 23:18:59 +0000 Subject: dummy label to avoid gcc optimisations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@301 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exec.h b/exec.h index bd36453ba..92b248db0 100644 --- a/exec.h +++ b/exec.h @@ -219,10 +219,12 @@ label ## n:\ #define JUMP_TB(tbparam, n, eip)\ do {\ static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ + static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\ goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ label ## n:\ T0 = (long)(tbparam) + (n);\ EIP = eip;\ +dummy_label ## n:\ } while (0) #endif -- cgit v1.2.3 From b118d61e556a1f5cebc991e368af7292ffa1d8f3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 23:36:21 +0000 Subject: added PIC debug git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@302 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/vl.c b/vl.c index 23a4b5979..53f475a89 100644 --- a/vl.c +++ b/vl.c @@ -536,6 +536,8 @@ void cmos_init(void) /***********************************************************/ /* 8259 pic emulation */ +//#define DEBUG_PIC + typedef struct PicState { uint8_t last_irr; /* edge detection */ uint8_t irr; /* interrupt request register */ @@ -630,9 +632,18 @@ static void pic_update_irq(void) int64_t irq_time[16]; int64_t cpu_get_ticks(void); #endif +#ifdef DEBUG_PIC +int irq_level[16]; +#endif void pic_set_irq(int irq, int level) { +#ifdef DEBUG_PIC + if (level != irq_level[irq]) { + printf("pic_set_irq: irq=%d level=%d\n", irq, level); + irq_level[irq] = level; + } +#endif #ifdef DEBUG_IRQ_LATENCY if (level) { irq_time[irq] = cpu_get_ticks(); @@ -651,6 +662,9 @@ int cpu_x86_get_pic_interrupt(CPUX86State *env) #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%Ld\n", irq, cpu_get_ticks() - irq_time[irq]); #endif +#ifdef DEBUG_PIC + printf("pic_interrupt: irq=%d\n", irq); +#endif if (irq >= 8) { irq2 = irq & 7; @@ -671,6 +685,9 @@ void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) PicState *s; int priority; +#ifdef DEBUG_PIC + printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); +#endif s = &pics[addr >> 7]; addr &= 1; if (addr == 0) { @@ -743,19 +760,27 @@ void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } } -uint32_t pic_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t pic_ioport_read(CPUX86State *env, uint32_t addr1) { PicState *s; + unsigned int addr; + int ret; + + addr = addr1; s = &pics[addr >> 7]; addr &= 1; if (addr == 0) { if (s->read_reg_select) - return s->isr; + ret = s->isr; else - return s->irr; + ret = s->irr; } else { - return s->imr; + ret = s->imr; } +#ifdef DEBUG_PIC + printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); +#endif + return ret; } void pic_init(void) @@ -2634,6 +2659,7 @@ int main(int argc, char **argv) help(); /* init debug */ + setvbuf(stdout, NULL, _IOLBF, 0); if (loglevel) { logfile = fopen(DEBUG_LOGFILE, "w"); if (!logfile) { -- cgit v1.2.3 From e477b8b81ba5212747799ce71858e2b110fc6ae5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 30 Jun 2003 23:36:57 +0000 Subject: correct eflags evaluation order for all operations - fixed important CPU state restoring bug in some exception cases - disabled unsafe inc flags optimisation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@303 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- dyngen.c | 8 +- ops_template.h | 321 ++-------------------------------------- ops_template_mem.h | 423 +++++++++++++++++++++++++++++++++++++++++++++++++++++ translate-i386.c | 221 ++++++++++++++++++++++++---- 5 files changed, 636 insertions(+), 339 deletions(-) create mode 100644 ops_template_mem.h diff --git a/Makefile b/Makefile index 6d6458eb5..0fa0fa303 100644 --- a/Makefile +++ b/Makefile @@ -174,7 +174,7 @@ op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< -op-i386.o: op-i386.c opreg_template.h ops_template.h +op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h op-arm.o: op-arm.c op-arm-template.h diff --git a/dyngen.c b/dyngen.c index 3e846232b..c6c373bd1 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1200,11 +1200,11 @@ int load_elf(const char *filename, FILE *outfile, int out_type) } if (out_type == OUT_INDEX_OP) { - fprintf(outfile, "DEF(nop1, 0, 0)\n"); - fprintf(outfile, "DEF(nop2, 0, 0)\n"); - fprintf(outfile, "DEF(nop3, 0, 0)\n"); - fprintf(outfile, "DEF(nop, 0, 0)\n"); 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, *p; name = strtab + sym->st_name; diff --git a/ops_template.h b/ops_template.h index c6e2b6b97..4595291e7 100644 --- a/ops_template.h +++ b/ops_template.h @@ -406,127 +406,6 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) /* shifts */ -void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & SHIFT_MASK; - if (count) { - CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); - src = T0; - T0 &= DATA_MASK; - T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); - CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - (T0 & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT_MASK; - if (count) { - T0 &= DATA_MASK; - T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & SHIFT_MASK; - if (count) { - CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); - src = T0; - T0 &= DATA_MASK; - T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); - CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((T0 >> (DATA_BITS - 1)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT_MASK; - if (count) { - T0 &= DATA_MASK; - T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) -{ - int count, res, eflags; - unsigned int src; - - count = T1 & 0x1f; -#if DATA_BITS == 16 - count = rclw_table[count]; -#elif DATA_BITS == 8 - count = rclb_table[count]; -#endif - if (count) { - eflags = cc_table[CC_OP].compute_all(); - T0 &= DATA_MASK; - src = T0; - res = (T0 << count) | ((eflags & CC_C) << (count - 1)); - if (count > 1) - res |= T0 >> (DATA_BITS + 1 - count); - T0 = res; - CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((src >> (DATA_BITS - count)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) -{ - int count, res, eflags; - unsigned int src; - - count = T1 & 0x1f; -#if DATA_BITS == 16 - count = rclw_table[count]; -#elif DATA_BITS == 8 - count = rclb_table[count]; -#endif - if (count) { - eflags = cc_table[CC_OP].compute_all(); - T0 &= DATA_MASK; - src = T0; - res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); - if (count > 1) - res |= T0 << (DATA_BITS + 1 - count); - T0 = res; - CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((src >> (count - 1)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - CC_SRC = (DATA_TYPE)T0 << (count - 1); - T0 = T0 << count; - CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; - } - FORCE_RET(); -} - void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) { int count; @@ -535,20 +414,6 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) FORCE_RET(); } -void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & 0x1f; - if (count) { - T0 &= DATA_MASK; - CC_SRC = T0 >> (count - 1); - T0 = T0 >> count; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) { int count; @@ -558,20 +423,6 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) FORCE_RET(); } -void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & 0x1f; - if (count) { - src = (DATA_STYPE)T0; - CC_SRC = src >> (count - 1); - T0 = src >> count; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) { int count, src; @@ -581,162 +432,11 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) FORCE_RET(); } -#if DATA_BITS == 16 -/* XXX: overflow flag might be incorrect in some cases in shldw */ -void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - unsigned int res; - count = PARAM1; - T1 &= 0xffff; - res = T1 | (T0 << 16); - CC_SRC = res >> (32 - count); - res <<= count; - if (count > 16) - res |= T1 << (count - 16); - T0 = res >> 16; - CC_DST = T0; -} - -void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - unsigned int res; - count = ECX & 0x1f; - if (count) { - T1 &= 0xffff; - res = T1 | (T0 << 16); - CC_SRC = res >> (32 - count); - res <<= count; - if (count > 16) - res |= T1 << (count - 16); - T0 = res >> 16; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - unsigned int res; - - count = PARAM1; - res = (T0 & 0xffff) | (T1 << 16); - CC_SRC = res >> (count - 1); - res >>= count; - if (count > 16) - res |= T1 << (32 - count); - T0 = res; - CC_DST = T0; -} - - -void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - unsigned int res; - - count = ECX & 0x1f; - if (count) { - res = (T0 & 0xffff) | (T1 << 16); - CC_SRC = res >> (count - 1); - res >>= count; - if (count > 16) - res |= T1 << (32 - count); - T0 = res; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} -#endif - -#if DATA_BITS == 32 -void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - count = PARAM1; - T0 &= DATA_MASK; - T1 &= DATA_MASK; - CC_SRC = T0 << (count - 1); - T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); - CC_DST = T0; -} - -void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - count = ECX & 0x1f; - if (count) { - T0 &= DATA_MASK; - T1 &= DATA_MASK; - CC_SRC = T0 << (count - 1); - T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); - CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - count = PARAM1; - T0 &= DATA_MASK; - T1 &= DATA_MASK; - CC_SRC = T0 >> (count - 1); - T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); - CC_DST = T0; -} +#undef MEM_WRITE +#include "ops_template_mem.h" - -void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - count = ECX & 0x1f; - if (count) { - T0 &= DATA_MASK; - T1 &= DATA_MASK; - CC_SRC = T0 >> (count - 1); - T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} -#endif - -/* carry add/sub (we only need to set CC_OP differently) */ - -void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 + T1 + cf; - CC_OP = CC_OP_ADDB + SHIFT + cf * 3; -} - -void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 - T1 - cf; - CC_OP = CC_OP_SUBB + SHIFT + cf * 3; -} - -void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void) -{ - CC_SRC = T0; - CC_DST = EAX - T0; - if ((DATA_TYPE)CC_DST == 0) { - T0 = T1; - } else { - EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); - } - FORCE_RET(); -} +#define MEM_WRITE +#include "ops_template_mem.h" /* bit operations */ #if DATA_BITS >= 16 @@ -752,7 +452,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) { int count; count = T1 & SHIFT_MASK; - CC_SRC = T0 >> count; + T1 = T0 >> count; T0 |= (1 << count); } @@ -760,7 +460,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) { int count; count = T1 & SHIFT_MASK; - CC_SRC = T0 >> count; + T1 = T0 >> count; T0 &= ~(1 << count); } @@ -768,7 +468,7 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) { int count; count = T1 & SHIFT_MASK; - CC_SRC = T0 >> count; + T1 = T0 >> count; T0 ^= (1 << count); } @@ -810,6 +510,13 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) #endif +#if DATA_BITS == 32 +void OPPROTO op_update_bt_cc(void) +{ + CC_SRC = T1; +} +#endif + /* string operations */ /* XXX: maybe use lower level instructions to ease 16 bit / segment handling */ diff --git a/ops_template_mem.h b/ops_template_mem.h new file mode 100644 index 000000000..f1209d2aa --- /dev/null +++ b/ops_template_mem.h @@ -0,0 +1,423 @@ +/* + * i386 micro operations (included several times to generate + * different operand sizes) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef MEM_WRITE + +#if DATA_BITS == 8 +#define MEM_SUFFIX b_mem +#elif DATA_BITS == 16 +#define MEM_SUFFIX w_mem +#elif DATA_BITS == 32 +#define MEM_SUFFIX l_mem +#endif + +#else + +#define MEM_SUFFIX SUFFIX + +#endif + +void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & SHIFT_MASK; + if (count) { + src = T0; + T0 &= DATA_MASK; + T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + (T0 & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & SHIFT_MASK; + if (count) { + src = T0; + T0 &= DATA_MASK; + T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((T0 >> (DATA_BITS - 1)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & SHIFT_MASK; + if (count) { + T0 &= DATA_MASK; + T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & SHIFT_MASK; + if (count) { + T0 &= DATA_MASK; + T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, res, eflags; + unsigned int src; + + count = T1 & 0x1f; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + T0 &= DATA_MASK; + src = T0; + res = (T0 << count) | ((eflags & CC_C) << (count - 1)); + if (count > 1) + res |= T0 >> (DATA_BITS + 1 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (DATA_BITS - count)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, res, eflags; + unsigned int src; + + count = T1 & 0x1f; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + T0 &= DATA_MASK; + src = T0; + res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); + if (count > 1) + res |= T0 << (DATA_BITS + 1 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (count - 1)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + src = (DATA_TYPE)T0 << (count - 1); + T0 = T0 << count; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + T0 &= DATA_MASK; + src = T0 >> (count - 1); + T0 = T0 >> count; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + src = (DATA_STYPE)T0; + T0 = src >> count; + src = src >> (count - 1); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +#if DATA_BITS == 16 +/* XXX: overflow flag might be incorrect in some cases in shldw */ +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + unsigned int res, tmp; + count = PARAM1; + T1 &= 0xffff; + res = T1 | (T0 << 16); + tmp = res >> (32 - count); + res <<= count; + if (count > 16) + res |= T1 << (count - 16); + T0 = res >> 16; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + unsigned int res, tmp; + count = ECX & 0x1f; + if (count) { + T1 &= 0xffff; + res = T1 | (T0 << 16); + tmp = res >> (32 - count); + res <<= count; + if (count > 16) + res |= T1 << (count - 16); + T0 = res >> 16; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + unsigned int res, tmp; + + count = PARAM1; + res = (T0 & 0xffff) | (T1 << 16); + tmp = res >> (count - 1); + res >>= count; + if (count > 16) + res |= T1 << (32 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + unsigned int res, tmp; + + count = ECX & 0x1f; + if (count) { + res = (T0 & 0xffff) | (T1 << 16); + tmp = res >> (count - 1); + res >>= count; + if (count > 16) + res |= T1 << (32 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} +#endif + +#if DATA_BITS == 32 +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count, tmp; + count = PARAM1; + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 << (count - 1); + T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count, tmp; + count = ECX & 0x1f; + if (count) { + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 << (count - 1); + T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count, tmp; + count = PARAM1; + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 >> (count - 1); + T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count, tmp; + count = ECX & 0x1f; + if (count) { + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 >> (count - 1); + T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} +#endif + +/* carry add/sub (we only need to set CC_OP differently) */ + +void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + T0 = T0 + T1 + cf; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = T1; + CC_DST = T0; + CC_OP = CC_OP_ADDB + SHIFT + cf * 3; +} + +void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + T0 = T0 - T1 - cf; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = T1; + CC_DST = T0; + CC_OP = CC_OP_SUBB + SHIFT + cf * 3; +} + +void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) +{ + unsigned int src, dst; + + src = T0; + dst = EAX - T0; + if ((DATA_TYPE)dst == 0) { + T0 = T1; + } else { + EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); + } +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = dst; + FORCE_RET(); +} + +#undef MEM_SUFFIX +#undef MEM_WRITE diff --git a/translate-i386.c b/translate-i386.c index 8a7147c55..bfc988446 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -390,6 +390,21 @@ static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { }, }; +static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = { + [OT_BYTE] = { + gen_op_adcb_mem_T0_T1_cc, + gen_op_sbbb_mem_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_adcw_mem_T0_T1_cc, + gen_op_sbbw_mem_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_adcl_mem_T0_T1_cc, + gen_op_sbbl_mem_T0_T1_cc, + }, +}; + static const int cc_op_arithb[8] = { CC_OP_ADDB, CC_OP_LOGICB, @@ -407,6 +422,12 @@ static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { gen_op_cmpxchgl_T0_T1_EAX_cc, }; +static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = { + gen_op_cmpxchgb_mem_T0_T1_EAX_cc, + gen_op_cmpxchgw_mem_T0_T1_EAX_cc, + gen_op_cmpxchgl_mem_T0_T1_EAX_cc, +}; + static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { [OT_BYTE] = { gen_op_rolb_T0_T1_cc, @@ -440,6 +461,39 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { }, }; +static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = { + [OT_BYTE] = { + gen_op_rolb_mem_T0_T1_cc, + gen_op_rorb_mem_T0_T1_cc, + gen_op_rclb_mem_T0_T1_cc, + gen_op_rcrb_mem_T0_T1_cc, + gen_op_shlb_mem_T0_T1_cc, + gen_op_shrb_mem_T0_T1_cc, + gen_op_shlb_mem_T0_T1_cc, + gen_op_sarb_mem_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_rolw_mem_T0_T1_cc, + gen_op_rorw_mem_T0_T1_cc, + gen_op_rclw_mem_T0_T1_cc, + gen_op_rcrw_mem_T0_T1_cc, + gen_op_shlw_mem_T0_T1_cc, + gen_op_shrw_mem_T0_T1_cc, + gen_op_shlw_mem_T0_T1_cc, + gen_op_sarw_mem_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_roll_mem_T0_T1_cc, + gen_op_rorl_mem_T0_T1_cc, + gen_op_rcll_mem_T0_T1_cc, + gen_op_rcrl_mem_T0_T1_cc, + gen_op_shll_mem_T0_T1_cc, + gen_op_shrl_mem_T0_T1_cc, + gen_op_shll_mem_T0_T1_cc, + gen_op_sarl_mem_T0_T1_cc, + }, +}; + static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = { [0] = { gen_op_shldw_T0_T1_im_cc, @@ -462,6 +516,28 @@ static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = { }, }; +static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = { + [0] = { + gen_op_shldw_mem_T0_T1_im_cc, + gen_op_shrdw_mem_T0_T1_im_cc, + }, + [1] = { + gen_op_shldl_mem_T0_T1_im_cc, + gen_op_shrdl_mem_T0_T1_im_cc, + }, +}; + +static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = { + [0] = { + gen_op_shldw_mem_T0_T1_ECX_cc, + gen_op_shrdw_mem_T0_T1_ECX_cc, + }, + [1] = { + gen_op_shldl_mem_T0_T1_ECX_cc, + gen_op_shrdl_mem_T0_T1_ECX_cc, + }, +}; + static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { [0] = { gen_op_btw_T0_T1_cc, @@ -763,11 +839,14 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) case OP_SBBL: if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); - gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + if (d != OR_TMP0) { + gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + gen_op_mov_reg_T0[ot][d](); + } else { + gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL](); + } s1->cc_op = CC_OP_DYNAMIC; - /* XXX: incorrect: CC_OP must also be modified AFTER memory access */ - gen_update_cc = gen_op_update2_cc; - break; + goto the_end; case OP_ADDL: gen_op_addl_T0_T1(); s1->cc_op = CC_OP_ADDB + ot; @@ -802,6 +881,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) exception support) */ if (gen_update_cc) gen_update_cc(); + the_end: ; } /* if d == OR_TMP0, it means memory operand (address in A0) */ @@ -831,14 +911,18 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) { if (d != OR_TMP0) gen_op_mov_TN_reg[ot][0][d](); + else + gen_op_ld_T0_A0[ot](); if (s != OR_TMP1) gen_op_mov_TN_reg[ot][1][s](); /* for zero counts, flags are not updated, so must do it dynamically */ if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); - - gen_op_shift_T0_T1_cc[ot][op](); - + + if (d != OR_TMP0) + gen_op_shift_T0_T1_cc[ot][op](); + else + gen_op_shift_mem_T0_T1_cc[ot][op](); if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ @@ -1885,8 +1969,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T0_A0[ot](); - gen_op_cmpxchg_T0_T1_EAX_cc[ot](); - gen_op_st_T0_A0[ot](); + gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); } s->cc_op = CC_OP_SUBB + ot; break; @@ -2264,7 +2347,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); opreg = OR_TMP0; } else { opreg = rm + OR_EAX; @@ -2279,10 +2361,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } gen_shifti(s, op, ot, opreg, shift); } - - if (mod != 3) { - gen_op_st_T0_A0[ot](); - } } break; case 0xd0: @@ -2330,7 +2408,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = ldub(s->pc++); val &= 0x1f; if (val) { - gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); + if (mod == 3) + gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); + else + gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val); if (op == 0 && ot != OT_WORD) s->cc_op = CC_OP_SHLB + ot; else @@ -2339,12 +2420,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); + if (mod == 3) + gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); + else + gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op](); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } - if (mod != 3) { - gen_op_st_T0_A0[ot](); - } else { + if (mod == 3) { gen_op_mov_reg_T0[ot][rm](); } break; @@ -3202,6 +3284,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_st_T0_A0[ot](); else gen_op_mov_reg_T0[ot][rm](); + gen_op_update_bt_cc(); } break; case 0x1a3: /* bt Gv, Ev */ @@ -3240,6 +3323,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_st_T0_A0[ot](); else gen_op_mov_reg_T0[ot][rm](); + gen_op_update_bt_cc(); } break; case 0x1bc: /* bsf */ @@ -3640,6 +3724,13 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_sbbw_T0_T1_cc] = CC_C, [INDEX_op_sbbl_T0_T1_cc] = CC_C, + [INDEX_op_adcb_mem_T0_T1_cc] = CC_C, + [INDEX_op_adcw_mem_T0_T1_cc] = CC_C, + [INDEX_op_adcl_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbb_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbw_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbl_mem_T0_T1_cc] = CC_C, + /* subtle: due to the incl/decl implementation, C is used */ [INDEX_op_update_inc_cc] = CC_C, @@ -3717,23 +3808,38 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_rcrb_T0_T1_cc] = CC_C, [INDEX_op_rcrw_T0_T1_cc] = CC_C, [INDEX_op_rcrl_T0_T1_cc] = CC_C, + + [INDEX_op_rclb_mem_T0_T1_cc] = CC_C, + [INDEX_op_rclw_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcll_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrb_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrw_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrl_mem_T0_T1_cc] = CC_C, }; /* flags written by an operation */ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_update2_cc] = CC_OSZAPC, [INDEX_op_update1_cc] = CC_OSZAPC, + [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_update_neg_cc] = CC_OSZAPC, + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_update_inc_cc] = CC_OSZAPC, + [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC, [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_update_neg_cc] = CC_OSZAPC, - /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_update_inc_cc] = CC_OSZAPC, - [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC, [INDEX_op_mulb_AL_T0] = CC_OSZAPC, [INDEX_op_imulb_AL_T0] = CC_OSZAPC, @@ -3795,6 +3901,42 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC, [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, @@ -3832,6 +3974,10 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchg8b] = CC_Z, [INDEX_op_lar] = CC_Z, [INDEX_op_lsl] = CC_Z, @@ -3844,8 +3990,10 @@ static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_update2_cc] = INDEX_op_nop, [INDEX_op_update1_cc] = INDEX_op_nop, [INDEX_op_update_neg_cc] = INDEX_op_nop, +#if 0 + /* broken: CC_OP logic must be rewritten */ [INDEX_op_update_inc_cc] = INDEX_op_nop, - +#endif [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1, [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1, [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1, @@ -3854,6 +4002,14 @@ static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1, [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1, + [INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1, + [INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1, + [INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1, + + [INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1, + [INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1, + [INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1, + [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1, @@ -3971,6 +4127,10 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc break; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); + if (!dc->tf && dc->is_jmp == DISAS_NEXT) { + gen_jmp(dc, ret - (unsigned long)dc->cs_base); + } + /* we must store the eflags state if it is not already done */ if (dc->is_jmp != DISAS_TB_JUMP) { if (dc->cc_op != CC_OP_DYNAMIC) @@ -3983,12 +4143,19 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc if (dc->tf) { gen_op_raise_exception(EXCP01_SSTP); } - if (dc->is_jmp != 3) { + if (dc->is_jmp != DISAS_TB_JUMP) { /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); } *gen_opc_ptr = INDEX_op_end; - + /* we don't forget to fill the last values */ + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } + #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "----------------\n"); -- cgit v1.2.3 From 4d40895f2c30354c48ad9181e366e8d738f9b4d7 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Jul 2003 15:05:19 +0000 Subject: more accurate bcd convert - fixed FPU exceptions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@304 c046a42c-6fe2-441c-8c8c-71466251a162 --- helper-i386.c | 92 ++++++++++++++++++++--------------------------------------- 1 file changed, 31 insertions(+), 61 deletions(-) diff --git a/helper-i386.c b/helper-i386.c index f47252ac1..fef7c351e 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -981,7 +981,11 @@ void helper_lar(void) #ifndef USE_X86LDOUBLE void helper_fldt_ST0_A0(void) { - ST0 = helper_fldt((uint8_t *)A0); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void helper_fstt_ST0_A0(void) @@ -996,81 +1000,47 @@ void helper_fstt_ST0_A0(void) void helper_fbld_ST0_A0(void) { - uint8_t *seg; - CPU86_LDouble fpsrcop; - int m32i; + CPU86_LDouble tmp; + uint64_t val; unsigned int v; + int i; - /* in this code, seg/m32i will be used as temporary ptr/int */ - seg = (uint8_t *)A0 + 8; - v = ldub(seg--); - /* XXX: raise exception */ - if (v != 0) - return; - v = ldub(seg--); - /* XXX: raise exception */ - if ((v & 0xf0) != 0) - return; - m32i = v; /* <-- d14 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */ - fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0; - - v = ldub(seg--); - m32i = (v >> 4); /* <-- d7 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */ - v = ldub(seg--); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */ - v = ldub(seg); - m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */ - m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */ - fpsrcop += ((CPU86_LDouble)m32i); - if ( ldub(seg+9) & 0x80 ) - fpsrcop = -fpsrcop; - ST0 = fpsrcop; + val = 0; + for(i = 8; i >= 0; i--) { + v = ldub((uint8_t *)A0 + i); + val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); + } + tmp = val; + if (ldub((uint8_t *)A0 + 9) & 0x80) + tmp = -tmp; + fpush(); + ST0 = tmp; } void helper_fbst_ST0_A0(void) { - CPU86_LDouble fptemp; - CPU86_LDouble fpsrcop; + CPU86_LDouble tmp; int v; uint8_t *mem_ref, *mem_end; + int64_t val; - fpsrcop = rint(ST0); + tmp = rint(ST0); + val = (int64_t)tmp; mem_ref = (uint8_t *)A0; - mem_end = mem_ref + 8; - if ( fpsrcop < 0.0 ) { - stw(mem_end, 0x8000); - fpsrcop = -fpsrcop; + mem_end = mem_ref + 9; + if (val < 0) { + stb(mem_end, 0x80); + val = -val; } else { - stw(mem_end, 0x0000); + stb(mem_end, 0x00); } while (mem_ref < mem_end) { - if (fpsrcop == 0.0) + if (val == 0) break; - fptemp = floor(fpsrcop/10.0); - v = ((int)(fpsrcop - fptemp*10.0)); - if (fptemp == 0.0) { - stb(mem_ref++, v); - break; - } - fpsrcop = fptemp; - fptemp = floor(fpsrcop/10.0); - v |= (((int)(fpsrcop - fptemp*10.0)) << 4); + v = val % 100; + val = val / 100; + v = ((v / 10) << 4) | (v % 10); stb(mem_ref++, v); - fpsrcop = fptemp; } while (mem_ref < mem_end) { stb(mem_ref++, 0); -- cgit v1.2.3 From c39d5b78f62b0bdc10b9371c33e754ee1ba50f73 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Jul 2003 15:07:14 +0000 Subject: make FPU load exception safe git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@305 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 64 +++++++++++++++++++++++++++++++++++++++++++------------- translate-i386.c | 4 ---- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/op-i386.c b/op-i386.c index a7e057bdd..ee951b1da 100644 --- a/op-i386.c +++ b/op-i386.c @@ -1406,28 +1406,40 @@ void OPPROTO op_fildll_FT0_A0(void) void OPPROTO op_flds_ST0_A0(void) { + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i32 = ldl((void *)A0); - ST0 = FP_CONVERT.f; + env->fpregs[new_fpstt] = FP_CONVERT.f; #else - ST0 = ldfl((void *)A0); + env->fpregs[new_fpstt] = ldfl((void *)A0); #endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void OPPROTO op_fldl_ST0_A0(void) { + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i64 = ldq((void *)A0); - ST0 = FP_CONVERT.d; + env->fpregs[new_fpstt] = FP_CONVERT.d; #else - ST0 = ldfq((void *)A0); + env->fpregs[new_fpstt] = ldfq((void *)A0); #endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } #ifdef USE_X86LDOUBLE void OPPROTO op_fldt_ST0_A0(void) { - ST0 = *(long double *)A0; + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = *(long double *)A0; + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } #else void OPPROTO op_fldt_ST0_A0(void) @@ -1441,17 +1453,29 @@ void OPPROTO op_fldt_ST0_A0(void) void helper_fild_ST0_A0(void) { - ST0 = (CPU86_LDouble)ldsw((void *)A0); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void helper_fildl_ST0_A0(void) { - ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void helper_fildll_ST0_A0(void) { - ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void OPPROTO op_fild_ST0_A0(void) @@ -1473,32 +1497,44 @@ void OPPROTO op_fildll_ST0_A0(void) void OPPROTO op_fild_ST0_A0(void) { + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i32 = ldsw((void *)A0); - ST0 = (CPU86_LDouble)FP_CONVERT.i32; + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; #else - ST0 = (CPU86_LDouble)ldsw((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); #endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void OPPROTO op_fildl_ST0_A0(void) { + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i32 = (int32_t) ldl((void *)A0); - ST0 = (CPU86_LDouble)FP_CONVERT.i32; + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; #else - ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); #endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } void OPPROTO op_fildll_ST0_A0(void) { + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i64 = (int64_t) ldq((void *)A0); - ST0 = (CPU86_LDouble)FP_CONVERT.i64; + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64; #else - ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); #endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ } #endif diff --git a/translate-i386.c b/translate-i386.c index bfc988446..c8bd12f3d 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -2489,7 +2489,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) switch(op & 7) { case 0: - gen_op_fpush(); switch(op >> 4) { case 0: gen_op_flds_ST0_A0(); @@ -2540,7 +2539,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fnstcw_A0(); break; case 0x1d: /* fldt mem */ - gen_op_fpush(); gen_op_fldt_ST0_A0(); break; case 0x1f: /* fstpt mem */ @@ -2557,7 +2555,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fnstsw_A0(); break; case 0x3c: /* fbld */ - gen_op_fpush(); gen_op_fbld_ST0_A0(); break; case 0x3e: /* fbstp */ @@ -2565,7 +2562,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fpop(); break; case 0x3d: /* fildll */ - gen_op_fpush(); gen_op_fildll_ST0_A0(); break; case 0x3f: /* fistpll */ -- cgit v1.2.3 From abd0aaff03fd97f2330423754546605ee918c8b2 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Jul 2003 15:07:57 +0000 Subject: fixed date storage in CMOS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@306 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 53f475a89..885958b16 100644 --- a/vl.c +++ b/vl.c @@ -519,7 +519,7 @@ void cmos_init(void) cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); - cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon); + cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); cmos_data[RTC_REG_A] = 0x26; -- cgit v1.2.3 From 7916e2245d71aff10b48aab0ebdc754550c89539 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Jul 2003 16:27:45 +0000 Subject: allow up to 256 MB of ram git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@307 c046a42c-6fe2-441c-8c8c-71466251a162 --- i386-vl.ld | 2 +- vl.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/i386-vl.ld b/i386-vl.ld index e666ed83f..428fe83e1 100644 --- a/i386-vl.ld +++ b/i386-vl.ld @@ -8,7 +8,7 @@ ENTRY(_start) SECTIONS { /* Read-only sections, merged into text segment: */ - . = 0xa0000000 + SIZEOF_HEADERS; + . = 0xa8000000 + SIZEOF_HEADERS; .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } diff --git a/vl.c b/vl.c index 885958b16..1596f61a9 100644 --- a/vl.c +++ b/vl.c @@ -56,7 +56,9 @@ //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IRQ_LATENCY -#define PHYS_RAM_BASE 0xa8000000 +#define PHYS_RAM_BASE 0xac000000 +#define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) + #define KERNEL_LOAD_ADDR 0x00100000 #define INITRD_LOAD_ADDR 0x00400000 #define KERNEL_PARAMS_ADDR 0x00090000 @@ -2640,6 +2642,11 @@ int main(int argc, char **argv) phys_ram_size = atoi(optarg) * 1024 * 1024; if (phys_ram_size <= 0) help(); + if (phys_ram_size > PHYS_RAM_MAX_SIZE) { + fprintf(stderr, "vl: at most %d MB RAM can be simulated\n", + PHYS_RAM_MAX_SIZE / (1024 * 1024)); + exit(1); + } break; case 'd': loglevel = 1; @@ -2734,7 +2741,7 @@ int main(int argc, char **argv) params->mount_root_rdonly = 0; params->cl_magic = 0xA33F; params->cl_offset = params->commandline - (uint8_t *)params; - params->ext_mem_k = (phys_ram_size / 1024) - 1024; + params->alt_mem_k = (phys_ram_size / 1024) - 1024; for(i = optind + 1; i < argc; i++) { if (i != optind + 1) pstrcat(params->commandline, sizeof(params->commandline), " "); -- cgit v1.2.3 From cd4c3e888a385acbb27532745102b95796185777 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 4 Jul 2003 14:38:25 +0000 Subject: added IDE WIN_READ_NATIVE_MAX command (2.5.xx fix) - added support for proper system shutdown git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@308 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 1596f61a9..1683d5969 100644 --- a/vl.c +++ b/vl.c @@ -2282,6 +2282,11 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) n = s->req_nb_sectors; ide_transfer_start(s, 512 * n, ide_sector_write); break; + case WIN_READ_NATIVE_MAX: + ide_set_sector(s, s->nb_sectors - 1); + s->status = READY_STAT; + ide_set_irq(s); + break; default: abort_cmd: ide_abort_command(s); @@ -2449,6 +2454,34 @@ void ide_init(void) register_ioport_read(0x1f0, 4, ide_data_readl, 4); } +/***********************************************************/ +/* simulate reset (stop qemu) */ + +int reset_requested; + +uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) +{ + return 0; +} + +void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) +{ + switch(val) { + case 0xfe: + reset_requested = 1; + cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); + break; + default: + break; + } +} + +void kbd_init(void) +{ + register_ioport_read(0x64, 1, kbd_read_status, 1); + register_ioport_write(0x64, 1, kbd_write_command, 1); +} + /***********************************************************/ /* cpu signal handler */ static void host_segv_handler(int host_signum, siginfo_t *info, @@ -2497,7 +2530,9 @@ void main_loop(void *opaque) for(;;) { ret = cpu_x86_exec(env); - + if (reset_requested) + break; + /* if hlt instruction, we wait until the next IRQ */ if (ret == EXCP_HLT) timeout = 10; @@ -2767,6 +2802,7 @@ int main(int argc, char **argv) serial_init(); ne2000_init(); ide_init(); + kbd_init(); /* setup cpu signal handlers for MMU / self modifying code handling */ sigfillset(&act.sa_mask); -- cgit v1.2.3 From 33e3963e1b9298e01cadd738124f0e618b5b79f5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Jul 2003 17:15:21 +0000 Subject: added user mode Linux Copy On Write disk image support - added -snapshot support (initial patch by Rusty Russell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@309 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 7 +- block.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ vl.c | 59 ++++++++++---- vl.h | 18 ++++- vlmkcow.c | 142 ++++++++++++++++++++++++++++++++++ 5 files changed, 442 insertions(+), 44 deletions(-) create mode 100644 vlmkcow.c diff --git a/Makefile b/Makefile index 0fa0fa303..ef6aef285 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ else LDFLAGS+=-Wl,-shared endif ifeq ($(TARGET_ARCH), i386) -PROGS+=vl +PROGS+=vl vlmkcow endif endif @@ -141,7 +141,10 @@ endif # must use static linking to avoid leaving stuff in virtual address space vl: vl.o block.o libqemu.a - $(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) + $(CC) -pg -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) + +vlmkcow: vlmkcow.o + $(CC) -o $@ $^ $(LIBS) depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend diff --git a/block.c b/block.c index c687ff792..3e1ae0da2 100644 --- a/block.c +++ b/block.c @@ -38,76 +38,286 @@ #include #include #include +#include #include "vl.h" +#define NO_THUNK_TYPE_SIZE +#include "thunk.h" + struct BlockDriverState { - int fd; + int fd; /* if -1, only COW mappings */ int64_t total_sectors; int read_only; + + uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ + uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ + int cow_bitmap_size; + int cow_fd; + int64_t cow_sectors_offset; + char filename[1024]; }; -BlockDriverState *bdrv_open(const char *filename) +BlockDriverState *bdrv_open(const char *filename, int snapshot) { BlockDriverState *bs; - int fd; + int fd, cow_fd; int64_t size; + char template[] = "/tmp/vl.XXXXXX"; + struct cow_header_v2 cow_header; + struct stat st; bs = malloc(sizeof(BlockDriverState)); if(!bs) return NULL; bs->read_only = 0; - fd = open(filename, O_RDWR); + bs->fd = -1; + bs->cow_fd = -1; + bs->cow_bitmap = NULL; + strcpy(bs->filename, filename); + + /* open standard HD image */ + fd = open(filename, O_RDWR | O_LARGEFILE); if (fd < 0) { - fd = open(filename, O_RDONLY); + /* read only image on disk */ + fd = open(filename, O_RDONLY | O_LARGEFILE); if (fd < 0) { - close(fd); - free(bs); - return NULL; + perror(filename); + goto fail; } - bs->read_only = 1; + if (!snapshot) + bs->read_only = 1; } - size = lseek64(fd, 0, SEEK_END); - bs->total_sectors = size / 512; bs->fd = fd; + + /* see if it is a cow image */ + if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { + fprintf(stderr, "%s: could not read header\n", filename); + goto fail; + } + if (cow_header.magic == htonl(COW_MAGIC) && + cow_header.version == htonl(COW_VERSION)) { + /* cow image found */ + size = cow_header.size; +#ifndef WORDS_BIGENDIAN + size = bswap64(size); +#endif + bs->total_sectors = size / 512; + + bs->cow_fd = fd; + bs->fd = -1; + if (cow_header.backing_file[0] != '\0') { + if (stat(cow_header.backing_file, &st) != 0) { + fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); + goto fail; + } + if (st.st_mtime != htonl(cow_header.mtime)) { + fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); + goto fail; + } + fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); + if (fd < 0) + goto fail; + bs->fd = fd; + } + /* mmap the bitmap */ + bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); + bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), + bs->cow_bitmap_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, bs->cow_fd, 0); + if (bs->cow_bitmap_addr == MAP_FAILED) + goto fail; + bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header); + bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; + snapshot = 0; + } else { + /* standard raw image */ + size = lseek64(fd, 0, SEEK_END); + bs->total_sectors = size / 512; + bs->fd = fd; + } + + if (snapshot) { + /* create a temporary COW file */ + cow_fd = mkstemp(template); + if (cow_fd < 0) + goto fail; + bs->cow_fd = cow_fd; + unlink(template); + + /* just need to allocate bitmap */ + bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3; + bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), + bs->cow_bitmap_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (bs->cow_bitmap_addr == MAP_FAILED) + goto fail; + bs->cow_bitmap = bs->cow_bitmap_addr; + bs->cow_sectors_offset = 0; + } + return bs; + fail: + bdrv_close(bs); + return NULL; } void bdrv_close(BlockDriverState *bs) { - close(bs->fd); + /* we unmap the mapping so that it is written to the COW file */ + if (bs->cow_bitmap_addr) + munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); + if (bs->cow_fd >= 0) + close(bs->cow_fd); + if (bs->fd >= 0) + close(bs->fd); free(bs); } +static inline void set_bit(uint8_t *bitmap, int64_t bitnum) +{ + bitmap[bitnum / 8] |= (1 << (bitnum%8)); +} + +static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) +{ + return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); +} + + +/* Return true if first block has been changed (ie. current version is + * in COW file). Set the number of continuous blocks for which that + * is true. */ +static int is_changed(uint8_t *bitmap, + int64_t sector_num, int nb_sectors, + int *num_same) +{ + int changed; + + if (!bitmap || nb_sectors == 0) { + *num_same = nb_sectors; + return 0; + } + + changed = is_bit_set(bitmap, sector_num); + for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { + if (is_bit_set(bitmap, sector_num + *num_same) != changed) + break; + } + + return changed; +} + +/* commit COW file into the raw image */ +int bdrv_commit(BlockDriverState *bs) +{ + int64_t i; + uint8_t *cow_bitmap; + + if (!bs->cow_bitmap) { + fprintf(stderr, "Already committed to %s\n", bs->filename); + return 0; + } + + if (bs->read_only) { + fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename); + return -1; + } + + cow_bitmap = bs->cow_bitmap; + for (i = 0; i < bs->total_sectors; i++) { + if (is_bit_set(cow_bitmap, i)) { + unsigned char sector[512]; + if (bdrv_read(bs, i, sector, 1) != 0) { + fprintf(stderr, "Error reading sector %lli: aborting commit\n", + (long long)i); + return -1; + } + + /* Make bdrv_write write to real file for a moment. */ + bs->cow_bitmap = NULL; + if (bdrv_write(bs, i, sector, 1) != 0) { + fprintf(stderr, "Error writing sector %lli: aborting commit\n", + (long long)i); + bs->cow_bitmap = cow_bitmap; + return -1; + } + bs->cow_bitmap = cow_bitmap; + } + } + fprintf(stderr, "Committed snapshot to %s\n", bs->filename); + return 0; +} + /* return -1 if error */ int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { - int ret; + int ret, n, fd; + int64_t offset; + + while (nb_sectors > 0) { + if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) { + fd = bs->cow_fd; + offset = bs->cow_sectors_offset; + } else { + fd = bs->fd; + offset = 0; + } - lseek64(bs->fd, sector_num * 512, SEEK_SET); - ret = read(bs->fd, buf, nb_sectors * 512); - if (ret != nb_sectors * 512) - return -1; - else - return 0; + if (fd < 0) { + /* no file, just return empty sectors */ + memset(buf, 0, n * 512); + } else { + offset += sector_num * 512; + lseek64(fd, offset, SEEK_SET); + ret = read(fd, buf, n * 512); + if (ret != n * 512) { + return -1; + } + } + nb_sectors -= n; + sector_num += n; + buf += n * 512; + } + return 0; } /* return -1 if error */ int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - int ret; + int ret, fd, i; + int64_t offset, retl; if (bs->read_only) return -1; - lseek64(bs->fd, sector_num * 512, SEEK_SET); - ret = write(bs->fd, buf, nb_sectors * 512); - if (ret != nb_sectors * 512) + if (bs->cow_bitmap) { + fd = bs->cow_fd; + offset = bs->cow_sectors_offset; + } else { + fd = bs->fd; + offset = 0; + } + + offset += sector_num * 512; + retl = lseek64(fd, offset, SEEK_SET); + if (retl == -1) { return -1; - else - return 0; + } + ret = write(fd, buf, nb_sectors * 512); + if (ret != nb_sectors * 512) { + return -1; + } + + if (bs->cow_bitmap) { + for (i = 0; i < nb_sectors; i++) + set_bit(bs->cow_bitmap, sector_num + i); + } + return 0; } void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) diff --git a/vl.c b/vl.c index 1683d5969..bb15ac4a9 100644 --- a/vl.c +++ b/vl.c @@ -63,6 +63,8 @@ #define INITRD_LOAD_ADDR 0x00400000 #define KERNEL_PARAMS_ADDR 0x00090000 +#define MAX_DISKS 2 + /* from plex86 (BSD license) */ struct __attribute__ ((packed)) linux_params { // For 0x00..0x3f, see 'struct screen_info' in linux/include/linux/tty.h. @@ -190,6 +192,7 @@ FILE *logfile = NULL; int loglevel; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; +BlockDriverState *bs_table[MAX_DISKS]; /***********************************************************/ /* x86 io ports */ @@ -1265,6 +1268,7 @@ void term_print_help(void) printf("\n" "C-a h print this help\n" "C-a x exit emulatior\n" + "C-a s save disk data back to file (if -snapshot)\n" "C-a b send break (magic sysrq)\n" "C-a C-a send C-a\n" ); @@ -1282,6 +1286,15 @@ void serial_received_byte(SerialState *s, int ch) case 'x': exit(0); break; + case 's': + { + int i; + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) + bdrv_commit(bs_table[i]); + } + } + break; case 'b': /* send break */ s->rbr = 0; @@ -1976,8 +1989,6 @@ void ne2000_init(void) /* set to 1 set disable mult support */ #define MAX_MULT_SECTORS 8 -#define MAX_DISKS 2 - struct IDEState; typedef void EndTransferFunc(struct IDEState *); @@ -2009,7 +2020,6 @@ typedef struct IDEState { uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; } IDEState; -BlockDriverState *bs_table[MAX_DISKS]; IDEState ide_state[MAX_DISKS]; static void padstr(char *str, const char *src, int len) @@ -2513,6 +2523,16 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, } } +unsigned long mmap_addr = PHYS_RAM_BASE; + +void *get_mmap_addr(unsigned long size) +{ + unsigned long addr; + addr = mmap_addr; + mmap_addr += ((size + 4095) & ~4095) + 4096; + return (void *)addr; +} + /* main execution loop */ CPUState *cpu_gdbstub_get_env(void *opaque) @@ -2612,6 +2632,7 @@ void help(void) "-initrd file use 'file' as initial ram disk\n" "-hda file use 'file' as hard disk 0 image\n" "-hdb file use 'file' as hard disk 1 image\n" + "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB\n" "-n script set network init script [default=%s]\n" "\n" @@ -2630,12 +2651,14 @@ struct option long_options[] = { { "initrd", 1, NULL, 0, }, { "hda", 1, NULL, 0, }, { "hdb", 1, NULL, 0, }, + { "snapshot", 0, NULL, 0, }, { NULL, 0, NULL, 0 }, }; int main(int argc, char **argv) { int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; + int snapshot; struct linux_params *params; struct sigaction act; struct itimerval itv; @@ -2652,6 +2675,7 @@ int main(int argc, char **argv) pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; + snapshot = 0; for(;;) { c = getopt_long_only(argc, argv, "hm:dn:sp:", long_options, &long_index); if (c == -1) @@ -2668,6 +2692,9 @@ int main(int argc, char **argv) case 2: hd_filename[1] = optarg; break; + case 3: + snapshot = 1; + break; } break; case 'h': @@ -2711,18 +2738,6 @@ int main(int argc, char **argv) setvbuf(logfile, NULL, _IOLBF, 0); } - /* open the virtual block devices */ - for(i = 0; i < MAX_DISKS; i++) { - if (hd_filename[i]) { - bs_table[i] = bdrv_open(hd_filename[i]); - if (!bs_table[i]) { - fprintf(stderr, "vl: could not open hard disk image '%s\n", - hd_filename[i]); - exit(1); - } - } - } - /* init network tun interface */ net_init(); @@ -2744,7 +2759,7 @@ int main(int argc, char **argv) } ftruncate(phys_ram_fd, phys_ram_size); unlink(phys_ram_file); - phys_ram_base = mmap((void *)PHYS_RAM_BASE, phys_ram_size, + phys_ram_base = mmap(get_mmap_addr(phys_ram_size), phys_ram_size, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, phys_ram_fd, 0); if (phys_ram_base == MAP_FAILED) { @@ -2752,6 +2767,18 @@ int main(int argc, char **argv) exit(1); } + /* open the virtual block devices */ + for(i = 0; i < MAX_DISKS; i++) { + if (hd_filename[i]) { + bs_table[i] = bdrv_open(hd_filename[i], snapshot); + if (!bs_table[i]) { + fprintf(stderr, "vl: could not open hard disk image '%s\n", + hd_filename[i]); + exit(1); + } + } + } + /* now we can load the kernel */ ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); if (ret < 0) { diff --git a/vl.h b/vl.h index 87b569d0f..fa7d5da27 100644 --- a/vl.h +++ b/vl.h @@ -24,16 +24,32 @@ #ifndef VL_H #define VL_H +/* vl.c */ +void *get_mmap_addr(unsigned long size); + /* block.c */ typedef struct BlockDriverState BlockDriverState; -BlockDriverState *bdrv_open(const char *filename); +BlockDriverState *bdrv_open(const char *filename, int snapshot); void bdrv_close(BlockDriverState *bs); int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); +int bdrv_commit(BlockDriverState *bs); + +/* user mode linux compatible COW file */ +#define COW_MAGIC 0x4f4f4f4d /* MOOO */ +#define COW_VERSION 2 +struct cow_header_v2 { + uint32_t magic; + uint32_t long version; + char backing_file[1024]; + int32_t mtime; + uint64_t size; + uint32_t sectorsize; +}; #endif /* VL_H */ diff --git a/vlmkcow.c b/vlmkcow.c new file mode 100644 index 000000000..435ed21d2 --- /dev/null +++ b/vlmkcow.c @@ -0,0 +1,142 @@ +/* + * create a COW disk image + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vl.h" + +#define NO_THUNK_TYPE_SIZE +#include "thunk.h" + +int cow_create(int cow_fd, const char *image_filename, + int64_t image_sectors) +{ + struct cow_header_v2 cow_header; + int fd; + struct stat st; + + memset(&cow_header, 0, sizeof(cow_header)); + cow_header.magic = htonl(COW_MAGIC); + cow_header.version = htonl(COW_VERSION); + if (image_filename) { + fd = open(image_filename, O_RDONLY); + if (fd < 0) { + perror(image_filename); + exit(1); + } + image_sectors = lseek64(fd, 0, SEEK_END); + if (fstat(fd, &st) != 0) { + close(fd); + return -1; + } + close(fd); + image_sectors /= 512; + cow_header.mtime = htonl(st.st_mtime); + realpath(image_filename, cow_header.backing_file); + } + cow_header.sectorsize = htonl(512); + cow_header.size = image_sectors * 512; +#ifndef WORDS_BIGENDIAN + cow_header.size = bswap64(cow_header.size); +#endif + write(cow_fd, &cow_header, sizeof(cow_header)); + /* resize to include at least all the bitmap */ + ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); + lseek(cow_fd, 0, SEEK_SET); + return 0; +} + +void help(void) +{ + printf("usage vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n" + "Create a Copy On Write disk image from an optional raw disk image\n" + "\n" + "-f disk_image set the raw disk image name\n" + "cow_image the created cow_image\n" + "cow_size the create cow_image size in MB if no raw disk image is used\n" + "\n" + "Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n" + ); + exit(1); +} + +int main(int argc, char **argv) +{ + const char *image_filename, *cow_filename; + int cow_fd, c, nb_args; + int64_t image_size; + + image_filename = NULL; + image_size = 0; + for(;;) { + c = getopt(argc, argv, "hf:"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 'f': + image_filename = optarg; + break; + } + } + if (!image_filename) + nb_args = 2; + else + nb_args = 1; + if (optind + nb_args != argc) + help(); + + cow_filename = argv[optind]; + if (nb_args == 2) { + image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024; + } + + cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (!cow_fd < 0) + return -1; + if (cow_create(cow_fd, image_filename, image_size) < 0) { + fprintf(stderr, "%s: error while formating\n", cow_filename); + exit(1); + } + close(cow_fd); + return 0; +} -- cgit v1.2.3 From 1f47a9223ebe3d0c9c779f72341afc10c206d574 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Jul 2003 19:01:55 +0000 Subject: added disk image help git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@310 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 9 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 466363d78..917717b7b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -368,13 +368,13 @@ Use 'file' as initial ram disk. @item -hda file @item -hdb file -Use 'file' as hard disk 0 or 1 image. The disk images are simply raw -images of the hard disk. You can create them with the command: -@example -dd if=/dev/zero of=myimage bs=1024 count=mysize -@end example -where @var{myimage} is the image filename and @var{mysize} is its size -in kilobytes. +Use 'file' as hard disk 0 or 1 image (@xref{disk_images}). + +@item -snapshot + +Write to temporary files instead of disk image files. In this case, +the raw disk image you use is not written back. You can however force +the write back by pressing @key{C-a s} (@xref{disk_images}). @item -m megs Set virtual RAM size to @var{megs} megabytes. @@ -402,12 +402,85 @@ During emulation, use @key{C-a h} to get terminal commands: Print this help @item C-a x Exit emulatior -@item C-a b +@item C-a s +Save disk data back to file (if -snapshot) +@item C-a b Send break (magic sysrq) -@item C-a C-a +@item C-a C-a Send C-a @end table +@node disk_images +@section Disk Images + +@subsection Raw disk images + +The disk images can simply be raw images of the hard disk. You can +create them with the command: +@example +dd if=/dev/zero of=myimage bs=1024 count=mysize +@end example +where @var{myimage} is the image filename and @var{mysize} is its size +in kilobytes. + +@subsection Snapshot mode + +If you use the option @option{-snapshot}, all disk images are +considered as read only. When sectors in written, they are written in +a temporary file created in @file{/tmp}. You can however force the +write back to the raw disk images by pressing @key{C-a s}. + +NOTE: The snapshot mode only works with raw disk images. + +@subsection Copy On Write disk images + +QEMU also supports user mode Linux +(@url{http://user-mode-linux.sourceforge.net/}) Copy On Write (COW) +disk images. The COW disk images are much smaller than normal images +as they store only modified sectors. They also permit the use of the +same disk image template for many users. + +To create a COW disk images, use the command: + +@example +vlmkcow -f myrawimage.bin mycowimage.cow +@end example + +@file{myrawimage.bin} is a raw image you want to use as original disk +image. It will never be written to. + +@file{mycowimage.cow} is the COW disk image which is created by +@code{vlmkcow}. You can use it directly with the @option{-hdx} +options. You must not modify the original raw disk image if you use +COW images, as COW images only store the modified sectors from the raw +disk image. QEMU stores the original raw disk image name and its +modified time in the COW disk image so that chances of mistakes are +reduced. + +If raw disk image is not read-only, by pressing @key{C-a s} you can +flush the COW disk image back into the raw disk image, as in snapshot +mode. + +COW disk images can also be created without a corresponding raw disk +image. It is useful to have a big initial virtual disk image without +using much disk space. Use: + +@example +vlmkcow mycowimage.cow 1024 +@end example + +to create a 1 gigabyte empty COW disk image. + +NOTES: +@enumerate +@item +COW disk images must be created on file systems supporting +@emph{holes} such as ext2 or ext3. +@item +Since holes are used, the displayed size of the COW disk image is not +the real one. To know it, use the @code{ls -ls} command. +@end enumerate + @section Kernel Compilation You can use any Linux kernel within QEMU provided it is mapped at -- cgit v1.2.3 From 3c1cf9fa865927759a78d476a218a7759fb38fb4 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Jul 2003 11:30:47 +0000 Subject: dummy rdmsr and wrmsr support - xor reg, reg optimization git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@311 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-i386.h | 14 ++++++++++++++ exec-i386.h | 2 ++ exec.h | 15 +++++++++++++++ helper-i386.c | 39 +++++++++++++++++++++++++++++++++++++++ op-i386.c | 10 ++++++++++ translate-i386.c | 29 +++++++++++++++++++++++++---- translate.c | 13 ++++++++++++- 7 files changed, 117 insertions(+), 5 deletions(-) diff --git a/cpu-i386.h b/cpu-i386.h index 4029746c8..e6318fb7f 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -125,6 +125,15 @@ #define PG_ERROR_U_MASK 0x04 #define PG_ERROR_RSVD_MASK 0x08 +#define MSR_IA32_APICBASE 0x1b +#define MSR_IA32_APICBASE_BSP (1<<8) +#define MSR_IA32_APICBASE_ENABLE (1<<11) +#define MSR_IA32_APICBASE_BASE (0xfffff<<12) + +#define MSR_IA32_SYSENTER_CS 0x174 +#define MSR_IA32_SYSENTER_ESP 0x175 +#define MSR_IA32_SYSENTER_EIP 0x176 + #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 #define EXCP02_NMI 2 @@ -244,6 +253,11 @@ typedef struct CPUX86State { SegmentCache tr; SegmentCache gdt; /* only base and limit are used */ SegmentCache idt; /* only base and limit are used */ + + /* sysenter registers */ + uint32_t sysenter_cs; + uint32_t sysenter_esp; + uint32_t sysenter_eip; /* exception/interrupt handling */ jmp_buf jmp_env; diff --git a/exec-i386.h b/exec-i386.h index 12e22bb41..84a1dabf0 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -159,6 +159,8 @@ void helper_idivl_EAX_T0(uint32_t eip); void helper_cmpxchg8b(void); void helper_cpuid(void); void helper_rdtsc(void); +void helper_rdmsr(void); +void helper_wrmsr(void); void helper_lsl(void); void helper_lar(void); diff --git a/exec.h b/exec.h index 92b248db0..1f46e4a46 100644 --- a/exec.h +++ b/exec.h @@ -324,6 +324,7 @@ typedef int spinlock_t; #define SPIN_LOCK_UNLOCKED 0 +#if 1 static inline void spin_lock(spinlock_t *lock) { while (testandset(lock)); @@ -338,6 +339,20 @@ static inline int spin_trylock(spinlock_t *lock) { return !testandset(lock); } +#else +static inline void spin_lock(spinlock_t *lock) +{ +} + +static inline void spin_unlock(spinlock_t *lock) +{ +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return 1; +} +#endif extern spinlock_t tb_lock; diff --git a/helper-i386.c b/helper-i386.c index fef7c351e..72b75a5c2 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -947,6 +947,45 @@ void helper_rdtsc(void) EDX = val >> 32; } +void helper_wrmsr(void) +{ + switch(ECX) { + case MSR_IA32_SYSENTER_CS: + env->sysenter_cs = EAX & 0xffff; + break; + case MSR_IA32_SYSENTER_ESP: + env->sysenter_esp = EAX; + break; + case MSR_IA32_SYSENTER_EIP: + env->sysenter_eip = EAX; + break; + default: + /* XXX: exception ? */ + break; + } +} + +void helper_rdmsr(void) +{ + switch(ECX) { + case MSR_IA32_SYSENTER_CS: + EAX = env->sysenter_cs; + EDX = 0; + break; + case MSR_IA32_SYSENTER_ESP: + EAX = env->sysenter_esp; + EDX = 0; + break; + case MSR_IA32_SYSENTER_EIP: + EAX = env->sysenter_eip; + EDX = 0; + break; + default: + /* XXX: exception ? */ + break; + } +} + void helper_lsl(void) { unsigned int selector, limit; diff --git a/op-i386.c b/op-i386.c index ee951b1da..84b75d07b 100644 --- a/op-i386.c +++ b/op-i386.c @@ -751,6 +751,16 @@ void OPPROTO op_cpuid(void) helper_cpuid(); } +void OPPROTO op_rdmsr(void) +{ + helper_rdmsr(); +} + +void OPPROTO op_wrmsr(void) +{ + helper_wrmsr(); +} + /* bcd */ /* XXX: exception */ diff --git a/translate-i386.c b/translate-i386.c index c8bd12f3d..fdbd5ee92 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1575,14 +1575,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub(s->pc++); - reg = ((modrm >> 3) & 7) + OR_EAX; + reg = ((modrm >> 3) & 7); mod = (modrm >> 6) & 3; rm = modrm & 7; if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); opreg = OR_TMP0; + } else if (op == OP_XORL && rm == reg) { + xor_zero: + /* xor reg, reg optimisation */ + gen_op_movl_T0_0(); + s->cc_op = CC_OP_LOGICB + ot; + gen_op_mov_reg_T0[ot][reg](); + gen_op_update1_cc(); + break; } else { - opreg = OR_EAX + rm; + opreg = rm; } gen_op_mov_TN_reg[ot][1][reg](); gen_op(s, op, ot, opreg); @@ -1590,11 +1598,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 1: /* OP Gv, Ev */ modrm = ldub(s->pc++); mod = (modrm >> 6) & 3; - reg = ((modrm >> 3) & 7) + OR_EAX; + reg = ((modrm >> 3) & 7); rm = modrm & 7; if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[ot](); + } else if (op == OP_XORL && rm == reg) { + goto xor_zero; } else { gen_op_mov_TN_reg[ot][1][rm](); } @@ -3464,6 +3474,17 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_loop[s->aflag][b & 3](val, next_eip); s->is_jmp = 1; break; + case 0x130: /* wrmsr */ + case 0x132: /* rdmsr */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (b & 2) + gen_op_rdmsr(); + else + gen_op_wrmsr(); + } + break; case 0x131: /* rdtsc */ gen_op_rdtsc(); break; @@ -4267,7 +4288,7 @@ void cpu_x86_update_cr0(CPUX86State *env) void cpu_x86_update_cr3(CPUX86State *env) { if (env->cr[0] & CR0_PG_MASK) { -#ifdef DEBUG_MMU +#if defined(DEBUG_MMU) printf("CR3 update: CR3=%08x\n", env->cr[3]); #endif page_unmap(); diff --git a/translate.c b/translate.c index 2f11dfc03..72b4d24b7 100644 --- a/translate.c +++ b/translate.c @@ -179,7 +179,18 @@ int cpu_restore_state(TranslationBlock *tb, #if defined(TARGET_I386) { int cc_op; - +#ifdef DEBUG_DISAS + if (loglevel) { + int i; + for(i=0;i<=j; i++) { + if (gen_opc_instr_start[i]) { + fprintf(logfile, "0x%04x: 0x%08x", i, gen_opc_pc[i]); + } + } + fprintf(logfile, "j=0x%x eip=0x%lx cs_base=%lx\n", + j, gen_opc_pc[j] - tb->cs_base, tb->cs_base); + } +#endif env->eip = gen_opc_pc[j] - tb->cs_base; cc_op = gen_opc_cc_op[j]; if (cc_op != CC_OP_DYNAMIC) -- cgit v1.2.3 From 4690764bba3a489d5180106d08970ced59113e22 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Jul 2003 12:17:46 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@312 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 9 +++++ Makefile | 8 ++-- TODO | 13 ++++--- VERSION | 2 +- cpu-all.h | 2 +- cpu-arm.h | 1 - qemu-doc.texi | 120 ++++++++++++++++++++++++++++++++++++++-------------------- vlmkcow.c | 3 +- 8 files changed, 104 insertions(+), 54 deletions(-) diff --git a/Changelog b/Changelog index 5d92f07e4..525f019e4 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,12 @@ +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. diff --git a/Makefile b/Makefile index ef6aef285..1db299e8c 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space vl: vl.o block.o libqemu.a - $(CC) -pg -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) + $(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) vlmkcow: vlmkcow.o $(CC) -o $@ $^ $(LIBS) @@ -213,11 +213,11 @@ dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \ Makefile elf.h elfload.c main.c signal.c qemu.h \ syscall.c syscall_defs.h vm86.c path.c mmap.c \ i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\ -vl.c i386-vl.ld vl.h block.c\ +vl.c i386-vl.ld vl.h block.c vlmkcow.c\ thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\ -exec.c cpu-exec.c\ +exec.c cpu-exec.c gdbstub.c\ cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \ -exec-i386.h ops_template.h op_string.h opreg_template.h \ +exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \ cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \ dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \ arm-dis.c \ diff --git a/TODO b/TODO index 2f65f7d4e..56229dfd7 100644 --- a/TODO +++ b/TODO @@ -1,16 +1,17 @@ - -- finish segment ops (call far, ret far, load_seg suppressed) -- fix arm fpu rounding (at least for float->integer conversions) +- optimize FPU operations (evaluate x87 stack pointer statically) and + fix cr0.TS emulation - fix CCOP optimisation -- optimize FPU operations (evaluate x87 stack pointer statically) -- fpush not before mem load restarting - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). -- add gcc 2.96 test configure (some gcc3 flags are needed) +- cpu loop optimisation (optimise ret case as the cpu state does not change) +- fix arm fpu rounding (at least for float->integer conversions) - add IPC syscalls lower priority: -------------- +- sysenter/sysexit emulation +- SMP support +- finish segment ops (call far, ret far, load_seg suppressed) - use -msoft-float on ARM - use kernel traps for unaligned accesses on ARM ? - handle rare page fault cases (in particular if page fault in heplers or diff --git a/VERSION b/VERSION index 44bb5d1f7..f7abe273d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.1 \ No newline at end of file +0.4.2 \ No newline at end of file diff --git a/cpu-all.h b/cpu-all.h index 5c414e805..d61ad7734 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -311,7 +311,7 @@ extern CPUState *cpu_single_env; #define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ -void cpu_interrupt(CPUX86State *s, int mask); +void cpu_interrupt(CPUState *s, int mask); /* gdb stub API */ extern int gdbstub_fd; diff --git a/cpu-arm.h b/cpu-arm.h index e3720886a..3b2e628e9 100644 --- a/cpu-arm.h +++ b/cpu-arm.h @@ -49,7 +49,6 @@ typedef struct CPUARMState { CPUARMState *cpu_arm_init(void); int cpu_arm_exec(CPUARMState *s); -void cpu_arm_interrupt(CPUARMState *s); void cpu_arm_close(CPUARMState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/qemu-doc.texi b/qemu-doc.texi index 917717b7b..b3a13b9e1 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -240,9 +240,9 @@ This section explains how to launch a Linux kernel inside QEMU. @enumerate @item -Download the archive @file{vl-test-xxx.tar.gz} containing a Linux kernel -and an initrd (initial Ram Disk). The archive also contains a -precompiled version of @file{vl}, the QEMU System emulator. +Download the archive @file{vl-test-xxx.tar.gz} containing a Linux +kernel and a disk image. The archive also contains a precompiled +version of @file{vl}, the QEMU System emulator. @item Optional: If you want network support (for example to launch X11 examples), you must copy the script @file{vl-ifup} in @file{/etc} and configure @@ -262,20 +262,25 @@ seen from the emulated kernel at IP address 172.20.0.1. > ./vl.sh connected to host network interface: tun0 Uncompressing Linux... Ok, booting the kernel. -Linux version 2.4.20 (bellard@voyager) (gcc version 2.95.2 20000220 (Debian GNU/Linux)) #42 Wed Jun 25 14:16:12 CEST 2003 +Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003 BIOS-provided physical RAM map: - BIOS-88: 0000000000000000 - 000000000009f000 (usable) - BIOS-88: 0000000000100000 - 0000000002000000 (usable) + BIOS-e801: 0000000000000000 - 000000000009f000 (usable) + BIOS-e801: 0000000000100000 - 0000000002000000 (usable) 32MB LOWMEM available. On node 0 totalpages: 8192 zone(0): 4096 pages. zone(1): 4096 pages. zone(2): 0 pages. -Kernel command line: root=/dev/ram ramdisk_size=6144 +Kernel command line: root=/dev/hda ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe +ide_setup: ide1=noprobe +ide_setup: ide2=noprobe +ide_setup: ide3=noprobe +ide_setup: ide4=noprobe +ide_setup: ide5=noprobe Initializing CPU#0 -Detected 501.785 MHz processor. -Calibrating delay loop... 973.20 BogoMIPS -Memory: 24776k/32768k available (725k kernel code, 7604k reserved, 151k data, 48k init, 0k highmem) +Detected 501.285 MHz processor. +Calibrating delay loop... 989.59 BogoMIPS +Memory: 29268k/32768k available (907k kernel code, 3112k reserved, 212k data, 52k init, 0k highmem) Dentry cache hash table entries: 4096 (order: 3, 32768 bytes) Inode cache hash table entries: 2048 (order: 2, 16384 bytes) Mount-cache hash table entries: 512 (order: 0, 4096 bytes) @@ -289,24 +294,30 @@ Based upon Swansea University Computer Society NET3.039 Initializing RT netlink socket apm: BIOS not found. Starting kswapd +Journalled Block Device driver loaded pty: 256 Unix98 ptys configured Serial driver version 5.05c (2001-07-08) with no serial options enabled ttyS00 at 0x03f8 (irq = 4) is a 16450 +Uniform Multi-Platform E-IDE driver Revision: 6.31 +ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx +hda: QEMU HARDDISK, ATA DISK drive +ide0 at 0x1f0-0x1f7,0x3f6 on irq 14 +hda: 12288 sectors (6 MB) w/256KiB Cache, CHS=12/16/63 +Partition check: + hda: unknown partition table ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com) Last modified Nov 1, 2000 by Paul Gortmaker NE*000 ethercard probe at 0x300: 52 54 00 12 34 56 eth0: NE2000 found at 0x300, using IRQ 9. -RAMDISK driver initialized: 16 RAM disks of 6144K size 1024 blocksize +RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize NET4: Linux TCP/IP 1.0 for NET4.0 IP Protocols: ICMP, UDP, TCP, IGMP IP: routing cache hash table of 512 buckets, 4Kbytes -TCP: Hash tables configured (established 2048 bind 2048) +TCP: Hash tables configured (established 2048 bind 4096) NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. -RAMDISK: ext2 filesystem found at block 0 -RAMDISK: Loading 6144 blocks [1 disk] into ram disk... done. -Freeing initrd memory: 6144k freed +EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended VFS: Mounted root (ext2 filesystem). -Freeing unused kernel memory: 48k freed +Freeing unused kernel memory: 52k freed sh: can't access tty; job control turned off # @end example @@ -338,7 +349,7 @@ a real Virtual Linux system ! NOTES: @enumerate @item -A 2.5.66 kernel is also included in the vl-test archive. Just +A 2.5.74 kernel is also included in the vl-test archive. Just replace the bzImage in vl.sh to try it. @item @@ -348,7 +359,19 @@ a temporary directory using the tmpfs filesystem to avoid too many unnecessary disk accesses. @item -The example initrd is a modified version of the one made by Kevin +In order to exit cleanly for vl, you can do a @emph{shutdown} inside +vl. vl will automatically exit when the Linux shutdown is done. + +@item +You can boot slightly faster by disabling the probe of non present IDE +interfaces. To do so, add the following options on the kernel command +line: +@example +ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe +@end example + +@item +The example disk image is a modified version of the one made by Kevin Lawton for the plex86 Project (@url{www.plex86.org}). @end enumerate @@ -363,9 +386,6 @@ usage: vl [options] bzImage [kernel parameters...] General options: @table @option -@item -initrd file -Use 'file' as initial ram disk. - @item -hda file @item -hdb file Use 'file' as hard disk 0 or 1 image (@xref{disk_images}). @@ -383,6 +403,9 @@ Set virtual RAM size to @var{megs} megabytes. Set network init script [default=/etc/vl-ifup]. This script is launched to configure the host network interface (usually tun0) corresponding to the virtual NE2000 card. + +@item -initrd file +Use 'file' as initial ram disk. @end table Debug options: @@ -481,13 +504,17 @@ Since holes are used, the displayed size of the COW disk image is not the real one. To know it, use the @code{ls -ls} command. @end enumerate -@section Kernel Compilation +@section Linux Kernel Compilation + +You should be able to use any kernel with QEMU provided you make the +following changes (only 2.4.x and 2.5.x were tested): -You can use any Linux kernel within QEMU provided it is mapped at -address 0x90000000 (the default is 0xc0000000). You must modify only two -lines in the kernel source: +@enumerate +@item +The kernel must be mapped at 0x90000000 (the default is +0xc0000000). You must modify only two lines in the kernel source: -In asm/page.h, replace +In @file{include/asm/page.h}, replace @example #define __PAGE_OFFSET (0xc0000000) @end example @@ -496,7 +523,7 @@ by #define __PAGE_OFFSET (0x90000000) @end example -And in arch/i386/vmlinux.lds, replace +And in @file{arch/i386/vmlinux.lds}, replace @example . = 0xc0000000 + 0x100000; @end example @@ -505,22 +532,25 @@ by . = 0x90000000 + 0x100000; @end example -The file config-2.4.20 gives the configuration of the example kernel. - -Just type +@item +If you want to enable SMP (Symmetric Multi-Processing) support, you +must make the following change in @file{include/asm/fixmap.h}. Replace @example -make bzImage +#define FIXADDR_TOP (0xffffX000UL) @end example +by +@example +#define FIXADDR_TOP (0xa7ffX000UL) +@end example +(X is 'e' or 'f' depending on the kernel version). Although you can +use an SMP kernel with QEMU, it only supports one CPU. -As you would do to make a real kernel. Then you can use with QEMU -exactly the same kernel as you would boot on your PC (in -@file{arch/i386/boot/bzImage}). - +@item If you are not using a 2.5 kernel as host kernel but if you use a target 2.5 kernel, you must also ensure that the 'HZ' define is set to 100 (1000 is the default) as QEMU cannot currently emulate timers at frequencies greater than 100 Hz on host Linux systems < 2.5. In -asm/param.h, replace: +@file{include/asm/param.h}, replace: @example # define HZ 1000 /* Internal kernel timer frequency */ @@ -530,8 +560,18 @@ by # define HZ 100 /* Internal kernel timer frequency */ @end example -If you have problems running your kernel, verify that neither the SMP nor -HIGHMEM configuration options are activated. +@end enumerate + +The file config-2.x.x gives the configuration of the example kernels. + +Just type +@example +make bzImage +@end example + +As you would do to make a real kernel. Then you can use with QEMU +exactly the same kernel as you would boot on your PC (in +@file{arch/i386/boot/bzImage}). @section PC Emulation @@ -733,7 +773,7 @@ Correct translated code invalidation is done efficiently by maintaining a linked list of every translated block contained in a given page. Other linked lists are also maintained to undo direct block chaining. -Althought the overhead of doing @code{mprotect()} calls is important, +Although the overhead of doing @code{mprotect()} calls is important, most MSDOS programs can be emulated at reasonnable speed with QEMU and DOSEMU. @@ -802,7 +842,7 @@ reentrancy. @section Self-virtualization -QEMU was conceived so that ultimately it can emulate itself. Althought +QEMU was conceived so that ultimately it can emulate itself. Although it is not very useful, it is an important test to show the power of the emulator. diff --git a/vlmkcow.c b/vlmkcow.c index 435ed21d2..80d9a0885 100644 --- a/vlmkcow.c +++ b/vlmkcow.c @@ -85,7 +85,8 @@ int cow_create(int cow_fd, const char *image_filename, void help(void) { - printf("usage vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n" + printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + "usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n" "Create a Copy On Write disk image from an optional raw disk image\n" "\n" "-f disk_image set the raw disk image name\n" -- cgit v1.2.3 From f2674e31e0b79a8e30335438f274b846d084a383 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jul 2003 12:26:09 +0000 Subject: old select support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@313 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 12 +++++++++++- linux-user/syscall_defs.h | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b22642910..cd3fdf553 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1763,7 +1763,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_select: - goto unimplemented; + { + struct target_sel_arg_struct *sel = (void *)arg1; + sel->n = tswapl(sel->n); + sel->inp = tswapl(sel->inp); + sel->outp = tswapl(sel->outp); + sel->exp = tswapl(sel->exp); + sel->tvp = tswapl(sel->tvp); + ret = do_select(sel->n, (void *)sel->inp, (void *)sel->outp, + (void *)sel->exp, (void *)sel->tvp); + } + break; case TARGET_NR_symlink: ret = get_errno(symlink((const char *)arg1, (const char *)arg2)); break; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 3826c1290..5caf2d855 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -390,6 +390,12 @@ struct target_tms { target_clock_t tms_cstime; }; +struct target_sel_arg_struct { + target_long n; + target_long inp, outp, exp; + target_long tvp; +}; + struct target_iovec { target_long iov_base; /* Starting address */ target_long iov_len; /* Number of bytes */ -- cgit v1.2.3 From 6e295807acbaf7eb3200a685376fb968ebdb8571 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jul 2003 17:10:32 +0000 Subject: ARM fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@314 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm-dis.c | 4 +- exec-arm.h | 8 ++ op-arm.c | 31 ++++---- translate-arm.c | 224 +++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 209 insertions(+), 58 deletions(-) diff --git a/arm-dis.c b/arm-dis.c index adacd898b..a84d91b48 100644 --- a/arm-dis.c +++ b/arm-dis.c @@ -560,8 +560,8 @@ static arm_regname regnames[] = { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }} }; -/* Default to GCC register name set. */ -static unsigned int regname_selected = 1; +/* 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 diff --git a/exec-arm.h b/exec-arm.h index 8da263672..e838e8823 100644 --- a/exec-arm.h +++ b/exec-arm.h @@ -30,3 +30,11 @@ register uint32_t T2 asm(AREG3); void cpu_lock(void); void cpu_unlock(void); void cpu_loop_exit(void); + +static inline int compute_cpsr(void) +{ + int ZF; + ZF = (env->NZF == 0); + return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); +} diff --git a/op-arm.c b/op-arm.c index 40cf3cd25..8e5cce0e9 100644 --- a/op-arm.c +++ b/op-arm.c @@ -154,11 +154,11 @@ void OPPROTO op_adcl_T0_T1_cc(void) FORCE_RET(); } -#define OPSUB(sub, sbc, T0, T1) \ +#define OPSUB(sub, sbc, res, T0, T1) \ \ void OPPROTO op_ ## sub ## l_T0_T1(void) \ { \ - T0 -= T1; \ + res = T0 - T1; \ } \ \ void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ @@ -167,13 +167,14 @@ void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ src1 = T0; \ T0 -= T1; \ env->NZF = T0; \ - env->CF = src1 < T1; \ + env->CF = src1 >= T1; \ env->VF = (src1 ^ T1) & (src1 ^ T0); \ + res = T0; \ } \ \ void OPPROTO op_ ## sbc ## l_T0_T1(void) \ { \ - T0 = T0 - T1 + env->CF - 1; \ + res = T0 - T1 + env->CF - 1; \ } \ \ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ @@ -182,20 +183,20 @@ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ src1 = T0; \ if (!env->CF) { \ T0 = T0 - T1 - 1; \ - T0 += T1; \ - env->CF = src1 < T1; \ + env->CF = src1 >= T1; \ } else { \ T0 = T0 - T1; \ - env->CF = src1 <= T1; \ + env->CF = src1 > T1; \ } \ env->VF = (src1 ^ T1) & (src1 ^ T0); \ env->NZF = T0; \ + res = T0; \ FORCE_RET(); \ } -OPSUB(sub, sbc, T0, T1) +OPSUB(sub, sbc, T0, T0, T1) -OPSUB(rsb, rsc, T1, T0) +OPSUB(rsb, rsc, T0, T1, T0) void OPPROTO op_andl_T0_T1(void) { @@ -222,11 +223,16 @@ void OPPROTO op_notl_T1(void) T1 = ~T1; } -void OPPROTO op_logic_cc(void) +void OPPROTO op_logic_T0_cc(void) { env->NZF = T0; } +void OPPROTO op_logic_T1_cc(void) +{ + env->NZF = T1; +} + #define EIP (env->regs[15]) void OPPROTO op_test_eq(void) @@ -334,10 +340,7 @@ void OPPROTO op_jmp(void) void OPPROTO op_movl_T0_psr(void) { - int ZF; - ZF = (env->NZF == 0); - T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); + T0 = compute_cpsr(); } /* NOTE: N = 1 and Z = 1 cannot be stored currently */ diff --git a/translate-arm.c b/translate-arm.c index 2413f02a5..6020e772d 100644 --- a/translate-arm.c +++ b/translate-arm.c @@ -34,6 +34,8 @@ typedef struct DisasContext { struct TranslationBlock *tb; } DisasContext; +#define DISAS_JUMP_NEXT 4 + /* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; @@ -333,10 +335,11 @@ static void disas_arm_insn(DisasContext *s) /* if not always execute, we generate a conditional jump to next instruction */ gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); - s->is_jmp = 1; + s->is_jmp = DISAS_JUMP_NEXT; } - if ((insn & 0x0c000000) == 0 && - (insn & 0x00000090) != 0x90) { + if (((insn & 0x0e000000) == 0 && + (insn & 0x00000090) != 0x90) || + ((insn & 0x0e000000) == (1 << 25))) { int set_cc, logic_cc, shiftop; op1 = (insn >> 21) & 0xf; @@ -367,7 +370,7 @@ static void disas_arm_insn(DisasContext *s) } } } else { - rs = (insn >> 16) & 0xf; + rs = (insn >> 8) & 0xf; gen_movl_T0_reg(s, rs); if (logic_cc) { gen_shift_T1_T0_cc[shiftop](); @@ -385,10 +388,14 @@ static void disas_arm_insn(DisasContext *s) case 0x00: gen_op_andl_T0_T1(); gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); break; case 0x01: gen_op_xorl_T0_T1(); gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); break; case 0x02: if (set_cc) @@ -435,11 +442,13 @@ static void disas_arm_insn(DisasContext *s) case 0x08: if (set_cc) { gen_op_andl_T0_T1(); + gen_op_logic_T0_cc(); } break; case 0x09: if (set_cc) { gen_op_xorl_T0_T1(); + gen_op_logic_T0_cc(); } break; case 0x0a: @@ -455,22 +464,28 @@ static void disas_arm_insn(DisasContext *s) case 0x0c: gen_op_orl_T0_T1(); gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); break; case 0x0d: gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); break; case 0x0e: gen_op_bicl_T0_T1(); gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); break; default: case 0x0f: gen_op_notl_T1(); gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); break; } - if (logic_cc) - gen_op_logic_cc(); } else { /* other instructions */ op1 = (insn >> 24) & 0xf; @@ -494,7 +509,7 @@ static void disas_arm_insn(DisasContext *s) gen_op_addl_T0_T1(); } if (insn & (1 << 20)) - gen_op_logic_cc(); + gen_op_logic_T0_cc(); gen_movl_reg_T0(s, rd); } else { /* 64 bit mul */ @@ -551,10 +566,12 @@ static void disas_arm_insn(DisasContext *s) /* store */ gen_op_stw_T0_T1(); } - if (!(insn & (1 << 24))) + if (!(insn & (1 << 24))) { gen_add_datah_offset(s, insn); - if (insn & (1 << 21)) gen_movl_reg_T1(s, rn); + } else if (insn & (1 << 21)) { + gen_movl_reg_T1(s, rn); + } } break; case 0x4: @@ -582,40 +599,94 @@ static void disas_arm_insn(DisasContext *s) else gen_op_stl_T0_T1(); } - if (!(insn & (1 << 24))) + if (!(insn & (1 << 24))) { gen_add_data_offset(s, insn); - if (insn & (1 << 21)) gen_movl_reg_T1(s, rn); + } else if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); { + } break; case 0x08: case 0x09: - /* load/store multiple words */ - if (insn & (1 << 22)) - goto illegal_op; /* only usable in supervisor mode */ - rn = (insn >> 16) & 0xf; - gen_movl_T1_reg(s, rn); - val = 4; - if (!(insn & (1 << 23))) - val = -val; - for(i=0;i<16;i++) { - if (insn & (1 << i)) { - if (insn & (1 << 24)) - gen_op_addl_T1_im(val); - if (insn & (1 << 20)) { - /* load */ - gen_op_ldl_T0_T1(); - gen_movl_reg_T0(s, i); + { + int j, n; + /* load/store multiple words */ + /* XXX: store correct base if write back */ + if (insn & (1 << 22)) + goto illegal_op; /* only usable in supervisor mode */ + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + + /* compute total size */ + n = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) + n++; + } + /* XXX: test invalid n == 0 case ? */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + gen_op_addl_T1_im(4); } else { - /* store */ - gen_movl_T0_reg(s, i); - gen_op_stl_T0_T1(); + /* post increment */ + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + gen_op_addl_T1_im(-(n * 4)); + } else { + /* post decrement */ + if (n != 1) + gen_op_addl_T1_im(-((n - 1) * 4)); + } + } + j = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) { + if (insn & (1 << 20)) { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, i); + } else { + /* store */ + if (i == 15) { + /* special case: r15 = PC + 12 */ + val = (long)s->pc + 8; + gen_op_movl_TN_im[0](val); + } else { + gen_movl_T0_reg(s, i); + } + gen_op_stl_T0_T1(); + } + j++; + /* no need to add after the last transfer */ + if (j != n) + gen_op_addl_T1_im(4); } - if (!(insn & (1 << 24))) - gen_op_addl_T1_im(val); + } + if (insn & (1 << 21)) { + /* write back */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + } else { + /* post increment */ + gen_op_addl_T1_im(4); + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + if (n != 1) + gen_op_addl_T1_im(-((n - 1) * 4)); + } else { + /* post decrement */ + gen_op_addl_T1_im(-(n * 4)); + } + } + gen_movl_reg_T1(s, rn); } } - if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); break; case 0xa: case 0xb: @@ -641,6 +712,66 @@ static void disas_arm_insn(DisasContext *s) gen_op_swi(); s->is_jmp = DISAS_JUMP; break; + case 0xc: + case 0xd: + rd = (insn >> 12) & 0x7; + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + val = (insn) & 0xff; + if (!(insn & (1 << 23))) + val = -val; + switch((insn >> 8) & 0xf) { + case 0x1: + /* load/store */ + if ((insn & (1 << 24))) + gen_op_addl_T1_im(val); + /* XXX: do it */ + if (!(insn & (1 << 24))) + gen_op_addl_T1_im(val); + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + break; + case 0x2: + { + int n, i; + /* load store multiple */ + if ((insn & (1 << 24))) + gen_op_addl_T1_im(val); + switch(insn & 0x00408000) { + case 0x00008000: n = 1; break; + case 0x00400000: n = 2; break; + case 0x00408000: n = 3; break; + default: n = 4; break; + } + for(i = 0;i < n; i++) { + /* XXX: do it */ + } + if (!(insn & (1 << 24))) + gen_op_addl_T1_im(val); + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + } + break; + default: + goto illegal_op; + } + break; + case 0x0e: + /* float ops */ + /* XXX: do it */ + switch((insn >> 20) & 0xf) { + case 0x2: /* wfs */ + break; + case 0x3: /* rfs */ + break; + case 0x4: /* wfc */ + break; + case 0x5: /* rfc */ + break; + default: + goto illegal_op; + } + break; default: illegal_op: gen_op_movl_T0_im((long)s->pc - 4); @@ -688,15 +819,19 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc disas_arm_insn(dc); } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); - /* we must store the eflags state if it is not already done */ - if (dc->is_jmp != DISAS_TB_JUMP && - dc->is_jmp != DISAS_JUMP) { - gen_op_movl_T0_im((long)dc->pc - 4); - gen_op_movl_reg_TN[0][15](); - } - if (dc->is_jmp != DISAS_TB_JUMP) { + switch(dc->is_jmp) { + case DISAS_JUMP_NEXT: + case DISAS_NEXT: + gen_op_jmp((long)dc->tb, (long)dc->pc); + break; + default: + case DISAS_JUMP: /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; } *gen_opc_ptr = INDEX_op_end; @@ -756,5 +891,10 @@ void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) else fprintf(f, " "); } - fprintf(f, "CPSR=%08x", env->cpsr); + fprintf(f, "PSR=%08x %c%c%c%c\n", + env->cpsr, + env->cpsr & (1 << 31) ? 'N' : '-', + env->cpsr & (1 << 30) ? 'Z' : '-', + env->cpsr & (1 << 29) ? 'C' : '-', + env->cpsr & (1 << 28) ? 'V' : '-'); } -- cgit v1.2.3 From 6fb883e8e3ce8fc661e4bb9f068565b4ccd97abf Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jul 2003 17:12:39 +0000 Subject: ARM fix: mmap git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@315 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cd3fdf553..932fe4658 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1791,8 +1791,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; case TARGET_NR_readdir: goto unimplemented; -#ifdef TARGET_I386 case TARGET_NR_mmap: +#if defined(TARGET_I386) || defined(TARGET_ARM) { uint32_t v1, v2, v3, v4, v5, v6, *vptr; vptr = (uint32_t *)arg1; @@ -1806,13 +1806,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, target_to_host_bitmask(v4, mmap_flags_tbl), v5, v6)); } - break; -#endif -#ifdef TARGET_I386 - case TARGET_NR_mmap2: #else - case TARGET_NR_mmap: + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6)); #endif + break; + case TARGET_NR_mmap2: ret = get_errno(target_mmap(arg1, arg2, arg3, target_to_host_bitmask(arg4, mmap_flags_tbl), arg5, -- cgit v1.2.3 From a1516e92b6ed887ef27f3a33a27a9acd772a5de4 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jul 2003 17:13:37 +0000 Subject: ARM init fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@316 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 94059917c..9df46c112 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -74,7 +74,8 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->ARM_sp = infop->start_stack; regs->ARM_r2 = tswapl(stack[2]); /* envp */ regs->ARM_r1 = tswapl(stack[1]); /* argv */ - regs->ARM_r0 = tswapl(stack[0]); /* argc */ + /* XXX: it seems that r0 is zeroed after ! */ + // regs->ARM_r0 = tswapl(stack[0]); /* argc */ } #define USE_ELF_CORE_DUMP @@ -490,7 +491,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, * Force 16 byte alignment here for generality. */ sp = (unsigned int *) (~15UL & (unsigned long) p); - sp -= exec ? DLINFO_ITEMS*2 : 2; + sp -= DLINFO_ITEMS*2; dlinfo = sp; sp -= envc+1; envp = sp; @@ -505,21 +506,20 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, put_user (tswapl(id), dlinfo++); \ put_user (tswapl(val), dlinfo++) - if (exec) { /* Put this here for an ELF program interpreter */ - NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); - NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); - NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); - NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); - NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); - NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT (AT_UID, (target_ulong) getuid()); - NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid()); - NEW_AUX_ENT (AT_GID, (target_ulong) getgid()); - NEW_AUX_ENT (AT_EGID, (target_ulong) getegid()); - } + NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); + NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); + NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); + NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); + NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); + NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT (AT_UID, (target_ulong) getuid()); + NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid()); + NEW_AUX_ENT (AT_GID, (target_ulong) getgid()); + NEW_AUX_ENT (AT_EGID, (target_ulong) getegid()); NEW_AUX_ENT (AT_NULL, 0); #undef NEW_AUX_ENT + put_user(tswapl(argc),--sp); info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); while (argc-->0) { @@ -1087,7 +1087,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r create_elf_tables((char *)bprm->p, bprm->argc, bprm->envc, - (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), + &elf_ex, load_addr, load_bias, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1), -- cgit v1.2.3 From 1b21b62ab4b68da17b18f630e33ff7e1d5e3d3a2 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jul 2003 17:16:27 +0000 Subject: ARM fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@317 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index ddbeb2ce9..ef33aaa3e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -225,7 +225,9 @@ int cpu_exec(CPUState *env1) cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_ARM) + env->cpsr = compute_cpsr(); cpu_arm_dump_state(env, logfile, 0); + env->cpsr &= ~0xf0000000; #else #error unsupported target CPU #endif @@ -306,7 +308,7 @@ int cpu_exec(CPUState *env1) T0 = tmp_T0; #endif /* see if we can patch the calling TB. XXX: remove TF test */ - if (T0 != 0 + if (T0 != 0 #if defined(TARGET_I386) && !(env->eflags & TF_MASK) #endif @@ -372,12 +374,7 @@ int cpu_exec(CPUState *env1) EDI = saved_EDI; #endif #elif defined(TARGET_ARM) - { - int ZF; - ZF = (env->NZF == 0); - env->cpsr = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); - } + env->cpsr = compute_cpsr(); #else #error unsupported target CPU #endif -- cgit v1.2.3 From 43fff2384e7027f1c870520dbb111e0b2df8b4bb Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jul 2003 19:31:39 +0000 Subject: ARM signal support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@318 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 5 +- linux-user/signal.c | 483 +++++++++++++++++++++++++++++++++++++++++++++++----- syscall-arm.h | 1 + 3 files changed, 449 insertions(+), 40 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 56cba6189..2f341d92c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -246,8 +246,6 @@ void cpu_loop(CPUX86State *env) #ifdef TARGET_ARM -#define ARM_SYSCALL_BASE 0x900000 - void cpu_loop(CPUARMState *env) { int trapnr; @@ -285,6 +283,9 @@ void cpu_loop(CPUARMState *env) } } break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; default: error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", diff --git a/linux-user/signal.c b/linux-user/signal.c index 74aaeea68..18cf5e242 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -364,6 +364,80 @@ int do_sigaction(int sig, const struct target_sigaction *act, return 0; } +#define __put_user(x,ptr)\ +({\ + int size = sizeof(*ptr);\ + switch(size) {\ + case 1:\ + stb(ptr, (typeof(*ptr))(x));\ + break;\ + case 2:\ + stw(ptr, (typeof(*ptr))(x));\ + break;\ + case 4:\ + stl(ptr, (typeof(*ptr))(x));\ + break;\ + case 8:\ + stq(ptr, (typeof(*ptr))(x));\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) + +#define __get_user(x, ptr) \ +({\ + int size = sizeof(*ptr);\ + switch(size) {\ + case 1:\ + x = (typeof(*ptr))ldub(ptr);\ + break;\ + case 2:\ + x = (typeof(*ptr))lduw(ptr);\ + break;\ + case 4:\ + x = (typeof(*ptr))ldl(ptr);\ + break;\ + case 8:\ + x = (typeof(*ptr))ldq(ptr);\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) + + +#define __copy_to_user(dst, src, size)\ +({\ + memcpy(dst, src, size);\ + 0;\ +}) + +#define __copy_from_user(dst, src, size)\ +({\ + memcpy(dst, src, size);\ + 0;\ +}) + +#define __clear_user(dst, size)\ +({\ + memset(dst, 0, size);\ + 0;\ +}) + +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif + +static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, + const target_siginfo_t *info) +{ + tswap_siginfo(tinfo, info); + return 0; +} + #ifdef TARGET_I386 /* from the Linux kernel */ @@ -472,44 +546,6 @@ struct rt_sigframe * Set up a signal frame. */ -#define __put_user(x,ptr)\ -({\ - int size = sizeof(*ptr);\ - switch(size) {\ - case 1:\ - stb(ptr, (typeof(*ptr))(x));\ - break;\ - case 2:\ - stw(ptr, (typeof(*ptr))(x));\ - break;\ - case 4:\ - stl(ptr, (typeof(*ptr))(x));\ - break;\ - case 8:\ - stq(ptr, (typeof(*ptr))(x));\ - break;\ - default:\ - abort();\ - }\ - 0;\ -}) - -#define get_user(val, ptr) (typeof(*ptr))(*(ptr)) - - -#define __copy_to_user(dst, src, size)\ -({\ - memcpy(dst, src, size);\ - 0;\ -}) - -static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, - const target_siginfo_t *info) -{ - tswap_siginfo(tinfo, info); - return 0; -} - /* XXX: save x87 state */ static int setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, @@ -825,6 +861,377 @@ badframe: return 0; } +#elif defined(TARGET_ARM) + +struct target_sigcontext { + target_ulong trap_no; + target_ulong error_code; + target_ulong oldmask; + target_ulong arm_r0; + target_ulong arm_r1; + target_ulong arm_r2; + target_ulong arm_r3; + target_ulong arm_r4; + target_ulong arm_r5; + target_ulong arm_r6; + target_ulong arm_r7; + target_ulong arm_r8; + target_ulong arm_r9; + target_ulong arm_r10; + target_ulong arm_fp; + target_ulong arm_ip; + target_ulong arm_sp; + target_ulong arm_lr; + target_ulong arm_pc; + target_ulong arm_cpsr; + target_ulong fault_address; +}; + +typedef struct target_sigaltstack { + target_ulong ss_sp; + int ss_flags; + target_ulong ss_size; +} target_stack_t; + +struct target_ucontext { + target_ulong uc_flags; + target_ulong uc_link; + target_stack_t uc_stack; + struct target_sigcontext uc_mcontext; + target_sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +struct sigframe +{ + struct target_sigcontext sc; + target_ulong extramask[TARGET_NSIG_WORDS-1]; + target_ulong retcode; +}; + +struct rt_sigframe +{ + struct target_siginfo *pinfo; + void *puc; + struct target_siginfo info; + struct target_ucontext uc; + target_ulong retcode; +}; + +#define TARGET_CONFIG_CPU_32 1 + +/* + * For ARM syscalls, we encode the syscall number into the instruction. + */ +#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE)) +#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE)) + +/* + * For Thumb syscalls, we pass the syscall number via r7. We therefore + * need two 16-bit instructions. + */ +#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn)) +#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn)) + +static const target_ulong retcodes[4] = { + SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, + SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN +}; + + +#define __put_user_error(x,p,e) __put_user(x, p) +#define __get_user_error(x,p,e) __get_user(x, p) + +static inline int valid_user_regs(CPUState *regs) +{ + return 1; +} + +static int +setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ + CPUState *env, unsigned long mask) +{ + int err = 0; + + __put_user_error(env->regs[0], &sc->arm_r0, err); + __put_user_error(env->regs[1], &sc->arm_r1, err); + __put_user_error(env->regs[2], &sc->arm_r2, err); + __put_user_error(env->regs[3], &sc->arm_r3, err); + __put_user_error(env->regs[4], &sc->arm_r4, err); + __put_user_error(env->regs[5], &sc->arm_r5, err); + __put_user_error(env->regs[6], &sc->arm_r6, err); + __put_user_error(env->regs[7], &sc->arm_r7, err); + __put_user_error(env->regs[8], &sc->arm_r8, err); + __put_user_error(env->regs[9], &sc->arm_r9, err); + __put_user_error(env->regs[10], &sc->arm_r10, err); + __put_user_error(env->regs[11], &sc->arm_fp, err); + __put_user_error(env->regs[12], &sc->arm_ip, err); + __put_user_error(env->regs[13], &sc->arm_sp, err); + __put_user_error(env->regs[14], &sc->arm_lr, err); + __put_user_error(env->regs[15], &sc->arm_pc, err); +#ifdef TARGET_CONFIG_CPU_32 + __put_user_error(env->cpsr, &sc->arm_cpsr, err); +#endif + + __put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err); + __put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err); + __put_user_error(/* current->thread.address */ 0, &sc->fault_address, err); + __put_user_error(mask, &sc->oldmask, err); + + return err; +} + +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) +{ + unsigned long sp = regs->regs[13]; + +#if 0 + /* + * This is the X/Open sanctioned signal stack switching. + */ + if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; +#endif + /* + * ATPCS B01 mandates 8-byte alignment + */ + return (void *)((sp - framesize) & ~7); +} + +static int +setup_return(CPUState *env, struct emulated_sigaction *ka, + target_ulong *rc, void *frame, int usig) +{ + target_ulong handler = (target_ulong)ka->sa._sa_handler; + target_ulong retcode; + int thumb = 0; +#if defined(TARGET_CONFIG_CPU_32) + target_ulong cpsr = env->cpsr; + +#if 0 + /* + * Maybe we need to deliver a 32-bit signal to a 26-bit task. + */ + if (ka->sa.sa_flags & SA_THIRTYTWO) + cpsr = (cpsr & ~MODE_MASK) | USR_MODE; + +#ifdef CONFIG_ARM_THUMB + if (elf_hwcap & HWCAP_THUMB) { + /* + * The LSB of the handler determines if we're going to + * be using THUMB or ARM mode for this signal handler. + */ + thumb = handler & 1; + + if (thumb) + cpsr |= T_BIT; + else + cpsr &= ~T_BIT; + } +#endif +#endif +#endif /* TARGET_CONFIG_CPU_32 */ + + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { + retcode = (target_ulong)ka->sa.sa_restorer; + } else { + unsigned int idx = thumb; + + if (ka->sa.sa_flags & TARGET_SA_SIGINFO) + idx += 2; + + if (__put_user(retcodes[idx], rc)) + return 1; +#if 0 + flush_icache_range((target_ulong)rc, + (target_ulong)(rc + 1)); +#endif + retcode = ((target_ulong)rc) + thumb; + } + + env->regs[0] = usig; + env->regs[13] = (target_ulong)frame; + env->regs[14] = retcode; + env->regs[15] = handler & (thumb ? ~1 : ~3); + +#ifdef TARGET_CONFIG_CPU_32 + env->cpsr = cpsr; +#endif + + return 0; +} + +static void setup_frame(int usig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *regs) +{ + struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); + int err = 0; + + err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); + + if (TARGET_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + + if (err == 0) + err = setup_return(regs, ka, &frame->retcode, frame, usig); + // return err; +} + +static void setup_rt_frame(int usig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame)); + int err = 0; + +#if 0 + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + return 1; +#endif + __put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err); + __put_user_error(&frame->uc, (target_ulong *)&frame->puc, err); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Clear all the bits of the ucontext we don't use. */ + err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ + env, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + if (err == 0) + err = setup_return(env, ka, &frame->retcode, frame, usig); + + if (err == 0) { + /* + * For realtime signals we must also set the second and third + * arguments for the signal handler. + * -- Peter Maydell 2000-12-06 + */ + env->regs[1] = (target_ulong)frame->pinfo; + env->regs[2] = (target_ulong)frame->puc; + } + + // return err; +} + +static int +restore_sigcontext(CPUState *env, struct target_sigcontext *sc) +{ + int err = 0; + + __get_user_error(env->regs[0], &sc->arm_r0, err); + __get_user_error(env->regs[1], &sc->arm_r1, err); + __get_user_error(env->regs[2], &sc->arm_r2, err); + __get_user_error(env->regs[3], &sc->arm_r3, err); + __get_user_error(env->regs[4], &sc->arm_r4, err); + __get_user_error(env->regs[5], &sc->arm_r5, err); + __get_user_error(env->regs[6], &sc->arm_r6, err); + __get_user_error(env->regs[7], &sc->arm_r7, err); + __get_user_error(env->regs[8], &sc->arm_r8, err); + __get_user_error(env->regs[9], &sc->arm_r9, err); + __get_user_error(env->regs[10], &sc->arm_r10, err); + __get_user_error(env->regs[11], &sc->arm_fp, err); + __get_user_error(env->regs[12], &sc->arm_ip, err); + __get_user_error(env->regs[13], &sc->arm_sp, err); + __get_user_error(env->regs[14], &sc->arm_lr, err); + __get_user_error(env->regs[15], &sc->arm_pc, err); +#ifdef TARGET_CONFIG_CPU_32 + __get_user_error(env->cpsr, &sc->arm_cpsr, err); +#endif + + err |= !valid_user_regs(env); + + return err; +} + +long do_sigreturn(CPUState *env) +{ + struct sigframe *frame; + target_sigset_t set; + sigset_t host_set; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (env->regs[13] & 7) + goto badframe; + + frame = (struct sigframe *)env->regs[13]; + +#if 0 + if (verify_area(VERIFY_READ, frame, sizeof (*frame))) + goto badframe; +#endif + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (TARGET_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + target_to_host_sigset(&host_set, &set); + sigprocmask(SIG_SETMASK, &host_set, NULL); + + if (restore_sigcontext(env, &frame->sc)) + goto badframe; + +#if 0 + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); +#endif + return env->regs[0]; + +badframe: + force_sig(SIGSEGV /* , current */); + return 0; +} + +long do_rt_sigreturn(CPUState *env) +{ + struct rt_sigframe *frame; + target_sigset_t set; + sigset_t host_set; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (env->regs[13] & 7) + goto badframe; + + frame = (struct rt_sigframe *)env->regs[13]; + +#if 0 + if (verify_area(VERIFY_READ, frame, sizeof (*frame))) + goto badframe; +#endif + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + target_to_host_sigset(&host_set, &set); + sigprocmask(SIG_SETMASK, &host_set, NULL); + + if (restore_sigcontext(env, &frame->uc.uc_mcontext)) + goto badframe; + +#if 0 + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); +#endif + return env->regs[0]; + +badframe: + force_sig(SIGSEGV /* , current */); + return 0; +} + #else static void setup_frame(int sig, struct emulated_sigaction *ka, diff --git a/syscall-arm.h b/syscall-arm.h index e5977106b..34153c998 100644 --- a/syscall-arm.h +++ b/syscall-arm.h @@ -25,3 +25,4 @@ struct target_pt_regs { #define ARM_r0 uregs[0] #define ARM_ORIG_r0 uregs[17] +#define ARM_SYSCALL_BASE 0x900000 -- cgit v1.2.3 From f8c8799840d3250723de8247a1bb8c70a336f0f5 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jul 2003 19:41:41 +0000 Subject: added return for ARM case (may be incorrect - need checking) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@319 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.h | 1 + 1 file changed, 1 insertion(+) diff --git a/exec.h b/exec.h index 1f46e4a46..024129292 100644 --- a/exec.h +++ b/exec.h @@ -225,6 +225,7 @@ label ## n:\ T0 = (long)(tbparam) + (n);\ EIP = eip;\ dummy_label ## n:\ + return;\ } while (0) #endif -- cgit v1.2.3 From 7739f36e38fa9f02a6079853e797aea1b647e968 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Jul 2003 14:49:22 +0000 Subject: fixed EIP exception bug in case of nop operations (kernel 2.5.74 copy_from_user() bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@320 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-arm.c | 4 ++-- translate-i386.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/translate-arm.c b/translate-arm.c index 6020e772d..8b249ba15 100644 --- a/translate-arm.c +++ b/translate-arm.c @@ -812,9 +812,9 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc lj++; while (lj < j) gen_opc_instr_start[lj++] = 0; - gen_opc_pc[lj] = (uint32_t)dc->pc; - gen_opc_instr_start[lj] = 1; } + gen_opc_pc[lj] = (uint32_t)dc->pc; + gen_opc_instr_start[lj] = 1; } disas_arm_insn(dc); } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && diff --git a/translate-i386.c b/translate-i386.c index fdbd5ee92..a8ee672b2 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -4122,10 +4122,10 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc lj++; while (lj < j) gen_opc_instr_start[lj++] = 0; - gen_opc_pc[lj] = (uint32_t)pc_ptr; - gen_opc_cc_op[lj] = dc->cc_op; - gen_opc_instr_start[lj] = 1; } + gen_opc_pc[lj] = (uint32_t)pc_ptr; + gen_opc_cc_op[lj] = dc->cc_op; + gen_opc_instr_start[lj] = 1; } ret = disas_insn(dc, pc_ptr); if (ret == -1) { -- cgit v1.2.3 From ede28208d86096cd80699d8105f8ee2e909c4268 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Jul 2003 14:49:58 +0000 Subject: added nop test for exception git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@321 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index cb35f2125..30923238a 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1250,6 +1250,8 @@ void test_exceptions(void) printf("PF exception:\n"); if (setjmp(jmp_env) == 0) { val = 1; + /* we add a nop to test a weird PC retrieval case */ + asm volatile ("nop"); /* now store in an invalid address */ *(char *)0x1234 = 1; } -- cgit v1.2.3 From 9621339dcacc148a86d312d1e71623202c9df7db Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Jul 2003 15:17:41 +0000 Subject: changed basic block exit generation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@322 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 26 ++++++++++++++++++++++++++ dyngen.c | 36 ++++-------------------------------- dyngen.h | 6 +----- exec.h | 2 +- op-arm.c | 5 +++++ op-i386.c | 5 +++++ translate-arm.c | 1 + translate-i386.c | 1 + 8 files changed, 44 insertions(+), 38 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index f588ef0f3..e5b5e5fde 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -125,6 +125,8 @@ extern int printf(const char *, ...); #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 */ @@ -153,3 +155,27 @@ extern int __op_param1, __op_param2, __op_param3; #endif extern int __op_jmp0, __op_jmp1; + +#ifdef __i386__ +#define EXIT_TB() asm volatile ("ret") +#endif +#ifdef __powerpc__ +#define EXIT_TB() asm volatile ("blr") +#endif +#ifdef __s390__ +#define EXIT_TB() asm volatile ("br %r14") +#endif +#ifdef __alpha__ +#define EXIT_TB() asm volatile ("ret") +#endif +#ifdef __ia64__ +#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;") +#endif +#ifdef __sparc__ +#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" + "nop") +#endif +#ifdef __arm__ +#define EXIT_TB() asm volatile ("b exec_loop") +#endif + diff --git a/dyngen.c b/dyngen.c index c6c373bd1..762ee9d56 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1306,38 +1306,10 @@ fprintf(outfile, " the_end:\n" ); -/* generate epilogue */ - switch(ELF_ARCH) { - case EM_386: - fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n"); - break; - case EM_PPC: - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n"); - break; - case EM_S390: - fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n"); - break; - case EM_ALPHA: - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x6bfa8001; /* ret */\n"); - break; - case EM_IA_64: - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n"); - break; - case EM_SPARC: - case EM_SPARC32PLUS: - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n"); - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x01000000; /* nop */\n"); - break; - case EM_SPARCV9: - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n"); - fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n"); - break; - case EM_ARM: - fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n"); - break; - default: - error("unknown ELF architecture"); - } +/* generate some code patching */ +#ifdef HOST_ARM +fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n"); +#endif /* flush instruction cache */ fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n"); diff --git a/dyngen.h b/dyngen.h index 645ce4197..47fe263e4 100644 --- a/dyngen.h +++ b/dyngen.h @@ -152,11 +152,7 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, data_size = (uint8_t *)data_end - (uint8_t *)data_start; - if (!gen_jmp) { - /* b exec_loop */ - arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, (long)(&exec_loop)); - gen_code_ptr += 4; - } else { + if (gen_jmp) { /* generate branch to skip the data */ if (data_size == 0) return gen_code_ptr; diff --git a/exec.h b/exec.h index 024129292..5ae28ef9b 100644 --- a/exec.h +++ b/exec.h @@ -225,7 +225,7 @@ label ## n:\ T0 = (long)(tbparam) + (n);\ EIP = eip;\ dummy_label ## n:\ - return;\ + EXIT_TB();\ } while (0) #endif diff --git a/op-arm.c b/op-arm.c index 8e5cce0e9..fcc4ddc3d 100644 --- a/op-arm.c +++ b/op-arm.c @@ -338,6 +338,11 @@ void OPPROTO op_jmp(void) JUMP_TB(PARAM1, 1, PARAM2); } +void OPPROTO op_exit_tb(void) +{ + EXIT_TB(); +} + void OPPROTO op_movl_T0_psr(void) { T0 = compute_cpsr(); diff --git a/op-i386.c b/op-i386.c index 84b75d07b..be8b5a113 100644 --- a/op-i386.c +++ b/op-i386.c @@ -566,6 +566,11 @@ void OPPROTO op_movl_T0_0(void) T0 = 0; } +void OPPROTO op_exit_tb(void) +{ + EXIT_TB(); +} + /* multiple size ops */ #define ldul ldl diff --git a/translate-arm.c b/translate-arm.c index 8b249ba15..c9759f81b 100644 --- a/translate-arm.c +++ b/translate-arm.c @@ -828,6 +828,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc case DISAS_JUMP: /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); + gen_op_exit_tb(); break; case DISAS_TB_JUMP: /* nothing more to generate */ diff --git a/translate-i386.c b/translate-i386.c index a8ee672b2..871d99741 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -4163,6 +4163,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc if (dc->is_jmp != DISAS_TB_JUMP) { /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); + gen_op_exit_tb(); } *gen_opc_ptr = INDEX_op_end; /* we don't forget to fill the last values */ -- cgit v1.2.3 From 070893f4252a9f3bb9aaf919780a104eb020605e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 17:27:19 +0000 Subject: RedHat 9 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@323 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 30923238a..241186956 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -855,7 +856,6 @@ void test_segs(void) #endif /* do some tests with fs or gs */ asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); - asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2))); seg_data1[1] = 0xaa; seg_data2[1] = 0x55; @@ -863,7 +863,12 @@ void test_segs(void) asm volatile ("fs movzbl 0x1, %0" : "=r" (res)); printf("FS[1] = %02x\n", res); - asm volatile ("gs movzbl 0x1, %0" : "=r" (res)); + asm volatile ("pushl %%gs\n" + "movl %1, %%gs\n" + "gs movzbl 0x1, %0\n" + "popl %%gs\n" + : "=r" (res) + : "r" (MK_SEL(2))); printf("GS[1] = %02x\n", res); /* tests with ds/ss (implicit segment case) */ -- cgit v1.2.3 From d44b29c21e28ca2045c19122d69f7565544dd58b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 17:29:55 +0000 Subject: address printing fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@324 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/disas.c b/disas.c index dc1957b96..8a44e9147 100644 --- a/disas.c +++ b/disas.c @@ -42,7 +42,7 @@ perror_memory (status, memaddr, info) /* Actually, address between memaddr and memaddr + len was out of bounds. */ (*info->fprintf_func) (info->stream, - "Address 0x%x is out of bounds.\n", memaddr); + "Address 0x%llx is out of bounds.\n", memaddr); } /* This could be in a separate file, to save miniscule amounts of space @@ -57,7 +57,7 @@ generic_print_address (addr, info) bfd_vma addr; struct disassemble_info *info; { - (*info->fprintf_func) (info->stream, "0x%x", addr); + (*info->fprintf_func) (info->stream, "0x%llx", addr); } /* Just return the given address. */ -- cgit v1.2.3 From a96fc003bd347fc85d0eff0e9bf5839e73385c7b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 17:30:15 +0000 Subject: sparc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@325 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 ++- dyngen-exec.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1db299e8c..ab8e377f5 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,8 @@ CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 LDFLAGS+=-m32 OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat -LDFLAGS+=-Wl,-T,sparc.ld +# -static is used to avoid g1/g3 usage by the dynamic linker +LDFLAGS+=-Wl,-T,sparc.ld -static endif ifeq ($(ARCH),sparc64) diff --git a/dyngen-exec.h b/dyngen-exec.h index e5b5e5fde..46f4042f6 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -172,7 +172,7 @@ extern int __op_jmp0, __op_jmp1; #define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;") #endif #ifdef __sparc__ -#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" +#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \ "nop") #endif #ifdef __arm__ -- cgit v1.2.3 From 91cf4d88fbb174ba5a4ade9c4479f3b0775a5599 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 17:31:01 +0000 Subject: gcc 3.2.2 bug workaround (RedHat 9 fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@326 c046a42c-6fe2-441c-8c8c-71466251a162 --- ops_template_mem.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ops_template_mem.h b/ops_template_mem.h index f1209d2aa..eacaabba5 100644 --- a/ops_template_mem.h +++ b/ops_template_mem.h @@ -44,6 +44,9 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); #ifdef MEM_WRITE glue(st, SUFFIX)((uint8_t *)A0, T0); +#else + /* gcc 3.2 workaround. This is really a bug in gcc. */ + asm volatile("" : : "r" (T0)); #endif CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | @@ -63,6 +66,9 @@ void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); #ifdef MEM_WRITE glue(st, SUFFIX)((uint8_t *)A0, T0); +#else + /* gcc 3.2 workaround. This is really a bug in gcc. */ + asm volatile("" : : "r" (T0)); #endif CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | -- cgit v1.2.3 From c596ed17139b50a45a75a5491797d3b920385566 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 17:32:31 +0000 Subject: times() fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@327 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 25 +++++++++++++++++++++---- linux-user/syscall_defs.h | 8 ++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 932fe4658..1204a62c4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -210,6 +210,21 @@ static inline void host_to_target_fds(target_long *target_fds, #endif } +#if defined(__alpha__) +#define HOST_HZ 1024 +#else +#define HOST_HZ 100 +#endif + +static inline long host_to_target_clock_t(long ticks) +{ +#if HOST_HZ == TARGET_HZ + return ticks; +#else + return ((int64_t)ticks * TARGET_HZ) / HOST_HZ; +#endif +} + static inline void host_to_target_rusage(struct target_rusage *target_rusage, const struct rusage *rusage) { @@ -1423,11 +1438,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct tms tms; ret = get_errno(times(&tms)); if (tmsp) { - tmsp->tms_utime = tswapl(tms.tms_utime); - tmsp->tms_stime = tswapl(tms.tms_stime); - tmsp->tms_cutime = tswapl(tms.tms_cutime); - tmsp->tms_cstime = tswapl(tms.tms_cstime); + tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime)); + tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime)); + tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime)); + tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime)); } + if (!is_error(ret)) + ret = host_to_target_clock_t(ret); } break; case TARGET_NR_prof: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 5caf2d855..a4613bdf7 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -383,6 +383,8 @@ struct target_itimerval { typedef target_long target_clock_t; +#define TARGET_HZ 100 + struct target_tms { target_clock_t tms_utime; target_clock_t tms_stime; @@ -539,8 +541,8 @@ static inline void target_siginitset(target_sigset_t *d, target_ulong set) d->sig[i] = 0; } -void host_to_target_sigset(target_sigset_t *d, sigset_t *s); -void target_to_host_sigset(sigset_t *d, target_sigset_t *s); +void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); +void target_to_host_sigset(sigset_t *d, const target_sigset_t *s); void host_to_target_old_sigset(target_ulong *old_sigset, const sigset_t *sigset); void target_to_host_old_sigset(sigset_t *sigset, @@ -590,6 +592,8 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SIGPROF 27 #define TARGET_SIGWINCH 28 #define TARGET_SIGIO 29 +#define TARGET_SIGPWR 30 +#define TARGET_SIGSYS 31 #define TARGET_SIGRTMIN 32 #define TARGET_SIG_BLOCK 0 /* for blocking signals */ -- cgit v1.2.3 From 9e5f5284b3b452ace0097c5171d369be46847e74 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 17:33:54 +0000 Subject: convert signal numbers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@328 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 11 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 18cf5e242..46abf53d8 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -60,44 +60,122 @@ static int signal_pending; /* non zero if a signal may be pending */ static void host_signal_handler(int host_signum, siginfo_t *info, void *puc); -/* XXX: do it properly */ +static uint8_t host_to_target_signal_table[65] = { + [SIGHUP] = TARGET_SIGHUP, + [SIGINT] = TARGET_SIGINT, + [SIGQUIT] = TARGET_SIGQUIT, + [SIGILL] = TARGET_SIGILL, + [SIGTRAP] = TARGET_SIGTRAP, + [SIGABRT] = TARGET_SIGABRT, + [SIGIOT] = TARGET_SIGIOT, + [SIGBUS] = TARGET_SIGBUS, + [SIGFPE] = TARGET_SIGFPE, + [SIGKILL] = TARGET_SIGKILL, + [SIGUSR1] = TARGET_SIGUSR1, + [SIGSEGV] = TARGET_SIGSEGV, + [SIGUSR2] = TARGET_SIGUSR2, + [SIGPIPE] = TARGET_SIGPIPE, + [SIGALRM] = TARGET_SIGALRM, + [SIGTERM] = TARGET_SIGTERM, +#ifdef SIGSTKFLT + [SIGSTKFLT] = TARGET_SIGSTKFLT, +#endif + [SIGCHLD] = TARGET_SIGCHLD, + [SIGCONT] = TARGET_SIGCONT, + [SIGSTOP] = TARGET_SIGSTOP, + [SIGTSTP] = TARGET_SIGTSTP, + [SIGTTIN] = TARGET_SIGTTIN, + [SIGTTOU] = TARGET_SIGTTOU, + [SIGURG] = TARGET_SIGURG, + [SIGXCPU] = TARGET_SIGXCPU, + [SIGXFSZ] = TARGET_SIGXFSZ, + [SIGVTALRM] = TARGET_SIGVTALRM, + [SIGPROF] = TARGET_SIGPROF, + [SIGWINCH] = TARGET_SIGWINCH, + [SIGIO] = TARGET_SIGIO, + [SIGPWR] = TARGET_SIGPWR, + [SIGSYS] = TARGET_SIGSYS, + /* next signals stay the same */ +}; +static uint8_t target_to_host_signal_table[65]; + static inline int host_to_target_signal(int sig) { - return sig; + return host_to_target_signal_table[sig]; } static inline int target_to_host_signal(int sig) { - return sig; + return target_to_host_signal_table[sig]; } -void host_to_target_sigset(target_sigset_t *d, sigset_t *s) +void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) { int i; - for(i = 0;i < TARGET_NSIG_WORDS; i++) { + unsigned long sigmask; + uint32_t target_sigmask; + + sigmask = ((unsigned long *)s)[0]; + target_sigmask = 0; + for(i = 0; i < 32; i++) { + if (sigmask & (1 << i)) + target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1); + } +#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 + d->sig[0] = tswapl(target_sigmask); + for(i = 1;i < TARGET_NSIG_WORDS; i++) { d->sig[i] = tswapl(((unsigned long *)s)[i]); } +#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 + d->sig[0] = tswapl(target_sigmask); + d->sig[1] = tswapl(sigmask >> 32); +#else +#error host_to_target_sigset +#endif } -void target_to_host_sigset(sigset_t *d, target_sigset_t *s) +void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) { int i; - for(i = 0;i < TARGET_NSIG_WORDS; i++) { + unsigned long sigmask; + target_ulong target_sigmask; + + target_sigmask = tswapl(s->sig[0]); + sigmask = 0; + for(i = 0; i < 32; i++) { + if (target_sigmask & (1 << i)) + sigmask |= 1 << (target_to_host_signal(i + 1) - 1); + } +#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 + ((unsigned long *)d)[0] = sigmask; + for(i = 1;i < TARGET_NSIG_WORDS; i++) { ((unsigned long *)d)[i] = tswapl(s->sig[i]); } +#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 + ((unsigned long *)d)[0] = sigmask | (tswapl(s->sig[1]) << 32); +#else +#error target_to_host_sigset +#endif /* TARGET_LONG_BITS */ } void host_to_target_old_sigset(target_ulong *old_sigset, const sigset_t *sigset) { - *old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff); + target_sigset_t d; + host_to_target_sigset(&d, sigset); + *old_sigset = d.sig[0]; } void target_to_host_old_sigset(sigset_t *sigset, const target_ulong *old_sigset) { - sigemptyset(sigset); - *(unsigned long *)sigset = tswapl(*old_sigset); + target_sigset_t d; + int i; + + d.sig[0] = *old_sigset; + for(i = 1;i < TARGET_NSIG_WORDS; i++) + d.sig[i] = 0; + target_to_host_sigset(sigset, &d); } /* siginfo conversion */ @@ -167,8 +245,18 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) void signal_init(void) { struct sigaction act; - int i; + int i, j; + /* generate signal conversion tables */ + for(i = 1; i <= 64; i++) { + if (host_to_target_signal_table[i] == 0) + host_to_target_signal_table[i] = i; + } + for(i = 1; i <= 64; i++) { + j = host_to_target_signal_table[i]; + target_to_host_signal_table[j] = i; + } + /* set all host signal handlers. ALL signals are blocked during the handlers to serialize them. */ sigfillset(&act.sa_mask); -- cgit v1.2.3 From 6e0374f6b5a1cb1600f9d25e9309bc550748128a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 17:34:37 +0000 Subject: debug print git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@329 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/translate.c b/translate.c index 72b4d24b7..68c76224a 100644 --- a/translate.c +++ b/translate.c @@ -182,13 +182,14 @@ int cpu_restore_state(TranslationBlock *tb, #ifdef DEBUG_DISAS if (loglevel) { int i; + fprintf(logfile, "RESTORE:\n"); for(i=0;i<=j; i++) { if (gen_opc_instr_start[i]) { - fprintf(logfile, "0x%04x: 0x%08x", i, gen_opc_pc[i]); + fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]); } } - fprintf(logfile, "j=0x%x eip=0x%lx cs_base=%lx\n", - j, gen_opc_pc[j] - tb->cs_base, tb->cs_base); + fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%lx cs_base=%lx\n", + searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base); } #endif env->eip = gen_opc_pc[j] - tb->cs_base; -- cgit v1.2.3 From 9d0fe224f4a1561abb0f4f46ad40eec7fa7787b9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 22:08:50 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@330 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 9 ++++++++- README | 1 + VERSION | 2 +- qemu-doc.texi | 6 +++--- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Changelog b/Changelog index 525f019e4..78c72a319 100644 --- a/Changelog +++ b/Changelog @@ -1,10 +1,17 @@ +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 + - accept User Mode Linux Copy On Write disk images - SMP kernels can at least be booted version 0.4.1: diff --git a/README b/README index 44a470c92..13dae1ff8 100644 --- a/README +++ b/README @@ -50,6 +50,7 @@ host gcc binutils glibc linux distribution x86 2.95.2 2.13.2 2.1.3 2.4.18 3.2 2.13.2 2.1.3 2.4.18 2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3 + 3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9 PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 Debian 3.0 diff --git a/VERSION b/VERSION index f7abe273d..70d5b25fa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.2 \ No newline at end of file +0.4.3 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index b3a13b9e1..0a3f237b8 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -480,9 +480,9 @@ disk image. QEMU stores the original raw disk image name and its modified time in the COW disk image so that chances of mistakes are reduced. -If raw disk image is not read-only, by pressing @key{C-a s} you can -flush the COW disk image back into the raw disk image, as in snapshot -mode. +If the raw disk image is not read-only, by pressing @key{C-a s} you +can flush the COW disk image back into the raw disk image, as in +snapshot mode. COW disk images can also be created without a corresponding raw disk image. It is useful to have a big initial virtual disk image without -- cgit v1.2.3 From d6b4936796b37f629879de69d847c5cdc4892157 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jul 2003 22:37:44 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@331 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 0a3f237b8..06ad3086e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -602,7 +602,7 @@ QEMU has a primitive support to work with gdb, so that you can do In order to use gdb, launch vl with the '-s' option. It will wait for a gdb connection: @example -> vl -s arch/i386/boot/bzImage initrd-2.4.20.img root=/dev/ram0 ramdisk_size=6144 +> vl -s arch/i386/boot/bzImage -hda root-2.4.20.img root=/dev/hda Connected to host network interface: tun0 Waiting gdb connection on port 1234 @end example -- cgit v1.2.3 From 4c3a88a284b288e0ed3c097de7fc07111d848003 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jul 2003 12:06:08 +0000 Subject: gdb stub breakpoints support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@332 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 5 ++++- cpu-exec.c | 2 +- cpu-i386.h | 6 ++++++ exec.c | 42 ++++++++++++++++++++++++++++++++++++++++++ exec.h | 6 +++--- gdbstub.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++----- op-i386.c | 6 ++++++ translate-arm.c | 12 +++++++----- translate-i386.c | 30 +++++++++++++++++++++++++----- translate.c | 6 +++--- vl.c | 6 ++++-- 11 files changed, 151 insertions(+), 25 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index d61ad7734..787a054a4 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -313,9 +313,12 @@ extern CPUState *cpu_single_env; #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ void cpu_interrupt(CPUState *s, int mask); +int cpu_breakpoint_insert(CPUState *env, uint32_t pc); +int cpu_breakpoint_remove(CPUState *env, uint32_t pc); + /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); -int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port); +int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port); #endif /* CPU_ALL_H */ diff --git a/cpu-exec.c b/cpu-exec.c index ef33aaa3e..908f16184 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -280,7 +280,7 @@ int cpu_exec(CPUState *env1) tb->tc_ptr = tc_ptr; tb->cs_base = (unsigned long)cs_base; tb->flags = flags; - ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); + ret = cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); #if defined(TARGET_I386) /* XXX: suppress that, this is incorrect */ /* if invalid instruction, signal it */ diff --git a/cpu-i386.h b/cpu-i386.h index e6318fb7f..82cdffc25 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -155,6 +155,9 @@ #define EXCP_INTERRUPT 256 /* async interruption */ #define EXCP_HLT 257 /* hlt instruction reached */ +#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ + +#define MAX_BREAKPOINTS 32 enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ @@ -270,6 +273,9 @@ typedef struct CPUX86State { uint32_t dr[8]; /* debug registers */ int interrupt_request; int user_mode_only; /* user mode only simulation */ + + uint32_t breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; /* user data */ void *opaque; diff --git a/exec.c b/exec.c index e7f5081d0..fc0a0cf7a 100644 --- a/exec.c +++ b/exec.c @@ -617,6 +617,48 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } +/* add a breakpoint */ +int cpu_breakpoint_insert(CPUState *env, uint32_t pc) +{ +#if defined(TARGET_I386) + int i; + + for(i = 0; i < env->nb_breakpoints; i++) { + if (env->breakpoints[i] == pc) + return 0; + } + + if (env->nb_breakpoints >= MAX_BREAKPOINTS) + return -1; + env->breakpoints[env->nb_breakpoints++] = pc; + tb_invalidate_page(pc); + return 0; +#else + return -1; +#endif +} + +/* remove a breakpoint */ +int cpu_breakpoint_remove(CPUState *env, uint32_t pc) +{ +#if defined(TARGET_I386) + int i; + for(i = 0; i < env->nb_breakpoints; i++) { + if (env->breakpoints[i] == pc) + goto found; + } + return -1; + found: + memmove(&env->breakpoints[i], &env->breakpoints[i + 1], + (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); + env->nb_breakpoints--; + tb_invalidate_page(pc); + return 0; +#else + return -1; +#endif +} + /* mask must never be zero */ void cpu_interrupt(CPUState *env, int mask) { diff --git a/exec.h b/exec.h index 5ae28ef9b..9489c4777 100644 --- a/exec.h +++ b/exec.h @@ -58,10 +58,10 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; extern FILE *logfile; extern int loglevel; -int gen_intermediate_code(struct TranslationBlock *tb); -int gen_intermediate_code_pc(struct TranslationBlock *tb); +int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); +int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); -int cpu_gen_code(struct TranslationBlock *tb, +int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, int max_code_size, int *gen_code_size_ptr); int cpu_restore_state(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc); diff --git a/gdbstub.c b/gdbstub.c index 2d1f4784a..5fce5d883 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -37,7 +37,7 @@ #include "thunk.h" #include "exec.h" -//#define DEBUG_GDB +#define DEBUG_GDB int gdbstub_fd = -1; @@ -283,11 +283,11 @@ static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) } /* port = 0 means default port */ -int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) +int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) { CPUState *env; const char *p; - int ret, ch, nb_regs, i; + int ret, ch, nb_regs, i, type; char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; @@ -309,8 +309,19 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) put_packet(buf); break; case 'c': - main_loop(opaque); - snprintf(buf, sizeof(buf), "S%02x", 0); + if (*p != '\0') { + addr = strtoul(p, (char **)&p, 16); + env = cpu_gdbstub_get_env(opaque); +#if defined(TARGET_I386) + env->eip = addr; +#endif + } + ret = main_loop(opaque); + if (ret == EXCP_DEBUG) + ret = SIGTRAP; + else + ret = 0; + snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(buf); break; case 'g': @@ -379,6 +390,40 @@ int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port) else put_packet("OK"); break; + case 'Z': + type = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + if (type == 0 || type == 1) { + env = cpu_gdbstub_get_env(opaque); + if (cpu_breakpoint_insert(env, addr) < 0) + goto breakpoint_error; + put_packet("OK"); + } else { + breakpoint_error: + put_packet("ENN"); + } + break; + case 'z': + type = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + if (type == 0 || type == 1) { + env = cpu_gdbstub_get_env(opaque); + cpu_breakpoint_remove(env, addr); + put_packet("OK"); + } else { + goto breakpoint_error; + } + break; default: /* put empty packet */ buf[0] = '\0'; diff --git a/op-i386.c b/op-i386.c index be8b5a113..661d45bf4 100644 --- a/op-i386.c +++ b/op-i386.c @@ -471,6 +471,12 @@ void OPPROTO op_hlt(void) cpu_loop_exit(); } +void OPPROTO op_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + void OPPROTO op_raise_interrupt(void) { int intno; diff --git a/translate-arm.c b/translate-arm.c index c9759f81b..bc8be855f 100644 --- a/translate-arm.c +++ b/translate-arm.c @@ -786,7 +786,9 @@ static void disas_arm_insn(DisasContext *s) /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc) +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext dc1, *dc = &dc1; uint16_t *gen_opc_end; @@ -853,14 +855,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc return 0; } -int gen_intermediate_code(TranslationBlock *tb) +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(tb, 0); + return gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc(TranslationBlock *tb) +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(tb, 1); + return gen_intermediate_code_internal(env, tb, 1); } CPUARMState *cpu_arm_init(void) diff --git a/translate-i386.c b/translate-i386.c index 871d99741..1c051f995 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1463,6 +1463,15 @@ static void gen_interrupt(DisasContext *s, int intno, s->is_jmp = 1; } +static void gen_debug(DisasContext *s, unsigned int cur_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_debug(); + s->is_jmp = 1; +} + /* generate a jump to eip. No segment change must happen before as a direct call to the next block may occur */ static void gen_jmp(DisasContext *s, unsigned int eip) @@ -4080,7 +4089,9 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc) +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; @@ -4116,6 +4127,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc pc_ptr = pc_start; lj = -1; do { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == (unsigned long)pc_ptr) { + gen_debug(dc, pc_ptr - dc->cs_base); + goto the_end; + } + } + } if (search_pc) { j = gen_opc_ptr - gen_opc_buf; if (lj < j) { @@ -4160,6 +4179,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc if (dc->tf) { gen_op_raise_exception(EXCP01_SSTP); } + the_end: if (dc->is_jmp != DISAS_TB_JUMP) { /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); @@ -4202,14 +4222,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc return 0; } -int gen_intermediate_code(TranslationBlock *tb) +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(tb, 0); + return gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc(TranslationBlock *tb) +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) { - return gen_intermediate_code_internal(tb, 1); + return gen_intermediate_code_internal(env, tb, 1); } CPUX86State *cpu_x86_init(void) diff --git a/translate.c b/translate.c index 68c76224a..e9055c0dd 100644 --- a/translate.c +++ b/translate.c @@ -107,13 +107,13 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) '*gen_code_size_ptr' contains the size of the generated code (host code). */ -int cpu_gen_code(TranslationBlock *tb, +int cpu_gen_code(CPUState *env, TranslationBlock *tb, int max_code_size, int *gen_code_size_ptr) { uint8_t *gen_code_buf; int gen_code_size; - if (gen_intermediate_code(tb) < 0) + if (gen_intermediate_code(env, tb) < 0) return -1; /* generate machine code */ @@ -154,7 +154,7 @@ int cpu_restore_state(TranslationBlock *tb, unsigned long tc_ptr; uint16_t *opc_ptr; - if (gen_intermediate_code_pc(tb) < 0) + if (gen_intermediate_code_pc(env, tb) < 0) return -1; /* find opc index corresponding to search_pc */ diff --git a/vl.c b/vl.c index bb15ac4a9..9f76ac004 100644 --- a/vl.c +++ b/vl.c @@ -2540,7 +2540,7 @@ CPUState *cpu_gdbstub_get_env(void *opaque) return global_env; } -void main_loop(void *opaque) +int main_loop(void *opaque) { struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd, *gdb_ufd; int ret, n, timeout; @@ -2552,7 +2552,8 @@ void main_loop(void *opaque) ret = cpu_x86_exec(env); if (reset_requested) break; - + if (ret == EXCP_DEBUG) + return EXCP_DEBUG; /* if hlt instruction, we wait until the next IRQ */ if (ret == EXCP_HLT) timeout = 10; @@ -2618,6 +2619,7 @@ void main_loop(void *opaque) timer_irq_pending = 0; } } + return EXCP_INTERRUPT; } void help(void) -- cgit v1.2.3 From 8f186479e26e8207520c062248642153826d5cde Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jul 2003 17:59:00 +0000 Subject: real mode support (now boots from BOCHS BIOS and LGPL'ed VGA BIOS) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@333 c046a42c-6fe2-441c-8c8c-71466251a162 --- helper-i386.c | 31 ++++++++++++++++++++++++++++ op-i386.c | 5 +++++ translate-i386.c | 61 ++++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/helper-i386.c b/helper-i386.c index 72b75a5c2..3f63704d5 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -788,6 +788,37 @@ static inline void load_seg_vm(int seg, int selector) sc->limit = 0xffff; } +/* real mode iret */ +void helper_iret_real(int shift) +{ + uint32_t sp, new_cs, new_eip, new_eflags, new_esp; + uint8_t *ssp; + int eflags_mask; + + sp = env->regs[R_ESP] & 0xffff; + ssp = env->segs[R_SS].base + sp; + if (shift == 1) { + /* 32 bits */ + new_eflags = ldl(ssp + 8); + new_cs = ldl(ssp + 4) & 0xffff; + new_eip = ldl(ssp) & 0xffff; + } else { + /* 16 bits */ + new_eflags = lduw(ssp + 4); + new_cs = lduw(ssp + 2); + new_eip = lduw(ssp); + } + new_esp = sp + (6 << shift); + env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | + (new_esp & 0xffff); + load_seg_vm(R_CS, new_cs); + env->eip = new_eip; + eflags_mask = FL_UPDATE_CPL0_MASK; + if (shift == 0) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); +} + /* protected mode iret */ void helper_iret_protected(int shift) { diff --git a/op-i386.c b/op-i386.c index 661d45bf4..ff8cb4415 100644 --- a/op-i386.c +++ b/op-i386.c @@ -953,6 +953,11 @@ void OPPROTO op_ljmp_T0_T1(void) jmp_seg(T0 & 0xffff, T1); } +void OPPROTO op_iret_real(void) +{ + helper_iret_real(PARAM1); +} + void OPPROTO op_iret_protected(void) { helper_iret_protected(PARAM1); diff --git a/translate-i386.c b/translate-i386.c index 1c051f995..d5cdee575 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -52,6 +52,7 @@ typedef struct DisasContext { static state change (stop translation) */ /* current block context */ uint8_t *cs_base; /* base of CS segment */ + int pe; /* protected mode */ int code32; /* 32 bit code segment */ int ss32; /* 32 bit stack segment */ int cc_op; /* current CC operation */ @@ -989,7 +990,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ if (base >= 0) { /* for correct popl handling with esp */ if (base == 4 && s->popl_esp_hack) - disp += 4; + disp += s->popl_esp_hack; gen_op_movl_A0_reg[base](); if (disp != 0) gen_op_addl_A0_im(disp); @@ -1272,7 +1273,7 @@ static void gen_setcc(DisasContext *s, int b) /* move T0 to seg_reg and compute if the CPU state may change */ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) { - if (!s->vm86) + if (s->pe && !s->vm86) gen_op_movl_seg_T0(seg_reg, cur_eip); else gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); @@ -1855,7 +1856,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_ld_T1_A0[ot](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_lduw_T0_A0(); - if (!s->vm86) { + if (s->pe && !s->vm86) { /* we compute EIP to handle the exception case */ gen_op_jmp_im(pc_start - s->cs_base); gen_op_ljmp_T0_T1(); @@ -2036,7 +2037,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); gen_pop_T0(s); - s->popl_esp_hack = 1; + s->popl_esp_hack = 2 << dflag; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); s->popl_esp_hack = 0; gen_pop_update(s); @@ -2082,6 +2083,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_pop_T0(s); gen_movl_seg_T0(s, b >> 3, pc_start - s->cs_base); gen_pop_update(s); + /* XXX: if reg == SS, inhibit interrupts/trace */ break; case 0x1a1: /* pop fs */ case 0x1a9: /* pop gs */ @@ -2134,21 +2136,24 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_reg_T0[ot][reg](); break; case 0x8e: /* mov seg, Gv */ - ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); reg = (modrm >> 3) & 7; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); if (reg >= 6 || reg == R_CS) goto illegal_op; + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_movl_seg_T0(s, reg, pc_start - s->cs_base); + /* XXX: if reg == SS, inhibit interrupts/trace */ break; case 0x8c: /* mov Gv, seg */ - ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; if (reg >= 6) goto illegal_op; gen_op_movl_T0_seg(reg); + ot = OT_WORD; + if (mod == 3 && dflag) + ot = OT_LONG; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; @@ -2938,7 +2943,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x6c: /* insS */ case 0x6d: - if (s->cpl > s->iopl || s->vm86) { + if (s->pe && (s->cpl > s->iopl || s->vm86)) { /* NOTE: even for (E)CX = 0 the exception is raised */ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -2955,7 +2960,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x6e: /* outsS */ case 0x6f: - if (s->cpl > s->iopl || s->vm86) { + if (s->pe && (s->cpl > s->iopl || s->vm86)) { /* NOTE: even for (E)CX = 0 the exception is raised */ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -2975,7 +2980,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* port I/O */ case 0xe4: case 0xe5: - if (s->cpl > s->iopl || s->vm86) { + if (s->pe && (s->cpl > s->iopl || s->vm86)) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) @@ -2990,7 +2995,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xe6: case 0xe7: - if (s->cpl > s->iopl || s->vm86) { + if (s->pe && (s->cpl > s->iopl || s->vm86)) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) @@ -3005,7 +3010,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xec: case 0xed: - if (s->cpl > s->iopl || s->vm86) { + if (s->pe && (s->cpl > s->iopl || s->vm86)) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) @@ -3019,7 +3024,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xee: case 0xef: - if (s->cpl > s->iopl || s->vm86) { + if (s->pe && (s->cpl > s->iopl || s->vm86)) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) @@ -3076,7 +3081,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = 0; goto do_lret; case 0xcf: /* iret */ - if (s->vm86 && s->iopl != 3) { + if (!s->pe) { + /* real mode */ + gen_op_iret_real(s->dflag); + s->cc_op = CC_OP_EFLAGS; + } else if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) @@ -3142,7 +3151,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* change cs and pc */ gen_op_movl_T0_im(selector); - if (!s->vm86) { + if (s->pe && !s->vm86) { /* we compute EIP to handle the exception case */ gen_op_jmp_im(pc_start - s->cs_base); gen_op_movl_T1_im(offset); @@ -3442,6 +3451,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } + /* XXX: interruptions are enabled only the first insn after sti */ break; case 0x62: /* bound */ ot = dflag ? OT_LONG : OT_WORD; @@ -3628,7 +3638,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x102: /* lar */ case 0x103: /* lsl */ - if (s->vm86) + if (!s->pe || s->vm86) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; modrm = ldub(s->pc++); @@ -4106,19 +4116,26 @@ static inline int gen_intermediate_code_internal(CPUState *env, cs_base = (uint8_t *)tb->cs_base; flags = tb->flags; + dc->pe = env->cr[0] & CR0_PE_MASK; dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; - dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; + /* CPL is implicit if real mode or vm86 mode */ + if (!dc->pe) + dc->cpl = 0; + else if (dc->vm86) + dc->cpl = 3; + else + dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3; dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; dc->tb = tb; dc->popl_esp_hack = 0; - + gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; @@ -4270,13 +4287,14 @@ void cpu_x86_close(CPUX86State *env) /* called when cr3 or PG bit are modified */ static int last_pg_state = -1; +static int last_pe_state = 0; int phys_ram_size; int phys_ram_fd; uint8_t *phys_ram_base; void cpu_x86_update_cr0(CPUX86State *env) { - int pg_state; + int pg_state, pe_state; void *map_addr; #ifdef DEBUG_MMU @@ -4304,6 +4322,11 @@ void cpu_x86_update_cr0(CPUX86State *env) } last_pg_state = pg_state; } + pe_state = env->cr[0] & CR0_PE_MASK; + if (last_pe_state != pe_state) { + tb_flush(); + last_pe_state = pe_state; + } } void cpu_x86_update_cr3(CPUX86State *env) -- cgit v1.2.3 From b2b5fb228f273d2c72aefce3be1f9e11e23c6c24 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jul 2003 18:00:58 +0000 Subject: popw (%esp) test) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@334 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 241186956..a7ee032c0 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -970,6 +970,11 @@ void test_misc(void) asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0" : "=g" (res)); printf("popl esp=%x\n", res); + + /* specific popw test */ + asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popw (%%esp) ; addl $2, %%esp ; popl %0" + : "=g" (res)); + printf("popw esp=%x\n", res); } uint8_t str_buffer[4096]; -- cgit v1.2.3 From a412ac572ffad45f663795ba7dfa8fa1603ef206 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jul 2003 18:01:40 +0000 Subject: real mode support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@335 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 908f16184..1ffeb8e86 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -244,12 +244,12 @@ int cpu_exec(CPUState *env1) (unsigned long)env->segs[R_ES].base | (unsigned long)env->segs[R_SS].base) != 0) << GEN_FLAG_ADDSEG_SHIFT; - if (!(env->eflags & VM_MASK)) { - flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT; - } else { - /* NOTE: a dummy CPL is kept */ - flags |= (1 << GEN_FLAG_VM_SHIFT); - flags |= (3 << GEN_FLAG_CPL_SHIFT); + if (env->cr[0] & CR0_PE_MASK) { + if (!(env->eflags & VM_MASK)) + flags |= (env->segs[R_CS].selector & 3) << + GEN_FLAG_CPL_SHIFT; + else + flags |= (1 << GEN_FLAG_VM_SHIFT); } flags |= (env->eflags & (IOPL_MASK | TF_MASK)); cs_base = env->segs[R_CS].base; @@ -396,12 +396,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) saved_env = env; env = s; - if (env->eflags & VM_MASK) { + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { SegmentCache *sc; selector &= 0xffff; sc = &env->segs[seg_reg]; - /* NOTE: in VM86 mode, limit and flags are never reloaded, - so we must load them here */ sc->base = (void *)(selector << 4); sc->limit = 0xffff; sc->flags = 0; -- cgit v1.2.3 From 4abe615b841f5f992440fc8ed5b496b1b22c655b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jul 2003 18:01:58 +0000 Subject: removed debug git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@336 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdbstub.c b/gdbstub.c index 5fce5d883..d255eab6d 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -37,7 +37,7 @@ #include "thunk.h" #include "exec.h" -#define DEBUG_GDB +//#define DEBUG_GDB int gdbstub_fd = -1; -- cgit v1.2.3 From 3802ce26a1b60fe791aee1ff3e15ab6dc0bdac27 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jul 2003 18:02:28 +0000 Subject: set to protected mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@337 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 2f341d92c..b85637f8b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -433,6 +433,8 @@ int main(int argc, char **argv) env->user_mode_only = 1; #if defined(TARGET_I386) + env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; + /* linux register setup */ env->regs[R_EAX] = regs->eax; env->regs[R_EBX] = regs->ebx; -- cgit v1.2.3 From 330d0414a5968d36edb635c63a729ffa55520e76 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jul 2003 18:11:40 +0000 Subject: keyboard emulation - accepts to boot with Bochs BIOS and LGPL'ed VGA BIOS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@338 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 697 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 605 insertions(+), 92 deletions(-) diff --git a/vl.c b/vl.c index 9f76ac004..fb27e3b46 100644 --- a/vl.c +++ b/vl.c @@ -52,10 +52,28 @@ #define DEBUG_LOGFILE "/tmp/vl.log" #define DEFAULT_NETWORK_SCRIPT "/etc/vl-ifup" +#define BIOS_FILENAME "bios.bin" +#define VGABIOS_FILENAME "vgabios.bin" //#define DEBUG_UNUSED_IOPORT + //#define DEBUG_IRQ_LATENCY +/* output Bochs bios info messages */ +//#define DEBUG_BIOS + +/* debug IDE devices */ +//#define DEBUG_IDE + +/* debug PIC */ +//#define DEBUG_PIC + +/* debug NE2000 card */ +//#define DEBUG_NE2000 + +/* debug PC keyboard */ +//#define DEBUG_KBD + #define PHYS_RAM_BASE 0xac000000 #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) @@ -185,6 +203,7 @@ typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address); #define MAX_IOPORTS 4096 +static const char *interp_prefix = CONFIG_QEMU_PREFIX; char phys_ram_file[1024]; CPUX86State *global_env; CPUX86State *cpu_single_env; @@ -216,15 +235,15 @@ void default_ioport_writeb(CPUX86State *env, uint32_t address, uint32_t data) uint32_t default_ioport_readw(CPUX86State *env, uint32_t address) { uint32_t data; - data = ioport_read_table[0][address](env, address); - data |= ioport_read_table[0][address + 1](env, address + 1) << 8; + data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](env, address); + data |= ioport_read_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1) << 8; return data; } void default_ioport_writew(CPUX86State *env, uint32_t address, uint32_t data) { - ioport_write_table[0][address](env, address, data & 0xff); - ioport_write_table[0][address + 1](env, address + 1, (data >> 8) & 0xff); + ioport_write_table[0][address & (MAX_IOPORTS - 1)](env, address, data & 0xff); + ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1, (data >> 8) & 0xff); } uint32_t default_ioport_readl(CPUX86State *env, uint32_t address) @@ -516,6 +535,7 @@ void cmos_init(void) { struct tm *tm; time_t ti; + int val; ti = time(NULL); tm = gmtime(&ti); @@ -532,8 +552,27 @@ void cmos_init(void) cmos_data[RTC_REG_C] = 0x00; cmos_data[RTC_REG_D] = 0x80; + /* various important CMOS locations needed by PC/Bochs bios */ + cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ + /* memory size */ + val = (phys_ram_size / 1024) - 1024; + if (val > 65535) + val = 65535; + cmos_data[0x17] = val; + cmos_data[0x18] = val >> 8; + cmos_data[0x30] = val; + cmos_data[0x31] = val >> 8; + + val = (phys_ram_size / 65536) - ((16 * 1024 * 1024) / 65536); + if (val > 65535) + val = 65535; + cmos_data[0x34] = val; + cmos_data[0x35] = val >> 8; + + cmos_data[0x3d] = 0x02; /* hard drive boot */ + register_ioport_write(0x70, 2, cmos_ioport_write, 1); register_ioport_read(0x70, 2, cmos_ioport_read, 1); } @@ -541,8 +580,6 @@ void cmos_init(void) /***********************************************************/ /* 8259 pic emulation */ -//#define DEBUG_PIC - typedef struct PicState { uint8_t last_irr; /* edge detection */ uint8_t irr; /* interrupt request register */ @@ -1360,8 +1397,6 @@ void serial_init(void) /***********************************************************/ /* ne2000 emulation */ -//#define DEBUG_NE2000 - #define NE2000_IOPORT 0x300 #define NE2000_IRQ 9 @@ -1827,8 +1862,6 @@ void ne2000_init(void) /***********************************************************/ /* ide emulation */ -//#define DEBUG_IDE - /* Bits of HD_STATUS */ #define ERR_STAT 0x01 #define INDEX_STAT 0x02 @@ -2352,16 +2385,50 @@ uint32_t ide_status_read(CPUX86State *env, uint32_t addr) int ret; ret = s->status; #ifdef DEBUG_IDE - printf("ide: read addr=0x%x val=%02x\n", addr, ret); + printf("ide: read status val=%02x\n", ret); #endif return ret; } void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) { - IDEState *s = &ide_state[0]; + IDEState *s; + int i; + +#ifdef DEBUG_IDE + printf("ide: write control val=%02x\n", val); +#endif /* common for both drives */ - s->cmd = val; + if (!(ide_state[0].cmd & IDE_CMD_RESET) && + (val & IDE_CMD_RESET)) { + /* reset low to high */ + for(i = 0;i < 2; i++) { + s = &ide_state[i]; + s->status = BUSY_STAT | SEEK_STAT; + s->error = 0x01; + } + } else if ((ide_state[0].cmd & IDE_CMD_RESET) && + !(val & IDE_CMD_RESET)) { + /* high to low */ + for(i = 0;i < 2; i++) { + s = &ide_state[i]; + s->status = READY_STAT; + /* set hard disk drive ID */ + s->select &= 0xf0; /* clear head */ + s->nsector = 1; + s->sector = 1; + if (s->nb_sectors == 0) { + /* no disk present */ + s->lcyl = 0x12; + s->hcyl = 0x34; + } else { + s->lcyl = 0; + s->hcyl = 0; + } + } + } + + ide_state[0].cmd = val; } void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) @@ -2439,14 +2506,17 @@ void ide_init(void) s->bs = bs_table[i]; if (s->bs) { bdrv_get_geometry(s->bs, &nb_sectors); - cylinders = nb_sectors / (16 * 63); - if (cylinders > 16383) - cylinders = 16383; - else if (cylinders < 2) - cylinders = 2; - s->cylinders = cylinders; - s->heads = 16; - s->sectors = 63; + if (s->cylinders == 0) { + /* if no geometry, use a LBA compatible one */ + cylinders = nb_sectors / (16 * 63); + if (cylinders > 16383) + cylinders = 16383; + else if (cylinders < 2) + cylinders = 2; + s->cylinders = cylinders; + s->heads = 16; + s->sectors = 63; + } s->nb_sectors = nb_sectors; } s->irq = 14; @@ -2465,33 +2535,401 @@ void ide_init(void) } /***********************************************************/ -/* simulate reset (stop qemu) */ +/* keyboard emulation */ + +/* Keyboard Controller Commands */ +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ +#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ +#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ +#define KBD_CCMD_WRITE_OBUF 0xD2 +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ +#define KBD_CCMD_ENABLE_A20 0xDD +#define KBD_CCMD_DISABLE_A20 0xDF +#define KBD_CCMD_RESET 0xFE + +/* Keyboard Commands */ +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_ECHO 0xEE +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* Keyboard Replies */ +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* Status Register Bits */ +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +/* Controller Mode Register Bits */ +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* Mouse Commands */ +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define KBD_QUEUE_SIZE 64 + +typedef struct { + uint8_t data[KBD_QUEUE_SIZE]; + int rptr, wptr, count; +} KBDQueue; + +enum KBDWriteState { + KBD_STATE_CMD = 0, + KBD_STATE_LED, +}; +typedef struct KBDState { + KBDQueue queues[2]; + uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ + uint8_t status; + uint8_t mode; + int kbd_write_cmd; + int scan_enabled; +} KBDState; + +KBDState kbd_state; int reset_requested; +int a20_enabled; + +static void kbd_update_irq(KBDState *s) +{ + int level; + + level = ((s->status & KBD_STAT_OBF) && (s->mode & KBD_MODE_KBD_INT)); + pic_set_irq(1, level); + + level = ((s->status & KBD_STAT_MOUSE_OBF) && (s->mode & KBD_MODE_MOUSE_INT)); + pic_set_irq(12, level); +} + +static void kbd_queue(KBDState *s, int b, int aux) +{ + KBDQueue *q = &kbd_state.queues[aux]; + + if (q->count >= KBD_QUEUE_SIZE) + return; + q->data[q->wptr] = b; + if (++q->wptr == KBD_QUEUE_SIZE) + q->wptr = 0; + q->count++; + s->status |= KBD_STAT_OBF; + if (aux) + s->status |= KBD_STAT_MOUSE_OBF; + kbd_update_irq(s); +} uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) { - return 0; + KBDState *s = &kbd_state; + int val; + val = s->status; +#if defined(DEBUG_KBD) && 0 + printf("kbd: read status=0x%02x\n", val); +#endif + return val; } void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) { + KBDState *s = &kbd_state; + +#ifdef DEBUG_KBD + printf("kbd: write cmd=0x%02x\n", val); +#endif switch(val) { - case 0xfe: + case KBD_CCMD_READ_MODE: + kbd_queue(s, s->mode, 0); + break; + case KBD_CCMD_WRITE_MODE: + case KBD_CCMD_WRITE_OBUF: + case KBD_CCMD_WRITE_AUX_OBUF: + case KBD_CCMD_WRITE_MOUSE: + case KBD_CCMD_WRITE_OUTPORT: + s->write_cmd = val; + break; + case KBD_CCMD_MOUSE_DISABLE: + s->mode |= KBD_MODE_DISABLE_MOUSE; + break; + case KBD_CCMD_MOUSE_ENABLE: + s->mode &= ~KBD_MODE_DISABLE_MOUSE; + break; + case KBD_CCMD_TEST_MOUSE: + kbd_queue(s, 0x00, 0); + break; + case KBD_CCMD_SELF_TEST: + s->status |= KBD_STAT_SELFTEST; + kbd_queue(s, 0x55, 0); + break; + case KBD_CCMD_KBD_TEST: + kbd_queue(s, 0x00, 0); + break; + case KBD_CCMD_KBD_DISABLE: + s->mode |= KBD_MODE_DISABLE_KBD; + break; + case KBD_CCMD_KBD_ENABLE: + s->mode &= ~KBD_MODE_DISABLE_KBD; + break; + case KBD_CCMD_READ_INPORT: + kbd_queue(s, 0x00, 0); + break; + case KBD_CCMD_READ_OUTPORT: + /* XXX: check that */ + val = 0x01 | (a20_enabled << 1); + if (s->status & KBD_STAT_OBF) + val |= 0x10; + if (s->status & KBD_STAT_MOUSE_OBF) + val |= 0x20; + kbd_queue(s, val, 0); + break; + case KBD_CCMD_ENABLE_A20: + a20_enabled = 1; + break; + case KBD_CCMD_DISABLE_A20: + a20_enabled = 0; + break; + case KBD_CCMD_RESET: reset_requested = 1; cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); break; + default: + fprintf(stderr, "vl: unsupported keyboard cmd=0x%02x\n", val); + break; + } +} + +uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) +{ + KBDState *s = &kbd_state; + KBDQueue *q; + int val; + + q = &s->queues[1]; /* first check AUX data */ + if (q->count == 0) + q = &s->queues[0]; /* then check KBD data */ + if (q->count == 0) { + /* XXX: return something else ? */ + val = 0; + } else { + val = q->data[q->rptr]; + if (++q->rptr == KBD_QUEUE_SIZE) + q->rptr = 0; + q->count--; + } + if (s->queues[1].count == 0) { + s->status &= ~KBD_STAT_MOUSE_OBF; + if (s->queues[0].count == 0) + s->status &= ~KBD_STAT_OBF; + kbd_update_irq(s); + } + +#ifdef DEBUG_KBD + printf("kbd: read data=0x%02x\n", val); +#endif + return val; +} + +static void kbd_reset_keyboard(KBDState *s) +{ + s->scan_enabled = 1; +} + +static void kbd_write_keyboard(KBDState *s, int val) +{ + switch(s->kbd_write_cmd) { + default: + case -1: + switch(val) { + case 0x00: + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case 0x05: + kbd_queue(s, KBD_REPLY_RESEND, 0); + break; + case KBD_CMD_ECHO: + kbd_queue(s, KBD_CMD_ECHO, 0); + break; + case KBD_CMD_ENABLE: + s->scan_enabled = 1; + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case KBD_CMD_SET_LEDS: + case KBD_CMD_SET_RATE: + s->kbd_write_cmd = val; + break; + case KBD_CMD_RESET_DISABLE: + kbd_reset_keyboard(s); + s->scan_enabled = 0; + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case KBD_CMD_RESET_ENABLE: + kbd_reset_keyboard(s); + s->scan_enabled = 1; + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case KBD_CMD_RESET: + kbd_reset_keyboard(s); + kbd_queue(s, KBD_REPLY_ACK, 0); + kbd_queue(s, KBD_REPLY_POR, 0); + break; + default: + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + } + break; + case KBD_CMD_SET_LEDS: + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case KBD_CMD_SET_RATE: + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + } + s->kbd_write_cmd = -1; +} + +void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) +{ + KBDState *s = &kbd_state; + +#ifdef DEBUG_KBD + printf("kbd: write data=0x%02x\n", val); +#endif + + switch(s->write_cmd) { + case 0: + kbd_write_keyboard(s, val); + break; + case KBD_CCMD_WRITE_MODE: + s->mode = val; + kbd_update_irq(s); + break; + case KBD_CCMD_WRITE_OBUF: + kbd_queue(s, val, 0); + break; + case KBD_CCMD_WRITE_AUX_OBUF: + kbd_queue(s, val, 1); + break; + case KBD_CCMD_WRITE_OUTPORT: + a20_enabled = (val >> 1) & 1; + if (!(val & 1)) { + reset_requested = 1; + cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); + } + break; default: break; } + s->write_cmd = 0; +} + +void kbd_reset(KBDState *s) +{ + KBDQueue *q; + int i; + + s->kbd_write_cmd = -1; + s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; + s->status = KBD_MODE_SYS | KBD_MODE_NO_KEYLOCK; + for(i = 0; i < 2; i++) { + q = &s->queues[i]; + q->rptr = 0; + q->wptr = 0; + q->count = 0; + } } void kbd_init(void) { + kbd_reset(&kbd_state); + register_ioport_read(0x60, 1, kbd_read_data, 1); + register_ioport_write(0x60, 1, kbd_write_data, 1); register_ioport_read(0x64, 1, kbd_read_status, 1); register_ioport_write(0x64, 1, kbd_write_command, 1); } +/***********************************************************/ +/* Bochs BIOS debug ports */ + +void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + switch(addr) { + /* Bochs BIOS messages */ + case 0x400: + case 0x401: + fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); + exit(1); + case 0x402: + case 0x403: +#ifdef DEBUG_BIOS + fprintf(stderr, "%c", val); +#endif + break; + + /* LGPL'ed VGA BIOS messages */ + case 0x501: + case 0x502: + fprintf(stderr, "VGA BIOS panic, line %d\n", val); + exit(1); + case 0x500: + case 0x503: +#ifdef DEBUG_BIOS + fprintf(stderr, "%c", val); +#endif + break; + } +} + +void bochs_bios_init(void) +{ + register_ioport_write(0x400, 1, bochs_bios_write, 2); + register_ioport_write(0x401, 1, bochs_bios_write, 2); + register_ioport_write(0x402, 1, bochs_bios_write, 1); + register_ioport_write(0x403, 1, bochs_bios_write, 1); + + register_ioport_write(0x501, 1, bochs_bios_write, 2); + register_ioport_write(0x502, 1, bochs_bios_write, 2); + register_ioport_write(0x500, 1, bochs_bios_write, 1); + register_ioport_write(0x503, 1, bochs_bios_write, 1); +} + /***********************************************************/ /* cpu signal handler */ static void host_segv_handler(int host_signum, siginfo_t *info, @@ -2625,7 +3063,7 @@ int main_loop(void *opaque) void help(void) { printf("Virtual Linux version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: vl [options] bzImage [kernel parameters...]\n" + "usage: vl [options] [bzImage [kernel parameters...]]\n" "\n" "'bzImage' is a Linux kernel image (PAGE_OFFSET must be defined\n" "to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n" @@ -2638,10 +3076,12 @@ void help(void) "-m megs set virtual RAM size to megs MB\n" "-n script set network init script [default=%s]\n" "\n" - "Debug options:\n" + "Debug/Expert options:\n" "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" "-d output log in /tmp/vl.log\n" + "-hdachs c,h,s force hard disk 0 geometry for non LBA disk images\n" + "-L path set the directory for the BIOS and VGA BIOS\n" "\n" "During emulation, use C-a h to get terminal commands:\n", DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT); @@ -2654,13 +3094,14 @@ struct option long_options[] = { { "hda", 1, NULL, 0, }, { "hdb", 1, NULL, 0, }, { "snapshot", 0, NULL, 0, }, + { "hdachs", 1, NULL, 0, }, { NULL, 0, NULL, 0 }, }; int main(int argc, char **argv) { int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; - int snapshot; + int snapshot, linux_boot; struct linux_params *params; struct sigaction act; struct itimerval itv; @@ -2678,8 +3119,9 @@ int main(int argc, char **argv) use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; snapshot = 0; + linux_boot = 0; for(;;) { - c = getopt_long_only(argc, argv, "hm:dn:sp:", long_options, &long_index); + c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index); if (c == -1) break; switch(c) { @@ -2697,6 +3139,28 @@ int main(int argc, char **argv) case 3: snapshot = 1; break; + case 4: + { + int cyls, heads, secs; + const char *p; + p = optarg; + cyls = strtol(p, (char **)&p, 0); + if (*p != ',') + goto chs_fail; + p++; + heads = strtol(p, (char **)&p, 0); + if (*p != ',') + goto chs_fail; + p++; + secs = strtol(p, (char **)&p, 0); + if (*p != '\0') + goto chs_fail; + ide_state[0].cylinders = cyls; + ide_state[0].heads = heads; + ide_state[0].sectors = secs; + chs_fail: ; + } + break; } break; case 'h': @@ -2724,9 +3188,15 @@ int main(int argc, char **argv) case 'p': gdbstub_port = atoi(optarg); break; + case 'L': + interp_prefix = optarg; + break; } } - if (optind >= argc) + + linux_boot = (optind < argc); + + if (!linux_boot && hd_filename[0] == '\0') help(); /* init debug */ @@ -2781,46 +3251,119 @@ int main(int argc, char **argv) } } - /* now we can load the kernel */ - ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); - if (ret < 0) { - fprintf(stderr, "vl: could not load kernel '%s'\n", argv[optind]); - exit(1); - } + /* init CPU state */ + env = cpu_init(); + global_env = env; + cpu_single_env = env; + + init_ioports(); - /* load initrd */ - initrd_size = 0; - if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "vl: could not load initial ram disk '%s'\n", - initrd_filename); + if (linux_boot) { + /* now we can load the kernel */ + ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) { + fprintf(stderr, "vl: could not load kernel '%s'\n", argv[optind]); exit(1); } - } + + /* load initrd */ + initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "vl: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + + /* init kernel params */ + params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR); + memset(params, 0, sizeof(struct linux_params)); + params->mount_root_rdonly = 0; + params->cl_magic = 0xA33F; + params->cl_offset = params->commandline - (uint8_t *)params; + params->alt_mem_k = (phys_ram_size / 1024) - 1024; + for(i = optind + 1; i < argc; i++) { + if (i != optind + 1) + pstrcat(params->commandline, sizeof(params->commandline), " "); + pstrcat(params->commandline, sizeof(params->commandline), argv[i]); + } + params->loader_type = 0x01; + if (initrd_size > 0) { + params->initrd_start = INITRD_LOAD_ADDR; + params->initrd_size = initrd_size; + } + params->orig_video_lines = 25; + params->orig_video_cols = 80; + + /* setup basic memory access */ + env->cr[0] = 0x00000033; + cpu_x86_init_mmu(env); + + memset(params->idt_table, 0, sizeof(params->idt_table)); + + params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ + params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */ + + env->idt.base = (void *)params->idt_table; + env->idt.limit = sizeof(params->idt_table) - 1; + env->gdt.base = (void *)params->gdt_table; + env->gdt.limit = sizeof(params->gdt_table) - 1; + + cpu_x86_load_seg(env, R_CS, KERNEL_CS); + cpu_x86_load_seg(env, R_DS, KERNEL_DS); + cpu_x86_load_seg(env, R_ES, KERNEL_DS); + cpu_x86_load_seg(env, R_SS, KERNEL_DS); + cpu_x86_load_seg(env, R_FS, KERNEL_DS); + cpu_x86_load_seg(env, R_GS, KERNEL_DS); + + env->eip = KERNEL_LOAD_ADDR; + env->regs[R_ESI] = KERNEL_PARAMS_ADDR; + env->eflags = 0x2; - /* init kernel params */ - params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR); - memset(params, 0, sizeof(struct linux_params)); - params->mount_root_rdonly = 0; - params->cl_magic = 0xA33F; - params->cl_offset = params->commandline - (uint8_t *)params; - params->alt_mem_k = (phys_ram_size / 1024) - 1024; - for(i = optind + 1; i < argc; i++) { - if (i != optind + 1) - pstrcat(params->commandline, sizeof(params->commandline), " "); - pstrcat(params->commandline, sizeof(params->commandline), argv[i]); - } - params->loader_type = 0x01; - if (initrd_size > 0) { - params->initrd_start = INITRD_LOAD_ADDR; - params->initrd_size = initrd_size; + } else { + char buf[1024]; + + /* RAW PC boot */ + + /* BIOS load */ + snprintf(buf, sizeof(buf), "%s/%s", interp_prefix, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + 0x000f0000); + if (ret != 0x10000) { + fprintf(stderr, "vl: could not load PC bios '%s'\n", BIOS_FILENAME); + exit(1); + } + + /* VGA BIOS load */ + snprintf(buf, sizeof(buf), "%s/%s", interp_prefix, VGABIOS_FILENAME); + ret = load_image(buf, phys_ram_base + 0x000c0000); + + /* setup basic memory access */ + env->cr[0] = 0x60000010; + cpu_x86_init_mmu(env); + + env->idt.limit = 0xffff; + env->gdt.limit = 0xffff; + env->ldt.limit = 0xffff; + + /* not correct (CS base=0xffff0000) */ + cpu_x86_load_seg(env, R_CS, 0xf000); + cpu_x86_load_seg(env, R_DS, 0); + cpu_x86_load_seg(env, R_ES, 0); + cpu_x86_load_seg(env, R_SS, 0); + cpu_x86_load_seg(env, R_FS, 0); + cpu_x86_load_seg(env, R_GS, 0); + + env->eip = 0xfff0; + env->regs[R_EDX] = 0x600; /* indicate P6 processor */ + + env->eflags = 0x2; + + bochs_bios_init(); } - params->orig_video_lines = 25; - params->orig_video_cols = 80; /* init basic PC hardware */ - init_ioports(); register_ioport_write(0x80, 1, ioport80_write, 1); register_ioport_write(0x3d4, 2, vga_ioport_write, 1); @@ -2843,36 +3386,6 @@ int main(int argc, char **argv) act.sa_sigaction = host_alarm_handler; sigaction(SIGALRM, &act, NULL); - /* init CPU state */ - env = cpu_init(); - global_env = env; - cpu_single_env = env; - - /* setup basic memory access */ - env->cr[0] = 0x00000033; - cpu_x86_init_mmu(env); - - memset(params->idt_table, 0, sizeof(params->idt_table)); - - params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ - params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */ - - env->idt.base = (void *)params->idt_table; - env->idt.limit = sizeof(params->idt_table) - 1; - env->gdt.base = (void *)params->gdt_table; - env->gdt.limit = sizeof(params->gdt_table) - 1; - - cpu_x86_load_seg(env, R_CS, KERNEL_CS); - cpu_x86_load_seg(env, R_DS, KERNEL_DS); - cpu_x86_load_seg(env, R_ES, KERNEL_DS); - cpu_x86_load_seg(env, R_SS, KERNEL_DS); - cpu_x86_load_seg(env, R_FS, KERNEL_DS); - cpu_x86_load_seg(env, R_GS, KERNEL_DS); - - env->eip = KERNEL_LOAD_ADDR; - env->regs[R_ESI] = KERNEL_PARAMS_ADDR; - env->eflags = 0x2; - itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 1000; itv.it_value.tv_sec = 0; -- cgit v1.2.3 From 8a4c1cc4118720fb69f0e9aa3c15275e13294946 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jul 2003 20:34:00 +0000 Subject: fixed ss segment load - added ICEBP instruction git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@339 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index d5cdee575..7fce0e24b 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1277,9 +1277,10 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) gen_op_movl_seg_T0(seg_reg, cur_eip); else gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); - if (!s->addseg && seg_reg < R_FS) - s->is_jmp = 2; /* abort translation because the register may - have a non zero base */ + /* abort translation because the register may have a non zero base + or because ss32 may change */ + if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) + s->is_jmp = 2; } /* generate a push. It depends on ss32, addseg and dflag */ @@ -3420,6 +3421,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_set_cc_op(s->cc_op); gen_op_into(s->pc - s->cs_base); break; + case 0xf1: /* icebp (undocumented, exits to external debugger) */ + gen_debug(s, pc_start - s->cs_base); + break; case 0xfa: /* cli */ if (!s->vm86) { if (s->cpl <= s->iopl) { -- cgit v1.2.3 From 2c1794c42ef9d23dc6aeb5e07673f2fcd885b9eb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 27 Jul 2003 21:11:27 +0000 Subject: more generic ljmp and lcall - fixed REPNZ usage for non compare string ops (FreeDos boot loader fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@340 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-i386.h | 6 +- helper-i386.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++++------- op-i386.c | 19 +++- translate-i386.c | 99 ++++++++--------- 4 files changed, 348 insertions(+), 100 deletions(-) diff --git a/exec-i386.h b/exec-i386.h index 84a1dabf0..964abddfa 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -123,8 +123,12 @@ typedef struct CCTable { extern CCTable cc_table[]; void load_seg(int seg_reg, int selector, unsigned cur_eip); -void jmp_seg(int selector, unsigned int new_eip); +void helper_ljmp_protected_T0_T1(void); +void helper_lcall_real_T0_T1(int shift, int next_eip); +void helper_lcall_protected_T0_T1(int shift, int next_eip); +void helper_iret_real(int shift); void helper_iret_protected(int shift); +void helper_lret_protected(int shift, int addend); void helper_lldt_T0(void); void helper_ltr_T0(void); void helper_movl_crN_T0(int reg); diff --git a/helper-i386.c b/helper-i386.c index 3f63704d5..d3a931681 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -185,7 +185,7 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, /* protected mode interrupt */ static void do_interrupt_protected(int intno, int is_int, int error_code, - unsigned int next_eip) + unsigned int next_eip) { SegmentCache *dt; uint8_t *ptr, *ssp; @@ -378,20 +378,19 @@ static void do_interrupt_real(int intno, int is_int, int error_code, ptr = dt->base + intno * 4; offset = lduw(ptr); selector = lduw(ptr + 2); - esp = env->regs[R_ESP] & 0xffff; - ssp = env->segs[R_SS].base + esp; + esp = env->regs[R_ESP]; + ssp = env->segs[R_SS].base; if (is_int) old_eip = next_eip; else old_eip = env->eip; old_cs = env->segs[R_CS].selector; - ssp -= 2; - stw(ssp, compute_eflags()); - ssp -= 2; - stw(ssp, old_cs); - ssp -= 2; - stw(ssp, old_eip); - esp -= 6; + esp -= 2; + stw(ssp + (esp & 0xffff), compute_eflags()); + esp -= 2; + stw(ssp + (esp & 0xffff), old_cs); + esp -= 2; + stw(ssp + (esp & 0xffff), old_eip); /* update processor state */ env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); @@ -733,47 +732,275 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) } /* protected mode jump */ -void jmp_seg(int selector, unsigned int new_eip) +void helper_ljmp_protected_T0_T1(void) { + int new_cs, new_eip; SegmentCache sc1; uint32_t e1, e2, cpl, dpl, rpl; - if ((selector & 0xfffc) == 0) { + new_cs = T0; + new_eip = T1; + if ((new_cs & 0xfffc) == 0) raise_exception_err(EXCP0D_GPF, 0); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpl = env->segs[R_CS].selector & 3; + if (e2 & DESC_S_MASK) { + if (!(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_CS_MASK) { + /* conforming code segment */ + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } else { + /* non conforming code segment */ + rpl = new_cs & 3; + if (rpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (dpl != cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + load_seg_cache(&sc1, e1, e2); + if (new_eip > sc1.limit) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + env->segs[R_CS].base = sc1.base; + env->segs[R_CS].limit = sc1.limit; + env->segs[R_CS].flags = sc1.flags; + env->segs[R_CS].selector = (new_cs & 0xfffc) | cpl; + EIP = new_eip; + } else { + cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", + new_cs, new_eip); } +} - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); +/* real mode call */ +void helper_lcall_real_T0_T1(int shift, int next_eip) +{ + int new_cs, new_eip; + uint32_t esp, esp_mask; + uint8_t *ssp; + + new_cs = T0; + new_eip = T1; + esp = env->regs[R_ESP]; + esp_mask = 0xffffffff; + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + esp_mask = 0xffff; + ssp = env->segs[R_SS].base; + if (shift) { + esp -= 4; + stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); + esp -= 4; + stl(ssp + (esp & esp_mask), next_eip); + } else { + esp -= 2; + stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); + esp -= 2; + stw(ssp + (esp & esp_mask), next_eip); + } + + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); + else + env->regs[R_ESP] = esp; + env->eip = new_eip; + env->segs[R_CS].selector = new_cs; + env->segs[R_CS].base = (uint8_t *)(new_cs << 4); +} + +/* protected mode call */ +void helper_lcall_protected_T0_T1(int shift, int next_eip) +{ + int new_cs, new_eip; + SegmentCache sc1; + uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; + uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; + uint32_t old_ss, old_esp, val, i; + uint8_t *ssp, *old_ssp; + + new_cs = T0; + new_eip = T1; + if ((new_cs & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); cpl = env->segs[R_CS].selector & 3; if (e2 & DESC_S_MASK) { if (!(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (e2 & DESC_CS_MASK) { /* conforming code segment */ if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); } else { /* non conforming code segment */ - rpl = selector & 3; + rpl = new_cs & 3; if (rpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); if (dpl != cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); } if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + + sp = env->regs[R_ESP]; + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + sp &= 0xffff; + ssp = env->segs[R_SS].base + sp; + if (shift) { + ssp -= 4; + stl(ssp, env->segs[R_CS].selector); + ssp -= 4; + stl(ssp, next_eip); + } else { + ssp -= 2; + stw(ssp, env->segs[R_CS].selector); + ssp -= 2; + stw(ssp, next_eip); + } + sp -= (4 << shift); + load_seg_cache(&sc1, e1, e2); if (new_eip > sc1.limit) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + /* from this point, not restartable */ + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | (sp & 0xffff); + else + env->regs[R_ESP] = sp; env->segs[R_CS].base = sc1.base; env->segs[R_CS].limit = sc1.limit; env->segs[R_CS].flags = sc1.flags; - env->segs[R_CS].selector = (selector & 0xfffc) | cpl; + env->segs[R_CS].selector = (new_cs & 0xfffc) | cpl; EIP = new_eip; } else { - cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", - selector, new_eip); + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + switch(type) { + case 1: /* available 286 TSS */ + case 9: /* available 386 TSS */ + case 5: /* task gate */ + cpu_abort(env, "task gate not supported"); + break; + case 4: /* 286 call gate */ + case 12: /* 386 call gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + break; + } + shift = type >> 3; + + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + rpl = new_cs & 3; + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + selector = e1 >> 16; + offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); + if ((selector & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + + if (!(e2 & DESC_C_MASK) && dpl < cpl) { + /* to inner priviledge */ + get_ss_esp_from_tss(&ss, &sp, dpl); + if ((ss & 0xfffc) == 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if ((ss & 3) != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, ss) != 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (ss_dpl != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + + param_count = e2 & 0x1f; + push_size = ((param_count * 2) + 8) << shift; + + old_esp = env->regs[R_ESP]; + old_ss = env->segs[R_SS].selector; + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + old_esp &= 0xffff; + old_ssp = env->segs[R_SS].base + old_esp; + + /* XXX: from this point not restartable */ + load_seg(R_SS, ss, env->eip); + + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + sp &= 0xffff; + ssp = env->segs[R_SS].base + sp; + if (shift) { + ssp -= 4; + stl(ssp, old_ss); + ssp -= 4; + stl(ssp, old_esp); + ssp -= 4 * param_count; + for(i = 0; i < param_count; i++) { + val = ldl(old_ssp + i * 4); + stl(ssp + i * 4, val); + } + } else { + ssp -= 2; + stw(ssp, old_ss); + ssp -= 2; + stw(ssp, old_esp); + ssp -= 2 * param_count; + for(i = 0; i < param_count; i++) { + val = lduw(old_ssp + i * 2); + stw(ssp + i * 2, val); + } + } + } else { + /* to same priviledge */ + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + sp &= 0xffff; + ssp = env->segs[R_SS].base + sp; + push_size = (4 << shift); + } + + if (shift) { + ssp -= 4; + stl(ssp, env->segs[R_CS].selector); + ssp -= 4; + stl(ssp, next_eip); + } else { + ssp -= 2; + stw(ssp, env->segs[R_CS].selector); + ssp -= 2; + stw(ssp, next_eip); + } + + sp -= push_size; + load_seg(R_CS, selector, env->eip); + /* from this point, not restartable if same priviledge */ + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | (sp & 0xffff); + else + env->regs[R_ESP] = sp; + EIP = offset; } } @@ -820,7 +1047,7 @@ void helper_iret_real(int shift) } /* protected mode iret */ -void helper_iret_protected(int shift) +static inline void helper_ret_protected(int shift, int is_iret, int addend) { uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; uint32_t new_es, new_ds, new_fs, new_gs; @@ -834,14 +1061,16 @@ void helper_iret_protected(int shift) ssp = env->segs[R_SS].base + sp; if (shift == 1) { /* 32 bits */ - new_eflags = ldl(ssp + 8); + if (is_iret) + new_eflags = ldl(ssp + 8); new_cs = ldl(ssp + 4) & 0xffff; new_eip = ldl(ssp); - if (new_eflags & VM_MASK) + if (is_iret && (new_eflags & VM_MASK)) goto return_to_vm86; } else { /* 16 bits */ - new_eflags = lduw(ssp + 4); + if (is_iret) + new_eflags = lduw(ssp + 4); new_cs = lduw(ssp + 2); new_eip = lduw(ssp); } @@ -870,17 +1099,18 @@ void helper_iret_protected(int shift) if (rpl == cpl) { /* return to same priledge level */ load_seg(R_CS, new_cs, env->eip); - new_esp = sp + (6 << shift); + new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; } else { - /* return to differentr priviledge level */ + /* return to different priviledge level */ + ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; if (shift == 1) { /* 32 bits */ - new_esp = ldl(ssp + 12); - new_ss = ldl(ssp + 16) & 0xffff; + new_esp = ldl(ssp); + new_ss = ldl(ssp + 4) & 0xffff; } else { /* 16 bits */ - new_esp = lduw(ssp + 6); - new_ss = lduw(ssp + 8); + new_esp = lduw(ssp); + new_ss = lduw(ssp + 2); } if ((new_ss & 3) != rpl) @@ -906,13 +1136,15 @@ void helper_iret_protected(int shift) env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | (new_esp & 0xffff); env->eip = new_eip; - if (cpl == 0) - eflags_mask = FL_UPDATE_CPL0_MASK; - else - eflags_mask = FL_UPDATE_MASK32; - if (shift == 0) - eflags_mask &= 0xffff; - load_eflags(new_eflags, eflags_mask); + if (is_iret) { + if (cpl == 0) + eflags_mask = FL_UPDATE_CPL0_MASK; + else + eflags_mask = FL_UPDATE_MASK32; + if (shift == 0) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); + } return; return_to_vm86: @@ -936,6 +1168,16 @@ void helper_iret_protected(int shift) env->regs[R_ESP] = new_esp; } +void helper_iret_protected(int shift) +{ + helper_ret_protected(shift, 1, 0); +} + +void helper_lret_protected(int shift, int addend) +{ + helper_ret_protected(shift, 0, addend); +} + void helper_movl_crN_T0(int reg) { env->cr[reg] = T0; diff --git a/op-i386.c b/op-i386.c index ff8cb4415..fb062a0fc 100644 --- a/op-i386.c +++ b/op-i386.c @@ -948,9 +948,19 @@ void OPPROTO op_lar(void) } /* T0: segment, T1:eip */ -void OPPROTO op_ljmp_T0_T1(void) +void OPPROTO op_ljmp_protected_T0_T1(void) { - jmp_seg(T0 & 0xffff, T1); + helper_ljmp_protected_T0_T1(); +} + +void OPPROTO op_lcall_real_T0_T1(void) +{ + helper_lcall_real_T0_T1(PARAM1, PARAM2); +} + +void OPPROTO op_lcall_protected_T0_T1(void) +{ + helper_lcall_protected_T0_T1(PARAM1, PARAM2); } void OPPROTO op_iret_real(void) @@ -963,6 +973,11 @@ void OPPROTO op_iret_protected(void) helper_iret_protected(PARAM1); } +void OPPROTO op_lret_protected(void) +{ + helper_lret_protected(PARAM1, PARAM2); +} + void OPPROTO op_lldt_T0(void) { helper_lldt_T0(); diff --git a/translate-i386.c b/translate-i386.c index 7fce0e24b..820cc65c3 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1832,19 +1832,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->is_jmp = 1; break; case 3: /* lcall Ev */ - /* push return segment + offset */ - gen_op_movl_T0_seg(R_CS); - gen_push_T0(s); - next_eip = s->pc - s->cs_base; - gen_op_movl_T0_im(next_eip); - gen_push_T0(s); - gen_op_ld_T1_A0[ot](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_lduw_T0_A0(); - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - gen_op_movl_T0_T1(); - gen_op_jmp_T0(); + do_lcall: + if (s->pe && !s->vm86) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base); + } else { + gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); + } s->is_jmp = 1; break; case 4: /* jmp Ev */ @@ -1857,10 +1856,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_ld_T1_A0[ot](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_lduw_T0_A0(); + do_ljmp: if (s->pe && !s->vm86) { - /* we compute EIP to handle the exception case */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_jmp_im(pc_start - s->cs_base); - gen_op_ljmp_T0_T1(); + gen_op_ljmp_protected_T0_T1(); } else { gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); gen_op_movl_T0_T1(); @@ -2867,7 +2868,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_string_ds(s, ot, gen_op_movs + 9); } else { gen_string_ds(s, ot, gen_op_movs); @@ -2881,7 +2882,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_string_es(s, ot, gen_op_stos + 9); } else { gen_string_es(s, ot, gen_op_stos); @@ -2893,7 +2894,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_string_ds(s, ot, gen_op_lods + 9); } else { gen_string_ds(s, ot, gen_op_lods); @@ -2952,7 +2953,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_string_es(s, ot, gen_op_ins + 9); } else { gen_string_es(s, ot, gen_op_ins); @@ -2969,7 +2970,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_string_ds(s, ot, gen_op_outs + 9); } else { gen_string_ds(s, ot, gen_op_outs); @@ -3062,20 +3063,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = ldsw(s->pc); s->pc += 2; do_lret: - gen_stack_A0(s); - /* pop offset */ - gen_op_ld_T0_A0[1 + s->dflag](); - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - /* NOTE: keeping EIP updated is not a problem in case of - exception */ - gen_op_jmp_T0(); - /* pop selector */ - gen_op_addl_A0_im(2 << s->dflag); - gen_op_ld_T0_A0[1 + s->dflag](); - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - /* add stack offset */ - gen_stack_update(s, val + (4 << s->dflag)); + if (s->pe && !s->vm86) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lret_protected(s->dflag, val); + } else { + gen_stack_A0(s); + /* pop offset */ + gen_op_ld_T0_A0[1 + s->dflag](); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + /* NOTE: keeping EIP updated is not a problem in case of + exception */ + gen_op_jmp_T0(); + /* pop selector */ + gen_op_addl_A0_im(2 << s->dflag); + gen_op_ld_T0_A0[1 + s->dflag](); + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + /* add stack offset */ + gen_stack_update(s, val + (4 << s->dflag)); + } s->is_jmp = 1; break; case 0xcb: /* lret */ @@ -3114,26 +3122,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x9a: /* lcall im */ { unsigned int selector, offset; - /* XXX: not restartable */ ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); - /* push return segment + offset */ - gen_op_movl_T0_seg(R_CS); - gen_push_T0(s); - next_eip = s->pc - s->cs_base; - gen_op_movl_T0_im(next_eip); - gen_push_T0(s); - - /* change cs and pc */ gen_op_movl_T0_im(selector); - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); - gen_op_jmp_im((unsigned long)offset); - s->is_jmp = 1; + gen_op_movl_T1_im(offset); } - break; + goto do_lcall; case 0xe9: /* jmp */ ot = dflag ? OT_LONG : OT_WORD; val = insn_get(s, ot); @@ -3150,20 +3147,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); - /* change cs and pc */ gen_op_movl_T0_im(selector); - if (s->pe && !s->vm86) { - /* we compute EIP to handle the exception case */ - gen_op_jmp_im(pc_start - s->cs_base); - gen_op_movl_T1_im(offset); - gen_op_ljmp_T0_T1(); - } else { - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); - gen_op_jmp_im((unsigned long)offset); - } - s->is_jmp = 1; + gen_op_movl_T1_im(offset); } - break; + goto do_ljmp; case 0xeb: /* jmp Jb */ val = (int8_t)insn_get(s, OT_BYTE); val += s->pc - s->cs_base; -- cgit v1.2.3 From 61a2ad53cb6337eb2c535984f65f1cb531ccc452 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 27 Jul 2003 22:19:00 +0000 Subject: refresh clock dummy emulation (netbsd boot fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@341 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index fb27e3b46..a7e117f3e 100644 --- a/vl.c +++ b/vl.c @@ -858,6 +858,7 @@ typedef struct PITChannelState { PITChannelState pit_channels[3]; int speaker_data_on; +int dummy_refresh_clock; int pit_min_timer_count = 0; int64_t ticks_per_sec; @@ -1115,7 +1116,9 @@ uint32_t speaker_ioport_read(CPUX86State *env, uint32_t addr) { int out; out = pit_get_out(&pit_channels[2]); - return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5); + dummy_refresh_clock ^= 1; + return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | + (dummy_refresh_clock << 4); } void pit_init(void) -- cgit v1.2.3 From c33a346edff5910dddeea84792b73cb117518911 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Jul 2003 20:50:33 +0000 Subject: first part of single stepping support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@342 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + exec.c | 17 ++++++++++++++++- gdbstub.c | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index 787a054a4..cde8451dd 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -315,6 +315,7 @@ void cpu_interrupt(CPUState *s, int mask); int cpu_breakpoint_insert(CPUState *env, uint32_t pc); int cpu_breakpoint_remove(CPUState *env, uint32_t pc); +void cpu_single_step(CPUState *env, int enabled); /* gdb stub API */ extern int gdbstub_fd; diff --git a/exec.c b/exec.c index fc0a0cf7a..5ea216325 100644 --- a/exec.c +++ b/exec.c @@ -617,7 +617,8 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } -/* add a breakpoint */ +/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a + breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) { #if defined(TARGET_I386) @@ -659,6 +660,20 @@ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) #endif } +/* enable or disable single step mode. EXCP_DEBUG is returned by the + CPU loop after each instruction */ +void cpu_single_step(CPUState *env, int enabled) +{ +#if defined(TARGET_I386) + if (env->singlestep_enabled != enabled) { + env->singlestep_enabled = enabled; + /* must flush all the translated code to avoid inconsistancies */ + tb_flush(); + } +#endif +} + + /* mask must never be zero */ void cpu_interrupt(CPUState *env, int mask) { diff --git a/gdbstub.c b/gdbstub.c index d255eab6d..61cb6b1ab 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -324,6 +324,24 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(buf); break; + case 's': + env = cpu_gdbstub_get_env(opaque); + if (*p != '\0') { + addr = strtoul(p, (char **)&p, 16); +#if defined(TARGET_I386) + env->eip = addr; +#endif + } + cpu_single_step(env, 1); + ret = main_loop(opaque); + cpu_single_step(env, 0); + if (ret == EXCP_DEBUG) + ret = SIGTRAP; + else + ret = 0; + snprintf(buf, sizeof(buf), "S%02x", ret); + put_packet(buf); + break; case 'g': env = cpu_gdbstub_get_env(opaque); registers = (void *)mem_buf; -- cgit v1.2.3 From b6d78bfa0dc11a7a23cb7ccc9b00b217e6fb68fe Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 29 Jul 2003 20:53:01 +0000 Subject: correct CPL support (should fix flat real mode support) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@343 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 9 ++------- cpu-i386.h | 8 ++++++++ helper-i386.c | 31 +++++++++++++++---------------- translate-i386.c | 10 ++-------- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 1ffeb8e86..d478fa826 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -244,13 +244,8 @@ int cpu_exec(CPUState *env1) (unsigned long)env->segs[R_ES].base | (unsigned long)env->segs[R_SS].base) != 0) << GEN_FLAG_ADDSEG_SHIFT; - if (env->cr[0] & CR0_PE_MASK) { - if (!(env->eflags & VM_MASK)) - flags |= (env->segs[R_CS].selector & 3) << - GEN_FLAG_CPL_SHIFT; - else - flags |= (1 << GEN_FLAG_VM_SHIFT); - } + flags |= env->cpl << GEN_FLAG_CPL_SHIFT; + flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT); flags |= (env->eflags & (IOPL_MASK | TF_MASK)); cs_base = env->segs[R_CS].base; pc = cs_base + env->eip; diff --git a/cpu-i386.h b/cpu-i386.h index 82cdffc25..879ab1eb8 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -256,6 +256,7 @@ typedef struct CPUX86State { SegmentCache tr; SegmentCache gdt; /* only base and limit are used */ SegmentCache idt; /* only base and limit are used */ + int cpl; /* current cpl */ /* sysenter registers */ uint32_t sysenter_cs; @@ -276,6 +277,7 @@ typedef struct CPUX86State { uint32_t breakpoints[MAX_BREAKPOINTS]; int nb_breakpoints; + int singlestep_enabled; /* user data */ void *opaque; @@ -298,6 +300,12 @@ int cpu_x86_get_pic_interrupt(CPUX86State *s); /* needed to load some predefinied segment registers */ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); +/* wrapper, just in case memory mappings must be changed */ +static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) +{ + s->cpl = cpl; +} + /* simulate fsave/frstor */ void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); diff --git a/helper-i386.c b/helper-i386.c index d3a931681..0003fb46a 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -189,7 +189,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, { SegmentCache *dt; uint8_t *ptr, *ssp; - int type, dpl, cpl, selector, ss_dpl; + int type, dpl, selector, ss_dpl; int has_error_code, new_stack, shift; uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; uint32_t old_cs, old_ss, old_esp, old_eip; @@ -216,12 +216,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, break; } dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (env->eflags & VM_MASK) - cpl = 3; - else - cpl = env->segs[R_CS].selector & 3; /* check privledge if software int */ - if (is_int && dpl < cpl) + if (is_int && dpl < env->cpl) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); /* check valid bit */ if (!(e2 & DESC_P_MASK)) @@ -236,11 +232,11 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > cpl) + if (dpl > env->cpl) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - if (!(e2 & DESC_C_MASK) && dpl < cpl) { + if (!(e2 & DESC_C_MASK) && dpl < env->cpl) { /* to inner priviledge */ get_ss_esp_from_tss(&ss, &esp, dpl); if ((ss & 0xfffc) == 0) @@ -259,7 +255,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); new_stack = 1; - } else if ((e2 & DESC_C_MASK) || dpl == cpl) { + } else if ((e2 & DESC_C_MASK) || dpl == env->cpl) { /* to same priviledge */ new_stack = 0; } else { @@ -406,7 +402,7 @@ void do_interrupt_user(int intno, int is_int, int error_code, { SegmentCache *dt; uint8_t *ptr; - int dpl, cpl; + int dpl; uint32_t e2; dt = &env->idt; @@ -414,9 +410,8 @@ void do_interrupt_user(int intno, int is_int, int error_code, e2 = ldl(ptr + 4); dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = 3; /* check privledge if software int */ - if (is_int && dpl < cpl) + if (is_int && dpl < env->cpl) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); /* Since we emulate only user space, we cannot do more than @@ -728,6 +723,9 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) selector, (unsigned long)sc->base, sc->limit, sc->flags); #endif } + if (seg_reg == R_CS) { + cpu_x86_set_cpl(env, selector & 3); + } sc->selector = selector; } @@ -744,7 +742,7 @@ void helper_ljmp_protected_T0_T1(void) raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, new_cs) != 0) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->segs[R_CS].selector & 3; + cpl = env->cpl; if (e2 & DESC_S_MASK) { if (!(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -828,7 +826,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, new_cs) != 0) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->segs[R_CS].selector & 3; + cpl = env->cpl; if (e2 & DESC_S_MASK) { if (!(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -1081,7 +1079,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if (!(e2 & DESC_S_MASK) || !(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->segs[R_CS].selector & 3; + cpl = env->cpl; rpl = new_cs & 3; if (rpl < cpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -1158,12 +1156,13 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) /* modify processor state */ load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); load_seg_vm(R_CS, new_cs); + cpu_x86_set_cpl(env, 3); load_seg_vm(R_SS, new_ss); load_seg_vm(R_ES, new_es); load_seg_vm(R_DS, new_ds); load_seg_vm(R_FS, new_fs); load_seg_vm(R_GS, new_gs); - + env->eip = new_eip; env->regs[R_ESP] = new_esp; } diff --git a/translate-i386.c b/translate-i386.c index 820cc65c3..dd4a8a486 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -4113,13 +4113,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; - /* CPL is implicit if real mode or vm86 mode */ - if (!dc->pe) - dc->cpl = 0; - else if (dc->vm86) - dc->cpl = 3; - else - dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; + dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3; dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; dc->cc_op = CC_OP_DYNAMIC; @@ -4362,7 +4356,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) int cpl, error_code, is_dirty, is_user, prot, page_size; void *map_addr; - cpl = env->segs[R_CS].selector & 3; + cpl = env->cpl; is_user = (cpl == 3); #ifdef DEBUG_MMU -- cgit v1.2.3 From e89f66eca974d2a9d5d89271c6041daefdab2105 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 4 Aug 2003 23:30:47 +0000 Subject: Hardware level VGA emulation (only text mode is tested) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@344 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 1236 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/vga_template.h | 294 +++++++++++++ 2 files changed, 1530 insertions(+) create mode 100644 hw/vga.c create mode 100644 hw/vga_template.h diff --git a/hw/vga.c b/hw/vga.c new file mode 100644 index 000000000..7e08e6150 --- /dev/null +++ b/hw/vga.c @@ -0,0 +1,1236 @@ +/* + * QEMU VGA Emulator. An S3 86c968 is emulated + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu-i386.h" +#include "exec.h" + +#include "vl.h" + +#define NO_THUNK_TYPE_SIZE +#include "thunk.h" + +//#define DEBUG_VGA + +#define MSR_COLOR_EMULATION 0x01 +#define MSR_PAGE_SELECT 0x20 + +#define ST01_V_RETRACE 0x08 +#define ST01_DISP_ENABLE 0x01 + +typedef struct VGAState { + uint8_t *vram_ptr; + unsigned long vram_offset; + unsigned int vram_size; + uint32_t latch; + uint8_t sr_index; + uint8_t sr[8]; + uint8_t gr_index; + uint8_t gr[16]; + uint8_t ar_index; + uint8_t ar[21]; + int ar_flip_flop; + uint8_t cr_index; + uint8_t cr[256]; /* CRT registers */ + uint8_t msr; /* Misc Output Register */ + uint8_t fcr; /* Feature Control Register */ + uint8_t st00; /* status 0 */ + uint8_t st01; /* status 1 */ + uint8_t dac_state; + uint8_t dac_sub_index; + uint8_t dac_read_index; + uint8_t dac_write_index; + uint8_t dac_cache[3]; /* used when writing */ + uint8_t palette[768]; + + /* display refresh support */ + /* tell for each page if it has been updated since the last time */ + DisplayState *ds; + uint32_t font_offsets[2]; + int graphic_mode; + int shift_control; + uint32_t line_offset; + uint32_t line_compare; + uint32_t start_addr; + uint8_t last_cw, last_ch; + uint32_t last_width, last_height; + uint8_t cursor_start, cursor_end; + uint32_t cursor_offset; + uint8_t vram_updated[VGA_RAM_SIZE / 4096]; + uint32_t last_palette[256]; +#define CH_ATTR_SIZE (132 * 60) + uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ +} VGAState; + +/* force some bits to zero */ +static const uint8_t sr_mask[8] = { + (uint8_t)~0xfc, + (uint8_t)~0xc2, + (uint8_t)~0xf0, + (uint8_t)~0xc0, + (uint8_t)~0xf1, + (uint8_t)~0xff, + (uint8_t)~0xff, + (uint8_t)~0x00, +}; + +static const uint8_t gr_mask[16] = { + (uint8_t)~0xf0, /* 0x00 */ + (uint8_t)~0xf0, /* 0x01 */ + (uint8_t)~0xf0, /* 0x02 */ + (uint8_t)~0xe0, /* 0x03 */ + (uint8_t)~0xfc, /* 0x04 */ + (uint8_t)~0x84, /* 0x05 */ + (uint8_t)~0xf0, /* 0x06 */ + (uint8_t)~0xf0, /* 0x07 */ + (uint8_t)~0x00, /* 0x08 */ + (uint8_t)~0xff, /* 0x09 */ + (uint8_t)~0xff, /* 0x0a */ + (uint8_t)~0xff, /* 0x0b */ + (uint8_t)~0xff, /* 0x0c */ + (uint8_t)~0xff, /* 0x0d */ + (uint8_t)~0xff, /* 0x0e */ + (uint8_t)~0xff, /* 0x0f */ +}; + +#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 WORD_BIGENDIAN +#define PAT(x) cbswap_32(x) +#else +#define PAT(x) (x) +#endif + +static const uint32_t mask16[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), +}; + +#undef PAT + +#ifdef WORD_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 expand4[256]; +static uint16_t expand2[256]; + +VGAState vga_state; +int vga_io_memory; + +static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr) +{ + VGAState *s = &vga_state; + int val, index; + + /* check port range access depending on color/monochrome mode */ + if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || + (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) { + val = 0xff; + } else { + switch(addr) { + case 0x3c0: + if (s->ar_flip_flop == 0) { + val = s->ar_index; + } else { + val = 0; + } + break; + case 0x3c1: + index = s->ar_index & 0x1f; + if (index < 21) + val = s->ar[index]; + else + val = 0; + break; + case 0x3c2: + val = s->st00; + break; + case 0x3c4: + val = s->sr_index; + break; + case 0x3c5: + val = s->sr[s->sr_index]; + break; + case 0x3c7: + val = s->dac_state; + break; + case 0x3c9: + val = s->palette[s->dac_read_index * 3 + s->dac_sub_index]; + if (++s->dac_sub_index == 3) { + s->dac_sub_index = 0; + s->dac_read_index++; + } + break; + case 0x3ca: + val = s->fcr; + break; + case 0x3cc: + val = s->msr; + break; + case 0x3ce: + val = s->gr_index; + break; + case 0x3cf: + val = s->gr[s->gr_index]; + break; + case 0x3b4: + case 0x3d4: + val = s->cr_index; + break; + case 0x3b5: + case 0x3d5: + val = s->cr[s->cr_index]; + break; + case 0x3ba: + case 0x3da: + /* just toggle to fool polling */ + s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; + val = s->st01; + s->ar_flip_flop = 0; + break; + default: + val = 0x00; + break; + } + } +#ifdef DEBUG_VGA + printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val); +#endif + return val; +} + +static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + VGAState *s = &vga_state; + int index, v; + + /* check port range access depending on color/monochrome mode */ + if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || + (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) + return; + +#ifdef DEBUG_VGA + printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val); +#endif + + switch(addr) { + case 0x3c0: + if (s->ar_flip_flop == 0) { + val &= 0x3f; + s->ar_index = val; + } else { + index = s->ar_index & 0x1f; + switch(index) { + case 0x00 ... 0x0f: + s->ar[index] = val & 0x3f; + break; + case 0x10: + s->ar[index] = val & ~0x10; + break; + case 0x11: + s->ar[index] = val; + break; + case 0x12: + s->ar[index] = val & ~0xc0; + break; + case 0x13: + s->ar[index] = val & ~0xf0; + break; + case 0x14: + s->ar[index] = val & ~0xf0; + break; + default: + break; + } + } + s->ar_flip_flop ^= 1; + break; + case 0x3c2: + s->msr = val & ~0x10; + break; + case 0x3c4: + s->sr_index = val & 7; + break; + case 0x3c5: + s->sr[s->sr_index] = val & sr_mask[s->sr_index]; + break; + case 0x3c7: + s->dac_read_index = val; + s->dac_sub_index = 0; + s->dac_state = 3; + break; + case 0x3c8: + s->dac_write_index = val; + s->dac_sub_index = 0; + s->dac_state = 0; + break; + case 0x3c9: + s->dac_cache[s->dac_sub_index] = val; + if (++s->dac_sub_index == 3) { + memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3); + s->dac_sub_index = 0; + s->dac_write_index++; + } + break; + case 0x3ce: + s->gr_index = val & 0x0f; + break; + case 0x3cf: + s->gr[s->gr_index] = val & gr_mask[s->gr_index]; + break; + case 0x3b4: + case 0x3d4: + s->cr_index = val; + break; + case 0x3b5: + case 0x3d5: + /* handle CR0-7 protection */ + if ((s->cr[11] & 0x80) && s->cr_index <= 7) { + /* can always write bit 4 of CR7 */ + if (s->cr_index == 7) + s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); + return; + } + switch(s->cr_index) { + case 0x01: /* horizontal display end */ + case 0x07: + case 0x09: + case 0x0c: + case 0x0d: + case 0x12: /* veritcal display end */ + s->cr[s->cr_index] = val; + break; + + /* S3 registers */ + case 0x2d: + case 0x2e: + case 0x2f: + case 0x30: + /* chip ID, cannot write */ + break; + case 0x31: + /* update start address */ + s->cr[s->cr_index] = val; + v = (val >> 4) & 3; + s->cr[0x69] = (s->cr[69] & ~0x03) | v; + break; + case 0x51: + /* update start address */ + s->cr[s->cr_index] = val; + v = val & 3; + s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2); + break; + default: + s->cr[s->cr_index] = val; + break; + } + break; + case 0x3ba: + case 0x3da: + s->fcr = val & 0x10; + break; + } +} + +/* called for accesses between 0xa0000 and 0xc0000 */ +static uint32_t vga_mem_readb(uint32_t addr) +{ + VGAState *s = &vga_state; + int memory_map_mode, plane; + uint32_t ret; + + /* convert to VGA memory offset */ + memory_map_mode = (s->gr[6] >> 2) & 3; + switch(memory_map_mode) { + case 0: + addr -= 0xa0000; + break; + case 1: + addr -= 0xa0000; + if (addr >= 0x10000) + return 0xff; + break; + case 2: + addr -= 0xb0000; + if (addr >= 0x8000) + return 0xff; + break; + default: + case 3: + addr -= 0xb8000; + break; + } + + if (s->sr[4] & 0x08) { + /* chain 4 mode : simplest access */ + ret = s->vram_ptr[addr]; + } else if (s->gr[5] & 0x10) { + /* odd/even mode (aka text mode mapping) */ + plane = (s->gr[4] & 2) | (addr & 1); + ret = s->vram_ptr[((addr & ~1) << 1) | plane]; + } else { + /* standard VGA latched access */ + s->latch = ((uint32_t *)s->vram_ptr)[addr]; + + if (!(s->gr[5] & 0x08)) { + /* read mode 0 */ + plane = s->gr[4]; +#ifdef WORD_BIGENDIAN + ret = (s->latch >> (24 - (plane * 8))) & 0xff; +#else + ret = (s->latch >> (plane * 8)) & 0xff; +#endif + } else { + /* read mode 1 */ + ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]]; + ret |= ret >> 16; + ret |= ret >> 8; + ret = (~ret) & 0xff; + } + } + return ret; +} + +static uint32_t vga_mem_readw(uint32_t addr) +{ + uint32_t v; + v = vga_mem_readb(addr); + v |= vga_mem_readb(addr + 1) << 8; + return v; +} + +static uint32_t vga_mem_readl(uint32_t addr) +{ + uint32_t v; + v = vga_mem_readb(addr); + v |= vga_mem_readb(addr + 1) << 8; + v |= vga_mem_readb(addr + 2) << 16; + v |= vga_mem_readb(addr + 3) << 24; + return v; +} + + +/* called for accesses between 0xa0000 and 0xc0000 */ +void vga_mem_writeb(uint32_t addr, uint32_t val) +{ + VGAState *s = &vga_state; + int memory_map_mode, plane, write_mode, b, func_select; + uint32_t write_mask, bit_mask, set_mask; + +#ifdef DEBUG_VGA + printf("vga: [0x%x] = 0x%02x\n", addr, val); +#endif + /* convert to VGA memory offset */ + memory_map_mode = (s->gr[6] >> 2) & 3; + switch(memory_map_mode) { + case 0: + addr -= 0xa0000; + break; + case 1: + addr -= 0xa0000; + if (addr >= 0x10000) + return; + break; + case 2: + addr -= 0xb0000; + if (addr >= 0x8000) + return; + break; + default: + case 3: + addr -= 0xb8000; + break; + } + + if (s->sr[4] & 0x08) { + /* chain 4 mode : simplest access */ + plane = addr & 3; + if (s->sr[2] & (1 << plane)) { + s->vram_ptr[addr] = val; +#ifdef DEBUG_VGA + printf("vga: chain4: [0x%x]\n", addr); +#endif + s->vram_updated[addr >> 12] = 1; + } + } else if (s->gr[5] & 0x10) { + /* odd/even mode (aka text mode mapping) */ + plane = (s->gr[4] & 2) | (addr & 1); + if (s->sr[2] & (1 << plane)) { + addr = ((addr & ~1) << 1) | plane; + s->vram_ptr[addr] = val; +#ifdef DEBUG_VGA + printf("vga: odd/even: [0x%x]\n", addr); +#endif + s->vram_updated[addr >> 12] = 1; + } + } else { + /* standard VGA latched access */ + write_mode = s->gr[5] & 3; + switch(write_mode) { + default: + case 0: + /* rotate */ + b = s->gr[3] & 7; + val = ((val >> b) | (val << (8 - b))) & 0xff; + val |= val << 8; + val |= val << 16; + + /* apply set/reset mask */ + set_mask = mask16[s->gr[1]]; + val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask); + bit_mask = s->gr[8]; + break; + case 1: + val = s->latch; + goto do_write; + case 2: + val = mask16[val & 0x0f]; + bit_mask = s->gr[8]; + break; + case 3: + /* rotate */ + b = s->gr[3] & 7; + val = ((val >> b) | (val << (8 - b))); + + bit_mask = s->gr[8] & val; + val = mask16[s->gr[0]]; + break; + } + + /* apply logical operation */ + func_select = s->gr[3] >> 3; + switch(func_select) { + case 0: + default: + /* nothing to do */ + break; + case 1: + /* and */ + val &= s->latch; + break; + case 2: + /* or */ + val |= s->latch; + break; + case 3: + /* xor */ + val ^= s->latch; + break; + } + + /* apply bit mask */ + bit_mask |= bit_mask << 8; + bit_mask |= bit_mask << 16; + val = (val & bit_mask) | (s->latch & ~bit_mask); + + do_write: + /* mask data according to sr[2] */ + write_mask = mask16[s->sr[2]]; + ((uint32_t *)s->vram_ptr)[addr] = + (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | + (val & write_mask); +#ifdef DEBUG_VGA + printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", + addr * 4, write_mask, val); +#endif + s->vram_updated[addr >> 10] = 1; + } +} + +void vga_mem_writew(uint32_t addr, uint32_t val) +{ + vga_mem_writeb(addr, val & 0xff); + vga_mem_writeb(addr + 1, (val >> 8) & 0xff); +} + +void vga_mem_writel(uint32_t addr, uint32_t val) +{ + vga_mem_writeb(addr, val & 0xff); + vga_mem_writeb(addr + 1, (val >> 8) & 0xff); + vga_mem_writeb(addr + 2, (val >> 16) & 0xff); + vga_mem_writeb(addr + 3, (val >> 24) & 0xff); +} + +#ifdef WORD_BIGENDIAN +#define BIG 1 +#else +#define BIG 0 +#endif + +#ifdef WORDS_BIGENDIAN +#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff) +#else +#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff) +#endif + +typedef void vga_draw_glyph8_func(uint8_t *d, int linesize, + const uint8_t *font_ptr, int h, + uint32_t fgcol, uint32_t bgcol); +typedef void vga_draw_glyph9_func(uint8_t *d, int linesize, + const uint8_t *font_ptr, int h, + uint32_t fgcol, uint32_t bgcol, int dup9); +typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, + const uint8_t *s, int width); + +static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) +{ + /* XXX: TODO */ + return 0; +} + +static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); +} + +static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); +} + +static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) +{ + return (r << 16) | (g << 8) | b; +} + +#define DEPTH 8 +#include "vga_template.h" + +#define DEPTH 15 +#include "vga_template.h" + +#define DEPTH 16 +#include "vga_template.h" + +#define DEPTH 32 +#include "vga_template.h" + +static inline int c6_to_8(int v) +{ + int b; + v &= 0x3f; + b = v & 1; + return (v << 2) | (b << 1) | b; +} + +/* return true if the palette was modified */ +static int update_palette16(VGAState *s) +{ + int full_update, i, depth; + uint32_t v, col, *palette; + unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); + depth = s->ds->depth; + switch(depth) { + case 8: + rgb_to_pixel = rgb_to_pixel8; + break; + case 15: + rgb_to_pixel = rgb_to_pixel15; + break; + default: + case 16: + rgb_to_pixel = rgb_to_pixel16; + break; + case 32: + rgb_to_pixel = rgb_to_pixel32; + break; + } + + full_update = 0; + palette = s->last_palette; + for(i = 0; i < 16; i++) { + v = s->ar[i]; + if (s->ar[0x10] & 0x80) + v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf); + else + v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); + v = v * 3; + col = rgb_to_pixel(c6_to_8(s->palette[v]), + c6_to_8(s->palette[v + 1]), + c6_to_8(s->palette[v + 2])); + + if (depth == 8) { + col |= col << 8; + col |= col << 16; + } else if (depth <= 16) { + col |= col << 16; + } + // printf("%2d: %08x\n", i, col); + if (col != palette[i]) { + full_update = 1; + palette[i] = col; + } + } + return full_update; +} + +/* update start_addr and line_offset. Return TRUE if modified */ +static int update_basic_params(VGAState *s) +{ + int full_update; + uint32_t start_addr, line_offset, line_compare, v; + + full_update = 0; + /* compute line_offset in bytes */ + v = (s->cr[0x51] >> 4) & 3; /* S3 extension */ + if (v == 0) + v = (s->cr[0x43] >> 2) & 1; /* S3 extension */ + line_offset = s->cr[0x13] | (v << 8); + line_offset <<= 3; +#if 0 + /* XXX: check this - inconsistent with some VGA docs */ + if (s->cr[0x14] & 0x40) + line_offset <<= 2; + else if (!(s->cr[0x17] & 0x40)) + line_offset <<= 1; +#endif + /* starting address */ + start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); + start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */ + + /* line compare */ + line_compare = s->cr[0x18] | + ((s->cr[0x07] & 0x10) << 4) | + ((s->cr[0x09] & 0x40) << 3); + + if (line_offset != s->line_offset || + start_addr != s->start_addr || + line_compare != s->line_compare) { + s->line_offset = line_offset; + s->start_addr = start_addr; + s->line_compare = line_compare; + full_update = 1; + } + return full_update; +} + +static inline int get_depth_index(int depth) +{ + switch(depth) { + default: + case 8: + return 0; + case 15: + return 1; + case 16: + return 2; + case 32: + return 3; + } +} + +static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = { + vga_draw_glyph8_8, + vga_draw_glyph8_16, + vga_draw_glyph8_16, + vga_draw_glyph8_32, +}; + +static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = { + vga_draw_glyph9_8, + vga_draw_glyph9_16, + vga_draw_glyph9_16, + vga_draw_glyph9_32, +}; + +static const uint8_t cursor_glyph[32 * 4] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +/* + * Text mode update + * Missing: + * - double scan + * - double width + * - underline + * - flashing + */ +static void vga_draw_text(VGAState *s, int full_update) +{ + int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr; + int cx_min, cx_max, linesize, x_incr; + uint32_t offset, fgcol, bgcol, v, cursor_offset; + uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr; + const uint8_t *font_ptr, *font_base[2]; + int dup9, line_offset, depth_index; + uint32_t *palette; + uint32_t *ch_attr_ptr; + vga_draw_glyph8_func *vga_draw_glyph8; + vga_draw_glyph9_func *vga_draw_glyph9; + + full_update |= update_palette16(s); + palette = s->last_palette; + + /* compute font data address (in plane 2) */ + v = s->sr[3]; + offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2; + if (offset != s->font_offsets[0]) { + s->font_offsets[0] = offset; + full_update = 1; + } + font_base[0] = s->vram_ptr + offset; + + offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; + font_base[1] = s->vram_ptr + offset; + if (offset != s->font_offsets[1]) { + s->font_offsets[1] = offset; + full_update = 1; + } + + full_update |= update_basic_params(s); + + line_offset = s->line_offset; + s1 = s->vram_ptr + (s->start_addr * 4); + + /* total width & height */ + cheight = (s->cr[9] & 0x1f) + 1; + cw = 8; + if (s->sr[1] & 0x01) + cw = 9; + x_incr = cw * ((s->ds->depth + 7) >> 3); + width = (s->cr[0x01] + 1); + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | + ((s->cr[0x07] & 0x40) << 3); + height = (height + 1) / cheight; + if (width != s->last_width || height != s->last_height || + cw != s->last_cw || cw != s->last_cw) { + dpy_resize(s->ds, width * cw, height * cheight); + s->last_width = width; + s->last_height = height; + s->last_ch = cheight; + s->last_cw = cw; + full_update = 1; + } + cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; + if (cursor_offset != s->cursor_offset || + s->cr[0xa] != s->cursor_start || + s->cr[0xb] != s->cursor_end) { + /* if the cursor position changed, we update the old and new + chars */ + if (s->cursor_offset < CH_ATTR_SIZE) + s->last_ch_attr[s->cursor_offset] = -1; + if (cursor_offset < CH_ATTR_SIZE) + s->last_ch_attr[cursor_offset] = -1; + s->cursor_offset = cursor_offset; + s->cursor_start = s->cr[0xa]; + s->cursor_end = s->cr[0xb]; + } + cursor_ptr = s->vram_ptr + cursor_offset * 4; + + depth_index = get_depth_index(s->ds->depth); + vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; + vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; + + dest = s->ds->data; + linesize = s->ds->linesize; + ch_attr_ptr = s->last_ch_attr; + for(cy = 0; cy < height; cy++) { + d1 = dest; + src = s1; + cx_min = width; + cx_max = -1; + for(cx = 0; cx < width; cx++) { + ch_attr = *(uint16_t *)src; + if (full_update || ch_attr != *ch_attr_ptr) { + if (cx < cx_min) + cx_min = cx; + if (cx > cx_max) + cx_max = cx; + *ch_attr_ptr = ch_attr; +#ifdef WORDS_BIGENDIAN + ch = ch_attr >> 8; + cattr = ch_attr & 0xff; +#else + ch = ch_attr & 0xff; + cattr = ch_attr >> 8; +#endif + font_ptr = font_base[(cattr >> 3) & 1]; + font_ptr += 32 * 4 * ch; + bgcol = palette[cattr >> 4]; + fgcol = palette[cattr & 0x0f]; + if (cw == 8) { + vga_draw_glyph8(d1, linesize, + font_ptr, cheight, fgcol, bgcol); + } else { + dup9 = 0; + if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04)) + dup9 = 1; + vga_draw_glyph9(d1, linesize, + font_ptr, cheight, fgcol, bgcol, dup9); + } + if (src == cursor_ptr && + !(s->cr[0x0a] & 0x20)) { + int line_start, line_last, h; + /* draw the cursor */ + line_start = s->cr[0x0a] & 0x1f; + line_last = s->cr[0x0b] & 0x1f; + /* XXX: check that */ + if (line_last > cheight - 1) + line_last = cheight - 1; + if (line_last >= line_start && line_start < cheight) { + h = line_last - line_start + 1; + d = d1 + linesize * line_start; + if (cw == 8) { + vga_draw_glyph8(d, linesize, + cursor_glyph, h, fgcol, bgcol); + } else { + vga_draw_glyph9(d, linesize, + cursor_glyph, h, fgcol, bgcol, 1); + } + } + } + } + d1 += x_incr; + src += 4; + ch_attr_ptr++; + } + if (cx_max != -1) { + dpy_update(s->ds, cx_min * cw, cy * cheight, + (cx_max - cx_min + 1) * cw, cheight); + } + dest += linesize * cheight; + s1 += line_offset; + } +} + +static vga_draw_line_func *vga_draw_line_table[4 * 6] = { + vga_draw_line2_8, + vga_draw_line2_16, + vga_draw_line2_16, + vga_draw_line2_32, + + vga_draw_line4_8, + vga_draw_line4_16, + vga_draw_line4_16, + vga_draw_line4_32, + + vga_draw_line8_8, + vga_draw_line8_16, + vga_draw_line8_16, + vga_draw_line8_32, + + vga_draw_line15_8, + vga_draw_line15_15, + vga_draw_line15_16, + vga_draw_line15_32, + + vga_draw_line16_8, + vga_draw_line16_15, + vga_draw_line16_16, + vga_draw_line16_32, + + vga_draw_line32_8, + vga_draw_line32_15, + vga_draw_line32_16, + vga_draw_line32_32, +}; + +/* + * graphic modes + * Missing: + * - double scan + * - double width + */ +static void vga_draw_graphic(VGAState *s, int full_update) +{ + int y, update, y_min, y_max, page_min, page_max, linesize; + int width, height, shift_control, line_offset, page0, page1; + uint8_t *d; + uint32_t v, *palette, addr1, addr; + vga_draw_line_func *vga_draw_line; + + full_update |= update_palette16(s); + palette = s->last_palette; + + full_update |= update_basic_params(s); + + width = (s->cr[0x01] + 1); + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | + ((s->cr[0x07] & 0x40) << 3); + height = (height + 1); + + if (width != s->last_width || + height != s->last_height) { + s->last_width = width; + s->last_height = height; + full_update = 1; + } + + shift_control = (s->gr[0x05] >> 5) & 3; + if (shift_control != s->shift_control) { + full_update = 1; + s->shift_control = shift_control; + } + + if (shift_control == 0) + v = 1; /* 4 bit/pxeil */ + else if (shift_control == 1) + v = 0; /* 2 bit/pixel */ + else + v = 2; /* 8 bit/pixel */ + + vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; + + line_offset = s->line_offset; + addr1 = (s->start_addr * 4); + y_min = height; + y_max = -1; + page_min = 0x7fffffff; + page_max = -1; + d = s->ds->data; + linesize = s->ds->linesize; + for(y = 0; y < height; y++) { + addr = addr1; + if (s->cr[0x17] & 1) { + /* CGA compatibility handling */ + addr = (addr & ~0x2000) | ((y & 1) << 13); + } + if (s->cr[0x17] & 2) { + addr = (addr & ~0x4000) | ((y & 2) << 13); + } + page0 = addr >> 12; + page1 = (addr + width - 1) >> 12; + update = full_update | s->vram_updated[page0] | s->vram_updated[page1]; + if (update) { + if (y < y_min) + y_min = y; + if (y > y_max) + y_max = y; + if (page0 < page_min) + page_min = page0; + if (page1 > page_max) + page_max = page1; + vga_draw_line(s, d, s->vram_ptr + addr, width); + } + if (y == s->line_compare) { + addr1 = 0; + } else { + addr1 += line_offset; + } + d += linesize; + } + + /* reset modified pages */ + if (page_max != -1) { + memset(s->vram_updated + page_min, 0, page_max - page_min + 1); + } +} + +/* draw text terminal (very limited, just for simple boot debug + messages) */ +static int last_cursor_pos; + +void vga_draw_dumb(VGAState *s) +{ + int c, i, cursor_pos, eol; + + cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8); + eol = 0; + for(i = last_cursor_pos; i < cursor_pos; i++) { + /* XXX: should use vga RAM */ + c = phys_ram_base[0xb8000 + (i) * 2]; + if (c >= ' ') { + putchar(c); + eol = 0; + } else { + if (!eol) + putchar('\n'); + eol = 1; + } + } + fflush(stdout); + last_cursor_pos = cursor_pos; +} + +void vga_update_display(void) +{ + VGAState *s = &vga_state; + int full_update, graphic_mode; + + if (s->ds->depth == 0) { + vga_draw_dumb(s); + } else { + full_update = 0; + graphic_mode = s->gr[6] & 1; + if (graphic_mode != s->graphic_mode) { + s->graphic_mode = graphic_mode; + full_update = 1; + } + if (graphic_mode) + vga_draw_graphic(s, full_update); + else + vga_draw_text(s, full_update); + } +} + +void vga_reset(VGAState *s) +{ + memset(s, 0, sizeof(VGAState)); + /* chip ID for 8c968 */ + s->cr[0x2d] = 0x88; + s->cr[0x2e] = 0xb0; + s->cr[0x2f] = 0x01; /* XXX: check revision code */ + s->cr[0x30] = 0xe1; + s->graphic_mode = -1; /* force full update */ +} + +CPUReadMemoryFunc *vga_mem_read[3] = { + vga_mem_readb, + vga_mem_readw, + vga_mem_readl, +}; + +CPUWriteMemoryFunc *vga_mem_write[3] = { + vga_mem_writeb, + vga_mem_writew, + vga_mem_writel, +}; + +int vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size) +{ + VGAState *s = &vga_state; + int i, j, v; + + for(i = 0;i < 256; i++) { + v = 0; + for(j = 0; j < 8; j++) { + v |= ((i >> j) & 1) << (j * 4); + } + expand4[i] = v; + + v = 0; + for(j = 0; j < 4; j++) { + v |= ((i >> (2 * j)) & 3) << (j * 4); + } + expand2[i] = v; + } + + vga_reset(s); + + s->vram_ptr = vga_ram_base; + s->vram_offset = vga_ram_offset; + s->vram_size = vga_ram_size; + s->ds = ds; + + register_ioport_write(0x3c0, 16, vga_ioport_write, 1); + + register_ioport_write(0x3b4, 2, vga_ioport_write, 1); + register_ioport_write(0x3d4, 2, vga_ioport_write, 1); + register_ioport_write(0x3ba, 1, vga_ioport_write, 1); + register_ioport_write(0x3da, 1, vga_ioport_write, 1); + + register_ioport_read(0x3c0, 16, vga_ioport_read, 1); + + register_ioport_read(0x3b4, 2, vga_ioport_read, 1); + register_ioport_read(0x3d4, 2, vga_ioport_read, 1); + register_ioport_read(0x3ba, 1, vga_ioport_read, 1); + register_ioport_read(0x3da, 1, vga_ioport_read, 1); + + vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); + cpu_register_physical_memory(0xa0000, 0x20000, vga_io_memory); + return 0; +} diff --git a/hw/vga_template.h b/hw/vga_template.h new file mode 100644 index 000000000..dd6581e37 --- /dev/null +++ b/hw/vga_template.h @@ -0,0 +1,294 @@ +/* + * QEMU VGA Emulator templates + * + * 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. + */ + +#if DEPTH == 8 +#define BPP 1 +#define PIXEL_TYPE uint8_t +#elif DEPTH == 15 || DEPTH == 16 +#define BPP 2 +#define PIXEL_TYPE uint16_t +#elif DEPTH == 32 +#define BPP 4 +#define PIXEL_TYPE uint32_t +#else +#error unsupport depth +#endif + +#if DEPTH != 15 + +static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, + const uint8_t *font_ptr, int h, + uint32_t fgcol, uint32_t bgcol) +{ + uint32_t font_data, xorcol; + + xorcol = bgcol ^ fgcol; + do { + font_data = font_ptr[0]; +#if BPP == 1 + ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; + ((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; +#elif BPP == 2 + ((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; +#else + ((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; +#endif + font_ptr += 4; + d += linesize; + } while (--h); +} + +static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, + const uint8_t *font_ptr, int h, + uint32_t fgcol, uint32_t bgcol, int dup9) +{ + uint32_t font_data, xorcol, v; + + xorcol = bgcol ^ fgcol; + do { + font_data = font_ptr[0]; + /* XXX: unaligned accesses are done */ +#if BPP == 1 + ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; + v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; + ((uint32_t *)d)[3] = v; + if (dup9) + *(uint8_t *)(d + 8) = v >> (24 * (1 - BIG)); + else + *(uint8_t *)(d + 8) = bgcol; + +#elif BPP == 2 + ((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; + v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; + ((uint32_t *)d)[3] = v; + if (dup9) + *(uint16_t *)(d + 8) = v >> (16 * (1 - BIG)); + else + *(uint16_t *)(d + 8) = bgcol; +#else + ((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; + v = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol; + ((uint32_t *)d)[7] = v; + if (dup9) + *(uint32_t *)(d + 8) = v; + else + *(uint32_t *)(d + 8) = bgcol; +#endif + font_ptr += 4; + d += linesize; + } while (--h); +} + +/* + * 4 color mode + */ +static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + uint32_t plane_mask, *palette, data, v; + int x; + + palette = s1->last_palette; + plane_mask = mask16[s1->ar[0x12] & 0xf]; + width >>= 3; + for(x = 0; x < width; x++) { + data = ((uint32_t *)s)[0]; + data &= plane_mask; + v = expand2[GET_PLANE(data, 0)]; + v |= expand2[GET_PLANE(data, 2)] << 2; + ((PIXEL_TYPE *)d)[0] = palette[v >> 12]; + ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf]; + ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf]; + ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf]; + + v = expand2[GET_PLANE(data, 1)]; + v |= expand2[GET_PLANE(data, 3)] << 2; + ((PIXEL_TYPE *)d)[4] = palette[v >> 12]; + ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf]; + ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf]; + ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf]; + d += BPP * 8; + s += 4; + } +} + +/* + * 16 color mode + */ +static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + uint32_t plane_mask, data, v, *palette; + int x; + + palette = s1->last_palette; + plane_mask = mask16[s1->ar[0x12] & 0xf]; + width >>= 3; + for(x = 0; x < width; x++) { + data = ((uint32_t *)s)[0]; + data &= plane_mask; + v = expand4[GET_PLANE(data, 0)]; + v |= expand4[GET_PLANE(data, 1)] << 1; + v |= expand4[GET_PLANE(data, 2)] << 2; + v |= expand4[GET_PLANE(data, 3)] << 3; + ((PIXEL_TYPE *)d)[0] = palette[v >> 28]; + ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf]; + ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf]; + ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf]; + ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf]; + ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf]; + ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf]; + ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf]; + d += BPP * 8; + s += 4; + } +} + +/* + * 256 color mode + * + * XXX: add plane_mask support (never used in standard VGA modes) + */ +static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + uint32_t *palette; + int x; + + palette = s1->last_palette; + width >>= 3; + for(x = 0; x < width; x++) { + ((PIXEL_TYPE *)d)[0] = palette[s[0]]; + ((PIXEL_TYPE *)d)[1] = palette[s[1]]; + ((PIXEL_TYPE *)d)[2] = palette[s[2]]; + ((PIXEL_TYPE *)d)[3] = palette[s[3]]; + ((PIXEL_TYPE *)d)[4] = palette[s[4]]; + ((PIXEL_TYPE *)d)[5] = palette[s[5]]; + ((PIXEL_TYPE *)d)[6] = palette[s[6]]; + ((PIXEL_TYPE *)d)[7] = palette[s[7]]; + d += BPP * 8; + s += 8; + } +} + +#endif /* DEPTH != 15 */ + + +/* XXX: optimize */ + +/* + * 15 bit color + */ +static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ +#if DEPTH == 15 && !defined(WORDS_BIGENDIAN) + memcpy(d, s, width * 2); +#else + int w; + uint32_t v, r, g, b; + + w = width; + do { + v = lduw((void *)s); + r = (v >> 7) & 0xf8; + g = (v >> 2) & 0xf8; + b = (v << 3) & 0xf8; + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + s += 2; + d += BPP; + } while (--w != 0); +#endif +} + +/* + * 16 bit color + */ +static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ +#if DEPTH == 16 && !defined(WORDS_BIGENDIAN) + memcpy(d, s, width * 2); +#else + int w; + uint32_t v, r, g, b; + + w = width; + do { + v = lduw((void *)s); + r = (v >> 8) & 0xf8; + g = (v >> 3) & 0xfc; + b = (v << 3) & 0xf8; + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + s += 2; + d += BPP; + } while (--w != 0); +#endif +} + +/* + * 32 bit color + */ +static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ +#if DEPTH == 32 && !defined(WORDS_BIGENDIAN) + memcpy(d, s, width * 4); +#else + int w; + uint32_t r, g, b; + + w = width; + do { + b = s[0]; + g = s[1]; + r = s[2]; + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + s += 4; + d += BPP; + } while (--w != 0); +#endif +} + +#undef DEPTH +#undef BPP +#undef PIXEL_TYPE -- cgit v1.2.3 From 39cf7803273871207ec06a0d162e181998ccc384 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 5 Aug 2003 23:06:22 +0000 Subject: fixed graphical VGA 16 color mode - fixed 9 pixel wide text mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@345 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 58 ++++++++++++++++++++++++++++++------------------------- hw/vga_template.h | 12 ++++++------ 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 7e08e6150..97270bf0a 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -82,7 +82,6 @@ typedef struct VGAState { uint8_t palette[768]; /* display refresh support */ - /* tell for each page if it has been updated since the last time */ DisplayState *ds; uint32_t font_offsets[2]; int graphic_mode; @@ -94,6 +93,7 @@ typedef struct VGAState { uint32_t last_width, last_height; uint8_t cursor_start, cursor_end; uint32_t cursor_offset; + /* tell for each page if it has been updated since the last time */ uint8_t vram_updated[VGA_RAM_SIZE / 4096]; uint32_t last_palette[256]; #define CH_ATTR_SIZE (132 * 60) @@ -763,13 +763,7 @@ static int update_basic_params(VGAState *s) v = (s->cr[0x43] >> 2) & 1; /* S3 extension */ line_offset = s->cr[0x13] | (v << 8); line_offset <<= 3; -#if 0 - /* XXX: check this - inconsistent with some VGA docs */ - if (s->cr[0x14] & 0x40) - line_offset <<= 2; - else if (!(s->cr[0x17] & 0x40)) - line_offset <<= 1; -#endif + /* starting address */ start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */ @@ -917,7 +911,7 @@ static void vga_draw_text(VGAState *s, int full_update) s->cursor_start = s->cr[0xa]; s->cursor_end = s->cr[0xb]; } - cursor_ptr = s->vram_ptr + cursor_offset * 4; + cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; depth_index = get_depth_index(s->ds->depth); vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; @@ -1035,18 +1029,17 @@ static vga_draw_line_func *vga_draw_line_table[4 * 6] = { */ static void vga_draw_graphic(VGAState *s, int full_update) { - int y, update, y_min, y_max, page_min, page_max, linesize; - int width, height, shift_control, line_offset, page0, page1; + int y, update, page_min, page_max, linesize, y_start; + int width, height, shift_control, line_offset, page0, page1, bwidth; uint8_t *d; - uint32_t v, *palette, addr1, addr; + uint32_t v, addr1, addr; vga_draw_line_func *vga_draw_line; full_update |= update_palette16(s); - palette = s->last_palette; full_update |= update_basic_params(s); - width = (s->cr[0x01] + 1); + width = (s->cr[0x01] + 1) * 8; height = s->cr[0x12] | ((s->cr[0x07] & 0x02) << 7) | ((s->cr[0x07] & 0x40) << 3); @@ -1054,6 +1047,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) if (width != s->last_width || height != s->last_height) { + dpy_resize(s->ds, width, height); s->last_width = width; s->last_height = height; full_update = 1; @@ -1066,44 +1060,52 @@ static void vga_draw_graphic(VGAState *s, int full_update) } if (shift_control == 0) - v = 1; /* 4 bit/pxeil */ + v = 1; /* 4 bit/pixel */ else if (shift_control == 1) v = 0; /* 2 bit/pixel */ else v = 2; /* 8 bit/pixel */ - vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; line_offset = s->line_offset; addr1 = (s->start_addr * 4); - y_min = height; - y_max = -1; + bwidth = width * 4; + y_start = -1; page_min = 0x7fffffff; page_max = -1; d = s->ds->data; linesize = s->ds->linesize; for(y = 0; y < height; y++) { addr = addr1; - if (s->cr[0x17] & 1) { + if (!(s->cr[0x17] & 1)) { /* CGA compatibility handling */ addr = (addr & ~0x2000) | ((y & 1) << 13); } - if (s->cr[0x17] & 2) { + if (!(s->cr[0x17] & 2)) { addr = (addr & ~0x4000) | ((y & 2) << 13); } page0 = addr >> 12; - page1 = (addr + width - 1) >> 12; + page1 = (addr + bwidth - 1) >> 12; update = full_update | s->vram_updated[page0] | s->vram_updated[page1]; + if ((page1 - page0) > 1) { + /* if wide line, can use another page */ + update |= s->vram_updated[page0 + 1]; + } if (update) { - if (y < y_min) - y_min = y; - if (y > y_max) - y_max = y; + if (y_start < 0) + y_start = y; if (page0 < page_min) page_min = page0; if (page1 > page_max) page_max = page1; vga_draw_line(s, d, s->vram_ptr + addr, width); + } else { + if (y_start >= 0) { + /* flush to display */ + dpy_update(s->ds, 0, y_start, + width, y - y_start); + y_start = -1; + } } if (y == s->line_compare) { addr1 = 0; @@ -1112,7 +1114,11 @@ static void vga_draw_graphic(VGAState *s, int full_update) } d += linesize; } - + if (y_start >= 0) { + /* flush to display */ + dpy_update(s->ds, 0, y_start, + width, y - y_start); + } /* reset modified pages */ if (page_max != -1) { memset(s->vram_updated + page_min, 0, page_max - page_min + 1); diff --git a/hw/vga_template.h b/hw/vga_template.h index dd6581e37..2f658b4d1 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -84,9 +84,9 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; ((uint32_t *)d)[3] = v; if (dup9) - *(uint8_t *)(d + 8) = v >> (24 * (1 - BIG)); + ((uint8_t *)d)[8] = v >> (24 * (1 - BIG)); else - *(uint8_t *)(d + 8) = bgcol; + ((uint8_t *)d)[8] = bgcol; #elif BPP == 2 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; @@ -95,9 +95,9 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; ((uint32_t *)d)[3] = v; if (dup9) - *(uint16_t *)(d + 8) = v >> (16 * (1 - BIG)); + ((uint16_t *)d)[8] = v >> (16 * (1 - BIG)); else - *(uint16_t *)(d + 8) = bgcol; + ((uint16_t *)d)[8] = bgcol; #else ((uint32_t *)d)[0] = ((-(font_data >> 7)) & xorcol) ^ bgcol; ((uint32_t *)d)[1] = ((-(font_data >> 6) & 1) & xorcol) ^ bgcol; @@ -109,9 +109,9 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, v = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol; ((uint32_t *)d)[7] = v; if (dup9) - *(uint32_t *)(d + 8) = v; + ((uint32_t *)d)[8] = v; else - *(uint32_t *)(d + 8) = bgcol; + ((uint32_t *)d)[8] = bgcol; #endif font_ptr += 4; d += linesize; -- cgit v1.2.3 From 17b0018b4200b674bfcb7c946fce89f0a5ffaa24 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 8 Aug 2003 23:50:57 +0000 Subject: Full VGA support, including old CGA modes, VGA planar and mode X git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@346 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 277 ++++++++++++++++++++++++++++++++++++++++-------------- hw/vga_template.h | 144 ++++++++++++++++++++++++++-- 2 files changed, 340 insertions(+), 81 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 97270bf0a..0ed8abf24 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -49,6 +49,7 @@ #include "thunk.h" //#define DEBUG_VGA +//#define DEBUG_VGA_MEM #define MSR_COLOR_EMULATION 0x01 #define MSR_PAGE_SELECT 0x20 @@ -85,7 +86,8 @@ typedef struct VGAState { DisplayState *ds; uint32_t font_offsets[2]; int graphic_mode; - int shift_control; + uint8_t shift_control; + uint8_t double_scan; uint32_t line_offset; uint32_t line_compare; uint32_t start_addr; @@ -93,10 +95,11 @@ typedef struct VGAState { uint32_t last_width, last_height; uint8_t cursor_start, cursor_end; uint32_t cursor_offset; + unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); /* tell for each page if it has been updated since the last time */ uint8_t vram_updated[VGA_RAM_SIZE / 4096]; uint32_t last_palette[256]; -#define CH_ATTR_SIZE (132 * 60) +#define CH_ATTR_SIZE (160 * 100) uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ } VGAState; @@ -199,6 +202,7 @@ static const uint32_t dmask4[4] = { static uint32_t expand4[256]; static uint16_t expand2[256]; +static uint8_t expand4to8[16]; VGAState vga_state; int vga_io_memory; @@ -503,7 +507,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) int memory_map_mode, plane, write_mode, b, func_select; uint32_t write_mask, bit_mask, set_mask; -#ifdef DEBUG_VGA +#ifdef DEBUG_VGA_MEM printf("vga: [0x%x] = 0x%02x\n", addr, val); #endif /* convert to VGA memory offset */ @@ -533,7 +537,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) plane = addr & 3; if (s->sr[2] & (1 << plane)) { s->vram_ptr[addr] = val; -#ifdef DEBUG_VGA +#ifdef DEBUG_VGA_MEM printf("vga: chain4: [0x%x]\n", addr); #endif s->vram_updated[addr >> 12] = 1; @@ -544,7 +548,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) if (s->sr[2] & (1 << plane)) { addr = ((addr & ~1) << 1) | plane; s->vram_ptr[addr] = val; -#ifdef DEBUG_VGA +#ifdef DEBUG_VGA_MEM printf("vga: odd/even: [0x%x]\n", addr); #endif s->vram_updated[addr >> 12] = 1; @@ -615,7 +619,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) ((uint32_t *)s->vram_ptr)[addr] = (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | (val & write_mask); -#ifdef DEBUG_VGA +#ifdef DEBUG_VGA_MEM printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", addr * 4, write_mask, val); #endif @@ -699,28 +703,43 @@ static inline int c6_to_8(int v) return (v << 2) | (b << 1) | b; } +static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel8(r, g, b); + col |= col << 8; + col |= col << 16; + return col; +} + +static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel15(r, g, b); + col |= col << 16; + return col; +} + +static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel16(r, g, b); + col |= col << 16; + return col; +} + +static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel32(r, g, b); + return col; +} + /* return true if the palette was modified */ static int update_palette16(VGAState *s) { - int full_update, i, depth; + int full_update, i; uint32_t v, col, *palette; - unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); - depth = s->ds->depth; - switch(depth) { - case 8: - rgb_to_pixel = rgb_to_pixel8; - break; - case 15: - rgb_to_pixel = rgb_to_pixel15; - break; - default: - case 16: - rgb_to_pixel = rgb_to_pixel16; - break; - case 32: - rgb_to_pixel = rgb_to_pixel32; - break; - } full_update = 0; palette = s->last_palette; @@ -731,21 +750,35 @@ static int update_palette16(VGAState *s) else v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); v = v * 3; - col = rgb_to_pixel(c6_to_8(s->palette[v]), - c6_to_8(s->palette[v + 1]), - c6_to_8(s->palette[v + 2])); - - if (depth == 8) { - col |= col << 8; - col |= col << 16; - } else if (depth <= 16) { - col |= col << 16; + col = s->rgb_to_pixel(c6_to_8(s->palette[v]), + c6_to_8(s->palette[v + 1]), + c6_to_8(s->palette[v + 2])); + if (col != palette[i]) { + full_update = 1; + palette[i] = col; } - // printf("%2d: %08x\n", i, col); + } + return full_update; +} + +/* return true if the palette was modified */ +static int update_palette256(VGAState *s) +{ + int full_update, i; + uint32_t v, col, *palette; + + full_update = 0; + palette = s->last_palette; + v = 0; + for(i = 0; i < 256; i++) { + col = s->rgb_to_pixel(c6_to_8(s->palette[v]), + c6_to_8(s->palette[v + 1]), + c6_to_8(s->palette[v + 2])); if (col != palette[i]) { full_update = 1; palette[i] = col; } + v += 3; } return full_update; } @@ -806,6 +839,13 @@ static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = { vga_draw_glyph8_32, }; +static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = { + vga_draw_glyph16_8, + vga_draw_glyph16_16, + vga_draw_glyph16_16, + vga_draw_glyph16_32, +}; + static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = { vga_draw_glyph9_8, vga_draw_glyph9_16, @@ -882,12 +922,19 @@ static void vga_draw_text(VGAState *s, int full_update) cw = 8; if (s->sr[1] & 0x01) cw = 9; + if (s->sr[1] & 0x08) + cw = 16; /* NOTE: no 18 pixel wide */ x_incr = cw * ((s->ds->depth + 7) >> 3); width = (s->cr[0x01] + 1); - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); - height = (height + 1) / cheight; + if (s->cr[0x06] == 100) { + /* ugly hack for CGA 160x100x16 - explain me the logic */ + height = 100; + } else { + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | + ((s->cr[0x07] & 0x40) << 3); + height = (height + 1) / cheight; + } if (width != s->last_width || height != s->last_height || cw != s->last_cw || cw != s->last_cw) { dpy_resize(s->ds, width * cw, height * cheight); @@ -914,7 +961,10 @@ static void vga_draw_text(VGAState *s, int full_update) cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; depth_index = get_depth_index(s->ds->depth); - vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; + if (cw == 16) + vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; + else + vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; dest = s->ds->data; @@ -944,7 +994,7 @@ static void vga_draw_text(VGAState *s, int full_update) font_ptr += 32 * 4 * ch; bgcol = palette[cattr >> 4]; fgcol = palette[cattr & 0x0f]; - if (cw == 8) { + if (cw != 9) { vga_draw_glyph8(d1, linesize, font_ptr, cheight, fgcol, bgcol); } else { @@ -966,7 +1016,7 @@ static void vga_draw_text(VGAState *s, int full_update) if (line_last >= line_start && line_start < cheight) { h = line_last - line_start + 1; d = d1 + linesize * line_start; - if (cw == 8) { + if (cw != 9) { vga_draw_glyph8(d, linesize, cursor_glyph, h, fgcol, bgcol); } else { @@ -989,17 +1039,45 @@ static void vga_draw_text(VGAState *s, int full_update) } } -static vga_draw_line_func *vga_draw_line_table[4 * 6] = { +enum { + VGA_DRAW_LINE2, + VGA_DRAW_LINE2D2, + VGA_DRAW_LINE4, + VGA_DRAW_LINE4D2, + VGA_DRAW_LINE8D2, + VGA_DRAW_LINE8, + VGA_DRAW_LINE15, + VGA_DRAW_LINE16, + VGA_DRAW_LINE32, + VGA_DRAW_LINE_NB, +}; + +static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = { vga_draw_line2_8, vga_draw_line2_16, vga_draw_line2_16, vga_draw_line2_32, + vga_draw_line2d2_8, + vga_draw_line2d2_16, + vga_draw_line2d2_16, + vga_draw_line2d2_32, + vga_draw_line4_8, vga_draw_line4_16, vga_draw_line4_16, vga_draw_line4_32, + vga_draw_line4d2_8, + vga_draw_line4d2_16, + vga_draw_line4d2_16, + vga_draw_line4d2_32, + + vga_draw_line8d2_8, + vga_draw_line8d2_16, + vga_draw_line8d2_16, + vga_draw_line8d2_32, + vga_draw_line8_8, vga_draw_line8_16, vga_draw_line8_16, @@ -1029,14 +1107,13 @@ static vga_draw_line_func *vga_draw_line_table[4 * 6] = { */ static void vga_draw_graphic(VGAState *s, int full_update) { - int y, update, page_min, page_max, linesize, y_start; + int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask; int width, height, shift_control, line_offset, page0, page1, bwidth; + int disp_width; uint8_t *d; uint32_t v, addr1, addr; vga_draw_line_func *vga_draw_line; - - full_update |= update_palette16(s); - + full_update |= update_basic_params(s); width = (s->cr[0x01] + 1) * 8; @@ -1044,30 +1121,53 @@ static void vga_draw_graphic(VGAState *s, int full_update) ((s->cr[0x07] & 0x02) << 7) | ((s->cr[0x07] & 0x40) << 3); height = (height + 1); - - if (width != s->last_width || - height != s->last_height) { - dpy_resize(s->ds, width, height); - s->last_width = width; - s->last_height = height; - full_update = 1; - } - + disp_width = width; + shift_control = (s->gr[0x05] >> 5) & 3; - if (shift_control != s->shift_control) { + double_scan = (s->cr[0x09] & 0x80); + if (shift_control != s->shift_control || + double_scan != s->double_scan) { full_update = 1; s->shift_control = shift_control; + s->double_scan = double_scan; } - if (shift_control == 0) - v = 1; /* 4 bit/pixel */ - else if (shift_control == 1) - v = 0; /* 2 bit/pixel */ - else - v = 2; /* 8 bit/pixel */ + if (shift_control == 0) { + full_update |= update_palette16(s); + if (s->sr[0x01] & 8) { + v = VGA_DRAW_LINE4D2; + disp_width <<= 1; + } else { + v = VGA_DRAW_LINE4; + } + } else if (shift_control == 1) { + full_update |= update_palette16(s); + if (s->sr[0x01] & 8) { + v = VGA_DRAW_LINE2D2; + disp_width <<= 1; + } else { + v = VGA_DRAW_LINE2; + } + } else { + full_update |= update_palette256(s); + v = VGA_DRAW_LINE8D2; + double_scan = 1; /* XXX: explain me why it is always activated */ + } vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; - + + if (disp_width != s->last_width || + height != s->last_height) { + dpy_resize(s->ds, disp_width, height); + s->last_width = disp_width; + s->last_height = height; + full_update = 1; + } + line_offset = s->line_offset; +#if 0 + printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n", + width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]); +#endif addr1 = (s->start_addr * 4); bwidth = width * 4; y_start = -1; @@ -1075,14 +1175,17 @@ static void vga_draw_graphic(VGAState *s, int full_update) page_max = -1; d = s->ds->data; linesize = s->ds->linesize; + y1 = 0; for(y = 0; y < height; y++) { addr = addr1; if (!(s->cr[0x17] & 1)) { + int shift; /* CGA compatibility handling */ - addr = (addr & ~0x2000) | ((y & 1) << 13); + shift = 14 + ((s->cr[0x17] >> 6) & 1); + addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift); } if (!(s->cr[0x17] & 2)) { - addr = (addr & ~0x4000) | ((y & 2) << 13); + addr = (addr & ~0x8000) | ((y1 & 2) << 14); } page0 = addr >> 12; page1 = (addr + bwidth - 1) >> 12; @@ -1103,21 +1206,26 @@ static void vga_draw_graphic(VGAState *s, int full_update) if (y_start >= 0) { /* flush to display */ dpy_update(s->ds, 0, y_start, - width, y - y_start); + disp_width, y - y_start); y_start = -1; } } - if (y == s->line_compare) { - addr1 = 0; - } else { - addr1 += line_offset; + if (!double_scan || (y & 1) != 0) { + if (y1 == s->line_compare) { + addr1 = 0; + } else { + mask = (s->cr[0x17] & 3) ^ 3; + if ((y1 & mask) == mask) + addr1 += line_offset; + } + y1++; } d += linesize; } if (y_start >= 0) { /* flush to display */ dpy_update(s->ds, 0, y_start, - width, y - y_start); + disp_width, y - y_start); } /* reset modified pages */ if (page_max != -1) { @@ -1199,7 +1307,7 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { VGAState *s = &vga_state; - int i, j, v; + int i, j, v, b; for(i = 0;i < 256; i++) { v = 0; @@ -1214,9 +1322,34 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, } expand2[i] = v; } + for(i = 0; i < 16; i++) { + v = 0; + for(j = 0; j < 4; j++) { + b = ((i >> j) & 1); + v |= b << (2 * j); + v |= b << (2 * j + 1); + } + expand4to8[i] = v; + } vga_reset(s); + switch(ds->depth) { + case 8: + s->rgb_to_pixel = rgb_to_pixel8_dup; + break; + case 15: + s->rgb_to_pixel = rgb_to_pixel15_dup; + break; + default: + case 16: + s->rgb_to_pixel = rgb_to_pixel16_dup; + break; + case 32: + s->rgb_to_pixel = rgb_to_pixel32_dup; + break; + } + s->vram_ptr = vga_ram_base; s->vram_offset = vga_ram_offset; s->vram_size = vga_ram_size; diff --git a/hw/vga_template.h b/hw/vga_template.h index 2f658b4d1..ac2e6258a 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -37,15 +37,11 @@ #if DEPTH != 15 -static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, - const uint8_t *font_ptr, int h, - uint32_t fgcol, uint32_t bgcol) +static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, + uint32_t font_data, + uint32_t xorcol, + uint32_t bgcol) { - uint32_t font_data, xorcol; - - xorcol = bgcol ^ fgcol; - do { - font_data = font_ptr[0]; #if BPP == 1 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; ((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; @@ -64,6 +60,38 @@ static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, ((uint32_t *)d)[6] = ((-(font_data >> 1) & 1) & xorcol) ^ bgcol; ((uint32_t *)d)[7] = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol; #endif +} + +static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, + const uint8_t *font_ptr, int h, + uint32_t fgcol, uint32_t bgcol) +{ + uint32_t font_data, xorcol; + + xorcol = bgcol ^ fgcol; + do { + font_data = font_ptr[0]; + glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol); + font_ptr += 4; + d += linesize; + } while (--h); +} + +static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize, + const uint8_t *font_ptr, int h, + uint32_t fgcol, uint32_t bgcol) +{ + uint32_t font_data, xorcol; + + xorcol = bgcol ^ fgcol; + do { + font_data = font_ptr[0]; + glue(vga_draw_glyph_line_, DEPTH)(d, + expand4to8[font_data >> 4], + xorcol, bgcol); + glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP, + expand4to8[font_data & 0x0f], + xorcol, bgcol); font_ptr += 4; d += linesize; } while (--h); @@ -151,6 +179,48 @@ static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, } } +#if BPP == 1 +#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v) +#elif BPP == 2 +#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v) +#else +#define PUT_PIXEL2(d, n, v) \ +((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v) +#endif + +/* + * 4 color mode, dup2 horizontal + */ +static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + uint32_t plane_mask, *palette, data, v; + int x; + + palette = s1->last_palette; + plane_mask = mask16[s1->ar[0x12] & 0xf]; + width >>= 3; + for(x = 0; x < width; x++) { + data = ((uint32_t *)s)[0]; + data &= plane_mask; + v = expand2[GET_PLANE(data, 0)]; + v |= expand2[GET_PLANE(data, 2)] << 2; + PUT_PIXEL2(d, 0, palette[v >> 12]); + PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]); + PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]); + PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]); + + v = expand2[GET_PLANE(data, 1)]; + v |= expand2[GET_PLANE(data, 3)] << 2; + PUT_PIXEL2(d, 4, palette[v >> 12]); + PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); + PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); + PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); + d += BPP * 16; + s += 4; + } +} + /* * 16 color mode */ @@ -184,7 +254,62 @@ static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, } /* - * 256 color mode + * 16 color mode, dup2 horizontal + */ +static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + uint32_t plane_mask, data, v, *palette; + int x; + + palette = s1->last_palette; + plane_mask = mask16[s1->ar[0x12] & 0xf]; + width >>= 3; + for(x = 0; x < width; x++) { + data = ((uint32_t *)s)[0]; + data &= plane_mask; + v = expand4[GET_PLANE(data, 0)]; + v |= expand4[GET_PLANE(data, 1)] << 1; + v |= expand4[GET_PLANE(data, 2)] << 2; + v |= expand4[GET_PLANE(data, 3)] << 3; + PUT_PIXEL2(d, 0, palette[v >> 28]); + PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]); + PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]); + PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]); + PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]); + PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); + PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); + PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); + d += BPP * 16; + s += 4; + } +} + +/* + * 256 color mode, double pixels + * + * XXX: add plane_mask support (never used in standard VGA modes) + */ +static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + uint32_t *palette; + int x; + + palette = s1->last_palette; + width >>= 3; + for(x = 0; x < width; x++) { + PUT_PIXEL2(d, 0, palette[s[0]]); + PUT_PIXEL2(d, 1, palette[s[1]]); + PUT_PIXEL2(d, 2, palette[s[2]]); + PUT_PIXEL2(d, 3, palette[s[3]]); + d += BPP * 8; + s += 4; + } +} + +/* + * standard 256 color mode * * XXX: add plane_mask support (never used in standard VGA modes) */ @@ -289,6 +414,7 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, #endif } +#undef PUT_PIXEL2 #undef DEPTH #undef BPP #undef PIXEL_TYPE -- cgit v1.2.3 From b92e5a22ec3af6e697827d388897c9ab2ddd2975 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 8 Aug 2003 23:58:05 +0000 Subject: Software MMU support (used for memory mapped devices such as VGA) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@347 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_header.h | 111 ++++++++++++++++++++++++ softmmu_template.h | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 352 insertions(+) create mode 100644 softmmu_header.h create mode 100644 softmmu_template.h diff --git a/softmmu_header.h b/softmmu_header.h new file mode 100644 index 000000000..12306a666 --- /dev/null +++ b/softmmu_header.h @@ -0,0 +1,111 @@ +/* + * Software MMU support + * + * 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 DATA_SIZE == 8 +#define SUFFIX q +#define DATA_TYPE uint64_t +#elif DATA_SIZE == 4 +#define SUFFIX l +#define DATA_TYPE uint32_t +#elif DATA_SIZE == 2 +#define SUFFIX w +#define DATA_TYPE uint16_t +#define DATA_STYPE int16_t +#elif DATA_SIZE == 1 +#define SUFFIX b +#define DATA_TYPE uint8_t +#define DATA_STYPE int8_t +#else +#error unsupported data size +#endif + +#if MEMUSER == 0 +#define MEMSUFFIX _kernel +#else +#define MEMSUFFIX _user +#endif + +#if DATA_SIZE == 8 +#define RES_TYPE uint64_t +#else +#define RES_TYPE int +#endif + + +#if MEMUSER == 0 +DATA_TYPE __attribute((regparm(1))) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr); +void __attribute((regparm(2))) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE v); +#endif + +static inline int glue(glue(ldu, SUFFIX), MEMSUFFIX)(void *ptr) +{ + int index; + RES_TYPE res; + unsigned long addr, physaddr; + addr = (unsigned long)ptr; + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + if (__builtin_expect(env->tlb_read[MEMUSER][index].address != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { + res = glue(glue(__ld, SUFFIX), _mmu)(addr); + } else { + physaddr = addr + env->tlb_read[MEMUSER][index].addend; + res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr); + } + return res; +} + +#if DATA_SIZE <= 2 +static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr) +{ + int res, index; + unsigned long addr, physaddr; + addr = (unsigned long)ptr; + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + if (__builtin_expect(env->tlb_read[MEMUSER][index].address != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { + res = (DATA_STYPE)glue(glue(__ld, SUFFIX), _mmu)(addr); + } else { + physaddr = addr + env->tlb_read[MEMUSER][index].addend; + res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); + } + return res; +} +#endif + +static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) +{ + int index; + unsigned long addr, physaddr; + addr = (unsigned long)ptr; + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + if (__builtin_expect(env->tlb_write[MEMUSER][index].address != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { + glue(glue(__st, SUFFIX), _mmu)(addr, v); + } else { + physaddr = addr + env->tlb_write[MEMUSER][index].addend; + glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); + } +} + +#undef RES_TYPE +#undef DATA_TYPE +#undef DATA_STYPE +#undef SUFFIX +#undef DATA_SIZE +#undef MEMSUFFIX diff --git a/softmmu_template.h b/softmmu_template.h new file mode 100644 index 000000000..871cf5491 --- /dev/null +++ b/softmmu_template.h @@ -0,0 +1,241 @@ +/* + * Software MMU support + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define DATA_SIZE (1 << SHIFT) + +#if DATA_SIZE == 8 +#define SUFFIX q +#define DATA_TYPE uint64_t +#elif DATA_SIZE == 4 +#define SUFFIX l +#define DATA_TYPE uint32_t +#elif DATA_SIZE == 2 +#define SUFFIX w +#define DATA_TYPE uint16_t +#elif DATA_SIZE == 1 +#define SUFFIX b +#define DATA_TYPE uint8_t +#else +#error unsupported data size +#endif + +static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr); +static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, + void *retaddr); + +static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, + unsigned long tlb_addr) +{ + DATA_TYPE res; + int index; + + index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); +#if SHIFT <= 2 + res = io_mem_read[index][SHIFT](physaddr); +#else +#ifdef TARGET_WORDS_BIGENDIAN + res = (uint64_t)io_mem_read[index][2](physaddr) << 32; + res |= io_mem_read[index][2](physaddr + 4); +#else + res = io_mem_read[index][2](physaddr); + res |= (uint64_t)io_mem_read[index][2](physaddr + 4) << 32; +#endif +#endif /* SHIFT > 2 */ + return res; +} + +static inline void glue(io_write, SUFFIX)(unsigned long physaddr, + DATA_TYPE val, + unsigned long tlb_addr) +{ + int index; + + index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); +#if SHIFT <= 2 + io_mem_write[index][SHIFT](physaddr, val); +#else +#ifdef TARGET_WORDS_BIGENDIAN + io_mem_write[index][2](physaddr, val >> 32); + io_mem_write[index][2](physaddr + 4, val); +#else + io_mem_write[index][2](physaddr, val); + io_mem_write[index][2](physaddr + 4, val >> 32); +#endif +#endif /* SHIFT > 2 */ +} + +/* handle all cases except unaligned access which span two pages */ +DATA_TYPE __attribute((regparm(1))) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr) +{ + DATA_TYPE res; + int is_user, index; + unsigned long physaddr, tlb_addr; + void *retaddr; + + /* test if there is match for unaligned or IO access */ + /* XXX: could done more in memory macro in a non portable way */ + is_user = (env->cpl == 3); + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_read[is_user][index].address; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + physaddr = addr + env->tlb_read[is_user][index].addend; + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + res = glue(io_read, SUFFIX)(physaddr, tlb_addr); + } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + /* slow unaligned access (it spans two pages or IO) */ + do_unaligned_access: + retaddr = __builtin_return_address(0); + res = glue(slow_ld, SUFFIX)(addr, retaddr); + } else { + /* unaligned access in the same page */ + res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr); + } + } else { + /* the page is not in the TLB : fill it */ + retaddr = __builtin_return_address(0); + tlb_fill(addr, 0, retaddr); + goto redo; + } + return res; +} + +/* handle all unaligned cases */ +static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr) +{ + DATA_TYPE res, res1, res2; + int is_user, index, shift; + unsigned long physaddr, tlb_addr, addr1, addr2; + + is_user = (env->cpl == 3); + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_read[is_user][index].address; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + physaddr = addr + env->tlb_read[is_user][index].addend; + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + res = glue(io_read, SUFFIX)(physaddr, tlb_addr); + } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* slow unaligned access (it spans two pages) */ + addr1 = addr & ~(DATA_SIZE - 1); + addr2 = addr1 + DATA_SIZE; + res1 = glue(slow_ld, SUFFIX)(addr1, retaddr); + res2 = glue(slow_ld, SUFFIX)(addr2, retaddr); + shift = (addr & (DATA_SIZE - 1)) * 8; +#ifdef TARGET_WORDS_BIGENDIAN + res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); +#else + res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift)); +#endif + } else { + /* unaligned/aligned access in the same page */ + res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr); + } + } else { + /* the page is not in the TLB : fill it */ + tlb_fill(addr, 0, retaddr); + goto redo; + } + return res; +} + + +void __attribute((regparm(2))) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val) +{ + unsigned long physaddr, tlb_addr; + void *retaddr; + int is_user, index; + + is_user = (env->cpl == 3); + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_write[is_user][index].address; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + physaddr = addr + env->tlb_read[is_user][index].addend; + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + glue(io_write, SUFFIX)(physaddr, val, tlb_addr); + } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + retaddr = __builtin_return_address(0); + glue(slow_st, SUFFIX)(addr, val, retaddr); + } else { + /* aligned/unaligned access in the same page */ + glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val); + } + } else { + /* the page is not in the TLB : fill it */ + retaddr = __builtin_return_address(0); + tlb_fill(addr, 1, retaddr); + goto redo; + } +} + +/* handles all unaligned cases */ +static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, + void *retaddr) +{ + unsigned long physaddr, tlb_addr; + int is_user, index, i; + + is_user = (env->cpl == 3); + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_write[is_user][index].address; + if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + physaddr = addr + env->tlb_read[is_user][index].addend; + if (tlb_addr & ~TARGET_PAGE_MASK) { + /* IO access */ + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + glue(io_write, SUFFIX)(physaddr, val, tlb_addr); + } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* XXX: not efficient, but simple */ + for(i = 0;i < DATA_SIZE; i++) { +#ifdef TARGET_WORDS_BIGENDIAN + slow_stb(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), retaddr); +#else + slow_stb(addr + i, val >> (i * 8), retaddr); +#endif + } + } else { + /* aligned/unaligned access in the same page */ + glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val); + } + } else { + /* the page is not in the TLB : fill it */ + tlb_fill(addr, 1, retaddr); + goto redo; + } +} + +#undef SHIFT +#undef DATA_TYPE +#undef SUFFIX +#undef DATA_SIZE -- cgit v1.2.3 From 0f0b726444c45004910617da0c5bce666caa07b3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Aug 2003 18:26:36 +0000 Subject: SDL support for VGA, keyboard and mouse git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@348 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 sdl.c diff --git a/sdl.c b/sdl.c new file mode 100644 index 000000000..e9c28f2a1 --- /dev/null +++ b/sdl.c @@ -0,0 +1,275 @@ +/* + * QEMU SDL display 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cpu-i386.h" +#include "exec.h" + +#include "vl.h" + +static SDL_Surface *screen; +static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ + +static void sdl_update(DisplayState *ds, int x, int y, int w, int h) +{ + SDL_UpdateRect(screen, x, y, w, h); +} + +static void sdl_resize(DisplayState *ds, int w, int h) +{ + int flags; + + // printf("resizing to %d %d\n", w, h); + + flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; + flags |= SDL_RESIZABLE; + screen = SDL_SetVideoMode(w, h, 0, flags); + if (!screen) { + fprintf(stderr, "Could not open SDL display\n"); + exit(1); + } + ds->data = screen->pixels; + ds->linesize = screen->pitch; + ds->depth = screen->format->BitsPerPixel; +} + +static const uint32_t x_keycode_to_pc_keycode[61] = { + 0x47e0, /* 97 Home */ + 0x48e0, /* 98 Up */ + 0x49e0, /* 99 PgUp */ + 0x4be0, /* 100 Left */ + 0x4c, /* 101 KP-5 */ + 0x4de0, /* 102 Right */ + 0x4fe0, /* 103 End */ + 0x50e0, /* 104 Down */ + 0x51e0, /* 105 PgDn */ + 0x52e0, /* 106 Ins */ + 0x53e0, /* 107 Del */ + 0x1ce0, /* 108 Enter */ + 0x1de0, /* 109 Ctrl-R */ + 0x451de1, /* 110 Pause */ + 0x37e0, /* 111 Print */ + 0x35e0, /* 112 Divide */ + 0x38e0, /* 113 Alt-R */ + 0x46e0, /* 114 Break */ + 0x0, /* 115 */ + 0x0, /* 116 */ + 0x0, /* 117 */ + 0x0, /* 118 */ + 0x0, /* 119 */ + 0x0, /* 120 */ + 0x0, /* 121 */ + 0x0, /* 122 */ + 0x0, /* 123 */ + 0x0, /* 124 */ + 0x0, /* 125 */ + 0x0, /* 126 */ + 0x0, /* 127 */ + 0x0, /* 128 */ + 0x0, /* 129 */ + 0x0, /* 130 */ + 0x0, /* 131 */ + 0x0, /* 132 */ + 0x0, /* 133 */ + 0x0, /* 134 */ + 0x0, /* 135 */ + 0x47, /* 136 KP_7 */ + 0x48, /* 137 KP_8 */ + 0x49, /* 138 KP_9 */ + 0x4b, /* 139 KP_4 */ + 0x4c, /* 140 KP_5 */ + 0x4d, /* 141 KP_6 */ + 0x4f, /* 142 KP_1 */ + 0x50, /* 143 KP_2 */ + 0x51, /* 144 KP_3 */ + 0x52, /* 145 KP_0 */ + 0x53, /* 146 KP_. */ + 0x47, /* 147 KP_HOME */ + 0x48, /* 148 KP_UP */ + 0x49, /* 149 KP_PgUp */ + 0x4b, /* 150 KP_Left */ + 0x4c, /* 151 KP_ */ + 0x4d, /* 152 KP_Right */ + 0x4f, /* 153 KP_End */ + 0x50, /* 154 KP_Down */ + 0x51, /* 155 KP_PgDn */ + 0x52, /* 156 KP_Ins */ + 0x53, /* 157 KP_Del */ +}; + +static void sdl_process_key(SDL_KeyboardEvent *ev) +{ + int keycode, v; + + /* XXX: not portable, but avoids complicated mappings */ + keycode = ev->keysym.scancode; + if (keycode < 9) { + keycode = 0; + } else if (keycode < 97) { + keycode -= 8; /* just an offset */ + } else if (keycode < 158) { + /* use conversion table */ + keycode = x_keycode_to_pc_keycode[keycode - 97]; + } else { + keycode = 0; + } + + /* now send the key code */ + while (keycode != 0) { + v = keycode & 0xff; + if (ev->type == SDL_KEYUP) + v |= 0x80; + kbd_put_keycode(v); + keycode >>= 8; + } +} + +static void sdl_grab_start(void) +{ + SDL_WM_SetCaption("QEMU - Press Ctrl-Shift to exit grab", "QEMU"); + SDL_ShowCursor(0); + SDL_WM_GrabInput(SDL_GRAB_ON); + /* dummy read to avoid moving the mouse */ + SDL_GetRelativeMouseState(NULL, NULL); + gui_grab = 1; +} + +static void sdl_grab_end(void) +{ + SDL_WM_SetCaption("QEMU", "QEMU"); + SDL_WM_GrabInput(SDL_GRAB_OFF); + SDL_ShowCursor(1); + gui_grab = 0; +} + +static void sdl_send_mouse_event(void) +{ + int dx, dy, dz, state, buttons; + state = SDL_GetRelativeMouseState(&dx, &dy); + buttons = 0; + if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) + buttons |= MOUSE_EVENT_LBUTTON; + if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) + buttons |= MOUSE_EVENT_RBUTTON; + if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) + buttons |= MOUSE_EVENT_MBUTTON; + /* XXX: test wheel */ + dz = 0; + if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP)) + dz--; + if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN)) + dz++; + kbd_mouse_event(dx, dy, dz, buttons); +} + +static void sdl_refresh(DisplayState *ds) +{ + SDL_Event ev1, *ev = &ev1; + + vga_update_display(); + while (SDL_PollEvent(ev)) { + switch (ev->type) { + case SDL_VIDEOEXPOSE: + sdl_update(ds, 0, 0, screen->w, screen->h); + break; + case SDL_KEYDOWN: + case SDL_KEYUP: + if (ev->type == SDL_KEYDOWN) { + if ((SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) == + (KMOD_LSHIFT | KMOD_LCTRL)) { + /* exit/enter grab if pressing Ctrl-Shift */ + if (!gui_grab) + sdl_grab_start(); + else + sdl_grab_end(); + } + } + sdl_process_key(&ev->key); + break; + case SDL_QUIT: + reset_requested = 1; + break; + case SDL_MOUSEMOTION: + if (gui_grab) { + sdl_send_mouse_event(); + } + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + { + SDL_MouseButtonEvent *bev = &ev->button; + if (!gui_grab) { + if (ev->type == SDL_MOUSEBUTTONDOWN && + (bev->state & SDL_BUTTON_LMASK)) { + /* start grabbing all events */ + sdl_grab_start(); + } + } else { + sdl_send_mouse_event(); + } + } + break; + default: + break; + } + } +} + +void sdl_display_init(DisplayState *ds) +{ + int flags; + + flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; + if (SDL_Init (flags)) { + fprintf(stderr, "Could not initialize SDL - exiting\n"); + exit(1); + } + ds->dpy_update = sdl_update; + ds->dpy_resize = sdl_resize; + ds->dpy_refresh = sdl_refresh; + + sdl_resize(ds, 640, 400); + SDL_WM_SetCaption("QEMU", "QEMU"); + SDL_EnableKeyRepeat(250, 50); + gui_grab = 0; +} -- cgit v1.2.3 From ab93bbe2aebebce9901e740b1000058f74c15e26 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 21:35:13 +0000 Subject: soft mmu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@349 c046a42c-6fe2-441c-8c8c-71466251a162 --- bswap.h | 84 +++++++++++++ cpu-defs.h | 39 ++++++ helper2-i386.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ops_mem.h | 66 ++++++++++ 4 files changed, 579 insertions(+) create mode 100644 bswap.h create mode 100644 cpu-defs.h create mode 100644 helper2-i386.c create mode 100644 ops_mem.h diff --git a/bswap.h b/bswap.h new file mode 100644 index 000000000..0632a9d9a --- /dev/null +++ b/bswap.h @@ -0,0 +1,84 @@ +#ifndef BSWAP_H +#define BSWAP_H + +#include "config-host.h" + +#include + +#ifdef HAVE_BYTESWAP_H +#include +#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 */ + +#if defined(__alpha__) || defined (__ia64__) +#define HOST_LONG_BITS 64 +#else +#define HOST_LONG_BITS 32 +#endif + +#define HOST_LONG_SIZE (HOST_LONG_BITS / 8) + +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); +} + +#endif /* BSWAP_H */ diff --git a/cpu-defs.h b/cpu-defs.h new file mode 100644 index 000000000..3ec866fa7 --- /dev/null +++ b/cpu-defs.h @@ -0,0 +1,39 @@ +/* + * 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 + +#define EXCP_INTERRUPT 256 /* async interruption */ +#define EXCP_HLT 257 /* hlt instruction reached */ +#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ + +#define MAX_BREAKPOINTS 32 + +#define CPU_TLB_SIZE 256 + +typedef struct CPUTLBEntry { + uint32_t address; + uint32_t addend; +} CPUTLBEntry; + +#endif diff --git a/helper2-i386.c b/helper2-i386.c new file mode 100644 index 000000000..7a6fc13b5 --- /dev/null +++ b/helper2-i386.c @@ -0,0 +1,390 @@ +/* + * i386 helpers (without register variable usage) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu-i386.h" +#include "exec.h" + +//#define DEBUG_MMU + +CPUX86State *cpu_x86_init(void) +{ + CPUX86State *env; + int i; + static int inited; + + cpu_exec_init(); + + env = malloc(sizeof(CPUX86State)); + if (!env) + return NULL; + memset(env, 0, sizeof(CPUX86State)); + /* basic FPU init */ + for(i = 0;i < 8; i++) + env->fptags[i] = 1; + env->fpuc = 0x37f; + /* flags setup : we activate the IRQs by default as in user mode */ + env->eflags = 0x2 | IF_MASK; + + tlb_flush(env); +#ifdef CONFIG_SOFTMMU + env->soft_mmu = 1; +#endif + /* init various static tables */ + if (!inited) { + inited = 1; + optimize_flags_init(); + } + return env; +} + +void cpu_x86_close(CPUX86State *env) +{ + free(env); +} + +/***********************************************************/ +/* x86 debug */ + +static const char *cc_op_str[] = { + "DYNAMIC", + "EFLAGS", + "MUL", + "ADDB", + "ADDW", + "ADDL", + "ADCB", + "ADCW", + "ADCL", + "SUBB", + "SUBW", + "SUBL", + "SBBB", + "SBBW", + "SBBL", + "LOGICB", + "LOGICW", + "LOGICL", + "INCB", + "INCW", + "INCL", + "DECB", + "DECW", + "DECL", + "SHLB", + "SHLW", + "SHLL", + "SARB", + "SARW", + "SARL", +}; + +void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) +{ + int eflags; + char cc_op_name[32]; + + eflags = env->eflags; + fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", + env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], + env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], + env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-'); + fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", + env->segs[R_CS].selector, + env->segs[R_SS].selector, + env->segs[R_DS].selector, + env->segs[R_ES].selector, + env->segs[R_FS].selector, + env->segs[R_GS].selector); + if (flags & X86_DUMP_CCOP) { + if ((unsigned)env->cc_op < CC_OP_NB) + strcpy(cc_op_name, cc_op_str[env->cc_op]); + else + snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); + fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", + env->cc_src, env->cc_dst, cc_op_name); + } + if (flags & X86_DUMP_FPU) { + fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", + (double)env->fpregs[0], + (double)env->fpregs[1], + (double)env->fpregs[2], + (double)env->fpregs[3]); + fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", + (double)env->fpregs[4], + (double)env->fpregs[5], + (double)env->fpregs[7], + (double)env->fpregs[8]); + } +} + +/***********************************************************/ +/* x86 mmu */ +/* XXX: add PGE support */ + +/* called when cr3 or PG bit are modified */ +static int last_pg_state = -1; +static int last_pe_state = 0; +int phys_ram_size; +int phys_ram_fd; +uint8_t *phys_ram_base; + +void cpu_x86_update_cr0(CPUX86State *env) +{ + int pg_state, pe_state; + +#ifdef DEBUG_MMU + printf("CR0 update: CR0=0x%08x\n", env->cr[0]); +#endif + pg_state = env->cr[0] & CR0_PG_MASK; + if (pg_state != last_pg_state) { + page_unmap(); + tlb_flush(env); + last_pg_state = pg_state; + } + pe_state = env->cr[0] & CR0_PE_MASK; + if (last_pe_state != pe_state) { + tb_flush(); + last_pe_state = pe_state; + } +} + +void cpu_x86_update_cr3(CPUX86State *env) +{ + if (env->cr[0] & CR0_PG_MASK) { +#if defined(DEBUG_MMU) + printf("CR3 update: CR3=%08x\n", env->cr[3]); +#endif + page_unmap(); + tlb_flush(env); + } +} + +void cpu_x86_init_mmu(CPUX86State *env) +{ + last_pg_state = -1; + cpu_x86_update_cr0(env); +} + +/* XXX: also flush 4MB pages */ +void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) +{ + int flags; + unsigned long virt_addr; + + tlb_flush_page(env, addr); + + flags = page_get_flags(addr); + if (flags & PAGE_VALID) { + virt_addr = addr & ~0xfff; + munmap((void *)virt_addr, 4096); + page_set_flags(virt_addr, virt_addr + 4096, 0); + } +} + +/* return value: + -1 = cannot handle fault + 0 = nothing more to do + 1 = generate PF fault + 2 = soft MMU activation required for this block +*/ +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) +{ + uint8_t *pde_ptr, *pte_ptr; + uint32_t pde, pte, virt_addr; + int cpl, error_code, is_dirty, is_user, prot, page_size, ret; + unsigned long pd; + + cpl = env->cpl; + is_user = (cpl == 3); + +#ifdef DEBUG_MMU + printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", + addr, is_write, is_user, env->eip); +#endif + + if (env->user_mode_only) { + /* user mode only emulation */ + error_code = 0; + goto do_fault; + } + + if (!(env->cr[0] & CR0_PG_MASK)) { + pte = addr; + virt_addr = addr & ~0xfff; + prot = PROT_READ | PROT_WRITE; + page_size = 4096; + goto do_mapping; + } + + /* page directory entry */ + pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); + pde = ldl(pde_ptr); + if (!(pde & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (is_user) { + if (!(pde & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && + is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } + /* if PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + is_dirty = is_write && !(pde & PG_DIRTY_MASK); + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_DIRTY_MASK; + stl(pde_ptr, pde); + } + + pte = pde & ~0x003ff000; /* align to 4MB */ + page_size = 4096 * 1024; + virt_addr = addr & ~0x003fffff; + } else { + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl(pde_ptr, pde); + } + + /* page directory entry */ + pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); + pte = ldl(pte_ptr); + if (!(pte & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (is_user) { + if (!(pte & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pte & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && + is_write && !(pte & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) + pte |= PG_DIRTY_MASK; + stl(pte_ptr, pte); + } + page_size = 4096; + virt_addr = addr & ~0xfff; + } + /* the page can be put in the TLB */ + prot = PROT_READ; + if (is_user) { + if (pte & PG_RW_MASK) + prot |= PROT_WRITE; + } else { + if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || + (pte & PG_RW_MASK)) + prot |= PROT_WRITE; + } + + do_mapping: + if (env->soft_mmu) { + unsigned long paddr, vaddr, address, addend, page_offset; + int index; + + /* software MMU case. Even if 4MB pages, we map only one 4KB + page in the cache to avoid filling it too fast */ + page_offset = (addr & ~0xfff) & (page_size - 1); + paddr = (pte & ~0xfff) + page_offset; + vaddr = virt_addr + page_offset; + index = (addr >> 12) & (CPU_TLB_SIZE - 1); + pd = physpage_find(paddr); + if (pd & 0xfff) { + /* IO memory case */ + address = vaddr | pd; + addend = paddr; + } else { + /* standard memory */ + address = vaddr; + addend = (unsigned long)phys_ram_base + pd; + } + addend -= vaddr; + env->tlb_read[is_user][index].address = address; + env->tlb_read[is_user][index].addend = addend; + if (prot & PROT_WRITE) { + env->tlb_write[is_user][index].address = address; + env->tlb_write[is_user][index].addend = addend; + } + } + ret = 0; + /* XXX: incorrect for 4MB pages */ + pd = physpage_find(pte & ~0xfff); + if ((pd & 0xfff) != 0) { + /* IO access: no mapping is done as it will be handled by the + soft MMU */ + if (!env->soft_mmu) + ret = 2; + } else { + void *map_addr; + map_addr = mmap((void *)virt_addr, page_size, prot, + MAP_SHARED | MAP_FIXED, phys_ram_fd, pd); + if (map_addr == MAP_FAILED) { + fprintf(stderr, + "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", + pte & ~0xfff, virt_addr); + exit(1); + } +#ifdef DEBUG_MMU + printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", + pte & ~0xfff, virt_addr, (page_size != 4096)); +#endif + page_set_flags(virt_addr, virt_addr + page_size, + PAGE_VALID | PAGE_EXEC | prot); + } + return ret; + do_fault_protect: + error_code = PG_ERROR_P_MASK; + do_fault: + env->cr[2] = addr; + env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; + if (is_user) + env->error_code |= PG_ERROR_U_MASK; + return 1; +} diff --git a/ops_mem.h b/ops_mem.h new file mode 100644 index 000000000..e1c8277bb --- /dev/null +++ b/ops_mem.h @@ -0,0 +1,66 @@ +void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldub, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldsb, MEMSUFFIX)((int8_t *)A0); +} + +void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(lduw, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldsw, MEMSUFFIX)((int8_t *)A0); +} + +void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldl, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldub, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldsb, MEMSUFFIX)((int8_t *)A0); +} + +void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(lduw, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldsw, MEMSUFFIX)((int8_t *)A0); +} + +void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldl, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void) +{ + glue(stb, MEMSUFFIX)((uint8_t *)A0, T0); +} + +void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void) +{ + glue(stw, MEMSUFFIX)((uint8_t *)A0, T0); +} + +void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void) +{ + glue(stl, MEMSUFFIX)((uint8_t *)A0, T0); +} + +#undef MEMSUFFIX -- cgit v1.2.3 From 97a847bc03d22bf5b0562af2407bc3516b3bfdd1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 21:36:04 +0000 Subject: build all targets at the same time - SDL probe support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@350 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 217 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 130 insertions(+), 87 deletions(-) diff --git a/configure b/configure index e56c603d0..2b830710a 100755 --- a/configure +++ b/configure @@ -15,7 +15,6 @@ 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" -TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h" # default parameters prefix="/usr/local" @@ -27,12 +26,11 @@ host_cc="gcc" ar="ar" make="make" strip="strip" -target_cpu="x86" -target_bigendian="default" cpu=`uname -m` +target_list="i386 i386-softmmu arm" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) - cpu="x86" + cpu="i386" ;; armv4l) cpu="armv4l" @@ -71,6 +69,26 @@ case $targetos in *) ;; esac +########################################## +# SDL probe + +cat > $TMPC << EOF +#include +#undef main /* We don't want SDL to override our main() */ +int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } +EOF + +sdl_too_old=no +sdl=no +if $cc -o $TMPE `sdl-config --cflags` $TMPC `sdl-config --libs` 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 +fi + # find source path # XXX: we assume an absolute path is given when launching configure, # except in './configure' case. @@ -104,16 +122,14 @@ for opt do ;; --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` ;; - --target-cpu=*) target_cpu=`echo $opt | cut -d '=' -f 2` - ;; - --target-big-endian) target_bigendian="yes" - ;; - --target-little-endian) target_bigendian="no" + --target-list=*) target_list=${opt#--target-list=} ;; --enable-gprof) gprof="yes" ;; --static) static="yes" ;; + --disable-sdl) sdl="no" + ;; esac done @@ -164,16 +180,6 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu have_gcc3_options="yes" fi -if test "$target_bigendian" = "default" ; then - if test "$target_cpu" = "x86" ; then - target_bigendian="no" - elif test "$target_cpu" = "arm" ; then - target_bigendian="no" - else - target_bigendian="no" - fi -fi - if test x"$1" = x"-h" -o x"$1" = x"--help" ; then cat << EOF @@ -185,7 +191,7 @@ 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. [$interp_prefix]" -echo " --target_cpu=CPU set target cpu (x86 or arm) [$target_cpu]" +echo " --target-list=LIST set target list [$target_list]" echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]" @@ -205,94 +211,139 @@ echo "C compiler $cc" echo "make $make" echo "host CPU $cpu" echo "host big endian $bigendian" -echo "target CPU $target_cpu" -echo "target big endian $target_bigendian" +echo "target list $target_list" echo "gprof enabled $gprof" echo "static build $static" +echo "SDL support $sdl" +if test $sdl_too_old = "yes"; then +echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support" +fi + +config_mak="config-host.mak" +config_h="config-host.h" -echo "Creating config.mak and config.h" +echo "Creating $config_mak and $config_h" -echo "# Automatically generated by configure - do not modify" > config.mak -echo "/* Automatically generated by configure - do not modify */" > $TMPH +echo "# Automatically generated by configure - do not modify" > $config_mak +echo "/* Automatically generated by configure - do not modify */" > $config_h -echo "prefix=$prefix" >> config.mak -echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH -echo "MAKE=$make" >> config.mak -echo "CC=$cc" >> config.mak +echo "prefix=$prefix" >> $config_mak +echo "MAKE=$make" >> $config_mak +echo "CC=$cc" >> $config_mak if test "$have_gcc3_options" = "yes" ; then - echo "HAVE_GCC3_OPTIONS=yes" >> config.mak + echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak fi -echo "HOST_CC=$host_cc" >> config.mak -echo "AR=$ar" >> config.mak -echo "STRIP=$strip -s -R .comment -R .note" >> config.mak -echo "CFLAGS=$CFLAGS" >> config.mak -echo "LDFLAGS=$LDFLAGS" >> config.mak -if test "$cpu" = "x86" ; then - echo "ARCH=i386" >> config.mak - echo "#define HOST_I386 1" >> $TMPH +echo "HOST_CC=$host_cc" >> $config_mak +echo "AR=$ar" >> $config_mak +echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak +echo "CFLAGS=$CFLAGS" >> $config_mak +echo "LDFLAGS=$LDFLAGS" >> $config_mak +if test "$cpu" = "i386" ; then + echo "ARCH=i386" >> $config_mak + echo "#define HOST_I386 1" >> $config_h elif test "$cpu" = "armv4l" ; then - echo "ARCH=arm" >> config.mak - echo "#define HOST_ARM 1" >> $TMPH + 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" >> $TMPH + 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" >> $TMPH + 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" >> $TMPH + 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" >> $TMPH + 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" >> $TMPH + 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" >> $TMPH + 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" >> $TMPH + echo "ARCH=ia64" >> $config_mak + echo "#define HOST_IA64 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" >> $TMPH + echo "WORDS_BIGENDIAN=yes" >> $config_mak + echo "#define WORDS_BIGENDIAN 1" >> $config_h +fi +echo "#define HAVE_BYTESWAP_H 1" >> $config_h +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 fi +if test "$sdl" = "yes" ; then + echo "CONFIG_SDL=yes" >> $config_mak + echo "#define CONFIG_SDL 1" >> $config_h + echo "SDL_LIBS=`sdl-config --libs`" >> $config_mak + echo "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak +fi +echo -n "VERSION=" >>$config_mak +head $source_path/VERSION >>$config_mak +echo "" >>$config_mak +echo -n "#define QEMU_VERSION \"" >> $config_h +head $source_path/VERSION >> $config_h +echo "\"" >> $config_h + +echo "SRC_PATH=$source_path" >> $config_mak +echo "TARGET_DIRS=$target_list" >> $config_mak + +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_softmmu="no" +if expr $target : '.*-softmmu' > /dev/null ; then + target_softmmu="yes" +fi + +echo "Creating $config_mak, $config_h and $target_dir/Makefile" + +mkdir -p $target_dir +ln -sf $source_path/Makefile.target $target_dir/Makefile + +echo "# Automatically generated by configure - do not modify" > $config_mak +echo "/* Automatically generated by configure - do not modify */" > $config_h + -if test "$target_cpu" = "x86" ; then - echo "TARGET_ARCH=i386" >> config.mak - echo "#define TARGET_ARCH \"i386\"" >> $TMPH - echo "#define TARGET_I386 1" >> $TMPH +echo "include ../config-host.mak" >> $config_mak +echo "#include \"../config-host.h\"" >> $config_h +echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $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 elif test "$target_cpu" = "arm" ; then - echo "TARGET_ARCH=arm" >> config.mak - echo "#define TARGET_ARCH \"arm\"" >> $TMPH - echo "#define TARGET_ARM 1" >> $TMPH + echo "TARGET_ARCH=arm" >> $config_mak + echo "#define TARGET_ARCH \"arm\"" >> $config_h + echo "#define TARGET_ARM 1" >> $config_h else echo "Unsupported target CPU" exit 1 fi if test "$target_bigendian" = "yes" ; then - echo "TARGET_WORDS_BIGENDIAN=yes" >> config.mak - echo "#define TARGET_WORDS_BIGENDIAN 1" >> $TMPH + echo "TARGET_WORDS_BIGENDIAN=yes" >> $config_mak + echo "#define TARGET_WORDS_BIGENDIAN 1" >> $config_h fi - -if test "$gprof" = "yes" ; then - echo "TARGET_GPROF=yes" >> config.mak - echo "#define HAVE_GPROF 1" >> $TMPH -fi -if test "$static" = "yes" ; then - echo "CONFIG_STATIC=yes" >> config.mak +if test "$target_softmmu" = "yes" ; then + echo "CONFIG_SOFTMMU=yes" >> $config_mak + echo "#define CONFIG_SOFTMMU 1" >> $config_h fi -echo -n "VERSION=" >>config.mak -head $source_path/VERSION >>config.mak -echo "" >>config.mak -echo -n "#define QEMU_VERSION \"" >> $TMPH -head $source_path/VERSION >> $TMPH -echo "\"" >> $TMPH + +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 @@ -305,13 +356,5 @@ if test "$source_path_used" = "yes" ; then ln -sf $source_path/$f $f done fi -echo "SRC_PATH=$source_path" >> config.mak - -diff $TMPH config.h >/dev/null 2>&1 -if test $? -ne 0 ; then - mv -f $TMPH config.h -else - echo "config.h is unchanged" -fi -rm -f $TMPO $TMPC $TMPE $TMPS $TMPH +rm -f $TMPO $TMPC $TMPE $TMPS -- cgit v1.2.3 From abcd5da72e66becf055aff3a225f7c8645c18fff Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 21:38:48 +0000 Subject: use bswap.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@351 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 11 +++++----- thunk.h | 75 +-------------------------------------------------------------- vlmkcow.c | 4 ++-- 3 files changed, 8 insertions(+), 82 deletions(-) diff --git a/dyngen.c b/dyngen.c index 762ee9d56..df88dc2cc 100644 --- a/dyngen.c +++ b/dyngen.c @@ -25,7 +25,7 @@ #include #include -#include "config.h" +#include "config-host.h" /* elf format definitions. We use these macros to test the CPU to allow cross compilation (this tool must be ran on the build @@ -108,8 +108,7 @@ typedef uint64_t host_ulong; #define SHT_RELOC SHT_REL #endif -#define NO_THUNK_TYPE_SIZE -#include "thunk.h" +#include "bswap.h" enum { OUT_GEN_OP, @@ -648,7 +647,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { ElfW(Sym) *sym; const char *sym_name, *p; - target_ulong val; + unsigned long val; int n; for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { @@ -663,7 +662,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (!ptr) error("__op_labelN in invalid section"); offset = sym->st_value; - val = *(target_ulong *)(ptr + offset); + val = *(unsigned long *)(ptr + offset); #ifdef ELF_USES_RELOCA { int reloc_shndx, nb_relocs1, j; @@ -687,7 +686,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (val >= start_offset && val < start_offset + copy_size) { n = strtol(p, NULL, 10); - fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); + fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); } } } diff --git a/thunk.h b/thunk.h index 90586fc67..6b4c2c367 100644 --- a/thunk.h +++ b/thunk.h @@ -23,43 +23,7 @@ #include #include "config.h" -#ifdef HAVE_BYTESWAP_H -#include -#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 +#include "bswap.h" #if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) #define BSWAP_NEEDED @@ -68,44 +32,7 @@ /* XXX: autoconf */ #define TARGET_LONG_BITS 32 -#if defined(__alpha__) || defined (__ia64__) -#define HOST_LONG_BITS 64 -#else -#define HOST_LONG_BITS 32 -#endif - #define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8) -#define HOST_LONG_SIZE (HOST_LONG_BITS / 8) - -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); -} #ifdef BSWAP_NEEDED diff --git a/vlmkcow.c b/vlmkcow.c index 80d9a0885..2cc6332e7 100644 --- a/vlmkcow.c +++ b/vlmkcow.c @@ -38,12 +38,12 @@ #include #include #include +#include #include #include "vl.h" -#define NO_THUNK_TYPE_SIZE -#include "thunk.h" +#include "bswap.h" int cow_create(int cow_fd, const char *image_filename, int64_t image_sectors) -- cgit v1.2.3 From 626df76abbd6f74cf0b7df209671982a463c249d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 21:39:31 +0000 Subject: build all targets at the same time git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@352 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 200 ++++++------------------------------------------------- Makefile.target | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/Makefile | 4 +- 3 files changed, 223 insertions(+), 182 deletions(-) create mode 100644 Makefile.target diff --git a/Makefile b/Makefile index ab8e377f5..6174c9735 100644 --- a/Makefile +++ b/Makefile @@ -1,203 +1,43 @@ -include config.mak +include config-host.mak CFLAGS=-Wall -O2 -g LDFLAGS=-g LIBS= -DEFINES=-DHAVE_BYTESWAP_H -HELPER_CFLAGS=$(CFLAGS) -PROGS=qemu - -ifdef CONFIG_STATIC -LDFLAGS+=-static -endif - -ifeq ($(ARCH),i386) -CFLAGS+=-fomit-frame-pointer -OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2 -ifeq ($(HAVE_GCC3_OPTIONS),yes) -OP_CFLAGS+= -falign-functions=0 -else -OP_CFLAGS+= -malign-functions=0 -endif -ifdef TARGET_GPROF -LDFLAGS+=-Wl,-T,i386.ld -else -# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object -# that the kernel ELF loader considers as an executable. I think this -# is the simplest way to make it self virtualizable! -LDFLAGS+=-Wl,-shared -endif -ifeq ($(TARGET_ARCH), i386) -PROGS+=vl vlmkcow -endif -endif - -ifeq ($(ARCH),ppc) -OP_CFLAGS=$(CFLAGS) -LDFLAGS+=-Wl,-T,ppc.ld -endif - -ifeq ($(ARCH),s390) -OP_CFLAGS=$(CFLAGS) -LDFLAGS+=-Wl,-T,s390.ld -endif - -ifeq ($(ARCH),sparc) -CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 -LDFLAGS+=-m32 -OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 -HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat -# -static is used to avoid g1/g3 usage by the dynamic linker -LDFLAGS+=-Wl,-T,sparc.ld -static -endif - -ifeq ($(ARCH),sparc64) -CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 -LDFLAGS+=-m64 -OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 -endif - -ifeq ($(ARCH),alpha) -# -msmall-data is not used because we want two-instruction relocations -# for the constant constructions -OP_CFLAGS=-Wall -O2 -g -# Ensure there's only a single GP -CFLAGS += -msmall-data -LDFLAGS+=-Wl,-T,alpha.ld -endif - -ifeq ($(ARCH),ia64) -OP_CFLAGS=$(CFLAGS) -endif - -ifeq ($(ARCH),arm) -OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -LDFLAGS+=-Wl,-T,arm.ld -endif - -ifeq ($(HAVE_GCC3_OPTIONS),yes) -# very important to generate a return at the end of every operation -OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls -endif - -######################################################### - DEFINES+=-D_GNU_SOURCE -LIBS+=-lm - -# profiling code -ifdef TARGET_GPROF -LDFLAGS+=-p -main.o: CFLAGS+=-p -endif - -OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o -ifeq ($(TARGET_ARCH), i386) -OBJS+= vm86.o -endif -SRCS:= $(OBJS:.o=.c) -OBJS+= libqemu.a - -# cpu emulator library -LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o - -ifeq ($(TARGET_ARCH), i386) -LIBOBJS+=translate-i386.o op-i386.o helper-i386.o -endif -ifeq ($(TARGET_ARCH), arm) -LIBOBJS+=translate-arm.o op-arm.o -endif - -# NOTE: the disassembler code is only needed for debugging -LIBOBJS+=disas.o -ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) -LIBOBJS+=i386-dis.o -endif -ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha) -LIBOBJS+=alpha-dis.o -endif -ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc) -LIBOBJS+=ppc-dis.o -endif -ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc) -LIBOBJS+=sparc-dis.o -endif -ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm) -LIBOBJS+=arm-dis.o -endif - -ifeq ($(ARCH),ia64) -OBJS += ia64-syscall.o -endif - -all: $(PROGS) qemu-doc.html +TOOLS=vlmkcow -qemu: $(OBJS) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -ifeq ($(ARCH),alpha) -# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of -# the address space (31 bit so sign extending doesn't matter) - echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc -endif - -# must use static linking to avoid leaving stuff in virtual address space -vl: vl.o block.o libqemu.a - $(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS) +all: dyngen $(TOOLS) qemu-doc.html + for d in $(TARGET_DIRS); do \ + make -C $$d $@ || exit 1 ; \ + done vlmkcow: vlmkcow.o - $(CC) -o $@ $^ $(LIBS) - -depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend - -# libqemu - -libqemu.a: $(LIBOBJS) - rm -f $@ - $(AR) rcs $@ $(LIBOBJS) - -dyngen: dyngen.c - $(HOST_CC) -O2 -Wall -g $< -o $@ - -translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h - -translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h - -op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen - ./dyngen -o $@ $< - -opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen - ./dyngen -c -o $@ $< - -gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen - ./dyngen -g -o $@ $< - -op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c - $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $< - -helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c - $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< - -op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h + $(HOST_CC) -o $@ $^ $(LIBS) -op-arm.o: op-arm.c op-arm-template.h +dyngen: dyngen.o + $(HOST_CC) -o $@ $^ $(LIBS) %.o: %.c - $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + $(HOST_CC) $(CFLAGS) $(DEFINES) -c -o $@ $< clean: - $(MAKE) -C tests clean - rm -f *.o *.a *~ qemu dyngen TAGS + rm -f *.o *.a $(TOOLS) dyngen TAGS + for d in $(TARGET_DIRS); do \ + make -C $$d $@ || exit 1 ; \ + done distclean: clean rm -f config.mak config.h -install: $(PROGS) +install: all mkdir -p $(prefix)/bin - install -m 755 -s $(PROGS) $(prefix)/bin + install -m 755 -s $(TOOLS) $(prefix)/bin + for d in $(TARGET_DIRS); do \ + make -C $$d $@ || exit 1 ; \ + done # various test targets -test speed: qemu +test speed: all make -C tests $@ TAGS: diff --git a/Makefile.target b/Makefile.target new file mode 100644 index 000000000..db72eeb08 --- /dev/null +++ b/Makefile.target @@ -0,0 +1,201 @@ +include config.mak + +VPATH=$(SRC_PATH) +CFLAGS=-Wall -O2 -g +LDFLAGS=-g +LIBS= +DEFINES=-I. +HELPER_CFLAGS=$(CFLAGS) +DYNGEN=../dyngen +ifndef CONFIG_SOFTMMU +PROGS=qemu +endif + +ifdef CONFIG_STATIC +LDFLAGS+=-static +endif + +ifeq ($(ARCH),i386) +CFLAGS+=-fomit-frame-pointer +OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2 +ifeq ($(HAVE_GCC3_OPTIONS),yes) +OP_CFLAGS+= -falign-functions=0 +else +OP_CFLAGS+= -malign-functions=0 +endif +ifdef TARGET_GPROF +LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld +else +# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object +# that the kernel ELF loader considers as an executable. I think this +# is the simplest way to make it self virtualizable! +LDFLAGS+=-Wl,-shared +endif +ifeq ($(TARGET_ARCH), i386) +PROGS+=vl +endif +endif + +ifeq ($(ARCH),ppc) +OP_CFLAGS=$(CFLAGS) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld +endif + +ifeq ($(ARCH),s390) +OP_CFLAGS=$(CFLAGS) +LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld +endif + +ifeq ($(ARCH),sparc) +CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +LDFLAGS+=-m32 +OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 +HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat +# -static is used to avoid g1/g3 usage by the dynamic linker +LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static +endif + +ifeq ($(ARCH),sparc64) +CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +LDFLAGS+=-m64 +OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 +endif + +ifeq ($(ARCH),alpha) +# -msmall-data is not used because we want two-instruction relocations +# for the constant constructions +OP_CFLAGS=-Wall -O2 -g +# Ensure there's only a single GP +CFLAGS += -msmall-data +LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld +endif + +ifeq ($(ARCH),ia64) +OP_CFLAGS=$(CFLAGS) +endif + +ifeq ($(ARCH),arm) +OP_CFLAGS=$(CFLAGS) -mno-sched-prolog +LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld +endif + +ifeq ($(HAVE_GCC3_OPTIONS),yes) +# very important to generate a return at the end of every operation +OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls +endif + +######################################################### + +DEFINES+=-D_GNU_SOURCE +LIBS+=-lm + +# profiling code +ifdef TARGET_GPROF +LDFLAGS+=-p +main.o: CFLAGS+=-p +endif + +OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o +ifeq ($(TARGET_ARCH), i386) +OBJS+= vm86.o +endif +SRCS:= $(OBJS:.o=.c) +OBJS+= libqemu.a + +# cpu emulator library +LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o + +ifeq ($(TARGET_ARCH), i386) +LIBOBJS+=translate-i386.o op-i386.o helper-i386.o helper2-i386.o +endif +ifeq ($(TARGET_ARCH), arm) +LIBOBJS+=translate-arm.o op-arm.o +endif + +# NOTE: the disassembler code is only needed for debugging +LIBOBJS+=disas.o +ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) +LIBOBJS+=i386-dis.o +endif +ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha) +LIBOBJS+=alpha-dis.o +endif +ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc) +LIBOBJS+=ppc-dis.o +endif +ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc) +LIBOBJS+=sparc-dis.o +endif +ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm) +LIBOBJS+=arm-dis.o +endif + +ifeq ($(ARCH),ia64) +OBJS += ia64-syscall.o +endif + +all: $(PROGS) qemu-doc.html + +qemu: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) +ifeq ($(ARCH),alpha) +# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of +# the address space (31 bit so sign extending doesn't matter) + echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc +endif + +# must use static linking to avoid leaving stuff in virtual address space +VL_OBJS=vl.o block.o vga.o +ifdef CONFIG_SDL +VL_OBJS+=sdl.o +SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl +endif + +vl: $(VL_OBJS) libqemu.a + $(CC) -static -Wl,-T,$(SRC_PATH)/i386-vl.ld -o $@ $^ $(LIBS) $(SDL_LIBS) + +sdl.o: sdl.c + $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< + +depend: $(SRCS) + $(CC) -MM $(CFLAGS) $^ 1>.depend + +# libqemu + +libqemu.a: $(LIBOBJS) + rm -f $@ + $(AR) rcs $@ $(LIBOBJS) + +translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h + +translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h + +op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN) + $(DYNGEN) -o $@ $< + +opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN) + $(DYNGEN) -c -o $@ $< + +gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN) + $(DYNGEN) -g -o $@ $< + +op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c + $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $< + +helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c + $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< + +op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h + +op-arm.o: op-arm.c op-arm-template.h + +%.o: %.c + $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + +clean: + rm -f *.o *.a *~ $(PROGS) \ + gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h op-$(TARGET_ARCH).h + +ifneq ($(wildcard .depend),) +include .depend +endif diff --git a/tests/Makefile b/tests/Makefile index 52e81297a..f4e1b22f4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -include ../config.mak +include ../config-host.mak CFLAGS=-Wall -O2 -g LDFLAGS= @@ -8,7 +8,7 @@ TESTS=testclone testsig testthread sha1-i386 test-i386 runcom endif TESTS+=sha1 test_path -QEMU=../qemu +QEMU=../i386/qemu all: $(TESTS) -- cgit v1.2.3 From 4021dab0594761c939b258cad67275c492b88e4d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 21:41:46 +0000 Subject: soft mmu support - moved unrelated code to help2-i386.c - synthetize string instructions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@353 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 790 ++++++++++++++++++++++++++----------------------------- 1 file changed, 375 insertions(+), 415 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index dd4a8a486..e527c901d 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -30,8 +30,6 @@ #include "exec.h" #include "disas.h" -//#define DEBUG_MMU - /* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; @@ -62,6 +60,7 @@ typedef struct DisasContext { int cpl; int iopl; int tf; /* TF cpu flag */ + int mem_index; /* select memory access functions */ struct TranslationBlock *tb; int popl_esp_hack; /* for correct popl with esp base handling */ } DisasContext; @@ -565,37 +564,81 @@ static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { }, }; -static GenOpFunc *gen_op_lds_T0_A0[3] = { +static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = { gen_op_ldsb_T0_A0, gen_op_ldsw_T0_A0, + NULL, + + gen_op_ldsb_kernel_T0_A0, + gen_op_ldsw_kernel_T0_A0, + NULL, + + gen_op_ldsb_user_T0_A0, + gen_op_ldsw_user_T0_A0, + NULL, }; -static GenOpFunc *gen_op_ldu_T0_A0[3] = { +static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = { gen_op_ldub_T0_A0, gen_op_lduw_T0_A0, + NULL, + + gen_op_ldub_kernel_T0_A0, + gen_op_lduw_kernel_T0_A0, + NULL, + + gen_op_ldub_user_T0_A0, + gen_op_lduw_user_T0_A0, + NULL, }; -/* sign does not matter */ -static GenOpFunc *gen_op_ld_T0_A0[3] = { +/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */ +static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = { gen_op_ldub_T0_A0, gen_op_lduw_T0_A0, gen_op_ldl_T0_A0, + + gen_op_ldub_kernel_T0_A0, + gen_op_lduw_kernel_T0_A0, + gen_op_ldl_kernel_T0_A0, + + gen_op_ldub_user_T0_A0, + gen_op_lduw_user_T0_A0, + gen_op_ldl_user_T0_A0, }; -static GenOpFunc *gen_op_ld_T1_A0[3] = { +static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = { gen_op_ldub_T1_A0, gen_op_lduw_T1_A0, gen_op_ldl_T1_A0, + + gen_op_ldub_kernel_T1_A0, + gen_op_lduw_kernel_T1_A0, + gen_op_ldl_kernel_T1_A0, + + gen_op_ldub_user_T1_A0, + gen_op_lduw_user_T1_A0, + gen_op_ldl_user_T1_A0, }; -static GenOpFunc *gen_op_st_T0_A0[3] = { +static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { gen_op_stb_T0_A0, gen_op_stw_T0_A0, gen_op_stl_T0_A0, + + gen_op_stb_kernel_T0_A0, + gen_op_stw_kernel_T0_A0, + gen_op_stl_kernel_T0_A0, + + gen_op_stb_user_T0_A0, + gen_op_stw_user_T0_A0, + gen_op_stl_user_T0_A0, }; /* the _a32 and _a16 string operations use A0 as the base register. */ +#define STRINGOP_NB 9 + #define STRINGOP(x) \ gen_op_ ## x ## b_fast, \ gen_op_ ## x ## w_fast, \ @@ -607,44 +650,275 @@ static GenOpFunc *gen_op_st_T0_A0[3] = { gen_op_ ## x ## w_a16, \ gen_op_ ## x ## l_a16, -static GenOpFunc *gen_op_movs[9 * 2] = { - STRINGOP(movs) - STRINGOP(rep_movs) +static GenOpFunc *gen_op_scas[STRINGOP_NB * 3] = { + STRINGOP(repz_scas) + STRINGOP(repnz_scas) }; -static GenOpFunc *gen_op_stos[9 * 2] = { - STRINGOP(stos) - STRINGOP(rep_stos) +static GenOpFunc *gen_op_cmps[STRINGOP_NB * 3] = { + STRINGOP(repz_cmps) + STRINGOP(repnz_cmps) }; -static GenOpFunc *gen_op_lods[9 * 2] = { - STRINGOP(lods) - STRINGOP(rep_lods) -}; +static inline void gen_string_movl_A0_ESI(DisasContext *s) +{ + int override; -static GenOpFunc *gen_op_scas[9 * 3] = { - STRINGOP(scas) - STRINGOP(repz_scas) - STRINGOP(repnz_scas) + override = s->override; + if (s->aflag) { + /* 32 bit address */ + if (s->addseg && override < 0) + override = R_DS; + if (override >= 0) { + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addl_A0_reg_sN[0][R_ESI](); + } else { + gen_op_movl_A0_reg[R_ESI](); + } + } else { + /* 16 address, always override */ + if (override < 0) + override = R_DS; + gen_op_movl_A0_reg[R_ESI](); + gen_op_andl_A0_ffff(); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } +} + +static inline void gen_string_movl_A0_EDI(DisasContext *s) +{ + if (s->aflag) { + if (s->addseg) { + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); + gen_op_addl_A0_reg_sN[0][R_EDI](); + } else { + gen_op_movl_A0_reg[R_EDI](); + } + } else { + gen_op_movl_A0_reg[R_EDI](); + gen_op_andl_A0_ffff(); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); + } +} + +static GenOpFunc *gen_op_movl_T0_Dshift[3] = { + gen_op_movl_T0_Dshiftb, + gen_op_movl_T0_Dshiftw, + gen_op_movl_T0_Dshiftl, }; -static GenOpFunc *gen_op_cmps[9 * 3] = { - STRINGOP(cmps) - STRINGOP(repz_cmps) - STRINGOP(repnz_cmps) +static GenOpFunc2 *gen_op_jz_ecx[2] = { + gen_op_jz_ecxw, + gen_op_jz_ecxl, +}; + +static GenOpFunc *gen_op_dec_ECX[2] = { + gen_op_decw_ECX, + gen_op_decl_ECX, }; -static GenOpFunc *gen_op_ins[9 * 2] = { - STRINGOP(ins) - STRINGOP(rep_ins) +static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = { + { + gen_op_string_jnz_subb, + gen_op_string_jnz_subw, + gen_op_string_jnz_subl, + }, + { + gen_op_string_jz_subb, + gen_op_string_jz_subw, + gen_op_string_jz_subl, + }, }; +static GenOpFunc *gen_op_in_DX_T0[3] = { + gen_op_inb_DX_T0, + gen_op_inw_DX_T0, + gen_op_inl_DX_T0, +}; -static GenOpFunc *gen_op_outs[9 * 2] = { - STRINGOP(outs) - STRINGOP(rep_outs) +static GenOpFunc *gen_op_out_DX_T0[3] = { + gen_op_outb_DX_T0, + gen_op_outw_DX_T0, + gen_op_outl_DX_T0, }; +static inline void gen_movs(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_ESI_T0(); + gen_op_addw_EDI_T0(); + } +} + +/* same method as Valgrind : we generate jumps to current or next + instruction */ +static inline void gen_repz_movs(DisasContext *s, int ot, + unsigned int cur_eip, unsigned int next_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + gen_movs(s, ot); + gen_op_dec_ECX[s->aflag](); + gen_op_jmp_tb_next((long)s->tb, cur_eip); + s->is_jmp = 3; +} + +static inline void gen_stos(DisasContext *s, int ot) +{ + gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_repz_stos(DisasContext *s, int ot, + unsigned int cur_eip, unsigned int next_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + gen_stos(s, ot); + gen_op_dec_ECX[s->aflag](); + gen_op_jmp_tb_next((long)s->tb, cur_eip); + s->is_jmp = 3; +} + +static inline void gen_lods(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_mov_reg_T0[ot][R_EAX](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + } else { + gen_op_addw_ESI_T0(); + } +} + +static inline void gen_repz_lods(DisasContext *s, int ot, + unsigned int cur_eip, unsigned int next_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + gen_lods(s, ot); + gen_op_dec_ECX[s->aflag](); + gen_op_jmp_tb_next((long)s->tb, cur_eip); + s->is_jmp = 3; +} + +static inline void gen_scas(DisasContext *s, int ot) +{ + gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); + gen_string_movl_A0_EDI(s); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_cmpl_T0_T1_cc(); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +#if 0 +static inline void gen_repz_scas(DisasContext *s, int ot, + unsigned int cur_eip, unsigned int next_eip, + int nz) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + gen_scas(s, ot); + gen_op_set_cc_op(CC_OP_SUBB + ot); + gen_op_string_jnz_sub[nz][ot]((long)s->tb, next_eip); + gen_op_dec_ECX[s->aflag](); + gen_op_jmp_tb_next((long)s->tb, cur_eip); + s->is_jmp = 3; +} +#endif + +static inline void gen_cmps(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_string_movl_A0_EDI(s); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_cmpl_T0_T1_cc(); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_ESI_T0(); + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_ins(DisasContext *s, int ot) +{ + gen_op_in_DX_T0[ot](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_repz_ins(DisasContext *s, int ot, + unsigned int cur_eip, unsigned int next_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + gen_ins(s, ot); + gen_op_dec_ECX[s->aflag](); + gen_op_jmp_tb_next((long)s->tb, cur_eip); + s->is_jmp = 3; +} + +static inline void gen_outs(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_out_DX_T0[ot](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + } else { + gen_op_addw_ESI_T0(); + } +} + +static inline void gen_repz_outs(DisasContext *s, int ot, + unsigned int cur_eip, unsigned int next_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + gen_outs(s, ot); + gen_op_dec_ECX[s->aflag](); + gen_op_jmp_tb_next((long)s->tb, cur_eip); + s->is_jmp = 3; +} static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) { @@ -833,7 +1107,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) if (d != OR_TMP0) { gen_op_mov_TN_reg[ot][0][d](); } else { - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s1->mem_index](); } switch(op) { case OP_ADCL: @@ -876,7 +1150,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); else - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s1->mem_index](); } /* the flags update must happen after the memory write (precise exception support) */ @@ -891,7 +1165,7 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) if (d != OR_TMP0) gen_op_mov_TN_reg[ot][0][d](); else - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s1->mem_index](); if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); if (c > 0) { @@ -904,7 +1178,7 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); else - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s1->mem_index](); gen_op_update_inc_cc(); } @@ -913,7 +1187,7 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) if (d != OR_TMP0) gen_op_mov_TN_reg[ot][0][d](); else - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s1->mem_index](); if (s != OR_TMP1) gen_op_mov_TN_reg[ot][1][s](); /* for zero counts, flags are not updated, so must do it dynamically */ @@ -1107,9 +1381,9 @@ static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_s if (is_store) { if (reg != OR_TMP0) gen_op_mov_TN_reg[ot][0][reg](); - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); } else { - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s->mem_index](); if (reg != OR_TMP0) gen_op_mov_reg_T0[ot][reg](); } @@ -1376,7 +1650,7 @@ static void gen_pusha(DisasContext *s) gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); for(i = 0;i < 8; i++) { gen_op_mov_TN_reg[OT_LONG][0][7 - i](); - gen_op_st_T0_A0[OT_WORD + s->dflag](); + gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index](); gen_op_addl_A0_im(2 << s->dflag); } gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); @@ -1396,7 +1670,7 @@ static void gen_popa(DisasContext *s) for(i = 0;i < 8; i++) { /* ESP is not reloaded */ if (i != 3) { - gen_op_ld_T0_A0[OT_WORD + s->dflag](); + gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index](); gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); } gen_op_addl_A0_im(2 << s->dflag); @@ -1424,17 +1698,17 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); /* push bp */ gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); if (level) { while (level--) { gen_op_addl_A0_im(-opsize); gen_op_addl_T0_im(-opsize); - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); } gen_op_addl_A0_im(-opsize); /* XXX: add st_T1_A0 ? */ gen_op_movl_T0_T1(); - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); } gen_op_mov_reg_T1[ot][R_EBP](); addend = -esp_addend; @@ -1613,7 +1887,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) rm = modrm & 7; if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot](); + gen_op_ld_T1_A0[ot + s->mem_index](); } else if (op == OP_XORL && rm == reg) { goto xor_zero; } else { @@ -1691,7 +1965,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) op = (modrm >> 3) & 7; if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s->mem_index](); } else { gen_op_mov_TN_reg[ot][0][rm](); } @@ -1706,7 +1980,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 2: /* not */ gen_op_notl_T0(); if (mod != 3) { - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); } else { gen_op_mov_reg_T0[ot][rm](); } @@ -1714,7 +1988,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 3: /* neg */ gen_op_negl_T0(); if (mod != 3) { - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); } else { gen_op_mov_reg_T0[ot][rm](); } @@ -1801,7 +2075,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (op >= 2 && op != 3 && op != 5) - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s->mem_index](); } else { gen_op_mov_TN_reg[ot][0][rm](); } @@ -1832,9 +2106,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->is_jmp = 1; break; case 3: /* lcall Ev */ - gen_op_ld_T1_A0[ot](); + gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); - gen_op_lduw_T0_A0(); + gen_op_ld_T0_A0[OT_WORD + s->mem_index](); do_lcall: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) @@ -1853,7 +2127,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->is_jmp = 1; break; case 5: /* ljmp Ev */ - gen_op_ld_T1_A0[ot](); + gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_lduw_T0_A0(); do_ljmp: @@ -1965,9 +2239,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_mov_TN_reg[ot][0][reg](); - gen_op_ld_T1_A0[ot](); + gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_addl_T0_T1(); - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); gen_op_mov_reg_T1[ot][reg](); } gen_op_update2_cc(); @@ -1990,7 +2264,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_reg_T0[ot][rm](); } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s->mem_index](); gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); } s->cc_op = CC_OP_SUBB + ot; @@ -2121,7 +2395,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) val = insn_get(s, ot); gen_op_movl_T0_im(val); if (mod != 3) - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); else gen_op_mov_reg_T0[ot][modrm & 7](); break; @@ -2195,9 +2469,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (b & 8) { - gen_op_lds_T0_A0[ot](); + gen_op_lds_T0_A0[ot + s->mem_index](); } else { - gen_op_ldu_T0_A0[ot](); + gen_op_ldu_T0_A0[ot + s->mem_index](); } gen_op_mov_reg_T0[d_ot][reg](); } @@ -2245,11 +2519,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } } if ((b & 2) == 0) { - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s->mem_index](); gen_op_mov_reg_T0[ot][R_EAX](); } else { gen_op_mov_TN_reg[ot][0][R_EAX](); - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); } break; case 0xd7: /* xlat */ @@ -2272,7 +2546,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); } } - gen_op_ldub_T0_A0(); + gen_op_ldu_T0_A0[OT_BYTE + s->mem_index](); gen_op_mov_reg_T0[OT_BYTE][R_EAX](); break; case 0xb0 ... 0xb7: /* mov R, Ib */ @@ -2315,8 +2589,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* for xchg, lock is implicit */ if (!(prefixes & PREFIX_LOCK)) gen_op_lock(); - gen_op_ld_T1_A0[ot](); - gen_op_st_T0_A0[ot](); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_st_T0_A0[ot + s->mem_index](); if (!(prefixes & PREFIX_LOCK)) gen_op_unlock(); gen_op_mov_reg_T1[ot][reg](); @@ -2344,7 +2618,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot](); + gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ gen_op_lduw_T0_A0(); @@ -2424,7 +2698,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s->mem_index](); } else { gen_op_mov_TN_reg[ot][0][rm](); } @@ -2869,9 +3143,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = dflag ? OT_LONG : OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_string_ds(s, ot, gen_op_movs + 9); + gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { - gen_string_ds(s, ot, gen_op_movs); + gen_movs(s, ot); } break; @@ -2883,9 +3157,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) ot = dflag ? OT_LONG : OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_string_es(s, ot, gen_op_stos + 9); + gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { - gen_string_es(s, ot, gen_op_stos); + gen_stos(s, ot); } break; case 0xac: /* lodsS */ @@ -2895,9 +3169,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_string_ds(s, ot, gen_op_lods + 9); + gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { - gen_string_ds(s, ot, gen_op_lods); + gen_lods(s, ot); } break; case 0xae: /* scasS */ @@ -2909,15 +3183,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (prefixes & PREFIX_REPNZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_string_es(s, ot, gen_op_scas + 9 * 2); + gen_string_es(s, ot, gen_op_scas + STRINGOP_NB); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_string_es(s, ot, gen_op_scas + 9); + gen_string_es(s, ot, gen_op_scas); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { - gen_string_es(s, ot, gen_op_scas); + gen_scas(s, ot); s->cc_op = CC_OP_SUBB + ot; } break; @@ -2931,15 +3205,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (prefixes & PREFIX_REPNZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_string_ds(s, ot, gen_op_cmps + 9 * 2); + gen_string_ds(s, ot, gen_op_cmps + STRINGOP_NB); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_string_ds(s, ot, gen_op_cmps + 9); + gen_string_ds(s, ot, gen_op_cmps); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { - gen_string_ds(s, ot, gen_op_cmps); + gen_cmps(s, ot); s->cc_op = CC_OP_SUBB + ot; } break; @@ -2954,9 +3228,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_string_es(s, ot, gen_op_ins + 9); + gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { - gen_string_es(s, ot, gen_op_ins); + gen_ins(s, ot); } } break; @@ -2971,9 +3245,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_string_ds(s, ot, gen_op_outs + 9); + gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { - gen_string_ds(s, ot, gen_op_outs); + gen_outs(s, ot); } } break; @@ -3071,7 +3345,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_stack_A0(s); /* pop offset */ - gen_op_ld_T0_A0[1 + s->dflag](); + gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); if (s->dflag == 0) gen_op_andl_T0_ffff(); /* NOTE: keeping EIP updated is not a problem in case of @@ -3079,7 +3353,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_jmp_T0(); /* pop selector */ gen_op_addl_A0_im(2 << s->dflag); - gen_op_ld_T0_A0[1 + s->dflag](); + gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); /* add stack offset */ gen_stack_update(s, val + (4 << s->dflag)); @@ -3188,7 +3462,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_setcc(s, b); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot](); + gen_op_ld_T1_A0[ot + s->mem_index](); } else { rm = modrm & 7; gen_op_mov_TN_reg[ot][1][rm](); @@ -3279,7 +3553,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) rm = modrm & 7; if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s->mem_index](); } else { gen_op_mov_TN_reg[ot][0][rm](); } @@ -3293,7 +3567,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->cc_op = CC_OP_SARB + ot; if (op != 0) { if (mod != 3) - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); else gen_op_mov_reg_T0[ot][rm](); gen_op_update_bt_cc(); @@ -3324,7 +3598,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_add_bitw_A0_T1(); else gen_op_add_bitl_A0_T1(); - gen_op_ld_T0_A0[ot](); + gen_op_ld_T0_A0[ot + s->mem_index](); } else { gen_op_mov_TN_reg[ot][0][rm](); } @@ -3332,7 +3606,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) s->cc_op = CC_OP_SARB + ot; if (op != 0) { if (mod != 3) - gen_op_st_T0_A0[ot](); + gen_op_st_T0_A0[ot + s->mem_index](); else gen_op_mov_reg_T0[ot][rm](); gen_op_update_bt_cc(); @@ -3569,7 +3843,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); else gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); - gen_op_stw_T0_A0(); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); gen_op_addl_A0_im(2); if (op == 0) gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); @@ -3577,7 +3851,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); - gen_op_stl_T0_A0(); + gen_op_st_T0_A0[OT_LONG + s->mem_index](); break; case 2: /* lgdt */ case 3: /* lidt */ @@ -3587,9 +3861,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_lduw_T1_A0(); + gen_op_ld_T1_A0[OT_WORD + s->mem_index](); gen_op_addl_A0_im(2); - gen_op_ldl_T0_A0(); + gen_op_ld_T0_A0[OT_LONG + s->mem_index](); if (!s->dflag) gen_op_andl_T0_im(0xffffff); if (op == 2) { @@ -3990,10 +4264,8 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ [INDEX_op_ ## x ## l_a16] = CC_OSZAPC, - STRINGOP(scas) STRINGOP(repz_scas) STRINGOP(repnz_scas) - STRINGOP(cmps) STRINGOP(repz_cmps) STRINGOP(repnz_cmps) @@ -4050,7 +4322,7 @@ static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, }; -static void optimize_flags_init(void) +void optimize_flags_init(void) { int i; /* put default values in arrays */ @@ -4120,6 +4392,14 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->cs_base = cs_base; dc->tb = tb; dc->popl_esp_hack = 0; + /* select memory access functions */ + dc->mem_index = 0; + if ((flags >> GEN_FLAG_SOFT_MMU_SHIFT) & 1) { + if (dc->cpl == 3) + dc->mem_index = 6; + else + dc->mem_index = 3; + } gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; @@ -4234,323 +4514,3 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } -CPUX86State *cpu_x86_init(void) -{ - CPUX86State *env; - int i; - static int inited; - - cpu_exec_init(); - - env = malloc(sizeof(CPUX86State)); - if (!env) - return NULL; - memset(env, 0, sizeof(CPUX86State)); - /* basic FPU init */ - for(i = 0;i < 8; i++) - env->fptags[i] = 1; - env->fpuc = 0x37f; - /* flags setup : we activate the IRQs by default as in user mode */ - env->eflags = 0x2 | IF_MASK; - - /* init various static tables */ - if (!inited) { - inited = 1; - optimize_flags_init(); - } - return env; -} - -void cpu_x86_close(CPUX86State *env) -{ - free(env); -} - -/***********************************************************/ -/* x86 mmu */ -/* XXX: add PGE support */ - -/* called when cr3 or PG bit are modified */ -static int last_pg_state = -1; -static int last_pe_state = 0; -int phys_ram_size; -int phys_ram_fd; -uint8_t *phys_ram_base; - -void cpu_x86_update_cr0(CPUX86State *env) -{ - int pg_state, pe_state; - void *map_addr; - -#ifdef DEBUG_MMU - printf("CR0 update: CR0=0x%08x\n", env->cr[0]); -#endif - pg_state = env->cr[0] & CR0_PG_MASK; - if (pg_state != last_pg_state) { - if (!pg_state) { - /* we map the physical memory at address 0 */ - - map_addr = mmap((void *)0, phys_ram_size, PROT_WRITE | PROT_READ, - MAP_SHARED | MAP_FIXED, phys_ram_fd, 0); - if (map_addr == MAP_FAILED) { - fprintf(stderr, - "Could not map physical memory at host address 0x%08x\n", - 0); - exit(1); - } - page_set_flags(0, phys_ram_size, - PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC); - } else { - /* we unmap the physical memory */ - munmap((void *)0, phys_ram_size); - page_set_flags(0, phys_ram_size, 0); - } - last_pg_state = pg_state; - } - pe_state = env->cr[0] & CR0_PE_MASK; - if (last_pe_state != pe_state) { - tb_flush(); - last_pe_state = pe_state; - } -} - -void cpu_x86_update_cr3(CPUX86State *env) -{ - if (env->cr[0] & CR0_PG_MASK) { -#if defined(DEBUG_MMU) - printf("CR3 update: CR3=%08x\n", env->cr[3]); -#endif - page_unmap(); - } -} - -void cpu_x86_init_mmu(CPUX86State *env) -{ - last_pg_state = -1; - cpu_x86_update_cr0(env); -} - -/* XXX: also flush 4MB pages */ -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) -{ - int flags; - unsigned long virt_addr; - - flags = page_get_flags(addr); - if (flags & PAGE_VALID) { - virt_addr = addr & ~0xfff; - munmap((void *)virt_addr, 4096); - page_set_flags(virt_addr, virt_addr + 4096, 0); - } -} - -/* return value: - -1 = cannot handle fault - 0 = nothing more to do - 1 = generate PF fault -*/ -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) -{ - uint8_t *pde_ptr, *pte_ptr; - uint32_t pde, pte, virt_addr; - int cpl, error_code, is_dirty, is_user, prot, page_size; - void *map_addr; - - cpl = env->cpl; - is_user = (cpl == 3); - -#ifdef DEBUG_MMU - printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", - addr, is_write, is_user, env->eip); -#endif - - if (env->user_mode_only) { - /* user mode only emulation */ - error_code = 0; - goto do_fault; - } - - if (!(env->cr[0] & CR0_PG_MASK)) - return -1; - - /* page directory entry */ - pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); - pde = ldl(pde_ptr); - if (!(pde & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (is_user) { - if (!(pde & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && - is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } - /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - is_dirty = is_write && !(pde & PG_DIRTY_MASK); - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_DIRTY_MASK; - stl(pde_ptr, pde); - } - - pte = pde & ~0x003ff000; /* align to 4MB */ - page_size = 4096 * 1024; - virt_addr = addr & ~0x003fffff; - } else { - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - stl(pde_ptr, pde); - } - - /* page directory entry */ - pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); - pte = ldl(pte_ptr); - if (!(pte & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (is_user) { - if (!(pte & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(pte & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && - is_write && !(pte & PG_RW_MASK)) - goto do_fault_protect; - } - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) - pte |= PG_DIRTY_MASK; - stl(pte_ptr, pte); - } - page_size = 4096; - virt_addr = addr & ~0xfff; - } - /* the page can be put in the TLB */ - prot = PROT_READ; - if (is_user) { - if (pte & PG_RW_MASK) - prot |= PROT_WRITE; - } else { - if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || - (pte & PG_RW_MASK)) - prot |= PROT_WRITE; - } - map_addr = mmap((void *)virt_addr, page_size, prot, - MAP_SHARED | MAP_FIXED, phys_ram_fd, pte & ~0xfff); - if (map_addr == MAP_FAILED) { - fprintf(stderr, - "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", - pte & ~0xfff, virt_addr); - exit(1); - } - page_set_flags(virt_addr, virt_addr + page_size, - PAGE_VALID | PAGE_EXEC | prot); -#ifdef DEBUG_MMU - printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", - pte & ~0xfff, virt_addr, (page_size != 4096)); -#endif - return 0; - do_fault_protect: - error_code = PG_ERROR_P_MASK; - do_fault: - env->cr[2] = addr; - env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; - if (is_user) - env->error_code |= PG_ERROR_U_MASK; - return 1; -} - -/***********************************************************/ -/* x86 debug */ - -static const char *cc_op_str[] = { - "DYNAMIC", - "EFLAGS", - "MUL", - "ADDB", - "ADDW", - "ADDL", - "ADCB", - "ADCW", - "ADCL", - "SUBB", - "SUBW", - "SUBL", - "SBBB", - "SBBW", - "SBBL", - "LOGICB", - "LOGICW", - "LOGICL", - "INCB", - "INCW", - "INCL", - "DECB", - "DECW", - "DECL", - "SHLB", - "SHLW", - "SHLL", - "SARB", - "SARW", - "SARL", -}; - -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) -{ - int eflags; - char cc_op_name[32]; - - eflags = env->eflags; - fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", - env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], - env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], - env->eip, eflags, - eflags & DF_MASK ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-'); - fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", - env->segs[R_CS].selector, - env->segs[R_SS].selector, - env->segs[R_DS].selector, - env->segs[R_ES].selector, - env->segs[R_FS].selector, - env->segs[R_GS].selector); - if (flags & X86_DUMP_CCOP) { - if ((unsigned)env->cc_op < CC_OP_NB) - strcpy(cc_op_name, cc_op_str[env->cc_op]); - else - snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); - fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", - env->cc_src, env->cc_dst, cc_op_name); - } - if (flags & X86_DUMP_FPU) { - fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", - (double)env->fpregs[0], - (double)env->fpregs[1], - (double)env->fpregs[2], - (double)env->fpregs[3]); - fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", - (double)env->fpregs[4], - (double)env->fpregs[5], - (double)env->fpregs[7], - (double)env->fpregs[8]); - } -} -- cgit v1.2.3 From 33417e7025afa5ea1c38c3c2b2ea53d975b5648b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 21:47:01 +0000 Subject: soft mmu support - Memory I/O API - synthetize string instructions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@354 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 12 +++++ cpu-arm.h | 4 +- cpu-i386.h | 20 ++++---- exec-i386.h | 50 +++++++++++++++++++ exec.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++ exec.h | 43 ++++++++++++++--- helper-i386.c | 33 ++++++++++++- op-i386.c | 100 +++++++++++++++----------------------- op_string.h | 150 --------------------------------------------------------- ops_template.h | 35 ++++++++++++++ 10 files changed, 351 insertions(+), 234 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index cde8451dd..65304927e 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -140,6 +140,7 @@ static inline void stfl(void *ptr, float v) stl(ptr, u.i); } + #if defined(__arm__) && !defined(WORDS_BIGENDIAN) /* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ @@ -317,6 +318,17 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc); int cpu_breakpoint_remove(CPUState *env, uint32_t pc); void cpu_single_step(CPUState *env, int enabled); +/* memory API */ + +typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); +typedef uint32_t CPUReadMemoryFunc(uint32_t addr); + +void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, + long phys_offset); +int cpu_register_io_memory(int io_index, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write); + /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); diff --git a/cpu-arm.h b/cpu-arm.h index 3b2e628e9..7f755a754 100644 --- a/cpu-arm.h +++ b/cpu-arm.h @@ -20,12 +20,10 @@ #ifndef CPU_ARM_H #define CPU_ARM_H -#include "config.h" -#include +#include "cpu-defs.h" #define EXCP_UDEF 1 /* undefined instruction */ #define EXCP_SWI 2 /* software interrupt */ -#define EXCP_INTERRUPT 256 /* async interruption */ typedef struct CPUARMState { uint32_t regs[16]; diff --git a/cpu-i386.h b/cpu-i386.h index 879ab1eb8..a60e95915 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -20,8 +20,7 @@ #ifndef CPU_I386_H #define CPU_I386_H -#include "config.h" -#include +#include "cpu-defs.h" #define R_EAX 0 #define R_ECX 1 @@ -153,12 +152,6 @@ #define EXCP11_ALGN 17 #define EXCP12_MCHK 18 -#define EXCP_INTERRUPT 256 /* async interruption */ -#define EXCP_HLT 257 /* hlt instruction reached */ -#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ - -#define MAX_BREAKPOINTS 32 - enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ @@ -257,7 +250,8 @@ typedef struct CPUX86State { SegmentCache gdt; /* only base and limit are used */ SegmentCache idt; /* only base and limit are used */ int cpl; /* current cpl */ - + int soft_mmu; /* TRUE if soft mmu is being used */ + /* sysenter registers */ uint32_t sysenter_cs; uint32_t sysenter_esp; @@ -275,10 +269,16 @@ typedef struct CPUX86State { int interrupt_request; int user_mode_only; /* user mode only simulation */ + /* soft mmu support */ + /* 0 = kernel, 1 = user */ + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + + /* ice debug support */ uint32_t breakpoints[MAX_BREAKPOINTS]; int nb_breakpoints; int singlestep_enabled; - + /* user data */ void *opaque; } CPUX86State; diff --git a/exec-i386.h b/exec-i386.h index 964abddfa..03a547fb1 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -138,6 +138,7 @@ void cpu_x86_update_cr0(CPUX86State *env); void cpu_x86_update_cr3(CPUX86State *env); void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); +void tlb_fill(unsigned long addr, int is_write, void *retaddr); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); void do_interrupt(int intno, int is_int, int error_code, @@ -364,3 +365,52 @@ static inline void load_eflags(int eflags, int update_mask) env->eflags = (env->eflags & ~update_mask) | (eflags & update_mask); } + +/* memory access macros */ + +#define ldul ldl +#define lduq ldq +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel + +#define ldub_raw ldub +#define ldsb_raw ldsb +#define lduw_raw lduw +#define ldsw_raw ldsw +#define ldl_raw ldl +#define ldq_raw ldq + +#define stb_raw stb +#define stw_raw stw +#define stl_raw stl +#define stq_raw stq + +#define MEMUSER 0 +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" + +#undef MEMUSER +#define MEMUSER 1 +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" + +#undef MEMUSER + diff --git a/exec.c b/exec.c index 5ea216325..cdc2a0be3 100644 --- a/exec.c +++ b/exec.c @@ -68,6 +68,7 @@ typedef struct PageDesc { #define L2_SIZE (1 << L2_BITS) static void tb_invalidate_page(unsigned long address); +static void io_mem_init(void); unsigned long real_host_page_size; unsigned long host_page_bits; @@ -76,6 +77,12 @@ unsigned long host_page_mask; static PageDesc *l1_map[L1_SIZE]; +/* io memory support */ +static unsigned long *l1_physmap[L1_SIZE]; +CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +static int io_mem_nb; + static void page_init(void) { /* NOTE: we can always suppose that host_page_size >= @@ -201,6 +208,7 @@ void cpu_exec_init(void) if (!code_gen_ptr) { code_gen_ptr = code_gen_buffer; page_init(); + io_mem_init(); } } @@ -744,3 +752,133 @@ void page_unmap(void) tb_flush(); } #endif + +void tlb_flush(CPUState *env) +{ +#if defined(TARGET_I386) + int i; + for(i = 0; i < CPU_TLB_SIZE; i++) { + env->tlb_read[0][i].address = -1; + env->tlb_write[0][i].address = -1; + env->tlb_read[1][i].address = -1; + env->tlb_write[1][i].address = -1; + } +#endif +} + +void tlb_flush_page(CPUState *env, uint32_t addr) +{ +#if defined(TARGET_I386) + int i; + + i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + env->tlb_read[0][i].address = -1; + env->tlb_write[0][i].address = -1; + env->tlb_read[1][i].address = -1; + env->tlb_write[1][i].address = -1; +#endif +} + +static inline unsigned long *physpage_find_alloc(unsigned int page) +{ + unsigned long **lp, *p; + unsigned int index, i; + + index = page >> TARGET_PAGE_BITS; + lp = &l1_physmap[index >> L2_BITS]; + p = *lp; + if (!p) { + /* allocate if not found */ + p = malloc(sizeof(unsigned long) * L2_SIZE); + for(i = 0; i < L2_SIZE; i++) + p[i] = IO_MEM_UNASSIGNED; + *lp = p; + } + return p + (index & (L2_SIZE - 1)); +} + +/* return NULL if no page defined (unused memory) */ +unsigned long physpage_find(unsigned long page) +{ + unsigned long *p; + unsigned int index; + index = page >> TARGET_PAGE_BITS; + p = l1_physmap[index >> L2_BITS]; + if (!p) + return IO_MEM_UNASSIGNED; + return p[index & (L2_SIZE - 1)]; +} + +/* register physical memory. 'size' must be a multiple of the target + page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an + io memory page */ +void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, + long phys_offset) +{ + unsigned long addr, end_addr; + unsigned long *p; + + end_addr = start_addr + size; + for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { + p = physpage_find_alloc(addr); + *p = phys_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) == 0) + phys_offset += TARGET_PAGE_SIZE; + } +} + +static uint32_t unassigned_mem_readb(uint32_t addr) +{ + return 0; +} + +static void unassigned_mem_writeb(uint32_t addr, uint32_t val) +{ +} + +static CPUReadMemoryFunc *unassigned_mem_read[3] = { + unassigned_mem_readb, + unassigned_mem_readb, + unassigned_mem_readb, +}; + +static CPUWriteMemoryFunc *unassigned_mem_write[3] = { + unassigned_mem_writeb, + unassigned_mem_writeb, + unassigned_mem_writeb, +}; + + +static void io_mem_init(void) +{ + io_mem_nb = 1; + cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write); +} + +/* mem_read and mem_write are arrays of functions containing the + function to access byte (index 0), word (index 1) and dword (index + 2). All functions must be supplied. If io_index is non zero, the + corresponding io zone is modified. If it is zero, a new io zone is + allocated. The return value can be used with + cpu_register_physical_memory(). (-1) is returned if error. */ +int cpu_register_io_memory(int io_index, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write) +{ + int i; + + if (io_index <= 0) { + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; + io_index = io_mem_nb++; + } else { + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; + } + + for(i = 0;i < 3; i++) { + io_mem_read[io_index][i] = mem_read[i]; + io_mem_write[io_index][i] = mem_write[i]; + } + return io_index << IO_MEM_SHIFT; +} diff --git a/exec.h b/exec.h index 9489c4777..5c4e841a7 100644 --- a/exec.h +++ b/exec.h @@ -21,6 +21,17 @@ /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#if GCC_MAJOR < 3 +#define __builtin_expect(x, n) (x) +#endif + /* is_jmp field values */ #define DISAS_NEXT 0 /* next instruction can be analyzed */ #define DISAS_JUMP 1 /* only pc was modified dynamically */ @@ -44,14 +55,17 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #if defined(TARGET_I386) -#define GEN_FLAG_CODE32_SHIFT 0 -#define GEN_FLAG_ADDSEG_SHIFT 1 -#define GEN_FLAG_SS32_SHIFT 2 -#define GEN_FLAG_VM_SHIFT 3 -#define GEN_FLAG_ST_SHIFT 4 -#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */ -#define GEN_FLAG_CPL_SHIFT 9 -#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ +#define GEN_FLAG_CODE32_SHIFT 0 +#define GEN_FLAG_ADDSEG_SHIFT 1 +#define GEN_FLAG_SS32_SHIFT 2 +#define GEN_FLAG_VM_SHIFT 3 +#define GEN_FLAG_ST_SHIFT 4 +#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */ +#define GEN_FLAG_CPL_SHIFT 9 +#define GEN_FLAG_SOFT_MMU_SHIFT 11 +#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ + +void optimize_flags_init(void); #endif @@ -68,6 +82,8 @@ int cpu_restore_state(struct TranslationBlock *tb, void cpu_exec_init(void); int page_unprotect(unsigned long address); void page_unmap(void); +void tlb_flush_page(CPUState *env, uint32_t addr); +void tlb_flush(CPUState *env); #define CODE_GEN_MAX_SIZE 65536 #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ @@ -230,6 +246,17 @@ dummy_label ## n:\ #endif +/* physical memory access */ +#define IO_MEM_NB_ENTRIES 256 +#define TLB_INVALID_MASK (1 << 3) +#define IO_MEM_SHIFT 4 +#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT) + +unsigned long physpage_find(unsigned long page); + +extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; + #ifdef __powerpc__ static inline int testandset (int *p) { diff --git a/helper-i386.c b/helper-i386.c index 0003fb46a..01046ea09 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -781,7 +781,7 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) int new_cs, new_eip; uint32_t esp, esp_mask; uint8_t *ssp; - + new_cs = T0; new_eip = T1; esp = env->regs[R_ESP]; @@ -1741,3 +1741,34 @@ void helper_frstor(uint8_t *ptr, int data32) } } +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error */ +void tlb_fill(unsigned long addr, int is_write, void *retaddr) +{ + TranslationBlock *tb; + int ret; + unsigned long pc; + ret = cpu_x86_handle_mmu_fault(env, addr, is_write); + if (ret) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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); + } + raise_exception_err(EXCP0E_PAGE, env->error_code); + } +} diff --git a/op-i386.c b/op-i386.c index fb062a0fc..60ae5e55f 100644 --- a/op-i386.c +++ b/op-i386.c @@ -376,70 +376,14 @@ void OPPROTO op_andl_A0_ffff(void) /* memory access */ -void OPPROTO op_ldub_T0_A0(void) -{ - T0 = ldub((uint8_t *)A0); -} - -void OPPROTO op_ldsb_T0_A0(void) -{ - T0 = ldsb((int8_t *)A0); -} - -void OPPROTO op_lduw_T0_A0(void) -{ - T0 = lduw((uint8_t *)A0); -} - -void OPPROTO op_ldsw_T0_A0(void) -{ - T0 = ldsw((int8_t *)A0); -} - -void OPPROTO op_ldl_T0_A0(void) -{ - T0 = ldl((uint8_t *)A0); -} +#define MEMSUFFIX +#include "ops_mem.h" -void OPPROTO op_ldub_T1_A0(void) -{ - T1 = ldub((uint8_t *)A0); -} - -void OPPROTO op_ldsb_T1_A0(void) -{ - T1 = ldsb((int8_t *)A0); -} - -void OPPROTO op_lduw_T1_A0(void) -{ - T1 = lduw((uint8_t *)A0); -} +#define MEMSUFFIX _user +#include "ops_mem.h" -void OPPROTO op_ldsw_T1_A0(void) -{ - T1 = ldsw((int8_t *)A0); -} - -void OPPROTO op_ldl_T1_A0(void) -{ - T1 = ldl((uint8_t *)A0); -} - -void OPPROTO op_stb_T0_A0(void) -{ - stb((uint8_t *)A0, T0); -} - -void OPPROTO op_stw_T0_A0(void) -{ - stw((uint8_t *)A0, T0); -} - -void OPPROTO op_stl_T0_A0(void) -{ - stl((uint8_t *)A0, T0); -} +#define MEMSUFFIX _kernel +#include "ops_mem.h" /* used for bit operations */ @@ -635,6 +579,38 @@ void OPPROTO op_movswl_DX_AX(void) EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff); } +/* string ops helpers */ + +void OPPROTO op_addl_ESI_T0(void) +{ + ESI += T0; +} + +void OPPROTO op_addw_ESI_T0(void) +{ + ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff); +} + +void OPPROTO op_addl_EDI_T0(void) +{ + EDI += T0; +} + +void OPPROTO op_addw_EDI_T0(void) +{ + EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff); +} + +void OPPROTO op_decl_ECX(void) +{ + ECX--; +} + +void OPPROTO op_decw_ECX(void) +{ + ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff); +} + /* push/pop */ void op_pushl_T0(void) diff --git a/op_string.h b/op_string.h index 79bc11e1a..66b598b23 100644 --- a/op_string.h +++ b/op_string.h @@ -1,94 +1,4 @@ -void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - v = glue(ldu, SUFFIX)(SI_ADDR); - glue(st, SUFFIX)(DI_ADDR, v); - inc = (DF << SHIFT); - INC_SI(); - INC_DI(); -} - -void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - inc = (DF << SHIFT); - while (CX != 0) { - v = glue(ldu, SUFFIX)(SI_ADDR); - glue(st, SUFFIX)(DI_ADDR, v); - INC_SI(); - INC_DI(); - DEC_CX(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void) -{ - int inc; - glue(st, SUFFIX)(DI_ADDR, EAX); - inc = (DF << SHIFT); - INC_DI(); -} - -void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void) -{ - int inc; - inc = (DF << SHIFT); - while (CX != 0) { - glue(st, SUFFIX)(DI_ADDR, EAX); - INC_DI(); - DEC_CX(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - v = glue(ldu, SUFFIX)(SI_ADDR); -#if SHIFT == 0 - EAX = (EAX & ~0xff) | v; -#elif SHIFT == 1 - EAX = (EAX & ~0xffff) | v; -#else - EAX = v; -#endif - inc = (DF << SHIFT); - INC_SI(); -} - -/* don't know if it is used */ -void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - inc = (DF << SHIFT); - while (CX != 0) { - v = glue(ldu, SUFFIX)(SI_ADDR); -#if SHIFT == 0 - EAX = (EAX & ~0xff) | v; -#elif SHIFT == 1 - EAX = (EAX & ~0xffff) | v; -#else - EAX = v; -#endif - INC_SI(); - DEC_CX(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - - v = glue(ldu, SUFFIX)(DI_ADDR); - inc = (DF << SHIFT); - INC_DI(); - CC_SRC = v; - CC_DST = EAX - v; -} - void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void) { int v1, v2, inc; @@ -133,18 +43,6 @@ void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void) FORCE_RET(); } -void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void) -{ - int v1, v2, inc; - v1 = glue(ldu, SUFFIX)(SI_ADDR); - v2 = glue(ldu, SUFFIX)(DI_ADDR); - inc = (DF << SHIFT); - INC_SI(); - INC_DI(); - CC_SRC = v2; - CC_DST = v1 - v2; -} - void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void) { int v1, v2, inc; @@ -187,54 +85,6 @@ void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void) FORCE_RET(); } -void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void) -{ - int v, dx, inc; - dx = EDX & 0xffff; - v = glue(ldu, SUFFIX)(SI_ADDR); - glue(cpu_x86_out, SUFFIX)(env, dx, v); - inc = (DF << SHIFT); - INC_SI(); -} - -void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void) -{ - int v, dx, inc; - inc = (DF << SHIFT); - dx = EDX & 0xffff; - while (CX != 0) { - v = glue(ldu, SUFFIX)(SI_ADDR); - glue(cpu_x86_out, SUFFIX)(env, dx, v); - INC_SI(); - DEC_CX(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void) -{ - int v, dx, inc; - dx = EDX & 0xffff; - v = glue(cpu_x86_in, SUFFIX)(env, dx); - glue(st, SUFFIX)(DI_ADDR, v); - inc = (DF << SHIFT); - INC_DI(); -} - -void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void) -{ - int v, dx, inc; - inc = (DF << SHIFT); - dx = EDX & 0xffff; - while (CX != 0) { - v = glue(cpu_x86_in, SUFFIX)(env, dx); - glue(st, SUFFIX)(DI_ADDR, v); - INC_DI(); - DEC_CX(); - } - FORCE_RET(); -} - #undef STRING_SUFFIX #undef SI_ADDR #undef DI_ADDR diff --git a/ops_template.h b/ops_template.h index 4595291e7..89480dddb 100644 --- a/ops_template.h +++ b/ops_template.h @@ -547,6 +547,31 @@ void OPPROTO op_update_bt_cc(void) #define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff) #include "op_string.h" +void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) +{ + T0 = DF << SHIFT; +} + +void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) +{ + if ((DATA_TYPE)CC_DST == 0) + JUMP_TB(PARAM1, 1, PARAM2); +} + +void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) +{ + if ((DATA_TYPE)CC_DST != 0) + JUMP_TB(PARAM1, 1, PARAM2); +} + +#if DATA_BITS >= 16 +void OPPROTO glue(op_jz_ecx, SUFFIX)(void) +{ + if ((DATA_TYPE)ECX == 0) + JUMP_TB(PARAM1, 1, PARAM2); +} +#endif + /* port I/O */ void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) @@ -559,6 +584,16 @@ void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff); } +void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void) +{ + T0 = glue(cpu_x86_in, SUFFIX)(env, EDX & 0xffff); +} + +void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void) +{ + glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0); +} + #undef DATA_BITS #undef SHIFT_MASK #undef SIGN_MASK -- cgit v1.2.3 From 4cbf74b6b8097ca4c2396449babff639dab601cf Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 21:48:43 +0000 Subject: soft mmu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@355 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index d478fa826..ecab6ff11 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -245,6 +245,7 @@ int cpu_exec(CPUState *env1) (unsigned long)env->segs[R_SS].base) != 0) << GEN_FLAG_ADDSEG_SHIFT; flags |= env->cpl << GEN_FLAG_CPL_SHIFT; + flags |= env->soft_mmu << GEN_FLAG_SOFT_MMU_SHIFT; flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT); flags |= (env->eflags & (IOPL_MASK | TF_MASK)); cs_base = env->segs[R_CS].base; @@ -333,6 +334,15 @@ int cpu_exec(CPUState *env1) 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->soft_mmu) { + env->soft_mmu = 0; + /* do not allow linking to another block */ + T0 = 0; + } +#endif } } else { } @@ -478,14 +488,21 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, a virtual CPU fault */ cpu_restore_state(tb, env, pc); } + 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); + printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", + env->eip, env->cr[2], env->error_code); #endif - /* we restore the process signal mask as the sigreturn should - do it (XXX: use sigsetjmp) */ - sigprocmask(SIG_SETMASK, old_set, NULL); - raise_exception_err(EXCP0E_PAGE, env->error_code); + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + raise_exception_err(EXCP0E_PAGE, env->error_code); + } else { + /* activate soft MMU for this block */ + env->soft_mmu = 1; + sigprocmask(SIG_SETMASK, old_set, NULL); + cpu_loop_exit(); + } /* never comes here */ return 1; } -- cgit v1.2.3 From 313aa567104a63fbe84d6ec2eeff5b5c81cb3524 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 21:52:11 +0000 Subject: added VGA emulation - added PS/2 mouse and keyboard emulation - use SDL for VGA display git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@356 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- vl.h | 45 ++++++ 2 files changed, 454 insertions(+), 120 deletions(-) diff --git a/vl.c b/vl.c index a7e117f3e..97c3be8da 100644 --- a/vl.c +++ b/vl.c @@ -74,6 +74,9 @@ /* debug PC keyboard */ //#define DEBUG_KBD +/* debug PC keyboard : only mouse */ +//#define DEBUG_MOUSE + #define PHYS_RAM_BASE 0xac000000 #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) @@ -81,6 +84,8 @@ #define INITRD_LOAD_ADDR 0x00400000 #define KERNEL_PARAMS_ADDR 0x00090000 +#define GUI_REFRESH_INTERVAL 30 + #define MAX_DISKS 2 /* from plex86 (BSD license) */ @@ -198,9 +203,6 @@ struct __attribute__ ((packed)) linux_params { #define KERNEL_CS 0x10 #define KERNEL_DS 0x18 -typedef void (IOPortWriteFunc)(CPUX86State *env, uint32_t address, uint32_t data); -typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address); - #define MAX_IOPORTS 4096 static const char *interp_prefix = CONFIG_QEMU_PREFIX; @@ -212,6 +214,11 @@ int loglevel; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS]; +int vga_ram_size; +static DisplayState display_state; +int nodisp; +int term_inited; +int64_t ticks_per_sec; /***********************************************************/ /* x86 io ports */ @@ -430,49 +437,6 @@ void hw_error(const char *fmt, ...) abort(); } -/***********************************************************/ -/* vga emulation */ -static uint8_t vga_index; -static uint8_t vga_regs[256]; -static int last_cursor_pos; - -void update_console_messages(void) -{ - int c, i, cursor_pos, eol; - - cursor_pos = vga_regs[0x0f] | (vga_regs[0x0e] << 8); - eol = 0; - for(i = last_cursor_pos; i < cursor_pos; i++) { - c = phys_ram_base[0xb8000 + (i) * 2]; - if (c >= ' ') { - putchar(c); - eol = 0; - } else { - if (!eol) - putchar('\n'); - eol = 1; - } - } - fflush(stdout); - last_cursor_pos = cursor_pos; -} - -/* just to see first Linux console messages, we intercept cursor position */ -void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) -{ - switch(addr) { - case 0x3d4: - vga_index = data; - break; - case 0x3d5: - vga_regs[vga_index] = data; - if (vga_index == 0x0f) - update_console_messages(); - break; - } - -} - /***********************************************************/ /* cmos emulation */ @@ -555,6 +519,7 @@ void cmos_init(void) /* various important CMOS locations needed by PC/Bochs bios */ cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ + cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ /* memory size */ val = (phys_ram_size / 1024) - 1024; @@ -674,13 +639,13 @@ static void pic_update_irq(void) int64_t irq_time[16]; int64_t cpu_get_ticks(void); #endif -#ifdef DEBUG_PIC +#if defined(DEBUG_PIC) int irq_level[16]; #endif void pic_set_irq(int irq, int level) { -#ifdef DEBUG_PIC +#if defined(DEBUG_PIC) if (level != irq_level[irq]) { printf("pic_set_irq: irq=%d level=%d\n", irq, level); irq_level[irq] = level; @@ -702,7 +667,9 @@ int cpu_x86_get_pic_interrupt(CPUX86State *env) /* signal the pic that the irq was acked by the CPU */ irq = pic_irq_requested; #ifdef DEBUG_IRQ_LATENCY - printf("IRQ%d latency=%Ld\n", irq, cpu_get_ticks() - irq_time[irq]); + printf("IRQ%d latency=%0.3fus\n", + irq, + (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); #endif #ifdef DEBUG_PIC printf("pic_interrupt: irq=%d\n", irq); @@ -761,18 +728,22 @@ void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } if (val == 0xa0) s->priority_add = (s->priority_add + 1) & 7; + pic_update_irq(); break; case 0x60 ... 0x67: priority = val & 7; s->isr &= ~(1 << priority); + pic_update_irq(); break; case 0xc0 ... 0xc7: s->priority_add = (val + 1) & 7; + pic_update_irq(); break; case 0xe0 ... 0xe7: priority = val & 7; s->isr &= ~(1 << priority); s->priority_add = (priority + 1) & 7; + pic_update_irq(); break; } } @@ -861,8 +832,6 @@ int speaker_data_on; int dummy_refresh_clock; int pit_min_timer_count = 0; -int64_t ticks_per_sec; - int64_t get_clock(void) { struct timeval tv; @@ -1354,37 +1323,6 @@ void serial_received_byte(SerialState *s, int ch) } } -/* init terminal so that we can grab keys */ -static struct termios oldtty; - -static void term_exit(void) -{ - tcsetattr (0, TCSANOW, &oldtty); -} - -static void term_init(void) -{ - struct termios tty; - - tcgetattr (0, &tty); - oldtty = tty; - - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; - - tcsetattr (0, TCSANOW, &tty); - - atexit(term_exit); - - fcntl(0, F_SETFL, O_NONBLOCK); -} - void serial_init(void) { SerialState *s = &serial_ports[0]; @@ -1393,8 +1331,6 @@ void serial_init(void) register_ioport_write(0x3f8, 8, serial_ioport_write, 1); register_ioport_read(0x3f8, 8, serial_ioport_read, 1); - - term_init(); } /***********************************************************/ @@ -2597,69 +2533,111 @@ void ide_init(void) #define KBD_MODE_RFU 0x80 /* Mouse Commands */ -#define AUX_SET_RES 0xE8 /* Set resolution */ #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_SET_RES 0xE8 /* Set resolution */ #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ #define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_POLL 0xEB /* Poll */ +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ +#define AUX_GET_TYPE 0xF2 /* Get type */ #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_SET_DEFAULT 0xF6 #define AUX_RESET 0xFF /* Reset aux device */ #define AUX_ACK 0xFA /* Command byte ACK. */ -#define KBD_QUEUE_SIZE 64 +#define MOUSE_STATUS_REMOTE 0x40 +#define MOUSE_STATUS_ENABLED 0x20 +#define MOUSE_STATUS_SCALE21 0x10 + +#define KBD_QUEUE_SIZE 256 typedef struct { uint8_t data[KBD_QUEUE_SIZE]; int rptr, wptr, count; } KBDQueue; -enum KBDWriteState { - KBD_STATE_CMD = 0, - KBD_STATE_LED, -}; - typedef struct KBDState { KBDQueue queues[2]; uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ uint8_t status; uint8_t mode; + /* keyboard state */ int kbd_write_cmd; int scan_enabled; + /* mouse state */ + int mouse_write_cmd; + uint8_t mouse_status; + uint8_t mouse_resolution; + uint8_t mouse_sample_rate; + uint8_t mouse_wrap; + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ + uint8_t mouse_detect_state; + int mouse_dx; /* current values, needed for 'poll' mode */ + int mouse_dy; + int mouse_dz; + uint8_t mouse_buttons; } KBDState; KBDState kbd_state; int reset_requested; int a20_enabled; +/* update irq and KBD_STAT_[MOUSE_]OBF */ static void kbd_update_irq(KBDState *s) { - int level; - - level = ((s->status & KBD_STAT_OBF) && (s->mode & KBD_MODE_KBD_INT)); - pic_set_irq(1, level); - - level = ((s->status & KBD_STAT_MOUSE_OBF) && (s->mode & KBD_MODE_MOUSE_INT)); - pic_set_irq(12, level); + int irq12_level, irq1_level; + + irq1_level = 0; + irq12_level = 0; + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); + if (s->queues[0].count != 0 || + s->queues[1].count != 0) { + s->status |= KBD_STAT_OBF; + if (s->queues[1].count != 0) { + s->status |= KBD_STAT_MOUSE_OBF; + if (s->mode & KBD_MODE_MOUSE_INT) + irq12_level = 1; + } else { + if (s->mode & KBD_MODE_KBD_INT) + irq1_level = 1; + } + } + pic_set_irq(1, irq1_level); + pic_set_irq(12, irq12_level); } static void kbd_queue(KBDState *s, int b, int aux) { KBDQueue *q = &kbd_state.queues[aux]; +#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) + if (aux) + printf("mouse event: 0x%02x\n", b); +#ifdef DEBUG_KBD + else + printf("kbd event: 0x%02x\n", b); +#endif +#endif if (q->count >= KBD_QUEUE_SIZE) return; q->data[q->wptr] = b; if (++q->wptr == KBD_QUEUE_SIZE) q->wptr = 0; q->count++; - s->status |= KBD_STAT_OBF; - if (aux) - s->status |= KBD_STAT_MOUSE_OBF; kbd_update_irq(s); } +void kbd_put_keycode(int keycode) +{ + KBDState *s = &kbd_state; + kbd_queue(s, keycode, 0); +} + uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) { KBDState *s = &kbd_state; @@ -2745,9 +2723,9 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) KBDQueue *q; int val; - q = &s->queues[1]; /* first check AUX data */ + q = &s->queues[0]; /* first check KBD data */ if (q->count == 0) - q = &s->queues[0]; /* then check KBD data */ + q = &s->queues[1]; /* then check AUX data */ if (q->count == 0) { /* XXX: return something else ? */ val = 0; @@ -2756,14 +2734,14 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) if (++q->rptr == KBD_QUEUE_SIZE) q->rptr = 0; q->count--; + /* reading deasserts IRQ */ + if (q == &s->queues[0]) + pic_set_irq(1, 0); + else + pic_set_irq(12, 0); } - if (s->queues[1].count == 0) { - s->status &= ~KBD_STAT_MOUSE_OBF; - if (s->queues[0].count == 0) - s->status &= ~KBD_STAT_OBF; - kbd_update_irq(s); - } - + /* reassert IRQs if data left */ + kbd_update_irq(s); #ifdef DEBUG_KBD printf("kbd: read data=0x%02x\n", val); #endif @@ -2820,12 +2798,212 @@ static void kbd_write_keyboard(KBDState *s, int val) break; case KBD_CMD_SET_LEDS: kbd_queue(s, KBD_REPLY_ACK, 0); + s->kbd_write_cmd = -1; break; case KBD_CMD_SET_RATE: kbd_queue(s, KBD_REPLY_ACK, 0); + s->kbd_write_cmd = -1; + break; + } +} + +static void kbd_mouse_send_packet(KBDState *s) +{ + unsigned int b; + int dx1, dy1, dz1; + + dx1 = s->mouse_dx; + dy1 = s->mouse_dy; + dz1 = s->mouse_dz; + /* XXX: increase range to 8 bits ? */ + if (dx1 > 127) + dx1 = 127; + else if (dx1 < -127) + dx1 = -127; + if (dy1 > 127) + dy1 = 127; + else if (dy1 < -127) + dy1 = -127; + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); + kbd_queue(s, b, 1); + kbd_queue(s, dx1 & 0xff, 1); + kbd_queue(s, dy1 & 0xff, 1); + /* extra byte for IMPS/2 or IMEX */ + switch(s->mouse_type) { + default: + break; + case 3: + if (dz1 > 127) + dz1 = 127; + else if (dz1 < -127) + dz1 = -127; + kbd_queue(s, dz1 & 0xff, 1); + break; + case 4: + if (dz1 > 7) + dz1 = 7; + else if (dz1 < -7) + dz1 = -7; + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); + kbd_queue(s, b, 1); + break; + } + + /* update deltas */ + s->mouse_dx -= dx1; + s->mouse_dy -= dy1; + s->mouse_dz -= dz1; +} + +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) +{ + KBDState *s = &kbd_state; + + /* check if deltas are recorded when disabled */ + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) + return; + + s->mouse_dx += dx; + s->mouse_dy -= dy; + s->mouse_dz += dz; + s->mouse_buttons = buttons_state; + + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && + (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { + for(;;) { + /* if not remote, send event. Multiple events are sent if + too big deltas */ + kbd_mouse_send_packet(s); + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) + break; + } + } +} + +static void kbd_write_mouse(KBDState *s, int val) +{ +#ifdef DEBUG_MOUSE + printf("kbd: write mouse 0x%02x\n", val); +#endif + switch(s->mouse_write_cmd) { + default: + case -1: + /* mouse command */ + if (s->mouse_wrap) { + if (val == AUX_RESET_WRAP) { + s->mouse_wrap = 0; + kbd_queue(s, AUX_ACK, 1); + return; + } else if (val != AUX_RESET) { + kbd_queue(s, val, 1); + return; + } + } + switch(val) { + case AUX_SET_SCALE11: + s->mouse_status &= ~MOUSE_STATUS_SCALE21; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_SCALE21: + s->mouse_status |= MOUSE_STATUS_SCALE21; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_STREAM: + s->mouse_status &= ~MOUSE_STATUS_REMOTE; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_WRAP: + s->mouse_wrap = 1; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_REMOTE: + s->mouse_status |= MOUSE_STATUS_REMOTE; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_GET_TYPE: + kbd_queue(s, AUX_ACK, 1); + kbd_queue(s, s->mouse_type, 1); + break; + case AUX_SET_RES: + case AUX_SET_SAMPLE: + s->mouse_write_cmd = val; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_GET_SCALE: + kbd_queue(s, AUX_ACK, 1); + kbd_queue(s, s->mouse_status, 1); + kbd_queue(s, s->mouse_resolution, 1); + kbd_queue(s, s->mouse_sample_rate, 1); + break; + case AUX_POLL: + kbd_queue(s, AUX_ACK, 1); + kbd_mouse_send_packet(s); + break; + case AUX_ENABLE_DEV: + s->mouse_status |= MOUSE_STATUS_ENABLED; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_DISABLE_DEV: + s->mouse_status &= ~MOUSE_STATUS_ENABLED; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_DEFAULT: + s->mouse_sample_rate = 100; + s->mouse_resolution = 2; + s->mouse_status = 0; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_RESET: + s->mouse_sample_rate = 100; + s->mouse_resolution = 2; + s->mouse_status = 0; + kbd_queue(s, AUX_ACK, 1); + kbd_queue(s, 0xaa, 1); + kbd_queue(s, s->mouse_type, 1); + break; + default: + break; + } + break; + case AUX_SET_SAMPLE: + s->mouse_sample_rate = val; +#if 0 + /* detect IMPS/2 or IMEX */ + switch(s->mouse_detect_state) { + default: + case 0: + if (val == 200) + s->mouse_detect_state = 1; + break; + case 1: + if (val == 100) + s->mouse_detect_state = 2; + else if (val == 200) + s->mouse_detect_state = 3; + else + s->mouse_detect_state = 0; + break; + case 2: + if (val == 80) + s->mouse_type = 3; /* IMPS/2 */ + s->mouse_detect_state = 0; + break; + case 3: + if (val == 80) + s->mouse_type = 4; /* IMEX */ + s->mouse_detect_state = 0; + break; + } +#endif + kbd_queue(s, AUX_ACK, 1); + s->mouse_write_cmd = -1; + break; + case AUX_SET_RES: + s->mouse_resolution = val; + kbd_queue(s, AUX_ACK, 1); + s->mouse_write_cmd = -1; break; } - s->kbd_write_cmd = -1; } void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) @@ -2857,6 +3035,9 @@ void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); } break; + case KBD_CCMD_WRITE_MOUSE: + kbd_write_mouse(s, val); + break; default: break; } @@ -2869,8 +3050,9 @@ void kbd_reset(KBDState *s) int i; s->kbd_write_cmd = -1; + s->mouse_write_cmd = -1; s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; - s->status = KBD_MODE_SYS | KBD_MODE_NO_KEYLOCK; + s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; for(i = 0; i < 2; i++) { q = &s->queues[i]; q->rptr = 0; @@ -2933,6 +3115,63 @@ void bochs_bios_init(void) register_ioport_write(0x503, 1, bochs_bios_write, 1); } +/***********************************************************/ +/* dumb display */ + +/* init terminal so that we can grab keys */ +static struct termios oldtty; + +static void term_exit(void) +{ + tcsetattr (0, TCSANOW, &oldtty); +} + +static void term_init(void) +{ + struct termios tty; + + tcgetattr (0, &tty); + oldtty = tty; + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + tcsetattr (0, TCSANOW, &tty); + + atexit(term_exit); + + fcntl(0, F_SETFL, O_NONBLOCK); +} + +static void dumb_update(DisplayState *ds, int x, int y, int w, int h) +{ +} + +static void dumb_resize(DisplayState *ds, int w, int h) +{ +} + +static void dumb_refresh(DisplayState *ds) +{ + vga_update_display(); +} + +void dumb_display_init(DisplayState *ds) +{ + ds->data = NULL; + ds->linesize = 0; + ds->depth = 0; + ds->dpy_update = dumb_update; + ds->dpy_resize = dumb_resize; + ds->dpy_refresh = dumb_refresh; +} + /***********************************************************/ /* cpu signal handler */ static void host_segv_handler(int host_signum, siginfo_t *info, @@ -2947,6 +3186,9 @@ static void host_segv_handler(int host_signum, siginfo_t *info, static int timer_irq_pending; static int timer_irq_count; +static int timer_ms; +static int gui_refresh_pending, gui_refresh_count; + static void host_alarm_handler(int host_signum, siginfo_t *info, void *puc) { @@ -2958,9 +3200,17 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, if (timer_irq_count > 2) timer_irq_count = 2; timer_irq_count--; + timer_irq_pending = 1; + } + gui_refresh_count += timer_ms; + if (gui_refresh_count >= GUI_REFRESH_INTERVAL) { + gui_refresh_count = 0; + gui_refresh_pending = 1; + } + + if (gui_refresh_pending || timer_irq_pending) { /* just exit from the cpu to have a chance to handle timers */ cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); - timer_irq_pending = 1; } } @@ -2988,6 +3238,14 @@ int main_loop(void *opaque) uint8_t ch; CPUState *env = global_env; + if (nodisp && !term_inited) { + /* initialize terminal only there so that the user has a + chance to stop QEMU with Ctrl-C before the gdb connection + is launched */ + term_inited = 1; + term_init(); + } + for(;;) { ret = cpu_x86_exec(env); @@ -3059,6 +3317,12 @@ int main_loop(void *opaque) pic_set_irq(0, 0); timer_irq_pending = 0; } + + /* VGA */ + if (gui_refresh_pending) { + display_state.dpy_refresh(&display_state); + gui_refresh_pending = 0; + } } return EXCP_INTERRUPT; } @@ -3098,31 +3362,35 @@ struct option long_options[] = { { "hdb", 1, NULL, 0, }, { "snapshot", 0, NULL, 0, }, { "hdachs", 1, NULL, 0, }, + { "nodisp", 0, NULL, 0, }, { NULL, 0, NULL, 0 }, }; int main(int argc, char **argv) { int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; - int snapshot, linux_boot; + int snapshot, linux_boot, total_ram_size; struct linux_params *params; struct sigaction act; struct itimerval itv; CPUX86State *env; const char *tmpdir, *initrd_filename; const char *hd_filename[MAX_DISKS]; - + DisplayState *ds = &display_state; + /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); initrd_filename = NULL; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; phys_ram_size = 32 * 1024 * 1024; + vga_ram_size = VGA_RAM_SIZE; pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; snapshot = 0; linux_boot = 0; + nodisp = 0; for(;;) { c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index); if (c == -1) @@ -3164,6 +3432,9 @@ int main(int argc, char **argv) chs_fail: ; } break; + case 5: + nodisp = 1; + break; } break; case 'h': @@ -3232,9 +3503,11 @@ int main(int argc, char **argv) phys_ram_file); exit(1); } - ftruncate(phys_ram_fd, phys_ram_size); + total_ram_size = phys_ram_size + vga_ram_size; + ftruncate(phys_ram_fd, total_ram_size); unlink(phys_ram_file); - phys_ram_base = mmap(get_mmap_addr(phys_ram_size), phys_ram_size, + phys_ram_base = mmap(get_mmap_addr(total_ram_size), + total_ram_size, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, phys_ram_fd, 0); if (phys_ram_base == MAP_FAILED) { @@ -3261,6 +3534,9 @@ int main(int argc, char **argv) init_ioports(); + /* allocate RAM */ + cpu_register_physical_memory(0, phys_ram_size, 0); + if (linux_boot) { /* now we can load the kernel */ ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); @@ -3366,11 +3642,23 @@ int main(int argc, char **argv) bochs_bios_init(); } + /* terminal init */ + if (nodisp) { + dumb_display_init(ds); + } else { +#ifdef CONFIG_SDL + sdl_display_init(ds); + /* the pthreads modify sigaction. We don't want that. */ +#define sigaction __sigaction +#else + dumb_display_init(ds); +#endif + } /* init basic PC hardware */ register_ioport_write(0x80, 1, ioport80_write, 1); - register_ioport_write(0x3d4, 2, vga_ioport_write, 1); - + vga_init(ds, phys_ram_base + phys_ram_size, phys_ram_size, + vga_ram_size); cmos_init(); pic_init(); pit_init(); @@ -3378,7 +3666,7 @@ int main(int argc, char **argv) ne2000_init(); ide_init(); kbd_init(); - + /* setup cpu signal handlers for MMU / self modifying code handling */ sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; @@ -3397,6 +3685,7 @@ int main(int argc, char **argv) /* we probe the tick duration of the kernel to inform the user if the emulated kernel requested a too high timer frequency */ getitimer(ITIMER_REAL, &itv); + timer_ms = itv.it_interval.tv_usec / 1000; pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / 1000000; diff --git a/vl.h b/vl.h index fa7d5da27..669bd227e 100644 --- a/vl.h +++ b/vl.h @@ -25,7 +25,22 @@ #define VL_H /* vl.c */ +struct CPUX86State; +extern int reset_requested; + +typedef void (IOPortWriteFunc)(struct CPUX86State *env, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(struct CPUX86State *env, uint32_t address); + void *get_mmap_addr(unsigned long size); +int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); +int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); + +void kbd_put_keycode(int keycode); + +#define MOUSE_EVENT_LBUTTON 0x01 +#define MOUSE_EVENT_RBUTTON 0x02 +#define MOUSE_EVENT_MBUTTON 0x04 +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); /* block.c */ typedef struct BlockDriverState BlockDriverState; @@ -52,4 +67,34 @@ struct cow_header_v2 { uint32_t sectorsize; }; +/* vga.c */ + +#define VGA_RAM_SIZE (8192 * 1024) + +typedef struct DisplayState { + uint8_t *data; + int linesize; + int depth; + void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); + void (*dpy_resize)(struct DisplayState *s, int w, int h); + void (*dpy_refresh)(struct DisplayState *s); +} DisplayState; + +static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) +{ + s->dpy_update(s, x, y, w, h); +} + +static inline void dpy_resize(DisplayState *s, int w, int h) +{ + s->dpy_resize(s, w, h); +} + +int vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); +void vga_update_display(void); + +/* sdl.c */ +void sdl_display_init(DisplayState *ds); + #endif /* VL_H */ -- cgit v1.2.3 From 38e584a07279fffcfbfcafb207ce842edd093033 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 22:14:22 +0000 Subject: m68k host port (Richard Zidlicky) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@357 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 ++ configure | 8 ++- cpu-exec.c | 17 ++++++ dyngen-exec.h | 11 +++- dyngen.c | 57 ++++++++++++++++++ dyngen.h | 8 +++ exec.h | 12 ++++ m68k.ld | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 m68k.ld diff --git a/Makefile.target b/Makefile.target index db72eeb08..27c79e8ca 100644 --- a/Makefile.target +++ b/Makefile.target @@ -79,6 +79,11 @@ OP_CFLAGS=$(CFLAGS) -mno-sched-prolog LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld endif +ifeq ($(ARCH),m68k) +OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer +LDFLAGS+=-Wl,-T,m68k.ld +endif + ifeq ($(HAVE_GCC3_OPTIONS),yes) # very important to generate a return at the end of every operation OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls diff --git a/configure b/configure index 2b830710a..51f8bcc74 100755 --- a/configure +++ b/configure @@ -56,6 +56,9 @@ case "$cpu" in ia64) cpu="ia64" ;; + m68k) + cpu="m68k" + ;; *) cpu="unknown" ;; @@ -163,7 +166,7 @@ fi else # if cross compiling, cannot launch a program, so make a static guess -if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64"; then +if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then bigendian="yes" fi @@ -265,6 +268,9 @@ elif test "$cpu" = "sparc64" ; then 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" >> $TMPH else echo "Unsupported CPU" exit 1 diff --git a/cpu-exec.c b/cpu-exec.c index ecab6ff11..fe165dffd 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -642,6 +642,23 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, &uc->uc_sigmask); } +#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); +} + #else #error host CPU specific signal handler needed diff --git a/dyngen-exec.h b/dyngen-exec.h index 46f4042f6..980e70ca9 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -109,6 +109,13 @@ extern int printf(const char *, ...); #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 "r27" #define AREG1 "r24" @@ -178,4 +185,6 @@ extern int __op_jmp0, __op_jmp1; #ifdef __arm__ #define EXIT_TB() asm volatile ("b exec_loop") #endif - +#ifdef __mc68000 +#define EXIT_TB() asm volatile ("rts") +#endif diff --git a/dyngen.c b/dyngen.c index df88dc2cc..58d22d975 100644 --- a/dyngen.c +++ b/dyngen.c @@ -86,6 +86,13 @@ #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 @@ -575,6 +582,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, relocs, nb_relocs); break; #endif + case EM_68K: + { + 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; + } + break; default: error("unknown ELF architecture"); } @@ -1062,6 +1084,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#elif defined(HOST_M68K) + { + char name[256]; + int type; + int addend; + 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; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend; + 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", + rel->r_offset - start_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", + rel->r_offset - start_offset, name, rel->r_offset - start_offset, /*sym->st_value+*/ addend); + break; + default: + error("unsupported m68k relocation (%d)", type); + } + } + } + } #else #error unsupported CPU #endif diff --git a/dyngen.h b/dyngen.h index 47fe263e4..cc38228b7 100644 --- a/dyngen.h +++ b/dyngen.h @@ -94,6 +94,14 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) } #endif +#ifdef __mc68000 +#include +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"); diff --git a/exec.h b/exec.h index 5c4e841a7..54571a232 100644 --- a/exec.h +++ b/exec.h @@ -348,6 +348,18 @@ static inline int testandset (int *spinlock) } #endif +#ifdef __mc68000 +static inline int testandset (int *p) +{ + char ret; + __asm__ __volatile__("tas %1; sne %0" + : "=r" (ret) + : "m" (p) + : "cc","memory"); + return ret == 0; +} +#endif + typedef int spinlock_t; #define SPIN_LOCK_UNLOCKED 0 diff --git a/m68k.ld b/m68k.ld new file mode 100644 index 000000000..28da902fd --- /dev/null +++ b/m68k.ld @@ -0,0 +1,177 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", + "elf32-m68k") +OUTPUT_ARCH(m68k) +ENTRY(_start) +SEARCH_DIR("/usr/local/m68k-linux/lib"); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x4e754e75 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x4e754e75 + .fini : + { + KEEP (*(.fini)) + } =0x4e754e75 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x2000) + (. & (0x2000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} -- cgit v1.2.3 From 9368caf64db1c3c115c20a3d7253efb35d128d4e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 22:15:31 +0000 Subject: updated git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@358 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Changelog b/Changelog index 78c72a319..1830de559 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,16 @@ +version 0.4.4: + + - 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 vl + - m68k host port (Richard Zidlicky) + - partial soft MMU support for memory mapped I/Os + - multi-target build + version 0.4.3: - x86 exception fix in case of nop instruction. -- cgit v1.2.3 From 31e8f3c894002313b8817f661f5682223aa38103 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 22:52:34 +0000 Subject: PowerPC fix (Jon Nall) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@359 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.h | 1 + 1 file changed, 1 insertion(+) diff --git a/exec.h b/exec.h index 54571a232..5341496b7 100644 --- a/exec.h +++ b/exec.h @@ -226,6 +226,7 @@ do {\ label ## n:\ T0 = (long)(tbparam) + (n);\ EIP = eip;\ + EXIT_TB();\ } while (0) #else -- cgit v1.2.3 From e2222c39248e7a54ffdb8325ba7edf2e23171306 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 23:39:03 +0000 Subject: removed warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@360 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.h | 6 ++++++ softmmu_header.h | 4 ++-- softmmu_template.h | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/exec.h b/exec.h index 5341496b7..29779f99d 100644 --- a/exec.h +++ b/exec.h @@ -32,6 +32,12 @@ #define __builtin_expect(x, n) (x) #endif +#ifdef __i386__ +#define REGPARM(n) __attribute((regparm(n))) +#else +#define REGPARM(n) +#endif + /* is_jmp field values */ #define DISAS_NEXT 0 /* next instruction can be analyzed */ #define DISAS_JUMP 1 /* only pc was modified dynamically */ diff --git a/softmmu_header.h b/softmmu_header.h index 12306a666..36cf9f0a1 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -49,8 +49,8 @@ #if MEMUSER == 0 -DATA_TYPE __attribute((regparm(1))) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr); -void __attribute((regparm(2))) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE v); +DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr); +void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE v); #endif static inline int glue(glue(ldu, SUFFIX), MEMSUFFIX)(void *ptr) diff --git a/softmmu_template.h b/softmmu_template.h index 871cf5491..c36e25ae2 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -81,7 +81,7 @@ static inline void glue(io_write, SUFFIX)(unsigned long physaddr, } /* handle all cases except unaligned access which span two pages */ -DATA_TYPE __attribute((regparm(1))) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr) +DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr) { DATA_TYPE res; int is_user, index; @@ -163,7 +163,7 @@ static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr) } -void __attribute((regparm(2))) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val) +void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val) { unsigned long physaddr, tlb_addr; void *retaddr; -- cgit v1.2.3 From 96e6e05372837a00d26284a8ba25ecb533a2e410 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 23:39:55 +0000 Subject: fixed invalid code gen git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@361 c046a42c-6fe2-441c-8c8c-71466251a162 --- ops_template.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ops_template.h b/ops_template.h index 89480dddb..1c6513152 100644 --- a/ops_template.h +++ b/ops_template.h @@ -556,12 +556,14 @@ void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST == 0) JUMP_TB(PARAM1, 1, PARAM2); + FORCE_RET(); } void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST != 0) JUMP_TB(PARAM1, 1, PARAM2); + FORCE_RET(); } #if DATA_BITS >= 16 @@ -569,6 +571,7 @@ void OPPROTO glue(op_jz_ecx, SUFFIX)(void) { if ((DATA_TYPE)ECX == 0) JUMP_TB(PARAM1, 1, PARAM2); + FORCE_RET(); } #endif -- cgit v1.2.3 From 3b22c4707decb706b10ce023534f8b79413ff9fe Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 23:40:50 +0000 Subject: fixed invalid ESP usage (Jon Nall) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@362 c046a42c-6fe2-441c-8c8c-71466251a162 --- helper-i386.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/helper-i386.c b/helper-i386.c index 01046ea09..fba6b5b25 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -285,13 +285,13 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, /* XXX: check that enough room is available */ if (new_stack) { - old_esp = env->regs[R_ESP]; + old_esp = ESP; old_ss = env->segs[R_SS].selector; load_seg(R_SS, ss, env->eip); } else { old_esp = 0; old_ss = 0; - esp = env->regs[R_ESP]; + esp = ESP; } if (is_int) old_eip = next_eip; @@ -300,7 +300,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, old_cs = env->segs[R_CS].selector; load_seg(R_CS, selector, env->eip); env->eip = offset; - env->regs[R_ESP] = esp - push_size; + ESP = esp - push_size; ssp = env->segs[R_SS].base + esp; if (shift == 1) { int old_eflags; @@ -374,7 +374,7 @@ static void do_interrupt_real(int intno, int is_int, int error_code, ptr = dt->base + intno * 4; offset = lduw(ptr); selector = lduw(ptr + 2); - esp = env->regs[R_ESP]; + esp = ESP; ssp = env->segs[R_SS].base; if (is_int) old_eip = next_eip; @@ -389,7 +389,7 @@ static void do_interrupt_real(int intno, int is_int, int error_code, stw(ssp + (esp & 0xffff), old_eip); /* update processor state */ - env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); + ESP = (ESP & ~0xffff) | (esp & 0xffff); env->eip = offset; env->segs[R_CS].selector = selector; env->segs[R_CS].base = (uint8_t *)(selector << 4); @@ -784,7 +784,7 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) new_cs = T0; new_eip = T1; - esp = env->regs[R_ESP]; + esp = ESP; esp_mask = 0xffffffff; if (!(env->segs[R_SS].flags & DESC_B_MASK)) esp_mask = 0xffff; @@ -802,9 +802,9 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) } if (!(env->segs[R_SS].flags & DESC_B_MASK)) - env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); + ESP = (ESP & ~0xffff) | (esp & 0xffff); else - env->regs[R_ESP] = esp; + ESP = esp; env->eip = new_eip; env->segs[R_CS].selector = new_cs; env->segs[R_CS].base = (uint8_t *)(new_cs << 4); @@ -846,7 +846,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - sp = env->regs[R_ESP]; + sp = ESP; if (!(env->segs[R_SS].flags & DESC_B_MASK)) sp &= 0xffff; ssp = env->segs[R_SS].base + sp; @@ -868,9 +868,9 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); /* from this point, not restartable */ if (!(env->segs[R_SS].flags & DESC_B_MASK)) - env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | (sp & 0xffff); + ESP = (ESP & 0xffff0000) | (sp & 0xffff); else - env->regs[R_ESP] = sp; + ESP = sp; env->segs[R_CS].base = sc1.base; env->segs[R_CS].limit = sc1.limit; env->segs[R_CS].flags = sc1.flags; @@ -938,7 +938,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) param_count = e2 & 0x1f; push_size = ((param_count * 2) + 8) << shift; - old_esp = env->regs[R_ESP]; + old_esp = ESP; old_ss = env->segs[R_SS].selector; if (!(env->segs[R_SS].flags & DESC_B_MASK)) old_esp &= 0xffff; @@ -995,9 +995,9 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) load_seg(R_CS, selector, env->eip); /* from this point, not restartable if same priviledge */ if (!(env->segs[R_SS].flags & DESC_B_MASK)) - env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | (sp & 0xffff); + ESP = (ESP & 0xffff0000) | (sp & 0xffff); else - env->regs[R_ESP] = sp; + ESP = sp; EIP = offset; } } @@ -1020,7 +1020,7 @@ void helper_iret_real(int shift) uint8_t *ssp; int eflags_mask; - sp = env->regs[R_ESP] & 0xffff; + sp = ESP & 0xffff; ssp = env->segs[R_SS].base + sp; if (shift == 1) { /* 32 bits */ @@ -1034,7 +1034,7 @@ void helper_iret_real(int shift) new_eip = lduw(ssp); } new_esp = sp + (6 << shift); - env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | + ESP = (ESP & 0xffff0000) | (new_esp & 0xffff); load_seg_vm(R_CS, new_cs); env->eip = new_eip; @@ -1053,7 +1053,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) int cpl, dpl, rpl, eflags_mask; uint8_t *ssp; - sp = env->regs[R_ESP]; + sp = ESP; if (!(env->segs[R_SS].flags & DESC_B_MASK)) sp &= 0xffff; ssp = env->segs[R_SS].base + sp; @@ -1129,9 +1129,9 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) load_seg(R_SS, new_ss, env->eip); } if (env->segs[R_SS].flags & DESC_B_MASK) - env->regs[R_ESP] = new_esp; + ESP = new_esp; else - env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | + ESP = (ESP & 0xffff0000) | (new_esp & 0xffff); env->eip = new_eip; if (is_iret) { @@ -1164,7 +1164,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) load_seg_vm(R_GS, new_gs); env->eip = new_eip; - env->regs[R_ESP] = new_esp; + ESP = new_esp; } void helper_iret_protected(int shift) -- cgit v1.2.3 From 76bc68382096b941d58a018166d5604f44915b1b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Aug 2003 23:41:46 +0000 Subject: updated git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@363 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 6174c9735..52d6383c8 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,10 @@ clean: done distclean: clean - rm -f config.mak config.h + rm -f config-host.mak config-host.h config.mak config.h + for d in $(TARGET_DIRS); do \ + rm -f $$d/config.h $$d/config.mak || exit 1 ; \ + done install: all mkdir -p $(prefix)/bin @@ -49,16 +52,17 @@ qemu-doc.html: qemu-doc.texi FILES= \ README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ -configure \ +configure Makefile Makefile.target \ dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \ -Makefile elf.h elfload.c main.c signal.c qemu.h \ +elf.h elfload.c main.c signal.c qemu.h \ syscall.c syscall_defs.h vm86.c path.c mmap.c \ -i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\ -vl.c i386-vl.ld vl.h block.c vlmkcow.c\ -thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\ -exec.c cpu-exec.c gdbstub.c\ -cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \ +i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld m68k.ld \ +vl.c i386-vl.ld vl.h block.c vlmkcow.c vga.c vga_template.h sdl.c \ +thunk.c cpu-exec.c translate.c cpu-all.h cpu-defs.h thunk.h exec.h\ +exec.c cpu-exec.c gdbstub.c bswap.h \ +cpu-i386.h op-i386.c helper-i386.c helper2-i386.c syscall-i386.h translate-i386.c \ exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \ +ops_mem.h softmmu_template.h softmmu_header.h \ cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \ dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \ arm-dis.c \ -- cgit v1.2.3 From 9da8ba18e60273b9925991712883e54c16d4b626 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 11 Aug 2003 20:33:04 +0000 Subject: mode X double scan fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@364 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 0ed8abf24..9ab9a163c 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1124,7 +1124,10 @@ static void vga_draw_graphic(VGAState *s, int full_update) disp_width = width; shift_control = (s->gr[0x05] >> 5) & 3; - double_scan = (s->cr[0x09] & 0x80); + if (shift_control > 1) + double_scan = ((s->cr[0x09] & 0x1f) != 0); + else + double_scan = (s->cr[0x09] & 0x80); if (shift_control != s->shift_control || double_scan != s->double_scan) { full_update = 1; @@ -1151,7 +1154,6 @@ static void vga_draw_graphic(VGAState *s, int full_update) } else { full_update |= update_palette256(s); v = VGA_DRAW_LINE8D2; - double_scan = 1; /* XXX: explain me why it is always activated */ } vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; -- cgit v1.2.3 From 9dfa5b421dcb7f213163d2bd80549d6ca4bc74a6 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 11 Aug 2003 20:35:58 +0000 Subject: 64 bit fixes (Falk Hueffner) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@365 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 2 +- vl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 46abf53d8..0d2e30187 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -152,7 +152,7 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) ((unsigned long *)d)[i] = tswapl(s->sig[i]); } #elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 - ((unsigned long *)d)[0] = sigmask | (tswapl(s->sig[1]) << 32); + ((unsigned long *)d)[0] = sigmask | ((unsigned long)tswapl(s->sig[1]) << 32); #else #error target_to_host_sigset #endif /* TARGET_LONG_BITS */ diff --git a/vl.h b/vl.h index 669bd227e..531eabe02 100644 --- a/vl.h +++ b/vl.h @@ -60,7 +60,7 @@ int bdrv_commit(BlockDriverState *bs); struct cow_header_v2 { uint32_t magic; - uint32_t long version; + uint32_t version; char backing_file[1024]; int32_t mtime; uint64_t size; -- cgit v1.2.3 From 2573109866ead12fd0fa7442b33c8bf4aa125456 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 11 Aug 2003 22:19:11 +0000 Subject: pass function name to JMUP_TB() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@366 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-arm.c | 30 +++++++++++++++--------------- op-i386.c | 6 +++--- ops_template.h | 30 +++++++++++++++--------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/op-arm.c b/op-arm.c index fcc4ddc3d..98ef9a0c9 100644 --- a/op-arm.c +++ b/op-arm.c @@ -238,104 +238,104 @@ void OPPROTO op_logic_T1_cc(void) void OPPROTO op_test_eq(void) { if (env->NZF == 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_ne(void) { if (env->NZF != 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_cs(void) { if (env->CF != 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_cc(void) { if (env->CF == 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_mi(void) { if ((env->NZF & 0x80000000) != 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_pl(void) { if ((env->NZF & 0x80000000) == 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_vs(void) { if ((env->VF & 0x80000000) != 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_vc(void) { if ((env->VF & 0x80000000) == 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_hi(void) { if (env->CF != 0 && env->NZF != 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_ls(void) { if (env->CF == 0 || env->NZF == 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_ge(void) { if (((env->VF ^ env->NZF) & 0x80000000) == 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_lt(void) { if (((env->VF ^ env->NZF) & 0x80000000) != 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_gt(void) { if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_gt, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_test_le(void) { if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_test_le, PARAM1, 0, PARAM2); FORCE_RET(); } void OPPROTO op_jmp(void) { - JUMP_TB(PARAM1, 1, PARAM2); + JUMP_TB(op_jmp, PARAM1, 1, PARAM2); } void OPPROTO op_exit_tb(void) diff --git a/op-i386.c b/op-i386.c index 60ae5e55f..833b1f9d3 100644 --- a/op-i386.c +++ b/op-i386.c @@ -508,7 +508,7 @@ void OPPROTO op_cmpxchg8b(void) void OPPROTO op_jmp_tb_next(void) { - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_jmp_tb_next, PARAM1, 0, PARAM2); } void OPPROTO op_movl_T0_0(void) @@ -1016,9 +1016,9 @@ void OPPROTO op_clts(void) void OPPROTO op_jcc(void) { if (T0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(op_jcc, PARAM1, 0, PARAM2); else - JUMP_TB(PARAM1, 1, PARAM3); + JUMP_TB(op_jcc, PARAM1, 1, PARAM3); FORCE_RET(); } diff --git a/ops_template.h b/ops_template.h index 1c6513152..b55ccf9db 100644 --- a/ops_template.h +++ b/ops_template.h @@ -238,18 +238,18 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void) src2 = CC_SRC; if ((DATA_TYPE)src1 < (DATA_TYPE)src2) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 0, PARAM2); else - JUMP_TB(PARAM1, 1, PARAM3); + JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 1, PARAM3); FORCE_RET(); } void OPPROTO glue(op_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST == 0) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 0, PARAM2); else - JUMP_TB(PARAM1, 1, PARAM3); + JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 1, PARAM3); FORCE_RET(); } @@ -260,18 +260,18 @@ void OPPROTO glue(op_jbe_sub, SUFFIX)(void) src2 = CC_SRC; if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 0, PARAM2); else - JUMP_TB(PARAM1, 1, PARAM3); + JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 1, PARAM3); FORCE_RET(); } void OPPROTO glue(op_js_sub, SUFFIX)(void) { if (CC_DST & SIGN_MASK) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 0, PARAM2); else - JUMP_TB(PARAM1, 1, PARAM3); + JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 1, PARAM3); FORCE_RET(); } @@ -282,9 +282,9 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void) src2 = CC_SRC; if ((DATA_STYPE)src1 < (DATA_STYPE)src2) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 0, PARAM2); else - JUMP_TB(PARAM1, 1, PARAM3); + JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 1, PARAM3); FORCE_RET(); } @@ -295,9 +295,9 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) src2 = CC_SRC; if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) - JUMP_TB(PARAM1, 0, PARAM2); + JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 0, PARAM2); else - JUMP_TB(PARAM1, 1, PARAM3); + JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 1, PARAM3); FORCE_RET(); } @@ -555,14 +555,14 @@ void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST == 0) - JUMP_TB(PARAM1, 1, PARAM2); + JUMP_TB(glue(op_string_jz_sub, SUFFIX), PARAM1, 1, PARAM2); FORCE_RET(); } void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST != 0) - JUMP_TB(PARAM1, 1, PARAM2); + JUMP_TB(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1, PARAM2); FORCE_RET(); } @@ -570,7 +570,7 @@ void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) void OPPROTO glue(op_jz_ecx, SUFFIX)(void) { if ((DATA_TYPE)ECX == 0) - JUMP_TB(PARAM1, 1, PARAM2); + JUMP_TB(glue(op_jz_ecx, SUFFIX), PARAM1, 1, PARAM2); FORCE_RET(); } #endif -- cgit v1.2.3 From 70a194b930797263bd6cb962d7f09596a07b4fef Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 11 Aug 2003 22:20:16 +0000 Subject: fixed invalid Linux asm/unistd.h header for PowerPC and gcc 3.3 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@367 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1204a62c4..753a47cd2 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -68,6 +68,129 @@ #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) + +#if defined(__powerpc__) +#undef __syscall_nr +#undef __sc_loadargs_0 +#undef __sc_loadargs_1 +#undef __sc_loadargs_2 +#undef __sc_loadargs_3 +#undef __sc_loadargs_4 +#undef __sc_loadargs_5 +#undef __sc_asm_input_0 +#undef __sc_asm_input_1 +#undef __sc_asm_input_2 +#undef __sc_asm_input_3 +#undef __sc_asm_input_4 +#undef __sc_asm_input_5 +#undef _syscall0 +#undef _syscall1 +#undef _syscall2 +#undef _syscall3 +#undef _syscall4 +#undef _syscall5 + +/* need to redefine syscalls as Linux kernel defines are incorrect for + the clobber list */ +/* On powerpc a system call basically clobbers the same registers like a + * function call, with the exception of LR (which is needed for the + * "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal + * an error return status). + */ + +#define __syscall_nr(nr, type, name, args...) \ + unsigned long __sc_ret, __sc_err; \ + { \ + register unsigned long __sc_0 __asm__ ("r0"); \ + register unsigned long __sc_3 __asm__ ("r3"); \ + register unsigned long __sc_4 __asm__ ("r4"); \ + register unsigned long __sc_5 __asm__ ("r5"); \ + register unsigned long __sc_6 __asm__ ("r6"); \ + register unsigned long __sc_7 __asm__ ("r7"); \ + \ + __sc_loadargs_##nr(name, args); \ + __asm__ __volatile__ \ + ("sc \n\t" \ + "mfcr %0 " \ + : "=&r" (__sc_0), \ + "=&r" (__sc_3), "=&r" (__sc_4), \ + "=&r" (__sc_5), "=&r" (__sc_6), \ + "=&r" (__sc_7) \ + : __sc_asm_input_##nr \ + : "cr0", "ctr", "memory", \ + "r8", "r9", "r10","r11", "r12"); \ + __sc_ret = __sc_3; \ + __sc_err = __sc_0; \ + } \ + if (__sc_err & 0x10000000) \ + { \ + errno = __sc_ret; \ + __sc_ret = -1; \ + } \ + return (type) __sc_ret + +#define __sc_loadargs_0(name, dummy...) \ + __sc_0 = __NR_##name +#define __sc_loadargs_1(name, arg1) \ + __sc_loadargs_0(name); \ + __sc_3 = (unsigned long) (arg1) +#define __sc_loadargs_2(name, arg1, arg2) \ + __sc_loadargs_1(name, arg1); \ + __sc_4 = (unsigned long) (arg2) +#define __sc_loadargs_3(name, arg1, arg2, arg3) \ + __sc_loadargs_2(name, arg1, arg2); \ + __sc_5 = (unsigned long) (arg3) +#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4) \ + __sc_loadargs_3(name, arg1, arg2, arg3); \ + __sc_6 = (unsigned long) (arg4) +#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5) \ + __sc_loadargs_4(name, arg1, arg2, arg3, arg4); \ + __sc_7 = (unsigned long) (arg5) + +#define __sc_asm_input_0 "0" (__sc_0) +#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3) +#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4) +#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5) +#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6) +#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7) + +#define _syscall0(type,name) \ +type name(void) \ +{ \ + __syscall_nr(0, type, name); \ +} + +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ + __syscall_nr(1, type, name, arg1); \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1, type2 arg2) \ +{ \ + __syscall_nr(2, type, name, arg1, arg2); \ +} + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1, type2 arg2, type3 arg3) \ +{ \ + __syscall_nr(3, type, name, arg1, arg2, arg3); \ +} + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ + __syscall_nr(4, type, name, arg1, arg2, arg3, arg4); \ +} + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ +{ \ + __syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5); \ +} +#endif + #define __NR_sys_uname __NR_uname #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_statfs __NR_statfs -- cgit v1.2.3 From 9257a9e49c324145d4a34d6a3a5ecffa16ddc063 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 11 Aug 2003 22:21:18 +0000 Subject: workaround for gcc 3.3 bug or overoptimisation if a label is not used git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@368 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/exec.h b/exec.h index 29779f99d..026daaabe 100644 --- a/exec.h +++ b/exec.h @@ -225,11 +225,14 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); #if defined(__powerpc__) /* on PowerPC we patch the jump instruction directly */ -#define JUMP_TB(tbparam, n, eip)\ +#define JUMP_TB(opname, tbparam, n, eip)\ do {\ - static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ - asm volatile ("b %0" : : "i" (&__op_jmp ## n));\ -label ## n:\ + asm volatile (".section \".data\"\n"\ + "__op_label" #n "." stringify(opname) ":\n"\ + ".long 1f\n"\ + ".previous\n"\ + "b __op_jmp" #n "\n"\ + "1:\n");\ T0 = (long)(tbparam) + (n);\ EIP = eip;\ EXIT_TB();\ @@ -239,7 +242,7 @@ label ## n:\ /* jump to next block operations (more portable code, does not need cache flushing, but slower because of indirect jump) */ -#define JUMP_TB(tbparam, n, eip)\ +#define JUMP_TB(opname, tbparam, n, eip)\ do {\ static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\ -- cgit v1.2.3 From 17383a2a2a84953bc87252d32ec4382a475c88ba Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 11 Aug 2003 22:28:58 +0000 Subject: gcc 3.x is mandatory now on PowerPC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@369 c046a42c-6fe2-441c-8c8c-71466251a162 --- README | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README b/README index 13dae1ff8..c7038c21a 100644 --- a/README +++ b/README @@ -52,7 +52,8 @@ x86 2.95.2 2.13.2 2.1.3 2.4.18 2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3 3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9 -PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 Debian 3.0 +PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq + 3.2 Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0 @@ -66,6 +67,9 @@ ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0 (untested). [3] 2.4.9-ac10-rmk2-np1-cerf2 +[4] gcc 2.95.x generates invalid code when using too many register +variables. You must use gcc 3.x on PowerPC. + Documentation ------------- -- cgit v1.2.3 From 2d80ae898777a9069e38101b1b53a1347f558838 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 11 Aug 2003 23:01:33 +0000 Subject: avoid problems if make clean was not made before updating git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@370 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 52d6383c8..1ecf99c94 100644 --- a/Makefile +++ b/Makefile @@ -21,13 +21,15 @@ dyngen: dyngen.o $(HOST_CC) $(CFLAGS) $(DEFINES) -c -o $@ $< clean: +# avoid old build problems by removing potentially incorrect old files + rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f *.o *.a $(TOOLS) dyngen TAGS for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done distclean: clean - rm -f config-host.mak config-host.h config.mak config.h + rm -f config-host.mak config-host.h for d in $(TARGET_DIRS); do \ rm -f $$d/config.h $$d/config.mak || exit 1 ; \ done -- cgit v1.2.3 From d05e66d217f8f83487c3b1d3015a67316b47645f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 20 Aug 2003 21:34:35 +0000 Subject: no error code if hardware interrupt git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@371 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 ++-- exec-i386.h | 2 +- helper-i386.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index fe165dffd..39bb933f5 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -170,7 +170,7 @@ int cpu_exec(CPUState *env1) do_interrupt(env->exception_index, env->exception_is_int, env->error_code, - env->exception_next_eip); + env->exception_next_eip, 0); #endif } env->exception_index = -1; @@ -192,7 +192,7 @@ int cpu_exec(CPUState *env1) if (loglevel) { fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); } - do_interrupt(intno, 0, 0, 0); + do_interrupt(intno, 0, 0, 0, 1); env->interrupt_request &= ~CPU_INTERRUPT_HARD; /* ensure that no TB jump will be modified as the program flow was changed */ diff --git a/exec-i386.h b/exec-i386.h index 03a547fb1..96ad04e8e 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -142,7 +142,7 @@ void tlb_fill(unsigned long addr, int is_write, void *retaddr); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip); + unsigned int next_eip, int is_hw); void do_interrupt_user(int intno, int is_int, int error_code, unsigned int next_eip); void raise_interrupt(int intno, int is_int, int error_code, diff --git a/helper-i386.c b/helper-i386.c index fba6b5b25..fdbb885b1 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -185,7 +185,7 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, /* protected mode interrupt */ static void do_interrupt_protected(int intno, int is_int, int error_code, - unsigned int next_eip) + unsigned int next_eip, int is_hw) { SegmentCache *dt; uint8_t *ptr, *ssp; @@ -265,7 +265,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, shift = type >> 3; has_error_code = 0; - if (!is_int) { + if (!is_int && !is_hw) { switch(intno) { case 8: case 10: @@ -427,10 +427,10 @@ void do_interrupt_user(int intno, int is_int, int error_code, * instruction. It is only relevant if is_int is TRUE. */ void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip) + unsigned int next_eip, int is_hw) { if (env->cr[0] & CR0_PE_MASK) { - do_interrupt_protected(intno, is_int, error_code, next_eip); + do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); } else { do_interrupt_real(intno, is_int, error_code, next_eip); } -- cgit v1.2.3 From 3f3373166227b13e762e20d2fb51eadfa6a2d653 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 20 Aug 2003 23:02:09 +0000 Subject: pop ss, mov ss, x and sti disable irqs for the next instruction - began dispatch optimization by adding new x86 cpu 'hidden' flags git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@372 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 26 +++++++++++++------------- cpu-i386.h | 36 +++++++++++++++++++++++++++++++++--- exec.h | 10 ---------- helper-i386.c | 22 ++++++++++++---------- helper2-i386.c | 8 ++++---- op-i386.c | 10 ++++++++++ softmmu_template.h | 8 ++++---- translate-i386.c | 47 +++++++++++++++++++++++++++++++++-------------- 8 files changed, 109 insertions(+), 58 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 39bb933f5..7899a9086 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -186,7 +186,8 @@ int cpu_exec(CPUState *env1) #if defined(TARGET_I386) /* if hardware interrupt pending, we execute it */ if ((interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK)) { + (env->eflags & IF_MASK) && + !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; intno = cpu_x86_get_pic_interrupt(env); if (loglevel) { @@ -233,21 +234,20 @@ int cpu_exec(CPUState *env1) #endif } #endif - /* we compute the CPU state. We assume it will not - change during the whole generated block. */ + /* 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->segs[R_CS].flags & DESC_B_MASK) - >> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT); + >> (DESC_B_SHIFT - HF_CS32_SHIFT); flags |= (env->segs[R_SS].flags & DESC_B_MASK) - >> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT); + >> (DESC_B_SHIFT - HF_SS32_SHIFT); flags |= (((unsigned long)env->segs[R_DS].base | (unsigned long)env->segs[R_ES].base | (unsigned long)env->segs[R_SS].base) != 0) << - GEN_FLAG_ADDSEG_SHIFT; - flags |= env->cpl << GEN_FLAG_CPL_SHIFT; - flags |= env->soft_mmu << GEN_FLAG_SOFT_MMU_SHIFT; - flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT); - flags |= (env->eflags & (IOPL_MASK | TF_MASK)); + HF_ADDSEG_SHIFT; + 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) @@ -337,8 +337,8 @@ int cpu_exec(CPUState *env1) /* 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->soft_mmu) { - env->soft_mmu = 0; + if (env->hflags & HF_SOFTMMU_MASK) { + env->hflags &= ~HF_SOFTMMU_MASK; /* do not allow linking to another block */ T0 = 0; } @@ -499,7 +499,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, raise_exception_err(EXCP0E_PAGE, env->error_code); } else { /* activate soft MMU for this block */ - env->soft_mmu = 1; + env->hflags |= HF_SOFTMMU_MASK; sigprocmask(SIG_SETMASK, old_set, NULL); cpu_loop_exit(); } diff --git a/cpu-i386.h b/cpu-i386.h index a60e95915..ad3a6b801 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -73,6 +73,10 @@ #define CC_S 0x0080 #define CC_O 0x0800 +#define TF_SHIFT 8 +#define IOPL_SHIFT 12 +#define VM_SHIFT 17 + #define TF_MASK 0x00000100 #define IF_MASK 0x00000200 #define DF_MASK 0x00000400 @@ -85,6 +89,29 @@ #define VIP_MASK 0x00100000 #define ID_MASK 0x00200000 +/* hidden flags - used internally by qemu to represent additionnal cpu + states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid + using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring + with eflags. */ +/* current cpl */ +#define HF_CPL_SHIFT 0 +/* true if soft mmu is being used */ +#define HF_SOFTMMU_SHIFT 2 +/* true if hardware interrupts must be disabled for next instruction */ +#define HF_INHIBIT_IRQ_SHIFT 3 +/* 16 or 32 segments */ +#define HF_CS32_SHIFT 4 +#define HF_SS32_SHIFT 5 +/* zero base for DS, ES and SS */ +#define HF_ADDSEG_SHIFT 6 + +#define HF_CPL_MASK (3 << HF_CPL_SHIFT) +#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) +#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) +#define HF_CS32_MASK (1 << HF_CS32_SHIFT) +#define HF_SS32_MASK (1 << HF_CS32_SHIFT) +#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) + #define CR0_PE_MASK (1 << 0) #define CR0_TS_MASK (1 << 3) #define CR0_WP_MASK (1 << 16) @@ -226,6 +253,7 @@ typedef struct CPUX86State { uint32_t cc_dst; uint32_t cc_op; int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ + uint32_t hflags; /* hidden flags, see HF_xxx constants */ /* FPU state */ unsigned int fpstt; /* top of stack index */ @@ -249,8 +277,6 @@ typedef struct CPUX86State { SegmentCache tr; SegmentCache gdt; /* only base and limit are used */ SegmentCache idt; /* only base and limit are used */ - int cpl; /* current cpl */ - int soft_mmu; /* TRUE if soft mmu is being used */ /* sysenter registers */ uint32_t sysenter_cs; @@ -303,7 +329,11 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); /* wrapper, just in case memory mappings must be changed */ static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) { - s->cpl = cpl; +#if HF_CPL_MASK == 3 + s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl; +#else +#error HF_CPL_MASK is hardcoded +#endif } /* simulate fsave/frstor */ diff --git a/exec.h b/exec.h index 026daaabe..b63a66f51 100644 --- a/exec.h +++ b/exec.h @@ -61,16 +61,6 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #if defined(TARGET_I386) -#define GEN_FLAG_CODE32_SHIFT 0 -#define GEN_FLAG_ADDSEG_SHIFT 1 -#define GEN_FLAG_SS32_SHIFT 2 -#define GEN_FLAG_VM_SHIFT 3 -#define GEN_FLAG_ST_SHIFT 4 -#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */ -#define GEN_FLAG_CPL_SHIFT 9 -#define GEN_FLAG_SOFT_MMU_SHIFT 11 -#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ - void optimize_flags_init(void); #endif diff --git a/helper-i386.c b/helper-i386.c index fdbb885b1..0d128ea44 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -189,7 +189,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, { SegmentCache *dt; uint8_t *ptr, *ssp; - int type, dpl, selector, ss_dpl; + int type, dpl, selector, ss_dpl, cpl; int has_error_code, new_stack, shift; uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; uint32_t old_cs, old_ss, old_esp, old_eip; @@ -216,8 +216,9 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, break; } dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ - if (is_int && dpl < env->cpl) + if (is_int && dpl < cpl) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); /* check valid bit */ if (!(e2 & DESC_P_MASK)) @@ -232,11 +233,11 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > env->cpl) + if (dpl > cpl) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - if (!(e2 & DESC_C_MASK) && dpl < env->cpl) { + if (!(e2 & DESC_C_MASK) && dpl < cpl) { /* to inner priviledge */ get_ss_esp_from_tss(&ss, &esp, dpl); if ((ss & 0xfffc) == 0) @@ -255,7 +256,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); new_stack = 1; - } else if ((e2 & DESC_C_MASK) || dpl == env->cpl) { + } else if ((e2 & DESC_C_MASK) || dpl == cpl) { /* to same priviledge */ new_stack = 0; } else { @@ -402,7 +403,7 @@ void do_interrupt_user(int intno, int is_int, int error_code, { SegmentCache *dt; uint8_t *ptr; - int dpl; + int dpl, cpl; uint32_t e2; dt = &env->idt; @@ -410,8 +411,9 @@ void do_interrupt_user(int intno, int is_int, int error_code, e2 = ldl(ptr + 4); dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ - if (is_int && dpl < env->cpl) + if (is_int && dpl < cpl) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); /* Since we emulate only user space, we cannot do more than @@ -742,7 +744,7 @@ void helper_ljmp_protected_T0_T1(void) raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, new_cs) != 0) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->cpl; + cpl = env->hflags & HF_CPL_MASK; if (e2 & DESC_S_MASK) { if (!(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -826,7 +828,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, new_cs) != 0) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->cpl; + cpl = env->hflags & HF_CPL_MASK; if (e2 & DESC_S_MASK) { if (!(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -1079,7 +1081,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if (!(e2 & DESC_S_MASK) || !(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->cpl; + cpl = env->hflags & HF_CPL_MASK; rpl = new_cs & 3; if (rpl < cpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); diff --git a/helper2-i386.c b/helper2-i386.c index 7a6fc13b5..f006c72a2 100644 --- a/helper2-i386.c +++ b/helper2-i386.c @@ -52,7 +52,7 @@ CPUX86State *cpu_x86_init(void) tlb_flush(env); #ifdef CONFIG_SOFTMMU - env->soft_mmu = 1; + env->hflags |= HF_SOFTMMU_MASK; #endif /* init various static tables */ if (!inited) { @@ -228,7 +228,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) int cpl, error_code, is_dirty, is_user, prot, page_size, ret; unsigned long pd; - cpl = env->cpl; + cpl = env->hflags & HF_CPL_MASK; is_user = (cpl == 3); #ifdef DEBUG_MMU @@ -325,7 +325,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) } do_mapping: - if (env->soft_mmu) { + if (env->hflags & HF_SOFTMMU_MASK) { unsigned long paddr, vaddr, address, addend, page_offset; int index; @@ -359,7 +359,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) if ((pd & 0xfff) != 0) { /* IO access: no mapping is done as it will be handled by the soft MMU */ - if (!env->soft_mmu) + if (!(env->hflags & HF_SOFTMMU_MASK)) ret = 2; } else { void *map_addr; diff --git a/op-i386.c b/op-i386.c index 833b1f9d3..7b0c3917a 100644 --- a/op-i386.c +++ b/op-i386.c @@ -457,6 +457,16 @@ void OPPROTO op_sti(void) env->eflags |= IF_MASK; } +void OPPROTO op_set_inhibit_irq(void) +{ + env->hflags |= HF_INHIBIT_IRQ_MASK; +} + +void OPPROTO op_reset_inhibit_irq(void) +{ + env->hflags &= ~HF_INHIBIT_IRQ_MASK; +} + #if 0 /* vm86plus instructions */ void OPPROTO op_cli_vm(void) diff --git a/softmmu_template.h b/softmmu_template.h index c36e25ae2..765e913a6 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -90,7 +90,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr) /* test if there is match for unaligned or IO access */ /* XXX: could done more in memory macro in a non portable way */ - is_user = (env->cpl == 3); + is_user = ((env->hflags & HF_CPL_MASK) == 3); index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_read[is_user][index].address; @@ -126,7 +126,7 @@ static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr) int is_user, index, shift; unsigned long physaddr, tlb_addr, addr1, addr2; - is_user = (env->cpl == 3); + is_user = ((env->hflags & HF_CPL_MASK) == 3); index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_read[is_user][index].address; @@ -169,7 +169,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val void *retaddr; int is_user, index; - is_user = (env->cpl == 3); + is_user = ((env->hflags & HF_CPL_MASK) == 3); index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_write[is_user][index].address; @@ -203,7 +203,7 @@ static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, unsigned long physaddr, tlb_addr; int is_user, index, i; - is_user = (env->cpl == 3); + is_user = ((env->hflags & HF_CPL_MASK) == 3); index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_write[is_user][index].address; diff --git a/translate-i386.c b/translate-i386.c index e527c901d..0e72acf19 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1552,7 +1552,9 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) else gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); /* abort translation because the register may have a non zero base - or because ss32 may change */ + or because ss32 may change. For R_SS, translation must always + stop as a special handling must be done to disable hardware + interrupts for the next instruction */ if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) s->is_jmp = 2; } @@ -2356,10 +2358,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x07: /* pop es */ case 0x17: /* pop ss */ case 0x1f: /* pop ds */ + reg = b >> 3; gen_pop_T0(s); - gen_movl_seg_T0(s, b >> 3, pc_start - s->cs_base); + gen_movl_seg_T0(s, reg, pc_start - s->cs_base); gen_pop_update(s); - /* XXX: if reg == SS, inhibit interrupts/trace */ + if (reg == R_SS) { + /* if reg == SS, inhibit interrupts/trace */ + gen_op_set_inhibit_irq(); + } break; case 0x1a1: /* pop fs */ case 0x1a9: /* pop gs */ @@ -2418,7 +2424,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_movl_seg_T0(s, reg, pc_start - s->cs_base); - /* XXX: if reg == SS, inhibit interrupts/trace */ + if (reg == R_SS) { + /* if reg == SS, inhibit interrupts/trace */ + gen_op_set_inhibit_irq(); + } break; case 0x8c: /* mov Gv, seg */ modrm = ldub(s->pc++); @@ -3704,6 +3713,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (!s->vm86) { if (s->cpl <= s->iopl) { gen_op_sti(); + /* interruptions are enabled only the first insn after sti */ + gen_op_set_inhibit_irq(); s->is_jmp = 2; /* give a chance to handle pending irqs */ } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); @@ -3711,12 +3722,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { if (s->iopl == 3) { gen_op_sti(); + /* interruptions are enabled only the first insn after sti */ + gen_op_set_inhibit_irq(); s->is_jmp = 2; /* give a chance to handle pending irqs */ } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } - /* XXX: interruptions are enabled only the first insn after sti */ break; case 0x62: /* bound */ ot = dflag ? OT_LONG : OT_WORD; @@ -4380,21 +4392,21 @@ static inline int gen_intermediate_code_internal(CPUState *env, flags = tb->flags; dc->pe = env->cr[0] & CR0_PE_MASK; - dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; - dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; - dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; - dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; - dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; - dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; - dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3; - dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; + dc->code32 = (flags >> HF_CS32_SHIFT) & 1; + dc->ss32 = (flags >> HF_SS32_SHIFT) & 1; + dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1; + dc->f_st = 0; + dc->vm86 = (flags >> VM_SHIFT) & 1; + dc->cpl = (flags >> HF_CPL_SHIFT) & 3; + dc->iopl = (flags >> IOPL_SHIFT) & 3; + dc->tf = (flags >> TF_SHIFT) & 1; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; dc->tb = tb; dc->popl_esp_hack = 0; /* select memory access functions */ dc->mem_index = 0; - if ((flags >> GEN_FLAG_SOFT_MMU_SHIFT) & 1) { + if (flags & HF_SOFTMMU_MASK) { if (dc->cpl == 3) dc->mem_index = 6; else @@ -4408,6 +4420,13 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->is_jmp = DISAS_NEXT; pc_ptr = pc_start; lj = -1; + + /* if irq were inhibited for the next instruction, we can disable + them here as it is simpler (otherwise jumps would have to + handled as special case) */ + if (flags & HF_INHIBIT_IRQ_MASK) { + gen_op_reset_inhibit_irq(); + } do { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { -- cgit v1.2.3 From 2e255c6b9f05f78a7effc4d1246c8a420680b810 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 21 Aug 2003 23:25:21 +0000 Subject: faster and more accurate segment handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@373 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 20 ++----- cpu-i386.h | 45 ++++++++++++++-- helper-i386.c | 155 ++++++++++++++++++++++++++++++++---------------------- linux-user/main.c | 2 + op-i386.c | 1 + translate-i386.c | 3 +- vl.c | 24 ++++----- 7 files changed, 153 insertions(+), 97 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 7899a9086..e3d239199 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -182,7 +182,7 @@ int cpu_exec(CPUState *env1) tmp_T0 = T0; #endif interrupt_request = env->interrupt_request; - if (interrupt_request) { + if (__builtin_expect(interrupt_request, 0)) { #if defined(TARGET_I386) /* if hardware interrupt pending, we execute it */ if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -238,15 +238,7 @@ int cpu_exec(CPUState *env1) always be the same before a given translated block is executed. */ #if defined(TARGET_I386) - flags = (env->segs[R_CS].flags & DESC_B_MASK) - >> (DESC_B_SHIFT - HF_CS32_SHIFT); - flags |= (env->segs[R_SS].flags & DESC_B_MASK) - >> (DESC_B_SHIFT - HF_SS32_SHIFT); - flags |= (((unsigned long)env->segs[R_DS].base | - (unsigned long)env->segs[R_ES].base | - (unsigned long)env->segs[R_SS].base) != 0) << - HF_ADDSEG_SHIFT; - flags |= env->hflags; + flags = env->hflags; flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); cs_base = env->segs[R_CS].base; pc = cs_base + env->eip; @@ -402,13 +394,9 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) saved_env = env; env = s; if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { - SegmentCache *sc; selector &= 0xffff; - sc = &env->segs[seg_reg]; - sc->base = (void *)(selector << 4); - sc->limit = 0xffff; - sc->flags = 0; - sc->selector = selector; + cpu_x86_load_seg_cache(env, seg_reg, selector, + (uint8_t *)(selector << 4), 0xffff, 0); } else { load_seg(seg_reg, selector, 0); } diff --git a/cpu-i386.h b/cpu-i386.h index ad3a6b801..ffc4654d3 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -109,7 +109,7 @@ #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) #define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) #define HF_CS32_MASK (1 << HF_CS32_SHIFT) -#define HF_SS32_MASK (1 << HF_CS32_SHIFT) +#define HF_SS32_MASK (1 << HF_SS32_SHIFT) #define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) #define CR0_PE_MASK (1 << 0) @@ -323,8 +323,43 @@ int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); int cpu_x86_get_pic_interrupt(CPUX86State *s); -/* needed to load some predefinied segment registers */ -void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); +/* this function must always be used to load data in the segment + cache: it synchronizes the hflags with the segment cache values */ +static inline void cpu_x86_load_seg_cache(CPUX86State *env, + int seg_reg, unsigned int selector, + uint8_t *base, unsigned int limit, + unsigned int flags) +{ + SegmentCache *sc; + unsigned int new_hflags; + + sc = &env->segs[seg_reg]; + sc->selector = selector; + sc->base = base; + sc->limit = limit; + sc->flags = flags; + + /* update the hidden flags */ + new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - HF_CS32_SHIFT); + new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - HF_SS32_SHIFT); + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + /* XXX: try to avoid this test. The problem comes from the + fact that is real mode or vm86 mode we only modify the + 'base' and 'selector' fields of the segment cache to go + faster. A solution may be to force addseg to one in + translate-i386.c. */ + new_hflags |= HF_ADDSEG_MASK; + } else { + new_hflags |= (((unsigned long)env->segs[R_DS].base | + (unsigned long)env->segs[R_ES].base | + (unsigned long)env->segs[R_SS].base) != 0) << + HF_ADDSEG_SHIFT; + } + env->hflags = (env->hflags & + ~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags; +} /* wrapper, just in case memory mappings must be changed */ static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) @@ -336,7 +371,9 @@ static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) #endif } -/* simulate fsave/frstor */ +/* the following helpers are only usable in user mode simulation as + they can trigger unexpected exceptions */ +void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); diff --git a/helper-i386.c b/helper-i386.c index 0d128ea44..67c3aec6c 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -182,6 +182,34 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, return 0; } +static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) +{ + unsigned int limit; + limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & DESC_G_MASK) + limit = (limit << 12) | 0xfff; + return limit; +} + +static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) +{ + return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); +} + +static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) +{ + sc->base = get_seg_base(e1, e2); + sc->limit = get_seg_limit(e1, e2); + sc->flags = e2; +} + +/* init the segment cache in vm86 mode. */ +static inline void load_seg_vm(int seg, int selector) +{ + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg, selector, + (uint8_t *)(selector << 4), 0xffff, 0); +} /* protected mode interrupt */ static void do_interrupt_protected(int intno, int is_int, int error_code, @@ -288,7 +316,11 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (new_stack) { old_esp = ESP; old_ss = env->segs[R_SS].selector; - load_seg(R_SS, ss, env->eip); + ss = (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + get_seg_base(ss_e1, ss_e2), + get_seg_limit(ss_e1, ss_e2), + ss_e2); } else { old_esp = 0; old_ss = 0; @@ -299,7 +331,12 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, else old_eip = env->eip; old_cs = env->segs[R_CS].selector; - load_seg(R_CS, selector, env->eip); + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); env->eip = offset; ESP = esp - push_size; ssp = env->segs[R_SS].base + esp; @@ -593,15 +630,6 @@ void helper_cpuid(void) } } -static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2) -{ - sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); - sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & DESC_G_MASK) - sc->limit = (sc->limit << 12) | 0xfff; - sc->flags = e2; -} - void helper_lldt_T0(void) { int selector; @@ -629,7 +657,7 @@ void helper_lldt_T0(void) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - load_seg_cache(&env->ldt, e1, e2); + load_seg_cache_raw_dt(&env->ldt, e1, e2); } env->ldt.selector = selector; } @@ -664,30 +692,26 @@ void helper_ltr_T0(void) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - load_seg_cache(&env->tr, e1, e2); + load_seg_cache_raw_dt(&env->tr, e1, e2); e2 |= 0x00000200; /* set the busy bit */ stl(ptr + 4, e2); } env->tr.selector = selector; } -/* only works if protected mode and not VM86 */ +/* only works if protected mode and not VM86. Calling load_seg with + seg_reg == R_CS is discouraged */ void load_seg(int seg_reg, int selector, unsigned int cur_eip) { - SegmentCache *sc; uint32_t e1, e2; - sc = &env->segs[seg_reg]; if ((selector & 0xfffc) == 0) { /* null selector case */ if (seg_reg == R_SS) { EIP = cur_eip; raise_exception_err(EXCP0D_GPF, 0); } else { - /* XXX: each access should trigger an exception */ - sc->base = NULL; - sc->limit = 0; - sc->flags = 0; + cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); } } else { if (load_segment(&e1, &e2, selector) != 0) { @@ -719,24 +743,22 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) else raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); } - load_seg_cache(sc, e1, e2); + cpu_x86_load_seg_cache(env, seg_reg, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); #if 0 fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", selector, (unsigned long)sc->base, sc->limit, sc->flags); #endif } - if (seg_reg == R_CS) { - cpu_x86_set_cpl(env, selector & 3); - } - sc->selector = selector; } /* protected mode jump */ void helper_ljmp_protected_T0_T1(void) { int new_cs, new_eip; - SegmentCache sc1; - uint32_t e1, e2, cpl, dpl, rpl; + uint32_t e1, e2, cpl, dpl, rpl, limit; new_cs = T0; new_eip = T1; @@ -763,13 +785,11 @@ void helper_ljmp_protected_T0_T1(void) } if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - load_seg_cache(&sc1, e1, e2); - if (new_eip > sc1.limit) + limit = get_seg_limit(e1, e2); + if (new_eip > limit) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - env->segs[R_CS].base = sc1.base; - env->segs[R_CS].limit = sc1.limit; - env->segs[R_CS].flags = sc1.flags; - env->segs[R_CS].selector = (new_cs & 0xfffc) | cpl; + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); EIP = new_eip; } else { cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", @@ -816,10 +836,9 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) void helper_lcall_protected_T0_T1(int shift, int next_eip) { int new_cs, new_eip; - SegmentCache sc1; uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; - uint32_t old_ss, old_esp, val, i; + uint32_t old_ss, old_esp, val, i, limit; uint8_t *ssp, *old_ssp; new_cs = T0; @@ -865,18 +884,16 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) } sp -= (4 << shift); - load_seg_cache(&sc1, e1, e2); - if (new_eip > sc1.limit) + limit = get_seg_limit(e1, e2); + if (new_eip > limit) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); /* from this point, not restartable */ if (!(env->segs[R_SS].flags & DESC_B_MASK)) ESP = (ESP & 0xffff0000) | (sp & 0xffff); else ESP = sp; - env->segs[R_CS].base = sc1.base; - env->segs[R_CS].limit = sc1.limit; - env->segs[R_CS].flags = sc1.flags; - env->segs[R_CS].selector = (new_cs & 0xfffc) | cpl; + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); EIP = new_eip; } else { /* check gate type */ @@ -947,7 +964,11 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) old_ssp = env->segs[R_SS].base + old_esp; /* XXX: from this point not restartable */ - load_seg(R_SS, ss, env->eip); + ss = (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + get_seg_base(ss_e1, ss_e2), + get_seg_limit(ss_e1, ss_e2), + ss_e2); if (!(env->segs[R_SS].flags & DESC_B_MASK)) sp &= 0xffff; @@ -994,7 +1015,13 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) } sp -= push_size; - load_seg(R_CS, selector, env->eip); + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); + /* from this point, not restartable if same priviledge */ if (!(env->segs[R_SS].flags & DESC_B_MASK)) ESP = (ESP & 0xffff0000) | (sp & 0xffff); @@ -1004,17 +1031,6 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) } } -/* init the segment cache in vm86 mode */ -static inline void load_seg_vm(int seg, int selector) -{ - SegmentCache *sc = &env->segs[seg]; - selector &= 0xffff; - sc->base = (uint8_t *)(selector << 4); - sc->selector = selector; - sc->flags = 0; - sc->limit = 0xffff; -} - /* real mode iret */ void helper_iret_real(int shift) { @@ -1051,7 +1067,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) { uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; uint32_t new_es, new_ds, new_fs, new_gs; - uint32_t e1, e2; + uint32_t e1, e2, ss_e1, ss_e2; int cpl, dpl, rpl, eflags_mask; uint8_t *ssp; @@ -1098,7 +1114,10 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if (rpl == cpl) { /* return to same priledge level */ - load_seg(R_CS, new_cs, env->eip); + cpu_x86_load_seg_cache(env, R_CS, new_cs, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; } else { /* return to different priviledge level */ @@ -1115,20 +1134,27 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if ((new_ss & 3) != rpl) raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (load_segment(&e1, &e2, new_ss) != 0) + if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(e2 & DESC_S_MASK) || - (e2 & DESC_CS_MASK) || - !(e2 & DESC_W_MASK)) + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; + dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; if (dpl != rpl) raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(e2 & DESC_P_MASK)) + if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); - load_seg(R_CS, new_cs, env->eip); - load_seg(R_SS, new_ss, env->eip); + cpu_x86_load_seg_cache(env, R_CS, new_cs, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_load_seg_cache(env, R_SS, new_ss, + get_seg_base(ss_e1, ss_e2), + get_seg_limit(ss_e1, ss_e2), + ss_e2); + cpu_x86_set_cpl(env, rpl); } if (env->segs[R_SS].flags & DESC_B_MASK) ESP = new_esp; @@ -1137,6 +1163,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) (new_esp & 0xffff); env->eip = new_eip; if (is_iret) { + /* NOTE: 'cpl' can be different from the current CPL */ if (cpl == 0) eflags_mask = FL_UPDATE_CPL0_MASK; else diff --git a/linux-user/main.c b/linux-user/main.c index b85637f8b..f4c936c5b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -433,6 +433,8 @@ int main(int argc, char **argv) env->user_mode_only = 1; #if defined(TARGET_I386) + cpu_x86_set_cpl(env, 3); + env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; /* linux register setup */ diff --git a/op-i386.c b/op-i386.c index 7b0c3917a..2f84e15e5 100644 --- a/op-i386.c +++ b/op-i386.c @@ -890,6 +890,7 @@ void OPPROTO op_das(void) /* segment handling */ +/* never use it with R_CS */ void OPPROTO op_movl_seg_T0(void) { load_seg(PARAM1, T0 & 0xffff, PARAM2); diff --git a/translate-i386.c b/translate-i386.c index 0e72acf19..fd13adbe4 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -1544,7 +1544,8 @@ static void gen_setcc(DisasContext *s, int b) } } -/* move T0 to seg_reg and compute if the CPU state may change */ +/* move T0 to seg_reg and compute if the CPU state may change. Never + call this function with seg_reg == R_CS */ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) { if (s->pe && !s->vm86) diff --git a/vl.c b/vl.c index 97c3be8da..d517eeebe 100644 --- a/vl.c +++ b/vl.c @@ -3590,12 +3590,12 @@ int main(int argc, char **argv) env->gdt.base = (void *)params->gdt_table; env->gdt.limit = sizeof(params->gdt_table) - 1; - cpu_x86_load_seg(env, R_CS, KERNEL_CS); - cpu_x86_load_seg(env, R_DS, KERNEL_DS); - cpu_x86_load_seg(env, R_ES, KERNEL_DS); - cpu_x86_load_seg(env, R_SS, KERNEL_DS); - cpu_x86_load_seg(env, R_FS, KERNEL_DS); - cpu_x86_load_seg(env, R_GS, KERNEL_DS); + cpu_x86_load_seg_cache(env, R_CS, KERNEL_CS, NULL, 0xffffffff, 0x00cf9a00); + cpu_x86_load_seg_cache(env, R_DS, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); + cpu_x86_load_seg_cache(env, R_ES, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); + cpu_x86_load_seg_cache(env, R_SS, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); + cpu_x86_load_seg_cache(env, R_FS, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); + cpu_x86_load_seg_cache(env, R_GS, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); env->eip = KERNEL_LOAD_ADDR; env->regs[R_ESI] = KERNEL_PARAMS_ADDR; @@ -3627,12 +3627,12 @@ int main(int argc, char **argv) env->ldt.limit = 0xffff; /* not correct (CS base=0xffff0000) */ - cpu_x86_load_seg(env, R_CS, 0xf000); - cpu_x86_load_seg(env, R_DS, 0); - cpu_x86_load_seg(env, R_ES, 0); - cpu_x86_load_seg(env, R_SS, 0); - cpu_x86_load_seg(env, R_FS, 0); - cpu_x86_load_seg(env, R_GS, 0); + cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0); env->eip = 0xfff0; env->regs[R_EDX] = 0x600; /* indicate P6 processor */ -- cgit v1.2.3 From b67d59594e36b61b06e70ec79d7aa639acac20d5 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 16 Sep 2003 21:46:04 +0000 Subject: glibc 2.3.x fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@374 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index d517eeebe..94d919643 100644 --- a/vl.c +++ b/vl.c @@ -3247,7 +3247,6 @@ int main_loop(void *opaque) } for(;;) { - ret = cpu_x86_exec(env); if (reset_requested) break; @@ -3648,8 +3647,13 @@ int main(int argc, char **argv) } else { #ifdef CONFIG_SDL sdl_display_init(ds); - /* the pthreads modify sigaction. We don't want that. */ + /* SDL use the pthreads and they modify sigaction. We don't + want that. */ +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +#define sigaction __libc_sigaction +#else #define sigaction __sigaction +#endif #else dumb_display_init(ds); #endif -- cgit v1.2.3 From b1ba65744e99b0c844efba822940d5b0e4eb56cc Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 16 Sep 2003 21:47:08 +0000 Subject: depth 32 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@375 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga_template.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/vga_template.h b/hw/vga_template.h index ac2e6258a..0d1d5ce73 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -51,14 +51,14 @@ static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol; ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; #else - ((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; + ((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; #endif } -- cgit v1.2.3 From 3ff0631ed9b993f933c1430c7eae5c8b851bb8d2 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Sep 2003 22:49:51 +0000 Subject: added linux < 2.4.21 vm86 bug workaround - added extensive TF flag test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@376 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index a7ee032c0..3c0a76bef 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -13,6 +13,7 @@ #define TEST_CMOV 0 #define TEST_FCOMI 0 +//#define LINUX_VM86_IOPL_FIX #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) @@ -1106,7 +1107,7 @@ void test_vm86(void) switch(VM86_TYPE(ret)) { case VM86_INTx: { - int int_num, ah; + int int_num, ah, v; int_num = VM86_ARG(ret); if (int_num != 0x21) @@ -1134,8 +1135,12 @@ void test_vm86(void) r->eax = (r->eax & ~0xff) | '$'; } break; - case 0xff: /* extension: write hex number in edx */ - printf("%08x\n", (int)r->edx); + case 0xff: /* extension: write eflags number in edx */ + v = (int)r->edx; +#ifndef LINUX_VM86_IOPL_FIX + v &= ~0x3000; +#endif + printf("%08x\n", v); break; default: unknown_int: @@ -1356,6 +1361,90 @@ void test_exceptions(void) printf("val=0x%x\n", val); } +/* specific precise single step test */ +void sig_trap_handler(int sig, siginfo_t *info, void *puc) +{ + struct ucontext *uc = puc; + printf("EIP=0x%08x\n", uc->uc_mcontext.gregs[REG_EIP]); +} + +const uint8_t sstep_buf1[4] = { 1, 2, 3, 4}; +uint8_t sstep_buf2[4]; + +void test_single_step(void) +{ + struct sigaction act; + volatile int val; + int i; + + val = 0; + act.sa_sigaction = sig_trap_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + sigaction(SIGTRAP, &act, NULL); + asm volatile ("pushf\n" + "orl $0x00100, (%%esp)\n" + "popf\n" + "movl $0xabcd, %0\n" + + /* jmp test */ + "movl $3, %%ecx\n" + "1:\n" + "addl $1, %0\n" + "decl %%ecx\n" + "jnz 1b\n" + + /* movsb: the single step should stop at each movsb iteration */ + "movl $sstep_buf1, %%esi\n" + "movl $sstep_buf2, %%edi\n" + "movl $0, %%ecx\n" + "rep movsb\n" + "movl $3, %%ecx\n" + "rep movsb\n" + "movl $1, %%ecx\n" + "rep movsb\n" + + /* cmpsb: the single step should stop at each cmpsb iteration */ + "movl $sstep_buf1, %%esi\n" + "movl $sstep_buf2, %%edi\n" + "movl $0, %%ecx\n" + "rep cmpsb\n" + "movl $4, %%ecx\n" + "rep cmpsb\n" + + /* getpid() syscall: single step should skip one + instruction */ + "movl $20, %%eax\n" + "int $0x80\n" + "movl $0, %%eax\n" + + /* when modifying SS, trace is not done on the next + instruction */ + "movl %%ss, %%ecx\n" + "movl %%ecx, %%ss\n" + "addl $1, %0\n" + "movl $1, %%eax\n" + "movl %%ecx, %%ss\n" + "jmp 1f\n" + "addl $1, %0\n" + "1:\n" + "movl $1, %%eax\n" + "pushl %%ecx\n" + "popl %%ss\n" + "addl $1, %0\n" + "movl $1, %%eax\n" + + "pushf\n" + "andl $~0x00100, (%%esp)\n" + "popf\n" + : "=m" (val) + : + : "cc", "memory", "eax", "ecx", "esi", "edi"); + printf("val=%d\n", val); + for(i = 0; i < 4; i++) + printf("sstep_buf2[%d] = %d\n", i, sstep_buf2[i]); +} + /* self modifying code test */ uint8_t code[] = { 0xb8, 0x1, 0x00, 0x00, 0x00, /* movl $1, %eax */ @@ -1402,5 +1491,6 @@ int main(int argc, char **argv) test_vm86(); test_exceptions(); test_self_modifying_code(); + test_single_step(); return 0; } -- cgit v1.2.3 From facc68be25927d95dda2f0248ab66daa990e997d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Sep 2003 22:51:18 +0000 Subject: removed x86 hacks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@377 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index e3d239199..69671df86 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -268,17 +268,7 @@ int cpu_exec(CPUState *env1) tb->tc_ptr = tc_ptr; tb->cs_base = (unsigned long)cs_base; tb->flags = flags; - ret = cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); -#if defined(TARGET_I386) - /* XXX: suppress that, this is incorrect */ - /* if invalid instruction, signal it */ - if (ret != 0) { - /* NOTE: the tb is allocated but not linked, so we - can leave it */ - spin_unlock(&tb_lock); - raise_exception(EXCP06_ILLOP); - } -#endif + cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); *ptb = tb; tb->hash_next = NULL; tb_link(tb); @@ -295,12 +285,8 @@ int cpu_exec(CPUState *env1) #ifdef __sparc__ T0 = tmp_T0; #endif - /* see if we can patch the calling TB. XXX: remove TF test */ - if (T0 != 0 -#if defined(TARGET_I386) - && !(env->eflags & TF_MASK) -#endif - ) { + /* see if we can patch the calling TB. */ + if (T0 != 0) { spin_lock(&tb_lock); tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); spin_unlock(&tb_lock); -- cgit v1.2.3 From c106152d26a68e86400d454c86b1e908ba3f77d8 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Sep 2003 22:51:45 +0000 Subject: added two more jump points git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@378 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 2 +- dyngen.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 980e70ca9..ed286db8f 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -161,7 +161,7 @@ extern int __op_param1, __op_param2, __op_param3; #define PARAM3 ((long)(&__op_param3)) #endif -extern int __op_jmp0, __op_jmp1; +extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ #define EXIT_TB() asm volatile ("ret") diff --git a/dyngen.h b/dyngen.h index cc38228b7..f7f1d3aab 100644 --- a/dyngen.h +++ b/dyngen.h @@ -19,7 +19,7 @@ */ int __op_param1, __op_param2, __op_param3; -int __op_jmp0, __op_jmp1; +int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ static inline void flush_icache_range(unsigned long start, unsigned long stop) -- cgit v1.2.3 From f513a41a3db60c27c25147730e3a2bd6290bf622 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Sep 2003 22:52:47 +0000 Subject: finished simplifying string operations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@379 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 13 ++++++-- op_string.h | 94 ---------------------------------------------------------- ops_template.h | 71 +++++++++++++++++++++++++------------------- 3 files changed, 52 insertions(+), 126 deletions(-) delete mode 100644 op_string.h diff --git a/op-i386.c b/op-i386.c index 2f84e15e5..16521c93b 100644 --- a/op-i386.c +++ b/op-i386.c @@ -516,9 +516,9 @@ void OPPROTO op_cmpxchg8b(void) helper_cmpxchg8b(); } -void OPPROTO op_jmp_tb_next(void) +void OPPROTO op_jmp(void) { - JUMP_TB(op_jmp_tb_next, PARAM1, 0, PARAM2); + JUMP_TB(op_jmp, PARAM1, 0, PARAM2); } void OPPROTO op_movl_T0_0(void) @@ -1033,6 +1033,15 @@ void OPPROTO op_jcc(void) FORCE_RET(); } +void OPPROTO op_jcc_im(void) +{ + if (T0) + EIP = PARAM1; + else + EIP = PARAM2; + FORCE_RET(); +} + /* slow set cases (compute x86 flags) */ void OPPROTO op_seto_T0_cc(void) { diff --git a/op_string.h b/op_string.h deleted file mode 100644 index 66b598b23..000000000 --- a/op_string.h +++ /dev/null @@ -1,94 +0,0 @@ - -void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void) -{ - int v1, v2, inc; - - if (CX != 0) { - /* NOTE: the flags are not modified if CX == 0 */ - v1 = EAX & DATA_MASK; - inc = (DF << SHIFT); - do { - v2 = glue(ldu, SUFFIX)(DI_ADDR); - INC_DI(); - DEC_CX(); - if (v1 != v2) - break; - } while (CX != 0); - CC_SRC = v2; - CC_DST = v1 - v2; - CC_OP = CC_OP_SUBB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void) -{ - int v1, v2, inc; - - if (CX != 0) { - /* NOTE: the flags are not modified if CX == 0 */ - v1 = EAX & DATA_MASK; - inc = (DF << SHIFT); - do { - v2 = glue(ldu, SUFFIX)(DI_ADDR); - INC_DI(); - DEC_CX(); - if (v1 == v2) - break; - } while (CX != 0); - CC_SRC = v2; - CC_DST = v1 - v2; - CC_OP = CC_OP_SUBB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void) -{ - int v1, v2, inc; - if (CX != 0) { - inc = (DF << SHIFT); - do { - v1 = glue(ldu, SUFFIX)(SI_ADDR); - v2 = glue(ldu, SUFFIX)(DI_ADDR); - INC_SI(); - INC_DI(); - DEC_CX(); - if (v1 != v2) - break; - } while (CX != 0); - CC_SRC = v2; - CC_DST = v1 - v2; - CC_OP = CC_OP_SUBB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void) -{ - int v1, v2, inc; - if (CX != 0) { - inc = (DF << SHIFT); - do { - v1 = glue(ldu, SUFFIX)(SI_ADDR); - v2 = glue(ldu, SUFFIX)(DI_ADDR); - INC_SI(); - INC_DI(); - DEC_CX(); - if (v1 == v2) - break; - } while (CX != 0); - CC_SRC = v2; - CC_DST = v1 - v2; - CC_OP = CC_OP_SUBB + SHIFT; - } - FORCE_RET(); -} - -#undef STRING_SUFFIX -#undef SI_ADDR -#undef DI_ADDR -#undef INC_SI -#undef INC_DI -#undef CX -#undef DEC_CX diff --git a/ops_template.h b/ops_template.h index b55ccf9db..182296743 100644 --- a/ops_template.h +++ b/ops_template.h @@ -518,34 +518,6 @@ void OPPROTO op_update_bt_cc(void) #endif /* string operations */ -/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */ - -#define STRING_SUFFIX _fast -#define SI_ADDR (void *)ESI -#define DI_ADDR (void *)EDI -#define INC_SI() ESI += inc -#define INC_DI() EDI += inc -#define CX ECX -#define DEC_CX() ECX-- -#include "op_string.h" - -#define STRING_SUFFIX _a32 -#define SI_ADDR (uint8_t *)A0 + ESI -#define DI_ADDR env->segs[R_ES].base + EDI -#define INC_SI() ESI += inc -#define INC_DI() EDI += inc -#define CX ECX -#define DEC_CX() ECX-- -#include "op_string.h" - -#define STRING_SUFFIX _a16 -#define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff) -#define DI_ADDR env->segs[R_ES].base + (EDI & 0xffff) -#define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff) -#define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff) -#define CX (ECX & 0xffff) -#define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff) -#include "op_string.h" void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) { @@ -555,14 +527,40 @@ void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST == 0) - JUMP_TB(glue(op_string_jz_sub, SUFFIX), PARAM1, 1, PARAM2); + JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 1); FORCE_RET(); } void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST != 0) - JUMP_TB(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1, PARAM2); + JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1); + FORCE_RET(); +} + +void OPPROTO glue(glue(op_string_jz_sub, SUFFIX), _im)(void) +{ + if ((DATA_TYPE)CC_DST == 0) { + EIP = PARAM1; + if (env->eflags & TF_MASK) { + raise_exception(EXCP01_SSTP); + } + T0 = 0; + EXIT_TB(); + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_string_jnz_sub, SUFFIX), _im)(void) +{ + if ((DATA_TYPE)CC_DST != 0) { + EIP = PARAM1; + if (env->eflags & TF_MASK) { + raise_exception(EXCP01_SSTP); + } + T0 = 0; + EXIT_TB(); + } FORCE_RET(); } @@ -573,6 +571,19 @@ void OPPROTO glue(op_jz_ecx, SUFFIX)(void) JUMP_TB(glue(op_jz_ecx, SUFFIX), PARAM1, 1, PARAM2); FORCE_RET(); } + +void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void) +{ + if ((DATA_TYPE)ECX == 0) { + EIP = PARAM1; + if (env->eflags & TF_MASK) { + raise_exception(EXCP01_SSTP); + } + T0 = 0; + EXIT_TB(); + } + FORCE_RET(); +} #endif /* port I/O */ -- cgit v1.2.3 From 4cbb86e1c45acbad785490679e922344d5f144bf Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Sep 2003 22:53:29 +0000 Subject: added JUMP_TB2 for a third basic block exit jump point git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@380 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.h | 35 +++++++++++++++++++++++++++-------- translate.c | 5 +++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/exec.h b/exec.h index b63a66f51..070a162f3 100644 --- a/exec.h +++ b/exec.h @@ -108,7 +108,7 @@ typedef struct TranslationBlock { the code of this one. */ uint16_t tb_next_offset[2]; /* offset of original jump target */ #ifdef USE_DIRECT_JUMP - uint16_t tb_jmp_offset[2]; /* offset of jump instruction */ + uint16_t tb_jmp_offset[4]; /* offset of jump instruction */ #else uint32_t tb_next[2]; /* address of jump generated code */ #endif @@ -160,18 +160,14 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, #if defined(__powerpc__) -static inline void tb_set_jmp_target(TranslationBlock *tb, - int n, unsigned long addr) +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { uint32_t val, *ptr; - unsigned long offset; - - offset = (unsigned long)(tb->tc_ptr + tb->tb_jmp_offset[n]); /* patch the branch destination */ - ptr = (uint32_t *)offset; + ptr = (uint32_t *)jmp_addr; val = *ptr; - val = (val & ~0x03fffffc) | ((addr - offset) & 0x03fffffc); + val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc); *ptr = val; /* flush icache */ asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory"); @@ -181,6 +177,18 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, asm volatile ("isync" : : : "memory"); } +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + unsigned long offset; + + offset = tb->tb_jmp_offset[n]; + tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); + offset = tb->tb_jmp_offset[n + 2]; + if (offset != 0xffff) + tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); +} + #else /* set the jump target */ @@ -228,6 +236,11 @@ do {\ EXIT_TB();\ } while (0) +#define JUMP_TB2(opname, tbparam, n)\ +do {\ + asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\ +} while (0) + #else /* jump to next block operations (more portable code, does not need @@ -244,6 +257,12 @@ dummy_label ## n:\ EXIT_TB();\ } while (0) +/* second jump to same destination 'n' */ +#define JUMP_TB2(opname, tbparam, n)\ +do {\ + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ +} while (0) + #endif /* physical memory access */ diff --git a/translate.c b/translate.c index e9055c0dd..c9bca64db 100644 --- a/translate.c +++ b/translate.c @@ -120,6 +120,11 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, tb->tb_next_offset[0] = 0xffff; tb->tb_next_offset[1] = 0xffff; gen_code_buf = tb->tc_ptr; +#ifdef USE_DIRECT_JUMP + /* the following two entries are optional (only used for string ops) */ + tb->tb_jmp_offset[2] = 0xffff; + tb->tb_jmp_offset[3] = 0xffff; +#endif gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, #ifdef USE_DIRECT_JUMP tb->tb_jmp_offset, -- cgit v1.2.3 From dbc5594cb6294f34c257df11bef484e45493f85e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Sep 2003 22:56:30 +0000 Subject: finished simplifying string operations - correct TF flag handling for string operations and ss loading - simplified basic block exit code generation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@381 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 543 +++++++++++++++++++++++++------------------------------ 1 file changed, 247 insertions(+), 296 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index fd13adbe4..b732178cd 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -60,11 +60,15 @@ typedef struct DisasContext { int cpl; int iopl; int tf; /* TF cpu flag */ + int jmp_opt; /* use direct block chaining for direct jumps */ int mem_index; /* select memory access functions */ struct TranslationBlock *tb; int popl_esp_hack; /* for correct popl with esp base handling */ } DisasContext; +static void gen_eob(DisasContext *s); +static void gen_jmp(DisasContext *s, unsigned int eip); + /* i386 arith/logic operations */ enum { OP_ADDL, @@ -635,31 +639,6 @@ static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { gen_op_stl_user_T0_A0, }; -/* the _a32 and _a16 string operations use A0 as the base register. */ - -#define STRINGOP_NB 9 - -#define STRINGOP(x) \ - gen_op_ ## x ## b_fast, \ - gen_op_ ## x ## w_fast, \ - gen_op_ ## x ## l_fast, \ - gen_op_ ## x ## b_a32, \ - gen_op_ ## x ## w_a32, \ - gen_op_ ## x ## l_a32, \ - gen_op_ ## x ## b_a16, \ - gen_op_ ## x ## w_a16, \ - gen_op_ ## x ## l_a16, - -static GenOpFunc *gen_op_scas[STRINGOP_NB * 3] = { - STRINGOP(repz_scas) - STRINGOP(repnz_scas) -}; - -static GenOpFunc *gen_op_cmps[STRINGOP_NB * 3] = { - STRINGOP(repz_cmps) - STRINGOP(repnz_cmps) -}; - static inline void gen_string_movl_A0_ESI(DisasContext *s) { int override; @@ -712,12 +691,17 @@ static GenOpFunc2 *gen_op_jz_ecx[2] = { gen_op_jz_ecxl, }; +static GenOpFunc1 *gen_op_jz_ecx_im[2] = { + gen_op_jz_ecxw_im, + gen_op_jz_ecxl_im, +}; + static GenOpFunc *gen_op_dec_ECX[2] = { gen_op_decw_ECX, gen_op_decl_ECX, }; -static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = { +static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = { { gen_op_string_jnz_subb, gen_op_string_jnz_subw, @@ -730,6 +714,19 @@ static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = { }, }; +static GenOpFunc1 *gen_op_string_jnz_sub_im[2][3] = { + { + gen_op_string_jnz_subb_im, + gen_op_string_jnz_subw_im, + gen_op_string_jnz_subl_im, + }, + { + gen_op_string_jz_subb_im, + gen_op_string_jz_subw_im, + gen_op_string_jz_subl_im, + }, +}; + static GenOpFunc *gen_op_in_DX_T0[3] = { gen_op_inb_DX_T0, gen_op_inw_DX_T0, @@ -758,18 +755,23 @@ static inline void gen_movs(DisasContext *s, int ot) } } -/* same method as Valgrind : we generate jumps to current or next - instruction */ -static inline void gen_repz_movs(DisasContext *s, int ot, - unsigned int cur_eip, unsigned int next_eip) +static inline void gen_update_cc_op(DisasContext *s) { - if (s->cc_op != CC_OP_DYNAMIC) + if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); - gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); - gen_movs(s, ot); - gen_op_dec_ECX[s->aflag](); - gen_op_jmp_tb_next((long)s->tb, cur_eip); - s->is_jmp = 3; + s->cc_op = CC_OP_DYNAMIC; + } +} + +static inline void gen_jz_ecx_string(DisasContext *s, unsigned int next_eip) +{ + if (s->jmp_opt) { + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + } else { + /* XXX: does not work with gdbstub "ice" single step - not a + serious problem */ + gen_op_jz_ecx_im[s->aflag](next_eip); + } } static inline void gen_stos(DisasContext *s, int ot) @@ -785,18 +787,6 @@ static inline void gen_stos(DisasContext *s, int ot) } } -static inline void gen_repz_stos(DisasContext *s, int ot, - unsigned int cur_eip, unsigned int next_eip) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); - gen_stos(s, ot); - gen_op_dec_ECX[s->aflag](); - gen_op_jmp_tb_next((long)s->tb, cur_eip); - s->is_jmp = 3; -} - static inline void gen_lods(DisasContext *s, int ot) { gen_string_movl_A0_ESI(s); @@ -810,18 +800,6 @@ static inline void gen_lods(DisasContext *s, int ot) } } -static inline void gen_repz_lods(DisasContext *s, int ot, - unsigned int cur_eip, unsigned int next_eip) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); - gen_lods(s, ot); - gen_op_dec_ECX[s->aflag](); - gen_op_jmp_tb_next((long)s->tb, cur_eip); - s->is_jmp = 3; -} - static inline void gen_scas(DisasContext *s, int ot) { gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); @@ -836,23 +814,6 @@ static inline void gen_scas(DisasContext *s, int ot) } } -#if 0 -static inline void gen_repz_scas(DisasContext *s, int ot, - unsigned int cur_eip, unsigned int next_eip, - int nz) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); - gen_scas(s, ot); - gen_op_set_cc_op(CC_OP_SUBB + ot); - gen_op_string_jnz_sub[nz][ot]((long)s->tb, next_eip); - gen_op_dec_ECX[s->aflag](); - gen_op_jmp_tb_next((long)s->tb, cur_eip); - s->is_jmp = 3; -} -#endif - static inline void gen_cmps(DisasContext *s, int ot) { gen_string_movl_A0_ESI(s); @@ -883,18 +844,6 @@ static inline void gen_ins(DisasContext *s, int ot) } } -static inline void gen_repz_ins(DisasContext *s, int ot, - unsigned int cur_eip, unsigned int next_eip) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); - gen_ins(s, ot); - gen_op_dec_ECX[s->aflag](); - gen_op_jmp_tb_next((long)s->tb, cur_eip); - s->is_jmp = 3; -} - static inline void gen_outs(DisasContext *s, int ot) { gen_string_movl_A0_ESI(s); @@ -908,59 +857,50 @@ static inline void gen_outs(DisasContext *s, int ot) } } -static inline void gen_repz_outs(DisasContext *s, int ot, - unsigned int cur_eip, unsigned int next_eip) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); - gen_outs(s, ot); - gen_op_dec_ECX[s->aflag](); - gen_op_jmp_tb_next((long)s->tb, cur_eip); - s->is_jmp = 3; +/* same method as Valgrind : we generate jumps to current or next + instruction */ +#define GEN_REPZ(op) \ +static inline void gen_repz_ ## op(DisasContext *s, int ot, \ + unsigned int cur_eip, unsigned int next_eip) \ +{ \ + gen_update_cc_op(s); \ + gen_jz_ecx_string(s, next_eip); \ + gen_ ## op(s, ot); \ + gen_op_dec_ECX[s->aflag](); \ + /* a loop would cause two single step exceptions if ECX = 1 \ + before rep string_insn */ \ + if (!s->jmp_opt) \ + gen_op_jz_ecx_im[s->aflag](next_eip); \ + gen_jmp(s, cur_eip); \ } -static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) -{ - int index, override; - - override = s->override; - if (s->aflag) { - /* 32 bit address */ - if (s->addseg && override < 0) - override = R_DS; - if (override >= 0) { - gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); - index = 3 + ot; - } else { - index = ot; - } - } else { - if (override < 0) - override = R_DS; - gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); - /* 16 address, always override */ - index = 6 + ot; - } - func[index](); -} - -static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func) -{ - int index; - - if (s->aflag) { - if (s->addseg) { - index = 3 + ot; - } else { - index = ot; - } - } else { - index = 6 + ot; - } - func[index](); +#define GEN_REPZ2(op) \ +static inline void gen_repz_ ## op(DisasContext *s, int ot, \ + unsigned int cur_eip, \ + unsigned int next_eip, \ + int nz) \ +{ \ + gen_update_cc_op(s); \ + gen_jz_ecx_string(s, next_eip); \ + gen_ ## op(s, ot); \ + gen_op_dec_ECX[s->aflag](); \ + gen_op_set_cc_op(CC_OP_SUBB + ot); \ + if (!s->jmp_opt) \ + gen_op_string_jnz_sub_im[nz][ot](next_eip); \ + else \ + gen_op_string_jnz_sub[nz][ot]((long)s->tb); \ + if (!s->jmp_opt) \ + gen_op_jz_ecx_im[s->aflag](next_eip); \ + gen_jmp(s, cur_eip); \ } +GEN_REPZ(movs) +GEN_REPZ(stos) +GEN_REPZ(lods) +GEN_REPZ(ins) +GEN_REPZ(outs) +GEN_REPZ2(scas) +GEN_REPZ2(cmps) static GenOpFunc *gen_op_in[3] = { gen_op_inb_T0_T1, @@ -1420,71 +1360,86 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) inv = b & 1; jcc_op = (b >> 1) & 7; - switch(s->cc_op) { - /* we optimize the cmp/jcc case */ - case CC_OP_SUBB: - case CC_OP_SUBW: - case CC_OP_SUBL: - func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; - break; - - /* some jumps are easy to compute */ - case CC_OP_ADDB: - case CC_OP_ADDW: - case CC_OP_ADDL: - case CC_OP_ADCB: - case CC_OP_ADCW: - case CC_OP_ADCL: - case CC_OP_SBBB: - case CC_OP_SBBW: - case CC_OP_SBBL: - case CC_OP_LOGICB: - case CC_OP_LOGICW: - case CC_OP_LOGICL: - case CC_OP_INCB: - case CC_OP_INCW: - case CC_OP_INCL: - case CC_OP_DECB: - case CC_OP_DECW: - case CC_OP_DECL: - case CC_OP_SHLB: - case CC_OP_SHLW: - case CC_OP_SHLL: - case CC_OP_SARB: - case CC_OP_SARW: - case CC_OP_SARL: - switch(jcc_op) { - case JCC_Z: - func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + + if (s->jmp_opt) { + switch(s->cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; break; - case JCC_S: - func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_ADCB: + case CC_OP_ADCW: + case CC_OP_ADCL: + case CC_OP_SBBB: + case CC_OP_SBBW: + case CC_OP_SBBL: + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + case CC_OP_SARB: + case CC_OP_SARW: + case CC_OP_SARL: + switch(jcc_op) { + case JCC_Z: + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + case JCC_S: + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + default: + func = NULL; + break; + } break; default: func = NULL; break; } - break; - default: - func = NULL; - break; - } - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); - if (!func) { - gen_setcc_slow[jcc_op](); - func = gen_op_jcc; - } + if (!func) { + gen_setcc_slow[jcc_op](); + func = gen_op_jcc; + } - tb = s->tb; - if (!inv) { - func((long)tb, val, next_eip); + tb = s->tb; + if (!inv) { + func((long)tb, val, next_eip); + } else { + func((long)tb, next_eip, val); + } + s->is_jmp = 3; } else { - func((long)tb, next_eip, val); + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_setcc_slow[jcc_op](); + if (!inv) { + gen_op_jcc_im(val, next_eip); + } else { + gen_op_jcc_im(next_eip, val); + } + gen_eob(s); } - s->is_jmp = 3; } static void gen_setcc(DisasContext *s, int b) @@ -1557,7 +1512,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) stop as a special handling must be done to disable hardware interrupts for the next instruction */ if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) - s->is_jmp = 2; + s->is_jmp = 3; } /* generate a push. It depends on ss32, addseg and dflag */ @@ -1727,7 +1682,7 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) gen_op_set_cc_op(s->cc_op); gen_op_jmp_im(cur_eip); gen_op_raise_exception(trapno); - s->is_jmp = 1; + s->is_jmp = 3; } /* an interrupt is different from an exception because of the @@ -1739,7 +1694,7 @@ static void gen_interrupt(DisasContext *s, int intno, gen_op_set_cc_op(s->cc_op); gen_op_jmp_im(cur_eip); gen_op_raise_interrupt(intno, next_eip); - s->is_jmp = 1; + s->is_jmp = 3; } static void gen_debug(DisasContext *s, unsigned int cur_eip) @@ -1748,7 +1703,22 @@ static void gen_debug(DisasContext *s, unsigned int cur_eip) gen_op_set_cc_op(s->cc_op); gen_op_jmp_im(cur_eip); gen_op_debug(); - s->is_jmp = 1; + s->is_jmp = 3; +} + +/* generate a generic end of block. Trace exception is also generated + if needed */ +static void gen_eob(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (s->tf) { + gen_op_raise_exception(EXCP01_SSTP); + } else { + gen_op_movl_T0_0(); + gen_op_exit_tb(); + } + s->is_jmp = 3; } /* generate a jump to eip. No segment change must happen before as a @@ -1757,16 +1727,20 @@ static void gen_jmp(DisasContext *s, unsigned int eip) { TranslationBlock *tb = s->tb; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_tb_next((long)tb, eip); - s->is_jmp = 3; + if (s->jmp_opt) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp((long)tb, eip); + s->is_jmp = 3; + } else { + gen_op_jmp_im(eip); + gen_eob(s); + } } -/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr - is set to true if the instruction sets the PC (last instruction of - a basic block) */ -long disas_insn(DisasContext *s, uint8_t *pc_start) +/* convert one instruction. s->is_jmp is set if the translation must + be stopped. Return the next pc value */ +static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) { int b, prefixes, aflag, dflag; int shift, ot; @@ -2106,9 +2080,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) next_eip = s->pc - s->cs_base; gen_op_movl_T0_im(next_eip); gen_push_T0(s); - s->is_jmp = 1; + gen_eob(s); break; - case 3: /* lcall Ev */ + case 3: /*< lcall Ev */ gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); gen_op_ld_T0_A0[OT_WORD + s->mem_index](); @@ -2121,13 +2095,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); } - s->is_jmp = 1; + gen_eob(s); break; case 4: /* jmp Ev */ if (s->dflag == 0) gen_op_andl_T0_ffff(); gen_op_jmp_T0(); - s->is_jmp = 1; + gen_eob(s); break; case 5: /* ljmp Ev */ gen_op_ld_T1_A0[ot + s->mem_index](); @@ -2144,7 +2118,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_movl_T0_T1(); gen_op_jmp_T0(); } - s->is_jmp = 1; + gen_eob(s); break; case 6: /* push Ev */ gen_push_T0(s); @@ -2366,6 +2340,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (reg == R_SS) { /* if reg == SS, inhibit interrupts/trace */ gen_op_set_inhibit_irq(); + s->tf = 0; + } + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } break; case 0x1a1: /* pop fs */ @@ -2373,6 +2352,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_pop_T0(s); gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); gen_pop_update(s); + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } break; /**************************/ @@ -2428,6 +2411,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (reg == R_SS) { /* if reg == SS, inhibit interrupts/trace */ gen_op_set_inhibit_irq(); + s->tf = 0; + } + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } break; case 0x8c: /* mov Gv, seg */ @@ -2635,6 +2623,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_movl_seg_T0(s, op, pc_start - s->cs_base); /* then put the data */ gen_op_mov_reg_T1[ot][reg](); + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } break; /************************/ @@ -3191,15 +3183,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPNZ) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_string_es(s, ot, gen_op_scas + STRINGOP_NB); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); } else if (prefixes & PREFIX_REPZ) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_string_es(s, ot, gen_op_scas); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); } else { gen_scas(s, ot); s->cc_op = CC_OP_SUBB + ot; @@ -3213,15 +3199,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPNZ) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_string_ds(s, ot, gen_op_cmps + STRINGOP_NB); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); } else if (prefixes & PREFIX_REPZ) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_string_ds(s, ot, gen_op_cmps); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); } else { gen_cmps(s, ot); s->cc_op = CC_OP_SUBB + ot; @@ -3333,7 +3313,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->dflag == 0) gen_op_andl_T0_ffff(); gen_op_jmp_T0(); - s->is_jmp = 1; + gen_eob(s); break; case 0xc3: /* ret */ gen_pop_T0(s); @@ -3341,7 +3321,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->dflag == 0) gen_op_andl_T0_ffff(); gen_op_jmp_T0(); - s->is_jmp = 1; + gen_eob(s); break; case 0xca: /* lret im */ val = ldsw(s->pc); @@ -3368,7 +3348,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* add stack offset */ gen_stack_update(s, val + (4 << s->dflag)); } - s->is_jmp = 1; + gen_eob(s); break; case 0xcb: /* lret */ val = 0; @@ -3387,7 +3367,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_iret_protected(s->dflag); s->cc_op = CC_OP_EFLAGS; } - s->is_jmp = 1; + gen_eob(s); break; case 0xe8: /* call im */ { @@ -3512,7 +3492,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) } gen_pop_update(s); s->cc_op = CC_OP_EFLAGS; - s->is_jmp = 2; /* abort translation because TF flag may change */ + /* abort translation because TF flag may change */ + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } break; case 0x9e: /* sahf */ @@ -3713,19 +3695,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xfb: /* sti */ if (!s->vm86) { if (s->cpl <= s->iopl) { + gen_sti: gen_op_sti(); /* interruptions are enabled only the first insn after sti */ gen_op_set_inhibit_irq(); - s->is_jmp = 2; /* give a chance to handle pending irqs */ + /* give a chance to handle pending irqs */ + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { - gen_op_sti(); - /* interruptions are enabled only the first insn after sti */ - gen_op_set_inhibit_irq(); - s->is_jmp = 2; /* give a chance to handle pending irqs */ + goto gen_sti; } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } @@ -3769,7 +3751,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->dflag == 0) val &= 0xffff; gen_op_loop[s->aflag][b & 3](val, next_eip); - s->is_jmp = 1; + gen_eob(s); break; case 0x130: /* wrmsr */ case 0x132: /* rdmsr */ @@ -3796,7 +3778,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_set_cc_op(s->cc_op); gen_op_jmp_im(s->pc - s->cs_base); gen_op_hlt(); - s->is_jmp = 1; + s->is_jmp = 3; } break; case 0x100: @@ -3968,7 +3950,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (b & 2) { gen_op_mov_TN_reg[OT_LONG][0][rm](); gen_op_movl_crN_T0(reg); - s->is_jmp = 2; + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } else { gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); gen_op_mov_reg_T0[OT_LONG][rm](); @@ -3995,7 +3978,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (b & 2) { gen_op_mov_TN_reg[OT_LONG][0][rm](); gen_op_movl_drN_T0(reg); - s->is_jmp = 2; + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } else { gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); gen_op_mov_reg_T0[OT_LONG][rm](); @@ -4015,10 +3999,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* lock generation */ if (s->prefix & PREFIX_LOCK) gen_op_unlock(); - return (long)s->pc; + return s->pc; illegal_op: /* XXX: ensure that no lock was generated */ - return -1; + gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); + return s->pc; } #define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) @@ -4265,23 +4250,6 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, -#undef STRINGOP -#define STRINGOP(x) \ - [INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \ - [INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \ - [INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \ - [INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \ - [INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \ - [INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \ - [INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \ - [INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ - [INDEX_op_ ## x ## l_a16] = CC_OSZAPC, - - STRINGOP(repz_scas) - STRINGOP(repnz_scas) - STRINGOP(repz_cmps) - STRINGOP(repnz_cmps) - [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, @@ -4383,7 +4351,6 @@ static inline int gen_intermediate_code_internal(CPUState *env, uint8_t *pc_ptr; uint16_t *gen_opc_end; int flags, j, lj; - long ret; uint8_t *pc_start; uint8_t *cs_base; @@ -4413,7 +4380,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, else dc->mem_index = 3; } - + dc->jmp_opt = !(dc->tf || env->singlestep_enabled +#ifndef CONFIG_SOFT_MMU + || (flags & HF_SOFTMMU_MASK) +#endif + ); gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; @@ -4428,12 +4399,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, if (flags & HF_INHIBIT_IRQ_MASK) { gen_op_reset_inhibit_irq(); } - do { + for(;;) { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == (unsigned long)pc_ptr) { gen_debug(dc, pc_ptr - dc->cs_base); - goto the_end; + break; } } } @@ -4448,44 +4419,24 @@ static inline int gen_intermediate_code_internal(CPUState *env, gen_opc_cc_op[lj] = dc->cc_op; gen_opc_instr_start[lj] = 1; } - ret = disas_insn(dc, pc_ptr); - if (ret == -1) { - /* we trigger an illegal instruction operation only if it - is the first instruction. Otherwise, we simply stop - generating the code just before it */ - if (pc_ptr == pc_start) - return -1; - else - break; - } - pc_ptr = (void *)ret; + pc_ptr = disas_insn(dc, pc_ptr); + /* stop translation if indicated */ + if (dc->is_jmp) + break; /* if single step mode, we generate only one instruction and generate an exception */ - if (dc->tf) + if (dc->tf) { + gen_op_jmp_im(pc_ptr - dc->cs_base); + gen_eob(dc); + break; + } + /* if too long translation, stop generation too */ + if (gen_opc_ptr >= gen_opc_end || + (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + gen_op_jmp_im(pc_ptr - dc->cs_base); + gen_eob(dc); break; - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && - (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); - if (!dc->tf && dc->is_jmp == DISAS_NEXT) { - gen_jmp(dc, ret - (unsigned long)dc->cs_base); - } - - /* we must store the eflags state if it is not already done */ - if (dc->is_jmp != DISAS_TB_JUMP) { - if (dc->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(dc->cc_op); - if (dc->is_jmp != DISAS_JUMP) { - /* we add an additionnal jmp to update the simulated PC */ - gen_op_jmp_im(ret - (unsigned long)dc->cs_base); } - } - if (dc->tf) { - gen_op_raise_exception(EXCP01_SSTP); - } - the_end: - if (dc->is_jmp != DISAS_TB_JUMP) { - /* indicate that the hash table must be used to find the next TB */ - gen_op_movl_T0_0(); - gen_op_exit_tb(); } *gen_opc_ptr = INDEX_op_end; /* we don't forget to fill the last values */ -- cgit v1.2.3 From fcf8fcc8e5988404fe40082d43419ef9ff30642f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Sep 2003 22:56:56 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@382 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ VERSION | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 1830de559..4dfbeed10 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,9 @@ version 0.4.4: - 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 version 0.4.3: diff --git a/VERSION b/VERSION index 70d5b25fa..b300caa32 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.3 \ No newline at end of file +0.4.4 \ No newline at end of file -- cgit v1.2.3 From b7dda06abfd13ef42bfc93b71e5be6bc0025b94a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Sep 2003 22:57:56 +0000 Subject: Redhat 9 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@383 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- Makefile.target | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1ecf99c94..28b08cade 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,7 @@ vl.c i386-vl.ld vl.h block.c vlmkcow.c vga.c vga_template.h sdl.c \ thunk.c cpu-exec.c translate.c cpu-all.h cpu-defs.h thunk.h exec.h\ exec.c cpu-exec.c gdbstub.c bswap.h \ cpu-i386.h op-i386.c helper-i386.c helper2-i386.c syscall-i386.h translate-i386.c \ -exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \ +exec-i386.h ops_template.h ops_template_mem.h opreg_template.h \ ops_mem.h softmmu_template.h softmmu_header.h \ cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \ dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \ @@ -84,7 +84,7 @@ FILE=qemu-$(VERSION) tar: rm -rf /tmp/$(FILE) mkdir -p /tmp/$(FILE) - cp -P $(FILES) /tmp/$(FILE) + cp --parent $(FILES) /tmp/$(FILE) ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) ) rm -rf /tmp/$(FILE) diff --git a/Makefile.target b/Makefile.target index 27c79e8ca..712869351 100644 --- a/Makefile.target +++ b/Makefile.target @@ -153,7 +153,7 @@ endif VL_OBJS=vl.o block.o vga.o ifdef CONFIG_SDL VL_OBJS+=sdl.o -SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl +SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm endif vl: $(VL_OBJS) libqemu.a -- cgit v1.2.3 From 196ad10903ee4c2148f296600f537d7028ea845d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 28 Sep 2003 18:59:32 +0000 Subject: portable Linux test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@384 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/linux-test.c | 510 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100644 tests/linux-test.c diff --git a/tests/linux-test.c b/tests/linux-test.c new file mode 100644 index 000000000..3ced0dd69 --- /dev/null +++ b/tests/linux-test.c @@ -0,0 +1,510 @@ +/* + * linux and CPU test + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TESTPATH "/tmp/linux-test.tmp" +#define TESTPORT 7654 +#define STACK_SIZE 16384 + +void error1(const char *filename, int line, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d: ", filename, line); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + +int __chk_error(const char *filename, int line, int ret) +{ + if (ret < 0) { + error1(filename, line, "%m (ret=%d, errno=%d)", + ret, errno); + } + return ret; +} + +#define error(fmt, args...) error1(__FILE__, __LINE__, fmt, ##args) + +#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) + +/*******************************************************/ + +#define FILE_BUF_SIZE 300 + +void file_test(void) +{ + int fd, i, len, ret; + uint8_t buf[FILE_BUF_SIZE]; + uint8_t buf2[FILE_BUF_SIZE]; + uint8_t buf3[FILE_BUF_SIZE]; + char cur_dir[1024]; + struct stat st; + struct utimbuf tbuf; + struct iovec vecs[2]; + DIR *dir; + struct dirent *de; + + /* clean up, just in case */ + unlink(TESTPATH "/file1"); + unlink(TESTPATH "/file2"); + unlink(TESTPATH "/file3"); + rmdir(TESTPATH); + + if (getcwd(cur_dir, sizeof(cur_dir)) == NULL) + error("getcwd"); + + chk_error(mkdir(TESTPATH, 0755)); + + chk_error(chdir(TESTPATH)); + + /* open/read/write/close/readv/writev/lseek */ + + fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644)); + for(i=0;i < FILE_BUF_SIZE; i++) + buf[i] = i; + len = chk_error(write(fd, buf, FILE_BUF_SIZE / 2)); + if (len != (FILE_BUF_SIZE / 2)) + error("write"); + vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2); + vecs[0].iov_len = 16; + vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16; + vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16; + len = chk_error(writev(fd, vecs, 2)); + if (len != (FILE_BUF_SIZE / 2)) + error("writev"); + chk_error(close(fd)); + + chk_error(rename("file1", "file2")); + + fd = chk_error(open("file2", O_RDONLY)); + + len = chk_error(read(fd, buf2, FILE_BUF_SIZE)); + if (len != FILE_BUF_SIZE) + error("read"); + if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0) + error("memcmp"); + +#define FOFFSET 16 + ret = chk_error(lseek(fd, FOFFSET, SEEK_SET)); + if (ret != 16) + error("lseek"); + vecs[0].iov_base = buf3; + vecs[0].iov_len = 32; + vecs[1].iov_base = buf3 + 32; + vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32; + len = chk_error(readv(fd, vecs, 2)); + if (len != FILE_BUF_SIZE - FOFFSET) + error("readv"); + if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0) + error("memcmp"); + + chk_error(close(fd)); + + /* access */ + chk_error(access("file2", R_OK)); + + /* stat/chmod/utime/truncate */ + + chk_error(chmod("file2", 0600)); + tbuf.actime = 1001; + tbuf.modtime = 1000; + chk_error(truncate("file2", 100)); + chk_error(utime("file2", &tbuf)); + chk_error(stat("file2", &st)); + if (st.st_size != 100) + error("stat size"); + if (!S_ISREG(st.st_mode)) + error("stat mode"); + if ((st.st_mode & 0777) != 0600) + error("stat mode2"); + if (st.st_atime != 1001 || + st.st_mtime != 1000) + error("stat time"); + + chk_error(stat(TESTPATH, &st)); + if (!S_ISDIR(st.st_mode)) + error("stat mode"); + + /* fstat */ + fd = chk_error(open("file2", O_RDWR)); + chk_error(ftruncate(fd, 50)); + chk_error(fstat(fd, &st)); + chk_error(close(fd)); + + if (st.st_size != 50) + error("stat size"); + if (!S_ISREG(st.st_mode)) + error("stat mode"); + + /* symlink/lstat */ + chk_error(symlink("file2", "file3")); + chk_error(lstat("file3", &st)); + if (!S_ISLNK(st.st_mode)) + error("stat mode"); + + /* getdents */ + dir = opendir(TESTPATH); + if (!dir) + error("opendir"); + len = 0; + for(;;) { + de = readdir(dir); + if (!de) + break; + if (strcmp(de->d_name, ".") != 0 && + strcmp(de->d_name, "..") != 0 && + strcmp(de->d_name, "file2") != 0 && + strcmp(de->d_name, "file3") != 0) + error("readdir"); + len++; + } + closedir(dir); + if (len != 4) + error("readdir"); + + chk_error(unlink("file3")); + chk_error(unlink("file2")); + chk_error(chdir(cur_dir)); + chk_error(rmdir(TESTPATH)); +} + +void test_fork(void) +{ + int pid, status; + + pid = chk_error(fork()); + if (pid == 0) { + /* child */ + exit(2); + } + chk_error(waitpid(pid, &status, 0)); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 2) + error("waitpid status=0x%x", status); +} + +void test_time(void) +{ + struct timeval tv, tv2; + struct timespec ts, rem; + struct rusage rusg1, rusg2; + int ti, i; + + chk_error(gettimeofday(&tv, NULL)); + rem.tv_sec = 1; + ts.tv_sec = 0; + ts.tv_nsec = 20 * 1000000; + chk_error(nanosleep(&ts, &rem)); + if (rem.tv_sec != 1) + error("nanosleep"); + chk_error(gettimeofday(&tv2, NULL)); + ti = tv2.tv_sec - tv.tv_sec; + if (ti >= 2) + error("gettimeofday"); + + chk_error(getrusage(RUSAGE_SELF, &rusg1)); + for(i = 0;i < 10000; i++); + chk_error(getrusage(RUSAGE_SELF, &rusg2)); + if ((rusg2.ru_utime.tv_sec - rusg1.ru_utime.tv_sec) < 0 || + (rusg2.ru_stime.tv_sec - rusg1.ru_stime.tv_sec) < 0) + error("getrusage"); +} + +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 server_socket(void) +{ + int val, fd; + struct sockaddr_in sockaddr; + + /* server socket */ + fd = chk_error(socket(PF_INET, SOCK_STREAM, 0)); + + val = 1; + chk_error(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(TESTPORT); + sockaddr.sin_addr.s_addr = 0; + chk_error(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))); + chk_error(listen(fd, 0)); + return fd; + +} + +int client_socket(void) +{ + int fd; + struct sockaddr_in sockaddr; + + /* server socket */ + fd = chk_error(socket(PF_INET, SOCK_STREAM, 0)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(TESTPORT); + inet_aton("127.0.0.1", &sockaddr.sin_addr); + chk_error(connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))); + return fd; +} + +const char socket_msg[] = "hello socket\n"; + +void test_socket(void) +{ + int server_fd, client_fd, fd, pid, ret; + struct sockaddr_in sockaddr; + socklen_t len; + char buf[512]; + + server_fd = server_socket(); + pid = chk_error(fork()); + if (pid == 0) { + client_fd = client_socket(); + send(client_fd, socket_msg, sizeof(socket_msg), 0); + close(client_fd); + exit(0); + } + len = sizeof(sockaddr); + fd = chk_error(accept(server_fd, (struct sockaddr *)&sockaddr, &len)); + + ret = chk_error(recv(fd, buf, sizeof(buf), 0)); + if (ret != sizeof(socket_msg)) + error("recv"); + if (memcmp(buf, socket_msg, sizeof(socket_msg)) != 0) + error("socket_msg"); + chk_error(close(fd)); + chk_error(close(server_fd)); +} + +#define WCOUNT_MAX 512 + +void test_pipe(void) +{ + fd_set rfds, wfds; + int fds[2], fd_max, ret; + uint8_t ch; + int wcount, rcount; + + chk_error(pipe(fds)); + chk_error(fcntl(fds[0], F_SETFL, O_NONBLOCK)); + chk_error(fcntl(fds[1], F_SETFL, O_NONBLOCK)); + wcount = 0; + rcount = 0; + for(;;) { + FD_ZERO(&rfds); + fd_max = fds[0]; + FD_SET(fds[0], &rfds); + + FD_ZERO(&wfds); + FD_SET(fds[1], &wfds); + if (fds[1] > fd_max) + fd_max = fds[1]; + + ret = chk_error(select(fd_max + 1, &rfds, &wfds, NULL, NULL)); + if (ret > 0) { + if (FD_ISSET(fds[0], &rfds)) { + chk_error(read(fds[0], &ch, 1)); + rcount++; + if (rcount >= WCOUNT_MAX) + break; + } + if (FD_ISSET(fds[1], &wfds)) { + ch = 'a'; + chk_error(write(fds[0], &ch, 1)); + wcount++; + } + } + } + chk_error(close(fds[0])); + chk_error(close(fds[1])); +} + +int thread1_res; +int thread2_res; + +int thread1_func(void *arg) +{ + int i; + for(i=0;i<5;i++) { + thread1_res++; + usleep(10 * 1000); + } + return 0; +} + +int thread2_func(void *arg) +{ + int i; + for(i=0;i<6;i++) { + thread2_res++; + usleep(10 * 1000); + } + return 0; +} + +void test_clone(void) +{ + uint8_t *stack1, *stack2; + int pid1, pid2, status1, status2; + + stack1 = malloc(STACK_SIZE); + pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE, + CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1")); + + stack2 = malloc(STACK_SIZE); + pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE, + CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2")); + + while (waitpid(pid1, &status1, 0) != pid1); + while (waitpid(pid2, &status2, 0) != pid2); + if (thread1_res != 5 || + thread2_res != 6) + error("clone"); +} + +/***********************************/ + +volatile int alarm_count; +jmp_buf jmp_env; + +void sig_alarm(int sig) +{ + if (sig != SIGALRM) + error("signal"); + alarm_count++; +} + +void sig_segv(int sig, siginfo_t *info, void *puc) +{ + if (sig != SIGSEGV) + error("signal"); + longjmp(jmp_env, 1); +} + +void test_signal(void) +{ + struct sigaction act; + struct itimerval it, oit; + + /* timer test */ + + alarm_count = 0; + + act.sa_handler = sig_alarm; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + chk_error(sigaction(SIGALRM, &act, NULL)); + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 10 * 1000; + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 10 * 1000; + chk_error(setitimer(ITIMER_REAL, &it, NULL)); + chk_error(getitimer(ITIMER_REAL, &oit)); + if (oit.it_value.tv_sec != it.it_value.tv_sec || + oit.it_value.tv_usec != it.it_value.tv_usec) + error("itimer"); + + while (alarm_count < 5) { + usleep(10 * 1000); + } + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 0; + memset(&oit, 0xff, sizeof(oit)); + chk_error(setitimer(ITIMER_REAL, &it, &oit)); + if (oit.it_value.tv_sec != 0 || + oit.it_value.tv_usec != 10 * 1000) + error("setitimer"); + + /* SIGSEGV test */ + act.sa_sigaction = sig_segv; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + chk_error(sigaction(SIGSEGV, &act, NULL)); + if (setjmp(jmp_env) == 0) { + *(uint8_t *)0 = 0; + } + + act.sa_handler = SIG_DFL; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + chk_error(sigaction(SIGSEGV, &act, NULL)); +} + +int main(int argc, char **argv) +{ + file_test(); + test_fork(); + test_time(); + test_socket(); + test_clone(); + test_signal(); + return 0; +} + -- cgit v1.2.3 From 2c0262afa75d7d6cb68217f9a7587170ed3cd5b3 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 20:34:21 +0000 Subject: new directory structure git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@385 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/syscall.h | 28 + linux-user/arm/syscall_nr.h | 261 +++ linux-user/i386/syscall.h | 220 ++ linux-user/i386/syscall_nr.h | 273 +++ target-arm/cpu.h | 63 + target-arm/exec.h | 40 + target-arm/op.c | 673 ++++++ target-arm/op_template.h | 48 + target-arm/translate.c | 903 ++++++++ target-i386/cpu.h | 401 ++++ target-i386/exec.h | 416 ++++ target-i386/helper.c | 1803 ++++++++++++++++ target-i386/helper2.c | 390 ++++ target-i386/op.c | 2054 ++++++++++++++++++ target-i386/opreg_template.h | 134 ++ target-i386/ops_mem.h | 66 + target-i386/ops_template.h | 617 ++++++ target-i386/ops_template_mem.h | 429 ++++ target-i386/translate.c | 4487 ++++++++++++++++++++++++++++++++++++++++ 19 files changed, 13306 insertions(+) create mode 100644 linux-user/arm/syscall.h create mode 100644 linux-user/arm/syscall_nr.h create mode 100644 linux-user/i386/syscall.h create mode 100644 linux-user/i386/syscall_nr.h create mode 100644 target-arm/cpu.h create mode 100644 target-arm/exec.h create mode 100644 target-arm/op.c create mode 100644 target-arm/op_template.h create mode 100644 target-arm/translate.c create mode 100644 target-i386/cpu.h create mode 100644 target-i386/exec.h create mode 100644 target-i386/helper.c create mode 100644 target-i386/helper2.c create mode 100644 target-i386/op.c create mode 100644 target-i386/opreg_template.h create mode 100644 target-i386/ops_mem.h create mode 100644 target-i386/ops_template.h create mode 100644 target-i386/ops_template_mem.h create mode 100644 target-i386/translate.c diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h new file mode 100644 index 000000000..34153c998 --- /dev/null +++ b/linux-user/arm/syscall.h @@ -0,0 +1,28 @@ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { + target_long uregs[18]; +}; + +#define ARM_cpsr uregs[16] +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[17] + +#define ARM_SYSCALL_BASE 0x900000 diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h new file mode 100644 index 000000000..13a9ee11f --- /dev/null +++ b/linux-user/arm/syscall_nr.h @@ -0,0 +1,261 @@ +/* + * This file contains the system call numbers. + */ + +#define TARGET_NR_restart_syscall ( 0) +#define TARGET_NR_exit ( 1) +#define TARGET_NR_fork ( 2) +#define TARGET_NR_read ( 3) +#define TARGET_NR_write ( 4) +#define TARGET_NR_open ( 5) +#define TARGET_NR_close ( 6) +#define TARGET_NR_waitpid ( 7) /* removed */ +#define TARGET_NR_creat ( 8) +#define TARGET_NR_link ( 9) +#define TARGET_NR_unlink ( 10) +#define TARGET_NR_execve ( 11) +#define TARGET_NR_chdir ( 12) +#define TARGET_NR_time ( 13) +#define TARGET_NR_mknod ( 14) +#define TARGET_NR_chmod ( 15) +#define TARGET_NR_lchown ( 16) +#define TARGET_NR_break ( 17) /* removed */ + /* 18 was sys_stat */ +#define TARGET_NR_lseek ( 19) +#define TARGET_NR_getpid ( 20) +#define TARGET_NR_mount ( 21) +#define TARGET_NR_umount ( 22) +#define TARGET_NR_setuid ( 23) +#define TARGET_NR_getuid ( 24) +#define TARGET_NR_stime ( 25) +#define TARGET_NR_ptrace ( 26) +#define TARGET_NR_alarm ( 27) + +#define TARGET_NR_pause ( 29) +#define TARGET_NR_utime ( 30) +#define TARGET_NR_stty ( 31) /* removed */ +#define TARGET_NR_gtty ( 32) /* removed */ +#define TARGET_NR_access ( 33) +#define TARGET_NR_nice ( 34) +#define TARGET_NR_ftime ( 35) /* removed */ +#define TARGET_NR_sync ( 36) +#define TARGET_NR_kill ( 37) +#define TARGET_NR_rename ( 38) +#define TARGET_NR_mkdir ( 39) +#define TARGET_NR_rmdir ( 40) +#define TARGET_NR_dup ( 41) +#define TARGET_NR_pipe ( 42) +#define TARGET_NR_times ( 43) +#define TARGET_NR_prof ( 44) /* removed */ +#define TARGET_NR_brk ( 45) +#define TARGET_NR_setgid ( 46) +#define TARGET_NR_getgid ( 47) +#define TARGET_NR_signal ( 48) /* removed */ +#define TARGET_NR_geteuid ( 49) +#define TARGET_NR_getegid ( 50) +#define TARGET_NR_acct ( 51) +#define TARGET_NR_umount2 ( 52) +#define TARGET_NR_lock ( 53) /* removed */ +#define TARGET_NR_ioctl ( 54) +#define TARGET_NR_fcntl ( 55) +#define TARGET_NR_mpx ( 56) /* removed */ +#define TARGET_NR_setpgid ( 57) +#define TARGET_NR_ulimit ( 58) /* removed */ + /* 59 was sys_olduname */ +#define TARGET_NR_umask ( 60) +#define TARGET_NR_chroot ( 61) +#define TARGET_NR_ustat ( 62) +#define TARGET_NR_dup2 ( 63) +#define TARGET_NR_getppid ( 64) +#define TARGET_NR_getpgrp ( 65) +#define TARGET_NR_setsid ( 66) +#define TARGET_NR_sigaction ( 67) +#define TARGET_NR_sgetmask ( 68) /* removed */ +#define TARGET_NR_ssetmask ( 69) /* removed */ +#define TARGET_NR_setreuid ( 70) +#define TARGET_NR_setregid ( 71) +#define TARGET_NR_sigsuspend ( 72) +#define TARGET_NR_sigpending ( 73) +#define TARGET_NR_sethostname ( 74) +#define TARGET_NR_setrlimit ( 75) +#define TARGET_NR_getrlimit ( 76) /* Back compat 2GB limited rlimit */ +#define TARGET_NR_getrusage ( 77) +#define TARGET_NR_gettimeofday ( 78) +#define TARGET_NR_settimeofday ( 79) +#define TARGET_NR_getgroups ( 80) +#define TARGET_NR_setgroups ( 81) +#define TARGET_NR_select ( 82) +#define TARGET_NR_symlink ( 83) + /* 84 was sys_lstat */ +#define TARGET_NR_readlink ( 85) +#define TARGET_NR_uselib ( 86) +#define TARGET_NR_swapon ( 87) +#define TARGET_NR_reboot ( 88) +#define TARGET_NR_readdir ( 89) +#define TARGET_NR_mmap ( 90) +#define TARGET_NR_munmap ( 91) +#define TARGET_NR_truncate ( 92) +#define TARGET_NR_ftruncate ( 93) +#define TARGET_NR_fchmod ( 94) +#define TARGET_NR_fchown ( 95) +#define TARGET_NR_getpriority ( 96) +#define TARGET_NR_setpriority ( 97) +#define TARGET_NR_profil ( 98) /* removed */ +#define TARGET_NR_statfs ( 99) +#define TARGET_NR_fstatfs (100) +#define TARGET_NR_ioperm (101) +#define TARGET_NR_socketcall (102) +#define TARGET_NR_syslog (103) +#define TARGET_NR_setitimer (104) +#define TARGET_NR_getitimer (105) +#define TARGET_NR_stat (106) +#define TARGET_NR_lstat (107) +#define TARGET_NR_fstat (108) + /* 109 was sys_uname */ + /* 110 was sys_iopl */ +#define TARGET_NR_vhangup (111) +#define TARGET_NR_idle (112) +#define TARGET_NR_syscall (113) /* syscall to call a syscall! */ +#define TARGET_NR_wait4 (114) +#define TARGET_NR_swapoff (115) +#define TARGET_NR_sysinfo (116) +#define TARGET_NR_ipc (117) +#define TARGET_NR_fsync (118) +#define TARGET_NR_sigreturn (119) +#define TARGET_NR_clone (120) +#define TARGET_NR_setdomainname (121) +#define TARGET_NR_uname (122) +#define TARGET_NR_modify_ldt (123) +#define TARGET_NR_adjtimex (124) +#define TARGET_NR_mprotect (125) +#define TARGET_NR_sigprocmask (126) +#define TARGET_NR_create_module (127) /* removed */ +#define TARGET_NR_init_module (128) +#define TARGET_NR_delete_module (129) +#define TARGET_NR_get_kernel_syms (130) /* removed */ +#define TARGET_NR_quotactl (131) +#define TARGET_NR_getpgid (132) +#define TARGET_NR_fchdir (133) +#define TARGET_NR_bdflush (134) +#define TARGET_NR_sysfs (135) +#define TARGET_NR_personality (136) +#define TARGET_NR_afs_syscall (137) /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid (138) +#define TARGET_NR_setfsgid (139) +#define TARGET_NR__llseek (140) +#define TARGET_NR_getdents (141) +#define TARGET_NR__newselect (142) +#define TARGET_NR_flock (143) +#define TARGET_NR_msync (144) +#define TARGET_NR_readv (145) +#define TARGET_NR_writev (146) +#define TARGET_NR_getsid (147) +#define TARGET_NR_fdatasync (148) +#define TARGET_NR__sysctl (149) +#define TARGET_NR_mlock (150) +#define TARGET_NR_munlock (151) +#define TARGET_NR_mlockall (152) +#define TARGET_NR_munlockall (153) +#define TARGET_NR_sched_setparam (154) +#define TARGET_NR_sched_getparam (155) +#define TARGET_NR_sched_setscheduler (156) +#define TARGET_NR_sched_getscheduler (157) +#define TARGET_NR_sched_yield (158) +#define TARGET_NR_sched_get_priority_max (159) +#define TARGET_NR_sched_get_priority_min (160) +#define TARGET_NR_sched_rr_get_interval (161) +#define TARGET_NR_nanosleep (162) +#define TARGET_NR_mremap (163) +#define TARGET_NR_setresuid (164) +#define TARGET_NR_getresuid (165) +#define TARGET_NR_vm86 (166) /* removed */ +#define TARGET_NR_query_module (167) /* removed */ +#define TARGET_NR_poll (168) +#define TARGET_NR_nfsservctl (169) +#define TARGET_NR_setresgid (170) +#define TARGET_NR_getresgid (171) +#define TARGET_NR_prctl (172) +#define TARGET_NR_rt_sigreturn (173) +#define TARGET_NR_rt_sigaction (174) +#define TARGET_NR_rt_sigprocmask (175) +#define TARGET_NR_rt_sigpending (176) +#define TARGET_NR_rt_sigtimedwait (177) +#define TARGET_NR_rt_sigqueueinfo (178) +#define TARGET_NR_rt_sigsuspend (179) +#define TARGET_NR_pread (180) +#define TARGET_NR_pwrite (181) +#define TARGET_NR_chown (182) +#define TARGET_NR_getcwd (183) +#define TARGET_NR_capget (184) +#define TARGET_NR_capset (185) +#define TARGET_NR_sigaltstack (186) +#define TARGET_NR_sendfile (187) + /* 188 reserved */ + /* 189 reserved */ +#define TARGET_NR_vfork (190) +#define TARGET_NR_ugetrlimit (191) /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 (192) +#define TARGET_NR_truncate64 (193) +#define TARGET_NR_ftruncate64 (194) +#define TARGET_NR_stat64 (195) +#define TARGET_NR_lstat64 (196) +#define TARGET_NR_fstat64 (197) +#define TARGET_NR_lchown32 (198) +#define TARGET_NR_getuid32 (199) +#define TARGET_NR_getgid32 (200) +#define TARGET_NR_geteuid32 (201) +#define TARGET_NR_getegid32 (202) +#define TARGET_NR_setreuid32 (203) +#define TARGET_NR_setregid32 (204) +#define TARGET_NR_getgroups32 (205) +#define TARGET_NR_setgroups32 (206) +#define TARGET_NR_fchown32 (207) +#define TARGET_NR_setresuid32 (208) +#define TARGET_NR_getresuid32 (209) +#define TARGET_NR_setresgid32 (210) +#define TARGET_NR_getresgid32 (211) +#define TARGET_NR_chown32 (212) +#define TARGET_NR_setuid32 (213) +#define TARGET_NR_setgid32 (214) +#define TARGET_NR_setfsuid32 (215) +#define TARGET_NR_setfsgid32 (216) +#define TARGET_NR_getdents64 (217) +#define TARGET_NR_pivot_root (218) +#define TARGET_NR_mincore (219) +#define TARGET_NR_madvise (220) +#define TARGET_NR_fcntl64 (221) + /* 222 for tux */ + /* 223 is unused */ +#define TARGET_NR_gettid (224) +#define TARGET_NR_readahead (225) +#define TARGET_NR_setxattr (226) +#define TARGET_NR_lsetxattr (227) +#define TARGET_NR_fsetxattr (228) +#define TARGET_NR_getxattr (229) +#define TARGET_NR_lgetxattr (230) +#define TARGET_NR_fgetxattr (231) +#define TARGET_NR_listxattr (232) +#define TARGET_NR_llistxattr (233) +#define TARGET_NR_flistxattr (234) +#define TARGET_NR_removexattr (235) +#define TARGET_NR_lremovexattr (236) +#define TARGET_NR_fremovexattr (237) +#define TARGET_NR_tkill (238) +#define TARGET_NR_sendfile64 (239) +#define TARGET_NR_futex (240) +#define TARGET_NR_sched_setaffinity (241) +#define TARGET_NR_sched_getaffinity (242) +#define TARGET_NR_io_setup (243) +#define TARGET_NR_io_destroy (244) +#define TARGET_NR_io_getevents (245) +#define TARGET_NR_io_submit (246) +#define TARGET_NR_io_cancel (247) +#define TARGET_NR_exit_group (248) +#define TARGET_NR_lookup_dcookie (249) +#define TARGET_NR_epoll_create (250) +#define TARGET_NR_epoll_ctl (251) +#define TARGET_NR_epoll_wait (252) +#define TARGET_NR_remap_file_pages (253) + /* 254 for set_thread_area */ + /* 255 for get_thread_area */ + /* 256 for set_tid_address */ diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h new file mode 100644 index 000000000..e1f470d78 --- /dev/null +++ b/linux-user/i386/syscall.h @@ -0,0 +1,220 @@ +/* default linux values for the selectors */ +#define __USER_CS (0x23) +#define __USER_DS (0x2B) + +struct target_pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + int xds; + int xes; + long orig_eax; + long eip; + int xcs; + long eflags; + long esp; + int xss; +}; + +/* ioctls */ + +#define TARGET_LDT_ENTRIES 8192 +#define TARGET_LDT_ENTRY_SIZE 8 + +#define TARGET_GDT_ENTRY_TLS_ENTRIES 3 +#define TARGET_GDT_ENTRY_TLS_MIN 6 +#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1) + +struct target_modify_ldt_ldt_s { + unsigned int entry_number; + target_ulong base_addr; + unsigned int limit; + unsigned int flags; +}; + +/* vm86 defines */ + +#define TARGET_BIOSSEG 0x0f000 + +#define TARGET_CPU_086 0 +#define TARGET_CPU_186 1 +#define TARGET_CPU_286 2 +#define TARGET_CPU_386 3 +#define TARGET_CPU_486 4 +#define TARGET_CPU_586 5 + +#define TARGET_VM86_SIGNAL 0 /* return due to signal */ +#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ +#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */ +#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */ + +/* + * Additional return values when invoking new vm86() + */ +#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */ +#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */ + +/* + * function codes when invoking new vm86() + */ +#define TARGET_VM86_PLUS_INSTALL_CHECK 0 +#define TARGET_VM86_ENTER 1 +#define TARGET_VM86_ENTER_NO_BYPASS 2 +#define TARGET_VM86_REQUEST_IRQ 3 +#define TARGET_VM86_FREE_IRQ 4 +#define TARGET_VM86_GET_IRQ_BITS 5 +#define TARGET_VM86_GET_AND_RESET_IRQ 6 + +/* + * This is the stack-layout seen by the user space program when we have + * done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout + * is 'kernel_vm86_regs' (see below). + */ + +struct target_vm86_regs { +/* + * normal regs, with special meaning for the segment descriptors.. + */ + target_long ebx; + target_long ecx; + target_long edx; + target_long esi; + target_long edi; + target_long ebp; + target_long eax; + target_long __null_ds; + target_long __null_es; + target_long __null_fs; + target_long __null_gs; + target_long orig_eax; + target_long eip; + unsigned short cs, __csh; + target_long eflags; + target_long esp; + unsigned short ss, __ssh; +/* + * these are specific to v86 mode: + */ + unsigned short es, __esh; + unsigned short ds, __dsh; + unsigned short fs, __fsh; + unsigned short gs, __gsh; +}; + +struct target_revectored_struct { + target_ulong __map[8]; /* 256 bits */ +}; + +struct target_vm86_struct { + struct target_vm86_regs regs; + target_ulong flags; + target_ulong screen_bitmap; + target_ulong cpu_type; + struct target_revectored_struct int_revectored; + struct target_revectored_struct int21_revectored; +}; + +/* + * flags masks + */ +#define TARGET_VM86_SCREEN_BITMAP 0x0001 + +struct target_vm86plus_info_struct { + target_ulong flags; +#define TARGET_force_return_for_pic (1 << 0) +#define TARGET_vm86dbg_active (1 << 1) /* for debugger */ +#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */ +#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */ + unsigned char vm86dbg_intxxtab[32]; /* for debugger */ +}; + +struct target_vm86plus_struct { + struct target_vm86_regs regs; + target_ulong flags; + target_ulong screen_bitmap; + target_ulong cpu_type; + struct target_revectored_struct int_revectored; + struct target_revectored_struct int21_revectored; + struct target_vm86plus_info_struct vm86plus; +}; + +/* ipcs */ + +#define TARGET_SEMOP 1 +#define TARGET_SEMGET 2 +#define TARGET_SEMCTL 3 +#define TARGET_MSGSND 11 +#define TARGET_MSGRCV 12 +#define TARGET_MSGGET 13 +#define TARGET_MSGCTL 14 +#define TARGET_SHMAT 21 +#define TARGET_SHMDT 22 +#define TARGET_SHMGET 23 +#define TARGET_SHMCTL 24 + +struct target_msgbuf { + int mtype; + char mtext[1]; +}; + +struct target_ipc_kludge { + unsigned int msgp; /* Really (struct msgbuf *) */ + int msgtyp; +}; + +struct target_ipc_perm { + int key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +struct target_msqid_ds { + struct target_ipc_perm msg_perm; + unsigned int msg_first; /* really struct target_msg* */ + unsigned int msg_last; /* really struct target_msg* */ + unsigned int msg_stime; /* really target_time_t */ + unsigned int msg_rtime; /* really target_time_t */ + unsigned int msg_ctime; /* really target_time_t */ + unsigned int wwait; /* really struct wait_queue* */ + unsigned int rwait; /* really struct wait_queue* */ + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + unsigned short msg_lspid; + unsigned short msg_lrpid; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; + int shm_segsz; + unsigned int shm_atime; /* really target_time_t */ + unsigned int shm_dtime; /* really target_time_t */ + unsigned int shm_ctime; /* really target_time_t */ + unsigned short shm_cpid; + unsigned short shm_lpid; + short shm_nattch; + unsigned short shm_npages; + unsigned long *shm_pages; + void *attaches; /* really struct shm_desc * */ +}; + +#define TARGET_IPC_RMID 0 +#define TARGET_IPC_SET 1 +#define TARGET_IPC_STAT 2 + +union target_semun { + int val; + unsigned int buf; /* really struct semid_ds * */ + unsigned int array; /* really unsigned short * */ + unsigned int __buf; /* really struct seminfo * */ + unsigned int __pad; /* really void* */ +}; + diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h new file mode 100644 index 000000000..c994381aa --- /dev/null +++ b/linux-user/i386/syscall_nr.h @@ -0,0 +1,273 @@ +/* + * This file contains the system call numbers. + */ + +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86old 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_vm86 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread 180 +#define TARGET_NR_pwrite 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 +#define TARGET_NR_getpmsg 188 /* some people actually want streams */ +#define TARGET_NR_putpmsg 189 /* some people actually want streams */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_pivot_root 217 +#define TARGET_NR_mincore 218 +#define TARGET_NR_madvise 219 +#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */ +#define TARGET_NR_getdents64 220 +#define TARGET_NR_fcntl64 221 +/* 223 is unused */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_readahead 225 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_set_thread_area 243 +#define TARGET_NR_get_thread_area 244 +#define TARGET_NR_io_setup 245 +#define TARGET_NR_io_destroy 246 +#define TARGET_NR_io_getevents 247 +#define TARGET_NR_io_submit 248 +#define TARGET_NR_io_cancel 249 +#define TARGET_NR_fadvise64 250 + +#define TARGET_NR_exit_group 252 +#define TARGET_NR_lookup_dcookie 253 +#define TARGET_NR_epoll_create 254 +#define TARGET_NR_epoll_ctl 255 +#define TARGET_NR_epoll_wait 256 +#define TARGET_NR_remap_file_pages 257 +#define TARGET_NR_set_tid_address 258 +#define TARGET_NR_timer_create 259 +#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) +#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) +#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) +#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) +#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) +#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) +#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) +#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) + diff --git a/target-arm/cpu.h b/target-arm/cpu.h new file mode 100644 index 000000000..7f755a754 --- /dev/null +++ b/target-arm/cpu.h @@ -0,0 +1,63 @@ +/* + * ARM virtual CPU header + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef CPU_ARM_H +#define CPU_ARM_H + +#include "cpu-defs.h" + +#define EXCP_UDEF 1 /* undefined instruction */ +#define EXCP_SWI 2 /* software interrupt */ + +typedef struct CPUARMState { + uint32_t regs[16]; + uint32_t cpsr; + + /* cpsr flag cache for faster execution */ + uint32_t CF; /* 0 or 1 */ + uint32_t VF; /* V is the bit 31. All other bits are undefined */ + uint32_t NZF; /* N is bit 31. Z is computed from NZF */ + + /* exception/interrupt handling */ + jmp_buf jmp_env; + int exception_index; + int interrupt_request; + struct TranslationBlock *current_tb; + int user_mode_only; + + /* user data */ + void *opaque; +} CPUARMState; + +CPUARMState *cpu_arm_init(void); +int cpu_arm_exec(CPUARMState *s); +void cpu_arm_close(CPUARMState *s); +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +struct siginfo; +int cpu_arm_signal_handler(int host_signum, struct siginfo *info, + void *puc); + +void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags); + +#define TARGET_PAGE_BITS 12 +#include "cpu-all.h" + +#endif diff --git a/target-arm/exec.h b/target-arm/exec.h new file mode 100644 index 000000000..70afdc5d9 --- /dev/null +++ b/target-arm/exec.h @@ -0,0 +1,40 @@ +/* + * ARM execution defines + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "dyngen-exec.h" + +register struct CPUARMState *env asm(AREG0); +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +register uint32_t T2 asm(AREG3); + +#include "cpu.h" +#include "exec-all.h" + +void cpu_lock(void); +void cpu_unlock(void); +void cpu_loop_exit(void); + +static inline int compute_cpsr(void) +{ + int ZF; + ZF = (env->NZF == 0); + return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); +} diff --git a/target-arm/op.c b/target-arm/op.c new file mode 100644 index 000000000..5879eba9f --- /dev/null +++ b/target-arm/op.c @@ -0,0 +1,673 @@ +/* + * ARM micro operations + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "exec.h" + +#define REGNAME r0 +#define REG (env->regs[0]) +#include "op_template.h" + +#define REGNAME r1 +#define REG (env->regs[1]) +#include "op_template.h" + +#define REGNAME r2 +#define REG (env->regs[2]) +#include "op_template.h" + +#define REGNAME r3 +#define REG (env->regs[3]) +#include "op_template.h" + +#define REGNAME r4 +#define REG (env->regs[4]) +#include "op_template.h" + +#define REGNAME r5 +#define REG (env->regs[5]) +#include "op_template.h" + +#define REGNAME r6 +#define REG (env->regs[6]) +#include "op_template.h" + +#define REGNAME r7 +#define REG (env->regs[7]) +#include "op_template.h" + +#define REGNAME r8 +#define REG (env->regs[8]) +#include "op_template.h" + +#define REGNAME r9 +#define REG (env->regs[9]) +#include "op_template.h" + +#define REGNAME r10 +#define REG (env->regs[10]) +#include "op_template.h" + +#define REGNAME r11 +#define REG (env->regs[11]) +#include "op_template.h" + +#define REGNAME r12 +#define REG (env->regs[12]) +#include "op_template.h" + +#define REGNAME r13 +#define REG (env->regs[13]) +#include "op_template.h" + +#define REGNAME r14 +#define REG (env->regs[14]) +#include "op_template.h" + +#define REGNAME r15 +#define REG (env->regs[15]) +#include "op_template.h" + +void OPPROTO op_movl_T0_0(void) +{ + T0 = 0; +} + +void OPPROTO op_movl_T0_im(void) +{ + T0 = PARAM1; +} + +void OPPROTO op_movl_T1_im(void) +{ + T1 = PARAM1; +} + +void OPPROTO op_movl_T2_im(void) +{ + T2 = PARAM1; +} + +void OPPROTO op_addl_T1_im(void) +{ + T1 += PARAM1; +} + +void OPPROTO op_addl_T1_T2(void) +{ + T1 += T2; +} + +void OPPROTO op_subl_T1_T2(void) +{ + T1 -= T2; +} + +void OPPROTO op_addl_T0_T1(void) +{ + T0 += T1; +} + +void OPPROTO op_addl_T0_T1_cc(void) +{ + unsigned int src1; + src1 = T0; + T0 += T1; + env->NZF = T0; + env->CF = T0 < src1; + env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); +} + +void OPPROTO op_adcl_T0_T1(void) +{ + T0 += T1 + env->CF; +} + +void OPPROTO op_adcl_T0_T1_cc(void) +{ + unsigned int src1; + src1 = T0; + if (!env->CF) { + T0 += T1; + env->CF = T0 < src1; + } else { + T0 += T1 + 1; + env->CF = T0 <= src1; + } + env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); + env->NZF = T0; + FORCE_RET(); +} + +#define OPSUB(sub, sbc, res, T0, T1) \ + \ +void OPPROTO op_ ## sub ## l_T0_T1(void) \ +{ \ + res = T0 - T1; \ +} \ + \ +void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ +{ \ + unsigned int src1; \ + src1 = T0; \ + T0 -= T1; \ + env->NZF = T0; \ + env->CF = src1 >= T1; \ + env->VF = (src1 ^ T1) & (src1 ^ T0); \ + res = T0; \ +} \ + \ +void OPPROTO op_ ## sbc ## l_T0_T1(void) \ +{ \ + res = T0 - T1 + env->CF - 1; \ +} \ + \ +void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ +{ \ + unsigned int src1; \ + src1 = T0; \ + if (!env->CF) { \ + T0 = T0 - T1 - 1; \ + env->CF = src1 >= T1; \ + } else { \ + T0 = T0 - T1; \ + env->CF = src1 > T1; \ + } \ + env->VF = (src1 ^ T1) & (src1 ^ T0); \ + env->NZF = T0; \ + res = T0; \ + FORCE_RET(); \ +} + +OPSUB(sub, sbc, T0, T0, T1) + +OPSUB(rsb, rsc, T0, T1, T0) + +void OPPROTO op_andl_T0_T1(void) +{ + T0 &= T1; +} + +void OPPROTO op_xorl_T0_T1(void) +{ + T0 ^= T1; +} + +void OPPROTO op_orl_T0_T1(void) +{ + T0 |= T1; +} + +void OPPROTO op_bicl_T0_T1(void) +{ + T0 &= ~T1; +} + +void OPPROTO op_notl_T1(void) +{ + T1 = ~T1; +} + +void OPPROTO op_logic_T0_cc(void) +{ + env->NZF = T0; +} + +void OPPROTO op_logic_T1_cc(void) +{ + env->NZF = T1; +} + +#define EIP (env->regs[15]) + +void OPPROTO op_test_eq(void) +{ + if (env->NZF == 0) + JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_ne(void) +{ + if (env->NZF != 0) + JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_cs(void) +{ + if (env->CF != 0) + JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_cc(void) +{ + if (env->CF == 0) + JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_mi(void) +{ + if ((env->NZF & 0x80000000) != 0) + JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_pl(void) +{ + if ((env->NZF & 0x80000000) == 0) + JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_vs(void) +{ + if ((env->VF & 0x80000000) != 0) + JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_vc(void) +{ + if ((env->VF & 0x80000000) == 0) + JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_hi(void) +{ + if (env->CF != 0 && env->NZF != 0) + JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_ls(void) +{ + if (env->CF == 0 || env->NZF == 0) + JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_ge(void) +{ + if (((env->VF ^ env->NZF) & 0x80000000) == 0) + JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_lt(void) +{ + if (((env->VF ^ env->NZF) & 0x80000000) != 0) + JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_gt(void) +{ + if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) + JUMP_TB(op_test_gt, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_test_le(void) +{ + if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) + JUMP_TB(op_test_le, PARAM1, 0, PARAM2); + FORCE_RET(); +} + +void OPPROTO op_jmp(void) +{ + JUMP_TB(op_jmp, PARAM1, 1, PARAM2); +} + +void OPPROTO op_exit_tb(void) +{ + EXIT_TB(); +} + +void OPPROTO op_movl_T0_psr(void) +{ + T0 = compute_cpsr(); +} + +/* NOTE: N = 1 and Z = 1 cannot be stored currently */ +void OPPROTO op_movl_psr_T0(void) +{ + unsigned int psr; + psr = T0; + env->CF = (psr >> 29) & 1; + env->NZF = (psr & 0xc0000000) ^ 0x40000000; + env->VF = (psr << 3) & 0x80000000; + /* for user mode we do not update other state info */ +} + +void OPPROTO op_mul_T0_T1(void) +{ + T0 = T0 * T1; +} + +/* 64 bit unsigned mul */ +void OPPROTO op_mull_T0_T1(void) +{ + uint64_t res; + res = T0 * T1; + T1 = res >> 32; + T0 = res; +} + +/* 64 bit signed mul */ +void OPPROTO op_imull_T0_T1(void) +{ + uint64_t res; + res = (int32_t)T0 * (int32_t)T1; + T1 = res >> 32; + T0 = res; +} + +void OPPROTO op_addq_T0_T1(void) +{ + uint64_t res; + res = ((uint64_t)T1 << 32) | T0; + res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); + T1 = res >> 32; + T0 = res; +} + +void OPPROTO op_logicq_cc(void) +{ + env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); +} + +/* memory access */ + +void OPPROTO op_ldub_T0_T1(void) +{ + T0 = ldub((void *)T1); +} + +void OPPROTO op_ldsb_T0_T1(void) +{ + T0 = ldsb((void *)T1); +} + +void OPPROTO op_lduw_T0_T1(void) +{ + T0 = lduw((void *)T1); +} + +void OPPROTO op_ldsw_T0_T1(void) +{ + T0 = ldsw((void *)T1); +} + +void OPPROTO op_ldl_T0_T1(void) +{ + T0 = ldl((void *)T1); +} + +void OPPROTO op_stb_T0_T1(void) +{ + stb((void *)T1, T0); +} + +void OPPROTO op_stw_T0_T1(void) +{ + stw((void *)T1, T0); +} + +void OPPROTO op_stl_T0_T1(void) +{ + stl((void *)T1, T0); +} + +void OPPROTO op_swpb_T0_T1(void) +{ + int tmp; + + cpu_lock(); + tmp = ldub((void *)T1); + stb((void *)T1, T0); + T0 = tmp; + cpu_unlock(); +} + +void OPPROTO op_swpl_T0_T1(void) +{ + int tmp; + + cpu_lock(); + tmp = ldl((void *)T1); + stl((void *)T1, T0); + T0 = tmp; + cpu_unlock(); +} + +/* shifts */ + +/* T1 based */ +void OPPROTO op_shll_T1_im(void) +{ + T1 = T1 << PARAM1; +} + +void OPPROTO op_shrl_T1_im(void) +{ + T1 = (uint32_t)T1 >> PARAM1; +} + +void OPPROTO op_sarl_T1_im(void) +{ + T1 = (int32_t)T1 >> PARAM1; +} + +void OPPROTO op_rorl_T1_im(void) +{ + int shift; + shift = PARAM1; + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); +} + +/* T1 based, set C flag */ +void OPPROTO op_shll_T1_im_cc(void) +{ + env->CF = (T1 >> (32 - PARAM1)) & 1; + T1 = T1 << PARAM1; +} + +void OPPROTO op_shrl_T1_im_cc(void) +{ + env->CF = (T1 >> (PARAM1 - 1)) & 1; + T1 = (uint32_t)T1 >> PARAM1; +} + +void OPPROTO op_sarl_T1_im_cc(void) +{ + env->CF = (T1 >> (PARAM1 - 1)) & 1; + T1 = (int32_t)T1 >> PARAM1; +} + +void OPPROTO op_rorl_T1_im_cc(void) +{ + int shift; + shift = PARAM1; + env->CF = (T1 >> (shift - 1)) & 1; + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); +} + +/* T2 based */ +void OPPROTO op_shll_T2_im(void) +{ + T2 = T2 << PARAM1; +} + +void OPPROTO op_shrl_T2_im(void) +{ + T2 = (uint32_t)T2 >> PARAM1; +} + +void OPPROTO op_sarl_T2_im(void) +{ + T2 = (int32_t)T2 >> PARAM1; +} + +void OPPROTO op_rorl_T2_im(void) +{ + int shift; + shift = PARAM1; + T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); +} + +/* T1 based, use T0 as shift count */ + +void OPPROTO op_shll_T1_T0(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) + T1 = 0; + else + T1 = T1 << shift; + FORCE_RET(); +} + +void OPPROTO op_shrl_T1_T0(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) + T1 = 0; + else + T1 = (uint32_t)T1 >> shift; + FORCE_RET(); +} + +void OPPROTO op_sarl_T1_T0(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) + shift = 31; + T1 = (int32_t)T1 >> shift; +} + +void OPPROTO op_rorl_T1_T0(void) +{ + int shift; + shift = T0 & 0x1f; + if (shift) { + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); + } + FORCE_RET(); +} + +/* T1 based, use T0 as shift count and compute CF */ + +void OPPROTO op_shll_T1_T0_cc(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = T1 & 1; + else + env->CF = 0; + T1 = 0; + } else if (shift != 0) { + env->CF = (T1 >> (32 - shift)) & 1; + T1 = T1 << shift; + } + FORCE_RET(); +} + +void OPPROTO op_shrl_T1_T0_cc(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) { + if (shift == 32) + env->CF = (T1 >> 31) & 1; + else + env->CF = 0; + T1 = 0; + } else if (shift != 0) { + env->CF = (T1 >> (shift - 1)) & 1; + T1 = (uint32_t)T1 >> shift; + } + FORCE_RET(); +} + +void OPPROTO op_sarl_T1_T0_cc(void) +{ + int shift; + shift = T0 & 0xff; + if (shift >= 32) { + env->CF = (T1 >> 31) & 1; + T1 = (int32_t)T1 >> 31; + } else { + env->CF = (T1 >> (shift - 1)) & 1; + T1 = (int32_t)T1 >> shift; + } + FORCE_RET(); +} + +void OPPROTO op_rorl_T1_T0_cc(void) +{ + int shift1, shift; + shift1 = T0 & 0xff; + shift = shift1 & 0x1f; + if (shift == 0) { + if (shift1 != 0) + env->CF = (T1 >> 31) & 1; + } else { + env->CF = (T1 >> (shift - 1)) & 1; + T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); + } + FORCE_RET(); +} + +/* exceptions */ + +void OPPROTO op_swi(void) +{ + env->exception_index = EXCP_SWI; + cpu_loop_exit(); +} + +void OPPROTO op_undef_insn(void) +{ + env->exception_index = EXCP_UDEF; + cpu_loop_exit(); +} + +/* thread support */ + +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void cpu_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void cpu_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + diff --git a/target-arm/op_template.h b/target-arm/op_template.h new file mode 100644 index 000000000..00e9d51fe --- /dev/null +++ b/target-arm/op_template.h @@ -0,0 +1,48 @@ +/* + * ARM micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void OPPROTO glue(op_movl_T0_, REGNAME)(void) +{ + T0 = REG; +} + +void OPPROTO glue(op_movl_T1_, REGNAME)(void) +{ + T1 = REG; +} + +void OPPROTO glue(op_movl_T2_, REGNAME)(void) +{ + T2 = REG; +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) +{ + REG = T0; +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) +{ + REG = T1; +} + +#undef REG +#undef REGNAME diff --git a/target-arm/translate.c b/target-arm/translate.c new file mode 100644 index 000000000..bffeefa4f --- /dev/null +++ b/target-arm/translate.c @@ -0,0 +1,903 @@ +/* + * ARM translation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +/* internal defines */ +typedef struct DisasContext { + uint8_t *pc; + int is_jmp; + struct TranslationBlock *tb; +} DisasContext; + +#define DISAS_JUMP_NEXT 4 + +/* XXX: move that elsewhere */ +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; +extern FILE *logfile; +extern int loglevel; + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +#include "gen-op.h" + +typedef void (GenOpFunc)(void); +typedef void (GenOpFunc1)(long); +typedef void (GenOpFunc2)(long, long); +typedef void (GenOpFunc3)(long, long, long); + +static GenOpFunc2 *gen_test_cc[14] = { + gen_op_test_eq, + gen_op_test_ne, + gen_op_test_cs, + gen_op_test_cc, + gen_op_test_mi, + gen_op_test_pl, + gen_op_test_vs, + gen_op_test_vc, + gen_op_test_hi, + gen_op_test_ls, + gen_op_test_ge, + gen_op_test_lt, + gen_op_test_gt, + gen_op_test_le, +}; + +const uint8_t table_logic_cc[16] = { + 1, /* and */ + 1, /* xor */ + 0, /* sub */ + 0, /* rsb */ + 0, /* add */ + 0, /* adc */ + 0, /* sbc */ + 0, /* rsc */ + 1, /* andl */ + 1, /* xorl */ + 0, /* cmp */ + 0, /* cmn */ + 1, /* orr */ + 1, /* mov */ + 1, /* bic */ + 1, /* mvn */ +}; + +static GenOpFunc1 *gen_shift_T1_im[4] = { + gen_op_shll_T1_im, + gen_op_shrl_T1_im, + gen_op_sarl_T1_im, + gen_op_rorl_T1_im, +}; + +static GenOpFunc1 *gen_shift_T2_im[4] = { + gen_op_shll_T2_im, + gen_op_shrl_T2_im, + gen_op_sarl_T2_im, + gen_op_rorl_T2_im, +}; + +static GenOpFunc1 *gen_shift_T1_im_cc[4] = { + gen_op_shll_T1_im_cc, + gen_op_shrl_T1_im_cc, + gen_op_sarl_T1_im_cc, + gen_op_rorl_T1_im_cc, +}; + +static GenOpFunc *gen_shift_T1_T0[4] = { + gen_op_shll_T1_T0, + gen_op_shrl_T1_T0, + gen_op_sarl_T1_T0, + gen_op_rorl_T1_T0, +}; + +static GenOpFunc *gen_shift_T1_T0_cc[4] = { + gen_op_shll_T1_T0_cc, + gen_op_shrl_T1_T0_cc, + gen_op_sarl_T1_T0_cc, + gen_op_rorl_T1_T0_cc, +}; + +static GenOpFunc *gen_op_movl_TN_reg[3][16] = { + { + gen_op_movl_T0_r0, + gen_op_movl_T0_r1, + gen_op_movl_T0_r2, + gen_op_movl_T0_r3, + gen_op_movl_T0_r4, + gen_op_movl_T0_r5, + gen_op_movl_T0_r6, + gen_op_movl_T0_r7, + gen_op_movl_T0_r8, + gen_op_movl_T0_r9, + gen_op_movl_T0_r10, + gen_op_movl_T0_r11, + gen_op_movl_T0_r12, + gen_op_movl_T0_r13, + gen_op_movl_T0_r14, + gen_op_movl_T0_r15, + }, + { + gen_op_movl_T1_r0, + gen_op_movl_T1_r1, + gen_op_movl_T1_r2, + gen_op_movl_T1_r3, + gen_op_movl_T1_r4, + gen_op_movl_T1_r5, + gen_op_movl_T1_r6, + gen_op_movl_T1_r7, + gen_op_movl_T1_r8, + gen_op_movl_T1_r9, + gen_op_movl_T1_r10, + gen_op_movl_T1_r11, + gen_op_movl_T1_r12, + gen_op_movl_T1_r13, + gen_op_movl_T1_r14, + gen_op_movl_T1_r15, + }, + { + gen_op_movl_T2_r0, + gen_op_movl_T2_r1, + gen_op_movl_T2_r2, + gen_op_movl_T2_r3, + gen_op_movl_T2_r4, + gen_op_movl_T2_r5, + gen_op_movl_T2_r6, + gen_op_movl_T2_r7, + gen_op_movl_T2_r8, + gen_op_movl_T2_r9, + gen_op_movl_T2_r10, + gen_op_movl_T2_r11, + gen_op_movl_T2_r12, + gen_op_movl_T2_r13, + gen_op_movl_T2_r14, + gen_op_movl_T2_r15, + }, +}; + +static GenOpFunc *gen_op_movl_reg_TN[2][16] = { + { + gen_op_movl_r0_T0, + gen_op_movl_r1_T0, + gen_op_movl_r2_T0, + gen_op_movl_r3_T0, + gen_op_movl_r4_T0, + gen_op_movl_r5_T0, + gen_op_movl_r6_T0, + gen_op_movl_r7_T0, + gen_op_movl_r8_T0, + gen_op_movl_r9_T0, + gen_op_movl_r10_T0, + gen_op_movl_r11_T0, + gen_op_movl_r12_T0, + gen_op_movl_r13_T0, + gen_op_movl_r14_T0, + gen_op_movl_r15_T0, + }, + { + gen_op_movl_r0_T1, + gen_op_movl_r1_T1, + gen_op_movl_r2_T1, + gen_op_movl_r3_T1, + gen_op_movl_r4_T1, + gen_op_movl_r5_T1, + gen_op_movl_r6_T1, + gen_op_movl_r7_T1, + gen_op_movl_r8_T1, + gen_op_movl_r9_T1, + gen_op_movl_r10_T1, + gen_op_movl_r11_T1, + gen_op_movl_r12_T1, + gen_op_movl_r13_T1, + gen_op_movl_r14_T1, + gen_op_movl_r15_T1, + }, +}; + +static GenOpFunc1 *gen_op_movl_TN_im[3] = { + gen_op_movl_T0_im, + gen_op_movl_T1_im, + gen_op_movl_T2_im, +}; + +static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) +{ + int val; + + if (reg == 15) { + /* normaly, since we updated PC, we need only to add 4 */ + val = (long)s->pc + 4; + gen_op_movl_TN_im[t](val); + } else { + gen_op_movl_TN_reg[t][reg](); + } +} + +static inline void gen_movl_T0_reg(DisasContext *s, int reg) +{ + gen_movl_TN_reg(s, reg, 0); +} + +static inline void gen_movl_T1_reg(DisasContext *s, int reg) +{ + gen_movl_TN_reg(s, reg, 1); +} + +static inline void gen_movl_T2_reg(DisasContext *s, int reg) +{ + gen_movl_TN_reg(s, reg, 2); +} + +static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t) +{ + gen_op_movl_reg_TN[t][reg](); + if (reg == 15) { + s->is_jmp = DISAS_JUMP; + } +} + +static inline void gen_movl_reg_T0(DisasContext *s, int reg) +{ + gen_movl_reg_TN(s, reg, 0); +} + +static inline void gen_movl_reg_T1(DisasContext *s, int reg) +{ + gen_movl_reg_TN(s, reg, 1); +} + +static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) +{ + int val, rm, shift; + + if (!(insn & (1 << 25))) { + /* immediate */ + val = insn & 0xfff; + if (!(insn & (1 << 23))) + val = -val; + gen_op_addl_T1_im(val); + } else { + /* shift/register */ + rm = (insn) & 0xf; + shift = (insn >> 7) & 0x1f; + gen_movl_T2_reg(s, rm); + if (shift != 0) { + gen_shift_T2_im[(insn >> 5) & 3](shift); + } + if (!(insn & (1 << 23))) + gen_op_subl_T1_T2(); + else + gen_op_addl_T1_T2(); + } +} + +static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn) +{ + int val, rm; + + if (insn & (1 << 22)) { + /* immediate */ + val = (insn & 0xf) | ((insn >> 4) & 0xf0); + if (!(insn & (1 << 23))) + val = -val; + gen_op_addl_T1_im(val); + } else { + /* register */ + rm = (insn) & 0xf; + gen_movl_T2_reg(s, rm); + if (!(insn & (1 << 23))) + gen_op_subl_T1_T2(); + else + gen_op_addl_T1_T2(); + } +} + +static void disas_arm_insn(DisasContext *s) +{ + unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; + + insn = ldl(s->pc); + s->pc += 4; + + cond = insn >> 28; + if (cond == 0xf) + goto illegal_op; + if (cond != 0xe) { + /* if not always execute, we generate a conditional jump to + next instruction */ + gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); + s->is_jmp = DISAS_JUMP_NEXT; + } + if (((insn & 0x0e000000) == 0 && + (insn & 0x00000090) != 0x90) || + ((insn & 0x0e000000) == (1 << 25))) { + int set_cc, logic_cc, shiftop; + + op1 = (insn >> 21) & 0xf; + set_cc = (insn >> 20) & 1; + logic_cc = table_logic_cc[op1] & set_cc; + + /* data processing instruction */ + if (insn & (1 << 25)) { + /* immediate operand */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) + val = (val >> shift) | (val << (32 - shift)); + gen_op_movl_T1_im(val); + /* XXX: is CF modified ? */ + } else { + /* register */ + rm = (insn) & 0xf; + gen_movl_T1_reg(s, rm); + shiftop = (insn >> 5) & 3; + if (!(insn & (1 << 4))) { + shift = (insn >> 7) & 0x1f; + if (shift != 0) { + if (logic_cc) { + gen_shift_T1_im_cc[shiftop](shift); + } else { + gen_shift_T1_im[shiftop](shift); + } + } + } else { + rs = (insn >> 8) & 0xf; + gen_movl_T0_reg(s, rs); + if (logic_cc) { + gen_shift_T1_T0_cc[shiftop](); + } else { + gen_shift_T1_T0[shiftop](); + } + } + } + if (op1 != 0x0f && op1 != 0x0d) { + rn = (insn >> 16) & 0xf; + gen_movl_T0_reg(s, rn); + } + rd = (insn >> 12) & 0xf; + switch(op1) { + case 0x00: + gen_op_andl_T0_T1(); + gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); + break; + case 0x01: + gen_op_xorl_T0_T1(); + gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); + break; + case 0x02: + if (set_cc) + gen_op_subl_T0_T1_cc(); + else + gen_op_subl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x03: + if (set_cc) + gen_op_rsbl_T0_T1_cc(); + else + gen_op_rsbl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x04: + if (set_cc) + gen_op_addl_T0_T1_cc(); + else + gen_op_addl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x05: + if (set_cc) + gen_op_adcl_T0_T1_cc(); + else + gen_op_adcl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x06: + if (set_cc) + gen_op_sbcl_T0_T1_cc(); + else + gen_op_sbcl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x07: + if (set_cc) + gen_op_rscl_T0_T1_cc(); + else + gen_op_rscl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x08: + if (set_cc) { + gen_op_andl_T0_T1(); + gen_op_logic_T0_cc(); + } + break; + case 0x09: + if (set_cc) { + gen_op_xorl_T0_T1(); + gen_op_logic_T0_cc(); + } + break; + case 0x0a: + if (set_cc) { + gen_op_subl_T0_T1_cc(); + } + break; + case 0x0b: + if (set_cc) { + gen_op_addl_T0_T1_cc(); + } + break; + case 0x0c: + gen_op_orl_T0_T1(); + gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); + break; + case 0x0d: + gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); + break; + case 0x0e: + gen_op_bicl_T0_T1(); + gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); + break; + default: + case 0x0f: + gen_op_notl_T1(); + gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); + break; + } + } else { + /* other instructions */ + op1 = (insn >> 24) & 0xf; + switch(op1) { + case 0x0: + case 0x1: + sh = (insn >> 5) & 3; + if (sh == 0) { + if (op1 == 0x0) { + rd = (insn >> 16) & 0xf; + rn = (insn >> 12) & 0xf; + rs = (insn >> 8) & 0xf; + rm = (insn) & 0xf; + if (!(insn & (1 << 23))) { + /* 32 bit mul */ + gen_movl_T0_reg(s, rs); + gen_movl_T1_reg(s, rm); + gen_op_mul_T0_T1(); + if (insn & (1 << 21)) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1(); + } + if (insn & (1 << 20)) + gen_op_logic_T0_cc(); + gen_movl_reg_T0(s, rd); + } else { + /* 64 bit mul */ + gen_movl_T0_reg(s, rs); + gen_movl_T1_reg(s, rm); + if (insn & (1 << 22)) + gen_op_mull_T0_T1(); + else + gen_op_imull_T0_T1(); + if (insn & (1 << 21)) + gen_op_addq_T0_T1(rn, rd); + if (insn & (1 << 20)) + gen_op_logicq_cc(); + gen_movl_reg_T0(s, rn); + gen_movl_reg_T1(s, rd); + } + } else { + /* SWP instruction */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + rm = (insn) & 0xf; + + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if (insn & (1 << 22)) { + gen_op_swpb_T0_T1(); + } else { + gen_op_swpl_T0_T1(); + } + gen_movl_reg_T0(s, rd); + } + } else { + /* load/store half word */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + gen_movl_T1_reg(s, rn); + if (insn & (1 << 25)) + gen_add_datah_offset(s, insn); + if (insn & (1 << 20)) { + /* load */ + switch(sh) { + case 1: + gen_op_lduw_T0_T1(); + break; + case 2: + gen_op_ldsb_T0_T1(); + break; + default: + case 3: + gen_op_ldsw_T0_T1(); + break; + } + } else { + /* store */ + gen_op_stw_T0_T1(); + } + if (!(insn & (1 << 24))) { + gen_add_datah_offset(s, insn); + gen_movl_reg_T1(s, rn); + } else if (insn & (1 << 21)) { + gen_movl_reg_T1(s, rn); + } + } + break; + case 0x4: + case 0x5: + case 0x6: + case 0x7: + /* load/store byte/word */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + gen_movl_T1_reg(s, rn); + if (insn & (1 << 24)) + gen_add_data_offset(s, insn); + if (insn & (1 << 20)) { + /* load */ + if (insn & (1 << 22)) + gen_op_ldub_T0_T1(); + else + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd); + } else { + /* store */ + gen_movl_T0_reg(s, rd); + if (insn & (1 << 22)) + gen_op_stb_T0_T1(); + else + gen_op_stl_T0_T1(); + } + if (!(insn & (1 << 24))) { + gen_add_data_offset(s, insn); + gen_movl_reg_T1(s, rn); + } else if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); { + } + break; + case 0x08: + case 0x09: + { + int j, n; + /* load/store multiple words */ + /* XXX: store correct base if write back */ + if (insn & (1 << 22)) + goto illegal_op; /* only usable in supervisor mode */ + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + + /* compute total size */ + n = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) + n++; + } + /* XXX: test invalid n == 0 case ? */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + gen_op_addl_T1_im(4); + } else { + /* post increment */ + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + gen_op_addl_T1_im(-(n * 4)); + } else { + /* post decrement */ + if (n != 1) + gen_op_addl_T1_im(-((n - 1) * 4)); + } + } + j = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) { + if (insn & (1 << 20)) { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, i); + } else { + /* store */ + if (i == 15) { + /* special case: r15 = PC + 12 */ + val = (long)s->pc + 8; + gen_op_movl_TN_im[0](val); + } else { + gen_movl_T0_reg(s, i); + } + gen_op_stl_T0_T1(); + } + j++; + /* no need to add after the last transfer */ + if (j != n) + gen_op_addl_T1_im(4); + } + } + if (insn & (1 << 21)) { + /* write back */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + } else { + /* post increment */ + gen_op_addl_T1_im(4); + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + if (n != 1) + gen_op_addl_T1_im(-((n - 1) * 4)); + } else { + /* post decrement */ + gen_op_addl_T1_im(-(n * 4)); + } + } + gen_movl_reg_T1(s, rn); + } + } + break; + case 0xa: + case 0xb: + { + int offset; + + /* branch (and link) */ + val = (int)s->pc; + if (insn & (1 << 24)) { + gen_op_movl_T0_im(val); + gen_op_movl_reg_TN[0][14](); + } + offset = (((int)insn << 8) >> 8); + val += (offset << 2) + 4; + gen_op_jmp((long)s->tb, val); + s->is_jmp = DISAS_TB_JUMP; + } + break; + case 0xf: + /* swi */ + gen_op_movl_T0_im((long)s->pc); + gen_op_movl_reg_TN[0][15](); + gen_op_swi(); + s->is_jmp = DISAS_JUMP; + break; + case 0xc: + case 0xd: + rd = (insn >> 12) & 0x7; + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + val = (insn) & 0xff; + if (!(insn & (1 << 23))) + val = -val; + switch((insn >> 8) & 0xf) { + case 0x1: + /* load/store */ + if ((insn & (1 << 24))) + gen_op_addl_T1_im(val); + /* XXX: do it */ + if (!(insn & (1 << 24))) + gen_op_addl_T1_im(val); + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + break; + case 0x2: + { + int n, i; + /* load store multiple */ + if ((insn & (1 << 24))) + gen_op_addl_T1_im(val); + switch(insn & 0x00408000) { + case 0x00008000: n = 1; break; + case 0x00400000: n = 2; break; + case 0x00408000: n = 3; break; + default: n = 4; break; + } + for(i = 0;i < n; i++) { + /* XXX: do it */ + } + if (!(insn & (1 << 24))) + gen_op_addl_T1_im(val); + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); + } + break; + default: + goto illegal_op; + } + break; + case 0x0e: + /* float ops */ + /* XXX: do it */ + switch((insn >> 20) & 0xf) { + case 0x2: /* wfs */ + break; + case 0x3: /* rfs */ + break; + case 0x4: /* wfc */ + break; + case 0x5: /* rfc */ + break; + default: + goto illegal_op; + } + break; + default: + illegal_op: + gen_op_movl_T0_im((long)s->pc - 4); + gen_op_movl_reg_TN[0][15](); + gen_op_undef_insn(); + s->is_jmp = DISAS_JUMP; + break; + } + } +} + +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) +{ + DisasContext dc1, *dc = &dc1; + uint16_t *gen_opc_end; + int j, lj; + uint8_t *pc_start; + + /* generate intermediate code */ + pc_start = (uint8_t *)tb->pc; + + dc->tb = tb; + + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + + dc->is_jmp = DISAS_NEXT; + dc->pc = pc_start; + lj = -1; + do { + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = (uint32_t)dc->pc; + gen_opc_instr_start[lj] = 1; + } + disas_arm_insn(dc); + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + switch(dc->is_jmp) { + case DISAS_JUMP_NEXT: + case DISAS_NEXT: + gen_op_jmp((long)dc->tb, (long)dc->pc); + break; + default: + case DISAS_JUMP: + /* indicate that the hash table must be used to find the next TB */ + gen_op_movl_T0_0(); + gen_op_exit_tb(); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + } + *gen_opc_ptr = INDEX_op_end; + +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "----------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + disas(logfile, pc_start, dc->pc - pc_start, 0, 0); + fprintf(logfile, "\n"); + + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + if (!search_pc) + tb->size = dc->pc - pc_start; + return 0; +} + +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 1); +} + +CPUARMState *cpu_arm_init(void) +{ + CPUARMState *env; + + cpu_exec_init(); + + env = malloc(sizeof(CPUARMState)); + if (!env) + return NULL; + memset(env, 0, sizeof(CPUARMState)); + return env; +} + +void cpu_arm_close(CPUARMState *env) +{ + free(env); +} + +void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) +{ + int i; + + for(i=0;i<16;i++) { + fprintf(f, "R%02d=%08x", i, env->regs[i]); + if ((i % 4) == 3) + fprintf(f, "\n"); + else + fprintf(f, " "); + } + fprintf(f, "PSR=%08x %c%c%c%c\n", + env->cpsr, + env->cpsr & (1 << 31) ? 'N' : '-', + env->cpsr & (1 << 30) ? 'Z' : '-', + env->cpsr & (1 << 29) ? 'C' : '-', + env->cpsr & (1 << 28) ? 'V' : '-'); +} diff --git a/target-i386/cpu.h b/target-i386/cpu.h new file mode 100644 index 000000000..ffc4654d3 --- /dev/null +++ b/target-i386/cpu.h @@ -0,0 +1,401 @@ +/* + * i386 virtual CPU header + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef CPU_I386_H +#define CPU_I386_H + +#include "cpu-defs.h" + +#define R_EAX 0 +#define R_ECX 1 +#define R_EDX 2 +#define R_EBX 3 +#define R_ESP 4 +#define R_EBP 5 +#define R_ESI 6 +#define R_EDI 7 + +#define R_AL 0 +#define R_CL 1 +#define R_DL 2 +#define R_BL 3 +#define R_AH 4 +#define R_CH 5 +#define R_DH 6 +#define R_BH 7 + +#define R_ES 0 +#define R_CS 1 +#define R_SS 2 +#define R_DS 3 +#define R_FS 4 +#define R_GS 5 + +/* segment descriptor fields */ +#define DESC_G_MASK (1 << 23) +#define DESC_B_SHIFT 22 +#define DESC_B_MASK (1 << DESC_B_SHIFT) +#define DESC_AVL_MASK (1 << 20) +#define DESC_P_MASK (1 << 15) +#define DESC_DPL_SHIFT 13 +#define DESC_S_MASK (1 << 12) +#define DESC_TYPE_SHIFT 8 +#define DESC_A_MASK (1 << 8) + +#define DESC_CS_MASK (1 << 11) +#define DESC_C_MASK (1 << 10) +#define DESC_R_MASK (1 << 9) + +#define DESC_E_MASK (1 << 10) +#define DESC_W_MASK (1 << 9) + +/* eflags masks */ +#define CC_C 0x0001 +#define CC_P 0x0004 +#define CC_A 0x0010 +#define CC_Z 0x0040 +#define CC_S 0x0080 +#define CC_O 0x0800 + +#define TF_SHIFT 8 +#define IOPL_SHIFT 12 +#define VM_SHIFT 17 + +#define TF_MASK 0x00000100 +#define IF_MASK 0x00000200 +#define DF_MASK 0x00000400 +#define IOPL_MASK 0x00003000 +#define NT_MASK 0x00004000 +#define RF_MASK 0x00010000 +#define VM_MASK 0x00020000 +#define AC_MASK 0x00040000 +#define VIF_MASK 0x00080000 +#define VIP_MASK 0x00100000 +#define ID_MASK 0x00200000 + +/* hidden flags - used internally by qemu to represent additionnal cpu + states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid + using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring + with eflags. */ +/* current cpl */ +#define HF_CPL_SHIFT 0 +/* true if soft mmu is being used */ +#define HF_SOFTMMU_SHIFT 2 +/* true if hardware interrupts must be disabled for next instruction */ +#define HF_INHIBIT_IRQ_SHIFT 3 +/* 16 or 32 segments */ +#define HF_CS32_SHIFT 4 +#define HF_SS32_SHIFT 5 +/* zero base for DS, ES and SS */ +#define HF_ADDSEG_SHIFT 6 + +#define HF_CPL_MASK (3 << HF_CPL_SHIFT) +#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) +#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) +#define HF_CS32_MASK (1 << HF_CS32_SHIFT) +#define HF_SS32_MASK (1 << HF_SS32_SHIFT) +#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) + +#define CR0_PE_MASK (1 << 0) +#define CR0_TS_MASK (1 << 3) +#define CR0_WP_MASK (1 << 16) +#define CR0_AM_MASK (1 << 18) +#define CR0_PG_MASK (1 << 31) + +#define CR4_VME_MASK (1 << 0) +#define CR4_PVI_MASK (1 << 1) +#define CR4_TSD_MASK (1 << 2) +#define CR4_DE_MASK (1 << 3) +#define CR4_PSE_MASK (1 << 4) + +#define PG_PRESENT_BIT 0 +#define PG_RW_BIT 1 +#define PG_USER_BIT 2 +#define PG_PWT_BIT 3 +#define PG_PCD_BIT 4 +#define PG_ACCESSED_BIT 5 +#define PG_DIRTY_BIT 6 +#define PG_PSE_BIT 7 +#define PG_GLOBAL_BIT 8 + +#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT) +#define PG_RW_MASK (1 << PG_RW_BIT) +#define PG_USER_MASK (1 << PG_USER_BIT) +#define PG_PWT_MASK (1 << PG_PWT_BIT) +#define PG_PCD_MASK (1 << PG_PCD_BIT) +#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT) +#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT) +#define PG_PSE_MASK (1 << PG_PSE_BIT) +#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT) + +#define PG_ERROR_W_BIT 1 + +#define PG_ERROR_P_MASK 0x01 +#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT) +#define PG_ERROR_U_MASK 0x04 +#define PG_ERROR_RSVD_MASK 0x08 + +#define MSR_IA32_APICBASE 0x1b +#define MSR_IA32_APICBASE_BSP (1<<8) +#define MSR_IA32_APICBASE_ENABLE (1<<11) +#define MSR_IA32_APICBASE_BASE (0xfffff<<12) + +#define MSR_IA32_SYSENTER_CS 0x174 +#define MSR_IA32_SYSENTER_ESP 0x175 +#define MSR_IA32_SYSENTER_EIP 0x176 + +#define EXCP00_DIVZ 0 +#define EXCP01_SSTP 1 +#define EXCP02_NMI 2 +#define EXCP03_INT3 3 +#define EXCP04_INTO 4 +#define EXCP05_BOUND 5 +#define EXCP06_ILLOP 6 +#define EXCP07_PREX 7 +#define EXCP08_DBLE 8 +#define EXCP09_XERR 9 +#define EXCP0A_TSS 10 +#define EXCP0B_NOSEG 11 +#define EXCP0C_STACK 12 +#define EXCP0D_GPF 13 +#define EXCP0E_PAGE 14 +#define EXCP10_COPR 16 +#define EXCP11_ALGN 17 +#define EXCP12_MCHK 18 + +enum { + CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ + CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ + CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */ + + CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ + CC_OP_ADDW, + CC_OP_ADDL, + + CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ + CC_OP_ADCW, + CC_OP_ADCL, + + CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ + CC_OP_SUBW, + CC_OP_SUBL, + + CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ + CC_OP_SBBW, + CC_OP_SBBL, + + CC_OP_LOGICB, /* modify all flags, CC_DST = res */ + CC_OP_LOGICW, + CC_OP_LOGICL, + + CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */ + CC_OP_INCW, + CC_OP_INCL, + + CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */ + CC_OP_DECW, + CC_OP_DECL, + + CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ + CC_OP_SHLW, + CC_OP_SHLL, + + CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ + CC_OP_SARW, + CC_OP_SARL, + + CC_OP_NB, +}; + +#ifdef __i386__ +#define USE_X86LDOUBLE +#endif + +#ifdef USE_X86LDOUBLE +typedef long double CPU86_LDouble; +#else +typedef double CPU86_LDouble; +#endif + +typedef struct SegmentCache { + uint32_t selector; + uint8_t *base; + uint32_t limit; + uint32_t flags; +} SegmentCache; + +typedef struct CPUX86State { + /* standard registers */ + uint32_t regs[8]; + uint32_t eip; + uint32_t eflags; /* eflags register. During CPU emulation, CC + flags and DF are set to zero because they are + stored elsewhere */ + + /* emulator internal eflags handling */ + uint32_t cc_src; + uint32_t cc_dst; + uint32_t cc_op; + int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ + uint32_t hflags; /* hidden flags, see HF_xxx constants */ + + /* FPU state */ + unsigned int fpstt; /* top of stack index */ + unsigned int fpus; + unsigned int fpuc; + uint8_t fptags[8]; /* 0 = valid, 1 = empty */ + CPU86_LDouble fpregs[8]; + + /* emulator internal variables */ + CPU86_LDouble ft0; + union { + float f; + double d; + int i32; + int64_t i64; + } fp_convert; + + /* segments */ + SegmentCache segs[6]; /* selector values */ + SegmentCache ldt; + SegmentCache tr; + SegmentCache gdt; /* only base and limit are used */ + SegmentCache idt; /* only base and limit are used */ + + /* sysenter registers */ + uint32_t sysenter_cs; + uint32_t sysenter_esp; + uint32_t sysenter_eip; + + /* exception/interrupt handling */ + jmp_buf jmp_env; + int exception_index; + int error_code; + int exception_is_int; + int exception_next_eip; + struct TranslationBlock *current_tb; /* currently executing TB */ + uint32_t cr[5]; /* NOTE: cr1 is unused */ + uint32_t dr[8]; /* debug registers */ + int interrupt_request; + int user_mode_only; /* user mode only simulation */ + + /* soft mmu support */ + /* 0 = kernel, 1 = user */ + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + + /* ice debug support */ + uint32_t breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; + int singlestep_enabled; + + /* user data */ + void *opaque; +} CPUX86State; + +#ifndef IN_OP_I386 +void cpu_x86_outb(CPUX86State *env, int addr, int val); +void cpu_x86_outw(CPUX86State *env, int addr, int val); +void cpu_x86_outl(CPUX86State *env, int addr, int val); +int cpu_x86_inb(CPUX86State *env, int addr); +int cpu_x86_inw(CPUX86State *env, int addr); +int cpu_x86_inl(CPUX86State *env, int addr); +#endif + +CPUX86State *cpu_x86_init(void); +int cpu_x86_exec(CPUX86State *s); +void cpu_x86_close(CPUX86State *s); +int cpu_x86_get_pic_interrupt(CPUX86State *s); + +/* this function must always be used to load data in the segment + cache: it synchronizes the hflags with the segment cache values */ +static inline void cpu_x86_load_seg_cache(CPUX86State *env, + int seg_reg, unsigned int selector, + uint8_t *base, unsigned int limit, + unsigned int flags) +{ + SegmentCache *sc; + unsigned int new_hflags; + + sc = &env->segs[seg_reg]; + sc->selector = selector; + sc->base = base; + sc->limit = limit; + sc->flags = flags; + + /* update the hidden flags */ + new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - HF_CS32_SHIFT); + new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - HF_SS32_SHIFT); + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + /* XXX: try to avoid this test. The problem comes from the + fact that is real mode or vm86 mode we only modify the + 'base' and 'selector' fields of the segment cache to go + faster. A solution may be to force addseg to one in + translate-i386.c. */ + new_hflags |= HF_ADDSEG_MASK; + } else { + new_hflags |= (((unsigned long)env->segs[R_DS].base | + (unsigned long)env->segs[R_ES].base | + (unsigned long)env->segs[R_SS].base) != 0) << + HF_ADDSEG_SHIFT; + } + env->hflags = (env->hflags & + ~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags; +} + +/* wrapper, just in case memory mappings must be changed */ +static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) +{ +#if HF_CPL_MASK == 3 + s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl; +#else +#error HF_CPL_MASK is hardcoded +#endif +} + +/* the following helpers are only usable in user mode simulation as + they can trigger unexpected exceptions */ +void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); +void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); +void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); + +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +struct siginfo; +int cpu_x86_signal_handler(int host_signum, struct siginfo *info, + void *puc); + +/* MMU defines */ +void cpu_x86_init_mmu(CPUX86State *env); +extern int phys_ram_size; +extern int phys_ram_fd; +extern uint8_t *phys_ram_base; + +/* used to debug */ +#define X86_DUMP_FPU 0x0001 /* dump FPU state too */ +#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ +void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); + +#define TARGET_PAGE_BITS 12 +#include "cpu-all.h" + +#endif /* CPU_I386_H */ diff --git a/target-i386/exec.h b/target-i386/exec.h new file mode 100644 index 000000000..b53928c98 --- /dev/null +++ b/target-i386/exec.h @@ -0,0 +1,416 @@ +/* + * i386 execution defines + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "dyngen-exec.h" + +/* at least 4 register variables are defines */ +register struct CPUX86State *env asm(AREG0); +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +register uint32_t T2 asm(AREG3); + +#define A0 T2 + +/* if more registers are available, we define some registers too */ +#ifdef AREG4 +register uint32_t EAX asm(AREG4); +#define reg_EAX +#endif + +#ifdef AREG5 +register uint32_t ESP asm(AREG5); +#define reg_ESP +#endif + +#ifdef AREG6 +register uint32_t EBP asm(AREG6); +#define reg_EBP +#endif + +#ifdef AREG7 +register uint32_t ECX asm(AREG7); +#define reg_ECX +#endif + +#ifdef AREG8 +register uint32_t EDX asm(AREG8); +#define reg_EDX +#endif + +#ifdef AREG9 +register uint32_t EBX asm(AREG9); +#define reg_EBX +#endif + +#ifdef AREG10 +register uint32_t ESI asm(AREG10); +#define reg_ESI +#endif + +#ifdef AREG11 +register uint32_t EDI asm(AREG11); +#define reg_EDI +#endif + +extern FILE *logfile; +extern int loglevel; + +#ifndef reg_EAX +#define EAX (env->regs[R_EAX]) +#endif +#ifndef reg_ECX +#define ECX (env->regs[R_ECX]) +#endif +#ifndef reg_EDX +#define EDX (env->regs[R_EDX]) +#endif +#ifndef reg_EBX +#define EBX (env->regs[R_EBX]) +#endif +#ifndef reg_ESP +#define ESP (env->regs[R_ESP]) +#endif +#ifndef reg_EBP +#define EBP (env->regs[R_EBP]) +#endif +#ifndef reg_ESI +#define ESI (env->regs[R_ESI]) +#endif +#ifndef reg_EDI +#define EDI (env->regs[R_EDI]) +#endif +#define EIP (env->eip) +#define DF (env->df) + +#define CC_SRC (env->cc_src) +#define CC_DST (env->cc_dst) +#define CC_OP (env->cc_op) + +/* float macros */ +#define FT0 (env->ft0) +#define ST0 (env->fpregs[env->fpstt]) +#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) +#define ST1 ST(1) + +#ifdef USE_FP_CONVERT +#define FP_CONVERT (env->fp_convert) +#endif + +#include "cpu.h" +#include "exec-all.h" + +typedef struct CCTable { + int (*compute_all)(void); /* return all the flags */ + int (*compute_c)(void); /* return the C flag */ +} CCTable; + +extern CCTable cc_table[]; + +void load_seg(int seg_reg, int selector, unsigned cur_eip); +void helper_ljmp_protected_T0_T1(void); +void helper_lcall_real_T0_T1(int shift, int next_eip); +void helper_lcall_protected_T0_T1(int shift, int next_eip); +void helper_iret_real(int shift); +void helper_iret_protected(int shift); +void helper_lret_protected(int shift, int addend); +void helper_lldt_T0(void); +void helper_ltr_T0(void); +void helper_movl_crN_T0(int reg); +void helper_movl_drN_T0(int reg); +void helper_invlpg(unsigned int addr); +void cpu_x86_update_cr0(CPUX86State *env); +void cpu_x86_update_cr3(CPUX86State *env); +void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); +void tlb_fill(unsigned long addr, int is_write, void *retaddr); +void __hidden cpu_lock(void); +void __hidden cpu_unlock(void); +void do_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip, int is_hw); +void do_interrupt_user(int intno, int is_int, int error_code, + unsigned int next_eip); +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip); +void raise_exception_err(int exception_index, int error_code); +void raise_exception(int exception_index); +void __hidden cpu_loop_exit(void); +void helper_fsave(uint8_t *ptr, int data32); +void helper_frstor(uint8_t *ptr, int data32); + +void OPPROTO op_movl_eflags_T0(void); +void OPPROTO op_movl_T0_eflags(void); +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip); +void raise_exception_err(int exception_index, int error_code); +void raise_exception(int exception_index); +void helper_divl_EAX_T0(uint32_t eip); +void helper_idivl_EAX_T0(uint32_t eip); +void helper_cmpxchg8b(void); +void helper_cpuid(void); +void helper_rdtsc(void); +void helper_rdmsr(void); +void helper_wrmsr(void); +void helper_lsl(void); +void helper_lar(void); + +#ifdef USE_X86LDOUBLE +/* use long double functions */ +#define lrint lrintl +#define llrint llrintl +#define fabs fabsl +#define sin sinl +#define cos cosl +#define sqrt sqrtl +#define pow powl +#define log logl +#define tan tanl +#define atan2 atan2l +#define floor floorl +#define ceil ceill +#define rint rintl +#endif + +extern int lrint(CPU86_LDouble x); +extern int64_t llrint(CPU86_LDouble x); +extern CPU86_LDouble fabs(CPU86_LDouble x); +extern CPU86_LDouble sin(CPU86_LDouble x); +extern CPU86_LDouble cos(CPU86_LDouble x); +extern CPU86_LDouble sqrt(CPU86_LDouble x); +extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); +extern CPU86_LDouble log(CPU86_LDouble x); +extern CPU86_LDouble tan(CPU86_LDouble x); +extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); +extern CPU86_LDouble floor(CPU86_LDouble x); +extern CPU86_LDouble ceil(CPU86_LDouble x); +extern CPU86_LDouble rint(CPU86_LDouble x); + +#define RC_MASK 0xc00 +#define RC_NEAR 0x000 +#define RC_DOWN 0x400 +#define RC_UP 0x800 +#define RC_CHOP 0xc00 + +#define MAXTAN 9223372036854775808.0 + +#ifdef __arm__ +/* we have no way to do correct rounding - a FPU emulator is needed */ +#define FE_DOWNWARD FE_TONEAREST +#define FE_UPWARD FE_TONEAREST +#define FE_TOWARDZERO FE_TONEAREST +#endif + +#ifdef USE_X86LDOUBLE + +/* only for x86 */ +typedef union { + long double d; + struct { + unsigned long long lower; + unsigned short upper; + } l; +} CPU86_LDoubleU; + +/* the following deal with x86 long double-precision numbers */ +#define MAXEXPD 0x7fff +#define EXPBIAS 16383 +#define EXPD(fp) (fp.l.upper & 0x7fff) +#define SIGND(fp) ((fp.l.upper) & 0x8000) +#define MANTD(fp) (fp.l.lower) +#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS + +#else + +/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ +typedef union { + double d; +#if !defined(WORDS_BIGENDIAN) && !defined(__arm__) + struct { + uint32_t lower; + int32_t upper; + } l; +#else + struct { + int32_t upper; + uint32_t lower; + } l; +#endif +#ifndef __arm__ + int64_t ll; +#endif +} CPU86_LDoubleU; + +/* the following deal with IEEE double-precision numbers */ +#define MAXEXPD 0x7ff +#define EXPBIAS 1023 +#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) +#define SIGND(fp) ((fp.l.upper) & 0x80000000) +#ifdef __arm__ +#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32)) +#else +#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) +#endif +#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) +#endif + +static inline void fpush(void) +{ + env->fpstt = (env->fpstt - 1) & 7; + env->fptags[env->fpstt] = 0; /* validate stack entry */ +} + +static inline void fpop(void) +{ + env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ + env->fpstt = (env->fpstt + 1) & 7; +} + +#ifndef USE_X86LDOUBLE +static inline CPU86_LDouble helper_fldt(uint8_t *ptr) +{ + CPU86_LDoubleU temp; + int upper, e; + uint64_t ll; + + /* mantissa */ + upper = lduw(ptr + 8); + /* XXX: handle overflow ? */ + e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ + e |= (upper >> 4) & 0x800; /* sign */ + ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1); +#ifdef __arm__ + temp.l.upper = (e << 20) | (ll >> 32); + temp.l.lower = ll; +#else + temp.ll = ll | ((uint64_t)e << 52); +#endif + return temp.d; +} + +static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) +{ + CPU86_LDoubleU temp; + int e; + + temp.d = f; + /* mantissa */ + stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); + /* exponent + sign */ + e = EXPD(temp) - EXPBIAS + 16383; + e |= SIGND(temp) >> 16; + stw(ptr + 8, e); +} +#endif + +const CPU86_LDouble f15rk[7]; + +void helper_fldt_ST0_A0(void); +void helper_fstt_ST0_A0(void); +void helper_fbld_ST0_A0(void); +void helper_fbst_ST0_A0(void); +void helper_f2xm1(void); +void helper_fyl2x(void); +void helper_fptan(void); +void helper_fpatan(void); +void helper_fxtract(void); +void helper_fprem1(void); +void helper_fprem(void); +void helper_fyl2xp1(void); +void helper_fsqrt(void); +void helper_fsincos(void); +void helper_frndint(void); +void helper_fscale(void); +void helper_fsin(void); +void helper_fcos(void); +void helper_fxam_ST0(void); +void helper_fstenv(uint8_t *ptr, int data32); +void helper_fldenv(uint8_t *ptr, int data32); +void helper_fsave(uint8_t *ptr, int data32); +void helper_frstor(uint8_t *ptr, int data32); + +const uint8_t parity_table[256]; +const uint8_t rclw_table[32]; +const uint8_t rclb_table[32]; + +static inline uint32_t compute_eflags(void) +{ + return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); +} + +#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) + +#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \ + RF_MASK | AC_MASK | ID_MASK) + +/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */ +static inline void load_eflags(int eflags, int update_mask) +{ + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + env->eflags = (env->eflags & ~update_mask) | + (eflags & update_mask); +} + +/* memory access macros */ + +#define ldul ldl +#define lduq ldq +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel + +#define ldub_raw ldub +#define ldsb_raw ldsb +#define lduw_raw lduw +#define ldsw_raw ldsw +#define ldl_raw ldl +#define ldq_raw ldq + +#define stb_raw stb +#define stw_raw stw +#define stl_raw stl +#define stq_raw stq + +#define MEMUSER 0 +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" + +#undef MEMUSER +#define MEMUSER 1 +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" + +#undef MEMUSER + diff --git a/target-i386/helper.c b/target-i386/helper.c new file mode 100644 index 000000000..075a99f25 --- /dev/null +++ b/target-i386/helper.c @@ -0,0 +1,1803 @@ +/* + * i386 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 + */ +#include "exec.h" + +const uint8_t parity_table[256] = { + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +}; + +/* modulo 17 table */ +const uint8_t rclw_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, +}; + +/* modulo 9 table */ +const uint8_t rclb_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 0, 1, 2, 3, 4, +}; + +const CPU86_LDouble f15rk[7] = +{ + 0.00000000000000000000L, + 1.00000000000000000000L, + 3.14159265358979323851L, /*pi*/ + 0.30102999566398119523L, /*lg2*/ + 0.69314718055994530943L, /*ln2*/ + 1.44269504088896340739L, /*l2e*/ + 3.32192809488736234781L, /*l2t*/ +}; + +/* thread support */ + +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void cpu_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void cpu_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + +void cpu_loop_exit(void) +{ + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ +#ifdef reg_EAX + env->regs[R_EAX] = EAX; +#endif +#ifdef reg_ECX + env->regs[R_ECX] = ECX; +#endif +#ifdef reg_EDX + env->regs[R_EDX] = EDX; +#endif +#ifdef reg_EBX + env->regs[R_EBX] = EBX; +#endif +#ifdef reg_ESP + env->regs[R_ESP] = ESP; +#endif +#ifdef reg_EBP + env->regs[R_EBP] = EBP; +#endif +#ifdef reg_ESI + env->regs[R_ESI] = ESI; +#endif +#ifdef reg_EDI + env->regs[R_EDI] = EDI; +#endif + longjmp(env->jmp_env, 1); +} + +static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, + uint32_t *esp_ptr, int dpl) +{ + int type, index, shift; + +#if 0 + { + int i; + printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); + for(i=0;itr.limit;i++) { + printf("%02x ", env->tr.base[i]); + if ((i & 7) == 7) printf("\n"); + } + printf("\n"); + } +#endif + + if (!(env->tr.flags & DESC_P_MASK)) + cpu_abort(env, "invalid tss"); + type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; + if ((type & 7) != 1) + cpu_abort(env, "invalid tss type"); + shift = type >> 3; + index = (dpl * 4 + 2) << shift; + if (index + (4 << shift) - 1 > env->tr.limit) + raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); + if (shift == 0) { + *esp_ptr = lduw(env->tr.base + index); + *ss_ptr = lduw(env->tr.base + index + 2); + } else { + *esp_ptr = ldl(env->tr.base + index); + *ss_ptr = lduw(env->tr.base + index + 4); + } +} + +/* return non zero if error */ +static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, + int selector) +{ + SegmentCache *dt; + int index; + uint8_t *ptr; + + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + return -1; + ptr = dt->base + index; + *e1_ptr = ldl(ptr); + *e2_ptr = ldl(ptr + 4); + return 0; +} + +static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) +{ + unsigned int limit; + limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & DESC_G_MASK) + limit = (limit << 12) | 0xfff; + return limit; +} + +static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) +{ + return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); +} + +static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) +{ + sc->base = get_seg_base(e1, e2); + sc->limit = get_seg_limit(e1, e2); + sc->flags = e2; +} + +/* init the segment cache in vm86 mode. */ +static inline void load_seg_vm(int seg, int selector) +{ + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg, selector, + (uint8_t *)(selector << 4), 0xffff, 0); +} + +/* protected mode interrupt */ +static void do_interrupt_protected(int intno, int is_int, int error_code, + unsigned int next_eip, int is_hw) +{ + SegmentCache *dt; + uint8_t *ptr, *ssp; + int type, dpl, selector, ss_dpl, cpl; + int has_error_code, new_stack, shift; + uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; + uint32_t old_cs, old_ss, old_esp, old_eip; + + dt = &env->idt; + if (intno * 8 + 7 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + ptr = dt->base + intno * 8; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + switch(type) { + case 5: /* task gate */ + cpu_abort(env, "task gate not supported"); + break; + case 6: /* 286 interrupt gate */ + case 7: /* 286 trap gate */ + case 14: /* 386 interrupt gate */ + case 15: /* 386 trap gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + break; + } + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privledge if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); + selector = e1 >> 16; + offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); + if ((selector & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + if (!(e2 & DESC_C_MASK) && dpl < cpl) { + /* to inner priviledge */ + get_ss_esp_from_tss(&ss, &esp, dpl); + if ((ss & 0xfffc) == 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if ((ss & 3) != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, ss) != 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (ss_dpl != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + new_stack = 1; + } else if ((e2 & DESC_C_MASK) || dpl == cpl) { + /* to same priviledge */ + new_stack = 0; + } else { + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + new_stack = 0; /* avoid warning */ + } + + shift = type >> 3; + has_error_code = 0; + if (!is_int && !is_hw) { + switch(intno) { + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 17: + has_error_code = 1; + break; + } + } + push_size = 6 + (new_stack << 2) + (has_error_code << 1); + if (env->eflags & VM_MASK) + push_size += 8; + push_size <<= shift; + + /* XXX: check that enough room is available */ + if (new_stack) { + old_esp = ESP; + old_ss = env->segs[R_SS].selector; + ss = (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + get_seg_base(ss_e1, ss_e2), + get_seg_limit(ss_e1, ss_e2), + ss_e2); + } else { + old_esp = 0; + old_ss = 0; + esp = ESP; + } + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; + old_cs = env->segs[R_CS].selector; + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); + env->eip = offset; + ESP = esp - push_size; + ssp = env->segs[R_SS].base + esp; + if (shift == 1) { + int old_eflags; + if (env->eflags & VM_MASK) { + ssp -= 4; + stl(ssp, env->segs[R_GS].selector); + ssp -= 4; + stl(ssp, env->segs[R_FS].selector); + ssp -= 4; + stl(ssp, env->segs[R_DS].selector); + ssp -= 4; + stl(ssp, env->segs[R_ES].selector); + } + if (new_stack) { + ssp -= 4; + stl(ssp, old_ss); + ssp -= 4; + stl(ssp, old_esp); + } + ssp -= 4; + old_eflags = compute_eflags(); + stl(ssp, old_eflags); + ssp -= 4; + stl(ssp, old_cs); + ssp -= 4; + stl(ssp, old_eip); + if (has_error_code) { + ssp -= 4; + stl(ssp, error_code); + } + } else { + if (new_stack) { + ssp -= 2; + stw(ssp, old_ss); + ssp -= 2; + stw(ssp, old_esp); + } + ssp -= 2; + stw(ssp, compute_eflags()); + ssp -= 2; + stw(ssp, old_cs); + ssp -= 2; + stw(ssp, old_eip); + if (has_error_code) { + ssp -= 2; + stw(ssp, error_code); + } + } + + /* interrupt gate clear IF mask */ + if ((type & 1) == 0) { + env->eflags &= ~IF_MASK; + } + env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); +} + +/* real mode interrupt */ +static void do_interrupt_real(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentCache *dt; + uint8_t *ptr, *ssp; + int selector; + uint32_t offset, esp; + uint32_t old_cs, old_eip; + + /* real mode (simpler !) */ + dt = &env->idt; + if (intno * 4 + 3 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + ptr = dt->base + intno * 4; + offset = lduw(ptr); + selector = lduw(ptr + 2); + esp = ESP; + ssp = env->segs[R_SS].base; + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; + old_cs = env->segs[R_CS].selector; + esp -= 2; + stw(ssp + (esp & 0xffff), compute_eflags()); + esp -= 2; + stw(ssp + (esp & 0xffff), old_cs); + esp -= 2; + stw(ssp + (esp & 0xffff), old_eip); + + /* update processor state */ + ESP = (ESP & ~0xffff) | (esp & 0xffff); + env->eip = offset; + env->segs[R_CS].selector = selector; + env->segs[R_CS].base = (uint8_t *)(selector << 4); + env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); +} + +/* fake user mode interrupt */ +void do_interrupt_user(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + SegmentCache *dt; + uint8_t *ptr; + int dpl, cpl; + uint32_t e2; + + dt = &env->idt; + ptr = dt->base + (intno * 8); + e2 = ldl(ptr + 4); + + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privledge if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + + /* Since we emulate only user space, we cannot do more than + exiting the emulation with the suitable exception and error + code */ + if (is_int) + EIP = next_eip; +} + +/* + * Begin excution of an interruption. is_int is TRUE if coming from + * the int instruction. next_eip is the EIP value AFTER the interrupt + * instruction. It is only relevant if is_int is TRUE. + */ +void do_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip, int is_hw) +{ + if (env->cr[0] & CR0_PE_MASK) { + do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); + } else { + do_interrupt_real(intno, is_int, error_code, next_eip); + } +} + +/* + * Signal an interruption. It is executed in the main CPU loop. + * is_int is TRUE if coming from the int instruction. next_eip is the + * EIP value AFTER the interrupt instruction. It is only relevant if + * is_int is TRUE. + */ +void raise_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip) +{ + env->exception_index = intno; + env->error_code = error_code; + env->exception_is_int = is_int; + env->exception_next_eip = next_eip; + cpu_loop_exit(); +} + +/* shortcuts to generate exceptions */ +void raise_exception_err(int exception_index, int error_code) +{ + raise_interrupt(exception_index, 0, error_code, 0); +} + +void raise_exception(int exception_index) +{ + raise_interrupt(exception_index, 0, 0, 0); +} + +#ifdef BUGGY_GCC_DIV64 +/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we + call it from another function */ +uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) +{ + *q_ptr = num / den; + return num % den; +} + +int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) +{ + *q_ptr = num / den; + return num % den; +} +#endif + +void helper_divl_EAX_T0(uint32_t eip) +{ + unsigned int den, q, r; + uint64_t num; + + num = EAX | ((uint64_t)EDX << 32); + den = T0; + if (den == 0) { + EIP = eip; + raise_exception(EXCP00_DIVZ); + } +#ifdef BUGGY_GCC_DIV64 + r = div64(&q, num, den); +#else + q = (num / den); + r = (num % den); +#endif + EAX = q; + EDX = r; +} + +void helper_idivl_EAX_T0(uint32_t eip) +{ + int den, q, r; + int64_t num; + + num = EAX | ((uint64_t)EDX << 32); + den = T0; + if (den == 0) { + EIP = eip; + raise_exception(EXCP00_DIVZ); + } +#ifdef BUGGY_GCC_DIV64 + r = idiv64(&q, num, den); +#else + q = (num / den); + r = (num % den); +#endif + EAX = q; + EDX = r; +} + +void helper_cmpxchg8b(void) +{ + uint64_t d; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + d = ldq((uint8_t *)A0); + if (d == (((uint64_t)EDX << 32) | EAX)) { + stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); + eflags |= CC_Z; + } else { + EDX = d >> 32; + EAX = d; + eflags &= ~CC_Z; + } + CC_SRC = eflags; +} + +/* We simulate a pre-MMX pentium as in valgrind */ +#define CPUID_FP87 (1 << 0) +#define CPUID_VME (1 << 1) +#define CPUID_DE (1 << 2) +#define CPUID_PSE (1 << 3) +#define CPUID_TSC (1 << 4) +#define CPUID_MSR (1 << 5) +#define CPUID_PAE (1 << 6) +#define CPUID_MCE (1 << 7) +#define CPUID_CX8 (1 << 8) +#define CPUID_APIC (1 << 9) +#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ +#define CPUID_MTRR (1 << 12) +#define CPUID_PGE (1 << 13) +#define CPUID_MCA (1 << 14) +#define CPUID_CMOV (1 << 15) +/* ... */ +#define CPUID_MMX (1 << 23) +#define CPUID_FXSR (1 << 24) +#define CPUID_SSE (1 << 25) +#define CPUID_SSE2 (1 << 26) + +void helper_cpuid(void) +{ + if (EAX == 0) { + EAX = 1; /* max EAX index supported */ + EBX = 0x756e6547; + ECX = 0x6c65746e; + EDX = 0x49656e69; + } else if (EAX == 1) { + int family, model, stepping; + /* EAX = 1 info */ +#if 0 + /* pentium 75-200 */ + family = 5; + model = 2; + stepping = 11; +#else + /* pentium pro */ + family = 6; + model = 1; + stepping = 3; +#endif + EAX = (family << 8) | (model << 4) | stepping; + EBX = 0; + ECX = 0; + EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | + CPUID_TSC | CPUID_MSR | CPUID_MCE | + CPUID_CX8 | CPUID_PGE | CPUID_CMOV; + } +} + +void helper_lldt_T0(void) +{ + int selector; + SegmentCache *dt; + uint32_t e1, e2; + int index; + uint8_t *ptr; + + selector = T0 & 0xffff; + if ((selector & 0xfffc) == 0) { + /* XXX: NULL selector case: invalid LDT */ + env->ldt.base = NULL; + env->ldt.limit = 0; + } else { + if (selector & 0x4) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + load_seg_cache_raw_dt(&env->ldt, e1, e2); + } + env->ldt.selector = selector; +} + +void helper_ltr_T0(void) +{ + int selector; + SegmentCache *dt; + uint32_t e1, e2; + int index, type; + uint8_t *ptr; + + selector = T0 & 0xffff; + if ((selector & 0xfffc) == 0) { + /* NULL selector case: invalid LDT */ + env->tr.base = NULL; + env->tr.limit = 0; + env->tr.flags = 0; + } else { + if (selector & 0x4) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + ptr = dt->base + index; + e1 = ldl(ptr); + e2 = ldl(ptr + 4); + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + if ((e2 & DESC_S_MASK) || + (type != 2 && type != 9)) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + load_seg_cache_raw_dt(&env->tr, e1, e2); + e2 |= 0x00000200; /* set the busy bit */ + stl(ptr + 4, e2); + } + env->tr.selector = selector; +} + +/* only works if protected mode and not VM86. Calling load_seg with + seg_reg == R_CS is discouraged */ +void load_seg(int seg_reg, int selector, unsigned int cur_eip) +{ + uint32_t e1, e2; + + if ((selector & 0xfffc) == 0) { + /* null selector case */ + if (seg_reg == R_SS) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, 0); + } else { + cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); + } + } else { + if (load_segment(&e1, &e2, selector) != 0) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + if (!(e2 & DESC_S_MASK) || + (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + + if (seg_reg == R_SS) { + if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + } else { + if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + } + + if (!(e2 & DESC_P_MASK)) { + EIP = cur_eip; + if (seg_reg == R_SS) + raise_exception_err(EXCP0C_STACK, selector & 0xfffc); + else + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + } + cpu_x86_load_seg_cache(env, seg_reg, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); +#if 0 + fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", + selector, (unsigned long)sc->base, sc->limit, sc->flags); +#endif + } +} + +/* protected mode jump */ +void helper_ljmp_protected_T0_T1(void) +{ + int new_cs, new_eip; + uint32_t e1, e2, cpl, dpl, rpl, limit; + + new_cs = T0; + new_eip = T1; + if ((new_cs & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_S_MASK) { + if (!(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_CS_MASK) { + /* conforming code segment */ + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } else { + /* non conforming code segment */ + rpl = new_cs & 3; + if (rpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (dpl != cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + limit = get_seg_limit(e1, e2); + if (new_eip > limit) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); + EIP = new_eip; + } else { + cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", + new_cs, new_eip); + } +} + +/* real mode call */ +void helper_lcall_real_T0_T1(int shift, int next_eip) +{ + int new_cs, new_eip; + uint32_t esp, esp_mask; + uint8_t *ssp; + + new_cs = T0; + new_eip = T1; + esp = ESP; + esp_mask = 0xffffffff; + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + esp_mask = 0xffff; + ssp = env->segs[R_SS].base; + if (shift) { + esp -= 4; + stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); + esp -= 4; + stl(ssp + (esp & esp_mask), next_eip); + } else { + esp -= 2; + stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); + esp -= 2; + stw(ssp + (esp & esp_mask), next_eip); + } + + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + ESP = (ESP & ~0xffff) | (esp & 0xffff); + else + ESP = esp; + env->eip = new_eip; + env->segs[R_CS].selector = new_cs; + env->segs[R_CS].base = (uint8_t *)(new_cs << 4); +} + +/* protected mode call */ +void helper_lcall_protected_T0_T1(int shift, int next_eip) +{ + int new_cs, new_eip; + uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; + uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; + uint32_t old_ss, old_esp, val, i, limit; + uint8_t *ssp, *old_ssp; + + new_cs = T0; + new_eip = T1; + if ((new_cs & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_S_MASK) { + if (!(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_CS_MASK) { + /* conforming code segment */ + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } else { + /* non conforming code segment */ + rpl = new_cs & 3; + if (rpl > cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (dpl != cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + + sp = ESP; + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + sp &= 0xffff; + ssp = env->segs[R_SS].base + sp; + if (shift) { + ssp -= 4; + stl(ssp, env->segs[R_CS].selector); + ssp -= 4; + stl(ssp, next_eip); + } else { + ssp -= 2; + stw(ssp, env->segs[R_CS].selector); + ssp -= 2; + stw(ssp, next_eip); + } + sp -= (4 << shift); + + limit = get_seg_limit(e1, e2); + if (new_eip > limit) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + /* from this point, not restartable */ + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + ESP = (ESP & 0xffff0000) | (sp & 0xffff); + else + ESP = sp; + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); + EIP = new_eip; + } else { + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + switch(type) { + case 1: /* available 286 TSS */ + case 9: /* available 386 TSS */ + case 5: /* task gate */ + cpu_abort(env, "task gate not supported"); + break; + case 4: /* 286 call gate */ + case 12: /* 386 call gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + break; + } + shift = type >> 3; + + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + rpl = new_cs & 3; + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + selector = e1 >> 16; + offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); + if ((selector & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + + if (!(e2 & DESC_C_MASK) && dpl < cpl) { + /* to inner priviledge */ + get_ss_esp_from_tss(&ss, &sp, dpl); + if ((ss & 0xfffc) == 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if ((ss & 3) != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, ss) != 0) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (ss_dpl != dpl) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); + + param_count = e2 & 0x1f; + push_size = ((param_count * 2) + 8) << shift; + + old_esp = ESP; + old_ss = env->segs[R_SS].selector; + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + old_esp &= 0xffff; + old_ssp = env->segs[R_SS].base + old_esp; + + /* XXX: from this point not restartable */ + ss = (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + get_seg_base(ss_e1, ss_e2), + get_seg_limit(ss_e1, ss_e2), + ss_e2); + + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + sp &= 0xffff; + ssp = env->segs[R_SS].base + sp; + if (shift) { + ssp -= 4; + stl(ssp, old_ss); + ssp -= 4; + stl(ssp, old_esp); + ssp -= 4 * param_count; + for(i = 0; i < param_count; i++) { + val = ldl(old_ssp + i * 4); + stl(ssp + i * 4, val); + } + } else { + ssp -= 2; + stw(ssp, old_ss); + ssp -= 2; + stw(ssp, old_esp); + ssp -= 2 * param_count; + for(i = 0; i < param_count; i++) { + val = lduw(old_ssp + i * 2); + stw(ssp + i * 2, val); + } + } + } else { + /* to same priviledge */ + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + sp &= 0xffff; + ssp = env->segs[R_SS].base + sp; + push_size = (4 << shift); + } + + if (shift) { + ssp -= 4; + stl(ssp, env->segs[R_CS].selector); + ssp -= 4; + stl(ssp, next_eip); + } else { + ssp -= 2; + stw(ssp, env->segs[R_CS].selector); + ssp -= 2; + stw(ssp, next_eip); + } + + sp -= push_size; + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); + + /* from this point, not restartable if same priviledge */ + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + ESP = (ESP & 0xffff0000) | (sp & 0xffff); + else + ESP = sp; + EIP = offset; + } +} + +/* real mode iret */ +void helper_iret_real(int shift) +{ + uint32_t sp, new_cs, new_eip, new_eflags, new_esp; + uint8_t *ssp; + int eflags_mask; + + sp = ESP & 0xffff; + ssp = env->segs[R_SS].base + sp; + if (shift == 1) { + /* 32 bits */ + new_eflags = ldl(ssp + 8); + new_cs = ldl(ssp + 4) & 0xffff; + new_eip = ldl(ssp) & 0xffff; + } else { + /* 16 bits */ + new_eflags = lduw(ssp + 4); + new_cs = lduw(ssp + 2); + new_eip = lduw(ssp); + } + new_esp = sp + (6 << shift); + ESP = (ESP & 0xffff0000) | + (new_esp & 0xffff); + load_seg_vm(R_CS, new_cs); + env->eip = new_eip; + eflags_mask = FL_UPDATE_CPL0_MASK; + if (shift == 0) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); +} + +/* protected mode iret */ +static inline void helper_ret_protected(int shift, int is_iret, int addend) +{ + uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; + uint32_t new_es, new_ds, new_fs, new_gs; + uint32_t e1, e2, ss_e1, ss_e2; + int cpl, dpl, rpl, eflags_mask; + uint8_t *ssp; + + sp = ESP; + if (!(env->segs[R_SS].flags & DESC_B_MASK)) + sp &= 0xffff; + ssp = env->segs[R_SS].base + sp; + if (shift == 1) { + /* 32 bits */ + if (is_iret) + new_eflags = ldl(ssp + 8); + new_cs = ldl(ssp + 4) & 0xffff; + new_eip = ldl(ssp); + if (is_iret && (new_eflags & VM_MASK)) + goto return_to_vm86; + } else { + /* 16 bits */ + if (is_iret) + new_eflags = lduw(ssp + 4); + new_cs = lduw(ssp + 2); + new_eip = lduw(ssp); + } + if ((new_cs & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (load_segment(&e1, &e2, new_cs) != 0) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (!(e2 & DESC_S_MASK) || + !(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + cpl = env->hflags & HF_CPL_MASK; + rpl = new_cs & 3; + if (rpl < cpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (e2 & DESC_CS_MASK) { + if (dpl > rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } else { + if (dpl != rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + + if (rpl == cpl) { + /* return to same priledge level */ + cpu_x86_load_seg_cache(env, R_CS, new_cs, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; + } else { + /* return to different priviledge level */ + ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; + if (shift == 1) { + /* 32 bits */ + new_esp = ldl(ssp); + new_ss = ldl(ssp + 4) & 0xffff; + } else { + /* 16 bits */ + new_esp = lduw(ssp); + new_ss = lduw(ssp + 2); + } + + if ((new_ss & 3) != rpl) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (dpl != rpl) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); + + cpu_x86_load_seg_cache(env, R_CS, new_cs, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_load_seg_cache(env, R_SS, new_ss, + get_seg_base(ss_e1, ss_e2), + get_seg_limit(ss_e1, ss_e2), + ss_e2); + cpu_x86_set_cpl(env, rpl); + } + if (env->segs[R_SS].flags & DESC_B_MASK) + ESP = new_esp; + else + ESP = (ESP & 0xffff0000) | + (new_esp & 0xffff); + env->eip = new_eip; + if (is_iret) { + /* NOTE: 'cpl' can be different from the current CPL */ + if (cpl == 0) + eflags_mask = FL_UPDATE_CPL0_MASK; + else + eflags_mask = FL_UPDATE_MASK32; + if (shift == 0) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); + } + return; + + return_to_vm86: + new_esp = ldl(ssp + 12); + new_ss = ldl(ssp + 16); + new_es = ldl(ssp + 20); + new_ds = ldl(ssp + 24); + new_fs = ldl(ssp + 28); + new_gs = ldl(ssp + 32); + + /* modify processor state */ + load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); + load_seg_vm(R_CS, new_cs); + cpu_x86_set_cpl(env, 3); + load_seg_vm(R_SS, new_ss); + load_seg_vm(R_ES, new_es); + load_seg_vm(R_DS, new_ds); + load_seg_vm(R_FS, new_fs); + load_seg_vm(R_GS, new_gs); + + env->eip = new_eip; + ESP = new_esp; +} + +void helper_iret_protected(int shift) +{ + helper_ret_protected(shift, 1, 0); +} + +void helper_lret_protected(int shift, int addend) +{ + helper_ret_protected(shift, 0, addend); +} + +void helper_movl_crN_T0(int reg) +{ + env->cr[reg] = T0; + switch(reg) { + case 0: + cpu_x86_update_cr0(env); + break; + case 3: + cpu_x86_update_cr3(env); + break; + } +} + +/* XXX: do more */ +void helper_movl_drN_T0(int reg) +{ + env->dr[reg] = T0; +} + +void helper_invlpg(unsigned int addr) +{ + cpu_x86_flush_tlb(env, addr); +} + +/* rdtsc */ +#ifndef __i386__ +uint64_t emu_time; +#endif + +void helper_rdtsc(void) +{ + uint64_t val; +#ifdef __i386__ + asm("rdtsc" : "=A" (val)); +#else + /* better than nothing: the time increases */ + val = emu_time++; +#endif + EAX = val; + EDX = val >> 32; +} + +void helper_wrmsr(void) +{ + switch(ECX) { + case MSR_IA32_SYSENTER_CS: + env->sysenter_cs = EAX & 0xffff; + break; + case MSR_IA32_SYSENTER_ESP: + env->sysenter_esp = EAX; + break; + case MSR_IA32_SYSENTER_EIP: + env->sysenter_eip = EAX; + break; + default: + /* XXX: exception ? */ + break; + } +} + +void helper_rdmsr(void) +{ + switch(ECX) { + case MSR_IA32_SYSENTER_CS: + EAX = env->sysenter_cs; + EDX = 0; + break; + case MSR_IA32_SYSENTER_ESP: + EAX = env->sysenter_esp; + EDX = 0; + break; + case MSR_IA32_SYSENTER_EIP: + EAX = env->sysenter_eip; + EDX = 0; + break; + default: + /* XXX: exception ? */ + break; + } +} + +void helper_lsl(void) +{ + unsigned int selector, limit; + uint32_t e1, e2; + + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + selector = T0 & 0xffff; + if (load_segment(&e1, &e2, selector) != 0) + return; + limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & (1 << 23)) + limit = (limit << 12) | 0xfff; + T1 = limit; + CC_SRC |= CC_Z; +} + +void helper_lar(void) +{ + unsigned int selector; + uint32_t e1, e2; + + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + selector = T0 & 0xffff; + if (load_segment(&e1, &e2, selector) != 0) + return; + T1 = e2 & 0x00f0ff00; + CC_SRC |= CC_Z; +} + +/* FPU helpers */ + +#ifndef USE_X86LDOUBLE +void helper_fldt_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void helper_fstt_ST0_A0(void) +{ + helper_fstt(ST0, (uint8_t *)A0); +} +#endif + +/* BCD ops */ + +#define MUL10(iv) ( iv + iv + (iv << 3) ) + +void helper_fbld_ST0_A0(void) +{ + CPU86_LDouble tmp; + uint64_t val; + unsigned int v; + int i; + + val = 0; + for(i = 8; i >= 0; i--) { + v = ldub((uint8_t *)A0 + i); + val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); + } + tmp = val; + if (ldub((uint8_t *)A0 + 9) & 0x80) + tmp = -tmp; + fpush(); + ST0 = tmp; +} + +void helper_fbst_ST0_A0(void) +{ + CPU86_LDouble tmp; + int v; + uint8_t *mem_ref, *mem_end; + int64_t val; + + tmp = rint(ST0); + val = (int64_t)tmp; + mem_ref = (uint8_t *)A0; + mem_end = mem_ref + 9; + if (val < 0) { + stb(mem_end, 0x80); + val = -val; + } else { + stb(mem_end, 0x00); + } + while (mem_ref < mem_end) { + if (val == 0) + break; + v = val % 100; + val = val / 100; + v = ((v / 10) << 4) | (v % 10); + stb(mem_ref++, v); + } + while (mem_ref < mem_end) { + stb(mem_ref++, 0); + } +} + +void helper_f2xm1(void) +{ + ST0 = pow(2.0,ST0) - 1.0; +} + +void helper_fyl2x(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp>0.0){ + fptemp = log(fptemp)/log(2.0); /* log2(ST) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +void helper_fptan(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = tan(fptemp); + fpush(); + ST0 = 1.0; + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**52 only */ + } +} + +void helper_fpatan(void) +{ + CPU86_LDouble fptemp, fpsrcop; + + fpsrcop = ST1; + fptemp = ST0; + ST1 = atan2(fpsrcop,fptemp); + fpop(); +} + +void helper_fxtract(void) +{ + CPU86_LDoubleU temp; + unsigned int expdif; + + temp.d = ST0; + expdif = EXPD(temp) - EXPBIAS; + /*DP exponent bias*/ + ST0 = expdif; + fpush(); + BIASEXPONENT(temp); + ST0 = temp.d; +} + +void helper_fprem1(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + int q; + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + if (expdif < 53) { + dblq = fpsrcop / fptemp; + dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); + ST0 = fpsrcop - fptemp*dblq; + q = (int)dblq; /* cutting off top bits is assumed here */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C1,C3) <-- (q2,q1,q0) */ + env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ + env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ + env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif-50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by rounding to the nearest */ + fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? + floor(fpsrcop): ceil(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +void helper_fprem(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + int q; + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + if ( expdif < 53 ) { + dblq = fpsrcop / fptemp; + dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); + ST0 = fpsrcop - fptemp*dblq; + q = (int)dblq; /* cutting off top bits is assumed here */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C1,C3) <-- (q2,q1,q0) */ + env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ + env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ + env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif-50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by chopping */ + fpsrcop = (fpsrcop < 0.0)? + -(floor(fabs(fpsrcop))): floor(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +void helper_fyl2xp1(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp+1.0)>0.0) { + fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +void helper_fsqrt(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp<0.0) { + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + env->fpus |= 0x400; + } + ST0 = sqrt(fptemp); +} + +void helper_fsincos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + fpush(); + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**63 only */ + } +} + +void helper_frndint(void) +{ + CPU86_LDouble a; + + a = ST0; +#ifdef __arm__ + switch(env->fpuc & RC_MASK) { + default: + case RC_NEAR: + asm("rndd %0, %1" : "=f" (a) : "f"(a)); + break; + case RC_DOWN: + asm("rnddm %0, %1" : "=f" (a) : "f"(a)); + break; + case RC_UP: + asm("rnddp %0, %1" : "=f" (a) : "f"(a)); + break; + case RC_CHOP: + asm("rnddz %0, %1" : "=f" (a) : "f"(a)); + break; + } +#else + a = rint(a); +#endif + ST0 = a; +} + +void helper_fscale(void) +{ + CPU86_LDouble fpsrcop, fptemp; + + fpsrcop = 2.0; + fptemp = pow(fpsrcop,ST1); + ST0 *= fptemp; +} + +void helper_fsin(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**53 only */ + } +} + +void helper_fcos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg5 < 2**63 only */ + } +} + +void helper_fxam_ST0(void) +{ + CPU86_LDoubleU temp; + int expdif; + + temp.d = ST0; + + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + if (SIGND(temp)) + env->fpus |= 0x200; /* C1 <-- 1 */ + + expdif = EXPD(temp); + if (expdif == MAXEXPD) { + if (MANTD(temp) == 0) + env->fpus |= 0x500 /*Infinity*/; + else + env->fpus |= 0x100 /*NaN*/; + } else if (expdif == 0) { + if (MANTD(temp) == 0) + env->fpus |= 0x4000 /*Zero*/; + else + env->fpus |= 0x4400 /*Denormal*/; + } else { + env->fpus |= 0x400; + } +} + +void helper_fstenv(uint8_t *ptr, int data32) +{ + int fpus, fptag, exp, i; + uint64_t mant; + CPU86_LDoubleU tmp; + + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for (i=7; i>=0; i--) { + fptag <<= 2; + if (env->fptags[i]) { + fptag |= 3; + } else { + tmp.d = env->fpregs[i]; + exp = EXPD(tmp); + mant = MANTD(tmp); + if (exp == 0 && mant == 0) { + /* zero */ + fptag |= 1; + } else if (exp == 0 || exp == MAXEXPD +#ifdef USE_X86LDOUBLE + || (mant & (1LL << 63)) == 0 +#endif + ) { + /* NaNs, infinity, denormal */ + fptag |= 2; + } + } + } + if (data32) { + /* 32 bit */ + stl(ptr, env->fpuc); + stl(ptr + 4, fpus); + stl(ptr + 8, fptag); + stl(ptr + 12, 0); + stl(ptr + 16, 0); + stl(ptr + 20, 0); + stl(ptr + 24, 0); + } else { + /* 16 bit */ + stw(ptr, env->fpuc); + stw(ptr + 2, fpus); + stw(ptr + 4, fptag); + stw(ptr + 6, 0); + stw(ptr + 8, 0); + stw(ptr + 10, 0); + stw(ptr + 12, 0); + } +} + +void helper_fldenv(uint8_t *ptr, int data32) +{ + int i, fpus, fptag; + + if (data32) { + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 4); + fptag = lduw(ptr + 8); + } + else { + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 2); + fptag = lduw(ptr + 4); + } + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + for(i = 0;i < 7; i++) { + env->fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } +} + +void helper_fsave(uint8_t *ptr, int data32) +{ + CPU86_LDouble tmp; + int i; + + helper_fstenv(ptr, data32); + + ptr += (14 << data32); + for(i = 0;i < 8; i++) { + tmp = ST(i); +#ifdef USE_X86LDOUBLE + *(long double *)ptr = tmp; +#else + helper_fstt(tmp, ptr); +#endif + ptr += 10; + } + + /* fninit */ + env->fpus = 0; + env->fpstt = 0; + env->fpuc = 0x37f; + env->fptags[0] = 1; + env->fptags[1] = 1; + env->fptags[2] = 1; + env->fptags[3] = 1; + env->fptags[4] = 1; + env->fptags[5] = 1; + env->fptags[6] = 1; + env->fptags[7] = 1; +} + +void helper_frstor(uint8_t *ptr, int data32) +{ + CPU86_LDouble tmp; + int i; + + helper_fldenv(ptr, data32); + ptr += (14 << data32); + + for(i = 0;i < 8; i++) { +#ifdef USE_X86LDOUBLE + tmp = *(long double *)ptr; +#else + tmp = helper_fldt(ptr); +#endif + ST(i) = tmp; + ptr += 10; + } +} + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error */ +void tlb_fill(unsigned long addr, int is_write, void *retaddr) +{ + TranslationBlock *tb; + int ret; + unsigned long pc; + ret = cpu_x86_handle_mmu_fault(env, addr, is_write); + if (ret) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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); + } + raise_exception_err(EXCP0E_PAGE, env->error_code); + } +} diff --git a/target-i386/helper2.c b/target-i386/helper2.c new file mode 100644 index 000000000..bc0d426bc --- /dev/null +++ b/target-i386/helper2.c @@ -0,0 +1,390 @@ +/* + * i386 helpers (without register variable usage) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" + +//#define DEBUG_MMU + +CPUX86State *cpu_x86_init(void) +{ + CPUX86State *env; + int i; + static int inited; + + cpu_exec_init(); + + env = malloc(sizeof(CPUX86State)); + if (!env) + return NULL; + memset(env, 0, sizeof(CPUX86State)); + /* basic FPU init */ + for(i = 0;i < 8; i++) + env->fptags[i] = 1; + env->fpuc = 0x37f; + /* flags setup : we activate the IRQs by default as in user mode */ + env->eflags = 0x2 | IF_MASK; + + tlb_flush(env); +#ifdef CONFIG_SOFTMMU + env->hflags |= HF_SOFTMMU_MASK; +#endif + /* init various static tables */ + if (!inited) { + inited = 1; + optimize_flags_init(); + } + return env; +} + +void cpu_x86_close(CPUX86State *env) +{ + free(env); +} + +/***********************************************************/ +/* x86 debug */ + +static const char *cc_op_str[] = { + "DYNAMIC", + "EFLAGS", + "MUL", + "ADDB", + "ADDW", + "ADDL", + "ADCB", + "ADCW", + "ADCL", + "SUBB", + "SUBW", + "SUBL", + "SBBB", + "SBBW", + "SBBL", + "LOGICB", + "LOGICW", + "LOGICL", + "INCB", + "INCW", + "INCL", + "DECB", + "DECW", + "DECL", + "SHLB", + "SHLW", + "SHLL", + "SARB", + "SARW", + "SARL", +}; + +void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) +{ + int eflags; + char cc_op_name[32]; + + eflags = env->eflags; + fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", + env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], + env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], + env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-'); + fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", + env->segs[R_CS].selector, + env->segs[R_SS].selector, + env->segs[R_DS].selector, + env->segs[R_ES].selector, + env->segs[R_FS].selector, + env->segs[R_GS].selector); + if (flags & X86_DUMP_CCOP) { + if ((unsigned)env->cc_op < CC_OP_NB) + strcpy(cc_op_name, cc_op_str[env->cc_op]); + else + snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); + fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", + env->cc_src, env->cc_dst, cc_op_name); + } + if (flags & X86_DUMP_FPU) { + fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", + (double)env->fpregs[0], + (double)env->fpregs[1], + (double)env->fpregs[2], + (double)env->fpregs[3]); + fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", + (double)env->fpregs[4], + (double)env->fpregs[5], + (double)env->fpregs[7], + (double)env->fpregs[8]); + } +} + +/***********************************************************/ +/* x86 mmu */ +/* XXX: add PGE support */ + +/* called when cr3 or PG bit are modified */ +static int last_pg_state = -1; +static int last_pe_state = 0; +int phys_ram_size; +int phys_ram_fd; +uint8_t *phys_ram_base; + +void cpu_x86_update_cr0(CPUX86State *env) +{ + int pg_state, pe_state; + +#ifdef DEBUG_MMU + printf("CR0 update: CR0=0x%08x\n", env->cr[0]); +#endif + pg_state = env->cr[0] & CR0_PG_MASK; + if (pg_state != last_pg_state) { + page_unmap(); + tlb_flush(env); + last_pg_state = pg_state; + } + pe_state = env->cr[0] & CR0_PE_MASK; + if (last_pe_state != pe_state) { + tb_flush(); + last_pe_state = pe_state; + } +} + +void cpu_x86_update_cr3(CPUX86State *env) +{ + if (env->cr[0] & CR0_PG_MASK) { +#if defined(DEBUG_MMU) + printf("CR3 update: CR3=%08x\n", env->cr[3]); +#endif + page_unmap(); + tlb_flush(env); + } +} + +void cpu_x86_init_mmu(CPUX86State *env) +{ + last_pg_state = -1; + cpu_x86_update_cr0(env); +} + +/* XXX: also flush 4MB pages */ +void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) +{ + int flags; + unsigned long virt_addr; + + tlb_flush_page(env, addr); + + flags = page_get_flags(addr); + if (flags & PAGE_VALID) { + virt_addr = addr & ~0xfff; + munmap((void *)virt_addr, 4096); + page_set_flags(virt_addr, virt_addr + 4096, 0); + } +} + +/* return value: + -1 = cannot handle fault + 0 = nothing more to do + 1 = generate PF fault + 2 = soft MMU activation required for this block +*/ +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) +{ + uint8_t *pde_ptr, *pte_ptr; + uint32_t pde, pte, virt_addr; + int cpl, error_code, is_dirty, is_user, prot, page_size, ret; + unsigned long pd; + + cpl = env->hflags & HF_CPL_MASK; + is_user = (cpl == 3); + +#ifdef DEBUG_MMU + printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", + addr, is_write, is_user, env->eip); +#endif + + if (env->user_mode_only) { + /* user mode only emulation */ + error_code = 0; + goto do_fault; + } + + if (!(env->cr[0] & CR0_PG_MASK)) { + pte = addr; + virt_addr = addr & ~0xfff; + prot = PROT_READ | PROT_WRITE; + page_size = 4096; + goto do_mapping; + } + + /* page directory entry */ + pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); + pde = ldl(pde_ptr); + if (!(pde & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (is_user) { + if (!(pde & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && + is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } + /* if PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + is_dirty = is_write && !(pde & PG_DIRTY_MASK); + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_DIRTY_MASK; + stl(pde_ptr, pde); + } + + pte = pde & ~0x003ff000; /* align to 4MB */ + page_size = 4096 * 1024; + virt_addr = addr & ~0x003fffff; + } else { + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl(pde_ptr, pde); + } + + /* page directory entry */ + pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); + pte = ldl(pte_ptr); + if (!(pte & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (is_user) { + if (!(pte & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pte & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && + is_write && !(pte & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) + pte |= PG_DIRTY_MASK; + stl(pte_ptr, pte); + } + page_size = 4096; + virt_addr = addr & ~0xfff; + } + /* the page can be put in the TLB */ + prot = PROT_READ; + if (is_user) { + if (pte & PG_RW_MASK) + prot |= PROT_WRITE; + } else { + if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || + (pte & PG_RW_MASK)) + prot |= PROT_WRITE; + } + + do_mapping: + if (env->hflags & HF_SOFTMMU_MASK) { + unsigned long paddr, vaddr, address, addend, page_offset; + int index; + + /* software MMU case. Even if 4MB pages, we map only one 4KB + page in the cache to avoid filling it too fast */ + page_offset = (addr & ~0xfff) & (page_size - 1); + paddr = (pte & ~0xfff) + page_offset; + vaddr = virt_addr + page_offset; + index = (addr >> 12) & (CPU_TLB_SIZE - 1); + pd = physpage_find(paddr); + if (pd & 0xfff) { + /* IO memory case */ + address = vaddr | pd; + addend = paddr; + } else { + /* standard memory */ + address = vaddr; + addend = (unsigned long)phys_ram_base + pd; + } + addend -= vaddr; + env->tlb_read[is_user][index].address = address; + env->tlb_read[is_user][index].addend = addend; + if (prot & PROT_WRITE) { + env->tlb_write[is_user][index].address = address; + env->tlb_write[is_user][index].addend = addend; + } + } + ret = 0; + /* XXX: incorrect for 4MB pages */ + pd = physpage_find(pte & ~0xfff); + if ((pd & 0xfff) != 0) { + /* IO access: no mapping is done as it will be handled by the + soft MMU */ + if (!(env->hflags & HF_SOFTMMU_MASK)) + ret = 2; + } else { + void *map_addr; + map_addr = mmap((void *)virt_addr, page_size, prot, + MAP_SHARED | MAP_FIXED, phys_ram_fd, pd); + if (map_addr == MAP_FAILED) { + fprintf(stderr, + "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", + pte & ~0xfff, virt_addr); + exit(1); + } +#ifdef DEBUG_MMU + printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", + pte & ~0xfff, virt_addr, (page_size != 4096)); +#endif + page_set_flags(virt_addr, virt_addr + page_size, + PAGE_VALID | PAGE_EXEC | prot); + } + return ret; + do_fault_protect: + error_code = PG_ERROR_P_MASK; + do_fault: + env->cr[2] = addr; + env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; + if (is_user) + env->error_code |= PG_ERROR_U_MASK; + return 1; +} diff --git a/target-i386/op.c b/target-i386/op.c new file mode 100644 index 000000000..68191f9bc --- /dev/null +++ b/target-i386/op.c @@ -0,0 +1,2054 @@ +/* + * i386 micro operations + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "exec.h" + +/* n must be a constant to be efficient */ +static inline int lshift(int x, int n) +{ + if (n >= 0) + return x << n; + else + return x >> (-n); +} + +/* we define the various pieces of code used by the JIT */ + +#define REG EAX +#define REGNAME _EAX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ECX +#define REGNAME _ECX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EDX +#define REGNAME _EDX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EBX +#define REGNAME _EBX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ESP +#define REGNAME _ESP +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EBP +#define REGNAME _EBP +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ESI +#define REGNAME _ESI +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EDI +#define REGNAME _EDI +#include "opreg_template.h" +#undef REG +#undef REGNAME + +/* operations with flags */ + +/* update flags with T0 and T1 (add/sub case) */ +void OPPROTO op_update2_cc(void) +{ + CC_SRC = T1; + CC_DST = T0; +} + +/* update flags with T0 (logic operation case) */ +void OPPROTO op_update1_cc(void) +{ + CC_DST = T0; +} + +void OPPROTO op_update_neg_cc(void) +{ + CC_SRC = -T0; + CC_DST = T0; +} + +void OPPROTO op_cmpl_T0_T1_cc(void) +{ + CC_SRC = T1; + CC_DST = T0 - T1; +} + +void OPPROTO op_update_inc_cc(void) +{ + CC_SRC = cc_table[CC_OP].compute_c(); + CC_DST = T0; +} + +void OPPROTO op_testl_T0_T1_cc(void) +{ + CC_DST = T0 & T1; +} + +/* operations without flags */ + +void OPPROTO op_addl_T0_T1(void) +{ + T0 += T1; +} + +void OPPROTO op_orl_T0_T1(void) +{ + T0 |= T1; +} + +void OPPROTO op_andl_T0_T1(void) +{ + T0 &= T1; +} + +void OPPROTO op_subl_T0_T1(void) +{ + T0 -= T1; +} + +void OPPROTO op_xorl_T0_T1(void) +{ + T0 ^= T1; +} + +void OPPROTO op_negl_T0(void) +{ + T0 = -T0; +} + +void OPPROTO op_incl_T0(void) +{ + T0++; +} + +void OPPROTO op_decl_T0(void) +{ + T0--; +} + +void OPPROTO op_notl_T0(void) +{ + T0 = ~T0; +} + +void OPPROTO op_bswapl_T0(void) +{ + T0 = bswap32(T0); +} + +/* multiply/divide */ +void OPPROTO op_mulb_AL_T0(void) +{ + unsigned int res; + res = (uint8_t)EAX * (uint8_t)T0; + EAX = (EAX & 0xffff0000) | res; + CC_SRC = (res & 0xff00); +} + +void OPPROTO op_imulb_AL_T0(void) +{ + int res; + res = (int8_t)EAX * (int8_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + CC_SRC = (res != (int8_t)res); +} + +void OPPROTO op_mulw_AX_T0(void) +{ + unsigned int res; + res = (uint16_t)EAX * (uint16_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + CC_SRC = res >> 16; +} + +void OPPROTO op_imulw_AX_T0(void) +{ + int res; + res = (int16_t)EAX * (int16_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + CC_SRC = (res != (int16_t)res); +} + +void OPPROTO op_mull_EAX_T0(void) +{ + uint64_t res; + res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0); + EAX = res; + EDX = res >> 32; + CC_SRC = res >> 32; +} + +void OPPROTO op_imull_EAX_T0(void) +{ + int64_t res; + res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0); + EAX = res; + EDX = res >> 32; + CC_SRC = (res != (int32_t)res); +} + +void OPPROTO op_imulw_T0_T1(void) +{ + int res; + res = (int16_t)T0 * (int16_t)T1; + T0 = res; + CC_SRC = (res != (int16_t)res); +} + +void OPPROTO op_imull_T0_T1(void) +{ + int64_t res; + res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); + T0 = res; + CC_SRC = (res != (int32_t)res); +} + +/* division, flags are undefined */ +/* XXX: add exceptions for overflow */ + +void OPPROTO op_divb_AL_T0(void) +{ + unsigned int num, den, q, r; + + num = (EAX & 0xffff); + den = (T0 & 0xff); + if (den == 0) { + EIP = PARAM1; + raise_exception(EXCP00_DIVZ); + } + q = (num / den) & 0xff; + r = (num % den) & 0xff; + EAX = (EAX & 0xffff0000) | (r << 8) | q; +} + +void OPPROTO op_idivb_AL_T0(void) +{ + int num, den, q, r; + + num = (int16_t)EAX; + den = (int8_t)T0; + if (den == 0) { + EIP = PARAM1; + raise_exception(EXCP00_DIVZ); + } + q = (num / den) & 0xff; + r = (num % den) & 0xff; + EAX = (EAX & 0xffff0000) | (r << 8) | q; +} + +void OPPROTO op_divw_AX_T0(void) +{ + unsigned int num, den, q, r; + + num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); + den = (T0 & 0xffff); + if (den == 0) { + EIP = PARAM1; + raise_exception(EXCP00_DIVZ); + } + q = (num / den) & 0xffff; + r = (num % den) & 0xffff; + EAX = (EAX & 0xffff0000) | q; + EDX = (EDX & 0xffff0000) | r; +} + +void OPPROTO op_idivw_AX_T0(void) +{ + int num, den, q, r; + + num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); + den = (int16_t)T0; + if (den == 0) { + EIP = PARAM1; + raise_exception(EXCP00_DIVZ); + } + q = (num / den) & 0xffff; + r = (num % den) & 0xffff; + EAX = (EAX & 0xffff0000) | q; + EDX = (EDX & 0xffff0000) | r; +} + +void OPPROTO op_divl_EAX_T0(void) +{ + helper_divl_EAX_T0(PARAM1); +} + +void OPPROTO op_idivl_EAX_T0(void) +{ + helper_idivl_EAX_T0(PARAM1); +} + +/* constant load & misc op */ + +void OPPROTO op_movl_T0_im(void) +{ + T0 = PARAM1; +} + +void OPPROTO op_addl_T0_im(void) +{ + T0 += PARAM1; +} + +void OPPROTO op_andl_T0_ffff(void) +{ + T0 = T0 & 0xffff; +} + +void OPPROTO op_andl_T0_im(void) +{ + T0 = T0 & PARAM1; +} + +void OPPROTO op_movl_T0_T1(void) +{ + T0 = T1; +} + +void OPPROTO op_movl_T1_im(void) +{ + T1 = PARAM1; +} + +void OPPROTO op_addl_T1_im(void) +{ + T1 += PARAM1; +} + +void OPPROTO op_movl_T1_A0(void) +{ + T1 = A0; +} + +void OPPROTO op_movl_A0_im(void) +{ + A0 = PARAM1; +} + +void OPPROTO op_addl_A0_im(void) +{ + A0 += PARAM1; +} + +void OPPROTO op_addl_A0_AL(void) +{ + A0 += (EAX & 0xff); +} + +void OPPROTO op_andl_A0_ffff(void) +{ + A0 = A0 & 0xffff; +} + +/* memory access */ + +#define MEMSUFFIX +#include "ops_mem.h" + +#define MEMSUFFIX _user +#include "ops_mem.h" + +#define MEMSUFFIX _kernel +#include "ops_mem.h" + +/* used for bit operations */ + +void OPPROTO op_add_bitw_A0_T1(void) +{ + A0 += ((int32_t)T1 >> 4) << 1; +} + +void OPPROTO op_add_bitl_A0_T1(void) +{ + A0 += ((int32_t)T1 >> 5) << 2; +} + +/* indirect jump */ + +void OPPROTO op_jmp_T0(void) +{ + EIP = T0; +} + +void OPPROTO op_jmp_im(void) +{ + EIP = PARAM1; +} + +void OPPROTO op_hlt(void) +{ + env->exception_index = EXCP_HLT; + cpu_loop_exit(); +} + +void OPPROTO op_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + +void OPPROTO op_raise_interrupt(void) +{ + int intno; + unsigned int next_eip; + intno = PARAM1; + next_eip = PARAM2; + raise_interrupt(intno, 1, 0, next_eip); +} + +void OPPROTO op_raise_exception(void) +{ + int exception_index; + exception_index = PARAM1; + raise_exception(exception_index); +} + +void OPPROTO op_into(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + if (eflags & CC_O) { + raise_interrupt(EXCP04_INTO, 1, 0, PARAM1); + } + FORCE_RET(); +} + +void OPPROTO op_cli(void) +{ + env->eflags &= ~IF_MASK; +} + +void OPPROTO op_sti(void) +{ + env->eflags |= IF_MASK; +} + +void OPPROTO op_set_inhibit_irq(void) +{ + env->hflags |= HF_INHIBIT_IRQ_MASK; +} + +void OPPROTO op_reset_inhibit_irq(void) +{ + env->hflags &= ~HF_INHIBIT_IRQ_MASK; +} + +#if 0 +/* vm86plus instructions */ +void OPPROTO op_cli_vm(void) +{ + env->eflags &= ~VIF_MASK; +} + +void OPPROTO op_sti_vm(void) +{ + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + FORCE_RET(); +} +#endif + +void OPPROTO op_boundw(void) +{ + int low, high, v; + low = ldsw((uint8_t *)A0); + high = ldsw((uint8_t *)A0 + 2); + v = (int16_t)T0; + if (v < low || v > high) { + EIP = PARAM1; + raise_exception(EXCP05_BOUND); + } + FORCE_RET(); +} + +void OPPROTO op_boundl(void) +{ + int low, high, v; + low = ldl((uint8_t *)A0); + high = ldl((uint8_t *)A0 + 4); + v = T0; + if (v < low || v > high) { + EIP = PARAM1; + raise_exception(EXCP05_BOUND); + } + FORCE_RET(); +} + +void OPPROTO op_cmpxchg8b(void) +{ + helper_cmpxchg8b(); +} + +void OPPROTO op_jmp(void) +{ + JUMP_TB(op_jmp, PARAM1, 0, PARAM2); +} + +void OPPROTO op_movl_T0_0(void) +{ + T0 = 0; +} + +void OPPROTO op_exit_tb(void) +{ + EXIT_TB(); +} + +/* multiple size ops */ + +#define ldul ldl + +#define SHIFT 0 +#include "ops_template.h" +#undef SHIFT + +#define SHIFT 1 +#include "ops_template.h" +#undef SHIFT + +#define SHIFT 2 +#include "ops_template.h" +#undef SHIFT + +/* sign extend */ + +void OPPROTO op_movsbl_T0_T0(void) +{ + T0 = (int8_t)T0; +} + +void OPPROTO op_movzbl_T0_T0(void) +{ + T0 = (uint8_t)T0; +} + +void OPPROTO op_movswl_T0_T0(void) +{ + T0 = (int16_t)T0; +} + +void OPPROTO op_movzwl_T0_T0(void) +{ + T0 = (uint16_t)T0; +} + +void OPPROTO op_movswl_EAX_AX(void) +{ + EAX = (int16_t)EAX; +} + +void OPPROTO op_movsbw_AX_AL(void) +{ + EAX = (EAX & 0xffff0000) | ((int8_t)EAX & 0xffff); +} + +void OPPROTO op_movslq_EDX_EAX(void) +{ + EDX = (int32_t)EAX >> 31; +} + +void OPPROTO op_movswl_DX_AX(void) +{ + EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff); +} + +/* string ops helpers */ + +void OPPROTO op_addl_ESI_T0(void) +{ + ESI += T0; +} + +void OPPROTO op_addw_ESI_T0(void) +{ + ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff); +} + +void OPPROTO op_addl_EDI_T0(void) +{ + EDI += T0; +} + +void OPPROTO op_addw_EDI_T0(void) +{ + EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff); +} + +void OPPROTO op_decl_ECX(void) +{ + ECX--; +} + +void OPPROTO op_decw_ECX(void) +{ + ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff); +} + +/* push/pop */ + +void op_pushl_T0(void) +{ + uint32_t offset; + offset = ESP - 4; + stl((void *)offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_pushw_T0(void) +{ + uint32_t offset; + offset = ESP - 2; + stw((void *)offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_pushl_ss32_T0(void) +{ + uint32_t offset; + offset = ESP - 4; + stl(env->segs[R_SS].base + offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_pushw_ss32_T0(void) +{ + uint32_t offset; + offset = ESP - 2; + stw(env->segs[R_SS].base + offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_pushl_ss16_T0(void) +{ + uint32_t offset; + offset = (ESP - 4) & 0xffff; + stl(env->segs[R_SS].base + offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = (ESP & ~0xffff) | offset; +} + +void op_pushw_ss16_T0(void) +{ + uint32_t offset; + offset = (ESP - 2) & 0xffff; + stw(env->segs[R_SS].base + offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = (ESP & ~0xffff) | offset; +} + +/* NOTE: ESP update is done after */ +void op_popl_T0(void) +{ + T0 = ldl((void *)ESP); +} + +void op_popw_T0(void) +{ + T0 = lduw((void *)ESP); +} + +void op_popl_ss32_T0(void) +{ + T0 = ldl(env->segs[R_SS].base + ESP); +} + +void op_popw_ss32_T0(void) +{ + T0 = lduw(env->segs[R_SS].base + ESP); +} + +void op_popl_ss16_T0(void) +{ + T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff)); +} + +void op_popw_ss16_T0(void) +{ + T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff)); +} + +void op_addl_ESP_4(void) +{ + ESP += 4; +} + +void op_addl_ESP_2(void) +{ + ESP += 2; +} + +void op_addw_ESP_4(void) +{ + ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff); +} + +void op_addw_ESP_2(void) +{ + ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff); +} + +void op_addl_ESP_im(void) +{ + ESP += PARAM1; +} + +void op_addw_ESP_im(void) +{ + ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff); +} + +void OPPROTO op_rdtsc(void) +{ + helper_rdtsc(); +} + +void OPPROTO op_cpuid(void) +{ + helper_cpuid(); +} + +void OPPROTO op_rdmsr(void) +{ + helper_rdmsr(); +} + +void OPPROTO op_wrmsr(void) +{ + helper_wrmsr(); +} + +/* bcd */ + +/* XXX: exception */ +void OPPROTO op_aam(void) +{ + int base = PARAM1; + int al, ah; + al = EAX & 0xff; + ah = al / base; + al = al % base; + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_DST = al; +} + +void OPPROTO op_aad(void) +{ + int base = PARAM1; + int al, ah; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + al = ((ah * base) + al) & 0xff; + EAX = (EAX & ~0xffff) | al; + CC_DST = al; +} + +void OPPROTO op_aaa(void) +{ + int icarry; + int al, ah, af; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + af = eflags & CC_A; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + + icarry = (al > 0xf9); + if (((al & 0x0f) > 9 ) || af) { + al = (al + 6) & 0x0f; + ah = (ah + 1 + icarry) & 0xff; + eflags |= CC_C | CC_A; + } else { + eflags &= ~(CC_C | CC_A); + al &= 0x0f; + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; +} + +void OPPROTO op_aas(void) +{ + int icarry; + int al, ah, af; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + af = eflags & CC_A; + al = EAX & 0xff; + ah = (EAX >> 8) & 0xff; + + icarry = (al < 6); + if (((al & 0x0f) > 9 ) || af) { + al = (al - 6) & 0x0f; + ah = (ah - 1 - icarry) & 0xff; + eflags |= CC_C | CC_A; + } else { + eflags &= ~(CC_C | CC_A); + al &= 0x0f; + } + EAX = (EAX & ~0xffff) | al | (ah << 8); + CC_SRC = eflags; +} + +void OPPROTO op_daa(void) +{ + int al, af, cf; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + cf = eflags & CC_C; + af = eflags & CC_A; + al = EAX & 0xff; + + eflags = 0; + if (((al & 0x0f) > 9 ) || af) { + al = (al + 6) & 0xff; + eflags |= CC_A; + } + if ((al > 0x9f) || cf) { + al = (al + 0x60) & 0xff; + eflags |= CC_C; + } + EAX = (EAX & ~0xff) | al; + /* well, speed is not an issue here, so we compute the flags by hand */ + eflags |= (al == 0) << 6; /* zf */ + eflags |= parity_table[al]; /* pf */ + eflags |= (al & 0x80); /* sf */ + CC_SRC = eflags; +} + +void OPPROTO op_das(void) +{ + int al, al1, af, cf; + int eflags; + + eflags = cc_table[CC_OP].compute_all(); + cf = eflags & CC_C; + af = eflags & CC_A; + al = EAX & 0xff; + + eflags = 0; + al1 = al; + if (((al & 0x0f) > 9 ) || af) { + eflags |= CC_A; + if (al < 6 || cf) + eflags |= CC_C; + al = (al - 6) & 0xff; + } + if ((al1 > 0x99) || cf) { + al = (al - 0x60) & 0xff; + eflags |= CC_C; + } + EAX = (EAX & ~0xff) | al; + /* well, speed is not an issue here, so we compute the flags by hand */ + eflags |= (al == 0) << 6; /* zf */ + eflags |= parity_table[al]; /* pf */ + eflags |= (al & 0x80); /* sf */ + CC_SRC = eflags; +} + +/* segment handling */ + +/* never use it with R_CS */ +void OPPROTO op_movl_seg_T0(void) +{ + load_seg(PARAM1, T0 & 0xffff, PARAM2); +} + +/* faster VM86 version */ +void OPPROTO op_movl_seg_T0_vm(void) +{ + int selector; + SegmentCache *sc; + + selector = T0 & 0xffff; + /* env->segs[] access */ + sc = (SegmentCache *)((char *)env + PARAM1); + sc->selector = selector; + sc->base = (void *)(selector << 4); +} + +void OPPROTO op_movl_T0_seg(void) +{ + T0 = env->segs[PARAM1].selector; +} + +void OPPROTO op_movl_A0_seg(void) +{ + A0 = *(unsigned long *)((char *)env + PARAM1); +} + +void OPPROTO op_addl_A0_seg(void) +{ + A0 += *(unsigned long *)((char *)env + PARAM1); +} + +void OPPROTO op_lsl(void) +{ + helper_lsl(); +} + +void OPPROTO op_lar(void) +{ + helper_lar(); +} + +/* T0: segment, T1:eip */ +void OPPROTO op_ljmp_protected_T0_T1(void) +{ + helper_ljmp_protected_T0_T1(); +} + +void OPPROTO op_lcall_real_T0_T1(void) +{ + helper_lcall_real_T0_T1(PARAM1, PARAM2); +} + +void OPPROTO op_lcall_protected_T0_T1(void) +{ + helper_lcall_protected_T0_T1(PARAM1, PARAM2); +} + +void OPPROTO op_iret_real(void) +{ + helper_iret_real(PARAM1); +} + +void OPPROTO op_iret_protected(void) +{ + helper_iret_protected(PARAM1); +} + +void OPPROTO op_lret_protected(void) +{ + helper_lret_protected(PARAM1, PARAM2); +} + +void OPPROTO op_lldt_T0(void) +{ + helper_lldt_T0(); +} + +void OPPROTO op_ltr_T0(void) +{ + helper_ltr_T0(); +} + +/* CR registers access */ +void OPPROTO op_movl_crN_T0(void) +{ + helper_movl_crN_T0(PARAM1); +} + +/* DR registers access */ +void OPPROTO op_movl_drN_T0(void) +{ + helper_movl_drN_T0(PARAM1); +} + +void OPPROTO op_lmsw_T0(void) +{ + /* only 4 lower bits of CR0 are modified */ + T0 = (env->cr[0] & ~0xf) | (T0 & 0xf); + helper_movl_crN_T0(0); +} + +void OPPROTO op_invlpg_A0(void) +{ + helper_invlpg(A0); +} + +void OPPROTO op_movl_T0_env(void) +{ + T0 = *(uint32_t *)((char *)env + PARAM1); +} + +void OPPROTO op_movl_env_T0(void) +{ + *(uint32_t *)((char *)env + PARAM1) = T0; +} + +void OPPROTO op_movl_env_T1(void) +{ + *(uint32_t *)((char *)env + PARAM1) = T1; +} + +void OPPROTO op_clts(void) +{ + env->cr[0] &= ~CR0_TS_MASK; +} + +/* flags handling */ + +/* slow jumps cases : in order to avoid calling a function with a + pointer (which can generate a stack frame on PowerPC), we use + op_setcc to set T0 and then call op_jcc. */ +void OPPROTO op_jcc(void) +{ + if (T0) + JUMP_TB(op_jcc, PARAM1, 0, PARAM2); + else + JUMP_TB(op_jcc, PARAM1, 1, PARAM3); + FORCE_RET(); +} + +void OPPROTO op_jcc_im(void) +{ + if (T0) + EIP = PARAM1; + else + EIP = PARAM2; + FORCE_RET(); +} + +/* slow set cases (compute x86 flags) */ +void OPPROTO op_seto_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags >> 11) & 1; +} + +void OPPROTO op_setb_T0_cc(void) +{ + T0 = cc_table[CC_OP].compute_c(); +} + +void OPPROTO op_setz_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags >> 6) & 1; +} + +void OPPROTO op_setbe_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags & (CC_Z | CC_C)) != 0; +} + +void OPPROTO op_sets_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags >> 7) & 1; +} + +void OPPROTO op_setp_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (eflags >> 2) & 1; +} + +void OPPROTO op_setl_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = ((eflags ^ (eflags >> 4)) >> 7) & 1; +} + +void OPPROTO op_setle_T0_cc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + T0 = (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) != 0; +} + +void OPPROTO op_xor_T0_1(void) +{ + T0 ^= 1; +} + +void OPPROTO op_set_cc_op(void) +{ + CC_OP = PARAM1; +} + +#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff) + +void OPPROTO op_movl_eflags_T0(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | + (eflags & FL_UPDATE_MASK32); +} + +void OPPROTO op_movw_eflags_T0(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | + (eflags & FL_UPDATE_MASK16); +} + +void OPPROTO op_movl_eflags_T0_cpl0(void) +{ + load_eflags(T0, FL_UPDATE_CPL0_MASK); +} + +void OPPROTO op_movw_eflags_T0_cpl0(void) +{ + load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff); +} + +#if 0 +/* vm86plus version */ +void OPPROTO op_movw_eflags_T0_vm(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) | + (eflags & FL_UPDATE_MASK16); + if (eflags & IF_MASK) { + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + } + FORCE_RET(); +} + +void OPPROTO op_movl_eflags_T0_vm(void) +{ + int eflags; + eflags = T0; + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((eflags >> 10) & 1)); + /* we also update some system flags as in user mode */ + env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) | + (eflags & FL_UPDATE_MASK32); + if (eflags & IF_MASK) { + env->eflags |= VIF_MASK; + if (env->eflags & VIP_MASK) { + EIP = PARAM1; + raise_exception(EXCP0D_GPF); + } + } + FORCE_RET(); +} +#endif + +/* XXX: compute only O flag */ +void OPPROTO op_movb_eflags_T0(void) +{ + int of; + of = cc_table[CC_OP].compute_all() & CC_O; + CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of; +} + +void OPPROTO op_movl_T0_eflags(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DF_MASK); + eflags |= env->eflags & ~(VM_MASK | RF_MASK); + T0 = eflags; +} + +/* vm86plus version */ +#if 0 +void OPPROTO op_movl_T0_eflags_vm(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= (DF & DF_MASK); + eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); + if (env->eflags & VIF_MASK) + eflags |= IF_MASK; + T0 = eflags; +} +#endif + +void OPPROTO op_cld(void) +{ + DF = 1; +} + +void OPPROTO op_std(void) +{ + DF = -1; +} + +void OPPROTO op_clc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags &= ~CC_C; + CC_SRC = eflags; +} + +void OPPROTO op_stc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags |= CC_C; + CC_SRC = eflags; +} + +void OPPROTO op_cmc(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags ^= CC_C; + CC_SRC = eflags; +} + +void OPPROTO op_salc(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + EAX = (EAX & ~0xff) | ((-cf) & 0xff); +} + +static int compute_all_eflags(void) +{ + return CC_SRC; +} + +static int compute_c_eflags(void) +{ + return CC_SRC & CC_C; +} + +static int compute_c_mul(void) +{ + int cf; + cf = (CC_SRC != 0); + return cf; +} + +static int compute_all_mul(void) +{ + int cf, pf, af, zf, sf, of; + cf = (CC_SRC != 0); + pf = 0; /* undefined */ + af = 0; /* undefined */ + zf = 0; /* undefined */ + sf = 0; /* undefined */ + of = cf << 11; + return cf | pf | af | zf | sf | of; +} + +CCTable cc_table[CC_OP_NB] = { + [CC_OP_DYNAMIC] = { /* should never happen */ }, + + [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags }, + + [CC_OP_MUL] = { compute_all_mul, compute_c_mul }, + + [CC_OP_ADDB] = { compute_all_addb, compute_c_addb }, + [CC_OP_ADDW] = { compute_all_addw, compute_c_addw }, + [CC_OP_ADDL] = { compute_all_addl, compute_c_addl }, + + [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb }, + [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw }, + [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl }, + + [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, + [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, + [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, + + [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb }, + [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw }, + [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl }, + + [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, + [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, + [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, + + [CC_OP_INCB] = { compute_all_incb, compute_c_incl }, + [CC_OP_INCW] = { compute_all_incw, compute_c_incl }, + [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, + + [CC_OP_DECB] = { compute_all_decb, compute_c_incl }, + [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, + [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, + + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, + [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, + [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, + + [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl }, + [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl }, + [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl }, +}; + +/* floating point support. Some of the code for complicated x87 + functions comes from the LGPL'ed x86 emulator found in the Willows + TWIN windows emulator. */ + +#if defined(__powerpc__) +extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble); + +/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ +double qemu_rint(double x) +{ + double y = 4503599627370496.0; + if (fabs(x) >= y) + return x; + if (x < 0) + y = -y; + y = (x + y) - y; + if (y == 0.0) + y = copysign(y, x); + return y; +} + +#define rint qemu_rint +#endif + +/* fp load FT0 */ + +void OPPROTO op_flds_FT0_A0(void) +{ +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldl((void *)A0); + FT0 = FP_CONVERT.f; +#else + FT0 = ldfl((void *)A0); +#endif +} + +void OPPROTO op_fldl_FT0_A0(void) +{ +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = ldq((void *)A0); + FT0 = FP_CONVERT.d; +#else + FT0 = ldfq((void *)A0); +#endif +} + +/* helpers are needed to avoid static constant reference. XXX: find a better way */ +#ifdef USE_INT_TO_FLOAT_HELPERS + +void helper_fild_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)ldsw((void *)A0); +} + +void helper_fildl_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +} + +void helper_fildll_FT0_A0(void) +{ + FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +} + +void OPPROTO op_fild_FT0_A0(void) +{ + helper_fild_FT0_A0(); +} + +void OPPROTO op_fildl_FT0_A0(void) +{ + helper_fildl_FT0_A0(); +} + +void OPPROTO op_fildll_FT0_A0(void) +{ + helper_fildll_FT0_A0(); +} + +#else + +void OPPROTO op_fild_FT0_A0(void) +{ +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldsw((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i32; +#else + FT0 = (CPU86_LDouble)ldsw((void *)A0); +#endif +} + +void OPPROTO op_fildl_FT0_A0(void) +{ +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = (int32_t) ldl((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i32; +#else + FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +#endif +} + +void OPPROTO op_fildll_FT0_A0(void) +{ +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = (int64_t) ldq((void *)A0); + FT0 = (CPU86_LDouble)FP_CONVERT.i64; +#else + FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +#endif +} +#endif + +/* fp load ST0 */ + +void OPPROTO op_flds_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldl((void *)A0); + env->fpregs[new_fpstt] = FP_CONVERT.f; +#else + env->fpregs[new_fpstt] = ldfl((void *)A0); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void OPPROTO op_fldl_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = ldq((void *)A0); + env->fpregs[new_fpstt] = FP_CONVERT.d; +#else + env->fpregs[new_fpstt] = ldfq((void *)A0); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +#ifdef USE_X86LDOUBLE +void OPPROTO op_fldt_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = *(long double *)A0; + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} +#else +void OPPROTO op_fldt_ST0_A0(void) +{ + helper_fldt_ST0_A0(); +} +#endif + +/* helpers are needed to avoid static constant reference. XXX: find a better way */ +#ifdef USE_INT_TO_FLOAT_HELPERS + +void helper_fild_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void helper_fildl_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void helper_fildll_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; + env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void OPPROTO op_fild_ST0_A0(void) +{ + helper_fild_ST0_A0(); +} + +void OPPROTO op_fildl_ST0_A0(void) +{ + helper_fildl_ST0_A0(); +} + +void OPPROTO op_fildll_ST0_A0(void) +{ + helper_fildll_ST0_A0(); +} + +#else + +void OPPROTO op_fild_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = ldsw((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; +#else + env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void OPPROTO op_fildl_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i32 = (int32_t) ldl((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; +#else + env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +void OPPROTO op_fildll_ST0_A0(void) +{ + int new_fpstt; + new_fpstt = (env->fpstt - 1) & 7; +#ifdef USE_FP_CONVERT + FP_CONVERT.i64 = (int64_t) ldq((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64; +#else + env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); +#endif + env->fpstt = new_fpstt; + env->fptags[new_fpstt] = 0; /* validate stack entry */ +} + +#endif + +/* fp store */ + +void OPPROTO op_fsts_ST0_A0(void) +{ +#ifdef USE_FP_CONVERT + FP_CONVERT.f = (float)ST0; + stfl((void *)A0, FP_CONVERT.f); +#else + stfl((void *)A0, (float)ST0); +#endif +} + +void OPPROTO op_fstl_ST0_A0(void) +{ + stfq((void *)A0, (double)ST0); +} + +#ifdef USE_X86LDOUBLE +void OPPROTO op_fstt_ST0_A0(void) +{ + *(long double *)A0 = ST0; +} +#else +void OPPROTO op_fstt_ST0_A0(void) +{ + helper_fstt_ST0_A0(); +} +#endif + +void OPPROTO op_fist_ST0_A0(void) +{ +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif + int val; + + d = ST0; + val = lrint(d); + if (val != (int16_t)val) + val = -32768; + stw((void *)A0, val); +} + +void OPPROTO op_fistl_ST0_A0(void) +{ +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif + int val; + + d = ST0; + val = lrint(d); + stl((void *)A0, val); +} + +void OPPROTO op_fistll_ST0_A0(void) +{ +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif + int64_t val; + + d = ST0; + val = llrint(d); + stq((void *)A0, val); +} + +void OPPROTO op_fbld_ST0_A0(void) +{ + helper_fbld_ST0_A0(); +} + +void OPPROTO op_fbst_ST0_A0(void) +{ + helper_fbst_ST0_A0(); +} + +/* FPU move */ + +void OPPROTO op_fpush(void) +{ + fpush(); +} + +void OPPROTO op_fpop(void) +{ + fpop(); +} + +void OPPROTO op_fdecstp(void) +{ + env->fpstt = (env->fpstt - 1) & 7; + env->fpus &= (~0x4700); +} + +void OPPROTO op_fincstp(void) +{ + env->fpstt = (env->fpstt + 1) & 7; + env->fpus &= (~0x4700); +} + +void OPPROTO op_fmov_ST0_FT0(void) +{ + ST0 = FT0; +} + +void OPPROTO op_fmov_FT0_STN(void) +{ + FT0 = ST(PARAM1); +} + +void OPPROTO op_fmov_ST0_STN(void) +{ + ST0 = ST(PARAM1); +} + +void OPPROTO op_fmov_STN_ST0(void) +{ + ST(PARAM1) = ST0; +} + +void OPPROTO op_fxchg_ST0_STN(void) +{ + CPU86_LDouble tmp; + tmp = ST(PARAM1); + ST(PARAM1) = ST0; + ST0 = tmp; +} + +/* FPU operations */ + +/* XXX: handle nans */ +void OPPROTO op_fcom_ST0_FT0(void) +{ + env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ + if (ST0 < FT0) + env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ + else if (ST0 == FT0) + env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ + FORCE_RET(); +} + +/* XXX: handle nans */ +void OPPROTO op_fucom_ST0_FT0(void) +{ + env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ + if (ST0 < FT0) + env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ + else if (ST0 == FT0) + env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ + FORCE_RET(); +} + +/* XXX: handle nans */ +void OPPROTO op_fcomi_ST0_FT0(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags &= ~(CC_Z | CC_P | CC_C); + if (ST0 < FT0) + eflags |= CC_C; + else if (ST0 == FT0) + eflags |= CC_Z; + CC_SRC = eflags; + FORCE_RET(); +} + +/* XXX: handle nans */ +void OPPROTO op_fucomi_ST0_FT0(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + eflags &= ~(CC_Z | CC_P | CC_C); + if (ST0 < FT0) + eflags |= CC_C; + else if (ST0 == FT0) + eflags |= CC_Z; + CC_SRC = eflags; + FORCE_RET(); +} + +void OPPROTO op_fadd_ST0_FT0(void) +{ + ST0 += FT0; +} + +void OPPROTO op_fmul_ST0_FT0(void) +{ + ST0 *= FT0; +} + +void OPPROTO op_fsub_ST0_FT0(void) +{ + ST0 -= FT0; +} + +void OPPROTO op_fsubr_ST0_FT0(void) +{ + ST0 = FT0 - ST0; +} + +void OPPROTO op_fdiv_ST0_FT0(void) +{ + ST0 /= FT0; +} + +void OPPROTO op_fdivr_ST0_FT0(void) +{ + ST0 = FT0 / ST0; +} + +/* fp operations between STN and ST0 */ + +void OPPROTO op_fadd_STN_ST0(void) +{ + ST(PARAM1) += ST0; +} + +void OPPROTO op_fmul_STN_ST0(void) +{ + ST(PARAM1) *= ST0; +} + +void OPPROTO op_fsub_STN_ST0(void) +{ + ST(PARAM1) -= ST0; +} + +void OPPROTO op_fsubr_STN_ST0(void) +{ + CPU86_LDouble *p; + p = &ST(PARAM1); + *p = ST0 - *p; +} + +void OPPROTO op_fdiv_STN_ST0(void) +{ + ST(PARAM1) /= ST0; +} + +void OPPROTO op_fdivr_STN_ST0(void) +{ + CPU86_LDouble *p; + p = &ST(PARAM1); + *p = ST0 / *p; +} + +/* misc FPU operations */ +void OPPROTO op_fchs_ST0(void) +{ + ST0 = -ST0; +} + +void OPPROTO op_fabs_ST0(void) +{ + ST0 = fabs(ST0); +} + +void OPPROTO op_fxam_ST0(void) +{ + helper_fxam_ST0(); +} + +void OPPROTO op_fld1_ST0(void) +{ + ST0 = f15rk[1]; +} + +void OPPROTO op_fldl2t_ST0(void) +{ + ST0 = f15rk[6]; +} + +void OPPROTO op_fldl2e_ST0(void) +{ + ST0 = f15rk[5]; +} + +void OPPROTO op_fldpi_ST0(void) +{ + ST0 = f15rk[2]; +} + +void OPPROTO op_fldlg2_ST0(void) +{ + ST0 = f15rk[3]; +} + +void OPPROTO op_fldln2_ST0(void) +{ + ST0 = f15rk[4]; +} + +void OPPROTO op_fldz_ST0(void) +{ + ST0 = f15rk[0]; +} + +void OPPROTO op_fldz_FT0(void) +{ + ST0 = f15rk[0]; +} + +/* associated heplers to reduce generated code length and to simplify + relocation (FP constants are usually stored in .rodata section) */ + +void OPPROTO op_f2xm1(void) +{ + helper_f2xm1(); +} + +void OPPROTO op_fyl2x(void) +{ + helper_fyl2x(); +} + +void OPPROTO op_fptan(void) +{ + helper_fptan(); +} + +void OPPROTO op_fpatan(void) +{ + helper_fpatan(); +} + +void OPPROTO op_fxtract(void) +{ + helper_fxtract(); +} + +void OPPROTO op_fprem1(void) +{ + helper_fprem1(); +} + + +void OPPROTO op_fprem(void) +{ + helper_fprem(); +} + +void OPPROTO op_fyl2xp1(void) +{ + helper_fyl2xp1(); +} + +void OPPROTO op_fsqrt(void) +{ + helper_fsqrt(); +} + +void OPPROTO op_fsincos(void) +{ + helper_fsincos(); +} + +void OPPROTO op_frndint(void) +{ + helper_frndint(); +} + +void OPPROTO op_fscale(void) +{ + helper_fscale(); +} + +void OPPROTO op_fsin(void) +{ + helper_fsin(); +} + +void OPPROTO op_fcos(void) +{ + helper_fcos(); +} + +void OPPROTO op_fnstsw_A0(void) +{ + int fpus; + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + stw((void *)A0, fpus); +} + +void OPPROTO op_fnstsw_EAX(void) +{ + int fpus; + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + EAX = (EAX & 0xffff0000) | fpus; +} + +void OPPROTO op_fnstcw_A0(void) +{ + stw((void *)A0, env->fpuc); +} + +void OPPROTO op_fldcw_A0(void) +{ + int rnd_type; + env->fpuc = lduw((void *)A0); + /* set rounding mode */ + switch(env->fpuc & RC_MASK) { + default: + case RC_NEAR: + rnd_type = FE_TONEAREST; + break; + case RC_DOWN: + rnd_type = FE_DOWNWARD; + break; + case RC_UP: + rnd_type = FE_UPWARD; + break; + case RC_CHOP: + rnd_type = FE_TOWARDZERO; + break; + } + fesetround(rnd_type); +} + +void OPPROTO op_fclex(void) +{ + env->fpus &= 0x7f00; +} + +void OPPROTO op_fninit(void) +{ + env->fpus = 0; + env->fpstt = 0; + env->fpuc = 0x37f; + env->fptags[0] = 1; + env->fptags[1] = 1; + env->fptags[2] = 1; + env->fptags[3] = 1; + env->fptags[4] = 1; + env->fptags[5] = 1; + env->fptags[6] = 1; + env->fptags[7] = 1; +} + +void OPPROTO op_fnstenv_A0(void) +{ + helper_fstenv((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_fldenv_A0(void) +{ + helper_fldenv((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_fnsave_A0(void) +{ + helper_fsave((uint8_t *)A0, PARAM1); +} + +void OPPROTO op_frstor_A0(void) +{ + helper_frstor((uint8_t *)A0, PARAM1); +} + +/* threading support */ +void OPPROTO op_lock(void) +{ + cpu_lock(); +} + +void OPPROTO op_unlock(void) +{ + cpu_unlock(); +} + diff --git a/target-i386/opreg_template.h b/target-i386/opreg_template.h new file mode 100644 index 000000000..f35a1bbc9 --- /dev/null +++ b/target-i386/opreg_template.h @@ -0,0 +1,134 @@ +/* + * i386 micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +void OPPROTO glue(op_movl_A0,REGNAME)(void) +{ + A0 = REG; +} + +void OPPROTO glue(op_addl_A0,REGNAME)(void) +{ + A0 += REG; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void) +{ + A0 += REG << 1; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void) +{ + A0 += REG << 2; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void) +{ + A0 += REG << 3; +} + +void OPPROTO glue(op_movl_T0,REGNAME)(void) +{ + T0 = REG; +} + +void OPPROTO glue(op_movl_T1,REGNAME)(void) +{ + T1 = REG; +} + +void OPPROTO glue(op_movh_T0,REGNAME)(void) +{ + T0 = REG >> 8; +} + +void OPPROTO glue(op_movh_T1,REGNAME)(void) +{ + T1 = REG >> 8; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void) +{ + REG = T0; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void) +{ + REG = T1; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) +{ + REG = A0; +} + +/* mov T1 to REG if T0 is true */ +void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void) +{ + if (T0) + REG = (REG & 0xffff0000) | (T1 & 0xffff); +} + +void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void) +{ + if (T0) + REG = T1; +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) +{ + REG = (REG & 0xffff0000) | (T0 & 0xffff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void) +{ + REG = (REG & 0xffff0000) | (T1 & 0xffff); +} + +/* NOTE: A0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void) +{ + REG = (REG & 0xffff0000) | (A0 & 0xffff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void) +{ + REG = (REG & 0xffffff00) | (T0 & 0xff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void) +{ + REG = (REG & 0xffff00ff) | ((T0 & 0xff) << 8); +} + +/* NOTE: T1 high order bits are ignored */ +void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void) +{ + REG = (REG & 0xffffff00) | (T1 & 0xff); +} + +/* NOTE: T1 high order bits are ignored */ +void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void) +{ + REG = (REG & 0xffff00ff) | ((T1 & 0xff) << 8); +} diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h new file mode 100644 index 000000000..e1c8277bb --- /dev/null +++ b/target-i386/ops_mem.h @@ -0,0 +1,66 @@ +void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldub, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldsb, MEMSUFFIX)((int8_t *)A0); +} + +void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(lduw, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldsw, MEMSUFFIX)((int8_t *)A0); +} + +void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldl, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldub, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldsb, MEMSUFFIX)((int8_t *)A0); +} + +void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(lduw, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldsw, MEMSUFFIX)((int8_t *)A0); +} + +void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldl, MEMSUFFIX)((uint8_t *)A0); +} + +void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void) +{ + glue(stb, MEMSUFFIX)((uint8_t *)A0, T0); +} + +void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void) +{ + glue(stw, MEMSUFFIX)((uint8_t *)A0, T0); +} + +void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void) +{ + glue(stl, MEMSUFFIX)((uint8_t *)A0, T0); +} + +#undef MEMSUFFIX diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h new file mode 100644 index 000000000..182296743 --- /dev/null +++ b/target-i386/ops_template.h @@ -0,0 +1,617 @@ +/* + * i386 micro operations (included several times to generate + * different operand sizes) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define DATA_BITS (1 << (3 + SHIFT)) +#define SHIFT_MASK (DATA_BITS - 1) +#define SIGN_MASK (1 << (DATA_BITS - 1)) + +#if DATA_BITS == 8 +#define SUFFIX b +#define DATA_TYPE uint8_t +#define DATA_STYPE int8_t +#define DATA_MASK 0xff +#elif DATA_BITS == 16 +#define SUFFIX w +#define DATA_TYPE uint16_t +#define DATA_STYPE int16_t +#define DATA_MASK 0xffff +#elif DATA_BITS == 32 +#define SUFFIX l +#define DATA_TYPE uint32_t +#define DATA_STYPE int32_t +#define DATA_MASK 0xffffffff +#else +#error unhandled operand size +#endif + +/* dynamic flags computation */ + +static int glue(compute_all_add, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_DST - CC_SRC; + cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_add, SUFFIX)(void) +{ + int src1, cf; + src1 = CC_SRC; + cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; + return cf; +} + +static int glue(compute_all_adc, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_DST - CC_SRC - 1; + cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_adc, SUFFIX)(void) +{ + int src1, cf; + src1 = CC_SRC; + cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; + return cf; +} + +static int glue(compute_all_sub, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_sub, SUFFIX)(void) +{ + int src1, src2, cf; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; + return cf; +} + +static int glue(compute_all_sbb, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_DST + CC_SRC + 1; + src2 = CC_SRC; + cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_sbb, SUFFIX)(void) +{ + int src1, src2, cf; + src1 = CC_DST + CC_SRC + 1; + src2 = CC_SRC; + cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; + return cf; +} + +static int glue(compute_all_logic, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = 0; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = 0; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_logic, SUFFIX)(void) +{ + return 0; +} + +static int glue(compute_all_inc, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_DST - 1; + src2 = 1; + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; + return cf | pf | af | zf | sf | of; +} + +#if DATA_BITS == 32 +static int glue(compute_c_inc, SUFFIX)(void) +{ + return CC_SRC; +} +#endif + +static int glue(compute_all_dec, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_DST + 1; + src2 = 1; + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_all_shl, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + /* of is defined if shift count == 1 */ + of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_shl, SUFFIX)(void) +{ + return (CC_SRC >> (DATA_BITS - 1)) & CC_C; +} + +#if DATA_BITS == 32 +static int glue(compute_c_sar, SUFFIX)(void) +{ + return CC_SRC & 1; +} +#endif + +static int glue(compute_all_sar, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = CC_SRC & 1; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + /* of is defined if shift count == 1 */ + of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; + return cf | pf | af | zf | sf | of; +} + +/* various optimized jumps cases */ + +void OPPROTO glue(op_jb_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + + if ((DATA_TYPE)src1 < (DATA_TYPE)src2) + JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 0, PARAM2); + else + JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 1, PARAM3); + FORCE_RET(); +} + +void OPPROTO glue(op_jz_sub, SUFFIX)(void) +{ + if ((DATA_TYPE)CC_DST == 0) + JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 0, PARAM2); + else + JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 1, PARAM3); + FORCE_RET(); +} + +void OPPROTO glue(op_jbe_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + + if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) + JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 0, PARAM2); + else + JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 1, PARAM3); + FORCE_RET(); +} + +void OPPROTO glue(op_js_sub, SUFFIX)(void) +{ + if (CC_DST & SIGN_MASK) + JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 0, PARAM2); + else + JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 1, PARAM3); + FORCE_RET(); +} + +void OPPROTO glue(op_jl_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + + if ((DATA_STYPE)src1 < (DATA_STYPE)src2) + JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 0, PARAM2); + else + JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 1, PARAM3); + FORCE_RET(); +} + +void OPPROTO glue(op_jle_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + + if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) + JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 0, PARAM2); + else + JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 1, PARAM3); + FORCE_RET(); +} + +/* oldies */ + +#if DATA_BITS >= 16 + +void OPPROTO glue(op_loopnz, SUFFIX)(void) +{ + unsigned int tmp; + int eflags; + eflags = cc_table[CC_OP].compute_all(); + tmp = (ECX - 1) & DATA_MASK; + ECX = (ECX & ~DATA_MASK) | tmp; + if (tmp != 0 && !(eflags & CC_Z)) + EIP = PARAM1; + else + EIP = PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_loopz, SUFFIX)(void) +{ + unsigned int tmp; + int eflags; + eflags = cc_table[CC_OP].compute_all(); + tmp = (ECX - 1) & DATA_MASK; + ECX = (ECX & ~DATA_MASK) | tmp; + if (tmp != 0 && (eflags & CC_Z)) + EIP = PARAM1; + else + EIP = PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_loop, SUFFIX)(void) +{ + unsigned int tmp; + tmp = (ECX - 1) & DATA_MASK; + ECX = (ECX & ~DATA_MASK) | tmp; + if (tmp != 0) + EIP = PARAM1; + else + EIP = PARAM2; + FORCE_RET(); +} + +void OPPROTO glue(op_jecxz, SUFFIX)(void) +{ + if ((DATA_TYPE)ECX == 0) + EIP = PARAM1; + else + EIP = PARAM2; + FORCE_RET(); +} + +#endif + +/* various optimized set cases */ + +void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + + T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2); +} + +void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) +{ + T0 = ((DATA_TYPE)CC_DST == 0); +} + +void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + + T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2); +} + +void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void) +{ + T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1; +} + +void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + + T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2); +} + +void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) +{ + int src1, src2; + src1 = CC_DST + CC_SRC; + src2 = CC_SRC; + + T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2); +} + +/* shifts */ + +void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & 0x1f; + T0 = T0 << count; + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & 0x1f; + T0 &= DATA_MASK; + T0 = T0 >> count; + FORCE_RET(); +} + +void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) +{ + int count, src; + count = T1 & 0x1f; + src = (DATA_STYPE)T0; + T0 = src >> count; + FORCE_RET(); +} + +#undef MEM_WRITE +#include "ops_template_mem.h" + +#define MEM_WRITE +#include "ops_template_mem.h" + +/* bit operations */ +#if DATA_BITS >= 16 + +void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & SHIFT_MASK; + CC_SRC = T0 >> count; +} + +void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & SHIFT_MASK; + T1 = T0 >> count; + T0 |= (1 << count); +} + +void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & SHIFT_MASK; + T1 = T0 >> count; + T0 &= ~(1 << count); +} + +void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) +{ + int count; + count = T1 & SHIFT_MASK; + T1 = T0 >> count; + T0 ^= (1 << count); +} + +void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) +{ + int res, count; + res = T0 & DATA_MASK; + if (res != 0) { + count = 0; + while ((res & 1) == 0) { + count++; + res >>= 1; + } + T0 = count; + CC_DST = 1; /* ZF = 1 */ + } else { + CC_DST = 0; /* ZF = 1 */ + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) +{ + int res, count; + res = T0 & DATA_MASK; + if (res != 0) { + count = DATA_BITS - 1; + while ((res & SIGN_MASK) == 0) { + count--; + res <<= 1; + } + T0 = count; + CC_DST = 1; /* ZF = 1 */ + } else { + CC_DST = 0; /* ZF = 1 */ + } + FORCE_RET(); +} + +#endif + +#if DATA_BITS == 32 +void OPPROTO op_update_bt_cc(void) +{ + CC_SRC = T1; +} +#endif + +/* string operations */ + +void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) +{ + T0 = DF << SHIFT; +} + +void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) +{ + if ((DATA_TYPE)CC_DST == 0) + JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 1); + FORCE_RET(); +} + +void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) +{ + if ((DATA_TYPE)CC_DST != 0) + JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1); + FORCE_RET(); +} + +void OPPROTO glue(glue(op_string_jz_sub, SUFFIX), _im)(void) +{ + if ((DATA_TYPE)CC_DST == 0) { + EIP = PARAM1; + if (env->eflags & TF_MASK) { + raise_exception(EXCP01_SSTP); + } + T0 = 0; + EXIT_TB(); + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_string_jnz_sub, SUFFIX), _im)(void) +{ + if ((DATA_TYPE)CC_DST != 0) { + EIP = PARAM1; + if (env->eflags & TF_MASK) { + raise_exception(EXCP01_SSTP); + } + T0 = 0; + EXIT_TB(); + } + FORCE_RET(); +} + +#if DATA_BITS >= 16 +void OPPROTO glue(op_jz_ecx, SUFFIX)(void) +{ + if ((DATA_TYPE)ECX == 0) + JUMP_TB(glue(op_jz_ecx, SUFFIX), PARAM1, 1, PARAM2); + FORCE_RET(); +} + +void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void) +{ + if ((DATA_TYPE)ECX == 0) { + EIP = PARAM1; + if (env->eflags & TF_MASK) { + raise_exception(EXCP01_SSTP); + } + T0 = 0; + EXIT_TB(); + } + FORCE_RET(); +} +#endif + +/* port I/O */ + +void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) +{ + glue(cpu_x86_out, SUFFIX)(env, T0 & 0xffff, T1 & DATA_MASK); +} + +void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) +{ + T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff); +} + +void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void) +{ + T0 = glue(cpu_x86_in, SUFFIX)(env, EDX & 0xffff); +} + +void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void) +{ + glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0); +} + +#undef DATA_BITS +#undef SHIFT_MASK +#undef SIGN_MASK +#undef DATA_TYPE +#undef DATA_STYPE +#undef DATA_MASK +#undef SUFFIX diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h new file mode 100644 index 000000000..eacaabba5 --- /dev/null +++ b/target-i386/ops_template_mem.h @@ -0,0 +1,429 @@ +/* + * i386 micro operations (included several times to generate + * different operand sizes) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef MEM_WRITE + +#if DATA_BITS == 8 +#define MEM_SUFFIX b_mem +#elif DATA_BITS == 16 +#define MEM_SUFFIX w_mem +#elif DATA_BITS == 32 +#define MEM_SUFFIX l_mem +#endif + +#else + +#define MEM_SUFFIX SUFFIX + +#endif + +void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & SHIFT_MASK; + if (count) { + src = T0; + T0 &= DATA_MASK; + T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#else + /* gcc 3.2 workaround. This is really a bug in gcc. */ + asm volatile("" : : "r" (T0)); +#endif + CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + (T0 & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & SHIFT_MASK; + if (count) { + src = T0; + T0 &= DATA_MASK; + T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#else + /* gcc 3.2 workaround. This is really a bug in gcc. */ + asm volatile("" : : "r" (T0)); +#endif + CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((T0 >> (DATA_BITS - 1)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & SHIFT_MASK; + if (count) { + T0 &= DATA_MASK; + T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) +{ + int count; + count = T1 & SHIFT_MASK; + if (count) { + T0 &= DATA_MASK; + T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, res, eflags; + unsigned int src; + + count = T1 & 0x1f; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + T0 &= DATA_MASK; + src = T0; + res = (T0 << count) | ((eflags & CC_C) << (count - 1)); + if (count > 1) + res |= T0 >> (DATA_BITS + 1 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (DATA_BITS - count)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, res, eflags; + unsigned int src; + + count = T1 & 0x1f; +#if DATA_BITS == 16 + count = rclw_table[count]; +#elif DATA_BITS == 8 + count = rclb_table[count]; +#endif + if (count) { + eflags = cc_table[CC_OP].compute_all(); + T0 &= DATA_MASK; + src = T0; + res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); + if (count > 1) + res |= T0 << (DATA_BITS + 1 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = (eflags & ~(CC_C | CC_O)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + ((src >> (count - 1)) & CC_C); + CC_OP = CC_OP_EFLAGS; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + src = (DATA_TYPE)T0 << (count - 1); + T0 = T0 << count; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + T0 &= DATA_MASK; + src = T0 >> (count - 1); + T0 = T0 >> count; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int count, src; + count = T1 & 0x1f; + if (count) { + src = (DATA_STYPE)T0; + T0 = src >> count; + src = src >> (count - 1); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +#if DATA_BITS == 16 +/* XXX: overflow flag might be incorrect in some cases in shldw */ +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + unsigned int res, tmp; + count = PARAM1; + T1 &= 0xffff; + res = T1 | (T0 << 16); + tmp = res >> (32 - count); + res <<= count; + if (count > 16) + res |= T1 << (count - 16); + T0 = res >> 16; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + unsigned int res, tmp; + count = ECX & 0x1f; + if (count) { + T1 &= 0xffff; + res = T1 | (T0 << 16); + tmp = res >> (32 - count); + res <<= count; + if (count > 16) + res |= T1 << (count - 16); + T0 = res >> 16; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count; + unsigned int res, tmp; + + count = PARAM1; + res = (T0 & 0xffff) | (T1 << 16); + tmp = res >> (count - 1); + res >>= count; + if (count > 16) + res |= T1 << (32 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count; + unsigned int res, tmp; + + count = ECX & 0x1f; + if (count) { + res = (T0 & 0xffff) | (T1 << 16); + tmp = res >> (count - 1); + res >>= count; + if (count > 16) + res |= T1 << (32 - count); + T0 = res; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} +#endif + +#if DATA_BITS == 32 +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count, tmp; + count = PARAM1; + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 << (count - 1); + T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + +void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count, tmp; + count = ECX & 0x1f; + if (count) { + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 << (count - 1); + T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SHLB + SHIFT; + } + FORCE_RET(); +} + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) +{ + int count, tmp; + count = PARAM1; + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 >> (count - 1); + T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; +} + + +void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) +{ + int count, tmp; + count = ECX & 0x1f; + if (count) { + T0 &= DATA_MASK; + T1 &= DATA_MASK; + tmp = T0 >> (count - 1); + T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = tmp; + CC_DST = T0; + CC_OP = CC_OP_SARB + SHIFT; + } + FORCE_RET(); +} +#endif + +/* carry add/sub (we only need to set CC_OP differently) */ + +void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + T0 = T0 + T1 + cf; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = T1; + CC_DST = T0; + CC_OP = CC_OP_ADDB + SHIFT + cf * 3; +} + +void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) +{ + int cf; + cf = cc_table[CC_OP].compute_c(); + T0 = T0 - T1 - cf; +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = T1; + CC_DST = T0; + CC_OP = CC_OP_SUBB + SHIFT + cf * 3; +} + +void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) +{ + unsigned int src, dst; + + src = T0; + dst = EAX - T0; + if ((DATA_TYPE)dst == 0) { + T0 = T1; + } else { + EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); + } +#ifdef MEM_WRITE + glue(st, SUFFIX)((uint8_t *)A0, T0); +#endif + CC_SRC = src; + CC_DST = dst; + FORCE_RET(); +} + +#undef MEM_SUFFIX +#undef MEM_WRITE diff --git a/target-i386/translate.c b/target-i386/translate.c new file mode 100644 index 000000000..4d89ccbba --- /dev/null +++ b/target-i386/translate.c @@ -0,0 +1,4487 @@ +/* + * i386 translation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +/* XXX: move that elsewhere */ +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; + +#define PREFIX_REPZ 0x01 +#define PREFIX_REPNZ 0x02 +#define PREFIX_LOCK 0x04 +#define PREFIX_DATA 0x08 +#define PREFIX_ADR 0x10 + +typedef struct DisasContext { + /* current insn context */ + int override; /* -1 if no override */ + int prefix; + int aflag, dflag; + uint8_t *pc; /* pc = eip + cs_base */ + int is_jmp; /* 1 = means jump (stop translation), 2 means CPU + static state change (stop translation) */ + /* current block context */ + uint8_t *cs_base; /* base of CS segment */ + int pe; /* protected mode */ + int code32; /* 32 bit code segment */ + int ss32; /* 32 bit stack segment */ + int cc_op; /* current CC operation */ + int addseg; /* non zero if either DS/ES/SS have a non zero base */ + int f_st; /* currently unused */ + int vm86; /* vm86 mode */ + int cpl; + int iopl; + int tf; /* TF cpu flag */ + int jmp_opt; /* use direct block chaining for direct jumps */ + int mem_index; /* select memory access functions */ + struct TranslationBlock *tb; + int popl_esp_hack; /* for correct popl with esp base handling */ +} DisasContext; + +static void gen_eob(DisasContext *s); +static void gen_jmp(DisasContext *s, unsigned int eip); + +/* i386 arith/logic operations */ +enum { + OP_ADDL, + OP_ORL, + OP_ADCL, + OP_SBBL, + OP_ANDL, + OP_SUBL, + OP_XORL, + OP_CMPL, +}; + +/* i386 shift ops */ +enum { + OP_ROL, + OP_ROR, + OP_RCL, + OP_RCR, + OP_SHL, + OP_SHR, + OP_SHL1, /* undocumented */ + OP_SAR = 7, +}; + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +#include "gen-op.h" + +/* operand size */ +enum { + OT_BYTE = 0, + OT_WORD, + OT_LONG, + OT_QUAD, +}; + +enum { + /* I386 int registers */ + OR_EAX, /* MUST be even numbered */ + OR_ECX, + OR_EDX, + OR_EBX, + OR_ESP, + OR_EBP, + OR_ESI, + OR_EDI, + OR_TMP0, /* temporary operand register */ + OR_TMP1, + OR_A0, /* temporary register used when doing address evaluation */ + OR_ZERO, /* fixed zero register */ + NB_OREGS, +}; + +typedef void (GenOpFunc)(void); +typedef void (GenOpFunc1)(long); +typedef void (GenOpFunc2)(long, long); +typedef void (GenOpFunc3)(long, long, long); + +static GenOpFunc *gen_op_mov_reg_T0[3][8] = { + [OT_BYTE] = { + gen_op_movb_EAX_T0, + gen_op_movb_ECX_T0, + gen_op_movb_EDX_T0, + gen_op_movb_EBX_T0, + gen_op_movh_EAX_T0, + gen_op_movh_ECX_T0, + gen_op_movh_EDX_T0, + gen_op_movh_EBX_T0, + }, + [OT_WORD] = { + gen_op_movw_EAX_T0, + gen_op_movw_ECX_T0, + gen_op_movw_EDX_T0, + gen_op_movw_EBX_T0, + gen_op_movw_ESP_T0, + gen_op_movw_EBP_T0, + gen_op_movw_ESI_T0, + gen_op_movw_EDI_T0, + }, + [OT_LONG] = { + gen_op_movl_EAX_T0, + gen_op_movl_ECX_T0, + gen_op_movl_EDX_T0, + gen_op_movl_EBX_T0, + gen_op_movl_ESP_T0, + gen_op_movl_EBP_T0, + gen_op_movl_ESI_T0, + gen_op_movl_EDI_T0, + }, +}; + +static GenOpFunc *gen_op_mov_reg_T1[3][8] = { + [OT_BYTE] = { + gen_op_movb_EAX_T1, + gen_op_movb_ECX_T1, + gen_op_movb_EDX_T1, + gen_op_movb_EBX_T1, + gen_op_movh_EAX_T1, + gen_op_movh_ECX_T1, + gen_op_movh_EDX_T1, + gen_op_movh_EBX_T1, + }, + [OT_WORD] = { + gen_op_movw_EAX_T1, + gen_op_movw_ECX_T1, + gen_op_movw_EDX_T1, + gen_op_movw_EBX_T1, + gen_op_movw_ESP_T1, + gen_op_movw_EBP_T1, + gen_op_movw_ESI_T1, + gen_op_movw_EDI_T1, + }, + [OT_LONG] = { + gen_op_movl_EAX_T1, + gen_op_movl_ECX_T1, + gen_op_movl_EDX_T1, + gen_op_movl_EBX_T1, + gen_op_movl_ESP_T1, + gen_op_movl_EBP_T1, + gen_op_movl_ESI_T1, + gen_op_movl_EDI_T1, + }, +}; + +static GenOpFunc *gen_op_mov_reg_A0[2][8] = { + [0] = { + gen_op_movw_EAX_A0, + gen_op_movw_ECX_A0, + gen_op_movw_EDX_A0, + gen_op_movw_EBX_A0, + gen_op_movw_ESP_A0, + gen_op_movw_EBP_A0, + gen_op_movw_ESI_A0, + gen_op_movw_EDI_A0, + }, + [1] = { + gen_op_movl_EAX_A0, + gen_op_movl_ECX_A0, + gen_op_movl_EDX_A0, + gen_op_movl_EBX_A0, + gen_op_movl_ESP_A0, + gen_op_movl_EBP_A0, + gen_op_movl_ESI_A0, + gen_op_movl_EDI_A0, + }, +}; + +static GenOpFunc *gen_op_mov_TN_reg[3][2][8] = +{ + [OT_BYTE] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movh_T0_EAX, + gen_op_movh_T0_ECX, + gen_op_movh_T0_EDX, + gen_op_movh_T0_EBX, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movh_T1_EAX, + gen_op_movh_T1_ECX, + gen_op_movh_T1_EDX, + gen_op_movh_T1_EBX, + }, + }, + [OT_WORD] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movl_T0_ESP, + gen_op_movl_T0_EBP, + gen_op_movl_T0_ESI, + gen_op_movl_T0_EDI, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movl_T1_ESP, + gen_op_movl_T1_EBP, + gen_op_movl_T1_ESI, + gen_op_movl_T1_EDI, + }, + }, + [OT_LONG] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movl_T0_ESP, + gen_op_movl_T0_EBP, + gen_op_movl_T0_ESI, + gen_op_movl_T0_EDI, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movl_T1_ESP, + gen_op_movl_T1_EBP, + gen_op_movl_T1_ESI, + gen_op_movl_T1_EDI, + }, + }, +}; + +static GenOpFunc *gen_op_movl_A0_reg[8] = { + gen_op_movl_A0_EAX, + gen_op_movl_A0_ECX, + gen_op_movl_A0_EDX, + gen_op_movl_A0_EBX, + gen_op_movl_A0_ESP, + gen_op_movl_A0_EBP, + gen_op_movl_A0_ESI, + gen_op_movl_A0_EDI, +}; + +static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { + [0] = { + gen_op_addl_A0_EAX, + gen_op_addl_A0_ECX, + gen_op_addl_A0_EDX, + gen_op_addl_A0_EBX, + gen_op_addl_A0_ESP, + gen_op_addl_A0_EBP, + gen_op_addl_A0_ESI, + gen_op_addl_A0_EDI, + }, + [1] = { + gen_op_addl_A0_EAX_s1, + gen_op_addl_A0_ECX_s1, + gen_op_addl_A0_EDX_s1, + gen_op_addl_A0_EBX_s1, + gen_op_addl_A0_ESP_s1, + gen_op_addl_A0_EBP_s1, + gen_op_addl_A0_ESI_s1, + gen_op_addl_A0_EDI_s1, + }, + [2] = { + gen_op_addl_A0_EAX_s2, + gen_op_addl_A0_ECX_s2, + gen_op_addl_A0_EDX_s2, + gen_op_addl_A0_EBX_s2, + gen_op_addl_A0_ESP_s2, + gen_op_addl_A0_EBP_s2, + gen_op_addl_A0_ESI_s2, + gen_op_addl_A0_EDI_s2, + }, + [3] = { + gen_op_addl_A0_EAX_s3, + gen_op_addl_A0_ECX_s3, + gen_op_addl_A0_EDX_s3, + gen_op_addl_A0_EBX_s3, + gen_op_addl_A0_ESP_s3, + gen_op_addl_A0_EBP_s3, + gen_op_addl_A0_ESI_s3, + gen_op_addl_A0_EDI_s3, + }, +}; + +static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = { + [0] = { + gen_op_cmovw_EAX_T1_T0, + gen_op_cmovw_ECX_T1_T0, + gen_op_cmovw_EDX_T1_T0, + gen_op_cmovw_EBX_T1_T0, + gen_op_cmovw_ESP_T1_T0, + gen_op_cmovw_EBP_T1_T0, + gen_op_cmovw_ESI_T1_T0, + gen_op_cmovw_EDI_T1_T0, + }, + [1] = { + gen_op_cmovl_EAX_T1_T0, + gen_op_cmovl_ECX_T1_T0, + gen_op_cmovl_EDX_T1_T0, + gen_op_cmovl_EBX_T1_T0, + gen_op_cmovl_ESP_T1_T0, + gen_op_cmovl_EBP_T1_T0, + gen_op_cmovl_ESI_T1_T0, + gen_op_cmovl_EDI_T1_T0, + }, +}; + +static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { + NULL, + gen_op_orl_T0_T1, + NULL, + NULL, + gen_op_andl_T0_T1, + NULL, + gen_op_xorl_T0_T1, + NULL, +}; + +static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { + [OT_BYTE] = { + gen_op_adcb_T0_T1_cc, + gen_op_sbbb_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_adcw_T0_T1_cc, + gen_op_sbbw_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_adcl_T0_T1_cc, + gen_op_sbbl_T0_T1_cc, + }, +}; + +static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = { + [OT_BYTE] = { + gen_op_adcb_mem_T0_T1_cc, + gen_op_sbbb_mem_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_adcw_mem_T0_T1_cc, + gen_op_sbbw_mem_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_adcl_mem_T0_T1_cc, + gen_op_sbbl_mem_T0_T1_cc, + }, +}; + +static const int cc_op_arithb[8] = { + CC_OP_ADDB, + CC_OP_LOGICB, + CC_OP_ADDB, + CC_OP_SUBB, + CC_OP_LOGICB, + CC_OP_SUBB, + CC_OP_LOGICB, + CC_OP_SUBB, +}; + +static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { + gen_op_cmpxchgb_T0_T1_EAX_cc, + gen_op_cmpxchgw_T0_T1_EAX_cc, + gen_op_cmpxchgl_T0_T1_EAX_cc, +}; + +static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = { + gen_op_cmpxchgb_mem_T0_T1_EAX_cc, + gen_op_cmpxchgw_mem_T0_T1_EAX_cc, + gen_op_cmpxchgl_mem_T0_T1_EAX_cc, +}; + +static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { + [OT_BYTE] = { + gen_op_rolb_T0_T1_cc, + gen_op_rorb_T0_T1_cc, + gen_op_rclb_T0_T1_cc, + gen_op_rcrb_T0_T1_cc, + gen_op_shlb_T0_T1_cc, + gen_op_shrb_T0_T1_cc, + gen_op_shlb_T0_T1_cc, + gen_op_sarb_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_rolw_T0_T1_cc, + gen_op_rorw_T0_T1_cc, + gen_op_rclw_T0_T1_cc, + gen_op_rcrw_T0_T1_cc, + gen_op_shlw_T0_T1_cc, + gen_op_shrw_T0_T1_cc, + gen_op_shlw_T0_T1_cc, + gen_op_sarw_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_roll_T0_T1_cc, + gen_op_rorl_T0_T1_cc, + gen_op_rcll_T0_T1_cc, + gen_op_rcrl_T0_T1_cc, + gen_op_shll_T0_T1_cc, + gen_op_shrl_T0_T1_cc, + gen_op_shll_T0_T1_cc, + gen_op_sarl_T0_T1_cc, + }, +}; + +static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = { + [OT_BYTE] = { + gen_op_rolb_mem_T0_T1_cc, + gen_op_rorb_mem_T0_T1_cc, + gen_op_rclb_mem_T0_T1_cc, + gen_op_rcrb_mem_T0_T1_cc, + gen_op_shlb_mem_T0_T1_cc, + gen_op_shrb_mem_T0_T1_cc, + gen_op_shlb_mem_T0_T1_cc, + gen_op_sarb_mem_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_rolw_mem_T0_T1_cc, + gen_op_rorw_mem_T0_T1_cc, + gen_op_rclw_mem_T0_T1_cc, + gen_op_rcrw_mem_T0_T1_cc, + gen_op_shlw_mem_T0_T1_cc, + gen_op_shrw_mem_T0_T1_cc, + gen_op_shlw_mem_T0_T1_cc, + gen_op_sarw_mem_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_roll_mem_T0_T1_cc, + gen_op_rorl_mem_T0_T1_cc, + gen_op_rcll_mem_T0_T1_cc, + gen_op_rcrl_mem_T0_T1_cc, + gen_op_shll_mem_T0_T1_cc, + gen_op_shrl_mem_T0_T1_cc, + gen_op_shll_mem_T0_T1_cc, + gen_op_sarl_mem_T0_T1_cc, + }, +}; + +static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = { + [0] = { + gen_op_shldw_T0_T1_im_cc, + gen_op_shrdw_T0_T1_im_cc, + }, + [1] = { + gen_op_shldl_T0_T1_im_cc, + gen_op_shrdl_T0_T1_im_cc, + }, +}; + +static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = { + [0] = { + gen_op_shldw_T0_T1_ECX_cc, + gen_op_shrdw_T0_T1_ECX_cc, + }, + [1] = { + gen_op_shldl_T0_T1_ECX_cc, + gen_op_shrdl_T0_T1_ECX_cc, + }, +}; + +static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = { + [0] = { + gen_op_shldw_mem_T0_T1_im_cc, + gen_op_shrdw_mem_T0_T1_im_cc, + }, + [1] = { + gen_op_shldl_mem_T0_T1_im_cc, + gen_op_shrdl_mem_T0_T1_im_cc, + }, +}; + +static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = { + [0] = { + gen_op_shldw_mem_T0_T1_ECX_cc, + gen_op_shrdw_mem_T0_T1_ECX_cc, + }, + [1] = { + gen_op_shldl_mem_T0_T1_ECX_cc, + gen_op_shrdl_mem_T0_T1_ECX_cc, + }, +}; + +static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { + [0] = { + gen_op_btw_T0_T1_cc, + gen_op_btsw_T0_T1_cc, + gen_op_btrw_T0_T1_cc, + gen_op_btcw_T0_T1_cc, + }, + [1] = { + gen_op_btl_T0_T1_cc, + gen_op_btsl_T0_T1_cc, + gen_op_btrl_T0_T1_cc, + gen_op_btcl_T0_T1_cc, + }, +}; + +static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { + [0] = { + gen_op_bsfw_T0_cc, + gen_op_bsrw_T0_cc, + }, + [1] = { + gen_op_bsfl_T0_cc, + gen_op_bsrl_T0_cc, + }, +}; + +static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = { + gen_op_ldsb_T0_A0, + gen_op_ldsw_T0_A0, + NULL, + + gen_op_ldsb_kernel_T0_A0, + gen_op_ldsw_kernel_T0_A0, + NULL, + + gen_op_ldsb_user_T0_A0, + gen_op_ldsw_user_T0_A0, + NULL, +}; + +static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = { + gen_op_ldub_T0_A0, + gen_op_lduw_T0_A0, + NULL, + + gen_op_ldub_kernel_T0_A0, + gen_op_lduw_kernel_T0_A0, + NULL, + + gen_op_ldub_user_T0_A0, + gen_op_lduw_user_T0_A0, + NULL, +}; + +/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */ +static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = { + gen_op_ldub_T0_A0, + gen_op_lduw_T0_A0, + gen_op_ldl_T0_A0, + + gen_op_ldub_kernel_T0_A0, + gen_op_lduw_kernel_T0_A0, + gen_op_ldl_kernel_T0_A0, + + gen_op_ldub_user_T0_A0, + gen_op_lduw_user_T0_A0, + gen_op_ldl_user_T0_A0, +}; + +static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = { + gen_op_ldub_T1_A0, + gen_op_lduw_T1_A0, + gen_op_ldl_T1_A0, + + gen_op_ldub_kernel_T1_A0, + gen_op_lduw_kernel_T1_A0, + gen_op_ldl_kernel_T1_A0, + + gen_op_ldub_user_T1_A0, + gen_op_lduw_user_T1_A0, + gen_op_ldl_user_T1_A0, +}; + +static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { + gen_op_stb_T0_A0, + gen_op_stw_T0_A0, + gen_op_stl_T0_A0, + + gen_op_stb_kernel_T0_A0, + gen_op_stw_kernel_T0_A0, + gen_op_stl_kernel_T0_A0, + + gen_op_stb_user_T0_A0, + gen_op_stw_user_T0_A0, + gen_op_stl_user_T0_A0, +}; + +static inline void gen_string_movl_A0_ESI(DisasContext *s) +{ + int override; + + override = s->override; + if (s->aflag) { + /* 32 bit address */ + if (s->addseg && override < 0) + override = R_DS; + if (override >= 0) { + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addl_A0_reg_sN[0][R_ESI](); + } else { + gen_op_movl_A0_reg[R_ESI](); + } + } else { + /* 16 address, always override */ + if (override < 0) + override = R_DS; + gen_op_movl_A0_reg[R_ESI](); + gen_op_andl_A0_ffff(); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } +} + +static inline void gen_string_movl_A0_EDI(DisasContext *s) +{ + if (s->aflag) { + if (s->addseg) { + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); + gen_op_addl_A0_reg_sN[0][R_EDI](); + } else { + gen_op_movl_A0_reg[R_EDI](); + } + } else { + gen_op_movl_A0_reg[R_EDI](); + gen_op_andl_A0_ffff(); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); + } +} + +static GenOpFunc *gen_op_movl_T0_Dshift[3] = { + gen_op_movl_T0_Dshiftb, + gen_op_movl_T0_Dshiftw, + gen_op_movl_T0_Dshiftl, +}; + +static GenOpFunc2 *gen_op_jz_ecx[2] = { + gen_op_jz_ecxw, + gen_op_jz_ecxl, +}; + +static GenOpFunc1 *gen_op_jz_ecx_im[2] = { + gen_op_jz_ecxw_im, + gen_op_jz_ecxl_im, +}; + +static GenOpFunc *gen_op_dec_ECX[2] = { + gen_op_decw_ECX, + gen_op_decl_ECX, +}; + +static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = { + { + gen_op_string_jnz_subb, + gen_op_string_jnz_subw, + gen_op_string_jnz_subl, + }, + { + gen_op_string_jz_subb, + gen_op_string_jz_subw, + gen_op_string_jz_subl, + }, +}; + +static GenOpFunc1 *gen_op_string_jnz_sub_im[2][3] = { + { + gen_op_string_jnz_subb_im, + gen_op_string_jnz_subw_im, + gen_op_string_jnz_subl_im, + }, + { + gen_op_string_jz_subb_im, + gen_op_string_jz_subw_im, + gen_op_string_jz_subl_im, + }, +}; + +static GenOpFunc *gen_op_in_DX_T0[3] = { + gen_op_inb_DX_T0, + gen_op_inw_DX_T0, + gen_op_inl_DX_T0, +}; + +static GenOpFunc *gen_op_out_DX_T0[3] = { + gen_op_outb_DX_T0, + gen_op_outw_DX_T0, + gen_op_outl_DX_T0, +}; + +static inline void gen_movs(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_ESI_T0(); + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_update_cc_op(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } +} + +static inline void gen_jz_ecx_string(DisasContext *s, unsigned int next_eip) +{ + if (s->jmp_opt) { + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + } else { + /* XXX: does not work with gdbstub "ice" single step - not a + serious problem */ + gen_op_jz_ecx_im[s->aflag](next_eip); + } +} + +static inline void gen_stos(DisasContext *s, int ot) +{ + gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_lods(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_mov_reg_T0[ot][R_EAX](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + } else { + gen_op_addw_ESI_T0(); + } +} + +static inline void gen_scas(DisasContext *s, int ot) +{ + gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); + gen_string_movl_A0_EDI(s); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_cmpl_T0_T1_cc(); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_cmps(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_string_movl_A0_EDI(s); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_cmpl_T0_T1_cc(); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_ESI_T0(); + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_ins(DisasContext *s, int ot) +{ + gen_op_in_DX_T0[ot](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_outs(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_out_DX_T0[ot](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + } else { + gen_op_addw_ESI_T0(); + } +} + +/* same method as Valgrind : we generate jumps to current or next + instruction */ +#define GEN_REPZ(op) \ +static inline void gen_repz_ ## op(DisasContext *s, int ot, \ + unsigned int cur_eip, unsigned int next_eip) \ +{ \ + gen_update_cc_op(s); \ + gen_jz_ecx_string(s, next_eip); \ + gen_ ## op(s, ot); \ + gen_op_dec_ECX[s->aflag](); \ + /* a loop would cause two single step exceptions if ECX = 1 \ + before rep string_insn */ \ + if (!s->jmp_opt) \ + gen_op_jz_ecx_im[s->aflag](next_eip); \ + gen_jmp(s, cur_eip); \ +} + +#define GEN_REPZ2(op) \ +static inline void gen_repz_ ## op(DisasContext *s, int ot, \ + unsigned int cur_eip, \ + unsigned int next_eip, \ + int nz) \ +{ \ + gen_update_cc_op(s); \ + gen_jz_ecx_string(s, next_eip); \ + gen_ ## op(s, ot); \ + gen_op_dec_ECX[s->aflag](); \ + gen_op_set_cc_op(CC_OP_SUBB + ot); \ + if (!s->jmp_opt) \ + gen_op_string_jnz_sub_im[nz][ot](next_eip); \ + else \ + gen_op_string_jnz_sub[nz][ot]((long)s->tb); \ + if (!s->jmp_opt) \ + gen_op_jz_ecx_im[s->aflag](next_eip); \ + gen_jmp(s, cur_eip); \ +} + +GEN_REPZ(movs) +GEN_REPZ(stos) +GEN_REPZ(lods) +GEN_REPZ(ins) +GEN_REPZ(outs) +GEN_REPZ2(scas) +GEN_REPZ2(cmps) + +static GenOpFunc *gen_op_in[3] = { + gen_op_inb_T0_T1, + gen_op_inw_T0_T1, + gen_op_inl_T0_T1, +}; + +static GenOpFunc *gen_op_out[3] = { + gen_op_outb_T0_T1, + gen_op_outw_T0_T1, + gen_op_outl_T0_T1, +}; + +enum { + JCC_O, + JCC_B, + JCC_Z, + JCC_BE, + JCC_S, + JCC_P, + JCC_L, + JCC_LE, +}; + +static GenOpFunc3 *gen_jcc_sub[3][8] = { + [OT_BYTE] = { + NULL, + gen_op_jb_subb, + gen_op_jz_subb, + gen_op_jbe_subb, + gen_op_js_subb, + NULL, + gen_op_jl_subb, + gen_op_jle_subb, + }, + [OT_WORD] = { + NULL, + gen_op_jb_subw, + gen_op_jz_subw, + gen_op_jbe_subw, + gen_op_js_subw, + NULL, + gen_op_jl_subw, + gen_op_jle_subw, + }, + [OT_LONG] = { + NULL, + gen_op_jb_subl, + gen_op_jz_subl, + gen_op_jbe_subl, + gen_op_js_subl, + NULL, + gen_op_jl_subl, + gen_op_jle_subl, + }, +}; +static GenOpFunc2 *gen_op_loop[2][4] = { + [0] = { + gen_op_loopnzw, + gen_op_loopzw, + gen_op_loopw, + gen_op_jecxzw, + }, + [1] = { + gen_op_loopnzl, + gen_op_loopzl, + gen_op_loopl, + gen_op_jecxzl, + }, +}; + +static GenOpFunc *gen_setcc_slow[8] = { + gen_op_seto_T0_cc, + gen_op_setb_T0_cc, + gen_op_setz_T0_cc, + gen_op_setbe_T0_cc, + gen_op_sets_T0_cc, + gen_op_setp_T0_cc, + gen_op_setl_T0_cc, + gen_op_setle_T0_cc, +}; + +static GenOpFunc *gen_setcc_sub[3][8] = { + [OT_BYTE] = { + NULL, + gen_op_setb_T0_subb, + gen_op_setz_T0_subb, + gen_op_setbe_T0_subb, + gen_op_sets_T0_subb, + NULL, + gen_op_setl_T0_subb, + gen_op_setle_T0_subb, + }, + [OT_WORD] = { + NULL, + gen_op_setb_T0_subw, + gen_op_setz_T0_subw, + gen_op_setbe_T0_subw, + gen_op_sets_T0_subw, + NULL, + gen_op_setl_T0_subw, + gen_op_setle_T0_subw, + }, + [OT_LONG] = { + NULL, + gen_op_setb_T0_subl, + gen_op_setz_T0_subl, + gen_op_setbe_T0_subl, + gen_op_sets_T0_subl, + NULL, + gen_op_setl_T0_subl, + gen_op_setle_T0_subl, + }, +}; + +static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { + gen_op_fadd_ST0_FT0, + gen_op_fmul_ST0_FT0, + gen_op_fcom_ST0_FT0, + gen_op_fcom_ST0_FT0, + gen_op_fsub_ST0_FT0, + gen_op_fsubr_ST0_FT0, + gen_op_fdiv_ST0_FT0, + gen_op_fdivr_ST0_FT0, +}; + +/* NOTE the exception in "r" op ordering */ +static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { + gen_op_fadd_STN_ST0, + gen_op_fmul_STN_ST0, + NULL, + NULL, + gen_op_fsubr_STN_ST0, + gen_op_fsub_STN_ST0, + gen_op_fdivr_STN_ST0, + gen_op_fdiv_STN_ST0, +}; + +/* if d == OR_TMP0, it means memory operand (address in A0) */ +static void gen_op(DisasContext *s1, int op, int ot, int d) +{ + GenOpFunc *gen_update_cc; + + if (d != OR_TMP0) { + gen_op_mov_TN_reg[ot][0][d](); + } else { + gen_op_ld_T0_A0[ot + s1->mem_index](); + } + switch(op) { + case OP_ADCL: + case OP_SBBL: + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + if (d != OR_TMP0) { + gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + gen_op_mov_reg_T0[ot][d](); + } else { + gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL](); + } + s1->cc_op = CC_OP_DYNAMIC; + goto the_end; + case OP_ADDL: + gen_op_addl_T0_T1(); + s1->cc_op = CC_OP_ADDB + ot; + gen_update_cc = gen_op_update2_cc; + break; + case OP_SUBL: + gen_op_subl_T0_T1(); + s1->cc_op = CC_OP_SUBB + ot; + gen_update_cc = gen_op_update2_cc; + break; + default: + case OP_ANDL: + case OP_ORL: + case OP_XORL: + gen_op_arith_T0_T1_cc[op](); + s1->cc_op = CC_OP_LOGICB + ot; + gen_update_cc = gen_op_update1_cc; + break; + case OP_CMPL: + gen_op_cmpl_T0_T1_cc(); + s1->cc_op = CC_OP_SUBB + ot; + gen_update_cc = NULL; + break; + } + if (op != OP_CMPL) { + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); + else + gen_op_st_T0_A0[ot + s1->mem_index](); + } + /* the flags update must happen after the memory write (precise + exception support) */ + if (gen_update_cc) + gen_update_cc(); + the_end: ; +} + +/* if d == OR_TMP0, it means memory operand (address in A0) */ +static void gen_inc(DisasContext *s1, int ot, int d, int c) +{ + if (d != OR_TMP0) + gen_op_mov_TN_reg[ot][0][d](); + else + gen_op_ld_T0_A0[ot + s1->mem_index](); + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + if (c > 0) { + gen_op_incl_T0(); + s1->cc_op = CC_OP_INCB + ot; + } else { + gen_op_decl_T0(); + s1->cc_op = CC_OP_DECB + ot; + } + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); + else + gen_op_st_T0_A0[ot + s1->mem_index](); + gen_op_update_inc_cc(); +} + +static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) +{ + if (d != OR_TMP0) + gen_op_mov_TN_reg[ot][0][d](); + else + gen_op_ld_T0_A0[ot + s1->mem_index](); + if (s != OR_TMP1) + gen_op_mov_TN_reg[ot][1][s](); + /* for zero counts, flags are not updated, so must do it dynamically */ + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + + if (d != OR_TMP0) + gen_op_shift_T0_T1_cc[ot][op](); + else + gen_op_shift_mem_T0_T1_cc[ot][op](); + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); + s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ +} + +static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) +{ + /* currently not optimized */ + gen_op_movl_T1_im(c); + gen_shift(s1, op, ot, d, OR_TMP1); +} + +static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) +{ + int havesib; + int base, disp; + int index; + int scale; + int opreg; + int mod, rm, code, override, must_add_seg; + + override = s->override; + must_add_seg = s->addseg; + if (override >= 0) + must_add_seg = 1; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + + if (s->aflag) { + + havesib = 0; + base = rm; + index = 0; + scale = 0; + + if (base == 4) { + havesib = 1; + code = ldub(s->pc++); + scale = (code >> 6) & 3; + index = (code >> 3) & 7; + base = code & 7; + } + + switch (mod) { + case 0: + if (base == 5) { + base = -1; + disp = ldl(s->pc); + s->pc += 4; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub(s->pc++); + break; + default: + case 2: + disp = ldl(s->pc); + s->pc += 4; + break; + } + + if (base >= 0) { + /* for correct popl handling with esp */ + if (base == 4 && s->popl_esp_hack) + disp += s->popl_esp_hack; + gen_op_movl_A0_reg[base](); + if (disp != 0) + gen_op_addl_A0_im(disp); + } else { + gen_op_movl_A0_im(disp); + } + /* XXX: index == 4 is always invalid */ + if (havesib && (index != 4 || scale != 0)) { + gen_op_addl_A0_reg_sN[scale][index](); + } + if (must_add_seg) { + if (override < 0) { + if (base == R_EBP || base == R_ESP) + override = R_SS; + else + override = R_DS; + } + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } + } else { + switch (mod) { + case 0: + if (rm == 6) { + disp = lduw(s->pc); + s->pc += 2; + gen_op_movl_A0_im(disp); + rm = 0; /* avoid SS override */ + goto no_rm; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub(s->pc++); + break; + default: + case 2: + disp = lduw(s->pc); + s->pc += 2; + break; + } + switch(rm) { + case 0: + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_reg_sN[0][R_ESI](); + break; + case 1: + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_reg_sN[0][R_EDI](); + break; + case 2: + gen_op_movl_A0_reg[R_EBP](); + gen_op_addl_A0_reg_sN[0][R_ESI](); + break; + case 3: + gen_op_movl_A0_reg[R_EBP](); + gen_op_addl_A0_reg_sN[0][R_EDI](); + break; + case 4: + gen_op_movl_A0_reg[R_ESI](); + break; + case 5: + gen_op_movl_A0_reg[R_EDI](); + break; + case 6: + gen_op_movl_A0_reg[R_EBP](); + break; + default: + case 7: + gen_op_movl_A0_reg[R_EBX](); + break; + } + if (disp != 0) + gen_op_addl_A0_im(disp); + gen_op_andl_A0_ffff(); + no_rm: + if (must_add_seg) { + if (override < 0) { + if (rm == 2 || rm == 3 || rm == 6) + override = R_SS; + else + override = R_DS; + } + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } + } + + opreg = OR_A0; + disp = 0; + *reg_ptr = opreg; + *offset_ptr = disp; +} + +/* generate modrm memory load or store of 'reg'. TMP0 is used if reg != + OR_TMP0 */ +static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store) +{ + int mod, rm, opreg, disp; + + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod == 3) { + if (is_store) { + if (reg != OR_TMP0) + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_reg_T0[ot][rm](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + if (reg != OR_TMP0) + gen_op_mov_reg_T0[ot][reg](); + } + } else { + gen_lea_modrm(s, modrm, &opreg, &disp); + if (is_store) { + if (reg != OR_TMP0) + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_st_T0_A0[ot + s->mem_index](); + } else { + gen_op_ld_T0_A0[ot + s->mem_index](); + if (reg != OR_TMP0) + gen_op_mov_reg_T0[ot][reg](); + } + } +} + +static inline uint32_t insn_get(DisasContext *s, int ot) +{ + uint32_t ret; + + switch(ot) { + case OT_BYTE: + ret = ldub(s->pc); + s->pc++; + break; + case OT_WORD: + ret = lduw(s->pc); + s->pc += 2; + break; + default: + case OT_LONG: + ret = ldl(s->pc); + s->pc += 4; + break; + } + return ret; +} + +static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) +{ + TranslationBlock *tb; + int inv, jcc_op; + GenOpFunc3 *func; + + inv = b & 1; + jcc_op = (b >> 1) & 7; + + if (s->jmp_opt) { + switch(s->cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; + break; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_ADCB: + case CC_OP_ADCW: + case CC_OP_ADCL: + case CC_OP_SBBB: + case CC_OP_SBBW: + case CC_OP_SBBL: + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + case CC_OP_SARB: + case CC_OP_SARW: + case CC_OP_SARL: + switch(jcc_op) { + case JCC_Z: + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + case JCC_S: + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + default: + func = NULL; + break; + } + break; + default: + func = NULL; + break; + } + + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + + if (!func) { + gen_setcc_slow[jcc_op](); + func = gen_op_jcc; + } + + tb = s->tb; + if (!inv) { + func((long)tb, val, next_eip); + } else { + func((long)tb, next_eip, val); + } + s->is_jmp = 3; + } else { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_setcc_slow[jcc_op](); + if (!inv) { + gen_op_jcc_im(val, next_eip); + } else { + gen_op_jcc_im(next_eip, val); + } + gen_eob(s); + } +} + +static void gen_setcc(DisasContext *s, int b) +{ + int inv, jcc_op; + GenOpFunc *func; + + inv = b & 1; + jcc_op = (b >> 1) & 7; + switch(s->cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; + if (!func) + goto slow_jcc; + break; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + switch(jcc_op) { + case JCC_Z: + func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + case JCC_S: + func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + default: + goto slow_jcc; + } + break; + default: + slow_jcc: + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + func = gen_setcc_slow[jcc_op]; + break; + } + func(); + if (inv) { + gen_op_xor_T0_1(); + } +} + +/* move T0 to seg_reg and compute if the CPU state may change. Never + call this function with seg_reg == R_CS */ +static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) +{ + if (s->pe && !s->vm86) + gen_op_movl_seg_T0(seg_reg, cur_eip); + else + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); + /* abort translation because the register may have a non zero base + or because ss32 may change. For R_SS, translation must always + stop as a special handling must be done to disable hardware + interrupts for the next instruction */ + if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) + s->is_jmp = 3; +} + +/* generate a push. It depends on ss32, addseg and dflag */ +static void gen_push_T0(DisasContext *s) +{ + if (s->ss32) { + if (!s->addseg) { + if (s->dflag) + gen_op_pushl_T0(); + else + gen_op_pushw_T0(); + } else { + if (s->dflag) + gen_op_pushl_ss32_T0(); + else + gen_op_pushw_ss32_T0(); + } + } else { + if (s->dflag) + gen_op_pushl_ss16_T0(); + else + gen_op_pushw_ss16_T0(); + } +} + +/* two step pop is necessary for precise exceptions */ +static void gen_pop_T0(DisasContext *s) +{ + if (s->ss32) { + if (!s->addseg) { + if (s->dflag) + gen_op_popl_T0(); + else + gen_op_popw_T0(); + } else { + if (s->dflag) + gen_op_popl_ss32_T0(); + else + gen_op_popw_ss32_T0(); + } + } else { + if (s->dflag) + gen_op_popl_ss16_T0(); + else + gen_op_popw_ss16_T0(); + } +} + +static inline void gen_stack_update(DisasContext *s, int addend) +{ + if (s->ss32) { + if (addend == 2) + gen_op_addl_ESP_2(); + else if (addend == 4) + gen_op_addl_ESP_4(); + else + gen_op_addl_ESP_im(addend); + } else { + if (addend == 2) + gen_op_addw_ESP_2(); + else if (addend == 4) + gen_op_addw_ESP_4(); + else + gen_op_addw_ESP_im(addend); + } +} + +static void gen_pop_update(DisasContext *s) +{ + gen_stack_update(s, 2 << s->dflag); +} + +static void gen_stack_A0(DisasContext *s) +{ + gen_op_movl_A0_ESP(); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); +} + +/* NOTE: wrap around in 16 bit not fully handled */ +static void gen_pusha(DisasContext *s) +{ + int i; + gen_op_movl_A0_ESP(); + gen_op_addl_A0_im(-16 << s->dflag); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + for(i = 0;i < 8; i++) { + gen_op_mov_TN_reg[OT_LONG][0][7 - i](); + gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index](); + gen_op_addl_A0_im(2 << s->dflag); + } + gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); +} + +/* NOTE: wrap around in 16 bit not fully handled */ +static void gen_popa(DisasContext *s) +{ + int i; + gen_op_movl_A0_ESP(); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + gen_op_addl_T1_im(16 << s->dflag); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + for(i = 0;i < 8; i++) { + /* ESP is not reloaded */ + if (i != 3) { + gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index](); + gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); + } + gen_op_addl_A0_im(2 << s->dflag); + } + gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); +} + +/* NOTE: wrap around in 16 bit not fully handled */ +/* XXX: check this */ +static void gen_enter(DisasContext *s, int esp_addend, int level) +{ + int ot, level1, addend, opsize; + + ot = s->dflag + OT_WORD; + level &= 0x1f; + level1 = level; + opsize = 2 << s->dflag; + + gen_op_movl_A0_ESP(); + gen_op_addl_A0_im(-opsize); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + /* push bp */ + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_st_T0_A0[ot + s->mem_index](); + if (level) { + while (level--) { + gen_op_addl_A0_im(-opsize); + gen_op_addl_T0_im(-opsize); + gen_op_st_T0_A0[ot + s->mem_index](); + } + gen_op_addl_A0_im(-opsize); + /* XXX: add st_T1_A0 ? */ + gen_op_movl_T0_T1(); + gen_op_st_T0_A0[ot + s->mem_index](); + } + gen_op_mov_reg_T1[ot][R_EBP](); + addend = -esp_addend; + if (level1) + addend -= opsize * (level1 + 1); + gen_op_addl_T1_im(addend); + gen_op_mov_reg_T1[ot][R_ESP](); +} + +static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_raise_exception(trapno); + s->is_jmp = 3; +} + +/* an interrupt is different from an exception because of the + priviledge checks */ +static void gen_interrupt(DisasContext *s, int intno, + unsigned int cur_eip, unsigned int next_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_raise_interrupt(intno, next_eip); + s->is_jmp = 3; +} + +static void gen_debug(DisasContext *s, unsigned int cur_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_debug(); + s->is_jmp = 3; +} + +/* generate a generic end of block. Trace exception is also generated + if needed */ +static void gen_eob(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (s->tf) { + gen_op_raise_exception(EXCP01_SSTP); + } else { + gen_op_movl_T0_0(); + gen_op_exit_tb(); + } + s->is_jmp = 3; +} + +/* generate a jump to eip. No segment change must happen before as a + direct call to the next block may occur */ +static void gen_jmp(DisasContext *s, unsigned int eip) +{ + TranslationBlock *tb = s->tb; + + if (s->jmp_opt) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp((long)tb, eip); + s->is_jmp = 3; + } else { + gen_op_jmp_im(eip); + gen_eob(s); + } +} + +/* convert one instruction. s->is_jmp is set if the translation must + be stopped. Return the next pc value */ +static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) +{ + int b, prefixes, aflag, dflag; + int shift, ot; + int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; + unsigned int next_eip; + + s->pc = pc_start; + prefixes = 0; + aflag = s->code32; + dflag = s->code32; + s->override = -1; + next_byte: + b = ldub(s->pc); + s->pc++; + /* check prefixes */ + switch (b) { + case 0xf3: + prefixes |= PREFIX_REPZ; + goto next_byte; + case 0xf2: + prefixes |= PREFIX_REPNZ; + goto next_byte; + case 0xf0: + prefixes |= PREFIX_LOCK; + goto next_byte; + case 0x2e: + s->override = R_CS; + goto next_byte; + case 0x36: + s->override = R_SS; + goto next_byte; + case 0x3e: + s->override = R_DS; + goto next_byte; + case 0x26: + s->override = R_ES; + goto next_byte; + case 0x64: + s->override = R_FS; + goto next_byte; + case 0x65: + s->override = R_GS; + goto next_byte; + case 0x66: + prefixes |= PREFIX_DATA; + goto next_byte; + case 0x67: + prefixes |= PREFIX_ADR; + goto next_byte; + } + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + if (prefixes & PREFIX_ADR) + aflag ^= 1; + + s->prefix = prefixes; + s->aflag = aflag; + s->dflag = dflag; + + /* lock generation */ + if (prefixes & PREFIX_LOCK) + gen_op_lock(); + + /* now check op code */ + reswitch: + switch(b) { + case 0x0f: + /**************************/ + /* extended op code */ + b = ldub(s->pc++) | 0x100; + goto reswitch; + + /**************************/ + /* arith & logic */ + case 0x00 ... 0x05: + case 0x08 ... 0x0d: + case 0x10 ... 0x15: + case 0x18 ... 0x1d: + case 0x20 ... 0x25: + case 0x28 ... 0x2d: + case 0x30 ... 0x35: + case 0x38 ... 0x3d: + { + int op, f, val; + op = (b >> 3) & 7; + f = (b >> 1) & 3; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + switch(f) { + case 0: /* OP Ev, Gv */ + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + opreg = OR_TMP0; + } else if (op == OP_XORL && rm == reg) { + xor_zero: + /* xor reg, reg optimisation */ + gen_op_movl_T0_0(); + s->cc_op = CC_OP_LOGICB + ot; + gen_op_mov_reg_T0[ot][reg](); + gen_op_update1_cc(); + break; + } else { + opreg = rm; + } + gen_op_mov_TN_reg[ot][1][reg](); + gen_op(s, op, ot, opreg); + break; + case 1: /* OP Gv, Ev */ + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + reg = ((modrm >> 3) & 7); + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[ot + s->mem_index](); + } else if (op == OP_XORL && rm == reg) { + goto xor_zero; + } else { + gen_op_mov_TN_reg[ot][1][rm](); + } + gen_op(s, op, ot, reg); + break; + case 2: /* OP A, Iv */ + val = insn_get(s, ot); + gen_op_movl_T1_im(val); + gen_op(s, op, ot, OR_EAX); + break; + } + } + break; + + case 0x80: /* GRP1 */ + case 0x81: + case 0x83: + { + int val; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + opreg = OR_TMP0; + } else { + opreg = rm + OR_EAX; + } + + switch(b) { + default: + case 0x80: + case 0x81: + val = insn_get(s, ot); + break; + case 0x83: + val = (int8_t)insn_get(s, OT_BYTE); + break; + } + gen_op_movl_T1_im(val); + gen_op(s, op, ot, opreg); + } + break; + + /**************************/ + /* inc, dec, and other misc arith */ + case 0x40 ... 0x47: /* inc Gv */ + ot = dflag ? OT_LONG : OT_WORD; + gen_inc(s, ot, OR_EAX + (b & 7), 1); + break; + case 0x48 ... 0x4f: /* dec Gv */ + ot = dflag ? OT_LONG : OT_WORD; + gen_inc(s, ot, OR_EAX + (b & 7), -1); + break; + case 0xf6: /* GRP3 */ + case 0xf7: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + + switch(op) { + case 0: /* test */ + val = insn_get(s, ot); + gen_op_movl_T1_im(val); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + case 2: /* not */ + gen_op_notl_T0(); + if (mod != 3) { + gen_op_st_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + break; + case 3: /* neg */ + gen_op_negl_T0(); + if (mod != 3) { + gen_op_st_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + gen_op_update_neg_cc(); + s->cc_op = CC_OP_SUBB + ot; + break; + case 4: /* mul */ + switch(ot) { + case OT_BYTE: + gen_op_mulb_AL_T0(); + break; + case OT_WORD: + gen_op_mulw_AX_T0(); + break; + default: + case OT_LONG: + gen_op_mull_EAX_T0(); + break; + } + s->cc_op = CC_OP_MUL; + break; + case 5: /* imul */ + switch(ot) { + case OT_BYTE: + gen_op_imulb_AL_T0(); + break; + case OT_WORD: + gen_op_imulw_AX_T0(); + break; + default: + case OT_LONG: + gen_op_imull_EAX_T0(); + break; + } + s->cc_op = CC_OP_MUL; + break; + case 6: /* div */ + switch(ot) { + case OT_BYTE: + gen_op_divb_AL_T0(pc_start - s->cs_base); + break; + case OT_WORD: + gen_op_divw_AX_T0(pc_start - s->cs_base); + break; + default: + case OT_LONG: + gen_op_divl_EAX_T0(pc_start - s->cs_base); + break; + } + break; + case 7: /* idiv */ + switch(ot) { + case OT_BYTE: + gen_op_idivb_AL_T0(pc_start - s->cs_base); + break; + case OT_WORD: + gen_op_idivw_AX_T0(pc_start - s->cs_base); + break; + default: + case OT_LONG: + gen_op_idivl_EAX_T0(pc_start - s->cs_base); + break; + } + break; + default: + goto illegal_op; + } + break; + + case 0xfe: /* GRP4 */ + case 0xff: /* GRP5 */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + if (op >= 2 && b == 0xfe) { + goto illegal_op; + } + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (op >= 2 && op != 3 && op != 5) + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + + switch(op) { + case 0: /* inc Ev */ + if (mod != 3) + opreg = OR_TMP0; + else + opreg = rm; + gen_inc(s, ot, opreg, 1); + break; + case 1: /* dec Ev */ + if (mod != 3) + opreg = OR_TMP0; + else + opreg = rm; + gen_inc(s, ot, opreg, -1); + break; + case 2: /* call Ev */ + /* XXX: optimize if memory (no and is necessary) */ + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + next_eip = s->pc - s->cs_base; + gen_op_movl_T0_im(next_eip); + gen_push_T0(s); + gen_eob(s); + break; + case 3: /*< lcall Ev */ + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_op_ld_T0_A0[OT_WORD + s->mem_index](); + do_lcall: + if (s->pe && !s->vm86) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base); + } else { + gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); + } + gen_eob(s); + break; + case 4: /* jmp Ev */ + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_eob(s); + break; + case 5: /* ljmp Ev */ + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_op_lduw_T0_A0(); + do_ljmp: + if (s->pe && !s->vm86) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_ljmp_protected_T0_T1(); + } else { + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + gen_op_movl_T0_T1(); + gen_op_jmp_T0(); + } + gen_eob(s); + break; + case 6: /* push Ev */ + gen_push_T0(s); + break; + default: + goto illegal_op; + } + break; + + case 0x84: /* test Ev, Gv */ + case 0x85: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_TN_reg[ot][1][reg + OR_EAX](); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + + case 0xa8: /* test eAX, Iv */ + case 0xa9: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + + gen_op_mov_TN_reg[ot][0][OR_EAX](); + gen_op_movl_T1_im(val); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + + case 0x98: /* CWDE/CBW */ + if (dflag) + gen_op_movswl_EAX_AX(); + else + gen_op_movsbw_AX_AL(); + break; + case 0x99: /* CDQ/CWD */ + if (dflag) + gen_op_movslq_EDX_EAX(); + else + gen_op_movswl_DX_AX(); + break; + case 0x1af: /* imul Gv, Ev */ + case 0x69: /* imul Gv, Ev, I */ + case 0x6b: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7) + OR_EAX; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + if (b == 0x69) { + val = insn_get(s, ot); + gen_op_movl_T1_im(val); + } else if (b == 0x6b) { + val = insn_get(s, OT_BYTE); + gen_op_movl_T1_im(val); + } else { + gen_op_mov_TN_reg[ot][1][reg](); + } + + if (ot == OT_LONG) { + gen_op_imull_T0_T1(); + } else { + gen_op_imulw_T0_T1(); + } + gen_op_mov_reg_T0[ot][reg](); + s->cc_op = CC_OP_MUL; + break; + case 0x1c0: + case 0x1c1: /* xadd Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg[ot][1][rm](); + gen_op_addl_T0_T1(); + gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T1[ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_addl_T0_T1(); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_mov_reg_T1[ot][reg](); + } + gen_op_update2_cc(); + s->cc_op = CC_OP_ADDB + ot; + break; + case 0x1b0: + case 0x1b1: /* cmpxchg Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + gen_op_mov_TN_reg[ot][1][reg](); + if (mod == 3) { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][0][rm](); + gen_op_cmpxchg_T0_T1_EAX_cc[ot](); + gen_op_mov_reg_T0[ot][rm](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); + } + s->cc_op = CC_OP_SUBB + ot; + break; + case 0x1c7: /* cmpxchg8b */ + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_cmpxchg8b(); + s->cc_op = CC_OP_EFLAGS; + break; + + /**************************/ + /* push/pop */ + case 0x50 ... 0x57: /* push */ + gen_op_mov_TN_reg[OT_LONG][0][b & 7](); + gen_push_T0(s); + break; + case 0x58 ... 0x5f: /* pop */ + ot = dflag ? OT_LONG : OT_WORD; + gen_pop_T0(s); + gen_op_mov_reg_T0[ot][b & 7](); + gen_pop_update(s); + break; + case 0x60: /* pusha */ + gen_pusha(s); + break; + case 0x61: /* popa */ + gen_popa(s); + break; + case 0x68: /* push Iv */ + case 0x6a: + ot = dflag ? OT_LONG : OT_WORD; + if (b == 0x68) + val = insn_get(s, ot); + else + val = (int8_t)insn_get(s, OT_BYTE); + gen_op_movl_T0_im(val); + gen_push_T0(s); + break; + case 0x8f: /* pop Ev */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + gen_pop_T0(s); + s->popl_esp_hack = 2 << dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + s->popl_esp_hack = 0; + gen_pop_update(s); + break; + case 0xc8: /* enter */ + { + int level; + val = lduw(s->pc); + s->pc += 2; + level = ldub(s->pc++); + gen_enter(s, val, level); + } + break; + case 0xc9: /* leave */ + /* XXX: exception not precise (ESP is updated before potential exception) */ + if (s->ss32) { + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_mov_reg_T0[OT_LONG][R_ESP](); + } else { + gen_op_mov_TN_reg[OT_WORD][0][R_EBP](); + gen_op_mov_reg_T0[OT_WORD][R_ESP](); + } + gen_pop_T0(s); + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_reg_T0[ot][R_EBP](); + gen_pop_update(s); + break; + case 0x06: /* push es */ + case 0x0e: /* push cs */ + case 0x16: /* push ss */ + case 0x1e: /* push ds */ + gen_op_movl_T0_seg(b >> 3); + gen_push_T0(s); + break; + case 0x1a0: /* push fs */ + case 0x1a8: /* push gs */ + gen_op_movl_T0_seg((b >> 3) & 7); + gen_push_T0(s); + break; + case 0x07: /* pop es */ + case 0x17: /* pop ss */ + case 0x1f: /* pop ds */ + reg = b >> 3; + gen_pop_T0(s); + gen_movl_seg_T0(s, reg, pc_start - s->cs_base); + gen_pop_update(s); + if (reg == R_SS) { + /* if reg == SS, inhibit interrupts/trace */ + gen_op_set_inhibit_irq(); + s->tf = 0; + } + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + case 0x1a1: /* pop fs */ + case 0x1a9: /* pop gs */ + gen_pop_T0(s); + gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); + gen_pop_update(s); + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + + /**************************/ + /* mov */ + case 0x88: + case 0x89: /* mov Gv, Ev */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + + /* generate a generic store */ + gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1); + break; + case 0xc6: + case 0xc7: /* mov Ev, Iv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + if (mod != 3) + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + val = insn_get(s, ot); + gen_op_movl_T0_im(val); + if (mod != 3) + gen_op_st_T0_A0[ot + s->mem_index](); + else + gen_op_mov_reg_T0[ot][modrm & 7](); + break; + case 0x8a: + case 0x8b: /* mov Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_reg_T0[ot][reg](); + break; + case 0x8e: /* mov seg, Gv */ + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + if (reg >= 6 || reg == R_CS) + goto illegal_op; + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_movl_seg_T0(s, reg, pc_start - s->cs_base); + if (reg == R_SS) { + /* if reg == SS, inhibit interrupts/trace */ + gen_op_set_inhibit_irq(); + s->tf = 0; + } + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + case 0x8c: /* mov Gv, seg */ + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (reg >= 6) + goto illegal_op; + gen_op_movl_T0_seg(reg); + ot = OT_WORD; + if (mod == 3 && dflag) + ot = OT_LONG; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + + case 0x1b6: /* movzbS Gv, Eb */ + case 0x1b7: /* movzwS Gv, Eb */ + case 0x1be: /* movsbS Gv, Eb */ + case 0x1bf: /* movswS Gv, Eb */ + { + int d_ot; + /* d_ot is the size of destination */ + d_ot = dflag + OT_WORD; + /* ot is the size of source */ + ot = (b & 1) + OT_BYTE; + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7) + OR_EAX; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + + if (mod == 3) { + gen_op_mov_TN_reg[ot][0][rm](); + switch(ot | (b & 8)) { + case OT_BYTE: + gen_op_movzbl_T0_T0(); + break; + case OT_BYTE | 8: + gen_op_movsbl_T0_T0(); + break; + case OT_WORD: + gen_op_movzwl_T0_T0(); + break; + default: + case OT_WORD | 8: + gen_op_movswl_T0_T0(); + break; + } + gen_op_mov_reg_T0[d_ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (b & 8) { + gen_op_lds_T0_A0[ot + s->mem_index](); + } else { + gen_op_ldu_T0_A0[ot + s->mem_index](); + } + gen_op_mov_reg_T0[d_ot][reg](); + } + } + break; + + case 0x8d: /* lea */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + /* we must ensure that no segment is added */ + s->override = -1; + val = s->addseg; + s->addseg = 0; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + s->addseg = val; + gen_op_mov_reg_A0[ot - OT_WORD][reg](); + break; + + case 0xa0: /* mov EAX, Ov */ + case 0xa1: + case 0xa2: /* mov Ov, EAX */ + case 0xa3: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (s->aflag) + offset_addr = insn_get(s, OT_LONG); + else + offset_addr = insn_get(s, OT_WORD); + gen_op_movl_A0_im(offset_addr); + /* handle override */ + { + int override, must_add_seg; + must_add_seg = s->addseg; + if (s->override >= 0) { + override = s->override; + must_add_seg = 1; + } else { + override = R_DS; + } + if (must_add_seg) { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } + } + if ((b & 2) == 0) { + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_mov_reg_T0[ot][R_EAX](); + } else { + gen_op_mov_TN_reg[ot][0][R_EAX](); + gen_op_st_T0_A0[ot + s->mem_index](); + } + break; + case 0xd7: /* xlat */ + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_AL(); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + /* handle override */ + { + int override, must_add_seg; + must_add_seg = s->addseg; + override = R_DS; + if (s->override >= 0) { + override = s->override; + must_add_seg = 1; + } else { + override = R_DS; + } + if (must_add_seg) { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } + } + gen_op_ldu_T0_A0[OT_BYTE + s->mem_index](); + gen_op_mov_reg_T0[OT_BYTE][R_EAX](); + break; + case 0xb0 ... 0xb7: /* mov R, Ib */ + val = insn_get(s, OT_BYTE); + gen_op_movl_T0_im(val); + gen_op_mov_reg_T0[OT_BYTE][b & 7](); + break; + case 0xb8 ... 0xbf: /* mov R, Iv */ + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + reg = OR_EAX + (b & 7); + gen_op_movl_T0_im(val); + gen_op_mov_reg_T0[ot][reg](); + break; + + case 0x91 ... 0x97: /* xchg R, EAX */ + ot = dflag ? OT_LONG : OT_WORD; + reg = b & 7; + rm = R_EAX; + goto do_xchg_reg; + case 0x86: + case 0x87: /* xchg Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) { + rm = modrm & 7; + do_xchg_reg: + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg[ot][1][rm](); + gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T1[ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_mov_TN_reg[ot][0][reg](); + /* for xchg, lock is implicit */ + if (!(prefixes & PREFIX_LOCK)) + gen_op_lock(); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_st_T0_A0[ot + s->mem_index](); + if (!(prefixes & PREFIX_LOCK)) + gen_op_unlock(); + gen_op_mov_reg_T1[ot][reg](); + } + break; + case 0xc4: /* les Gv */ + op = R_ES; + goto do_lxx; + case 0xc5: /* lds Gv */ + op = R_DS; + goto do_lxx; + case 0x1b2: /* lss Gv */ + op = R_SS; + goto do_lxx; + case 0x1b4: /* lfs Gv */ + op = R_FS; + goto do_lxx; + case 0x1b5: /* lgs Gv */ + op = R_GS; + do_lxx: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + /* load the segment first to handle exceptions properly */ + gen_op_lduw_T0_A0(); + gen_movl_seg_T0(s, op, pc_start - s->cs_base); + /* then put the data */ + gen_op_mov_reg_T1[ot][reg](); + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + + /************************/ + /* shifts */ + case 0xc0: + case 0xc1: + /* shift Ev,Ib */ + shift = 2; + grp2: + { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + opreg = OR_TMP0; + } else { + opreg = rm + OR_EAX; + } + + /* simpler op */ + if (shift == 0) { + gen_shift(s, op, ot, opreg, OR_ECX); + } else { + if (shift == 2) { + shift = ldub(s->pc++); + } + gen_shifti(s, op, ot, opreg, shift); + } + } + break; + case 0xd0: + case 0xd1: + /* shift Ev,1 */ + shift = 1; + goto grp2; + case 0xd2: + case 0xd3: + /* shift Ev,cl */ + shift = 0; + goto grp2; + + case 0x1a4: /* shld imm */ + op = 0; + shift = 1; + goto do_shiftd; + case 0x1a5: /* shld cl */ + op = 0; + shift = 0; + goto do_shiftd; + case 0x1ac: /* shrd imm */ + op = 1; + shift = 1; + goto do_shiftd; + case 0x1ad: /* shrd cl */ + op = 1; + shift = 0; + do_shiftd: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + gen_op_mov_TN_reg[ot][1][reg](); + + if (shift) { + val = ldub(s->pc++); + val &= 0x1f; + if (val) { + if (mod == 3) + gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); + else + gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val); + if (op == 0 && ot != OT_WORD) + s->cc_op = CC_OP_SHLB + ot; + else + s->cc_op = CC_OP_SARB + ot; + } + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (mod == 3) + gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); + else + gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + } + if (mod == 3) { + gen_op_mov_reg_T0[ot][rm](); + } + break; + + /************************/ + /* floats */ + case 0xd8 ... 0xdf: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = ((b & 7) << 3) | ((modrm >> 3) & 7); + + if (mod != 3) { + /* memory op */ + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + switch(op) { + case 0x00 ... 0x07: /* fxxxs */ + case 0x10 ... 0x17: /* fixxxl */ + case 0x20 ... 0x27: /* fxxxl */ + case 0x30 ... 0x37: /* fixxx */ + { + int op1; + op1 = op & 7; + + switch(op >> 4) { + case 0: + gen_op_flds_FT0_A0(); + break; + case 1: + gen_op_fildl_FT0_A0(); + break; + case 2: + gen_op_fldl_FT0_A0(); + break; + case 3: + default: + gen_op_fild_FT0_A0(); + break; + } + + gen_op_fp_arith_ST0_FT0[op1](); + if (op1 == 3) { + /* fcomp needs pop */ + gen_op_fpop(); + } + } + break; + case 0x08: /* flds */ + case 0x0a: /* fsts */ + case 0x0b: /* fstps */ + case 0x18: /* fildl */ + case 0x1a: /* fistl */ + case 0x1b: /* fistpl */ + case 0x28: /* fldl */ + case 0x2a: /* fstl */ + case 0x2b: /* fstpl */ + case 0x38: /* filds */ + case 0x3a: /* fists */ + case 0x3b: /* fistps */ + + switch(op & 7) { + case 0: + switch(op >> 4) { + case 0: + gen_op_flds_ST0_A0(); + break; + case 1: + gen_op_fildl_ST0_A0(); + break; + case 2: + gen_op_fldl_ST0_A0(); + break; + case 3: + default: + gen_op_fild_ST0_A0(); + break; + } + break; + default: + switch(op >> 4) { + case 0: + gen_op_fsts_ST0_A0(); + break; + case 1: + gen_op_fistl_ST0_A0(); + break; + case 2: + gen_op_fstl_ST0_A0(); + break; + case 3: + default: + gen_op_fist_ST0_A0(); + break; + } + if ((op & 7) == 3) + gen_op_fpop(); + break; + } + break; + case 0x0c: /* fldenv mem */ + gen_op_fldenv_A0(s->dflag); + break; + case 0x0d: /* fldcw mem */ + gen_op_fldcw_A0(); + break; + case 0x0e: /* fnstenv mem */ + gen_op_fnstenv_A0(s->dflag); + break; + case 0x0f: /* fnstcw mem */ + gen_op_fnstcw_A0(); + break; + case 0x1d: /* fldt mem */ + gen_op_fldt_ST0_A0(); + break; + case 0x1f: /* fstpt mem */ + gen_op_fstt_ST0_A0(); + gen_op_fpop(); + break; + case 0x2c: /* frstor mem */ + gen_op_frstor_A0(s->dflag); + break; + case 0x2e: /* fnsave mem */ + gen_op_fnsave_A0(s->dflag); + break; + case 0x2f: /* fnstsw mem */ + gen_op_fnstsw_A0(); + break; + case 0x3c: /* fbld */ + gen_op_fbld_ST0_A0(); + break; + case 0x3e: /* fbstp */ + gen_op_fbst_ST0_A0(); + gen_op_fpop(); + break; + case 0x3d: /* fildll */ + gen_op_fildll_ST0_A0(); + break; + case 0x3f: /* fistpll */ + gen_op_fistll_ST0_A0(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + } else { + /* register float ops */ + opreg = rm; + + switch(op) { + case 0x08: /* fld sti */ + gen_op_fpush(); + gen_op_fmov_ST0_STN((opreg + 1) & 7); + break; + case 0x09: /* fxchg sti */ + gen_op_fxchg_ST0_STN(opreg); + break; + case 0x0a: /* grp d9/2 */ + switch(rm) { + case 0: /* fnop */ + break; + default: + goto illegal_op; + } + break; + case 0x0c: /* grp d9/4 */ + switch(rm) { + case 0: /* fchs */ + gen_op_fchs_ST0(); + break; + case 1: /* fabs */ + gen_op_fabs_ST0(); + break; + case 4: /* ftst */ + gen_op_fldz_FT0(); + gen_op_fcom_ST0_FT0(); + break; + case 5: /* fxam */ + gen_op_fxam_ST0(); + break; + default: + goto illegal_op; + } + break; + case 0x0d: /* grp d9/5 */ + { + switch(rm) { + case 0: + gen_op_fpush(); + gen_op_fld1_ST0(); + break; + case 1: + gen_op_fpush(); + gen_op_fldl2t_ST0(); + break; + case 2: + gen_op_fpush(); + gen_op_fldl2e_ST0(); + break; + case 3: + gen_op_fpush(); + gen_op_fldpi_ST0(); + break; + case 4: + gen_op_fpush(); + gen_op_fldlg2_ST0(); + break; + case 5: + gen_op_fpush(); + gen_op_fldln2_ST0(); + break; + case 6: + gen_op_fpush(); + gen_op_fldz_ST0(); + break; + default: + goto illegal_op; + } + } + break; + case 0x0e: /* grp d9/6 */ + switch(rm) { + case 0: /* f2xm1 */ + gen_op_f2xm1(); + break; + case 1: /* fyl2x */ + gen_op_fyl2x(); + break; + case 2: /* fptan */ + gen_op_fptan(); + break; + case 3: /* fpatan */ + gen_op_fpatan(); + break; + case 4: /* fxtract */ + gen_op_fxtract(); + break; + case 5: /* fprem1 */ + gen_op_fprem1(); + break; + case 6: /* fdecstp */ + gen_op_fdecstp(); + break; + default: + case 7: /* fincstp */ + gen_op_fincstp(); + break; + } + break; + case 0x0f: /* grp d9/7 */ + switch(rm) { + case 0: /* fprem */ + gen_op_fprem(); + break; + case 1: /* fyl2xp1 */ + gen_op_fyl2xp1(); + break; + case 2: /* fsqrt */ + gen_op_fsqrt(); + break; + case 3: /* fsincos */ + gen_op_fsincos(); + break; + case 5: /* fscale */ + gen_op_fscale(); + break; + case 4: /* frndint */ + gen_op_frndint(); + break; + case 6: /* fsin */ + gen_op_fsin(); + break; + default: + case 7: /* fcos */ + gen_op_fcos(); + break; + } + break; + case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ + case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ + case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ + { + int op1; + + op1 = op & 7; + if (op >= 0x20) { + gen_op_fp_arith_STN_ST0[op1](opreg); + if (op >= 0x30) + gen_op_fpop(); + } else { + gen_op_fmov_FT0_STN(opreg); + gen_op_fp_arith_ST0_FT0[op1](); + } + } + break; + case 0x02: /* fcom */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fcom_ST0_FT0(); + break; + case 0x03: /* fcomp */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); + break; + case 0x15: /* da/5 */ + switch(rm) { + case 1: /* fucompp */ + gen_op_fmov_FT0_STN(1); + gen_op_fucom_ST0_FT0(); + gen_op_fpop(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + break; + case 0x1c: + switch(rm) { + case 0: /* feni (287 only, just do nop here) */ + break; + case 1: /* fdisi (287 only, just do nop here) */ + break; + case 2: /* fclex */ + gen_op_fclex(); + break; + case 3: /* fninit */ + gen_op_fninit(); + break; + case 4: /* fsetpm (287 only, just do nop here) */ + break; + default: + goto illegal_op; + } + break; + case 0x1d: /* fucomi */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fucomi_ST0_FT0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x1e: /* fcomi */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcomi_ST0_FT0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x2a: /* fst sti */ + gen_op_fmov_STN_ST0(opreg); + break; + case 0x2b: /* fstp sti */ + gen_op_fmov_STN_ST0(opreg); + gen_op_fpop(); + break; + case 0x2c: /* fucom st(i) */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fucom_ST0_FT0(); + break; + case 0x2d: /* fucomp st(i) */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fucom_ST0_FT0(); + gen_op_fpop(); + break; + case 0x33: /* de/3 */ + switch(rm) { + case 1: /* fcompp */ + gen_op_fmov_FT0_STN(1); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + break; + case 0x3c: /* df/4 */ + switch(rm) { + case 0: + gen_op_fnstsw_EAX(); + break; + default: + goto illegal_op; + } + break; + case 0x3d: /* fucomip */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fucomi_ST0_FT0(); + gen_op_fpop(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x3e: /* fcomip */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcomi_ST0_FT0(); + gen_op_fpop(); + s->cc_op = CC_OP_EFLAGS; + break; + default: + goto illegal_op; + } + } + break; + /************************/ + /* string ops */ + + case 0xa4: /* movsS */ + case 0xa5: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_movs(s, ot); + } + break; + + case 0xaa: /* stosS */ + case 0xab: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_stos(s, ot); + } + break; + case 0xac: /* lodsS */ + case 0xad: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_lods(s, ot); + } + break; + case 0xae: /* scasS */ + case 0xaf: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPNZ) { + gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); + } else if (prefixes & PREFIX_REPZ) { + gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); + } else { + gen_scas(s, ot); + s->cc_op = CC_OP_SUBB + ot; + } + break; + + case 0xa6: /* cmpsS */ + case 0xa7: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPNZ) { + gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); + } else if (prefixes & PREFIX_REPZ) { + gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); + } else { + gen_cmps(s, ot); + s->cc_op = CC_OP_SUBB + ot; + } + break; + case 0x6c: /* insS */ + case 0x6d: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + /* NOTE: even for (E)CX = 0 the exception is raised */ + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_ins(s, ot); + } + } + break; + case 0x6e: /* outsS */ + case 0x6f: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + /* NOTE: even for (E)CX = 0 the exception is raised */ + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_outs(s, ot); + } + } + break; + + /************************/ + /* port I/O */ + case 0xe4: + case 0xe5: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + } + break; + case 0xe6: + case 0xe7: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + } + break; + case 0xec: + case 0xed: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + } + break; + case 0xee: + case 0xef: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + } + break; + + /************************/ + /* control */ + case 0xc2: /* ret im */ + val = ldsw(s->pc); + s->pc += 2; + gen_pop_T0(s); + gen_stack_update(s, val + (2 << s->dflag)); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_eob(s); + break; + case 0xc3: /* ret */ + gen_pop_T0(s); + gen_pop_update(s); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_eob(s); + break; + case 0xca: /* lret im */ + val = ldsw(s->pc); + s->pc += 2; + do_lret: + if (s->pe && !s->vm86) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lret_protected(s->dflag, val); + } else { + gen_stack_A0(s); + /* pop offset */ + gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + /* NOTE: keeping EIP updated is not a problem in case of + exception */ + gen_op_jmp_T0(); + /* pop selector */ + gen_op_addl_A0_im(2 << s->dflag); + gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + /* add stack offset */ + gen_stack_update(s, val + (4 << s->dflag)); + } + gen_eob(s); + break; + case 0xcb: /* lret */ + val = 0; + goto do_lret; + case 0xcf: /* iret */ + if (!s->pe) { + /* real mode */ + gen_op_iret_real(s->dflag); + s->cc_op = CC_OP_EFLAGS; + } else if (s->vm86 && s->iopl != 3) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_iret_protected(s->dflag); + s->cc_op = CC_OP_EFLAGS; + } + gen_eob(s); + break; + case 0xe8: /* call im */ + { + unsigned int next_eip; + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_op_movl_T0_im(next_eip); + gen_push_T0(s); + gen_jmp(s, val); + } + break; + case 0x9a: /* lcall im */ + { + unsigned int selector, offset; + + ot = dflag ? OT_LONG : OT_WORD; + offset = insn_get(s, ot); + selector = insn_get(s, OT_WORD); + + gen_op_movl_T0_im(selector); + gen_op_movl_T1_im(offset); + } + goto do_lcall; + case 0xe9: /* jmp */ + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + val += s->pc - s->cs_base; + if (s->dflag == 0) + val = val & 0xffff; + gen_jmp(s, val); + break; + case 0xea: /* ljmp im */ + { + unsigned int selector, offset; + + ot = dflag ? OT_LONG : OT_WORD; + offset = insn_get(s, ot); + selector = insn_get(s, OT_WORD); + + gen_op_movl_T0_im(selector); + gen_op_movl_T1_im(offset); + } + goto do_ljmp; + case 0xeb: /* jmp Jb */ + val = (int8_t)insn_get(s, OT_BYTE); + val += s->pc - s->cs_base; + if (s->dflag == 0) + val = val & 0xffff; + gen_jmp(s, val); + break; + case 0x70 ... 0x7f: /* jcc Jb */ + val = (int8_t)insn_get(s, OT_BYTE); + goto do_jcc; + case 0x180 ... 0x18f: /* jcc Jv */ + if (dflag) { + val = insn_get(s, OT_LONG); + } else { + val = (int16_t)insn_get(s, OT_WORD); + } + do_jcc: + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_jcc(s, b, val, next_eip); + break; + + case 0x190 ... 0x19f: /* setcc Gv */ + modrm = ldub(s->pc++); + gen_setcc(s, b); + gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); + break; + case 0x140 ... 0x14f: /* cmov Gv, Ev */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + gen_setcc(s, b); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[ot + s->mem_index](); + } else { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][1][rm](); + } + gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); + break; + + /************************/ + /* flags */ + case 0x9c: /* pushf */ + if (s->vm86 && s->iopl != 3) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_movl_T0_eflags(); + gen_push_T0(s); + } + break; + case 0x9d: /* popf */ + if (s->vm86 && s->iopl != 3) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_pop_T0(s); + if (s->cpl == 0) { + if (s->dflag) { + gen_op_movl_eflags_T0_cpl0(); + } else { + gen_op_movw_eflags_T0_cpl0(); + } + } else { + if (s->dflag) { + gen_op_movl_eflags_T0(); + } else { + gen_op_movw_eflags_T0(); + } + } + gen_pop_update(s); + s->cc_op = CC_OP_EFLAGS; + /* abort translation because TF flag may change */ + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + case 0x9e: /* sahf */ + gen_op_mov_TN_reg[OT_BYTE][0][R_AH](); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_movb_eflags_T0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x9f: /* lahf */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_movl_T0_eflags(); + gen_op_mov_reg_T0[OT_BYTE][R_AH](); + break; + case 0xf5: /* cmc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_cmc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xf8: /* clc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_clc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xf9: /* stc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_stc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xfc: /* cld */ + gen_op_cld(); + break; + case 0xfd: /* std */ + gen_op_std(); + break; + + /************************/ + /* bit operations */ + case 0x1ba: /* bt/bts/btr/btc Gv, im */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + op = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + /* load shift */ + val = ldub(s->pc++); + gen_op_movl_T1_im(val); + if (op < 4) + goto illegal_op; + op -= 4; + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_SARB + ot; + if (op != 0) { + if (mod != 3) + gen_op_st_T0_A0[ot + s->mem_index](); + else + gen_op_mov_reg_T0[ot][rm](); + gen_op_update_bt_cc(); + } + break; + case 0x1a3: /* bt Gv, Ev */ + op = 0; + goto do_btx; + case 0x1ab: /* bts */ + op = 1; + goto do_btx; + case 0x1b3: /* btr */ + op = 2; + goto do_btx; + case 0x1bb: /* btc */ + op = 3; + do_btx: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + gen_op_mov_TN_reg[OT_LONG][1][reg](); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* specific case: we need to add a displacement */ + if (ot == OT_WORD) + gen_op_add_bitw_A0_T1(); + else + gen_op_add_bitl_A0_T1(); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_SARB + ot; + if (op != 0) { + if (mod != 3) + gen_op_st_T0_A0[ot + s->mem_index](); + else + gen_op_mov_reg_T0[ot][rm](); + gen_op_update_bt_cc(); + } + break; + case 0x1bc: /* bsf */ + case 0x1bd: /* bsr */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_bsx_T0_cc[ot - OT_WORD][b & 1](); + /* NOTE: we always write back the result. Intel doc says it is + undefined if T0 == 0 */ + gen_op_mov_reg_T0[ot][reg](); + s->cc_op = CC_OP_LOGICB + ot; + break; + /************************/ + /* bcd */ + case 0x27: /* daa */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_daa(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x2f: /* das */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_das(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x37: /* aaa */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_aaa(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x3f: /* aas */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_aas(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xd4: /* aam */ + val = ldub(s->pc++); + gen_op_aam(val); + s->cc_op = CC_OP_LOGICB; + break; + case 0xd5: /* aad */ + val = ldub(s->pc++); + gen_op_aad(val); + s->cc_op = CC_OP_LOGICB; + break; + /************************/ + /* misc */ + case 0x90: /* nop */ + break; + case 0x9b: /* fwait */ + break; + case 0xcc: /* int3 */ + gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); + break; + case 0xcd: /* int N */ + val = ldub(s->pc++); + /* XXX: add error code for vm86 GPF */ + if (!s->vm86) + gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); + else + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + break; + case 0xce: /* into */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_into(s->pc - s->cs_base); + break; + case 0xf1: /* icebp (undocumented, exits to external debugger) */ + gen_debug(s, pc_start - s->cs_base); + break; + case 0xfa: /* cli */ + if (!s->vm86) { + if (s->cpl <= s->iopl) { + gen_op_cli(); + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } + } else { + if (s->iopl == 3) { + gen_op_cli(); + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } + } + break; + case 0xfb: /* sti */ + if (!s->vm86) { + if (s->cpl <= s->iopl) { + gen_sti: + gen_op_sti(); + /* interruptions are enabled only the first insn after sti */ + gen_op_set_inhibit_irq(); + /* give a chance to handle pending irqs */ + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } + } else { + if (s->iopl == 3) { + goto gen_sti; + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } + } + break; + case 0x62: /* bound */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + gen_op_mov_reg_T0[ot][reg](); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (ot == OT_WORD) + gen_op_boundw(pc_start - s->cs_base); + else + gen_op_boundl(pc_start - s->cs_base); + break; + case 0x1c8 ... 0x1cf: /* bswap reg */ + reg = b & 7; + gen_op_mov_TN_reg[OT_LONG][0][reg](); + gen_op_bswapl_T0(); + gen_op_mov_reg_T0[OT_LONG][reg](); + break; + case 0xd6: /* salc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_salc(); + break; + case 0xe0: /* loopnz */ + case 0xe1: /* loopz */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + /* FALL THRU */ + case 0xe2: /* loop */ + case 0xe3: /* jecxz */ + val = (int8_t)insn_get(s, OT_BYTE); + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_op_loop[s->aflag][b & 3](val, next_eip); + gen_eob(s); + break; + case 0x130: /* wrmsr */ + case 0x132: /* rdmsr */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (b & 2) + gen_op_rdmsr(); + else + gen_op_wrmsr(); + } + break; + case 0x131: /* rdtsc */ + gen_op_rdtsc(); + break; + case 0x1a2: /* cpuid */ + gen_op_cpuid(); + break; + case 0xf4: /* hlt */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(s->pc - s->cs_base); + gen_op_hlt(); + s->is_jmp = 3; + } + break; + case 0x100: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* sldt */ + gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); + ot = OT_WORD; + if (mod == 3) + ot += s->dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 2: /* lldt */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lldt_T0(); + } + break; + case 1: /* str */ + gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); + ot = OT_WORD; + if (mod == 3) + ot += s->dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 3: /* ltr */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_ltr_T0(); + } + break; + case 4: /* verr */ + case 5: /* verw */ + default: + goto illegal_op; + } + break; + case 0x101: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* sgdt */ + case 1: /* sidt */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (op == 0) + gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); + else + gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + gen_op_addl_A0_im(2); + if (op == 0) + gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); + else + gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + gen_op_st_T0_A0[OT_LONG + s->mem_index](); + break; + case 2: /* lgdt */ + case 3: /* lidt */ + if (mod == 3) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[OT_WORD + s->mem_index](); + gen_op_addl_A0_im(2); + gen_op_ld_T0_A0[OT_LONG + s->mem_index](); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + if (op == 2) { + gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base)); + gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit)); + } else { + gen_op_movl_env_T0(offsetof(CPUX86State,idt.base)); + gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit)); + } + } + break; + case 4: /* smsw */ + gen_op_movl_T0_env(offsetof(CPUX86State,cr[0])); + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); + break; + case 6: /* lmsw */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_lmsw_T0(); + } + break; + case 7: /* invlpg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_invlpg_A0(); + } + break; + default: + goto illegal_op; + } + break; + case 0x102: /* lar */ + case 0x103: /* lsl */ + if (!s->pe || s->vm86) + goto illegal_op; + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_TN_reg[ot][1][reg](); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (b == 0x102) + gen_op_lar(); + else + gen_op_lsl(); + s->cc_op = CC_OP_EFLAGS; + gen_op_mov_reg_T1[ot][reg](); + break; + case 0x118: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* prefetchnta */ + case 1: /* prefetchnt0 */ + case 2: /* prefetchnt0 */ + case 3: /* prefetchnt0 */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* nothing more to do */ + break; + default: + goto illegal_op; + } + break; + case 0x120: /* mov reg, crN */ + case 0x122: /* mov crN, reg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + modrm = ldub(s->pc++); + if ((modrm & 0xc0) != 0xc0) + goto illegal_op; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + switch(reg) { + case 0: + case 2: + case 3: + case 4: + if (b & 2) { + gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_movl_crN_T0(reg); + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } else { + gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); + gen_op_mov_reg_T0[OT_LONG][rm](); + } + break; + default: + goto illegal_op; + } + } + break; + case 0x121: /* mov reg, drN */ + case 0x123: /* mov drN, reg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + modrm = ldub(s->pc++); + if ((modrm & 0xc0) != 0xc0) + goto illegal_op; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + /* XXX: do it dynamically with CR4.DE bit */ + if (reg == 4 || reg == 5) + goto illegal_op; + if (b & 2) { + gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_movl_drN_T0(reg); + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } else { + gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); + gen_op_mov_reg_T0[OT_LONG][rm](); + } + } + break; + case 0x106: /* clts */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_op_clts(); + } + break; + default: + goto illegal_op; + } + /* lock generation */ + if (s->prefix & PREFIX_LOCK) + gen_op_unlock(); + return s->pc; + illegal_op: + /* XXX: ensure that no lock was generated */ + gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); + return s->pc; +} + +#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) +#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P) + +/* flags read by an operation */ +static uint16_t opc_read_flags[NB_OPS] = { + [INDEX_op_aas] = CC_A, + [INDEX_op_aaa] = CC_A, + [INDEX_op_das] = CC_A | CC_C, + [INDEX_op_daa] = CC_A | CC_C, + + [INDEX_op_adcb_T0_T1_cc] = CC_C, + [INDEX_op_adcw_T0_T1_cc] = CC_C, + [INDEX_op_adcl_T0_T1_cc] = CC_C, + [INDEX_op_sbbb_T0_T1_cc] = CC_C, + [INDEX_op_sbbw_T0_T1_cc] = CC_C, + [INDEX_op_sbbl_T0_T1_cc] = CC_C, + + [INDEX_op_adcb_mem_T0_T1_cc] = CC_C, + [INDEX_op_adcw_mem_T0_T1_cc] = CC_C, + [INDEX_op_adcl_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbb_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbw_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbl_mem_T0_T1_cc] = CC_C, + + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_update_inc_cc] = CC_C, + + [INDEX_op_into] = CC_O, + + [INDEX_op_jb_subb] = CC_C, + [INDEX_op_jb_subw] = CC_C, + [INDEX_op_jb_subl] = CC_C, + + [INDEX_op_jz_subb] = CC_Z, + [INDEX_op_jz_subw] = CC_Z, + [INDEX_op_jz_subl] = CC_Z, + + [INDEX_op_jbe_subb] = CC_Z | CC_C, + [INDEX_op_jbe_subw] = CC_Z | CC_C, + [INDEX_op_jbe_subl] = CC_Z | CC_C, + + [INDEX_op_js_subb] = CC_S, + [INDEX_op_js_subw] = CC_S, + [INDEX_op_js_subl] = CC_S, + + [INDEX_op_jl_subb] = CC_O | CC_S, + [INDEX_op_jl_subw] = CC_O | CC_S, + [INDEX_op_jl_subl] = CC_O | CC_S, + + [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z, + [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z, + [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z, + + [INDEX_op_loopnzw] = CC_Z, + [INDEX_op_loopnzl] = CC_Z, + [INDEX_op_loopzw] = CC_Z, + [INDEX_op_loopzl] = CC_Z, + + [INDEX_op_seto_T0_cc] = CC_O, + [INDEX_op_setb_T0_cc] = CC_C, + [INDEX_op_setz_T0_cc] = CC_Z, + [INDEX_op_setbe_T0_cc] = CC_Z | CC_C, + [INDEX_op_sets_T0_cc] = CC_S, + [INDEX_op_setp_T0_cc] = CC_P, + [INDEX_op_setl_T0_cc] = CC_O | CC_S, + [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z, + + [INDEX_op_setb_T0_subb] = CC_C, + [INDEX_op_setb_T0_subw] = CC_C, + [INDEX_op_setb_T0_subl] = CC_C, + + [INDEX_op_setz_T0_subb] = CC_Z, + [INDEX_op_setz_T0_subw] = CC_Z, + [INDEX_op_setz_T0_subl] = CC_Z, + + [INDEX_op_setbe_T0_subb] = CC_Z | CC_C, + [INDEX_op_setbe_T0_subw] = CC_Z | CC_C, + [INDEX_op_setbe_T0_subl] = CC_Z | CC_C, + + [INDEX_op_sets_T0_subb] = CC_S, + [INDEX_op_sets_T0_subw] = CC_S, + [INDEX_op_sets_T0_subl] = CC_S, + + [INDEX_op_setl_T0_subb] = CC_O | CC_S, + [INDEX_op_setl_T0_subw] = CC_O | CC_S, + [INDEX_op_setl_T0_subl] = CC_O | CC_S, + + [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z, + [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z, + [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, + + [INDEX_op_movl_T0_eflags] = CC_OSZAPC, + [INDEX_op_cmc] = CC_C, + [INDEX_op_salc] = CC_C, + + [INDEX_op_rclb_T0_T1_cc] = CC_C, + [INDEX_op_rclw_T0_T1_cc] = CC_C, + [INDEX_op_rcll_T0_T1_cc] = CC_C, + [INDEX_op_rcrb_T0_T1_cc] = CC_C, + [INDEX_op_rcrw_T0_T1_cc] = CC_C, + [INDEX_op_rcrl_T0_T1_cc] = CC_C, + + [INDEX_op_rclb_mem_T0_T1_cc] = CC_C, + [INDEX_op_rclw_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcll_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrb_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrw_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrl_mem_T0_T1_cc] = CC_C, +}; + +/* flags written by an operation */ +static uint16_t opc_write_flags[NB_OPS] = { + [INDEX_op_update2_cc] = CC_OSZAPC, + [INDEX_op_update1_cc] = CC_OSZAPC, + [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_update_neg_cc] = CC_OSZAPC, + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_update_inc_cc] = CC_OSZAPC, + [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_mulb_AL_T0] = CC_OSZAPC, + [INDEX_op_imulb_AL_T0] = CC_OSZAPC, + [INDEX_op_mulw_AX_T0] = CC_OSZAPC, + [INDEX_op_imulw_AX_T0] = CC_OSZAPC, + [INDEX_op_mull_EAX_T0] = CC_OSZAPC, + [INDEX_op_imull_EAX_T0] = CC_OSZAPC, + [INDEX_op_imulw_T0_T1] = CC_OSZAPC, + [INDEX_op_imull_T0_T1] = CC_OSZAPC, + + /* bcd */ + [INDEX_op_aam] = CC_OSZAPC, + [INDEX_op_aad] = CC_OSZAPC, + [INDEX_op_aas] = CC_OSZAPC, + [INDEX_op_aaa] = CC_OSZAPC, + [INDEX_op_das] = CC_OSZAPC, + [INDEX_op_daa] = CC_OSZAPC, + + [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, + [INDEX_op_movw_eflags_T0] = CC_OSZAPC, + [INDEX_op_movl_eflags_T0] = CC_OSZAPC, + [INDEX_op_clc] = CC_C, + [INDEX_op_stc] = CC_C, + [INDEX_op_cmc] = CC_C, + + [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_bsfw_T0_cc] = CC_OSZAPC, + [INDEX_op_bsfl_T0_cc] = CC_OSZAPC, + [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, + [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, + + [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, + + [INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC, + + [INDEX_op_cmpxchg8b] = CC_Z, + [INDEX_op_lar] = CC_Z, + [INDEX_op_lsl] = CC_Z, + [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, + [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, +}; + +/* simpler form of an operation if no flags need to be generated */ +static uint16_t opc_simpler[NB_OPS] = { + [INDEX_op_update2_cc] = INDEX_op_nop, + [INDEX_op_update1_cc] = INDEX_op_nop, + [INDEX_op_update_neg_cc] = INDEX_op_nop, +#if 0 + /* broken: CC_OP logic must be rewritten */ + [INDEX_op_update_inc_cc] = INDEX_op_nop, +#endif + [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1, + [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1, + [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1, + + [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1, + [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1, + [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1, + + [INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1, + [INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1, + [INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1, + + [INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1, + [INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1, + [INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1, + + [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, + [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, + [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1, + + [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1, + [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1, + [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1, + + [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1, + [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1, + [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, +}; + +void optimize_flags_init(void) +{ + int i; + /* put default values in arrays */ + for(i = 0; i < NB_OPS; i++) { + if (opc_simpler[i] == 0) + opc_simpler[i] = i; + } +} + +/* CPU flags computation optimization: we move backward thru the + generated code to see which flags are needed. The operation is + modified if suitable */ +static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) +{ + uint16_t *opc_ptr; + int live_flags, write_flags, op; + + opc_ptr = opc_buf + opc_buf_len; + /* live_flags contains the flags needed by the next instructions + in the code. At the end of the bloc, we consider that all the + flags are live. */ + live_flags = CC_OSZAPC; + while (opc_ptr > opc_buf) { + op = *--opc_ptr; + /* if none of the flags written by the instruction is used, + then we can try to find a simpler instruction */ + write_flags = opc_write_flags[op]; + if ((live_flags & write_flags) == 0) { + *opc_ptr = opc_simpler[op]; + } + /* compute the live flags before the instruction */ + live_flags &= ~write_flags; + live_flags |= opc_read_flags[op]; + } +} + +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) +{ + DisasContext dc1, *dc = &dc1; + uint8_t *pc_ptr; + uint16_t *gen_opc_end; + int flags, j, lj; + uint8_t *pc_start; + uint8_t *cs_base; + + /* generate intermediate code */ + pc_start = (uint8_t *)tb->pc; + cs_base = (uint8_t *)tb->cs_base; + flags = tb->flags; + + dc->pe = env->cr[0] & CR0_PE_MASK; + dc->code32 = (flags >> HF_CS32_SHIFT) & 1; + dc->ss32 = (flags >> HF_SS32_SHIFT) & 1; + dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1; + dc->f_st = 0; + dc->vm86 = (flags >> VM_SHIFT) & 1; + dc->cpl = (flags >> HF_CPL_SHIFT) & 3; + dc->iopl = (flags >> IOPL_SHIFT) & 3; + dc->tf = (flags >> TF_SHIFT) & 1; + dc->cc_op = CC_OP_DYNAMIC; + dc->cs_base = cs_base; + dc->tb = tb; + dc->popl_esp_hack = 0; + /* select memory access functions */ + dc->mem_index = 0; + if (flags & HF_SOFTMMU_MASK) { + if (dc->cpl == 3) + dc->mem_index = 6; + else + dc->mem_index = 3; + } + dc->jmp_opt = !(dc->tf || env->singlestep_enabled +#ifndef CONFIG_SOFT_MMU + || (flags & HF_SOFTMMU_MASK) +#endif + ); + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + + dc->is_jmp = DISAS_NEXT; + pc_ptr = pc_start; + lj = -1; + + /* if irq were inhibited for the next instruction, we can disable + them here as it is simpler (otherwise jumps would have to + handled as special case) */ + if (flags & HF_INHIBIT_IRQ_MASK) { + gen_op_reset_inhibit_irq(); + } + for(;;) { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == (unsigned long)pc_ptr) { + gen_debug(dc, pc_ptr - dc->cs_base); + break; + } + } + } + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = (uint32_t)pc_ptr; + gen_opc_cc_op[lj] = dc->cc_op; + gen_opc_instr_start[lj] = 1; + } + pc_ptr = disas_insn(dc, pc_ptr); + /* stop translation if indicated */ + if (dc->is_jmp) + break; + /* if single step mode, we generate only one instruction and + generate an exception */ + if (dc->tf) { + gen_op_jmp_im(pc_ptr - dc->cs_base); + gen_eob(dc); + break; + } + /* if too long translation, stop generation too */ + if (gen_opc_ptr >= gen_opc_end || + (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + gen_op_jmp_im(pc_ptr - dc->cs_base); + gen_eob(dc); + break; + } + } + *gen_opc_ptr = INDEX_op_end; + /* we don't forget to fill the last values */ + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } + +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "----------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32); + fprintf(logfile, "\n"); + + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + + /* optimize flag computations */ + optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf); + +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "AFTER FLAGS OPT:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + if (!search_pc) + tb->size = pc_ptr - pc_start; + return 0; +} + +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 1); +} + -- cgit v1.2.3 From 7a3f194486ad5c8e21c96a19dee37b14a1057580 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 20:36:07 +0000 Subject: sparc emulation target (thanx to Thomas M. Ogrisegg) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@386 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/sparc/syscall.h | 7 + linux-user/sparc/syscall_nr.h | 220 +++++++++++++ target-sparc/cpu.h | 46 +++ target-sparc/exec.h | 16 + target-sparc/op.c | 500 ++++++++++++++++++++++++++++ target-sparc/op_template.h | 48 +++ target-sparc/translate.c | 744 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1581 insertions(+) create mode 100644 linux-user/sparc/syscall.h create mode 100644 linux-user/sparc/syscall_nr.h create mode 100644 target-sparc/cpu.h create mode 100644 target-sparc/exec.h create mode 100644 target-sparc/op.c create mode 100644 target-sparc/op_template.h create mode 100644 target-sparc/translate.c diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h new file mode 100644 index 000000000..474c87c30 --- /dev/null +++ b/linux-user/sparc/syscall.h @@ -0,0 +1,7 @@ +struct target_pt_regs { + target_ulong psr; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong u_regs[16]; +}; diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h new file mode 100644 index 000000000..afb364f07 --- /dev/null +++ b/linux-user/sparc/syscall_nr.h @@ -0,0 +1,220 @@ +#define TARGET_NR_exit 1 /* Common */ +#define TARGET_NR_fork 2 /* Common */ +#define TARGET_NR_read 3 /* Common */ +#define TARGET_NR_write 4 /* Common */ +#define TARGET_NR_open 5 /* Common */ +#define TARGET_NR_close 6 /* Common */ +#define TARGET_NR_wait4 7 /* Common */ +#define TARGET_NR_creat 8 /* Common */ +#define TARGET_NR_link 9 /* Common */ +#define TARGET_NR_unlink 10 /* Common */ +#define TARGET_NR_execv 11 /* SunOS Specific */ +#define TARGET_NR_chdir 12 /* Common */ +#define TARGET_NR_chown 13 /* Common */ +#define TARGET_NR_mknod 14 /* Common */ +#define TARGET_NR_chmod 15 /* Common */ +#define TARGET_NR_lchown 16 /* Common */ +#define TARGET_NR_brk 17 /* Common */ +#define TARGET_NR_perfctr 18 /* Performance counter operations */ +#define TARGET_NR_lseek 19 /* Common */ +#define TARGET_NR_getpid 20 /* Common */ +#define TARGET_NR_capget 21 /* Linux Specific */ +#define TARGET_NR_capset 22 /* Linux Specific */ +#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */ +#define TARGET_NR_getuid 24 /* Common */ +#define TARGET_NR_ptrace 26 /* Common */ +#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */ +#define TARGET_NR_sigaltstack 28 /* Common */ +#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */ +#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */ +#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */ +#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */ +#define TARGET_NR_access 33 /* Common */ +#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */ +#define TARGET_NR_chown32 35 /* Linux sparc32 specific */ +#define TARGET_NR_sync 36 /* Common */ +#define TARGET_NR_kill 37 /* Common */ +#define TARGET_NR_stat 38 /* Common */ +#define TARGET_NR_sendfile 39 /* Linux Specific */ +#define TARGET_NR_lstat 40 /* Common */ +#define TARGET_NR_dup 41 /* Common */ +#define TARGET_NR_pipe 42 /* Common */ +#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */ +#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */ +#define TARGET_NR_umount2 45 /* Linux Specific */ +#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */ +#define TARGET_NR_getgid 47 /* Common */ +#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */ +#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */ +#define TARGET_NR_getegid 50 /* SunOS calls getgid() */ +#define TARGET_NR_acct 51 /* Common */ +#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */ +#define TARGET_NR_ioctl 54 /* Common */ +#define TARGET_NR_reboot 55 /* Common */ +#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */ +#define TARGET_NR_symlink 57 /* Common */ +#define TARGET_NR_readlink 58 /* Common */ +#define TARGET_NR_execve 59 /* Common */ +#define TARGET_NR_umask 60 /* Common */ +#define TARGET_NR_chroot 61 /* Common */ +#define TARGET_NR_fstat 62 /* Common */ +#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */ +#define TARGET_NR_getpagesize 64 /* Common */ +#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */ +#define TARGET_NR_vfork 66 /* Common */ +#define TARGET_NR_pread 67 /* Linux Specific */ +#define TARGET_NR_pwrite 68 /* Linux Specific */ +#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */ +#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */ +#define TARGET_NR_mmap 71 /* Common */ +#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */ +#define TARGET_NR_munmap 73 /* Common */ +#define TARGET_NR_mprotect 74 /* Common */ +#define TARGET_NR_madvise 75 /* Common */ +#define TARGET_NR_vhangup 76 /* Common */ +#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */ +#define TARGET_NR_mincore 78 /* Common */ +#define TARGET_NR_getgroups 79 /* Common */ +#define TARGET_NR_setgroups 80 /* Common */ +#define TARGET_NR_getpgrp 81 /* Common */ +#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */ +#define TARGET_NR_setitimer 83 /* Common */ +#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */ +#define TARGET_NR_swapon 85 /* Common */ +#define TARGET_NR_getitimer 86 /* Common */ +#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */ +#define TARGET_NR_sethostname 88 /* Common */ +#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */ +#define TARGET_NR_dup2 90 /* Common */ +#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */ +#define TARGET_NR_fcntl 92 /* Common */ +#define TARGET_NR_select 93 /* Common */ +#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */ +#define TARGET_NR_fsync 95 /* Common */ +#define TARGET_NR_setpriority 96 /* Common */ +#define TARGET_NR_socket 97 /* Common */ +#define TARGET_NR_connect 98 /* Common */ +#define TARGET_NR_accept 99 /* Common */ +#define TARGET_NR_getpriority 100 /* Common */ +#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */ +#define TARGET_NR_rt_sigaction 102 /* Linux Specific */ +#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */ +#define TARGET_NR_rt_sigpending 104 /* Linux Specific */ +#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */ +#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */ +#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */ +#define TARGET_NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */ +#define TARGET_NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */ +#define TARGET_NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */ +#define TARGET_NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */ +#define TARGET_NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */ +#define TARGET_NR_recvmsg 113 /* Common */ +#define TARGET_NR_sendmsg 114 /* Common */ +#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */ +#define TARGET_NR_gettimeofday 116 /* Common */ +#define TARGET_NR_getrusage 117 /* Common */ +#define TARGET_NR_getsockopt 118 /* Common */ +#define TARGET_NR_getcwd 119 /* Linux Specific */ +#define TARGET_NR_readv 120 /* Common */ +#define TARGET_NR_writev 121 /* Common */ +#define TARGET_NR_settimeofday 122 /* Common */ +#define TARGET_NR_fchown 123 /* Common */ +#define TARGET_NR_fchmod 124 /* Common */ +#define TARGET_NR_recvfrom 125 /* Common */ +#define TARGET_NR_setreuid 126 /* Common */ +#define TARGET_NR_setregid 127 /* Common */ +#define TARGET_NR_rename 128 /* Common */ +#define TARGET_NR_truncate 129 /* Common */ +#define TARGET_NR_ftruncate 130 /* Common */ +#define TARGET_NR_flock 131 /* Common */ +#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */ +#define TARGET_NR_sendto 133 /* Common */ +#define TARGET_NR_shutdown 134 /* Common */ +#define TARGET_NR_socketpair 135 /* Common */ +#define TARGET_NR_mkdir 136 /* Common */ +#define TARGET_NR_rmdir 137 /* Common */ +#define TARGET_NR_utimes 138 /* SunOS Specific */ +#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */ +#define TARGET_NR_getpeername 141 /* Common */ +#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */ +#define TARGET_NR_getrlimit 144 /* Common */ +#define TARGET_NR_setrlimit 145 /* Common */ +#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */ +#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */ +#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */ +#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */ +#define TARGET_NR_getsockname 150 /* Common */ +#define TARGET_NR_poll 153 /* Common */ +#define TARGET_NR_getdents64 154 /* Linux specific */ +#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */ +#define TARGET_NR_statfs 157 /* Common */ +#define TARGET_NR_fstatfs 158 /* Common */ +#define TARGET_NR_umount 159 /* Common */ +#define TARGET_NR_getdomainname 162 /* SunOS Specific */ +#define TARGET_NR_setdomainname 163 /* Common */ +#define TARGET_NR_quotactl 165 /* Common */ +#define TARGET_NR_mount 167 /* Common */ +#define TARGET_NR_ustat 168 /* Common */ +#define TARGET_NR_getdents 174 /* Common */ +#define TARGET_NR_setsid 175 /* Common */ +#define TARGET_NR_fchdir 176 /* Common */ +#define TARGET_NR_sigpending 183 /* Common */ +#define TARGET_NR_query_module 184 /* Linux Specific */ +#define TARGET_NR_setpgid 185 /* Common */ +#define TARGET_NR_tkill 187 /* SunOS: fpathconf */ +#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */ +#define TARGET_NR_uname 189 /* Linux Specific */ +#define TARGET_NR_init_module 190 /* Linux Specific */ +#define TARGET_NR_personality 191 /* Linux Specific */ +#define TARGET_NR_getppid 197 /* Linux Specific */ +#define TARGET_NR_sigaction 198 /* Linux Specific */ +#define TARGET_NR_sgetmask 199 /* Linux Specific */ +#define TARGET_NR_ssetmask 200 /* Linux Specific */ +#define TARGET_NR_sigsuspend 201 /* Linux Specific */ +#define TARGET_NR_oldlstat 202 /* Linux Specific */ +#define TARGET_NR_uselib 203 /* Linux Specific */ +#define TARGET_NR_readdir 204 /* Linux Specific */ +#define TARGET_NR_readahead 205 /* Linux Specific */ +#define TARGET_NR_socketcall 206 /* Linux Specific */ +#define TARGET_NR_syslog 207 /* Linux Specific */ +#define TARGET_NR_waitpid 212 /* Linux Specific */ +#define TARGET_NR_swapoff 213 /* Linux Specific */ +#define TARGET_NR_sysinfo 214 /* Linux Specific */ +#define TARGET_NR_ipc 215 /* Linux Specific */ +#define TARGET_NR_sigreturn 216 /* Linux Specific */ +#define TARGET_NR_clone 217 /* Linux Specific */ +#define TARGET_NR_adjtimex 219 /* Linux Specific */ +#define TARGET_NR_sigprocmask 220 /* Linux Specific */ +#define TARGET_NR_create_module 221 /* Linux Specific */ +#define TARGET_NR_delete_module 222 /* Linux Specific */ +#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */ +#define TARGET_NR_getpgid 224 /* Linux Specific */ +#define TARGET_NR_bdflush 225 /* Linux Specific */ +#define TARGET_NR_sysfs 226 /* Linux Specific */ +#define TARGET_NR_afs_syscall 227 /* Linux Specific */ +#define TARGET_NR_setfsuid 228 /* Linux Specific */ +#define TARGET_NR_setfsgid 229 /* Linux Specific */ +#define TARGET_NR__newselect 230 /* Linux Specific */ +#define TARGET_NR_time 231 /* Linux Specific */ +#define TARGET_NR_stime 233 /* Linux Specific */ +#define TARGET_NR__llseek 236 /* Linux Specific */ +#define TARGET_NR_mlock 237 +#define TARGET_NR_munlock 238 +#define TARGET_NR_mlockall 239 +#define TARGET_NR_munlockall 240 +#define TARGET_NR_sched_setparam 241 +#define TARGET_NR_sched_getparam 242 +#define TARGET_NR_sched_setscheduler 243 +#define TARGET_NR_sched_getscheduler 244 +#define TARGET_NR_sched_yield 245 +#define TARGET_NR_sched_get_priority_max 246 +#define TARGET_NR_sched_get_priority_min 247 +#define TARGET_NR_sched_rr_get_interval 248 +#define TARGET_NR_nanosleep 249 +#define TARGET_NR_mremap 250 +#define TARGET_NR__sysctl 251 +#define TARGET_NR_getsid 252 +#define TARGET_NR_fdatasync 253 +#define TARGET_NR_nfsservctl 254 +#define TARGET_NR_aplib 255 +#define TARGET_NR__exit TARGET_NR_exit diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h new file mode 100644 index 000000000..350d7b719 --- /dev/null +++ b/target-sparc/cpu.h @@ -0,0 +1,46 @@ +#ifndef CPU_SPARC_H +#define CPU_SPARC_H + +#include +#include "config.h" +#include "cpu-defs.h" + +/*#define EXCP_INTERRUPT 0x100*/ + + +#define PSR_NEG (1<<23) +#define PSR_ZERO (1<<22) +#define PSR_OVF (1<<21) +#define PSR_CARRY (1<<20) + +typedef struct CPUSPARCState { + uint32_t gregs[8]; /* general registers */ + uint32_t *regwptr; /* pointer to current register window */ + double *regfptr; /* floating point registers */ + uint32_t pc; /* program counter */ + uint32_t npc; /* next program counter */ + uint32_t sp; /* stack pointer */ + uint32_t y; /* multiply/divide register */ + uint32_t psr; /* processor state register */ + uint32_t T2; + jmp_buf jmp_env; + int user_mode_only; + int exception_index; + int interrupt_index; + int interrupt_request; + struct TranslationBlock *current_tb; + void *opaque; +} CPUSPARCState; + +CPUSPARCState *cpu_sparc_init(void); +int cpu_sparc_exec(CPUSPARCState *s); +int cpu_sparc_close(CPUSPARCState *s); + +struct siginfo; +int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); +void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags); + +#define TARGET_PAGE_BITS 13 +#include "cpu-all.h" + +#endif diff --git a/target-sparc/exec.h b/target-sparc/exec.h new file mode 100644 index 000000000..72e4588f6 --- /dev/null +++ b/target-sparc/exec.h @@ -0,0 +1,16 @@ +#ifndef EXEC_SPARC_H +#define EXEC_SPARC_H 1 +#include "dyngen-exec.h" + +register struct CPUSPARCState *env asm(AREG0); +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +register uint32_t T2 asm(AREG3); + +#include "cpu.h" +#include "exec-all.h" + +void cpu_lock(void); +void cpu_unlock(void); +void cpu_loop_exit(void); +#endif diff --git a/target-sparc/op.c b/target-sparc/op.c new file mode 100644 index 000000000..d36566164 --- /dev/null +++ b/target-sparc/op.c @@ -0,0 +1,500 @@ +/* + SPARC micro operations + + Copyright (C) 2003 Thomas M. Ogrisegg + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "exec.h" + +/*XXX*/ +#define REGNAME g0 +#define REG (env->gregs[0]) +#include "op_template.h" +#define REGNAME g1 +#define REG (env->gregs[1]) +#include "op_template.h" +#define REGNAME g2 +#define REG (env->gregs[2]) +#include "op_template.h" +#define REGNAME g3 +#define REG (env->gregs[3]) +#include "op_template.h" +#define REGNAME g4 +#define REG (env->gregs[4]) +#include "op_template.h" +#define REGNAME g5 +#define REG (env->gregs[5]) +#include "op_template.h" +#define REGNAME g6 +#define REG (env->gregs[6]) +#include "op_template.h" +#define REGNAME g7 +#define REG (env->gregs[7]) +#include "op_template.h" +#define REGNAME i0 +#define REG (env->regwptr[16]) +#include "op_template.h" +#define REGNAME i1 +#define REG (env->regwptr[17]) +#include "op_template.h" +#define REGNAME i2 +#define REG (env->regwptr[18]) +#include "op_template.h" +#define REGNAME i3 +#define REG (env->regwptr[19]) +#include "op_template.h" +#define REGNAME i4 +#define REG (env->regwptr[20]) +#include "op_template.h" +#define REGNAME i5 +#define REG (env->regwptr[21]) +#include "op_template.h" +#define REGNAME i6 +#define REG (env->regwptr[22]) +#include "op_template.h" +#define REGNAME i7 +#define REG (env->regwptr[23]) +#include "op_template.h" +#define REGNAME l0 +#define REG (env->regwptr[8]) +#include "op_template.h" +#define REGNAME l1 +#define REG (env->regwptr[9]) +#include "op_template.h" +#define REGNAME l2 +#define REG (env->regwptr[10]) +#include "op_template.h" +#define REGNAME l3 +#define REG (env->regwptr[11]) +#include "op_template.h" +#define REGNAME l4 +#define REG (env->regwptr[12]) +#include "op_template.h" +#define REGNAME l5 +#define REG (env->regwptr[13]) +#include "op_template.h" +#define REGNAME l6 +#define REG (env->regwptr[14]) +#include "op_template.h" +#define REGNAME l7 +#define REG (env->regwptr[15]) +#include "op_template.h" +#define REGNAME o0 +#define REG (env->regwptr[0]) +#include "op_template.h" +#define REGNAME o1 +#define REG (env->regwptr[1]) +#include "op_template.h" +#define REGNAME o2 +#define REG (env->regwptr[2]) +#include "op_template.h" +#define REGNAME o3 +#define REG (env->regwptr[3]) +#include "op_template.h" +#define REGNAME o4 +#define REG (env->regwptr[4]) +#include "op_template.h" +#define REGNAME o5 +#define REG (env->regwptr[5]) +#include "op_template.h" +#define REGNAME o6 +#define REG (env->regwptr[6]) +#include "op_template.h" +#define REGNAME o7 +#define REG (env->regwptr[7]) +#include "op_template.h" + +#define EIP (env->pc) + +void OPPROTO op_movl_T0_0(void) +{ + T0 = 0; +} + +void OPPROTO op_movl_T0_1(void) +{ + T0 = 1; +} + +void OPPROTO op_movl_T0_im(void) +{ + T0 = PARAM1; +} + +void OPPROTO op_movl_T1_im(void) +{ + T1 = PARAM1; +} + +void OPPROTO op_movl_T2_im(void) +{ + T2 = PARAM1; +} + +void OPPROTO op_addl_T1_im(void) +{ + T1 += PARAM1; +} + +void OPPROTO op_addl_T1_T2(void) +{ + T1 += T2; +} + +void OPPROTO op_subl_T1_T2(void) +{ + T1 -= T2; +} + +void OPPROTO op_add_T1_T0 (void) +{ + T0 += T1; +} + +void OPPROTO op_and_T1_T0 (void) +{ + T0 &= T1; +} + +void OPPROTO op_or_T1_T0 (void) +{ + T0 |= T1; +} + +void OPPROTO op_xor_T1_T0 (void) +{ + T0 ^= T1; +} + +void OPPROTO op_sub_T1_T0 (void) +{ + T0 -= T1; +} + +void OPPROTO op_andn_T1_T0 (void) +{ + T0 &= ~T1; +} + +void OPPROTO op_orn_T1_T0 (void) +{ + T0 |= ~T1; +} + +void OPPROTO op_xnor_T1_T0 (void) +{ + T0 ^= ~T1; +} + +void OPPROTO op_addx_T1_T0 (void) +{ + T0 += T1+((env->psr & PSR_CARRY)?1:0); +} + +void OPPROTO op_umul_T1_T0 (void) +{ + unsigned long long res = T0*T1; + T0 = res & 0xffffffff; + env->y = res >> 32; +} + +void OPPROTO op_smul_T1_T0 (void) +{ + long long res = T0*T1; + T0 = res & 0xffffffff; + env->y = res >> 32; +} + +void OPPROTO op_udiv_T1_T0 (void) +{ + unsigned long long x0 = T0 * env->y; + unsigned int x1 = T1; + T0 = x0 / x1; +} + +void OPPROTO op_sdiv_T1_T0 (void) +{ + long long x0 = T0 * env->y; + int x1 = T1; + T0 = x0 / x1; +} + +void OPPROTO op_subx_T1_T0 (void) +{ + T0 -= T1+((env->psr & PSR_CARRY)?1:0); +} + +void OPPROTO op_set_flags (void) +{ + env->psr = 0; + if (!T0) env->psr |= PSR_ZERO; + if ((unsigned int) T0 < (unsigned int) T1) env->psr |= PSR_CARRY; + if ((int) T0 < (int) T1) env->psr |= PSR_OVF; + if ((int) T0 < 0) env->psr |= PSR_NEG; +} + +void OPPROTO op_sll (void) +{ + T0 <<= T1; +} + +void OPPROTO op_srl (void) +{ + T0 >>= T1; +} + +void OPPROTO op_sra (void) +{ + int x = T0 >> T1; + T0 = x; +} + +void OPPROTO op_st (void) +{ + stl ((void *) T0, T1); +} + +void OPPROTO op_stb (void) +{ + stb ((void *) T0, T1); +} + +void OPPROTO op_sth (void) +{ + stw ((void *) T0, T1); +} + +void OPPROTO op_ld (void) +{ + T1 = ldl ((void *) T0); +} + +void OPPROTO op_ldub (void) +{ + T1 = ldub ((void *) T0); +} + +void OPPROTO op_lduh (void) +{ + T1 = lduw ((void *) T0); +} + +void OPPROTO op_ldsb (void) +{ + T1 = ldsb ((void *) T0); +} + +void OPPROTO op_ldsh (void) +{ + T1 = ldsw ((void *) T0); +} + +void OPPROTO op_ldstub (void) +{ + T1 = ldub ((void *) T0); + stb ((void *) T0, 0xff); /* XXX: Should be Atomically */ +} + +void OPPROTO op_swap (void) +{ + unsigned int tmp = ldl ((void *) T0); + stl ((void *) T0, T1); /* XXX: Should be Atomically */ + T1 = tmp; +} + +void OPPROTO op_ldd (void) +{ + T1 = ldl ((void *) T0); + T0 = ldl ((void *) T0+4); +} + +void OPPROTO op_wry (void) +{ + env->y = T0^T1; +} + +void OPPROTO op_rdy (void) +{ + T0 = env->y; +} + +#define regwptr (env->regwptr) + +void OPPROTO op_save (void) +{ + regwptr -= 16; +} + +void OPPROTO op_restore (void) +{ + regwptr += 16; +} + +void OPPROTO op_trap (void) +{ + env->exception_index = PARAM1; + cpu_loop_exit (); +} + +void OPPROTO op_exit_tb (void) +{ + EXIT_TB (); +} + +void OPPROTO op_eval_be (void) +{ + T0 = (env->psr & PSR_ZERO); +} + +#define FLAG_SET(x) (env->psr&x)?1:0 +#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY) + +void OPPROTO op_eval_ble (void) +{ + GET_FLAGS; + T0 = Z | (N^V); +} + +void OPPROTO op_eval_bl (void) +{ + GET_FLAGS; + T0 = N^V; +} + +void OPPROTO op_eval_bleu (void) +{ + GET_FLAGS; + T0 = C|Z; +} + +void OPPROTO op_eval_bcs (void) +{ + T0 = (env->psr & PSR_CARRY); +} + +void OPPROTO op_eval_bvs (void) +{ + T0 = (env->psr & PSR_OVF); +} + +void OPPROTO op_eval_bneg (void) +{ + T0 = (env->psr & PSR_NEG); +} + +void OPPROTO op_eval_bne (void) +{ + T0 = !(env->psr & PSR_ZERO); +} + +void OPPROTO op_eval_bg (void) +{ + GET_FLAGS; + T0 = !(Z | (N^V)); +} + +/*XXX: This seems to be documented wrong in the SPARC V8 Manual + The manual states: !(N^V) + but I assume Z | !(N^V) to be correct */ +void OPPROTO op_eval_bge (void) +{ + GET_FLAGS; + T0 = Z | !(N^V); +} + +void OPPROTO op_eval_bgu (void) +{ + GET_FLAGS; + T0 = !(C | Z); +} + +void OPPROTO op_eval_bcc (void) +{ + T0 = !(env->psr & PSR_CARRY); +} + +void OPPROTO op_eval_bpos (void) +{ + T0 = !(env->psr & PSR_NEG); +} + +void OPPROTO op_eval_bvc (void) +{ + T0 = !(env->psr & PSR_OVF); +} + +void OPPROTO op_jmp_im (void) +{ + env->pc = PARAM1; +} + +void OPPROTO op_call (void) +{ + regwptr[7] = PARAM1-4; + env->pc = PARAM1+PARAM2; +} + +void OPPROTO op_jmpl (void) +{ + env->npc = T0; +} + +void OPPROTO op_generic_jmp_1 (void) +{ + T1 = PARAM1; + env->pc = PARAM1+PARAM2; +} + +void OPPROTO op_generic_jmp_2 (void) +{ + T1 = PARAM1; + env->pc = env->npc; +} + +unsigned long old_T0; + +void OPPROTO op_save_T0 (void) +{ + old_T0 = T0; +} + +void OPPROTO op_restore_T0 (void) +{ + T0 = old_T0; +} + +void OPPROTO op_generic_branch (void) +{ + if (T0) + JUMP_TB (__func__, PARAM1, 0, PARAM2); + else + JUMP_TB (__func__, PARAM1, 1, PARAM3); + FORCE_RET (); +} + +void OPPROTO op_generic_branch_a (void) +{ + if (T0) + env->npc = PARAM3; + else + JUMP_TB (__func__, PARAM1, 0, PARAM2); + FORCE_RET (); +} + +void OPPROTO op_noop (void) +{ +} diff --git a/target-sparc/op_template.h b/target-sparc/op_template.h new file mode 100644 index 000000000..ecf65fd70 --- /dev/null +++ b/target-sparc/op_template.h @@ -0,0 +1,48 @@ +/* + * SPARC micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void OPPROTO glue(op_movl_T0_, REGNAME)(void) +{ + T0 = REG; +} + +void OPPROTO glue(op_movl_T1_, REGNAME)(void) +{ + T1 = REG; +} + +void OPPROTO glue(op_movl_T2_, REGNAME)(void) +{ + T2 = REG; +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) +{ + REG = T0; +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) +{ + REG = T1; +} + +#undef REG +#undef REGNAME diff --git a/target-sparc/translate.c b/target-sparc/translate.c new file mode 100644 index 000000000..d302c3dec --- /dev/null +++ b/target-sparc/translate.c @@ -0,0 +1,744 @@ +/* + SPARC translation + + Copyright (C) 2003 Thomas M. Ogrisegg + + 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 + */ + +/* + SPARC has two pitfalls: Delay slots and (a)nullification. + This is currently solved as follows: + + 'call' instructions simply execute the delay slot before the actual + control transfer instructions. + + 'jmpl' instructions execute calculate the destination, then execute + the delay slot and then do the control transfer. + + (conditional) branch instructions are the most difficult ones, as the + delay slot may be nullified (ie. not executed). This happens when a + conditional branch is not executed (thus no control transfer happens) + and the 'anull' bit in the branch instruction opcode is set. This is + currently solved by doing a jump after the delay slot instruction. + + There is also one big (currently unsolved) bug in the branch code: + If a delay slot modifies the condition codes then the new condition + codes, instead of the old ones will be used. + + TODO-list: + + FPU-Instructions + Coprocessor-Instructions + Fix above bug + Check signedness issues + Privileged instructions + Register window overflow/underflow check + Optimize synthetic instructions + Optional alignment and privileged instruction check + + -- TMO, 09/03/03 + */ + +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +#define DEBUG_DISAS + +typedef struct DisasContext { + uint8_t *pc; + uint8_t *npc; + void (*branch) (struct DisasContext *, uint32_t, uint32_t); + unsigned int delay_slot:2; + uint32_t insn; + uint32_t target; + int is_br; + struct TranslationBlock *tb; +} DisasContext; + +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; +extern FILE *logfile; +extern int loglevel; + +enum { +#define DEF(s,n,copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS +}; + +#include "gen-op.h" + +#define GET_FIELD(X, FROM, TO) \ + ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) + +#define IS_IMM (insn & (1<<13)) + +static void disas_sparc_insn (DisasContext *dc); + +typedef void (GenOpFunc)(void); +typedef void (GenOpFunc1)(long); +typedef void (GenOpFunc2)(long, long); +typedef void (GenOpFunc3)(long, long, long); + +static GenOpFunc *gen_op_movl_TN_reg[2][32] = { + { + gen_op_movl_g0_T0, + gen_op_movl_g1_T0, + gen_op_movl_g2_T0, + gen_op_movl_g3_T0, + gen_op_movl_g4_T0, + gen_op_movl_g5_T0, + gen_op_movl_g6_T0, + gen_op_movl_g7_T0, + gen_op_movl_o0_T0, + gen_op_movl_o1_T0, + gen_op_movl_o2_T0, + gen_op_movl_o3_T0, + gen_op_movl_o4_T0, + gen_op_movl_o5_T0, + gen_op_movl_o6_T0, + gen_op_movl_o7_T0, + gen_op_movl_l0_T0, + gen_op_movl_l1_T0, + gen_op_movl_l2_T0, + gen_op_movl_l3_T0, + gen_op_movl_l4_T0, + gen_op_movl_l5_T0, + gen_op_movl_l6_T0, + gen_op_movl_l7_T0, + gen_op_movl_i0_T0, + gen_op_movl_i1_T0, + gen_op_movl_i2_T0, + gen_op_movl_i3_T0, + gen_op_movl_i4_T0, + gen_op_movl_i5_T0, + gen_op_movl_i6_T0, + gen_op_movl_i7_T0, + }, + { + gen_op_movl_g0_T1, + gen_op_movl_g1_T1, + gen_op_movl_g2_T1, + gen_op_movl_g3_T1, + gen_op_movl_g4_T1, + gen_op_movl_g5_T1, + gen_op_movl_g6_T1, + gen_op_movl_g7_T1, + gen_op_movl_o0_T1, + gen_op_movl_o1_T1, + gen_op_movl_o2_T1, + gen_op_movl_o3_T1, + gen_op_movl_o4_T1, + gen_op_movl_o5_T1, + gen_op_movl_o6_T1, + gen_op_movl_o7_T1, + gen_op_movl_l0_T1, + gen_op_movl_l1_T1, + gen_op_movl_l2_T1, + gen_op_movl_l3_T1, + gen_op_movl_l4_T1, + gen_op_movl_l5_T1, + gen_op_movl_l6_T1, + gen_op_movl_l7_T1, + gen_op_movl_i0_T1, + gen_op_movl_i1_T1, + gen_op_movl_i2_T1, + gen_op_movl_i3_T1, + gen_op_movl_i4_T1, + gen_op_movl_i5_T1, + gen_op_movl_i6_T1, + gen_op_movl_i7_T1, + } +}; + +static GenOpFunc *gen_op_movl_reg_TN[3][32] = { + { + gen_op_movl_T0_g0, + gen_op_movl_T0_g1, + gen_op_movl_T0_g2, + gen_op_movl_T0_g3, + gen_op_movl_T0_g4, + gen_op_movl_T0_g5, + gen_op_movl_T0_g6, + gen_op_movl_T0_g7, + gen_op_movl_T0_o0, + gen_op_movl_T0_o1, + gen_op_movl_T0_o2, + gen_op_movl_T0_o3, + gen_op_movl_T0_o4, + gen_op_movl_T0_o5, + gen_op_movl_T0_o6, + gen_op_movl_T0_o7, + gen_op_movl_T0_l0, + gen_op_movl_T0_l1, + gen_op_movl_T0_l2, + gen_op_movl_T0_l3, + gen_op_movl_T0_l4, + gen_op_movl_T0_l5, + gen_op_movl_T0_l6, + gen_op_movl_T0_l7, + gen_op_movl_T0_i0, + gen_op_movl_T0_i1, + gen_op_movl_T0_i2, + gen_op_movl_T0_i3, + gen_op_movl_T0_i4, + gen_op_movl_T0_i5, + gen_op_movl_T0_i6, + gen_op_movl_T0_i7, + }, + { + gen_op_movl_T1_g0, + gen_op_movl_T1_g1, + gen_op_movl_T1_g2, + gen_op_movl_T1_g3, + gen_op_movl_T1_g4, + gen_op_movl_T1_g5, + gen_op_movl_T1_g6, + gen_op_movl_T1_g7, + gen_op_movl_T1_o0, + gen_op_movl_T1_o1, + gen_op_movl_T1_o2, + gen_op_movl_T1_o3, + gen_op_movl_T1_o4, + gen_op_movl_T1_o5, + gen_op_movl_T1_o6, + gen_op_movl_T1_o7, + gen_op_movl_T1_l0, + gen_op_movl_T1_l1, + gen_op_movl_T1_l2, + gen_op_movl_T1_l3, + gen_op_movl_T1_l4, + gen_op_movl_T1_l5, + gen_op_movl_T1_l6, + gen_op_movl_T1_l7, + gen_op_movl_T1_i0, + gen_op_movl_T1_i1, + gen_op_movl_T1_i2, + gen_op_movl_T1_i3, + gen_op_movl_T1_i4, + gen_op_movl_T1_i5, + gen_op_movl_T1_i6, + gen_op_movl_T1_i7, + }, + { + gen_op_movl_T2_g0, + gen_op_movl_T2_g1, + gen_op_movl_T2_g2, + gen_op_movl_T2_g3, + gen_op_movl_T2_g4, + gen_op_movl_T2_g5, + gen_op_movl_T2_g6, + gen_op_movl_T2_g7, + gen_op_movl_T2_o0, + gen_op_movl_T2_o1, + gen_op_movl_T2_o2, + gen_op_movl_T2_o3, + gen_op_movl_T2_o4, + gen_op_movl_T2_o5, + gen_op_movl_T2_o6, + gen_op_movl_T2_o7, + gen_op_movl_T2_l0, + gen_op_movl_T2_l1, + gen_op_movl_T2_l2, + gen_op_movl_T2_l3, + gen_op_movl_T2_l4, + gen_op_movl_T2_l5, + gen_op_movl_T2_l6, + gen_op_movl_T2_l7, + gen_op_movl_T2_i0, + gen_op_movl_T2_i1, + gen_op_movl_T2_i2, + gen_op_movl_T2_i3, + gen_op_movl_T2_i4, + gen_op_movl_T2_i5, + gen_op_movl_T2_i6, + gen_op_movl_T2_i7, + } +}; + +static GenOpFunc1 *gen_op_movl_TN_im[3] = { + gen_op_movl_T0_im, + gen_op_movl_T1_im, + gen_op_movl_T2_im +}; + +static inline void gen_movl_imm_TN (int reg, int imm) +{ + gen_op_movl_TN_im[reg](imm); +} + +static inline void gen_movl_imm_T1 (int val) +{ + gen_movl_imm_TN (1, val); +} + +static inline void gen_movl_imm_T0 (int val) +{ + gen_movl_imm_TN (0, val); +} + +static inline void gen_movl_reg_TN (int reg, int t) +{ + if (reg) gen_op_movl_reg_TN[t][reg](); + else gen_movl_imm_TN (t, 0); +} + +static inline void gen_movl_reg_T0 (int reg) +{ + gen_movl_reg_TN (reg, 0); +} + +static inline void gen_movl_reg_T1 (int reg) +{ + gen_movl_reg_TN (reg, 1); +} + +static inline void gen_movl_reg_T2 (int reg) +{ + gen_movl_reg_TN (reg, 2); +} + +static inline void gen_movl_TN_reg (int reg, int t) +{ + if (reg) gen_op_movl_TN_reg[t][reg](); +} + +static inline void gen_movl_T0_reg (int reg) +{ + gen_movl_TN_reg (reg, 0); +} + +static inline void gen_movl_T1_reg (int reg) +{ + gen_movl_TN_reg (reg, 1); +} + +static void do_branch (DisasContext *dc, uint32_t target, uint32_t insn) +{ + unsigned int cond = GET_FIELD (insn, 3, 6), a = (insn & (1<<29)), ib = 0; + target += (uint32_t) dc->pc-4; + if (!a) disas_sparc_insn (dc); + switch (cond) { + case 0x0: gen_op_movl_T0_0 (); break; + case 0x1: gen_op_eval_be (); break; + case 0x2: gen_op_eval_ble (); break; + case 0x3: gen_op_eval_bl (); break; + case 0x4: gen_op_eval_bleu (); break; + case 0x5: gen_op_eval_bcs (); break; + case 0x6: gen_op_eval_bneg (); break; + case 0x7: gen_op_eval_bvs (); break; + case 0x8: gen_op_movl_T0_1 (); break; + case 0x9: gen_op_eval_bne (); break; + case 0xa: gen_op_eval_bg (); break; + case 0xb: gen_op_eval_bge (); break; + case 0xc: gen_op_eval_bgu (); break; + case 0xd: gen_op_eval_bcc (); break; + case 0xe: gen_op_eval_bpos (); break; + case 0xf: gen_op_eval_bvc (); break; + } + if (a && ((cond|0x8) != 0x8)) { + gen_op_generic_branch_a ((uint32_t) dc->tb, + (uint32_t) dc->pc+4, target); + disas_sparc_insn (dc); + ib = 1; + } + else + if (cond && !a) { + gen_op_generic_branch ((uint32_t) dc->tb, (uint32_t) target, + (uint32_t) dc->pc); + ib = 1; + } + if (ib) dc->is_br = DISAS_JUMP; +} + +/* target == 0x1 means CALL- else JMPL-instruction */ +static void do_jump (DisasContext *dc, uint32_t target, uint32_t rd) +{ + uint32_t orig_pc = (uint32_t) dc->pc-8; + if (target != 0x1) + gen_op_generic_jmp_1 (orig_pc, target); + else + gen_op_generic_jmp_2 (orig_pc); + gen_movl_T1_reg (rd); + dc->is_br = DISAS_JUMP; + gen_op_movl_T0_0 (); +} + +#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), b-a) + +static int +sign_extend (x, len) + int x, len; +{ + int signbit = (1 << (len - 1)); + int mask = (signbit << 1) - 1; + return ((x & mask) ^ signbit) - signbit; +} + +static void disas_sparc_insn (DisasContext *dc) +{ + unsigned int insn, opc, rs1, rs2, rd; + + if (dc->delay_slot == 1) { + insn = dc->insn; + } else { + if (dc->delay_slot) dc->delay_slot--; + insn = htonl (*(unsigned int *) (dc->pc)); + dc->pc += 4; + } + + opc = GET_FIELD (insn, 0, 1); + + rd = GET_FIELD (insn, 2, 6); + switch (opc) { + case 0: /* branches/sethi */ + { + unsigned int xop = GET_FIELD (insn, 7, 9); + int target; + target = GET_FIELD (insn, 10, 31); + switch (xop) { + case 0x0: case 0x1: /* UNIMPL */ + printf ("UNIMPLEMENTED: %p\n", dc->pc-4); + exit (23); + break; + case 0x2: /* BN+x */ + { + target <<= 2; + target = sign_extend (target, 22); + do_branch (dc, target, insn); + break; + } + case 0x3: /* FBN+x */ + break; + case 0x4: /* SETHI */ + gen_movl_imm_T0 (target<<10); + gen_movl_T0_reg (rd); + break; + case 0x5: /*CBN+x*/ + break; + } + break; + } + case 1: /*CALL*/ + { + unsigned int target = GET_FIELDs (insn, 2, 31) << 2; + if (dc->delay_slot) { + do_jump (dc, target, 15); + dc->delay_slot = 0; + } else { + dc->insn = insn; + dc->delay_slot = 2; + } + break; + } + case 2: /* FPU & Logical Operations */ + { + unsigned int xop = GET_FIELD (insn, 7, 12); + if (xop == 58) { /* generate trap */ + dc->is_br = DISAS_JUMP; + gen_op_jmp_im ((uint32_t) dc->pc); + if (IS_IMM) gen_op_trap (GET_FIELD (insn, 25, 31)); + /* else XXX*/ + gen_op_movl_T0_0 (); + break; + } + if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ + exit (33); + } + rs1 = GET_FIELD (insn, 13, 17); + gen_movl_reg_T0 (rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs (insn, 20, 31); + gen_movl_imm_T1 (rs2); + } else { /* register */ + rs2 = GET_FIELD (insn, 27, 31); + gen_movl_reg_T1 (rs2); + } + if (xop < 0x20) { + switch (xop &~ 0x10) { + case 0x0: + gen_op_add_T1_T0 (); + break; + case 0x1: + gen_op_and_T1_T0 (); + break; + case 0x2: + gen_op_or_T1_T0 (); + break; + case 0x3: + gen_op_xor_T1_T0 (); + break; + case 0x4: + gen_op_sub_T1_T0 (); + break; + case 0x5: + gen_op_andn_T1_T0 (); + break; + case 0x6: + gen_op_orn_T1_T0 (); + break; + case 0x7: + gen_op_xnor_T1_T0 (); + break; + case 0x8: + gen_op_addx_T1_T0 (); + break; + case 0xa: + gen_op_umul_T1_T0 (); + break; + case 0xb: + gen_op_smul_T1_T0 (); + break; + case 0xc: + gen_op_subx_T1_T0 (); + break; + case 0xe: + gen_op_udiv_T1_T0 (); + break; + case 0xf: + gen_op_sdiv_T1_T0 (); + break; + default: + exit (17); + break; + } + gen_movl_T0_reg (rd); + if (xop & 0x10) { + gen_op_set_flags (); + } + } else { + switch (xop) { + case 0x25: /* SLL */ + gen_op_sll (); + break; + case 0x26: + gen_op_srl (); + break; + case 0x27: + gen_op_sra (); + break; + case 0x28: case 0x30: + { + unsigned int rdi = GET_FIELD (insn, 13, 17); + if (!rdi) (xop==0x28?gen_op_rdy ():gen_op_wry()); + /* else gen_op_su_trap (); */ + break; + } + /* Problem with jmpl: if restore is executed in the delay + slot, then the wrong registers are beeing used */ + case 0x38: /* jmpl */ + { + if (dc->delay_slot) { + gen_op_add_T1_T0 (); + do_jump (dc, 1, rd); + dc->delay_slot = 0; + } else { + gen_op_add_T1_T0 (); + gen_op_jmpl (); + dc->insn = insn; + dc->delay_slot = 2; + } + break; + } + case 0x3c: /* save */ + gen_op_add_T1_T0 (); + gen_op_save (); + gen_movl_T0_reg (rd); + break; + case 0x3d: /* restore */ + gen_op_add_T1_T0 (); + gen_op_restore (); + gen_movl_T0_reg (rd); + break; + } + } + break; + } + case 3: /* load/store instructions */ + { + unsigned int xop = GET_FIELD (insn, 7, 12); + rs1 = GET_FIELD (insn, 13, 17); + gen_movl_reg_T0 (rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs (insn, 20, 31); + gen_movl_imm_T1 (rs2); + } else { /* register */ + rs2 = GET_FIELD (insn, 27, 31); + gen_movl_reg_T1 (rs2); + } + gen_op_add_T1_T0 (); + if (xop < 4 || xop > 7) { + switch (xop) { + case 0x0: /* load word */ + gen_op_ld (); + break; + case 0x1: /* load unsigned byte */ + gen_op_ldub (); + break; + case 0x2: /* load unsigned halfword */ + gen_op_lduh (); + break; + case 0x3: /* load double word */ + gen_op_ldd (); + gen_movl_T0_reg (rd+1); + break; + case 0x9: /* load signed byte */ + gen_op_ldsb (); + break; + case 0xa: /* load signed halfword */ + gen_op_ldsh (); + break; + case 0xd: /* ldstub -- XXX: should be atomically */ + gen_op_ldstub (); + break; + case 0x0f: /* swap register with memory. Also atomically */ + gen_op_swap (); + break; + } + gen_movl_T1_reg (rd); + } else if (xop < 8) { + gen_movl_reg_T1 (rd); + switch (xop) { + case 0x4: + gen_op_st (); + break; + case 0x5: + gen_op_stb (); + break; + case 0x6: + gen_op_sth (); + break; + case 0x7: + gen_op_st (); + gen_movl_reg_T1 (rd+1); + gen_op_st (); + break; + } + } + } + } +} + +static inline int gen_intermediate_code_internal (TranslationBlock *tb, int spc) +{ + uint8_t *pc_start = (uint8_t *) tb->pc; + uint16_t *gen_opc_end; + DisasContext dc; + + memset (&dc, 0, sizeof (dc)); + if (spc) { + printf ("SearchPC not yet supported\n"); + exit (0); + } + dc.tb = tb; + dc.pc = pc_start; + + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + + do { + disas_sparc_insn (&dc); + } while (!dc.is_br && (gen_opc_ptr < gen_opc_end) && + (dc.pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + + switch (dc.is_br) { + case DISAS_JUMP: + case DISAS_TB_JUMP: + gen_op_exit_tb (); + break; + } + + *gen_opc_ptr = INDEX_op_end; +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf (logfile, "--------------\n"); + fprintf (logfile, "IN: %s\n", lookup_symbol (pc_start)); + disas(logfile, pc_start, dc.pc - pc_start, 0, 0); + fprintf(logfile, "\n"); + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + + return 0; +} + +int gen_intermediate_code (CPUSPARCState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(tb, 0); +} + +int gen_intermediate_code_pc (CPUSPARCState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(tb, 1); +} + +void *mycpu; + +CPUSPARCState *cpu_sparc_init (void) +{ + CPUSPARCState *env; + + cpu_exec_init (); + + if (!(env = malloc (sizeof(CPUSPARCState)))) + return (NULL); + memset (env, 0, sizeof (*env)); + if (!(env->regwptr = malloc (0x2000))) + return (NULL); + memset (env->regwptr, 0, 0x2000); + env->regwptr += 127; + env->user_mode_only = 1; + mycpu = env; + return (env); +} + +#define GET_FLAG(a,b) ((env->psr & a)?b:'-') + +void cpu_sparc_dump_state (CPUSPARCState *env, FILE *f, int flags) +{ + int i, x; + + fprintf (f, "@PC: %p\n", (void *) env->pc); + fprintf (f, "General Registers:\n"); + for (i=0;i<4;i++) + fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]); + fprintf (f, "\n"); + for (;i<8;i++) + fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]); + fprintf (f, "\nCurrent Register Window:\n"); + for (x=0;x<3;x++) { + for (i=0;i<4;i++) + fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':(x==1?'l':'i')), i, env->regwptr[i+x*8]); + fprintf (f, "\n"); + for (;i<8;i++) + fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':x==1?'l':'i'), i, env->regwptr[i+x*8]); + fprintf (f, "\n"); + } + fprintf (f, "PSR: %x -> %c%c%c%c\n", env->psr, + GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), + GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C')); +} -- cgit v1.2.3 From 1e43adfc89d2730ab5b24b7a6b5c8ed373b6e284 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 20:54:24 +0000 Subject: new directory structure - changed naming of qemu and vl git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@387 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 37 +++++---------------------------- Makefile.target | 64 ++++++++++++++++++++++++++++++++++++--------------------- configure | 16 +++++++++++---- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/Makefile b/Makefile index 28b08cade..bb5f574c0 100644 --- a/Makefile +++ b/Makefile @@ -4,14 +4,14 @@ CFLAGS=-Wall -O2 -g LDFLAGS=-g LIBS= DEFINES+=-D_GNU_SOURCE -TOOLS=vlmkcow +TOOLS=qemu-mkcow all: dyngen $(TOOLS) qemu-doc.html for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done -vlmkcow: vlmkcow.o +qemu-mkcow: qemu-mkcow.o $(HOST_CC) -o $@ $^ $(LIBS) dyngen: dyngen.o @@ -52,39 +52,12 @@ TAGS: qemu-doc.html: qemu-doc.texi texi2html -monolithic -number $< -FILES= \ -README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \ -configure Makefile Makefile.target \ -dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \ -elf.h elfload.c main.c signal.c qemu.h \ -syscall.c syscall_defs.h vm86.c path.c mmap.c \ -i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld m68k.ld \ -vl.c i386-vl.ld vl.h block.c vlmkcow.c vga.c vga_template.h sdl.c \ -thunk.c cpu-exec.c translate.c cpu-all.h cpu-defs.h thunk.h exec.h\ -exec.c cpu-exec.c gdbstub.c bswap.h \ -cpu-i386.h op-i386.c helper-i386.c helper2-i386.c syscall-i386.h translate-i386.c \ -exec-i386.h ops_template.h ops_template_mem.h opreg_template.h \ -ops_mem.h softmmu_template.h softmmu_header.h \ -cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \ -dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \ -arm-dis.c \ -tests/Makefile \ -tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \ -tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \ -tests/hello-i386.c tests/hello-i386 \ -tests/hello-arm.c tests/hello-arm \ -tests/sha1.c \ -tests/testsig.c tests/testclone.c tests/testthread.c \ -tests/runcom.c tests/pi_10.com \ -tests/test_path.c \ -qemu-doc.texi qemu-doc.html - -FILE=qemu-$(VERSION) +FILE=qemu-$(shell cat VERSION) +# tar release (use 'make -k tar' on a checkouted tree) tar: rm -rf /tmp/$(FILE) - mkdir -p /tmp/$(FILE) - cp --parent $(FILES) /tmp/$(FILE) + cp -r . /tmp/$(FILE) ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) ) rm -rf /tmp/$(FILE) diff --git a/Makefile.target b/Makefile.target index 712869351..ee5443867 100644 --- a/Makefile.target +++ b/Makefile.target @@ -1,14 +1,24 @@ include config.mak -VPATH=$(SRC_PATH) +TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) +VPATH=$(SRC_PATH):$(TARGET_PATH) CFLAGS=-Wall -O2 -g LDFLAGS=-g LIBS= -DEFINES=-I. +DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH) HELPER_CFLAGS=$(CFLAGS) DYNGEN=../dyngen +# user emulator name +QEMU_USER=qemu-$(TARGET_ARCH) +# system emulator name +ifdef CONFIG_SOFTMMU +QEMU_SYSTEM=qemu-softmmu +else +QEMU_SYSTEM=qemu +endif + ifndef CONFIG_SOFTMMU -PROGS=qemu +PROGS=$(QEMU_USER) endif ifdef CONFIG_STATIC @@ -32,7 +42,7 @@ else LDFLAGS+=-Wl,-shared endif ifeq ($(TARGET_ARCH), i386) -PROGS+=vl +PROGS+=$(QEMU_SYSTEM) endif endif @@ -108,13 +118,11 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a # cpu emulator library -LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o +LIBOBJS=thunk.o exec.o translate-all.o cpu-exec.o gdbstub.o \ + translate.o op.o ifeq ($(TARGET_ARCH), i386) -LIBOBJS+=translate-i386.o op-i386.o helper-i386.o helper2-i386.o -endif -ifeq ($(TARGET_ARCH), arm) -LIBOBJS+=translate-arm.o op-arm.o +LIBOBJS+=helper.o helper2.o endif # NOTE: the disassembler code is only needed for debugging @@ -139,9 +147,9 @@ ifeq ($(ARCH),ia64) OBJS += ia64-syscall.o endif -all: $(PROGS) qemu-doc.html +all: $(PROGS) -qemu: $(OBJS) +$(QEMU_USER): $(OBJS) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) ifeq ($(ARCH),alpha) # Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of @@ -156,7 +164,7 @@ VL_OBJS+=sdl.o SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm endif -vl: $(VL_OBJS) libqemu.a +$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(CC) -static -Wl,-T,$(SRC_PATH)/i386-vl.ld -o $@ $^ $(LIBS) $(SDL_LIBS) sdl.o: sdl.c @@ -171,35 +179,45 @@ libqemu.a: $(LIBOBJS) rm -f $@ $(AR) rcs $@ $(LIBOBJS) -translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h +translate.o: translate.c gen-op.h opc.h cpu.h -translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h +translate-all.o: translate-all.c op.h opc.h cpu.h -op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN) +op.h: op.o $(DYNGEN) $(DYNGEN) -o $@ $< -opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN) +opc.h: op.o $(DYNGEN) $(DYNGEN) -c -o $@ $< -gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o $(DYNGEN) +gen-op.h: op.o $(DYNGEN) $(DYNGEN) -g -o $@ $< -op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c +op.o: op.c $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $< -helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c +helper.o: helper.c $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< -op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h +ifeq ($(TARGET_ARCH), i386) +op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h +endif + +ifeq ($(TARGET_ARCH), arm) +op.o: op.c op_template.h +endif -op-arm.o: op-arm.c op-arm-template.h +ifeq ($(TARGET_ARCH), sparc) +op.o: op.c op_template.h +endif %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< clean: - rm -f *.o *.a *~ $(PROGS) \ - gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h op-$(TARGET_ARCH).h + rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h + +install: all + install -m 755 -s $(PROGS) $(prefix)/bin ifneq ($(wildcard .depend),) include .depend diff --git a/configure b/configure index 51f8bcc74..f680b6945 100755 --- a/configure +++ b/configure @@ -18,7 +18,7 @@ TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S" # default parameters prefix="/usr/local" -interp_prefix="/usr/gnemul/qemu-i386" +interp_prefix="/usr/gnemul/qemu-%M" static="no" cross_prefix="" cc="gcc" @@ -27,7 +27,7 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386 i386-softmmu arm" +target_list="i386 i386-softmmu arm sparc" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" @@ -193,7 +193,8 @@ 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. [$interp_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 "Advanced options (experts only):" @@ -310,6 +311,7 @@ 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" = "sparc" ] && target_bigendian=yes target_softmmu="no" if expr $target : '.*-softmmu' > /dev/null ; then target_softmmu="yes" @@ -326,7 +328,9 @@ echo "/* Automatically generated by configure - do not modify */" > $config_h echo "include ../config-host.mak" >> $config_mak echo "#include \"../config-host.h\"" >> $config_h -echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $config_h + +interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` +echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h if test "$target_cpu" = "i386" ; then echo "TARGET_ARCH=i386" >> $config_mak @@ -336,6 +340,10 @@ elif test "$target_cpu" = "arm" ; then echo "TARGET_ARCH=arm" >> $config_mak echo "#define TARGET_ARCH \"arm\"" >> $config_h echo "#define TARGET_ARM 1" >> $config_h +elif test "$target_cpu" = "sparc" ; then + echo "TARGET_ARCH=sparc" >> $config_mak + echo "#define TARGET_ARCH \"sparc\"" >> $config_h + echo "#define TARGET_SPARC 1" >> $config_h else echo "Unsupported target CPU" exit 1 -- cgit v1.2.3 From 93ac68bca5a3332ffacd7bf10e7b9c4cfdab6374 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 20:57:29 +0000 Subject: sparc emulation target (thanx to Thomas M. Ogrisegg) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@388 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ cpu-exec.c | 28 ++++++++++++++++++-------- disas.c | 2 ++ linux-user/main.c | 38 +++++++++++++++++++++++++++++++---- 4 files changed, 115 insertions(+), 12 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 65304927e..43c03c96c 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -188,6 +188,56 @@ static inline void stfq(void *ptr, double v) } #endif +#elif defined(TARGET_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN) + +static inline int lduw(void *ptr) +{ + uint8_t *b = (uint8_t *) ptr; + return (b[0]<<8|b[1]); +} + +static inline int ldsw(void *ptr) +{ + int8_t *b = (int8_t *) ptr; + return (b[0]<<8|b[1]); +} + +static inline int ldl(void *ptr) +{ + uint8_t *b = (uint8_t *) ptr; + return (b[0]<<24|b[1]<<16|b[2]<<8|b[3]); +} + +static inline uint64_t ldq(void *ptr) +{ + uint32_t a,b; + a = ldl (ptr); + b = ldl (ptr+4); + return (((uint64_t)a<<32)|b); +} + +static inline void stw(void *ptr, int v) +{ + uint8_t *d = (uint8_t *) ptr; + d[0] = v >> 8; + d[1] = v; +} + +static inline void stl(void *ptr, int v) +{ + uint8_t *d = (uint8_t *) ptr; + d[0] = v >> 24; + d[1] = v >> 16; + d[2] = v >> 8; + d[3] = v; +} + +static inline void stq(void *ptr, uint64_t v) +{ + stl (ptr, v); + stl (ptr+4, v >> 32); +} + #else static inline int lduw(void *ptr) @@ -297,6 +347,15 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_interrupt cpu_arm_interrupt #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_interrupt cpu_sparc_interrupt +#define cpu_signal_handler cpu_sparc_signal_handler + #else #error unsupported target CPU diff --git a/cpu-exec.c b/cpu-exec.c index 69671df86..035f10414 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -18,19 +18,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" -#ifdef TARGET_I386 -#include "exec-i386.h" -#endif -#ifdef TARGET_ARM -#include "exec-arm.h" -#endif - +#include "exec.h" #include "disas.h" //#define DEBUG_EXEC //#define DEBUG_SIGNAL -#if defined(TARGET_ARM) +#if defined(TARGET_ARM) || defined(TARGET_SPARC) /* XXX: unify with i386 target */ void cpu_loop_exit(void) { @@ -136,6 +130,7 @@ int cpu_exec(CPUState *env1) env->VF = (psr << 3) & 0x80000000; env->cpsr = psr & ~0xf0000000; } +#elif defined(TARGET_SPARC) #else #error unsupported target CPU #endif @@ -229,6 +224,8 @@ int cpu_exec(CPUState *env1) env->cpsr = compute_cpsr(); cpu_arm_dump_state(env, logfile, 0); env->cpsr &= ~0xf0000000; +#elif defined(TARGET_SPARC) + cpu_sparc_dump_state (env, logfile, 0); #else #error unsupported target CPU #endif @@ -246,6 +243,14 @@ int cpu_exec(CPUState *env1) flags = 0; cs_base = 0; pc = (uint8_t *)env->regs[15]; +#elif defined(TARGET_SPARC) + flags = 0; + cs_base = 0; + if (env->npc) { + env->pc = env->npc; + env->npc = 0; + } + pc = (uint8_t *) env->pc; #else #error unsupported CPU #endif @@ -358,6 +363,7 @@ int cpu_exec(CPUState *env1) #endif #elif defined(TARGET_ARM) env->cpsr = compute_cpsr(); +#elif defined(TARGET_SPARC) #else #error unsupported target CPU #endif @@ -488,6 +494,12 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* XXX: do more */ return 0; } +#elif defined(TARGET_SPARC) +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set) +{ + return 0; +} #else #error unsupported target CPU #endif diff --git a/disas.c b/disas.c index 8a44e9147..81ba50a96 100644 --- a/disas.c +++ b/disas.c @@ -142,6 +142,8 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) print_insn = print_insn_i386; #elif defined(TARGET_ARM) print_insn = print_insn_arm; +#elif defined(TARGET_SPARC) + print_insn = print_insn_sparc; #else fprintf(out, "Asm output not supported on this arch\n"); return; diff --git a/linux-user/main.c b/linux-user/main.c index f4c936c5b..811b8bfba 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1,5 +1,5 @@ /* - * qemu main + * qemu user main * * Copyright (c) 2003 Fabrice Bellard * @@ -38,7 +38,7 @@ static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; #endif -/* for recent libc, we add these dummies symbol which are not declared +/* for recent libc, we add these dummy symbols which are not declared when generating a linked object (bug in ld ?) */ #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) long __init_array_start[0]; @@ -299,10 +299,37 @@ void cpu_loop(CPUARMState *env) #endif +#ifdef TARGET_SPARC + +void cpu_loop (CPUSPARCState *env) +{ + int trapnr; + + while (1) { + trapnr = cpu_sparc_exec (env); + + switch (trapnr) { + case 0x8: case 0x10: + env->regwptr[0] = do_syscall (env, env->gregs[1], + env->regwptr[0], env->regwptr[1], env->regwptr[2], + env->regwptr[3], env->regwptr[4], env->regwptr[13]); + if (env->regwptr[0] >= 0xffffffe0) + env->psr |= PSR_CARRY; + break; + default: + printf ("Invalid trap: %d\n", trapnr); + exit (1); + } + process_pending_signals (env); + } +} + +#endif + void usage(void) { - printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n" + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + "usage: qemu-" TARGET_ARCH " [-h] [-d] [-L path] [-s size] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" "-h print this help\n" @@ -497,6 +524,9 @@ int main(int argc, char **argv) } env->cpsr = regs->uregs[16]; } +#elif defined(TARGET_SPARC) + env->pc = regs->u_regs[0]; + env->regwptr[6] = regs->u_regs[1]-0x40; #else #error unsupported target CPU #endif -- cgit v1.2.3 From 853d6f7a835ff33cf53f2922e4039d4cfad8ac17 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 20:58:32 +0000 Subject: sparc support - hack to fix case where real_host_page_size < TARGET_PAGE_SIZE (typically sparc target case) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@389 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 9df46c112..a0e205cd6 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -83,6 +83,27 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif +#ifdef TARGET_SPARC + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SPARC ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARC + +/*XXX*/ +#define ELF_PLAT_INIT(_r) + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->u_regs[0] = infop->entry; + regs->u_regs[1] = infop->start_stack; +} + +#endif + #include "elf.h" /* @@ -456,18 +477,32 @@ static void set_brk(unsigned long start, unsigned long end) } -/* We need to explicitly zero any fractional pages - after the data section (i.e. bss). This would - contain the junk from the file that should not - be in memory */ - - +/* We need to explicitly zero any fractional pages after the data + section (i.e. bss). This would contain the junk from the file that + should not be in memory. */ static void padzero(unsigned long elf_bss) { unsigned long nbyte; char * fpnt; - nbyte = elf_bss & (host_page_size-1); /* was TARGET_PAGE_SIZE - JRP */ + /* XXX: this is really a hack : if the real host page size is + smaller than the target page size, some pages after the end + of the file may not be mapped. A better fix would be to + patch target_mmap(), but it is more complicated as the file + size must be known */ + if (real_host_page_size < host_page_size) { + unsigned long end_addr, end_addr1; + end_addr1 = (elf_bss + real_host_page_size - 1) & + ~(real_host_page_size - 1); + end_addr = HOST_PAGE_ALIGN(elf_bss); + if (end_addr1 < end_addr) { + mmap((void *)end_addr1, end_addr - end_addr1, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + } + } + + nbyte = elf_bss & (host_page_size-1); if (nbyte) { nbyte = host_page_size - nbyte; fpnt = (char *) elf_bss; -- cgit v1.2.3 From d3eead2eec2f74fded2bed2cb8c21fd8404aeeb9 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 20:59:51 +0000 Subject: new directory structure git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@390 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-arm.h | 63 - cpu-i386.h | 401 ----- exec-all.h | 417 +++++ exec-arm.h | 40 - exec-i386.h | 416 ----- exec.h | 417 ----- helper-i386.c | 1803 --------------------- helper2-i386.c | 390 ----- op-arm-template.h | 48 - op-arm.c | 673 -------- op-i386.c | 2054 ------------------------ opreg_template.h | 134 -- ops_mem.h | 66 - ops_template.h | 617 -------- ops_template_mem.h | 429 ----- qemu-mkcow.c | 143 ++ syscall-arm.h | 28 - syscall-i386.h | 220 --- translate-all.c | 198 +++ translate-arm.c | 903 ----------- translate-i386.c | 4487 ---------------------------------------------------- translate.c | 211 --- vlmkcow.c | 143 -- 23 files changed, 758 insertions(+), 13543 deletions(-) delete mode 100644 cpu-arm.h delete mode 100644 cpu-i386.h create mode 100644 exec-all.h delete mode 100644 exec-arm.h delete mode 100644 exec-i386.h delete mode 100644 exec.h delete mode 100644 helper-i386.c delete mode 100644 helper2-i386.c delete mode 100644 op-arm-template.h delete mode 100644 op-arm.c delete mode 100644 op-i386.c delete mode 100644 opreg_template.h delete mode 100644 ops_mem.h delete mode 100644 ops_template.h delete mode 100644 ops_template_mem.h create mode 100644 qemu-mkcow.c delete mode 100644 syscall-arm.h delete mode 100644 syscall-i386.h create mode 100644 translate-all.c delete mode 100644 translate-arm.c delete mode 100644 translate-i386.c delete mode 100644 translate.c delete mode 100644 vlmkcow.c diff --git a/cpu-arm.h b/cpu-arm.h deleted file mode 100644 index 7f755a754..000000000 --- a/cpu-arm.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ARM virtual CPU header - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef CPU_ARM_H -#define CPU_ARM_H - -#include "cpu-defs.h" - -#define EXCP_UDEF 1 /* undefined instruction */ -#define EXCP_SWI 2 /* software interrupt */ - -typedef struct CPUARMState { - uint32_t regs[16]; - uint32_t cpsr; - - /* cpsr flag cache for faster execution */ - uint32_t CF; /* 0 or 1 */ - uint32_t VF; /* V is the bit 31. All other bits are undefined */ - uint32_t NZF; /* N is bit 31. Z is computed from NZF */ - - /* exception/interrupt handling */ - jmp_buf jmp_env; - int exception_index; - int interrupt_request; - struct TranslationBlock *current_tb; - int user_mode_only; - - /* user data */ - void *opaque; -} CPUARMState; - -CPUARMState *cpu_arm_init(void); -int cpu_arm_exec(CPUARMState *s); -void cpu_arm_close(CPUARMState *s); -/* you can call this signal handler from your SIGBUS and SIGSEGV - signal handlers to inform the virtual CPU of exceptions. non zero - is returned if the signal was handled by the virtual CPU. */ -struct siginfo; -int cpu_arm_signal_handler(int host_signum, struct siginfo *info, - void *puc); - -void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags); - -#define TARGET_PAGE_BITS 12 -#include "cpu-all.h" - -#endif diff --git a/cpu-i386.h b/cpu-i386.h deleted file mode 100644 index ffc4654d3..000000000 --- a/cpu-i386.h +++ /dev/null @@ -1,401 +0,0 @@ -/* - * i386 virtual CPU header - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef CPU_I386_H -#define CPU_I386_H - -#include "cpu-defs.h" - -#define R_EAX 0 -#define R_ECX 1 -#define R_EDX 2 -#define R_EBX 3 -#define R_ESP 4 -#define R_EBP 5 -#define R_ESI 6 -#define R_EDI 7 - -#define R_AL 0 -#define R_CL 1 -#define R_DL 2 -#define R_BL 3 -#define R_AH 4 -#define R_CH 5 -#define R_DH 6 -#define R_BH 7 - -#define R_ES 0 -#define R_CS 1 -#define R_SS 2 -#define R_DS 3 -#define R_FS 4 -#define R_GS 5 - -/* segment descriptor fields */ -#define DESC_G_MASK (1 << 23) -#define DESC_B_SHIFT 22 -#define DESC_B_MASK (1 << DESC_B_SHIFT) -#define DESC_AVL_MASK (1 << 20) -#define DESC_P_MASK (1 << 15) -#define DESC_DPL_SHIFT 13 -#define DESC_S_MASK (1 << 12) -#define DESC_TYPE_SHIFT 8 -#define DESC_A_MASK (1 << 8) - -#define DESC_CS_MASK (1 << 11) -#define DESC_C_MASK (1 << 10) -#define DESC_R_MASK (1 << 9) - -#define DESC_E_MASK (1 << 10) -#define DESC_W_MASK (1 << 9) - -/* eflags masks */ -#define CC_C 0x0001 -#define CC_P 0x0004 -#define CC_A 0x0010 -#define CC_Z 0x0040 -#define CC_S 0x0080 -#define CC_O 0x0800 - -#define TF_SHIFT 8 -#define IOPL_SHIFT 12 -#define VM_SHIFT 17 - -#define TF_MASK 0x00000100 -#define IF_MASK 0x00000200 -#define DF_MASK 0x00000400 -#define IOPL_MASK 0x00003000 -#define NT_MASK 0x00004000 -#define RF_MASK 0x00010000 -#define VM_MASK 0x00020000 -#define AC_MASK 0x00040000 -#define VIF_MASK 0x00080000 -#define VIP_MASK 0x00100000 -#define ID_MASK 0x00200000 - -/* hidden flags - used internally by qemu to represent additionnal cpu - states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid - using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring - with eflags. */ -/* current cpl */ -#define HF_CPL_SHIFT 0 -/* true if soft mmu is being used */ -#define HF_SOFTMMU_SHIFT 2 -/* true if hardware interrupts must be disabled for next instruction */ -#define HF_INHIBIT_IRQ_SHIFT 3 -/* 16 or 32 segments */ -#define HF_CS32_SHIFT 4 -#define HF_SS32_SHIFT 5 -/* zero base for DS, ES and SS */ -#define HF_ADDSEG_SHIFT 6 - -#define HF_CPL_MASK (3 << HF_CPL_SHIFT) -#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) -#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) -#define HF_CS32_MASK (1 << HF_CS32_SHIFT) -#define HF_SS32_MASK (1 << HF_SS32_SHIFT) -#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) - -#define CR0_PE_MASK (1 << 0) -#define CR0_TS_MASK (1 << 3) -#define CR0_WP_MASK (1 << 16) -#define CR0_AM_MASK (1 << 18) -#define CR0_PG_MASK (1 << 31) - -#define CR4_VME_MASK (1 << 0) -#define CR4_PVI_MASK (1 << 1) -#define CR4_TSD_MASK (1 << 2) -#define CR4_DE_MASK (1 << 3) -#define CR4_PSE_MASK (1 << 4) - -#define PG_PRESENT_BIT 0 -#define PG_RW_BIT 1 -#define PG_USER_BIT 2 -#define PG_PWT_BIT 3 -#define PG_PCD_BIT 4 -#define PG_ACCESSED_BIT 5 -#define PG_DIRTY_BIT 6 -#define PG_PSE_BIT 7 -#define PG_GLOBAL_BIT 8 - -#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT) -#define PG_RW_MASK (1 << PG_RW_BIT) -#define PG_USER_MASK (1 << PG_USER_BIT) -#define PG_PWT_MASK (1 << PG_PWT_BIT) -#define PG_PCD_MASK (1 << PG_PCD_BIT) -#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT) -#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT) -#define PG_PSE_MASK (1 << PG_PSE_BIT) -#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT) - -#define PG_ERROR_W_BIT 1 - -#define PG_ERROR_P_MASK 0x01 -#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT) -#define PG_ERROR_U_MASK 0x04 -#define PG_ERROR_RSVD_MASK 0x08 - -#define MSR_IA32_APICBASE 0x1b -#define MSR_IA32_APICBASE_BSP (1<<8) -#define MSR_IA32_APICBASE_ENABLE (1<<11) -#define MSR_IA32_APICBASE_BASE (0xfffff<<12) - -#define MSR_IA32_SYSENTER_CS 0x174 -#define MSR_IA32_SYSENTER_ESP 0x175 -#define MSR_IA32_SYSENTER_EIP 0x176 - -#define EXCP00_DIVZ 0 -#define EXCP01_SSTP 1 -#define EXCP02_NMI 2 -#define EXCP03_INT3 3 -#define EXCP04_INTO 4 -#define EXCP05_BOUND 5 -#define EXCP06_ILLOP 6 -#define EXCP07_PREX 7 -#define EXCP08_DBLE 8 -#define EXCP09_XERR 9 -#define EXCP0A_TSS 10 -#define EXCP0B_NOSEG 11 -#define EXCP0C_STACK 12 -#define EXCP0D_GPF 13 -#define EXCP0E_PAGE 14 -#define EXCP10_COPR 16 -#define EXCP11_ALGN 17 -#define EXCP12_MCHK 18 - -enum { - CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ - CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ - CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */ - - CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ - CC_OP_ADDW, - CC_OP_ADDL, - - CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ - CC_OP_ADCW, - CC_OP_ADCL, - - CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ - CC_OP_SUBW, - CC_OP_SUBL, - - CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ - CC_OP_SBBW, - CC_OP_SBBL, - - CC_OP_LOGICB, /* modify all flags, CC_DST = res */ - CC_OP_LOGICW, - CC_OP_LOGICL, - - CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */ - CC_OP_INCW, - CC_OP_INCL, - - CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */ - CC_OP_DECW, - CC_OP_DECL, - - CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ - CC_OP_SHLW, - CC_OP_SHLL, - - CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ - CC_OP_SARW, - CC_OP_SARL, - - CC_OP_NB, -}; - -#ifdef __i386__ -#define USE_X86LDOUBLE -#endif - -#ifdef USE_X86LDOUBLE -typedef long double CPU86_LDouble; -#else -typedef double CPU86_LDouble; -#endif - -typedef struct SegmentCache { - uint32_t selector; - uint8_t *base; - uint32_t limit; - uint32_t flags; -} SegmentCache; - -typedef struct CPUX86State { - /* standard registers */ - uint32_t regs[8]; - uint32_t eip; - uint32_t eflags; /* eflags register. During CPU emulation, CC - flags and DF are set to zero because they are - stored elsewhere */ - - /* emulator internal eflags handling */ - uint32_t cc_src; - uint32_t cc_dst; - uint32_t cc_op; - int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ - uint32_t hflags; /* hidden flags, see HF_xxx constants */ - - /* FPU state */ - unsigned int fpstt; /* top of stack index */ - unsigned int fpus; - unsigned int fpuc; - uint8_t fptags[8]; /* 0 = valid, 1 = empty */ - CPU86_LDouble fpregs[8]; - - /* emulator internal variables */ - CPU86_LDouble ft0; - union { - float f; - double d; - int i32; - int64_t i64; - } fp_convert; - - /* segments */ - SegmentCache segs[6]; /* selector values */ - SegmentCache ldt; - SegmentCache tr; - SegmentCache gdt; /* only base and limit are used */ - SegmentCache idt; /* only base and limit are used */ - - /* sysenter registers */ - uint32_t sysenter_cs; - uint32_t sysenter_esp; - uint32_t sysenter_eip; - - /* exception/interrupt handling */ - jmp_buf jmp_env; - int exception_index; - int error_code; - int exception_is_int; - int exception_next_eip; - struct TranslationBlock *current_tb; /* currently executing TB */ - uint32_t cr[5]; /* NOTE: cr1 is unused */ - uint32_t dr[8]; /* debug registers */ - int interrupt_request; - int user_mode_only; /* user mode only simulation */ - - /* soft mmu support */ - /* 0 = kernel, 1 = user */ - CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; - - /* ice debug support */ - uint32_t breakpoints[MAX_BREAKPOINTS]; - int nb_breakpoints; - int singlestep_enabled; - - /* user data */ - void *opaque; -} CPUX86State; - -#ifndef IN_OP_I386 -void cpu_x86_outb(CPUX86State *env, int addr, int val); -void cpu_x86_outw(CPUX86State *env, int addr, int val); -void cpu_x86_outl(CPUX86State *env, int addr, int val); -int cpu_x86_inb(CPUX86State *env, int addr); -int cpu_x86_inw(CPUX86State *env, int addr); -int cpu_x86_inl(CPUX86State *env, int addr); -#endif - -CPUX86State *cpu_x86_init(void); -int cpu_x86_exec(CPUX86State *s); -void cpu_x86_close(CPUX86State *s); -int cpu_x86_get_pic_interrupt(CPUX86State *s); - -/* this function must always be used to load data in the segment - cache: it synchronizes the hflags with the segment cache values */ -static inline void cpu_x86_load_seg_cache(CPUX86State *env, - int seg_reg, unsigned int selector, - uint8_t *base, unsigned int limit, - unsigned int flags) -{ - SegmentCache *sc; - unsigned int new_hflags; - - sc = &env->segs[seg_reg]; - sc->selector = selector; - sc->base = base; - sc->limit = limit; - sc->flags = flags; - - /* update the hidden flags */ - new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) - >> (DESC_B_SHIFT - HF_CS32_SHIFT); - new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) - >> (DESC_B_SHIFT - HF_SS32_SHIFT); - if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { - /* XXX: try to avoid this test. The problem comes from the - fact that is real mode or vm86 mode we only modify the - 'base' and 'selector' fields of the segment cache to go - faster. A solution may be to force addseg to one in - translate-i386.c. */ - new_hflags |= HF_ADDSEG_MASK; - } else { - new_hflags |= (((unsigned long)env->segs[R_DS].base | - (unsigned long)env->segs[R_ES].base | - (unsigned long)env->segs[R_SS].base) != 0) << - HF_ADDSEG_SHIFT; - } - env->hflags = (env->hflags & - ~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags; -} - -/* wrapper, just in case memory mappings must be changed */ -static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) -{ -#if HF_CPL_MASK == 3 - s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl; -#else -#error HF_CPL_MASK is hardcoded -#endif -} - -/* the following helpers are only usable in user mode simulation as - they can trigger unexpected exceptions */ -void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); -void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); -void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); - -/* you can call this signal handler from your SIGBUS and SIGSEGV - signal handlers to inform the virtual CPU of exceptions. non zero - is returned if the signal was handled by the virtual CPU. */ -struct siginfo; -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, - void *puc); - -/* MMU defines */ -void cpu_x86_init_mmu(CPUX86State *env); -extern int phys_ram_size; -extern int phys_ram_fd; -extern uint8_t *phys_ram_base; - -/* used to debug */ -#define X86_DUMP_FPU 0x0001 /* dump FPU state too */ -#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); - -#define TARGET_PAGE_BITS 12 -#include "cpu-all.h" - -#endif /* CPU_I386_H */ diff --git a/exec-all.h b/exec-all.h new file mode 100644 index 000000000..070a162f3 --- /dev/null +++ b/exec-all.h @@ -0,0 +1,417 @@ +/* + * internal execution defines for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* allow to see translation results - the slowdown should be negligible, so we leave it */ +#define DEBUG_DISAS + +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#if GCC_MAJOR < 3 +#define __builtin_expect(x, n) (x) +#endif + +#ifdef __i386__ +#define REGPARM(n) __attribute((regparm(n))) +#else +#define REGPARM(n) +#endif + +/* is_jmp field values */ +#define DISAS_NEXT 0 /* next instruction can be analyzed */ +#define DISAS_JUMP 1 /* only pc was modified dynamically */ +#define DISAS_UPDATE 2 /* cpu state was modified dynamically */ +#define DISAS_TB_JUMP 3 /* only pc was modified statically */ + +struct TranslationBlock; + +/* XXX: make safe guess about sizes */ +#define MAX_OP_PER_INSTR 32 +#define OPC_BUF_SIZE 512 +#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) + +#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3) + +extern uint16_t gen_opc_buf[OPC_BUF_SIZE]; +extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; +extern uint32_t gen_opc_pc[OPC_BUF_SIZE]; +extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; +extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; + +#if defined(TARGET_I386) + +void optimize_flags_init(void); + +#endif + +extern FILE *logfile; +extern int loglevel; + +int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); +int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); +void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); +int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, + int max_code_size, int *gen_code_size_ptr); +int cpu_restore_state(struct TranslationBlock *tb, + CPUState *env, unsigned long searched_pc); +void cpu_exec_init(void); +int page_unprotect(unsigned long address); +void page_unmap(void); +void tlb_flush_page(CPUState *env, uint32_t addr); +void tlb_flush(CPUState *env); + +#define CODE_GEN_MAX_SIZE 65536 +#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ + +#define CODE_GEN_HASH_BITS 15 +#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) + +/* maximum total translate dcode allocated */ +#define CODE_GEN_BUFFER_SIZE (2048 * 1024) +//#define CODE_GEN_BUFFER_SIZE (128 * 1024) + +#if defined(__powerpc__) +#define USE_DIRECT_JUMP +#endif + +typedef struct TranslationBlock { + unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ + unsigned long cs_base; /* CS base for this block */ + unsigned int flags; /* flags defining in which context the code was generated */ + uint16_t size; /* size of target code for this block (1 <= + size <= TARGET_PAGE_SIZE) */ + uint8_t *tc_ptr; /* pointer to the translated code */ + struct TranslationBlock *hash_next; /* next matching block */ + struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */ + /* the following data are used to directly call another TB from + the code of this one. */ + uint16_t tb_next_offset[2]; /* offset of original jump target */ +#ifdef USE_DIRECT_JUMP + uint16_t tb_jmp_offset[4]; /* offset of jump instruction */ +#else + uint32_t tb_next[2]; /* address of jump generated code */ +#endif + /* list of TBs jumping to this one. This is a circular list using + the two least significant bits of the pointers to tell what is + the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 = + jmp_first */ + struct TranslationBlock *jmp_next[2]; + struct TranslationBlock *jmp_first; +} TranslationBlock; + +static inline unsigned int tb_hash_func(unsigned long pc) +{ + return pc & (CODE_GEN_HASH_SIZE - 1); +} + +TranslationBlock *tb_alloc(unsigned long pc); +void tb_flush(void); +void tb_link(TranslationBlock *tb); + +extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; + +extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; +extern uint8_t *code_gen_ptr; + +/* find a translation block in the translation cache. If not found, + return NULL and the pointer to the last element of the list in pptb */ +static inline TranslationBlock *tb_find(TranslationBlock ***pptb, + unsigned long pc, + unsigned long cs_base, + unsigned int flags) +{ + TranslationBlock **ptb, *tb; + unsigned int h; + + h = tb_hash_func(pc); + ptb = &tb_hash[h]; + for(;;) { + tb = *ptb; + if (!tb) + break; + if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) + return tb; + ptb = &tb->hash_next; + } + *pptb = ptb; + return NULL; +} + +#if defined(__powerpc__) + +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) +{ + uint32_t val, *ptr; + + /* patch the branch destination */ + ptr = (uint32_t *)jmp_addr; + val = *ptr; + val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc); + *ptr = val; + /* flush icache */ + asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory"); + asm volatile ("sync" : : : "memory"); + asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory"); + asm volatile ("sync" : : : "memory"); + asm volatile ("isync" : : : "memory"); +} + +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + unsigned long offset; + + offset = tb->tb_jmp_offset[n]; + tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); + offset = tb->tb_jmp_offset[n + 2]; + if (offset != 0xffff) + tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); +} + +#else + +/* set the jump target */ +static inline void tb_set_jmp_target(TranslationBlock *tb, + int n, unsigned long addr) +{ + tb->tb_next[n] = addr; +} + +#endif + +static inline void tb_add_jump(TranslationBlock *tb, int n, + TranslationBlock *tb_next) +{ + /* NOTE: this test is only needed for thread safety */ + if (!tb->jmp_next[n]) { + /* patch the native jump address */ + tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); + + /* add in TB jmp circular list */ + tb->jmp_next[n] = tb_next->jmp_first; + tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); + } +} + +TranslationBlock *tb_find_pc(unsigned long pc_ptr); + +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif + +#if defined(__powerpc__) + +/* on PowerPC we patch the jump instruction directly */ +#define JUMP_TB(opname, tbparam, n, eip)\ +do {\ + asm volatile (".section \".data\"\n"\ + "__op_label" #n "." stringify(opname) ":\n"\ + ".long 1f\n"\ + ".previous\n"\ + "b __op_jmp" #n "\n"\ + "1:\n");\ + T0 = (long)(tbparam) + (n);\ + EIP = eip;\ + EXIT_TB();\ +} while (0) + +#define JUMP_TB2(opname, tbparam, n)\ +do {\ + asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\ +} while (0) + +#else + +/* jump to next block operations (more portable code, does not need + cache flushing, but slower because of indirect jump) */ +#define JUMP_TB(opname, tbparam, n, eip)\ +do {\ + static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ + static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\ + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ +label ## n:\ + T0 = (long)(tbparam) + (n);\ + EIP = eip;\ +dummy_label ## n:\ + EXIT_TB();\ +} while (0) + +/* second jump to same destination 'n' */ +#define JUMP_TB2(opname, tbparam, n)\ +do {\ + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ +} while (0) + +#endif + +/* physical memory access */ +#define IO_MEM_NB_ENTRIES 256 +#define TLB_INVALID_MASK (1 << 3) +#define IO_MEM_SHIFT 4 +#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT) + +unsigned long physpage_find(unsigned long page); + +extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; + +#ifdef __powerpc__ +static inline int testandset (int *p) +{ + int ret; + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r" (ret) + : "r" (p), "r" (1), "r" (0) + : "cr0", "memory"); + return ret; +} +#endif + +#ifdef __i386__ +static inline int testandset (int *p) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (1), "m" (*p), "a" (0) + : "memory"); + return ret; +} +#endif + +#ifdef __s390__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" + " jl 0b" + : "=&d" (ret) + : "r" (1), "a" (p), "0" (*p) + : "cc", "memory" ); + return ret; +} +#endif + +#ifdef __alpha__ +static inline int testandset (int *p) +{ + int ret; + unsigned long one; + + __asm__ __volatile__ ("0: mov 1,%2\n" + " ldl_l %0,%1\n" + " stl_c %2,%1\n" + " beq %2,1f\n" + ".subsection 2\n" + "1: br 0b\n" + ".previous" + : "=r" (ret), "=m" (*p), "=r" (one) + : "m" (*p)); + return ret; +} +#endif + +#ifdef __sparc__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (ret) + : "r" (p) + : "memory"); + + return (ret ? 1 : 0); +} +#endif + +#ifdef __arm__ +static inline int testandset (int *spinlock) +{ + register unsigned int ret; + __asm__ __volatile__("swp %0, %1, [%2]" + : "=r"(ret) + : "0"(1), "r"(spinlock)); + + return ret; +} +#endif + +#ifdef __mc68000 +static inline int testandset (int *p) +{ + char ret; + __asm__ __volatile__("tas %1; sne %0" + : "=r" (ret) + : "m" (p) + : "cc","memory"); + return ret == 0; +} +#endif + +typedef int spinlock_t; + +#define SPIN_LOCK_UNLOCKED 0 + +#if 1 +static inline void spin_lock(spinlock_t *lock) +{ + while (testandset(lock)); +} + +static inline void spin_unlock(spinlock_t *lock) +{ + *lock = 0; +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return !testandset(lock); +} +#else +static inline void spin_lock(spinlock_t *lock) +{ +} + +static inline void spin_unlock(spinlock_t *lock) +{ +} + +static inline int spin_trylock(spinlock_t *lock) +{ + return 1; +} +#endif + +extern spinlock_t tb_lock; + diff --git a/exec-arm.h b/exec-arm.h deleted file mode 100644 index e838e8823..000000000 --- a/exec-arm.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ARM execution defines - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "dyngen-exec.h" - -register struct CPUARMState *env asm(AREG0); -register uint32_t T0 asm(AREG1); -register uint32_t T1 asm(AREG2); -register uint32_t T2 asm(AREG3); - -#include "cpu-arm.h" -#include "exec.h" - -void cpu_lock(void); -void cpu_unlock(void); -void cpu_loop_exit(void); - -static inline int compute_cpsr(void) -{ - int ZF; - ZF = (env->NZF == 0); - return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); -} diff --git a/exec-i386.h b/exec-i386.h deleted file mode 100644 index 96ad04e8e..000000000 --- a/exec-i386.h +++ /dev/null @@ -1,416 +0,0 @@ -/* - * i386 execution defines - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "dyngen-exec.h" - -/* at least 4 register variables are defines */ -register struct CPUX86State *env asm(AREG0); -register uint32_t T0 asm(AREG1); -register uint32_t T1 asm(AREG2); -register uint32_t T2 asm(AREG3); - -#define A0 T2 - -/* if more registers are available, we define some registers too */ -#ifdef AREG4 -register uint32_t EAX asm(AREG4); -#define reg_EAX -#endif - -#ifdef AREG5 -register uint32_t ESP asm(AREG5); -#define reg_ESP -#endif - -#ifdef AREG6 -register uint32_t EBP asm(AREG6); -#define reg_EBP -#endif - -#ifdef AREG7 -register uint32_t ECX asm(AREG7); -#define reg_ECX -#endif - -#ifdef AREG8 -register uint32_t EDX asm(AREG8); -#define reg_EDX -#endif - -#ifdef AREG9 -register uint32_t EBX asm(AREG9); -#define reg_EBX -#endif - -#ifdef AREG10 -register uint32_t ESI asm(AREG10); -#define reg_ESI -#endif - -#ifdef AREG11 -register uint32_t EDI asm(AREG11); -#define reg_EDI -#endif - -extern FILE *logfile; -extern int loglevel; - -#ifndef reg_EAX -#define EAX (env->regs[R_EAX]) -#endif -#ifndef reg_ECX -#define ECX (env->regs[R_ECX]) -#endif -#ifndef reg_EDX -#define EDX (env->regs[R_EDX]) -#endif -#ifndef reg_EBX -#define EBX (env->regs[R_EBX]) -#endif -#ifndef reg_ESP -#define ESP (env->regs[R_ESP]) -#endif -#ifndef reg_EBP -#define EBP (env->regs[R_EBP]) -#endif -#ifndef reg_ESI -#define ESI (env->regs[R_ESI]) -#endif -#ifndef reg_EDI -#define EDI (env->regs[R_EDI]) -#endif -#define EIP (env->eip) -#define DF (env->df) - -#define CC_SRC (env->cc_src) -#define CC_DST (env->cc_dst) -#define CC_OP (env->cc_op) - -/* float macros */ -#define FT0 (env->ft0) -#define ST0 (env->fpregs[env->fpstt]) -#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) -#define ST1 ST(1) - -#ifdef USE_FP_CONVERT -#define FP_CONVERT (env->fp_convert) -#endif - -#include "cpu-i386.h" -#include "exec.h" - -typedef struct CCTable { - int (*compute_all)(void); /* return all the flags */ - int (*compute_c)(void); /* return the C flag */ -} CCTable; - -extern CCTable cc_table[]; - -void load_seg(int seg_reg, int selector, unsigned cur_eip); -void helper_ljmp_protected_T0_T1(void); -void helper_lcall_real_T0_T1(int shift, int next_eip); -void helper_lcall_protected_T0_T1(int shift, int next_eip); -void helper_iret_real(int shift); -void helper_iret_protected(int shift); -void helper_lret_protected(int shift, int addend); -void helper_lldt_T0(void); -void helper_ltr_T0(void); -void helper_movl_crN_T0(int reg); -void helper_movl_drN_T0(int reg); -void helper_invlpg(unsigned int addr); -void cpu_x86_update_cr0(CPUX86State *env); -void cpu_x86_update_cr3(CPUX86State *env); -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); -void tlb_fill(unsigned long addr, int is_write, void *retaddr); -void __hidden cpu_lock(void); -void __hidden cpu_unlock(void); -void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw); -void do_interrupt_user(int intno, int is_int, int error_code, - unsigned int next_eip); -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip); -void raise_exception_err(int exception_index, int error_code); -void raise_exception(int exception_index); -void __hidden cpu_loop_exit(void); -void helper_fsave(uint8_t *ptr, int data32); -void helper_frstor(uint8_t *ptr, int data32); - -void OPPROTO op_movl_eflags_T0(void); -void OPPROTO op_movl_T0_eflags(void); -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip); -void raise_exception_err(int exception_index, int error_code); -void raise_exception(int exception_index); -void helper_divl_EAX_T0(uint32_t eip); -void helper_idivl_EAX_T0(uint32_t eip); -void helper_cmpxchg8b(void); -void helper_cpuid(void); -void helper_rdtsc(void); -void helper_rdmsr(void); -void helper_wrmsr(void); -void helper_lsl(void); -void helper_lar(void); - -#ifdef USE_X86LDOUBLE -/* use long double functions */ -#define lrint lrintl -#define llrint llrintl -#define fabs fabsl -#define sin sinl -#define cos cosl -#define sqrt sqrtl -#define pow powl -#define log logl -#define tan tanl -#define atan2 atan2l -#define floor floorl -#define ceil ceill -#define rint rintl -#endif - -extern int lrint(CPU86_LDouble x); -extern int64_t llrint(CPU86_LDouble x); -extern CPU86_LDouble fabs(CPU86_LDouble x); -extern CPU86_LDouble sin(CPU86_LDouble x); -extern CPU86_LDouble cos(CPU86_LDouble x); -extern CPU86_LDouble sqrt(CPU86_LDouble x); -extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); -extern CPU86_LDouble log(CPU86_LDouble x); -extern CPU86_LDouble tan(CPU86_LDouble x); -extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); -extern CPU86_LDouble floor(CPU86_LDouble x); -extern CPU86_LDouble ceil(CPU86_LDouble x); -extern CPU86_LDouble rint(CPU86_LDouble x); - -#define RC_MASK 0xc00 -#define RC_NEAR 0x000 -#define RC_DOWN 0x400 -#define RC_UP 0x800 -#define RC_CHOP 0xc00 - -#define MAXTAN 9223372036854775808.0 - -#ifdef __arm__ -/* we have no way to do correct rounding - a FPU emulator is needed */ -#define FE_DOWNWARD FE_TONEAREST -#define FE_UPWARD FE_TONEAREST -#define FE_TOWARDZERO FE_TONEAREST -#endif - -#ifdef USE_X86LDOUBLE - -/* only for x86 */ -typedef union { - long double d; - struct { - unsigned long long lower; - unsigned short upper; - } l; -} CPU86_LDoubleU; - -/* the following deal with x86 long double-precision numbers */ -#define MAXEXPD 0x7fff -#define EXPBIAS 16383 -#define EXPD(fp) (fp.l.upper & 0x7fff) -#define SIGND(fp) ((fp.l.upper) & 0x8000) -#define MANTD(fp) (fp.l.lower) -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS - -#else - -/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ -typedef union { - double d; -#if !defined(WORDS_BIGENDIAN) && !defined(__arm__) - struct { - uint32_t lower; - int32_t upper; - } l; -#else - struct { - int32_t upper; - uint32_t lower; - } l; -#endif -#ifndef __arm__ - int64_t ll; -#endif -} CPU86_LDoubleU; - -/* the following deal with IEEE double-precision numbers */ -#define MAXEXPD 0x7ff -#define EXPBIAS 1023 -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define SIGND(fp) ((fp.l.upper) & 0x80000000) -#ifdef __arm__ -#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32)) -#else -#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) -#endif -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) -#endif - -static inline void fpush(void) -{ - env->fpstt = (env->fpstt - 1) & 7; - env->fptags[env->fpstt] = 0; /* validate stack entry */ -} - -static inline void fpop(void) -{ - env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ - env->fpstt = (env->fpstt + 1) & 7; -} - -#ifndef USE_X86LDOUBLE -static inline CPU86_LDouble helper_fldt(uint8_t *ptr) -{ - CPU86_LDoubleU temp; - int upper, e; - uint64_t ll; - - /* mantissa */ - upper = lduw(ptr + 8); - /* XXX: handle overflow ? */ - e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ - e |= (upper >> 4) & 0x800; /* sign */ - ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1); -#ifdef __arm__ - temp.l.upper = (e << 20) | (ll >> 32); - temp.l.lower = ll; -#else - temp.ll = ll | ((uint64_t)e << 52); -#endif - return temp.d; -} - -static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) -{ - CPU86_LDoubleU temp; - int e; - - temp.d = f; - /* mantissa */ - stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); - /* exponent + sign */ - e = EXPD(temp) - EXPBIAS + 16383; - e |= SIGND(temp) >> 16; - stw(ptr + 8, e); -} -#endif - -const CPU86_LDouble f15rk[7]; - -void helper_fldt_ST0_A0(void); -void helper_fstt_ST0_A0(void); -void helper_fbld_ST0_A0(void); -void helper_fbst_ST0_A0(void); -void helper_f2xm1(void); -void helper_fyl2x(void); -void helper_fptan(void); -void helper_fpatan(void); -void helper_fxtract(void); -void helper_fprem1(void); -void helper_fprem(void); -void helper_fyl2xp1(void); -void helper_fsqrt(void); -void helper_fsincos(void); -void helper_frndint(void); -void helper_fscale(void); -void helper_fsin(void); -void helper_fcos(void); -void helper_fxam_ST0(void); -void helper_fstenv(uint8_t *ptr, int data32); -void helper_fldenv(uint8_t *ptr, int data32); -void helper_fsave(uint8_t *ptr, int data32); -void helper_frstor(uint8_t *ptr, int data32); - -const uint8_t parity_table[256]; -const uint8_t rclw_table[32]; -const uint8_t rclb_table[32]; - -static inline uint32_t compute_eflags(void) -{ - return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); -} - -#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) - -#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \ - RF_MASK | AC_MASK | ID_MASK) - -/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */ -static inline void load_eflags(int eflags, int update_mask) -{ - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - env->eflags = (env->eflags & ~update_mask) | - (eflags & update_mask); -} - -/* memory access macros */ - -#define ldul ldl -#define lduq ldq -#define ldul_user ldl_user -#define ldul_kernel ldl_kernel - -#define ldub_raw ldub -#define ldsb_raw ldsb -#define lduw_raw lduw -#define ldsw_raw ldsw -#define ldl_raw ldl -#define ldq_raw ldq - -#define stb_raw stb -#define stw_raw stw -#define stl_raw stl -#define stq_raw stq - -#define MEMUSER 0 -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" - -#undef MEMUSER -#define MEMUSER 1 -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" - -#undef MEMUSER - diff --git a/exec.h b/exec.h deleted file mode 100644 index 070a162f3..000000000 --- a/exec.h +++ /dev/null @@ -1,417 +0,0 @@ -/* - * internal execution defines for qemu - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* allow to see translation results - the slowdown should be negligible, so we leave it */ -#define DEBUG_DISAS - -#ifndef glue -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s -#endif - -#if GCC_MAJOR < 3 -#define __builtin_expect(x, n) (x) -#endif - -#ifdef __i386__ -#define REGPARM(n) __attribute((regparm(n))) -#else -#define REGPARM(n) -#endif - -/* is_jmp field values */ -#define DISAS_NEXT 0 /* next instruction can be analyzed */ -#define DISAS_JUMP 1 /* only pc was modified dynamically */ -#define DISAS_UPDATE 2 /* cpu state was modified dynamically */ -#define DISAS_TB_JUMP 3 /* only pc was modified statically */ - -struct TranslationBlock; - -/* XXX: make safe guess about sizes */ -#define MAX_OP_PER_INSTR 32 -#define OPC_BUF_SIZE 512 -#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) - -#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3) - -extern uint16_t gen_opc_buf[OPC_BUF_SIZE]; -extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; -extern uint32_t gen_opc_pc[OPC_BUF_SIZE]; -extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; -extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; - -#if defined(TARGET_I386) - -void optimize_flags_init(void); - -#endif - -extern FILE *logfile; -extern int loglevel; - -int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); -int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); -void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); -int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr); -int cpu_restore_state(struct TranslationBlock *tb, - CPUState *env, unsigned long searched_pc); -void cpu_exec_init(void); -int page_unprotect(unsigned long address); -void page_unmap(void); -void tlb_flush_page(CPUState *env, uint32_t addr); -void tlb_flush(CPUState *env); - -#define CODE_GEN_MAX_SIZE 65536 -#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ - -#define CODE_GEN_HASH_BITS 15 -#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) - -/* maximum total translate dcode allocated */ -#define CODE_GEN_BUFFER_SIZE (2048 * 1024) -//#define CODE_GEN_BUFFER_SIZE (128 * 1024) - -#if defined(__powerpc__) -#define USE_DIRECT_JUMP -#endif - -typedef struct TranslationBlock { - unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ - unsigned long cs_base; /* CS base for this block */ - unsigned int flags; /* flags defining in which context the code was generated */ - uint16_t size; /* size of target code for this block (1 <= - size <= TARGET_PAGE_SIZE) */ - uint8_t *tc_ptr; /* pointer to the translated code */ - struct TranslationBlock *hash_next; /* next matching block */ - struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */ - /* the following data are used to directly call another TB from - the code of this one. */ - uint16_t tb_next_offset[2]; /* offset of original jump target */ -#ifdef USE_DIRECT_JUMP - uint16_t tb_jmp_offset[4]; /* offset of jump instruction */ -#else - uint32_t tb_next[2]; /* address of jump generated code */ -#endif - /* list of TBs jumping to this one. This is a circular list using - the two least significant bits of the pointers to tell what is - the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 = - jmp_first */ - struct TranslationBlock *jmp_next[2]; - struct TranslationBlock *jmp_first; -} TranslationBlock; - -static inline unsigned int tb_hash_func(unsigned long pc) -{ - return pc & (CODE_GEN_HASH_SIZE - 1); -} - -TranslationBlock *tb_alloc(unsigned long pc); -void tb_flush(void); -void tb_link(TranslationBlock *tb); - -extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; - -extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; -extern uint8_t *code_gen_ptr; - -/* find a translation block in the translation cache. If not found, - return NULL and the pointer to the last element of the list in pptb */ -static inline TranslationBlock *tb_find(TranslationBlock ***pptb, - unsigned long pc, - unsigned long cs_base, - unsigned int flags) -{ - TranslationBlock **ptb, *tb; - unsigned int h; - - h = tb_hash_func(pc); - ptb = &tb_hash[h]; - for(;;) { - tb = *ptb; - if (!tb) - break; - if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) - return tb; - ptb = &tb->hash_next; - } - *pptb = ptb; - return NULL; -} - -#if defined(__powerpc__) - -static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) -{ - uint32_t val, *ptr; - - /* patch the branch destination */ - ptr = (uint32_t *)jmp_addr; - val = *ptr; - val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc); - *ptr = val; - /* flush icache */ - asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory"); - asm volatile ("sync" : : : "memory"); - asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory"); - asm volatile ("sync" : : : "memory"); - asm volatile ("isync" : : : "memory"); -} - -static inline void tb_set_jmp_target(TranslationBlock *tb, - int n, unsigned long addr) -{ - unsigned long offset; - - offset = tb->tb_jmp_offset[n]; - tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); - offset = tb->tb_jmp_offset[n + 2]; - if (offset != 0xffff) - tb_set_jmp_target1((unsigned long)(tb->tc_ptr + offset), addr); -} - -#else - -/* set the jump target */ -static inline void tb_set_jmp_target(TranslationBlock *tb, - int n, unsigned long addr) -{ - tb->tb_next[n] = addr; -} - -#endif - -static inline void tb_add_jump(TranslationBlock *tb, int n, - TranslationBlock *tb_next) -{ - /* NOTE: this test is only needed for thread safety */ - if (!tb->jmp_next[n]) { - /* patch the native jump address */ - tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); - - /* add in TB jmp circular list */ - tb->jmp_next[n] = tb_next->jmp_first; - tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); - } -} - -TranslationBlock *tb_find_pc(unsigned long pc_ptr); - -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - -#if defined(__powerpc__) - -/* on PowerPC we patch the jump instruction directly */ -#define JUMP_TB(opname, tbparam, n, eip)\ -do {\ - asm volatile (".section \".data\"\n"\ - "__op_label" #n "." stringify(opname) ":\n"\ - ".long 1f\n"\ - ".previous\n"\ - "b __op_jmp" #n "\n"\ - "1:\n");\ - T0 = (long)(tbparam) + (n);\ - EIP = eip;\ - EXIT_TB();\ -} while (0) - -#define JUMP_TB2(opname, tbparam, n)\ -do {\ - asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\ -} while (0) - -#else - -/* jump to next block operations (more portable code, does not need - cache flushing, but slower because of indirect jump) */ -#define JUMP_TB(opname, tbparam, n, eip)\ -do {\ - static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ - static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\ - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ -label ## n:\ - T0 = (long)(tbparam) + (n);\ - EIP = eip;\ -dummy_label ## n:\ - EXIT_TB();\ -} while (0) - -/* second jump to same destination 'n' */ -#define JUMP_TB2(opname, tbparam, n)\ -do {\ - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ -} while (0) - -#endif - -/* physical memory access */ -#define IO_MEM_NB_ENTRIES 256 -#define TLB_INVALID_MASK (1 << 3) -#define IO_MEM_SHIFT 4 -#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT) - -unsigned long physpage_find(unsigned long page); - -extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; -extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; - -#ifdef __powerpc__ -static inline int testandset (int *p) -{ - int ret; - __asm__ __volatile__ ( - "0: lwarx %0,0,%1 ;" - " xor. %0,%3,%0;" - " bne 1f;" - " stwcx. %2,0,%1;" - " bne- 0b;" - "1: " - : "=&r" (ret) - : "r" (p), "r" (1), "r" (0) - : "cr0", "memory"); - return ret; -} -#endif - -#ifdef __i386__ -static inline int testandset (int *p) -{ - char ret; - long int readval; - - __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" - : "=q" (ret), "=m" (*p), "=a" (readval) - : "r" (1), "m" (*p), "a" (0) - : "memory"); - return ret; -} -#endif - -#ifdef __s390__ -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" - " jl 0b" - : "=&d" (ret) - : "r" (1), "a" (p), "0" (*p) - : "cc", "memory" ); - return ret; -} -#endif - -#ifdef __alpha__ -static inline int testandset (int *p) -{ - int ret; - unsigned long one; - - __asm__ __volatile__ ("0: mov 1,%2\n" - " ldl_l %0,%1\n" - " stl_c %2,%1\n" - " beq %2,1f\n" - ".subsection 2\n" - "1: br 0b\n" - ".previous" - : "=r" (ret), "=m" (*p), "=r" (one) - : "m" (*p)); - return ret; -} -#endif - -#ifdef __sparc__ -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__("ldstub [%1], %0" - : "=r" (ret) - : "r" (p) - : "memory"); - - return (ret ? 1 : 0); -} -#endif - -#ifdef __arm__ -static inline int testandset (int *spinlock) -{ - register unsigned int ret; - __asm__ __volatile__("swp %0, %1, [%2]" - : "=r"(ret) - : "0"(1), "r"(spinlock)); - - return ret; -} -#endif - -#ifdef __mc68000 -static inline int testandset (int *p) -{ - char ret; - __asm__ __volatile__("tas %1; sne %0" - : "=r" (ret) - : "m" (p) - : "cc","memory"); - return ret == 0; -} -#endif - -typedef int spinlock_t; - -#define SPIN_LOCK_UNLOCKED 0 - -#if 1 -static inline void spin_lock(spinlock_t *lock) -{ - while (testandset(lock)); -} - -static inline void spin_unlock(spinlock_t *lock) -{ - *lock = 0; -} - -static inline int spin_trylock(spinlock_t *lock) -{ - return !testandset(lock); -} -#else -static inline void spin_lock(spinlock_t *lock) -{ -} - -static inline void spin_unlock(spinlock_t *lock) -{ -} - -static inline int spin_trylock(spinlock_t *lock) -{ - return 1; -} -#endif - -extern spinlock_t tb_lock; - diff --git a/helper-i386.c b/helper-i386.c deleted file mode 100644 index 67c3aec6c..000000000 --- a/helper-i386.c +++ /dev/null @@ -1,1803 +0,0 @@ -/* - * i386 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 - */ -#include "exec-i386.h" - -const uint8_t parity_table[256] = { - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, -}; - -/* modulo 17 table */ -const uint8_t rclw_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9,10,11,12,13,14,15, - 16, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9,10,11,12,13,14, -}; - -/* modulo 9 table */ -const uint8_t rclb_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 0, 1, 2, 3, 4, -}; - -const CPU86_LDouble f15rk[7] = -{ - 0.00000000000000000000L, - 1.00000000000000000000L, - 3.14159265358979323851L, /*pi*/ - 0.30102999566398119523L, /*lg2*/ - 0.69314718055994530943L, /*ln2*/ - 1.44269504088896340739L, /*l2e*/ - 3.32192809488736234781L, /*l2t*/ -}; - -/* thread support */ - -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; - -void cpu_lock(void) -{ - spin_lock(&global_cpu_lock); -} - -void cpu_unlock(void) -{ - spin_unlock(&global_cpu_lock); -} - -void cpu_loop_exit(void) -{ - /* NOTE: the register at this point must be saved by hand because - longjmp restore them */ -#ifdef reg_EAX - env->regs[R_EAX] = EAX; -#endif -#ifdef reg_ECX - env->regs[R_ECX] = ECX; -#endif -#ifdef reg_EDX - env->regs[R_EDX] = EDX; -#endif -#ifdef reg_EBX - env->regs[R_EBX] = EBX; -#endif -#ifdef reg_ESP - env->regs[R_ESP] = ESP; -#endif -#ifdef reg_EBP - env->regs[R_EBP] = EBP; -#endif -#ifdef reg_ESI - env->regs[R_ESI] = ESI; -#endif -#ifdef reg_EDI - env->regs[R_EDI] = EDI; -#endif - longjmp(env->jmp_env, 1); -} - -static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, - uint32_t *esp_ptr, int dpl) -{ - int type, index, shift; - -#if 0 - { - int i; - printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); - for(i=0;itr.limit;i++) { - printf("%02x ", env->tr.base[i]); - if ((i & 7) == 7) printf("\n"); - } - printf("\n"); - } -#endif - - if (!(env->tr.flags & DESC_P_MASK)) - cpu_abort(env, "invalid tss"); - type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; - if ((type & 7) != 1) - cpu_abort(env, "invalid tss type"); - shift = type >> 3; - index = (dpl * 4 + 2) << shift; - if (index + (4 << shift) - 1 > env->tr.limit) - raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); - if (shift == 0) { - *esp_ptr = lduw(env->tr.base + index); - *ss_ptr = lduw(env->tr.base + index + 2); - } else { - *esp_ptr = ldl(env->tr.base + index); - *ss_ptr = lduw(env->tr.base + index + 4); - } -} - -/* return non zero if error */ -static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, - int selector) -{ - SegmentCache *dt; - int index; - uint8_t *ptr; - - if (selector & 0x4) - dt = &env->ldt; - else - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - return -1; - ptr = dt->base + index; - *e1_ptr = ldl(ptr); - *e2_ptr = ldl(ptr + 4); - return 0; -} - -static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) -{ - unsigned int limit; - limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & DESC_G_MASK) - limit = (limit << 12) | 0xfff; - return limit; -} - -static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) -{ - return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); -} - -static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) -{ - sc->base = get_seg_base(e1, e2); - sc->limit = get_seg_limit(e1, e2); - sc->flags = e2; -} - -/* init the segment cache in vm86 mode. */ -static inline void load_seg_vm(int seg, int selector) -{ - selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg, selector, - (uint8_t *)(selector << 4), 0xffff, 0); -} - -/* protected mode interrupt */ -static void do_interrupt_protected(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw) -{ - SegmentCache *dt; - uint8_t *ptr, *ssp; - int type, dpl, selector, ss_dpl, cpl; - int has_error_code, new_stack, shift; - uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; - uint32_t old_cs, old_ss, old_esp, old_eip; - - dt = &env->idt; - if (intno * 8 + 7 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - ptr = dt->base + intno * 8; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - /* check gate type */ - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; - switch(type) { - case 5: /* task gate */ - cpu_abort(env, "task gate not supported"); - break; - case 6: /* 286 interrupt gate */ - case 7: /* 286 trap gate */ - case 14: /* 386 interrupt gate */ - case 15: /* 386 trap gate */ - break; - default: - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - break; - } - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - /* check valid bit */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); - selector = e1 >> 16; - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); - if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - if (!(e2 & DESC_C_MASK) && dpl < cpl) { - /* to inner priviledge */ - get_ss_esp_from_tss(&ss, &esp, dpl); - if ((ss & 0xfffc) == 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if ((ss & 3) != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, ss) != 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (ss_dpl != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - new_stack = 1; - } else if ((e2 & DESC_C_MASK) || dpl == cpl) { - /* to same priviledge */ - new_stack = 0; - } else { - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - new_stack = 0; /* avoid warning */ - } - - shift = type >> 3; - has_error_code = 0; - if (!is_int && !is_hw) { - switch(intno) { - case 8: - case 10: - case 11: - case 12: - case 13: - case 14: - case 17: - has_error_code = 1; - break; - } - } - push_size = 6 + (new_stack << 2) + (has_error_code << 1); - if (env->eflags & VM_MASK) - push_size += 8; - push_size <<= shift; - - /* XXX: check that enough room is available */ - if (new_stack) { - old_esp = ESP; - old_ss = env->segs[R_SS].selector; - ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - } else { - old_esp = 0; - old_ss = 0; - esp = ESP; - } - if (is_int) - old_eip = next_eip; - else - old_eip = env->eip; - old_cs = env->segs[R_CS].selector; - selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, dpl); - env->eip = offset; - ESP = esp - push_size; - ssp = env->segs[R_SS].base + esp; - if (shift == 1) { - int old_eflags; - if (env->eflags & VM_MASK) { - ssp -= 4; - stl(ssp, env->segs[R_GS].selector); - ssp -= 4; - stl(ssp, env->segs[R_FS].selector); - ssp -= 4; - stl(ssp, env->segs[R_DS].selector); - ssp -= 4; - stl(ssp, env->segs[R_ES].selector); - } - if (new_stack) { - ssp -= 4; - stl(ssp, old_ss); - ssp -= 4; - stl(ssp, old_esp); - } - ssp -= 4; - old_eflags = compute_eflags(); - stl(ssp, old_eflags); - ssp -= 4; - stl(ssp, old_cs); - ssp -= 4; - stl(ssp, old_eip); - if (has_error_code) { - ssp -= 4; - stl(ssp, error_code); - } - } else { - if (new_stack) { - ssp -= 2; - stw(ssp, old_ss); - ssp -= 2; - stw(ssp, old_esp); - } - ssp -= 2; - stw(ssp, compute_eflags()); - ssp -= 2; - stw(ssp, old_cs); - ssp -= 2; - stw(ssp, old_eip); - if (has_error_code) { - ssp -= 2; - stw(ssp, error_code); - } - } - - /* interrupt gate clear IF mask */ - if ((type & 1) == 0) { - env->eflags &= ~IF_MASK; - } - env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); -} - -/* real mode interrupt */ -static void do_interrupt_real(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - SegmentCache *dt; - uint8_t *ptr, *ssp; - int selector; - uint32_t offset, esp; - uint32_t old_cs, old_eip; - - /* real mode (simpler !) */ - dt = &env->idt; - if (intno * 4 + 3 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - ptr = dt->base + intno * 4; - offset = lduw(ptr); - selector = lduw(ptr + 2); - esp = ESP; - ssp = env->segs[R_SS].base; - if (is_int) - old_eip = next_eip; - else - old_eip = env->eip; - old_cs = env->segs[R_CS].selector; - esp -= 2; - stw(ssp + (esp & 0xffff), compute_eflags()); - esp -= 2; - stw(ssp + (esp & 0xffff), old_cs); - esp -= 2; - stw(ssp + (esp & 0xffff), old_eip); - - /* update processor state */ - ESP = (ESP & ~0xffff) | (esp & 0xffff); - env->eip = offset; - env->segs[R_CS].selector = selector; - env->segs[R_CS].base = (uint8_t *)(selector << 4); - env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); -} - -/* fake user mode interrupt */ -void do_interrupt_user(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - SegmentCache *dt; - uint8_t *ptr; - int dpl, cpl; - uint32_t e2; - - dt = &env->idt; - ptr = dt->base + (intno * 8); - e2 = ldl(ptr + 4); - - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privledge if software int */ - if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); - - /* Since we emulate only user space, we cannot do more than - exiting the emulation with the suitable exception and error - code */ - if (is_int) - EIP = next_eip; -} - -/* - * Begin excution of an interruption. is_int is TRUE if coming from - * the int instruction. next_eip is the EIP value AFTER the interrupt - * instruction. It is only relevant if is_int is TRUE. - */ -void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw) -{ - if (env->cr[0] & CR0_PE_MASK) { - do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); - } else { - do_interrupt_real(intno, is_int, error_code, next_eip); - } -} - -/* - * Signal an interruption. It is executed in the main CPU loop. - * is_int is TRUE if coming from the int instruction. next_eip is the - * EIP value AFTER the interrupt instruction. It is only relevant if - * is_int is TRUE. - */ -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip) -{ - env->exception_index = intno; - env->error_code = error_code; - env->exception_is_int = is_int; - env->exception_next_eip = next_eip; - cpu_loop_exit(); -} - -/* shortcuts to generate exceptions */ -void raise_exception_err(int exception_index, int error_code) -{ - raise_interrupt(exception_index, 0, error_code, 0); -} - -void raise_exception(int exception_index) -{ - raise_interrupt(exception_index, 0, 0, 0); -} - -#ifdef BUGGY_GCC_DIV64 -/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we - call it from another function */ -uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) -{ - *q_ptr = num / den; - return num % den; -} - -int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) -{ - *q_ptr = num / den; - return num % den; -} -#endif - -void helper_divl_EAX_T0(uint32_t eip) -{ - unsigned int den, q, r; - uint64_t num; - - num = EAX | ((uint64_t)EDX << 32); - den = T0; - if (den == 0) { - EIP = eip; - raise_exception(EXCP00_DIVZ); - } -#ifdef BUGGY_GCC_DIV64 - r = div64(&q, num, den); -#else - q = (num / den); - r = (num % den); -#endif - EAX = q; - EDX = r; -} - -void helper_idivl_EAX_T0(uint32_t eip) -{ - int den, q, r; - int64_t num; - - num = EAX | ((uint64_t)EDX << 32); - den = T0; - if (den == 0) { - EIP = eip; - raise_exception(EXCP00_DIVZ); - } -#ifdef BUGGY_GCC_DIV64 - r = idiv64(&q, num, den); -#else - q = (num / den); - r = (num % den); -#endif - EAX = q; - EDX = r; -} - -void helper_cmpxchg8b(void) -{ - uint64_t d; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - d = ldq((uint8_t *)A0); - if (d == (((uint64_t)EDX << 32) | EAX)) { - stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); - eflags |= CC_Z; - } else { - EDX = d >> 32; - EAX = d; - eflags &= ~CC_Z; - } - CC_SRC = eflags; -} - -/* We simulate a pre-MMX pentium as in valgrind */ -#define CPUID_FP87 (1 << 0) -#define CPUID_VME (1 << 1) -#define CPUID_DE (1 << 2) -#define CPUID_PSE (1 << 3) -#define CPUID_TSC (1 << 4) -#define CPUID_MSR (1 << 5) -#define CPUID_PAE (1 << 6) -#define CPUID_MCE (1 << 7) -#define CPUID_CX8 (1 << 8) -#define CPUID_APIC (1 << 9) -#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ -#define CPUID_MTRR (1 << 12) -#define CPUID_PGE (1 << 13) -#define CPUID_MCA (1 << 14) -#define CPUID_CMOV (1 << 15) -/* ... */ -#define CPUID_MMX (1 << 23) -#define CPUID_FXSR (1 << 24) -#define CPUID_SSE (1 << 25) -#define CPUID_SSE2 (1 << 26) - -void helper_cpuid(void) -{ - if (EAX == 0) { - EAX = 1; /* max EAX index supported */ - EBX = 0x756e6547; - ECX = 0x6c65746e; - EDX = 0x49656e69; - } else if (EAX == 1) { - int family, model, stepping; - /* EAX = 1 info */ -#if 0 - /* pentium 75-200 */ - family = 5; - model = 2; - stepping = 11; -#else - /* pentium pro */ - family = 6; - model = 1; - stepping = 3; -#endif - EAX = (family << 8) | (model << 4) | stepping; - EBX = 0; - ECX = 0; - EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | - CPUID_TSC | CPUID_MSR | CPUID_MCE | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV; - } -} - -void helper_lldt_T0(void) -{ - int selector; - SegmentCache *dt; - uint32_t e1, e2; - int index; - uint8_t *ptr; - - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) { - /* XXX: NULL selector case: invalid LDT */ - env->ldt.base = NULL; - env->ldt.limit = 0; - } else { - if (selector & 0x4) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - load_seg_cache_raw_dt(&env->ldt, e1, e2); - } - env->ldt.selector = selector; -} - -void helper_ltr_T0(void) -{ - int selector; - SegmentCache *dt; - uint32_t e1, e2; - int index, type; - uint8_t *ptr; - - selector = T0 & 0xffff; - if ((selector & 0xfffc) == 0) { - /* NULL selector case: invalid LDT */ - env->tr.base = NULL; - env->tr.limit = 0; - env->tr.flags = 0; - } else { - if (selector & 0x4) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dt = &env->gdt; - index = selector & ~7; - if ((index + 7) > dt->limit) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; - if ((e2 & DESC_S_MASK) || - (type != 2 && type != 9)) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - load_seg_cache_raw_dt(&env->tr, e1, e2); - e2 |= 0x00000200; /* set the busy bit */ - stl(ptr + 4, e2); - } - env->tr.selector = selector; -} - -/* only works if protected mode and not VM86. Calling load_seg with - seg_reg == R_CS is discouraged */ -void load_seg(int seg_reg, int selector, unsigned int cur_eip) -{ - uint32_t e1, e2; - - if ((selector & 0xfffc) == 0) { - /* null selector case */ - if (seg_reg == R_SS) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, 0); - } else { - cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); - } - } else { - if (load_segment(&e1, &e2, selector) != 0) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - if (!(e2 & DESC_S_MASK) || - (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - - if (seg_reg == R_SS) { - if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - } else { - if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { - EIP = cur_eip; - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - } - - if (!(e2 & DESC_P_MASK)) { - EIP = cur_eip; - if (seg_reg == R_SS) - raise_exception_err(EXCP0C_STACK, selector & 0xfffc); - else - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - } - cpu_x86_load_seg_cache(env, seg_reg, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); -#if 0 - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", - selector, (unsigned long)sc->base, sc->limit, sc->flags); -#endif - } -} - -/* protected mode jump */ -void helper_ljmp_protected_T0_T1(void) -{ - int new_cs, new_eip; - uint32_t e1, e2, cpl, dpl, rpl, limit; - - new_cs = T0; - new_eip = T1; - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_S_MASK) { - if (!(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { - /* conforming code segment */ - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - /* non conforming code segment */ - rpl = new_cs & 3; - if (rpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (dpl != cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - limit = get_seg_limit(e1, e2); - if (new_eip > limit) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), limit, e2); - EIP = new_eip; - } else { - cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", - new_cs, new_eip); - } -} - -/* real mode call */ -void helper_lcall_real_T0_T1(int shift, int next_eip) -{ - int new_cs, new_eip; - uint32_t esp, esp_mask; - uint8_t *ssp; - - new_cs = T0; - new_eip = T1; - esp = ESP; - esp_mask = 0xffffffff; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - esp_mask = 0xffff; - ssp = env->segs[R_SS].base; - if (shift) { - esp -= 4; - stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); - esp -= 4; - stl(ssp + (esp & esp_mask), next_eip); - } else { - esp -= 2; - stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); - esp -= 2; - stw(ssp + (esp & esp_mask), next_eip); - } - - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & ~0xffff) | (esp & 0xffff); - else - ESP = esp; - env->eip = new_eip; - env->segs[R_CS].selector = new_cs; - env->segs[R_CS].base = (uint8_t *)(new_cs << 4); -} - -/* protected mode call */ -void helper_lcall_protected_T0_T1(int shift, int next_eip) -{ - int new_cs, new_eip; - uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; - uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; - uint32_t old_ss, old_esp, val, i, limit; - uint8_t *ssp, *old_ssp; - - new_cs = T0; - new_eip = T1; - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; - if (e2 & DESC_S_MASK) { - if (!(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { - /* conforming code segment */ - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - /* non conforming code segment */ - rpl = new_cs & 3; - if (rpl > cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (dpl != cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - - sp = ESP; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - if (shift) { - ssp -= 4; - stl(ssp, env->segs[R_CS].selector); - ssp -= 4; - stl(ssp, next_eip); - } else { - ssp -= 2; - stw(ssp, env->segs[R_CS].selector); - ssp -= 2; - stw(ssp, next_eip); - } - sp -= (4 << shift); - - limit = get_seg_limit(e1, e2); - if (new_eip > limit) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - /* from this point, not restartable */ - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & 0xffff0000) | (sp & 0xffff); - else - ESP = sp; - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), limit, e2); - EIP = new_eip; - } else { - /* check gate type */ - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; - switch(type) { - case 1: /* available 286 TSS */ - case 9: /* available 386 TSS */ - case 5: /* task gate */ - cpu_abort(env, "task gate not supported"); - break; - case 4: /* 286 call gate */ - case 12: /* 386 call gate */ - break; - default: - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - break; - } - shift = type >> 3; - - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - rpl = new_cs & 3; - if (dpl < cpl || dpl < rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - /* check valid bit */ - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - selector = e1 >> 16; - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); - if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); - - if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - - if (!(e2 & DESC_C_MASK) && dpl < cpl) { - /* to inner priviledge */ - get_ss_esp_from_tss(&ss, &sp, dpl); - if ((ss & 0xfffc) == 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if ((ss & 3) != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, ss) != 0) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (ss_dpl != dpl) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - - param_count = e2 & 0x1f; - push_size = ((param_count * 2) + 8) << shift; - - old_esp = ESP; - old_ss = env->segs[R_SS].selector; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - old_esp &= 0xffff; - old_ssp = env->segs[R_SS].base + old_esp; - - /* XXX: from this point not restartable */ - ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - if (shift) { - ssp -= 4; - stl(ssp, old_ss); - ssp -= 4; - stl(ssp, old_esp); - ssp -= 4 * param_count; - for(i = 0; i < param_count; i++) { - val = ldl(old_ssp + i * 4); - stl(ssp + i * 4, val); - } - } else { - ssp -= 2; - stw(ssp, old_ss); - ssp -= 2; - stw(ssp, old_esp); - ssp -= 2 * param_count; - for(i = 0; i < param_count; i++) { - val = lduw(old_ssp + i * 2); - stw(ssp + i * 2, val); - } - } - } else { - /* to same priviledge */ - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - push_size = (4 << shift); - } - - if (shift) { - ssp -= 4; - stl(ssp, env->segs[R_CS].selector); - ssp -= 4; - stl(ssp, next_eip); - } else { - ssp -= 2; - stw(ssp, env->segs[R_CS].selector); - ssp -= 2; - stw(ssp, next_eip); - } - - sp -= push_size; - selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, dpl); - - /* from this point, not restartable if same priviledge */ - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & 0xffff0000) | (sp & 0xffff); - else - ESP = sp; - EIP = offset; - } -} - -/* real mode iret */ -void helper_iret_real(int shift) -{ - uint32_t sp, new_cs, new_eip, new_eflags, new_esp; - uint8_t *ssp; - int eflags_mask; - - sp = ESP & 0xffff; - ssp = env->segs[R_SS].base + sp; - if (shift == 1) { - /* 32 bits */ - new_eflags = ldl(ssp + 8); - new_cs = ldl(ssp + 4) & 0xffff; - new_eip = ldl(ssp) & 0xffff; - } else { - /* 16 bits */ - new_eflags = lduw(ssp + 4); - new_cs = lduw(ssp + 2); - new_eip = lduw(ssp); - } - new_esp = sp + (6 << shift); - ESP = (ESP & 0xffff0000) | - (new_esp & 0xffff); - load_seg_vm(R_CS, new_cs); - env->eip = new_eip; - eflags_mask = FL_UPDATE_CPL0_MASK; - if (shift == 0) - eflags_mask &= 0xffff; - load_eflags(new_eflags, eflags_mask); -} - -/* protected mode iret */ -static inline void helper_ret_protected(int shift, int is_iret, int addend) -{ - uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; - uint32_t new_es, new_ds, new_fs, new_gs; - uint32_t e1, e2, ss_e1, ss_e2; - int cpl, dpl, rpl, eflags_mask; - uint8_t *ssp; - - sp = ESP; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - if (shift == 1) { - /* 32 bits */ - if (is_iret) - new_eflags = ldl(ssp + 8); - new_cs = ldl(ssp + 4) & 0xffff; - new_eip = ldl(ssp); - if (is_iret && (new_eflags & VM_MASK)) - goto return_to_vm86; - } else { - /* 16 bits */ - if (is_iret) - new_eflags = lduw(ssp + 4); - new_cs = lduw(ssp + 2); - new_eip = lduw(ssp); - } - if ((new_cs & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (load_segment(&e1, &e2, new_cs) != 0) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - if (!(e2 & DESC_S_MASK) || - !(e2 & DESC_CS_MASK)) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - cpl = env->hflags & HF_CPL_MASK; - rpl = new_cs & 3; - if (rpl < cpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { - if (dpl > rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } else { - if (dpl != rpl) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - } - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - - if (rpl == cpl) { - /* return to same priledge level */ - cpu_x86_load_seg_cache(env, R_CS, new_cs, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; - } else { - /* return to different priviledge level */ - ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; - if (shift == 1) { - /* 32 bits */ - new_esp = ldl(ssp); - new_ss = ldl(ssp + 4) & 0xffff; - } else { - /* 16 bits */ - new_esp = lduw(ssp); - new_ss = lduw(ssp + 2); - } - - if ((new_ss & 3) != rpl) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (dpl != rpl) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); - - cpu_x86_load_seg_cache(env, R_CS, new_cs, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_load_seg_cache(env, R_SS, new_ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - cpu_x86_set_cpl(env, rpl); - } - if (env->segs[R_SS].flags & DESC_B_MASK) - ESP = new_esp; - else - ESP = (ESP & 0xffff0000) | - (new_esp & 0xffff); - env->eip = new_eip; - if (is_iret) { - /* NOTE: 'cpl' can be different from the current CPL */ - if (cpl == 0) - eflags_mask = FL_UPDATE_CPL0_MASK; - else - eflags_mask = FL_UPDATE_MASK32; - if (shift == 0) - eflags_mask &= 0xffff; - load_eflags(new_eflags, eflags_mask); - } - return; - - return_to_vm86: - new_esp = ldl(ssp + 12); - new_ss = ldl(ssp + 16); - new_es = ldl(ssp + 20); - new_ds = ldl(ssp + 24); - new_fs = ldl(ssp + 28); - new_gs = ldl(ssp + 32); - - /* modify processor state */ - load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); - load_seg_vm(R_CS, new_cs); - cpu_x86_set_cpl(env, 3); - load_seg_vm(R_SS, new_ss); - load_seg_vm(R_ES, new_es); - load_seg_vm(R_DS, new_ds); - load_seg_vm(R_FS, new_fs); - load_seg_vm(R_GS, new_gs); - - env->eip = new_eip; - ESP = new_esp; -} - -void helper_iret_protected(int shift) -{ - helper_ret_protected(shift, 1, 0); -} - -void helper_lret_protected(int shift, int addend) -{ - helper_ret_protected(shift, 0, addend); -} - -void helper_movl_crN_T0(int reg) -{ - env->cr[reg] = T0; - switch(reg) { - case 0: - cpu_x86_update_cr0(env); - break; - case 3: - cpu_x86_update_cr3(env); - break; - } -} - -/* XXX: do more */ -void helper_movl_drN_T0(int reg) -{ - env->dr[reg] = T0; -} - -void helper_invlpg(unsigned int addr) -{ - cpu_x86_flush_tlb(env, addr); -} - -/* rdtsc */ -#ifndef __i386__ -uint64_t emu_time; -#endif - -void helper_rdtsc(void) -{ - uint64_t val; -#ifdef __i386__ - asm("rdtsc" : "=A" (val)); -#else - /* better than nothing: the time increases */ - val = emu_time++; -#endif - EAX = val; - EDX = val >> 32; -} - -void helper_wrmsr(void) -{ - switch(ECX) { - case MSR_IA32_SYSENTER_CS: - env->sysenter_cs = EAX & 0xffff; - break; - case MSR_IA32_SYSENTER_ESP: - env->sysenter_esp = EAX; - break; - case MSR_IA32_SYSENTER_EIP: - env->sysenter_eip = EAX; - break; - default: - /* XXX: exception ? */ - break; - } -} - -void helper_rdmsr(void) -{ - switch(ECX) { - case MSR_IA32_SYSENTER_CS: - EAX = env->sysenter_cs; - EDX = 0; - break; - case MSR_IA32_SYSENTER_ESP: - EAX = env->sysenter_esp; - EDX = 0; - break; - case MSR_IA32_SYSENTER_EIP: - EAX = env->sysenter_eip; - EDX = 0; - break; - default: - /* XXX: exception ? */ - break; - } -} - -void helper_lsl(void) -{ - unsigned int selector, limit; - uint32_t e1, e2; - - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; - selector = T0 & 0xffff; - if (load_segment(&e1, &e2, selector) != 0) - return; - limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & (1 << 23)) - limit = (limit << 12) | 0xfff; - T1 = limit; - CC_SRC |= CC_Z; -} - -void helper_lar(void) -{ - unsigned int selector; - uint32_t e1, e2; - - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; - selector = T0 & 0xffff; - if (load_segment(&e1, &e2, selector) != 0) - return; - T1 = e2 & 0x00f0ff00; - CC_SRC |= CC_Z; -} - -/* FPU helpers */ - -#ifndef USE_X86LDOUBLE -void helper_fldt_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void helper_fstt_ST0_A0(void) -{ - helper_fstt(ST0, (uint8_t *)A0); -} -#endif - -/* BCD ops */ - -#define MUL10(iv) ( iv + iv + (iv << 3) ) - -void helper_fbld_ST0_A0(void) -{ - CPU86_LDouble tmp; - uint64_t val; - unsigned int v; - int i; - - val = 0; - for(i = 8; i >= 0; i--) { - v = ldub((uint8_t *)A0 + i); - val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); - } - tmp = val; - if (ldub((uint8_t *)A0 + 9) & 0x80) - tmp = -tmp; - fpush(); - ST0 = tmp; -} - -void helper_fbst_ST0_A0(void) -{ - CPU86_LDouble tmp; - int v; - uint8_t *mem_ref, *mem_end; - int64_t val; - - tmp = rint(ST0); - val = (int64_t)tmp; - mem_ref = (uint8_t *)A0; - mem_end = mem_ref + 9; - if (val < 0) { - stb(mem_end, 0x80); - val = -val; - } else { - stb(mem_end, 0x00); - } - while (mem_ref < mem_end) { - if (val == 0) - break; - v = val % 100; - val = val / 100; - v = ((v / 10) << 4) | (v % 10); - stb(mem_ref++, v); - } - while (mem_ref < mem_end) { - stb(mem_ref++, 0); - } -} - -void helper_f2xm1(void) -{ - ST0 = pow(2.0,ST0) - 1.0; -} - -void helper_fyl2x(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp>0.0){ - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fptan(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = tan(fptemp); - fpush(); - ST0 = 1.0; - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**52 only */ - } -} - -void helper_fpatan(void) -{ - CPU86_LDouble fptemp, fpsrcop; - - fpsrcop = ST1; - fptemp = ST0; - ST1 = atan2(fpsrcop,fptemp); - fpop(); -} - -void helper_fxtract(void) -{ - CPU86_LDoubleU temp; - unsigned int expdif; - - temp.d = ST0; - expdif = EXPD(temp) - EXPBIAS; - /*DP exponent bias*/ - ST0 = expdif; - fpush(); - BIASEXPONENT(temp); - ST0 = temp.d; -} - -void helper_fprem1(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - if (expdif < 53) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by rounding to the nearest */ - fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? - floor(fpsrcop): ceil(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fprem(void) -{ - CPU86_LDouble dblq, fpsrcop, fptemp; - CPU86_LDoubleU fpsrcop1, fptemp1; - int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; - fpsrcop1.d = fpsrcop; - fptemp1.d = fptemp; - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); - if ( expdif < 53 ) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ - } else { - env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); - fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0)? - -(floor(fabs(fpsrcop))): floor(fpsrcop); - ST0 -= (ST1 * fpsrcop * fptemp); - } -} - -void helper_fyl2xp1(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp+1.0)>0.0) { - fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ - ST1 *= fptemp; - fpop(); - } else { - env->fpus &= (~0x4700); - env->fpus |= 0x400; - } -} - -void helper_fsqrt(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if (fptemp<0.0) { - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - env->fpus |= 0x400; - } - ST0 = sqrt(fptemp); -} - -void helper_fsincos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - fpush(); - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**63 only */ - } -} - -void helper_frndint(void) -{ - CPU86_LDouble a; - - a = ST0; -#ifdef __arm__ - switch(env->fpuc & RC_MASK) { - default: - case RC_NEAR: - asm("rndd %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_DOWN: - asm("rnddm %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_UP: - asm("rnddp %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_CHOP: - asm("rnddz %0, %1" : "=f" (a) : "f"(a)); - break; - } -#else - a = rint(a); -#endif - ST0 = a; -} - -void helper_fscale(void) -{ - CPU86_LDouble fpsrcop, fptemp; - - fpsrcop = 2.0; - fptemp = pow(fpsrcop,ST1); - ST0 *= fptemp; -} - -void helper_fsin(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = sin(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg| < 2**53 only */ - } -} - -void helper_fcos(void) -{ - CPU86_LDouble fptemp; - - fptemp = ST0; - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { - env->fpus |= 0x400; - } else { - ST0 = cos(fptemp); - env->fpus &= (~0x400); /* C2 <-- 0 */ - /* the above code is for |arg5 < 2**63 only */ - } -} - -void helper_fxam_ST0(void) -{ - CPU86_LDoubleU temp; - int expdif; - - temp.d = ST0; - - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - if (SIGND(temp)) - env->fpus |= 0x200; /* C1 <-- 1 */ - - expdif = EXPD(temp); - if (expdif == MAXEXPD) { - if (MANTD(temp) == 0) - env->fpus |= 0x500 /*Infinity*/; - else - env->fpus |= 0x100 /*NaN*/; - } else if (expdif == 0) { - if (MANTD(temp) == 0) - env->fpus |= 0x4000 /*Zero*/; - else - env->fpus |= 0x4400 /*Denormal*/; - } else { - env->fpus |= 0x400; - } -} - -void helper_fstenv(uint8_t *ptr, int data32) -{ - int fpus, fptag, exp, i; - uint64_t mant; - CPU86_LDoubleU tmp; - - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - fptag = 0; - for (i=7; i>=0; i--) { - fptag <<= 2; - if (env->fptags[i]) { - fptag |= 3; - } else { - tmp.d = env->fpregs[i]; - exp = EXPD(tmp); - mant = MANTD(tmp); - if (exp == 0 && mant == 0) { - /* zero */ - fptag |= 1; - } else if (exp == 0 || exp == MAXEXPD -#ifdef USE_X86LDOUBLE - || (mant & (1LL << 63)) == 0 -#endif - ) { - /* NaNs, infinity, denormal */ - fptag |= 2; - } - } - } - if (data32) { - /* 32 bit */ - stl(ptr, env->fpuc); - stl(ptr + 4, fpus); - stl(ptr + 8, fptag); - stl(ptr + 12, 0); - stl(ptr + 16, 0); - stl(ptr + 20, 0); - stl(ptr + 24, 0); - } else { - /* 16 bit */ - stw(ptr, env->fpuc); - stw(ptr + 2, fpus); - stw(ptr + 4, fptag); - stw(ptr + 6, 0); - stw(ptr + 8, 0); - stw(ptr + 10, 0); - stw(ptr + 12, 0); - } -} - -void helper_fldenv(uint8_t *ptr, int data32) -{ - int i, fpus, fptag; - - if (data32) { - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 4); - fptag = lduw(ptr + 8); - } - else { - env->fpuc = lduw(ptr); - fpus = lduw(ptr + 2); - fptag = lduw(ptr + 4); - } - env->fpstt = (fpus >> 11) & 7; - env->fpus = fpus & ~0x3800; - for(i = 0;i < 7; i++) { - env->fptags[i] = ((fptag & 3) == 3); - fptag >>= 2; - } -} - -void helper_fsave(uint8_t *ptr, int data32) -{ - CPU86_LDouble tmp; - int i; - - helper_fstenv(ptr, data32); - - ptr += (14 << data32); - for(i = 0;i < 8; i++) { - tmp = ST(i); -#ifdef USE_X86LDOUBLE - *(long double *)ptr = tmp; -#else - helper_fstt(tmp, ptr); -#endif - ptr += 10; - } - - /* fninit */ - env->fpus = 0; - env->fpstt = 0; - env->fpuc = 0x37f; - env->fptags[0] = 1; - env->fptags[1] = 1; - env->fptags[2] = 1; - env->fptags[3] = 1; - env->fptags[4] = 1; - env->fptags[5] = 1; - env->fptags[6] = 1; - env->fptags[7] = 1; -} - -void helper_frstor(uint8_t *ptr, int data32) -{ - CPU86_LDouble tmp; - int i; - - helper_fldenv(ptr, data32); - ptr += (14 << data32); - - for(i = 0;i < 8; i++) { -#ifdef USE_X86LDOUBLE - tmp = *(long double *)ptr; -#else - tmp = helper_fldt(ptr); -#endif - ST(i) = tmp; - ptr += 10; - } -} - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - -/* try to fill the TLB and return an exception if error */ -void tlb_fill(unsigned long addr, int is_write, void *retaddr) -{ - TranslationBlock *tb; - int ret; - unsigned long pc; - ret = cpu_x86_handle_mmu_fault(env, addr, is_write); - if (ret) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - 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); - } - raise_exception_err(EXCP0E_PAGE, env->error_code); - } -} diff --git a/helper2-i386.c b/helper2-i386.c deleted file mode 100644 index f006c72a2..000000000 --- a/helper2-i386.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * i386 helpers (without register variable usage) - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu-i386.h" -#include "exec.h" - -//#define DEBUG_MMU - -CPUX86State *cpu_x86_init(void) -{ - CPUX86State *env; - int i; - static int inited; - - cpu_exec_init(); - - env = malloc(sizeof(CPUX86State)); - if (!env) - return NULL; - memset(env, 0, sizeof(CPUX86State)); - /* basic FPU init */ - for(i = 0;i < 8; i++) - env->fptags[i] = 1; - env->fpuc = 0x37f; - /* flags setup : we activate the IRQs by default as in user mode */ - env->eflags = 0x2 | IF_MASK; - - tlb_flush(env); -#ifdef CONFIG_SOFTMMU - env->hflags |= HF_SOFTMMU_MASK; -#endif - /* init various static tables */ - if (!inited) { - inited = 1; - optimize_flags_init(); - } - return env; -} - -void cpu_x86_close(CPUX86State *env) -{ - free(env); -} - -/***********************************************************/ -/* x86 debug */ - -static const char *cc_op_str[] = { - "DYNAMIC", - "EFLAGS", - "MUL", - "ADDB", - "ADDW", - "ADDL", - "ADCB", - "ADCW", - "ADCL", - "SUBB", - "SUBW", - "SUBL", - "SBBB", - "SBBW", - "SBBL", - "LOGICB", - "LOGICW", - "LOGICL", - "INCB", - "INCW", - "INCL", - "DECB", - "DECW", - "DECL", - "SHLB", - "SHLW", - "SHLL", - "SARB", - "SARW", - "SARL", -}; - -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) -{ - int eflags; - char cc_op_name[32]; - - eflags = env->eflags; - fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", - env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], - env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], - env->eip, eflags, - eflags & DF_MASK ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-'); - fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", - env->segs[R_CS].selector, - env->segs[R_SS].selector, - env->segs[R_DS].selector, - env->segs[R_ES].selector, - env->segs[R_FS].selector, - env->segs[R_GS].selector); - if (flags & X86_DUMP_CCOP) { - if ((unsigned)env->cc_op < CC_OP_NB) - strcpy(cc_op_name, cc_op_str[env->cc_op]); - else - snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); - fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", - env->cc_src, env->cc_dst, cc_op_name); - } - if (flags & X86_DUMP_FPU) { - fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", - (double)env->fpregs[0], - (double)env->fpregs[1], - (double)env->fpregs[2], - (double)env->fpregs[3]); - fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", - (double)env->fpregs[4], - (double)env->fpregs[5], - (double)env->fpregs[7], - (double)env->fpregs[8]); - } -} - -/***********************************************************/ -/* x86 mmu */ -/* XXX: add PGE support */ - -/* called when cr3 or PG bit are modified */ -static int last_pg_state = -1; -static int last_pe_state = 0; -int phys_ram_size; -int phys_ram_fd; -uint8_t *phys_ram_base; - -void cpu_x86_update_cr0(CPUX86State *env) -{ - int pg_state, pe_state; - -#ifdef DEBUG_MMU - printf("CR0 update: CR0=0x%08x\n", env->cr[0]); -#endif - pg_state = env->cr[0] & CR0_PG_MASK; - if (pg_state != last_pg_state) { - page_unmap(); - tlb_flush(env); - last_pg_state = pg_state; - } - pe_state = env->cr[0] & CR0_PE_MASK; - if (last_pe_state != pe_state) { - tb_flush(); - last_pe_state = pe_state; - } -} - -void cpu_x86_update_cr3(CPUX86State *env) -{ - if (env->cr[0] & CR0_PG_MASK) { -#if defined(DEBUG_MMU) - printf("CR3 update: CR3=%08x\n", env->cr[3]); -#endif - page_unmap(); - tlb_flush(env); - } -} - -void cpu_x86_init_mmu(CPUX86State *env) -{ - last_pg_state = -1; - cpu_x86_update_cr0(env); -} - -/* XXX: also flush 4MB pages */ -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) -{ - int flags; - unsigned long virt_addr; - - tlb_flush_page(env, addr); - - flags = page_get_flags(addr); - if (flags & PAGE_VALID) { - virt_addr = addr & ~0xfff; - munmap((void *)virt_addr, 4096); - page_set_flags(virt_addr, virt_addr + 4096, 0); - } -} - -/* return value: - -1 = cannot handle fault - 0 = nothing more to do - 1 = generate PF fault - 2 = soft MMU activation required for this block -*/ -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) -{ - uint8_t *pde_ptr, *pte_ptr; - uint32_t pde, pte, virt_addr; - int cpl, error_code, is_dirty, is_user, prot, page_size, ret; - unsigned long pd; - - cpl = env->hflags & HF_CPL_MASK; - is_user = (cpl == 3); - -#ifdef DEBUG_MMU - printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", - addr, is_write, is_user, env->eip); -#endif - - if (env->user_mode_only) { - /* user mode only emulation */ - error_code = 0; - goto do_fault; - } - - if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr; - virt_addr = addr & ~0xfff; - prot = PROT_READ | PROT_WRITE; - page_size = 4096; - goto do_mapping; - } - - /* page directory entry */ - pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); - pde = ldl(pde_ptr); - if (!(pde & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (is_user) { - if (!(pde & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && - is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } - /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - is_dirty = is_write && !(pde & PG_DIRTY_MASK); - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_DIRTY_MASK; - stl(pde_ptr, pde); - } - - pte = pde & ~0x003ff000; /* align to 4MB */ - page_size = 4096 * 1024; - virt_addr = addr & ~0x003fffff; - } else { - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - stl(pde_ptr, pde); - } - - /* page directory entry */ - pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); - pte = ldl(pte_ptr); - if (!(pte & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (is_user) { - if (!(pte & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(pte & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && - is_write && !(pte & PG_RW_MASK)) - goto do_fault_protect; - } - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) - pte |= PG_DIRTY_MASK; - stl(pte_ptr, pte); - } - page_size = 4096; - virt_addr = addr & ~0xfff; - } - /* the page can be put in the TLB */ - prot = PROT_READ; - if (is_user) { - if (pte & PG_RW_MASK) - prot |= PROT_WRITE; - } else { - if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || - (pte & PG_RW_MASK)) - prot |= PROT_WRITE; - } - - do_mapping: - if (env->hflags & HF_SOFTMMU_MASK) { - unsigned long paddr, vaddr, address, addend, page_offset; - int index; - - /* software MMU case. Even if 4MB pages, we map only one 4KB - page in the cache to avoid filling it too fast */ - page_offset = (addr & ~0xfff) & (page_size - 1); - paddr = (pte & ~0xfff) + page_offset; - vaddr = virt_addr + page_offset; - index = (addr >> 12) & (CPU_TLB_SIZE - 1); - pd = physpage_find(paddr); - if (pd & 0xfff) { - /* IO memory case */ - address = vaddr | pd; - addend = paddr; - } else { - /* standard memory */ - address = vaddr; - addend = (unsigned long)phys_ram_base + pd; - } - addend -= vaddr; - env->tlb_read[is_user][index].address = address; - env->tlb_read[is_user][index].addend = addend; - if (prot & PROT_WRITE) { - env->tlb_write[is_user][index].address = address; - env->tlb_write[is_user][index].addend = addend; - } - } - ret = 0; - /* XXX: incorrect for 4MB pages */ - pd = physpage_find(pte & ~0xfff); - if ((pd & 0xfff) != 0) { - /* IO access: no mapping is done as it will be handled by the - soft MMU */ - if (!(env->hflags & HF_SOFTMMU_MASK)) - ret = 2; - } else { - void *map_addr; - map_addr = mmap((void *)virt_addr, page_size, prot, - MAP_SHARED | MAP_FIXED, phys_ram_fd, pd); - if (map_addr == MAP_FAILED) { - fprintf(stderr, - "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", - pte & ~0xfff, virt_addr); - exit(1); - } -#ifdef DEBUG_MMU - printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", - pte & ~0xfff, virt_addr, (page_size != 4096)); -#endif - page_set_flags(virt_addr, virt_addr + page_size, - PAGE_VALID | PAGE_EXEC | prot); - } - return ret; - do_fault_protect: - error_code = PG_ERROR_P_MASK; - do_fault: - env->cr[2] = addr; - env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; - if (is_user) - env->error_code |= PG_ERROR_U_MASK; - return 1; -} diff --git a/op-arm-template.h b/op-arm-template.h deleted file mode 100644 index 00e9d51fe..000000000 --- a/op-arm-template.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * ARM micro operations (templates for various register related - * operations) - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -void OPPROTO glue(op_movl_T0_, REGNAME)(void) -{ - T0 = REG; -} - -void OPPROTO glue(op_movl_T1_, REGNAME)(void) -{ - T1 = REG; -} - -void OPPROTO glue(op_movl_T2_, REGNAME)(void) -{ - T2 = REG; -} - -void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) -{ - REG = T0; -} - -void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) -{ - REG = T1; -} - -#undef REG -#undef REGNAME diff --git a/op-arm.c b/op-arm.c deleted file mode 100644 index 98ef9a0c9..000000000 --- a/op-arm.c +++ /dev/null @@ -1,673 +0,0 @@ -/* - * ARM micro operations - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "exec-arm.h" - -#define REGNAME r0 -#define REG (env->regs[0]) -#include "op-arm-template.h" - -#define REGNAME r1 -#define REG (env->regs[1]) -#include "op-arm-template.h" - -#define REGNAME r2 -#define REG (env->regs[2]) -#include "op-arm-template.h" - -#define REGNAME r3 -#define REG (env->regs[3]) -#include "op-arm-template.h" - -#define REGNAME r4 -#define REG (env->regs[4]) -#include "op-arm-template.h" - -#define REGNAME r5 -#define REG (env->regs[5]) -#include "op-arm-template.h" - -#define REGNAME r6 -#define REG (env->regs[6]) -#include "op-arm-template.h" - -#define REGNAME r7 -#define REG (env->regs[7]) -#include "op-arm-template.h" - -#define REGNAME r8 -#define REG (env->regs[8]) -#include "op-arm-template.h" - -#define REGNAME r9 -#define REG (env->regs[9]) -#include "op-arm-template.h" - -#define REGNAME r10 -#define REG (env->regs[10]) -#include "op-arm-template.h" - -#define REGNAME r11 -#define REG (env->regs[11]) -#include "op-arm-template.h" - -#define REGNAME r12 -#define REG (env->regs[12]) -#include "op-arm-template.h" - -#define REGNAME r13 -#define REG (env->regs[13]) -#include "op-arm-template.h" - -#define REGNAME r14 -#define REG (env->regs[14]) -#include "op-arm-template.h" - -#define REGNAME r15 -#define REG (env->regs[15]) -#include "op-arm-template.h" - -void OPPROTO op_movl_T0_0(void) -{ - T0 = 0; -} - -void OPPROTO op_movl_T0_im(void) -{ - T0 = PARAM1; -} - -void OPPROTO op_movl_T1_im(void) -{ - T1 = PARAM1; -} - -void OPPROTO op_movl_T2_im(void) -{ - T2 = PARAM1; -} - -void OPPROTO op_addl_T1_im(void) -{ - T1 += PARAM1; -} - -void OPPROTO op_addl_T1_T2(void) -{ - T1 += T2; -} - -void OPPROTO op_subl_T1_T2(void) -{ - T1 -= T2; -} - -void OPPROTO op_addl_T0_T1(void) -{ - T0 += T1; -} - -void OPPROTO op_addl_T0_T1_cc(void) -{ - unsigned int src1; - src1 = T0; - T0 += T1; - env->NZF = T0; - env->CF = T0 < src1; - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); -} - -void OPPROTO op_adcl_T0_T1(void) -{ - T0 += T1 + env->CF; -} - -void OPPROTO op_adcl_T0_T1_cc(void) -{ - unsigned int src1; - src1 = T0; - if (!env->CF) { - T0 += T1; - env->CF = T0 < src1; - } else { - T0 += T1 + 1; - env->CF = T0 <= src1; - } - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); - env->NZF = T0; - FORCE_RET(); -} - -#define OPSUB(sub, sbc, res, T0, T1) \ - \ -void OPPROTO op_ ## sub ## l_T0_T1(void) \ -{ \ - res = T0 - T1; \ -} \ - \ -void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ -{ \ - unsigned int src1; \ - src1 = T0; \ - T0 -= T1; \ - env->NZF = T0; \ - env->CF = src1 >= T1; \ - env->VF = (src1 ^ T1) & (src1 ^ T0); \ - res = T0; \ -} \ - \ -void OPPROTO op_ ## sbc ## l_T0_T1(void) \ -{ \ - res = T0 - T1 + env->CF - 1; \ -} \ - \ -void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ -{ \ - unsigned int src1; \ - src1 = T0; \ - if (!env->CF) { \ - T0 = T0 - T1 - 1; \ - env->CF = src1 >= T1; \ - } else { \ - T0 = T0 - T1; \ - env->CF = src1 > T1; \ - } \ - env->VF = (src1 ^ T1) & (src1 ^ T0); \ - env->NZF = T0; \ - res = T0; \ - FORCE_RET(); \ -} - -OPSUB(sub, sbc, T0, T0, T1) - -OPSUB(rsb, rsc, T0, T1, T0) - -void OPPROTO op_andl_T0_T1(void) -{ - T0 &= T1; -} - -void OPPROTO op_xorl_T0_T1(void) -{ - T0 ^= T1; -} - -void OPPROTO op_orl_T0_T1(void) -{ - T0 |= T1; -} - -void OPPROTO op_bicl_T0_T1(void) -{ - T0 &= ~T1; -} - -void OPPROTO op_notl_T1(void) -{ - T1 = ~T1; -} - -void OPPROTO op_logic_T0_cc(void) -{ - env->NZF = T0; -} - -void OPPROTO op_logic_T1_cc(void) -{ - env->NZF = T1; -} - -#define EIP (env->regs[15]) - -void OPPROTO op_test_eq(void) -{ - if (env->NZF == 0) - JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_ne(void) -{ - if (env->NZF != 0) - JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_cs(void) -{ - if (env->CF != 0) - JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_cc(void) -{ - if (env->CF == 0) - JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_mi(void) -{ - if ((env->NZF & 0x80000000) != 0) - JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_pl(void) -{ - if ((env->NZF & 0x80000000) == 0) - JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_vs(void) -{ - if ((env->VF & 0x80000000) != 0) - JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_vc(void) -{ - if ((env->VF & 0x80000000) == 0) - JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_hi(void) -{ - if (env->CF != 0 && env->NZF != 0) - JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_ls(void) -{ - if (env->CF == 0 || env->NZF == 0) - JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_ge(void) -{ - if (((env->VF ^ env->NZF) & 0x80000000) == 0) - JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_lt(void) -{ - if (((env->VF ^ env->NZF) & 0x80000000) != 0) - JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_gt(void) -{ - if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) - JUMP_TB(op_test_gt, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_test_le(void) -{ - if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) - JUMP_TB(op_test_le, PARAM1, 0, PARAM2); - FORCE_RET(); -} - -void OPPROTO op_jmp(void) -{ - JUMP_TB(op_jmp, PARAM1, 1, PARAM2); -} - -void OPPROTO op_exit_tb(void) -{ - EXIT_TB(); -} - -void OPPROTO op_movl_T0_psr(void) -{ - T0 = compute_cpsr(); -} - -/* NOTE: N = 1 and Z = 1 cannot be stored currently */ -void OPPROTO op_movl_psr_T0(void) -{ - unsigned int psr; - psr = T0; - env->CF = (psr >> 29) & 1; - env->NZF = (psr & 0xc0000000) ^ 0x40000000; - env->VF = (psr << 3) & 0x80000000; - /* for user mode we do not update other state info */ -} - -void OPPROTO op_mul_T0_T1(void) -{ - T0 = T0 * T1; -} - -/* 64 bit unsigned mul */ -void OPPROTO op_mull_T0_T1(void) -{ - uint64_t res; - res = T0 * T1; - T1 = res >> 32; - T0 = res; -} - -/* 64 bit signed mul */ -void OPPROTO op_imull_T0_T1(void) -{ - uint64_t res; - res = (int32_t)T0 * (int32_t)T1; - T1 = res >> 32; - T0 = res; -} - -void OPPROTO op_addq_T0_T1(void) -{ - uint64_t res; - res = ((uint64_t)T1 << 32) | T0; - res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); - T1 = res >> 32; - T0 = res; -} - -void OPPROTO op_logicq_cc(void) -{ - env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); -} - -/* memory access */ - -void OPPROTO op_ldub_T0_T1(void) -{ - T0 = ldub((void *)T1); -} - -void OPPROTO op_ldsb_T0_T1(void) -{ - T0 = ldsb((void *)T1); -} - -void OPPROTO op_lduw_T0_T1(void) -{ - T0 = lduw((void *)T1); -} - -void OPPROTO op_ldsw_T0_T1(void) -{ - T0 = ldsw((void *)T1); -} - -void OPPROTO op_ldl_T0_T1(void) -{ - T0 = ldl((void *)T1); -} - -void OPPROTO op_stb_T0_T1(void) -{ - stb((void *)T1, T0); -} - -void OPPROTO op_stw_T0_T1(void) -{ - stw((void *)T1, T0); -} - -void OPPROTO op_stl_T0_T1(void) -{ - stl((void *)T1, T0); -} - -void OPPROTO op_swpb_T0_T1(void) -{ - int tmp; - - cpu_lock(); - tmp = ldub((void *)T1); - stb((void *)T1, T0); - T0 = tmp; - cpu_unlock(); -} - -void OPPROTO op_swpl_T0_T1(void) -{ - int tmp; - - cpu_lock(); - tmp = ldl((void *)T1); - stl((void *)T1, T0); - T0 = tmp; - cpu_unlock(); -} - -/* shifts */ - -/* T1 based */ -void OPPROTO op_shll_T1_im(void) -{ - T1 = T1 << PARAM1; -} - -void OPPROTO op_shrl_T1_im(void) -{ - T1 = (uint32_t)T1 >> PARAM1; -} - -void OPPROTO op_sarl_T1_im(void) -{ - T1 = (int32_t)T1 >> PARAM1; -} - -void OPPROTO op_rorl_T1_im(void) -{ - int shift; - shift = PARAM1; - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); -} - -/* T1 based, set C flag */ -void OPPROTO op_shll_T1_im_cc(void) -{ - env->CF = (T1 >> (32 - PARAM1)) & 1; - T1 = T1 << PARAM1; -} - -void OPPROTO op_shrl_T1_im_cc(void) -{ - env->CF = (T1 >> (PARAM1 - 1)) & 1; - T1 = (uint32_t)T1 >> PARAM1; -} - -void OPPROTO op_sarl_T1_im_cc(void) -{ - env->CF = (T1 >> (PARAM1 - 1)) & 1; - T1 = (int32_t)T1 >> PARAM1; -} - -void OPPROTO op_rorl_T1_im_cc(void) -{ - int shift; - shift = PARAM1; - env->CF = (T1 >> (shift - 1)) & 1; - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); -} - -/* T2 based */ -void OPPROTO op_shll_T2_im(void) -{ - T2 = T2 << PARAM1; -} - -void OPPROTO op_shrl_T2_im(void) -{ - T2 = (uint32_t)T2 >> PARAM1; -} - -void OPPROTO op_sarl_T2_im(void) -{ - T2 = (int32_t)T2 >> PARAM1; -} - -void OPPROTO op_rorl_T2_im(void) -{ - int shift; - shift = PARAM1; - T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); -} - -/* T1 based, use T0 as shift count */ - -void OPPROTO op_shll_T1_T0(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) - T1 = 0; - else - T1 = T1 << shift; - FORCE_RET(); -} - -void OPPROTO op_shrl_T1_T0(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) - T1 = 0; - else - T1 = (uint32_t)T1 >> shift; - FORCE_RET(); -} - -void OPPROTO op_sarl_T1_T0(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) - shift = 31; - T1 = (int32_t)T1 >> shift; -} - -void OPPROTO op_rorl_T1_T0(void) -{ - int shift; - shift = T0 & 0x1f; - if (shift) { - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); - } - FORCE_RET(); -} - -/* T1 based, use T0 as shift count and compute CF */ - -void OPPROTO op_shll_T1_T0_cc(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) { - if (shift == 32) - env->CF = T1 & 1; - else - env->CF = 0; - T1 = 0; - } else if (shift != 0) { - env->CF = (T1 >> (32 - shift)) & 1; - T1 = T1 << shift; - } - FORCE_RET(); -} - -void OPPROTO op_shrl_T1_T0_cc(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) { - if (shift == 32) - env->CF = (T1 >> 31) & 1; - else - env->CF = 0; - T1 = 0; - } else if (shift != 0) { - env->CF = (T1 >> (shift - 1)) & 1; - T1 = (uint32_t)T1 >> shift; - } - FORCE_RET(); -} - -void OPPROTO op_sarl_T1_T0_cc(void) -{ - int shift; - shift = T0 & 0xff; - if (shift >= 32) { - env->CF = (T1 >> 31) & 1; - T1 = (int32_t)T1 >> 31; - } else { - env->CF = (T1 >> (shift - 1)) & 1; - T1 = (int32_t)T1 >> shift; - } - FORCE_RET(); -} - -void OPPROTO op_rorl_T1_T0_cc(void) -{ - int shift1, shift; - shift1 = T0 & 0xff; - shift = shift1 & 0x1f; - if (shift == 0) { - if (shift1 != 0) - env->CF = (T1 >> 31) & 1; - } else { - env->CF = (T1 >> (shift - 1)) & 1; - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); - } - FORCE_RET(); -} - -/* exceptions */ - -void OPPROTO op_swi(void) -{ - env->exception_index = EXCP_SWI; - cpu_loop_exit(); -} - -void OPPROTO op_undef_insn(void) -{ - env->exception_index = EXCP_UDEF; - cpu_loop_exit(); -} - -/* thread support */ - -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; - -void cpu_lock(void) -{ - spin_lock(&global_cpu_lock); -} - -void cpu_unlock(void) -{ - spin_unlock(&global_cpu_lock); -} - diff --git a/op-i386.c b/op-i386.c deleted file mode 100644 index 16521c93b..000000000 --- a/op-i386.c +++ /dev/null @@ -1,2054 +0,0 @@ -/* - * i386 micro operations - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "exec-i386.h" - -/* n must be a constant to be efficient */ -static inline int lshift(int x, int n) -{ - if (n >= 0) - return x << n; - else - return x >> (-n); -} - -/* we define the various pieces of code used by the JIT */ - -#define REG EAX -#define REGNAME _EAX -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG ECX -#define REGNAME _ECX -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG EDX -#define REGNAME _EDX -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG EBX -#define REGNAME _EBX -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG ESP -#define REGNAME _ESP -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG EBP -#define REGNAME _EBP -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG ESI -#define REGNAME _ESI -#include "opreg_template.h" -#undef REG -#undef REGNAME - -#define REG EDI -#define REGNAME _EDI -#include "opreg_template.h" -#undef REG -#undef REGNAME - -/* operations with flags */ - -/* update flags with T0 and T1 (add/sub case) */ -void OPPROTO op_update2_cc(void) -{ - CC_SRC = T1; - CC_DST = T0; -} - -/* update flags with T0 (logic operation case) */ -void OPPROTO op_update1_cc(void) -{ - CC_DST = T0; -} - -void OPPROTO op_update_neg_cc(void) -{ - CC_SRC = -T0; - CC_DST = T0; -} - -void OPPROTO op_cmpl_T0_T1_cc(void) -{ - CC_SRC = T1; - CC_DST = T0 - T1; -} - -void OPPROTO op_update_inc_cc(void) -{ - CC_SRC = cc_table[CC_OP].compute_c(); - CC_DST = T0; -} - -void OPPROTO op_testl_T0_T1_cc(void) -{ - CC_DST = T0 & T1; -} - -/* operations without flags */ - -void OPPROTO op_addl_T0_T1(void) -{ - T0 += T1; -} - -void OPPROTO op_orl_T0_T1(void) -{ - T0 |= T1; -} - -void OPPROTO op_andl_T0_T1(void) -{ - T0 &= T1; -} - -void OPPROTO op_subl_T0_T1(void) -{ - T0 -= T1; -} - -void OPPROTO op_xorl_T0_T1(void) -{ - T0 ^= T1; -} - -void OPPROTO op_negl_T0(void) -{ - T0 = -T0; -} - -void OPPROTO op_incl_T0(void) -{ - T0++; -} - -void OPPROTO op_decl_T0(void) -{ - T0--; -} - -void OPPROTO op_notl_T0(void) -{ - T0 = ~T0; -} - -void OPPROTO op_bswapl_T0(void) -{ - T0 = bswap32(T0); -} - -/* multiply/divide */ -void OPPROTO op_mulb_AL_T0(void) -{ - unsigned int res; - res = (uint8_t)EAX * (uint8_t)T0; - EAX = (EAX & 0xffff0000) | res; - CC_SRC = (res & 0xff00); -} - -void OPPROTO op_imulb_AL_T0(void) -{ - int res; - res = (int8_t)EAX * (int8_t)T0; - EAX = (EAX & 0xffff0000) | (res & 0xffff); - CC_SRC = (res != (int8_t)res); -} - -void OPPROTO op_mulw_AX_T0(void) -{ - unsigned int res; - res = (uint16_t)EAX * (uint16_t)T0; - EAX = (EAX & 0xffff0000) | (res & 0xffff); - EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); - CC_SRC = res >> 16; -} - -void OPPROTO op_imulw_AX_T0(void) -{ - int res; - res = (int16_t)EAX * (int16_t)T0; - EAX = (EAX & 0xffff0000) | (res & 0xffff); - EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); - CC_SRC = (res != (int16_t)res); -} - -void OPPROTO op_mull_EAX_T0(void) -{ - uint64_t res; - res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0); - EAX = res; - EDX = res >> 32; - CC_SRC = res >> 32; -} - -void OPPROTO op_imull_EAX_T0(void) -{ - int64_t res; - res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0); - EAX = res; - EDX = res >> 32; - CC_SRC = (res != (int32_t)res); -} - -void OPPROTO op_imulw_T0_T1(void) -{ - int res; - res = (int16_t)T0 * (int16_t)T1; - T0 = res; - CC_SRC = (res != (int16_t)res); -} - -void OPPROTO op_imull_T0_T1(void) -{ - int64_t res; - res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); - T0 = res; - CC_SRC = (res != (int32_t)res); -} - -/* division, flags are undefined */ -/* XXX: add exceptions for overflow */ - -void OPPROTO op_divb_AL_T0(void) -{ - unsigned int num, den, q, r; - - num = (EAX & 0xffff); - den = (T0 & 0xff); - if (den == 0) { - EIP = PARAM1; - raise_exception(EXCP00_DIVZ); - } - q = (num / den) & 0xff; - r = (num % den) & 0xff; - EAX = (EAX & 0xffff0000) | (r << 8) | q; -} - -void OPPROTO op_idivb_AL_T0(void) -{ - int num, den, q, r; - - num = (int16_t)EAX; - den = (int8_t)T0; - if (den == 0) { - EIP = PARAM1; - raise_exception(EXCP00_DIVZ); - } - q = (num / den) & 0xff; - r = (num % den) & 0xff; - EAX = (EAX & 0xffff0000) | (r << 8) | q; -} - -void OPPROTO op_divw_AX_T0(void) -{ - unsigned int num, den, q, r; - - num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); - den = (T0 & 0xffff); - if (den == 0) { - EIP = PARAM1; - raise_exception(EXCP00_DIVZ); - } - q = (num / den) & 0xffff; - r = (num % den) & 0xffff; - EAX = (EAX & 0xffff0000) | q; - EDX = (EDX & 0xffff0000) | r; -} - -void OPPROTO op_idivw_AX_T0(void) -{ - int num, den, q, r; - - num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); - den = (int16_t)T0; - if (den == 0) { - EIP = PARAM1; - raise_exception(EXCP00_DIVZ); - } - q = (num / den) & 0xffff; - r = (num % den) & 0xffff; - EAX = (EAX & 0xffff0000) | q; - EDX = (EDX & 0xffff0000) | r; -} - -void OPPROTO op_divl_EAX_T0(void) -{ - helper_divl_EAX_T0(PARAM1); -} - -void OPPROTO op_idivl_EAX_T0(void) -{ - helper_idivl_EAX_T0(PARAM1); -} - -/* constant load & misc op */ - -void OPPROTO op_movl_T0_im(void) -{ - T0 = PARAM1; -} - -void OPPROTO op_addl_T0_im(void) -{ - T0 += PARAM1; -} - -void OPPROTO op_andl_T0_ffff(void) -{ - T0 = T0 & 0xffff; -} - -void OPPROTO op_andl_T0_im(void) -{ - T0 = T0 & PARAM1; -} - -void OPPROTO op_movl_T0_T1(void) -{ - T0 = T1; -} - -void OPPROTO op_movl_T1_im(void) -{ - T1 = PARAM1; -} - -void OPPROTO op_addl_T1_im(void) -{ - T1 += PARAM1; -} - -void OPPROTO op_movl_T1_A0(void) -{ - T1 = A0; -} - -void OPPROTO op_movl_A0_im(void) -{ - A0 = PARAM1; -} - -void OPPROTO op_addl_A0_im(void) -{ - A0 += PARAM1; -} - -void OPPROTO op_addl_A0_AL(void) -{ - A0 += (EAX & 0xff); -} - -void OPPROTO op_andl_A0_ffff(void) -{ - A0 = A0 & 0xffff; -} - -/* memory access */ - -#define MEMSUFFIX -#include "ops_mem.h" - -#define MEMSUFFIX _user -#include "ops_mem.h" - -#define MEMSUFFIX _kernel -#include "ops_mem.h" - -/* used for bit operations */ - -void OPPROTO op_add_bitw_A0_T1(void) -{ - A0 += ((int32_t)T1 >> 4) << 1; -} - -void OPPROTO op_add_bitl_A0_T1(void) -{ - A0 += ((int32_t)T1 >> 5) << 2; -} - -/* indirect jump */ - -void OPPROTO op_jmp_T0(void) -{ - EIP = T0; -} - -void OPPROTO op_jmp_im(void) -{ - EIP = PARAM1; -} - -void OPPROTO op_hlt(void) -{ - env->exception_index = EXCP_HLT; - cpu_loop_exit(); -} - -void OPPROTO op_debug(void) -{ - env->exception_index = EXCP_DEBUG; - cpu_loop_exit(); -} - -void OPPROTO op_raise_interrupt(void) -{ - int intno; - unsigned int next_eip; - intno = PARAM1; - next_eip = PARAM2; - raise_interrupt(intno, 1, 0, next_eip); -} - -void OPPROTO op_raise_exception(void) -{ - int exception_index; - exception_index = PARAM1; - raise_exception(exception_index); -} - -void OPPROTO op_into(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if (eflags & CC_O) { - raise_interrupt(EXCP04_INTO, 1, 0, PARAM1); - } - FORCE_RET(); -} - -void OPPROTO op_cli(void) -{ - env->eflags &= ~IF_MASK; -} - -void OPPROTO op_sti(void) -{ - env->eflags |= IF_MASK; -} - -void OPPROTO op_set_inhibit_irq(void) -{ - env->hflags |= HF_INHIBIT_IRQ_MASK; -} - -void OPPROTO op_reset_inhibit_irq(void) -{ - env->hflags &= ~HF_INHIBIT_IRQ_MASK; -} - -#if 0 -/* vm86plus instructions */ -void OPPROTO op_cli_vm(void) -{ - env->eflags &= ~VIF_MASK; -} - -void OPPROTO op_sti_vm(void) -{ - env->eflags |= VIF_MASK; - if (env->eflags & VIP_MASK) { - EIP = PARAM1; - raise_exception(EXCP0D_GPF); - } - FORCE_RET(); -} -#endif - -void OPPROTO op_boundw(void) -{ - int low, high, v; - low = ldsw((uint8_t *)A0); - high = ldsw((uint8_t *)A0 + 2); - v = (int16_t)T0; - if (v < low || v > high) { - EIP = PARAM1; - raise_exception(EXCP05_BOUND); - } - FORCE_RET(); -} - -void OPPROTO op_boundl(void) -{ - int low, high, v; - low = ldl((uint8_t *)A0); - high = ldl((uint8_t *)A0 + 4); - v = T0; - if (v < low || v > high) { - EIP = PARAM1; - raise_exception(EXCP05_BOUND); - } - FORCE_RET(); -} - -void OPPROTO op_cmpxchg8b(void) -{ - helper_cmpxchg8b(); -} - -void OPPROTO op_jmp(void) -{ - JUMP_TB(op_jmp, PARAM1, 0, PARAM2); -} - -void OPPROTO op_movl_T0_0(void) -{ - T0 = 0; -} - -void OPPROTO op_exit_tb(void) -{ - EXIT_TB(); -} - -/* multiple size ops */ - -#define ldul ldl - -#define SHIFT 0 -#include "ops_template.h" -#undef SHIFT - -#define SHIFT 1 -#include "ops_template.h" -#undef SHIFT - -#define SHIFT 2 -#include "ops_template.h" -#undef SHIFT - -/* sign extend */ - -void OPPROTO op_movsbl_T0_T0(void) -{ - T0 = (int8_t)T0; -} - -void OPPROTO op_movzbl_T0_T0(void) -{ - T0 = (uint8_t)T0; -} - -void OPPROTO op_movswl_T0_T0(void) -{ - T0 = (int16_t)T0; -} - -void OPPROTO op_movzwl_T0_T0(void) -{ - T0 = (uint16_t)T0; -} - -void OPPROTO op_movswl_EAX_AX(void) -{ - EAX = (int16_t)EAX; -} - -void OPPROTO op_movsbw_AX_AL(void) -{ - EAX = (EAX & 0xffff0000) | ((int8_t)EAX & 0xffff); -} - -void OPPROTO op_movslq_EDX_EAX(void) -{ - EDX = (int32_t)EAX >> 31; -} - -void OPPROTO op_movswl_DX_AX(void) -{ - EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff); -} - -/* string ops helpers */ - -void OPPROTO op_addl_ESI_T0(void) -{ - ESI += T0; -} - -void OPPROTO op_addw_ESI_T0(void) -{ - ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff); -} - -void OPPROTO op_addl_EDI_T0(void) -{ - EDI += T0; -} - -void OPPROTO op_addw_EDI_T0(void) -{ - EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff); -} - -void OPPROTO op_decl_ECX(void) -{ - ECX--; -} - -void OPPROTO op_decw_ECX(void) -{ - ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff); -} - -/* push/pop */ - -void op_pushl_T0(void) -{ - uint32_t offset; - offset = ESP - 4; - stl((void *)offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = offset; -} - -void op_pushw_T0(void) -{ - uint32_t offset; - offset = ESP - 2; - stw((void *)offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = offset; -} - -void op_pushl_ss32_T0(void) -{ - uint32_t offset; - offset = ESP - 4; - stl(env->segs[R_SS].base + offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = offset; -} - -void op_pushw_ss32_T0(void) -{ - uint32_t offset; - offset = ESP - 2; - stw(env->segs[R_SS].base + offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = offset; -} - -void op_pushl_ss16_T0(void) -{ - uint32_t offset; - offset = (ESP - 4) & 0xffff; - stl(env->segs[R_SS].base + offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = (ESP & ~0xffff) | offset; -} - -void op_pushw_ss16_T0(void) -{ - uint32_t offset; - offset = (ESP - 2) & 0xffff; - stw(env->segs[R_SS].base + offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = (ESP & ~0xffff) | offset; -} - -/* NOTE: ESP update is done after */ -void op_popl_T0(void) -{ - T0 = ldl((void *)ESP); -} - -void op_popw_T0(void) -{ - T0 = lduw((void *)ESP); -} - -void op_popl_ss32_T0(void) -{ - T0 = ldl(env->segs[R_SS].base + ESP); -} - -void op_popw_ss32_T0(void) -{ - T0 = lduw(env->segs[R_SS].base + ESP); -} - -void op_popl_ss16_T0(void) -{ - T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff)); -} - -void op_popw_ss16_T0(void) -{ - T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff)); -} - -void op_addl_ESP_4(void) -{ - ESP += 4; -} - -void op_addl_ESP_2(void) -{ - ESP += 2; -} - -void op_addw_ESP_4(void) -{ - ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff); -} - -void op_addw_ESP_2(void) -{ - ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff); -} - -void op_addl_ESP_im(void) -{ - ESP += PARAM1; -} - -void op_addw_ESP_im(void) -{ - ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff); -} - -void OPPROTO op_rdtsc(void) -{ - helper_rdtsc(); -} - -void OPPROTO op_cpuid(void) -{ - helper_cpuid(); -} - -void OPPROTO op_rdmsr(void) -{ - helper_rdmsr(); -} - -void OPPROTO op_wrmsr(void) -{ - helper_wrmsr(); -} - -/* bcd */ - -/* XXX: exception */ -void OPPROTO op_aam(void) -{ - int base = PARAM1; - int al, ah; - al = EAX & 0xff; - ah = al / base; - al = al % base; - EAX = (EAX & ~0xffff) | al | (ah << 8); - CC_DST = al; -} - -void OPPROTO op_aad(void) -{ - int base = PARAM1; - int al, ah; - al = EAX & 0xff; - ah = (EAX >> 8) & 0xff; - al = ((ah * base) + al) & 0xff; - EAX = (EAX & ~0xffff) | al; - CC_DST = al; -} - -void OPPROTO op_aaa(void) -{ - int icarry; - int al, ah, af; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - af = eflags & CC_A; - al = EAX & 0xff; - ah = (EAX >> 8) & 0xff; - - icarry = (al > 0xf9); - if (((al & 0x0f) > 9 ) || af) { - al = (al + 6) & 0x0f; - ah = (ah + 1 + icarry) & 0xff; - eflags |= CC_C | CC_A; - } else { - eflags &= ~(CC_C | CC_A); - al &= 0x0f; - } - EAX = (EAX & ~0xffff) | al | (ah << 8); - CC_SRC = eflags; -} - -void OPPROTO op_aas(void) -{ - int icarry; - int al, ah, af; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - af = eflags & CC_A; - al = EAX & 0xff; - ah = (EAX >> 8) & 0xff; - - icarry = (al < 6); - if (((al & 0x0f) > 9 ) || af) { - al = (al - 6) & 0x0f; - ah = (ah - 1 - icarry) & 0xff; - eflags |= CC_C | CC_A; - } else { - eflags &= ~(CC_C | CC_A); - al &= 0x0f; - } - EAX = (EAX & ~0xffff) | al | (ah << 8); - CC_SRC = eflags; -} - -void OPPROTO op_daa(void) -{ - int al, af, cf; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - cf = eflags & CC_C; - af = eflags & CC_A; - al = EAX & 0xff; - - eflags = 0; - if (((al & 0x0f) > 9 ) || af) { - al = (al + 6) & 0xff; - eflags |= CC_A; - } - if ((al > 0x9f) || cf) { - al = (al + 0x60) & 0xff; - eflags |= CC_C; - } - EAX = (EAX & ~0xff) | al; - /* well, speed is not an issue here, so we compute the flags by hand */ - eflags |= (al == 0) << 6; /* zf */ - eflags |= parity_table[al]; /* pf */ - eflags |= (al & 0x80); /* sf */ - CC_SRC = eflags; -} - -void OPPROTO op_das(void) -{ - int al, al1, af, cf; - int eflags; - - eflags = cc_table[CC_OP].compute_all(); - cf = eflags & CC_C; - af = eflags & CC_A; - al = EAX & 0xff; - - eflags = 0; - al1 = al; - if (((al & 0x0f) > 9 ) || af) { - eflags |= CC_A; - if (al < 6 || cf) - eflags |= CC_C; - al = (al - 6) & 0xff; - } - if ((al1 > 0x99) || cf) { - al = (al - 0x60) & 0xff; - eflags |= CC_C; - } - EAX = (EAX & ~0xff) | al; - /* well, speed is not an issue here, so we compute the flags by hand */ - eflags |= (al == 0) << 6; /* zf */ - eflags |= parity_table[al]; /* pf */ - eflags |= (al & 0x80); /* sf */ - CC_SRC = eflags; -} - -/* segment handling */ - -/* never use it with R_CS */ -void OPPROTO op_movl_seg_T0(void) -{ - load_seg(PARAM1, T0 & 0xffff, PARAM2); -} - -/* faster VM86 version */ -void OPPROTO op_movl_seg_T0_vm(void) -{ - int selector; - SegmentCache *sc; - - selector = T0 & 0xffff; - /* env->segs[] access */ - sc = (SegmentCache *)((char *)env + PARAM1); - sc->selector = selector; - sc->base = (void *)(selector << 4); -} - -void OPPROTO op_movl_T0_seg(void) -{ - T0 = env->segs[PARAM1].selector; -} - -void OPPROTO op_movl_A0_seg(void) -{ - A0 = *(unsigned long *)((char *)env + PARAM1); -} - -void OPPROTO op_addl_A0_seg(void) -{ - A0 += *(unsigned long *)((char *)env + PARAM1); -} - -void OPPROTO op_lsl(void) -{ - helper_lsl(); -} - -void OPPROTO op_lar(void) -{ - helper_lar(); -} - -/* T0: segment, T1:eip */ -void OPPROTO op_ljmp_protected_T0_T1(void) -{ - helper_ljmp_protected_T0_T1(); -} - -void OPPROTO op_lcall_real_T0_T1(void) -{ - helper_lcall_real_T0_T1(PARAM1, PARAM2); -} - -void OPPROTO op_lcall_protected_T0_T1(void) -{ - helper_lcall_protected_T0_T1(PARAM1, PARAM2); -} - -void OPPROTO op_iret_real(void) -{ - helper_iret_real(PARAM1); -} - -void OPPROTO op_iret_protected(void) -{ - helper_iret_protected(PARAM1); -} - -void OPPROTO op_lret_protected(void) -{ - helper_lret_protected(PARAM1, PARAM2); -} - -void OPPROTO op_lldt_T0(void) -{ - helper_lldt_T0(); -} - -void OPPROTO op_ltr_T0(void) -{ - helper_ltr_T0(); -} - -/* CR registers access */ -void OPPROTO op_movl_crN_T0(void) -{ - helper_movl_crN_T0(PARAM1); -} - -/* DR registers access */ -void OPPROTO op_movl_drN_T0(void) -{ - helper_movl_drN_T0(PARAM1); -} - -void OPPROTO op_lmsw_T0(void) -{ - /* only 4 lower bits of CR0 are modified */ - T0 = (env->cr[0] & ~0xf) | (T0 & 0xf); - helper_movl_crN_T0(0); -} - -void OPPROTO op_invlpg_A0(void) -{ - helper_invlpg(A0); -} - -void OPPROTO op_movl_T0_env(void) -{ - T0 = *(uint32_t *)((char *)env + PARAM1); -} - -void OPPROTO op_movl_env_T0(void) -{ - *(uint32_t *)((char *)env + PARAM1) = T0; -} - -void OPPROTO op_movl_env_T1(void) -{ - *(uint32_t *)((char *)env + PARAM1) = T1; -} - -void OPPROTO op_clts(void) -{ - env->cr[0] &= ~CR0_TS_MASK; -} - -/* flags handling */ - -/* slow jumps cases : in order to avoid calling a function with a - pointer (which can generate a stack frame on PowerPC), we use - op_setcc to set T0 and then call op_jcc. */ -void OPPROTO op_jcc(void) -{ - if (T0) - JUMP_TB(op_jcc, PARAM1, 0, PARAM2); - else - JUMP_TB(op_jcc, PARAM1, 1, PARAM3); - FORCE_RET(); -} - -void OPPROTO op_jcc_im(void) -{ - if (T0) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -/* slow set cases (compute x86 flags) */ -void OPPROTO op_seto_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags >> 11) & 1; -} - -void OPPROTO op_setb_T0_cc(void) -{ - T0 = cc_table[CC_OP].compute_c(); -} - -void OPPROTO op_setz_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags >> 6) & 1; -} - -void OPPROTO op_setbe_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags & (CC_Z | CC_C)) != 0; -} - -void OPPROTO op_sets_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags >> 7) & 1; -} - -void OPPROTO op_setp_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (eflags >> 2) & 1; -} - -void OPPROTO op_setl_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = ((eflags ^ (eflags >> 4)) >> 7) & 1; -} - -void OPPROTO op_setle_T0_cc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - T0 = (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) != 0; -} - -void OPPROTO op_xor_T0_1(void) -{ - T0 ^= 1; -} - -void OPPROTO op_set_cc_op(void) -{ - CC_OP = PARAM1; -} - -#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff) - -void OPPROTO op_movl_eflags_T0(void) -{ - int eflags; - eflags = T0; - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | - (eflags & FL_UPDATE_MASK32); -} - -void OPPROTO op_movw_eflags_T0(void) -{ - int eflags; - eflags = T0; - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | - (eflags & FL_UPDATE_MASK16); -} - -void OPPROTO op_movl_eflags_T0_cpl0(void) -{ - load_eflags(T0, FL_UPDATE_CPL0_MASK); -} - -void OPPROTO op_movw_eflags_T0_cpl0(void) -{ - load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff); -} - -#if 0 -/* vm86plus version */ -void OPPROTO op_movw_eflags_T0_vm(void) -{ - int eflags; - eflags = T0; - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) | - (eflags & FL_UPDATE_MASK16); - if (eflags & IF_MASK) { - env->eflags |= VIF_MASK; - if (env->eflags & VIP_MASK) { - EIP = PARAM1; - raise_exception(EXCP0D_GPF); - } - } - FORCE_RET(); -} - -void OPPROTO op_movl_eflags_T0_vm(void) -{ - int eflags; - eflags = T0; - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) | - (eflags & FL_UPDATE_MASK32); - if (eflags & IF_MASK) { - env->eflags |= VIF_MASK; - if (env->eflags & VIP_MASK) { - EIP = PARAM1; - raise_exception(EXCP0D_GPF); - } - } - FORCE_RET(); -} -#endif - -/* XXX: compute only O flag */ -void OPPROTO op_movb_eflags_T0(void) -{ - int of; - of = cc_table[CC_OP].compute_all() & CC_O; - CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of; -} - -void OPPROTO op_movl_T0_eflags(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags |= (DF & DF_MASK); - eflags |= env->eflags & ~(VM_MASK | RF_MASK); - T0 = eflags; -} - -/* vm86plus version */ -#if 0 -void OPPROTO op_movl_T0_eflags_vm(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags |= (DF & DF_MASK); - eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); - if (env->eflags & VIF_MASK) - eflags |= IF_MASK; - T0 = eflags; -} -#endif - -void OPPROTO op_cld(void) -{ - DF = 1; -} - -void OPPROTO op_std(void) -{ - DF = -1; -} - -void OPPROTO op_clc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags &= ~CC_C; - CC_SRC = eflags; -} - -void OPPROTO op_stc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags |= CC_C; - CC_SRC = eflags; -} - -void OPPROTO op_cmc(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags ^= CC_C; - CC_SRC = eflags; -} - -void OPPROTO op_salc(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - EAX = (EAX & ~0xff) | ((-cf) & 0xff); -} - -static int compute_all_eflags(void) -{ - return CC_SRC; -} - -static int compute_c_eflags(void) -{ - return CC_SRC & CC_C; -} - -static int compute_c_mul(void) -{ - int cf; - cf = (CC_SRC != 0); - return cf; -} - -static int compute_all_mul(void) -{ - int cf, pf, af, zf, sf, of; - cf = (CC_SRC != 0); - pf = 0; /* undefined */ - af = 0; /* undefined */ - zf = 0; /* undefined */ - sf = 0; /* undefined */ - of = cf << 11; - return cf | pf | af | zf | sf | of; -} - -CCTable cc_table[CC_OP_NB] = { - [CC_OP_DYNAMIC] = { /* should never happen */ }, - - [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags }, - - [CC_OP_MUL] = { compute_all_mul, compute_c_mul }, - - [CC_OP_ADDB] = { compute_all_addb, compute_c_addb }, - [CC_OP_ADDW] = { compute_all_addw, compute_c_addw }, - [CC_OP_ADDL] = { compute_all_addl, compute_c_addl }, - - [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb }, - [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw }, - [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl }, - - [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, - [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, - [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, - - [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb }, - [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw }, - [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl }, - - [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, - [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, - [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, - - [CC_OP_INCB] = { compute_all_incb, compute_c_incl }, - [CC_OP_INCW] = { compute_all_incw, compute_c_incl }, - [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, - - [CC_OP_DECB] = { compute_all_decb, compute_c_incl }, - [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, - [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, - - [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, - [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, - [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, - - [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl }, - [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl }, - [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl }, -}; - -/* floating point support. Some of the code for complicated x87 - functions comes from the LGPL'ed x86 emulator found in the Willows - TWIN windows emulator. */ - -#if defined(__powerpc__) -extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble); - -/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ -double qemu_rint(double x) -{ - double y = 4503599627370496.0; - if (fabs(x) >= y) - return x; - if (x < 0) - y = -y; - y = (x + y) - y; - if (y == 0.0) - y = copysign(y, x); - return y; -} - -#define rint qemu_rint -#endif - -/* fp load FT0 */ - -void OPPROTO op_flds_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldl((void *)A0); - FT0 = FP_CONVERT.f; -#else - FT0 = ldfl((void *)A0); -#endif -} - -void OPPROTO op_fldl_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i64 = ldq((void *)A0); - FT0 = FP_CONVERT.d; -#else - FT0 = ldfq((void *)A0); -#endif -} - -/* helpers are needed to avoid static constant reference. XXX: find a better way */ -#ifdef USE_INT_TO_FLOAT_HELPERS - -void helper_fild_FT0_A0(void) -{ - FT0 = (CPU86_LDouble)ldsw((void *)A0); -} - -void helper_fildl_FT0_A0(void) -{ - FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); -} - -void helper_fildll_FT0_A0(void) -{ - FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); -} - -void OPPROTO op_fild_FT0_A0(void) -{ - helper_fild_FT0_A0(); -} - -void OPPROTO op_fildl_FT0_A0(void) -{ - helper_fildl_FT0_A0(); -} - -void OPPROTO op_fildll_FT0_A0(void) -{ - helper_fildll_FT0_A0(); -} - -#else - -void OPPROTO op_fild_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldsw((void *)A0); - FT0 = (CPU86_LDouble)FP_CONVERT.i32; -#else - FT0 = (CPU86_LDouble)ldsw((void *)A0); -#endif -} - -void OPPROTO op_fildl_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = (int32_t) ldl((void *)A0); - FT0 = (CPU86_LDouble)FP_CONVERT.i32; -#else - FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); -#endif -} - -void OPPROTO op_fildll_FT0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.i64 = (int64_t) ldq((void *)A0); - FT0 = (CPU86_LDouble)FP_CONVERT.i64; -#else - FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); -#endif -} -#endif - -/* fp load ST0 */ - -void OPPROTO op_flds_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldl((void *)A0); - env->fpregs[new_fpstt] = FP_CONVERT.f; -#else - env->fpregs[new_fpstt] = ldfl((void *)A0); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fldl_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i64 = ldq((void *)A0); - env->fpregs[new_fpstt] = FP_CONVERT.d; -#else - env->fpregs[new_fpstt] = ldfq((void *)A0); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -#ifdef USE_X86LDOUBLE -void OPPROTO op_fldt_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = *(long double *)A0; - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} -#else -void OPPROTO op_fldt_ST0_A0(void) -{ - helper_fldt_ST0_A0(); -} -#endif - -/* helpers are needed to avoid static constant reference. XXX: find a better way */ -#ifdef USE_INT_TO_FLOAT_HELPERS - -void helper_fild_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void helper_fildl_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void helper_fildll_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fild_ST0_A0(void) -{ - helper_fild_ST0_A0(); -} - -void OPPROTO op_fildl_ST0_A0(void) -{ - helper_fildl_ST0_A0(); -} - -void OPPROTO op_fildll_ST0_A0(void) -{ - helper_fildll_ST0_A0(); -} - -#else - -void OPPROTO op_fild_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldsw((void *)A0); - env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; -#else - env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fildl_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i32 = (int32_t) ldl((void *)A0); - env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; -#else - env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -void OPPROTO op_fildll_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; -#ifdef USE_FP_CONVERT - FP_CONVERT.i64 = (int64_t) ldq((void *)A0); - env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64; -#else - env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); -#endif - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} - -#endif - -/* fp store */ - -void OPPROTO op_fsts_ST0_A0(void) -{ -#ifdef USE_FP_CONVERT - FP_CONVERT.f = (float)ST0; - stfl((void *)A0, FP_CONVERT.f); -#else - stfl((void *)A0, (float)ST0); -#endif -} - -void OPPROTO op_fstl_ST0_A0(void) -{ - stfq((void *)A0, (double)ST0); -} - -#ifdef USE_X86LDOUBLE -void OPPROTO op_fstt_ST0_A0(void) -{ - *(long double *)A0 = ST0; -} -#else -void OPPROTO op_fstt_ST0_A0(void) -{ - helper_fstt_ST0_A0(); -} -#endif - -void OPPROTO op_fist_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int val; - - d = ST0; - val = lrint(d); - if (val != (int16_t)val) - val = -32768; - stw((void *)A0, val); -} - -void OPPROTO op_fistl_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int val; - - d = ST0; - val = lrint(d); - stl((void *)A0, val); -} - -void OPPROTO op_fistll_ST0_A0(void) -{ -#if defined(__sparc__) && !defined(__sparc_v9__) - register CPU86_LDouble d asm("o0"); -#else - CPU86_LDouble d; -#endif - int64_t val; - - d = ST0; - val = llrint(d); - stq((void *)A0, val); -} - -void OPPROTO op_fbld_ST0_A0(void) -{ - helper_fbld_ST0_A0(); -} - -void OPPROTO op_fbst_ST0_A0(void) -{ - helper_fbst_ST0_A0(); -} - -/* FPU move */ - -void OPPROTO op_fpush(void) -{ - fpush(); -} - -void OPPROTO op_fpop(void) -{ - fpop(); -} - -void OPPROTO op_fdecstp(void) -{ - env->fpstt = (env->fpstt - 1) & 7; - env->fpus &= (~0x4700); -} - -void OPPROTO op_fincstp(void) -{ - env->fpstt = (env->fpstt + 1) & 7; - env->fpus &= (~0x4700); -} - -void OPPROTO op_fmov_ST0_FT0(void) -{ - ST0 = FT0; -} - -void OPPROTO op_fmov_FT0_STN(void) -{ - FT0 = ST(PARAM1); -} - -void OPPROTO op_fmov_ST0_STN(void) -{ - ST0 = ST(PARAM1); -} - -void OPPROTO op_fmov_STN_ST0(void) -{ - ST(PARAM1) = ST0; -} - -void OPPROTO op_fxchg_ST0_STN(void) -{ - CPU86_LDouble tmp; - tmp = ST(PARAM1); - ST(PARAM1) = ST0; - ST0 = tmp; -} - -/* FPU operations */ - -/* XXX: handle nans */ -void OPPROTO op_fcom_ST0_FT0(void) -{ - env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ - if (ST0 < FT0) - env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ - else if (ST0 == FT0) - env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ - FORCE_RET(); -} - -/* XXX: handle nans */ -void OPPROTO op_fucom_ST0_FT0(void) -{ - env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ - if (ST0 < FT0) - env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ - else if (ST0 == FT0) - env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ - FORCE_RET(); -} - -/* XXX: handle nans */ -void OPPROTO op_fcomi_ST0_FT0(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags &= ~(CC_Z | CC_P | CC_C); - if (ST0 < FT0) - eflags |= CC_C; - else if (ST0 == FT0) - eflags |= CC_Z; - CC_SRC = eflags; - FORCE_RET(); -} - -/* XXX: handle nans */ -void OPPROTO op_fucomi_ST0_FT0(void) -{ - int eflags; - eflags = cc_table[CC_OP].compute_all(); - eflags &= ~(CC_Z | CC_P | CC_C); - if (ST0 < FT0) - eflags |= CC_C; - else if (ST0 == FT0) - eflags |= CC_Z; - CC_SRC = eflags; - FORCE_RET(); -} - -void OPPROTO op_fadd_ST0_FT0(void) -{ - ST0 += FT0; -} - -void OPPROTO op_fmul_ST0_FT0(void) -{ - ST0 *= FT0; -} - -void OPPROTO op_fsub_ST0_FT0(void) -{ - ST0 -= FT0; -} - -void OPPROTO op_fsubr_ST0_FT0(void) -{ - ST0 = FT0 - ST0; -} - -void OPPROTO op_fdiv_ST0_FT0(void) -{ - ST0 /= FT0; -} - -void OPPROTO op_fdivr_ST0_FT0(void) -{ - ST0 = FT0 / ST0; -} - -/* fp operations between STN and ST0 */ - -void OPPROTO op_fadd_STN_ST0(void) -{ - ST(PARAM1) += ST0; -} - -void OPPROTO op_fmul_STN_ST0(void) -{ - ST(PARAM1) *= ST0; -} - -void OPPROTO op_fsub_STN_ST0(void) -{ - ST(PARAM1) -= ST0; -} - -void OPPROTO op_fsubr_STN_ST0(void) -{ - CPU86_LDouble *p; - p = &ST(PARAM1); - *p = ST0 - *p; -} - -void OPPROTO op_fdiv_STN_ST0(void) -{ - ST(PARAM1) /= ST0; -} - -void OPPROTO op_fdivr_STN_ST0(void) -{ - CPU86_LDouble *p; - p = &ST(PARAM1); - *p = ST0 / *p; -} - -/* misc FPU operations */ -void OPPROTO op_fchs_ST0(void) -{ - ST0 = -ST0; -} - -void OPPROTO op_fabs_ST0(void) -{ - ST0 = fabs(ST0); -} - -void OPPROTO op_fxam_ST0(void) -{ - helper_fxam_ST0(); -} - -void OPPROTO op_fld1_ST0(void) -{ - ST0 = f15rk[1]; -} - -void OPPROTO op_fldl2t_ST0(void) -{ - ST0 = f15rk[6]; -} - -void OPPROTO op_fldl2e_ST0(void) -{ - ST0 = f15rk[5]; -} - -void OPPROTO op_fldpi_ST0(void) -{ - ST0 = f15rk[2]; -} - -void OPPROTO op_fldlg2_ST0(void) -{ - ST0 = f15rk[3]; -} - -void OPPROTO op_fldln2_ST0(void) -{ - ST0 = f15rk[4]; -} - -void OPPROTO op_fldz_ST0(void) -{ - ST0 = f15rk[0]; -} - -void OPPROTO op_fldz_FT0(void) -{ - ST0 = f15rk[0]; -} - -/* associated heplers to reduce generated code length and to simplify - relocation (FP constants are usually stored in .rodata section) */ - -void OPPROTO op_f2xm1(void) -{ - helper_f2xm1(); -} - -void OPPROTO op_fyl2x(void) -{ - helper_fyl2x(); -} - -void OPPROTO op_fptan(void) -{ - helper_fptan(); -} - -void OPPROTO op_fpatan(void) -{ - helper_fpatan(); -} - -void OPPROTO op_fxtract(void) -{ - helper_fxtract(); -} - -void OPPROTO op_fprem1(void) -{ - helper_fprem1(); -} - - -void OPPROTO op_fprem(void) -{ - helper_fprem(); -} - -void OPPROTO op_fyl2xp1(void) -{ - helper_fyl2xp1(); -} - -void OPPROTO op_fsqrt(void) -{ - helper_fsqrt(); -} - -void OPPROTO op_fsincos(void) -{ - helper_fsincos(); -} - -void OPPROTO op_frndint(void) -{ - helper_frndint(); -} - -void OPPROTO op_fscale(void) -{ - helper_fscale(); -} - -void OPPROTO op_fsin(void) -{ - helper_fsin(); -} - -void OPPROTO op_fcos(void) -{ - helper_fcos(); -} - -void OPPROTO op_fnstsw_A0(void) -{ - int fpus; - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - stw((void *)A0, fpus); -} - -void OPPROTO op_fnstsw_EAX(void) -{ - int fpus; - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - EAX = (EAX & 0xffff0000) | fpus; -} - -void OPPROTO op_fnstcw_A0(void) -{ - stw((void *)A0, env->fpuc); -} - -void OPPROTO op_fldcw_A0(void) -{ - int rnd_type; - env->fpuc = lduw((void *)A0); - /* set rounding mode */ - switch(env->fpuc & RC_MASK) { - default: - case RC_NEAR: - rnd_type = FE_TONEAREST; - break; - case RC_DOWN: - rnd_type = FE_DOWNWARD; - break; - case RC_UP: - rnd_type = FE_UPWARD; - break; - case RC_CHOP: - rnd_type = FE_TOWARDZERO; - break; - } - fesetround(rnd_type); -} - -void OPPROTO op_fclex(void) -{ - env->fpus &= 0x7f00; -} - -void OPPROTO op_fninit(void) -{ - env->fpus = 0; - env->fpstt = 0; - env->fpuc = 0x37f; - env->fptags[0] = 1; - env->fptags[1] = 1; - env->fptags[2] = 1; - env->fptags[3] = 1; - env->fptags[4] = 1; - env->fptags[5] = 1; - env->fptags[6] = 1; - env->fptags[7] = 1; -} - -void OPPROTO op_fnstenv_A0(void) -{ - helper_fstenv((uint8_t *)A0, PARAM1); -} - -void OPPROTO op_fldenv_A0(void) -{ - helper_fldenv((uint8_t *)A0, PARAM1); -} - -void OPPROTO op_fnsave_A0(void) -{ - helper_fsave((uint8_t *)A0, PARAM1); -} - -void OPPROTO op_frstor_A0(void) -{ - helper_frstor((uint8_t *)A0, PARAM1); -} - -/* threading support */ -void OPPROTO op_lock(void) -{ - cpu_lock(); -} - -void OPPROTO op_unlock(void) -{ - cpu_unlock(); -} - diff --git a/opreg_template.h b/opreg_template.h deleted file mode 100644 index f35a1bbc9..000000000 --- a/opreg_template.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * i386 micro operations (templates for various register related - * operations) - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -void OPPROTO glue(op_movl_A0,REGNAME)(void) -{ - A0 = REG; -} - -void OPPROTO glue(op_addl_A0,REGNAME)(void) -{ - A0 += REG; -} - -void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void) -{ - A0 += REG << 1; -} - -void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void) -{ - A0 += REG << 2; -} - -void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void) -{ - A0 += REG << 3; -} - -void OPPROTO glue(op_movl_T0,REGNAME)(void) -{ - T0 = REG; -} - -void OPPROTO glue(op_movl_T1,REGNAME)(void) -{ - T1 = REG; -} - -void OPPROTO glue(op_movh_T0,REGNAME)(void) -{ - T0 = REG >> 8; -} - -void OPPROTO glue(op_movh_T1,REGNAME)(void) -{ - T1 = REG >> 8; -} - -void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void) -{ - REG = T0; -} - -void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void) -{ - REG = T1; -} - -void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) -{ - REG = A0; -} - -/* mov T1 to REG if T0 is true */ -void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void) -{ - if (T0) - REG = (REG & 0xffff0000) | (T1 & 0xffff); -} - -void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void) -{ - if (T0) - REG = T1; -} - -/* NOTE: T0 high order bits are ignored */ -void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) -{ - REG = (REG & 0xffff0000) | (T0 & 0xffff); -} - -/* NOTE: T0 high order bits are ignored */ -void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void) -{ - REG = (REG & 0xffff0000) | (T1 & 0xffff); -} - -/* NOTE: A0 high order bits are ignored */ -void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void) -{ - REG = (REG & 0xffff0000) | (A0 & 0xffff); -} - -/* NOTE: T0 high order bits are ignored */ -void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void) -{ - REG = (REG & 0xffffff00) | (T0 & 0xff); -} - -/* NOTE: T0 high order bits are ignored */ -void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void) -{ - REG = (REG & 0xffff00ff) | ((T0 & 0xff) << 8); -} - -/* NOTE: T1 high order bits are ignored */ -void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void) -{ - REG = (REG & 0xffffff00) | (T1 & 0xff); -} - -/* NOTE: T1 high order bits are ignored */ -void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void) -{ - REG = (REG & 0xffff00ff) | ((T1 & 0xff) << 8); -} diff --git a/ops_mem.h b/ops_mem.h deleted file mode 100644 index e1c8277bb..000000000 --- a/ops_mem.h +++ /dev/null @@ -1,66 +0,0 @@ -void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(ldub, MEMSUFFIX)((uint8_t *)A0); -} - -void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(ldsb, MEMSUFFIX)((int8_t *)A0); -} - -void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(lduw, MEMSUFFIX)((uint8_t *)A0); -} - -void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(ldsw, MEMSUFFIX)((int8_t *)A0); -} - -void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void) -{ - T0 = glue(ldl, MEMSUFFIX)((uint8_t *)A0); -} - -void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(ldub, MEMSUFFIX)((uint8_t *)A0); -} - -void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(ldsb, MEMSUFFIX)((int8_t *)A0); -} - -void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(lduw, MEMSUFFIX)((uint8_t *)A0); -} - -void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(ldsw, MEMSUFFIX)((int8_t *)A0); -} - -void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void) -{ - T1 = glue(ldl, MEMSUFFIX)((uint8_t *)A0); -} - -void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void) -{ - glue(stb, MEMSUFFIX)((uint8_t *)A0, T0); -} - -void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void) -{ - glue(stw, MEMSUFFIX)((uint8_t *)A0, T0); -} - -void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void) -{ - glue(stl, MEMSUFFIX)((uint8_t *)A0, T0); -} - -#undef MEMSUFFIX diff --git a/ops_template.h b/ops_template.h deleted file mode 100644 index 182296743..000000000 --- a/ops_template.h +++ /dev/null @@ -1,617 +0,0 @@ -/* - * i386 micro operations (included several times to generate - * different operand sizes) - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#define DATA_BITS (1 << (3 + SHIFT)) -#define SHIFT_MASK (DATA_BITS - 1) -#define SIGN_MASK (1 << (DATA_BITS - 1)) - -#if DATA_BITS == 8 -#define SUFFIX b -#define DATA_TYPE uint8_t -#define DATA_STYPE int8_t -#define DATA_MASK 0xff -#elif DATA_BITS == 16 -#define SUFFIX w -#define DATA_TYPE uint16_t -#define DATA_STYPE int16_t -#define DATA_MASK 0xffff -#elif DATA_BITS == 32 -#define SUFFIX l -#define DATA_TYPE uint32_t -#define DATA_STYPE int32_t -#define DATA_MASK 0xffffffff -#else -#error unhandled operand size -#endif - -/* dynamic flags computation */ - -static int glue(compute_all_add, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_SRC; - src2 = CC_DST - CC_SRC; - cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_add, SUFFIX)(void) -{ - int src1, cf; - src1 = CC_SRC; - cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; - return cf; -} - -static int glue(compute_all_adc, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_SRC; - src2 = CC_DST - CC_SRC - 1; - cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_adc, SUFFIX)(void) -{ - int src1, cf; - src1 = CC_SRC; - cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; - return cf; -} - -static int glue(compute_all_sub, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_sub, SUFFIX)(void) -{ - int src1, src2, cf; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; - return cf; -} - -static int glue(compute_all_sbb, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_DST + CC_SRC + 1; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_sbb, SUFFIX)(void) -{ - int src1, src2, cf; - src1 = CC_DST + CC_SRC + 1; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; - return cf; -} - -static int glue(compute_all_logic, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - cf = 0; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = 0; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_logic, SUFFIX)(void) -{ - return 0; -} - -static int glue(compute_all_inc, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_DST - 1; - src2 = 1; - cf = CC_SRC; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; - return cf | pf | af | zf | sf | of; -} - -#if DATA_BITS == 32 -static int glue(compute_c_inc, SUFFIX)(void) -{ - return CC_SRC; -} -#endif - -static int glue(compute_all_dec, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - int src1, src2; - src1 = CC_DST + 1; - src2 = 1; - cf = CC_SRC; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_all_shl, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - /* of is defined if shift count == 1 */ - of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -static int glue(compute_c_shl, SUFFIX)(void) -{ - return (CC_SRC >> (DATA_BITS - 1)) & CC_C; -} - -#if DATA_BITS == 32 -static int glue(compute_c_sar, SUFFIX)(void) -{ - return CC_SRC & 1; -} -#endif - -static int glue(compute_all_sar, SUFFIX)(void) -{ - int cf, pf, af, zf, sf, of; - cf = CC_SRC & 1; - pf = parity_table[(uint8_t)CC_DST]; - af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - /* of is defined if shift count == 1 */ - of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; - return cf | pf | af | zf | sf | of; -} - -/* various optimized jumps cases */ - -void OPPROTO glue(op_jb_sub, SUFFIX)(void) -{ - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - if ((DATA_TYPE)src1 < (DATA_TYPE)src2) - JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 1, PARAM3); - FORCE_RET(); -} - -void OPPROTO glue(op_jz_sub, SUFFIX)(void) -{ - if ((DATA_TYPE)CC_DST == 0) - JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 1, PARAM3); - FORCE_RET(); -} - -void OPPROTO glue(op_jbe_sub, SUFFIX)(void) -{ - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) - JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 1, PARAM3); - FORCE_RET(); -} - -void OPPROTO glue(op_js_sub, SUFFIX)(void) -{ - if (CC_DST & SIGN_MASK) - JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 1, PARAM3); - FORCE_RET(); -} - -void OPPROTO glue(op_jl_sub, SUFFIX)(void) -{ - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - if ((DATA_STYPE)src1 < (DATA_STYPE)src2) - JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 1, PARAM3); - FORCE_RET(); -} - -void OPPROTO glue(op_jle_sub, SUFFIX)(void) -{ - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) - JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 1, PARAM3); - FORCE_RET(); -} - -/* oldies */ - -#if DATA_BITS >= 16 - -void OPPROTO glue(op_loopnz, SUFFIX)(void) -{ - unsigned int tmp; - int eflags; - eflags = cc_table[CC_OP].compute_all(); - tmp = (ECX - 1) & DATA_MASK; - ECX = (ECX & ~DATA_MASK) | tmp; - if (tmp != 0 && !(eflags & CC_Z)) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO glue(op_loopz, SUFFIX)(void) -{ - unsigned int tmp; - int eflags; - eflags = cc_table[CC_OP].compute_all(); - tmp = (ECX - 1) & DATA_MASK; - ECX = (ECX & ~DATA_MASK) | tmp; - if (tmp != 0 && (eflags & CC_Z)) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO glue(op_loop, SUFFIX)(void) -{ - unsigned int tmp; - tmp = (ECX - 1) & DATA_MASK; - ECX = (ECX & ~DATA_MASK) | tmp; - if (tmp != 0) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -void OPPROTO glue(op_jecxz, SUFFIX)(void) -{ - if ((DATA_TYPE)ECX == 0) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); -} - -#endif - -/* various optimized set cases */ - -void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) -{ - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2); -} - -void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) -{ - T0 = ((DATA_TYPE)CC_DST == 0); -} - -void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) -{ - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2); -} - -void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void) -{ - T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1; -} - -void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) -{ - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2); -} - -void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) -{ - int src1, src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - - T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2); -} - -/* shifts */ - -void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & 0x1f; - T0 = T0 << count; - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & 0x1f; - T0 &= DATA_MASK; - T0 = T0 >> count; - FORCE_RET(); -} - -void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) -{ - int count, src; - count = T1 & 0x1f; - src = (DATA_STYPE)T0; - T0 = src >> count; - FORCE_RET(); -} - -#undef MEM_WRITE -#include "ops_template_mem.h" - -#define MEM_WRITE -#include "ops_template_mem.h" - -/* bit operations */ -#if DATA_BITS >= 16 - -void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & SHIFT_MASK; - CC_SRC = T0 >> count; -} - -void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & SHIFT_MASK; - T1 = T0 >> count; - T0 |= (1 << count); -} - -void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & SHIFT_MASK; - T1 = T0 >> count; - T0 &= ~(1 << count); -} - -void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) -{ - int count; - count = T1 & SHIFT_MASK; - T1 = T0 >> count; - T0 ^= (1 << count); -} - -void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) -{ - int res, count; - res = T0 & DATA_MASK; - if (res != 0) { - count = 0; - while ((res & 1) == 0) { - count++; - res >>= 1; - } - T0 = count; - CC_DST = 1; /* ZF = 1 */ - } else { - CC_DST = 0; /* ZF = 1 */ - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) -{ - int res, count; - res = T0 & DATA_MASK; - if (res != 0) { - count = DATA_BITS - 1; - while ((res & SIGN_MASK) == 0) { - count--; - res <<= 1; - } - T0 = count; - CC_DST = 1; /* ZF = 1 */ - } else { - CC_DST = 0; /* ZF = 1 */ - } - FORCE_RET(); -} - -#endif - -#if DATA_BITS == 32 -void OPPROTO op_update_bt_cc(void) -{ - CC_SRC = T1; -} -#endif - -/* string operations */ - -void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) -{ - T0 = DF << SHIFT; -} - -void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) -{ - if ((DATA_TYPE)CC_DST == 0) - JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 1); - FORCE_RET(); -} - -void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) -{ - if ((DATA_TYPE)CC_DST != 0) - JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_string_jz_sub, SUFFIX), _im)(void) -{ - if ((DATA_TYPE)CC_DST == 0) { - EIP = PARAM1; - if (env->eflags & TF_MASK) { - raise_exception(EXCP01_SSTP); - } - T0 = 0; - EXIT_TB(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_string_jnz_sub, SUFFIX), _im)(void) -{ - if ((DATA_TYPE)CC_DST != 0) { - EIP = PARAM1; - if (env->eflags & TF_MASK) { - raise_exception(EXCP01_SSTP); - } - T0 = 0; - EXIT_TB(); - } - FORCE_RET(); -} - -#if DATA_BITS >= 16 -void OPPROTO glue(op_jz_ecx, SUFFIX)(void) -{ - if ((DATA_TYPE)ECX == 0) - JUMP_TB(glue(op_jz_ecx, SUFFIX), PARAM1, 1, PARAM2); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void) -{ - if ((DATA_TYPE)ECX == 0) { - EIP = PARAM1; - if (env->eflags & TF_MASK) { - raise_exception(EXCP01_SSTP); - } - T0 = 0; - EXIT_TB(); - } - FORCE_RET(); -} -#endif - -/* port I/O */ - -void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) -{ - glue(cpu_x86_out, SUFFIX)(env, T0 & 0xffff, T1 & DATA_MASK); -} - -void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) -{ - T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff); -} - -void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void) -{ - T0 = glue(cpu_x86_in, SUFFIX)(env, EDX & 0xffff); -} - -void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void) -{ - glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0); -} - -#undef DATA_BITS -#undef SHIFT_MASK -#undef SIGN_MASK -#undef DATA_TYPE -#undef DATA_STYPE -#undef DATA_MASK -#undef SUFFIX diff --git a/ops_template_mem.h b/ops_template_mem.h deleted file mode 100644 index eacaabba5..000000000 --- a/ops_template_mem.h +++ /dev/null @@ -1,429 +0,0 @@ -/* - * i386 micro operations (included several times to generate - * different operand sizes) - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifdef MEM_WRITE - -#if DATA_BITS == 8 -#define MEM_SUFFIX b_mem -#elif DATA_BITS == 16 -#define MEM_SUFFIX w_mem -#elif DATA_BITS == 32 -#define MEM_SUFFIX l_mem -#endif - -#else - -#define MEM_SUFFIX SUFFIX - -#endif - -void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & SHIFT_MASK; - if (count) { - src = T0; - T0 &= DATA_MASK; - T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#else - /* gcc 3.2 workaround. This is really a bug in gcc. */ - asm volatile("" : : "r" (T0)); -#endif - CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - (T0 & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & SHIFT_MASK; - if (count) { - src = T0; - T0 &= DATA_MASK; - T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#else - /* gcc 3.2 workaround. This is really a bug in gcc. */ - asm volatile("" : : "r" (T0)); -#endif - CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((T0 >> (DATA_BITS - 1)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT_MASK; - if (count) { - T0 &= DATA_MASK; - T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) -{ - int count; - count = T1 & SHIFT_MASK; - if (count) { - T0 &= DATA_MASK; - T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, res, eflags; - unsigned int src; - - count = T1 & 0x1f; -#if DATA_BITS == 16 - count = rclw_table[count]; -#elif DATA_BITS == 8 - count = rclb_table[count]; -#endif - if (count) { - eflags = cc_table[CC_OP].compute_all(); - T0 &= DATA_MASK; - src = T0; - res = (T0 << count) | ((eflags & CC_C) << (count - 1)); - if (count > 1) - res |= T0 >> (DATA_BITS + 1 - count); - T0 = res; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((src >> (DATA_BITS - count)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, res, eflags; - unsigned int src; - - count = T1 & 0x1f; -#if DATA_BITS == 16 - count = rclw_table[count]; -#elif DATA_BITS == 8 - count = rclb_table[count]; -#endif - if (count) { - eflags = cc_table[CC_OP].compute_all(); - T0 &= DATA_MASK; - src = T0; - res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); - if (count > 1) - res |= T0 << (DATA_BITS + 1 - count); - T0 = res; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | - ((src >> (count - 1)) & CC_C); - CC_OP = CC_OP_EFLAGS; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & 0x1f; - if (count) { - src = (DATA_TYPE)T0 << (count - 1); - T0 = T0 << count; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = src; - CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & 0x1f; - if (count) { - T0 &= DATA_MASK; - src = T0 >> (count - 1); - T0 = T0 >> count; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = src; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int count, src; - count = T1 & 0x1f; - if (count) { - src = (DATA_STYPE)T0; - T0 = src >> count; - src = src >> (count - 1); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = src; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - -#if DATA_BITS == 16 -/* XXX: overflow flag might be incorrect in some cases in shldw */ -void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - unsigned int res, tmp; - count = PARAM1; - T1 &= 0xffff; - res = T1 | (T0 << 16); - tmp = res >> (32 - count); - res <<= count; - if (count > 16) - res |= T1 << (count - 16); - T0 = res >> 16; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; -} - -void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - unsigned int res, tmp; - count = ECX & 0x1f; - if (count) { - T1 &= 0xffff; - res = T1 | (T0 << 16); - tmp = res >> (32 - count); - res <<= count; - if (count > 16) - res |= T1 << (count - 16); - T0 = res >> 16; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) -{ - int count; - unsigned int res, tmp; - - count = PARAM1; - res = (T0 & 0xffff) | (T1 << 16); - tmp = res >> (count - 1); - res >>= count; - if (count > 16) - res |= T1 << (32 - count); - T0 = res; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; -} - - -void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count; - unsigned int res, tmp; - - count = ECX & 0x1f; - if (count) { - res = (T0 & 0xffff) | (T1 << 16); - tmp = res >> (count - 1); - res >>= count; - if (count > 16) - res |= T1 << (32 - count); - T0 = res; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} -#endif - -#if DATA_BITS == 32 -void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) -{ - int count, tmp; - count = PARAM1; - T0 &= DATA_MASK; - T1 &= DATA_MASK; - tmp = T0 << (count - 1); - T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; -} - -void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count, tmp; - count = ECX & 0x1f; - if (count) { - T0 &= DATA_MASK; - T1 &= DATA_MASK; - tmp = T0 << (count - 1); - T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; - CC_OP = CC_OP_SHLB + SHIFT; - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) -{ - int count, tmp; - count = PARAM1; - T0 &= DATA_MASK; - T1 &= DATA_MASK; - tmp = T0 >> (count - 1); - T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; -} - - -void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) -{ - int count, tmp; - count = ECX & 0x1f; - if (count) { - T0 &= DATA_MASK; - T1 &= DATA_MASK; - tmp = T0 >> (count - 1); - T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = tmp; - CC_DST = T0; - CC_OP = CC_OP_SARB + SHIFT; - } - FORCE_RET(); -} -#endif - -/* carry add/sub (we only need to set CC_OP differently) */ - -void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 + T1 + cf; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = T1; - CC_DST = T0; - CC_OP = CC_OP_ADDB + SHIFT + cf * 3; -} - -void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) -{ - int cf; - cf = cc_table[CC_OP].compute_c(); - T0 = T0 - T1 - cf; -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = T1; - CC_DST = T0; - CC_OP = CC_OP_SUBB + SHIFT + cf * 3; -} - -void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) -{ - unsigned int src, dst; - - src = T0; - dst = EAX - T0; - if ((DATA_TYPE)dst == 0) { - T0 = T1; - } else { - EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); - } -#ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); -#endif - CC_SRC = src; - CC_DST = dst; - FORCE_RET(); -} - -#undef MEM_SUFFIX -#undef MEM_WRITE diff --git a/qemu-mkcow.c b/qemu-mkcow.c new file mode 100644 index 000000000..2cc6332e7 --- /dev/null +++ b/qemu-mkcow.c @@ -0,0 +1,143 @@ +/* + * create a COW disk image + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vl.h" + +#include "bswap.h" + +int cow_create(int cow_fd, const char *image_filename, + int64_t image_sectors) +{ + struct cow_header_v2 cow_header; + int fd; + struct stat st; + + memset(&cow_header, 0, sizeof(cow_header)); + cow_header.magic = htonl(COW_MAGIC); + cow_header.version = htonl(COW_VERSION); + if (image_filename) { + fd = open(image_filename, O_RDONLY); + if (fd < 0) { + perror(image_filename); + exit(1); + } + image_sectors = lseek64(fd, 0, SEEK_END); + if (fstat(fd, &st) != 0) { + close(fd); + return -1; + } + close(fd); + image_sectors /= 512; + cow_header.mtime = htonl(st.st_mtime); + realpath(image_filename, cow_header.backing_file); + } + cow_header.sectorsize = htonl(512); + cow_header.size = image_sectors * 512; +#ifndef WORDS_BIGENDIAN + cow_header.size = bswap64(cow_header.size); +#endif + write(cow_fd, &cow_header, sizeof(cow_header)); + /* resize to include at least all the bitmap */ + ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); + lseek(cow_fd, 0, SEEK_SET); + return 0; +} + +void help(void) +{ + printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + "usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n" + "Create a Copy On Write disk image from an optional raw disk image\n" + "\n" + "-f disk_image set the raw disk image name\n" + "cow_image the created cow_image\n" + "cow_size the create cow_image size in MB if no raw disk image is used\n" + "\n" + "Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n" + ); + exit(1); +} + +int main(int argc, char **argv) +{ + const char *image_filename, *cow_filename; + int cow_fd, c, nb_args; + int64_t image_size; + + image_filename = NULL; + image_size = 0; + for(;;) { + c = getopt(argc, argv, "hf:"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 'f': + image_filename = optarg; + break; + } + } + if (!image_filename) + nb_args = 2; + else + nb_args = 1; + if (optind + nb_args != argc) + help(); + + cow_filename = argv[optind]; + if (nb_args == 2) { + image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024; + } + + cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (!cow_fd < 0) + return -1; + if (cow_create(cow_fd, image_filename, image_size) < 0) { + fprintf(stderr, "%s: error while formating\n", cow_filename); + exit(1); + } + close(cow_fd); + return 0; +} diff --git a/syscall-arm.h b/syscall-arm.h deleted file mode 100644 index 34153c998..000000000 --- a/syscall-arm.h +++ /dev/null @@ -1,28 +0,0 @@ - -/* this struct defines the way the registers are stored on the - stack during a system call. */ - -struct target_pt_regs { - target_long uregs[18]; -}; - -#define ARM_cpsr uregs[16] -#define ARM_pc uregs[15] -#define ARM_lr uregs[14] -#define ARM_sp uregs[13] -#define ARM_ip uregs[12] -#define ARM_fp uregs[11] -#define ARM_r10 uregs[10] -#define ARM_r9 uregs[9] -#define ARM_r8 uregs[8] -#define ARM_r7 uregs[7] -#define ARM_r6 uregs[6] -#define ARM_r5 uregs[5] -#define ARM_r4 uregs[4] -#define ARM_r3 uregs[3] -#define ARM_r2 uregs[2] -#define ARM_r1 uregs[1] -#define ARM_r0 uregs[0] -#define ARM_ORIG_r0 uregs[17] - -#define ARM_SYSCALL_BASE 0x900000 diff --git a/syscall-i386.h b/syscall-i386.h deleted file mode 100644 index e1f470d78..000000000 --- a/syscall-i386.h +++ /dev/null @@ -1,220 +0,0 @@ -/* default linux values for the selectors */ -#define __USER_CS (0x23) -#define __USER_DS (0x2B) - -struct target_pt_regs { - long ebx; - long ecx; - long edx; - long esi; - long edi; - long ebp; - long eax; - int xds; - int xes; - long orig_eax; - long eip; - int xcs; - long eflags; - long esp; - int xss; -}; - -/* ioctls */ - -#define TARGET_LDT_ENTRIES 8192 -#define TARGET_LDT_ENTRY_SIZE 8 - -#define TARGET_GDT_ENTRY_TLS_ENTRIES 3 -#define TARGET_GDT_ENTRY_TLS_MIN 6 -#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1) - -struct target_modify_ldt_ldt_s { - unsigned int entry_number; - target_ulong base_addr; - unsigned int limit; - unsigned int flags; -}; - -/* vm86 defines */ - -#define TARGET_BIOSSEG 0x0f000 - -#define TARGET_CPU_086 0 -#define TARGET_CPU_186 1 -#define TARGET_CPU_286 2 -#define TARGET_CPU_386 3 -#define TARGET_CPU_486 4 -#define TARGET_CPU_586 5 - -#define TARGET_VM86_SIGNAL 0 /* return due to signal */ -#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ -#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */ -#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */ - -/* - * Additional return values when invoking new vm86() - */ -#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */ -#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */ - -/* - * function codes when invoking new vm86() - */ -#define TARGET_VM86_PLUS_INSTALL_CHECK 0 -#define TARGET_VM86_ENTER 1 -#define TARGET_VM86_ENTER_NO_BYPASS 2 -#define TARGET_VM86_REQUEST_IRQ 3 -#define TARGET_VM86_FREE_IRQ 4 -#define TARGET_VM86_GET_IRQ_BITS 5 -#define TARGET_VM86_GET_AND_RESET_IRQ 6 - -/* - * This is the stack-layout seen by the user space program when we have - * done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout - * is 'kernel_vm86_regs' (see below). - */ - -struct target_vm86_regs { -/* - * normal regs, with special meaning for the segment descriptors.. - */ - target_long ebx; - target_long ecx; - target_long edx; - target_long esi; - target_long edi; - target_long ebp; - target_long eax; - target_long __null_ds; - target_long __null_es; - target_long __null_fs; - target_long __null_gs; - target_long orig_eax; - target_long eip; - unsigned short cs, __csh; - target_long eflags; - target_long esp; - unsigned short ss, __ssh; -/* - * these are specific to v86 mode: - */ - unsigned short es, __esh; - unsigned short ds, __dsh; - unsigned short fs, __fsh; - unsigned short gs, __gsh; -}; - -struct target_revectored_struct { - target_ulong __map[8]; /* 256 bits */ -}; - -struct target_vm86_struct { - struct target_vm86_regs regs; - target_ulong flags; - target_ulong screen_bitmap; - target_ulong cpu_type; - struct target_revectored_struct int_revectored; - struct target_revectored_struct int21_revectored; -}; - -/* - * flags masks - */ -#define TARGET_VM86_SCREEN_BITMAP 0x0001 - -struct target_vm86plus_info_struct { - target_ulong flags; -#define TARGET_force_return_for_pic (1 << 0) -#define TARGET_vm86dbg_active (1 << 1) /* for debugger */ -#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */ -#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */ - unsigned char vm86dbg_intxxtab[32]; /* for debugger */ -}; - -struct target_vm86plus_struct { - struct target_vm86_regs regs; - target_ulong flags; - target_ulong screen_bitmap; - target_ulong cpu_type; - struct target_revectored_struct int_revectored; - struct target_revectored_struct int21_revectored; - struct target_vm86plus_info_struct vm86plus; -}; - -/* ipcs */ - -#define TARGET_SEMOP 1 -#define TARGET_SEMGET 2 -#define TARGET_SEMCTL 3 -#define TARGET_MSGSND 11 -#define TARGET_MSGRCV 12 -#define TARGET_MSGGET 13 -#define TARGET_MSGCTL 14 -#define TARGET_SHMAT 21 -#define TARGET_SHMDT 22 -#define TARGET_SHMGET 23 -#define TARGET_SHMCTL 24 - -struct target_msgbuf { - int mtype; - char mtext[1]; -}; - -struct target_ipc_kludge { - unsigned int msgp; /* Really (struct msgbuf *) */ - int msgtyp; -}; - -struct target_ipc_perm { - int key; - unsigned short uid; - unsigned short gid; - unsigned short cuid; - unsigned short cgid; - unsigned short mode; - unsigned short seq; -}; - -struct target_msqid_ds { - struct target_ipc_perm msg_perm; - unsigned int msg_first; /* really struct target_msg* */ - unsigned int msg_last; /* really struct target_msg* */ - unsigned int msg_stime; /* really target_time_t */ - unsigned int msg_rtime; /* really target_time_t */ - unsigned int msg_ctime; /* really target_time_t */ - unsigned int wwait; /* really struct wait_queue* */ - unsigned int rwait; /* really struct wait_queue* */ - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - unsigned short msg_lspid; - unsigned short msg_lrpid; -}; - -struct target_shmid_ds { - struct target_ipc_perm shm_perm; - int shm_segsz; - unsigned int shm_atime; /* really target_time_t */ - unsigned int shm_dtime; /* really target_time_t */ - unsigned int shm_ctime; /* really target_time_t */ - unsigned short shm_cpid; - unsigned short shm_lpid; - short shm_nattch; - unsigned short shm_npages; - unsigned long *shm_pages; - void *attaches; /* really struct shm_desc * */ -}; - -#define TARGET_IPC_RMID 0 -#define TARGET_IPC_SET 1 -#define TARGET_IPC_STAT 2 - -union target_semun { - int val; - unsigned int buf; /* really struct semid_ds * */ - unsigned int array; /* really unsigned short * */ - unsigned int __buf; /* really struct seminfo * */ - unsigned int __pad; /* really void* */ -}; - diff --git a/translate-all.c b/translate-all.c new file mode 100644 index 000000000..ff9e037bb --- /dev/null +++ b/translate-all.c @@ -0,0 +1,198 @@ +/* + * Host code generation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include "config.h" + +#define IN_OP_I386 +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +#include "dyngen.h" +#include "op.h" + +uint16_t gen_opc_buf[OPC_BUF_SIZE]; +uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; +uint32_t gen_opc_pc[OPC_BUF_SIZE]; +uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +#if defined(TARGET_I386) +uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; +#endif + +#ifdef DEBUG_DISAS +static const char *op_str[] = { +#define DEF(s, n, copy_size) #s, +#include "opc.h" +#undef DEF +}; + +static uint8_t op_nb_args[] = { +#define DEF(s, n, copy_size) n, +#include "opc.h" +#undef DEF +}; + +void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) +{ + const uint16_t *opc_ptr; + const uint32_t *opparam_ptr; + int c, n, i; + + opc_ptr = opc_buf; + opparam_ptr = opparam_buf; + for(;;) { + c = *opc_ptr++; + n = op_nb_args[c]; + fprintf(logfile, "0x%04x: %s", + (int)(opc_ptr - opc_buf - 1), op_str[c]); + for(i = 0; i < n; i++) { + fprintf(logfile, " 0x%x", opparam_ptr[i]); + } + fprintf(logfile, "\n"); + if (c == INDEX_op_end) + break; + opparam_ptr += n; + } +} + +#endif + +/* return non zero if the very first instruction is invalid so that + the virtual CPU can trigger an exception. + + '*gen_code_size_ptr' contains the size of the generated code (host + code). +*/ +int cpu_gen_code(CPUState *env, TranslationBlock *tb, + int max_code_size, int *gen_code_size_ptr) +{ + uint8_t *gen_code_buf; + int gen_code_size; + + if (gen_intermediate_code(env, tb) < 0) + return -1; + + /* generate machine code */ + tb->tb_next_offset[0] = 0xffff; + tb->tb_next_offset[1] = 0xffff; + gen_code_buf = tb->tc_ptr; +#ifdef USE_DIRECT_JUMP + /* the following two entries are optional (only used for string ops) */ + tb->tb_jmp_offset[2] = 0xffff; + tb->tb_jmp_offset[3] = 0xffff; +#endif + gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, +#ifdef USE_DIRECT_JUMP + tb->tb_jmp_offset, +#else + NULL, +#endif + gen_opc_buf, gen_opparam_buf); + *gen_code_size_ptr = gen_code_size; +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); + disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0); + fprintf(logfile, "\n"); + fflush(logfile); + } +#endif + return 0; +} + +static const unsigned short opc_copy_size[] = { +#define DEF(s, n, copy_size) copy_size, +#include "opc.h" +#undef DEF +}; + +/* The cpu state corresponding to 'searched_pc' is restored. + */ +int cpu_restore_state(TranslationBlock *tb, + CPUState *env, unsigned long searched_pc) +{ + int j, c; + unsigned long tc_ptr; + uint16_t *opc_ptr; + + if (gen_intermediate_code_pc(env, tb) < 0) + return -1; + + /* find opc index corresponding to search_pc */ + tc_ptr = (unsigned long)tb->tc_ptr; + if (searched_pc < tc_ptr) + return -1; + j = 0; + opc_ptr = gen_opc_buf; + for(;;) { + c = *opc_ptr; + if (c == INDEX_op_end) + return -1; + tc_ptr += opc_copy_size[c]; + if (searched_pc < tc_ptr) + break; + opc_ptr++; + } + j = opc_ptr - gen_opc_buf; + /* now find start of instruction before */ + while (gen_opc_instr_start[j] == 0) + j--; +#if defined(TARGET_I386) + { + int cc_op; +#ifdef DEBUG_DISAS + if (loglevel) { + int i; + fprintf(logfile, "RESTORE:\n"); + for(i=0;i<=j; i++) { + if (gen_opc_instr_start[i]) { + fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]); + } + } + fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%lx cs_base=%lx\n", + searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base); + } +#endif + env->eip = gen_opc_pc[j] - tb->cs_base; + cc_op = gen_opc_cc_op[j]; + if (cc_op != CC_OP_DYNAMIC) + env->cc_op = cc_op; + } +#elif defined(TARGET_ARM) + env->regs[15] = gen_opc_pc[j]; +#elif defined(TARGET_SPARC) + env->pc = gen_opc_pc[j]; +#endif + return 0; +} + + diff --git a/translate-arm.c b/translate-arm.c deleted file mode 100644 index bc8be855f..000000000 --- a/translate-arm.c +++ /dev/null @@ -1,903 +0,0 @@ -/* - * ARM translation - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include - -#include "cpu-arm.h" -#include "exec.h" -#include "disas.h" - -/* internal defines */ -typedef struct DisasContext { - uint8_t *pc; - int is_jmp; - struct TranslationBlock *tb; -} DisasContext; - -#define DISAS_JUMP_NEXT 4 - -/* XXX: move that elsewhere */ -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; -extern FILE *logfile; -extern int loglevel; - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc-arm.h" -#undef DEF - NB_OPS, -}; - -#include "gen-op-arm.h" - -typedef void (GenOpFunc)(void); -typedef void (GenOpFunc1)(long); -typedef void (GenOpFunc2)(long, long); -typedef void (GenOpFunc3)(long, long, long); - -static GenOpFunc2 *gen_test_cc[14] = { - gen_op_test_eq, - gen_op_test_ne, - gen_op_test_cs, - gen_op_test_cc, - gen_op_test_mi, - gen_op_test_pl, - gen_op_test_vs, - gen_op_test_vc, - gen_op_test_hi, - gen_op_test_ls, - gen_op_test_ge, - gen_op_test_lt, - gen_op_test_gt, - gen_op_test_le, -}; - -const uint8_t table_logic_cc[16] = { - 1, /* and */ - 1, /* xor */ - 0, /* sub */ - 0, /* rsb */ - 0, /* add */ - 0, /* adc */ - 0, /* sbc */ - 0, /* rsc */ - 1, /* andl */ - 1, /* xorl */ - 0, /* cmp */ - 0, /* cmn */ - 1, /* orr */ - 1, /* mov */ - 1, /* bic */ - 1, /* mvn */ -}; - -static GenOpFunc1 *gen_shift_T1_im[4] = { - gen_op_shll_T1_im, - gen_op_shrl_T1_im, - gen_op_sarl_T1_im, - gen_op_rorl_T1_im, -}; - -static GenOpFunc1 *gen_shift_T2_im[4] = { - gen_op_shll_T2_im, - gen_op_shrl_T2_im, - gen_op_sarl_T2_im, - gen_op_rorl_T2_im, -}; - -static GenOpFunc1 *gen_shift_T1_im_cc[4] = { - gen_op_shll_T1_im_cc, - gen_op_shrl_T1_im_cc, - gen_op_sarl_T1_im_cc, - gen_op_rorl_T1_im_cc, -}; - -static GenOpFunc *gen_shift_T1_T0[4] = { - gen_op_shll_T1_T0, - gen_op_shrl_T1_T0, - gen_op_sarl_T1_T0, - gen_op_rorl_T1_T0, -}; - -static GenOpFunc *gen_shift_T1_T0_cc[4] = { - gen_op_shll_T1_T0_cc, - gen_op_shrl_T1_T0_cc, - gen_op_sarl_T1_T0_cc, - gen_op_rorl_T1_T0_cc, -}; - -static GenOpFunc *gen_op_movl_TN_reg[3][16] = { - { - gen_op_movl_T0_r0, - gen_op_movl_T0_r1, - gen_op_movl_T0_r2, - gen_op_movl_T0_r3, - gen_op_movl_T0_r4, - gen_op_movl_T0_r5, - gen_op_movl_T0_r6, - gen_op_movl_T0_r7, - gen_op_movl_T0_r8, - gen_op_movl_T0_r9, - gen_op_movl_T0_r10, - gen_op_movl_T0_r11, - gen_op_movl_T0_r12, - gen_op_movl_T0_r13, - gen_op_movl_T0_r14, - gen_op_movl_T0_r15, - }, - { - gen_op_movl_T1_r0, - gen_op_movl_T1_r1, - gen_op_movl_T1_r2, - gen_op_movl_T1_r3, - gen_op_movl_T1_r4, - gen_op_movl_T1_r5, - gen_op_movl_T1_r6, - gen_op_movl_T1_r7, - gen_op_movl_T1_r8, - gen_op_movl_T1_r9, - gen_op_movl_T1_r10, - gen_op_movl_T1_r11, - gen_op_movl_T1_r12, - gen_op_movl_T1_r13, - gen_op_movl_T1_r14, - gen_op_movl_T1_r15, - }, - { - gen_op_movl_T2_r0, - gen_op_movl_T2_r1, - gen_op_movl_T2_r2, - gen_op_movl_T2_r3, - gen_op_movl_T2_r4, - gen_op_movl_T2_r5, - gen_op_movl_T2_r6, - gen_op_movl_T2_r7, - gen_op_movl_T2_r8, - gen_op_movl_T2_r9, - gen_op_movl_T2_r10, - gen_op_movl_T2_r11, - gen_op_movl_T2_r12, - gen_op_movl_T2_r13, - gen_op_movl_T2_r14, - gen_op_movl_T2_r15, - }, -}; - -static GenOpFunc *gen_op_movl_reg_TN[2][16] = { - { - gen_op_movl_r0_T0, - gen_op_movl_r1_T0, - gen_op_movl_r2_T0, - gen_op_movl_r3_T0, - gen_op_movl_r4_T0, - gen_op_movl_r5_T0, - gen_op_movl_r6_T0, - gen_op_movl_r7_T0, - gen_op_movl_r8_T0, - gen_op_movl_r9_T0, - gen_op_movl_r10_T0, - gen_op_movl_r11_T0, - gen_op_movl_r12_T0, - gen_op_movl_r13_T0, - gen_op_movl_r14_T0, - gen_op_movl_r15_T0, - }, - { - gen_op_movl_r0_T1, - gen_op_movl_r1_T1, - gen_op_movl_r2_T1, - gen_op_movl_r3_T1, - gen_op_movl_r4_T1, - gen_op_movl_r5_T1, - gen_op_movl_r6_T1, - gen_op_movl_r7_T1, - gen_op_movl_r8_T1, - gen_op_movl_r9_T1, - gen_op_movl_r10_T1, - gen_op_movl_r11_T1, - gen_op_movl_r12_T1, - gen_op_movl_r13_T1, - gen_op_movl_r14_T1, - gen_op_movl_r15_T1, - }, -}; - -static GenOpFunc1 *gen_op_movl_TN_im[3] = { - gen_op_movl_T0_im, - gen_op_movl_T1_im, - gen_op_movl_T2_im, -}; - -static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) -{ - int val; - - if (reg == 15) { - /* normaly, since we updated PC, we need only to add 4 */ - val = (long)s->pc + 4; - gen_op_movl_TN_im[t](val); - } else { - gen_op_movl_TN_reg[t][reg](); - } -} - -static inline void gen_movl_T0_reg(DisasContext *s, int reg) -{ - gen_movl_TN_reg(s, reg, 0); -} - -static inline void gen_movl_T1_reg(DisasContext *s, int reg) -{ - gen_movl_TN_reg(s, reg, 1); -} - -static inline void gen_movl_T2_reg(DisasContext *s, int reg) -{ - gen_movl_TN_reg(s, reg, 2); -} - -static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t) -{ - gen_op_movl_reg_TN[t][reg](); - if (reg == 15) { - s->is_jmp = DISAS_JUMP; - } -} - -static inline void gen_movl_reg_T0(DisasContext *s, int reg) -{ - gen_movl_reg_TN(s, reg, 0); -} - -static inline void gen_movl_reg_T1(DisasContext *s, int reg) -{ - gen_movl_reg_TN(s, reg, 1); -} - -static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) -{ - int val, rm, shift; - - if (!(insn & (1 << 25))) { - /* immediate */ - val = insn & 0xfff; - if (!(insn & (1 << 23))) - val = -val; - gen_op_addl_T1_im(val); - } else { - /* shift/register */ - rm = (insn) & 0xf; - shift = (insn >> 7) & 0x1f; - gen_movl_T2_reg(s, rm); - if (shift != 0) { - gen_shift_T2_im[(insn >> 5) & 3](shift); - } - if (!(insn & (1 << 23))) - gen_op_subl_T1_T2(); - else - gen_op_addl_T1_T2(); - } -} - -static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn) -{ - int val, rm; - - if (insn & (1 << 22)) { - /* immediate */ - val = (insn & 0xf) | ((insn >> 4) & 0xf0); - if (!(insn & (1 << 23))) - val = -val; - gen_op_addl_T1_im(val); - } else { - /* register */ - rm = (insn) & 0xf; - gen_movl_T2_reg(s, rm); - if (!(insn & (1 << 23))) - gen_op_subl_T1_T2(); - else - gen_op_addl_T1_T2(); - } -} - -static void disas_arm_insn(DisasContext *s) -{ - unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; - - insn = ldl(s->pc); - s->pc += 4; - - cond = insn >> 28; - if (cond == 0xf) - goto illegal_op; - if (cond != 0xe) { - /* if not always execute, we generate a conditional jump to - next instruction */ - gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); - s->is_jmp = DISAS_JUMP_NEXT; - } - if (((insn & 0x0e000000) == 0 && - (insn & 0x00000090) != 0x90) || - ((insn & 0x0e000000) == (1 << 25))) { - int set_cc, logic_cc, shiftop; - - op1 = (insn >> 21) & 0xf; - set_cc = (insn >> 20) & 1; - logic_cc = table_logic_cc[op1] & set_cc; - - /* data processing instruction */ - if (insn & (1 << 25)) { - /* immediate operand */ - val = insn & 0xff; - shift = ((insn >> 8) & 0xf) * 2; - if (shift) - val = (val >> shift) | (val << (32 - shift)); - gen_op_movl_T1_im(val); - /* XXX: is CF modified ? */ - } else { - /* register */ - rm = (insn) & 0xf; - gen_movl_T1_reg(s, rm); - shiftop = (insn >> 5) & 3; - if (!(insn & (1 << 4))) { - shift = (insn >> 7) & 0x1f; - if (shift != 0) { - if (logic_cc) { - gen_shift_T1_im_cc[shiftop](shift); - } else { - gen_shift_T1_im[shiftop](shift); - } - } - } else { - rs = (insn >> 8) & 0xf; - gen_movl_T0_reg(s, rs); - if (logic_cc) { - gen_shift_T1_T0_cc[shiftop](); - } else { - gen_shift_T1_T0[shiftop](); - } - } - } - if (op1 != 0x0f && op1 != 0x0d) { - rn = (insn >> 16) & 0xf; - gen_movl_T0_reg(s, rn); - } - rd = (insn >> 12) & 0xf; - switch(op1) { - case 0x00: - gen_op_andl_T0_T1(); - gen_movl_reg_T0(s, rd); - if (logic_cc) - gen_op_logic_T0_cc(); - break; - case 0x01: - gen_op_xorl_T0_T1(); - gen_movl_reg_T0(s, rd); - if (logic_cc) - gen_op_logic_T0_cc(); - break; - case 0x02: - if (set_cc) - gen_op_subl_T0_T1_cc(); - else - gen_op_subl_T0_T1(); - gen_movl_reg_T0(s, rd); - break; - case 0x03: - if (set_cc) - gen_op_rsbl_T0_T1_cc(); - else - gen_op_rsbl_T0_T1(); - gen_movl_reg_T0(s, rd); - break; - case 0x04: - if (set_cc) - gen_op_addl_T0_T1_cc(); - else - gen_op_addl_T0_T1(); - gen_movl_reg_T0(s, rd); - break; - case 0x05: - if (set_cc) - gen_op_adcl_T0_T1_cc(); - else - gen_op_adcl_T0_T1(); - gen_movl_reg_T0(s, rd); - break; - case 0x06: - if (set_cc) - gen_op_sbcl_T0_T1_cc(); - else - gen_op_sbcl_T0_T1(); - gen_movl_reg_T0(s, rd); - break; - case 0x07: - if (set_cc) - gen_op_rscl_T0_T1_cc(); - else - gen_op_rscl_T0_T1(); - gen_movl_reg_T0(s, rd); - break; - case 0x08: - if (set_cc) { - gen_op_andl_T0_T1(); - gen_op_logic_T0_cc(); - } - break; - case 0x09: - if (set_cc) { - gen_op_xorl_T0_T1(); - gen_op_logic_T0_cc(); - } - break; - case 0x0a: - if (set_cc) { - gen_op_subl_T0_T1_cc(); - } - break; - case 0x0b: - if (set_cc) { - gen_op_addl_T0_T1_cc(); - } - break; - case 0x0c: - gen_op_orl_T0_T1(); - gen_movl_reg_T0(s, rd); - if (logic_cc) - gen_op_logic_T0_cc(); - break; - case 0x0d: - gen_movl_reg_T1(s, rd); - if (logic_cc) - gen_op_logic_T1_cc(); - break; - case 0x0e: - gen_op_bicl_T0_T1(); - gen_movl_reg_T0(s, rd); - if (logic_cc) - gen_op_logic_T0_cc(); - break; - default: - case 0x0f: - gen_op_notl_T1(); - gen_movl_reg_T1(s, rd); - if (logic_cc) - gen_op_logic_T1_cc(); - break; - } - } else { - /* other instructions */ - op1 = (insn >> 24) & 0xf; - switch(op1) { - case 0x0: - case 0x1: - sh = (insn >> 5) & 3; - if (sh == 0) { - if (op1 == 0x0) { - rd = (insn >> 16) & 0xf; - rn = (insn >> 12) & 0xf; - rs = (insn >> 8) & 0xf; - rm = (insn) & 0xf; - if (!(insn & (1 << 23))) { - /* 32 bit mul */ - gen_movl_T0_reg(s, rs); - gen_movl_T1_reg(s, rm); - gen_op_mul_T0_T1(); - if (insn & (1 << 21)) { - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1(); - } - if (insn & (1 << 20)) - gen_op_logic_T0_cc(); - gen_movl_reg_T0(s, rd); - } else { - /* 64 bit mul */ - gen_movl_T0_reg(s, rs); - gen_movl_T1_reg(s, rm); - if (insn & (1 << 22)) - gen_op_mull_T0_T1(); - else - gen_op_imull_T0_T1(); - if (insn & (1 << 21)) - gen_op_addq_T0_T1(rn, rd); - if (insn & (1 << 20)) - gen_op_logicq_cc(); - gen_movl_reg_T0(s, rn); - gen_movl_reg_T1(s, rd); - } - } else { - /* SWP instruction */ - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - rm = (insn) & 0xf; - - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rn); - if (insn & (1 << 22)) { - gen_op_swpb_T0_T1(); - } else { - gen_op_swpl_T0_T1(); - } - gen_movl_reg_T0(s, rd); - } - } else { - /* load/store half word */ - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - gen_movl_T1_reg(s, rn); - if (insn & (1 << 25)) - gen_add_datah_offset(s, insn); - if (insn & (1 << 20)) { - /* load */ - switch(sh) { - case 1: - gen_op_lduw_T0_T1(); - break; - case 2: - gen_op_ldsb_T0_T1(); - break; - default: - case 3: - gen_op_ldsw_T0_T1(); - break; - } - } else { - /* store */ - gen_op_stw_T0_T1(); - } - if (!(insn & (1 << 24))) { - gen_add_datah_offset(s, insn); - gen_movl_reg_T1(s, rn); - } else if (insn & (1 << 21)) { - gen_movl_reg_T1(s, rn); - } - } - break; - case 0x4: - case 0x5: - case 0x6: - case 0x7: - /* load/store byte/word */ - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - gen_movl_T1_reg(s, rn); - if (insn & (1 << 24)) - gen_add_data_offset(s, insn); - if (insn & (1 << 20)) { - /* load */ - if (insn & (1 << 22)) - gen_op_ldub_T0_T1(); - else - gen_op_ldl_T0_T1(); - gen_movl_reg_T0(s, rd); - } else { - /* store */ - gen_movl_T0_reg(s, rd); - if (insn & (1 << 22)) - gen_op_stb_T0_T1(); - else - gen_op_stl_T0_T1(); - } - if (!(insn & (1 << 24))) { - gen_add_data_offset(s, insn); - gen_movl_reg_T1(s, rn); - } else if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); { - } - break; - case 0x08: - case 0x09: - { - int j, n; - /* load/store multiple words */ - /* XXX: store correct base if write back */ - if (insn & (1 << 22)) - goto illegal_op; /* only usable in supervisor mode */ - rn = (insn >> 16) & 0xf; - gen_movl_T1_reg(s, rn); - - /* compute total size */ - n = 0; - for(i=0;i<16;i++) { - if (insn & (1 << i)) - n++; - } - /* XXX: test invalid n == 0 case ? */ - if (insn & (1 << 23)) { - if (insn & (1 << 24)) { - /* pre increment */ - gen_op_addl_T1_im(4); - } else { - /* post increment */ - } - } else { - if (insn & (1 << 24)) { - /* pre decrement */ - gen_op_addl_T1_im(-(n * 4)); - } else { - /* post decrement */ - if (n != 1) - gen_op_addl_T1_im(-((n - 1) * 4)); - } - } - j = 0; - for(i=0;i<16;i++) { - if (insn & (1 << i)) { - if (insn & (1 << 20)) { - /* load */ - gen_op_ldl_T0_T1(); - gen_movl_reg_T0(s, i); - } else { - /* store */ - if (i == 15) { - /* special case: r15 = PC + 12 */ - val = (long)s->pc + 8; - gen_op_movl_TN_im[0](val); - } else { - gen_movl_T0_reg(s, i); - } - gen_op_stl_T0_T1(); - } - j++; - /* no need to add after the last transfer */ - if (j != n) - gen_op_addl_T1_im(4); - } - } - if (insn & (1 << 21)) { - /* write back */ - if (insn & (1 << 23)) { - if (insn & (1 << 24)) { - /* pre increment */ - } else { - /* post increment */ - gen_op_addl_T1_im(4); - } - } else { - if (insn & (1 << 24)) { - /* pre decrement */ - if (n != 1) - gen_op_addl_T1_im(-((n - 1) * 4)); - } else { - /* post decrement */ - gen_op_addl_T1_im(-(n * 4)); - } - } - gen_movl_reg_T1(s, rn); - } - } - break; - case 0xa: - case 0xb: - { - int offset; - - /* branch (and link) */ - val = (int)s->pc; - if (insn & (1 << 24)) { - gen_op_movl_T0_im(val); - gen_op_movl_reg_TN[0][14](); - } - offset = (((int)insn << 8) >> 8); - val += (offset << 2) + 4; - gen_op_jmp((long)s->tb, val); - s->is_jmp = DISAS_TB_JUMP; - } - break; - case 0xf: - /* swi */ - gen_op_movl_T0_im((long)s->pc); - gen_op_movl_reg_TN[0][15](); - gen_op_swi(); - s->is_jmp = DISAS_JUMP; - break; - case 0xc: - case 0xd: - rd = (insn >> 12) & 0x7; - rn = (insn >> 16) & 0xf; - gen_movl_T1_reg(s, rn); - val = (insn) & 0xff; - if (!(insn & (1 << 23))) - val = -val; - switch((insn >> 8) & 0xf) { - case 0x1: - /* load/store */ - if ((insn & (1 << 24))) - gen_op_addl_T1_im(val); - /* XXX: do it */ - if (!(insn & (1 << 24))) - gen_op_addl_T1_im(val); - if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); - break; - case 0x2: - { - int n, i; - /* load store multiple */ - if ((insn & (1 << 24))) - gen_op_addl_T1_im(val); - switch(insn & 0x00408000) { - case 0x00008000: n = 1; break; - case 0x00400000: n = 2; break; - case 0x00408000: n = 3; break; - default: n = 4; break; - } - for(i = 0;i < n; i++) { - /* XXX: do it */ - } - if (!(insn & (1 << 24))) - gen_op_addl_T1_im(val); - if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); - } - break; - default: - goto illegal_op; - } - break; - case 0x0e: - /* float ops */ - /* XXX: do it */ - switch((insn >> 20) & 0xf) { - case 0x2: /* wfs */ - break; - case 0x3: /* rfs */ - break; - case 0x4: /* wfc */ - break; - case 0x5: /* rfc */ - break; - default: - goto illegal_op; - } - break; - default: - illegal_op: - gen_op_movl_T0_im((long)s->pc - 4); - gen_op_movl_reg_TN[0][15](); - gen_op_undef_insn(); - s->is_jmp = DISAS_JUMP; - break; - } - } -} - -/* generate intermediate code in gen_opc_buf and gen_opparam_buf for - basic block 'tb'. If search_pc is TRUE, also generate PC - information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, - int search_pc) -{ - DisasContext dc1, *dc = &dc1; - uint16_t *gen_opc_end; - int j, lj; - uint8_t *pc_start; - - /* generate intermediate code */ - pc_start = (uint8_t *)tb->pc; - - dc->tb = tb; - - gen_opc_ptr = gen_opc_buf; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; - - dc->is_jmp = DISAS_NEXT; - dc->pc = pc_start; - lj = -1; - do { - if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; - if (lj < j) { - lj++; - while (lj < j) - gen_opc_instr_start[lj++] = 0; - } - gen_opc_pc[lj] = (uint32_t)dc->pc; - gen_opc_instr_start[lj] = 1; - } - disas_arm_insn(dc); - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && - (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); - switch(dc->is_jmp) { - case DISAS_JUMP_NEXT: - case DISAS_NEXT: - gen_op_jmp((long)dc->tb, (long)dc->pc); - break; - default: - case DISAS_JUMP: - /* indicate that the hash table must be used to find the next TB */ - gen_op_movl_T0_0(); - gen_op_exit_tb(); - break; - case DISAS_TB_JUMP: - /* nothing more to generate */ - break; - } - *gen_opc_ptr = INDEX_op_end; - -#ifdef DEBUG_DISAS - if (loglevel) { - fprintf(logfile, "----------------\n"); - fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - disas(logfile, pc_start, dc->pc - pc_start, 0, 0); - fprintf(logfile, "\n"); - - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } -#endif - if (!search_pc) - tb->size = dc->pc - pc_start; - return 0; -} - -int gen_intermediate_code(CPUState *env, TranslationBlock *tb) -{ - return gen_intermediate_code_internal(env, tb, 0); -} - -int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) -{ - return gen_intermediate_code_internal(env, tb, 1); -} - -CPUARMState *cpu_arm_init(void) -{ - CPUARMState *env; - - cpu_exec_init(); - - env = malloc(sizeof(CPUARMState)); - if (!env) - return NULL; - memset(env, 0, sizeof(CPUARMState)); - return env; -} - -void cpu_arm_close(CPUARMState *env) -{ - free(env); -} - -void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) -{ - int i; - - for(i=0;i<16;i++) { - fprintf(f, "R%02d=%08x", i, env->regs[i]); - if ((i % 4) == 3) - fprintf(f, "\n"); - else - fprintf(f, " "); - } - fprintf(f, "PSR=%08x %c%c%c%c\n", - env->cpsr, - env->cpsr & (1 << 31) ? 'N' : '-', - env->cpsr & (1 << 30) ? 'Z' : '-', - env->cpsr & (1 << 29) ? 'C' : '-', - env->cpsr & (1 << 28) ? 'V' : '-'); -} diff --git a/translate-i386.c b/translate-i386.c deleted file mode 100644 index b732178cd..000000000 --- a/translate-i386.c +++ /dev/null @@ -1,4487 +0,0 @@ -/* - * i386 translation - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu-i386.h" -#include "exec.h" -#include "disas.h" - -/* XXX: move that elsewhere */ -static uint16_t *gen_opc_ptr; -static uint32_t *gen_opparam_ptr; - -#define PREFIX_REPZ 0x01 -#define PREFIX_REPNZ 0x02 -#define PREFIX_LOCK 0x04 -#define PREFIX_DATA 0x08 -#define PREFIX_ADR 0x10 - -typedef struct DisasContext { - /* current insn context */ - int override; /* -1 if no override */ - int prefix; - int aflag, dflag; - uint8_t *pc; /* pc = eip + cs_base */ - int is_jmp; /* 1 = means jump (stop translation), 2 means CPU - static state change (stop translation) */ - /* current block context */ - uint8_t *cs_base; /* base of CS segment */ - int pe; /* protected mode */ - int code32; /* 32 bit code segment */ - int ss32; /* 32 bit stack segment */ - int cc_op; /* current CC operation */ - int addseg; /* non zero if either DS/ES/SS have a non zero base */ - int f_st; /* currently unused */ - int vm86; /* vm86 mode */ - int cpl; - int iopl; - int tf; /* TF cpu flag */ - int jmp_opt; /* use direct block chaining for direct jumps */ - int mem_index; /* select memory access functions */ - struct TranslationBlock *tb; - int popl_esp_hack; /* for correct popl with esp base handling */ -} DisasContext; - -static void gen_eob(DisasContext *s); -static void gen_jmp(DisasContext *s, unsigned int eip); - -/* i386 arith/logic operations */ -enum { - OP_ADDL, - OP_ORL, - OP_ADCL, - OP_SBBL, - OP_ANDL, - OP_SUBL, - OP_XORL, - OP_CMPL, -}; - -/* i386 shift ops */ -enum { - OP_ROL, - OP_ROR, - OP_RCL, - OP_RCR, - OP_SHL, - OP_SHR, - OP_SHL1, /* undocumented */ - OP_SAR = 7, -}; - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include "opc-i386.h" -#undef DEF - NB_OPS, -}; - -#include "gen-op-i386.h" - -/* operand size */ -enum { - OT_BYTE = 0, - OT_WORD, - OT_LONG, - OT_QUAD, -}; - -enum { - /* I386 int registers */ - OR_EAX, /* MUST be even numbered */ - OR_ECX, - OR_EDX, - OR_EBX, - OR_ESP, - OR_EBP, - OR_ESI, - OR_EDI, - OR_TMP0, /* temporary operand register */ - OR_TMP1, - OR_A0, /* temporary register used when doing address evaluation */ - OR_ZERO, /* fixed zero register */ - NB_OREGS, -}; - -typedef void (GenOpFunc)(void); -typedef void (GenOpFunc1)(long); -typedef void (GenOpFunc2)(long, long); -typedef void (GenOpFunc3)(long, long, long); - -static GenOpFunc *gen_op_mov_reg_T0[3][8] = { - [OT_BYTE] = { - gen_op_movb_EAX_T0, - gen_op_movb_ECX_T0, - gen_op_movb_EDX_T0, - gen_op_movb_EBX_T0, - gen_op_movh_EAX_T0, - gen_op_movh_ECX_T0, - gen_op_movh_EDX_T0, - gen_op_movh_EBX_T0, - }, - [OT_WORD] = { - gen_op_movw_EAX_T0, - gen_op_movw_ECX_T0, - gen_op_movw_EDX_T0, - gen_op_movw_EBX_T0, - gen_op_movw_ESP_T0, - gen_op_movw_EBP_T0, - gen_op_movw_ESI_T0, - gen_op_movw_EDI_T0, - }, - [OT_LONG] = { - gen_op_movl_EAX_T0, - gen_op_movl_ECX_T0, - gen_op_movl_EDX_T0, - gen_op_movl_EBX_T0, - gen_op_movl_ESP_T0, - gen_op_movl_EBP_T0, - gen_op_movl_ESI_T0, - gen_op_movl_EDI_T0, - }, -}; - -static GenOpFunc *gen_op_mov_reg_T1[3][8] = { - [OT_BYTE] = { - gen_op_movb_EAX_T1, - gen_op_movb_ECX_T1, - gen_op_movb_EDX_T1, - gen_op_movb_EBX_T1, - gen_op_movh_EAX_T1, - gen_op_movh_ECX_T1, - gen_op_movh_EDX_T1, - gen_op_movh_EBX_T1, - }, - [OT_WORD] = { - gen_op_movw_EAX_T1, - gen_op_movw_ECX_T1, - gen_op_movw_EDX_T1, - gen_op_movw_EBX_T1, - gen_op_movw_ESP_T1, - gen_op_movw_EBP_T1, - gen_op_movw_ESI_T1, - gen_op_movw_EDI_T1, - }, - [OT_LONG] = { - gen_op_movl_EAX_T1, - gen_op_movl_ECX_T1, - gen_op_movl_EDX_T1, - gen_op_movl_EBX_T1, - gen_op_movl_ESP_T1, - gen_op_movl_EBP_T1, - gen_op_movl_ESI_T1, - gen_op_movl_EDI_T1, - }, -}; - -static GenOpFunc *gen_op_mov_reg_A0[2][8] = { - [0] = { - gen_op_movw_EAX_A0, - gen_op_movw_ECX_A0, - gen_op_movw_EDX_A0, - gen_op_movw_EBX_A0, - gen_op_movw_ESP_A0, - gen_op_movw_EBP_A0, - gen_op_movw_ESI_A0, - gen_op_movw_EDI_A0, - }, - [1] = { - gen_op_movl_EAX_A0, - gen_op_movl_ECX_A0, - gen_op_movl_EDX_A0, - gen_op_movl_EBX_A0, - gen_op_movl_ESP_A0, - gen_op_movl_EBP_A0, - gen_op_movl_ESI_A0, - gen_op_movl_EDI_A0, - }, -}; - -static GenOpFunc *gen_op_mov_TN_reg[3][2][8] = -{ - [OT_BYTE] = { - { - gen_op_movl_T0_EAX, - gen_op_movl_T0_ECX, - gen_op_movl_T0_EDX, - gen_op_movl_T0_EBX, - gen_op_movh_T0_EAX, - gen_op_movh_T0_ECX, - gen_op_movh_T0_EDX, - gen_op_movh_T0_EBX, - }, - { - gen_op_movl_T1_EAX, - gen_op_movl_T1_ECX, - gen_op_movl_T1_EDX, - gen_op_movl_T1_EBX, - gen_op_movh_T1_EAX, - gen_op_movh_T1_ECX, - gen_op_movh_T1_EDX, - gen_op_movh_T1_EBX, - }, - }, - [OT_WORD] = { - { - gen_op_movl_T0_EAX, - gen_op_movl_T0_ECX, - gen_op_movl_T0_EDX, - gen_op_movl_T0_EBX, - gen_op_movl_T0_ESP, - gen_op_movl_T0_EBP, - gen_op_movl_T0_ESI, - gen_op_movl_T0_EDI, - }, - { - gen_op_movl_T1_EAX, - gen_op_movl_T1_ECX, - gen_op_movl_T1_EDX, - gen_op_movl_T1_EBX, - gen_op_movl_T1_ESP, - gen_op_movl_T1_EBP, - gen_op_movl_T1_ESI, - gen_op_movl_T1_EDI, - }, - }, - [OT_LONG] = { - { - gen_op_movl_T0_EAX, - gen_op_movl_T0_ECX, - gen_op_movl_T0_EDX, - gen_op_movl_T0_EBX, - gen_op_movl_T0_ESP, - gen_op_movl_T0_EBP, - gen_op_movl_T0_ESI, - gen_op_movl_T0_EDI, - }, - { - gen_op_movl_T1_EAX, - gen_op_movl_T1_ECX, - gen_op_movl_T1_EDX, - gen_op_movl_T1_EBX, - gen_op_movl_T1_ESP, - gen_op_movl_T1_EBP, - gen_op_movl_T1_ESI, - gen_op_movl_T1_EDI, - }, - }, -}; - -static GenOpFunc *gen_op_movl_A0_reg[8] = { - gen_op_movl_A0_EAX, - gen_op_movl_A0_ECX, - gen_op_movl_A0_EDX, - gen_op_movl_A0_EBX, - gen_op_movl_A0_ESP, - gen_op_movl_A0_EBP, - gen_op_movl_A0_ESI, - gen_op_movl_A0_EDI, -}; - -static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { - [0] = { - gen_op_addl_A0_EAX, - gen_op_addl_A0_ECX, - gen_op_addl_A0_EDX, - gen_op_addl_A0_EBX, - gen_op_addl_A0_ESP, - gen_op_addl_A0_EBP, - gen_op_addl_A0_ESI, - gen_op_addl_A0_EDI, - }, - [1] = { - gen_op_addl_A0_EAX_s1, - gen_op_addl_A0_ECX_s1, - gen_op_addl_A0_EDX_s1, - gen_op_addl_A0_EBX_s1, - gen_op_addl_A0_ESP_s1, - gen_op_addl_A0_EBP_s1, - gen_op_addl_A0_ESI_s1, - gen_op_addl_A0_EDI_s1, - }, - [2] = { - gen_op_addl_A0_EAX_s2, - gen_op_addl_A0_ECX_s2, - gen_op_addl_A0_EDX_s2, - gen_op_addl_A0_EBX_s2, - gen_op_addl_A0_ESP_s2, - gen_op_addl_A0_EBP_s2, - gen_op_addl_A0_ESI_s2, - gen_op_addl_A0_EDI_s2, - }, - [3] = { - gen_op_addl_A0_EAX_s3, - gen_op_addl_A0_ECX_s3, - gen_op_addl_A0_EDX_s3, - gen_op_addl_A0_EBX_s3, - gen_op_addl_A0_ESP_s3, - gen_op_addl_A0_EBP_s3, - gen_op_addl_A0_ESI_s3, - gen_op_addl_A0_EDI_s3, - }, -}; - -static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = { - [0] = { - gen_op_cmovw_EAX_T1_T0, - gen_op_cmovw_ECX_T1_T0, - gen_op_cmovw_EDX_T1_T0, - gen_op_cmovw_EBX_T1_T0, - gen_op_cmovw_ESP_T1_T0, - gen_op_cmovw_EBP_T1_T0, - gen_op_cmovw_ESI_T1_T0, - gen_op_cmovw_EDI_T1_T0, - }, - [1] = { - gen_op_cmovl_EAX_T1_T0, - gen_op_cmovl_ECX_T1_T0, - gen_op_cmovl_EDX_T1_T0, - gen_op_cmovl_EBX_T1_T0, - gen_op_cmovl_ESP_T1_T0, - gen_op_cmovl_EBP_T1_T0, - gen_op_cmovl_ESI_T1_T0, - gen_op_cmovl_EDI_T1_T0, - }, -}; - -static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { - NULL, - gen_op_orl_T0_T1, - NULL, - NULL, - gen_op_andl_T0_T1, - NULL, - gen_op_xorl_T0_T1, - NULL, -}; - -static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { - [OT_BYTE] = { - gen_op_adcb_T0_T1_cc, - gen_op_sbbb_T0_T1_cc, - }, - [OT_WORD] = { - gen_op_adcw_T0_T1_cc, - gen_op_sbbw_T0_T1_cc, - }, - [OT_LONG] = { - gen_op_adcl_T0_T1_cc, - gen_op_sbbl_T0_T1_cc, - }, -}; - -static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = { - [OT_BYTE] = { - gen_op_adcb_mem_T0_T1_cc, - gen_op_sbbb_mem_T0_T1_cc, - }, - [OT_WORD] = { - gen_op_adcw_mem_T0_T1_cc, - gen_op_sbbw_mem_T0_T1_cc, - }, - [OT_LONG] = { - gen_op_adcl_mem_T0_T1_cc, - gen_op_sbbl_mem_T0_T1_cc, - }, -}; - -static const int cc_op_arithb[8] = { - CC_OP_ADDB, - CC_OP_LOGICB, - CC_OP_ADDB, - CC_OP_SUBB, - CC_OP_LOGICB, - CC_OP_SUBB, - CC_OP_LOGICB, - CC_OP_SUBB, -}; - -static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { - gen_op_cmpxchgb_T0_T1_EAX_cc, - gen_op_cmpxchgw_T0_T1_EAX_cc, - gen_op_cmpxchgl_T0_T1_EAX_cc, -}; - -static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = { - gen_op_cmpxchgb_mem_T0_T1_EAX_cc, - gen_op_cmpxchgw_mem_T0_T1_EAX_cc, - gen_op_cmpxchgl_mem_T0_T1_EAX_cc, -}; - -static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { - [OT_BYTE] = { - gen_op_rolb_T0_T1_cc, - gen_op_rorb_T0_T1_cc, - gen_op_rclb_T0_T1_cc, - gen_op_rcrb_T0_T1_cc, - gen_op_shlb_T0_T1_cc, - gen_op_shrb_T0_T1_cc, - gen_op_shlb_T0_T1_cc, - gen_op_sarb_T0_T1_cc, - }, - [OT_WORD] = { - gen_op_rolw_T0_T1_cc, - gen_op_rorw_T0_T1_cc, - gen_op_rclw_T0_T1_cc, - gen_op_rcrw_T0_T1_cc, - gen_op_shlw_T0_T1_cc, - gen_op_shrw_T0_T1_cc, - gen_op_shlw_T0_T1_cc, - gen_op_sarw_T0_T1_cc, - }, - [OT_LONG] = { - gen_op_roll_T0_T1_cc, - gen_op_rorl_T0_T1_cc, - gen_op_rcll_T0_T1_cc, - gen_op_rcrl_T0_T1_cc, - gen_op_shll_T0_T1_cc, - gen_op_shrl_T0_T1_cc, - gen_op_shll_T0_T1_cc, - gen_op_sarl_T0_T1_cc, - }, -}; - -static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = { - [OT_BYTE] = { - gen_op_rolb_mem_T0_T1_cc, - gen_op_rorb_mem_T0_T1_cc, - gen_op_rclb_mem_T0_T1_cc, - gen_op_rcrb_mem_T0_T1_cc, - gen_op_shlb_mem_T0_T1_cc, - gen_op_shrb_mem_T0_T1_cc, - gen_op_shlb_mem_T0_T1_cc, - gen_op_sarb_mem_T0_T1_cc, - }, - [OT_WORD] = { - gen_op_rolw_mem_T0_T1_cc, - gen_op_rorw_mem_T0_T1_cc, - gen_op_rclw_mem_T0_T1_cc, - gen_op_rcrw_mem_T0_T1_cc, - gen_op_shlw_mem_T0_T1_cc, - gen_op_shrw_mem_T0_T1_cc, - gen_op_shlw_mem_T0_T1_cc, - gen_op_sarw_mem_T0_T1_cc, - }, - [OT_LONG] = { - gen_op_roll_mem_T0_T1_cc, - gen_op_rorl_mem_T0_T1_cc, - gen_op_rcll_mem_T0_T1_cc, - gen_op_rcrl_mem_T0_T1_cc, - gen_op_shll_mem_T0_T1_cc, - gen_op_shrl_mem_T0_T1_cc, - gen_op_shll_mem_T0_T1_cc, - gen_op_sarl_mem_T0_T1_cc, - }, -}; - -static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = { - [0] = { - gen_op_shldw_T0_T1_im_cc, - gen_op_shrdw_T0_T1_im_cc, - }, - [1] = { - gen_op_shldl_T0_T1_im_cc, - gen_op_shrdl_T0_T1_im_cc, - }, -}; - -static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = { - [0] = { - gen_op_shldw_T0_T1_ECX_cc, - gen_op_shrdw_T0_T1_ECX_cc, - }, - [1] = { - gen_op_shldl_T0_T1_ECX_cc, - gen_op_shrdl_T0_T1_ECX_cc, - }, -}; - -static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = { - [0] = { - gen_op_shldw_mem_T0_T1_im_cc, - gen_op_shrdw_mem_T0_T1_im_cc, - }, - [1] = { - gen_op_shldl_mem_T0_T1_im_cc, - gen_op_shrdl_mem_T0_T1_im_cc, - }, -}; - -static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = { - [0] = { - gen_op_shldw_mem_T0_T1_ECX_cc, - gen_op_shrdw_mem_T0_T1_ECX_cc, - }, - [1] = { - gen_op_shldl_mem_T0_T1_ECX_cc, - gen_op_shrdl_mem_T0_T1_ECX_cc, - }, -}; - -static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { - [0] = { - gen_op_btw_T0_T1_cc, - gen_op_btsw_T0_T1_cc, - gen_op_btrw_T0_T1_cc, - gen_op_btcw_T0_T1_cc, - }, - [1] = { - gen_op_btl_T0_T1_cc, - gen_op_btsl_T0_T1_cc, - gen_op_btrl_T0_T1_cc, - gen_op_btcl_T0_T1_cc, - }, -}; - -static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { - [0] = { - gen_op_bsfw_T0_cc, - gen_op_bsrw_T0_cc, - }, - [1] = { - gen_op_bsfl_T0_cc, - gen_op_bsrl_T0_cc, - }, -}; - -static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = { - gen_op_ldsb_T0_A0, - gen_op_ldsw_T0_A0, - NULL, - - gen_op_ldsb_kernel_T0_A0, - gen_op_ldsw_kernel_T0_A0, - NULL, - - gen_op_ldsb_user_T0_A0, - gen_op_ldsw_user_T0_A0, - NULL, -}; - -static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = { - gen_op_ldub_T0_A0, - gen_op_lduw_T0_A0, - NULL, - - gen_op_ldub_kernel_T0_A0, - gen_op_lduw_kernel_T0_A0, - NULL, - - gen_op_ldub_user_T0_A0, - gen_op_lduw_user_T0_A0, - NULL, -}; - -/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */ -static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = { - gen_op_ldub_T0_A0, - gen_op_lduw_T0_A0, - gen_op_ldl_T0_A0, - - gen_op_ldub_kernel_T0_A0, - gen_op_lduw_kernel_T0_A0, - gen_op_ldl_kernel_T0_A0, - - gen_op_ldub_user_T0_A0, - gen_op_lduw_user_T0_A0, - gen_op_ldl_user_T0_A0, -}; - -static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = { - gen_op_ldub_T1_A0, - gen_op_lduw_T1_A0, - gen_op_ldl_T1_A0, - - gen_op_ldub_kernel_T1_A0, - gen_op_lduw_kernel_T1_A0, - gen_op_ldl_kernel_T1_A0, - - gen_op_ldub_user_T1_A0, - gen_op_lduw_user_T1_A0, - gen_op_ldl_user_T1_A0, -}; - -static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { - gen_op_stb_T0_A0, - gen_op_stw_T0_A0, - gen_op_stl_T0_A0, - - gen_op_stb_kernel_T0_A0, - gen_op_stw_kernel_T0_A0, - gen_op_stl_kernel_T0_A0, - - gen_op_stb_user_T0_A0, - gen_op_stw_user_T0_A0, - gen_op_stl_user_T0_A0, -}; - -static inline void gen_string_movl_A0_ESI(DisasContext *s) -{ - int override; - - override = s->override; - if (s->aflag) { - /* 32 bit address */ - if (s->addseg && override < 0) - override = R_DS; - if (override >= 0) { - gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); - gen_op_addl_A0_reg_sN[0][R_ESI](); - } else { - gen_op_movl_A0_reg[R_ESI](); - } - } else { - /* 16 address, always override */ - if (override < 0) - override = R_DS; - gen_op_movl_A0_reg[R_ESI](); - gen_op_andl_A0_ffff(); - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); - } -} - -static inline void gen_string_movl_A0_EDI(DisasContext *s) -{ - if (s->aflag) { - if (s->addseg) { - gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); - gen_op_addl_A0_reg_sN[0][R_EDI](); - } else { - gen_op_movl_A0_reg[R_EDI](); - } - } else { - gen_op_movl_A0_reg[R_EDI](); - gen_op_andl_A0_ffff(); - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); - } -} - -static GenOpFunc *gen_op_movl_T0_Dshift[3] = { - gen_op_movl_T0_Dshiftb, - gen_op_movl_T0_Dshiftw, - gen_op_movl_T0_Dshiftl, -}; - -static GenOpFunc2 *gen_op_jz_ecx[2] = { - gen_op_jz_ecxw, - gen_op_jz_ecxl, -}; - -static GenOpFunc1 *gen_op_jz_ecx_im[2] = { - gen_op_jz_ecxw_im, - gen_op_jz_ecxl_im, -}; - -static GenOpFunc *gen_op_dec_ECX[2] = { - gen_op_decw_ECX, - gen_op_decl_ECX, -}; - -static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = { - { - gen_op_string_jnz_subb, - gen_op_string_jnz_subw, - gen_op_string_jnz_subl, - }, - { - gen_op_string_jz_subb, - gen_op_string_jz_subw, - gen_op_string_jz_subl, - }, -}; - -static GenOpFunc1 *gen_op_string_jnz_sub_im[2][3] = { - { - gen_op_string_jnz_subb_im, - gen_op_string_jnz_subw_im, - gen_op_string_jnz_subl_im, - }, - { - gen_op_string_jz_subb_im, - gen_op_string_jz_subw_im, - gen_op_string_jz_subl_im, - }, -}; - -static GenOpFunc *gen_op_in_DX_T0[3] = { - gen_op_inb_DX_T0, - gen_op_inw_DX_T0, - gen_op_inl_DX_T0, -}; - -static GenOpFunc *gen_op_out_DX_T0[3] = { - gen_op_outb_DX_T0, - gen_op_outw_DX_T0, - gen_op_outl_DX_T0, -}; - -static inline void gen_movs(DisasContext *s, int ot) -{ - gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_string_movl_A0_EDI(s); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_movl_T0_Dshift[ot](); - if (s->aflag) { - gen_op_addl_ESI_T0(); - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_ESI_T0(); - gen_op_addw_EDI_T0(); - } -} - -static inline void gen_update_cc_op(DisasContext *s) -{ - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; - } -} - -static inline void gen_jz_ecx_string(DisasContext *s, unsigned int next_eip) -{ - if (s->jmp_opt) { - gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); - } else { - /* XXX: does not work with gdbstub "ice" single step - not a - serious problem */ - gen_op_jz_ecx_im[s->aflag](next_eip); - } -} - -static inline void gen_stos(DisasContext *s, int ot) -{ - gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); - gen_string_movl_A0_EDI(s); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_movl_T0_Dshift[ot](); - if (s->aflag) { - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_EDI_T0(); - } -} - -static inline void gen_lods(DisasContext *s, int ot) -{ - gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_mov_reg_T0[ot][R_EAX](); - gen_op_movl_T0_Dshift[ot](); - if (s->aflag) { - gen_op_addl_ESI_T0(); - } else { - gen_op_addw_ESI_T0(); - } -} - -static inline void gen_scas(DisasContext *s, int ot) -{ - gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); - gen_string_movl_A0_EDI(s); - gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_cmpl_T0_T1_cc(); - gen_op_movl_T0_Dshift[ot](); - if (s->aflag) { - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_EDI_T0(); - } -} - -static inline void gen_cmps(DisasContext *s, int ot) -{ - gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_string_movl_A0_EDI(s); - gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_cmpl_T0_T1_cc(); - gen_op_movl_T0_Dshift[ot](); - if (s->aflag) { - gen_op_addl_ESI_T0(); - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_ESI_T0(); - gen_op_addw_EDI_T0(); - } -} - -static inline void gen_ins(DisasContext *s, int ot) -{ - gen_op_in_DX_T0[ot](); - gen_string_movl_A0_EDI(s); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_movl_T0_Dshift[ot](); - if (s->aflag) { - gen_op_addl_EDI_T0(); - } else { - gen_op_addw_EDI_T0(); - } -} - -static inline void gen_outs(DisasContext *s, int ot) -{ - gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_out_DX_T0[ot](); - gen_op_movl_T0_Dshift[ot](); - if (s->aflag) { - gen_op_addl_ESI_T0(); - } else { - gen_op_addw_ESI_T0(); - } -} - -/* same method as Valgrind : we generate jumps to current or next - instruction */ -#define GEN_REPZ(op) \ -static inline void gen_repz_ ## op(DisasContext *s, int ot, \ - unsigned int cur_eip, unsigned int next_eip) \ -{ \ - gen_update_cc_op(s); \ - gen_jz_ecx_string(s, next_eip); \ - gen_ ## op(s, ot); \ - gen_op_dec_ECX[s->aflag](); \ - /* a loop would cause two single step exceptions if ECX = 1 \ - before rep string_insn */ \ - if (!s->jmp_opt) \ - gen_op_jz_ecx_im[s->aflag](next_eip); \ - gen_jmp(s, cur_eip); \ -} - -#define GEN_REPZ2(op) \ -static inline void gen_repz_ ## op(DisasContext *s, int ot, \ - unsigned int cur_eip, \ - unsigned int next_eip, \ - int nz) \ -{ \ - gen_update_cc_op(s); \ - gen_jz_ecx_string(s, next_eip); \ - gen_ ## op(s, ot); \ - gen_op_dec_ECX[s->aflag](); \ - gen_op_set_cc_op(CC_OP_SUBB + ot); \ - if (!s->jmp_opt) \ - gen_op_string_jnz_sub_im[nz][ot](next_eip); \ - else \ - gen_op_string_jnz_sub[nz][ot]((long)s->tb); \ - if (!s->jmp_opt) \ - gen_op_jz_ecx_im[s->aflag](next_eip); \ - gen_jmp(s, cur_eip); \ -} - -GEN_REPZ(movs) -GEN_REPZ(stos) -GEN_REPZ(lods) -GEN_REPZ(ins) -GEN_REPZ(outs) -GEN_REPZ2(scas) -GEN_REPZ2(cmps) - -static GenOpFunc *gen_op_in[3] = { - gen_op_inb_T0_T1, - gen_op_inw_T0_T1, - gen_op_inl_T0_T1, -}; - -static GenOpFunc *gen_op_out[3] = { - gen_op_outb_T0_T1, - gen_op_outw_T0_T1, - gen_op_outl_T0_T1, -}; - -enum { - JCC_O, - JCC_B, - JCC_Z, - JCC_BE, - JCC_S, - JCC_P, - JCC_L, - JCC_LE, -}; - -static GenOpFunc3 *gen_jcc_sub[3][8] = { - [OT_BYTE] = { - NULL, - gen_op_jb_subb, - gen_op_jz_subb, - gen_op_jbe_subb, - gen_op_js_subb, - NULL, - gen_op_jl_subb, - gen_op_jle_subb, - }, - [OT_WORD] = { - NULL, - gen_op_jb_subw, - gen_op_jz_subw, - gen_op_jbe_subw, - gen_op_js_subw, - NULL, - gen_op_jl_subw, - gen_op_jle_subw, - }, - [OT_LONG] = { - NULL, - gen_op_jb_subl, - gen_op_jz_subl, - gen_op_jbe_subl, - gen_op_js_subl, - NULL, - gen_op_jl_subl, - gen_op_jle_subl, - }, -}; -static GenOpFunc2 *gen_op_loop[2][4] = { - [0] = { - gen_op_loopnzw, - gen_op_loopzw, - gen_op_loopw, - gen_op_jecxzw, - }, - [1] = { - gen_op_loopnzl, - gen_op_loopzl, - gen_op_loopl, - gen_op_jecxzl, - }, -}; - -static GenOpFunc *gen_setcc_slow[8] = { - gen_op_seto_T0_cc, - gen_op_setb_T0_cc, - gen_op_setz_T0_cc, - gen_op_setbe_T0_cc, - gen_op_sets_T0_cc, - gen_op_setp_T0_cc, - gen_op_setl_T0_cc, - gen_op_setle_T0_cc, -}; - -static GenOpFunc *gen_setcc_sub[3][8] = { - [OT_BYTE] = { - NULL, - gen_op_setb_T0_subb, - gen_op_setz_T0_subb, - gen_op_setbe_T0_subb, - gen_op_sets_T0_subb, - NULL, - gen_op_setl_T0_subb, - gen_op_setle_T0_subb, - }, - [OT_WORD] = { - NULL, - gen_op_setb_T0_subw, - gen_op_setz_T0_subw, - gen_op_setbe_T0_subw, - gen_op_sets_T0_subw, - NULL, - gen_op_setl_T0_subw, - gen_op_setle_T0_subw, - }, - [OT_LONG] = { - NULL, - gen_op_setb_T0_subl, - gen_op_setz_T0_subl, - gen_op_setbe_T0_subl, - gen_op_sets_T0_subl, - NULL, - gen_op_setl_T0_subl, - gen_op_setle_T0_subl, - }, -}; - -static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { - gen_op_fadd_ST0_FT0, - gen_op_fmul_ST0_FT0, - gen_op_fcom_ST0_FT0, - gen_op_fcom_ST0_FT0, - gen_op_fsub_ST0_FT0, - gen_op_fsubr_ST0_FT0, - gen_op_fdiv_ST0_FT0, - gen_op_fdivr_ST0_FT0, -}; - -/* NOTE the exception in "r" op ordering */ -static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { - gen_op_fadd_STN_ST0, - gen_op_fmul_STN_ST0, - NULL, - NULL, - gen_op_fsubr_STN_ST0, - gen_op_fsub_STN_ST0, - gen_op_fdivr_STN_ST0, - gen_op_fdiv_STN_ST0, -}; - -/* if d == OR_TMP0, it means memory operand (address in A0) */ -static void gen_op(DisasContext *s1, int op, int ot, int d) -{ - GenOpFunc *gen_update_cc; - - if (d != OR_TMP0) { - gen_op_mov_TN_reg[ot][0][d](); - } else { - gen_op_ld_T0_A0[ot + s1->mem_index](); - } - switch(op) { - case OP_ADCL: - case OP_SBBL: - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - if (d != OR_TMP0) { - gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); - gen_op_mov_reg_T0[ot][d](); - } else { - gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL](); - } - s1->cc_op = CC_OP_DYNAMIC; - goto the_end; - case OP_ADDL: - gen_op_addl_T0_T1(); - s1->cc_op = CC_OP_ADDB + ot; - gen_update_cc = gen_op_update2_cc; - break; - case OP_SUBL: - gen_op_subl_T0_T1(); - s1->cc_op = CC_OP_SUBB + ot; - gen_update_cc = gen_op_update2_cc; - break; - default: - case OP_ANDL: - case OP_ORL: - case OP_XORL: - gen_op_arith_T0_T1_cc[op](); - s1->cc_op = CC_OP_LOGICB + ot; - gen_update_cc = gen_op_update1_cc; - break; - case OP_CMPL: - gen_op_cmpl_T0_T1_cc(); - s1->cc_op = CC_OP_SUBB + ot; - gen_update_cc = NULL; - break; - } - if (op != OP_CMPL) { - if (d != OR_TMP0) - gen_op_mov_reg_T0[ot][d](); - else - gen_op_st_T0_A0[ot + s1->mem_index](); - } - /* the flags update must happen after the memory write (precise - exception support) */ - if (gen_update_cc) - gen_update_cc(); - the_end: ; -} - -/* if d == OR_TMP0, it means memory operand (address in A0) */ -static void gen_inc(DisasContext *s1, int ot, int d, int c) -{ - if (d != OR_TMP0) - gen_op_mov_TN_reg[ot][0][d](); - else - gen_op_ld_T0_A0[ot + s1->mem_index](); - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - if (c > 0) { - gen_op_incl_T0(); - s1->cc_op = CC_OP_INCB + ot; - } else { - gen_op_decl_T0(); - s1->cc_op = CC_OP_DECB + ot; - } - if (d != OR_TMP0) - gen_op_mov_reg_T0[ot][d](); - else - gen_op_st_T0_A0[ot + s1->mem_index](); - gen_op_update_inc_cc(); -} - -static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) -{ - if (d != OR_TMP0) - gen_op_mov_TN_reg[ot][0][d](); - else - gen_op_ld_T0_A0[ot + s1->mem_index](); - if (s != OR_TMP1) - gen_op_mov_TN_reg[ot][1][s](); - /* for zero counts, flags are not updated, so must do it dynamically */ - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - - if (d != OR_TMP0) - gen_op_shift_T0_T1_cc[ot][op](); - else - gen_op_shift_mem_T0_T1_cc[ot][op](); - if (d != OR_TMP0) - gen_op_mov_reg_T0[ot][d](); - s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ -} - -static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) -{ - /* currently not optimized */ - gen_op_movl_T1_im(c); - gen_shift(s1, op, ot, d, OR_TMP1); -} - -static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) -{ - int havesib; - int base, disp; - int index; - int scale; - int opreg; - int mod, rm, code, override, must_add_seg; - - override = s->override; - must_add_seg = s->addseg; - if (override >= 0) - must_add_seg = 1; - mod = (modrm >> 6) & 3; - rm = modrm & 7; - - if (s->aflag) { - - havesib = 0; - base = rm; - index = 0; - scale = 0; - - if (base == 4) { - havesib = 1; - code = ldub(s->pc++); - scale = (code >> 6) & 3; - index = (code >> 3) & 7; - base = code & 7; - } - - switch (mod) { - case 0: - if (base == 5) { - base = -1; - disp = ldl(s->pc); - s->pc += 4; - } else { - disp = 0; - } - break; - case 1: - disp = (int8_t)ldub(s->pc++); - break; - default: - case 2: - disp = ldl(s->pc); - s->pc += 4; - break; - } - - if (base >= 0) { - /* for correct popl handling with esp */ - if (base == 4 && s->popl_esp_hack) - disp += s->popl_esp_hack; - gen_op_movl_A0_reg[base](); - if (disp != 0) - gen_op_addl_A0_im(disp); - } else { - gen_op_movl_A0_im(disp); - } - /* XXX: index == 4 is always invalid */ - if (havesib && (index != 4 || scale != 0)) { - gen_op_addl_A0_reg_sN[scale][index](); - } - if (must_add_seg) { - if (override < 0) { - if (base == R_EBP || base == R_ESP) - override = R_SS; - else - override = R_DS; - } - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); - } - } else { - switch (mod) { - case 0: - if (rm == 6) { - disp = lduw(s->pc); - s->pc += 2; - gen_op_movl_A0_im(disp); - rm = 0; /* avoid SS override */ - goto no_rm; - } else { - disp = 0; - } - break; - case 1: - disp = (int8_t)ldub(s->pc++); - break; - default: - case 2: - disp = lduw(s->pc); - s->pc += 2; - break; - } - switch(rm) { - case 0: - gen_op_movl_A0_reg[R_EBX](); - gen_op_addl_A0_reg_sN[0][R_ESI](); - break; - case 1: - gen_op_movl_A0_reg[R_EBX](); - gen_op_addl_A0_reg_sN[0][R_EDI](); - break; - case 2: - gen_op_movl_A0_reg[R_EBP](); - gen_op_addl_A0_reg_sN[0][R_ESI](); - break; - case 3: - gen_op_movl_A0_reg[R_EBP](); - gen_op_addl_A0_reg_sN[0][R_EDI](); - break; - case 4: - gen_op_movl_A0_reg[R_ESI](); - break; - case 5: - gen_op_movl_A0_reg[R_EDI](); - break; - case 6: - gen_op_movl_A0_reg[R_EBP](); - break; - default: - case 7: - gen_op_movl_A0_reg[R_EBX](); - break; - } - if (disp != 0) - gen_op_addl_A0_im(disp); - gen_op_andl_A0_ffff(); - no_rm: - if (must_add_seg) { - if (override < 0) { - if (rm == 2 || rm == 3 || rm == 6) - override = R_SS; - else - override = R_DS; - } - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); - } - } - - opreg = OR_A0; - disp = 0; - *reg_ptr = opreg; - *offset_ptr = disp; -} - -/* generate modrm memory load or store of 'reg'. TMP0 is used if reg != - OR_TMP0 */ -static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store) -{ - int mod, rm, opreg, disp; - - mod = (modrm >> 6) & 3; - rm = modrm & 7; - if (mod == 3) { - if (is_store) { - if (reg != OR_TMP0) - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_mov_reg_T0[ot][rm](); - } else { - gen_op_mov_TN_reg[ot][0][rm](); - if (reg != OR_TMP0) - gen_op_mov_reg_T0[ot][reg](); - } - } else { - gen_lea_modrm(s, modrm, &opreg, &disp); - if (is_store) { - if (reg != OR_TMP0) - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_st_T0_A0[ot + s->mem_index](); - } else { - gen_op_ld_T0_A0[ot + s->mem_index](); - if (reg != OR_TMP0) - gen_op_mov_reg_T0[ot][reg](); - } - } -} - -static inline uint32_t insn_get(DisasContext *s, int ot) -{ - uint32_t ret; - - switch(ot) { - case OT_BYTE: - ret = ldub(s->pc); - s->pc++; - break; - case OT_WORD: - ret = lduw(s->pc); - s->pc += 2; - break; - default: - case OT_LONG: - ret = ldl(s->pc); - s->pc += 4; - break; - } - return ret; -} - -static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) -{ - TranslationBlock *tb; - int inv, jcc_op; - GenOpFunc3 *func; - - inv = b & 1; - jcc_op = (b >> 1) & 7; - - if (s->jmp_opt) { - switch(s->cc_op) { - /* we optimize the cmp/jcc case */ - case CC_OP_SUBB: - case CC_OP_SUBW: - case CC_OP_SUBL: - func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; - break; - - /* some jumps are easy to compute */ - case CC_OP_ADDB: - case CC_OP_ADDW: - case CC_OP_ADDL: - case CC_OP_ADCB: - case CC_OP_ADCW: - case CC_OP_ADCL: - case CC_OP_SBBB: - case CC_OP_SBBW: - case CC_OP_SBBL: - case CC_OP_LOGICB: - case CC_OP_LOGICW: - case CC_OP_LOGICL: - case CC_OP_INCB: - case CC_OP_INCW: - case CC_OP_INCL: - case CC_OP_DECB: - case CC_OP_DECW: - case CC_OP_DECL: - case CC_OP_SHLB: - case CC_OP_SHLW: - case CC_OP_SHLL: - case CC_OP_SARB: - case CC_OP_SARW: - case CC_OP_SARL: - switch(jcc_op) { - case JCC_Z: - func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; - break; - case JCC_S: - func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; - break; - default: - func = NULL; - break; - } - break; - default: - func = NULL; - break; - } - - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - - if (!func) { - gen_setcc_slow[jcc_op](); - func = gen_op_jcc; - } - - tb = s->tb; - if (!inv) { - func((long)tb, val, next_eip); - } else { - func((long)tb, next_eip, val); - } - s->is_jmp = 3; - } else { - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; - } - gen_setcc_slow[jcc_op](); - if (!inv) { - gen_op_jcc_im(val, next_eip); - } else { - gen_op_jcc_im(next_eip, val); - } - gen_eob(s); - } -} - -static void gen_setcc(DisasContext *s, int b) -{ - int inv, jcc_op; - GenOpFunc *func; - - inv = b & 1; - jcc_op = (b >> 1) & 7; - switch(s->cc_op) { - /* we optimize the cmp/jcc case */ - case CC_OP_SUBB: - case CC_OP_SUBW: - case CC_OP_SUBL: - func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; - if (!func) - goto slow_jcc; - break; - - /* some jumps are easy to compute */ - case CC_OP_ADDB: - case CC_OP_ADDW: - case CC_OP_ADDL: - case CC_OP_LOGICB: - case CC_OP_LOGICW: - case CC_OP_LOGICL: - case CC_OP_INCB: - case CC_OP_INCW: - case CC_OP_INCL: - case CC_OP_DECB: - case CC_OP_DECW: - case CC_OP_DECL: - case CC_OP_SHLB: - case CC_OP_SHLW: - case CC_OP_SHLL: - switch(jcc_op) { - case JCC_Z: - func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; - break; - case JCC_S: - func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; - break; - default: - goto slow_jcc; - } - break; - default: - slow_jcc: - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - func = gen_setcc_slow[jcc_op]; - break; - } - func(); - if (inv) { - gen_op_xor_T0_1(); - } -} - -/* move T0 to seg_reg and compute if the CPU state may change. Never - call this function with seg_reg == R_CS */ -static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) -{ - if (s->pe && !s->vm86) - gen_op_movl_seg_T0(seg_reg, cur_eip); - else - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); - /* abort translation because the register may have a non zero base - or because ss32 may change. For R_SS, translation must always - stop as a special handling must be done to disable hardware - interrupts for the next instruction */ - if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) - s->is_jmp = 3; -} - -/* generate a push. It depends on ss32, addseg and dflag */ -static void gen_push_T0(DisasContext *s) -{ - if (s->ss32) { - if (!s->addseg) { - if (s->dflag) - gen_op_pushl_T0(); - else - gen_op_pushw_T0(); - } else { - if (s->dflag) - gen_op_pushl_ss32_T0(); - else - gen_op_pushw_ss32_T0(); - } - } else { - if (s->dflag) - gen_op_pushl_ss16_T0(); - else - gen_op_pushw_ss16_T0(); - } -} - -/* two step pop is necessary for precise exceptions */ -static void gen_pop_T0(DisasContext *s) -{ - if (s->ss32) { - if (!s->addseg) { - if (s->dflag) - gen_op_popl_T0(); - else - gen_op_popw_T0(); - } else { - if (s->dflag) - gen_op_popl_ss32_T0(); - else - gen_op_popw_ss32_T0(); - } - } else { - if (s->dflag) - gen_op_popl_ss16_T0(); - else - gen_op_popw_ss16_T0(); - } -} - -static inline void gen_stack_update(DisasContext *s, int addend) -{ - if (s->ss32) { - if (addend == 2) - gen_op_addl_ESP_2(); - else if (addend == 4) - gen_op_addl_ESP_4(); - else - gen_op_addl_ESP_im(addend); - } else { - if (addend == 2) - gen_op_addw_ESP_2(); - else if (addend == 4) - gen_op_addw_ESP_4(); - else - gen_op_addw_ESP_im(addend); - } -} - -static void gen_pop_update(DisasContext *s) -{ - gen_stack_update(s, 2 << s->dflag); -} - -static void gen_stack_A0(DisasContext *s) -{ - gen_op_movl_A0_ESP(); - if (!s->ss32) - gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); -} - -/* NOTE: wrap around in 16 bit not fully handled */ -static void gen_pusha(DisasContext *s) -{ - int i; - gen_op_movl_A0_ESP(); - gen_op_addl_A0_im(-16 << s->dflag); - if (!s->ss32) - gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); - for(i = 0;i < 8; i++) { - gen_op_mov_TN_reg[OT_LONG][0][7 - i](); - gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index](); - gen_op_addl_A0_im(2 << s->dflag); - } - gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); -} - -/* NOTE: wrap around in 16 bit not fully handled */ -static void gen_popa(DisasContext *s) -{ - int i; - gen_op_movl_A0_ESP(); - if (!s->ss32) - gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - gen_op_addl_T1_im(16 << s->dflag); - if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); - for(i = 0;i < 8; i++) { - /* ESP is not reloaded */ - if (i != 3) { - gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index](); - gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); - } - gen_op_addl_A0_im(2 << s->dflag); - } - gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); -} - -/* NOTE: wrap around in 16 bit not fully handled */ -/* XXX: check this */ -static void gen_enter(DisasContext *s, int esp_addend, int level) -{ - int ot, level1, addend, opsize; - - ot = s->dflag + OT_WORD; - level &= 0x1f; - level1 = level; - opsize = 2 << s->dflag; - - gen_op_movl_A0_ESP(); - gen_op_addl_A0_im(-opsize); - if (!s->ss32) - gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); - /* push bp */ - gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_st_T0_A0[ot + s->mem_index](); - if (level) { - while (level--) { - gen_op_addl_A0_im(-opsize); - gen_op_addl_T0_im(-opsize); - gen_op_st_T0_A0[ot + s->mem_index](); - } - gen_op_addl_A0_im(-opsize); - /* XXX: add st_T1_A0 ? */ - gen_op_movl_T0_T1(); - gen_op_st_T0_A0[ot + s->mem_index](); - } - gen_op_mov_reg_T1[ot][R_EBP](); - addend = -esp_addend; - if (level1) - addend -= opsize * (level1 + 1); - gen_op_addl_T1_im(addend); - gen_op_mov_reg_T1[ot][R_ESP](); -} - -static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(cur_eip); - gen_op_raise_exception(trapno); - s->is_jmp = 3; -} - -/* an interrupt is different from an exception because of the - priviledge checks */ -static void gen_interrupt(DisasContext *s, int intno, - unsigned int cur_eip, unsigned int next_eip) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(cur_eip); - gen_op_raise_interrupt(intno, next_eip); - s->is_jmp = 3; -} - -static void gen_debug(DisasContext *s, unsigned int cur_eip) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(cur_eip); - gen_op_debug(); - s->is_jmp = 3; -} - -/* generate a generic end of block. Trace exception is also generated - if needed */ -static void gen_eob(DisasContext *s) -{ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - if (s->tf) { - gen_op_raise_exception(EXCP01_SSTP); - } else { - gen_op_movl_T0_0(); - gen_op_exit_tb(); - } - s->is_jmp = 3; -} - -/* generate a jump to eip. No segment change must happen before as a - direct call to the next block may occur */ -static void gen_jmp(DisasContext *s, unsigned int eip) -{ - TranslationBlock *tb = s->tb; - - if (s->jmp_opt) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp((long)tb, eip); - s->is_jmp = 3; - } else { - gen_op_jmp_im(eip); - gen_eob(s); - } -} - -/* convert one instruction. s->is_jmp is set if the translation must - be stopped. Return the next pc value */ -static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) -{ - int b, prefixes, aflag, dflag; - int shift, ot; - int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; - unsigned int next_eip; - - s->pc = pc_start; - prefixes = 0; - aflag = s->code32; - dflag = s->code32; - s->override = -1; - next_byte: - b = ldub(s->pc); - s->pc++; - /* check prefixes */ - switch (b) { - case 0xf3: - prefixes |= PREFIX_REPZ; - goto next_byte; - case 0xf2: - prefixes |= PREFIX_REPNZ; - goto next_byte; - case 0xf0: - prefixes |= PREFIX_LOCK; - goto next_byte; - case 0x2e: - s->override = R_CS; - goto next_byte; - case 0x36: - s->override = R_SS; - goto next_byte; - case 0x3e: - s->override = R_DS; - goto next_byte; - case 0x26: - s->override = R_ES; - goto next_byte; - case 0x64: - s->override = R_FS; - goto next_byte; - case 0x65: - s->override = R_GS; - goto next_byte; - case 0x66: - prefixes |= PREFIX_DATA; - goto next_byte; - case 0x67: - prefixes |= PREFIX_ADR; - goto next_byte; - } - - if (prefixes & PREFIX_DATA) - dflag ^= 1; - if (prefixes & PREFIX_ADR) - aflag ^= 1; - - s->prefix = prefixes; - s->aflag = aflag; - s->dflag = dflag; - - /* lock generation */ - if (prefixes & PREFIX_LOCK) - gen_op_lock(); - - /* now check op code */ - reswitch: - switch(b) { - case 0x0f: - /**************************/ - /* extended op code */ - b = ldub(s->pc++) | 0x100; - goto reswitch; - - /**************************/ - /* arith & logic */ - case 0x00 ... 0x05: - case 0x08 ... 0x0d: - case 0x10 ... 0x15: - case 0x18 ... 0x1d: - case 0x20 ... 0x25: - case 0x28 ... 0x2d: - case 0x30 ... 0x35: - case 0x38 ... 0x3d: - { - int op, f, val; - op = (b >> 3) & 7; - f = (b >> 1) & 3; - - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - switch(f) { - case 0: /* OP Ev, Gv */ - modrm = ldub(s->pc++); - reg = ((modrm >> 3) & 7); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - opreg = OR_TMP0; - } else if (op == OP_XORL && rm == reg) { - xor_zero: - /* xor reg, reg optimisation */ - gen_op_movl_T0_0(); - s->cc_op = CC_OP_LOGICB + ot; - gen_op_mov_reg_T0[ot][reg](); - gen_op_update1_cc(); - break; - } else { - opreg = rm; - } - gen_op_mov_TN_reg[ot][1][reg](); - gen_op(s, op, ot, opreg); - break; - case 1: /* OP Gv, Ev */ - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - reg = ((modrm >> 3) & 7); - rm = modrm & 7; - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot + s->mem_index](); - } else if (op == OP_XORL && rm == reg) { - goto xor_zero; - } else { - gen_op_mov_TN_reg[ot][1][rm](); - } - gen_op(s, op, ot, reg); - break; - case 2: /* OP A, Iv */ - val = insn_get(s, ot); - gen_op_movl_T1_im(val); - gen_op(s, op, ot, OR_EAX); - break; - } - } - break; - - case 0x80: /* GRP1 */ - case 0x81: - case 0x83: - { - int val; - - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - op = (modrm >> 3) & 7; - - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - opreg = OR_TMP0; - } else { - opreg = rm + OR_EAX; - } - - switch(b) { - default: - case 0x80: - case 0x81: - val = insn_get(s, ot); - break; - case 0x83: - val = (int8_t)insn_get(s, OT_BYTE); - break; - } - gen_op_movl_T1_im(val); - gen_op(s, op, ot, opreg); - } - break; - - /**************************/ - /* inc, dec, and other misc arith */ - case 0x40 ... 0x47: /* inc Gv */ - ot = dflag ? OT_LONG : OT_WORD; - gen_inc(s, ot, OR_EAX + (b & 7), 1); - break; - case 0x48 ... 0x4f: /* dec Gv */ - ot = dflag ? OT_LONG : OT_WORD; - gen_inc(s, ot, OR_EAX + (b & 7), -1); - break; - case 0xf6: /* GRP3 */ - case 0xf7: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - op = (modrm >> 3) & 7; - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_TN_reg[ot][0][rm](); - } - - switch(op) { - case 0: /* test */ - val = insn_get(s, ot); - gen_op_movl_T1_im(val); - gen_op_testl_T0_T1_cc(); - s->cc_op = CC_OP_LOGICB + ot; - break; - case 2: /* not */ - gen_op_notl_T0(); - if (mod != 3) { - gen_op_st_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_reg_T0[ot][rm](); - } - break; - case 3: /* neg */ - gen_op_negl_T0(); - if (mod != 3) { - gen_op_st_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_reg_T0[ot][rm](); - } - gen_op_update_neg_cc(); - s->cc_op = CC_OP_SUBB + ot; - break; - case 4: /* mul */ - switch(ot) { - case OT_BYTE: - gen_op_mulb_AL_T0(); - break; - case OT_WORD: - gen_op_mulw_AX_T0(); - break; - default: - case OT_LONG: - gen_op_mull_EAX_T0(); - break; - } - s->cc_op = CC_OP_MUL; - break; - case 5: /* imul */ - switch(ot) { - case OT_BYTE: - gen_op_imulb_AL_T0(); - break; - case OT_WORD: - gen_op_imulw_AX_T0(); - break; - default: - case OT_LONG: - gen_op_imull_EAX_T0(); - break; - } - s->cc_op = CC_OP_MUL; - break; - case 6: /* div */ - switch(ot) { - case OT_BYTE: - gen_op_divb_AL_T0(pc_start - s->cs_base); - break; - case OT_WORD: - gen_op_divw_AX_T0(pc_start - s->cs_base); - break; - default: - case OT_LONG: - gen_op_divl_EAX_T0(pc_start - s->cs_base); - break; - } - break; - case 7: /* idiv */ - switch(ot) { - case OT_BYTE: - gen_op_idivb_AL_T0(pc_start - s->cs_base); - break; - case OT_WORD: - gen_op_idivw_AX_T0(pc_start - s->cs_base); - break; - default: - case OT_LONG: - gen_op_idivl_EAX_T0(pc_start - s->cs_base); - break; - } - break; - default: - goto illegal_op; - } - break; - - case 0xfe: /* GRP4 */ - case 0xff: /* GRP5 */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - op = (modrm >> 3) & 7; - if (op >= 2 && b == 0xfe) { - goto illegal_op; - } - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (op >= 2 && op != 3 && op != 5) - gen_op_ld_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_TN_reg[ot][0][rm](); - } - - switch(op) { - case 0: /* inc Ev */ - if (mod != 3) - opreg = OR_TMP0; - else - opreg = rm; - gen_inc(s, ot, opreg, 1); - break; - case 1: /* dec Ev */ - if (mod != 3) - opreg = OR_TMP0; - else - opreg = rm; - gen_inc(s, ot, opreg, -1); - break; - case 2: /* call Ev */ - /* XXX: optimize if memory (no and is necessary) */ - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); - next_eip = s->pc - s->cs_base; - gen_op_movl_T0_im(next_eip); - gen_push_T0(s); - gen_eob(s); - break; - case 3: /*< lcall Ev */ - gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); - gen_op_ld_T0_A0[OT_WORD + s->mem_index](); - do_lcall: - if (s->pe && !s->vm86) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); - gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base); - } else { - gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); - } - gen_eob(s); - break; - case 4: /* jmp Ev */ - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); - gen_eob(s); - break; - case 5: /* ljmp Ev */ - gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); - gen_op_lduw_T0_A0(); - do_ljmp: - if (s->pe && !s->vm86) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); - gen_op_ljmp_protected_T0_T1(); - } else { - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); - gen_op_movl_T0_T1(); - gen_op_jmp_T0(); - } - gen_eob(s); - break; - case 6: /* push Ev */ - gen_push_T0(s); - break; - default: - goto illegal_op; - } - break; - - case 0x84: /* test Ev, Gv */ - case 0x85: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - reg = (modrm >> 3) & 7; - - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - gen_op_mov_TN_reg[ot][1][reg + OR_EAX](); - gen_op_testl_T0_T1_cc(); - s->cc_op = CC_OP_LOGICB + ot; - break; - - case 0xa8: /* test eAX, Iv */ - case 0xa9: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); - - gen_op_mov_TN_reg[ot][0][OR_EAX](); - gen_op_movl_T1_im(val); - gen_op_testl_T0_T1_cc(); - s->cc_op = CC_OP_LOGICB + ot; - break; - - case 0x98: /* CWDE/CBW */ - if (dflag) - gen_op_movswl_EAX_AX(); - else - gen_op_movsbw_AX_AL(); - break; - case 0x99: /* CDQ/CWD */ - if (dflag) - gen_op_movslq_EDX_EAX(); - else - gen_op_movswl_DX_AX(); - break; - case 0x1af: /* imul Gv, Ev */ - case 0x69: /* imul Gv, Ev, I */ - case 0x6b: - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = ((modrm >> 3) & 7) + OR_EAX; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - if (b == 0x69) { - val = insn_get(s, ot); - gen_op_movl_T1_im(val); - } else if (b == 0x6b) { - val = insn_get(s, OT_BYTE); - gen_op_movl_T1_im(val); - } else { - gen_op_mov_TN_reg[ot][1][reg](); - } - - if (ot == OT_LONG) { - gen_op_imull_T0_T1(); - } else { - gen_op_imulw_T0_T1(); - } - gen_op_mov_reg_T0[ot][reg](); - s->cc_op = CC_OP_MUL; - break; - case 0x1c0: - case 0x1c1: /* xadd Ev, Gv */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - if (mod == 3) { - rm = modrm & 7; - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_mov_TN_reg[ot][1][rm](); - gen_op_addl_T0_T1(); - gen_op_mov_reg_T0[ot][rm](); - gen_op_mov_reg_T1[ot][reg](); - } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_addl_T0_T1(); - gen_op_st_T0_A0[ot + s->mem_index](); - gen_op_mov_reg_T1[ot][reg](); - } - gen_op_update2_cc(); - s->cc_op = CC_OP_ADDB + ot; - break; - case 0x1b0: - case 0x1b1: /* cmpxchg Ev, Gv */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - gen_op_mov_TN_reg[ot][1][reg](); - if (mod == 3) { - rm = modrm & 7; - gen_op_mov_TN_reg[ot][0][rm](); - gen_op_cmpxchg_T0_T1_EAX_cc[ot](); - gen_op_mov_reg_T0[ot][rm](); - } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); - } - s->cc_op = CC_OP_SUBB + ot; - break; - case 0x1c7: /* cmpxchg8b */ - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - if (mod == 3) - goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_cmpxchg8b(); - s->cc_op = CC_OP_EFLAGS; - break; - - /**************************/ - /* push/pop */ - case 0x50 ... 0x57: /* push */ - gen_op_mov_TN_reg[OT_LONG][0][b & 7](); - gen_push_T0(s); - break; - case 0x58 ... 0x5f: /* pop */ - ot = dflag ? OT_LONG : OT_WORD; - gen_pop_T0(s); - gen_op_mov_reg_T0[ot][b & 7](); - gen_pop_update(s); - break; - case 0x60: /* pusha */ - gen_pusha(s); - break; - case 0x61: /* popa */ - gen_popa(s); - break; - case 0x68: /* push Iv */ - case 0x6a: - ot = dflag ? OT_LONG : OT_WORD; - if (b == 0x68) - val = insn_get(s, ot); - else - val = (int8_t)insn_get(s, OT_BYTE); - gen_op_movl_T0_im(val); - gen_push_T0(s); - break; - case 0x8f: /* pop Ev */ - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - gen_pop_T0(s); - s->popl_esp_hack = 2 << dflag; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); - s->popl_esp_hack = 0; - gen_pop_update(s); - break; - case 0xc8: /* enter */ - { - int level; - val = lduw(s->pc); - s->pc += 2; - level = ldub(s->pc++); - gen_enter(s, val, level); - } - break; - case 0xc9: /* leave */ - /* XXX: exception not precise (ESP is updated before potential exception) */ - if (s->ss32) { - gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_mov_reg_T0[OT_LONG][R_ESP](); - } else { - gen_op_mov_TN_reg[OT_WORD][0][R_EBP](); - gen_op_mov_reg_T0[OT_WORD][R_ESP](); - } - gen_pop_T0(s); - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_reg_T0[ot][R_EBP](); - gen_pop_update(s); - break; - case 0x06: /* push es */ - case 0x0e: /* push cs */ - case 0x16: /* push ss */ - case 0x1e: /* push ds */ - gen_op_movl_T0_seg(b >> 3); - gen_push_T0(s); - break; - case 0x1a0: /* push fs */ - case 0x1a8: /* push gs */ - gen_op_movl_T0_seg((b >> 3) & 7); - gen_push_T0(s); - break; - case 0x07: /* pop es */ - case 0x17: /* pop ss */ - case 0x1f: /* pop ds */ - reg = b >> 3; - gen_pop_T0(s); - gen_movl_seg_T0(s, reg, pc_start - s->cs_base); - gen_pop_update(s); - if (reg == R_SS) { - /* if reg == SS, inhibit interrupts/trace */ - gen_op_set_inhibit_irq(); - s->tf = 0; - } - if (s->is_jmp) { - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); - } - break; - case 0x1a1: /* pop fs */ - case 0x1a9: /* pop gs */ - gen_pop_T0(s); - gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); - gen_pop_update(s); - if (s->is_jmp) { - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); - } - break; - - /**************************/ - /* mov */ - case 0x88: - case 0x89: /* mov Gv, Ev */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - - /* generate a generic store */ - gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1); - break; - case 0xc6: - case 0xc7: /* mov Ev, Iv */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - if (mod != 3) - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - val = insn_get(s, ot); - gen_op_movl_T0_im(val); - if (mod != 3) - gen_op_st_T0_A0[ot + s->mem_index](); - else - gen_op_mov_reg_T0[ot][modrm & 7](); - break; - case 0x8a: - case 0x8b: /* mov Ev, Gv */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - gen_op_mov_reg_T0[ot][reg](); - break; - case 0x8e: /* mov seg, Gv */ - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - if (reg >= 6 || reg == R_CS) - goto illegal_op; - gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); - gen_movl_seg_T0(s, reg, pc_start - s->cs_base); - if (reg == R_SS) { - /* if reg == SS, inhibit interrupts/trace */ - gen_op_set_inhibit_irq(); - s->tf = 0; - } - if (s->is_jmp) { - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); - } - break; - case 0x8c: /* mov Gv, seg */ - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - if (reg >= 6) - goto illegal_op; - gen_op_movl_T0_seg(reg); - ot = OT_WORD; - if (mod == 3 && dflag) - ot = OT_LONG; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); - break; - - case 0x1b6: /* movzbS Gv, Eb */ - case 0x1b7: /* movzwS Gv, Eb */ - case 0x1be: /* movsbS Gv, Eb */ - case 0x1bf: /* movswS Gv, Eb */ - { - int d_ot; - /* d_ot is the size of destination */ - d_ot = dflag + OT_WORD; - /* ot is the size of source */ - ot = (b & 1) + OT_BYTE; - modrm = ldub(s->pc++); - reg = ((modrm >> 3) & 7) + OR_EAX; - mod = (modrm >> 6) & 3; - rm = modrm & 7; - - if (mod == 3) { - gen_op_mov_TN_reg[ot][0][rm](); - switch(ot | (b & 8)) { - case OT_BYTE: - gen_op_movzbl_T0_T0(); - break; - case OT_BYTE | 8: - gen_op_movsbl_T0_T0(); - break; - case OT_WORD: - gen_op_movzwl_T0_T0(); - break; - default: - case OT_WORD | 8: - gen_op_movswl_T0_T0(); - break; - } - gen_op_mov_reg_T0[d_ot][reg](); - } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (b & 8) { - gen_op_lds_T0_A0[ot + s->mem_index](); - } else { - gen_op_ldu_T0_A0[ot + s->mem_index](); - } - gen_op_mov_reg_T0[d_ot][reg](); - } - } - break; - - case 0x8d: /* lea */ - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - /* we must ensure that no segment is added */ - s->override = -1; - val = s->addseg; - s->addseg = 0; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - s->addseg = val; - gen_op_mov_reg_A0[ot - OT_WORD][reg](); - break; - - case 0xa0: /* mov EAX, Ov */ - case 0xa1: - case 0xa2: /* mov Ov, EAX */ - case 0xa3: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (s->aflag) - offset_addr = insn_get(s, OT_LONG); - else - offset_addr = insn_get(s, OT_WORD); - gen_op_movl_A0_im(offset_addr); - /* handle override */ - { - int override, must_add_seg; - must_add_seg = s->addseg; - if (s->override >= 0) { - override = s->override; - must_add_seg = 1; - } else { - override = R_DS; - } - if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); - } - } - if ((b & 2) == 0) { - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_mov_reg_T0[ot][R_EAX](); - } else { - gen_op_mov_TN_reg[ot][0][R_EAX](); - gen_op_st_T0_A0[ot + s->mem_index](); - } - break; - case 0xd7: /* xlat */ - gen_op_movl_A0_reg[R_EBX](); - gen_op_addl_A0_AL(); - if (s->aflag == 0) - gen_op_andl_A0_ffff(); - /* handle override */ - { - int override, must_add_seg; - must_add_seg = s->addseg; - override = R_DS; - if (s->override >= 0) { - override = s->override; - must_add_seg = 1; - } else { - override = R_DS; - } - if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); - } - } - gen_op_ldu_T0_A0[OT_BYTE + s->mem_index](); - gen_op_mov_reg_T0[OT_BYTE][R_EAX](); - break; - case 0xb0 ... 0xb7: /* mov R, Ib */ - val = insn_get(s, OT_BYTE); - gen_op_movl_T0_im(val); - gen_op_mov_reg_T0[OT_BYTE][b & 7](); - break; - case 0xb8 ... 0xbf: /* mov R, Iv */ - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); - reg = OR_EAX + (b & 7); - gen_op_movl_T0_im(val); - gen_op_mov_reg_T0[ot][reg](); - break; - - case 0x91 ... 0x97: /* xchg R, EAX */ - ot = dflag ? OT_LONG : OT_WORD; - reg = b & 7; - rm = R_EAX; - goto do_xchg_reg; - case 0x86: - case 0x87: /* xchg Ev, Gv */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - if (mod == 3) { - rm = modrm & 7; - do_xchg_reg: - gen_op_mov_TN_reg[ot][0][reg](); - gen_op_mov_TN_reg[ot][1][rm](); - gen_op_mov_reg_T0[ot][rm](); - gen_op_mov_reg_T1[ot][reg](); - } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_mov_TN_reg[ot][0][reg](); - /* for xchg, lock is implicit */ - if (!(prefixes & PREFIX_LOCK)) - gen_op_lock(); - gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_st_T0_A0[ot + s->mem_index](); - if (!(prefixes & PREFIX_LOCK)) - gen_op_unlock(); - gen_op_mov_reg_T1[ot][reg](); - } - break; - case 0xc4: /* les Gv */ - op = R_ES; - goto do_lxx; - case 0xc5: /* lds Gv */ - op = R_DS; - goto do_lxx; - case 0x1b2: /* lss Gv */ - op = R_SS; - goto do_lxx; - case 0x1b4: /* lfs Gv */ - op = R_FS; - goto do_lxx; - case 0x1b5: /* lgs Gv */ - op = R_GS; - do_lxx: - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - if (mod == 3) - goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); - /* load the segment first to handle exceptions properly */ - gen_op_lduw_T0_A0(); - gen_movl_seg_T0(s, op, pc_start - s->cs_base); - /* then put the data */ - gen_op_mov_reg_T1[ot][reg](); - if (s->is_jmp) { - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); - } - break; - - /************************/ - /* shifts */ - case 0xc0: - case 0xc1: - /* shift Ev,Ib */ - shift = 2; - grp2: - { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - op = (modrm >> 3) & 7; - - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - opreg = OR_TMP0; - } else { - opreg = rm + OR_EAX; - } - - /* simpler op */ - if (shift == 0) { - gen_shift(s, op, ot, opreg, OR_ECX); - } else { - if (shift == 2) { - shift = ldub(s->pc++); - } - gen_shifti(s, op, ot, opreg, shift); - } - } - break; - case 0xd0: - case 0xd1: - /* shift Ev,1 */ - shift = 1; - goto grp2; - case 0xd2: - case 0xd3: - /* shift Ev,cl */ - shift = 0; - goto grp2; - - case 0x1a4: /* shld imm */ - op = 0; - shift = 1; - goto do_shiftd; - case 0x1a5: /* shld cl */ - op = 0; - shift = 0; - goto do_shiftd; - case 0x1ac: /* shrd imm */ - op = 1; - shift = 1; - goto do_shiftd; - case 0x1ad: /* shrd cl */ - op = 1; - shift = 0; - do_shiftd: - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - reg = (modrm >> 3) & 7; - - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_TN_reg[ot][0][rm](); - } - gen_op_mov_TN_reg[ot][1][reg](); - - if (shift) { - val = ldub(s->pc++); - val &= 0x1f; - if (val) { - if (mod == 3) - gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); - else - gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val); - if (op == 0 && ot != OT_WORD) - s->cc_op = CC_OP_SHLB + ot; - else - s->cc_op = CC_OP_SARB + ot; - } - } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - if (mod == 3) - gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); - else - gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op](); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ - } - if (mod == 3) { - gen_op_mov_reg_T0[ot][rm](); - } - break; - - /************************/ - /* floats */ - case 0xd8 ... 0xdf: - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - op = ((b & 7) << 3) | ((modrm >> 3) & 7); - - if (mod != 3) { - /* memory op */ - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - switch(op) { - case 0x00 ... 0x07: /* fxxxs */ - case 0x10 ... 0x17: /* fixxxl */ - case 0x20 ... 0x27: /* fxxxl */ - case 0x30 ... 0x37: /* fixxx */ - { - int op1; - op1 = op & 7; - - switch(op >> 4) { - case 0: - gen_op_flds_FT0_A0(); - break; - case 1: - gen_op_fildl_FT0_A0(); - break; - case 2: - gen_op_fldl_FT0_A0(); - break; - case 3: - default: - gen_op_fild_FT0_A0(); - break; - } - - gen_op_fp_arith_ST0_FT0[op1](); - if (op1 == 3) { - /* fcomp needs pop */ - gen_op_fpop(); - } - } - break; - case 0x08: /* flds */ - case 0x0a: /* fsts */ - case 0x0b: /* fstps */ - case 0x18: /* fildl */ - case 0x1a: /* fistl */ - case 0x1b: /* fistpl */ - case 0x28: /* fldl */ - case 0x2a: /* fstl */ - case 0x2b: /* fstpl */ - case 0x38: /* filds */ - case 0x3a: /* fists */ - case 0x3b: /* fistps */ - - switch(op & 7) { - case 0: - switch(op >> 4) { - case 0: - gen_op_flds_ST0_A0(); - break; - case 1: - gen_op_fildl_ST0_A0(); - break; - case 2: - gen_op_fldl_ST0_A0(); - break; - case 3: - default: - gen_op_fild_ST0_A0(); - break; - } - break; - default: - switch(op >> 4) { - case 0: - gen_op_fsts_ST0_A0(); - break; - case 1: - gen_op_fistl_ST0_A0(); - break; - case 2: - gen_op_fstl_ST0_A0(); - break; - case 3: - default: - gen_op_fist_ST0_A0(); - break; - } - if ((op & 7) == 3) - gen_op_fpop(); - break; - } - break; - case 0x0c: /* fldenv mem */ - gen_op_fldenv_A0(s->dflag); - break; - case 0x0d: /* fldcw mem */ - gen_op_fldcw_A0(); - break; - case 0x0e: /* fnstenv mem */ - gen_op_fnstenv_A0(s->dflag); - break; - case 0x0f: /* fnstcw mem */ - gen_op_fnstcw_A0(); - break; - case 0x1d: /* fldt mem */ - gen_op_fldt_ST0_A0(); - break; - case 0x1f: /* fstpt mem */ - gen_op_fstt_ST0_A0(); - gen_op_fpop(); - break; - case 0x2c: /* frstor mem */ - gen_op_frstor_A0(s->dflag); - break; - case 0x2e: /* fnsave mem */ - gen_op_fnsave_A0(s->dflag); - break; - case 0x2f: /* fnstsw mem */ - gen_op_fnstsw_A0(); - break; - case 0x3c: /* fbld */ - gen_op_fbld_ST0_A0(); - break; - case 0x3e: /* fbstp */ - gen_op_fbst_ST0_A0(); - gen_op_fpop(); - break; - case 0x3d: /* fildll */ - gen_op_fildll_ST0_A0(); - break; - case 0x3f: /* fistpll */ - gen_op_fistll_ST0_A0(); - gen_op_fpop(); - break; - default: - goto illegal_op; - } - } else { - /* register float ops */ - opreg = rm; - - switch(op) { - case 0x08: /* fld sti */ - gen_op_fpush(); - gen_op_fmov_ST0_STN((opreg + 1) & 7); - break; - case 0x09: /* fxchg sti */ - gen_op_fxchg_ST0_STN(opreg); - break; - case 0x0a: /* grp d9/2 */ - switch(rm) { - case 0: /* fnop */ - break; - default: - goto illegal_op; - } - break; - case 0x0c: /* grp d9/4 */ - switch(rm) { - case 0: /* fchs */ - gen_op_fchs_ST0(); - break; - case 1: /* fabs */ - gen_op_fabs_ST0(); - break; - case 4: /* ftst */ - gen_op_fldz_FT0(); - gen_op_fcom_ST0_FT0(); - break; - case 5: /* fxam */ - gen_op_fxam_ST0(); - break; - default: - goto illegal_op; - } - break; - case 0x0d: /* grp d9/5 */ - { - switch(rm) { - case 0: - gen_op_fpush(); - gen_op_fld1_ST0(); - break; - case 1: - gen_op_fpush(); - gen_op_fldl2t_ST0(); - break; - case 2: - gen_op_fpush(); - gen_op_fldl2e_ST0(); - break; - case 3: - gen_op_fpush(); - gen_op_fldpi_ST0(); - break; - case 4: - gen_op_fpush(); - gen_op_fldlg2_ST0(); - break; - case 5: - gen_op_fpush(); - gen_op_fldln2_ST0(); - break; - case 6: - gen_op_fpush(); - gen_op_fldz_ST0(); - break; - default: - goto illegal_op; - } - } - break; - case 0x0e: /* grp d9/6 */ - switch(rm) { - case 0: /* f2xm1 */ - gen_op_f2xm1(); - break; - case 1: /* fyl2x */ - gen_op_fyl2x(); - break; - case 2: /* fptan */ - gen_op_fptan(); - break; - case 3: /* fpatan */ - gen_op_fpatan(); - break; - case 4: /* fxtract */ - gen_op_fxtract(); - break; - case 5: /* fprem1 */ - gen_op_fprem1(); - break; - case 6: /* fdecstp */ - gen_op_fdecstp(); - break; - default: - case 7: /* fincstp */ - gen_op_fincstp(); - break; - } - break; - case 0x0f: /* grp d9/7 */ - switch(rm) { - case 0: /* fprem */ - gen_op_fprem(); - break; - case 1: /* fyl2xp1 */ - gen_op_fyl2xp1(); - break; - case 2: /* fsqrt */ - gen_op_fsqrt(); - break; - case 3: /* fsincos */ - gen_op_fsincos(); - break; - case 5: /* fscale */ - gen_op_fscale(); - break; - case 4: /* frndint */ - gen_op_frndint(); - break; - case 6: /* fsin */ - gen_op_fsin(); - break; - default: - case 7: /* fcos */ - gen_op_fcos(); - break; - } - break; - case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ - case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ - case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ - { - int op1; - - op1 = op & 7; - if (op >= 0x20) { - gen_op_fp_arith_STN_ST0[op1](opreg); - if (op >= 0x30) - gen_op_fpop(); - } else { - gen_op_fmov_FT0_STN(opreg); - gen_op_fp_arith_ST0_FT0[op1](); - } - } - break; - case 0x02: /* fcom */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fcom_ST0_FT0(); - break; - case 0x03: /* fcomp */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fcom_ST0_FT0(); - gen_op_fpop(); - break; - case 0x15: /* da/5 */ - switch(rm) { - case 1: /* fucompp */ - gen_op_fmov_FT0_STN(1); - gen_op_fucom_ST0_FT0(); - gen_op_fpop(); - gen_op_fpop(); - break; - default: - goto illegal_op; - } - break; - case 0x1c: - switch(rm) { - case 0: /* feni (287 only, just do nop here) */ - break; - case 1: /* fdisi (287 only, just do nop here) */ - break; - case 2: /* fclex */ - gen_op_fclex(); - break; - case 3: /* fninit */ - gen_op_fninit(); - break; - case 4: /* fsetpm (287 only, just do nop here) */ - break; - default: - goto illegal_op; - } - break; - case 0x1d: /* fucomi */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fucomi_ST0_FT0(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0x1e: /* fcomi */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fcomi_ST0_FT0(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0x2a: /* fst sti */ - gen_op_fmov_STN_ST0(opreg); - break; - case 0x2b: /* fstp sti */ - gen_op_fmov_STN_ST0(opreg); - gen_op_fpop(); - break; - case 0x2c: /* fucom st(i) */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fucom_ST0_FT0(); - break; - case 0x2d: /* fucomp st(i) */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fucom_ST0_FT0(); - gen_op_fpop(); - break; - case 0x33: /* de/3 */ - switch(rm) { - case 1: /* fcompp */ - gen_op_fmov_FT0_STN(1); - gen_op_fcom_ST0_FT0(); - gen_op_fpop(); - gen_op_fpop(); - break; - default: - goto illegal_op; - } - break; - case 0x3c: /* df/4 */ - switch(rm) { - case 0: - gen_op_fnstsw_EAX(); - break; - default: - goto illegal_op; - } - break; - case 0x3d: /* fucomip */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fucomi_ST0_FT0(); - gen_op_fpop(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0x3e: /* fcomip */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fcomi_ST0_FT0(); - gen_op_fpop(); - s->cc_op = CC_OP_EFLAGS; - break; - default: - goto illegal_op; - } - } - break; - /************************/ - /* string ops */ - - case 0xa4: /* movsS */ - case 0xa5: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - } else { - gen_movs(s, ot); - } - break; - - case 0xaa: /* stosS */ - case 0xab: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - } else { - gen_stos(s, ot); - } - break; - case 0xac: /* lodsS */ - case 0xad: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - } else { - gen_lods(s, ot); - } - break; - case 0xae: /* scasS */ - case 0xaf: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPNZ) { - gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); - } else if (prefixes & PREFIX_REPZ) { - gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); - } else { - gen_scas(s, ot); - s->cc_op = CC_OP_SUBB + ot; - } - break; - - case 0xa6: /* cmpsS */ - case 0xa7: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPNZ) { - gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); - } else if (prefixes & PREFIX_REPZ) { - gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); - } else { - gen_cmps(s, ot); - s->cc_op = CC_OP_SUBB + ot; - } - break; - case 0x6c: /* insS */ - case 0x6d: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - /* NOTE: even for (E)CX = 0 the exception is raised */ - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - } else { - gen_ins(s, ot); - } - } - break; - case 0x6e: /* outsS */ - case 0x6f: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - /* NOTE: even for (E)CX = 0 the exception is raised */ - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - } else { - gen_outs(s, ot); - } - } - break; - - /************************/ - /* port I/O */ - case 0xe4: - case 0xe5: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = ldub(s->pc++); - gen_op_movl_T0_im(val); - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); - } - break; - case 0xe6: - case 0xe7: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = ldub(s->pc++); - gen_op_movl_T0_im(val); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); - } - break; - case 0xec: - case 0xed: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); - } - break; - case 0xee: - case 0xef: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); - } - break; - - /************************/ - /* control */ - case 0xc2: /* ret im */ - val = ldsw(s->pc); - s->pc += 2; - gen_pop_T0(s); - gen_stack_update(s, val + (2 << s->dflag)); - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); - gen_eob(s); - break; - case 0xc3: /* ret */ - gen_pop_T0(s); - gen_pop_update(s); - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); - gen_eob(s); - break; - case 0xca: /* lret im */ - val = ldsw(s->pc); - s->pc += 2; - do_lret: - if (s->pe && !s->vm86) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); - gen_op_lret_protected(s->dflag, val); - } else { - gen_stack_A0(s); - /* pop offset */ - gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - /* NOTE: keeping EIP updated is not a problem in case of - exception */ - gen_op_jmp_T0(); - /* pop selector */ - gen_op_addl_A0_im(2 << s->dflag); - gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); - /* add stack offset */ - gen_stack_update(s, val + (4 << s->dflag)); - } - gen_eob(s); - break; - case 0xcb: /* lret */ - val = 0; - goto do_lret; - case 0xcf: /* iret */ - if (!s->pe) { - /* real mode */ - gen_op_iret_real(s->dflag); - s->cc_op = CC_OP_EFLAGS; - } else if (s->vm86 && s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); - gen_op_iret_protected(s->dflag); - s->cc_op = CC_OP_EFLAGS; - } - gen_eob(s); - break; - case 0xe8: /* call im */ - { - unsigned int next_eip; - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); - next_eip = s->pc - s->cs_base; - val += next_eip; - if (s->dflag == 0) - val &= 0xffff; - gen_op_movl_T0_im(next_eip); - gen_push_T0(s); - gen_jmp(s, val); - } - break; - case 0x9a: /* lcall im */ - { - unsigned int selector, offset; - - ot = dflag ? OT_LONG : OT_WORD; - offset = insn_get(s, ot); - selector = insn_get(s, OT_WORD); - - gen_op_movl_T0_im(selector); - gen_op_movl_T1_im(offset); - } - goto do_lcall; - case 0xe9: /* jmp */ - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); - val += s->pc - s->cs_base; - if (s->dflag == 0) - val = val & 0xffff; - gen_jmp(s, val); - break; - case 0xea: /* ljmp im */ - { - unsigned int selector, offset; - - ot = dflag ? OT_LONG : OT_WORD; - offset = insn_get(s, ot); - selector = insn_get(s, OT_WORD); - - gen_op_movl_T0_im(selector); - gen_op_movl_T1_im(offset); - } - goto do_ljmp; - case 0xeb: /* jmp Jb */ - val = (int8_t)insn_get(s, OT_BYTE); - val += s->pc - s->cs_base; - if (s->dflag == 0) - val = val & 0xffff; - gen_jmp(s, val); - break; - case 0x70 ... 0x7f: /* jcc Jb */ - val = (int8_t)insn_get(s, OT_BYTE); - goto do_jcc; - case 0x180 ... 0x18f: /* jcc Jv */ - if (dflag) { - val = insn_get(s, OT_LONG); - } else { - val = (int16_t)insn_get(s, OT_WORD); - } - do_jcc: - next_eip = s->pc - s->cs_base; - val += next_eip; - if (s->dflag == 0) - val &= 0xffff; - gen_jcc(s, b, val, next_eip); - break; - - case 0x190 ... 0x19f: /* setcc Gv */ - modrm = ldub(s->pc++); - gen_setcc(s, b); - gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); - break; - case 0x140 ... 0x14f: /* cmov Gv, Ev */ - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - gen_setcc(s, b); - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[ot + s->mem_index](); - } else { - rm = modrm & 7; - gen_op_mov_TN_reg[ot][1][rm](); - } - gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); - break; - - /************************/ - /* flags */ - case 0x9c: /* pushf */ - if (s->vm86 && s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_movl_T0_eflags(); - gen_push_T0(s); - } - break; - case 0x9d: /* popf */ - if (s->vm86 && s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_pop_T0(s); - if (s->cpl == 0) { - if (s->dflag) { - gen_op_movl_eflags_T0_cpl0(); - } else { - gen_op_movw_eflags_T0_cpl0(); - } - } else { - if (s->dflag) { - gen_op_movl_eflags_T0(); - } else { - gen_op_movw_eflags_T0(); - } - } - gen_pop_update(s); - s->cc_op = CC_OP_EFLAGS; - /* abort translation because TF flag may change */ - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); - } - break; - case 0x9e: /* sahf */ - gen_op_mov_TN_reg[OT_BYTE][0][R_AH](); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_movb_eflags_T0(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0x9f: /* lahf */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_movl_T0_eflags(); - gen_op_mov_reg_T0[OT_BYTE][R_AH](); - break; - case 0xf5: /* cmc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_cmc(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0xf8: /* clc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_clc(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0xf9: /* stc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_stc(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0xfc: /* cld */ - gen_op_cld(); - break; - case 0xfd: /* std */ - gen_op_std(); - break; - - /************************/ - /* bit operations */ - case 0x1ba: /* bt/bts/btr/btc Gv, im */ - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - op = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - rm = modrm & 7; - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_TN_reg[ot][0][rm](); - } - /* load shift */ - val = ldub(s->pc++); - gen_op_movl_T1_im(val); - if (op < 4) - goto illegal_op; - op -= 4; - gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); - s->cc_op = CC_OP_SARB + ot; - if (op != 0) { - if (mod != 3) - gen_op_st_T0_A0[ot + s->mem_index](); - else - gen_op_mov_reg_T0[ot][rm](); - gen_op_update_bt_cc(); - } - break; - case 0x1a3: /* bt Gv, Ev */ - op = 0; - goto do_btx; - case 0x1ab: /* bts */ - op = 1; - goto do_btx; - case 0x1b3: /* btr */ - op = 2; - goto do_btx; - case 0x1bb: /* btc */ - op = 3; - do_btx: - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - rm = modrm & 7; - gen_op_mov_TN_reg[OT_LONG][1][reg](); - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - /* specific case: we need to add a displacement */ - if (ot == OT_WORD) - gen_op_add_bitw_A0_T1(); - else - gen_op_add_bitl_A0_T1(); - gen_op_ld_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_TN_reg[ot][0][rm](); - } - gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); - s->cc_op = CC_OP_SARB + ot; - if (op != 0) { - if (mod != 3) - gen_op_st_T0_A0[ot + s->mem_index](); - else - gen_op_mov_reg_T0[ot][rm](); - gen_op_update_bt_cc(); - } - break; - case 0x1bc: /* bsf */ - case 0x1bd: /* bsr */ - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - gen_op_bsx_T0_cc[ot - OT_WORD][b & 1](); - /* NOTE: we always write back the result. Intel doc says it is - undefined if T0 == 0 */ - gen_op_mov_reg_T0[ot][reg](); - s->cc_op = CC_OP_LOGICB + ot; - break; - /************************/ - /* bcd */ - case 0x27: /* daa */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_daa(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0x2f: /* das */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_das(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0x37: /* aaa */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_aaa(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0x3f: /* aas */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_aas(); - s->cc_op = CC_OP_EFLAGS; - break; - case 0xd4: /* aam */ - val = ldub(s->pc++); - gen_op_aam(val); - s->cc_op = CC_OP_LOGICB; - break; - case 0xd5: /* aad */ - val = ldub(s->pc++); - gen_op_aad(val); - s->cc_op = CC_OP_LOGICB; - break; - /************************/ - /* misc */ - case 0x90: /* nop */ - break; - case 0x9b: /* fwait */ - break; - case 0xcc: /* int3 */ - gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); - break; - case 0xcd: /* int N */ - val = ldub(s->pc++); - /* XXX: add error code for vm86 GPF */ - if (!s->vm86) - gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); - else - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - break; - case 0xce: /* into */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_into(s->pc - s->cs_base); - break; - case 0xf1: /* icebp (undocumented, exits to external debugger) */ - gen_debug(s, pc_start - s->cs_base); - break; - case 0xfa: /* cli */ - if (!s->vm86) { - if (s->cpl <= s->iopl) { - gen_op_cli(); - } else { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } - } else { - if (s->iopl == 3) { - gen_op_cli(); - } else { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } - } - break; - case 0xfb: /* sti */ - if (!s->vm86) { - if (s->cpl <= s->iopl) { - gen_sti: - gen_op_sti(); - /* interruptions are enabled only the first insn after sti */ - gen_op_set_inhibit_irq(); - /* give a chance to handle pending irqs */ - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); - } else { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } - } else { - if (s->iopl == 3) { - goto gen_sti; - } else { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } - } - break; - case 0x62: /* bound */ - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - mod = (modrm >> 6) & 3; - if (mod == 3) - goto illegal_op; - gen_op_mov_reg_T0[ot][reg](); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (ot == OT_WORD) - gen_op_boundw(pc_start - s->cs_base); - else - gen_op_boundl(pc_start - s->cs_base); - break; - case 0x1c8 ... 0x1cf: /* bswap reg */ - reg = b & 7; - gen_op_mov_TN_reg[OT_LONG][0][reg](); - gen_op_bswapl_T0(); - gen_op_mov_reg_T0[OT_LONG][reg](); - break; - case 0xd6: /* salc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_salc(); - break; - case 0xe0: /* loopnz */ - case 0xe1: /* loopz */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - /* FALL THRU */ - case 0xe2: /* loop */ - case 0xe3: /* jecxz */ - val = (int8_t)insn_get(s, OT_BYTE); - next_eip = s->pc - s->cs_base; - val += next_eip; - if (s->dflag == 0) - val &= 0xffff; - gen_op_loop[s->aflag][b & 3](val, next_eip); - gen_eob(s); - break; - case 0x130: /* wrmsr */ - case 0x132: /* rdmsr */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if (b & 2) - gen_op_rdmsr(); - else - gen_op_wrmsr(); - } - break; - case 0x131: /* rdtsc */ - gen_op_rdtsc(); - break; - case 0x1a2: /* cpuid */ - gen_op_cpuid(); - break; - case 0xf4: /* hlt */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(s->pc - s->cs_base); - gen_op_hlt(); - s->is_jmp = 3; - } - break; - case 0x100: - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - op = (modrm >> 3) & 7; - switch(op) { - case 0: /* sldt */ - gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); - ot = OT_WORD; - if (mod == 3) - ot += s->dflag; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); - break; - case 2: /* lldt */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); - gen_op_jmp_im(pc_start - s->cs_base); - gen_op_lldt_T0(); - } - break; - case 1: /* str */ - gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); - ot = OT_WORD; - if (mod == 3) - ot += s->dflag; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); - break; - case 3: /* ltr */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); - gen_op_jmp_im(pc_start - s->cs_base); - gen_op_ltr_T0(); - } - break; - case 4: /* verr */ - case 5: /* verw */ - default: - goto illegal_op; - } - break; - case 0x101: - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - op = (modrm >> 3) & 7; - switch(op) { - case 0: /* sgdt */ - case 1: /* sidt */ - if (mod == 3) - goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (op == 0) - gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); - else - gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); - gen_op_st_T0_A0[OT_WORD + s->mem_index](); - gen_op_addl_A0_im(2); - if (op == 0) - gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); - else - gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); - if (!s->dflag) - gen_op_andl_T0_im(0xffffff); - gen_op_st_T0_A0[OT_LONG + s->mem_index](); - break; - case 2: /* lgdt */ - case 3: /* lidt */ - if (mod == 3) - goto illegal_op; - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T1_A0[OT_WORD + s->mem_index](); - gen_op_addl_A0_im(2); - gen_op_ld_T0_A0[OT_LONG + s->mem_index](); - if (!s->dflag) - gen_op_andl_T0_im(0xffffff); - if (op == 2) { - gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base)); - gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit)); - } else { - gen_op_movl_env_T0(offsetof(CPUX86State,idt.base)); - gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit)); - } - } - break; - case 4: /* smsw */ - gen_op_movl_T0_env(offsetof(CPUX86State,cr[0])); - gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); - break; - case 6: /* lmsw */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); - gen_op_lmsw_T0(); - } - break; - case 7: /* invlpg */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if (mod == 3) - goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_invlpg_A0(); - } - break; - default: - goto illegal_op; - } - break; - case 0x102: /* lar */ - case 0x103: /* lsl */ - if (!s->pe || s->vm86) - goto illegal_op; - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); - reg = (modrm >> 3) & 7; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - gen_op_mov_TN_reg[ot][1][reg](); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - if (b == 0x102) - gen_op_lar(); - else - gen_op_lsl(); - s->cc_op = CC_OP_EFLAGS; - gen_op_mov_reg_T1[ot][reg](); - break; - case 0x118: - modrm = ldub(s->pc++); - mod = (modrm >> 6) & 3; - op = (modrm >> 3) & 7; - switch(op) { - case 0: /* prefetchnta */ - case 1: /* prefetchnt0 */ - case 2: /* prefetchnt0 */ - case 3: /* prefetchnt0 */ - if (mod == 3) - goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - /* nothing more to do */ - break; - default: - goto illegal_op; - } - break; - case 0x120: /* mov reg, crN */ - case 0x122: /* mov crN, reg */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - modrm = ldub(s->pc++); - if ((modrm & 0xc0) != 0xc0) - goto illegal_op; - rm = modrm & 7; - reg = (modrm >> 3) & 7; - switch(reg) { - case 0: - case 2: - case 3: - case 4: - if (b & 2) { - gen_op_mov_TN_reg[OT_LONG][0][rm](); - gen_op_movl_crN_T0(reg); - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); - } else { - gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); - gen_op_mov_reg_T0[OT_LONG][rm](); - } - break; - default: - goto illegal_op; - } - } - break; - case 0x121: /* mov reg, drN */ - case 0x123: /* mov drN, reg */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - modrm = ldub(s->pc++); - if ((modrm & 0xc0) != 0xc0) - goto illegal_op; - rm = modrm & 7; - reg = (modrm >> 3) & 7; - /* XXX: do it dynamically with CR4.DE bit */ - if (reg == 4 || reg == 5) - goto illegal_op; - if (b & 2) { - gen_op_mov_TN_reg[OT_LONG][0][rm](); - gen_op_movl_drN_T0(reg); - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); - } else { - gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); - gen_op_mov_reg_T0[OT_LONG][rm](); - } - } - break; - case 0x106: /* clts */ - if (s->cpl != 0) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - gen_op_clts(); - } - break; - default: - goto illegal_op; - } - /* lock generation */ - if (s->prefix & PREFIX_LOCK) - gen_op_unlock(); - return s->pc; - illegal_op: - /* XXX: ensure that no lock was generated */ - gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); - return s->pc; -} - -#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) -#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P) - -/* flags read by an operation */ -static uint16_t opc_read_flags[NB_OPS] = { - [INDEX_op_aas] = CC_A, - [INDEX_op_aaa] = CC_A, - [INDEX_op_das] = CC_A | CC_C, - [INDEX_op_daa] = CC_A | CC_C, - - [INDEX_op_adcb_T0_T1_cc] = CC_C, - [INDEX_op_adcw_T0_T1_cc] = CC_C, - [INDEX_op_adcl_T0_T1_cc] = CC_C, - [INDEX_op_sbbb_T0_T1_cc] = CC_C, - [INDEX_op_sbbw_T0_T1_cc] = CC_C, - [INDEX_op_sbbl_T0_T1_cc] = CC_C, - - [INDEX_op_adcb_mem_T0_T1_cc] = CC_C, - [INDEX_op_adcw_mem_T0_T1_cc] = CC_C, - [INDEX_op_adcl_mem_T0_T1_cc] = CC_C, - [INDEX_op_sbbb_mem_T0_T1_cc] = CC_C, - [INDEX_op_sbbw_mem_T0_T1_cc] = CC_C, - [INDEX_op_sbbl_mem_T0_T1_cc] = CC_C, - - /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_update_inc_cc] = CC_C, - - [INDEX_op_into] = CC_O, - - [INDEX_op_jb_subb] = CC_C, - [INDEX_op_jb_subw] = CC_C, - [INDEX_op_jb_subl] = CC_C, - - [INDEX_op_jz_subb] = CC_Z, - [INDEX_op_jz_subw] = CC_Z, - [INDEX_op_jz_subl] = CC_Z, - - [INDEX_op_jbe_subb] = CC_Z | CC_C, - [INDEX_op_jbe_subw] = CC_Z | CC_C, - [INDEX_op_jbe_subl] = CC_Z | CC_C, - - [INDEX_op_js_subb] = CC_S, - [INDEX_op_js_subw] = CC_S, - [INDEX_op_js_subl] = CC_S, - - [INDEX_op_jl_subb] = CC_O | CC_S, - [INDEX_op_jl_subw] = CC_O | CC_S, - [INDEX_op_jl_subl] = CC_O | CC_S, - - [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z, - [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z, - [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z, - - [INDEX_op_loopnzw] = CC_Z, - [INDEX_op_loopnzl] = CC_Z, - [INDEX_op_loopzw] = CC_Z, - [INDEX_op_loopzl] = CC_Z, - - [INDEX_op_seto_T0_cc] = CC_O, - [INDEX_op_setb_T0_cc] = CC_C, - [INDEX_op_setz_T0_cc] = CC_Z, - [INDEX_op_setbe_T0_cc] = CC_Z | CC_C, - [INDEX_op_sets_T0_cc] = CC_S, - [INDEX_op_setp_T0_cc] = CC_P, - [INDEX_op_setl_T0_cc] = CC_O | CC_S, - [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z, - - [INDEX_op_setb_T0_subb] = CC_C, - [INDEX_op_setb_T0_subw] = CC_C, - [INDEX_op_setb_T0_subl] = CC_C, - - [INDEX_op_setz_T0_subb] = CC_Z, - [INDEX_op_setz_T0_subw] = CC_Z, - [INDEX_op_setz_T0_subl] = CC_Z, - - [INDEX_op_setbe_T0_subb] = CC_Z | CC_C, - [INDEX_op_setbe_T0_subw] = CC_Z | CC_C, - [INDEX_op_setbe_T0_subl] = CC_Z | CC_C, - - [INDEX_op_sets_T0_subb] = CC_S, - [INDEX_op_sets_T0_subw] = CC_S, - [INDEX_op_sets_T0_subl] = CC_S, - - [INDEX_op_setl_T0_subb] = CC_O | CC_S, - [INDEX_op_setl_T0_subw] = CC_O | CC_S, - [INDEX_op_setl_T0_subl] = CC_O | CC_S, - - [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z, - [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z, - [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, - - [INDEX_op_movl_T0_eflags] = CC_OSZAPC, - [INDEX_op_cmc] = CC_C, - [INDEX_op_salc] = CC_C, - - [INDEX_op_rclb_T0_T1_cc] = CC_C, - [INDEX_op_rclw_T0_T1_cc] = CC_C, - [INDEX_op_rcll_T0_T1_cc] = CC_C, - [INDEX_op_rcrb_T0_T1_cc] = CC_C, - [INDEX_op_rcrw_T0_T1_cc] = CC_C, - [INDEX_op_rcrl_T0_T1_cc] = CC_C, - - [INDEX_op_rclb_mem_T0_T1_cc] = CC_C, - [INDEX_op_rclw_mem_T0_T1_cc] = CC_C, - [INDEX_op_rcll_mem_T0_T1_cc] = CC_C, - [INDEX_op_rcrb_mem_T0_T1_cc] = CC_C, - [INDEX_op_rcrw_mem_T0_T1_cc] = CC_C, - [INDEX_op_rcrl_mem_T0_T1_cc] = CC_C, -}; - -/* flags written by an operation */ -static uint16_t opc_write_flags[NB_OPS] = { - [INDEX_op_update2_cc] = CC_OSZAPC, - [INDEX_op_update1_cc] = CC_OSZAPC, - [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_update_neg_cc] = CC_OSZAPC, - /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_update_inc_cc] = CC_OSZAPC, - [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_mulb_AL_T0] = CC_OSZAPC, - [INDEX_op_imulb_AL_T0] = CC_OSZAPC, - [INDEX_op_mulw_AX_T0] = CC_OSZAPC, - [INDEX_op_imulw_AX_T0] = CC_OSZAPC, - [INDEX_op_mull_EAX_T0] = CC_OSZAPC, - [INDEX_op_imull_EAX_T0] = CC_OSZAPC, - [INDEX_op_imulw_T0_T1] = CC_OSZAPC, - [INDEX_op_imull_T0_T1] = CC_OSZAPC, - - /* bcd */ - [INDEX_op_aam] = CC_OSZAPC, - [INDEX_op_aad] = CC_OSZAPC, - [INDEX_op_aas] = CC_OSZAPC, - [INDEX_op_aaa] = CC_OSZAPC, - [INDEX_op_das] = CC_OSZAPC, - [INDEX_op_daa] = CC_OSZAPC, - - [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, - [INDEX_op_movw_eflags_T0] = CC_OSZAPC, - [INDEX_op_movl_eflags_T0] = CC_OSZAPC, - [INDEX_op_clc] = CC_C, - [INDEX_op_stc] = CC_C, - [INDEX_op_cmc] = CC_C, - - [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C, - - [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C, - - [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC, - - [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC, - - [INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C, - - [INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C, - - [INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC, - - [INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC, - - [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_bsfw_T0_cc] = CC_OSZAPC, - [INDEX_op_bsfl_T0_cc] = CC_OSZAPC, - [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, - [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, - - [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, - - [INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC, - - [INDEX_op_cmpxchg8b] = CC_Z, - [INDEX_op_lar] = CC_Z, - [INDEX_op_lsl] = CC_Z, - [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, - [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, -}; - -/* simpler form of an operation if no flags need to be generated */ -static uint16_t opc_simpler[NB_OPS] = { - [INDEX_op_update2_cc] = INDEX_op_nop, - [INDEX_op_update1_cc] = INDEX_op_nop, - [INDEX_op_update_neg_cc] = INDEX_op_nop, -#if 0 - /* broken: CC_OP logic must be rewritten */ - [INDEX_op_update_inc_cc] = INDEX_op_nop, -#endif - [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1, - [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1, - [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1, - - [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1, - [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1, - [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1, - - [INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1, - [INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1, - [INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1, - - [INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1, - [INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1, - [INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1, - - [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, - [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, - [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1, - - [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1, - [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1, - [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1, - - [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1, - [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1, - [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, -}; - -void optimize_flags_init(void) -{ - int i; - /* put default values in arrays */ - for(i = 0; i < NB_OPS; i++) { - if (opc_simpler[i] == 0) - opc_simpler[i] = i; - } -} - -/* CPU flags computation optimization: we move backward thru the - generated code to see which flags are needed. The operation is - modified if suitable */ -static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) -{ - uint16_t *opc_ptr; - int live_flags, write_flags, op; - - opc_ptr = opc_buf + opc_buf_len; - /* live_flags contains the flags needed by the next instructions - in the code. At the end of the bloc, we consider that all the - flags are live. */ - live_flags = CC_OSZAPC; - while (opc_ptr > opc_buf) { - op = *--opc_ptr; - /* if none of the flags written by the instruction is used, - then we can try to find a simpler instruction */ - write_flags = opc_write_flags[op]; - if ((live_flags & write_flags) == 0) { - *opc_ptr = opc_simpler[op]; - } - /* compute the live flags before the instruction */ - live_flags &= ~write_flags; - live_flags |= opc_read_flags[op]; - } -} - -/* generate intermediate code in gen_opc_buf and gen_opparam_buf for - basic block 'tb'. If search_pc is TRUE, also generate PC - information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, - int search_pc) -{ - DisasContext dc1, *dc = &dc1; - uint8_t *pc_ptr; - uint16_t *gen_opc_end; - int flags, j, lj; - uint8_t *pc_start; - uint8_t *cs_base; - - /* generate intermediate code */ - pc_start = (uint8_t *)tb->pc; - cs_base = (uint8_t *)tb->cs_base; - flags = tb->flags; - - dc->pe = env->cr[0] & CR0_PE_MASK; - dc->code32 = (flags >> HF_CS32_SHIFT) & 1; - dc->ss32 = (flags >> HF_SS32_SHIFT) & 1; - dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1; - dc->f_st = 0; - dc->vm86 = (flags >> VM_SHIFT) & 1; - dc->cpl = (flags >> HF_CPL_SHIFT) & 3; - dc->iopl = (flags >> IOPL_SHIFT) & 3; - dc->tf = (flags >> TF_SHIFT) & 1; - dc->cc_op = CC_OP_DYNAMIC; - dc->cs_base = cs_base; - dc->tb = tb; - dc->popl_esp_hack = 0; - /* select memory access functions */ - dc->mem_index = 0; - if (flags & HF_SOFTMMU_MASK) { - if (dc->cpl == 3) - dc->mem_index = 6; - else - dc->mem_index = 3; - } - dc->jmp_opt = !(dc->tf || env->singlestep_enabled -#ifndef CONFIG_SOFT_MMU - || (flags & HF_SOFTMMU_MASK) -#endif - ); - gen_opc_ptr = gen_opc_buf; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; - - dc->is_jmp = DISAS_NEXT; - pc_ptr = pc_start; - lj = -1; - - /* if irq were inhibited for the next instruction, we can disable - them here as it is simpler (otherwise jumps would have to - handled as special case) */ - if (flags & HF_INHIBIT_IRQ_MASK) { - gen_op_reset_inhibit_irq(); - } - for(;;) { - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == (unsigned long)pc_ptr) { - gen_debug(dc, pc_ptr - dc->cs_base); - break; - } - } - } - if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; - if (lj < j) { - lj++; - while (lj < j) - gen_opc_instr_start[lj++] = 0; - } - gen_opc_pc[lj] = (uint32_t)pc_ptr; - gen_opc_cc_op[lj] = dc->cc_op; - gen_opc_instr_start[lj] = 1; - } - pc_ptr = disas_insn(dc, pc_ptr); - /* stop translation if indicated */ - if (dc->is_jmp) - break; - /* if single step mode, we generate only one instruction and - generate an exception */ - if (dc->tf) { - gen_op_jmp_im(pc_ptr - dc->cs_base); - gen_eob(dc); - break; - } - /* if too long translation, stop generation too */ - if (gen_opc_ptr >= gen_opc_end || - (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { - gen_op_jmp_im(pc_ptr - dc->cs_base); - gen_eob(dc); - break; - } - } - *gen_opc_ptr = INDEX_op_end; - /* we don't forget to fill the last values */ - if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; - lj++; - while (lj <= j) - gen_opc_instr_start[lj++] = 0; - } - -#ifdef DEBUG_DISAS - if (loglevel) { - fprintf(logfile, "----------------\n"); - fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32); - fprintf(logfile, "\n"); - - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } -#endif - - /* optimize flag computations */ - optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf); - -#ifdef DEBUG_DISAS - if (loglevel) { - fprintf(logfile, "AFTER FLAGS OPT:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } -#endif - if (!search_pc) - tb->size = pc_ptr - pc_start; - return 0; -} - -int gen_intermediate_code(CPUState *env, TranslationBlock *tb) -{ - return gen_intermediate_code_internal(env, tb, 0); -} - -int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) -{ - return gen_intermediate_code_internal(env, tb, 1); -} - diff --git a/translate.c b/translate.c deleted file mode 100644 index c9bca64db..000000000 --- a/translate.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Host code generation - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include - -#include "config.h" - -#define IN_OP_I386 -#if defined(TARGET_I386) -#include "cpu-i386.h" -#define OPC_CPU_H "opc-i386.h" -#elif defined(TARGET_ARM) -#include "cpu-arm.h" -#define OPC_CPU_H "opc-arm.h" -#else -#error unsupported target CPU -#endif - -#include "exec.h" -#include "disas.h" - -enum { -#define DEF(s, n, copy_size) INDEX_op_ ## s, -#include OPC_CPU_H -#undef DEF - NB_OPS, -}; - -#include "dyngen.h" -#if defined(TARGET_I386) -#include "op-i386.h" -#elif defined(TARGET_ARM) -#include "op-arm.h" -#else -#error unsupported target CPU -#endif - -uint16_t gen_opc_buf[OPC_BUF_SIZE]; -uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; -uint32_t gen_opc_pc[OPC_BUF_SIZE]; -uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; -#if defined(TARGET_I386) -uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; -#endif - -#ifdef DEBUG_DISAS -static const char *op_str[] = { -#define DEF(s, n, copy_size) #s, -#include OPC_CPU_H -#undef DEF -}; - -static uint8_t op_nb_args[] = { -#define DEF(s, n, copy_size) n, -#include OPC_CPU_H -#undef DEF -}; - -void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) -{ - const uint16_t *opc_ptr; - const uint32_t *opparam_ptr; - int c, n, i; - - opc_ptr = opc_buf; - opparam_ptr = opparam_buf; - for(;;) { - c = *opc_ptr++; - n = op_nb_args[c]; - fprintf(logfile, "0x%04x: %s", - (int)(opc_ptr - opc_buf - 1), op_str[c]); - for(i = 0; i < n; i++) { - fprintf(logfile, " 0x%x", opparam_ptr[i]); - } - fprintf(logfile, "\n"); - if (c == INDEX_op_end) - break; - opparam_ptr += n; - } -} - -#endif - -/* return non zero if the very first instruction is invalid so that - the virtual CPU can trigger an exception. - - '*gen_code_size_ptr' contains the size of the generated code (host - code). -*/ -int cpu_gen_code(CPUState *env, TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr) -{ - uint8_t *gen_code_buf; - int gen_code_size; - - if (gen_intermediate_code(env, tb) < 0) - return -1; - - /* generate machine code */ - tb->tb_next_offset[0] = 0xffff; - tb->tb_next_offset[1] = 0xffff; - gen_code_buf = tb->tc_ptr; -#ifdef USE_DIRECT_JUMP - /* the following two entries are optional (only used for string ops) */ - tb->tb_jmp_offset[2] = 0xffff; - tb->tb_jmp_offset[3] = 0xffff; -#endif - gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, -#ifdef USE_DIRECT_JUMP - tb->tb_jmp_offset, -#else - NULL, -#endif - gen_opc_buf, gen_opparam_buf); - *gen_code_size_ptr = gen_code_size; -#ifdef DEBUG_DISAS - if (loglevel) { - fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); - disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0); - fprintf(logfile, "\n"); - fflush(logfile); - } -#endif - return 0; -} - -static const unsigned short opc_copy_size[] = { -#define DEF(s, n, copy_size) copy_size, -#include OPC_CPU_H -#undef DEF -}; - -/* The cpu state corresponding to 'searched_pc' is restored. - */ -int cpu_restore_state(TranslationBlock *tb, - CPUState *env, unsigned long searched_pc) -{ - int j, c; - unsigned long tc_ptr; - uint16_t *opc_ptr; - - if (gen_intermediate_code_pc(env, tb) < 0) - return -1; - - /* find opc index corresponding to search_pc */ - tc_ptr = (unsigned long)tb->tc_ptr; - if (searched_pc < tc_ptr) - return -1; - j = 0; - opc_ptr = gen_opc_buf; - for(;;) { - c = *opc_ptr; - if (c == INDEX_op_end) - return -1; - tc_ptr += opc_copy_size[c]; - if (searched_pc < tc_ptr) - break; - opc_ptr++; - } - j = opc_ptr - gen_opc_buf; - /* now find start of instruction before */ - while (gen_opc_instr_start[j] == 0) - j--; -#if defined(TARGET_I386) - { - int cc_op; -#ifdef DEBUG_DISAS - if (loglevel) { - int i; - fprintf(logfile, "RESTORE:\n"); - for(i=0;i<=j; i++) { - if (gen_opc_instr_start[i]) { - fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]); - } - } - fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%lx cs_base=%lx\n", - searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base); - } -#endif - env->eip = gen_opc_pc[j] - tb->cs_base; - cc_op = gen_opc_cc_op[j]; - if (cc_op != CC_OP_DYNAMIC) - env->cc_op = cc_op; - } -#elif defined(TARGET_ARM) - env->regs[15] = gen_opc_pc[j]; -#endif - return 0; -} - - diff --git a/vlmkcow.c b/vlmkcow.c deleted file mode 100644 index 2cc6332e7..000000000 --- a/vlmkcow.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * create a COW disk image - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vl.h" - -#include "bswap.h" - -int cow_create(int cow_fd, const char *image_filename, - int64_t image_sectors) -{ - struct cow_header_v2 cow_header; - int fd; - struct stat st; - - memset(&cow_header, 0, sizeof(cow_header)); - cow_header.magic = htonl(COW_MAGIC); - cow_header.version = htonl(COW_VERSION); - if (image_filename) { - fd = open(image_filename, O_RDONLY); - if (fd < 0) { - perror(image_filename); - exit(1); - } - image_sectors = lseek64(fd, 0, SEEK_END); - if (fstat(fd, &st) != 0) { - close(fd); - return -1; - } - close(fd); - image_sectors /= 512; - cow_header.mtime = htonl(st.st_mtime); - realpath(image_filename, cow_header.backing_file); - } - cow_header.sectorsize = htonl(512); - cow_header.size = image_sectors * 512; -#ifndef WORDS_BIGENDIAN - cow_header.size = bswap64(cow_header.size); -#endif - write(cow_fd, &cow_header, sizeof(cow_header)); - /* resize to include at least all the bitmap */ - ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); - lseek(cow_fd, 0, SEEK_SET); - return 0; -} - -void help(void) -{ - printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n" - "Create a Copy On Write disk image from an optional raw disk image\n" - "\n" - "-f disk_image set the raw disk image name\n" - "cow_image the created cow_image\n" - "cow_size the create cow_image size in MB if no raw disk image is used\n" - "\n" - "Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n" - ); - exit(1); -} - -int main(int argc, char **argv) -{ - const char *image_filename, *cow_filename; - int cow_fd, c, nb_args; - int64_t image_size; - - image_filename = NULL; - image_size = 0; - for(;;) { - c = getopt(argc, argv, "hf:"); - if (c == -1) - break; - switch(c) { - case 'h': - help(); - break; - case 'f': - image_filename = optarg; - break; - } - } - if (!image_filename) - nb_args = 2; - else - nb_args = 1; - if (optind + nb_args != argc) - help(); - - cow_filename = argv[optind]; - if (nb_args == 2) { - image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024; - } - - cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644); - if (!cow_fd < 0) - return -1; - if (cow_create(cow_fd, image_filename, image_size) < 0) { - fprintf(stderr, "%s: error while formating\n", cow_filename); - exit(1); - } - close(cow_fd); - return 0; -} -- cgit v1.2.3 From 6180a1818ad1f6147983e48314ab6cbf49d4f084 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 21:04:53 +0000 Subject: new directory structure git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@391 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 9 +- gdbstub.c | 9 +- hw/vga.c | 4 +- linux-user/qemu.h | 11 +- linux-user/syscall_defs.h | 290 ++-------------------------------------------- 5 files changed, 17 insertions(+), 306 deletions(-) diff --git a/exec.c b/exec.c index cdc2a0be3..46cccb5de 100644 --- a/exec.c +++ b/exec.c @@ -27,13 +27,8 @@ #include #include "config.h" -#ifdef TARGET_I386 -#include "cpu-i386.h" -#endif -#ifdef TARGET_ARM -#include "cpu-arm.h" -#endif -#include "exec.h" +#include "cpu.h" +#include "exec-all.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH diff --git a/gdbstub.c b/gdbstub.c index 61cb6b1ab..d73a7efe3 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -28,14 +28,9 @@ #include #include "config.h" -#ifdef TARGET_I386 -#include "cpu-i386.h" -#endif -#ifdef TARGET_ARM -#include "cpu-arm.h" -#endif +#include "cpu.h" #include "thunk.h" -#include "exec.h" +#include "exec-all.h" //#define DEBUG_GDB diff --git a/hw/vga.c b/hw/vga.c index 9ab9a163c..1176502e4 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -40,8 +40,8 @@ #include #include -#include "cpu-i386.h" -#include "exec.h" +#include "cpu.h" +#include "exec-all.h" #include "vl.h" diff --git a/linux-user/qemu.h b/linux-user/qemu.h index a68e8f4b4..f6b8d96f4 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -6,15 +6,8 @@ #include #include "syscall_defs.h" -#if defined(TARGET_I386) -#include "cpu-i386.h" -#include "syscall-i386.h" -#elif defined(TARGET_ARM) -#include "cpu-arm.h" -#include "syscall-arm.h" -#else -#error unsupported target CPU -#endif +#include "cpu.h" +#include "syscall.h" /* This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index a4613bdf7..8f6d14e55 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -4,284 +4,7 @@ most of them stay the same, so we handle it by puting ifdefs if necessary */ -#define TARGET_NR_exit 1 -#define TARGET_NR_fork 2 -#define TARGET_NR_read 3 -#define TARGET_NR_write 4 -#define TARGET_NR_open 5 -#define TARGET_NR_close 6 -#define TARGET_NR_waitpid 7 -#define TARGET_NR_creat 8 -#define TARGET_NR_link 9 -#define TARGET_NR_unlink 10 -#define TARGET_NR_execve 11 -#define TARGET_NR_chdir 12 -#define TARGET_NR_time 13 -#define TARGET_NR_mknod 14 -#define TARGET_NR_chmod 15 -#define TARGET_NR_lchown 16 -#define TARGET_NR_break 17 -#define TARGET_NR_oldstat 18 -#define TARGET_NR_lseek 19 -#define TARGET_NR_getpid 20 -#define TARGET_NR_mount 21 -#define TARGET_NR_umount 22 -#define TARGET_NR_setuid 23 -#define TARGET_NR_getuid 24 -#define TARGET_NR_stime 25 -#define TARGET_NR_ptrace 26 -#define TARGET_NR_alarm 27 -#define TARGET_NR_oldfstat 28 -#define TARGET_NR_pause 29 -#define TARGET_NR_utime 30 -#define TARGET_NR_stty 31 -#define TARGET_NR_gtty 32 -#define TARGET_NR_access 33 -#define TARGET_NR_nice 34 -#define TARGET_NR_ftime 35 -#define TARGET_NR_sync 36 -#define TARGET_NR_kill 37 -#define TARGET_NR_rename 38 -#define TARGET_NR_mkdir 39 -#define TARGET_NR_rmdir 40 -#define TARGET_NR_dup 41 -#define TARGET_NR_pipe 42 -#define TARGET_NR_times 43 -#define TARGET_NR_prof 44 -#define TARGET_NR_brk 45 -#define TARGET_NR_setgid 46 -#define TARGET_NR_getgid 47 -#define TARGET_NR_signal 48 -#define TARGET_NR_geteuid 49 -#define TARGET_NR_getegid 50 -#define TARGET_NR_acct 51 -#define TARGET_NR_umount2 52 -#define TARGET_NR_lock 53 -#define TARGET_NR_ioctl 54 -#define TARGET_NR_fcntl 55 -#define TARGET_NR_mpx 56 -#define TARGET_NR_setpgid 57 -#define TARGET_NR_ulimit 58 -#define TARGET_NR_oldolduname 59 -#define TARGET_NR_umask 60 -#define TARGET_NR_chroot 61 -#define TARGET_NR_ustat 62 -#define TARGET_NR_dup2 63 -#define TARGET_NR_getppid 64 -#define TARGET_NR_getpgrp 65 -#define TARGET_NR_setsid 66 -#define TARGET_NR_sigaction 67 -#define TARGET_NR_sgetmask 68 -#define TARGET_NR_ssetmask 69 -#define TARGET_NR_setreuid 70 -#define TARGET_NR_setregid 71 -#define TARGET_NR_sigsuspend 72 -#define TARGET_NR_sigpending 73 -#define TARGET_NR_sethostname 74 -#define TARGET_NR_setrlimit 75 -#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ -#define TARGET_NR_getrusage 77 -#define TARGET_NR_gettimeofday 78 -#define TARGET_NR_settimeofday 79 -#define TARGET_NR_getgroups 80 -#define TARGET_NR_setgroups 81 -#define TARGET_NR_select 82 -#define TARGET_NR_symlink 83 -#define TARGET_NR_oldlstat 84 -#define TARGET_NR_readlink 85 -#define TARGET_NR_uselib 86 -#define TARGET_NR_swapon 87 -#define TARGET_NR_reboot 88 -#define TARGET_NR_readdir 89 -#define TARGET_NR_mmap 90 -#define TARGET_NR_munmap 91 -#define TARGET_NR_truncate 92 -#define TARGET_NR_ftruncate 93 -#define TARGET_NR_fchmod 94 -#define TARGET_NR_fchown 95 -#define TARGET_NR_getpriority 96 -#define TARGET_NR_setpriority 97 -#define TARGET_NR_profil 98 -#define TARGET_NR_statfs 99 -#define TARGET_NR_fstatfs 100 -#define TARGET_NR_ioperm 101 -#define TARGET_NR_socketcall 102 -#define TARGET_NR_syslog 103 -#define TARGET_NR_setitimer 104 -#define TARGET_NR_getitimer 105 -#define TARGET_NR_stat 106 -#define TARGET_NR_lstat 107 -#define TARGET_NR_fstat 108 -#define TARGET_NR_olduname 109 -#define TARGET_NR_iopl 110 -#define TARGET_NR_vhangup 111 -#define TARGET_NR_idle 112 -#define TARGET_NR_vm86old 113 -#define TARGET_NR_wait4 114 -#define TARGET_NR_swapoff 115 -#define TARGET_NR_sysinfo 116 -#define TARGET_NR_ipc 117 -#define TARGET_NR_fsync 118 -#define TARGET_NR_sigreturn 119 -#define TARGET_NR_clone 120 -#define TARGET_NR_setdomainname 121 -#define TARGET_NR_uname 122 -#define TARGET_NR_modify_ldt 123 -#define TARGET_NR_adjtimex 124 -#define TARGET_NR_mprotect 125 -#define TARGET_NR_sigprocmask 126 -#define TARGET_NR_create_module 127 -#define TARGET_NR_init_module 128 -#define TARGET_NR_delete_module 129 -#define TARGET_NR_get_kernel_syms 130 -#define TARGET_NR_quotactl 131 -#define TARGET_NR_getpgid 132 -#define TARGET_NR_fchdir 133 -#define TARGET_NR_bdflush 134 -#define TARGET_NR_sysfs 135 -#define TARGET_NR_personality 136 -#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ -#define TARGET_NR_setfsuid 138 -#define TARGET_NR_setfsgid 139 -#define TARGET_NR__llseek 140 -#define TARGET_NR_getdents 141 -#define TARGET_NR__newselect 142 -#define TARGET_NR_flock 143 -#define TARGET_NR_msync 144 -#define TARGET_NR_readv 145 -#define TARGET_NR_writev 146 -#define TARGET_NR_getsid 147 -#define TARGET_NR_fdatasync 148 -#define TARGET_NR__sysctl 149 -#define TARGET_NR_mlock 150 -#define TARGET_NR_munlock 151 -#define TARGET_NR_mlockall 152 -#define TARGET_NR_munlockall 153 -#define TARGET_NR_sched_setparam 154 -#define TARGET_NR_sched_getparam 155 -#define TARGET_NR_sched_setscheduler 156 -#define TARGET_NR_sched_getscheduler 157 -#define TARGET_NR_sched_yield 158 -#define TARGET_NR_sched_get_priority_max 159 -#define TARGET_NR_sched_get_priority_min 160 -#define TARGET_NR_sched_rr_get_interval 161 -#define TARGET_NR_nanosleep 162 -#define TARGET_NR_mremap 163 -#define TARGET_NR_setresuid 164 -#define TARGET_NR_getresuid 165 -#define TARGET_NR_vm86 166 -#define TARGET_NR_query_module 167 -#define TARGET_NR_poll 168 -#define TARGET_NR_nfsservctl 169 -#define TARGET_NR_setresgid 170 -#define TARGET_NR_getresgid 171 -#define TARGET_NR_prctl 172 -#define TARGET_NR_rt_sigreturn 173 -#define TARGET_NR_rt_sigaction 174 -#define TARGET_NR_rt_sigprocmask 175 -#define TARGET_NR_rt_sigpending 176 -#define TARGET_NR_rt_sigtimedwait 177 -#define TARGET_NR_rt_sigqueueinfo 178 -#define TARGET_NR_rt_sigsuspend 179 -#define TARGET_NR_pread 180 -#define TARGET_NR_pwrite 181 -#define TARGET_NR_chown 182 -#define TARGET_NR_getcwd 183 -#define TARGET_NR_capget 184 -#define TARGET_NR_capset 185 -#define TARGET_NR_sigaltstack 186 -#define TARGET_NR_sendfile 187 -#define TARGET_NR_getpmsg 188 /* some people actually want streams */ -#define TARGET_NR_putpmsg 189 /* some people actually want streams */ -#define TARGET_NR_vfork 190 -#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ -#define TARGET_NR_mmap2 192 -#define TARGET_NR_truncate64 193 -#define TARGET_NR_ftruncate64 194 -#define TARGET_NR_stat64 195 -#define TARGET_NR_lstat64 196 -#define TARGET_NR_fstat64 197 -#define TARGET_NR_lchown32 198 -#define TARGET_NR_getuid32 199 -#define TARGET_NR_getgid32 200 -#define TARGET_NR_geteuid32 201 -#define TARGET_NR_getegid32 202 -#define TARGET_NR_setreuid32 203 -#define TARGET_NR_setregid32 204 -#define TARGET_NR_getgroups32 205 -#define TARGET_NR_setgroups32 206 -#define TARGET_NR_fchown32 207 -#define TARGET_NR_setresuid32 208 -#define TARGET_NR_getresuid32 209 -#define TARGET_NR_setresgid32 210 -#define TARGET_NR_getresgid32 211 -#define TARGET_NR_chown32 212 -#define TARGET_NR_setuid32 213 -#define TARGET_NR_setgid32 214 -#define TARGET_NR_setfsuid32 215 -#define TARGET_NR_setfsgid32 216 - -#if defined(TARGET_I386) -#define TARGET_NR_pivot_root 217 -#define TARGET_NR_mincore 218 -#define TARGET_NR_madvise 219 -#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */ -#define TARGET_NR_getdents64 220 -#endif - -#if defined(TARGET_ARM) -#define TARGET_NR_getdents64 217 -#define TARGET_NR_pivot_root 218 -#define TARGET_NR_mincore 219 -#define TARGET_NR_madvise 220 -#endif - -#define TARGET_NR_fcntl64 221 -#define TARGET_NR_security 223 /* syscall for security modules */ -#define TARGET_NR_gettid 224 -#define TARGET_NR_readahead 225 -#define TARGET_NR_setxattr 226 -#define TARGET_NR_lsetxattr 227 -#define TARGET_NR_fsetxattr 228 -#define TARGET_NR_getxattr 229 -#define TARGET_NR_lgetxattr 230 -#define TARGET_NR_fgetxattr 231 -#define TARGET_NR_listxattr 232 -#define TARGET_NR_llistxattr 233 -#define TARGET_NR_flistxattr 234 -#define TARGET_NR_removexattr 235 -#define TARGET_NR_lremovexattr 236 -#define TARGET_NR_fremovexattr 237 -#define TARGET_NR_tkill 238 -#define TARGET_NR_sendfile64 239 -#define TARGET_NR_futex 240 -#define TARGET_NR_sched_setaffinity 241 -#define TARGET_NR_sched_getaffinity 242 -#define TARGET_NR_set_thread_area 243 -#define TARGET_NR_get_thread_area 244 -#define TARGET_NR_io_setup 245 -#define TARGET_NR_io_destroy 246 -#define TARGET_NR_io_getevents 247 -#define TARGET_NR_io_submit 248 -#define TARGET_NR_io_cancel 249 -#define TARGET_NR_fadvise64 250 - -#define TARGET_NR_exit_group 252 -#define TARGET_NR_lookup_dcookie 253 -#define TARGET_NR_epoll_create 254 -#define TARGET_NR_epoll_ctl 255 -#define TARGET_NR_epoll_wait 256 -#define TARGET_NR_remap_file_pages 257 -#define TARGET_NR_set_tid_address 258 -#define TARGET_NR_timer_create 259 -#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) -#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) -#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) -#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) -#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) -#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) -#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) -#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) +#include "syscall_nr.h" #define SOCKOP_socket 1 #define SOCKOP_bind 2 @@ -321,7 +44,7 @@ #define TARGET_IOC_WRITE 1U #define TARGET_IOC_READ 2U -#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) +#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_SPARC) #define TARGET_IOC_SIZEBITS 13 #define TARGET_IOC_DIRBITS 3 @@ -392,6 +115,11 @@ struct target_tms { target_clock_t tms_cstime; }; +struct target_utimbuf { + target_long actime; + target_long modtime; +}; + struct target_sel_arg_struct { target_long n; target_long inp, outp, exp; @@ -551,7 +279,7 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 0x00000001 #define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ @@ -936,7 +664,7 @@ struct target_pollfd { #define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ -#if defined(TARGET_I386) || defined(TARGET_ARM) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) /* 0x54 is just a magic number to make these relatively unique ('T') */ -- cgit v1.2.3 From a20dd508aa3895b2e5f4d4f255a4d6306b5e2631 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 21:07:02 +0000 Subject: simplified invocation - added automatic IDE disk geometry guessing to reuse old disk images directly git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@392 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 43 deletions(-) diff --git a/vl.c b/vl.c index 94d919643..ddb622c1a 100644 --- a/vl.c +++ b/vl.c @@ -44,7 +44,7 @@ #include #include -#include "cpu-i386.h" +#include "cpu.h" #include "disas.h" #include "thunk.h" @@ -216,7 +216,7 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS]; int vga_ram_size; static DisplayState display_state; -int nodisp; +int nographic; int term_inited; int64_t ticks_per_sec; @@ -2434,6 +2434,52 @@ void ide_reset(IDEState *s) s->select = 0xa0; } +struct partition { + uint8_t boot_ind; /* 0x80 - active */ + uint8_t head; /* starting head */ + uint8_t sector; /* starting sector */ + uint8_t cyl; /* starting cylinder */ + uint8_t sys_ind; /* What partition type */ + uint8_t end_head; /* end head */ + uint8_t end_sector; /* end sector */ + uint8_t end_cyl; /* end cylinder */ + uint32_t start_sect; /* starting sector counting from 0 */ + uint32_t nr_sects; /* nr of sectors in partition */ +} __attribute__((packed)); + +/* try to guess the IDE geometry from the MSDOS partition table */ +void ide_guess_geometry(IDEState *s) +{ + uint8_t buf[512]; + int ret, i; + struct partition *p; + uint32_t nr_sects; + + if (s->cylinders != 0) + return; + ret = bdrv_read(s->bs, 0, buf, 1); + if (ret < 0) + return; + /* test msdos magic */ + if (buf[510] != 0x55 || buf[511] != 0xaa) + return; + for(i = 0; i < 4; i++) { + p = ((struct partition *)(buf + 0x1be)) + i; + nr_sects = tswap32(p->nr_sects); + if (nr_sects && p->end_head) { + /* We make the assumption that the partition terminates on + a cylinder boundary */ + s->heads = p->end_head + 1; + s->sectors = p->end_sector & 63; + s->cylinders = s->nb_sectors / (s->heads * s->sectors); +#if 0 + printf("guessed partition: CHS=%d %d %d\n", + s->cylinders, s->heads, s->sectors); +#endif + } + } +} + void ide_init(void) { IDEState *s; @@ -2445,6 +2491,8 @@ void ide_init(void) s->bs = bs_table[i]; if (s->bs) { bdrv_get_geometry(s->bs, &nb_sectors); + s->nb_sectors = nb_sectors; + ide_guess_geometry(s); if (s->cylinders == 0) { /* if no geometry, use a LBA compatible one */ cylinders = nb_sectors / (16 * 63); @@ -2456,7 +2504,6 @@ void ide_init(void) s->heads = 16; s->sectors = 63; } - s->nb_sectors = nb_sectors; } s->irq = 14; ide_reset(s); @@ -3136,7 +3183,10 @@ static void term_init(void) tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + /* if graphical mode, we allow Ctrl-C handling */ + if (nographic) + tty.c_lflag &= ~ISIG; tty.c_cflag &= ~(CSIZE|PARENB); tty.c_cflag |= CS8; tty.c_cc[VMIN] = 1; @@ -3238,7 +3288,7 @@ int main_loop(void *opaque) uint8_t ch; CPUState *env = global_env; - if (nodisp && !term_inited) { + if (!term_inited) { /* initialize terminal only there so that the user has a chance to stop QEMU with Ctrl-C before the gdb connection is launched */ @@ -3328,26 +3378,30 @@ int main_loop(void *opaque) void help(void) { - printf("Virtual Linux version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: vl [options] [bzImage [kernel parameters...]]\n" + printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + "usage: qemu [options] [disk_image]\n" "\n" - "'bzImage' is a Linux kernel image (PAGE_OFFSET must be defined\n" - "to 0x90000000 in asm/page.h and arch/i386/vmlinux.lds)\n" + "'disk_image' is a raw hard image image for IDE hard disk 0\n" "\n" - "General options:\n" - "-initrd file use 'file' as initial ram disk\n" - "-hda file use 'file' as hard disk 0 image\n" - "-hdb file use 'file' as hard disk 1 image\n" - "-snapshot write to temporary files instead of disk image files\n" - "-m megs set virtual RAM size to megs MB\n" - "-n script set network init script [default=%s]\n" + "Standard options:\n" + "-hda file use 'file' as IDE hard disk 0 image\n" + "-hdb file use 'file' as IDE hard disk 1 image\n" + "-snapshot write to temporary files instead of disk image files\n" + "-m megs set virtual RAM size to megs MB\n" + "-n script set network init script [default=%s]\n" + "-nographic disable graphical output\n" + "\n" + "Linux boot specific (does not require PC BIOS):\n" + "-kernel bzImage use 'bzImage' as kernel image\n" + "-append cmdline use 'cmdline' as kernel command line\n" + "-initrd file use 'file' as initial ram disk\n" "\n" "Debug/Expert options:\n" - "-s wait gdb connection to port %d\n" - "-p port change gdb connection port\n" - "-d output log in /tmp/vl.log\n" - "-hdachs c,h,s force hard disk 0 geometry for non LBA disk images\n" - "-L path set the directory for the BIOS and VGA BIOS\n" + "-s wait gdb connection to port %d\n" + "-p port change gdb connection port\n" + "-d output log in /tmp/vl.log\n" + "-hdachs c,h,s force hard disk 0 geometry (usually qemu can guess it)\n" + "-L path set the directory for the BIOS and VGA BIOS\n" "\n" "During emulation, use C-a h to get terminal commands:\n", DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT); @@ -3361,10 +3415,24 @@ struct option long_options[] = { { "hdb", 1, NULL, 0, }, { "snapshot", 0, NULL, 0, }, { "hdachs", 1, NULL, 0, }, - { "nodisp", 0, NULL, 0, }, + { "nographic", 0, NULL, 0, }, + { "kernel", 1, NULL, 0, }, + { "append", 1, NULL, 0, }, { NULL, 0, NULL, 0 }, }; +#ifdef CONFIG_SDL +/* SDL use the pthreads and they modify sigaction. We don't + want that. */ +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +extern void __libc_sigaction(); +#define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact) +#else +extern void __sigaction(); +#define sigaction(sig, act, oact) __sigaction(sig, act, oact) +#endif +#endif /* CONFIG_SDL */ + int main(int argc, char **argv) { int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; @@ -3375,6 +3443,7 @@ int main(int argc, char **argv) CPUX86State *env; const char *tmpdir, *initrd_filename; const char *hd_filename[MAX_DISKS]; + const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; /* we never want that malloc() uses mmap() */ @@ -3388,8 +3457,9 @@ int main(int argc, char **argv) use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; snapshot = 0; - linux_boot = 0; - nodisp = 0; + nographic = 0; + kernel_filename = NULL; + kernel_cmdline = ""; for(;;) { c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index); if (c == -1) @@ -3432,7 +3502,13 @@ int main(int argc, char **argv) } break; case 5: - nodisp = 1; + nographic = 1; + break; + case 6: + kernel_filename = optarg; + break; + case 7: + kernel_cmdline = optarg; break; } break; @@ -3467,7 +3543,11 @@ int main(int argc, char **argv) } } - linux_boot = (optind < argc); + if (optind < argc) { + hd_filename[0] = argv[optind++]; + } + + linux_boot = (kernel_filename != NULL); if (!linux_boot && hd_filename[0] == '\0') help(); @@ -3487,7 +3567,7 @@ int main(int argc, char **argv) net_init(); /* init the memory */ - tmpdir = getenv("VLTMPDIR"); + tmpdir = getenv("QEMU_TMPDIR"); if (!tmpdir) tmpdir = "/tmp"; snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir); @@ -3538,9 +3618,10 @@ int main(int argc, char **argv) if (linux_boot) { /* now we can load the kernel */ - ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); + ret = load_kernel(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (ret < 0) { - fprintf(stderr, "vl: could not load kernel '%s'\n", argv[optind]); + fprintf(stderr, "vl: could not load kernel '%s'\n", + kernel_filename); exit(1); } @@ -3562,11 +3643,7 @@ int main(int argc, char **argv) params->cl_magic = 0xA33F; params->cl_offset = params->commandline - (uint8_t *)params; params->alt_mem_k = (phys_ram_size / 1024) - 1024; - for(i = optind + 1; i < argc; i++) { - if (i != optind + 1) - pstrcat(params->commandline, sizeof(params->commandline), " "); - pstrcat(params->commandline, sizeof(params->commandline), argv[i]); - } + pstrcat(params->commandline, sizeof(params->commandline), kernel_cmdline); params->loader_type = 0x01; if (initrd_size > 0) { params->initrd_start = INITRD_LOAD_ADDR; @@ -3602,7 +3679,7 @@ int main(int argc, char **argv) } else { char buf[1024]; - + /* RAW PC boot */ /* BIOS load */ @@ -3642,18 +3719,11 @@ int main(int argc, char **argv) } /* terminal init */ - if (nodisp) { + if (nographic) { dumb_display_init(ds); } else { #ifdef CONFIG_SDL sdl_display_init(ds); - /* SDL use the pthreads and they modify sigaction. We don't - want that. */ -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) -#define sigaction __libc_sigaction -#else -#define sigaction __sigaction -#endif #else dumb_display_init(ds); #endif -- cgit v1.2.3 From ebc054881ff60643abe1995b4bcdc558264470f2 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 21:08:41 +0000 Subject: added utime syscall - fixed nanosleep exact behaviour git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@393 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 753a47cd2..d218009ad 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -41,6 +41,7 @@ #include #include #include +#include //#include #include @@ -1262,6 +1263,8 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) newsp = env->regs[13]; new_env->regs[13] = newsp; new_env->regs[0] = 0; +#elif defined(TARGET_SPARC) + printf ("HELPME: %s:%d\n", __FILE__, __LINE__); #else #error unsupported target CPU #endif @@ -1472,10 +1475,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_lchown: ret = get_errno(chown((const char *)arg1, arg2, arg3)); break; +#ifdef TARGET_NR_break case TARGET_NR_break: goto unimplemented; +#endif +#ifdef TARGET_NR_oldstat case TARGET_NR_oldstat: goto unimplemented; +#endif case TARGET_NR_lseek: ret = get_errno(lseek(arg1, arg2, arg3)); break; @@ -1507,25 +1514,40 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_alarm: ret = alarm(arg1); break; +#ifdef TARGET_NR_oldfstat case TARGET_NR_oldfstat: goto unimplemented; +#endif case TARGET_NR_pause: ret = get_errno(pause()); break; case TARGET_NR_utime: - goto unimplemented; + { + struct utimbuf tbuf; + struct target_utimbuf *target_tbuf = (void *)arg2; + tbuf.actime = tswapl(target_tbuf->actime); + tbuf.modtime = tswapl(target_tbuf->modtime); + ret = get_errno(utime((const char *)arg1, &tbuf)); + } + break; +#ifdef TARGET_NR_stty case TARGET_NR_stty: goto unimplemented; +#endif +#ifdef TARGET_NR_gtty case TARGET_NR_gtty: goto unimplemented; +#endif case TARGET_NR_access: ret = get_errno(access((const char *)arg1, arg2)); break; case TARGET_NR_nice: ret = get_errno(nice(arg1)); break; +#ifdef TARGET_NR_ftime case TARGET_NR_ftime: goto unimplemented; +#endif case TARGET_NR_sync: sync(); ret = 0; @@ -1570,8 +1592,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = host_to_target_clock_t(ret); } break; +#ifdef TARGET_NR_prof case TARGET_NR_prof: goto unimplemented; +#endif case TARGET_NR_setgid: ret = get_errno(setgid(low2highgid(arg1))); break; @@ -1591,23 +1615,31 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_umount2: ret = get_errno(umount2((const char *)arg1, arg2)); break; +#ifdef TARGET_NR_lock case TARGET_NR_lock: goto unimplemented; +#endif case TARGET_NR_ioctl: ret = do_ioctl(arg1, arg2, arg3); break; case TARGET_NR_fcntl: ret = get_errno(do_fcntl(arg1, arg2, arg3)); break; +#ifdef TARGET_NR_mpx case TARGET_NR_mpx: goto unimplemented; +#endif case TARGET_NR_setpgid: ret = get_errno(setpgid(arg1, arg2)); break; +#ifdef TARGET_NR_ulimit case TARGET_NR_ulimit: goto unimplemented; +#endif +#ifdef TARGET_NR_oldolduname case TARGET_NR_oldolduname: goto unimplemented; +#endif case TARGET_NR_umask: ret = get_errno(umask(arg1)); break; @@ -1917,8 +1949,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_symlink: ret = get_errno(symlink((const char *)arg1, (const char *)arg2)); break; +#ifdef TARGET_NR_oldlstat case TARGET_NR_oldlstat: goto unimplemented; +#endif case TARGET_NR_readlink: ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3)); break; @@ -2001,8 +2035,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_setpriority: ret = get_errno(setpriority(arg1, arg2, arg3)); break; +#ifdef TARGET_NR_profil case TARGET_NR_profil: goto unimplemented; +#endif case TARGET_NR_statfs: stfs = (void *)arg2; ret = get_errno(sys_statfs(path((const char *)arg1), stfs)); @@ -2024,8 +2060,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, stfs = (void *)arg2; ret = get_errno(sys_fstatfs(arg1, stfs)); goto convert_statfs; +#ifdef TARGET_NR_ioperm case TARGET_NR_ioperm: goto unimplemented; +#endif case TARGET_NR_socketcall: ret = do_socketcall(arg1, (int32_t *)arg2); break; @@ -2097,15 +2135,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#ifdef TARGET_NR_olduname case TARGET_NR_olduname: goto unimplemented; +#endif +#ifdef TARGET_NR_iopl case TARGET_NR_iopl: goto unimplemented; +#endif case TARGET_NR_vhangup: ret = get_errno(vhangup()); break; +#ifdef TARGET_NR_idle case TARGET_NR_idle: goto unimplemented; +#endif case TARGET_NR_wait4: { int status; @@ -2415,17 +2459,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, req.tv_sec = tswapl(target_req->tv_sec); req.tv_nsec = tswapl(target_req->tv_nsec); ret = get_errno(nanosleep(&req, &rem)); - if (target_rem) { + if (is_error(ret) && target_rem) { target_rem->tv_sec = tswapl(rem.tv_sec); target_rem->tv_nsec = tswapl(rem.tv_nsec); } } break; +#ifdef TARGET_NR_setresuid case TARGET_NR_setresuid: ret = get_errno(setresuid(low2highuid(arg1), low2highuid(arg2), low2highuid(arg3))); break; +#endif +#ifdef TARGET_NR_getresuid case TARGET_NR_getresuid: { int ruid, euid, suid; @@ -2437,11 +2484,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#endif +#ifdef TARGET_NR_getresgid case TARGET_NR_setresgid: ret = get_errno(setresgid(low2highgid(arg1), low2highgid(arg2), low2highgid(arg3))); break; +#endif +#ifdef TARGET_NR_getresgid case TARGET_NR_getresgid: { int rgid, egid, sgid; @@ -2453,6 +2504,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#endif case TARGET_NR_query_module: goto unimplemented; case TARGET_NR_nfsservctl: @@ -2480,13 +2532,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; case TARGET_NR_sendfile: goto unimplemented; +#ifdef TARGET_NR_getpmsg case TARGET_NR_getpmsg: goto unimplemented; +#endif +#ifdef TARGET_NR_putpmsg case TARGET_NR_putpmsg: goto unimplemented; +#endif case TARGET_NR_vfork: ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); break; +#ifdef TARGET_NR_ugetrlimit case TARGET_NR_ugetrlimit: { struct rlimit rlim; @@ -2498,6 +2555,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; } +#endif case TARGET_NR_truncate64: goto unimplemented; case TARGET_NR_ftruncate64: @@ -2647,13 +2705,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; } #endif +#ifdef TARGET_NR_security case TARGET_NR_security: goto unimplemented; +#endif case TARGET_NR_gettid: ret = get_errno(gettid()); break; case TARGET_NR_readahead: goto unimplemented; +#ifdef TARGET_NR_setxattr case TARGET_NR_setxattr: case TARGET_NR_lsetxattr: case TARGET_NR_fsetxattr: @@ -2667,9 +2728,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_lremovexattr: case TARGET_NR_fremovexattr: goto unimplemented_nowarn; +#endif +#ifdef TARGET_NR_set_thread_area case TARGET_NR_set_thread_area: case TARGET_NR_get_thread_area: goto unimplemented_nowarn; +#endif default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -- cgit v1.2.3 From 0ae04d73678af8b975394e4a40e8326ddb7e5b9d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 21:09:16 +0000 Subject: allow Ctrl-C to be pressed when using gdb stub and SDL git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@394 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sdl.c b/sdl.c index e9c28f2a1..d8ec2c6a3 100644 --- a/sdl.c +++ b/sdl.c @@ -42,8 +42,8 @@ #include -#include "cpu-i386.h" -#include "exec.h" +#include "cpu.h" +#include "exec-all.h" #include "vl.h" @@ -264,6 +264,10 @@ void sdl_display_init(DisplayState *ds) fprintf(stderr, "Could not initialize SDL - exiting\n"); exit(1); } + /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */ + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + ds->dpy_update = sdl_update; ds->dpy_resize = sdl_resize; ds->dpy_refresh = sdl_refresh; -- cgit v1.2.3 From 01e3b763a64bcca82d125706b9f5fdcc1b7ccb75 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 21:10:14 +0000 Subject: removed SIGIOT git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@395 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 0d2e30187..587792d48 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -67,7 +67,7 @@ static uint8_t host_to_target_signal_table[65] = { [SIGILL] = TARGET_SIGILL, [SIGTRAP] = TARGET_SIGTRAP, [SIGABRT] = TARGET_SIGABRT, - [SIGIOT] = TARGET_SIGIOT, +/* [SIGIOT] = TARGET_SIGIOT,*/ [SIGBUS] = TARGET_SIGBUS, [SIGFPE] = TARGET_SIGFPE, [SIGKILL] = TARGET_SIGKILL, -- cgit v1.2.3 From a07cf92aed58a1fbf03d9010e6a81258300be642 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 21:29:03 +0000 Subject: multiscan/doublescan fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@396 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 1176502e4..b16118b88 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1109,7 +1109,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) { int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask; int width, height, shift_control, line_offset, page0, page1, bwidth; - int disp_width; + int disp_width, multi_scan, multi_run; uint8_t *d; uint32_t v, addr1, addr; vga_draw_line_func *vga_draw_line; @@ -1124,10 +1124,13 @@ static void vga_draw_graphic(VGAState *s, int full_update) disp_width = width; shift_control = (s->gr[0x05] >> 5) & 3; - if (shift_control > 1) - double_scan = ((s->cr[0x09] & 0x1f) != 0); - else - double_scan = (s->cr[0x09] & 0x80); + double_scan = (s->cr[0x09] & 0x80); + if (shift_control > 1) { + multi_scan = (s->cr[0x09] & 0x1f); + } else { + multi_scan = 0; + } + multi_run = multi_scan; if (shift_control != s->shift_control || double_scan != s->double_scan) { full_update = 1; @@ -1212,14 +1215,20 @@ static void vga_draw_graphic(VGAState *s, int full_update) y_start = -1; } } - if (!double_scan || (y & 1) != 0) { - if (y1 == s->line_compare) { - addr1 = 0; - } else { - mask = (s->cr[0x17] & 3) ^ 3; - if ((y1 & mask) == mask) - addr1 += line_offset; + if (!multi_run) { + if (!double_scan || (y & 1) != 0) { + if (y1 == s->line_compare) { + addr1 = 0; + } else { + mask = (s->cr[0x17] & 3) ^ 3; + if ((y1 & mask) == mask) + addr1 += line_offset; + } + y1++; } + multi_run = multi_scan; + } else { + multi_run--; y1++; } d += linesize; -- cgit v1.2.3 From 27c3f2cb9bf2112b82edac898094e0a39e6efca1 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 21:40:47 +0000 Subject: buffer overflow fix - handle case where stdin is closed (Rusty Russell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@397 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index ddb622c1a..89a9e06d5 100644 --- a/vl.c +++ b/vl.c @@ -3283,8 +3283,8 @@ CPUState *cpu_gdbstub_get_env(void *opaque) int main_loop(void *opaque) { - struct pollfd ufds[2], *pf, *serial_ufd, *net_ufd, *gdb_ufd; - int ret, n, timeout; + struct pollfd ufds[3], *pf, *serial_ufd, *net_ufd, *gdb_ufd; + int ret, n, timeout, serial_ok; uint8_t ch; CPUState *env = global_env; @@ -3296,6 +3296,7 @@ int main_loop(void *opaque) term_init(); } + serial_ok = 1; for(;;) { ret = cpu_x86_exec(env); if (reset_requested) @@ -3310,7 +3311,7 @@ int main_loop(void *opaque) /* poll any events */ serial_ufd = NULL; pf = ufds; - if (!(serial_ports[0].lsr & UART_LSR_DR)) { + if (serial_ok && !(serial_ports[0].lsr & UART_LSR_DR)) { serial_ufd = pf; pf->fd = 0; pf->events = POLLIN; @@ -3337,6 +3338,9 @@ int main_loop(void *opaque) n = read(0, &ch, 1); if (n == 1) { serial_received_byte(&serial_ports[0], ch); + } else { + /* Closed, stop polling. */ + serial_ok = 0; } } if (net_ufd && (net_ufd->revents & POLLIN)) { -- cgit v1.2.3 From 42f1e0e49b9c162c211eba0115c5e7d1de861f44 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Sep 2003 22:11:17 +0000 Subject: tun-fd option support for external tundev config (Rusty Russell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@398 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 89a9e06d5..f70c6af1c 100644 --- a/vl.c +++ b/vl.c @@ -3393,6 +3393,7 @@ void help(void) "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB\n" "-n script set network init script [default=%s]\n" + "-tun-fd fd this fd talks to tap/tun, use it.\n" "-nographic disable graphical output\n" "\n" "Linux boot specific (does not require PC BIOS):\n" @@ -3422,6 +3423,7 @@ struct option long_options[] = { { "nographic", 0, NULL, 0, }, { "kernel", 1, NULL, 0, }, { "append", 1, NULL, 0, }, + { "tun-fd", 1, NULL, 0, }, { NULL, 0, NULL, 0 }, }; @@ -3514,6 +3516,9 @@ int main(int argc, char **argv) case 7: kernel_cmdline = optarg; break; + case 8: + net_fd = atoi(optarg); + break; } break; case 'h': @@ -3568,7 +3573,8 @@ int main(int argc, char **argv) } /* init network tun interface */ - net_init(); + if (net_fd < 0) + net_init(); /* init the memory */ tmpdir = getenv("QEMU_TMPDIR"); -- cgit v1.2.3 From 5a67135a0b169b768435ace7c7698f7709ba131f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Oct 2003 00:13:48 +0000 Subject: automatic man page generation - BIOS installation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@399 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 12 +- configure | 10 +- texi2pod.pl | 428 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 12 +- 4 files changed, 453 insertions(+), 9 deletions(-) create mode 100755 texi2pod.pl diff --git a/Makefile b/Makefile index bb5f574c0..e21712faf 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ LIBS= DEFINES+=-D_GNU_SOURCE TOOLS=qemu-mkcow -all: dyngen $(TOOLS) qemu-doc.html +all: dyngen $(TOOLS) qemu-doc.html qemu.1 for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done @@ -23,7 +23,7 @@ dyngen: dyngen.o clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h - rm -f *.o *.a $(TOOLS) dyngen TAGS + rm -f *.o *.a $(TOOLS) dyngen TAGS qemu.pod for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done @@ -37,6 +37,10 @@ distclean: clean install: all mkdir -p $(prefix)/bin install -m 755 -s $(TOOLS) $(prefix)/bin + mkdir -p $(sharedir) + install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin $(sharedir) + mkdir -p $(mandir)/man1 + install qemu.1 $(mandir)/man1 for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done @@ -52,6 +56,10 @@ TAGS: qemu-doc.html: qemu-doc.texi texi2html -monolithic -number $< +qemu.1: qemu-doc.texi + ./texi2pod.pl $< qemu.pod + pod2man --section=1 --center=" " --release=" " qemu.pod > $@ + FILE=qemu-$(shell cat VERSION) # tar release (use 'make -k tar' on a checkouted tree) diff --git a/configure b/configure index f680b6945..443d648a7 100755 --- a/configure +++ b/configure @@ -208,9 +208,14 @@ echo "NOTE: The object files are build at the place where configure is launched" exit 1 fi +mandir="$prefix/share/man" +sharedir="$prefix/share/qemu" + echo "Install prefix $prefix" -echo "Source path $source_path" +echo "Manual directory $mandir" +echo "BIOS directory $sharedir" echo "ELF interp prefix $interp_prefix" +echo "Source path $source_path" echo "C compiler $cc" echo "make $make" echo "host CPU $cpu" @@ -232,6 +237,9 @@ echo "# Automatically generated by configure - do not modify" > $config_mak echo "/* Automatically generated by configure - do not modify */" > $config_h echo "prefix=$prefix" >> $config_mak +echo "mandir=$mandir" >> $config_mak +echo "sharedir=$sharedir" >> $config_mak +echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h echo "MAKE=$make" >> $config_mak echo "CC=$cc" >> $config_mak if test "$have_gcc3_options" = "yes" ; then diff --git a/texi2pod.pl b/texi2pod.pl new file mode 100755 index 000000000..176627e9b --- /dev/null +++ b/texi2pod.pl @@ -0,0 +1,428 @@ +#! /usr/bin/perl -w + +# Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +# This file is part of GNU CC. + +# GNU CC 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, or (at your option) +# any later version. + +# GNU CC 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 GNU CC; see the file COPYING. If not, write to +# the Free Software Foundation, 59 Temple Place - Suite 330, +# Boston MA 02111-1307, USA. + +# This does trivial (and I mean _trivial_) conversion of Texinfo +# markup to Perl POD format. It's intended to be used to extract +# something suitable for a manpage from a Texinfo document. + +$output = 0; +$skipping = 0; +%sects = (); +$section = ""; +@icstack = (); +@endwstack = (); +@skstack = (); +@instack = (); +$shift = ""; +%defs = (); +$fnno = 1; +$inf = ""; +$ibase = ""; + +while ($_ = shift) { + if (/^-D(.*)$/) { + if ($1 ne "") { + $flag = $1; + } else { + $flag = shift; + } + $value = ""; + ($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/); + die "no flag specified for -D\n" + unless $flag ne ""; + die "flags may only contain letters, digits, hyphens, dashes and underscores\n" + unless $flag =~ /^[a-zA-Z0-9_-]+$/; + $defs{$flag} = $value; + } elsif (/^-/) { + usage(); + } else { + $in = $_, next unless defined $in; + $out = $_, next unless defined $out; + usage(); + } +} + +if (defined $in) { + $inf = gensym(); + open($inf, "<$in") or die "opening \"$in\": $!\n"; + $ibase = $1 if $in =~ m|^(.+)/[^/]+$|; +} else { + $inf = \*STDIN; +} + +if (defined $out) { + open(STDOUT, ">$out") or die "opening \"$out\": $!\n"; +} + +while(defined $inf) { +while(<$inf>) { + # Certain commands are discarded without further processing. + /^\@(?: + [a-z]+index # @*index: useful only in complete manual + |need # @need: useful only in printed manual + |(?:end\s+)?group # @group .. @end group: ditto + |page # @page: ditto + |node # @node: useful only in .info file + |(?:end\s+)?ifnottex # @ifnottex .. @end ifnottex: use contents + )\b/x and next; + + chomp; + + # Look for filename and title markers. + /^\@setfilename\s+([^.]+)/ and $fn = $1, next; + /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next; + + # Identify a man title but keep only the one we are interested in. + /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do { + if (exists $defs{$1}) { + $fn = $1; + $tl = postprocess($2); + } + next; + }; + + # Look for blocks surrounded by @c man begin SECTION ... @c man end. + # This really oughta be @ifman ... @end ifman and the like, but such + # would require rev'ing all other Texinfo translators. + /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do { + $output = 1 if exists $defs{$2}; + $sect = $1; + next; + }; + /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next; + /^\@c\s+man\s+end/ and do { + $sects{$sect} = "" unless exists $sects{$sect}; + $sects{$sect} .= postprocess($section); + $section = ""; + $output = 0; + next; + }; + + # handle variables + /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do { + $defs{$1} = $2; + next; + }; + /^\@clear\s+([a-zA-Z0-9_-]+)/ and do { + delete $defs{$1}; + next; + }; + + next unless $output; + + # Discard comments. (Can't do it above, because then we'd never see + # @c man lines.) + /^\@c\b/ and next; + + # End-block handler goes up here because it needs to operate even + # if we are skipping. + /^\@end\s+([a-z]+)/ and do { + # Ignore @end foo, where foo is not an operation which may + # cause us to skip, if we are presently skipping. + my $ended = $1; + next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/; + + die "\@end $ended without \@$ended at line $.\n" unless defined $endw; + die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw; + + $endw = pop @endwstack; + + if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) { + $skipping = pop @skstack; + next; + } elsif ($ended =~ /^(?:example|smallexample|display)$/) { + $shift = ""; + $_ = ""; # need a paragraph break + } elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) { + $_ = "\n=back\n"; + $ic = pop @icstack; + } else { + die "unknown command \@end $ended at line $.\n"; + } + }; + + # We must handle commands which can cause skipping even while we + # are skipping, otherwise we will not process nested conditionals + # correctly. + /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do { + push @endwstack, $endw; + push @skstack, $skipping; + $endw = "ifset"; + $skipping = 1 unless exists $defs{$1}; + next; + }; + + /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do { + push @endwstack, $endw; + push @skstack, $skipping; + $endw = "ifclear"; + $skipping = 1 if exists $defs{$1}; + next; + }; + + /^\@(ignore|menu|iftex)\b/ and do { + push @endwstack, $endw; + push @skstack, $skipping; + $endw = $1; + $skipping = 1; + next; + }; + + next if $skipping; + + # Character entities. First the ones that can be replaced by raw text + # or discarded outright: + s/\@copyright\{\}/(c)/g; + s/\@dots\{\}/.../g; + s/\@enddots\{\}/..../g; + s/\@([.!? ])/$1/g; + s/\@[:-]//g; + s/\@bullet(?:\{\})?/*/g; + s/\@TeX\{\}/TeX/g; + s/\@pounds\{\}/\#/g; + s/\@minus(?:\{\})?/-/g; + s/\\,/,/g; + + # Now the ones that have to be replaced by special escapes + # (which will be turned back into text by unmunge()) + s/&/&/g; + s/\@\{/{/g; + s/\@\}/}/g; + s/\@\@/&at;/g; + + # Inside a verbatim block, handle @var specially. + if ($shift ne "") { + s/\@var\{([^\}]*)\}/<$1>/g; + } + + # POD doesn't interpret E<> inside a verbatim block. + if ($shift eq "") { + s//>/g; + } else { + s//>/g; + } + + # Single line command handlers. + + /^\@include\s+(.+)$/ and do { + push @instack, $inf; + $inf = gensym(); + + # Try cwd and $ibase. + open($inf, "<" . $1) + or open($inf, "<" . $ibase . "/" . $1) + or die "cannot open $1 or $ibase/$1: $!\n"; + next; + }; + + /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/ + and $_ = "\n=head2 $1\n"; + /^\@subsection\s+(.+)$/ + and $_ = "\n=head3 $1\n"; + + # Block command handlers: + /^\@itemize\s+(\@[a-z]+|\*|-)/ and do { + push @endwstack, $endw; + push @icstack, $ic; + $ic = $1; + $_ = "\n=over 4\n"; + $endw = "itemize"; + }; + + /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do { + push @endwstack, $endw; + push @icstack, $ic; + if (defined $1) { + $ic = $1 . "."; + } else { + $ic = "1."; + } + $_ = "\n=over 4\n"; + $endw = "enumerate"; + }; + + /^\@([fv]?table)\s+(\@[a-z]+)/ and do { + push @endwstack, $endw; + push @icstack, $ic; + $endw = $1; + $ic = $2; + $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/; + $ic =~ s/\@(?:code|kbd)/C/; + $ic =~ s/\@(?:dfn|var|emph|cite|i)/I/; + $ic =~ s/\@(?:file)/F/; + $_ = "\n=over 4\n"; + }; + + /^\@((?:small)?example|display)/ and do { + push @endwstack, $endw; + $endw = $1; + $shift = "\t"; + $_ = ""; # need a paragraph break + }; + + /^\@itemx?\s*(.+)?$/ and do { + if (defined $1) { + # Entity escapes prevent munging by the <> processing below. +# print "$ic\n"; + $_ = "\n=item $ic\<$1\>\n"; + } else { + $_ = "\n=item $ic\n"; + $ic =~ y/A-Ya-y/B-Zb-z/; + $ic =~ s/(\d+)/$1 + 1/eg; + } + }; + + $section .= $shift.$_."\n"; +} +# End of current file. +close($inf); +$inf = pop @instack; +} + +die "No filename or title\n" unless defined $fn && defined $tl; + +$sects{NAME} = "$fn \- $tl\n"; +$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES}; + +for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES + BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) { + if(exists $sects{$sect}) { + $head = $sect; + $head =~ s/SEEALSO/SEE ALSO/; + print "=head1 $head\n\n"; + print scalar unmunge ($sects{$sect}); + print "\n"; + } +} + +sub usage +{ + die "usage: $0 [-D toggle...] [infile [outfile]]\n"; +} + +sub postprocess +{ + local $_ = $_[0]; + + # @value{foo} is replaced by whatever 'foo' is defined as. + while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) { + if (! exists $defs{$2}) { + print STDERR "Option $2 not defined\n"; + s/\Q$1\E//; + } else { + $value = $defs{$2}; + s/\Q$1\E/$value/; + } + } + + # Formatting commands. + # Temporary escape for @r. + s/\@r\{([^\}]*)\}/R<$1>/g; + s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g; + s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g; + s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g; + s/\@sc\{([^\}]*)\}/\U$1/g; + s/\@file\{([^\}]*)\}/F<$1>/g; + s/\@w\{([^\}]*)\}/S<$1>/g; + s/\@(?:dmn|math)\{([^\}]*)\}/$1/g; + + # Cross references are thrown away, as are @noindent and @refill. + # (@noindent is impossible in .pod, and @refill is unnecessary.) + # @* is also impossible in .pod; we discard it and any newline that + # follows it. Similarly, our macro @gol must be discarded. + + s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g; + s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g; + s/;\s+\@pxref\{(?:[^\}]*)\}//g; + s/\@noindent\s*//g; + s/\@refill//g; + s/\@gol//g; + s/\@\*\s*\n?//g; + + # @uref can take one, two, or three arguments, with different + # semantics each time. @url and @email are just like @uref with + # one argument, for our purposes. + s/\@(?:uref|url|email)\{([^\},]*)\}/<B<$1>>/g; + s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g; + s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g; + + # Turn B blah> into B I B to + # match Texinfo semantics of @emph inside @samp. Also handle @r + # inside bold. + s/<//g; + 1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B]*)I<([^>]+)>/B<$1>I<$2>B]*)B<([^>]+)>/I<$1>B<$2>I//g; + s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g; + s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g; + + # Extract footnotes. This has to be done after all other + # processing because otherwise the regexp will choke on formatting + # inside @footnote. + while (/\@footnote/g) { + s/\@footnote\{([^\}]+)\}/[$fnno]/; + add_footnote($1, $fnno); + $fnno++; + } + + return $_; +} + +sub unmunge +{ + # Replace escaped symbols with their equivalents. + local $_ = $_[0]; + + s/</E/g; + s/>/E/g; + s/{/\{/g; + s/}/\}/g; + s/&at;/\@/g; + s/&/&/g; + return $_; +} + +sub add_footnote +{ + unless (exists $sects{FOOTNOTES}) { + $sects{FOOTNOTES} = "\n=over 4\n\n"; + } + + $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++; + $sects{FOOTNOTES} .= $_[0]; + $sects{FOOTNOTES} .= "\n\n"; +} + +# stolen from Symbol.pm +{ + my $genseq = 0; + sub gensym + { + my $name = "GEN" . $genseq++; + my $ref = \*{$name}; + delete $::{$name}; + return $ref; + } +} diff --git a/vl.c b/vl.c index f70c6af1c..2978694d6 100644 --- a/vl.c +++ b/vl.c @@ -51,7 +51,7 @@ #include "vl.h" #define DEBUG_LOGFILE "/tmp/vl.log" -#define DEFAULT_NETWORK_SCRIPT "/etc/vl-ifup" +#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define BIOS_FILENAME "bios.bin" #define VGABIOS_FILENAME "vgabios.bin" @@ -205,7 +205,7 @@ struct __attribute__ ((packed)) linux_params { #define MAX_IOPORTS 4096 -static const char *interp_prefix = CONFIG_QEMU_PREFIX; +static const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; CPUX86State *global_env; CPUX86State *cpu_single_env; @@ -3547,7 +3547,7 @@ int main(int argc, char **argv) gdbstub_port = atoi(optarg); break; case 'L': - interp_prefix = optarg; + bios_dir = optarg; break; } } @@ -3693,15 +3693,15 @@ int main(int argc, char **argv) /* RAW PC boot */ /* BIOS load */ - snprintf(buf, sizeof(buf), "%s/%s", interp_prefix, BIOS_FILENAME); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); ret = load_image(buf, phys_ram_base + 0x000f0000); if (ret != 0x10000) { - fprintf(stderr, "vl: could not load PC bios '%s'\n", BIOS_FILENAME); + fprintf(stderr, "vl: could not load PC bios '%s'\n", buf); exit(1); } /* VGA BIOS load */ - snprintf(buf, sizeof(buf), "%s/%s", interp_prefix, VGABIOS_FILENAME); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); ret = load_image(buf, phys_ram_base + 0x000c0000); /* setup basic memory access */ -- cgit v1.2.3 From 39b4da28b3c008e23e1a1537192ac98fc6dde8c3 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Oct 2003 00:14:04 +0000 Subject: bios binary images git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@400 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 4 ++++ pc-bios/bios.bin | Bin 0 -> 65536 bytes pc-bios/vgabios.bin | Bin 0 -> 27493 bytes 3 files changed, 4 insertions(+) create mode 100644 pc-bios/README create mode 100644 pc-bios/bios.bin create mode 100644 pc-bios/vgabios.bin diff --git a/pc-bios/README b/pc-bios/README new file mode 100644 index 000000000..508801dce --- /dev/null +++ b/pc-bios/README @@ -0,0 +1,4 @@ +- The PC BIOS comes from the Bochs project + (http://bochs.sourceforge.net/). +- The VGA BIOS comes from the LGPL VGA bios project + (http://www.nongnu.org/vgabios/). diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin new file mode 100644 index 000000000..ae2240b2a Binary files /dev/null and b/pc-bios/bios.bin differ diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin new file mode 100644 index 000000000..b4937a841 Binary files /dev/null and b/pc-bios/vgabios.bin differ -- cgit v1.2.3 From 0806e3f66f1fbc924741246716ef75272715543a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Oct 2003 00:15:32 +0000 Subject: updated git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@401 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 +- qemu-doc.texi | 215 ++++++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 170 insertions(+), 52 deletions(-) diff --git a/Changelog b/Changelog index 4dfbeed10..8468853b9 100644 --- a/Changelog +++ b/Changelog @@ -6,13 +6,18 @@ version 0.4.4: - popw (%esp) fix - mov to/from segment data width fix - added real mode support - - added Bochs BIOS and LGPL'ed VGA BIOS loader in vl + - 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 and user qemu to qemu-{cpu}. + - added man page version 0.4.3: diff --git a/qemu-doc.texi b/qemu-doc.texi index 06ad3086e..0ff1454c1 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1,11 +1,13 @@ \input texinfo @c -*- texinfo -*- +@iftex @settitle QEMU CPU Emulator Reference Documentation @titlepage @sp 7 @center @titlefont{QEMU CPU Emulator Reference Documentation} @sp 3 @end titlepage +@end iftex @chapter Introduction @@ -16,14 +18,18 @@ achieves a reasonnable speed while being easy to port on new host CPUs. QEMU has two operating modes: -@itemize -@item User mode emulation. In this mode, QEMU can launch Linux processes + +@itemize @minus + +@item +User mode emulation. In this mode, QEMU can launch Linux processes compiled for one CPU on another CPU. Linux system calls are converted because of endianness and 32/64 bit mismatches. The Wine Windows API emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator (@url{www.dosemu.org}) are the main targets for QEMU. -@item Full system emulation. In this mode, QEMU emulates a full +@item +Full system emulation. In this mode, QEMU emulates a full system, including a processor and various peripherials. Currently, it is only used to launch an x86 Linux kernel on an x86 Linux system. It enables easier testing and debugging of system code. It can also be @@ -128,6 +134,10 @@ generic dynamic code generation architecture of QEMU. @end itemize +@section SPARC emulation + +The SPARC emulation is currently in development. + @chapter QEMU User space emulator invocation @section Quick Start @@ -144,7 +154,7 @@ itself and all the target (x86) dynamic libraries used by it. libraries: @example -qemu -L / /bin/ls +qemu-i386 -L / /bin/ls @end example @code{-L /} tells that the x86 dynamic linker must be searched with a @@ -153,7 +163,7 @@ qemu -L / /bin/ls @item Since QEMU is also a linux process, you can launch qemu with qemu: @example -qemu -L / qemu -L / /bin/ls +qemu-i386 -L / qemu-i386 -L / /bin/ls @end example @item On non x86 CPUs, you need first to download at least an x86 glibc @@ -167,7 +177,7 @@ unset LD_LIBRARY_PATH Then you can launch the precompiled @file{ls} x86 executable: @example -qemu /usr/local/qemu-i386/bin/ls-i386 +qemu-i386 /usr/local/qemu-i386/bin/ls-i386 @end example You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that QEMU is automatically launched by the Linux kernel when you try to @@ -176,7 +186,7 @@ Linux kernel. @item The x86 version of QEMU is also included. You can try weird things such as: @example -qemu /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386 +qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386 @end example @end itemize @@ -190,7 +200,7 @@ distribution (see previous section). In order to verify it, you must be able to do: @example -qemu /usr/local/qemu-i386/bin/ls-i386 +qemu-i386 /usr/local/qemu-i386/bin/ls-i386 @end example @item Download the binary x86 Wine install @@ -203,7 +213,7 @@ qemu /usr/local/qemu-i386/bin/ls-i386 @item Then you can try the example @file{putty.exe}: @example -qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe +qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe @end example @end itemize @@ -211,7 +221,7 @@ qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Fil @section Command line options @example -usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...] +usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] @end example @table @option @@ -234,20 +244,81 @@ Act as if the host page size was 'pagesize' bytes @chapter QEMU System emulator invocation +@section Introduction + +@c man begin DESCRIPTION + +The QEMU System emulator simulates a complete PC. It can either boot +directly a Linux kernel (without any BIOS or boot loader) or boot like a +real PC with the included BIOS. + +In order to meet specific user needs, two versions of QEMU are +available: + +@enumerate + +@item +@code{qemu} uses the host Memory Management Unit (MMU) to simulate +the x86 MMU. It is @emph{fast} but has limitations because the whole 4 GB +address space cannot be used and some memory mapped peripherials +cannot be emulated accurately yet. Therefore, a specific Linux kernel +must be used (@xref{linux_compile}). + +@item +@code{qemu-softmmu} uses a software MMU. It is about @emph{two times +slower} but gives a more accurate emulation. (XXX: Linux cannot be ran +unpatched yet). + +@end enumerate + +QEMU emulates the following PC peripherials: + +@itemize @minus +@item +VGA (hardware level, including all non standard modes) +@item +PS/2 mouse and keyboard +@item +IDE disk interface (port=0x1f0, irq=14) +@item +NE2000 network adapter (port=0x300, irq=9) +@item +Serial port (port=0x3f8, irq=4) +@item +PIC (interrupt controler) +@item +PIT (timers) +@item +CMOS memory +@end itemize + +@c man end + @section Quick Start -This section explains how to launch a Linux kernel inside QEMU. +Download the linux image (@file{linux.img}) and type: + +@example +qemu-softmmu linux.img +@end example + +Linux should boot and give you a prompt. + +@section Direct Linux Boot and Network emulation + +This section explains how to launch a Linux kernel inside QEMU without +having to make a full bootable image. It is very useful for fast Linux +kernel testing. The QEMU network configuration is also explained. @enumerate @item -Download the archive @file{vl-test-xxx.tar.gz} containing a Linux -kernel and a disk image. The archive also contains a precompiled -version of @file{vl}, the QEMU System emulator. +Download the archive @file{linux-test-xxx.tar.gz} containing a Linux +kernel and a disk image. @item Optional: If you want network support (for example to launch X11 examples), you -must copy the script @file{vl-ifup} in @file{/etc} and configure +must copy the script @file{qemu-ifup} in @file{/etc} and configure properly @code{sudo} so that the command @code{ifconfig} contained in -@file{vl-ifup} can be executed as root. You must verify that your host +@file{qemu-ifup} can be executed as root. You must verify that your host kernel supports the TUN/TAP network interfaces: the device @file{/dev/net/tun} must be present. @@ -256,10 +327,10 @@ the host kernel and the emulated kernel. The emulated kernel is seen from the host kernel at IP address 172.20.0.2 and the host kernel is seen from the emulated kernel at IP address 172.20.0.1. -@item Launch @code{vl.sh}. You should have the following output: +@item Launch @code{qemu.sh}. You should have the following output: @example -> ./vl.sh +> ./qemu.sh connected to host network interface: tun0 Uncompressing Linux... Ok, booting the kernel. Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003 @@ -349,11 +420,11 @@ a real Virtual Linux system ! NOTES: @enumerate @item -A 2.5.74 kernel is also included in the vl-test archive. Just -replace the bzImage in vl.sh to try it. +A 2.5.74 kernel is also included in the archive. Just +replace the bzImage in qemu.sh to try it. @item -vl creates a temporary file in @var{$VLTMPDIR} (@file{/tmp} is the +vl creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the default) containing all the simulated PC memory. If possible, try to use a temporary directory using the tmpfs filesystem to avoid too many unnecessary disk accesses. @@ -379,16 +450,19 @@ Lawton for the plex86 Project (@url{www.plex86.org}). @section Invocation @example -usage: vl [options] bzImage [kernel parameters...] +@c man begin SYNOPSIS +usage: qemu [options] [disk_image] +@c man end @end example -@file{bzImage} is a Linux kernel image. +@c man begin OPTIONS +@var{disk_image} is a raw hard image image for IDE hard disk 0. General options: @table @option @item -hda file @item -hdb file -Use 'file' as hard disk 0 or 1 image (@xref{disk_images}). +Use @var{file} as hard disk 0 or 1 image (@xref{disk_images}). @item -snapshot @@ -405,13 +479,41 @@ launched to configure the host network interface (usually tun0) corresponding to the virtual NE2000 card. @item -initrd file -Use 'file' as initial ram disk. +Use @var{file} as initial ram disk. + +@item -tun-fd fd +Assumes @var{fd} talks to tap/tun and use it. Read +@url{http://bellard.org/qemu/tetrinet.html} to have an example of its +use. + +@item -nographic + +Normally, QEMU uses SDL to display the VGA output. With this option, +you can totally disable graphical output so that QEMU is a simple +command line application. The emulated serial port is redirected on +the console. Therefore, you can still use QEMU to debug a Linux kernel +with a serial console. + +@end table + +Linux boot specific (does not require a full PC boot with a BIOS): +@table @option + +@item -kernel bzImage +Use @var{bzImage} as kernel image. + +@item -append cmdline +Use @var{cmdline} as kernel command line + +@item -initrd file +Use @var{file} as initial ram disk. + @end table Debug options: @table @option @item -s -Wait gdb connection to port 1234. +Wait gdb connection to port 1234 (@xref{gdb_usage}). @item -p port Change gdb connection port. @item -d @@ -432,7 +534,25 @@ Send break (magic sysrq) @item C-a C-a Send C-a @end table +@c man end + +@ignore + +@setfilename qemu +@settitle QEMU System Emulator + +@c man begin SEEALSO +The HTML documentation of QEMU for more precise information and Linux +user mode emulator invocation. +@c man end + +@c man begin AUTHOR +Fabrice Bellard +@c man end + +@end ignore +@end ignore @node disk_images @section Disk Images @@ -466,14 +586,14 @@ same disk image template for many users. To create a COW disk images, use the command: @example -vlmkcow -f myrawimage.bin mycowimage.cow +qemu-mkcow -f myrawimage.bin mycowimage.cow @end example @file{myrawimage.bin} is a raw image you want to use as original disk image. It will never be written to. @file{mycowimage.cow} is the COW disk image which is created by -@code{vlmkcow}. You can use it directly with the @option{-hdx} +@code{qemu-mkcow}. You can use it directly with the @option{-hdx} options. You must not modify the original raw disk image if you use COW images, as COW images only store the modified sectors from the raw disk image. QEMU stores the original raw disk image name and its @@ -489,7 +609,7 @@ image. It is useful to have a big initial virtual disk image without using much disk space. Use: @example -vlmkcow mycowimage.cow 1024 +qemu-mkcow mycowimage.cow 1024 @end example to create a 1 gigabyte empty COW disk image. @@ -504,6 +624,7 @@ Since holes are used, the displayed size of the COW disk image is not the real one. To know it, use the @code{ls -ls} command. @end enumerate +@node linux_compile @section Linux Kernel Compilation You should be able to use any kernel with QEMU provided you make the @@ -573,31 +694,11 @@ As you would do to make a real kernel. Then you can use with QEMU exactly the same kernel as you would boot on your PC (in @file{arch/i386/boot/bzImage}). -@section PC Emulation - -QEMU emulates the following PC peripherials: - -@itemize -@item -PIC (interrupt controler) -@item -PIT (timers) -@item -CMOS memory -@item -Dumb VGA (to print the @code{Uncompressing Linux} message) -@item -Serial port (port=0x3f8, irq=4) -@item -NE2000 network adapter (port=0x300, irq=9) -@item -IDE disk interface (port=0x1f0, irq=14) -@end itemize - +@node gdb_usage @section GDB usage QEMU has a primitive support to work with gdb, so that you can do -'Ctrl-C' while the kernel is running and inspect its state. +'Ctrl-C' while the virtual machine is running and inspect its state. In order to use gdb, launch vl with the '-s' option. It will wait for a gdb connection: @@ -624,6 +725,18 @@ Then you can use gdb normally. For example, type 'c' to launch the kernel: WARNING: breakpoints and single stepping are not yet supported. +Here are some useful tips in order to use gdb on system code: + +@enumerate +@item +Use @code{info reg} to display all the CPU registers. +@item +Use @code{x/10i $eip} to display the code at the PC position. +@item +Use @code{set architecture i8086} to dump 16 bit code. Then use +@code{x/10i $cs*16+*eip} to dump the code at the PC position. +@end enumerate + @chapter QEMU Internals @section QEMU compared to other emulators -- cgit v1.2.3 From 34865134335df669132f9c2ed12d1e0be361f30f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Oct 2003 14:28:56 +0000 Subject: log activation from gdb - gdb single step support for x86 - stop timer when cpu is being debugged git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@402 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 4 ++ exec.c | 23 ++++++++++++ gdbstub.c | 17 +++++++++ target-i386/translate.c | 8 +++- vl.c | 97 ++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 125 insertions(+), 24 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 43c03c96c..00b9399e5 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -377,6 +377,10 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc); int cpu_breakpoint_remove(CPUState *env, uint32_t pc); void cpu_single_step(CPUState *env, int enabled); +#define CPU_LOG_ALL 1 +void cpu_set_log(int log_flags); +void cpu_set_log_filename(const char *filename); + /* memory API */ typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); diff --git a/exec.c b/exec.c index 46cccb5de..f4f6a9bc4 100644 --- a/exec.c +++ b/exec.c @@ -78,6 +78,11 @@ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; static int io_mem_nb; +/* log support */ +char *logfilename = "/tmp/qemu.log"; +FILE *logfile; +int loglevel; + static void page_init(void) { /* NOTE: we can always suppose that host_page_size >= @@ -676,6 +681,24 @@ void cpu_single_step(CPUState *env, int enabled) #endif } +/* enable or disable low levels log */ +void cpu_set_log(int log_flags) +{ + loglevel = log_flags; + if (loglevel && !logfile) { + logfile = fopen(logfilename, "w"); + if (!logfile) { + perror(logfilename); + _exit(1); + } + setvbuf(logfile, NULL, _IOLBF, 0); + } +} + +void cpu_set_log_filename(const char *filename) +{ + logfilename = strdup(filename); +} /* mask must never be zero */ void cpu_interrupt(CPUState *env, int mask) diff --git a/gdbstub.c b/gdbstub.c index d73a7efe3..15b3940ed 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -437,7 +437,24 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) goto breakpoint_error; } break; + case 'Q': + if (!strncmp(p, "Tinit", 5)) { + /* init traces */ + put_packet("OK"); + } else if (!strncmp(p, "TStart", 6)) { + /* start log (gdb 'tstart' command) */ + cpu_set_log(CPU_LOG_ALL); + put_packet("OK"); + } else if (!strncmp(p, "TStop", 5)) { + /* stop log (gdb 'tstop' command) */ + cpu_set_log(0); + put_packet("OK"); + } else { + goto unknown_command; + } + break; default: + unknown_command: /* put empty packet */ buf[0] = '\0'; put_packet(buf); diff --git a/target-i386/translate.c b/target-i386/translate.c index 4d89ccbba..43d3bbcbb 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -60,6 +60,7 @@ typedef struct DisasContext { int cpl; int iopl; int tf; /* TF cpu flag */ + int singlestep_enabled; /* "hardware" single step enabled */ int jmp_opt; /* use direct block chaining for direct jumps */ int mem_index; /* select memory access functions */ struct TranslationBlock *tb; @@ -1712,7 +1713,9 @@ static void gen_eob(DisasContext *s) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - if (s->tf) { + if (s->singlestep_enabled) { + gen_op_debug(); + } else if (s->tf) { gen_op_raise_exception(EXCP01_SSTP); } else { gen_op_movl_T0_0(); @@ -4368,6 +4371,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->cpl = (flags >> HF_CPL_SHIFT) & 3; dc->iopl = (flags >> IOPL_SHIFT) & 3; dc->tf = (flags >> TF_SHIFT) & 1; + dc->singlestep_enabled = env->singlestep_enabled; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; dc->tb = tb; @@ -4425,7 +4429,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, break; /* if single step mode, we generate only one instruction and generate an exception */ - if (dc->tf) { + if (dc->tf || dc->singlestep_enabled) { gen_op_jmp_im(pc_ptr - dc->cs_base); gen_eob(dc); break; diff --git a/vl.c b/vl.c index 2978694d6..f027bebb9 100644 --- a/vl.c +++ b/vl.c @@ -50,7 +50,6 @@ #include "vl.h" -#define DEBUG_LOGFILE "/tmp/vl.log" #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define BIOS_FILENAME "bios.bin" #define VGABIOS_FILENAME "vgabios.bin" @@ -209,8 +208,6 @@ static const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; CPUX86State *global_env; CPUX86State *cpu_single_env; -FILE *logfile = NULL; -int loglevel; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS]; @@ -832,20 +829,76 @@ int speaker_data_on; int dummy_refresh_clock; int pit_min_timer_count = 0; -int64_t get_clock(void) + +#if defined(__powerpc__) + +static inline uint32_t get_tbl(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000LL + tv.tv_usec; + uint32_t tbl; + asm volatile("mftb %0" : "=r" (tbl)); + return tbl; } -int64_t cpu_get_ticks(void) +static inline uint32_t get_tbu(void) +{ + uint32_t tbl; + asm volatile("mftbu %0" : "=r" (tbl)); + return tbl; +} + +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__) + +int64_t cpu_get_real_ticks(void) { int64_t val; asm("rdtsc" : "=A" (val)); return val; } +#else +#error unsupported CPU +#endif + +static int64_t cpu_ticks_offset; +static int64_t cpu_ticks_last; + +int64_t cpu_get_ticks(void) +{ + return cpu_get_real_ticks() + cpu_ticks_offset; +} + +/* enable cpu_get_ticks() */ +void cpu_enable_ticks(void) +{ + cpu_ticks_offset = cpu_ticks_last - cpu_get_real_ticks(); +} + +/* disable cpu_get_ticks() : the clock is stopped. You must not call + cpu_get_ticks() after that. */ +void cpu_disable_ticks(void) +{ + cpu_ticks_last = cpu_get_ticks(); +} + +int64_t get_clock(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000LL + tv.tv_usec; +} + void cpu_calibrate_ticks(void) { int64_t usec, ticks; @@ -3297,12 +3350,17 @@ int main_loop(void *opaque) } serial_ok = 1; + cpu_enable_ticks(); for(;;) { ret = cpu_x86_exec(env); - if (reset_requested) + if (reset_requested) { + ret = EXCP_INTERRUPT; break; - if (ret == EXCP_DEBUG) - return EXCP_DEBUG; + } + if (ret == EXCP_DEBUG) { + ret = EXCP_DEBUG; + break; + } /* if hlt instruction, we wait until the next IRQ */ if (ret == EXCP_HLT) timeout = 10; @@ -3359,8 +3417,10 @@ int main_loop(void *opaque) uint8_t buf[1]; /* stop emulation if requested by gdb */ n = read(gdbstub_fd, buf, 1); - if (n == 1) + if (n == 1) { + ret = EXCP_INTERRUPT; break; + } } } @@ -3377,7 +3437,8 @@ int main_loop(void *opaque) gui_refresh_pending = 0; } } - return EXCP_INTERRUPT; + cpu_disable_ticks(); + return ret; } void help(void) @@ -3535,7 +3596,7 @@ int main(int argc, char **argv) } break; case 'd': - loglevel = 1; + cpu_set_log(CPU_LOG_ALL); break; case 'n': pstrcpy(network_script, sizeof(network_script), optarg); @@ -3563,14 +3624,6 @@ int main(int argc, char **argv) /* init debug */ setvbuf(stdout, NULL, _IOLBF, 0); - if (loglevel) { - logfile = fopen(DEBUG_LOGFILE, "w"); - if (!logfile) { - perror(DEBUG_LOGFILE); - _exit(1); - } - setvbuf(logfile, NULL, _IOLBF, 0); - } /* init network tun interface */ if (net_fd < 0) -- cgit v1.2.3 From 16e9b7de41bc4163fe53140f387c020ea55d0a06 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:09:52 +0000 Subject: filename fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@403 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Makefile.target b/Makefile.target index ee5443867..cfb3cd88f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -17,8 +17,14 @@ else QEMU_SYSTEM=qemu endif -ifndef CONFIG_SOFTMMU +ifdef CONFIG_USER_ONLY PROGS=$(QEMU_USER) +else +ifeq ($(ARCH),i386) +ifeq ($(TARGET_ARCH), i386) +PROGS+=$(QEMU_SYSTEM) +endif +endif endif ifdef CONFIG_STATIC @@ -41,9 +47,6 @@ else # is the simplest way to make it self virtualizable! LDFLAGS+=-Wl,-shared endif -ifeq ($(TARGET_ARCH), i386) -PROGS+=$(QEMU_SYSTEM) -endif endif ifeq ($(ARCH),ppc) @@ -171,7 +174,7 @@ sdl.o: sdl.c $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< depend: $(SRCS) - $(CC) -MM $(CFLAGS) $^ 1>.depend + $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend # libqemu -- cgit v1.2.3 From 997344f303a7a7d5c0e21c2a90ada350da2be8f9 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:10:39 +0000 Subject: added i386 user only target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@404 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 443d648a7..0e2227084 100755 --- a/configure +++ b/configure @@ -27,7 +27,7 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386 i386-softmmu arm sparc" +target_list="i386-user i386 i386-softmmu arm-user sparc-user" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" @@ -324,6 +324,10 @@ 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 echo "Creating $config_mak, $config_h and $target_dir/Makefile" @@ -364,6 +368,10 @@ 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 done # for target in $targets -- cgit v1.2.3 From db8d74668856e5bbc6c8fede0bb17c4f83e7debf Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:12:17 +0000 Subject: comments git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@405 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 3ec866fa7..84b5e280e 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -32,8 +32,15 @@ #define CPU_TLB_SIZE 256 typedef struct CPUTLBEntry { - uint32_t address; - uint32_t addend; + /* 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 + */ + uint32_t address; + /* addend to virtual address to get physical address */ + uint32_t addend; } CPUTLBEntry; #endif -- cgit v1.2.3 From 93a40ea9264dfd5df63669e785fed1c9db0041f4 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:13:06 +0000 Subject: fixed mmu fault priviledge logic git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@406 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 035f10414..956504d82 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -225,7 +225,7 @@ int cpu_exec(CPUState *env1) cpu_arm_dump_state(env, logfile, 0); env->cpsr &= ~0xf0000000; #elif defined(TARGET_SPARC) - cpu_sparc_dump_state (env, logfile, 0); + cpu_sparc_dump_state (env, logfile, 0); #else #error unsupported target CPU #endif @@ -273,6 +273,7 @@ int cpu_exec(CPUState *env1) tb->tc_ptr = tc_ptr; tb->cs_base = (unsigned long)cs_base; tb->flags = flags; + /* XXX: an MMU exception can occur here */ cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); *ptb = tb; tb->hash_next = NULL; @@ -456,7 +457,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } /* see if it is an MMU fault */ - ret = cpu_x86_handle_mmu_fault(env, address, is_write); + 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) -- cgit v1.2.3 From c6105c0a042ba0ecb59038f9f2edab8aa4322baf Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:13:58 +0000 Subject: added correct memory access code for system emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@407 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/disas.c b/disas.c index 81ba50a96..0c8cc2a8f 100644 --- a/disas.c +++ b/disas.c @@ -5,6 +5,9 @@ #include "elf.h" #include +#include "cpu.h" +#include "exec-all.h" + /* Filled in by elfload.c. Simplistic, but will do for now. */ unsigned int disas_num_syms; void *disas_symtab; @@ -19,14 +22,32 @@ buffer_read_memory (memaddr, myaddr, length, info) 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; + 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; } +#if !defined(CONFIG_USER_ONLY) +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +static int +target_read_memory (memaddr, myaddr, length, info) + bfd_vma memaddr; + bfd_byte *myaddr; + int length; + struct disassemble_info *info; +{ + int i; + for(i = 0; i < length; i++) { + myaddr[i] = ldub_code((void *)((long)memaddr)); + } + return 0; +} +#endif + /* Print an error message. We can assume that this is in response to an error return from buffer_read_memory. */ void @@ -103,6 +124,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); +#if !defined(CONFIG_USER_ONLY) + if (!is_host) { + disasm_info.read_memory_func = target_read_memory; + } +#endif + disasm_info.buffer = code; disasm_info.buffer_vma = (unsigned long)code; disasm_info.buffer_length = size; -- cgit v1.2.3 From cc38b844d71d3ee1dd15a8cce152431717e4e17b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:16:14 +0000 Subject: factorized debug code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@408 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 811b8bfba..6df7b42c5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -28,8 +28,6 @@ #define DEBUG_LOGFILE "/tmp/qemu.log" -FILE *logfile = NULL; -int loglevel; static const char *interp_prefix = CONFIG_QEMU_PREFIX; #ifdef __i386__ @@ -367,7 +365,9 @@ int main(int argc, char **argv) if (argc <= 1) usage(); - loglevel = 0; + /* init debug */ + cpu_set_log_filename(DEBUG_LOGFILE); + optind = 1; for(;;) { if (optind >= argc) @@ -380,7 +380,7 @@ int main(int argc, char **argv) if (!strcmp(r, "-")) { break; } else if (!strcmp(r, "d")) { - loglevel = 1; + cpu_set_log(CPU_LOG_ALL); } else if (!strcmp(r, "s")) { r = argv[optind++]; x86_stack_size = strtol(r, (char **)&r, 0); @@ -407,16 +407,6 @@ int main(int argc, char **argv) usage(); filename = argv[optind]; - /* init debug */ - if (loglevel) { - logfile = fopen(DEBUG_LOGFILE, "w"); - if (!logfile) { - perror(DEBUG_LOGFILE); - _exit(1); - } - setvbuf(logfile, NULL, _IOLBF, 0); - } - /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); -- cgit v1.2.3 From 3a51dee658b9cc781acd57dd11bffbd1e402f93d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:18:35 +0000 Subject: disabled signal hacks for softmmu version (qemu should be much more portable now...) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@409 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 62 +++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/vl.c b/vl.c index f027bebb9..1286fac0b 100644 --- a/vl.c +++ b/vl.c @@ -2067,40 +2067,40 @@ static void ide_identify(IDEState *s) memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; - stw(p + 0, 0x0040); - stw(p + 1, s->cylinders); - stw(p + 3, s->heads); - stw(p + 4, 512 * s->sectors); /* sectors */ - stw(p + 5, 512); /* sector size */ - stw(p + 6, s->sectors); - stw(p + 20, 3); /* buffer type */ - stw(p + 21, 512); /* cache size in sectors */ - stw(p + 22, 4); /* ecc bytes */ + stw_raw(p + 0, 0x0040); + stw_raw(p + 1, s->cylinders); + stw_raw(p + 3, s->heads); + stw_raw(p + 4, 512 * s->sectors); /* sectors */ + stw_raw(p + 5, 512); /* sector size */ + stw_raw(p + 6, s->sectors); + stw_raw(p + 20, 3); /* buffer type */ + stw_raw(p + 21, 512); /* cache size in sectors */ + stw_raw(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); #if MAX_MULT_SECTORS > 1 - stw(p + 47, MAX_MULT_SECTORS); + stw_raw(p + 47, MAX_MULT_SECTORS); #endif - stw(p + 48, 1); /* dword I/O */ - stw(p + 49, 1 << 9); /* LBA supported, no DMA */ - stw(p + 51, 0x200); /* PIO transfer cycle */ - stw(p + 52, 0x200); /* DMA transfer cycle */ - stw(p + 54, s->cylinders); - stw(p + 55, s->heads); - stw(p + 56, s->sectors); + stw_raw(p + 48, 1); /* dword I/O */ + stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ + stw_raw(p + 51, 0x200); /* PIO transfer cycle */ + stw_raw(p + 52, 0x200); /* DMA transfer cycle */ + stw_raw(p + 54, s->cylinders); + stw_raw(p + 55, s->heads); + stw_raw(p + 56, s->sectors); oldsize = s->cylinders * s->heads * s->sectors; - stw(p + 57, oldsize); - stw(p + 58, oldsize >> 16); + stw_raw(p + 57, oldsize); + stw_raw(p + 58, oldsize >> 16); if (s->mult_sectors) - stw(p + 59, 0x100 | s->mult_sectors); - stw(p + 60, s->nb_sectors); - stw(p + 61, s->nb_sectors >> 16); - stw(p + 80, (1 << 1) | (1 << 2)); - stw(p + 82, (1 << 14)); - stw(p + 83, (1 << 14)); - stw(p + 84, (1 << 14)); - stw(p + 85, (1 << 14)); - stw(p + 86, 0); - stw(p + 87, (1 << 14)); + stw_raw(p + 59, 0x100 | s->mult_sectors); + stw_raw(p + 60, s->nb_sectors); + stw_raw(p + 61, s->nb_sectors >> 16); + stw_raw(p + 80, (1 << 1) | (1 << 2)); + stw_raw(p + 82, (1 << 14)); + stw_raw(p + 83, (1 << 14)); + stw_raw(p + 84, (1 << 14)); + stw_raw(p + 85, (1 << 14)); + stw_raw(p + 86, 0); + stw_raw(p + 87, (1 << 14)); } static inline void ide_abort_command(IDEState *s) @@ -3275,6 +3275,7 @@ void dumb_display_init(DisplayState *ds) ds->dpy_refresh = dumb_refresh; } +#if !defined(CONFIG_SOFTMMU) /***********************************************************/ /* cpu signal handler */ static void host_segv_handler(int host_signum, siginfo_t *info, @@ -3285,6 +3286,7 @@ static void host_segv_handler(int host_signum, siginfo_t *info, term_exit(); abort(); } +#endif static int timer_irq_pending; static int timer_irq_count; @@ -3807,9 +3809,11 @@ int main(int argc, char **argv) /* setup cpu signal handlers for MMU / self modifying code handling */ sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; +#if !defined(CONFIG_SOFTMMU) act.sa_sigaction = host_segv_handler; sigaction(SIGSEGV, &act, NULL); sigaction(SIGBUS, &act, NULL); +#endif act.sa_sigaction = host_alarm_handler; sigaction(SIGALRM, &act, NULL); -- cgit v1.2.3 From 61382a500a9e54ef96ca28e0f221151f569cbb6e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:22:23 +0000 Subject: full softmmu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@410 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 133 ++++++++++++++++++++------------ exec.c | 103 +++++++++++++++++++------ hw/vga_template.h | 4 +- softmmu_header.h | 70 ++++++++++++----- softmmu_template.h | 82 ++++++++++++-------- target-i386/exec.h | 100 +++++++++++++++++++----- target-i386/helper.c | 198 +++++++++++++++++++++++++++--------------------- target-i386/helper2.c | 76 +++++++++++-------- target-i386/op.c | 4 +- target-i386/translate.c | 163 ++++++++++++++++++++------------------- 10 files changed, 594 insertions(+), 339 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 00b9399e5..c91813fba 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -20,18 +20,19 @@ #ifndef CPU_ALL_H #define CPU_ALL_H -/* all CPU memory access use these macros */ -static inline int ldub(void *ptr) +/* CPU memory access without any memory or io remapping */ + +static inline int ldub_raw(void *ptr) { return *(uint8_t *)ptr; } -static inline int ldsb(void *ptr) +static inline int ldsb_raw(void *ptr) { return *(int8_t *)ptr; } -static inline void stb(void *ptr, int v) +static inline void stb_raw(void *ptr, int v) { *(uint8_t *)ptr = v; } @@ -42,7 +43,7 @@ static inline void stb(void *ptr, int v) #if defined(WORDS_BIGENDIAN) || defined(__arm__) /* conservative code for little endian unaligned accesses */ -static inline int lduw(void *ptr) +static inline int lduw_raw(void *ptr) { #ifdef __powerpc__ int val; @@ -54,7 +55,7 @@ static inline int lduw(void *ptr) #endif } -static inline int ldsw(void *ptr) +static inline int ldsw_raw(void *ptr) { #ifdef __powerpc__ int val; @@ -66,7 +67,7 @@ static inline int ldsw(void *ptr) #endif } -static inline int ldl(void *ptr) +static inline int ldl_raw(void *ptr) { #ifdef __powerpc__ int val; @@ -78,16 +79,16 @@ static inline int ldl(void *ptr) #endif } -static inline uint64_t ldq(void *ptr) +static inline uint64_t ldq_raw(void *ptr) { uint8_t *p = ptr; uint32_t v1, v2; - v1 = ldl(p); - v2 = ldl(p + 4); + v1 = ldl_raw(p); + v2 = ldl_raw(p + 4); return v1 | ((uint64_t)v2 << 32); } -static inline void stw(void *ptr, int v) +static inline void stw_raw(void *ptr, int v) { #ifdef __powerpc__ __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); @@ -98,7 +99,7 @@ static inline void stw(void *ptr, int v) #endif } -static inline void stl(void *ptr, int v) +static inline void stl_raw(void *ptr, int v) { #ifdef __powerpc__ __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); @@ -111,104 +112,104 @@ static inline void stl(void *ptr, int v) #endif } -static inline void stq(void *ptr, uint64_t v) +static inline void stq_raw(void *ptr, uint64_t v) { uint8_t *p = ptr; - stl(p, (uint32_t)v); - stl(p + 4, v >> 32); + stl_raw(p, (uint32_t)v); + stl_raw(p + 4, v >> 32); } /* float access */ -static inline float ldfl(void *ptr) +static inline float ldfl_raw(void *ptr) { union { float f; uint32_t i; } u; - u.i = ldl(ptr); + u.i = ldl_raw(ptr); return u.f; } -static inline void stfl(void *ptr, float v) +static inline void stfl_raw(void *ptr, float v) { union { float f; uint32_t i; } u; u.f = v; - stl(ptr, u.i); + stl_raw(ptr, u.i); } #if defined(__arm__) && !defined(WORDS_BIGENDIAN) /* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ -static inline double ldfq(void *ptr) +static inline double ldfq_raw(void *ptr) { union { double d; uint32_t tab[2]; } u; - u.tab[1] = ldl(ptr); - u.tab[0] = ldl(ptr + 4); + u.tab[1] = ldl_raw(ptr); + u.tab[0] = ldl_raw(ptr + 4); return u.d; } -static inline void stfq(void *ptr, double v) +static inline void stfq_raw(void *ptr, double v) { union { double d; uint32_t tab[2]; } u; u.d = v; - stl(ptr, u.tab[1]); - stl(ptr + 4, u.tab[0]); + stl_raw(ptr, u.tab[1]); + stl_raw(ptr + 4, u.tab[0]); } #else -static inline double ldfq(void *ptr) +static inline double ldfq_raw(void *ptr) { union { double d; uint64_t i; } u; - u.i = ldq(ptr); + u.i = ldq_raw(ptr); return u.d; } -static inline void stfq(void *ptr, double v) +static inline void stfq_raw(void *ptr, double v) { union { double d; uint64_t i; } u; u.d = v; - stq(ptr, u.i); + stq_raw(ptr, u.i); } #endif #elif defined(TARGET_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN) -static inline int lduw(void *ptr) +static inline int lduw_raw(void *ptr) { uint8_t *b = (uint8_t *) ptr; return (b[0]<<8|b[1]); } -static inline int ldsw(void *ptr) +static inline int ldsw_raw(void *ptr) { int8_t *b = (int8_t *) ptr; return (b[0]<<8|b[1]); } -static inline int ldl(void *ptr) +static inline int ldl_raw(void *ptr) { uint8_t *b = (uint8_t *) ptr; return (b[0]<<24|b[1]<<16|b[2]<<8|b[3]); } -static inline uint64_t ldq(void *ptr) +static inline uint64_t ldq_raw(void *ptr) { uint32_t a,b; a = ldl (ptr); @@ -216,14 +217,14 @@ static inline uint64_t ldq(void *ptr) return (((uint64_t)a<<32)|b); } -static inline void stw(void *ptr, int v) +static inline void stw_raw(void *ptr, int v) { uint8_t *d = (uint8_t *) ptr; d[0] = v >> 8; d[1] = v; } -static inline void stl(void *ptr, int v) +static inline void stl_raw(void *ptr, int v) { uint8_t *d = (uint8_t *) ptr; d[0] = v >> 24; @@ -232,7 +233,7 @@ static inline void stl(void *ptr, int v) d[3] = v; } -static inline void stq(void *ptr, uint64_t v) +static inline void stq_raw(void *ptr, uint64_t v) { stl (ptr, v); stl (ptr+4, v >> 32); @@ -240,64 +241,102 @@ static inline void stq(void *ptr, uint64_t v) #else -static inline int lduw(void *ptr) +static inline int lduw_raw(void *ptr) { return *(uint16_t *)ptr; } -static inline int ldsw(void *ptr) +static inline int ldsw_raw(void *ptr) { return *(int16_t *)ptr; } -static inline int ldl(void *ptr) +static inline int ldl_raw(void *ptr) { return *(uint32_t *)ptr; } -static inline uint64_t ldq(void *ptr) +static inline uint64_t ldq_raw(void *ptr) { return *(uint64_t *)ptr; } -static inline void stw(void *ptr, int v) +static inline void stw_raw(void *ptr, int v) { *(uint16_t *)ptr = v; } -static inline void stl(void *ptr, int v) +static inline void stl_raw(void *ptr, int v) { *(uint32_t *)ptr = v; } -static inline void stq(void *ptr, uint64_t v) +static inline void stq_raw(void *ptr, uint64_t v) { *(uint64_t *)ptr = v; } /* float access */ -static inline float ldfl(void *ptr) +static inline float ldfl_raw(void *ptr) { return *(float *)ptr; } -static inline double ldfq(void *ptr) +static inline double ldfq_raw(void *ptr) { return *(double *)ptr; } -static inline void stfl(void *ptr, float v) +static inline void stfl_raw(void *ptr, float v) { *(float *)ptr = v; } -static inline void stfq(void *ptr, double v) +static inline void stfq_raw(void *ptr, double v) { *(double *)ptr = v; } #endif +/* MMU memory access macros */ + +#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 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) + +#endif /* defined(CONFIG_USER_ONLY) */ + /* page related stuff */ #define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) diff --git a/exec.c b/exec.c index f4f6a9bc4..ca767e2af 100644 --- a/exec.c +++ b/exec.c @@ -444,16 +444,20 @@ static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index) prot = 0; for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) prot |= page_get_flags(addr); +#if !defined(CONFIG_SOFTMMU) mprotect((void *)host_start, host_page_size, (prot & PAGE_BITS) & ~PAGE_WRITE); +#endif +#if !defined(CONFIG_USER_ONLY) + /* suppress soft TLB */ + /* XXX: must flush on all processor with same address space */ + tlb_flush_page_write(cpu_single_env, host_start); +#endif #ifdef DEBUG_TB_INVALIDATE printf("protecting code page: 0x%08lx\n", host_start); #endif p->flags &= ~PAGE_WRITE; -#ifdef DEBUG_TB_CHECK - tb_page_check(); -#endif } } @@ -483,6 +487,9 @@ void tb_link(TranslationBlock *tb) if (page_index2 != page_index1) { tb_alloc_page(tb, page_index2); } +#ifdef DEBUG_TB_CHECK + tb_page_check(); +#endif tb->jmp_first = (TranslationBlock *)((long)tb | 2); tb->jmp_next[0] = NULL; tb->jmp_next[1] = NULL; @@ -517,20 +524,23 @@ int page_unprotect(unsigned long address) /* if the page was really writable, then we change its protection back to writable */ if (prot & PAGE_WRITE_ORG) { - mprotect((void *)host_start, host_page_size, - (prot & PAGE_BITS) | PAGE_WRITE); pindex = (address - host_start) >> TARGET_PAGE_BITS; - p1[pindex].flags |= PAGE_WRITE; - /* and since the content will be modified, we must invalidate - the corresponding translated code. */ - tb_invalidate_page(address); + if (!(p1[pindex].flags & PAGE_WRITE)) { +#if !defined(CONFIG_SOFTMMU) + mprotect((void *)host_start, host_page_size, + (prot & PAGE_BITS) | PAGE_WRITE); +#endif + p1[pindex].flags |= PAGE_WRITE; + /* and since the content will be modified, we must invalidate + the corresponding translated code. */ + tb_invalidate_page(address); #ifdef DEBUG_TB_CHECK - tb_invalidate_check(address); + tb_invalidate_check(address); #endif - return 1; - } else { - return 0; + return 1; + } } + return 0; } /* call this function when system calls directly modify a memory area */ @@ -734,13 +744,17 @@ void cpu_abort(CPUState *env, const char *fmt, ...) /* unmap all maped pages and flush all associated code */ void page_unmap(void) { - PageDesc *p, *pmap; - unsigned long addr; - int i, j, ret, j1; + PageDesc *pmap; + int i; for(i = 0; i < L1_SIZE; i++) { pmap = l1_map[i]; if (pmap) { +#if !defined(CONFIG_SOFTMMU) + PageDesc *p; + unsigned long addr; + int j, ret, j1; + p = pmap; for(j = 0;j < L2_SIZE;) { if (p->flags & PAGE_VALID) { @@ -763,6 +777,7 @@ void page_unmap(void) j++; } } +#endif free(pmap); l1_map[i] = NULL; } @@ -773,7 +788,7 @@ void page_unmap(void) void tlb_flush(CPUState *env) { -#if defined(TARGET_I386) +#if !defined(CONFIG_USER_ONLY) int i; for(i = 0; i < CPU_TLB_SIZE; i++) { env->tlb_read[0][i].address = -1; @@ -784,16 +799,38 @@ void tlb_flush(CPUState *env) #endif } +static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) +{ + if (addr == (tlb_entry->address & + (TARGET_PAGE_MASK | TLB_INVALID_MASK))) + tlb_entry->address = -1; +} + void tlb_flush_page(CPUState *env, uint32_t addr) { -#if defined(TARGET_I386) +#if !defined(CONFIG_USER_ONLY) + int i; + + addr &= TARGET_PAGE_MASK; + i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_flush_entry(&env->tlb_read[0][i], addr); + tlb_flush_entry(&env->tlb_write[0][i], addr); + tlb_flush_entry(&env->tlb_read[1][i], addr); + tlb_flush_entry(&env->tlb_write[1][i], addr); +#endif +} + +/* make all write to page 'addr' trigger a TLB exception to detect + self modifying code */ +void tlb_flush_page_write(CPUState *env, uint32_t addr) +{ +#if !defined(CONFIG_USER_ONLY) int i; + addr &= TARGET_PAGE_MASK; i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - env->tlb_read[0][i].address = -1; - env->tlb_write[0][i].address = -1; - env->tlb_read[1][i].address = -1; - env->tlb_write[1][i].address = -1; + tlb_flush_entry(&env->tlb_write[0][i], addr); + tlb_flush_entry(&env->tlb_write[1][i], addr); #endif } @@ -900,3 +937,25 @@ int cpu_register_io_memory(int io_index, } return io_index << IO_MEM_SHIFT; } + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _cmmu +#define GETPC() NULL +#define env cpu_single_env + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +#undef env + +#endif diff --git a/hw/vga_template.h b/hw/vga_template.h index 0d1d5ce73..cc4df95e3 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -354,7 +354,7 @@ static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d, w = width; do { - v = lduw((void *)s); + v = lduw_raw((void *)s); r = (v >> 7) & 0xf8; g = (v >> 2) & 0xf8; b = (v << 3) & 0xf8; @@ -379,7 +379,7 @@ static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d, w = width; do { - v = lduw((void *)s); + v = lduw_raw((void *)s); r = (v >> 8) & 0xf8; g = (v >> 3) & 0xfc; b = (v << 3) & 0xf8; diff --git a/softmmu_header.h b/softmmu_header.h index 36cf9f0a1..26b4f2cdd 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -19,26 +19,48 @@ */ #if DATA_SIZE == 8 #define SUFFIX q +#define USUFFIX q #define DATA_TYPE uint64_t #elif DATA_SIZE == 4 #define SUFFIX l +#define USUFFIX l #define DATA_TYPE uint32_t #elif DATA_SIZE == 2 #define SUFFIX w +#define USUFFIX uw #define DATA_TYPE uint16_t #define DATA_STYPE int16_t #elif DATA_SIZE == 1 #define SUFFIX b +#define USUFFIX ub #define DATA_TYPE uint8_t #define DATA_STYPE int8_t #else #error unsupported data size #endif -#if MEMUSER == 0 -#define MEMSUFFIX _kernel +#if ACCESS_TYPE == 0 + +#define CPU_MEM_INDEX 0 +#define MMUSUFFIX _mmu + +#elif ACCESS_TYPE == 1 + +#define CPU_MEM_INDEX 1 +#define MMUSUFFIX _mmu + +#elif ACCESS_TYPE == 2 + +#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) +#define MMUSUFFIX _mmu + +#elif ACCESS_TYPE == 3 + +#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) +#define MMUSUFFIX _cmmu + #else -#define MEMSUFFIX _user +#error invalid ACCESS_TYPE #endif #if DATA_SIZE == 8 @@ -48,24 +70,26 @@ #endif -#if MEMUSER == 0 -DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr); -void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE v); -#endif +DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, + int is_user); +void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, DATA_TYPE v, int is_user); -static inline int glue(glue(ldu, SUFFIX), MEMSUFFIX)(void *ptr) +static inline int glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) { int index; RES_TYPE res; unsigned long addr, physaddr; + int is_user; + addr = (unsigned long)ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - if (__builtin_expect(env->tlb_read[MEMUSER][index].address != + is_user = CPU_MEM_INDEX; + if (__builtin_expect(env->tlb_read[is_user][index].address != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { - res = glue(glue(__ld, SUFFIX), _mmu)(addr); + res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user); } else { - physaddr = addr + env->tlb_read[MEMUSER][index].addend; - res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr); + physaddr = addr + env->tlb_read[is_user][index].addend; + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); } return res; } @@ -75,13 +99,16 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr) { int res, index; unsigned long addr, physaddr; + int is_user; + addr = (unsigned long)ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - if (__builtin_expect(env->tlb_read[MEMUSER][index].address != + is_user = CPU_MEM_INDEX; + if (__builtin_expect(env->tlb_read[is_user][index].address != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { - res = (DATA_STYPE)glue(glue(__ld, SUFFIX), _mmu)(addr); + res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user); } else { - physaddr = addr + env->tlb_read[MEMUSER][index].addend; + physaddr = addr + env->tlb_read[is_user][index].addend; res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); } return res; @@ -92,13 +119,16 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) { int index; unsigned long addr, physaddr; + int is_user; + addr = (unsigned long)ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - if (__builtin_expect(env->tlb_write[MEMUSER][index].address != + is_user = CPU_MEM_INDEX; + if (__builtin_expect(env->tlb_write[is_user][index].address != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { - glue(glue(__st, SUFFIX), _mmu)(addr, v); + glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user); } else { - physaddr = addr + env->tlb_write[MEMUSER][index].addend; + physaddr = addr + env->tlb_write[is_user][index].addend; glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); } } @@ -107,5 +137,7 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) #undef DATA_TYPE #undef DATA_STYPE #undef SUFFIX +#undef USUFFIX #undef DATA_SIZE -#undef MEMSUFFIX +#undef CPU_MEM_INDEX +#undef MMUSUFFIX diff --git a/softmmu_template.h b/softmmu_template.h index 765e913a6..4f4f2f4d3 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -21,23 +21,31 @@ #if DATA_SIZE == 8 #define SUFFIX q +#define USUFFIX q #define DATA_TYPE uint64_t #elif DATA_SIZE == 4 #define SUFFIX l +#define USUFFIX l #define DATA_TYPE uint32_t #elif DATA_SIZE == 2 #define SUFFIX w +#define USUFFIX uw #define DATA_TYPE uint16_t #elif DATA_SIZE == 1 #define SUFFIX b +#define USUFFIX ub #define DATA_TYPE uint8_t #else #error unsupported data size #endif -static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr); -static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, - void *retaddr); +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, + int is_user, + void *retaddr); +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, + DATA_TYPE val, + int is_user, + void *retaddr); static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, unsigned long tlb_addr) @@ -81,16 +89,16 @@ static inline void glue(io_write, SUFFIX)(unsigned long physaddr, } /* handle all cases except unaligned access which span two pages */ -DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr) +DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, + int is_user) { DATA_TYPE res; - int is_user, index; + int index; unsigned long physaddr, tlb_addr; void *retaddr; /* test if there is match for unaligned or IO access */ /* XXX: could done more in memory macro in a non portable way */ - is_user = ((env->hflags & HF_CPL_MASK) == 3); index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_read[is_user][index].address; @@ -104,29 +112,31 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr) } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { /* slow unaligned access (it spans two pages or IO) */ do_unaligned_access: - retaddr = __builtin_return_address(0); - res = glue(slow_ld, SUFFIX)(addr, retaddr); + retaddr = GETPC(); + res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, + is_user, retaddr); } else { /* unaligned access in the same page */ - res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr); + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); } } else { /* the page is not in the TLB : fill it */ - retaddr = __builtin_return_address(0); - tlb_fill(addr, 0, retaddr); + retaddr = GETPC(); + tlb_fill(addr, 0, is_user, retaddr); goto redo; } return res; } /* handle all unaligned cases */ -static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr) +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, + int is_user, + void *retaddr) { DATA_TYPE res, res1, res2; - int is_user, index, shift; + int index, shift; unsigned long physaddr, tlb_addr, addr1, addr2; - is_user = ((env->hflags & HF_CPL_MASK) == 3); index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_read[is_user][index].address; @@ -142,8 +152,10 @@ static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr) /* slow unaligned access (it spans two pages) */ addr1 = addr & ~(DATA_SIZE - 1); addr2 = addr1 + DATA_SIZE; - res1 = glue(slow_ld, SUFFIX)(addr1, retaddr); - res2 = glue(slow_ld, SUFFIX)(addr2, retaddr); + res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, + is_user, retaddr); + res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, + is_user, retaddr); shift = (addr & (DATA_SIZE - 1)) * 8; #ifdef TARGET_WORDS_BIGENDIAN res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); @@ -152,24 +164,25 @@ static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr) #endif } else { /* unaligned/aligned access in the same page */ - res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr); + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); } } else { /* the page is not in the TLB : fill it */ - tlb_fill(addr, 0, retaddr); + tlb_fill(addr, 0, is_user, retaddr); goto redo; } return res; } -void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val) +void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, + DATA_TYPE val, + int is_user) { unsigned long physaddr, tlb_addr; void *retaddr; - int is_user, index; + int index; - is_user = ((env->hflags & HF_CPL_MASK) == 3); index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_write[is_user][index].address; @@ -182,28 +195,30 @@ void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val glue(io_write, SUFFIX)(physaddr, val, tlb_addr); } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: - retaddr = __builtin_return_address(0); - glue(slow_st, SUFFIX)(addr, val, retaddr); + retaddr = GETPC(); + glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, + is_user, retaddr); } else { /* aligned/unaligned access in the same page */ glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val); } } else { /* the page is not in the TLB : fill it */ - retaddr = __builtin_return_address(0); - tlb_fill(addr, 1, retaddr); + retaddr = GETPC(); + tlb_fill(addr, 1, is_user, retaddr); goto redo; } } /* handles all unaligned cases */ -static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, - void *retaddr) +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, + DATA_TYPE val, + int is_user, + void *retaddr) { unsigned long physaddr, tlb_addr; - int is_user, index, i; + int index, i; - is_user = ((env->hflags & HF_CPL_MASK) == 3); index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_write[is_user][index].address; @@ -219,9 +234,11 @@ static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, /* XXX: not efficient, but simple */ for(i = 0;i < DATA_SIZE; i++) { #ifdef TARGET_WORDS_BIGENDIAN - slow_stb(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), retaddr); + glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), + is_user, retaddr); #else - slow_stb(addr + i, val >> (i * 8), retaddr); + glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), + is_user, retaddr); #endif } } else { @@ -230,7 +247,7 @@ static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, } } else { /* the page is not in the TLB : fill it */ - tlb_fill(addr, 1, retaddr); + tlb_fill(addr, 1, is_user, retaddr); goto redo; } } @@ -238,4 +255,5 @@ static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, #undef SHIFT #undef DATA_TYPE #undef SUFFIX +#undef USUFFIX #undef DATA_SIZE diff --git a/target-i386/exec.h b/target-i386/exec.h index b53928c98..eb13186cf 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -137,8 +137,10 @@ void helper_invlpg(unsigned int addr); void cpu_x86_update_cr0(CPUX86State *env); void cpu_x86_update_cr3(CPUX86State *env); void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); -void tlb_fill(unsigned long addr, int is_write, void *retaddr); +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, + int is_write, int is_user, int is_softmmu); +void tlb_fill(unsigned long addr, int is_write, int is_user, + void *retaddr); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); void do_interrupt(int intno, int is_int, int error_code, @@ -366,26 +368,30 @@ static inline void load_eflags(int eflags, int update_mask) (eflags & update_mask); } -/* memory access macros */ +/* XXX: move that to a generic header */ +#if !defined(CONFIG_USER_ONLY) -#define ldul ldl -#define lduq ldq #define ldul_user ldl_user #define ldul_kernel ldl_kernel -#define ldub_raw ldub -#define ldsb_raw ldsb -#define lduw_raw lduw -#define ldsw_raw ldsw -#define ldl_raw ldl -#define ldq_raw ldq +#define ACCESS_TYPE 0 +#define MEMSUFFIX _kernel +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" -#define stb_raw stb -#define stw_raw stw -#define stl_raw stl -#define stq_raw stq +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX -#define MEMUSER 0 +#define ACCESS_TYPE 1 +#define MEMSUFFIX _user #define DATA_SIZE 1 #include "softmmu_header.h" @@ -397,9 +403,12 @@ static inline void load_eflags(int eflags, int update_mask) #define DATA_SIZE 8 #include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX -#undef MEMUSER -#define MEMUSER 1 +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE 2 +#define MEMSUFFIX _data #define DATA_SIZE 1 #include "softmmu_header.h" @@ -411,6 +420,59 @@ static inline void load_eflags(int eflags, int update_mask) #define DATA_SIZE 8 #include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ldub(p) ldub_data(p) +#define ldsb(p) ldsb_data(p) +#define lduw(p) lduw_data(p) +#define ldsw(p) ldsw_data(p) +#define ldl(p) ldl_data(p) +#define ldq(p) ldq_data(p) + +#define stb(p, v) stb_data(p, v) +#define stw(p, v) stw_data(p, v) +#define stl(p, v) stl_data(p, v) +#define stq(p, v) stq_data(p, v) + +static inline double ldfq(void *ptr) +{ + union { + double d; + uint64_t i; + } u; + u.i = ldq(ptr); + return u.d; +} + +static inline void stfq(void *ptr, double v) +{ + union { + double d; + uint64_t i; + } u; + u.d = v; + stq(ptr, u.i); +} -#undef MEMUSER +static inline float ldfl(void *ptr) +{ + union { + float f; + uint32_t i; + } u; + u.i = ldl(ptr); + return u.f; +} + +static inline void stfl(void *ptr, float v) +{ + union { + float f; + uint32_t i; + } u; + u.f = v; + stl(ptr, u.i); +} +#endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target-i386/helper.c b/target-i386/helper.c index 075a99f25..43b8168a1 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -153,11 +153,11 @@ static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, if (index + (4 << shift) - 1 > env->tr.limit) raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); if (shift == 0) { - *esp_ptr = lduw(env->tr.base + index); - *ss_ptr = lduw(env->tr.base + index + 2); + *esp_ptr = lduw_kernel(env->tr.base + index); + *ss_ptr = lduw_kernel(env->tr.base + index + 2); } else { - *esp_ptr = ldl(env->tr.base + index); - *ss_ptr = lduw(env->tr.base + index + 4); + *esp_ptr = ldl_kernel(env->tr.base + index); + *ss_ptr = lduw_kernel(env->tr.base + index + 4); } } @@ -177,8 +177,8 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, if ((index + 7) > dt->limit) return -1; ptr = dt->base + index; - *e1_ptr = ldl(ptr); - *e2_ptr = ldl(ptr + 4); + *e1_ptr = ldl_kernel(ptr); + *e2_ptr = ldl_kernel(ptr + 4); return 0; } @@ -226,8 +226,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (intno * 8 + 7 > dt->limit) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ptr = dt->base + intno * 8; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); /* check gate type */ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; switch(type) { @@ -344,47 +344,47 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, int old_eflags; if (env->eflags & VM_MASK) { ssp -= 4; - stl(ssp, env->segs[R_GS].selector); + stl_kernel(ssp, env->segs[R_GS].selector); ssp -= 4; - stl(ssp, env->segs[R_FS].selector); + stl_kernel(ssp, env->segs[R_FS].selector); ssp -= 4; - stl(ssp, env->segs[R_DS].selector); + stl_kernel(ssp, env->segs[R_DS].selector); ssp -= 4; - stl(ssp, env->segs[R_ES].selector); + stl_kernel(ssp, env->segs[R_ES].selector); } if (new_stack) { ssp -= 4; - stl(ssp, old_ss); + stl_kernel(ssp, old_ss); ssp -= 4; - stl(ssp, old_esp); + stl_kernel(ssp, old_esp); } ssp -= 4; old_eflags = compute_eflags(); - stl(ssp, old_eflags); + stl_kernel(ssp, old_eflags); ssp -= 4; - stl(ssp, old_cs); + stl_kernel(ssp, old_cs); ssp -= 4; - stl(ssp, old_eip); + stl_kernel(ssp, old_eip); if (has_error_code) { ssp -= 4; - stl(ssp, error_code); + stl_kernel(ssp, error_code); } } else { if (new_stack) { ssp -= 2; - stw(ssp, old_ss); + stw_kernel(ssp, old_ss); ssp -= 2; - stw(ssp, old_esp); + stw_kernel(ssp, old_esp); } ssp -= 2; - stw(ssp, compute_eflags()); + stw_kernel(ssp, compute_eflags()); ssp -= 2; - stw(ssp, old_cs); + stw_kernel(ssp, old_cs); ssp -= 2; - stw(ssp, old_eip); + stw_kernel(ssp, old_eip); if (has_error_code) { ssp -= 2; - stw(ssp, error_code); + stw_kernel(ssp, error_code); } } @@ -410,8 +410,8 @@ static void do_interrupt_real(int intno, int is_int, int error_code, if (intno * 4 + 3 > dt->limit) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); ptr = dt->base + intno * 4; - offset = lduw(ptr); - selector = lduw(ptr + 2); + offset = lduw_kernel(ptr); + selector = lduw_kernel(ptr + 2); esp = ESP; ssp = env->segs[R_SS].base; if (is_int) @@ -420,11 +420,11 @@ static void do_interrupt_real(int intno, int is_int, int error_code, old_eip = env->eip; old_cs = env->segs[R_CS].selector; esp -= 2; - stw(ssp + (esp & 0xffff), compute_eflags()); + stw_kernel(ssp + (esp & 0xffff), compute_eflags()); esp -= 2; - stw(ssp + (esp & 0xffff), old_cs); + stw_kernel(ssp + (esp & 0xffff), old_cs); esp -= 2; - stw(ssp + (esp & 0xffff), old_eip); + stw_kernel(ssp + (esp & 0xffff), old_eip); /* update processor state */ ESP = (ESP & ~0xffff) | (esp & 0xffff); @@ -445,7 +445,7 @@ void do_interrupt_user(int intno, int is_int, int error_code, dt = &env->idt; ptr = dt->base + (intno * 8); - e2 = ldl(ptr + 4); + e2 = ldl_kernel(ptr + 4); dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; @@ -651,8 +651,8 @@ void helper_lldt_T0(void) if ((index + 7) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) @@ -684,8 +684,8 @@ void helper_ltr_T0(void) if ((index + 7) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ptr = dt->base + index; - e1 = ldl(ptr); - e2 = ldl(ptr + 4); + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); type = (e2 >> DESC_TYPE_SHIFT) & 0xf; if ((e2 & DESC_S_MASK) || (type != 2 && type != 9)) @@ -694,7 +694,7 @@ void helper_ltr_T0(void) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); load_seg_cache_raw_dt(&env->tr, e1, e2); e2 |= 0x00000200; /* set the busy bit */ - stl(ptr + 4, e2); + stl_kernel(ptr + 4, e2); } env->tr.selector = selector; } @@ -813,14 +813,14 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) ssp = env->segs[R_SS].base; if (shift) { esp -= 4; - stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); + stl_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector); esp -= 4; - stl(ssp + (esp & esp_mask), next_eip); + stl_kernel(ssp + (esp & esp_mask), next_eip); } else { esp -= 2; - stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); + stw_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector); esp -= 2; - stw(ssp + (esp & esp_mask), next_eip); + stw_kernel(ssp + (esp & esp_mask), next_eip); } if (!(env->segs[R_SS].flags & DESC_B_MASK)) @@ -873,14 +873,14 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) ssp = env->segs[R_SS].base + sp; if (shift) { ssp -= 4; - stl(ssp, env->segs[R_CS].selector); + stl_kernel(ssp, env->segs[R_CS].selector); ssp -= 4; - stl(ssp, next_eip); + stl_kernel(ssp, next_eip); } else { ssp -= 2; - stw(ssp, env->segs[R_CS].selector); + stw_kernel(ssp, env->segs[R_CS].selector); ssp -= 2; - stw(ssp, next_eip); + stw_kernel(ssp, next_eip); } sp -= (4 << shift); @@ -975,23 +975,23 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) ssp = env->segs[R_SS].base + sp; if (shift) { ssp -= 4; - stl(ssp, old_ss); + stl_kernel(ssp, old_ss); ssp -= 4; - stl(ssp, old_esp); + stl_kernel(ssp, old_esp); ssp -= 4 * param_count; for(i = 0; i < param_count; i++) { - val = ldl(old_ssp + i * 4); - stl(ssp + i * 4, val); + val = ldl_kernel(old_ssp + i * 4); + stl_kernel(ssp + i * 4, val); } } else { ssp -= 2; - stw(ssp, old_ss); + stw_kernel(ssp, old_ss); ssp -= 2; - stw(ssp, old_esp); + stw_kernel(ssp, old_esp); ssp -= 2 * param_count; for(i = 0; i < param_count; i++) { - val = lduw(old_ssp + i * 2); - stw(ssp + i * 2, val); + val = lduw_kernel(old_ssp + i * 2); + stw_kernel(ssp + i * 2, val); } } } else { @@ -1004,14 +1004,14 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (shift) { ssp -= 4; - stl(ssp, env->segs[R_CS].selector); + stl_kernel(ssp, env->segs[R_CS].selector); ssp -= 4; - stl(ssp, next_eip); + stl_kernel(ssp, next_eip); } else { ssp -= 2; - stw(ssp, env->segs[R_CS].selector); + stw_kernel(ssp, env->segs[R_CS].selector); ssp -= 2; - stw(ssp, next_eip); + stw_kernel(ssp, next_eip); } sp -= push_size; @@ -1042,14 +1042,14 @@ void helper_iret_real(int shift) ssp = env->segs[R_SS].base + sp; if (shift == 1) { /* 32 bits */ - new_eflags = ldl(ssp + 8); - new_cs = ldl(ssp + 4) & 0xffff; - new_eip = ldl(ssp) & 0xffff; + new_eflags = ldl_kernel(ssp + 8); + new_cs = ldl_kernel(ssp + 4) & 0xffff; + new_eip = ldl_kernel(ssp) & 0xffff; } else { /* 16 bits */ - new_eflags = lduw(ssp + 4); - new_cs = lduw(ssp + 2); - new_eip = lduw(ssp); + new_eflags = lduw_kernel(ssp + 4); + new_cs = lduw_kernel(ssp + 2); + new_eip = lduw_kernel(ssp); } new_esp = sp + (6 << shift); ESP = (ESP & 0xffff0000) | @@ -1078,17 +1078,17 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if (shift == 1) { /* 32 bits */ if (is_iret) - new_eflags = ldl(ssp + 8); - new_cs = ldl(ssp + 4) & 0xffff; - new_eip = ldl(ssp); + new_eflags = ldl_kernel(ssp + 8); + new_cs = ldl_kernel(ssp + 4) & 0xffff; + new_eip = ldl_kernel(ssp); if (is_iret && (new_eflags & VM_MASK)) goto return_to_vm86; } else { /* 16 bits */ if (is_iret) - new_eflags = lduw(ssp + 4); - new_cs = lduw(ssp + 2); - new_eip = lduw(ssp); + new_eflags = lduw_kernel(ssp + 4); + new_cs = lduw_kernel(ssp + 2); + new_eip = lduw_kernel(ssp); } if ((new_cs & 0xfffc) == 0) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -1124,12 +1124,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; if (shift == 1) { /* 32 bits */ - new_esp = ldl(ssp); - new_ss = ldl(ssp + 4) & 0xffff; + new_esp = ldl_kernel(ssp); + new_ss = ldl_kernel(ssp + 4) & 0xffff; } else { /* 16 bits */ - new_esp = lduw(ssp); - new_ss = lduw(ssp + 2); + new_esp = lduw_kernel(ssp); + new_ss = lduw_kernel(ssp + 2); } if ((new_ss & 3) != rpl) @@ -1175,12 +1175,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) return; return_to_vm86: - new_esp = ldl(ssp + 12); - new_ss = ldl(ssp + 16); - new_es = ldl(ssp + 20); - new_ds = ldl(ssp + 24); - new_fs = ldl(ssp + 28); - new_gs = ldl(ssp + 32); + new_esp = ldl_kernel(ssp + 12); + new_ss = ldl_kernel(ssp + 16); + new_es = ldl_kernel(ssp + 20); + new_ds = ldl_kernel(ssp + 24); + new_fs = ldl_kernel(ssp + 28); + new_gs = ldl_kernel(ssp + 32); /* modify processor state */ load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); @@ -1770,6 +1770,11 @@ void helper_frstor(uint8_t *ptr, int data32) } } +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + #define SHIFT 0 #include "softmmu_template.h" @@ -1782,22 +1787,41 @@ void helper_frstor(uint8_t *ptr, int data32) #define SHIFT 3 #include "softmmu_template.h" -/* try to fill the TLB and return an exception if error */ -void tlb_fill(unsigned long addr, int is_write, void *retaddr) +#endif + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; int ret; unsigned long pc; - ret = cpu_x86_handle_mmu_fault(env, addr, is_write); + CPUX86State *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + if (is_write && page_unprotect(addr)) { + /* nothing more to do: the page was write protected because + there was code in it. page_unprotect() flushed the code. */ + } + + ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1); if (ret) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - tb = tb_find_pc(pc); - if (tb) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, pc); + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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); + } } raise_exception_err(EXCP0E_PAGE, env->error_code); } + env = saved_env; } diff --git a/target-i386/helper2.c b/target-i386/helper2.c index bc0d426bc..1bec82081 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -210,7 +210,9 @@ void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) flags = page_get_flags(addr); if (flags & PAGE_VALID) { virt_addr = addr & ~0xfff; +#if !defined(CONFIG_SOFTMMU) munmap((void *)virt_addr, 4096); +#endif page_set_flags(virt_addr, virt_addr + 4096, 0); } } @@ -221,16 +223,14 @@ void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) 1 = generate PF fault 2 = soft MMU activation required for this block */ -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, + int is_write, int is_user, int is_softmmu) { uint8_t *pde_ptr, *pte_ptr; uint32_t pde, pte, virt_addr; - int cpl, error_code, is_dirty, is_user, prot, page_size, ret; + int error_code, is_dirty, prot, page_size, ret; unsigned long pd; - cpl = env->hflags & HF_CPL_MASK; - is_user = (cpl == 3); - #ifdef DEBUG_MMU printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", addr, is_write, is_user, env->eip); @@ -252,7 +252,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) /* page directory entry */ pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); - pde = ldl(pde_ptr); + pde = ldl_raw(pde_ptr); if (!(pde & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; @@ -274,7 +274,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) pde |= PG_ACCESSED_MASK; if (is_dirty) pde |= PG_DIRTY_MASK; - stl(pde_ptr, pde); + stl_raw(pde_ptr, pde); } pte = pde & ~0x003ff000; /* align to 4MB */ @@ -283,12 +283,12 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) } else { if (!(pde & PG_ACCESSED_MASK)) { pde |= PG_ACCESSED_MASK; - stl(pde_ptr, pde); + stl_raw(pde_ptr, pde); } /* page directory entry */ pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); - pte = ldl(pte_ptr); + pte = ldl_raw(pte_ptr); if (!(pte & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; @@ -308,7 +308,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) pte |= PG_ACCESSED_MASK; if (is_dirty) pte |= PG_DIRTY_MASK; - stl(pte_ptr, pte); + stl_raw(pte_ptr, pte); } page_size = 4096; virt_addr = addr & ~0xfff; @@ -325,7 +325,10 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) } do_mapping: - if (env->hflags & HF_SOFTMMU_MASK) { +#if !defined(CONFIG_SOFTMMU) + if (is_softmmu) +#endif + { unsigned long paddr, vaddr, address, addend, page_offset; int index; @@ -352,32 +355,39 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) env->tlb_write[is_user][index].address = address; env->tlb_write[is_user][index].addend = addend; } + page_set_flags(vaddr, vaddr + TARGET_PAGE_SIZE, + PAGE_VALID | PAGE_EXEC | prot); + ret = 0; } - ret = 0; - /* XXX: incorrect for 4MB pages */ - pd = physpage_find(pte & ~0xfff); - if ((pd & 0xfff) != 0) { - /* IO access: no mapping is done as it will be handled by the - soft MMU */ - if (!(env->hflags & HF_SOFTMMU_MASK)) - ret = 2; - } else { - void *map_addr; - map_addr = mmap((void *)virt_addr, page_size, prot, - MAP_SHARED | MAP_FIXED, phys_ram_fd, pd); - if (map_addr == MAP_FAILED) { - fprintf(stderr, - "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", - pte & ~0xfff, virt_addr); - exit(1); - } +#if !defined(CONFIG_SOFTMMU) + else { + ret = 0; + /* XXX: incorrect for 4MB pages */ + pd = physpage_find(pte & ~0xfff); + if ((pd & 0xfff) != 0) { + /* IO access: no mapping is done as it will be handled by the + soft MMU */ + if (!(env->hflags & HF_SOFTMMU_MASK)) + ret = 2; + } else { + void *map_addr; + map_addr = mmap((void *)virt_addr, page_size, prot, + MAP_SHARED | MAP_FIXED, phys_ram_fd, pd); + if (map_addr == MAP_FAILED) { + fprintf(stderr, + "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", + pte & ~0xfff, virt_addr); + exit(1); + } #ifdef DEBUG_MMU - printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", - pte & ~0xfff, virt_addr, (page_size != 4096)); + printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", + pte & ~0xfff, virt_addr, (page_size != 4096)); #endif - page_set_flags(virt_addr, virt_addr + page_size, - PAGE_VALID | PAGE_EXEC | prot); + page_set_flags(virt_addr, virt_addr + page_size, + PAGE_VALID | PAGE_EXEC | prot); + } } +#endif return ret; do_fault_protect: error_code = PG_ERROR_P_MASK; diff --git a/target-i386/op.c b/target-i386/op.c index 68191f9bc..0f4dbd18e 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -376,14 +376,16 @@ void OPPROTO op_andl_A0_ffff(void) /* memory access */ -#define MEMSUFFIX +#define MEMSUFFIX _raw #include "ops_mem.h" +#if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user #include "ops_mem.h" #define MEMSUFFIX _kernel #include "ops_mem.h" +#endif /* used for bit operations */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 43d3bbcbb..a64c58c8d 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -570,10 +570,10 @@ static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { }; static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = { - gen_op_ldsb_T0_A0, - gen_op_ldsw_T0_A0, + gen_op_ldsb_raw_T0_A0, + gen_op_ldsw_raw_T0_A0, NULL, - +#ifndef CONFIG_USER_ONLY gen_op_ldsb_kernel_T0_A0, gen_op_ldsw_kernel_T0_A0, NULL, @@ -581,13 +581,15 @@ static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = { gen_op_ldsb_user_T0_A0, gen_op_ldsw_user_T0_A0, NULL, +#endif }; static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = { - gen_op_ldub_T0_A0, - gen_op_lduw_T0_A0, + gen_op_ldub_raw_T0_A0, + gen_op_lduw_raw_T0_A0, NULL, +#ifndef CONFIG_USER_ONLY gen_op_ldub_kernel_T0_A0, gen_op_lduw_kernel_T0_A0, NULL, @@ -595,14 +597,16 @@ static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = { gen_op_ldub_user_T0_A0, gen_op_lduw_user_T0_A0, NULL, +#endif }; /* sign does not matter, except for lidt/lgdt call (TODO: fix it) */ static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = { - gen_op_ldub_T0_A0, - gen_op_lduw_T0_A0, - gen_op_ldl_T0_A0, + gen_op_ldub_raw_T0_A0, + gen_op_lduw_raw_T0_A0, + gen_op_ldl_raw_T0_A0, +#ifndef CONFIG_USER_ONLY gen_op_ldub_kernel_T0_A0, gen_op_lduw_kernel_T0_A0, gen_op_ldl_kernel_T0_A0, @@ -610,13 +614,15 @@ static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = { gen_op_ldub_user_T0_A0, gen_op_lduw_user_T0_A0, gen_op_ldl_user_T0_A0, +#endif }; static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = { - gen_op_ldub_T1_A0, - gen_op_lduw_T1_A0, - gen_op_ldl_T1_A0, + gen_op_ldub_raw_T1_A0, + gen_op_lduw_raw_T1_A0, + gen_op_ldl_raw_T1_A0, +#ifndef CONFIG_USER_ONLY gen_op_ldub_kernel_T1_A0, gen_op_lduw_kernel_T1_A0, gen_op_ldl_kernel_T1_A0, @@ -624,13 +630,15 @@ static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = { gen_op_ldub_user_T1_A0, gen_op_lduw_user_T1_A0, gen_op_ldl_user_T1_A0, +#endif }; static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { - gen_op_stb_T0_A0, - gen_op_stw_T0_A0, - gen_op_stl_T0_A0, + gen_op_stb_raw_T0_A0, + gen_op_stw_raw_T0_A0, + gen_op_stl_raw_T0_A0, +#ifndef CONFIG_USER_ONLY gen_op_stb_kernel_T0_A0, gen_op_stw_kernel_T0_A0, gen_op_stl_kernel_T0_A0, @@ -638,6 +646,7 @@ static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { gen_op_stb_user_T0_A0, gen_op_stw_user_T0_A0, gen_op_stl_user_T0_A0, +#endif }; static inline void gen_string_movl_A0_ESI(DisasContext *s) @@ -1176,7 +1185,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ if (base == 4) { havesib = 1; - code = ldub(s->pc++); + code = ldub_code(s->pc++); scale = (code >> 6) & 3; index = (code >> 3) & 7; base = code & 7; @@ -1186,18 +1195,18 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ case 0: if (base == 5) { base = -1; - disp = ldl(s->pc); + disp = ldl_code(s->pc); s->pc += 4; } else { disp = 0; } break; case 1: - disp = (int8_t)ldub(s->pc++); + disp = (int8_t)ldub_code(s->pc++); break; default: case 2: - disp = ldl(s->pc); + disp = ldl_code(s->pc); s->pc += 4; break; } @@ -1229,7 +1238,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ switch (mod) { case 0: if (rm == 6) { - disp = lduw(s->pc); + disp = lduw_code(s->pc); s->pc += 2; gen_op_movl_A0_im(disp); rm = 0; /* avoid SS override */ @@ -1239,11 +1248,11 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ } break; case 1: - disp = (int8_t)ldub(s->pc++); + disp = (int8_t)ldub_code(s->pc++); break; default: case 2: - disp = lduw(s->pc); + disp = lduw_code(s->pc); s->pc += 2; break; } @@ -1337,16 +1346,16 @@ static inline uint32_t insn_get(DisasContext *s, int ot) switch(ot) { case OT_BYTE: - ret = ldub(s->pc); + ret = ldub_code(s->pc); s->pc++; break; case OT_WORD: - ret = lduw(s->pc); + ret = lduw_code(s->pc); s->pc += 2; break; default: case OT_LONG: - ret = ldl(s->pc); + ret = ldl_code(s->pc); s->pc += 4; break; } @@ -1756,7 +1765,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) dflag = s->code32; s->override = -1; next_byte: - b = ldub(s->pc); + b = ldub_code(s->pc); s->pc++; /* check prefixes */ switch (b) { @@ -1814,7 +1823,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x0f: /**************************/ /* extended op code */ - b = ldub(s->pc++) | 0x100; + b = ldub_code(s->pc++) | 0x100; goto reswitch; /**************************/ @@ -1839,7 +1848,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) switch(f) { case 0: /* OP Ev, Gv */ - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7); mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -1861,7 +1870,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op(s, op, ot, opreg); break; case 1: /* OP Gv, Ev */ - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; reg = ((modrm >> 3) & 7); rm = modrm & 7; @@ -1895,7 +1904,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; op = (modrm >> 3) & 7; @@ -1939,7 +1948,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; op = (modrm >> 3) & 7; @@ -2045,7 +2054,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; op = (modrm >> 3) & 7; @@ -2085,10 +2094,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_push_T0(s); gen_eob(s); break; - case 3: /*< lcall Ev */ + case 3: /* lcall Ev */ gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); - gen_op_ld_T0_A0[OT_WORD + s->mem_index](); + gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); do_lcall: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) @@ -2109,7 +2118,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 5: /* ljmp Ev */ gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); - gen_op_lduw_T0_A0(); + gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); do_ljmp: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) @@ -2138,7 +2147,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; reg = (modrm >> 3) & 7; @@ -2179,7 +2188,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x69: /* imul Gv, Ev, I */ case 0x6b: ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) + OR_EAX; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); if (b == 0x69) { @@ -2206,7 +2215,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; if (mod == 3) { @@ -2233,7 +2242,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; gen_op_mov_TN_reg[ot][1][reg](); @@ -2250,7 +2259,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) s->cc_op = CC_OP_SUBB + ot; break; case 0x1c7: /* cmpxchg8b */ - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; @@ -2291,7 +2300,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x8f: /* pop Ev */ ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); gen_pop_T0(s); s->popl_esp_hack = 2 << dflag; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); @@ -2301,9 +2310,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0xc8: /* enter */ { int level; - val = lduw(s->pc); + val = lduw_code(s->pc); s->pc += 2; - level = ldub(s->pc++); + level = ldub_code(s->pc++); gen_enter(s, val, level); } break; @@ -2369,7 +2378,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; /* generate a generic store */ @@ -2381,7 +2390,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if (mod != 3) gen_lea_modrm(s, modrm, ®_addr, &offset_addr); @@ -2398,14 +2407,14 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_reg_T0[ot][reg](); break; case 0x8e: /* mov seg, Gv */ - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; if (reg >= 6 || reg == R_CS) goto illegal_op; @@ -2422,7 +2431,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0x8c: /* mov Gv, seg */ - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; if (reg >= 6) @@ -2444,7 +2453,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) d_ot = dflag + OT_WORD; /* ot is the size of source */ ot = (b & 1) + OT_BYTE; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) + OR_EAX; mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -2481,7 +2490,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x8d: /* lea */ ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; /* we must ensure that no segment is added */ s->override = -1; @@ -2574,7 +2583,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; if (mod == 3) { @@ -2613,7 +2622,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) op = R_GS; do_lxx: ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; if (mod == 3) @@ -2622,7 +2631,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ - gen_op_lduw_T0_A0(); + gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); gen_movl_seg_T0(s, op, pc_start - s->cs_base); /* then put the data */ gen_op_mov_reg_T1[ot][reg](); @@ -2645,7 +2654,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; op = (modrm >> 3) & 7; @@ -2662,7 +2671,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_shift(s, op, ot, opreg, OR_ECX); } else { if (shift == 2) { - shift = ldub(s->pc++); + shift = ldub_code(s->pc++); } gen_shifti(s, op, ot, opreg, shift); } @@ -2696,7 +2705,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) shift = 0; do_shiftd: ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; reg = (modrm >> 3) & 7; @@ -2710,7 +2719,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_TN_reg[ot][1][reg](); if (shift) { - val = ldub(s->pc++); + val = ldub_code(s->pc++); val &= 0x1f; if (val) { if (mod == 3) @@ -2739,7 +2748,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* floats */ case 0xd8 ... 0xdf: - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; op = ((b & 7) << 3) | ((modrm >> 3) & 7); @@ -3256,7 +3265,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - val = ldub(s->pc++); + val = ldub_code(s->pc++); gen_op_movl_T0_im(val); gen_op_in[ot](); gen_op_mov_reg_T1[ot][R_EAX](); @@ -3271,7 +3280,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - val = ldub(s->pc++); + val = ldub_code(s->pc++); gen_op_movl_T0_im(val); gen_op_mov_TN_reg[ot][1][R_EAX](); gen_op_out[ot](); @@ -3309,7 +3318,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* control */ case 0xc2: /* ret im */ - val = ldsw(s->pc); + val = ldsw_code(s->pc); s->pc += 2; gen_pop_T0(s); gen_stack_update(s, val + (2 << s->dflag)); @@ -3327,7 +3336,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_eob(s); break; case 0xca: /* lret im */ - val = ldsw(s->pc); + val = ldsw_code(s->pc); s->pc += 2; do_lret: if (s->pe && !s->vm86) { @@ -3443,13 +3452,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x190 ... 0x19f: /* setcc Gv */ - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); gen_setcc(s, b); gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); break; case 0x140 ... 0x14f: /* cmov Gv, Ev */ ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; gen_setcc(s, b); @@ -3542,7 +3551,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /* bit operations */ case 0x1ba: /* bt/bts/btr/btc Gv, im */ ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); op = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -3553,7 +3562,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_TN_reg[ot][0][rm](); } /* load shift */ - val = ldub(s->pc++); + val = ldub_code(s->pc++); gen_op_movl_T1_im(val); if (op < 4) goto illegal_op; @@ -3581,7 +3590,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) op = 3; do_btx: ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -3610,7 +3619,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x1bc: /* bsf */ case 0x1bd: /* bsr */ ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_bsx_T0_cc[ot - OT_WORD][b & 1](); @@ -3646,12 +3655,12 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) s->cc_op = CC_OP_EFLAGS; break; case 0xd4: /* aam */ - val = ldub(s->pc++); + val = ldub_code(s->pc++); gen_op_aam(val); s->cc_op = CC_OP_LOGICB; break; case 0xd5: /* aad */ - val = ldub(s->pc++); + val = ldub_code(s->pc++); gen_op_aad(val); s->cc_op = CC_OP_LOGICB; break; @@ -3665,7 +3674,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); break; case 0xcd: /* int N */ - val = ldub(s->pc++); + val = ldub_code(s->pc++); /* XXX: add error code for vm86 GPF */ if (!s->vm86) gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); @@ -3718,7 +3727,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x62: /* bound */ ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; if (mod == 3) @@ -3785,7 +3794,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0x100: - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; switch(op) { @@ -3828,7 +3837,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0x101: - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; switch(op) { @@ -3904,7 +3913,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (!s->pe || s->vm86) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_TN_reg[ot][1][reg](); @@ -3918,7 +3927,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_reg_T1[ot][reg](); break; case 0x118: - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; switch(op) { @@ -3940,7 +3949,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); if ((modrm & 0xc0) != 0xc0) goto illegal_op; rm = modrm & 7; @@ -3970,7 +3979,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - modrm = ldub(s->pc++); + modrm = ldub_code(s->pc++); if ((modrm & 0xc0) != 0xc0) goto illegal_op; rm = modrm & 7; -- cgit v1.2.3 From 6e59c1db892ce768178e705a5b68ab349eb5282f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:24:54 +0000 Subject: full soft mmu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@411 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/exec-all.h b/exec-all.h index 070a162f3..9994acb7a 100644 --- a/exec-all.h +++ b/exec-all.h @@ -79,6 +79,7 @@ void cpu_exec_init(void); int page_unprotect(unsigned long address); void page_unmap(void); void tlb_flush_page(CPUState *env, uint32_t addr); +void tlb_flush_page_write(CPUState *env, uint32_t addr); void tlb_flush(CPUState *env); #define CODE_GEN_MAX_SIZE 65536 @@ -415,3 +416,27 @@ static inline int spin_trylock(spinlock_t *lock) extern spinlock_t tb_lock; + +#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY) + +void tlb_fill(unsigned long addr, int is_write, int is_user, + void *retaddr); + +#define ACCESS_TYPE 3 +#define MEMSUFFIX _code +#define env cpu_single_env + +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#undef ACCESS_TYPE +#undef MEMSUFFIX +#undef env + +#endif -- cgit v1.2.3 From 0db634747efe579cc2ac44b05b01f33bcfaeb1df Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 21:37:46 +0000 Subject: qemu with softmmu is now the default executable git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@412 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++-- vl.c | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Makefile.target b/Makefile.target index cfb3cd88f..95ea88640 100644 --- a/Makefile.target +++ b/Makefile.target @@ -12,9 +12,9 @@ DYNGEN=../dyngen QEMU_USER=qemu-$(TARGET_ARCH) # system emulator name ifdef CONFIG_SOFTMMU -QEMU_SYSTEM=qemu-softmmu -else QEMU_SYSTEM=qemu +else +QEMU_SYSTEM=qemu-fast endif ifdef CONFIG_USER_ONLY diff --git a/vl.c b/vl.c index 1286fac0b..19343cf6c 100644 --- a/vl.c +++ b/vl.c @@ -3446,7 +3446,7 @@ int main_loop(void *opaque) void help(void) { printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: qemu [options] [disk_image]\n" + "usage: %s [options] [disk_image]\n" "\n" "'disk_image' is a raw hard image image for IDE hard disk 0\n" "\n" @@ -3472,8 +3472,20 @@ void help(void) "-L path set the directory for the BIOS and VGA BIOS\n" "\n" "During emulation, use C-a h to get terminal commands:\n", - DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT); +#ifdef CONFIG_SOFTMMU + "qemu", +#else + "qemu-fast", +#endif + DEFAULT_NETWORK_SCRIPT, + DEFAULT_GDBSTUB_PORT); term_print_help(); +#ifndef CONFIG_SOFTMMU + printf("\n" + "NOTE: this version of QEMU is faster but it needs slightly patched OSes to\n" + "work. Please use the 'qemu' executable to have a more accurate (but slower)\n" + "PC emulation.\n"); +#endif exit(1); } -- cgit v1.2.3 From dd6ee15c37c9cbb387db17f26f4daaf4798556fd Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 23:36:59 +0000 Subject: fixed idt/gdt relocation bug - added support for Redhat kernels git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@413 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 19343cf6c..944e759a0 100644 --- a/vl.c +++ b/vl.c @@ -3737,10 +3737,13 @@ int main(int argc, char **argv) params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */ + /* for newer kernels (2.6.0) CS/DS are at different addresses */ + params->gdt_table[12] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ + params->gdt_table[13] = 0x00cf92000000ffffLL; /* KERNEL_DS */ - env->idt.base = (void *)params->idt_table; + env->idt.base = (void *)((uint8_t *)params->idt_table - phys_ram_base); env->idt.limit = sizeof(params->idt_table) - 1; - env->gdt.base = (void *)params->gdt_table; + env->gdt.base = (void *)((uint8_t *)params->gdt_table - phys_ram_base); env->gdt.limit = sizeof(params->gdt_table) - 1; cpu_x86_load_seg_cache(env, R_CS, KERNEL_CS, NULL, 0xffffffff, 0x00cf9a00); -- cgit v1.2.3 From 78d6da976c1d81e9274435d214d03d4e13aad5a3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 23:55:20 +0000 Subject: license git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@414 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 3c0a76bef..09c662633 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1,3 +1,22 @@ +/* + * x86 CPU test + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #define _GNU_SOURCE #include #include -- cgit v1.2.3 From 9d16dd550ee51431d83e9fbfbc0adc022219b4c1 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 23:56:59 +0000 Subject: make cpu test static git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@415 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index f4e1b22f4..6daaaa2bb 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -4,11 +4,12 @@ CFLAGS=-Wall -O2 -g LDFLAGS= ifeq ($(ARCH),i386) -TESTS=testclone testsig testthread sha1-i386 test-i386 runcom +TESTS=linux-test testthread sha1-i386 test-i386 runcom endif -TESTS+=sha1 test_path +TESTS+=sha1# test_path +#TESTS+=test_path -QEMU=../i386/qemu +QEMU=../i386/qemu-i386 all: $(TESTS) @@ -16,12 +17,6 @@ hello-i386: hello-i386.c $(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< strip $@ -testclone: testclone.c - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< - -testsig: testsig.c - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< - testthread: testthread.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lpthread @@ -32,7 +27,7 @@ test_path: test_path.c # i386 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \ + $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c \ test-i386-code16.S test-i386-vm86.S -lm ifeq ($(ARCH),i386) @@ -44,6 +39,10 @@ endif $(QEMU) test-i386 > test-i386.out @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi +# generic Linux and CPU test +linux-test: linux-test.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lm + # speed test sha1-i386: sha1.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -- cgit v1.2.3 From baf8ebf01a70782d222f0eaf29591dc60723f73c Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 23:57:40 +0000 Subject: fixed virtual memory access git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@416 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disas.c b/disas.c index 0c8cc2a8f..d5aa7f371 100644 --- a/disas.c +++ b/disas.c @@ -42,7 +42,7 @@ target_read_memory (memaddr, myaddr, length, info) { int i; for(i = 0; i < length; i++) { - myaddr[i] = ldub_code((void *)((long)memaddr)); + myaddr[i] = ldub_code((void *)((long)memaddr + i)); } return 0; } -- cgit v1.2.3 From 285dc330bd28aa0e097106875bb184e2707bbed5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 27 Oct 2003 23:58:04 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@417 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 5 +- README | 26 ++----- README.distrib | 4 +- TODO | 9 ++- VERSION | 2 +- qemu-doc.texi | 60 ++++++++--------- tests/linux-test.c | 5 +- tests/testclone.c | 62 ----------------- tests/testsig.c | 194 ----------------------------------------------------- 9 files changed, 47 insertions(+), 320 deletions(-) delete mode 100644 tests/testclone.c delete mode 100644 tests/testsig.c diff --git a/Changelog b/Changelog index 8468853b9..6a0c711cf 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -version 0.4.4: +version 0.5.0: - full hardware level VGA emulation - graphical display with SDL @@ -16,8 +16,9 @@ version 0.4.4: - preliminary SPARC target support (Thomas M. Ogrisegg) - tun-fd option (Rusty Russell) - automatic IDE geometry detection - - renamed 'vl' to qemu and user qemu to qemu-{cpu}. + - renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}. - added man page + - added full soft mmy mode to launch unpatched OSes. version 0.4.3: diff --git a/README b/README index c7038c21a..030306717 100644 --- a/README +++ b/README @@ -6,35 +6,17 @@ INSTALLATION Type - ./configure --interp-prefix=/usr/local/qemu-i386 + ./configure make -to build qemu and libqemu.a. +to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various +supported target CPUs). Type make install -to install QEMU in /usr/local/bin - -* On x86 you should be able to launch any program by using the -libraries installed on your PC. For example: - - ./qemu -L / /bin/ls - -* On non x86 CPUs, you need first to download at least an x86 glibc -(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that -LD_LIBRARY_PATH is not set: - - unset LD_LIBRARY_PATH - -Then you can launch the precompiled 'ls' x86 executable: - - ./qemu /usr/local/qemu-i386/bin/ls-i386 - -You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is -automatically launched by the Linux kernel when you try to launch x86 -executables. +to install QEMU in /usr/local Tested tool versions -------------------- diff --git a/README.distrib b/README.distrib index 35dff250b..a1598a299 100644 --- a/README.distrib +++ b/README.distrib @@ -6,11 +6,11 @@ x86 binary distribution: * wine-20020411 tarball - ./configure --prefix=/usr/local/qemu-i386/wine + ./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 /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache + qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache diff --git a/TODO b/TODO index 56229dfd7..fece491bc 100644 --- a/TODO +++ b/TODO @@ -1,17 +1,20 @@ +- tests for each target CPU +- ppc qemu test - optimize FPU operations (evaluate x87 stack pointer statically) and fix cr0.TS emulation +- fix some 16 bit sp push/pop overflow +- sysenter/sysexit emulation +- finish segment ops (call far, ret far, load_seg suppressed) - fix CCOP optimisation - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). - cpu loop optimisation (optimise ret case as the cpu state does not change) - fix arm fpu rounding (at least for float->integer conversions) -- add IPC syscalls lower priority: -------------- -- sysenter/sysexit emulation +- add IPC syscalls - SMP support -- finish segment ops (call far, ret far, load_seg suppressed) - use -msoft-float on ARM - use kernel traps for unaligned accesses on ARM ? - handle rare page fault cases (in particular if page fault in heplers or diff --git a/VERSION b/VERSION index b300caa32..79a2734bb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.4 \ No newline at end of file +0.5.0 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index 0ff1454c1..8bb883afb 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -72,7 +72,7 @@ QEMU user mode emulation features: QEMU full system emulation features: @itemize -@item Using mmap() system calls to simulate the MMU +@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU. @end itemize @section x86 emulation @@ -110,14 +110,7 @@ memory access. 10 byte @code{long double}s of x86 for floating point emulation to get maximum performances. -@item Full system emulation only works if no data are mapped above the virtual address -0xc0000000 (yet). - -@item Some priviledged instructions or behaviors are missing. Only the ones -needed for proper Linux kernel operation are emulated. - -@item No memory separation between the kernel and the user processes is done. -It will be implemented very soon. +@item Some priviledged instructions or behaviors are missing, especially for segment protection testing (yet). @end itemize @@ -177,9 +170,9 @@ unset LD_LIBRARY_PATH Then you can launch the precompiled @file{ls} x86 executable: @example -qemu-i386 /usr/local/qemu-i386/bin/ls-i386 +qemu-i386 tests/i386/ls @end example -You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that +You can look at @file{qemu-binfmt-conf.sh} so that QEMU is automatically launched by the Linux kernel when you try to launch x86 executables. It requires the @code{binfmt_misc} module in the Linux kernel. @@ -258,16 +251,15 @@ available: @enumerate @item -@code{qemu} uses the host Memory Management Unit (MMU) to simulate +@code{qemu-fast} uses the host Memory Management Unit (MMU) to simulate the x86 MMU. It is @emph{fast} but has limitations because the whole 4 GB address space cannot be used and some memory mapped peripherials cannot be emulated accurately yet. Therefore, a specific Linux kernel must be used (@xref{linux_compile}). @item -@code{qemu-softmmu} uses a software MMU. It is about @emph{two times -slower} but gives a more accurate emulation. (XXX: Linux cannot be ran -unpatched yet). +@code{qemu} uses a software MMU. It is about @emph{two times +slower} but gives a more accurate emulation. @end enumerate @@ -296,10 +288,10 @@ CMOS memory @section Quick Start -Download the linux image (@file{linux.img}) and type: +Download and uncompress the linux image (@file{linux.img}) and type: @example -qemu-softmmu linux.img +qemu linux.img @end example Linux should boot and give you a prompt. @@ -627,8 +619,10 @@ the real one. To know it, use the @code{ls -ls} command. @node linux_compile @section Linux Kernel Compilation -You should be able to use any kernel with QEMU provided you make the -following changes (only 2.4.x and 2.5.x were tested): +You can use any linux kernel with QEMU. However, if you want to use +@code{qemu-fast} to get maximum performances, you should make the +following changes to the Linux kernel (only 2.4.x and 2.5.x were +tested): @enumerate @item @@ -723,8 +717,6 @@ Then you can use gdb normally. For example, type 'c' to launch the kernel: (gdb) c @end example -WARNING: breakpoints and single stepping are not yet supported. - Here are some useful tips in order to use gdb on system code: @enumerate @@ -1019,16 +1011,6 @@ The new Plex86 project. In the directory @file{tests/}, various interesting testing programs are available. There are used for regression testing. -@section @file{hello-i386} - -Very simple statically linked x86 program, just to test QEMU during a -port to a new host CPU. - -@section @file{hello-arm} - -Very simple statically linked ARM program, just to test QEMU during a -port to a new host CPU. - @section @file{test-i386} This program executes most of the 16 bit and 32 bit x86 instructions and @@ -1044,6 +1026,22 @@ The Linux system call @code{vm86()} is used to test vm86 emulation. Various exceptions are raised to test most of the x86 user space exception reporting. +@section @file{linux-test} + +This program tests various Linux system calls. It is used to verify +that the system call parameters are correctly converted between target +and host CPUs. + +@section @file{hello-i386} + +Very simple statically linked x86 program, just to test QEMU during a +port to a new host CPU. + +@section @file{hello-arm} + +Very simple statically linked ARM program, just to test QEMU during a +port to a new host CPU. + @section @file{sha1} It is a simple benchmark. Care must be taken to interpret the results diff --git a/tests/linux-test.c b/tests/linux-test.c index 3ced0dd69..14cbe1385 100644 --- a/tests/linux-test.c +++ b/tests/linux-test.c @@ -71,7 +71,7 @@ int __chk_error(const char *filename, int line, int ret) #define FILE_BUF_SIZE 300 -void file_test(void) +void test_file(void) { int fd, i, len, ret; uint8_t buf[FILE_BUF_SIZE]; @@ -499,7 +499,7 @@ void test_signal(void) int main(int argc, char **argv) { - file_test(); + test_file(); test_fork(); test_time(); test_socket(); @@ -507,4 +507,3 @@ int main(int argc, char **argv) test_signal(); return 0; } - diff --git a/tests/testclone.c b/tests/testclone.c deleted file mode 100644 index 531bd5c61..000000000 --- a/tests/testclone.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int thread1_func(void *arg) -{ - int i; - char buf[512]; - - for(i=0;i<10;i++) { - snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg); - write(1, buf, strlen(buf)); - usleep(100 * 1000); - } - return 0; -} - -int thread2_func(void *arg) -{ - int i; - char buf[512]; - for(i=0;i<20;i++) { - snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg); - write(1, buf, strlen(buf)); - usleep(120 * 1000); - } - return 0; -} - -#define STACK_SIZE 16384 - -void test_clone(void) -{ - uint8_t *stack1, *stack2; - int pid1, pid2, status1, status2; - - stack1 = malloc(STACK_SIZE); - pid1 = clone(thread1_func, stack1 + STACK_SIZE, - CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"); - - stack2 = malloc(STACK_SIZE); - pid2 = clone(thread2_func, stack2 + STACK_SIZE, - CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"); - - while (waitpid(pid1, &status1, 0) != pid1); - while (waitpid(pid2, &status2, 0) != pid2); - printf("status1=0x%x\n", status1); - printf("status2=0x%x\n", status2); - printf("End of clone test.\n"); -} - -int main(int argc, char **argv) -{ - test_clone(); - return 0; -} diff --git a/tests/testsig.c b/tests/testsig.c deleted file mode 100644 index 2eb2bfc4a..000000000 --- a/tests/testsig.c +++ /dev/null @@ -1,194 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -jmp_buf jmp_env; - -void alarm_handler(int sig) -{ - printf("alarm signal=%d\n", sig); - alarm(1); -} - -#ifndef REG_EAX -#define REG_EAX EAX -#define REG_EBX EBX -#define REG_ECX ECX -#define REG_EDX EDX -#define REG_ESI ESI -#define REG_EDI EDI -#define REG_EBP EBP -#define REG_ESP ESP -#define REG_EIP EIP -#define REG_EFL EFL -#define REG_TRAPNO TRAPNO -#define REG_ERR ERR -#endif - -void dump_regs(struct ucontext *uc) -{ - printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EFL=%08x EIP=%08x trapno=%02x err=%08x\n", - uc->uc_mcontext.gregs[REG_EAX], - uc->uc_mcontext.gregs[REG_EBX], - uc->uc_mcontext.gregs[REG_ECX], - uc->uc_mcontext.gregs[REG_EDX], - uc->uc_mcontext.gregs[REG_ESI], - uc->uc_mcontext.gregs[REG_EDI], - uc->uc_mcontext.gregs[REG_EBP], - uc->uc_mcontext.gregs[REG_ESP], - uc->uc_mcontext.gregs[REG_EFL], - uc->uc_mcontext.gregs[REG_EIP], - uc->uc_mcontext.gregs[REG_TRAPNO], - uc->uc_mcontext.gregs[REG_ERR]); -} - -void sig_handler(int sig, siginfo_t *info, void *puc) -{ - struct ucontext *uc = puc; - - printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n", - strsignal(info->si_signo), - info->si_signo, info->si_errno, info->si_code, - (unsigned long)info->si_addr); - dump_regs(uc); - longjmp(jmp_env, 1); -} - -int v1; -int tab[2]; - -int main(int argc, char **argv) -{ - struct sigaction act; - volatile int val; - - act.sa_sigaction = sig_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - sigaction(SIGFPE, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGTRAP, &act, NULL); - - /* test division by zero reporting */ - if (setjmp(jmp_env) == 0) { - /* now divide by zero */ - v1 = 0; - v1 = 2 / v1; - } - - /* test illegal instruction reporting */ - if (setjmp(jmp_env) == 0) { - /* now execute an invalid instruction */ - asm volatile("ud2"); - } - - /* test SEGV reporting */ - if (setjmp(jmp_env) == 0) { - /* now store in an invalid address */ - *(char *)0x1234 = 1; - } - - /* test SEGV reporting */ - if (setjmp(jmp_env) == 0) { - /* read from an invalid address */ - v1 = *(char *)0x1234; - } - - printf("segment GPF exception:\n"); - if (setjmp(jmp_env) == 0) { - /* load an invalid segment */ - asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0)); - } - - printf("INT exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("int $0xfd"); - } - - printf("INT3 exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("int3"); - } - - printf("CLI exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("cli"); - } - - printf("STI exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("cli"); - } - - printf("INTO exception:\n"); - if (setjmp(jmp_env) == 0) { - /* overflow exception */ - asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff)); - } - - printf("BOUND exception:\n"); - if (setjmp(jmp_env) == 0) { - /* bound exception */ - tab[0] = 1; - tab[1] = 10; - asm volatile ("bound %0, %1" : : "r" (11), "m" (tab)); - } - - printf("OUTB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0)); - } - - printf("INB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321)); - } - - printf("REP OUTSB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1)); - } - - printf("REP INSB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1)); - } - - printf("HLT exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("hlt"); - } - - printf("single step exception:\n"); - val = 0; - if (setjmp(jmp_env) == 0) { - asm volatile ("pushf\n" - "orl $0x00100, (%%esp)\n" - "popf\n" - "movl $0xabcd, %0\n" : "=m" (val) : : "cc", "memory"); - } - printf("val=0x%x\n", val); - -#if 1 - { - int i; - act.sa_handler = alarm_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - sigaction(SIGALRM, &act, NULL); - alarm(1); - for(i = 0;i < 2; i++) { - sleep(1); - } - } -#endif - return 0; -} -- cgit v1.2.3 From 9f05cc34df6ea0cdd9183e8405792aa09ddac7d3 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 00:09:28 +0000 Subject: fixed big endian ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@418 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index c91813fba..c7491a00c 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -212,8 +212,8 @@ static inline int ldl_raw(void *ptr) static inline uint64_t ldq_raw(void *ptr) { uint32_t a,b; - a = ldl (ptr); - b = ldl (ptr+4); + a = ldl_raw(ptr); + b = ldl_raw(ptr+4); return (((uint64_t)a<<32)|b); } @@ -235,8 +235,8 @@ static inline void stl_raw(void *ptr, int v) static inline void stq_raw(void *ptr, uint64_t v) { - stl (ptr, v); - stl (ptr+4, v >> 32); + stl_raw(ptr, v); + stl_raw(ptr+4, v >> 32); } #else -- cgit v1.2.3 From 03d5f74aeec3c282f06ff0151596df25ab88659a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 00:09:43 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@419 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- tests/sha1.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 tests/sha1.c diff --git a/tests/Makefile b/tests/Makefile index 6daaaa2bb..4cfe7912e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -9,7 +9,7 @@ endif TESTS+=sha1# test_path #TESTS+=test_path -QEMU=../i386/qemu-i386 +QEMU=../i386-user/qemu-i386 all: $(TESTS) diff --git a/tests/sha1.c b/tests/sha1.c new file mode 100644 index 000000000..31b001920 --- /dev/null +++ b/tests/sha1.c @@ -0,0 +1,242 @@ + +/* from valgrind tests */ + +/* ================ sha1.c ================ */ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define SHA1HANDSOFF + +#include +#include +#include /* for u_int*_t */ + +/* ================ sha1.h ================ */ +/* +SHA-1 in C +By Steve Reid +100% Public Domain +*/ + +typedef struct { + u_int32_t state[5]; + u_int32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]); +void SHA1Init(SHA1_CTX* context); +void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len); +void SHA1Final(unsigned char digest[20], SHA1_CTX* context); +/* ================ end of sha1.h ================ */ +#include + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN +#define blk0(i) block->l[i] +#else +#error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) +{ +u_int32_t a, b, c, d, e; +typedef union { + unsigned char c[64]; + u_int32_t l[16]; +} CHAR64LONG16; +#ifdef SHA1HANDSOFF +CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + memcpy(block, buffer, 64); +#else + /* The following had better never be used because it causes the + * pointer-to-const buffer to be cast into a pointer to non-const. + * And the result is written through. I threw a "const" in, hoping + * this will cause a diagnostic. + */ +CHAR64LONG16* block = (const CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, '\0', sizeof(block)); +#endif +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len) +{ +u_int32_t i; +u_int32_t j; + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) + context->count[1]++; + context->count[1] += (len>>29); + j = (j >> 3) & 63; + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +unsigned i; +unsigned char finalcount[8]; +unsigned char c; + +#if 0 /* untested "improvement" by DHR */ + /* Convert context->count to a sequence of bytes + * in finalcount. Second element first, but + * big-endian order within element. + * But we do it all backwards. + */ + unsigned char *fcp = &finalcount[8]; + + for (i = 0; i < 2; i++) + { + u_int32_t t = context->count[i]; + int j; + + for (j = 0; j < 4; t >>= 8, j++) + *--fcp = (unsigned char) t + } +#else + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } +#endif + c = 0200; + SHA1Update(context, &c, 1); + while ((context->count[0] & 504) != 448) { + c = 0000; + SHA1Update(context, &c, 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} +/* ================ end of sha1.c ================ */ + +#define BUFSIZE 4096 + +int +main(int argc, char **argv) +{ + SHA1_CTX ctx; + unsigned char hash[20], buf[BUFSIZE]; + int i; + + for(i=0;i Date: Tue, 28 Oct 2003 00:12:52 +0000 Subject: fixed distclean target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@420 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e21712faf..b3da26606 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ clean: distclean: clean rm -f config-host.mak config-host.h for d in $(TARGET_DIRS); do \ - rm -f $$d/config.h $$d/config.mak || exit 1 ; \ + rm -rf $$d || exit 1 ; \ done install: all -- cgit v1.2.3 From b1f645758a19428783578a6ceed4fef9f24ab8d3 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 00:47:19 +0000 Subject: redhat 9 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@421 c046a42c-6fe2-441c-8c8c-71466251a162 --- i386.ld | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/i386.ld b/i386.ld index a64ec2f87..d41c62695 100644 --- a/i386.ld +++ b/i386.ld @@ -53,6 +53,16 @@ SECTIONS _etext = .; PROVIDE (etext = .); .fini : { *(.fini) } =0x47ff041f + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); .rodata : { *(.rodata) *(.gnu.linkonce.r*) } .rodata1 : { *(.rodata1) } .reginfo : { *(.reginfo) } -- cgit v1.2.3 From 76b62fd00130a9e8606aeaab82659bddb942dded Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 00:47:44 +0000 Subject: added binary archive git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@422 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index b3da26606..efec671b7 100644 --- a/Makefile +++ b/Makefile @@ -66,17 +66,19 @@ FILE=qemu-$(shell cat VERSION) tar: rm -rf /tmp/$(FILE) cp -r . /tmp/$(FILE) - ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) ) + ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS ) rm -rf /tmp/$(FILE) -# generate a binary distribution including the test binary environnment -BINPATH=/usr/local/qemu-i386 - +# generate a binary distribution tarbin: - tar zcvf /tmp/qemu-$(VERSION)-i386-glibc21.tar.gz \ - $(BINPATH)/etc $(BINPATH)/lib $(BINPATH)/bin $(BINPATH)/usr - tar zcvf /tmp/qemu-$(VERSION)-i386-wine.tar.gz \ - $(BINPATH)/wine + ( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \ + $(prefix)/bin/qemu $(prefix)/bin/qemu-fast \ + $(prefix)/bin/qemu-i386 \ + $(prefix)/bin/qemu-arm \ + $(prefix)/bin/qemu-sparc \ + $(sharedir)/bios.bin \ + $(sharedir)/vgabios.bin \ + $(mandir)/man1/qemu.1 ) ifneq ($(wildcard .depend),) include .depend -- cgit v1.2.3 From 3a4739d651cb69acfb23f7f8ec83784c24bc6e48 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 00:48:22 +0000 Subject: static link git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@423 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 7 +++++++ linux-user/main.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 95ea88640..cb6a0cc60 100644 --- a/Makefile.target +++ b/Makefile.target @@ -39,7 +39,14 @@ OP_CFLAGS+= -falign-functions=0 else OP_CFLAGS+= -malign-functions=0 endif + ifdef TARGET_GPROF +USE_I386_LD=y +endif +ifdef CONFIG_STATIC +USE_I386_LD=y +endif +ifdef USE_I386_LD LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386.ld else # WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object diff --git a/linux-user/main.c b/linux-user/main.c index 6df7b42c5..5b751541e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -30,7 +30,7 @@ static const char *interp_prefix = CONFIG_QEMU_PREFIX; -#ifdef __i386__ +#if defined(__i386__) && !defined(CONFIG_STATIC) /* Force usage of an ELF interpreter even if it is an ELF shared object ! */ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; -- cgit v1.2.3 From 5b9f457a8968f7ee0a4e8fd3dce66c2602da96f0 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 00:49:54 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@424 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-binfmt-conf.sh | 3 +++ qemu-doc.texi | 20 +++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 qemu-binfmt-conf.sh diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh new file mode 100644 index 000000000..a51f28102 --- /dev/null +++ b/qemu-binfmt-conf.sh @@ -0,0 +1,3 @@ +# enable automatic i386 program execution by the kernel (must enable binfmt_misc) +echo ':i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register +echo ':i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register diff --git a/qemu-doc.texi b/qemu-doc.texi index 8bb883afb..53d5c4f34 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -131,13 +131,23 @@ generic dynamic code generation architecture of QEMU. The SPARC emulation is currently in development. +@chapter Installation + +If you want to compile QEMU, please read the @file{README} which gives +the related information. Otherwise just download the binary +distribution (@file{qemu-XXX-i386.tar.gz}) and untar it as root in +@file{/}: + +@example +su +cd / +tar zxvf /tmp/qemu-XXX-i386.tar.gz +@end example + @chapter QEMU User space emulator invocation @section Quick Start -If you need to compile QEMU, please read the @file{README} which gives -the related information. - In order to launch a Linux process, QEMU needs the process executable itself and all the target (x86) dynamic libraries used by it. @@ -153,14 +163,14 @@ qemu-i386 -L / /bin/ls @code{-L /} tells that the x86 dynamic linker must be searched with a @file{/} prefix. -@item Since QEMU is also a linux process, you can launch qemu with qemu: +@item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources): @example qemu-i386 -L / qemu-i386 -L / /bin/ls @end example @item On non x86 CPUs, you need first to download at least an x86 glibc -(@file{qemu-XXX-i386-glibc21.tar.gz} on the QEMU web page). Ensure that +(@file{qemu-runtime-i386-XXX-.tar.gz} on the QEMU web page). Ensure that @code{LD_LIBRARY_PATH} is not set: @example -- cgit v1.2.3 From 9d4520d0e06a7dda8f3bf515e2b51fc240db698a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 01:38:57 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@425 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 53d5c4f34..0b8c069fc 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -426,14 +426,14 @@ A 2.5.74 kernel is also included in the archive. Just replace the bzImage in qemu.sh to try it. @item -vl creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the +qemu creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the default) containing all the simulated PC memory. If possible, try to use a temporary directory using the tmpfs filesystem to avoid too many unnecessary disk accesses. @item -In order to exit cleanly for vl, you can do a @emph{shutdown} inside -vl. vl will automatically exit when the Linux shutdown is done. +In order to exit cleanly from qemu, you can do a @emph{shutdown} inside +qemu. qemu will automatically exit when the Linux shutdown is done. @item You can boot slightly faster by disabling the probe of non present IDE @@ -458,7 +458,7 @@ usage: qemu [options] [disk_image] @end example @c man begin OPTIONS -@var{disk_image} is a raw hard image image for IDE hard disk 0. +@var{disk_image} is a raw hard disk image for IDE hard disk 0. General options: @table @option @@ -476,7 +476,7 @@ the write back by pressing @key{C-a s} (@xref{disk_images}). Set virtual RAM size to @var{megs} megabytes. @item -n script -Set network init script [default=/etc/vl-ifup]. This script is +Set network init script [default=/etc/qemu-ifup]. This script is launched to configure the host network interface (usually tun0) corresponding to the virtual NE2000 card. @@ -519,7 +519,7 @@ Wait gdb connection to port 1234 (@xref{gdb_usage}). @item -p port Change gdb connection port. @item -d -Output log in /tmp/vl.log +Output log in /tmp/qemu.log @end table During emulation, use @key{C-a h} to get terminal commands: @@ -704,10 +704,10 @@ exactly the same kernel as you would boot on your PC (in QEMU has a primitive support to work with gdb, so that you can do 'Ctrl-C' while the virtual machine is running and inspect its state. -In order to use gdb, launch vl with the '-s' option. It will wait for a +In order to use gdb, launch qemu with the '-s' option. It will wait for a gdb connection: @example -> vl -s arch/i386/boot/bzImage -hda root-2.4.20.img root=/dev/hda +> qemu -s arch/i386/boot/bzImage -hda root-2.4.20.img root=/dev/hda Connected to host network interface: tun0 Waiting gdb connection on port 1234 @end example -- cgit v1.2.3 From 508634723981e5cf269efb1c353afd1ec8b7a45a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 23:04:01 +0000 Subject: CONFIG_STATIC patch git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@426 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 0e2227084..2f27deed6 100755 --- a/configure +++ b/configure @@ -295,6 +295,7 @@ if test "$gprof" = "yes" ; then fi if test "$static" = "yes" ; then echo "CONFIG_STATIC=yes" >> $config_mak + echo "#define CONFIG_STATIC 1" >> $config_h fi if test "$sdl" = "yes" ; then echo "CONFIG_SDL=yes" >> $config_mak -- cgit v1.2.3 From 8948b5d6136eb0d338a71f94f5d607dd353c421d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 23:04:30 +0000 Subject: fixed ldq() macros git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@427 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_header.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/softmmu_header.h b/softmmu_header.h index 26b4f2cdd..82aae40b2 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -74,7 +74,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, int is_user); void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, DATA_TYPE v, int is_user); -static inline int glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) +static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) { int index; RES_TYPE res; -- cgit v1.2.3 From 9951bf39f90519a2a2eb3809eb13a27471b9398d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 28 Oct 2003 23:06:17 +0000 Subject: fixed long double accesses when using soft MMU git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@428 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 259 +++++++++++++++++++++++++++++---------------------- target-i386/helper.c | 10 -- target-i386/op.c | 18 ---- 3 files changed, 150 insertions(+), 137 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index eb13186cf..dc1df94ab 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -171,6 +171,115 @@ void helper_wrmsr(void); void helper_lsl(void); void helper_lar(void); +/* XXX: move that to a generic header */ +#if !defined(CONFIG_USER_ONLY) + +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel + +#define ACCESS_TYPE 0 +#define MEMSUFFIX _kernel +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ACCESS_TYPE 1 +#define MEMSUFFIX _user +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE 2 +#define MEMSUFFIX _data +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ldub(p) ldub_data(p) +#define ldsb(p) ldsb_data(p) +#define lduw(p) lduw_data(p) +#define ldsw(p) ldsw_data(p) +#define ldl(p) ldl_data(p) +#define ldq(p) ldq_data(p) + +#define stb(p, v) stb_data(p, v) +#define stw(p, v) stw_data(p, v) +#define stl(p, v) stl_data(p, v) +#define stq(p, v) stq_data(p, v) + +static inline double ldfq(void *ptr) +{ + union { + double d; + uint64_t i; + } u; + u.i = ldq(ptr); + return u.d; +} + +static inline void stfq(void *ptr, double v) +{ + union { + double d; + uint64_t i; + } u; + u.d = v; + stq(ptr, u.i); +} + +static inline float ldfl(void *ptr) +{ + union { + float f; + uint32_t i; + } u; + u.i = ldl(ptr); + return u.f; +} + +static inline void stfl(void *ptr, float v) +{ + union { + float f; + uint32_t i; + } u; + u.f = v; + stl(ptr, u.i); +} + +#endif /* !defined(CONFIG_USER_ONLY) */ + #ifdef USE_X86LDOUBLE /* use long double functions */ #define lrint lrintl @@ -317,7 +426,47 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) e |= SIGND(temp) >> 16; stw(ptr + 8, e); } -#endif +#else + +/* XXX: same endianness assumed */ + +#ifdef CONFIG_USER_ONLY + +static inline CPU86_LDouble helper_fldt(uint8_t *ptr) +{ + return *(CPU86_LDouble *)ptr; +} + +static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) +{ + *(CPU86_LDouble *)ptr = f; +} + +#else + +/* we use memory access macros */ + +static inline CPU86_LDouble helper_fldt(uint8_t *ptr) +{ + CPU86_LDoubleU temp; + + temp.l.lower = ldq(ptr); + temp.l.upper = lduw(ptr + 8); + return temp.d; +} + +static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) +{ + CPU86_LDoubleU temp; + + temp.d = f; + stq(ptr, temp.l.lower); + stw(ptr + 8, temp.l.upper); +} + +#endif /* !CONFIG_USER_ONLY */ + +#endif /* USE_X86LDOUBLE */ const CPU86_LDouble f15rk[7]; @@ -368,111 +517,3 @@ static inline void load_eflags(int eflags, int update_mask) (eflags & update_mask); } -/* XXX: move that to a generic header */ -#if !defined(CONFIG_USER_ONLY) - -#define ldul_user ldl_user -#define ldul_kernel ldl_kernel - -#define ACCESS_TYPE 0 -#define MEMSUFFIX _kernel -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ACCESS_TYPE 1 -#define MEMSUFFIX _user -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -/* these access are slower, they must be as rare as possible */ -#define ACCESS_TYPE 2 -#define MEMSUFFIX _data -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ldub(p) ldub_data(p) -#define ldsb(p) ldsb_data(p) -#define lduw(p) lduw_data(p) -#define ldsw(p) ldsw_data(p) -#define ldl(p) ldl_data(p) -#define ldq(p) ldq_data(p) - -#define stb(p, v) stb_data(p, v) -#define stw(p, v) stw_data(p, v) -#define stl(p, v) stl_data(p, v) -#define stq(p, v) stq_data(p, v) - -static inline double ldfq(void *ptr) -{ - union { - double d; - uint64_t i; - } u; - u.i = ldq(ptr); - return u.d; -} - -static inline void stfq(void *ptr, double v) -{ - union { - double d; - uint64_t i; - } u; - u.d = v; - stq(ptr, u.i); -} - -static inline float ldfl(void *ptr) -{ - union { - float f; - uint32_t i; - } u; - u.i = ldl(ptr); - return u.f; -} - -static inline void stfl(void *ptr, float v) -{ - union { - float f; - uint32_t i; - } u; - u.f = v; - stl(ptr, u.i); -} - -#endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target-i386/helper.c b/target-i386/helper.c index 43b8168a1..1c0920bcf 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1318,7 +1318,6 @@ void helper_lar(void) /* FPU helpers */ -#ifndef USE_X86LDOUBLE void helper_fldt_ST0_A0(void) { int new_fpstt; @@ -1332,7 +1331,6 @@ void helper_fstt_ST0_A0(void) { helper_fstt(ST0, (uint8_t *)A0); } -#endif /* BCD ops */ @@ -1729,11 +1727,7 @@ void helper_fsave(uint8_t *ptr, int data32) ptr += (14 << data32); for(i = 0;i < 8; i++) { tmp = ST(i); -#ifdef USE_X86LDOUBLE - *(long double *)ptr = tmp; -#else helper_fstt(tmp, ptr); -#endif ptr += 10; } @@ -1760,11 +1754,7 @@ void helper_frstor(uint8_t *ptr, int data32) ptr += (14 << data32); for(i = 0;i < 8; i++) { -#ifdef USE_X86LDOUBLE - tmp = *(long double *)ptr; -#else tmp = helper_fldt(ptr); -#endif ST(i) = tmp; ptr += 10; } diff --git a/target-i386/op.c b/target-i386/op.c index 0f4dbd18e..f1276f7a6 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1471,21 +1471,10 @@ void OPPROTO op_fldl_ST0_A0(void) env->fptags[new_fpstt] = 0; /* validate stack entry */ } -#ifdef USE_X86LDOUBLE -void OPPROTO op_fldt_ST0_A0(void) -{ - int new_fpstt; - new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = *(long double *)A0; - env->fpstt = new_fpstt; - env->fptags[new_fpstt] = 0; /* validate stack entry */ -} -#else void OPPROTO op_fldt_ST0_A0(void) { helper_fldt_ST0_A0(); } -#endif /* helpers are needed to avoid static constant reference. XXX: find a better way */ #ifdef USE_INT_TO_FLOAT_HELPERS @@ -1595,17 +1584,10 @@ void OPPROTO op_fstl_ST0_A0(void) stfq((void *)A0, (double)ST0); } -#ifdef USE_X86LDOUBLE -void OPPROTO op_fstt_ST0_A0(void) -{ - *(long double *)A0 = ST0; -} -#else void OPPROTO op_fstt_ST0_A0(void) { helper_fstt_ST0_A0(); } -#endif void OPPROTO op_fist_ST0_A0(void) { -- cgit v1.2.3 From 415fa2ea77b726ea5a5768d659881e919df1fcf2 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 00:39:38 +0000 Subject: soft MMU performance fix (oops) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@429 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index a64c58c8d..ab4fe09e6 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4394,7 +4394,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->mem_index = 3; } dc->jmp_opt = !(dc->tf || env->singlestep_enabled -#ifndef CONFIG_SOFT_MMU +#ifndef CONFIG_SOFTMMU || (flags & HF_SOFTMMU_MASK) #endif ); -- cgit v1.2.3 From 128b346e0a910d62162bc12588f38060f72e72df Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 01:05:49 +0000 Subject: cmov fix (bug on PowerPC) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@430 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/opreg_template.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/opreg_template.h b/target-i386/opreg_template.h index f35a1bbc9..16a43f2db 100644 --- a/target-i386/opreg_template.h +++ b/target-i386/opreg_template.h @@ -83,12 +83,14 @@ void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void) { if (T0) REG = (REG & 0xffff0000) | (T1 & 0xffff); + FORCE_RET(); } void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void) { if (T0) REG = T1; + FORCE_RET(); } /* NOTE: T0 high order bits are ignored */ -- cgit v1.2.3 From 03a6c5103d1a4c139cc28c8bb05a5752df4ee200 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 01:07:22 +0000 Subject: cannot simply write segment registers in system mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@431 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gdbstub.c b/gdbstub.c index 15b3940ed..bb3fed946 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -368,6 +368,7 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) } env->eip = registers[8]; env->eflags = registers[9]; +#if defined(CONFIG_USER_ONLY) #define LOAD_SEG(index, sreg)\ if (tswapl(registers[index]) != env->segs[sreg].selector)\ cpu_x86_load_seg(env, sreg, tswapl(registers[index])); @@ -377,6 +378,7 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) LOAD_SEG(13, R_ES); LOAD_SEG(14, R_FS); LOAD_SEG(15, R_GS); +#endif #endif put_packet("OK"); break; -- cgit v1.2.3 From 1a18c71b5037cff63a3e2c99debfcca0c6f7d09a Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 01:07:51 +0000 Subject: unused functions in system mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@432 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 956504d82..1f08934cb 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -378,7 +378,7 @@ int cpu_exec(CPUState *env1) return ret; } -#if defined(TARGET_I386) +#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY) void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) { -- cgit v1.2.3 From aebcb60e55587a675aa0a3023e60c827e19f73f2 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 01:08:17 +0000 Subject: no need for locks in system mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@433 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec-all.h b/exec-all.h index 9994acb7a..7d0972e86 100644 --- a/exec-all.h +++ b/exec-all.h @@ -384,7 +384,7 @@ typedef int spinlock_t; #define SPIN_LOCK_UNLOCKED 0 -#if 1 +#if defined(CONFIG_USER_ONLY) static inline void spin_lock(spinlock_t *lock) { while (testandset(lock)); -- cgit v1.2.3 From 7f7f98734192824c3899458963861f2f62b9ed2c Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 01:11:23 +0000 Subject: endianness and portability fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@434 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 90 ++++++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/vl.c b/vl.c index 944e759a0..a356dbf18 100644 --- a/vl.c +++ b/vl.c @@ -3319,6 +3319,12 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, } } +#ifdef CONFIG_SOFTMMU +void *get_mmap_addr(unsigned long size) +{ + return NULL; +} +#else unsigned long mmap_addr = PHYS_RAM_BASE; void *get_mmap_addr(unsigned long size) @@ -3328,6 +3334,7 @@ void *get_mmap_addr(unsigned long size) mmap_addr += ((size + 4095) & ~4095) + 4096; return (void *)addr; } +#endif /* main execution loop */ @@ -3522,7 +3529,7 @@ int main(int argc, char **argv) struct sigaction act; struct itimerval itv; CPUX86State *env; - const char *tmpdir, *initrd_filename; + const char *initrd_filename; const char *hd_filename[MAX_DISKS]; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; @@ -3644,32 +3651,47 @@ int main(int argc, char **argv) net_init(); /* init the memory */ - tmpdir = getenv("QEMU_TMPDIR"); - if (!tmpdir) - tmpdir = "/tmp"; - snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir); - if (mkstemp(phys_ram_file) < 0) { - fprintf(stderr, "Could not create temporary memory file '%s'\n", - phys_ram_file); - exit(1); - } - phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); - if (phys_ram_fd < 0) { - fprintf(stderr, "Could not open temporary memory file '%s'\n", - phys_ram_file); - exit(1); - } total_ram_size = phys_ram_size + vga_ram_size; - ftruncate(phys_ram_fd, total_ram_size); - unlink(phys_ram_file); - phys_ram_base = mmap(get_mmap_addr(total_ram_size), - total_ram_size, - PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, - phys_ram_fd, 0); - if (phys_ram_base == MAP_FAILED) { - fprintf(stderr, "Could not map physical memory\n"); + +#ifdef CONFIG_SOFTMMU + phys_ram_base = malloc(total_ram_size); + if (!phys_ram_base) { + fprintf(stderr, "Could not allocate physical memory\n"); exit(1); } +#else + /* as we must map the same page at several addresses, we must use + a fd */ + { + const char *tmpdir; + + tmpdir = getenv("QEMU_TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir); + if (mkstemp(phys_ram_file) < 0) { + fprintf(stderr, "Could not create temporary memory file '%s'\n", + phys_ram_file); + exit(1); + } + phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); + if (phys_ram_fd < 0) { + fprintf(stderr, "Could not open temporary memory file '%s'\n", + phys_ram_file); + exit(1); + } + ftruncate(phys_ram_fd, total_ram_size); + unlink(phys_ram_file); + phys_ram_base = mmap(get_mmap_addr(total_ram_size), + total_ram_size, + PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, + phys_ram_fd, 0); + if (phys_ram_base == MAP_FAILED) { + fprintf(stderr, "Could not map physical memory\n"); + exit(1); + } + } +#endif /* open the virtual block devices */ for(i = 0; i < MAX_DISKS; i++) { @@ -3717,14 +3739,14 @@ int main(int argc, char **argv) params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR); memset(params, 0, sizeof(struct linux_params)); params->mount_root_rdonly = 0; - params->cl_magic = 0xA33F; - params->cl_offset = params->commandline - (uint8_t *)params; - params->alt_mem_k = (phys_ram_size / 1024) - 1024; + stw_raw(¶ms->cl_magic, 0xA33F); + stw_raw(¶ms->cl_offset, params->commandline - (uint8_t *)params); + stl_raw(¶ms->alt_mem_k, (phys_ram_size / 1024) - 1024); pstrcat(params->commandline, sizeof(params->commandline), kernel_cmdline); params->loader_type = 0x01; if (initrd_size > 0) { - params->initrd_start = INITRD_LOAD_ADDR; - params->initrd_size = initrd_size; + stl_raw(¶ms->initrd_start, INITRD_LOAD_ADDR); + stl_raw(¶ms->initrd_size, initrd_size); } params->orig_video_lines = 25; params->orig_video_cols = 80; @@ -3735,11 +3757,11 @@ int main(int argc, char **argv) memset(params->idt_table, 0, sizeof(params->idt_table)); - params->gdt_table[2] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ - params->gdt_table[3] = 0x00cf92000000ffffLL; /* KERNEL_DS */ + stq_raw(¶ms->gdt_table[2], 0x00cf9a000000ffffLL); /* KERNEL_CS */ + stq_raw(¶ms->gdt_table[3], 0x00cf92000000ffffLL); /* KERNEL_DS */ /* for newer kernels (2.6.0) CS/DS are at different addresses */ - params->gdt_table[12] = 0x00cf9a000000ffffLL; /* KERNEL_CS */ - params->gdt_table[13] = 0x00cf92000000ffffLL; /* KERNEL_DS */ + stq_raw(¶ms->gdt_table[12], 0x00cf9a000000ffffLL); /* KERNEL_CS */ + stq_raw(¶ms->gdt_table[13], 0x00cf92000000ffffLL); /* KERNEL_DS */ env->idt.base = (void *)((uint8_t *)params->idt_table - phys_ram_base); env->idt.limit = sizeof(params->idt_table) - 1; @@ -3844,7 +3866,7 @@ int main(int argc, char **argv) timer_ms = itv.it_interval.tv_usec / 1000; pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / 1000000; - + if (use_gdbstub) { cpu_gdbstub(NULL, main_loop, gdbstub_port); } else { -- cgit v1.2.3 From c321f673095506f7fd67af8298eaf361f89fe554 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 01:18:42 +0000 Subject: enabled system emulator build on PowerPC - increased portability of soft mmu code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@435 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index cb6a0cc60..5bd8a8c3b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -20,10 +20,18 @@ endif ifdef CONFIG_USER_ONLY PROGS=$(QEMU_USER) else -ifeq ($(ARCH),i386) ifeq ($(TARGET_ARCH), i386) + +ifeq ($(ARCH), i386) +PROGS+=$(QEMU_SYSTEM) +endif + +ifeq ($(ARCH), ppc) +ifdef CONFIG_SOFTMMU PROGS+=$(QEMU_SYSTEM) endif +endif + endif endif @@ -174,8 +182,17 @@ VL_OBJS+=sdl.o SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm endif +VL_LDFLAGS= +# specific flags are needed for non soft mmu emulator +ifndef CONFIG_SOFTMMU +VL_LDFLAGS+=-static -Wl,-T,$(SRC_PATH)/i386-vl.ld +endif +ifdef CONFIG_STATIC +VL_LDFLAGS+=-static +endif + $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a - $(CC) -static -Wl,-T,$(SRC_PATH)/i386-vl.ld -o $@ $^ $(LIBS) $(SDL_LIBS) + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) sdl.o: sdl.c $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< -- cgit v1.2.3 From c970a162e7b152622b394f9268fc4aeb0f0e3b20 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 01:21:44 +0000 Subject: temporary hack for PowerPC system emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@436 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dyngen-exec.h b/dyngen-exec.h index ed286db8f..ec32fbc9e 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -54,6 +54,8 @@ extern int printf(const char *, ...); #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" @@ -62,6 +64,7 @@ extern int printf(const char *, ...); #define AREG9 "r21" #define AREG10 "r22" #define AREG11 "r23" +#endif #define USE_INT_TO_FLOAT_HELPERS #define BUGGY_GCC_DIV64 #endif -- cgit v1.2.3 From b8ed223bfe3b1af434adce07b2981ce8b5b9ecb4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Oct 2003 22:10:22 +0000 Subject: big endian fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@437 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index b16118b88..9db5d955c 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -141,12 +141,24 @@ static const uint8_t gr_mask[16] = { (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) -#ifdef WORD_BIGENDIAN +#ifdef WORDS_BIGENDIAN #define PAT(x) cbswap_32(x) #else #define PAT(x) (x) #endif +#ifdef WORDS_BIGENDIAN +#define BIG 1 +#else +#define BIG 0 +#endif + +#ifdef WORDS_BIGENDIAN +#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff) +#else +#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff) +#endif + static const uint32_t mask16[16] = { PAT(0x00000000), PAT(0x000000ff), @@ -168,7 +180,7 @@ static const uint32_t mask16[16] = { #undef PAT -#ifdef WORD_BIGENDIAN +#ifdef WORDS_BIGENDIAN #define PAT(x) (x) #else #define PAT(x) cbswap_32(x) @@ -465,11 +477,7 @@ static uint32_t vga_mem_readb(uint32_t addr) if (!(s->gr[5] & 0x08)) { /* read mode 0 */ plane = s->gr[4]; -#ifdef WORD_BIGENDIAN - ret = (s->latch >> (24 - (plane * 8))) & 0xff; -#else - ret = (s->latch >> (plane * 8)) & 0xff; -#endif + ret = GET_PLANE(s->latch, plane); } else { /* read mode 1 */ ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]]; @@ -641,18 +649,6 @@ void vga_mem_writel(uint32_t addr, uint32_t val) vga_mem_writeb(addr + 3, (val >> 24) & 0xff); } -#ifdef WORD_BIGENDIAN -#define BIG 1 -#else -#define BIG 0 -#endif - -#ifdef WORDS_BIGENDIAN -#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff) -#else -#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff) -#endif - typedef void vga_draw_glyph8_func(uint8_t *d, int linesize, const uint8_t *font_ptr, int h, uint32_t fgcol, uint32_t bgcol); -- cgit v1.2.3 From e748ba4f5352061474668a47341abe2a898e03ad Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Nov 2003 22:25:25 +0000 Subject: ARM half word load/store fix (Ulrich Hecht) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@438 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index bffeefa4f..808fa2b34 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -546,8 +546,7 @@ static void disas_arm_insn(DisasContext *s) rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; gen_movl_T1_reg(s, rn); - if (insn & (1 << 25)) - gen_add_datah_offset(s, insn); + gen_add_datah_offset(s, insn); if (insn & (1 << 20)) { /* load */ switch(sh) { @@ -562,8 +561,10 @@ static void disas_arm_insn(DisasContext *s) gen_op_ldsw_T0_T1(); break; } + gen_movl_reg_T0(s, rd); } else { /* store */ + gen_movl_T0_reg(s, rd); gen_op_stw_T0_T1(); } if (!(insn & (1 << 24))) { -- cgit v1.2.3 From 9c3ad57432e9e90b3a79acd7ac487cd614762a3b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Nov 2003 23:33:13 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@439 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 6a0c711cf..5b6ce64b6 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +version 0.5.1: + + - float access fixes when using soft mmu + - PC emulation support on PowerPC + - A20 support + version 0.5.0: - full hardware level VGA emulation @@ -18,7 +24,7 @@ version 0.5.0: - automatic IDE geometry detection - renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}. - added man page - - added full soft mmy mode to launch unpatched OSes. + - added full soft mmu mode to launch unpatched OSes. version 0.4.3: -- cgit v1.2.3 From 461c0471af05cf29ac416afdbc9480e4732e4252 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Nov 2003 23:34:23 +0000 Subject: a20 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@440 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 3 +++ target-i386/helper2.c | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index ffc4654d3..00bc17e76 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -389,6 +389,9 @@ void cpu_x86_init_mmu(CPUX86State *env); extern int phys_ram_size; extern int phys_ram_fd; extern uint8_t *phys_ram_base; +extern int a20_enabled; + +void cpu_x86_set_a20(CPUX86State *env, int a20_state); /* used to debug */ #define X86_DUMP_FPU 0x0001 /* dump FPU state too */ diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 1bec82081..f1617d8c6 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -158,10 +158,29 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) /* called when cr3 or PG bit are modified */ static int last_pg_state = -1; static int last_pe_state = 0; +static uint32_t a20_mask; +int a20_enabled; + int phys_ram_size; int phys_ram_fd; uint8_t *phys_ram_base; +void cpu_x86_set_a20(CPUX86State *env, int a20_state) +{ + a20_state = (a20_state != 0); + if (a20_state != a20_enabled) { + /* when a20 is changed, all the MMU mappings are invalid, so + we must flush everything */ + page_unmap(); + tlb_flush(env); + a20_enabled = a20_state; + if (a20_enabled) + a20_mask = 0xffffffff; + else + a20_mask = 0xffefffff; + } +} + void cpu_x86_update_cr0(CPUX86State *env) { int pg_state, pe_state; @@ -195,6 +214,9 @@ void cpu_x86_update_cr3(CPUX86State *env) void cpu_x86_init_mmu(CPUX86State *env) { + a20_enabled = 1; + a20_mask = 0xffffffff; + last_pg_state = -1; cpu_x86_update_cr0(env); } @@ -244,14 +266,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr; - virt_addr = addr & ~0xfff; + virt_addr = addr & TARGET_PAGE_MASK; prot = PROT_READ | PROT_WRITE; page_size = 4096; goto do_mapping; } /* page directory entry */ - pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); + pde_ptr = phys_ram_base + + (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask); pde = ldl_raw(pde_ptr); if (!(pde & PG_PRESENT_MASK)) { error_code = 0; @@ -287,7 +310,8 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, } /* page directory entry */ - pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); + pte_ptr = phys_ram_base + + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); pte = ldl_raw(pte_ptr); if (!(pte & PG_PRESENT_MASK)) { error_code = 0; @@ -325,6 +349,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, } do_mapping: + pte = pte & a20_mask; #if !defined(CONFIG_SOFTMMU) if (is_softmmu) #endif @@ -334,8 +359,8 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, /* software MMU case. Even if 4MB pages, we map only one 4KB page in the cache to avoid filling it too fast */ - page_offset = (addr & ~0xfff) & (page_size - 1); - paddr = (pte & ~0xfff) + page_offset; + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); + paddr = (pte & TARGET_PAGE_MASK) + page_offset; vaddr = virt_addr + page_offset; index = (addr >> 12) & (CPU_TLB_SIZE - 1); pd = physpage_find(paddr); -- cgit v1.2.3 From 1f5476fcce8f76fe0d53ae8c51e1c50e8f13e1ed Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Nov 2003 23:35:20 +0000 Subject: a20 support - keyboard led fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@441 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vl.c b/vl.c index a356dbf18..a3b49ab13 100644 --- a/vl.c +++ b/vl.c @@ -2594,8 +2594,8 @@ void ide_init(void) #define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if initiated by the auxiliary device */ #define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ -#define KBD_CCMD_ENABLE_A20 0xDD -#define KBD_CCMD_DISABLE_A20 0xDF +#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ +#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ #define KBD_CCMD_RESET 0xFE /* Keyboard Commands */ @@ -2685,7 +2685,6 @@ typedef struct KBDState { KBDState kbd_state; int reset_requested; -int a20_enabled; /* update irq and KBD_STAT_[MOUSE_]OBF */ static void kbd_update_irq(KBDState *s) @@ -2802,10 +2801,10 @@ void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) kbd_queue(s, val, 0); break; case KBD_CCMD_ENABLE_A20: - a20_enabled = 1; + cpu_x86_set_a20(env, 1); break; case KBD_CCMD_DISABLE_A20: - a20_enabled = 0; + cpu_x86_set_a20(env, 0); break; case KBD_CCMD_RESET: reset_requested = 1; @@ -2875,6 +2874,7 @@ static void kbd_write_keyboard(KBDState *s, int val) case KBD_CMD_SET_LEDS: case KBD_CMD_SET_RATE: s->kbd_write_cmd = val; + kbd_queue(s, KBD_REPLY_ACK, 0); break; case KBD_CMD_RESET_DISABLE: kbd_reset_keyboard(s); @@ -3129,7 +3129,7 @@ void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) kbd_queue(s, val, 1); break; case KBD_CCMD_WRITE_OUTPORT: - a20_enabled = (val >> 1) & 1; + cpu_x86_set_a20(env, (val >> 1) & 1); if (!(val & 1)) { reset_requested = 1; cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); -- cgit v1.2.3 From e58143b3550f08254118995c667adefc64f2cc20 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 9 Nov 2003 14:42:54 +0000 Subject: ppc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@442 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index d36566164..65922aa77 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -480,9 +480,9 @@ void OPPROTO op_restore_T0 (void) void OPPROTO op_generic_branch (void) { if (T0) - JUMP_TB (__func__, PARAM1, 0, PARAM2); + JUMP_TB (op_generic_branch, PARAM1, 0, PARAM2); else - JUMP_TB (__func__, PARAM1, 1, PARAM3); + JUMP_TB (op_generic_branch, PARAM1, 1, PARAM3); FORCE_RET (); } @@ -491,10 +491,6 @@ void OPPROTO op_generic_branch_a (void) if (T0) env->npc = PARAM3; else - JUMP_TB (__func__, PARAM1, 0, PARAM2); + JUMP_TB (op_generic_branch_a, PARAM1, 0, PARAM2); FORCE_RET (); } - -void OPPROTO op_noop (void) -{ -} -- cgit v1.2.3 From 4ad06a29b2460d4f2474f82dad3cb53467f14eb3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 9 Nov 2003 16:58:12 +0000 Subject: soft mmu fix (aka debian random seg fault fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@443 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_template.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/softmmu_template.h b/softmmu_template.h index 4f4f2f4d3..2dad910bf 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -187,7 +187,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, redo: tlb_addr = env->tlb_write[is_user][index].address; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_read[is_user][index].addend; + physaddr = addr + env->tlb_write[is_user][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -223,7 +223,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, redo: tlb_addr = env->tlb_write[is_user][index].address; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_read[is_user][index].addend; + physaddr = addr + env->tlb_write[is_user][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) -- cgit v1.2.3 From 36b486bb74ca651d07968372cebd6e742114e144 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 11 Nov 2003 13:36:08 +0000 Subject: hardware level IDE CD-ROM emulation - added second IDE interface for up to 4 IDE disks emulation - added -boot command to enable CD boot git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@444 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 815 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 744 insertions(+), 71 deletions(-) diff --git a/vl.c b/vl.c index a3b49ab13..053f3e90f 100644 --- a/vl.c +++ b/vl.c @@ -63,6 +63,7 @@ /* debug IDE devices */ //#define DEBUG_IDE +//#define DEBUG_IDE_ATAPI /* debug PIC */ //#define DEBUG_PIC @@ -85,7 +86,7 @@ #define GUI_REFRESH_INTERVAL 30 -#define MAX_DISKS 2 +#define MAX_DISKS 4 /* from plex86 (BSD license) */ struct __attribute__ ((packed)) linux_params { @@ -216,6 +217,7 @@ static DisplayState display_state; int nographic; int term_inited; int64_t ticks_per_sec; +int boot_device = 'c'; /***********************************************************/ /* x86 io ports */ @@ -533,8 +535,19 @@ void cmos_init(void) cmos_data[0x34] = val; cmos_data[0x35] = val >> 8; - cmos_data[0x3d] = 0x02; /* hard drive boot */ - + switch(boot_device) { + case 'a': + cmos_data[0x3d] = 0x01; /* floppy boot */ + break; + default: + case 'c': + cmos_data[0x3d] = 0x02; /* hard drive boot */ + break; + case 'd': + cmos_data[0x3d] = 0x03; /* CD-ROM boot */ + break; + } + register_ioport_write(0x70, 2, cmos_ioport_write, 1); register_ioport_read(0x70, 2, cmos_ioport_read, 1); } @@ -1045,7 +1058,7 @@ static inline void pit_load_count(PITChannelState *s, int val) s->count = val; if (s == &pit_channels[0] && val <= pit_min_timer_count) { fprintf(stderr, - "\nWARNING: vl: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.5.xx Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", + "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.5.xx Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", PIT_FREQ / pit_min_timer_count); } } @@ -2014,12 +2027,111 @@ void ne2000_init(void) /* set to 1 set disable mult support */ #define MAX_MULT_SECTORS 8 +/* ATAPI defines */ + +#define ATAPI_PACKET_SIZE 12 + +/* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +#define GPCMD_BLANK 0xa1 +#define GPCMD_CLOSE_TRACK 0x5b +#define GPCMD_FLUSH_CACHE 0x35 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_GET_PERFORMANCE 0xac +#define GPCMD_INQUIRY 0x12 +#define GPCMD_LOAD_UNLOAD 0xa6 +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TI 0x48 +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define GPCMD_READ_10 0x28 +#define GPCMD_READ_12 0xa8 +#define GPCMD_READ_CDVD_CAPACITY 0x25 +#define GPCMD_READ_CD 0xbe +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_READ_DISC_INFO 0x51 +#define GPCMD_READ_DVD_STRUCTURE 0xad +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_READ_TRACK_RZONE_INFO 0x52 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_REPAIR_RZONE_TRACK 0x58 +#define GPCMD_REPORT_KEY 0xa4 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_RESERVE_RZONE_TRACK 0x53 +#define GPCMD_SCAN 0xba +#define GPCMD_SEEK 0x2b +#define GPCMD_SEND_DVD_STRUCTURE 0xad +#define GPCMD_SEND_EVENT 0xa2 +#define GPCMD_SEND_KEY 0xa3 +#define GPCMD_SEND_OPC 0x54 +#define GPCMD_SET_READ_AHEAD 0xa7 +#define GPCMD_SET_STREAMING 0xb6 +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_WRITE_10 0x2a +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +/* This is listed as optional in ATAPI 2.6, but is (curiously) + * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji + * Table 377 as an MMC command for SCSi devices though... Most ATAPI + * drives support it. */ +#define GPCMD_SET_SPEED 0xbb +/* This seems to be a SCSI specific CD-ROM opcode + * to play data at track/index */ +#define GPCMD_PLAYAUDIO_TI 0x48 +/* + * From MS Media Status Notification Support Specification. For + * older drives only. + */ +#define GPCMD_GET_MEDIA_STATUS 0xda + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_WRITE_PARMS_PAGE 0x05 +#define GPMODE_AUDIO_CTL_PAGE 0x0e +#define GPMODE_POWER_PAGE 0x1a +#define GPMODE_FAULT_FAIL_PAGE 0x1c +#define GPMODE_TO_PROTECT_PAGE 0x1d +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f +/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor + * of MODE_SENSE_POWER_PAGE */ +#define GPMODE_CDROM_PAGE 0x0d + +#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ +#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ +#define ATAPI_INT_REASON_REL 0x04 +#define ATAPI_INT_REASON_TAG 0xf8 + +/* same constants as bochs */ +#define ASC_LOGICAL_BLOCK_OOR 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 + +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + struct IDEState; typedef void EndTransferFunc(struct IDEState *); typedef struct IDEState { /* ide config */ + int is_cdrom; + int cdrom_locked; int cylinders, heads, sectors; int64_t nb_sectors; int mult_sectors; @@ -2038,6 +2150,14 @@ typedef struct IDEState { /* depends on bit 4 in select, only meaningful for drive 0 */ struct IDEState *cur_drive; BlockDriverState *bs; + /* ATAPI specific */ + uint8_t sense_key; + uint8_t asc; + int packet_transfer_size; + int elementary_transfer_size; + int io_buffer_index; + int lba; + /* transfer handling */ int req_nb_sectors; /* number of sectors per interrupt */ EndTransferFunc *end_transfer_func; uint8_t *data_ptr; @@ -2046,6 +2166,12 @@ typedef struct IDEState { } IDEState; IDEState ide_state[MAX_DISKS]; +IDEState *ide_table[0x400 >> 3]; + +static inline IDEState *get_ide_interface(uint32_t addr) +{ + return ide_table[addr >> 3]; +} static void padstr(char *str, const char *src, int len) { @@ -2073,10 +2199,12 @@ static void ide_identify(IDEState *s) stw_raw(p + 4, 512 * s->sectors); /* sectors */ stw_raw(p + 5, 512); /* sector size */ stw_raw(p + 6, s->sectors); + padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ stw_raw(p + 20, 3); /* buffer type */ stw_raw(p + 21, 512); /* cache size in sectors */ stw_raw(p + 22, 4); /* ecc bytes */ - padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); + padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ #if MAX_MULT_SECTORS > 1 stw_raw(p + 47, MAX_MULT_SECTORS); #endif @@ -2103,6 +2231,59 @@ static void ide_identify(IDEState *s) stw_raw(p + 87, (1 << 14)); } +static void ide_atapi_identify(IDEState *s) +{ + uint16_t *p; + + memset(s->io_buffer, 0, 512); + p = (uint16_t *)s->io_buffer; + /* Removable CDROM, 50us response, 12 byte packets */ + stw_raw(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); + stw_raw(p + 1, s->cylinders); + stw_raw(p + 3, s->heads); + stw_raw(p + 4, 512 * s->sectors); /* sectors */ + stw_raw(p + 5, 512); /* sector size */ + stw_raw(p + 6, s->sectors); + padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ + stw_raw(p + 20, 3); /* buffer type */ + stw_raw(p + 21, 512); /* cache size in sectors */ + stw_raw(p + 22, 4); /* ecc bytes */ + padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ + stw_raw(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ + stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ + stw_raw(p + 53, 3); /* words 64-70, 54-58 valid */ + stw_raw(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ + stw_raw(p + 64, 1); /* PIO modes */ + stw_raw(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ + stw_raw(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ + stw_raw(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ + stw_raw(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ + + stw_raw(p + 71, 30); /* in ns */ + stw_raw(p + 72, 30); /* in ns */ + + stw_raw(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ +} + +static void ide_set_signature(IDEState *s) +{ + s->select &= 0xf0; /* clear head */ + /* put signature */ + s->nsector = 1; + s->sector = 1; + if (s->is_cdrom) { + s->lcyl = 0x14; + s->hcyl = 0xeb; + } else if (s->bs) { + s->lcyl = 0; + s->hcyl = 0; + } else { + s->lcyl = 0xff; + s->hcyl = 0xff; + } +} + static inline void ide_abort_command(IDEState *s) { s->status = READY_STAT | ERR_STAT; @@ -2111,18 +2292,18 @@ static inline void ide_abort_command(IDEState *s) static inline void ide_set_irq(IDEState *s) { - if (!(ide_state[0].cmd & IDE_CMD_DISABLE_IRQ)) { + if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { pic_set_irq(s->irq, 1); } } /* prepare data transfer and tell what to do after */ -static void ide_transfer_start(IDEState *s, int size, +static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, EndTransferFunc *end_transfer_func) { s->end_transfer_func = end_transfer_func; - s->data_ptr = s->io_buffer; - s->data_end = s->io_buffer + size; + s->data_ptr = buf; + s->data_end = buf + size; s->status |= DRQ_STAT; } @@ -2185,7 +2366,7 @@ static void ide_sector_read(IDEState *s) if (n > s->req_nb_sectors) n = s->req_nb_sectors; ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); - ide_transfer_start(s, 512 * n, ide_sector_read); + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); ide_set_irq(s); ide_set_sector(s, sector_num + n); s->nsector -= n; @@ -2214,21 +2395,457 @@ static void ide_sector_write(IDEState *s) n1 = s->nsector; if (n1 > s->req_nb_sectors) n1 = s->req_nb_sectors; - ide_transfer_start(s, 512 * n1, ide_sector_write); + ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); } ide_set_sector(s, sector_num + n); ide_set_irq(s); } +static void ide_atapi_cmd_ok(IDEState *s) +{ + s->error = 0; + s->status = READY_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s); +} + +static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) +{ +#ifdef DEBUG_IDE_ATAPI + printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); +#endif + s->error = sense_key << 4; + s->status = READY_STAT | ERR_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + s->sense_key = sense_key; + s->asc = asc; + ide_set_irq(s); +} + +static inline void cpu_to_ube16(uint8_t *buf, int val) +{ + buf[0] = val >> 8; + buf[1] = val; +} + +static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) +{ + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; +} + +static inline int ube16_to_cpu(const uint8_t *buf) +{ + return (buf[0] << 8) | buf[1]; +} + +static inline int ube32_to_cpu(const uint8_t *buf) +{ + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + +/* The whole ATAPI transfer logic is handled in this function */ +static void ide_atapi_cmd_reply_end(IDEState *s) +{ + int byte_count_limit, size; +#ifdef DEBUG_IDE_ATAPI + printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", + s->packet_transfer_size, + s->elementary_transfer_size, + s->io_buffer_index); +#endif + if (s->packet_transfer_size <= 0) { + /* end of transfer */ + ide_transfer_stop(s); + s->status = READY_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s); +#ifdef DEBUG_IDE_ATAPI + printf("status=0x%x\n", s->status); +#endif + } else { + /* see if a new sector must be read */ + if (s->lba != -1 && s->io_buffer_index >= 2048) { + bdrv_read(s->bs, (int64_t)s->lba << 2, s->io_buffer, 4); + s->lba++; + s->io_buffer_index = 0; + } + if (s->elementary_transfer_size > 0) { + /* there are some data left to transmit in this elementary + transfer */ + size = 2048 - s->io_buffer_index; + if (size > s->elementary_transfer_size) + size = s->elementary_transfer_size; + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, + size, ide_atapi_cmd_reply_end); + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; + } else { + /* a new transfer is needed */ + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; + byte_count_limit = s->lcyl | (s->hcyl << 8); +#ifdef DEBUG_IDE_ATAPI + printf("byte_count_limit=%d\n", byte_count_limit); +#endif + if (byte_count_limit == 0xffff) + byte_count_limit--; + size = s->packet_transfer_size; + if (size > byte_count_limit) { + /* byte count limit must be even if this case */ + if (byte_count_limit & 1) + byte_count_limit--; + size = byte_count_limit; + } else { + s->lcyl = size; + s->hcyl = size >> 8; + } + s->elementary_transfer_size = size; + /* we cannot transmit more than one sector at a time */ + if (s->lba != -1) { + if (size > (2048 - s->io_buffer_index)) + size = (2048 - s->io_buffer_index); + } + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, + size, ide_atapi_cmd_reply_end); + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; + ide_set_irq(s); +#ifdef DEBUG_IDE_ATAPI + printf("status=0x%x\n", s->status); +#endif + } + } +} + +/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ +static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) +{ + if (size > max_size) + size = max_size; + s->lba = -1; /* no sector read */ + s->packet_transfer_size = size; + s->elementary_transfer_size = 0; + s->io_buffer_index = 0; + + s->status = READY_STAT; + ide_atapi_cmd_reply_end(s); +} + +/* start a CD-CDROM read command */ +static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors) +{ +#ifdef DEBUG_IDE_ATAPI + printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); +#endif + s->lba = lba; + s->packet_transfer_size = nb_sectors * 2048; + s->elementary_transfer_size = 0; + s->io_buffer_index = 2048; + + s->status = READY_STAT; + ide_atapi_cmd_reply_end(s); +} + +/* same toc as bochs. Return -1 if error or the toc length */ +static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) +{ + uint8_t *q; + int nb_sectors, len; + + if (start_track > 1 && start_track != 0xaa) + return -1; + q = buf + 2; + *q++ = 1; + *q++ = 1; + if (start_track <= 1) { + *q++ = 0; /* reserved */ + *q++ = 0x14; /* ADR, control */ + *q++ = 1; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + *q++ = 0; /* minute */ + *q++ = 2; /* second */ + *q++ = 0; /* frame */ + } else { + /* sector 0 */ + cpu_to_ube32(q, 0); + q += 4; + } + } + /* lead out track */ + *q++ = 0; /* reserved */ + *q++ = 0x16; /* ADR, control */ + *q++ = 0xaa; /* track number */ + *q++ = 0; /* reserved */ + nb_sectors = s->nb_sectors >> 2; + if (msf) { + *q++ = 0; /* reserved */ + *q++ = ((nb_sectors + 150) / 75) / 60; + *q++ = ((nb_sectors + 150) / 75) % 60; + *q++ = (nb_sectors + 150) % 75; + } else { + cpu_to_ube32(q, nb_sectors); + q += 4; + } + len = q - buf; + cpu_to_ube16(buf, len - 2); + return len; +} + +static void ide_atapi_cmd(IDEState *s) +{ + const uint8_t *packet; + uint8_t *buf; + int max_len; + + packet = s->io_buffer; + buf = s->io_buffer; +#ifdef DEBUG_IDE_ATAPI + { + int i; + printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); + for(i = 0; i < ATAPI_PACKET_SIZE; i++) { + printf(" %02x", packet[i]); + } + printf("\n"); + } +#endif + switch(s->io_buffer[0]) { + case GPCMD_TEST_UNIT_READY: + if (s->bs) { + ide_atapi_cmd_ok(s); + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } + break; + case GPCMD_MODE_SENSE_10: + { + int action, code; + max_len = ube16_to_cpu(packet + 7); + action = packet[2] >> 6; + code = packet[2] & 0x3f; + switch(action) { + case 0: /* current values */ + switch(code) { + case 0x01: /* error recovery */ + cpu_to_ube16(&buf[0], 16 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x01; + buf[9] = 0x06; + buf[10] = 0x00; + buf[11] = 0x05; + buf[12] = 0x00; + buf[13] = 0x00; + buf[14] = 0x00; + buf[15] = 0x00; + ide_atapi_cmd_reply(s, 16, max_len); + break; + case 0x2a: + cpu_to_ube16(&buf[0], 28 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x2a; + buf[9] = 0x12; + buf[10] = 0x00; + buf[11] = 0x00; + + buf[12] = 0x70; + buf[13] = 3 << 5; + buf[14] = (1 << 0) | (1 << 3) | (1 << 5); + if (s->cdrom_locked) + buf[6] |= 1 << 1; + buf[15] = 0x00; + cpu_to_ube16(&buf[16], 706); + buf[18] = 0; + buf[19] = 2; + cpu_to_ube16(&buf[20], 512); + cpu_to_ube16(&buf[22], 706); + buf[24] = 0; + buf[25] = 0; + buf[26] = 0; + buf[27] = 0; + ide_atapi_cmd_reply(s, 28, max_len); + break; + default: + goto error_cmd; + } + break; + case 1: /* changeable values */ + goto error_cmd; + case 2: /* default values */ + goto error_cmd; + default: + case 3: /* saved values */ + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_SAVING_PARAMETERS_NOT_SUPPORTED); + break; + } + } + break; + case GPCMD_REQUEST_SENSE: + max_len = packet[4]; + memset(buf, 0, 18); + buf[0] = 0x70 | (1 << 7); + buf[2] = s->sense_key; + buf[7] = 10; + buf[12] = s->asc; + ide_atapi_cmd_reply(s, 18, max_len); + break; + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + if (s->bs) { + s->cdrom_locked = packet[4] & 1; + ide_atapi_cmd_ok(s); + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } + break; + case GPCMD_READ_10: + case GPCMD_READ_12: + { + int nb_sectors, lba; + + if (!s->bs) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + if (packet[0] == GPCMD_READ_10) + nb_sectors = ube16_to_cpu(packet + 7); + else + nb_sectors = ube32_to_cpu(packet + 6); + lba = ube32_to_cpu(packet + 2); + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + break; + } + if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + break; + } + ide_atapi_cmd_read(s, lba, nb_sectors); + } + break; + case GPCMD_SEEK: + { + int lba; + if (!s->bs) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + lba = ube32_to_cpu(packet + 2); + if (((int64_t)lba << 2) > s->nb_sectors) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + break; + } + ide_atapi_cmd_ok(s); + } + break; + case GPCMD_START_STOP_UNIT: + { + int start, eject; + start = packet[4] & 1; + eject = (packet[4] >> 1) & 1; + + /* XXX: currently none implemented */ + ide_atapi_cmd_ok(s); + } + break; + case GPCMD_MECHANISM_STATUS: + { + max_len = ube16_to_cpu(packet + 8); + cpu_to_ube16(buf, 0); + /* no current LBA */ + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + buf[5] = 1; + cpu_to_ube16(buf + 6, 0); + ide_atapi_cmd_reply(s, 8, max_len); + } + break; + case GPCMD_READ_TOC_PMA_ATIP: + { + int format, msf, start_track, len; + + if (!s->bs) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + max_len = ube16_to_cpu(packet + 7); + format = packet[9] >> 6; + msf = (packet[1] >> 1) & 1; + start_track = packet[6]; + switch(format) { + case 0: + len = cdrom_read_toc(s, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; + case 1: + /* multi session : only a single session defined */ + memset(buf, 0, 12); + buf[1] = 0x0a; + buf[2] = 0x01; + buf[3] = 0x01; + ide_atapi_cmd_reply(s, 12, max_len); + break; + default: + goto error_cmd; + } + } + break; + case GPCMD_READ_CDVD_CAPACITY: + if (!s->bs) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + /* NOTE: it is really the number of sectors minus 1 */ + cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); + cpu_to_ube32(buf + 4, 2048); + ide_atapi_cmd_reply(s, 8, 8); + break; + default: + error_cmd: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } +} + void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) { - IDEState *s = ide_state[0].cur_drive; + IDEState *ide_if = get_ide_interface(addr); + IDEState *s = ide_if->cur_drive; int unit, n; - addr &= 7; #ifdef DEBUG_IDE printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); #endif + addr &= 7; switch(addr) { case 0: break; @@ -2252,8 +2869,8 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) case 6: /* select drive */ unit = (val >> 4) & 1; - s = &ide_state[unit]; - ide_state[0].cur_drive = s; + s = ide_if + unit; + ide_if->cur_drive = s; s->select = val; break; default: @@ -2263,13 +2880,15 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) printf("ide: CMD=%02x\n", val); #endif switch(val) { - case WIN_PIDENTIFY: case WIN_IDENTIFY: - if (s->bs) { + if (s->bs && !s->is_cdrom) { ide_identify(s); s->status = READY_STAT; - ide_transfer_start(s, 512, ide_transfer_stop); + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); } else { + if (s->is_cdrom) { + ide_set_signature(s); + } ide_abort_command(s); } ide_set_irq(s); @@ -2299,7 +2918,7 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) case WIN_WRITE_ONCE: s->status = SEEK_STAT; s->req_nb_sectors = 1; - ide_transfer_start(s, 512, ide_sector_write); + ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); break; case WIN_MULTREAD: if (!s->mult_sectors) @@ -2315,13 +2934,42 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) n = s->nsector; if (n > s->req_nb_sectors) n = s->req_nb_sectors; - ide_transfer_start(s, 512 * n, ide_sector_write); + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); break; case WIN_READ_NATIVE_MAX: ide_set_sector(s, s->nb_sectors - 1); s->status = READY_STAT; ide_set_irq(s); break; + + /* ATAPI commands */ + case WIN_PIDENTIFY: + if (s->is_cdrom) { + ide_atapi_identify(s); + s->status = READY_STAT; + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); + } else { + ide_abort_command(s); + } + ide_set_irq(s); + break; + case WIN_SRST: + if (!s->is_cdrom) + goto abort_cmd; + ide_set_signature(s); + s->status = READY_STAT; + s->error = 0x01; + break; + case WIN_PACKETCMD: + if (!s->is_cdrom) + goto abort_cmd; + /* DMA or overlapping commands not supported */ + if ((s->feature & 0x03) != 0) + goto abort_cmd; + s->nsector = 1; + ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, + ide_atapi_cmd); + break; default: abort_cmd: ide_abort_command(s); @@ -2331,12 +2979,13 @@ void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } } -uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr1) { - IDEState *s = ide_state[0].cur_drive; + IDEState *s = get_ide_interface(addr1)->cur_drive; + uint32_t addr; int ret; - addr &= 7; + addr = addr1 & 7; switch(addr) { case 0: ret = 0xff; @@ -2366,66 +3015,57 @@ uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr) break; } #ifdef DEBUG_IDE - printf("ide: read addr=0x%x val=%02x\n", addr, ret); + printf("ide: read addr=0x%x val=%02x\n", addr1, ret); #endif return ret; } uint32_t ide_status_read(CPUX86State *env, uint32_t addr) { - IDEState *s = ide_state[0].cur_drive; + IDEState *s = get_ide_interface(addr)->cur_drive; int ret; ret = s->status; #ifdef DEBUG_IDE - printf("ide: read status val=%02x\n", ret); + printf("ide: read status addr=0x%x val=%02x\n", addr, ret); #endif return ret; } void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) { + IDEState *ide_if = get_ide_interface(addr); IDEState *s; int i; #ifdef DEBUG_IDE - printf("ide: write control val=%02x\n", val); + printf("ide: write control addr=0x%x val=%02x\n", addr, val); #endif /* common for both drives */ - if (!(ide_state[0].cmd & IDE_CMD_RESET) && + if (!(ide_if[0].cmd & IDE_CMD_RESET) && (val & IDE_CMD_RESET)) { /* reset low to high */ for(i = 0;i < 2; i++) { - s = &ide_state[i]; + s = &ide_if[i]; s->status = BUSY_STAT | SEEK_STAT; s->error = 0x01; } - } else if ((ide_state[0].cmd & IDE_CMD_RESET) && + } else if ((ide_if[0].cmd & IDE_CMD_RESET) && !(val & IDE_CMD_RESET)) { /* high to low */ for(i = 0;i < 2; i++) { - s = &ide_state[i]; + s = &ide_if[i]; s->status = READY_STAT; - /* set hard disk drive ID */ - s->select &= 0xf0; /* clear head */ - s->nsector = 1; - s->sector = 1; - if (s->nb_sectors == 0) { - /* no disk present */ - s->lcyl = 0x12; - s->hcyl = 0x34; - } else { - s->lcyl = 0; - s->hcyl = 0; - } + ide_set_signature(s); } } - ide_state[0].cmd = val; + ide_if[0].cmd = val; + ide_if[1].cmd = val; } void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) { - IDEState *s = ide_state[0].cur_drive; + IDEState *s = get_ide_interface(addr)->cur_drive; uint8_t *p; p = s->data_ptr; @@ -2438,10 +3078,9 @@ void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) { - IDEState *s = ide_state[0].cur_drive; + IDEState *s = get_ide_interface(addr)->cur_drive; uint8_t *p; int ret; - p = s->data_ptr; ret = tswap16(*(uint16_t *)p); p += 2; @@ -2453,7 +3092,7 @@ uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) { - IDEState *s = ide_state[0].cur_drive; + IDEState *s = get_ide_interface(addr)->cur_drive; uint8_t *p; p = s->data_ptr; @@ -2466,7 +3105,7 @@ void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) uint32_t ide_data_readl(CPUX86State *env, uint32_t addr) { - IDEState *s = ide_state[0].cur_drive; + IDEState *s = get_ide_interface(addr)->cur_drive; uint8_t *p; int ret; @@ -2482,9 +3121,10 @@ uint32_t ide_data_readl(CPUX86State *env, uint32_t addr) void ide_reset(IDEState *s) { s->mult_sectors = MAX_MULT_SECTORS; - s->status = READY_STAT; s->cur_drive = s; s->select = 0xa0; + s->status = READY_STAT; + ide_set_signature(s); } struct partition { @@ -2536,8 +3176,11 @@ void ide_guess_geometry(IDEState *s) void ide_init(void) { IDEState *s; - int i, cylinders; + int i, cylinders, iobase, iobase2; int64_t nb_sectors; + static const int ide_iobase[2] = { 0x1f0, 0x170 }; + static const int ide_iobase2[2] = { 0x3f6, 0x376 }; + static const int ide_irq[2] = { 14, 15 }; for(i = 0; i < MAX_DISKS; i++) { s = &ide_state[i]; @@ -2558,19 +3201,26 @@ void ide_init(void) s->sectors = 63; } } - s->irq = 14; + s->irq = ide_irq[i >> 1]; ide_reset(s); } - register_ioport_write(0x1f0, 8, ide_ioport_write, 1); - register_ioport_read(0x1f0, 8, ide_ioport_read, 1); - register_ioport_read(0x3f6, 1, ide_status_read, 1); - register_ioport_write(0x3f6, 1, ide_cmd_write, 1); - - /* data ports */ - register_ioport_write(0x1f0, 2, ide_data_writew, 2); - register_ioport_read(0x1f0, 2, ide_data_readw, 2); - register_ioport_write(0x1f0, 4, ide_data_writel, 4); - register_ioport_read(0x1f0, 4, ide_data_readl, 4); + for(i = 0; i < (MAX_DISKS / 2); i++) { + iobase = ide_iobase[i]; + iobase2 = ide_iobase2[i]; + ide_table[iobase >> 3] = &ide_state[2 * i]; + if (ide_iobase2[i]) + ide_table[iobase2 >> 3] = &ide_state[2 * i]; + register_ioport_write(iobase, 8, ide_ioport_write, 1); + register_ioport_read(iobase, 8, ide_ioport_read, 1); + register_ioport_read(iobase2, 1, ide_status_read, 1); + register_ioport_write(iobase2, 1, ide_cmd_write, 1); + + /* data ports */ + register_ioport_write(iobase, 2, ide_data_writew, 2); + register_ioport_read(iobase, 2, ide_data_readw, 2); + register_ioport_write(iobase, 4, ide_data_writel, 4); + register_ioport_read(iobase, 4, ide_data_readl, 4); + } } /***********************************************************/ @@ -2811,7 +3461,7 @@ void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); break; default: - fprintf(stderr, "vl: unsupported keyboard cmd=0x%02x\n", val); + fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); break; } } @@ -3458,8 +4108,10 @@ void help(void) "'disk_image' is a raw hard image image for IDE hard disk 0\n" "\n" "Standard options:\n" - "-hda file use 'file' as IDE hard disk 0 image\n" - "-hdb file use 'file' as IDE hard disk 1 image\n" + "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" + "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" + "-cdrom file use 'file' as IDE cdrom 2 image\n" + "-boot [c|d] boot on hard disk or CD-ROM\n" "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB\n" "-n script set network init script [default=%s]\n" @@ -3506,6 +4158,10 @@ struct option long_options[] = { { "kernel", 1, NULL, 0, }, { "append", 1, NULL, 0, }, { "tun-fd", 1, NULL, 0, }, + { "hdc", 1, NULL, 0, }, + { "hdd", 1, NULL, 0, }, + { "cdrom", 1, NULL, 0, }, + { "boot", 1, NULL, 0, }, { NULL, 0, NULL, 0 }, }; @@ -3601,6 +4257,23 @@ int main(int argc, char **argv) case 8: net_fd = atoi(optarg); break; + case 9: + hd_filename[2] = optarg; + break; + case 10: + hd_filename[3] = optarg; + break; + case 11: + hd_filename[2] = optarg; + ide_state[2].is_cdrom = 1; + break; + case 12: + boot_device = optarg[0]; + if (boot_device != 'c' && boot_device != 'd') { + fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device); + exit(1); + } + break; } break; case 'h': @@ -3611,7 +4284,7 @@ int main(int argc, char **argv) if (phys_ram_size <= 0) help(); if (phys_ram_size > PHYS_RAM_MAX_SIZE) { - fprintf(stderr, "vl: at most %d MB RAM can be simulated\n", + fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", PHYS_RAM_MAX_SIZE / (1024 * 1024)); exit(1); } @@ -3640,7 +4313,7 @@ int main(int argc, char **argv) linux_boot = (kernel_filename != NULL); - if (!linux_boot && hd_filename[0] == '\0') + if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0') help(); /* init debug */ @@ -3698,7 +4371,7 @@ int main(int argc, char **argv) if (hd_filename[i]) { bs_table[i] = bdrv_open(hd_filename[i], snapshot); if (!bs_table[i]) { - fprintf(stderr, "vl: could not open hard disk image '%s\n", + fprintf(stderr, "qemu: could not open hard disk image '%s\n", hd_filename[i]); exit(1); } @@ -3719,7 +4392,7 @@ int main(int argc, char **argv) /* now we can load the kernel */ ret = load_kernel(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (ret < 0) { - fprintf(stderr, "vl: could not load kernel '%s'\n", + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } @@ -3729,7 +4402,7 @@ int main(int argc, char **argv) if (initrd_filename) { initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); if (initrd_size < 0) { - fprintf(stderr, "vl: could not load initial ram disk '%s'\n", + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } @@ -3788,7 +4461,7 @@ int main(int argc, char **argv) snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); ret = load_image(buf, phys_ram_base + 0x000f0000); if (ret != 0x10000) { - fprintf(stderr, "vl: could not load PC bios '%s'\n", buf); + fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); exit(1); } -- cgit v1.2.3 From 5391d8066941d9ed0dc32c3e8e02cfcde6a0c53b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 11 Nov 2003 13:48:59 +0000 Subject: moved IDE driver to ide.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@445 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/ide.c | 1421 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 1371 +---------------------------------------------------- vl.h | 10 + 4 files changed, 1434 insertions(+), 1370 deletions(-) create mode 100644 hw/ide.c diff --git a/Makefile.target b/Makefile.target index 5bd8a8c3b..e4e4cea2d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -176,7 +176,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o block.o vga.o +VL_OBJS=vl.o block.o ide.o vga.o ifdef CONFIG_SDL VL_OBJS+=sdl.o SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm diff --git a/hw/ide.c b/hw/ide.c new file mode 100644 index 000000000..96e43da5c --- /dev/null +++ b/hw/ide.c @@ -0,0 +1,1421 @@ +/* + * QEMU IDE disk and CD-ROM Emulator + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" + +#include "vl.h" + +#define NO_THUNK_TYPE_SIZE +#include "thunk.h" + +/* debug IDE devices */ +//#define DEBUG_IDE +//#define DEBUG_IDE_ATAPI + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define SRV_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +/* Bits of HD_NSECTOR */ +#define CD 0x01 +#define IO 0x02 +#define REL 0x04 +#define TAG_MASK 0xf8 + +#define IDE_CMD_RESET 0x04 +#define IDE_CMD_DISABLE_IRQ 0x02 + +/* ATA/ATAPI Commands pre T13 Spec */ +#define WIN_NOP 0x00 +/* + * 0x01->0x02 Reserved + */ +#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ +/* + * 0x04->0x07 Reserved + */ +#define WIN_SRST 0x08 /* ATAPI soft reset command */ +#define WIN_DEVICE_RESET 0x08 +/* + * 0x09->0x0F Reserved + */ +#define WIN_RECAL 0x10 +#define WIN_RESTORE WIN_RECAL +/* + * 0x10->0x1F Reserved + */ +#define WIN_READ 0x20 /* 28-Bit */ +#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */ +#define WIN_READ_LONG 0x22 /* 28-Bit */ +#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */ +#define WIN_READ_EXT 0x24 /* 48-Bit */ +#define WIN_READDMA_EXT 0x25 /* 48-Bit */ +#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ +#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ +/* + * 0x28 + */ +#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ +/* + * 0x2A->0x2F Reserved + */ +#define WIN_WRITE 0x30 /* 28-Bit */ +#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */ +#define WIN_WRITE_LONG 0x32 /* 28-Bit */ +#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */ +#define WIN_WRITE_EXT 0x34 /* 48-Bit */ +#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ +#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ +#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ +#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ +#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ +/* + * 0x3A->0x3B Reserved + */ +#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ +/* + * 0x3D->0x3F Reserved + */ +#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ +#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */ +#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ +/* + * 0x43->0x4F Reserved + */ +#define WIN_FORMAT 0x50 +/* + * 0x51->0x5F Reserved + */ +#define WIN_INIT 0x60 +/* + * 0x61->0x5F Reserved + */ +#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */ +#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 /* set drive geometry translation */ +#define WIN_DOWNLOAD_MICROCODE 0x92 +#define WIN_STANDBYNOW2 0x94 +#define WIN_STANDBY2 0x96 +#define WIN_SETIDLE2 0x97 +#define WIN_CHECKPOWERMODE2 0x98 +#define WIN_SLEEPNOW2 0x99 +/* + * 0x9A VENDOR + */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ +#define WIN_QUEUED_SERVICE 0xA2 +#define WIN_SMART 0xB0 /* self-monitoring and reporting */ +#define CFA_ERASE_SECTORS 0xC0 +#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ +#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ +#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ +#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ +#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ +#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */ +#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ +#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ +#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ +#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ +#define WIN_GETMEDIASTATUS 0xDA +#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */ +#define WIN_POSTBOOT 0xDC +#define WIN_PREBOOT 0xDD +#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ +#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ +#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ +#define WIN_SETIDLE1 0xE3 +#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEPNOW1 0xE6 +#define WIN_FLUSH_CACHE 0xE7 +#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ +#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */ + /* SET_FEATURES 0x22 or 0xDD */ +#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ +#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ +#define WIN_MEDIAEJECT 0xED +#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ +#define WIN_SETFEATURES 0xEF /* set special drive features */ +#define EXABYTE_ENABLE_NEST 0xF0 +#define WIN_SECURITY_SET_PASS 0xF1 +#define WIN_SECURITY_UNLOCK 0xF2 +#define WIN_SECURITY_ERASE_PREPARE 0xF3 +#define WIN_SECURITY_ERASE_UNIT 0xF4 +#define WIN_SECURITY_FREEZE_LOCK 0xF5 +#define WIN_SECURITY_DISABLE 0xF6 +#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ +#define WIN_SET_MAX 0xF9 +#define DISABLE_SEAGATE 0xFB + +/* set to 1 set disable mult support */ +#define MAX_MULT_SECTORS 8 + +/* ATAPI defines */ + +#define ATAPI_PACKET_SIZE 12 + +/* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +#define GPCMD_BLANK 0xa1 +#define GPCMD_CLOSE_TRACK 0x5b +#define GPCMD_FLUSH_CACHE 0x35 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_GET_PERFORMANCE 0xac +#define GPCMD_INQUIRY 0x12 +#define GPCMD_LOAD_UNLOAD 0xa6 +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TI 0x48 +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define GPCMD_READ_10 0x28 +#define GPCMD_READ_12 0xa8 +#define GPCMD_READ_CDVD_CAPACITY 0x25 +#define GPCMD_READ_CD 0xbe +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_READ_DISC_INFO 0x51 +#define GPCMD_READ_DVD_STRUCTURE 0xad +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_READ_TRACK_RZONE_INFO 0x52 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_REPAIR_RZONE_TRACK 0x58 +#define GPCMD_REPORT_KEY 0xa4 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_RESERVE_RZONE_TRACK 0x53 +#define GPCMD_SCAN 0xba +#define GPCMD_SEEK 0x2b +#define GPCMD_SEND_DVD_STRUCTURE 0xad +#define GPCMD_SEND_EVENT 0xa2 +#define GPCMD_SEND_KEY 0xa3 +#define GPCMD_SEND_OPC 0x54 +#define GPCMD_SET_READ_AHEAD 0xa7 +#define GPCMD_SET_STREAMING 0xb6 +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_WRITE_10 0x2a +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +/* This is listed as optional in ATAPI 2.6, but is (curiously) + * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji + * Table 377 as an MMC command for SCSi devices though... Most ATAPI + * drives support it. */ +#define GPCMD_SET_SPEED 0xbb +/* This seems to be a SCSI specific CD-ROM opcode + * to play data at track/index */ +#define GPCMD_PLAYAUDIO_TI 0x48 +/* + * From MS Media Status Notification Support Specification. For + * older drives only. + */ +#define GPCMD_GET_MEDIA_STATUS 0xda + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_WRITE_PARMS_PAGE 0x05 +#define GPMODE_AUDIO_CTL_PAGE 0x0e +#define GPMODE_POWER_PAGE 0x1a +#define GPMODE_FAULT_FAIL_PAGE 0x1c +#define GPMODE_TO_PROTECT_PAGE 0x1d +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f +/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor + * of MODE_SENSE_POWER_PAGE */ +#define GPMODE_CDROM_PAGE 0x0d + +#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ +#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ +#define ATAPI_INT_REASON_REL 0x04 +#define ATAPI_INT_REASON_TAG 0xf8 + +/* same constants as bochs */ +#define ASC_LOGICAL_BLOCK_OOR 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 + +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +struct IDEState; + +typedef void EndTransferFunc(struct IDEState *); + +typedef struct IDEState { + /* ide config */ + int is_cdrom; + int cdrom_locked; + int cylinders, heads, sectors; + int64_t nb_sectors; + int mult_sectors; + int irq; + /* ide regs */ + uint8_t feature; + uint8_t error; + uint16_t nsector; /* 0 is 256 to ease computations */ + uint8_t sector; + uint8_t lcyl; + uint8_t hcyl; + uint8_t select; + uint8_t status; + /* 0x3f6 command, only meaningful for drive 0 */ + uint8_t cmd; + /* depends on bit 4 in select, only meaningful for drive 0 */ + struct IDEState *cur_drive; + BlockDriverState *bs; + /* ATAPI specific */ + uint8_t sense_key; + uint8_t asc; + int packet_transfer_size; + int elementary_transfer_size; + int io_buffer_index; + int lba; + /* transfer handling */ + int req_nb_sectors; /* number of sectors per interrupt */ + EndTransferFunc *end_transfer_func; + uint8_t *data_ptr; + uint8_t *data_end; + uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; +} IDEState; + +IDEState ide_state[MAX_DISKS]; +IDEState *ide_table[0x400 >> 3]; + +static inline IDEState *get_ide_interface(uint32_t addr) +{ + return ide_table[addr >> 3]; +} + +static void padstr(char *str, const char *src, int len) +{ + int i, v; + for(i = 0; i < len; i++) { + if (*src) + v = *src++; + else + v = ' '; + *(char *)((long)str ^ 1) = v; + str++; + } +} + +static void ide_identify(IDEState *s) +{ + uint16_t *p; + unsigned int oldsize; + + memset(s->io_buffer, 0, 512); + p = (uint16_t *)s->io_buffer; + stw_raw(p + 0, 0x0040); + stw_raw(p + 1, s->cylinders); + stw_raw(p + 3, s->heads); + stw_raw(p + 4, 512 * s->sectors); /* sectors */ + stw_raw(p + 5, 512); /* sector size */ + stw_raw(p + 6, s->sectors); + padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ + stw_raw(p + 20, 3); /* buffer type */ + stw_raw(p + 21, 512); /* cache size in sectors */ + stw_raw(p + 22, 4); /* ecc bytes */ + padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ +#if MAX_MULT_SECTORS > 1 + stw_raw(p + 47, MAX_MULT_SECTORS); +#endif + stw_raw(p + 48, 1); /* dword I/O */ + stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ + stw_raw(p + 51, 0x200); /* PIO transfer cycle */ + stw_raw(p + 52, 0x200); /* DMA transfer cycle */ + stw_raw(p + 54, s->cylinders); + stw_raw(p + 55, s->heads); + stw_raw(p + 56, s->sectors); + oldsize = s->cylinders * s->heads * s->sectors; + stw_raw(p + 57, oldsize); + stw_raw(p + 58, oldsize >> 16); + if (s->mult_sectors) + stw_raw(p + 59, 0x100 | s->mult_sectors); + stw_raw(p + 60, s->nb_sectors); + stw_raw(p + 61, s->nb_sectors >> 16); + stw_raw(p + 80, (1 << 1) | (1 << 2)); + stw_raw(p + 82, (1 << 14)); + stw_raw(p + 83, (1 << 14)); + stw_raw(p + 84, (1 << 14)); + stw_raw(p + 85, (1 << 14)); + stw_raw(p + 86, 0); + stw_raw(p + 87, (1 << 14)); +} + +static void ide_atapi_identify(IDEState *s) +{ + uint16_t *p; + + memset(s->io_buffer, 0, 512); + p = (uint16_t *)s->io_buffer; + /* Removable CDROM, 50us response, 12 byte packets */ + stw_raw(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); + stw_raw(p + 1, s->cylinders); + stw_raw(p + 3, s->heads); + stw_raw(p + 4, 512 * s->sectors); /* sectors */ + stw_raw(p + 5, 512); /* sector size */ + stw_raw(p + 6, s->sectors); + padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ + stw_raw(p + 20, 3); /* buffer type */ + stw_raw(p + 21, 512); /* cache size in sectors */ + stw_raw(p + 22, 4); /* ecc bytes */ + padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ + stw_raw(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ + stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ + stw_raw(p + 53, 3); /* words 64-70, 54-58 valid */ + stw_raw(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ + stw_raw(p + 64, 1); /* PIO modes */ + stw_raw(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ + stw_raw(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ + stw_raw(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ + stw_raw(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ + + stw_raw(p + 71, 30); /* in ns */ + stw_raw(p + 72, 30); /* in ns */ + + stw_raw(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ +} + +static void ide_set_signature(IDEState *s) +{ + s->select &= 0xf0; /* clear head */ + /* put signature */ + s->nsector = 1; + s->sector = 1; + if (s->is_cdrom) { + s->lcyl = 0x14; + s->hcyl = 0xeb; + } else if (s->bs) { + s->lcyl = 0; + s->hcyl = 0; + } else { + s->lcyl = 0xff; + s->hcyl = 0xff; + } +} + +static inline void ide_abort_command(IDEState *s) +{ + s->status = READY_STAT | ERR_STAT; + s->error = ABRT_ERR; +} + +static inline void ide_set_irq(IDEState *s) +{ + if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { + pic_set_irq(s->irq, 1); + } +} + +/* prepare data transfer and tell what to do after */ +static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, + EndTransferFunc *end_transfer_func) +{ + s->end_transfer_func = end_transfer_func; + s->data_ptr = buf; + s->data_end = buf + size; + s->status |= DRQ_STAT; +} + +static void ide_transfer_stop(IDEState *s) +{ + s->end_transfer_func = ide_transfer_stop; + s->data_ptr = s->io_buffer; + s->data_end = s->io_buffer; + s->status &= ~DRQ_STAT; +} + +static int64_t ide_get_sector(IDEState *s) +{ + int64_t sector_num; + if (s->select & 0x40) { + /* lba */ + sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | + (s->lcyl << 8) | s->sector; + } else { + sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors + + (s->select & 0x0f) * s->sectors + + (s->sector - 1); + } + return sector_num; +} + +static void ide_set_sector(IDEState *s, int64_t sector_num) +{ + unsigned int cyl, r; + if (s->select & 0x40) { + s->select = (s->select & 0xf0) | (sector_num >> 24); + s->hcyl = (sector_num >> 16); + s->lcyl = (sector_num >> 8); + s->sector = (sector_num); + } else { + cyl = sector_num / (s->heads * s->sectors); + r = sector_num % (s->heads * s->sectors); + s->hcyl = cyl >> 8; + s->lcyl = cyl; + s->select = (s->select & 0xf0) | (r / s->sectors); + s->sector = (r % s->sectors) + 1; + } +} + +static void ide_sector_read(IDEState *s) +{ + int64_t sector_num; + int ret, n; + + s->status = READY_STAT | SEEK_STAT; + sector_num = ide_get_sector(s); + n = s->nsector; + if (n == 0) { + /* no more sector to read from disk */ + ide_transfer_stop(s); + } else { +#if defined(DEBUG_IDE) + printf("read sector=%Ld\n", sector_num); +#endif + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); + ide_set_irq(s); + ide_set_sector(s, sector_num + n); + s->nsector -= n; + } +} + +static void ide_sector_write(IDEState *s) +{ + int64_t sector_num; + int ret, n, n1; + + s->status = READY_STAT | SEEK_STAT; + sector_num = ide_get_sector(s); +#if defined(DEBUG_IDE) + printf("write sector=%Ld\n", sector_num); +#endif + n = s->nsector; + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); + s->nsector -= n; + if (s->nsector == 0) { + /* no more sector to write */ + ide_transfer_stop(s); + } else { + n1 = s->nsector; + if (n1 > s->req_nb_sectors) + n1 = s->req_nb_sectors; + ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); + } + ide_set_sector(s, sector_num + n); + ide_set_irq(s); +} + +static void ide_atapi_cmd_ok(IDEState *s) +{ + s->error = 0; + s->status = READY_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s); +} + +static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) +{ +#ifdef DEBUG_IDE_ATAPI + printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); +#endif + s->error = sense_key << 4; + s->status = READY_STAT | ERR_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + s->sense_key = sense_key; + s->asc = asc; + ide_set_irq(s); +} + +static inline void cpu_to_ube16(uint8_t *buf, int val) +{ + buf[0] = val >> 8; + buf[1] = val; +} + +static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) +{ + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; +} + +static inline int ube16_to_cpu(const uint8_t *buf) +{ + return (buf[0] << 8) | buf[1]; +} + +static inline int ube32_to_cpu(const uint8_t *buf) +{ + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + +/* The whole ATAPI transfer logic is handled in this function */ +static void ide_atapi_cmd_reply_end(IDEState *s) +{ + int byte_count_limit, size; +#ifdef DEBUG_IDE_ATAPI + printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", + s->packet_transfer_size, + s->elementary_transfer_size, + s->io_buffer_index); +#endif + if (s->packet_transfer_size <= 0) { + /* end of transfer */ + ide_transfer_stop(s); + s->status = READY_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s); +#ifdef DEBUG_IDE_ATAPI + printf("status=0x%x\n", s->status); +#endif + } else { + /* see if a new sector must be read */ + if (s->lba != -1 && s->io_buffer_index >= 2048) { + bdrv_read(s->bs, (int64_t)s->lba << 2, s->io_buffer, 4); + s->lba++; + s->io_buffer_index = 0; + } + if (s->elementary_transfer_size > 0) { + /* there are some data left to transmit in this elementary + transfer */ + size = 2048 - s->io_buffer_index; + if (size > s->elementary_transfer_size) + size = s->elementary_transfer_size; + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, + size, ide_atapi_cmd_reply_end); + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; + } else { + /* a new transfer is needed */ + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; + byte_count_limit = s->lcyl | (s->hcyl << 8); +#ifdef DEBUG_IDE_ATAPI + printf("byte_count_limit=%d\n", byte_count_limit); +#endif + if (byte_count_limit == 0xffff) + byte_count_limit--; + size = s->packet_transfer_size; + if (size > byte_count_limit) { + /* byte count limit must be even if this case */ + if (byte_count_limit & 1) + byte_count_limit--; + size = byte_count_limit; + } else { + s->lcyl = size; + s->hcyl = size >> 8; + } + s->elementary_transfer_size = size; + /* we cannot transmit more than one sector at a time */ + if (s->lba != -1) { + if (size > (2048 - s->io_buffer_index)) + size = (2048 - s->io_buffer_index); + } + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, + size, ide_atapi_cmd_reply_end); + s->packet_transfer_size -= size; + s->elementary_transfer_size -= size; + s->io_buffer_index += size; + ide_set_irq(s); +#ifdef DEBUG_IDE_ATAPI + printf("status=0x%x\n", s->status); +#endif + } + } +} + +/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ +static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) +{ + if (size > max_size) + size = max_size; + s->lba = -1; /* no sector read */ + s->packet_transfer_size = size; + s->elementary_transfer_size = 0; + s->io_buffer_index = 0; + + s->status = READY_STAT; + ide_atapi_cmd_reply_end(s); +} + +/* start a CD-CDROM read command */ +static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors) +{ +#ifdef DEBUG_IDE_ATAPI + printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); +#endif + s->lba = lba; + s->packet_transfer_size = nb_sectors * 2048; + s->elementary_transfer_size = 0; + s->io_buffer_index = 2048; + + s->status = READY_STAT; + ide_atapi_cmd_reply_end(s); +} + +/* same toc as bochs. Return -1 if error or the toc length */ +static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) +{ + uint8_t *q; + int nb_sectors, len; + + if (start_track > 1 && start_track != 0xaa) + return -1; + q = buf + 2; + *q++ = 1; + *q++ = 1; + if (start_track <= 1) { + *q++ = 0; /* reserved */ + *q++ = 0x14; /* ADR, control */ + *q++ = 1; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + *q++ = 0; /* minute */ + *q++ = 2; /* second */ + *q++ = 0; /* frame */ + } else { + /* sector 0 */ + cpu_to_ube32(q, 0); + q += 4; + } + } + /* lead out track */ + *q++ = 0; /* reserved */ + *q++ = 0x16; /* ADR, control */ + *q++ = 0xaa; /* track number */ + *q++ = 0; /* reserved */ + nb_sectors = s->nb_sectors >> 2; + if (msf) { + *q++ = 0; /* reserved */ + *q++ = ((nb_sectors + 150) / 75) / 60; + *q++ = ((nb_sectors + 150) / 75) % 60; + *q++ = (nb_sectors + 150) % 75; + } else { + cpu_to_ube32(q, nb_sectors); + q += 4; + } + len = q - buf; + cpu_to_ube16(buf, len - 2); + return len; +} + +static void ide_atapi_cmd(IDEState *s) +{ + const uint8_t *packet; + uint8_t *buf; + int max_len; + + packet = s->io_buffer; + buf = s->io_buffer; +#ifdef DEBUG_IDE_ATAPI + { + int i; + printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); + for(i = 0; i < ATAPI_PACKET_SIZE; i++) { + printf(" %02x", packet[i]); + } + printf("\n"); + } +#endif + switch(s->io_buffer[0]) { + case GPCMD_TEST_UNIT_READY: + if (s->bs) { + ide_atapi_cmd_ok(s); + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } + break; + case GPCMD_MODE_SENSE_10: + { + int action, code; + max_len = ube16_to_cpu(packet + 7); + action = packet[2] >> 6; + code = packet[2] & 0x3f; + switch(action) { + case 0: /* current values */ + switch(code) { + case 0x01: /* error recovery */ + cpu_to_ube16(&buf[0], 16 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x01; + buf[9] = 0x06; + buf[10] = 0x00; + buf[11] = 0x05; + buf[12] = 0x00; + buf[13] = 0x00; + buf[14] = 0x00; + buf[15] = 0x00; + ide_atapi_cmd_reply(s, 16, max_len); + break; + case 0x2a: + cpu_to_ube16(&buf[0], 28 + 6); + buf[2] = 0x70; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = 0; + buf[7] = 0; + + buf[8] = 0x2a; + buf[9] = 0x12; + buf[10] = 0x00; + buf[11] = 0x00; + + buf[12] = 0x70; + buf[13] = 3 << 5; + buf[14] = (1 << 0) | (1 << 3) | (1 << 5); + if (s->cdrom_locked) + buf[6] |= 1 << 1; + buf[15] = 0x00; + cpu_to_ube16(&buf[16], 706); + buf[18] = 0; + buf[19] = 2; + cpu_to_ube16(&buf[20], 512); + cpu_to_ube16(&buf[22], 706); + buf[24] = 0; + buf[25] = 0; + buf[26] = 0; + buf[27] = 0; + ide_atapi_cmd_reply(s, 28, max_len); + break; + default: + goto error_cmd; + } + break; + case 1: /* changeable values */ + goto error_cmd; + case 2: /* default values */ + goto error_cmd; + default: + case 3: /* saved values */ + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_SAVING_PARAMETERS_NOT_SUPPORTED); + break; + } + } + break; + case GPCMD_REQUEST_SENSE: + max_len = packet[4]; + memset(buf, 0, 18); + buf[0] = 0x70 | (1 << 7); + buf[2] = s->sense_key; + buf[7] = 10; + buf[12] = s->asc; + ide_atapi_cmd_reply(s, 18, max_len); + break; + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + if (s->bs) { + s->cdrom_locked = packet[4] & 1; + ide_atapi_cmd_ok(s); + } else { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } + break; + case GPCMD_READ_10: + case GPCMD_READ_12: + { + int nb_sectors, lba; + + if (!s->bs) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + if (packet[0] == GPCMD_READ_10) + nb_sectors = ube16_to_cpu(packet + 7); + else + nb_sectors = ube32_to_cpu(packet + 6); + lba = ube32_to_cpu(packet + 2); + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + break; + } + if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + break; + } + ide_atapi_cmd_read(s, lba, nb_sectors); + } + break; + case GPCMD_SEEK: + { + int lba; + if (!s->bs) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + lba = ube32_to_cpu(packet + 2); + if (((int64_t)lba << 2) > s->nb_sectors) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + break; + } + ide_atapi_cmd_ok(s); + } + break; + case GPCMD_START_STOP_UNIT: + { + int start, eject; + start = packet[4] & 1; + eject = (packet[4] >> 1) & 1; + + /* XXX: currently none implemented */ + ide_atapi_cmd_ok(s); + } + break; + case GPCMD_MECHANISM_STATUS: + { + max_len = ube16_to_cpu(packet + 8); + cpu_to_ube16(buf, 0); + /* no current LBA */ + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + buf[5] = 1; + cpu_to_ube16(buf + 6, 0); + ide_atapi_cmd_reply(s, 8, max_len); + } + break; + case GPCMD_READ_TOC_PMA_ATIP: + { + int format, msf, start_track, len; + + if (!s->bs) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + max_len = ube16_to_cpu(packet + 7); + format = packet[9] >> 6; + msf = (packet[1] >> 1) & 1; + start_track = packet[6]; + switch(format) { + case 0: + len = cdrom_read_toc(s, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; + case 1: + /* multi session : only a single session defined */ + memset(buf, 0, 12); + buf[1] = 0x0a; + buf[2] = 0x01; + buf[3] = 0x01; + ide_atapi_cmd_reply(s, 12, max_len); + break; + default: + goto error_cmd; + } + } + break; + case GPCMD_READ_CDVD_CAPACITY: + if (!s->bs) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + /* NOTE: it is really the number of sectors minus 1 */ + cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); + cpu_to_ube32(buf + 4, 2048); + ide_atapi_cmd_reply(s, 8, 8); + break; + default: + error_cmd: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } +} + +static void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + IDEState *ide_if = get_ide_interface(addr); + IDEState *s = ide_if->cur_drive; + int unit, n; + +#ifdef DEBUG_IDE + printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); +#endif + addr &= 7; + switch(addr) { + case 0: + break; + case 1: + s->feature = val; + break; + case 2: + if (val == 0) + val = 256; + s->nsector = val; + break; + case 3: + s->sector = val; + break; + case 4: + s->lcyl = val; + break; + case 5: + s->hcyl = val; + break; + case 6: + /* select drive */ + unit = (val >> 4) & 1; + s = ide_if + unit; + ide_if->cur_drive = s; + s->select = val; + break; + default: + case 7: + /* command */ +#if defined(DEBUG_IDE) + printf("ide: CMD=%02x\n", val); +#endif + switch(val) { + case WIN_IDENTIFY: + if (s->bs && !s->is_cdrom) { + ide_identify(s); + s->status = READY_STAT; + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); + } else { + if (s->is_cdrom) { + ide_set_signature(s); + } + ide_abort_command(s); + } + ide_set_irq(s); + break; + case WIN_SPECIFY: + case WIN_RECAL: + s->status = READY_STAT; + ide_set_irq(s); + break; + case WIN_SETMULT: + if (s->nsector > MAX_MULT_SECTORS || + s->nsector == 0 || + (s->nsector & (s->nsector - 1)) != 0) { + ide_abort_command(s); + } else { + s->mult_sectors = s->nsector; + s->status = READY_STAT; + } + ide_set_irq(s); + break; + case WIN_READ: + case WIN_READ_ONCE: + s->req_nb_sectors = 1; + ide_sector_read(s); + break; + case WIN_WRITE: + case WIN_WRITE_ONCE: + s->status = SEEK_STAT; + s->req_nb_sectors = 1; + ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); + break; + case WIN_MULTREAD: + if (!s->mult_sectors) + goto abort_cmd; + s->req_nb_sectors = s->mult_sectors; + ide_sector_read(s); + break; + case WIN_MULTWRITE: + if (!s->mult_sectors) + goto abort_cmd; + s->status = SEEK_STAT; + s->req_nb_sectors = s->mult_sectors; + n = s->nsector; + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); + break; + case WIN_READ_NATIVE_MAX: + ide_set_sector(s, s->nb_sectors - 1); + s->status = READY_STAT; + ide_set_irq(s); + break; + + /* ATAPI commands */ + case WIN_PIDENTIFY: + if (s->is_cdrom) { + ide_atapi_identify(s); + s->status = READY_STAT; + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); + } else { + ide_abort_command(s); + } + ide_set_irq(s); + break; + case WIN_SRST: + if (!s->is_cdrom) + goto abort_cmd; + ide_set_signature(s); + s->status = READY_STAT; + s->error = 0x01; + break; + case WIN_PACKETCMD: + if (!s->is_cdrom) + goto abort_cmd; + /* DMA or overlapping commands not supported */ + if ((s->feature & 0x03) != 0) + goto abort_cmd; + s->nsector = 1; + ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, + ide_atapi_cmd); + break; + default: + abort_cmd: + ide_abort_command(s); + ide_set_irq(s); + break; + } + } +} + +static uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr1) +{ + IDEState *s = get_ide_interface(addr1)->cur_drive; + uint32_t addr; + int ret; + + addr = addr1 & 7; + switch(addr) { + case 0: + ret = 0xff; + break; + case 1: + ret = s->error; + break; + case 2: + ret = s->nsector & 0xff; + break; + case 3: + ret = s->sector; + break; + case 4: + ret = s->lcyl; + break; + case 5: + ret = s->hcyl; + break; + case 6: + ret = s->select; + break; + default: + case 7: + ret = s->status; + pic_set_irq(s->irq, 0); + break; + } +#ifdef DEBUG_IDE + printf("ide: read addr=0x%x val=%02x\n", addr1, ret); +#endif + return ret; +} + +static uint32_t ide_status_read(CPUX86State *env, uint32_t addr) +{ + IDEState *s = get_ide_interface(addr)->cur_drive; + int ret; + ret = s->status; +#ifdef DEBUG_IDE + printf("ide: read status addr=0x%x val=%02x\n", addr, ret); +#endif + return ret; +} + +static void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + IDEState *ide_if = get_ide_interface(addr); + IDEState *s; + int i; + +#ifdef DEBUG_IDE + printf("ide: write control addr=0x%x val=%02x\n", addr, val); +#endif + /* common for both drives */ + if (!(ide_if[0].cmd & IDE_CMD_RESET) && + (val & IDE_CMD_RESET)) { + /* reset low to high */ + for(i = 0;i < 2; i++) { + s = &ide_if[i]; + s->status = BUSY_STAT | SEEK_STAT; + s->error = 0x01; + } + } else if ((ide_if[0].cmd & IDE_CMD_RESET) && + !(val & IDE_CMD_RESET)) { + /* high to low */ + for(i = 0;i < 2; i++) { + s = &ide_if[i]; + s->status = READY_STAT; + ide_set_signature(s); + } + } + + ide_if[0].cmd = val; + ide_if[1].cmd = val; +} + +static void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) +{ + IDEState *s = get_ide_interface(addr)->cur_drive; + uint8_t *p; + + p = s->data_ptr; + *(uint16_t *)p = tswap16(val); + p += 2; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); +} + +static uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) +{ + IDEState *s = get_ide_interface(addr)->cur_drive; + uint8_t *p; + int ret; + p = s->data_ptr; + ret = tswap16(*(uint16_t *)p); + p += 2; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); + return ret; +} + +static void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) +{ + IDEState *s = get_ide_interface(addr)->cur_drive; + uint8_t *p; + + p = s->data_ptr; + *(uint32_t *)p = tswap32(val); + p += 4; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); +} + +static uint32_t ide_data_readl(CPUX86State *env, uint32_t addr) +{ + IDEState *s = get_ide_interface(addr)->cur_drive; + uint8_t *p; + int ret; + + p = s->data_ptr; + ret = tswap32(*(uint32_t *)p); + p += 4; + s->data_ptr = p; + if (p >= s->data_end) + s->end_transfer_func(s); + return ret; +} + +static void ide_reset(IDEState *s) +{ + s->mult_sectors = MAX_MULT_SECTORS; + s->cur_drive = s; + s->select = 0xa0; + s->status = READY_STAT; + ide_set_signature(s); +} + +struct partition { + uint8_t boot_ind; /* 0x80 - active */ + uint8_t head; /* starting head */ + uint8_t sector; /* starting sector */ + uint8_t cyl; /* starting cylinder */ + uint8_t sys_ind; /* What partition type */ + uint8_t end_head; /* end head */ + uint8_t end_sector; /* end sector */ + uint8_t end_cyl; /* end cylinder */ + uint32_t start_sect; /* starting sector counting from 0 */ + uint32_t nr_sects; /* nr of sectors in partition */ +} __attribute__((packed)); + +/* try to guess the IDE geometry from the MSDOS partition table */ +static void ide_guess_geometry(IDEState *s) +{ + uint8_t buf[512]; + int ret, i; + struct partition *p; + uint32_t nr_sects; + + if (s->cylinders != 0) + return; + ret = bdrv_read(s->bs, 0, buf, 1); + if (ret < 0) + return; + /* test msdos magic */ + if (buf[510] != 0x55 || buf[511] != 0xaa) + return; + for(i = 0; i < 4; i++) { + p = ((struct partition *)(buf + 0x1be)) + i; + nr_sects = tswap32(p->nr_sects); + if (nr_sects && p->end_head) { + /* We make the assumption that the partition terminates on + a cylinder boundary */ + s->heads = p->end_head + 1; + s->sectors = p->end_sector & 63; + s->cylinders = s->nb_sectors / (s->heads * s->sectors); +#if 0 + printf("guessed partition: CHS=%d %d %d\n", + s->cylinders, s->heads, s->sectors); +#endif + } + } +} + +void ide_init(void) +{ + IDEState *s; + int i, cylinders, iobase, iobase2; + int64_t nb_sectors; + static const int ide_iobase[2] = { 0x1f0, 0x170 }; + static const int ide_iobase2[2] = { 0x3f6, 0x376 }; + static const int ide_irq[2] = { 14, 15 }; + + for(i = 0; i < MAX_DISKS; i++) { + s = &ide_state[i]; + s->bs = bs_table[i]; + if (s->bs) { + bdrv_get_geometry(s->bs, &nb_sectors); + s->nb_sectors = nb_sectors; + ide_guess_geometry(s); + if (s->cylinders == 0) { + /* if no geometry, use a LBA compatible one */ + cylinders = nb_sectors / (16 * 63); + if (cylinders > 16383) + cylinders = 16383; + else if (cylinders < 2) + cylinders = 2; + s->cylinders = cylinders; + s->heads = 16; + s->sectors = 63; + } + } + s->irq = ide_irq[i >> 1]; + ide_reset(s); + } + for(i = 0; i < (MAX_DISKS / 2); i++) { + iobase = ide_iobase[i]; + iobase2 = ide_iobase2[i]; + ide_table[iobase >> 3] = &ide_state[2 * i]; + if (ide_iobase2[i]) + ide_table[iobase2 >> 3] = &ide_state[2 * i]; + register_ioport_write(iobase, 8, ide_ioport_write, 1); + register_ioport_read(iobase, 8, ide_ioport_read, 1); + register_ioport_read(iobase2, 1, ide_status_read, 1); + register_ioport_write(iobase2, 1, ide_cmd_write, 1); + + /* data ports */ + register_ioport_write(iobase, 2, ide_data_writew, 2); + register_ioport_read(iobase, 2, ide_data_readw, 2); + register_ioport_write(iobase, 4, ide_data_writel, 4); + register_ioport_read(iobase, 4, ide_data_readl, 4); + } +} + +void ide_set_geometry(int n, int cyls, int heads, int secs) +{ + ide_state[n].cylinders = cyls; + ide_state[n].heads = heads; + ide_state[n].sectors = secs; +} + +void ide_set_cdrom(int n, int is_cdrom) +{ + ide_state[n].is_cdrom = is_cdrom; +} diff --git a/vl.c b/vl.c index 053f3e90f..ff7ff89b9 100644 --- a/vl.c +++ b/vl.c @@ -61,10 +61,6 @@ /* output Bochs bios info messages */ //#define DEBUG_BIOS -/* debug IDE devices */ -//#define DEBUG_IDE -//#define DEBUG_IDE_ATAPI - /* debug PIC */ //#define DEBUG_PIC @@ -86,8 +82,6 @@ #define GUI_REFRESH_INTERVAL 30 -#define MAX_DISKS 4 - /* from plex86 (BSD license) */ struct __attribute__ ((packed)) linux_params { // For 0x00..0x3f, see 'struct screen_info' in linux/include/linux/tty.h. @@ -1864,1365 +1858,6 @@ void ne2000_init(void) ne2000_reset(); } -/***********************************************************/ -/* ide emulation */ - -/* Bits of HD_STATUS */ -#define ERR_STAT 0x01 -#define INDEX_STAT 0x02 -#define ECC_STAT 0x04 /* Corrected error */ -#define DRQ_STAT 0x08 -#define SEEK_STAT 0x10 -#define SRV_STAT 0x10 -#define WRERR_STAT 0x20 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits for HD_ERROR */ -#define MARK_ERR 0x01 /* Bad address mark */ -#define TRK0_ERR 0x02 /* couldn't find track 0 */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* media change request */ -#define ID_ERR 0x10 /* ID field not found */ -#define MC_ERR 0x20 /* media changed */ -#define ECC_ERR 0x40 /* Uncorrectable ECC error */ -#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ -#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ - -/* Bits of HD_NSECTOR */ -#define CD 0x01 -#define IO 0x02 -#define REL 0x04 -#define TAG_MASK 0xf8 - -#define IDE_CMD_RESET 0x04 -#define IDE_CMD_DISABLE_IRQ 0x02 - -/* ATA/ATAPI Commands pre T13 Spec */ -#define WIN_NOP 0x00 -/* - * 0x01->0x02 Reserved - */ -#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ -/* - * 0x04->0x07 Reserved - */ -#define WIN_SRST 0x08 /* ATAPI soft reset command */ -#define WIN_DEVICE_RESET 0x08 -/* - * 0x09->0x0F Reserved - */ -#define WIN_RECAL 0x10 -#define WIN_RESTORE WIN_RECAL -/* - * 0x10->0x1F Reserved - */ -#define WIN_READ 0x20 /* 28-Bit */ -#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */ -#define WIN_READ_LONG 0x22 /* 28-Bit */ -#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */ -#define WIN_READ_EXT 0x24 /* 48-Bit */ -#define WIN_READDMA_EXT 0x25 /* 48-Bit */ -#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ -#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ -/* - * 0x28 - */ -#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ -/* - * 0x2A->0x2F Reserved - */ -#define WIN_WRITE 0x30 /* 28-Bit */ -#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */ -#define WIN_WRITE_LONG 0x32 /* 28-Bit */ -#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */ -#define WIN_WRITE_EXT 0x34 /* 48-Bit */ -#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ -#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ -#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ -#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ -#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ -/* - * 0x3A->0x3B Reserved - */ -#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ -/* - * 0x3D->0x3F Reserved - */ -#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ -#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */ -#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ -/* - * 0x43->0x4F Reserved - */ -#define WIN_FORMAT 0x50 -/* - * 0x51->0x5F Reserved - */ -#define WIN_INIT 0x60 -/* - * 0x61->0x5F Reserved - */ -#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */ -#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ -#define WIN_DIAGNOSE 0x90 -#define WIN_SPECIFY 0x91 /* set drive geometry translation */ -#define WIN_DOWNLOAD_MICROCODE 0x92 -#define WIN_STANDBYNOW2 0x94 -#define WIN_STANDBY2 0x96 -#define WIN_SETIDLE2 0x97 -#define WIN_CHECKPOWERMODE2 0x98 -#define WIN_SLEEPNOW2 0x99 -/* - * 0x9A VENDOR - */ -#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ -#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ -#define WIN_QUEUED_SERVICE 0xA2 -#define WIN_SMART 0xB0 /* self-monitoring and reporting */ -#define CFA_ERASE_SECTORS 0xC0 -#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ -#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ -#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ -#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ -#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ -#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */ -#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ -#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ -#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ -#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ -#define WIN_GETMEDIASTATUS 0xDA -#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */ -#define WIN_POSTBOOT 0xDC -#define WIN_PREBOOT 0xDD -#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ -#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ -#define WIN_STANDBYNOW1 0xE0 -#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ -#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ -#define WIN_SETIDLE1 0xE3 -#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ -#define WIN_CHECKPOWERMODE1 0xE5 -#define WIN_SLEEPNOW1 0xE6 -#define WIN_FLUSH_CACHE 0xE7 -#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ -#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */ - /* SET_FEATURES 0x22 or 0xDD */ -#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ -#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ -#define WIN_MEDIAEJECT 0xED -#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ -#define WIN_SETFEATURES 0xEF /* set special drive features */ -#define EXABYTE_ENABLE_NEST 0xF0 -#define WIN_SECURITY_SET_PASS 0xF1 -#define WIN_SECURITY_UNLOCK 0xF2 -#define WIN_SECURITY_ERASE_PREPARE 0xF3 -#define WIN_SECURITY_ERASE_UNIT 0xF4 -#define WIN_SECURITY_FREEZE_LOCK 0xF5 -#define WIN_SECURITY_DISABLE 0xF6 -#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ -#define WIN_SET_MAX 0xF9 -#define DISABLE_SEAGATE 0xFB - -/* set to 1 set disable mult support */ -#define MAX_MULT_SECTORS 8 - -/* ATAPI defines */ - -#define ATAPI_PACKET_SIZE 12 - -/* The generic packet command opcodes for CD/DVD Logical Units, - * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -#define GPCMD_BLANK 0xa1 -#define GPCMD_CLOSE_TRACK 0x5b -#define GPCMD_FLUSH_CACHE 0x35 -#define GPCMD_FORMAT_UNIT 0x04 -#define GPCMD_GET_CONFIGURATION 0x46 -#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a -#define GPCMD_GET_PERFORMANCE 0xac -#define GPCMD_INQUIRY 0x12 -#define GPCMD_LOAD_UNLOAD 0xa6 -#define GPCMD_MECHANISM_STATUS 0xbd -#define GPCMD_MODE_SELECT_10 0x55 -#define GPCMD_MODE_SENSE_10 0x5a -#define GPCMD_PAUSE_RESUME 0x4b -#define GPCMD_PLAY_AUDIO_10 0x45 -#define GPCMD_PLAY_AUDIO_MSF 0x47 -#define GPCMD_PLAY_AUDIO_TI 0x48 -#define GPCMD_PLAY_CD 0xbc -#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e -#define GPCMD_READ_10 0x28 -#define GPCMD_READ_12 0xa8 -#define GPCMD_READ_CDVD_CAPACITY 0x25 -#define GPCMD_READ_CD 0xbe -#define GPCMD_READ_CD_MSF 0xb9 -#define GPCMD_READ_DISC_INFO 0x51 -#define GPCMD_READ_DVD_STRUCTURE 0xad -#define GPCMD_READ_FORMAT_CAPACITIES 0x23 -#define GPCMD_READ_HEADER 0x44 -#define GPCMD_READ_TRACK_RZONE_INFO 0x52 -#define GPCMD_READ_SUBCHANNEL 0x42 -#define GPCMD_READ_TOC_PMA_ATIP 0x43 -#define GPCMD_REPAIR_RZONE_TRACK 0x58 -#define GPCMD_REPORT_KEY 0xa4 -#define GPCMD_REQUEST_SENSE 0x03 -#define GPCMD_RESERVE_RZONE_TRACK 0x53 -#define GPCMD_SCAN 0xba -#define GPCMD_SEEK 0x2b -#define GPCMD_SEND_DVD_STRUCTURE 0xad -#define GPCMD_SEND_EVENT 0xa2 -#define GPCMD_SEND_KEY 0xa3 -#define GPCMD_SEND_OPC 0x54 -#define GPCMD_SET_READ_AHEAD 0xa7 -#define GPCMD_SET_STREAMING 0xb6 -#define GPCMD_START_STOP_UNIT 0x1b -#define GPCMD_STOP_PLAY_SCAN 0x4e -#define GPCMD_TEST_UNIT_READY 0x00 -#define GPCMD_VERIFY_10 0x2f -#define GPCMD_WRITE_10 0x2a -#define GPCMD_WRITE_AND_VERIFY_10 0x2e -/* This is listed as optional in ATAPI 2.6, but is (curiously) - * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji - * Table 377 as an MMC command for SCSi devices though... Most ATAPI - * drives support it. */ -#define GPCMD_SET_SPEED 0xbb -/* This seems to be a SCSI specific CD-ROM opcode - * to play data at track/index */ -#define GPCMD_PLAYAUDIO_TI 0x48 -/* - * From MS Media Status Notification Support Specification. For - * older drives only. - */ -#define GPCMD_GET_MEDIA_STATUS 0xda - -/* Mode page codes for mode sense/set */ -#define GPMODE_R_W_ERROR_PAGE 0x01 -#define GPMODE_WRITE_PARMS_PAGE 0x05 -#define GPMODE_AUDIO_CTL_PAGE 0x0e -#define GPMODE_POWER_PAGE 0x1a -#define GPMODE_FAULT_FAIL_PAGE 0x1c -#define GPMODE_TO_PROTECT_PAGE 0x1d -#define GPMODE_CAPABILITIES_PAGE 0x2a -#define GPMODE_ALL_PAGES 0x3f -/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor - * of MODE_SENSE_POWER_PAGE */ -#define GPMODE_CDROM_PAGE 0x0d - -#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ -#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ -#define ATAPI_INT_REASON_REL 0x04 -#define ATAPI_INT_REASON_TAG 0xf8 - -/* same constants as bochs */ -#define ASC_LOGICAL_BLOCK_OOR 0x21 -#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 -#define ASC_MEDIUM_NOT_PRESENT 0x3a -#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 - -#define SENSE_NONE 0 -#define SENSE_NOT_READY 2 -#define SENSE_ILLEGAL_REQUEST 5 -#define SENSE_UNIT_ATTENTION 6 - -struct IDEState; - -typedef void EndTransferFunc(struct IDEState *); - -typedef struct IDEState { - /* ide config */ - int is_cdrom; - int cdrom_locked; - int cylinders, heads, sectors; - int64_t nb_sectors; - int mult_sectors; - int irq; - /* ide regs */ - uint8_t feature; - uint8_t error; - uint16_t nsector; /* 0 is 256 to ease computations */ - uint8_t sector; - uint8_t lcyl; - uint8_t hcyl; - uint8_t select; - uint8_t status; - /* 0x3f6 command, only meaningful for drive 0 */ - uint8_t cmd; - /* depends on bit 4 in select, only meaningful for drive 0 */ - struct IDEState *cur_drive; - BlockDriverState *bs; - /* ATAPI specific */ - uint8_t sense_key; - uint8_t asc; - int packet_transfer_size; - int elementary_transfer_size; - int io_buffer_index; - int lba; - /* transfer handling */ - int req_nb_sectors; /* number of sectors per interrupt */ - EndTransferFunc *end_transfer_func; - uint8_t *data_ptr; - uint8_t *data_end; - uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; -} IDEState; - -IDEState ide_state[MAX_DISKS]; -IDEState *ide_table[0x400 >> 3]; - -static inline IDEState *get_ide_interface(uint32_t addr) -{ - return ide_table[addr >> 3]; -} - -static void padstr(char *str, const char *src, int len) -{ - int i, v; - for(i = 0; i < len; i++) { - if (*src) - v = *src++; - else - v = ' '; - *(char *)((long)str ^ 1) = v; - str++; - } -} - -static void ide_identify(IDEState *s) -{ - uint16_t *p; - unsigned int oldsize; - - memset(s->io_buffer, 0, 512); - p = (uint16_t *)s->io_buffer; - stw_raw(p + 0, 0x0040); - stw_raw(p + 1, s->cylinders); - stw_raw(p + 3, s->heads); - stw_raw(p + 4, 512 * s->sectors); /* sectors */ - stw_raw(p + 5, 512); /* sector size */ - stw_raw(p + 6, s->sectors); - padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ - stw_raw(p + 20, 3); /* buffer type */ - stw_raw(p + 21, 512); /* cache size in sectors */ - stw_raw(p + 22, 4); /* ecc bytes */ - padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ - padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ -#if MAX_MULT_SECTORS > 1 - stw_raw(p + 47, MAX_MULT_SECTORS); -#endif - stw_raw(p + 48, 1); /* dword I/O */ - stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ - stw_raw(p + 51, 0x200); /* PIO transfer cycle */ - stw_raw(p + 52, 0x200); /* DMA transfer cycle */ - stw_raw(p + 54, s->cylinders); - stw_raw(p + 55, s->heads); - stw_raw(p + 56, s->sectors); - oldsize = s->cylinders * s->heads * s->sectors; - stw_raw(p + 57, oldsize); - stw_raw(p + 58, oldsize >> 16); - if (s->mult_sectors) - stw_raw(p + 59, 0x100 | s->mult_sectors); - stw_raw(p + 60, s->nb_sectors); - stw_raw(p + 61, s->nb_sectors >> 16); - stw_raw(p + 80, (1 << 1) | (1 << 2)); - stw_raw(p + 82, (1 << 14)); - stw_raw(p + 83, (1 << 14)); - stw_raw(p + 84, (1 << 14)); - stw_raw(p + 85, (1 << 14)); - stw_raw(p + 86, 0); - stw_raw(p + 87, (1 << 14)); -} - -static void ide_atapi_identify(IDEState *s) -{ - uint16_t *p; - - memset(s->io_buffer, 0, 512); - p = (uint16_t *)s->io_buffer; - /* Removable CDROM, 50us response, 12 byte packets */ - stw_raw(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); - stw_raw(p + 1, s->cylinders); - stw_raw(p + 3, s->heads); - stw_raw(p + 4, 512 * s->sectors); /* sectors */ - stw_raw(p + 5, 512); /* sector size */ - stw_raw(p + 6, s->sectors); - padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ - stw_raw(p + 20, 3); /* buffer type */ - stw_raw(p + 21, 512); /* cache size in sectors */ - stw_raw(p + 22, 4); /* ecc bytes */ - padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ - padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ - stw_raw(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ - stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ - stw_raw(p + 53, 3); /* words 64-70, 54-58 valid */ - stw_raw(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ - stw_raw(p + 64, 1); /* PIO modes */ - stw_raw(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ - stw_raw(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ - stw_raw(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ - stw_raw(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ - - stw_raw(p + 71, 30); /* in ns */ - stw_raw(p + 72, 30); /* in ns */ - - stw_raw(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ -} - -static void ide_set_signature(IDEState *s) -{ - s->select &= 0xf0; /* clear head */ - /* put signature */ - s->nsector = 1; - s->sector = 1; - if (s->is_cdrom) { - s->lcyl = 0x14; - s->hcyl = 0xeb; - } else if (s->bs) { - s->lcyl = 0; - s->hcyl = 0; - } else { - s->lcyl = 0xff; - s->hcyl = 0xff; - } -} - -static inline void ide_abort_command(IDEState *s) -{ - s->status = READY_STAT | ERR_STAT; - s->error = ABRT_ERR; -} - -static inline void ide_set_irq(IDEState *s) -{ - if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { - pic_set_irq(s->irq, 1); - } -} - -/* prepare data transfer and tell what to do after */ -static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, - EndTransferFunc *end_transfer_func) -{ - s->end_transfer_func = end_transfer_func; - s->data_ptr = buf; - s->data_end = buf + size; - s->status |= DRQ_STAT; -} - -static void ide_transfer_stop(IDEState *s) -{ - s->end_transfer_func = ide_transfer_stop; - s->data_ptr = s->io_buffer; - s->data_end = s->io_buffer; - s->status &= ~DRQ_STAT; -} - -static int64_t ide_get_sector(IDEState *s) -{ - int64_t sector_num; - if (s->select & 0x40) { - /* lba */ - sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | - (s->lcyl << 8) | s->sector; - } else { - sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors + - (s->select & 0x0f) * s->sectors + - (s->sector - 1); - } - return sector_num; -} - -static void ide_set_sector(IDEState *s, int64_t sector_num) -{ - unsigned int cyl, r; - if (s->select & 0x40) { - s->select = (s->select & 0xf0) | (sector_num >> 24); - s->hcyl = (sector_num >> 16); - s->lcyl = (sector_num >> 8); - s->sector = (sector_num); - } else { - cyl = sector_num / (s->heads * s->sectors); - r = sector_num % (s->heads * s->sectors); - s->hcyl = cyl >> 8; - s->lcyl = cyl; - s->select = (s->select & 0xf0) | (r / s->sectors); - s->sector = (r % s->sectors) + 1; - } -} - -static void ide_sector_read(IDEState *s) -{ - int64_t sector_num; - int ret, n; - - s->status = READY_STAT | SEEK_STAT; - sector_num = ide_get_sector(s); - n = s->nsector; - if (n == 0) { - /* no more sector to read from disk */ - ide_transfer_stop(s); - } else { -#if defined(DEBUG_IDE) - printf("read sector=%Ld\n", sector_num); -#endif - if (n > s->req_nb_sectors) - n = s->req_nb_sectors; - ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); - ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); - ide_set_irq(s); - ide_set_sector(s, sector_num + n); - s->nsector -= n; - } -} - -static void ide_sector_write(IDEState *s) -{ - int64_t sector_num; - int ret, n, n1; - - s->status = READY_STAT | SEEK_STAT; - sector_num = ide_get_sector(s); -#if defined(DEBUG_IDE) - printf("write sector=%Ld\n", sector_num); -#endif - n = s->nsector; - if (n > s->req_nb_sectors) - n = s->req_nb_sectors; - ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); - s->nsector -= n; - if (s->nsector == 0) { - /* no more sector to write */ - ide_transfer_stop(s); - } else { - n1 = s->nsector; - if (n1 > s->req_nb_sectors) - n1 = s->req_nb_sectors; - ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); - } - ide_set_sector(s, sector_num + n); - ide_set_irq(s); -} - -static void ide_atapi_cmd_ok(IDEState *s) -{ - s->error = 0; - s->status = READY_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_set_irq(s); -} - -static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) -{ -#ifdef DEBUG_IDE_ATAPI - printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); -#endif - s->error = sense_key << 4; - s->status = READY_STAT | ERR_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - s->sense_key = sense_key; - s->asc = asc; - ide_set_irq(s); -} - -static inline void cpu_to_ube16(uint8_t *buf, int val) -{ - buf[0] = val >> 8; - buf[1] = val; -} - -static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) -{ - buf[0] = val >> 24; - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val; -} - -static inline int ube16_to_cpu(const uint8_t *buf) -{ - return (buf[0] << 8) | buf[1]; -} - -static inline int ube32_to_cpu(const uint8_t *buf) -{ - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - -/* The whole ATAPI transfer logic is handled in this function */ -static void ide_atapi_cmd_reply_end(IDEState *s) -{ - int byte_count_limit, size; -#ifdef DEBUG_IDE_ATAPI - printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", - s->packet_transfer_size, - s->elementary_transfer_size, - s->io_buffer_index); -#endif - if (s->packet_transfer_size <= 0) { - /* end of transfer */ - ide_transfer_stop(s); - s->status = READY_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_set_irq(s); -#ifdef DEBUG_IDE_ATAPI - printf("status=0x%x\n", s->status); -#endif - } else { - /* see if a new sector must be read */ - if (s->lba != -1 && s->io_buffer_index >= 2048) { - bdrv_read(s->bs, (int64_t)s->lba << 2, s->io_buffer, 4); - s->lba++; - s->io_buffer_index = 0; - } - if (s->elementary_transfer_size > 0) { - /* there are some data left to transmit in this elementary - transfer */ - size = 2048 - s->io_buffer_index; - if (size > s->elementary_transfer_size) - size = s->elementary_transfer_size; - ide_transfer_start(s, s->io_buffer + s->io_buffer_index, - size, ide_atapi_cmd_reply_end); - s->packet_transfer_size -= size; - s->elementary_transfer_size -= size; - s->io_buffer_index += size; - } else { - /* a new transfer is needed */ - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; - byte_count_limit = s->lcyl | (s->hcyl << 8); -#ifdef DEBUG_IDE_ATAPI - printf("byte_count_limit=%d\n", byte_count_limit); -#endif - if (byte_count_limit == 0xffff) - byte_count_limit--; - size = s->packet_transfer_size; - if (size > byte_count_limit) { - /* byte count limit must be even if this case */ - if (byte_count_limit & 1) - byte_count_limit--; - size = byte_count_limit; - } else { - s->lcyl = size; - s->hcyl = size >> 8; - } - s->elementary_transfer_size = size; - /* we cannot transmit more than one sector at a time */ - if (s->lba != -1) { - if (size > (2048 - s->io_buffer_index)) - size = (2048 - s->io_buffer_index); - } - ide_transfer_start(s, s->io_buffer + s->io_buffer_index, - size, ide_atapi_cmd_reply_end); - s->packet_transfer_size -= size; - s->elementary_transfer_size -= size; - s->io_buffer_index += size; - ide_set_irq(s); -#ifdef DEBUG_IDE_ATAPI - printf("status=0x%x\n", s->status); -#endif - } - } -} - -/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ -static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) -{ - if (size > max_size) - size = max_size; - s->lba = -1; /* no sector read */ - s->packet_transfer_size = size; - s->elementary_transfer_size = 0; - s->io_buffer_index = 0; - - s->status = READY_STAT; - ide_atapi_cmd_reply_end(s); -} - -/* start a CD-CDROM read command */ -static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors) -{ -#ifdef DEBUG_IDE_ATAPI - printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); -#endif - s->lba = lba; - s->packet_transfer_size = nb_sectors * 2048; - s->elementary_transfer_size = 0; - s->io_buffer_index = 2048; - - s->status = READY_STAT; - ide_atapi_cmd_reply_end(s); -} - -/* same toc as bochs. Return -1 if error or the toc length */ -static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) -{ - uint8_t *q; - int nb_sectors, len; - - if (start_track > 1 && start_track != 0xaa) - return -1; - q = buf + 2; - *q++ = 1; - *q++ = 1; - if (start_track <= 1) { - *q++ = 0; /* reserved */ - *q++ = 0x14; /* ADR, control */ - *q++ = 1; /* track number */ - *q++ = 0; /* reserved */ - if (msf) { - *q++ = 0; /* reserved */ - *q++ = 0; /* minute */ - *q++ = 2; /* second */ - *q++ = 0; /* frame */ - } else { - /* sector 0 */ - cpu_to_ube32(q, 0); - q += 4; - } - } - /* lead out track */ - *q++ = 0; /* reserved */ - *q++ = 0x16; /* ADR, control */ - *q++ = 0xaa; /* track number */ - *q++ = 0; /* reserved */ - nb_sectors = s->nb_sectors >> 2; - if (msf) { - *q++ = 0; /* reserved */ - *q++ = ((nb_sectors + 150) / 75) / 60; - *q++ = ((nb_sectors + 150) / 75) % 60; - *q++ = (nb_sectors + 150) % 75; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - -static void ide_atapi_cmd(IDEState *s) -{ - const uint8_t *packet; - uint8_t *buf; - int max_len; - - packet = s->io_buffer; - buf = s->io_buffer; -#ifdef DEBUG_IDE_ATAPI - { - int i; - printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); - for(i = 0; i < ATAPI_PACKET_SIZE; i++) { - printf(" %02x", packet[i]); - } - printf("\n"); - } -#endif - switch(s->io_buffer[0]) { - case GPCMD_TEST_UNIT_READY: - if (s->bs) { - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } - break; - case GPCMD_MODE_SENSE_10: - { - int action, code; - max_len = ube16_to_cpu(packet + 7); - action = packet[2] >> 6; - code = packet[2] & 0x3f; - switch(action) { - case 0: /* current values */ - switch(code) { - case 0x01: /* error recovery */ - cpu_to_ube16(&buf[0], 16 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - buf[8] = 0x01; - buf[9] = 0x06; - buf[10] = 0x00; - buf[11] = 0x05; - buf[12] = 0x00; - buf[13] = 0x00; - buf[14] = 0x00; - buf[15] = 0x00; - ide_atapi_cmd_reply(s, 16, max_len); - break; - case 0x2a: - cpu_to_ube16(&buf[0], 28 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - buf[8] = 0x2a; - buf[9] = 0x12; - buf[10] = 0x00; - buf[11] = 0x00; - - buf[12] = 0x70; - buf[13] = 3 << 5; - buf[14] = (1 << 0) | (1 << 3) | (1 << 5); - if (s->cdrom_locked) - buf[6] |= 1 << 1; - buf[15] = 0x00; - cpu_to_ube16(&buf[16], 706); - buf[18] = 0; - buf[19] = 2; - cpu_to_ube16(&buf[20], 512); - cpu_to_ube16(&buf[22], 706); - buf[24] = 0; - buf[25] = 0; - buf[26] = 0; - buf[27] = 0; - ide_atapi_cmd_reply(s, 28, max_len); - break; - default: - goto error_cmd; - } - break; - case 1: /* changeable values */ - goto error_cmd; - case 2: /* default values */ - goto error_cmd; - default: - case 3: /* saved values */ - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_SAVING_PARAMETERS_NOT_SUPPORTED); - break; - } - } - break; - case GPCMD_REQUEST_SENSE: - max_len = packet[4]; - memset(buf, 0, 18); - buf[0] = 0x70 | (1 << 7); - buf[2] = s->sense_key; - buf[7] = 10; - buf[12] = s->asc; - ide_atapi_cmd_reply(s, 18, max_len); - break; - case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - if (s->bs) { - s->cdrom_locked = packet[4] & 1; - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } - break; - case GPCMD_READ_10: - case GPCMD_READ_12: - { - int nb_sectors, lba; - - if (!s->bs) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - if (packet[0] == GPCMD_READ_10) - nb_sectors = ube16_to_cpu(packet + 7); - else - nb_sectors = ube32_to_cpu(packet + 6); - lba = ube32_to_cpu(packet + 2); - if (nb_sectors == 0) { - ide_atapi_cmd_ok(s); - break; - } - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } - ide_atapi_cmd_read(s, lba, nb_sectors); - } - break; - case GPCMD_SEEK: - { - int lba; - if (!s->bs) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - lba = ube32_to_cpu(packet + 2); - if (((int64_t)lba << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } - ide_atapi_cmd_ok(s); - } - break; - case GPCMD_START_STOP_UNIT: - { - int start, eject; - start = packet[4] & 1; - eject = (packet[4] >> 1) & 1; - - /* XXX: currently none implemented */ - ide_atapi_cmd_ok(s); - } - break; - case GPCMD_MECHANISM_STATUS: - { - max_len = ube16_to_cpu(packet + 8); - cpu_to_ube16(buf, 0); - /* no current LBA */ - buf[2] = 0; - buf[3] = 0; - buf[4] = 0; - buf[5] = 1; - cpu_to_ube16(buf + 6, 0); - ide_atapi_cmd_reply(s, 8, max_len); - } - break; - case GPCMD_READ_TOC_PMA_ATIP: - { - int format, msf, start_track, len; - - if (!s->bs) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - max_len = ube16_to_cpu(packet + 7); - format = packet[9] >> 6; - msf = (packet[1] >> 1) & 1; - start_track = packet[6]; - switch(format) { - case 0: - len = cdrom_read_toc(s, buf, msf, start_track); - if (len < 0) - goto error_cmd; - ide_atapi_cmd_reply(s, len, max_len); - break; - case 1: - /* multi session : only a single session defined */ - memset(buf, 0, 12); - buf[1] = 0x0a; - buf[2] = 0x01; - buf[3] = 0x01; - ide_atapi_cmd_reply(s, 12, max_len); - break; - default: - goto error_cmd; - } - } - break; - case GPCMD_READ_CDVD_CAPACITY: - if (!s->bs) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - /* NOTE: it is really the number of sectors minus 1 */ - cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); - cpu_to_ube32(buf + 4, 2048); - ide_atapi_cmd_reply(s, 8, 8); - break; - default: - error_cmd: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } -} - -void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) -{ - IDEState *ide_if = get_ide_interface(addr); - IDEState *s = ide_if->cur_drive; - int unit, n; - -#ifdef DEBUG_IDE - printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); -#endif - addr &= 7; - switch(addr) { - case 0: - break; - case 1: - s->feature = val; - break; - case 2: - if (val == 0) - val = 256; - s->nsector = val; - break; - case 3: - s->sector = val; - break; - case 4: - s->lcyl = val; - break; - case 5: - s->hcyl = val; - break; - case 6: - /* select drive */ - unit = (val >> 4) & 1; - s = ide_if + unit; - ide_if->cur_drive = s; - s->select = val; - break; - default: - case 7: - /* command */ -#if defined(DEBUG_IDE) - printf("ide: CMD=%02x\n", val); -#endif - switch(val) { - case WIN_IDENTIFY: - if (s->bs && !s->is_cdrom) { - ide_identify(s); - s->status = READY_STAT; - ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); - } else { - if (s->is_cdrom) { - ide_set_signature(s); - } - ide_abort_command(s); - } - ide_set_irq(s); - break; - case WIN_SPECIFY: - case WIN_RECAL: - s->status = READY_STAT; - ide_set_irq(s); - break; - case WIN_SETMULT: - if (s->nsector > MAX_MULT_SECTORS || - s->nsector == 0 || - (s->nsector & (s->nsector - 1)) != 0) { - ide_abort_command(s); - } else { - s->mult_sectors = s->nsector; - s->status = READY_STAT; - } - ide_set_irq(s); - break; - case WIN_READ: - case WIN_READ_ONCE: - s->req_nb_sectors = 1; - ide_sector_read(s); - break; - case WIN_WRITE: - case WIN_WRITE_ONCE: - s->status = SEEK_STAT; - s->req_nb_sectors = 1; - ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); - break; - case WIN_MULTREAD: - if (!s->mult_sectors) - goto abort_cmd; - s->req_nb_sectors = s->mult_sectors; - ide_sector_read(s); - break; - case WIN_MULTWRITE: - if (!s->mult_sectors) - goto abort_cmd; - s->status = SEEK_STAT; - s->req_nb_sectors = s->mult_sectors; - n = s->nsector; - if (n > s->req_nb_sectors) - n = s->req_nb_sectors; - ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); - break; - case WIN_READ_NATIVE_MAX: - ide_set_sector(s, s->nb_sectors - 1); - s->status = READY_STAT; - ide_set_irq(s); - break; - - /* ATAPI commands */ - case WIN_PIDENTIFY: - if (s->is_cdrom) { - ide_atapi_identify(s); - s->status = READY_STAT; - ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); - } else { - ide_abort_command(s); - } - ide_set_irq(s); - break; - case WIN_SRST: - if (!s->is_cdrom) - goto abort_cmd; - ide_set_signature(s); - s->status = READY_STAT; - s->error = 0x01; - break; - case WIN_PACKETCMD: - if (!s->is_cdrom) - goto abort_cmd; - /* DMA or overlapping commands not supported */ - if ((s->feature & 0x03) != 0) - goto abort_cmd; - s->nsector = 1; - ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, - ide_atapi_cmd); - break; - default: - abort_cmd: - ide_abort_command(s); - ide_set_irq(s); - break; - } - } -} - -uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr1) -{ - IDEState *s = get_ide_interface(addr1)->cur_drive; - uint32_t addr; - int ret; - - addr = addr1 & 7; - switch(addr) { - case 0: - ret = 0xff; - break; - case 1: - ret = s->error; - break; - case 2: - ret = s->nsector & 0xff; - break; - case 3: - ret = s->sector; - break; - case 4: - ret = s->lcyl; - break; - case 5: - ret = s->hcyl; - break; - case 6: - ret = s->select; - break; - default: - case 7: - ret = s->status; - pic_set_irq(s->irq, 0); - break; - } -#ifdef DEBUG_IDE - printf("ide: read addr=0x%x val=%02x\n", addr1, ret); -#endif - return ret; -} - -uint32_t ide_status_read(CPUX86State *env, uint32_t addr) -{ - IDEState *s = get_ide_interface(addr)->cur_drive; - int ret; - ret = s->status; -#ifdef DEBUG_IDE - printf("ide: read status addr=0x%x val=%02x\n", addr, ret); -#endif - return ret; -} - -void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) -{ - IDEState *ide_if = get_ide_interface(addr); - IDEState *s; - int i; - -#ifdef DEBUG_IDE - printf("ide: write control addr=0x%x val=%02x\n", addr, val); -#endif - /* common for both drives */ - if (!(ide_if[0].cmd & IDE_CMD_RESET) && - (val & IDE_CMD_RESET)) { - /* reset low to high */ - for(i = 0;i < 2; i++) { - s = &ide_if[i]; - s->status = BUSY_STAT | SEEK_STAT; - s->error = 0x01; - } - } else if ((ide_if[0].cmd & IDE_CMD_RESET) && - !(val & IDE_CMD_RESET)) { - /* high to low */ - for(i = 0;i < 2; i++) { - s = &ide_if[i]; - s->status = READY_STAT; - ide_set_signature(s); - } - } - - ide_if[0].cmd = val; - ide_if[1].cmd = val; -} - -void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) -{ - IDEState *s = get_ide_interface(addr)->cur_drive; - uint8_t *p; - - p = s->data_ptr; - *(uint16_t *)p = tswap16(val); - p += 2; - s->data_ptr = p; - if (p >= s->data_end) - s->end_transfer_func(s); -} - -uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) -{ - IDEState *s = get_ide_interface(addr)->cur_drive; - uint8_t *p; - int ret; - p = s->data_ptr; - ret = tswap16(*(uint16_t *)p); - p += 2; - s->data_ptr = p; - if (p >= s->data_end) - s->end_transfer_func(s); - return ret; -} - -void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) -{ - IDEState *s = get_ide_interface(addr)->cur_drive; - uint8_t *p; - - p = s->data_ptr; - *(uint32_t *)p = tswap32(val); - p += 4; - s->data_ptr = p; - if (p >= s->data_end) - s->end_transfer_func(s); -} - -uint32_t ide_data_readl(CPUX86State *env, uint32_t addr) -{ - IDEState *s = get_ide_interface(addr)->cur_drive; - uint8_t *p; - int ret; - - p = s->data_ptr; - ret = tswap32(*(uint32_t *)p); - p += 4; - s->data_ptr = p; - if (p >= s->data_end) - s->end_transfer_func(s); - return ret; -} - -void ide_reset(IDEState *s) -{ - s->mult_sectors = MAX_MULT_SECTORS; - s->cur_drive = s; - s->select = 0xa0; - s->status = READY_STAT; - ide_set_signature(s); -} - -struct partition { - uint8_t boot_ind; /* 0x80 - active */ - uint8_t head; /* starting head */ - uint8_t sector; /* starting sector */ - uint8_t cyl; /* starting cylinder */ - uint8_t sys_ind; /* What partition type */ - uint8_t end_head; /* end head */ - uint8_t end_sector; /* end sector */ - uint8_t end_cyl; /* end cylinder */ - uint32_t start_sect; /* starting sector counting from 0 */ - uint32_t nr_sects; /* nr of sectors in partition */ -} __attribute__((packed)); - -/* try to guess the IDE geometry from the MSDOS partition table */ -void ide_guess_geometry(IDEState *s) -{ - uint8_t buf[512]; - int ret, i; - struct partition *p; - uint32_t nr_sects; - - if (s->cylinders != 0) - return; - ret = bdrv_read(s->bs, 0, buf, 1); - if (ret < 0) - return; - /* test msdos magic */ - if (buf[510] != 0x55 || buf[511] != 0xaa) - return; - for(i = 0; i < 4; i++) { - p = ((struct partition *)(buf + 0x1be)) + i; - nr_sects = tswap32(p->nr_sects); - if (nr_sects && p->end_head) { - /* We make the assumption that the partition terminates on - a cylinder boundary */ - s->heads = p->end_head + 1; - s->sectors = p->end_sector & 63; - s->cylinders = s->nb_sectors / (s->heads * s->sectors); -#if 0 - printf("guessed partition: CHS=%d %d %d\n", - s->cylinders, s->heads, s->sectors); -#endif - } - } -} - -void ide_init(void) -{ - IDEState *s; - int i, cylinders, iobase, iobase2; - int64_t nb_sectors; - static const int ide_iobase[2] = { 0x1f0, 0x170 }; - static const int ide_iobase2[2] = { 0x3f6, 0x376 }; - static const int ide_irq[2] = { 14, 15 }; - - for(i = 0; i < MAX_DISKS; i++) { - s = &ide_state[i]; - s->bs = bs_table[i]; - if (s->bs) { - bdrv_get_geometry(s->bs, &nb_sectors); - s->nb_sectors = nb_sectors; - ide_guess_geometry(s); - if (s->cylinders == 0) { - /* if no geometry, use a LBA compatible one */ - cylinders = nb_sectors / (16 * 63); - if (cylinders > 16383) - cylinders = 16383; - else if (cylinders < 2) - cylinders = 2; - s->cylinders = cylinders; - s->heads = 16; - s->sectors = 63; - } - } - s->irq = ide_irq[i >> 1]; - ide_reset(s); - } - for(i = 0; i < (MAX_DISKS / 2); i++) { - iobase = ide_iobase[i]; - iobase2 = ide_iobase2[i]; - ide_table[iobase >> 3] = &ide_state[2 * i]; - if (ide_iobase2[i]) - ide_table[iobase2 >> 3] = &ide_state[2 * i]; - register_ioport_write(iobase, 8, ide_ioport_write, 1); - register_ioport_read(iobase, 8, ide_ioport_read, 1); - register_ioport_read(iobase2, 1, ide_status_read, 1); - register_ioport_write(iobase2, 1, ide_cmd_write, 1); - - /* data ports */ - register_ioport_write(iobase, 2, ide_data_writew, 2); - register_ioport_read(iobase, 2, ide_data_readw, 2); - register_ioport_write(iobase, 4, ide_data_writel, 4); - register_ioport_read(iobase, 4, ide_data_readl, 4); - } -} - /***********************************************************/ /* keyboard emulation */ @@ -4239,9 +2874,7 @@ int main(int argc, char **argv) secs = strtol(p, (char **)&p, 0); if (*p != '\0') goto chs_fail; - ide_state[0].cylinders = cyls; - ide_state[0].heads = heads; - ide_state[0].sectors = secs; + ide_set_geometry(0, cyls, heads, secs); chs_fail: ; } break; @@ -4265,7 +2898,7 @@ int main(int argc, char **argv) break; case 11: hd_filename[2] = optarg; - ide_state[2].is_cdrom = 1; + ide_set_cdrom(2, 1); break; case 12: boot_device = optarg[0]; diff --git a/vl.h b/vl.h index 531eabe02..f2c8d6d0d 100644 --- a/vl.h +++ b/vl.h @@ -34,6 +34,7 @@ typedef uint32_t (IOPortReadFunc)(struct CPUX86State *env, uint32_t address); void *get_mmap_addr(unsigned long size); int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); +void pic_set_irq(int irq, int level); void kbd_put_keycode(int keycode); @@ -97,4 +98,13 @@ void vga_update_display(void); /* sdl.c */ void sdl_display_init(DisplayState *ds); +/* ide.c */ +#define MAX_DISKS 4 + +extern BlockDriverState *bs_table[MAX_DISKS]; + +void ide_init(void); +void ide_set_geometry(int n, int cyls, int heads, int secs); +void ide_set_cdrom(int n, int is_cdrom); + #endif /* VL_H */ -- cgit v1.2.3 From 2e134c9c55cb4f1d8e9aca26360c006624344091 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 11 Nov 2003 13:55:33 +0000 Subject: 64-bit multiplication fix (Ulrich Hecht) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@446 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 4 ++-- target-arm/translate.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target-arm/op.c b/target-arm/op.c index 5879eba9f..73f95b777 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -368,7 +368,7 @@ void OPPROTO op_mul_T0_T1(void) void OPPROTO op_mull_T0_T1(void) { uint64_t res; - res = T0 * T1; + res = (uint64_t)T0 * (uint64_t)T1; T1 = res >> 32; T0 = res; } @@ -377,7 +377,7 @@ void OPPROTO op_mull_T0_T1(void) void OPPROTO op_imull_T0_T1(void) { uint64_t res; - res = (int32_t)T0 * (int32_t)T1; + res = (int64_t)T0 * (int64_t)T1; T1 = res >> 32; T0 = res; } diff --git a/target-arm/translate.c b/target-arm/translate.c index 808fa2b34..944794629 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -516,9 +516,9 @@ static void disas_arm_insn(DisasContext *s) gen_movl_T0_reg(s, rs); gen_movl_T1_reg(s, rm); if (insn & (1 << 22)) - gen_op_mull_T0_T1(); - else gen_op_imull_T0_T1(); + else + gen_op_mull_T0_T1(); if (insn & (1 << 21)) gen_op_addq_T0_T1(rn, rd); if (insn & (1 << 20)) -- cgit v1.2.3 From 1a0636f8d79088e967f9fa0f93962008c0b303d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 11 Nov 2003 14:20:17 +0000 Subject: new VGA bios git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@447 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/vgabios.bin | Bin 27493 -> 29673 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index b4937a841..88e99f6cb 100644 Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ -- cgit v1.2.3 From bd0d90b21d84c7ac3eb258fbf93bec1cbf277986 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Nov 2003 22:23:01 +0000 Subject: make Knoppix CD-ROM probe happy git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@448 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index 96e43da5c..49ae488bb 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -371,6 +371,17 @@ static void padstr(char *str, const char *src, int len) } } +static void padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + for(i = 0; i < buf_size; i++) { + if (*src) + buf[i] = *src++; + else + buf[i] = ' '; + } +} + static void ide_identify(IDEState *s) { uint16_t *p; @@ -1013,6 +1024,21 @@ static void ide_atapi_cmd(IDEState *s) cpu_to_ube32(buf + 4, 2048); ide_atapi_cmd_reply(s, 8, 8); break; + case GPCMD_INQUIRY: + max_len = packet[4]; + buf[0] = 0x05; /* CD-ROM */ + buf[1] = 0x80; /* removable */ + buf[2] = 0x00; /* ISO */ + buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ + buf[4] = 31; /* additionnal length */ + buf[5] = 0; /* reserved */ + buf[6] = 0; /* reserved */ + buf[7] = 0; /* reserved */ + padstr8(buf + 8, 8, "QEMU"); + padstr8(buf + 16, 16, "QEMU CD-ROM"); + padstr8(buf + 32, 4, QEMU_VERSION); + ide_atapi_cmd_reply(s, 36, max_len); + break; default: error_cmd: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -- cgit v1.2.3 From e670b89e3b42997fc7fb997bdfdc6ff998cfd8a7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Nov 2003 23:23:42 +0000 Subject: added comments and TSS bit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@449 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 00bc17e76..0d5d8244c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -58,12 +58,14 @@ #define DESC_TYPE_SHIFT 8 #define DESC_A_MASK (1 << 8) -#define DESC_CS_MASK (1 << 11) -#define DESC_C_MASK (1 << 10) -#define DESC_R_MASK (1 << 9) +#define DESC_CS_MASK (1 << 11) /* 1=code segment 0=data segment */ +#define DESC_C_MASK (1 << 10) /* code: conforming */ +#define DESC_R_MASK (1 << 9) /* code: readable */ -#define DESC_E_MASK (1 << 10) -#define DESC_W_MASK (1 << 9) +#define DESC_E_MASK (1 << 10) /* data: expansion direction */ +#define DESC_W_MASK (1 << 9) /* data: writable */ + +#define DESC_TSS_BUSY_MASK (1 << 9) /* eflags masks */ #define CC_C 0x0001 -- cgit v1.2.3 From 7e84c2498f0ff3999937d18d1e9abaa030400000 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Nov 2003 23:39:19 +0000 Subject: full TSS support - IO map check support - conforming segment check fixes - iret in vm86 mode fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@450 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 525 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 465 insertions(+), 60 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 1c0920bcf..2f4a15d87 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -126,6 +126,56 @@ void cpu_loop_exit(void) longjmp(env->jmp_env, 1); } +/* return non zero if error */ +static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, + int selector) +{ + SegmentCache *dt; + int index; + uint8_t *ptr; + + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) + return -1; + ptr = dt->base + index; + *e1_ptr = ldl_kernel(ptr); + *e2_ptr = ldl_kernel(ptr + 4); + return 0; +} + +static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) +{ + unsigned int limit; + limit = (e1 & 0xffff) | (e2 & 0x000f0000); + if (e2 & DESC_G_MASK) + limit = (limit << 12) | 0xfff; + return limit; +} + +static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) +{ + return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); +} + +static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) +{ + sc->base = get_seg_base(e1, e2); + sc->limit = get_seg_limit(e1, e2); + sc->flags = e2; +} + +/* init the segment cache in vm86 mode. */ +static inline void load_seg_vm(int seg, int selector) +{ + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg, selector, + (uint8_t *)(selector << 4), 0xffff, 0); +} + static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, uint32_t *esp_ptr, int dpl) { @@ -161,54 +211,322 @@ static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, } } -/* return non zero if error */ -static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, - int selector) +/* XXX: merge with load_seg() */ +static void tss_load_seg(int seg_reg, int selector) { + uint32_t e1, e2; + int rpl, dpl, cpl; + + if ((selector & 0xfffc) != 0) { + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + if (!(e2 & DESC_S_MASK)) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (seg_reg == R_CS) { + if (!(e2 & DESC_CS_MASK)) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + if (dpl != rpl) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + if ((e2 & DESC_C_MASK) && dpl > rpl) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + + } else if (seg_reg == R_SS) { + /* SS must be writable data */ + if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + if (dpl != cpl || dpl != rpl) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + } else { + /* not readable code */ + if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK)) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + /* if data or non conforming code, checks the rights */ + if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) { + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + } + } + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + cpu_x86_load_seg_cache(env, seg_reg, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + } else { + if (seg_reg == R_SS || seg_reg == R_CS) + raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + } +} + +#define SWITCH_TSS_JMP 0 +#define SWITCH_TSS_IRET 1 +#define SWITCH_TSS_CALL 2 + +/* XXX: restore CPU state in registers (PowerPC case) */ +static void switch_tss(int tss_selector, + uint32_t e1, uint32_t e2, int source) +{ + int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; + uint8_t *tss_base; + uint32_t new_regs[8], new_segs[6]; + uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap; + uint32_t old_eflags, eflags_mask; SegmentCache *dt; int index; uint8_t *ptr; - if (selector & 0x4) - dt = &env->ldt; + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + + /* if task gate, we read the TSS segment and we load it */ + if (type == 5) { + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); + tss_selector = e1 >> 16; + if (tss_selector & 4) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + if (load_segment(&e1, &e2, tss_selector) != 0) + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); + if (e2 & DESC_S_MASK) + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + if ((type & 7) != 1) + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc); + } + + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc); + + if (type & 8) + tss_limit_max = 103; else - dt = &env->gdt; - index = selector & ~7; + tss_limit_max = 43; + tss_limit = get_seg_limit(e1, e2); + tss_base = get_seg_base(e1, e2); + if ((tss_selector & 4) != 0 || + tss_limit < tss_limit_max) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; + if (old_type & 8) + old_tss_limit_max = 103; + else + old_tss_limit_max = 43; + + /* read all the registers from the new TSS */ + if (type & 8) { + /* 32 bit */ + new_cr3 = ldl_kernel(tss_base + 0x1c); + new_eip = ldl_kernel(tss_base + 0x20); + new_eflags = ldl_kernel(tss_base + 0x24); + for(i = 0; i < 8; i++) + new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4)); + for(i = 0; i < 6; i++) + new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4)); + new_ldt = lduw_kernel(tss_base + 0x60); + new_trap = ldl_kernel(tss_base + 0x64); + } else { + /* 16 bit */ + new_cr3 = 0; + new_eip = lduw_kernel(tss_base + 0x0e); + new_eflags = lduw_kernel(tss_base + 0x10); + for(i = 0; i < 8; i++) + new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000; + for(i = 0; i < 4; i++) + new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4)); + new_ldt = lduw_kernel(tss_base + 0x2a); + new_segs[R_FS] = 0; + new_segs[R_GS] = 0; + new_trap = 0; + } + + /* NOTE: we must avoid memory exceptions during the task switch, + so we make dummy accesses before */ + /* XXX: it can still fail in some cases, so a bigger hack is + necessary to valid the TLB after having done the accesses */ + + v1 = ldub_kernel(env->tr.base); + v2 = ldub(env->tr.base + old_tss_limit_max); + stb_kernel(env->tr.base, v1); + stb_kernel(env->tr.base + old_tss_limit_max, v2); + + /* clear busy bit (it is restartable) */ + if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { + uint8_t *ptr; + uint32_t e2; + ptr = env->gdt.base + (env->tr.selector << 3); + e2 = ldl_kernel(ptr + 4); + e2 &= ~DESC_TSS_BUSY_MASK; + stl_kernel(ptr + 4, e2); + } + old_eflags = compute_eflags(); + if (source == SWITCH_TSS_IRET) + old_eflags &= ~NT_MASK; + + /* save the current state in the old TSS */ + if (type & 8) { + /* 32 bit */ + stl_kernel(env->tr.base + 0x20, env->eip); + stl_kernel(env->tr.base + 0x24, old_eflags); + for(i = 0; i < 8; i++) + stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]); + for(i = 0; i < 6; i++) + stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); + } else { + /* 16 bit */ + stw_kernel(env->tr.base + 0x0e, new_eip); + stw_kernel(env->tr.base + 0x10, old_eflags); + for(i = 0; i < 8; i++) + stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]); + for(i = 0; i < 4; i++) + stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); + } + + /* now if an exception occurs, it will occurs in the next task + context */ + + if (source == SWITCH_TSS_CALL) { + stw_kernel(tss_base, env->tr.selector); + new_eflags |= NT_MASK; + } + + /* set busy bit */ + if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { + uint8_t *ptr; + uint32_t e2; + ptr = env->gdt.base + (tss_selector << 3); + e2 = ldl_kernel(ptr + 4); + e2 |= DESC_TSS_BUSY_MASK; + stl_kernel(ptr + 4, e2); + } + + /* set the new CPU state */ + /* from this point, any exception which occurs can give problems */ + env->cr[0] |= CR0_TS_MASK; + env->tr.selector = tss_selector; + env->tr.base = tss_base; + env->tr.limit = tss_limit; + env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; + + if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { + env->cr[3] = new_cr3; + cpu_x86_update_cr3(env); + } + + /* load all registers without an exception, then reload them with + possible exception */ + env->eip = new_eip; + eflags_mask = FL_UPDATE_CPL0_MASK; + if (!(type & 8)) + eflags_mask &= 0xffff; + load_eflags(new_eflags, eflags_mask); + for(i = 0; i < 8; i++) + env->regs[i] = new_regs[i]; + if (new_eflags & VM_MASK) { + for(i = 0; i < 6; i++) + load_seg_vm(i, new_segs[i]); + /* in vm86, CPL is always 3 */ + cpu_x86_set_cpl(env, 3); + } else { + /* CPL is set the RPL of CS */ + cpu_x86_set_cpl(env, new_segs[R_CS] & 3); + /* first just selectors as the rest may trigger exceptions */ + for(i = 0; i < 6; i++) + cpu_x86_load_seg_cache(env, i, new_segs[i], NULL, 0, 0); + } + + env->ldt.selector = new_ldt & ~4; + env->ldt.base = NULL; + env->ldt.limit = 0; + env->ldt.flags = 0; + + /* load the LDT */ + if (new_ldt & 4) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + + dt = &env->gdt; + index = new_ldt & ~7; if ((index + 7) > dt->limit) - return -1; + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); ptr = dt->base + index; - *e1_ptr = ldl_kernel(ptr); - *e2_ptr = ldl_kernel(ptr + 4); - return 0; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + load_seg_cache_raw_dt(&env->ldt, e1, e2); + + /* load the segments */ + if (!(new_eflags & VM_MASK)) { + tss_load_seg(R_CS, new_segs[R_CS]); + tss_load_seg(R_SS, new_segs[R_SS]); + tss_load_seg(R_ES, new_segs[R_ES]); + tss_load_seg(R_DS, new_segs[R_DS]); + tss_load_seg(R_FS, new_segs[R_FS]); + tss_load_seg(R_GS, new_segs[R_GS]); + } + + /* check that EIP is in the CS segment limits */ + if (new_eip > env->segs[R_CS].limit) { + raise_exception_err(EXCP0D_GPF, 0); + } } - -static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) + +/* check if Port I/O is allowed in TSS */ +static inline void check_io(int addr, int size) { - unsigned int limit; - limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & DESC_G_MASK) - limit = (limit << 12) | 0xfff; - return limit; + int io_offset, val, mask; + + /* TSS must be a valid 32 bit one */ + if (!(env->tr.flags & DESC_P_MASK) || + ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || + env->tr.limit < 103) + goto fail; + io_offset = lduw_kernel(env->tr.base + 0x66); + io_offset += (addr >> 3); + /* Note: the check needs two bytes */ + if ((io_offset + 1) > env->tr.limit) + goto fail; + val = lduw_kernel(env->tr.base + io_offset); + val >>= (addr & 7); + mask = (1 << size) - 1; + /* all bits must be zero to allow the I/O */ + if ((val & mask) != 0) { + fail: + raise_exception_err(EXCP0D_GPF, 0); + } } -static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) +void check_iob_T0(void) { - return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); + check_io(T0, 1); } -static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) +void check_iow_T0(void) { - sc->base = get_seg_base(e1, e2); - sc->limit = get_seg_limit(e1, e2); - sc->flags = e2; + check_io(T0, 2); } -/* init the segment cache in vm86 mode. */ -static inline void load_seg_vm(int seg, int selector) +void check_iol_T0(void) { - selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg, selector, - (uint8_t *)(selector << 4), 0xffff, 0); + check_io(T0, 4); +} + +void check_iob_DX(void) +{ + check_io(EDX & 0xffff, 1); +} + +void check_iow_DX(void) +{ + check_io(EDX & 0xffff, 2); +} + +void check_iol_DX(void) +{ + check_io(EDX & 0xffff, 4); } /* protected mode interrupt */ @@ -222,6 +540,21 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; uint32_t old_cs, old_ss, old_esp, old_eip; + has_error_code = 0; + if (!is_int && !is_hw) { + switch(intno) { + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 17: + has_error_code = 1; + break; + } + } + dt = &env->idt; if (intno * 8 + 7 > dt->limit) raise_exception_err(EXCP0D_GPF, intno * 8 + 2); @@ -232,8 +565,27 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; switch(type) { case 5: /* task gate */ - cpu_abort(env, "task gate not supported"); - break; + /* must do that check here to return the correct error code */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); + switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL); + if (has_error_code) { + int mask; + /* push the error code */ + shift = (env->segs[R_CS].flags >> DESC_B_SHIFT) & 1; + if (env->segs[R_SS].flags & DESC_B_MASK) + mask = 0xffffffff; + else + mask = 0xffff; + esp = (env->regs[R_ESP] - (2 << shift)) & mask; + ssp = env->segs[R_SS].base + esp; + if (shift) + stl_kernel(ssp, error_code); + else + stw_kernel(ssp, error_code); + env->regs[R_ESP] = (esp & mask) | (env->regs[R_ESP] & ~mask); + } + return; case 6: /* 286 interrupt gate */ case 7: /* 286 trap gate */ case 14: /* 386 interrupt gate */ @@ -293,20 +645,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, } shift = type >> 3; - has_error_code = 0; - if (!is_int && !is_hw) { - switch(intno) { - case 8: - case 10: - case 11: - case 12: - case 13: - case 14: - case 17: - has_error_code = 1; - break; - } - } push_size = 6 + (new_stack << 2) + (has_error_code << 1); if (env->eflags & VM_MASK) push_size += 8; @@ -688,7 +1026,7 @@ void helper_ltr_T0(void) e2 = ldl_kernel(ptr + 4); type = (e2 >> DESC_TYPE_SHIFT) & 0xf; if ((e2 & DESC_S_MASK) || - (type != 2 && type != 9)) + (type != 1 && type != 9)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); @@ -701,6 +1039,7 @@ void helper_ltr_T0(void) /* only works if protected mode and not VM86. Calling load_seg with seg_reg == R_CS is discouraged */ +/* XXX: add ring level checks */ void load_seg(int seg_reg, int selector, unsigned int cur_eip) { uint32_t e1, e2; @@ -725,7 +1064,7 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) } if (seg_reg == R_SS) { - if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { + if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { EIP = cur_eip; raise_exception_err(EXCP0D_GPF, selector & 0xfffc); } @@ -757,7 +1096,7 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) /* protected mode jump */ void helper_ljmp_protected_T0_T1(void) { - int new_cs, new_eip; + int new_cs, new_eip, gate_cs, type; uint32_t e1, e2, cpl, dpl, rpl, limit; new_cs = T0; @@ -771,7 +1110,7 @@ void helper_ljmp_protected_T0_T1(void) if (!(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { + if (e2 & DESC_C_MASK) { /* conforming code segment */ if (dpl > cpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -792,8 +1131,52 @@ void helper_ljmp_protected_T0_T1(void) get_seg_base(e1, e2), limit, e2); EIP = new_eip; } else { - cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", - new_cs, new_eip); + /* jump to call or task gate */ + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + rpl = new_cs & 3; + cpl = env->hflags & HF_CPL_MASK; + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + switch(type) { + case 1: /* 286 TSS */ + case 9: /* 386 TSS */ + case 5: /* task gate */ + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP); + break; + case 4: /* 286 call gate */ + case 12: /* 386 call gate */ + if ((dpl < cpl) || (dpl < rpl)) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + gate_cs = e1 >> 16; + if (load_segment(&e1, &e2, gate_cs) != 0) + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + /* must be code segment */ + if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != + (DESC_S_MASK | DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); + if (((e2 & DESC_C_MASK) && (dpl > cpl)) || + (!(e2 & DESC_C_MASK) && (dpl != cpl))) + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); + new_eip = (e1 & 0xffff); + if (type == 12) + new_eip |= (e2 & 0xffff0000); + limit = get_seg_limit(e1, e2); + if (new_eip > limit) + raise_exception_err(EXCP0D_GPF, 0); + cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); + EIP = new_eip; + break; + default: + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + break; + } } } @@ -852,7 +1235,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (!(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { + if (e2 & DESC_C_MASK) { /* conforming code segment */ if (dpl > cpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -898,11 +1281,15 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) } else { /* check gate type */ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + rpl = new_cs & 3; switch(type) { case 1: /* available 286 TSS */ case 9: /* available 386 TSS */ case 5: /* task gate */ - cpu_abort(env, "task gate not supported"); + if (dpl < cpl || dpl < rpl) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL); break; case 4: /* 286 call gate */ case 12: /* 386 call gate */ @@ -913,8 +1300,6 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) } shift = type >> 3; - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - rpl = new_cs & 3; if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); /* check valid bit */ @@ -1031,13 +1416,13 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) } } -/* real mode iret */ +/* real and vm86 mode iret */ void helper_iret_real(int shift) { uint32_t sp, new_cs, new_eip, new_eflags, new_esp; uint8_t *ssp; int eflags_mask; - + sp = ESP & 0xffff; ssp = env->segs[R_SS].base + sp; if (shift == 1) { @@ -1056,7 +1441,10 @@ void helper_iret_real(int shift) (new_esp & 0xffff); load_seg_vm(R_CS, new_cs); env->eip = new_eip; - eflags_mask = FL_UPDATE_CPL0_MASK; + if (env->eflags & VM_MASK) + eflags_mask = FL_UPDATE_MASK32 | IF_MASK | RF_MASK; + else + eflags_mask = FL_UPDATE_CPL0_MASK; if (shift == 0) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); @@ -1102,7 +1490,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if (rpl < cpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; - if (e2 & DESC_CS_MASK) { + if (e2 & DESC_C_MASK) { if (dpl > rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); } else { @@ -1198,7 +1586,24 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) void helper_iret_protected(int shift) { - helper_ret_protected(shift, 1, 0); + int tss_selector, type; + uint32_t e1, e2; + + /* specific case for TSS */ + if (env->eflags & NT_MASK) { + tss_selector = lduw_kernel(env->tr.base + 0); + if (tss_selector & 4) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + if (load_segment(&e1, &e2, tss_selector) != 0) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + type = (e2 >> DESC_TYPE_SHIFT) & 0x17; + /* NOTE: we check both segment and busy TSS */ + if (type != 3) + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); + switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET); + } else { + helper_ret_protected(shift, 1, 0); + } } void helper_lret_protected(int shift, int addend) -- cgit v1.2.3 From 246d897f4c85cb982bef839f7723025eecb78789 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Nov 2003 23:55:40 +0000 Subject: dump more registers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@451 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index f1617d8c6..fb8f254d4 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -105,13 +105,14 @@ static const char *cc_op_str[] = { void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) { - int eflags; + int eflags, i; char cc_op_name[32]; + static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" }; eflags = env->eflags; fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], env->eip, eflags, @@ -121,14 +122,34 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) eflags & CC_Z ? 'Z' : '-', eflags & CC_A ? 'A' : '-', eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-'); - fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", - env->segs[R_CS].selector, - env->segs[R_SS].selector, - env->segs[R_DS].selector, - env->segs[R_ES].selector, - env->segs[R_FS].selector, - env->segs[R_GS].selector); + eflags & CC_C ? 'C' : '-', + env->hflags & HF_CPL_MASK); + for(i = 0; i < 6; i++) { + SegmentCache *sc = &env->segs[i]; + fprintf(f, "%s =%04x %08x %08x %08x\n", + seg_name[i], + sc->selector, + (int)sc->base, + sc->limit, + sc->flags); + } + fprintf(f, "LDT=%04x %08x %08x %08x\n", + env->ldt.selector, + (int)env->ldt.base, + env->ldt.limit, + env->ldt.flags); + fprintf(f, "TR =%04x %08x %08x %08x\n", + env->tr.selector, + (int)env->tr.base, + env->tr.limit, + env->tr.flags); + fprintf(f, "GDT= %08x %08x\n", + (int)env->gdt.base, env->gdt.limit); + fprintf(f, "IDT= %08x %08x\n", + (int)env->idt.base, env->idt.limit); + fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", + env->cr[0], env->cr[2], env->cr[3], env->cr[4]); + if (flags & X86_DUMP_CCOP) { if ((unsigned)env->cc_op < CC_OP_NB) strcpy(cc_op_name, cc_op_str[env->cc_op]); -- cgit v1.2.3 From 3e25f9515a07d47da843d9b3835e25def785dcee Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Nov 2003 00:13:08 +0000 Subject: io map checks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@452 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 7 +++++++ target-i386/ops_template.h | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/target-i386/exec.h b/target-i386/exec.h index dc1df94ab..6741485a0 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -171,6 +171,13 @@ void helper_wrmsr(void); void helper_lsl(void); void helper_lar(void); +void check_iob_T0(void); +void check_iow_T0(void); +void check_iol_T0(void); +void check_iob_DX(void); +void check_iow_DX(void); +void check_iol_DX(void); + /* XXX: move that to a generic header */ #if !defined(CONFIG_USER_ONLY) diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 182296743..064881558 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -608,6 +608,16 @@ void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void) glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0); } +void OPPROTO glue(glue(op_check_io, SUFFIX), _T0)(void) +{ + glue(glue(check_io, SUFFIX), _T0)(); +} + +void OPPROTO glue(glue(op_check_io, SUFFIX), _DX)(void) +{ + glue(glue(check_io, SUFFIX), _DX)(); +} + #undef DATA_BITS #undef SHIFT_MASK #undef SIGN_MASK -- cgit v1.2.3 From 3ab493de4c524926bb75b04765b644f9189ccf01 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Nov 2003 01:42:19 +0000 Subject: added verr, verw, arpl - more precise segment rights checks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@453 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 2 + target-i386/helper.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++---- target-i386/op.c | 29 +++++++++ 3 files changed, 190 insertions(+), 11 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 6741485a0..dd11a3a3e 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -170,6 +170,8 @@ void helper_rdmsr(void); void helper_wrmsr(void); void helper_lsl(void); void helper_lar(void); +void helper_verr(void); +void helper_verw(void); void check_iob_T0(void); void check_iow_T0(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 2f4a15d87..070651530 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1037,13 +1037,15 @@ void helper_ltr_T0(void) env->tr.selector = selector; } -/* only works if protected mode and not VM86. Calling load_seg with - seg_reg == R_CS is discouraged */ -/* XXX: add ring level checks */ +/* only works if protected mode and not VM86. seg_reg must be != R_CS */ void load_seg(int seg_reg, int selector, unsigned int cur_eip) { uint32_t e1, e2; - + int cpl, dpl, rpl; + SegmentCache *dt; + int index; + uint8_t *ptr; + if ((selector & 0xfffc) == 0) { /* null selector case */ if (seg_reg == R_SS) { @@ -1053,26 +1055,51 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); } } else { - if (load_segment(&e1, &e2, selector) != 0) { + + if (selector & 0x4) + dt = &env->ldt; + else + dt = &env->gdt; + index = selector & ~7; + if ((index + 7) > dt->limit) { EIP = cur_eip; raise_exception_err(EXCP0D_GPF, selector & 0xfffc); } - if (!(e2 & DESC_S_MASK) || - (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { + ptr = dt->base + index; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + + if (!(e2 & DESC_S_MASK)) { EIP = cur_eip; raise_exception_err(EXCP0D_GPF, selector & 0xfffc); } - + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; if (seg_reg == R_SS) { + /* must be writable segment */ if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { EIP = cur_eip; raise_exception_err(EXCP0D_GPF, selector & 0xfffc); } + if (rpl != cpl || dpl != cpl) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } } else { + /* must be readable segment */ if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { EIP = cur_eip; raise_exception_err(EXCP0D_GPF, selector & 0xfffc); } + + if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { + /* if not conforming code, test rights */ + if (dpl < cpl || dpl < rpl) { + EIP = cur_eip; + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + } + } } if (!(e2 & DESC_P_MASK)) { @@ -1082,6 +1109,13 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) else raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); } + + /* set the access bit if not already set */ + if (!(e2 & DESC_A_MASK)) { + e2 |= DESC_A_MASK; + stl_kernel(ptr + 4, e2); + } + cpu_x86_load_seg_cache(env, seg_reg, selector, get_seg_base(e1, e2), get_seg_limit(e1, e2), @@ -1696,14 +1730,38 @@ void helper_lsl(void) { unsigned int selector, limit; uint32_t e1, e2; + int rpl, dpl, cpl, type; CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; selector = T0 & 0xffff; if (load_segment(&e1, &e2, selector) != 0) return; - limit = (e1 & 0xffff) | (e2 & 0x000f0000); - if (e2 & (1 << 23)) - limit = (limit << 12) | 0xfff; + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_S_MASK) { + if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { + /* conforming */ + } else { + if (dpl < cpl || dpl < rpl) + return; + } + } else { + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + switch(type) { + case 1: + case 2: + case 3: + case 9: + case 11: + break; + default: + return; + } + if (dpl < cpl || dpl < rpl) + return; + } + limit = get_seg_limit(e1, e2); T1 = limit; CC_SRC |= CC_Z; } @@ -1712,15 +1770,105 @@ void helper_lar(void) { unsigned int selector; uint32_t e1, e2; + int rpl, dpl, cpl, type; CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; selector = T0 & 0xffff; + if ((selector & 0xfffc) == 0) + return; if (load_segment(&e1, &e2, selector) != 0) return; + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_S_MASK) { + if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) { + /* conforming */ + } else { + if (dpl < cpl || dpl < rpl) + return; + } + } else { + type = (e2 >> DESC_TYPE_SHIFT) & 0xf; + switch(type) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 9: + case 11: + case 12: + break; + default: + return; + } + if (dpl < cpl || dpl < rpl) + return; + } T1 = e2 & 0x00f0ff00; CC_SRC |= CC_Z; } +void helper_verr(void) +{ + unsigned int selector; + uint32_t e1, e2; + int rpl, dpl, cpl; + + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + selector = T0 & 0xffff; + if ((selector & 0xfffc) == 0) + return; + if (load_segment(&e1, &e2, selector) != 0) + return; + if (!(e2 & DESC_S_MASK)) + return; + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_CS_MASK) { + if (!(e2 & DESC_R_MASK)) + return; + if (!(e2 & DESC_C_MASK)) { + if (dpl < cpl || dpl < rpl) + return; + } + } else { + if (dpl < cpl || dpl < rpl) + return; + } + /* ok */ +} + +void helper_verw(void) +{ + unsigned int selector; + uint32_t e1, e2; + int rpl, dpl, cpl; + + CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + selector = T0 & 0xffff; + if ((selector & 0xfffc) == 0) + return; + if (load_segment(&e1, &e2, selector) != 0) + return; + if (!(e2 & DESC_S_MASK)) + return; + rpl = selector & 3; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + if (e2 & DESC_CS_MASK) { + return; + } else { + if (dpl < cpl || dpl < rpl) + return; + if (!(e2 & DESC_W_MASK)) + return; + } + /* ok */ +} + /* FPU helpers */ void helper_fldt_ST0_A0(void) diff --git a/target-i386/op.c b/target-i386/op.c index f1276f7a6..d4742a384 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -936,6 +936,35 @@ void OPPROTO op_lar(void) helper_lar(); } +void OPPROTO op_verr(void) +{ + helper_verr(); +} + +void OPPROTO op_verw(void) +{ + helper_verw(); +} + +void OPPROTO op_arpl(void) +{ + if ((T0 & 3) < (T1 & 3)) { + /* XXX: emulate bug or 0xff3f0000 oring as in bochs ? */ + T0 = (T0 & ~3) | (T1 & 3); + T1 = CC_Z; + } else { + T1 = 0; + } + FORCE_RET(); +} + +void OPPROTO op_arpl_update(void) +{ + int eflags; + eflags = cc_table[CC_OP].compute_all(); + CC_SRC = (eflags & ~CC_Z) | T1; +} + /* T0: segment, T1:eip */ void OPPROTO op_ljmp_protected_T0_T1(void) { -- cgit v1.2.3 From f115e911d70dedbbab90efe589b267bf53178f10 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Nov 2003 01:43:28 +0000 Subject: iret and int fix for vm86 - added undefined instructions for real and vm86 modes - added verr, verrw, arpl - added port io map git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@454 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 230 ++++++++++++++++++++++++++++++------------------ 1 file changed, 142 insertions(+), 88 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index ab4fe09e6..7ce8f4bde 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -749,6 +749,43 @@ static GenOpFunc *gen_op_out_DX_T0[3] = { gen_op_outl_DX_T0, }; +static GenOpFunc *gen_op_in[3] = { + gen_op_inb_T0_T1, + gen_op_inw_T0_T1, + gen_op_inl_T0_T1, +}; + +static GenOpFunc *gen_op_out[3] = { + gen_op_outb_T0_T1, + gen_op_outw_T0_T1, + gen_op_outl_T0_T1, +}; + +static GenOpFunc *gen_check_io_T0[3] = { + gen_op_check_iob_T0, + gen_op_check_iow_T0, + gen_op_check_iol_T0, +}; + +static GenOpFunc *gen_check_io_DX[3] = { + gen_op_check_iob_DX, + gen_op_check_iow_DX, + gen_op_check_iol_DX, +}; + +static void gen_check_io(DisasContext *s, int ot, int use_dx, int cur_eip) +{ + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + if (use_dx) + gen_check_io_DX[ot](); + else + gen_check_io_T0[ot](); + } +} + static inline void gen_movs(DisasContext *s, int ot) { gen_string_movl_A0_ESI(s); @@ -912,18 +949,6 @@ GEN_REPZ(outs) GEN_REPZ2(scas) GEN_REPZ2(cmps) -static GenOpFunc *gen_op_in[3] = { - gen_op_inb_T0_T1, - gen_op_inw_T0_T1, - gen_op_inl_T0_T1, -}; - -static GenOpFunc *gen_op_out[3] = { - gen_op_outb_T0_T1, - gen_op_outw_T0_T1, - gen_op_outl_T0_T1, -}; - enum { JCC_O, JCC_B, @@ -3221,36 +3246,28 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x6c: /* insS */ case 0x6d: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - /* NOTE: even for (E)CX = 0 the exception is raised */ - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_check_io(s, ot, 1, pc_start - s->cs_base); + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - } else { - gen_ins(s, ot); - } + gen_ins(s, ot); } break; case 0x6e: /* outsS */ case 0x6f: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - /* NOTE: even for (E)CX = 0 the exception is raised */ - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_check_io(s, ot, 1, pc_start - s->cs_base); + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { - gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); - } else { - gen_outs(s, ot); - } + gen_outs(s, ot); } break; @@ -3258,61 +3275,49 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /* port I/O */ case 0xe4: case 0xe5: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = ldub_code(s->pc++); - gen_op_movl_T0_im(val); - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); - } + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub_code(s->pc++); + gen_op_movl_T0_im(val); + gen_check_io(s, ot, 0, pc_start - s->cs_base); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); break; case 0xe6: case 0xe7: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = ldub_code(s->pc++); - gen_op_movl_T0_im(val); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); - } + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub_code(s->pc++); + gen_op_movl_T0_im(val); + gen_check_io(s, ot, 0, pc_start - s->cs_base); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); break; case 0xec: case 0xed: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); - } + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_check_io(s, ot, 0, pc_start - s->cs_base); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); break; case 0xee: case 0xef: - if (s->pe && (s->cpl > s->iopl || s->vm86)) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); - } else { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); - } + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_check_io(s, ot, 0, pc_start - s->cs_base); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); break; /************************/ @@ -3370,8 +3375,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /* real mode */ gen_op_iret_real(s->dflag); s->cc_op = CC_OP_EFLAGS; - } else if (s->vm86 && s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else if (s->vm86) { + if (s->iopl != 3) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_op_iret_real(s->dflag); + s->cc_op = CC_OP_EFLAGS; + } } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); @@ -3675,11 +3685,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xcd: /* int N */ val = ldub_code(s->pc++); - /* XXX: add error code for vm86 GPF */ - if (!s->vm86) - gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); - else + if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); + } break; case 0xce: /* into */ if (s->cc_op != CC_OP_DYNAMIC) @@ -3799,6 +3809,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) op = (modrm >> 3) & 7; switch(op) { case 0: /* sldt */ + if (!s->pe || s->vm86) + goto illegal_op; gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); ot = OT_WORD; if (mod == 3) @@ -3806,6 +3818,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; case 2: /* lldt */ + if (!s->pe || s->vm86) + goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -3815,6 +3829,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 1: /* str */ + if (!s->pe || s->vm86) + goto illegal_op; gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); ot = OT_WORD; if (mod == 3) @@ -3822,6 +3838,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; case 3: /* ltr */ + if (!s->pe || s->vm86) + goto illegal_op; if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -3832,6 +3850,17 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 4: /* verr */ case 5: /* verw */ + if (!s->pe || s->vm86) + goto illegal_op; + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (op == 4) + gen_op_verr(); + else + gen_op_verw(); + s->cc_op = CC_OP_EFLAGS; + break; default: goto illegal_op; } @@ -3908,6 +3937,31 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; } break; + case 0x63: /* arpl */ + if (!s->pe || s->vm86) + goto illegal_op; + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub_code(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_arpl(); + s->cc_op = CC_OP_EFLAGS; + if (mod != 3) { + gen_op_st_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + gen_op_arpl_update(); + break; case 0x102: /* lar */ case 0x103: /* lsl */ if (!s->pe || s->vm86) -- cgit v1.2.3 From 275033239681346347766ac3712e3af792a0304f Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Nov 2003 01:46:15 +0000 Subject: Soundblaster 16 support (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@455 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/dma.c | 395 +++++++++++++++++++++++++++++++ hw/sb16.c | 723 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ oss.c | 512 +++++++++++++++++++++++++++++++++++++++ vl.c | 12 +- vl.h | 37 +++ 6 files changed, 1679 insertions(+), 2 deletions(-) create mode 100644 hw/dma.c create mode 100644 hw/sb16.c create mode 100644 oss.c diff --git a/Makefile.target b/Makefile.target index e4e4cea2d..18daeaba1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -176,7 +176,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o block.o ide.o vga.o +VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o ifdef CONFIG_SDL VL_OBJS+=sdl.o SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm diff --git a/hw/dma.c b/hw/dma.c new file mode 100644 index 000000000..ac85efba1 --- /dev/null +++ b/hw/dma.c @@ -0,0 +1,395 @@ +/* + * QEMU DMA emulation + * + * Copyright (c) 2003 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "vl.h" +#include "cpu.h" + +#define log(...) fprintf (stderr, "dma: " __VA_ARGS__) +#ifdef DEBUG_DMA +#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__) +#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__) +#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__) +#else +#define lwarn(...) +#define linfo(...) +#define ldebug(...) +#endif + +#define MEM_REAL(addr) ((addr)+(uint32_t)(phys_ram_base)) +#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) + +struct dma_regs { + int now[2]; + uint16_t base[2]; + uint8_t mode; + uint8_t page; + uint8_t dack; + uint8_t eop; + DMA_read_handler read_handler; + DMA_misc_handler misc_handler; +}; + +#define ADDR 0 +#define COUNT 1 + +static struct dma_cont { + uint8_t status; + uint8_t command; + uint8_t mask; + uint8_t flip_flop; + struct dma_regs regs[4]; +} dma_controllers[2]; + +enum { + CMD_MEMORY_TO_MEMORY = 0x01, + CMD_FIXED_ADDRESS = 0x02, + CMD_BLOCK_CONTROLLER = 0x04, + CMD_COMPRESSED_TIME = 0x08, + CMD_CYCLIC_PRIORITY = 0x10, + CMD_EXTENDED_WRITE = 0x20, + CMD_LOW_DREQ = 0x40, + CMD_LOW_DACK = 0x80, + CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS + | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE + | CMD_LOW_DREQ | CMD_LOW_DACK + +}; + +static void write_page (struct CPUX86State *env, uint32_t nport, uint32_t data) +{ + int ichan; + int ncont; + static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0}; + + ncont = nport > 0x87; + ichan = channels[nport - 0x80 - (ncont << 3)]; + + if (-1 == ichan) { + log ("invalid channel %#x %#x\n", nport, data); + return; + } + + dma_controllers[ncont].regs[ichan].page = data; +} + +static void init_chan (int ncont, int ichan) +{ + struct dma_regs *r; + + r = dma_controllers[ncont].regs + ichan; + r->now[ADDR] = r->base[0] << ncont; + r->now[COUNT] = 0; +} + +static inline int getff (int ncont) +{ + int ff; + + ff = dma_controllers[ncont].flip_flop; + dma_controllers[ncont].flip_flop = !ff; + return ff; +} + +static uint32_t read_chan (struct CPUX86State *env, uint32_t nport) +{ + int ff; + int ncont, ichan, nreg; + struct dma_regs *r; + int val; + + ncont = nport > 7; + ichan = (nport >> (1 + ncont)) & 3; + nreg = (nport >> ncont) & 1; + r = dma_controllers[ncont].regs + ichan; + + ff = getff (ncont); + + if (nreg) + val = (r->base[COUNT] << ncont) - r->now[COUNT]; + else + val = r->now[ADDR] + r->now[COUNT]; + + return (val >> (ncont + (ff << 3))) & 0xff; +} + +static void write_chan (uint32_t nport, int size, uint32_t data) +{ + int ncont, ichan, nreg; + struct dma_regs *r; + + ncont = nport > 7; + ichan = (nport >> (1 + ncont)) & 3; + nreg = (nport >> ncont) & 1; + r = dma_controllers[ncont].regs + ichan; + + if (2 == size) { + r->base[nreg] = data; + init_chan (ncont, ichan); + } + else { + if (getff (ncont)) { + r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00); + init_chan (ncont, ichan); + } + else { + r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff); + } + } +} +static void write_chanb (struct CPUX86State *env, uint32_t nport, uint32_t data) +{ + write_chan (nport, 1, data); +} + +static void write_chanw (struct CPUX86State *env, uint32_t nport, uint32_t data) +{ + write_chan (nport, 2, data); +} + +static void write_cont (struct CPUX86State *env, uint32_t nport, uint32_t data) +{ + int iport, ichan, ncont; + struct dma_cont *d; + + ncont = nport > 0xf; + ichan = -1; + + d = dma_controllers + ncont; + if (ncont) { + iport = ((nport - 0xd0) >> 1) + 8; + } + else { + iport = nport; + } + + switch (iport) { + case 8: /* command */ + if (data && (data | CMD_NOT_SUPPORTED)) { + log ("command %#x not supported\n", data); + goto error; + } + d->command = data; + break; + + case 9: + ichan = data & 3; + if (data & 4) { + d->status |= 1 << (ichan + 4); + } + else { + d->status &= ~(1 << (ichan + 4)); + } + d->status &= ~(1 << ichan); + break; + + case 0xa: /* single mask */ + if (data & 4) + d->mask |= 1 << (data & 3); + else + d->mask &= ~(1 << (data & 3)); + break; + + case 0xb: /* mode */ + { +#ifdef DMA_DEBUG + int op; + int ai; + int dir; + int opmode; + + ichan = val & 3; + op = (val >> 2) & 3; + ai = (val >> 4) & 1; + dir = (val >> 5) & 1; + opmode = (val >> 6) & 3; + + linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n", + ichan, op, ai, dir, opmode); +#endif + + d->regs[ichan].mode = data; + break; + } + + case 0xc: /* clear flip flop */ + d->flip_flop = 0; + break; + + case 0xd: /* reset */ + d->flip_flop = 0; + d->mask = ~0; + d->status = 0; + d->command = 0; + break; + + case 0xe: /* clear mask for all channels */ + d->mask = 0; + break; + + case 0xf: /* write mask for all channels */ + d->mask = data; + break; + + default: + log ("dma: unknown iport %#x\n", iport); + goto error; + } + +#ifdef DMA_DEBUG + if (0xc != iport) { + linfo ("nport %#06x, ncont %d, ichan % 2d, val %#06x\n", + nport, d != dma_controllers, ichan, data); + } +#endif + return; + + error: + abort (); +} + +int DMA_get_channel_mode (int nchan) +{ + return dma_controllers[nchan > 3].regs[nchan & 3].mode; +} + +void DMA_hold_DREQ (int nchan) +{ + int ncont, ichan; + + ncont = nchan > 3; + ichan = nchan & 3; + linfo ("held cont=%d chan=%d\n", ncont, ichan); + dma_controllers[ncont].status |= 1 << (ichan + 4); +} + +void DMA_release_DREQ (int nchan) +{ + int ncont, ichan; + + ncont = nchan > 3; + ichan = nchan & 3; + linfo ("released cont=%d chan=%d\n", ncont, ichan); + dma_controllers[ncont].status &= ~(1 << (ichan + 4)); +} + +static void channel_run (int ncont, int ichan) +{ + struct dma_regs *r; + int n; + int irq; + uint32_t addr; +/* int ai, dir; */ + + r = dma_controllers[ncont].regs + ichan; +/* ai = r->mode & 16; */ +/* dir = r->mode & 32 ? -1 : 1; */ + + addr = MEM_REAL ((r->page << 16) | r->now[ADDR]); + + irq = -1; + n = r->read_handler (addr, (r->base[COUNT] << ncont) + (1 << ncont), &irq); + r->now[COUNT] = n; + + ldebug ("dma_pos %d irq %d size %d\n", + n, irq, (r->base[1] << ncont) + (1 << ncont)); + + if (-1 != irq) { + pic_set_irq (irq, 1); + } +} + +void DMA_run (void) +{ + static int in_dma; + struct dma_cont *d; + int icont, ichan; + + if (in_dma) { + log ("attempt to re-enter dma\n"); + return; + } + + in_dma = 1; + d = dma_controllers; + + for (icont = 0; icont < 2; icont++, d++) { + for (ichan = 0; ichan < 4; ichan++) { + int mask; + + mask = 1 << ichan; + + if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) + channel_run (icont, ichan); + } + } + in_dma = 0; +} + +void DMA_register_channel (int nchan, + DMA_read_handler read_handler, + DMA_misc_handler misc_handler) +{ + struct dma_regs *r; + int ichan, ncont; + + ncont = nchan > 3; + ichan = nchan & 3; + + r = dma_controllers[ncont].regs + ichan; + r->read_handler = read_handler; + r->misc_handler = misc_handler; +} + +void DMA_init (void) +{ + int i; + int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; + + for (i = 0; i < 8; i++) { + register_ioport_write (i, 1, write_chanb, 1); + register_ioport_write (i, 1, write_chanw, 2); + + register_ioport_write (0xc0 + (i << 1), 1, write_chanb, 1); + register_ioport_write (0xc0 + (i << 1), 1, write_chanw, 2); + + register_ioport_read (i, 1, read_chan, 1); + register_ioport_read (0xc0 + (i << 1), 1, read_chan, 2); + } + + for (i = 0; i < LENOFA (page_port_list); i++) { + register_ioport_write (page_port_list[i] + 0x80, 1, write_page, 1); + register_ioport_write (page_port_list[i] + 0x88, 1, write_page, 1); + } + + for (i = 0; i < 8; i++) { + register_ioport_write (i + 8, 1, write_cont, 1); + register_ioport_write (0xd0 + (i << 1), 1, write_cont, 1); + } + + write_cont (NULL, 0xd, 0); + write_cont (NULL, 0xdd, 0); +} diff --git a/hw/sb16.c b/hw/sb16.c new file mode 100644 index 000000000..a57754839 --- /dev/null +++ b/hw/sb16.c @@ -0,0 +1,723 @@ +/* + * QEMU Soundblaster 16 emulation + * + * Copyright (c) 2003 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "vl.h" + +#define MIN(a, b) ((a)>(b)?(b):(a)) +#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) + +#define DEREF(x) (void)x +#define log(...) fprintf (stderr, "sb16: " __VA_ARGS__) +#define Fail(...) do { \ + fprintf (stderr, "sb16: " __VA_ARGS__); \ + abort (); \ +} while (0) + +#ifdef DEBUG_SB16 +#define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__) +#define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__) +#define ldebug(...) fprintf (stderr, "sb16: " __VA_ARGS__) +#else +#define lwarn(...) +#define linfo(...) +#define ldebug(...) +#endif + +#define IO_READ_PROTO(name) \ + uint32_t name (struct CPUX86State *env, uint32_t nport) +#define IO_WRITE_PROTO(name) \ + void name (struct CPUX86State *env, uint32_t nport, uint32_t val) + +static struct { + int ver_lo; + int ver_hi; + int irq; + int dma; + int hdma; + int port; + int mix_block; +} sb = {4, 5, 5, 1, 5, 0x220, -1}; + +static int mix_block, noirq; + +static struct mixer { + int nreg; + uint8_t regs[0x83]; +} mixer; + +static struct dsp { + int in_index; + int out_data_len; + int fmt_stereo; + int fmt_signed; + int fmt_bits; + int dma_auto; + int dma_buffer_size; + int fifo; + int freq; + int time_const; + int speaker; + int needed_bytes; + int cmd; + int dma_pos; + int use_hdma; + + int v2x6; + + uint8_t in_data[10]; + uint8_t out_data[10]; + + int left_till_irq; +} dsp; + +#define nocmd ~0 + +static void log_dsp (const char *cap) +{ + DEREF (cap); + + linfo ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n", + dsp.fmt_stereo ? 'S' : 'M', + dsp.fmt_signed ? 'S' : 'U', + dsp.fmt_bits, + dsp.dma_auto ? 'a' : 's', + dsp.dma_buffer_size, + dsp.dma_pos, + dsp.freq, + dsp.time_const, + dsp.speaker); +} + +static void control (int hold) +{ + linfo ("%d high %d\n", hold, dsp.use_hdma); + if (hold) { + if (dsp.use_hdma) + DMA_hold_DREQ (sb.hdma); + else + DMA_hold_DREQ (sb.dma); + } + else { + if (dsp.use_hdma) + DMA_release_DREQ (sb.hdma); + else + DMA_release_DREQ (sb.dma); + } +} + +static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len) +{ + int bps; + audfmt_e fmt; + + dsp.use_hdma = cmd < 0xc0; + dsp.fifo = (cmd >> 1) & 1; + dsp.dma_auto = (cmd >> 2) & 1; + + switch (cmd >> 4) { + case 11: + dsp.fmt_bits = 16; + break; + + case 12: + dsp.fmt_bits = 8; + break; + } + + dsp.fmt_signed = (d0 >> 4) & 1; + dsp.fmt_stereo = (d0 >> 5) & 1; + + if (-1 != dsp.time_const) { + int tmp; + + tmp = 256 - dsp.time_const; + dsp.freq = (1000000 + (tmp / 2)) / tmp; + } + bps = 1 << (16 == dsp.fmt_bits); + + if (-1 != dma_len) + dsp.dma_buffer_size = (dma_len + 1) * bps; + + linfo ("frequency %d, stereo %d, signed %d, bits %d, size %d, auto %d\n", + dsp.freq, dsp.fmt_stereo, dsp.fmt_signed, dsp.fmt_bits, + dsp.dma_buffer_size, dsp.dma_auto); + + if (16 == dsp.fmt_bits) { + if (dsp.fmt_signed) { + fmt = AUD_FMT_S16; + } + else { + fmt = AUD_FMT_U16; + } + } + else { + if (dsp.fmt_signed) { + fmt = AUD_FMT_S8; + } + else { + fmt = AUD_FMT_U8; + } + } + + dsp.dma_pos = 0; + dsp.left_till_irq = dsp.dma_buffer_size; + + if (sb.mix_block) { + mix_block = sb.mix_block; + } + else { + int align; + + align = bps << dsp.fmt_stereo; + mix_block = ((dsp.freq * align) / 100) & ~(align - 1); + } + + AUD_reset (dsp.freq, 1 << dsp.fmt_stereo, fmt); + control (1); + dsp.speaker = 1; +} + +static void command (uint8_t cmd) +{ + char *msg; + + msg = (char *)-1; + + linfo ("%#x\n", cmd); + + if (cmd > 0xaf && cmd < 0xd0) { + if (cmd & 8) + goto error; + + switch (cmd >> 4) { + case 11: + case 12: + break; + default: + msg = "wrong bits"; + goto error; + } + dsp.needed_bytes = 3; + } + else { + switch (cmd) { + case 0x10: + dsp.needed_bytes = 1; + break; + + case 0x14: + dsp.needed_bytes = 2; + dsp.dma_buffer_size = 0; + break; + + case 0x20: + dsp.out_data[dsp.out_data_len++] = 0xff; + break; + + case 0x35: + lwarn ("MIDI commands not implemented\n"); + break; + + case 0x40: + dsp.freq = -1; + dsp.time_const = -1; + dsp.needed_bytes = 1; + break; + + case 0x41: + case 0x42: + dsp.freq = -1; + dsp.time_const = -1; + dsp.needed_bytes = 2; + break; + + case 0x47: /* Continue Auto-Initialize DMA 16bit */ + break; + + case 0x48: + dsp.needed_bytes = 2; + break; + + case 0x27: /* ????????? */ + case 0x4e: + return; + + case 0x80: + cmd = nocmd; + break; + + case 0x90: + case 0x91: + { + uint8_t d0; + + d0 = 4; + if (dsp.fmt_signed) d0 |= 16; + if (dsp.fmt_stereo) d0 |= 32; + dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1); + cmd = nocmd; + break; + } + + case 0xd0: /* XXX */ + control (0); + return; + + case 0xd1: + dsp.speaker = 1; + break; + + case 0xd3: + dsp.speaker = 0; + return; + + case 0xd4: + control (1); + break; + + case 0xd5: + control (0); + break; + + case 0xd6: + control (1); + break; + + case 0xd9: + control (0); + dsp.dma_auto = 0; + return; + + case 0xda: + control (0); + dsp.dma_auto = 0; + break; + + case 0xe0: + dsp.needed_bytes = 1; + break; + + case 0xe1: + dsp.out_data[dsp.out_data_len++] = sb.ver_lo; + dsp.out_data[dsp.out_data_len++] = sb.ver_hi; + return; + + case 0xf2: + dsp.out_data[dsp.out_data_len++] = 0xaa; + mixer.regs[0x82] |= 1; + pic_set_irq (sb.irq, 1); + return; + + default: + msg = "is unknown"; + goto error; + } + } + dsp.cmd = cmd; + return; + + error: + Fail ("%#x %s", cmd, msg); + return; +} + +static void complete (void) +{ + linfo ("complete command %#x, in_index %d, needed_bytes %d\n", + dsp.cmd, dsp.in_index, dsp.needed_bytes); + + if (dsp.cmd > 0xaf && dsp.cmd < 0xd0) { + int d0, d1, d2; + + d0 = dsp.in_data[0]; + d1 = dsp.in_data[1]; + d2 = dsp.in_data[2]; + + ldebug ("d0 = %d, d1 = %d, d2 = %d\n", + d0, d1, d2); + dma_cmd (dsp.cmd, d0, d1 + (d2 << 8)); + } + else { + switch (dsp.cmd) { + + case 0x10: + break; + + case 0x14: + { + int d0, d1; + int save_left; + int save_pos; + + d0 = dsp.in_data[0]; + d1 = dsp.in_data[1]; + + save_left = dsp.left_till_irq; + save_pos = dsp.dma_pos; + dma_cmd (0xc0, 0, d0 + (d1 << 8)); + dsp.left_till_irq = save_left; + dsp.dma_pos = save_pos; + + linfo ("set buffer size data[%d, %d] %d pos %d\n", + d0, d1, dsp.dma_buffer_size, dsp.dma_pos); + break; + } + + case 0x40: + dsp.time_const = dsp.in_data[0]; + linfo ("set time const %d\n", dsp.time_const); + break; + + case 0x41: + case 0x42: + dsp.freq = dsp.in_data[1] + (dsp.in_data[0] << 8); + linfo ("set freq %#x, %#x = %d\n", + dsp.in_data[1], dsp.in_data[0], dsp.freq); + break; + + case 0x48: + dsp.dma_buffer_size = dsp.in_data[1] + (dsp.in_data[0] << 8); + linfo ("set dma len %#x, %#x = %d\n", + dsp.in_data[1], dsp.in_data[0], dsp.dma_buffer_size); + break; + + case 0xe0: + dsp.out_data_len = 1; + linfo ("data = %#x\n", dsp.in_data[0]); + dsp.out_data[0] = dsp.in_data[0] ^ 0xff; + break; + + default: + goto error; + } + } + + dsp.cmd = -1; + return; + + error: + Fail ("unrecognized command %#x", dsp.cmd); +} + +static IO_WRITE_PROTO (dsp_write) +{ + int iport; + + iport = nport - sb.port; + + switch (iport) { + case 0x6: + if (0 == val) + dsp.v2x6 = 0; + else if ((1 == val) && (0 == dsp.v2x6)) { + dsp.v2x6 = 1; + dsp.out_data[dsp.out_data_len++] = 0xaa; + } + else + dsp.v2x6 = ~0; + break; + + case 0xc: /* write data or command | write status */ + if (0 == dsp.needed_bytes) { + command (val); + if (0 == dsp.needed_bytes) { + log_dsp (__func__); + } + } + else { + dsp.in_data[dsp.in_index++] = val; + if (dsp.in_index == dsp.needed_bytes) { + dsp.needed_bytes = 0; + dsp.in_index = 0; + complete (); + log_dsp (__func__); + } + } + break; + + default: + Fail ("(nport=%#x, val=%#x)", nport, val); + } +} + +static IO_READ_PROTO (dsp_read) +{ + char *msg; + int iport, retval; + + msg = (char *) -1; + iport = nport - sb.port; + + switch (iport) { + + case 0x6: /* reset */ + return 0; + + case 0xa: /* read data */ + if (dsp.out_data_len) { + retval = dsp.out_data[--dsp.out_data_len]; + } + else { +#if 1 + lwarn ("empty output buffer\n"); + retval = 0; +#else + msg = "empty output buffer"; + goto error; +#endif + } + break; + + case 0xc: /* 0 can write */ + retval = 0; + break; + + case 0xd: /* timer interrupt clear */ + goto error; + + case 0xe: /* data available status | irq 8 ack */ + retval = (0 == dsp.out_data_len) ? 0 : 0x80; + break; + + case 0xf: /* irq 16 ack */ + retval = 0xff; + mixer.regs[0x82] &= ~2; + ldebug ("16 ack\n"); + break; + + default: + goto error; + } + + if ((0xc != iport) && (0xe != iport)) { + ldebug ("(nport=%#x, size=%d) iport %#x = %#x\n", + nport, size, iport, retval); + } + + return retval; + + error: + Fail ("(nport=%#x) %s", nport, msg); +} + +static IO_WRITE_PROTO(mixer_write_indexb) +{ + mixer.nreg = val & 0xff; +} + +static IO_WRITE_PROTO(mixer_write_datab) +{ + mixer.regs[mixer.nreg] = val; +} + +static IO_WRITE_PROTO(mixer_write_indexw) +{ + mixer_write_indexb (env, nport, val & 0xff); + mixer_write_datab (env, nport, (val >> 8) & 0xff); +} + +static IO_READ_PROTO(mixer_read) +{ + return mixer.regs[mixer.nreg]; +} + +void SB16_run (void) +{ + if (0 == dsp.speaker) + return; + + AUD_run (); +} + +static int write_audio (uint32_t addr, int len, int size) +{ + int temp, net; + + temp = size; + + net = 0; + + while (temp) { + int left_till_end; + int to_copy; + int copied; + + left_till_end = len - dsp.dma_pos; + + to_copy = MIN (temp, left_till_end); + + copied = AUD_write ((void *) (addr + dsp.dma_pos), to_copy); + + temp -= copied; + dsp.dma_pos += copied; + + if (dsp.dma_pos == len) { + dsp.dma_pos = 0; + } + + net += copied; + + if (copied != to_copy) + return net; + } + + return net; +} + +static int SB_read_DMA (uint32_t addr, int size, int *_irq) +{ + int free, till, copy, written; + + if (0 == dsp.speaker) + return 0; + + if (dsp.left_till_irq < 0) { + dsp.left_till_irq += dsp.dma_buffer_size; + return dsp.dma_pos; + } + + free = AUD_get_free (); + + if ((free <= 0) || (0 == size)) { + return dsp.dma_pos; + } + + if (mix_block > 0) { + copy = MIN (free, mix_block); + } + else { + copy = free; + } + + till = dsp.left_till_irq; + + ldebug ("addr:%#010x free:%d till:%d size:%d\n", + addr, free, till, size); +/* linfo ("pos %d free %d size %d till %d copy %d auto %d noirq %d\n", */ +/* dsp.dma_pos, free, size, till, copy, dsp.dma_auto, noirq); */ + if (till <= copy) { + if (0 == dsp.dma_auto) { + copy = till; + } + } + + written = write_audio (addr, size, copy); + dsp.left_till_irq -= written; + AUD_adjust_estimate (free - written); + + if (dsp.left_till_irq <= 0) { + mixer.regs[0x82] |= mixer.regs[0x80]; + if (0 == noirq) + *_irq = sb.irq; + + if (0 == dsp.dma_auto) { + control (0); + } + } + + ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n", + dsp.dma_pos, free, size, dsp.left_till_irq, copy, + dsp.dma_buffer_size); + + if (dsp.left_till_irq <= 0) { + dsp.left_till_irq += dsp.dma_buffer_size; + } + + return dsp.dma_pos; +} + +static int dma_misc_handler (int moo) +{ + return -1; +} + +static int magic_of_irq (int irq) +{ + switch (irq) { + case 2: + return 1; + case 5: + return 2; + case 7: + return 4; + case 10: + return 8; + default: + log ("bad irq %d\n", irq); + return 2; + } +} + +static int irq_of_magic (int magic) +{ + switch (magic) { + case 1: + return 2; + case 2: + return 5; + case 4: + return 7; + case 8: + return 10; + default: + log ("bad irq magic %d\n", magic); + return 2; + } +} + +void SB16_init (void) +{ + int i; + static const uint8_t dsp_write_ports[] = {0x6, 0xc}; + static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; + + mixer.regs[0x0e] = ~0; + mixer.regs[0x80] = magic_of_irq (sb.irq); + mixer.regs[0x81] = 0x20 | (sb.dma << 1); + + DEREF (irq_of_magic); + + for (i = 0x30; i < 0x48; i++) { + mixer.regs[i] = 0x20; + } + + for (i = 0; i < LENOFA (dsp_write_ports); i++) { + register_ioport_write (sb.port + dsp_write_ports[i], 1, dsp_write, 1); + } + + for (i = 0; i < LENOFA (dsp_read_ports); i++) { + register_ioport_read (sb.port + dsp_read_ports[i], 1, dsp_read, 1); + } + + register_ioport_write (sb.port + 0x4, 1, mixer_write_indexb, 1); + register_ioport_write (sb.port + 0x4, 1, mixer_write_indexw, 2); + register_ioport_read (sb.port + 0x5, 1, mixer_read, 1); + register_ioport_write (sb.port + 0x5, 1, mixer_write_datab, 1); + + DMA_register_channel (sb.hdma, SB_read_DMA, dma_misc_handler); + DMA_register_channel (sb.dma, SB_read_DMA, dma_misc_handler); +} diff --git a/oss.c b/oss.c new file mode 100644 index 000000000..4210799eb --- /dev/null +++ b/oss.c @@ -0,0 +1,512 @@ +/* + * QEMU OSS Audio output driver + * + * Copyright (c) 2003 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vl.h" + +/* http://www.df.lth.se/~john_e/gems/gem002d.html */ +/* http://www.multi-platforms.com/Tips/PopCount.htm */ +static inline uint32_t popcount (uint32_t u) +{ + u = ((u&0x55555555) + ((u>>1)&0x55555555)); + u = ((u&0x33333333) + ((u>>2)&0x33333333)); + u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); + u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); + u = ( u&0x0000ffff) + (u>>16); + return u; +} + +static inline uint32_t lsbindex (uint32_t u) +{ + return popcount ((u&-u)-1); +} + +#define MIN(a, b) ((a)>(b)?(b):(a)) +#define MAX(a, b) ((a)<(b)?(b):(a)) + +#define DEREF(x) (void)x +#define log(...) fprintf (stderr, "oss: " __VA_ARGS__) +#define ERRFail(...) do { \ + int _errno = errno; \ + fprintf (stderr, "oss: " __VA_ARGS__); \ + fprintf (stderr, "system error: %s\n", strerror (_errno)); \ + abort (); \ +} while (0) +#define Fail(...) do { \ + fprintf (stderr, "oss: " __VA_ARGS__); \ + fprintf (stderr, "\n"); \ + abort (); \ +} while (0) + +#ifdef DEBUG_OSS +#define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__) +#define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__) +#define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__) +#else +#define lwarn(...) +#define linfo(...) +#define ldebug(...) +#endif + + +#define IOCTL(args) do { \ + int ret = ioctl args; \ + if (-1 == ret) { \ + ERRFail (#args); \ + } \ + ldebug ("ioctl " #args " = %d\n", ret); \ +} while (0) + +static int audio_fd = -1; +static int freq; +static int conf_nfrags = 4; +static int conf_fragsize; +static int nfrags; +static int fragsize; +static int bufsize; +static int nchannels; +static int fmt; +static int rpos; +static int wpos; +static int atom; +static int live; +static int leftover; +static int bytes_per_second; +static void *buf; +static enum {DONT, DSP, TID} estimate = TID; + +static void (*copy_fn)(void *, void *, int); + +static void copy_no_conversion (void *dst, void *src, int size) +{ + memcpy (dst, src, size); +} + +static void copy_u16_to_s16 (void *dst, void *src, int size) +{ + int i; + uint16_t *out, *in; + + out = dst; + in = src; + + for (i = 0; i < size / 2; i++) { + out[i] = in[i] + 0x8000; + } +} + +static void pab (struct audio_buf_info *abinfo) +{ + DEREF (abinfo); + + ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n" + "rpos %d, wpos %d, live %d\n", + abinfo->fragments, + abinfo->fragstotal, + abinfo->fragsize, + abinfo->bytes, + rpos, wpos, live); +} + +void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) +{ + int fmt_; + int bits16; + + if (-1 == audio_fd) { + AUD_open (rfreq, rnchannels, rfmt); + return; + } + + switch (rfmt) { + case AUD_FMT_U8: + bits16 = 0; + fmt_ = AFMT_U8; + copy_fn = copy_no_conversion; + atom = 1; + break; + + case AUD_FMT_S8: + Fail ("can not play 8bit signed"); + + case AUD_FMT_S16: + bits16 = 1; + fmt_ = AFMT_S16_LE; + copy_fn = copy_no_conversion; + atom = 2; + break; + + case AUD_FMT_U16: + bits16 = 1; + fmt_ = AFMT_S16_LE; + copy_fn = copy_u16_to_s16; + atom = 2; + break; + + default: + abort (); + } + + if ((fmt_ == fmt) && (bits16 + 1 == nchannels) && (rfreq == freq)) + return; + else { + AUD_open (rfreq, rnchannels, rfmt); + } +} + +void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) +{ + int fmt_; + int mmmmssss; + struct audio_buf_info abinfo; + int _fmt; + int _freq; + int _nchannels; + int bits16; + + bits16 = 0; + + switch (rfmt) { + case AUD_FMT_U8: + bits16 = 0; + fmt_ = AFMT_U8; + copy_fn = copy_no_conversion; + atom = 1; + break; + + case AUD_FMT_S8: + Fail ("can not play 8bit signed"); + + case AUD_FMT_S16: + bits16 = 1; + fmt_ = AFMT_S16_LE; + copy_fn = copy_no_conversion; + atom = 2; + break; + + case AUD_FMT_U16: + bits16 = 1; + fmt_ = AFMT_S16_LE; + copy_fn = copy_u16_to_s16; + atom = 2; + break; + + default: + abort (); + } + + if (buf) { + free (buf); + buf = 0; + } + + if (-1 != audio_fd) + close (audio_fd); + + audio_fd = open ("/dev/dsp", O_WRONLY | O_NONBLOCK); + if (-1 == audio_fd) { + ERRFail ("can not open /dev/dsp"); + } + + _fmt = fmt_; + _freq = rfreq; + _nchannels = rnchannels; + + IOCTL ((audio_fd, SNDCTL_DSP_RESET, 1)); + IOCTL ((audio_fd, SNDCTL_DSP_SAMPLESIZE, &_fmt)); + IOCTL ((audio_fd, SNDCTL_DSP_CHANNELS, &_nchannels)); + IOCTL ((audio_fd, SNDCTL_DSP_SPEED, &_freq)); + IOCTL ((audio_fd, SNDCTL_DSP_NONBLOCK)); + + /* from oss.pdf: + + The argument to this call is an integer encoded as 0xMMMMSSSS (in + hex). The 16 least significant bits determine the fragment + size. The size is 2^SSSS. For examp le SSSS=0008 gives fragment + size of 256 bytes (2^8). The minimum is 16 bytes (SSSS=4) and the + maximum is total_buffer_size/2. Some devices or processor + architectures may require larger fragments - in this case the + requested fragment size is automatically increased. + + So ahem... 4096 = 2^12, and grand total 0x0004000c + */ + + mmmmssss = (conf_nfrags << 16) | conf_fragsize; + IOCTL ((audio_fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); + + linfo ("_fmt = %d, fmt = %d\n" + "_channels = %d, rnchannels = %d\n" + "_freq = %d, freq = %d\n", + _fmt, fmt_, + _nchannels, rnchannels, + _freq, rfreq); + + if (_fmt != fmt_) { + Fail ("format %d != %d", _fmt, fmt_); + } + + if (_nchannels != rnchannels) { + Fail ("channels %d != %d", _nchannels, rnchannels); + } + + if (_freq != rfreq) { + Fail ("freq %d != %d", _freq, rfreq); + } + + IOCTL ((audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo)); + + nfrags = abinfo.fragstotal; + fragsize = abinfo.fragsize; + freq = _freq; + fmt = _fmt; + nchannels = rnchannels; + atom <<= nchannels >> 1; + bufsize = nfrags * fragsize; + + bytes_per_second = (freq << (nchannels >> 1)) << bits16; + + linfo ("bytes per second %d\n", bytes_per_second); + + linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", + abinfo.fragments, + abinfo.fragstotal, + abinfo.fragsize, + abinfo.bytes, + bufsize); + + if (NULL == buf) { + buf = malloc (bufsize); + if (NULL == buf) { + abort (); + } + } + + rpos = 0; + wpos = 0; + live = 0; +} + +int AUD_write (void *in_buf, int size) +{ + int to_copy, temp; + uint8_t *in, *out; + + to_copy = MIN (bufsize - live, size); + + temp = to_copy; + + in = in_buf; + out = buf; + + while (temp) { + int copy; + + copy = MIN (temp, bufsize - wpos); + copy_fn (out + wpos, in, copy); + + wpos += copy; + if (wpos == bufsize) { + wpos = 0; + } + + temp -= copy; + in += copy; + live += copy; + } + + return to_copy; +} + +void AUD_run (void) +{ + int res; + int bytes; + struct audio_buf_info abinfo; + + if (0 == live) + return; + + res = ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo); + + if (-1 == res) { + int err; + + err = errno; + lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err)); + } + + bytes = abinfo.bytes; + bytes = MIN (live, bytes); +#if 0 + bytes = (bytes / fragsize) * fragsize; +#endif + + while (bytes) { + int left, play, written; + + left = bufsize - rpos; + play = MIN (left, bytes); + written = write (audio_fd, (void *) ((uint32_t) buf + rpos), play); + + if (-1 == written) { + if (EAGAIN == errno || EINTR == errno) { + return; + } + else { + ERRFail ("write audio"); + } + } + + play = written; + live -= play; + rpos += play; + bytes -= play; + + if (rpos == bufsize) { + rpos = 0; + } + } +} + +static int get_dsp_bytes (void) +{ + int res; + struct count_info info; + + res = ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &info); + if (-1 == res) { + int err; + + err = errno; + lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err)); + return -1; + } + else { + ldebug ("bytes %d\n", info.bytes); + return info.bytes; + } +} + +void AUD_adjust_estimate (int _leftover) +{ + leftover = _leftover; +} + +int AUD_get_free (void) +{ + int free, elapsed; + + free = bufsize - live; + + if (0 == free) + return 0; + + elapsed = free; + switch (estimate) { + case DONT: + break; + + case DSP: + { + static int old_bytes; + int bytes; + + bytes = get_dsp_bytes (); + if (bytes <= 0) + return free; + + elapsed = bytes - old_bytes; + old_bytes = bytes; + ldebug ("dsp elapsed %d bytes\n", elapsed); + break; + } + + case TID: + { + static uint64_t old_ticks; + uint64_t ticks, delta; + uint64_t ua_elapsed; + uint64_t al_elapsed; + + ticks = cpu_get_ticks (); + delta = ticks - old_ticks; + old_ticks = ticks; + + ua_elapsed = (delta * bytes_per_second) / ticks_per_sec; + al_elapsed = ua_elapsed & ~3ULL; + + ldebug ("tid elapsed %llu bytes\n", ua_elapsed); + + if (al_elapsed > (uint64_t) INT_MAX) + elapsed = INT_MAX; + else + elapsed = al_elapsed; + + elapsed += leftover; + } + } + + if (elapsed > free) { + lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free); + return free; + } + else { + return elapsed; + } +} + +int AUD_get_live (void) +{ + return live; +} + +int AUD_get_buffer_size (void) +{ + return bufsize; +} + +void AUD_init (void) +{ + int fsp; + int _fragsize = 4096; + + DEREF (pab); + + fsp = _fragsize; + if (0 != (fsp & (fsp - 1))) { + Fail ("fragment size %d is not power of 2", fsp); + } + + conf_fragsize = lsbindex (fsp); +} diff --git a/vl.c b/vl.c index ff7ff89b9..9363f1e74 100644 --- a/vl.c +++ b/vl.c @@ -2095,6 +2095,9 @@ void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) reset_requested = 1; cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); break; + case 0xff: + /* ignore that - I don't know what is its use */ + break; default: fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); break; @@ -2598,6 +2601,10 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, gui_refresh_pending = 1; } + /* XXX: seems dangerous to run that here. */ + DMA_run(); + SB16_run(); + if (gui_refresh_pending || timer_irq_pending) { /* just exit from the cpu to have a chance to handle timers */ cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); @@ -2746,7 +2753,7 @@ void help(void) "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom 2 image\n" - "-boot [c|d] boot on hard disk or CD-ROM\n" + "-boot [c|d] boot on hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB\n" "-n script set network init script [default=%s]\n" @@ -3148,6 +3155,9 @@ int main(int argc, char **argv) ne2000_init(); ide_init(); kbd_init(); + AUD_init(); + DMA_init(); + SB16_init(); /* setup cpu signal handlers for MMU / self modifying code handling */ sigfillset(&act.sa_mask); diff --git a/vl.h b/vl.h index f2c8d6d0d..a65440fd6 100644 --- a/vl.h +++ b/vl.h @@ -27,6 +27,7 @@ /* vl.c */ struct CPUX86State; extern int reset_requested; +extern int64_t ticks_per_sec; typedef void (IOPortWriteFunc)(struct CPUX86State *env, uint32_t address, uint32_t data); typedef uint32_t (IOPortReadFunc)(struct CPUX86State *env, uint32_t address); @@ -35,6 +36,7 @@ void *get_mmap_addr(unsigned long size); int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); void pic_set_irq(int irq, int level); +int64_t cpu_get_ticks(void); void kbd_put_keycode(int keycode); @@ -107,4 +109,39 @@ void ide_init(void); void ide_set_geometry(int n, int cyls, int heads, int secs); void ide_set_cdrom(int n, int is_cdrom); +/* oss.c */ +typedef enum { + AUD_FMT_U8, + AUD_FMT_S8, + AUD_FMT_U16, + AUD_FMT_S16 +} audfmt_e; + +void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt); +void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt); +int AUD_write (void *in_buf, int size); +void AUD_run (void); +void AUD_adjust_estimate (int _leftover); +int AUD_get_free (void); +int AUD_get_live (void); +int AUD_get_buffer_size (void); +void AUD_init (void); + +/* dma.c */ +typedef int (*DMA_read_handler) (uint32_t addr, int size, int *irq); +typedef int (*DMA_misc_handler) (int); + +int DMA_get_channel_mode (int nchan); +void DMA_hold_DREQ (int nchan); +void DMA_release_DREQ (int nchan); +void DMA_run (void); +void DMA_init (void); +void DMA_register_channel (int nchan, + DMA_read_handler read_handler, + DMA_misc_handler misc_handler); + +/* sb16.c */ +void SB16_run (void); +void SB16_init (void); + #endif /* VL_H */ -- cgit v1.2.3 From 181f1558cd58f40f05ee0e4e46c08c692efb76fa Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Nov 2003 01:47:16 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@456 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 +++++++ qemu-doc.texi | 64 ++++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/Changelog b/Changelog index 5b6ce64b6..3c98c5cf6 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,13 @@ 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 version 0.5.0: diff --git a/qemu-doc.texi b/qemu-doc.texi index 0b8c069fc..c0a5bd048 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -281,11 +281,13 @@ VGA (hardware level, including all non standard modes) @item PS/2 mouse and keyboard @item -IDE disk interface (port=0x1f0, irq=14) +2 IDE interfaces with hard disk and CD-ROM support @item NE2000 network adapter (port=0x300, irq=9) @item -Serial port (port=0x3f8, irq=4) +Serial port +@item +Soundblaster 16 card @item PIC (interrupt controler) @item @@ -333,9 +335,8 @@ seen from the emulated kernel at IP address 172.20.0.1. @example > ./qemu.sh -connected to host network interface: tun0 -Uncompressing Linux... Ok, booting the kernel. -Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003 +Connected to host network interface: tun0 +Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 BIOS-provided physical RAM map: BIOS-e801: 0000000000000000 - 000000000009f000 (usable) BIOS-e801: 0000000000100000 - 0000000002000000 (usable) @@ -344,19 +345,19 @@ On node 0 totalpages: 8192 zone(0): 4096 pages. zone(1): 4096 pages. zone(2): 0 pages. -Kernel command line: root=/dev/hda ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe -ide_setup: ide1=noprobe +Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe console=ttyS0 ide_setup: ide2=noprobe ide_setup: ide3=noprobe ide_setup: ide4=noprobe ide_setup: ide5=noprobe Initializing CPU#0 -Detected 501.285 MHz processor. -Calibrating delay loop... 989.59 BogoMIPS -Memory: 29268k/32768k available (907k kernel code, 3112k reserved, 212k data, 52k init, 0k highmem) +Detected 2399.621 MHz processor. +Console: colour EGA 80x25 +Calibrating delay loop... 4744.80 BogoMIPS +Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, 0k highmem) Dentry cache hash table entries: 4096 (order: 3, 32768 bytes) Inode cache hash table entries: 2048 (order: 2, 16384 bytes) -Mount-cache hash table entries: 512 (order: 0, 4096 bytes) +Mount cache hash table entries: 512 (order: 0, 4096 bytes) Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes) Page-cache hash table entries: 8192 (order: 3, 32768 bytes) CPU: Intel Pentium Pro stepping 03 @@ -368,21 +369,24 @@ Initializing RT netlink socket apm: BIOS not found. Starting kswapd Journalled Block Device driver loaded +Detected PS/2 Mouse Port. pty: 256 Unix98 ptys configured Serial driver version 5.05c (2001-07-08) with no serial options enabled ttyS00 at 0x03f8 (irq = 4) is a 16450 -Uniform Multi-Platform E-IDE driver Revision: 6.31 -ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx -hda: QEMU HARDDISK, ATA DISK drive -ide0 at 0x1f0-0x1f7,0x3f6 on irq 14 -hda: 12288 sectors (6 MB) w/256KiB Cache, CHS=12/16/63 -Partition check: - hda: unknown partition table ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com) Last modified Nov 1, 2000 by Paul Gortmaker NE*000 ethercard probe at 0x300: 52 54 00 12 34 56 eth0: NE2000 found at 0x300, using IRQ 9. RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize +Uniform Multi-Platform E-IDE driver Revision: 7.00beta4-2.4 +ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx +hda: QEMU HARDDISK, ATA DISK drive +ide0 at 0x1f0-0x1f7,0x3f6 on irq 14 +hda: attached ide-disk driver. +hda: 20480 sectors (10 MB) w/256KiB Cache, CHS=20/16/63 +Partition check: + hda: +Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996 NET4: Linux TCP/IP 1.0 for NET4.0 IP Protocols: ICMP, UDP, TCP, IGMP IP: routing cache hash table of 512 buckets, 4Kbytes @@ -390,9 +394,15 @@ TCP: Hash tables configured (established 2048 bind 4096) NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended VFS: Mounted root (ext2 filesystem). -Freeing unused kernel memory: 52k freed -sh: can't access tty; job control turned off -# +Freeing unused kernel memory: 64k freed + +Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 + +QEMU Linux test distribution (based on Redhat 9) + +Type 'exit' to halt the system + +sh-2.05b# @end example @item @@ -464,10 +474,18 @@ General options: @table @option @item -hda file @item -hdb file -Use @var{file} as hard disk 0 or 1 image (@xref{disk_images}). +@item -hdc file +@item -hdd file +Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}). -@item -snapshot +@item -cdrom file +Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and +@option{-cdrom} at the same time). + +@item -boot [c|d] +Boot on hard disk (c) or CD-ROM (d). Hard disk boot is the default. +@item -snapshot Write to temporary files instead of disk image files. In this case, the raw disk image you use is not written back. You can however force the write back by pressing @key{C-a s} (@xref{disk_images}). -- cgit v1.2.3 From d71b9a8b2fa294c7689e43d97ee15dc56bb99853 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Nov 2003 02:48:18 +0000 Subject: fixed lmsw instruction git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@457 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index 7ce8f4bde..8457b6c23 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3921,6 +3921,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_op_lmsw_T0(); + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } break; case 7: /* invlpg */ -- cgit v1.2.3 From 77729c244527432e5795ae1811c2d0226b6cff9b Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Nov 2003 23:09:07 +0000 Subject: fixed pop %sp bug git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@458 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 8457b6c23..3ab09a328 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2304,8 +2304,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x58 ... 0x5f: /* pop */ ot = dflag ? OT_LONG : OT_WORD; gen_pop_T0(s); - gen_op_mov_reg_T0[ot][b & 7](); + /* NOTE: order is important for pop %sp */ gen_pop_update(s); + gen_op_mov_reg_T0[ot][b & 7](); break; case 0x60: /* pusha */ gen_pusha(s); @@ -2326,11 +2327,20 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x8f: /* pop Ev */ ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; gen_pop_T0(s); - s->popl_esp_hack = 2 << dflag; - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); - s->popl_esp_hack = 0; - gen_pop_update(s); + if (mod == 3) { + /* NOTE: order is important for pop %sp */ + gen_pop_update(s); + rm = modrm & 7; + gen_op_mov_reg_T0[ot][rm](); + } else { + /* NOTE: order is important too for MMU exceptions */ + s->popl_esp_hack = 2 << dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + s->popl_esp_hack = 0; + gen_pop_update(s); + } break; case 0xc8: /* enter */ { -- cgit v1.2.3 From f3f2d9be03816c991fff05ba30e6d9490005d282 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Nov 2003 23:15:36 +0000 Subject: call gate fix - verr and verw fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@459 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 070651530..7fd9a9a8f 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -19,6 +19,8 @@ */ #include "exec.h" +//#define DEBUG_PCALL + const uint8_t parity_table[256] = { CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, @@ -540,6 +542,27 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; uint32_t old_cs, old_ss, old_esp, old_eip; +#ifdef DEBUG_PCALL + if (loglevel) { + static int count; + fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d CS:IP=%04x:%08x CPL=%d\n", + count, intno, error_code, is_int, env->segs[R_CS].selector, env->eip, env->hflags & 3); +#if 0 + { + int i; + uint8_t *ptr; + printf(" code="); + ptr = env->segs[R_CS].base + env->eip; + for(i = 0; i < 16; i++) { + printf(" %02x", ldub(ptr + i)); + } + printf("\n"); + } +#endif + count++; + } +#endif + has_error_code = 0; if (!is_int && !is_hw) { switch(intno) { @@ -1260,11 +1283,22 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) new_cs = T0; new_eip = T1; +#ifdef DEBUG_PCALL + if (loglevel) { + fprintf(logfile, "lcall %04x:%08x\n", + new_cs, new_eip); + } +#endif if ((new_cs & 0xfffc) == 0) raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, new_cs) != 0) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); cpl = env->hflags & HF_CPL_MASK; +#ifdef DEBUG_PCALL + if (loglevel) { + fprintf(logfile, "desc=%08x:%08x\n", e1, e2); + } +#endif if (e2 & DESC_S_MASK) { if (!(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -1341,6 +1375,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); selector = e1 >> 16; offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); + param_count = e2 & 0x1f; if ((selector & 0xfffc) == 0) raise_exception_err(EXCP0D_GPF, 0); @@ -1357,6 +1392,11 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (!(e2 & DESC_C_MASK) && dpl < cpl) { /* to inner priviledge */ get_ss_esp_from_tss(&ss, &sp, dpl); +#ifdef DEBUG_PCALL + if (loglevel) + fprintf(logfile, "ss=%04x sp=%04x param_count=%d ESP=%x\n", + ss, sp, param_count, ESP); +#endif if ((ss & 0xfffc) == 0) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if ((ss & 3) != dpl) @@ -1373,7 +1413,6 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - param_count = e2 & 0x1f; push_size = ((param_count * 2) + 8) << shift; old_esp = ESP; @@ -1389,7 +1428,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) get_seg_limit(ss_e1, ss_e2), ss_e2); - if (!(env->segs[R_SS].flags & DESC_B_MASK)) + if (!(ss_e2 & DESC_B_MASK)) sp &= 0xffff; ssp = env->segs[R_SS].base + sp; if (shift) { @@ -1441,7 +1480,6 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) e2); cpu_x86_set_cpl(env, dpl); - /* from this point, not restartable if same priviledge */ if (!(env->segs[R_SS].flags & DESC_B_MASK)) ESP = (ESP & 0xffff0000) | (sp & 0xffff); else @@ -1838,7 +1876,7 @@ void helper_verr(void) if (dpl < cpl || dpl < rpl) return; } - /* ok */ + CC_SRC |= CC_Z; } void helper_verw(void) @@ -1866,7 +1904,7 @@ void helper_verw(void) if (!(e2 & DESC_W_MASK)) return; } - /* ok */ + CC_SRC |= CC_Z; } /* FPU helpers */ -- cgit v1.2.3 From 4ce900b44cb7542f49a898482ea9627011b02eb6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Nov 2003 15:46:05 +0000 Subject: make windows happier git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@460 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index 49ae488bb..a0bf8aba8 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1120,6 +1120,12 @@ static void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } ide_set_irq(s); break; + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + /* do sector number check ? */ + s->status = READY_STAT; + ide_set_irq(s); + break; case WIN_READ: case WIN_READ_ONCE: s->req_nb_sectors = 1; -- cgit v1.2.3 From 7dea1da4aebe3aa797fd37accf097d5d1a98d51d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Nov 2003 15:59:30 +0000 Subject: quick and dirty CMOS irq emulation (windows install uses it) - emm386 keyboard fix (need a better way...) - better serial emulation (windows install uses it) - LDT and TR caches init fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@461 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 118 insertions(+), 12 deletions(-) diff --git a/vl.c b/vl.c index 9363f1e74..a4f340398 100644 --- a/vl.c +++ b/vl.c @@ -61,6 +61,8 @@ /* output Bochs bios info messages */ //#define DEBUG_BIOS +//#define DEBUG_CMOS + /* debug PIC */ //#define DEBUG_PIC @@ -73,6 +75,8 @@ /* debug PC keyboard : only mouse */ //#define DEBUG_MOUSE +//#define DEBUG_SERIAL + #define PHYS_RAM_BASE 0xac000000 #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) @@ -197,7 +201,8 @@ struct __attribute__ ((packed)) linux_params { #define KERNEL_CS 0x10 #define KERNEL_DS 0x18 -#define MAX_IOPORTS 4096 +/* XXX: use a two level table to limit memory usage */ +#define MAX_IOPORTS 65536 static const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; @@ -461,6 +466,39 @@ void cmos_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) { if (addr == 0x70) { cmos_index = data & 0x7f; + } else { +#ifdef DEBUG_CMOS + printf("cmos: write index=0x%02x val=0x%02x\n", + cmos_index, data); +#endif + switch(addr) { + case RTC_SECONDS_ALARM: + case RTC_MINUTES_ALARM: + case RTC_HOURS_ALARM: + /* XXX: not supported */ + cmos_data[cmos_index] = data; + break; + case RTC_SECONDS: + case RTC_MINUTES: + case RTC_HOURS: + case RTC_DAY_OF_WEEK: + case RTC_DAY_OF_MONTH: + case RTC_MONTH: + case RTC_YEAR: + cmos_data[cmos_index] = data; + break; + case RTC_REG_A: + case RTC_REG_B: + cmos_data[cmos_index] = data; + break; + case RTC_REG_C: + case RTC_REG_D: + /* cannot write to them */ + break; + default: + cmos_data[cmos_index] = data; + break; + } } } @@ -471,13 +509,22 @@ uint32_t cmos_ioport_read(CPUX86State *env, uint32_t addr) if (addr == 0x70) { return 0xff; } else { - /* toggle update-in-progress bit for Linux (same hack as - plex86) */ ret = cmos_data[cmos_index]; - if (cmos_index == RTC_REG_A) + switch(cmos_index) { + case RTC_REG_A: + /* toggle update-in-progress bit for Linux (same hack as + plex86) */ cmos_data[RTC_REG_A] ^= 0x80; - else if (cmos_index == RTC_REG_C) + break; + case RTC_REG_C: + pic_set_irq(8, 0); cmos_data[RTC_REG_C] = 0x00; + break; + } +#ifdef DEBUG_CMOS + printf("cmos: read index=0x%02x val=0x%02x\n", + cmos_index, ret); +#endif return ret; } } @@ -675,7 +722,7 @@ int cpu_x86_get_pic_interrupt(CPUX86State *env) irq, (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); #endif -#ifdef DEBUG_PIC +#if defined(DEBUG_PIC) printf("pic_interrupt: irq=%d\n", irq); #endif @@ -1191,6 +1238,28 @@ void pit_init(void) #define UART_IIR_RDI 0x04 /* Receiver data interrupt */ #define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ +/* + * These are the definitions for the Modem Control Register + */ +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ +#define UART_MCR_OUT2 0x08 /* Out2 complement */ +#define UART_MCR_OUT1 0x04 /* Out1 complement */ +#define UART_MCR_RTS 0x02 /* RTS complement */ +#define UART_MCR_DTR 0x01 /* DTR complement */ + +/* + * These are the definitions for the Modem Status Register + */ +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ +#define UART_MSR_RI 0x40 /* Ring Indicator */ +#define UART_MSR_DSR 0x20 /* Data Set Ready */ +#define UART_MSR_CTS 0x10 /* Clear to Send */ +#define UART_MSR_DDCD 0x08 /* Delta DCD */ +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ +#define UART_MSR_DDSR 0x02 /* Delta DSR */ +#define UART_MSR_DCTS 0x01 /* Delta CTS */ +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ + #define UART_LSR_TEMT 0x40 /* Transmitter empty */ #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ #define UART_LSR_BI 0x10 /* Break interrupt indicator */ @@ -1209,6 +1278,9 @@ typedef struct SerialState { uint8_t lsr; /* read only */ uint8_t msr; uint8_t scr; + /* NOTE: this hidden state is necessary for tx irq generation as + it can be reset while reading iir */ + int thr_ipending; } SerialState; SerialState serial_ports[1]; @@ -1219,7 +1291,7 @@ void serial_update_irq(void) if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { s->iir = UART_IIR_RDI; - } else if ((s->lsr & UART_LSR_THRE) && (s->ier & UART_IER_THRI)) { + } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { s->iir = UART_IIR_THRI; } else { s->iir = UART_IIR_NO_INT; @@ -1238,12 +1310,16 @@ void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) int ret; addr &= 7; +#ifdef DEBUG_SERIAL + printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); +#endif switch(addr) { default: case 0: if (s->lcr & UART_LCR_DLAB) { s->divider = (s->divider & 0xff00) | val; } else { + s->thr_ipending = 0; s->lsr &= ~UART_LSR_THRE; serial_update_irq(); @@ -1251,6 +1327,7 @@ void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) do { ret = write(1, &ch, 1); } while (ret != 1); + s->thr_ipending = 1; s->lsr |= UART_LSR_THRE; s->lsr |= UART_LSR_TEMT; serial_update_irq(); @@ -1309,6 +1386,10 @@ uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr) break; case 2: ret = s->iir; + /* reset THR pending bit */ + if ((ret & 0x7) == UART_IIR_THRI) + s->thr_ipending = 0; + serial_update_irq(); break; case 3: ret = s->lcr; @@ -1320,12 +1401,23 @@ uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr) ret = s->lsr; break; case 6: - ret = s->msr; + if (s->mcr & UART_MCR_LOOP) { + /* in loopback, the modem output pins are connected to the + inputs */ + ret = (s->mcr & 0x0c) << 4; + ret |= (s->mcr & 0x02) << 3; + ret |= (s->mcr & 0x01) << 5; + } else { + ret = s->msr; + } break; case 7: ret = s->scr; break; } +#ifdef DEBUG_SERIAL + printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret); +#endif return ret; } @@ -1388,7 +1480,8 @@ void serial_init(void) SerialState *s = &serial_ports[0]; s->lsr = UART_LSR_TEMT | UART_LSR_THRE; - + s->iir = UART_IIR_NO_INT; + register_ioport_write(0x3f8, 8, serial_ioport_write, 1); register_ioport_read(0x3f8, 8, serial_ioport_read, 1); } @@ -2108,14 +2201,20 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) { KBDState *s = &kbd_state; KBDQueue *q; - int val; + int val, index; q = &s->queues[0]; /* first check KBD data */ if (q->count == 0) q = &s->queues[1]; /* then check AUX data */ if (q->count == 0) { - /* XXX: return something else ? */ - val = 0; + /* NOTE: if no data left, we return the last keyboard one + (needed for EMM386) */ + /* XXX: need a timer to do things correctly */ + q = &s->queues[0]; + index = q->rptr - 1; + if (index < 0) + index = KBD_QUEUE_SIZE - 1; + val = q->data[index]; } else { val = q->data[q->rptr]; if (++q->rptr == KBD_QUEUE_SIZE) @@ -2730,6 +2829,10 @@ int main_loop(void *opaque) pic_set_irq(0, 1); pic_set_irq(0, 0); timer_irq_pending = 0; + /* XXX: RTC test */ + if (cmos_data[RTC_REG_B] & 0x40) { + pic_set_irq(8, 1); + } } /* VGA */ @@ -3116,6 +3219,9 @@ int main(int argc, char **argv) env->idt.limit = 0xffff; env->gdt.limit = 0xffff; env->ldt.limit = 0xffff; + env->ldt.flags = DESC_P_MASK; + env->tr.limit = 0xffff; + env->tr.flags = DESC_P_MASK; /* not correct (CS base=0xffff0000) */ cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); -- cgit v1.2.3 From 891b38e446f3546b6642fb53b37d07f4c1242f9d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Nov 2003 16:06:03 +0000 Subject: more precise stack operations in call/int gates (16 bit wrapping is handled in all cases) - makes all call/int gates operations restartable in case of exception git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@462 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 388 +++++++++++++++++++++++++-------------------------- 1 file changed, 188 insertions(+), 200 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 7fd9a9a8f..861266fa1 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -531,16 +531,49 @@ void check_iol_DX(void) check_io(EDX & 0xffff, 4); } +static inline unsigned int get_sp_mask(unsigned int e2) +{ + if (e2 & DESC_B_MASK) + return 0xffffffff; + else + return 0xffff; +} + +/* XXX: add a is_user flag to have proper security support */ +#define PUSHW(ssp, sp, sp_mask, val)\ +{\ + sp -= 2;\ + stw_kernel((ssp) + (sp & (sp_mask)), (val));\ +} + +#define PUSHL(ssp, sp, sp_mask, val)\ +{\ + sp -= 4;\ + stl_kernel((ssp) + (sp & (sp_mask)), (val));\ +} + +#define POPW(ssp, sp, sp_mask, val)\ +{\ + val = lduw_kernel((ssp) + (sp & (sp_mask)));\ + sp += 2;\ +} + +#define POPL(ssp, sp, sp_mask, val)\ +{\ + val = ldl_kernel((ssp) + (sp & (sp_mask)));\ + sp += 4;\ +} + /* protected mode interrupt */ static void do_interrupt_protected(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw) { SegmentCache *dt; uint8_t *ptr, *ssp; - int type, dpl, selector, ss_dpl, cpl; + int type, dpl, selector, ss_dpl, cpl, sp_mask; int has_error_code, new_stack, shift; - uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; - uint32_t old_cs, old_ss, old_esp, old_eip; + uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; + uint32_t old_eip; #ifdef DEBUG_PCALL if (loglevel) { @@ -659,96 +692,80 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); new_stack = 1; + sp_mask = get_sp_mask(ss_e2); + ssp = get_seg_base(ss_e1, ss_e2); } else if ((e2 & DESC_C_MASK) || dpl == cpl) { /* to same priviledge */ new_stack = 0; + sp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + esp = ESP; } else { raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; /* avoid warning */ + sp_mask = 0; /* avoid warning */ + ssp = NULL; /* avoid warning */ + esp = 0; /* avoid warning */ } shift = type >> 3; + +#if 0 + /* XXX: check that enough room is available */ push_size = 6 + (new_stack << 2) + (has_error_code << 1); if (env->eflags & VM_MASK) push_size += 8; push_size <<= shift; - - /* XXX: check that enough room is available */ - if (new_stack) { - old_esp = ESP; - old_ss = env->segs[R_SS].selector; - ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - } else { - old_esp = 0; - old_ss = 0; - esp = ESP; - } +#endif if (is_int) old_eip = next_eip; else old_eip = env->eip; - old_cs = env->segs[R_CS].selector; - selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, - get_seg_base(e1, e2), - get_seg_limit(e1, e2), - e2); - cpu_x86_set_cpl(env, dpl); - env->eip = offset; - ESP = esp - push_size; - ssp = env->segs[R_SS].base + esp; if (shift == 1) { - int old_eflags; if (env->eflags & VM_MASK) { - ssp -= 4; - stl_kernel(ssp, env->segs[R_GS].selector); - ssp -= 4; - stl_kernel(ssp, env->segs[R_FS].selector); - ssp -= 4; - stl_kernel(ssp, env->segs[R_DS].selector); - ssp -= 4; - stl_kernel(ssp, env->segs[R_ES].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); } if (new_stack) { - ssp -= 4; - stl_kernel(ssp, old_ss); - ssp -= 4; - stl_kernel(ssp, old_esp); + PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); + PUSHL(ssp, esp, sp_mask, ESP); } - ssp -= 4; - old_eflags = compute_eflags(); - stl_kernel(ssp, old_eflags); - ssp -= 4; - stl_kernel(ssp, old_cs); - ssp -= 4; - stl_kernel(ssp, old_eip); + PUSHL(ssp, esp, sp_mask, compute_eflags()); + PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector); + PUSHL(ssp, esp, sp_mask, old_eip); if (has_error_code) { - ssp -= 4; - stl_kernel(ssp, error_code); + PUSHL(ssp, esp, sp_mask, error_code); } } else { if (new_stack) { - ssp -= 2; - stw_kernel(ssp, old_ss); - ssp -= 2; - stw_kernel(ssp, old_esp); + PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); + PUSHW(ssp, esp, sp_mask, ESP); } - ssp -= 2; - stw_kernel(ssp, compute_eflags()); - ssp -= 2; - stw_kernel(ssp, old_cs); - ssp -= 2; - stw_kernel(ssp, old_eip); + PUSHW(ssp, esp, sp_mask, compute_eflags()); + PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector); + PUSHW(ssp, esp, sp_mask, old_eip); if (has_error_code) { - ssp -= 2; - stw_kernel(ssp, error_code); + PUSHW(ssp, esp, sp_mask, error_code); } } + if (new_stack) { + ss = (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); + } + ESP = (ESP & ~sp_mask) | (esp & sp_mask); + + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); + env->eip = offset; + /* interrupt gate clear IF mask */ if ((type & 1) == 0) { env->eflags &= ~IF_MASK; @@ -780,12 +797,10 @@ static void do_interrupt_real(int intno, int is_int, int error_code, else old_eip = env->eip; old_cs = env->segs[R_CS].selector; - esp -= 2; - stw_kernel(ssp + (esp & 0xffff), compute_eflags()); - esp -= 2; - stw_kernel(ssp + (esp & 0xffff), old_cs); - esp -= 2; - stw_kernel(ssp + (esp & 0xffff), old_eip); + /* XXX: use SS segment size ? */ + PUSHW(ssp, esp, 0xffff, compute_eflags()); + PUSHW(ssp, esp, 0xffff, old_cs); + PUSHW(ssp, esp, 0xffff, old_eip); /* update processor state */ ESP = (ESP & ~0xffff) | (esp & 0xffff); @@ -1247,26 +1262,17 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) new_cs = T0; new_eip = T1; esp = ESP; - esp_mask = 0xffffffff; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - esp_mask = 0xffff; + esp_mask = get_sp_mask(env->segs[R_SS].flags); ssp = env->segs[R_SS].base; if (shift) { - esp -= 4; - stl_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector); - esp -= 4; - stl_kernel(ssp + (esp & esp_mask), next_eip); + PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector); + PUSHL(ssp, esp, esp_mask, next_eip); } else { - esp -= 2; - stw_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector); - esp -= 2; - stw_kernel(ssp + (esp & esp_mask), next_eip); + PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector); + PUSHW(ssp, esp, esp_mask, next_eip); } - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & ~0xffff) | (esp & 0xffff); - else - ESP = esp; + ESP = (ESP & ~esp_mask) | (esp & esp_mask); env->eip = new_eip; env->segs[R_CS].selector = new_cs; env->segs[R_CS].base = (uint8_t *)(new_cs << 4); @@ -1275,10 +1281,10 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) /* protected mode call */ void helper_lcall_protected_T0_T1(int shift, int next_eip) { - int new_cs, new_eip; + int new_cs, new_eip, new_stack, i; uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; - uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; - uint32_t old_ss, old_esp, val, i, limit; + uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; + uint32_t val, limit, old_sp_mask; uint8_t *ssp, *old_ssp; new_cs = T0; @@ -1319,30 +1325,21 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); sp = ESP; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; + sp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; if (shift) { - ssp -= 4; - stl_kernel(ssp, env->segs[R_CS].selector); - ssp -= 4; - stl_kernel(ssp, next_eip); + PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHL(ssp, sp, sp_mask, next_eip); } else { - ssp -= 2; - stw_kernel(ssp, env->segs[R_CS].selector); - ssp -= 2; - stw_kernel(ssp, next_eip); + PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHW(ssp, sp, sp_mask, next_eip); } - sp -= (4 << shift); limit = get_seg_limit(e1, e2); if (new_eip > limit) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); /* from this point, not restartable */ - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & 0xffff0000) | (sp & 0xffff); - else - ESP = sp; + ESP = (ESP & ~sp_mask) | (sp & sp_mask); cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, get_seg_base(e1, e2), limit, e2); EIP = new_eip; @@ -1413,77 +1410,63 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - push_size = ((param_count * 2) + 8) << shift; + // push_size = ((param_count * 2) + 8) << shift; - old_esp = ESP; - old_ss = env->segs[R_SS].selector; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - old_esp &= 0xffff; - old_ssp = env->segs[R_SS].base + old_esp; + old_sp_mask = get_sp_mask(env->segs[R_SS].flags); + old_ssp = env->segs[R_SS].base; - /* XXX: from this point not restartable */ - ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); - - if (!(ss_e2 & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; + sp_mask = get_sp_mask(ss_e2); + ssp = get_seg_base(ss_e1, ss_e2); if (shift) { - ssp -= 4; - stl_kernel(ssp, old_ss); - ssp -= 4; - stl_kernel(ssp, old_esp); - ssp -= 4 * param_count; - for(i = 0; i < param_count; i++) { - val = ldl_kernel(old_ssp + i * 4); - stl_kernel(ssp + i * 4, val); + PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector); + PUSHL(ssp, sp, sp_mask, ESP); + for(i = param_count - 1; i >= 0; i--) { + val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask)); + PUSHL(ssp, sp, sp_mask, val); } } else { - ssp -= 2; - stw_kernel(ssp, old_ss); - ssp -= 2; - stw_kernel(ssp, old_esp); - ssp -= 2 * param_count; - for(i = 0; i < param_count; i++) { - val = lduw_kernel(old_ssp + i * 2); - stw_kernel(ssp + i * 2, val); + PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector); + PUSHW(ssp, sp, sp_mask, ESP); + for(i = param_count - 1; i >= 0; i--) { + val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask)); + PUSHW(ssp, sp, sp_mask, val); } } + new_stack = 1; } else { /* to same priviledge */ - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; - push_size = (4 << shift); + sp = ESP; + sp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + // push_size = (4 << shift); + new_stack = 0; } if (shift) { - ssp -= 4; - stl_kernel(ssp, env->segs[R_CS].selector); - ssp -= 4; - stl_kernel(ssp, next_eip); + PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHL(ssp, sp, sp_mask, next_eip); } else { - ssp -= 2; - stw_kernel(ssp, env->segs[R_CS].selector); - ssp -= 2; - stw_kernel(ssp, next_eip); + PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHW(ssp, sp, sp_mask, next_eip); + } + + /* from this point, not restartable */ + + if (new_stack) { + ss = (ss & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, + ssp, + get_seg_limit(ss_e1, ss_e2), + ss_e2); } - sp -= push_size; selector = (selector & ~3) | dpl; cpu_x86_load_seg_cache(env, R_CS, selector, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); cpu_x86_set_cpl(env, dpl); - - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - ESP = (ESP & 0xffff0000) | (sp & 0xffff); - else - ESP = sp; + ESP = (ESP & ~sp_mask) | (sp & sp_mask); EIP = offset; } } @@ -1491,26 +1474,26 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) /* real and vm86 mode iret */ void helper_iret_real(int shift) { - uint32_t sp, new_cs, new_eip, new_eflags, new_esp; + uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; uint8_t *ssp; int eflags_mask; - sp = ESP & 0xffff; - ssp = env->segs[R_SS].base + sp; + sp_mask = 0xffff; /* XXXX: use SS segment size ? */ + sp = ESP; + ssp = env->segs[R_SS].base; if (shift == 1) { /* 32 bits */ - new_eflags = ldl_kernel(ssp + 8); - new_cs = ldl_kernel(ssp + 4) & 0xffff; - new_eip = ldl_kernel(ssp) & 0xffff; + POPL(ssp, sp, sp_mask, new_eip); + POPL(ssp, sp, sp_mask, new_cs); + new_cs &= 0xffff; + POPL(ssp, sp, sp_mask, new_eflags); } else { /* 16 bits */ - new_eflags = lduw_kernel(ssp + 4); - new_cs = lduw_kernel(ssp + 2); - new_eip = lduw_kernel(ssp); + POPW(ssp, sp, sp_mask, new_eip); + POPW(ssp, sp, sp_mask, new_cs); + POPW(ssp, sp, sp_mask, new_eflags); } - new_esp = sp + (6 << shift); - ESP = (ESP & 0xffff0000) | - (new_esp & 0xffff); + ESP = (ESP & ~sp_mask) | (sp & 0xffff); load_seg_vm(R_CS, new_cs); env->eip = new_eip; if (env->eflags & VM_MASK) @@ -1525,31 +1508,38 @@ void helper_iret_real(int shift) /* protected mode iret */ static inline void helper_ret_protected(int shift, int is_iret, int addend) { - uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; + uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask; uint32_t new_es, new_ds, new_fs, new_gs; uint32_t e1, e2, ss_e1, ss_e2; int cpl, dpl, rpl, eflags_mask; uint8_t *ssp; + sp_mask = get_sp_mask(env->segs[R_SS].flags); sp = ESP; - if (!(env->segs[R_SS].flags & DESC_B_MASK)) - sp &= 0xffff; - ssp = env->segs[R_SS].base + sp; + ssp = env->segs[R_SS].base; if (shift == 1) { /* 32 bits */ - if (is_iret) - new_eflags = ldl_kernel(ssp + 8); - new_cs = ldl_kernel(ssp + 4) & 0xffff; - new_eip = ldl_kernel(ssp); - if (is_iret && (new_eflags & VM_MASK)) - goto return_to_vm86; + POPL(ssp, sp, sp_mask, new_eip); + POPL(ssp, sp, sp_mask, new_cs); + new_cs &= 0xffff; + if (is_iret) { + POPL(ssp, sp, sp_mask, new_eflags); + if (new_eflags & VM_MASK) + goto return_to_vm86; + } } else { /* 16 bits */ + POPW(ssp, sp, sp_mask, new_eip); + POPW(ssp, sp, sp_mask, new_cs); if (is_iret) - new_eflags = lduw_kernel(ssp + 4); - new_cs = lduw_kernel(ssp + 2); - new_eip = lduw_kernel(ssp); + POPW(ssp, sp, sp_mask, new_eflags); } +#ifdef DEBUG_PCALL + if (loglevel) { + fprintf(logfile, "lret new %04x:%08x\n", + new_cs, new_eip); + } +#endif if ((new_cs & 0xfffc) == 0) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); if (load_segment(&e1, &e2, new_cs) != 0) @@ -1572,24 +1562,24 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); + sp += addend; if (rpl == cpl) { /* return to same priledge level */ cpu_x86_load_seg_cache(env, R_CS, new_cs, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); - new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; } else { /* return to different priviledge level */ - ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; if (shift == 1) { /* 32 bits */ - new_esp = ldl_kernel(ssp); - new_ss = ldl_kernel(ssp + 4) & 0xffff; + POPL(ssp, sp, sp_mask, new_esp); + POPL(ssp, sp, sp_mask, new_ss); + new_ss &= 0xffff; } else { /* 16 bits */ - new_esp = lduw_kernel(ssp); - new_ss = lduw_kernel(ssp + 2); + POPW(ssp, sp, sp_mask, new_esp); + POPW(ssp, sp, sp_mask, new_ss); } if ((new_ss & 3) != rpl) @@ -1615,12 +1605,10 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) get_seg_limit(ss_e1, ss_e2), ss_e2); cpu_x86_set_cpl(env, rpl); + sp = new_esp; + /* XXX: change sp_mask according to old segment ? */ } - if (env->segs[R_SS].flags & DESC_B_MASK) - ESP = new_esp; - else - ESP = (ESP & 0xffff0000) | - (new_esp & 0xffff); + ESP = (ESP & ~sp_mask) | (sp & sp_mask); env->eip = new_eip; if (is_iret) { /* NOTE: 'cpl' can be different from the current CPL */ @@ -1635,22 +1623,22 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) return; return_to_vm86: - new_esp = ldl_kernel(ssp + 12); - new_ss = ldl_kernel(ssp + 16); - new_es = ldl_kernel(ssp + 20); - new_ds = ldl_kernel(ssp + 24); - new_fs = ldl_kernel(ssp + 28); - new_gs = ldl_kernel(ssp + 32); + POPL(ssp, sp, sp_mask, new_esp); + POPL(ssp, sp, sp_mask, new_ss); + POPL(ssp, sp, sp_mask, new_es); + POPL(ssp, sp, sp_mask, new_ds); + POPL(ssp, sp, sp_mask, new_fs); + POPL(ssp, sp, sp_mask, new_gs); /* modify processor state */ load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); - load_seg_vm(R_CS, new_cs); + load_seg_vm(R_CS, new_cs & 0xffff); cpu_x86_set_cpl(env, 3); - load_seg_vm(R_SS, new_ss); - load_seg_vm(R_ES, new_es); - load_seg_vm(R_DS, new_ds); - load_seg_vm(R_FS, new_fs); - load_seg_vm(R_GS, new_gs); + load_seg_vm(R_SS, new_ss & 0xffff); + load_seg_vm(R_ES, new_es & 0xffff); + load_seg_vm(R_DS, new_ds & 0xffff); + load_seg_vm(R_FS, new_fs & 0xffff); + load_seg_vm(R_GS, new_gs & 0xffff); env->eip = new_eip; ESP = new_esp; -- cgit v1.2.3 From 8f2b1fb008a3bd8964f381c91adf7a7abeccd577 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Nov 2003 19:46:01 +0000 Subject: more hack for CMOS interruption (enable linux /dev/rtc not to hang) - auto boot on cdrom if only device present git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@463 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index a4f340398..550443f88 100644 --- a/vl.c +++ b/vl.c @@ -2830,7 +2830,7 @@ int main_loop(void *opaque) pic_set_irq(0, 0); timer_irq_pending = 0; /* XXX: RTC test */ - if (cmos_data[RTC_REG_B] & 0x40) { + if (cmos_data[RTC_REG_B] & 0x50) { pic_set_irq(8, 1); } } @@ -3058,6 +3058,10 @@ int main(int argc, char **argv) if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0') help(); + + /* boot to cd by default if no hard disk */ + if (hd_filename[0] == '\0' && boot_device == 'c') + boot_device = 'd'; /* init debug */ setvbuf(stdout, NULL, _IOLBF, 0); -- cgit v1.2.3 From 75175024757fd716dc0f8d50d9a8837b6d88143d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Nov 2003 20:18:52 +0000 Subject: fcmovx support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@464 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 09c662633..2bcc574db 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -658,6 +658,43 @@ void test_fenv(void) TEST_ENV(&float_env32, ""); } + +#define TEST_FCMOV(a, b, eflags, CC)\ +{\ + double res;\ + asm("push %3\n"\ + "popf\n"\ + "fcmov" CC " %2, %0\n"\ + : "=t" (res)\ + : "0" (a), "u" (b), "g" (eflags));\ + printf("fcmov%s eflags=0x%04x-> %f\n", \ + CC, eflags, res);\ +} + +void test_fcmov(void) +{ + double a, b; + int eflags, i; + + a = 1.0; + b = 2.0; + for(i = 0; i < 4; i++) { + eflags = 0; + if (i & 1) + eflags |= CC_C; + if (i & 2) + eflags |= CC_Z; + TEST_FCMOV(a, b, eflags, "b"); + TEST_FCMOV(a, b, eflags, "e"); + TEST_FCMOV(a, b, eflags, "be"); + TEST_FCMOV(a, b, eflags, "nb"); + TEST_FCMOV(a, b, eflags, "ne"); + TEST_FCMOV(a, b, eflags, "nbe"); + } + TEST_FCMOV(a, b, 0, "u"); + TEST_FCMOV(a, b, CC_P, "nu"); +} + void test_floats(void) { test_fops(2, 3); @@ -675,6 +712,9 @@ void test_floats(void) test_fbcd(1234567890123456); test_fbcd(-123451234567890); test_fenv(); + if (TEST_CMOV) { + test_fcmov(); + } } /**********************************************/ -- cgit v1.2.3 From de5eaa6452e8bace2251592475459f6d0fde2c15 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Nov 2003 23:18:17 +0000 Subject: static config for SDL git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@465 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 13 +++++++++---- configure | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile.target b/Makefile.target index 18daeaba1..b88887641 100644 --- a/Makefile.target +++ b/Makefile.target @@ -24,6 +24,9 @@ ifeq ($(TARGET_ARCH), i386) ifeq ($(ARCH), i386) PROGS+=$(QEMU_SYSTEM) +ifndef CONFIG_SOFTMMU +CONFIG_STATIC=y +endif endif ifeq ($(ARCH), ppc) @@ -179,17 +182,19 @@ endif VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o ifdef CONFIG_SDL VL_OBJS+=sdl.o -SDL_LIBS+=-L/usr/X11R6/lib -lX11 -lXext -lXv -ldl -lm +ifdef CONFIG_STATIC +SDL_LIBS:=$(SDL_STATIC_LIBS) +endif endif VL_LDFLAGS= # specific flags are needed for non soft mmu emulator -ifndef CONFIG_SOFTMMU -VL_LDFLAGS+=-static -Wl,-T,$(SRC_PATH)/i386-vl.ld -endif ifdef CONFIG_STATIC VL_LDFLAGS+=-static endif +ifndef CONFIG_SOFTMMU +VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld +endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) diff --git a/configure b/configure index 2f27deed6..3c9a29876 100755 --- a/configure +++ b/configure @@ -301,6 +301,7 @@ if test "$sdl" = "yes" ; then echo "CONFIG_SDL=yes" >> $config_mak echo "#define CONFIG_SDL 1" >> $config_h echo "SDL_LIBS=`sdl-config --libs`" >> $config_mak + echo "SDL_STATIC_LIBS=`sdl-config --static-libs`" >> $config_mak echo "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak fi echo -n "VERSION=" >>$config_mak -- cgit v1.2.3 From afa05eb15e71a0cca62bd75b5424119419b8a074 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Nov 2003 22:04:21 +0000 Subject: always completely redefine the TLB in case of MMU fault git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@466 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index fb8f254d4..9abf7ffc7 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -400,6 +400,9 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, if (prot & PROT_WRITE) { env->tlb_write[is_user][index].address = address; env->tlb_write[is_user][index].addend = addend; + } else { + env->tlb_write[is_user][index].address = -1; + env->tlb_write[is_user][index].addend = -1; } page_set_flags(vaddr, vaddr + TARGET_PAGE_SIZE, PAGE_VALID | PAGE_EXEC | prot); -- cgit v1.2.3 From a2cc3b24334643ddba2f9aa740392162285aa58b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Nov 2003 22:08:13 +0000 Subject: added fcmovxx support (fixes segfaults in some recent linux tools) - fixed irq inhibit logic : the irqs are inhibited only for one instruction after, even if the next one also inhibit irqs - stop translation after irq inhibition stops to give a chance to irqs (fixes install NT kernel startup) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@467 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 50 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 3ab09a328..b09f1b7a4 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1747,6 +1747,9 @@ static void gen_eob(DisasContext *s) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); + if (s->tb->flags & HF_INHIBIT_IRQ_MASK) { + gen_op_reset_inhibit_irq(); + } if (s->singlestep_enabled) { gen_op_debug(); } else if (s->tf) { @@ -2385,8 +2388,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_movl_seg_T0(s, reg, pc_start - s->cs_base); gen_pop_update(s); if (reg == R_SS) { - /* if reg == SS, inhibit interrupts/trace */ - gen_op_set_inhibit_irq(); + /* if reg == SS, inhibit interrupts/trace. */ + /* If several instructions disable interrupts, only the + _first_ does it */ + if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) + gen_op_set_inhibit_irq(); s->tf = 0; } if (s->is_jmp) { @@ -2457,7 +2463,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_movl_seg_T0(s, reg, pc_start - s->cs_base); if (reg == R_SS) { /* if reg == SS, inhibit interrupts/trace */ - gen_op_set_inhibit_irq(); + /* If several instructions disable interrupts, only the + _first_ does it */ + if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) + gen_op_set_inhibit_irq(); s->tf = 0; } if (s->is_jmp) { @@ -3176,6 +3185,21 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fpop(); s->cc_op = CC_OP_EFLAGS; break; + case 0x10 ... 0x13: /* fcmovxx */ + case 0x18 ... 0x1b: + { + int op1; + const static uint8_t fcmov_cc[8] = { + (JCC_B << 1), + (JCC_Z << 1), + (JCC_BE << 1), + (JCC_P << 1), + }; + op1 = fcmov_cc[op & 3] | ((op >> 3) & 1); + gen_setcc(s, op1); + gen_op_fcmov_ST0_STN_T0(opreg); + } + break; default: goto illegal_op; } @@ -3730,7 +3754,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_sti: gen_op_sti(); /* interruptions are enabled only the first insn after sti */ - gen_op_set_inhibit_irq(); + /* If several instructions disable interrupts, only the + _first_ does it */ + if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) + gen_op_set_inhibit_irq(); /* give a chance to handle pending irqs */ gen_op_jmp_im(s->pc - s->cs_base); gen_eob(s); @@ -4459,7 +4486,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, else dc->mem_index = 3; } - dc->jmp_opt = !(dc->tf || env->singlestep_enabled + dc->jmp_opt = !(dc->tf || env->singlestep_enabled || + (flags & HF_INHIBIT_IRQ_MASK) #ifndef CONFIG_SOFTMMU || (flags & HF_SOFTMMU_MASK) #endif @@ -4472,12 +4500,6 @@ static inline int gen_intermediate_code_internal(CPUState *env, pc_ptr = pc_start; lj = -1; - /* if irq were inhibited for the next instruction, we can disable - them here as it is simpler (otherwise jumps would have to - handled as special case) */ - if (flags & HF_INHIBIT_IRQ_MASK) { - gen_op_reset_inhibit_irq(); - } for(;;) { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { @@ -4504,7 +4526,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, break; /* if single step mode, we generate only one instruction and generate an exception */ - if (dc->tf || dc->singlestep_enabled) { + /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear + the flag and abort the translation to give the irqs a + change to be happen */ + if (dc->tf || dc->singlestep_enabled || + (flags & HF_INHIBIT_IRQ_MASK)) { gen_op_jmp_im(pc_ptr - dc->cs_base); gen_eob(dc); break; -- cgit v1.2.3 From 8004340674c4b014e18357acfbcaa24d10ec9c22 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Nov 2003 22:09:03 +0000 Subject: added fcmovxx support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@468 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-i386/op.c b/target-i386/op.c index d4742a384..a1e399516 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1776,6 +1776,14 @@ void OPPROTO op_fucomi_ST0_FT0(void) FORCE_RET(); } +void OPPROTO op_fcmov_ST0_STN_T0(void) +{ + if (T0) { + ST0 = ST(PARAM1); + } + FORCE_RET(); +} + void OPPROTO op_fadd_ST0_FT0(void) { ST0 += FT0; -- cgit v1.2.3 From 36bdbe5479cebb5765779a430d14daddddcab871 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Nov 2003 22:12:02 +0000 Subject: fixed TB linking in case of code invalidation (fixes random segfaults) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@469 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 13 ++++++++++++- exec-all.h | 1 + exec.c | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 1f08934cb..5bbace345 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -21,6 +21,8 @@ #include "exec.h" #include "disas.h" +int tb_invalidated_flag; + //#define DEBUG_EXEC //#define DEBUG_SIGNAL @@ -273,8 +275,17 @@ int cpu_exec(CPUState *env1) tb->tc_ptr = tc_ptr; tb->cs_base = (unsigned long)cs_base; tb->flags = flags; - /* XXX: an MMU exception can occur here */ + tb_invalidated_flag = 0; cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); + 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 */ + ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; + while (*ptb != NULL) + ptb = &(*ptb)->hash_next; + T0 = 0; + } *ptb = tb; tb->hash_next = NULL; tb_link(tb); diff --git a/exec-all.h b/exec-all.h index 7d0972e86..2023cf225 100644 --- a/exec-all.h +++ b/exec-all.h @@ -416,6 +416,7 @@ static inline int spin_trylock(spinlock_t *lock) extern spinlock_t tb_lock; +extern int tb_invalidated_flag; #if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY) diff --git a/exec.c b/exec.c index ca767e2af..9cc251f95 100644 --- a/exec.c +++ b/exec.c @@ -362,6 +362,8 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity) unsigned int h, n1; TranslationBlock *tb1, *tb2; + tb_invalidated_flag = 1; + /* remove the TB from the hash list */ h = tb_hash_func(tb->pc); tb_remove(&tb_hash[h], tb, -- cgit v1.2.3 From 9cdf757fd58b4c6b6bcc9847d3eef59e24b86c39 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Nov 2003 22:12:47 +0000 Subject: more fcmovxx tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@470 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 2bcc574db..821b79b65 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -692,6 +692,8 @@ void test_fcmov(void) TEST_FCMOV(a, b, eflags, "nbe"); } TEST_FCMOV(a, b, 0, "u"); + TEST_FCMOV(a, b, CC_P, "u"); + TEST_FCMOV(a, b, 0, "nu"); TEST_FCMOV(a, b, CC_P, "nu"); } -- cgit v1.2.3 From 6a8c397debd815e2f9b51577900b2ade16e51c3c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 Nov 2003 23:57:34 +0000 Subject: FTST instruction fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@471 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/op.c b/target-i386/op.c index a1e399516..04046fc0b 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1903,7 +1903,7 @@ void OPPROTO op_fldz_ST0(void) void OPPROTO op_fldz_FT0(void) { - ST0 = f15rk[0]; + FT0 = f15rk[0]; } /* associated heplers to reduce generated code length and to simplify -- cgit v1.2.3 From 79aceca54a8f12a70e23f418ae584e85093c8907 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Nov 2003 14:55:54 +0000 Subject: PowerPC support (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@472 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ppc/syscall.h | 129 +++ linux-user/ppc/syscall_nr.h | 258 +++++ target-ppc/cpu.h | 407 ++++++++ target-ppc/exec.h | 157 +++ target-ppc/helper.c | 262 +++++ target-ppc/op.c | 1116 ++++++++++++++++++++ target-ppc/op.tpl | 197 ++++ target-ppc/translate.c | 2376 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 4902 insertions(+) create mode 100644 linux-user/ppc/syscall.h create mode 100644 linux-user/ppc/syscall_nr.h create mode 100644 target-ppc/cpu.h create mode 100644 target-ppc/exec.h create mode 100644 target-ppc/helper.c create mode 100644 target-ppc/op.c create mode 100644 target-ppc/op.tpl create mode 100644 target-ppc/translate.c diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h new file mode 100644 index 000000000..e7ded9974 --- /dev/null +++ b/linux-user/ppc/syscall.h @@ -0,0 +1,129 @@ +/* + * PPC emulation for qemu: syscall definitions. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * 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 + */ + +/* XXX: ABSOLUTELY BUGGY: + * for now, this is quite just a cut-and-paste from i386 target... + */ + +/* default linux values for the selectors */ +#define __USER_DS (1) + +struct target_pt_regs { + unsigned long gpr[32]; + unsigned long nip; + unsigned long msr; + unsigned long orig_gpr3; /* Used for restarting system calls */ + unsigned long ctr; + unsigned long link; + unsigned long xer; + unsigned long ccr; + unsigned long mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + unsigned long trap; /* Reason for being here */ + unsigned long dar; /* Fault registers */ + unsigned long dsisr; + unsigned long result; /* Result of a system call */ +}; + +/* ioctls */ +struct target_revectored_struct { + target_ulong __map[8]; /* 256 bits */ +}; + +/* + * flags masks + */ + +/* ipcs */ + +#define TARGET_SEMOP 1 +#define TARGET_SEMGET 2 +#define TARGET_SEMCTL 3 +#define TARGET_MSGSND 11 +#define TARGET_MSGRCV 12 +#define TARGET_MSGGET 13 +#define TARGET_MSGCTL 14 +#define TARGET_SHMAT 21 +#define TARGET_SHMDT 22 +#define TARGET_SHMGET 23 +#define TARGET_SHMCTL 24 + +struct target_msgbuf { + int mtype; + char mtext[1]; +}; + +struct target_ipc_kludge { + unsigned int msgp; /* Really (struct msgbuf *) */ + int msgtyp; +}; + +struct target_ipc_perm { + int key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +struct target_msqid_ds { + struct target_ipc_perm msg_perm; + unsigned int msg_first; /* really struct target_msg* */ + unsigned int msg_last; /* really struct target_msg* */ + unsigned int msg_stime; /* really target_time_t */ + unsigned int msg_rtime; /* really target_time_t */ + unsigned int msg_ctime; /* really target_time_t */ + unsigned int wwait; /* really struct wait_queue* */ + unsigned int rwait; /* really struct wait_queue* */ + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + unsigned short msg_lspid; + unsigned short msg_lrpid; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; + int shm_segsz; + unsigned int shm_atime; /* really target_time_t */ + unsigned int shm_dtime; /* really target_time_t */ + unsigned int shm_ctime; /* really target_time_t */ + unsigned short shm_cpid; + unsigned short shm_lpid; + short shm_nattch; + unsigned short shm_npages; + unsigned long *shm_pages; + void *attaches; /* really struct shm_desc * */ +}; + +#define TARGET_IPC_RMID 0 +#define TARGET_IPC_SET 1 +#define TARGET_IPC_STAT 2 + +union target_semun { + int val; + unsigned int buf; /* really struct semid_ds * */ + unsigned int array; /* really unsigned short * */ + unsigned int __buf; /* really struct seminfo * */ + unsigned int __pad; /* really void* */ +}; + diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h new file mode 100644 index 000000000..b97189a2e --- /dev/null +++ b/linux-user/ppc/syscall_nr.h @@ -0,0 +1,258 @@ +/* + * This file contains the system call numbers. + */ +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown32 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid32 23 +#define TARGET_NR_getuid32 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid32 46 +#define TARGET_NR_getgid32 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid32 49 +#define TARGET_NR_getegid32 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid32 70 +#define TARGET_NR_setregid32 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups32 80 +#define TARGET_NR_setgroups32 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown32 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid32 138 +#define TARGET_NR_setfsgid32 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid32 164 +#define TARGET_NR_getresuid32 165 +#define TARGET_NR_query_module 166 +#define TARGET_NR_poll 167 +#define TARGET_NR_nfsservctl 168 +#define TARGET_NR_setresgid32 169 +#define TARGET_NR_getresgid32 170 +#define TARGET_NR_prctl 171 +#define TARGET_NR_rt_sigreturn 172 +#define TARGET_NR_rt_sigaction 173 +#define TARGET_NR_rt_sigprocmask 174 +#define TARGET_NR_rt_sigpending 175 +#define TARGET_NR_rt_sigtimedwait 176 +#define TARGET_NR_rt_sigqueueinfo 177 +#define TARGET_NR_rt_sigsuspend 178 +#define TARGET_NR_pread64 179 +#define TARGET_NR_pwrite64 180 +#define TARGET_NR_chown32 181 +#define TARGET_NR_getcwd 182 +#define TARGET_NR_capget 183 +#define TARGET_NR_capset 184 +#define TARGET_NR_sigaltstack 185 +#define TARGET_NR_sendfile 186 +#define TARGET_NR_getpmsg 187 /* some people actually want streams */ +#define TARGET_NR_putpmsg 188 /* some people actually want streams */ +#define TARGET_NR_vfork 189 +#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */ +#define TARGET_NR_readahead 191 +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_pciconfig_read 198 +#define TARGET_NR_pciconfig_write 199 +#define TARGET_NR_pciconfig_iobase 200 +#define TARGET_NR_multiplexer 201 +#define TARGET_NR_getdents64 202 +#define TARGET_NR_pivot_root 203 +#define TARGET_NR_fcntl64 204 +#define TARGET_NR_madvise 205 +#define TARGET_NR_mincore 206 +#define TARGET_NR_gettid 207 +#define TARGET_NR_tkill 208 +#define TARGET_NR_setxattr 209 +#define TARGET_NR_lsetxattr 210 +#define TARGET_NR_fsetxattr 211 +#define TARGET_NR_getxattr 212 +#define TARGET_NR_lgetxattr 213 +#define TARGET_NR_fgetxattr 214 +#define TARGET_NR_listxattr 215 +#define TARGET_NR_llistxattr 216 +#define TARGET_NR_flistxattr 217 +#define TARGET_NR_removexattr 218 +#define TARGET_NR_lremovexattr 219 +#define TARGET_NR_fremovexattr 220 +#define TARGET_NR_futex 221 +#define TARGET_NR_sched_setaffinity 222 +#define TARGET_NR_sched_getaffinity 223 +/* 224 currently unused */ +#define TARGET_NR_tuxcall 225 +#define TARGET_NR_sendfile64 226 +#define TARGET_NR_io_setup 227 +#define TARGET_NR_io_destroy 228 +#define TARGET_NR_io_getevents 229 +#define TARGET_NR_io_submit 230 +#define TARGET_NR_io_cancel 231 +#define TARGET_NR_set_tid_address 232 +#define TARGET_NR_fadvise64 233 +#define TARGET_NR_exit_group 234 +#define TARGET_NR_lookup_dcookie 235 +#define TARGET_NR_epoll_create 236 +#define TARGET_NR_epoll_ctl 237 +#define TARGET_NR_epoll_wait 238 +#define TARGET_NR_remap_file_pages 239 +#define TARGET_NR_timer_create 240 +#define TARGET_NR_timer_settime 241 +#define TARGET_NR_timer_gettime 242 +#define TARGET_NR_timer_getoverrun 243 +#define TARGET_NR_timer_delete 244 +#define TARGET_NR_clock_settime 245 +#define TARGET_NR_clock_gettime 246 +#define TARGET_NR_clock_getres 247 +#define TARGET_NR_clock_nanosleep 248 +#define TARGET_NR_swapcontext 249 +#define TARGET_NR_tgkill 250 +#define TARGET_NR_utimes 251 +#define TARGET_NR_statfs64 252 +#define TARGET_NR_fstatfs64 253 +#define TARGET_NR_fadvise64_64 254 diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h new file mode 100644 index 000000000..12cfc4648 --- /dev/null +++ b/target-ppc/cpu.h @@ -0,0 +1,407 @@ +/* + * PPC emulation cpu definitions for qemu. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * 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 (__CPU_PPC_H__) +#define __CPU_PPC_H__ + +#include +#include + +#include "cpu-defs.h" + +/*** Sign extend constants ***/ +/* 8 to 32 bits */ +static inline int32_t s_ext8 (uint8_t value) +{ + int8_t *tmp = &value; + + return *tmp; +} + +/* 16 to 32 bits */ +static inline int32_t s_ext16 (uint16_t value) +{ + int16_t *tmp = &value; + + return *tmp; +} + +/* 24 to 32 bits */ +static inline int32_t s_ext24 (uint32_t value) +{ + uint16_t utmp = (value >> 8) & 0xFFFF; + int16_t *tmp = &utmp; + + return (*tmp << 8) | (value & 0xFF); +} + +#include "config.h" +#include + +/* Floting point status and control register */ +#define FPSCR_FX 31 +#define FPSCR_FEX 30 +#define FPSCR_VX 29 +#define FPSCR_OX 28 +#define FPSCR_UX 27 +#define FPSCR_ZX 26 +#define FPSCR_XX 25 +#define FPSCR_VXSNAN 24 +#define FPSCR_VXISI 26 +#define FPSCR_VXIDI 25 +#define FPSCR_VXZDZ 21 +#define FPSCR_VXIMZ 20 + +#define FPSCR_VXVC 18 +#define FPSCR_FR 17 +#define FPSCR_FI 16 +#define FPSCR_FPRF 11 +#define FPSCR_VXSOFT 9 +#define FPSCR_VXSQRT 8 +#define FPSCR_VXCVI 7 +#define FPSCR_OE 6 +#define FPSCR_UE 5 +#define FPSCR_ZE 4 +#define FPSCR_XE 3 +#define FPSCR_NI 2 +#define FPSCR_RN 0 +#define fpscr_fx env->fpscr[FPSCR_FX] +#define fpscr_fex env->fpscr[FPSCR_FEX] +#define fpscr_vx env->fpscr[FPSCR_VX] +#define fpscr_ox env->fpscr[FPSCR_OX] +#define fpscr_ux env->fpscr[FPSCR_UX] +#define fpscr_zx env->fpscr[FPSCR_ZX] +#define fpscr_xx env->fpscr[FPSCR_XX] +#define fpscr_vsxnan env->fpscr[FPSCR_VXSNAN] +#define fpscr_vxisi env->fpscr[FPSCR_VXISI] +#define fpscr_vxidi env->fpscr[FPSCR_VXIDI] +#define fpscr_vxzdz env->fpscr[FPSCR_VXZDZ] +#define fpscr_vximz env->fpscr[FPSCR_VXIMZ] +#define fpscr_fr env->fpscr[FPSCR_FR] +#define fpscr_fi env->fpscr[FPSCR_FI] +#define fpscr_fprf env->fpscr[FPSCR_FPRF] +#define fpscr_vxsoft env->fpscr[FPSCR_VXSOFT] +#define fpscr_vxsqrt env->fpscr[FPSCR_VXSQRT] +#define fpscr_oe env->fpscr[FPSCR_OE] +#define fpscr_ue env->fpscr[FPSCR_UE] +#define fpscr_ze env->fpscr[FPSCR_ZE] +#define fpscr_xe env->fpscr[FPSCR_XE] +#define fpscr_ni env->fpscr[FPSCR_NI] +#define fpscr_rn env->fpscr[FPSCR_RN] + +/* Supervisor mode registers */ +/* Machine state register */ +#define MSR_POW 18 +#define MSR_ILE 16 +#define MSR_EE 15 +#define MSR_PR 14 +#define MSR_FP 13 +#define MSR_ME 12 +#define MSR_FE0 11 +#define MSR_SE 10 +#define MSR_BE 9 +#define MSR_FE1 8 +#define MSR_IP 6 +#define MSR_IR 5 +#define MSR_DR 4 +#define MSR_RI 1 +#define MSR_LE 0 +#define msr_pow env->msr[MSR_POW] +#define msr_ile env->msr[MSR_ILE] +#define msr_ee env->msr[MSR_EE] +#define msr_pr env->msr[MSR_PR] +#define msr_fp env->msr[MSR_FP] +#define msr_me env->msr[MSR_ME] +#define msr_fe0 env->msr[MSR_FE0] +#define msr_se env->msr[MSR_SE] +#define msr_be env->msr[MSR_BE] +#define msr_fe1 env->msr[MSR_FE1] +#define msr_ip env->msr[MSR_IP] +#define msr_ir env->msr[MSR_IR] +#define msr_dr env->msr[MSR_DR] +#define msr_ri env->msr[MSR_RI] +#define msr_le env->msr[MSR_LE] + +/* Segment registers */ +typedef struct ppc_sr_t { + uint32_t t:1; + uint32_t ks:1; + uint32_t kp:1; + uint32_t n:1; + uint32_t res:4; + uint32_t vsid:24; +} ppc_sr_t; + +typedef struct CPUPPCState { + /* general purpose registers */ + uint32_t gpr[32]; + /* floating point registers */ + uint64_t fpr[32]; + /* segment registers */ + ppc_sr_t sr[16]; + /* special purpose registers */ + uint32_t spr[1024]; + /* XER */ + uint8_t xer[32]; + /* Reservation address */ + uint32_t reserve; + /* machine state register */ + uint8_t msr[32]; + /* condition register */ + uint8_t crf[8]; + /* floating point status and control register */ + uint8_t fpscr[32]; + uint32_t nip; + /* CPU exception code */ + uint32_t exception; + + /* qemu dedicated */ + int interrupt_request; + jmp_buf jmp_env; + int exception_index; + int error_code; + int user_mode_only; /* user mode only simulation */ + struct TranslationBlock *current_tb; /* currently executing TB */ + + /* user data */ + void *opaque; +} CPUPPCState; + +CPUPPCState *cpu_ppc_init(void); +int cpu_ppc_exec(CPUPPCState *s); +void cpu_ppc_close(CPUPPCState *s); +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +struct siginfo; +int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, + void *puc); + +void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); + +#define TARGET_PAGE_BITS 12 +#include "cpu-all.h" + +#define ugpr(n) (env->gpr[n]) +#define fpr(n) (env->fpr[n]) + +#define SPR_ENCODE(sprn) \ +(((sprn) >> 5) | (((sprn) & 0x1F) << 5)) + +/* User mode SPR */ +#define spr(n) env->spr[n] +//#define XER spr[1] +#define XER env->xer +#define XER_SO 31 +#define XER_OV 30 +#define XER_CA 29 +#define XER_BC 0 +#define xer_so env->xer[XER_SO] +#define xer_ov env->xer[XER_OV] +#define xer_ca env->xer[XER_CA] +#define xer_bc env->xer[XER_BC] + +#define LR spr[SPR_ENCODE(8)] +#define CTR spr[SPR_ENCODE(9)] +/* VEA mode SPR */ +#define V_TBL spr[SPR_ENCODE(268)] +#define V_TBU spr[SPR_ENCODE(269)] +/* supervisor mode SPR */ +#define DSISR spr[SPR_ENCODE(18)] +#define DAR spr[SPR_ENCODE(19)] +#define DEC spr[SPR_ENCODE(22)] +#define SDR1 spr[SPR_ENCODE(25)] +typedef struct ppc_sdr1_t { + uint32_t htaborg:16; + uint32_t res:7; + uint32_t htabmask:9; +} ppc_sdr1_t; +#define SRR0 spr[SPR_ENCODE(26)] +#define SRR0_MASK 0xFFFFFFFC +#define SRR1 spr[SPR_ENCODE(27)] +#define SPRG0 spr[SPR_ENCODE(272)] +#define SPRG1 spr[SPR_ENCODE(273)] +#define SPRG2 spr[SPR_ENCODE(274)] +#define SPRG3 spr[SPR_ENCODE(275)] +#define EAR spr[SPR_ENCODE(282)] +typedef struct ppc_ear_t { + uint32_t e:1; + uint32_t res:25; + uint32_t rid:6; +} ppc_ear_t; +#define TBL spr[SPR_ENCODE(284)] +#define TBU spr[SPR_ENCODE(285)] +#define PVR spr[SPR_ENCODE(287)] +typedef struct ppc_pvr_t { + uint32_t version:16; + uint32_t revision:16; +} ppc_pvr_t; +#define IBAT0U spr[SPR_ENCODE(528)] +#define IBAT0L spr[SPR_ENCODE(529)] +#define IBAT1U spr[SPR_ENCODE(530)] +#define IBAT1L spr[SPR_ENCODE(531)] +#define IBAT2U spr[SPR_ENCODE(532)] +#define IBAT2L spr[SPR_ENCODE(533)] +#define IBAT3U spr[SPR_ENCODE(534)] +#define IBAT3L spr[SPR_ENCODE(535)] +#define DBAT0U spr[SPR_ENCODE(536)] +#define DBAT0L spr[SPR_ENCODE(537)] +#define DBAT1U spr[SPR_ENCODE(538)] +#define DBAT1L spr[SPR_ENCODE(539)] +#define DBAT2U spr[SPR_ENCODE(540)] +#define DBAT2L spr[SPR_ENCODE(541)] +#define DBAT3U spr[SPR_ENCODE(542)] +#define DBAT3L spr[SPR_ENCODE(543)] +typedef struct ppc_ubat_t { + uint32_t bepi:15; + uint32_t res:4; + uint32_t bl:11; + uint32_t vs:1; + uint32_t vp:1; +} ppc_ubat_t; +typedef struct ppc_lbat_t { + uint32_t brpn:15; + uint32_t res0:10; + uint32_t w:1; + uint32_t i:1; + uint32_t m:1; + uint32_t g:1; + uint32_t res1:1; + uint32_t pp:2; +} ppc_lbat_t; +#define DABR spr[SPR_ENCODE(1013)] +#define DABR_MASK 0xFFFFFFF8 +typedef struct ppc_dabr_t { + uint32_t dab:29; + uint32_t bt:1; + uint32_t dw:1; + uint32_t dr:1; +} ppc_dabr_t; +#define FPECR spr[SPR_ENCODE(1022)] +#define PIR spr[SPR_ENCODE(1023)] + +#define TARGET_PAGE_BITS 12 +#include "cpu-all.h" + +CPUPPCState *cpu_ppc_init(void); +int cpu_ppc_exec(CPUPPCState *s); +void cpu_ppc_close(CPUPPCState *s); +void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); + +/* Exeptions */ +enum { + EXCP_NONE = 0x00, + /* PPC hardware exceptions : exception vector / 0x100 */ + EXCP_RESET = 0x01, /* System reset */ + EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */ + EXCP_DSI = 0x03, /* Impossible memory access */ + EXCP_ISI = 0x04, /* Impossible instruction fetch */ + EXCP_EXTERNAL = 0x05, /* External interruption */ + EXCP_ALIGN = 0x06, /* Alignment exception */ + EXCP_PROGRAM = 0x07, /* Program exception */ + EXCP_NO_FP = 0x08, /* No floating point */ + EXCP_DECR = 0x09, /* Decrementer exception */ + EXCP_RESA = 0x0A, /* Implementation specific */ + EXCP_RESB = 0x0B, /* Implementation specific */ + EXCP_SYSCALL = 0x0C, /* System call */ + EXCP_TRACE = 0x0D, /* Trace exception (optional) */ + EXCP_FP_ASSIST = 0x0E, /* Floating-point assist (optional) */ +#if 0 + /* Exeption subtypes for EXCP_DSI */ + EXCP_DSI_TRANSLATE = 0x10301, /* Data address can't be translated */ + EXCP_DSI_NOTSUP = 0x10302, /* Access type not supported */ + EXCP_DSI_PROT = 0x10303, /* Memory protection violation */ + EXCP_DSI_EXTERNAL = 0x10304, /* External access disabled */ + EXCP_DSI_DABR = 0x10305, /* Data address breakpoint */ + /* Exeption subtypes for EXCP_ISI */ + EXCP_ISI_TRANSLATE = 0x10401, /* Code address can't be translated */ + EXCP_ISI_NOTSUP = 0x10402, /* Access type not supported */ + EXCP_ISI_PROT = 0x10403, /* Memory protection violation */ + EXCP_ISI_GUARD = 0x10404, /* Fetch into guarded memory */ + /* Exeption subtypes for EXCP_ALIGN */ + EXCP_ALIGN_FP = 0x10601, /* FP alignment exception */ + EXCP_ALIGN_LST = 0x10602, /* Unaligned memory load/store */ + EXCP_ALIGN_LE = 0x10603, /* Unaligned little-endian access */ + EXCP_ALIGN_PROT = 0x10604, /* Access cross protection boundary */ + EXCP_ALIGN_BAT = 0x10605, /* Access cross a BAT/seg boundary */ + EXCP_ALIGN_CACHE = 0x10606, /* Impossible dcbz access */ + /* Exeption subtypes for EXCP_PROGRAM */ + /* FP exceptions */ + EXCP_FP_OX = 0x10701, /* FP overflow */ + EXCP_FP_UX = 0x10702, /* FP underflow */ + EXCP_FP_ZX = 0x10703, /* FP divide by zero */ + EXCP_FP_XX = 0x10704, /* FP inexact */ + EXCP_FP_VXNAN = 0x10705, /* FP invalid SNaN op */ + EXCP_FP_VXISI = 0x10706, /* FP invalid infinite substraction */ + EXCP_FP_VXIDI = 0x10707, /* FP invalid infinite divide */ + EXCP_FP_VXZDZ = 0x10708, /* FP invalid zero divide */ + EXCP_FP_VXIMZ = 0x10709, /* FP invalid infinite * zero */ + EXCP_FP_VXVC = 0x1070A, /* FP invalid compare */ + EXCP_FP_VXSOFT = 0x1070B, /* FP invalid operation */ + EXCP_FP_VXSQRT = 0x1070C, /* FP invalid square root */ + EXCP_FP_VXCVI = 0x1070D, /* FP invalid integer conversion */ + /* Invalid instruction */ + EXCP_INVAL_INVAL = 0x10711, /* Invalid instruction */ + EXCP_INVAL_LSWX = 0x10712, /* Invalid lswx instruction */ + EXCP_INVAL_SPR = 0x10713, /* Invalid SPR access */ + EXCP_INVAL_FP = 0x10714, /* Unimplemented mandatory fp instr */ +#endif + EXCP_INVAL = 0x70, /* Invalid instruction */ + /* Privileged instruction */ + EXCP_PRIV = 0x71, /* Privileged instruction */ + /* Trap */ + EXCP_TRAP = 0x72, /* Trap */ + /* Special cases where we want to stop translation */ + EXCP_MTMSR = 0x103, /* mtmsr instruction: */ + /* may change privilege level */ + EXCP_BRANCH = 0x104, /* branch instruction */ +}; + +/* + * We need to put in some extra aux table entries to tell glibc what + * the cache block size is, so it can use the dcbz instruction safely. + */ +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 +/* A special ignored type value for PPC, for glibc compatibility. */ +#define AT_IGNOREPPC 22 +/* + * The requirements here are: + * - keep the final alignment of sp (sp & 0xf) + * - make sure the 32-bit value at the first 16 byte aligned position of + * AUXV is greater than 16 for glibc compatibility. + * AT_IGNOREPPC is used for that. + * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, + * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. + */ +#define DLINFO_ARCH_ITEMS 3 +#define ARCH_DLINFO \ +do { \ + /* \ + * Now handle glibc compatibility. \ + */ \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + \ + NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ + } while (0) +#endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h new file mode 100644 index 000000000..1bb7c1ddd --- /dev/null +++ b/target-ppc/exec.h @@ -0,0 +1,157 @@ +/* + * PPC emulation definitions for qemu. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * 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 (__PPC_H__) +#define __PPC_H__ + +#include "dyngen-exec.h" + +register struct CPUPPCState *env asm(AREG0); +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +register uint32_t T2 asm(AREG3); + +#define PARAM(n) ((uint32_t)PARAM##n) +#define SPARAM(n) ((int32_t)PARAM##n) + +#define RETURN() __asm__ __volatile__(""); + +#include "cpu.h" +#include "exec-all.h" + +static inline uint8_t ld8 (uint32_t EA) +{ + return *((uint8_t *)EA); +} + +static inline uint16_t ld16 (uint32_t EA) +{ + return __be16_to_cpu(*((uint16_t *)EA)); +} + +static inline uint16_t ld16r (uint32_t EA) +{ + return __le16_to_cpu(*((uint16_t *)EA)); +} + +static inline uint32_t ld32 (uint32_t EA) +{ + return __be32_to_cpu(*((uint32_t *)EA)); +} + +static inline uint32_t ld32r (uint32_t EA) +{ + return __le32_to_cpu(*((uint32_t *)EA)); +} + +static inline uint64_t ld64 (uint32_t EA) +{ + return __be64_to_cpu(*((uint64_t *)EA)); +} + +static inline uint64_t ld64r (uint32_t EA) +{ + return __le64_to_cpu(*((uint64_t *)EA)); +} + +static inline void st8 (uint32_t EA, uint8_t data) +{ + *((uint8_t *)EA) = data; +} + +static inline void st16 (uint32_t EA, uint16_t data) +{ + *((uint16_t *)EA) = __cpu_to_be16(data); +} + +static inline void st16r (uint32_t EA, uint16_t data) +{ + *((uint16_t *)EA) = __cpu_to_le16(data); +} + +static inline void st32 (uint32_t EA, uint32_t data) +{ + *((uint32_t *)EA) = __cpu_to_be32(data); +} + +static inline void st32r (uint32_t EA, uint32_t data) +{ + *((uint32_t *)EA) = __cpu_to_le32(data); +} + +static inline void st64 (uint32_t EA, uint64_t data) +{ + *((uint64_t *)EA) = __cpu_to_be64(data); +} + +static inline void st64r (uint32_t EA, uint64_t data) +{ + *((uint64_t *)EA) = __cpu_to_le64(data); +} + +static inline void set_CRn(int n, uint8_t value) +{ + env->crf[n] = value; +} + +static inline void set_carry (void) +{ + xer_ca = 1; +} + +static inline void reset_carry (void) +{ + xer_ca = 0; +} + +static inline void set_overflow (void) +{ + xer_so = 1; + xer_ov = 1; +} + +static inline void reset_overflow (void) +{ + xer_ov = 0; +} + +static inline uint32_t rotl (uint32_t i, int n) +{ + return ((i << n) | (i >> (32 - n))); +} + +void raise_exception (int exception_index); +void raise_exception_err (int exception_index, int error_code); + +uint32_t do_load_cr (void); +void do_store_cr (uint32_t crn, uint32_t value); +uint32_t do_load_xer (void); +void do_store_xer (uint32_t value); +uint32_t do_load_msr (void); +void do_store_msr (uint32_t msr_value); +uint32_t do_load_fpscr (void); +void do_store_fpscr (uint8_t mask, uint32_t fp); + +int32_t do_sraw(int32_t Ta, uint32_t Tb); +void do_lmw (int reg, uint32_t src); +void do_stmw (int reg, uint32_t dest); +void do_lsw (uint32_t reg, int count, uint32_t src); +void do_stsw (uint32_t reg, int count, uint32_t dest); + +#endif /* !defined (__PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c new file mode 100644 index 000000000..87e54111e --- /dev/null +++ b/target-ppc/helper.c @@ -0,0 +1,262 @@ +/* + * PPC emulation helpers for qemu. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "exec.h" + +extern FILE *logfile; + +void cpu_loop_exit(void) +{ + longjmp(env->jmp_env, 1); +} + +/* shortcuts to generate exceptions */ +void raise_exception_err (int exception_index, int error_code) +{ + env->exception_index = exception_index; + env->error_code = error_code; + + cpu_loop_exit(); +} + +void raise_exception (int exception_index) +{ + env->exception_index = exception_index; + env->error_code = 0; + + cpu_loop_exit(); +} + +/* Helpers for "fat" micro operations */ +uint32_t do_load_cr (void) +{ + return (env->crf[0] << 28) | + (env->crf[1] << 24) | + (env->crf[2] << 20) | + (env->crf[3] << 16) | + (env->crf[4] << 12) | + (env->crf[5] << 8) | + (env->crf[6] << 4) | + (env->crf[7] << 0); +} + +void do_store_cr (uint32_t crn, uint32_t value) +{ + int i, sh; + + for (i = 0, sh = 7; i < 8; i++, sh --) { + if (crn & (1 << sh)) + env->crf[i] = (value >> (sh * 4)) & 0xF; + } +} + +uint32_t do_load_xer (void) +{ + return (xer_so << XER_SO) | + (xer_ov << XER_OV) | + (xer_ca << XER_CA) | + (xer_bc << XER_BC); +} + +void do_store_xer (uint32_t value) +{ + xer_so = (value >> XER_SO) & 0x01; + xer_ov = (value >> XER_OV) & 0x01; + xer_ca = (value >> XER_CA) & 0x01; + xer_bc = (value >> XER_BC) & 0x1f; +} + +uint32_t do_load_msr (void) +{ + return (msr_pow << MSR_POW) | + (msr_ile << MSR_ILE) | + (msr_ee << MSR_EE) | + (msr_pr << MSR_PR) | + (msr_fp << MSR_FP) | + (msr_me << MSR_ME) | + (msr_fe0 << MSR_FE0) | + (msr_se << MSR_SE) | + (msr_be << MSR_BE) | + (msr_fe1 << MSR_FE1) | + (msr_ip << MSR_IP) | + (msr_ir << MSR_IR) | + (msr_dr << MSR_DR) | + (msr_ri << MSR_RI) | + (msr_le << MSR_LE); +} + +void do_store_msr (uint32_t msr_value) +{ + msr_pow = (msr_value >> MSR_POW) & 0x03; + msr_ile = (msr_value >> MSR_ILE) & 0x01; + msr_ee = (msr_value >> MSR_EE) & 0x01; + msr_pr = (msr_value >> MSR_PR) & 0x01; + msr_fp = (msr_value >> MSR_FP) & 0x01; + msr_me = (msr_value >> MSR_ME) & 0x01; + msr_fe0 = (msr_value >> MSR_FE0) & 0x01; + msr_se = (msr_value >> MSR_SE) & 0x01; + msr_be = (msr_value >> MSR_BE) & 0x01; + msr_fe1 = (msr_value >> MSR_FE1) & 0x01; + msr_ip = (msr_value >> MSR_IP) & 0x01; + msr_ir = (msr_value >> MSR_IR) & 0x01; + msr_dr = (msr_value >> MSR_DR) & 0x01; + msr_ri = (msr_value >> MSR_RI) & 0x01; + msr_le = (msr_value >> MSR_LE) & 0x01; +} + +/* The 32 MSB of the target fpr are undefined. They'll be zero... */ +uint32_t do_load_fpscr (void) +{ + return (fpscr_fx << FPSCR_FX) | + (fpscr_fex << FPSCR_FEX) | + (fpscr_vx << FPSCR_VX) | + (fpscr_ox << FPSCR_OX) | + (fpscr_ux << FPSCR_UX) | + (fpscr_zx << FPSCR_ZX) | + (fpscr_xx << FPSCR_XX) | + (fpscr_vsxnan << FPSCR_VXSNAN) | + (fpscr_vxisi << FPSCR_VXISI) | + (fpscr_vxidi << FPSCR_VXIDI) | + (fpscr_vxzdz << FPSCR_VXZDZ) | + (fpscr_vximz << FPSCR_VXIMZ) | + (fpscr_fr << FPSCR_FR) | + (fpscr_fi << FPSCR_FI) | + (fpscr_fprf << FPSCR_FPRF) | + (fpscr_vxsoft << FPSCR_VXSOFT) | + (fpscr_vxsqrt << FPSCR_VXSQRT) | + (fpscr_oe << FPSCR_OE) | + (fpscr_ue << FPSCR_UE) | + (fpscr_ze << FPSCR_ZE) | + (fpscr_xe << FPSCR_XE) | + (fpscr_ni << FPSCR_NI) | + (fpscr_rn << FPSCR_RN); +} + +/* We keep only 32 bits of input... */ +/* For now, this is COMPLETELY BUGGY ! */ +void do_store_fpscr (uint8_t mask, uint32_t fp) +{ + int i; + + for (i = 0; i < 7; i++) { + if ((mask & (1 << i)) == 0) + fp &= ~(0xf << (4 * i)); + } + if ((mask & 80) != 0) + fpscr_fx = (fp >> FPSCR_FX) & 0x01; + fpscr_fex = (fp >> FPSCR_FEX) & 0x01; + fpscr_vx = (fp >> FPSCR_VX) & 0x01; + fpscr_ox = (fp >> FPSCR_OX) & 0x01; + fpscr_ux = (fp >> FPSCR_UX) & 0x01; + fpscr_zx = (fp >> FPSCR_ZX) & 0x01; + fpscr_xx = (fp >> FPSCR_XX) & 0x01; + fpscr_vsxnan = (fp >> FPSCR_VXSNAN) & 0x01; + fpscr_vxisi = (fp >> FPSCR_VXISI) & 0x01; + fpscr_vxidi = (fp >> FPSCR_VXIDI) & 0x01; + fpscr_vxzdz = (fp >> FPSCR_VXZDZ) & 0x01; + fpscr_vximz = (fp >> FPSCR_VXIMZ) & 0x01; + fpscr_fr = (fp >> FPSCR_FR) & 0x01; + fpscr_fi = (fp >> FPSCR_FI) & 0x01; + fpscr_fprf = (fp >> FPSCR_FPRF) & 0x1F; + fpscr_vxsoft = (fp >> FPSCR_VXSOFT) & 0x01; + fpscr_vxsqrt = (fp >> FPSCR_VXSQRT) & 0x01; + fpscr_oe = (fp >> FPSCR_OE) & 0x01; + fpscr_ue = (fp >> FPSCR_UE) & 0x01; + fpscr_ze = (fp >> FPSCR_ZE) & 0x01; + fpscr_xe = (fp >> FPSCR_XE) & 0x01; + fpscr_ni = (fp >> FPSCR_NI) & 0x01; + fpscr_rn = (fp >> FPSCR_RN) & 0x03; +} + +int32_t do_sraw(int32_t value, uint32_t shift) +{ + int32_t ret; + + xer_ca = 0; + if (shift & 0x20) { + ret = (-1) * ((uint32_t)value >> 31); + if (ret < 0) + xer_ca = 1; + } else { + ret = value >> (shift & 0x1f); + if (ret < 0 && (value & ((1 << shift) - 1)) != 0) + xer_ca = 1; + } + + return ret; +} + +void do_lmw (int reg, uint32_t src) +{ + for (; reg <= 31; reg++, src += 4) + ugpr(reg) = ld32(src); +} + +void do_stmw (int reg, uint32_t dest) +{ + for (; reg <= 31; reg++, dest += 4) + st32(dest, ugpr(reg)); +} + +void do_lsw (uint32_t reg, int count, uint32_t src) +{ + uint32_t tmp; + int sh; + + for (; count > 3; count -= 4, src += 4) { + if (reg == 32) + reg = 0; + ugpr(reg++) = ld32(src); + } + if (count > 0) { + for (sh = 24, tmp = 0; count > 0; count--, src++, sh -= 8) { + if (reg == 32) + reg = 0; + tmp |= ld8(src) << sh; + if (sh == 0) { + sh = 32; + ugpr(reg++) = tmp; + tmp = 0; + } + } + ugpr(reg) = tmp; + } +} + +void do_stsw (uint32_t reg, int count, uint32_t dest) +{ + int sh; + + for (; count > 3; count -= 4, dest += 4) { + if (reg == 32) + reg = 0; + st32(dest, ugpr(reg++)); + } + if (count > 0) { + for (sh = 24; count > 0; count--, dest++, sh -= 8) { + if (reg == 32) + reg = 0; + st8(dest, (ugpr(reg) >> sh) & 0xFF); + if (sh == 0) { + sh = 32; + reg++; + } + } + } +} diff --git a/target-ppc/op.c b/target-ppc/op.c new file mode 100644 index 000000000..ecb991786 --- /dev/null +++ b/target-ppc/op.c @@ -0,0 +1,1116 @@ +/* + * PPC emulation micro-operations for qemu. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * 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" + +#define regs (env) +extern uint32_t __a; +extern uint32_t __b; +extern uint32_t __c; +extern uint32_t __d; +extern uint32_t __e; +extern uint32_t __f; +#define Ts0 (int32_t)T0 +#define Ts1 (int32_t)T1 +#define Ts2 (int32_t)T2 + +#include "op-multi.c" + +#define PPC_OP(name) void op_##name(void) + +/* PPC state maintenance operations */ +/* set_Rc0 */ +PPC_OP(set_Rc0) +{ + uint32_t tmp; + + if (Ts0 < 0) { + tmp = 0x08; + } else if (Ts0 > 0) { + tmp = 0x04; + } else { + tmp = 0x02; + } + set_CRn(0, tmp); + RETURN(); +} + +PPC_OP(set_Rc0_ov) +{ + uint32_t tmp; + + if (Ts0 < 0) { + tmp = 0x08; + } else if (Ts0 > 0) { + tmp = 0x04; + } else { + tmp = 0x02; + } + tmp |= xer_ov; + set_CRn(0, tmp); + RETURN(); +} + +/* reset_Rc0 */ +PPC_OP(reset_Rc0) +{ + set_CRn(0, 0x02 | xer_ov); + RETURN(); +} + +/* set_Rc0_1 */ +PPC_OP(set_Rc0_1) +{ + set_CRn(0, 0x04 | xer_ov); + RETURN(); +} + +PPC_OP(set_T0) +{ + T0 = PARAM(1); + RETURN(); +} + +PPC_OP(set_T1) +{ + T1 = PARAM(1); + RETURN(); +} + +PPC_OP(set_T2) +{ + T2 = PARAM(1); + RETURN(); +} + +/* Update time base */ +PPC_OP(update_tb) +{ + T0 = regs->spr[SPR_ENCODE(268)]; + T1 = T0; + T0 += PARAM(1); + if (T0 < T1) { + T1 = regs->spr[SPR_ENCODE(269)] + 1; + regs->spr[SPR_ENCODE(269)] = T1; + } + regs->spr[SPR_ENCODE(268)] = T0; + RETURN(); +} + +PPC_OP(raise_exception) +{ + raise_exception(PARAM(1)); + RETURN(); +} + +PPC_OP(exit_tb) +{ + EXIT_TB(); +} + +PPC_OP(load_cr) +{ + T0 = do_load_cr(); + RETURN(); +} + +PPC_OP(store_cr) +{ + do_store_cr(PARAM(1), T0); + RETURN(); +} + +PPC_OP(load_xer_cr) +{ + T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1); + RETURN(); +} + +PPC_OP(clear_xer_cr) +{ + xer_so = 0; + xer_ov = 0; + xer_ca = 0; + RETURN(); +} + +PPC_OP(load_xer_bc) +{ + T0 = xer_bc; + RETURN(); +} + +PPC_OP(load_xer) +{ + T0 = do_load_xer(); + RETURN(); +} + +PPC_OP(store_xer) +{ + do_store_xer(T0); + RETURN(); +} + +PPC_OP(load_msr) +{ + T0 = do_load_msr(); + RETURN(); +} + +PPC_OP(store_msr) +{ + do_store_msr(T0); + RETURN(); +} + +PPC_OP(load_lr) +{ + regs->LR = PARAM(1); + RETURN(); +} + +/* Set reservation */ +PPC_OP(set_reservation) +{ + regs->reserve = T1 & ~0x03; + RETURN(); +} + +/* Reset reservation */ +PPC_OP(reset_reservation) +{ + regs->reserve = 0; + RETURN(); +} + +/* crf operations */ +PPC_OP(getbit_T0) +{ + T0 = (T0 >> PARAM(1)) & 1; + RETURN(); +} + +PPC_OP(getbit_T1) +{ + T1 = (T1 >> PARAM(1)) & 1; + RETURN(); +} + +PPC_OP(setcrfbit) +{ + T1 = (T1 & PARAM(1)) | (T0 << PARAM(2)); + RETURN(); +} + +/* Branch */ +#define __PPC_OP_B(name, target) \ +PPC_OP(name) \ +{ \ + regs->nip = (target); \ + RETURN(); \ +} + +#define __PPC_OP_BL(name, target) \ +PPC_OP(name) \ +{ \ + regs->LR = PARAM(1); \ + regs->nip = (target); \ + RETURN(); \ +} + +#define PPC_OP_B(name, target) \ +__PPC_OP_B(name, target); \ +__PPC_OP_BL(name##l, target) + +#define __PPC_OP_BC(name, cond, target) \ +PPC_OP(name) \ +{ \ + if (cond) { \ + T0 = (target); \ + } else { \ + T0 = PARAM(1); \ + } \ + regs->nip = T0; \ + RETURN(); \ +} + +#define __PPC_OP_BCL(name, cond, target) \ +PPC_OP(name) \ +{ \ + if (cond) { \ + T0 = (target); \ + regs->LR = PARAM(1); \ + } else { \ + T0 = PARAM(1); \ + } \ + regs->nip = T0; \ + RETURN(); \ +} + +#define _PPC_OP_BC(name, namel, cond, target) \ +__PPC_OP_BC(name, cond, target); \ +__PPC_OP_BCL(namel, cond, target) + +/* Branch to target */ +#define PPC_OP_BC(name, cond) \ +_PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2)) + +PPC_OP_B(b, PARAM(1)); +PPC_OP_BC(ctr, (regs->CTR != 0)); +PPC_OP_BC(ctr_true, (regs->CTR != 0 && (T0 & PARAM(3)) != 0)); +PPC_OP_BC(ctr_false, (regs->CTR != 0 && (T0 & PARAM(3)) == 0)); +PPC_OP_BC(ctrz, (regs->CTR == 0)); +PPC_OP_BC(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(3)) != 0)); +PPC_OP_BC(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(3)) == 0)); +PPC_OP_BC(true, ((T0 & PARAM(3)) != 0)); +PPC_OP_BC(false, ((T0 & PARAM(3)) == 0)); + +/* Branch to CTR */ +#define PPC_OP_BCCTR(name, cond) \ +_PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->CTR & ~0x03) + +PPC_OP_B(bctr, regs->CTR & ~0x03); +PPC_OP_BCCTR(ctr, (regs->CTR != 0)); +PPC_OP_BCCTR(ctr_true, (regs->CTR != 0 && (T0 & PARAM(2)) != 0)); +PPC_OP_BCCTR(ctr_false, (regs->CTR != 0 && (T0 & PARAM(2)) == 0)); +PPC_OP_BCCTR(ctrz, (regs->CTR == 0)); +PPC_OP_BCCTR(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(2)) != 0)); +PPC_OP_BCCTR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0)); +PPC_OP_BCCTR(true, ((T0 & PARAM(2)) != 0)); +PPC_OP_BCCTR(false, ((T0 & PARAM(2)) == 0)); + +/* Branch to LR */ +#define PPC_OP_BCLR(name, cond) \ +_PPC_OP_BC(blr_##name, blrl_##name, cond, regs->LR & ~0x03) + +PPC_OP_B(blr, regs->LR & ~0x03); +PPC_OP_BCLR(ctr, (regs->CTR != 0)); +PPC_OP_BCLR(ctr_true, (regs->CTR != 0 && (T0 & PARAM(2)) != 0)); +PPC_OP_BCLR(ctr_false, (regs->CTR != 0 && (T0 & PARAM(2)) == 0)); +PPC_OP_BCLR(ctrz, (regs->CTR == 0)); +PPC_OP_BCLR(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(2)) != 0)); +PPC_OP_BCLR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0)); +PPC_OP_BCLR(true, ((T0 & PARAM(2)) != 0)); +PPC_OP_BCLR(false, ((T0 & PARAM(2)) == 0)); + +/* CTR maintenance */ +PPC_OP(dec_ctr) +{ + regs->CTR--; + RETURN(); +} + +/*** Integer arithmetic ***/ +/* add */ +PPC_OP(add) +{ + T0 += T1; + RETURN(); +} + +PPC_OP(addo) +{ + T2 = T0; + T0 += T1; + if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + RETURN(); +} + +/* add carrying */ +PPC_OP(addc) +{ + T2 = T0; + T0 += T1; + if (T0 < T2) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +PPC_OP(addco) +{ + T2 = T0; + T0 += T1; + if (T0 < T2) { + xer_ca = 1; + } else { + xer_ca = 0; + } + if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + RETURN(); +} + +/* add extended */ +/* candidate for helper (too long) */ +PPC_OP(adde) +{ + T2 = T0; + T0 += T1 + xer_ca; + if (T0 < T2 || (xer_ca == 1 && T0 == T2)) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +PPC_OP(addeo) +{ + T2 = T0; + T0 += T1 + xer_ca; + if (T0 < T2 || (xer_ca == 1 && T0 == T2)) { + xer_ca = 1; + } else { + xer_ca = 0; + } + if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + RETURN(); +} + +/* add immediate */ +PPC_OP(addi) +{ + T0 += PARAM(1); + RETURN(); +} + +/* add immediate carrying */ +PPC_OP(addic) +{ + T1 = T0; + T0 += PARAM(1); + if (T0 < T1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +/* add to minus one extended */ +PPC_OP(addme) +{ + T1 = T0; + T0 += xer_ca + (-1); + if (T1 != 0) + xer_ca = 1; + RETURN(); +} + +PPC_OP(addmeo) +{ + T1 = T0; + T0 += xer_ca + (-1); + if (T1 & (T1 ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + if (T1 != 0) + xer_ca = 1; + RETURN(); +} + +/* add to zero extended */ +PPC_OP(addze) +{ + T1 = T0; + T0 += xer_ca; + if (T0 < T1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +PPC_OP(addzeo) +{ + T1 = T0; + T0 += xer_ca; + if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + if (T0 < T1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +/* divide word */ +/* candidate for helper (too long) */ +PPC_OP(divw) +{ + if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + Ts0 = (-1) * (T0 >> 31); + } else { + Ts0 /= Ts1; + } + RETURN(); +} + +PPC_OP(divwo) +{ + if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + xer_so = 1; + xer_ov = 1; + T0 = (-1) * (T0 >> 31); + } else { + xer_ov = 0; + Ts0 /= Ts1; + } + RETURN(); +} + +/* divide word unsigned */ +PPC_OP(divwu) +{ + if (T1 == 0) { + T0 = 0; + } else { + T0 /= T1; + } + RETURN(); +} + +PPC_OP(divwuo) +{ + if (T1 == 0) { + xer_so = 1; + xer_ov = 1; + T0 = 0; + } else { + xer_ov = 0; + T0 /= T1; + } + RETURN(); +} + +/* multiply high word */ +PPC_OP(mulhw) +{ + Ts0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32; + RETURN(); +} + +/* multiply high word unsigned */ +PPC_OP(mulhwu) +{ + T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32; + RETURN(); +} + +/* multiply low immediate */ +PPC_OP(mulli) +{ + Ts0 *= SPARAM(1); + RETURN(); +} + +/* multiply low word */ +PPC_OP(mullw) +{ + T0 *= T1; + RETURN(); +} + +PPC_OP(mullwo) +{ + int64_t res = (int64_t)Ts0 * (int64_t)Ts1; + + if ((int32_t)res != res) { + xer_ov = 1; + xer_so = 1; + } else { + xer_ov = 0; + } + Ts0 = res; + RETURN(); +} + +/* negate */ +PPC_OP(neg) +{ + if (T0 != 0x80000000) { + Ts0 = -Ts0; + } + RETURN(); +} + +PPC_OP(nego) +{ + if (T0 == 0x80000000) { + xer_ov = 1; + xer_so = 1; + } else { + xer_ov = 0; + Ts0 = -Ts0; + } + RETURN(); +} + +/* substract from */ +PPC_OP(subf) +{ + T0 = T1 - T0; + RETURN(); +} + +PPC_OP(subfo) +{ + T2 = T0; + T0 = T1 - T0; + if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + RETURN(); +} + +/* substract from carrying */ +PPC_OP(subfc) +{ + T0 = T1 - T0; + if (T0 <= T1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +PPC_OP(subfco) +{ + T2 = T0; + T0 = T1 - T0; + if (T0 <= T1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + RETURN(); +} + +/* substract from extended */ +/* candidate for helper (too long) */ +PPC_OP(subfe) +{ + T0 = T1 + ~T0 + xer_ca; + if (T0 < T1 || (xer_ca == 1 && T0 == T1)) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +PPC_OP(subfeo) +{ + T2 = T0; + T0 = T1 + ~T0 + xer_ca; + if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + if (T0 < T1 || (xer_ca == 1 && T0 == T1)) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +/* substract from immediate carrying */ +PPC_OP(subfic) +{ + T0 = PARAM(1) + ~T0 + 1; + if (T0 <= PARAM(1)) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +/* substract from minus one extended */ +PPC_OP(subfme) +{ + T0 = ~T0 + xer_ca - 1; + + if (T0 != -1) + xer_ca = 1; + RETURN(); +} + +PPC_OP(subfmeo) +{ + T1 = T0; + T0 = ~T0 + xer_ca - 1; + if (~T1 & (~T1 ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + if (T1 != -1) + xer_ca = 1; + RETURN(); +} + +/* substract from zero extended */ +PPC_OP(subfze) +{ + T1 = ~T0; + T0 = T1 + xer_ca; + if (T0 < T1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +PPC_OP(subfzeo) +{ + T1 = T0; + T0 = ~T0 + xer_ca; + if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) { + xer_ov = 1; + xer_so = 1; + } else { + xer_ov = 0; + } + if (T0 < ~T1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +/*** Integer comparison ***/ +/* compare */ +PPC_OP(cmp) +{ + if (Ts0 < Ts1) { + T0 = 0x08; + } else if (Ts0 > Ts1) { + T0 = 0x04; + } else { + T0 = 0x02; + } + RETURN(); +} + +/* compare immediate */ +PPC_OP(cmpi) +{ + if (Ts0 < SPARAM(1)) { + T0 = 0x08; + } else if (Ts0 > SPARAM(1)) { + T0 = 0x04; + } else { + T0 = 0x02; + } + RETURN(); +} + +/* compare logical */ +PPC_OP(cmpl) +{ + if (T0 < T1) { + T0 = 0x08; + } else if (T0 > T1) { + T0 = 0x04; + } else { + T0 = 0x02; + } + RETURN(); +} + +/* compare logical immediate */ +PPC_OP(cmpli) +{ + if (T0 < PARAM(1)) { + T0 = 0x08; + } else if (T0 > PARAM(1)) { + T0 = 0x04; + } else { + T0 = 0x02; + } + RETURN(); +} + +/*** Integer logical ***/ +/* and */ +PPC_OP(and) +{ + T0 &= T1; + RETURN(); +} + +/* andc */ +PPC_OP(andc) +{ + T0 &= ~T1; + RETURN(); +} + +/* andi. */ +PPC_OP(andi_) +{ + T0 &= PARAM(1); + RETURN(); +} + +/* count leading zero */ +PPC_OP(cntlzw) +{ + T1 = T0; + for (T0 = 32; T1 > 0; T0--) + T1 = T1 >> 1; + RETURN(); +} + +/* eqv */ +PPC_OP(eqv) +{ + T0 = ~(T0 ^ T1); + RETURN(); +} + +/* extend sign byte */ +PPC_OP(extsb) +{ + Ts0 = s_ext8(Ts0); + RETURN(); +} + +/* extend sign half word */ +PPC_OP(extsh) +{ + Ts0 = s_ext16(Ts0); + RETURN(); +} + +/* nand */ +PPC_OP(nand) +{ + T0 = ~(T0 & T1); + RETURN(); +} + +/* nor */ +PPC_OP(nor) +{ + T0 = ~(T0 | T1); + RETURN(); +} + +/* or */ +PPC_OP(or) +{ + T0 |= T1; + RETURN(); +} + +/* orc */ +PPC_OP(orc) +{ + T0 |= ~T1; + RETURN(); +} + +/* ori */ +PPC_OP(ori) +{ + T0 |= PARAM(1); + RETURN(); +} + +/* xor */ +PPC_OP(xor) +{ + T0 ^= T1; + RETURN(); +} + +/* xori */ +PPC_OP(xori) +{ + T0 ^= PARAM(1); + RETURN(); +} + +/*** Integer rotate ***/ +/* rotate left word immediate then mask insert */ +PPC_OP(rlwimi) +{ + T0 = rotl(T0, PARAM(1) & PARAM(2)) | (T0 & PARAM(3)); + RETURN(); +} + +/* rotate left immediate then and with mask insert */ +PPC_OP(rotlwi) +{ + T0 = rotl(T0, PARAM(1)); + RETURN(); +} + +PPC_OP(slwi) +{ + T0 = T0 << PARAM(1); + RETURN(); +} + +PPC_OP(srwi) +{ + T0 = T0 >> PARAM(1); + RETURN(); +} + +/* rotate left word then and with mask insert */ +PPC_OP(rlwinm) +{ + T0 = rotl(T0, PARAM(1)) & PARAM(2); + RETURN(); +} + +PPC_OP(rotl) +{ + T0 = rotl(T0, T1); + RETURN(); +} + +PPC_OP(rlwnm) +{ + T0 = rotl(T0, T1) & PARAM(1); + RETURN(); +} + +/*** Integer shift ***/ +/* shift left word */ +PPC_OP(slw) +{ + if (T1 & 0x20) { + T0 = 0; + } else { + T0 = T0 << T1; + } + RETURN(); +} + +/* shift right algebraic word */ +PPC_OP(sraw) +{ + Ts0 = do_sraw(Ts0, T1); + RETURN(); +} + +/* shift right algebraic word immediate */ +PPC_OP(srawi) +{ + Ts1 = Ts0; + Ts0 = Ts0 >> PARAM(1); + if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} + +/* shift right word */ +PPC_OP(srw) +{ + if (T1 & 0x20) { + T0 = 0; + } else { + T0 = T0 >> T1; + } + RETURN(); +} + +/*** Floating-Point arithmetic ***/ + +/*** Floating-Point multiply-and-add ***/ + +/*** Floating-Point round & convert ***/ + +/*** Floating-Point compare ***/ + +/*** Floating-Point status & ctrl register ***/ + +/*** Integer load ***/ +#define ld16x(x) s_ext16(ld16(x)) +#define PPC_ILD_OPX(name, op) \ +PPC_OP(l##name##x_z) \ +{ \ + T1 = op(T0); \ + RETURN(); \ +} \ +PPC_OP(l##name##x) \ +{ \ + T0 += T1; \ + T1 = op(T0); \ + RETURN(); \ +} + +#define PPC_ILD_OP(name, op) \ +PPC_OP(l##name##_z) \ +{ \ + T1 = op(SPARAM(1)); \ + RETURN(); \ +} \ +PPC_OP(l##name) \ +{ \ + T0 += SPARAM(1); \ + T1 = op(T0); \ + RETURN(); \ +} \ +PPC_ILD_OPX(name, op) + +PPC_ILD_OP(bz, ld8); +PPC_ILD_OP(ha, ld16x); +PPC_ILD_OP(hz, ld16); +PPC_ILD_OP(wz, ld32); + +/*** Integer store ***/ +#define PPC_IST_OPX(name, op) \ +PPC_OP(st##name##x_z) \ +{ \ + op(T0, T1); \ + RETURN(); \ +} \ +PPC_OP(st##name##x) \ +{ \ + T0 += T1; \ + op(T0, T2); \ + RETURN(); \ +} + +#define PPC_IST_OP(name, op) \ +PPC_OP(st##name##_z) \ +{ \ + op(SPARAM(1), T0); \ + RETURN(); \ +} \ +PPC_OP(st##name) \ +{ \ + T0 += SPARAM(1); \ + op(T0, T1); \ + RETURN(); \ +} \ +PPC_IST_OPX(name, op); + +PPC_IST_OP(b, st8); +PPC_IST_OP(h, st16); +PPC_IST_OP(w, st32); + +/*** Integer load and store with byte reverse ***/ +PPC_ILD_OPX(hbr, ld16r); +PPC_ILD_OPX(wbr, ld32r); +PPC_IST_OPX(hbr, st16r); +PPC_IST_OPX(wbr, st32r); + +/*** Integer load and store multiple ***/ +PPC_OP(lmw) +{ + do_lmw(PARAM(1), SPARAM(2) + T0); + RETURN(); +} + +PPC_OP(stmw) +{ + do_stmw(PARAM(1), SPARAM(2) + T0); + RETURN(); +} + +/*** Integer load and store strings ***/ +PPC_OP(lswi) +{ + do_lsw(PARAM(1), PARAM(2), T0); + RETURN(); +} + +PPC_OP(lswx) +{ + do_lsw(PARAM(1), T0, T1 + T2); + RETURN(); +} + +PPC_OP(stswi_z) +{ + do_stsw(PARAM(1), PARAM(2), 0); + RETURN(); +} + +PPC_OP(stswi) +{ + do_stsw(PARAM(1), PARAM(2), T0); + RETURN(); +} + +PPC_OP(stswx_z) +{ + do_stsw(PARAM(1), T0, T1); + RETURN(); +} + +PPC_OP(stswx) +{ + do_stsw(PARAM(1), T0, T1 + T2); + RETURN(); +} diff --git a/target-ppc/op.tpl b/target-ppc/op.tpl new file mode 100644 index 000000000..f6f6d9817 --- /dev/null +++ b/target-ppc/op.tpl @@ -0,0 +1,197 @@ +/* + * PPC emulation micro-operations for qemu. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * 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 + */ + +/* Host registers definitions */ +$DEFH T 3 +/* PPC registers definitions */ +$DEF gpr 32 +$DEF fpr 32 +$DEF crf 8 +$DEF spr 1024 + +/* PPC registers <-> host registers move */ +/* GPR */ +$OP load_gpr_T0 gpr +{ + T0 = regs->gpra; + RETURN(); +} +$ENDOP + +$OP load_gpr_T1 gpr +{ + T1 = regs->gpra; + RETURN(); +} +$ENDOP + +$OP load_gpr_T2 gpr +{ + T2 = regs->gpra; + RETURN(); +} +$ENDOP + +$OP store_T0_gpr gpr +{ + regs->gpra = T0; + RETURN(); +} +$ENDOP + +$OP store_T1_gpr gpr +{ + regs->gpra = T1; + RETURN(); +} +$ENDOP + +$OP store_gpr_P gpr PARAM +{ + regs->gpra = PARAM(1); + RETURN(); +} +$ENDOP + +/* crf */ +$OP load_crf_T0 crf +{ + T0 = regs->crfa; + RETURN(); +} +$ENDOP + +$OP load_crf_T1 crf +{ + T1 = regs->crfa; + RETURN(); +} +$ENDOP + +$OP store_T0_crf crf +{ + regs->crfa = T0; + RETURN(); +} +$ENDOP + +$OP store_T1_crf crf +{ + regs->crfa = T1; + RETURN(); +} +$ENDOP + +/* SPR */ +$OP load_spr spr +{ + T0 = regs->spra; + RETURN(); +} +$ENDOP + +$OP store_spr spr +{ + regs->spra = T0; + RETURN(); +} +$ENDOP + +/* FPSCR */ +$OP load_fpscr fpr +{ + regs->fpra = do_load_fpscr(); + RETURN(); +} +$ENDOP + +$OP store_fpscr fpr PARAM +{ + do_store_fpscr(PARAM(1), regs->fpra); + RETURN(); +} +$ENDOP + +/*** Floating-point store ***/ +/* candidate for helper (too long on x86 host) */ +$OP stfd_z fpr PARAM +{ + st64(SPARAM(1), regs->fpra); + RETURN(); +} +$ENDOP + +/* candidate for helper (too long on x86 host) */ +$OP stfd fpr PARAM +{ + T0 += SPARAM(1); + st64(T0, regs->fpra); + RETURN(); +} +$ENDOP + +/* candidate for helper (too long on x86 host) */ +$OP stfdx_z fpr +{ + st64(T0, regs->fpra); + RETURN(); +} +$ENDOP +/* candidate for helper (too long on x86 host) */ +$OP stfdx fpr +{ + T0 += T1; + st64(T0, regs->fpra); + RETURN(); +} +$ENDOP + +/* candidate for helper (too long on x86 host) */ +$OP lfd_z fpr PARAM +{ + regs->fpra = ld64(SPARAM(1)); + RETURN(); +} +$ENDOP + +/* candidate for helper (too long) */ +$OP lfd fpr PARAM +{ + T0 += SPARAM(1); + regs->fpra = ld64(T0); + RETURN(); +} +$ENDOP + +$OP lfdx_z fpr +{ + regs->fpra = ld64(T0); + RETURN(); +} +$ENDOP + +$OP lfdx fpr +{ + T0 += T1; + regs->fpra = ld64(T0); + RETURN(); +} +$ENDOP +/*****************************************************************************/ diff --git a/target-ppc/translate.c b/target-ppc/translate.c new file mode 100644 index 000000000..5560e72b4 --- /dev/null +++ b/target-ppc/translate.c @@ -0,0 +1,2376 @@ +/* + * PPC emulation for qemu: main translation routines. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "dyngen-exec.h" +#include "cpu.h" +#include "exec.h" +#include "disas.h" + +//#define DO_SINGLE_STEP +//#define DO_STEP_FLUSH + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; + +#include "gen-op.h" +#include "select.h" + +static uint8_t spr_access[1024 / 2]; + +/* internal defines */ +typedef struct DisasContext { + struct TranslationBlock *tb; + uint32_t *nip; + uint32_t opcode; + int exception; + int retcode; + /* Time base */ + uint32_t tb_offset; + int supervisor; +} DisasContext; + +typedef struct opc_handler_t { + /* invalid bits */ + uint32_t inval; + /* handler */ + void (*handler)(DisasContext *ctx); +} opc_handler_t; + +#define SET_RETVAL(n) \ +do { \ + if ((n) != 0) { \ + ctx->exception = (n); \ + } \ + return; \ +} while (0) + +#define GET_RETVAL(func, __opcode) \ +({ \ + (func)(&ctx); \ + ctx.exception; \ +}) + +#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ +static void gen_##name (DisasContext *ctx); \ +GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \ +static void gen_##name (DisasContext *ctx) + +/* Instruction types */ +enum { + PPC_INTEGER = 0x0001, /* CPU has integer operations instructions */ + PPC_FLOAT = 0x0002, /* CPU has floating point operations instructions */ + PPC_FLOW = 0x0004, /* CPU has flow control instructions */ + PPC_MEM = 0x0008, /* CPU has virtual memory instructions */ + PPC_MISC = 0x0010, /* CPU has spr/msr access instructions */ + PPC_EXTERN = 0x0020, /* CPU has external control instructions */ + PPC_SEGMENT = 0x0040, /* CPU has memory segment instructions */ +}; + +typedef struct opcode_t { + unsigned char opc1, opc2, opc3; + uint32_t type; + opc_handler_t handler; +} opcode_t; + +/* XXX: move that elsewhere */ +extern FILE *logfile; +extern int loglevel; + +/* XXX: shouldn't stay all alone here ! */ +static int reserve = 0; + +/*** Instruction decoding ***/ +#define EXTRACT_HELPER(name, shift, nb) \ +static inline uint32_t name (uint32_t opcode) \ +{ \ + return (opcode >> (shift)) & ((1 << (nb)) - 1); \ +} + +#define EXTRACT_SHELPER(name, shift, nb) \ +static inline int32_t name (uint32_t opcode) \ +{ \ + return s_ext16((opcode >> (shift)) & ((1 << (nb)) - 1)); \ +} + +/* Opcode part 1 */ +EXTRACT_HELPER(opc1, 26, 6); +/* Opcode part 2 */ +EXTRACT_HELPER(opc2, 1, 5); +/* Opcode part 3 */ +EXTRACT_HELPER(opc3, 6, 5); +/* Update Cr0 flags */ +EXTRACT_HELPER(Rc, 0, 1); +/* Destination */ +EXTRACT_HELPER(rD, 21, 5); +/* Source */ +EXTRACT_HELPER(rS, 21, 5); +/* First operand */ +EXTRACT_HELPER(rA, 16, 5); +/* Second operand */ +EXTRACT_HELPER(rB, 11, 5); +/* Third operand */ +EXTRACT_HELPER(rC, 6, 5); +/*** Get CRn ***/ +EXTRACT_HELPER(crfD, 23, 3); +EXTRACT_HELPER(crfS, 18, 3); +EXTRACT_HELPER(crbD, 21, 5); +EXTRACT_HELPER(crbA, 16, 5); +EXTRACT_HELPER(crbB, 11, 5); +/* SPR / TBL */ +EXTRACT_HELPER(SPR, 11, 10); +/*** Get constants ***/ +EXTRACT_HELPER(IMM, 12, 8); +/* 16 bits signed immediate value */ +EXTRACT_SHELPER(SIMM, 0, 16); +/* 16 bits unsigned immediate value */ +EXTRACT_HELPER(UIMM, 0, 16); +/* Bit count */ +EXTRACT_HELPER(NB, 11, 5); +/* Shift count */ +EXTRACT_HELPER(SH, 11, 5); +/* Mask start */ +EXTRACT_HELPER(MB, 6, 5); +/* Mask end */ +EXTRACT_HELPER(ME, 1, 5); + +EXTRACT_HELPER(CRM, 12, 8); +EXTRACT_HELPER(FM, 17, 8); +EXTRACT_HELPER(SR, 16, 4); +/*** Jump target decoding ***/ +/* Displacement */ +EXTRACT_SHELPER(d, 0, 16); +/* Immediate address */ +static inline uint32_t LI (uint32_t opcode) +{ + return (opcode >> 0) & 0x03FFFFFC; +} + +static inline uint32_t BD (uint32_t opcode) +{ + return (opcode >> 0) & 0xFFFC; +} + +EXTRACT_HELPER(BO, 21, 5); +EXTRACT_HELPER(BI, 16, 5); +/* Absolute/relative address */ +EXTRACT_HELPER(AA, 1, 1); +/* Link */ +EXTRACT_HELPER(LK, 0, 1); + +/* Create a mask between and bits */ +static inline uint32_t MASK (uint32_t start, uint32_t end) +{ + uint32_t ret; + + ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1); + if (start > end) + return ~ret; + + return ret; +} + +#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ +__attribute__ ((section(".opcodes"), unused)) \ +static opcode_t opc_##name = { \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .type = _typ, \ + .handler = { \ + .inval = invl, \ + .handler = &gen_##name, \ + }, \ +} + +#define GEN_OPCODE_MARK(name) \ +__attribute__ ((section(".opcodes"), unused)) \ +static opcode_t opc_##name = { \ + .opc1 = 0xFF, \ + .opc2 = 0xFF, \ + .opc3 = 0xFF, \ + .type = 0x00, \ + .handler = { \ + .inval = 0x00000000, \ + .handler = NULL, \ + }, \ +} + +/* Start opcode list */ +GEN_OPCODE_MARK(start); + +/* Invalid instruction */ +GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, 0) +{ + /* Branch to next instruction to force nip update */ + gen_op_b((uint32_t)ctx->nip); + SET_RETVAL(EXCP_INVAL); +} + +static opc_handler_t invalid_handler = { + .inval = 0xFFFFFFFF, + .handler = gen_invalid, +}; + +/*** Integer arithmetic ***/ +#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval) \ +GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_##name(); \ + if (Rc(ctx->opcode) != 0) \ + gen_op_set_Rc0(); \ + gen_op_store_T0_gpr(rD(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \ +GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_##name(); \ + if (Rc(ctx->opcode) != 0) \ + gen_op_set_Rc0_ov(); \ + gen_op_store_T0_gpr(rD(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \ +GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_##name(); \ + if (Rc(ctx->opcode) != 0) \ + gen_op_set_Rc0(); \ + gen_op_store_T0_gpr(rD(ctx->opcode)); \ + SET_RETVAL(0); \ +} +#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \ +GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_##name(); \ + if (Rc(ctx->opcode) != 0) \ + gen_op_set_Rc0_ov(); \ + gen_op_store_T0_gpr(rD(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +/* Two operands arithmetic functions */ +#define GEN_INT_ARITH2(name, opc1, opc2, opc3) \ +__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000) \ +__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000) + +/* Two operands arithmetic functions with no overflow allowed */ +#define GEN_INT_ARITHN(name, opc1, opc2, opc3) \ +__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400) + +/* One operand arithmetic functions */ +#define GEN_INT_ARITH1(name, opc1, opc2, opc3) \ +__GEN_INT_ARITH1(name, opc1, opc2, opc3) \ +__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10) + +/* add add. addo addo. */ +GEN_INT_ARITH2 (add, 0x1F, 0x0A, 0x08); +/* addc addc. addco addco. */ +GEN_INT_ARITH2 (addc, 0x1F, 0x0A, 0x00); +/* adde adde. addeo addeo. */ +GEN_INT_ARITH2 (adde, 0x1F, 0x0A, 0x04); +/* addme addme. addmeo addmeo. */ +GEN_INT_ARITH1 (addme, 0x1F, 0x0A, 0x07); +/* addze addze. addzeo addzeo. */ +GEN_INT_ARITH1 (addze, 0x1F, 0x0A, 0x06); +/* divw divw. divwo divwo. */ +GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F); +/* divwu divwu. divwuo divwuo. */ +GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E); +/* mulhw mulhw. */ +GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02); +/* mulhwu mulhwu. */ +GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00); +/* mullw mullw. mullwo mullwo. */ +GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07); +/* neg neg. nego nego. */ +GEN_INT_ARITH1 (neg, 0x1F, 0x08, 0x03); +/* subf subf. subfo subfo. */ +GEN_INT_ARITH2 (subf, 0x1F, 0x08, 0x01); +/* subfc subfc. subfco subfco. */ +GEN_INT_ARITH2 (subfc, 0x1F, 0x08, 0x00); +/* subfe subfe. subfeo subfeo. */ +GEN_INT_ARITH2 (subfe, 0x1F, 0x08, 0x04); +/* subfme subfme. subfmeo subfmeo. */ +GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07); +/* subfze subfze. subfzeo subfzeo. */ +GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06); +/* addi */ +GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + int32_t simm = SIMM(ctx->opcode); + + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(simm); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_addi(simm); + } + gen_op_store_T0_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} +/* addic */ +GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_addic(SIMM(ctx->opcode)); + gen_op_store_T0_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} +/* addic. */ +GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_addic(SIMM(ctx->opcode)); + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} +/* addis */ +GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + int32_t simm = SIMM(ctx->opcode); + + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(simm << 16); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_addi(simm << 16); + } + gen_op_store_T0_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} +/* mulli */ +GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_mulli(SIMM(ctx->opcode)); + gen_op_store_T0_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} +/* subfic */ +GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_subfic(SIMM(ctx->opcode)); + gen_op_store_T0_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} + +/*** Integer comparison ***/ +#define GEN_CMP(name, opc) \ +GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_##name(); \ + gen_op_store_T0_crf(crfD(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +/* cmp */ +GEN_CMP(cmp, 0x00); +/* cmpi */ +GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_cmpi(SIMM(ctx->opcode)); + gen_op_store_T0_crf(crfD(ctx->opcode)); + SET_RETVAL(0); +} +/* cmpl */ +GEN_CMP(cmpl, 0x01); +/* cmpli */ +GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_cmpli(UIMM(ctx->opcode)); + gen_op_store_T0_crf(crfD(ctx->opcode)); + SET_RETVAL(0); +} + +/*** Integer logical ***/ +#define __GEN_LOGICAL2(name, opc2, opc3) \ +GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \ +{ \ + gen_op_load_gpr_T0(rS(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_##name(); \ + if (Rc(ctx->opcode) != 0) \ + gen_op_set_Rc0(); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} +#define GEN_LOGICAL2(name, opc) \ +__GEN_LOGICAL2(name, 0x1C, opc) + +#define GEN_LOGICAL1(name, opc) \ +GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \ +{ \ + gen_op_load_gpr_T0(rS(ctx->opcode)); \ + gen_op_##name(); \ + if (Rc(ctx->opcode) != 0) \ + gen_op_set_Rc0(); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +/* and & and. */ +GEN_LOGICAL2(and, 0x00); +/* andc & andc. */ +GEN_LOGICAL2(andc, 0x01); +/* andi. */ +GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_andi_(UIMM(ctx->opcode)); + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + SET_RETVAL(0); +} +/* andis. */ +GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_andi_(UIMM(ctx->opcode) << 16); + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + SET_RETVAL(0); +} + +/* cntlzw */ +GEN_LOGICAL1(cntlzw, 0x00); +/* eqv & eqv. */ +GEN_LOGICAL2(eqv, 0x08); +/* extsb & extsb. */ +GEN_LOGICAL1(extsb, 0x1D); +/* extsh & extsh. */ +GEN_LOGICAL1(extsh, 0x1C); +/* nand & nand. */ +GEN_LOGICAL2(nand, 0x0E); +/* nor & nor. */ +GEN_LOGICAL2(nor, 0x03); +/* or & or. */ +GEN_LOGICAL2(or, 0x0D); +/* orc & orc. */ +GEN_LOGICAL2(orc, 0x0C); +/* xor & xor. */ +GEN_LOGICAL2(xor, 0x09); +/* ori */ +GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + uint32_t uimm = UIMM(ctx->opcode); + +#if 0 + if (uimm == 0) { + if (rA(ctx->opcode) != rS(ctx->opcode)) { + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_store_T0_gpr(rA(ctx->opcode)); + } + } else +#endif + { + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_ori(uimm); + gen_op_store_T0_gpr(rA(ctx->opcode)); + } + SET_RETVAL(0); +} +/* oris */ +GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + uint32_t uimm = UIMM(ctx->opcode); + +#if 0 + if (uimm == 0) { + if (rA(ctx->opcode) != rS(ctx->opcode)) { + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_store_T0_gpr(rA(ctx->opcode)); + } + } else +#endif + { + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_ori(uimm << 16); + gen_op_store_T0_gpr(rA(ctx->opcode)); + } + SET_RETVAL(0); +} +/* xori */ +GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_xori(UIMM(ctx->opcode)); + gen_op_store_T0_gpr(rA(ctx->opcode)); + SET_RETVAL(0); +} + +/* xoris */ +GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_xori(UIMM(ctx->opcode) << 16); + gen_op_store_T0_gpr(rA(ctx->opcode)); + SET_RETVAL(0); +} + +/*** Integer rotate ***/ +/* rlwimi & rlwimi. */ +GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + uint32_t mb, me; + + mb = MB(ctx->opcode); + me = ME(ctx->opcode); + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me)); + if (Rc(ctx->opcode) != 0) + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + SET_RETVAL(0); +} +/* rlwinm & rlwinm. */ +GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + uint32_t mb, me, sh; + + sh = SH(ctx->opcode); + mb = MB(ctx->opcode); + me = ME(ctx->opcode); + gen_op_load_gpr_T0(rS(ctx->opcode)); + if (loglevel > 0) { + fprintf(logfile, "%s sh=%u mb=%u me=%u MASK=0x%08x\n", + __func__, sh, mb, me, MASK(mb, me)); + } + if (mb == 0) { + if (me == 31) { + gen_op_rotlwi(sh); + goto store; + } else if (me == (31 - sh)) { + gen_op_slwi(sh); + goto store; + } else if (sh == 0) { + gen_op_andi_(MASK(0, me)); + goto store; + } + } else if (me == 31) { + if (sh == (32 - mb)) { + gen_op_srwi(mb); + goto store; + } else if (sh == 0) { + gen_op_andi_(MASK(mb, 31)); + goto store; + } + } + gen_op_rlwinm(sh, MASK(mb, me)); +store: + if (Rc(ctx->opcode) != 0) + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + SET_RETVAL(0); +} +/* rlwnm & rlwnm. */ +GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + uint32_t mb, me; + + mb = MB(ctx->opcode); + me = ME(ctx->opcode); + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + if (mb == 0 && me == 31) { + gen_op_rotl(); + } else + { + gen_op_rlwnm(MASK(mb, me)); + } + if (Rc(ctx->opcode) != 0) + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + SET_RETVAL(0); +} + +/*** Integer shift ***/ +/* slw & slw. */ +__GEN_LOGICAL2(slw, 0x18, 0x00); +/* sraw & sraw. */ +__GEN_LOGICAL2(sraw, 0x18, 0x18); +/* srawi & srawi. */ +GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31)); + if (Rc(ctx->opcode) != 0) + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + SET_RETVAL(0); +} +/* srw & srw. */ +__GEN_LOGICAL2(srw, 0x18, 0x10); + +/*** Floating-Point arithmetic ***/ +/* fadd */ +GEN_HANDLER(fadd, 0x3F, 0x15, 0xFF, 0x000007C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fadds */ +GEN_HANDLER(fadds, 0x3B, 0x15, 0xFF, 0x000007C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fdiv */ +GEN_HANDLER(fdiv, 0x3F, 0x12, 0xFF, 0x000007C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fdivs */ +GEN_HANDLER(fdivs, 0x3B, 0x12, 0xFF, 0x000007C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fmul */ +GEN_HANDLER(fmul, 0x3F, 0x19, 0xFF, 0x0000F800, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fmuls */ +GEN_HANDLER(fmuls, 0x3B, 0x19, 0xFF, 0x0000F800, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fres */ +GEN_HANDLER(fres, 0x3B, 0x18, 0xFF, 0x001807C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* frsqrte */ +GEN_HANDLER(frsqrte, 0x3F, 0x1A, 0xFF, 0x001807C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fsel */ +GEN_HANDLER(fsel, 0x3F, 0x17, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fsub */ +GEN_HANDLER(fsub, 0x3F, 0x14, 0xFF, 0x000007C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fsubs */ +GEN_HANDLER(fsubs, 0x3B, 0x14, 0xFF, 0x000007C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* Optional: */ +/* fsqrt */ +GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001807C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fsqrts */ +GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001807C0, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Floating-Point multiply-and-add ***/ +/* fmadd */ +GEN_HANDLER(fmadd, 0x3F, 0x1D, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fmadds */ +GEN_HANDLER(fmadds, 0x3B, 0x1D, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fmsub */ +GEN_HANDLER(fmsub, 0x3F, 0x1C, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fmsubs */ +GEN_HANDLER(fmsubs, 0x3B, 0x1C, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fnmadd */ +GEN_HANDLER(fnmadd, 0x3F, 0x1F, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fnmadds */ +GEN_HANDLER(fnmadds, 0x3B, 0x1F, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fnmsub */ +GEN_HANDLER(fnmsub, 0x3F, 0x1E, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fnmsubs */ +GEN_HANDLER(fnmsubs, 0x3B, 0x1E, 0xFF, 0x00000000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Floating-Point round & convert ***/ +/* fctiw */ +GEN_HANDLER(fctiw, 0x3F, 0x0E, 0xFF, 0x001F0000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fctiwz */ +GEN_HANDLER(fctiwz, 0x3F, 0x0F, 0xFF, 0x001F0000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* frsp */ +GEN_HANDLER(frsp, 0x3F, 0x0C, 0xFF, 0x001F0000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Floating-Point compare ***/ +/* fcmpo */ +GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fcmpu */ +GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Floating-Point status & ctrl register ***/ +/* mcrfs */ +GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* mffs */ +GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) +{ + gen_op_load_fpscr(rD(ctx->opcode)); + if (Rc(ctx->opcode)) { + /* Update CR1 */ + } + SET_RETVAL(0); +} + +/* mtfsb0 */ +GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* mtfsb1 */ +GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* mtfsf */ +GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) +{ + gen_op_store_fpscr(FM(ctx->opcode), rB(ctx->opcode)); + if (Rc(ctx->opcode)) { + /* Update CR1 */ + } + SET_RETVAL(0); +} + +/* mtfsfi */ +GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Integer load ***/ +#define GEN_ILDZ(width, opc) \ +GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +{ \ + uint32_t simm = SIMM(ctx->opcode); \ + if (rA(ctx->opcode) == 0) { \ + gen_op_l##width##_z(simm); \ + } else { \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_l##width (simm); \ + } \ + gen_op_store_T1_gpr(rD(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_ILDZU(width, opc) \ +GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +{ \ + if (rA(ctx->opcode) == 0 || \ + rA(ctx->opcode) == rD(ctx->opcode)) \ + SET_RETVAL(EXCP_INVAL); \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_l##width(SIMM(ctx->opcode)); \ + gen_op_store_T1_gpr(rD(ctx->opcode)); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_ILDZUX(width, opc) \ +GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ +{ \ + if (rA(ctx->opcode) == 0 || \ + rA(ctx->opcode) == rD(ctx->opcode)) \ + SET_RETVAL(EXCP_INVAL); \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_l##width##x(); \ + gen_op_store_T1_gpr(rD(ctx->opcode)); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_ILDZX(width, opc2, opc3) \ +GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ +{ \ + if (rA(ctx->opcode) == 0) { \ + gen_op_load_gpr_T0(rB(ctx->opcode)); \ + gen_op_l##width##x_z(); \ + } else { \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_l##width##x(); \ + } \ + gen_op_store_T1_gpr(rD(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_ILD(width, op) \ +GEN_ILDZ(width, op | 0x20) \ +GEN_ILDZU(width, op | 0x21) \ +GEN_ILDZUX(width, op | 0x01) \ +GEN_ILDZX(width, 0x17, op | 0x00) + +/* lbz lbzu lbzux lbzx */ +GEN_ILD(bz, 0x02); +/* lha lhau lhaux lhax */ +GEN_ILD(ha, 0x0A); +/* lhz lhzu lhzux lhzx */ +GEN_ILD(hz, 0x08); +/* lwz lwzu lwzux lwzx */ +GEN_ILD(wz, 0x00); + +/*** Integer store ***/ +#define GEN_IST(width, opc) \ +GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +{ \ + uint32_t simm = SIMM(ctx->opcode); \ + if (rA(ctx->opcode) == 0) { \ + gen_op_load_gpr_T0(rS(ctx->opcode)); \ + gen_op_st##width##_z(simm); \ + } else { \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rS(ctx->opcode)); \ + gen_op_st##width(simm); \ + } \ + SET_RETVAL(0); \ +} + +#define GEN_ISTU(width, opc) \ +GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +{ \ + if (rA(ctx->opcode) == 0) \ + SET_RETVAL(EXCP_INVAL); \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rS(ctx->opcode)); \ + gen_op_st##width(SIMM(ctx->opcode)); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_ISTUX(width, opc) \ +GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ +{ \ + if (rA(ctx->opcode) == 0) \ + SET_RETVAL(EXCP_INVAL); \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_load_gpr_T2(rS(ctx->opcode)); \ + gen_op_st##width##x(); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_ISTX(width, opc2, opc3) \ +GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ +{ \ + if (rA(ctx->opcode) == 0) { \ + gen_op_load_gpr_T0(rB(ctx->opcode)); \ + gen_op_load_gpr_T1(rS(ctx->opcode)); \ + gen_op_st##width##x_z(); \ + } else { \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_load_gpr_T2(rS(ctx->opcode)); \ + gen_op_st##width##x(); \ + } \ + SET_RETVAL(0); \ +} + +#define GEN_ISTO(width, opc) \ +GEN_IST(width, opc | 0x20) \ +GEN_ISTU(width, opc | 0x21) \ +GEN_ISTUX(width, opc | 0x01) \ +GEN_ISTX(width, 0x17, opc | 0x00) + +/* stb stbu stbux stbx */ +GEN_ISTO(b, 0x06); +/* sth sthu sthux sthx */ +GEN_ISTO(h, 0x0C); +/* stw stwu stwux stwx */ +GEN_ISTO(w, 0x04); + +/*** Integer load and store with byte reverse ***/ +/* lhbrx */ +GEN_ILDZX(hbr, 0x16, 0x18); +/* lwbrx */ +GEN_ILDZX(wbr, 0x16, 0x10); +/* sthbrx */ +GEN_ISTX(hbr, 0x16, 0x1C); +/* stwbrx */ +GEN_ISTX(wbr, 0x16, 0x14); + +/*** Integer load and store multiple ***/ +/* lmw */ +GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(0); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + } + gen_op_lmw(rD(ctx->opcode), SIMM(ctx->opcode)); + SET_RETVAL(0); +} + +/* stmw */ +GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +{ + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(0); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + } + gen_op_stmw(rS(ctx->opcode), SIMM(ctx->opcode)); + SET_RETVAL(0); +} + +/*** Integer load and store strings ***/ +/* lswi */ +GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) +{ + int nb = NB(ctx->opcode); + int start = rD(ctx->opcode); + int nr; + + if (nb == 0) + nb = 32; + nr = nb / 4; + if ((start + nr) > 32) { + /* handle wrap around r0 */ + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(0); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + } + gen_op_lswi(start, 4 * (32 - start)); + nb -= 4 * (32 - start); + start = 0; + } + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(0); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + } + gen_op_lswi(start, nb); + SET_RETVAL(0); +} + +/* lswx */ +GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) +{ + gen_op_load_xer_bc(); + gen_op_load_gpr_T1(rB(ctx->opcode)); + if (rA(ctx->opcode) == 0) { + gen_op_set_T2(0); + } else { + gen_op_load_gpr_T2(rA(ctx->opcode)); + } + gen_op_lswx(rD(ctx->opcode)); + SET_RETVAL(0); +} + +/* stswi */ +GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) +{ + int nb = NB(ctx->opcode); + int start = rS(ctx->opcode); + int nr; + + if (nb == 0) + nb = 32; + nr = nb / 4; + if ((start + nr) > 32) { + /* handle wrap around r0 */ + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(0); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + } + gen_op_stswi(start, 4 * (32 - start)); + nb -= 4 * (32 - start); + start = 0; + } + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(0); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + } + gen_op_stswi(start, nb); + SET_RETVAL(0); +} + +/* stswx */ +GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) +{ + gen_op_load_xer_bc(); + gen_op_load_gpr_T1(rB(ctx->opcode)); + if (rA(ctx->opcode) == 0) { + gen_op_set_T2(0); + } else { + gen_op_load_gpr_T2(rA(ctx->opcode)); + } + gen_op_stswx(rS(ctx->opcode)); + SET_RETVAL(0); +} + +/*** Memory synchronisation ***/ +/* eieio */ +GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM) +{ + /* Do a branch to next instruction */ + gen_op_b((uint32_t)ctx->nip); + SET_RETVAL(EXCP_BRANCH); +} + +/* isync */ +GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM) +{ + /* Do a branch to next instruction */ + gen_op_b((uint32_t)ctx->nip); + SET_RETVAL(EXCP_BRANCH); +} + +/* lwarx */ +GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_MEM) +{ + reserve = 1; + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_lwzx_z(); + gen_op_set_reservation(); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_lwzx(); + gen_op_set_reservation(); + } + gen_op_store_T1_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} + +/* stwcx. */ +GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_MEM) +{ + if (reserve == 0) { + gen_op_reset_Rc0(); + } else { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_stwx_z(); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_load_gpr_T2(rS(ctx->opcode)); + gen_op_stwx(); + } + gen_op_set_Rc0_1(); + gen_op_reset_reservation(); + } + SET_RETVAL(0); +} + +/* sync */ +GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) +{ + /* Do a branch to next instruction */ + gen_op_b((uint32_t)ctx->nip); + SET_RETVAL(EXCP_BRANCH); +} + +/*** Floating-point load ***/ +#define GEN_LF(width, opc) \ +GEN_HANDLER(lf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +{ \ + uint32_t simm = SIMM(ctx->opcode); \ + if (rA(ctx->opcode) == 0) { \ + gen_op_lf##width##_z(simm, rD(ctx->opcode)); \ + } else { \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_lf##width(simm, rD(ctx->opcode)); \ + } \ + SET_RETVAL(0); \ +} + +#define GEN_LFU(width, opc) \ +GEN_HANDLER(lf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +{ \ + if (rA(ctx->opcode) == 0 || \ + rA(ctx->opcode) == rD(ctx->opcode)) \ + SET_RETVAL(EXCP_INVAL); \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_lf##width(SIMM(ctx->opcode), rD(ctx->opcode)); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_LFUX(width, opc) \ +GEN_HANDLER(lf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +{ \ + if (rA(ctx->opcode) == 0 || \ + rA(ctx->opcode) == rD(ctx->opcode)) \ + SET_RETVAL(EXCP_INVAL); \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_lf##width##x(rD(ctx->opcode)); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_LFX(width, opc) \ +GEN_HANDLER(lf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +{ \ + if (rA(ctx->opcode) == 0) { \ + gen_op_load_gpr_T0(rB(ctx->opcode)); \ + gen_op_lf##width##x_z(rD(ctx->opcode)); \ + } else { \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_lf##width##x(rD(ctx->opcode)); \ + } \ + SET_RETVAL(0); \ +} + +#define GEN_LDF(width, opc) \ +GEN_LF(width, opc | 0x20) \ +GEN_LFU(width, opc | 0x21) \ +GEN_LFUX(width, opc | 0x01) \ +GEN_LFX(width, opc | 0x00) + +/* lfd lfdu lfdux lfdx */ +GEN_LDF(d, 0x12); +/* lfs lfsu lfsux lfsx */ +#define gen_op_lfs_z(a, b) +#define gen_op_lfs(a, b) +#define gen_op_lfsx_z(a) +#define gen_op_lfsx(a) +GEN_LDF(s, 0x10); + +/*** Floating-point store ***/ +#define GEN_STF(width, opc) \ +GEN_HANDLER(stf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +{ \ + uint32_t simm = SIMM(ctx->opcode); \ + if (rA(ctx->opcode) == 0) { \ + gen_op_stf##width##_z(simm, rS(ctx->opcode)); \ + } else { \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_stf##width(simm, rS(ctx->opcode)); \ + } \ + SET_RETVAL(0); \ +} + +#define GEN_STFU(width, opc) \ +GEN_HANDLER(stf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +{ \ + if (rA(ctx->opcode) == 0) \ + SET_RETVAL(EXCP_INVAL); \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_stf##width(SIMM(ctx->opcode), rS(ctx->opcode)); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_STFUX(width, opc) \ +GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +{ \ + if (rA(ctx->opcode) == 0) \ + SET_RETVAL(EXCP_INVAL); \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_stf##width##x(rS(ctx->opcode)); \ + gen_op_store_T0_gpr(rA(ctx->opcode)); \ + SET_RETVAL(0); \ +} + +#define GEN_STFX(width, opc) \ +GEN_HANDLER(stf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +{ \ + if (rA(ctx->opcode) == 0) { \ + gen_op_load_gpr_T0(rB(ctx->opcode)); \ + gen_op_stf##width##x_z(rS(ctx->opcode)); \ + } else { \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + gen_op_stf##width##x(rS(ctx->opcode)); \ + } \ + SET_RETVAL(0); \ +} + +#define GEN_STOF(width, opc) \ +GEN_STF(width, opc | 0x20) \ +GEN_STFU(width, opc | 0x21) \ +GEN_STFUX(width, opc | 0x01) \ +GEN_STFX(width, opc | 0x00) + +/* stfd stfdu stfdux stfdx */ +GEN_STOF(d, 0x16); +/* stfs stfsu stfsux stfsx */ +#define gen_op_stfs_z(a, b) +#define gen_op_stfs(a, b) +#define gen_op_stfsx_z(a) +#define gen_op_stfsx(a) +GEN_STOF(s, 0x14); + +/* Optional: */ +/* stfiwx */ +GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Floating-point move ***/ +/* fabs */ +GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fmr */ +GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fnabs */ +GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* fneg */ +GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Branch ***/ +#define GEN_BCOND(name, opc1, opc2, opc3, prologue, \ + bl_ctr, b_ctr, bl_ctrz, b_ctrz, b, \ + bl_ctr_true, b_ctr_true, bl_ctrz_true, b_ctrz_true, bl_true, b_true, \ + bl_ctr_false, b_ctr_false, bl_ctrz_false, b_ctrz_false, bl_false, b_false) \ +GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW) \ +{ \ + __attribute__ ((unused)) uint32_t target; \ + uint32_t bo = BO(ctx->opcode); \ + uint32_t bi = BI(ctx->opcode); \ + uint32_t mask; \ + prologue; \ + if ((bo & 0x4) == 0) \ + gen_op_dec_ctr(); \ + if (bo & 0x10) { \ + /* No CR condition */ \ + switch (bo & 0x6) { \ + case 0: \ + if (LK(ctx->opcode)) { \ + bl_ctr; \ + } else { \ + b_ctr; \ + } \ + break; \ + case 2: \ + if (LK(ctx->opcode)) { \ + bl_ctrz; \ + } else { \ + b_ctrz; \ + } \ + break; \ + case 4: \ + case 6: \ + b; \ + if (LK(ctx->opcode)) \ + gen_op_load_lr((uint32_t)ctx->nip); \ + break; \ + default: \ + printf("ERROR: %s: unhandled ba case (%d)\n", __func__, bo); \ + SET_RETVAL(EXCP_INVAL); \ + break; \ + } \ + } else { \ + mask = 1 << (3 - (bi & 0x03)); \ + gen_op_load_crf_T0(bi >> 2); \ + if (bo & 0x8) { \ + switch (bo & 0x6) { \ + case 0: \ + if (LK(ctx->opcode)) { \ + bl_ctr_true; \ + } else { \ + b_ctr_true; \ + } \ + break; \ + case 2: \ + if (LK(ctx->opcode)) { \ + bl_ctrz_true; \ + } else { \ + b_ctrz_true; \ + } \ + break; \ + case 4: \ + case 6: \ + if (LK(ctx->opcode)) { \ + bl_true; \ + } else { \ + b_true; \ + } \ + break; \ + default: \ + printf("ERROR: %s: unhandled b case (%d)\n", __func__, bo); \ + SET_RETVAL(EXCP_INVAL); \ + break; \ + } \ + } else { \ + switch (bo & 0x6) { \ + case 0: \ + if (LK(ctx->opcode)) { \ + bl_ctr_false; \ + } else { \ + b_ctr_false; \ + } \ + break; \ + case 2: \ + if (LK(ctx->opcode)) { \ + bl_ctrz_false; \ + } else { \ + b_ctrz_false; \ + } \ + break; \ + case 4: \ + case 6: \ + if (LK(ctx->opcode)) { \ + bl_false; \ + } else { \ + b_false; \ + } \ + break; \ + default: \ + printf("ERROR: %s: unhandled bn case (%d)\n", __func__, bo); \ + SET_RETVAL(EXCP_INVAL); \ + break; \ + } \ + } \ + } \ + SET_RETVAL(EXCP_BRANCH); \ +} + +/* b ba bl bla */ +GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) +{ + uint32_t li = s_ext24(LI(ctx->opcode)), target; + + if (AA(ctx->opcode) == 0) + target = (uint32_t)ctx->nip + li - 4; + else + target = s_ext24(LI(ctx->opcode)); + gen_op_b(target); + if (LK(ctx->opcode)) + gen_op_load_lr((uint32_t)ctx->nip); + SET_RETVAL(EXCP_BRANCH); +} + +/* bc bca bcl bcla */ +GEN_BCOND(bc, 0x10, 0xFF, 0xFF, + do { + uint32_t li = s_ext16(BD(ctx->opcode)); + if (AA(ctx->opcode) == 0) { + target = (uint32_t)ctx->nip + li - 4; + } else { + target = li; + } + } while (0), + gen_op_bl_ctr((uint32_t)ctx->nip, target), + gen_op_b_ctr((uint32_t)ctx->nip, target), + gen_op_bl_ctrz((uint32_t)ctx->nip, target), + gen_op_b_ctrz((uint32_t)ctx->nip, target), + gen_op_b(target), + gen_op_bl_ctr_true((uint32_t)ctx->nip, target, mask), + gen_op_b_ctr_true((uint32_t)ctx->nip, target, mask), + gen_op_bl_ctrz_true((uint32_t)ctx->nip, target, mask), + gen_op_b_ctrz_true((uint32_t)ctx->nip, target, mask), + gen_op_bl_true((uint32_t)ctx->nip, target, mask), + gen_op_b_true((uint32_t)ctx->nip, target, mask), + gen_op_bl_ctr_false((uint32_t)ctx->nip, target, mask), + gen_op_b_ctr_false((uint32_t)ctx->nip, target, mask), + gen_op_bl_ctrz_false((uint32_t)ctx->nip, target, mask), + gen_op_b_ctrz_false((uint32_t)ctx->nip, target, mask), + gen_op_bl_false((uint32_t)ctx->nip, target, mask), + gen_op_b_false((uint32_t)ctx->nip, target, mask)); + +/* bcctr bcctrl */ +GEN_BCOND(bcctr, 0x13, 0x10, 0x10, do { } while (0), + gen_op_bctrl_ctr((uint32_t)ctx->nip), + gen_op_bctr_ctr((uint32_t)ctx->nip), + gen_op_bctrl_ctrz((uint32_t)ctx->nip), + gen_op_bctr_ctrz((uint32_t)ctx->nip), + gen_op_bctr(), + gen_op_bctrl_ctr_true((uint32_t)ctx->nip, mask), + gen_op_bctr_ctr_true((uint32_t)ctx->nip, mask), + gen_op_bctrl_ctrz_true((uint32_t)ctx->nip, mask), + gen_op_bctr_ctrz_true((uint32_t)ctx->nip, mask), + gen_op_bctrl_true((uint32_t)ctx->nip, mask), + gen_op_bctr_true((uint32_t)ctx->nip, mask), + gen_op_bctrl_ctr_false((uint32_t)ctx->nip, mask), + gen_op_bctr_ctr_false((uint32_t)ctx->nip, mask), + gen_op_bctrl_ctrz_false((uint32_t)ctx->nip, mask), + gen_op_bctr_ctrz_false((uint32_t)ctx->nip, mask), + gen_op_bctrl_false((uint32_t)ctx->nip, mask), + gen_op_bctr_false((uint32_t)ctx->nip, mask)) + +/* bclr bclrl */ +GEN_BCOND(bclr, 0x13, 0x10, 0x00, do { } while (0), + gen_op_blrl_ctr((uint32_t)ctx->nip), + gen_op_blr_ctr((uint32_t)ctx->nip), + gen_op_blrl_ctrz((uint32_t)ctx->nip), + gen_op_blr_ctrz((uint32_t)ctx->nip), + gen_op_blr(), + gen_op_blrl_ctr_true((uint32_t)ctx->nip, mask), + gen_op_blr_ctr_true((uint32_t)ctx->nip, mask), + gen_op_blrl_ctrz_true((uint32_t)ctx->nip, mask), + gen_op_blr_ctrz_true((uint32_t)ctx->nip, mask), + gen_op_blrl_true((uint32_t)ctx->nip, mask), + gen_op_blr_true((uint32_t)ctx->nip, mask), + gen_op_blrl_ctr_false((uint32_t)ctx->nip, mask), + gen_op_blr_ctr_false((uint32_t)ctx->nip, mask), + gen_op_blrl_ctrz_false((uint32_t)ctx->nip, mask), + gen_op_blr_ctrz_false((uint32_t)ctx->nip, mask), + gen_op_blrl_false((uint32_t)ctx->nip, mask), + gen_op_blr_false((uint32_t)ctx->nip, mask)) + +/*** Condition register logical ***/ +#define GEN_CRLOGIC(op, opc) \ +GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \ +{ \ + gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \ + gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03)); \ + gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \ + gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03)); \ + gen_op_##op(); \ + gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \ + gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \ + 3 - (crbD(ctx->opcode) & 0x03)); \ + gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \ + SET_RETVAL(0); \ +} + +/* crand */ +GEN_CRLOGIC(and, 0x08) +/* crandc */ +GEN_CRLOGIC(andc, 0x04) +/* creqv */ +GEN_CRLOGIC(eqv, 0x09) +/* crnand */ +GEN_CRLOGIC(nand, 0x07) +/* crnor */ +GEN_CRLOGIC(nor, 0x01) +/* cror */ +GEN_CRLOGIC(or, 0x0E) +/* crorc */ +GEN_CRLOGIC(orc, 0x0D) +/* crxor */ +GEN_CRLOGIC(xor, 0x06) +/* mcrf */ +GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) +{ + gen_op_load_crf_T0(crfS(ctx->opcode)); + gen_op_store_T0_crf(crfD(ctx->opcode)); + SET_RETVAL(0); +} + +/*** System linkage ***/ +/* rfi (supervisor only) */ +GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* sc */ +GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) +{ + gen_op_b((uint32_t)ctx->nip); + SET_RETVAL(EXCP_SYSCALL); +} + +/*** Trap ***/ +/* tw */ +GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* twi */ +GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Processor control ***/ +static inline int check_spr_access (int spr, int rw, int supervisor) +{ + uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1)); + + rights = rights >> (2 * supervisor); + rights = rights >> rw; + + return rights & 1; +} + +/* mcrxr */ +GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) +{ + gen_op_load_xer_cr(); + gen_op_store_T0_crf(crfD(ctx->opcode)); + gen_op_clear_xer_cr(); + SET_RETVAL(0); +} + +/* mfcr */ +GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC) +{ + gen_op_load_cr(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} + +/* mfmsr */ +GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) +{ + if (!ctx->supervisor) + SET_RETVAL(EXCP_PRIV); + gen_op_load_msr(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + SET_RETVAL(0); +} + +/* mfspr */ +GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) +{ + uint32_t sprn = SPR(ctx->opcode); + + if (check_spr_access(sprn, 0, ctx->supervisor) == 0) + SET_RETVAL(EXCP_PRIV); + /* XXX: make this more generic */ + switch (sprn) { + case SPR_ENCODE(1): + if (loglevel > 0) { + fprintf(logfile, "LOAD XER at %p\n", ctx->nip - 1); + } + gen_op_load_xer(); + break; + case SPR_ENCODE(268): + /* We need to update the time base before reading it */ + gen_op_update_tb(ctx->tb_offset); + ctx->tb_offset = 0; + break; + case SPR_ENCODE(269): + gen_op_update_tb(ctx->tb_offset); + ctx->tb_offset = 0; + break; + default: + gen_op_load_spr(sprn); + break; + } + gen_op_store_T0_gpr(rD(ctx->opcode)); // + SET_RETVAL(0); +} + +/* mftb */ +GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) +{ + uint32_t sprn = SPR(ctx->opcode); + + if (check_spr_access(sprn, 0, ctx->supervisor) == 0) + SET_RETVAL(EXCP_PRIV); + switch (sprn) { + case SPR_ENCODE(268): + /* We need to update the time base before reading it */ + gen_op_update_tb(ctx->tb_offset); + ctx->tb_offset = 0; + break; + case SPR_ENCODE(269): + gen_op_update_tb(ctx->tb_offset); + ctx->tb_offset = 0; + break; + default: + SET_RETVAL(EXCP_INVAL); + break; + } + SET_RETVAL(0); +} + +/* mtcrf */ +GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_store_cr(CRM(ctx->opcode)); + SET_RETVAL(0); +} + +/* mtmsr */ +GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) +{ + if (!ctx->supervisor) + SET_RETVAL(EXCP_PRIV); + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_store_msr(); + /* Must stop the translation as machine state (may have) changed */ + SET_RETVAL(EXCP_MTMSR); +} + +/* mtspr */ +GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) +{ + uint32_t sprn = SPR(ctx->opcode); + + if (check_spr_access(sprn, 1, ctx->supervisor) == 0) + SET_RETVAL(EXCP_PRIV); + gen_op_load_gpr_T0(rS(ctx->opcode)); + if (sprn == SPR_ENCODE(1)) { + gen_op_store_xer(); + } else { + gen_op_store_spr(sprn); + } + SET_RETVAL(0); +} + +/*** Cache management ***/ +/* For now, all those will be implemented as nop: + * this is valid, regarding the PowerPC specs... + */ +/* dcbf */ +GEN_HANDLER(dcbf, 0x1F, 0x16, 0x17, 0x03E00001, PPC_MEM) +{ + SET_RETVAL(0); +} + +/* dcbi (Supervisor only) */ +GEN_HANDLER(dcbi, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_MEM) +{ + SET_RETVAL(0); +} + +/* dcdst */ +GEN_HANDLER(dcbst, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_MEM) +{ + SET_RETVAL(0); +} + +/* dcbt */ +GEN_HANDLER(dcbt, 0x1F, 0x16, 0x01, 0x03E00001, PPC_MEM) +{ + SET_RETVAL(0); +} + +/* dcbtst */ +GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x02, 0x03E00001, PPC_MEM) +{ + SET_RETVAL(0); +} + +/* dcbz */ +GEN_HANDLER(dcbz, 0x1F, 0x16, 0x08, 0x03E00001, PPC_MEM) +{ + SET_RETVAL(0); +} + +/* icbi */ +GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_MEM) +{ + SET_RETVAL(0); +} + +/* Optional: */ +/* dcba */ +GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_MEM) +{ + SET_RETVAL(0); +} + +/*** Segment register manipulation ***/ +/* Supervisor only: */ +/* mfsr */ +GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* mfsrin */ +GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x0010F001, PPC_SEGMENT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* mtsr */ +GEN_HANDLER(mtsr, 0x1F, 0x12, 0x02, 0x0010F801, PPC_SEGMENT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* mtsrin */ +GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x0010F001, PPC_SEGMENT) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** Lookaside buffer management ***/ +/* Optional & supervisor only: */ +/* tlbia */ +GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* tlbie */ +GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF8001, PPC_MEM) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* tlbsync */ +GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFFC01, PPC_MEM) +{ + SET_RETVAL(EXCP_INVAL); +} + +/*** External control ***/ +/* Optional: */ +/* eciwx */ +GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* ecowx */ +GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) +{ + SET_RETVAL(EXCP_INVAL); +} + +/* End opcode list */ +GEN_OPCODE_MARK(end); + +/*****************************************************************************/ + +#include +extern FILE *stderr; +void free (void *p); +int fflush (FILE *f); + +/* Main ppc opcodes table: + * at init, all opcodes are invalids + */ +static opc_handler_t *ppc_opcodes[0x40]; + +/* Opcode types */ +enum { + PPC_DIRECT = 0, /* Opcode routine */ + PPC_INDIRECT = 1, /* Indirect opcode table */ +}; + +static inline int is_indirect_opcode (void *handler) +{ + return ((unsigned long)handler & 0x03) == PPC_INDIRECT; +} + +static inline opc_handler_t **ind_table(void *handler) +{ + return (opc_handler_t **)((unsigned long)handler & ~3); +} + +/* Opcodes tables creation */ +static void fill_new_table (opc_handler_t **table, int len) +{ + int i; + + for (i = 0; i < len; i++) + table[i] = &invalid_handler; +} + +static int create_new_table (opc_handler_t **table, unsigned char idx) +{ + opc_handler_t **tmp; + + tmp = malloc(0x20 * sizeof(opc_handler_t)); + if (tmp == NULL) + return -1; + fill_new_table(tmp, 0x20); + table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT); + + return 0; +} + +static int insert_in_table (opc_handler_t **table, unsigned char idx, + opc_handler_t *handler) +{ + if (table[idx] != &invalid_handler) + return -1; + table[idx] = handler; + + return 0; +} + +static int register_direct_insn (unsigned char idx, opc_handler_t *handler) +{ + if (insert_in_table(ppc_opcodes, idx, handler) < 0) { + fprintf(stderr, "*** ERROR: opcode %02x already assigned in main " + "opcode table\n", idx); + return -1; + } + + return 0; +} + +static int register_ind_in_table (opc_handler_t **table, + unsigned char idx1, unsigned char idx2, + opc_handler_t *handler) +{ + if (table[idx1] == &invalid_handler) { + if (create_new_table(table, idx1) < 0) { + fprintf(stderr, "*** ERROR: unable to create indirect table " + "idx=%02x\n", idx1); + return -1; + } + } else { + if (!is_indirect_opcode(table[idx1])) { + fprintf(stderr, "*** ERROR: idx %02x already assigned to a direct " + "opcode\n", idx1); + return -1; + } + } + if (handler != NULL && + insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { + fprintf(stderr, "*** ERROR: opcode %02x already assigned in " + "opcode table %02x\n", idx2, idx1); + return -1; + } + + return 0; +} + +static int register_ind_insn (unsigned char idx1, unsigned char idx2, + opc_handler_t *handler) +{ + int ret; + + ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler); + + return ret; +} + +static int register_dblind_insn (unsigned char idx1, unsigned char idx2, + unsigned char idx3, opc_handler_t *handler) +{ + if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { + fprintf(stderr, "*** ERROR: unable to join indirect table idx " + "[%02x-%02x]\n", idx1, idx2); + return -1; + } + if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, + handler) < 0) { + fprintf(stderr, "*** ERROR: unable to insert opcode " + "[%02x-%02x-%02x]\n", idx1, idx2, idx3); + return -1; + } + + return 0; +} + +static int register_insn (opcode_t *insn) +{ + if (insn->opc2 != 0xFF) { + if (insn->opc3 != 0xFF) { + if (register_dblind_insn(insn->opc1, insn->opc2, insn->opc3, + &insn->handler) < 0) + return -1; + } else { + if (register_ind_insn(insn->opc1, insn->opc2, &insn->handler) < 0) + return -1; + } + } else { + if (register_direct_insn(insn->opc1, &insn->handler) < 0) + return -1; + } + + return 0; +} + +static int test_opcode_table (opc_handler_t **table, int len) +{ + int i, count, tmp; + + for (i = 0, count = 0; i < len; i++) { + /* Consistency fixup */ + if (table[i] == NULL) + table[i] = &invalid_handler; + if (table[i] != &invalid_handler) { + if (is_indirect_opcode(table[i])) { + tmp = test_opcode_table(ind_table(table[i]), 0x20); + if (tmp == 0) { + free(table[i]); + table[i] = &invalid_handler; + } else { + count++; + } + } else { + count++; + } + } + } + + return count; +} + +static void fix_opcode_tables (void) +{ + if (test_opcode_table(ppc_opcodes, 0x40) == 0) + fprintf(stderr, "*** WARNING: no opcode defined !\n"); +} + +#define SPR_RIGHTS(rw, priv) ((2 * (priv)) + (rw)) +#define SPR_UR SPR_RIGHTS(0, 0) +#define SPR_UW SPR_RIGHTS(1, 0) +#define SPR_SR SPR_RIGHTS(0, 1) +#define SPR_SW SPR_RIGHTS(1, 1) + +#define spr_set_rights(spr, rights) \ +do { \ + spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \ +} while (0) + +static void init_spr_rights (void) +{ + /* XER (SPR 1) */ + spr_set_rights(SPR_ENCODE(1), SPR_UR | SPR_UW | SPR_SR | SPR_SW); + /* LR (SPR 8) */ + spr_set_rights(SPR_ENCODE(8), SPR_UR | SPR_UW | SPR_SR | SPR_SW); + /* CTR (SPR 9) */ + spr_set_rights(SPR_ENCODE(9), SPR_UR | SPR_UW | SPR_SR | SPR_SW); + /* TBL (SPR 268) */ + spr_set_rights(SPR_ENCODE(268), SPR_UR | SPR_SR); + /* TBU (SPR 269) */ + spr_set_rights(SPR_ENCODE(269), SPR_UR | SPR_SR); + /* DSISR (SPR 18) */ + spr_set_rights(SPR_ENCODE(18), SPR_SR | SPR_SW); + /* DAR (SPR 19) */ + spr_set_rights(SPR_ENCODE(19), SPR_SR | SPR_SW); + /* DEC (SPR 22) */ + spr_set_rights(SPR_ENCODE(22), SPR_SR | SPR_SW); + /* SDR1 (SPR 25) */ + spr_set_rights(SPR_ENCODE(25), SPR_SR | SPR_SW); + /* SPRG0 (SPR 272) */ + spr_set_rights(SPR_ENCODE(272), SPR_SR | SPR_SW); + /* SPRG1 (SPR 273) */ + spr_set_rights(SPR_ENCODE(273), SPR_SR | SPR_SW); + /* SPRG2 (SPR 274) */ + spr_set_rights(SPR_ENCODE(274), SPR_SR | SPR_SW); + /* SPRG3 (SPR 275) */ + spr_set_rights(SPR_ENCODE(275), SPR_SR | SPR_SW); + /* ASR (SPR 280) */ + spr_set_rights(SPR_ENCODE(281), SPR_SR | SPR_SW); + /* EAR (SPR 282) */ + spr_set_rights(SPR_ENCODE(282), SPR_SR | SPR_SW); + /* IBAT0U (SPR 528) */ + spr_set_rights(SPR_ENCODE(528), SPR_SR | SPR_SW); + /* IBAT0L (SPR 529) */ + spr_set_rights(SPR_ENCODE(529), SPR_SR | SPR_SW); + /* IBAT1U (SPR 530) */ + spr_set_rights(SPR_ENCODE(530), SPR_SR | SPR_SW); + /* IBAT1L (SPR 531) */ + spr_set_rights(SPR_ENCODE(531), SPR_SR | SPR_SW); + /* IBAT2U (SPR 532) */ + spr_set_rights(SPR_ENCODE(532), SPR_SR | SPR_SW); + /* IBAT2L (SPR 533) */ + spr_set_rights(SPR_ENCODE(533), SPR_SR | SPR_SW); + /* IBAT3U (SPR 534) */ + spr_set_rights(SPR_ENCODE(534), SPR_SR | SPR_SW); + /* IBAT3L (SPR 535) */ + spr_set_rights(SPR_ENCODE(535), SPR_SR | SPR_SW); + /* DBAT0U (SPR 536) */ + spr_set_rights(SPR_ENCODE(536), SPR_SR | SPR_SW); + /* DBAT0L (SPR 537) */ + spr_set_rights(SPR_ENCODE(537), SPR_SR | SPR_SW); + /* DBAT1U (SPR 538) */ + spr_set_rights(SPR_ENCODE(538), SPR_SR | SPR_SW); + /* DBAT1L (SPR 539) */ + spr_set_rights(SPR_ENCODE(539), SPR_SR | SPR_SW); + /* DBAT2U (SPR 540) */ + spr_set_rights(SPR_ENCODE(540), SPR_SR | SPR_SW); + /* DBAT2L (SPR 541) */ + spr_set_rights(SPR_ENCODE(541), SPR_SR | SPR_SW); + /* DBAT3U (SPR 542) */ + spr_set_rights(SPR_ENCODE(542), SPR_SR | SPR_SW); + /* DBAT3L (SPR 543) */ + spr_set_rights(SPR_ENCODE(543), SPR_SR | SPR_SW); + /* DABR (SPR 1013) */ + spr_set_rights(SPR_ENCODE(1013), SPR_SR | SPR_SW); + /* FPECR (SPR 1022) */ + spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW); + /* PIR (SPR 1023) */ + spr_set_rights(SPR_ENCODE(1023), SPR_SR | SPR_SW); + /* PVR (SPR 287) */ + spr_set_rights(SPR_ENCODE(287), SPR_SR); + /* TBL (SPR 284) */ + spr_set_rights(SPR_ENCODE(284), SPR_SW); + /* TBU (SPR 285) */ + spr_set_rights(SPR_ENCODE(285), SPR_SW); +} + +/* PPC "main stream" common instructions */ +#define PPC_COMMON (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ + PPC_MISC | PPC_EXTERN | PPC_SEGMENT) + +typedef struct ppc_proc_t { + int flags; + void *specific; +} ppc_proc_t; + +typedef struct ppc_def_t { + unsigned long pvr; + unsigned long pvr_mask; + ppc_proc_t *proc; +} ppc_def_t; + +static ppc_proc_t ppc_proc_common = { + .flags = PPC_COMMON, + .specific = NULL, +}; + +static ppc_def_t ppc_defs[] = +{ + /* Fallback */ + { + .pvr = 0x00000000, + .pvr_mask = 0x00000000, + .proc = &ppc_proc_common, + }, +}; + +static int create_ppc_proc (unsigned long pvr) +{ + opcode_t *opc; + int i, flags; + + fill_new_table(ppc_opcodes, 0x40); + for (i = 0; ; i++) { + if ((ppc_defs[i].pvr & ppc_defs[i].pvr_mask) == + (pvr & ppc_defs[i].pvr_mask)) { + flags = ppc_defs[i].proc->flags; + break; + } + } + + for (opc = &opc_start + 1; opc != &opc_end; opc++) { + if ((opc->type & flags) != 0) + if (register_insn(opc) < 0) { + fprintf(stderr, "*** ERROR initializing PPC instruction " + "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + opc->opc3); + return -1; + } + } + fix_opcode_tables(); + + return 0; +} + +/*****************************************************************************/ +uint32_t do_load_xer (void); + +void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) +{ + int i; + + if (loglevel > 0) { + fprintf(logfile, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x\n", + env->nip, env->LR, env->CTR, do_load_xer()); + for (i = 0; i < 32; i++) { + if ((i & 7) == 0) + fprintf(logfile, "GPR%02d:", i); + fprintf(logfile, " %08x", env->gpr[i]); + if ((i & 7) == 7) + fprintf(logfile, "\n"); + } + fprintf(logfile, "CR: 0x"); + for (i = 0; i < 8; i++) + fprintf(logfile, "%01x", env->crf[i]); + fprintf(logfile, " ["); + for (i = 0; i < 8; i++) { + char a = '-'; + + if (env->crf[i] & 0x08) + a = 'L'; + else if (env->crf[i] & 0x04) + a = 'G'; + else if (env->crf[i] & 0x02) + a = 'E'; + fprintf(logfile, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); + } + fprintf(logfile, " ] "); + fprintf(logfile, "TB: 0x%08x %08x\n", env->spr[SPR_ENCODE(269)], + env->spr[SPR_ENCODE(268)]); + for (i = 0; i < 16; i++) { + if ((i & 3) == 0) + fprintf(logfile, "FPR%02d:", i); + fprintf(logfile, " %016llx", env->fpr[i]); + if ((i & 3) == 3) + fprintf(logfile, "\n"); + } + fflush(logfile); + } +} + +CPUPPCState *cpu_ppc_init(void) +{ + CPUPPCState *env; + + cpu_exec_init(); + + env = malloc(sizeof(CPUPPCState)); + if (!env) + return NULL; + memset(env, 0, sizeof(CPUPPCState)); + env->PVR = 0; + if (create_ppc_proc(0) < 0) + return NULL; + init_spr_rights(); + + return env; +} + +void cpu_ppc_close(CPUPPCState *env) +{ + /* Should also remove all opcode tables... */ + free(env); +} + +int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, + int search_pc) +{ + DisasContext ctx; + opc_handler_t **table, *handler; + uint32_t pc_start; + uint16_t *gen_opc_end; + int j, lj = -1; + int ret = 0; + + pc_start = tb->pc; + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + ctx.nip = (uint32_t *)pc_start; + ctx.tb_offset = 0; + ctx.supervisor = msr_ip; + ctx.tb = tb; + ctx.exception = 0; + + while (ret == 0 && gen_opc_ptr < gen_opc_end) { + if (search_pc) { + if (loglevel > 0) + fprintf(logfile, "Search PC...\n"); + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + gen_opc_pc[lj] = (uint32_t)ctx.nip; + gen_opc_instr_start[lj] = 1; + } + } + ctx.opcode = __be32_to_cpu(*ctx.nip); +#ifdef DEBUG_DISAS + if (loglevel > 0) { + fprintf(logfile, "----------------\n"); + fprintf(logfile, "%p: translate opcode %08x\n", + ctx.nip, ctx.opcode); + } +#endif + ctx.nip++; + table = ppc_opcodes; + handler = table[opc1(ctx.opcode)]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + handler = table[opc2(ctx.opcode)]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + handler = table[opc3(ctx.opcode)]; + } + } + /* Is opcode *REALLY* valid ? */ + if ((ctx.opcode & handler->inval) != 0) { + if (loglevel > 0) { + if (handler->handler == &gen_invalid) { + fprintf(logfile, "invalid/unsupported opcode: " + "%02x -%02x - %02x (%08x)\n", opc1(ctx.opcode), + opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode); + } else { + fprintf(logfile, "invalid bits: %08x for opcode: " + "%02x -%02x - %02x (%p)\n", + ctx.opcode & handler->inval, opc1(ctx.opcode), + opc2(ctx.opcode), opc3(ctx.opcode), + handler->handler); + } + } + ret = GET_RETVAL(gen_invalid, ctx.opcode); + } else { + ret = GET_RETVAL(*(handler->handler), ctx.opcode); + } + ctx.tb_offset++; +#if defined (DO_SINGLE_STEP) + break; +#endif + } +#if defined (DO_STEP_FLUSH) + tb_flush(); +#endif + /* We need to update the time base */ + if (!search_pc) + gen_op_update_tb(ctx.tb_offset); + /* If we are in step-by-step mode, do a branch to the next instruction + * so the nip will be up-to-date + */ +#if defined (DO_SINGLE_STEP) + if (ret == 0) { + gen_op_b((uint32_t)ctx.nip); + ret = EXCP_BRANCH; + } +#endif + /* If the exeption isn't a PPC one, + * generate it now. + */ + if (ret != EXCP_BRANCH) { + gen_op_set_T0(0); + if ((ret & 0x2000) == 0) + gen_op_raise_exception(ret); + } + /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump + * do bad business and then qemu crashes ! + */ + gen_op_set_T0(0); + /* Generate the return instruction */ + gen_op_exit_tb(); + *gen_opc_ptr = INDEX_op_end; + if (!search_pc) + tb->size = (uint32_t)ctx.nip - pc_start; + else + tb->size = 0; +// *gen_opc_ptr = INDEX_op_end; +#ifdef DEBUG_DISAS + if (loglevel > 0) { + fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); + disas(logfile, (void *)pc_start, (uint32_t)ctx.nip - pc_start, 0, 0); + fprintf(logfile, "\n"); + + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + + return 0; +} + +int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 1); +} -- cgit v1.2.3 From 28b6751f30603a4c7146282fde9efcf8b5f31f7b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Nov 2003 16:58:08 +0000 Subject: suppressed use of gen_multi - use intermediate FT0 register for floats - use T0 temporary for fpscr update - use PARAM1 for spr access - added untested single load/store support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@473 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 1 + target-ppc/op.c | 236 +++++++++++++++++++++++++++++++++++++++++++++-- target-ppc/op.tpl | 197 --------------------------------------- target-ppc/op_template.h | 87 +++++++++++++++++ target-ppc/translate.c | 91 +++++++++++++----- 5 files changed, 385 insertions(+), 227 deletions(-) delete mode 100644 target-ppc/op.tpl create mode 100644 target-ppc/op_template.h diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 12cfc4648..5b8ea0ad8 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -172,6 +172,7 @@ typedef struct CPUPPCState { uint32_t exception; /* qemu dedicated */ + uint64_t ft0; /* temporary float register */ int interrupt_request; jmp_buf jmp_env; int exception_index; diff --git a/target-ppc/op.c b/target-ppc/op.c index ecb991786..e5ba00473 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -22,20 +22,110 @@ #include "exec.h" #define regs (env) -extern uint32_t __a; -extern uint32_t __b; -extern uint32_t __c; -extern uint32_t __d; -extern uint32_t __e; -extern uint32_t __f; #define Ts0 (int32_t)T0 #define Ts1 (int32_t)T1 #define Ts2 (int32_t)T2 -#include "op-multi.c" +#define FT0 (env->ft0) #define PPC_OP(name) void op_##name(void) +#define REG 0 +#include "op_template.h" + +#define REG 1 +#include "op_template.h" + +#define REG 2 +#include "op_template.h" + +#define REG 3 +#include "op_template.h" + +#define REG 4 +#include "op_template.h" + +#define REG 5 +#include "op_template.h" + +#define REG 6 +#include "op_template.h" + +#define REG 7 +#include "op_template.h" + +#define REG 8 +#include "op_template.h" + +#define REG 9 +#include "op_template.h" + +#define REG 10 +#include "op_template.h" + +#define REG 11 +#include "op_template.h" + +#define REG 12 +#include "op_template.h" + +#define REG 13 +#include "op_template.h" + +#define REG 14 +#include "op_template.h" + +#define REG 15 +#include "op_template.h" + +#define REG 16 +#include "op_template.h" + +#define REG 17 +#include "op_template.h" + +#define REG 18 +#include "op_template.h" + +#define REG 19 +#include "op_template.h" + +#define REG 20 +#include "op_template.h" + +#define REG 21 +#include "op_template.h" + +#define REG 22 +#include "op_template.h" + +#define REG 23 +#include "op_template.h" + +#define REG 24 +#include "op_template.h" + +#define REG 25 +#include "op_template.h" + +#define REG 26 +#include "op_template.h" + +#define REG 27 +#include "op_template.h" + +#define REG 28 +#include "op_template.h" + +#define REG 29 +#include "op_template.h" + +#define REG 30 +#include "op_template.h" + +#define REG 31 +#include "op_template.h" + /* PPC state maintenance operations */ /* set_Rc0 */ PPC_OP(set_Rc0) @@ -1114,3 +1204,135 @@ PPC_OP(stswx) do_stsw(PARAM(1), T0, T1 + T2); RETURN(); } + +/* SPR */ +PPC_OP(load_spr) +{ + T0 = regs->spr[PARAM(1)]; +} + +PPC_OP(store_spr) +{ + regs->spr[PARAM(1)] = T0; +} + +/* FPSCR */ +PPC_OP(load_fpscr) +{ + T0 = do_load_fpscr(); +} + +PPC_OP(store_fpscr) +{ + do_store_fpscr(PARAM(1), T0); +} + +/*** Floating-point store ***/ + +static inline uint32_t dtos(uint64_t f) +{ + unsigned int e, m, s; + e = (((f >> 52) & 0x7ff) - 1022) + 126; + s = (f >> 63); + m = (f >> 29); + return (s << 31) | (e << 23) | m; +} + +static inline uint64_t stod(uint32_t f) +{ + unsigned int e, m, s; + e = ((f >> 23) & 0xff) - 126 + 1022; + s = f >> 31; + m = f & ((1 << 23) - 1); + return ((uint64_t)s << 63) | ((uint64_t)e << 52) | ((uint64_t)m << 29); +} + +PPC_OP(stfd_z_FT0) +{ + st64(SPARAM(1), FT0); +} + +PPC_OP(stfd_FT0) +{ + T0 += SPARAM(1); + st64(T0, FT0); +} + +PPC_OP(stfdx_z_FT0) +{ + st64(T0, FT0); +} + +PPC_OP(stfdx_FT0) +{ + T0 += T1; + st64(T0, FT0); +} + + +PPC_OP(stfs_z_FT0) +{ + st32(SPARAM(1), dtos(FT0)); +} + +PPC_OP(stfs_FT0) +{ + T0 += SPARAM(1); + st32(T0, dtos(FT0)); +} + +PPC_OP(stfsx_z_FT0) +{ + st32(T0, dtos(FT0)); +} + +PPC_OP(stfsx_FT0) +{ + T0 += T1; + st32(T0, dtos(FT0)); +} + +/*** Floating-point load ***/ +PPC_OP(lfd_z_FT0) +{ + FT0 = ld64(SPARAM(1)); +} + +PPC_OP(lfd_FT0) +{ + T0 += SPARAM(1); + FT0 = ld64(T0); +} + +PPC_OP(lfdx_z_FT0) +{ + FT0 = ld64(T0); +} + +PPC_OP(lfdx_FT0) +{ + T0 += T1; + FT0 = ld64(T0); +} + +PPC_OP(lfs_z_FT0) +{ + FT0 = stod(ld32(SPARAM(1))); +} + +PPC_OP(lfs_FT0) +{ + T0 += SPARAM(1); + FT0 = stod(ld32(T0)); +} + +PPC_OP(lfsx_z_FT0) +{ + FT0 = stod(ld32(T0)); +} + +PPC_OP(lfsx_FT0) +{ + T0 += T1; + FT0 = stod(ld32(T0)); +} diff --git a/target-ppc/op.tpl b/target-ppc/op.tpl deleted file mode 100644 index f6f6d9817..000000000 --- a/target-ppc/op.tpl +++ /dev/null @@ -1,197 +0,0 @@ -/* - * PPC emulation micro-operations for qemu. - * - * Copyright (c) 2003 Jocelyn Mayer - * - * 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 - */ - -/* Host registers definitions */ -$DEFH T 3 -/* PPC registers definitions */ -$DEF gpr 32 -$DEF fpr 32 -$DEF crf 8 -$DEF spr 1024 - -/* PPC registers <-> host registers move */ -/* GPR */ -$OP load_gpr_T0 gpr -{ - T0 = regs->gpra; - RETURN(); -} -$ENDOP - -$OP load_gpr_T1 gpr -{ - T1 = regs->gpra; - RETURN(); -} -$ENDOP - -$OP load_gpr_T2 gpr -{ - T2 = regs->gpra; - RETURN(); -} -$ENDOP - -$OP store_T0_gpr gpr -{ - regs->gpra = T0; - RETURN(); -} -$ENDOP - -$OP store_T1_gpr gpr -{ - regs->gpra = T1; - RETURN(); -} -$ENDOP - -$OP store_gpr_P gpr PARAM -{ - regs->gpra = PARAM(1); - RETURN(); -} -$ENDOP - -/* crf */ -$OP load_crf_T0 crf -{ - T0 = regs->crfa; - RETURN(); -} -$ENDOP - -$OP load_crf_T1 crf -{ - T1 = regs->crfa; - RETURN(); -} -$ENDOP - -$OP store_T0_crf crf -{ - regs->crfa = T0; - RETURN(); -} -$ENDOP - -$OP store_T1_crf crf -{ - regs->crfa = T1; - RETURN(); -} -$ENDOP - -/* SPR */ -$OP load_spr spr -{ - T0 = regs->spra; - RETURN(); -} -$ENDOP - -$OP store_spr spr -{ - regs->spra = T0; - RETURN(); -} -$ENDOP - -/* FPSCR */ -$OP load_fpscr fpr -{ - regs->fpra = do_load_fpscr(); - RETURN(); -} -$ENDOP - -$OP store_fpscr fpr PARAM -{ - do_store_fpscr(PARAM(1), regs->fpra); - RETURN(); -} -$ENDOP - -/*** Floating-point store ***/ -/* candidate for helper (too long on x86 host) */ -$OP stfd_z fpr PARAM -{ - st64(SPARAM(1), regs->fpra); - RETURN(); -} -$ENDOP - -/* candidate for helper (too long on x86 host) */ -$OP stfd fpr PARAM -{ - T0 += SPARAM(1); - st64(T0, regs->fpra); - RETURN(); -} -$ENDOP - -/* candidate for helper (too long on x86 host) */ -$OP stfdx_z fpr -{ - st64(T0, regs->fpra); - RETURN(); -} -$ENDOP -/* candidate for helper (too long on x86 host) */ -$OP stfdx fpr -{ - T0 += T1; - st64(T0, regs->fpra); - RETURN(); -} -$ENDOP - -/* candidate for helper (too long on x86 host) */ -$OP lfd_z fpr PARAM -{ - regs->fpra = ld64(SPARAM(1)); - RETURN(); -} -$ENDOP - -/* candidate for helper (too long) */ -$OP lfd fpr PARAM -{ - T0 += SPARAM(1); - regs->fpra = ld64(T0); - RETURN(); -} -$ENDOP - -$OP lfdx_z fpr -{ - regs->fpra = ld64(T0); - RETURN(); -} -$ENDOP - -$OP lfdx fpr -{ - T0 += T1; - regs->fpra = ld64(T0); - RETURN(); -} -$ENDOP -/*****************************************************************************/ diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h new file mode 100644 index 000000000..d0a3f85f1 --- /dev/null +++ b/target-ppc/op_template.h @@ -0,0 +1,87 @@ +/* + * PPC emulation micro-operations for qemu. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void) +{ + T0 = regs->gpr[REG]; +} + +void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void) +{ + T1 = regs->gpr[REG]; +} + +void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void) +{ + T2 = regs->gpr[REG]; +} + +void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void) +{ + regs->gpr[REG] = T0; +} + +void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void) +{ + regs->gpr[REG] = T1; +} + +void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void) +{ + regs->gpr[REG] = T2; +} + +#if REG <= 7 + +void OPPROTO glue(op_load_crf_T0_crf, REG)(void) +{ + T0 = regs->crf[REG]; +} + +void OPPROTO glue(op_load_crf_T1_crf, REG)(void) +{ + T1 = regs->crf[REG]; +} + +void OPPROTO glue(op_store_T0_crf_crf, REG)(void) +{ + regs->crf[REG] = T0; +} + +void OPPROTO glue(op_store_T1_crf_crf, REG)(void) +{ + regs->crf[REG] = T1; +} + +#endif /* REG <= 7 */ + +/* float moves */ + +void OPPROTO glue(op_load_FT0_fpr, REG)(void) +{ + FT0 = env->fpr[REG]; +} + +void OPPROTO glue(op_store_FT0_fpr, REG)(void) +{ + env->fpr[REG] = FT0; +} + +#undef REG diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 5560e72b4..f2e30a78e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -36,7 +36,50 @@ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; #include "gen-op.h" -#include "select.h" + +typedef void (GenOpFunc)(void); + +#define GEN8(func, NAME) \ +static GenOpFunc *NAME ## _table [8] = {\ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,\ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,\ +};\ +static inline void func(int n)\ +{\ + NAME ## _table[n]();\ +} + +#define GEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = {\ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,\ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,\ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11,\ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,\ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,\ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,\ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,\ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,\ +};\ +static inline void func(int n)\ +{\ + NAME ## _table[n]();\ +} + +GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf) +GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf) +GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf) +GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf) + +GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr) +GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr) +GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr) + +GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr) +GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr) +GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr) + +GEN32(gen_op_load_FT0_fpr, gen_op_load_FT0_fpr) +GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr) static uint8_t spr_access[1024 / 2]; @@ -810,7 +853,8 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) /* mffs */ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) { - gen_op_load_fpscr(rD(ctx->opcode)); + gen_op_load_fpscr(); + gen_op_store_T0_gpr(rD(ctx->opcode)); if (Rc(ctx->opcode)) { /* Update CR1 */ } @@ -832,7 +876,8 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) /* mtfsf */ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) { - gen_op_store_fpscr(FM(ctx->opcode), rB(ctx->opcode)); + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_store_fpscr(FM(ctx->opcode)); if (Rc(ctx->opcode)) { /* Update CR1 */ } @@ -1182,11 +1227,12 @@ GEN_HANDLER(lf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0) { \ - gen_op_lf##width##_z(simm, rD(ctx->opcode)); \ + gen_op_lf##width##_z_FT0(simm); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_lf##width(simm, rD(ctx->opcode)); \ + gen_op_lf##width##_FT0(simm); \ } \ + gen_op_store_FT0_fpr(rD(ctx->opcode));\ SET_RETVAL(0); \ } @@ -1197,7 +1243,8 @@ GEN_HANDLER(lf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ rA(ctx->opcode) == rD(ctx->opcode)) \ SET_RETVAL(EXCP_INVAL); \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_lf##width(SIMM(ctx->opcode), rD(ctx->opcode)); \ + gen_op_lf##width##_FT0(SIMM(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode));\ gen_op_store_T0_gpr(rA(ctx->opcode)); \ SET_RETVAL(0); \ } @@ -1210,7 +1257,8 @@ GEN_HANDLER(lf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ SET_RETVAL(EXCP_INVAL); \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_lf##width##x(rD(ctx->opcode)); \ + gen_op_lf##width##x_FT0(); \ + gen_op_store_FT0_fpr(rD(ctx->opcode));\ gen_op_store_T0_gpr(rA(ctx->opcode)); \ SET_RETVAL(0); \ } @@ -1220,12 +1268,13 @@ GEN_HANDLER(lf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ - gen_op_lf##width##x_z(rD(ctx->opcode)); \ + gen_op_lf##width##x_z_FT0(); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_lf##width##x(rD(ctx->opcode)); \ + gen_op_lf##width##x_FT0(); \ } \ + gen_op_store_FT0_fpr(rD(ctx->opcode));\ SET_RETVAL(0); \ } @@ -1238,10 +1287,6 @@ GEN_LFX(width, opc | 0x00) /* lfd lfdu lfdux lfdx */ GEN_LDF(d, 0x12); /* lfs lfsu lfsux lfsx */ -#define gen_op_lfs_z(a, b) -#define gen_op_lfs(a, b) -#define gen_op_lfsx_z(a) -#define gen_op_lfsx(a) GEN_LDF(s, 0x10); /*** Floating-point store ***/ @@ -1249,11 +1294,12 @@ GEN_LDF(s, 0x10); GEN_HANDLER(stf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ uint32_t simm = SIMM(ctx->opcode); \ + gen_op_load_FT0_fpr(rS(ctx->opcode));\ if (rA(ctx->opcode) == 0) { \ - gen_op_stf##width##_z(simm, rS(ctx->opcode)); \ + gen_op_stf##width##_z_FT0(simm); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_stf##width(simm, rS(ctx->opcode)); \ + gen_op_stf##width##_FT0(simm); \ } \ SET_RETVAL(0); \ } @@ -1264,7 +1310,8 @@ GEN_HANDLER(stf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ if (rA(ctx->opcode) == 0) \ SET_RETVAL(EXCP_INVAL); \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_stf##width(SIMM(ctx->opcode), rS(ctx->opcode)); \ + gen_op_load_FT0_fpr(rS(ctx->opcode));\ + gen_op_stf##width##_FT0(SIMM(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ SET_RETVAL(0); \ } @@ -1276,7 +1323,8 @@ GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ SET_RETVAL(EXCP_INVAL); \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_stf##width##x(rS(ctx->opcode)); \ + gen_op_load_FT0_fpr(rS(ctx->opcode));\ + gen_op_stf##width##x_FT0(); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ SET_RETVAL(0); \ } @@ -1284,13 +1332,14 @@ GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ #define GEN_STFX(width, opc) \ GEN_HANDLER(stf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ + gen_op_load_FT0_fpr(rS(ctx->opcode));\ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ - gen_op_stf##width##x_z(rS(ctx->opcode)); \ + gen_op_stf##width##x_z_FT0(); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_stf##width##x(rS(ctx->opcode)); \ + gen_op_stf##width##x_FT0(); \ } \ SET_RETVAL(0); \ } @@ -1304,10 +1353,6 @@ GEN_STFX(width, opc | 0x00) /* stfd stfdu stfdux stfdx */ GEN_STOF(d, 0x16); /* stfs stfsu stfsux stfsx */ -#define gen_op_stfs_z(a, b) -#define gen_op_stfs(a, b) -#define gen_op_stfsx_z(a) -#define gen_op_stfsx(a) GEN_STOF(s, 0x14); /* Optional: */ -- cgit v1.2.3 From 678673089d1ba7cd0f2960a2815a0d5bb8a72fa3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Nov 2003 17:05:30 +0000 Subject: PowerPC target support (Jocelyn Mayer) - added better support for uid16 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@474 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +- Makefile.target | 4 + configure | 7 +- cpu-all.h | 9 ++ cpu-exec.c | 59 ++++++++-- disas.c | 2 + dyngen-exec.h | 18 +++ linux-user/elfload.c | 40 +++++++ linux-user/main.c | 131 +++++++++++++++++++++ linux-user/syscall.c | 283 ++++++++++++++++++++++++++++------------------ linux-user/syscall_defs.h | 64 ++++++++++- 11 files changed, 495 insertions(+), 125 deletions(-) diff --git a/Changelog b/Changelog index 3c98c5cf6..401f364cc 100644 --- a/Changelog +++ b/Changelog @@ -9,7 +9,8 @@ version 0.5.1: - 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 + - added verr, verw, arpl, fcmovxx + - PowerPC target support (Jocelyn Mayer) version 0.5.0: diff --git a/Makefile.target b/Makefile.target index b88887641..eb2e6db12 100644 --- a/Makefile.target +++ b/Makefile.target @@ -146,6 +146,10 @@ ifeq ($(TARGET_ARCH), i386) LIBOBJS+=helper.o helper2.o endif +ifeq ($(TARGET_ARCH), ppc) +LIBOBJS+=helper.o +endif + # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) diff --git a/configure b/configure index 3c9a29876..05bc3b6a6 100755 --- a/configure +++ b/configure @@ -27,7 +27,7 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386-user i386 i386-softmmu arm-user sparc-user" +target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" @@ -322,6 +322,7 @@ config_h=$target_dir/config.h target_cpu=`echo $target | cut -d '-' -f 1` target_bigendian="no" [ "$target_cpu" = "sparc" ] && target_bigendian=yes +[ "$target_cpu" = "ppc" ] && target_bigendian=yes target_softmmu="no" if expr $target : '.*-softmmu' > /dev/null ; then target_softmmu="yes" @@ -358,6 +359,10 @@ 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" = "ppc" ; then + echo "TARGET_ARCH=ppc" >> $config_mak + echo "#define TARGET_ARCH \"ppc\"" >> $config_h + echo "#define TARGET_PPC 1" >> $config_h else echo "Unsupported target CPU" exit 1 diff --git a/cpu-all.h b/cpu-all.h index c7491a00c..9c880824f 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -395,6 +395,15 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_interrupt cpu_sparc_interrupt #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_interrupt cpu_ppc_interrupt +#define cpu_signal_handler cpu_ppc_signal_handler + #else #error unsupported target CPU diff --git a/cpu-exec.c b/cpu-exec.c index 5bbace345..5507c04dd 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -133,6 +133,7 @@ int cpu_exec(CPUState *env1) env->cpsr = psr & ~0xf0000000; } #elif defined(TARGET_SPARC) +#elif defined(TARGET_PPC) #else #error unsupported target CPU #endif @@ -228,6 +229,8 @@ int cpu_exec(CPUState *env1) env->cpsr &= ~0xf0000000; #elif defined(TARGET_SPARC) cpu_sparc_dump_state (env, logfile, 0); +#elif defined(TARGET_PPC) + cpu_ppc_dump_state(env, logfile, 0); #else #error unsupported target CPU #endif @@ -246,13 +249,17 @@ int cpu_exec(CPUState *env1) cs_base = 0; pc = (uint8_t *)env->regs[15]; #elif defined(TARGET_SPARC) - flags = 0; - cs_base = 0; - if (env->npc) { - env->pc = env->npc; - env->npc = 0; - } - pc = (uint8_t *) env->pc; + flags = 0; + cs_base = 0; + if (env->npc) { + env->pc = env->npc; + env->npc = 0; + } + pc = (uint8_t *) env->pc; +#elif defined(TARGET_PPC) + flags = 0; + cs_base = 0; + pc = (uint8_t *)env->nip; #else #error unsupported CPU #endif @@ -376,6 +383,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_ARM) env->cpsr = compute_cpsr(); #elif defined(TARGET_SPARC) +#elif defined(TARGET_PPC) #else #error unsupported target CPU #endif @@ -513,6 +521,43 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { return 0; } +#elif defined (TARGET_PPC) +static inline int handle_cpu_signal(unsigned long pc, unsigned long address, + int is_write, sigset_t *old_set) +{ + TranslationBlock *tb; + +#if 0 + if (cpu_single_env) + env = cpu_single_env; /* XXX: find a correct solution for multithread */ +#endif +#if defined(DEBUG_SIGNAL) + printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", + pc, address, is_write, *(unsigned long *)old_set); +#endif + /* XXX: locking issue */ + if (is_write && page_unprotect(address)) { + return 1; + } + + /* now we have a real cpu fault */ + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc); + } +#if 0 + printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", + env->eip, env->cr[2], env->error_code); +#endif + /* we restore the process signal mask as the sigreturn should + do it (XXX: use sigsetjmp) */ + sigprocmask(SIG_SETMASK, old_set, NULL); + raise_exception_err(EXCP_PROGRAM, env->error_code); + /* never comes here */ + return 1; +} #else #error unsupported target CPU #endif diff --git a/disas.c b/disas.c index d5aa7f371..f274ac52d 100644 --- a/disas.c +++ b/disas.c @@ -171,6 +171,8 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) print_insn = print_insn_arm; #elif defined(TARGET_SPARC) print_insn = print_insn_sparc; +#elif defined(TARGET_PPC) + print_insn = print_insn_ppc; #else fprintf(out, "Asm output not supported on this arch\n"); return; diff --git a/dyngen-exec.h b/dyngen-exec.h index ec32fbc9e..2b8ba3a3e 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -17,6 +17,9 @@ * 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__ + typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; @@ -27,6 +30,19 @@ typedef signed short int16_t; typedef signed int int32_t; typedef signed long long int64_t; +#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)) + #define bswap32(x) \ ({ \ uint32_t __x = (x); \ @@ -191,3 +207,5 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __mc68000 #define EXIT_TB() asm volatile ("rts") #endif + +#endif /* !defined(__DYNGEN_EXEC_H__) */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index a0e205cd6..a7a2f61eb 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -104,6 +104,46 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif +#ifdef TARGET_PPC + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_PPC ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_PPC + +/* Note that isn't exactly what regular kernel does + * but this is what the ABI wants and is needed to allow + * execution of PPC BSD programs. + */ +#define ELF_PLAT_INIT(_r) \ +do { \ + unsigned long *pos = (unsigned long *)bprm->p, tmp = 1; \ + _r->gpr[3] = bprm->argc; \ + _r->gpr[4] = (unsigned long)++pos; \ + for (; tmp != 0; pos++) \ + tmp = *pos; \ + _r->gpr[5] = (unsigned long)pos; \ +} while (0) + +static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) +{ + _regs->msr = 1 << MSR_PR; /* Set user mode */ + _regs->gpr[1] = infop->start_stack; + _regs->nip = infop->entry; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + #include "elf.h" /* diff --git a/linux-user/main.c b/linux-user/main.c index 5b751541e..aa5b758d6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -324,6 +324,127 @@ void cpu_loop (CPUSPARCState *env) #endif +#ifdef TARGET_PPC + +void cpu_loop(CPUPPCState *env) +{ + int trapnr; + target_siginfo_t info; + + for(;;) { + trapnr = cpu_ppc_exec(env); + switch(trapnr) { + case EXCP_NONE: + case EXCP_INTERRUPT: + case EXCP_MTMSR: /* mtmsr instruction: */ + case EXCP_BRANCH: /* branch instruction */ + /* Single step mode */ + break; +#if 0 + case EXCP_RESET: /* System reset */ + fprintf(stderr, "RESET asked... Stop emulation\n"); + cpu_ppc_dump_state(env, stderr, 0); + abort(); +#endif + case EXCP_MACHINE_CHECK: /* Machine check exception */ + fprintf(stderr, "Machine check exeption... " + "See you in kernel code !\n"); + cpu_ppc_dump_state(env, stderr, 0); + abort(); + case EXCP_DSI: /* Impossible memory access */ + fprintf(stderr, "Invalid memory access\n"); + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->nip; + queue_signal(info.si_signo, &info); + break; + case EXCP_ISI: /* Impossible instruction fetch */ + fprintf(stderr, "Invalid instruction fetch\n"); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->nip; + queue_signal(info.si_signo, &info); + break; + case EXCP_EXTERNAL: /* External interruption */ + fprintf(stderr, "External access exeption\n"); + cpu_ppc_dump_state(env, stderr, 0); + abort(); + case EXCP_ALIGN: /* Alignment exception */ + fprintf(stderr, "Alignment exception\n"); + cpu_ppc_dump_state(env, stderr, 0); + abort(); + case EXCP_PROGRAM: /* Program exception */ + fprintf(stderr, "Program exception\n"); + cpu_ppc_dump_state(env, stderr, 0); + abort(); + break; + /* Trap */ + case EXCP_TRAP: /* Trap */ + case EXCP_TRACE: /* Trace exception (optional) */ + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->nip; + queue_signal(info.si_signo, &info); + break; + /* Invalid instruction */ + case EXCP_INVAL: + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->nip; + queue_signal(info.si_signo, &info); + break; + /* Privileged instruction */ + case EXCP_PRIV: /* Privileged instruction */ + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->nip; + queue_signal(info.si_signo, &info); + break; + case EXCP_NO_FP: /* No floating point */ + case EXCP_DECR: /* Decrementer exception */ + case EXCP_RESA: /* Implementation specific */ + case EXCP_RESB: /* Implementation specific */ + case EXCP_FP_ASSIST: /* Floating-point assist (optional) */ + fprintf(stderr, "Misc expt...\n"); + cpu_ppc_dump_state(env, stderr, 0); + abort(); + + case EXCP_SYSCALL: + { + uint32_t ret; + /* system call */ + /* WARNING: + * PPC ABI uses overflow flag in cr0 to signal an error + * in syscalls. + */ + env->crf[0] &= ~0x1; + ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8]); + if (ret > (uint32_t)(-515)) { + env->crf[0] |= 0x1; + ret = -ret; + } + env->gpr[3] = ret; + break; + } + default: +// error: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + cpu_ppc_dump_state(env, stderr, 0); + abort(); + } + process_pending_signals(env); + } +} +#endif + void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" @@ -517,6 +638,16 @@ int main(int argc, char **argv) #elif defined(TARGET_SPARC) env->pc = regs->u_regs[0]; env->regwptr[6] = regs->u_regs[1]-0x40; +#elif defined(TARGET_PPC) + { + int i; + for (i = 0; i < 32; i++) + env->msr[i] = (regs->msr >> i) & 1; + env->nip = regs->nip; + for(i = 0; i < 32; i++) { + env->gpr[i] = regs->gpr[i]; + } + } #else #error unsupported target CPU #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d218009ad..ddf1d9c52 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -65,6 +65,11 @@ //#define DEBUG +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) +/* 16 bit uid wrappers emulation */ +#define USE_UID16 +#endif + //#include #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) @@ -1264,7 +1269,16 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) new_env->regs[13] = newsp; new_env->regs[0] = 0; #elif defined(TARGET_SPARC) - printf ("HELPME: %s:%d\n", __FILE__, __LINE__); + printf ("HELPME: %s:%d\n", __FILE__, __LINE__); +#elif defined(TARGET_PPC) + if (!newsp) + newsp = env->gpr[1]; + new_env->gpr[1] = newsp; + { + int i; + for (i = 7; i < 32; i++) + new_env->gpr[i] = 0; + } #else #error unsupported target CPU #endif @@ -1325,11 +1339,41 @@ static long do_fcntl(int fd, int cmd, unsigned long arg) return ret; } +#ifdef USE_UID16 -#define high2lowuid(x) (x) -#define high2lowgid(x) (x) -#define low2highuid(x) (x) -#define low2highgid(x) (x) +static inline int high2lowuid(int uid) +{ + if (uid > 65535) + return 65534; + else + return uid; +} + +static inline int high2lowgid(int gid) +{ + if (gid > 65535) + return 65534; + else + return gid; +} + +static inline int low2highuid(int uid) +{ + if ((int16_t)uid == -1) + return -1; + else + return uid; +} + +static inline int low2highgid(int gid) +{ + if ((int16_t)gid == -1) + return -1; + else + return gid; +} + +#endif /* USE_UID16 */ void syscall_init(void) { @@ -1472,9 +1516,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_chmod: ret = get_errno(chmod((const char *)arg1, arg2)); break; - case TARGET_NR_lchown: - ret = get_errno(chown((const char *)arg1, arg2, arg3)); - break; #ifdef TARGET_NR_break case TARGET_NR_break: goto unimplemented; @@ -1495,12 +1536,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_umount: ret = get_errno(umount((const char *)arg1)); break; - case TARGET_NR_setuid: - ret = get_errno(setuid(low2highuid(arg1))); - break; - case TARGET_NR_getuid: - ret = get_errno(getuid()); - break; case TARGET_NR_stime: { int *time_ptr = (int *)arg1; @@ -1596,20 +1631,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_prof: goto unimplemented; #endif - case TARGET_NR_setgid: - ret = get_errno(setgid(low2highgid(arg1))); - break; - case TARGET_NR_getgid: - ret = get_errno(getgid()); - break; case TARGET_NR_signal: goto unimplemented; - case TARGET_NR_geteuid: - ret = get_errno(geteuid()); - break; - case TARGET_NR_getegid: - ret = get_errno(getegid()); - break; + case TARGET_NR_acct: goto unimplemented; case TARGET_NR_umount2: @@ -1844,12 +1868,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, /* NOTE: ret is eax, so not transcoding must be done */ ret = do_rt_sigreturn(cpu_env); break; - case TARGET_NR_setreuid: - ret = get_errno(setreuid(arg1, arg2)); - break; - case TARGET_NR_setregid: - ret = get_errno(setregid(arg1, arg2)); - break; case TARGET_NR_sethostname: ret = get_errno(sethostname((const char *)arg1, arg2)); break; @@ -1906,34 +1924,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(settimeofday(&tv, NULL)); } break; - case TARGET_NR_getgroups: - { - int gidsetsize = arg1; - uint16_t *target_grouplist = (void *)arg2; - gid_t *grouplist; - int i; - - grouplist = alloca(gidsetsize * sizeof(gid_t)); - ret = get_errno(getgroups(gidsetsize, grouplist)); - if (!is_error(ret)) { - for(i = 0;i < gidsetsize; i++) - target_grouplist[i] = tswap16(grouplist[i]); - } - } - break; - case TARGET_NR_setgroups: - { - int gidsetsize = arg1; - uint16_t *target_grouplist = (void *)arg2; - gid_t *grouplist; - int i; - - grouplist = alloca(gidsetsize * sizeof(gid_t)); - for(i = 0;i < gidsetsize; i++) - grouplist[i] = tswap16(target_grouplist[i]); - ret = get_errno(setgroups(gidsetsize, grouplist)); - } - break; case TARGET_NR_select: { struct target_sel_arg_struct *sel = (void *)arg1; @@ -2026,9 +2016,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_fchmod: ret = get_errno(fchmod(arg1, arg2)); break; - case TARGET_NR_fchown: - ret = get_errno(fchown(arg1, arg2, arg3)); - break; case TARGET_NR_getpriority: ret = get_errno(getpriority(arg1, arg2)); break; @@ -2121,10 +2108,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct target_stat *target_st = (void *)arg2; target_st->st_dev = tswap16(st.st_dev); target_st->st_ino = tswapl(st.st_ino); +#if defined(TARGET_PPC) + target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */ + target_st->st_uid = tswap32(st.st_uid); + target_st->st_gid = tswap32(st.st_gid); +#else target_st->st_mode = tswap16(st.st_mode); - target_st->st_nlink = tswap16(st.st_nlink); target_st->st_uid = tswap16(st.st_uid); target_st->st_gid = tswap16(st.st_gid); +#endif + target_st->st_nlink = tswap16(st.st_nlink); target_st->st_rdev = tswap16(st.st_rdev); target_st->st_size = tswapl(st.st_size); target_st->st_blksize = tswapl(st.st_blksize); @@ -2230,12 +2223,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_afs_syscall: goto unimplemented; - case TARGET_NR_setfsuid: - ret = get_errno(setfsuid(arg1)); - break; - case TARGET_NR_setfsgid: - ret = get_errno(setfsgid(arg1)); - break; case TARGET_NR__llseek: { int64_t res; @@ -2465,52 +2452,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; -#ifdef TARGET_NR_setresuid - case TARGET_NR_setresuid: - ret = get_errno(setresuid(low2highuid(arg1), - low2highuid(arg2), - low2highuid(arg3))); - break; -#endif -#ifdef TARGET_NR_getresuid - case TARGET_NR_getresuid: - { - int ruid, euid, suid; - ret = get_errno(getresuid(&ruid, &euid, &suid)); - if (!is_error(ret)) { - *(uint16_t *)arg1 = tswap16(high2lowuid(ruid)); - *(uint16_t *)arg2 = tswap16(high2lowuid(euid)); - *(uint16_t *)arg3 = tswap16(high2lowuid(suid)); - } - } - break; -#endif -#ifdef TARGET_NR_getresgid - case TARGET_NR_setresgid: - ret = get_errno(setresgid(low2highgid(arg1), - low2highgid(arg2), - low2highgid(arg3))); - break; -#endif -#ifdef TARGET_NR_getresgid - case TARGET_NR_getresgid: - { - int rgid, egid, sgid; - ret = get_errno(getresgid(&rgid, &egid, &sgid)); - if (!is_error(ret)) { - *(uint16_t *)arg1 = high2lowgid(tswap16(rgid)); - *(uint16_t *)arg2 = high2lowgid(tswap16(egid)); - *(uint16_t *)arg3 = high2lowgid(tswap16(sgid)); - } - } - break; -#endif case TARGET_NR_query_module: goto unimplemented; case TARGET_NR_nfsservctl: goto unimplemented; case TARGET_NR_prctl: goto unimplemented; +#ifdef TARGET_NR_pread case TARGET_NR_pread: page_unprotect_range((void *)arg2, arg3); ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4)); @@ -2518,9 +2466,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_pwrite: ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4)); break; - case TARGET_NR_chown: - ret = get_errno(chown((const char *)arg1, arg2, arg3)); - break; +#endif case TARGET_NR_getcwd: ret = get_errno(sys_getcwd1((char *)arg1, arg2)); break; @@ -2594,6 +2540,116 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; +#ifdef USE_UID16 + case TARGET_NR_lchown: + ret = get_errno(lchown((const char *)arg1, low2highuid(arg2), low2highgid(arg3))); + break; + case TARGET_NR_getuid: + ret = get_errno(high2lowuid(getuid())); + break; + case TARGET_NR_getgid: + ret = get_errno(high2lowgid(getgid())); + break; + case TARGET_NR_geteuid: + ret = get_errno(high2lowuid(geteuid())); + break; + case TARGET_NR_getegid: + ret = get_errno(high2lowgid(getegid())); + break; + case TARGET_NR_setreuid: + ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2))); + break; + case TARGET_NR_setregid: + ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2))); + break; + case TARGET_NR_getgroups: + { + int gidsetsize = arg1; + uint16_t *target_grouplist = (void *)arg2; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + ret = get_errno(getgroups(gidsetsize, grouplist)); + if (!is_error(ret)) { + for(i = 0;i < gidsetsize; i++) + target_grouplist[i] = tswap16(grouplist[i]); + } + } + break; + case TARGET_NR_setgroups: + { + int gidsetsize = arg1; + uint16_t *target_grouplist = (void *)arg2; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + for(i = 0;i < gidsetsize; i++) + grouplist[i] = tswap16(target_grouplist[i]); + ret = get_errno(setgroups(gidsetsize, grouplist)); + } + break; + case TARGET_NR_fchown: + ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3))); + break; +#ifdef TARGET_NR_setresuid + case TARGET_NR_setresuid: + ret = get_errno(setresuid(low2highuid(arg1), + low2highuid(arg2), + low2highuid(arg3))); + break; +#endif +#ifdef TARGET_NR_getresuid + case TARGET_NR_getresuid: + { + int ruid, euid, suid; + ret = get_errno(getresuid(&ruid, &euid, &suid)); + if (!is_error(ret)) { + *(uint16_t *)arg1 = tswap16(high2lowuid(ruid)); + *(uint16_t *)arg2 = tswap16(high2lowuid(euid)); + *(uint16_t *)arg3 = tswap16(high2lowuid(suid)); + } + } + break; +#endif +#ifdef TARGET_NR_getresgid + case TARGET_NR_setresgid: + ret = get_errno(setresgid(low2highgid(arg1), + low2highgid(arg2), + low2highgid(arg3))); + break; +#endif +#ifdef TARGET_NR_getresgid + case TARGET_NR_getresgid: + { + int rgid, egid, sgid; + ret = get_errno(getresgid(&rgid, &egid, &sgid)); + if (!is_error(ret)) { + *(uint16_t *)arg1 = tswap16(high2lowgid(rgid)); + *(uint16_t *)arg2 = tswap16(high2lowgid(egid)); + *(uint16_t *)arg3 = tswap16(high2lowgid(sgid)); + } + } + break; +#endif + case TARGET_NR_chown: + ret = get_errno(chown((const char *)arg1, low2highuid(arg2), low2highgid(arg3))); + break; + case TARGET_NR_setuid: + ret = get_errno(setuid(low2highuid(arg1))); + break; + case TARGET_NR_setgid: + ret = get_errno(setgid(low2highgid(arg1))); + break; + case TARGET_NR_setfsuid: + ret = get_errno(setfsuid(arg1)); + break; + case TARGET_NR_setfsgid: + ret = get_errno(setfsgid(arg1)); + break; +#endif /* USE_UID16 */ + case TARGET_NR_lchown32: ret = get_errno(lchown((const char *)arg1, arg2, arg3)); break; @@ -2665,6 +2721,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_setfsgid32: ret = get_errno(setfsgid(arg1)); break; + case TARGET_NR_pivot_root: goto unimplemented; case TARGET_NR_mincore: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 8f6d14e55..caa40d1f0 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -279,7 +279,7 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) #define TARGET_SA_NOCLDSTOP 0x00000001 #define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ @@ -664,7 +664,7 @@ struct target_pollfd { #define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) /* 0x54 is just a magic number to make these relatively unique ('T') */ @@ -891,6 +891,9 @@ struct target_termios { #define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ +#endif /* defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) */ + +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) struct target_stat { unsigned short st_dev; unsigned short __pad1; @@ -951,7 +954,62 @@ struct target_stat64 { unsigned long long st_ino; } __attribute__((packed)); -#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */ +#elif defined(TARGET_PPC) + +struct target_stat { + unsigned short st_dev; + target_ulong st_ino; + unsigned int st_mode; + unsigned short st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned short st_rdev; + target_ulong st_size; + target_ulong st_blksize; + target_ulong st_blocks; + target_ulong target_st_atime; + target_ulong __unused1; + target_ulong target_st_mtime; + target_ulong __unused2; + target_ulong target_st_ctime; + target_ulong __unused3; + target_ulong __unused4; + target_ulong __unused5; +}; + +struct target_stat64 { + unsigned long long st_dev; + + unsigned long long st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned int st_uid; + unsigned int st_gid; + + unsigned long long st_rdev; + unsigned short int __pad2; + + long long st_size; + target_ulong st_blksize; + + long long st_blocks; /* Number 512-byte blocks allocated. */ + + target_ulong target_st_atime; + target_ulong target_st_atime_nsec; + + target_ulong target_st_mtime; + target_ulong target_st_mtime_nsec; + + target_ulong target_st_ctime; + target_ulong target_st_ctime_nsec; + + target_ulong __unused4; + target_ulong __unused5; +}; + +#endif /* defined(TARGET_PPC) */ #define TARGET_F_DUPFD 0 /* dup */ #define TARGET_F_GETFD 1 /* get close_on_exec */ -- cgit v1.2.3 From 6dca2016fc0cca49ce866b7f2fcfffe011c1f496 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Nov 2003 17:32:06 +0000 Subject: fixed PPC state reloading git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@475 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-all.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/translate-all.c b/translate-all.c index ff9e037bb..b02c87a22 100644 --- a/translate-all.c +++ b/translate-all.c @@ -190,9 +190,9 @@ int cpu_restore_state(TranslationBlock *tb, #elif defined(TARGET_ARM) env->regs[15] = gen_opc_pc[j]; #elif defined(TARGET_SPARC) - env->pc = gen_opc_pc[j]; + env->pc = gen_opc_pc[j]; +#elif defined(TARGET_PPC) + env->nip = gen_opc_pc[j]; #endif return 0; } - - -- cgit v1.2.3 From 4136f33c7e3c034b17bb0032fa5d4297ae2f317a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Nov 2003 23:09:40 +0000 Subject: fixed eflags IF/IOPL update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@476 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 5 ---- target-i386/helper.c | 74 ++++++++++++++++++++++++++----------------------- target-i386/op.c | 32 ++++++++++----------- target-i386/translate.c | 18 ++++++++++-- 4 files changed, 70 insertions(+), 59 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index dd11a3a3e..f6c717eed 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -512,11 +512,6 @@ static inline uint32_t compute_eflags(void) return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); } -#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) - -#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \ - RF_MASK | AC_MASK | ID_MASK) - /* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */ static inline void load_eflags(int eflags, int update_mask) { diff --git a/target-i386/helper.c b/target-i386/helper.c index 861266fa1..a743cfb5a 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -419,7 +419,8 @@ static void switch_tss(int tss_selector, /* load all registers without an exception, then reload them with possible exception */ env->eip = new_eip; - eflags_mask = FL_UPDATE_CPL0_MASK; + eflags_mask = TF_MASK | AC_MASK | ID_MASK | + IF_MASK | IOPL_MASK | VM_MASK | RF_MASK; if (!(type & 8)) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); @@ -575,27 +576,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; uint32_t old_eip; -#ifdef DEBUG_PCALL - if (loglevel) { - static int count; - fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d CS:IP=%04x:%08x CPL=%d\n", - count, intno, error_code, is_int, env->segs[R_CS].selector, env->eip, env->hflags & 3); -#if 0 - { - int i; - uint8_t *ptr; - printf(" code="); - ptr = env->segs[R_CS].base + env->eip; - for(i = 0; i < 16; i++) { - printf(" %02x", ldub(ptr + i)); - } - printf("\n"); - } -#endif - count++; - } -#endif - has_error_code = 0; if (!is_int && !is_hw) { switch(intno) { @@ -775,7 +755,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, /* real mode interrupt */ static void do_interrupt_real(int intno, int is_int, int error_code, - unsigned int next_eip) + unsigned int next_eip) { SegmentCache *dt; uint8_t *ptr, *ssp; @@ -844,6 +824,27 @@ void do_interrupt_user(int intno, int is_int, int error_code, void do_interrupt(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw) { +#ifdef DEBUG_PCALL + if (loglevel) { + static int count; + fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", + count, intno, error_code, is_int); + cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); +#if 0 + { + int i; + uint8_t *ptr; + printf(" code="); + ptr = env->segs[R_CS].base + env->eip; + for(i = 0; i < 16; i++) { + printf(" %02x", ldub(ptr + i)); + } + printf("\n"); + } +#endif + count++; + } +#endif if (env->cr[0] & CR0_PE_MASK) { do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); } else { @@ -1293,6 +1294,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (loglevel) { fprintf(logfile, "lcall %04x:%08x\n", new_cs, new_eip); + cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); } #endif if ((new_cs & 0xfffc) == 0) @@ -1493,13 +1495,13 @@ void helper_iret_real(int shift) POPW(ssp, sp, sp_mask, new_cs); POPW(ssp, sp, sp_mask, new_eflags); } - ESP = (ESP & ~sp_mask) | (sp & 0xffff); + ESP = (ESP & ~sp_mask) | (sp & sp_mask); load_seg_vm(R_CS, new_cs); env->eip = new_eip; if (env->eflags & VM_MASK) - eflags_mask = FL_UPDATE_MASK32 | IF_MASK | RF_MASK; + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK; else - eflags_mask = FL_UPDATE_CPL0_MASK; + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK; if (shift == 0) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); @@ -1511,7 +1513,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask; uint32_t new_es, new_ds, new_fs, new_gs; uint32_t e1, e2, ss_e1, ss_e2; - int cpl, dpl, rpl, eflags_mask; + int cpl, dpl, rpl, eflags_mask, iopl; uint8_t *ssp; sp_mask = get_sp_mask(env->segs[R_SS].flags); @@ -1536,8 +1538,9 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) } #ifdef DEBUG_PCALL if (loglevel) { - fprintf(logfile, "lret new %04x:%08x\n", - new_cs, new_eip); + fprintf(logfile, "lret new %04x:%08x addend=0x%x\n", + new_cs, new_eip, addend); + cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); } #endif if ((new_cs & 0xfffc) == 0) @@ -1611,11 +1614,13 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) ESP = (ESP & ~sp_mask) | (sp & sp_mask); env->eip = new_eip; if (is_iret) { - /* NOTE: 'cpl' can be different from the current CPL */ + /* NOTE: 'cpl' is the _old_ CPL */ + eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK; if (cpl == 0) - eflags_mask = FL_UPDATE_CPL0_MASK; - else - eflags_mask = FL_UPDATE_MASK32; + eflags_mask |= IOPL_MASK; + iopl = (env->eflags >> IOPL_SHIFT) & 3; + if (cpl <= iopl) + eflags_mask |= IF_MASK; if (shift == 0) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); @@ -1631,7 +1636,8 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) POPL(ssp, sp, sp_mask, new_gs); /* modify processor state */ - load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); + load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | + IF_MASK | IOPL_MASK | VM_MASK | VIF_MASK | VIP_MASK); load_seg_vm(R_CS, new_cs & 0xffff); cpu_x86_set_cpl(env, 3); load_seg_vm(R_SS, new_ss & 0xffff); diff --git a/target-i386/op.c b/target-i386/op.c index 04046fc0b..8988e061c 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1138,38 +1138,36 @@ void OPPROTO op_set_cc_op(void) CC_OP = PARAM1; } -#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff) +/* XXX: clear VIF/VIP in all ops ? */ void OPPROTO op_movl_eflags_T0(void) { - int eflags; - eflags = T0; - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | - (eflags & FL_UPDATE_MASK32); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK)); } void OPPROTO op_movw_eflags_T0(void) { - int eflags; - eflags = T0; - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((eflags >> 10) & 1)); - /* we also update some system flags as in user mode */ - env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | - (eflags & FL_UPDATE_MASK16); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK) & 0xffff); +} + +void OPPROTO op_movl_eflags_T0_io(void) +{ + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK)); +} + +void OPPROTO op_movw_eflags_T0_io(void) +{ + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK) & 0xffff); } void OPPROTO op_movl_eflags_T0_cpl0(void) { - load_eflags(T0, FL_UPDATE_CPL0_MASK); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK)); } void OPPROTO op_movw_eflags_T0_cpl0(void) { - load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK) & 0xffff); } #if 0 diff --git a/target-i386/translate.c b/target-i386/translate.c index b09f1b7a4..9c5c52e4b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3540,10 +3540,18 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_movw_eflags_T0_cpl0(); } } else { - if (s->dflag) { - gen_op_movl_eflags_T0(); + if (s->cpl <= s->iopl) { + if (s->dflag) { + gen_op_movl_eflags_T0_io(); + } else { + gen_op_movw_eflags_T0_io(); + } } else { - gen_op_movw_eflags_T0(); + if (s->dflag) { + gen_op_movl_eflags_T0(); + } else { + gen_op_movw_eflags_T0(); + } } } gen_pop_update(s); @@ -4265,6 +4273,10 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, [INDEX_op_movw_eflags_T0] = CC_OSZAPC, [INDEX_op_movl_eflags_T0] = CC_OSZAPC, + [INDEX_op_movw_eflags_T0_io] = CC_OSZAPC, + [INDEX_op_movl_eflags_T0_io] = CC_OSZAPC, + [INDEX_op_movw_eflags_T0_cpl0] = CC_OSZAPC, + [INDEX_op_movl_eflags_T0_cpl0] = CC_OSZAPC, [INDEX_op_clc] = CC_C, [INDEX_op_stc] = CC_C, [INDEX_op_cmc] = CC_C, -- cgit v1.2.3 From 6bb705711b90a64dd1b4ff4dad41cf866e69de78 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Nov 2003 23:26:39 +0000 Subject: a20 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@477 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 9abf7ffc7..47c18fbaa 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -190,6 +190,10 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) { a20_state = (a20_state != 0); if (a20_state != a20_enabled) { + /* if the cpu is currently executing code, we must unlink it and + all the potentially executing TB */ + cpu_interrupt(env, 0); + /* when a20 is changed, all the MMU mappings are invalid, so we must flush everything */ page_unmap(); -- cgit v1.2.3 From 163a7cb6207f3a412da54b8d213571812338a044 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Nov 2003 19:40:08 +0000 Subject: imull fix (suggested by Robert J. Harley) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@478 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/op.c b/target-arm/op.c index 73f95b777..a27db0085 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -377,7 +377,7 @@ void OPPROTO op_mull_T0_T1(void) void OPPROTO op_imull_T0_T1(void) { uint64_t res; - res = (int64_t)T0 * (int64_t)T1; + res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); T1 = res >> 32; T0 = res; } -- cgit v1.2.3 From 791c2261d6f1d9fbb1c6d1194129828009f9025e Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 2 Dec 2003 21:55:34 +0000 Subject: more complete eflags testing for multiplication (P4 case only) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@479 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 821b79b65..0718f5a0e 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -33,6 +33,7 @@ #define TEST_CMOV 0 #define TEST_FCOMI 0 //#define LINUX_VM86_IOPL_FIX +//#define TEST_P4_FLAGS #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) @@ -352,7 +353,11 @@ void test_jcc(void) } #undef CC_MASK +#ifdef TEST_P4_FLAGS +#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) +#else #define CC_MASK (CC_O | CC_C) +#endif #define OP mul #include "test-i386-muldiv.h" @@ -360,15 +365,6 @@ void test_jcc(void) #define OP imul #include "test-i386-muldiv.h" -#undef CC_MASK -#define CC_MASK (0) - -#define OP div -#include "test-i386-muldiv.h" - -#define OP idiv -#include "test-i386-muldiv.h" - void test_imulw2(int op0, int op1) { int res, s1, s0, flags; @@ -405,6 +401,15 @@ void test_imull2(int op0, int op1) "imull", s0, s1, res, flags & CC_MASK); } +#undef CC_MASK +#define CC_MASK (0) + +#define OP div +#include "test-i386-muldiv.h" + +#define OP idiv +#include "test-i386-muldiv.h" + void test_mul(void) { test_imulb(0x1234561d, 4); -- cgit v1.2.3 From 5e809a80955cda9c4053fac02411edff733b4840 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 2 Dec 2003 21:59:21 +0000 Subject: dump irq inhibit flag as it is a part of the cpu state git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@480 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 47c18fbaa..7d74e2afa 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -112,7 +112,7 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) eflags = env->eflags; fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d\n", + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], env->eip, eflags, @@ -123,7 +123,8 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) eflags & CC_A ? 'A' : '-', eflags & CC_P ? 'P' : '-', eflags & CC_C ? 'C' : '-', - env->hflags & HF_CPL_MASK); + env->hflags & HF_CPL_MASK, + (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1); for(i = 0; i < 6; i++) { SegmentCache *sc = &env->segs[i]; fprintf(f, "%s =%04x %08x %08x %08x\n", -- cgit v1.2.3 From d36cd60e6c8c66e0279bad4b17e2d23833eb20b9 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 2 Dec 2003 22:01:31 +0000 Subject: P4 style multiplication eflags git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@481 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 5 ++++- target-i386/op.c | 35 +++++++++++++++-------------------- target-i386/ops_template.h | 23 +++++++++++++++++++++++ target-i386/translate.c | 10 +++++++--- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 0d5d8244c..07e48c0c2 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -184,7 +184,10 @@ enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ - CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */ + + CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */ + CC_OP_MULW, + CC_OP_MULL, CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ CC_OP_ADDW, diff --git a/target-i386/op.c b/target-i386/op.c index 8988e061c..5423be5a3 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -169,11 +169,16 @@ void OPPROTO op_bswapl_T0(void) } /* multiply/divide */ + +/* XXX: add eflags optimizations */ +/* XXX: add non P4 style flags */ + void OPPROTO op_mulb_AL_T0(void) { unsigned int res; res = (uint8_t)EAX * (uint8_t)T0; EAX = (EAX & 0xffff0000) | res; + CC_DST = res; CC_SRC = (res & 0xff00); } @@ -182,6 +187,7 @@ void OPPROTO op_imulb_AL_T0(void) int res; res = (int8_t)EAX * (int8_t)T0; EAX = (EAX & 0xffff0000) | (res & 0xffff); + CC_DST = res; CC_SRC = (res != (int8_t)res); } @@ -191,6 +197,7 @@ void OPPROTO op_mulw_AX_T0(void) res = (uint16_t)EAX * (uint16_t)T0; EAX = (EAX & 0xffff0000) | (res & 0xffff); EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + CC_DST = res; CC_SRC = res >> 16; } @@ -200,6 +207,7 @@ void OPPROTO op_imulw_AX_T0(void) res = (int16_t)EAX * (int16_t)T0; EAX = (EAX & 0xffff0000) | (res & 0xffff); EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + CC_DST = res; CC_SRC = (res != (int16_t)res); } @@ -209,6 +217,7 @@ void OPPROTO op_mull_EAX_T0(void) res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0); EAX = res; EDX = res >> 32; + CC_DST = res; CC_SRC = res >> 32; } @@ -218,6 +227,7 @@ void OPPROTO op_imull_EAX_T0(void) res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0); EAX = res; EDX = res >> 32; + CC_DST = res; CC_SRC = (res != (int32_t)res); } @@ -226,6 +236,7 @@ void OPPROTO op_imulw_T0_T1(void) int res; res = (int16_t)T0 * (int16_t)T1; T0 = res; + CC_DST = res; CC_SRC = (res != (int16_t)res); } @@ -234,6 +245,7 @@ void OPPROTO op_imull_T0_T1(void) int64_t res; res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); T0 = res; + CC_DST = res; CC_SRC = (res != (int32_t)res); } @@ -1293,31 +1305,14 @@ static int compute_c_eflags(void) return CC_SRC & CC_C; } -static int compute_c_mul(void) -{ - int cf; - cf = (CC_SRC != 0); - return cf; -} - -static int compute_all_mul(void) -{ - int cf, pf, af, zf, sf, of; - cf = (CC_SRC != 0); - pf = 0; /* undefined */ - af = 0; /* undefined */ - zf = 0; /* undefined */ - sf = 0; /* undefined */ - of = cf << 11; - return cf | pf | af | zf | sf | of; -} - CCTable cc_table[CC_OP_NB] = { [CC_OP_DYNAMIC] = { /* should never happen */ }, [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags }, - [CC_OP_MUL] = { compute_all_mul, compute_c_mul }, + [CC_OP_MULB] = { compute_all_mulb, compute_c_mull }, + [CC_OP_MULW] = { compute_all_mulw, compute_c_mull }, + [CC_OP_MULL] = { compute_all_mull, compute_c_mull }, [CC_OP_ADDB] = { compute_all_addb, compute_c_addb }, [CC_OP_ADDW] = { compute_all_addw, compute_c_addw }, diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 064881558..a486d2081 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -229,6 +229,29 @@ static int glue(compute_all_sar, SUFFIX)(void) return cf | pf | af | zf | sf | of; } +#if DATA_BITS == 32 +static int glue(compute_c_mul, SUFFIX)(void) +{ + int cf; + cf = (CC_SRC != 0); + return cf; +} +#endif + +/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and + CF are modified and it is slower to do that. */ +static int glue(compute_all_mul, SUFFIX)(void) +{ + int cf, pf, af, zf, sf, of; + cf = (CC_SRC != 0); + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((DATA_TYPE)CC_DST == 0) << 6; + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + of = cf << 11; + return cf | pf | af | zf | sf | of; +} + /* various optimized jumps cases */ void OPPROTO glue(op_jb_sub, SUFFIX)(void) diff --git a/target-i386/translate.c b/target-i386/translate.c index 9c5c52e4b..35067bff6 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2016,31 +2016,35 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) switch(ot) { case OT_BYTE: gen_op_mulb_AL_T0(); + s->cc_op = CC_OP_MULB; break; case OT_WORD: gen_op_mulw_AX_T0(); + s->cc_op = CC_OP_MULW; break; default: case OT_LONG: gen_op_mull_EAX_T0(); + s->cc_op = CC_OP_MULL; break; } - s->cc_op = CC_OP_MUL; break; case 5: /* imul */ switch(ot) { case OT_BYTE: gen_op_imulb_AL_T0(); + s->cc_op = CC_OP_MULB; break; case OT_WORD: gen_op_imulw_AX_T0(); + s->cc_op = CC_OP_MULW; break; default: case OT_LONG: gen_op_imull_EAX_T0(); + s->cc_op = CC_OP_MULL; break; } - s->cc_op = CC_OP_MUL; break; case 6: /* div */ switch(ot) { @@ -2235,7 +2239,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_imulw_T0_T1(); } gen_op_mov_reg_T0[ot][reg](); - s->cc_op = CC_OP_MUL; + s->cc_op = CC_OP_MULB + ot; break; case 0x1c0: case 0x1c1: /* xadd Ev, Gv */ -- cgit v1.2.3 From 07ad1b93a365a15c77b5848bba0f6a3399bce076 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 2 Dec 2003 22:18:10 +0000 Subject: disable keyboard interrupts if keyboard clock disabled (may not be fully correct) - added keyboard ID for extended keyboard git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@482 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 550443f88..830b5462d 100644 --- a/vl.c +++ b/vl.c @@ -1462,6 +1462,10 @@ void serial_received_byte(SerialState *s, int ch) s->lsr |= UART_LSR_BI | UART_LSR_DR; serial_update_irq(); break; + case 'd': + // tb_flush(); + cpu_set_log(CPU_LOG_ALL); + break; case TERM_ESCAPE: goto send_char; } @@ -1979,6 +1983,7 @@ void ne2000_init(void) /* Keyboard Commands */ #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ #define KBD_CMD_ECHO 0xEE +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ @@ -2065,6 +2070,8 @@ KBDState kbd_state; int reset_requested; /* update irq and KBD_STAT_[MOUSE_]OBF */ +/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be + incorrect, but it avoids having to simulate exact delays */ static void kbd_update_irq(KBDState *s) { int irq12_level, irq1_level; @@ -2080,7 +2087,8 @@ static void kbd_update_irq(KBDState *s) if (s->mode & KBD_MODE_MOUSE_INT) irq12_level = 1; } else { - if (s->mode & KBD_MODE_KBD_INT) + if ((s->mode & KBD_MODE_KBD_INT) && + !(s->mode & KBD_MODE_DISABLE_KBD)) irq1_level = 1; } } @@ -2120,7 +2128,7 @@ uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) KBDState *s = &kbd_state; int val; val = s->status; -#if defined(DEBUG_KBD) && 0 +#if defined(DEBUG_KBD) printf("kbd: read status=0x%02x\n", val); #endif return val; @@ -2162,9 +2170,11 @@ void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) break; case KBD_CCMD_KBD_DISABLE: s->mode |= KBD_MODE_DISABLE_KBD; + kbd_update_irq(s); break; case KBD_CCMD_KBD_ENABLE: s->mode &= ~KBD_MODE_DISABLE_KBD; + kbd_update_irq(s); break; case KBD_CCMD_READ_INPORT: kbd_queue(s, 0x00, 0); @@ -2251,6 +2261,11 @@ static void kbd_write_keyboard(KBDState *s, int val) case 0x05: kbd_queue(s, KBD_REPLY_RESEND, 0); break; + case KBD_CMD_GET_ID: + kbd_queue(s, KBD_REPLY_ACK, 0); + kbd_queue(s, 0xab, 0); + kbd_queue(s, 0x83, 0); + break; case KBD_CMD_ECHO: kbd_queue(s, KBD_CMD_ECHO, 0); break; -- cgit v1.2.3 From fb0eaffc6d9982b5eee439b8461851bd18bf35ce Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 14:57:11 +0000 Subject: PowerPC fixes (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@483 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 38 ++--------- target-ppc/exec.h | 13 +++- target-ppc/helper.c | 145 ++++++++++++++++++++------------------- target-ppc/op.c | 174 ++++++++++++++++++++++++++++++++++------------- target-ppc/op_template.h | 76 ++++++++++++++++++++- target-ppc/translate.c | 116 ++++++++++++++++++++++++------- 6 files changed, 382 insertions(+), 180 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 5b8ea0ad8..53824896a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -152,7 +152,7 @@ typedef struct CPUPPCState { /* general purpose registers */ uint32_t gpr[32]; /* floating point registers */ - uint64_t fpr[32]; + double fpr[32]; /* segment registers */ ppc_sr_t sr[16]; /* special purpose registers */ @@ -172,7 +172,10 @@ typedef struct CPUPPCState { uint32_t exception; /* qemu dedicated */ - uint64_t ft0; /* temporary float register */ + /* temporary float registers */ + double ft0; + double ft1; + double ft2; int interrupt_request; jmp_buf jmp_env; int exception_index; @@ -374,35 +377,4 @@ enum { EXCP_BRANCH = 0x104, /* branch instruction */ }; -/* - * We need to put in some extra aux table entries to tell glibc what - * the cache block size is, so it can use the dcbz instruction safely. - */ -#define AT_DCACHEBSIZE 19 -#define AT_ICACHEBSIZE 20 -#define AT_UCACHEBSIZE 21 -/* A special ignored type value for PPC, for glibc compatibility. */ -#define AT_IGNOREPPC 22 -/* - * The requirements here are: - * - keep the final alignment of sp (sp & 0xf) - * - make sure the 32-bit value at the first 16 byte aligned position of - * AUXV is greater than 16 for glibc compatibility. - * AT_IGNOREPPC is used for that. - * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, - * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. - */ -#define DLINFO_ARCH_ITEMS 3 -#define ARCH_DLINFO \ -do { \ - /* \ - * Now handle glibc compatibility. \ - */ \ - NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ - NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ - \ - NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ - NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ - NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ - } while (0) #endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 1bb7c1ddd..da1ebb765 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -29,6 +29,12 @@ register uint32_t T2 asm(AREG3); #define PARAM(n) ((uint32_t)PARAM##n) #define SPARAM(n) ((int32_t)PARAM##n) +#define FT0 (env->ft0) +#define FT1 (env->ft1) +#define FT2 (env->ft2) +#define FTS0 ((float)env->ft0) +#define FTS1 ((float)env->ft1) +#define FTS2 ((float)env->ft2) #define RETURN() __asm__ __volatile__(""); @@ -145,8 +151,8 @@ uint32_t do_load_xer (void); void do_store_xer (uint32_t value); uint32_t do_load_msr (void); void do_store_msr (uint32_t msr_value); -uint32_t do_load_fpscr (void); -void do_store_fpscr (uint8_t mask, uint32_t fp); +void do_load_fpscr (void); +void do_store_fpscr (uint32_t mask); int32_t do_sraw(int32_t Ta, uint32_t Tb); void do_lmw (int reg, uint32_t src); @@ -154,4 +160,7 @@ void do_stmw (int reg, uint32_t dest); void do_lsw (uint32_t reg, int count, uint32_t src); void do_stsw (uint32_t reg, int count, uint32_t dest); +void do_dcbz (void); +void do_icbi (void); + #endif /* !defined (__PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 87e54111e..b263d6535 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -121,67 +121,67 @@ void do_store_msr (uint32_t msr_value) } /* The 32 MSB of the target fpr are undefined. They'll be zero... */ -uint32_t do_load_fpscr (void) +/* Floating point operations helpers */ +void do_load_fpscr (void) { - return (fpscr_fx << FPSCR_FX) | - (fpscr_fex << FPSCR_FEX) | - (fpscr_vx << FPSCR_VX) | - (fpscr_ox << FPSCR_OX) | - (fpscr_ux << FPSCR_UX) | - (fpscr_zx << FPSCR_ZX) | - (fpscr_xx << FPSCR_XX) | - (fpscr_vsxnan << FPSCR_VXSNAN) | - (fpscr_vxisi << FPSCR_VXISI) | - (fpscr_vxidi << FPSCR_VXIDI) | - (fpscr_vxzdz << FPSCR_VXZDZ) | - (fpscr_vximz << FPSCR_VXIMZ) | - (fpscr_fr << FPSCR_FR) | - (fpscr_fi << FPSCR_FI) | - (fpscr_fprf << FPSCR_FPRF) | - (fpscr_vxsoft << FPSCR_VXSOFT) | - (fpscr_vxsqrt << FPSCR_VXSQRT) | - (fpscr_oe << FPSCR_OE) | - (fpscr_ue << FPSCR_UE) | - (fpscr_ze << FPSCR_ZE) | - (fpscr_xe << FPSCR_XE) | - (fpscr_ni << FPSCR_NI) | - (fpscr_rn << FPSCR_RN); + /* The 32 MSB of the target fpr are undefined. + * They'll be zero... + */ + union { + double d; + struct { + uint32_t u[2]; + } s; + } u; + int i; + + u.s.u[0] = 0; + u.s.u[1] = 0; + for (i = 0; i < 8; i++) + u.s.u[1] |= env->fpscr[i] << (4 * i); + FT0 = u.d; } -/* We keep only 32 bits of input... */ -/* For now, this is COMPLETELY BUGGY ! */ -void do_store_fpscr (uint8_t mask, uint32_t fp) +void do_store_fpscr (uint32_t mask) { + /* + * We use only the 32 LSB of the incoming fpr + */ + union { + double d; + struct { + uint32_t u[2]; + } s; + } u; int i; - for (i = 0; i < 7; i++) { - if ((mask & (1 << i)) == 0) - fp &= ~(0xf << (4 * i)); + u.d = FT0; + if (mask & 0x80) + env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[1] >> 28) & ~0x9); + for (i = 1; i < 7; i++) { + if (mask & (1 << (7 - i))) + env->fpscr[i] = (u.s.u[1] >> (4 * (7 - i))) & 0xF; + } + /* TODO: update FEX & VX */ + /* Set rounding mode */ + switch (env->fpscr[0] & 0x3) { + case 0: + /* Best approximation (round to nearest) */ + fesetround(FE_TONEAREST); + break; + case 1: + /* Smaller magnitude (round toward zero) */ + fesetround(FE_TOWARDZERO); + break; + case 2: + /* Round toward +infinite */ + fesetround(FE_UPWARD); + break; + case 3: + /* Round toward -infinite */ + fesetround(FE_DOWNWARD); + break; } - if ((mask & 80) != 0) - fpscr_fx = (fp >> FPSCR_FX) & 0x01; - fpscr_fex = (fp >> FPSCR_FEX) & 0x01; - fpscr_vx = (fp >> FPSCR_VX) & 0x01; - fpscr_ox = (fp >> FPSCR_OX) & 0x01; - fpscr_ux = (fp >> FPSCR_UX) & 0x01; - fpscr_zx = (fp >> FPSCR_ZX) & 0x01; - fpscr_xx = (fp >> FPSCR_XX) & 0x01; - fpscr_vsxnan = (fp >> FPSCR_VXSNAN) & 0x01; - fpscr_vxisi = (fp >> FPSCR_VXISI) & 0x01; - fpscr_vxidi = (fp >> FPSCR_VXIDI) & 0x01; - fpscr_vxzdz = (fp >> FPSCR_VXZDZ) & 0x01; - fpscr_vximz = (fp >> FPSCR_VXIMZ) & 0x01; - fpscr_fr = (fp >> FPSCR_FR) & 0x01; - fpscr_fi = (fp >> FPSCR_FI) & 0x01; - fpscr_fprf = (fp >> FPSCR_FPRF) & 0x1F; - fpscr_vxsoft = (fp >> FPSCR_VXSOFT) & 0x01; - fpscr_vxsqrt = (fp >> FPSCR_VXSQRT) & 0x01; - fpscr_oe = (fp >> FPSCR_OE) & 0x01; - fpscr_ue = (fp >> FPSCR_UE) & 0x01; - fpscr_ze = (fp >> FPSCR_ZE) & 0x01; - fpscr_xe = (fp >> FPSCR_XE) & 0x01; - fpscr_ni = (fp >> FPSCR_NI) & 0x01; - fpscr_rn = (fp >> FPSCR_RN) & 0x03; } int32_t do_sraw(int32_t value, uint32_t shift) @@ -220,20 +220,14 @@ void do_lsw (uint32_t reg, int count, uint32_t src) int sh; for (; count > 3; count -= 4, src += 4) { - if (reg == 32) - reg = 0; ugpr(reg++) = ld32(src); + if (T2 == 32) + T2 = 0; } if (count > 0) { - for (sh = 24, tmp = 0; count > 0; count--, src++, sh -= 8) { - if (reg == 32) - reg = 0; - tmp |= ld8(src) << sh; - if (sh == 0) { - sh = 32; - ugpr(reg++) = tmp; tmp = 0; - } + for (sh = 24; count > 0; count--, src++, sh -= 8) { + tmp |= ld8(src) << sh; } ugpr(reg) = tmp; } @@ -244,19 +238,30 @@ void do_stsw (uint32_t reg, int count, uint32_t dest) int sh; for (; count > 3; count -= 4, dest += 4) { + st32(dest, ugpr(reg++)); if (reg == 32) reg = 0; - st32(dest, ugpr(reg++)); } if (count > 0) { for (sh = 24; count > 0; count--, dest++, sh -= 8) { - if (reg == 32) - reg = 0; st8(dest, (ugpr(reg) >> sh) & 0xFF); - if (sh == 0) { - sh = 32; - reg++; } } +} + +void do_dcbz (void) +{ + int i; + + /* Assume cache line size is 32 */ + for (i = 0; i < 8; i++) { + st32(T0, 0); + T0 += 4; } } + +/* Instruction cache invalidation helper */ +void do_icbi (void) +{ + tb_invalidate_page(T0); +} diff --git a/target-ppc/op.c b/target-ppc/op.c index e5ba00473..cf77d5ee2 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -27,6 +27,12 @@ #define Ts2 (int32_t)T2 #define FT0 (env->ft0) +#define FT1 (env->ft1) +#define FT2 (env->ft2) + +#define FTS0 ((float)env->ft0) +#define FTS1 ((float)env->ft1) +#define FTS2 ((float)env->ft2) #define PPC_OP(name) void op_##name(void) @@ -173,6 +179,13 @@ PPC_OP(set_Rc0_1) RETURN(); } +/* Set Rc1 (for floating point arithmetic) */ +PPC_OP(set_Rc1) +{ + env->crf[1] = regs->fpscr[7]; + RETURN(); +} + PPC_OP(set_T0) { T0 = PARAM(1); @@ -278,6 +291,25 @@ PPC_OP(load_lr) RETURN(); } +/* FPSCR */ +PPC_OP(load_fpscr) +{ + do_load_fpscr(); + RETURN(); +} + +PPC_OP(store_fpscr) +{ + do_store_fpscr(PARAM(1)); + RETURN(); +} + +PPC_OP(reset_scrfx) +{ + regs->fpscr[7] &= ~0x8; + RETURN(); +} + /* Set reservation */ PPC_OP(set_reservation) { @@ -988,7 +1020,7 @@ PPC_OP(xori) /* rotate left word immediate then mask insert */ PPC_OP(rlwimi) { - T0 = rotl(T0, PARAM(1) & PARAM(2)) | (T0 & PARAM(3)); + T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3)); RETURN(); } @@ -1216,123 +1248,171 @@ PPC_OP(store_spr) regs->spr[PARAM(1)] = T0; } -/* FPSCR */ -PPC_OP(load_fpscr) -{ - T0 = do_load_fpscr(); -} - -PPC_OP(store_fpscr) -{ - do_store_fpscr(PARAM(1), T0); -} - /*** Floating-point store ***/ -static inline uint32_t dtos(uint64_t f) -{ - unsigned int e, m, s; - e = (((f >> 52) & 0x7ff) - 1022) + 126; - s = (f >> 63); - m = (f >> 29); - return (s << 31) | (e << 23) | m; -} - -static inline uint64_t stod(uint32_t f) -{ - unsigned int e, m, s; - e = ((f >> 23) & 0xff) - 126 + 1022; - s = f >> 31; - m = f & ((1 << 23) - 1); - return ((uint64_t)s << 63) | ((uint64_t)e << 52) | ((uint64_t)m << 29); -} - PPC_OP(stfd_z_FT0) { - st64(SPARAM(1), FT0); + stfq((void *)SPARAM(1), FT0); } PPC_OP(stfd_FT0) { T0 += SPARAM(1); - st64(T0, FT0); + stfq((void *)T0, FT0); } PPC_OP(stfdx_z_FT0) { - st64(T0, FT0); + stfq((void *)T0, FT0); } PPC_OP(stfdx_FT0) { T0 += T1; - st64(T0, FT0); + stfq((void *)T0, FT0); } - PPC_OP(stfs_z_FT0) { - st32(SPARAM(1), dtos(FT0)); + float tmp = FT0; + stfl((void *)SPARAM(1), tmp); } PPC_OP(stfs_FT0) { + float tmp = FT0; T0 += SPARAM(1); - st32(T0, dtos(FT0)); + stfl((void *)T0, tmp); } PPC_OP(stfsx_z_FT0) { - st32(T0, dtos(FT0)); + float tmp = FT0; + stfl((void *)T0, tmp); } PPC_OP(stfsx_FT0) { + float tmp = FT0; T0 += T1; - st32(T0, dtos(FT0)); + stfl((void *)T0, tmp); } /*** Floating-point load ***/ PPC_OP(lfd_z_FT0) { - FT0 = ld64(SPARAM(1)); + FT0 = ldfq((void *)SPARAM(1)); } PPC_OP(lfd_FT0) { T0 += SPARAM(1); - FT0 = ld64(T0); + FT0 = ldfq((void *)T0); } PPC_OP(lfdx_z_FT0) { - FT0 = ld64(T0); + FT0 = ldfq((void *)T0); } PPC_OP(lfdx_FT0) { T0 += T1; - FT0 = ld64(T0); + FT0 = ldfq((void *)T0); } PPC_OP(lfs_z_FT0) { - FT0 = stod(ld32(SPARAM(1))); + float tmp = ldfl((void *)SPARAM(1)); + FT0 = tmp; } PPC_OP(lfs_FT0) { + float tmp; T0 += SPARAM(1); - FT0 = stod(ld32(T0)); + tmp = ldfl((void *)T0); + FT0 = tmp; } PPC_OP(lfsx_z_FT0) { - FT0 = stod(ld32(T0)); + float tmp; + tmp = ldfl((void *)T0); + FT0 = tmp; } PPC_OP(lfsx_FT0) +{ + float tmp; + T0 += T1; + tmp = ldfl((void *)T0); + FT0 = tmp; +} + +PPC_OP(lwarx_z) +{ + T1 = ld32(T0); + regs->reserve = T0; + RETURN(); +} + +PPC_OP(lwarx) +{ + T0 += T1; + T1 = ld32(T0); + regs->reserve = T0; + RETURN(); +} + +PPC_OP(stwcx_z) +{ + if (regs->reserve != T0) { + env->crf[0] = xer_ov; + } else { + st32(T0, T1); + env->crf[0] = xer_ov | 0x02; + } + regs->reserve = 0; + RETURN(); +} + +PPC_OP(stwcx) { T0 += T1; - FT0 = stod(ld32(T0)); + if (regs->reserve != (T0 & ~0x03)) { + env->crf[0] = xer_ov; + } else { + st32(T0, T2); + env->crf[0] = xer_ov | 0x02; + } + regs->reserve = 0; + RETURN(); +} + +PPC_OP(dcbz_z) +{ + do_dcbz(); + RETURN(); +} + +PPC_OP(dcbz) +{ + T0 += T1; + do_dcbz(); + RETURN(); +} + +/* Instruction cache block invalidate */ +PPC_OP(icbi_z) +{ + do_icbi(); + RETURN(); +} + +PPC_OP(icbi) +{ + T0 += T1; + do_icbi(); + RETURN(); } diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index d0a3f85f1..4a849ffea 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -70,18 +70,90 @@ void OPPROTO glue(op_store_T1_crf_crf, REG)(void) regs->crf[REG] = T1; } +/* Floating point condition and status register moves */ +void OPPROTO glue(op_load_fpscr_T0_fpscr, REG)(void) +{ + T0 = regs->fpscr[REG]; + RETURN(); +} + +#if REG == 0 +void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void) +{ + regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9); + RETURN(); +} + +void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void) +{ + regs->fpscr[REG] = (regs->fpscr[REG] & ~0x9) | (PARAM(1) & 0x9); + RETURN(); +} + +void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void) +{ + regs->fpscr[REG] = (regs->fpscr[REG] & 0x9); + RETURN(); +} +#else +void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void) +{ + regs->fpscr[REG] = T0; + RETURN(); +} + +void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void) +{ + regs->fpscr[REG] = PARAM(1); + RETURN(); +} + +void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void) +{ + regs->fpscr[REG] = 0x0; + RETURN(); +} +#endif + #endif /* REG <= 7 */ /* float moves */ -void OPPROTO glue(op_load_FT0_fpr, REG)(void) +/* floating point registers moves */ +void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void) { FT0 = env->fpr[REG]; + RETURN(); } -void OPPROTO glue(op_store_FT0_fpr, REG)(void) +void OPPROTO glue(op_store_FT0_fpr_fpr, REG)(void) { env->fpr[REG] = FT0; + RETURN(); +} + +void OPPROTO glue(op_load_fpr_FT1_fpr, REG)(void) +{ + FT1 = env->fpr[REG]; + RETURN(); +} + +void OPPROTO glue(op_store_FT1_fpr_fpr, REG)(void) +{ + env->fpr[REG] = FT1; + RETURN(); +} + +void OPPROTO glue(op_load_fpr_FT2_fpr, REG)(void) +{ + FT2 = env->fpr[REG]; + RETURN(); +} + +void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void) +{ + env->fpr[REG] = FT2; + RETURN(); } #undef REG diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f2e30a78e..60b511c19 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -38,6 +38,9 @@ static uint32_t *gen_opparam_ptr; #include "gen-op.h" typedef void (GenOpFunc)(void); +typedef void (GenOpFunc1)(long); +typedef void (GenOpFunc2)(long, long); +typedef void (GenOpFunc3)(long, long, long); #define GEN8(func, NAME) \ static GenOpFunc *NAME ## _table [8] = {\ @@ -70,6 +73,25 @@ GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf) GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf) GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf) +/* Floating point condition and status register moves */ +GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr); +GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr); +GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr); +static GenOpFunc1 *gen_op_store_T0_fpscri_fpscr_table[8] = { + &gen_op_store_T0_fpscri_fpscr0, + &gen_op_store_T0_fpscri_fpscr1, + &gen_op_store_T0_fpscri_fpscr2, + &gen_op_store_T0_fpscri_fpscr3, + &gen_op_store_T0_fpscri_fpscr4, + &gen_op_store_T0_fpscri_fpscr5, + &gen_op_store_T0_fpscri_fpscr6, + &gen_op_store_T0_fpscri_fpscr7, +}; +static inline void gen_op_store_T0_fpscri(int n, uint8_t param) +{ + (*gen_op_store_T0_fpscri_fpscr_table[n])(param); +} + GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr) GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr) GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr) @@ -78,8 +100,13 @@ GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr) GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr) GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr) -GEN32(gen_op_load_FT0_fpr, gen_op_load_FT0_fpr) -GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr) +/* floating point registers moves */ +GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr); +GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr); +GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr); +GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr); +GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr); +GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr); static uint8_t spr_access[1024 / 2]; @@ -198,10 +225,14 @@ EXTRACT_HELPER(SH, 11, 5); EXTRACT_HELPER(MB, 6, 5); /* Mask end */ EXTRACT_HELPER(ME, 1, 5); +/* Trap operand */ +EXTRACT_HELPER(TO, 21, 5); EXTRACT_HELPER(CRM, 12, 8); EXTRACT_HELPER(FM, 17, 8); EXTRACT_HELPER(SR, 16, 4); +EXTRACT_HELPER(FPIMM, 20, 4); + /*** Jump target decoding ***/ /* Displacement */ EXTRACT_SHELPER(d, 0, 16); @@ -597,6 +628,7 @@ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) mb = MB(ctx->opcode); me = ME(ctx->opcode); gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me)); if (Rc(ctx->opcode) != 0) gen_op_set_Rc0(); @@ -847,47 +879,67 @@ GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) /* mcrfs */ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) { - SET_RETVAL(EXCP_INVAL); + gen_op_load_fpscr_T0(crfS(ctx->opcode)); + gen_op_store_T0_crf(crfD(ctx->opcode)); + gen_op_clear_fpscr(crfS(ctx->opcode)); + SET_RETVAL(0); } /* mffs */ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) { gen_op_load_fpscr(); - gen_op_store_T0_gpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) { - /* Update CR1 */ - } + gen_op_store_FT0_fpr(rD(ctx->opcode)); + if (Rc(ctx->opcode)) + gen_op_set_Rc1(); SET_RETVAL(0); } /* mtfsb0 */ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) { - SET_RETVAL(EXCP_INVAL); + uint8_t crb; + + crb = crbD(ctx->opcode) >> 2; + gen_op_load_fpscr_T0(crb); + gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03))); + gen_op_store_T0_fpscr(crb); + if (Rc(ctx->opcode)) + gen_op_set_Rc1(); + SET_RETVAL(0); } /* mtfsb1 */ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) { - SET_RETVAL(EXCP_INVAL); + uint8_t crb; + + crb = crbD(ctx->opcode) >> 2; + gen_op_load_fpscr_T0(crb); + gen_op_ori(1 << (crbD(ctx->opcode) & 0x03)); + gen_op_store_T0_fpscr(crb); + if (Rc(ctx->opcode)) + gen_op_set_Rc1(); + SET_RETVAL(0); } /* mtfsf */ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) { - gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_store_fpscr(FM(ctx->opcode)); - if (Rc(ctx->opcode)) { - /* Update CR1 */ - } + if (Rc(ctx->opcode)) + gen_op_set_Rc1(); SET_RETVAL(0); } /* mtfsfi */ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) { - SET_RETVAL(EXCP_INVAL); + gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode)); + if (Rc(ctx->opcode)) + gen_op_set_Rc1(); + SET_RETVAL(0); } /*** Integer load ***/ @@ -1179,13 +1231,11 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_MEM) reserve = 1; if (rA(ctx->opcode) == 0) { gen_op_load_gpr_T0(rB(ctx->opcode)); - gen_op_lwzx_z(); - gen_op_set_reservation(); + gen_op_lwarx_z(); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_lwzx(); - gen_op_set_reservation(); + gen_op_lwarx(); } gen_op_store_T1_gpr(rD(ctx->opcode)); SET_RETVAL(0); @@ -1207,8 +1257,6 @@ GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_MEM) gen_op_load_gpr_T2(rS(ctx->opcode)); gen_op_stwx(); } - gen_op_set_Rc0_1(); - gen_op_reset_reservation(); } SET_RETVAL(0); } @@ -1294,7 +1342,7 @@ GEN_LDF(s, 0x10); GEN_HANDLER(stf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ uint32_t simm = SIMM(ctx->opcode); \ - gen_op_load_FT0_fpr(rS(ctx->opcode));\ + gen_op_load_fpr_FT0(rS(ctx->opcode));\ if (rA(ctx->opcode) == 0) { \ gen_op_stf##width##_z_FT0(simm); \ } else { \ @@ -1310,7 +1358,7 @@ GEN_HANDLER(stf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ if (rA(ctx->opcode) == 0) \ SET_RETVAL(EXCP_INVAL); \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_FT0_fpr(rS(ctx->opcode));\ + gen_op_load_fpr_FT0(rS(ctx->opcode));\ gen_op_stf##width##_FT0(SIMM(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ SET_RETVAL(0); \ @@ -1323,7 +1371,7 @@ GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ SET_RETVAL(EXCP_INVAL); \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_load_FT0_fpr(rS(ctx->opcode));\ + gen_op_load_fpr_FT0(rS(ctx->opcode));\ gen_op_stf##width##x_FT0(); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ SET_RETVAL(0); \ @@ -1332,7 +1380,7 @@ GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ #define GEN_STFX(width, opc) \ GEN_HANDLER(stf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ - gen_op_load_FT0_fpr(rS(ctx->opcode));\ + gen_op_load_fpr_FT0(rS(ctx->opcode));\ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ gen_op_stf##width##x_z_FT0(); \ @@ -1811,12 +1859,28 @@ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x02, 0x03E00001, PPC_MEM) /* dcbz */ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x08, 0x03E00001, PPC_MEM) { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_dcbz_z(); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_dcbz(); + } SET_RETVAL(0); } /* icbi */ GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_MEM) { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_icbi_z(); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_icbi(); + } SET_RETVAL(0); } @@ -2252,7 +2316,7 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) for (i = 0; i < 16; i++) { if ((i & 3) == 0) fprintf(logfile, "FPR%02d:", i); - fprintf(logfile, " %016llx", env->fpr[i]); + fprintf(logfile, " %016llx", *((uint64_t *)(&env->fpr[i]))); if ((i & 3) == 3) fprintf(logfile, "\n"); } @@ -2361,7 +2425,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #endif } #if defined (DO_STEP_FLUSH) - tb_flush(); + tb_flush(env); #endif /* We need to update the time base */ if (!search_pc) -- cgit v1.2.3 From cf495bcf9ffe0f1450a5de7497612dd1be23ff2a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:01:44 +0000 Subject: SPARC fixes: corrected PC/NPC logic (now slower but can be optimized a lot) - fixed flags computations - added register window exceptions support - fixed mul and div - added mulscc - fixed immediate field decoding git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@484 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/sparc/syscall_nr.h | 2 +- target-sparc/cpu.h | 45 +- target-sparc/op.c | 501 ++++++++++------ target-sparc/translate.c | 1281 ++++++++++++++++++++++------------------- 4 files changed, 1064 insertions(+), 765 deletions(-) diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index afb364f07..3270a3021 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -182,7 +182,7 @@ #define TARGET_NR_sysinfo 214 /* Linux Specific */ #define TARGET_NR_ipc 215 /* Linux Specific */ #define TARGET_NR_sigreturn 216 /* Linux Specific */ -#define TARGET_NR_clone 217 /* Linux Specific */ +#define TARGET_NR_clone 2170 /* Linux Specific */ #define TARGET_NR_adjtimex 219 /* Linux Specific */ #define TARGET_NR_sigprocmask 220 /* Linux Specific */ #define TARGET_NR_create_module 221 /* Linux Specific */ diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 350d7b719..67fece712 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -7,29 +7,42 @@ /*#define EXCP_INTERRUPT 0x100*/ +/* trap definitions */ +#define TT_ILL_INSN 0x02 +#define TT_WIN_OVF 0x05 +#define TT_WIN_UNF 0x06 +#define TT_DIV_ZERO 0x2a +#define TT_TRAP 0x80 #define PSR_NEG (1<<23) #define PSR_ZERO (1<<22) #define PSR_OVF (1<<21) #define PSR_CARRY (1<<20) +#define NWINDOWS 32 + typedef struct CPUSPARCState { - uint32_t gregs[8]; /* general registers */ - uint32_t *regwptr; /* pointer to current register window */ - double *regfptr; /* floating point registers */ - uint32_t pc; /* program counter */ - uint32_t npc; /* next program counter */ - uint32_t sp; /* stack pointer */ - uint32_t y; /* multiply/divide register */ - uint32_t psr; /* processor state register */ - uint32_t T2; - jmp_buf jmp_env; - int user_mode_only; - int exception_index; - int interrupt_index; - int interrupt_request; - struct TranslationBlock *current_tb; - void *opaque; + uint32_t gregs[8]; /* general registers */ + uint32_t *regwptr; /* pointer to current register window */ + double *regfptr; /* floating point registers */ + uint32_t pc; /* program counter */ + uint32_t npc; /* next program counter */ + uint32_t sp; /* stack pointer */ + uint32_t y; /* multiply/divide register */ + uint32_t psr; /* processor state register */ + uint32_t T2; + uint32_t cwp; /* index of current register window (extracted + from PSR) */ + uint32_t wim; /* window invalid mask */ + jmp_buf jmp_env; + int user_mode_only; + int exception_index; + int interrupt_index; + int interrupt_request; + struct TranslationBlock *current_tb; + void *opaque; + /* NOTE: we allow 8 more registers to handle wrapping */ + uint32_t regbase[NWINDOWS * 16 + 8]; } CPUSPARCState; CPUSPARCState *cpu_sparc_init(void); diff --git a/target-sparc/op.c b/target-sparc/op.c index 65922aa77..394c2241a 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -20,7 +20,7 @@ #include "exec.h" -/*XXX*/ + /*XXX*/ #define REGNAME g0 #define REG (env->gregs[0]) #include "op_template.h" @@ -117,380 +117,545 @@ #define REGNAME o7 #define REG (env->regwptr[7]) #include "op_template.h" - #define EIP (env->pc) +#define FLAG_SET(x) (env->psr&x)?1:0 +#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY) + void OPPROTO op_movl_T0_0(void) { - T0 = 0; + T0 = 0; } void OPPROTO op_movl_T0_1(void) { - T0 = 1; + T0 = 1; } void OPPROTO op_movl_T0_im(void) { - T0 = PARAM1; + T0 = PARAM1; } void OPPROTO op_movl_T1_im(void) { - T1 = PARAM1; + T1 = PARAM1; } void OPPROTO op_movl_T2_im(void) { - T2 = PARAM1; + T2 = PARAM1; } void OPPROTO op_addl_T1_im(void) { - T1 += PARAM1; + T1 += PARAM1; } void OPPROTO op_addl_T1_T2(void) { - T1 += T2; + T1 += T2; } void OPPROTO op_subl_T1_T2(void) { - T1 -= T2; + T1 -= T2; } -void OPPROTO op_add_T1_T0 (void) +void OPPROTO op_add_T1_T0(void) { - T0 += T1; + T0 += T1; } -void OPPROTO op_and_T1_T0 (void) +void OPPROTO op_add_T1_T0_cc(void) { - T0 &= T1; + unsigned int src1; + src1 = T0; + T0 += T1; + env->psr = 0; + if (!T0) + env->psr |= PSR_ZERO; + if ((int) T0 < 0) + env->psr |= PSR_NEG; + if (T0 < src1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + FORCE_RET(); } -void OPPROTO op_or_T1_T0 (void) +void OPPROTO op_sub_T1_T0(void) { - T0 |= T1; + T0 -= T1; } -void OPPROTO op_xor_T1_T0 (void) +void OPPROTO op_sub_T1_T0_cc(void) { - T0 ^= T1; + unsigned int src1; + + src1 = T0; + T0 -= T1; + env->psr = 0; + if (!T0) + env->psr |= PSR_ZERO; + if ((int) T0 < 0) + env->psr |= PSR_NEG; + if (src1 < T1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + FORCE_RET(); } -void OPPROTO op_sub_T1_T0 (void) +void OPPROTO op_and_T1_T0(void) { - T0 -= T1; + T0 &= T1; } -void OPPROTO op_andn_T1_T0 (void) +void OPPROTO op_or_T1_T0(void) { - T0 &= ~T1; + T0 |= T1; } -void OPPROTO op_orn_T1_T0 (void) +void OPPROTO op_xor_T1_T0(void) { - T0 |= ~T1; + T0 ^= T1; } -void OPPROTO op_xnor_T1_T0 (void) +void OPPROTO op_andn_T1_T0(void) { - T0 ^= ~T1; + T0 &= ~T1; } -void OPPROTO op_addx_T1_T0 (void) +void OPPROTO op_orn_T1_T0(void) { - T0 += T1+((env->psr & PSR_CARRY)?1:0); + T0 |= ~T1; } -void OPPROTO op_umul_T1_T0 (void) +void OPPROTO op_xnor_T1_T0(void) { - unsigned long long res = T0*T1; - T0 = res & 0xffffffff; - env->y = res >> 32; + T0 ^= ~T1; } -void OPPROTO op_smul_T1_T0 (void) +void OPPROTO op_addx_T1_T0(void) { - long long res = T0*T1; - T0 = res & 0xffffffff; - env->y = res >> 32; + T0 += T1 + ((env->psr & PSR_CARRY) ? 1 : 0); } -void OPPROTO op_udiv_T1_T0 (void) +void OPPROTO op_umul_T1_T0(void) { - unsigned long long x0 = T0 * env->y; - unsigned int x1 = T1; - T0 = x0 / x1; + uint64_t res; + res = (uint64_t) T0 *(uint64_t) T1; + T0 = res & 0xffffffff; + env->y = res >> 32; } -void OPPROTO op_sdiv_T1_T0 (void) +void OPPROTO op_smul_T1_T0(void) { - long long x0 = T0 * env->y; - int x1 = T1; - T0 = x0 / x1; + uint64_t res; + res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1); + T0 = res & 0xffffffff; + env->y = res >> 32; } -void OPPROTO op_subx_T1_T0 (void) +void OPPROTO op_mulscc_T1_T0(void) { - T0 -= T1+((env->psr & PSR_CARRY)?1:0); + unsigned int b1, C, V, b2, src1; + C = FLAG_SET(PSR_CARRY); + V = FLAG_SET(PSR_OVF); + b1 = C ^ V; + b2 = T0 & 1; + T0 = (b1 << 31) | (T0 >> 1); + if (!(env->y & 1)) + T1 = 0; + /* do addition and update flags */ + src1 = T0; + T0 += T1; + env->psr = 0; + if (!T0) + env->psr |= PSR_ZERO; + if ((int) T0 < 0) + env->psr |= PSR_NEG; + if (T0 < src1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + env->y = (b2 << 31) | (env->y >> 1); + FORCE_RET(); +} + +void OPPROTO op_udiv_T1_T0(void) +{ + uint64_t x0; + uint32_t x1; + + x0 = T0 | ((uint64_t) (env->y) << 32); + x1 = T1; + x0 = x0 / x1; + if (x0 > 0xffffffff) { + T0 = 0xffffffff; + T1 = 1; + } else { + T0 = x0; + T1 = 0; + } + FORCE_RET(); } -void OPPROTO op_set_flags (void) +void OPPROTO op_sdiv_T1_T0(void) { - env->psr = 0; - if (!T0) env->psr |= PSR_ZERO; - if ((unsigned int) T0 < (unsigned int) T1) env->psr |= PSR_CARRY; - if ((int) T0 < (int) T1) env->psr |= PSR_OVF; - if ((int) T0 < 0) env->psr |= PSR_NEG; + int64_t x0; + int32_t x1; + + x0 = T0 | ((uint64_t) (env->y) << 32); + x1 = T1; + x0 = x0 / x1; + if ((int32_t) x0 != x0) { + T0 = x0 >> 63; + T1 = 1; + } else { + T0 = x0; + T1 = 0; + } + FORCE_RET(); } -void OPPROTO op_sll (void) +void OPPROTO op_div_cc(void) { - T0 <<= T1; + env->psr = 0; + if (!T0) + env->psr |= PSR_ZERO; + if ((int) T0 < 0) + env->psr |= PSR_NEG; + if (T1) + env->psr |= PSR_OVF; + FORCE_RET(); } -void OPPROTO op_srl (void) +void OPPROTO op_subx_T1_T0(void) { - T0 >>= T1; + T0 -= T1 + ((env->psr & PSR_CARRY) ? 1 : 0); } -void OPPROTO op_sra (void) +void OPPROTO op_logic_T0_cc(void) { - int x = T0 >> T1; - T0 = x; + env->psr = 0; + if (!T0) + env->psr |= PSR_ZERO; + if ((int) T0 < 0) + env->psr |= PSR_NEG; + FORCE_RET(); } -void OPPROTO op_st (void) +void OPPROTO op_set_flags(void) { - stl ((void *) T0, T1); + env->psr = 0; + if (!T0) + env->psr |= PSR_ZERO; + if ((unsigned int) T0 < (unsigned int) T1) + env->psr |= PSR_CARRY; + if ((int) T0 < (int) T1) + env->psr |= PSR_OVF; + if ((int) T0 < 0) + env->psr |= PSR_NEG; + FORCE_RET(); } -void OPPROTO op_stb (void) +void OPPROTO op_sll(void) { - stb ((void *) T0, T1); + T0 <<= T1; } -void OPPROTO op_sth (void) +void OPPROTO op_srl(void) { - stw ((void *) T0, T1); + T0 >>= T1; } -void OPPROTO op_ld (void) +void OPPROTO op_sra(void) { - T1 = ldl ((void *) T0); + T0 = ((int32_t) T0) >> T1; } -void OPPROTO op_ldub (void) +void OPPROTO op_st(void) { - T1 = ldub ((void *) T0); + stl((void *) T0, T1); } -void OPPROTO op_lduh (void) +void OPPROTO op_stb(void) { - T1 = lduw ((void *) T0); + stb((void *) T0, T1); } -void OPPROTO op_ldsb (void) +void OPPROTO op_sth(void) { - T1 = ldsb ((void *) T0); + stw((void *) T0, T1); } -void OPPROTO op_ldsh (void) +void OPPROTO op_std(void) { - T1 = ldsw ((void *) T0); + stl((void *) T0, T1); + stl((void *) (T0 + 4), T2); } -void OPPROTO op_ldstub (void) +void OPPROTO op_ld(void) { - T1 = ldub ((void *) T0); - stb ((void *) T0, 0xff); /* XXX: Should be Atomically */ + T1 = ldl((void *) T0); } -void OPPROTO op_swap (void) +void OPPROTO op_ldub(void) { - unsigned int tmp = ldl ((void *) T0); - stl ((void *) T0, T1); /* XXX: Should be Atomically */ - T1 = tmp; + T1 = ldub((void *) T0); } -void OPPROTO op_ldd (void) +void OPPROTO op_lduh(void) { - T1 = ldl ((void *) T0); - T0 = ldl ((void *) T0+4); + T1 = lduw((void *) T0); } -void OPPROTO op_wry (void) +void OPPROTO op_ldsb(void) { - env->y = T0^T1; + T1 = ldsb((void *) T0); } -void OPPROTO op_rdy (void) +void OPPROTO op_ldsh(void) { - T0 = env->y; + T1 = ldsw((void *) T0); } -#define regwptr (env->regwptr) +void OPPROTO op_ldstub(void) +{ + T1 = ldub((void *) T0); + stb((void *) T0, 0xff); /* XXX: Should be Atomically */ +} -void OPPROTO op_save (void) +void OPPROTO op_swap(void) { - regwptr -= 16; + unsigned int tmp = ldl((void *) T0); + stl((void *) T0, T1); /* XXX: Should be Atomically */ + T1 = tmp; } -void OPPROTO op_restore (void) +void OPPROTO op_ldd(void) { - regwptr += 16; + T1 = ldl((void *) T0); + T0 = ldl((void *) (T0 + 4)); } -void OPPROTO op_trap (void) +void OPPROTO op_wry(void) { - env->exception_index = PARAM1; - cpu_loop_exit (); + env->y = T0; } -void OPPROTO op_exit_tb (void) +void OPPROTO op_rdy(void) { - EXIT_TB (); + T0 = env->y; } -void OPPROTO op_eval_be (void) +void raise_exception(int tt) +{ + env->exception_index = tt; + cpu_loop_exit(); +} + +void memcpy32(uint32_t *dst, const uint32_t *src) { - T0 = (env->psr & PSR_ZERO); + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; } -#define FLAG_SET(x) (env->psr&x)?1:0 -#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY) +static inline void set_cwp(int new_cwp) +{ + /* put the modified wrap registers at their proper location */ + if (env->cwp == (NWINDOWS - 1)) + memcpy32(env->regbase, env->regbase + NWINDOWS * 16); + env->cwp = new_cwp; + /* put the wrap registers at their temporary location */ + if (new_cwp == (NWINDOWS - 1)) + memcpy32(env->regbase + NWINDOWS * 16, env->regbase); + env->regwptr = env->regbase + (new_cwp * 16); +} -void OPPROTO op_eval_ble (void) +/* XXX: use another pointer for %iN registers to avoid slow wrapping + handling ? */ +void OPPROTO op_save(void) { - GET_FLAGS; - T0 = Z | (N^V); + int cwp; + cwp = (env->cwp - 1) & (NWINDOWS - 1); + if (env->wim & (1 << cwp)) { + raise_exception(TT_WIN_OVF); + } + set_cwp(cwp); + FORCE_RET(); } -void OPPROTO op_eval_bl (void) +void OPPROTO op_restore(void) { - GET_FLAGS; - T0 = N^V; + int cwp; + cwp = (env->cwp + 1) & (NWINDOWS - 1); + if (env->wim & (1 << cwp)) { + raise_exception(TT_WIN_UNF); + } + set_cwp(cwp); + FORCE_RET(); } -void OPPROTO op_eval_bleu (void) +void OPPROTO op_exception(void) { - GET_FLAGS; - T0 = C|Z; + env->exception_index = PARAM1; + cpu_loop_exit(); } -void OPPROTO op_eval_bcs (void) +void OPPROTO op_trap_T0(void) { - T0 = (env->psr & PSR_CARRY); + env->exception_index = TT_TRAP + (T0 & 0x7f); + cpu_loop_exit(); } -void OPPROTO op_eval_bvs (void) +void OPPROTO op_trapcc_T0(void) { - T0 = (env->psr & PSR_OVF); + if (T2) { + env->exception_index = TT_TRAP + (T0 & 0x7f); + cpu_loop_exit(); + } + FORCE_RET(); } -void OPPROTO op_eval_bneg (void) +void OPPROTO op_exit_tb(void) { - T0 = (env->psr & PSR_NEG); + EXIT_TB(); } -void OPPROTO op_eval_bne (void) +void OPPROTO op_eval_be(void) { - T0 = !(env->psr & PSR_ZERO); + T2 = (env->psr & PSR_ZERO); } -void OPPROTO op_eval_bg (void) +void OPPROTO op_eval_ble(void) { - GET_FLAGS; - T0 = !(Z | (N^V)); + GET_FLAGS; + T2 = Z | (N ^ V); } -/*XXX: This seems to be documented wrong in the SPARC V8 Manual - The manual states: !(N^V) - but I assume Z | !(N^V) to be correct */ -void OPPROTO op_eval_bge (void) +void OPPROTO op_eval_bl(void) { - GET_FLAGS; - T0 = Z | !(N^V); + GET_FLAGS; + T2 = N ^ V; } -void OPPROTO op_eval_bgu (void) +void OPPROTO op_eval_bleu(void) { - GET_FLAGS; - T0 = !(C | Z); + GET_FLAGS; + T2 = C | Z; } -void OPPROTO op_eval_bcc (void) +void OPPROTO op_eval_bcs(void) { - T0 = !(env->psr & PSR_CARRY); + T2 = (env->psr & PSR_CARRY); } -void OPPROTO op_eval_bpos (void) +void OPPROTO op_eval_bvs(void) { - T0 = !(env->psr & PSR_NEG); + T2 = (env->psr & PSR_OVF); } -void OPPROTO op_eval_bvc (void) +void OPPROTO op_eval_bneg(void) { - T0 = !(env->psr & PSR_OVF); + T2 = (env->psr & PSR_NEG); } -void OPPROTO op_jmp_im (void) +void OPPROTO op_eval_bne(void) { - env->pc = PARAM1; + T2 = !(env->psr & PSR_ZERO); } -void OPPROTO op_call (void) +void OPPROTO op_eval_bg(void) { - regwptr[7] = PARAM1-4; - env->pc = PARAM1+PARAM2; + GET_FLAGS; + T2 = !(Z | (N ^ V)); } -void OPPROTO op_jmpl (void) +void OPPROTO op_eval_bge(void) { - env->npc = T0; + GET_FLAGS; + T2 = !(N ^ V); } -void OPPROTO op_generic_jmp_1 (void) +void OPPROTO op_eval_bgu(void) { - T1 = PARAM1; - env->pc = PARAM1+PARAM2; + GET_FLAGS; + T2 = !(C | Z); } -void OPPROTO op_generic_jmp_2 (void) +void OPPROTO op_eval_bcc(void) { - T1 = PARAM1; - env->pc = env->npc; + T2 = !(env->psr & PSR_CARRY); } -unsigned long old_T0; +void OPPROTO op_eval_bpos(void) +{ + T2 = !(env->psr & PSR_NEG); +} + +void OPPROTO op_eval_bvc(void) +{ + T2 = !(env->psr & PSR_OVF); +} + +void OPPROTO op_movl_T2_0(void) +{ + T2 = 0; +} + +void OPPROTO op_movl_T2_1(void) +{ + T2 = 1; +} + +void OPPROTO op_jmp_im(void) +{ + env->pc = PARAM1; +} + +void OPPROTO op_movl_npc_im(void) +{ + env->npc = PARAM1; +} -void OPPROTO op_save_T0 (void) +void OPPROTO op_movl_npc_T0(void) { - old_T0 = T0; + env->npc = T0; } -void OPPROTO op_restore_T0 (void) +void OPPROTO op_next_insn(void) { - T0 = old_T0; + env->pc = env->npc; + env->npc = env->npc + 4; } -void OPPROTO op_generic_branch (void) +void OPPROTO op_generic_branch(void) { - if (T0) - JUMP_TB (op_generic_branch, PARAM1, 0, PARAM2); - else - JUMP_TB (op_generic_branch, PARAM1, 1, PARAM3); - FORCE_RET (); + if (T2) { + env->npc = PARAM1; + } else { + env->npc = PARAM2; + } + FORCE_RET(); } -void OPPROTO op_generic_branch_a (void) +void OPPROTO op_generic_branch_a(void) { - if (T0) - env->npc = PARAM3; - else - JUMP_TB (op_generic_branch_a, PARAM1, 0, PARAM2); - FORCE_RET (); + if (T2) { + env->pc = PARAM2; + env->npc = PARAM1; + } else { + env->pc = PARAM2 + 4; + env->npc = PARAM2 + 8; + } + FORCE_RET(); } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d302c3dec..a5c1dbe6f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -34,18 +34,13 @@ and the 'anull' bit in the branch instruction opcode is set. This is currently solved by doing a jump after the delay slot instruction. - There is also one big (currently unsolved) bug in the branch code: - If a delay slot modifies the condition codes then the new condition - codes, instead of the old ones will be used. - TODO-list: + Register window overflow/underflow check FPU-Instructions Coprocessor-Instructions - Fix above bug Check signedness issues Privileged instructions - Register window overflow/underflow check Optimize synthetic instructions Optional alignment and privileged instruction check @@ -65,14 +60,10 @@ #define DEBUG_DISAS typedef struct DisasContext { - uint8_t *pc; - uint8_t *npc; - void (*branch) (struct DisasContext *, uint32_t, uint32_t); - unsigned int delay_slot:2; - uint32_t insn; - uint32_t target; - int is_br; - struct TranslationBlock *tb; + uint8_t *pc; /* NULL means dynamic value */ + uint8_t *npc; /* NULL means dynamic value */ + int is_br; + struct TranslationBlock *tb; } DisasContext; static uint16_t *gen_opc_ptr; @@ -84,7 +75,7 @@ enum { #define DEF(s,n,copy_size) INDEX_op_ ## s, #include "opc.h" #undef DEF - NB_OPS + NB_OPS }; #include "gen-op.h" @@ -94,651 +85,781 @@ enum { #define IS_IMM (insn & (1<<13)) -static void disas_sparc_insn (DisasContext *dc); +static void disas_sparc_insn(DisasContext * dc); -typedef void (GenOpFunc)(void); -typedef void (GenOpFunc1)(long); -typedef void (GenOpFunc2)(long, long); -typedef void (GenOpFunc3)(long, long, long); +typedef void (GenOpFunc) (void); +typedef void (GenOpFunc1) (long); +typedef void (GenOpFunc2) (long, long); +typedef void (GenOpFunc3) (long, long, long); static GenOpFunc *gen_op_movl_TN_reg[2][32] = { - { - gen_op_movl_g0_T0, - gen_op_movl_g1_T0, - gen_op_movl_g2_T0, - gen_op_movl_g3_T0, - gen_op_movl_g4_T0, - gen_op_movl_g5_T0, - gen_op_movl_g6_T0, - gen_op_movl_g7_T0, - gen_op_movl_o0_T0, - gen_op_movl_o1_T0, - gen_op_movl_o2_T0, - gen_op_movl_o3_T0, - gen_op_movl_o4_T0, - gen_op_movl_o5_T0, - gen_op_movl_o6_T0, - gen_op_movl_o7_T0, - gen_op_movl_l0_T0, - gen_op_movl_l1_T0, - gen_op_movl_l2_T0, - gen_op_movl_l3_T0, - gen_op_movl_l4_T0, - gen_op_movl_l5_T0, - gen_op_movl_l6_T0, - gen_op_movl_l7_T0, - gen_op_movl_i0_T0, - gen_op_movl_i1_T0, - gen_op_movl_i2_T0, - gen_op_movl_i3_T0, - gen_op_movl_i4_T0, - gen_op_movl_i5_T0, - gen_op_movl_i6_T0, - gen_op_movl_i7_T0, - }, - { - gen_op_movl_g0_T1, - gen_op_movl_g1_T1, - gen_op_movl_g2_T1, - gen_op_movl_g3_T1, - gen_op_movl_g4_T1, - gen_op_movl_g5_T1, - gen_op_movl_g6_T1, - gen_op_movl_g7_T1, - gen_op_movl_o0_T1, - gen_op_movl_o1_T1, - gen_op_movl_o2_T1, - gen_op_movl_o3_T1, - gen_op_movl_o4_T1, - gen_op_movl_o5_T1, - gen_op_movl_o6_T1, - gen_op_movl_o7_T1, - gen_op_movl_l0_T1, - gen_op_movl_l1_T1, - gen_op_movl_l2_T1, - gen_op_movl_l3_T1, - gen_op_movl_l4_T1, - gen_op_movl_l5_T1, - gen_op_movl_l6_T1, - gen_op_movl_l7_T1, - gen_op_movl_i0_T1, - gen_op_movl_i1_T1, - gen_op_movl_i2_T1, - gen_op_movl_i3_T1, - gen_op_movl_i4_T1, - gen_op_movl_i5_T1, - gen_op_movl_i6_T1, - gen_op_movl_i7_T1, - } + { + gen_op_movl_g0_T0, + gen_op_movl_g1_T0, + gen_op_movl_g2_T0, + gen_op_movl_g3_T0, + gen_op_movl_g4_T0, + gen_op_movl_g5_T0, + gen_op_movl_g6_T0, + gen_op_movl_g7_T0, + gen_op_movl_o0_T0, + gen_op_movl_o1_T0, + gen_op_movl_o2_T0, + gen_op_movl_o3_T0, + gen_op_movl_o4_T0, + gen_op_movl_o5_T0, + gen_op_movl_o6_T0, + gen_op_movl_o7_T0, + gen_op_movl_l0_T0, + gen_op_movl_l1_T0, + gen_op_movl_l2_T0, + gen_op_movl_l3_T0, + gen_op_movl_l4_T0, + gen_op_movl_l5_T0, + gen_op_movl_l6_T0, + gen_op_movl_l7_T0, + gen_op_movl_i0_T0, + gen_op_movl_i1_T0, + gen_op_movl_i2_T0, + gen_op_movl_i3_T0, + gen_op_movl_i4_T0, + gen_op_movl_i5_T0, + gen_op_movl_i6_T0, + gen_op_movl_i7_T0, + }, + { + gen_op_movl_g0_T1, + gen_op_movl_g1_T1, + gen_op_movl_g2_T1, + gen_op_movl_g3_T1, + gen_op_movl_g4_T1, + gen_op_movl_g5_T1, + gen_op_movl_g6_T1, + gen_op_movl_g7_T1, + gen_op_movl_o0_T1, + gen_op_movl_o1_T1, + gen_op_movl_o2_T1, + gen_op_movl_o3_T1, + gen_op_movl_o4_T1, + gen_op_movl_o5_T1, + gen_op_movl_o6_T1, + gen_op_movl_o7_T1, + gen_op_movl_l0_T1, + gen_op_movl_l1_T1, + gen_op_movl_l2_T1, + gen_op_movl_l3_T1, + gen_op_movl_l4_T1, + gen_op_movl_l5_T1, + gen_op_movl_l6_T1, + gen_op_movl_l7_T1, + gen_op_movl_i0_T1, + gen_op_movl_i1_T1, + gen_op_movl_i2_T1, + gen_op_movl_i3_T1, + gen_op_movl_i4_T1, + gen_op_movl_i5_T1, + gen_op_movl_i6_T1, + gen_op_movl_i7_T1, + } }; static GenOpFunc *gen_op_movl_reg_TN[3][32] = { - { - gen_op_movl_T0_g0, - gen_op_movl_T0_g1, - gen_op_movl_T0_g2, - gen_op_movl_T0_g3, - gen_op_movl_T0_g4, - gen_op_movl_T0_g5, - gen_op_movl_T0_g6, - gen_op_movl_T0_g7, - gen_op_movl_T0_o0, - gen_op_movl_T0_o1, - gen_op_movl_T0_o2, - gen_op_movl_T0_o3, - gen_op_movl_T0_o4, - gen_op_movl_T0_o5, - gen_op_movl_T0_o6, - gen_op_movl_T0_o7, - gen_op_movl_T0_l0, - gen_op_movl_T0_l1, - gen_op_movl_T0_l2, - gen_op_movl_T0_l3, - gen_op_movl_T0_l4, - gen_op_movl_T0_l5, - gen_op_movl_T0_l6, - gen_op_movl_T0_l7, - gen_op_movl_T0_i0, - gen_op_movl_T0_i1, - gen_op_movl_T0_i2, - gen_op_movl_T0_i3, - gen_op_movl_T0_i4, - gen_op_movl_T0_i5, - gen_op_movl_T0_i6, - gen_op_movl_T0_i7, - }, - { - gen_op_movl_T1_g0, - gen_op_movl_T1_g1, - gen_op_movl_T1_g2, - gen_op_movl_T1_g3, - gen_op_movl_T1_g4, - gen_op_movl_T1_g5, - gen_op_movl_T1_g6, - gen_op_movl_T1_g7, - gen_op_movl_T1_o0, - gen_op_movl_T1_o1, - gen_op_movl_T1_o2, - gen_op_movl_T1_o3, - gen_op_movl_T1_o4, - gen_op_movl_T1_o5, - gen_op_movl_T1_o6, - gen_op_movl_T1_o7, - gen_op_movl_T1_l0, - gen_op_movl_T1_l1, - gen_op_movl_T1_l2, - gen_op_movl_T1_l3, - gen_op_movl_T1_l4, - gen_op_movl_T1_l5, - gen_op_movl_T1_l6, - gen_op_movl_T1_l7, - gen_op_movl_T1_i0, - gen_op_movl_T1_i1, - gen_op_movl_T1_i2, - gen_op_movl_T1_i3, - gen_op_movl_T1_i4, - gen_op_movl_T1_i5, - gen_op_movl_T1_i6, - gen_op_movl_T1_i7, - }, - { - gen_op_movl_T2_g0, - gen_op_movl_T2_g1, - gen_op_movl_T2_g2, - gen_op_movl_T2_g3, - gen_op_movl_T2_g4, - gen_op_movl_T2_g5, - gen_op_movl_T2_g6, - gen_op_movl_T2_g7, - gen_op_movl_T2_o0, - gen_op_movl_T2_o1, - gen_op_movl_T2_o2, - gen_op_movl_T2_o3, - gen_op_movl_T2_o4, - gen_op_movl_T2_o5, - gen_op_movl_T2_o6, - gen_op_movl_T2_o7, - gen_op_movl_T2_l0, - gen_op_movl_T2_l1, - gen_op_movl_T2_l2, - gen_op_movl_T2_l3, - gen_op_movl_T2_l4, - gen_op_movl_T2_l5, - gen_op_movl_T2_l6, - gen_op_movl_T2_l7, - gen_op_movl_T2_i0, - gen_op_movl_T2_i1, - gen_op_movl_T2_i2, - gen_op_movl_T2_i3, - gen_op_movl_T2_i4, - gen_op_movl_T2_i5, - gen_op_movl_T2_i6, - gen_op_movl_T2_i7, - } + { + gen_op_movl_T0_g0, + gen_op_movl_T0_g1, + gen_op_movl_T0_g2, + gen_op_movl_T0_g3, + gen_op_movl_T0_g4, + gen_op_movl_T0_g5, + gen_op_movl_T0_g6, + gen_op_movl_T0_g7, + gen_op_movl_T0_o0, + gen_op_movl_T0_o1, + gen_op_movl_T0_o2, + gen_op_movl_T0_o3, + gen_op_movl_T0_o4, + gen_op_movl_T0_o5, + gen_op_movl_T0_o6, + gen_op_movl_T0_o7, + gen_op_movl_T0_l0, + gen_op_movl_T0_l1, + gen_op_movl_T0_l2, + gen_op_movl_T0_l3, + gen_op_movl_T0_l4, + gen_op_movl_T0_l5, + gen_op_movl_T0_l6, + gen_op_movl_T0_l7, + gen_op_movl_T0_i0, + gen_op_movl_T0_i1, + gen_op_movl_T0_i2, + gen_op_movl_T0_i3, + gen_op_movl_T0_i4, + gen_op_movl_T0_i5, + gen_op_movl_T0_i6, + gen_op_movl_T0_i7, + }, + { + gen_op_movl_T1_g0, + gen_op_movl_T1_g1, + gen_op_movl_T1_g2, + gen_op_movl_T1_g3, + gen_op_movl_T1_g4, + gen_op_movl_T1_g5, + gen_op_movl_T1_g6, + gen_op_movl_T1_g7, + gen_op_movl_T1_o0, + gen_op_movl_T1_o1, + gen_op_movl_T1_o2, + gen_op_movl_T1_o3, + gen_op_movl_T1_o4, + gen_op_movl_T1_o5, + gen_op_movl_T1_o6, + gen_op_movl_T1_o7, + gen_op_movl_T1_l0, + gen_op_movl_T1_l1, + gen_op_movl_T1_l2, + gen_op_movl_T1_l3, + gen_op_movl_T1_l4, + gen_op_movl_T1_l5, + gen_op_movl_T1_l6, + gen_op_movl_T1_l7, + gen_op_movl_T1_i0, + gen_op_movl_T1_i1, + gen_op_movl_T1_i2, + gen_op_movl_T1_i3, + gen_op_movl_T1_i4, + gen_op_movl_T1_i5, + gen_op_movl_T1_i6, + gen_op_movl_T1_i7, + }, + { + gen_op_movl_T2_g0, + gen_op_movl_T2_g1, + gen_op_movl_T2_g2, + gen_op_movl_T2_g3, + gen_op_movl_T2_g4, + gen_op_movl_T2_g5, + gen_op_movl_T2_g6, + gen_op_movl_T2_g7, + gen_op_movl_T2_o0, + gen_op_movl_T2_o1, + gen_op_movl_T2_o2, + gen_op_movl_T2_o3, + gen_op_movl_T2_o4, + gen_op_movl_T2_o5, + gen_op_movl_T2_o6, + gen_op_movl_T2_o7, + gen_op_movl_T2_l0, + gen_op_movl_T2_l1, + gen_op_movl_T2_l2, + gen_op_movl_T2_l3, + gen_op_movl_T2_l4, + gen_op_movl_T2_l5, + gen_op_movl_T2_l6, + gen_op_movl_T2_l7, + gen_op_movl_T2_i0, + gen_op_movl_T2_i1, + gen_op_movl_T2_i2, + gen_op_movl_T2_i3, + gen_op_movl_T2_i4, + gen_op_movl_T2_i5, + gen_op_movl_T2_i6, + gen_op_movl_T2_i7, + } }; static GenOpFunc1 *gen_op_movl_TN_im[3] = { - gen_op_movl_T0_im, - gen_op_movl_T1_im, - gen_op_movl_T2_im + gen_op_movl_T0_im, + gen_op_movl_T1_im, + gen_op_movl_T2_im }; -static inline void gen_movl_imm_TN (int reg, int imm) +static inline void gen_movl_imm_TN(int reg, int imm) { - gen_op_movl_TN_im[reg](imm); + gen_op_movl_TN_im[reg] (imm); } -static inline void gen_movl_imm_T1 (int val) +static inline void gen_movl_imm_T1(int val) { - gen_movl_imm_TN (1, val); + gen_movl_imm_TN(1, val); } -static inline void gen_movl_imm_T0 (int val) +static inline void gen_movl_imm_T0(int val) { - gen_movl_imm_TN (0, val); + gen_movl_imm_TN(0, val); } -static inline void gen_movl_reg_TN (int reg, int t) +static inline void gen_movl_reg_TN(int reg, int t) { - if (reg) gen_op_movl_reg_TN[t][reg](); - else gen_movl_imm_TN (t, 0); + if (reg) + gen_op_movl_reg_TN[t][reg] (); + else + gen_movl_imm_TN(t, 0); } -static inline void gen_movl_reg_T0 (int reg) +static inline void gen_movl_reg_T0(int reg) { - gen_movl_reg_TN (reg, 0); + gen_movl_reg_TN(reg, 0); } -static inline void gen_movl_reg_T1 (int reg) +static inline void gen_movl_reg_T1(int reg) { - gen_movl_reg_TN (reg, 1); + gen_movl_reg_TN(reg, 1); } -static inline void gen_movl_reg_T2 (int reg) +static inline void gen_movl_reg_T2(int reg) { - gen_movl_reg_TN (reg, 2); + gen_movl_reg_TN(reg, 2); } -static inline void gen_movl_TN_reg (int reg, int t) +static inline void gen_movl_TN_reg(int reg, int t) { - if (reg) gen_op_movl_TN_reg[t][reg](); + if (reg) + gen_op_movl_TN_reg[t][reg] (); } -static inline void gen_movl_T0_reg (int reg) +static inline void gen_movl_T0_reg(int reg) { - gen_movl_TN_reg (reg, 0); + gen_movl_TN_reg(reg, 0); } -static inline void gen_movl_T1_reg (int reg) +static inline void gen_movl_T1_reg(int reg) { - gen_movl_TN_reg (reg, 1); + gen_movl_TN_reg(reg, 1); } -static void do_branch (DisasContext *dc, uint32_t target, uint32_t insn) +static void gen_cond(int cond) { - unsigned int cond = GET_FIELD (insn, 3, 6), a = (insn & (1<<29)), ib = 0; - target += (uint32_t) dc->pc-4; - if (!a) disas_sparc_insn (dc); switch (cond) { - case 0x0: gen_op_movl_T0_0 (); break; - case 0x1: gen_op_eval_be (); break; - case 0x2: gen_op_eval_ble (); break; - case 0x3: gen_op_eval_bl (); break; - case 0x4: gen_op_eval_bleu (); break; - case 0x5: gen_op_eval_bcs (); break; - case 0x6: gen_op_eval_bneg (); break; - case 0x7: gen_op_eval_bvs (); break; - case 0x8: gen_op_movl_T0_1 (); break; - case 0x9: gen_op_eval_bne (); break; - case 0xa: gen_op_eval_bg (); break; - case 0xb: gen_op_eval_bge (); break; - case 0xc: gen_op_eval_bgu (); break; - case 0xd: gen_op_eval_bcc (); break; - case 0xe: gen_op_eval_bpos (); break; - case 0xf: gen_op_eval_bvc (); break; - } - if (a && ((cond|0x8) != 0x8)) { - gen_op_generic_branch_a ((uint32_t) dc->tb, - (uint32_t) dc->pc+4, target); - disas_sparc_insn (dc); - ib = 1; + case 0x0: + gen_op_movl_T2_0(); + break; + case 0x1: + gen_op_eval_be(); + break; + case 0x2: + gen_op_eval_ble(); + break; + case 0x3: + gen_op_eval_bl(); + break; + case 0x4: + gen_op_eval_bleu(); + break; + case 0x5: + gen_op_eval_bcs(); + break; + case 0x6: + gen_op_eval_bneg(); + break; + case 0x7: + gen_op_eval_bvs(); + break; + case 0x8: + gen_op_movl_T2_1(); + break; + case 0x9: + gen_op_eval_bne(); + break; + case 0xa: + gen_op_eval_bg(); + break; + case 0xb: + gen_op_eval_bge(); + break; + case 0xc: + gen_op_eval_bgu(); + break; + case 0xd: + gen_op_eval_bcc(); + break; + case 0xe: + gen_op_eval_bpos(); + break; + default: + case 0xf: + gen_op_eval_bvc(); + break; } - else - if (cond && !a) { - gen_op_generic_branch ((uint32_t) dc->tb, (uint32_t) target, - (uint32_t) dc->pc); - ib = 1; - } - if (ib) dc->is_br = DISAS_JUMP; } -/* target == 0x1 means CALL- else JMPL-instruction */ -static void do_jump (DisasContext *dc, uint32_t target, uint32_t rd) + +static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) { - uint32_t orig_pc = (uint32_t) dc->pc-8; - if (target != 0x1) - gen_op_generic_jmp_1 (orig_pc, target); - else - gen_op_generic_jmp_2 (orig_pc); - gen_movl_T1_reg (rd); - dc->is_br = DISAS_JUMP; - gen_op_movl_T0_0 (); + unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); + target += (uint32_t) dc->pc; + if (cond == 0x0) { + /* unconditional not taken */ + if (a) { + dc->pc = dc->npc + 4; + dc->npc = dc->pc + 4; + } else { + dc->pc = dc->npc; + dc->npc = dc->pc + 4; + } + } else if (cond == 0x8) { + /* unconditional taken */ + if (a) { + dc->pc = (uint8_t *) target; + dc->npc = dc->pc + 4; + } else { + dc->pc = dc->npc; + dc->npc = (uint8_t *) target; + } + } else { + gen_cond(cond); + if (a) { + gen_op_generic_branch_a((uint32_t) target, + (uint32_t) (dc->npc)); + dc->is_br = 1; + dc->pc = NULL; + dc->npc = NULL; + } else { + dc->pc = dc->npc; + gen_op_generic_branch((uint32_t) target, + (uint32_t) (dc->npc + 4)); + dc->npc = NULL; + } + } } -#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), b-a) +#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) -static int -sign_extend (x, len) - int x, len; +static int sign_extend(int x, int len) { - int signbit = (1 << (len - 1)); - int mask = (signbit << 1) - 1; - return ((x & mask) ^ signbit) - signbit; + len = 32 - len; + return (x << len) >> len; } -static void disas_sparc_insn (DisasContext *dc) +static inline void save_state(DisasContext * dc) { - unsigned int insn, opc, rs1, rs2, rd; + gen_op_jmp_im((uint32_t)dc->pc); + if (dc->npc != NULL) + gen_op_movl_npc_im((long) dc->npc); +} - if (dc->delay_slot == 1) { - insn = dc->insn; - } else { - if (dc->delay_slot) dc->delay_slot--; - insn = htonl (*(unsigned int *) (dc->pc)); - dc->pc += 4; - } +static void disas_sparc_insn(DisasContext * dc) +{ + unsigned int insn, opc, rs1, rs2, rd; - opc = GET_FIELD (insn, 0, 1); + insn = ldl_code(dc->pc); + opc = GET_FIELD(insn, 0, 1); - rd = GET_FIELD (insn, 2, 6); - switch (opc) { - case 0: /* branches/sethi */ - { - unsigned int xop = GET_FIELD (insn, 7, 9); - int target; - target = GET_FIELD (insn, 10, 31); - switch (xop) { - case 0x0: case 0x1: /* UNIMPL */ - printf ("UNIMPLEMENTED: %p\n", dc->pc-4); - exit (23); - break; - case 0x2: /* BN+x */ - { - target <<= 2; - target = sign_extend (target, 22); - do_branch (dc, target, insn); - break; - } - case 0x3: /* FBN+x */ - break; - case 0x4: /* SETHI */ - gen_movl_imm_T0 (target<<10); - gen_movl_T0_reg (rd); - break; - case 0x5: /*CBN+x*/ - break; - } - break; - } - case 1: /*CALL*/ + rd = GET_FIELD(insn, 2, 6); + switch (opc) { + case 0: /* branches/sethi */ + { + unsigned int xop = GET_FIELD(insn, 7, 9); + int target; + target = GET_FIELD(insn, 10, 31); + switch (xop) { + case 0x0: + case 0x1: /* UNIMPL */ + goto illegal_insn; + case 0x2: /* BN+x */ { - unsigned int target = GET_FIELDs (insn, 2, 31) << 2; - if (dc->delay_slot) { - do_jump (dc, target, 15); - dc->delay_slot = 0; - } else { - dc->insn = insn; - dc->delay_slot = 2; - } - break; + target <<= 2; + target = sign_extend(target, 22); + do_branch(dc, target, insn); + goto jmp_insn; } - case 2: /* FPU & Logical Operations */ - { - unsigned int xop = GET_FIELD (insn, 7, 12); - if (xop == 58) { /* generate trap */ - dc->is_br = DISAS_JUMP; - gen_op_jmp_im ((uint32_t) dc->pc); - if (IS_IMM) gen_op_trap (GET_FIELD (insn, 25, 31)); - /* else XXX*/ - gen_op_movl_T0_0 (); - break; - } - if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ - exit (33); - } - rs1 = GET_FIELD (insn, 13, 17); - gen_movl_reg_T0 (rs1); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELDs (insn, 20, 31); - gen_movl_imm_T1 (rs2); - } else { /* register */ - rs2 = GET_FIELD (insn, 27, 31); - gen_movl_reg_T1 (rs2); - } - if (xop < 0x20) { - switch (xop &~ 0x10) { - case 0x0: - gen_op_add_T1_T0 (); - break; - case 0x1: - gen_op_and_T1_T0 (); - break; - case 0x2: - gen_op_or_T1_T0 (); - break; - case 0x3: - gen_op_xor_T1_T0 (); - break; - case 0x4: - gen_op_sub_T1_T0 (); - break; - case 0x5: - gen_op_andn_T1_T0 (); - break; - case 0x6: - gen_op_orn_T1_T0 (); - break; - case 0x7: - gen_op_xnor_T1_T0 (); - break; - case 0x8: - gen_op_addx_T1_T0 (); - break; - case 0xa: - gen_op_umul_T1_T0 (); - break; - case 0xb: - gen_op_smul_T1_T0 (); - break; - case 0xc: - gen_op_subx_T1_T0 (); - break; - case 0xe: - gen_op_udiv_T1_T0 (); - break; - case 0xf: - gen_op_sdiv_T1_T0 (); - break; - default: - exit (17); - break; - } - gen_movl_T0_reg (rd); - if (xop & 0x10) { - gen_op_set_flags (); - } - } else { - switch (xop) { - case 0x25: /* SLL */ - gen_op_sll (); - break; - case 0x26: - gen_op_srl (); - break; - case 0x27: - gen_op_sra (); - break; - case 0x28: case 0x30: - { - unsigned int rdi = GET_FIELD (insn, 13, 17); - if (!rdi) (xop==0x28?gen_op_rdy ():gen_op_wry()); - /* else gen_op_su_trap (); */ - break; - } - /* Problem with jmpl: if restore is executed in the delay - slot, then the wrong registers are beeing used */ - case 0x38: /* jmpl */ - { - if (dc->delay_slot) { - gen_op_add_T1_T0 (); - do_jump (dc, 1, rd); - dc->delay_slot = 0; - } else { - gen_op_add_T1_T0 (); - gen_op_jmpl (); - dc->insn = insn; - dc->delay_slot = 2; - } - break; - } - case 0x3c: /* save */ - gen_op_add_T1_T0 (); - gen_op_save (); - gen_movl_T0_reg (rd); - break; - case 0x3d: /* restore */ - gen_op_add_T1_T0 (); - gen_op_restore (); - gen_movl_T0_reg (rd); - break; - } - } - break; + case 0x3: /* FBN+x */ + break; + case 0x4: /* SETHI */ + gen_movl_imm_T0(target << 10); + gen_movl_T0_reg(rd); + break; + case 0x5: /*CBN+x */ + break; + } + break; + } + case 1: + /*CALL*/ { + unsigned int target = GET_FIELDs(insn, 2, 31) << 2; + + gen_op_movl_T0_im((long) (dc->pc)); + gen_movl_T0_reg(15); + target = (long) dc->pc + target; + dc->pc = dc->npc; + dc->npc = (uint8_t *) target; + } + goto jmp_insn; + case 2: /* FPU & Logical Operations */ + { + unsigned int xop = GET_FIELD(insn, 7, 12); + if (xop == 0x3a) { /* generate trap */ + int cond; + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { + gen_movl_imm_T1(GET_FIELD(insn, 25, 31)); + } else { + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + gen_op_add_T1_T0(); + save_state(dc); + cond = GET_FIELD(insn, 3, 6); + if (cond == 0x8) { + gen_op_trap_T0(); + dc->is_br = 1; + goto jmp_insn; + } else { + gen_op_trapcc_T0(); + } + } else if (xop == 0x28) { + rs1 = GET_FIELD(insn, 13, 17); + switch(rs1) { + case 0: /* rdy */ + gen_op_rdy(); + gen_movl_T0_reg(rd); + break; + default: + goto illegal_insn; + } + } else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ + goto illegal_insn; + } else { + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); + gen_movl_imm_T1(rs2); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + if (xop < 0x20) { + switch (xop & ~0x10) { + case 0x0: + if (xop & 0x10) + gen_op_add_T1_T0_cc(); + else + gen_op_add_T1_T0(); + break; + case 0x1: + gen_op_and_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; + case 0x2: + gen_op_or_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; + case 0x3: + gen_op_xor_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; + case 0x4: + if (xop & 0x10) + gen_op_sub_T1_T0_cc(); + else + gen_op_sub_T1_T0(); + break; + case 0x5: + gen_op_andn_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; + case 0x6: + gen_op_orn_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; + case 0x7: + gen_op_xnor_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; + case 0x8: + gen_op_addx_T1_T0(); + if (xop & 0x10) + gen_op_set_flags(); + break; + case 0xa: + gen_op_umul_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; + case 0xb: + gen_op_smul_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; + case 0xc: + gen_op_subx_T1_T0(); + if (xop & 0x10) + gen_op_set_flags(); + break; + case 0xe: + gen_op_udiv_T1_T0(); + if (xop & 0x10) + gen_op_div_cc(); + break; + case 0xf: + gen_op_sdiv_T1_T0(); + if (xop & 0x10) + gen_op_div_cc(); + break; + default: + goto illegal_insn; + } + gen_movl_T0_reg(rd); + } else { + switch (xop) { + case 0x24: /* mulscc */ + gen_op_mulscc_T1_T0(); + gen_movl_T0_reg(rd); + break; + case 0x25: /* SLL */ + gen_op_sll(); + gen_movl_T0_reg(rd); + break; + case 0x26: + gen_op_srl(); + gen_movl_T0_reg(rd); + break; + case 0x27: + gen_op_sra(); + gen_movl_T0_reg(rd); + break; + case 0x30: + { + gen_op_xor_T1_T0(); + switch(rd) { + case 0: + gen_op_wry(); + break; + default: + goto illegal_insn; + } + } + break; + case 0x38: /* jmpl */ + { + gen_op_add_T1_T0(); + gen_op_movl_npc_T0(); + if (rd != 0) { + gen_op_movl_T0_im((long) (dc->pc)); + gen_movl_T0_reg(rd); + } + dc->pc = dc->npc; + dc->npc = NULL; + } + goto jmp_insn; + case 0x3b: /* flush */ + /* nothing to do */ + break; + case 0x3c: /* save */ + save_state(dc); + gen_op_add_T1_T0(); + gen_op_save(); + gen_movl_T0_reg(rd); + break; + case 0x3d: /* restore */ + save_state(dc); + gen_op_add_T1_T0(); + gen_op_restore(); + gen_movl_T0_reg(rd); + break; + default: + goto illegal_insn; + } + } + } + break; + } + case 3: /* load/store instructions */ + { + unsigned int xop = GET_FIELD(insn, 7, 12); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); + gen_movl_imm_T1(rs2); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + gen_op_add_T1_T0(); + if (xop < 4 || xop > 7) { + switch (xop) { + case 0x0: /* load word */ + gen_op_ld(); + break; + case 0x1: /* load unsigned byte */ + gen_op_ldub(); + break; + case 0x2: /* load unsigned halfword */ + gen_op_lduh(); + break; + case 0x3: /* load double word */ + gen_op_ldd(); + gen_movl_T0_reg(rd + 1); + break; + case 0x9: /* load signed byte */ + gen_op_ldsb(); + break; + case 0xa: /* load signed halfword */ + gen_op_ldsh(); + break; + case 0xd: /* ldstub -- XXX: should be atomically */ + gen_op_ldstub(); + break; + case 0x0f: /* swap register with memory. Also atomically */ + gen_op_swap(); + break; } - case 3: /* load/store instructions */ - { - unsigned int xop = GET_FIELD (insn, 7, 12); - rs1 = GET_FIELD (insn, 13, 17); - gen_movl_reg_T0 (rs1); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELDs (insn, 20, 31); - gen_movl_imm_T1 (rs2); - } else { /* register */ - rs2 = GET_FIELD (insn, 27, 31); - gen_movl_reg_T1 (rs2); - } - gen_op_add_T1_T0 (); - if (xop < 4 || xop > 7) { - switch (xop) { - case 0x0: /* load word */ - gen_op_ld (); - break; - case 0x1: /* load unsigned byte */ - gen_op_ldub (); - break; - case 0x2: /* load unsigned halfword */ - gen_op_lduh (); - break; - case 0x3: /* load double word */ - gen_op_ldd (); - gen_movl_T0_reg (rd+1); - break; - case 0x9: /* load signed byte */ - gen_op_ldsb (); - break; - case 0xa: /* load signed halfword */ - gen_op_ldsh (); - break; - case 0xd: /* ldstub -- XXX: should be atomically */ - gen_op_ldstub (); - break; - case 0x0f: /* swap register with memory. Also atomically */ - gen_op_swap (); - break; - } - gen_movl_T1_reg (rd); - } else if (xop < 8) { - gen_movl_reg_T1 (rd); - switch (xop) { - case 0x4: - gen_op_st (); - break; - case 0x5: - gen_op_stb (); - break; - case 0x6: - gen_op_sth (); - break; - case 0x7: - gen_op_st (); - gen_movl_reg_T1 (rd+1); - gen_op_st (); - break; - } - } + gen_movl_T1_reg(rd); + } else if (xop < 8) { + gen_movl_reg_T1(rd); + switch (xop) { + case 0x4: + gen_op_st(); + break; + case 0x5: + gen_op_stb(); + break; + case 0x6: + gen_op_sth(); + break; + case 0x7: + gen_movl_reg_T2(rd + 1); + gen_op_std(); + break; } + } } + } + /* default case for non jump instructions */ + if (dc->npc != NULL) { + dc->pc = dc->npc; + dc->npc = dc->npc + 4; + } else { + dc->pc = NULL; + gen_op_next_insn(); + } + jmp_insn:; + return; + illegal_insn: + gen_op_jmp_im((uint32_t)dc->pc); + if (dc->npc != NULL) + gen_op_movl_npc_im((long) dc->npc); + gen_op_exception(TT_ILL_INSN); + dc->is_br = 1; } -static inline int gen_intermediate_code_internal (TranslationBlock *tb, int spc) +static inline int gen_intermediate_code_internal(TranslationBlock * tb, + int spc) { - uint8_t *pc_start = (uint8_t *) tb->pc; - uint16_t *gen_opc_end; - DisasContext dc; - - memset (&dc, 0, sizeof (dc)); - if (spc) { - printf ("SearchPC not yet supported\n"); - exit (0); - } - dc.tb = tb; - dc.pc = pc_start; - - gen_opc_ptr = gen_opc_buf; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - gen_opparam_ptr = gen_opparam_buf; - - do { - disas_sparc_insn (&dc); - } while (!dc.is_br && (gen_opc_ptr < gen_opc_end) && - (dc.pc - pc_start) < (TARGET_PAGE_SIZE - 32)); - - switch (dc.is_br) { - case DISAS_JUMP: - case DISAS_TB_JUMP: - gen_op_exit_tb (); - break; - } - - *gen_opc_ptr = INDEX_op_end; + uint8_t *pc_start, *last_pc; + uint16_t *gen_opc_end; + DisasContext dc1, *dc = &dc1; + + memset(dc, 0, sizeof(DisasContext)); + if (spc) { + printf("SearchPC not yet supported\n"); + exit(0); + } + dc->tb = tb; + pc_start = (uint8_t *) tb->pc; + dc->pc = pc_start; + dc->npc = (uint8_t *) tb->cs_base; + + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + + do { + last_pc = dc->pc; + disas_sparc_insn(dc); + if (dc->is_br) + break; + /* if the next PC is different, we abort now */ + if (dc->pc != (last_pc + 4)) + break; + } while ((gen_opc_ptr < gen_opc_end) && + (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + if (dc->pc != NULL) + gen_op_jmp_im((long) dc->pc); + if (dc->npc != NULL) + gen_op_movl_npc_im((long) dc->npc); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + + *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS - if (loglevel) { - fprintf (logfile, "--------------\n"); - fprintf (logfile, "IN: %s\n", lookup_symbol (pc_start)); - disas(logfile, pc_start, dc.pc - pc_start, 0, 0); - fprintf(logfile, "\n"); - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); - } + if (loglevel) { + fprintf(logfile, "--------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0); + fprintf(logfile, "\n"); + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } #endif - return 0; + return 0; } -int gen_intermediate_code (CPUSPARCState *env, TranslationBlock *tb) +int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) { - return gen_intermediate_code_internal(tb, 0); + return gen_intermediate_code_internal(tb, 0); } -int gen_intermediate_code_pc (CPUSPARCState *env, TranslationBlock *tb) +int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) { - return gen_intermediate_code_internal(tb, 1); + return gen_intermediate_code_internal(tb, 1); } -void *mycpu; - -CPUSPARCState *cpu_sparc_init (void) +CPUSPARCState *cpu_sparc_init(void) { - CPUSPARCState *env; - - cpu_exec_init (); - - if (!(env = malloc (sizeof(CPUSPARCState)))) - return (NULL); - memset (env, 0, sizeof (*env)); - if (!(env->regwptr = malloc (0x2000))) - return (NULL); - memset (env->regwptr, 0, 0x2000); - env->regwptr += 127; - env->user_mode_only = 1; - mycpu = env; - return (env); + CPUSPARCState *env; + + cpu_exec_init(); + + if (!(env = malloc(sizeof(CPUSPARCState)))) + return (NULL); + memset(env, 0, sizeof(*env)); + env->cwp = 0; + env->wim = 1; + env->regwptr = env->regbase + (env->cwp * 16); + env->user_mode_only = 1; + return (env); } #define GET_FLAG(a,b) ((env->psr & a)?b:'-') -void cpu_sparc_dump_state (CPUSPARCState *env, FILE *f, int flags) +void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags) { - int i, x; - - fprintf (f, "@PC: %p\n", (void *) env->pc); - fprintf (f, "General Registers:\n"); - for (i=0;i<4;i++) - fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]); - fprintf (f, "\n"); - for (;i<8;i++) - fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]); - fprintf (f, "\nCurrent Register Window:\n"); - for (x=0;x<3;x++) { - for (i=0;i<4;i++) - fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':(x==1?'l':'i')), i, env->regwptr[i+x*8]); - fprintf (f, "\n"); - for (;i<8;i++) - fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':x==1?'l':'i'), i, env->regwptr[i+x*8]); - fprintf (f, "\n"); - } - fprintf (f, "PSR: %x -> %c%c%c%c\n", env->psr, - GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), - GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C')); + int i, x; + + fprintf(f, "pc: 0x%08x npc: 0x%08x\n", (int) env->pc, (int) env->npc); + fprintf(f, "General Registers:\n"); + for (i = 0; i < 4; i++) + fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]); + fprintf(f, "\n"); + for (; i < 8; i++) + fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]); + fprintf(f, "\nCurrent Register Window:\n"); + for (x = 0; x < 3; x++) { + for (i = 0; i < 4; i++) + fprintf(f, "%%%c%d: 0x%08x\t", + (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, + env->regwptr[i + x * 8]); + fprintf(f, "\n"); + for (; i < 8; i++) + fprintf(f, "%%%c%d: 0x%08x\t", + (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, + env->regwptr[i + x * 8]); + fprintf(f, "\n"); + } + fprintf(f, "psr: 0x%08x -> %c%c%c%c wim: 0x%08x\n", env->psr | env->cwp, + GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), + GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), + env->wim); } -- cgit v1.2.3 From 8e682019e37c8f8939244fcf44a592fa6347d127 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:18:37 +0000 Subject: correct zero segment values when coming from VM86 mode - cache infos in CPUID - simpler exception handling in load_seg() - validate segments after lret/iret git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@485 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 2 +- target-i386/helper.c | 160 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 107 insertions(+), 55 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index f6c717eed..c3d24d55d 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -122,7 +122,7 @@ typedef struct CCTable { extern CCTable cc_table[]; -void load_seg(int seg_reg, int selector, unsigned cur_eip); +void load_seg(int seg_reg, int selector); void helper_ljmp_protected_T0_T1(void); void helper_lcall_real_T0_T1(int shift, int next_eip); void helper_lcall_protected_T0_T1(int shift, int next_eip); diff --git a/target-i386/helper.c b/target-i386/helper.c index a743cfb5a..c660980ca 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -676,6 +676,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, ssp = get_seg_base(ss_e1, ss_e2); } else if ((e2 & DESC_C_MASK) || dpl == cpl) { /* to same priviledge */ + if (env->eflags & VM_MASK) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; sp_mask = get_sp_mask(env->segs[R_SS].flags); ssp = env->segs[R_SS].base; @@ -702,13 +704,13 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, else old_eip = env->eip; if (shift == 1) { - if (env->eflags & VM_MASK) { - PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); - PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); - PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); - PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); - } if (new_stack) { + if (env->eflags & VM_MASK) { + PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); + PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); + } PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); PUSHL(ssp, esp, sp_mask, ESP); } @@ -720,6 +722,12 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, } } else { if (new_stack) { + if (env->eflags & VM_MASK) { + PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector); + PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector); + PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector); + PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector); + } PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); PUSHW(ssp, esp, sp_mask, ESP); } @@ -732,6 +740,18 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, } if (new_stack) { + if (env->eflags & VM_MASK) { + /* XXX: explain me why W2K hangs if the whole segment cache is + reset ? */ + env->segs[R_ES].selector = 0; + env->segs[R_ES].flags = 0; + env->segs[R_DS].selector = 0; + env->segs[R_DS].flags = 0; + env->segs[R_FS].selector = 0; + env->segs[R_FS].flags = 0; + env->segs[R_GS].selector = 0; + env->segs[R_GS].flags = 0; + } ss = (ss & ~3) | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); @@ -824,22 +844,37 @@ void do_interrupt_user(int intno, int is_int, int error_code, void do_interrupt(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw) { +#if 0 + { + extern FILE *stdout; + static int count; + if (env->cr[0] & CR0_PE_MASK) { + fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", + count, intno, error_code, is_int); + count++; + } + } + if ((env->cr[0] & CR0_PE_MASK) && intno == 0x10) { + tb_flush(env); + cpu_set_log(CPU_LOG_ALL); + } +#endif #ifdef DEBUG_PCALL if (loglevel) { static int count; fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", count, intno, error_code, is_int); cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); -#if 0 +#if 1 { int i; uint8_t *ptr; - printf(" code="); + fprintf(logfile, " code="); ptr = env->segs[R_CS].base + env->eip; for(i = 0; i < 16; i++) { - printf(" %02x", ldub(ptr + i)); + fprintf(logfile, " %02x", ldub(ptr + i)); } - printf("\n"); + fprintf(logfile, "\n"); } #endif count++; @@ -955,7 +990,6 @@ void helper_cmpxchg8b(void) CC_SRC = eflags; } -/* We simulate a pre-MMX pentium as in valgrind */ #define CPUID_FP87 (1 << 0) #define CPUID_VME (1 << 1) #define CPUID_DE (1 << 2) @@ -979,31 +1013,43 @@ void helper_cmpxchg8b(void) void helper_cpuid(void) { - if (EAX == 0) { - EAX = 1; /* max EAX index supported */ + switch(EAX) { + case 0: + EAX = 2; /* max EAX index supported */ EBX = 0x756e6547; ECX = 0x6c65746e; EDX = 0x49656e69; - } else if (EAX == 1) { - int family, model, stepping; - /* EAX = 1 info */ + break; + case 1: + { + int family, model, stepping; + /* EAX = 1 info */ #if 0 - /* pentium 75-200 */ - family = 5; - model = 2; - stepping = 11; + /* pentium 75-200 */ + family = 5; + model = 2; + stepping = 11; #else - /* pentium pro */ - family = 6; - model = 1; - stepping = 3; + /* pentium pro */ + family = 6; + model = 1; + stepping = 3; #endif - EAX = (family << 8) | (model << 4) | stepping; + EAX = (family << 8) | (model << 4) | stepping; + EBX = 0; + ECX = 0; + EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | + CPUID_TSC | CPUID_MSR | CPUID_MCE | + CPUID_CX8 | CPUID_PGE | CPUID_CMOV; + } + break; + default: + /* cache info: needed for Pentium Pro compatibility */ + EAX = 0x410601; EBX = 0; ECX = 0; - EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | - CPUID_TSC | CPUID_MSR | CPUID_MCE | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV; + EDX = 0; + break; } } @@ -1070,14 +1116,14 @@ void helper_ltr_T0(void) if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); load_seg_cache_raw_dt(&env->tr, e1, e2); - e2 |= 0x00000200; /* set the busy bit */ + e2 |= DESC_TSS_BUSY_MASK; stl_kernel(ptr + 4, e2); } env->tr.selector = selector; } /* only works if protected mode and not VM86. seg_reg must be != R_CS */ -void load_seg(int seg_reg, int selector, unsigned int cur_eip) +void load_seg(int seg_reg, int selector) { uint32_t e1, e2; int cpl, dpl, rpl; @@ -1085,14 +1131,12 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) int index; uint8_t *ptr; + selector &= 0xffff; if ((selector & 0xfffc) == 0) { /* null selector case */ - if (seg_reg == R_SS) { - EIP = cur_eip; + if (seg_reg == R_SS) raise_exception_err(EXCP0D_GPF, 0); - } else { - cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); - } + cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); } else { if (selector & 0x4) @@ -1100,49 +1144,36 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) else dt = &env->gdt; index = selector & ~7; - if ((index + 7) > dt->limit) { - EIP = cur_eip; + if ((index + 7) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } ptr = dt->base + index; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); - if (!(e2 & DESC_S_MASK)) { - EIP = cur_eip; + if (!(e2 & DESC_S_MASK)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; if (seg_reg == R_SS) { /* must be writable segment */ - if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { - EIP = cur_eip; + if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } - if (rpl != cpl || dpl != cpl) { - EIP = cur_eip; + if (rpl != cpl || dpl != cpl) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } } else { /* must be readable segment */ - if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { - EIP = cur_eip; + if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { /* if not conforming code, test rights */ - if (dpl < cpl || dpl < rpl) { - EIP = cur_eip; + if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - } } } if (!(e2 & DESC_P_MASK)) { - EIP = cur_eip; if (seg_reg == R_SS) raise_exception_err(EXCP0C_STACK, selector & 0xfffc); else @@ -1507,6 +1538,21 @@ void helper_iret_real(int shift) load_eflags(new_eflags, eflags_mask); } +static inline void validate_seg(int seg_reg, int cpl) +{ + int dpl; + uint32_t e2; + + e2 = env->segs[seg_reg].flags; + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { + /* data or non conforming code segment */ + if (dpl < cpl) { + cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0); + } + } +} + /* protected mode iret */ static inline void helper_ret_protected(int shift, int is_iret, int addend) { @@ -1610,6 +1656,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) cpu_x86_set_cpl(env, rpl); sp = new_esp; /* XXX: change sp_mask according to old segment ? */ + + /* validate data segments */ + validate_seg(R_ES, cpl); + validate_seg(R_DS, cpl); + validate_seg(R_FS, cpl); + validate_seg(R_GS, cpl); } ESP = (ESP & ~sp_mask) | (sp & sp_mask); env->eip = new_eip; -- cgit v1.2.3 From b7f0f463a55e4f4bded580905582f2dfa6652fca Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:20:25 +0000 Subject: debug fixes - use more generic TLB mappings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@486 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 7d74e2afa..51ffb7f96 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -73,7 +73,9 @@ void cpu_x86_close(CPUX86State *env) static const char *cc_op_str[] = { "DYNAMIC", "EFLAGS", - "MUL", + "MULB", + "MULW", + "MULL", "ADDB", "ADDW", "ADDL", @@ -191,13 +193,15 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) { a20_state = (a20_state != 0); if (a20_state != a20_enabled) { +#if defined(DEBUG_MMU) + printf("A20 update: a20=%d\n", a20_state); +#endif /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ cpu_interrupt(env, 0); /* when a20 is changed, all the MMU mappings are invalid, so we must flush everything */ - page_unmap(); tlb_flush(env); a20_enabled = a20_state; if (a20_enabled) @@ -211,18 +215,17 @@ void cpu_x86_update_cr0(CPUX86State *env) { int pg_state, pe_state; -#ifdef DEBUG_MMU +#if defined(DEBUG_MMU) printf("CR0 update: CR0=0x%08x\n", env->cr[0]); #endif pg_state = env->cr[0] & CR0_PG_MASK; if (pg_state != last_pg_state) { - page_unmap(); tlb_flush(env); last_pg_state = pg_state; } pe_state = env->cr[0] & CR0_PE_MASK; if (last_pe_state != pe_state) { - tb_flush(); + tb_flush(env); last_pe_state = pe_state; } } @@ -233,7 +236,6 @@ void cpu_x86_update_cr3(CPUX86State *env) #if defined(DEBUG_MMU) printf("CR3 update: CR3=%08x\n", env->cr[3]); #endif - page_unmap(); tlb_flush(env); } } @@ -250,19 +252,7 @@ void cpu_x86_init_mmu(CPUX86State *env) /* XXX: also flush 4MB pages */ void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) { - int flags; - unsigned long virt_addr; - tlb_flush_page(env, addr); - - flags = page_get_flags(addr); - if (flags & PAGE_VALID) { - virt_addr = addr & ~0xfff; -#if !defined(CONFIG_SOFTMMU) - munmap((void *)virt_addr, 4096); -#endif - page_set_flags(virt_addr, virt_addr + 4096, 0); - } } /* return value: -- cgit v1.2.3 From 3415a4ddb4dc88a206b25cc4daec4b506bfa5096 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:21:33 +0000 Subject: invd and wbinvd support - fixed code gen logic for invlpg - simpler exception handling in load_seg() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@487 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 2 +- target-i386/translate.c | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index 5423be5a3..63e34cf01 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -907,7 +907,7 @@ void OPPROTO op_das(void) /* never use it with R_CS */ void OPPROTO op_movl_seg_T0(void) { - load_seg(PARAM1, T0 & 0xffff, PARAM2); + load_seg(PARAM1, T0); } /* faster VM86 version */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 35067bff6..87b6711bc 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1538,10 +1538,15 @@ static void gen_setcc(DisasContext *s, int b) call this function with seg_reg == R_CS */ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) { - if (s->pe && !s->vm86) - gen_op_movl_seg_T0(seg_reg, cur_eip); - else + if (s->pe && !s->vm86) { + /* XXX: optimize by finding processor state dynamically */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_movl_seg_T0(seg_reg); + } else { gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); + } /* abort translation because the register may have a non zero base or because ss32 may change. For R_SS, translation must always stop as a special handling must be done to disable hardware @@ -3982,12 +3987,22 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_invlpg_A0(); + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } break; default: goto illegal_op; } break; + case 0x108: /* invd */ + case 0x109: /* wbinvd */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + /* nothing to do */ + } + break; case 0x63: /* arpl */ if (!s->pe || s->vm86) goto illegal_op; -- cgit v1.2.3 From 3811a291e2106ee1499a80965fa4e48e3635da43 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:27:57 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@488 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + VERSION | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 401f364cc..3432229f2 100644 --- a/Changelog +++ b/Changelog @@ -11,6 +11,7 @@ version 0.5.1: - 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: diff --git a/VERSION b/VERSION index 79a2734bb..5d4294b91 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.0 \ No newline at end of file +0.5.1 \ No newline at end of file -- cgit v1.2.3 From 0ac4bd56a8baf235c136c84b338616d47ce01689 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:44:17 +0000 Subject: float access fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@489 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 128 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 86 insertions(+), 42 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 9c880824f..f3922dc99 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -20,6 +20,40 @@ #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 + */ + +/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ +typedef union { + double d; +#if !defined(WORDS_BIGENDIAN) && !defined(__arm__) + struct { + uint32_t lower; + uint32_t upper; + } l; +#else + struct { + uint32_t upper; + uint32_t lower; + } l; +#endif + uint64_t ll; +} CPU_DoubleU; + /* CPU memory access without any memory or io remapping */ static inline int ldub_raw(void *ptr) @@ -40,7 +74,7 @@ static inline void stb_raw(void *ptr, int v) /* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the kernel handles unaligned load/stores may give better results, but it is a system wide setting : bad */ -#if defined(WORDS_BIGENDIAN) || defined(__arm__) +#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)) /* conservative code for little endian unaligned accesses */ static inline int lduw_raw(void *ptr) @@ -141,55 +175,23 @@ static inline void stfl_raw(void *ptr, float v) stl_raw(ptr, u.i); } - -#if defined(__arm__) && !defined(WORDS_BIGENDIAN) - -/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ static inline double ldfq_raw(void *ptr) { - union { - double d; - uint32_t tab[2]; - } u; - u.tab[1] = ldl_raw(ptr); - u.tab[0] = ldl_raw(ptr + 4); + CPU_DoubleU u; + u.l.lower = ldl_raw(ptr); + u.l.upper = ldl_raw(ptr + 4); return u.d; } static inline void stfq_raw(void *ptr, double v) { - union { - double d; - uint32_t tab[2]; - } u; + CPU_DoubleU u; u.d = v; - stl_raw(ptr, u.tab[1]); - stl_raw(ptr + 4, u.tab[0]); + stl_raw(ptr, u.l.lower); + stl_raw(ptr + 4, u.l.upper); } -#else -static inline double ldfq_raw(void *ptr) -{ - union { - double d; - uint64_t i; - } u; - u.i = ldq_raw(ptr); - return u.d; -} - -static inline void stfq_raw(void *ptr, double v) -{ - union { - double d; - uint64_t i; - } u; - u.d = v; - stq_raw(ptr, u.i); -} -#endif - -#elif defined(TARGET_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN) +#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)) static inline int lduw_raw(void *ptr) { @@ -235,8 +237,46 @@ static inline void stl_raw(void *ptr, int v) static inline void stq_raw(void *ptr, uint64_t v) { - stl_raw(ptr, v); - stl_raw(ptr+4, v >> 32); + stl_raw(ptr, v >> 32); + stl_raw(ptr + 4, v); +} + +/* float access */ + +static inline float ldfl_raw(void *ptr) +{ + union { + float f; + uint32_t i; + } u; + u.i = ldl_raw(ptr); + return u.f; +} + +static inline void stfl_raw(void *ptr, float v) +{ + union { + float f; + uint32_t i; + } u; + u.f = v; + stl_raw(ptr, u.i); +} + +static inline double ldfq_raw(void *ptr) +{ + CPU_DoubleU u; + u.l.upper = ldl_raw(ptr); + u.l.lower = ldl_raw(ptr + 4); + return u.d; +} + +static inline void stfq_raw(void *ptr, double v) +{ + CPU_DoubleU u; + u.d = v; + stl_raw(ptr, u.l.upper); + stl_raw(ptr + 4, u.l.lower); } #else @@ -330,10 +370,14 @@ static inline void stfq_raw(void *ptr, double v) #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) */ -- cgit v1.2.3 From b453b70bd8e61c4ab4bba48a32ae99c0aa758c79 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:45:21 +0000 Subject: sparc fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@490 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 5507c04dd..08ecea126 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -250,11 +250,7 @@ int cpu_exec(CPUState *env1) pc = (uint8_t *)env->regs[15]; #elif defined(TARGET_SPARC) flags = 0; - cs_base = 0; - if (env->npc) { - env->pc = env->npc; - env->npc = 0; - } + cs_base = env->npc; pc = (uint8_t *) env->pc; #elif defined(TARGET_PPC) flags = 0; @@ -271,7 +267,7 @@ int cpu_exec(CPUState *env1) tb = tb_alloc((unsigned long)pc); if (!tb) { /* flush must be done */ - tb_flush(); + tb_flush(env); /* cannot fail at this point */ tb = tb_alloc((unsigned long)pc); /* don't forget to invalidate previous TB info */ @@ -410,7 +406,7 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) cpu_x86_load_seg_cache(env, seg_reg, selector, (uint8_t *)(selector << 4), 0xffff, 0); } else { - load_seg(seg_reg, selector, 0); + load_seg(seg_reg, selector); } env = saved_env; } @@ -519,7 +515,11 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, static inline int handle_cpu_signal(unsigned long pc, unsigned long address, int is_write, sigset_t *old_set) { - return 0; + /* XXX: locking issue */ + if (is_write && page_unprotect(address)) { + return 1; + } + return 0; } #elif defined (TARGET_PPC) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, -- cgit v1.2.3 From f515528907764d1fb1fab2e68a8be25e15b3c096 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:46:50 +0000 Subject: aligned stack on 16 byte boundary - PPC target fixes - SPARC target fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@491 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 115 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 31 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index a7a2f61eb..9999268ea 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -98,8 +98,11 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - regs->u_regs[0] = infop->entry; - regs->u_regs[1] = infop->start_stack; + regs->psr = 0; + regs->pc = infop->entry; + regs->npc = regs->pc + 4; + regs->y = 0; + regs->u_regs[14] = infop->start_stack - 16 * 4; } #endif @@ -129,9 +132,42 @@ do { \ _r->gpr[4] = (unsigned long)++pos; \ for (; tmp != 0; pos++) \ tmp = *pos; \ - _r->gpr[5] = (unsigned long)pos; \ + _r->gpr[5] = (unsigned long)pos; \ } while (0) +/* + * We need to put in some extra aux table entries to tell glibc what + * the cache block size is, so it can use the dcbz instruction safely. + */ +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 +/* A special ignored type value for PPC, for glibc compatibility. */ +#define AT_IGNOREPPC 22 +/* + * The requirements here are: + * - keep the final alignment of sp (sp & 0xf) + * - make sure the 32-bit value at the first 16 byte aligned position of + * AUXV is greater than 16 for glibc compatibility. + * AT_IGNOREPPC is used for that. + * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, + * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. + */ +#define DLINFO_ARCH_ITEMS 3 +#define ARCH_DLINFO \ +do { \ + sp -= DLINFO_ARCH_ITEMS * 2; \ + NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \ + NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \ + NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \ + /* \ + * Now handle glibc compatibility. \ + */ \ + sp -= 2*2; \ + NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \ + } while (0) + static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) { _regs->msr = 1 << MSR_PR; /* Set user mode */ @@ -225,7 +261,7 @@ struct exec #define INTERPRETER_AOUT 1 #define INTERPRETER_ELF 2 -#define DLINFO_ITEMS 12 +#define DLINFO_ITEMS 11 #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) #define get_user(ptr) (typeof(*ptr))(*(ptr)) @@ -559,15 +595,51 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, unsigned long interp_load_addr, int ibcs, struct image_info *info) { - target_ulong *argv, *envp, *dlinfo; - target_ulong *sp; - - /* - * Force 16 byte alignment here for generality. - */ + target_ulong *argv, *envp; + target_ulong *sp, *csp; + + /* + * Force 16 byte _final_ alignment here for generality. + */ sp = (unsigned int *) (~15UL & (unsigned long) p); - sp -= DLINFO_ITEMS*2; - dlinfo = sp; + csp = sp; + csp -= (DLINFO_ITEMS + 1) * 2; +#ifdef DLINFO_ARCH_ITEMS + csp -= DLINFO_ARCH_ITEMS*2; +#endif + csp -= envc+1; + csp -= argc+1; + csp -= (!ibcs ? 3 : 1); /* argc itself */ + if ((unsigned long)csp & 15UL) + sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); + +#define NEW_AUX_ENT(nr, id, val) \ + put_user (tswapl(id), sp + (nr * 2)); \ + put_user (tswapl(val), sp + (nr * 2 + 1)) + sp -= 2; + NEW_AUX_ENT (0, AT_NULL, 0); + + sp -= DLINFO_ITEMS*2; + NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); + NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum)); + NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); + NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr)); + NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0); + NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid()); + NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid()); + NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid()); + NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid()); +#ifdef ARCH_DLINFO + /* + * ARCH_DLINFO must come last so platform specific code can enforce + * special alignment requirements on the AUXV if necessary (eg. PPC). + */ + ARCH_DLINFO; +#endif +#undef NEW_AUX_ENT + sp -= envc+1; envp = sp; sp -= argc+1; @@ -576,25 +648,6 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, put_user(tswapl((target_ulong)envp),--sp); put_user(tswapl((target_ulong)argv),--sp); } - -#define NEW_AUX_ENT(id, val) \ - put_user (tswapl(id), dlinfo++); \ - put_user (tswapl(val), dlinfo++) - - NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); - NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); - NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); - NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); - NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); - NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT (AT_UID, (target_ulong) getuid()); - NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid()); - NEW_AUX_ENT (AT_GID, (target_ulong) getgid()); - NEW_AUX_ENT (AT_EGID, (target_ulong) getegid()); - NEW_AUX_ENT (AT_NULL, 0); -#undef NEW_AUX_ENT - put_user(tswapl(argc),--sp); info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); while (argc-->0) { -- cgit v1.2.3 From 0124311e00452fa1555968dfe794dc8feed1a67c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:48:17 +0000 Subject: more generic TLB support - began to fix unlikely interrupt issues git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@492 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 4 ++-- exec.c | 68 +++++++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/exec-all.h b/exec-all.h index 2023cf225..de21774ee 100644 --- a/exec-all.h +++ b/exec-all.h @@ -77,7 +77,7 @@ int cpu_restore_state(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc); void cpu_exec_init(void); int page_unprotect(unsigned long address); -void page_unmap(void); +void tb_invalidate_page(unsigned long address); void tlb_flush_page(CPUState *env, uint32_t addr); void tlb_flush_page_write(CPUState *env, uint32_t addr); void tlb_flush(CPUState *env); @@ -127,7 +127,7 @@ static inline unsigned int tb_hash_func(unsigned long pc) } TranslationBlock *tb_alloc(unsigned long pc); -void tb_flush(void); +void tb_flush(CPUState *env); void tb_link(TranslationBlock *tb); extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; diff --git a/exec.c b/exec.c index 9cc251f95..2ef509dcf 100644 --- a/exec.c +++ b/exec.c @@ -62,7 +62,6 @@ typedef struct PageDesc { #define L1_SIZE (1 << L1_BITS) #define L2_SIZE (1 << L2_BITS) -static void tb_invalidate_page(unsigned long address); static void io_mem_init(void); unsigned long real_host_page_size; @@ -229,15 +228,19 @@ static void page_flush_tb(void) /* flush all the translation blocks */ /* XXX: tb_flush is currently not thread safe */ -void tb_flush(void) +void tb_flush(CPUState *env) { int i; -#ifdef DEBUG_FLUSH +#if defined(DEBUG_FLUSH) printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", code_gen_ptr - code_gen_buffer, nb_tbs, - (code_gen_ptr - code_gen_buffer) / nb_tbs); + nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); #endif + /* must reset current TB so that interrupts cannot modify the + links while we are modifying them */ + env->current_tb = NULL; + nb_tbs = 0; for(i = 0;i < CODE_GEN_HASH_SIZE; i++) tb_hash[i] = NULL; @@ -402,7 +405,7 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity) } /* invalidate all TBs which intersect with the target page starting at addr */ -static void tb_invalidate_page(unsigned long address) +void tb_invalidate_page(unsigned long address) { TranslationBlock *tb_next, *tb; unsigned int page_index; @@ -626,7 +629,7 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) /* suppress the jump to next tb in generated code */ tb_reset_jump(tb, n); - /* suppress jumps in the tb on which we could have jump */ + /* suppress jumps in the tb on which we could have jumped */ tb_reset_jump_recursive(tb_next); } } @@ -688,7 +691,7 @@ void cpu_single_step(CPUState *env, int enabled) if (env->singlestep_enabled != enabled) { env->singlestep_enabled = enabled; /* must flush all the translated code to avoid inconsistancies */ - tb_flush(); + tb_flush(env); } #endif } @@ -712,7 +715,7 @@ void cpu_set_log_filename(const char *filename) logfilename = strdup(filename); } -/* mask must never be zero */ +/* mask must never be zero, except for A20 change call */ void cpu_interrupt(CPUState *env, int mask) { TranslationBlock *tb; @@ -742,9 +745,10 @@ void cpu_abort(CPUState *env, const char *fmt, ...) abort(); } -#ifdef TARGET_I386 +#if !defined(CONFIG_USER_ONLY) + /* unmap all maped pages and flush all associated code */ -void page_unmap(void) +static void page_unmap(CPUState *env) { PageDesc *pmap; int i; @@ -784,21 +788,25 @@ void page_unmap(void) l1_map[i] = NULL; } } - tb_flush(); + tb_flush(env); } -#endif void tlb_flush(CPUState *env) { -#if !defined(CONFIG_USER_ONLY) int i; + + /* must reset current TB so that interrupts cannot modify the + links while we are modifying them */ + env->current_tb = NULL; + for(i = 0; i < CPU_TLB_SIZE; i++) { env->tlb_read[0][i].address = -1; env->tlb_write[0][i].address = -1; env->tlb_read[1][i].address = -1; env->tlb_write[1][i].address = -1; } -#endif + /* XXX: avoid flushing the TBs */ + page_unmap(env); } static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) @@ -810,8 +818,11 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) void tlb_flush_page(CPUState *env, uint32_t addr) { -#if !defined(CONFIG_USER_ONLY) - int i; + int i, flags; + + /* must reset current TB so that interrupts cannot modify the + links while we are modifying them */ + env->current_tb = NULL; addr &= TARGET_PAGE_MASK; i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); @@ -819,23 +830,44 @@ void tlb_flush_page(CPUState *env, uint32_t addr) tlb_flush_entry(&env->tlb_write[0][i], addr); tlb_flush_entry(&env->tlb_read[1][i], addr); tlb_flush_entry(&env->tlb_write[1][i], addr); + + flags = page_get_flags(addr); + if (flags & PAGE_VALID) { +#if !defined(CONFIG_SOFTMMU) + munmap((void *)addr, TARGET_PAGE_SIZE); #endif + page_set_flags(addr, addr + TARGET_PAGE_SIZE, 0); + } } /* make all write to page 'addr' trigger a TLB exception to detect self modifying code */ void tlb_flush_page_write(CPUState *env, uint32_t addr) { -#if !defined(CONFIG_USER_ONLY) int i; addr &= TARGET_PAGE_MASK; i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_flush_entry(&env->tlb_write[0][i], addr); tlb_flush_entry(&env->tlb_write[1][i], addr); -#endif } +#else + +void tlb_flush(CPUState *env) +{ +} + +void tlb_flush_page(CPUState *env, uint32_t addr) +{ +} + +void tlb_flush_page_write(CPUState *env, uint32_t addr) +{ +} + +#endif /* defined(CONFIG_USER_ONLY) */ + static inline unsigned long *physpage_find_alloc(unsigned int page) { unsigned long **lp, *p; -- cgit v1.2.3 From 6da41eafc40c543c581d8b585a906691beca43b0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:48:38 +0000 Subject: added CPU callbacks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@493 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 140 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 103 insertions(+), 37 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index bb3fed946..8b7dd9a53 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -248,6 +248,23 @@ static int put_packet(char *buf) return 0; } + /* better than nothing for SOFTMMU : we use physical addresses */ +#ifdef CONFIG_SOFTMMU +static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) +{ + uint8_t *ptr; + + if (addr >= phys_ram_size || + ((int64_t)addr + len > phys_ram_size)) + return -1; + ptr = phys_ram_base + addr; + if (is_write) + memcpy(ptr, buf, len); + else + memcpy(buf, ptr, len); + return 0; +} +#else static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) { int l, flags; @@ -276,13 +293,91 @@ static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) } return 0; } +#endif + +#if defined(TARGET_I386) + +static void to_le32(uint8_t *p, int v) +{ + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +} + +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + int i, fpus; + + for(i = 0; i < 8; i++) { + to_le32(mem_buf + i * 4, env->regs[i]); + } + to_le32(mem_buf + 8 * 4, env->eip); + to_le32(mem_buf + 9 * 4, env->eflags); + to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector); + to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector); + to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector); + to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector); + to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector); + to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector); + /* XXX: convert floats */ + for(i = 0; i < 8; i++) { + memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10); + } + to_le32(mem_buf + 36 * 4, env->fpuc); + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + to_le32(mem_buf + 37 * 4, fpus); + to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */ + to_le32(mem_buf + 39 * 4, 0); /* fiseg */ + to_le32(mem_buf + 40 * 4, 0); /* fioff */ + to_le32(mem_buf + 41 * 4, 0); /* foseg */ + to_le32(mem_buf + 42 * 4, 0); /* fooff */ + to_le32(mem_buf + 43 * 4, 0); /* fop */ + return 44 * 4; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + uint32_t *registers = (uint32_t *)mem_buf; + int i; + + for(i = 0; i < 8; i++) { + env->regs[i] = tswapl(registers[i]); + } + env->eip = registers[8]; + env->eflags = registers[9]; +#if defined(CONFIG_USER_ONLY) +#define LOAD_SEG(index, sreg)\ + if (tswapl(registers[index]) != env->segs[sreg].selector)\ + cpu_x86_load_seg(env, sreg, tswapl(registers[index])); + LOAD_SEG(10, R_CS); + LOAD_SEG(11, R_SS); + LOAD_SEG(12, R_DS); + LOAD_SEG(13, R_ES); + LOAD_SEG(14, R_FS); + LOAD_SEG(15, R_GS); +#endif +} + +#else + +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + return 0; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ +} + +#endif /* port = 0 means default port */ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) { CPUState *env; const char *p; - int ret, ch, nb_regs, i, type; + int ret, ch, reg_size, type; char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; @@ -339,47 +434,16 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) break; case 'g': env = cpu_gdbstub_get_env(opaque); - registers = (void *)mem_buf; -#if defined(TARGET_I386) - for(i = 0; i < 8; i++) { - registers[i] = tswapl(env->regs[i]); - } - registers[8] = env->eip; - registers[9] = env->eflags; - registers[10] = env->segs[R_CS].selector; - registers[11] = env->segs[R_SS].selector; - registers[12] = env->segs[R_DS].selector; - registers[13] = env->segs[R_ES].selector; - registers[14] = env->segs[R_FS].selector; - registers[15] = env->segs[R_GS].selector; - nb_regs = 16; -#endif - memtohex(buf, (const uint8_t *)registers, - sizeof(registers[0]) * nb_regs); + reg_size = cpu_gdb_read_registers(env, mem_buf); + memtohex(buf, mem_buf, reg_size); put_packet(buf); break; case 'G': env = cpu_gdbstub_get_env(opaque); registers = (void *)mem_buf; -#if defined(TARGET_I386) - hextomem((uint8_t *)registers, p, 16 * 4); - for(i = 0; i < 8; i++) { - env->regs[i] = tswapl(registers[i]); - } - env->eip = registers[8]; - env->eflags = registers[9]; -#if defined(CONFIG_USER_ONLY) -#define LOAD_SEG(index, sreg)\ - if (tswapl(registers[index]) != env->segs[sreg].selector)\ - cpu_x86_load_seg(env, sreg, tswapl(registers[index])); - LOAD_SEG(10, R_CS); - LOAD_SEG(11, R_SS); - LOAD_SEG(12, R_DS); - LOAD_SEG(13, R_ES); - LOAD_SEG(14, R_FS); - LOAD_SEG(15, R_GS); -#endif -#endif + len = strlen(p) / 2; + hextomem((uint8_t *)registers, p, len); + cpu_gdb_write_registers(env, mem_buf, len); put_packet("OK"); break; case 'm': @@ -445,6 +509,8 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) put_packet("OK"); } else if (!strncmp(p, "TStart", 6)) { /* start log (gdb 'tstart' command) */ + env = cpu_gdbstub_get_env(opaque); + tb_flush(env); cpu_set_log(CPU_LOG_ALL); put_packet("OK"); } else if (!strncmp(p, "TStop", 5)) { -- cgit v1.2.3 From 060366c5ad18b3e32886d8f7ce89c6cc23abb7ff Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:50:01 +0000 Subject: SPARC fixes : syscall fixes - added user register window exception support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@494 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 129 insertions(+), 21 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index aa5b758d6..bc19c645f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -299,27 +299,127 @@ void cpu_loop(CPUARMState *env) #ifdef TARGET_SPARC +//#define DEBUG_WIN + +/* WARNING: dealing with register windows _is_ complicated */ +static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) +{ + index = (index + cwp * 16) & (16 * NWINDOWS - 1); + /* wrap handling : if cwp is on the last window, then we use the + registers 'after' the end */ + if (index < 8 && env->cwp == (NWINDOWS - 1)) + index += (16 * NWINDOWS); + return index; +} + +static inline void save_window_offset(CPUSPARCState *env, int offset) +{ + unsigned int new_wim, i, cwp1; + uint32_t *sp_ptr; + + new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & + ((1LL << NWINDOWS) - 1); + /* save the window */ + cwp1 = (env->cwp + offset) & (NWINDOWS - 1); + sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); +#if defined(DEBUG_WIN) + printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", + (int)sp_ptr, cwp1); +#endif + for(i = 0; i < 16; i++) + stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]); + env->wim = new_wim; +} + +static void save_window(CPUSPARCState *env) +{ + save_window_offset(env, 2); +} + +static void restore_window(CPUSPARCState *env) +{ + unsigned int new_wim, i, cwp1; + uint32_t *sp_ptr; + + new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & + ((1LL << NWINDOWS) - 1); + + /* restore the invalid window */ + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); +#if defined(DEBUG_WIN) + printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", + (int)sp_ptr, cwp1); +#endif + for(i = 0; i < 16; i++) + env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i); + env->wim = new_wim; +} + +static void flush_windows(CPUSPARCState *env) +{ + int offset, cwp1; +#if defined(DEBUG_WIN) + printf("flush_windows:\n"); +#endif + offset = 2; + for(;;) { + /* if restore would invoke restore_window(), then we can stop */ + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + if (env->wim & (1 << cwp1)) + break; +#if defined(DEBUG_WIN) + printf("offset=%d: ", offset); +#endif + save_window_offset(env, offset); + offset++; + } +} + void cpu_loop (CPUSPARCState *env) { - int trapnr; - - while (1) { - trapnr = cpu_sparc_exec (env); - - switch (trapnr) { - case 0x8: case 0x10: - env->regwptr[0] = do_syscall (env, env->gregs[1], - env->regwptr[0], env->regwptr[1], env->regwptr[2], - env->regwptr[3], env->regwptr[4], env->regwptr[13]); - if (env->regwptr[0] >= 0xffffffe0) - env->psr |= PSR_CARRY; - break; - default: - printf ("Invalid trap: %d\n", trapnr); - exit (1); - } - process_pending_signals (env); - } + int trapnr, ret; + + while (1) { + trapnr = cpu_sparc_exec (env); + + switch (trapnr) { + case 0x88: + case 0x90: + ret = do_syscall (env, env->gregs[1], + env->regwptr[0], env->regwptr[1], + env->regwptr[2], env->regwptr[3], + env->regwptr[4], env->regwptr[5]); + if ((unsigned int)ret >= (unsigned int)(-515)) { + env->psr |= PSR_CARRY; + ret = -ret; + } else { + env->psr &= ~PSR_CARRY; + } + env->regwptr[0] = ret; + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; + case 0x83: /* flush windows */ + // flush_windows(env); + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; + case TT_WIN_OVF: /* window overflow */ + save_window(env); + break; + case TT_WIN_UNF: /* window underflow */ + restore_window(env); + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_sparc_dump_state(env, stderr, 0); + exit (1); + } + process_pending_signals (env); + } } #endif @@ -636,8 +736,16 @@ int main(int argc, char **argv) env->cpsr = regs->uregs[16]; } #elif defined(TARGET_SPARC) - env->pc = regs->u_regs[0]; - env->regwptr[6] = regs->u_regs[1]-0x40; + { + int i; + env->pc = regs->pc; + env->npc = regs->npc; + env->y = regs->y; + for(i = 0; i < 8; i++) + env->gregs[i] = regs->u_regs[i]; + for(i = 0; i < 8; i++) + env->regwptr[i] = regs->u_regs[i + 8]; + } #elif defined(TARGET_PPC) { int i; -- cgit v1.2.3 From c573ff67522c98232748bef44f18faf6ae587fff Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:51:36 +0000 Subject: stat64 fix - added getpagesize() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@495 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 68 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ddf1d9c52..abd5ce4e9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -239,6 +239,27 @@ extern int setresgid(gid_t, gid_t, gid_t); extern int getresgid(gid_t *, gid_t *, gid_t *); extern int setgroups(int, gid_t *); +#define put_user(x,ptr)\ +({\ + int size = sizeof(*ptr);\ + switch(size) {\ + case 1:\ + stb(ptr, (typeof(*ptr))(x));\ + break;\ + case 2:\ + stw(ptr, (typeof(*ptr))(x));\ + break;\ + case 4:\ + stl(ptr, (typeof(*ptr))(x));\ + break;\ + case 8:\ + stq(ptr, (typeof(*ptr))(x));\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) static inline long get_errno(long ret) { if (ret == -1) @@ -1415,7 +1436,7 @@ void syscall_init(void) ie++; } } - + long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { @@ -1424,7 +1445,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct kernel_statfs *stfs; #ifdef DEBUG - gemu_log("syscall %d\n", num); + gemu_log("syscall %d", num); #endif switch(num) { case TARGET_NR_exit: @@ -1978,10 +1999,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif break; case TARGET_NR_mmap2: +#if defined(TARGET_SPARC) +#define MMAP_SHIFT 12 +#else +#define MMAP_SHIFT TARGET_PAGE_BITS +#endif ret = get_errno(target_mmap(arg1, arg2, arg3, target_to_host_bitmask(arg4, mmap_flags_tbl), arg5, - arg6 << TARGET_PAGE_BITS)); + arg6 << MMAP_SHIFT)); break; case TARGET_NR_munmap: ret = get_errno(target_munmap(arg1, arg2)); @@ -2519,23 +2545,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, if (!is_error(ret)) { struct target_stat64 *target_st = (void *)arg2; memset(target_st, 0, sizeof(struct target_stat64)); - target_st->st_dev = tswap16(st.st_dev); - target_st->st_ino = tswap64(st.st_ino); + put_user(st.st_dev, &target_st->st_dev); + put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - target_st->__st_ino = tswapl(st.st_ino); + put_user(st.st_ino, &target_st->__st_ino); #endif - target_st->st_mode = tswap32(st.st_mode); - target_st->st_nlink = tswap32(st.st_nlink); - target_st->st_uid = tswapl(st.st_uid); - target_st->st_gid = tswapl(st.st_gid); - target_st->st_rdev = tswap16(st.st_rdev); + put_user(st.st_mode, &target_st->st_mode); + put_user(st.st_nlink, &target_st->st_nlink); + put_user(st.st_uid, &target_st->st_uid); + put_user(st.st_gid, &target_st->st_gid); + put_user(st.st_rdev, &target_st->st_rdev); /* XXX: better use of kernel struct */ - target_st->st_size = tswap64(st.st_size); - target_st->st_blksize = tswapl(st.st_blksize); - target_st->st_blocks = tswapl(st.st_blocks); - target_st->target_st_atime = tswapl(st.st_atime); - target_st->target_st_mtime = tswapl(st.st_mtime); - target_st->target_st_ctime = tswapl(st.st_ctime); + put_user(st.st_size, &target_st->st_size); + put_user(st.st_blksize, &target_st->st_blksize); + put_user(st.st_blocks, &target_st->st_blocks); + put_user(st.st_atime, &target_st->target_st_atime); + put_user(st.st_mtime, &target_st->target_st_mtime); + put_user(st.st_ctime, &target_st->target_st_ctime); } } break; @@ -2765,6 +2791,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_security case TARGET_NR_security: goto unimplemented; +#endif +#ifdef TARGET_NR_getpagesize + case TARGET_NR_getpagesize: + ret = TARGET_PAGE_SIZE; + break; #endif case TARGET_NR_gettid: ret = get_errno(gettid()); @@ -2799,6 +2830,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; } fail: +#ifdef DEBUG + gemu_log(" = %ld\n", ret); +#endif return ret; } -- cgit v1.2.3 From 3bfd9da14f53ffd567b0fa36449ce7296eb49b00 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:52:31 +0000 Subject: termios support for SPARC and PPC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@496 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/termbits.h | 215 +++++++++++++++++++++++++++++++ linux-user/i386/termbits.h | 214 ++++++++++++++++++++++++++++++ linux-user/ppc/termbits.h | 235 +++++++++++++++++++++++++++++++++ linux-user/sparc/termbits.h | 279 ++++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 307 ++++++++++++-------------------------------- 5 files changed, 1023 insertions(+), 227 deletions(-) create mode 100644 linux-user/arm/termbits.h create mode 100644 linux-user/i386/termbits.h create mode 100644 linux-user/ppc/termbits.h create mode 100644 linux-user/sparc/termbits.h diff --git a/linux-user/arm/termbits.h b/linux-user/arm/termbits.h new file mode 100644 index 000000000..36ead0895 --- /dev/null +++ b/linux-user/arm/termbits.h @@ -0,0 +1,215 @@ +/* from asm/termbits.h */ +/* NOTE: exactly the same as i386 */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + diff --git a/linux-user/i386/termbits.h b/linux-user/i386/termbits.h new file mode 100644 index 000000000..adff80243 --- /dev/null +++ b/linux-user/i386/termbits.h @@ -0,0 +1,214 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + diff --git a/linux-user/ppc/termbits.h b/linux-user/ppc/termbits.h new file mode 100644 index 000000000..6326747ee --- /dev/null +++ b/linux-user/ppc/termbits.h @@ -0,0 +1,235 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ + unsigned int c_ispeed; /* input speed */ + unsigned int c_ospeed; /* output speed */ +}; + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VMIN 5 +#define TARGET_VEOL 6 +#define TARGET_VTIME 7 +#define TARGET_VEOL2 8 +#define TARGET_VSWTC 9 + +#define TARGET_VWERASE 10 +#define TARGET_VREPRINT 11 +#define TARGET_VSUSP 12 +#define TARGET_VSTART 13 +#define TARGET_VSTOP 14 +#define TARGET_VLNEXT 15 +#define TARGET_VDISCARD 16 + +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IXON 0001000 +#define TARGET_IXOFF 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IUCLC 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_ONLCR 0000002 +#define TARGET_OLCUC 0000004 + +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 + +#define TARGET_OFILL 00000100 +#define TARGET_OFDEL 00000200 +#define TARGET_NLDLY 00001400 +#define TARGET_NL0 00000000 +#define TARGET_NL1 00000400 +#define TARGET_NL2 00001000 +#define TARGET_NL3 00001400 +#define TARGET_TABDLY 00006000 +#define TARGET_TAB0 00000000 +#define TARGET_TAB1 00002000 +#define TARGET_TAB2 00004000 +#define TARGET_TAB3 00006000 +#define TARGET_CRDLY 00030000 +#define TARGET_CR0 00000000 +#define TARGET_CR1 00010000 +#define TARGET_CR2 00020000 +#define TARGET_CR3 00030000 +#define TARGET_FFDLY 00040000 +#define TARGET_FF0 00000000 +#define TARGET_FF1 00040000 +#define TARGET_BSDLY 00100000 +#define TARGET_BS0 00000000 +#define TARGET_BS1 00100000 +#define TARGET_VTDLY 00200000 +#define TARGET_VT0 00000000 +#define TARGET_VT1 00200000 +#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0000377 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CBAUDEX 0000000 +#define TARGET_B57600 00020 +#define TARGET_B115200 00021 +#define TARGET_B230400 00022 +#define TARGET_B460800 00023 +#define TARGET_B500000 00024 +#define TARGET_B576000 00025 +#define TARGET_B921600 00026 +#define TARGET_B1000000 00027 +#define TARGET_B1152000 00030 +#define TARGET_B1500000 00031 +#define TARGET_B2000000 00032 +#define TARGET_B2500000 00033 +#define TARGET_B3000000 00034 +#define TARGET_B3500000 00035 +#define TARGET_B4000000 00036 + +#define TARGET_CSIZE 00001400 +#define TARGET_CS5 00000000 +#define TARGET_CS6 00000400 +#define TARGET_CS7 00001000 +#define TARGET_CS8 00001400 + +#define TARGET_CSTOPB 00002000 +#define TARGET_CREAD 00004000 +#define TARGET_PARENB 00010000 +#define TARGET_PARODD 00020000 +#define TARGET_HUPCL 00040000 + +#define TARGET_CLOCAL 00100000 +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000080 +#define TARGET_ICANON 0x00000100 +#define TARGET_XCASE 0x00004000 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000002 +#define TARGET_ECHOK 0x00000004 +#define TARGET_ECHONL 0x00000010 +#define TARGET_NOFLSH 0x80000000 +#define TARGET_TOSTOP 0x00400000 +#define TARGET_ECHOCTL 0x00000040 +#define TARGET_ECHOPRT 0x00000020 +#define TARGET_ECHOKE 0x00000001 +#define TARGET_FLUSHO 0x00800000 +#define TARGET_PENDIN 0x20000000 +#define TARGET_IEXTEN 0x00000400 + +/* ioctls */ + +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD +//#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) + +#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios) + +#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio) + +#define TARGET_TCSBRK TARGET_IO('t', 29) +#define TARGET_TCXONC TARGET_IO('t', 30) +#define TARGET_TCFLSH TARGET_IO('t', 31) + +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars) +#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars) +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E + +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 + +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 + +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ + diff --git a/linux-user/sparc/termbits.h b/linux-user/sparc/termbits.h new file mode 100644 index 000000000..cad45b292 --- /dev/null +++ b/linux-user/sparc/termbits.h @@ -0,0 +1,279 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VEOL 5 +#define TARGET_VEOL2 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 + +#define TARGET_VSUSP 10 +#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */ +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 + +/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is + * shared with eof/eol + */ +#define TARGET_VMIN TARGET_VEOF +#define TARGET_VTIME TARGET_VEOL + +/* c_iflag bits */ +#define TARGET_IGNBRK 0x00000001 +#define TARGET_BRKINT 0x00000002 +#define TARGET_IGNPAR 0x00000004 +#define TARGET_PARMRK 0x00000008 +#define TARGET_INPCK 0x00000010 +#define TARGET_ISTRIP 0x00000020 +#define TARGET_INLCR 0x00000040 +#define TARGET_IGNCR 0x00000080 +#define TARGET_ICRNL 0x00000100 +#define TARGET_IUCLC 0x00000200 +#define TARGET_IXON 0x00000400 +#define TARGET_IXANY 0x00000800 +#define TARGET_IXOFF 0x00001000 +#define TARGET_IMAXBEL 0x00002000 + +/* c_oflag bits */ +#define TARGET_OPOST 0x00000001 +#define TARGET_OLCUC 0x00000002 +#define TARGET_ONLCR 0x00000004 +#define TARGET_OCRNL 0x00000008 +#define TARGET_ONOCR 0x00000010 +#define TARGET_ONLRET 0x00000020 +#define TARGET_OFILL 0x00000040 +#define TARGET_OFDEL 0x00000080 +#define TARGET_NLDLY 0x00000100 +#define TARGET_NL0 0x00000000 +#define TARGET_NL1 0x00000100 +#define TARGET_CRDLY 0x00000600 +#define TARGET_CR0 0x00000000 +#define TARGET_CR1 0x00000200 +#define TARGET_CR2 0x00000400 +#define TARGET_CR3 0x00000600 +#define TARGET_TABDLY 0x00001800 +#define TARGET_TAB0 0x00000000 +#define TARGET_TAB1 0x00000800 +#define TARGET_TAB2 0x00001000 +#define TARGET_TAB3 0x00001800 +#define TARGET_XTABS 0x00001800 +#define TARGET_BSDLY 0x00002000 +#define TARGET_BS0 0x00000000 +#define TARGET_BS1 0x00002000 +#define TARGET_VTDLY 0x00004000 +#define TARGET_VT0 0x00000000 +#define TARGET_VT1 0x00004000 +#define TARGET_FFDLY 0x00008000 +#define TARGET_FF0 0x00000000 +#define TARGET_FF1 0x00008000 +#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */ +#define TARGET_WRAP 0x00020000 /* SUNOS specific */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0x0000100f +#define TARGET_B0 0x00000000 /* hang up */ +#define TARGET_B50 0x00000001 +#define TARGET_B75 0x00000002 +#define TARGET_B110 0x00000003 +#define TARGET_B134 0x00000004 +#define TARGET_B150 0x00000005 +#define TARGET_B200 0x00000006 +#define TARGET_B300 0x00000007 +#define TARGET_B600 0x00000008 +#define TARGET_B1200 0x00000009 +#define TARGET_B1800 0x0000000a +#define TARGET_B2400 0x0000000b +#define TARGET_B4800 0x0000000c +#define TARGET_B9600 0x0000000d +#define TARGET_B19200 0x0000000e +#define TARGET_B38400 0x0000000f +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0x00000030 +#define TARGET_CS5 0x00000000 +#define TARGET_CS6 0x00000010 +#define TARGET_CS7 0x00000020 +#define TARGET_CS8 0x00000030 +#define TARGET_CSTOPB 0x00000040 +#define TARGET_CREAD 0x00000080 +#define TARGET_PARENB 0x00000100 +#define TARGET_PARODD 0x00000200 +#define TARGET_HUPCL 0x00000400 +#define TARGET_CLOCAL 0x00000800 +#define TARGET_CBAUDEX 0x00001000 +/* We'll never see these speeds with the Zilogs, but for completeness... */ +#define TARGET_B57600 0x00001001 +#define TARGET_B115200 0x00001002 +#define TARGET_B230400 0x00001003 +#define TARGET_B460800 0x00001004 +/* This is what we can do with the Zilogs. */ +#define TARGET_B76800 0x00001005 +/* This is what we can do with the SAB82532. */ +#define TARGET_B153600 0x00001006 +#define TARGET_B307200 0x00001007 +#define TARGET_B614400 0x00001008 +#define TARGET_B921600 0x00001009 +/* And these are the rest... */ +#define TARGET_B500000 0x0000100a +#define TARGET_B576000 0x0000100b +#define TARGET_B1000000 0x0000100c +#define TARGET_B1152000 0x0000100d +#define TARGET_B1500000 0x0000100e +#define TARGET_B2000000 0x0000100f +/* These have totally bogus values and nobody uses them + so far. Later on we'd have to use say 0x10000x and + adjust CBAUD constant and drivers accordingly. +#define B2500000 0x00001010 +#define B3000000 0x00001011 +#define B3500000 0x00001012 +#define B4000000 0x00001013 */ +#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 0x80000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000001 +#define TARGET_ICANON 0x00000002 +#define TARGET_XCASE 0x00000004 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000010 +#define TARGET_ECHOK 0x00000020 +#define TARGET_ECHONL 0x00000040 +#define TARGET_NOFLSH 0x00000080 +#define TARGET_TOSTOP 0x00000100 +#define TARGET_ECHOCTL 0x00000200 +#define TARGET_ECHOPRT 0x00000400 +#define TARGET_ECHOKE 0x00000800 +#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */ +#define TARGET_FLUSHO 0x00002000 +#define TARGET_PENDIN 0x00004000 +#define TARGET_IEXTEN 0x00008000 + +/* ioctls */ + +/* Big T */ +#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio) +#define TARGET_TCSBRK TARGET_IO('T', 5) +#define TARGET_TCXONC TARGET_IO('T', 6) +#define TARGET_TCFLSH TARGET_IO('T', 7) +#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios) + +/* Note that all the ioctls that are not available in Linux have a + * double underscore on the front to: a) avoid some programs to + * thing we support some ioctls under Linux (autoconfiguration stuff) + */ +/* Little t */ +#define TARGET_TIOCGETD TARGET_IOR('t', 0, int) +#define TARGET_TIOCSETD TARGET_IOW('t', 1, int) +//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */ +//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */ +//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */ +//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */ +//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */ +//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */ +#define TARGET_TIOCEXCL TARGET_IO('t', 13) +#define TARGET_TIOCNXCL TARGET_IO('t', 14) +//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */ +//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */ +//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */ +//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */ +//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */ +//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */ +//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */ +#define TARGET_TIOCCONS TARGET_IO('t', 36) +//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */ +//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */ +#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int) +#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int) +//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) +//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */ +#define TARGET_TIOCMGET TARGET_IOR('t', 106, int) +#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) +#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) +#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) +#define TARGET_TIOCSTART TARGET_IO('t', 110) +#define TARGET_TIOCSTOP TARGET_IO('t', 111) +#define TARGET_TIOCPKT TARGET_IOW('t', 112, int) +#define TARGET_TIOCNOTTY TARGET_IO('t', 113) +#define TARGET_TIOCSTI TARGET_IOW('t', 114, char) +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) +//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */ +//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */ +/* 118 is the non-posix setpgrp tty ioctl */ +/* 119 is the non-posix getpgrp tty ioctl */ +//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */ +//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */ +#define TARGET_TIOCCBRK TARGET_IO('t', 122) +#define TARGET_TIOCSBRK TARGET_IO('t', 123) +//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */ +//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */ +//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */ +//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */ +//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */ +//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int) +#define TARGET_TIOCSCTTY TARGET_IO('t', 132) +#define TARGET_TIOCGSID TARGET_IOR('t', 133, int) +/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ +#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */ +#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */ + +/* Little f */ +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD + +/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it + * someday. This is completely bogus, I know... + */ +//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */ +//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */ + +/* Linux specific, no SunOS equivalent. */ +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TCSBRKP 0x5425 +#define TARGET_TIOCTTYGSTRUCT 0x5426 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x545C /* Wait input */ +#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */ + diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index caa40d1f0..a0a04aab3 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -664,220 +664,26 @@ struct target_pollfd { #define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) - -/* 0x54 is just a magic number to make these relatively unique ('T') */ - -#define TARGET_TCGETS 0x5401 -#define TARGET_TCSETS 0x5402 -#define TARGET_TCSETSW 0x5403 -#define TARGET_TCSETSF 0x5404 -#define TARGET_TCGETA 0x5405 -#define TARGET_TCSETA 0x5406 -#define TARGET_TCSETAW 0x5407 -#define TARGET_TCSETAF 0x5408 -#define TARGET_TCSBRK 0x5409 -#define TARGET_TCXONC 0x540A -#define TARGET_TCFLSH 0x540B -#define TARGET_TIOCEXCL 0x540C -#define TARGET_TIOCNXCL 0x540D -#define TARGET_TIOCSCTTY 0x540E -#define TARGET_TIOCGPGRP 0x540F -#define TARGET_TIOCSPGRP 0x5410 -#define TARGET_TIOCOUTQ 0x5411 -#define TARGET_TIOCSTI 0x5412 -#define TARGET_TIOCGWINSZ 0x5413 -#define TARGET_TIOCSWINSZ 0x5414 -#define TARGET_TIOCMGET 0x5415 -#define TARGET_TIOCMBIS 0x5416 -#define TARGET_TIOCMBIC 0x5417 -#define TARGET_TIOCMSET 0x5418 -#define TARGET_TIOCGSOFTCAR 0x5419 -#define TARGET_TIOCSSOFTCAR 0x541A -#define TARGET_FIONREAD 0x541B -#define TARGET_TIOCINQ FIONREAD -#define TARGET_TIOCLINUX 0x541C -#define TARGET_TIOCCONS 0x541D -#define TARGET_TIOCGSERIAL 0x541E -#define TARGET_TIOCSSERIAL 0x541F -#define TARGET_TIOCPKT 0x5420 -#define TARGET_FIONBIO 0x5421 -#define TARGET_TIOCNOTTY 0x5422 -#define TARGET_TIOCSETD 0x5423 -#define TARGET_TIOCGETD 0x5424 -#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ -#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ -#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ -#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ - -#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ -#define TARGET_FIOCLEX 0x5451 -#define TARGET_FIOASYNC 0x5452 -#define TARGET_TIOCSERCONFIG 0x5453 -#define TARGET_TIOCSERGWILD 0x5454 -#define TARGET_TIOCSERSWILD 0x5455 -#define TARGET_TIOCGLCKTRMIOS 0x5456 -#define TARGET_TIOCSLCKTRMIOS 0x5457 -#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ - -#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ - -/* Used for packet mode */ -#define TARGET_TIOCPKT_DATA 0 -#define TARGET_TIOCPKT_FLUSHREAD 1 -#define TARGET_TIOCPKT_FLUSHWRITE 2 -#define TARGET_TIOCPKT_STOP 4 -#define TARGET_TIOCPKT_START 8 -#define TARGET_TIOCPKT_NOSTOP 16 -#define TARGET_TIOCPKT_DOSTOP 32 - -#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ - /* from asm/termbits.h */ -#define TARGET_NCCS 19 +#define TARGET_NCC 8 +struct target_termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCC]; /* control characters */ +}; -struct target_termios { - unsigned int c_iflag; /* input mode flags */ - unsigned int c_oflag; /* output mode flags */ - unsigned int c_cflag; /* control mode flags */ - unsigned int c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[TARGET_NCCS]; /* control characters */ +struct target_winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; }; -/* c_iflag bits */ -#define TARGET_IGNBRK 0000001 -#define TARGET_BRKINT 0000002 -#define TARGET_IGNPAR 0000004 -#define TARGET_PARMRK 0000010 -#define TARGET_INPCK 0000020 -#define TARGET_ISTRIP 0000040 -#define TARGET_INLCR 0000100 -#define TARGET_IGNCR 0000200 -#define TARGET_ICRNL 0000400 -#define TARGET_IUCLC 0001000 -#define TARGET_IXON 0002000 -#define TARGET_IXANY 0004000 -#define TARGET_IXOFF 0010000 -#define TARGET_IMAXBEL 0020000 - -/* c_oflag bits */ -#define TARGET_OPOST 0000001 -#define TARGET_OLCUC 0000002 -#define TARGET_ONLCR 0000004 -#define TARGET_OCRNL 0000010 -#define TARGET_ONOCR 0000020 -#define TARGET_ONLRET 0000040 -#define TARGET_OFILL 0000100 -#define TARGET_OFDEL 0000200 -#define TARGET_NLDLY 0000400 -#define TARGET_NL0 0000000 -#define TARGET_NL1 0000400 -#define TARGET_CRDLY 0003000 -#define TARGET_CR0 0000000 -#define TARGET_CR1 0001000 -#define TARGET_CR2 0002000 -#define TARGET_CR3 0003000 -#define TARGET_TABDLY 0014000 -#define TARGET_TAB0 0000000 -#define TARGET_TAB1 0004000 -#define TARGET_TAB2 0010000 -#define TARGET_TAB3 0014000 -#define TARGET_XTABS 0014000 -#define TARGET_BSDLY 0020000 -#define TARGET_BS0 0000000 -#define TARGET_BS1 0020000 -#define TARGET_VTDLY 0040000 -#define TARGET_VT0 0000000 -#define TARGET_VT1 0040000 -#define TARGET_FFDLY 0100000 -#define TARGET_FF0 0000000 -#define TARGET_FF1 0100000 - -/* c_cflag bit meaning */ -#define TARGET_CBAUD 0010017 -#define TARGET_B0 0000000 /* hang up */ -#define TARGET_B50 0000001 -#define TARGET_B75 0000002 -#define TARGET_B110 0000003 -#define TARGET_B134 0000004 -#define TARGET_B150 0000005 -#define TARGET_B200 0000006 -#define TARGET_B300 0000007 -#define TARGET_B600 0000010 -#define TARGET_B1200 0000011 -#define TARGET_B1800 0000012 -#define TARGET_B2400 0000013 -#define TARGET_B4800 0000014 -#define TARGET_B9600 0000015 -#define TARGET_B19200 0000016 -#define TARGET_B38400 0000017 -#define TARGET_EXTA B19200 -#define TARGET_EXTB B38400 -#define TARGET_CSIZE 0000060 -#define TARGET_CS5 0000000 -#define TARGET_CS6 0000020 -#define TARGET_CS7 0000040 -#define TARGET_CS8 0000060 -#define TARGET_CSTOPB 0000100 -#define TARGET_CREAD 0000200 -#define TARGET_PARENB 0000400 -#define TARGET_PARODD 0001000 -#define TARGET_HUPCL 0002000 -#define TARGET_CLOCAL 0004000 -#define TARGET_CBAUDEX 0010000 -#define TARGET_B57600 0010001 -#define TARGET_B115200 0010002 -#define TARGET_B230400 0010003 -#define TARGET_B460800 0010004 -#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -#define TARGET_CRTSCTS 020000000000 /* flow control */ - -/* c_lflag bits */ -#define TARGET_ISIG 0000001 -#define TARGET_ICANON 0000002 -#define TARGET_XCASE 0000004 -#define TARGET_ECHO 0000010 -#define TARGET_ECHOE 0000020 -#define TARGET_ECHOK 0000040 -#define TARGET_ECHONL 0000100 -#define TARGET_NOFLSH 0000200 -#define TARGET_TOSTOP 0000400 -#define TARGET_ECHOCTL 0001000 -#define TARGET_ECHOPRT 0002000 -#define TARGET_ECHOKE 0004000 -#define TARGET_FLUSHO 0010000 -#define TARGET_PENDIN 0040000 -#define TARGET_IEXTEN 0100000 - -/* c_cc character offsets */ -#define TARGET_VINTR 0 -#define TARGET_VQUIT 1 -#define TARGET_VERASE 2 -#define TARGET_VKILL 3 -#define TARGET_VEOF 4 -#define TARGET_VTIME 5 -#define TARGET_VMIN 6 -#define TARGET_VSWTC 7 -#define TARGET_VSTART 8 -#define TARGET_VSTOP 9 -#define TARGET_VSUSP 10 -#define TARGET_VEOL 11 -#define TARGET_VREPRINT 12 -#define TARGET_VDISCARD 13 -#define TARGET_VWERASE 14 -#define TARGET_VLNEXT 15 -#define TARGET_VEOL2 16 +#include "termbits.h" #define TARGET_MAP_SHARED 0x01 /* Share changes */ #define TARGET_MAP_PRIVATE 0x02 /* Changes are private */ @@ -891,9 +697,7 @@ struct target_termios { #define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ -#endif /* defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) */ - -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) +#if defined(TARGET_I386) || defined(TARGET_ARM) struct target_stat { unsigned short st_dev; unsigned short __pad1; @@ -954,6 +758,64 @@ struct target_stat64 { unsigned long long st_ino; } __attribute__((packed)); +#elif defined(TARGET_SPARC) + +struct target_stat { + unsigned short st_dev; + target_ulong st_ino; + unsigned short st_mode; + short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + target_long st_size; + target_long target_st_atime; + target_ulong __unused1; + target_long target_st_mtime; + target_ulong __unused2; + target_long target_st_ctime; + target_ulong __unused3; + target_long st_blksize; + target_long st_blocks; + target_ulong __unused4[2]; +}; + +struct target_stat64 { + unsigned char __pad0[6]; + unsigned short st_dev; + + uint64_t st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned int st_uid; + unsigned int st_gid; + + unsigned char __pad2[6]; + unsigned short st_rdev; + + unsigned char __pad3[8]; + + int64_t st_size; + unsigned int st_blksize; + + unsigned char __pad4[8]; + unsigned int st_blocks; + + unsigned int target_st_atime; + unsigned int __unused1; + + unsigned int target_st_mtime; + unsigned int __unused2; + + unsigned int target_st_ctime; + unsigned int __unused3; + + unsigned int __unused4; + unsigned int __unused5; +}; + #elif defined(TARGET_PPC) struct target_stat { @@ -979,32 +841,23 @@ struct target_stat { struct target_stat64 { unsigned long long st_dev; - unsigned long long st_ino; - - unsigned int st_mode; - unsigned int st_nlink; - + unsigned int st_mode; + unsigned int st_nlink; unsigned int st_uid; unsigned int st_gid; - - unsigned long long st_rdev; - unsigned short int __pad2; - - long long st_size; + unsigned long long st_rdev; + long long pad0; + long long st_size; target_ulong st_blksize; - + target_ulong pad1; long long st_blocks; /* Number 512-byte blocks allocated. */ - target_ulong target_st_atime; target_ulong target_st_atime_nsec; - target_ulong target_st_mtime; target_ulong target_st_mtime_nsec; - target_ulong target_st_ctime; target_ulong target_st_ctime_nsec; - target_ulong __unused4; target_ulong __unused5; }; -- cgit v1.2.3 From a41bc9af8fc6fe89a7539f1c00e743f69643d744 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:55:00 +0000 Subject: explicited S3 specific code - added more debug code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@497 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 9db5d955c..099031442 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -50,6 +50,10 @@ //#define DEBUG_VGA //#define DEBUG_VGA_MEM +//#define DEBUG_VGA_REG + +//#define DEBUG_S3 +#define CONFIG_S3VGA #define MSR_COLOR_EMULATION 0x01 #define MSR_PAGE_SELECT 0x20 @@ -252,6 +256,9 @@ static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr) break; case 0x3c5: val = s->sr[s->sr_index]; +#ifdef DEBUG_VGA_REG + printf("vga: read SR%x = 0x%02x\n", s->sr_index, val); +#endif break; case 0x3c7: val = s->dac_state; @@ -274,6 +281,9 @@ static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr) break; case 0x3cf: val = s->gr[s->gr_index]; +#ifdef DEBUG_VGA_REG + printf("vga: read GR%x = 0x%02x\n", s->gr_index, val); +#endif break; case 0x3b4: case 0x3d4: @@ -282,6 +292,14 @@ static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr) case 0x3b5: case 0x3d5: val = s->cr[s->cr_index]; +#ifdef DEBUG_VGA_REG + printf("vga: read CR%x = 0x%02x\n", s->cr_index, val); +#endif +#ifdef DEBUG_S3 + if (s->cr_index >= 0x20) + printf("S3: CR read index=0x%x val=0x%x\n", + s->cr_index, val); +#endif break; case 0x3ba: case 0x3da: @@ -354,6 +372,9 @@ static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) s->sr_index = val & 7; break; case 0x3c5: +#ifdef DEBUG_VGA_REG + printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); +#endif s->sr[s->sr_index] = val & sr_mask[s->sr_index]; break; case 0x3c7: @@ -378,6 +399,9 @@ static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) s->gr_index = val & 0x0f; break; case 0x3cf: +#ifdef DEBUG_VGA_REG + printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); +#endif s->gr[s->gr_index] = val & gr_mask[s->gr_index]; break; case 0x3b4: @@ -386,6 +410,9 @@ static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) break; case 0x3b5: case 0x3d5: +#ifdef DEBUG_VGA_REG + printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); +#endif /* handle CR0-7 protection */ if ((s->cr[11] & 0x80) && s->cr_index <= 7) { /* can always write bit 4 of CR7 */ @@ -403,6 +430,7 @@ static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) s->cr[s->cr_index] = val; break; +#ifdef CONFIG_S3VGA /* S3 registers */ case 0x2d: case 0x2e: @@ -422,10 +450,16 @@ static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) v = val & 3; s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2); break; +#endif default: s->cr[s->cr_index] = val; break; } +#ifdef DEBUG_S3 + if (s->cr_index >= 0x20) + printf("S3: CR write index=0x%x val=0x%x\n", + s->cr_index, val); +#endif break; case 0x3ba: case 0x3da: @@ -507,7 +541,6 @@ static uint32_t vga_mem_readl(uint32_t addr) return v; } - /* called for accesses between 0xa0000 and 0xc0000 */ void vga_mem_writeb(uint32_t addr, uint32_t val) { @@ -588,7 +621,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) case 3: /* rotate */ b = s->gr[3] & 7; - val = ((val >> b) | (val << (8 - b))); + val = (val >> b) | (val << (8 - b)); bit_mask = s->gr[8] & val; val = mask16[s->gr[0]]; @@ -787,15 +820,20 @@ static int update_basic_params(VGAState *s) full_update = 0; /* compute line_offset in bytes */ + line_offset = s->cr[0x13]; +#ifdef CONFIG_S3VGA v = (s->cr[0x51] >> 4) & 3; /* S3 extension */ if (v == 0) v = (s->cr[0x43] >> 2) & 1; /* S3 extension */ - line_offset = s->cr[0x13] | (v << 8); + line_offset |= (v << 8); +#endif line_offset <<= 3; /* starting address */ start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); +#ifdef CONFIG_S3VGA start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */ +#endif /* line compare */ line_compare = s->cr[0x18] | @@ -1290,11 +1328,13 @@ void vga_update_display(void) void vga_reset(VGAState *s) { memset(s, 0, sizeof(VGAState)); +#ifdef CONFIG_S3VGA /* chip ID for 8c968 */ s->cr[0x2d] = 0x88; s->cr[0x2e] = 0xb0; s->cr[0x2f] = 0x01; /* XXX: check revision code */ s->cr[0x30] = 0xe1; +#endif s->graphic_mode = -1; /* force full update */ } -- cgit v1.2.3 From dd4e27d8101425b807df672df754eaa242c64351 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 15:58:16 +0000 Subject: removed test code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@498 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/sparc/syscall_nr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index 3270a3021..afb364f07 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -182,7 +182,7 @@ #define TARGET_NR_sysinfo 214 /* Linux Specific */ #define TARGET_NR_ipc 215 /* Linux Specific */ #define TARGET_NR_sigreturn 216 /* Linux Specific */ -#define TARGET_NR_clone 2170 /* Linux Specific */ +#define TARGET_NR_clone 217 /* Linux Specific */ #define TARGET_NR_adjtimex 219 /* Linux Specific */ #define TARGET_NR_sigprocmask 220 /* Linux Specific */ #define TARGET_NR_create_module 221 /* Linux Specific */ -- cgit v1.2.3 From c2655080670e25f13756d00ab1548a364b7ddd01 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 16:07:06 +0000 Subject: more precise PIT gate emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@499 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index 830b5462d..9b1a3fcc7 100644 --- a/vl.c +++ b/vl.c @@ -1002,6 +1002,10 @@ static int pit_get_count(PITChannelState *s) case 5: counter = (s->count - d) & 0xffff; break; + case 3: + /* XXX: may be incorrect for odd counts */ + counter = s->count - ((2 * d) % s->count); + break; default: counter = s->count - (d % s->count); break; @@ -1031,7 +1035,7 @@ static int pit_get_out(PITChannelState *s) out = 0; break; case 3: - out = (d % s->count) < (s->count >> 1); + out = (d % s->count) < ((s->count + 1) >> 1); break; case 4: case 5: @@ -1074,7 +1078,7 @@ static int pit_get_out_edges(PITChannelState *s) ret = d2 - d1; break; case 3: - v = s->count - (s->count >> 1); + v = s->count - ((s->count + 1) >> 1); d1 = (d1 + v) / s->count; d2 = (d2 + v) / s->count; ret = d2 - d1; @@ -1090,6 +1094,36 @@ static int pit_get_out_edges(PITChannelState *s) return ret; } +/* val must be 0 or 1 */ +static inline void pit_set_gate(PITChannelState *s, int val) +{ + switch(s->mode) { + default: + case 0: + case 4: + /* XXX: just disable/enable counting */ + break; + case 1: + case 5: + if (s->gate < val) { + /* restart counting on rising edge */ + s->count_load_time = cpu_get_ticks(); + s->count_last_edge_check_time = s->count_load_time; + } + break; + case 2: + case 3: + if (s->gate < val) { + /* restart counting on rising edge */ + s->count_load_time = cpu_get_ticks(); + s->count_last_edge_check_time = s->count_load_time; + } + /* XXX: disable/enable counting */ + break; + } + s->gate = val; +} + static inline void pit_load_count(PITChannelState *s, int val) { if (val == 0) @@ -1185,7 +1219,7 @@ uint32_t pit_ioport_read(CPUX86State *env, uint32_t addr) void speaker_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) { speaker_data_on = (val >> 1) & 1; - pit_channels[2].gate = val & 1; + pit_set_gate(&pit_channels[2], val & 1); } uint32_t speaker_ioport_read(CPUX86State *env, uint32_t addr) @@ -1463,7 +1497,6 @@ void serial_received_byte(SerialState *s, int ch) serial_update_irq(); break; case 'd': - // tb_flush(); cpu_set_log(CPU_LOG_ALL); break; case TERM_ESCAPE: @@ -2128,7 +2161,7 @@ uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) KBDState *s = &kbd_state; int val; val = s->status; -#if defined(DEBUG_KBD) +#if defined(DEBUG_KBD) && 0 printf("kbd: read status=0x%02x\n", val); #endif return val; -- cgit v1.2.3 From 546cdbd77da8ceb09ce1b4df4fbf9c68533e7f17 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 16:08:39 +0000 Subject: first multi target test (lauches 'ls') git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@500 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Makefile b/tests/Makefile index 4cfe7912e..a9bb0f3dc 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -65,5 +65,11 @@ hello-arm: hello-arm.o hello-arm.o: hello-arm.c arm-linux-gcc -Wall -g -O2 -c -o $@ $< +# XXX: find a way to compile easily a test for each arch +test2: + @for arch in i386 arm sparc ppc; do \ + ../$${arch}-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \ + done + clean: rm -f *~ *.o $(TESTS) -- cgit v1.2.3 From 82c7e2a4c6745ace4dbf3f0792d98dcb08979c00 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 16:10:33 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@501 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- TODO | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index efec671b7..401776a4e 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ install: all done # various test targets -test speed: all +test speed test2: all make -C tests $@ TAGS: diff --git a/TODO b/TODO index fece491bc..da07daae0 100644 --- a/TODO +++ b/TODO @@ -1,14 +1,17 @@ +- user/kernel PUSHL/POPL in helper.c +- keyboard output buffer filling timing emulation +- verify tb_flush() with a20 and TLBs + +- cmos clock update and timers +- test ldt limit < 7 ? - tests for each target CPU -- ppc qemu test - optimize FPU operations (evaluate x87 stack pointer statically) and fix cr0.TS emulation -- fix some 16 bit sp push/pop overflow +- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) - sysenter/sysexit emulation -- finish segment ops (call far, ret far, load_seg suppressed) - fix CCOP optimisation - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). -- cpu loop optimisation (optimise ret case as the cpu state does not change) - fix arm fpu rounding (at least for float->integer conversions) lower priority: -- cgit v1.2.3 From 773b93ee0684a9b9d1f0029a936a251411289027 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:15:59 +0000 Subject: signal fix: update the host signal 'signal ignored' state to avoid unexpected -EINTR values (ash fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@503 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 52 +++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 587792d48..bb006cc79 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -370,33 +370,6 @@ int queue_signal(int sig, target_siginfo_t *info) } } -#if defined(DEBUG_SIGNAL) -#ifdef __i386__ -static void dump_regs(struct ucontext *uc) -{ - fprintf(stderr, - "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EFL=%08x EIP=%08x\n", - uc->uc_mcontext.gregs[EAX], - uc->uc_mcontext.gregs[EBX], - uc->uc_mcontext.gregs[ECX], - uc->uc_mcontext.gregs[EDX], - uc->uc_mcontext.gregs[ESI], - uc->uc_mcontext.gregs[EDI], - uc->uc_mcontext.gregs[EBP], - uc->uc_mcontext.gregs[ESP], - uc->uc_mcontext.gregs[EFL], - uc->uc_mcontext.gregs[EIP]); -} -#else -static void dump_regs(struct ucontext *uc) -{ -} -#endif - -#endif - static void host_signal_handler(int host_signum, siginfo_t *info, void *puc) { @@ -416,7 +389,6 @@ static void host_signal_handler(int host_signum, siginfo_t *info, return; #if defined(DEBUG_SIGNAL) fprintf(stderr, "qemu: got signal %d\n", sig); - dump_regs(puc); #endif host_to_target_siginfo_noswap(&tinfo, info); if (queue_signal(sig, &tinfo) == 1) { @@ -429,11 +401,13 @@ int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact) { struct emulated_sigaction *k; + struct sigaction act1; + int host_sig; if (sig < 1 || sig > TARGET_NSIG) return -EINVAL; k = &sigact_table[sig - 1]; -#if defined(DEBUG_SIGNAL) && 0 +#if defined(DEBUG_SIGNAL) fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n", sig, (int)act, (int)oact); #endif @@ -448,6 +422,26 @@ int do_sigaction(int sig, const struct target_sigaction *act, k->sa.sa_flags = tswapl(act->sa_flags); k->sa.sa_restorer = tswapl(act->sa_restorer); k->sa.sa_mask = act->sa_mask; + + /* we update the host linux signal state */ + host_sig = target_to_host_signal(sig); + if (host_sig != SIGSEGV && host_sig != SIGBUS) { + sigfillset(&act1.sa_mask); + act1.sa_flags = SA_SIGINFO; + if (k->sa.sa_flags & TARGET_SA_RESTART) + act1.sa_flags |= SA_RESTART; + /* NOTE: it is important to update the host kernel signal + ignore state to avoid getting unexpected interrupted + syscalls */ + if (k->sa._sa_handler == TARGET_SIG_IGN) { + act1.sa_sigaction = (void *)SIG_IGN; + } else if (k->sa._sa_handler == TARGET_SIG_DFL) { + act1.sa_sigaction = (void *)SIG_DFL; + } else { + act1.sa_sigaction = host_signal_handler; + } + sigaction(host_sig, &act1, NULL); + } } return 0; } -- cgit v1.2.3 From 65262d57382c228ed62b90a94a0968eb0167bb2d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:20:53 +0000 Subject: added PE to static CPU state (avoids flushing translated code when swiching between protected and real mode) - moved memory defs to cpu-all.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@504 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 07e48c0c2..6be987c51 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -106,6 +106,11 @@ #define HF_SS32_SHIFT 5 /* zero base for DS, ES and SS */ #define HF_ADDSEG_SHIFT 6 +/* copy of CR0.PE (protected mode) */ +#define HF_PE_SHIFT 7 +#define HF_TF_SHIFT 8 /* must be same as eflags */ +#define HF_IOPL_SHIFT 12 /* must be same as eflags */ +#define HF_VM_SHIFT 17 /* must be same as eflags */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) @@ -113,6 +118,7 @@ #define HF_CS32_MASK (1 << HF_CS32_SHIFT) #define HF_SS32_MASK (1 << HF_SS32_SHIFT) #define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) +#define HF_PE_MASK (1 << HF_PE_SHIFT) #define CR0_PE_MASK (1 << 0) #define CR0_TS_MASK (1 << 3) @@ -391,9 +397,6 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, /* MMU defines */ void cpu_x86_init_mmu(CPUX86State *env); -extern int phys_ram_size; -extern int phys_ram_fd; -extern uint8_t *phys_ram_base; extern int a20_enabled; void cpu_x86_set_a20(CPUX86State *env, int a20_state); -- cgit v1.2.3 From dc6f57fd55d03546197dc0ea96b743fffe7b8f75 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:24:35 +0000 Subject: debug updates - page_unprotect() is no longer needed in softmmu case git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@505 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index c660980ca..071169827 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -281,6 +281,10 @@ static void switch_tss(int tss_selector, uint8_t *ptr; type = (e2 >> DESC_TYPE_SHIFT) & 0xf; +#ifdef DEBUG_PCALL + if (loglevel) + fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source); +#endif /* if task gate, we read the TSS segment and we load it */ if (type == 5) { @@ -848,24 +852,40 @@ void do_interrupt(int intno, int is_int, int error_code, { extern FILE *stdout; static int count; - if (env->cr[0] & CR0_PE_MASK) { - fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", - count, intno, error_code, is_int); + if ((env->cr[0] && CR0_PE_MASK)) { + fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x EAX=%08x\n", + count, intno, error_code, is_int, + env->hflags & HF_CPL_MASK, + env->segs[R_CS].selector, EIP, + env->segs[R_SS].selector, ESP, + EAX); + if (0) { + cpu_x86_dump_state(env, stdout, X86_DUMP_CCOP); +#if 0 + { + int i; + uint8_t *ptr; + fprintf(stdout, " code="); + ptr = env->segs[R_CS].base + env->eip; + for(i = 0; i < 16; i++) { + fprintf(stdout, " %02x", ldub(ptr + i)); + } + fprintf(stdout, "\n"); + } +#endif + } count++; } } - if ((env->cr[0] & CR0_PE_MASK) && intno == 0x10) { - tb_flush(env); - cpu_set_log(CPU_LOG_ALL); - } #endif + #ifdef DEBUG_PCALL if (loglevel) { static int count; fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", count, intno, error_code, is_int); cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); -#if 1 +#if 0 { int i; uint8_t *ptr; @@ -2431,10 +2451,6 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; - if (is_write && page_unprotect(addr)) { - /* nothing more to do: the page was write protected because - there was code in it. page_unprotect() flushed the code. */ - } ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1); if (ret) { -- cgit v1.2.3 From 436d8b892a84eed2144030a8a07affb94b5f15d7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:26:31 +0000 Subject: correct value for ADDSEG is real mode (fixes GRUB boot) - update static protected mode state - use generic tlb_set_page() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@506 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 91 ++++++++------------------------------------------- 1 file changed, 14 insertions(+), 77 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 51ffb7f96..fcceb1de5 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -181,14 +181,9 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) /* called when cr3 or PG bit are modified */ static int last_pg_state = -1; -static int last_pe_state = 0; static uint32_t a20_mask; int a20_enabled; -int phys_ram_size; -int phys_ram_fd; -uint8_t *phys_ram_base; - void cpu_x86_set_a20(CPUX86State *env, int a20_state) { a20_state = (a20_state != 0); @@ -223,11 +218,11 @@ void cpu_x86_update_cr0(CPUX86State *env) tlb_flush(env); last_pg_state = pg_state; } - pe_state = env->cr[0] & CR0_PE_MASK; - if (last_pe_state != pe_state) { - tb_flush(env); - last_pe_state = pe_state; - } + /* update PE flag in hidden flags */ + pe_state = (env->cr[0] & CR0_PE_MASK); + env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); + /* ensure that ADDSEG is always set in real mode */ + env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT); } void cpu_x86_update_cr3(CPUX86State *env) @@ -267,9 +262,9 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, uint8_t *pde_ptr, *pte_ptr; uint32_t pde, pte, virt_addr; int error_code, is_dirty, prot, page_size, ret; - unsigned long pd; + unsigned long paddr, vaddr, page_offset; -#ifdef DEBUG_MMU +#if defined(DEBUG_MMU) printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", addr, is_write, is_user, env->eip); #endif @@ -366,72 +361,14 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, do_mapping: pte = pte & a20_mask; -#if !defined(CONFIG_SOFTMMU) - if (is_softmmu) -#endif - { - unsigned long paddr, vaddr, address, addend, page_offset; - int index; - /* software MMU case. Even if 4MB pages, we map only one 4KB - page in the cache to avoid filling it too fast */ - page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); - paddr = (pte & TARGET_PAGE_MASK) + page_offset; - vaddr = virt_addr + page_offset; - index = (addr >> 12) & (CPU_TLB_SIZE - 1); - pd = physpage_find(paddr); - if (pd & 0xfff) { - /* IO memory case */ - address = vaddr | pd; - addend = paddr; - } else { - /* standard memory */ - address = vaddr; - addend = (unsigned long)phys_ram_base + pd; - } - addend -= vaddr; - env->tlb_read[is_user][index].address = address; - env->tlb_read[is_user][index].addend = addend; - if (prot & PROT_WRITE) { - env->tlb_write[is_user][index].address = address; - env->tlb_write[is_user][index].addend = addend; - } else { - env->tlb_write[is_user][index].address = -1; - env->tlb_write[is_user][index].addend = -1; - } - page_set_flags(vaddr, vaddr + TARGET_PAGE_SIZE, - PAGE_VALID | PAGE_EXEC | prot); - ret = 0; - } -#if !defined(CONFIG_SOFTMMU) - else { - ret = 0; - /* XXX: incorrect for 4MB pages */ - pd = physpage_find(pte & ~0xfff); - if ((pd & 0xfff) != 0) { - /* IO access: no mapping is done as it will be handled by the - soft MMU */ - if (!(env->hflags & HF_SOFTMMU_MASK)) - ret = 2; - } else { - void *map_addr; - map_addr = mmap((void *)virt_addr, page_size, prot, - MAP_SHARED | MAP_FIXED, phys_ram_fd, pd); - if (map_addr == MAP_FAILED) { - fprintf(stderr, - "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", - pte & ~0xfff, virt_addr); - exit(1); - } -#ifdef DEBUG_MMU - printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", - pte & ~0xfff, virt_addr, (page_size != 4096)); -#endif - page_set_flags(virt_addr, virt_addr + page_size, - PAGE_VALID | PAGE_EXEC | prot); - } - } -#endif + /* Even if 4MB pages, we map only one 4KB page in the cache to + avoid filling it too fast */ + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); + paddr = (pte & TARGET_PAGE_MASK) + page_offset; + vaddr = virt_addr + page_offset; + + ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; do_fault_protect: error_code = PG_ERROR_P_MASK; -- cgit v1.2.3 From f68dd770075ca35630f8070ddbcef50ceb3b5a27 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:27:42 +0000 Subject: fixed word bit operations with memory offset - suppressed push/pop micro operations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@507 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 94 +++++++++----------------------------------------------- 1 file changed, 14 insertions(+), 80 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index 63e34cf01..34fc4c734 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -17,6 +17,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* XXX: must use this define because the soft mmu macros have huge + register constraints so they cannot be used in any C code */ +#define ASM_SOFTMMU #include "exec.h" /* n must be a constant to be efficient */ @@ -392,10 +396,10 @@ void OPPROTO op_andl_A0_ffff(void) #include "ops_mem.h" #if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user +#define MEMSUFFIX _kernel #include "ops_mem.h" -#define MEMSUFFIX _kernel +#define MEMSUFFIX _user #include "ops_mem.h" #endif @@ -403,7 +407,7 @@ void OPPROTO op_andl_A0_ffff(void) void OPPROTO op_add_bitw_A0_T1(void) { - A0 += ((int32_t)T1 >> 4) << 1; + A0 += ((int16_t)T1 >> 4) << 1; } void OPPROTO op_add_bitl_A0_T1(void) @@ -635,91 +639,21 @@ void OPPROTO op_decw_ECX(void) ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff); } -/* push/pop */ - -void op_pushl_T0(void) -{ - uint32_t offset; - offset = ESP - 4; - stl((void *)offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = offset; -} - -void op_pushw_T0(void) -{ - uint32_t offset; - offset = ESP - 2; - stw((void *)offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = offset; -} - -void op_pushl_ss32_T0(void) -{ - uint32_t offset; - offset = ESP - 4; - stl(env->segs[R_SS].base + offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = offset; -} - -void op_pushw_ss32_T0(void) -{ - uint32_t offset; - offset = ESP - 2; - stw(env->segs[R_SS].base + offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = offset; -} - -void op_pushl_ss16_T0(void) -{ - uint32_t offset; - offset = (ESP - 4) & 0xffff; - stl(env->segs[R_SS].base + offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = (ESP & ~0xffff) | offset; -} - -void op_pushw_ss16_T0(void) -{ - uint32_t offset; - offset = (ESP - 2) & 0xffff; - stw(env->segs[R_SS].base + offset, T0); - /* modify ESP after to handle exceptions correctly */ - ESP = (ESP & ~0xffff) | offset; -} - -/* NOTE: ESP update is done after */ -void op_popl_T0(void) -{ - T0 = ldl((void *)ESP); -} - -void op_popw_T0(void) -{ - T0 = lduw((void *)ESP); -} - -void op_popl_ss32_T0(void) -{ - T0 = ldl(env->segs[R_SS].base + ESP); -} +/* push/pop utils */ -void op_popw_ss32_T0(void) +void op_addl_A0_SS(void) { - T0 = lduw(env->segs[R_SS].base + ESP); + A0 += (long)env->segs[R_SS].base; } -void op_popl_ss16_T0(void) +void op_subl_A0_2(void) { - T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff)); + A0 -= 2; } -void op_popw_ss16_T0(void) +void op_subl_A0_4(void) { - T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff)); + A0 -= 4; } void op_addl_ESP_4(void) -- cgit v1.2.3 From 7f1135b9a40ae7b3ae5a65d5a5553a60f714e44f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:28:06 +0000 Subject: added stx_T1_A0 micro ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@508 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_mem.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h index e1c8277bb..6a2ad41ee 100644 --- a/target-i386/ops_mem.h +++ b/target-i386/ops_mem.h @@ -63,4 +63,21 @@ void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void) glue(stl, MEMSUFFIX)((uint8_t *)A0, T0); } +#if 0 +void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T1_A0)(void) +{ + glue(stb, MEMSUFFIX)((uint8_t *)A0, T1); +} +#endif + +void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T1_A0)(void) +{ + glue(stw, MEMSUFFIX)((uint8_t *)A0, T1); +} + +void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T1_A0)(void) +{ + glue(stl, MEMSUFFIX)((uint8_t *)A0, T1); +} + #undef MEMSUFFIX -- cgit v1.2.3 From 34e01bbf0785bc1a203685d3ad9c328855238335 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:30:14 +0000 Subject: fixed dx based protected in/outs (win98 install) - changed JUMP_TB2 branch number arg git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@509 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_template.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index a486d2081..4ea94e4a7 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -458,9 +458,17 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) #undef MEM_WRITE #include "ops_template_mem.h" -#define MEM_WRITE +#define MEM_WRITE 0 #include "ops_template_mem.h" +#if !defined(CONFIG_USER_ONLY) +#define MEM_WRITE 1 +#include "ops_template_mem.h" + +#define MEM_WRITE 2 +#include "ops_template_mem.h" +#endif + /* bit operations */ #if DATA_BITS >= 16 @@ -550,14 +558,14 @@ void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST == 0) - JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 1); + JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 3); FORCE_RET(); } void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST != 0) - JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1); + JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 3); FORCE_RET(); } @@ -613,12 +621,12 @@ void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void) void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) { - glue(cpu_x86_out, SUFFIX)(env, T0 & 0xffff, T1 & DATA_MASK); + glue(cpu_x86_out, SUFFIX)(env, T0, T1 & DATA_MASK); } void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) { - T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff); + T1 = glue(cpu_x86_in, SUFFIX)(env, T0); } void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void) -- cgit v1.2.3 From 943144d91af00c0ece95e1b2e64d8eed4d2c38ec Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:31:11 +0000 Subject: added raw/user/kernel memory accesses (faster emulation) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@510 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_template_mem.h | 74 +++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h index eacaabba5..1b83536c9 100644 --- a/target-i386/ops_template_mem.h +++ b/target-i386/ops_template_mem.h @@ -20,12 +20,40 @@ */ #ifdef MEM_WRITE +#if MEM_WRITE == 0 + +#if DATA_BITS == 8 +#define MEM_SUFFIX b_raw +#elif DATA_BITS == 16 +#define MEM_SUFFIX w_raw +#elif DATA_BITS == 32 +#define MEM_SUFFIX l_raw +#endif + +#elif MEM_WRITE == 1 + +#if DATA_BITS == 8 +#define MEM_SUFFIX b_kernel +#elif DATA_BITS == 16 +#define MEM_SUFFIX w_kernel +#elif DATA_BITS == 32 +#define MEM_SUFFIX l_kernel +#endif + +#elif MEM_WRITE == 2 + #if DATA_BITS == 8 -#define MEM_SUFFIX b_mem +#define MEM_SUFFIX b_user #elif DATA_BITS == 16 -#define MEM_SUFFIX w_mem +#define MEM_SUFFIX w_user #elif DATA_BITS == 32 -#define MEM_SUFFIX l_mem +#define MEM_SUFFIX l_user +#endif + +#else + +#error invalid MEM_WRITE + #endif #else @@ -43,7 +71,7 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) T0 &= DATA_MASK; T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #else /* gcc 3.2 workaround. This is really a bug in gcc. */ asm volatile("" : : "r" (T0)); @@ -65,7 +93,7 @@ void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) T0 &= DATA_MASK; T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #else /* gcc 3.2 workaround. This is really a bug in gcc. */ asm volatile("" : : "r" (T0)); @@ -86,7 +114,7 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void) T0 &= DATA_MASK; T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif } FORCE_RET(); @@ -100,7 +128,7 @@ void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) T0 &= DATA_MASK; T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif } FORCE_RET(); @@ -126,7 +154,7 @@ void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) res |= T0 >> (DATA_BITS + 1 - count); T0 = res; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = (eflags & ~(CC_C | CC_O)) | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | @@ -156,7 +184,7 @@ void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) res |= T0 << (DATA_BITS + 1 - count); T0 = res; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = (eflags & ~(CC_C | CC_O)) | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | @@ -174,7 +202,7 @@ void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) src = (DATA_TYPE)T0 << (count - 1); T0 = T0 << count; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = src; CC_DST = T0; @@ -192,7 +220,7 @@ void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) src = T0 >> (count - 1); T0 = T0 >> count; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = src; CC_DST = T0; @@ -210,7 +238,7 @@ void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void) T0 = src >> count; src = src >> (count - 1); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = src; CC_DST = T0; @@ -234,7 +262,7 @@ void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) res |= T1 << (count - 16); T0 = res >> 16; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -254,7 +282,7 @@ void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) res |= T1 << (count - 16); T0 = res >> 16; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -276,7 +304,7 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) res |= T1 << (32 - count); T0 = res; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -297,7 +325,7 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) res |= T1 << (32 - count); T0 = res; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -317,7 +345,7 @@ void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) tmp = T0 << (count - 1); T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -333,7 +361,7 @@ void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) tmp = T0 << (count - 1); T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -351,7 +379,7 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) tmp = T0 >> (count - 1); T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -368,7 +396,7 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) tmp = T0 >> (count - 1); T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -386,7 +414,7 @@ void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) cf = cc_table[CC_OP].compute_c(); T0 = T0 + T1 + cf; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = T1; CC_DST = T0; @@ -399,7 +427,7 @@ void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) cf = cc_table[CC_OP].compute_c(); T0 = T0 - T1 - cf; #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = T1; CC_DST = T0; @@ -418,7 +446,7 @@ void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); } #ifdef MEM_WRITE - glue(st, SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); #endif CC_SRC = src; CC_DST = dst; -- cgit v1.2.3 From 4f31916ffbb196ac1a68ecd53703167a70880022 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:35:00 +0000 Subject: added raw/user/kernel memory accesses for shifts/adc/sbb/cmpxchg/push/pop (faster emulation) - make 'call Ev' exception safe - in/out dx fix - PE flag is static git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@511 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 614 +++++++++++++++++++++++------------------------- 1 file changed, 295 insertions(+), 319 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 87b6711bc..725ee5ba8 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -380,34 +380,30 @@ static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { NULL, }; -static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { - [OT_BYTE] = { - gen_op_adcb_T0_T1_cc, - gen_op_sbbb_T0_T1_cc, - }, - [OT_WORD] = { - gen_op_adcw_T0_T1_cc, - gen_op_sbbw_T0_T1_cc, - }, - [OT_LONG] = { - gen_op_adcl_T0_T1_cc, - gen_op_sbbl_T0_T1_cc, +#define DEF_ARITHC(SUFFIX)\ + {\ + gen_op_adcb ## SUFFIX ## _T0_T1_cc,\ + gen_op_sbbb ## SUFFIX ## _T0_T1_cc,\ + },\ + {\ + gen_op_adcw ## SUFFIX ## _T0_T1_cc,\ + gen_op_sbbw ## SUFFIX ## _T0_T1_cc,\ + },\ + {\ + gen_op_adcl ## SUFFIX ## _T0_T1_cc,\ + gen_op_sbbl ## SUFFIX ## _T0_T1_cc,\ }, + +static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { + DEF_ARITHC() }; -static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = { - [OT_BYTE] = { - gen_op_adcb_mem_T0_T1_cc, - gen_op_sbbb_mem_T0_T1_cc, - }, - [OT_WORD] = { - gen_op_adcw_mem_T0_T1_cc, - gen_op_sbbw_mem_T0_T1_cc, - }, - [OT_LONG] = { - gen_op_adcl_mem_T0_T1_cc, - gen_op_sbbl_mem_T0_T1_cc, - }, +static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[9][2] = { + DEF_ARITHC(_raw) +#ifndef CONFIG_USER_ONLY + DEF_ARITHC(_kernel) + DEF_ARITHC(_user) +#endif }; static const int cc_op_arithb[8] = { @@ -421,126 +417,105 @@ static const int cc_op_arithb[8] = { CC_OP_SUBB, }; +#define DEF_CMPXCHG(SUFFIX)\ + gen_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc,\ + gen_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc,\ + gen_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc, + + static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { - gen_op_cmpxchgb_T0_T1_EAX_cc, - gen_op_cmpxchgw_T0_T1_EAX_cc, - gen_op_cmpxchgl_T0_T1_EAX_cc, + DEF_CMPXCHG() }; -static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = { - gen_op_cmpxchgb_mem_T0_T1_EAX_cc, - gen_op_cmpxchgw_mem_T0_T1_EAX_cc, - gen_op_cmpxchgl_mem_T0_T1_EAX_cc, +static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = { + DEF_CMPXCHG(_raw) +#ifndef CONFIG_USER_ONLY + DEF_CMPXCHG(_kernel) + DEF_CMPXCHG(_user) +#endif }; -static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { - [OT_BYTE] = { - gen_op_rolb_T0_T1_cc, - gen_op_rorb_T0_T1_cc, - gen_op_rclb_T0_T1_cc, - gen_op_rcrb_T0_T1_cc, - gen_op_shlb_T0_T1_cc, - gen_op_shrb_T0_T1_cc, - gen_op_shlb_T0_T1_cc, - gen_op_sarb_T0_T1_cc, - }, - [OT_WORD] = { - gen_op_rolw_T0_T1_cc, - gen_op_rorw_T0_T1_cc, - gen_op_rclw_T0_T1_cc, - gen_op_rcrw_T0_T1_cc, - gen_op_shlw_T0_T1_cc, - gen_op_shrw_T0_T1_cc, - gen_op_shlw_T0_T1_cc, - gen_op_sarw_T0_T1_cc, - }, - [OT_LONG] = { - gen_op_roll_T0_T1_cc, - gen_op_rorl_T0_T1_cc, - gen_op_rcll_T0_T1_cc, - gen_op_rcrl_T0_T1_cc, - gen_op_shll_T0_T1_cc, - gen_op_shrl_T0_T1_cc, - gen_op_shll_T0_T1_cc, - gen_op_sarl_T0_T1_cc, +#define DEF_SHIFT(SUFFIX)\ + {\ + gen_op_rolb ## SUFFIX ## _T0_T1_cc,\ + gen_op_rorb ## SUFFIX ## _T0_T1_cc,\ + gen_op_rclb ## SUFFIX ## _T0_T1_cc,\ + gen_op_rcrb ## SUFFIX ## _T0_T1_cc,\ + gen_op_shlb ## SUFFIX ## _T0_T1_cc,\ + gen_op_shrb ## SUFFIX ## _T0_T1_cc,\ + gen_op_shlb ## SUFFIX ## _T0_T1_cc,\ + gen_op_sarb ## SUFFIX ## _T0_T1_cc,\ + },\ + {\ + gen_op_rolw ## SUFFIX ## _T0_T1_cc,\ + gen_op_rorw ## SUFFIX ## _T0_T1_cc,\ + gen_op_rclw ## SUFFIX ## _T0_T1_cc,\ + gen_op_rcrw ## SUFFIX ## _T0_T1_cc,\ + gen_op_shlw ## SUFFIX ## _T0_T1_cc,\ + gen_op_shrw ## SUFFIX ## _T0_T1_cc,\ + gen_op_shlw ## SUFFIX ## _T0_T1_cc,\ + gen_op_sarw ## SUFFIX ## _T0_T1_cc,\ + },\ + {\ + gen_op_roll ## SUFFIX ## _T0_T1_cc,\ + gen_op_rorl ## SUFFIX ## _T0_T1_cc,\ + gen_op_rcll ## SUFFIX ## _T0_T1_cc,\ + gen_op_rcrl ## SUFFIX ## _T0_T1_cc,\ + gen_op_shll ## SUFFIX ## _T0_T1_cc,\ + gen_op_shrl ## SUFFIX ## _T0_T1_cc,\ + gen_op_shll ## SUFFIX ## _T0_T1_cc,\ + gen_op_sarl ## SUFFIX ## _T0_T1_cc,\ }, + +static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { + DEF_SHIFT() }; -static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = { - [OT_BYTE] = { - gen_op_rolb_mem_T0_T1_cc, - gen_op_rorb_mem_T0_T1_cc, - gen_op_rclb_mem_T0_T1_cc, - gen_op_rcrb_mem_T0_T1_cc, - gen_op_shlb_mem_T0_T1_cc, - gen_op_shrb_mem_T0_T1_cc, - gen_op_shlb_mem_T0_T1_cc, - gen_op_sarb_mem_T0_T1_cc, - }, - [OT_WORD] = { - gen_op_rolw_mem_T0_T1_cc, - gen_op_rorw_mem_T0_T1_cc, - gen_op_rclw_mem_T0_T1_cc, - gen_op_rcrw_mem_T0_T1_cc, - gen_op_shlw_mem_T0_T1_cc, - gen_op_shrw_mem_T0_T1_cc, - gen_op_shlw_mem_T0_T1_cc, - gen_op_sarw_mem_T0_T1_cc, - }, - [OT_LONG] = { - gen_op_roll_mem_T0_T1_cc, - gen_op_rorl_mem_T0_T1_cc, - gen_op_rcll_mem_T0_T1_cc, - gen_op_rcrl_mem_T0_T1_cc, - gen_op_shll_mem_T0_T1_cc, - gen_op_shrl_mem_T0_T1_cc, - gen_op_shll_mem_T0_T1_cc, - gen_op_sarl_mem_T0_T1_cc, - }, +static GenOpFunc *gen_op_shift_mem_T0_T1_cc[9][8] = { + DEF_SHIFT(_raw) +#ifndef CONFIG_USER_ONLY + DEF_SHIFT(_kernel) + DEF_SHIFT(_user) +#endif }; -static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = { - [0] = { - gen_op_shldw_T0_T1_im_cc, - gen_op_shrdw_T0_T1_im_cc, - }, - [1] = { - gen_op_shldl_T0_T1_im_cc, - gen_op_shrdl_T0_T1_im_cc, +#define DEF_SHIFTD(SUFFIX, op)\ + {\ + NULL,\ + NULL,\ + },\ + {\ + gen_op_shldw ## SUFFIX ## _T0_T1_ ## op ## _cc,\ + gen_op_shrdw ## SUFFIX ## _T0_T1_ ## op ## _cc,\ + },\ + {\ + gen_op_shldl ## SUFFIX ## _T0_T1_ ## op ## _cc,\ + gen_op_shrdl ## SUFFIX ## _T0_T1_ ## op ## _cc,\ }, + + +static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[3][2] = { + DEF_SHIFTD(, im) }; -static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = { - [0] = { - gen_op_shldw_T0_T1_ECX_cc, - gen_op_shrdw_T0_T1_ECX_cc, - }, - [1] = { - gen_op_shldl_T0_T1_ECX_cc, - gen_op_shrdl_T0_T1_ECX_cc, - }, +static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[3][2] = { + DEF_SHIFTD(, ECX) }; -static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = { - [0] = { - gen_op_shldw_mem_T0_T1_im_cc, - gen_op_shrdw_mem_T0_T1_im_cc, - }, - [1] = { - gen_op_shldl_mem_T0_T1_im_cc, - gen_op_shrdl_mem_T0_T1_im_cc, - }, +static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[9][2] = { + DEF_SHIFTD(_raw, im) +#ifndef CONFIG_USER_ONLY + DEF_SHIFTD(_kernel, im) + DEF_SHIFTD(_user, im) +#endif }; -static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = { - [0] = { - gen_op_shldw_mem_T0_T1_ECX_cc, - gen_op_shrdw_mem_T0_T1_ECX_cc, - }, - [1] = { - gen_op_shldl_mem_T0_T1_ECX_cc, - gen_op_shrdl_mem_T0_T1_ECX_cc, - }, +static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[9][2] = { + DEF_SHIFTD(_raw, ECX) +#ifndef CONFIG_USER_ONLY + DEF_SHIFTD(_kernel, ECX) + DEF_SHIFTD(_user, ECX) +#endif }; static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { @@ -649,6 +624,22 @@ static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { #endif }; +static GenOpFunc *gen_op_st_T1_A0[3 * 3] = { + NULL, + gen_op_stw_raw_T1_A0, + gen_op_stl_raw_T1_A0, + +#ifndef CONFIG_USER_ONLY + NULL, + gen_op_stw_kernel_T1_A0, + gen_op_stl_kernel_T1_A0, + + NULL, + gen_op_stw_user_T1_A0, + gen_op_stl_user_T1_A0, +#endif +}; + static inline void gen_string_movl_A0_ESI(DisasContext *s) { int override; @@ -1093,7 +1084,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); gen_op_mov_reg_T0[ot][d](); } else { - gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL](); + gen_op_arithc_mem_T0_T1_cc[ot + s1->mem_index][op - OP_ADCL](); } s1->cc_op = CC_OP_DYNAMIC; goto the_end; @@ -1172,7 +1163,7 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) if (d != OR_TMP0) gen_op_shift_T0_T1_cc[ot][op](); else - gen_op_shift_mem_T0_T1_cc[ot][op](); + gen_op_shift_mem_T0_T1_cc[ot + s1->mem_index][op](); if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ @@ -1555,69 +1546,87 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) s->is_jmp = 3; } +static inline void gen_stack_update(DisasContext *s, int addend) +{ + if (s->ss32) { + if (addend == 2) + gen_op_addl_ESP_2(); + else if (addend == 4) + gen_op_addl_ESP_4(); + else + gen_op_addl_ESP_im(addend); + } else { + if (addend == 2) + gen_op_addw_ESP_2(); + else if (addend == 4) + gen_op_addw_ESP_4(); + else + gen_op_addw_ESP_im(addend); + } +} + /* generate a push. It depends on ss32, addseg and dflag */ static void gen_push_T0(DisasContext *s) { + gen_op_movl_A0_reg[R_ESP](); + if (!s->dflag) + gen_op_subl_A0_2(); + else + gen_op_subl_A0_4(); if (s->ss32) { - if (!s->addseg) { - if (s->dflag) - gen_op_pushl_T0(); - else - gen_op_pushw_T0(); - } else { - if (s->dflag) - gen_op_pushl_ss32_T0(); - else - gen_op_pushw_ss32_T0(); + if (s->addseg) { + gen_op_movl_T1_A0(); + gen_op_addl_A0_SS(); } } else { - if (s->dflag) - gen_op_pushl_ss16_T0(); - else - gen_op_pushw_ss16_T0(); + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + gen_op_addl_A0_SS(); } + gen_op_st_T0_A0[s->dflag + 1 + s->mem_index](); + if (s->ss32 && !s->addseg) + gen_op_movl_ESP_A0(); + else + gen_op_mov_reg_T1[s->ss32 + 1][R_ESP](); } -/* two step pop is necessary for precise exceptions */ -static void gen_pop_T0(DisasContext *s) +/* generate a push. It depends on ss32, addseg and dflag */ +/* slower version for T1, only used for call Ev */ +static void gen_push_T1(DisasContext *s) { + gen_op_movl_A0_reg[R_ESP](); + if (!s->dflag) + gen_op_subl_A0_2(); + else + gen_op_subl_A0_4(); if (s->ss32) { - if (!s->addseg) { - if (s->dflag) - gen_op_popl_T0(); - else - gen_op_popw_T0(); - } else { - if (s->dflag) - gen_op_popl_ss32_T0(); - else - gen_op_popw_ss32_T0(); + if (s->addseg) { + gen_op_addl_A0_SS(); } } else { - if (s->dflag) - gen_op_popl_ss16_T0(); - else - gen_op_popw_ss16_T0(); + gen_op_andl_A0_ffff(); + gen_op_addl_A0_SS(); } + gen_op_st_T1_A0[s->dflag + 1 + s->mem_index](); + + if (s->ss32 && !s->addseg) + gen_op_movl_ESP_A0(); + else + gen_stack_update(s, (-2) << s->dflag); } -static inline void gen_stack_update(DisasContext *s, int addend) +/* two step pop is necessary for precise exceptions */ +static void gen_pop_T0(DisasContext *s) { + gen_op_movl_A0_reg[R_ESP](); if (s->ss32) { - if (addend == 2) - gen_op_addl_ESP_2(); - else if (addend == 4) - gen_op_addl_ESP_4(); - else - gen_op_addl_ESP_im(addend); + if (s->addseg) + gen_op_addl_A0_SS(); } else { - if (addend == 2) - gen_op_addw_ESP_2(); - else if (addend == 4) - gen_op_addw_ESP_4(); - else - gen_op_addw_ESP_im(addend); + gen_op_andl_A0_ffff(); + gen_op_addl_A0_SS(); } + gen_op_ld_T0_A0[s->dflag + 1 + s->mem_index](); } static void gen_pop_update(DisasContext *s) @@ -1704,9 +1713,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_st_T0_A0[ot + s->mem_index](); } gen_op_addl_A0_im(-opsize); - /* XXX: add st_T1_A0 ? */ - gen_op_movl_T0_T1(); - gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_st_T1_A0[ot + s->mem_index](); } gen_op_mov_reg_T1[ot][R_EBP](); addend = -esp_addend; @@ -2122,13 +2129,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_inc(s, ot, opreg, -1); break; case 2: /* call Ev */ - /* XXX: optimize if memory (no and is necessary) */ + /* XXX: optimize if memory (no 'and' is necessary) */ if (s->dflag == 0) gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); next_eip = s->pc - s->cs_base; - gen_op_movl_T0_im(next_eip); - gen_push_T0(s); + gen_op_movl_T1_im(next_eip); + gen_push_T1(s); + gen_op_jmp_T0(); gen_eob(s); break; case 3: /* lcall Ev */ @@ -2291,7 +2298,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); + gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot + s->mem_index](); } s->cc_op = CC_OP_SUBB + ot; break; @@ -2776,9 +2783,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) val &= 0x1f; if (val) { if (mod == 3) - gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); + gen_op_shiftd_T0_T1_im_cc[ot][op](val); else - gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val); + gen_op_shiftd_mem_T0_T1_im_cc[ot + s->mem_index][op](val); if (op == 0 && ot != OT_WORD) s->cc_op = CC_OP_SHLB + ot; else @@ -2788,9 +2795,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); if (mod == 3) - gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); + gen_op_shiftd_T0_T1_ECX_cc[ot][op](); else - gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op](); + gen_op_shiftd_mem_T0_T1_ECX_cc[ot + s->mem_index][op](); s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } if (mod == 3) { @@ -3347,6 +3354,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_andl_T0_ffff(); gen_check_io(s, ot, 0, pc_start - s->cs_base); gen_op_in[ot](); gen_op_mov_reg_T1[ot][R_EAX](); @@ -3358,6 +3366,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) else ot = dflag ? OT_LONG : OT_WORD; gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_andl_T0_ffff(); gen_check_io(s, ot, 0, pc_start - s->cs_base); gen_op_mov_TN_reg[ot][1][R_EAX](); gen_op_out[ot](); @@ -4148,20 +4157,6 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_das] = CC_A | CC_C, [INDEX_op_daa] = CC_A | CC_C, - [INDEX_op_adcb_T0_T1_cc] = CC_C, - [INDEX_op_adcw_T0_T1_cc] = CC_C, - [INDEX_op_adcl_T0_T1_cc] = CC_C, - [INDEX_op_sbbb_T0_T1_cc] = CC_C, - [INDEX_op_sbbw_T0_T1_cc] = CC_C, - [INDEX_op_sbbl_T0_T1_cc] = CC_C, - - [INDEX_op_adcb_mem_T0_T1_cc] = CC_C, - [INDEX_op_adcw_mem_T0_T1_cc] = CC_C, - [INDEX_op_adcl_mem_T0_T1_cc] = CC_C, - [INDEX_op_sbbb_mem_T0_T1_cc] = CC_C, - [INDEX_op_sbbw_mem_T0_T1_cc] = CC_C, - [INDEX_op_sbbl_mem_T0_T1_cc] = CC_C, - /* subtle: due to the incl/decl implementation, C is used */ [INDEX_op_update_inc_cc] = CC_C, @@ -4233,19 +4228,28 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_cmc] = CC_C, [INDEX_op_salc] = CC_C, - [INDEX_op_rclb_T0_T1_cc] = CC_C, - [INDEX_op_rclw_T0_T1_cc] = CC_C, - [INDEX_op_rcll_T0_T1_cc] = CC_C, - [INDEX_op_rcrb_T0_T1_cc] = CC_C, - [INDEX_op_rcrw_T0_T1_cc] = CC_C, - [INDEX_op_rcrl_T0_T1_cc] = CC_C, - - [INDEX_op_rclb_mem_T0_T1_cc] = CC_C, - [INDEX_op_rclw_mem_T0_T1_cc] = CC_C, - [INDEX_op_rcll_mem_T0_T1_cc] = CC_C, - [INDEX_op_rcrb_mem_T0_T1_cc] = CC_C, - [INDEX_op_rcrw_mem_T0_T1_cc] = CC_C, - [INDEX_op_rcrl_mem_T0_T1_cc] = CC_C, +#define DEF_READF(SUFFIX)\ + [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_C,\ +\ + [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_C,\ + [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C, + + + DEF_READF() + DEF_READF(_raw) +#ifndef CONFIG_USER_ONLY + DEF_READF(_kernel) + DEF_READF(_user) +#endif }; /* flags written by an operation */ @@ -4258,20 +4262,6 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_update_inc_cc] = CC_OSZAPC, [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_mulb_AL_T0] = CC_OSZAPC, [INDEX_op_imulb_AL_T0] = CC_OSZAPC, [INDEX_op_mulw_AX_T0] = CC_OSZAPC, @@ -4300,78 +4290,6 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_stc] = CC_C, [INDEX_op_cmc] = CC_C, - [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C, - - [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C, - - [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC, - - [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC, - - [INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C, - - [INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C, - [INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C, - - [INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC, - [INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC, - - [INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC, - - [INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC, - [INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC, - [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, @@ -4390,15 +4308,67 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC, - [INDEX_op_cmpxchg8b] = CC_Z, [INDEX_op_lar] = CC_Z, [INDEX_op_lsl] = CC_Z, [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, + +#define DEF_WRITEF(SUFFIX)\ + [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ +\ + [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ +\ + [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ +\ + [INDEX_op_shlb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_shlw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_shll ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ +\ + [INDEX_op_shrb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_shrw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_shrl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ +\ + [INDEX_op_sarb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_sarw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + [INDEX_op_sarl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ +\ + [INDEX_op_shldw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ + [INDEX_op_shldl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ + [INDEX_op_shldw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ + [INDEX_op_shldl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ +\ + [INDEX_op_shrdw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ + [INDEX_op_shrdl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ + [INDEX_op_shrdw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ + [INDEX_op_shrdl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ +\ + [INDEX_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\ + [INDEX_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\ + [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC, + + + DEF_WRITEF() + DEF_WRITEF(_raw) +#ifndef CONFIG_USER_ONLY + DEF_WRITEF(_kernel) + DEF_WRITEF(_user) +#endif }; /* simpler form of an operation if no flags need to be generated */ @@ -4410,21 +4380,6 @@ static uint16_t opc_simpler[NB_OPS] = { /* broken: CC_OP logic must be rewritten */ [INDEX_op_update_inc_cc] = INDEX_op_nop, #endif - [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1, - [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1, - [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1, - - [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1, - [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1, - [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1, - - [INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1, - [INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1, - [INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1, - - [INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1, - [INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1, - [INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1, [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, @@ -4437,6 +4392,22 @@ static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1, [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1, [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, + +#define DEF_SIMPLER(SUFFIX)\ + [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolb ## SUFFIX ## _T0_T1,\ + [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolw ## SUFFIX ## _T0_T1,\ + [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = INDEX_op_roll ## SUFFIX ## _T0_T1,\ +\ + [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorb ## SUFFIX ## _T0_T1,\ + [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorw ## SUFFIX ## _T0_T1,\ + [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorl ## SUFFIX ## _T0_T1, + + DEF_SIMPLER() + DEF_SIMPLER(_raw) +#ifndef CONFIG_USER_ONLY + DEF_SIMPLER(_kernel) + DEF_SIMPLER(_user) +#endif }; void optimize_flags_init(void) @@ -4495,7 +4466,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, cs_base = (uint8_t *)tb->cs_base; flags = tb->flags; - dc->pe = env->cr[0] & CR0_PE_MASK; + dc->pe = (flags >> HF_PE_SHIFT) & 1; dc->code32 = (flags >> HF_CS32_SHIFT) & 1; dc->ss32 = (flags >> HF_SS32_SHIFT) & 1; dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1; @@ -4523,6 +4494,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, || (flags & HF_SOFTMMU_MASK) #endif ); +#if 0 + /* check addseg logic */ + if (!dc->addseg && (dc->vm86 || !dc->pe)) + printf("ERROR addseg\n"); +#endif + gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; @@ -4589,7 +4566,6 @@ static inline int gen_intermediate_code_internal(CPUState *env, fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32); fprintf(logfile, "\n"); - fprintf(logfile, "OP:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); -- cgit v1.2.3 From 17348a7f5ed81bfd58cacdf911a75c558aa0fc8f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:36:11 +0000 Subject: waiting for TARGET_HAS_SMC patch git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@512 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b263d6535..4e9cc98e3 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -263,5 +263,5 @@ void do_dcbz (void) /* Instruction cache invalidation helper */ void do_icbi (void) { - tb_invalidate_page(T0); + // tb_invalidate_page(T0); } -- cgit v1.2.3 From 1376847f9f003a5a1c7f62a1425352d397348ba7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:43:01 +0000 Subject: support for new TLB handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@513 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 08ecea126..bd42d002b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -262,7 +262,42 @@ int cpu_exec(CPUState *env1) tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, flags); if (!tb) { + TranslationBlock **ptb1; + unsigned int h; + target_ulong phys_pc, phys_page1, phys_page2, virt_page2; + + spin_lock(&tb_lock); + + tb_invalidated_flag = 0; + + /* find translated block using physical mappings */ + phys_pc = get_phys_addr_code(env, (unsigned long)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 == (unsigned long)pc && + tb->page_addr[0] == phys_page1 && + tb->cs_base == (unsigned long)cs_base && + tb->flags == flags) { + /* check next page if needed */ + virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK; + if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) { + 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((unsigned long)pc); if (!tb) { @@ -278,8 +313,18 @@ int cpu_exec(CPUState *env1) tb->tc_ptr = tc_ptr; tb->cs_base = (unsigned long)cs_base; tb->flags = flags; - tb_invalidated_flag = 0; 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 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK; + phys_page2 = -1; + if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) { + phys_page2 = get_phys_addr_code(env, virt_page2); + } + tb_link_phys(tb, phys_pc, phys_page2); + + found: if (tb_invalidated_flag) { /* as some TB could have been invalidated because of memory exceptions while generating the code, we @@ -289,10 +334,10 @@ int cpu_exec(CPUState *env1) ptb = &(*ptb)->hash_next; T0 = 0; } + /* we add the TB in the virtual pc hash table */ *ptb = tb; tb->hash_next = NULL; tb_link(tb); - code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); spin_unlock(&tb_lock); } #ifdef DEBUG_EXEC -- cgit v1.2.3 From edf75d592cf7ec0ed8286f1900b0d1d567477c52 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:43:30 +0000 Subject: export more memory defines git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@514 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index f3922dc99..bbe7bb9a9 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -475,6 +475,20 @@ void cpu_set_log_filename(const char *filename); /* memory API */ +extern int phys_ram_size; +extern int phys_ram_fd; +extern uint8_t *phys_ram_base; + +/* physical memory access */ +#define IO_MEM_NB_ENTRIES 256 +#define TLB_INVALID_MASK (1 << 3) +#define IO_MEM_SHIFT 4 + +#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */ +#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ +#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) +#define IO_MEM_CODE (3 << IO_MEM_SHIFT) + typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(uint32_t addr); -- cgit v1.2.3 From 513b500f7565690e2d1b1cf9de2cf78993fc8a79 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:44:08 +0000 Subject: include stddef.h for size_t definition git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@515 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dyngen-exec.h b/dyngen-exec.h index 2b8ba3a3e..da23e0e6a 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -20,6 +20,8 @@ #if !defined(__DYNGEN_EXEC_H__) #define __DYNGEN_EXEC_H__ +#include + typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; @@ -56,6 +58,7 @@ typedef signed long long int64_t; typedef struct FILE FILE; extern int fprintf(FILE *, const char *, ...); extern int printf(const char *, ...); +#undef NULL #define NULL 0 #include -- cgit v1.2.3 From ecd854fdb47bfaae79b1196c5229efbaf8e673d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 17:45:05 +0000 Subject: added support for direct patching on i386 host (faster emulation) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@516 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dyngen.c b/dyngen.c index 58d22d975..390fc3a8a 100644 --- a/dyngen.c +++ b/dyngen.c @@ -729,6 +729,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_jmp", &p)) { + int n; + n = strtol(p, NULL, 10); + /* __op_jmp relocations are done at + runtime to do translated block + chaining: the offset of the instruction + needs to be stored */ + fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", + n, rel->r_offset - start_offset); + continue; + } + if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); } else { -- cgit v1.2.3 From 4390df510788b6e19cce96db48a94ab2e519e469 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:03:10 +0000 Subject: added support for direct patching on i386 host (faster emulation) - increased translation buffer size - added new TLB support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@517 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 120 insertions(+), 17 deletions(-) diff --git a/exec-all.h b/exec-all.h index de21774ee..f116533ed 100644 --- a/exec-all.h +++ b/exec-all.h @@ -28,6 +28,11 @@ #define tostring(s) #s #endif +#ifndef THUNK_H +/* horrible */ +typedef uint32_t target_ulong; +#endif + #if GCC_MAJOR < 3 #define __builtin_expect(x, n) (x) #endif @@ -77,10 +82,12 @@ int cpu_restore_state(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc); void cpu_exec_init(void); int page_unprotect(unsigned long address); -void tb_invalidate_page(unsigned long address); +void tb_invalidate_page_range(target_ulong start, target_ulong end); void tlb_flush_page(CPUState *env, uint32_t addr); void tlb_flush_page_write(CPUState *env, uint32_t addr); void tlb_flush(CPUState *env); +int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, + int is_user, int is_softmmu); #define CODE_GEN_MAX_SIZE 65536 #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ @@ -88,11 +95,47 @@ void tlb_flush(CPUState *env); #define CODE_GEN_HASH_BITS 15 #define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) +#define CODE_GEN_PHYS_HASH_BITS 15 +#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) + /* maximum total translate dcode allocated */ -#define CODE_GEN_BUFFER_SIZE (2048 * 1024) + +/* NOTE: the translated code area cannot be too big because on some + archs the range of "fast" function calls are limited. Here is a + summary of the ranges: + + i386 : signed 32 bits + arm : signed 26 bits + ppc : signed 24 bits + sparc : signed 32 bits + alpha : signed 23 bits +*/ + +#if defined(__alpha__) +#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024) +#elif defined(__powerpc__) +#define CODE_GEN_BUFFER_SIZE (6 * 1024) +#else +#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024) +#endif + //#define CODE_GEN_BUFFER_SIZE (128 * 1024) -#if defined(__powerpc__) +/* estimated block size for TB allocation */ +/* XXX: use a per code average code fragment size and modulate it + according to the host CPU */ +#if defined(CONFIG_SOFTMMU) +#define CODE_GEN_AVG_BLOCK_SIZE 128 +#else +#define CODE_GEN_AVG_BLOCK_SIZE 64 +#endif + +#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE) + +#if defined(__powerpc__) +#define USE_DIRECT_JUMP +#endif +#if defined(__i386__) #define USE_DIRECT_JUMP #endif @@ -103,8 +146,14 @@ typedef struct TranslationBlock { uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ uint8_t *tc_ptr; /* pointer to the translated code */ - struct TranslationBlock *hash_next; /* next matching block */ - struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */ + struct TranslationBlock *hash_next; /* next matching tb for virtual address */ + /* next matching tb for physical address. */ + struct TranslationBlock *phys_hash_next; + /* first and second physical page containing code. The lower bit + of the pointer tells the index in page_next[] */ + struct TranslationBlock *page_next[2]; + target_ulong page_addr[2]; + /* the following data are used to directly call another TB from the code of this one. */ uint16_t tb_next_offset[2]; /* offset of original jump target */ @@ -126,11 +175,19 @@ static inline unsigned int tb_hash_func(unsigned long pc) return pc & (CODE_GEN_HASH_SIZE - 1); } +static inline unsigned int tb_phys_hash_func(unsigned long pc) +{ + return pc & (CODE_GEN_PHYS_HASH_SIZE - 1); +} + TranslationBlock *tb_alloc(unsigned long pc); void tb_flush(CPUState *env); void tb_link(TranslationBlock *tb); +void tb_link_phys(TranslationBlock *tb, + target_ulong phys_pc, target_ulong phys_page2); extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; +extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; extern uint8_t *code_gen_ptr; @@ -159,8 +216,10 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, return NULL; } -#if defined(__powerpc__) +#if defined(USE_DIRECT_JUMP) + +#if defined(__powerpc__) static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { uint32_t val, *ptr; @@ -177,6 +236,14 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr asm volatile ("sync" : : : "memory"); asm volatile ("isync" : : : "memory"); } +#elif defined(__i386__) +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) +{ + /* patch the branch destination */ + *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); + /* no need to flush icache explicitely */ +} +#endif static inline void tb_set_jmp_target(TranslationBlock *tb, int n, unsigned long addr) @@ -223,7 +290,7 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); #if defined(__powerpc__) -/* on PowerPC we patch the jump instruction directly */ +/* we patch the jump instruction directly */ #define JUMP_TB(opname, tbparam, n, eip)\ do {\ asm volatile (".section \".data\"\n"\ @@ -239,7 +306,28 @@ do {\ #define JUMP_TB2(opname, tbparam, n)\ do {\ - asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\ + asm volatile ("b __op_jmp" #n "\n");\ +} while (0) + +#elif defined(__i386__) && defined(USE_DIRECT_JUMP) + +/* we patch the jump instruction directly */ +#define JUMP_TB(opname, tbparam, n, eip)\ +do {\ + asm volatile (".section \".data\"\n"\ + "__op_label" #n "." stringify(opname) ":\n"\ + ".long 1f\n"\ + ".previous\n"\ + "jmp __op_jmp" #n "\n"\ + "1:\n");\ + T0 = (long)(tbparam) + (n);\ + EIP = eip;\ + EXIT_TB();\ +} while (0) + +#define JUMP_TB2(opname, tbparam, n)\ +do {\ + asm volatile ("jmp __op_jmp" #n "\n");\ } while (0) #else @@ -261,19 +349,11 @@ dummy_label ## n:\ /* second jump to same destination 'n' */ #define JUMP_TB2(opname, tbparam, n)\ do {\ - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\ } while (0) #endif -/* physical memory access */ -#define IO_MEM_NB_ENTRIES 256 -#define TLB_INVALID_MASK (1 << 3) -#define IO_MEM_SHIFT 4 -#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT) - -unsigned long physpage_find(unsigned long page); - extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; @@ -441,3 +521,26 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, #undef env #endif + +#if defined(CONFIG_USER_ONLY) +static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) +{ + return addr; +} +#else +/* NOTE: this function can trigger an exception */ +/* XXX: i386 target specific */ +static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) +{ + int is_user, index; + + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + is_user = ((env->hflags & HF_CPL_MASK) == 3); + if (__builtin_expect(env->tlb_read[is_user][index].address != + (addr & TARGET_PAGE_MASK), 0)) { + ldub_code((void *)addr); + } + return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; +} +#endif + -- cgit v1.2.3 From 9fa3e8535317f24a921338a32f1eb18cd46fa22d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:06:42 +0000 Subject: new generic TLB support - faster self modifying code support - added ROM memory support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@518 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 1126 ++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 849 insertions(+), 277 deletions(-) diff --git a/exec.c b/exec.c index 2ef509dcf..a68771256 100644 --- a/exec.c +++ b/exec.c @@ -32,6 +32,7 @@ //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH +//#define DEBUG_TLB /* make various TB consistency checks */ //#define DEBUG_TB_CHECK @@ -39,10 +40,14 @@ /* threshold to flush the translated code buffer */ #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) -#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64) +#define SMC_BITMAP_USE_THRESHOLD 10 + +#define MMAP_AREA_START 0x00000000 +#define MMAP_AREA_END 0xa8000000 TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; +TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; int nb_tbs; /* any access to the tbs or the page table must use this lock */ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; @@ -50,12 +55,36 @@ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; uint8_t *code_gen_ptr; -/* XXX: pack the flags in the low bits of the pointer ? */ +int phys_ram_size; +int phys_ram_fd; +uint8_t *phys_ram_base; + typedef struct PageDesc { - unsigned long flags; + /* offset in memory of the page + io_index in the low 12 bits */ + unsigned long phys_offset; + /* list of TBs intersecting this physical page */ TranslationBlock *first_tb; + /* in order to optimize self modifying code, we count the number + of lookups we do to a given page to use a bitmap */ + unsigned int code_write_count; + uint8_t *code_bitmap; +#if defined(CONFIG_USER_ONLY) + unsigned long flags; +#endif } PageDesc; +typedef struct VirtPageDesc { + /* physical address of code page. It is valid only if 'valid_tag' + matches 'virt_valid_tag' */ + target_ulong phys_addr; + unsigned int valid_tag; +#if !defined(CONFIG_SOFTMMU) + /* original page access rights. It is valid only if 'valid_tag' + matches 'virt_valid_tag' */ + unsigned int prot; +#endif +} VirtPageDesc; + #define L2_BITS 10 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) @@ -71,8 +100,12 @@ unsigned long host_page_mask; static PageDesc *l1_map[L1_SIZE]; +#if !defined(CONFIG_USER_ONLY) +static VirtPageDesc *l1_virt_map[L1_SIZE]; +static unsigned int virt_valid_tag; +#endif + /* io memory support */ -static unsigned long *l1_physmap[L1_SIZE]; CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; static int io_mem_nb; @@ -95,49 +128,9 @@ static void page_init(void) while ((1 << host_page_bits) < host_page_size) host_page_bits++; host_page_mask = ~(host_page_size - 1); -} - -/* dump memory mappings */ -void page_dump(FILE *f) -{ - unsigned long start, end; - int i, j, prot, prot1; - PageDesc *p; - - fprintf(f, "%-8s %-8s %-8s %s\n", - "start", "end", "size", "prot"); - start = -1; - end = -1; - prot = 0; - for(i = 0; i <= L1_SIZE; i++) { - if (i < L1_SIZE) - p = l1_map[i]; - else - p = NULL; - for(j = 0;j < L2_SIZE; j++) { - if (!p) - prot1 = 0; - else - prot1 = p[j].flags; - if (prot1 != prot) { - end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); - if (start != -1) { - fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", - start, end, end - start, - prot & PAGE_READ ? 'r' : '-', - prot & PAGE_WRITE ? 'w' : '-', - prot & PAGE_EXEC ? 'x' : '-'); - } - if (prot1 != 0) - start = end; - else - start = -1; - prot = prot1; - } - if (!p) - break; - } - } +#if !defined(CONFIG_USER_ONLY) + virt_valid_tag = 1; +#endif } static inline PageDesc *page_find_alloc(unsigned int index) @@ -165,42 +158,59 @@ static inline PageDesc *page_find(unsigned int index) return p + (index & (L2_SIZE - 1)); } -int page_get_flags(unsigned long address) +#if !defined(CONFIG_USER_ONLY) +static void tlb_protect_code(CPUState *env, uint32_t addr); +static void tlb_unprotect_code(CPUState *env, uint32_t addr); +static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr); + +static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) { - PageDesc *p; + VirtPageDesc **lp, *p; - p = page_find(address >> TARGET_PAGE_BITS); + lp = &l1_virt_map[index >> L2_BITS]; + p = *lp; + if (!p) { + /* allocate if not found */ + p = malloc(sizeof(VirtPageDesc) * L2_SIZE); + memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE); + *lp = p; + } + return p + (index & (L2_SIZE - 1)); +} + +static inline VirtPageDesc *virt_page_find(unsigned int index) +{ + VirtPageDesc *p; + + p = l1_virt_map[index >> L2_BITS]; if (!p) return 0; - return p->flags; + return p + (index & (L2_SIZE - 1)); } -/* modify the flags of a page and invalidate the code if - necessary. The flag PAGE_WRITE_ORG is positionned automatically - depending on PAGE_WRITE */ -void page_set_flags(unsigned long start, unsigned long end, int flags) +static void virt_page_flush(void) { - PageDesc *p; - unsigned long addr; - - start = start & TARGET_PAGE_MASK; - end = TARGET_PAGE_ALIGN(end); - if (flags & PAGE_WRITE) - flags |= PAGE_WRITE_ORG; - spin_lock(&tb_lock); - for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { - p = page_find_alloc(addr >> TARGET_PAGE_BITS); - /* if the write protection is set, then we invalidate the code - inside */ - if (!(p->flags & PAGE_WRITE) && - (flags & PAGE_WRITE) && - p->first_tb) { - tb_invalidate_page(addr); + int i, j; + VirtPageDesc *p; + + virt_valid_tag++; + + if (virt_valid_tag == 0) { + virt_valid_tag = 1; + for(i = 0; i < L1_SIZE; i++) { + p = l1_virt_map[i]; + if (p) { + for(j = 0; j < L2_SIZE; j++) + p[j].valid_tag = 0; + } } - p->flags = flags; } - spin_unlock(&tb_lock); } +#else +static void virt_page_flush(void) +{ +} +#endif void cpu_exec_init(void) { @@ -211,6 +221,15 @@ void cpu_exec_init(void) } } +static inline void invalidate_page_bitmap(PageDesc *p) +{ + if (p->code_bitmap) { + free(p->code_bitmap); + p->code_bitmap = NULL; + } + p->code_write_count = 0; +} + /* set to NULL all the 'first_tb' fields in all PageDescs */ static void page_flush_tb(void) { @@ -220,8 +239,11 @@ static void page_flush_tb(void) for(i = 0; i < L1_SIZE; i++) { p = l1_map[i]; if (p) { - for(j = 0; j < L2_SIZE; j++) - p[j].first_tb = NULL; + for(j = 0; j < L2_SIZE; j++) { + p->first_tb = NULL; + invalidate_page_bitmap(p); + p++; + } } } } @@ -244,7 +266,12 @@ void tb_flush(CPUState *env) nb_tbs = 0; for(i = 0;i < CODE_GEN_HASH_SIZE; i++) tb_hash[i] = NULL; + virt_page_flush(); + + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) + tb_phys_hash[i] = NULL; page_flush_tb(); + code_gen_ptr = code_gen_buffer; /* XXX: flush processor icache at this point if cache flush is expensive */ @@ -323,6 +350,23 @@ static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb, } } +static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb) +{ + TranslationBlock *tb1; + unsigned int n1; + + for(;;) { + tb1 = *ptb; + n1 = (long)tb1 & 3; + tb1 = (TranslationBlock *)((long)tb1 & ~3); + if (tb1 == tb) { + *ptb = tb1->page_next[n1]; + break; + } + ptb = &tb1->page_next[n1]; + } +} + static inline void tb_jmp_remove(TranslationBlock *tb, int n) { TranslationBlock *tb1, **ptb; @@ -358,31 +402,27 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); } -static inline void tb_invalidate(TranslationBlock *tb, int parity) +static inline void tb_invalidate(TranslationBlock *tb) { - PageDesc *p; - unsigned int page_index1, page_index2; unsigned int h, n1; - TranslationBlock *tb1, *tb2; + TranslationBlock *tb1, *tb2, **ptb; tb_invalidated_flag = 1; /* remove the TB from the hash list */ h = tb_hash_func(tb->pc); - tb_remove(&tb_hash[h], tb, - offsetof(TranslationBlock, hash_next)); - /* remove the TB from the page list */ - page_index1 = tb->pc >> TARGET_PAGE_BITS; - if ((page_index1 & 1) == parity) { - p = page_find(page_index1); - tb_remove(&p->first_tb, tb, - offsetof(TranslationBlock, page_next[page_index1 & 1])); - } - page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS; - if ((page_index2 & 1) == parity) { - p = page_find(page_index2); - tb_remove(&p->first_tb, tb, - offsetof(TranslationBlock, page_next[page_index2 & 1])); + ptb = &tb_hash[h]; + for(;;) { + tb1 = *ptb; + /* NOTE: the TB is not necessarily linked in the hash. It + indicates that it is not currently used */ + if (tb1 == NULL) + return; + if (tb1 == tb) { + *ptb = tb1->hash_next; + break; + } + ptb = &tb1->hash_next; } /* suppress this TB from the two jump lists */ @@ -404,66 +444,276 @@ static inline void tb_invalidate(TranslationBlock *tb, int parity) tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ } -/* invalidate all TBs which intersect with the target page starting at addr */ -void tb_invalidate_page(unsigned long address) +static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) { - TranslationBlock *tb_next, *tb; - unsigned int page_index; - int parity1, parity2; PageDesc *p; -#ifdef DEBUG_TB_INVALIDATE - printf("tb_invalidate_page: %lx\n", address); + unsigned int h; + target_ulong phys_pc; + + /* remove the TB from the hash list */ + phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + h = tb_phys_hash_func(phys_pc); + tb_remove(&tb_phys_hash[h], tb, + offsetof(TranslationBlock, phys_hash_next)); + + /* remove the TB from the page list */ + if (tb->page_addr[0] != page_addr) { + p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); + tb_page_remove(&p->first_tb, tb); + invalidate_page_bitmap(p); + } + if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) { + p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); + tb_page_remove(&p->first_tb, tb); + invalidate_page_bitmap(p); + } + + tb_invalidate(tb); +} + +static inline void set_bits(uint8_t *tab, int start, int len) +{ + int end, mask, end1; + + end = start + len; + tab += start >> 3; + mask = 0xff << (start & 7); + if ((start & ~7) == (end & ~7)) { + if (start < end) { + mask &= ~(0xff << (end & 7)); + *tab |= mask; + } + } else { + *tab++ |= mask; + start = (start + 8) & ~7; + end1 = end & ~7; + while (start < end1) { + *tab++ = 0xff; + start += 8; + } + if (start < end) { + mask = ~(0xff << (end & 7)); + *tab |= mask; + } + } +} + +static void build_page_bitmap(PageDesc *p) +{ + int n, tb_start, tb_end; + TranslationBlock *tb; + + p->code_bitmap = malloc(TARGET_PAGE_SIZE / 8); + if (!p->code_bitmap) + return; + memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8); + + tb = p->first_tb; + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + /* NOTE: this is subtle as a TB may span two physical pages */ + if (n == 0) { + /* NOTE: tb_end may be after the end of the page, but + it is not a problem */ + tb_start = tb->pc & ~TARGET_PAGE_MASK; + tb_end = tb_start + tb->size; + if (tb_end > TARGET_PAGE_SIZE) + tb_end = TARGET_PAGE_SIZE; + } else { + tb_start = 0; + tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); + } + set_bits(p->code_bitmap, tb_start, tb_end - tb_start); + tb = tb->page_next[n]; + } +} + +/* invalidate all TBs which intersect with the target physical page + starting in range [start;end[. NOTE: start and end must refer to + the same physical page */ +static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end) +{ + int n; + PageDesc *p; + TranslationBlock *tb, *tb_next; + target_ulong tb_start, tb_end; + + p = page_find(start >> TARGET_PAGE_BITS); + if (!p) + return; + if (!p->code_bitmap && + ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) { + /* build code bitmap */ + build_page_bitmap(p); + } + + /* we remove all the TBs in the range [start, end[ */ + /* XXX: see if in some cases it could be faster to invalidate all the code */ + tb = p->first_tb; + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + tb_next = tb->page_next[n]; + /* NOTE: this is subtle as a TB may span two physical pages */ + if (n == 0) { + /* NOTE: tb_end may be after the end of the page, but + it is not a problem */ + tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + tb_end = tb_start + tb->size; + } else { + tb_start = tb->page_addr[1]; + tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); + } + if (!(tb_end <= start || tb_start >= end)) { + tb_phys_invalidate(tb, -1); + } + tb = tb_next; + } +#if !defined(CONFIG_USER_ONLY) + /* if no code remaining, no need to continue to use slow writes */ + if (!p->first_tb) { + invalidate_page_bitmap(p); + tlb_unprotect_code_phys(cpu_single_env, start); + } #endif +} - page_index = address >> TARGET_PAGE_BITS; - p = page_find(page_index); - if (!p) +/* len must be <= 8 and start must be a multiple of len */ +static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) +{ + PageDesc *p; + int offset, b; + + p = page_find(start >> TARGET_PAGE_BITS); + if (!p) + return; + if (p->code_bitmap) { + offset = start & ~TARGET_PAGE_MASK; + b = p->code_bitmap[offset >> 3] >> (offset & 7); + if (b & ((1 << len) - 1)) + goto do_invalidate; + } else { + do_invalidate: + tb_invalidate_phys_page_range(start, start + len); + } +} + +/* invalidate all TBs which intersect with the target virtual page + starting in range [start;end[. This function is usually used when + the target processor flushes its I-cache. NOTE: start and end must + refer to the same physical page */ +void tb_invalidate_page_range(target_ulong start, target_ulong end) +{ + int n; + PageDesc *p; + TranslationBlock *tb, *tb_next; + target_ulong pc; + target_ulong phys_start; + +#if !defined(CONFIG_USER_ONLY) + { + VirtPageDesc *vp; + vp = virt_page_find(start >> TARGET_PAGE_BITS); + if (!vp) + return; + if (vp->valid_tag != virt_valid_tag) + return; + phys_start = vp->phys_addr + (start & ~TARGET_PAGE_MASK); + } +#else + phys_start = start; +#endif + p = page_find(phys_start >> TARGET_PAGE_BITS); + if (!p) return; + /* we remove all the TBs in the range [start, end[ */ + /* XXX: see if in some cases it could be faster to invalidate all the code */ tb = p->first_tb; - parity1 = page_index & 1; - parity2 = parity1 ^ 1; while (tb != NULL) { - tb_next = tb->page_next[parity1]; - tb_invalidate(tb, parity2); + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + tb_next = tb->page_next[n]; + pc = tb->pc; + if (!((pc + tb->size) <= start || pc >= end)) { + tb_phys_invalidate(tb, -1); + } tb = tb_next; } +#if !defined(CONFIG_USER_ONLY) + /* if no code remaining, no need to continue to use slow writes */ + if (!p->first_tb) + tlb_unprotect_code(cpu_single_env, start); +#endif +} + +#if !defined(CONFIG_SOFTMMU) +static void tb_invalidate_phys_page(target_ulong addr) +{ + int n; + PageDesc *p; + TranslationBlock *tb; + + addr &= TARGET_PAGE_MASK; + p = page_find(addr >> TARGET_PAGE_BITS); + if (!p) + return; + tb = p->first_tb; + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + tb_phys_invalidate(tb, addr); + tb = tb->page_next[n]; + } p->first_tb = NULL; } +#endif /* add the tb in the target page and protect it if necessary */ -static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index) +static inline void tb_alloc_page(TranslationBlock *tb, + unsigned int n, unsigned int page_addr) { PageDesc *p; - unsigned long host_start, host_end, addr, page_addr; - int prot; + TranslationBlock *last_first_tb; + + tb->page_addr[n] = page_addr; + p = page_find(page_addr >> TARGET_PAGE_BITS); + tb->page_next[n] = p->first_tb; + last_first_tb = p->first_tb; + p->first_tb = (TranslationBlock *)((long)tb | n); + invalidate_page_bitmap(p); - p = page_find_alloc(page_index); - tb->page_next[page_index & 1] = p->first_tb; - p->first_tb = tb; +#if defined(CONFIG_USER_ONLY) if (p->flags & PAGE_WRITE) { + unsigned long host_start, host_end, addr; + int prot; + /* force the host page as non writable (writes will have a page fault + mprotect overhead) */ - page_addr = (page_index << TARGET_PAGE_BITS); host_start = page_addr & host_page_mask; host_end = host_start + host_page_size; prot = 0; for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) prot |= page_get_flags(addr); -#if !defined(CONFIG_SOFTMMU) mprotect((void *)host_start, host_page_size, (prot & PAGE_BITS) & ~PAGE_WRITE); -#endif -#if !defined(CONFIG_USER_ONLY) - /* suppress soft TLB */ - /* XXX: must flush on all processor with same address space */ - tlb_flush_page_write(cpu_single_env, host_start); -#endif #ifdef DEBUG_TB_INVALIDATE printf("protecting code page: 0x%08lx\n", host_start); #endif p->flags &= ~PAGE_WRITE; } +#else + /* if some code is already present, then the pages are already + protected. So we handle the case where only the first TB is + allocated in a physical page */ + if (!last_first_tb) { + target_ulong virt_addr; + + virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS); + tlb_protect_code(cpu_single_env, virt_addr); + } +#endif } /* Allocate a new translation block. Flush the translation buffer if @@ -480,21 +730,54 @@ TranslationBlock *tb_alloc(unsigned long pc) return tb; } -/* link the tb with the other TBs */ -void tb_link(TranslationBlock *tb) +/* add a new TB and link it to the physical page tables. phys_page2 is + (-1) to indicate that only one page contains the TB. */ +void tb_link_phys(TranslationBlock *tb, + target_ulong phys_pc, target_ulong phys_page2) { - unsigned int page_index1, page_index2; + unsigned int h; + TranslationBlock **ptb; + + /* add in the physical hash table */ + h = tb_phys_hash_func(phys_pc); + ptb = &tb_phys_hash[h]; + tb->phys_hash_next = *ptb; + *ptb = tb; /* add in the page list */ - page_index1 = tb->pc >> TARGET_PAGE_BITS; - tb_alloc_page(tb, page_index1); - page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS; - if (page_index2 != page_index1) { - tb_alloc_page(tb, page_index2); - } + tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK); + if (phys_page2 != -1) + tb_alloc_page(tb, 1, phys_page2); + else + tb->page_addr[1] = -1; #ifdef DEBUG_TB_CHECK tb_page_check(); #endif +} + +/* link the tb with the other TBs */ +void tb_link(TranslationBlock *tb) +{ +#if !defined(CONFIG_USER_ONLY) + { + VirtPageDesc *vp; + target_ulong addr; + + /* save the code memory mappings (needed to invalidate the code) */ + addr = tb->pc & TARGET_PAGE_MASK; + vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); + vp->phys_addr = tb->page_addr[0]; + vp->valid_tag = virt_valid_tag; + + if (tb->page_addr[1] != -1) { + addr += TARGET_PAGE_SIZE; + vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); + vp->phys_addr = tb->page_addr[1]; + vp->valid_tag = virt_valid_tag; + } + } +#endif + tb->jmp_first = (TranslationBlock *)((long)tb | 2); tb->jmp_next[0] = NULL; tb->jmp_next[1] = NULL; @@ -506,69 +789,13 @@ void tb_link(TranslationBlock *tb) tb_reset_jump(tb, 1); } -/* called from signal handler: invalidate the code and unprotect the - page. Return TRUE if the fault was succesfully handled. */ -int page_unprotect(unsigned long address) +/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < + tb[1].tc_ptr. Return NULL if not found */ +TranslationBlock *tb_find_pc(unsigned long tc_ptr) { - unsigned int page_index, prot, pindex; - PageDesc *p, *p1; - unsigned long host_start, host_end, addr; - - host_start = address & host_page_mask; - page_index = host_start >> TARGET_PAGE_BITS; - p1 = page_find(page_index); - if (!p1) - return 0; - host_end = host_start + host_page_size; - p = p1; - prot = 0; - for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) { - prot |= p->flags; - p++; - } - /* if the page was really writable, then we change its - protection back to writable */ - if (prot & PAGE_WRITE_ORG) { - pindex = (address - host_start) >> TARGET_PAGE_BITS; - if (!(p1[pindex].flags & PAGE_WRITE)) { -#if !defined(CONFIG_SOFTMMU) - mprotect((void *)host_start, host_page_size, - (prot & PAGE_BITS) | PAGE_WRITE); -#endif - p1[pindex].flags |= PAGE_WRITE; - /* and since the content will be modified, we must invalidate - the corresponding translated code. */ - tb_invalidate_page(address); -#ifdef DEBUG_TB_CHECK - tb_invalidate_check(address); -#endif - return 1; - } - } - return 0; -} - -/* call this function when system calls directly modify a memory area */ -void page_unprotect_range(uint8_t *data, unsigned long data_size) -{ - unsigned long start, end, addr; - - start = (unsigned long)data; - end = start + data_size; - start &= TARGET_PAGE_MASK; - end = TARGET_PAGE_ALIGN(end); - for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { - page_unprotect(addr); - } -} - -/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < - tb[1].tc_ptr. Return NULL if not found */ -TranslationBlock *tb_find_pc(unsigned long tc_ptr) -{ - int m_min, m_max, m; - unsigned long v; - TranslationBlock *tb; + int m_min, m_max, m; + unsigned long v; + TranslationBlock *tb; if (nb_tbs <= 0) return NULL; @@ -655,7 +882,7 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) if (env->nb_breakpoints >= MAX_BREAKPOINTS) return -1; env->breakpoints[env->nb_breakpoints++] = pc; - tb_invalidate_page(pc); + tb_invalidate_page_range(pc, pc + 1); return 0; #else return -1; @@ -676,7 +903,7 @@ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) memmove(&env->breakpoints[i], &env->breakpoints[i + 1], (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); env->nb_breakpoints--; - tb_invalidate_page(pc); + tb_invalidate_page_range(pc, pc + 1); return 0; #else return -1; @@ -691,6 +918,7 @@ void cpu_single_step(CPUState *env, int enabled) if (env->singlestep_enabled != enabled) { env->singlestep_enabled = enabled; /* must flush all the translated code to avoid inconsistancies */ + /* XXX: only flush what is necessary */ tb_flush(env); } #endif @@ -706,7 +934,15 @@ void cpu_set_log(int log_flags) perror(logfilename); _exit(1); } +#if !defined(CONFIG_SOFTMMU) + /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ + { + static uint8_t logfile_buf[4096]; + setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); + } +#else setvbuf(logfile, NULL, _IOLBF, 0); +#endif } } @@ -747,54 +983,13 @@ void cpu_abort(CPUState *env, const char *fmt, ...) #if !defined(CONFIG_USER_ONLY) -/* unmap all maped pages and flush all associated code */ -static void page_unmap(CPUState *env) -{ - PageDesc *pmap; - int i; - - for(i = 0; i < L1_SIZE; i++) { - pmap = l1_map[i]; - if (pmap) { -#if !defined(CONFIG_SOFTMMU) - PageDesc *p; - unsigned long addr; - int j, ret, j1; - - p = pmap; - for(j = 0;j < L2_SIZE;) { - if (p->flags & PAGE_VALID) { - addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); - /* we try to find a range to make less syscalls */ - j1 = j; - p++; - j++; - while (j < L2_SIZE && (p->flags & PAGE_VALID)) { - p++; - j++; - } - ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS); - if (ret != 0) { - fprintf(stderr, "Could not unmap page 0x%08lx\n", addr); - exit(1); - } - } else { - p++; - j++; - } - } -#endif - free(pmap); - l1_map[i] = NULL; - } - } - tb_flush(env); -} - void tlb_flush(CPUState *env) { int i; +#if defined(DEBUG_TLB) + printf("tlb_flush:\n"); +#endif /* must reset current TB so that interrupts cannot modify the links while we are modifying them */ env->current_tb = NULL; @@ -805,8 +1000,14 @@ void tlb_flush(CPUState *env) env->tlb_read[1][i].address = -1; env->tlb_write[1][i].address = -1; } - /* XXX: avoid flushing the TBs */ - page_unmap(env); + + virt_page_flush(); + for(i = 0;i < CODE_GEN_HASH_SIZE; i++) + tb_hash[i] = NULL; + +#if !defined(CONFIG_SOFTMMU) + munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); +#endif } static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) @@ -818,8 +1019,14 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) void tlb_flush_page(CPUState *env, uint32_t addr) { - int i, flags; + int i, n; + VirtPageDesc *vp; + PageDesc *p; + TranslationBlock *tb; +#if defined(DEBUG_TLB) + printf("tlb_flush_page: 0x%08x\n", addr); +#endif /* must reset current TB so that interrupts cannot modify the links while we are modifying them */ env->current_tb = NULL; @@ -831,25 +1038,240 @@ void tlb_flush_page(CPUState *env, uint32_t addr) tlb_flush_entry(&env->tlb_read[1][i], addr); tlb_flush_entry(&env->tlb_write[1][i], addr); - flags = page_get_flags(addr); - if (flags & PAGE_VALID) { + /* remove from the virtual pc hash table all the TB at this + virtual address */ + + vp = virt_page_find(addr >> TARGET_PAGE_BITS); + if (vp && vp->valid_tag == virt_valid_tag) { + p = page_find(vp->phys_addr >> TARGET_PAGE_BITS); + if (p) { + /* we remove all the links to the TBs in this virtual page */ + tb = p->first_tb; + while (tb != NULL) { + n = (long)tb & 3; + tb = (TranslationBlock *)((long)tb & ~3); + if ((tb->pc & TARGET_PAGE_MASK) == addr || + ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) { + tb_invalidate(tb); + } + tb = tb->page_next[n]; + } + } + } + #if !defined(CONFIG_SOFTMMU) + if (addr < MMAP_AREA_END) munmap((void *)addr, TARGET_PAGE_SIZE); #endif - page_set_flags(addr, addr + TARGET_PAGE_SIZE, 0); +} + +static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr) +{ + if (addr == (tlb_entry->address & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && + (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { + tlb_entry->address |= IO_MEM_CODE; + tlb_entry->addend -= (unsigned long)phys_ram_base; } } -/* make all write to page 'addr' trigger a TLB exception to detect - self modifying code */ -void tlb_flush_page_write(CPUState *env, uint32_t addr) +/* update the TLBs so that writes to code in the virtual page 'addr' + can be detected */ +static void tlb_protect_code(CPUState *env, uint32_t addr) { int i; addr &= TARGET_PAGE_MASK; i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_flush_entry(&env->tlb_write[0][i], addr); - tlb_flush_entry(&env->tlb_write[1][i], addr); + tlb_protect_code1(&env->tlb_write[0][i], addr); + tlb_protect_code1(&env->tlb_write[1][i], addr); +#if !defined(CONFIG_SOFTMMU) + /* NOTE: as we generated the code for this page, it is already at + least readable */ + if (addr < MMAP_AREA_END) + mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ); +#endif +} + +static inline void tlb_unprotect_code1(CPUTLBEntry *tlb_entry, uint32_t addr) +{ + if (addr == (tlb_entry->address & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && + (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE) { + tlb_entry->address &= TARGET_PAGE_MASK; + tlb_entry->addend += (unsigned long)phys_ram_base; + } +} + +/* update the TLB so that writes in virtual page 'addr' are no longer + tested self modifying code */ +static void tlb_unprotect_code(CPUState *env, uint32_t addr) +{ + int i; + + addr &= TARGET_PAGE_MASK; + i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_unprotect_code1(&env->tlb_write[0][i], addr); + tlb_unprotect_code1(&env->tlb_write[1][i], addr); +} + +static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, + uint32_t phys_addr) +{ + if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE && + ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) { + tlb_entry->address &= TARGET_PAGE_MASK; + tlb_entry->addend += (unsigned long)phys_ram_base; + } +} + +/* update the TLB so that writes in physical page 'phys_addr' are no longer + tested self modifying code */ +/* XXX: find a way to improve it */ +static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr) +{ + int i; + + phys_addr &= TARGET_PAGE_MASK; + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr); + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr); +} + +/* add a new TLB entry. At most a single entry for a given virtual + address is permitted. */ +int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, + int is_user, int is_softmmu) +{ + PageDesc *p; + target_ulong pd; + TranslationBlock *first_tb; + unsigned int index; + target_ulong address, addend; + int ret; + + p = page_find(paddr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + first_tb = NULL; + } else { + pd = p->phys_offset; + first_tb = p->first_tb; + } +#if defined(DEBUG_TLB) + printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n", + vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd); +#endif + + ret = 0; +#if !defined(CONFIG_SOFTMMU) + if (is_softmmu) +#endif + { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + /* IO memory case */ + address = vaddr | pd; + addend = paddr; + } else { + /* standard memory */ + address = vaddr; + addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); + } + + index = (vaddr >> 12) & (CPU_TLB_SIZE - 1); + addend -= vaddr; + if (prot & PROT_READ) { + env->tlb_read[is_user][index].address = address; + env->tlb_read[is_user][index].addend = addend; + } else { + env->tlb_read[is_user][index].address = -1; + env->tlb_read[is_user][index].addend = -1; + } + if (prot & PROT_WRITE) { + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { + /* ROM: access is ignored (same as unassigned) */ + env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM; + env->tlb_write[is_user][index].addend = addend - (unsigned long)phys_ram_base; + } else if (first_tb) { + /* if code is present, we use a specific memory + handler. It works only for physical memory access */ + env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE; + env->tlb_write[is_user][index].addend = addend - (unsigned long)phys_ram_base; + } else { + env->tlb_write[is_user][index].address = address; + env->tlb_write[is_user][index].addend = addend; + } + } else { + env->tlb_write[is_user][index].address = -1; + env->tlb_write[is_user][index].addend = -1; + } + } +#if !defined(CONFIG_SOFTMMU) + else { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + /* IO access: no mapping is done as it will be handled by the + soft MMU */ + if (!(env->hflags & HF_SOFTMMU_MASK)) + ret = 2; + } else { + void *map_addr; + if (prot & PROT_WRITE) { + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || first_tb) { + /* ROM: we do as if code was inside */ + /* if code is present, we only map as read only and save the + original mapping */ + VirtPageDesc *vp; + + vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS); + vp->phys_addr = pd; + vp->prot = prot; + vp->valid_tag = virt_valid_tag; + prot &= ~PAGE_WRITE; + } + } + map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, + MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK)); + if (map_addr == MAP_FAILED) { + cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", + paddr, vaddr); + } + } + } +#endif + return ret; +} + +/* called from signal handler: invalidate the code and unprotect the + page. Return TRUE if the fault was succesfully handled. */ +int page_unprotect(unsigned long addr) +{ +#if !defined(CONFIG_SOFTMMU) + VirtPageDesc *vp; + +#if defined(DEBUG_TLB) + printf("page_unprotect: addr=0x%08x\n", addr); +#endif + addr &= TARGET_PAGE_MASK; + vp = virt_page_find(addr >> TARGET_PAGE_BITS); + if (!vp) + return 0; + /* NOTE: in this case, validate_tag is _not_ tested as it + validates only the code TLB */ + if (vp->valid_tag != virt_valid_tag) + return 0; + if (!(vp->prot & PAGE_WRITE)) + return 0; +#if defined(DEBUG_TLB) + printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", + addr, vp->phys_addr, vp->prot); +#endif + tb_invalidate_phys_page(vp->phys_addr); + mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot); + return 1; +#else + return 0; +#endif } #else @@ -866,38 +1288,148 @@ void tlb_flush_page_write(CPUState *env, uint32_t addr) { } -#endif /* defined(CONFIG_USER_ONLY) */ +int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, + int is_user, int is_softmmu) +{ + return 0; +} -static inline unsigned long *physpage_find_alloc(unsigned int page) +/* dump memory mappings */ +void page_dump(FILE *f) { - unsigned long **lp, *p; - unsigned int index, i; + unsigned long start, end; + int i, j, prot, prot1; + PageDesc *p; - index = page >> TARGET_PAGE_BITS; - lp = &l1_physmap[index >> L2_BITS]; - p = *lp; - if (!p) { - /* allocate if not found */ - p = malloc(sizeof(unsigned long) * L2_SIZE); - for(i = 0; i < L2_SIZE; i++) - p[i] = IO_MEM_UNASSIGNED; - *lp = p; + fprintf(f, "%-8s %-8s %-8s %s\n", + "start", "end", "size", "prot"); + start = -1; + end = -1; + prot = 0; + for(i = 0; i <= L1_SIZE; i++) { + if (i < L1_SIZE) + p = l1_map[i]; + else + p = NULL; + for(j = 0;j < L2_SIZE; j++) { + if (!p) + prot1 = 0; + else + prot1 = p[j].flags; + if (prot1 != prot) { + end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); + if (start != -1) { + fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", + start, end, end - start, + prot & PAGE_READ ? 'r' : '-', + prot & PAGE_WRITE ? 'w' : '-', + prot & PAGE_EXEC ? 'x' : '-'); + } + if (prot1 != 0) + start = end; + else + start = -1; + prot = prot1; + } + if (!p) + break; + } } - return p + (index & (L2_SIZE - 1)); } -/* return NULL if no page defined (unused memory) */ -unsigned long physpage_find(unsigned long page) +int page_get_flags(unsigned long address) { - unsigned long *p; - unsigned int index; - index = page >> TARGET_PAGE_BITS; - p = l1_physmap[index >> L2_BITS]; + PageDesc *p; + + p = page_find(address >> TARGET_PAGE_BITS); if (!p) - return IO_MEM_UNASSIGNED; - return p[index & (L2_SIZE - 1)]; + return 0; + return p->flags; } +/* modify the flags of a page and invalidate the code if + necessary. The flag PAGE_WRITE_ORG is positionned automatically + depending on PAGE_WRITE */ +void page_set_flags(unsigned long start, unsigned long end, int flags) +{ + PageDesc *p; + unsigned long addr; + + start = start & TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + if (flags & PAGE_WRITE) + flags |= PAGE_WRITE_ORG; + spin_lock(&tb_lock); + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find_alloc(addr >> TARGET_PAGE_BITS); + /* if the write protection is set, then we invalidate the code + inside */ + if (!(p->flags & PAGE_WRITE) && + (flags & PAGE_WRITE) && + p->first_tb) { + tb_invalidate_phys_page(addr); + } + p->flags = flags; + } + spin_unlock(&tb_lock); +} + +/* called from signal handler: invalidate the code and unprotect the + page. Return TRUE if the fault was succesfully handled. */ +int page_unprotect(unsigned long address) +{ + unsigned int page_index, prot, pindex; + PageDesc *p, *p1; + unsigned long host_start, host_end, addr; + + host_start = address & host_page_mask; + page_index = host_start >> TARGET_PAGE_BITS; + p1 = page_find(page_index); + if (!p1) + return 0; + host_end = host_start + host_page_size; + p = p1; + prot = 0; + for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= p->flags; + p++; + } + /* if the page was really writable, then we change its + protection back to writable */ + if (prot & PAGE_WRITE_ORG) { + pindex = (address - host_start) >> TARGET_PAGE_BITS; + if (!(p1[pindex].flags & PAGE_WRITE)) { + mprotect((void *)host_start, host_page_size, + (prot & PAGE_BITS) | PAGE_WRITE); + p1[pindex].flags |= PAGE_WRITE; + /* and since the content will be modified, we must invalidate + the corresponding translated code. */ + tb_invalidate_phys_page(address); +#ifdef DEBUG_TB_CHECK + tb_invalidate_check(address); +#endif + return 1; + } + } + return 0; +} + +/* call this function when system calls directly modify a memory area */ +void page_unprotect_range(uint8_t *data, unsigned long data_size) +{ + unsigned long start, end, addr; + + start = (unsigned long)data; + end = start + data_size; + start &= TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + page_unprotect(addr); + } +} + +#endif /* defined(CONFIG_USER_ONLY) */ + /* register physical memory. 'size' must be a multiple of the target page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an io memory page */ @@ -905,13 +1437,13 @@ void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, long phys_offset) { unsigned long addr, end_addr; - unsigned long *p; + PageDesc *p; end_addr = start_addr + size; for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { - p = physpage_find_alloc(addr); - *p = phys_offset; - if ((phys_offset & ~TARGET_PAGE_MASK) == 0) + p = page_find_alloc(addr >> TARGET_PAGE_BITS); + p->phys_offset = phys_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) phys_offset += TARGET_PAGE_SIZE; } } @@ -937,11 +1469,51 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = { unassigned_mem_writeb, }; +/* self modifying code support in soft mmu mode : writing to a page + containing code comes to these functions */ + +static void code_mem_writeb(uint32_t addr, uint32_t val) +{ +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(addr, 1); +#endif + stb_raw(phys_ram_base + addr, val); +} + +static void code_mem_writew(uint32_t addr, uint32_t val) +{ +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(addr, 2); +#endif + stw_raw(phys_ram_base + addr, val); +} + +static void code_mem_writel(uint32_t addr, uint32_t val) +{ +#if !defined(CONFIG_USER_ONLY) + tb_invalidate_phys_page_fast(addr, 4); +#endif + stl_raw(phys_ram_base + addr, val); +} + +static CPUReadMemoryFunc *code_mem_read[3] = { + NULL, /* never used */ + NULL, /* never used */ + NULL, /* never used */ +}; + +static CPUWriteMemoryFunc *code_mem_write[3] = { + code_mem_writeb, + code_mem_writew, + code_mem_writel, +}; static void io_mem_init(void) { - io_mem_nb = 1; - cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write); + cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write); + cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write); + cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write); + io_mem_nb = 4; } /* mem_read and mem_write are arrays of functions containing the -- cgit v1.2.3 From 2ddbbd10de80b3d364d726fe6dda824a37cb42b0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:07:27 +0000 Subject: (temporary) only physical dump is possible in gdb git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@519 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 8b7dd9a53..140ab7f04 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -248,8 +248,8 @@ static int put_packet(char *buf) return 0; } - /* better than nothing for SOFTMMU : we use physical addresses */ -#ifdef CONFIG_SOFTMMU +/* better than nothing for SOFTMMU : we use physical addresses */ +#if !defined(CONFIG_USER_ONLY) static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) { uint8_t *ptr; -- cgit v1.2.3 From 6b136f9e8f3934f50e07a01b537ade3b57f6b2ce Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:08:12 +0000 Subject: CD-ROM detection fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@520 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index a0bf8aba8..3771bb0a5 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -40,14 +40,14 @@ #include #include +#define NO_THUNK_TYPE_SIZE +#include "thunk.h" + #include "cpu.h" #include "exec-all.h" #include "vl.h" -#define NO_THUNK_TYPE_SIZE -#include "thunk.h" - /* debug IDE devices */ //#define DEBUG_IDE //#define DEBUG_IDE_ATAPI @@ -1128,6 +1128,8 @@ static void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) break; case WIN_READ: case WIN_READ_ONCE: + if (!s->bs) + goto abort_cmd; s->req_nb_sectors = 1; ide_sector_read(s); break; @@ -1174,7 +1176,7 @@ static void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) if (!s->is_cdrom) goto abort_cmd; ide_set_signature(s); - s->status = READY_STAT; + s->status = 0x00; /* NOTE: READY is _not_ set */ s->error = 0x01; break; case WIN_PACKETCMD: @@ -1271,7 +1273,10 @@ static void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) /* high to low */ for(i = 0;i < 2; i++) { s = &ide_if[i]; - s->status = READY_STAT; + if (s->is_cdrom) + s->status = 0x00; /* NOTE: READY is _not_ set */ + else + s->status = READY_STAT; ide_set_signature(s); } } -- cgit v1.2.3 From 75c6215f9802657175c78fa84c2ffcc0ab905f4b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:08:37 +0000 Subject: correct cpu state git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@521 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-user/main.c b/linux-user/main.c index bc19c645f..2c9fe3cd6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -674,6 +674,7 @@ int main(int argc, char **argv) cpu_x86_set_cpl(env, 3); env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; + env->hflags |= HF_PE_MASK; /* linux register setup */ env->regs[R_EAX] = regs->eax; -- cgit v1.2.3 From 08785f48b73cfe79f316c49b60dded9afb220161 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:12:46 +0000 Subject: updated so that PPC/ARM/SPARC executables are automatically launched when invoked git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@522 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-binfmt-conf.sh | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh index a51f28102..e5acc474a 100644 --- a/qemu-binfmt-conf.sh +++ b/qemu-binfmt-conf.sh @@ -1,3 +1,34 @@ -# enable automatic i386 program execution by the kernel (must enable binfmt_misc) -echo ':i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register -echo ':i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register +#!/bin/sh +# enable automatic i386/ARM/SPARC/PPC program execution by the kernel + +# load the binfmt_misc module +/sbin/modprobe binfmt_misc + +# probe cpu type +cpu=`uname -m` +case "$cpu" in + i386|i486|i586|i686|i86pc|BePC) + cpu="i386" + ;; + "Power Macintosh"|ppc|ppc64) + cpu="ppc" + ;; + armv4l) + cpu="arm" + ;; +esac + +# register the interpreter for each cpu except for the native one +if [ $cpu != "i386" ] ; then + echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register + echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register +fi +if [ $cpu != "arm" ] ; then + echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register +fi +if [ $cpu != "sparc" ] ; then + echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register +fi +if [ $cpu != "ppc" ] ; then + echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register +fi -- cgit v1.2.3 From 8351d2d481d5d0565dd38afdf895596183903594 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:15:01 +0000 Subject: WHEEL defines may not be available in SDL git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@523 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdl.c b/sdl.c index d8ec2c6a3..335ef8849 100644 --- a/sdl.c +++ b/sdl.c @@ -195,10 +195,12 @@ static void sdl_send_mouse_event(void) buttons |= MOUSE_EVENT_MBUTTON; /* XXX: test wheel */ dz = 0; +#ifdef SDL_BUTTON_WHEELUP if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP)) dz--; if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN)) dz++; +#endif kbd_mouse_event(dx, dy, dz, buttons); } -- cgit v1.2.3 From e16c53fabbc3eea32be2837c08c8d4180429b2b8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:15:29 +0000 Subject: assembly soft MMU defines on i386 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@524 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_header.h | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/softmmu_header.h b/softmmu_header.h index 82aae40b2..b8077ef43 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -74,6 +74,152 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, int is_user); void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, DATA_TYPE v, int is_user); +#if (DATA_SIZE <= 4) && defined(__i386__) && (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) + +static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) +{ + int res; + + asm volatile ("movl %1, %%edx\n" + "movl %1, %%eax\n" + "shrl %3, %%edx\n" + "andl %4, %%eax\n" + "andl %2, %%edx\n" + "leal %5(%%edx, %%ebp), %%edx\n" + "cmpl (%%edx), %%eax\n" + "movl %1, %%eax\n" + "je 1f\n" + "pushl %6\n" + "call %7\n" + "popl %%edx\n" + "movl %%eax, %0\n" + "jmp 2f\n" + "1:\n" + "addl 4(%%edx), %%eax\n" +#if DATA_SIZE == 1 + "movzbl (%%eax), %0\n" +#elif DATA_SIZE == 2 + "movzwl (%%eax), %0\n" +#elif DATA_SIZE == 4 + "movl (%%eax), %0\n" +#else +#error unsupported size +#endif + "2:\n" + : "=r" (res) + : "r" (ptr), + "i" ((CPU_TLB_SIZE - 1) << 3), + "i" (TARGET_PAGE_BITS - 3), + "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), + "m" (*(uint32_t *)offsetof(CPUState, tlb_read[CPU_MEM_INDEX][0].address)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) + : "%eax", "%ecx", "%edx", "memory", "cc"); + return res; +} + +#if DATA_SIZE <= 2 +static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr) +{ + int res; + + asm volatile ("movl %1, %%edx\n" + "movl %1, %%eax\n" + "shrl %3, %%edx\n" + "andl %4, %%eax\n" + "andl %2, %%edx\n" + "leal %5(%%edx, %%ebp), %%edx\n" + "cmpl (%%edx), %%eax\n" + "movl %1, %%eax\n" + "je 1f\n" + "pushl %6\n" + "call %7\n" + "popl %%edx\n" +#if DATA_SIZE == 1 + "movsbl %%al, %0\n" +#elif DATA_SIZE == 2 + "movswl %%ax, %0\n" +#else +#error unsupported size +#endif + "jmp 2f\n" + "1:\n" + "addl 4(%%edx), %%eax\n" +#if DATA_SIZE == 1 + "movsbl (%%eax), %0\n" +#elif DATA_SIZE == 2 + "movswl (%%eax), %0\n" +#else +#error unsupported size +#endif + "2:\n" + : "=r" (res) + : "r" (ptr), + "i" ((CPU_TLB_SIZE - 1) << 3), + "i" (TARGET_PAGE_BITS - 3), + "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), + "m" (*(uint32_t *)offsetof(CPUState, tlb_read[CPU_MEM_INDEX][0].address)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) + : "%eax", "%ecx", "%edx", "memory", "cc"); + return res; +} +#endif + +static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) +{ + asm volatile ("movl %0, %%edx\n" + "movl %0, %%eax\n" + "shrl %3, %%edx\n" + "andl %4, %%eax\n" + "andl %2, %%edx\n" + "leal %5(%%edx, %%ebp), %%edx\n" + "cmpl (%%edx), %%eax\n" + "movl %0, %%eax\n" + "je 1f\n" +#if DATA_SIZE == 1 + "movzbl %b1, %%edx\n" +#elif DATA_SIZE == 2 + "movzwl %w1, %%edx\n" +#elif DATA_SIZE == 4 + "movl %1, %%edx\n" +#else +#error unsupported size +#endif + "pushl %6\n" + "call %7\n" + "popl %%eax\n" + "jmp 2f\n" + "1:\n" + "addl 4(%%edx), %%eax\n" +#if DATA_SIZE == 1 + "movb %b1, (%%eax)\n" +#elif DATA_SIZE == 2 + "movw %w1, (%%eax)\n" +#elif DATA_SIZE == 4 + "movl %1, (%%eax)\n" +#else +#error unsupported size +#endif + "2:\n" + : + : "r" (ptr), +/* NOTE: 'q' would be needed as constraint, but we could not use it + with T1 ! */ + "r" (v), + "i" ((CPU_TLB_SIZE - 1) << 3), + "i" (TARGET_PAGE_BITS - 3), + "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), + "m" (*(uint32_t *)offsetof(CPUState, tlb_write[CPU_MEM_INDEX][0].address)), + "i" (CPU_MEM_INDEX), + "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX)) + : "%eax", "%ecx", "%edx", "memory", "cc"); +} + +#else + +/* generic load/store macros */ + static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) { int index; @@ -115,6 +261,8 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr) } #endif +/* generic store macro */ + static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) { int index; @@ -133,6 +281,8 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) } } +#endif + #undef RES_TYPE #undef DATA_TYPE #undef DATA_STYPE -- cgit v1.2.3 From b9f19507970ae813ca14e12887b01a2abbca8eaa Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:17:13 +0000 Subject: hack for target_ulong define git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@525 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 099031442..bc07aca78 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -40,14 +40,14 @@ #include #include +#define NO_THUNK_TYPE_SIZE +#include "thunk.h" + #include "cpu.h" #include "exec-all.h" #include "vl.h" -#define NO_THUNK_TYPE_SIZE -#include "thunk.h" - //#define DEBUG_VGA //#define DEBUG_VGA_MEM //#define DEBUG_VGA_REG -- cgit v1.2.3 From dc887a4dae9bb118c6f29db5006ac7c1d58fdeb1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:18:57 +0000 Subject: make the bios be a ROM memory - glibc hacks for setvbuf and signals - correct century storage in CMOS emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@526 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 9b1a3fcc7..3008f95bb 100644 --- a/vl.c +++ b/vl.c @@ -458,6 +458,7 @@ void hw_error(const char *fmt, ...) /* PC cmos mappings */ #define REG_EQUIPMENT_BYTE 0x14 +#define REG_IBM_CENTURY_BYTE 0x32 uint8_t cmos_data[128]; uint8_t cmos_index; @@ -557,6 +558,7 @@ void cmos_init(void) cmos_data[RTC_REG_D] = 0x80; /* various important CMOS locations needed by PC/Bochs bios */ + cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ @@ -2961,7 +2963,7 @@ struct option long_options[] = { #ifdef CONFIG_SDL /* SDL use the pthreads and they modify sigaction. We don't want that. */ -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) extern void __libc_sigaction(); #define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact) #else @@ -3111,8 +3113,15 @@ int main(int argc, char **argv) if (hd_filename[0] == '\0' && boot_device == 'c') boot_device = 'd'; - /* init debug */ +#if !defined(CONFIG_SOFTMMU) + /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ + { + static uint8_t stdout_buf[4096]; + setvbuf(stdout, stdout_buf, _IOLBF, sizeof(stdout_buf)); + } +#else setvbuf(stdout, NULL, _IOLBF, 0); +#endif /* init network tun interface */ if (net_fd < 0) @@ -3221,6 +3230,7 @@ int main(int argc, char **argv) /* setup basic memory access */ env->cr[0] = 0x00000033; + env->hflags |= HF_PE_MASK; cpu_x86_init_mmu(env); memset(params->idt_table, 0, sizeof(params->idt_table)); @@ -3268,6 +3278,9 @@ int main(int argc, char **argv) env->cr[0] = 0x60000010; cpu_x86_init_mmu(env); + cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); + cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); + env->idt.limit = 0xffff; env->gdt.limit = 0xffff; env->ldt.limit = 0xffff; -- cgit v1.2.3 From efe160c502bc9ebb4d9e6fcb94cea708af73a2a1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 18:28:47 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@527 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 15 +++++++++++++++ VERSION | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 3432229f2..ed3b0e4ae 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,18 @@ +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. + version 0.5.1: - float access fixes when using soft mmu diff --git a/VERSION b/VERSION index 5d4294b91..2411653a5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.1 \ No newline at end of file +0.5.2 \ No newline at end of file -- cgit v1.2.3 From 9a64fbe4d89751524be0954f87dd514083295e99 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 22:58:38 +0000 Subject: PowerPC system emulation (Jocelyn Mayer) - modified patch to use new TLB api git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@528 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 407 +++++---- target-ppc/exec.h | 181 ++-- target-ppc/helper.c | 1024 +++++++++++++++++---- target-ppc/hw.c | 935 ++++++++++++++++++++ target-ppc/op.c | 653 ++++++++------ target-ppc/op_helper.c | 445 ++++++++++ target-ppc/op_helper_mem.h | 44 + target-ppc/op_mem.h | 187 ++++ target-ppc/op_template.h | 33 +- target-ppc/translate.c | 2116 +++++++++++++++++++++++++++++--------------- 10 files changed, 4596 insertions(+), 1429 deletions(-) create mode 100644 target-ppc/hw.c create mode 100644 target-ppc/op_helper.c create mode 100644 target-ppc/op_helper_mem.h create mode 100644 target-ppc/op_mem.h diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 53824896a..bc3c46df6 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -25,6 +25,8 @@ #include "cpu-defs.h" +//#define USE_OPEN_FIRMWARE + /*** Sign extend constants ***/ /* 8 to 32 bits */ static inline int32_t s_ext8 (uint8_t value) @@ -54,56 +56,28 @@ static inline int32_t s_ext24 (uint32_t value) #include "config.h" #include -/* Floting point status and control register */ -#define FPSCR_FX 31 -#define FPSCR_FEX 30 -#define FPSCR_VX 29 -#define FPSCR_OX 28 -#define FPSCR_UX 27 -#define FPSCR_ZX 26 -#define FPSCR_XX 25 -#define FPSCR_VXSNAN 24 -#define FPSCR_VXISI 26 -#define FPSCR_VXIDI 25 -#define FPSCR_VXZDZ 21 -#define FPSCR_VXIMZ 20 +/* Instruction types */ +enum { + PPC_NONE = 0x0000, + PPC_INTEGER = 0x0001, /* CPU has integer operations instructions */ + PPC_FLOAT = 0x0002, /* CPU has floating point operations instructions */ + PPC_FLOW = 0x0004, /* CPU has flow control instructions */ + PPC_MEM = 0x0008, /* CPU has virtual memory instructions */ + PPC_RES = 0x0010, /* CPU has ld/st with reservation instructions */ + PPC_CACHE = 0x0020, /* CPU has cache control instructions */ + PPC_MISC = 0x0040, /* CPU has spr/msr access instructions */ + PPC_EXTERN = 0x0080, /* CPU has external control instructions */ + PPC_SEGMENT = 0x0100, /* CPU has memory segment instructions */ + PPC_CACHE_OPT= 0x0200, + PPC_FLOAT_OPT= 0x0400, + PPC_MEM_OPT = 0x0800, +}; -#define FPSCR_VXVC 18 -#define FPSCR_FR 17 -#define FPSCR_FI 16 -#define FPSCR_FPRF 11 -#define FPSCR_VXSOFT 9 -#define FPSCR_VXSQRT 8 -#define FPSCR_VXCVI 7 -#define FPSCR_OE 6 -#define FPSCR_UE 5 -#define FPSCR_ZE 4 -#define FPSCR_XE 3 -#define FPSCR_NI 2 -#define FPSCR_RN 0 -#define fpscr_fx env->fpscr[FPSCR_FX] -#define fpscr_fex env->fpscr[FPSCR_FEX] -#define fpscr_vx env->fpscr[FPSCR_VX] -#define fpscr_ox env->fpscr[FPSCR_OX] -#define fpscr_ux env->fpscr[FPSCR_UX] -#define fpscr_zx env->fpscr[FPSCR_ZX] -#define fpscr_xx env->fpscr[FPSCR_XX] -#define fpscr_vsxnan env->fpscr[FPSCR_VXSNAN] -#define fpscr_vxisi env->fpscr[FPSCR_VXISI] -#define fpscr_vxidi env->fpscr[FPSCR_VXIDI] -#define fpscr_vxzdz env->fpscr[FPSCR_VXZDZ] -#define fpscr_vximz env->fpscr[FPSCR_VXIMZ] -#define fpscr_fr env->fpscr[FPSCR_FR] -#define fpscr_fi env->fpscr[FPSCR_FI] -#define fpscr_fprf env->fpscr[FPSCR_FPRF] -#define fpscr_vxsoft env->fpscr[FPSCR_VXSOFT] -#define fpscr_vxsqrt env->fpscr[FPSCR_VXSQRT] -#define fpscr_oe env->fpscr[FPSCR_OE] -#define fpscr_ue env->fpscr[FPSCR_UE] -#define fpscr_ze env->fpscr[FPSCR_ZE] -#define fpscr_xe env->fpscr[FPSCR_XE] -#define fpscr_ni env->fpscr[FPSCR_NI] -#define fpscr_rn env->fpscr[FPSCR_RN] +#define PPC_COMMON (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ + PPC_RES | PPC_CACHE | PPC_MISC | PPC_SEGMENT) +/* PPC 740/745/750/755 (aka G3) has external access instructions */ +#define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ + PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT) /* Supervisor mode registers */ /* Machine state register */ @@ -139,26 +113,16 @@ static inline int32_t s_ext24 (uint32_t value) #define msr_le env->msr[MSR_LE] /* Segment registers */ -typedef struct ppc_sr_t { - uint32_t t:1; - uint32_t ks:1; - uint32_t kp:1; - uint32_t n:1; - uint32_t res:4; - uint32_t vsid:24; -} ppc_sr_t; - typedef struct CPUPPCState { /* general purpose registers */ uint32_t gpr[32]; /* floating point registers */ double fpr[32]; /* segment registers */ - ppc_sr_t sr[16]; - /* special purpose registers */ - uint32_t spr[1024]; + uint32_t sdr1; + uint32_t sr[16]; /* XER */ - uint8_t xer[32]; + uint8_t xer[4]; /* Reservation address */ uint32_t reserve; /* machine state register */ @@ -166,11 +130,20 @@ typedef struct CPUPPCState { /* condition register */ uint8_t crf[8]; /* floating point status and control register */ - uint8_t fpscr[32]; + uint8_t fpscr[8]; uint32_t nip; - /* CPU exception code */ - uint32_t exception; - + /* special purpose registers */ + uint32_t lr; + uint32_t ctr; + /* Time base */ + uint32_t tb[2]; + /* decrementer */ + uint32_t decr; + /* BATs */ + uint32_t DBAT[2][8]; + uint32_t IBAT[2][8]; + /* all others */ + uint32_t spr[1024]; /* qemu dedicated */ /* temporary float registers */ double ft0; @@ -180,9 +153,14 @@ typedef struct CPUPPCState { jmp_buf jmp_env; int exception_index; int error_code; + uint32_t exceptions; /* exception queue */ + uint32_t errors[16]; int user_mode_only; /* user mode only simulation */ struct TranslationBlock *current_tb; /* currently executing TB */ - + /* soft mmu support */ + /* 0 = kernel, 1 = user */ + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; /* user data */ void *opaque; } CPUPPCState; @@ -198,107 +176,99 @@ int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, void *puc); void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); +void cpu_loop_exit(void); +void dump_stack (CPUPPCState *env); +uint32_t _load_xer (void); +void _store_xer (uint32_t value); +uint32_t _load_msr (void); +void _store_msr (uint32_t value); +void do_interrupt (CPUPPCState *env); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" #define ugpr(n) (env->gpr[n]) -#define fpr(n) (env->fpr[n]) +#define fprd(n) (env->fpr[n]) +#define fprs(n) ((float)env->fpr[n]) +#define fpru(n) ((uint32_t)env->fpr[n]) +#define fpri(n) ((int32_t)env->fpr[n]) #define SPR_ENCODE(sprn) \ (((sprn) >> 5) | (((sprn) & 0x1F) << 5)) /* User mode SPR */ #define spr(n) env->spr[n] -//#define XER spr[1] -#define XER env->xer #define XER_SO 31 #define XER_OV 30 #define XER_CA 29 #define XER_BC 0 -#define xer_so env->xer[XER_SO] -#define xer_ov env->xer[XER_OV] -#define xer_ca env->xer[XER_CA] -#define xer_bc env->xer[XER_BC] +#define xer_so env->xer[3] +#define xer_ov env->xer[2] +#define xer_ca env->xer[1] +#define xer_bc env->xer[0] -#define LR spr[SPR_ENCODE(8)] -#define CTR spr[SPR_ENCODE(9)] +#define XER SPR_ENCODE(1) +#define LR SPR_ENCODE(8) +#define CTR SPR_ENCODE(9) /* VEA mode SPR */ -#define V_TBL spr[SPR_ENCODE(268)] -#define V_TBU spr[SPR_ENCODE(269)] +#define V_TBL SPR_ENCODE(268) +#define V_TBU SPR_ENCODE(269) /* supervisor mode SPR */ -#define DSISR spr[SPR_ENCODE(18)] -#define DAR spr[SPR_ENCODE(19)] -#define DEC spr[SPR_ENCODE(22)] -#define SDR1 spr[SPR_ENCODE(25)] -typedef struct ppc_sdr1_t { - uint32_t htaborg:16; - uint32_t res:7; - uint32_t htabmask:9; -} ppc_sdr1_t; -#define SRR0 spr[SPR_ENCODE(26)] -#define SRR0_MASK 0xFFFFFFFC -#define SRR1 spr[SPR_ENCODE(27)] -#define SPRG0 spr[SPR_ENCODE(272)] -#define SPRG1 spr[SPR_ENCODE(273)] -#define SPRG2 spr[SPR_ENCODE(274)] -#define SPRG3 spr[SPR_ENCODE(275)] -#define EAR spr[SPR_ENCODE(282)] -typedef struct ppc_ear_t { - uint32_t e:1; - uint32_t res:25; - uint32_t rid:6; -} ppc_ear_t; -#define TBL spr[SPR_ENCODE(284)] -#define TBU spr[SPR_ENCODE(285)] -#define PVR spr[SPR_ENCODE(287)] -typedef struct ppc_pvr_t { - uint32_t version:16; - uint32_t revision:16; -} ppc_pvr_t; -#define IBAT0U spr[SPR_ENCODE(528)] -#define IBAT0L spr[SPR_ENCODE(529)] -#define IBAT1U spr[SPR_ENCODE(530)] -#define IBAT1L spr[SPR_ENCODE(531)] -#define IBAT2U spr[SPR_ENCODE(532)] -#define IBAT2L spr[SPR_ENCODE(533)] -#define IBAT3U spr[SPR_ENCODE(534)] -#define IBAT3L spr[SPR_ENCODE(535)] -#define DBAT0U spr[SPR_ENCODE(536)] -#define DBAT0L spr[SPR_ENCODE(537)] -#define DBAT1U spr[SPR_ENCODE(538)] -#define DBAT1L spr[SPR_ENCODE(539)] -#define DBAT2U spr[SPR_ENCODE(540)] -#define DBAT2L spr[SPR_ENCODE(541)] -#define DBAT3U spr[SPR_ENCODE(542)] -#define DBAT3L spr[SPR_ENCODE(543)] -typedef struct ppc_ubat_t { - uint32_t bepi:15; - uint32_t res:4; - uint32_t bl:11; - uint32_t vs:1; - uint32_t vp:1; -} ppc_ubat_t; -typedef struct ppc_lbat_t { - uint32_t brpn:15; - uint32_t res0:10; - uint32_t w:1; - uint32_t i:1; - uint32_t m:1; - uint32_t g:1; - uint32_t res1:1; - uint32_t pp:2; -} ppc_lbat_t; -#define DABR spr[SPR_ENCODE(1013)] +#define DSISR SPR_ENCODE(18) +#define DAR SPR_ENCODE(19) +#define DECR SPR_ENCODE(22) +#define SDR1 SPR_ENCODE(25) +#define SRR0 SPR_ENCODE(26) +#define SRR1 SPR_ENCODE(27) +#define SPRG0 SPR_ENCODE(272) +#define SPRG1 SPR_ENCODE(273) +#define SPRG2 SPR_ENCODE(274) +#define SPRG3 SPR_ENCODE(275) +#define SPRG4 SPR_ENCODE(276) +#define SPRG5 SPR_ENCODE(277) +#define SPRG6 SPR_ENCODE(278) +#define SPRG7 SPR_ENCODE(279) +#define ASR SPR_ENCODE(280) +#define EAR SPR_ENCODE(282) +#define O_TBL SPR_ENCODE(284) +#define O_TBU SPR_ENCODE(285) +#define PVR SPR_ENCODE(287) +#define IBAT0U SPR_ENCODE(528) +#define IBAT0L SPR_ENCODE(529) +#define IBAT1U SPR_ENCODE(530) +#define IBAT1L SPR_ENCODE(531) +#define IBAT2U SPR_ENCODE(532) +#define IBAT2L SPR_ENCODE(533) +#define IBAT3U SPR_ENCODE(534) +#define IBAT3L SPR_ENCODE(535) +#define DBAT0U SPR_ENCODE(536) +#define DBAT0L SPR_ENCODE(537) +#define DBAT1U SPR_ENCODE(538) +#define DBAT1L SPR_ENCODE(539) +#define DBAT2U SPR_ENCODE(540) +#define DBAT2L SPR_ENCODE(541) +#define DBAT3U SPR_ENCODE(542) +#define DBAT3L SPR_ENCODE(543) +#define IBAT4U SPR_ENCODE(560) +#define IBAT4L SPR_ENCODE(561) +#define IBAT5U SPR_ENCODE(562) +#define IBAT5L SPR_ENCODE(563) +#define IBAT6U SPR_ENCODE(564) +#define IBAT6L SPR_ENCODE(565) +#define IBAT7U SPR_ENCODE(566) +#define IBAT7L SPR_ENCODE(567) +#define DBAT4U SPR_ENCODE(568) +#define DBAT4L SPR_ENCODE(569) +#define DBAT5U SPR_ENCODE(570) +#define DBAT5L SPR_ENCODE(571) +#define DBAT6U SPR_ENCODE(572) +#define DBAT6L SPR_ENCODE(573) +#define DBAT7U SPR_ENCODE(574) +#define DBAT7L SPR_ENCODE(575) +#define DABR SPR_ENCODE(1013) #define DABR_MASK 0xFFFFFFF8 -typedef struct ppc_dabr_t { - uint32_t dab:29; - uint32_t bt:1; - uint32_t dw:1; - uint32_t dr:1; -} ppc_dabr_t; -#define FPECR spr[SPR_ENCODE(1022)] -#define PIR spr[SPR_ENCODE(1023)] +#define FPECR SPR_ENCODE(1022) +#define PIR SPR_ENCODE(1023) #define TARGET_PAGE_BITS 12 #include "cpu-all.h" @@ -307,10 +277,30 @@ CPUPPCState *cpu_ppc_init(void); int cpu_ppc_exec(CPUPPCState *s); void cpu_ppc_close(CPUPPCState *s); void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); +void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, + uint32_t kernel_addr, uint32_t kernel_size, + uint32_t stack_addr, int boot_device); -/* Exeptions */ +/* Memory access type : + * may be needed for precise access rights control and precise exceptions. + */ enum { - EXCP_NONE = 0x00, + /* 1 bit to define user level / supervisor access */ + ACCESS_USER = 0x00, + ACCESS_SUPER = 0x01, + /* Type of instruction that generated the access */ + ACCESS_CODE = 0x10, /* Code fetch access */ + ACCESS_INT = 0x20, /* Integer load/store access */ + ACCESS_FLOAT = 0x30, /* floating point load/store access */ + ACCESS_RES = 0x40, /* load/store with reservation */ + ACCESS_EXT = 0x50, /* external access */ + ACCESS_CACHE = 0x60, /* Cache manipulation */ +}; + +/*****************************************************************************/ +/* Exceptions */ +enum { + EXCP_NONE = -1, /* PPC hardware exceptions : exception vector / 0x100 */ EXCP_RESET = 0x01, /* System reset */ EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */ @@ -326,55 +316,80 @@ enum { EXCP_SYSCALL = 0x0C, /* System call */ EXCP_TRACE = 0x0D, /* Trace exception (optional) */ EXCP_FP_ASSIST = 0x0E, /* Floating-point assist (optional) */ -#if 0 - /* Exeption subtypes for EXCP_DSI */ - EXCP_DSI_TRANSLATE = 0x10301, /* Data address can't be translated */ - EXCP_DSI_NOTSUP = 0x10302, /* Access type not supported */ - EXCP_DSI_PROT = 0x10303, /* Memory protection violation */ - EXCP_DSI_EXTERNAL = 0x10304, /* External access disabled */ - EXCP_DSI_DABR = 0x10305, /* Data address breakpoint */ - /* Exeption subtypes for EXCP_ISI */ - EXCP_ISI_TRANSLATE = 0x10401, /* Code address can't be translated */ - EXCP_ISI_NOTSUP = 0x10402, /* Access type not supported */ - EXCP_ISI_PROT = 0x10403, /* Memory protection violation */ - EXCP_ISI_GUARD = 0x10404, /* Fetch into guarded memory */ - /* Exeption subtypes for EXCP_ALIGN */ - EXCP_ALIGN_FP = 0x10601, /* FP alignment exception */ - EXCP_ALIGN_LST = 0x10602, /* Unaligned memory load/store */ - EXCP_ALIGN_LE = 0x10603, /* Unaligned little-endian access */ - EXCP_ALIGN_PROT = 0x10604, /* Access cross protection boundary */ - EXCP_ALIGN_BAT = 0x10605, /* Access cross a BAT/seg boundary */ - EXCP_ALIGN_CACHE = 0x10606, /* Impossible dcbz access */ - /* Exeption subtypes for EXCP_PROGRAM */ + /* MPC740/745/750 & IBM 750 */ + EXCP_PERF = 0x0F, /* Performance monitor */ + EXCP_IABR = 0x13, /* Instruction address breakpoint */ + EXCP_SMI = 0x14, /* System management interrupt */ + EXCP_THRM = 0x15, /* Thermal management interrupt */ + /* MPC755 */ + EXCP_TLBMISS = 0x10, /* Instruction TLB miss */ + EXCP_TLBMISS_DL = 0x11, /* Data TLB miss for load */ + EXCP_TLBMISS_DS = 0x12, /* Data TLB miss for store */ + EXCP_PPC_MAX = 0x16, + /* Qemu exception */ + EXCP_OFCALL = 0x20, /* Call open-firmware emulator */ + EXCP_RTASCALL = 0x21, /* Call RTAS emulator */ + /* Special cases where we want to stop translation */ + EXCP_MTMSR = 0x104, /* mtmsr instruction: */ + /* may change privilege level */ + EXCP_BRANCH = 0x108, /* branch instruction */ + EXCP_RFI = 0x10C, /* return from interrupt */ + EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */ +}; +/* Error codes */ +enum { + /* Exception subtypes for EXCP_DSI */ + EXCP_DSI_TRANSLATE = 0x01, /* Data address can't be translated */ + EXCP_DSI_NOTSUP = 0x02, /* Access type not supported */ + EXCP_DSI_PROT = 0x03, /* Memory protection violation */ + EXCP_DSI_EXTERNAL = 0x04, /* External access disabled */ + EXCP_DSI_DABR = 0x05, /* Data address breakpoint */ + /* flags for EXCP_DSI */ + EXCP_DSI_DIRECT = 0x10, + EXCP_DSI_STORE = 0x20, + EXCP_ECXW = 0x40, + /* Exception subtypes for EXCP_ISI */ + EXCP_ISI_TRANSLATE = 0x01, /* Code address can't be translated */ + EXCP_ISI_NOEXEC = 0x02, /* Try to fetch from a data segment */ + EXCP_ISI_GUARD = 0x03, /* Fetch from guarded memory */ + EXCP_ISI_PROT = 0x04, /* Memory protection violation */ + /* Exception subtypes for EXCP_ALIGN */ + EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ + EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ + EXCP_ALIGN_LE = 0x03, /* Multiple little-endian access */ + EXCP_ALIGN_PROT = 0x04, /* Access cross protection boundary */ + EXCP_ALIGN_BAT = 0x05, /* Access cross a BAT/seg boundary */ + EXCP_ALIGN_CACHE = 0x06, /* Impossible dcbz access */ + /* Exception subtypes for EXCP_PROGRAM */ /* FP exceptions */ - EXCP_FP_OX = 0x10701, /* FP overflow */ - EXCP_FP_UX = 0x10702, /* FP underflow */ - EXCP_FP_ZX = 0x10703, /* FP divide by zero */ - EXCP_FP_XX = 0x10704, /* FP inexact */ - EXCP_FP_VXNAN = 0x10705, /* FP invalid SNaN op */ - EXCP_FP_VXISI = 0x10706, /* FP invalid infinite substraction */ - EXCP_FP_VXIDI = 0x10707, /* FP invalid infinite divide */ - EXCP_FP_VXZDZ = 0x10708, /* FP invalid zero divide */ - EXCP_FP_VXIMZ = 0x10709, /* FP invalid infinite * zero */ - EXCP_FP_VXVC = 0x1070A, /* FP invalid compare */ - EXCP_FP_VXSOFT = 0x1070B, /* FP invalid operation */ - EXCP_FP_VXSQRT = 0x1070C, /* FP invalid square root */ - EXCP_FP_VXCVI = 0x1070D, /* FP invalid integer conversion */ + EXCP_FP = 0x10, + EXCP_FP_OX = 0x01, /* FP overflow */ + EXCP_FP_UX = 0x02, /* FP underflow */ + EXCP_FP_ZX = 0x03, /* FP divide by zero */ + EXCP_FP_XX = 0x04, /* FP inexact */ + EXCP_FP_VXNAN = 0x05, /* FP invalid SNaN op */ + EXCP_FP_VXISI = 0x06, /* FP invalid infinite substraction */ + EXCP_FP_VXIDI = 0x07, /* FP invalid infinite divide */ + EXCP_FP_VXZDZ = 0x08, /* FP invalid zero divide */ + EXCP_FP_VXIMZ = 0x09, /* FP invalid infinite * zero */ + EXCP_FP_VXVC = 0x0A, /* FP invalid compare */ + EXCP_FP_VXSOFT = 0x0B, /* FP invalid operation */ + EXCP_FP_VXSQRT = 0x0C, /* FP invalid square root */ + EXCP_FP_VXCVI = 0x0D, /* FP invalid integer conversion */ /* Invalid instruction */ - EXCP_INVAL_INVAL = 0x10711, /* Invalid instruction */ - EXCP_INVAL_LSWX = 0x10712, /* Invalid lswx instruction */ - EXCP_INVAL_SPR = 0x10713, /* Invalid SPR access */ - EXCP_INVAL_FP = 0x10714, /* Unimplemented mandatory fp instr */ -#endif - EXCP_INVAL = 0x70, /* Invalid instruction */ + EXCP_INVAL = 0x20, + EXCP_INVAL_INVAL = 0x01, /* Invalid instruction */ + EXCP_INVAL_LSWX = 0x02, /* Invalid lswx instruction */ + EXCP_INVAL_SPR = 0x03, /* Invalid SPR access */ + EXCP_INVAL_FP = 0x04, /* Unimplemented mandatory fp instr */ /* Privileged instruction */ - EXCP_PRIV = 0x71, /* Privileged instruction */ + EXCP_PRIV = 0x30, + EXCP_PRIV_OPC = 0x01, + EXCP_PRIV_REG = 0x02, /* Trap */ - EXCP_TRAP = 0x72, /* Trap */ - /* Special cases where we want to stop translation */ - EXCP_MTMSR = 0x103, /* mtmsr instruction: */ - /* may change privilege level */ - EXCP_BRANCH = 0x104, /* branch instruction */ + EXCP_TRAP = 0x40, }; +/*****************************************************************************/ + #endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index da1ebb765..8a255ec6f 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -41,126 +41,119 @@ register uint32_t T2 asm(AREG3); #include "cpu.h" #include "exec-all.h" -static inline uint8_t ld8 (uint32_t EA) +static inline uint32_t rotl (uint32_t i, int n) { - return *((uint8_t *)EA); + return ((i << n) | (i >> (32 - n))); } -static inline uint16_t ld16 (uint32_t EA) -{ - return __be16_to_cpu(*((uint16_t *)EA)); -} +/* XXX: move that to a generic header */ +#if !defined(CONFIG_USER_ONLY) -static inline uint16_t ld16r (uint32_t EA) -{ - return __le16_to_cpu(*((uint16_t *)EA)); -} +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel -static inline uint32_t ld32 (uint32_t EA) -{ - return __be32_to_cpu(*((uint32_t *)EA)); -} - -static inline uint32_t ld32r (uint32_t EA) -{ - return __le32_to_cpu(*((uint32_t *)EA)); -} +#define ACCESS_TYPE 0 +#define MEMSUFFIX _kernel +#define DATA_SIZE 1 +#include "softmmu_header.h" -static inline uint64_t ld64 (uint32_t EA) -{ - return __be64_to_cpu(*((uint64_t *)EA)); -} +#define DATA_SIZE 2 +#include "softmmu_header.h" -static inline uint64_t ld64r (uint32_t EA) -{ - return __le64_to_cpu(*((uint64_t *)EA)); -} +#define DATA_SIZE 4 +#include "softmmu_header.h" -static inline void st8 (uint32_t EA, uint8_t data) -{ - *((uint8_t *)EA) = data; -} +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX -static inline void st16 (uint32_t EA, uint16_t data) -{ - *((uint16_t *)EA) = __cpu_to_be16(data); -} +#define ACCESS_TYPE 1 +#define MEMSUFFIX _user +#define DATA_SIZE 1 +#include "softmmu_header.h" -static inline void st16r (uint32_t EA, uint16_t data) -{ - *((uint16_t *)EA) = __cpu_to_le16(data); -} +#define DATA_SIZE 2 +#include "softmmu_header.h" -static inline void st32 (uint32_t EA, uint32_t data) -{ - *((uint32_t *)EA) = __cpu_to_be32(data); -} +#define DATA_SIZE 4 +#include "softmmu_header.h" -static inline void st32r (uint32_t EA, uint32_t data) -{ - *((uint32_t *)EA) = __cpu_to_le32(data); -} +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX -static inline void st64 (uint32_t EA, uint64_t data) -{ - *((uint64_t *)EA) = __cpu_to_be64(data); -} +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE 2 +#define MEMSUFFIX _data +#define DATA_SIZE 1 +#include "softmmu_header.h" -static inline void st64r (uint32_t EA, uint64_t data) -{ - *((uint64_t *)EA) = __cpu_to_le64(data); -} +#define DATA_SIZE 2 +#include "softmmu_header.h" -static inline void set_CRn(int n, uint8_t value) -{ - env->crf[n] = value; -} +#define DATA_SIZE 4 +#include "softmmu_header.h" -static inline void set_carry (void) -{ - xer_ca = 1; -} +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX -static inline void reset_carry (void) -{ - xer_ca = 0; -} +#define ldub(p) ldub_data(p) +#define ldsb(p) ldsb_data(p) +#define lduw(p) lduw_data(p) +#define ldsw(p) ldsw_data(p) +#define ldl(p) ldl_data(p) +#define ldq(p) ldq_data(p) -static inline void set_overflow (void) -{ - xer_so = 1; - xer_ov = 1; -} +#define stb(p, v) stb_data(p, v) +#define stw(p, v) stw_data(p, v) +#define stl(p, v) stl_data(p, v) +#define stq(p, v) stq_data(p, v) -static inline void reset_overflow (void) -{ - xer_ov = 0; -} +#endif /* !defined(CONFIG_USER_ONLY) */ -static inline uint32_t rotl (uint32_t i, int n) -{ - return ((i << n) | (i >> (32 - n))); -} +int check_exception_state (CPUState *env); -void raise_exception (int exception_index); -void raise_exception_err (int exception_index, int error_code); +void do_queue_exception_err (uint32_t exception, int error_code); +void do_queue_exception (uint32_t exception); +void do_process_exceptions (void); +void do_check_exception_state (void); -uint32_t do_load_cr (void); -void do_store_cr (uint32_t crn, uint32_t value); -uint32_t do_load_xer (void); -void do_store_xer (uint32_t value); -uint32_t do_load_msr (void); -void do_store_msr (uint32_t msr_value); +void do_load_cr (void); +void do_store_cr (uint32_t mask); +void do_load_xer (void); +void do_store_xer (void); +void do_load_msr (void); +void do_store_msr (void); void do_load_fpscr (void); void do_store_fpscr (uint32_t mask); -int32_t do_sraw(int32_t Ta, uint32_t Tb); -void do_lmw (int reg, uint32_t src); -void do_stmw (int reg, uint32_t dest); -void do_lsw (uint32_t reg, int count, uint32_t src); -void do_stsw (uint32_t reg, int count, uint32_t dest); +void do_sraw(void); + +void do_fctiw (void); +void do_fctiwz (void); +void do_fsqrt (void); +void do_fsqrts (void); +void do_fres (void); +void do_fsqrte (void); +void do_fsel (void); +void do_fcmpu (void); +void do_fcmpo (void); +void do_fabs (void); +void do_fnabs (void); -void do_dcbz (void); void do_icbi (void); +void do_tlbia (void); +void do_tlbie (void); + +void dump_rfi (void); +void dump_store_sr (int srnum); +void dump_store_ibat (int ul, int nr); +void dump_store_dbat (int ul, int nr); +void dump_store_tb (int ul); +void dump_update_tb(uint32_t param); #endif /* !defined (__PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4e9cc98e3..272dc9588 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -17,56 +17,642 @@ * 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 + #include "exec.h" +#if defined (USE_OPEN_FIRMWARE) +#include "of.h" +#endif + +//#define DEBUG_MMU +//#define DEBUG_BATS +//#define DEBUG_EXCEPTIONS + +extern FILE *logfile, *stderr; +void exit (int); +void abort (void); -extern FILE *logfile; +int phys_ram_size; +int phys_ram_fd; +uint8_t *phys_ram_base; void cpu_loop_exit(void) { longjmp(env->jmp_env, 1); } -/* shortcuts to generate exceptions */ -void raise_exception_err (int exception_index, int error_code) +void do_process_exceptions (void) { - env->exception_index = exception_index; - env->error_code = error_code; - cpu_loop_exit(); } -void raise_exception (int exception_index) +int check_exception_state (CPUState *env) { - env->exception_index = exception_index; - env->error_code = 0; + int i; - cpu_loop_exit(); + /* Process PPC exceptions */ + for (i = 1; i < EXCP_PPC_MAX; i++) { + if (env->exceptions & (1 << i)) { + switch (i) { + case EXCP_EXTERNAL: + case EXCP_DECR: + if (msr_ee == 0) + return 0; + break; + case EXCP_PROGRAM: + if (env->errors[EXCP_PROGRAM] == EXCP_FP && + msr_fe0 == 0 && msr_fe1 == 0) + return 0; + break; + default: + break; + } + env->exception_index = i; + env->error_code = env->errors[i]; + return 1; + } + } + + return 0; +} + +/*****************************************************************************/ +/* PPC MMU emulation */ +/* Perform BAT hit & translation */ +static int get_bat (CPUState *env, uint32_t *real, int *prot, + uint32_t virtual, int rw, int type) +{ + uint32_t *BATlt, *BATut, *BATu, *BATl; + uint32_t base, BEPIl, BEPIu, bl; + int i; + int ret = -1; + +#if defined (DEBUG_BATS) + if (loglevel > 0) { + fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', virtual); + } + printf("%s: %cBAT v 0x%08x\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', virtual); +#endif + switch (type) { + case ACCESS_CODE: + BATlt = env->IBAT[1]; + BATut = env->IBAT[0]; + break; + default: + BATlt = env->DBAT[1]; + BATut = env->DBAT[0]; + break; + } +#if defined (DEBUG_BATS) + if (loglevel > 0) { + fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', virtual); + } + printf("%s...: %cBAT v 0x%08x\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', virtual); +#endif + base = virtual & 0xFFFC0000; + for (i = 0; i < 4; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & 0xF0000000; + BEPIl = *BATu & 0x0FFE0000; + bl = (*BATu & 0x00001FFC) << 15; +#if defined (DEBUG_BATS) + if (loglevel > 0) { + fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", + __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, + *BATu, *BATl); + } else { + printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", + __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, + *BATu, *BATl); + } +#endif + if ((virtual & 0xF0000000) == BEPIu && + ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { + /* BAT matches */ + if ((msr_pr == 0 && (*BATu & 0x00000002)) || + (msr_pr == 1 && (*BATu & 0x00000001))) { + /* Get physical address */ + *real = (*BATl & 0xF0000000) | + ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | + (virtual & 0x0001FFFF); + if (*BATl & 0x00000001) + *prot = PROT_READ; + if (*BATl & 0x00000002) + *prot = PROT_WRITE | PROT_READ; +#if defined (DEBUG_BATS) + if (loglevel > 0) { + fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", + i, *real, *prot & PROT_READ ? 'R' : '-', + *prot & PROT_WRITE ? 'W' : '-'); + } else { + printf("BAT %d match: 0x%08x => 0x%08x prot=%c%c\n", + i, virtual, *real, *prot & PROT_READ ? 'R' : '-', + *prot & PROT_WRITE ? 'W' : '-'); + } +#endif + ret = 0; + break; + } + } + } + if (ret < 0) { +#if defined (DEBUG_BATS) + printf("no BAT match for 0x%08x:\n", virtual); + for (i = 0; i < 4; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & 0xF0000000; + BEPIl = *BATu & 0x0FFE0000; + bl = (*BATu & 0x00001FFC) << 15; + printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x \n\t" + "0x%08x 0x%08x 0x%08x\n", + __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, + *BATu, *BATl, BEPIu, BEPIl, bl); + } +#endif + env->spr[DAR] = virtual; + } + /* No hit */ + return ret; +} + +/* PTE table lookup */ +static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, + int h, int key, int rw) +{ + uint32_t pte0, pte1, keep = 0; + int i, good = -1, store = 0; + int ret = -1; /* No entry found */ + + for (i = 0; i < 8; i++) { + pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8))); + pte1 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4)); +#if defined (DEBUG_MMU) + printf("Load pte from 0x%08x => 0x%08x 0x%08x\n", base + (i * 8), + pte0, pte1); +#endif + /* Check validity and table match */ + if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) { +#if defined (DEBUG_MMU) + printf("PTE is valid and table matches... compare 0x%08x:%08x\n", + pte0 & 0x7FFFFFBF, va); +#endif + /* Check vsid & api */ + if ((pte0 & 0x7FFFFFBF) == va) { +#if defined (DEBUG_MMU) + printf("PTE match !\n"); +#endif + if (good == -1) { + good = i; + keep = pte1; + } else { + /* All matches should have equal RPN, WIMG & PP */ + if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) { + printf("Bad RPN/WIMG/PP\n"); + return -1; + } + } + /* Check access rights */ + if (key == 0) { + *prot = PROT_READ; + if ((pte1 & 0x00000003) != 0x3) + *prot |= PROT_WRITE; + } else { + switch (pte1 & 0x00000003) { + case 0x0: + *prot = 0; + break; + case 0x1: + case 0x3: + *prot = PROT_READ; + break; + case 0x2: + *prot = PROT_READ | PROT_WRITE; + break; + } + } + if ((rw == 0 && *prot != 0) || + (rw == 1 && (*prot & PROT_WRITE))) { +#if defined (DEBUG_MMU) + printf("PTE access granted !\n"); +#endif + good = i; + keep = pte1; + ret = 0; + } else if (ret == -1) { + ret = -2; /* Access right violation */ +#if defined (DEBUG_MMU) + printf("PTE access rejected\n"); +#endif + } + } + } + } + if (good != -1) { + *RPN = keep & 0xFFFFF000; +#if defined (DEBUG_MMU) + printf("found PTE at addr 0x%08x prot=0x%01x ret=%d\n", + *RPN, *prot, ret); +#endif + /* Update page flags */ + if (!(keep & 0x00000100)) { + keep |= 0x00000100; + store = 1; + } + if (rw) { + if (!(keep & 0x00000080)) { + keep |= 0x00000080; + store = 1; + } + } + if (store) + stl_raw((void *)(base + (good * 2) + 1), keep); + } + + return ret; } -/* Helpers for "fat" micro operations */ -uint32_t do_load_cr (void) +static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask) { - return (env->crf[0] << 28) | - (env->crf[1] << 24) | - (env->crf[2] << 20) | - (env->crf[3] << 16) | - (env->crf[4] << 12) | - (env->crf[5] << 8) | - (env->crf[6] << 4) | - (env->crf[7] << 0); + return (sdr1 & 0xFFFF0000) | (hash & mask); } -void do_store_cr (uint32_t crn, uint32_t value) +/* Perform segment based translation */ +static int get_segment (CPUState *env, uint32_t *real, int *prot, + uint32_t virtual, int rw, int type) { - int i, sh; + uint32_t pg_addr, sdr, ptem, vsid, pgidx; + uint32_t hash, mask; + uint32_t sr; + int key; + int ret = -1, ret2; - for (i = 0, sh = 7; i < 8; i++, sh --) { - if (crn & (1 << sh)) - env->crf[i] = (value >> (sh * 4)) & 0xF; + sr = env->sr[virtual >> 28]; +#if defined (DEBUG_MMU) + printf("Check segment v=0x%08x %d 0x%08x nip=0x%08x lr=0x%08x ir=%d dr=%d " + "pr=%d t=%d\n", virtual, virtual >> 28, sr, env->nip, + env->lr, msr_ir, msr_dr, msr_pr, type); +#endif + key = ((sr & 0x20000000) && msr_pr == 1) || + ((sr & 0x40000000) && msr_pr == 0) ? 1 : 0; + if ((sr & 0x80000000) == 0) { +#if defined (DEBUG_MMU) + printf("pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000); +#endif + /* Check if instruction fetch is allowed, if needed */ + if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { + /* Page address translation */ + vsid = sr & 0x00FFFFFF; + pgidx = (virtual >> 12) & 0xFFFF; + sdr = env->spr[SDR1]; + hash = ((vsid ^ pgidx) & 0x07FFFF) << 6; + mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; + pg_addr = get_pgaddr(sdr, hash, mask); + ptem = (vsid << 7) | (pgidx >> 10); +#if defined (DEBUG_MMU) + printf("0 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%07x " + "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); +#endif + /* Primary table lookup */ + ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw); + if (ret < 0) { + /* Secondary table lookup */ + hash = (~hash) & 0x01FFFFC0; + pg_addr = get_pgaddr(sdr, hash, mask); +#if defined (DEBUG_MMU) + printf("1 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%05x " + "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); +#endif + ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw); + if (ret2 != -1) + ret = ret2; + } + if (ret != -1) + *real |= (virtual & 0x00000FFF); + if (ret == -2 && type == ACCESS_CODE && (sr & 0x10000000)) + ret = -3; + } else { +#if defined (DEBUG_MMU) + printf("No access allowed\n"); +#endif + } + } else { +#if defined (DEBUG_MMU) + printf("direct store...\n"); +#endif + /* Direct-store segment : absolutely *BUGGY* for now */ + switch (type) { + case ACCESS_INT: + /* Integer load/store : only access allowed */ + break; + case ACCESS_CODE: + /* No code fetch is allowed in direct-store areas */ + return -4; + case ACCESS_FLOAT: + /* Floating point load/store */ + return -4; + case ACCESS_RES: + /* lwarx, ldarx or srwcx. */ + return -4; + case ACCESS_CACHE: + /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */ + /* Should make the instruction do no-op. + * As it already do no-op, it's quite easy :-) + */ + *real = virtual; + return 0; + case ACCESS_EXT: + /* eciwx or ecowx */ + return -4; + default: + if (logfile) { + fprintf(logfile, "ERROR: instruction should not need " + "address translation\n"); + } + printf("ERROR: instruction should not need " + "address translation\n"); + return -4; + } + if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) { + *real = virtual; + ret = 2; + } else { + ret = -2; + } } + + return ret; } -uint32_t do_load_xer (void) +int get_physical_address (CPUState *env, uint32_t *physical, int *prot, + uint32_t address, int rw, int access_type) +{ + int ret; + + if (loglevel > 0) { + fprintf(logfile, "%s\n", __func__); + } + if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) { + /* No address translation */ + *physical = address; + *prot = PROT_READ | PROT_WRITE; + ret = 0; + } else { + /* Try to find a BAT */ + ret = get_bat(env, physical, prot, address, rw, access_type); + if (ret < 0) { + /* We didn't match any BAT entry */ + ret = get_segment(env, physical, prot, address, rw, access_type); + } + } + + return ret; +} + + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) +{ + TranslationBlock *tb; + int ret, is_user; + unsigned long pc; + CPUState *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + is_user = flags & 0x01; + { + unsigned long tlb_addrr, tlb_addrw; + int index; + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_addrr = env->tlb_read[is_user][index].address; + tlb_addrw = env->tlb_write[is_user][index].address; +#if 0 + printf("%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " + "(0x%08lx 0x%08lx)\n", __func__, env, + &env->tlb_read[is_user][index], index, addr, + tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, + tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); +#endif + } + ret = cpu_handle_mmu_fault(env, addr, is_write, flags, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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); + } + } + do_queue_exception_err(env->exception_index, env->error_code); + do_process_exceptions(); + } + { + unsigned long tlb_addrr, tlb_addrw; + int index; + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_addrr = env->tlb_read[is_user][index].address; + tlb_addrw = env->tlb_write[is_user][index].address; +#if 0 + printf("%s 2 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " + "(0x%08lx 0x%08lx)\n", __func__, env, + &env->tlb_read[is_user][index], index, addr, + tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, + tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); +#endif + } + env = saved_env; +} + +void cpu_ppc_init_mmu(CPUPPCState *env) +{ + /* Nothing to do: all translation are disabled */ +} +#endif + +/* Perform address translation */ +int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int flags, int is_softmmu) +{ + uint32_t physical; + int prot; + int exception = 0, error_code = 0; + int is_user, access_type; + int ret = 0; + +// printf("%s 0\n", __func__); + is_user = flags & 0x01; + access_type = flags & ~0x01; + if (env->user_mode_only) { + /* user mode only emulation */ + ret = -1; + goto do_fault; + } + ret = get_physical_address(env, &physical, &prot, + address, rw, access_type); + if (ret == 0) { + ret = tlb_set_page(env, address, physical, prot, is_user, is_softmmu); + } else if (ret < 0) { + do_fault: +#if defined (DEBUG_MMU) + printf("%s 5\n", __func__); + printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x TBL=0x%08x\n", + env->nip, env->lr, env->ctr, /*msr*/0, env->tb[0]); + { + int i; + for (i = 0; i < 32; i++) { + if ((i & 7) == 0) + printf("GPR%02d:", i); + printf(" %08x", env->gpr[i]); + if ((i & 7) == 7) + printf("\n"); + } + printf("CR: 0x"); + for (i = 0; i < 8; i++) + printf("%01x", env->crf[i]); + printf(" ["); + for (i = 0; i < 8; i++) { + char a = '-'; + if (env->crf[i] & 0x08) + a = 'L'; + else if (env->crf[i] & 0x04) + a = 'G'; + else if (env->crf[i] & 0x02) + a = 'E'; + printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); + } + printf(" ] "); + } + printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); + printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); +#endif + if (access_type == ACCESS_CODE) { + exception = EXCP_ISI; + switch (ret) { + case -1: + /* No matches in page tables */ + error_code = EXCP_ISI_TRANSLATE; + break; + case -2: + /* Access rights violation */ + error_code = EXCP_ISI_PROT; + break; + case -3: + error_code = EXCP_ISI_NOEXEC; + break; + case -4: + /* Direct store exception */ + /* No code fetch is allowed in direct-store areas */ + exception = EXCP_ISI; + error_code = EXCP_ISI_NOEXEC; + break; + } + } else { + exception = EXCP_DSI; + switch (ret) { + case -1: + /* No matches in page tables */ + error_code = EXCP_DSI_TRANSLATE; + break; + case -2: + /* Access rights violation */ + error_code = EXCP_DSI_PROT; + break; + case -4: + /* Direct store exception */ + switch (access_type) { + case ACCESS_FLOAT: + /* Floating point load/store */ + exception = EXCP_ALIGN; + error_code = EXCP_ALIGN_FP; + break; + case ACCESS_RES: + /* lwarx, ldarx or srwcx. */ + exception = EXCP_DSI; + error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT; + if (rw) + error_code |= EXCP_DSI_STORE; + break; + case ACCESS_EXT: + /* eciwx or ecowx */ + exception = EXCP_DSI; + error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | EXCP_ECXW; + break; + default: + exception = EXCP_PROGRAM; + error_code = EXCP_INVAL | EXCP_INVAL_INVAL; + break; + } + } + if (rw) + error_code |= EXCP_DSI_STORE; + /* Should find a better solution: + * this will be invalid for some exception if more than one + * exception occurs for one instruction + */ + env->spr[DSISR] = 0; + if (error_code & EXCP_DSI_DIRECT) { + env->spr[DSISR] |= 0x80000000; + if (access_type == ACCESS_EXT || + access_type == ACCESS_RES) + env->spr[DSISR] |= 0x04000000; + } + if ((error_code & 0xF) == EXCP_DSI_TRANSLATE) + env->spr[DSISR] |= 0x40000000; + if (error_code & EXCP_DSI_PROT) + env->spr[DSISR] |= 0x08000000; + if (error_code & EXCP_DSI_STORE) + env->spr[DSISR] |= 0x02000000; + if ((error_code & 0xF) == EXCP_DSI_DABR) + env->spr[DSISR] |= 0x00400000; + if (access_type == ACCESS_EXT) + env->spr[DSISR] |= 0x00100000; + } +#if 0 + printf("%s: set exception to %d %02x\n", + __func__, exception, error_code); +#endif + env->exception_index = exception; + env->error_code = error_code; + /* Store fault address */ + env->spr[DAR] = address; + ret = 1; + } + + return ret; +} + +uint32_t _load_xer (void) { return (xer_so << XER_SO) | (xer_ov << XER_OV) | @@ -74,7 +660,7 @@ uint32_t do_load_xer (void) (xer_bc << XER_BC); } -void do_store_xer (uint32_t value) +void _store_xer (uint32_t value) { xer_so = (value >> XER_SO) & 0x01; xer_ov = (value >> XER_OV) & 0x01; @@ -82,7 +668,7 @@ void do_store_xer (uint32_t value) xer_bc = (value >> XER_BC) & 0x1f; } -uint32_t do_load_msr (void) +uint32_t _load_msr (void) { return (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | @@ -101,167 +687,255 @@ uint32_t do_load_msr (void) (msr_le << MSR_LE); } -void do_store_msr (uint32_t msr_value) +void _store_msr (uint32_t value) { - msr_pow = (msr_value >> MSR_POW) & 0x03; - msr_ile = (msr_value >> MSR_ILE) & 0x01; - msr_ee = (msr_value >> MSR_EE) & 0x01; - msr_pr = (msr_value >> MSR_PR) & 0x01; - msr_fp = (msr_value >> MSR_FP) & 0x01; - msr_me = (msr_value >> MSR_ME) & 0x01; - msr_fe0 = (msr_value >> MSR_FE0) & 0x01; - msr_se = (msr_value >> MSR_SE) & 0x01; - msr_be = (msr_value >> MSR_BE) & 0x01; - msr_fe1 = (msr_value >> MSR_FE1) & 0x01; - msr_ip = (msr_value >> MSR_IP) & 0x01; - msr_ir = (msr_value >> MSR_IR) & 0x01; - msr_dr = (msr_value >> MSR_DR) & 0x01; - msr_ri = (msr_value >> MSR_RI) & 0x01; - msr_le = (msr_value >> MSR_LE) & 0x01; + msr_pow = (value >> MSR_POW) & 0x03; + msr_ile = (value >> MSR_ILE) & 0x01; + msr_ee = (value >> MSR_EE) & 0x01; + msr_pr = (value >> MSR_PR) & 0x01; + msr_fp = (value >> MSR_FP) & 0x01; + msr_me = (value >> MSR_ME) & 0x01; + msr_fe0 = (value >> MSR_FE0) & 0x01; + msr_se = (value >> MSR_SE) & 0x01; + msr_be = (value >> MSR_BE) & 0x01; + msr_fe1 = (value >> MSR_FE1) & 0x01; + msr_ip = (value >> MSR_IP) & 0x01; + msr_ir = (value >> MSR_IR) & 0x01; + msr_dr = (value >> MSR_DR) & 0x01; + msr_ri = (value >> MSR_RI) & 0x01; + msr_le = (value >> MSR_LE) & 0x01; } -/* The 32 MSB of the target fpr are undefined. They'll be zero... */ -/* Floating point operations helpers */ -void do_load_fpscr (void) +void do_interrupt (CPUState *env) { - /* The 32 MSB of the target fpr are undefined. - * They'll be zero... - */ - union { - double d; - struct { - uint32_t u[2]; - } s; - } u; - int i; - - u.s.u[0] = 0; - u.s.u[1] = 0; - for (i = 0; i < 8; i++) - u.s.u[1] |= env->fpscr[i] << (4 * i); - FT0 = u.d; -} +#if defined (CONFIG_USER_ONLY) + env->exception_index |= 0x100; +#else + uint32_t msr; + int excp = env->exception_index; -void do_store_fpscr (uint32_t mask) -{ - /* - * We use only the 32 LSB of the incoming fpr - */ - union { - double d; - struct { - uint32_t u[2]; - } s; - } u; + /* Dequeue PPC exceptions */ + if (excp < EXCP_PPC_MAX) + env->exceptions &= ~(1 << excp); + msr = _load_msr(); +#if defined (DEBUG_EXCEPTIONS) + if (excp != EXCP_DECR && excp == EXCP_PROGRAM && excp < EXCP_PPC_MAX) + { + if (loglevel > 0) { + fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", + env->nip, excp << 8, env->error_code); + } else { + printf("Raise exception at 0x%08x => 0x%08x (%02x)\n", + env->nip, excp << 8, env->error_code); + } + printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x DECR=0x%08x\n", + env->nip, env->lr, env->ctr, msr, env->decr); + { int i; - - u.d = FT0; - if (mask & 0x80) - env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[1] >> 28) & ~0x9); - for (i = 1; i < 7; i++) { - if (mask & (1 << (7 - i))) - env->fpscr[i] = (u.s.u[1] >> (4 * (7 - i))) & 0xF; + for (i = 0; i < 32; i++) { + if ((i & 7) == 0) + printf("GPR%02d:", i); + printf(" %08x", env->gpr[i]); + if ((i & 7) == 7) + printf("\n"); } - /* TODO: update FEX & VX */ - /* Set rounding mode */ - switch (env->fpscr[0] & 0x3) { - case 0: - /* Best approximation (round to nearest) */ - fesetround(FE_TONEAREST); - break; - case 1: - /* Smaller magnitude (round toward zero) */ - fesetround(FE_TOWARDZERO); - break; - case 2: - /* Round toward +infinite */ - fesetround(FE_UPWARD); - break; - case 3: - /* Round toward -infinite */ - fesetround(FE_DOWNWARD); - break; + printf("CR: 0x"); + for (i = 0; i < 8; i++) + printf("%01x", env->crf[i]); + printf(" ["); + for (i = 0; i < 8; i++) { + char a = '-'; + if (env->crf[i] & 0x08) + a = 'L'; + else if (env->crf[i] & 0x04) + a = 'G'; + else if (env->crf[i] & 0x02) + a = 'E'; + printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } -} - -int32_t do_sraw(int32_t value, uint32_t shift) -{ - int32_t ret; - - xer_ca = 0; - if (shift & 0x20) { - ret = (-1) * ((uint32_t)value >> 31); - if (ret < 0) - xer_ca = 1; - } else { - ret = value >> (shift & 0x1f); - if (ret < 0 && (value & ((1 << shift) - 1)) != 0) - xer_ca = 1; + printf(" ] "); } - - return ret; -} - -void do_lmw (int reg, uint32_t src) -{ - for (; reg <= 31; reg++, src += 4) - ugpr(reg) = ld32(src); -} - -void do_stmw (int reg, uint32_t dest) -{ - for (; reg <= 31; reg++, dest += 4) - st32(dest, ugpr(reg)); -} - -void do_lsw (uint32_t reg, int count, uint32_t src) -{ - uint32_t tmp; - int sh; - - for (; count > 3; count -= 4, src += 4) { - ugpr(reg++) = ld32(src); - if (T2 == 32) - T2 = 0; + printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); + printf("XER 0x%08x SRR0 0x%08x SRR1 0x%08x\n", + _load_xer(), env->spr[SRR0], env->spr[SRR1]); } - if (count > 0) { - tmp = 0; - for (sh = 24; count > 0; count--, src++, sh -= 8) { - tmp |= ld8(src) << sh; +#endif + /* Generate informations in save/restore registers */ + switch (excp) { + case EXCP_OFCALL: +#if defined (USE_OPEN_FIRMWARE) + env->gpr[3] = OF_client_entry((void *)env->gpr[3]); +#endif + return; + case EXCP_RTASCALL: +#if defined (USE_OPEN_FIRMWARE) + printf("RTAS call !\n"); + env->gpr[3] = RTAS_entry((void *)env->gpr[3]); + printf("RTAS call done\n"); +#endif + return; + case EXCP_NONE: + /* Do nothing */ +#if defined (DEBUG_EXCEPTIONS) + printf("%s: escape EXCP_NONE\n", __func__); +#endif + return; + case EXCP_RESET: + if (msr_ip) + excp += 0xFFC00; + goto store_next; + case EXCP_MACHINE_CHECK: + if (msr_me == 0) { + printf("Machine check exception while not allowed !\n"); + if (loglevel) { + fprintf(logfile, + "Machine check exception while not allowed !\n"); } - ugpr(reg) = tmp; + abort(); } -} - -void do_stsw (uint32_t reg, int count, uint32_t dest) -{ - int sh; - - for (; count > 3; count -= 4, dest += 4) { - st32(dest, ugpr(reg++)); - if (reg == 32) - reg = 0; + msr_me = 0; + break; + case EXCP_DSI: + /* Store exception cause */ + /* data location address has been stored + * when the fault has been detected + */ + goto store_current; + case EXCP_ISI: + /* Store exception cause */ + if (env->error_code == EXCP_ISI_TRANSLATE) + msr |= 0x40000000; + else if (env->error_code == EXCP_ISI_NOEXEC || + env->error_code == EXCP_ISI_GUARD) + msr |= 0x10000000; + else + msr |= 0x08000000; + goto store_next; + case EXCP_EXTERNAL: + if (msr_ee == 0) { +#if defined (DEBUG_EXCEPTIONS) + if (loglevel > 0) { + fprintf(logfile, "Skipping hardware interrupt\n"); + } else { + printf("Skipping hardware interrupt\n"); } - if (count > 0) { - for (sh = 24; count > 0; count--, dest++, sh -= 8) { - st8(dest, (ugpr(reg) >> sh) & 0xFF); +#endif + return; } + goto store_next; + case EXCP_ALIGN: + /* Store exception cause */ + /* Get rS/rD and rA from faulting opcode */ + env->spr[DSISR] |= + (ldl_code((void *)(env->nip - 4)) & 0x03FF0000) >> 16; + /* data location address has been stored + * when the fault has been detected + */ + goto store_current; + case EXCP_PROGRAM: + msr &= ~0xFFFF0000; + switch (env->error_code & ~0xF) { + case EXCP_FP: + if (msr_fe0 == 0 && msr_fe1 == 0) { +#if defined (DEBUG_EXCEPTIONS) + printf("Ignore floating point exception\n"); +#endif + return; } -} - -void do_dcbz (void) -{ - int i; - - /* Assume cache line size is 32 */ - for (i = 0; i < 8; i++) { - st32(T0, 0); - T0 += 4; + msr |= 0x00100000; + /* Set FX */ + env->fpscr[7] |= 0x8; + /* Finally, update FEX */ + if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & + ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) + env->fpscr[7] |= 0x4; + break; + case EXCP_INVAL: + msr |= 0x00080000; + break; + case EXCP_PRIV: + msr |= 0x00040000; + break; + case EXCP_TRAP: + msr |= 0x00020000; + break; + default: + /* Should never occur */ + break; } -} - -/* Instruction cache invalidation helper */ -void do_icbi (void) -{ - // tb_invalidate_page(T0); + msr |= 0x00010000; + goto store_current; + case EXCP_NO_FP: + goto store_current; + case EXCP_DECR: + if (msr_ee == 0) { + /* Requeue it */ + do_queue_exception(EXCP_DECR); + return; + } + goto store_next; + case EXCP_SYSCALL: +#if defined (DEBUG_EXCEPTIONS) + printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", + env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); +#endif + goto store_next; + case EXCP_TRACE: + goto store_next; + case EXCP_FP_ASSIST: + goto store_next; + case EXCP_MTMSR: + /* Nothing to do */ +#if defined (DEBUG_EXCEPTIONS) + printf("%s: escape EXCP_MTMSR\n", __func__); +#endif + return; + case EXCP_BRANCH: + /* Nothing to do */ +#if defined (DEBUG_EXCEPTIONS) + printf("%s: escape EXCP_BRANCH\n", __func__); +#endif + return; + case EXCP_RFI: + /* Restore user-mode state */ +#if defined (DEBUG_EXCEPTIONS) + printf("%s: escape EXCP_RFI\n", __func__); +#endif + return; + store_current: + /* SRR0 is set to current instruction */ + env->spr[SRR0] = (uint32_t)env->nip - 4; + break; + store_next: + /* SRR0 is set to next instruction */ + env->spr[SRR0] = (uint32_t)env->nip; + break; + } + env->spr[SRR1] = msr; + /* reload MSR with correct bits */ + msr_pow = 0; + msr_ee = 0; + msr_pr = 0; + msr_fp = 0; + msr_fe0 = 0; + msr_se = 0; + msr_be = 0; + msr_fe1 = 0; + msr_ir = 0; + msr_dr = 0; + msr_ri = 0; + msr_le = msr_ile; + /* Jump to handler */ + env->nip = excp << 8; + env->exception_index = EXCP_NONE; + /* Invalidate all TLB as we may have changed translation mode */ + do_tlbia(); + /* ensure that no TB jump will be modified as + the program flow was changed */ +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif +#endif } diff --git a/target-ppc/hw.c b/target-ppc/hw.c new file mode 100644 index 000000000..090b610c3 --- /dev/null +++ b/target-ppc/hw.c @@ -0,0 +1,935 @@ +/* + * Hardware simulation for PPC target. + * For now, this is only a 'minimal' collection of hacks needed to boot Linux. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +//#define HARD_DEBUG_PPC_IO +#define DEBUG_PPC_IO + +extern int loglevel; +extern FILE *logfile; + +#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO) +#define DEBUG_PPC_IO +#endif + +#if defined (HARD_DEBUG_PPC_IO) +#define PPC_IO_DPRINTF(fmt, args...) \ +do { \ + if (loglevel > 0) { \ + fprintf(logfile, "%s: " fmt, __func__ , ##args); \ + } else { \ + printf("%s : " fmt, __func__ , ##args); \ + } \ +} while (0) +#elif defined (DEBUG_PPC_IO) +#define PPC_IO_DPRINTF(fmt, args...) \ +do { \ + if (loglevel > 0) { \ + fprintf(logfile, "%s: " fmt, __func__ , ##args); \ + } \ +} while (0) +#else +#define PPC_IO_DPRINTF(fmt, args...) do { } while (0) +#endif + +#if defined (USE_OPEN_FIRMWARE) +#include "of.h" +#else +#define NVRAM_SIZE 0x2000 +#endif + +/* IO ports emulation */ +#define PPC_IO_BASE 0x80000000 + +static void PPC_io_writeb (uint32_t addr, uint32_t value) +{ + /* Don't polute serial port output */ + if ((addr < 0x800003F0 || addr > 0x80000400) && + (addr < 0x80000074 || addr > 0x80000077) && + (addr < 0x80000020 || addr > 0x80000021) && + (addr < 0x800000a0 || addr > 0x800000a1) && + (addr < 0x800001f0 || addr > 0x800001f7) && + (addr < 0x80000170 || addr > 0x80000177)) { + PPC_IO_DPRINTF("0x%08x => 0x%02x\n", addr - PPC_IO_BASE, value); + } + cpu_outb(NULL, addr - PPC_IO_BASE, value); +} + +static uint32_t PPC_io_readb (uint32_t addr) +{ + uint32_t ret = cpu_inb(NULL, addr - PPC_IO_BASE); + + if ((addr < 0x800003F0 || addr > 0x80000400) && + (addr < 0x80000074 || addr > 0x80000077) && + (addr < 0x80000020 || addr > 0x80000021) && + (addr < 0x800000a0 || addr > 0x800000a1) && + (addr < 0x800001f0 || addr > 0x800001f7) && + (addr < 0x80000170 || addr > 0x80000177) && + (addr < 0x8000060 || addr > 0x8000064)) { +// PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); + } + + return ret; +} + +static void PPC_io_writew (uint32_t addr, uint32_t value) +{ + if ((addr < 0x800001f0 || addr > 0x800001f7) && + (addr < 0x80000170 || addr > 0x80000177)) { + PPC_IO_DPRINTF("0x%08x => 0x%04x\n", addr - PPC_IO_BASE, value); + } + cpu_outw(NULL, addr - PPC_IO_BASE, value); +} + +static uint32_t PPC_io_readw (uint32_t addr) +{ + uint32_t ret = cpu_inw(NULL, addr - PPC_IO_BASE); + + if ((addr < 0x800001f0 || addr > 0x800001f7) && + (addr < 0x80000170 || addr > 0x80000177)) { + PPC_IO_DPRINTF("0x%08x <= 0x%04x\n", addr - PPC_IO_BASE, ret); + } + + return ret; +} + +static void PPC_io_writel (uint32_t addr, uint32_t value) +{ + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); + cpu_outl(NULL, addr - PPC_IO_BASE, value); +} + +static uint32_t PPC_io_readl (uint32_t addr) +{ + uint32_t ret = cpu_inl(NULL, addr - PPC_IO_BASE); + + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, ret); + + return ret; +} + +static CPUWriteMemoryFunc *PPC_io_write[] = { + &PPC_io_writeb, + &PPC_io_writew, + &PPC_io_writel, +}; + +static CPUReadMemoryFunc *PPC_io_read[] = { + &PPC_io_readb, + &PPC_io_readw, + &PPC_io_readl, +}; + +uint32_t pic_intack_read(CPUState *env); + +/* Read-only register (?) */ +static void _PPC_ioB_write (uint32_t addr, uint32_t value) +{ + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr, value); +} + +static uint32_t _PPC_ioB_read (uint32_t addr) +{ + uint32_t retval = 0; + + if (addr == 0xBFFFFFF0) + retval = pic_intack_read(NULL); + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr, retval); + + return retval; +} + +static CPUWriteMemoryFunc *PPC_ioB_write[] = { + &_PPC_ioB_write, + &_PPC_ioB_write, + &_PPC_ioB_write, +}; + +static CPUReadMemoryFunc *PPC_ioB_read[] = { + &_PPC_ioB_read, + &_PPC_ioB_read, + &_PPC_ioB_read, +}; + +#if 0 +static CPUWriteMemoryFunc *PPC_io3_write[] = { + &PPC_io3_writeb, + &PPC_io3_writew, + &PPC_io3_writel, +}; + +static CPUReadMemoryFunc *PPC_io3_read[] = { + &PPC_io3_readb, + &PPC_io3_readw, + &PPC_io3_readl, +}; +#endif + +/* Fake super-io ports for PREP platform (Intel 82378ZB) */ +static uint8_t PREP_fake_io[2]; +static uint8_t NVRAM_lock; + +static void PREP_io_write (CPUState *env, uint32_t addr, uint32_t val) +{ + PREP_fake_io[addr - 0x0398] = val; +} + +static uint32_t PREP_io_read (CPUState *env, uint32_t addr) +{ + return PREP_fake_io[addr - 0x0398]; +} + +static uint8_t syscontrol; + +static void PREP_io_800_writeb (CPUState *env, uint32_t addr, uint32_t val) +{ + switch (addr) { + case 0x0092: + /* Special port 92 */ + /* Check soft reset asked */ + if (val & 0x80) { + printf("Soft reset asked... Stop emulation\n"); + abort(); + } + /* Check LE mode */ + if (val & 0x40) { + printf("Little Endian mode isn't supported (yet ?)\n"); + abort(); + } + break; + case 0x0808: + /* Hardfile light register: don't care */ + break; + case 0x0810: + /* Password protect 1 register */ + NVRAM_lock ^= 0x01; + break; + case 0x0812: + /* Password protect 2 register */ + NVRAM_lock ^= 0x02; + break; + case 0x0814: + /* L2 invalidate register: don't care */ + break; + case 0x081C: + /* system control register */ + syscontrol = val; + break; + case 0x0850: + /* I/O map type register */ + if (val & 0x80) { + printf("No support for non-continuous I/O map mode\n"); + abort(); + } + break; + default: + break; + } +} + +static uint32_t PREP_io_800_readb (CPUState *env, uint32_t addr) +{ + uint32_t retval = 0xFF; + + switch (addr) { + case 0x0092: + /* Special port 92 */ + retval = 0x40; + break; + case 0x080C: + /* Equipment present register: + * no L2 cache + * no upgrade processor + * no cards in PCI slots + * SCSI fuse is bad + */ + retval = 0xFC; + break; + case 0x0818: + /* Keylock */ + retval = 0x00; + break; + case 0x081C: + /* system control register + * 7 - 6 / 1 - 0: L2 cache enable + */ + retval = syscontrol; + break; + case 0x0823: + /* */ + retval = 0x03; /* no L2 cache */ + break; + case 0x0850: + /* I/O map type register */ + retval = 0x00; + break; + default: + break; + } + + return retval; +} + +/* M48T59 NVRAM/RTC emulation */ +static uint8_t NVRAM[NVRAM_SIZE]; + +/* RTC */ +static time_t time_offset; + +time_t get_time (void) +{ + return time(NULL) + time_offset; +} + +void set_time_offset (time_t new_time) +{ + time_t now = time(NULL); + + time_offset = new_time - now; +} + +static void NVRAM_init (void) +{ + /* NVRAM header */ + /* 0x00: NVRAM size in kB */ + NVRAM[0x00] = (NVRAM_SIZE >> 12) & 0xFF; + NVRAM[0x01] = (NVRAM_SIZE >> 10) & 0xFF; + /* 0x02: NVRAM version */ + NVRAM[0x02] = 0x01; + /* 0x03: NVRAM revision */ + NVRAM[0x03] = 0x00; + /* 0x04: checksum 0 => OS area */ + /* 0x06: checksum of config area */ + /* 0x08: last OS */ + NVRAM[0x08] = 0x00; /* Unknown */ + /* 0x09: endian */ + NVRAM[0x09] = 'B'; + /* 0x0B: PM mode */ + NVRAM[0x0B] = 0x00; + /* Restart block description record */ + /* 0x0C: restart block version */ + NVRAM[0x0C] = 0x00; + NVRAM[0x0D] = 0x01; + /* 0x0E: restart block revision */ + NVRAM[0x0E] = 0x00; + NVRAM[0x0F] = 0x00; + /* 0x1C: checksum of restart block */ + /* 0x20: restart address */ + NVRAM[0x20] = 0x00; + NVRAM[0x21] = 0x00; + NVRAM[0x22] = 0x00; + NVRAM[0x23] = 0x00; + /* 0x24: save area address */ + NVRAM[0x24] = 0x00; + NVRAM[0x25] = 0x00; + NVRAM[0x26] = 0x00; + NVRAM[0x27] = 0x00; + /* 0x28: save area length */ + NVRAM[0x28] = 0x00; + NVRAM[0x29] = 0x00; + NVRAM[0x2A] = 0x00; + NVRAM[0x2B] = 0x00; + /* Security section */ + /* Set all to zero */ + /* 0xC4: pointer to global environment area */ + NVRAM[0xC4] = 0x00; + NVRAM[0xC5] = 0x00; + NVRAM[0xC6] = 0x01; + NVRAM[0xC7] = 0x00; + /* 0xC8: size of global environment area */ + NVRAM[0xC8] = 0x00; + NVRAM[0xC9] = 0x00; + NVRAM[0xCA] = 0x07; + NVRAM[0xCB] = 0x00; + /* 0xD4: pointer to configuration area */ + NVRAM[0xD4] = 0x00; + NVRAM[0xD5] = 0x00; + NVRAM[0xD6] = 0x08; + NVRAM[0xD7] = 0x00; + /* 0xD8: size of configuration area */ + NVRAM[0xD8] = 0x00; + NVRAM[0xD9] = 0x00; + NVRAM[0xDA] = 0x08; + NVRAM[0xDB] = 0x00; + /* 0xE8: pointer to OS specific area */ + NVRAM[0xE8] = 0x00; + NVRAM[0xE9] = 0x00; + NVRAM[0xEA] = 0x10; + NVRAM[0xEB] = 0x00; + /* 0xD8: size of OS specific area */ + NVRAM[0xEC] = 0x00; + NVRAM[0xED] = 0x00; + NVRAM[0xEE] = 0x0F; + NVRAM[0xEF] = 0xF0; + /* CRC */ + /* RTC init */ + NVRAM[0x1FFC] = 0x50; +} + +static uint16_t NVRAM_addr; + +/* Direct access to NVRAM */ +void NVRAM_write (CPUState *env, uint32_t addr, uint32_t val) +{ + switch (addr) { + case 0x1FF0: + /* flags register */ + break; + case 0x1FF1: + /* unused */ + break; + case 0x1FF2: + /* alarm seconds */ + break; + case 0x1FF3: + /* alarm minutes */ + break; + case 0x1FF4: + /* alarm hours */ + break; + case 0x1FF5: + /* alarm date */ + break; + case 0x1FF6: + /* interrupts */ + break; + case 0x1FF7: + /* watchdog */ + break; + case 0x1FF8: + /* control */ + break; + case 0x1FF9: + /* seconds (BCD) */ + break; + case 0x1FFA: + /* minutes (BCD) */ + break; + case 0x1FFB: + /* hours (BCD) */ + break; + case 0x1FFC: + /* day of the week / century */ + NVRAM[0x1FFC] = val & 0x50; + break; + case 0x1FFD: + /* date */ + break; + case 0x1FFE: + /* month */ + break; + case 0x1FFF: + /* year */ + break; + default: + if (addr < NVRAM_SIZE) + NVRAM[addr] = val & 0xFF; + break; + } +} + +uint32_t NVRAM_read (CPUState *env, uint32_t addr) +{ + struct tm tm; + time_t t; + uint32_t retval = 0xFF; + + switch (addr) { + case 0x1FF0: + /* flags register */ + break; + case 0x1FF1: + /* unused */ + break; + case 0x1FF2: + /* alarm seconds */ + break; + case 0x1FF3: + /* alarm minutes */ + break; + case 0x1FF4: + /* alarm hours */ + break; + case 0x1FF5: + /* alarm date */ + break; + case 0x1FF6: + /* interrupts */ + break; + case 0x1FF7: + /* watchdog */ + break; + case 0x1FF8: + /* control */ + break; + case 0x1FF9: + /* seconds (BCD) */ + t = get_time(); + localtime_r(&t, &tm); + retval = ((tm.tm_sec / 10) << 4) | (tm.tm_sec % 10); +// printf("return seconds=%d\n", tm.tm_sec); + break; + case 0x1FFA: + /* minutes (BCD) */ + t = get_time(); + localtime_r(&t, &tm); + retval = ((tm.tm_min / 10) << 4) | (tm.tm_min % 10); + break; + case 0x1FFB: + /* hours (BCD) */ + t = get_time(); + localtime_r(&t, &tm); + retval = ((tm.tm_hour / 10) << 4) | (tm.tm_hour % 10); + break; + case 0x1FFC: + /* day of the week / century */ + t = get_time(); + localtime_r(&t, &tm); + retval = (NVRAM[0x1FFC] & 0x50) | tm.tm_wday; + break; + case 0x1FFD: + /* date */ + t = get_time(); + localtime_r(&t, &tm); + retval = ((tm.tm_mday / 10) << 4) | (tm.tm_mday % 10); + break; + case 0x1FFE: + /* month */ + t = get_time(); + localtime_r(&t, &tm); + retval = ((tm.tm_mon / 10) << 4) | (tm.tm_mon % 10); + break; + case 0x1FFF: + /* year */ + t = get_time(); + localtime_r(&t, &tm); + retval = ((tm.tm_year / 10) << 4) | (tm.tm_year % 10); + break; + default: + if (NVRAM_addr < NVRAM_SIZE) + retval = NVRAM[NVRAM_addr]; + break; + } + + return retval; +} + +/* IO access to NVRAM */ +static void NVRAM_writeb (CPUState *env, uint32_t addr, uint32_t val) +{ + switch (addr) { + case 0x74: + NVRAM_addr &= ~0x00FF; + NVRAM_addr |= val; + break; + case 0x75: + NVRAM_addr &= ~0xFF00; + NVRAM_addr |= val << 8; + break; + case 0x77: + NVRAM_write(env, NVRAM_addr, val); + NVRAM_addr = 0x0000; + break; + default: + break; + } +} + +static uint32_t NVRAM_readb (CPUState *env, uint32_t addr) +{ + if (addr == 0x77) + return NVRAM_read(env, NVRAM_addr); + + return 0xFF; +} + +int load_initrd (const char *filename, uint8_t *addr) +{ + int fd, size; + + printf("Load initrd\n"); + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + size = read(fd, addr, 16 * 1024 * 1024); + if (size < 0) + goto fail; + close(fd); + printf("Load initrd: %d\n", size); + return size; + fail: + close(fd); + printf("Load initrd failed\n"); + return -1; +} + +/* Quick hack for PPC memory infos... */ +static void put_long (void *addr, uint32_t l) +{ + char *pos = addr; + pos[0] = (l >> 24) & 0xFF; + pos[1] = (l >> 16) & 0xFF; + pos[2] = (l >> 8) & 0xFF; + pos[3] = l & 0xFF; +} + +/* bootloader infos are in the form: + * uint32_t TAG + * uint32_t TAG_size (from TAG to next TAG). + * datas + * .... + */ +#if !defined (USE_OPEN_FIRMWARE) +static void *set_bootinfo_tag (void *addr, uint32_t tag, uint32_t size, + void *data) +{ + char *pos = addr; + + put_long(pos, tag); + pos += 4; + put_long(pos, size + 8); + pos += 4; + memcpy(pos, data, size); + pos += size; + + return pos; +} +#endif + +typedef struct boot_dev_t { + const unsigned char *name; + int major; + int minor; +} boot_dev_t; + +static boot_dev_t boot_devs[] = +{ + { "/dev/fd0", 2, 0, }, + { "/dev/fd1", 2, 1, }, + { "/dev/hda1", 3, 1, }, +// { "/dev/ide/host0/bus0/target0/lun0/part1", 3, 1, }, + { "/dev/hdc", 22, 0, }, + { "/dev/ram0 init=/linuxrc", 1, 0, }, +}; + +/* BATU: + * BEPI : bloc virtual address + * BL : area size bits (128 kB is 0, 256 1, 512 3, ... + * Vs/Vp + * BATL: + * BPRN : bloc real address align on 4MB boundary + * WIMG : cache access mode : not used + * PP : protection bits + */ +static void setup_BAT (CPUPPCState *env, int BAT, + uint32_t virtual, uint32_t physical, + uint32_t size, int Vs, int Vp, int PP) +{ + uint32_t sz_bits, tmp_sz, align, tmp; + + sz_bits = 0; + align = 131072; + for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) { + sz_bits = (sz_bits << 1) + 1; + align = align << 1; + } + tmp = virtual & ~(align - 1); /* Align virtual area start */ + tmp |= sz_bits << 2; /* Fix BAT size */ + tmp |= Vs << 1; /* Supervisor access */ + tmp |= Vp; /* User access */ + env->DBAT[0][BAT] = tmp; + env->IBAT[0][BAT] = tmp; + tmp = physical & ~(align - 1); /* Align physical area start */ + tmp |= 0; /* Don't care about WIMG */ + tmp |= PP; /* Protection */ + env->DBAT[1][BAT] = tmp; + env->IBAT[1][BAT] = tmp; + printf("Set BATU0 to 0x%08x BATL0 to 0x%08x\n", + env->DBAT[0][BAT], env->DBAT[1][BAT]); +} + +static void VGA_printf (uint8_t *s) +{ + uint16_t *arg_ptr; + unsigned int format_width, i; + int in_format; + uint16_t arg, digit, nibble; + uint8_t c; + + arg_ptr = (uint16_t *)(&s); + in_format = 0; + format_width = 0; + while ((c = *s) != '\0') { + if (c == '%') { + in_format = 1; + format_width = 0; + } else if (in_format) { + if ((c >= '0') && (c <= '9')) { + format_width = (format_width * 10) + (c - '0'); + } else if (c == 'x') { + arg_ptr++; // increment to next arg + arg = *arg_ptr; + if (format_width == 0) + format_width = 4; + digit = format_width - 1; + for (i = 0; i < format_width; i++) { + nibble = (arg >> (4 * digit)) & 0x000f; + if (nibble <= 9) + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0'); + else + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A'); + digit--; + } + in_format = 0; + } + //else if (c == 'd') { + // in_format = 0; + // } + } else { + PPC_io_writeb(PPC_IO_BASE + 0x500, c); + } + s++; + } +} + +static void VGA_init (void) +{ + /* Basic VGA init, inspired by plex86 VGAbios */ + printf("Init VGA...\n"); + /* switch to color mode and enable CPU access 480 lines */ + PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); + /* more than 64k 3C4/04 */ + PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04); + PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02); + VGA_printf("PPC VGA BIOS...\n"); +} + +void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, + uint32_t kernel_addr, uint32_t kernel_size, + uint32_t stack_addr, int boot_device) +{ + char *p; +#if !defined (USE_OPEN_FIRMWARE) + char *tmp; + uint32_t tmpi[2]; +#endif + int PPC_io_memory; + +#if defined (USE_OPEN_FIRMWARE) + setup_memory(env, mem_size); +#endif + /* Register 64 kB of IO space */ + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); + cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); + /* Register fake IO ports for PREP */ + register_ioport_read(0x398, 2, PREP_io_read, 1); + register_ioport_write(0x398, 2, PREP_io_write, 1); + /* System control ports */ + register_ioport_write(0x0092, 0x1, PREP_io_800_writeb, 1); + register_ioport_read(0x0800, 0x52, PREP_io_800_readb, 1); + register_ioport_write(0x0800, 0x52, PREP_io_800_writeb, 1); + /* PCI intack location */ + PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); + cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); + /* NVRAM ports */ + NVRAM_init(); + register_ioport_read(0x0074, 0x04, NVRAM_readb, 1); + register_ioport_write(0x0074, 0x04, NVRAM_writeb, 1); + + /* Fake bootloader */ + env->nip = kernel_addr + (3 * sizeof(uint32_t)); + /* Set up msr according to PREP specification */ + msr_ee = 0; + msr_fp = 1; + msr_pr = 0; /* Start in supervisor mode */ + msr_me = 1; + msr_fe0 = msr_fe1 = 0; + msr_ip = 0; + msr_ir = msr_dr = 1; +// msr_sf = 0; + msr_le = msr_ile = 0; + env->gpr[1] = stack_addr; /* Let's have a stack */ + env->gpr[2] = 0; + env->gpr[8] = kernel_addr; + /* There is a bug in 2.4 kernels: + * if a decrementer exception is pending when it enables msr_ee, + * it's not ready to handle it... + */ + env->decr = 0xFFFFFFFF; + p = (void *)(phys_ram_base + kernel_addr); +#if !defined (USE_OPEN_FIRMWARE) + /* Let's register the whole memory available only in supervisor mode */ + setup_BAT(env, 0, 0x00000000, 0x00000000, mem_size, 1, 0, 2); + /* Avoid open firmware init call (to get a console) + * This will make the kernel think we are a PREP machine... + */ + put_long(p, 0xdeadc0de); + /* Build a real stack room */ + p = (void *)(phys_ram_base + stack_addr); + put_long(p, stack_addr); + p -= 32; + env->gpr[1] -= 32; + /* Pretend there are no residual data */ + env->gpr[3] = 0; +#if 1 + { + int size; + env->gpr[4] = 0x00800000; + size = load_initrd("initrd", + (void *)((uint32_t)phys_ram_base + env->gpr[4])); + if (size < 0) { + /* No initrd */ + env->gpr[4] = env->gpr[5] = 0; + } else { + env->gpr[5] = size; + boot_device = 'e'; + } + printf("Initrd loaded at 0x%08x (%d)\n", env->gpr[4], env->gpr[5]); + } +#else + env->gpr[4] = env->gpr[5] = 0; +#endif + /* We have to put bootinfos after the BSS + * The BSS starts after the kernel end. + */ +#if 0 + p = (void *)(((uint32_t)phys_ram_base + kernel_addr + + kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); +#else + p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); +#endif + if (loglevel > 0) { + fprintf(logfile, "bootinfos: %p 0x%08x\n", + p, (uint32_t)p - (uint32_t)phys_ram_base); + } else { + printf("bootinfos: %p 0x%08x\n", + p, (uint32_t)p - (uint32_t)phys_ram_base); + } + /* Command line: let's put it after bootinfos */ +#if 0 + sprintf(p + 0x1000, "console=ttyS0,9600 root=%02x%02x mem=%dM", + boot_devs[boot_device - 'a'].major, + boot_devs[boot_device - 'a'].minor, + phys_ram_size >> 20); +#else + sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM load_ramdisk=1", + boot_devs[boot_device - 'a'].name, + phys_ram_size >> 20); +#endif + env->gpr[6] = (uint32_t)p + 0x1000 - (uint32_t)phys_ram_base; + env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); + if (loglevel > 0) { + fprintf(logfile, "cmdline: %p 0x%08x [%s]\n", + p + 0x1000, env->gpr[6], p + 0x1000); + } else { + printf("cmdline: %p 0x%08x [%s]\n", + p + 0x1000, env->gpr[6], p + 0x1000); + } + /* BI_FIRST */ + p = set_bootinfo_tag(p, 0x1010, 0, 0); + /* BI_CMD_LINE */ + p = set_bootinfo_tag(p, 0x1012, env->gpr[7] - env->gpr[6], + (void *)(env->gpr[6] + (uint32_t)phys_ram_base)); + /* BI_MEM_SIZE */ + tmp = (void *)tmpi; + tmp[0] = (phys_ram_size >> 24) & 0xFF; + tmp[1] = (phys_ram_size >> 16) & 0xFF; + tmp[2] = (phys_ram_size >> 8) & 0xFF; + tmp[3] = phys_ram_size & 0xFF; + p = set_bootinfo_tag(p, 0x1017, 4, tmpi); + /* BI_INITRD */ + tmp[0] = (env->gpr[4] >> 24) & 0xFF; + tmp[1] = (env->gpr[4] >> 16) & 0xFF; + tmp[2] = (env->gpr[4] >> 8) & 0xFF; + tmp[3] = env->gpr[4] & 0xFF; + tmp[4] = (env->gpr[5] >> 24) & 0xFF; + tmp[5] = (env->gpr[5] >> 16) & 0xFF; + tmp[6] = (env->gpr[5] >> 8) & 0xFF; + tmp[7] = env->gpr[5] & 0xFF; + p = set_bootinfo_tag(p, 0x1014, 8, tmpi); + /* BI_LAST */ + p = set_bootinfo_tag(p, 0x1011, 0, 0); +#else + /* Set up MMU: + * kernel is loaded at kernel_addr and wants to be seen at 0x01000000 + */ + setup_BAT(env, 0, 0x01000000, kernel_addr, 0x00400000, 1, 0, 2); + { +#if 0 + uint32_t offset = + *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); +#else + uint32_t offset = 12; +#endif + env->nip = 0x01000000 | (kernel_addr + offset); + printf("Start address: 0x%08x\n", env->nip); + } + env->gpr[1] = env->nip + (1 << 22); + p = (void *)(phys_ram_base + stack_addr); + put_long(p - 32, stack_addr); + env->gpr[1] -= 32; + printf("Kernel starts at 0x%08x stack 0x%08x\n", env->nip, env->gpr[1]); + /* We want all lower address not to be translated */ + setup_BAT(env, 1, 0x00000000, 0x00000000, 0x010000000, 1, 1, 2); + /* We also need a BAT to access OF */ + setup_BAT(env, 2, 0xFFFE0000, mem_size - 131072, 131072, 1, 0, 1); + /* Setup OF entry point */ + { + char *p; + p = (char *)phys_ram_base + mem_size - 131072; + /* Special opcode to call OF */ + *p++ = 0x18; *p++ = 0x00; *p++ = 0x00; *p++ = 0x02; + /* blr */ + *p++ = 0x4E; *p++ = 0x80; *p++ = 0x00; *p++ = 0x20; + } + env->gpr[5] = 0xFFFE0000; + /* Register translations */ + { + OF_transl_t translations[3] = { + { 0x01000000, 0x00400000, kernel_addr, 0x00000002, }, + { 0x00000000, 0x01000000, 0x00000000, 0x00000002, }, + { 0xFFFE0000, 0x00020000, mem_size - (128 * 1024), + 0x00000001, }, + }; + OF_register_translations(3, translations); + } + /* Quite artificial, for now */ + OF_register_bus("isa", "isa"); + OF_register_serial("isa", "serial", 4, 0x3f8); + OF_register_stdio("serial", "serial"); + /* Set up RTAS service */ + RTAS_init(); + /* Command line: let's put it just over the stack */ +#if 1 + sprintf(p, "console=ttyS0,9600 root=%02x%02x mem=%dM", + boot_devs[boot_device - 'a'].major, + boot_devs[boot_device - 'a'].minor, + phys_ram_size >> 20); +#else + sprintf(p, "console=ttyS0,9600 root=%s mem=%dM ne2000=0x300,9", + boot_devs[boot_device - 'a'].name, + phys_ram_size >> 20); +#endif + OF_register_bootargs(p); +#endif +} + +void PPC_end_init (void) +{ + VGA_init(); +} diff --git a/target-ppc/op.c b/target-ppc/op.c index cf77d5ee2..28722d650 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -21,6 +21,8 @@ #include "config.h" #include "exec.h" +//#define DEBUG_OP + #define regs (env) #define Ts0 (int32_t)T0 #define Ts1 (int32_t)T1 @@ -34,7 +36,7 @@ #define FTS1 ((float)env->ft1) #define FTS2 ((float)env->ft2) -#define PPC_OP(name) void op_##name(void) +#define PPC_OP(name) void glue(op_, name)(void) #define REG 0 #include "op_template.h" @@ -145,7 +147,7 @@ PPC_OP(set_Rc0) } else { tmp = 0x02; } - set_CRn(0, tmp); + env->crf[0] = tmp; RETURN(); } @@ -161,21 +163,21 @@ PPC_OP(set_Rc0_ov) tmp = 0x02; } tmp |= xer_ov; - set_CRn(0, tmp); + env->crf[0] = tmp; RETURN(); } /* reset_Rc0 */ PPC_OP(reset_Rc0) { - set_CRn(0, 0x02 | xer_ov); + env->crf[0] = 0x02 | xer_ov; RETURN(); } /* set_Rc0_1 */ PPC_OP(set_Rc0_1) { - set_CRn(0, 0x04 | xer_ov); + env->crf[0] = 0x04 | xer_ov; RETURN(); } @@ -186,6 +188,7 @@ PPC_OP(set_Rc1) RETURN(); } +/* Constants load */ PPC_OP(set_T0) { T0 = PARAM(1); @@ -204,23 +207,50 @@ PPC_OP(set_T2) RETURN(); } -/* Update time base */ -PPC_OP(update_tb) +/* Generate exceptions */ +PPC_OP(queue_exception_err) { - T0 = regs->spr[SPR_ENCODE(268)]; - T1 = T0; - T0 += PARAM(1); - if (T0 < T1) { - T1 = regs->spr[SPR_ENCODE(269)] + 1; - regs->spr[SPR_ENCODE(269)] = T1; + do_queue_exception_err(PARAM(1), PARAM(2)); +} + +PPC_OP(queue_exception) +{ + do_queue_exception(PARAM(1)); +} + +PPC_OP(process_exceptions) +{ + if (env->exceptions != 0) { + env->nip = PARAM(1); + do_check_exception_state(); } - regs->spr[SPR_ENCODE(268)] = T0; +} + +/* Segment registers load and store with immediate index */ +PPC_OP(load_srin) +{ + T0 = regs->sr[T1 >> 28]; + RETURN(); +} + +PPC_OP(store_srin) +{ +#if defined (DEBUG_OP) + dump_store_sr(T1 >> 28); +#endif + regs->sr[T1 >> 28] = T0; + RETURN(); +} + +PPC_OP(load_sdr1) +{ + T0 = regs->sdr1; RETURN(); } -PPC_OP(raise_exception) +PPC_OP(store_sdr1) { - raise_exception(PARAM(1)); + regs->sdr1 = T0; RETURN(); } @@ -229,15 +259,16 @@ PPC_OP(exit_tb) EXIT_TB(); } +/* Load/store special registers */ PPC_OP(load_cr) { - T0 = do_load_cr(); + do_load_cr(); RETURN(); } PPC_OP(store_cr) { - do_store_cr(PARAM(1), T0); + do_store_cr(PARAM(1)); RETURN(); } @@ -257,40 +288,152 @@ PPC_OP(clear_xer_cr) PPC_OP(load_xer_bc) { - T0 = xer_bc; + T1 = xer_bc; RETURN(); } PPC_OP(load_xer) { - T0 = do_load_xer(); + do_load_xer(); RETURN(); } PPC_OP(store_xer) { - do_store_xer(T0); + do_store_xer(); RETURN(); } PPC_OP(load_msr) { - T0 = do_load_msr(); + do_load_msr(); RETURN(); } PPC_OP(store_msr) { - do_store_msr(T0); + do_store_msr(); + RETURN(); +} + +/* SPR */ +PPC_OP(load_spr) +{ + T0 = regs->spr[PARAM(1)]; + RETURN(); +} + +PPC_OP(store_spr) +{ + regs->spr[PARAM(1)] = T0; RETURN(); } PPC_OP(load_lr) { - regs->LR = PARAM(1); + T0 = regs->lr; + RETURN(); +} + +PPC_OP(store_lr) +{ + regs->lr = T0; + RETURN(); +} + +PPC_OP(load_ctr) +{ + T0 = regs->ctr; + RETURN(); +} + +PPC_OP(store_ctr) +{ + regs->ctr = T0; + RETURN(); +} + +/* Update time base */ +PPC_OP(update_tb) +{ + T0 = regs->tb[0]; + T1 = T0; + T0 += PARAM(1); +#if defined (DEBUG_OP) + dump_update_tb(PARAM(1)); +#endif + if (T0 < T1) { + T1 = regs->tb[1] + 1; + regs->tb[1] = T1; + } + regs->tb[0] = T0; + RETURN(); +} + +PPC_OP(load_tb) +{ + T0 = regs->tb[PARAM(1)]; + RETURN(); +} + +PPC_OP(store_tb) +{ + regs->tb[PARAM(1)] = T0; +#if defined (DEBUG_OP) + dump_store_tb(PARAM(1)); +#endif RETURN(); } +/* Update decrementer */ +PPC_OP(update_decr) +{ + T0 = regs->decr; + T1 = T0; + T0 -= PARAM(1); + regs->decr = T0; + if (PARAM(1) > T1) { + do_queue_exception(EXCP_DECR); + } + RETURN(); +} + +PPC_OP(store_decr) +{ + T1 = regs->decr; + regs->decr = T0; + if (Ts0 < 0 && Ts1 > 0) { + do_queue_exception(EXCP_DECR); + } + RETURN(); +} + +PPC_OP(load_ibat) +{ + T0 = regs->IBAT[PARAM(1)][PARAM(2)]; +} + +PPC_OP(store_ibat) +{ +#if defined (DEBUG_OP) + dump_store_ibat(PARAM(1), PARAM(2)); +#endif + regs->IBAT[PARAM(1)][PARAM(2)] = T0; +} + +PPC_OP(load_dbat) +{ + T0 = regs->DBAT[PARAM(1)][PARAM(2)]; +} + +PPC_OP(store_dbat) +{ +#if defined (DEBUG_OP) + dump_store_dbat(PARAM(1), PARAM(2)); +#endif + regs->DBAT[PARAM(1)][PARAM(2)] = T0; +} + /* FPSCR */ PPC_OP(load_fpscr) { @@ -313,14 +456,7 @@ PPC_OP(reset_scrfx) /* Set reservation */ PPC_OP(set_reservation) { - regs->reserve = T1 & ~0x03; - RETURN(); -} - -/* Reset reservation */ -PPC_OP(reset_reservation) -{ - regs->reserve = 0; + regs->reserve = T0 & ~0x03; RETURN(); } @@ -344,47 +480,65 @@ PPC_OP(setcrfbit) } /* Branch */ +#if 0 +#define EIP regs->nip +#define TB_DO_JUMP(name, tb, n, target) JUMP_TB(name, tb, n, target) +#else +#define TB_DO_JUMP(name, tb, n, target) regs->nip = target; +#endif + #define __PPC_OP_B(name, target) \ PPC_OP(name) \ { \ - regs->nip = (target); \ + TB_DO_JUMP(glue(op_, name), T1, 0, (target)); \ RETURN(); \ } -#define __PPC_OP_BL(name, target) \ +#define __PPC_OP_BL(name, target, link) \ PPC_OP(name) \ { \ - regs->LR = PARAM(1); \ - regs->nip = (target); \ + regs->lr = (link); \ + TB_DO_JUMP(glue(op_, name), T1, 0, (target)); \ RETURN(); \ } -#define PPC_OP_B(name, target) \ +#define PPC_OP_B(name, target, link) \ __PPC_OP_B(name, target); \ -__PPC_OP_BL(name##l, target) +__PPC_OP_BL(glue(name, l), target, link) #define __PPC_OP_BC(name, cond, target) \ PPC_OP(name) \ { \ if (cond) { \ - T0 = (target); \ + TB_DO_JUMP(glue(op_, name), T1, 1, (target)); \ } else { \ - T0 = PARAM(1); \ + TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \ } \ - regs->nip = T0; \ RETURN(); \ } #define __PPC_OP_BCL(name, cond, target) \ PPC_OP(name) \ { \ + regs->lr = PARAM(1); \ if (cond) { \ - T0 = (target); \ - regs->LR = PARAM(1); \ + TB_DO_JUMP(glue(op_, name), T1, 1, (target)); \ } else { \ - T0 = PARAM(1); \ + TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \ + } \ + RETURN(); \ +} + +#define __PPC_OP_BCLRL(name, cond, target) \ +PPC_OP(name) \ +{ \ + T2 = (target); \ + regs->lr = PARAM(1); \ + if (cond) { \ + TB_DO_JUMP(glue(op_, name), T1, 1, T2); \ + } else { \ + TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \ } \ - regs->nip = T0; \ RETURN(); \ } @@ -396,48 +550,56 @@ __PPC_OP_BCL(namel, cond, target) #define PPC_OP_BC(name, cond) \ _PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2)) -PPC_OP_B(b, PARAM(1)); -PPC_OP_BC(ctr, (regs->CTR != 0)); -PPC_OP_BC(ctr_true, (regs->CTR != 0 && (T0 & PARAM(3)) != 0)); -PPC_OP_BC(ctr_false, (regs->CTR != 0 && (T0 & PARAM(3)) == 0)); -PPC_OP_BC(ctrz, (regs->CTR == 0)); -PPC_OP_BC(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(3)) != 0)); -PPC_OP_BC(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(3)) == 0)); +PPC_OP_B(b, PARAM(1), PARAM(2)); +PPC_OP_BC(ctr, (regs->ctr != 0)); +PPC_OP_BC(ctr_true, (regs->ctr != 0 && (T0 & PARAM(3)) != 0)); +PPC_OP_BC(ctr_false, (regs->ctr != 0 && (T0 & PARAM(3)) == 0)); +PPC_OP_BC(ctrz, (regs->ctr == 0)); +PPC_OP_BC(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(3)) != 0)); +PPC_OP_BC(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(3)) == 0)); PPC_OP_BC(true, ((T0 & PARAM(3)) != 0)); PPC_OP_BC(false, ((T0 & PARAM(3)) == 0)); /* Branch to CTR */ #define PPC_OP_BCCTR(name, cond) \ -_PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->CTR & ~0x03) - -PPC_OP_B(bctr, regs->CTR & ~0x03); -PPC_OP_BCCTR(ctr, (regs->CTR != 0)); -PPC_OP_BCCTR(ctr_true, (regs->CTR != 0 && (T0 & PARAM(2)) != 0)); -PPC_OP_BCCTR(ctr_false, (regs->CTR != 0 && (T0 & PARAM(2)) == 0)); -PPC_OP_BCCTR(ctrz, (regs->CTR == 0)); -PPC_OP_BCCTR(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(2)) != 0)); -PPC_OP_BCCTR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0)); +_PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->ctr & ~0x03) + +PPC_OP_B(bctr, regs->ctr & ~0x03, PARAM(1)); +PPC_OP_BCCTR(ctr, (regs->ctr != 0)); +PPC_OP_BCCTR(ctr_true, (regs->ctr != 0 && (T0 & PARAM(2)) != 0)); +PPC_OP_BCCTR(ctr_false, (regs->ctr != 0 && (T0 & PARAM(2)) == 0)); +PPC_OP_BCCTR(ctrz, (regs->ctr == 0)); +PPC_OP_BCCTR(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(2)) != 0)); +PPC_OP_BCCTR(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(2)) == 0)); PPC_OP_BCCTR(true, ((T0 & PARAM(2)) != 0)); PPC_OP_BCCTR(false, ((T0 & PARAM(2)) == 0)); /* Branch to LR */ #define PPC_OP_BCLR(name, cond) \ -_PPC_OP_BC(blr_##name, blrl_##name, cond, regs->LR & ~0x03) - -PPC_OP_B(blr, regs->LR & ~0x03); -PPC_OP_BCLR(ctr, (regs->CTR != 0)); -PPC_OP_BCLR(ctr_true, (regs->CTR != 0 && (T0 & PARAM(2)) != 0)); -PPC_OP_BCLR(ctr_false, (regs->CTR != 0 && (T0 & PARAM(2)) == 0)); -PPC_OP_BCLR(ctrz, (regs->CTR == 0)); -PPC_OP_BCLR(ctrz_true, (regs->CTR == 0 && (T0 & PARAM(2)) != 0)); -PPC_OP_BCLR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0)); +__PPC_OP_BC(blr_##name, cond, regs->lr & ~0x03); \ +__PPC_OP_BCLRL(blrl_##name, cond, regs->lr & ~0x03) + +__PPC_OP_B(blr, regs->lr & ~0x03); +PPC_OP(blrl) +{ + T0 = regs->lr & ~0x03; + regs->lr = PARAM(1); + TB_DO_JUMP(op_blrl, T1, 0, T0); + RETURN(); +} +PPC_OP_BCLR(ctr, (regs->ctr != 0)); +PPC_OP_BCLR(ctr_true, (regs->ctr != 0 && (T0 & PARAM(2)) != 0)); +PPC_OP_BCLR(ctr_false, (regs->ctr != 0 && (T0 & PARAM(2)) == 0)); +PPC_OP_BCLR(ctrz, (regs->ctr == 0)); +PPC_OP_BCLR(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(2)) != 0)); +PPC_OP_BCLR(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(2)) == 0)); PPC_OP_BCLR(true, ((T0 & PARAM(2)) != 0)); PPC_OP_BCLR(false, ((T0 & PARAM(2)) == 0)); /* CTR maintenance */ PPC_OP(dec_ctr) { - regs->CTR--; + regs->ctr--; RETURN(); } @@ -1077,7 +1239,7 @@ PPC_OP(slw) /* shift right algebraic word */ PPC_OP(sraw) { - Ts0 = do_sraw(Ts0, T1); + do_sraw(); RETURN(); } @@ -1106,313 +1268,280 @@ PPC_OP(srw) } /*** Floating-Point arithmetic ***/ - -/*** Floating-Point multiply-and-add ***/ - -/*** Floating-Point round & convert ***/ - -/*** Floating-Point compare ***/ - -/*** Floating-Point status & ctrl register ***/ - -/*** Integer load ***/ -#define ld16x(x) s_ext16(ld16(x)) -#define PPC_ILD_OPX(name, op) \ -PPC_OP(l##name##x_z) \ -{ \ - T1 = op(T0); \ - RETURN(); \ -} \ -PPC_OP(l##name##x) \ -{ \ - T0 += T1; \ - T1 = op(T0); \ - RETURN(); \ -} - -#define PPC_ILD_OP(name, op) \ -PPC_OP(l##name##_z) \ -{ \ - T1 = op(SPARAM(1)); \ - RETURN(); \ -} \ -PPC_OP(l##name) \ -{ \ - T0 += SPARAM(1); \ - T1 = op(T0); \ - RETURN(); \ -} \ -PPC_ILD_OPX(name, op) - -PPC_ILD_OP(bz, ld8); -PPC_ILD_OP(ha, ld16x); -PPC_ILD_OP(hz, ld16); -PPC_ILD_OP(wz, ld32); - -/*** Integer store ***/ -#define PPC_IST_OPX(name, op) \ -PPC_OP(st##name##x_z) \ -{ \ - op(T0, T1); \ - RETURN(); \ -} \ -PPC_OP(st##name##x) \ -{ \ - T0 += T1; \ - op(T0, T2); \ - RETURN(); \ -} - -#define PPC_IST_OP(name, op) \ -PPC_OP(st##name##_z) \ -{ \ - op(SPARAM(1), T0); \ - RETURN(); \ -} \ -PPC_OP(st##name) \ -{ \ - T0 += SPARAM(1); \ - op(T0, T1); \ - RETURN(); \ -} \ -PPC_IST_OPX(name, op); - -PPC_IST_OP(b, st8); -PPC_IST_OP(h, st16); -PPC_IST_OP(w, st32); - -/*** Integer load and store with byte reverse ***/ -PPC_ILD_OPX(hbr, ld16r); -PPC_ILD_OPX(wbr, ld32r); -PPC_IST_OPX(hbr, st16r); -PPC_IST_OPX(wbr, st32r); - -/*** Integer load and store multiple ***/ -PPC_OP(lmw) +/* fadd - fadd. */ +PPC_OP(fadd) { - do_lmw(PARAM(1), SPARAM(2) + T0); + FT0 += FT1; RETURN(); } -PPC_OP(stmw) +/* fadds - fadds. */ +PPC_OP(fadds) { - do_stmw(PARAM(1), SPARAM(2) + T0); + FTS0 += FTS1; RETURN(); } -/*** Integer load and store strings ***/ -PPC_OP(lswi) +/* fsub - fsub. */ +PPC_OP(fsub) { - do_lsw(PARAM(1), PARAM(2), T0); + FT0 -= FT1; RETURN(); } -PPC_OP(lswx) +/* fsubs - fsubs. */ +PPC_OP(fsubs) { - do_lsw(PARAM(1), T0, T1 + T2); + FTS0 -= FTS1; RETURN(); } -PPC_OP(stswi_z) +/* fmul - fmul. */ +PPC_OP(fmul) { - do_stsw(PARAM(1), PARAM(2), 0); + FT0 *= FT1; RETURN(); } -PPC_OP(stswi) +/* fmuls - fmuls. */ +PPC_OP(fmuls) { - do_stsw(PARAM(1), PARAM(2), T0); + FTS0 *= FTS1; RETURN(); } -PPC_OP(stswx_z) +/* fdiv - fdiv. */ +PPC_OP(fdiv) { - do_stsw(PARAM(1), T0, T1); + FT0 /= FT1; RETURN(); } -PPC_OP(stswx) +/* fdivs - fdivs. */ +PPC_OP(fdivs) { - do_stsw(PARAM(1), T0, T1 + T2); + FTS0 /= FTS1; RETURN(); } -/* SPR */ -PPC_OP(load_spr) +/* fsqrt - fsqrt. */ +PPC_OP(fsqrt) { - T0 = regs->spr[PARAM(1)]; + do_fsqrt(); + RETURN(); } -PPC_OP(store_spr) +/* fsqrts - fsqrts. */ +PPC_OP(fsqrts) { - regs->spr[PARAM(1)] = T0; + do_fsqrts(); + RETURN(); } -/*** Floating-point store ***/ - -PPC_OP(stfd_z_FT0) +/* fres - fres. */ +PPC_OP(fres) { - stfq((void *)SPARAM(1), FT0); + do_fres(); + RETURN(); } -PPC_OP(stfd_FT0) +/* frsqrte - frsqrte. */ +PPC_OP(frsqrte) { - T0 += SPARAM(1); - stfq((void *)T0, FT0); + do_fsqrte(); + RETURN(); } -PPC_OP(stfdx_z_FT0) +/* fsel - fsel. */ +PPC_OP(fsel) { - stfq((void *)T0, FT0); + do_fsel(); + RETURN(); } -PPC_OP(stfdx_FT0) +/*** Floating-Point multiply-and-add ***/ +/* fmadd - fmadd. */ +PPC_OP(fmadd) { - T0 += T1; - stfq((void *)T0, FT0); + FT0 = (FT0 * FT1) + FT2; + RETURN(); } -PPC_OP(stfs_z_FT0) +/* fmadds - fmadds. */ +PPC_OP(fmadds) { - float tmp = FT0; - stfl((void *)SPARAM(1), tmp); + FTS0 = (FTS0 * FTS1) + FTS2; + RETURN(); } -PPC_OP(stfs_FT0) +/* fmsub - fmsub. */ +PPC_OP(fmsub) { - float tmp = FT0; - T0 += SPARAM(1); - stfl((void *)T0, tmp); + FT0 = (FT0 * FT1) - FT2; + RETURN(); } -PPC_OP(stfsx_z_FT0) +/* fmsubs - fmsubs. */ +PPC_OP(fmsubs) { - float tmp = FT0; - stfl((void *)T0, tmp); + FTS0 = (FTS0 * FTS1) - FTS2; + RETURN(); } -PPC_OP(stfsx_FT0) +/* fnmadd - fnmadd. - fnmadds - fnmadds. */ +PPC_OP(fnmadd) { - float tmp = FT0; - T0 += T1; - stfl((void *)T0, tmp); + FT0 = -((FT0 * FT1) + FT2); + RETURN(); } -/*** Floating-point load ***/ -PPC_OP(lfd_z_FT0) +/* fnmadds - fnmadds. */ +PPC_OP(fnmadds) { - FT0 = ldfq((void *)SPARAM(1)); + FTS0 = -((FTS0 * FTS1) + FTS2); + RETURN(); } -PPC_OP(lfd_FT0) +/* fnmsub - fnmsub. */ +PPC_OP(fnmsub) { - T0 += SPARAM(1); - FT0 = ldfq((void *)T0); + FT0 = -((FT0 * FT1) - FT2); + RETURN(); } -PPC_OP(lfdx_z_FT0) +/* fnmsubs - fnmsubs. */ +PPC_OP(fnmsubs) { - FT0 = ldfq((void *)T0); + FTS0 = -((FTS0 * FTS1) - FTS2); + RETURN(); } -PPC_OP(lfdx_FT0) +/*** Floating-Point round & convert ***/ +/* frsp - frsp. */ +PPC_OP(frsp) { - T0 += T1; - FT0 = ldfq((void *)T0); + FT0 = FTS0; + RETURN(); } -PPC_OP(lfs_z_FT0) +/* fctiw - fctiw. */ +PPC_OP(fctiw) { - float tmp = ldfl((void *)SPARAM(1)); - FT0 = tmp; + do_fctiw(); + RETURN(); } -PPC_OP(lfs_FT0) +/* fctiwz - fctiwz. */ +PPC_OP(fctiwz) { - float tmp; - T0 += SPARAM(1); - tmp = ldfl((void *)T0); - FT0 = tmp; + do_fctiwz(); + RETURN(); } -PPC_OP(lfsx_z_FT0) + +/*** Floating-Point compare ***/ +/* fcmpu */ +PPC_OP(fcmpu) { - float tmp; - tmp = ldfl((void *)T0); - FT0 = tmp; + do_fcmpu(); + RETURN(); } -PPC_OP(lfsx_FT0) +/* fcmpo */ +PPC_OP(fcmpo) { - float tmp; - T0 += T1; - tmp = ldfl((void *)T0); - FT0 = tmp; + do_fcmpo(); + RETURN(); } -PPC_OP(lwarx_z) +/*** Floating-point move ***/ +/* fabs */ +PPC_OP(fabs) { - T1 = ld32(T0); - regs->reserve = T0; + do_fabs(); RETURN(); } -PPC_OP(lwarx) +/* fnabs */ +PPC_OP(fnabs) { - T0 += T1; - T1 = ld32(T0); - regs->reserve = T0; + do_fnabs(); RETURN(); } -PPC_OP(stwcx_z) +/* fneg */ +PPC_OP(fneg) { - if (regs->reserve != T0) { - env->crf[0] = xer_ov; - } else { - st32(T0, T1); - env->crf[0] = xer_ov | 0x02; - } - regs->reserve = 0; + FT0 = -FT0; RETURN(); } -PPC_OP(stwcx) +/* Load and store */ +#if defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _raw +#include "op_mem.h" +#else +#define MEMSUFFIX _user +#include "op_mem.h" + +#define MEMSUFFIX _kernel +#include "op_mem.h" +#endif + +/* Return from interrupt */ +PPC_OP(rfi) { - T0 += T1; - if (regs->reserve != (T0 & ~0x03)) { - env->crf[0] = xer_ov; - } else { - st32(T0, T2); - env->crf[0] = xer_ov | 0x02; + T0 = regs->spr[SRR1] & ~0xFFFF0000; + do_store_msr(); + do_tlbia(); + dump_rfi(); + regs->nip = regs->spr[SRR0] & ~0x00000003; + if (env->exceptions != 0) { + do_check_exception_state(); } - regs->reserve = 0; RETURN(); } -PPC_OP(dcbz_z) +/* Trap word */ +PPC_OP(tw) { - do_dcbz(); + if ((Ts0 < Ts1 && (PARAM(1) & 0x10)) || + (Ts0 > Ts1 && (PARAM(1) & 0x08)) || + (Ts0 == Ts1 && (PARAM(1) & 0x04)) || + (T0 < T1 && (PARAM(1) & 0x02)) || + (T0 > T1 && (PARAM(1) & 0x01))) + do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP); RETURN(); } -PPC_OP(dcbz) +PPC_OP(twi) { - T0 += T1; - do_dcbz(); + if ((Ts0 < SPARAM(1) && (PARAM(2) & 0x10)) || + (Ts0 > SPARAM(1) && (PARAM(2) & 0x08)) || + (Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) || + (T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) || + (T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01))) + do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP); RETURN(); } /* Instruction cache block invalidate */ -PPC_OP(icbi_z) +PPC_OP(icbi) { do_icbi(); RETURN(); } -PPC_OP(icbi) +/* tlbia */ +PPC_OP(tlbia) { - T0 += T1; - do_icbi(); + do_tlbia(); + RETURN(); +} + +/* tlbie */ +PPC_OP(tlbie) +{ + do_tlbie(); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c new file mode 100644 index 000000000..5d02dfabe --- /dev/null +++ b/target-ppc/op_helper.c @@ -0,0 +1,445 @@ +/* + * PPC emulation helpers for qemu. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * 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 +#include "exec.h" + +#if defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _raw +#include "op_helper_mem.h" +#else +#define MEMSUFFIX _user +#include "op_helper_mem.h" +#define MEMSUFFIX _kernel +#include "op_helper_mem.h" +#endif + +/*****************************************************************************/ +/* Exceptions processing helpers */ +void do_queue_exception_err (uint32_t exception, int error_code) +{ + /* Queue real PPC exceptions */ + if (exception < EXCP_PPC_MAX) { + env->exceptions |= 1 << exception; + env->errors[exception] = error_code; + } else { + /* Preserve compatibility with qemu core */ + env->exceptions |= 1; + env->exception_index = exception; + env->error_code = error_code; + } +} + +void do_queue_exception (uint32_t exception) +{ + do_queue_exception_err(exception, 0); +} + +void do_check_exception_state (void) +{ + if ((env->exceptions & 1) == 1 || check_exception_state(env)) { + env->exceptions &= ~1; + cpu_loop_exit(); + } +} + +/*****************************************************************************/ +/* Helpers for "fat" micro operations */ +/* Special registers load and store */ +void do_load_cr (void) +{ + T0 = (env->crf[0] << 28) | + (env->crf[1] << 24) | + (env->crf[2] << 20) | + (env->crf[3] << 16) | + (env->crf[4] << 12) | + (env->crf[5] << 8) | + (env->crf[6] << 4) | + (env->crf[7] << 0); +} + +void do_store_cr (uint32_t mask) +{ + int i, sh; + + for (i = 0, sh = 7; i < 8; i++, sh --) { + if (mask & (1 << sh)) + env->crf[i] = (T0 >> (sh * 4)) & 0xF; + } +} + +void do_load_xer (void) +{ + T0 = (xer_so << XER_SO) | + (xer_ov << XER_OV) | + (xer_ca << XER_CA) | + (xer_bc << XER_BC); +} + +void do_store_xer (void) +{ + xer_so = (T0 >> XER_SO) & 0x01; + xer_ov = (T0 >> XER_OV) & 0x01; + xer_ca = (T0 >> XER_CA) & 0x01; + xer_bc = (T0 >> XER_BC) & 0x1f; +} + +void do_load_msr (void) +{ + T0 = (msr_pow << MSR_POW) | + (msr_ile << MSR_ILE) | + (msr_ee << MSR_EE) | + (msr_pr << MSR_PR) | + (msr_fp << MSR_FP) | + (msr_me << MSR_ME) | + (msr_fe0 << MSR_FE0) | + (msr_se << MSR_SE) | + (msr_be << MSR_BE) | + (msr_fe1 << MSR_FE1) | + (msr_ip << MSR_IP) | + (msr_ir << MSR_IR) | + (msr_dr << MSR_DR) | + (msr_ri << MSR_RI) | + (msr_le << MSR_LE); +} + +void do_store_msr (void) +{ + if (((T0 >> MSR_IR) & 0x01) != msr_ir || + ((T0 >> MSR_DR) & 0x01) != msr_dr || + ((T0 >> MSR_PR) & 0x01) != msr_pr) { + /* Flush all tlb when changing translation mode or privilege level */ + do_tlbia(); + } +#if 0 + if ((T0 >> MSR_IP) & 0x01) { + printf("Halting CPU. Stop emulation\n"); + do_queue_exception(EXCP_HLT); + cpu_loop_exit(); + } +#endif + msr_pow = (T0 >> MSR_POW) & 0x03; + msr_ile = (T0 >> MSR_ILE) & 0x01; + msr_ee = (T0 >> MSR_EE) & 0x01; + msr_pr = (T0 >> MSR_PR) & 0x01; + msr_fp = (T0 >> MSR_FP) & 0x01; + msr_me = (T0 >> MSR_ME) & 0x01; + msr_fe0 = (T0 >> MSR_FE0) & 0x01; + msr_se = (T0 >> MSR_SE) & 0x01; + msr_be = (T0 >> MSR_BE) & 0x01; + msr_fe1 = (T0 >> MSR_FE1) & 0x01; + msr_ip = (T0 >> MSR_IP) & 0x01; + msr_ir = (T0 >> MSR_IR) & 0x01; + msr_dr = (T0 >> MSR_DR) & 0x01; + msr_ri = (T0 >> MSR_RI) & 0x01; + msr_le = (T0 >> MSR_LE) & 0x01; +} + +/* shift right arithmetic helper */ +void do_sraw (void) +{ + int32_t ret; + + xer_ca = 0; + if (T1 & 0x20) { + ret = (-1) * (T0 >> 31); + if (ret < 0) + xer_ca = 1; + } else { + ret = (int32_t)T0 >> (T1 & 0x1f); + if (ret < 0 && ((int32_t)T0 & ((1 << T1) - 1)) != 0) + xer_ca = 1; + } + (int32_t)T0 = ret; +} + +/* Floating point operations helpers */ +void do_load_fpscr (void) +{ + /* The 32 MSB of the target fpr are undefined. + * They'll be zero... + */ + union { + double d; + struct { + uint32_t u[2]; + } s; + } u; + int i; + + u.s.u[0] = 0; + u.s.u[1] = 0; + for (i = 0; i < 8; i++) + u.s.u[1] |= env->fpscr[i] << (4 * i); + FT0 = u.d; +} + +void do_store_fpscr (uint32_t mask) +{ + /* + * We use only the 32 LSB of the incoming fpr + */ + union { + double d; + struct { + uint32_t u[2]; + } s; + } u; + int i; + + u.d = FT0; + if (mask & 0x80) + env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[1] >> 28) & ~0x9); + for (i = 1; i < 7; i++) { + if (mask & (1 << (7 - i))) + env->fpscr[i] = (u.s.u[1] >> (4 * (7 - i))) & 0xF; + } + /* TODO: update FEX & VX */ + /* Set rounding mode */ + switch (env->fpscr[0] & 0x3) { + case 0: + /* Best approximation (round to nearest) */ + fesetround(FE_TONEAREST); + break; + case 1: + /* Smaller magnitude (round toward zero) */ + fesetround(FE_TOWARDZERO); + break; + case 2: + /* Round toward +infinite */ + fesetround(FE_UPWARD); + break; + case 3: + /* Round toward -infinite */ + fesetround(FE_DOWNWARD); + break; + } +} + +void do_fctiw (void) +{ + union { + double d; + uint64_t i; + } *p = (void *)&FT1; + + if (FT0 > (double)0x7FFFFFFF) + p->i = 0x7FFFFFFFULL << 32; + else if (FT0 < -(double)0x80000000) + p->i = 0x80000000ULL << 32; + else + p->i = 0; + p->i |= (uint32_t)FT0; + FT0 = p->d; +} + +void do_fctiwz (void) +{ + union { + double d; + uint64_t i; + } *p = (void *)&FT1; + int cround = fegetround(); + + fesetround(FE_TOWARDZERO); + if (FT0 > (double)0x7FFFFFFF) + p->i = 0x7FFFFFFFULL << 32; + else if (FT0 < -(double)0x80000000) + p->i = 0x80000000ULL << 32; + else + p->i = 0; + p->i |= (uint32_t)FT0; + FT0 = p->d; + fesetround(cround); +} + +void do_fsqrt (void) +{ + FT0 = sqrt(FT0); +} + +void do_fsqrts (void) +{ + FT0 = (float)sqrt((float)FT0); +} + +void do_fres (void) +{ + FT0 = 1.0 / FT0; +} + +void do_fsqrte (void) +{ + FT0 = 1.0 / sqrt(FT0); +} + +void do_fsel (void) +{ + if (FT0 >= 0) + FT0 = FT2; + else + FT0 = FT1; +} + +void do_fcmpu (void) +{ + env->fpscr[4] &= ~0x1; + if (isnan(FT0) || isnan(FT1)) { + T0 = 0x01; + env->fpscr[4] |= 0x1; + env->fpscr[6] |= 0x1; + } else if (FT0 < FT1) { + T0 = 0x08; + } else if (FT0 > FT1) { + T0 = 0x04; + } else { + T0 = 0x02; + } + env->fpscr[3] |= T0; +} + +void do_fcmpo (void) +{ + env->fpscr[4] &= ~0x1; + if (isnan(FT0) || isnan(FT1)) { + T0 = 0x01; + env->fpscr[4] |= 0x1; + /* I don't know how to test "quiet" nan... */ + if (0 /* || ! quiet_nan(...) */) { + env->fpscr[6] |= 0x1; + if (!(env->fpscr[1] & 0x8)) + env->fpscr[4] |= 0x8; + } else { + env->fpscr[4] |= 0x8; + } + } else if (FT0 < FT1) { + T0 = 0x08; + } else if (FT0 > FT1) { + T0 = 0x04; + } else { + T0 = 0x02; + } + env->fpscr[3] |= T0; +} + +void do_fabs (void) +{ + FT0 = fabsl(FT0); +} + +void do_fnabs (void) +{ + FT0 = -fabsl(FT0); +} + +/* Instruction cache invalidation helper */ +void do_icbi (void) +{ + // tb_invalidate_page(T0); +} + +/* TLB invalidation helpers */ +void do_tlbia (void) +{ + tlb_flush(env); +} + +void do_tlbie (void) +{ + tlb_flush_page(env, T0); +} + +/*****************************************************************************/ +/* Special helpers for debug */ +void dump_rfi (void) +{ +#if 0 + printf("Return from interrupt\n"); + printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x\n", + env->nip, env->lr, env->ctr, + (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | (msr_ee << MSR_EE) | + (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_me << MSR_ME) | + (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | (msr_be << MSR_BE) | + (msr_fe1 << MSR_FE1) | (msr_ip << MSR_IP) | (msr_ir << MSR_IR) | + (msr_dr << MSR_DR) | (msr_ri << MSR_RI) | (msr_le << MSR_LE)); + { + int i; + for (i = 0; i < 32; i++) { + if ((i & 7) == 0) + printf("GPR%02d:", i); + printf(" %08x", env->gpr[i]); + if ((i & 7) == 7) + printf("\n"); + } + printf("CR: 0x"); + for (i = 0; i < 8; i++) + printf("%01x", env->crf[i]); + printf(" ["); + for (i = 0; i < 8; i++) { + char a = '-'; + if (env->crf[i] & 0x08) + a = 'L'; + else if (env->crf[i] & 0x04) + a = 'G'; + else if (env->crf[i] & 0x02) + a = 'E'; + printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); + } + printf(" ] "); + } + printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); + printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); +#endif +} + +void dump_store_sr (int srnum) +{ +#if 0 + printf("%s: reg=%d 0x%08x\n", __func__, srnum, T0); +#endif +} + +static void _dump_store_bat (char ID, int ul, int nr) +{ + printf("Set %cBAT%d%c to 0x%08x (0x%08x)\n", + ID, nr, ul == 0 ? 'u' : 'l', T0, env->nip); +} + +void dump_store_ibat (int ul, int nr) +{ + _dump_store_bat('I', ul, nr); +} + +void dump_store_dbat (int ul, int nr) +{ + _dump_store_bat('D', ul, nr); +} + +void dump_store_tb (int ul) +{ + printf("Set TB%c to 0x%08x\n", ul == 0 ? 'L' : 'U', T0); +} + +void dump_update_tb(uint32_t param) +{ +#if 0 + printf("Update TB: 0x%08x + %d => 0x%08x\n", T1, param, T0); +#endif +} + diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h new file mode 100644 index 000000000..6c2027319 --- /dev/null +++ b/target-ppc/op_helper_mem.h @@ -0,0 +1,44 @@ +void glue(do_lsw, MEMSUFFIX) (int dst) +{ + uint32_t tmp; + int sh; + + if (loglevel > 0) { + fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", + __func__, T0, T1, dst); + } + for (; T1 > 3; T1 -= 4, T0 += 4) { + ugpr(dst++) = glue(_ldl, MEMSUFFIX)((void *)T0, ACCESS_INT); + if (dst == 32) + dst = 0; + } + if (T1 > 0) { + tmp = 0; + for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { + tmp |= glue(_ldub, MEMSUFFIX)((void *)T0, ACCESS_INT) << sh; + } + ugpr(dst) = tmp; + } +} + +void glue(do_stsw, MEMSUFFIX) (int src) +{ + int sh; + + if (loglevel > 0) { + fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", + __func__, T0, T1, src); + } + for (; T1 > 3; T1 -= 4, T0 += 4) { + glue(_stl, MEMSUFFIX)((void *)T0, ugpr(src++), ACCESS_INT); + if (src == 32) + src = 0; + } + if (T1 > 0) { + for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) + glue(_stb, MEMSUFFIX)((void *)T0, (ugpr(src) >> sh) & 0xFF, + ACCESS_INT); + } +} + +#undef MEMSUFFIX diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h new file mode 100644 index 000000000..2a50f84f4 --- /dev/null +++ b/target-ppc/op_mem.h @@ -0,0 +1,187 @@ +/* External helpers */ +void glue(do_lsw, MEMSUFFIX) (int dst); +void glue(do_stsw, MEMSUFFIX) (int src); + +/* Internal helpers for sign extension and byte-reverse */ +static inline uint32_t glue(_ld16x, MEMSUFFIX) (void *EA, int type) +{ + return s_ext16(glue(_lduw, MEMSUFFIX)(EA, type)); +} + +static inline uint16_t glue(_ld16r, MEMSUFFIX) (void *EA, int type) +{ + uint16_t tmp = glue(_lduw, MEMSUFFIX)(EA, type); + return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); +} + +static inline uint32_t glue(_ld32r, MEMSUFFIX) (void *EA, int type) +{ + uint32_t tmp = glue(_ldl, MEMSUFFIX)(EA, type); + return ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | + ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); +} + +static inline void glue(_st16r, MEMSUFFIX) (void *EA, uint16_t data, int type) +{ + uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8); + glue(_stw, MEMSUFFIX)(EA, tmp, type); +} + +static inline void glue(_st32r, MEMSUFFIX) (void *EA, uint32_t data, int type) +{ + uint32_t tmp = ((data & 0xFF000000) >> 24) | ((data & 0x00FF0000) >> 8) | + ((data & 0x0000FF00) << 8) | ((data & 0x000000FF) << 24); + glue(_stl, MEMSUFFIX)(EA, tmp, type); +} + +/*** Integer load ***/ +#define PPC_LD_OP(name, op) \ +PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ +{ \ + T1 = glue(op, MEMSUFFIX)((void *)T0, ACCESS_INT); \ + RETURN(); \ +} + +#define PPC_ST_OP(name, op) \ +PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ +{ \ + glue(op, MEMSUFFIX)((void *)T0, T1, ACCESS_INT); \ + RETURN(); \ +} + +PPC_LD_OP(bz, _ldub); +PPC_LD_OP(ha, _ld16x); +PPC_LD_OP(hz, _lduw); +PPC_LD_OP(wz, _ldl); + +/*** Integer store ***/ +PPC_ST_OP(b, _stb); +PPC_ST_OP(h, _stw); +PPC_ST_OP(w, _stl); + +/*** Integer load and store with byte reverse ***/ +PPC_LD_OP(hbr, _ld16r); +PPC_LD_OP(wbr, _ld32r); +PPC_ST_OP(hbr, _st16r); +PPC_ST_OP(wbr, _st32r); + +/*** Integer load and store multiple ***/ +PPC_OP(glue(lmw, MEMSUFFIX)) +{ + int dst = PARAM(1); + + for (; dst < 32; dst++, T0 += 4) { + ugpr(dst) = glue(_ldl, MEMSUFFIX)((void *)T0, ACCESS_INT); + } + RETURN(); +} + +PPC_OP(glue(stmw, MEMSUFFIX)) +{ + int src = PARAM(1); + + for (; src < 32; src++, T0 += 4) { + glue(_stl, MEMSUFFIX)((void *)T0, ugpr(src), ACCESS_INT); + } + RETURN(); +} + +/*** Integer load and store strings ***/ +PPC_OP(glue(lswi, MEMSUFFIX)) +{ + glue(do_lsw, MEMSUFFIX)(PARAM(1)); + RETURN(); +} + +/* PPC32 specification says we must generate an exception if + * rA is in the range of registers to be loaded. + * In an other hand, IBM says this is valid, but rA won't be loaded. + * For now, I'll follow the spec... + */ +PPC_OP(glue(lswx, MEMSUFFIX)) +{ + if (T1 > 0) { + if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) || + (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) { + do_queue_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + do_process_exceptions(); + } else { + glue(do_lsw, MEMSUFFIX)(PARAM(1)); + } + } + RETURN(); +} + +PPC_OP(glue(stsw, MEMSUFFIX)) +{ + glue(do_stsw, MEMSUFFIX)(PARAM(1)); + RETURN(); +} + +/*** Floating-point store ***/ +#define PPC_STF_OP(name, op) \ +PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ +{ \ + glue(op, MEMSUFFIX)((void *)T0, FT1); \ + RETURN(); \ +} + +PPC_STF_OP(fd, stfq); +PPC_STF_OP(fs, stfl); + +/*** Floating-point load ***/ +#define PPC_LDF_OP(name, op) \ +PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ +{ \ + FT1 = glue(op, MEMSUFFIX)((void *)T0); \ + RETURN(); \ +} + +PPC_LDF_OP(fd, ldfq); +PPC_LDF_OP(fs, ldfl); + +/* Store with reservation */ +PPC_OP(glue(stwcx, MEMSUFFIX)) +{ + if (T0 & 0x03) { + do_queue_exception(EXCP_ALIGN); + do_process_exceptions(); + } else { + if (regs->reserve != T0) { + env->crf[0] = xer_ov; + } else { + glue(_stl, MEMSUFFIX)((void *)T0, T1, ACCESS_RES); + env->crf[0] = xer_ov | 0x02; + } + } + regs->reserve = 0; + RETURN(); +} + +PPC_OP(glue(dcbz, MEMSUFFIX)) +{ + glue(_stl, MEMSUFFIX)((void *)(T0 + 0x00), 0, ACCESS_INT); + glue(_stl, MEMSUFFIX)((void *)(T0 + 0x04), 0, ACCESS_INT); + glue(_stl, MEMSUFFIX)((void *)(T0 + 0x08), 0, ACCESS_INT); + glue(_stl, MEMSUFFIX)((void *)(T0 + 0x0C), 0, ACCESS_INT); + glue(_stl, MEMSUFFIX)((void *)(T0 + 0x10), 0, ACCESS_INT); + glue(_stl, MEMSUFFIX)((void *)(T0 + 0x14), 0, ACCESS_INT); + glue(_stl, MEMSUFFIX)((void *)(T0 + 0x18), 0, ACCESS_INT); + glue(_stl, MEMSUFFIX)((void *)(T0 + 0x1C), 0, ACCESS_INT); + RETURN(); +} + +/* External access */ +PPC_OP(glue(eciwx, MEMSUFFIX)) +{ + T1 = glue(_ldl, MEMSUFFIX)((void *)T0, ACCESS_EXT); + RETURN(); +} + +PPC_OP(glue(ecowx, MEMSUFFIX)) +{ + glue(_stl, MEMSUFFIX)((void *)T0, T1, ACCESS_EXT); + RETURN(); +} + +#undef MEMSUFFIX diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 4a849ffea..5ba4dfcbe 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -18,56 +18,67 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* General purpose registers moves */ void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void) { T0 = regs->gpr[REG]; + RETURN(); } void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void) { T1 = regs->gpr[REG]; + RETURN(); } void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void) { T2 = regs->gpr[REG]; + RETURN(); } void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void) { regs->gpr[REG] = T0; + RETURN(); } void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void) { regs->gpr[REG] = T1; + RETURN(); } void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void) { regs->gpr[REG] = T2; + RETURN(); } #if REG <= 7 - +/* Condition register moves */ void OPPROTO glue(op_load_crf_T0_crf, REG)(void) { T0 = regs->crf[REG]; + RETURN(); } void OPPROTO glue(op_load_crf_T1_crf, REG)(void) { T1 = regs->crf[REG]; + RETURN(); } void OPPROTO glue(op_store_T0_crf_crf, REG)(void) { regs->crf[REG] = T0; + RETURN(); } void OPPROTO glue(op_store_T1_crf_crf, REG)(void) { regs->crf[REG] = T1; + RETURN(); } /* Floating point condition and status register moves */ @@ -117,8 +128,6 @@ void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void) #endif /* REG <= 7 */ -/* float moves */ - /* floating point registers moves */ void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void) { @@ -156,4 +165,22 @@ void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void) RETURN(); } +#if REG <= 15 +/* Segment register moves */ +void OPPROTO glue(op_load_sr, REG)(void) +{ + T0 = env->sr[REG]; + RETURN(); +} + +void OPPROTO glue(op_store_sr, REG)(void) +{ +#if defined (DEBUG_OP) + dump_store_sr(REG); +#endif + env->sr[REG] = T0; + RETURN(); +} +#endif + #undef REG diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 60b511c19..34f92bd16 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -24,6 +24,7 @@ //#define DO_SINGLE_STEP //#define DO_STEP_FLUSH +//#define DEBUG_DISAS enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, @@ -37,41 +38,49 @@ static uint32_t *gen_opparam_ptr; #include "gen-op.h" -typedef void (GenOpFunc)(void); -typedef void (GenOpFunc1)(long); -typedef void (GenOpFunc2)(long, long); -typedef void (GenOpFunc3)(long, long, long); - #define GEN8(func, NAME) \ -static GenOpFunc *NAME ## _table [8] = {\ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,\ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,\ -};\ -static inline void func(int n)\ -{\ - NAME ## _table[n]();\ +static GenOpFunc *NAME ## _table [8] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} + +#define GEN16(func, NAME) \ +static GenOpFunc *NAME ## _table [16] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ } #define GEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = {\ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,\ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,\ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11,\ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,\ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,\ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,\ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,\ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,\ -};\ -static inline void func(int n)\ -{\ - NAME ## _table[n]();\ -} - -GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf) -GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf) -GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf) -GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf) +static GenOpFunc *NAME ## _table [32] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} + +/* Condition register moves */ +GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf); +GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf); +GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf); +GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf); /* Floating point condition and status register moves */ GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr); @@ -92,13 +101,18 @@ static inline void gen_op_store_T0_fpscri(int n, uint8_t param) (*gen_op_store_T0_fpscri_fpscr_table[n])(param); } -GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr) -GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr) -GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr) +/* Segment register moves */ +GEN16(gen_op_load_sr, gen_op_load_sr); +GEN16(gen_op_store_sr, gen_op_store_sr); -GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr) -GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr) -GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr) +/* General purpose registers moves */ +GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); +GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr); +GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); + +GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); +GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); +GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr); /* floating point registers moves */ GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr); @@ -115,53 +129,51 @@ typedef struct DisasContext { struct TranslationBlock *tb; uint32_t *nip; uint32_t opcode; - int exception; - int retcode; - /* Time base */ + uint32_t exception; + /* Time base offset */ uint32_t tb_offset; + /* Decrementer offset */ + uint32_t decr_offset; + /* Execution mode */ +#if !defined(CONFIG_USER_ONLY) int supervisor; +#endif + /* Routine used to access memory */ + int mem_idx; } DisasContext; typedef struct opc_handler_t { /* invalid bits */ uint32_t inval; + /* instruction type */ + uint32_t type; /* handler */ void (*handler)(DisasContext *ctx); } opc_handler_t; -#define SET_RETVAL(n) \ +#define RET_EXCP(excp, error) \ do { \ - if ((n) != 0) { \ - ctx->exception = (n); \ - } \ + gen_op_queue_exception_err(excp, error); \ + ctx->exception = excp; \ return; \ } while (0) -#define GET_RETVAL(func, __opcode) \ -({ \ - (func)(&ctx); \ - ctx.exception; \ -}) +#define RET_INVAL() \ +RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) + +#define RET_PRIVOPC() \ +RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) + +#define RET_PRIVREG() \ +RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ static void gen_##name (DisasContext *ctx); \ GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \ static void gen_##name (DisasContext *ctx) -/* Instruction types */ -enum { - PPC_INTEGER = 0x0001, /* CPU has integer operations instructions */ - PPC_FLOAT = 0x0002, /* CPU has floating point operations instructions */ - PPC_FLOW = 0x0004, /* CPU has flow control instructions */ - PPC_MEM = 0x0008, /* CPU has virtual memory instructions */ - PPC_MISC = 0x0010, /* CPU has spr/msr access instructions */ - PPC_EXTERN = 0x0020, /* CPU has external control instructions */ - PPC_SEGMENT = 0x0040, /* CPU has memory segment instructions */ -}; - typedef struct opcode_t { unsigned char opc1, opc2, opc3; - uint32_t type; opc_handler_t handler; } opcode_t; @@ -169,9 +181,6 @@ typedef struct opcode_t { extern FILE *logfile; extern int loglevel; -/* XXX: shouldn't stay all alone here ! */ -static int reserve = 0; - /*** Instruction decoding ***/ #define EXTRACT_HELPER(name, shift, nb) \ static inline uint32_t name (uint32_t opcode) \ @@ -272,9 +281,9 @@ static opcode_t opc_##name = { \ .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ - .type = _typ, \ .handler = { \ .inval = invl, \ + .type = _typ, \ .handler = &gen_##name, \ }, \ } @@ -285,9 +294,9 @@ static opcode_t opc_##name = { \ .opc1 = 0xFF, \ .opc2 = 0xFF, \ .opc3 = 0xFF, \ - .type = 0x00, \ .handler = { \ .inval = 0x00000000, \ + .type = 0x00, \ .handler = NULL, \ }, \ } @@ -296,15 +305,36 @@ static opcode_t opc_##name = { \ GEN_OPCODE_MARK(start); /* Invalid instruction */ -GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, 0) +GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE) +{ + RET_INVAL(); +} + +/* Special opcode to stop emulation */ +GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON) { - /* Branch to next instruction to force nip update */ - gen_op_b((uint32_t)ctx->nip); - SET_RETVAL(EXCP_INVAL); + gen_op_queue_exception(EXCP_HLT); + ctx->exception = EXCP_HLT; +} + +/* Special opcode to call open-firmware */ +GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON) +{ + gen_op_queue_exception(EXCP_OFCALL); + ctx->exception = EXCP_OFCALL; +} + +/* Special opcode to call RTAS */ +GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON) +{ + printf("RTAS entry point !\n"); + gen_op_queue_exception(EXCP_RTASCALL); + ctx->exception = EXCP_RTASCALL; } static opc_handler_t invalid_handler = { .inval = 0xFFFFFFFF, + .type = PPC_NONE, .handler = gen_invalid, }; @@ -318,7 +348,6 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ if (Rc(ctx->opcode) != 0) \ gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ - SET_RETVAL(0); \ } #define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \ @@ -330,7 +359,6 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ if (Rc(ctx->opcode) != 0) \ gen_op_set_Rc0_ov(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ - SET_RETVAL(0); \ } #define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \ @@ -341,7 +369,6 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ if (Rc(ctx->opcode) != 0) \ gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ - SET_RETVAL(0); \ } #define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ @@ -351,7 +378,6 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ if (Rc(ctx->opcode) != 0) \ gen_op_set_Rc0_ov(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ - SET_RETVAL(0); \ } /* Two operands arithmetic functions */ @@ -412,7 +438,6 @@ GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_addi(simm); } gen_op_store_T0_gpr(rD(ctx->opcode)); - SET_RETVAL(0); } /* addic */ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -420,7 +445,6 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_addic(SIMM(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); - SET_RETVAL(0); } /* addic. */ GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -429,7 +453,6 @@ GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_addic(SIMM(ctx->opcode)); gen_op_set_Rc0(); gen_op_store_T0_gpr(rD(ctx->opcode)); - SET_RETVAL(0); } /* addis */ GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -443,7 +466,6 @@ GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_addi(simm << 16); } gen_op_store_T0_gpr(rD(ctx->opcode)); - SET_RETVAL(0); } /* mulli */ GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -451,7 +473,6 @@ GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_mulli(SIMM(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); - SET_RETVAL(0); } /* subfic */ GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -459,7 +480,6 @@ GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_subfic(SIMM(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); - SET_RETVAL(0); } /*** Integer comparison ***/ @@ -470,7 +490,6 @@ GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ gen_op_store_T0_crf(crfD(ctx->opcode)); \ - SET_RETVAL(0); \ } /* cmp */ @@ -481,7 +500,6 @@ GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_cmpi(SIMM(ctx->opcode)); gen_op_store_T0_crf(crfD(ctx->opcode)); - SET_RETVAL(0); } /* cmpl */ GEN_CMP(cmpl, 0x01); @@ -491,7 +509,6 @@ GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_cmpli(UIMM(ctx->opcode)); gen_op_store_T0_crf(crfD(ctx->opcode)); - SET_RETVAL(0); } /*** Integer logical ***/ @@ -504,7 +521,6 @@ GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \ if (Rc(ctx->opcode) != 0) \ gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } #define GEN_LOGICAL2(name, opc) \ __GEN_LOGICAL2(name, 0x1C, opc) @@ -517,7 +533,6 @@ GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \ if (Rc(ctx->opcode) != 0) \ gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } /* and & and. */ @@ -531,7 +546,6 @@ GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_andi_(UIMM(ctx->opcode)); gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); - SET_RETVAL(0); } /* andis. */ GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -540,7 +554,6 @@ GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_andi_(UIMM(ctx->opcode) << 16); gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); - SET_RETVAL(0); } /* cntlzw */ @@ -555,68 +568,94 @@ GEN_LOGICAL1(extsh, 0x1C); GEN_LOGICAL2(nand, 0x0E); /* nor & nor. */ GEN_LOGICAL2(nor, 0x03); + /* or & or. */ -GEN_LOGICAL2(or, 0x0D); +GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + /* Optimisation for mr case */ + if (rS(ctx->opcode) != rB(ctx->opcode)) { + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_or(); + } + if (Rc(ctx->opcode) != 0) + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rA(ctx->opcode)); +} + /* orc & orc. */ GEN_LOGICAL2(orc, 0x0C); /* xor & xor. */ -GEN_LOGICAL2(xor, 0x09); +GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + /* Optimisation for "set to zero" case */ + if (rS(ctx->opcode) != rB(ctx->opcode)) { + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_xor(); + } else { + gen_op_set_T0(0); + } + if (Rc(ctx->opcode) != 0) + gen_op_set_Rc0(); + gen_op_store_T0_gpr(rA(ctx->opcode)); +} /* ori */ GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { uint32_t uimm = UIMM(ctx->opcode); -#if 0 - if (uimm == 0) { - if (rA(ctx->opcode) != rS(ctx->opcode)) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_store_T0_gpr(rA(ctx->opcode)); + if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { + /* NOP */ + return; } - } else -#endif - { gen_op_load_gpr_T0(rS(ctx->opcode)); + if (uimm != 0) gen_op_ori(uimm); gen_op_store_T0_gpr(rA(ctx->opcode)); - } - SET_RETVAL(0); } /* oris */ GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { uint32_t uimm = UIMM(ctx->opcode); -#if 0 - if (uimm == 0) { - if (rA(ctx->opcode) != rS(ctx->opcode)) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_store_T0_gpr(rA(ctx->opcode)); + if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { + /* NOP */ + return; } - } else -#endif - { gen_op_load_gpr_T0(rS(ctx->opcode)); + if (uimm != 0) gen_op_ori(uimm << 16); gen_op_store_T0_gpr(rA(ctx->opcode)); - } - SET_RETVAL(0); } /* xori */ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { + uint32_t uimm = UIMM(ctx->opcode); + + if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { + /* NOP */ + return; + } gen_op_load_gpr_T0(rS(ctx->opcode)); + if (uimm != 0) gen_op_xori(UIMM(ctx->opcode)); gen_op_store_T0_gpr(rA(ctx->opcode)); - SET_RETVAL(0); } /* xoris */ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { + uint32_t uimm = UIMM(ctx->opcode); + + if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { + /* NOP */ + return; + } gen_op_load_gpr_T0(rS(ctx->opcode)); + if (uimm != 0) gen_op_xori(UIMM(ctx->opcode) << 16); gen_op_store_T0_gpr(rA(ctx->opcode)); - SET_RETVAL(0); } /*** Integer rotate ***/ @@ -633,7 +672,6 @@ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) if (Rc(ctx->opcode) != 0) gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); - SET_RETVAL(0); } /* rlwinm & rlwinm. */ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -644,10 +682,6 @@ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) mb = MB(ctx->opcode); me = ME(ctx->opcode); gen_op_load_gpr_T0(rS(ctx->opcode)); - if (loglevel > 0) { - fprintf(logfile, "%s sh=%u mb=%u me=%u MASK=0x%08x\n", - __func__, sh, mb, me, MASK(mb, me)); - } if (mb == 0) { if (me == 31) { gen_op_rotlwi(sh); @@ -673,7 +707,6 @@ store: if (Rc(ctx->opcode) != 0) gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); - SET_RETVAL(0); } /* rlwnm & rlwnm. */ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -693,7 +726,6 @@ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) if (Rc(ctx->opcode) != 0) gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); - SET_RETVAL(0); } /*** Integer shift ***/ @@ -709,172 +741,169 @@ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) if (Rc(ctx->opcode) != 0) gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); - SET_RETVAL(0); } /* srw & srw. */ __GEN_LOGICAL2(srw, 0x18, 0x10); /*** Floating-Point arithmetic ***/ -/* fadd */ -GEN_HANDLER(fadd, 0x3F, 0x15, 0xFF, 0x000007C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); +#define _GEN_FLOAT_ACB(name, op1, op2) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ +{ \ + gen_op_reset_scrfx(); \ + gen_op_load_fpr_FT0(rA(ctx->opcode)); \ + gen_op_load_fpr_FT1(rC(ctx->opcode)); \ + gen_op_load_fpr_FT2(rB(ctx->opcode)); \ + gen_op_f##name(); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + if (Rc(ctx->opcode)) \ + gen_op_set_Rc1(); \ +} + +#define GEN_FLOAT_ACB(name, op2) \ +_GEN_FLOAT_ACB(name, 0x3F, op2); \ +_GEN_FLOAT_ACB(name##s, 0x3B, op2); + +#define _GEN_FLOAT_AB(name, op1, op2, inval) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ +{ \ + gen_op_reset_scrfx(); \ + gen_op_load_fpr_FT0(rA(ctx->opcode)); \ + gen_op_load_fpr_FT1(rB(ctx->opcode)); \ + gen_op_f##name(); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + if (Rc(ctx->opcode)) \ + gen_op_set_Rc1(); \ +} +#define GEN_FLOAT_AB(name, op2, inval) \ +_GEN_FLOAT_AB(name, 0x3F, op2, inval); \ +_GEN_FLOAT_AB(name##s, 0x3B, op2, inval); + +#define _GEN_FLOAT_AC(name, op1, op2, inval) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ +{ \ + gen_op_reset_scrfx(); \ + gen_op_load_fpr_FT0(rA(ctx->opcode)); \ + gen_op_load_fpr_FT1(rC(ctx->opcode)); \ + gen_op_f##name(); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + if (Rc(ctx->opcode)) \ + gen_op_set_Rc1(); \ +} +#define GEN_FLOAT_AC(name, op2, inval) \ +_GEN_FLOAT_AC(name, 0x3F, op2, inval); \ +_GEN_FLOAT_AC(name##s, 0x3B, op2, inval); + +#define GEN_FLOAT_B(name, op2, op3) \ +GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ +{ \ + gen_op_reset_scrfx(); \ + gen_op_load_fpr_FT0(rB(ctx->opcode)); \ + gen_op_f##name(); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + if (Rc(ctx->opcode)) \ + gen_op_set_Rc1(); \ } -/* fadds */ -GEN_HANDLER(fadds, 0x3B, 0x15, 0xFF, 0x000007C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); +#define GEN_FLOAT_BS(name, op2) \ +GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ +{ \ + gen_op_reset_scrfx(); \ + gen_op_load_fpr_FT0(rB(ctx->opcode)); \ + gen_op_f##name(); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ + if (Rc(ctx->opcode)) \ + gen_op_set_Rc1(); \ } +/* fadd - fadds */ +GEN_FLOAT_AB(add, 0x15, 0x000007C0); /* fdiv */ -GEN_HANDLER(fdiv, 0x3F, 0x12, 0xFF, 0x000007C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fdivs */ -GEN_HANDLER(fdivs, 0x3B, 0x12, 0xFF, 0x000007C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - +GEN_FLOAT_AB(div, 0x12, 0x000007C0); /* fmul */ -GEN_HANDLER(fmul, 0x3F, 0x19, 0xFF, 0x0000F800, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fmuls */ -GEN_HANDLER(fmuls, 0x3B, 0x19, 0xFF, 0x0000F800, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} +GEN_FLOAT_AC(mul, 0x19, 0x0000F800); /* fres */ -GEN_HANDLER(fres, 0x3B, 0x18, 0xFF, 0x001807C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} +GEN_FLOAT_BS(res, 0x18); /* frsqrte */ -GEN_HANDLER(frsqrte, 0x3F, 0x1A, 0xFF, 0x001807C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} +GEN_FLOAT_BS(rsqrte, 0x1A); /* fsel */ -GEN_HANDLER(fsel, 0x3F, 0x17, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - +_GEN_FLOAT_ACB(sel, 0x3F, 0x17); /* fsub */ -GEN_HANDLER(fsub, 0x3F, 0x14, 0xFF, 0x000007C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fsubs */ -GEN_HANDLER(fsubs, 0x3B, 0x14, 0xFF, 0x000007C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - +GEN_FLOAT_AB(sub, 0x14, 0x000007C0); /* Optional: */ /* fsqrt */ -GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001807C0, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} +GEN_FLOAT_BS(sqrt, 0x16); -/* fsqrts */ -GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001807C0, PPC_FLOAT) +GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) { - SET_RETVAL(EXCP_INVAL); + gen_op_reset_scrfx(); + gen_op_load_fpr_FT0(rB(ctx->opcode)); + gen_op_fsqrts(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + if (Rc(ctx->opcode)) + gen_op_set_Rc1(); } /*** Floating-Point multiply-and-add ***/ /* fmadd */ -GEN_HANDLER(fmadd, 0x3F, 0x1D, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fmadds */ -GEN_HANDLER(fmadds, 0x3B, 0x1D, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - +GEN_FLOAT_ACB(madd, 0x1D); /* fmsub */ -GEN_HANDLER(fmsub, 0x3F, 0x1C, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fmsubs */ -GEN_HANDLER(fmsubs, 0x3B, 0x1C, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - +GEN_FLOAT_ACB(msub, 0x1C); /* fnmadd */ -GEN_HANDLER(fnmadd, 0x3F, 0x1F, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fnmadds */ -GEN_HANDLER(fnmadds, 0x3B, 0x1F, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - +GEN_FLOAT_ACB(nmadd, 0x1F); /* fnmsub */ -GEN_HANDLER(fnmsub, 0x3F, 0x1E, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fnmsubs */ -GEN_HANDLER(fnmsubs, 0x3B, 0x1E, 0xFF, 0x00000000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} +GEN_FLOAT_ACB(nmsub, 0x1E); /*** Floating-Point round & convert ***/ /* fctiw */ -GEN_HANDLER(fctiw, 0x3F, 0x0E, 0xFF, 0x001F0000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - +GEN_FLOAT_B(ctiw, 0x0E, 0x00); /* fctiwz */ -GEN_HANDLER(fctiwz, 0x3F, 0x0F, 0xFF, 0x001F0000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - +GEN_FLOAT_B(ctiwz, 0x0F, 0x00); /* frsp */ -GEN_HANDLER(frsp, 0x3F, 0x0C, 0xFF, 0x001F0000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} +GEN_FLOAT_B(rsp, 0x0C, 0x00); /*** Floating-Point compare ***/ /* fcmpo */ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) { - SET_RETVAL(EXCP_INVAL); + gen_op_reset_scrfx(); + gen_op_load_fpr_FT0(rA(ctx->opcode)); + gen_op_load_fpr_FT1(rB(ctx->opcode)); + gen_op_fcmpo(); + gen_op_store_T0_crf(crfD(ctx->opcode)); } /* fcmpu */ GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) { - SET_RETVAL(EXCP_INVAL); + gen_op_reset_scrfx(); + gen_op_load_fpr_FT0(rA(ctx->opcode)); + gen_op_load_fpr_FT1(rB(ctx->opcode)); + gen_op_fcmpu(); + gen_op_store_T0_crf(crfD(ctx->opcode)); } +/*** Floating-point move ***/ +/* fabs */ +GEN_FLOAT_B(abs, 0x08, 0x08); + +/* fmr - fmr. */ +GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) +{ + gen_op_reset_scrfx(); + gen_op_load_fpr_FT0(rB(ctx->opcode)); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + if (Rc(ctx->opcode)) + gen_op_set_Rc1(); +} + +/* fnabs */ +GEN_FLOAT_B(nabs, 0x08, 0x04); +/* fneg */ +GEN_FLOAT_B(neg, 0x08, 0x01); + /*** Floating-Point status & ctrl register ***/ /* mcrfs */ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) @@ -882,7 +911,6 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) gen_op_load_fpscr_T0(crfS(ctx->opcode)); gen_op_store_T0_crf(crfD(ctx->opcode)); gen_op_clear_fpscr(crfS(ctx->opcode)); - SET_RETVAL(0); } /* mffs */ @@ -892,7 +920,6 @@ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) gen_op_store_FT0_fpr(rD(ctx->opcode)); if (Rc(ctx->opcode)) gen_op_set_Rc1(); - SET_RETVAL(0); } /* mtfsb0 */ @@ -906,7 +933,6 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) gen_op_store_T0_fpscr(crb); if (Rc(ctx->opcode)) gen_op_set_Rc1(); - SET_RETVAL(0); } /* mtfsb1 */ @@ -920,7 +946,6 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) gen_op_store_T0_fpscr(crb); if (Rc(ctx->opcode)) gen_op_set_Rc1(); - SET_RETVAL(0); } /* mtfsf */ @@ -930,7 +955,6 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) gen_op_store_fpscr(FM(ctx->opcode)); if (Rc(ctx->opcode)) gen_op_set_Rc1(); - SET_RETVAL(0); } /* mtfsfi */ @@ -939,505 +963,541 @@ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode)); if (Rc(ctx->opcode)) gen_op_set_Rc1(); - SET_RETVAL(0); } /*** Integer load ***/ -#define GEN_ILDZ(width, opc) \ +#if defined(CONFIG_USER_ONLY) +#define op_ldst(name) gen_op_##name##_raw() +#define OP_LD_TABLE(width) +#define OP_ST_TABLE(width) +#else +#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_l##width[] = { \ + &gen_op_l##width##_user, \ + &gen_op_l##width##_kernel, \ +} +#define OP_ST_TABLE(width) \ +static GenOpFunc *gen_op_st##width[] = { \ + &gen_op_st##width##_user, \ + &gen_op_st##width##_kernel, \ +} +#endif + +#define GEN_LD(width, opc) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0) { \ - gen_op_l##width##_z(simm); \ + gen_op_set_T0(simm); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_l##width (simm); \ + if (simm != 0) \ + gen_op_addi(simm); \ } \ + op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_ILDZU(width, opc) \ +#define GEN_LDU(width, opc) \ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ + uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) \ - SET_RETVAL(EXCP_INVAL); \ + rA(ctx->opcode) == rD(ctx->opcode)) { \ + RET_INVAL(); \ + } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_l##width(SIMM(ctx->opcode)); \ + if (simm != 0) \ + gen_op_addi(simm); \ + op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_ILDZUX(width, opc) \ +#define GEN_LDUX(width, opc) \ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) \ - SET_RETVAL(EXCP_INVAL); \ + rA(ctx->opcode) == rD(ctx->opcode)) { \ + RET_INVAL(); \ + } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_l##width##x(); \ + gen_op_add(); \ + op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_ILDZX(width, opc2, opc3) \ +#define GEN_LDX(width, opc2, opc3) \ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ - gen_op_l##width##x_z(); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_l##width##x(); \ + gen_op_add(); \ } \ + op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_ILD(width, op) \ -GEN_ILDZ(width, op | 0x20) \ -GEN_ILDZU(width, op | 0x21) \ -GEN_ILDZUX(width, op | 0x01) \ -GEN_ILDZX(width, 0x17, op | 0x00) +#define GEN_LDS(width, op) \ +OP_LD_TABLE(width); \ +GEN_LD(width, op | 0x20); \ +GEN_LDU(width, op | 0x21); \ +GEN_LDUX(width, op | 0x01); \ +GEN_LDX(width, 0x17, op | 0x00) /* lbz lbzu lbzux lbzx */ -GEN_ILD(bz, 0x02); +GEN_LDS(bz, 0x02); /* lha lhau lhaux lhax */ -GEN_ILD(ha, 0x0A); +GEN_LDS(ha, 0x0A); /* lhz lhzu lhzux lhzx */ -GEN_ILD(hz, 0x08); +GEN_LDS(hz, 0x08); /* lwz lwzu lwzux lwzx */ -GEN_ILD(wz, 0x00); +GEN_LDS(wz, 0x00); /*** Integer store ***/ -#define GEN_IST(width, opc) \ +#define GEN_ST(width, opc) \ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rS(ctx->opcode)); \ - gen_op_st##width##_z(simm); \ + gen_op_set_T0(simm); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rS(ctx->opcode)); \ - gen_op_st##width(simm); \ + if (simm != 0) \ + gen_op_addi(simm); \ } \ - SET_RETVAL(0); \ + gen_op_load_gpr_T1(rS(ctx->opcode)); \ + op_ldst(st##width); \ } -#define GEN_ISTU(width, opc) \ +#define GEN_STU(width, opc) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) \ - SET_RETVAL(EXCP_INVAL); \ + uint32_t simm = SIMM(ctx->opcode); \ + if (rA(ctx->opcode) == 0) { \ + RET_INVAL(); \ + } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ + if (simm != 0) \ + gen_op_addi(simm); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ - gen_op_st##width(SIMM(ctx->opcode)); \ + op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_ISTUX(width, opc) \ +#define GEN_STUX(width, opc) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) \ - SET_RETVAL(EXCP_INVAL); \ + if (rA(ctx->opcode) == 0) { \ + RET_INVAL(); \ + } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_load_gpr_T2(rS(ctx->opcode)); \ - gen_op_st##width##x(); \ + gen_op_add(); \ + gen_op_load_gpr_T1(rS(ctx->opcode)); \ + op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_ISTX(width, opc2, opc3) \ +#define GEN_STX(width, opc2, opc3) \ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ - gen_op_load_gpr_T1(rS(ctx->opcode)); \ - gen_op_st##width##x_z(); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_load_gpr_T2(rS(ctx->opcode)); \ - gen_op_st##width##x(); \ + gen_op_add(); \ } \ - SET_RETVAL(0); \ + gen_op_load_gpr_T1(rS(ctx->opcode)); \ + op_ldst(st##width); \ } -#define GEN_ISTO(width, opc) \ -GEN_IST(width, opc | 0x20) \ -GEN_ISTU(width, opc | 0x21) \ -GEN_ISTUX(width, opc | 0x01) \ -GEN_ISTX(width, 0x17, opc | 0x00) +#define GEN_STS(width, op) \ +OP_ST_TABLE(width); \ +GEN_ST(width, op | 0x20); \ +GEN_STU(width, op | 0x21); \ +GEN_STUX(width, op | 0x01); \ +GEN_STX(width, 0x17, op | 0x00) /* stb stbu stbux stbx */ -GEN_ISTO(b, 0x06); +GEN_STS(b, 0x06); /* sth sthu sthux sthx */ -GEN_ISTO(h, 0x0C); +GEN_STS(h, 0x0C); /* stw stwu stwux stwx */ -GEN_ISTO(w, 0x04); +GEN_STS(w, 0x04); /*** Integer load and store with byte reverse ***/ /* lhbrx */ -GEN_ILDZX(hbr, 0x16, 0x18); +OP_LD_TABLE(hbr); +GEN_LDX(hbr, 0x16, 0x18); /* lwbrx */ -GEN_ILDZX(wbr, 0x16, 0x10); +OP_LD_TABLE(wbr); +GEN_LDX(wbr, 0x16, 0x10); /* sthbrx */ -GEN_ISTX(hbr, 0x16, 0x1C); +OP_ST_TABLE(hbr); +GEN_STX(hbr, 0x16, 0x1C); /* stwbrx */ -GEN_ISTX(wbr, 0x16, 0x14); +OP_ST_TABLE(wbr); +GEN_STX(wbr, 0x16, 0x14); /*** Integer load and store multiple ***/ +#if defined(CONFIG_USER_ONLY) +#define op_ldstm(name, reg) gen_op_##name##_raw(reg) +#else +#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg) +static GenOpFunc1 *gen_op_lmw[] = { + &gen_op_lmw_user, + &gen_op_lmw_kernel, +}; +static GenOpFunc1 *gen_op_stmw[] = { + &gen_op_stmw_user, + &gen_op_stmw_kernel, +}; +#endif + /* lmw */ GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { + int simm = SIMM(ctx->opcode); + if (rA(ctx->opcode) == 0) { - gen_op_set_T0(0); + gen_op_set_T0(simm); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); + if (simm != 0) + gen_op_addi(simm); } - gen_op_lmw(rD(ctx->opcode), SIMM(ctx->opcode)); - SET_RETVAL(0); + op_ldstm(lmw, rD(ctx->opcode)); } /* stmw */ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { + int simm = SIMM(ctx->opcode); + if (rA(ctx->opcode) == 0) { - gen_op_set_T0(0); + gen_op_set_T0(simm); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); + if (simm != 0) + gen_op_addi(simm); } - gen_op_stmw(rS(ctx->opcode), SIMM(ctx->opcode)); - SET_RETVAL(0); + op_ldstm(stmw, rS(ctx->opcode)); } /*** Integer load and store strings ***/ +#if defined(CONFIG_USER_ONLY) +#define op_ldsts(name, start) gen_op_##name##_raw(start) +#define op_ldstsx(name, rd, ra, rb) gen_op_##name##_raw(rd, ra, rb) +#else +#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start) +#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb) +static GenOpFunc1 *gen_op_lswi[] = { + &gen_op_lswi_user, + &gen_op_lswi_kernel, +}; +static GenOpFunc3 *gen_op_lswx[] = { + &gen_op_lswx_user, + &gen_op_lswx_kernel, +}; +static GenOpFunc1 *gen_op_stsw[] = { + &gen_op_stsw_user, + &gen_op_stsw_kernel, +}; +#endif + /* lswi */ +/* PPC32 specification says we must generate an exception if + * rA is in the range of registers to be loaded. + * In an other hand, IBM says this is valid, but rA won't be loaded. + * For now, I'll follow the spec... + */ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) { int nb = NB(ctx->opcode); int start = rD(ctx->opcode); + int ra = rA(ctx->opcode); int nr; if (nb == 0) nb = 32; nr = nb / 4; - if ((start + nr) > 32) { - /* handle wrap around r0 */ - if (rA(ctx->opcode) == 0) { - gen_op_set_T0(0); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); + if (((start + nr) > 32 && start <= ra && (start + nr - 32) >= ra) || + ((start + nr) <= 32 && start <= ra && (start + nr) >= ra)) { + RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); } - gen_op_lswi(start, 4 * (32 - start)); - nb -= 4 * (32 - start); - start = 0; - } - if (rA(ctx->opcode) == 0) { + if (ra == 0) { gen_op_set_T0(0); } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T0(ra); } - gen_op_lswi(start, nb); - SET_RETVAL(0); + gen_op_set_T1(nb); + op_ldsts(lswi, start); } /* lswx */ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) { - gen_op_load_xer_bc(); - gen_op_load_gpr_T1(rB(ctx->opcode)); - if (rA(ctx->opcode) == 0) { - gen_op_set_T2(0); + int ra = rA(ctx->opcode); + int rb = rB(ctx->opcode); + + if (ra == 0) { + gen_op_load_gpr_T0(rb); + ra = rb; } else { - gen_op_load_gpr_T2(rA(ctx->opcode)); + gen_op_load_gpr_T0(ra); + gen_op_load_gpr_T1(rb); + gen_op_add(); } - gen_op_lswx(rD(ctx->opcode)); - SET_RETVAL(0); + gen_op_load_xer_bc(); + op_ldstsx(lswx, rD(ctx->opcode), ra, rb); } /* stswi */ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) { - int nb = NB(ctx->opcode); - int start = rS(ctx->opcode); - int nr; - - if (nb == 0) - nb = 32; - nr = nb / 4; - if ((start + nr) > 32) { - /* handle wrap around r0 */ - if (rA(ctx->opcode) == 0) { - gen_op_set_T0(0); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - } - gen_op_stswi(start, 4 * (32 - start)); - nb -= 4 * (32 - start); - start = 0; - } if (rA(ctx->opcode) == 0) { gen_op_set_T0(0); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); } - gen_op_stswi(start, nb); - SET_RETVAL(0); + gen_op_set_T1(NB(ctx->opcode)); + op_ldsts(stsw, rS(ctx->opcode)); } /* stswx */ GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) { - gen_op_load_xer_bc(); - gen_op_load_gpr_T1(rB(ctx->opcode)); - if (rA(ctx->opcode) == 0) { - gen_op_set_T2(0); + int ra = rA(ctx->opcode); + + if (ra == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + ra = rB(ctx->opcode); } else { - gen_op_load_gpr_T2(rA(ctx->opcode)); + gen_op_load_gpr_T0(ra); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); } - gen_op_stswx(rS(ctx->opcode)); - SET_RETVAL(0); + gen_op_load_xer_bc(); + op_ldsts(stsw, rS(ctx->opcode)); } /*** Memory synchronisation ***/ /* eieio */ GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM) { - /* Do a branch to next instruction */ - gen_op_b((uint32_t)ctx->nip); - SET_RETVAL(EXCP_BRANCH); } /* isync */ GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM) { - /* Do a branch to next instruction */ - gen_op_b((uint32_t)ctx->nip); - SET_RETVAL(EXCP_BRANCH); } /* lwarx */ -GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_MEM) +#if defined(CONFIG_USER_ONLY) +#define op_stwcx() gen_op_stwcx_raw() +#else +#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])() +static GenOpFunc *gen_op_stwcx[] = { + &gen_op_stwcx_user, + &gen_op_stwcx_kernel, +}; +#endif + +GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES) { - reserve = 1; if (rA(ctx->opcode) == 0) { gen_op_load_gpr_T0(rB(ctx->opcode)); - gen_op_lwarx_z(); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_lwarx(); + gen_op_add(); } + op_ldst(lwz); gen_op_store_T1_gpr(rD(ctx->opcode)); - SET_RETVAL(0); + gen_op_set_reservation(); } /* stwcx. */ -GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_MEM) +GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) { - if (reserve == 0) { - gen_op_reset_Rc0(); - } else { if (rA(ctx->opcode) == 0) { gen_op_load_gpr_T0(rB(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); - gen_op_stwx_z(); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_load_gpr_T2(rS(ctx->opcode)); - gen_op_stwx(); + gen_op_add(); } - } - SET_RETVAL(0); + gen_op_load_gpr_T1(rS(ctx->opcode)); + op_stwcx(); } /* sync */ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) { - /* Do a branch to next instruction */ - gen_op_b((uint32_t)ctx->nip); - SET_RETVAL(EXCP_BRANCH); } /*** Floating-point load ***/ -#define GEN_LF(width, opc) \ -GEN_HANDLER(lf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +#define GEN_LDF(width, opc) \ +GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0) { \ - gen_op_lf##width##_z_FT0(simm); \ + gen_op_set_T0(simm); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_lf##width##_FT0(simm); \ + if (simm != 0) \ + gen_op_addi(simm); \ } \ - gen_op_store_FT0_fpr(rD(ctx->opcode));\ - SET_RETVAL(0); \ + op_ldst(l##width); \ + gen_op_store_FT1_fpr(rD(ctx->opcode)); \ } -#define GEN_LFU(width, opc) \ -GEN_HANDLER(lf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +#define GEN_LDUF(width, opc) \ +GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ + uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) \ - SET_RETVAL(EXCP_INVAL); \ + rA(ctx->opcode) == rD(ctx->opcode)) { \ + RET_INVAL(); \ + } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_lf##width##_FT0(SIMM(ctx->opcode)); \ - gen_op_store_FT0_fpr(rD(ctx->opcode));\ + if (simm != 0) \ + gen_op_addi(simm); \ + op_ldst(l##width); \ + gen_op_store_FT1_fpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_LFUX(width, opc) \ -GEN_HANDLER(lf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +#define GEN_LDUXF(width, opc) \ +GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) \ - SET_RETVAL(EXCP_INVAL); \ + rA(ctx->opcode) == rD(ctx->opcode)) { \ + RET_INVAL(); \ + } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_lf##width##x_FT0(); \ - gen_op_store_FT0_fpr(rD(ctx->opcode));\ + gen_op_add(); \ + op_ldst(l##width); \ + gen_op_store_FT1_fpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_LFX(width, opc) \ -GEN_HANDLER(lf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +#define GEN_LDXF(width, opc2, opc3) \ +GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ - gen_op_lf##width##x_z_FT0(); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_lf##width##x_FT0(); \ + gen_op_add(); \ } \ - gen_op_store_FT0_fpr(rD(ctx->opcode));\ - SET_RETVAL(0); \ + op_ldst(l##width); \ + gen_op_store_FT1_fpr(rD(ctx->opcode)); \ } -#define GEN_LDF(width, opc) \ -GEN_LF(width, opc | 0x20) \ -GEN_LFU(width, opc | 0x21) \ -GEN_LFUX(width, opc | 0x01) \ -GEN_LFX(width, opc | 0x00) +#define GEN_LDFS(width, op) \ +OP_LD_TABLE(width); \ +GEN_LDF(width, op | 0x20); \ +GEN_LDUF(width, op | 0x21); \ +GEN_LDUXF(width, op | 0x01); \ +GEN_LDXF(width, 0x17, op | 0x00) /* lfd lfdu lfdux lfdx */ -GEN_LDF(d, 0x12); +GEN_LDFS(fd, 0x12); /* lfs lfsu lfsux lfsx */ -GEN_LDF(s, 0x10); +GEN_LDFS(fs, 0x10); /*** Floating-point store ***/ #define GEN_STF(width, opc) \ -GEN_HANDLER(stf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ - gen_op_load_fpr_FT0(rS(ctx->opcode));\ if (rA(ctx->opcode) == 0) { \ - gen_op_stf##width##_z_FT0(simm); \ + gen_op_set_T0(simm); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_stf##width##_FT0(simm); \ + if (simm != 0) \ + gen_op_addi(simm); \ } \ - SET_RETVAL(0); \ + gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + op_ldst(st##width); \ } -#define GEN_STFU(width, opc) \ -GEN_HANDLER(stf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +#define GEN_STUF(width, opc) \ +GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) \ - SET_RETVAL(EXCP_INVAL); \ + uint32_t simm = SIMM(ctx->opcode); \ + if (rA(ctx->opcode) == 0) { \ + RET_INVAL(); \ + } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_fpr_FT0(rS(ctx->opcode));\ - gen_op_stf##width##_FT0(SIMM(ctx->opcode)); \ + if (simm != 0) \ + gen_op_addi(simm); \ + gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_STFUX(width, opc) \ -GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +#define GEN_STUXF(width, opc) \ +GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) \ - SET_RETVAL(EXCP_INVAL); \ + if (rA(ctx->opcode) == 0) { \ + RET_INVAL(); \ + } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_load_fpr_FT0(rS(ctx->opcode));\ - gen_op_stf##width##x_FT0(); \ + gen_op_add(); \ + gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ - SET_RETVAL(0); \ } -#define GEN_STFX(width, opc) \ -GEN_HANDLER(stf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +#define GEN_STXF(width, opc2, opc3) \ +GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ - gen_op_load_fpr_FT0(rS(ctx->opcode));\ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ - gen_op_stf##width##x_z_FT0(); \ } else { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_stf##width##x_FT0(); \ + gen_op_add(); \ } \ - SET_RETVAL(0); \ + gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + op_ldst(st##width); \ } -#define GEN_STOF(width, opc) \ -GEN_STF(width, opc | 0x20) \ -GEN_STFU(width, opc | 0x21) \ -GEN_STFUX(width, opc | 0x01) \ -GEN_STFX(width, opc | 0x00) +#define GEN_STFS(width, op) \ +OP_ST_TABLE(width); \ +GEN_STF(width, op | 0x20); \ +GEN_STUF(width, op | 0x21); \ +GEN_STUXF(width, op | 0x01); \ +GEN_STXF(width, 0x17, op | 0x00) /* stfd stfdu stfdux stfdx */ -GEN_STOF(d, 0x16); +GEN_STFS(fd, 0x16); /* stfs stfsu stfsux stfsx */ -GEN_STOF(s, 0x14); +GEN_STFS(fs, 0x14); /* Optional: */ /* stfiwx */ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) { - SET_RETVAL(EXCP_INVAL); -} - -/*** Floating-point move ***/ -/* fabs */ -GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fmr */ -GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fnabs */ -GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); -} - -/* fneg */ -GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT) -{ - SET_RETVAL(EXCP_INVAL); + RET_INVAL(); } /*** Branch ***/ #define GEN_BCOND(name, opc1, opc2, opc3, prologue, \ - bl_ctr, b_ctr, bl_ctrz, b_ctrz, b, \ + bl_ctr, b_ctr, bl_ctrz, b_ctrz, b, bl, \ bl_ctr_true, b_ctr_true, bl_ctrz_true, b_ctrz_true, bl_true, b_true, \ bl_ctr_false, b_ctr_false, bl_ctrz_false, b_ctrz_false, bl_false, b_false) \ GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW) \ @@ -1446,7 +1506,11 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW) \ uint32_t bo = BO(ctx->opcode); \ uint32_t bi = BI(ctx->opcode); \ uint32_t mask; \ + gen_op_update_tb(ctx->tb_offset); \ + gen_op_update_decr(ctx->decr_offset); \ + gen_op_process_exceptions((uint32_t)ctx->nip - 4); \ prologue; \ +/* gen_op_set_T1((uint32_t)ctx->tb);*/ \ if ((bo & 0x4) == 0) \ gen_op_dec_ctr(); \ if (bo & 0x10) { \ @@ -1468,13 +1532,15 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW) \ break; \ case 4: \ case 6: \ + if (LK(ctx->opcode)) { \ + bl; \ + } else { \ b; \ - if (LK(ctx->opcode)) \ - gen_op_load_lr((uint32_t)ctx->nip); \ + } \ break; \ default: \ printf("ERROR: %s: unhandled ba case (%d)\n", __func__, bo); \ - SET_RETVAL(EXCP_INVAL); \ + RET_INVAL(); \ break; \ } \ } else { \ @@ -1506,7 +1572,7 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW) \ break; \ default: \ printf("ERROR: %s: unhandled b case (%d)\n", __func__, bo); \ - SET_RETVAL(EXCP_INVAL); \ + RET_INVAL(); \ break; \ } \ } else { \ @@ -1535,12 +1601,12 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW) \ break; \ default: \ printf("ERROR: %s: unhandled bn case (%d)\n", __func__, bo); \ - SET_RETVAL(EXCP_INVAL); \ + RET_INVAL(); \ break; \ } \ } \ } \ - SET_RETVAL(EXCP_BRANCH); \ + ctx->exception = EXCP_BRANCH; \ } /* b ba bl bla */ @@ -1548,14 +1614,20 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { uint32_t li = s_ext24(LI(ctx->opcode)), target; + gen_op_update_tb(ctx->tb_offset); + gen_op_update_decr(ctx->decr_offset); + gen_op_process_exceptions((uint32_t)ctx->nip - 4); if (AA(ctx->opcode) == 0) target = (uint32_t)ctx->nip + li - 4; else - target = s_ext24(LI(ctx->opcode)); + target = li; +// gen_op_set_T1((uint32_t)ctx->tb); + if (LK(ctx->opcode)) { + gen_op_bl(target, (uint32_t)ctx->nip); + } else { gen_op_b(target); - if (LK(ctx->opcode)) - gen_op_load_lr((uint32_t)ctx->nip); - SET_RETVAL(EXCP_BRANCH); + } + ctx->exception = EXCP_BRANCH; } /* bc bca bcl bcla */ @@ -1573,6 +1645,7 @@ GEN_BCOND(bc, 0x10, 0xFF, 0xFF, gen_op_bl_ctrz((uint32_t)ctx->nip, target), gen_op_b_ctrz((uint32_t)ctx->nip, target), gen_op_b(target), + gen_op_bl(target, (uint32_t)ctx->nip), gen_op_bl_ctr_true((uint32_t)ctx->nip, target, mask), gen_op_b_ctr_true((uint32_t)ctx->nip, target, mask), gen_op_bl_ctrz_true((uint32_t)ctx->nip, target, mask), @@ -1593,6 +1666,7 @@ GEN_BCOND(bcctr, 0x13, 0x10, 0x10, do { } while (0), gen_op_bctrl_ctrz((uint32_t)ctx->nip), gen_op_bctr_ctrz((uint32_t)ctx->nip), gen_op_bctr(), + gen_op_bctrl((uint32_t)ctx->nip), gen_op_bctrl_ctr_true((uint32_t)ctx->nip, mask), gen_op_bctr_ctr_true((uint32_t)ctx->nip, mask), gen_op_bctrl_ctrz_true((uint32_t)ctx->nip, mask), @@ -1613,6 +1687,7 @@ GEN_BCOND(bclr, 0x13, 0x10, 0x00, do { } while (0), gen_op_blrl_ctrz((uint32_t)ctx->nip), gen_op_blr_ctrz((uint32_t)ctx->nip), gen_op_blr(), + gen_op_blrl((uint32_t)ctx->nip), gen_op_blrl_ctr_true((uint32_t)ctx->nip, mask), gen_op_blr_ctr_true((uint32_t)ctx->nip, mask), gen_op_blrl_ctrz_true((uint32_t)ctx->nip, mask), @@ -1639,7 +1714,6 @@ GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \ gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \ 3 - (crbD(ctx->opcode) & 0x03)); \ gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \ - SET_RETVAL(0); \ } /* crand */ @@ -1663,34 +1737,53 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) { gen_op_load_crf_T0(crfS(ctx->opcode)); gen_op_store_T0_crf(crfD(ctx->opcode)); - SET_RETVAL(0); } /*** System linkage ***/ /* rfi (supervisor only) */ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) { - SET_RETVAL(EXCP_INVAL); +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(); +#else + /* Restore CPU state */ + if (!ctx->supervisor) { + RET_PRIVOPC(); + } + gen_op_rfi(); + ctx->exception = EXCP_RFI; +#endif } /* sc */ GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) { - gen_op_b((uint32_t)ctx->nip); - SET_RETVAL(EXCP_SYSCALL); +#if defined(CONFIG_USER_ONLY) + gen_op_queue_exception(EXCP_SYSCALL_USER); +#else + gen_op_queue_exception(EXCP_SYSCALL); +#endif + ctx->exception = EXCP_SYSCALL; } /*** Trap ***/ /* tw */ GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW) { - SET_RETVAL(EXCP_INVAL); + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_tw(TO(ctx->opcode)); } /* twi */ GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { - SET_RETVAL(EXCP_INVAL); + gen_op_load_gpr_T0(rA(ctx->opcode)); +#if 0 + printf("%s: param=0x%04x T0=0x%04x\n", __func__, + SIMM(ctx->opcode), TO(ctx->opcode)); +#endif + gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode)); } /*** Processor control ***/ @@ -1698,6 +1791,21 @@ static inline int check_spr_access (int spr, int rw, int supervisor) { uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1)); +#if 0 + if (spr != LR && spr != CTR) { + if (loglevel > 0) { + fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__, + SPR_ENCODE(spr), supervisor, rw, rights, + (rights >> ((2 * supervisor) + rw)) & 1); + } else { + printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__, + SPR_ENCODE(spr), supervisor, rw, rights, + (rights >> ((2 * supervisor) + rw)) & 1); + } + } +#endif + if (rights == 0) + return -1; rights = rights >> (2 * supervisor); rights = rights >> rw; @@ -1710,7 +1818,6 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) gen_op_load_xer_cr(); gen_op_store_T0_crf(crfD(ctx->opcode)); gen_op_clear_xer_cr(); - SET_RETVAL(0); } /* mfcr */ @@ -1718,17 +1825,20 @@ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC) { gen_op_load_cr(); gen_op_store_T0_gpr(rD(ctx->opcode)); - SET_RETVAL(0); } /* mfmsr */ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) { - if (!ctx->supervisor) - SET_RETVAL(EXCP_PRIV); +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(); +#else + if (!ctx->supervisor) { + RET_PRIVREG(); + } gen_op_load_msr(); gen_op_store_T0_gpr(rD(ctx->opcode)); - SET_RETVAL(0); +#endif } /* mfspr */ @@ -1736,31 +1846,150 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) { uint32_t sprn = SPR(ctx->opcode); - if (check_spr_access(sprn, 0, ctx->supervisor) == 0) - SET_RETVAL(EXCP_PRIV); - /* XXX: make this more generic */ - switch (sprn) { - case SPR_ENCODE(1): - if (loglevel > 0) { - fprintf(logfile, "LOAD XER at %p\n", ctx->nip - 1); +#if defined(CONFIG_USER_ONLY) + switch (check_spr_access(sprn, 0, 0)) +#else + switch (check_spr_access(sprn, 0, ctx->supervisor)) +#endif + { + case -1: + RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + break; + case 0: + RET_PRIVREG(); + break; + default: + break; } + switch (sprn) { + case XER: gen_op_load_xer(); break; - case SPR_ENCODE(268): - /* We need to update the time base before reading it */ + case LR: + gen_op_load_lr(); + break; + case CTR: + gen_op_load_ctr(); + break; + case IBAT0U: + gen_op_load_ibat(0, 0); + break; + case IBAT1U: + gen_op_load_ibat(0, 1); + break; + case IBAT2U: + gen_op_load_ibat(0, 2); + break; + case IBAT3U: + gen_op_load_ibat(0, 3); + break; + case IBAT4U: + gen_op_load_ibat(0, 4); + break; + case IBAT5U: + gen_op_load_ibat(0, 5); + break; + case IBAT6U: + gen_op_load_ibat(0, 6); + break; + case IBAT7U: + gen_op_load_ibat(0, 7); + break; + case IBAT0L: + gen_op_load_ibat(1, 0); + break; + case IBAT1L: + gen_op_load_ibat(1, 1); + break; + case IBAT2L: + gen_op_load_ibat(1, 2); + break; + case IBAT3L: + gen_op_load_ibat(1, 3); + break; + case IBAT4L: + gen_op_load_ibat(1, 4); + break; + case IBAT5L: + gen_op_load_ibat(1, 5); + break; + case IBAT6L: + gen_op_load_ibat(1, 6); + break; + case IBAT7L: + gen_op_load_ibat(1, 7); + break; + case DBAT0U: + gen_op_load_dbat(0, 0); + break; + case DBAT1U: + gen_op_load_dbat(0, 1); + break; + case DBAT2U: + gen_op_load_dbat(0, 2); + break; + case DBAT3U: + gen_op_load_dbat(0, 3); + break; + case DBAT4U: + gen_op_load_dbat(0, 4); + break; + case DBAT5U: + gen_op_load_dbat(0, 5); + break; + case DBAT6U: + gen_op_load_dbat(0, 6); + break; + case DBAT7U: + gen_op_load_dbat(0, 7); + break; + case DBAT0L: + gen_op_load_dbat(1, 0); + break; + case DBAT1L: + gen_op_load_dbat(1, 1); + break; + case DBAT2L: + gen_op_load_dbat(1, 2); + break; + case DBAT3L: + gen_op_load_dbat(1, 3); + break; + case DBAT4L: + gen_op_load_dbat(1, 4); + break; + case DBAT5L: + gen_op_load_dbat(1, 5); + break; + case DBAT6L: + gen_op_load_dbat(1, 6); + break; + case DBAT7L: + gen_op_load_dbat(1, 7); + break; + case SDR1: + gen_op_load_sdr1(); + break; + case V_TBL: gen_op_update_tb(ctx->tb_offset); ctx->tb_offset = 0; + /* TBL is still in T0 */ break; - case SPR_ENCODE(269): + case V_TBU: gen_op_update_tb(ctx->tb_offset); ctx->tb_offset = 0; + gen_op_load_tb(1); + break; + case DECR: + gen_op_update_decr(ctx->decr_offset); + ctx->decr_offset = 0; + /* decr is still in T0 */ break; default: gen_op_load_spr(sprn); break; } - gen_op_store_T0_gpr(rD(ctx->opcode)); // - SET_RETVAL(0); + gen_op_store_T0_gpr(rD(ctx->opcode)); } /* mftb */ @@ -1768,23 +1997,22 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) { uint32_t sprn = SPR(ctx->opcode); - if (check_spr_access(sprn, 0, ctx->supervisor) == 0) - SET_RETVAL(EXCP_PRIV); - switch (sprn) { - case SPR_ENCODE(268): /* We need to update the time base before reading it */ + switch (sprn) { + case V_TBL: gen_op_update_tb(ctx->tb_offset); - ctx->tb_offset = 0; + /* TBL is still in T0 */ break; - case SPR_ENCODE(269): + case V_TBU: gen_op_update_tb(ctx->tb_offset); - ctx->tb_offset = 0; + gen_op_load_tb(1); break; default: - SET_RETVAL(EXCP_INVAL); + RET_INVAL(); break; } - SET_RETVAL(0); + ctx->tb_offset = 0; + gen_op_store_T0_gpr(rD(ctx->opcode)); } /* mtcrf */ @@ -1792,18 +2020,22 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC) { gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_cr(CRM(ctx->opcode)); - SET_RETVAL(0); } /* mtmsr */ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) { - if (!ctx->supervisor) - SET_RETVAL(EXCP_PRIV); +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(); +#else + if (!ctx->supervisor) { + RET_PRIVREG(); + } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - SET_RETVAL(EXCP_MTMSR); + ctx->exception = EXCP_MTMSR; +#endif } /* mtspr */ @@ -1811,84 +2043,265 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) { uint32_t sprn = SPR(ctx->opcode); - if (check_spr_access(sprn, 1, ctx->supervisor) == 0) - SET_RETVAL(EXCP_PRIV); +#if 0 + if (loglevel > 0) { + fprintf(logfile, "MTSPR %d src=%d (%d)\n", SPR_ENCODE(sprn), + rS(ctx->opcode), sprn); + } +#endif +#if defined(CONFIG_USER_ONLY) + switch (check_spr_access(sprn, 1, 0)) +#else + switch (check_spr_access(sprn, 1, ctx->supervisor)) +#endif + { + case -1: + RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + break; + case 0: + RET_PRIVREG(); + break; + default: + break; + } gen_op_load_gpr_T0(rS(ctx->opcode)); - if (sprn == SPR_ENCODE(1)) { + switch (sprn) { + case XER: gen_op_store_xer(); - } else { + break; + case LR: + gen_op_andi_(~0x03); + gen_op_store_lr(); + break; + case CTR: + gen_op_store_ctr(); + break; + case IBAT0U: + gen_op_store_ibat(0, 0); + gen_op_tlbia(); + break; + case IBAT1U: + gen_op_store_ibat(0, 1); + gen_op_tlbia(); + break; + case IBAT2U: + gen_op_store_ibat(0, 2); + gen_op_tlbia(); + break; + case IBAT3U: + gen_op_store_ibat(0, 3); + gen_op_tlbia(); + break; + case IBAT4U: + gen_op_store_ibat(0, 4); + gen_op_tlbia(); + break; + case IBAT5U: + gen_op_store_ibat(0, 5); + gen_op_tlbia(); + break; + case IBAT6U: + gen_op_store_ibat(0, 6); + gen_op_tlbia(); + break; + case IBAT7U: + gen_op_store_ibat(0, 7); + gen_op_tlbia(); + break; + case IBAT0L: + gen_op_store_ibat(1, 0); + gen_op_tlbia(); + break; + case IBAT1L: + gen_op_store_ibat(1, 1); + gen_op_tlbia(); + break; + case IBAT2L: + gen_op_store_ibat(1, 2); + gen_op_tlbia(); + break; + case IBAT3L: + gen_op_store_ibat(1, 3); + gen_op_tlbia(); + break; + case IBAT4L: + gen_op_store_ibat(1, 4); + gen_op_tlbia(); + break; + case IBAT5L: + gen_op_store_ibat(1, 5); + gen_op_tlbia(); + break; + case IBAT6L: + gen_op_store_ibat(1, 6); + gen_op_tlbia(); + break; + case IBAT7L: + gen_op_store_ibat(1, 7); + gen_op_tlbia(); + break; + case DBAT0U: + gen_op_store_dbat(0, 0); + gen_op_tlbia(); + break; + case DBAT1U: + gen_op_store_dbat(0, 1); + gen_op_tlbia(); + break; + case DBAT2U: + gen_op_store_dbat(0, 2); + gen_op_tlbia(); + break; + case DBAT3U: + gen_op_store_dbat(0, 3); + gen_op_tlbia(); + break; + case DBAT4U: + gen_op_store_dbat(0, 4); + gen_op_tlbia(); + break; + case DBAT5U: + gen_op_store_dbat(0, 5); + gen_op_tlbia(); + break; + case DBAT6U: + gen_op_store_dbat(0, 6); + gen_op_tlbia(); + break; + case DBAT7U: + gen_op_store_dbat(0, 7); + gen_op_tlbia(); + break; + case DBAT0L: + gen_op_store_dbat(1, 0); + gen_op_tlbia(); + break; + case DBAT1L: + gen_op_store_dbat(1, 1); + gen_op_tlbia(); + break; + case DBAT2L: + gen_op_store_dbat(1, 2); + gen_op_tlbia(); + break; + case DBAT3L: + gen_op_store_dbat(1, 3); + gen_op_tlbia(); + break; + case DBAT4L: + gen_op_store_dbat(1, 4); + gen_op_tlbia(); + break; + case DBAT5L: + gen_op_store_dbat(1, 5); + gen_op_tlbia(); + break; + case DBAT6L: + gen_op_store_dbat(1, 6); + gen_op_tlbia(); + break; + case DBAT7L: + gen_op_store_dbat(1, 7); + gen_op_tlbia(); + break; + case SDR1: + gen_op_store_sdr1(); + gen_op_tlbia(); + break; + case O_TBL: + gen_op_store_tb(0); + ctx->tb_offset = 0; + break; + case O_TBU: + gen_op_store_tb(1); + ctx->tb_offset = 0; + break; + case DECR: + gen_op_store_decr(); + ctx->decr_offset = 0; + break; + default: gen_op_store_spr(sprn); + break; } - SET_RETVAL(0); } /*** Cache management ***/ /* For now, all those will be implemented as nop: * this is valid, regarding the PowerPC specs... + * We just have to flush tb while invalidating instruction cache lines... */ /* dcbf */ -GEN_HANDLER(dcbf, 0x1F, 0x16, 0x17, 0x03E00001, PPC_MEM) +GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) { - SET_RETVAL(0); } /* dcbi (Supervisor only) */ -GEN_HANDLER(dcbi, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_MEM) +GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) { - SET_RETVAL(0); +#if !defined(CONFIG_USER_ONLY) + if (!ctx->supervisor) +#endif + { + RET_PRIVOPC(); + } } /* dcdst */ -GEN_HANDLER(dcbst, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_MEM) +GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) { - SET_RETVAL(0); } /* dcbt */ -GEN_HANDLER(dcbt, 0x1F, 0x16, 0x01, 0x03E00001, PPC_MEM) +GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE) { - SET_RETVAL(0); } /* dcbtst */ -GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x02, 0x03E00001, PPC_MEM) +GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE) { - SET_RETVAL(0); } /* dcbz */ -GEN_HANDLER(dcbz, 0x1F, 0x16, 0x08, 0x03E00001, PPC_MEM) +#if defined(CONFIG_USER_ONLY) +#define op_dcbz() gen_op_dcbz_raw() +#else +#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() +static GenOpFunc *gen_op_dcbz[] = { + &gen_op_dcbz_user, + &gen_op_dcbz_kernel, +}; +#endif + +GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) { if (rA(ctx->opcode) == 0) { gen_op_load_gpr_T0(rB(ctx->opcode)); - gen_op_dcbz_z(); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_dcbz(); + gen_op_add(); } - SET_RETVAL(0); + op_dcbz(); } /* icbi */ -GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_MEM) +GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) { if (rA(ctx->opcode) == 0) { gen_op_load_gpr_T0(rB(ctx->opcode)); - gen_op_icbi_z(); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_icbi(); + gen_op_add(); } - SET_RETVAL(0); + gen_op_icbi(); } /* Optional: */ /* dcba */ -GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_MEM) +GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT) { - SET_RETVAL(0); } /*** Segment register manipulation ***/ @@ -1896,70 +2309,163 @@ GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_MEM) /* mfsr */ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) { - SET_RETVAL(EXCP_INVAL); +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(); +#else + if (!ctx->supervisor) { + RET_PRIVREG(); + } + gen_op_load_sr(SR(ctx->opcode)); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif } /* mfsrin */ -GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x0010F001, PPC_SEGMENT) +GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) { - SET_RETVAL(EXCP_INVAL); +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(); +#else + if (!ctx->supervisor) { + RET_PRIVREG(); + } + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_load_srin(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif } /* mtsr */ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x02, 0x0010F801, PPC_SEGMENT) { - SET_RETVAL(EXCP_INVAL); +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(); +#else + if (!ctx->supervisor) { + RET_PRIVREG(); + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_store_sr(SR(ctx->opcode)); + gen_op_tlbia(); +#endif } /* mtsrin */ -GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x0010F001, PPC_SEGMENT) +GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) { - SET_RETVAL(EXCP_INVAL); +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(); +#else + if (!ctx->supervisor) { + RET_PRIVREG(); + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_store_srin(); + gen_op_tlbia(); +#endif } /*** Lookaside buffer management ***/ /* Optional & supervisor only: */ /* tlbia */ -GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM) +GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) { - SET_RETVAL(EXCP_INVAL); +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(); +#else + if (!ctx->supervisor) { + RET_PRIVOPC(); + } + gen_op_tlbia(); +#endif } /* tlbie */ -GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF8001, PPC_MEM) +GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) { - SET_RETVAL(EXCP_INVAL); +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(); +#else + if (!ctx->supervisor) { + RET_PRIVOPC(); + } + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_tlbie(); +#endif } /* tlbsync */ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFFC01, PPC_MEM) { - SET_RETVAL(EXCP_INVAL); +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(); +#else + if (!ctx->supervisor) { + RET_PRIVOPC(); + } + /* This has no effect: it should ensure that all previous + * tlbie have completed + */ +#endif } /*** External control ***/ /* Optional: */ /* eciwx */ +#if defined(CONFIG_USER_ONLY) +#define op_eciwx() gen_op_eciwx_raw() +#define op_ecowx() gen_op_ecowx_raw() +#else +#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])() +#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])() +static GenOpFunc *gen_op_eciwx[] = { + &gen_op_eciwx_user, + &gen_op_eciwx_kernel, +}; +static GenOpFunc *gen_op_ecowx[] = { + &gen_op_ecowx_user, + &gen_op_ecowx_kernel, +}; +#endif + GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN) { - SET_RETVAL(EXCP_INVAL); + /* Should check EAR[E] & alignment ! */ + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_eciwx(); + gen_op_store_T0_gpr(rD(ctx->opcode)); } /* ecowx */ GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) { - SET_RETVAL(EXCP_INVAL); + /* Should check EAR[E] & alignment ! */ + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + gen_op_load_gpr_T2(rS(ctx->opcode)); + op_ecowx(); } /* End opcode list */ GEN_OPCODE_MARK(end); /*****************************************************************************/ - +#include #include -extern FILE *stderr; -void free (void *p); -int fflush (FILE *f); + +int fflush (FILE *stream); /* Main ppc opcodes table: * at init, all opcodes are invalids @@ -1982,6 +2488,7 @@ static inline opc_handler_t **ind_table(void *handler) return (opc_handler_t **)((unsigned long)handler & ~3); } +/* Instruction table creation */ /* Opcodes tables creation */ static void fill_new_table (opc_handler_t **table, int len) { @@ -2014,10 +2521,11 @@ static int insert_in_table (opc_handler_t **table, unsigned char idx, return 0; } -static int register_direct_insn (unsigned char idx, opc_handler_t *handler) +static int register_direct_insn (opc_handler_t **ppc_opcodes, + unsigned char idx, opc_handler_t *handler) { if (insert_in_table(ppc_opcodes, idx, handler) < 0) { - fprintf(stderr, "*** ERROR: opcode %02x already assigned in main " + printf("*** ERROR: opcode %02x already assigned in main " "opcode table\n", idx); return -1; } @@ -2031,20 +2539,20 @@ static int register_ind_in_table (opc_handler_t **table, { if (table[idx1] == &invalid_handler) { if (create_new_table(table, idx1) < 0) { - fprintf(stderr, "*** ERROR: unable to create indirect table " + printf("*** ERROR: unable to create indirect table " "idx=%02x\n", idx1); return -1; } } else { if (!is_indirect_opcode(table[idx1])) { - fprintf(stderr, "*** ERROR: idx %02x already assigned to a direct " + printf("*** ERROR: idx %02x already assigned to a direct " "opcode\n", idx1); return -1; } } if (handler != NULL && insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { - fprintf(stderr, "*** ERROR: opcode %02x already assigned in " + printf("*** ERROR: opcode %02x already assigned in " "opcode table %02x\n", idx2, idx1); return -1; } @@ -2052,7 +2560,8 @@ static int register_ind_in_table (opc_handler_t **table, return 0; } -static int register_ind_insn (unsigned char idx1, unsigned char idx2, +static int register_ind_insn (opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, opc_handler_t *handler) { int ret; @@ -2062,17 +2571,18 @@ static int register_ind_insn (unsigned char idx1, unsigned char idx2, return ret; } -static int register_dblind_insn (unsigned char idx1, unsigned char idx2, +static int register_dblind_insn (opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, unsigned char idx3, opc_handler_t *handler) { if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { - fprintf(stderr, "*** ERROR: unable to join indirect table idx " + printf("*** ERROR: unable to join indirect table idx " "[%02x-%02x]\n", idx1, idx2); return -1; } if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, handler) < 0) { - fprintf(stderr, "*** ERROR: unable to insert opcode " + printf("*** ERROR: unable to insert opcode " "[%02x-%02x-%02x]\n", idx1, idx2, idx3); return -1; } @@ -2080,19 +2590,20 @@ static int register_dblind_insn (unsigned char idx1, unsigned char idx2, return 0; } -static int register_insn (opcode_t *insn) +static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn) { if (insn->opc2 != 0xFF) { if (insn->opc3 != 0xFF) { - if (register_dblind_insn(insn->opc1, insn->opc2, insn->opc3, - &insn->handler) < 0) + if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, + insn->opc3, &insn->handler) < 0) return -1; } else { - if (register_ind_insn(insn->opc1, insn->opc2, &insn->handler) < 0) + if (register_ind_insn(ppc_opcodes, insn->opc1, + insn->opc2, &insn->handler) < 0) return -1; } } else { - if (register_direct_insn(insn->opc1, &insn->handler) < 0) + if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) return -1; } @@ -2125,13 +2636,13 @@ static int test_opcode_table (opc_handler_t **table, int len) return count; } -static void fix_opcode_tables (void) +static void fix_opcode_tables (opc_handler_t **ppc_opcodes) { if (test_opcode_table(ppc_opcodes, 0x40) == 0) - fprintf(stderr, "*** WARNING: no opcode defined !\n"); + printf("*** WARNING: no opcode defined !\n"); } -#define SPR_RIGHTS(rw, priv) ((2 * (priv)) + (rw)) +#define SPR_RIGHTS(rw, priv) (1 << ((2 * (priv)) + (rw))) #define SPR_UR SPR_RIGHTS(0, 0) #define SPR_UW SPR_RIGHTS(1, 0) #define SPR_SR SPR_RIGHTS(0, 1) @@ -2142,87 +2653,199 @@ do { \ spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \ } while (0) -static void init_spr_rights (void) +static void init_spr_rights (uint32_t pvr) { /* XER (SPR 1) */ - spr_set_rights(SPR_ENCODE(1), SPR_UR | SPR_UW | SPR_SR | SPR_SW); + spr_set_rights(XER, SPR_UR | SPR_UW | SPR_SR | SPR_SW); /* LR (SPR 8) */ - spr_set_rights(SPR_ENCODE(8), SPR_UR | SPR_UW | SPR_SR | SPR_SW); + spr_set_rights(LR, SPR_UR | SPR_UW | SPR_SR | SPR_SW); /* CTR (SPR 9) */ - spr_set_rights(SPR_ENCODE(9), SPR_UR | SPR_UW | SPR_SR | SPR_SW); + spr_set_rights(CTR, SPR_UR | SPR_UW | SPR_SR | SPR_SW); /* TBL (SPR 268) */ - spr_set_rights(SPR_ENCODE(268), SPR_UR | SPR_SR); + spr_set_rights(V_TBL, SPR_UR | SPR_SR); /* TBU (SPR 269) */ - spr_set_rights(SPR_ENCODE(269), SPR_UR | SPR_SR); + spr_set_rights(V_TBU, SPR_UR | SPR_SR); /* DSISR (SPR 18) */ - spr_set_rights(SPR_ENCODE(18), SPR_SR | SPR_SW); + spr_set_rights(DSISR, SPR_SR | SPR_SW); /* DAR (SPR 19) */ - spr_set_rights(SPR_ENCODE(19), SPR_SR | SPR_SW); + spr_set_rights(DAR, SPR_SR | SPR_SW); /* DEC (SPR 22) */ - spr_set_rights(SPR_ENCODE(22), SPR_SR | SPR_SW); + spr_set_rights(DECR, SPR_SR | SPR_SW); /* SDR1 (SPR 25) */ - spr_set_rights(SPR_ENCODE(25), SPR_SR | SPR_SW); + spr_set_rights(SDR1, SPR_SR | SPR_SW); + /* SRR0 (SPR 26) */ + spr_set_rights(SRR0, SPR_SR | SPR_SW); + /* SRR1 (SPR 27) */ + spr_set_rights(SRR1, SPR_SR | SPR_SW); /* SPRG0 (SPR 272) */ - spr_set_rights(SPR_ENCODE(272), SPR_SR | SPR_SW); + spr_set_rights(SPRG0, SPR_SR | SPR_SW); /* SPRG1 (SPR 273) */ - spr_set_rights(SPR_ENCODE(273), SPR_SR | SPR_SW); + spr_set_rights(SPRG1, SPR_SR | SPR_SW); /* SPRG2 (SPR 274) */ - spr_set_rights(SPR_ENCODE(274), SPR_SR | SPR_SW); + spr_set_rights(SPRG2, SPR_SR | SPR_SW); /* SPRG3 (SPR 275) */ - spr_set_rights(SPR_ENCODE(275), SPR_SR | SPR_SW); + spr_set_rights(SPRG3, SPR_SR | SPR_SW); /* ASR (SPR 280) */ - spr_set_rights(SPR_ENCODE(281), SPR_SR | SPR_SW); + spr_set_rights(ASR, SPR_SR | SPR_SW); /* EAR (SPR 282) */ - spr_set_rights(SPR_ENCODE(282), SPR_SR | SPR_SW); + spr_set_rights(EAR, SPR_SR | SPR_SW); + /* TBL (SPR 284) */ + spr_set_rights(O_TBL, SPR_SW); + /* TBU (SPR 285) */ + spr_set_rights(O_TBU, SPR_SW); + /* PVR (SPR 287) */ + spr_set_rights(PVR, SPR_SR); /* IBAT0U (SPR 528) */ - spr_set_rights(SPR_ENCODE(528), SPR_SR | SPR_SW); + spr_set_rights(IBAT0U, SPR_SR | SPR_SW); /* IBAT0L (SPR 529) */ - spr_set_rights(SPR_ENCODE(529), SPR_SR | SPR_SW); + spr_set_rights(IBAT0L, SPR_SR | SPR_SW); /* IBAT1U (SPR 530) */ - spr_set_rights(SPR_ENCODE(530), SPR_SR | SPR_SW); + spr_set_rights(IBAT1U, SPR_SR | SPR_SW); /* IBAT1L (SPR 531) */ - spr_set_rights(SPR_ENCODE(531), SPR_SR | SPR_SW); + spr_set_rights(IBAT1L, SPR_SR | SPR_SW); /* IBAT2U (SPR 532) */ - spr_set_rights(SPR_ENCODE(532), SPR_SR | SPR_SW); + spr_set_rights(IBAT2U, SPR_SR | SPR_SW); /* IBAT2L (SPR 533) */ - spr_set_rights(SPR_ENCODE(533), SPR_SR | SPR_SW); + spr_set_rights(IBAT2L, SPR_SR | SPR_SW); /* IBAT3U (SPR 534) */ - spr_set_rights(SPR_ENCODE(534), SPR_SR | SPR_SW); + spr_set_rights(IBAT3U, SPR_SR | SPR_SW); /* IBAT3L (SPR 535) */ - spr_set_rights(SPR_ENCODE(535), SPR_SR | SPR_SW); + spr_set_rights(IBAT3L, SPR_SR | SPR_SW); /* DBAT0U (SPR 536) */ - spr_set_rights(SPR_ENCODE(536), SPR_SR | SPR_SW); + spr_set_rights(DBAT0U, SPR_SR | SPR_SW); /* DBAT0L (SPR 537) */ - spr_set_rights(SPR_ENCODE(537), SPR_SR | SPR_SW); + spr_set_rights(DBAT0L, SPR_SR | SPR_SW); /* DBAT1U (SPR 538) */ - spr_set_rights(SPR_ENCODE(538), SPR_SR | SPR_SW); + spr_set_rights(DBAT1U, SPR_SR | SPR_SW); /* DBAT1L (SPR 539) */ - spr_set_rights(SPR_ENCODE(539), SPR_SR | SPR_SW); + spr_set_rights(DBAT1L, SPR_SR | SPR_SW); /* DBAT2U (SPR 540) */ - spr_set_rights(SPR_ENCODE(540), SPR_SR | SPR_SW); + spr_set_rights(DBAT2U, SPR_SR | SPR_SW); /* DBAT2L (SPR 541) */ - spr_set_rights(SPR_ENCODE(541), SPR_SR | SPR_SW); + spr_set_rights(DBAT2L, SPR_SR | SPR_SW); /* DBAT3U (SPR 542) */ - spr_set_rights(SPR_ENCODE(542), SPR_SR | SPR_SW); + spr_set_rights(DBAT3U, SPR_SR | SPR_SW); /* DBAT3L (SPR 543) */ - spr_set_rights(SPR_ENCODE(543), SPR_SR | SPR_SW); + spr_set_rights(DBAT3L, SPR_SR | SPR_SW); /* DABR (SPR 1013) */ - spr_set_rights(SPR_ENCODE(1013), SPR_SR | SPR_SW); + spr_set_rights(DABR, SPR_SR | SPR_SW); /* FPECR (SPR 1022) */ - spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW); + spr_set_rights(FPECR, SPR_SR | SPR_SW); /* PIR (SPR 1023) */ - spr_set_rights(SPR_ENCODE(1023), SPR_SR | SPR_SW); - /* PVR (SPR 287) */ - spr_set_rights(SPR_ENCODE(287), SPR_SR); - /* TBL (SPR 284) */ - spr_set_rights(SPR_ENCODE(284), SPR_SW); - /* TBU (SPR 285) */ - spr_set_rights(SPR_ENCODE(285), SPR_SW); + spr_set_rights(PIR, SPR_SR | SPR_SW); + /* Special registers for MPC740/745/750/755 (aka G3) & IBM 750 */ + if ((pvr & 0xFFFF0000) == 0x00080000 || + (pvr & 0xFFFF0000) == 0x70000000) { + /* HID0 */ + spr_set_rights(SPR_ENCODE(1008), SPR_SR | SPR_SW); + /* HID1 */ + spr_set_rights(SPR_ENCODE(1009), SPR_SR | SPR_SW); + /* IABR */ + spr_set_rights(SPR_ENCODE(1010), SPR_SR | SPR_SW); + /* ICTC */ + spr_set_rights(SPR_ENCODE(1019), SPR_SR | SPR_SW); + /* L2CR */ + spr_set_rights(SPR_ENCODE(1017), SPR_SR | SPR_SW); + /* MMCR0 */ + spr_set_rights(SPR_ENCODE(952), SPR_SR | SPR_SW); + /* MMCR1 */ + spr_set_rights(SPR_ENCODE(956), SPR_SR | SPR_SW); + /* PMC1 */ + spr_set_rights(SPR_ENCODE(953), SPR_SR | SPR_SW); + /* PMC2 */ + spr_set_rights(SPR_ENCODE(954), SPR_SR | SPR_SW); + /* PMC3 */ + spr_set_rights(SPR_ENCODE(957), SPR_SR | SPR_SW); + /* PMC4 */ + spr_set_rights(SPR_ENCODE(958), SPR_SR | SPR_SW); + /* SIA */ + spr_set_rights(SPR_ENCODE(955), SPR_SR | SPR_SW); + /* THRM1 */ + spr_set_rights(SPR_ENCODE(1020), SPR_SR | SPR_SW); + /* THRM2 */ + spr_set_rights(SPR_ENCODE(1021), SPR_SR | SPR_SW); + /* THRM3 */ + spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW); + /* UMMCR0 */ + spr_set_rights(SPR_ENCODE(936), SPR_UR | SPR_UW); + /* UMMCR1 */ + spr_set_rights(SPR_ENCODE(940), SPR_UR | SPR_UW); + /* UPMC1 */ + spr_set_rights(SPR_ENCODE(937), SPR_UR | SPR_UW); + /* UPMC2 */ + spr_set_rights(SPR_ENCODE(938), SPR_UR | SPR_UW); + /* UPMC3 */ + spr_set_rights(SPR_ENCODE(941), SPR_UR | SPR_UW); + /* UPMC4 */ + spr_set_rights(SPR_ENCODE(942), SPR_UR | SPR_UW); + /* USIA */ + spr_set_rights(SPR_ENCODE(939), SPR_UR | SPR_UW); + } + /* MPC755 has special registers */ + if (pvr == 0x00083100) { + /* SPRG4 */ + spr_set_rights(SPRG4, SPR_SR | SPR_SW); + /* SPRG5 */ + spr_set_rights(SPRG5, SPR_SR | SPR_SW); + /* SPRG6 */ + spr_set_rights(SPRG6, SPR_SR | SPR_SW); + /* SPRG7 */ + spr_set_rights(SPRG7, SPR_SR | SPR_SW); + /* IBAT4U */ + spr_set_rights(IBAT4U, SPR_SR | SPR_SW); + /* IBAT4L */ + spr_set_rights(IBAT4L, SPR_SR | SPR_SW); + /* IBAT5U */ + spr_set_rights(IBAT5U, SPR_SR | SPR_SW); + /* IBAT5L */ + spr_set_rights(IBAT5L, SPR_SR | SPR_SW); + /* IBAT6U */ + spr_set_rights(IBAT6U, SPR_SR | SPR_SW); + /* IBAT6L */ + spr_set_rights(IBAT6L, SPR_SR | SPR_SW); + /* IBAT7U */ + spr_set_rights(IBAT7U, SPR_SR | SPR_SW); + /* IBAT7L */ + spr_set_rights(IBAT7L, SPR_SR | SPR_SW); + /* DBAT4U */ + spr_set_rights(DBAT4U, SPR_SR | SPR_SW); + /* DBAT4L */ + spr_set_rights(DBAT4L, SPR_SR | SPR_SW); + /* DBAT5U */ + spr_set_rights(DBAT5U, SPR_SR | SPR_SW); + /* DBAT5L */ + spr_set_rights(DBAT5L, SPR_SR | SPR_SW); + /* DBAT6U */ + spr_set_rights(DBAT6U, SPR_SR | SPR_SW); + /* DBAT6L */ + spr_set_rights(DBAT6L, SPR_SR | SPR_SW); + /* DBAT7U */ + spr_set_rights(DBAT7U, SPR_SR | SPR_SW); + /* DBAT7L */ + spr_set_rights(DBAT7L, SPR_SR | SPR_SW); + /* DMISS */ + spr_set_rights(SPR_ENCODE(976), SPR_SR | SPR_SW); + /* DCMP */ + spr_set_rights(SPR_ENCODE(977), SPR_SR | SPR_SW); + /* DHASH1 */ + spr_set_rights(SPR_ENCODE(978), SPR_SR | SPR_SW); + /* DHASH2 */ + spr_set_rights(SPR_ENCODE(979), SPR_SR | SPR_SW); + /* IMISS */ + spr_set_rights(SPR_ENCODE(980), SPR_SR | SPR_SW); + /* ICMP */ + spr_set_rights(SPR_ENCODE(981), SPR_SR | SPR_SW); + /* RPA */ + spr_set_rights(SPR_ENCODE(982), SPR_SR | SPR_SW); + /* HID2 */ + spr_set_rights(SPR_ENCODE(1011), SPR_SR | SPR_SW); + /* L2PM */ + spr_set_rights(SPR_ENCODE(1016), SPR_SR | SPR_SW); + } } -/* PPC "main stream" common instructions */ -#define PPC_COMMON (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ - PPC_MISC | PPC_EXTERN | PPC_SEGMENT) +/*****************************************************************************/ +/* PPC "main stream" common instructions (no optional ones) */ typedef struct ppc_proc_t { int flags; @@ -2240,9 +2863,26 @@ static ppc_proc_t ppc_proc_common = { .specific = NULL, }; +static ppc_proc_t ppc_proc_G3 = { + .flags = PPC_750, + .specific = NULL, +}; + static ppc_def_t ppc_defs[] = { - /* Fallback */ + /* MPC740/745/750/755 (G3) */ + { + .pvr = 0x00080000, + .pvr_mask = 0xFFFF0000, + .proc = &ppc_proc_G3, + }, + /* IBM 750FX (G3 embedded) */ + { + .pvr = 0x70000000, + .pvr_mask = 0xFFFF0000, + .proc = &ppc_proc_G3, + }, + /* Fallback (generic PPC) */ { .pvr = 0x00000000, .pvr_mask = 0x00000000, @@ -2250,7 +2890,7 @@ static ppc_def_t ppc_defs[] = }, }; -static int create_ppc_proc (unsigned long pvr) +static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr) { opcode_t *opc; int i, flags; @@ -2265,65 +2905,71 @@ static int create_ppc_proc (unsigned long pvr) } for (opc = &opc_start + 1; opc != &opc_end; opc++) { - if ((opc->type & flags) != 0) - if (register_insn(opc) < 0) { - fprintf(stderr, "*** ERROR initializing PPC instruction " + if ((opc->handler.type & flags) != 0) + if (register_insn(ppc_opcodes, opc) < 0) { + printf("*** ERROR initializing PPC instruction " "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, opc->opc3); return -1; } } - fix_opcode_tables(); + fix_opcode_tables(ppc_opcodes); return 0; } + /*****************************************************************************/ -uint32_t do_load_xer (void); +/* Misc PPC helpers */ +FILE *stdout; void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) { int i; - if (loglevel > 0) { - fprintf(logfile, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x\n", - env->nip, env->LR, env->CTR, do_load_xer()); + fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x " + "MSR=0x%08x\n", env->nip, env->lr, env->ctr, + _load_xer(), _load_msr()); for (i = 0; i < 32; i++) { if ((i & 7) == 0) - fprintf(logfile, "GPR%02d:", i); - fprintf(logfile, " %08x", env->gpr[i]); + fprintf(f, "GPR%02d:", i); + fprintf(f, " %08x", env->gpr[i]); if ((i & 7) == 7) - fprintf(logfile, "\n"); + fprintf(f, "\n"); } - fprintf(logfile, "CR: 0x"); + fprintf(f, "CR: 0x"); for (i = 0; i < 8; i++) - fprintf(logfile, "%01x", env->crf[i]); - fprintf(logfile, " ["); + fprintf(f, "%01x", env->crf[i]); + fprintf(f, " ["); for (i = 0; i < 8; i++) { char a = '-'; - if (env->crf[i] & 0x08) a = 'L'; else if (env->crf[i] & 0x04) a = 'G'; else if (env->crf[i] & 0x02) a = 'E'; - fprintf(logfile, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); + fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } - fprintf(logfile, " ] "); - fprintf(logfile, "TB: 0x%08x %08x\n", env->spr[SPR_ENCODE(269)], - env->spr[SPR_ENCODE(268)]); + fprintf(f, " ] "); + fprintf(f, "TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); for (i = 0; i < 16; i++) { if ((i & 3) == 0) - fprintf(logfile, "FPR%02d:", i); - fprintf(logfile, " %016llx", *((uint64_t *)(&env->fpr[i]))); + fprintf(f, "FPR%02d:", i); + fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i])); if ((i & 3) == 3) - fprintf(logfile, "\n"); - } - fflush(logfile); + fprintf(f, "\n"); } + fprintf(f, "SRR0 0x%08x SRR1 0x%08x\n", + env->spr[SRR0], env->spr[SRR1]); + fprintf(f, "reservation 0x%08x\n", env->reserve); + fflush(f); } +#if !defined(CONFIG_USER_ONLY) && defined (USE_OPENFIRMWARE) +int setup_machine (CPUPPCState *env, uint32_t mid); +#endif + CPUPPCState *cpu_ppc_init(void) { CPUPPCState *env; @@ -2334,10 +2980,26 @@ CPUPPCState *cpu_ppc_init(void) if (!env) return NULL; memset(env, 0, sizeof(CPUPPCState)); - env->PVR = 0; - if (create_ppc_proc(0) < 0) +#if !defined(CONFIG_USER_ONLY) && defined (USE_OPEN_FIRMWARE) + setup_machine(env, 0); +#else +// env->spr[PVR] = 0; /* Basic PPC */ + env->spr[PVR] = 0x00080100; /* G3 CPU */ +// env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */ +// env->spr[PVR] = 0x00070100; /* IBM 750FX */ +#endif + env->decr = 0xFFFFFFFF; + if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) return NULL; - init_spr_rights(); + init_spr_rights(env->spr[PVR]); + tlb_flush(env); +#if defined (DO_SINGLE_STEP) + /* Single step trace mode */ + msr_se = 1; +#endif +#if defined(CONFIG_USER_ONLY) + msr_pr = 1; +#endif return env; } @@ -2348,6 +3010,11 @@ void cpu_ppc_close(CPUPPCState *env) free(env); } +/*****************************************************************************/ +void raise_exception_err (int exception_index, int error_code); +int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, + int dialect); + int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) { @@ -2356,7 +3023,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, uint32_t pc_start; uint16_t *gen_opc_end; int j, lj = -1; - int ret = 0; pc_start = tb->pc; gen_opc_ptr = gen_opc_buf; @@ -2364,11 +3030,21 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opparam_ptr = gen_opparam_buf; ctx.nip = (uint32_t *)pc_start; ctx.tb_offset = 0; - ctx.supervisor = msr_ip; + ctx.decr_offset = 0; ctx.tb = tb; - ctx.exception = 0; - - while (ret == 0 && gen_opc_ptr < gen_opc_end) { + ctx.exception = EXCP_NONE; +#if defined(CONFIG_USER_ONLY) + ctx.mem_idx = 0; +#else + ctx.supervisor = 1 - msr_pr; + ctx.mem_idx = (1 - msr_pr); +#endif +#if defined (DO_SINGLE_STEP) + /* Single step trace mode */ + msr_se = 1; +#endif + /* Set env in case of segfault during code fetch */ + while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { if (search_pc) { if (loglevel > 0) fprintf(logfile, "Search PC...\n"); @@ -2381,15 +3057,26 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_instr_start[lj] = 1; } } - ctx.opcode = __be32_to_cpu(*ctx.nip); -#ifdef DEBUG_DISAS +#if defined DEBUG_DISAS if (loglevel > 0) { fprintf(logfile, "----------------\n"); - fprintf(logfile, "%p: translate opcode %08x\n", - ctx.nip, ctx.opcode); + fprintf(logfile, "nip=%p super=%d ir=%d\n", + ctx.nip, 1 - msr_pr, msr_ir); + } +#endif + ctx.opcode = ldl_code(ctx.nip); +#if defined DEBUG_DISAS + if (loglevel > 0) { + fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", + ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), + opc3(ctx.opcode)); } #endif ctx.nip++; + ctx.tb_offset++; + /* Check decrementer exception */ + if (++ctx.decr_offset == env->decr + 1) + ctx.exception = EXCP_DECR; table = ppc_opcodes; handler = table[opc1(ctx.opcode)]; if (is_indirect_opcode(handler)) { @@ -2405,62 +3092,93 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (loglevel > 0) { if (handler->handler == &gen_invalid) { fprintf(logfile, "invalid/unsupported opcode: " - "%02x -%02x - %02x (%08x)\n", opc1(ctx.opcode), - opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode); + "%02x -%02x - %02x (%08x) %p\n", + opc1(ctx.opcode), opc2(ctx.opcode), + opc3(ctx.opcode), ctx.opcode, ctx.nip - 1); } else { fprintf(logfile, "invalid bits: %08x for opcode: " - "%02x -%02x - %02x (%p)\n", + "%02x -%02x - %02x (0x%08x) (%p)\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), - handler->handler); + ctx.opcode, ctx.nip - 1); } + } else { + if (handler->handler == &gen_invalid) { + printf("invalid/unsupported opcode: " + "%02x -%02x - %02x (%08x) %p\n", + opc1(ctx.opcode), opc2(ctx.opcode), + opc3(ctx.opcode), ctx.opcode, ctx.nip - 1); + } else { + printf("invalid bits: %08x for opcode: " + "%02x -%02x - %02x (0x%08x) (%p)\n", + ctx.opcode & handler->inval, opc1(ctx.opcode), + opc2(ctx.opcode), opc3(ctx.opcode), + ctx.opcode, ctx.nip - 1); + } } - ret = GET_RETVAL(gen_invalid, ctx.opcode); + (*gen_invalid)(&ctx); } else { - ret = GET_RETVAL(*(handler->handler), ctx.opcode); + (*(handler->handler))(&ctx); } - ctx.tb_offset++; -#if defined (DO_SINGLE_STEP) - break; + /* Check trace mode exceptions */ + if ((msr_be && ctx.exception == EXCP_BRANCH) || + /* Check in single step trace mode + * we need to stop except if: + * - rfi, trap or syscall + * - first instruction of an exception handler + */ + (msr_se && ((uint32_t)ctx.nip < 0x100 || + (uint32_t)ctx.nip > 0xF00 || + ((uint32_t)ctx.nip & 0xFC) != 0x04) && + ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI && + ctx.exception != EXCP_TRAP)) { +#if !defined(CONFIG_USER_ONLY) + gen_op_queue_exception(EXCP_TRACE); #endif + if (ctx.exception == EXCP_NONE) { + ctx.exception = EXCP_TRACE; } -#if defined (DO_STEP_FLUSH) - tb_flush(env); -#endif - /* We need to update the time base */ - if (!search_pc) - gen_op_update_tb(ctx.tb_offset); - /* If we are in step-by-step mode, do a branch to the next instruction - * so the nip will be up-to-date - */ -#if defined (DO_SINGLE_STEP) - if (ret == 0) { + } + /* if too long translation, stop generation too */ + if (gen_opc_ptr >= gen_opc_end || + ((uint32_t)ctx.nip - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + if (ctx.exception == EXCP_NONE) { gen_op_b((uint32_t)ctx.nip); - ret = EXCP_BRANCH; + ctx.exception = EXCP_BRANCH; } -#endif - /* If the exeption isn't a PPC one, - * generate it now. - */ - if (ret != EXCP_BRANCH) { - gen_op_set_T0(0); - if ((ret & 0x2000) == 0) - gen_op_raise_exception(ret); } + } + /* In case of branch, this has already been done *BEFORE* the branch */ + if (ctx.exception != EXCP_BRANCH && ctx.exception != EXCP_RFI) { + gen_op_update_tb(ctx.tb_offset); + gen_op_update_decr(ctx.decr_offset); + gen_op_process_exceptions((uint32_t)ctx.nip); + } +#if 1 /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump * do bad business and then qemu crashes ! */ gen_op_set_T0(0); +#endif /* Generate the return instruction */ gen_op_exit_tb(); *gen_opc_ptr = INDEX_op_end; - if (!search_pc) - tb->size = (uint32_t)ctx.nip - pc_start; - else + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; tb->size = 0; -// *gen_opc_ptr = INDEX_op_end; + if (loglevel > 0) { + page_dump(logfile); + } + } else { + tb->size = (uint32_t)ctx.nip - pc_start; + } #ifdef DEBUG_DISAS if (loglevel > 0) { + fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); + cpu_ppc_dump_state(env, logfile, 0); fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); disas(logfile, (void *)pc_start, (uint32_t)ctx.nip - pc_start, 0, 0); fprintf(logfile, "\n"); @@ -2474,12 +3192,12 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, return 0; } -int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb) +int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) { return gen_intermediate_code_internal(env, tb, 0); } -int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb) +int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) { return gen_intermediate_code_internal(env, tb, 1); } -- cgit v1.2.3 From ac9eb0731ad123f8789005978500ac67026188c2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:26:24 +0000 Subject: suppressed explicit access type and use the exception routine to infer it from the micro operation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@529 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 ++ target-ppc/helper.c | 2 +- target-ppc/op_helper_mem.h | 9 +++--- target-ppc/op_mem.h | 74 +++++++++++++++++++++------------------------- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index bc3c46df6..850a88ba8 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -153,6 +153,8 @@ typedef struct CPUPPCState { jmp_buf jmp_env; int exception_index; int error_code; + int access_type; /* when a memory exception occurs, the access + type is stored here */ uint32_t exceptions; /* exception queue */ uint32_t errors[16]; int user_mode_only; /* user mode only simulation */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 272dc9588..1520d6c82 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -512,7 +512,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, // printf("%s 0\n", __func__); is_user = flags & 0x01; - access_type = flags & ~0x01; + access_type = env->access_type; if (env->user_mode_only) { /* user mode only emulation */ ret = -1; diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index 6c2027319..f3d5a1675 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -8,14 +8,14 @@ void glue(do_lsw, MEMSUFFIX) (int dst) __func__, T0, T1, dst); } for (; T1 > 3; T1 -= 4, T0 += 4) { - ugpr(dst++) = glue(_ldl, MEMSUFFIX)((void *)T0, ACCESS_INT); + ugpr(dst++) = glue(ldl, MEMSUFFIX)((void *)T0); if (dst == 32) dst = 0; } if (T1 > 0) { tmp = 0; for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { - tmp |= glue(_ldub, MEMSUFFIX)((void *)T0, ACCESS_INT) << sh; + tmp |= glue(ldub, MEMSUFFIX)((void *)T0) << sh; } ugpr(dst) = tmp; } @@ -30,14 +30,13 @@ void glue(do_stsw, MEMSUFFIX) (int src) __func__, T0, T1, src); } for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(_stl, MEMSUFFIX)((void *)T0, ugpr(src++), ACCESS_INT); + glue(stl, MEMSUFFIX)((void *)T0, ugpr(src++)); if (src == 32) src = 0; } if (T1 > 0) { for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) - glue(_stb, MEMSUFFIX)((void *)T0, (ugpr(src) >> sh) & 0xFF, - ACCESS_INT); + glue(stb, MEMSUFFIX)((void *)T0, (ugpr(src) >> sh) & 0xFF); } } diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 2a50f84f4..e66a1dbe0 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -2,68 +2,62 @@ void glue(do_lsw, MEMSUFFIX) (int dst); void glue(do_stsw, MEMSUFFIX) (int src); -/* Internal helpers for sign extension and byte-reverse */ -static inline uint32_t glue(_ld16x, MEMSUFFIX) (void *EA, int type) +static inline uint16_t glue(ld16r, MEMSUFFIX) (void *EA) { - return s_ext16(glue(_lduw, MEMSUFFIX)(EA, type)); -} - -static inline uint16_t glue(_ld16r, MEMSUFFIX) (void *EA, int type) -{ - uint16_t tmp = glue(_lduw, MEMSUFFIX)(EA, type); + uint16_t tmp = glue(lduw, MEMSUFFIX)(EA); return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); } -static inline uint32_t glue(_ld32r, MEMSUFFIX) (void *EA, int type) +static inline uint32_t glue(ld32r, MEMSUFFIX) (void *EA) { - uint32_t tmp = glue(_ldl, MEMSUFFIX)(EA, type); + uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); return ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); } -static inline void glue(_st16r, MEMSUFFIX) (void *EA, uint16_t data, int type) +static inline void glue(st16r, MEMSUFFIX) (void *EA, uint16_t data) { uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8); - glue(_stw, MEMSUFFIX)(EA, tmp, type); + glue(stw, MEMSUFFIX)(EA, tmp); } -static inline void glue(_st32r, MEMSUFFIX) (void *EA, uint32_t data, int type) +static inline void glue(st32r, MEMSUFFIX) (void *EA, uint32_t data) { uint32_t tmp = ((data & 0xFF000000) >> 24) | ((data & 0x00FF0000) >> 8) | ((data & 0x0000FF00) << 8) | ((data & 0x000000FF) << 24); - glue(_stl, MEMSUFFIX)(EA, tmp, type); + glue(stl, MEMSUFFIX)(EA, tmp); } /*** Integer load ***/ #define PPC_LD_OP(name, op) \ PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ { \ - T1 = glue(op, MEMSUFFIX)((void *)T0, ACCESS_INT); \ + T1 = glue(op, MEMSUFFIX)((void *)T0); \ RETURN(); \ } #define PPC_ST_OP(name, op) \ PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ { \ - glue(op, MEMSUFFIX)((void *)T0, T1, ACCESS_INT); \ + glue(op, MEMSUFFIX)((void *)T0, T1); \ RETURN(); \ } -PPC_LD_OP(bz, _ldub); -PPC_LD_OP(ha, _ld16x); -PPC_LD_OP(hz, _lduw); -PPC_LD_OP(wz, _ldl); +PPC_LD_OP(bz, ldub); +PPC_LD_OP(ha, ldsw); +PPC_LD_OP(hz, lduw); +PPC_LD_OP(wz, ldl); /*** Integer store ***/ -PPC_ST_OP(b, _stb); -PPC_ST_OP(h, _stw); -PPC_ST_OP(w, _stl); +PPC_ST_OP(b, stb); +PPC_ST_OP(h, stw); +PPC_ST_OP(w, stl); /*** Integer load and store with byte reverse ***/ -PPC_LD_OP(hbr, _ld16r); -PPC_LD_OP(wbr, _ld32r); -PPC_ST_OP(hbr, _st16r); -PPC_ST_OP(wbr, _st32r); +PPC_LD_OP(hbr, ld16r); +PPC_LD_OP(wbr, ld32r); +PPC_ST_OP(hbr, st16r); +PPC_ST_OP(wbr, st32r); /*** Integer load and store multiple ***/ PPC_OP(glue(lmw, MEMSUFFIX)) @@ -71,7 +65,7 @@ PPC_OP(glue(lmw, MEMSUFFIX)) int dst = PARAM(1); for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(_ldl, MEMSUFFIX)((void *)T0, ACCESS_INT); + ugpr(dst) = glue(ldl, MEMSUFFIX)((void *)T0); } RETURN(); } @@ -81,7 +75,7 @@ PPC_OP(glue(stmw, MEMSUFFIX)) int src = PARAM(1); for (; src < 32; src++, T0 += 4) { - glue(_stl, MEMSUFFIX)((void *)T0, ugpr(src), ACCESS_INT); + glue(stl, MEMSUFFIX)((void *)T0, ugpr(src)); } RETURN(); } @@ -150,7 +144,7 @@ PPC_OP(glue(stwcx, MEMSUFFIX)) if (regs->reserve != T0) { env->crf[0] = xer_ov; } else { - glue(_stl, MEMSUFFIX)((void *)T0, T1, ACCESS_RES); + glue(stl, MEMSUFFIX)((void *)T0, T1); env->crf[0] = xer_ov | 0x02; } } @@ -160,27 +154,27 @@ PPC_OP(glue(stwcx, MEMSUFFIX)) PPC_OP(glue(dcbz, MEMSUFFIX)) { - glue(_stl, MEMSUFFIX)((void *)(T0 + 0x00), 0, ACCESS_INT); - glue(_stl, MEMSUFFIX)((void *)(T0 + 0x04), 0, ACCESS_INT); - glue(_stl, MEMSUFFIX)((void *)(T0 + 0x08), 0, ACCESS_INT); - glue(_stl, MEMSUFFIX)((void *)(T0 + 0x0C), 0, ACCESS_INT); - glue(_stl, MEMSUFFIX)((void *)(T0 + 0x10), 0, ACCESS_INT); - glue(_stl, MEMSUFFIX)((void *)(T0 + 0x14), 0, ACCESS_INT); - glue(_stl, MEMSUFFIX)((void *)(T0 + 0x18), 0, ACCESS_INT); - glue(_stl, MEMSUFFIX)((void *)(T0 + 0x1C), 0, ACCESS_INT); + glue(stl, MEMSUFFIX)((void *)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((void *)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((void *)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((void *)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((void *)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((void *)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((void *)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((void *)(T0 + 0x1C), 0); RETURN(); } /* External access */ PPC_OP(glue(eciwx, MEMSUFFIX)) { - T1 = glue(_ldl, MEMSUFFIX)((void *)T0, ACCESS_EXT); + T1 = glue(ldl, MEMSUFFIX)((void *)T0); RETURN(); } PPC_OP(glue(ecowx, MEMSUFFIX)) { - glue(_stl, MEMSUFFIX)((void *)T0, T1, ACCESS_EXT); + glue(stl, MEMSUFFIX)((void *)T0, T1); RETURN(); } -- cgit v1.2.3 From af5ad10728f8265846f64274edd69c01e6da77e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:28:12 +0000 Subject: infer access type git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@530 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-all.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/translate-all.c b/translate-all.c index b02c87a22..c8f345735 100644 --- a/translate-all.c +++ b/translate-all.c @@ -25,7 +25,7 @@ #include "config.h" -#define IN_OP_I386 +#define NO_CPU_IO_DEFS #include "cpu.h" #include "exec-all.h" #include "disas.h" @@ -192,7 +192,41 @@ int cpu_restore_state(TranslationBlock *tb, #elif defined(TARGET_SPARC) env->pc = gen_opc_pc[j]; #elif defined(TARGET_PPC) - env->nip = gen_opc_pc[j]; + { + int type; + /* for PPC, we need to look at the micro operation to get the + access type */ + env->nip = gen_opc_pc[j]; + switch(c) { +#if defined(CONFIG_USER_ONLY) +#define CASE3(op)\ + case INDEX_op_ ## op ## _raw +#else +#define CASE3(op)\ + case INDEX_op_ ## op ## _raw:\ + case INDEX_op_ ## op ## _user:\ + case INDEX_op_ ## op ## _kernel +#endif + + CASE3(stfd): + CASE3(stfs): + CASE3(lfd): + CASE3(lfs): + type = ACCESS_FLOAT; + break; + CASE3(stwcx): + type = ACCESS_RES; + break; + CASE3(eciwx): + CASE3(ecowx): + type = ACCESS_EXT; + break; + default: + type = ACCESS_INT; + break; + } + env->access_type = type; + } #endif return 0; } -- cgit v1.2.3 From 590b7eed184838bc95710813fb5ceddffa43fe8d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:49:02 +0000 Subject: aalib support with SDL git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@531 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 05bc3b6a6..392365d7b 100755 --- a/configure +++ b/configure @@ -301,8 +301,18 @@ if test "$sdl" = "yes" ; then echo "CONFIG_SDL=yes" >> $config_mak echo "#define CONFIG_SDL 1" >> $config_h echo "SDL_LIBS=`sdl-config --libs`" >> $config_mak - echo "SDL_STATIC_LIBS=`sdl-config --static-libs`" >> $config_mak - echo "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak + aa="no" + `sdl-config --static-libs | grep \\\-laa > /dev/null` && aa="yes" + echo -n "SDL_STATIC_LIBS=`sdl-config --static-libs`" >> $config_mak + if [ "${aa}" = "yes" ] ; then + echo -n " `aalib-config --libs`" >> $config_mak ; + fi + echo "" >> $config_mak + echo -n "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak + if [ "${aa}" = "yes" ] ; then + echo -n " `aalib-config --cflags`" >> $config_mak ; + fi + echo "" >> $config_mak fi echo -n "VERSION=" >>$config_mak head $source_path/VERSION >>$config_mak -- cgit v1.2.3 From 09683d35974f3d91cf018deed20346d255deae9b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:49:41 +0000 Subject: changed cpu_x86_in/out to cpu_in/out git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@532 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index bbe7bb9a9..499e1483d 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -420,6 +420,7 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_gen_code cpu_x86_gen_code #define cpu_interrupt cpu_x86_interrupt #define cpu_signal_handler cpu_x86_signal_handler +#define cpu_dump_state cpu_x86_dump_state #elif defined(TARGET_ARM) @@ -429,6 +430,7 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_gen_code cpu_arm_gen_code #define cpu_interrupt cpu_arm_interrupt #define cpu_signal_handler cpu_arm_signal_handler +#define cpu_dump_state cpu_arm_dump_state #elif defined(TARGET_SPARC) @@ -438,6 +440,7 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_gen_code cpu_sparc_gen_code #define cpu_interrupt cpu_sparc_interrupt #define cpu_signal_handler cpu_sparc_signal_handler +#define cpu_dump_state cpu_sparc_dump_state #elif defined(TARGET_PPC) @@ -447,6 +450,7 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_gen_code cpu_ppc_gen_code #define cpu_interrupt cpu_ppc_interrupt #define cpu_signal_handler cpu_ppc_signal_handler +#define cpu_dump_state cpu_ppc_dump_state #else @@ -473,6 +477,19 @@ void cpu_single_step(CPUState *env, int enabled); void cpu_set_log(int log_flags); void cpu_set_log_filename(const char *filename); +/* 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; -- cgit v1.2.3 From 5be1a8e065c56266fa2d99ae21fdad670cd0d963 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:51:58 +0000 Subject: ppc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@533 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gdbstub.c b/gdbstub.c index 140ab7f04..9471d8c16 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -404,6 +404,8 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) env = cpu_gdbstub_get_env(opaque); #if defined(TARGET_I386) env->eip = addr; +#elif defined (TARGET_PPC) + env->nip = addr; #endif } ret = main_loop(opaque); @@ -420,6 +422,8 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) addr = strtoul(p, (char **)&p, 16); #if defined(TARGET_I386) env->eip = addr; +#elif defined (TARGET_PPC) + env->nip = addr; #endif } cpu_single_step(env, 1); -- cgit v1.2.3 From ce09776be290b06562d3a6a7c262e880cbac666a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:53:18 +0000 Subject: PowerPC System emulation (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@534 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index bd42d002b..817200823 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -169,6 +169,8 @@ int cpu_exec(CPUState *env1) env->exception_is_int, env->error_code, env->exception_next_eip, 0); +#elif defined(TARGET_PPC) + do_interrupt(env); #endif } env->exception_index = -1; @@ -201,6 +203,13 @@ int cpu_exec(CPUState *env1) T0 = 0; #endif } +#elif defined(TARGET_PPC) + if ((interrupt_request & CPU_INTERRUPT_HARD)) { + do_queue_exception(EXCP_EXTERNAL); + if (check_exception_state(env)) + do_interrupt(env); + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + } #endif if (interrupt_request & CPU_INTERRUPT_EXIT) { env->interrupt_request &= ~CPU_INTERRUPT_EXIT; @@ -250,7 +259,7 @@ int cpu_exec(CPUState *env1) pc = (uint8_t *)env->regs[15]; #elif defined(TARGET_SPARC) flags = 0; - cs_base = env->npc; + cs_base = (uint8_t *)env->npc; pc = (uint8_t *) env->pc; #elif defined(TARGET_PPC) flags = 0; @@ -571,8 +580,9 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, int is_write, sigset_t *old_set) { TranslationBlock *tb; + int ret; -#if 0 +#if 1 if (cpu_single_env) env = cpu_single_env; /* XXX: find a correct solution for multithread */ #endif @@ -585,6 +595,13 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } + /* see if it is an MMU fault */ + ret = cpu_ppc_handle_mmu_fault(env, address, is_write | ACCESS_INT, 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) { @@ -592,14 +609,20 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, a virtual CPU fault */ cpu_restore_state(tb, env, pc); } + 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); + 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); - raise_exception_err(EXCP_PROGRAM, env->error_code); + do_queue_exception_err(env->exception_index, env->error_code); + } else { + /* activate soft MMU for this block */ + sigprocmask(SIG_SETMASK, old_set, NULL); + cpu_loop_exit(); + } /* never comes here */ return 1; } -- cgit v1.2.3 From 9886cc165ac2c594f62a597de2c7b4df9922e2e6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:53:54 +0000 Subject: factorized GenOpFunc git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@535 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/exec-all.h b/exec-all.h index f116533ed..7c185e528 100644 --- a/exec-all.h +++ b/exec-all.h @@ -64,6 +64,11 @@ extern uint32_t gen_opc_pc[OPC_BUF_SIZE]; extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +typedef void (GenOpFunc)(void); +typedef void (GenOpFunc1)(long); +typedef void (GenOpFunc2)(long, long); +typedef void (GenOpFunc3)(long, long, long); + #if defined(TARGET_I386) void optimize_flags_init(void); @@ -498,7 +503,8 @@ extern spinlock_t tb_lock; extern int tb_invalidated_flag; -#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY) +#if (defined(TARGET_I386) || defined(TARGET_PPC)) && \ + !defined(CONFIG_USER_ONLY) void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr); -- cgit v1.2.3 From 61190b14fc96d4e19c9bdde25643be4c5eb90e62 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:54:31 +0000 Subject: PowerPC update (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@536 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 401 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 315 insertions(+), 86 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 2c9fe3cd6..8bc57a9e9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -59,44 +59,44 @@ void gemu_log(const char *fmt, ...) va_end(ap); } -#ifdef TARGET_I386 -/***********************************************************/ -/* CPUX86 core interface */ - -void cpu_x86_outb(CPUX86State *env, int addr, int val) +void cpu_outb(CPUState *env, int addr, int val) { fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); } -void cpu_x86_outw(CPUX86State *env, int addr, int val) +void cpu_outw(CPUState *env, int addr, int val) { fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); } -void cpu_x86_outl(CPUX86State *env, int addr, int val) +void cpu_outl(CPUState *env, int addr, int val) { fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); } -int cpu_x86_inb(CPUX86State *env, int addr) +int cpu_inb(CPUState *env, int addr) { fprintf(stderr, "inb: port=0x%04x\n", addr); return 0; } -int cpu_x86_inw(CPUX86State *env, int addr) +int cpu_inw(CPUState *env, int addr) { fprintf(stderr, "inw: port=0x%04x\n", addr); return 0; } -int cpu_x86_inl(CPUX86State *env, int addr) +int cpu_inl(CPUState *env, int addr) { fprintf(stderr, "inl: port=0x%04x\n", addr); return 0; } -int cpu_x86_get_pic_interrupt(CPUX86State *env) +#ifdef TARGET_I386 +/***********************************************************/ +/* CPUX86 core interface */ + +int cpu_x86_get_pic_interrupt(CPUState *env) { return -1; } @@ -428,119 +428,346 @@ void cpu_loop (CPUSPARCState *env) void cpu_loop(CPUPPCState *env) { - int trapnr; target_siginfo_t info; + int trapnr; + uint32_t ret; for(;;) { trapnr = cpu_ppc_exec(env); + if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && + trapnr != EXCP_TRACE) { + if (loglevel > 0) { + cpu_ppc_dump_state(env, logfile, 0); + } + } switch(trapnr) { case EXCP_NONE: - case EXCP_INTERRUPT: - case EXCP_MTMSR: /* mtmsr instruction: */ - case EXCP_BRANCH: /* branch instruction */ - /* Single step mode */ break; + case EXCP_SYSCALL_USER: + /* system call */ + /* WARNING: + * PPC ABI uses overflow flag in cr0 to signal an error + * in syscalls. + */ #if 0 - case EXCP_RESET: /* System reset */ - fprintf(stderr, "RESET asked... Stop emulation\n"); - cpu_ppc_dump_state(env, stderr, 0); - abort(); + printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0], + env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); #endif - case EXCP_MACHINE_CHECK: /* Machine check exception */ - fprintf(stderr, "Machine check exeption... " - "See you in kernel code !\n"); - cpu_ppc_dump_state(env, stderr, 0); + env->crf[0] &= ~0x1; + ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8]); + if (ret > (uint32_t)(-515)) { + env->crf[0] |= 0x1; + ret = -ret; + } + env->gpr[3] = ret; +#if 0 + printf("syscall returned 0x%08x (%d)\n", ret, ret); +#endif + break; + case EXCP_RESET: + /* Should not happen ! */ + fprintf(stderr, "RESET asked... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "RESET asked... Stop emulation\n"); abort(); - case EXCP_DSI: /* Impossible memory access */ - fprintf(stderr, "Invalid memory access\n"); - info.si_signo = SIGSEGV; + case EXCP_MACHINE_CHECK: + fprintf(stderr, "Machine check exeption... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "RESET asked... Stop emulation\n"); + info.si_signo = TARGET_SIGBUS; info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; + info.si_code = TARGET_BUS_OBJERR; + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); + case EXCP_DSI: + fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]); + if (loglevel) { + fprintf(logfile, "Invalid data memory access: 0x%08x\n", + env->spr[DAR]); + } + switch (env->error_code & 0xF) { + case EXCP_DSI_TRANSLATE: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + case EXCP_DSI_NOTSUP: + case EXCP_DSI_EXTERNAL: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLADR; + break; + case EXCP_DSI_PROT: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_ACCERR; + break; + case EXCP_DSI_DABR: + info.si_signo = TARGET_SIGTRAP; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + break; + default: + /* Let's send a regular segfault... */ + fprintf(stderr, "Invalid segfault errno (%02x)\n", + env->error_code); + if (loglevel) { + fprintf(logfile, "Invalid segfault errno (%02x)\n", + env->error_code); + } + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + } info._sifields._sigfault._addr = env->nip; queue_signal(info.si_signo, &info); break; - case EXCP_ISI: /* Impossible instruction fetch */ + case EXCP_ISI: fprintf(stderr, "Invalid instruction fetch\n"); - info.si_signo = SIGBUS; + if (loglevel) + fprintf(logfile, "Invalid instruction fetch\n"); + switch (env->error_code) { + case EXCP_ISI_TRANSLATE: + info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->nip; + info.si_code = TARGET_SEGV_MAPERR; + break; + case EXCP_ISI_GUARD: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLADR; + break; + case EXCP_ISI_NOEXEC: + case EXCP_ISI_PROT: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_ACCERR; + break; + default: + /* Let's send a regular segfault... */ + fprintf(stderr, "Invalid segfault errno (%02x)\n", + env->error_code); + if (loglevel) { + fprintf(logfile, "Invalid segfault errno (%02x)\n", + env->error_code); + } + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + } + info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); break; - case EXCP_EXTERNAL: /* External interruption */ - fprintf(stderr, "External access exeption\n"); - cpu_ppc_dump_state(env, stderr, 0); - abort(); - case EXCP_ALIGN: /* Alignment exception */ - fprintf(stderr, "Alignment exception\n"); - cpu_ppc_dump_state(env, stderr, 0); - abort(); - case EXCP_PROGRAM: /* Program exception */ - fprintf(stderr, "Program exception\n"); - cpu_ppc_dump_state(env, stderr, 0); + case EXCP_EXTERNAL: + /* Should not happen ! */ + fprintf(stderr, "External interruption... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "External interruption... Stop emulation\n"); abort(); - break; - /* Trap */ - case EXCP_TRAP: /* Trap */ - case EXCP_TRACE: /* Trace exception (optional) */ - info.si_signo = SIGTRAP; + case EXCP_ALIGN: + fprintf(stderr, "Invalid unaligned memory access\n"); + if (loglevel) + fprintf(logfile, "Invalid unaligned memory access\n"); + info.si_signo = TARGET_SIGBUS; info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->nip; + info.si_code = TARGET_BUS_ADRALN; + info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); break; - /* Invalid instruction */ + case EXCP_PROGRAM: + switch (env->error_code & ~0xF) { + case EXCP_FP: + fprintf(stderr, "Program exception\n"); + if (loglevel) + fprintf(logfile, "Program exception\n"); + /* Set FX */ + env->fpscr[7] |= 0x8; + /* Finally, update FEX */ + if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & + ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) + env->fpscr[7] |= 0x4; + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_FP_OX: + info.si_code = TARGET_FPE_FLTOVF; + break; + case EXCP_FP_UX: + info.si_code = TARGET_FPE_FLTUND; + break; + case EXCP_FP_ZX: + case EXCP_FP_VXZDZ: + info.si_code = TARGET_FPE_FLTDIV; + break; + case EXCP_FP_XX: + info.si_code = TARGET_FPE_FLTRES; + break; + case EXCP_FP_VXSOFT: + info.si_code = TARGET_FPE_FLTINV; + break; + case EXCP_FP_VXNAN: + case EXCP_FP_VXISI: + case EXCP_FP_VXIDI: + case EXCP_FP_VXIMZ: + case EXCP_FP_VXVC: + case EXCP_FP_VXSQRT: + case EXCP_FP_VXCVI: + info.si_code = TARGET_FPE_FLTSUB; + break; + default: + fprintf(stderr, "Unknown floating point exception " + "(%02x)\n", env->error_code); + if (loglevel) { + fprintf(logfile, "Unknown floating point exception " + "(%02x)\n", env->error_code & 0xF); + } + } + break; case EXCP_INVAL: - info.si_signo = SIGILL; - info.si_errno = 0; + fprintf(stderr, "Invalid instruction\n"); + if (loglevel) + fprintf(logfile, "Invalid instruction\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_INVAL_INVAL: + info.si_code = TARGET_ILL_ILLOPC; + break; + case EXCP_INVAL_LSWX: info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->nip; + break; + case EXCP_INVAL_SPR: + info.si_code = TARGET_ILL_PRVREG; + break; + case EXCP_INVAL_FP: + info.si_code = TARGET_ILL_COPROC; + break; + default: + fprintf(stderr, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + if (loglevel) { + fprintf(logfile, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + } + info.si_code = TARGET_ILL_ILLADR; + break; + } + break; + case EXCP_PRIV: + fprintf(stderr, "Privilege violation\n"); + if (loglevel) + fprintf(logfile, "Privilege violation\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_PRIV_OPC: + info.si_code = TARGET_ILL_PRVOPC; + break; + case EXCP_PRIV_REG: + info.si_code = TARGET_ILL_PRVREG; + break; + default: + fprintf(stderr, "Unknown privilege violation (%02x)\n", + env->error_code & 0xF); + info.si_code = TARGET_ILL_PRVOPC; + break; + } + break; + case EXCP_TRAP: + fprintf(stderr, "Tried to call a TRAP\n"); + if (loglevel) + fprintf(logfile, "Tried to call a TRAP\n"); + abort(); + default: + /* Should not happen ! */ + fprintf(stderr, "Unknown program exception (%02x)\n", + env->error_code); + if (loglevel) { + fprintf(logfile, "Unknwon program exception (%02x)\n", + env->error_code); + } + abort(); + } + info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); break; - /* Privileged instruction */ - case EXCP_PRIV: /* Privileged instruction */ - info.si_signo = SIGILL; + case EXCP_NO_FP: + fprintf(stderr, "No floating point allowed\n"); + if (loglevel) + fprintf(logfile, "No floating point allowed\n"); + info.si_signo = TARGET_SIGILL; info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->nip; + info.si_code = TARGET_ILL_COPROC; + info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); break; - case EXCP_NO_FP: /* No floating point */ - case EXCP_DECR: /* Decrementer exception */ + case EXCP_DECR: + /* Should not happen ! */ + fprintf(stderr, "Decrementer exception\n"); + if (loglevel) + fprintf(logfile, "Decrementer exception\n"); + abort(); case EXCP_RESA: /* Implementation specific */ + /* Should not happen ! */ + fprintf(stderr, "RESA exception should never happen !\n"); + if (loglevel) + fprintf(logfile, "RESA exception should never happen !\n"); + abort(); case EXCP_RESB: /* Implementation specific */ - case EXCP_FP_ASSIST: /* Floating-point assist (optional) */ - fprintf(stderr, "Misc expt...\n"); - cpu_ppc_dump_state(env, stderr, 0); + /* Should not happen ! */ + fprintf(stderr, "RESB exception should never happen !\n"); + if (loglevel) + fprintf(logfile, "RESB exception should never happen !\n"); abort(); - - case EXCP_SYSCALL: - { - uint32_t ret; - /* system call */ - /* WARNING: - * PPC ABI uses overflow flag in cr0 to signal an error - * in syscalls. - */ - env->crf[0] &= ~0x1; - ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6], env->gpr[7], - env->gpr[8]); - if (ret > (uint32_t)(-515)) { - env->crf[0] |= 0x1; - ret = -ret; - } - env->gpr[3] = ret; + case EXCP_TRACE: + /* Do nothing: we use this to trace execution */ break; + case EXCP_FP_ASSIST: + /* Should not happen ! */ + fprintf(stderr, "Floating point assist exception\n"); + if (loglevel) + fprintf(logfile, "Floating point assist exception\n"); + abort(); + case EXCP_MTMSR: + /* We reloaded the msr, just go on */ + if (msr_pr) { + fprintf(stderr, "Tried to go into supervisor mode !\n"); + if (loglevel) + fprintf(logfile, "Tried to go into supervisor mode !\n"); + abort(); } + break; + case EXCP_BRANCH: + /* We stopped because of a jump... */ + break; + case EXCP_RFI: + /* Should not occur: we always are in user mode */ + fprintf(stderr, "Return from interrupt ?\n"); + if (loglevel) + fprintf(logfile, "Return from interrupt ?\n"); + abort(); + case EXCP_INTERRUPT: + /* Don't know why this should ever happen... */ + break; default: -// error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); - cpu_ppc_dump_state(env, stderr, 0); + if (loglevel) { + fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " + "0x%02x - aborting\n", trapnr, env->error_code); + } abort(); } + if (trapnr < EXCP_PPC_MAX) + env->exceptions &= ~(1 << trapnr); process_pending_signals(env); + if (env->exceptions != 0) { + check_exception_state(env); + } } } #endif @@ -750,8 +977,10 @@ int main(int argc, char **argv) #elif defined(TARGET_PPC) { int i; - for (i = 0; i < 32; i++) - env->msr[i] = (regs->msr >> i) & 1; + for (i = 0; i < 32; i++) { + if (i != 12 && i != 6) + env->msr[i] = (regs->msr >> i) & 1; + } env->nip = regs->nip; for(i = 0; i < 32; i++) { env->gpr[i] = regs->gpr[i]; -- cgit v1.2.3 From 2d603d2216444a0654223fd80f51300f36e52076 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:56:24 +0000 Subject: PowerPC support - float macros git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@537 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_header.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/softmmu_header.h b/softmmu_header.h index b8077ef43..0bbc3681c 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -51,12 +51,20 @@ #elif ACCESS_TYPE == 2 +#ifdef TARGET_I386 #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) +#elif defined (TARGET_PPC) +#define CPU_MEM_INDEX (msr_pr) +#endif #define MMUSUFFIX _mmu #elif ACCESS_TYPE == 3 +#ifdef TARGET_I386 #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) +#elif defined (TARGET_PPC) +#define CPU_MEM_INDEX (msr_pr) +#endif #define MMUSUFFIX _cmmu #else @@ -283,6 +291,50 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) #endif +#if DATA_SIZE == 8 +static inline double glue(ldfq, MEMSUFFIX)(void *ptr) +{ + union { + double d; + uint64_t i; + } u; + u.i = glue(ldq, MEMSUFFIX)(ptr); + return u.d; +} + +static inline void glue(stfq, MEMSUFFIX)(void *ptr, double v) +{ + union { + double d; + uint64_t i; + } u; + u.d = v; + glue(stq, MEMSUFFIX)(ptr, u.i); +} +#endif /* DATA_SIZE == 8 */ + +#if DATA_SIZE == 4 +static inline float glue(ldfl, MEMSUFFIX)(void *ptr) +{ + union { + float f; + uint32_t i; + } u; + u.i = glue(ldl, MEMSUFFIX)(ptr); + return u.f; +} + +static inline void glue(stfl, MEMSUFFIX)(void *ptr, float v) +{ + union { + float f; + uint32_t i; + } u; + u.f = v; + glue(stl, MEMSUFFIX)(ptr, u.i); +} +#endif /* DATA_SIZE == 4 */ + #undef RES_TYPE #undef DATA_TYPE #undef DATA_STYPE -- cgit v1.2.3 From ffa65c3b700c5f94d5b22a685ff992fb1353b1c1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Jan 2004 23:57:22 +0000 Subject: fcntl flags convertion (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@538 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 35 ++++++++++++++++++++++++++++++- linux-user/syscall_defs.h | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index abd5ce4e9..52e1c6b53 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1130,6 +1130,24 @@ static bitmask_transtbl mmap_flags_tbl[] = { { 0, 0, 0, 0 } }; +static bitmask_transtbl fcntl_flags_tbl[] = { + { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, + { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, }, + { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, }, + { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, }, + { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, }, + { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, }, + { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, }, + { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, }, + { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, }, + { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, }, + { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, }, + { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, }, + { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, }, + { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, }, + { 0, 0, 0, 0 } +}; + #if defined(TARGET_I386) /* NOTE: there is really one LDT for all the threads */ @@ -1353,6 +1371,15 @@ static long do_fcntl(int fd, int cmd, unsigned long arg) errno = EINVAL; break; + case F_GETFL: + ret = fcntl(fd, cmd, arg); + ret = host_to_target_bitmask(ret, fcntl_flags_tbl); + break; + + case F_SETFL: + ret = fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)); + break; + default: ret = fcntl(fd, cmd, arg); break; @@ -1464,7 +1491,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(write(arg1, (void *)arg2, arg3)); break; case TARGET_NR_open: - ret = get_errno(open(path((const char *)arg1), arg2, arg3)); + ret = get_errno(open(path((const char *)arg1), + target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); break; case TARGET_NR_close: ret = get_errno(close(arg1)); @@ -2750,10 +2779,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_pivot_root: goto unimplemented; +#ifdef TARGET_NR_mincore case TARGET_NR_mincore: goto unimplemented; +#endif +#ifdef TARGET_NR_madvise case TARGET_NR_madvise: goto unimplemented; +#endif #if TARGET_LONG_BITS == 32 case TARGET_NR_fcntl64: { diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index a0a04aab3..4e36a222d 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -414,7 +414,14 @@ typedef struct target_siginfo { /* * SIGILL si_codes */ +#define TARGET_ILL_ILLOPC (1) /* illegal opcode */ #define TARGET_ILL_ILLOPN (2) /* illegal operand */ +#define TARGET_ILL_ILLADR (3) /* illegal addressing mode */ +#define TARGET_ILL_ILLTRP (4) /* illegal trap */ +#define TARGET_ILL_PRVOPC (5) /* privileged opcode */ +#define TARGET_ILL_PRVREG (6) /* privileged register */ +#define TARGET_ILL_COPROC (7) /* coprocessor error */ +#define TARGET_ILL_BADSTK (8) /* internal stack error */ /* * SIGFPE si_codes @@ -435,6 +442,13 @@ typedef struct target_siginfo { #define TARGET_SEGV_MAPERR (1) /* address not mapped to object */ #define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */ +/* + * SIGBUS si_codes + */ +#define TARGET_BUS_ADRALN (1) /* invalid address alignment */ +#define TARGET_BUS_ADRERR (2) /* non-existant physical address */ +#define TARGET_BUS_OBJERR (3) /* object specific hardware error */ + /* * SIGTRAP si_codes */ @@ -891,6 +905,44 @@ struct target_stat64 { #define TARGET_F_SETLK64 13 #define TARGET_F_SETLKW64 14 +#if defined (TARGET_PPC) +#define TARGET_O_ACCMODE 0003 +#define TARGET_O_RDONLY 00 +#define TARGET_O_WRONLY 01 +#define TARGET_O_RDWR 02 +#define TARGET_O_CREAT 0100 /* not fcntl */ +#define TARGET_O_EXCL 0200 /* not fcntl */ +#define TARGET_O_NOCTTY 0400 /* not fcntl */ +#define TARGET_O_TRUNC 01000 /* not fcntl */ +#define TARGET_O_APPEND 02000 +#define TARGET_O_NONBLOCK 04000 +#define TARGET_O_NDELAY O_NONBLOCK +#define TARGET_O_SYNC 010000 +#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ +#define TARGET_O_DIRECTORY 040000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */ +#define TARGET_O_LARGEFILE 0200000 +#define TARGET_O_DIRECT 0400000 /* direct disk access hint */ +#else +#define TARGET_O_ACCMODE 0003 +#define TARGET_O_RDONLY 00 +#define TARGET_O_WRONLY 01 +#define TARGET_O_RDWR 02 +#define TARGET_O_CREAT 0100 /* not fcntl */ +#define TARGET_O_EXCL 0200 /* not fcntl */ +#define TARGET_O_NOCTTY 0400 /* not fcntl */ +#define TARGET_O_TRUNC 01000 /* not fcntl */ +#define TARGET_O_APPEND 02000 +#define TARGET_O_NONBLOCK 04000 +#define TARGET_O_NDELAY O_NONBLOCK +#define TARGET_O_SYNC 010000 +#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ +#define TARGET_O_DIRECT 040000 /* direct disk access hint */ +#define TARGET_O_LARGEFILE 0100000 +#define TARGET_O_DIRECTORY 0200000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0400000 /* don't follow links */ +#endif + struct target_flock { short l_type; short l_whence; -- cgit v1.2.3 From c45886db19fb117a8ad8a5118572d23a957e5de5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jan 2004 00:02:06 +0000 Subject: PowerPC system emulation (Jocelyn Mayer) - PIC poll mode (Jocelyn Mayer) - use CPUState - Floppy support (Jocelyn Mayer) - command line debug (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@539 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 441 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 382 insertions(+), 59 deletions(-) diff --git a/vl.c b/vl.c index 3008f95bb..c8a065225 100644 --- a/vl.c +++ b/vl.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +81,18 @@ #define PHYS_RAM_BASE 0xac000000 #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) +#if defined (TARGET_I386) #define KERNEL_LOAD_ADDR 0x00100000 +#elif defined (TARGET_PPC) +//#define USE_OPEN_FIRMWARE +#if defined (USE_OPEN_FIRMWARE) +#define KERNEL_LOAD_ADDR 0x01000000 +#define KERNEL_STACK_ADDR 0x01200000 +#else +#define KERNEL_LOAD_ADDR 0x00000000 +#define KERNEL_STACK_ADDR 0x00400000 +#endif +#endif #define INITRD_LOAD_ADDR 0x00400000 #define KERNEL_PARAMS_ADDR 0x00090000 @@ -206,11 +218,11 @@ struct __attribute__ ((packed)) linux_params { static const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; -CPUX86State *global_env; -CPUX86State *cpu_single_env; +CPUState *global_env; +CPUState *cpu_single_env; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; -BlockDriverState *bs_table[MAX_DISKS]; +BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD]; int vga_ram_size; static DisplayState display_state; int nographic; @@ -221,7 +233,7 @@ int boot_device = 'c'; /***********************************************************/ /* x86 io ports */ -uint32_t default_ioport_readb(CPUX86State *env, uint32_t address) +uint32_t default_ioport_readb(CPUState *env, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "inb: port=0x%04x\n", address); @@ -229,7 +241,7 @@ uint32_t default_ioport_readb(CPUX86State *env, uint32_t address) return 0xff; } -void default_ioport_writeb(CPUX86State *env, uint32_t address, uint32_t data) +void default_ioport_writeb(CPUState *env, uint32_t address, uint32_t data) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data); @@ -237,7 +249,7 @@ void default_ioport_writeb(CPUX86State *env, uint32_t address, uint32_t data) } /* default is to make two byte accesses */ -uint32_t default_ioport_readw(CPUX86State *env, uint32_t address) +uint32_t default_ioport_readw(CPUState *env, uint32_t address) { uint32_t data; data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](env, address); @@ -245,13 +257,13 @@ uint32_t default_ioport_readw(CPUX86State *env, uint32_t address) return data; } -void default_ioport_writew(CPUX86State *env, uint32_t address, uint32_t data) +void default_ioport_writew(CPUState *env, uint32_t address, uint32_t data) { ioport_write_table[0][address & (MAX_IOPORTS - 1)](env, address, data & 0xff); ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1, (data >> 8) & 0xff); } -uint32_t default_ioport_readl(CPUX86State *env, uint32_t address) +uint32_t default_ioport_readl(CPUState *env, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "inl: port=0x%04x\n", address); @@ -259,7 +271,7 @@ uint32_t default_ioport_readl(CPUX86State *env, uint32_t address) return 0xffffffff; } -void default_ioport_writel(CPUX86State *env, uint32_t address, uint32_t data) +void default_ioport_writel(CPUState *env, uint32_t address, uint32_t data) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data); @@ -345,12 +357,18 @@ char *pstrcat(char *buf, int buf_size, const char *s) int load_kernel(const char *filename, uint8_t *addr) { - int fd, size, setup_sects; + int fd, size; +#if defined (TARGET_I386) + int setup_sects; uint8_t bootsect[512]; +#endif + printf("Load kernel at %p (0x%08x)\n", addr, + (uint32_t)addr - (uint32_t)phys_ram_base); fd = open(filename, O_RDONLY); if (fd < 0) return -1; +#if defined (TARGET_I386) if (read(fd, bootsect, 512) != 512) goto fail; setup_sects = bootsect[0x1F1]; @@ -358,6 +376,7 @@ int load_kernel(const char *filename, uint8_t *addr) setup_sects = 4; /* skip 16 bit setup code */ lseek(fd, (setup_sects + 1) * 512, SEEK_SET); +#endif size = read(fd, addr, 16 * 1024 * 1024); if (size < 0) goto fail; @@ -385,38 +404,38 @@ int load_image(const char *filename, uint8_t *addr) return size; } -void cpu_x86_outb(CPUX86State *env, int addr, int val) +void cpu_outb(CPUState *env, int addr, int val) { ioport_write_table[0][addr & (MAX_IOPORTS - 1)](env, addr, val); } -void cpu_x86_outw(CPUX86State *env, int addr, int val) +void cpu_outw(CPUState *env, int addr, int val) { ioport_write_table[1][addr & (MAX_IOPORTS - 1)](env, addr, val); } -void cpu_x86_outl(CPUX86State *env, int addr, int val) +void cpu_outl(CPUState *env, int addr, int val) { ioport_write_table[2][addr & (MAX_IOPORTS - 1)](env, addr, val); } -int cpu_x86_inb(CPUX86State *env, int addr) +int cpu_inb(CPUState *env, int addr) { return ioport_read_table[0][addr & (MAX_IOPORTS - 1)](env, addr); } -int cpu_x86_inw(CPUX86State *env, int addr) +int cpu_inw(CPUState *env, int addr) { return ioport_read_table[1][addr & (MAX_IOPORTS - 1)](env, addr); } -int cpu_x86_inl(CPUX86State *env, int addr) +int cpu_inl(CPUState *env, int addr) { return ioport_read_table[2][addr & (MAX_IOPORTS - 1)](env, addr); } /***********************************************************/ -void ioport80_write(CPUX86State *env, uint32_t addr, uint32_t data) +void ioport80_write(CPUState *env, uint32_t addr, uint32_t data) { } @@ -430,6 +449,8 @@ void hw_error(const char *fmt, ...) fprintf(stderr, "\n"); #ifdef TARGET_I386 cpu_x86_dump_state(global_env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + cpu_dump_state(global_env, stderr, 0); #endif va_end(ap); abort(); @@ -438,6 +459,7 @@ void hw_error(const char *fmt, ...) /***********************************************************/ /* cmos emulation */ +#if defined (TARGET_I386) #define RTC_SECONDS 0 #define RTC_SECONDS_ALARM 1 #define RTC_MINUTES 2 @@ -463,7 +485,7 @@ void hw_error(const char *fmt, ...) uint8_t cmos_data[128]; uint8_t cmos_index; -void cmos_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) +void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) { if (addr == 0x70) { cmos_index = data & 0x7f; @@ -503,7 +525,7 @@ void cmos_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) } } -uint32_t cmos_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) { int ret; @@ -580,6 +602,7 @@ void cmos_init(void) switch(boot_device) { case 'a': + case 'b': cmos_data[0x3d] = 0x01; /* floppy boot */ break; default: @@ -595,6 +618,56 @@ void cmos_init(void) register_ioport_read(0x70, 2, cmos_ioport_read, 1); } +void cmos_register_fd (uint8_t fd0, uint8_t fd1) +{ + int nb = 0; + + cmos_data[0x10] = 0; + switch (fd0) { + case 0: + /* 1.44 Mb 3"5 drive */ + cmos_data[0x10] |= 0x40; + break; + case 1: + /* 2.88 Mb 3"5 drive */ + cmos_data[0x10] |= 0x60; + break; + case 2: + /* 1.2 Mb 5"5 drive */ + cmos_data[0x10] |= 0x20; + break; + } + switch (fd1) { + case 0: + /* 1.44 Mb 3"5 drive */ + cmos_data[0x10] |= 0x04; + break; + case 1: + /* 2.88 Mb 3"5 drive */ + cmos_data[0x10] |= 0x06; + break; + case 2: + /* 1.2 Mb 5"5 drive */ + cmos_data[0x10] |= 0x02; + break; + } + if (fd0 < 3) + nb++; + if (fd1 < 3) + nb++; + switch (nb) { + case 0: + break; + case 1: + cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ + break; + case 2: + cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ + break; + } +} +#endif /* TARGET_I386 */ + /***********************************************************/ /* 8259 pic emulation */ @@ -606,6 +679,7 @@ typedef struct PicState { uint8_t priority_add; /* used to compute irq priority */ uint8_t irq_base; uint8_t read_reg_select; + uint8_t poll; uint8_t special_mask; uint8_t init_state; uint8_t auto_eoi; @@ -663,7 +737,7 @@ static int pic_get_irq(PicState *s) /* raise irq to CPU if necessary. must be called every time the active irq may change */ -static void pic_update_irq(void) +void pic_update_irq(void) { int irq2, irq; @@ -684,7 +758,7 @@ static void pic_update_irq(void) /* from master pic */ pic_irq_requested = irq; } - cpu_x86_interrupt(global_env, CPU_INTERRUPT_HARD); + cpu_interrupt(global_env, CPU_INTERRUPT_HARD); } } @@ -713,7 +787,7 @@ void pic_set_irq(int irq, int level) pic_update_irq(); } -int cpu_x86_get_pic_interrupt(CPUX86State *env) +int cpu_x86_get_pic_interrupt(CPUState *env) { int irq, irq2, intno; @@ -742,7 +816,7 @@ int cpu_x86_get_pic_interrupt(CPUX86State *env) return intno; } -void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { PicState *s; int priority; @@ -763,10 +837,14 @@ void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) if (val & 0x08) hw_error("level sensitive irq not supported"); } else if (val & 0x08) { + if (val & 0x04) { + s->poll = 1; + } else { if (val & 0x02) s->read_reg_select = val & 1; if (val & 0x40) s->special_mask = (val >> 5) & 1; + } } else { switch(val) { case 0x00: @@ -826,7 +904,29 @@ void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } } -uint32_t pic_ioport_read(CPUX86State *env, uint32_t addr1) +static uint32_t pic_poll_read (PicState *s, uint32_t addr1) +{ + int ret; + + ret = pic_get_irq(s); + if (ret >= 0) { + if (addr1 >> 7) { + pics[0].isr &= ~(1 << 2); + pics[0].irr &= ~(1 << 2); + } + s->irr &= ~(1 << ret); + s->isr &= ~(1 << ret); + if (addr1 >> 7 || ret != 2) + pic_update_irq(); + } else { + ret = 0x07; + pic_update_irq(); + } + + return ret; +} + +uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) { PicState *s; unsigned int addr; @@ -835,6 +935,10 @@ uint32_t pic_ioport_read(CPUX86State *env, uint32_t addr1) addr = addr1; s = &pics[addr >> 7]; addr &= 1; + if (s->poll == 1) { + ret = pic_poll_read(s, addr1); + s->poll = 0; + } else { if (addr == 0) { if (s->read_reg_select) ret = s->isr; @@ -843,18 +947,35 @@ uint32_t pic_ioport_read(CPUX86State *env, uint32_t addr1) } else { ret = s->imr; } + } #ifdef DEBUG_PIC printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); #endif return ret; } +/* memory mapped interrupt status */ +uint32_t pic_intack_read(CPUState *env) +{ + int ret; + + ret = pic_poll_read(&pics[0], 0x00); + if (ret == 2) + ret = pic_poll_read(&pics[1], 0x80) + 8; + /* Prepare for ISR read */ + pics[0].read_reg_select = 1; + + return ret; +} + void pic_init(void) { +#if defined (TARGET_I386) || defined (TARGET_PPC) register_ioport_write(0x20, 2, pic_ioport_write, 1); register_ioport_read(0x20, 2, pic_ioport_read, 1); register_ioport_write(0xa0, 2, pic_ioport_write, 1); register_ioport_read(0xa0, 2, pic_ioport_read, 1); +#endif } /***********************************************************/ @@ -1140,7 +1261,7 @@ static inline void pit_load_count(PITChannelState *s, int val) } } -void pit_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { int channel, access; PITChannelState *s; @@ -1185,7 +1306,7 @@ void pit_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } } -uint32_t pit_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t pit_ioport_read(CPUState *env, uint32_t addr) { int ret, count; PITChannelState *s; @@ -1218,13 +1339,14 @@ uint32_t pit_ioport_read(CPUX86State *env, uint32_t addr) return ret; } -void speaker_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +#if defined (TARGET_I386) +void speaker_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { speaker_data_on = (val >> 1) & 1; pit_set_gate(&pit_channels[2], val & 1); } -uint32_t speaker_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t speaker_ioport_read(CPUState *env, uint32_t addr) { int out; out = pit_get_out(&pit_channels[2]); @@ -1232,6 +1354,7 @@ uint32_t speaker_ioport_read(CPUX86State *env, uint32_t addr) return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | (dummy_refresh_clock << 4); } +#endif void pit_init(void) { @@ -1250,8 +1373,10 @@ void pit_init(void) register_ioport_write(0x40, 4, pit_ioport_write, 1); register_ioport_read(0x40, 3, pit_ioport_read, 1); +#if defined (TARGET_I386) register_ioport_read(0x61, 1, speaker_ioport_read, 1); register_ioport_write(0x61, 1, speaker_ioport_write, 1); +#endif } /***********************************************************/ @@ -1339,7 +1464,7 @@ void serial_update_irq(void) } } -void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { SerialState *s = &serial_ports[0]; unsigned char ch; @@ -1396,7 +1521,7 @@ void serial_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } } -uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t serial_ioport_read(CPUState *env, uint32_t addr) { SerialState *s = &serial_ports[0]; uint32_t ret; @@ -1458,23 +1583,124 @@ uint32_t serial_ioport_read(CPUX86State *env, uint32_t addr) } #define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ -static int term_got_escape; +static int term_got_escape, term_command; +static unsigned char term_cmd_buf[128]; + +typedef struct term_cmd_t { + const unsigned char *name; + void (*handler)(unsigned char *params); +} term_cmd_t; + +static void do_change_cdrom (unsigned char *params); +static void do_change_fd0 (unsigned char *params); +static void do_change_fd1 (unsigned char *params); + +static term_cmd_t term_cmds[] = { + { "changecd", &do_change_cdrom, }, + { "changefd0", &do_change_fd0, }, + { "changefd1", &do_change_fd1, }, + { NULL, NULL, }, +}; void term_print_help(void) { printf("\n" "C-a h print this help\n" "C-a x exit emulatior\n" + "C-a d switch on/off debug log\n" "C-a s save disk data back to file (if -snapshot)\n" "C-a b send break (magic sysrq)\n" + "C-a c send qemu internal command\n" "C-a C-a send C-a\n" ); } +static void do_change_cdrom (unsigned char *params) +{ + /* Dunno how to do it... */ +} + +static void do_change_fd (int fd, unsigned char *params) +{ + unsigned char *name_start, *name_end, *ros; + int ro; + + for (name_start = params; + isspace(*name_start); name_start++) + continue; + if (*name_start == '\0') + return; + for (name_end = name_start; + !isspace(*name_end) && *name_end != '\0'; name_end++) + continue; + for (ros = name_end + 1; isspace(*ros); ros++) + continue; + if (ros[0] == 'r' && ros[1] == 'o') + ro = 1; + else + ro = 0; + *name_end = '\0'; + printf("Change fd %d to %s (%s)\n", fd, name_start, params); + fdctrl_disk_change(fd, name_start, ro); +} + +static void do_change_fd0 (unsigned char *params) +{ + do_change_fd(0, params); +} + +static void do_change_fd1 (unsigned char *params) +{ + do_change_fd(1, params); +} + +static void serial_treat_command () +{ + unsigned char *cmd_start, *cmd_end; + int i; + + for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++) + continue; + for (cmd_end = cmd_start; + !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++) + continue; + for (i = 0; term_cmds[i].name != NULL; i++) { + if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) && + memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) { + (*term_cmds[i].handler)(cmd_end + 1); + return; + } + } + *cmd_end = '\0'; + printf("Unknown term command: %s\n", cmd_start); +} + +extern FILE *logfile; + /* called when a char is received */ void serial_received_byte(SerialState *s, int ch) { - if (term_got_escape) { + if (term_command) { + if (ch == '\n' || ch == '\r' || term_command == 127) { + printf("\n"); + serial_treat_command(); + term_command = 0; + } else { + if (ch == 0x7F || ch == 0x08) { + if (term_command > 1) { + term_cmd_buf[--term_command - 1] = '\0'; + printf("\r " + " "); + printf("\r> %s", term_cmd_buf); + } + } else if (ch > 0x1f) { + term_cmd_buf[term_command++ - 1] = ch; + term_cmd_buf[term_command - 1] = '\0'; + printf("\r> %s", term_cmd_buf); + } + fflush(stdout); + } + } else if (term_got_escape) { term_got_escape = 0; switch(ch) { case 'h': @@ -1498,8 +1724,10 @@ void serial_received_byte(SerialState *s, int ch) s->lsr |= UART_LSR_BI | UART_LSR_DR; serial_update_irq(); break; - case 'd': - cpu_set_log(CPU_LOG_ALL); + case 'c': + printf("> "); + fflush(stdout); + term_command = 1; break; case TERM_ESCAPE: goto send_char; @@ -1521,13 +1749,16 @@ void serial_init(void) s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; +#if defined(TARGET_I386) || defined (TARGET_PPC) register_ioport_write(0x3f8, 8, serial_ioport_write, 1); register_ioport_read(0x3f8, 8, serial_ioport_read, 1); +#endif } /***********************************************************/ /* ne2000 emulation */ +#if defined (TARGET_I386) #define NE2000_IOPORT 0x300 #define NE2000_IRQ 9 @@ -1775,7 +2006,7 @@ void ne2000_receive(NE2000State *s, uint8_t *buf, int size) ne2000_update_irq(s); } -void ne2000_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { NE2000State *s = &ne2000_state; int offset, page; @@ -1860,7 +2091,7 @@ void ne2000_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } } -uint32_t ne2000_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) { NE2000State *s = &ne2000_state; int offset, page, ret; @@ -1901,7 +2132,7 @@ uint32_t ne2000_ioport_read(CPUX86State *env, uint32_t addr) return ret; } -void ne2000_asic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { NE2000State *s = &ne2000_state; uint8_t *p; @@ -1932,7 +2163,7 @@ void ne2000_asic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } } -uint32_t ne2000_asic_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) { NE2000State *s = &ne2000_state; uint8_t *p; @@ -1964,12 +2195,12 @@ uint32_t ne2000_asic_ioport_read(CPUX86State *env, uint32_t addr) return ret; } -void ne2000_reset_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { /* nothing to do (end of reset pulse) */ } -uint32_t ne2000_reset_ioport_read(CPUX86State *env, uint32_t addr) +uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr) { ne2000_reset(); return 0; @@ -1989,6 +2220,25 @@ void ne2000_init(void) register_ioport_read(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_read, 1); ne2000_reset(); } +#endif + +/***********************************************************/ +/* PC floppy disk controler emulation glue */ +#define PC_FDC_DMA 0x2 +#define PC_FDC_IRQ 0x6 +#define PC_FDC_BASE 0x3F0 + +static void fdctrl_register (unsigned char **disknames, int ro, + char boot_device) +{ + int i; + + fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device); + for (i = 0; i < MAX_FD; i++) { + if (disknames[i] != NULL) + fdctrl_disk_change(i, disknames[i], ro); + } +} /***********************************************************/ /* keyboard emulation */ @@ -2158,18 +2408,18 @@ void kbd_put_keycode(int keycode) kbd_queue(s, keycode, 0); } -uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) +uint32_t kbd_read_status(CPUState *env, uint32_t addr) { KBDState *s = &kbd_state; int val; val = s->status; -#if defined(DEBUG_KBD) && 0 +#if defined(DEBUG_KBD) printf("kbd: read status=0x%02x\n", val); #endif return val; } -void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) +void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) { KBDState *s = &kbd_state; @@ -2216,22 +2466,28 @@ void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) break; case KBD_CCMD_READ_OUTPORT: /* XXX: check that */ +#ifdef TARGET_I386 val = 0x01 | (a20_enabled << 1); +#else + val = 0x01; +#endif if (s->status & KBD_STAT_OBF) val |= 0x10; if (s->status & KBD_STAT_MOUSE_OBF) val |= 0x20; kbd_queue(s, val, 0); break; +#ifdef TARGET_I386 case KBD_CCMD_ENABLE_A20: cpu_x86_set_a20(env, 1); break; case KBD_CCMD_DISABLE_A20: cpu_x86_set_a20(env, 0); break; +#endif case KBD_CCMD_RESET: reset_requested = 1; - cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); break; case 0xff: /* ignore that - I don't know what is its use */ @@ -2242,7 +2498,7 @@ void kbd_write_command(CPUX86State *env, uint32_t addr, uint32_t val) } } -uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) +uint32_t kbd_read_data(CPUState *env, uint32_t addr) { KBDState *s = &kbd_state; KBDQueue *q; @@ -2543,7 +2799,7 @@ static void kbd_write_mouse(KBDState *s, int val) } } -void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) +void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val) { KBDState *s = &kbd_state; @@ -2566,10 +2822,12 @@ void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) kbd_queue(s, val, 1); break; case KBD_CCMD_WRITE_OUTPORT: +#ifdef TARGET_I386 cpu_x86_set_a20(env, (val >> 1) & 1); +#endif if (!(val & 1)) { reset_requested = 1; - cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); } break; case KBD_CCMD_WRITE_MOUSE: @@ -2601,15 +2859,17 @@ void kbd_reset(KBDState *s) void kbd_init(void) { kbd_reset(&kbd_state); +#if defined (TARGET_I386) || defined (TARGET_PPC) register_ioport_read(0x60, 1, kbd_read_data, 1); register_ioport_write(0x60, 1, kbd_write_data, 1); register_ioport_read(0x64, 1, kbd_read_status, 1); register_ioport_write(0x64, 1, kbd_write_command, 1); +#endif } /***********************************************************/ /* Bochs BIOS debug ports */ - +#ifdef TARGET_I386 void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) { switch(addr) { @@ -2651,6 +2911,7 @@ void bochs_bios_init(void) register_ioport_write(0x500, 1, bochs_bios_write, 1); register_ioport_write(0x503, 1, bochs_bios_write, 1); } +#endif /***********************************************************/ /* dumb display */ @@ -2756,7 +3017,7 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, if (gui_refresh_pending || timer_irq_pending) { /* just exit from the cpu to have a chance to handle timers */ - cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); } } @@ -2786,7 +3047,10 @@ CPUState *cpu_gdbstub_get_env(void *opaque) int main_loop(void *opaque) { - struct pollfd ufds[3], *pf, *serial_ufd, *net_ufd, *gdb_ufd; + struct pollfd ufds[3], *pf, *serial_ufd, *gdb_ufd; +#if defined (TARGET_I386) + struct pollfd *net_ufd; +#endif int ret, n, timeout, serial_ok; uint8_t ch; CPUState *env = global_env; @@ -2802,7 +3066,10 @@ int main_loop(void *opaque) serial_ok = 1; cpu_enable_ticks(); for(;;) { - ret = cpu_x86_exec(env); +#if defined (DO_TB_FLUSH) + tb_flush(); +#endif + ret = cpu_exec(env); if (reset_requested) { ret = EXCP_INTERRUPT; break; @@ -2825,6 +3092,7 @@ int main_loop(void *opaque) pf->events = POLLIN; pf++; } +#if defined (TARGET_I386) net_ufd = NULL; if (net_fd > 0 && ne2000_can_receive(&ne2000_state)) { net_ufd = pf; @@ -2832,6 +3100,7 @@ int main_loop(void *opaque) pf->events = POLLIN; pf++; } +#endif gdb_ufd = NULL; if (gdbstub_fd > 0) { gdb_ufd = pf; @@ -2851,6 +3120,7 @@ int main_loop(void *opaque) serial_ok = 0; } } +#if defined (TARGET_I386) if (net_ufd && (net_ufd->revents & POLLIN)) { uint8_t buf[MAX_ETH_FRAME_SIZE]; @@ -2863,6 +3133,7 @@ int main_loop(void *opaque) ne2000_receive(&ne2000_state, buf, n); } } +#endif if (gdb_ufd && (gdb_ufd->revents & POLLIN)) { uint8_t buf[1]; /* stop emulation if requested by gdb */ @@ -2876,6 +3147,7 @@ int main_loop(void *opaque) /* timer IRQ */ if (timer_irq_pending) { +#if defined (TARGET_I386) pic_set_irq(0, 1); pic_set_irq(0, 0); timer_irq_pending = 0; @@ -2883,6 +3155,7 @@ int main_loop(void *opaque) if (cmos_data[RTC_REG_B] & 0x50) { pic_set_irq(8, 1); } +#endif } /* VGA */ @@ -2903,6 +3176,7 @@ void help(void) "'disk_image' is a raw hard image image for IDE hard disk 0\n" "\n" "Standard options:\n" + "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom 2 image\n" @@ -2957,6 +3231,8 @@ struct option long_options[] = { { "hdd", 1, NULL, 0, }, { "cdrom", 1, NULL, 0, }, { "boot", 1, NULL, 0, }, + { "fda", 1, NULL, 0, }, + { "fdb", 1, NULL, 0, }, { NULL, 0, NULL, 0 }, }; @@ -2976,23 +3252,29 @@ int main(int argc, char **argv) { int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; int snapshot, linux_boot, total_ram_size; +#if defined (TARGET_I386) struct linux_params *params; +#endif struct sigaction act; struct itimerval itv; - CPUX86State *env; + CPUState *env; const char *initrd_filename; - const char *hd_filename[MAX_DISKS]; + const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); initrd_filename = NULL; + for(i = 0; i < MAX_FD; i++) + fd_filename[i] = NULL; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; phys_ram_size = 32 * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; +#if defined (TARGET_I386) pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); +#endif use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; snapshot = 0; @@ -3047,9 +3329,11 @@ int main(int argc, char **argv) case 7: kernel_cmdline = optarg; break; +#if defined (TARGET_I386) case 8: net_fd = atoi(optarg); break; +#endif case 9: hd_filename[2] = optarg; break; @@ -3062,11 +3346,18 @@ int main(int argc, char **argv) break; case 12: boot_device = optarg[0]; - if (boot_device != 'c' && boot_device != 'd') { + if (boot_device != 'a' && boot_device != 'b' && + boot_device != 'c' && boot_device != 'd') { fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device); exit(1); } break; + case 13: + fd_filename[0] = optarg; + break; + case 14: + fd_filename[1] = optarg; + break; } break; case 'h': @@ -3085,9 +3376,11 @@ int main(int argc, char **argv) case 'd': cpu_set_log(CPU_LOG_ALL); break; +#if defined (TARGET_I386) case 'n': pstrcpy(network_script, sizeof(network_script), optarg); break; +#endif case 's': use_gdbstub = 1; break; @@ -3106,7 +3399,8 @@ int main(int argc, char **argv) linux_boot = (kernel_filename != NULL); - if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0') + if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0' && + fd_filename[0] == '\0') help(); /* boot to cd by default if no hard disk */ @@ -3124,8 +3418,10 @@ int main(int argc, char **argv) #endif /* init network tun interface */ +#if defined (TARGET_I386) if (net_fd < 0) net_init(); +#endif /* init the memory */ total_ram_size = phys_ram_size + vga_ram_size; @@ -3213,6 +3509,7 @@ int main(int argc, char **argv) } /* init kernel params */ +#ifdef TARGET_I386 params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR); memset(params, 0, sizeof(struct linux_params)); params->mount_root_rdonly = 0; @@ -3256,12 +3553,16 @@ int main(int argc, char **argv) env->eip = KERNEL_LOAD_ADDR; env->regs[R_ESI] = KERNEL_PARAMS_ADDR; env->eflags = 0x2; - +#elif defined (TARGET_PPC) + cpu_x86_init_mmu(env); + PPC_init_hw(env, phys_ram_size, KERNEL_LOAD_ADDR, ret, + KERNEL_STACK_ADDR, boot_device); +#endif } else { char buf[1024]; /* RAW PC boot */ - +#if defined(TARGET_I386) /* BIOS load */ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); ret = load_image(buf, phys_ram_base + 0x000f0000); @@ -3302,6 +3603,19 @@ int main(int argc, char **argv) env->eflags = 0x2; bochs_bios_init(); +#elif defined(TARGET_PPC) + cpu_x86_init_mmu(env); + /* allocate ROM */ + // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); + printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); + ret = load_image(buf, phys_ram_base + 0x000f0000); + if (ret != 0x10000) { + fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", + buf, ret); + exit(1); + } +#endif } /* terminal init */ @@ -3317,19 +3631,28 @@ int main(int argc, char **argv) /* init basic PC hardware */ register_ioport_write(0x80, 1, ioport80_write, 1); - vga_init(ds, phys_ram_base + phys_ram_size, phys_ram_size, + vga_initialize(ds, phys_ram_base + phys_ram_size, phys_ram_size, vga_ram_size); +#if defined (TARGET_I386) cmos_init(); +#endif pic_init(); pit_init(); serial_init(); +#if defined (TARGET_I386) ne2000_init(); +#endif ide_init(); kbd_init(); AUD_init(); DMA_init(); +#if defined (TARGET_I386) SB16_init(); - +#endif +#if defined (TARGET_PPC) + PPC_end_init(); +#endif + fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device); /* setup cpu signal handlers for MMU / self modifying code handling */ sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; -- cgit v1.2.3 From 7138fcfbf7dd74a0bc68e2fc3fa7c5ba58f2d6c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jan 2004 00:02:28 +0000 Subject: use CPUState git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@540 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 16 ++++++++-------- hw/sb16.c | 4 ++-- hw/vga.c | 14 +++++++++----- vl.h | 19 ++++++++++++++----- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 3771bb0a5..480a7be6d 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1047,7 +1047,7 @@ static void ide_atapi_cmd(IDEState *s) } } -static void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { IDEState *ide_if = get_ide_interface(addr); IDEState *s = ide_if->cur_drive; @@ -1198,7 +1198,7 @@ static void ide_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) } } -static uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr1) +static uint32_t ide_ioport_read(CPUState *env, uint32_t addr1) { IDEState *s = get_ide_interface(addr1)->cur_drive; uint32_t addr; @@ -1239,7 +1239,7 @@ static uint32_t ide_ioport_read(CPUX86State *env, uint32_t addr1) return ret; } -static uint32_t ide_status_read(CPUX86State *env, uint32_t addr) +static uint32_t ide_status_read(CPUState *env, uint32_t addr) { IDEState *s = get_ide_interface(addr)->cur_drive; int ret; @@ -1250,7 +1250,7 @@ static uint32_t ide_status_read(CPUX86State *env, uint32_t addr) return ret; } -static void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) +static void ide_cmd_write(CPUState *env, uint32_t addr, uint32_t val) { IDEState *ide_if = get_ide_interface(addr); IDEState *s; @@ -1285,7 +1285,7 @@ static void ide_cmd_write(CPUX86State *env, uint32_t addr, uint32_t val) ide_if[1].cmd = val; } -static void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) +static void ide_data_writew(CPUState *env, uint32_t addr, uint32_t val) { IDEState *s = get_ide_interface(addr)->cur_drive; uint8_t *p; @@ -1298,7 +1298,7 @@ static void ide_data_writew(CPUX86State *env, uint32_t addr, uint32_t val) s->end_transfer_func(s); } -static uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) +static uint32_t ide_data_readw(CPUState *env, uint32_t addr) { IDEState *s = get_ide_interface(addr)->cur_drive; uint8_t *p; @@ -1312,7 +1312,7 @@ static uint32_t ide_data_readw(CPUX86State *env, uint32_t addr) return ret; } -static void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) +static void ide_data_writel(CPUState *env, uint32_t addr, uint32_t val) { IDEState *s = get_ide_interface(addr)->cur_drive; uint8_t *p; @@ -1325,7 +1325,7 @@ static void ide_data_writel(CPUX86State *env, uint32_t addr, uint32_t val) s->end_transfer_func(s); } -static uint32_t ide_data_readl(CPUX86State *env, uint32_t addr) +static uint32_t ide_data_readl(CPUState *env, uint32_t addr) { IDEState *s = get_ide_interface(addr)->cur_drive; uint8_t *p; diff --git a/hw/sb16.c b/hw/sb16.c index a57754839..5644db4a1 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -48,9 +48,9 @@ #endif #define IO_READ_PROTO(name) \ - uint32_t name (struct CPUX86State *env, uint32_t nport) + uint32_t name (struct CPUState *env, uint32_t nport) #define IO_WRITE_PROTO(name) \ - void name (struct CPUX86State *env, uint32_t nport, uint32_t val) + void name (struct CPUState *env, uint32_t nport, uint32_t val) static struct { int ver_lo; diff --git a/hw/vga.c b/hw/vga.c index bc07aca78..c3aa93f42 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -223,7 +223,7 @@ static uint8_t expand4to8[16]; VGAState vga_state; int vga_io_memory; -static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr) +static uint32_t vga_ioport_read(CPUState *env, uint32_t addr) { VGAState *s = &vga_state; int val, index; @@ -319,7 +319,7 @@ static uint32_t vga_ioport_read(CPUX86State *env, uint32_t addr) return val; } -static void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) +static void vga_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { VGAState *s = &vga_state; int index, v; @@ -1350,8 +1350,8 @@ CPUWriteMemoryFunc *vga_mem_write[3] = { vga_mem_writel, }; -int vga_init(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size) +int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size) { VGAState *s = &vga_state; int i, j, v, b; @@ -1417,6 +1417,10 @@ int vga_init(DisplayState *ds, uint8_t *vga_ram_base, register_ioport_read(0x3da, 1, vga_ioport_read, 1); vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); - cpu_register_physical_memory(0xa0000, 0x20000, vga_io_memory); +#if defined (TARGET_I386) + cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory); +#elif defined (TARGET_PPC) + cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory); +#endif return 0; } diff --git a/vl.h b/vl.h index a65440fd6..f99aa03d4 100644 --- a/vl.h +++ b/vl.h @@ -25,12 +25,12 @@ #define VL_H /* vl.c */ -struct CPUX86State; +struct CPUState; extern int reset_requested; extern int64_t ticks_per_sec; -typedef void (IOPortWriteFunc)(struct CPUX86State *env, uint32_t address, uint32_t data); -typedef uint32_t (IOPortReadFunc)(struct CPUX86State *env, uint32_t address); +typedef void (IOPortWriteFunc)(struct CPUState *env, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(struct CPUState *env, uint32_t address); void *get_mmap_addr(unsigned long size); int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); @@ -93,8 +93,8 @@ static inline void dpy_resize(DisplayState *s, int w, int h) s->dpy_resize(s, w, h); } -int vga_init(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size); +int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); void vga_update_display(void); /* sdl.c */ @@ -144,4 +144,13 @@ void DMA_register_channel (int nchan, void SB16_run (void); void SB16_init (void); +/* fdc.c */ +#define MAX_FD 2 +extern BlockDriverState *fd_table[MAX_FD]; + +void cmos_register_fd (uint8_t fd0, uint8_t fd1); +void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, + char boot_device); +int fdctrl_disk_change (int idx, const unsigned char *filename, int ro); + #endif /* VL_H */ -- cgit v1.2.3 From 4487d0ac49322ddbbd4ede838c0e13a128380606 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jan 2004 00:05:04 +0000 Subject: changed cpu_x86_in/out to cpu_in/out git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@541 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_template.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 4ea94e4a7..5ffde89e4 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -621,22 +621,22 @@ void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void) void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) { - glue(cpu_x86_out, SUFFIX)(env, T0, T1 & DATA_MASK); + glue(cpu_out, SUFFIX)(env, T0, T1 & DATA_MASK); } void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) { - T1 = glue(cpu_x86_in, SUFFIX)(env, T0); + T1 = glue(cpu_in, SUFFIX)(env, T0); } void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void) { - T0 = glue(cpu_x86_in, SUFFIX)(env, EDX & 0xffff); + T0 = glue(cpu_in, SUFFIX)(env, EDX & 0xffff); } void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void) { - glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0); + glue(cpu_out, SUFFIX)(env, EDX & 0xffff, T0); } void OPPROTO glue(glue(op_check_io, SUFFIX), _T0)(void) -- cgit v1.2.3 From 16d17fdb8ee6b25c501b1d32a74cf187455fe3d7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jan 2004 00:05:50 +0000 Subject: debug fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@542 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index ac85efba1..a1e77f591 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -25,8 +25,8 @@ #include #include -#include "vl.h" #include "cpu.h" +#include "vl.h" #define log(...) fprintf (stderr, "dma: " __VA_ARGS__) #ifdef DEBUG_DMA @@ -79,7 +79,7 @@ enum { }; -static void write_page (struct CPUX86State *env, uint32_t nport, uint32_t data) +static void write_page (CPUState *env, uint32_t nport, uint32_t data) { int ichan; int ncont; @@ -114,7 +114,7 @@ static inline int getff (int ncont) return ff; } -static uint32_t read_chan (struct CPUX86State *env, uint32_t nport) +static uint32_t read_chan (CPUState *env, uint32_t nport) { int ff; int ncont, ichan, nreg; @@ -160,17 +160,17 @@ static void write_chan (uint32_t nport, int size, uint32_t data) } } } -static void write_chanb (struct CPUX86State *env, uint32_t nport, uint32_t data) +static void write_chanb (CPUState *env, uint32_t nport, uint32_t data) { write_chan (nport, 1, data); } -static void write_chanw (struct CPUX86State *env, uint32_t nport, uint32_t data) +static void write_chanw (CPUState *env, uint32_t nport, uint32_t data) { write_chan (nport, 2, data); } -static void write_cont (struct CPUX86State *env, uint32_t nport, uint32_t data) +static void write_cont (CPUState *env, uint32_t nport, uint32_t data) { int iport, ichan, ncont; struct dma_cont *d; @@ -215,17 +215,17 @@ static void write_cont (struct CPUX86State *env, uint32_t nport, uint32_t data) case 0xb: /* mode */ { -#ifdef DMA_DEBUG + ichan = data & 3; +#ifdef DEBUG_DMA int op; int ai; int dir; int opmode; - ichan = val & 3; - op = (val >> 2) & 3; - ai = (val >> 4) & 1; - dir = (val >> 5) & 1; - opmode = (val >> 6) & 3; + op = (data >> 2) & 3; + ai = (data >> 4) & 1; + dir = (data >> 5) & 1; + opmode = (data >> 6) & 3; linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n", ichan, op, ai, dir, opmode); @@ -259,7 +259,7 @@ static void write_cont (struct CPUX86State *env, uint32_t nport, uint32_t data) goto error; } -#ifdef DMA_DEBUG +#ifdef DEBUG_DMA if (0xc != iport) { linfo ("nport %#06x, ncont %d, ichan % 2d, val %#06x\n", nport, d != dma_controllers, ichan, data); -- cgit v1.2.3 From bd497938895ec4fd7b327aac4de390e34f543509 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jan 2004 00:06:41 +0000 Subject: use generic GenOpFunc git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@543 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 5 ----- target-i386/translate.c | 5 ----- target-sparc/translate.c | 30 ++++-------------------------- 3 files changed, 4 insertions(+), 36 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 944794629..44c6387ea 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -51,11 +51,6 @@ enum { #include "gen-op.h" -typedef void (GenOpFunc)(void); -typedef void (GenOpFunc1)(long); -typedef void (GenOpFunc2)(long, long); -typedef void (GenOpFunc3)(long, long, long); - static GenOpFunc2 *gen_test_cc[14] = { gen_op_test_eq, gen_op_test_ne, diff --git a/target-i386/translate.c b/target-i386/translate.c index 725ee5ba8..e45b6a438 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -128,11 +128,6 @@ enum { NB_OREGS, }; -typedef void (GenOpFunc)(void); -typedef void (GenOpFunc1)(long); -typedef void (GenOpFunc2)(long, long); -typedef void (GenOpFunc3)(long, long, long); - static GenOpFunc *gen_op_mov_reg_T0[3][8] = { [OT_BYTE] = { gen_op_movb_EAX_T0, diff --git a/target-sparc/translate.c b/target-sparc/translate.c index a5c1dbe6f..82bd33c8e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2,6 +2,7 @@ SPARC translation Copyright (C) 2003 Thomas M. Ogrisegg + 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 @@ -19,33 +20,15 @@ */ /* - SPARC has two pitfalls: Delay slots and (a)nullification. - This is currently solved as follows: - - 'call' instructions simply execute the delay slot before the actual - control transfer instructions. - - 'jmpl' instructions execute calculate the destination, then execute - the delay slot and then do the control transfer. - - (conditional) branch instructions are the most difficult ones, as the - delay slot may be nullified (ie. not executed). This happens when a - conditional branch is not executed (thus no control transfer happens) - and the 'anull' bit in the branch instruction opcode is set. This is - currently solved by doing a jump after the delay slot instruction. - TODO-list: - Register window overflow/underflow check + NPC/PC static optimisations (use JUMP_TB when possible) FPU-Instructions - Coprocessor-Instructions - Check signedness issues Privileged instructions + Coprocessor-Instructions Optimize synthetic instructions Optional alignment and privileged instruction check - - -- TMO, 09/03/03 - */ +*/ #include #include @@ -87,11 +70,6 @@ enum { static void disas_sparc_insn(DisasContext * dc); -typedef void (GenOpFunc) (void); -typedef void (GenOpFunc1) (long); -typedef void (GenOpFunc2) (long, long); -typedef void (GenOpFunc3) (long, long, long); - static GenOpFunc *gen_op_movl_TN_reg[2][32] = { { gen_op_movl_g0_T0, -- cgit v1.2.3 From 728c9fd5a9a3d3dc955c0fa8bd9a090c9a08f4eb Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jan 2004 00:08:14 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@544 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ Makefile.target | 26 ++++++++++++++++++++++++-- TODO | 20 +++++++++++++++----- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/Changelog b/Changelog index ed3b0e4ae..9cddb49cc 100644 --- a/Changelog +++ b/Changelog @@ -12,6 +12,9 @@ version 0.5.2: - 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) version 0.5.1: diff --git a/Makefile.target b/Makefile.target index eb2e6db12..9d52680a9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -36,7 +36,21 @@ endif endif endif + +ifeq ($(TARGET_ARCH), ppc) + +ifeq ($(ARCH), ppc) +PROGS+=$(QEMU_SYSTEM) +endif + +ifeq ($(ARCH), i386) +ifdef CONFIG_SOFTMMU +PROGS+=$(QEMU_SYSTEM) endif +endif # ARCH = i386 + +endif # TARGET_ARCH = ppc +endif # !CONFIG_USER_ONLY ifdef CONFIG_STATIC LDFLAGS+=-static @@ -147,7 +161,7 @@ LIBOBJS+=helper.o helper2.o endif ifeq ($(TARGET_ARCH), ppc) -LIBOBJS+=helper.o +LIBOBJS+= op_helper.o helper.o endif # NOTE: the disassembler code is only needed for debugging @@ -183,7 +197,10 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o +VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o +ifeq ($(TARGET_ARCH), ppc) +VL_OBJS+= hw.o +endif ifdef CONFIG_SDL VL_OBJS+=sdl.o ifdef CONFIG_STATIC @@ -246,6 +263,11 @@ ifeq ($(TARGET_ARCH), sparc) op.o: op.c op_template.h endif +ifeq ($(TARGET_ARCH), ppc) +op.o: op.c op_template.h op_mem.h +op_helper.o: op_helper_mem.h +endif + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< diff --git a/TODO b/TODO index da07daae0..d483eb4d7 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,12 @@ +before 0.5.2: +------------ + +- TLB code protection support +- basic VGA optimizations +- disable SMC handling for ARM/SPARC/PPC + +short term: +---------- - user/kernel PUSHL/POPL in helper.c - keyboard output buffer filling timing emulation - verify tb_flush() with a20 and TLBs @@ -5,19 +14,20 @@ - cmos clock update and timers - test ldt limit < 7 ? - tests for each target CPU -- optimize FPU operations (evaluate x87 stack pointer statically) and - fix cr0.TS emulation -- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) -- sysenter/sysexit emulation - fix CCOP optimisation - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). - fix arm fpu rounding (at least for float->integer conversions) +- SMP support lower priority: -------------- +- suppress shift_mem ops +- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) +- sysenter/sysexit emulation +- optimize FPU operations (evaluate x87 stack pointer statically) and + fix cr0.TS emulation - add IPC syscalls -- SMP support - use -msoft-float on ARM - use kernel traps for unaligned accesses on ARM ? - handle rare page fault cases (in particular if page fault in heplers or -- cgit v1.2.3 From 8977f3c107efa48edc19ea45f513f204bfe9d8e7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jan 2004 00:09:06 +0000 Subject: Floppy disk emulation (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@545 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 1435 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1435 insertions(+) create mode 100644 hw/fdc.c diff --git a/hw/fdc.c b/hw/fdc.c new file mode 100644 index 000000000..a47b809b4 --- /dev/null +++ b/hw/fdc.c @@ -0,0 +1,1435 @@ +/* + * QEMU Floppy disk emulator + * + * Copyright (c) 2003 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +/********************************************************/ +/* debug Floppy devices */ +//#define DEBUG_FLOPPY + +#ifdef DEBUG_FLOPPY +#define FLOPPY_DPRINTF(fmt, args...) \ +do { printf("FLOPPY: " fmt , ##args); } while (0) +#else +#define FLOPPY_DPRINTF(fmt, args...) +#endif + +#define FLOPPY_ERROR(fmt, args...) \ +do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0) + +/********************************************************/ +/* Floppy drive emulation */ + +/* Will always be a fixed parameter for us */ +#define FD_SECTOR_LEN 512 +#define FD_SECTOR_SC 2 /* Sector size code */ + +/* Floppy disk drive emulation */ +typedef enum fdisk_type_t { + FDRIVE_DISK_288 = 0x01, /* 2.88 MB disk */ + FDRIVE_DISK_144 = 0x02, /* 1.44 MB disk */ + FDRIVE_DISK_720 = 0x03, /* 720 kB disk */ + FDRIVE_DISK_NONE = 0x04, /* No disk */ +} fdisk_type_t; + +typedef enum fdrive_type_t { + FDRIVE_DRV_144 = 0x00, /* 1.44 MB 3"5 drive */ + FDRIVE_DRV_288 = 0x01, /* 2.88 MB 3"5 drive */ + FDRIVE_DRV_120 = 0x02, /* 1.2 MB 5"25 drive */ + FDRIVE_DRV_NONE = 0x03, /* No drive connected */ +} fdrive_type_t; + +typedef struct fdrive_t { + BlockDriverState *bs; + /* Drive status */ + fdrive_type_t drive; + uint8_t motor; /* on/off */ + uint8_t perpendicular; /* 2.88 MB access mode */ + uint8_t rv; /* Revalidated */ + /* Position */ + uint8_t head; + uint8_t track; + uint8_t sect; + /* Last operation status */ + uint8_t dir; /* Direction */ + uint8_t rw; /* Read/write */ + /* Media */ + fdisk_type_t disk; /* Disk type */ + uint8_t last_sect; /* Nb sector per track */ + uint8_t max_track; /* Nb of tracks */ + uint8_t ro; /* Is read-only */ +} fdrive_t; + +static void fd_init (fdrive_t *drv) +{ + /* Drive */ + drv->bs = NULL; +// drv->drive = FDRIVE_DRV_288; + drv->drive = FDRIVE_DRV_144; + drv->motor = 0; + drv->perpendicular = 0; + drv->rv = 0; + /* Disk */ + drv->disk = FDRIVE_DISK_NONE; + drv->last_sect = 1; + drv->max_track = 0; +} + +static int _fd_sector (uint8_t head, uint8_t track, + uint8_t sect, uint8_t last_sect) +{ + return (((track * 2) + head) * last_sect) + sect - 1; +} + +/* Returns current position, in sectors, for given drive */ +static int fd_sector (fdrive_t *drv) +{ + return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect); +} + +static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect, + int enable_seek) +{ + uint32_t sector; + + if (track > drv->max_track) { + FLOPPY_ERROR("try to read %d %02x %02x (max=%d %02x %02x)\n", + head, track, sect, 1, drv->max_track, drv->last_sect); + return 2; + } + if (sect > drv->last_sect) { + FLOPPY_ERROR("try to read %d %02x %02x (max=%d %02x %02x)\n", + head, track, sect, 1, drv->max_track, drv->last_sect); + return 3; + } + sector = _fd_sector(head, track, sect, drv->last_sect); + if (sector != fd_sector(drv)) { +#if 0 + if (!enable_seek) { + FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n", + head, track, sect, 1, drv->max_track, drv->last_sect); + return 4; + } +#endif + drv->head = head; + drv->track = track; + drv->sect = sect; + return 1; + } + + return 0; +} + +/* Set drive back to track 0 */ +static void fd_recalibrate (fdrive_t *drv) +{ + FLOPPY_DPRINTF("recalibrate\n"); + drv->head = 0; + drv->track = 0; + drv->sect = 1; + drv->dir = 1; + drv->rw = 0; +} + +/* Revalidate a disk drive after a disk change */ +static void fd_revalidate (fdrive_t *drv, int ro) +{ + int64_t nb_sectors; + + FLOPPY_DPRINTF("revalidate\n"); + drv->rv = 0; + if (drv->bs != NULL) { + bdrv_get_geometry(drv->bs, &nb_sectors); +#if 1 + if (nb_sectors > 2880) +#endif + { + /* Pretend we have a 2.88 MB disk */ + drv->disk = FDRIVE_DISK_288; + drv->last_sect = 36; + drv->max_track = 80; +#if 1 + } else if (nb_sectors > 1440) { + /* Pretend we have a 1.44 MB disk */ + drv->disk = FDRIVE_DISK_144; + drv->last_sect = 18; + drv->max_track = 80; + } else { + /* Pretend we have a 720 kB disk */ + drv->disk = FDRIVE_DISK_720; + drv->last_sect = 9; + drv->max_track = 80; +#endif + } + } else { + drv->disk = FDRIVE_DISK_NONE; + drv->last_sect = 1; /* Avoid eventual divide by 0 bugs */ + } + drv->ro = ro; + drv->rv = 1; +} + +/* Motor control */ +static void fd_start (fdrive_t *drv) +{ + drv->motor = 1; +} + +static void fd_stop (fdrive_t *drv) +{ + drv->motor = 0; +} + +/* Re-initialise a drives (motor off, repositioned) */ +static void fd_reset (fdrive_t *drv) +{ + fd_stop(drv); + fd_recalibrate(drv); +} + +/********************************************************/ +/* Intel 82078 floppy disk controler emulation */ + +static void fdctrl_reset (int do_irq); +static void fdctrl_reset_fifo (void); +static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq); +static int fdctrl_misc_handler (int duknwo); +static void fdctrl_raise_irq (uint8_t status); + +static uint32_t fdctrl_read_statusB (CPUState *env, uint32_t reg); +static uint32_t fdctrl_read_dor (CPUState *env, uint32_t reg); +static void fdctrl_write_dor (CPUState *env, uint32_t reg, uint32_t value); +static uint32_t fdctrl_read_tape (CPUState *env, uint32_t reg); +static void fdctrl_write_tape (CPUState *env, uint32_t reg, uint32_t value); +static uint32_t fdctrl_read_main_status (CPUState *env, uint32_t reg); +static void fdctrl_write_rate (CPUState *env, uint32_t reg, uint32_t value); +static uint32_t fdctrl_read_data (CPUState *env, uint32_t reg); +static void fdctrl_write_data (CPUState *env, uint32_t reg, uint32_t value); +static uint32_t fdctrl_read_dir (CPUState *env, uint32_t reg); + +enum { + FD_CTRL_ACTIVE = 0x01, + FD_CTRL_RESET = 0x02, + FD_CTRL_SLEEP = 0x04, + FD_CTRL_BUSY = 0x08, + FD_CTRL_INTR = 0x10, +}; + +enum { + FD_DIR_WRITE = 0, + FD_DIR_READ = 1, + FD_DIR_SCANE = 2, + FD_DIR_SCANL = 3, + FD_DIR_SCANH = 4, +}; + +enum { + FD_STATE_CMD = 0x00, + FD_STATE_STATUS = 0x01, + FD_STATE_DATA = 0x02, + FD_STATE_STATE = 0x03, + FD_STATE_MULTI = 0x10, + FD_STATE_SEEK = 0x20, +}; + +#define FD_STATE(state) ((state) & FD_STATE_STATE) +#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI) +#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK) + +typedef struct fdctrl_t { + /* Controler's identification */ + uint8_t version; + /* HW */ + int irq_lvl; + int dma_chann; + /* Controler state */ + uint8_t state; + uint8_t dma_en; + uint8_t cur_drv; + uint8_t bootsel; + /* Command FIFO */ + uint8_t fifo[FD_SECTOR_LEN]; + uint32_t data_pos; + uint32_t data_len; + uint8_t data_state; + uint8_t data_dir; + uint8_t int_status; + /* States kept only to be returned back */ + /* Timers state */ + uint8_t timer0; + uint8_t timer1; + /* precompensation */ + uint8_t precomp_trk; + uint8_t config; + uint8_t lock; + /* Power down config (also with status regB access mode */ + uint8_t pwrd; + /* Floppy drives */ + fdrive_t drives[2]; +} fdctrl_t; + +static fdctrl_t fdctrl; + +void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, + char boot_device) +{ +// int io_mem; + int i; + + FLOPPY_DPRINTF("init controler\n"); + memset(&fdctrl, 0, sizeof(fdctrl)); + fdctrl.version = 0x90; /* Intel 82078 controler */ + fdctrl.irq_lvl = irq_lvl; + fdctrl.dma_chann = dma_chann; + fdctrl.config = 0x40; /* Implicit seek, polling & FIFO enabled */ + if (fdctrl.dma_chann != -1) { + fdctrl.dma_en = 1; + DMA_register_channel(dma_chann, &fdctrl_transfer_handler, + &fdctrl_misc_handler); + } else { + fdctrl.dma_en = 0; + } + for (i = 0; i < MAX_FD; i++) + fd_init(&fdctrl.drives[i]); + fdctrl_reset(0); + fdctrl.state = FD_CTRL_ACTIVE; + if (mem_mapped) { + FLOPPY_ERROR("memory mapped floppy not supported by now !\n"); +#if 0 + io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write); + cpu_register_physical_memory(base, 0x08, io_mem); +#endif + } else { + register_ioport_read(base + 0x01, 1, fdctrl_read_statusB, 1); + register_ioport_read(base + 0x02, 1, fdctrl_read_dor, 1); + register_ioport_write(base + 0x02, 1, fdctrl_write_dor, 1); + register_ioport_read(base + 0x03, 1, fdctrl_read_tape, 1); + register_ioport_write(base + 0x03, 1, fdctrl_write_tape, 1); + register_ioport_read(base + 0x04, 1, fdctrl_read_main_status, 1); + register_ioport_write(base + 0x04, 1, fdctrl_write_rate, 1); + register_ioport_read(base + 0x05, 1, fdctrl_read_data, 1); + register_ioport_write(base + 0x05, 1, fdctrl_write_data, 1); + register_ioport_read(base + 0x07, 1, fdctrl_read_dir, 1); + } + if (boot_device == 'b') + fdctrl.bootsel = 1; + else + fdctrl.bootsel = 0; +#if defined (TARGET_I386) + cmos_register_fd(fdctrl.drives[0].drive, fdctrl.drives[1].drive); +#endif +} + +int fdctrl_disk_change (int idx, const unsigned char *filename, int ro) +{ + fdrive_t *drv; + + if (idx < 0 || idx > 1) + return -1; + FLOPPY_DPRINTF("disk %d change: %s (%s)\n", idx, filename, + ro == 0 ? "rw" : "ro"); + drv = &fdctrl.drives[idx]; + if (fd_table[idx] != NULL) { + bdrv_close(fd_table[idx]); + fd_table[idx] = NULL; + } + fd_table[idx] = bdrv_open(filename, ro); + drv->bs = fd_table[idx]; + if (fd_table[idx] == NULL) + return -1; + fd_revalidate(drv, ro); +#if 0 + fd_recalibrate(drv); + fdctrl_reset_fifo(); + fdctrl_raise_irq(0x20); +#endif + + return 0; +} + +/* Change IRQ state */ +static void fdctrl_reset_irq (void) +{ + if (fdctrl.state & FD_CTRL_INTR) { + pic_set_irq(fdctrl.irq_lvl, 0); + fdctrl.state &= ~(FD_CTRL_INTR | FD_CTRL_SLEEP | FD_CTRL_BUSY); + } +} + +static void fdctrl_raise_irq (uint8_t status) +{ + if (~(fdctrl.state & FD_CTRL_INTR)) { + pic_set_irq(fdctrl.irq_lvl, 1); + fdctrl.state |= FD_CTRL_INTR; + } + FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status); + fdctrl.int_status = status; +} + +/* Reset controler */ +static void fdctrl_reset (int do_irq) +{ + int i; + + FLOPPY_DPRINTF("reset controler\n"); + fdctrl_reset_irq(); + /* Initialise controler */ + fdctrl.cur_drv = 0; + /* FIFO state */ + fdctrl.data_pos = 0; + fdctrl.data_len = 0; + fdctrl.data_state = FD_STATE_CMD; + fdctrl.data_dir = FD_DIR_WRITE; + for (i = 0; i < MAX_FD; i++) + fd_reset(&fdctrl.drives[i]); + fdctrl_reset_fifo(); + if (do_irq) + fdctrl_raise_irq(0x20); +} + +/* Status B register : 0x01 (read-only) */ +static uint32_t fdctrl_read_statusB (CPUState *env, uint32_t reg) +{ + fdctrl_reset_irq(); + FLOPPY_DPRINTF("status register: 0x00\n"); + + return 0; +} + +/* Digital output register : 0x02 */ +static uint32_t fdctrl_read_dor (CPUState *env, uint32_t reg) +{ + fdrive_t *cur_drv, *drv0, *drv1; + uint32_t retval = 0; + + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + /* Drive motors state indicators */ + retval |= drv1->motor << 5; + retval |= drv0->motor << 4; + /* DMA enable */ + retval |= fdctrl.dma_en << 3; + /* Reset indicator */ + retval |= (fdctrl.state & FD_CTRL_RESET) == 0 ? 0x04 : 0; + /* Selected drive */ + retval |= fdctrl.cur_drv; + FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval); + + return retval; +} + +static void fdctrl_write_dor (CPUState *env, uint32_t reg, uint32_t value) +{ + fdrive_t *drv0, *drv1; + + fdctrl_reset_irq(); + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + /* Reset mode */ + if (fdctrl.state & FD_CTRL_RESET) { + if (!(value & 0x04)) { + FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + return; + } + } + FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value); + /* Drive motors state indicators */ + if (value & 0x20) + fd_start(drv1); + else + fd_stop(drv1); + if (value & 0x10) + fd_start(drv0); + else + fd_stop(drv0); + /* DMA enable */ +#if 0 + if (fdctrl.dma_chann != -1) + fdctrl.dma_en = 1 - ((value >> 3) & 1); +#endif + /* Reset */ + if (!(value & 0x04)) { + if (!(fdctrl.state & FD_CTRL_RESET)) { + FLOPPY_DPRINTF("controler enter RESET state\n"); + fdctrl.state |= FD_CTRL_RESET; + fdctrl_reset(1); + } + } else { + if (fdctrl.state & FD_CTRL_RESET) { + FLOPPY_DPRINTF("controler out of RESET state\n"); + fdctrl.state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); + } + } + /* Selected drive */ + fdctrl.cur_drv = value & 1; +} + +/* Tape drive register : 0x03 */ +static uint32_t fdctrl_read_tape (CPUState *env, uint32_t reg) +{ + uint32_t retval = 0; + + fdctrl_reset_irq(); + /* Disk boot selection indicator */ + retval |= fdctrl.bootsel << 2; + /* Tape indicators: never allowed */ + FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval); + + return retval; +} + +static void fdctrl_write_tape (CPUState *env, uint32_t reg, uint32_t value) +{ + fdctrl_reset_irq(); + /* Reset mode */ + if (fdctrl.state & FD_CTRL_RESET) { + FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + return; + } + FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value); + /* Disk boot selection indicator */ + fdctrl.bootsel = (value >> 2) & 1; + /* Tape indicators: never allow */ +} + +/* Main status register : 0x04 (read) */ +static uint32_t fdctrl_read_main_status (CPUState *env, uint32_t reg) +{ + uint32_t retval = 0; + + fdctrl_reset_irq(); + fdctrl.state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET); + if (!(fdctrl.state & FD_CTRL_BUSY)) { + /* Data transfer allowed */ + retval |= 0x80; + /* Data transfer direction indicator */ + if (fdctrl.data_dir == FD_DIR_READ) + retval |= 0x40; + } + /* Should handle 0x20 for SPECIFY command */ + /* Command busy indicator */ + if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA || + FD_STATE(fdctrl.data_state) == FD_STATE_STATUS) + retval |= 0x10; + FLOPPY_DPRINTF("main status register: 0x%02x\n", retval); + + return retval; +} + +/* Data select rate register : 0x04 (write) */ +static void fdctrl_write_rate (CPUState *env, uint32_t reg, uint32_t value) +{ + fdctrl_reset_irq(); + /* Reset mode */ + if (fdctrl.state & FD_CTRL_RESET) { + if (reg != 0x2 || !(value & 0x04)) { + FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + return; + } + } + FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); + /* Reset: autoclear */ + if (value & 0x80) { + fdctrl.state |= FD_CTRL_RESET; + fdctrl_reset(1); + fdctrl.state &= ~FD_CTRL_RESET; + } + if (value & 0x40) { + fdctrl.state |= FD_CTRL_SLEEP; + fdctrl_reset(1); + } +// fdctrl.precomp = (value >> 2) & 0x07; +} + +/* Digital input register : 0x07 (read-only) */ +static uint32_t fdctrl_read_dir (CPUState *env, uint32_t reg) +{ + fdrive_t *drv0, *drv1; + uint32_t retval = 0; + + fdctrl_reset_irq(); + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + if (drv0->rv || drv1->rv) + retval |= 0x80; + if (retval != 0) + FLOPPY_ERROR("Floppy digital input register: 0x%02x\n", retval); + drv0->rv = 0; + drv1->rv = 0; + + return retval; +} + +/* FIFO state control */ +static void fdctrl_reset_fifo (void) +{ + fdctrl.data_dir = FD_DIR_WRITE; + fdctrl.data_pos = 0; + fdctrl.data_state = FD_STATE_CMD; +} + +/* Set FIFO status for the host to read */ +static void fdctrl_set_fifo (int fifo_len, int do_irq) +{ + fdctrl.data_dir = FD_DIR_READ; + fdctrl.data_len = fifo_len; + fdctrl.data_pos = 0; + fdctrl.data_state = FD_STATE_STATUS; + if (do_irq) + fdctrl_raise_irq(0x00); +} + +/* Set an error: unimplemented/unknown command */ +static void fdctrl_unimplemented (void) +{ +#if 0 + fdrive_t *cur_drv, *drv0, *drv1; + + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + fdctrl.fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl.cur_drv; + fdctrl.fifo[1] = 0x00; + fdctrl.fifo[2] = 0x00; + fdctrl_set_fifo(3, 1); +#else + fdctrl_reset_fifo(); +#endif +} + +/* Callback for transfer end (stop or abort) */ +static void fdctrl_stop_transfer (uint8_t status0, uint8_t status1, + uint8_t status2) +{ + fdrive_t *cur_drv, *drv0, *drv1; + + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", + status0, status1, status2, + status0 | (cur_drv->head << 1) | fdctrl.cur_drv); + fdctrl.fifo[0] = status0 | (cur_drv->head << 1) | fdctrl.cur_drv; + fdctrl.fifo[1] = status1; + fdctrl.fifo[2] = status2; + fdctrl.fifo[3] = cur_drv->track; + fdctrl.fifo[4] = cur_drv->head; + fdctrl.fifo[5] = cur_drv->sect; + fdctrl.fifo[6] = FD_SECTOR_SC; + fdctrl.data_dir = FD_DIR_READ; + if (fdctrl.state & FD_CTRL_BUSY) + DMA_release_DREQ(fdctrl.dma_chann); + fdctrl_set_fifo(7, 1); +} + +/* Prepare a data transfer (either DMA or FIFO) */ +static void fdctrl_start_transfer (int direction) +{ + fdrive_t *cur_drv, *drv0, *drv1; + uint8_t kh, kt, ks; + int did_seek; + + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + fdctrl.cur_drv = fdctrl.fifo[1] & 1; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + kt = fdctrl.fifo[2]; + kh = fdctrl.fifo[3]; + ks = fdctrl.fifo[4]; + FLOPPY_DPRINTF("Start tranfert at %d %d %02x %02x (%d)\n", + fdctrl.cur_drv, kh, kt, ks, + _fd_sector(kh, kt, ks, cur_drv->last_sect)); + did_seek = 0; + switch (fd_seek(cur_drv, kh, kt, ks, fdctrl.config & 0x40)) { + case 2: + /* sect too big */ + fdctrl_stop_transfer(0x40, 0x00, 0x00); + fdctrl.fifo[3] = kt; + fdctrl.fifo[4] = kh; + fdctrl.fifo[5] = ks; + return; + case 3: + /* track too big */ + fdctrl_stop_transfer(0x40, 0x80, 0x00); + fdctrl.fifo[3] = kt; + fdctrl.fifo[4] = kh; + fdctrl.fifo[5] = ks; + return; + case 4: + /* No seek enabled */ + fdctrl_stop_transfer(0x40, 0x00, 0x00); + fdctrl.fifo[3] = kt; + fdctrl.fifo[4] = kh; + fdctrl.fifo[5] = ks; + return; + case 1: + did_seek = 1; + break; + default: + break; + } + /* Set the FIFO state */ + fdctrl.data_dir = direction; + fdctrl.data_pos = 0; + fdctrl.data_state = FD_STATE_DATA; /* FIFO ready for data */ + if (fdctrl.fifo[0] & 0x80) + fdctrl.data_state |= FD_STATE_MULTI; + if (did_seek) + fdctrl.data_state |= FD_STATE_SEEK; + if (fdctrl.dma_en) { + int dma_mode; + /* DMA transfer are enabled. Check if DMA channel is well programmed */ + dma_mode = DMA_get_channel_mode(fdctrl.dma_chann); + dma_mode = (dma_mode >> 2) & 3; + FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d)\n", dma_mode, direction, + (128 << fdctrl.fifo[5]) * + (cur_drv->last_sect - ks + 1)); + if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL || + direction == FD_DIR_SCANH) && dma_mode == 0) || + (direction == FD_DIR_WRITE && dma_mode == 2) || + (direction == FD_DIR_READ && dma_mode == 1)) { + /* No access is allowed until DMA transfer has completed */ + fdctrl.state |= FD_CTRL_BUSY; + /* Now, we just have to wait for the DMA controler to + * recall us... + */ + DMA_hold_DREQ(fdctrl.dma_chann); + return; + } + } + FLOPPY_DPRINTF("start non-DMA transfer\n"); + /* IO based transfer: calculate len */ + if (fdctrl.fifo[5] == 00) { + fdctrl.data_len = fdctrl.fifo[8]; + } else { + fdctrl.data_len = 128 << fdctrl.fifo[5]; + fdctrl.data_len *= (cur_drv->last_sect - ks + 1); + if (fdctrl.fifo[0] & 0x80) + fdctrl.data_len *= 2; + } + fdctrl_raise_irq(0x00); + + return; +} + +/* Prepare a transfer of deleted data */ +static void fdctrl_start_transfer_del (int direction) +{ + /* We don't handle deleted data, + * so we don't return *ANYTHING* + */ + fdctrl_stop_transfer(0x60, 0x00, 0x00); +} + +/* handlers for DMA transfers */ +static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq) +{ + fdrive_t *cur_drv, *drv0, *drv1; + void *orig; + int len; + uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; + + fdctrl_reset_irq(); + if (!(fdctrl.state & FD_CTRL_BUSY)) { + FLOPPY_DPRINTF("Not in DMA transfer mode !\n"); + return 0; + } + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; +// *irq = fdctrl.irq_lvl; + *irq = -1; + if (fdctrl.data_dir == FD_DIR_SCANE || fdctrl.data_dir == FD_DIR_SCANL || + fdctrl.data_dir == FD_DIR_SCANH) + status2 = 0x04; + for (fdctrl.data_len = size; fdctrl.data_pos < fdctrl.data_len; + fdctrl.data_pos += len) { + len = size - fdctrl.data_pos; + if (len > FD_SECTOR_LEN) + len = FD_SECTOR_LEN; + FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x " + "(%d-0x%08x)\n", len, size, fdctrl.data_pos, + fdctrl.data_len, fdctrl.cur_drv, cur_drv->head, + cur_drv->track, cur_drv->sect, fd_sector(cur_drv), + fd_sector(cur_drv) * 512); + if (len < FD_SECTOR_LEN) { + memset(&fdctrl.fifo[FD_SECTOR_LEN - len], 0, + FD_SECTOR_LEN - len - 1); + orig = fdctrl.fifo; + } else { + orig = (void *)(addr + fdctrl.data_pos); + } + if (fdctrl.data_dir != FD_DIR_WRITE) { + /* READ & SCAN commands */ + if (cur_drv->bs == NULL || + bdrv_read(cur_drv->bs, fd_sector(cur_drv), orig, 1) < 0) { + FLOPPY_DPRINTF("Floppy: error getting sector %d\n", + fd_sector(cur_drv)); + /* Sure, image size is too small... */ + memset((void *)(addr + fdctrl.data_pos), 0, FD_SECTOR_LEN); + } + if (fdctrl.data_dir == FD_DIR_READ) { + if (len < FD_SECTOR_LEN) { + memcpy((void *)(addr + fdctrl.data_pos), + fdctrl.fifo, FD_SECTOR_LEN); + } + } else { + int ret; + ret = memcmp((void *)(addr + fdctrl.data_pos), + fdctrl.fifo, FD_SECTOR_LEN); + if (ret == 0) { + status2 = 0x08; + goto end_transfer; + } + if ((ret < 0 && fdctrl.data_dir == FD_DIR_SCANL) || + (ret > 0 && fdctrl.data_dir == FD_DIR_SCANH)) { + status2 = 0x00; + goto end_transfer; + } + } + } else { + /* WRITE commands */ + if (cur_drv->bs == NULL || + bdrv_write(cur_drv->bs, fd_sector(cur_drv), orig, 1) < 0) { + FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); + fdctrl_stop_transfer(0x60, 0x00, 0x00); + goto transfer_error; + } + } + if (len == FD_SECTOR_LEN) { + /* Seek to next sector */ + if (cur_drv->sect == cur_drv->last_sect) { + if (cur_drv->head == 0) { + cur_drv->head = 1; + } else { + cur_drv->track++; + cur_drv->head = 0; + } + cur_drv->sect = 1; + FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n", + cur_drv->head, cur_drv->track, cur_drv->sect, + fd_sector(cur_drv)); + if (cur_drv->head == 0) { + FLOPPY_DPRINTF("end transfer\n"); + goto end_transfer; + } + if (!FD_MULTI_TRACK(fdctrl.data_state)) { + /* Single track read */ + FLOPPY_DPRINTF("single track transfert: end transfer\n"); +// status1 |= 0x80; + goto end_transfer; + } + } else { + cur_drv->sect++; + FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n", + cur_drv->head, cur_drv->track, cur_drv->sect, + fd_sector(cur_drv)); + } + } + } +end_transfer: + if (fdctrl.data_dir == FD_DIR_SCANE || + fdctrl.data_dir == FD_DIR_SCANL || + fdctrl.data_dir == FD_DIR_SCANH) + status2 = 0x08; + if (FD_DID_SEEK(fdctrl.data_state)) + status0 |= 0x20; + fdctrl_stop_transfer(status0, status1, status2); +transfer_error: + + return fdctrl.data_pos; +} + +/* Unused... */ +static int fdctrl_misc_handler (int duknwo) +{ + return -1; +} + +/* Data register : 0x05 */ +static uint32_t fdctrl_read_data (CPUState *env, uint32_t reg) +{ + fdrive_t *cur_drv, *drv0, *drv1; + uint32_t retval = 0; + int pos, len; + + fdctrl_reset_irq(); + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + fdctrl.state &= ~FD_CTRL_SLEEP; + if (FD_STATE(fdctrl.data_state) == FD_STATE_CMD) { + FLOPPY_ERROR("can't read data in CMD state\n"); + return 0; + } + pos = fdctrl.data_pos; + if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) { + pos %= FD_SECTOR_LEN; + if (pos == 0) { + len = fdctrl.data_len - fdctrl.data_pos; + if (len > FD_SECTOR_LEN) + len = FD_SECTOR_LEN; + bdrv_read(cur_drv->bs, fd_sector(cur_drv), + fdctrl.fifo, len); + } + } + retval = fdctrl.fifo[pos]; + if (++fdctrl.data_pos == fdctrl.data_len) { + fdctrl.data_pos = 0; + /* Switch from transfert mode to status mode + * then from status mode to command mode + */ + if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) + fdctrl_stop_transfer(0x20, 0x00, 0x00); + else + fdctrl_reset_fifo(); + } + FLOPPY_DPRINTF("data register: 0x%02x\n", retval); + + return retval; +} + +static void fdctrl_write_data (CPUState *env, uint32_t reg, uint32_t value) +{ + fdrive_t *cur_drv, *drv0, *drv1; + + fdctrl_reset_irq(); + drv0 = &fdctrl.drives[fdctrl.bootsel]; + drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + /* Reset mode */ + if (fdctrl.state & FD_CTRL_RESET) { + FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + return; + } + fdctrl.state &= ~FD_CTRL_SLEEP; + if ((fdctrl.data_state & FD_STATE_STATE) == FD_STATE_STATUS) { + FLOPPY_ERROR("can't write data in status mode\n"); + return; + } + /* Is it write command time ? */ + if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) { + /* FIFO data write */ + fdctrl.fifo[fdctrl.data_pos++] = value; + if (fdctrl.data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) || + fdctrl.data_pos == fdctrl.data_len) { + bdrv_write(cur_drv->bs, fd_sector(cur_drv), + fdctrl.fifo, FD_SECTOR_LEN); + } + /* Switch from transfert mode to status mode + * then from status mode to command mode + */ + if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) + fdctrl_stop_transfer(0x20, 0x00, 0x00); + return; + } + if (fdctrl.data_pos == 0) { + /* Command */ + switch (value & 0x5F) { + case 0x46: + /* READ variants */ + FLOPPY_DPRINTF("READ command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + case 0x4C: + /* READ_DELETED variants */ + FLOPPY_DPRINTF("READ_DELETED command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + case 0x50: + /* SCAN_EQUAL variants */ + FLOPPY_DPRINTF("SCAN_EQUAL command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + case 0x56: + /* VERIFY variants */ + FLOPPY_DPRINTF("VERIFY command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + case 0x59: + /* SCAN_LOW_OR_EQUAL variants */ + FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + case 0x5D: + /* SCAN_HIGH_OR_EQUAL variants */ + FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + default: + break; + } + switch (value & 0x7F) { + case 0x45: + /* WRITE variants */ + FLOPPY_DPRINTF("WRITE command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + case 0x49: + /* WRITE_DELETED variants */ + FLOPPY_DPRINTF("WRITE_DELETED command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + default: + break; + } + switch (value) { + case 0x03: + /* SPECIFY */ + FLOPPY_DPRINTF("SPECIFY command\n"); + /* 1 parameter cmd */ + fdctrl.data_len = 3; + goto enqueue; + case 0x04: + /* SENSE_DRIVE_STATUS */ + FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n"); + /* 1 parameter cmd */ + fdctrl.data_len = 2; + goto enqueue; + case 0x07: + /* RECALIBRATE */ + FLOPPY_DPRINTF("RECALIBRATE command\n"); + /* 1 parameter cmd */ + fdctrl.data_len = 2; + goto enqueue; + case 0x08: + /* SENSE_INTERRUPT_STATUS */ + FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n", + fdctrl.int_status); + /* No parameters cmd: returns status if no interrupt */ + fdctrl.fifo[0] = + fdctrl.int_status | (cur_drv->head << 2) | fdctrl.cur_drv; + fdctrl.fifo[1] = cur_drv->track; + fdctrl_set_fifo(2, 0); + return; + case 0x0E: + /* DUMPREG */ + FLOPPY_DPRINTF("DUMPREG command\n"); + /* Drives position */ + fdctrl.fifo[0] = drv0->track; + fdctrl.fifo[1] = drv1->track; + fdctrl.fifo[2] = 0; + fdctrl.fifo[3] = 0; + /* timers */ + fdctrl.fifo[4] = fdctrl.timer0; + fdctrl.fifo[5] = (fdctrl.timer1 << 1) | fdctrl.dma_en; + fdctrl.fifo[6] = cur_drv->last_sect; + fdctrl.fifo[7] = (fdctrl.lock << 7) | + (cur_drv->perpendicular << 2); + fdctrl.fifo[8] = fdctrl.config; + fdctrl.fifo[9] = fdctrl.precomp_trk; + fdctrl_set_fifo(10, 0); + return; + case 0x0F: + /* SEEK */ + FLOPPY_DPRINTF("SEEK command\n"); + /* 2 parameters cmd */ + fdctrl.data_len = 3; + goto enqueue; + case 0x10: + /* VERSION */ + FLOPPY_DPRINTF("VERSION command\n"); + /* No parameters cmd */ + /* Controler's version */ + fdctrl.fifo[0] = fdctrl.version; + fdctrl_set_fifo(1, 1); + return; + case 0x12: + /* PERPENDICULAR_MODE */ + FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n"); + /* 1 parameter cmd */ + fdctrl.data_len = 2; + goto enqueue; + case 0x13: + /* CONFIGURE */ + FLOPPY_DPRINTF("CONFIGURE command\n"); + /* 3 parameters cmd */ + fdctrl.data_len = 4; + goto enqueue; + case 0x14: + /* UNLOCK */ + FLOPPY_DPRINTF("UNLOCK command\n"); + /* No parameters cmd */ + fdctrl.lock = 0; + fdctrl.fifo[0] = 0; + fdctrl_set_fifo(1, 0); + return; + case 0x17: + /* POWERDOWN_MODE */ + FLOPPY_DPRINTF("POWERDOWN_MODE command\n"); + /* 2 parameters cmd */ + fdctrl.data_len = 3; + goto enqueue; + case 0x18: + /* PART_ID */ + FLOPPY_DPRINTF("PART_ID command\n"); + /* No parameters cmd */ + fdctrl.fifo[0] = 0x41; /* Stepping 1 */ + fdctrl_set_fifo(1, 0); + return; + case 0x2C: + /* SAVE */ + FLOPPY_DPRINTF("SAVE command\n"); + /* No parameters cmd */ + fdctrl.fifo[0] = 0; + fdctrl.fifo[1] = 0; + /* Drives position */ + fdctrl.fifo[2] = drv0->track; + fdctrl.fifo[3] = drv1->track; + fdctrl.fifo[4] = 0; + fdctrl.fifo[5] = 0; + /* timers */ + fdctrl.fifo[6] = fdctrl.timer0; + fdctrl.fifo[7] = fdctrl.timer1; + fdctrl.fifo[8] = cur_drv->last_sect; + fdctrl.fifo[9] = (fdctrl.lock << 7) | + (cur_drv->perpendicular << 2); + fdctrl.fifo[10] = fdctrl.config; + fdctrl.fifo[11] = fdctrl.precomp_trk; + fdctrl.fifo[12] = fdctrl.pwrd; + fdctrl.fifo[13] = 0; + fdctrl.fifo[14] = 0; + fdctrl_set_fifo(15, 1); + return; + case 0x33: + /* OPTION */ + FLOPPY_DPRINTF("OPTION command\n"); + /* 1 parameter cmd */ + fdctrl.data_len = 2; + goto enqueue; + case 0x42: + /* READ_TRACK */ + FLOPPY_DPRINTF("READ_TRACK command\n"); + /* 8 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + case 0x4A: + /* READ_ID */ + FLOPPY_DPRINTF("READ_ID command\n"); + /* 1 parameter cmd */ + fdctrl.data_len = 2; + goto enqueue; + case 0x4C: + /* RESTORE */ + FLOPPY_DPRINTF("RESTORE command\n"); + /* 17 parameters cmd */ + fdctrl.data_len = 18; + goto enqueue; + case 0x4D: + /* FORMAT_TRACK */ + FLOPPY_DPRINTF("FORMAT_TRACK command\n"); + /* 5 parameters cmd */ + fdctrl.data_len = 9; + goto enqueue; + case 0x8E: + /* DRIVE_SPECIFICATION_COMMAND */ + FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n"); + /* 5 parameters cmd */ + fdctrl.data_len = 6; + goto enqueue; + case 0x8F: + /* RELATIVE_SEEK_OUT */ + FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n"); + /* 2 parameters cmd */ + fdctrl.data_len = 3; + goto enqueue; + case 0x94: + /* LOCK */ + FLOPPY_DPRINTF("LOCK command\n"); + /* No parameters cmd */ + fdctrl.lock = 1; + fdctrl.fifo[0] = 0x10; + fdctrl_set_fifo(1, 1); + return; + case 0xCD: + /* FORMAT_AND_WRITE */ + FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n"); + /* 10 parameters cmd */ + fdctrl.data_len = 11; + goto enqueue; + case 0xCF: + /* RELATIVE_SEEK_IN */ + FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n"); + /* 2 parameters cmd */ + fdctrl.data_len = 3; + goto enqueue; + default: + /* Unknown command */ + FLOPPY_ERROR("unknown command: 0x%02x\n", value); + fdctrl_unimplemented(); + return; + } + } +enqueue: + fdctrl.fifo[fdctrl.data_pos] = value; + if (++fdctrl.data_pos == fdctrl.data_len) { + /* We now have all parameters + * and will be able to treat the command + */ + switch (fdctrl.fifo[0] & 0x1F) { + case 0x06: + { + /* READ variants */ + FLOPPY_DPRINTF("treat READ command\n"); + fdctrl_start_transfer(FD_DIR_READ); + return; + } + case 0x0C: + /* READ_DELETED variants */ +// FLOPPY_DPRINTF("treat READ_DELETED command\n"); + FLOPPY_ERROR("treat READ_DELETED command\n"); + fdctrl_start_transfer_del(1); + return; + case 0x16: + /* VERIFY variants */ +// FLOPPY_DPRINTF("treat VERIFY command\n"); + FLOPPY_ERROR("treat VERIFY command\n"); + fdctrl_stop_transfer(0x20, 0x00, 0x00); + return; + case 0x10: + /* SCAN_EQUAL variants */ +// FLOPPY_DPRINTF("treat SCAN_EQUAL command\n"); + FLOPPY_ERROR("treat SCAN_EQUAL command\n"); + fdctrl_start_transfer(FD_DIR_SCANE); + return; + case 0x19: + /* SCAN_LOW_OR_EQUAL variants */ +// FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n"); + FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n"); + fdctrl_start_transfer(FD_DIR_SCANL); + return; + case 0x1D: + /* SCAN_HIGH_OR_EQUAL variants */ +// FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n"); + FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n"); + fdctrl_start_transfer(FD_DIR_SCANH); + return; + default: + break; + } + switch (fdctrl.fifo[0] & 0x3F) { + case 0x05: + /* WRITE variants */ + FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl.fifo[0]); + fdctrl_start_transfer(FD_DIR_WRITE); + return; + case 0x09: + /* WRITE_DELETED variants */ +// FLOPPY_DPRINTF("treat WRITE_DELETED command\n"); + FLOPPY_ERROR("treat WRITE_DELETED command\n"); + fdctrl_start_transfer_del(FD_DIR_WRITE); + return; + default: + break; + } + switch (fdctrl.fifo[0]) { + case 0x03: + /* SPECIFY */ + FLOPPY_DPRINTF("treat SPECIFY command\n"); + fdctrl.timer0 = (fdctrl.fifo[1] >> 4) & 0xF; + fdctrl.timer1 = fdctrl.fifo[1] >> 1; + /* No result back */ + fdctrl_reset_fifo(); + break; + case 0x04: + /* SENSE_DRIVE_STATUS */ + FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n"); + fdctrl.cur_drv = fdctrl.fifo[1] & 1; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + cur_drv->head = (fdctrl.fifo[1] >> 2) & 1; + /* 1 Byte status back */ + fdctrl.fifo[0] = (cur_drv->ro << 6) | + (cur_drv->track == 0 ? 0x10 : 0x00) | + fdctrl.cur_drv; + fdctrl_set_fifo(1, 0); + break; + case 0x07: + /* RECALIBRATE */ + FLOPPY_DPRINTF("treat RECALIBRATE command\n"); + fdctrl.cur_drv = fdctrl.fifo[1] & 1; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + fd_recalibrate(cur_drv); + fdctrl_reset_fifo(); + /* Raise Interrupt */ + fdctrl_raise_irq(0x20); + break; + case 0x0F: + /* SEEK */ + FLOPPY_DPRINTF("treat SEEK command\n"); + fdctrl.cur_drv = fdctrl.fifo[1] & 1; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + if (fdctrl.fifo[2] <= cur_drv->track) + cur_drv->dir = 1; + else + cur_drv->dir = 0; + cur_drv->head = (fdctrl.fifo[1] >> 2) & 1; + if (fdctrl.fifo[2] > cur_drv->max_track) { + fdctrl_raise_irq(0x60); + } else { + cur_drv->track = fdctrl.fifo[2]; + fdctrl_reset_fifo(); + /* Raise Interrupt */ + fdctrl_raise_irq(0x20); + } + break; + case 0x12: + /* PERPENDICULAR_MODE */ + FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n"); + if (fdctrl.fifo[1] & 0x80) + cur_drv->perpendicular = fdctrl.fifo[1] & 0x7; + /* No result back */ + fdctrl_reset_fifo(); + break; + case 0x13: + /* CONFIGURE */ + FLOPPY_DPRINTF("treat CONFIGURE command\n"); + fdctrl.config = fdctrl.fifo[2]; + fdctrl.precomp_trk = fdctrl.fifo[3]; + /* No result back */ + fdctrl_reset_fifo(); + break; + case 0x17: + /* POWERDOWN_MODE */ + FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n"); + fdctrl.pwrd = fdctrl.fifo[1]; + fdctrl.fifo[0] = fdctrl.fifo[1]; + fdctrl_set_fifo(1, 1); + break; + case 0x33: + /* OPTION */ + FLOPPY_DPRINTF("treat OPTION command\n"); + /* No result back */ + fdctrl_reset_fifo(); + break; + case 0x42: + /* READ_TRACK */ +// FLOPPY_DPRINTF("treat READ_TRACK command\n"); + FLOPPY_ERROR("treat READ_TRACK command\n"); + fdctrl_unimplemented(); + break; + case 0x4A: + /* READ_ID */ +// FLOPPY_DPRINTF("treat READ_ID command\n"); + FLOPPY_ERROR("treat READ_ID command\n"); + fdctrl_stop_transfer(0x00, 0x00, 0x00); + break; + case 0x4C: + /* RESTORE */ + FLOPPY_DPRINTF("treat RESTORE command\n"); + /* Drives position */ + drv0->track = fdctrl.fifo[3]; + drv1->track = fdctrl.fifo[4]; + /* timers */ + fdctrl.timer0 = fdctrl.fifo[7]; + fdctrl.timer1 = fdctrl.fifo[8]; + cur_drv->last_sect = fdctrl.fifo[9]; + fdctrl.lock = fdctrl.fifo[10] >> 7; + cur_drv->perpendicular = (fdctrl.fifo[10] >> 2) & 0xF; + fdctrl.config = fdctrl.fifo[11]; + fdctrl.precomp_trk = fdctrl.fifo[12]; + fdctrl.pwrd = fdctrl.fifo[13]; + fdctrl_reset_fifo(); + break; + case 0x4D: + /* FORMAT_TRACK */ +// FLOPPY_DPRINTF("treat FORMAT_TRACK command\n"); + FLOPPY_ERROR("treat FORMAT_TRACK command\n"); + fdctrl_unimplemented(); + break; + case 0x8E: + /* DRIVE_SPECIFICATION_COMMAND */ + FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n"); + if (fdctrl.fifo[fdctrl.data_pos - 1] & 0x80) { + /* Command parameters done */ + if (fdctrl.fifo[fdctrl.data_pos - 1] & 0x40) { + fdctrl.fifo[0] = fdctrl.fifo[1]; + fdctrl.fifo[2] = 0; + fdctrl.fifo[3] = 0; + fdctrl_set_fifo(4, 1); + } else { + fdctrl_reset_fifo(); + } + } else if (fdctrl.data_len > 7) { + /* ERROR */ + fdctrl.fifo[0] = 0x80 | + (cur_drv->head << 2) | fdctrl.cur_drv; + fdctrl_set_fifo(1, 1); + } + break; + case 0x8F: + /* RELATIVE_SEEK_OUT */ + FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n"); + fdctrl.cur_drv = fdctrl.fifo[1] & 1; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + cur_drv->head = (fdctrl.fifo[1] >> 2) & 1; + if (fdctrl.fifo[2] + cur_drv->track > cur_drv->max_track) { + /* ERROR */ + fdctrl_raise_irq(0x70); + } else { + cur_drv->track += fdctrl.fifo[2]; + cur_drv->dir = 0; + fdctrl_reset_fifo(); + fdctrl_raise_irq(0x20); + } + break; + case 0xCD: + /* FORMAT_AND_WRITE */ +// FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n"); + FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n"); + fdctrl_unimplemented(); + break; + case 0xCF: + /* RELATIVE_SEEK_IN */ + FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n"); + fdctrl.cur_drv = fdctrl.fifo[1] & 1; + cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + cur_drv->head = (fdctrl.fifo[1] >> 2) & 1; + if (fdctrl.fifo[2] > cur_drv->track) { + /* ERROR */ + fdctrl_raise_irq(0x60); + } else { + fdctrl_reset_fifo(); + cur_drv->track -= fdctrl.fifo[2]; + cur_drv->dir = 1; + /* Raise Interrupt */ + fdctrl_raise_irq(0x20); + } + break; + } + } +} -- cgit v1.2.3 From 9e62fd7f26d522f77f2a56bda6033c73bf286e07 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jan 2004 22:49:06 +0000 Subject: ppc support (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@546 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/gdbstub.c b/gdbstub.c index 9471d8c16..469a15962 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -359,6 +359,69 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) #endif } +#elif defined (TARGET_PPC) +static void to_le32(uint8_t *p, int v) +{ + p[3] = v; + p[2] = v >> 8; + p[1] = v >> 16; + p[0] = v >> 24; +} + +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + uint32_t tmp; + int i; + + /* fill in gprs */ + for(i = 0; i < 8; i++) { + to_le32(mem_buf + i * 4, env->gpr[i]); + } + /* fill in fprs */ + for (i = 0; i < 32; i++) { + to_le32(mem_buf + (i * 2) + 32, *((uint32_t *)&env->fpr[i])); + to_le32(mem_buf + (i * 2) + 33, *((uint32_t *)&env->fpr[i] + 1)); + } + /* nip, msr, ccr, lnk, ctr, xer, mq */ + to_le32(mem_buf + 96, tswapl(env->nip)); + to_le32(mem_buf + 97, tswapl(_load_msr())); + to_le32(mem_buf + 98, 0); + tmp = 0; + for (i = 0; i < 8; i++) + tmp |= env->crf[i] << (32 - (i * 4)); + to_le32(mem_buf + 98, tmp); + to_le32(mem_buf + 99, tswapl(env->lr)); + to_le32(mem_buf + 100, tswapl(env->ctr)); + to_le32(mem_buf + 101, tswapl(_load_xer())); + to_le32(mem_buf + 102, 0); + + return 102; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + uint32_t *registers = (uint32_t *)mem_buf; + int i; + + /* fill in gprs */ + for (i = 0; i < 32; i++) { + env->gpr[i] = tswapl(registers[i]); + } + /* fill in fprs */ + for (i = 0; i < 32; i++) { + *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]); + *((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]); + } + /* nip, msr, ccr, lnk, ctr, xer, mq */ + env->nip = tswapl(registers[96]); + _store_msr(tswapl(registers[97])); + registers[98] = tswapl(registers[98]); + for (i = 0; i < 8; i++) + env->crf[i] = (registers[98] >> (32 - (i * 4))) & 0xF; + env->lr = tswapl(registers[99]); + env->ctr = tswapl(registers[100]); + _store_xer(tswapl(registers[101])); +} #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) -- cgit v1.2.3 From c8135d9af670d091359cb8b03f594c7591f199ec Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 Jan 2004 00:00:25 +0000 Subject: fixed subtle bug: in some cases PG_DIRTY was not set correctly git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@547 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index fcceb1de5..2feccc345 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -348,15 +348,20 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, page_size = 4096; virt_addr = addr & ~0xfff; } + /* the page can be put in the TLB */ prot = PROT_READ; - if (is_user) { - if (pte & PG_RW_MASK) - prot |= PROT_WRITE; - } else { - if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || - (pte & PG_RW_MASK)) - prot |= PROT_WRITE; + if (pte & PG_DIRTY_MASK) { + /* only set write access if already dirty... otherwise wait + for dirty access */ + if (is_user) { + if (pte & PG_RW_MASK) + prot |= PROT_WRITE; + } else { + if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || + (pte & PG_RW_MASK)) + prot |= PROT_WRITE; + } } do_mapping: -- cgit v1.2.3 From 69e5bc90688361772120a1199e7459b8b72a9998 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:37:47 +0000 Subject: generate read error if no image (win XP install boot) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@548 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index a47b809b4..ec4fa7227 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -788,8 +788,12 @@ static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq) } if (fdctrl.data_dir != FD_DIR_WRITE) { /* READ & SCAN commands */ - if (cur_drv->bs == NULL || - bdrv_read(cur_drv->bs, fd_sector(cur_drv), orig, 1) < 0) { + if (cur_drv->bs == NULL) { + fdctrl_stop_transfer(0x40, 0x00, 0x00); + goto transfer_error; + } + + if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), orig, 1) < 0) { FLOPPY_DPRINTF("Floppy: error getting sector %d\n", fd_sector(cur_drv)); /* Sure, image size is too small... */ -- cgit v1.2.3 From 777aca2fd3f7edd6329e343f94401afe99919085 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:39:51 +0000 Subject: fixed dirty bit support for 4M pages (L4 Pistachio fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@549 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 2feccc345..d5c7727cb 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -304,7 +304,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, /* if PSE bit is set, then we use a 4MB page */ if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { is_dirty = is_write && !(pde & PG_DIRTY_MASK); - if (!(pde & PG_ACCESSED_MASK)) { + if (!(pde & PG_ACCESSED_MASK) || is_dirty) { pde |= PG_ACCESSED_MASK; if (is_dirty) pde |= PG_DIRTY_MASK; @@ -363,7 +363,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, prot |= PROT_WRITE; } } - + do_mapping: pte = pte & a20_mask; -- cgit v1.2.3 From 5a1388b6df19d01894e409d00f021334e843dffc Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:41:29 +0000 Subject: xadd fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@550 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index e45b6a438..240773528 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2262,8 +2262,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_TN_reg[ot][0][reg](); gen_op_mov_TN_reg[ot][1][rm](); gen_op_addl_T0_T1(); - gen_op_mov_reg_T0[ot][rm](); gen_op_mov_reg_T1[ot][reg](); + gen_op_mov_reg_T0[ot][rm](); } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_mov_TN_reg[ot][0][reg](); @@ -4561,9 +4561,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32); fprintf(logfile, "\n"); +#if 0 fprintf(logfile, "OP:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); +#endif } #endif -- cgit v1.2.3 From debf7a7c7e16a271b413e886c11224aa9e20f034 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:43:36 +0000 Subject: comments fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@551 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_template.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 5ffde89e4..037c4306a 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -514,7 +514,7 @@ void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) res >>= 1; } T0 = count; - CC_DST = 1; /* ZF = 1 */ + CC_DST = 1; /* ZF = 0 */ } else { CC_DST = 0; /* ZF = 1 */ } @@ -532,7 +532,7 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) res <<= 1; } T0 = count; - CC_DST = 1; /* ZF = 1 */ + CC_DST = 1; /* ZF = 0 */ } else { CC_DST = 0; /* ZF = 1 */ } -- cgit v1.2.3 From 1e4fe7cee25d12d1ecbf9bc2790246b90fede0b1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:44:40 +0000 Subject: fixed potential exception pb on cmpxchg git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@552 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_template_mem.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h index 1b83536c9..ea73c96ca 100644 --- a/target-i386/ops_template_mem.h +++ b/target-i386/ops_template_mem.h @@ -442,12 +442,12 @@ void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) dst = EAX - T0; if ((DATA_TYPE)dst == 0) { T0 = T1; +#ifdef MEM_WRITE + glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); +#endif } else { EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); } -#ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); -#endif CC_SRC = src; CC_DST = dst; FORCE_RET(); -- cgit v1.2.3 From b516f85ca80008bedc3169e22652dcd710008125 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:50:04 +0000 Subject: simpler second page physical address test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@553 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 817200823..f0fa722ca 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -295,8 +295,9 @@ int cpu_exec(CPUState *env1) tb->cs_base == (unsigned long)cs_base && tb->flags == flags) { /* check next page if needed */ - virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK; - if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) { + if (tb->page_addr[1] != -1) { + virt_page2 = ((unsigned long)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; -- cgit v1.2.3 From c4c7e3e61008134419036d830e047e2c649edfea Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:50:28 +0000 Subject: ppc code gen size fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@554 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exec-all.h b/exec-all.h index 7c185e528..d78224a07 100644 --- a/exec-all.h +++ b/exec-all.h @@ -106,7 +106,7 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, /* maximum total translate dcode allocated */ /* NOTE: the translated code area cannot be too big because on some - archs the range of "fast" function calls are limited. Here is a + archs the range of "fast" function calls is limited. Here is a summary of the ranges: i386 : signed 32 bits @@ -119,7 +119,7 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, #if defined(__alpha__) #define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024) #elif defined(__powerpc__) -#define CODE_GEN_BUFFER_SIZE (6 * 1024) +#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024) #else #define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024) #endif -- cgit v1.2.3 From 988578886e0b9af507a7ef111f549c5dd47d93f3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:52:14 +0000 Subject: fixed tlb invalidation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@555 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/exec.c b/exec.c index a68771256..3ae2f31a9 100644 --- a/exec.c +++ b/exec.c @@ -36,6 +36,7 @@ /* make various TB consistency checks */ //#define DEBUG_TB_CHECK +//#define DEBUG_TLB_CHECK /* threshold to flush the translated code buffer */ #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) @@ -766,12 +767,26 @@ void tb_link(TranslationBlock *tb) /* save the code memory mappings (needed to invalidate the code) */ addr = tb->pc & TARGET_PAGE_MASK; vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); +#ifdef DEBUG_TLB_CHECK + if (vp->valid_tag == virt_valid_tag && + vp->phys_addr != tb->page_addr[0]) { + printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n", + addr, tb->page_addr[0], vp->phys_addr); + } +#endif vp->phys_addr = tb->page_addr[0]; vp->valid_tag = virt_valid_tag; if (tb->page_addr[1] != -1) { addr += TARGET_PAGE_SIZE; vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); +#ifdef DEBUG_TLB_CHECK + if (vp->valid_tag == virt_valid_tag && + vp->phys_addr != tb->page_addr[1]) { + printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n", + addr, tb->page_addr[1], vp->phys_addr); + } +#endif vp->phys_addr = tb->page_addr[1]; vp->valid_tag = virt_valid_tag; } @@ -1057,6 +1072,7 @@ void tlb_flush_page(CPUState *env, uint32_t addr) tb = tb->page_next[n]; } } + vp->valid_tag = 0; } #if !defined(CONFIG_SOFTMMU) @@ -1069,7 +1085,8 @@ static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr) { if (addr == (tlb_entry->address & (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && - (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { + (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE && + (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) { tlb_entry->address |= IO_MEM_CODE; tlb_entry->addend -= (unsigned long)phys_ram_base; } @@ -1139,7 +1156,7 @@ static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr) tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr); } -/* add a new TLB entry. At most a single entry for a given virtual +/* add a new TLB entry. At most one entry for a given virtual address is permitted. */ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, int is_user, int is_softmmu) -- cgit v1.2.3 From 6986f88c3f9694752b254f5d7ac92d7e6def635a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:53:18 +0000 Subject: cast to return type git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@556 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_template.h | 1 + 1 file changed, 1 insertion(+) diff --git a/softmmu_template.h b/softmmu_template.h index 2dad910bf..2d3db62f6 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -162,6 +162,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, #else res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift)); #endif + res = (DATA_TYPE)res; } else { /* unaligned/aligned access in the same page */ res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); -- cgit v1.2.3 From 6e44ba7fa22389896be6c21b68b53778a0775821 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:56:49 +0000 Subject: cmos return current date - current irq priority in PIC (L4 Pistachio support) - help fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@557 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 193 +++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 125 insertions(+), 68 deletions(-) diff --git a/vl.c b/vl.c index c8a065225..6c43a58e1 100644 --- a/vl.c +++ b/vl.c @@ -525,6 +525,28 @@ void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) } } +static inline int to_bcd(int a) +{ + return ((a / 10) << 4) | (a % 10); +} + +static void cmos_update_time(void) +{ + struct tm *tm; + time_t ti; + + ti = time(NULL); + tm = gmtime(&ti); + cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); + cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); + cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); + cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); + cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); + cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); + cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); + cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); +} + uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) { int ret; @@ -532,17 +554,32 @@ uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) if (addr == 0x70) { return 0xff; } else { - ret = cmos_data[cmos_index]; switch(cmos_index) { + case RTC_SECONDS: + case RTC_MINUTES: + case RTC_HOURS: + case RTC_DAY_OF_WEEK: + case RTC_DAY_OF_MONTH: + case RTC_MONTH: + case RTC_YEAR: + case REG_IBM_CENTURY_BYTE: + cmos_update_time(); + ret = cmos_data[cmos_index]; + break; case RTC_REG_A: + ret = cmos_data[cmos_index]; /* toggle update-in-progress bit for Linux (same hack as plex86) */ cmos_data[RTC_REG_A] ^= 0x80; break; case RTC_REG_C: + ret = cmos_data[cmos_index]; pic_set_irq(8, 0); cmos_data[RTC_REG_C] = 0x00; break; + default: + ret = cmos_data[cmos_index]; + break; } #ifdef DEBUG_CMOS printf("cmos: read index=0x%02x val=0x%02x\n", @@ -552,27 +589,11 @@ uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) } } - -static inline int to_bcd(int a) -{ - return ((a / 10) << 4) | (a % 10); -} - void cmos_init(void) { - struct tm *tm; - time_t ti; int val; - ti = time(NULL); - tm = gmtime(&ti); - cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); - cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); - cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); - cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); - cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); - cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); - cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); + cmos_update_time(); cmos_data[RTC_REG_A] = 0x26; cmos_data[RTC_REG_B] = 0x02; @@ -580,7 +601,6 @@ void cmos_init(void) cmos_data[RTC_REG_D] = 0x80; /* various important CMOS locations needed by PC/Bochs bios */ - cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ @@ -676,14 +696,15 @@ typedef struct PicState { uint8_t irr; /* interrupt request register */ uint8_t imr; /* interrupt mask register */ uint8_t isr; /* interrupt service register */ - uint8_t priority_add; /* used to compute irq priority */ + uint8_t priority_add; /* highest irq priority */ uint8_t irq_base; uint8_t read_reg_select; uint8_t poll; uint8_t special_mask; uint8_t init_state; uint8_t auto_eoi; - uint8_t rotate_on_autoeoi; + uint8_t rotate_on_auto_eoi; + uint8_t special_fully_nested_mode; uint8_t init4; /* true if 4 byte init */ } PicState; @@ -705,14 +726,16 @@ static inline void pic_set_irq1(PicState *s, int irq, int level) } } +/* return the highest priority found in mask (highest = smallest + number). Return 8 if no irq */ static inline int get_priority(PicState *s, int mask) { int priority; if (mask == 0) - return -1; - priority = 7; + return 8; + priority = 0; while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) - priority--; + priority++; return priority; } @@ -723,13 +746,18 @@ static int pic_get_irq(PicState *s) mask = s->irr & ~s->imr; priority = get_priority(s, mask); - if (priority < 0) + if (priority == 8) return -1; - /* compute current priority */ - cur_priority = get_priority(s, s->isr); - if (priority > cur_priority) { + /* compute current priority. If special fully nested mode on the + master, the IRQ coming from the slave is not taken into account + for the priority computation. */ + mask = s->isr; + if (s->special_fully_nested_mode && s == &pics[0]) + mask &= ~(1 << 2); + cur_priority = get_priority(s, mask); + if (priority < cur_priority) { /* higher priority found: an irq should be generated */ - return priority; + return (priority + s->priority_add) & 7; } else { return -1; } @@ -758,6 +786,17 @@ void pic_update_irq(void) /* from master pic */ pic_irq_requested = irq; } +#if defined(DEBUG_PIC) + { + int i; + for(i = 0; i < 2; i++) { + printf("pic%d: imr=%x irr=%x padd=%d\n", + i, pics[i].imr, pics[i].irr, pics[i].priority_add); + + } + } + printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); +#endif cpu_interrupt(global_env, CPU_INTERRUPT_HARD); } } @@ -787,6 +826,18 @@ void pic_set_irq(int irq, int level) pic_update_irq(); } +/* acknowledge interrupt 'irq' */ +static inline void pic_intack(PicState *s, int irq) +{ + if (s->auto_eoi) { + if (s->rotate_on_auto_eoi) + s->priority_add = (irq + 1) & 7; + } else { + s->isr |= (1 << irq); + } + s->irr &= ~(1 << irq); +} + int cpu_x86_get_pic_interrupt(CPUState *env) { int irq, irq2, intno; @@ -804,22 +855,20 @@ int cpu_x86_get_pic_interrupt(CPUState *env) if (irq >= 8) { irq2 = irq & 7; - pics[1].isr |= (1 << irq2); - pics[1].irr &= ~(1 << irq2); + pic_intack(&pics[1], irq2); irq = 2; intno = pics[1].irq_base + irq2; } else { intno = pics[0].irq_base + irq; } - pics[0].isr |= (1 << irq); - pics[0].irr &= ~(1 << irq); + pic_intack(&pics[0], irq); return intno; } void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) { PicState *s; - int priority; + int priority, cmd, irq; #ifdef DEBUG_PIC printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); @@ -837,45 +886,48 @@ void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) if (val & 0x08) hw_error("level sensitive irq not supported"); } else if (val & 0x08) { - if (val & 0x04) { + if (val & 0x04) s->poll = 1; - } else { if (val & 0x02) s->read_reg_select = val & 1; if (val & 0x40) s->special_mask = (val >> 5) & 1; - } } else { - switch(val) { - case 0x00: - case 0x80: - s->rotate_on_autoeoi = val >> 7; + cmd = val >> 5; + switch(cmd) { + case 0: + case 4: + s->rotate_on_auto_eoi = cmd >> 2; break; - case 0x20: /* end of interrupt */ - case 0xa0: + case 1: /* end of interrupt */ + case 5: priority = get_priority(s, s->isr); - if (priority >= 0) { - s->isr &= ~(1 << ((priority + s->priority_add) & 7)); + if (priority != 8) { + irq = (priority + s->priority_add) & 7; + s->isr &= ~(1 << irq); + if (cmd == 5) + s->priority_add = (irq + 1) & 7; + pic_update_irq(); } - if (val == 0xa0) - s->priority_add = (s->priority_add + 1) & 7; - pic_update_irq(); break; - case 0x60 ... 0x67: - priority = val & 7; - s->isr &= ~(1 << priority); + case 3: + irq = val & 7; + s->isr &= ~(1 << irq); pic_update_irq(); break; - case 0xc0 ... 0xc7: + case 6: s->priority_add = (val + 1) & 7; pic_update_irq(); break; - case 0xe0 ... 0xe7: - priority = val & 7; - s->isr &= ~(1 << priority); - s->priority_add = (priority + 1) & 7; + case 7: + irq = val & 7; + s->isr &= ~(1 << irq); + s->priority_add = (irq + 1) & 7; pic_update_irq(); break; + default: + /* no operation */ + break; } } } else { @@ -897,6 +949,7 @@ void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } break; case 3: + s->special_fully_nested_mode = (val >> 4) & 1; s->auto_eoi = (val >> 1) & 1; s->init_state = 0; break; @@ -935,18 +988,18 @@ uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) addr = addr1; s = &pics[addr >> 7]; addr &= 1; - if (s->poll == 1) { + if (s->poll) { ret = pic_poll_read(s, addr1); s->poll = 0; } else { - if (addr == 0) { - if (s->read_reg_select) - ret = s->isr; - else - ret = s->irr; - } else { - ret = s->imr; - } + if (addr == 0) { + if (s->read_reg_select) + ret = s->isr; + else + ret = s->irr; + } else { + ret = s->imr; + } } #ifdef DEBUG_PIC printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); @@ -1729,6 +1782,9 @@ void serial_received_byte(SerialState *s, int ch) fflush(stdout); term_command = 1; break; + case 'd': + cpu_set_log(CPU_LOG_ALL); + break; case TERM_ESCAPE: goto send_char; } @@ -3180,7 +3236,7 @@ void help(void) "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom 2 image\n" - "-boot [c|d] boot on hard disk (c) or CD-ROM (d)\n" + "-boot [a|b|c|d] boot on floppy (a, b), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB\n" "-n script set network init script [default=%s]\n" @@ -3195,7 +3251,7 @@ void help(void) "Debug/Expert options:\n" "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" - "-d output log in /tmp/vl.log\n" + "-d output log to %s\n" "-hdachs c,h,s force hard disk 0 geometry (usually qemu can guess it)\n" "-L path set the directory for the BIOS and VGA BIOS\n" "\n" @@ -3206,7 +3262,8 @@ void help(void) "qemu-fast", #endif DEFAULT_NETWORK_SCRIPT, - DEFAULT_GDBSTUB_PORT); + DEFAULT_GDBSTUB_PORT, + "/tmp/qemu.log"); term_print_help(); #ifndef CONFIG_SOFTMMU printf("\n" -- cgit v1.2.3 From d575b78aabd7579959cc089cc993960709b5bb33 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 21:57:29 +0000 Subject: more xadd tests - cmpxchg8b test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@558 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 0718f5a0e..086ff2887 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -832,6 +832,13 @@ void test_xchg(void) TEST_XCHG(xaddw, "w", "=q"); TEST_XCHG(xaddb, "b", "=q"); + { + int res; + res = 0x12345678; + asm("xaddl %1, %0" : "=r" (res) : "0" (res)); + printf("xaddl same res=%08x\n", res); + } + TEST_XCHG(xaddl, "", "=m"); TEST_XCHG(xaddw, "w", "=m"); TEST_XCHG(xaddb, "b", "=m"); @@ -851,6 +858,27 @@ void test_xchg(void) TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfffefdfc); TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc); TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc); + + { + uint64_t op0, op1, op2; + int i, eflags; + + for(i = 0; i < 2; i++) { + op0 = 0x123456789abcd; + if (i == 0) + op1 = 0xfbca765423456; + else + op1 = op0; + op2 = 0x6532432432434; + asm("cmpxchg8b %1\n" + "pushf\n" + "popl %2\n" + : "=A" (op0), "=m" (op1), "=g" (eflags) + : "0" (op0), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32))); + printf("cmpxchg8b: op0=%016llx op1=%016llx CC=%02x\n", + op0, op1, eflags & CC_Z); + } + } } /**********************************************/ -- cgit v1.2.3 From 44a91cae103d8c6f76236da1531aa0e65b858f38 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:05:44 +0000 Subject: suppressed cast to lvalue git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@559 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 9999268ea..f2970f88d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -386,10 +386,12 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, --p; --tmp; --len; if (--offset < 0) { offset = p % TARGET_PAGE_SIZE; - if (!(pag = (char *) page[p/TARGET_PAGE_SIZE]) && - !(pag = (char *) page[p/TARGET_PAGE_SIZE] = - (unsigned long *) get_free_page())) { - return 0; + pag = (char *) page[p/TARGET_PAGE_SIZE]; + if (!pag) { + pag = (char *)get_free_page(); + page[p/TARGET_PAGE_SIZE] = (unsigned long)pag; + if (!pag) + return 0; } } if (len == 0 || offset == 0) { -- cgit v1.2.3 From 630be16f6c663de0b39eb36dd5ebfe0aa4efbc6b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:06:47 +0000 Subject: alpha fix (Falk Hueffner) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@560 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dyngen.c b/dyngen.c index 390fc3a8a..89e98245b 100644 --- a/dyngen.c +++ b/dyngen.c @@ -485,8 +485,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { 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; -- cgit v1.2.3 From bc0b1dc1eb30b729dc9cd5ee218370162033afaa Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:19:31 +0000 Subject: sb16 patch (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@561 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sb16.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/hw/sb16.c b/hw/sb16.c index 5644db4a1..b04110d9e 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -37,6 +37,7 @@ abort (); \ } while (0) +/* #define DEBUG_SB16 */ #ifdef DEBUG_SB16 #define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__) #define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__) @@ -60,7 +61,7 @@ static struct { int hdma; int port; int mix_block; -} sb = {4, 5, 5, 1, 5, 0x220, -1}; +} sb = {5, 4, 5, 1, 5, 0x220, -1}; static int mix_block, noirq; @@ -205,7 +206,7 @@ static void command (uint8_t cmd) { char *msg; - msg = (char *)-1; + msg = (char *) -1; linfo ("%#x\n", cmd); @@ -225,6 +226,12 @@ static void command (uint8_t cmd) } else { switch (cmd) { + case 0x00: + case 0x03: + case 0xe7: + /* IMS uses those when probing for sound devices */ + return; + case 0x10: dsp.needed_bytes = 1; break; @@ -328,7 +335,7 @@ static void command (uint8_t cmd) case 0xf2: dsp.out_data[dsp.out_data_len++] = 0xaa; - mixer.regs[0x82] |= 1; + mixer.regs[0x82] |= mixer.regs[0x80]; pic_set_irq (sb.irq, 1); return; @@ -500,13 +507,19 @@ static IO_READ_PROTO (dsp_read) goto error; case 0xe: /* data available status | irq 8 ack */ + /* XXX drop pic irq line here? */ + ldebug ("8 ack\n"); retval = (0 == dsp.out_data_len) ? 0 : 0x80; + mixer.regs[0x82] &= ~mixer.regs[0x80]; + pic_set_irq (sb.irq, 0); break; case 0xf: /* irq 16 ack */ - retval = 0xff; - mixer.regs[0x82] &= ~2; + /* XXX drop pic irq line here? */ ldebug ("16 ack\n"); + retval = 0xff; + mixer.regs[0x82] &= ~mixer.regs[0x80]; + pic_set_irq (sb.irq, 0); break; default: @@ -514,8 +527,8 @@ static IO_READ_PROTO (dsp_read) } if ((0xc != iport) && (0xe != iport)) { - ldebug ("(nport=%#x, size=%d) iport %#x = %#x\n", - nport, size, iport, retval); + ldebug ("nport=%#x iport %#x = %#x\n", + nport, iport, retval); } return retval; @@ -617,8 +630,6 @@ static int SB_read_DMA (uint32_t addr, int size, int *_irq) ldebug ("addr:%#010x free:%d till:%d size:%d\n", addr, free, till, size); -/* linfo ("pos %d free %d size %d till %d copy %d auto %d noirq %d\n", */ -/* dsp.dma_pos, free, size, till, copy, dsp.dma_auto, noirq); */ if (till <= copy) { if (0 == dsp.dma_auto) { copy = till; @@ -631,8 +642,10 @@ static int SB_read_DMA (uint32_t addr, int size, int *_irq) if (dsp.left_till_irq <= 0) { mixer.regs[0x82] |= mixer.regs[0x80]; - if (0 == noirq) + if (0 == noirq) { + ldebug ("request irq\n"); *_irq = sb.irq; + } if (0 == dsp.dma_auto) { control (0); -- cgit v1.2.3 From 825bd5f8e5dfe4f521e1dcbce91e7d37b263d65d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:25:49 +0000 Subject: temporary gcc 3.3 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@562 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target-i386/op.c b/target-i386/op.c index 34fc4c734..46e75e192 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -19,8 +19,12 @@ */ /* XXX: must use this define because the soft mmu macros have huge - register constraints so they cannot be used in any C code */ + register constraints so they cannot be used in any C code. gcc 3.3 + does not seem to be able to handle some constraints in rol + operations, so we disable it. */ +#if !(__GNUC__ == 3 && __GNUC_MINOR__ == 3) #define ASM_SOFTMMU +#endif #include "exec.h" /* n must be a constant to be efficient */ -- cgit v1.2.3 From d030931173a2d8c9038c45950d72900097013ecb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:35:25 +0000 Subject: automatic floppy boot git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@563 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 6c43a58e1..7b52203a7 100644 --- a/vl.c +++ b/vl.c @@ -3461,8 +3461,12 @@ int main(int argc, char **argv) help(); /* boot to cd by default if no hard disk */ - if (hd_filename[0] == '\0' && boot_device == 'c') - boot_device = 'd'; + if (hd_filename[0] == '\0' && boot_device == 'c') { + if (fd_filename[0] != '\0') + boot_device = 'a'; + else + boot_device = 'd'; + } #if !defined(CONFIG_SOFTMMU) /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ -- cgit v1.2.3 From f09936ac82b3c56a0a36a533dd3f63d08e013e7d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:39:25 +0000 Subject: ARM fcntl flag fixes (Lennert Buytenhek) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@564 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall_defs.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 4e36a222d..a05b6f679 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -905,7 +905,25 @@ struct target_stat64 { #define TARGET_F_SETLK64 13 #define TARGET_F_SETLKW64 14 -#if defined (TARGET_PPC) +#if defined (TARGET_ARM) +#define TARGET_O_ACCMODE 0003 +#define TARGET_O_RDONLY 00 +#define TARGET_O_WRONLY 01 +#define TARGET_O_RDWR 02 +#define TARGET_O_CREAT 0100 /* not fcntl */ +#define TARGET_O_EXCL 0200 /* not fcntl */ +#define TARGET_O_NOCTTY 0400 /* not fcntl */ +#define TARGET_O_TRUNC 01000 /* not fcntl */ +#define TARGET_O_APPEND 02000 +#define TARGET_O_NONBLOCK 04000 +#define TARGET_O_NDELAY O_NONBLOCK +#define TARGET_O_SYNC 010000 +#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ +#define TARGET_O_DIRECTORY 040000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */ +#define TARGET_O_DIRECT 0200000 /* direct disk access hint */ +#define TARGET_O_LARGEFILE 0400000 +#elif defined (TARGET_PPC) #define TARGET_O_ACCMODE 0003 #define TARGET_O_RDONLY 00 #define TARGET_O_WRONLY 01 -- cgit v1.2.3 From 3f5dcc340c1e4fa8a49066e30cf980bafdb3ecf4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:44:01 +0000 Subject: PowerPC merge (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@565 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 6 ++++++ translate-all.c | 3 +-- vl.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/exec-all.h b/exec-all.h index d78224a07..fa407e94a 100644 --- a/exec-all.h +++ b/exec-all.h @@ -541,7 +541,13 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) int is_user, index; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); +#if defined(TARGET_I386) is_user = ((env->hflags & HF_CPL_MASK) == 3); +#elif defined (TARGET_PPC) + is_user = msr_pr; +#else +#error "Unimplemented !" +#endif if (__builtin_expect(env->tlb_read[is_user][index].address != (addr & TARGET_PAGE_MASK), 0)) { ldub_code((void *)addr); diff --git a/translate-all.c b/translate-all.c index c8f345735..108a21f26 100644 --- a/translate-all.c +++ b/translate-all.c @@ -119,7 +119,7 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, gen_opc_buf, gen_opparam_buf); *gen_code_size_ptr = gen_code_size; #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel && 0) { fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0); fprintf(logfile, "\n"); @@ -203,7 +203,6 @@ int cpu_restore_state(TranslationBlock *tb, case INDEX_op_ ## op ## _raw #else #define CASE3(op)\ - case INDEX_op_ ## op ## _raw:\ case INDEX_op_ ## op ## _user:\ case INDEX_op_ ## op ## _kernel #endif diff --git a/vl.c b/vl.c index 7b52203a7..cc49e333b 100644 --- a/vl.c +++ b/vl.c @@ -85,7 +85,7 @@ #define KERNEL_LOAD_ADDR 0x00100000 #elif defined (TARGET_PPC) //#define USE_OPEN_FIRMWARE -#if defined (USE_OPEN_FIRMWARE) +#if !defined (USE_OPEN_FIRMWARE) #define KERNEL_LOAD_ADDR 0x01000000 #define KERNEL_STACK_ADDR 0x01200000 #else -- cgit v1.2.3 From 985a19d6d1d7ab3705bf42698cc95abfbbfa24f8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:49:57 +0000 Subject: PowerPC merge (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@566 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 7 ------- target-ppc/op_helper.c | 6 +++++- target-ppc/op_mem.h | 13 +++++++++++++ target-ppc/translate.c | 11 +++++++++-- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 28722d650..98d788585 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -453,13 +453,6 @@ PPC_OP(reset_scrfx) RETURN(); } -/* Set reservation */ -PPC_OP(set_reservation) -{ - regs->reserve = T0 & ~0x03; - RETURN(); -} - /* crf operations */ PPC_OP(getbit_T0) { diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5d02dfabe..a0e936028 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -349,9 +349,13 @@ void do_fnabs (void) } /* Instruction cache invalidation helper */ +#define ICACHE_LINE_SIZE 32 + void do_icbi (void) { - // tb_invalidate_page(T0); + /* Invalidate one cache line */ + T0 &= ~(ICACHE_LINE_SIZE - 1); + tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE); } /* TLB invalidation helpers */ diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index e66a1dbe0..01df45d9c 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -134,6 +134,19 @@ PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ PPC_LDF_OP(fd, ldfq); PPC_LDF_OP(fs, ldfl); +/* Load and set reservation */ +PPC_OP(glue(lwarx, MEMSUFFIX)) +{ + if (T0 & 0x03) { + do_queue_exception(EXCP_ALIGN); + do_process_exceptions(); + } else { + glue(ldl, MEMSUFFIX)((void *)T0); + regs->reserve = T0 & ~0x03; + } + RETURN(); +} + /* Store with reservation */ PPC_OP(glue(stwcx, MEMSUFFIX)) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 34f92bd16..9ad8f6dea 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1302,8 +1302,14 @@ GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM) /* lwarx */ #if defined(CONFIG_USER_ONLY) +#define op_lwarx() gen_op_lwarx_raw() #define op_stwcx() gen_op_stwcx_raw() #else +#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])() +static GenOpFunc *gen_op_lwarx[] = { + &gen_op_lwarx_user, + &gen_op_lwarx_kernel, +}; #define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])() static GenOpFunc *gen_op_stwcx[] = { &gen_op_stwcx_user, @@ -1320,9 +1326,8 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES) gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_add(); } - op_ldst(lwz); + op_lwarx(); gen_op_store_T1_gpr(rD(ctx->opcode)); - gen_op_set_reservation(); } /* stwcx. */ @@ -3169,9 +3174,11 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, while (lj <= j) gen_opc_instr_start[lj++] = 0; tb->size = 0; +#if 0 if (loglevel > 0) { page_dump(logfile); } +#endif } else { tb->size = (uint32_t)ctx.nip - pc_start; } -- cgit v1.2.3 From c27357906a339eb55e600efc71aef3f7617cb277 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 22:55:23 +0000 Subject: avoid exiting directly if file not found git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@567 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index f2970f88d..71055255c 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1284,14 +1284,9 @@ int elf_exec(const char * filename, char ** argv, char ** envp, for (i=0 ; i Date: Sun, 18 Jan 2004 23:14:25 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@568 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 ++++ TODO | 14 +++++++------- qemu-doc.texi | 13 +++++++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Changelog b/Changelog index 9cddb49cc..9952f363a 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,5 @@ version 0.5.2: + - improved soft MMU speed (assembly functions and specializing) - improved multitasking speed by avoiding flushing TBs when switching tasks @@ -15,6 +16,9 @@ version 0.5.2: - 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 version 0.5.1: diff --git a/TODO b/TODO index d483eb4d7..9d7ed03f8 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,12 @@ -before 0.5.2: ------------- - -- TLB code protection support -- basic VGA optimizations -- disable SMC handling for ARM/SPARC/PPC - short term: ---------- +- XP install bug fix +- L4 Pistachio kernel boot fix +- TLB code protection support for PPC +- add sysenter/sysexit and fxsr for L4 pistachio 686 +- basic VGA optimizations +- disable SMC handling for ARM/SPARC/PPC +- see undefined flags for BTx insn - user/kernel PUSHL/POPL in helper.c - keyboard output buffer filling timing emulation - verify tb_flush() with a20 and TLBs diff --git a/qemu-doc.texi b/qemu-doc.texi index c0a5bd048..f4a69c272 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -26,7 +26,7 @@ User mode emulation. In this mode, QEMU can launch Linux processes compiled for one CPU on another CPU. Linux system calls are converted because of endianness and 32/64 bit mismatches. The Wine Windows API emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator -(@url{www.dosemu.org}) are the main targets for QEMU. +(@url{http://www.dosemu.org}) are the main targets for QEMU. @item Full system emulation. In this mode, QEMU emulates a full @@ -472,18 +472,23 @@ usage: qemu [options] [disk_image] General options: @table @option +@item -fda file +@item -fdb file +Use @var{file} as floppy disk 0/1 image (@xref{disk_images}). + @item -hda file @item -hdb file @item -hdc file @item -hdd file -Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}). +Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}). @item -cdrom file Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and @option{-cdrom} at the same time). -@item -boot [c|d] -Boot on hard disk (c) or CD-ROM (d). Hard disk boot is the default. +@item -boot [a|b|c|d] +Boot on floppy (a, b), hard disk (c) or CD-ROM (d). Hard disk boot is +the default. @item -snapshot Write to temporary files instead of disk image files. In this case, -- cgit v1.2.3 From 7f957d280b8054d5134b5807b13205b33868426b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Jan 2004 23:19:48 +0000 Subject: PowerPC merge (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@569 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index f0fa722ca..bd0cbb35e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -597,7 +597,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_ppc_handle_mmu_fault(env, address, is_write | ACCESS_INT, msr_pr, 0); + 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) -- cgit v1.2.3 From 4120b61d000117bf016dead1443682c74838227f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Jan 2004 20:29:34 +0000 Subject: test at least one invalid lock op code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@570 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 086ff2887..b0c2af855 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1379,6 +1379,11 @@ void test_exceptions(void) /* now execute an invalid instruction */ asm volatile("ud2"); } + printf("lock nop exception:\n"); + if (setjmp(jmp_env) == 0) { + /* now execute an invalid instruction */ + asm volatile("lock nop"); + } printf("INT exception:\n"); if (setjmp(jmp_env) == 0) { -- cgit v1.2.3 From ab1f142ba0b667679ea2ed55598f22551c19dac4 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Jan 2004 20:31:37 +0000 Subject: L4 fix for rep nop (should handle all cases) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@571 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index 240773528..cec9a425a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3732,6 +3732,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* misc */ case 0x90: /* nop */ + /* XXX: correct lock test for all insn */ + if (prefixes & PREFIX_LOCK) + goto illegal_op; break; case 0x9b: /* fwait */ break; @@ -4137,6 +4140,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_unlock(); return s->pc; illegal_op: + if (s->prefix & PREFIX_LOCK) + gen_op_unlock(); /* XXX: ensure that no lock was generated */ gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); return s->pc; -- cgit v1.2.3 From 3504fe171b62bb0362191e1fd66538ff7c4f4210 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Jan 2004 21:11:02 +0000 Subject: 16 bit DMA fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@572 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index a1e77f591..ee7cc42ec 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -136,7 +136,7 @@ static uint32_t read_chan (CPUState *env, uint32_t nport) return (val >> (ncont + (ff << 3))) & 0xff; } -static void write_chan (uint32_t nport, int size, uint32_t data) +static void write_chan (CPUState *env, uint32_t nport, uint32_t data) { int ncont, ichan, nreg; struct dma_regs *r; @@ -146,28 +146,12 @@ static void write_chan (uint32_t nport, int size, uint32_t data) nreg = (nport >> ncont) & 1; r = dma_controllers[ncont].regs + ichan; - if (2 == size) { - r->base[nreg] = data; + if (getff (ncont)) { + r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00); init_chan (ncont, ichan); + } else { + r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff); } - else { - if (getff (ncont)) { - r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00); - init_chan (ncont, ichan); - } - else { - r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff); - } - } -} -static void write_chanb (CPUState *env, uint32_t nport, uint32_t data) -{ - write_chan (nport, 1, data); -} - -static void write_chanw (CPUState *env, uint32_t nport, uint32_t data) -{ - write_chan (nport, 2, data); } static void write_cont (CPUState *env, uint32_t nport, uint32_t data) @@ -370,14 +354,12 @@ void DMA_init (void) int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; for (i = 0; i < 8; i++) { - register_ioport_write (i, 1, write_chanb, 1); - register_ioport_write (i, 1, write_chanw, 2); + register_ioport_write (i, 1, write_chan, 1); - register_ioport_write (0xc0 + (i << 1), 1, write_chanb, 1); - register_ioport_write (0xc0 + (i << 1), 1, write_chanw, 2); + register_ioport_write (0xc0 + (i << 1), 1, write_chan, 1); register_ioport_read (i, 1, read_chan, 1); - register_ioport_read (0xc0 + (i << 1), 1, read_chan, 2); + register_ioport_read (0xc0 + (i << 1), 1, read_chan, 1); } for (i = 0; i < LENOFA (page_port_list); i++) { @@ -390,6 +372,6 @@ void DMA_init (void) register_ioport_write (0xd0 + (i << 1), 1, write_cont, 1); } - write_cont (NULL, 0xd, 0); - write_cont (NULL, 0xdd, 0); + write_cont (NULL, 0x0d, 0); + write_cont (NULL, 0xda, 0); } -- cgit v1.2.3 From 4796f5e9bc5efc46d0149bae57b530afd26ff65d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Jan 2004 23:46:39 +0000 Subject: interrupt to conforming segment fix (QNX boot fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@573 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-i386/helper.c b/target-i386/helper.c index 071169827..320e09a75 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -686,6 +686,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, sp_mask = get_sp_mask(env->segs[R_SS].flags); ssp = env->segs[R_SS].base; esp = ESP; + dpl = cpl; } else { raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; /* avoid warning */ -- cgit v1.2.3 From a136e5a8b176bfd3ba687769ed999c55782f2584 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 22 Jan 2004 23:52:27 +0000 Subject: ATAPI transfer size fix (NetBSD CDROM access fix) - added WIN_CHECKPOWERMODE1 - set error to zero in some cases git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@574 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 480a7be6d..794572109 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -550,6 +550,7 @@ static void ide_sector_read(IDEState *s) int ret, n; s->status = READY_STAT | SEEK_STAT; + s->error = 0; /* not needed by IDE spec, but needed by Windows */ sector_num = ide_get_sector(s); n = s->nsector; if (n == 0) { @@ -694,10 +695,9 @@ static void ide_atapi_cmd_reply_end(IDEState *s) if (byte_count_limit & 1) byte_count_limit--; size = byte_count_limit; - } else { - s->lcyl = size; - s->hcyl = size >> 8; } + s->lcyl = size; + s->hcyl = size >> 8; s->elementary_transfer_size = size; /* we cannot transmit more than one sector at a time */ if (s->lba != -1) { @@ -1106,6 +1106,7 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val) break; case WIN_SPECIFY: case WIN_RECAL: + s->error = 0; s->status = READY_STAT; ide_set_irq(s); break; @@ -1135,6 +1136,7 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val) break; case WIN_WRITE: case WIN_WRITE_ONCE: + s->error = 0; s->status = SEEK_STAT; s->req_nb_sectors = 1; ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); @@ -1148,6 +1150,7 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val) case WIN_MULTWRITE: if (!s->mult_sectors) goto abort_cmd; + s->error = 0; s->status = SEEK_STAT; s->req_nb_sectors = s->mult_sectors; n = s->nsector; @@ -1160,6 +1163,11 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val) s->status = READY_STAT; ide_set_irq(s); break; + case WIN_CHECKPOWERMODE1: + s->nsector = 0xff; /* device active or idle */ + s->status = READY_STAT; + ide_set_irq(s); + break; /* ATAPI commands */ case WIN_PIDENTIFY: -- cgit v1.2.3 From bb551faa4ac8a798df9757c0ae26893041344bc3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 13:42:26 +0000 Subject: increased physical RAM limit to 2047 MB in soft MMU mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@575 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index cc49e333b..621bbeb88 100644 --- a/vl.c +++ b/vl.c @@ -79,7 +79,11 @@ //#define DEBUG_SERIAL #define PHYS_RAM_BASE 0xac000000 +#if !defined(CONFIG_SOFTMMU) #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) +#else +#define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024) +#endif #if defined (TARGET_I386) #define KERNEL_LOAD_ADDR 0x00100000 @@ -1309,7 +1313,7 @@ static inline void pit_load_count(PITChannelState *s, int val) s->count = val; if (s == &pit_channels[0] && val <= pit_min_timer_count) { fprintf(stderr, - "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.5.xx Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", + "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", PIT_FREQ / pit_min_timer_count); } } -- cgit v1.2.3 From 6c9bf8936a14e8b460cfd074e1a78251a0d85da0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 13:46:56 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@576 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index f4a69c272..5ca8e8f3b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -730,7 +730,7 @@ QEMU has a primitive support to work with gdb, so that you can do In order to use gdb, launch qemu with the '-s' option. It will wait for a gdb connection: @example -> qemu -s arch/i386/boot/bzImage -hda root-2.4.20.img root=/dev/hda +> qemu -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda" Connected to host network interface: tun0 Waiting gdb connection on port 1234 @end example @@ -742,7 +742,7 @@ Then launch gdb on the 'vmlinux' executable: In gdb, connect to QEMU: @example -(gdb) target remote locahost:1234 +(gdb) target remote localhost:1234 @end example Then you can use gdb normally. For example, type 'c' to launch the kernel: -- cgit v1.2.3 From 612b477d48c9c71669d686da9897afc603c71877 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 15:10:18 +0000 Subject: removed warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@577 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 394c2241a..e466e09f8 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -120,7 +120,6 @@ #define EIP (env->pc) #define FLAG_SET(x) (env->psr&x)?1:0 -#define GET_FLAGS unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF), C = FLAG_SET(PSR_CARRY) void OPPROTO op_movl_T0_0(void) { @@ -538,19 +537,22 @@ void OPPROTO op_eval_be(void) void OPPROTO op_eval_ble(void) { - GET_FLAGS; + unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); + T2 = Z | (N ^ V); } void OPPROTO op_eval_bl(void) { - GET_FLAGS; + unsigned int N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); + T2 = N ^ V; } void OPPROTO op_eval_bleu(void) { - GET_FLAGS; + unsigned int Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY); + T2 = C | Z; } @@ -576,19 +578,22 @@ void OPPROTO op_eval_bne(void) void OPPROTO op_eval_bg(void) { - GET_FLAGS; + unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); + T2 = !(Z | (N ^ V)); } void OPPROTO op_eval_bge(void) { - GET_FLAGS; + unsigned int N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); + T2 = !(N ^ V); } void OPPROTO op_eval_bgu(void) { - GET_FLAGS; + unsigned int Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY); + T2 = !(C | Z); } -- cgit v1.2.3 From edfcbd99373f44d61980d731a9e176591a85f420 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 15:11:05 +0000 Subject: added cpu_get_phys_page_debug() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@578 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 82bd33c8e..f9c28d080 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -841,3 +841,8 @@ void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags) GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), env->wim); } + +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} -- cgit v1.2.3 From a6b025d37d13fffe6f2bc0b5fc8d88503348eeb7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 15:18:16 +0000 Subject: added cpu_get_phys_page_debug() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@579 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 5 +++++ target-ppc/helper.c | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/target-arm/translate.c b/target-arm/translate.c index 44c6387ea..4a3dd3b99 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -897,3 +897,8 @@ void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) env->cpsr & (1 << 29) ? 'C' : '-', env->cpsr & (1 << 28) ? 'V' : '-'); } + +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 1520d6c82..50c480e2b 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -414,6 +414,22 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, return ret; } +#if defined(CONFIG_USER_ONLY) +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} +#else +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint32_t phys_addr; + int prot; + + if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) + return -1; + return phys_addr; +} +#endif #if !defined(CONFIG_USER_ONLY) -- cgit v1.2.3 From 3cf1e035ba16423d1278ac34bea2ec795a9716a3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 15:19:09 +0000 Subject: added TARGET_LONG_BITS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@580 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/cpu.h | 2 ++ target-i386/cpu.h | 2 ++ target-ppc/cpu.h | 2 ++ target-sparc/cpu.h | 4 ++-- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7f755a754..174f60db6 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -20,6 +20,8 @@ #ifndef CPU_ARM_H #define CPU_ARM_H +#define TARGET_LONG_BITS 32 + #include "cpu-defs.h" #define EXCP_UDEF 1 /* undefined instruction */ diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 6be987c51..a93486cbe 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -20,6 +20,8 @@ #ifndef CPU_I386_H #define CPU_I386_H +#define TARGET_LONG_BITS 32 + #include "cpu-defs.h" #define R_EAX 0 diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 850a88ba8..3809f2014 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -23,6 +23,8 @@ #include #include +#define TARGET_LONG_BITS 32 + #include "cpu-defs.h" //#define USE_OPEN_FIRMWARE diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 67fece712..af5ecb508 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -1,8 +1,8 @@ #ifndef CPU_SPARC_H #define CPU_SPARC_H -#include -#include "config.h" +#define TARGET_LONG_BITS 32 + #include "cpu-defs.h" /*#define EXCP_INTERRUPT 0x100*/ -- cgit v1.2.3 From 13eb76e091a302dff848b0001a64d1b571450ccc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 15:23:36 +0000 Subject: virtual memory access for gdbstub git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@581 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 10 +++++ exec.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdbstub.c | 53 ++---------------------- 3 files changed, 152 insertions(+), 49 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 499e1483d..1cf35ea23 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -473,6 +473,11 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc); int cpu_breakpoint_remove(CPUState *env, uint32_t pc); void cpu_single_step(CPUState *env, int enabled); +/* 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_ALL 1 void cpu_set_log(int log_flags); void cpu_set_log_filename(const char *filename); @@ -515,6 +520,11 @@ int cpu_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write); +void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, + int len, int is_write); +int cpu_memory_rw_debug(CPUState *env, + uint8_t *buf, target_ulong addr, int len, int is_write); + /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); diff --git a/exec.c b/exec.c index 3ae2f31a9..9104efbb1 100644 --- a/exec.c +++ b/exec.c @@ -1561,6 +1561,144 @@ int cpu_register_io_memory(int io_index, return io_index << IO_MEM_SHIFT; } +/* physical memory access (slow version, mainly for debug) */ +#if defined(CONFIG_USER_ONLY) +void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, + int len, int is_write) +{ + int l, flags; + target_ulong page; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + flags = page_get_flags(page); + if (!(flags & PAGE_VALID)) + return; + if (is_write) { + if (!(flags & PAGE_WRITE)) + return; + memcpy((uint8_t *)addr, buf, len); + } else { + if (!(flags & PAGE_READ)) + return; + memcpy(buf, (uint8_t *)addr, len); + } + len -= l; + buf += l; + addr += l; + } +} +#else +void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, + int len, int is_write) +{ + int l, io_index; + uint8_t *ptr; + uint32_t val; + target_ulong page, pd; + PageDesc *p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = page_find(page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if (is_write) { + if ((pd & ~TARGET_PAGE_MASK) != 0) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (l >= 4 && ((addr & 3) == 0)) { + /* 32 bit read access */ + val = ldl_raw(buf); + io_mem_write[io_index][2](addr, val); + l = 4; + } else if (l >= 2 && ((addr & 1) == 0)) { + /* 16 bit read access */ + val = lduw_raw(buf); + io_mem_write[io_index][1](addr, val); + l = 2; + } else { + /* 8 bit access */ + val = ldub_raw(buf); + io_mem_write[io_index][0](addr, val); + l = 1; + } + } else { + /* RAM case */ + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + memcpy(ptr, buf, l); + } + } else { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + if (l >= 4 && ((addr & 3) == 0)) { + /* 32 bit read access */ + val = io_mem_read[io_index][2](addr); + stl_raw(buf, val); + l = 4; + } else if (l >= 2 && ((addr & 1) == 0)) { + /* 16 bit read access */ + val = io_mem_read[io_index][1](addr); + stw_raw(buf, val); + l = 2; + } else { + /* 8 bit access */ + val = io_mem_read[io_index][0](addr); + stb_raw(buf, val); + l = 1; + } + } else { + /* RAM case */ + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + memcpy(buf, ptr, l); + } + } + len -= l; + buf += l; + addr += l; + } +} +#endif + +/* virtual memory access for debug */ +int cpu_memory_rw_debug(CPUState *env, + uint8_t *buf, target_ulong addr, int len, int is_write) +{ + int l; + target_ulong page, phys_addr; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + phys_addr = cpu_get_phys_page_debug(env, page); + /* if no physical page mapped, return an error */ + if (phys_addr == -1) + return -1; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + cpu_physical_memory_rw(env, buf, + phys_addr + (addr & ~TARGET_PAGE_MASK), l, + is_write); + len -= l; + buf += l; + addr += l; + } + return 0; +} + #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _cmmu diff --git a/gdbstub.c b/gdbstub.c index 469a15962..4fa4af79a 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -248,53 +248,6 @@ static int put_packet(char *buf) return 0; } -/* better than nothing for SOFTMMU : we use physical addresses */ -#if !defined(CONFIG_USER_ONLY) -static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) -{ - uint8_t *ptr; - - if (addr >= phys_ram_size || - ((int64_t)addr + len > phys_ram_size)) - return -1; - ptr = phys_ram_base + addr; - if (is_write) - memcpy(ptr, buf, len); - else - memcpy(buf, ptr, len); - return 0; -} -#else -static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write) -{ - int l, flags; - uint32_t page; - - while (len > 0) { - page = addr & TARGET_PAGE_MASK; - l = (page + TARGET_PAGE_SIZE) - addr; - if (l > len) - l = len; - flags = page_get_flags(page); - if (!(flags & PAGE_VALID)) - return -1; - if (is_write) { - if (!(flags & PAGE_WRITE)) - return -1; - memcpy((uint8_t *)addr, buf, l); - } else { - if (!(flags & PAGE_READ)) - return -1; - memcpy(buf, (uint8_t *)addr, l); - } - len -= l; - buf += l; - addr += l; - } - return 0; -} -#endif - #if defined(TARGET_I386) static void to_le32(uint8_t *p, int v) @@ -514,16 +467,18 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) put_packet("OK"); break; case 'm': + env = cpu_gdbstub_get_env(opaque); addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; len = strtoul(p, NULL, 16); - if (memory_rw(mem_buf, addr, len, 0) != 0) + if (cpu_memory_rw_debug(env, mem_buf, addr, len, 0) != 0) memset(mem_buf, 0, len); memtohex(buf, mem_buf, len); put_packet(buf); break; case 'M': + env = cpu_gdbstub_get_env(opaque); addr = strtoul(p, (char **)&p, 16); if (*p == ',') p++; @@ -531,7 +486,7 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) if (*p == ',') p++; hextomem(mem_buf, p, len); - if (memory_rw(mem_buf, addr, len, 1) != 0) + if (cpu_memory_rw_debug(env, mem_buf, addr, len, 1) != 0) put_packet("ENN"); else put_packet("OK"); -- cgit v1.2.3 From 35b66fc4f9dd2c4c3fb8e26c5c1480965b81bbd4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 15:26:06 +0000 Subject: correct target_ulong definition git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@582 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 16 ++++++++++++++++ exec-all.h | 5 ----- thunk.h | 17 +---------------- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 84b5e280e..013076b4b 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -23,6 +23,22 @@ #include "config.h" #include +#ifndef TARGET_LONG_BITS +#error TARGET_LONG_BITS must be defined before including this header +#endif + +#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8) + +#if TARGET_LONG_SIZE == 4 +typedef int32_t target_long; +typedef uint32_t target_ulong; +#elif TARGET_LONG_SIZE == 8 +typedef int64_t target_long; +typedef uint64_t target_ulong; +#else +#error TARGET_LONG_SIZE undefined +#endif + #define EXCP_INTERRUPT 256 /* async interruption */ #define EXCP_HLT 257 /* hlt instruction reached */ #define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ diff --git a/exec-all.h b/exec-all.h index fa407e94a..9c7e5ed83 100644 --- a/exec-all.h +++ b/exec-all.h @@ -28,11 +28,6 @@ #define tostring(s) #s #endif -#ifndef THUNK_H -/* horrible */ -typedef uint32_t target_ulong; -#endif - #if GCC_MAJOR < 3 #define __builtin_expect(x, n) (x) #endif diff --git a/thunk.h b/thunk.h index 6b4c2c367..b281319a5 100644 --- a/thunk.h +++ b/thunk.h @@ -21,7 +21,7 @@ #define THUNK_H #include -#include "config.h" +#include "cpu.h" #include "bswap.h" @@ -29,11 +29,6 @@ #define BSWAP_NEEDED #endif -/* XXX: autoconf */ -#define TARGET_LONG_BITS 32 - -#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8) - #ifdef BSWAP_NEEDED static inline uint16_t tswap16(uint16_t s) @@ -105,16 +100,6 @@ static inline void tswap64s(uint64_t *s) #define tswapls(s) tswap64s((uint64_t *)(s)) #endif -#if TARGET_LONG_SIZE == 4 -typedef int32_t target_long; -typedef uint32_t target_ulong; -#elif TARGET_LONG_SIZE == 8 -typedef int64_t target_long; -typedef uint64_t target_ulong; -#else -#error TARGET_LONG_SIZE undefined -#endif - /* types enums definitions */ typedef enum argtype { -- cgit v1.2.3 From 4b7aba517372180537d98434e1604d5b0c4e8527 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 15:27:58 +0000 Subject: correct NT flag behavior git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@583 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index 46e75e192..1503134d1 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1092,32 +1092,32 @@ void OPPROTO op_set_cc_op(void) void OPPROTO op_movl_eflags_T0(void) { - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK)); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK)); } void OPPROTO op_movw_eflags_T0(void) { - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK) & 0xffff); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff); } void OPPROTO op_movl_eflags_T0_io(void) { - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK)); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK)); } void OPPROTO op_movw_eflags_T0_io(void) { - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK) & 0xffff); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK) & 0xffff); } void OPPROTO op_movl_eflags_T0_cpl0(void) { - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK)); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK)); } void OPPROTO op_movw_eflags_T0_cpl0(void) { - load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK) & 0xffff); + load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK) & 0xffff); } #if 0 -- cgit v1.2.3 From 10f0e412f81c40a2b853b0f44708bb92a99cd587 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 15:29:03 +0000 Subject: combine PDE and PTE protections as in intel specs - added cpu_get_phys_page_debug() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@584 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 80 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index d5c7727cb..5e91b2d1c 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -260,7 +260,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write, int is_user, int is_softmmu) { uint8_t *pde_ptr, *pte_ptr; - uint32_t pde, pte, virt_addr; + uint32_t pde, pte, virt_addr, ptep; int error_code, is_dirty, prot, page_size, ret; unsigned long paddr, vaddr, page_offset; @@ -291,18 +291,18 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, error_code = 0; goto do_fault; } - if (is_user) { - if (!(pde & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && - is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } /* if PSE bit is set, then we use a 4MB page */ if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + if (is_user) { + if (!(pde & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && + is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } is_dirty = is_write && !(pde & PG_DIRTY_MASK); if (!(pde & PG_ACCESSED_MASK) || is_dirty) { pde |= PG_ACCESSED_MASK; @@ -312,6 +312,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, } pte = pde & ~0x003ff000; /* align to 4MB */ + ptep = pte; page_size = 4096 * 1024; virt_addr = addr & ~0x003fffff; } else { @@ -328,14 +329,16 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, error_code = 0; goto do_fault; } + /* combine pde and pte user and rw protections */ + ptep = pte & pde; if (is_user) { - if (!(pte & PG_USER_MASK)) + if (!(ptep & PG_USER_MASK)) goto do_fault_protect; - if (is_write && !(pte & PG_RW_MASK)) + if (is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } else { - if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && - is_write && !(pte & PG_RW_MASK)) + if ((env->cr[0] & CR0_WP_MASK) && (ptep & PG_USER_MASK) && + is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } is_dirty = is_write && !(pte & PG_DIRTY_MASK); @@ -355,11 +358,11 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, /* only set write access if already dirty... otherwise wait for dirty access */ if (is_user) { - if (pte & PG_RW_MASK) + if (ptep & PG_RW_MASK) prot |= PROT_WRITE; } else { - if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || - (pte & PG_RW_MASK)) + if (!(env->cr[0] & CR0_WP_MASK) || !(ptep & PG_USER_MASK) || + (ptep & PG_RW_MASK)) prot |= PROT_WRITE; } } @@ -384,3 +387,44 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, env->error_code |= PG_ERROR_U_MASK; return 1; } + +#if defined(CONFIG_USER_ONLY) +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} +#else +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint8_t *pde_ptr, *pte_ptr; + uint32_t pde, pte, paddr, page_offset, page_size; + + if (!(env->cr[0] & CR0_PG_MASK)) { + pte = addr; + page_size = 4096; + } else { + /* page directory entry */ + pde_ptr = phys_ram_base + + (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask); + pde = ldl_raw(pde_ptr); + if (!(pde & PG_PRESENT_MASK)) + return -1; + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + pte = pde & ~0x003ff000; /* align to 4MB */ + page_size = 4096 * 1024; + } else { + /* page directory entry */ + pte_ptr = phys_ram_base + + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); + pte = ldl_raw(pte_ptr); + if (!(pte & PG_PRESENT_MASK)) + return -1; + page_size = 4096; + } + } + pte = pte & a20_mask; + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); + paddr = (pte & TARGET_PAGE_MASK) + page_offset; + return paddr; +} +#endif -- cgit v1.2.3 From 7399c5a9beff882e4faa8b08ccedfa4be6491039 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 16:24:06 +0000 Subject: fixed eflags optimisations with string operation (aka linux 2.6.2rc1 fix) - removed warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@585 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index cec9a425a..0bbd160b4 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -697,7 +697,15 @@ static GenOpFunc *gen_op_dec_ECX[2] = { gen_op_decl_ECX, }; -static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = { +#ifdef USE_DIRECT_JUMP +typedef GenOpFunc GenOpFuncTB2; +#define gen_op_string_jnz_sub(nz, ot, tb) gen_op_string_jnz_sub2[nz][ot]() +#else +typedef GenOpFunc1 GenOpFuncTB2; +#define gen_op_string_jnz_sub(nz, ot, tb) gen_op_string_jnz_sub2[nz][ot](tb) +#endif + +static GenOpFuncTB2 *gen_op_string_jnz_sub2[2][3] = { { gen_op_string_jnz_subb, gen_op_string_jnz_subw, @@ -921,7 +929,7 @@ static inline void gen_repz_ ## op(DisasContext *s, int ot, \ if (!s->jmp_opt) \ gen_op_string_jnz_sub_im[nz][ot](next_eip); \ else \ - gen_op_string_jnz_sub[nz][ot]((long)s->tb); \ + gen_op_string_jnz_sub(nz, ot, (long)s->tb); \ if (!s->jmp_opt) \ gen_op_jz_ecx_im[s->aflag](next_eip); \ gen_jmp(s, cur_eip); \ @@ -2807,7 +2815,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) mod = (modrm >> 6) & 3; rm = modrm & 7; op = ((b & 7) << 3) | ((modrm >> 3) & 7); - + if (mod != 3) { /* memory op */ gen_lea_modrm(s, modrm, ®_addr, &offset_addr); @@ -4228,6 +4236,12 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_cmc] = CC_C, [INDEX_op_salc] = CC_C, + /* needed for correct flag optimisation before string ops */ + [INDEX_op_jz_ecxw] = CC_OSZAPC, + [INDEX_op_jz_ecxl] = CC_OSZAPC, + [INDEX_op_jz_ecxw_im] = CC_OSZAPC, + [INDEX_op_jz_ecxl_im] = CC_OSZAPC, + #define DEF_READF(SUFFIX)\ [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_C,\ [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_C,\ -- cgit v1.2.3 From 8145122b0862ff307ebb4c50ffd0207c675685dc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jan 2004 16:27:56 +0000 Subject: correct NT flag behavior - zero ldt task switch bug fix - task switch thru call insn bug fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@586 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 71 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 320e09a75..b33d9cf1e 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -21,6 +21,14 @@ //#define DEBUG_PCALL +#if 0 +#define raise_exception_err(a, b)\ +do {\ + printf("raise_exception line=%d\n", __LINE__);\ + (raise_exception_err)(a, b);\ +} while (0) +#endif + const uint8_t parity_table[256] = { CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, @@ -424,7 +432,7 @@ static void switch_tss(int tss_selector, possible exception */ env->eip = new_eip; eflags_mask = TF_MASK | AC_MASK | ID_MASK | - IF_MASK | IOPL_MASK | VM_MASK | RF_MASK; + IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; if (!(type & 8)) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); @@ -452,18 +460,20 @@ static void switch_tss(int tss_selector, if (new_ldt & 4) raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); - dt = &env->gdt; - index = new_ldt & ~7; - if ((index + 7) > dt->limit) - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); - ptr = dt->base + index; - e1 = ldl_kernel(ptr); - e2 = ldl_kernel(ptr + 4); - if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); - if (!(e2 & DESC_P_MASK)) - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); - load_seg_cache_raw_dt(&env->ldt, e1, e2); + if ((new_ldt & 0xfffc) != 0) { + dt = &env->gdt; + index = new_ldt & ~7; + if ((index + 7) > dt->limit) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + ptr = dt->base + index; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); + load_seg_cache_raw_dt(&env->ldt, e1, e2); + } /* load the segments */ if (!(new_eflags & VM_MASK)) { @@ -748,6 +758,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (env->eflags & VM_MASK) { /* XXX: explain me why W2K hangs if the whole segment cache is reset ? */ +#if 1 env->segs[R_ES].selector = 0; env->segs[R_ES].flags = 0; env->segs[R_DS].selector = 0; @@ -756,6 +767,12 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, env->segs[R_FS].flags = 0; env->segs[R_GS].selector = 0; env->segs[R_GS].flags = 0; +#else + cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0, 0); + cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0, 0); + cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0, 0); + cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0, 0); +#endif } ss = (ss & ~3) | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, @@ -853,13 +870,19 @@ void do_interrupt(int intno, int is_int, int error_code, { extern FILE *stdout; static int count; - if ((env->cr[0] && CR0_PE_MASK)) { - fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x EAX=%08x\n", + if (env->cr[0] & CR0_PE_MASK) { + fprintf(stdout, "%d: v=%02x e=%04x i=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x", count, intno, error_code, is_int, env->hflags & HF_CPL_MASK, env->segs[R_CS].selector, EIP, - env->segs[R_SS].selector, ESP, - EAX); + env->segs[R_SS].selector, ESP); + if (intno == 0x0e) { + fprintf(stdout, " CR2=%08x", env->cr[2]); + } else { + fprintf(stdout, " EAX=%08x", env->regs[R_EAX]); + } + fprintf(stdout, "\n"); + if (0) { cpu_x86_dump_state(env, stdout, X86_DUMP_CCOP); #if 0 @@ -879,7 +902,6 @@ void do_interrupt(int intno, int is_int, int error_code, } } #endif - #ifdef DEBUG_PCALL if (loglevel) { static int count; @@ -925,7 +947,8 @@ void raise_interrupt(int intno, int is_int, int error_code, } /* shortcuts to generate exceptions */ -void raise_exception_err(int exception_index, int error_code) + +void (raise_exception_err)(int exception_index, int error_code) { raise_interrupt(exception_index, 0, error_code, 0); } @@ -1409,7 +1432,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL); - break; + return; case 4: /* 286 call gate */ case 12: /* 386 call gate */ break; @@ -1551,9 +1574,9 @@ void helper_iret_real(int shift) load_seg_vm(R_CS, new_cs); env->eip = new_eip; if (env->eflags & VM_MASK) - eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK; + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK; else - eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK; + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK; if (shift == 0) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); @@ -1688,7 +1711,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) env->eip = new_eip; if (is_iret) { /* NOTE: 'cpl' is the _old_ CPL */ - eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK; + eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK; if (cpl == 0) eflags_mask |= IOPL_MASK; iopl = (env->eflags >> IOPL_SHIFT) & 3; @@ -1710,7 +1733,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) /* modify processor state */ load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | - IF_MASK | IOPL_MASK | VM_MASK | VIF_MASK | VIP_MASK); + IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); load_seg_vm(R_CS, new_cs & 0xffff); cpu_x86_set_cpl(env, 3); load_seg_vm(R_SS, new_ss & 0xffff); -- cgit v1.2.3 From 3d4b4c0f4bae11ca3b09cb6f189f2bbd3f4c647b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jan 2004 15:22:15 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@587 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ TODO | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 9952f363a..8336caae5 100644 --- a/Changelog +++ b/Changelog @@ -19,6 +19,8 @@ version 0.5.2: - 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 version 0.5.1: diff --git a/TODO b/TODO index 9d7ed03f8..088d7bc2d 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,7 @@ short term: ---------- - XP install bug fix +- handle Self Modifying Code even if modifying current TB (BE OS 5 install) - L4 Pistachio kernel boot fix - TLB code protection support for PPC - add sysenter/sysexit and fxsr for L4 pistachio 686 @@ -10,7 +11,7 @@ short term: - user/kernel PUSHL/POPL in helper.c - keyboard output buffer filling timing emulation - verify tb_flush() with a20 and TLBs - +- return UD exception if LOCK prefix incorrectly used - cmos clock update and timers - test ldt limit < 7 ? - tests for each target CPU -- cgit v1.2.3 From e98c87213e1b977b61faa34a4eec68205e3a96bb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jan 2004 15:26:12 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@588 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 8336caae5..23c15649c 100644 --- a/Changelog +++ b/Changelog @@ -21,6 +21,7 @@ version 0.5.2: - 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: -- cgit v1.2.3 From c0637b3794f74e09af0435cf9061832b12633e33 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jan 2004 15:38:01 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@589 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 401776a4e..ecbd9d4d1 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,7 @@ tarbin: $(prefix)/bin/qemu-i386 \ $(prefix)/bin/qemu-arm \ $(prefix)/bin/qemu-sparc \ + $(prefix)/bin/qemu-ppc \ $(sharedir)/bios.bin \ $(sharedir)/vgabios.bin \ $(mandir)/man1/qemu.1 ) -- cgit v1.2.3 From 68e73e391fe7a26c46bb95df226fade0427669c0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jan 2004 15:47:27 +0000 Subject: clean tests dir git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@590 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 + tests/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ecbd9d4d1..4c49bd492 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ 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 TAGS qemu.pod + make -C tests clean for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done diff --git a/tests/Makefile b/tests/Makefile index a9bb0f3dc..c22450430 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -72,4 +72,4 @@ test2: done clean: - rm -f *~ *.o $(TESTS) + rm -f *~ *.o test-i386.out test-i386.ref $(TESTS) -- cgit v1.2.3 From c92b2e845f0669c71081f0f637191d553f9f3499 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 Jan 2004 00:14:11 +0000 Subject: vga memory address fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@591 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/vga.c b/hw/vga.c index c3aa93f42..ac9708161 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -494,6 +494,8 @@ static uint32_t vga_mem_readb(uint32_t addr) default: case 3: addr -= 0xb8000; + if (addr >= 0x8000) + return 0xff; break; } @@ -570,6 +572,8 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) default: case 3: addr -= 0xb8000; + if (addr >= 0x8000) + return; break; } -- cgit v1.2.3 From 56bf1d37a05b6c6f9f01ddceeb154130710158e4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Feb 2004 17:24:11 +0000 Subject: SEEK_STAT bit ata reset fix (Jens Axboe) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@592 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index 794572109..af90e2645 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1284,7 +1284,7 @@ static void ide_cmd_write(CPUState *env, uint32_t addr, uint32_t val) if (s->is_cdrom) s->status = 0x00; /* NOTE: READY is _not_ set */ else - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_signature(s); } } -- cgit v1.2.3 From 7f777bf385211e98cb7f274fe57302d061d89c9c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Feb 2004 17:37:48 +0000 Subject: fixed atapi error codes (initial patch by Jens Axboe) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@593 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index af90e2645..1517f63b1 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -299,6 +299,7 @@ #define ATAPI_INT_REASON_TAG 0xf8 /* same constants as bochs */ +#define ASC_ILLEGAL_OPCODE 0x20 #define ASC_LOGICAL_BLOCK_OOR 0x21 #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 #define ASC_MEDIUM_NOT_PRESENT 0x3a @@ -1009,7 +1010,10 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 12, max_len); break; default: - goto error_cmd; + error_cmd: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; } } break; @@ -1040,9 +1044,8 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 36, max_len); break; default: - error_cmd: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); + ASC_ILLEGAL_OPCODE); break; } } -- cgit v1.2.3 From 3ad9a57e4f0471d73e88a73f17a0e975a162c4e7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Feb 2004 17:55:47 +0000 Subject: ide identify fix (initial patch by Jens Axboe) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@594 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 1517f63b1..82e8fba88 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -393,22 +393,23 @@ static void ide_identify(IDEState *s) stw_raw(p + 0, 0x0040); stw_raw(p + 1, s->cylinders); stw_raw(p + 3, s->heads); - stw_raw(p + 4, 512 * s->sectors); /* sectors */ - stw_raw(p + 5, 512); /* sector size */ + stw_raw(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ + stw_raw(p + 5, 512); /* XXX: retired, remove ? */ stw_raw(p + 6, s->sectors); padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ - stw_raw(p + 20, 3); /* buffer type */ + stw_raw(p + 20, 3); /* XXX: retired, remove ? */ stw_raw(p + 21, 512); /* cache size in sectors */ stw_raw(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ #if MAX_MULT_SECTORS > 1 - stw_raw(p + 47, MAX_MULT_SECTORS); + stw_raw(p + 47, 0x8000 | MAX_MULT_SECTORS); #endif stw_raw(p + 48, 1); /* dword I/O */ stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ stw_raw(p + 51, 0x200); /* PIO transfer cycle */ stw_raw(p + 52, 0x200); /* DMA transfer cycle */ + stw_raw(p + 53, 1); /* words 54-58 are valid */ stw_raw(p + 54, s->cylinders); stw_raw(p + 55, s->heads); stw_raw(p + 56, s->sectors); -- cgit v1.2.3 From 64a595f26ae04ee386a3ce725c9222535dc28022 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Feb 2004 23:27:13 +0000 Subject: cleanup git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@595 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index a93486cbe..676e6ceae 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -133,6 +133,8 @@ #define CR4_TSD_MASK (1 << 2) #define CR4_DE_MASK (1 << 3) #define CR4_PSE_MASK (1 << 4) +#define CR4_PAE_MASK (1 << 5) +#define CR4_PGE_MASK (1 << 7) #define PG_PRESENT_BIT 0 #define PG_RW_BIT 1 @@ -309,6 +311,7 @@ typedef struct CPUX86State { int user_mode_only; /* user mode only simulation */ /* soft mmu support */ + uint32_t a20_mask; /* 0 = kernel, 1 = user */ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; @@ -396,13 +399,11 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); struct siginfo; int cpu_x86_signal_handler(int host_signum, struct siginfo *info, void *puc); - -/* MMU defines */ -void cpu_x86_init_mmu(CPUX86State *env); -extern int a20_enabled; - void cpu_x86_set_a20(CPUX86State *env, int a20_state); +/* will be suppressed */ +void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); + /* used to debug */ #define X86_DUMP_FPU 0x0001 /* dump FPU state too */ #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ -- cgit v1.2.3 From 1ac157da77c863b62b1d2f467626a440d57cf17d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Feb 2004 23:28:30 +0000 Subject: more precise TLB invalidation - init cleanup git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@596 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 5 ++- target-i386/helper.c | 14 ++++--- target-i386/helper2.c | 103 ++++++++++++++++++++++++++++++-------------------- 3 files changed, 74 insertions(+), 48 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index c3d24d55d..c757abc5e 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -134,8 +134,9 @@ void helper_ltr_T0(void); void helper_movl_crN_T0(int reg); void helper_movl_drN_T0(int reg); void helper_invlpg(unsigned int addr); -void cpu_x86_update_cr0(CPUX86State *env); -void cpu_x86_update_cr3(CPUX86State *env); +void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); +void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3); +void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write, int is_user, int is_softmmu); diff --git a/target-i386/helper.c b/target-i386/helper.c index b33d9cf1e..9a980bd9d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -424,8 +424,7 @@ static void switch_tss(int tss_selector, env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { - env->cr[3] = new_cr3; - cpu_x86_update_cr3(env); + cpu_x86_update_cr3(env, new_cr3); } /* load all registers without an exception, then reload them with @@ -1775,13 +1774,18 @@ void helper_lret_protected(int shift, int addend) void helper_movl_crN_T0(int reg) { - env->cr[reg] = T0; switch(reg) { case 0: - cpu_x86_update_cr0(env); + cpu_x86_update_cr0(env, T0); break; case 3: - cpu_x86_update_cr3(env); + cpu_x86_update_cr3(env, T0); + break; + case 4: + cpu_x86_update_cr4(env, T0); + break; + default: + env->cr[reg] = T0; break; } } diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 5e91b2d1c..47a93cddf 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -43,17 +43,42 @@ CPUX86State *cpu_x86_init(void) if (!env) return NULL; memset(env, 0, sizeof(CPUX86State)); - /* basic FPU init */ - for(i = 0;i < 8; i++) - env->fptags[i] = 1; - env->fpuc = 0x37f; - /* flags setup : we activate the IRQs by default as in user mode */ - env->eflags = 0x2 | IF_MASK; - tlb_flush(env); + /* init to reset state */ + + tlb_flush(env, 1); #ifdef CONFIG_SOFTMMU env->hflags |= HF_SOFTMMU_MASK; #endif + + cpu_x86_update_cr0(env, 0x60000010); + env->a20_mask = 0xffffffff; + + env->idt.limit = 0xffff; + env->gdt.limit = 0xffff; + env->ldt.limit = 0xffff; + env->ldt.flags = DESC_P_MASK; + env->tr.limit = 0xffff; + env->tr.flags = DESC_P_MASK; + + /* not correct (CS base=0xffff0000) */ + cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0); + + env->eip = 0xfff0; + env->regs[R_EDX] = 0x600; /* indicate P6 processor */ + + env->eflags = 0x2; + + /* FPU init */ + for(i = 0;i < 8; i++) + env->fptags[i] = 1; + env->fpuc = 0x37f; + /* init various static tables */ if (!inited) { inited = 1; @@ -179,15 +204,10 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) /* x86 mmu */ /* XXX: add PGE support */ -/* called when cr3 or PG bit are modified */ -static int last_pg_state = -1; -static uint32_t a20_mask; -int a20_enabled; - void cpu_x86_set_a20(CPUX86State *env, int a20_state) { a20_state = (a20_state != 0); - if (a20_state != a20_enabled) { + if (a20_state != ((env->a20_mask >> 20) & 1)) { #if defined(DEBUG_MMU) printf("A20 update: a20=%d\n", a20_state); #endif @@ -197,27 +217,24 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) /* when a20 is changed, all the MMU mappings are invalid, so we must flush everything */ - tlb_flush(env); - a20_enabled = a20_state; - if (a20_enabled) - a20_mask = 0xffffffff; - else - a20_mask = 0xffefffff; + tlb_flush(env, 1); + env->a20_mask = 0xffefffff | (a20_state << 20); } } -void cpu_x86_update_cr0(CPUX86State *env) +void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) { - int pg_state, pe_state; + int pe_state; #if defined(DEBUG_MMU) - printf("CR0 update: CR0=0x%08x\n", env->cr[0]); + printf("CR0 update: CR0=0x%08x\n", new_cr0); #endif - pg_state = env->cr[0] & CR0_PG_MASK; - if (pg_state != last_pg_state) { - tlb_flush(env); - last_pg_state = pg_state; + if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) != + (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) { + tlb_flush(env, 1); } + env->cr[0] = new_cr0; + /* update PE flag in hidden flags */ pe_state = (env->cr[0] & CR0_PE_MASK); env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); @@ -225,23 +242,27 @@ void cpu_x86_update_cr0(CPUX86State *env) env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT); } -void cpu_x86_update_cr3(CPUX86State *env) +void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3) { + env->cr[3] = new_cr3; if (env->cr[0] & CR0_PG_MASK) { #if defined(DEBUG_MMU) - printf("CR3 update: CR3=%08x\n", env->cr[3]); + printf("CR3 update: CR3=%08x\n", new_cr3); #endif - tlb_flush(env); + tlb_flush(env, 0); } } -void cpu_x86_init_mmu(CPUX86State *env) +void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) { - a20_enabled = 1; - a20_mask = 0xffffffff; - - last_pg_state = -1; - cpu_x86_update_cr0(env); +#if defined(DEBUG_MMU) + printf("CR4 update: CR4=%08x\n", env->cr[4]); +#endif + if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) != + (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) { + tlb_flush(env, 1); + } + env->cr[4] = new_cr4; } /* XXX: also flush 4MB pages */ @@ -285,7 +306,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, /* page directory entry */ pde_ptr = phys_ram_base + - (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask); + (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask); pde = ldl_raw(pde_ptr); if (!(pde & PG_PRESENT_MASK)) { error_code = 0; @@ -323,7 +344,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, /* page directory entry */ pte_ptr = phys_ram_base + - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); pte = ldl_raw(pte_ptr); if (!(pte & PG_PRESENT_MASK)) { error_code = 0; @@ -368,7 +389,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, } do_mapping: - pte = pte & a20_mask; + pte = pte & env->a20_mask; /* Even if 4MB pages, we map only one 4KB page in the cache to avoid filling it too fast */ @@ -405,7 +426,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } else { /* page directory entry */ pde_ptr = phys_ram_base + - (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask); + (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask); pde = ldl_raw(pde_ptr); if (!(pde & PG_PRESENT_MASK)) return -1; @@ -415,14 +436,14 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } else { /* page directory entry */ pte_ptr = phys_ram_base + - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); pte = ldl_raw(pte_ptr); if (!(pte & PG_PRESENT_MASK)) return -1; page_size = 4096; } } - pte = pte & a20_mask; + pte = pte & env->a20_mask; page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); paddr = (pte & TARGET_PAGE_MASK) + page_offset; return paddr; -- cgit v1.2.3 From 625976dac8a2233233c7a5943d2b970ac29ef8ad Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Feb 2004 23:30:47 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@597 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Changelog b/Changelog index 23c15649c..502f60f44 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,10 @@ +version 0.5.3: + + - 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) + version 0.5.2: - improved soft MMU speed (assembly functions and specializing) -- cgit v1.2.3 From ee8b7021da823e11e3c6ea9063ebb2ab50406a3e Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Feb 2004 23:35:10 +0000 Subject: temporary interrupt locking fix (need rework) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@598 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 1 + exec-all.h | 2 +- exec.c | 15 ++++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index bd0cbb35e..4e2d77f3a 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -142,6 +142,7 @@ int cpu_exec(CPUState *env1) /* 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) { diff --git a/exec-all.h b/exec-all.h index 9c7e5ed83..407e96328 100644 --- a/exec-all.h +++ b/exec-all.h @@ -85,7 +85,7 @@ int page_unprotect(unsigned long address); void tb_invalidate_page_range(target_ulong start, target_ulong end); void tlb_flush_page(CPUState *env, uint32_t addr); void tlb_flush_page_write(CPUState *env, uint32_t addr); -void tlb_flush(CPUState *env); +void tlb_flush(CPUState *env, int flush_global); int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, int is_user, int is_softmmu); diff --git a/exec.c b/exec.c index 9104efbb1..4bf87e37e 100644 --- a/exec.c +++ b/exec.c @@ -260,10 +260,6 @@ void tb_flush(CPUState *env) nb_tbs, nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); #endif - /* must reset current TB so that interrupts cannot modify the - links while we are modifying them */ - env->current_tb = NULL; - nb_tbs = 0; for(i = 0;i < CODE_GEN_HASH_SIZE; i++) tb_hash[i] = NULL; @@ -970,13 +966,16 @@ void cpu_set_log_filename(const char *filename) void cpu_interrupt(CPUState *env, int mask) { TranslationBlock *tb; + static int interrupt_lock; env->interrupt_request |= mask; /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ tb = env->current_tb; - if (tb) { + if (tb && !testandset(&interrupt_lock)) { + env->current_tb = NULL; tb_reset_jump_recursive(tb); + interrupt_lock = 0; } } @@ -998,7 +997,9 @@ void cpu_abort(CPUState *env, const char *fmt, ...) #if !defined(CONFIG_USER_ONLY) -void tlb_flush(CPUState *env) +/* NOTE: if flush_global is true, also flush global entries (not + implemented yet) */ +void tlb_flush(CPUState *env, int flush_global) { int i; @@ -1293,7 +1294,7 @@ int page_unprotect(unsigned long addr) #else -void tlb_flush(CPUState *env) +void tlb_flush(CPUState *env, int flush_global) { } -- cgit v1.2.3 From 415e561f1de19e9fa609a58bec67c9b59fcdf726 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Feb 2004 23:37:12 +0000 Subject: cleanup git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@599 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 3 +++ vl.c | 31 ++----------------------------- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 8bc57a9e9..171a1fe95 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -903,6 +903,9 @@ int main(int argc, char **argv) env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; env->hflags |= HF_PE_MASK; + /* flags setup : we activate the IRQs by default as in user mode */ + env->eflags |= IF_MASK; + /* linux register setup */ env->regs[R_EAX] = regs->eax; env->regs[R_EBX] = regs->ebx; diff --git a/vl.c b/vl.c index 621bbeb88..0ebfa7407 100644 --- a/vl.c +++ b/vl.c @@ -2527,7 +2527,7 @@ void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) case KBD_CCMD_READ_OUTPORT: /* XXX: check that */ #ifdef TARGET_I386 - val = 0x01 | (a20_enabled << 1); + val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1); #else val = 0x01; #endif @@ -3591,9 +3591,7 @@ int main(int argc, char **argv) params->orig_video_cols = 80; /* setup basic memory access */ - env->cr[0] = 0x00000033; - env->hflags |= HF_PE_MASK; - cpu_x86_init_mmu(env); + cpu_x86_update_cr0(env, 0x00000033); memset(params->idt_table, 0, sizeof(params->idt_table)); @@ -3619,7 +3617,6 @@ int main(int argc, char **argv) env->regs[R_ESI] = KERNEL_PARAMS_ADDR; env->eflags = 0x2; #elif defined (TARGET_PPC) - cpu_x86_init_mmu(env); PPC_init_hw(env, phys_ram_size, KERNEL_LOAD_ADDR, ret, KERNEL_STACK_ADDR, boot_device); #endif @@ -3641,35 +3638,11 @@ int main(int argc, char **argv) ret = load_image(buf, phys_ram_base + 0x000c0000); /* setup basic memory access */ - env->cr[0] = 0x60000010; - cpu_x86_init_mmu(env); - cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); - env->idt.limit = 0xffff; - env->gdt.limit = 0xffff; - env->ldt.limit = 0xffff; - env->ldt.flags = DESC_P_MASK; - env->tr.limit = 0xffff; - env->tr.flags = DESC_P_MASK; - - /* not correct (CS base=0xffff0000) */ - cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0); - - env->eip = 0xfff0; - env->regs[R_EDX] = 0x600; /* indicate P6 processor */ - - env->eflags = 0x2; - bochs_bios_init(); #elif defined(TARGET_PPC) - cpu_x86_init_mmu(env); /* allocate ROM */ // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); -- cgit v1.2.3 From ad08132319713918a58b1ffa35a57431ed294888 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Feb 2004 23:39:42 +0000 Subject: added tlb_flush() flags git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@600 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.c | 2 +- target-ppc/translate.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index a0e936028..5bd138da5 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -361,7 +361,7 @@ void do_icbi (void) /* TLB invalidation helpers */ void do_tlbia (void) { - tlb_flush(env); + tlb_flush(env, 1); } void do_tlbie (void) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 9ad8f6dea..1b16fd541 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2997,7 +2997,7 @@ CPUPPCState *cpu_ppc_init(void) if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) return NULL; init_spr_rights(env->spr[PVR]); - tlb_flush(env); + tlb_flush(env, 1); #if defined (DO_SINGLE_STEP) /* Single step trace mode */ msr_se = 1; -- cgit v1.2.3 From 1ccde1cb942f77958776578939bbcfc4c9bdf362 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 6 Feb 2004 19:46:14 +0000 Subject: added generic physical memory dirty bit support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@601 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 20 +++++- exec-all.h | 2 + exec.c | 175 +++++++++++++++++++++++++++++++++++++++++++---------- softmmu_template.h | 10 +-- vl.c | 33 +++++----- 5 files changed, 185 insertions(+), 55 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 1cf35ea23..a01818a98 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -500,6 +500,7 @@ int cpu_inl(CPUState *env, int addr); extern int phys_ram_size; extern int phys_ram_fd; extern uint8_t *phys_ram_base; +extern uint8_t *phys_ram_dirty; /* physical memory access */ #define IO_MEM_NB_ENTRIES 256 @@ -509,9 +510,11 @@ extern uint8_t *phys_ram_base; #define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */ #define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ #define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) -#define IO_MEM_CODE (3 << IO_MEM_SHIFT) +#define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */ +#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ -typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); +/* NOTE: vaddr is only used internally. Never use it except if you know what you do */ +typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value, uint32_t vaddr); typedef uint32_t CPUReadMemoryFunc(uint32_t addr); void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, @@ -525,6 +528,19 @@ void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, int cpu_memory_rw_debug(CPUState *env, uint8_t *buf, target_ulong addr, int len, int is_write); +/* read dirty bit (return 0 or 1) */ +static inline int cpu_physical_memory_is_dirty(target_ulong addr) +{ + return phys_ram_dirty[addr >> TARGET_PAGE_BITS]; +} + +static inline void cpu_physical_memory_set_dirty(target_ulong addr) +{ + phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 1; +} + +void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end); + /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); diff --git a/exec-all.h b/exec-all.h index 407e96328..500818ba8 100644 --- a/exec-all.h +++ b/exec-all.h @@ -530,6 +530,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) } #else /* NOTE: this function can trigger an exception */ +/* NOTE2: the returned address is not exactly the physical address: it + is the offset relative to phys_ram_base */ /* XXX: i386 target specific */ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) { diff --git a/exec.c b/exec.c index 4bf87e37e..20a379508 100644 --- a/exec.c +++ b/exec.c @@ -59,6 +59,7 @@ uint8_t *code_gen_ptr; int phys_ram_size; int phys_ram_fd; uint8_t *phys_ram_base; +uint8_t *phys_ram_dirty; typedef struct PageDesc { /* offset in memory of the page + io_index in the low 12 bits */ @@ -162,7 +163,7 @@ static inline PageDesc *page_find(unsigned int index) #if !defined(CONFIG_USER_ONLY) static void tlb_protect_code(CPUState *env, uint32_t addr); static void tlb_unprotect_code(CPUState *env, uint32_t addr); -static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr); +static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr); static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) { @@ -528,8 +529,11 @@ static void build_page_bitmap(PageDesc *p) /* invalidate all TBs which intersect with the target physical page starting in range [start;end[. NOTE: start and end must refer to - the same physical page */ -static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end) + the same physical page. 'vaddr' is a virtual address referencing + the physical page of code. It is only used an a hint if there is no + code left. */ +static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, + target_ulong vaddr) { int n; PageDesc *p; @@ -571,13 +575,13 @@ static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end) /* if no code remaining, no need to continue to use slow writes */ if (!p->first_tb) { invalidate_page_bitmap(p); - tlb_unprotect_code_phys(cpu_single_env, start); + tlb_unprotect_code_phys(cpu_single_env, start, vaddr); } #endif } /* len must be <= 8 and start must be a multiple of len */ -static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) +static inline void tb_invalidate_phys_page_fast(target_ulong start, int len, target_ulong vaddr) { PageDesc *p; int offset, b; @@ -592,7 +596,7 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) goto do_invalidate; } else { do_invalidate: - tb_invalidate_phys_page_range(start, start + len); + tb_invalidate_phys_page_range(start, start + len, vaddr); } } @@ -1088,8 +1092,7 @@ static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr) (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE && (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) { - tlb_entry->address |= IO_MEM_CODE; - tlb_entry->addend -= (unsigned long)phys_ram_base; + tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE; } } @@ -1116,8 +1119,7 @@ static inline void tlb_unprotect_code1(CPUTLBEntry *tlb_entry, uint32_t addr) if (addr == (tlb_entry->address & (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE) { - tlb_entry->address &= TARGET_PAGE_MASK; - tlb_entry->addend += (unsigned long)phys_ram_base; + tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; } } @@ -1138,23 +1140,84 @@ static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, { if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE && ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) { - tlb_entry->address &= TARGET_PAGE_MASK; - tlb_entry->addend += (unsigned long)phys_ram_base; + tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; } } /* update the TLB so that writes in physical page 'phys_addr' are no longer tested self modifying code */ -/* XXX: find a way to improve it */ -static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr) +static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr) { int i; phys_addr &= TARGET_PAGE_MASK; + phys_addr += (long)phys_ram_base; + i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr); + tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr); +} + +static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, + unsigned long start, unsigned long length) +{ + unsigned long addr; + if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend; + if ((addr - start) < length) { + tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; + } + } +} + +void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end) +{ + CPUState *env; + target_ulong length; + int i; + + start &= TARGET_PAGE_MASK; + end = TARGET_PAGE_ALIGN(end); + + length = end - start; + if (length == 0) + return; + memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS); + + env = cpu_single_env; + /* we modify the TLB cache so that the dirty bit will be set again + when accessing the range */ + start += (unsigned long)phys_ram_base; for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr); + tlb_reset_dirty_range(&env->tlb_write[0][i], start, length); for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr); + tlb_reset_dirty_range(&env->tlb_write[1][i], start, length); +} + +static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, + unsigned long start) +{ + unsigned long addr; + if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) { + addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend; + if (addr == start) { + tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM; + } + } +} + +/* update the TLB corresponding to virtual page vaddr and phys addr + addr so that it is no longer dirty */ +static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) +{ + CPUState *env = cpu_single_env; + int i; + + phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1; + + addr &= TARGET_PAGE_MASK; + i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_set_dirty1(&env->tlb_write[0][i], addr); + tlb_set_dirty1(&env->tlb_write[1][i], addr); } /* add a new TLB entry. At most one entry for a given virtual @@ -1210,12 +1273,16 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { /* ROM: access is ignored (same as unassigned) */ env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM; - env->tlb_write[is_user][index].addend = addend - (unsigned long)phys_ram_base; + env->tlb_write[is_user][index].addend = addend; } else if (first_tb) { /* if code is present, we use a specific memory handler. It works only for physical memory access */ env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE; - env->tlb_write[is_user][index].addend = addend - (unsigned long)phys_ram_base; + env->tlb_write[is_user][index].addend = addend; + } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + !cpu_physical_memory_is_dirty(pd)) { + env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY; + env->tlb_write[is_user][index].addend = addend; } else { env->tlb_write[is_user][index].address = address; env->tlb_write[is_user][index].addend = addend; @@ -1446,6 +1513,10 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size) } } +static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) +{ +} + #endif /* defined(CONFIG_USER_ONLY) */ /* register physical memory. 'size' must be a multiple of the target @@ -1471,7 +1542,7 @@ static uint32_t unassigned_mem_readb(uint32_t addr) return 0; } -static void unassigned_mem_writeb(uint32_t addr, uint32_t val) +static void unassigned_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) { } @@ -1490,28 +1561,40 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = { /* self modifying code support in soft mmu mode : writing to a page containing code comes to these functions */ -static void code_mem_writeb(uint32_t addr, uint32_t val) +static void code_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) { + unsigned long phys_addr; + + phys_addr = addr - (long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(addr, 1); + tb_invalidate_phys_page_fast(phys_addr, 1, vaddr); #endif - stb_raw(phys_ram_base + addr, val); + stb_raw((uint8_t *)addr, val); + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } -static void code_mem_writew(uint32_t addr, uint32_t val) +static void code_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr) { + unsigned long phys_addr; + + phys_addr = addr - (long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(addr, 2); + tb_invalidate_phys_page_fast(phys_addr, 2, vaddr); #endif - stw_raw(phys_ram_base + addr, val); + stw_raw((uint8_t *)addr, val); + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } -static void code_mem_writel(uint32_t addr, uint32_t val) +static void code_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr) { + unsigned long phys_addr; + + phys_addr = addr - (long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(addr, 4); + tb_invalidate_phys_page_fast(phys_addr, 4, vaddr); #endif - stl_raw(phys_ram_base + addr, val); + stl_raw((uint8_t *)addr, val); + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } static CPUReadMemoryFunc *code_mem_read[3] = { @@ -1526,12 +1609,40 @@ static CPUWriteMemoryFunc *code_mem_write[3] = { code_mem_writel, }; +static void notdirty_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) +{ + stb_raw((uint8_t *)addr, val); + tlb_set_dirty(addr, vaddr); +} + +static void notdirty_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr) +{ + stw_raw((uint8_t *)addr, val); + tlb_set_dirty(addr, vaddr); +} + +static void notdirty_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr) +{ + stl_raw((uint8_t *)addr, val); + tlb_set_dirty(addr, vaddr); +} + +static CPUWriteMemoryFunc *notdirty_mem_write[3] = { + notdirty_mem_writeb, + notdirty_mem_writew, + notdirty_mem_writel, +}; + static void io_mem_init(void) { cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write); cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write); cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write); - io_mem_nb = 4; + cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write); + io_mem_nb = 5; + + /* alloc dirty bits array */ + phys_ram_dirty = malloc(phys_ram_size >> TARGET_PAGE_BITS); } /* mem_read and mem_write are arrays of functions containing the @@ -1620,17 +1731,17 @@ void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ val = ldl_raw(buf); - io_mem_write[io_index][2](addr, val); + io_mem_write[io_index][2](addr, val, 0); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { /* 16 bit read access */ val = lduw_raw(buf); - io_mem_write[io_index][1](addr, val); + io_mem_write[io_index][1](addr, val, 0); l = 2; } else { /* 8 bit access */ val = ldub_raw(buf); - io_mem_write[io_index][0](addr, val); + io_mem_write[io_index][0](addr, val, 0); l = 1; } } else { diff --git a/softmmu_template.h b/softmmu_template.h index 2d3db62f6..2203c5a5c 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -76,14 +76,14 @@ static inline void glue(io_write, SUFFIX)(unsigned long physaddr, index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); #if SHIFT <= 2 - io_mem_write[index][SHIFT](physaddr, val); + io_mem_write[index][SHIFT](physaddr, val, tlb_addr); #else #ifdef TARGET_WORDS_BIGENDIAN - io_mem_write[index][2](physaddr, val >> 32); - io_mem_write[index][2](physaddr + 4, val); + io_mem_write[index][2](physaddr, val >> 32, tlb_addr); + io_mem_write[index][2](physaddr + 4, val, tlb_addr); #else - io_mem_write[index][2](physaddr, val); - io_mem_write[index][2](physaddr + 4, val >> 32); + io_mem_write[index][2](physaddr, val, tlb_addr); + io_mem_write[index][2](physaddr + 4, val >> 32, tlb_addr); #endif #endif /* SHIFT > 2 */ } diff --git a/vl.c b/vl.c index 0ebfa7407..0c1f839d7 100644 --- a/vl.c +++ b/vl.c @@ -233,6 +233,7 @@ int nographic; int term_inited; int64_t ticks_per_sec; int boot_device = 'c'; +static int ram_size; /***********************************************************/ /* x86 io ports */ @@ -610,7 +611,7 @@ void cmos_init(void) cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ /* memory size */ - val = (phys_ram_size / 1024) - 1024; + val = (ram_size / 1024) - 1024; if (val > 65535) val = 65535; cmos_data[0x17] = val; @@ -618,7 +619,7 @@ void cmos_init(void) cmos_data[0x30] = val; cmos_data[0x31] = val >> 8; - val = (phys_ram_size / 65536) - ((16 * 1024 * 1024) / 65536); + val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); if (val > 65535) val = 65535; cmos_data[0x34] = val; @@ -3312,7 +3313,7 @@ extern void __sigaction(); int main(int argc, char **argv) { int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; - int snapshot, linux_boot, total_ram_size; + int snapshot, linux_boot; #if defined (TARGET_I386) struct linux_params *params; #endif @@ -3331,7 +3332,7 @@ int main(int argc, char **argv) fd_filename[i] = NULL; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; - phys_ram_size = 32 * 1024 * 1024; + ram_size = 32 * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; #if defined (TARGET_I386) pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); @@ -3425,10 +3426,10 @@ int main(int argc, char **argv) help(); break; case 'm': - phys_ram_size = atoi(optarg) * 1024 * 1024; - if (phys_ram_size <= 0) + ram_size = atoi(optarg) * 1024 * 1024; + if (ram_size <= 0) help(); - if (phys_ram_size > PHYS_RAM_MAX_SIZE) { + if (ram_size > PHYS_RAM_MAX_SIZE) { fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", PHYS_RAM_MAX_SIZE / (1024 * 1024)); exit(1); @@ -3489,10 +3490,10 @@ int main(int argc, char **argv) #endif /* init the memory */ - total_ram_size = phys_ram_size + vga_ram_size; + phys_ram_size = ram_size + vga_ram_size; #ifdef CONFIG_SOFTMMU - phys_ram_base = malloc(total_ram_size); + phys_ram_base = memalign(TARGET_PAGE_SIZE, phys_ram_size); if (!phys_ram_base) { fprintf(stderr, "Could not allocate physical memory\n"); exit(1); @@ -3518,10 +3519,10 @@ int main(int argc, char **argv) phys_ram_file); exit(1); } - ftruncate(phys_ram_fd, total_ram_size); + ftruncate(phys_ram_fd, phys_ram_size); unlink(phys_ram_file); - phys_ram_base = mmap(get_mmap_addr(total_ram_size), - total_ram_size, + phys_ram_base = mmap(get_mmap_addr(phys_ram_size), + phys_ram_size, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, phys_ram_fd, 0); if (phys_ram_base == MAP_FAILED) { @@ -3551,7 +3552,7 @@ int main(int argc, char **argv) init_ioports(); /* allocate RAM */ - cpu_register_physical_memory(0, phys_ram_size, 0); + cpu_register_physical_memory(0, ram_size, 0); if (linux_boot) { /* now we can load the kernel */ @@ -3580,7 +3581,7 @@ int main(int argc, char **argv) params->mount_root_rdonly = 0; stw_raw(¶ms->cl_magic, 0xA33F); stw_raw(¶ms->cl_offset, params->commandline - (uint8_t *)params); - stl_raw(¶ms->alt_mem_k, (phys_ram_size / 1024) - 1024); + stl_raw(¶ms->alt_mem_k, (ram_size / 1024) - 1024); pstrcat(params->commandline, sizeof(params->commandline), kernel_cmdline); params->loader_type = 0x01; if (initrd_size > 0) { @@ -3617,7 +3618,7 @@ int main(int argc, char **argv) env->regs[R_ESI] = KERNEL_PARAMS_ADDR; env->eflags = 0x2; #elif defined (TARGET_PPC) - PPC_init_hw(env, phys_ram_size, KERNEL_LOAD_ADDR, ret, + PPC_init_hw(env, ram_size, KERNEL_LOAD_ADDR, ret, KERNEL_STACK_ADDR, boot_device); #endif } else { @@ -3669,7 +3670,7 @@ int main(int argc, char **argv) /* init basic PC hardware */ register_ioport_write(0x80, 1, ioport80_write, 1); - vga_initialize(ds, phys_ram_base + phys_ram_size, phys_ram_size, + vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); #if defined (TARGET_I386) cmos_init(); -- cgit v1.2.3 From 4fa0f5d292add0d53554eb02351a78b18af8985d Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 6 Feb 2004 19:47:52 +0000 Subject: added bochs VBE support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@602 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++------- hw/vga_template.h | 20 ++++ vl.h | 2 +- 3 files changed, 263 insertions(+), 37 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index ac9708161..a480ea79a 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1,5 +1,5 @@ /* - * QEMU VGA Emulator. An S3 86c968 is emulated + * QEMU VGA Emulator. * * Copyright (c) 2003 Fabrice Bellard * @@ -53,6 +53,8 @@ //#define DEBUG_VGA_REG //#define DEBUG_S3 +//#define DEBUG_BOCHS_VBE + #define CONFIG_S3VGA #define MSR_COLOR_EMULATION 0x01 @@ -61,6 +63,35 @@ #define ST01_V_RETRACE 0x08 #define ST01_DISP_ENABLE 0x01 +/* bochs VBE support */ +#define CONFIG_BOCHS_VBE + +#define VBE_DISPI_MAX_XRES 1024 +#define VBE_DISPI_MAX_YRES 768 + +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_NB 0xa + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 + typedef struct VGAState { uint8_t *vram_ptr; unsigned long vram_offset; @@ -85,7 +116,12 @@ typedef struct VGAState { uint8_t dac_write_index; uint8_t dac_cache[3]; /* used when writing */ uint8_t palette[768]; - +#ifdef CONFIG_BOCHS_VBE + uint16_t vbe_index; + uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; + uint32_t vbe_start_addr; + uint32_t vbe_line_offset; +#endif /* display refresh support */ DisplayState *ds; uint32_t font_offsets[2]; @@ -101,7 +137,6 @@ typedef struct VGAState { uint32_t cursor_offset; unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); /* tell for each page if it has been updated since the last time */ - uint8_t vram_updated[VGA_RAM_SIZE / 4096]; uint32_t last_palette[256]; #define CH_ATTR_SIZE (160 * 100) uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ @@ -313,7 +348,7 @@ static uint32_t vga_ioport_read(CPUState *env, uint32_t addr) break; } } -#ifdef DEBUG_VGA +#if defined(DEBUG_VGA) printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val); #endif return val; @@ -468,6 +503,122 @@ static void vga_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } } +#ifdef CONFIG_BOCHS_VBE +static uint32_t vbe_ioport_read(CPUState *env, uint32_t addr) +{ + VGAState *s = &vga_state; + uint32_t val; + + addr &= 1; + if (addr == 0) { + val = s->vbe_index; + } else { + if (s->vbe_index <= VBE_DISPI_INDEX_NB) + val = s->vbe_regs[s->vbe_index]; + else + val = 0; +#ifdef DEBUG_BOCHS_VBE + printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); +#endif + } + return val; +} + +static void vbe_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +{ + VGAState *s = &vga_state; + + addr &= 1; + if (addr == 0) { + s->vbe_index = val; + } else if (s->vbe_index <= VBE_DISPI_INDEX_NB) { +#ifdef DEBUG_BOCHS_VBE + printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val); +#endif + switch(s->vbe_index) { + case VBE_DISPI_INDEX_ID: + if (val != VBE_DISPI_ID0 && + val != VBE_DISPI_ID1 && + val != VBE_DISPI_ID2) + return; + break; + case VBE_DISPI_INDEX_XRES: + if ((val > VBE_DISPI_MAX_XRES) || ((val & 7) != 0)) + return; + break; + case VBE_DISPI_INDEX_YRES: + if (val > VBE_DISPI_MAX_YRES) + return; + break; + case VBE_DISPI_INDEX_BPP: + if (val == 0) + val = 8; + if (val != 4 && val != 8 && val != 15 && + val != 16 && val != 24 && val != 32) + return; + break; + case VBE_DISPI_INDEX_BANK: + val &= 0xff; + break; + case VBE_DISPI_INDEX_ENABLE: + if (val & VBE_DISPI_ENABLED) { + int h, shift_control; + + s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = + s->vbe_regs[VBE_DISPI_INDEX_XRES]; + s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = + s->vbe_regs[VBE_DISPI_INDEX_YRES]; + s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; + s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; + + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) + s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1; + else + s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * + ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); + s->vbe_start_addr = 0; + + /* clear the screen (should be done in BIOS) */ + if (!(val & VBE_DISPI_NOCLEARMEM)) { + memset(s->vram_ptr, 0, + s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); + } + + /* we initialize graphic mode force graphic mode + (should be done in BIOS) */ + s->gr[6] |= 1; + s->cr[0x17] |= 3; /* no CGA modes */ + s->cr[0x13] = s->vbe_line_offset >> 3; + /* width */ + s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; + /* height */ + h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; + s->cr[0x12] = h; + s->cr[0x07] = (s->cr[0x07] & ~0x42) | + ((h >> 7) & 0x02) | ((h >> 3) & 0x40); + /* line compare to 1023 */ + s->cr[0x18] = 0xff; + s->cr[0x07] |= 0x10; + s->cr[0x09] |= 0x40; + + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { + shift_control = 0; + s->sr[0x01] &= ~8; /* no double line */ + } else { + shift_control = 2; + } + s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5); + s->cr[0x09] &= ~0x9f; /* no double scan */ + } + break; + default: + break; + } + s->vbe_regs[s->vbe_index] = val; + } +} +#endif + /* called for accesses between 0xa0000 and 0xc0000 */ static uint32_t vga_mem_readb(uint32_t addr) { @@ -544,7 +695,7 @@ static uint32_t vga_mem_readl(uint32_t addr) } /* called for accesses between 0xa0000 and 0xc0000 */ -void vga_mem_writeb(uint32_t addr, uint32_t val) +void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) { VGAState *s = &vga_state; int memory_map_mode, plane, write_mode, b, func_select; @@ -585,7 +736,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) #ifdef DEBUG_VGA_MEM printf("vga: chain4: [0x%x]\n", addr); #endif - s->vram_updated[addr >> 12] = 1; + cpu_physical_memory_set_dirty(s->vram_offset + addr); } } else if (s->gr[5] & 0x10) { /* odd/even mode (aka text mode mapping) */ @@ -596,7 +747,7 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) #ifdef DEBUG_VGA_MEM printf("vga: odd/even: [0x%x]\n", addr); #endif - s->vram_updated[addr >> 12] = 1; + cpu_physical_memory_set_dirty(s->vram_offset + addr); } } else { /* standard VGA latched access */ @@ -668,22 +819,22 @@ void vga_mem_writeb(uint32_t addr, uint32_t val) printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", addr * 4, write_mask, val); #endif - s->vram_updated[addr >> 10] = 1; + cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2)); } } -void vga_mem_writew(uint32_t addr, uint32_t val) +void vga_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr) { - vga_mem_writeb(addr, val & 0xff); - vga_mem_writeb(addr + 1, (val >> 8) & 0xff); + vga_mem_writeb(addr, val & 0xff, vaddr); + vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr); } -void vga_mem_writel(uint32_t addr, uint32_t val) +void vga_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr) { - vga_mem_writeb(addr, val & 0xff); - vga_mem_writeb(addr + 1, (val >> 8) & 0xff); - vga_mem_writeb(addr + 2, (val >> 16) & 0xff); - vga_mem_writeb(addr + 3, (val >> 24) & 0xff); + vga_mem_writeb(addr, val & 0xff, vaddr); + vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr); + vga_mem_writeb(addr + 2, (val >> 16) & 0xff, vaddr); + vga_mem_writeb(addr + 3, (val >> 24) & 0xff, vaddr); } typedef void vga_draw_glyph8_func(uint8_t *d, int linesize, @@ -823,22 +974,31 @@ static int update_basic_params(VGAState *s) uint32_t start_addr, line_offset, line_compare, v; full_update = 0; - /* compute line_offset in bytes */ - line_offset = s->cr[0x13]; + +#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + line_offset = s->vbe_line_offset; + start_addr = s->vbe_start_addr; + } else +#endif + { + /* compute line_offset in bytes */ + line_offset = s->cr[0x13]; #ifdef CONFIG_S3VGA - v = (s->cr[0x51] >> 4) & 3; /* S3 extension */ - if (v == 0) - v = (s->cr[0x43] >> 2) & 1; /* S3 extension */ - line_offset |= (v << 8); + v = (s->cr[0x51] >> 4) & 3; /* S3 extension */ + if (v == 0) + v = (s->cr[0x43] >> 2) & 1; /* S3 extension */ + line_offset |= (v << 8); #endif - line_offset <<= 3; - - /* starting address */ - start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); + line_offset <<= 3; + + /* starting address */ + start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); #ifdef CONFIG_S3VGA - start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */ + start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */ #endif - + } + /* line compare */ line_compare = s->cr[0x18] | ((s->cr[0x07] & 0x10) << 4) | @@ -1086,6 +1246,7 @@ enum { VGA_DRAW_LINE8, VGA_DRAW_LINE15, VGA_DRAW_LINE16, + VGA_DRAW_LINE24, VGA_DRAW_LINE32, VGA_DRAW_LINE_NB, }; @@ -1131,6 +1292,11 @@ static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = { vga_draw_line16_16, vga_draw_line16_32, + vga_draw_line24_8, + vga_draw_line24_15, + vga_draw_line24_16, + vga_draw_line24_32, + vga_draw_line32_8, vga_draw_line32_15, vga_draw_line32_16, @@ -1193,8 +1359,33 @@ static void vga_draw_graphic(VGAState *s, int full_update) v = VGA_DRAW_LINE2; } } else { - full_update |= update_palette256(s); - v = VGA_DRAW_LINE8D2; +#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) { + default: + case 8: + full_update |= update_palette256(s); + v = VGA_DRAW_LINE8; + break; + case 15: + v = VGA_DRAW_LINE15; + break; + case 16: + v = VGA_DRAW_LINE16; + break; + case 24: + v = VGA_DRAW_LINE24; + break; + case 32: + v = VGA_DRAW_LINE32; + break; + } + } else +#endif + { + full_update |= update_palette256(s); + v = VGA_DRAW_LINE8D2; + } } vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; @@ -1230,12 +1421,13 @@ static void vga_draw_graphic(VGAState *s, int full_update) if (!(s->cr[0x17] & 2)) { addr = (addr & ~0x8000) | ((y1 & 2) << 14); } - page0 = addr >> 12; - page1 = (addr + bwidth - 1) >> 12; - update = full_update | s->vram_updated[page0] | s->vram_updated[page1]; - if ((page1 - page0) > 1) { + page0 = s->vram_offset + (addr & TARGET_PAGE_MASK); + page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK); + update = full_update | cpu_physical_memory_is_dirty(page0) | + cpu_physical_memory_is_dirty(page1); + if ((page1 - page0) > TARGET_PAGE_SIZE) { /* if wide line, can use another page */ - update |= s->vram_updated[page0 + 1]; + update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE); } if (update) { if (y_start < 0) @@ -1278,7 +1470,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) } /* reset modified pages */ if (page_max != -1) { - memset(s->vram_updated + page_min, 0, page_max - page_min + 1); + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE); } } @@ -1420,9 +1612,23 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, register_ioport_read(0x3ba, 1, vga_ioport_read, 1); register_ioport_read(0x3da, 1, vga_ioport_read, 1); +#ifdef CONFIG_BOCHS_VBE + s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0; + register_ioport_read(0x1ce, 1, vbe_ioport_read, 2); + register_ioport_read(0x1cf, 1, vbe_ioport_read, 2); + + register_ioport_write(0x1ce, 1, vbe_ioport_write, 2); + register_ioport_write(0x1cf, 1, vbe_ioport_write, 2); +#endif + vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); #if defined (TARGET_I386) cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory); +#ifdef CONFIG_BOCHS_VBE + /* XXX: use optimized standard vga accesses */ + cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, + vga_ram_size, vga_ram_offset); +#endif #elif defined (TARGET_PPC) cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory); #endif diff --git a/hw/vga_template.h b/hw/vga_template.h index cc4df95e3..810b4b128 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -390,6 +390,26 @@ static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d, #endif } +/* + * 24 bit color + */ +static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + int w; + uint32_t r, g, b; + + w = width; + do { + b = s[0]; + g = s[1]; + r = s[2]; + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + s += 3; + d += BPP; + } while (--w != 0); +} + /* * 32 bit color */ diff --git a/vl.h b/vl.h index f99aa03d4..4c2ed6ee0 100644 --- a/vl.h +++ b/vl.h @@ -72,7 +72,7 @@ struct cow_header_v2 { /* vga.c */ -#define VGA_RAM_SIZE (8192 * 1024) +#define VGA_RAM_SIZE (4096 * 1024) typedef struct DisplayState { uint8_t *data; -- cgit v1.2.3 From 898712a85c80d037446c7c5871c2491ae7fdbad7 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 6 Feb 2004 19:56:42 +0000 Subject: sdl_cleanup fix (Martin Garton) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@603 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sdl.c b/sdl.c index 335ef8849..5f1538f03 100644 --- a/sdl.c +++ b/sdl.c @@ -52,6 +52,7 @@ static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static void sdl_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); SDL_UpdateRect(screen, x, y, w, h); } @@ -257,6 +258,11 @@ static void sdl_refresh(DisplayState *ds) } } +static void sdl_cleanup(void) +{ + SDL_Quit(); +} + void sdl_display_init(DisplayState *ds) { int flags; @@ -278,4 +284,6 @@ void sdl_display_init(DisplayState *ds) SDL_WM_SetCaption("QEMU", "QEMU"); SDL_EnableKeyRepeat(250, 50); gui_grab = 0; + + atexit(sdl_cleanup); } -- cgit v1.2.3 From 6411cfb6f3cec4f89735f22c56a35f5931dd07a4 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 6 Feb 2004 19:57:09 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@604 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 502f60f44..bfcf48881 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,6 @@ 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 -- cgit v1.2.3 From cae61cef8976a819e590df66068f056e758c7429 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 6 Feb 2004 23:58:08 +0000 Subject: bochs vbe: virtual screen support and bank switch (untested) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@605 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index a480ea79a..b3c462ccb 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -116,11 +116,13 @@ typedef struct VGAState { uint8_t dac_write_index; uint8_t dac_cache[3]; /* used when writing */ uint8_t palette[768]; + uint32_t bank_offset; #ifdef CONFIG_BOCHS_VBE uint16_t vbe_index; uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; uint32_t vbe_start_addr; uint32_t vbe_line_offset; + uint32_t vbe_bank_mask; #endif /* display refresh support */ DisplayState *ds; @@ -537,28 +539,34 @@ static void vbe_ioport_write(CPUState *env, uint32_t addr, uint32_t val) #endif switch(s->vbe_index) { case VBE_DISPI_INDEX_ID: - if (val != VBE_DISPI_ID0 && - val != VBE_DISPI_ID1 && - val != VBE_DISPI_ID2) - return; + if (val == VBE_DISPI_ID0 || + val == VBE_DISPI_ID1 || + val == VBE_DISPI_ID2) { + s->vbe_regs[s->vbe_index] = val; + } break; case VBE_DISPI_INDEX_XRES: - if ((val > VBE_DISPI_MAX_XRES) || ((val & 7) != 0)) - return; + if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) { + s->vbe_regs[s->vbe_index] = val; + } break; case VBE_DISPI_INDEX_YRES: - if (val > VBE_DISPI_MAX_YRES) - return; + if (val <= VBE_DISPI_MAX_YRES) { + s->vbe_regs[s->vbe_index] = val; + } break; case VBE_DISPI_INDEX_BPP: if (val == 0) val = 8; - if (val != 4 && val != 8 && val != 15 && - val != 16 && val != 24 && val != 32) - return; + if (val == 4 || val == 8 || val == 15 || + val == 16 || val == 24 || val == 32) { + s->vbe_regs[s->vbe_index] = val; + } break; case VBE_DISPI_INDEX_BANK: - val &= 0xff; + val &= s->vbe_bank_mask; + s->vbe_regs[s->vbe_index] = val; + s->bank_offset = (val << 16) - 0xa0000; break; case VBE_DISPI_INDEX_ENABLE: if (val & VBE_DISPI_ENABLED) { @@ -584,9 +592,9 @@ static void vbe_ioport_write(CPUState *env, uint32_t addr, uint32_t val) s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); } - /* we initialize graphic mode force graphic mode - (should be done in BIOS) */ - s->gr[6] |= 1; + /* we initialize the VGA graphic mode (should be done + in BIOS) */ + s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */ s->cr[0x17] |= 3; /* no CGA modes */ s->cr[0x13] = s->vbe_line_offset >> 3; /* width */ @@ -609,12 +617,49 @@ static void vbe_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5); s->cr[0x09] &= ~0x9f; /* no double scan */ + s->vbe_regs[s->vbe_index] = val; + } else { + /* XXX: the bios should do that */ + s->bank_offset = -0xa0000; + } + break; + case VBE_DISPI_INDEX_VIRT_WIDTH: + { + int w, h, line_offset; + + if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES]) + return; + w = val; + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) + line_offset = w >> 1; + else + line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); + h = s->vram_size / line_offset; + /* XXX: support weird bochs semantics ? */ + if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES]) + return; + s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w; + s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h; + s->vbe_line_offset = line_offset; + } + break; + case VBE_DISPI_INDEX_X_OFFSET: + case VBE_DISPI_INDEX_Y_OFFSET: + { + int x; + s->vbe_regs[s->vbe_index] = val; + s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET]; + x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET]; + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) + s->vbe_start_addr += x >> 1; + else + s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); + s->vbe_start_addr >>= 2; } break; default: break; } - s->vbe_regs[s->vbe_index] = val; } } #endif @@ -633,9 +678,9 @@ static uint32_t vga_mem_readb(uint32_t addr) addr -= 0xa0000; break; case 1: - addr -= 0xa0000; - if (addr >= 0x10000) + if (addr >= 0xb0000) return 0xff; + addr += s->bank_offset; break; case 2: addr -= 0xb0000; @@ -711,9 +756,9 @@ void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) addr -= 0xa0000; break; case 1: - addr -= 0xa0000; - if (addr >= 0x10000) + if (addr >= 0xb0000) return; + addr += s->bank_offset; break; case 2: addr -= 0xb0000; @@ -1611,9 +1656,11 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, register_ioport_read(0x3d4, 2, vga_ioport_read, 1); register_ioport_read(0x3ba, 1, vga_ioport_read, 1); register_ioport_read(0x3da, 1, vga_ioport_read, 1); + s->bank_offset = -0xa0000; #ifdef CONFIG_BOCHS_VBE s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0; + s->vbe_bank_mask = ((s->vram_size >> 16) - 1); register_ioport_read(0x1ce, 1, vbe_ioport_read, 2); register_ioport_read(0x1cf, 1, vbe_ioport_read, 2); -- cgit v1.2.3 From 34f715e754adad52939d7b187fec655ddf3e0ba8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 7 Feb 2004 20:42:14 +0000 Subject: fixed WP semantics git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@606 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 47a93cddf..f5c31d0df 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -320,7 +320,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, if (is_write && !(pde & PG_RW_MASK)) goto do_fault_protect; } else { - if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && + if ((env->cr[0] & CR0_WP_MASK) && is_write && !(pde & PG_RW_MASK)) goto do_fault_protect; } @@ -358,7 +358,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, if (is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } else { - if ((env->cr[0] & CR0_WP_MASK) && (ptep & PG_USER_MASK) && + if ((env->cr[0] & CR0_WP_MASK) && is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } @@ -382,7 +382,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, if (ptep & PG_RW_MASK) prot |= PROT_WRITE; } else { - if (!(env->cr[0] & CR0_WP_MASK) || !(ptep & PG_USER_MASK) || + if (!(env->cr[0] & CR0_WP_MASK) || (ptep & PG_RW_MASK)) prot |= PROT_WRITE; } -- cgit v1.2.3 From 72cbca10e184637ec0e813ead71975b7446cc695 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 20:30:05 +0000 Subject: direct chaining support for SPARC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@607 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 33 +++++++++++--- target-sparc/translate.c | 112 ++++++++++++++++++++++++++++++----------------- 2 files changed, 97 insertions(+), 48 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index e466e09f8..1ce3f9509 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -643,24 +643,43 @@ void OPPROTO op_next_insn(void) env->npc = env->npc + 4; } -void OPPROTO op_generic_branch(void) +void OPPROTO op_branch(void) +{ + env->npc = PARAM3; /* XXX: optimize */ + JUMP_TB(op_branch, PARAM1, 0, PARAM2); +} + +void OPPROTO op_branch2(void) { if (T2) { - env->npc = PARAM1; + env->npc = PARAM2 + 4; + JUMP_TB(op_branch2, PARAM1, 0, PARAM2); } else { - env->npc = PARAM2; + env->npc = PARAM3 + 4; + JUMP_TB(op_branch2, PARAM1, 1, PARAM3); + } + FORCE_RET(); +} + +void OPPROTO op_branch_a(void) +{ + if (T2) { + env->npc = PARAM2; /* XXX: optimize */ + JUMP_TB(op_generic_branch_a, PARAM1, 0, PARAM3); + } else { + env->npc = PARAM3 + 8; /* XXX: optimize */ + JUMP_TB(op_generic_branch_a, PARAM1, 1, PARAM3 + 4); } FORCE_RET(); } -void OPPROTO op_generic_branch_a(void) +void OPPROTO op_generic_branch(void) { if (T2) { - env->pc = PARAM2; env->npc = PARAM1; } else { - env->pc = PARAM2 + 4; - env->npc = PARAM2 + 8; + env->npc = PARAM2; } FORCE_RET(); } + diff --git a/target-sparc/translate.c b/target-sparc/translate.c index f9c28d080..321b4eba4 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -42,9 +42,14 @@ #define DEBUG_DISAS +#define DYNAMIC_PC 1 /* dynamic pc value */ +#define JUMP_PC 2 /* dynamic pc value which takes only two values + according to jump_pc[T2] */ + typedef struct DisasContext { - uint8_t *pc; /* NULL means dynamic value */ - uint8_t *npc; /* NULL means dynamic value */ + target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ + target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ + target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ int is_br; struct TranslationBlock *tb; } DisasContext; @@ -306,6 +311,31 @@ static inline void gen_movl_T1_reg(int reg) gen_movl_TN_reg(reg, 1); } +/* call this function before using T2 as it may have been set for a jump */ +static inline void flush_T2(DisasContext * dc) +{ + if (dc->npc == JUMP_PC) { + gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); + dc->npc = DYNAMIC_PC; + } +} + +static inline void save_npc(DisasContext * dc) +{ + if (dc->npc == JUMP_PC) { + gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); + dc->npc = DYNAMIC_PC; + } else if (dc->npc != DYNAMIC_PC) { + gen_op_movl_npc_im(dc->npc); + } +} + +static inline void save_state(DisasContext * dc) +{ + gen_op_jmp_im((uint32_t)dc->pc); + save_npc(dc); +} + static void gen_cond(int cond) { switch (cond) { @@ -378,25 +408,23 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) } else if (cond == 0x8) { /* unconditional taken */ if (a) { - dc->pc = (uint8_t *) target; + dc->pc = target; dc->npc = dc->pc + 4; } else { dc->pc = dc->npc; - dc->npc = (uint8_t *) target; + dc->npc = target; } } else { + flush_T2(dc); gen_cond(cond); if (a) { - gen_op_generic_branch_a((uint32_t) target, - (uint32_t) (dc->npc)); + gen_op_branch_a((long)dc->tb, target, dc->npc); dc->is_br = 1; - dc->pc = NULL; - dc->npc = NULL; } else { dc->pc = dc->npc; - gen_op_generic_branch((uint32_t) target, - (uint32_t) (dc->npc + 4)); - dc->npc = NULL; + dc->jump_pc[0] = target; + dc->jump_pc[1] = dc->npc + 4; + dc->npc = JUMP_PC; } } } @@ -409,18 +437,11 @@ static int sign_extend(int x, int len) return (x << len) >> len; } -static inline void save_state(DisasContext * dc) -{ - gen_op_jmp_im((uint32_t)dc->pc); - if (dc->npc != NULL) - gen_op_movl_npc_im((long) dc->npc); -} - static void disas_sparc_insn(DisasContext * dc) { unsigned int insn, opc, rs1, rs2, rd; - insn = ldl_code(dc->pc); + insn = ldl_code((uint8_t *)dc->pc); opc = GET_FIELD(insn, 0, 1); rd = GET_FIELD(insn, 2, 6); @@ -458,9 +479,9 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movl_T0_im((long) (dc->pc)); gen_movl_T0_reg(15); - target = (long) dc->pc + target; + target = dc->pc + target; dc->pc = dc->npc; - dc->npc = (uint8_t *) target; + dc->npc = target; } goto jmp_insn; case 2: /* FPU & Logical Operations */ @@ -625,7 +646,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); } dc->pc = dc->npc; - dc->npc = NULL; + dc->npc = DYNAMIC_PC; } goto jmp_insn; case 0x3b: /* flush */ @@ -705,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_sth(); break; case 0x7: + flush_T2(dc); gen_movl_reg_T2(rd + 1); gen_op_std(); break; @@ -713,19 +735,21 @@ static void disas_sparc_insn(DisasContext * dc) } } /* default case for non jump instructions */ - if (dc->npc != NULL) { + if (dc->npc == DYNAMIC_PC) { + dc->pc = DYNAMIC_PC; + gen_op_next_insn(); + } else if (dc->npc == JUMP_PC) { + /* we can do a static jump */ + gen_op_branch2((long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]); + dc->is_br = 1; + } else { dc->pc = dc->npc; dc->npc = dc->npc + 4; - } else { - dc->pc = NULL; - gen_op_next_insn(); } jmp_insn:; return; illegal_insn: - gen_op_jmp_im((uint32_t)dc->pc); - if (dc->npc != NULL) - gen_op_movl_npc_im((long) dc->npc); + save_state(dc); gen_op_exception(TT_ILL_INSN); dc->is_br = 1; } @@ -733,7 +757,7 @@ static void disas_sparc_insn(DisasContext * dc) static inline int gen_intermediate_code_internal(TranslationBlock * tb, int spc) { - uint8_t *pc_start, *last_pc; + target_ulong pc_start, last_pc; uint16_t *gen_opc_end; DisasContext dc1, *dc = &dc1; @@ -743,9 +767,9 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, exit(0); } dc->tb = tb; - pc_start = (uint8_t *) tb->pc; + pc_start = tb->pc; dc->pc = pc_start; - dc->npc = (uint8_t *) tb->cs_base; + dc->npc = (target_ulong) tb->cs_base; gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; @@ -761,19 +785,25 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, break; } while ((gen_opc_ptr < gen_opc_end) && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); - if (dc->pc != NULL) - gen_op_jmp_im((long) dc->pc); - if (dc->npc != NULL) - gen_op_movl_npc_im((long) dc->npc); - gen_op_movl_T0_0(); - gen_op_exit_tb(); - + if (!dc->is_br) { + if (dc->pc != DYNAMIC_PC && + (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { + /* static PC and NPC: we can use direct chaining */ + gen_op_branch((long)tb, dc->pc, dc->npc); + } else { + if (dc->pc != DYNAMIC_PC) + gen_op_jmp_im(dc->pc); + save_npc(dc); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + } + } *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "--------------\n"); - fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0); + fprintf(logfile, "IN: %s\n", lookup_symbol((uint8_t *)pc_start)); + disas(logfile, (uint8_t *)pc_start, last_pc + 4 - pc_start, 0, 0); fprintf(logfile, "\n"); fprintf(logfile, "OP:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); -- cgit v1.2.3 From 69de927c6cf7e77508c16d13057122398abe20ec Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:40:43 +0000 Subject: arm nwfpe support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@608 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index 392365d7b..0caae4277 100755 --- a/configure +++ b/configure @@ -345,6 +345,10 @@ fi echo "Creating $config_mak, $config_h and $target_dir/Makefile" mkdir -p $target_dir +if test "$target" = "arm-user" ; then + mkdir -p $target_dir/nwfpe +fi + ln -sf $source_path/Makefile.target $target_dir/Makefile echo "# Automatically generated by configure - do not modify" > $config_mak -- cgit v1.2.3 From 00406dff19893a4fb9fb582792a249b770eb1d11 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:43:58 +0000 Subject: added arm nwfpe support (initial patch by Ulrich Hecht) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@609 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/nwfpe/ARM-gcc.h | 120 ++ target-arm/nwfpe/double_cpdo.c | 288 +++ target-arm/nwfpe/extended_cpdo.c | 273 +++ target-arm/nwfpe/fpa11.c | 231 +++ target-arm/nwfpe/fpa11.h | 131 ++ target-arm/nwfpe/fpa11.inl | 51 + target-arm/nwfpe/fpa11_cpdo.c | 117 ++ target-arm/nwfpe/fpa11_cpdt.c | 358 ++++ target-arm/nwfpe/fpa11_cprt.c | 290 +++ target-arm/nwfpe/fpopcode.c | 148 ++ target-arm/nwfpe/fpopcode.h | 390 ++++ target-arm/nwfpe/fpsr.h | 108 ++ target-arm/nwfpe/milieu.h | 48 + target-arm/nwfpe/single_cpdo.c | 255 +++ target-arm/nwfpe/softfloat-macros | 740 +++++++ target-arm/nwfpe/softfloat-specialize | 366 ++++ target-arm/nwfpe/softfloat.c | 3427 +++++++++++++++++++++++++++++++++ target-arm/nwfpe/softfloat.h | 232 +++ 18 files changed, 7573 insertions(+) create mode 100644 target-arm/nwfpe/ARM-gcc.h create mode 100644 target-arm/nwfpe/double_cpdo.c create mode 100644 target-arm/nwfpe/extended_cpdo.c create mode 100644 target-arm/nwfpe/fpa11.c create mode 100644 target-arm/nwfpe/fpa11.h create mode 100644 target-arm/nwfpe/fpa11.inl create mode 100644 target-arm/nwfpe/fpa11_cpdo.c create mode 100644 target-arm/nwfpe/fpa11_cpdt.c create mode 100644 target-arm/nwfpe/fpa11_cprt.c create mode 100644 target-arm/nwfpe/fpopcode.c create mode 100644 target-arm/nwfpe/fpopcode.h create mode 100644 target-arm/nwfpe/fpsr.h create mode 100644 target-arm/nwfpe/milieu.h create mode 100644 target-arm/nwfpe/single_cpdo.c create mode 100644 target-arm/nwfpe/softfloat-macros create mode 100644 target-arm/nwfpe/softfloat-specialize create mode 100644 target-arm/nwfpe/softfloat.c create mode 100644 target-arm/nwfpe/softfloat.h diff --git a/target-arm/nwfpe/ARM-gcc.h b/target-arm/nwfpe/ARM-gcc.h new file mode 100644 index 000000000..e6598470b --- /dev/null +++ b/target-arm/nwfpe/ARM-gcc.h @@ -0,0 +1,120 @@ +/* +------------------------------------------------------------------------------- +The macro `BITS64' can be defined to indicate that 64-bit integer types are +supported by the compiler. +------------------------------------------------------------------------------- +*/ +#define BITS64 + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines the most convenient type that holds +integers of at least as many bits as specified. For example, `uint8' should +be the most convenient type that can hold unsigned integers of as many as +8 bits. The `flag' type must be able to hold either a 0 or 1. For most +implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +to the same as `int'. +------------------------------------------------------------------------------- +*/ +typedef char flag; +typedef unsigned char uint8; +typedef signed char int8; +typedef int uint16; +typedef int int16; +typedef unsigned int uint32; +typedef signed int int32; +#ifdef BITS64 +typedef unsigned long long int bits64; +typedef signed long long int sbits64; +#endif + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines a type that holds integers +of _exactly_ the number of bits specified. For instance, for most +implementation of C, `bits16' and `sbits16' should be `typedef'ed to +`unsigned short int' and `signed short int' (or `short int'), respectively. +------------------------------------------------------------------------------- +*/ +typedef unsigned char bits8; +typedef signed char sbits8; +typedef unsigned short int bits16; +typedef signed short int sbits16; +typedef unsigned int bits32; +typedef signed int sbits32; +#ifdef BITS64 +typedef unsigned long long int uint64; +typedef signed long long int int64; +#endif + +#ifdef BITS64 +/* +------------------------------------------------------------------------------- +The `LIT64' macro takes as its argument a textual integer literal and if +necessary ``marks'' the literal as having a 64-bit integer type. For +example, the Gnu C Compiler (`gcc') requires that 64-bit literals be +appended with the letters `LL' standing for `long long', which is `gcc's +name for the 64-bit integer type. Some compilers may allow `LIT64' to be +defined as the identity macro: `#define LIT64( a ) a'. +------------------------------------------------------------------------------- +*/ +#define LIT64( a ) a##LL +#endif + +/* +------------------------------------------------------------------------------- +The macro `INLINE' can be used before functions that should be inlined. If +a compiler does not support explicit inlining, this macro should be defined +to be `static'. +------------------------------------------------------------------------------- +*/ +#define INLINE extern __inline__ + + +/* For use as a GCC soft-float library we need some special function names. */ + +#ifdef __LIBFLOAT__ + +/* Some 32-bit ops can be mapped straight across by just changing the name. */ +#define float32_add __addsf3 +#define float32_sub __subsf3 +#define float32_mul __mulsf3 +#define float32_div __divsf3 +#define int32_to_float32 __floatsisf +#define float32_to_int32_round_to_zero __fixsfsi +#define float32_to_uint32_round_to_zero __fixunssfsi + +/* These ones go through the glue code. To avoid namespace pollution + we rename the internal functions too. */ +#define float32_eq ___float32_eq +#define float32_le ___float32_le +#define float32_lt ___float32_lt + +/* All the 64-bit ops have to go through the glue, so we pull the same + trick. */ +#define float64_add ___float64_add +#define float64_sub ___float64_sub +#define float64_mul ___float64_mul +#define float64_div ___float64_div +#define int32_to_float64 ___int32_to_float64 +#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero +#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero +#define float64_to_float32 ___float64_to_float32 +#define float32_to_float64 ___float32_to_float64 +#define float64_eq ___float64_eq +#define float64_le ___float64_le +#define float64_lt ___float64_lt + +#if 0 +#define float64_add __adddf3 +#define float64_sub __subdf3 +#define float64_mul __muldf3 +#define float64_div __divdf3 +#define int32_to_float64 __floatsidf +#define float64_to_int32_round_to_zero __fixdfsi +#define float64_to_uint32_round_to_zero __fixunsdfsi +#define float64_to_float32 __truncdfsf2 +#define float32_to_float64 __extendsfdf2 +#endif + +#endif diff --git a/target-arm/nwfpe/double_cpdo.c b/target-arm/nwfpe/double_cpdo.c new file mode 100644 index 000000000..0f303ea6f --- /dev/null +++ b/target-arm/nwfpe/double_cpdo.c @@ -0,0 +1,288 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +float64 float64_exp(float64 Fm); +float64 float64_ln(float64 Fm); +float64 float64_sin(float64 rFm); +float64 float64_cos(float64 rFm); +float64 float64_arcsin(float64 rFm); +float64 float64_arctan(float64 rFm); +float64 float64_log(float64 rFm); +float64 float64_tan(float64 rFm); +float64 float64_arccos(float64 rFm); +float64 float64_pow(float64 rFn,float64 rFm); +float64 float64_pol(float64 rFn,float64 rFm); + +unsigned int DoubleCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + float64 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //printk("DoubleCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getDoubleConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + rFm = fpa11->fpreg[Fm].fDouble; + break; + + case typeExtended: + // !! patb + //printk("not implemented! why not?\n"); + //!! ScottB + // should never get here, if extended involved + // then other operand should be promoted then + // ExtendedCPDO called. + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + rFn = fpa11->fpreg[Fn].fDouble; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fDouble = rFm; + break; + + case MNF_CODE: + { + unsigned int *p = (unsigned int*)&rFm; + p[1] ^= 0x80000000; + fpa11->fpreg[Fd].fDouble = rFm; + } + break; + + case ABS_CODE: + { + unsigned int *p = (unsigned int*)&rFm; + p[1] &= 0x7fffffff; + fpa11->fpreg[Fd].fDouble = rFm; + } + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fDouble = float64_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fDouble = float64_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fDouble = float64_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fDouble = float64_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fDouble = float64_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fDouble = float64_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fDouble = float64_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fDouble = float64_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeDouble; + return nRc; +} + +#if 0 +float64 float64_exp(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_ln(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_sin(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_cos(float64 rFm) +{ + return rFm; + //series +} + +#if 0 +float64 float64_arcsin(float64 rFm) +{ +//series +} + +float64 float64_arctan(float64 rFm) +{ + //series +} +#endif + +float64 float64_log(float64 rFm) +{ + return float64_div(float64_ln(rFm),getDoubleConstant(7)); +} + +float64 float64_tan(float64 rFm) +{ + return float64_div(float64_sin(rFm),float64_cos(rFm)); +} + +float64 float64_arccos(float64 rFm) +{ +return rFm; + //return float64_sub(halfPi,float64_arcsin(rFm)); +} + +float64 float64_pow(float64 rFn,float64 rFm) +{ + return float64_exp(float64_mul(rFm,float64_ln(rFn))); +} + +float64 float64_pol(float64 rFn,float64 rFm) +{ + return float64_arctan(float64_div(rFn,rFm)); +} +#endif diff --git a/target-arm/nwfpe/extended_cpdo.c b/target-arm/nwfpe/extended_cpdo.c new file mode 100644 index 000000000..331407596 --- /dev/null +++ b/target-arm/nwfpe/extended_cpdo.c @@ -0,0 +1,273 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +floatx80 floatx80_exp(floatx80 Fm); +floatx80 floatx80_ln(floatx80 Fm); +floatx80 floatx80_sin(floatx80 rFm); +floatx80 floatx80_cos(floatx80 rFm); +floatx80 floatx80_arcsin(floatx80 rFm); +floatx80 floatx80_arctan(floatx80 rFm); +floatx80 floatx80_log(floatx80 rFm); +floatx80 floatx80_tan(floatx80 rFm); +floatx80 floatx80_arccos(floatx80 rFm); +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); + +unsigned int ExtendedCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + floatx80 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //printk("ExtendedCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getExtendedConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + break; + + case typeExtended: + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case MNF_CODE: + rFm.high ^= 0x8000; + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case ABS_CODE: + rFm.high &= 0x7fff; + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeExtended; + return nRc; +} + +#if 0 +floatx80 floatx80_exp(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_ln(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_sin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_cos(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arcsin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arctan(floatx80 rFm) +{ + //series +} + +floatx80 floatx80_log(floatx80 rFm) +{ + return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); +} + +floatx80 floatx80_tan(floatx80 rFm) +{ + return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); +} + +floatx80 floatx80_arccos(floatx80 rFm) +{ + //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); +} + +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) +{ + return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); +} + +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) +{ + return floatx80_arctan(floatx80_div(rFn,rFm)); +} +#endif diff --git a/target-arm/nwfpe/fpa11.c b/target-arm/nwfpe/fpa11.c new file mode 100644 index 000000000..143bcd399 --- /dev/null +++ b/target-arm/nwfpe/fpa11.c @@ -0,0 +1,231 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" + +#include "fpopcode.h" + +//#include "fpmodule.h" +//#include "fpmodule.inl" + +//#include + +#include + +/* forward declarations */ +unsigned int EmulateCPDO(const unsigned int); +unsigned int EmulateCPDT(const unsigned int); +unsigned int EmulateCPRT(const unsigned int); + +FPA11* qemufpa=0; +unsigned int* user_registers=0; + +/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ +void resetFPA11(void) +{ + int i; + FPA11 *fpa11 = GET_FPA11(); + + /* initialize the register type array */ + for (i=0;i<=7;i++) + { + fpa11->fType[i] = typeNone; + } + + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ + fpa11->fpsr = FP_EMULATOR | BIT_AC; + + /* FPCR: set SB, AB and DA bits, clear all others */ +#if MAINTAIN_FPCR + fpa11->fpcr = MASK_RESET; +#endif +} + +void SetRoundingMode(const unsigned int opcode) +{ +#if MAINTAIN_FPCR + FPA11 *fpa11 = GET_FPA11(); + fpa11->fpcr &= ~MASK_ROUNDING_MODE; +#endif + switch (opcode & MASK_ROUNDING_MODE) + { + default: + case ROUND_TO_NEAREST: + float_rounding_mode = float_round_nearest_even; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_NEAREST; +#endif + break; + + case ROUND_TO_PLUS_INFINITY: + float_rounding_mode = float_round_up; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; +#endif + break; + + case ROUND_TO_MINUS_INFINITY: + float_rounding_mode = float_round_down; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; +#endif + break; + + case ROUND_TO_ZERO: + float_rounding_mode = float_round_to_zero; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_ZERO; +#endif + break; + } +} + +void SetRoundingPrecision(const unsigned int opcode) +{ +#if MAINTAIN_FPCR + FPA11 *fpa11 = GET_FPA11(); + fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; +#endif + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + floatx80_rounding_precision = 32; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_SINGLE; +#endif + break; + + case ROUND_DOUBLE: + floatx80_rounding_precision = 64; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_DOUBLE; +#endif + break; + + case ROUND_EXTENDED: + floatx80_rounding_precision = 80; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_EXTENDED; +#endif + break; + + default: floatx80_rounding_precision = 80; + } +} + +/* Emulate the instruction in the opcode. */ +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs) +{ + unsigned int nRc = 0; +// unsigned long flags; + FPA11 *fpa11; +// save_flags(flags); sti(); + + qemufpa=qfpa; + user_registers=qregs; + +#if 0 + fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", + opcode, qregs[REG_PC]); +#endif + fpa11 = GET_FPA11(); + + if (fpa11->initflag == 0) /* good place for __builtin_expect */ + { + resetFPA11(); + SetRoundingMode(ROUND_TO_NEAREST); + SetRoundingPrecision(ROUND_EXTENDED); + fpa11->initflag = 1; + } + + if (TEST_OPCODE(opcode,MASK_CPRT)) + { + //fprintf(stderr,"emulating CPRT\n"); + /* Emulate conversion opcodes. */ + /* Emulate register transfer opcodes. */ + /* Emulate comparison opcodes. */ + nRc = EmulateCPRT(opcode); + } + else if (TEST_OPCODE(opcode,MASK_CPDO)) + { + //fprintf(stderr,"emulating CPDO\n"); + /* Emulate monadic arithmetic opcodes. */ + /* Emulate dyadic arithmetic opcodes. */ + nRc = EmulateCPDO(opcode); + } + else if (TEST_OPCODE(opcode,MASK_CPDT)) + { + //fprintf(stderr,"emulating CPDT\n"); + /* Emulate load/store opcodes. */ + /* Emulate load/store multiple opcodes. */ + nRc = EmulateCPDT(opcode); + } + else + { + /* Invalid instruction detected. Return FALSE. */ + nRc = 0; + } + +// restore_flags(flags); + + //printf("returning %d\n",nRc); + return(nRc); +} + +#if 0 +unsigned int EmulateAll1(unsigned int opcode) +{ + switch ((opcode >> 24) & 0xf) + { + case 0xc: + case 0xd: + if ((opcode >> 20) & 0x1) + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformLDF(opcode); break; + case 0x2: return PerformLFM(opcode); break; + default: return 0; + } + } + else + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformSTF(opcode); break; + case 0x2: return PerformSFM(opcode); break; + default: return 0; + } + } + break; + + case 0xe: + if (opcode & 0x10) + return EmulateCPDO(opcode); + else + return EmulateCPRT(opcode); + break; + + default: return 0; + } +} +#endif + diff --git a/target-arm/nwfpe/fpa11.h b/target-arm/nwfpe/fpa11.h new file mode 100644 index 000000000..95ad11936 --- /dev/null +++ b/target-arm/nwfpe/fpa11.h @@ -0,0 +1,131 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#ifndef __FPA11_H__ +#define __FPA11_H__ + +#define GET_FPA11() (qemufpa) + +/* + * The processes registers are always at the very top of the 8K + * stack+task struct. Use the same method as 'current' uses to + * reach them. + */ +extern unsigned int *user_registers; + +#define GET_USERREG() (user_registers) + +/* Need task_struct */ +//#include + +/* includes */ +#include "fpsr.h" /* FP control and status register definitions */ +#include "softfloat.h" + +#define typeNone 0x00 +#define typeSingle 0x01 +#define typeDouble 0x02 +#define typeExtended 0x03 + +/* + * This must be no more and no less than 12 bytes. + */ +typedef union tagFPREG { + floatx80 fExtended; + float64 fDouble; + float32 fSingle; +} FPREG; + +/* + * FPA11 device model. + * + * This structure is exported to user space. Do not re-order. + * Only add new stuff to the end, and do not change the size of + * any element. Elements of this structure are used by user + * space, and must match struct user_fp in include/asm-arm/user.h. + * We include the byte offsets below for documentation purposes. + * + * The size of this structure and FPREG are checked by fpmodule.c + * on initialisation. If the rules have been broken, NWFPE will + * not initialise. + */ +typedef struct tagFPA11 { +/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ +/* 96 */ FPSR fpsr; /* floating point status register */ +/* 100 */ FPCR fpcr; /* floating point control register */ +/* 104 */ unsigned char fType[8]; /* type of floating point value held in + floating point registers. One of none + single, double or extended. */ +/* 112 */ int initflag; /* this is special. The kernel guarantees + to set it to 0 when a thread is launched, + so we can use it to detect whether this + instance of the emulator needs to be + initialised. */ +} FPA11; + +extern FPA11* qemufpa; + +extern void resetFPA11(void); +extern void SetRoundingMode(const unsigned int); +extern void SetRoundingPrecision(const unsigned int); + +#define get_user(x,y) ((x)=*(y)) +#define put_user(x,y) (*(y)=(x)) +static inline unsigned int readRegister(unsigned int reg) +{ + return (user_registers[(reg)]); +} + +static inline void writeRegister(unsigned int x, unsigned int y) +{ +#if 0 + printf("writing %d to r%d\n",y,x); +#endif + user_registers[(x)]=(y); +} + +static inline void writeConditionCodes(unsigned int x) +{ +#if 0 +unsigned int y; +unsigned int ZF; + printf("setting flags to %x from %x\n",x,user_registers[16]); +#endif + user_registers[16]=(x); // cpsr + user_registers[17]=(x>>29)&1; // cf + user_registers[18]=(x<<3)&(1<<31); // vf + user_registers[19]=x&(1<<31); // nzf + if(!(x&(1<<30))) user_registers[19]++; // nzf must be non-zero for zf to be cleared + +#if 0 + ZF = (user_registers[19] == 0); + y=user_registers[16] | (user_registers[19] & 0x80000000) | (ZF << 30) | + (user_registers[17] << 29) | ((user_registers[18] & 0x80000000) >> 3); + if(y != x) + printf("GODDAM SHIIIIIIIIIIIIIIIIT! %x %x nzf %x zf %x\n",x,y,user_registers[19],ZF); +#endif +} + +#define REG_PC 15 + +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs); + +#endif diff --git a/target-arm/nwfpe/fpa11.inl b/target-arm/nwfpe/fpa11.inl new file mode 100644 index 000000000..1c45cba2d --- /dev/null +++ b/target-arm/nwfpe/fpa11.inl @@ -0,0 +1,51 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" + +/* Read and write floating point status register */ +extern __inline__ unsigned int readFPSR(void) +{ + FPA11 *fpa11 = GET_FPA11(); + return(fpa11->fpsr); +} + +extern __inline__ void writeFPSR(FPSR reg) +{ + FPA11 *fpa11 = GET_FPA11(); + /* the sysid byte in the status register is readonly */ + fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); +} + +/* Read and write floating point control register */ +extern __inline__ FPCR readFPCR(void) +{ + FPA11 *fpa11 = GET_FPA11(); + /* clear SB, AB and DA bits before returning FPCR */ + return(fpa11->fpcr & ~MASK_RFC); +} + +extern __inline__ void writeFPCR(FPCR reg) +{ + FPA11 *fpa11 = GET_FPA11(); + fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ + fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ +} diff --git a/target-arm/nwfpe/fpa11_cpdo.c b/target-arm/nwfpe/fpa11_cpdo.c new file mode 100644 index 000000000..343a6b9fd --- /dev/null +++ b/target-arm/nwfpe/fpa11_cpdo.c @@ -0,0 +1,117 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" +#include "fpopcode.h" + +unsigned int SingleCPDO(const unsigned int opcode); +unsigned int DoubleCPDO(const unsigned int opcode); +unsigned int ExtendedCPDO(const unsigned int opcode); + +unsigned int EmulateCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int Fd, nType, nDest, nRc = 1; + + //printk("EmulateCPDO(0x%08x)\n",opcode); + + /* Get the destination size. If not valid let Linux perform + an invalid instruction trap. */ + nDest = getDestinationSize(opcode); + if (typeNone == nDest) return 0; + + SetRoundingMode(opcode); + + /* Compare the size of the operands in Fn and Fm. + Choose the largest size and perform operations in that size, + in order to make use of all the precision of the operands. + If Fm is a constant, we just grab a constant of a size + matching the size of the operand in Fn. */ + if (MONADIC_INSTRUCTION(opcode)) + nType = nDest; + else + nType = fpa11->fType[getFn(opcode)]; + + if (!CONSTANT_FM(opcode)) + { + register unsigned int Fm = getFm(opcode); + if (nType < fpa11->fType[Fm]) + { + nType = fpa11->fType[Fm]; + } + } + + switch (nType) + { + case typeSingle : nRc = SingleCPDO(opcode); break; + case typeDouble : nRc = DoubleCPDO(opcode); break; + case typeExtended : nRc = ExtendedCPDO(opcode); break; + default : nRc = 0; + } + + /* If the operation succeeded, check to see if the result in the + destination register is the correct size. If not force it + to be. */ + Fd = getFd(opcode); + nType = fpa11->fType[Fd]; + if ((0 != nRc) && (nDest != nType)) + { + switch (nDest) + { + case typeSingle: + { + if (typeDouble == nType) + fpa11->fpreg[Fd].fSingle = + float64_to_float32(fpa11->fpreg[Fd].fDouble); + else + fpa11->fpreg[Fd].fSingle = + floatx80_to_float32(fpa11->fpreg[Fd].fExtended); + } + break; + + case typeDouble: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fDouble = + float32_to_float64(fpa11->fpreg[Fd].fSingle); + else + fpa11->fpreg[Fd].fDouble = + floatx80_to_float64(fpa11->fpreg[Fd].fExtended); + } + break; + + case typeExtended: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fExtended = + float32_to_floatx80(fpa11->fpreg[Fd].fSingle); + else + fpa11->fpreg[Fd].fExtended = + float64_to_floatx80(fpa11->fpreg[Fd].fDouble); + } + break; + } + + fpa11->fType[Fd] = nDest; + } + + return nRc; +} diff --git a/target-arm/nwfpe/fpa11_cpdt.c b/target-arm/nwfpe/fpa11_cpdt.c new file mode 100644 index 000000000..283e34673 --- /dev/null +++ b/target-arm/nwfpe/fpa11_cpdt.c @@ -0,0 +1,358 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + (c) Philip Blundell, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" +//#include "fpmodule.h" +//#include "fpmodule.inl" + +//#include + +static inline +void loadSingle(const unsigned int Fn,const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + fpa11->fType[Fn] = typeSingle; + get_user(fpa11->fpreg[Fn].fSingle, pMem); +} + +static inline +void loadDouble(const unsigned int Fn,const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; + fpa11->fType[Fn] = typeDouble; + get_user(p[0], &pMem[1]); + get_user(p[1], &pMem[0]); /* sign & exponent */ +} + +static inline +void loadExtended(const unsigned int Fn,const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; + fpa11->fType[Fn] = typeExtended; + get_user(p[0], &pMem[0]); /* sign & exponent */ + get_user(p[1], &pMem[2]); /* ls bits */ + get_user(p[2], &pMem[1]); /* ms bits */ +} + +static inline +void loadMultiple(const unsigned int Fn,const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + register unsigned int *p; + unsigned long x; + + p = (unsigned int*)&(fpa11->fpreg[Fn]); + get_user(x, &pMem[0]); + fpa11->fType[Fn] = (x >> 14) & 0x00000003; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + case typeDouble: + { + get_user(p[0], &pMem[2]); /* Single */ + get_user(p[1], &pMem[1]); /* double msw */ + p[2] = 0; /* empty */ + } + break; + + case typeExtended: + { + get_user(p[1], &pMem[2]); + get_user(p[2], &pMem[1]); /* msw */ + p[0] = (x & 0x80003fff); + } + break; + } +} + +static inline +void storeSingle(const unsigned int Fn,unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + float32 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeDouble: + val = float64_to_float32(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); + break; + + default: val = fpa11->fpreg[Fn].fSingle; + } + + put_user(p[0], pMem); +} + +static inline +void storeDouble(const unsigned int Fn,unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + float64 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + val = float32_to_float64(fpa11->fpreg[Fn].fSingle); + break; + + case typeExtended: + val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); + break; + + default: val = fpa11->fpreg[Fn].fDouble; + } + put_user(p[1], &pMem[0]); /* msw */ + put_user(p[0], &pMem[1]); /* lsw */ +} + +static inline +void storeExtended(const unsigned int Fn,unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + floatx80 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + default: val = fpa11->fpreg[Fn].fExtended; + } + + put_user(p[0], &pMem[0]); /* sign & exp */ + put_user(p[1], &pMem[2]); + put_user(p[2], &pMem[1]); /* msw */ +} + +static inline +void storeMultiple(const unsigned int Fn,unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + register unsigned int nType, *p; + + p = (unsigned int*)&(fpa11->fpreg[Fn]); + nType = fpa11->fType[Fn]; + + switch (nType) + { + case typeSingle: + case typeDouble: + { + put_user(p[0], &pMem[2]); /* single */ + put_user(p[1], &pMem[1]); /* double msw */ + put_user(nType << 14, &pMem[0]); + } + break; + + case typeExtended: + { + put_user(p[2], &pMem[1]); /* msw */ + put_user(p[1], &pMem[2]); + put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); + } + break; + } +} + +unsigned int PerformLDF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); + + //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformSTF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); + + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + SetRoundingMode(ROUND_TO_NEAREST); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformLFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + loadMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +unsigned int PerformSFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + storeMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +#if 1 +unsigned int EmulateCPDT(const unsigned int opcode) +{ + unsigned int nRc = 0; + + //printk("EmulateCPDT(0x%08x)\n",opcode); + + if (LDF_OP(opcode)) + { + nRc = PerformLDF(opcode); + } + else if (LFM_OP(opcode)) + { + nRc = PerformLFM(opcode); + } + else if (STF_OP(opcode)) + { + nRc = PerformSTF(opcode); + } + else if (SFM_OP(opcode)) + { + nRc = PerformSFM(opcode); + } + else + { + nRc = 0; + } + + return nRc; +} +#endif diff --git a/target-arm/nwfpe/fpa11_cprt.c b/target-arm/nwfpe/fpa11_cprt.c new file mode 100644 index 000000000..17871c1d7 --- /dev/null +++ b/target-arm/nwfpe/fpa11_cprt.c @@ -0,0 +1,290 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + (c) Philip Blundell, 1999 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" +#include "milieu.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.inl" +//#include "fpmodule.h" +//#include "fpmodule.inl" + +extern flag floatx80_is_nan(floatx80); +extern flag float64_is_nan( float64); +extern flag float32_is_nan( float32); + +void SetRoundingMode(const unsigned int opcode); + +unsigned int PerformFLT(const unsigned int opcode); +unsigned int PerformFIX(const unsigned int opcode); + +static unsigned int +PerformComparison(const unsigned int opcode); + +unsigned int EmulateCPRT(const unsigned int opcode) +{ + unsigned int nRc = 1; + + //printk("EmulateCPRT(0x%08x)\n",opcode); + + if (opcode & 0x800000) + { + /* This is some variant of a comparison (PerformComparison will + sort out which one). Since most of the other CPRT + instructions are oddball cases of some sort or other it makes + sense to pull this out into a fast path. */ + return PerformComparison(opcode); + } + + /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ + switch ((opcode & 0x700000) >> 20) + { + case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; + case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; + + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; + case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; + +#if 0 /* We currently have no use for the FPCR, so there's no point + in emulating it. */ + case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); + case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; +#endif + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFLT(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + + unsigned int nRc = 1; + SetRoundingMode(opcode); + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + { + fpa11->fType[getFn(opcode)] = typeSingle; + fpa11->fpreg[getFn(opcode)].fSingle = + int32_to_float32(readRegister(getRd(opcode))); + } + break; + + case ROUND_DOUBLE: + { + fpa11->fType[getFn(opcode)] = typeDouble; + fpa11->fpreg[getFn(opcode)].fDouble = + int32_to_float64(readRegister(getRd(opcode))); + } + break; + + case ROUND_EXTENDED: + { + fpa11->fType[getFn(opcode)] = typeExtended; + fpa11->fpreg[getFn(opcode)].fExtended = + int32_to_floatx80(readRegister(getRd(opcode))); + } + break; + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFIX(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int nRc = 1; + unsigned int Fn = getFm(opcode); + + SetRoundingMode(opcode); + + switch (fpa11->fType[Fn]) + { + case typeSingle: + { + writeRegister(getRd(opcode), + float32_to_int32(fpa11->fpreg[Fn].fSingle)); + } + break; + + case typeDouble: + { + //printf("F%d is 0x%llx\n",Fn,fpa11->fpreg[Fn].fDouble); + writeRegister(getRd(opcode), + float64_to_int32(fpa11->fpreg[Fn].fDouble)); + } + break; + + case typeExtended: + { + writeRegister(getRd(opcode), + floatx80_to_int32(fpa11->fpreg[Fn].fExtended)); + } + break; + + default: nRc = 0; + } + + return nRc; +} + + +static unsigned int __inline__ +PerformComparisonOperation(floatx80 Fn, floatx80 Fm) +{ + unsigned int flags = 0; + + /* test for less than condition */ + if (floatx80_lt(Fn,Fm)) + { + flags |= CC_NEGATIVE; + } + + /* test for equal condition */ + if (floatx80_eq(Fn,Fm)) + { + flags |= CC_ZERO; + } + + /* test for greater than or equal condition */ + if (floatx80_lt(Fm,Fn)) + { + flags |= CC_CARRY; + } + + writeConditionCodes(flags); + return 1; +} + +/* This instruction sets the flags N, Z, C, V in the FPSR. */ + +static unsigned int PerformComparison(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int Fn, Fm; + floatx80 rFn, rFm; + int e_flag = opcode & 0x400000; /* 1 if CxFE */ + int n_flag = opcode & 0x200000; /* 1 if CNxx */ + unsigned int flags = 0; + + //printk("PerformComparison(0x%08x)\n",opcode); + + Fn = getFn(opcode); + Fm = getFm(opcode); + + /* Check for unordered condition and convert all operands to 80-bit + format. + ?? Might be some mileage in avoiding this conversion if possible. + Eg, if both operands are 32-bit, detect this and do a 32-bit + comparison (cheaper than an 80-bit one). */ + switch (fpa11->fType[Fn]) + { + case typeSingle: + //printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) + goto unordered; + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + //printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) + goto unordered; + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + //printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) + goto unordered; + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: return 0; + } + + if (CONSTANT_FM(opcode)) + { + //printk("Fm is a constant: #%d.\n",Fm); + rFm = getExtendedConstant(Fm); + if (floatx80_is_nan(rFm)) + goto unordered; + } + else + { + //printk("Fm = r%d which contains a ",Fm); + switch (fpa11->fType[Fm]) + { + case typeSingle: + //printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) + goto unordered; + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + //printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) + goto unordered; + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + break; + + case typeExtended: + //printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) + goto unordered; + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: return 0; + } + } + + if (n_flag) + { + rFm.high ^= 0x8000; + } + + return PerformComparisonOperation(rFn,rFm); + + unordered: + /* ?? The FPA data sheet is pretty vague about this, in particular + about whether the non-E comparisons can ever raise exceptions. + This implementation is based on a combination of what it says in + the data sheet, observation of how the Acorn emulator actually + behaves (and how programs expect it to) and guesswork. */ + flags |= CC_OVERFLOW; + flags &= ~(CC_ZERO | CC_NEGATIVE); + + if (BIT_AC & readFPSR()) flags |= CC_CARRY; + + if (e_flag) float_raise(float_flag_invalid); + + writeConditionCodes(flags); + return 1; +} diff --git a/target-arm/nwfpe/fpopcode.c b/target-arm/nwfpe/fpopcode.c new file mode 100644 index 000000000..0886a0bdf --- /dev/null +++ b/target-arm/nwfpe/fpopcode.c @@ -0,0 +1,148 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpsr.h" +//#include "fpmodule.h" +//#include "fpmodule.inl" + +const floatx80 floatx80Constant[] = { + { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ + { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ + { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ + { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ + { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ + { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ + { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ + { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ +}; + +const float64 float64Constant[] = { + 0x0000000000000000ULL, /* double 0.0 */ + 0x3ff0000000000000ULL, /* double 1.0 */ + 0x4000000000000000ULL, /* double 2.0 */ + 0x4008000000000000ULL, /* double 3.0 */ + 0x4010000000000000ULL, /* double 4.0 */ + 0x4014000000000000ULL, /* double 5.0 */ + 0x3fe0000000000000ULL, /* double 0.5 */ + 0x4024000000000000ULL /* double 10.0 */ +}; + +const float32 float32Constant[] = { + 0x00000000, /* single 0.0 */ + 0x3f800000, /* single 1.0 */ + 0x40000000, /* single 2.0 */ + 0x40400000, /* single 3.0 */ + 0x40800000, /* single 4.0 */ + 0x40a00000, /* single 5.0 */ + 0x3f000000, /* single 0.5 */ + 0x41200000 /* single 10.0 */ +}; + +unsigned int getTransferLength(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case 0x00000000: nRc = 1; break; /* single precision */ + case 0x00008000: nRc = 2; break; /* double precision */ + case 0x00400000: nRc = 3; break; /* extended precision */ + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRegisterCount(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_REGISTER_COUNT) + { + case 0x00000000: nRc = 4; break; + case 0x00008000: nRc = 1; break; + case 0x00400000: nRc = 2; break; + case 0x00408000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRoundingPrecision(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case 0x00000000: nRc = 1; break; + case 0x00000080: nRc = 2; break; + case 0x00080000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getDestinationSize(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_DESTINATION_SIZE) + { + case 0x00000000: nRc = typeSingle; break; + case 0x00000080: nRc = typeDouble; break; + case 0x00080000: nRc = typeExtended; break; + default: nRc = typeNone; + } + + return(nRc); +} + +/* condition code lookup table + index into the table is test code: EQ, NE, ... LT, GT, AL, NV + bit position in short is condition code: NZCV */ +static const unsigned short aCC[16] = { + 0xF0F0, // EQ == Z set + 0x0F0F, // NE + 0xCCCC, // CS == C set + 0x3333, // CC + 0xFF00, // MI == N set + 0x00FF, // PL + 0xAAAA, // VS == V set + 0x5555, // VC + 0x0C0C, // HI == C set && Z clear + 0xF3F3, // LS == C clear || Z set + 0xAA55, // GE == (N==V) + 0x55AA, // LT == (N!=V) + 0x0A05, // GT == (!Z && (N==V)) + 0xF5FA, // LE == (Z || (N!=V)) + 0xFFFF, // AL always + 0 // NV +}; + +unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) +{ + return (aCC[opcode>>28] >> (ccodes>>28)) & 1; +} diff --git a/target-arm/nwfpe/fpopcode.h b/target-arm/nwfpe/fpopcode.h new file mode 100644 index 000000000..13c741926 --- /dev/null +++ b/target-arm/nwfpe/fpopcode.h @@ -0,0 +1,390 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#ifndef __FPOPCODE_H__ +#define __FPOPCODE_H__ + +/* +ARM Floating Point Instruction Classes +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT +|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO +|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT +|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + +CPDT data transfer instructions + LDF, STF, LFM, SFM + +CPDO dyadic arithmetic instructions + ADF, MUF, SUF, RSF, DVF, RDF, + POW, RPW, RMF, FML, FDV, FRD, POL + +CPDO monadic arithmetic instructions + MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, + SIN, COS, TAN, ASN, ACS, ATN, URD, NRM + +CPRT joint arithmetic/data transfer instructions + FIX (arithmetic followed by load/store) + FLT (load/store followed by arithmetic) + CMF, CNF CMFE, CNFE (comparisons) + WFS, RFS (write/read floating point status register) + WFC, RFC (write/read floating point control register) + +cond condition codes +P pre/post index bit: 0 = postindex, 1 = preindex +U up/down bit: 0 = stack grows down, 1 = stack grows up +W write back bit: 1 = update base register (Rn) +L load/store bit: 0 = store, 1 = load +Rn base register +Rd destination/source register +Fd floating point destination register +Fn floating point source register +Fm floating point source register or floating point constant + +uv transfer length (TABLE 1) +wx register count (TABLE 2) +abcd arithmetic opcode (TABLES 3 & 4) +ef destination size (rounding precision) (TABLE 5) +gh rounding mode (TABLE 6) +j dyadic/monadic bit: 0 = dyadic, 1 = monadic +i constant bit: 1 = constant (TABLE 6) +*/ + +/* +TABLE 1 ++-------------------------+---+---+---------+---------+ +| Precision | u | v | FPSR.EP | length | ++-------------------------+---+---+---------+---------+ +| Single | 0 0 | x | 1 words | +| Double | 1 1 | x | 2 words | +| Extended | 1 1 | x | 3 words | +| Packed decimal | 1 1 | 0 | 3 words | +| Expanded packed decimal | 1 1 | 1 | 4 words | ++-------------------------+---+---+---------+---------+ +Note: x = don't care +*/ + +/* +TABLE 2 ++---+---+---------------------------------+ +| w | x | Number of registers to transfer | ++---+---+---------------------------------+ +| 0 1 | 1 | +| 1 0 | 2 | +| 1 1 | 3 | +| 0 0 | 4 | ++---+---+---------------------------------+ +*/ + +/* +TABLE 3: Dyadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | +| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | +| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | +| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | +| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | +| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | +| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | +| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | +| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | +| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | +| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | +| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | +| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | +| 1 | 1 | 0 | 1 | | undefined instruction | trap | +| 1 | 1 | 1 | 0 | | undefined instruction | trap | +| 1 | 1 | 1 | 1 | | undefined instruction | trap | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: POW, RPW, POL are deprecated, and are available for backwards + compatibility only. +*/ + +/* +TABLE 4: Monadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | +| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | +| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | +| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | +| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | +| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | +| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | +| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | +| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | +| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | +| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | +| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | +| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | +| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | +| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | +| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are + available for backwards compatibility only. +*/ + +/* +TABLE 5 ++-------------------------+---+---+ +| Rounding Precision | e | f | ++-------------------------+---+---+ +| IEEE Single precision | 0 0 | +| IEEE Double precision | 0 1 | +| IEEE Extended precision | 1 0 | +| undefined (trap) | 1 1 | ++-------------------------+---+---+ +*/ + +/* +TABLE 5 ++---------------------------------+---+---+ +| Rounding Mode | g | h | ++---------------------------------+---+---+ +| Round to nearest (default) | 0 0 | +| Round toward plus infinity | 0 1 | +| Round toward negative infinity | 1 0 | +| Round toward zero | 1 1 | ++---------------------------------+---+---+ +*/ + +/* +=== +=== Definitions for load and store instructions +=== +*/ + +/* bit masks */ +#define BIT_PREINDEX 0x01000000 +#define BIT_UP 0x00800000 +#define BIT_WRITE_BACK 0x00200000 +#define BIT_LOAD 0x00100000 + +/* masks for load/store */ +#define MASK_CPDT 0x0c000000 /* data processing opcode */ +#define MASK_OFFSET 0x000000ff +#define MASK_TRANSFER_LENGTH 0x00408000 +#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH +#define MASK_COPROCESSOR 0x00000f00 + +/* Tests for transfer length */ +#define TRANSFER_SINGLE 0x00000000 +#define TRANSFER_DOUBLE 0x00008000 +#define TRANSFER_EXTENDED 0x00400000 +#define TRANSFER_PACKED MASK_TRANSFER_LENGTH + +/* Get the coprocessor number from the opcode. */ +#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) + +/* Get the offset from the opcode. */ +#define getOffset(opcode) (opcode & MASK_OFFSET) + +/* Tests for specific data transfer load/store opcodes. */ +#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) + +#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) +#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) + +#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) +#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) + +#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) +#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) +#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) +#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) +#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) +#define LOAD(opcode) ((opcode & BIT_LOAD) != 0) +#define STORE(opcode) ((opcode & BIT_LOAD) == 0) + +/* +=== +=== Definitions for arithmetic instructions +=== +*/ +/* bit masks */ +#define BIT_MONADIC 0x00008000 +#define BIT_CONSTANT 0x00000008 + +#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) +#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) + +/* instruction identification masks */ +#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ +#define MASK_ARITHMETIC_OPCODE 0x00f08000 +#define MASK_DESTINATION_SIZE 0x00080080 + +/* dyadic arithmetic opcodes. */ +#define ADF_CODE 0x00000000 +#define MUF_CODE 0x00100000 +#define SUF_CODE 0x00200000 +#define RSF_CODE 0x00300000 +#define DVF_CODE 0x00400000 +#define RDF_CODE 0x00500000 +#define POW_CODE 0x00600000 +#define RPW_CODE 0x00700000 +#define RMF_CODE 0x00800000 +#define FML_CODE 0x00900000 +#define FDV_CODE 0x00a00000 +#define FRD_CODE 0x00b00000 +#define POL_CODE 0x00c00000 +/* 0x00d00000 is an invalid dyadic arithmetic opcode */ +/* 0x00e00000 is an invalid dyadic arithmetic opcode */ +/* 0x00f00000 is an invalid dyadic arithmetic opcode */ + +/* monadic arithmetic opcodes. */ +#define MVF_CODE 0x00008000 +#define MNF_CODE 0x00108000 +#define ABS_CODE 0x00208000 +#define RND_CODE 0x00308000 +#define SQT_CODE 0x00408000 +#define LOG_CODE 0x00508000 +#define LGN_CODE 0x00608000 +#define EXP_CODE 0x00708000 +#define SIN_CODE 0x00808000 +#define COS_CODE 0x00908000 +#define TAN_CODE 0x00a08000 +#define ASN_CODE 0x00b08000 +#define ACS_CODE 0x00c08000 +#define ATN_CODE 0x00d08000 +#define URD_CODE 0x00e08000 +#define NRM_CODE 0x00f08000 + +/* +=== +=== Definitions for register transfer and comparison instructions +=== +*/ + +#define MASK_CPRT 0x0e000010 /* register transfer opcode */ +#define MASK_CPRT_CODE 0x00f00000 +#define FLT_CODE 0x00000000 +#define FIX_CODE 0x00100000 +#define WFS_CODE 0x00200000 +#define RFS_CODE 0x00300000 +#define WFC_CODE 0x00400000 +#define RFC_CODE 0x00500000 +#define CMF_CODE 0x00900000 +#define CNF_CODE 0x00b00000 +#define CMFE_CODE 0x00d00000 +#define CNFE_CODE 0x00f00000 + +/* +=== +=== Common definitions +=== +*/ + +/* register masks */ +#define MASK_Rd 0x0000f000 +#define MASK_Rn 0x000f0000 +#define MASK_Fd 0x00007000 +#define MASK_Fm 0x00000007 +#define MASK_Fn 0x00070000 + +/* condition code masks */ +#define CC_MASK 0xf0000000 +#define CC_NEGATIVE 0x80000000 +#define CC_ZERO 0x40000000 +#define CC_CARRY 0x20000000 +#define CC_OVERFLOW 0x10000000 +#define CC_EQ 0x00000000 +#define CC_NE 0x10000000 +#define CC_CS 0x20000000 +#define CC_HS CC_CS +#define CC_CC 0x30000000 +#define CC_LO CC_CC +#define CC_MI 0x40000000 +#define CC_PL 0x50000000 +#define CC_VS 0x60000000 +#define CC_VC 0x70000000 +#define CC_HI 0x80000000 +#define CC_LS 0x90000000 +#define CC_GE 0xa0000000 +#define CC_LT 0xb0000000 +#define CC_GT 0xc0000000 +#define CC_LE 0xd0000000 +#define CC_AL 0xe0000000 +#define CC_NV 0xf0000000 + +/* rounding masks/values */ +#define MASK_ROUNDING_MODE 0x00000060 +#define ROUND_TO_NEAREST 0x00000000 +#define ROUND_TO_PLUS_INFINITY 0x00000020 +#define ROUND_TO_MINUS_INFINITY 0x00000040 +#define ROUND_TO_ZERO 0x00000060 + +#define MASK_ROUNDING_PRECISION 0x00080080 +#define ROUND_SINGLE 0x00000000 +#define ROUND_DOUBLE 0x00000080 +#define ROUND_EXTENDED 0x00080000 + +/* Get the condition code from the opcode. */ +#define getCondition(opcode) (opcode >> 28) + +/* Get the source register from the opcode. */ +#define getRn(opcode) ((opcode & MASK_Rn) >> 16) + +/* Get the destination floating point register from the opcode. */ +#define getFd(opcode) ((opcode & MASK_Fd) >> 12) + +/* Get the first source floating point register from the opcode. */ +#define getFn(opcode) ((opcode & MASK_Fn) >> 16) + +/* Get the second source floating point register from the opcode. */ +#define getFm(opcode) (opcode & MASK_Fm) + +/* Get the destination register from the opcode. */ +#define getRd(opcode) ((opcode & MASK_Rd) >> 12) + +/* Get the rounding mode from the opcode. */ +#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) + +static inline const floatx80 getExtendedConstant(const unsigned int nIndex) +{ + extern const floatx80 floatx80Constant[]; + return floatx80Constant[nIndex]; +} + +static inline const float64 getDoubleConstant(const unsigned int nIndex) +{ + extern const float64 float64Constant[]; + return float64Constant[nIndex]; +} + +static inline const float32 getSingleConstant(const unsigned int nIndex) +{ + extern const float32 float32Constant[]; + return float32Constant[nIndex]; +} + +extern unsigned int getRegisterCount(const unsigned int opcode); +extern unsigned int getDestinationSize(const unsigned int opcode); + +#endif diff --git a/target-arm/nwfpe/fpsr.h b/target-arm/nwfpe/fpsr.h new file mode 100644 index 000000000..6dafb0f52 --- /dev/null +++ b/target-arm/nwfpe/fpsr.h @@ -0,0 +1,108 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + + Direct questions, comments to Scott Bambrough + + 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. +*/ + +#ifndef __FPSR_H__ +#define __FPSR_H__ + +/* +The FPSR is a 32 bit register consisting of 4 parts, each exactly +one byte. + + SYSTEM ID + EXCEPTION TRAP ENABLE BYTE + SYSTEM CONTROL BYTE + CUMULATIVE EXCEPTION FLAGS BYTE + +The FPCR is a 32 bit register consisting of bit flags. +*/ + +/* SYSTEM ID +------------ +Note: the system id byte is read only */ + +typedef unsigned int FPSR; /* type for floating point status register */ +typedef unsigned int FPCR; /* type for floating point control register */ + +#define MASK_SYSID 0xff000000 +#define BIT_HARDWARE 0x80000000 +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ +#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ + +/* EXCEPTION TRAP ENABLE BYTE +----------------------------- */ + +#define MASK_TRAP_ENABLE 0x00ff0000 +#define MASK_TRAP_ENABLE_STRICT 0x001f0000 +#define BIT_IXE 0x00100000 /* inexact exception enable */ +#define BIT_UFE 0x00080000 /* underflow exception enable */ +#define BIT_OFE 0x00040000 /* overflow exception enable */ +#define BIT_DZE 0x00020000 /* divide by zero exception enable */ +#define BIT_IOE 0x00010000 /* invalid operation exception enable */ + +/* SYSTEM CONTROL BYTE +---------------------- */ + +#define MASK_SYSTEM_CONTROL 0x0000ff00 +#define MASK_TRAP_STRICT 0x00001f00 + +#define BIT_AC 0x00001000 /* use alternative C-flag definition + for compares */ +#define BIT_EP 0x00000800 /* use expanded packed decimal format */ +#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ +#define BIT_NE 0x00000200 /* NaN exception bit */ +#define BIT_ND 0x00000100 /* no denormalized numbers bit */ + +/* CUMULATIVE EXCEPTION FLAGS BYTE +---------------------------------- */ + +#define MASK_EXCEPTION_FLAGS 0x000000ff +#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f + +#define BIT_IXC 0x00000010 /* inexact exception flag */ +#define BIT_UFC 0x00000008 /* underflow exception flag */ +#define BIT_OFC 0x00000004 /* overfloat exception flag */ +#define BIT_DZC 0x00000002 /* divide by zero exception flag */ +#define BIT_IOC 0x00000001 /* invalid operation exception flag */ + +/* Floating Point Control Register +----------------------------------*/ + +#define BIT_RU 0x80000000 /* rounded up bit */ +#define BIT_IE 0x10000000 /* inexact bit */ +#define BIT_MO 0x08000000 /* mantissa overflow bit */ +#define BIT_EO 0x04000000 /* exponent overflow bit */ +#define BIT_SB 0x00000800 /* store bounce */ +#define BIT_AB 0x00000400 /* arithmetic bounce */ +#define BIT_RE 0x00000200 /* rounding exception */ +#define BIT_DA 0x00000100 /* disable FPA */ + +#define MASK_OP 0x00f08010 /* AU operation code */ +#define MASK_PR 0x00080080 /* AU precision */ +#define MASK_S1 0x00070000 /* AU source register 1 */ +#define MASK_S2 0x00000007 /* AU source register 2 */ +#define MASK_DS 0x00007000 /* AU destination register */ +#define MASK_RM 0x00000060 /* AU rounding mode */ +#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */ +#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */ +#define MASK_WFC MASK_RESET +#define MASK_RFC ~MASK_RESET + +#endif diff --git a/target-arm/nwfpe/milieu.h b/target-arm/nwfpe/milieu.h new file mode 100644 index 000000000..a3892ab2d --- /dev/null +++ b/target-arm/nwfpe/milieu.h @@ -0,0 +1,48 @@ + +/* +=============================================================================== + +This C header file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Include common integer types and flags. +------------------------------------------------------------------------------- +*/ +#include "ARM-gcc.h" + +/* +------------------------------------------------------------------------------- +Symbolic Boolean literals. +------------------------------------------------------------------------------- +*/ +enum { + FALSE = 0, + TRUE = 1 +}; + diff --git a/target-arm/nwfpe/single_cpdo.c b/target-arm/nwfpe/single_cpdo.c new file mode 100644 index 000000000..c38cb01e4 --- /dev/null +++ b/target-arm/nwfpe/single_cpdo.c @@ -0,0 +1,255 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +float32 float32_exp(float32 Fm); +float32 float32_ln(float32 Fm); +float32 float32_sin(float32 rFm); +float32 float32_cos(float32 rFm); +float32 float32_arcsin(float32 rFm); +float32 float32_arctan(float32 rFm); +float32 float32_log(float32 rFm); +float32 float32_tan(float32 rFm); +float32 float32_arccos(float32 rFm); +float32 float32_pow(float32 rFn,float32 rFm); +float32 float32_pol(float32 rFn,float32 rFm); + +unsigned int SingleCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + float32 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getSingleConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = fpa11->fpreg[Fm].fSingle; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = fpa11->fpreg[Fn].fSingle; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fSingle = rFm; + break; + + case MNF_CODE: + rFm ^= 0x80000000; + fpa11->fpreg[Fd].fSingle = rFm; + break; + + case ABS_CODE: + rFm &= 0x7fffffff; + fpa11->fpreg[Fd].fSingle = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fSingle = float32_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fSingle = float32_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fSingle = float32_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fSingle = float32_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fSingle = float32_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fSingle = float32_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fSingle = float32_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fSingle = float32_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeSingle; + return nRc; +} + +#if 0 +float32 float32_exp(float32 Fm) +{ +//series +} + +float32 float32_ln(float32 Fm) +{ +//series +} + +float32 float32_sin(float32 rFm) +{ +//series +} + +float32 float32_cos(float32 rFm) +{ +//series +} + +float32 float32_arcsin(float32 rFm) +{ +//series +} + +float32 float32_arctan(float32 rFm) +{ + //series +} + +float32 float32_arccos(float32 rFm) +{ + //return float32_sub(halfPi,float32_arcsin(rFm)); +} + +float32 float32_log(float32 rFm) +{ + return float32_div(float32_ln(rFm),getSingleConstant(7)); +} + +float32 float32_tan(float32 rFm) +{ + return float32_div(float32_sin(rFm),float32_cos(rFm)); +} + +float32 float32_pow(float32 rFn,float32 rFm) +{ + return float32_exp(float32_mul(rFm,float32_ln(rFn))); +} + +float32 float32_pol(float32 rFn,float32 rFm) +{ + return float32_arctan(float32_div(rFn,rFm)); +} +#endif diff --git a/target-arm/nwfpe/softfloat-macros b/target-arm/nwfpe/softfloat-macros new file mode 100644 index 000000000..c245a0ef4 --- /dev/null +++ b/target-arm/nwfpe/softfloat-macros @@ -0,0 +1,740 @@ + +/* +=============================================================================== + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Shifts `a' right by the number of bits given in `count'. If any nonzero +bits are shifted off, they are ``jammed'' into the least significant bit of +the result by setting the least significant bit to 1. The value of `count' +can be arbitrarily large; in particular, if `count' is greater than 32, the +result will be either 0 or 1, depending on whether `a' is zero or nonzero. +The result is stored in the location pointed to by `zPtr'. +------------------------------------------------------------------------------- +*/ +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +{ + bits32 z; + if ( count == 0 ) { + z = a; + } + else if ( count < 32 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; +} + +/* +------------------------------------------------------------------------------- +Shifts `a' right by the number of bits given in `count'. If any nonzero +bits are shifted off, they are ``jammed'' into the least significant bit of +the result by setting the least significant bit to 1. The value of `count' +can be arbitrarily large; in particular, if `count' is greater than 64, the +result will be either 0 or 1, depending on whether `a' is zero or nonzero. +The result is stored in the location pointed to by `zPtr'. +------------------------------------------------------------------------------- +*/ +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) +{ + bits64 z; + +// __asm__("@shift64RightJamming -- start"); + if ( count == 0 ) { + z = a; + } + else if ( count < 64 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } +// __asm__("@shift64RightJamming -- end"); + *zPtr = z; +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 +_plus_ the number of bits given in `count'. The shifted result is at most +64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The +bits shifted off form a second 64-bit result as follows: The _last_ bit +shifted off is the most-significant bit of the extra result, and the other +63 bits of the extra result are all zero if and only if _all_but_the_last_ +bits shifted off were all zero. This extra result is stored in the location +pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. + (This routine makes more sense if `a0' and `a1' are considered to form a +fixed-point value with binary point between `a0' and `a1'. This fixed-point +value is shifted right by the number of bits given in `count', and the +integer part of the result is returned at the location pointed to by +`z0Ptr'. The fractional part of the result may be slightly corrupted as +described above, and is returned at the location pointed to by `z1Ptr'.) +------------------------------------------------------------------------------- +*/ +INLINE void + shift64ExtraRightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else { + z1 = ( ( a0 | a1 ) != 0 ); + } + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +number of bits given in `count'. Any bits shifted off are lost. The value +of `count' can be arbitrarily large; in particular, if `count' is greater +than 128, the result will be 0. The result is broken into two 64-bit pieces +which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shift128Right( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ); + z0 = a0>>count; + } + else { + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +number of bits given in `count'. If any nonzero bits are shifted off, they +are ``jammed'' into the least significant bit of the result by setting the +least significant bit to 1. The value of `count' can be arbitrarily large; +in particular, if `count' is greater than 128, the result will be either 0 +or 1, depending on whether the concatenation of `a0' and `a1' is zero or +nonzero. The result is broken into two 64-bit pieces which are stored at +the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shift128RightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ) | ( ( a1<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 128 ) { + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 128 ) { + z2 = a0<>( count & 63 ); + } + else { + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); + z1 = 0; + } + } + z0 = 0; + } + z2 |= ( a2 != 0 ); + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the +number of bits given in `count'. Any bits shifted off are lost. The value +of `count' must be less than 64. The result is broken into two 64-bit +pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shortShift128Left( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1<>( ( - count ) & 63 ) ); + +} + +/* +------------------------------------------------------------------------------- +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left +by the number of bits given in `count'. Any bits shifted off are lost. +The value of `count' must be less than 64. The result is broken into three +64-bit pieces which are stored at the locations pointed to by `z0Ptr', +`z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shortShift192Left( + bits64 a0, + bits64 a1, + bits64 a2, + int16 count, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 negCount; + + z2 = a2<>negCount; + z0 |= a1>>negCount; + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit +value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so +any carry out is lost. The result is broken into two 64-bit pieces which +are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + add128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z1; + + z1 = a1 + b1; + *z1Ptr = z1; + *z0Ptr = a0 + b0 + ( z1 < a1 ); + +} + +/* +------------------------------------------------------------------------------- +Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the +192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +modulo 2^192, so any carry out is lost. The result is broken into three +64-bit pieces which are stored at the locations pointed to by `z0Ptr', +`z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + add192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 carry0, carry1; + + z2 = a2 + b2; + carry1 = ( z2 < a2 ); + z1 = a1 + b1; + carry0 = ( z1 < a1 ); + z0 = a0 + b0; + z1 += carry1; + z0 += ( z1 < carry1 ); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the +128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +2^128, so any borrow out (carry out) is lost. The result is broken into two +64-bit pieces which are stored at the locations pointed to by `z0Ptr' and +`z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + sub128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - ( a1 < b1 ); + +} + +/* +------------------------------------------------------------------------------- +Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' +from the 192-bit value formed by concatenating `a0', `a1', and `a2'. +Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The +result is broken into three 64-bit pieces which are stored at the locations +pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + sub192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 borrow0, borrow1; + + z2 = a2 - b2; + borrow1 = ( a2 < b2 ); + z1 = a1 - b1; + borrow0 = ( a1 < b1 ); + z0 = a0 - b0; + z0 -= ( z1 < borrow1 ); + z1 -= borrow1; + z0 -= borrow0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies `a' by `b' to obtain a 128-bit product. The product is broken +into two 64-bit pieces which are stored at the locations pointed to by +`z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits32 aHigh, aLow, bHigh, bLow; + bits64 z0, zMiddleA, zMiddleB, z1; + + aLow = a; + aHigh = a>>32; + bLow = b; + bHigh = b>>32; + z1 = ( (bits64) aLow ) * bLow; + zMiddleA = ( (bits64) aLow ) * bHigh; + zMiddleB = ( (bits64) aHigh ) * bLow; + z0 = ( (bits64) aHigh ) * bHigh; + zMiddleA += zMiddleB; + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); + zMiddleA <<= 32; + z1 += zMiddleA; + z0 += ( z1 < zMiddleA ); + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to +obtain a 192-bit product. The product is broken into three 64-bit pieces +which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +`z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + mul128By64To192( + bits64 a0, + bits64 a1, + bits64 b, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2, more1; + + mul64To128( a1, b, &z1, &z2 ); + mul64To128( a0, b, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the +128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit +product. The product is broken into four 64-bit pieces which are stored at +the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + mul128To256( + bits64 a0, + bits64 a1, + bits64 b0, + bits64 b1, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr, + bits64 *z3Ptr + ) +{ + bits64 z0, z1, z2, z3; + bits64 more1, more2; + + mul64To128( a1, b1, &z2, &z3 ); + mul64To128( a1, b0, &z1, &more2 ); + add128( z1, more2, 0, z2, &z1, &z2 ); + mul64To128( a0, b0, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + mul64To128( a0, b1, &more1, &more2 ); + add128( more1, more2, 0, z2, &more1, &z2 ); + add128( z0, z1, 0, more1, &z0, &z1 ); + *z3Ptr = z3; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Returns an approximation to the 64-bit integer quotient obtained by dividing +`b' into the 128-bit value formed by concatenating `a0' and `a1'. The +divisor `b' must be at least 2^63. If q is the exact quotient truncated +toward zero, the approximation returned lies between q and q + 2 inclusive. +If the exact quotient q is larger than 64 bits, the maximum positive 64-bit +unsigned integer is returned. +------------------------------------------------------------------------------- +*/ +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) +{ + bits64 b0, b1; + bits64 rem0, rem1, term0, term1; + bits64 z; + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); + b0 = b>>32; + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; + mul64To128( b, z, &term0, &term1 ); + sub128( a0, a1, term0, term1, &rem0, &rem1 ); + while ( ( (sbits64) rem0 ) < 0 ) { + z -= LIT64( 0x100000000 ); + b1 = b<<32; + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); + } + rem0 = ( rem0<<32 ) | ( rem1>>32 ); + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns an approximation to the square root of the 32-bit significand given +by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of +`aExp' (the least significant bit) is 1, the integer returned approximates +2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' +is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either +case, the approximation returned lies strictly within +/-2 of the exact +value. +------------------------------------------------------------------------------- +*/ +static bits32 estimateSqrt32( int16 aExp, bits32 a ) +{ + static const bits16 sqrtOddAdjustments[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; + static const bits16 sqrtEvenAdjustments[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + int8 index; + bits32 z; + + index = ( a>>27 ) & 15; + if ( aExp & 1 ) { + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; + z = ( ( a / z )<<14 ) + ( z<<15 ); + a >>= 1; + } + else { + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; + z = a / z + z; + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); + } + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the number of leading 0 bits before the most-significant 1 bit +of `a'. If `a' is zero, 32 is returned. +------------------------------------------------------------------------------- +*/ +static int8 countLeadingZeros32( bits32 a ) +{ + static const int8 countLeadingZerosHigh[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + int8 shiftCount; + + shiftCount = 0; + if ( a < 0x10000 ) { + shiftCount += 16; + a <<= 16; + } + if ( a < 0x1000000 ) { + shiftCount += 8; + a <<= 8; + } + shiftCount += countLeadingZerosHigh[ a>>24 ]; + return shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Returns the number of leading 0 bits before the most-significant 1 bit +of `a'. If `a' is zero, 64 is returned. +------------------------------------------------------------------------------- +*/ +static int8 countLeadingZeros64( bits64 a ) +{ + int8 shiftCount; + + shiftCount = 0; + if ( a < ( (bits64) 1 )<<32 ) { + shiftCount += 32; + } + else { + a >>= 32; + } + shiftCount += countLeadingZeros32( a ); + return shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' +is equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 == b0 ) && ( a1 == b1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +than or equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, +returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is +not equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 != b0 ) || ( a1 != b1 ); + +} + diff --git a/target-arm/nwfpe/softfloat-specialize b/target-arm/nwfpe/softfloat-specialize new file mode 100644 index 000000000..a23a8a360 --- /dev/null +++ b/target-arm/nwfpe/softfloat-specialize @@ -0,0 +1,366 @@ + +/* +=============================================================================== + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Underflow tininess-detection mode, statically initialized to default value. +(The declaration in `softfloat.h' must match the `int8' type here.) +------------------------------------------------------------------------------- +*/ +int8 float_detect_tininess = float_tininess_after_rounding; + +/* +------------------------------------------------------------------------------- +Raises the exceptions specified by `flags'. Floating-point traps can be +defined here if desired. It is currently not possible for such a trap to +substitute a result value. If traps are not implemented, this routine +should be simply `float_exception_flags |= flags;'. + +ScottB: November 4, 1998 +Moved this function out of softfloat-specialize into fpmodule.c. +This effectively isolates all the changes required for integrating with the +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying +fpmodule.c to integrate with the NetBSD kernel (I hope!). +------------------------------------------------------------------------------- +*/ +void float_raise( int8 flags ) +{ + float_exception_flags |= flags; +} + +/* +------------------------------------------------------------------------------- +Internal canonical NaN format. +------------------------------------------------------------------------------- +*/ +typedef struct { + flag sign; + bits64 high, low; +} commonNaNT; + +/* +------------------------------------------------------------------------------- +The pattern for a default generated single-precision NaN. +------------------------------------------------------------------------------- +*/ +#define float32_default_nan 0xFFFFFFFF + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float32_is_nan( float32 a ) +{ + + return ( 0xFF000000 < (bits32) ( a<<1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is a signaling +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float32_is_signaling_nan( float32 a ) +{ + + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float32ToCommonNaN( float32 a ) +{ + commonNaNT z; + + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>31; + z.low = 0; + z.high = ( (bits64) a )<<41; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the single- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float32 commonNaNToFloat32( commonNaNT a ) +{ + + return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); + +} + +/* +------------------------------------------------------------------------------- +Takes two single-precision floating-point values `a' and `b', one of which +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float32 propagateFloat32NaN( float32 a, float32 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float32_is_nan( a ); + aIsSignalingNaN = float32_is_signaling_nan( a ); + bIsNaN = float32_is_nan( b ); + bIsSignalingNaN = float32_is_signaling_nan( b ); + a |= 0x00400000; + b |= 0x00400000; + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +/* +------------------------------------------------------------------------------- +The pattern for a default generated double-precision NaN. +------------------------------------------------------------------------------- +*/ +#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float64_is_nan( float64 a ) +{ + + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is a signaling +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float64_is_signaling_nan( float64 a ) +{ + + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float64ToCommonNaN( float64 a ) +{ + commonNaNT z; + + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>63; + z.low = 0; + z.high = a<<12; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the double- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float64 commonNaNToFloat64( commonNaNT a ) +{ + + return + ( ( (bits64) a.sign )<<63 ) + | LIT64( 0x7FF8000000000000 ) + | ( a.high>>12 ); + +} + +/* +------------------------------------------------------------------------------- +Takes two double-precision floating-point values `a' and `b', one of which +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float64 propagateFloat64NaN( float64 a, float64 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float64_is_nan( a ); + aIsSignalingNaN = float64_is_signaling_nan( a ); + bIsNaN = float64_is_nan( b ); + bIsSignalingNaN = float64_is_signaling_nan( b ); + a |= LIT64( 0x0008000000000000 ); + b |= LIT64( 0x0008000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +The pattern for a default generated extended double-precision NaN. The +`high' and `low' values hold the most- and least-significant bits, +respectively. +------------------------------------------------------------------------------- +*/ +#define floatx80_default_nan_high 0xFFFF +#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is a +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag floatx80_is_nan( floatx80 a ) +{ + + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is a +signaling NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag floatx80_is_signaling_nan( floatx80 a ) +{ + //register int lr; + bits64 aLow; + + //__asm__("mov %0, lr" : : "g" (lr)); + //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr); + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the +invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT floatx80ToCommonNaN( floatx80 a ) +{ + commonNaNT z; + + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a.high>>15; + z.low = 0; + z.high = a.low<<1; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the extended +double-precision floating-point format. +------------------------------------------------------------------------------- +*/ +static floatx80 commonNaNToFloatx80( commonNaNT a ) +{ + floatx80 z; + + z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + return z; + +} + +/* +------------------------------------------------------------------------------- +Takes two extended double-precision floating-point values `a' and `b', one +of which is a NaN, and returns the appropriate NaN result. If either `a' or +`b' is a signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = floatx80_is_nan( a ); + aIsSignalingNaN = floatx80_is_signaling_nan( a ); + bIsNaN = floatx80_is_nan( b ); + bIsSignalingNaN = floatx80_is_signaling_nan( b ); + a.low |= LIT64( 0xC000000000000000 ); + b.low |= LIT64( 0xC000000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#endif diff --git a/target-arm/nwfpe/softfloat.c b/target-arm/nwfpe/softfloat.c new file mode 100644 index 000000000..8ffb9a98d --- /dev/null +++ b/target-arm/nwfpe/softfloat.c @@ -0,0 +1,3427 @@ +/* +=============================================================================== + +This C source file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +#include "fpa11.h" +#include "milieu.h" +#include "softfloat.h" + +/* +------------------------------------------------------------------------------- +Floating-point rounding mode, extended double-precision rounding precision, +and exception flags. +------------------------------------------------------------------------------- +*/ +int8 float_rounding_mode = float_round_nearest_even; +int8 floatx80_rounding_precision = 80; +int8 float_exception_flags; + +/* +------------------------------------------------------------------------------- +Primitive arithmetic functions, including multi-word arithmetic, and +division and square root approximations. (Can be specialized to target if +desired.) +------------------------------------------------------------------------------- +*/ +#include "softfloat-macros" + +/* +------------------------------------------------------------------------------- +Functions and definitions to determine: (1) whether tininess for underflow +is detected before or after rounding by default, (2) what (if anything) +happens when exceptions are raised, (3) how signaling NaNs are distinguished +from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs +are propagated from function inputs to output. These details are target- +specific. +------------------------------------------------------------------------------- +*/ +#include "softfloat-specialize" + +/* +------------------------------------------------------------------------------- +Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 +and 7, and returns the properly rounded 32-bit integer corresponding to the +input. If `zSign' is nonzero, the input is negated before being converted +to an integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point +input is simply rounded to an integer, with the inexact exception raised if +the input cannot be represented exactly as an integer. If the fixed-point +input is too large, however, the invalid exception is raised and the largest +positive or negative integer is returned. +------------------------------------------------------------------------------- +*/ +static int32 roundAndPackInt32( flag zSign, bits64 absZ ) +{ + int8 roundingMode; + flag roundNearestEven; + int8 roundIncrement, roundBits; + int32 z; + + roundingMode = float_rounding_mode; + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x40; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x7F; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = absZ & 0x7F; + absZ = ( absZ + roundIncrement )>>7; + absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + z = absZ; + if ( zSign ) z = - z; + if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { + float_exception_flags |= float_flag_invalid; + return zSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( roundBits ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the fraction bits of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE bits32 extractFloat32Frac( float32 a ) +{ + + return a & 0x007FFFFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the exponent bits of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE int16 extractFloat32Exp( float32 a ) +{ + + return ( a>>23 ) & 0xFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat32Sign( float32 a ) +{ + + return a>>31; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal single-precision floating-point value represented +by the denormalized significand `aSig'. The normalized exponent and +significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( aSig ) - 8; + *zSigPtr = aSig<>7; + zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper single-precision floating- +point value corresponding to the abstract input. This routine is just like +`roundAndPackFloat32' except that `zSig' does not have to be normalized in +any way. In all cases, `zExp' must be 1 less than the ``true'' floating- +point exponent. +------------------------------------------------------------------------------- +*/ +static float32 + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( zSig ) - 1; + return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>52 ) & 0x7FF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the double-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat64Sign( float64 a ) +{ + + return a>>63; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal double-precision floating-point value represented +by the denormalized significand `aSig'. The normalized exponent and +significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ) - 11; + *zSigPtr = aSig<>10; + zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper double-precision floating- +point value corresponding to the abstract input. This routine is just like +`roundAndPackFloat64' except that `zSig' does not have to be normalized in +any way. In all cases, `zExp' must be 1 less than the ``true'' floating- +point exponent. +------------------------------------------------------------------------------- +*/ +static float64 + normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( zSig ) - 1; + return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>15; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal extended double-precision floating-point value +represented by the denormalized significand `aSig'. The normalized exponent +and significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ); + *zSigPtr = aSig<>( - shiftCount ); + if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + float_exception_flags |= float_flag_inexact; + } + return aSign ? - z : z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the double-precision floating-point format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float32_to_float64( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) ); + return packFloat64( aSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the extended double-precision floating-point format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 float32_to_floatx80( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + aSig |= 0x00800000; + return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); + +} + +#endif + +/* +------------------------------------------------------------------------------- +Rounds the single-precision floating-point value `a' to an integer, and +returns the result as a single-precision floating-point value. The +operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_round_to_int( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + float32 z; + + aExp = extractFloat32Exp( a ); + if ( 0x96 <= aExp ) { + if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { + return propagateFloat32NaN( a, a ); + } + return a; + } + if ( aExp <= 0x7E ) { + if ( (bits32) ( a<<1 ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat32Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { + return packFloat32( aSign, 0x7F, 0 ); + } + break; + case float_round_down: + return aSign ? 0xBF800000 : 0; + case float_round_up: + return aSign ? 0x80000000 : 0x3F800000; + } + return packFloat32( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x96 - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the single-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 addFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 6; + bSig <<= 6; + if ( 0 < expDiff ) { + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x20000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x20000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + zSig = 0x40000000 + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= 0x20000000; + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits32) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the single- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 subFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 7; + bSig <<= 7; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat32( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign ^ 1, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x40000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + bSig |= 0x40000000; + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x40000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + aSig |= 0x40000000; + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the single-precision floating-point values `a' +and `b'. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_add( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return addFloat32Sigs( a, b, aSign ); + } + else { + return subFloat32Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the single-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_sub( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign ); + } + else { + return addFloat32Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the single-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_mul( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig; + bits64 zSig64; + bits32 zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x7F; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); + zSig = zSig64; + if ( 0 <= (sbits32) ( zSig<<1 ) ) { + zSig <<= 1; + --zExp; + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the single-precision floating-point value `a' +by the corresponding value `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_div( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat32( zSign, 0xFF, 0 ); + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x7D; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = ( ( (bits64) aSig )<<32 ) / bSig; + if ( ( zSig & 0x3F ) == 0 ) { + zSig |= ( ( (bits64) bSig ) * zSig != ( (bits64) aSig )<<32 ); + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the single-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_rem( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig, bSig; + bits32 q; + bits64 aSig64, bSig64, q64; + bits32 alternateASig; + sbits32 sigMean; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig |= 0x00800000; + bSig |= 0x00800000; + if ( expDiff < 32 ) { + aSig <<= 8; + bSig <<= 8; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + if ( 0 < expDiff ) { + q = ( ( (bits64) aSig )<<32 ) / bSig; + q >>= 32 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + } + else { + if ( bSig <= aSig ) aSig -= bSig; + aSig64 = ( (bits64) aSig )<<40; + bSig64 = ( (bits64) bSig )<<40; + expDiff -= 64; + while ( 0 < expDiff ) { + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + aSig64 = - ( ( bSig * q64 )<<38 ); + expDiff -= 62; + } + expDiff += 64; + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + q = q64>>( 64 - expDiff ); + bSig <<= 6; + aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits32) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits32) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the single-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_sqrt( float32 a ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig, zSig; + bits64 rem, term; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, 0 ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; + aSig = ( aSig | 0x00800000 )<<8; + zSig = estimateSqrt32( aExp, aSig ) + 2; + if ( ( zSig & 0x7F ) <= 5 ) { + if ( zSig < 2 ) { + zSig = 0xFFFFFFFF; + } + else { + aSig >>= aExp & 1; + term = ( (bits64) zSig ) * zSig; + rem = ( ( (bits64) aSig )<<32 ) - term; + while ( (sbits64) rem < 0 ) { + --zSig; + rem += ( ( (bits64) zSig )<<1 ) | 1; + } + zSig |= ( rem != 0 ); + } + } + shift32RightJamming( zSig, 1, &zSig ); + return roundAndPackFloat32( 0, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_eq( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_le( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_lt( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The invalid exception is raised +if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_eq_signaling( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_le_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + //int16 aExp, bExp; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_lt_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_int32( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x42C - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic, except that the conversion is always rounded toward zero. If +`a' is a NaN, the largest positive integer is returned. Otherwise, if the +conversion overflows, the largest integer with the same sign as `a' is +returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_int32_round_to_zero( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + shiftCount = 0x433 - aExp; + if ( shiftCount < 21 ) { + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + goto invalid; + } + else if ( 52 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig |= LIT64( 0x0010000000000000 ); + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the double-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 addFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 9; + bSig <<= 9; + if ( 0 < expDiff ) { + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= LIT64( 0x2000000000000000 ); + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits64) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the double- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 subFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 10; + bSig <<= 10; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b ); + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat64( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign ^ 1, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + bSig |= LIT64( 0x4000000000000000 ); + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + aSig |= LIT64( 0x4000000000000000 ); + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the double-precision floating-point values `a' +and `b'. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_add( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return addFloat64Sigs( a, b, aSign ); + } + else { + return subFloat64Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the double-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_sub( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return subFloat64Sigs( a, b, aSign ); + } + else { + return addFloat64Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the double-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_mul( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FF; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + zSig0 |= ( zSig1 != 0 ); + if ( 0 <= (sbits64) ( zSig0<<1 ) ) { + zSig0 <<= 1; + --zExp; + } + return roundAndPackFloat64( zSign, zExp, zSig0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the double-precision floating-point value `a' +by the corresponding value `b'. The operation is performed according to +the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_div( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + bits64 rem0, rem1; + bits64 term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat64( zSign, 0x7FF, 0 ); + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FD; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = estimateDiv128To64( aSig, 0, bSig ); + if ( ( zSig & 0x1FF ) <= 2 ) { + mul64To128( bSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig |= ( rem1 != 0 ); + } + return roundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the double-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_rem( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits64 aSig, bSig; + bits64 q, alternateASig; + sbits64 sigMean; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + aSig = - ( ( bSig>>2 ) * q ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits64) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits64) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the double-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_sqrt( float64 a ) +{ + flag aSign; + int16 aExp, zExp; + bits64 aSig, zSig; + bits64 rem0, rem1, term0, term1; //, shiftedRem; + //float64 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, a ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; + aSig |= LIT64( 0x0010000000000000 ); + zSig = estimateSqrt32( aExp, aSig>>21 ); + zSig <<= 31; + aSig <<= 9 - ( aExp & 1 ); + zSig = estimateDiv128To64( aSig, 0, zSig ) + zSig + 2; + if ( ( zSig & 0x3FF ) <= 5 ) { + if ( zSig < 2 ) { + zSig = LIT64( 0xFFFFFFFFFFFFFFFF ); + } + else { + aSig <<= 2; + mul64To128( zSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + shortShift128Left( 0, zSig, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + zSig |= ( ( rem0 | rem1 ) != 0 ); + } + } + shift64RightJamming( zSig, 1, &zSig ); + return roundAndPackFloat64( 0, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_eq( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_le( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_lt( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The invalid exception is raised +if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_eq_signaling( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_le_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + //int16 aExp, bExp; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_lt_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the 32-bit two's complement integer format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic---which means in particular that the conversion +is rounded according to the current rounding mode. If `a' is a NaN, the +largest positive integer is returned. Otherwise, if the conversion +overflows, the largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 floatx80_to_int32( floatx80 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + shiftCount = 0x4037 - aExp; + if ( shiftCount <= 0 ) shiftCount = 1; + shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the 32-bit two's complement integer format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic, except that the conversion is always rounded +toward zero. If `a' is a NaN, the largest positive integer is returned. +Otherwise, if the conversion overflows, the largest integer with the same +sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 floatx80_to_int32_round_to_zero( floatx80 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + shiftCount = 0x403E - aExp; + if ( shiftCount < 32 ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + goto invalid; + } + else if ( 63 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>1; + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z.low += roundBitsMask; + } + } + z.low &= ~ roundBitsMask; + if ( z.low == 0 ) { + ++z.high; + z.low = LIT64( 0x8000000000000000 ); + } + if ( z.low != a.low ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the extended double- +precision floating-point values `a' and `b'. If `zSign' is true, the sum is +negated before being returned. `zSign' is ignored if the result is a NaN. +The addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b ); + } + return a; + } + zSig1 = 0; + zSig0 = aSig + bSig; + if ( aExp == 0 ) { + normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); + goto roundAndPack; + } + zExp = aExp; + goto shiftRight1; + } + + zSig0 = aSig + bSig; + + if ( (sbits64) zSig0 < 0 ) goto roundAndPack; + shiftRight1: + shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= LIT64( 0x8000000000000000 ); + ++zExp; + roundAndPack: + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the extended +double-precision floating-point values `a' and `b'. If `zSign' is true, +the difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b ); + } + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + zSig1 = 0; + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloatx80( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + bBigger: + sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + aBigger: + sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + return + normalizeRoundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the extended double-precision floating-point +values `a' and `b'. The operation is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_add( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return addFloatx80Sigs( a, b, aSign ); + } + else { + return subFloatx80Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the extended double-precision floating- +point values `a' and `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_sub( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return subFloatx80Sigs( a, b, aSign ); + } + else { + return addFloatx80Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the extended double-precision floating- +point values `a' and `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_mul( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) goto invalid; + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FFE; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + if ( 0 < (sbits64) zSig0 ) { + shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); + --zExp; + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the extended double-precision floating-point +value `a' by the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_div( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + bits64 rem0, rem1, rem2, term0, term1, term2; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + goto invalid; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FFE; + rem1 = 0; + if ( bSig <= aSig ) { + shift128Right( aSig, 0, 1, &aSig, &rem1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig, rem1, bSig ); + mul64To128( bSig, zSig0, &term0, &term1 ); + sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, bSig ); + if ( (bits64) ( zSig1<<1 ) <= 8 ) { + mul64To128( bSig, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); + } + zSig1 |= ( ( rem1 | rem2 ) != 0 ); + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the extended double-precision floating-point value +`a' with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_rem( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig; + bits64 q, term0, term1, alternateASig0, alternateASig1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( (bits64) ( aSig0<<1 ) == 0 ) return a; + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + bSig |= LIT64( 0x8000000000000000 ); + zSign = aSign; + expDiff = aExp - bExp; + aSig1 = 0; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); + expDiff = 0; + } + q = ( bSig <= aSig0 ); + if ( q ) aSig0 -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + mul64To128( bSig, q, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); + while ( le128( term0, term1, aSig0, aSig1 ) ) { + ++q; + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + } + } + else { + term1 = 0; + term0 = bSig; + } + sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); + if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) + || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) + && ( q & 1 ) ) + ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + zSign = ! zSign; + } + return + normalizeRoundAndPackFloatx80( + 80, zSign, bExp + expDiff, aSig0, aSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the extended double-precision floating-point +value `a'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_sqrt( floatx80 a ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + bits64 shiftedRem0, shiftedRem1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; + zSig0 = estimateSqrt32( aExp, aSig0>>32 ); + zSig0 <<= 31; + aSig1 = 0; + shift128Right( aSig0, 0, ( aExp & 1 ) + 2, &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; + if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); + shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + shortShift128Left( 0, zSig0, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); + zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); + if ( (bits64) ( zSig1<<1 ) <= 10 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( zSig0, zSig1, &term1, &term2 ); + shortShift128Left( term1, term2, 1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); + term3 |= 1; + add192( + rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, 0, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_eq( floatx80 a, floatx80 b ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +less than or equal to the corresponding value `b', and 0 otherwise. The +comparison is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_le( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +less than the corresponding value `b', and 0 otherwise. The comparison +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_lt( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is equal +to the corresponding value `b', and 0 otherwise. The invalid exception is +raised if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_eq_signaling( floatx80 a, floatx80 b ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is less +than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs +do not cause an exception. Otherwise, the comparison is performed according +to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_le_quiet( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is less +than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause +an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_lt_quiet( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + diff --git a/target-arm/nwfpe/softfloat.h b/target-arm/nwfpe/softfloat.h new file mode 100644 index 000000000..22c2193a4 --- /dev/null +++ b/target-arm/nwfpe/softfloat.h @@ -0,0 +1,232 @@ + +/* +=============================================================================== + +This C header file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +#ifndef __SOFTFLOAT_H__ +#define __SOFTFLOAT_H__ + +/* +------------------------------------------------------------------------------- +The macro `FLOATX80' must be defined to enable the extended double-precision +floating-point format `floatx80'. If this macro is not defined, the +`floatx80' type will not be defined, and none of the functions that either +input or output the `floatx80' type will be defined. +------------------------------------------------------------------------------- +*/ +#define FLOATX80 + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point types. +------------------------------------------------------------------------------- +*/ +typedef unsigned long int float32; +typedef unsigned long long float64; +typedef struct { + unsigned short high; + unsigned long long low; +} floatx80; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point underflow tininess-detection mode. +------------------------------------------------------------------------------- +*/ +extern signed char float_detect_tininess; +enum { + float_tininess_after_rounding = 0, + float_tininess_before_rounding = 1 +}; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point rounding mode. +------------------------------------------------------------------------------- +*/ +extern signed char float_rounding_mode; +enum { + float_round_nearest_even = 0, + float_round_to_zero = 1, + float_round_down = 2, + float_round_up = 3 +}; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point exception flags. +------------------------------------------------------------------------------- +extern signed char float_exception_flags; +enum { + float_flag_inexact = 1, + float_flag_underflow = 2, + float_flag_overflow = 4, + float_flag_divbyzero = 8, + float_flag_invalid = 16 +}; + +ScottB: November 4, 1998 +Changed the enumeration to match the bit order in the FPA11. +*/ + +extern signed char float_exception_flags; +enum { + float_flag_invalid = 1, + float_flag_divbyzero = 2, + float_flag_overflow = 4, + float_flag_underflow = 8, + float_flag_inexact = 16 +}; + +/* +------------------------------------------------------------------------------- +Routine to raise any or all of the software IEC/IEEE floating-point +exception flags. +------------------------------------------------------------------------------- +*/ +void float_raise( signed char ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE integer-to-floating-point conversion routines. +------------------------------------------------------------------------------- +*/ +float32 int32_to_float32( signed int ); +float64 int32_to_float64( signed int ); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( signed int ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE single-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float32_to_int32( float32 ); +signed int float32_to_int32_round_to_zero( float32 ); +float64 float32_to_float64( float32 ); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE single-precision operations. +------------------------------------------------------------------------------- +*/ +float32 float32_round_to_int( float32 ); +float32 float32_add( float32, float32 ); +float32 float32_sub( float32, float32 ); +float32 float32_mul( float32, float32 ); +float32 float32_div( float32, float32 ); +float32 float32_rem( float32, float32 ); +float32 float32_sqrt( float32 ); +char float32_eq( float32, float32 ); +char float32_le( float32, float32 ); +char float32_lt( float32, float32 ); +char float32_eq_signaling( float32, float32 ); +char float32_le_quiet( float32, float32 ); +char float32_lt_quiet( float32, float32 ); +char float32_is_signaling_nan( float32 ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE double-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float64_to_int32( float64 ); +signed int float64_to_int32_round_to_zero( float64 ); +float32 float64_to_float32( float64 ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE double-precision operations. +------------------------------------------------------------------------------- +*/ +float64 float64_round_to_int( float64 ); +float64 float64_add( float64, float64 ); +float64 float64_sub( float64, float64 ); +float64 float64_mul( float64, float64 ); +float64 float64_div( float64, float64 ); +float64 float64_rem( float64, float64 ); +float64 float64_sqrt( float64 ); +char float64_eq( float64, float64 ); +char float64_le( float64, float64 ); +char float64_lt( float64, float64 ); +char float64_eq_signaling( float64, float64 ); +char float64_le_quiet( float64, float64 ); +char float64_lt_quiet( float64, float64 ); +char float64_is_signaling_nan( float64 ); + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int floatx80_to_int32( floatx80 ); +signed int floatx80_to_int32_round_to_zero( floatx80 ); +float32 floatx80_to_float32( floatx80 ); +float64 floatx80_to_float64( floatx80 ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision rounding precision. Valid +values are 32, 64, and 80. +------------------------------------------------------------------------------- +*/ +extern signed char floatx80_rounding_precision; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision operations. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_round_to_int( floatx80 ); +floatx80 floatx80_add( floatx80, floatx80 ); +floatx80 floatx80_sub( floatx80, floatx80 ); +floatx80 floatx80_mul( floatx80, floatx80 ); +floatx80 floatx80_div( floatx80, floatx80 ); +floatx80 floatx80_rem( floatx80, floatx80 ); +floatx80 floatx80_sqrt( floatx80 ); +char floatx80_eq( floatx80, floatx80 ); +char floatx80_le( floatx80, floatx80 ); +char floatx80_lt( floatx80, floatx80 ); +char floatx80_eq_signaling( floatx80, floatx80 ); +char floatx80_le_quiet( floatx80, floatx80 ); +char floatx80_lt_quiet( floatx80, floatx80 ); +char floatx80_is_signaling_nan( floatx80 ); + +#endif + +#endif -- cgit v1.2.3 From 3d57da2a70c0737d388b79f591e86a2821355c92 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:47:14 +0000 Subject: suppressed dummy FPU ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@610 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 60 -------------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 4a3dd3b99..50fe8aa5e 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -708,66 +708,6 @@ static void disas_arm_insn(DisasContext *s) gen_op_swi(); s->is_jmp = DISAS_JUMP; break; - case 0xc: - case 0xd: - rd = (insn >> 12) & 0x7; - rn = (insn >> 16) & 0xf; - gen_movl_T1_reg(s, rn); - val = (insn) & 0xff; - if (!(insn & (1 << 23))) - val = -val; - switch((insn >> 8) & 0xf) { - case 0x1: - /* load/store */ - if ((insn & (1 << 24))) - gen_op_addl_T1_im(val); - /* XXX: do it */ - if (!(insn & (1 << 24))) - gen_op_addl_T1_im(val); - if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); - break; - case 0x2: - { - int n, i; - /* load store multiple */ - if ((insn & (1 << 24))) - gen_op_addl_T1_im(val); - switch(insn & 0x00408000) { - case 0x00008000: n = 1; break; - case 0x00400000: n = 2; break; - case 0x00408000: n = 3; break; - default: n = 4; break; - } - for(i = 0;i < n; i++) { - /* XXX: do it */ - } - if (!(insn & (1 << 24))) - gen_op_addl_T1_im(val); - if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); - } - break; - default: - goto illegal_op; - } - break; - case 0x0e: - /* float ops */ - /* XXX: do it */ - switch((insn >> 20) & 0xf) { - case 0x2: /* wfs */ - break; - case 0x3: /* rfs */ - break; - case 0x4: /* wfc */ - break; - case 0x5: /* rfc */ - break; - default: - goto illegal_op; - } - break; default: illegal_op: gen_op_movl_T0_im((long)s->pc - 4); -- cgit v1.2.3 From 28c4f361ac740b4994cda7d1a4a6803cd08be396 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:47:43 +0000 Subject: arm nwfpe support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@611 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index f6b8d96f4..1a3ad6274 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -48,10 +48,21 @@ struct vm86_saved_state { }; #endif +#ifdef TARGET_ARM +/* FPU emulator */ +#include "nwfpe/fpa11.h" +#undef put_user +#undef get_user +#endif + /* NOTE: we force a big alignment so that the stack stored after is aligned too */ typedef struct TaskState { struct TaskState *next; +#ifdef TARGET_ARM + /* FPA state */ + FPA11 fpa; +#endif #ifdef TARGET_I386 struct target_vm86plus_struct *target_v86; struct vm86_saved_state vm86_saved_regs; -- cgit v1.2.3 From c69810559ba962ad5da4ae6b9069ee6159d2efd1 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:49:03 +0000 Subject: arm nwfpe support - added code no-code-copy option - __preinit_array_start bug fix (untested) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@612 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 171a1fe95..5a8292b12 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -39,6 +39,8 @@ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; /* for recent libc, we add these dummy symbols which are not declared when generating a linked object (bug in ld ?) */ #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +long __preinit_array_start[0]; +long __preinit_array_end[0]; long __init_array_start[0]; long __init_array_end[0]; long __fini_array_start[0]; @@ -254,11 +256,25 @@ void cpu_loop(CPUARMState *env) trapnr = cpu_arm_exec(env); switch(trapnr) { case EXCP_UDEF: - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->regs[15]; - queue_signal(info.si_signo, &info); + { + TaskState *ts = env->opaque; + uint32_t opcode; + + /* we handle the FPU emulation here, as Linux */ + /* we get the opcode */ + opcode = ldl_raw((uint8_t *)env->regs[15]); + + if (EmulateAll(opcode, &ts->fpa, env->regs) == 0) { + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->regs[15]; + queue_signal(info.si_signo, &info); + } else { + /* increment PC */ + env->regs[15] += 4; + } + } break; case EXCP_SWI: { @@ -783,6 +799,9 @@ void usage(void) "-s size set the stack size in bytes (default=%ld)\n" "\n" "debug options:\n" +#ifdef USE_CODE_COPY + "-no-code-copy disable code copy acceleration\n" +#endif "-d activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n", TARGET_ARCH, @@ -847,7 +866,13 @@ int main(int argc, char **argv) fprintf(stderr, "page size must be a power of two\n"); exit(1); } - } else { + } else +#ifdef USE_CODE_COPY + if (!strcmp(r, "no-code-copy")) { + code_copy_enabled = 0; + } else +#endif + { usage(); } } -- cgit v1.2.3 From b324e814a9a7114ba2d753de133cdc75a88f9860 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:54:14 +0000 Subject: suppressed unused variables git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@613 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 50c480e2b..4e8206e72 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -32,10 +32,6 @@ extern FILE *logfile, *stderr; void exit (int); void abort (void); -int phys_ram_size; -int phys_ram_fd; -uint8_t *phys_ram_base; - void cpu_loop_exit(void) { longjmp(env->jmp_env, 1); @@ -487,7 +483,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc); + cpu_restore_state(tb, env, pc, NULL); } } do_queue_exception_err(env->exception_index, env->error_code); -- cgit v1.2.3 From 07ce05eaa93941648721973375f1c11874122d45 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:55:09 +0000 Subject: fast Linux boot support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@614 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux_boot.S | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 linux_boot.S diff --git a/linux_boot.S b/linux_boot.S new file mode 100644 index 000000000..353052c97 --- /dev/null +++ b/linux_boot.S @@ -0,0 +1,32 @@ +/* + * QEMU Boot sector to launch a preloaded Linux kernel + * Copyright (c) 2004 Fabrice Bellard + */ + +#define LOAD_SEG 0x9000 + +.code16 +.text + .globl linux_boot_start + .globl linux_boot_end + +linux_boot_start: + cli + cld + mov $LOAD_SEG, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + mov $0x8ffe, %sp + ljmp $LOAD_SEG + 0x20, $0 + +1: + .fill 510 - (1b - linux_boot_start), 1, 0 + + /* boot sector signature */ + .byte 0x55 + .byte 0xaa + +linux_boot_end: -- cgit v1.2.3 From f72b519c86b0700473155194a39edf937007eab8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:55:35 +0000 Subject: added osdep.o and nwfpe git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@615 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Makefile.target b/Makefile.target index 9d52680a9..3f5a1ba85 100644 --- a/Makefile.target +++ b/Makefile.target @@ -145,10 +145,15 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o +OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o ifeq ($(TARGET_ARCH), i386) OBJS+= vm86.o endif +ifeq ($(TARGET_ARCH), arm) +OBJS+=nwfpe/softfloat.o 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 +endif SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a @@ -158,6 +163,9 @@ LIBOBJS=thunk.o exec.o translate-all.o cpu-exec.o gdbstub.o \ ifeq ($(TARGET_ARCH), i386) LIBOBJS+=helper.o helper2.o +ifeq ($(ARCH), i386) +LIBOBJS+=translate-copy.o +endif endif ifeq ($(TARGET_ARCH), ppc) @@ -197,7 +205,10 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o +VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o osdep.o +ifeq ($(TARGET_ARCH), i386) +VL_OBJS+=linux_boot.o +endif ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= hw.o endif @@ -271,8 +282,11 @@ endif %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< +%.o: %.S + $(CC) $(DEFINES) -c -o $@ $< + clean: - rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h + rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o install: all install -m 755 -s $(PROGS) $(prefix)/bin -- cgit v1.2.3 From cf98951b82adefb46318b3ed45c8456aac2b9575 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:56:36 +0000 Subject: force boot sector feature git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@616 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 3e1ae0da2..6a1701a5b 100644 --- a/block.c +++ b/block.c @@ -55,6 +55,9 @@ struct BlockDriverState { int cow_bitmap_size; int cow_fd; int64_t cow_sectors_offset; + int boot_sector_enabled; + uint8_t boot_sector_data[512]; + char filename[1024]; }; @@ -262,6 +265,10 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) { fd = bs->cow_fd; offset = bs->cow_sectors_offset; + } else if (sector_num == 0 && bs->boot_sector_enabled) { + memcpy(buf, bs->boot_sector_data, 512); + n = 1; + goto next; } else { fd = bs->fd; offset = 0; @@ -278,6 +285,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, return -1; } } + next: nb_sectors -= n; sector_num += n; buf += n * 512; @@ -291,7 +299,7 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, { int ret, fd, i; int64_t offset, retl; - + if (bs->read_only) return -1; @@ -324,3 +332,13 @@ void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) { *nb_sectors_ptr = bs->total_sectors; } + +/* force a given boot sector. */ +void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) +{ + bs->boot_sector_enabled = 1; + if (size > 512) + size = 512; + memcpy(bs->boot_sector_data, data, size); + memset(bs->boot_sector_data + size, 0, 512 - size); +} -- cgit v1.2.3 From 9acbed06053fc344feb4cd81f2523923c27c9277 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:57:02 +0000 Subject: added CPU_INTERRUPT_EXITTB and code_copy_enabled git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@617 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index a01818a98..a2b62df90 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -464,9 +464,11 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); void cpu_abort(CPUState *env, const char *fmt, ...); extern CPUState *cpu_single_env; +extern int code_copy_enabled; -#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ -#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ +#define CPU_INTERRUPT_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) */ void cpu_interrupt(CPUState *s, int mask); int cpu_breakpoint_insert(CPUState *env, uint32_t pc); -- cgit v1.2.3 From bf3e8bf11e78b271cde3ddadf9e4521585e42867 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 21:58:54 +0000 Subject: experimental code copy support - CPU_INTERRUPT_EXITTB support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@618 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 134 insertions(+), 18 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 4e2d77f3a..44a0f73a5 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -212,6 +212,16 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_HARD; } #endif + if (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 */ +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif + } if (interrupt_request & CPU_INTERRUPT_EXIT) { env->interrupt_request &= ~CPU_INTERRUPT_EXIT; env->exception_index = EXCP_INTERRUPT; @@ -362,7 +372,12 @@ int cpu_exec(CPUState *env1) T0 = tmp_T0; #endif /* see if we can patch the calling TB. */ - if (T0 != 0) { + if (T0 != 0 +#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 *)(T0 & ~3), T0 & 3, tb); spin_unlock(&tb_lock); @@ -384,6 +399,74 @@ int cpu_exec(CPUState *env1) : /* 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)) { + gen_func(); + } else { + /* 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" + ); + } +} #else gen_func(); #endif @@ -512,7 +595,8 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) 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) + int is_write, sigset_t *old_set, + void *puc) { TranslationBlock *tb; int ret; @@ -520,8 +604,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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); + 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(address)) { @@ -539,7 +623,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc); + cpu_restore_state(tb, env, pc, puc); } if (ret == 1) { #if 0 @@ -562,14 +646,16 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, #elif defined(TARGET_ARM) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, - int is_write, sigset_t *old_set) + int is_write, sigset_t *old_set, + void *puc) { /* XXX: do more */ return 0; } #elif defined(TARGET_SPARC) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, - int is_write, sigset_t *old_set) + int is_write, sigset_t *old_set, + void *puc) { /* XXX: locking issue */ if (is_write && page_unprotect(address)) { @@ -579,7 +665,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } #elif defined (TARGET_PPC) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, - int is_write, sigset_t *old_set) + int is_write, sigset_t *old_set, + void *puc) { TranslationBlock *tb; int ret; @@ -609,7 +696,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc); + cpu_restore_state(tb, env, pc, puc); } if (ret == 1) { #if 0 @@ -618,7 +705,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, #endif /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ - sigprocmask(SIG_SETMASK, old_set, NULL); + sigprocmask(SIG_SETMASK, old_set, NULL); do_queue_exception_err(env->exception_index, env->error_code); } else { /* activate soft MMU for this block */ @@ -634,11 +721,32 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, #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 */ @@ -647,10 +755,18 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #define REG_TRAPNO TRAPNO #endif pc = uc->uc_mcontext.gregs[REG_EIP]; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? - (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, - &uc->uc_sigmask); + 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(__powerpc) @@ -674,7 +790,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, is_write = 1; #endif return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask); + is_write, &uc->uc_sigmask, puc); } #elif defined(__alpha__) @@ -704,7 +820,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, } return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask); + is_write, &uc->uc_sigmask, puc); } #elif defined(__sparc__) @@ -736,7 +852,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, } } return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, sigmask); + is_write, sigmask, NULL); } #elif defined(__arm__) @@ -770,7 +886,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, is_write = 0; return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, - &uc->uc_sigmask); + &uc->uc_sigmask, puc); } #else -- cgit v1.2.3 From 59817ccb2c220732d3dc282b47a74faa1c4d06ce Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 22:01:13 +0000 Subject: use qemu memory allocation - added dirty bit support when using host MMU git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@619 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 35 deletions(-) diff --git a/exec.c b/exec.c index 20a379508..06fc0429a 100644 --- a/exec.c +++ b/exec.c @@ -143,7 +143,7 @@ static inline PageDesc *page_find_alloc(unsigned int index) p = *lp; if (!p) { /* allocate if not found */ - p = malloc(sizeof(PageDesc) * L2_SIZE); + p = qemu_malloc(sizeof(PageDesc) * L2_SIZE); memset(p, 0, sizeof(PageDesc) * L2_SIZE); *lp = p; } @@ -173,7 +173,7 @@ static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) p = *lp; if (!p) { /* allocate if not found */ - p = malloc(sizeof(VirtPageDesc) * L2_SIZE); + p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE); memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE); *lp = p; } @@ -226,7 +226,7 @@ void cpu_exec_init(void) static inline void invalidate_page_bitmap(PageDesc *p) { if (p->code_bitmap) { - free(p->code_bitmap); + qemu_free(p->code_bitmap); p->code_bitmap = NULL; } p->code_write_count = 0; @@ -406,7 +406,7 @@ static inline void tb_invalidate(TranslationBlock *tb) TranslationBlock *tb1, *tb2, **ptb; tb_invalidated_flag = 1; - + /* remove the TB from the hash list */ h = tb_hash_func(tb->pc); ptb = &tb_hash[h]; @@ -501,7 +501,7 @@ static void build_page_bitmap(PageDesc *p) int n, tb_start, tb_end; TranslationBlock *tb; - p->code_bitmap = malloc(TARGET_PAGE_SIZE / 8); + p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8); if (!p->code_bitmap) return; memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8); @@ -585,7 +585,13 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len, tar { PageDesc *p; int offset, b; - +#if 0 + if (cpu_single_env->cr[0] & CR0_PE_MASK) { + printf("modifying code at 0x%x size=%d EIP=%x\n", + (vaddr & TARGET_PAGE_MASK) | (start & ~TARGET_PAGE_MASK), len, + cpu_single_env->eip); + } +#endif p = page_find(start >> TARGET_PAGE_BITS); if (!p) return; @@ -775,7 +781,12 @@ void tb_link(TranslationBlock *tb) } #endif vp->phys_addr = tb->page_addr[0]; - vp->valid_tag = virt_valid_tag; + if (vp->valid_tag != virt_valid_tag) { + vp->valid_tag = virt_valid_tag; +#if !defined(CONFIG_SOFTMMU) + vp->prot = 0; +#endif + } if (tb->page_addr[1] != -1) { addr += TARGET_PAGE_SIZE; @@ -788,7 +799,12 @@ void tb_link(TranslationBlock *tb) } #endif vp->phys_addr = tb->page_addr[1]; - vp->valid_tag = virt_valid_tag; + if (vp->valid_tag != virt_valid_tag) { + vp->valid_tag = virt_valid_tag; +#if !defined(CONFIG_SOFTMMU) + vp->prot = 0; +#endif + } } } #endif @@ -971,7 +987,7 @@ void cpu_interrupt(CPUState *env, int mask) { TranslationBlock *tb; static int interrupt_lock; - + env->interrupt_request |= mask; /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ @@ -1172,7 +1188,7 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end) { CPUState *env; - target_ulong length; + target_ulong length, start1; int i; start &= TARGET_PAGE_MASK; @@ -1186,11 +1202,39 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end) env = cpu_single_env; /* we modify the TLB cache so that the dirty bit will be set again when accessing the range */ - start += (unsigned long)phys_ram_base; + start1 = start + (unsigned long)phys_ram_base; for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_write[0][i], start, length); + tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length); for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_write[1][i], start, length); + tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length); + +#if !defined(CONFIG_SOFTMMU) + /* XXX: this is expensive */ + { + VirtPageDesc *p; + int j; + target_ulong addr; + + for(i = 0; i < L1_SIZE; i++) { + p = l1_virt_map[i]; + if (p) { + addr = i << (TARGET_PAGE_BITS + L2_BITS); + for(j = 0; j < L2_SIZE; j++) { + if (p->valid_tag == virt_valid_tag && + p->phys_addr >= start && p->phys_addr < end && + (p->prot & PROT_WRITE)) { + if (addr < MMAP_AREA_END) { + mprotect((void *)addr, TARGET_PAGE_SIZE, + p->prot & ~PROT_WRITE); + } + } + addr += TARGET_PAGE_SIZE; + p++; + } + } + } + } +#endif } static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, @@ -1220,8 +1264,10 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) tlb_set_dirty1(&env->tlb_write[1][i], addr); } -/* add a new TLB entry. At most one entry for a given virtual - address is permitted. */ +/* add a new TLB entry. At most one entry for a given virtual address + is permitted. Return 0 if OK or 2 if the page could not be mapped + (can only happen in non SOFTMMU mode for I/O pages or pages + conflicting with the host address space). */ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, int is_user, int is_softmmu) { @@ -1301,25 +1347,33 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, ret = 2; } else { void *map_addr; - if (prot & PROT_WRITE) { - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || first_tb) { - /* ROM: we do as if code was inside */ - /* if code is present, we only map as read only and save the - original mapping */ - VirtPageDesc *vp; - - vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS); - vp->phys_addr = pd; - vp->prot = prot; - vp->valid_tag = virt_valid_tag; - prot &= ~PAGE_WRITE; + + if (vaddr >= MMAP_AREA_END) { + ret = 2; + } else { + if (prot & PROT_WRITE) { + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + first_tb || + ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + !cpu_physical_memory_is_dirty(pd))) { + /* ROM: we do as if code was inside */ + /* if code is present, we only map as read only and save the + original mapping */ + VirtPageDesc *vp; + + vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS); + vp->phys_addr = pd; + vp->prot = prot; + vp->valid_tag = virt_valid_tag; + prot &= ~PAGE_WRITE; + } + } + map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, + MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK)); + if (map_addr == MAP_FAILED) { + cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", + paddr, vaddr); } - } - map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, - MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK)); - if (map_addr == MAP_FAILED) { - cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", - paddr, vaddr); } } } @@ -1338,6 +1392,10 @@ int page_unprotect(unsigned long addr) printf("page_unprotect: addr=0x%08x\n", addr); #endif addr &= TARGET_PAGE_MASK; + + /* if it is not mapped, no need to worry here */ + if (addr >= MMAP_AREA_END) + return 0; vp = virt_page_find(addr >> TARGET_PAGE_BITS); if (!vp) return 0; @@ -1351,8 +1409,13 @@ int page_unprotect(unsigned long addr) printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", addr, vp->phys_addr, vp->prot); #endif + /* set the dirty bit */ + phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1; + /* flush the code inside */ tb_invalidate_phys_page(vp->phys_addr); - mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot); + if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0) + cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n", + (unsigned long)addr, vp->prot); return 1; #else return 0; @@ -1642,7 +1705,7 @@ static void io_mem_init(void) io_mem_nb = 5; /* alloc dirty bits array */ - phys_ram_dirty = malloc(phys_ram_size >> TARGET_PAGE_BITS); + phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS); } /* mem_read and mem_write are arrays of functions containing the -- cgit v1.2.3 From 77fef8c148e4bec1d1089b3729bd32efdbd3a6c0 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 22:05:46 +0000 Subject: experimental code copy support - added new Linux kernel loader git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@620 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 352 +++++++++++++++++++++++-------------------------------------------- vl.h | 2 +- 2 files changed, 122 insertions(+), 232 deletions(-) diff --git a/vl.c b/vl.c index 0c1f839d7..99a9fc4a1 100644 --- a/vl.c +++ b/vl.c @@ -78,7 +78,6 @@ //#define DEBUG_SERIAL -#define PHYS_RAM_BASE 0xac000000 #if !defined(CONFIG_SOFTMMU) #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) #else @@ -97,126 +96,12 @@ #define KERNEL_STACK_ADDR 0x00400000 #endif #endif -#define INITRD_LOAD_ADDR 0x00400000 -#define KERNEL_PARAMS_ADDR 0x00090000 +#define INITRD_LOAD_ADDR 0x00400000 +#define KERNEL_PARAMS_ADDR 0x00090000 +#define KERNEL_CMDLINE_ADDR 0x00099000 #define GUI_REFRESH_INTERVAL 30 -/* from plex86 (BSD license) */ -struct __attribute__ ((packed)) linux_params { - // For 0x00..0x3f, see 'struct screen_info' in linux/include/linux/tty.h. - // I just padded out the VESA parts, rather than define them. - - /* 0x000 */ uint8_t orig_x; - /* 0x001 */ uint8_t orig_y; - /* 0x002 */ uint16_t ext_mem_k; - /* 0x004 */ uint16_t orig_video_page; - /* 0x006 */ uint8_t orig_video_mode; - /* 0x007 */ uint8_t orig_video_cols; - /* 0x008 */ uint16_t unused1; - /* 0x00a */ uint16_t orig_video_ega_bx; - /* 0x00c */ uint16_t unused2; - /* 0x00e */ uint8_t orig_video_lines; - /* 0x00f */ uint8_t orig_video_isVGA; - /* 0x010 */ uint16_t orig_video_points; - /* 0x012 */ uint8_t pad0[0x20 - 0x12]; // VESA info. - /* 0x020 */ uint16_t cl_magic; // Commandline magic number (0xA33F) - /* 0x022 */ uint16_t cl_offset; // Commandline offset. Address of commandline - // is calculated as 0x90000 + cl_offset, bu - // only if cl_magic == 0xA33F. - /* 0x024 */ uint8_t pad1[0x40 - 0x24]; // VESA info. - - /* 0x040 */ uint8_t apm_bios_info[20]; // struct apm_bios_info - /* 0x054 */ uint8_t pad2[0x80 - 0x54]; - - // Following 2 from 'struct drive_info_struct' in drivers/block/cciss.h. - // Might be truncated? - /* 0x080 */ uint8_t hd0_info[16]; // hd0-disk-parameter from intvector 0x41 - /* 0x090 */ uint8_t hd1_info[16]; // hd1-disk-parameter from intvector 0x46 - - // System description table truncated to 16 bytes - // From 'struct sys_desc_table_struct' in linux/arch/i386/kernel/setup.c. - /* 0x0a0 */ uint16_t sys_description_len; - /* 0x0a2 */ uint8_t sys_description_table[14]; - // [0] machine id - // [1] machine submodel id - // [2] BIOS revision - // [3] bit1: MCA bus - - /* 0x0b0 */ uint8_t pad3[0x1e0 - 0xb0]; - /* 0x1e0 */ uint32_t alt_mem_k; - /* 0x1e4 */ uint8_t pad4[4]; - /* 0x1e8 */ uint8_t e820map_entries; - /* 0x1e9 */ uint8_t eddbuf_entries; // EDD_NR - /* 0x1ea */ uint8_t pad5[0x1f1 - 0x1ea]; - /* 0x1f1 */ uint8_t setup_sects; // size of setup.S, number of sectors - /* 0x1f2 */ uint16_t mount_root_rdonly; // MOUNT_ROOT_RDONLY (if !=0) - /* 0x1f4 */ uint16_t sys_size; // size of compressed kernel-part in the - // (b)zImage-file (in 16 byte units, rounded up) - /* 0x1f6 */ uint16_t swap_dev; // (unused AFAIK) - /* 0x1f8 */ uint16_t ramdisk_flags; - /* 0x1fa */ uint16_t vga_mode; // (old one) - /* 0x1fc */ uint16_t orig_root_dev; // (high=Major, low=minor) - /* 0x1fe */ uint8_t pad6[1]; - /* 0x1ff */ uint8_t aux_device_info; - /* 0x200 */ uint16_t jump_setup; // Jump to start of setup code, - // aka "reserved" field. - /* 0x202 */ uint8_t setup_signature[4]; // Signature for SETUP-header, ="HdrS" - /* 0x206 */ uint16_t header_format_version; // Version number of header format; - /* 0x208 */ uint8_t setup_S_temp0[8]; // Used by setup.S for communication with - // boot loaders, look there. - /* 0x210 */ uint8_t loader_type; - // 0 for old one. - // else 0xTV: - // T=0: LILO - // T=1: Loadlin - // T=2: bootsect-loader - // T=3: SYSLINUX - // T=4: ETHERBOOT - // V=version - /* 0x211 */ uint8_t loadflags; - // bit0 = 1: kernel is loaded high (bzImage) - // bit7 = 1: Heap and pointer (see below) set by boot - // loader. - /* 0x212 */ uint16_t setup_S_temp1; - /* 0x214 */ uint32_t kernel_start; - /* 0x218 */ uint32_t initrd_start; - /* 0x21c */ uint32_t initrd_size; - /* 0x220 */ uint8_t setup_S_temp2[4]; - /* 0x224 */ uint16_t setup_S_heap_end_pointer; - /* 0x226 */ uint8_t pad7[0x2d0 - 0x226]; - - /* 0x2d0 : Int 15, ax=e820 memory map. */ - // (linux/include/asm-i386/e820.h, 'struct e820entry') -#define E820MAX 32 -#define E820_RAM 1 -#define E820_RESERVED 2 -#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */ -#define E820_NVS 4 - struct { - uint64_t addr; - uint64_t size; - uint32_t type; - } e820map[E820MAX]; - - /* 0x550 */ uint8_t pad8[0x600 - 0x550]; - - // BIOS Enhanced Disk Drive Services. - // (From linux/include/asm-i386/edd.h, 'struct edd_info') - // Each 'struct edd_info is 78 bytes, times a max of 6 structs in array. - /* 0x600 */ uint8_t eddbuf[0x7d4 - 0x600]; - - /* 0x7d4 */ uint8_t pad9[0x800 - 0x7d4]; - /* 0x800 */ uint8_t commandline[0x800]; - - /* 0x1000 */ - uint64_t gdt_table[256]; - uint64_t idt_table[48]; -}; - -#define KERNEL_CS 0x10 -#define KERNEL_DS 0x18 - /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 @@ -360,28 +245,28 @@ char *pstrcat(char *buf, int buf_size, const char *s) return buf; } -int load_kernel(const char *filename, uint8_t *addr) +#if defined (TARGET_I386) +int load_kernel(const char *filename, uint8_t *addr, + uint8_t *real_addr) { int fd, size; -#if defined (TARGET_I386) int setup_sects; - uint8_t bootsect[512]; -#endif - printf("Load kernel at %p (0x%08x)\n", addr, - (uint32_t)addr - (uint32_t)phys_ram_base); fd = open(filename, O_RDONLY); if (fd < 0) return -1; -#if defined (TARGET_I386) - if (read(fd, bootsect, 512) != 512) + + /* load 16 bit code */ + if (read(fd, real_addr, 512) != 512) goto fail; - setup_sects = bootsect[0x1F1]; + setup_sects = real_addr[0x1F1]; if (!setup_sects) setup_sects = 4; - /* skip 16 bit setup code */ - lseek(fd, (setup_sects + 1) * 512, SEEK_SET); -#endif + if (read(fd, real_addr + 512, setup_sects * 512) != + setup_sects * 512) + goto fail; + + /* load 32 bit code */ size = read(fd, addr, 16 * 1024 * 1024); if (size < 0) goto fail; @@ -391,6 +276,7 @@ int load_kernel(const char *filename, uint8_t *addr) close(fd); return -1; } +#endif /* return the size or -1 if error */ int load_image(const char *filename, uint8_t *addr) @@ -486,6 +372,7 @@ void hw_error(const char *fmt, ...) /* PC cmos mappings */ #define REG_EQUIPMENT_BYTE 0x14 #define REG_IBM_CENTURY_BYTE 0x32 +#define REG_IBM_PS2_CENTURY_BYTE 0x37 uint8_t cmos_data[128]; uint8_t cmos_index; @@ -550,6 +437,7 @@ static void cmos_update_time(void) cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); + cmos_data[REG_IBM_PS2_CENTURY_BYTE] = cmos_data[REG_IBM_CENTURY_BYTE]; } uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) @@ -568,6 +456,7 @@ uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) case RTC_MONTH: case RTC_YEAR: case REG_IBM_CENTURY_BYTE: + case REG_IBM_PS2_CENTURY_BYTE: cmos_update_time(); ret = cmos_data[cmos_index]; break; @@ -3082,23 +2971,6 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, } } -#ifdef CONFIG_SOFTMMU -void *get_mmap_addr(unsigned long size) -{ - return NULL; -} -#else -unsigned long mmap_addr = PHYS_RAM_BASE; - -void *get_mmap_addr(unsigned long size) -{ - unsigned long addr; - addr = mmap_addr; - mmap_addr += ((size + 4095) & ~4095) + 4096; - return (void *)addr; -} -#endif - /* main execution loop */ CPUState *cpu_gdbstub_get_env(void *opaque) @@ -3259,6 +3131,10 @@ void help(void) "-d output log to %s\n" "-hdachs c,h,s force hard disk 0 geometry (usually qemu can guess it)\n" "-L path set the directory for the BIOS and VGA BIOS\n" +#ifdef USE_CODE_COPY + "-no-code-copy disable code copy acceleration\n" +#endif + "\n" "During emulation, use C-a h to get terminal commands:\n", #ifdef CONFIG_SOFTMMU @@ -3295,6 +3171,7 @@ struct option long_options[] = { { "boot", 1, NULL, 0, }, { "fda", 1, NULL, 0, }, { "fdb", 1, NULL, 0, }, + { "no-code-copy", 0, NULL, 0}, { NULL, 0, NULL, 0 }, }; @@ -3310,19 +3187,26 @@ extern void __sigaction(); #endif #endif /* CONFIG_SDL */ +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + +/* this stack is only used during signal handling */ +#define SIGNAL_STACK_SIZE 32768 + +static uint8_t *signal_stack; + +#endif + int main(int argc, char **argv) { int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; int snapshot, linux_boot; -#if defined (TARGET_I386) - struct linux_params *params; -#endif struct sigaction act; struct itimerval itv; CPUState *env; const char *initrd_filename; const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *kernel_filename, *kernel_cmdline; + char buf[1024]; DisplayState *ds = &display_state; /* we never want that malloc() uses mmap() */ @@ -3420,6 +3304,9 @@ int main(int argc, char **argv) case 14: fd_filename[1] = optarg; break; + case 15: + code_copy_enabled = 0; + break; } break; case 'h': @@ -3554,9 +3441,42 @@ int main(int argc, char **argv) /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); +#if defined(TARGET_I386) + /* RAW PC boot */ + + /* BIOS load */ + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + 0x000f0000); + if (ret != 0x10000) { + fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); + exit(1); + } + + /* VGA BIOS load */ + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); + ret = load_image(buf, phys_ram_base + 0x000c0000); + + /* setup basic memory access */ + cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); + cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); + + bochs_bios_init(); + if (linux_boot) { + extern uint8_t linux_boot_start; + extern uint8_t linux_boot_end; + + if (bs_table[0] == NULL) { + fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); + exit(1); + } + bdrv_set_boot_sector(bs_table[0], &linux_boot_start, + &linux_boot_end - &linux_boot_start); + /* now we can load the kernel */ - ret = load_kernel(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + ret = load_kernel(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR, + phys_ram_base + KERNEL_PARAMS_ADDR); if (ret < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); @@ -3573,89 +3493,30 @@ int main(int argc, char **argv) exit(1); } } - - /* init kernel params */ -#ifdef TARGET_I386 - params = (void *)(phys_ram_base + KERNEL_PARAMS_ADDR); - memset(params, 0, sizeof(struct linux_params)); - params->mount_root_rdonly = 0; - stw_raw(¶ms->cl_magic, 0xA33F); - stw_raw(¶ms->cl_offset, params->commandline - (uint8_t *)params); - stl_raw(¶ms->alt_mem_k, (ram_size / 1024) - 1024); - pstrcat(params->commandline, sizeof(params->commandline), kernel_cmdline); - params->loader_type = 0x01; if (initrd_size > 0) { - stl_raw(¶ms->initrd_start, INITRD_LOAD_ADDR); - stl_raw(¶ms->initrd_size, initrd_size); + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); } - params->orig_video_lines = 25; - params->orig_video_cols = 80; - - /* setup basic memory access */ - cpu_x86_update_cr0(env, 0x00000033); - - memset(params->idt_table, 0, sizeof(params->idt_table)); - - stq_raw(¶ms->gdt_table[2], 0x00cf9a000000ffffLL); /* KERNEL_CS */ - stq_raw(¶ms->gdt_table[3], 0x00cf92000000ffffLL); /* KERNEL_DS */ - /* for newer kernels (2.6.0) CS/DS are at different addresses */ - stq_raw(¶ms->gdt_table[12], 0x00cf9a000000ffffLL); /* KERNEL_CS */ - stq_raw(¶ms->gdt_table[13], 0x00cf92000000ffffLL); /* KERNEL_DS */ - - env->idt.base = (void *)((uint8_t *)params->idt_table - phys_ram_base); - env->idt.limit = sizeof(params->idt_table) - 1; - env->gdt.base = (void *)((uint8_t *)params->gdt_table - phys_ram_base); - env->gdt.limit = sizeof(params->gdt_table) - 1; - - cpu_x86_load_seg_cache(env, R_CS, KERNEL_CS, NULL, 0xffffffff, 0x00cf9a00); - cpu_x86_load_seg_cache(env, R_DS, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); - cpu_x86_load_seg_cache(env, R_ES, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); - cpu_x86_load_seg_cache(env, R_SS, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); - cpu_x86_load_seg_cache(env, R_FS, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); - cpu_x86_load_seg_cache(env, R_GS, KERNEL_DS, NULL, 0xffffffff, 0x00cf9200); - - env->eip = KERNEL_LOAD_ADDR; - env->regs[R_ESI] = KERNEL_PARAMS_ADDR; - env->eflags = 0x2; -#elif defined (TARGET_PPC) - PPC_init_hw(env, ram_size, KERNEL_LOAD_ADDR, ret, - KERNEL_STACK_ADDR, boot_device); -#endif - } else { - char buf[1024]; - - /* RAW PC boot */ -#if defined(TARGET_I386) - /* BIOS load */ - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - ret = load_image(buf, phys_ram_base + 0x000f0000); - if (ret != 0x10000) { - fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); - exit(1); - } - - /* VGA BIOS load */ - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); - ret = load_image(buf, phys_ram_base + 0x000c0000); - - /* setup basic memory access */ - cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); - cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); - - bochs_bios_init(); + pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, + kernel_cmdline); + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, + KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); + /* loader type */ + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); + } #elif defined(TARGET_PPC) - /* allocate ROM */ - // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); - printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); - ret = load_image(buf, phys_ram_base + 0x000f0000); - if (ret != 0x10000) { - fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", - buf, ret); - exit(1); - } -#endif + /* allocate ROM */ + // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); + printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); + ret = load_image(buf, phys_ram_base + 0x000f0000); + if (ret != 0x10000) { + fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", + buf, ret); + exit(1); } +#endif /* terminal init */ if (nographic) { @@ -3692,15 +3553,44 @@ int main(int argc, char **argv) PPC_end_init(); #endif fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device); + /* setup cpu signal handlers for MMU / self modifying code handling */ +#if !defined(CONFIG_SOFTMMU) + +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + { + stack_t stk; + signal_stack = malloc(SIGNAL_STACK_SIZE); + stk.ss_sp = signal_stack; + stk.ss_size = SIGNAL_STACK_SIZE; + stk.ss_flags = 0; + + if (sigaltstack(&stk, NULL) < 0) { + perror("sigaltstack"); + exit(1); + } + } +#endif + sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; -#if !defined(CONFIG_SOFTMMU) +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + act.sa_flags |= SA_ONSTACK; +#endif act.sa_sigaction = host_segv_handler; sigaction(SIGSEGV, &act, NULL); sigaction(SIGBUS, &act, NULL); +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + sigaction(SIGFPE, &act, NULL); +#endif #endif + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + act.sa_flags |= SA_ONSTACK; +#endif act.sa_sigaction = host_alarm_handler; sigaction(SIGALRM, &act, NULL); diff --git a/vl.h b/vl.h index 4c2ed6ee0..ebc809a1c 100644 --- a/vl.h +++ b/vl.h @@ -32,7 +32,6 @@ extern int64_t ticks_per_sec; typedef void (IOPortWriteFunc)(struct CPUState *env, uint32_t address, uint32_t data); typedef uint32_t (IOPortReadFunc)(struct CPUState *env, uint32_t address); -void *get_mmap_addr(unsigned long size); int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); void pic_set_irq(int irq, int level); @@ -56,6 +55,7 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); +void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); /* user mode linux compatible COW file */ #define COW_MAGIC 0x4f4f4f4d /* MOOO */ -- cgit v1.2.3 From 0e4b179d3308382e9da91a3b8f443d0b72eb0db4 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 22:08:32 +0000 Subject: experimental code copy support - fixed A20 emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@621 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index f5c31d0df..e1dc4741d 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -31,6 +31,13 @@ //#define DEBUG_MMU +#ifdef USE_CODE_COPY +#include +#include + +_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) +#endif + CPUX86State *cpu_x86_init(void) { CPUX86State *env; @@ -84,6 +91,26 @@ CPUX86State *cpu_x86_init(void) inited = 1; optimize_flags_init(); } +#ifdef USE_CODE_COPY + /* testing code for code copy case */ + { + struct modify_ldt_ldt_s ldt; + + ldt.entry_number = 1; + ldt.base_addr = (unsigned long)env; + ldt.limit = (sizeof(CPUState) + 0xfff) >> 12; + ldt.seg_32bit = 1; + ldt.contents = MODIFY_LDT_CONTENTS_DATA; + ldt.read_exec_only = 0; + ldt.limit_in_pages = 1; + ldt.seg_not_present = 0; + ldt.useable = 1; + modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ + + asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); + cpu_single_env = env; + } +#endif return env; } @@ -213,7 +240,7 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) #endif /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ - cpu_interrupt(env, 0); + cpu_interrupt(env, CPU_INTERRUPT_EXITTB); /* when a20 is changed, all the MMU mappings are invalid, so we must flush everything */ -- cgit v1.2.3 From 3a1d9b8bbb693d18a346552a5e98c96ad5006ff9 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 22:10:33 +0000 Subject: fixed lea exception git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@622 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 0bbd160b4..6e8d8116c 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2554,6 +2554,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x8d: /* lea */ ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; reg = (modrm >> 3) & 7; /* we must ensure that no segment is added */ s->override = -1; @@ -2815,7 +2818,6 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) mod = (modrm >> 6) & 3; rm = modrm & 7; op = ((b & 7) << 3) | ((modrm >> 3) & 7); - if (mod != 3) { /* memory op */ gen_lea_modrm(s, modrm, ®_addr, &offset_addr); @@ -4479,7 +4481,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, pc_start = (uint8_t *)tb->pc; cs_base = (uint8_t *)tb->cs_base; flags = tb->flags; - + dc->pe = (flags >> HF_PE_SHIFT) & 1; dc->code32 = (flags >> HF_CS32_SHIFT) & 1; dc->ss32 = (flags >> HF_SS32_SHIFT) & 1; -- cgit v1.2.3 From 58fe2f10f0e9ddd63bc6004776ef6e874101e9c5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 22:11:32 +0000 Subject: experimental code copy support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@623 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 12 +- linux-user/signal.c | 6 +- target-i386/cpu.h | 9 + target-i386/helper.c | 4 +- target-i386/translate-copy.c | 1544 ++++++++++++++++++++++++++++++++++++++++++ translate-all.c | 49 +- 6 files changed, 1603 insertions(+), 21 deletions(-) create mode 100644 target-i386/translate-copy.c diff --git a/exec-all.h b/exec-all.h index 500818ba8..a14efa94e 100644 --- a/exec-all.h +++ b/exec-all.h @@ -79,7 +79,13 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, int max_code_size, int *gen_code_size_ptr); int cpu_restore_state(struct TranslationBlock *tb, - CPUState *env, unsigned long searched_pc); + CPUState *env, unsigned long searched_pc, + void *puc); +int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb, + int max_code_size, int *gen_code_size_ptr); +int cpu_restore_state_copy(struct TranslationBlock *tb, + CPUState *env, unsigned long searched_pc, + void *puc); void cpu_exec_init(void); int page_unprotect(unsigned long address); void tb_invalidate_page_range(target_ulong start, target_ulong end); @@ -145,6 +151,9 @@ typedef struct TranslationBlock { unsigned int flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ + uint16_t cflags; /* compile flags */ +#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */ + uint8_t *tc_ptr; /* pointer to the translated code */ struct TranslationBlock *hash_next; /* next matching tb for virtual address */ /* next matching tb for physical address. */ @@ -552,4 +561,3 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; } #endif - diff --git a/linux-user/signal.c b/linux-user/signal.c index bb006cc79..666d6e14f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -378,7 +378,11 @@ static void host_signal_handler(int host_signum, siginfo_t *info, /* the CPU emulator uses some host signals to detect exceptions, we we forward to it some signals */ - if (host_signum == SIGSEGV || host_signum == SIGBUS) { + if (host_signum == SIGSEGV || host_signum == SIGBUS +#if defined(TARGET_I386) && defined(USE_CODE_COPY) + || host_signum == SIGFPE +#endif + ) { if (cpu_signal_handler(host_signum, info, puc)) return; } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 676e6ceae..99c6bb98c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -24,6 +24,10 @@ #include "cpu-defs.h" +#if defined(__i386__) && !defined(CONFIG_SOFTMMU) +#define USE_CODE_COPY +#endif + #define R_EAX 0 #define R_ECX 1 #define R_EDX 2 @@ -121,6 +125,7 @@ #define HF_SS32_MASK (1 << HF_SS32_SHIFT) #define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) #define HF_PE_MASK (1 << HF_PE_SHIFT) +#define HF_TF_MASK (1 << HF_TF_SHIFT) #define CR0_PE_MASK (1 << 0) #define CR0_TS_MASK (1 << 3) @@ -297,6 +302,10 @@ typedef struct CPUX86State { uint32_t sysenter_cs; uint32_t sysenter_esp; uint32_t sysenter_eip; + + /* temporary data for USE_CODE_COPY mode */ + uint32_t tmp0; + uint32_t saved_esp; /* exception/interrupt handling */ jmp_buf jmp_env; diff --git a/target-i386/helper.c b/target-i386/helper.c index 9a980bd9d..31168573e 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -869,7 +869,7 @@ void do_interrupt(int intno, int is_int, int error_code, { extern FILE *stdout; static int count; - if (env->cr[0] & CR0_PE_MASK) { + if (env->cr[0] & CR0_PE_MASK) { fprintf(stdout, "%d: v=%02x e=%04x i=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x", count, intno, error_code, is_int, env->hflags & HF_CPL_MASK, @@ -2489,7 +2489,7 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc); + cpu_restore_state(tb, env, pc, NULL); } } raise_exception_err(EXCP0E_PAGE, env->error_code); diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c new file mode 100644 index 000000000..340864ac7 --- /dev/null +++ b/target-i386/translate-copy.c @@ -0,0 +1,1544 @@ +/* + * i386 on i386 translation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +extern char exec_loop; + +/* operand size */ +enum { + OT_BYTE = 0, + OT_WORD, + OT_LONG, + OT_QUAD, +}; + +#define PREFIX_REPZ 0x01 +#define PREFIX_REPNZ 0x02 +#define PREFIX_LOCK 0x04 +#define PREFIX_DATA 0x08 +#define PREFIX_ADR 0x10 + +typedef struct DisasContext { + /* current insn context */ + int override; /* -1 if no override */ + int prefix; + int aflag, dflag; + uint8_t *pc; /* pc = eip + cs_base */ + int is_jmp; /* 1 = means jump (stop translation), 2 means CPU + static state change (stop translation) */ + /* code output */ + uint8_t *gen_code_ptr; + uint8_t *gen_code_start; + + /* current block context */ + uint8_t *cs_base; /* base of CS segment */ + int pe; /* protected mode */ + int code32; /* 32 bit code segment */ + int f_st; /* currently unused */ + int vm86; /* vm86 mode */ + int cpl; + int iopl; + struct TranslationBlock *tb; +} DisasContext; + +#define CPU_FIELD_OFFSET(field) offsetof(CPUState, field) + +#define CPU_SEG 0x64 /* fs override */ + +static inline void gb(DisasContext *s, uint32_t val) +{ + *s->gen_code_ptr++ = val; +} + +static inline void gw(DisasContext *s, uint32_t val) +{ + *s->gen_code_ptr++ = val; + *s->gen_code_ptr++ = val >> 8; +} + +static inline void gl(DisasContext *s, uint32_t val) +{ + *s->gen_code_ptr++ = val; + *s->gen_code_ptr++ = val >> 8; + *s->gen_code_ptr++ = val >> 16; + *s->gen_code_ptr++ = val >> 24; +} + +static inline void gjmp(DisasContext *s, long val) +{ + gb(s, 0xe9); /* jmp */ + gl(s, val - (long)(s->gen_code_ptr + 4)); +} + +static inline void gen_movl_addr_im(DisasContext *s, + uint32_t addr, uint32_t val) +{ + gb(s, CPU_SEG); /* seg movl im, addr */ + gb(s, 0xc7); + gb(s, 0x05); + gl(s, addr); + gl(s, val); +} + +static inline void gen_movw_addr_im(DisasContext *s, + uint32_t addr, uint32_t val) +{ + gb(s, CPU_SEG); /* seg movl im, addr */ + gb(s, 0x66); + gb(s, 0xc7); + gb(s, 0x05); + gl(s, addr); + gw(s, val); +} + + +static void gen_jmp(DisasContext *s, uint32_t target_eip) +{ + TranslationBlock *tb = s->tb; + + gb(s, 0xe9); /* jmp */ + tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start; + gl(s, 0); + + tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; + gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); + gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); + gjmp(s, (long)&exec_loop); + + s->is_jmp = 1; +} + +static void gen_jcc(DisasContext *s, int op, + uint32_t target_eip, uint32_t next_eip) +{ + TranslationBlock *tb = s->tb; + + gb(s, 0x0f); /* jcc */ + gb(s, 0x80 + op); + tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start; + gl(s, 0); + gb(s, 0xe9); /* jmp */ + tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start; + gl(s, 0); + + tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; + gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); + gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); + gjmp(s, (long)&exec_loop); + + tb->tb_next_offset[1] = s->gen_code_ptr - s->gen_code_start; + gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), next_eip); + gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb | 1); + gjmp(s, (long)&exec_loop); + + s->is_jmp = 1; +} + +static void gen_eob(DisasContext *s) +{ + gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), 0); + gjmp(s, (long)&exec_loop); + + s->is_jmp = 1; +} + +static inline void gen_lea_modrm(DisasContext *s, int modrm) +{ + int havesib; + int base, disp; + int index; + int scale; + int mod, rm, code; + + mod = (modrm >> 6) & 3; + rm = modrm & 7; + + if (s->aflag) { + + havesib = 0; + base = rm; + index = 0; + scale = 0; + + if (base == 4) { + havesib = 1; + code = ldub_code(s->pc++); + scale = (code >> 6) & 3; + index = (code >> 3) & 7; + base = code & 7; + } + + switch (mod) { + case 0: + if (base == 5) { + base = -1; + disp = ldl_code(s->pc); + s->pc += 4; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub_code(s->pc++); + break; + default: + case 2: + disp = ldl_code(s->pc); + s->pc += 4; + break; + } + + } else { + switch (mod) { + case 0: + if (rm == 6) { + disp = lduw_code(s->pc); + s->pc += 2; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub_code(s->pc++); + break; + default: + case 2: + disp = lduw_code(s->pc); + s->pc += 2; + break; + } + } +} + +static inline void parse_modrm(DisasContext *s, int modrm) +{ + if ((modrm & 0xc0) != 0xc0) + gen_lea_modrm(s, modrm); +} + +static inline uint32_t insn_get(DisasContext *s, int ot) +{ + uint32_t ret; + + switch(ot) { + case OT_BYTE: + ret = ldub_code(s->pc); + s->pc++; + break; + case OT_WORD: + ret = lduw_code(s->pc); + s->pc += 2; + break; + default: + case OT_LONG: + ret = ldl_code(s->pc); + s->pc += 4; + break; + } + return ret; +} + +/* convert one instruction. s->is_jmp is set if the translation must + be stopped. */ +static int disas_insn(DisasContext *s) +{ + uint8_t *pc_start, *pc_tmp, *pc_start_insn; + int b, prefixes, aflag, dflag, next_eip, val; + int ot; + int modrm, mod, op; + + pc_start = s->pc; + prefixes = 0; + aflag = s->code32; + dflag = s->code32; + s->override = -1; + next_byte: + b = ldub_code(s->pc); + s->pc++; + /* check prefixes */ + switch (b) { + case 0xf3: + prefixes |= PREFIX_REPZ; + goto next_byte; + case 0xf2: + prefixes |= PREFIX_REPNZ; + goto next_byte; + case 0xf0: + prefixes |= PREFIX_LOCK; + goto next_byte; + case 0x2e: + s->override = R_CS; + goto next_byte; + case 0x36: + s->override = R_SS; + goto next_byte; + case 0x3e: + s->override = R_DS; + goto next_byte; + case 0x26: + s->override = R_ES; + goto next_byte; + case 0x64: + s->override = R_FS; + goto next_byte; + case 0x65: + s->override = R_GS; + goto next_byte; + case 0x66: + prefixes |= PREFIX_DATA; + goto next_byte; + case 0x67: + prefixes |= PREFIX_ADR; + goto next_byte; + } + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + if (prefixes & PREFIX_ADR) + aflag ^= 1; + + s->prefix = prefixes; + s->aflag = aflag; + s->dflag = dflag; + + /* lock generation */ + if (prefixes & PREFIX_LOCK) + goto unsupported_op; + if (s->override == R_FS || s->override == R_GS || s->override == R_CS) + goto unsupported_op; + + pc_start_insn = s->pc - 1; + /* now check op code */ + reswitch: + switch(b) { + case 0x0f: + /**************************/ + /* extended op code */ + b = ldub_code(s->pc++) | 0x100; + goto reswitch; + + /**************************/ + /* arith & logic */ + case 0x00 ... 0x05: + case 0x08 ... 0x0d: + case 0x10 ... 0x15: + case 0x18 ... 0x1d: + case 0x20 ... 0x25: + case 0x28 ... 0x2d: + case 0x30 ... 0x35: + case 0x38 ... 0x3d: + { + int f; + f = (b >> 1) & 3; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + switch(f) { + case 0: /* OP Ev, Gv */ + modrm = ldub_code(s->pc++); + parse_modrm(s, modrm); + break; + case 1: /* OP Gv, Ev */ + modrm = ldub_code(s->pc++); + parse_modrm(s, modrm); + break; + case 2: /* OP A, Iv */ + insn_get(s, ot); + break; + } + } + break; + + case 0x80: /* GRP1 */ + case 0x81: + case 0x83: + { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub_code(s->pc++); + parse_modrm(s, modrm); + + switch(b) { + default: + case 0x80: + case 0x81: + insn_get(s, ot); + break; + case 0x83: + insn_get(s, OT_BYTE); + break; + } + } + break; + + /**************************/ + /* inc, dec, and other misc arith */ + case 0x40 ... 0x47: /* inc Gv */ + break; + case 0x48 ... 0x4f: /* dec Gv */ + break; + case 0xf6: /* GRP3 */ + case 0xf7: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub_code(s->pc++); + op = (modrm >> 3) & 7; + parse_modrm(s, modrm); + + switch(op) { + case 0: /* test */ + insn_get(s, ot); + break; + case 2: /* not */ + break; + case 3: /* neg */ + break; + case 4: /* mul */ + break; + case 5: /* imul */ + break; + case 6: /* div */ + break; + case 7: /* idiv */ + break; + default: + goto illegal_op; + } + break; + + case 0xfe: /* GRP4 */ + case 0xff: /* GRP5 */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + if (op >= 2 && b == 0xfe) { + goto illegal_op; + } + pc_tmp = s->pc; + parse_modrm(s, modrm); + + switch(op) { + case 0: /* inc Ev */ + break; + case 1: /* dec Ev */ + break; + case 2: /* call Ev */ + /* XXX: optimize and handle MEM exceptions specifically + fs movl %eax, regs[0] + movl Ev, %eax + pushl next_eip + fs movl %eax, eip + */ + goto unsupported_op; + case 3: /* lcall Ev */ + goto unsupported_op; + case 4: /* jmp Ev */ + /* XXX: optimize and handle MEM exceptions specifically + fs movl %eax, regs[0] + movl Ev, %eax + fs movl %eax, eip + */ + goto unsupported_op; + case 5: /* ljmp Ev */ + goto unsupported_op; + case 6: /* push Ev */ + break; + default: + goto illegal_op; + } + break; + case 0xa8: /* test eAX, Iv */ + case 0xa9: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + insn_get(s, ot); + break; + + case 0x98: /* CWDE/CBW */ + break; + case 0x99: /* CDQ/CWD */ + break; + case 0x1af: /* imul Gv, Ev */ + case 0x69: /* imul Gv, Ev, I */ + case 0x6b: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub_code(s->pc++); + parse_modrm(s, modrm); + if (b == 0x69) { + insn_get(s, ot); + } else if (b == 0x6b) { + insn_get(s, OT_BYTE); + } else { + } + break; + + case 0x84: /* test Ev, Gv */ + case 0x85: + + case 0x1c0: + case 0x1c1: /* xadd Ev, Gv */ + + case 0x1b0: + case 0x1b1: /* cmpxchg Ev, Gv */ + + case 0x8f: /* pop Ev */ + + case 0x88: + case 0x89: /* mov Gv, Ev */ + + case 0x8a: + case 0x8b: /* mov Ev, Gv */ + + case 0x1b6: /* movzbS Gv, Eb */ + case 0x1b7: /* movzwS Gv, Eb */ + case 0x1be: /* movsbS Gv, Eb */ + case 0x1bf: /* movswS Gv, Eb */ + + case 0x86: + case 0x87: /* xchg Ev, Gv */ + + case 0xd0: + case 0xd1: /* shift Ev,1 */ + + case 0xd2: + case 0xd3: /* shift Ev,cl */ + + case 0x1a5: /* shld cl */ + case 0x1ad: /* shrd cl */ + + case 0x190 ... 0x19f: /* setcc Gv */ + + /* XXX: emulate cmov if not available ? */ + case 0x140 ... 0x14f: /* cmov Gv, Ev */ + + case 0x1a3: /* bt Gv, Ev */ + case 0x1ab: /* bts */ + case 0x1b3: /* btr */ + case 0x1bb: /* btc */ + + case 0x1bc: /* bsf */ + case 0x1bd: /* bsr */ + + modrm = ldub_code(s->pc++); + parse_modrm(s, modrm); + break; + + case 0x1c7: /* cmpxchg8b */ + modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + parse_modrm(s, modrm); + break; + + /**************************/ + /* push/pop */ + case 0x50 ... 0x57: /* push */ + case 0x58 ... 0x5f: /* pop */ + case 0x60: /* pusha */ + case 0x61: /* popa */ + break; + + case 0x68: /* push Iv */ + case 0x6a: + ot = dflag ? OT_LONG : OT_WORD; + if (b == 0x68) + insn_get(s, ot); + else + insn_get(s, OT_BYTE); + break; + case 0xc8: /* enter */ + lduw_code(s->pc); + s->pc += 2; + ldub_code(s->pc++); + break; + case 0xc9: /* leave */ + break; + + case 0x06: /* push es */ + case 0x0e: /* push cs */ + case 0x16: /* push ss */ + case 0x1e: /* push ds */ + /* XXX: optimize: + push segs[n].selector + */ + goto unsupported_op; + case 0x1a0: /* push fs */ + case 0x1a8: /* push gs */ + goto unsupported_op; + case 0x07: /* pop es */ + case 0x17: /* pop ss */ + case 0x1f: /* pop ds */ + goto unsupported_op; + case 0x1a1: /* pop fs */ + case 0x1a9: /* pop gs */ + goto unsupported_op; + case 0x8e: /* mov seg, Gv */ + /* XXX: optimize: + fs movl r, regs[] + movl segs[].selector, r + mov r, Gv + fs movl regs[], r + */ + goto unsupported_op; + case 0x8c: /* mov Gv, seg */ + goto unsupported_op; + case 0xc4: /* les Gv */ + op = R_ES; + goto do_lxx; + case 0xc5: /* lds Gv */ + op = R_DS; + goto do_lxx; + case 0x1b2: /* lss Gv */ + op = R_SS; + goto do_lxx; + case 0x1b4: /* lfs Gv */ + op = R_FS; + goto do_lxx; + case 0x1b5: /* lgs Gv */ + op = R_GS; + do_lxx: + goto unsupported_op; +#if 0 + /************************/ + /* floats */ + case 0xd8 ... 0xdf: + modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = ((b & 7) << 3) | ((modrm >> 3) & 7); + if (mod != 3) { + /* memory op */ + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + switch(op) { + case 0x00 ... 0x07: /* fxxxs */ + case 0x10 ... 0x17: /* fixxxl */ + case 0x20 ... 0x27: /* fxxxl */ + case 0x30 ... 0x37: /* fixxx */ + { + int op1; + op1 = op & 7; + + switch(op >> 4) { + case 0: + gen_op_flds_FT0_A0(); + break; + case 1: + gen_op_fildl_FT0_A0(); + break; + case 2: + gen_op_fldl_FT0_A0(); + break; + case 3: + default: + gen_op_fild_FT0_A0(); + break; + } + + gen_op_fp_arith_ST0_FT0[op1](); + if (op1 == 3) { + /* fcomp needs pop */ + gen_op_fpop(); + } + } + break; + case 0x08: /* flds */ + case 0x0a: /* fsts */ + case 0x0b: /* fstps */ + case 0x18: /* fildl */ + case 0x1a: /* fistl */ + case 0x1b: /* fistpl */ + case 0x28: /* fldl */ + case 0x2a: /* fstl */ + case 0x2b: /* fstpl */ + case 0x38: /* filds */ + case 0x3a: /* fists */ + case 0x3b: /* fistps */ + + switch(op & 7) { + case 0: + switch(op >> 4) { + case 0: + gen_op_flds_ST0_A0(); + break; + case 1: + gen_op_fildl_ST0_A0(); + break; + case 2: + gen_op_fldl_ST0_A0(); + break; + case 3: + default: + gen_op_fild_ST0_A0(); + break; + } + break; + default: + switch(op >> 4) { + case 0: + gen_op_fsts_ST0_A0(); + break; + case 1: + gen_op_fistl_ST0_A0(); + break; + case 2: + gen_op_fstl_ST0_A0(); + break; + case 3: + default: + gen_op_fist_ST0_A0(); + break; + } + if ((op & 7) == 3) + gen_op_fpop(); + break; + } + break; + case 0x0c: /* fldenv mem */ + gen_op_fldenv_A0(s->dflag); + break; + case 0x0d: /* fldcw mem */ + gen_op_fldcw_A0(); + break; + case 0x0e: /* fnstenv mem */ + gen_op_fnstenv_A0(s->dflag); + break; + case 0x0f: /* fnstcw mem */ + gen_op_fnstcw_A0(); + break; + case 0x1d: /* fldt mem */ + gen_op_fldt_ST0_A0(); + break; + case 0x1f: /* fstpt mem */ + gen_op_fstt_ST0_A0(); + gen_op_fpop(); + break; + case 0x2c: /* frstor mem */ + gen_op_frstor_A0(s->dflag); + break; + case 0x2e: /* fnsave mem */ + gen_op_fnsave_A0(s->dflag); + break; + case 0x2f: /* fnstsw mem */ + gen_op_fnstsw_A0(); + break; + case 0x3c: /* fbld */ + gen_op_fbld_ST0_A0(); + break; + case 0x3e: /* fbstp */ + gen_op_fbst_ST0_A0(); + gen_op_fpop(); + break; + case 0x3d: /* fildll */ + gen_op_fildll_ST0_A0(); + break; + case 0x3f: /* fistpll */ + gen_op_fistll_ST0_A0(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + } else { + /* register float ops */ + opreg = rm; + + switch(op) { + case 0x08: /* fld sti */ + gen_op_fpush(); + gen_op_fmov_ST0_STN((opreg + 1) & 7); + break; + case 0x09: /* fxchg sti */ + gen_op_fxchg_ST0_STN(opreg); + break; + case 0x0a: /* grp d9/2 */ + switch(rm) { + case 0: /* fnop */ + break; + default: + goto illegal_op; + } + break; + case 0x0c: /* grp d9/4 */ + switch(rm) { + case 0: /* fchs */ + gen_op_fchs_ST0(); + break; + case 1: /* fabs */ + gen_op_fabs_ST0(); + break; + case 4: /* ftst */ + gen_op_fldz_FT0(); + gen_op_fcom_ST0_FT0(); + break; + case 5: /* fxam */ + gen_op_fxam_ST0(); + break; + default: + goto illegal_op; + } + break; + case 0x0d: /* grp d9/5 */ + { + switch(rm) { + case 0: + gen_op_fpush(); + gen_op_fld1_ST0(); + break; + case 1: + gen_op_fpush(); + gen_op_fldl2t_ST0(); + break; + case 2: + gen_op_fpush(); + gen_op_fldl2e_ST0(); + break; + case 3: + gen_op_fpush(); + gen_op_fldpi_ST0(); + break; + case 4: + gen_op_fpush(); + gen_op_fldlg2_ST0(); + break; + case 5: + gen_op_fpush(); + gen_op_fldln2_ST0(); + break; + case 6: + gen_op_fpush(); + gen_op_fldz_ST0(); + break; + default: + goto illegal_op; + } + } + break; + case 0x0e: /* grp d9/6 */ + switch(rm) { + case 0: /* f2xm1 */ + gen_op_f2xm1(); + break; + case 1: /* fyl2x */ + gen_op_fyl2x(); + break; + case 2: /* fptan */ + gen_op_fptan(); + break; + case 3: /* fpatan */ + gen_op_fpatan(); + break; + case 4: /* fxtract */ + gen_op_fxtract(); + break; + case 5: /* fprem1 */ + gen_op_fprem1(); + break; + case 6: /* fdecstp */ + gen_op_fdecstp(); + break; + default: + case 7: /* fincstp */ + gen_op_fincstp(); + break; + } + break; + case 0x0f: /* grp d9/7 */ + switch(rm) { + case 0: /* fprem */ + gen_op_fprem(); + break; + case 1: /* fyl2xp1 */ + gen_op_fyl2xp1(); + break; + case 2: /* fsqrt */ + gen_op_fsqrt(); + break; + case 3: /* fsincos */ + gen_op_fsincos(); + break; + case 5: /* fscale */ + gen_op_fscale(); + break; + case 4: /* frndint */ + gen_op_frndint(); + break; + case 6: /* fsin */ + gen_op_fsin(); + break; + default: + case 7: /* fcos */ + gen_op_fcos(); + break; + } + break; + case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ + case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ + case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ + { + int op1; + + op1 = op & 7; + if (op >= 0x20) { + gen_op_fp_arith_STN_ST0[op1](opreg); + if (op >= 0x30) + gen_op_fpop(); + } else { + gen_op_fmov_FT0_STN(opreg); + gen_op_fp_arith_ST0_FT0[op1](); + } + } + break; + case 0x02: /* fcom */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fcom_ST0_FT0(); + break; + case 0x03: /* fcomp */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); + break; + case 0x15: /* da/5 */ + switch(rm) { + case 1: /* fucompp */ + gen_op_fmov_FT0_STN(1); + gen_op_fucom_ST0_FT0(); + gen_op_fpop(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + break; + case 0x1c: + switch(rm) { + case 0: /* feni (287 only, just do nop here) */ + break; + case 1: /* fdisi (287 only, just do nop here) */ + break; + case 2: /* fclex */ + gen_op_fclex(); + break; + case 3: /* fninit */ + gen_op_fninit(); + break; + case 4: /* fsetpm (287 only, just do nop here) */ + break; + default: + goto illegal_op; + } + break; + case 0x1d: /* fucomi */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fucomi_ST0_FT0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x1e: /* fcomi */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcomi_ST0_FT0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x2a: /* fst sti */ + gen_op_fmov_STN_ST0(opreg); + break; + case 0x2b: /* fstp sti */ + gen_op_fmov_STN_ST0(opreg); + gen_op_fpop(); + break; + case 0x2c: /* fucom st(i) */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fucom_ST0_FT0(); + break; + case 0x2d: /* fucomp st(i) */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fucom_ST0_FT0(); + gen_op_fpop(); + break; + case 0x33: /* de/3 */ + switch(rm) { + case 1: /* fcompp */ + gen_op_fmov_FT0_STN(1); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + break; + case 0x3c: /* df/4 */ + switch(rm) { + case 0: + gen_op_fnstsw_EAX(); + break; + default: + goto illegal_op; + } + break; + case 0x3d: /* fucomip */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fucomi_ST0_FT0(); + gen_op_fpop(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x3e: /* fcomip */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcomi_ST0_FT0(); + gen_op_fpop(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x10 ... 0x13: /* fcmovxx */ + case 0x18 ... 0x1b: + { + int op1; + const static uint8_t fcmov_cc[8] = { + (JCC_B << 1), + (JCC_Z << 1), + (JCC_BE << 1), + (JCC_P << 1), + }; + op1 = fcmov_cc[op & 3] | ((op >> 3) & 1); + gen_setcc(s, op1); + gen_op_fcmov_ST0_STN_T0(opreg); + } + break; + default: + goto illegal_op; + } + } + break; +#endif + /**************************/ + /* mov */ + case 0xc6: + case 0xc7: /* mov Ev, Iv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub_code(s->pc++); + parse_modrm(s, modrm); + insn_get(s, ot); + break; + + case 0x8d: /* lea */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + parse_modrm(s, modrm); + break; + + case 0xa0: /* mov EAX, Ov */ + case 0xa1: + case 0xa2: /* mov Ov, EAX */ + case 0xa3: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (s->aflag) + insn_get(s, OT_LONG); + else + insn_get(s, OT_WORD); + break; + case 0xd7: /* xlat */ + break; + case 0xb0 ... 0xb7: /* mov R, Ib */ + insn_get(s, OT_BYTE); + break; + case 0xb8 ... 0xbf: /* mov R, Iv */ + ot = dflag ? OT_LONG : OT_WORD; + insn_get(s, ot); + break; + + case 0x91 ... 0x97: /* xchg R, EAX */ + break; + + /************************/ + /* shifts */ + case 0xc0: + case 0xc1: /* shift Ev,imm */ + + case 0x1a4: /* shld imm */ + case 0x1ac: /* shrd imm */ + modrm = ldub_code(s->pc++); + parse_modrm(s, modrm); + ldub_code(s->pc++); + break; + + /************************/ + /* string ops */ + + case 0xa4: /* movsS */ + case 0xa5: + break; + + case 0xaa: /* stosS */ + case 0xab: + break; + + case 0xac: /* lodsS */ + case 0xad: + break; + + case 0xae: /* scasS */ + case 0xaf: + break; + + case 0xa6: /* cmpsS */ + case 0xa7: + break; + + case 0x6c: /* insS */ + case 0x6d: + goto unsupported_op; + + case 0x6e: /* outsS */ + case 0x6f: + goto unsupported_op; + + /************************/ + /* port I/O */ + case 0xe4: + case 0xe5: + goto unsupported_op; + + case 0xe6: + case 0xe7: + goto unsupported_op; + + case 0xec: + case 0xed: + goto unsupported_op; + + case 0xee: + case 0xef: + goto unsupported_op; + + /************************/ + /* control */ +#if 0 + case 0xc2: /* ret im */ + val = ldsw_code(s->pc); + s->pc += 2; + gen_pop_T0(s); + gen_stack_update(s, val + (2 << s->dflag)); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_eob(s); + break; +#endif + + case 0xc3: /* ret */ + gb(s, CPU_SEG); + if (!s->dflag) + gb(s, 0x66); /* d16 */ + gb(s, 0x8f); /* pop addr */ + gb(s, 0x05); + gl(s, CPU_FIELD_OFFSET(eip)); + if (!s->dflag) { + /* reset high bits of EIP */ + gen_movw_addr_im(s, CPU_FIELD_OFFSET(eip) + 2, 0); + } + gen_eob(s); + goto no_copy; + case 0xca: /* lret im */ + case 0xcb: /* lret */ + case 0xcf: /* iret */ + case 0x9a: /* lcall im */ + case 0xea: /* ljmp im */ + goto unsupported_op; + + case 0xe8: /* call im */ + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag) { + gb(s, 0x68); /* pushl imm */ + gl(s, next_eip); + } else { + gb(s, 0x66); /* pushw imm */ + gb(s, 0x68); + gw(s, next_eip); + val &= 0xffff; + } + gen_jmp(s, val); + goto no_copy; + case 0xe9: /* jmp */ + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + val += s->pc - s->cs_base; + if (s->dflag == 0) + val = val & 0xffff; + gen_jmp(s, val); + goto no_copy; + case 0xeb: /* jmp Jb */ + val = (int8_t)insn_get(s, OT_BYTE); + val += s->pc - s->cs_base; + if (s->dflag == 0) + val = val & 0xffff; + gen_jmp(s, val); + goto no_copy; + case 0x70 ... 0x7f: /* jcc Jb */ + val = (int8_t)insn_get(s, OT_BYTE); + goto do_jcc; + case 0x180 ... 0x18f: /* jcc Jv */ + if (dflag) { + val = insn_get(s, OT_LONG); + } else { + val = (int16_t)insn_get(s, OT_WORD); + } + do_jcc: + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_jcc(s, b & 0xf, val, next_eip); + goto no_copy; + + /************************/ + /* flags */ + case 0x9c: /* pushf */ + /* XXX: put specific code ? */ + goto unsupported_op; + case 0x9d: /* popf */ + goto unsupported_op; + + case 0x9e: /* sahf */ + case 0x9f: /* lahf */ + case 0xf5: /* cmc */ + case 0xf8: /* clc */ + case 0xf9: /* stc */ + case 0xfc: /* cld */ + case 0xfd: /* std */ + break; + + /************************/ + /* bit operations */ + case 0x1ba: /* bt/bts/btr/btc Gv, im */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub_code(s->pc++); + op = (modrm >> 3) & 7; + parse_modrm(s, modrm); + /* load shift */ + ldub_code(s->pc++); + if (op < 4) + goto illegal_op; + break; + /************************/ + /* bcd */ + case 0x27: /* daa */ + break; + case 0x2f: /* das */ + break; + case 0x37: /* aaa */ + break; + case 0x3f: /* aas */ + break; + case 0xd4: /* aam */ + ldub_code(s->pc++); + break; + case 0xd5: /* aad */ + ldub_code(s->pc++); + break; + /************************/ + /* misc */ + case 0x90: /* nop */ + break; + case 0x9b: /* fwait */ + break; + case 0xcc: /* int3 */ + goto unsupported_op; + case 0xcd: /* int N */ + goto unsupported_op; + case 0xce: /* into */ + goto unsupported_op; + case 0xf1: /* icebp (undocumented, exits to external debugger) */ + goto unsupported_op; + case 0xfa: /* cli */ + goto unsupported_op; + case 0xfb: /* sti */ + goto unsupported_op; + case 0x62: /* bound */ + modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + parse_modrm(s, modrm); + break; + case 0x1c8 ... 0x1cf: /* bswap reg */ + break; + case 0xd6: /* salc */ + break; + case 0xe0: /* loopnz */ + case 0xe1: /* loopz */ + case 0xe2: /* loop */ + case 0xe3: /* jecxz */ + goto unsupported_op; + + case 0x130: /* wrmsr */ + case 0x132: /* rdmsr */ + goto unsupported_op; + case 0x131: /* rdtsc */ + goto unsupported_op; + case 0x1a2: /* cpuid */ + goto unsupported_op; + case 0xf4: /* hlt */ + goto unsupported_op; + case 0x100: + goto unsupported_op; + case 0x101: + goto unsupported_op; + case 0x108: /* invd */ + case 0x109: /* wbinvd */ + goto unsupported_op; + case 0x63: /* arpl */ + goto unsupported_op; + case 0x102: /* lar */ + case 0x103: /* lsl */ + goto unsupported_op; + case 0x118: + goto unsupported_op; + case 0x120: /* mov reg, crN */ + case 0x122: /* mov crN, reg */ + goto unsupported_op; + case 0x121: /* mov reg, drN */ + case 0x123: /* mov drN, reg */ + goto unsupported_op; + case 0x106: /* clts */ + goto unsupported_op; + default: + goto illegal_op; + } + + /* just copy the code */ + + /* no override yet */ + if (!s->dflag) + gb(s, 0x66); + if (!s->aflag) + gb(s, 0x67); + if (prefixes & PREFIX_REPZ) + gb(s, 0xf3); + else if (prefixes & PREFIX_REPNZ) + gb(s, 0xf2); + { + int len, i; + len = s->pc - pc_start_insn; + for(i = 0; i < len; i++) { + *s->gen_code_ptr++ = ldub_code(pc_start_insn + i); + } + } + no_copy: + return 0; + illegal_op: + unsupported_op: + /* fall back to slower code gen necessary */ + s->pc = pc_start; + return -1; +} + +#define GEN_CODE_MAX_SIZE 8192 +#define GEN_CODE_MAX_INSN_SIZE 512 + +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + uint8_t *gen_code_ptr, + int *gen_code_size_ptr, + int search_pc, + uint8_t *tc_ptr) +{ + DisasContext dc1, *dc = &dc1; + uint8_t *pc_insn, *pc_start, *gen_code_end; + int flags, ret; + uint8_t *cs_base; + + if (env->nb_breakpoints > 0 || + env->singlestep_enabled) + return -1; + flags = tb->flags; + if (flags & (HF_TF_MASK | HF_ADDSEG_MASK | + HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK)) + return -1; + if (!(flags & HF_SS32_MASK)) + return -1; + gen_code_end = gen_code_ptr + + GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE; + dc->gen_code_ptr = gen_code_ptr; + dc->gen_code_start = gen_code_ptr; + + /* generate intermediate code */ + pc_start = (uint8_t *)tb->pc; + cs_base = (uint8_t *)tb->cs_base; + dc->pc = pc_start; + dc->cs_base = cs_base; + dc->pe = (flags >> HF_PE_SHIFT) & 1; + dc->code32 = (flags >> HF_CS32_SHIFT) & 1; + dc->f_st = 0; + dc->vm86 = (flags >> VM_SHIFT) & 1; + dc->cpl = (flags >> HF_CPL_SHIFT) & 3; + dc->iopl = (flags >> IOPL_SHIFT) & 3; + dc->tb = tb; + + dc->is_jmp = 0; + + for(;;) { + pc_insn = dc->pc; + ret = disas_insn(dc); + if (ret < 0) { + /* unsupported insn */ + if (dc->pc == pc_start) { + /* if first instruction, signal that no copying was done */ + return -1; + } else { + gen_jmp(dc, dc->pc - dc->cs_base); + dc->is_jmp = 1; + } + } + if (search_pc) { + /* search pc mode */ + if (tc_ptr < dc->gen_code_ptr) { + env->eip = pc_insn - cs_base; + return 0; + } + } + /* stop translation if indicated */ + if (dc->is_jmp) + break; + /* if too long translation, stop generation */ + if (dc->gen_code_ptr >= gen_code_end || + (dc->pc - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + gen_jmp(dc, dc->pc - dc->cs_base); + break; + } + } + +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "----------------\n"); + fprintf(logfile, "IN: COPY: %s\n", lookup_symbol(pc_start)); + disas(logfile, pc_start, dc->pc - pc_start, 0, !dc->code32); + fprintf(logfile, "\n"); + } +#endif + + if (!search_pc) { + *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start; + tb->size = dc->pc - pc_start; + tb->cflags = CF_CODE_COPY; + return 0; + } else { + return -1; + } +} + +/* generate code by just copying data. Return -1 if cannot generate + any code. Return 0 if code was generated */ +int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb, + int max_code_size, int *gen_code_size_ptr) +{ + /* generate machine code */ + tb->tb_next_offset[0] = 0xffff; + tb->tb_next_offset[1] = 0xffff; +#ifdef USE_DIRECT_JUMP + /* the following two entries are optional (only used for string ops) */ + tb->tb_jmp_offset[2] = 0xffff; + tb->tb_jmp_offset[3] = 0xffff; +#endif + return gen_intermediate_code_internal(env, tb, + tb->tc_ptr, gen_code_size_ptr, + 0, NULL); +} + +static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE]; + +int cpu_restore_state_copy(TranslationBlock *tb, + CPUState *env, unsigned long searched_pc, + void *puc) +{ + struct ucontext *uc = puc; + int ret, eflags; + + /* find opc index corresponding to search_pc */ + if (searched_pc < (unsigned long)tb->tc_ptr) + return -1; + searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf; + ret = gen_intermediate_code_internal(env, tb, + dummy_gen_code_buf, NULL, + 1, (uint8_t *)searched_pc); + if (ret < 0) + return ret; + /* restore all the CPU state from the CPU context from the + signal */ + + env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX]; + env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX]; + env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX]; + env->regs[R_EBX] = uc->uc_mcontext.gregs[REG_EBX]; + env->regs[R_ESP] = uc->uc_mcontext.gregs[REG_ESP]; + env->regs[R_EBP] = uc->uc_mcontext.gregs[REG_EBP]; + env->regs[R_ESI] = uc->uc_mcontext.gregs[REG_ESI]; + env->regs[R_EDI] = uc->uc_mcontext.gregs[REG_EDI]; + eflags = uc->uc_mcontext.gregs[REG_EFL]; + env->df = 1 - (2 * ((eflags >> 10) & 1)); + env->cc_src = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + env->cc_op = CC_OP_EFLAGS; + return 0; +} diff --git a/translate-all.c b/translate-all.c index 108a21f26..dd314023b 100644 --- a/translate-all.c +++ b/translate-all.c @@ -48,6 +48,8 @@ uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; #endif +int code_copy_enabled = 1; + #ifdef DEBUG_DISAS static const char *op_str[] = { #define DEF(s, n, copy_size) #s, @@ -98,30 +100,38 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, uint8_t *gen_code_buf; int gen_code_size; - if (gen_intermediate_code(env, tb) < 0) - return -1; +#ifdef USE_CODE_COPY + if (code_copy_enabled && + cpu_gen_code_copy(env, tb, max_code_size, &gen_code_size) == 0) { + /* nothing more to do */ + } else +#endif + { + if (gen_intermediate_code(env, tb) < 0) + return -1; - /* generate machine code */ - tb->tb_next_offset[0] = 0xffff; - tb->tb_next_offset[1] = 0xffff; - gen_code_buf = tb->tc_ptr; + /* generate machine code */ + tb->tb_next_offset[0] = 0xffff; + tb->tb_next_offset[1] = 0xffff; + gen_code_buf = tb->tc_ptr; #ifdef USE_DIRECT_JUMP - /* the following two entries are optional (only used for string ops) */ - tb->tb_jmp_offset[2] = 0xffff; - tb->tb_jmp_offset[3] = 0xffff; + /* the following two entries are optional (only used for string ops) */ + tb->tb_jmp_offset[2] = 0xffff; + tb->tb_jmp_offset[3] = 0xffff; #endif - gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, + gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, #ifdef USE_DIRECT_JUMP - tb->tb_jmp_offset, + tb->tb_jmp_offset, #else - NULL, + NULL, #endif - gen_opc_buf, gen_opparam_buf); + gen_opc_buf, gen_opparam_buf); + } *gen_code_size_ptr = gen_code_size; #ifdef DEBUG_DISAS - if (loglevel && 0) { + if (loglevel) { fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); - disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0); + disas(logfile, tb->tc_ptr, *gen_code_size_ptr, 1, 0); fprintf(logfile, "\n"); fflush(logfile); } @@ -138,12 +148,18 @@ static const unsigned short opc_copy_size[] = { /* The cpu state corresponding to 'searched_pc' is restored. */ int cpu_restore_state(TranslationBlock *tb, - CPUState *env, unsigned long searched_pc) + CPUState *env, unsigned long searched_pc, + void *puc) { int j, c; unsigned long tc_ptr; uint16_t *opc_ptr; +#ifdef USE_CODE_COPY + if (tb->cflags & CF_CODE_COPY) { + return cpu_restore_state_copy(tb, env, searched_pc, puc); + } +#endif if (gen_intermediate_code_pc(env, tb) < 0) return -1; @@ -190,6 +206,7 @@ int cpu_restore_state(TranslationBlock *tb, #elif defined(TARGET_ARM) env->regs[15] = gen_opc_pc[j]; #elif defined(TARGET_SPARC) + /* XXX: restore npc too */ env->pc = gen_opc_pc[j]; #elif defined(TARGET_PPC) { -- cgit v1.2.3 From ea88812f4f4fa19e08a665fb75a38ffa6d87715f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 22:12:40 +0000 Subject: added OS dependent functions (temporary as most functions are generic in fact) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@624 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 460 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ osdep.h | 25 ++++ 2 files changed, 485 insertions(+) create mode 100644 osdep.c create mode 100644 osdep.h diff --git a/osdep.c b/osdep.c new file mode 100644 index 000000000..d4d336462 --- /dev/null +++ b/osdep.c @@ -0,0 +1,460 @@ +/* + * QEMU low level functions + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" + +#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) + +/* When not using soft mmu, libc independant functions are needed for + the CPU core because it needs to use alternates stacks and + libc/thread incompatibles settings */ + +#include + +#define QEMU_SYSCALL0(name) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name)); \ +return __res; \ +} + +#define QEMU_SYSCALL1(name,arg1) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(arg1))); \ +return __res; \ +} + +#define QEMU_SYSCALL2(name,arg1,arg2) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \ +return __res; \ +} + +#define QEMU_SYSCALL3(name,arg1,arg2,arg3) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ + "d" ((long)(arg3))); \ +return __res; \ +} + +#define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ + "d" ((long)(arg3)),"S" ((long)(arg4))); \ +return __res; \ +} + +#define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ + "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \ +return __res; \ +} + +#define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \ +{ \ +long __res; \ +__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \ + : "=a" (__res) \ + : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ + "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \ + "0" ((long)(arg6))); \ +return __res; \ +} + +int qemu_write(int fd, const void *buf, size_t n) +{ + QEMU_SYSCALL3(write, fd, buf, n); +} + + + +/****************************************************************/ +/* shmat replacement */ + +int qemu_ipc(int call, unsigned long first, + unsigned long second, unsigned long third, + void *ptr, unsigned long fifth) +{ + QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth); +} + +#define SHMAT 21 + +/* we must define shmat so that a specific address will be used when + mapping the X11 ximage */ +void *shmat(int shmid, const void *shmaddr, int shmflg) +{ + void *ptr; + int ret; + /* we give an address in the right memory area */ + if (!shmaddr) + shmaddr = get_mmap_addr(8192 * 1024); + ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0); + if (ret < 0) + return NULL; + return ptr; +} + +/****************************************************************/ +/* memory allocation */ + +//#define DEBUG_MALLOC + +#define MALLOC_BASE 0xab000000 +#define PHYS_RAM_BASE 0xac000000 + +#define MALLOC_ALIGN 16 +#define BLOCK_HEADER_SIZE 16 + +typedef struct MemoryBlock { + struct MemoryBlock *next; + unsigned long size; /* size of block, including header */ +} MemoryBlock; + +static MemoryBlock *first_free_block; +static unsigned long malloc_addr = MALLOC_BASE; + +static void *malloc_get_space(size_t size) +{ + void *ptr; + size = TARGET_PAGE_ALIGN(size); + ptr = mmap((void *)malloc_addr, size, + PROT_WRITE | PROT_READ, + MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0); + if (ptr == MAP_FAILED) + return NULL; + malloc_addr += size; + return ptr; +} + +void *qemu_malloc(size_t size) +{ + MemoryBlock *mb, *mb1, **pmb; + void *ptr; + size_t size1, area_size; + + if (size == 0) + return NULL; + + size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1); + pmb = &first_free_block; + for(;;) { + mb = *pmb; + if (mb == NULL) + break; + if (size <= mb->size) + goto found; + pmb = &mb->next; + } + /* no big enough blocks found: get new space */ + area_size = TARGET_PAGE_ALIGN(size); + mb = malloc_get_space(area_size); + if (!mb) + return NULL; + size1 = area_size - size; + if (size1 > 0) { + /* create a new free block */ + mb1 = (MemoryBlock *)((uint8_t *)mb + size); + mb1->next = NULL; + mb1->size = size1; + *pmb = mb1; + } + goto the_end; + found: + /* a free block was found: use it */ + size1 = mb->size - size; + if (size1 > 0) { + /* create a new free block */ + mb1 = (MemoryBlock *)((uint8_t *)mb + size); + mb1->next = mb->next; + mb1->size = size1; + *pmb = mb1; + } else { + /* suppress the first block */ + *pmb = mb->next; + } + the_end: + mb->size = size; + mb->next = NULL; + ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE); +#ifdef DEBUG_MALLOC + qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr); +#endif + return ptr; +} + +void qemu_free(void *ptr) +{ + MemoryBlock *mb; + + mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE); + mb->next = first_free_block; + first_free_block = mb; +} + +/****************************************************************/ +/* virtual memory allocation */ + +unsigned long mmap_addr = PHYS_RAM_BASE; + +void *get_mmap_addr(unsigned long size) +{ + unsigned long addr; + addr = mmap_addr; + mmap_addr += ((size + 4095) & ~4095) + 4096; + return (void *)addr; +} + +#else + +int qemu_write(int fd, const void *buf, size_t n) +{ + int ret; + ret = write(fd, buf, n); + if (ret < 0) + return -errno; + else + return ret; +} + +void *get_mmap_addr(unsigned long size) +{ + return NULL; +} + +void qemu_free(void *ptr) +{ + free(ptr); +} + +void *qemu_malloc(size_t size) +{ + return malloc(size); +} + +#endif + +/****************************************************************/ +/* printf support */ + +static inline int qemu_isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) + +/* from BSD ppp sources */ +int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args) +{ + int c, i, n; + int width, prec, fillch; + int base, len, neg; + unsigned long val = 0; + const char *f; + char *str, *buf0; + char num[32]; + static const char hexchars[] = "0123456789abcdef"; + + buf0 = buf; + --buflen; + while (buflen > 0) { + for (f = fmt; *f != '%' && *f != 0; ++f) + ; + if (f > fmt) { + len = f - fmt; + if (len > buflen) + len = buflen; + memcpy(buf, fmt, len); + buf += len; + buflen -= len; + fmt = f; + } + if (*fmt == 0) + break; + c = *++fmt; + width = prec = 0; + fillch = ' '; + if (c == '0') { + fillch = '0'; + c = *++fmt; + } + if (c == '*') { + width = va_arg(args, int); + c = *++fmt; + } else { + while (qemu_isdigit(c)) { + width = width * 10 + c - '0'; + c = *++fmt; + } + } + if (c == '.') { + c = *++fmt; + if (c == '*') { + prec = va_arg(args, int); + c = *++fmt; + } else { + while (qemu_isdigit(c)) { + prec = prec * 10 + c - '0'; + c = *++fmt; + } + } + } + /* modifiers */ + switch(c) { + case 'l': + c = *++fmt; + break; + default: + break; + } + str = 0; + base = 0; + neg = 0; + ++fmt; + switch (c) { + case 'd': + i = va_arg(args, int); + if (i < 0) { + neg = 1; + val = -i; + } else + val = i; + base = 10; + break; + case 'o': + val = va_arg(args, unsigned int); + base = 8; + break; + case 'x': + case 'X': + val = va_arg(args, unsigned int); + base = 16; + break; + case 'p': + val = (unsigned long) va_arg(args, void *); + base = 16; + neg = 2; + break; + case 's': + str = va_arg(args, char *); + break; + case 'c': + num[0] = va_arg(args, int); + num[1] = 0; + str = num; + break; + default: + *buf++ = '%'; + if (c != '%') + --fmt; /* so %z outputs %z etc. */ + --buflen; + continue; + } + if (base != 0) { + str = num + sizeof(num); + *--str = 0; + while (str > num + neg) { + *--str = hexchars[val % base]; + val = val / base; + if (--prec <= 0 && val == 0) + break; + } + switch (neg) { + case 1: + *--str = '-'; + break; + case 2: + *--str = 'x'; + *--str = '0'; + break; + } + len = num + sizeof(num) - 1 - str; + } else { + len = strlen(str); + if (prec > 0 && len > prec) + len = prec; + } + if (width > 0) { + if (width > buflen) + width = buflen; + if ((n = width - len) > 0) { + buflen -= n; + for (; n > 0; --n) + *buf++ = fillch; + } + } + if (len > buflen) + len = buflen; + memcpy(buf, str, len); + buf += len; + buflen -= len; + } + *buf = 0; + return buf - buf0; +} + +void qemu_vprintf(const char *fmt, va_list ap) +{ + char buf[1024]; + int len; + + len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap); + qemu_write(1, buf, len); +} + +void qemu_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + qemu_vprintf(fmt, ap); + va_end(ap); +} + diff --git a/osdep.h b/osdep.h new file mode 100644 index 000000000..16148da1b --- /dev/null +++ b/osdep.h @@ -0,0 +1,25 @@ +#ifndef QEMU_OSDEP_H +#define QEMU_OSDEP_H + +#include + +int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args); +void qemu_vprintf(const char *fmt, va_list ap); +void qemu_printf(const char *fmt, ...); + +void *qemu_malloc(size_t size); +void qemu_free(void *ptr); + +void *get_mmap_addr(unsigned long size); + +/* specific kludges for OS compatibility (should be moved elsewhere) */ +#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) + +/* disabled pthread version of longjmp which prevent us from using an + alternative signal stack */ +extern void __longjmp(jmp_buf env, int val); +#define longjmp __longjmp + +#endif + +#endif -- cgit v1.2.3 From 22a46c55e4765e3ca0d95cae8775118e697aba1b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 22:13:24 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@625 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index bfcf48881..f714131b2 100644 --- a/Changelog +++ b/Changelog @@ -5,7 +5,12 @@ version 0.5.3: - 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 (3x 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) + version 0.5.2: - improved soft MMU speed (assembly functions and specializing) -- cgit v1.2.3 From ed1c0bcb0cffd5a61ae6ffcc3bb2d4baa6021ad8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 16 Feb 2004 22:17:43 +0000 Subject: use osdep.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@626 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpu-defs.h b/cpu-defs.h index 013076b4b..59a0c0f32 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -22,6 +22,8 @@ #include "config.h" #include +#include +#include "osdep.h" #ifndef TARGET_LONG_BITS #error TARGET_LONG_BITS must be defined before including this header -- cgit v1.2.3 From 004bc62c288c707dcd31189149b01c8624c49ee3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Feb 2004 14:10:04 +0000 Subject: update nip when processing exceptions (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@627 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 98d788585..7916b83c5 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -220,8 +220,8 @@ PPC_OP(queue_exception) PPC_OP(process_exceptions) { + env->nip = PARAM(1); if (env->exceptions != 0) { - env->nip = PARAM(1); do_check_exception_state(); } } -- cgit v1.2.3 From 297d8e6227ff1186857b17b1890fc94c637733da Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Feb 2004 14:11:27 +0000 Subject: Fix check for lswi (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@628 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1b16fd541..f6df06b5b 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1229,10 +1229,10 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) if (nb == 0) nb = 32; nr = nb / 4; - if (((start + nr) > 32 && start <= ra && (start + nr - 32) >= ra) || - ((start + nr) <= 32 && start <= ra && (start + nr) >= ra)) { + if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) || + ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) { RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); - } + } if (ra == 0) { gen_op_set_T0(0); } else { -- cgit v1.2.3 From 28fbe299c3048caf845a26c4dc2027acabdaa689 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Feb 2004 14:13:13 +0000 Subject: lwarx fix (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@629 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_mem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 01df45d9c..52f55c91b 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -141,8 +141,8 @@ PPC_OP(glue(lwarx, MEMSUFFIX)) do_queue_exception(EXCP_ALIGN); do_process_exceptions(); } else { - glue(ldl, MEMSUFFIX)((void *)T0); - regs->reserve = T0 & ~0x03; + T1 = glue(ldl, MEMSUFFIX)((void *)T0); + regs->reserve = T0; } RETURN(); } -- cgit v1.2.3 From e98a6e40a9d56e16e52a4a839eaa698b658b94e0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Feb 2004 15:35:00 +0000 Subject: adding direct block chaining support - simplified branch code gen git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@630 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 199 ++++++++++++++------------------ target-ppc/translate.c | 304 +++++++++++++++++++------------------------------ 2 files changed, 203 insertions(+), 300 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 7916b83c5..94ead452f 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -473,121 +473,94 @@ PPC_OP(setcrfbit) } /* Branch */ -#if 0 #define EIP regs->nip -#define TB_DO_JUMP(name, tb, n, target) JUMP_TB(name, tb, n, target) -#else -#define TB_DO_JUMP(name, tb, n, target) regs->nip = target; -#endif -#define __PPC_OP_B(name, target) \ -PPC_OP(name) \ -{ \ - TB_DO_JUMP(glue(op_, name), T1, 0, (target)); \ - RETURN(); \ -} - -#define __PPC_OP_BL(name, target, link) \ -PPC_OP(name) \ -{ \ - regs->lr = (link); \ - TB_DO_JUMP(glue(op_, name), T1, 0, (target)); \ - RETURN(); \ -} - -#define PPC_OP_B(name, target, link) \ -__PPC_OP_B(name, target); \ -__PPC_OP_BL(glue(name, l), target, link) - -#define __PPC_OP_BC(name, cond, target) \ -PPC_OP(name) \ -{ \ - if (cond) { \ - TB_DO_JUMP(glue(op_, name), T1, 1, (target)); \ - } else { \ - TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \ - } \ - RETURN(); \ -} - -#define __PPC_OP_BCL(name, cond, target) \ -PPC_OP(name) \ -{ \ - regs->lr = PARAM(1); \ - if (cond) { \ - TB_DO_JUMP(glue(op_, name), T1, 1, (target)); \ - } else { \ - TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \ - } \ - RETURN(); \ -} - -#define __PPC_OP_BCLRL(name, cond, target) \ -PPC_OP(name) \ -{ \ - T2 = (target); \ - regs->lr = PARAM(1); \ - if (cond) { \ - TB_DO_JUMP(glue(op_, name), T1, 1, T2); \ - } else { \ - TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1)); \ - } \ - RETURN(); \ -} - -#define _PPC_OP_BC(name, namel, cond, target) \ -__PPC_OP_BC(name, cond, target); \ -__PPC_OP_BCL(namel, cond, target) - -/* Branch to target */ -#define PPC_OP_BC(name, cond) \ -_PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2)) - -PPC_OP_B(b, PARAM(1), PARAM(2)); -PPC_OP_BC(ctr, (regs->ctr != 0)); -PPC_OP_BC(ctr_true, (regs->ctr != 0 && (T0 & PARAM(3)) != 0)); -PPC_OP_BC(ctr_false, (regs->ctr != 0 && (T0 & PARAM(3)) == 0)); -PPC_OP_BC(ctrz, (regs->ctr == 0)); -PPC_OP_BC(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(3)) != 0)); -PPC_OP_BC(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(3)) == 0)); -PPC_OP_BC(true, ((T0 & PARAM(3)) != 0)); -PPC_OP_BC(false, ((T0 & PARAM(3)) == 0)); - -/* Branch to CTR */ -#define PPC_OP_BCCTR(name, cond) \ -_PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->ctr & ~0x03) - -PPC_OP_B(bctr, regs->ctr & ~0x03, PARAM(1)); -PPC_OP_BCCTR(ctr, (regs->ctr != 0)); -PPC_OP_BCCTR(ctr_true, (regs->ctr != 0 && (T0 & PARAM(2)) != 0)); -PPC_OP_BCCTR(ctr_false, (regs->ctr != 0 && (T0 & PARAM(2)) == 0)); -PPC_OP_BCCTR(ctrz, (regs->ctr == 0)); -PPC_OP_BCCTR(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(2)) != 0)); -PPC_OP_BCCTR(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(2)) == 0)); -PPC_OP_BCCTR(true, ((T0 & PARAM(2)) != 0)); -PPC_OP_BCCTR(false, ((T0 & PARAM(2)) == 0)); - -/* Branch to LR */ -#define PPC_OP_BCLR(name, cond) \ -__PPC_OP_BC(blr_##name, cond, regs->lr & ~0x03); \ -__PPC_OP_BCLRL(blrl_##name, cond, regs->lr & ~0x03) - -__PPC_OP_B(blr, regs->lr & ~0x03); -PPC_OP(blrl) -{ - T0 = regs->lr & ~0x03; - regs->lr = PARAM(1); - TB_DO_JUMP(op_blrl, T1, 0, T0); - RETURN(); -} -PPC_OP_BCLR(ctr, (regs->ctr != 0)); -PPC_OP_BCLR(ctr_true, (regs->ctr != 0 && (T0 & PARAM(2)) != 0)); -PPC_OP_BCLR(ctr_false, (regs->ctr != 0 && (T0 & PARAM(2)) == 0)); -PPC_OP_BCLR(ctrz, (regs->ctr == 0)); -PPC_OP_BCLR(ctrz_true, (regs->ctr == 0 && (T0 & PARAM(2)) != 0)); -PPC_OP_BCLR(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(2)) == 0)); -PPC_OP_BCLR(true, ((T0 & PARAM(2)) != 0)); -PPC_OP_BCLR(false, ((T0 & PARAM(2)) == 0)); +PPC_OP(setlr) +{ + regs->lr = PARAM1; +} + +PPC_OP(b) +{ + JUMP_TB(b1, PARAM1, 0, PARAM2); +} + +PPC_OP(b_T1) +{ + regs->nip = T1; +} + +PPC_OP(btest) +{ + if (T0) { + JUMP_TB(btest, PARAM1, 0, PARAM2); + } else { + JUMP_TB(btest, PARAM1, 1, PARAM3); + } + RETURN(); +} + +PPC_OP(btest_T1) +{ + if (T0) { + regs->nip = T1 & ~3; + } else { + regs->nip = PARAM1; + } + RETURN(); +} + +PPC_OP(movl_T1_ctr) +{ + T1 = regs->ctr; +} + +PPC_OP(movl_T1_lr) +{ + T1 = regs->lr; +} + +/* tests with result in T0 */ + +PPC_OP(test_ctr) +{ + T0 = (regs->ctr != 0); +} + +PPC_OP(test_ctr_true) +{ + T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0); +} + +PPC_OP(test_ctr_false) +{ + T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0); +} + +PPC_OP(test_ctrz) +{ + T0 = (regs->ctr == 0); +} + +PPC_OP(test_ctrz_true) +{ + T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0); +} + +PPC_OP(test_ctrz_false) +{ + T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0); +} + +PPC_OP(test_true) +{ + T0 = ((T0 & PARAM(1)) != 0); +} + +PPC_OP(test_false) +{ + T0 = ((T0 & PARAM(1)) == 0); +} /* CTR maintenance */ PPC_OP(dec_ctr) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f6df06b5b..e4c6ec9db 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1501,118 +1501,6 @@ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) } /*** Branch ***/ -#define GEN_BCOND(name, opc1, opc2, opc3, prologue, \ - bl_ctr, b_ctr, bl_ctrz, b_ctrz, b, bl, \ - bl_ctr_true, b_ctr_true, bl_ctrz_true, b_ctrz_true, bl_true, b_true, \ - bl_ctr_false, b_ctr_false, bl_ctrz_false, b_ctrz_false, bl_false, b_false) \ -GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW) \ -{ \ - __attribute__ ((unused)) uint32_t target; \ - uint32_t bo = BO(ctx->opcode); \ - uint32_t bi = BI(ctx->opcode); \ - uint32_t mask; \ - gen_op_update_tb(ctx->tb_offset); \ - gen_op_update_decr(ctx->decr_offset); \ - gen_op_process_exceptions((uint32_t)ctx->nip - 4); \ - prologue; \ -/* gen_op_set_T1((uint32_t)ctx->tb);*/ \ - if ((bo & 0x4) == 0) \ - gen_op_dec_ctr(); \ - if (bo & 0x10) { \ - /* No CR condition */ \ - switch (bo & 0x6) { \ - case 0: \ - if (LK(ctx->opcode)) { \ - bl_ctr; \ - } else { \ - b_ctr; \ - } \ - break; \ - case 2: \ - if (LK(ctx->opcode)) { \ - bl_ctrz; \ - } else { \ - b_ctrz; \ - } \ - break; \ - case 4: \ - case 6: \ - if (LK(ctx->opcode)) { \ - bl; \ - } else { \ - b; \ - } \ - break; \ - default: \ - printf("ERROR: %s: unhandled ba case (%d)\n", __func__, bo); \ - RET_INVAL(); \ - break; \ - } \ - } else { \ - mask = 1 << (3 - (bi & 0x03)); \ - gen_op_load_crf_T0(bi >> 2); \ - if (bo & 0x8) { \ - switch (bo & 0x6) { \ - case 0: \ - if (LK(ctx->opcode)) { \ - bl_ctr_true; \ - } else { \ - b_ctr_true; \ - } \ - break; \ - case 2: \ - if (LK(ctx->opcode)) { \ - bl_ctrz_true; \ - } else { \ - b_ctrz_true; \ - } \ - break; \ - case 4: \ - case 6: \ - if (LK(ctx->opcode)) { \ - bl_true; \ - } else { \ - b_true; \ - } \ - break; \ - default: \ - printf("ERROR: %s: unhandled b case (%d)\n", __func__, bo); \ - RET_INVAL(); \ - break; \ - } \ - } else { \ - switch (bo & 0x6) { \ - case 0: \ - if (LK(ctx->opcode)) { \ - bl_ctr_false; \ - } else { \ - b_ctr_false; \ - } \ - break; \ - case 2: \ - if (LK(ctx->opcode)) { \ - bl_ctrz_false; \ - } else { \ - b_ctrz_false; \ - } \ - break; \ - case 4: \ - case 6: \ - if (LK(ctx->opcode)) { \ - bl_false; \ - } else { \ - b_false; \ - } \ - break; \ - default: \ - printf("ERROR: %s: unhandled bn case (%d)\n", __func__, bo); \ - RET_INVAL(); \ - break; \ - } \ - } \ - } \ - ctx->exception = EXCP_BRANCH; \ -} /* b ba bl bla */ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) @@ -1626,85 +1514,127 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) target = (uint32_t)ctx->nip + li - 4; else target = li; -// gen_op_set_T1((uint32_t)ctx->tb); if (LK(ctx->opcode)) { - gen_op_bl(target, (uint32_t)ctx->nip); - } else { - gen_op_b(target); + gen_op_setlr((uint32_t)ctx->nip); } + gen_op_b((long)ctx->tb, target); ctx->exception = EXCP_BRANCH; } -/* bc bca bcl bcla */ -GEN_BCOND(bc, 0x10, 0xFF, 0xFF, - do { - uint32_t li = s_ext16(BD(ctx->opcode)); - if (AA(ctx->opcode) == 0) { - target = (uint32_t)ctx->nip + li - 4; - } else { - target = li; - } - } while (0), - gen_op_bl_ctr((uint32_t)ctx->nip, target), - gen_op_b_ctr((uint32_t)ctx->nip, target), - gen_op_bl_ctrz((uint32_t)ctx->nip, target), - gen_op_b_ctrz((uint32_t)ctx->nip, target), - gen_op_b(target), - gen_op_bl(target, (uint32_t)ctx->nip), - gen_op_bl_ctr_true((uint32_t)ctx->nip, target, mask), - gen_op_b_ctr_true((uint32_t)ctx->nip, target, mask), - gen_op_bl_ctrz_true((uint32_t)ctx->nip, target, mask), - gen_op_b_ctrz_true((uint32_t)ctx->nip, target, mask), - gen_op_bl_true((uint32_t)ctx->nip, target, mask), - gen_op_b_true((uint32_t)ctx->nip, target, mask), - gen_op_bl_ctr_false((uint32_t)ctx->nip, target, mask), - gen_op_b_ctr_false((uint32_t)ctx->nip, target, mask), - gen_op_bl_ctrz_false((uint32_t)ctx->nip, target, mask), - gen_op_b_ctrz_false((uint32_t)ctx->nip, target, mask), - gen_op_bl_false((uint32_t)ctx->nip, target, mask), - gen_op_b_false((uint32_t)ctx->nip, target, mask)); - -/* bcctr bcctrl */ -GEN_BCOND(bcctr, 0x13, 0x10, 0x10, do { } while (0), - gen_op_bctrl_ctr((uint32_t)ctx->nip), - gen_op_bctr_ctr((uint32_t)ctx->nip), - gen_op_bctrl_ctrz((uint32_t)ctx->nip), - gen_op_bctr_ctrz((uint32_t)ctx->nip), - gen_op_bctr(), - gen_op_bctrl((uint32_t)ctx->nip), - gen_op_bctrl_ctr_true((uint32_t)ctx->nip, mask), - gen_op_bctr_ctr_true((uint32_t)ctx->nip, mask), - gen_op_bctrl_ctrz_true((uint32_t)ctx->nip, mask), - gen_op_bctr_ctrz_true((uint32_t)ctx->nip, mask), - gen_op_bctrl_true((uint32_t)ctx->nip, mask), - gen_op_bctr_true((uint32_t)ctx->nip, mask), - gen_op_bctrl_ctr_false((uint32_t)ctx->nip, mask), - gen_op_bctr_ctr_false((uint32_t)ctx->nip, mask), - gen_op_bctrl_ctrz_false((uint32_t)ctx->nip, mask), - gen_op_bctr_ctrz_false((uint32_t)ctx->nip, mask), - gen_op_bctrl_false((uint32_t)ctx->nip, mask), - gen_op_bctr_false((uint32_t)ctx->nip, mask)) - -/* bclr bclrl */ -GEN_BCOND(bclr, 0x13, 0x10, 0x00, do { } while (0), - gen_op_blrl_ctr((uint32_t)ctx->nip), - gen_op_blr_ctr((uint32_t)ctx->nip), - gen_op_blrl_ctrz((uint32_t)ctx->nip), - gen_op_blr_ctrz((uint32_t)ctx->nip), - gen_op_blr(), - gen_op_blrl((uint32_t)ctx->nip), - gen_op_blrl_ctr_true((uint32_t)ctx->nip, mask), - gen_op_blr_ctr_true((uint32_t)ctx->nip, mask), - gen_op_blrl_ctrz_true((uint32_t)ctx->nip, mask), - gen_op_blr_ctrz_true((uint32_t)ctx->nip, mask), - gen_op_blrl_true((uint32_t)ctx->nip, mask), - gen_op_blr_true((uint32_t)ctx->nip, mask), - gen_op_blrl_ctr_false((uint32_t)ctx->nip, mask), - gen_op_blr_ctr_false((uint32_t)ctx->nip, mask), - gen_op_blrl_ctrz_false((uint32_t)ctx->nip, mask), - gen_op_blr_ctrz_false((uint32_t)ctx->nip, mask), - gen_op_blrl_false((uint32_t)ctx->nip, mask), - gen_op_blr_false((uint32_t)ctx->nip, mask)) +#define BCOND_IM 0 +#define BCOND_LR 1 +#define BCOND_CTR 2 + +static inline void gen_bcond(DisasContext *ctx, int type) +{ + uint32_t target = 0; + uint32_t bo = BO(ctx->opcode); + uint32_t bi = BI(ctx->opcode); + uint32_t mask; + uint32_t li; + + gen_op_update_tb(ctx->tb_offset); + gen_op_update_decr(ctx->decr_offset); + gen_op_process_exceptions((uint32_t)ctx->nip - 4); + + if ((bo & 0x4) == 0) + gen_op_dec_ctr(); + switch(type) { + case BCOND_IM: + li = s_ext16(BD(ctx->opcode)); + if (AA(ctx->opcode) == 0) { + target = (uint32_t)ctx->nip + li - 4; + } else { + target = li; + } + break; + case BCOND_CTR: + gen_op_movl_T1_ctr(); + break; + default: + case BCOND_LR: + gen_op_movl_T1_lr(); + break; + } + if (LK(ctx->opcode)) { + gen_op_setlr((uint32_t)ctx->nip); + } + if (bo & 0x10) { + /* No CR condition */ + switch (bo & 0x6) { + case 0: + gen_op_test_ctr(); + break; + case 2: + gen_op_test_ctrz(); + break; + default: + case 4: + case 6: + if (type == BCOND_IM) { + gen_op_b((long)ctx->tb, target); + } else { + gen_op_b_T1(); + break; + } + goto no_test; + } + } else { + mask = 1 << (3 - (bi & 0x03)); + gen_op_load_crf_T0(bi >> 2); + if (bo & 0x8) { + switch (bo & 0x6) { + case 0: + gen_op_test_ctr_true(mask); + break; + case 2: + gen_op_test_ctrz_true(mask); + break; + default: + case 4: + case 6: + gen_op_test_true(mask); + break; + } + } else { + switch (bo & 0x6) { + case 0: + gen_op_test_ctr_false(mask); + break; + case 2: + gen_op_test_ctrz_false(mask); + break; + default: + case 4: + case 6: + gen_op_test_false(mask); + break; + } + } + } + if (type == BCOND_IM) { + gen_op_btest((long)ctx->tb, target, (uint32_t)ctx->nip); + } else { + gen_op_btest_T1((uint32_t)ctx->nip); + } + no_test: + ctx->exception = EXCP_BRANCH; +} + +GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW) +{ + gen_bcond(ctx, BCOND_IM); +} + +GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW) +{ + gen_bcond(ctx, BCOND_CTR); +} + +GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW) +{ + gen_bcond(ctx, BCOND_LR); +} /*** Condition register logical ***/ #define GEN_CRLOGIC(op, opc) \ @@ -3148,7 +3078,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (gen_opc_ptr >= gen_opc_end || ((uint32_t)ctx.nip - pc_start) >= (TARGET_PAGE_SIZE - 32)) { if (ctx.exception == EXCP_NONE) { - gen_op_b((uint32_t)ctx.nip); + gen_op_b((long)ctx.tb, (uint32_t)ctx.nip); ctx.exception = EXCP_BRANCH; } } -- cgit v1.2.3 From 6b2d3e3c961d62d5e12b54f8ca8b3b60ca92defd Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 21 Feb 2004 15:41:09 +0000 Subject: fixed blr/bctr cases git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@631 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e4c6ec9db..97a0d27a2 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1575,7 +1575,6 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_op_b((long)ctx->tb, target); } else { gen_op_b_T1(); - break; } goto no_test; } -- cgit v1.2.3 From 83d73968500d903a8dde19298a324bf45be7b3ee Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 22 Feb 2004 11:53:50 +0000 Subject: faster big endian accesses on i386 - big endian ldsw_raw fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@632 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index a2b62df90..931ea052d 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -56,6 +56,39 @@ typedef union { /* 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_raw(void *ptr) { return *(uint8_t *)ptr; @@ -195,20 +228,47 @@ static inline void stfq_raw(void *ptr, double v) static inline int lduw_raw(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]); + return ((b[0] << 8) | b[1]); +#endif } static inline int ldsw_raw(void *ptr) { - int8_t *b = (int8_t *) ptr; - return (b[0]<<8|b[1]); +#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_raw(void *ptr) { +#if defined(__i386__) + 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]); + return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; +#endif } static inline uint64_t ldq_raw(void *ptr) @@ -221,18 +281,32 @@ static inline uint64_t ldq_raw(void *ptr) static inline void stw_raw(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_raw(void *ptr, int v) { +#if defined(__i386__) + 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_raw(void *ptr, uint64_t v) -- cgit v1.2.3 From 121061dcdfdf5ef1d78cd2ae84b39b779a568e28 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 22 Feb 2004 11:56:01 +0000 Subject: O_DIRECT compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@633 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 52e1c6b53..9ac95729f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1144,7 +1144,9 @@ static bitmask_transtbl fcntl_flags_tbl[] = { { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, }, { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, }, { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, }, +#if defined(O_DIRECT) { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, }, +#endif { 0, 0, 0, 0 } }; -- cgit v1.2.3 From edf779ffccc836661a7b654d320571a6c220caea Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 22 Feb 2004 13:40:13 +0000 Subject: use kernel like macros for user access (will be useful someday to have a better error checking git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@634 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 43 ++++++++++--------- linux-user/qemu.h | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/signal.c | 72 +------------------------------ linux-user/syscall.c | 21 --------- 4 files changed, 142 insertions(+), 112 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 71055255c..980ab6ba0 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -263,19 +263,11 @@ struct exec #define DLINFO_ITEMS 11 -#define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) -#define get_user(ptr) (typeof(*ptr))(*(ptr)) - static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { memcpy(to, from, n); } -static inline void memcpy_tofs(void * to, const void * from, unsigned long n) -{ - memcpy(to, from, n); -} - extern unsigned long x86_stack_size; static int load_aout_interp(void * exptr, int interp_fd); @@ -373,11 +365,13 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, return 0; /* bullet-proofing */ } while (argc-- > 0) { - if (!(tmp1 = tmp = get_user(argv+argc))) { + tmp = argv[argc]; + if (!tmp) { fprintf(stderr, "VFS: argc is wrong"); exit(-1); } - while (get_user(tmp++)); + tmp1 = tmp; + while (*tmp++); len = tmp - tmp1; if (p < len) { /* this shouldn't happen - 128kB */ return 0; @@ -395,7 +389,7 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, } } if (len == 0 || offset == 0) { - *(pag + offset) = get_user(tmp); + *(pag + offset) = *tmp; } else { int bytes_to_copy = (len > offset) ? offset : len; @@ -599,7 +593,8 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, { target_ulong *argv, *envp; target_ulong *sp, *csp; - + int v; + /* * Force 16 byte _final_ alignment here for generality. */ @@ -616,8 +611,8 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); #define NEW_AUX_ENT(nr, id, val) \ - put_user (tswapl(id), sp + (nr * 2)); \ - put_user (tswapl(val), sp + (nr * 2 + 1)) + put_user (id, sp + (nr * 2)); \ + put_user (val, sp + (nr * 2 + 1)) sp -= 2; NEW_AUX_ENT (0, AT_NULL, 0); @@ -647,20 +642,26 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, sp -= argc+1; argv = sp; if (!ibcs) { - put_user(tswapl((target_ulong)envp),--sp); - put_user(tswapl((target_ulong)argv),--sp); + put_user((target_ulong)envp,--sp); + put_user((target_ulong)argv,--sp); } - put_user(tswapl(argc),--sp); + put_user(argc,--sp); info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); while (argc-->0) { - put_user(tswapl((target_ulong)p),argv++); - while (get_user(p++)) /* nothing */ ; + put_user((target_ulong)p,argv++); + do { + get_user(v, p); + p++; + } while (v != 0); } put_user(0,argv); info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); while (envc-->0) { - put_user(tswapl((target_ulong)p),envp++); - while (get_user(p++)) /* nothing */ ; + put_user((target_ulong)p,envp++); + do { + get_user(v, p); + p++; + } while (v != 0); } put_user(0,envp); info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 1a3ad6274..be95ff918 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -4,6 +4,7 @@ #include "thunk.h" #include +#include #include "syscall_defs.h" #include "cpu.h" @@ -120,4 +121,121 @@ long target_mremap(unsigned long old_addr, unsigned long old_size, unsigned long new_addr); int target_msync(unsigned long start, unsigned long len, int flags); +/* user access */ + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +#define access_ok(type,addr,size) (1) + +#define __put_user(x,ptr)\ +({\ + int size = sizeof(*ptr);\ + switch(size) {\ + case 1:\ + stb(ptr, (typeof(*ptr))(x));\ + break;\ + case 2:\ + stw(ptr, (typeof(*ptr))(x));\ + break;\ + case 4:\ + stl(ptr, (typeof(*ptr))(x));\ + break;\ + case 8:\ + stq(ptr, (typeof(*ptr))(x));\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) + +#define __get_user(x, ptr) \ +({\ + int size = sizeof(*ptr);\ + switch(size) {\ + case 1:\ + x = (typeof(*ptr))ldub(ptr);\ + break;\ + case 2:\ + x = (typeof(*ptr))lduw(ptr);\ + break;\ + case 4:\ + x = (typeof(*ptr))ldl(ptr);\ + break;\ + case 8:\ + x = (typeof(*ptr))ldq(ptr);\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) + +static inline unsigned long __copy_to_user(void *dst, const void *src, + unsigned long size) +{ + memcpy(dst, src, size); + return 0; +} + +static inline unsigned long __copy_from_user(void *dst, const void *src, + unsigned long size) +{ + memcpy(dst, src, size); + return 0; +} + +static inline unsigned long __clear_user(void *dst, unsigned long size) +{ + memset(dst, 0, size); + return 0; +} + +#define put_user(x,ptr)\ +({\ + int __ret;\ + if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\ + __ret = __put_user(x, ptr);\ + else\ + __ret = -EFAULT;\ + __ret;\ +}) + +#define get_user(x,ptr)\ +({\ + int __ret;\ + if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\ + __ret = __get_user(x, ptr);\ + else\ + __ret = -EFAULT;\ + __ret;\ +}) + +static inline unsigned long copy_to_user(void *dst, const void *src, + unsigned long size) +{ + if (access_ok(VERIFY_WRITE, dst, size)) + return __copy_to_user(dst, src, size); + else + return size; +} + +static inline unsigned long copy_from_user(void *dst, const void *src, + unsigned long size) +{ + if (access_ok(VERIFY_READ, src, size)) + return __copy_from_user(dst, src, size); + else + return size; +} + +static inline unsigned long clear_user(void *dst, unsigned long size) +{ + if (access_ok(VERIFY_WRITE, dst, size)) + return __clear_user(dst, size); + else + return size; +} + #endif diff --git a/linux-user/signal.c b/linux-user/signal.c index 666d6e14f..41affb56e 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -450,69 +450,6 @@ int do_sigaction(int sig, const struct target_sigaction *act, return 0; } -#define __put_user(x,ptr)\ -({\ - int size = sizeof(*ptr);\ - switch(size) {\ - case 1:\ - stb(ptr, (typeof(*ptr))(x));\ - break;\ - case 2:\ - stw(ptr, (typeof(*ptr))(x));\ - break;\ - case 4:\ - stl(ptr, (typeof(*ptr))(x));\ - break;\ - case 8:\ - stq(ptr, (typeof(*ptr))(x));\ - break;\ - default:\ - abort();\ - }\ - 0;\ -}) - -#define __get_user(x, ptr) \ -({\ - int size = sizeof(*ptr);\ - switch(size) {\ - case 1:\ - x = (typeof(*ptr))ldub(ptr);\ - break;\ - case 2:\ - x = (typeof(*ptr))lduw(ptr);\ - break;\ - case 4:\ - x = (typeof(*ptr))ldl(ptr);\ - break;\ - case 8:\ - x = (typeof(*ptr))ldq(ptr);\ - break;\ - default:\ - abort();\ - }\ - 0;\ -}) - - -#define __copy_to_user(dst, src, size)\ -({\ - memcpy(dst, src, size);\ - 0;\ -}) - -#define __copy_from_user(dst, src, size)\ -({\ - memcpy(dst, src, size);\ - 0;\ -}) - -#define __clear_user(dst, size)\ -({\ - memset(dst, 0, size);\ - 0;\ -}) - #ifndef offsetof #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif @@ -707,10 +644,8 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, frame = get_sigframe(ka, env, sizeof(*frame)); -#if 0 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; -#endif err |= __put_user((/*current->exec_domain && current->exec_domain->signal_invmap && sig < 32 @@ -773,10 +708,8 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, frame = get_sigframe(ka, env, sizeof(*frame)); -#if 0 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; -#endif err |= __put_user((/*current->exec_domain && current->exec_domain->signal_invmap @@ -1172,10 +1105,9 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame)); int err = 0; -#if 0 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) - return 1; -#endif + return /* 1 */; + __put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err); __put_user_error(&frame->uc, (target_ulong *)&frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9ac95729f..6fae50dd0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -239,27 +239,6 @@ extern int setresgid(gid_t, gid_t, gid_t); extern int getresgid(gid_t *, gid_t *, gid_t *); extern int setgroups(int, gid_t *); -#define put_user(x,ptr)\ -({\ - int size = sizeof(*ptr);\ - switch(size) {\ - case 1:\ - stb(ptr, (typeof(*ptr))(x));\ - break;\ - case 2:\ - stw(ptr, (typeof(*ptr))(x));\ - break;\ - case 4:\ - stl(ptr, (typeof(*ptr))(x));\ - break;\ - case 8:\ - stq(ptr, (typeof(*ptr))(x));\ - break;\ - default:\ - abort();\ - }\ - 0;\ -}) static inline long get_errno(long ret) { if (ret == -1) -- cgit v1.2.3 From 537730b956572a9e32adfa2e18164e8234594c08 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 22 Feb 2004 13:40:57 +0000 Subject: zero offset optimisation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@635 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 50fe8aa5e..3efd55ee3 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -279,7 +279,8 @@ static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) val = insn & 0xfff; if (!(insn & (1 << 23))) val = -val; - gen_op_addl_T1_im(val); + if (val != 0) + gen_op_addl_T1_im(val); } else { /* shift/register */ rm = (insn) & 0xf; @@ -304,7 +305,8 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn) val = (insn & 0xf) | ((insn >> 4) & 0xf0); if (!(insn & (1 << 23))) val = -val; - gen_op_addl_T1_im(val); + if (val != 0) + gen_op_addl_T1_im(val); } else { /* register */ rm = (insn) & 0xf; -- cgit v1.2.3 From b88e4a9a3bf7cdd1528755bbd18ff3dc3cf6def6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 22 Feb 2004 13:41:47 +0000 Subject: small test optimisations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@636 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 94ead452f..e47e245af 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -524,7 +524,7 @@ PPC_OP(movl_T1_lr) PPC_OP(test_ctr) { - T0 = (regs->ctr != 0); + T0 = regs->ctr; } PPC_OP(test_ctr_true) @@ -554,7 +554,7 @@ PPC_OP(test_ctrz_false) PPC_OP(test_true) { - T0 = ((T0 & PARAM(1)) != 0); + T0 = (T0 & PARAM(1)); } PPC_OP(test_false) -- cgit v1.2.3 From e374bfa35bfb833928e8edf686e962d16705abeb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 22 Feb 2004 14:54:18 +0000 Subject: shm tests - disabled clone test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@637 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/linux-test.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/linux-test.c b/tests/linux-test.c index 14cbe1385..6ca902965 100644 --- a/tests/linux-test.c +++ b/tests/linux-test.c @@ -38,6 +38,7 @@ #include #include #include +#include #define TESTPATH "/tmp/linux-test.tmp" #define TESTPORT 7654 @@ -314,12 +315,19 @@ const char socket_msg[] = "hello socket\n"; void test_socket(void) { - int server_fd, client_fd, fd, pid, ret; + int server_fd, client_fd, fd, pid, ret, val; struct sockaddr_in sockaddr; socklen_t len; char buf[512]; server_fd = server_socket(); + + /* test a few socket options */ + len = sizeof(val); + chk_error(getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &val, &len)); + if (val != SOCK_STREAM) + error("getsockopt"); + pid = chk_error(fork()); if (pid == 0) { client_fd = client_socket(); @@ -497,13 +505,32 @@ void test_signal(void) chk_error(sigaction(SIGSEGV, &act, NULL)); } +#define SHM_SIZE 32768 + +void test_shm(void) +{ + void *ptr; + int shmid; + + shmid = chk_error(shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0777)); + ptr = shmat(shmid, NULL, 0); + if (!ptr) + error("shmat"); + + memset(ptr, 0, SHM_SIZE); + + chk_error(shmctl(shmid, IPC_RMID, 0)); + chk_error(shmdt(ptr)); +} + int main(int argc, char **argv) { test_file(); test_fork(); test_time(); test_socket(); - test_clone(); + // test_clone(); test_signal(); + test_shm(); return 0; } -- cgit v1.2.3 From 8853f86e1da70e79464aa3329f7b84a27a199bad Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 22 Feb 2004 14:57:26 +0000 Subject: shm support, more setsockopt and getsockopt calls, fds fix (initial patch by Paul McKerras) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@638 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 245 ++++++++++++++++++++++++++++++++++++---------- linux-user/syscall_defs.h | 13 +++ 2 files changed, 206 insertions(+), 52 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6fae50dd0..0abe68503 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -41,8 +41,10 @@ #include #include #include +#include #include //#include +#include #include #define termios host_termios @@ -325,7 +327,7 @@ static inline void host_to_target_fds(target_long *target_fds, target_long v; if (target_fds) { - nw = n / TARGET_LONG_BITS; + nw = (n + TARGET_LONG_BITS - 1) / TARGET_LONG_BITS; k = 0; for(i = 0;i < nw; i++) { v = 0; @@ -530,61 +532,116 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, static long do_setsockopt(int sockfd, int level, int optname, void *optval, socklen_t optlen) { - if (level == SOL_TCP) { + int val, ret; + + switch(level) { + case SOL_TCP: /* TCP options all take an 'int' value. */ - int val; - if (optlen < sizeof(uint32_t)) return -EINVAL; - - val = tswap32(*(uint32_t *)optval); - return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); - } - - else if (level != SOL_SOCKET) { - gemu_log("Unsupported setsockopt level: %d\n", level); - return -ENOSYS; - } - - switch (optname) { - /* Options with 'int' argument. */ - case SO_DEBUG: - case SO_REUSEADDR: - case SO_TYPE: - case SO_ERROR: - case SO_DONTROUTE: - case SO_BROADCAST: - case SO_SNDBUF: - case SO_RCVBUF: - case SO_KEEPALIVE: - case SO_OOBINLINE: - case SO_NO_CHECK: - case SO_PRIORITY: - case SO_BSDCOMPAT: - case SO_PASSCRED: - case SO_TIMESTAMP: - case SO_RCVLOWAT: - case SO_RCVTIMEO: - case SO_SNDTIMEO: - { - int val; - if (optlen < sizeof(uint32_t)) - return -EINVAL; - val = tswap32(*(uint32_t *)optval); - return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); - } - + + if (get_user(val, (uint32_t *)optval)) + return -EFAULT; + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + break; + case SOL_IP: + switch(optname) { + case IP_HDRINCL: + val = 0; + if (optlen >= sizeof(uint32_t)) { + if (get_user(val, (uint32_t *)optval)) + return -EFAULT; + } else if (optlen >= 1) { + if (get_user(val, (uint8_t *)optval)) + return -EFAULT; + } + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + break; + default: + goto unimplemented; + } + break; + case SOL_SOCKET: + switch (optname) { + /* Options with 'int' argument. */ + case SO_DEBUG: + case SO_REUSEADDR: + case SO_TYPE: + case SO_ERROR: + case SO_DONTROUTE: + case SO_BROADCAST: + case SO_SNDBUF: + case SO_RCVBUF: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case SO_NO_CHECK: + case SO_PRIORITY: + case SO_BSDCOMPAT: + case SO_PASSCRED: + case SO_TIMESTAMP: + case SO_RCVLOWAT: + case SO_RCVTIMEO: + case SO_SNDTIMEO: + if (optlen < sizeof(uint32_t)) + return -EINVAL; + if (get_user(val, (uint32_t *)optval)) + return -EFAULT; + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + break; + default: + goto unimplemented; + } + break; default: - gemu_log("Unsupported setsockopt SOL_SOCKET option: %d\n", optname); - return -ENOSYS; + unimplemented: + gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname); + ret = -ENOSYS; } + return ret; } static long do_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { - gemu_log("getsockopt not yet supported\n"); - return -ENOSYS; + int len, lv, val, ret; + + switch(level) { + case SOL_SOCKET: + switch (optname) { + case SO_LINGER: + case SO_RCVTIMEO: + case SO_SNDTIMEO: + case SO_PEERCRED: + case SO_PEERNAME: + /* These don't just return a single integer */ + goto unimplemented; + default: + if (get_user(len, optlen)) + return -EFAULT; + if (len < 0) + return -EINVAL; + lv = sizeof(int); + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); + if (ret < 0) + return ret; + val = tswap32(val); + if (len > lv) + len = lv; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + if (put_user(len, optlen)) + return -EFAULT; + break; + } + break; + default: + unimplemented: + gemu_log("getsockopt level=%d optname=%d not yet supported\n", + level, optname); + ret = -ENOSYS; + break; + } + return ret; } static long do_socketcall(int num, int32_t *vptr) @@ -807,12 +864,9 @@ static long do_socketcall(int num, int32_t *vptr) int level = tswap32(vptr[1]); int optname = tswap32(vptr[2]); void *optval = (void *)tswap32(vptr[3]); - uint32_t *target_len = (void *)tswap32(vptr[4]); - socklen_t optlen = tswap32(*target_len); + uint32_t *poptlen = (void *)tswap32(vptr[4]); - ret = do_getsockopt(sockfd, level, optname, optval, &optlen); - if (!is_error(ret)) - *target_len = tswap32(optlen); + ret = do_getsockopt(sockfd, level, optname, optval, poptlen); } break; default: @@ -823,6 +877,92 @@ static long do_socketcall(int num, int32_t *vptr) return ret; } + +#define N_SHM_REGIONS 32 + +static struct shm_region { + uint32_t start; + uint32_t size; +} shm_regions[N_SHM_REGIONS]; + +static long do_ipc(long call, long first, long second, long third, + long ptr, long fifth) +{ + int version; + long ret = 0; + unsigned long raddr; + struct shmid_ds shm_info; + int i; + + version = call >> 16; + call &= 0xffff; + + switch (call) { + case IPCOP_shmat: + /* SHM_* flags are the same on all linux platforms */ + ret = get_errno((long) shmat(first, (void *) ptr, second)); + if (is_error(ret)) + break; + raddr = ret; + /* find out the length of the shared memory segment */ + + ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); + if (is_error(ret)) { + /* can't get length, bail out */ + shmdt((void *) raddr); + break; + } + page_set_flags(raddr, raddr + shm_info.shm_segsz, + PAGE_VALID | PAGE_READ | + ((second & SHM_RDONLY)? 0: PAGE_WRITE)); + for (i = 0; i < N_SHM_REGIONS; ++i) { + if (shm_regions[i].start == 0) { + shm_regions[i].start = raddr; + shm_regions[i].size = shm_info.shm_segsz; + break; + } + } + if (put_user(raddr, (uint32_t *)third)) + return -EFAULT; + ret = 0; + break; + case IPCOP_shmdt: + for (i = 0; i < N_SHM_REGIONS; ++i) { + if (shm_regions[i].start == ptr) { + shm_regions[i].start = 0; + page_set_flags(ptr, shm_regions[i].size, 0); + break; + } + } + ret = get_errno(shmdt((void *) ptr)); + break; + + case IPCOP_shmget: + /* IPC_* flag values are the same on all linux platforms */ + ret = get_errno(shmget(first, second, third)); + break; + + /* IPC_* and SHM_* command values are the same on all linux platforms */ + case IPCOP_shmctl: + switch(second) { + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + ret = get_errno(shmctl(first, second, NULL)); + break; + default: + goto unimplemented; + } + break; + default: + unimplemented: + gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version); + ret = -ENOSYS; + break; + } + return ret; +} + /* kernel structure types definitions */ #define IFNAMSIZ 16 @@ -2205,7 +2345,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_sysinfo: goto unimplemented; case TARGET_NR_ipc: - goto unimplemented; + ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); + break; case TARGET_NR_fsync: ret = get_errno(fsync(arg1)); break; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index a05b6f679..356e6fd96 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -24,6 +24,19 @@ #define SOCKOP_sendmsg 16 #define SOCKOP_recvmsg 17 +#define IPCOP_semop 1 +#define IPCOP_semget 2 +#define IPCOP_semctl 3 +#define IPCOP_semtimedop 4 +#define IPCOP_msgsnd 11 +#define IPCOP_msgrcv 12 +#define IPCOP_msgget 13 +#define IPCOP_msgctl 14 +#define IPCOP_shmat 21 +#define IPCOP_shmdt 22 +#define IPCOP_shmget 23 +#define IPCOP_shmctl 24 + /* * The following is for compatibility across the various Linux * platforms. The i386 ioctl numbering scheme doesn't really enforce -- cgit v1.2.3 From 2edcdce334e8bf6143a498550a39e4a363c69bfc Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:15:06 +0000 Subject: fpu fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@639 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 31168573e..0c320836c 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2364,10 +2364,10 @@ void helper_fstenv(uint8_t *ptr, int data32) stl(ptr, env->fpuc); stl(ptr + 4, fpus); stl(ptr + 8, fptag); - stl(ptr + 12, 0); - stl(ptr + 16, 0); - stl(ptr + 20, 0); - stl(ptr + 24, 0); + stl(ptr + 12, 0); /* fpip */ + stl(ptr + 16, 0); /* fpcs */ + stl(ptr + 20, 0); /* fpoo */ + stl(ptr + 24, 0); /* fpos */ } else { /* 16 bit */ stw(ptr, env->fpuc); @@ -2396,7 +2396,7 @@ void helper_fldenv(uint8_t *ptr, int data32) } env->fpstt = (fpus >> 11) & 7; env->fpus = fpus & ~0x3800; - for(i = 0;i < 7; i++) { + for(i = 0;i < 8; i++) { env->fptags[i] = ((fptag & 3) == 3); fptag >>= 2; } -- cgit v1.2.3 From 9588b95a0849cb4c9e344b3791a76af7df0aaf80 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:15:55 +0000 Subject: CR0.MP/EM/TS support - native fpu support in code copy mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@640 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index e1dc4741d..c98262c2d 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -267,6 +267,9 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); /* ensure that ADDSEG is always set in real mode */ env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT); + /* update FPU flags */ + env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) | + ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)); } void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3) @@ -476,3 +479,73 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return paddr; } #endif + +#if defined(USE_CODE_COPY) +struct fpstate { + uint16_t fpuc; + uint16_t dummy1; + uint16_t fpus; + uint16_t dummy2; + uint16_t fptag; + uint16_t dummy3; + + uint32_t fpip; + uint32_t fpcs; + uint32_t fpoo; + uint32_t fpos; + uint8_t fpregs1[8 * 10]; +}; + +void restore_native_fp_state(CPUState *env) +{ + int fptag, i, j; + struct fpstate fp1, *fp = &fp1; + + fp->fpuc = env->fpuc; + fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for (i=7; i>=0; i--) { + fptag <<= 2; + if (env->fptags[i]) { + fptag |= 3; + } else { + /* the FPU automatically computes it */ + } + } + fp->fptag = fptag; + j = env->fpstt; + for(i = 0;i < 8; i++) { + memcpy(&fp->fpregs1[i * 10], &env->fpregs[j], 10); + j = (j + 1) & 7; + } + asm volatile ("frstor %0" : "=m" (*fp)); + env->native_fp_regs = 1; +} + +void save_native_fp_state(CPUState *env) +{ + int fptag, i, j; + uint16_t fpuc; + struct fpstate fp1, *fp = &fp1; + + asm volatile ("fsave %0" : : "m" (*fp)); + env->fpuc = fp->fpuc; + env->fpstt = (fp->fpus >> 11) & 7; + env->fpus = fp->fpus & ~0x3800; + fptag = fp->fptag; + for(i = 0;i < 8; i++) { + env->fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } + j = env->fpstt; + for(i = 0;i < 8; i++) { + memcpy(&env->fpregs[j], &fp->fpregs1[i * 10], 10); + j = (j + 1) & 7; + } + /* we must restore the default rounding state */ + /* XXX: we do not restore the exception state */ + fpuc = 0x037f | (env->fpuc & (3 << 10)); + asm volatile("fldcw %0" : : "m" (fpuc)); + env->native_fp_regs = 0; +} +#endif -- cgit v1.2.3 From 42c3c0cceddee64c22024e3e92ed636e75ea9c77 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:17:25 +0000 Subject: native FPU support (disabled) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@641 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate-copy.c | 324 +++++++------------------------------------ 1 file changed, 47 insertions(+), 277 deletions(-) diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index 340864ac7..08775e618 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -31,6 +31,8 @@ #include "exec-all.h" #include "disas.h" +#ifdef USE_CODE_COPY + extern char exec_loop; /* operand size */ @@ -67,6 +69,7 @@ typedef struct DisasContext { int vm86; /* vm86 mode */ int cpl; int iopl; + int flags; struct TranslationBlock *tb; } DisasContext; @@ -274,7 +277,7 @@ static int disas_insn(DisasContext *s) uint8_t *pc_start, *pc_tmp, *pc_start_insn; int b, prefixes, aflag, dflag, next_eip, val; int ot; - int modrm, mod, op; + int modrm, mod, op, rm; pc_start = s->pc; prefixes = 0; @@ -644,48 +647,37 @@ static int disas_insn(DisasContext *s) op = R_GS; do_lxx: goto unsupported_op; -#if 0 /************************/ /* floats */ case 0xd8 ... 0xdf: +#if 1 + /* currently not stable enough */ + goto unsupported_op; +#else + if (s->flags & (HF_EM_MASK | HF_TS_MASK)) + goto unsupported_op; +#endif +#if 0 + /* for testing FPU context switch */ + { + static int count; + count = (count + 1) % 3; + if (count != 0) + goto unsupported_op; + } +#endif modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; op = ((b & 7) << 3) | ((modrm >> 3) & 7); if (mod != 3) { /* memory op */ - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + parse_modrm(s, modrm); switch(op) { case 0x00 ... 0x07: /* fxxxs */ case 0x10 ... 0x17: /* fixxxl */ case 0x20 ... 0x27: /* fxxxl */ case 0x30 ... 0x37: /* fixxx */ - { - int op1; - op1 = op & 7; - - switch(op >> 4) { - case 0: - gen_op_flds_FT0_A0(); - break; - case 1: - gen_op_fildl_FT0_A0(); - break; - case 2: - gen_op_fldl_FT0_A0(); - break; - case 3: - default: - gen_op_fild_FT0_A0(); - break; - } - - gen_op_fp_arith_ST0_FT0[op1](); - if (op1 == 3) { - /* fcomp needs pop */ - gen_op_fpop(); - } - } break; case 0x08: /* flds */ case 0x0a: /* fsts */ @@ -699,102 +691,28 @@ static int disas_insn(DisasContext *s) case 0x38: /* filds */ case 0x3a: /* fists */ case 0x3b: /* fistps */ - - switch(op & 7) { - case 0: - switch(op >> 4) { - case 0: - gen_op_flds_ST0_A0(); - break; - case 1: - gen_op_fildl_ST0_A0(); - break; - case 2: - gen_op_fldl_ST0_A0(); - break; - case 3: - default: - gen_op_fild_ST0_A0(); - break; - } - break; - default: - switch(op >> 4) { - case 0: - gen_op_fsts_ST0_A0(); - break; - case 1: - gen_op_fistl_ST0_A0(); - break; - case 2: - gen_op_fstl_ST0_A0(); - break; - case 3: - default: - gen_op_fist_ST0_A0(); - break; - } - if ((op & 7) == 3) - gen_op_fpop(); - break; - } - break; case 0x0c: /* fldenv mem */ - gen_op_fldenv_A0(s->dflag); - break; case 0x0d: /* fldcw mem */ - gen_op_fldcw_A0(); - break; case 0x0e: /* fnstenv mem */ - gen_op_fnstenv_A0(s->dflag); - break; case 0x0f: /* fnstcw mem */ - gen_op_fnstcw_A0(); - break; case 0x1d: /* fldt mem */ - gen_op_fldt_ST0_A0(); - break; case 0x1f: /* fstpt mem */ - gen_op_fstt_ST0_A0(); - gen_op_fpop(); - break; case 0x2c: /* frstor mem */ - gen_op_frstor_A0(s->dflag); - break; case 0x2e: /* fnsave mem */ - gen_op_fnsave_A0(s->dflag); - break; case 0x2f: /* fnstsw mem */ - gen_op_fnstsw_A0(); - break; case 0x3c: /* fbld */ - gen_op_fbld_ST0_A0(); - break; case 0x3e: /* fbstp */ - gen_op_fbst_ST0_A0(); - gen_op_fpop(); - break; case 0x3d: /* fildll */ - gen_op_fildll_ST0_A0(); - break; case 0x3f: /* fistpll */ - gen_op_fistll_ST0_A0(); - gen_op_fpop(); break; default: goto illegal_op; } } else { /* register float ops */ - opreg = rm; - switch(op) { case 0x08: /* fld sti */ - gen_op_fpush(); - gen_op_fmov_ST0_STN((opreg + 1) & 7); - break; case 0x09: /* fxchg sti */ - gen_op_fxchg_ST0_STN(opreg); break; case 0x0a: /* grp d9/2 */ switch(rm) { @@ -807,149 +725,43 @@ static int disas_insn(DisasContext *s) case 0x0c: /* grp d9/4 */ switch(rm) { case 0: /* fchs */ - gen_op_fchs_ST0(); - break; case 1: /* fabs */ - gen_op_fabs_ST0(); - break; case 4: /* ftst */ - gen_op_fldz_FT0(); - gen_op_fcom_ST0_FT0(); - break; case 5: /* fxam */ - gen_op_fxam_ST0(); break; default: goto illegal_op; } break; case 0x0d: /* grp d9/5 */ - { - switch(rm) { - case 0: - gen_op_fpush(); - gen_op_fld1_ST0(); - break; - case 1: - gen_op_fpush(); - gen_op_fldl2t_ST0(); - break; - case 2: - gen_op_fpush(); - gen_op_fldl2e_ST0(); - break; - case 3: - gen_op_fpush(); - gen_op_fldpi_ST0(); - break; - case 4: - gen_op_fpush(); - gen_op_fldlg2_ST0(); - break; - case 5: - gen_op_fpush(); - gen_op_fldln2_ST0(); - break; - case 6: - gen_op_fpush(); - gen_op_fldz_ST0(); - break; - default: - goto illegal_op; - } - } - break; - case 0x0e: /* grp d9/6 */ switch(rm) { - case 0: /* f2xm1 */ - gen_op_f2xm1(); - break; - case 1: /* fyl2x */ - gen_op_fyl2x(); - break; - case 2: /* fptan */ - gen_op_fptan(); - break; - case 3: /* fpatan */ - gen_op_fpatan(); - break; - case 4: /* fxtract */ - gen_op_fxtract(); - break; - case 5: /* fprem1 */ - gen_op_fprem1(); - break; - case 6: /* fdecstp */ - gen_op_fdecstp(); + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: break; default: - case 7: /* fincstp */ - gen_op_fincstp(); - break; + goto illegal_op; } break; + case 0x0e: /* grp d9/6 */ + break; case 0x0f: /* grp d9/7 */ - switch(rm) { - case 0: /* fprem */ - gen_op_fprem(); - break; - case 1: /* fyl2xp1 */ - gen_op_fyl2xp1(); - break; - case 2: /* fsqrt */ - gen_op_fsqrt(); - break; - case 3: /* fsincos */ - gen_op_fsincos(); - break; - case 5: /* fscale */ - gen_op_fscale(); - break; - case 4: /* frndint */ - gen_op_frndint(); - break; - case 6: /* fsin */ - gen_op_fsin(); - break; - default: - case 7: /* fcos */ - gen_op_fcos(); - break; - } break; case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ - { - int op1; - - op1 = op & 7; - if (op >= 0x20) { - gen_op_fp_arith_STN_ST0[op1](opreg); - if (op >= 0x30) - gen_op_fpop(); - } else { - gen_op_fmov_FT0_STN(opreg); - gen_op_fp_arith_ST0_FT0[op1](); - } - } break; case 0x02: /* fcom */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fcom_ST0_FT0(); break; case 0x03: /* fcomp */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fcom_ST0_FT0(); - gen_op_fpop(); break; case 0x15: /* da/5 */ switch(rm) { case 1: /* fucompp */ - gen_op_fmov_FT0_STN(1); - gen_op_fucom_ST0_FT0(); - gen_op_fpop(); - gen_op_fpop(); break; default: goto illegal_op; @@ -958,15 +770,10 @@ static int disas_insn(DisasContext *s) case 0x1c: switch(rm) { case 0: /* feni (287 only, just do nop here) */ - break; case 1: /* fdisi (287 only, just do nop here) */ - break; + goto unsupported_op; case 2: /* fclex */ - gen_op_fclex(); - break; case 3: /* fninit */ - gen_op_fninit(); - break; case 4: /* fsetpm (287 only, just do nop here) */ break; default: @@ -974,42 +781,20 @@ static int disas_insn(DisasContext *s) } break; case 0x1d: /* fucomi */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fucomi_ST0_FT0(); - s->cc_op = CC_OP_EFLAGS; break; case 0x1e: /* fcomi */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fcomi_ST0_FT0(); - s->cc_op = CC_OP_EFLAGS; break; case 0x2a: /* fst sti */ - gen_op_fmov_STN_ST0(opreg); break; case 0x2b: /* fstp sti */ - gen_op_fmov_STN_ST0(opreg); - gen_op_fpop(); break; case 0x2c: /* fucom st(i) */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fucom_ST0_FT0(); break; case 0x2d: /* fucomp st(i) */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fucom_ST0_FT0(); - gen_op_fpop(); break; case 0x33: /* de/3 */ switch(rm) { case 1: /* fcompp */ - gen_op_fmov_FT0_STN(1); - gen_op_fcom_ST0_FT0(); - gen_op_fpop(); - gen_op_fpop(); break; default: goto illegal_op; @@ -1018,49 +803,25 @@ static int disas_insn(DisasContext *s) case 0x3c: /* df/4 */ switch(rm) { case 0: - gen_op_fnstsw_EAX(); break; default: goto illegal_op; } break; case 0x3d: /* fucomip */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fucomi_ST0_FT0(); - gen_op_fpop(); - s->cc_op = CC_OP_EFLAGS; break; case 0x3e: /* fcomip */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fcomi_ST0_FT0(); - gen_op_fpop(); - s->cc_op = CC_OP_EFLAGS; break; case 0x10 ... 0x13: /* fcmovxx */ case 0x18 ... 0x1b: - { - int op1; - const static uint8_t fcmov_cc[8] = { - (JCC_B << 1), - (JCC_Z << 1), - (JCC_BE << 1), - (JCC_P << 1), - }; - op1 = fcmov_cc[op & 3] | ((op >> 3) & 1); - gen_setcc(s, op1); - gen_op_fcmov_ST0_STN_T0(opreg); - } break; default: goto illegal_op; } } + s->tb->cflags |= CF_TB_FP_USED; break; -#endif + /**************************/ /* mov */ case 0xc6: @@ -1303,6 +1064,10 @@ static int disas_insn(DisasContext *s) case 0x90: /* nop */ break; case 0x9b: /* fwait */ + if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == + (HF_MP_MASK | HF_TS_MASK)) { + goto unsupported_op; + } break; case 0xcc: /* int3 */ goto unsupported_op; @@ -1436,7 +1201,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->cpl = (flags >> HF_CPL_SHIFT) & 3; dc->iopl = (flags >> IOPL_SHIFT) & 3; dc->tb = tb; - + dc->flags = flags; + dc->is_jmp = 0; for(;;) { @@ -1473,7 +1239,9 @@ static inline int gen_intermediate_code_internal(CPUState *env, #ifdef DEBUG_DISAS if (loglevel) { fprintf(logfile, "----------------\n"); - fprintf(logfile, "IN: COPY: %s\n", lookup_symbol(pc_start)); + fprintf(logfile, "IN: COPY: %s fpu=%d\n", + lookup_symbol(pc_start), + tb->cflags & CF_TB_FP_USED ? 1 : 0); disas(logfile, pc_start, dc->pc - pc_start, 0, !dc->code32); fprintf(logfile, "\n"); } @@ -1482,7 +1250,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, if (!search_pc) { *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start; tb->size = dc->pc - pc_start; - tb->cflags = CF_CODE_COPY; + tb->cflags |= CF_CODE_COPY; return 0; } else { return -1; @@ -1526,7 +1294,7 @@ int cpu_restore_state_copy(TranslationBlock *tb, if (ret < 0) return ret; /* restore all the CPU state from the CPU context from the - signal */ + signal. The FPU context stays in the host CPU. */ env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX]; env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX]; @@ -1542,3 +1310,5 @@ int cpu_restore_state_copy(TranslationBlock *tb, env->cc_op = CC_OP_EFLAGS; return 0; } + +#endif /* USE_CODE_COPY */ -- cgit v1.2.3 From 7eee2a509a9a777aafd0c2efb14b837b83a8df9c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:17:58 +0000 Subject: CR0.MP/EM/TS support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@642 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 14 +++++++++++++- target-i386/op.c | 1 + target-i386/translate.c | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 99c6bb98c..84b202659 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -115,6 +115,9 @@ /* copy of CR0.PE (protected mode) */ #define HF_PE_SHIFT 7 #define HF_TF_SHIFT 8 /* must be same as eflags */ +#define HF_MP_SHIFT 9 /* the order must be MP, EM, TS */ +#define HF_EM_SHIFT 10 +#define HF_TS_SHIFT 11 #define HF_IOPL_SHIFT 12 /* must be same as eflags */ #define HF_VM_SHIFT 17 /* must be same as eflags */ @@ -126,9 +129,15 @@ #define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) #define HF_PE_MASK (1 << HF_PE_SHIFT) #define HF_TF_MASK (1 << HF_TF_SHIFT) +#define HF_MP_MASK (1 << HF_MP_SHIFT) +#define HF_EM_MASK (1 << HF_EM_SHIFT) +#define HF_TS_MASK (1 << HF_TS_SHIFT) #define CR0_PE_MASK (1 << 0) +#define CR0_MP_MASK (1 << 1) +#define CR0_EM_MASK (1 << 2) #define CR0_TS_MASK (1 << 3) +#define CR0_NE_MASK (1 << 5) #define CR0_WP_MASK (1 << 16) #define CR0_AM_MASK (1 << 18) #define CR0_PG_MASK (1 << 31) @@ -280,7 +289,7 @@ typedef struct CPUX86State { unsigned int fpus; unsigned int fpuc; uint8_t fptags[8]; /* 0 = valid, 1 = empty */ - CPU86_LDouble fpregs[8]; + CPU86_LDouble fpregs[8]; /* emulator internal variables */ CPU86_LDouble ft0; @@ -304,8 +313,11 @@ typedef struct CPUX86State { uint32_t sysenter_eip; /* temporary data for USE_CODE_COPY mode */ +#ifdef USE_CODE_COPY uint32_t tmp0; uint32_t saved_esp; + int native_fp_regs; /* if true, the FPU state is in the native CPU regs */ +#endif /* exception/interrupt handling */ jmp_buf jmp_env; diff --git a/target-i386/op.c b/target-i386/op.c index 1503134d1..f592b67a6 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -998,6 +998,7 @@ void OPPROTO op_movl_env_T1(void) void OPPROTO op_clts(void) { env->cr[0] &= ~CR0_TS_MASK; + env->hflags &= ~HF_TS_MASK; } /* flags handling */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 6e8d8116c..f9823a49d 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -63,6 +63,7 @@ typedef struct DisasContext { int singlestep_enabled; /* "hardware" single step enabled */ int jmp_opt; /* use direct block chaining for direct jumps */ int mem_index; /* select memory access functions */ + int flags; /* all execution flags */ struct TranslationBlock *tb; int popl_esp_hack; /* for correct popl with esp base handling */ } DisasContext; @@ -2814,6 +2815,12 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* floats */ case 0xd8 ... 0xdf: + if (s->flags & (HF_EM_MASK | HF_TS_MASK)) { + /* if CR0.EM or CR0.TS are set, generate an FPU exception */ + /* XXX: what to do if illegal op ? */ + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + break; + } modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; @@ -3225,6 +3232,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; } } +#ifdef USE_CODE_COPY + s->tb->cflags |= CF_TB_FP_USED; +#endif break; /************************/ /* string ops */ @@ -3747,6 +3757,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; break; case 0x9b: /* fwait */ + if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == + (HF_MP_MASK | HF_TS_MASK)) { + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + } break; case 0xcc: /* int3 */ gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); @@ -4140,6 +4154,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_op_clts(); + /* abort block because static cpu state changed */ + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); } break; default: @@ -4504,6 +4521,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, else dc->mem_index = 3; } + dc->flags = flags; dc->jmp_opt = !(dc->tf || env->singlestep_enabled || (flags & HF_INHIBIT_IRQ_MASK) #ifndef CONFIG_SOFTMMU -- cgit v1.2.3 From 97eb5b14dcfad346fa79e95e0e020aced9973311 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:19:55 +0000 Subject: native FPU support in code copy mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@643 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 44a0f73a5..c6f52f278 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -380,6 +380,11 @@ int cpu_exec(CPUState *env1) ) { spin_lock(&tb_lock); tb_add_jump((TranslationBlock *)(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; @@ -402,8 +407,14 @@ int cpu_exec(CPUState *env1) #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; @@ -487,6 +498,11 @@ int cpu_exec(CPUState *env1) #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); @@ -747,7 +763,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, struct ucontext *uc = puc; unsigned long pc; int trapno; - + #ifndef REG_EIP /* for glibc 2.1 */ #define REG_EIP EIP -- cgit v1.2.3 From b448f2f36c473f9ac8de4200a897268e0cf419c1 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:24:04 +0000 Subject: new physical memory access API (used by DMA accesses) - code copy FP fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@644 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/exec.c b/exec.c index 06fc0429a..b945c8271 100644 --- a/exec.c +++ b/exec.c @@ -734,6 +734,7 @@ TranslationBlock *tb_alloc(unsigned long pc) return NULL; tb = &tbs[nb_tbs++]; tb->pc = pc; + tb->cflags = 0; return tb; } @@ -812,6 +813,11 @@ void tb_link(TranslationBlock *tb) tb->jmp_first = (TranslationBlock *)((long)tb | 2); tb->jmp_next[0] = NULL; tb->jmp_next[1] = NULL; +#ifdef USE_CODE_COPY + tb->cflags &= ~CF_FP_USED; + if (tb->cflags & CF_TB_FP_USED) + tb->cflags |= CF_FP_USED; +#endif /* init original jump addresses */ if (tb->tb_next_offset[0] != 0xffff) @@ -1738,7 +1744,7 @@ int cpu_register_io_memory(int io_index, /* physical memory access (slow version, mainly for debug) */ #if defined(CONFIG_USER_ONLY) -void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, +void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, int len, int is_write) { int l, flags; @@ -1767,7 +1773,7 @@ void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, } } #else -void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, +void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, int len, int is_write) { int l, io_index; @@ -1808,10 +1814,15 @@ void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, l = 1; } } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); /* RAM case */ - ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + - (addr & ~TARGET_PAGE_MASK); + ptr = phys_ram_base + addr1; memcpy(ptr, buf, l); + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + l, 0); + /* set dirty bit */ + phys_ram_dirty[page >> TARGET_PAGE_BITS] = 1; } } else { if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && @@ -1849,8 +1860,8 @@ void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, #endif /* virtual memory access for debug */ -int cpu_memory_rw_debug(CPUState *env, - uint8_t *buf, target_ulong addr, int len, int is_write) +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write) { int l; target_ulong page, phys_addr; @@ -1864,9 +1875,8 @@ int cpu_memory_rw_debug(CPUState *env, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - cpu_physical_memory_rw(env, buf, - phys_addr + (addr & ~TARGET_PAGE_MASK), l, - is_write); + cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), + buf, l, is_write); len -= l; buf += l; addr += l; -- cgit v1.2.3 From 8b1f24b0903a8e43e035d5680aed2fa62c68b197 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:24:38 +0000 Subject: new physical memory access API (used by DMA accesses) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@645 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 17 ++++++++++++++--- gdbstub.c | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 931ea052d..247674c63 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -599,10 +599,21 @@ int cpu_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write); -void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, +void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, int len, int is_write); -int cpu_memory_rw_debug(CPUState *env, - uint8_t *buf, target_ulong addr, int len, int is_write); +static inline void cpu_physical_memory_read(target_ulong addr, uint8_t *buf, + int len) +{ + cpu_physical_memory_rw(addr, buf, len, 0); +} +static inline void cpu_physical_memory_write(target_ulong addr, const uint8_t *buf, + int len) +{ + cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1); +} + +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write); /* read dirty bit (return 0 or 1) */ static inline int cpu_physical_memory_is_dirty(target_ulong addr) diff --git a/gdbstub.c b/gdbstub.c index 4fa4af79a..29f73c9cb 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -472,7 +472,7 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) if (*p == ',') p++; len = strtoul(p, NULL, 16); - if (cpu_memory_rw_debug(env, mem_buf, addr, len, 0) != 0) + if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) memset(mem_buf, 0, len); memtohex(buf, mem_buf, len); put_packet(buf); @@ -486,7 +486,7 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) if (*p == ',') p++; hextomem(mem_buf, p, len); - if (cpu_memory_rw_debug(env, mem_buf, addr, len, 1) != 0) + if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) put_packet("ENN"); else put_packet("OK"); -- cgit v1.2.3 From 16f62432c4985fa732c0c7dd63761b06f076a48f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:25:55 +0000 Subject: DMA API change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@646 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 45 ++++++++++++++++++--------------------------- vl.h | 11 +++++------ 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index ee7cc42ec..2c85b6e7b 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -39,7 +39,6 @@ #define ldebug(...) #endif -#define MEM_REAL(addr) ((addr)+(uint32_t)(phys_ram_base)) #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) struct dma_regs { @@ -49,8 +48,8 @@ struct dma_regs { uint8_t page; uint8_t dack; uint8_t eop; - DMA_read_handler read_handler; - DMA_misc_handler misc_handler; + DMA_transfer_handler transfer_handler; + void *opaque; }; #define ADDR 0 @@ -284,40 +283,27 @@ static void channel_run (int ncont, int ichan) { struct dma_regs *r; int n; - int irq; - uint32_t addr; + target_ulong addr; /* int ai, dir; */ r = dma_controllers[ncont].regs + ichan; /* ai = r->mode & 16; */ /* dir = r->mode & 32 ? -1 : 1; */ - addr = MEM_REAL ((r->page << 16) | r->now[ADDR]); - - irq = -1; - n = r->read_handler (addr, (r->base[COUNT] << ncont) + (1 << ncont), &irq); + addr = (r->page << 16) | r->now[ADDR]; + n = r->transfer_handler (r->opaque, addr, + (r->base[COUNT] << ncont) + (1 << ncont)); r->now[COUNT] = n; - ldebug ("dma_pos %d irq %d size %d\n", - n, irq, (r->base[1] << ncont) + (1 << ncont)); - - if (-1 != irq) { - pic_set_irq (irq, 1); - } + ldebug ("dma_pos %d size %d\n", + n, (r->base[1] << ncont) + (1 << ncont)); } void DMA_run (void) { - static int in_dma; struct dma_cont *d; int icont, ichan; - if (in_dma) { - log ("attempt to re-enter dma\n"); - return; - } - - in_dma = 1; d = dma_controllers; for (icont = 0; icont < 2; icont++, d++) { @@ -330,12 +316,11 @@ void DMA_run (void) channel_run (icont, ichan); } } - in_dma = 0; } void DMA_register_channel (int nchan, - DMA_read_handler read_handler, - DMA_misc_handler misc_handler) + DMA_transfer_handler transfer_handler, + void *opaque) { struct dma_regs *r; int ichan, ncont; @@ -344,8 +329,14 @@ void DMA_register_channel (int nchan, ichan = nchan & 3; r = dma_controllers[ncont].regs + ichan; - r->read_handler = read_handler; - r->misc_handler = misc_handler; + r->transfer_handler = transfer_handler; + r->opaque = opaque; +} + +/* request the emulator to transfer a new DMA memory block ASAP */ +void DMA_schedule(int nchan) +{ + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } void DMA_init (void) diff --git a/vl.h b/vl.h index ebc809a1c..c8c22ac39 100644 --- a/vl.h +++ b/vl.h @@ -24,8 +24,9 @@ #ifndef VL_H #define VL_H +#include "cpu.h" + /* vl.c */ -struct CPUState; extern int reset_requested; extern int64_t ticks_per_sec; @@ -128,17 +129,15 @@ int AUD_get_buffer_size (void); void AUD_init (void); /* dma.c */ -typedef int (*DMA_read_handler) (uint32_t addr, int size, int *irq); -typedef int (*DMA_misc_handler) (int); - +typedef int (*DMA_transfer_handler) (void *opaque, target_ulong addr, int size); int DMA_get_channel_mode (int nchan); void DMA_hold_DREQ (int nchan); void DMA_release_DREQ (int nchan); +void DMA_schedule(int nchan); void DMA_run (void); void DMA_init (void); void DMA_register_channel (int nchan, - DMA_read_handler read_handler, - DMA_misc_handler misc_handler); + DMA_transfer_handler transfer_handler, void *opaque); /* sb16.c */ void SB16_run (void); -- cgit v1.2.3 From 03857e318e5159dfb3e574bc886df52fe22d0d8b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:26:33 +0000 Subject: native FPU support in code copy mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@647 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/exec.h b/target-i386/exec.h index c757abc5e..3f6ddf1b4 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -503,6 +503,8 @@ void helper_fstenv(uint8_t *ptr, int data32); void helper_fldenv(uint8_t *ptr, int data32); void helper_fsave(uint8_t *ptr, int data32); void helper_frstor(uint8_t *ptr, int data32); +void restore_native_fp_state(CPUState *env); +void save_native_fp_state(CPUState *env); const uint8_t parity_table[256]; const uint8_t rclw_table[32]; -- cgit v1.2.3 From 8dc75d7535974b18fb43c514f2699e714b6ce387 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:30:56 +0000 Subject: moved DMA and SB16 outside timer (may break SB16) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@648 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index 99a9fc4a1..7e729ee54 100644 --- a/vl.c +++ b/vl.c @@ -45,7 +45,6 @@ #include #include -#include "cpu.h" #include "disas.h" #include "thunk.h" @@ -2961,10 +2960,6 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, gui_refresh_pending = 1; } - /* XXX: seems dangerous to run that here. */ - DMA_run(); - SB16_run(); - if (gui_refresh_pending || timer_irq_pending) { /* just exit from the cpu to have a chance to handle timers */ cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); @@ -3090,6 +3085,11 @@ int main_loop(void *opaque) } #endif } + /* XXX: add explicit timer */ + SB16_run(); + + /* run dma transfers, if any */ + DMA_run(); /* VGA */ if (gui_refresh_pending) { -- cgit v1.2.3 From f9e92e973f4a383a73363ff795a4562c3c6a7c71 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:32:01 +0000 Subject: use physical memory access functions for DMA git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@649 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 54 ++++++++++++++++++++++++------------------------------ hw/sb16.c | 21 ++++++++++----------- 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index ec4fa7227..819e2f7b3 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -26,7 +26,6 @@ #include #include -#include "cpu.h" #include "vl.h" /********************************************************/ @@ -218,8 +217,7 @@ static void fd_reset (fdrive_t *drv) static void fdctrl_reset (int do_irq); static void fdctrl_reset_fifo (void); -static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq); -static int fdctrl_misc_handler (int duknwo); +static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size); static void fdctrl_raise_irq (uint8_t status); static uint32_t fdctrl_read_statusB (CPUState *env, uint32_t reg); @@ -310,8 +308,7 @@ void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, fdctrl.config = 0x40; /* Implicit seek, polling & FIFO enabled */ if (fdctrl.dma_chann != -1) { fdctrl.dma_en = 1; - DMA_register_channel(dma_chann, &fdctrl_transfer_handler, - &fdctrl_misc_handler); + DMA_register_channel(dma_chann, fdctrl_transfer_handler, &fdctrl); } else { fdctrl.dma_en = 0; } @@ -721,6 +718,7 @@ static void fdctrl_start_transfer (int direction) * recall us... */ DMA_hold_DREQ(fdctrl.dma_chann); + DMA_schedule(fdctrl.dma_chann); return; } } @@ -749,12 +747,13 @@ static void fdctrl_start_transfer_del (int direction) } /* handlers for DMA transfers */ -static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq) +/* XXX: the partial transfer logic seems to be broken */ +static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) { fdrive_t *cur_drv, *drv0, *drv1; - void *orig; int len; uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; + uint8_t tmpbuf[FD_SECTOR_LEN]; fdctrl_reset_irq(); if (!(fdctrl.state & FD_CTRL_BUSY)) { @@ -764,8 +763,6 @@ static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq) drv0 = &fdctrl.drives[fdctrl.bootsel]; drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; -// *irq = fdctrl.irq_lvl; - *irq = -1; if (fdctrl.data_dir == FD_DIR_SCANE || fdctrl.data_dir == FD_DIR_SCANL || fdctrl.data_dir == FD_DIR_SCANH) status2 = 0x04; @@ -779,35 +776,34 @@ static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq) fdctrl.data_len, fdctrl.cur_drv, cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv), fd_sector(cur_drv) * 512); - if (len < FD_SECTOR_LEN) { - memset(&fdctrl.fifo[FD_SECTOR_LEN - len], 0, - FD_SECTOR_LEN - len - 1); - orig = fdctrl.fifo; - } else { - orig = (void *)(addr + fdctrl.data_pos); - } if (fdctrl.data_dir != FD_DIR_WRITE) { /* READ & SCAN commands */ if (cur_drv->bs == NULL) { fdctrl_stop_transfer(0x40, 0x00, 0x00); goto transfer_error; } - - if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), orig, 1) < 0) { + if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), tmpbuf, 1) < 0) { FLOPPY_DPRINTF("Floppy: error getting sector %d\n", fd_sector(cur_drv)); /* Sure, image size is too small... */ - memset((void *)(addr + fdctrl.data_pos), 0, FD_SECTOR_LEN); + memset(tmpbuf, 0, FD_SECTOR_LEN); } if (fdctrl.data_dir == FD_DIR_READ) { + cpu_physical_memory_write(addr + fdctrl.data_pos, + tmpbuf, len); if (len < FD_SECTOR_LEN) { - memcpy((void *)(addr + fdctrl.data_pos), - fdctrl.fifo, FD_SECTOR_LEN); + memcpy(&fdctrl.fifo[0], tmpbuf + len, FD_SECTOR_LEN - len); + memset(&fdctrl.fifo[FD_SECTOR_LEN - len], 0, len); } } else { int ret; - ret = memcmp((void *)(addr + fdctrl.data_pos), - fdctrl.fifo, FD_SECTOR_LEN); + /* XXX: what to do if not enough data ? */ + cpu_physical_memory_read(addr + fdctrl.data_pos, + fdctrl.fifo, len); + if (len < FD_SECTOR_LEN) { + memset(&fdctrl.fifo[len], 0, FD_SECTOR_LEN - len); + } + ret = memcmp(tmpbuf, fdctrl.fifo, FD_SECTOR_LEN); if (ret == 0) { status2 = 0x08; goto end_transfer; @@ -820,8 +816,12 @@ static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq) } } else { /* WRITE commands */ + cpu_physical_memory_read(addr + fdctrl.data_pos, tmpbuf, len); + if (len < FD_SECTOR_LEN) { + memset(tmpbuf + len, 0, FD_SECTOR_LEN - len); + } if (cur_drv->bs == NULL || - bdrv_write(cur_drv->bs, fd_sector(cur_drv), orig, 1) < 0) { + bdrv_write(cur_drv->bs, fd_sector(cur_drv), tmpbuf, 1) < 0) { FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(0x60, 0x00, 0x00); goto transfer_error; @@ -871,12 +871,6 @@ transfer_error: return fdctrl.data_pos; } -/* Unused... */ -static int fdctrl_misc_handler (int duknwo) -{ - return -1; -} - /* Data register : 0x05 */ static uint32_t fdctrl_read_data (CPUState *env, uint32_t reg) { diff --git a/hw/sb16.c b/hw/sb16.c index b04110d9e..9fbf085f0 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -25,6 +25,7 @@ #include #include +#include "cpu.h" #include "vl.h" #define MIN(a, b) ((a)>(b)?(b):(a)) @@ -569,6 +570,7 @@ void SB16_run (void) static int write_audio (uint32_t addr, int len, int size) { int temp, net; + uint8_t tmpbuf[4096]; temp = size; @@ -582,8 +584,10 @@ static int write_audio (uint32_t addr, int len, int size) left_till_end = len - dsp.dma_pos; to_copy = MIN (temp, left_till_end); - - copied = AUD_write ((void *) (addr + dsp.dma_pos), to_copy); + if (to_copy > sizeof(tmpbuf)) + to_copy = sizeof(tmpbuf); + cpu_physical_memory_read(addr + dsp.dma_pos, tmpbuf, to_copy); + copied = AUD_write (tmpbuf, to_copy); temp -= copied; dsp.dma_pos += copied; @@ -601,7 +605,7 @@ static int write_audio (uint32_t addr, int len, int size) return net; } -static int SB_read_DMA (uint32_t addr, int size, int *_irq) +static int SB_read_DMA (void *opaque, target_ulong addr, int size) { int free, till, copy, written; @@ -644,7 +648,7 @@ static int SB_read_DMA (uint32_t addr, int size, int *_irq) mixer.regs[0x82] |= mixer.regs[0x80]; if (0 == noirq) { ldebug ("request irq\n"); - *_irq = sb.irq; + pic_set_irq(sb.irq, 1); } if (0 == dsp.dma_auto) { @@ -663,11 +667,6 @@ static int SB_read_DMA (uint32_t addr, int size, int *_irq) return dsp.dma_pos; } -static int dma_misc_handler (int moo) -{ - return -1; -} - static int magic_of_irq (int irq) { switch (irq) { @@ -731,6 +730,6 @@ void SB16_init (void) register_ioport_read (sb.port + 0x5, 1, mixer_read, 1); register_ioport_write (sb.port + 0x5, 1, mixer_write_datab, 1); - DMA_register_channel (sb.hdma, SB_read_DMA, dma_misc_handler); - DMA_register_channel (sb.dma, SB_read_DMA, dma_misc_handler); + DMA_register_channel (sb.hdma, SB_read_DMA, NULL); + DMA_register_channel (sb.dma, SB_read_DMA, NULL); } -- cgit v1.2.3 From bf0880614547dfeaed77cde6f37f081eec3b626e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:33:36 +0000 Subject: native FPU support in code copy mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@650 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exec-all.h b/exec-all.h index a14efa94e..3c79eca91 100644 --- a/exec-all.h +++ b/exec-all.h @@ -152,7 +152,9 @@ typedef struct TranslationBlock { uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ uint16_t cflags; /* compile flags */ -#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */ +#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */ +#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */ +#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */ uint8_t *tc_ptr; /* pointer to the translated code */ struct TranslationBlock *hash_next; /* next matching tb for virtual address */ -- cgit v1.2.3 From 6b2b6112f872f656ba4c9ef22ff1576e87042bcc Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:34:07 +0000 Subject: more FPU context save tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@651 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index b0c2af855..650a5a96a 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -612,30 +612,21 @@ void test_fbcd(double a) a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); } -#define TEST_ENV(env, prefix)\ +#define TEST_ENV(env, save, restore)\ {\ memset((env), 0xaa, sizeof(*(env)));\ - asm("fld1\n"\ - prefix "fnstenv %1\n"\ - prefix "fldenv %1\n"\ - : "=t" (res) : "m" (*(env)));\ - printf("res=%f\n", res);\ + for(i=0;i<5;i++)\ + asm volatile ("fldl %0" : : "m" (dtab[i]));\ + asm(save " %0\n" : : "m" (*(env)));\ + asm(restore " %0\n": : "m" (*(env)));\ + for(i=0;i<5;i++)\ + asm volatile ("fstpl %0" : "=m" (rtab[i]));\ + for(i=0;i<5;i++)\ + printf("res[%d]=%f\n", i, rtab[i]);\ printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ (env)->fpuc,\ (env)->fpus & 0xff00,\ (env)->fptag);\ - memset((env), 0xaa, sizeof(*(env)));\ - asm("fld1\n"\ - prefix "fnsave %1\n"\ - prefix "frstor %1\n"\ - : "=t" (res) : "m" (*(env)));\ - printf("res=%f\n", res);\ - printf("fpuc=%04x fpus=%04x fptag=%04x\n",\ - (env)->fpuc,\ - (env)->fpus & 0xff00,\ - (env)->fptag);\ - printf("ST(0) = %Lf\n",\ - (env)->fpregs[0]);\ } void test_fenv(void) @@ -657,10 +648,17 @@ void test_fenv(void) uint16_t ignored[4]; long double fpregs[8]; } float_env16; - double res; + double dtab[8]; + double rtab[8]; + int i; + + for(i=0;i<8;i++) + dtab[i] = i + 1; - TEST_ENV(&float_env16, "data16 "); - TEST_ENV(&float_env32, ""); + TEST_ENV(&float_env16, "data16 fnstenv", "data16 fldenv"); + TEST_ENV(&float_env16, "data16 fnsave", "data16 frstor"); + TEST_ENV(&float_env32, "fnstenv", "fldenv"); + TEST_ENV(&float_env32, "fnsave", "frstor"); } -- cgit v1.2.3 From a735aa3139c5b9785eac09dcf6384d89c8d8c445 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Feb 2004 23:54:25 +0000 Subject: added precompiled linux boot sector git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@652 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 ++- Makefile.target | 3 --- linux_boot.S | 32 -------------------------------- pc-bios/Makefile | 24 ++++++++++++++++++++++++ pc-bios/linux_boot.S | 29 +++++++++++++++++++++++++++++ pc-bios/linux_boot.bin | Bin 0 -> 512 bytes vl.c | 15 +++++++++++---- 7 files changed, 66 insertions(+), 40 deletions(-) delete mode 100644 linux_boot.S create mode 100644 pc-bios/Makefile create mode 100644 pc-bios/linux_boot.S create mode 100644 pc-bios/linux_boot.bin diff --git a/Makefile b/Makefile index 4c49bd492..11f791550 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,8 @@ install: all mkdir -p $(prefix)/bin install -m 755 -s $(TOOLS) $(prefix)/bin mkdir -p $(sharedir) - install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin $(sharedir) + install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ + pc-bios/linux_boot.bin $(sharedir) mkdir -p $(mandir)/man1 install qemu.1 $(mandir)/man1 for d in $(TARGET_DIRS); do \ diff --git a/Makefile.target b/Makefile.target index 3f5a1ba85..08d8dfc18 100644 --- a/Makefile.target +++ b/Makefile.target @@ -206,9 +206,6 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o osdep.o -ifeq ($(TARGET_ARCH), i386) -VL_OBJS+=linux_boot.o -endif ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= hw.o endif diff --git a/linux_boot.S b/linux_boot.S deleted file mode 100644 index 353052c97..000000000 --- a/linux_boot.S +++ /dev/null @@ -1,32 +0,0 @@ -/* - * QEMU Boot sector to launch a preloaded Linux kernel - * Copyright (c) 2004 Fabrice Bellard - */ - -#define LOAD_SEG 0x9000 - -.code16 -.text - .globl linux_boot_start - .globl linux_boot_end - -linux_boot_start: - cli - cld - mov $LOAD_SEG, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - mov $0x8ffe, %sp - ljmp $LOAD_SEG + 0x20, $0 - -1: - .fill 510 - (1b - linux_boot_start), 1, 0 - - /* boot sector signature */ - .byte 0x55 - .byte 0xaa - -linux_boot_end: diff --git a/pc-bios/Makefile b/pc-bios/Makefile new file mode 100644 index 000000000..7ae0ff02a --- /dev/null +++ b/pc-bios/Makefile @@ -0,0 +1,24 @@ +# +# NOTE: only compilable with x86 cross compile tools +# +include ../config-host.mak + +DEFINES= + +TARGETS= +ifeq ($(ARCH),i386) +TARGETS+=linux_boot.bin +endif + +all: $(TARGETS) + +linux_boot.bin: linux_boot.o + ld --oformat binary -Ttext 0 -o $@ $< + chmod a-x $@ + +%.o: %.S + $(CC) $(DEFINES) -c -o $@ $< + +clean: + rm -f $(TARGETS) *.o *~ + diff --git a/pc-bios/linux_boot.S b/pc-bios/linux_boot.S new file mode 100644 index 000000000..22fcd4be8 --- /dev/null +++ b/pc-bios/linux_boot.S @@ -0,0 +1,29 @@ +/* + * QEMU Boot sector to launch a preloaded Linux kernel + * Copyright (c) 2004 Fabrice Bellard + */ + +#define LOAD_SEG 0x9000 + +.code16 +.text + .globl _start + +_start: + cli + cld + mov $LOAD_SEG, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + mov $0x8ffe, %sp + ljmp $LOAD_SEG + 0x20, $0 + +1: + .fill 510 - (1b - _start), 1, 0 + + /* boot sector signature */ + .byte 0x55 + .byte 0xaa diff --git a/pc-bios/linux_boot.bin b/pc-bios/linux_boot.bin new file mode 100644 index 000000000..80f7b5fee Binary files /dev/null and b/pc-bios/linux_boot.bin differ diff --git a/vl.c b/vl.c index 7e729ee54..e2e139303 100644 --- a/vl.c +++ b/vl.c @@ -53,6 +53,7 @@ #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define BIOS_FILENAME "bios.bin" #define VGABIOS_FILENAME "vgabios.bin" +#define LINUX_BOOT_FILENAME "linux_boot.bin" //#define DEBUG_UNUSED_IOPORT @@ -3463,15 +3464,21 @@ int main(int argc, char **argv) bochs_bios_init(); if (linux_boot) { - extern uint8_t linux_boot_start; - extern uint8_t linux_boot_end; + uint8_t bootsect[512]; if (bs_table[0] == NULL) { fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); exit(1); } - bdrv_set_boot_sector(bs_table[0], &linux_boot_start, - &linux_boot_end - &linux_boot_start); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); + ret = load_image(buf, bootsect); + if (ret != sizeof(bootsect)) { + fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", + buf); + exit(1); + } + + bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); /* now we can load the kernel */ ret = load_kernel(kernel_filename, -- cgit v1.2.3 From 00af2b26809d9cfb20af348ea7df255780348dd2 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 26 Feb 2004 00:20:56 +0000 Subject: added cow.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@653 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 2 ++ cow.h | 13 +++++++++++++ qemu-mkcow.c | 22 +++++++++++++++------- vl.h | 13 ------------- 4 files changed, 30 insertions(+), 20 deletions(-) create mode 100644 cow.h diff --git a/block.c b/block.c index 6a1701a5b..29f316e00 100644 --- a/block.c +++ b/block.c @@ -45,6 +45,8 @@ #define NO_THUNK_TYPE_SIZE #include "thunk.h" +#include "cow.h" + struct BlockDriverState { int fd; /* if -1, only COW mappings */ int64_t total_sectors; diff --git a/cow.h b/cow.h new file mode 100644 index 000000000..5b5f497ed --- /dev/null +++ b/cow.h @@ -0,0 +1,13 @@ +/* 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; +}; + diff --git a/qemu-mkcow.c b/qemu-mkcow.c index 2cc6332e7..7968bf972 100644 --- a/qemu-mkcow.c +++ b/qemu-mkcow.c @@ -41,7 +41,7 @@ #include #include -#include "vl.h" +#include "cow.h" #include "bswap.h" @@ -101,13 +101,14 @@ void help(void) int main(int argc, char **argv) { const char *image_filename, *cow_filename; - int cow_fd, c, nb_args; + int cow_fd, c, nb_args, simple_image; int64_t image_size; image_filename = NULL; image_size = 0; + simple_image = 0; for(;;) { - c = getopt(argc, argv, "hf:"); + c = getopt(argc, argv, "hf:s"); if (c == -1) break; switch(c) { @@ -117,6 +118,9 @@ int main(int argc, char **argv) case 'f': image_filename = optarg; break; + case 's': + simple_image = 1; + break; } } if (!image_filename) @@ -131,12 +135,16 @@ int main(int argc, char **argv) image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024; } - cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644); + cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); if (!cow_fd < 0) return -1; - if (cow_create(cow_fd, image_filename, image_size) < 0) { - fprintf(stderr, "%s: error while formating\n", cow_filename); - exit(1); + if (simple_image) { + ftruncate64(cow_fd, image_size * 512); + } else { + if (cow_create(cow_fd, image_filename, image_size) < 0) { + fprintf(stderr, "%s: error while formating\n", cow_filename); + exit(1); + } } close(cow_fd); return 0; diff --git a/vl.h b/vl.h index c8c22ac39..35962d198 100644 --- a/vl.h +++ b/vl.h @@ -58,19 +58,6 @@ void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); -/* 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; -}; - /* vga.c */ #define VGA_RAM_SIZE (4096 * 1024) -- cgit v1.2.3 From 73bdea1951ce3894826907a6ce0cf68ad5e4dd0c Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 4 Mar 2004 22:50:52 +0000 Subject: 2.6 kernel compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@654 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 5 +++++ tests/test-i386.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index c98262c2d..c9c9d7e36 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -34,9 +34,14 @@ #ifdef USE_CODE_COPY #include #include +#include _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) +#define modify_ldt_ldt_s user_desc #endif +#endif /* USE_CODE_COPY */ CPUX86State *cpu_x86_init(void) { diff --git a/tests/test-i386.c b/tests/test-i386.c index 650a5a96a..ce1213a7d 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -884,9 +884,14 @@ void test_xchg(void) #include #include +#include _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) +#define modify_ldt_ldt_s user_desc +#endif + uint8_t seg_data1[4096]; uint8_t seg_data2[4096]; -- cgit v1.2.3 From 38ca2abc2eb0fc8edd067420b3fcfa10ffa0054b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 13 Mar 2004 18:32:13 +0000 Subject: m68k compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@655 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 9 ++++----- configure | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Makefile.target b/Makefile.target index 08d8dfc18..862961ed4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -27,15 +27,14 @@ PROGS+=$(QEMU_SYSTEM) ifndef CONFIG_SOFTMMU CONFIG_STATIC=y endif -endif - -ifeq ($(ARCH), ppc) +else +# the system emulator using soft mmu is portable ifdef CONFIG_SOFTMMU PROGS+=$(QEMU_SYSTEM) endif -endif +endif # ARCH != i386 -endif +endif # TARGET_ARCH = i386 ifeq ($(TARGET_ARCH), ppc) diff --git a/configure b/configure index 0caae4277..be8c8bcbc 100755 --- a/configure +++ b/configure @@ -278,8 +278,8 @@ 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" >> $TMPH + echo "ARCH=m68k" >> $config_mak + echo "#define HOST_M68K 1" >> $config_h else echo "Unsupported CPU" exit 1 -- cgit v1.2.3 From 80cabfad16384ca47f783a7c494bd1c3c6e3c4bc Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 12:20:30 +0000 Subject: separated more devices from emulator git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@656 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 +- hw/i8254.c | 297 ++++++ hw/i8259.c | 388 ++++++++ hw/mc146818rtc.c | 203 ++++ hw/ne2000.c | 465 ++++++++++ hw/pc.c | 368 ++++++++ hw/pckbd.c | 672 ++++++++++++++ hw/serial.c | 281 ++++++ vl.c | 2721 ++++-------------------------------------------------- vl.h | 90 +- 10 files changed, 2936 insertions(+), 2554 deletions(-) create mode 100644 hw/i8254.c create mode 100644 hw/i8259.c create mode 100644 hw/mc146818rtc.c create mode 100644 hw/ne2000.c create mode 100644 hw/pc.c create mode 100644 hw/pckbd.c create mode 100644 hw/serial.c diff --git a/Makefile.target b/Makefile.target index 862961ed4..1b837c782 100644 --- a/Makefile.target +++ b/Makefile.target @@ -1,7 +1,7 @@ include config.mak TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) -VPATH=$(SRC_PATH):$(TARGET_PATH) +VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw CFLAGS=-Wall -O2 -g LDFLAGS=-g LIBS= @@ -204,7 +204,8 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o osdep.o +VL_OBJS=vl.o osdep.o block.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ + fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= hw.o endif diff --git a/hw/i8254.c b/hw/i8254.c new file mode 100644 index 000000000..7dc5f3c25 --- /dev/null +++ b/hw/i8254.c @@ -0,0 +1,297 @@ +/* + * QEMU 8253/8254 interval timer emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +#define RW_STATE_LSB 0 +#define RW_STATE_MSB 1 +#define RW_STATE_WORD0 2 +#define RW_STATE_WORD1 3 +#define RW_STATE_LATCHED_WORD0 4 +#define RW_STATE_LATCHED_WORD1 5 + +PITChannelState pit_channels[3]; + +static int pit_get_count(PITChannelState *s) +{ + uint64_t d; + int counter; + + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); + switch(s->mode) { + case 0: + case 1: + case 4: + case 5: + counter = (s->count - d) & 0xffff; + break; + case 3: + /* XXX: may be incorrect for odd counts */ + counter = s->count - ((2 * d) % s->count); + break; + default: + counter = s->count - (d % s->count); + break; + } + return counter; +} + +/* get pit output bit */ +int pit_get_out(PITChannelState *s) +{ + uint64_t d; + int out; + + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); + switch(s->mode) { + default: + case 0: + out = (d >= s->count); + break; + case 1: + out = (d < s->count); + break; + case 2: + if ((d % s->count) == 0 && d != 0) + out = 1; + else + out = 0; + break; + case 3: + out = (d % s->count) < ((s->count + 1) >> 1); + break; + case 4: + case 5: + out = (d == s->count); + break; + } + return out; +} + +/* get the number of 0 to 1 transitions we had since we call this + function */ +/* XXX: maybe better to use ticks precision to avoid getting edges + twice if checks are done at very small intervals */ +int pit_get_out_edges(PITChannelState *s) +{ + uint64_t d1, d2; + int64_t ticks; + int ret, v; + + ticks = cpu_get_ticks(); + d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, + PIT_FREQ, ticks_per_sec); + d2 = muldiv64(ticks - s->count_load_time, + PIT_FREQ, ticks_per_sec); + s->count_last_edge_check_time = ticks; + switch(s->mode) { + default: + case 0: + if (d1 < s->count && d2 >= s->count) + ret = 1; + else + ret = 0; + break; + case 1: + ret = 0; + break; + case 2: + d1 /= s->count; + d2 /= s->count; + ret = d2 - d1; + break; + case 3: + v = s->count - ((s->count + 1) >> 1); + d1 = (d1 + v) / s->count; + d2 = (d2 + v) / s->count; + ret = d2 - d1; + break; + case 4: + case 5: + if (d1 < s->count && d2 >= s->count) + ret = 1; + else + ret = 0; + break; + } + return ret; +} + +/* val must be 0 or 1 */ +void pit_set_gate(PITChannelState *s, int val) +{ + switch(s->mode) { + default: + case 0: + case 4: + /* XXX: just disable/enable counting */ + break; + case 1: + case 5: + if (s->gate < val) { + /* restart counting on rising edge */ + s->count_load_time = cpu_get_ticks(); + s->count_last_edge_check_time = s->count_load_time; + } + break; + case 2: + case 3: + if (s->gate < val) { + /* restart counting on rising edge */ + s->count_load_time = cpu_get_ticks(); + s->count_last_edge_check_time = s->count_load_time; + } + /* XXX: disable/enable counting */ + break; + } + s->gate = val; +} + +static inline void pit_load_count(PITChannelState *s, int val) +{ + if (val == 0) + val = 0x10000; + s->count_load_time = cpu_get_ticks(); + s->count_last_edge_check_time = s->count_load_time; + s->count = val; + if (s == &pit_channels[0] && val <= pit_min_timer_count) { + fprintf(stderr, + "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", + PIT_FREQ / pit_min_timer_count); + } +} + +void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +{ + int channel, access; + PITChannelState *s; + + addr &= 3; + if (addr == 3) { + channel = val >> 6; + if (channel == 3) + return; + s = &pit_channels[channel]; + access = (val >> 4) & 3; + switch(access) { + case 0: + s->latched_count = pit_get_count(s); + s->rw_state = RW_STATE_LATCHED_WORD0; + break; + default: + s->mode = (val >> 1) & 7; + s->bcd = val & 1; + s->rw_state = access - 1 + RW_STATE_LSB; + break; + } + } else { + s = &pit_channels[addr]; + switch(s->rw_state) { + case RW_STATE_LSB: + pit_load_count(s, val); + break; + case RW_STATE_MSB: + pit_load_count(s, val << 8); + break; + case RW_STATE_WORD0: + case RW_STATE_WORD1: + if (s->rw_state & 1) { + pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); + } else { + s->latched_count = val; + } + s->rw_state ^= 1; + break; + } + } +} + +uint32_t pit_ioport_read(CPUState *env, uint32_t addr) +{ + int ret, count; + PITChannelState *s; + + addr &= 3; + s = &pit_channels[addr]; + switch(s->rw_state) { + case RW_STATE_LSB: + case RW_STATE_MSB: + case RW_STATE_WORD0: + case RW_STATE_WORD1: + count = pit_get_count(s); + if (s->rw_state & 1) + ret = (count >> 8) & 0xff; + else + ret = count & 0xff; + if (s->rw_state & 2) + s->rw_state ^= 1; + break; + default: + case RW_STATE_LATCHED_WORD0: + case RW_STATE_LATCHED_WORD1: + if (s->rw_state & 1) + ret = s->latched_count >> 8; + else + ret = s->latched_count & 0xff; + s->rw_state ^= 1; + break; + } + return ret; +} + +void pit_init(void) +{ + PITChannelState *s; + int i; + + for(i = 0;i < 3; i++) { + s = &pit_channels[i]; + s->mode = 3; + s->gate = (i != 2); + pit_load_count(s, 0); + } + + register_ioport_write(0x40, 4, pit_ioport_write, 1); + register_ioport_read(0x40, 3, pit_ioport_read, 1); +} + diff --git a/hw/i8259.c b/hw/i8259.c new file mode 100644 index 000000000..08c7be394 --- /dev/null +++ b/hw/i8259.c @@ -0,0 +1,388 @@ +/* + * QEMU 8259 interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +/* debug PIC */ +//#define DEBUG_PIC + +typedef struct PicState { + uint8_t last_irr; /* edge detection */ + uint8_t irr; /* interrupt request register */ + uint8_t imr; /* interrupt mask register */ + uint8_t isr; /* interrupt service register */ + uint8_t priority_add; /* highest irq priority */ + uint8_t irq_base; + uint8_t read_reg_select; + uint8_t poll; + uint8_t special_mask; + uint8_t init_state; + uint8_t auto_eoi; + uint8_t rotate_on_auto_eoi; + uint8_t special_fully_nested_mode; + uint8_t init4; /* true if 4 byte init */ +} PicState; + +/* 0 is master pic, 1 is slave pic */ +PicState pics[2]; +int pic_irq_requested; + +/* set irq level. If an edge is detected, then the IRR is set to 1 */ +static inline void pic_set_irq1(PicState *s, int irq, int level) +{ + int mask; + mask = 1 << irq; + if (level) { + if ((s->last_irr & mask) == 0) + s->irr |= mask; + s->last_irr |= mask; + } else { + s->last_irr &= ~mask; + } +} + +/* return the highest priority found in mask (highest = smallest + number). Return 8 if no irq */ +static inline int get_priority(PicState *s, int mask) +{ + int priority; + if (mask == 0) + return 8; + priority = 0; + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) + priority++; + return priority; +} + +/* return the pic wanted interrupt. return -1 if none */ +static int pic_get_irq(PicState *s) +{ + int mask, cur_priority, priority; + + mask = s->irr & ~s->imr; + priority = get_priority(s, mask); + if (priority == 8) + return -1; + /* compute current priority. If special fully nested mode on the + master, the IRQ coming from the slave is not taken into account + for the priority computation. */ + mask = s->isr; + if (s->special_fully_nested_mode && s == &pics[0]) + mask &= ~(1 << 2); + cur_priority = get_priority(s, mask); + if (priority < cur_priority) { + /* higher priority found: an irq should be generated */ + return (priority + s->priority_add) & 7; + } else { + return -1; + } +} + +/* raise irq to CPU if necessary. must be called every time the active + irq may change */ +void pic_update_irq(void) +{ + int irq2, irq; + + /* first look at slave pic */ + irq2 = pic_get_irq(&pics[1]); + if (irq2 >= 0) { + /* if irq request by slave pic, signal master PIC */ + pic_set_irq1(&pics[0], 2, 1); + pic_set_irq1(&pics[0], 2, 0); + } + /* look at requested irq */ + irq = pic_get_irq(&pics[0]); + if (irq >= 0) { + if (irq == 2) { + /* from slave pic */ + pic_irq_requested = 8 + irq2; + } else { + /* from master pic */ + pic_irq_requested = irq; + } +#if defined(DEBUG_PIC) + { + int i; + for(i = 0; i < 2; i++) { + printf("pic%d: imr=%x irr=%x padd=%d\n", + i, pics[i].imr, pics[i].irr, pics[i].priority_add); + + } + } + printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); +#endif + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } +} + +#ifdef DEBUG_IRQ_LATENCY +int64_t irq_time[16]; +int64_t cpu_get_ticks(void); +#endif +#if defined(DEBUG_PIC) +int irq_level[16]; +#endif + +void pic_set_irq(int irq, int level) +{ +#if defined(DEBUG_PIC) + if (level != irq_level[irq]) { + printf("pic_set_irq: irq=%d level=%d\n", irq, level); + irq_level[irq] = level; + } +#endif +#ifdef DEBUG_IRQ_LATENCY + if (level) { + irq_time[irq] = cpu_get_ticks(); + } +#endif + pic_set_irq1(&pics[irq >> 3], irq & 7, level); + pic_update_irq(); +} + +/* acknowledge interrupt 'irq' */ +static inline void pic_intack(PicState *s, int irq) +{ + if (s->auto_eoi) { + if (s->rotate_on_auto_eoi) + s->priority_add = (irq + 1) & 7; + } else { + s->isr |= (1 << irq); + } + s->irr &= ~(1 << irq); +} + +int cpu_x86_get_pic_interrupt(CPUState *env) +{ + int irq, irq2, intno; + + /* signal the pic that the irq was acked by the CPU */ + irq = pic_irq_requested; +#ifdef DEBUG_IRQ_LATENCY + printf("IRQ%d latency=%0.3fus\n", + irq, + (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); +#endif +#if defined(DEBUG_PIC) + printf("pic_interrupt: irq=%d\n", irq); +#endif + + if (irq >= 8) { + irq2 = irq & 7; + pic_intack(&pics[1], irq2); + irq = 2; + intno = pics[1].irq_base + irq2; + } else { + intno = pics[0].irq_base + irq; + } + pic_intack(&pics[0], irq); + return intno; +} + +void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +{ + PicState *s; + int priority, cmd, irq; + +#ifdef DEBUG_PIC + printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); +#endif + s = &pics[addr >> 7]; + addr &= 1; + if (addr == 0) { + if (val & 0x10) { + /* init */ + memset(s, 0, sizeof(PicState)); + s->init_state = 1; + s->init4 = val & 1; + if (val & 0x02) + hw_error("single mode not supported"); + if (val & 0x08) + hw_error("level sensitive irq not supported"); + } else if (val & 0x08) { + if (val & 0x04) + s->poll = 1; + if (val & 0x02) + s->read_reg_select = val & 1; + if (val & 0x40) + s->special_mask = (val >> 5) & 1; + } else { + cmd = val >> 5; + switch(cmd) { + case 0: + case 4: + s->rotate_on_auto_eoi = cmd >> 2; + break; + case 1: /* end of interrupt */ + case 5: + priority = get_priority(s, s->isr); + if (priority != 8) { + irq = (priority + s->priority_add) & 7; + s->isr &= ~(1 << irq); + if (cmd == 5) + s->priority_add = (irq + 1) & 7; + pic_update_irq(); + } + break; + case 3: + irq = val & 7; + s->isr &= ~(1 << irq); + pic_update_irq(); + break; + case 6: + s->priority_add = (val + 1) & 7; + pic_update_irq(); + break; + case 7: + irq = val & 7; + s->isr &= ~(1 << irq); + s->priority_add = (irq + 1) & 7; + pic_update_irq(); + break; + default: + /* no operation */ + break; + } + } + } else { + switch(s->init_state) { + case 0: + /* normal mode */ + s->imr = val; + pic_update_irq(); + break; + case 1: + s->irq_base = val & 0xf8; + s->init_state = 2; + break; + case 2: + if (s->init4) { + s->init_state = 3; + } else { + s->init_state = 0; + } + break; + case 3: + s->special_fully_nested_mode = (val >> 4) & 1; + s->auto_eoi = (val >> 1) & 1; + s->init_state = 0; + break; + } + } +} + +static uint32_t pic_poll_read (PicState *s, uint32_t addr1) +{ + int ret; + + ret = pic_get_irq(s); + if (ret >= 0) { + if (addr1 >> 7) { + pics[0].isr &= ~(1 << 2); + pics[0].irr &= ~(1 << 2); + } + s->irr &= ~(1 << ret); + s->isr &= ~(1 << ret); + if (addr1 >> 7 || ret != 2) + pic_update_irq(); + } else { + ret = 0x07; + pic_update_irq(); + } + + return ret; +} + +uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) +{ + PicState *s; + unsigned int addr; + int ret; + + addr = addr1; + s = &pics[addr >> 7]; + addr &= 1; + if (s->poll) { + ret = pic_poll_read(s, addr1); + s->poll = 0; + } else { + if (addr == 0) { + if (s->read_reg_select) + ret = s->isr; + else + ret = s->irr; + } else { + ret = s->imr; + } + } +#ifdef DEBUG_PIC + printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); +#endif + return ret; +} + +/* memory mapped interrupt status */ +uint32_t pic_intack_read(CPUState *env) +{ + int ret; + + ret = pic_poll_read(&pics[0], 0x00); + if (ret == 2) + ret = pic_poll_read(&pics[1], 0x80) + 8; + /* Prepare for ISR read */ + pics[0].read_reg_select = 1; + + return ret; +} + +void pic_init(void) +{ +#if defined (TARGET_I386) || defined (TARGET_PPC) + register_ioport_write(0x20, 2, pic_ioport_write, 1); + register_ioport_read(0x20, 2, pic_ioport_read, 1); + register_ioport_write(0xa0, 2, pic_ioport_write, 1); + register_ioport_read(0xa0, 2, pic_ioport_read, 1); +#endif +} + diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c new file mode 100644 index 000000000..cab76cfab --- /dev/null +++ b/hw/mc146818rtc.c @@ -0,0 +1,203 @@ +/* + * QEMU MC146818 RTC emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +//#define DEBUG_CMOS + +#define RTC_SECONDS 0 +#define RTC_SECONDS_ALARM 1 +#define RTC_MINUTES 2 +#define RTC_MINUTES_ALARM 3 +#define RTC_HOURS 4 +#define RTC_HOURS_ALARM 5 +#define RTC_ALARM_DONT_CARE 0xC0 + +#define RTC_DAY_OF_WEEK 6 +#define RTC_DAY_OF_MONTH 7 +#define RTC_MONTH 8 +#define RTC_YEAR 9 + +#define RTC_REG_A 10 +#define RTC_REG_B 11 +#define RTC_REG_C 12 +#define RTC_REG_D 13 + +/* PC cmos mappings */ +#define REG_IBM_CENTURY_BYTE 0x32 +#define REG_IBM_PS2_CENTURY_BYTE 0x37 + +RTCState rtc_state; + +static void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) +{ + RTCState *s = &rtc_state; + + if ((addr & 1) == 0) { + s->cmos_index = data & 0x7f; + } else { +#ifdef DEBUG_CMOS + printf("cmos: write index=0x%02x val=0x%02x\n", + s->cmos_index, data); +#endif + switch(addr) { + case RTC_SECONDS_ALARM: + case RTC_MINUTES_ALARM: + case RTC_HOURS_ALARM: + /* XXX: not supported */ + s->cmos_data[s->cmos_index] = data; + break; + case RTC_SECONDS: + case RTC_MINUTES: + case RTC_HOURS: + case RTC_DAY_OF_WEEK: + case RTC_DAY_OF_MONTH: + case RTC_MONTH: + case RTC_YEAR: + s->cmos_data[s->cmos_index] = data; + break; + case RTC_REG_A: + case RTC_REG_B: + s->cmos_data[s->cmos_index] = data; + break; + case RTC_REG_C: + case RTC_REG_D: + /* cannot write to them */ + break; + default: + s->cmos_data[s->cmos_index] = data; + break; + } + } +} + +static inline int to_bcd(int a) +{ + return ((a / 10) << 4) | (a % 10); +} + +static void cmos_update_time(RTCState *s) +{ + struct tm *tm; + time_t ti; + + ti = time(NULL); + tm = gmtime(&ti); + s->cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); + s->cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); + s->cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); + s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); + s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); + s->cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); + s->cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); + s->cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); + s->cmos_data[REG_IBM_PS2_CENTURY_BYTE] = s->cmos_data[REG_IBM_CENTURY_BYTE]; +} + +static uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) +{ + RTCState *s = &rtc_state; + int ret; + if ((addr & 1) == 0) { + return 0xff; + } else { + switch(s->cmos_index) { + case RTC_SECONDS: + case RTC_MINUTES: + case RTC_HOURS: + case RTC_DAY_OF_WEEK: + case RTC_DAY_OF_MONTH: + case RTC_MONTH: + case RTC_YEAR: + case REG_IBM_CENTURY_BYTE: + case REG_IBM_PS2_CENTURY_BYTE: + cmos_update_time(s); + ret = s->cmos_data[s->cmos_index]; + break; + case RTC_REG_A: + ret = s->cmos_data[s->cmos_index]; + /* toggle update-in-progress bit for Linux (same hack as + plex86) */ + s->cmos_data[RTC_REG_A] ^= 0x80; + break; + case RTC_REG_C: + ret = s->cmos_data[s->cmos_index]; + pic_set_irq(s->irq, 0); + s->cmos_data[RTC_REG_C] = 0x00; + break; + default: + ret = s->cmos_data[s->cmos_index]; + break; + } +#ifdef DEBUG_CMOS + printf("cmos: read index=0x%02x val=0x%02x\n", + s->cmos_index, ret); +#endif + return ret; + } +} + +void rtc_timer(void) +{ + RTCState *s = &rtc_state; + if (s->cmos_data[RTC_REG_B] & 0x50) { + pic_set_irq(s->irq, 1); + } +} + +void rtc_init(int base, int irq) +{ + RTCState *s = &rtc_state; + + cmos_update_time(s); + + s->irq = irq; + s->cmos_data[RTC_REG_A] = 0x26; + s->cmos_data[RTC_REG_B] = 0x02; + s->cmos_data[RTC_REG_C] = 0x00; + s->cmos_data[RTC_REG_D] = 0x80; + + register_ioport_write(base, 2, cmos_ioport_write, 1); + register_ioport_read(base, 2, cmos_ioport_read, 1); +} + diff --git a/hw/ne2000.c b/hw/ne2000.c new file mode 100644 index 000000000..0b35495f9 --- /dev/null +++ b/hw/ne2000.c @@ -0,0 +1,465 @@ +/* + * QEMU NE2000 emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +/* debug NE2000 card */ +//#define DEBUG_NE2000 + +/***********************************************************/ +/* ne2000 emulation */ + +#define E8390_CMD 0x00 /* The command register (for all pages) */ +/* Page 0 register offsets. */ +#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ +#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ +#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ +#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ +#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ +#define EN0_TSR 0x04 /* Transmit status reg RD */ +#define EN0_TPSR 0x04 /* Transmit starting page WR */ +#define EN0_NCR 0x05 /* Number of collision reg RD */ +#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ +#define EN0_FIFO 0x06 /* FIFO RD */ +#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ +#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ +#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ +#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ +#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ +#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ +#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ +#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ +#define EN0_RSR 0x0c /* rx status reg RD */ +#define EN0_RXCR 0x0c /* RX configuration reg WR */ +#define EN0_TXCR 0x0d /* TX configuration reg WR */ +#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ +#define EN0_DCFG 0x0e /* Data configuration reg WR */ +#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ +#define EN0_IMR 0x0f /* Interrupt mask reg WR */ +#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ + +#define EN1_PHYS 0x11 +#define EN1_CURPAG 0x17 +#define EN1_MULT 0x18 + +/* Register accessed at EN_CMD, the 8390 base addr. */ +#define E8390_STOP 0x01 /* Stop and reset the chip */ +#define E8390_START 0x02 /* Start the chip, clear reset */ +#define E8390_TRANS 0x04 /* Transmit a frame */ +#define E8390_RREAD 0x08 /* Remote read */ +#define E8390_RWRITE 0x10 /* Remote write */ +#define E8390_NODMA 0x20 /* Remote DMA */ +#define E8390_PAGE0 0x00 /* Select page chip registers */ +#define E8390_PAGE1 0x40 /* using the two high-order bits */ +#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ + +/* Bits in EN0_ISR - Interrupt status register */ +#define ENISR_RX 0x01 /* Receiver, no error */ +#define ENISR_TX 0x02 /* Transmitter, no error */ +#define ENISR_RX_ERR 0x04 /* Receiver, with error */ +#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ +#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ +#define ENISR_COUNTERS 0x20 /* Counters need emptying */ +#define ENISR_RDC 0x40 /* remote dma complete */ +#define ENISR_RESET 0x80 /* Reset completed */ +#define ENISR_ALL 0x3f /* Interrupts we will enable */ + +/* Bits in received packet status byte and EN0_RSR*/ +#define ENRSR_RXOK 0x01 /* Received a good packet */ +#define ENRSR_CRC 0x02 /* CRC error */ +#define ENRSR_FAE 0x04 /* frame alignment error */ +#define ENRSR_FO 0x08 /* FIFO overrun */ +#define ENRSR_MPA 0x10 /* missed pkt */ +#define ENRSR_PHY 0x20 /* physical/multicast address */ +#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ +#define ENRSR_DEF 0x80 /* deferring */ + +/* Transmitted packet status, EN0_TSR. */ +#define ENTSR_PTX 0x01 /* Packet transmitted without error */ +#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ +#define ENTSR_COL 0x04 /* The transmit collided at least once. */ +#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ +#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ +#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ +#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ +#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ + +#define NE2000_MEM_SIZE 32768 + +typedef struct NE2000State { + uint8_t cmd; + uint32_t start; + uint32_t stop; + uint8_t boundary; + uint8_t tsr; + uint8_t tpsr; + uint16_t tcnt; + uint16_t rcnt; + uint32_t rsar; + uint8_t isr; + uint8_t dcfg; + uint8_t imr; + uint8_t phys[6]; /* mac address */ + uint8_t curpag; + uint8_t mult[8]; /* multicast mask array */ + int irq; + uint8_t mem[NE2000_MEM_SIZE]; +} NE2000State; + +static NE2000State ne2000_state; +int net_fd = -1; + +static void ne2000_reset(NE2000State *s) +{ + int i; + + s->isr = ENISR_RESET; + s->mem[0] = 0x52; + s->mem[1] = 0x54; + s->mem[2] = 0x00; + s->mem[3] = 0x12; + s->mem[4] = 0x34; + s->mem[5] = 0x56; + s->mem[14] = 0x57; + s->mem[15] = 0x57; + + /* duplicate prom data */ + for(i = 15;i >= 0; i--) { + s->mem[2 * i] = s->mem[i]; + s->mem[2 * i + 1] = s->mem[i]; + } +} + +static void ne2000_update_irq(NE2000State *s) +{ + int isr; + isr = s->isr & s->imr; + if (isr) + pic_set_irq(s->irq, 1); + else + pic_set_irq(s->irq, 0); +} + +/* return true if the NE2000 can receive more data */ +int ne2000_can_receive(void) +{ + NE2000State *s = &ne2000_state; + int avail, index, boundary; + + if (s->cmd & E8390_STOP) + return 0; + index = s->curpag << 8; + boundary = s->boundary << 8; + if (index < boundary) + avail = boundary - index; + else + avail = (s->stop - s->start) - (index - boundary); + if (avail < (MAX_ETH_FRAME_SIZE + 4)) + return 0; + return 1; +} + +void ne2000_receive(uint8_t *buf, int size) +{ + NE2000State *s = &ne2000_state; + uint8_t *p; + int total_len, next, avail, len, index; + +#if defined(DEBUG_NE2000) + printf("NE2000: received len=%d\n", size); +#endif + + index = s->curpag << 8; + /* 4 bytes for header */ + total_len = size + 4; + /* address for next packet (4 bytes for CRC) */ + next = index + ((total_len + 4 + 255) & ~0xff); + if (next >= s->stop) + next -= (s->stop - s->start); + /* prepare packet header */ + p = s->mem + index; + p[0] = ENRSR_RXOK; /* receive status */ + p[1] = next >> 8; + p[2] = total_len; + p[3] = total_len >> 8; + index += 4; + + /* write packet data */ + while (size > 0) { + avail = s->stop - index; + len = size; + if (len > avail) + len = avail; + memcpy(s->mem + index, buf, len); + buf += len; + index += len; + if (index == s->stop) + index = s->start; + size -= len; + } + s->curpag = next >> 8; + + /* now we can signal we have receive something */ + s->isr |= ENISR_RX; + ne2000_update_irq(s); +} + +static void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +{ + NE2000State *s = &ne2000_state; + int offset, page; + + addr &= 0xf; +#ifdef DEBUG_NE2000 + printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val); +#endif + if (addr == E8390_CMD) { + /* control register */ + s->cmd = val; + if (val & E8390_START) { + /* test specific case: zero length transfert */ + if ((val & (E8390_RREAD | E8390_RWRITE)) && + s->rcnt == 0) { + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } + if (val & E8390_TRANS) { + net_send_packet(net_fd, s->mem + (s->tpsr << 8), s->tcnt); + /* signal end of transfert */ + s->tsr = ENTSR_PTX; + s->isr |= ENISR_TX; + ne2000_update_irq(s); + } + } + } else { + page = s->cmd >> 6; + offset = addr | (page << 4); + switch(offset) { + case EN0_STARTPG: + s->start = val << 8; + break; + case EN0_STOPPG: + s->stop = val << 8; + break; + case EN0_BOUNDARY: + s->boundary = val; + break; + case EN0_IMR: + s->imr = val; + ne2000_update_irq(s); + break; + case EN0_TPSR: + s->tpsr = val; + break; + case EN0_TCNTLO: + s->tcnt = (s->tcnt & 0xff00) | val; + break; + case EN0_TCNTHI: + s->tcnt = (s->tcnt & 0x00ff) | (val << 8); + break; + case EN0_RSARLO: + s->rsar = (s->rsar & 0xff00) | val; + break; + case EN0_RSARHI: + s->rsar = (s->rsar & 0x00ff) | (val << 8); + break; + case EN0_RCNTLO: + s->rcnt = (s->rcnt & 0xff00) | val; + break; + case EN0_RCNTHI: + s->rcnt = (s->rcnt & 0x00ff) | (val << 8); + break; + case EN0_DCFG: + s->dcfg = val; + break; + case EN0_ISR: + s->isr &= ~val; + ne2000_update_irq(s); + break; + case EN1_PHYS ... EN1_PHYS + 5: + s->phys[offset - EN1_PHYS] = val; + break; + case EN1_CURPAG: + s->curpag = val; + break; + case EN1_MULT ... EN1_MULT + 7: + s->mult[offset - EN1_MULT] = val; + break; + } + } +} + +static uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) +{ + NE2000State *s = &ne2000_state; + int offset, page, ret; + + addr &= 0xf; + if (addr == E8390_CMD) { + ret = s->cmd; + } else { + page = s->cmd >> 6; + offset = addr | (page << 4); + switch(offset) { + case EN0_TSR: + ret = s->tsr; + break; + case EN0_BOUNDARY: + ret = s->boundary; + break; + case EN0_ISR: + ret = s->isr; + break; + case EN1_PHYS ... EN1_PHYS + 5: + ret = s->phys[offset - EN1_PHYS]; + break; + case EN1_CURPAG: + ret = s->curpag; + break; + case EN1_MULT ... EN1_MULT + 7: + ret = s->mult[offset - EN1_MULT]; + break; + default: + ret = 0x00; + break; + } + } +#ifdef DEBUG_NE2000 + printf("NE2000: read addr=0x%x val=%02x\n", addr, ret); +#endif + return ret; +} + +static void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +{ + NE2000State *s = &ne2000_state; + uint8_t *p; + +#ifdef DEBUG_NE2000 + printf("NE2000: asic write val=0x%04x\n", val); +#endif + p = s->mem + s->rsar; + if (s->dcfg & 0x01) { + /* 16 bit access */ + p[0] = val; + p[1] = val >> 8; + s->rsar += 2; + s->rcnt -= 2; + } else { + /* 8 bit access */ + p[0] = val; + s->rsar++; + s->rcnt--; + } + /* wrap */ + if (s->rsar == s->stop) + s->rsar = s->start; + if (s->rcnt == 0) { + /* signal end of transfert */ + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } +} + +static uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) +{ + NE2000State *s = &ne2000_state; + uint8_t *p; + int ret; + + p = s->mem + s->rsar; + if (s->dcfg & 0x01) { + /* 16 bit access */ + ret = p[0] | (p[1] << 8); + s->rsar += 2; + s->rcnt -= 2; + } else { + /* 8 bit access */ + ret = p[0]; + s->rsar++; + s->rcnt--; + } + /* wrap */ + if (s->rsar == s->stop) + s->rsar = s->start; + if (s->rcnt == 0) { + /* signal end of transfert */ + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } +#ifdef DEBUG_NE2000 + printf("NE2000: asic read val=0x%04x\n", ret); +#endif + return ret; +} + +static void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +{ + /* nothing to do (end of reset pulse) */ +} + +static uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr) +{ + NE2000State *s = &ne2000_state; + ne2000_reset(s); + return 0; +} + +void ne2000_init(int base, int irq) +{ + NE2000State *s = &ne2000_state; + + register_ioport_write(base, 16, ne2000_ioport_write, 1); + register_ioport_read(base, 16, ne2000_ioport_read, 1); + + register_ioport_write(base + 0x10, 1, ne2000_asic_ioport_write, 1); + register_ioport_read(base + 0x10, 1, ne2000_asic_ioport_read, 1); + register_ioport_write(base + 0x10, 2, ne2000_asic_ioport_write, 2); + register_ioport_read(base + 0x10, 2, ne2000_asic_ioport_read, 2); + + register_ioport_write(base + 0x1f, 1, ne2000_reset_ioport_write, 1); + register_ioport_read(base + 0x1f, 1, ne2000_reset_ioport_read, 1); + s->irq = irq; + + ne2000_reset(s); +} diff --git a/hw/pc.c b/hw/pc.c new file mode 100644 index 000000000..bee812c2b --- /dev/null +++ b/hw/pc.c @@ -0,0 +1,368 @@ +/* + * QEMU PC System Emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +#define BIOS_FILENAME "bios.bin" +#define VGABIOS_FILENAME "vgabios.bin" +#define LINUX_BOOT_FILENAME "linux_boot.bin" + +#define KERNEL_LOAD_ADDR 0x00100000 +#define INITRD_LOAD_ADDR 0x00400000 +#define KERNEL_PARAMS_ADDR 0x00090000 +#define KERNEL_CMDLINE_ADDR 0x00099000 + +int speaker_data_on; +int dummy_refresh_clock; + +static void ioport80_write(CPUState *env, uint32_t addr, uint32_t data) +{ +} + +#define REG_EQUIPMENT_BYTE 0x14 + +static void cmos_init(int ram_size, int boot_device) +{ + RTCState *s = &rtc_state; + int val; + + /* various important CMOS locations needed by PC/Bochs bios */ + + s->cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ + + /* memory size */ + val = (ram_size / 1024) - 1024; + if (val > 65535) + val = 65535; + s->cmos_data[0x17] = val; + s->cmos_data[0x18] = val >> 8; + s->cmos_data[0x30] = val; + s->cmos_data[0x31] = val >> 8; + + val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); + if (val > 65535) + val = 65535; + s->cmos_data[0x34] = val; + s->cmos_data[0x35] = val >> 8; + + switch(boot_device) { + case 'a': + case 'b': + s->cmos_data[0x3d] = 0x01; /* floppy boot */ + break; + default: + case 'c': + s->cmos_data[0x3d] = 0x02; /* hard drive boot */ + break; + case 'd': + s->cmos_data[0x3d] = 0x03; /* CD-ROM boot */ + break; + } +} + +void cmos_register_fd (uint8_t fd0, uint8_t fd1) +{ + RTCState *s = &rtc_state; + int nb = 0; + + s->cmos_data[0x10] = 0; + switch (fd0) { + case 0: + /* 1.44 Mb 3"5 drive */ + s->cmos_data[0x10] |= 0x40; + break; + case 1: + /* 2.88 Mb 3"5 drive */ + s->cmos_data[0x10] |= 0x60; + break; + case 2: + /* 1.2 Mb 5"5 drive */ + s->cmos_data[0x10] |= 0x20; + break; + } + switch (fd1) { + case 0: + /* 1.44 Mb 3"5 drive */ + s->cmos_data[0x10] |= 0x04; + break; + case 1: + /* 2.88 Mb 3"5 drive */ + s->cmos_data[0x10] |= 0x06; + break; + case 2: + /* 1.2 Mb 5"5 drive */ + s->cmos_data[0x10] |= 0x02; + break; + } + if (fd0 < 3) + nb++; + if (fd1 < 3) + nb++; + switch (nb) { + case 0: + break; + case 1: + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ + break; + case 2: + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ + break; + } +} + +void speaker_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +{ + speaker_data_on = (val >> 1) & 1; + pit_set_gate(&pit_channels[2], val & 1); +} + +uint32_t speaker_ioport_read(CPUState *env, uint32_t addr) +{ + int out; + out = pit_get_out(&pit_channels[2]); + dummy_refresh_clock ^= 1; + return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | + (dummy_refresh_clock << 4); +} + +/***********************************************************/ +/* PC floppy disk controler emulation glue */ +#define PC_FDC_DMA 0x2 +#define PC_FDC_IRQ 0x6 +#define PC_FDC_BASE 0x3F0 + +static void fdctrl_register (unsigned char **disknames, int ro, + char boot_device) +{ + int i; + + fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device); + for (i = 0; i < MAX_FD; i++) { + if (disknames[i] != NULL) + fdctrl_disk_change(i, disknames[i], ro); + } +} + +/***********************************************************/ +/* Bochs BIOS debug ports */ + +void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) +{ + switch(addr) { + /* Bochs BIOS messages */ + case 0x400: + case 0x401: + fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); + exit(1); + case 0x402: + case 0x403: +#ifdef DEBUG_BIOS + fprintf(stderr, "%c", val); +#endif + break; + + /* LGPL'ed VGA BIOS messages */ + case 0x501: + case 0x502: + fprintf(stderr, "VGA BIOS panic, line %d\n", val); + exit(1); + case 0x500: + case 0x503: +#ifdef DEBUG_BIOS + fprintf(stderr, "%c", val); +#endif + break; + } +} + +void bochs_bios_init(void) +{ + register_ioport_write(0x400, 1, bochs_bios_write, 2); + register_ioport_write(0x401, 1, bochs_bios_write, 2); + register_ioport_write(0x402, 1, bochs_bios_write, 1); + register_ioport_write(0x403, 1, bochs_bios_write, 1); + + register_ioport_write(0x501, 1, bochs_bios_write, 2); + register_ioport_write(0x502, 1, bochs_bios_write, 2); + register_ioport_write(0x500, 1, bochs_bios_write, 1); + register_ioport_write(0x503, 1, bochs_bios_write, 1); +} + + +int load_kernel(const char *filename, uint8_t *addr, + uint8_t *real_addr) +{ + int fd, size; + int setup_sects; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + + /* load 16 bit code */ + if (read(fd, real_addr, 512) != 512) + goto fail; + setup_sects = real_addr[0x1F1]; + if (!setup_sects) + setup_sects = 4; + if (read(fd, real_addr + 512, setup_sects * 512) != + setup_sects * 512) + goto fail; + + /* load 32 bit code */ + size = read(fd, addr, 16 * 1024 * 1024); + if (size < 0) + goto fail; + close(fd); + return size; + fail: + close(fd); + return -1; +} + +/* PC hardware initialisation */ +void pc_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + char buf[1024]; + int ret, linux_boot, initrd_size; + + linux_boot = (kernel_filename != NULL); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, 0); + + /* BIOS load */ + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + 0x000f0000); + if (ret != 0x10000) { + fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); + exit(1); + } + + /* VGA BIOS load */ + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); + ret = load_image(buf, phys_ram_base + 0x000c0000); + + /* setup basic memory access */ + cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); + cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); + + bochs_bios_init(); + + if (linux_boot) { + uint8_t bootsect[512]; + + if (bs_table[0] == NULL) { + fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); + exit(1); + } + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); + ret = load_image(buf, bootsect); + if (ret != sizeof(bootsect)) { + fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", + buf); + exit(1); + } + + bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); + + /* now we can load the kernel */ + ret = load_kernel(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR, + phys_ram_base + KERNEL_PARAMS_ADDR); + if (ret < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + if (initrd_size > 0) { + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); + } + pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, + kernel_cmdline); + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, + KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); + /* loader type */ + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); + } + + /* init basic PC hardware */ + register_ioport_write(0x80, 1, ioport80_write, 1); + + vga_initialize(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + + rtc_init(0x70, 8); + cmos_init(ram_size, boot_device); + register_ioport_read(0x61, 1, speaker_ioport_read, 1); + register_ioport_write(0x61, 1, speaker_ioport_write, 1); + + pic_init(); + pit_init(); + serial_init(0x3f8, 4); + ne2000_init(0x300, 9); + ide_init(); + kbd_init(); + AUD_init(); + DMA_init(); + SB16_init(); + + fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device); +} diff --git a/hw/pckbd.c b/hw/pckbd.c new file mode 100644 index 000000000..8c0d3a72c --- /dev/null +++ b/hw/pckbd.c @@ -0,0 +1,672 @@ +/* + * QEMU PC keyboard emulation + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +/* debug PC keyboard */ +//#define DEBUG_KBD + +/* debug PC keyboard : only mouse */ +//#define DEBUG_MOUSE + +/* Keyboard Controller Commands */ +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ +#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ +#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ +#define KBD_CCMD_WRITE_OBUF 0xD2 +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ +#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ +#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ +#define KBD_CCMD_RESET 0xFE + +/* Keyboard Commands */ +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_ECHO 0xEE +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* Keyboard Replies */ +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* Status Register Bits */ +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +/* Controller Mode Register Bits */ +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* Mouse Commands */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_POLL 0xEB /* Poll */ +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ +#define AUX_GET_TYPE 0xF2 /* Get type */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_SET_DEFAULT 0xF6 +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define MOUSE_STATUS_REMOTE 0x40 +#define MOUSE_STATUS_ENABLED 0x20 +#define MOUSE_STATUS_SCALE21 0x10 + +#define KBD_QUEUE_SIZE 256 + +typedef struct { + uint8_t data[KBD_QUEUE_SIZE]; + int rptr, wptr, count; +} KBDQueue; + +typedef struct KBDState { + KBDQueue queues[2]; + uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ + uint8_t status; + uint8_t mode; + /* keyboard state */ + int kbd_write_cmd; + int scan_enabled; + /* mouse state */ + int mouse_write_cmd; + uint8_t mouse_status; + uint8_t mouse_resolution; + uint8_t mouse_sample_rate; + uint8_t mouse_wrap; + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ + uint8_t mouse_detect_state; + int mouse_dx; /* current values, needed for 'poll' mode */ + int mouse_dy; + int mouse_dz; + uint8_t mouse_buttons; +} KBDState; + +KBDState kbd_state; +int reset_requested; + +/* update irq and KBD_STAT_[MOUSE_]OBF */ +/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be + incorrect, but it avoids having to simulate exact delays */ +static void kbd_update_irq(KBDState *s) +{ + int irq12_level, irq1_level; + + irq1_level = 0; + irq12_level = 0; + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); + if (s->queues[0].count != 0 || + s->queues[1].count != 0) { + s->status |= KBD_STAT_OBF; + if (s->queues[1].count != 0) { + s->status |= KBD_STAT_MOUSE_OBF; + if (s->mode & KBD_MODE_MOUSE_INT) + irq12_level = 1; + } else { + if ((s->mode & KBD_MODE_KBD_INT) && + !(s->mode & KBD_MODE_DISABLE_KBD)) + irq1_level = 1; + } + } + pic_set_irq(1, irq1_level); + pic_set_irq(12, irq12_level); +} + +static void kbd_queue(KBDState *s, int b, int aux) +{ + KBDQueue *q = &kbd_state.queues[aux]; + +#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) + if (aux) + printf("mouse event: 0x%02x\n", b); +#ifdef DEBUG_KBD + else + printf("kbd event: 0x%02x\n", b); +#endif +#endif + if (q->count >= KBD_QUEUE_SIZE) + return; + q->data[q->wptr] = b; + if (++q->wptr == KBD_QUEUE_SIZE) + q->wptr = 0; + q->count++; + kbd_update_irq(s); +} + +void kbd_put_keycode(int keycode) +{ + KBDState *s = &kbd_state; + kbd_queue(s, keycode, 0); +} + +static uint32_t kbd_read_status(CPUState *env, uint32_t addr) +{ + KBDState *s = &kbd_state; + int val; + val = s->status; +#if defined(DEBUG_KBD) + printf("kbd: read status=0x%02x\n", val); +#endif + return val; +} + +static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) +{ + KBDState *s = &kbd_state; + +#ifdef DEBUG_KBD + printf("kbd: write cmd=0x%02x\n", val); +#endif + switch(val) { + case KBD_CCMD_READ_MODE: + kbd_queue(s, s->mode, 0); + break; + case KBD_CCMD_WRITE_MODE: + case KBD_CCMD_WRITE_OBUF: + case KBD_CCMD_WRITE_AUX_OBUF: + case KBD_CCMD_WRITE_MOUSE: + case KBD_CCMD_WRITE_OUTPORT: + s->write_cmd = val; + break; + case KBD_CCMD_MOUSE_DISABLE: + s->mode |= KBD_MODE_DISABLE_MOUSE; + break; + case KBD_CCMD_MOUSE_ENABLE: + s->mode &= ~KBD_MODE_DISABLE_MOUSE; + break; + case KBD_CCMD_TEST_MOUSE: + kbd_queue(s, 0x00, 0); + break; + case KBD_CCMD_SELF_TEST: + s->status |= KBD_STAT_SELFTEST; + kbd_queue(s, 0x55, 0); + break; + case KBD_CCMD_KBD_TEST: + kbd_queue(s, 0x00, 0); + break; + case KBD_CCMD_KBD_DISABLE: + s->mode |= KBD_MODE_DISABLE_KBD; + kbd_update_irq(s); + break; + case KBD_CCMD_KBD_ENABLE: + s->mode &= ~KBD_MODE_DISABLE_KBD; + kbd_update_irq(s); + break; + case KBD_CCMD_READ_INPORT: + kbd_queue(s, 0x00, 0); + break; + case KBD_CCMD_READ_OUTPORT: + /* XXX: check that */ +#ifdef TARGET_I386 + val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1); +#else + val = 0x01; +#endif + if (s->status & KBD_STAT_OBF) + val |= 0x10; + if (s->status & KBD_STAT_MOUSE_OBF) + val |= 0x20; + kbd_queue(s, val, 0); + break; +#ifdef TARGET_I386 + case KBD_CCMD_ENABLE_A20: + cpu_x86_set_a20(env, 1); + break; + case KBD_CCMD_DISABLE_A20: + cpu_x86_set_a20(env, 0); + break; +#endif + case KBD_CCMD_RESET: + reset_requested = 1; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + break; + case 0xff: + /* ignore that - I don't know what is its use */ + break; + default: + fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); + break; + } +} + +static uint32_t kbd_read_data(CPUState *env, uint32_t addr) +{ + KBDState *s = &kbd_state; + KBDQueue *q; + int val, index; + + q = &s->queues[0]; /* first check KBD data */ + if (q->count == 0) + q = &s->queues[1]; /* then check AUX data */ + if (q->count == 0) { + /* NOTE: if no data left, we return the last keyboard one + (needed for EMM386) */ + /* XXX: need a timer to do things correctly */ + q = &s->queues[0]; + index = q->rptr - 1; + if (index < 0) + index = KBD_QUEUE_SIZE - 1; + val = q->data[index]; + } else { + val = q->data[q->rptr]; + if (++q->rptr == KBD_QUEUE_SIZE) + q->rptr = 0; + q->count--; + /* reading deasserts IRQ */ + if (q == &s->queues[0]) + pic_set_irq(1, 0); + else + pic_set_irq(12, 0); + } + /* reassert IRQs if data left */ + kbd_update_irq(s); +#ifdef DEBUG_KBD + printf("kbd: read data=0x%02x\n", val); +#endif + return val; +} + +static void kbd_reset_keyboard(KBDState *s) +{ + s->scan_enabled = 1; +} + +static void kbd_write_keyboard(KBDState *s, int val) +{ + switch(s->kbd_write_cmd) { + default: + case -1: + switch(val) { + case 0x00: + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case 0x05: + kbd_queue(s, KBD_REPLY_RESEND, 0); + break; + case KBD_CMD_GET_ID: + kbd_queue(s, KBD_REPLY_ACK, 0); + kbd_queue(s, 0xab, 0); + kbd_queue(s, 0x83, 0); + break; + case KBD_CMD_ECHO: + kbd_queue(s, KBD_CMD_ECHO, 0); + break; + case KBD_CMD_ENABLE: + s->scan_enabled = 1; + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case KBD_CMD_SET_LEDS: + case KBD_CMD_SET_RATE: + s->kbd_write_cmd = val; + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case KBD_CMD_RESET_DISABLE: + kbd_reset_keyboard(s); + s->scan_enabled = 0; + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case KBD_CMD_RESET_ENABLE: + kbd_reset_keyboard(s); + s->scan_enabled = 1; + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + case KBD_CMD_RESET: + kbd_reset_keyboard(s); + kbd_queue(s, KBD_REPLY_ACK, 0); + kbd_queue(s, KBD_REPLY_POR, 0); + break; + default: + kbd_queue(s, KBD_REPLY_ACK, 0); + break; + } + break; + case KBD_CMD_SET_LEDS: + kbd_queue(s, KBD_REPLY_ACK, 0); + s->kbd_write_cmd = -1; + break; + case KBD_CMD_SET_RATE: + kbd_queue(s, KBD_REPLY_ACK, 0); + s->kbd_write_cmd = -1; + break; + } +} + +static void kbd_mouse_send_packet(KBDState *s) +{ + unsigned int b; + int dx1, dy1, dz1; + + dx1 = s->mouse_dx; + dy1 = s->mouse_dy; + dz1 = s->mouse_dz; + /* XXX: increase range to 8 bits ? */ + if (dx1 > 127) + dx1 = 127; + else if (dx1 < -127) + dx1 = -127; + if (dy1 > 127) + dy1 = 127; + else if (dy1 < -127) + dy1 = -127; + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); + kbd_queue(s, b, 1); + kbd_queue(s, dx1 & 0xff, 1); + kbd_queue(s, dy1 & 0xff, 1); + /* extra byte for IMPS/2 or IMEX */ + switch(s->mouse_type) { + default: + break; + case 3: + if (dz1 > 127) + dz1 = 127; + else if (dz1 < -127) + dz1 = -127; + kbd_queue(s, dz1 & 0xff, 1); + break; + case 4: + if (dz1 > 7) + dz1 = 7; + else if (dz1 < -7) + dz1 = -7; + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); + kbd_queue(s, b, 1); + break; + } + + /* update deltas */ + s->mouse_dx -= dx1; + s->mouse_dy -= dy1; + s->mouse_dz -= dz1; +} + +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) +{ + KBDState *s = &kbd_state; + + /* check if deltas are recorded when disabled */ + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) + return; + + s->mouse_dx += dx; + s->mouse_dy -= dy; + s->mouse_dz += dz; + s->mouse_buttons = buttons_state; + + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && + (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { + for(;;) { + /* if not remote, send event. Multiple events are sent if + too big deltas */ + kbd_mouse_send_packet(s); + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) + break; + } + } +} + +static void kbd_write_mouse(KBDState *s, int val) +{ +#ifdef DEBUG_MOUSE + printf("kbd: write mouse 0x%02x\n", val); +#endif + switch(s->mouse_write_cmd) { + default: + case -1: + /* mouse command */ + if (s->mouse_wrap) { + if (val == AUX_RESET_WRAP) { + s->mouse_wrap = 0; + kbd_queue(s, AUX_ACK, 1); + return; + } else if (val != AUX_RESET) { + kbd_queue(s, val, 1); + return; + } + } + switch(val) { + case AUX_SET_SCALE11: + s->mouse_status &= ~MOUSE_STATUS_SCALE21; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_SCALE21: + s->mouse_status |= MOUSE_STATUS_SCALE21; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_STREAM: + s->mouse_status &= ~MOUSE_STATUS_REMOTE; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_WRAP: + s->mouse_wrap = 1; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_REMOTE: + s->mouse_status |= MOUSE_STATUS_REMOTE; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_GET_TYPE: + kbd_queue(s, AUX_ACK, 1); + kbd_queue(s, s->mouse_type, 1); + break; + case AUX_SET_RES: + case AUX_SET_SAMPLE: + s->mouse_write_cmd = val; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_GET_SCALE: + kbd_queue(s, AUX_ACK, 1); + kbd_queue(s, s->mouse_status, 1); + kbd_queue(s, s->mouse_resolution, 1); + kbd_queue(s, s->mouse_sample_rate, 1); + break; + case AUX_POLL: + kbd_queue(s, AUX_ACK, 1); + kbd_mouse_send_packet(s); + break; + case AUX_ENABLE_DEV: + s->mouse_status |= MOUSE_STATUS_ENABLED; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_DISABLE_DEV: + s->mouse_status &= ~MOUSE_STATUS_ENABLED; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_SET_DEFAULT: + s->mouse_sample_rate = 100; + s->mouse_resolution = 2; + s->mouse_status = 0; + kbd_queue(s, AUX_ACK, 1); + break; + case AUX_RESET: + s->mouse_sample_rate = 100; + s->mouse_resolution = 2; + s->mouse_status = 0; + kbd_queue(s, AUX_ACK, 1); + kbd_queue(s, 0xaa, 1); + kbd_queue(s, s->mouse_type, 1); + break; + default: + break; + } + break; + case AUX_SET_SAMPLE: + s->mouse_sample_rate = val; +#if 0 + /* detect IMPS/2 or IMEX */ + switch(s->mouse_detect_state) { + default: + case 0: + if (val == 200) + s->mouse_detect_state = 1; + break; + case 1: + if (val == 100) + s->mouse_detect_state = 2; + else if (val == 200) + s->mouse_detect_state = 3; + else + s->mouse_detect_state = 0; + break; + case 2: + if (val == 80) + s->mouse_type = 3; /* IMPS/2 */ + s->mouse_detect_state = 0; + break; + case 3: + if (val == 80) + s->mouse_type = 4; /* IMEX */ + s->mouse_detect_state = 0; + break; + } +#endif + kbd_queue(s, AUX_ACK, 1); + s->mouse_write_cmd = -1; + break; + case AUX_SET_RES: + s->mouse_resolution = val; + kbd_queue(s, AUX_ACK, 1); + s->mouse_write_cmd = -1; + break; + } +} + +void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val) +{ + KBDState *s = &kbd_state; + +#ifdef DEBUG_KBD + printf("kbd: write data=0x%02x\n", val); +#endif + + switch(s->write_cmd) { + case 0: + kbd_write_keyboard(s, val); + break; + case KBD_CCMD_WRITE_MODE: + s->mode = val; + kbd_update_irq(s); + break; + case KBD_CCMD_WRITE_OBUF: + kbd_queue(s, val, 0); + break; + case KBD_CCMD_WRITE_AUX_OBUF: + kbd_queue(s, val, 1); + break; + case KBD_CCMD_WRITE_OUTPORT: +#ifdef TARGET_I386 + cpu_x86_set_a20(env, (val >> 1) & 1); +#endif + if (!(val & 1)) { + reset_requested = 1; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + } + break; + case KBD_CCMD_WRITE_MOUSE: + kbd_write_mouse(s, val); + break; + default: + break; + } + s->write_cmd = 0; +} + +void kbd_reset(KBDState *s) +{ + KBDQueue *q; + int i; + + s->kbd_write_cmd = -1; + s->mouse_write_cmd = -1; + s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; + s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; + for(i = 0; i < 2; i++) { + q = &s->queues[i]; + q->rptr = 0; + q->wptr = 0; + q->count = 0; + } +} + +void kbd_init(void) +{ + kbd_reset(&kbd_state); + register_ioport_read(0x60, 1, kbd_read_data, 1); + register_ioport_write(0x60, 1, kbd_write_data, 1); + register_ioport_read(0x64, 1, kbd_read_status, 1); + register_ioport_write(0x64, 1, kbd_write_command, 1); +} diff --git a/hw/serial.c b/hw/serial.c new file mode 100644 index 000000000..e1225ec40 --- /dev/null +++ b/hw/serial.c @@ -0,0 +1,281 @@ +/* + * QEMU 16450 UART emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +//#define DEBUG_SERIAL + +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ + +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ + +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ + +#define UART_IIR_MSI 0x00 /* Modem status interrupt */ +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ + +/* + * These are the definitions for the Modem Control Register + */ +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ +#define UART_MCR_OUT2 0x08 /* Out2 complement */ +#define UART_MCR_OUT1 0x04 /* Out1 complement */ +#define UART_MCR_RTS 0x02 /* RTS complement */ +#define UART_MCR_DTR 0x01 /* DTR complement */ + +/* + * These are the definitions for the Modem Status Register + */ +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ +#define UART_MSR_RI 0x40 /* Ring Indicator */ +#define UART_MSR_DSR 0x20 /* Data Set Ready */ +#define UART_MSR_CTS 0x10 /* Clear to Send */ +#define UART_MSR_DDCD 0x08 /* Delta DCD */ +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ +#define UART_MSR_DDSR 0x02 /* Delta DSR */ +#define UART_MSR_DCTS 0x01 /* Delta CTS */ +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ + +#define UART_LSR_TEMT 0x40 /* Transmitter empty */ +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ +#define UART_LSR_BI 0x10 /* Break interrupt indicator */ +#define UART_LSR_FE 0x08 /* Frame error indicator */ +#define UART_LSR_PE 0x04 /* Parity error indicator */ +#define UART_LSR_OE 0x02 /* Overrun error indicator */ +#define UART_LSR_DR 0x01 /* Receiver data ready */ + +typedef struct SerialState { + uint8_t divider; + uint8_t rbr; /* receive register */ + uint8_t ier; + uint8_t iir; /* read only */ + uint8_t lcr; + uint8_t mcr; + uint8_t lsr; /* read only */ + uint8_t msr; + uint8_t scr; + /* NOTE: this hidden state is necessary for tx irq generation as + it can be reset while reading iir */ + int thr_ipending; + int irq; +} SerialState; + +SerialState serial_ports[1]; + +void serial_update_irq(void) +{ + SerialState *s = &serial_ports[0]; + + if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { + s->iir = UART_IIR_RDI; + } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { + s->iir = UART_IIR_THRI; + } else { + s->iir = UART_IIR_NO_INT; + } + if (s->iir != UART_IIR_NO_INT) { + pic_set_irq(s->irq, 1); + } else { + pic_set_irq(s->irq, 0); + } +} + +void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +{ + SerialState *s = &serial_ports[0]; + unsigned char ch; + int ret; + + addr &= 7; +#ifdef DEBUG_SERIAL + printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); +#endif + switch(addr) { + default: + case 0: + if (s->lcr & UART_LCR_DLAB) { + s->divider = (s->divider & 0xff00) | val; + } else { + s->thr_ipending = 0; + s->lsr &= ~UART_LSR_THRE; + serial_update_irq(); + + ch = val; + do { + ret = write(1, &ch, 1); + } while (ret != 1); + s->thr_ipending = 1; + s->lsr |= UART_LSR_THRE; + s->lsr |= UART_LSR_TEMT; + serial_update_irq(); + } + break; + case 1: + if (s->lcr & UART_LCR_DLAB) { + s->divider = (s->divider & 0x00ff) | (val << 8); + } else { + s->ier = val; + serial_update_irq(); + } + break; + case 2: + break; + case 3: + s->lcr = val; + break; + case 4: + s->mcr = val; + break; + case 5: + break; + case 6: + s->msr = val; + break; + case 7: + s->scr = val; + break; + } +} + +uint32_t serial_ioport_read(CPUState *env, uint32_t addr) +{ + SerialState *s = &serial_ports[0]; + uint32_t ret; + + addr &= 7; + switch(addr) { + default: + case 0: + if (s->lcr & UART_LCR_DLAB) { + ret = s->divider & 0xff; + } else { + ret = s->rbr; + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); + serial_update_irq(); + } + break; + case 1: + if (s->lcr & UART_LCR_DLAB) { + ret = (s->divider >> 8) & 0xff; + } else { + ret = s->ier; + } + break; + case 2: + ret = s->iir; + /* reset THR pending bit */ + if ((ret & 0x7) == UART_IIR_THRI) + s->thr_ipending = 0; + serial_update_irq(); + break; + case 3: + ret = s->lcr; + break; + case 4: + ret = s->mcr; + break; + case 5: + ret = s->lsr; + break; + case 6: + if (s->mcr & UART_MCR_LOOP) { + /* in loopback, the modem output pins are connected to the + inputs */ + ret = (s->mcr & 0x0c) << 4; + ret |= (s->mcr & 0x02) << 3; + ret |= (s->mcr & 0x01) << 5; + } else { + ret = s->msr; + } + break; + case 7: + ret = s->scr; + break; + } +#ifdef DEBUG_SERIAL + printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret); +#endif + return ret; +} + +int serial_can_receive(void) +{ + SerialState *s = &serial_ports[0]; + return !(s->lsr & UART_LSR_DR); +} + +void serial_receive_byte(int ch) +{ + SerialState *s = &serial_ports[0]; + + s->rbr = ch; + s->lsr |= UART_LSR_DR; + serial_update_irq(); +} + +void serial_receive_break(void) +{ + SerialState *s = &serial_ports[0]; + + s->rbr = 0; + s->lsr |= UART_LSR_BI | UART_LSR_DR; + serial_update_irq(); +} + +void serial_init(int base, int irq) +{ + SerialState *s = &serial_ports[0]; + + s->irq = irq; + s->lsr = UART_LSR_TEMT | UART_LSR_THRE; + s->iir = UART_IIR_NO_INT; + + register_ioport_write(base, 8, serial_ioport_write, 1); + register_ioport_read(base, 8, serial_ioport_read, 1); +} diff --git a/vl.c b/vl.c index e2e139303..432bc067a 100644 --- a/vl.c +++ b/vl.c @@ -1,7 +1,7 @@ /* - * QEMU PC System Emulator + * QEMU System Emulator * - * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003-2004 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -51,33 +51,9 @@ #include "vl.h" #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" -#define BIOS_FILENAME "bios.bin" -#define VGABIOS_FILENAME "vgabios.bin" -#define LINUX_BOOT_FILENAME "linux_boot.bin" //#define DEBUG_UNUSED_IOPORT -//#define DEBUG_IRQ_LATENCY - -/* output Bochs bios info messages */ -//#define DEBUG_BIOS - -//#define DEBUG_CMOS - -/* debug PIC */ -//#define DEBUG_PIC - -/* debug NE2000 card */ -//#define DEBUG_NE2000 - -/* debug PC keyboard */ -//#define DEBUG_KBD - -/* debug PC keyboard : only mouse */ -//#define DEBUG_MOUSE - -//#define DEBUG_SERIAL - #if !defined(CONFIG_SOFTMMU) #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) #else @@ -85,7 +61,6 @@ #endif #if defined (TARGET_I386) -#define KERNEL_LOAD_ADDR 0x00100000 #elif defined (TARGET_PPC) //#define USE_OPEN_FIRMWARE #if !defined (USE_OPEN_FIRMWARE) @@ -96,16 +71,13 @@ #define KERNEL_STACK_ADDR 0x00400000 #endif #endif -#define INITRD_LOAD_ADDR 0x00400000 -#define KERNEL_PARAMS_ADDR 0x00090000 -#define KERNEL_CMDLINE_ADDR 0x00099000 #define GUI_REFRESH_INTERVAL 30 /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 -static const char *bios_dir = CONFIG_QEMU_SHAREDIR; +const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; CPUState *global_env; CPUState *cpu_single_env; @@ -119,6 +91,8 @@ int term_inited; int64_t ticks_per_sec; int boot_device = 'c'; static int ram_size; +static char network_script[1024]; +int pit_min_timer_count = 0; /***********************************************************/ /* x86 io ports */ @@ -245,39 +219,6 @@ char *pstrcat(char *buf, int buf_size, const char *s) return buf; } -#if defined (TARGET_I386) -int load_kernel(const char *filename, uint8_t *addr, - uint8_t *real_addr) -{ - int fd, size; - int setup_sects; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return -1; - - /* load 16 bit code */ - if (read(fd, real_addr, 512) != 512) - goto fail; - setup_sects = real_addr[0x1F1]; - if (!setup_sects) - setup_sects = 4; - if (read(fd, real_addr + 512, setup_sects * 512) != - setup_sects * 512) - goto fail; - - /* load 32 bit code */ - size = read(fd, addr, 16 * 1024 * 1024); - if (size < 0) - goto fail; - close(fd); - return size; - fail: - close(fd); - return -1; -} -#endif - /* return the size or -1 if error */ int load_image(const char *filename, uint8_t *addr) { @@ -326,10 +267,6 @@ int cpu_inl(CPUState *env, int addr) } /***********************************************************/ -void ioport80_write(CPUState *env, uint32_t addr, uint32_t data) -{ -} - void hw_error(const char *fmt, ...) { va_list ap; @@ -347,613 +284,6 @@ void hw_error(const char *fmt, ...) abort(); } -/***********************************************************/ -/* cmos emulation */ - -#if defined (TARGET_I386) -#define RTC_SECONDS 0 -#define RTC_SECONDS_ALARM 1 -#define RTC_MINUTES 2 -#define RTC_MINUTES_ALARM 3 -#define RTC_HOURS 4 -#define RTC_HOURS_ALARM 5 -#define RTC_ALARM_DONT_CARE 0xC0 - -#define RTC_DAY_OF_WEEK 6 -#define RTC_DAY_OF_MONTH 7 -#define RTC_MONTH 8 -#define RTC_YEAR 9 - -#define RTC_REG_A 10 -#define RTC_REG_B 11 -#define RTC_REG_C 12 -#define RTC_REG_D 13 - -/* PC cmos mappings */ -#define REG_EQUIPMENT_BYTE 0x14 -#define REG_IBM_CENTURY_BYTE 0x32 -#define REG_IBM_PS2_CENTURY_BYTE 0x37 - -uint8_t cmos_data[128]; -uint8_t cmos_index; - -void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) -{ - if (addr == 0x70) { - cmos_index = data & 0x7f; - } else { -#ifdef DEBUG_CMOS - printf("cmos: write index=0x%02x val=0x%02x\n", - cmos_index, data); -#endif - switch(addr) { - case RTC_SECONDS_ALARM: - case RTC_MINUTES_ALARM: - case RTC_HOURS_ALARM: - /* XXX: not supported */ - cmos_data[cmos_index] = data; - break; - case RTC_SECONDS: - case RTC_MINUTES: - case RTC_HOURS: - case RTC_DAY_OF_WEEK: - case RTC_DAY_OF_MONTH: - case RTC_MONTH: - case RTC_YEAR: - cmos_data[cmos_index] = data; - break; - case RTC_REG_A: - case RTC_REG_B: - cmos_data[cmos_index] = data; - break; - case RTC_REG_C: - case RTC_REG_D: - /* cannot write to them */ - break; - default: - cmos_data[cmos_index] = data; - break; - } - } -} - -static inline int to_bcd(int a) -{ - return ((a / 10) << 4) | (a % 10); -} - -static void cmos_update_time(void) -{ - struct tm *tm; - time_t ti; - - ti = time(NULL); - tm = gmtime(&ti); - cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); - cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); - cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); - cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); - cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); - cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); - cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); - cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); - cmos_data[REG_IBM_PS2_CENTURY_BYTE] = cmos_data[REG_IBM_CENTURY_BYTE]; -} - -uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) -{ - int ret; - - if (addr == 0x70) { - return 0xff; - } else { - switch(cmos_index) { - case RTC_SECONDS: - case RTC_MINUTES: - case RTC_HOURS: - case RTC_DAY_OF_WEEK: - case RTC_DAY_OF_MONTH: - case RTC_MONTH: - case RTC_YEAR: - case REG_IBM_CENTURY_BYTE: - case REG_IBM_PS2_CENTURY_BYTE: - cmos_update_time(); - ret = cmos_data[cmos_index]; - break; - case RTC_REG_A: - ret = cmos_data[cmos_index]; - /* toggle update-in-progress bit for Linux (same hack as - plex86) */ - cmos_data[RTC_REG_A] ^= 0x80; - break; - case RTC_REG_C: - ret = cmos_data[cmos_index]; - pic_set_irq(8, 0); - cmos_data[RTC_REG_C] = 0x00; - break; - default: - ret = cmos_data[cmos_index]; - break; - } -#ifdef DEBUG_CMOS - printf("cmos: read index=0x%02x val=0x%02x\n", - cmos_index, ret); -#endif - return ret; - } -} - -void cmos_init(void) -{ - int val; - - cmos_update_time(); - - cmos_data[RTC_REG_A] = 0x26; - cmos_data[RTC_REG_B] = 0x02; - cmos_data[RTC_REG_C] = 0x00; - cmos_data[RTC_REG_D] = 0x80; - - /* various important CMOS locations needed by PC/Bochs bios */ - - cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ - cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ - - /* memory size */ - val = (ram_size / 1024) - 1024; - if (val > 65535) - val = 65535; - cmos_data[0x17] = val; - cmos_data[0x18] = val >> 8; - cmos_data[0x30] = val; - cmos_data[0x31] = val >> 8; - - val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); - if (val > 65535) - val = 65535; - cmos_data[0x34] = val; - cmos_data[0x35] = val >> 8; - - switch(boot_device) { - case 'a': - case 'b': - cmos_data[0x3d] = 0x01; /* floppy boot */ - break; - default: - case 'c': - cmos_data[0x3d] = 0x02; /* hard drive boot */ - break; - case 'd': - cmos_data[0x3d] = 0x03; /* CD-ROM boot */ - break; - } - - register_ioport_write(0x70, 2, cmos_ioport_write, 1); - register_ioport_read(0x70, 2, cmos_ioport_read, 1); -} - -void cmos_register_fd (uint8_t fd0, uint8_t fd1) -{ - int nb = 0; - - cmos_data[0x10] = 0; - switch (fd0) { - case 0: - /* 1.44 Mb 3"5 drive */ - cmos_data[0x10] |= 0x40; - break; - case 1: - /* 2.88 Mb 3"5 drive */ - cmos_data[0x10] |= 0x60; - break; - case 2: - /* 1.2 Mb 5"5 drive */ - cmos_data[0x10] |= 0x20; - break; - } - switch (fd1) { - case 0: - /* 1.44 Mb 3"5 drive */ - cmos_data[0x10] |= 0x04; - break; - case 1: - /* 2.88 Mb 3"5 drive */ - cmos_data[0x10] |= 0x06; - break; - case 2: - /* 1.2 Mb 5"5 drive */ - cmos_data[0x10] |= 0x02; - break; - } - if (fd0 < 3) - nb++; - if (fd1 < 3) - nb++; - switch (nb) { - case 0: - break; - case 1: - cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ - break; - case 2: - cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ - break; - } -} -#endif /* TARGET_I386 */ - -/***********************************************************/ -/* 8259 pic emulation */ - -typedef struct PicState { - uint8_t last_irr; /* edge detection */ - uint8_t irr; /* interrupt request register */ - uint8_t imr; /* interrupt mask register */ - uint8_t isr; /* interrupt service register */ - uint8_t priority_add; /* highest irq priority */ - uint8_t irq_base; - uint8_t read_reg_select; - uint8_t poll; - uint8_t special_mask; - uint8_t init_state; - uint8_t auto_eoi; - uint8_t rotate_on_auto_eoi; - uint8_t special_fully_nested_mode; - uint8_t init4; /* true if 4 byte init */ -} PicState; - -/* 0 is master pic, 1 is slave pic */ -PicState pics[2]; -int pic_irq_requested; - -/* set irq level. If an edge is detected, then the IRR is set to 1 */ -static inline void pic_set_irq1(PicState *s, int irq, int level) -{ - int mask; - mask = 1 << irq; - if (level) { - if ((s->last_irr & mask) == 0) - s->irr |= mask; - s->last_irr |= mask; - } else { - s->last_irr &= ~mask; - } -} - -/* return the highest priority found in mask (highest = smallest - number). Return 8 if no irq */ -static inline int get_priority(PicState *s, int mask) -{ - int priority; - if (mask == 0) - return 8; - priority = 0; - while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) - priority++; - return priority; -} - -/* return the pic wanted interrupt. return -1 if none */ -static int pic_get_irq(PicState *s) -{ - int mask, cur_priority, priority; - - mask = s->irr & ~s->imr; - priority = get_priority(s, mask); - if (priority == 8) - return -1; - /* compute current priority. If special fully nested mode on the - master, the IRQ coming from the slave is not taken into account - for the priority computation. */ - mask = s->isr; - if (s->special_fully_nested_mode && s == &pics[0]) - mask &= ~(1 << 2); - cur_priority = get_priority(s, mask); - if (priority < cur_priority) { - /* higher priority found: an irq should be generated */ - return (priority + s->priority_add) & 7; - } else { - return -1; - } -} - -/* raise irq to CPU if necessary. must be called every time the active - irq may change */ -void pic_update_irq(void) -{ - int irq2, irq; - - /* first look at slave pic */ - irq2 = pic_get_irq(&pics[1]); - if (irq2 >= 0) { - /* if irq request by slave pic, signal master PIC */ - pic_set_irq1(&pics[0], 2, 1); - pic_set_irq1(&pics[0], 2, 0); - } - /* look at requested irq */ - irq = pic_get_irq(&pics[0]); - if (irq >= 0) { - if (irq == 2) { - /* from slave pic */ - pic_irq_requested = 8 + irq2; - } else { - /* from master pic */ - pic_irq_requested = irq; - } -#if defined(DEBUG_PIC) - { - int i; - for(i = 0; i < 2; i++) { - printf("pic%d: imr=%x irr=%x padd=%d\n", - i, pics[i].imr, pics[i].irr, pics[i].priority_add); - - } - } - printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); -#endif - cpu_interrupt(global_env, CPU_INTERRUPT_HARD); - } -} - -#ifdef DEBUG_IRQ_LATENCY -int64_t irq_time[16]; -int64_t cpu_get_ticks(void); -#endif -#if defined(DEBUG_PIC) -int irq_level[16]; -#endif - -void pic_set_irq(int irq, int level) -{ -#if defined(DEBUG_PIC) - if (level != irq_level[irq]) { - printf("pic_set_irq: irq=%d level=%d\n", irq, level); - irq_level[irq] = level; - } -#endif -#ifdef DEBUG_IRQ_LATENCY - if (level) { - irq_time[irq] = cpu_get_ticks(); - } -#endif - pic_set_irq1(&pics[irq >> 3], irq & 7, level); - pic_update_irq(); -} - -/* acknowledge interrupt 'irq' */ -static inline void pic_intack(PicState *s, int irq) -{ - if (s->auto_eoi) { - if (s->rotate_on_auto_eoi) - s->priority_add = (irq + 1) & 7; - } else { - s->isr |= (1 << irq); - } - s->irr &= ~(1 << irq); -} - -int cpu_x86_get_pic_interrupt(CPUState *env) -{ - int irq, irq2, intno; - - /* signal the pic that the irq was acked by the CPU */ - irq = pic_irq_requested; -#ifdef DEBUG_IRQ_LATENCY - printf("IRQ%d latency=%0.3fus\n", - irq, - (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); -#endif -#if defined(DEBUG_PIC) - printf("pic_interrupt: irq=%d\n", irq); -#endif - - if (irq >= 8) { - irq2 = irq & 7; - pic_intack(&pics[1], irq2); - irq = 2; - intno = pics[1].irq_base + irq2; - } else { - intno = pics[0].irq_base + irq; - } - pic_intack(&pics[0], irq); - return intno; -} - -void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) -{ - PicState *s; - int priority, cmd, irq; - -#ifdef DEBUG_PIC - printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); -#endif - s = &pics[addr >> 7]; - addr &= 1; - if (addr == 0) { - if (val & 0x10) { - /* init */ - memset(s, 0, sizeof(PicState)); - s->init_state = 1; - s->init4 = val & 1; - if (val & 0x02) - hw_error("single mode not supported"); - if (val & 0x08) - hw_error("level sensitive irq not supported"); - } else if (val & 0x08) { - if (val & 0x04) - s->poll = 1; - if (val & 0x02) - s->read_reg_select = val & 1; - if (val & 0x40) - s->special_mask = (val >> 5) & 1; - } else { - cmd = val >> 5; - switch(cmd) { - case 0: - case 4: - s->rotate_on_auto_eoi = cmd >> 2; - break; - case 1: /* end of interrupt */ - case 5: - priority = get_priority(s, s->isr); - if (priority != 8) { - irq = (priority + s->priority_add) & 7; - s->isr &= ~(1 << irq); - if (cmd == 5) - s->priority_add = (irq + 1) & 7; - pic_update_irq(); - } - break; - case 3: - irq = val & 7; - s->isr &= ~(1 << irq); - pic_update_irq(); - break; - case 6: - s->priority_add = (val + 1) & 7; - pic_update_irq(); - break; - case 7: - irq = val & 7; - s->isr &= ~(1 << irq); - s->priority_add = (irq + 1) & 7; - pic_update_irq(); - break; - default: - /* no operation */ - break; - } - } - } else { - switch(s->init_state) { - case 0: - /* normal mode */ - s->imr = val; - pic_update_irq(); - break; - case 1: - s->irq_base = val & 0xf8; - s->init_state = 2; - break; - case 2: - if (s->init4) { - s->init_state = 3; - } else { - s->init_state = 0; - } - break; - case 3: - s->special_fully_nested_mode = (val >> 4) & 1; - s->auto_eoi = (val >> 1) & 1; - s->init_state = 0; - break; - } - } -} - -static uint32_t pic_poll_read (PicState *s, uint32_t addr1) -{ - int ret; - - ret = pic_get_irq(s); - if (ret >= 0) { - if (addr1 >> 7) { - pics[0].isr &= ~(1 << 2); - pics[0].irr &= ~(1 << 2); - } - s->irr &= ~(1 << ret); - s->isr &= ~(1 << ret); - if (addr1 >> 7 || ret != 2) - pic_update_irq(); - } else { - ret = 0x07; - pic_update_irq(); - } - - return ret; -} - -uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) -{ - PicState *s; - unsigned int addr; - int ret; - - addr = addr1; - s = &pics[addr >> 7]; - addr &= 1; - if (s->poll) { - ret = pic_poll_read(s, addr1); - s->poll = 0; - } else { - if (addr == 0) { - if (s->read_reg_select) - ret = s->isr; - else - ret = s->irr; - } else { - ret = s->imr; - } - } -#ifdef DEBUG_PIC - printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); -#endif - return ret; -} - -/* memory mapped interrupt status */ -uint32_t pic_intack_read(CPUState *env) -{ - int ret; - - ret = pic_poll_read(&pics[0], 0x00); - if (ret == 2) - ret = pic_poll_read(&pics[1], 0x80) + 8; - /* Prepare for ISR read */ - pics[0].read_reg_select = 1; - - return ret; -} - -void pic_init(void) -{ -#if defined (TARGET_I386) || defined (TARGET_PPC) - register_ioport_write(0x20, 2, pic_ioport_write, 1); - register_ioport_read(0x20, 2, pic_ioport_read, 1); - register_ioport_write(0xa0, 2, pic_ioport_write, 1); - register_ioport_read(0xa0, 2, pic_ioport_read, 1); -#endif -} - -/***********************************************************/ -/* 8253 PIT emulation */ - -#define PIT_FREQ 1193182 - -#define RW_STATE_LSB 0 -#define RW_STATE_MSB 1 -#define RW_STATE_WORD0 2 -#define RW_STATE_WORD1 3 -#define RW_STATE_LATCHED_WORD0 4 -#define RW_STATE_LATCHED_WORD1 5 - -typedef struct PITChannelState { - int count; /* can be 65536 */ - uint16_t latched_count; - uint8_t rw_state; - uint8_t mode; - uint8_t bcd; /* not supported */ - uint8_t gate; /* timer start */ - int64_t count_load_time; - int64_t count_last_edge_check_time; -} PITChannelState; - -PITChannelState pit_channels[3]; -int speaker_data_on; -int dummy_refresh_clock; -int pit_min_timer_count = 0; - - #if defined(__powerpc__) static inline uint32_t get_tbl(void) @@ -1036,7 +366,7 @@ void cpu_calibrate_ticks(void) } /* compute with 96 bit intermediate result: (a*b)/c */ -static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) { union { uint64_t ll; @@ -1059,1809 +389,214 @@ static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) return res.ll; } -static int pit_get_count(PITChannelState *s) -{ - uint64_t d; - int counter; - - d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); - switch(s->mode) { - case 0: - case 1: - case 4: - case 5: - counter = (s->count - d) & 0xffff; - break; - case 3: - /* XXX: may be incorrect for odd counts */ - counter = s->count - ((2 * d) % s->count); - break; - default: - counter = s->count - (d % s->count); - break; - } - return counter; -} - -/* get pit output bit */ -static int pit_get_out(PITChannelState *s) -{ - uint64_t d; - int out; - - d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); - switch(s->mode) { - default: - case 0: - out = (d >= s->count); - break; - case 1: - out = (d < s->count); - break; - case 2: - if ((d % s->count) == 0 && d != 0) - out = 1; - else - out = 0; - break; - case 3: - out = (d % s->count) < ((s->count + 1) >> 1); - break; - case 4: - case 5: - out = (d == s->count); - break; - } - return out; -} - -/* get the number of 0 to 1 transitions we had since we call this - function */ -/* XXX: maybe better to use ticks precision to avoid getting edges - twice if checks are done at very small intervals */ -static int pit_get_out_edges(PITChannelState *s) -{ - uint64_t d1, d2; - int64_t ticks; - int ret, v; - - ticks = cpu_get_ticks(); - d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, - PIT_FREQ, ticks_per_sec); - d2 = muldiv64(ticks - s->count_load_time, - PIT_FREQ, ticks_per_sec); - s->count_last_edge_check_time = ticks; - switch(s->mode) { - default: - case 0: - if (d1 < s->count && d2 >= s->count) - ret = 1; - else - ret = 0; - break; - case 1: - ret = 0; - break; - case 2: - d1 /= s->count; - d2 /= s->count; - ret = d2 - d1; - break; - case 3: - v = s->count - ((s->count + 1) >> 1); - d1 = (d1 + v) / s->count; - d2 = (d2 + v) / s->count; - ret = d2 - d1; - break; - case 4: - case 5: - if (d1 < s->count && d2 >= s->count) - ret = 1; - else - ret = 0; - break; - } - return ret; -} - -/* val must be 0 or 1 */ -static inline void pit_set_gate(PITChannelState *s, int val) -{ - switch(s->mode) { - default: - case 0: - case 4: - /* XXX: just disable/enable counting */ - break; - case 1: - case 5: - if (s->gate < val) { - /* restart counting on rising edge */ - s->count_load_time = cpu_get_ticks(); - s->count_last_edge_check_time = s->count_load_time; - } - break; - case 2: - case 3: - if (s->gate < val) { - /* restart counting on rising edge */ - s->count_load_time = cpu_get_ticks(); - s->count_last_edge_check_time = s->count_load_time; - } - /* XXX: disable/enable counting */ - break; - } - s->gate = val; -} - -static inline void pit_load_count(PITChannelState *s, int val) -{ - if (val == 0) - val = 0x10000; - s->count_load_time = cpu_get_ticks(); - s->count_last_edge_check_time = s->count_load_time; - s->count = val; - if (s == &pit_channels[0] && val <= pit_min_timer_count) { - fprintf(stderr, - "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", - PIT_FREQ / pit_min_timer_count); - } -} - -void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) -{ - int channel, access; - PITChannelState *s; - - addr &= 3; - if (addr == 3) { - channel = val >> 6; - if (channel == 3) - return; - s = &pit_channels[channel]; - access = (val >> 4) & 3; - switch(access) { - case 0: - s->latched_count = pit_get_count(s); - s->rw_state = RW_STATE_LATCHED_WORD0; - break; - default: - s->mode = (val >> 1) & 7; - s->bcd = val & 1; - s->rw_state = access - 1 + RW_STATE_LSB; - break; - } - } else { - s = &pit_channels[addr]; - switch(s->rw_state) { - case RW_STATE_LSB: - pit_load_count(s, val); - break; - case RW_STATE_MSB: - pit_load_count(s, val << 8); - break; - case RW_STATE_WORD0: - case RW_STATE_WORD1: - if (s->rw_state & 1) { - pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); - } else { - s->latched_count = val; - } - s->rw_state ^= 1; - break; - } - } -} - -uint32_t pit_ioport_read(CPUState *env, uint32_t addr) -{ - int ret, count; - PITChannelState *s; - - addr &= 3; - s = &pit_channels[addr]; - switch(s->rw_state) { - case RW_STATE_LSB: - case RW_STATE_MSB: - case RW_STATE_WORD0: - case RW_STATE_WORD1: - count = pit_get_count(s); - if (s->rw_state & 1) - ret = (count >> 8) & 0xff; - else - ret = count & 0xff; - if (s->rw_state & 2) - s->rw_state ^= 1; - break; - default: - case RW_STATE_LATCHED_WORD0: - case RW_STATE_LATCHED_WORD1: - if (s->rw_state & 1) - ret = s->latched_count >> 8; - else - ret = s->latched_count & 0xff; - s->rw_state ^= 1; - break; - } - return ret; -} - -#if defined (TARGET_I386) -void speaker_ioport_write(CPUState *env, uint32_t addr, uint32_t val) -{ - speaker_data_on = (val >> 1) & 1; - pit_set_gate(&pit_channels[2], val & 1); -} - -uint32_t speaker_ioport_read(CPUState *env, uint32_t addr) -{ - int out; - out = pit_get_out(&pit_channels[2]); - dummy_refresh_clock ^= 1; - return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | - (dummy_refresh_clock << 4); -} -#endif +#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ +static int term_got_escape, term_command; +static unsigned char term_cmd_buf[128]; -void pit_init(void) -{ - PITChannelState *s; - int i; +typedef struct term_cmd_t { + const unsigned char *name; + void (*handler)(unsigned char *params); +} term_cmd_t; - cpu_calibrate_ticks(); - - for(i = 0;i < 3; i++) { - s = &pit_channels[i]; - s->mode = 3; - s->gate = (i != 2); - pit_load_count(s, 0); - } - - register_ioport_write(0x40, 4, pit_ioport_write, 1); - register_ioport_read(0x40, 3, pit_ioport_read, 1); - -#if defined (TARGET_I386) - register_ioport_read(0x61, 1, speaker_ioport_read, 1); - register_ioport_write(0x61, 1, speaker_ioport_write, 1); -#endif -} - -/***********************************************************/ -/* serial port emulation */ - -#define UART_IRQ 4 - -#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ - -#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ -#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ -#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ -#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ - -#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ -#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ - -#define UART_IIR_MSI 0x00 /* Modem status interrupt */ -#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ -#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ -#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ - -/* - * These are the definitions for the Modem Control Register - */ -#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ -#define UART_MCR_OUT2 0x08 /* Out2 complement */ -#define UART_MCR_OUT1 0x04 /* Out1 complement */ -#define UART_MCR_RTS 0x02 /* RTS complement */ -#define UART_MCR_DTR 0x01 /* DTR complement */ - -/* - * These are the definitions for the Modem Status Register - */ -#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ -#define UART_MSR_RI 0x40 /* Ring Indicator */ -#define UART_MSR_DSR 0x20 /* Data Set Ready */ -#define UART_MSR_CTS 0x10 /* Clear to Send */ -#define UART_MSR_DDCD 0x08 /* Delta DCD */ -#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ -#define UART_MSR_DDSR 0x02 /* Delta DSR */ -#define UART_MSR_DCTS 0x01 /* Delta CTS */ -#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ - -#define UART_LSR_TEMT 0x40 /* Transmitter empty */ -#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ -#define UART_LSR_BI 0x10 /* Break interrupt indicator */ -#define UART_LSR_FE 0x08 /* Frame error indicator */ -#define UART_LSR_PE 0x04 /* Parity error indicator */ -#define UART_LSR_OE 0x02 /* Overrun error indicator */ -#define UART_LSR_DR 0x01 /* Receiver data ready */ - -typedef struct SerialState { - uint8_t divider; - uint8_t rbr; /* receive register */ - uint8_t ier; - uint8_t iir; /* read only */ - uint8_t lcr; - uint8_t mcr; - uint8_t lsr; /* read only */ - uint8_t msr; - uint8_t scr; - /* NOTE: this hidden state is necessary for tx irq generation as - it can be reset while reading iir */ - int thr_ipending; -} SerialState; - -SerialState serial_ports[1]; - -void serial_update_irq(void) -{ - SerialState *s = &serial_ports[0]; - - if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { - s->iir = UART_IIR_RDI; - } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { - s->iir = UART_IIR_THRI; - } else { - s->iir = UART_IIR_NO_INT; - } - if (s->iir != UART_IIR_NO_INT) { - pic_set_irq(UART_IRQ, 1); - } else { - pic_set_irq(UART_IRQ, 0); - } -} - -void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) -{ - SerialState *s = &serial_ports[0]; - unsigned char ch; - int ret; - - addr &= 7; -#ifdef DEBUG_SERIAL - printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); -#endif - switch(addr) { - default: - case 0: - if (s->lcr & UART_LCR_DLAB) { - s->divider = (s->divider & 0xff00) | val; - } else { - s->thr_ipending = 0; - s->lsr &= ~UART_LSR_THRE; - serial_update_irq(); - - ch = val; - do { - ret = write(1, &ch, 1); - } while (ret != 1); - s->thr_ipending = 1; - s->lsr |= UART_LSR_THRE; - s->lsr |= UART_LSR_TEMT; - serial_update_irq(); - } - break; - case 1: - if (s->lcr & UART_LCR_DLAB) { - s->divider = (s->divider & 0x00ff) | (val << 8); - } else { - s->ier = val; - serial_update_irq(); - } - break; - case 2: - break; - case 3: - s->lcr = val; - break; - case 4: - s->mcr = val; - break; - case 5: - break; - case 6: - s->msr = val; - break; - case 7: - s->scr = val; - break; - } -} - -uint32_t serial_ioport_read(CPUState *env, uint32_t addr) -{ - SerialState *s = &serial_ports[0]; - uint32_t ret; - - addr &= 7; - switch(addr) { - default: - case 0: - if (s->lcr & UART_LCR_DLAB) { - ret = s->divider & 0xff; - } else { - ret = s->rbr; - s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); - serial_update_irq(); - } - break; - case 1: - if (s->lcr & UART_LCR_DLAB) { - ret = (s->divider >> 8) & 0xff; - } else { - ret = s->ier; - } - break; - case 2: - ret = s->iir; - /* reset THR pending bit */ - if ((ret & 0x7) == UART_IIR_THRI) - s->thr_ipending = 0; - serial_update_irq(); - break; - case 3: - ret = s->lcr; - break; - case 4: - ret = s->mcr; - break; - case 5: - ret = s->lsr; - break; - case 6: - if (s->mcr & UART_MCR_LOOP) { - /* in loopback, the modem output pins are connected to the - inputs */ - ret = (s->mcr & 0x0c) << 4; - ret |= (s->mcr & 0x02) << 3; - ret |= (s->mcr & 0x01) << 5; - } else { - ret = s->msr; - } - break; - case 7: - ret = s->scr; - break; - } -#ifdef DEBUG_SERIAL - printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret); -#endif - return ret; -} - -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ -static int term_got_escape, term_command; -static unsigned char term_cmd_buf[128]; - -typedef struct term_cmd_t { - const unsigned char *name; - void (*handler)(unsigned char *params); -} term_cmd_t; - -static void do_change_cdrom (unsigned char *params); -static void do_change_fd0 (unsigned char *params); -static void do_change_fd1 (unsigned char *params); +static void do_change_cdrom (unsigned char *params); +static void do_change_fd0 (unsigned char *params); +static void do_change_fd1 (unsigned char *params); static term_cmd_t term_cmds[] = { { "changecd", &do_change_cdrom, }, { "changefd0", &do_change_fd0, }, { "changefd1", &do_change_fd1, }, - { NULL, NULL, }, -}; - -void term_print_help(void) -{ - printf("\n" - "C-a h print this help\n" - "C-a x exit emulatior\n" - "C-a d switch on/off debug log\n" - "C-a s save disk data back to file (if -snapshot)\n" - "C-a b send break (magic sysrq)\n" - "C-a c send qemu internal command\n" - "C-a C-a send C-a\n" - ); -} - -static void do_change_cdrom (unsigned char *params) -{ - /* Dunno how to do it... */ -} - -static void do_change_fd (int fd, unsigned char *params) -{ - unsigned char *name_start, *name_end, *ros; - int ro; - - for (name_start = params; - isspace(*name_start); name_start++) - continue; - if (*name_start == '\0') - return; - for (name_end = name_start; - !isspace(*name_end) && *name_end != '\0'; name_end++) - continue; - for (ros = name_end + 1; isspace(*ros); ros++) - continue; - if (ros[0] == 'r' && ros[1] == 'o') - ro = 1; - else - ro = 0; - *name_end = '\0'; - printf("Change fd %d to %s (%s)\n", fd, name_start, params); - fdctrl_disk_change(fd, name_start, ro); -} - -static void do_change_fd0 (unsigned char *params) -{ - do_change_fd(0, params); -} - -static void do_change_fd1 (unsigned char *params) -{ - do_change_fd(1, params); -} - -static void serial_treat_command () -{ - unsigned char *cmd_start, *cmd_end; - int i; - - for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++) - continue; - for (cmd_end = cmd_start; - !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++) - continue; - for (i = 0; term_cmds[i].name != NULL; i++) { - if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) && - memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) { - (*term_cmds[i].handler)(cmd_end + 1); - return; - } - } - *cmd_end = '\0'; - printf("Unknown term command: %s\n", cmd_start); -} - -extern FILE *logfile; - -/* called when a char is received */ -void serial_received_byte(SerialState *s, int ch) -{ - if (term_command) { - if (ch == '\n' || ch == '\r' || term_command == 127) { - printf("\n"); - serial_treat_command(); - term_command = 0; - } else { - if (ch == 0x7F || ch == 0x08) { - if (term_command > 1) { - term_cmd_buf[--term_command - 1] = '\0'; - printf("\r " - " "); - printf("\r> %s", term_cmd_buf); - } - } else if (ch > 0x1f) { - term_cmd_buf[term_command++ - 1] = ch; - term_cmd_buf[term_command - 1] = '\0'; - printf("\r> %s", term_cmd_buf); - } - fflush(stdout); - } - } else if (term_got_escape) { - term_got_escape = 0; - switch(ch) { - case 'h': - term_print_help(); - break; - case 'x': - exit(0); - break; - case 's': - { - int i; - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) - bdrv_commit(bs_table[i]); - } - } - break; - case 'b': - /* send break */ - s->rbr = 0; - s->lsr |= UART_LSR_BI | UART_LSR_DR; - serial_update_irq(); - break; - case 'c': - printf("> "); - fflush(stdout); - term_command = 1; - break; - case 'd': - cpu_set_log(CPU_LOG_ALL); - break; - case TERM_ESCAPE: - goto send_char; - } - } else if (ch == TERM_ESCAPE) { - term_got_escape = 1; - } else { - send_char: - s->rbr = ch; - s->lsr |= UART_LSR_DR; - serial_update_irq(); - } -} - -void serial_init(void) -{ - SerialState *s = &serial_ports[0]; - - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; - s->iir = UART_IIR_NO_INT; - -#if defined(TARGET_I386) || defined (TARGET_PPC) - register_ioport_write(0x3f8, 8, serial_ioport_write, 1); - register_ioport_read(0x3f8, 8, serial_ioport_read, 1); -#endif -} - -/***********************************************************/ -/* ne2000 emulation */ - -#if defined (TARGET_I386) -#define NE2000_IOPORT 0x300 -#define NE2000_IRQ 9 - -#define MAX_ETH_FRAME_SIZE 1514 - -#define E8390_CMD 0x00 /* The command register (for all pages) */ -/* Page 0 register offsets. */ -#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ -#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ -#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ -#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ -#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ -#define EN0_TSR 0x04 /* Transmit status reg RD */ -#define EN0_TPSR 0x04 /* Transmit starting page WR */ -#define EN0_NCR 0x05 /* Number of collision reg RD */ -#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ -#define EN0_FIFO 0x06 /* FIFO RD */ -#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ -#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ -#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ -#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ -#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ -#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ -#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ -#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ -#define EN0_RSR 0x0c /* rx status reg RD */ -#define EN0_RXCR 0x0c /* RX configuration reg WR */ -#define EN0_TXCR 0x0d /* TX configuration reg WR */ -#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ -#define EN0_DCFG 0x0e /* Data configuration reg WR */ -#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ -#define EN0_IMR 0x0f /* Interrupt mask reg WR */ -#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ - -#define EN1_PHYS 0x11 -#define EN1_CURPAG 0x17 -#define EN1_MULT 0x18 - -/* Register accessed at EN_CMD, the 8390 base addr. */ -#define E8390_STOP 0x01 /* Stop and reset the chip */ -#define E8390_START 0x02 /* Start the chip, clear reset */ -#define E8390_TRANS 0x04 /* Transmit a frame */ -#define E8390_RREAD 0x08 /* Remote read */ -#define E8390_RWRITE 0x10 /* Remote write */ -#define E8390_NODMA 0x20 /* Remote DMA */ -#define E8390_PAGE0 0x00 /* Select page chip registers */ -#define E8390_PAGE1 0x40 /* using the two high-order bits */ -#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ - -/* Bits in EN0_ISR - Interrupt status register */ -#define ENISR_RX 0x01 /* Receiver, no error */ -#define ENISR_TX 0x02 /* Transmitter, no error */ -#define ENISR_RX_ERR 0x04 /* Receiver, with error */ -#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ -#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ -#define ENISR_COUNTERS 0x20 /* Counters need emptying */ -#define ENISR_RDC 0x40 /* remote dma complete */ -#define ENISR_RESET 0x80 /* Reset completed */ -#define ENISR_ALL 0x3f /* Interrupts we will enable */ - -/* Bits in received packet status byte and EN0_RSR*/ -#define ENRSR_RXOK 0x01 /* Received a good packet */ -#define ENRSR_CRC 0x02 /* CRC error */ -#define ENRSR_FAE 0x04 /* frame alignment error */ -#define ENRSR_FO 0x08 /* FIFO overrun */ -#define ENRSR_MPA 0x10 /* missed pkt */ -#define ENRSR_PHY 0x20 /* physical/multicast address */ -#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ -#define ENRSR_DEF 0x80 /* deferring */ - -/* Transmitted packet status, EN0_TSR. */ -#define ENTSR_PTX 0x01 /* Packet transmitted without error */ -#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ -#define ENTSR_COL 0x04 /* The transmit collided at least once. */ -#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ -#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ -#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ -#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ -#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ - -#define NE2000_MEM_SIZE 32768 - -typedef struct NE2000State { - uint8_t cmd; - uint32_t start; - uint32_t stop; - uint8_t boundary; - uint8_t tsr; - uint8_t tpsr; - uint16_t tcnt; - uint16_t rcnt; - uint32_t rsar; - uint8_t isr; - uint8_t dcfg; - uint8_t imr; - uint8_t phys[6]; /* mac address */ - uint8_t curpag; - uint8_t mult[8]; /* multicast mask array */ - uint8_t mem[NE2000_MEM_SIZE]; -} NE2000State; - -NE2000State ne2000_state; -int net_fd = -1; -char network_script[1024]; - -void ne2000_reset(void) -{ - NE2000State *s = &ne2000_state; - int i; - - s->isr = ENISR_RESET; - s->mem[0] = 0x52; - s->mem[1] = 0x54; - s->mem[2] = 0x00; - s->mem[3] = 0x12; - s->mem[4] = 0x34; - s->mem[5] = 0x56; - s->mem[14] = 0x57; - s->mem[15] = 0x57; - - /* duplicate prom data */ - for(i = 15;i >= 0; i--) { - s->mem[2 * i] = s->mem[i]; - s->mem[2 * i + 1] = s->mem[i]; - } -} - -void ne2000_update_irq(NE2000State *s) -{ - int isr; - isr = s->isr & s->imr; - if (isr) - pic_set_irq(NE2000_IRQ, 1); - else - pic_set_irq(NE2000_IRQ, 0); -} - -int net_init(void) -{ - struct ifreq ifr; - int fd, ret, pid, status; - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) { - fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); - return -1; - } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d"); - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - if (ret != 0) { - fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); - close(fd); - return -1; - } - printf("Connected to host network interface: %s\n", ifr.ifr_name); - fcntl(fd, F_SETFL, O_NONBLOCK); - net_fd = fd; - - /* try to launch network init script */ - pid = fork(); - if (pid >= 0) { - if (pid == 0) { - execl(network_script, network_script, ifr.ifr_name, NULL); - exit(1); - } - while (waitpid(pid, &status, 0) != pid); - if (!WIFEXITED(status) || - WEXITSTATUS(status) != 0) { - fprintf(stderr, "%s: could not launch network script for '%s'\n", - network_script, ifr.ifr_name); - } - } - return 0; -} - -void net_send_packet(NE2000State *s, const uint8_t *buf, int size) -{ -#ifdef DEBUG_NE2000 - printf("NE2000: sending packet size=%d\n", size); -#endif - write(net_fd, buf, size); -} - -/* return true if the NE2000 can receive more data */ -int ne2000_can_receive(NE2000State *s) -{ - int avail, index, boundary; - - if (s->cmd & E8390_STOP) - return 0; - index = s->curpag << 8; - boundary = s->boundary << 8; - if (index < boundary) - avail = boundary - index; - else - avail = (s->stop - s->start) - (index - boundary); - if (avail < (MAX_ETH_FRAME_SIZE + 4)) - return 0; - return 1; -} - -void ne2000_receive(NE2000State *s, uint8_t *buf, int size) -{ - uint8_t *p; - int total_len, next, avail, len, index; - -#if defined(DEBUG_NE2000) - printf("NE2000: received len=%d\n", size); -#endif - - index = s->curpag << 8; - /* 4 bytes for header */ - total_len = size + 4; - /* address for next packet (4 bytes for CRC) */ - next = index + ((total_len + 4 + 255) & ~0xff); - if (next >= s->stop) - next -= (s->stop - s->start); - /* prepare packet header */ - p = s->mem + index; - p[0] = ENRSR_RXOK; /* receive status */ - p[1] = next >> 8; - p[2] = total_len; - p[3] = total_len >> 8; - index += 4; - - /* write packet data */ - while (size > 0) { - avail = s->stop - index; - len = size; - if (len > avail) - len = avail; - memcpy(s->mem + index, buf, len); - buf += len; - index += len; - if (index == s->stop) - index = s->start; - size -= len; - } - s->curpag = next >> 8; - - /* now we can signal we have receive something */ - s->isr |= ENISR_RX; - ne2000_update_irq(s); -} - -void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) -{ - NE2000State *s = &ne2000_state; - int offset, page; - - addr &= 0xf; -#ifdef DEBUG_NE2000 - printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val); -#endif - if (addr == E8390_CMD) { - /* control register */ - s->cmd = val; - if (val & E8390_START) { - /* test specific case: zero length transfert */ - if ((val & (E8390_RREAD | E8390_RWRITE)) && - s->rcnt == 0) { - s->isr |= ENISR_RDC; - ne2000_update_irq(s); - } - if (val & E8390_TRANS) { - net_send_packet(s, s->mem + (s->tpsr << 8), s->tcnt); - /* signal end of transfert */ - s->tsr = ENTSR_PTX; - s->isr |= ENISR_TX; - ne2000_update_irq(s); - } - } - } else { - page = s->cmd >> 6; - offset = addr | (page << 4); - switch(offset) { - case EN0_STARTPG: - s->start = val << 8; - break; - case EN0_STOPPG: - s->stop = val << 8; - break; - case EN0_BOUNDARY: - s->boundary = val; - break; - case EN0_IMR: - s->imr = val; - ne2000_update_irq(s); - break; - case EN0_TPSR: - s->tpsr = val; - break; - case EN0_TCNTLO: - s->tcnt = (s->tcnt & 0xff00) | val; - break; - case EN0_TCNTHI: - s->tcnt = (s->tcnt & 0x00ff) | (val << 8); - break; - case EN0_RSARLO: - s->rsar = (s->rsar & 0xff00) | val; - break; - case EN0_RSARHI: - s->rsar = (s->rsar & 0x00ff) | (val << 8); - break; - case EN0_RCNTLO: - s->rcnt = (s->rcnt & 0xff00) | val; - break; - case EN0_RCNTHI: - s->rcnt = (s->rcnt & 0x00ff) | (val << 8); - break; - case EN0_DCFG: - s->dcfg = val; - break; - case EN0_ISR: - s->isr &= ~val; - ne2000_update_irq(s); - break; - case EN1_PHYS ... EN1_PHYS + 5: - s->phys[offset - EN1_PHYS] = val; - break; - case EN1_CURPAG: - s->curpag = val; - break; - case EN1_MULT ... EN1_MULT + 7: - s->mult[offset - EN1_MULT] = val; - break; - } - } -} - -uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) -{ - NE2000State *s = &ne2000_state; - int offset, page, ret; - - addr &= 0xf; - if (addr == E8390_CMD) { - ret = s->cmd; - } else { - page = s->cmd >> 6; - offset = addr | (page << 4); - switch(offset) { - case EN0_TSR: - ret = s->tsr; - break; - case EN0_BOUNDARY: - ret = s->boundary; - break; - case EN0_ISR: - ret = s->isr; - break; - case EN1_PHYS ... EN1_PHYS + 5: - ret = s->phys[offset - EN1_PHYS]; - break; - case EN1_CURPAG: - ret = s->curpag; - break; - case EN1_MULT ... EN1_MULT + 7: - ret = s->mult[offset - EN1_MULT]; - break; - default: - ret = 0x00; - break; - } - } -#ifdef DEBUG_NE2000 - printf("NE2000: read addr=0x%x val=%02x\n", addr, ret); -#endif - return ret; -} - -void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) -{ - NE2000State *s = &ne2000_state; - uint8_t *p; - -#ifdef DEBUG_NE2000 - printf("NE2000: asic write val=0x%04x\n", val); -#endif - p = s->mem + s->rsar; - if (s->dcfg & 0x01) { - /* 16 bit access */ - p[0] = val; - p[1] = val >> 8; - s->rsar += 2; - s->rcnt -= 2; - } else { - /* 8 bit access */ - p[0] = val; - s->rsar++; - s->rcnt--; - } - /* wrap */ - if (s->rsar == s->stop) - s->rsar = s->start; - if (s->rcnt == 0) { - /* signal end of transfert */ - s->isr |= ENISR_RDC; - ne2000_update_irq(s); - } -} - -uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) -{ - NE2000State *s = &ne2000_state; - uint8_t *p; - int ret; - - p = s->mem + s->rsar; - if (s->dcfg & 0x01) { - /* 16 bit access */ - ret = p[0] | (p[1] << 8); - s->rsar += 2; - s->rcnt -= 2; - } else { - /* 8 bit access */ - ret = p[0]; - s->rsar++; - s->rcnt--; - } - /* wrap */ - if (s->rsar == s->stop) - s->rsar = s->start; - if (s->rcnt == 0) { - /* signal end of transfert */ - s->isr |= ENISR_RDC; - ne2000_update_irq(s); - } -#ifdef DEBUG_NE2000 - printf("NE2000: asic read val=0x%04x\n", ret); -#endif - return ret; -} - -void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val) -{ - /* nothing to do (end of reset pulse) */ -} - -uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr) -{ - ne2000_reset(); - return 0; -} - -void ne2000_init(void) -{ - register_ioport_write(NE2000_IOPORT, 16, ne2000_ioport_write, 1); - register_ioport_read(NE2000_IOPORT, 16, ne2000_ioport_read, 1); - - register_ioport_write(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_write, 1); - register_ioport_read(NE2000_IOPORT + 0x10, 1, ne2000_asic_ioport_read, 1); - register_ioport_write(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_write, 2); - register_ioport_read(NE2000_IOPORT + 0x10, 2, ne2000_asic_ioport_read, 2); - - register_ioport_write(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_write, 1); - register_ioport_read(NE2000_IOPORT + 0x1f, 1, ne2000_reset_ioport_read, 1); - ne2000_reset(); -} -#endif - -/***********************************************************/ -/* PC floppy disk controler emulation glue */ -#define PC_FDC_DMA 0x2 -#define PC_FDC_IRQ 0x6 -#define PC_FDC_BASE 0x3F0 - -static void fdctrl_register (unsigned char **disknames, int ro, - char boot_device) -{ - int i; - - fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device); - for (i = 0; i < MAX_FD; i++) { - if (disknames[i] != NULL) - fdctrl_disk_change(i, disknames[i], ro); - } -} - -/***********************************************************/ -/* keyboard emulation */ - -/* Keyboard Controller Commands */ -#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ -#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ -#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ -#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ -#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ -#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ -#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ -#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ -#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ -#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ -#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ -#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ -#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ -#define KBD_CCMD_WRITE_OBUF 0xD2 -#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if - initiated by the auxiliary device */ -#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ -#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ -#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ -#define KBD_CCMD_RESET 0xFE - -/* Keyboard Commands */ -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_ECHO 0xEE -#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ -#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ - -/* Keyboard Replies */ -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - -/* Status Register Bits */ -#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ -#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ -#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ -#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ -#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ -#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ -#define KBD_STAT_PERR 0x80 /* Parity error */ - -/* Controller Mode Register Bits */ -#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ -#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ -#define KBD_MODE_SYS 0x04 /* The system flag (?) */ -#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ -#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ -#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ -#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ -#define KBD_MODE_RFU 0x80 - -/* Mouse Commands */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_POLL 0xEB /* Poll */ -#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ -#define AUX_SET_WRAP 0xEE /* Set wrap mode */ -#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ -#define AUX_GET_TYPE 0xF2 /* Get type */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_SET_DEFAULT 0xF6 -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ - -#define MOUSE_STATUS_REMOTE 0x40 -#define MOUSE_STATUS_ENABLED 0x20 -#define MOUSE_STATUS_SCALE21 0x10 - -#define KBD_QUEUE_SIZE 256 - -typedef struct { - uint8_t data[KBD_QUEUE_SIZE]; - int rptr, wptr, count; -} KBDQueue; - -typedef struct KBDState { - KBDQueue queues[2]; - uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ - uint8_t status; - uint8_t mode; - /* keyboard state */ - int kbd_write_cmd; - int scan_enabled; - /* mouse state */ - int mouse_write_cmd; - uint8_t mouse_status; - uint8_t mouse_resolution; - uint8_t mouse_sample_rate; - uint8_t mouse_wrap; - uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ - uint8_t mouse_detect_state; - int mouse_dx; /* current values, needed for 'poll' mode */ - int mouse_dy; - int mouse_dz; - uint8_t mouse_buttons; -} KBDState; - -KBDState kbd_state; -int reset_requested; - -/* update irq and KBD_STAT_[MOUSE_]OBF */ -/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be - incorrect, but it avoids having to simulate exact delays */ -static void kbd_update_irq(KBDState *s) -{ - int irq12_level, irq1_level; - - irq1_level = 0; - irq12_level = 0; - s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); - if (s->queues[0].count != 0 || - s->queues[1].count != 0) { - s->status |= KBD_STAT_OBF; - if (s->queues[1].count != 0) { - s->status |= KBD_STAT_MOUSE_OBF; - if (s->mode & KBD_MODE_MOUSE_INT) - irq12_level = 1; - } else { - if ((s->mode & KBD_MODE_KBD_INT) && - !(s->mode & KBD_MODE_DISABLE_KBD)) - irq1_level = 1; - } - } - pic_set_irq(1, irq1_level); - pic_set_irq(12, irq12_level); -} - -static void kbd_queue(KBDState *s, int b, int aux) -{ - KBDQueue *q = &kbd_state.queues[aux]; - -#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) - if (aux) - printf("mouse event: 0x%02x\n", b); -#ifdef DEBUG_KBD - else - printf("kbd event: 0x%02x\n", b); -#endif -#endif - if (q->count >= KBD_QUEUE_SIZE) - return; - q->data[q->wptr] = b; - if (++q->wptr == KBD_QUEUE_SIZE) - q->wptr = 0; - q->count++; - kbd_update_irq(s); -} - -void kbd_put_keycode(int keycode) -{ - KBDState *s = &kbd_state; - kbd_queue(s, keycode, 0); -} + { NULL, NULL, }, +}; -uint32_t kbd_read_status(CPUState *env, uint32_t addr) +void term_print_help(void) { - KBDState *s = &kbd_state; - int val; - val = s->status; -#if defined(DEBUG_KBD) - printf("kbd: read status=0x%02x\n", val); -#endif - return val; + printf("\n" + "C-a h print this help\n" + "C-a x exit emulatior\n" + "C-a d switch on/off debug log\n" + "C-a s save disk data back to file (if -snapshot)\n" + "C-a b send break (magic sysrq)\n" + "C-a c send qemu internal command\n" + "C-a C-a send C-a\n" + ); } -void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) +static void do_change_cdrom (unsigned char *params) { - KBDState *s = &kbd_state; - -#ifdef DEBUG_KBD - printf("kbd: write cmd=0x%02x\n", val); -#endif - switch(val) { - case KBD_CCMD_READ_MODE: - kbd_queue(s, s->mode, 0); - break; - case KBD_CCMD_WRITE_MODE: - case KBD_CCMD_WRITE_OBUF: - case KBD_CCMD_WRITE_AUX_OBUF: - case KBD_CCMD_WRITE_MOUSE: - case KBD_CCMD_WRITE_OUTPORT: - s->write_cmd = val; - break; - case KBD_CCMD_MOUSE_DISABLE: - s->mode |= KBD_MODE_DISABLE_MOUSE; - break; - case KBD_CCMD_MOUSE_ENABLE: - s->mode &= ~KBD_MODE_DISABLE_MOUSE; - break; - case KBD_CCMD_TEST_MOUSE: - kbd_queue(s, 0x00, 0); - break; - case KBD_CCMD_SELF_TEST: - s->status |= KBD_STAT_SELFTEST; - kbd_queue(s, 0x55, 0); - break; - case KBD_CCMD_KBD_TEST: - kbd_queue(s, 0x00, 0); - break; - case KBD_CCMD_KBD_DISABLE: - s->mode |= KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); - break; - case KBD_CCMD_KBD_ENABLE: - s->mode &= ~KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); - break; - case KBD_CCMD_READ_INPORT: - kbd_queue(s, 0x00, 0); - break; - case KBD_CCMD_READ_OUTPORT: - /* XXX: check that */ -#ifdef TARGET_I386 - val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1); -#else - val = 0x01; -#endif - if (s->status & KBD_STAT_OBF) - val |= 0x10; - if (s->status & KBD_STAT_MOUSE_OBF) - val |= 0x20; - kbd_queue(s, val, 0); - break; -#ifdef TARGET_I386 - case KBD_CCMD_ENABLE_A20: - cpu_x86_set_a20(env, 1); - break; - case KBD_CCMD_DISABLE_A20: - cpu_x86_set_a20(env, 0); - break; -#endif - case KBD_CCMD_RESET: - reset_requested = 1; - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); - break; - case 0xff: - /* ignore that - I don't know what is its use */ - break; - default: - fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); - break; - } + /* Dunno how to do it... */ } -uint32_t kbd_read_data(CPUState *env, uint32_t addr) +static void do_change_fd (int fd, unsigned char *params) { - KBDState *s = &kbd_state; - KBDQueue *q; - int val, index; - - q = &s->queues[0]; /* first check KBD data */ - if (q->count == 0) - q = &s->queues[1]; /* then check AUX data */ - if (q->count == 0) { - /* NOTE: if no data left, we return the last keyboard one - (needed for EMM386) */ - /* XXX: need a timer to do things correctly */ - q = &s->queues[0]; - index = q->rptr - 1; - if (index < 0) - index = KBD_QUEUE_SIZE - 1; - val = q->data[index]; - } else { - val = q->data[q->rptr]; - if (++q->rptr == KBD_QUEUE_SIZE) - q->rptr = 0; - q->count--; - /* reading deasserts IRQ */ - if (q == &s->queues[0]) - pic_set_irq(1, 0); - else - pic_set_irq(12, 0); - } - /* reassert IRQs if data left */ - kbd_update_irq(s); -#ifdef DEBUG_KBD - printf("kbd: read data=0x%02x\n", val); -#endif - return val; -} + unsigned char *name_start, *name_end, *ros; + int ro; -static void kbd_reset_keyboard(KBDState *s) -{ - s->scan_enabled = 1; + for (name_start = params; + isspace(*name_start); name_start++) + continue; + if (*name_start == '\0') + return; + for (name_end = name_start; + !isspace(*name_end) && *name_end != '\0'; name_end++) + continue; + for (ros = name_end + 1; isspace(*ros); ros++) + continue; + if (ros[0] == 'r' && ros[1] == 'o') + ro = 1; + else + ro = 0; + *name_end = '\0'; + printf("Change fd %d to %s (%s)\n", fd, name_start, params); + fdctrl_disk_change(fd, name_start, ro); } -static void kbd_write_keyboard(KBDState *s, int val) +static void do_change_fd0 (unsigned char *params) { - switch(s->kbd_write_cmd) { - default: - case -1: - switch(val) { - case 0x00: - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case 0x05: - kbd_queue(s, KBD_REPLY_RESEND, 0); - break; - case KBD_CMD_GET_ID: - kbd_queue(s, KBD_REPLY_ACK, 0); - kbd_queue(s, 0xab, 0); - kbd_queue(s, 0x83, 0); - break; - case KBD_CMD_ECHO: - kbd_queue(s, KBD_CMD_ECHO, 0); - break; - case KBD_CMD_ENABLE: - s->scan_enabled = 1; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_SET_LEDS: - case KBD_CMD_SET_RATE: - s->kbd_write_cmd = val; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET_DISABLE: - kbd_reset_keyboard(s); - s->scan_enabled = 0; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET_ENABLE: - kbd_reset_keyboard(s); - s->scan_enabled = 1; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET: - kbd_reset_keyboard(s); - kbd_queue(s, KBD_REPLY_ACK, 0); - kbd_queue(s, KBD_REPLY_POR, 0); - break; - default: - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - } - break; - case KBD_CMD_SET_LEDS: - kbd_queue(s, KBD_REPLY_ACK, 0); - s->kbd_write_cmd = -1; - break; - case KBD_CMD_SET_RATE: - kbd_queue(s, KBD_REPLY_ACK, 0); - s->kbd_write_cmd = -1; - break; - } + do_change_fd(0, params); } -static void kbd_mouse_send_packet(KBDState *s) +static void do_change_fd1 (unsigned char *params) { - unsigned int b; - int dx1, dy1, dz1; - - dx1 = s->mouse_dx; - dy1 = s->mouse_dy; - dz1 = s->mouse_dz; - /* XXX: increase range to 8 bits ? */ - if (dx1 > 127) - dx1 = 127; - else if (dx1 < -127) - dx1 = -127; - if (dy1 > 127) - dy1 = 127; - else if (dy1 < -127) - dy1 = -127; - b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); - kbd_queue(s, b, 1); - kbd_queue(s, dx1 & 0xff, 1); - kbd_queue(s, dy1 & 0xff, 1); - /* extra byte for IMPS/2 or IMEX */ - switch(s->mouse_type) { - default: - break; - case 3: - if (dz1 > 127) - dz1 = 127; - else if (dz1 < -127) - dz1 = -127; - kbd_queue(s, dz1 & 0xff, 1); - break; - case 4: - if (dz1 > 7) - dz1 = 7; - else if (dz1 < -7) - dz1 = -7; - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); - kbd_queue(s, b, 1); - break; - } - - /* update deltas */ - s->mouse_dx -= dx1; - s->mouse_dy -= dy1; - s->mouse_dz -= dz1; + do_change_fd(1, params); } -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) +static void term_treat_command(void) { - KBDState *s = &kbd_state; - - /* check if deltas are recorded when disabled */ - if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) - return; + unsigned char *cmd_start, *cmd_end; + int i; - s->mouse_dx += dx; - s->mouse_dy -= dy; - s->mouse_dz += dz; - s->mouse_buttons = buttons_state; - - if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && - (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { - for(;;) { - /* if not remote, send event. Multiple events are sent if - too big deltas */ - kbd_mouse_send_packet(s); - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) - break; + for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++) + continue; + for (cmd_end = cmd_start; + !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++) + continue; + for (i = 0; term_cmds[i].name != NULL; i++) { + if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) && + memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) { + (*term_cmds[i].handler)(cmd_end + 1); + return; } } + *cmd_end = '\0'; + printf("Unknown term command: %s\n", cmd_start); } -static void kbd_write_mouse(KBDState *s, int val) +extern FILE *logfile; + +/* called when a char is received */ +void term_received_byte(int ch) { -#ifdef DEBUG_MOUSE - printf("kbd: write mouse 0x%02x\n", val); -#endif - switch(s->mouse_write_cmd) { - default: - case -1: - /* mouse command */ - if (s->mouse_wrap) { - if (val == AUX_RESET_WRAP) { - s->mouse_wrap = 0; - kbd_queue(s, AUX_ACK, 1); - return; - } else if (val != AUX_RESET) { - kbd_queue(s, val, 1); - return; + if (term_command) { + if (ch == '\n' || ch == '\r' || term_command == 127) { + printf("\n"); + term_treat_command(); + term_command = 0; + } else { + if (ch == 0x7F || ch == 0x08) { + if (term_command > 1) { + term_cmd_buf[--term_command - 1] = '\0'; + printf("\r " + " "); + printf("\r> %s", term_cmd_buf); + } + } else if (ch > 0x1f) { + term_cmd_buf[term_command++ - 1] = ch; + term_cmd_buf[term_command - 1] = '\0'; + printf("\r> %s", term_cmd_buf); } + fflush(stdout); } - switch(val) { - case AUX_SET_SCALE11: - s->mouse_status &= ~MOUSE_STATUS_SCALE21; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_SCALE21: - s->mouse_status |= MOUSE_STATUS_SCALE21; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_STREAM: - s->mouse_status &= ~MOUSE_STATUS_REMOTE; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_WRAP: - s->mouse_wrap = 1; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_REMOTE: - s->mouse_status |= MOUSE_STATUS_REMOTE; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_GET_TYPE: - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, s->mouse_type, 1); - break; - case AUX_SET_RES: - case AUX_SET_SAMPLE: - s->mouse_write_cmd = val; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_GET_SCALE: - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, s->mouse_status, 1); - kbd_queue(s, s->mouse_resolution, 1); - kbd_queue(s, s->mouse_sample_rate, 1); - break; - case AUX_POLL: - kbd_queue(s, AUX_ACK, 1); - kbd_mouse_send_packet(s); - break; - case AUX_ENABLE_DEV: - s->mouse_status |= MOUSE_STATUS_ENABLED; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_DISABLE_DEV: - s->mouse_status &= ~MOUSE_STATUS_ENABLED; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_DEFAULT: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_RESET: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, 0xaa, 1); - kbd_queue(s, s->mouse_type, 1); + } else if (term_got_escape) { + term_got_escape = 0; + switch(ch) { + case 'h': + term_print_help(); break; - default: + case 'x': + exit(0); break; - } - break; - case AUX_SET_SAMPLE: - s->mouse_sample_rate = val; -#if 0 - /* detect IMPS/2 or IMEX */ - switch(s->mouse_detect_state) { - default: - case 0: - if (val == 200) - s->mouse_detect_state = 1; + case 's': + { + int i; + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) + bdrv_commit(bs_table[i]); + } + } break; - case 1: - if (val == 100) - s->mouse_detect_state = 2; - else if (val == 200) - s->mouse_detect_state = 3; - else - s->mouse_detect_state = 0; + case 'b': + serial_receive_break(); break; - case 2: - if (val == 80) - s->mouse_type = 3; /* IMPS/2 */ - s->mouse_detect_state = 0; + case 'c': + printf("> "); + fflush(stdout); + term_command = 1; break; - case 3: - if (val == 80) - s->mouse_type = 4; /* IMEX */ - s->mouse_detect_state = 0; + case 'd': + cpu_set_log(CPU_LOG_ALL); break; + case TERM_ESCAPE: + goto send_char; } -#endif - kbd_queue(s, AUX_ACK, 1); - s->mouse_write_cmd = -1; - break; - case AUX_SET_RES: - s->mouse_resolution = val; - kbd_queue(s, AUX_ACK, 1); - s->mouse_write_cmd = -1; - break; + } else if (ch == TERM_ESCAPE) { + term_got_escape = 1; + } else { + send_char: + serial_receive_byte(ch); } } -void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val) -{ - KBDState *s = &kbd_state; - -#ifdef DEBUG_KBD - printf("kbd: write data=0x%02x\n", val); -#endif - - switch(s->write_cmd) { - case 0: - kbd_write_keyboard(s, val); - break; - case KBD_CCMD_WRITE_MODE: - s->mode = val; - kbd_update_irq(s); - break; - case KBD_CCMD_WRITE_OBUF: - kbd_queue(s, val, 0); - break; - case KBD_CCMD_WRITE_AUX_OBUF: - kbd_queue(s, val, 1); - break; - case KBD_CCMD_WRITE_OUTPORT: -#ifdef TARGET_I386 - cpu_x86_set_a20(env, (val >> 1) & 1); -#endif - if (!(val & 1)) { - reset_requested = 1; - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); - } - break; - case KBD_CCMD_WRITE_MOUSE: - kbd_write_mouse(s, val); - break; - default: - break; - } - s->write_cmd = 0; -} +/***********************************************************/ +/* Linux network device redirector */ -void kbd_reset(KBDState *s) +int net_init(void) { - KBDQueue *q; - int i; - - s->kbd_write_cmd = -1; - s->mouse_write_cmd = -1; - s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; - s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; - for(i = 0; i < 2; i++) { - q = &s->queues[i]; - q->rptr = 0; - q->wptr = 0; - q->count = 0; + struct ifreq ifr; + int fd, ret, pid, status; + + fd = open("/dev/net/tun", O_RDWR); + if (fd < 0) { + fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); + return -1; } -} - -void kbd_init(void) -{ - kbd_reset(&kbd_state); -#if defined (TARGET_I386) || defined (TARGET_PPC) - register_ioport_read(0x60, 1, kbd_read_data, 1); - register_ioport_write(0x60, 1, kbd_write_data, 1); - register_ioport_read(0x64, 1, kbd_read_status, 1); - register_ioport_write(0x64, 1, kbd_write_command, 1); -#endif -} - -/***********************************************************/ -/* Bochs BIOS debug ports */ -#ifdef TARGET_I386 -void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) -{ - switch(addr) { - /* Bochs BIOS messages */ - case 0x400: - case 0x401: - fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); - exit(1); - case 0x402: - case 0x403: -#ifdef DEBUG_BIOS - fprintf(stderr, "%c", val); -#endif - break; + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d"); + ret = ioctl(fd, TUNSETIFF, (void *) &ifr); + if (ret != 0) { + fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); + close(fd); + return -1; + } + printf("Connected to host network interface: %s\n", ifr.ifr_name); + fcntl(fd, F_SETFL, O_NONBLOCK); + net_fd = fd; - /* LGPL'ed VGA BIOS messages */ - case 0x501: - case 0x502: - fprintf(stderr, "VGA BIOS panic, line %d\n", val); - exit(1); - case 0x500: - case 0x503: -#ifdef DEBUG_BIOS - fprintf(stderr, "%c", val); -#endif - break; + /* try to launch network init script */ + pid = fork(); + if (pid >= 0) { + if (pid == 0) { + execl(network_script, network_script, ifr.ifr_name, NULL); + exit(1); + } + while (waitpid(pid, &status, 0) != pid); + if (!WIFEXITED(status) || + WEXITSTATUS(status) != 0) { + fprintf(stderr, "%s: could not launch network script for '%s'\n", + network_script, ifr.ifr_name); + } } + return 0; } -void bochs_bios_init(void) +void net_send_packet(int net_fd, const uint8_t *buf, int size) { - register_ioport_write(0x400, 1, bochs_bios_write, 2); - register_ioport_write(0x401, 1, bochs_bios_write, 2); - register_ioport_write(0x402, 1, bochs_bios_write, 1); - register_ioport_write(0x403, 1, bochs_bios_write, 1); - - register_ioport_write(0x501, 1, bochs_bios_write, 2); - register_ioport_write(0x502, 1, bochs_bios_write, 2); - register_ioport_write(0x500, 1, bochs_bios_write, 1); - register_ioport_write(0x503, 1, bochs_bios_write, 1); -} +#ifdef DEBUG_NE2000 + printf("NE2000: sending packet size=%d\n", size); #endif + write(net_fd, buf, size); +} /***********************************************************/ /* dumb display */ @@ -3015,7 +750,7 @@ int main_loop(void *opaque) /* poll any events */ serial_ufd = NULL; pf = ufds; - if (serial_ok && !(serial_ports[0].lsr & UART_LSR_DR)) { + if (serial_ok && serial_can_receive()) { serial_ufd = pf; pf->fd = 0; pf->events = POLLIN; @@ -3023,7 +758,7 @@ int main_loop(void *opaque) } #if defined (TARGET_I386) net_ufd = NULL; - if (net_fd > 0 && ne2000_can_receive(&ne2000_state)) { + if (net_fd > 0 && ne2000_can_receive()) { net_ufd = pf; pf->fd = net_fd; pf->events = POLLIN; @@ -3043,7 +778,7 @@ int main_loop(void *opaque) if (serial_ufd && (serial_ufd->revents & POLLIN)) { n = read(0, &ch, 1); if (n == 1) { - serial_received_byte(&serial_ports[0], ch); + term_received_byte(ch); } else { /* Closed, stop polling. */ serial_ok = 0; @@ -3059,7 +794,7 @@ int main_loop(void *opaque) memset(buf + n, 0, 60 - n); n = 60; } - ne2000_receive(&ne2000_state, buf, n); + ne2000_receive(buf, n); } } #endif @@ -3080,10 +815,7 @@ int main_loop(void *opaque) pic_set_irq(0, 1); pic_set_irq(0, 0); timer_irq_pending = 0; - /* XXX: RTC test */ - if (cmos_data[RTC_REG_B] & 0x50) { - pic_set_irq(8, 1); - } + rtc_timer(); #endif } /* XXX: add explicit timer */ @@ -3199,7 +931,7 @@ static uint8_t *signal_stack; int main(int argc, char **argv) { - int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; + int c, i, use_gdbstub, gdbstub_port, long_index; int snapshot, linux_boot; struct sigaction act; struct itimerval itv; @@ -3207,7 +939,6 @@ int main(int argc, char **argv) const char *initrd_filename; const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *kernel_filename, *kernel_cmdline; - char buf[1024]; DisplayState *ds = &display_state; /* we never want that malloc() uses mmap() */ @@ -3438,92 +1169,7 @@ int main(int argc, char **argv) cpu_single_env = env; init_ioports(); - - /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); - -#if defined(TARGET_I386) - /* RAW PC boot */ - - /* BIOS load */ - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - ret = load_image(buf, phys_ram_base + 0x000f0000); - if (ret != 0x10000) { - fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); - exit(1); - } - - /* VGA BIOS load */ - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); - ret = load_image(buf, phys_ram_base + 0x000c0000); - - /* setup basic memory access */ - cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); - cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); - - bochs_bios_init(); - - if (linux_boot) { - uint8_t bootsect[512]; - - if (bs_table[0] == NULL) { - fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); - exit(1); - } - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); - ret = load_image(buf, bootsect); - if (ret != sizeof(bootsect)) { - fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", - buf); - exit(1); - } - - bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); - - /* now we can load the kernel */ - ret = load_kernel(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR, - phys_ram_base + KERNEL_PARAMS_ADDR); - if (ret < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - if (initrd_size > 0) { - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); - } - pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, - kernel_cmdline); - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, - KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); - /* loader type */ - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); - } -#elif defined(TARGET_PPC) - /* allocate ROM */ - // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); - printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); - ret = load_image(buf, phys_ram_base + 0x000f0000); - if (ret != 0x10000) { - fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", - buf, ret); - exit(1); - } -#endif + cpu_calibrate_ticks(); /* terminal init */ if (nographic) { @@ -3535,31 +1181,14 @@ int main(int argc, char **argv) dumb_display_init(ds); #endif } - /* init basic PC hardware */ - register_ioport_write(0x80, 1, ioport80_write, 1); - vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); -#if defined (TARGET_I386) - cmos_init(); -#endif - pic_init(); - pit_init(); - serial_init(); -#if defined (TARGET_I386) - ne2000_init(); -#endif - ide_init(); - kbd_init(); - AUD_init(); - DMA_init(); -#if defined (TARGET_I386) - SB16_init(); -#endif -#if defined (TARGET_PPC) - PPC_end_init(); +#if defined(TARGET_I386) + pc_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); +#elif defined(TARGET_PPC) + ppc_init(); #endif - fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device); /* setup cpu signal handlers for MMU / self modifying code handling */ #if !defined(CONFIG_SOFTMMU) diff --git a/vl.h b/vl.h index 35962d198..026a5dee5 100644 --- a/vl.h +++ b/vl.h @@ -29,21 +29,25 @@ /* vl.c */ extern int reset_requested; extern int64_t ticks_per_sec; +extern int pit_min_timer_count; typedef void (IOPortWriteFunc)(struct CPUState *env, uint32_t address, uint32_t data); typedef uint32_t (IOPortReadFunc)(struct CPUState *env, uint32_t address); int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); -void pic_set_irq(int irq, int level); int64_t cpu_get_ticks(void); +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); -void kbd_put_keycode(int keycode); +void net_send_packet(int net_fd, const uint8_t *buf, int size); -#define MOUSE_EVENT_LBUTTON 0x01 -#define MOUSE_EVENT_RBUTTON 0x02 -#define MOUSE_EVENT_MBUTTON 0x04 -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); +void hw_error(const char *fmt, ...); + +int load_image(const char *filename, uint8_t *addr); +extern const char *bios_dir; + +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); /* block.c */ typedef struct BlockDriverState BlockDriverState; @@ -139,4 +143,78 @@ void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, char boot_device); int fdctrl_disk_change (int idx, const unsigned char *filename, int ro); +/* ne2000.c */ + +#define MAX_ETH_FRAME_SIZE 1514 + +void ne2000_init(int base, int irq); +int ne2000_can_receive(void); +void ne2000_receive(uint8_t *buf, int size); + +extern int net_fd; + +/* pckbd.c */ + +void kbd_put_keycode(int keycode); + +#define MOUSE_EVENT_LBUTTON 0x01 +#define MOUSE_EVENT_RBUTTON 0x02 +#define MOUSE_EVENT_MBUTTON 0x04 +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); + +void kbd_init(void); + +/* mc146818rtc.c */ + +typedef struct RTCState { + uint8_t cmos_data[128]; + uint8_t cmos_index; + int irq; +} RTCState; + +extern RTCState rtc_state; + +void rtc_init(int base, int irq); +void rtc_timer(void); + +/* serial.c */ + +void serial_init(int base, int irq); +int serial_can_receive(void); +void serial_receive_byte(int ch); +void serial_receive_break(void); + +/* i8259.c */ + +void pic_set_irq(int irq, int level); +void pic_init(void); + +/* i8254.c */ + +#define PIT_FREQ 1193182 + +typedef struct PITChannelState { + int count; /* can be 65536 */ + uint16_t latched_count; + uint8_t rw_state; + uint8_t mode; + uint8_t bcd; /* not supported */ + uint8_t gate; /* timer start */ + int64_t count_load_time; + int64_t count_last_edge_check_time; +} PITChannelState; + +extern PITChannelState pit_channels[3]; + +void pit_init(void); +void pit_set_gate(PITChannelState *s, int val); +int pit_get_out(PITChannelState *s); +int pit_get_out_edges(PITChannelState *s); + +/* pc.c */ +void pc_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + #endif /* VL_H */ -- cgit v1.2.3 From 9dc39cbae32d54f0f0c07337439446787f723fb7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:38:27 +0000 Subject: added a command line monitor git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@657 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 +- monitor.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 572 insertions(+), 2 deletions(-) create mode 100644 monitor.c diff --git a/Makefile.target b/Makefile.target index 1b837c782..769237ac9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -204,7 +204,8 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ +VL_OBJS=vl.o osdep.o block.o monitor.o \ + ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= hw.o @@ -226,7 +227,7 @@ VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a - $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) -lutil sdl.o: sdl.c $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< diff --git a/monitor.c b/monitor.c new file mode 100644 index 000000000..633b89892 --- /dev/null +++ b/monitor.c @@ -0,0 +1,569 @@ +/* + * QEMU monitor + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" + +//#define DEBUG + +#define TERM_CMD_BUF_SIZE 4095 +#define MAX_ARGS 64 + +#define IS_NORM 0 +#define IS_ESC 1 +#define IS_CSI 2 + +#define printf do_not_use_printf + +static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1]; +static int term_cmd_buf_index; +static int term_cmd_buf_size; +static int term_esc_state; +static int term_esc_param; + +typedef struct term_cmd_t { + const char *name; + void (*handler)(int argc, const char **argv); + const char *params; + const char *help; +} term_cmd_t; + +static term_cmd_t term_cmds[]; +static term_cmd_t info_cmds[]; + +void term_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +void term_flush(void) +{ + fflush(stdout); +} + +static int compare_cmd(const char *name, const char *list) +{ + const char *p, *pstart; + int len; + len = strlen(name); + p = list; + for(;;) { + pstart = p; + p = strchr(p, '|'); + if (!p) + p = pstart + strlen(pstart); + if ((p - pstart) == len && !memcmp(pstart, name, len)) + return 1; + if (*p == '\0') + break; + p++; + } + return 0; +} + +static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name) +{ + term_cmd_t *cmd; + + for(cmd = cmds; cmd->name != NULL; cmd++) { + if (!name || !strcmp(name, cmd->name)) + term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help); + } +} + +static void help_cmd(const char *name) +{ + if (name && !strcmp(name, "info")) { + help_cmd1(info_cmds, "info ", NULL); + } else { + help_cmd1(term_cmds, "", name); + } +} + +static void do_help(int argc, const char **argv) +{ + help_cmd(argv[1]); +} + +static void do_commit(int argc, const char **argv) +{ + int i; + + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) + bdrv_commit(bs_table[i]); + } +} + +static void do_info(int argc, const char **argv) +{ + term_cmd_t *cmd; + const char *item; + + if (argc < 2) + goto help; + item = argv[1]; + for(cmd = info_cmds; cmd->name != NULL; cmd++) { + if (compare_cmd(argv[1], cmd->name)) + goto found; + } + help: + help_cmd(argv[0]); + return; + found: + cmd->handler(argc, argv); +} + +static void do_info_network(int argc, const char **argv) +{ + int i, j; + NetDriverState *nd; + + for(i = 0; i < nb_nics; i++) { + nd = &nd_table[i]; + term_printf("%d: ifname=%s macaddr=", i, nd->ifname); + for(j = 0; j < 6; j++) { + if (j > 0) + term_printf(":"); + term_printf("%02x", nd->macaddr[j]); + } + term_printf("\n"); + } +} + +static void do_info_block(int argc, const char **argv) +{ + bdrv_info(); +} + +static void do_quit(int argc, const char **argv) +{ + exit(0); +} + +static int eject_device(BlockDriverState *bs, int force) +{ + if (bdrv_is_inserted(bs)) { + if (!force) { + if (!bdrv_is_removable(bs)) { + term_printf("device is not removable\n"); + return -1; + } + if (bdrv_is_locked(bs)) { + term_printf("device is locked\n"); + return -1; + } + } + bdrv_close(bs); + } + return 0; +} + +static void do_eject(int argc, const char **argv) +{ + BlockDriverState *bs; + const char **parg; + int force; + + parg = argv + 1; + if (!*parg) { + fail: + help_cmd(argv[0]); + return; + } + force = 0; + if (!strcmp(*parg, "-f")) { + force = 1; + parg++; + } + if (!*parg) + goto fail; + bs = bdrv_find(*parg); + if (!bs) { + term_printf("device not found\n"); + return; + } + eject_device(bs, force); +} + +static void do_change(int argc, const char **argv) +{ + BlockDriverState *bs; + + if (argc != 3) { + help_cmd(argv[0]); + return; + } + bs = bdrv_find(argv[1]); + if (!bs) { + term_printf("device not found\n"); + return; + } + if (eject_device(bs, 0) < 0) + return; + bdrv_open(bs, argv[2], 0); +} + +static term_cmd_t term_cmds[] = { + { "help|?", do_help, + "[cmd]", "show the help" }, + { "commit", do_commit, + "", "commit changes to the disk images (if -snapshot is used)" }, + { "info", do_info, + "subcommand", "show various information about the system state" }, + { "q|quit", do_quit, + "", "quit the emulator" }, + { "eject", do_eject, + "[-f] device", "eject a removable media (use -f to force it)" }, + { "change", do_change, + "device filename", "change a removable media" }, + { NULL, NULL, }, +}; + +static term_cmd_t info_cmds[] = { + { "network", do_info_network, + "", "show the network state" }, + { "block", do_info_block, + "", "show the block devices" }, + { NULL, NULL, }, +}; + +static void term_handle_command(char *cmdline) +{ + char *p, *pstart; + int argc; + const char *args[MAX_ARGS + 1]; + term_cmd_t *cmd; + +#ifdef DEBUG + term_printf("command='%s'\n", cmdline); +#endif + + /* split command in words */ + argc = 0; + p = cmdline; + for(;;) { + while (isspace(*p)) + p++; + if (*p == '\0') + break; + pstart = p; + while (*p != '\0' && !isspace(*p)) + p++; + args[argc] = pstart; + argc++; + if (argc >= MAX_ARGS) + break; + if (*p == '\0') + break; + *p++ = '\0'; + } + args[argc] = NULL; +#ifdef DEBUG + for(i=0;iname != NULL; cmd++) { + if (compare_cmd(args[0], cmd->name)) + goto found; + } + term_printf("unknown command: '%s'\n", args[0]); + return; + found: + cmd->handler(argc, args); +} + +static void term_show_prompt(void) +{ + term_printf("(qemu) "); + fflush(stdout); + term_cmd_buf_index = 0; + term_cmd_buf_size = 0; + term_esc_state = IS_NORM; +} + +static void term_insert_char(int ch) +{ + if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) { + memmove(term_cmd_buf + term_cmd_buf_index + 1, + term_cmd_buf + term_cmd_buf_index, + term_cmd_buf_size - term_cmd_buf_index); + term_cmd_buf[term_cmd_buf_index] = ch; + term_cmd_buf_size++; + term_printf("\033[@%c", ch); + term_cmd_buf_index++; + term_flush(); + } +} + +static void term_backward_char(void) +{ + if (term_cmd_buf_index > 0) { + term_cmd_buf_index--; + term_printf("\033[D"); + term_flush(); + } +} + +static void term_forward_char(void) +{ + if (term_cmd_buf_index < term_cmd_buf_size) { + term_cmd_buf_index++; + term_printf("\033[C"); + term_flush(); + } +} + +static void term_delete_char(void) +{ + if (term_cmd_buf_index < term_cmd_buf_size) { + memmove(term_cmd_buf + term_cmd_buf_index, + term_cmd_buf + term_cmd_buf_index + 1, + term_cmd_buf_size - term_cmd_buf_index - 1); + term_printf("\033[P"); + term_cmd_buf_size--; + term_flush(); + } +} + +static void term_backspace(void) +{ + if (term_cmd_buf_index > 0) { + term_backward_char(); + term_delete_char(); + } +} + +static void term_bol(void) +{ + while (term_cmd_buf_index > 0) + term_backward_char(); +} + +static void term_eol(void) +{ + while (term_cmd_buf_index < term_cmd_buf_size) + term_forward_char(); +} + +/* return true if command handled */ +static void term_handle_byte(int ch) +{ + switch(term_esc_state) { + case IS_NORM: + switch(ch) { + case 1: + term_bol(); + break; + case 5: + term_eol(); + break; + case 10: + case 13: + term_cmd_buf[term_cmd_buf_size] = '\0'; + term_printf("\n"); + term_handle_command(term_cmd_buf); + term_show_prompt(); + break; + case 27: + term_esc_state = IS_ESC; + break; + case 127: + case 8: + term_backspace(); + break; + default: + if (ch >= 32) { + term_insert_char(ch); + } + break; + } + break; + case IS_ESC: + if (ch == '[') { + term_esc_state = IS_CSI; + term_esc_param = 0; + } else { + term_esc_state = IS_NORM; + } + break; + case IS_CSI: + switch(ch) { + case 'D': + term_backward_char(); + break; + case 'C': + term_forward_char(); + break; + case '0' ... '9': + term_esc_param = term_esc_param * 10 + (ch - '0'); + goto the_end; + case '~': + switch(term_esc_param) { + case 1: + term_bol(); + break; + case 3: + term_delete_char(); + break; + case 4: + term_eol(); + break; + } + break; + default: + break; + } + term_esc_state = IS_NORM; + the_end: + break; + } +} + +/*************************************************************/ +/* serial console support */ + +#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ + +static int term_got_escape, term_command; + +void term_print_help(void) +{ + term_printf("\n" + "C-a h print this help\n" + "C-a x exit emulatior\n" + "C-a d switch on/off debug log\n" + "C-a s save disk data back to file (if -snapshot)\n" + "C-a b send break (magic sysrq)\n" + "C-a c switch between console and monitor\n" + "C-a C-a send C-a\n" + ); +} + +/* called when a char is received */ +static void term_received_byte(int ch) +{ + if (!serial_console) { + /* if no serial console, handle every command */ + term_handle_byte(ch); + } else { + if (term_got_escape) { + term_got_escape = 0; + switch(ch) { + case 'h': + term_print_help(); + break; + case 'x': + exit(0); + break; + case 's': + { + int i; + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) + bdrv_commit(bs_table[i]); + } + } + break; + case 'b': + if (serial_console) + serial_receive_break(serial_console); + break; + case 'c': + if (!term_command) { + term_show_prompt(); + term_command = 1; + } else { + term_command = 0; + } + break; + case 'd': + cpu_set_log(CPU_LOG_ALL); + break; + case TERM_ESCAPE: + goto send_char; + } + } else if (ch == TERM_ESCAPE) { + term_got_escape = 1; + } else { + send_char: + if (term_command) { + term_handle_byte(ch); + } else { + if (serial_console) + serial_receive_byte(serial_console, ch); + } + } + } +} + +static int term_can_read(void *opaque) +{ + if (serial_console) { + return serial_can_receive(serial_console); + } else { + return 1; + } +} + +static void term_read(void *opaque, const uint8_t *buf, int size) +{ + int i; + for(i = 0; i < size; i++) + term_received_byte(buf[i]); +} + +void monitor_init(void) +{ + if (!serial_console) { + term_printf("QEMU %s monitor - type 'help' for more information\n", + QEMU_VERSION); + term_show_prompt(); + } + add_fd_read_handler(0, term_can_read, term_read, NULL); +} -- cgit v1.2.3 From b338082b3f0f1831deec6fa68145ae01ae136398 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:38:54 +0000 Subject: remoable device support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@658 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 173 insertions(+), 16 deletions(-) diff --git a/block.c b/block.c index 29f316e00..3886ec099 100644 --- a/block.c +++ b/block.c @@ -50,7 +50,13 @@ struct BlockDriverState { int fd; /* if -1, only COW mappings */ int64_t total_sectors; - int read_only; + int read_only; /* if true, the media is read only */ + int inserted; /* if true, the media is present */ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ @@ -61,20 +67,42 @@ struct BlockDriverState { uint8_t boot_sector_data[512]; char filename[1024]; + + /* NOTE: the following infos are only hints for real hardware + drivers. They are not used by the block driver */ + int cyls, heads, secs; + int type; + char device_name[32]; + BlockDriverState *next; }; -BlockDriverState *bdrv_open(const char *filename, int snapshot) +static BlockDriverState *bdrv_first; + +/* 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); + /* insert at the end */ + pbs = &bdrv_first; + while (*pbs != NULL) + pbs = &(*pbs)->next; + *pbs = bs; + return bs; +} + +int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) { - BlockDriverState *bs; int fd, cow_fd; int64_t size; char template[] = "/tmp/vl.XXXXXX"; struct cow_header_v2 cow_header; struct stat st; - bs = malloc(sizeof(BlockDriverState)); - if(!bs) - return NULL; bs->read_only = 0; bs->fd = -1; bs->cow_fd = -1; @@ -163,22 +191,40 @@ BlockDriverState *bdrv_open(const char *filename, int snapshot) bs->cow_sectors_offset = 0; } - return bs; + bs->inserted = 1; + + /* call the change callback */ + if (bs->change_cb) + bs->change_cb(bs->change_opaque); + + return 0; fail: bdrv_close(bs); - return NULL; + return -1; } void bdrv_close(BlockDriverState *bs) { - /* we unmap the mapping so that it is written to the COW file */ - if (bs->cow_bitmap_addr) - munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); - if (bs->cow_fd >= 0) - close(bs->cow_fd); - if (bs->fd >= 0) - close(bs->fd); - free(bs); + if (bs->inserted) { + /* we unmap the mapping so that it is written to the COW file */ + if (bs->cow_bitmap_addr) + munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); + if (bs->cow_fd >= 0) + close(bs->cow_fd); + if (bs->fd >= 0) + close(bs->fd); + bs->inserted = 0; + + /* call the change callback */ + if (bs->change_cb) + bs->change_cb(bs->change_opaque); + } +} + +void bdrv_delete(BlockDriverState *bs) +{ + bdrv_close(bs); + qemu_free(bs); } static inline void set_bit(uint8_t *bitmap, int64_t bitnum) @@ -221,6 +267,9 @@ int bdrv_commit(BlockDriverState *bs) int64_t i; uint8_t *cow_bitmap; + if (!bs->inserted) + return -1; + if (!bs->cow_bitmap) { fprintf(stderr, "Already committed to %s\n", bs->filename); return 0; @@ -263,6 +312,9 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, int ret, n, fd; int64_t offset; + if (!bs->inserted) + return -1; + while (nb_sectors > 0) { if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) { fd = bs->cow_fd; @@ -302,6 +354,8 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, int ret, fd, i; int64_t offset, retl; + if (!bs->inserted) + return -1; if (bs->read_only) return -1; @@ -344,3 +398,106 @@ void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) 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_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_is_removable(BlockDriverState *bs) +{ + return bs->removable; +} + +int bdrv_is_read_only(BlockDriverState *bs) +{ + return bs->read_only; +} + +int bdrv_is_inserted(BlockDriverState *bs) +{ + return bs->inserted; +} + +int bdrv_is_locked(BlockDriverState *bs) +{ + return bs->locked; +} + +void bdrv_set_locked(BlockDriverState *bs, int locked) +{ + bs->locked = locked; +} + +void bdrv_set_change_cb(BlockDriverState *bs, + void (*change_cb)(void *opaque), void *opaque) +{ + bs->change_cb = change_cb; + bs->change_opaque = opaque; +} + +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_info(void) +{ + BlockDriverState *bs; + + for (bs = bdrv_first; bs != NULL; bs = bs->next) { + term_printf("%s:", bs->device_name); + term_printf(" type="); + switch(bs->type) { + case BDRV_TYPE_HD: + term_printf("hd"); + break; + case BDRV_TYPE_CDROM: + term_printf("cdrom"); + break; + case BDRV_TYPE_FLOPPY: + term_printf("floppy"); + break; + } + term_printf(" removable=%d", bs->removable); + if (bs->removable) { + term_printf(" locked=%d", bs->locked); + } + if (bs->inserted) { + term_printf(" file=%s", bs->filename); + term_printf(" ro=%d", bs->read_only); + } else { + term_printf(" [not inserted]"); + } + term_printf("\n"); + } +} -- cgit v1.2.3 From caed880216f3572b5f33691f46c934e1d0faccb2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:40:43 +0000 Subject: removable device support - io port API change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@659 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 134 +++++++++++++++++++++++-------------------------- hw/ide.c | 170 +++++++++++++++++++++++++++++++++------------------------------ 2 files changed, 151 insertions(+), 153 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index 819e2f7b3..d3c885401 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -85,12 +85,14 @@ typedef struct fdrive_t { uint8_t ro; /* Is read-only */ } fdrive_t; -static void fd_init (fdrive_t *drv) +static void fd_init (fdrive_t *drv, BlockDriverState *bs) { /* Drive */ - drv->bs = NULL; -// drv->drive = FDRIVE_DRV_288; - drv->drive = FDRIVE_DRV_144; + drv->bs = bs; + if (bs) + drv->drive = FDRIVE_DRV_144; + else + drv->drive = FDRIVE_DRV_NONE; drv->motor = 0; drv->perpendicular = 0; drv->rv = 0; @@ -157,13 +159,17 @@ static void fd_recalibrate (fdrive_t *drv) } /* Revalidate a disk drive after a disk change */ -static void fd_revalidate (fdrive_t *drv, int ro) +static void fd_revalidate (fdrive_t *drv) { int64_t nb_sectors; FLOPPY_DPRINTF("revalidate\n"); drv->rv = 0; - if (drv->bs != NULL) { + /* if no drive present, cannot do more */ + if (!drv->bs) + return; + + if (bdrv_is_inserted(drv->bs)) { bdrv_get_geometry(drv->bs, &nb_sectors); #if 1 if (nb_sectors > 2880) @@ -186,14 +192,21 @@ static void fd_revalidate (fdrive_t *drv, int ro) drv->max_track = 80; #endif } + drv->ro = bdrv_is_read_only(drv->bs); } else { drv->disk = FDRIVE_DISK_NONE; drv->last_sect = 1; /* Avoid eventual divide by 0 bugs */ + drv->ro = 0; } - drv->ro = ro; drv->rv = 1; } +static void fd_change_cb (void *opaque) +{ + fdrive_t *drv = opaque; + fd_revalidate(drv); +} + /* Motor control */ static void fd_start (fdrive_t *drv) { @@ -220,16 +233,16 @@ static void fdctrl_reset_fifo (void); static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size); static void fdctrl_raise_irq (uint8_t status); -static uint32_t fdctrl_read_statusB (CPUState *env, uint32_t reg); -static uint32_t fdctrl_read_dor (CPUState *env, uint32_t reg); -static void fdctrl_write_dor (CPUState *env, uint32_t reg, uint32_t value); -static uint32_t fdctrl_read_tape (CPUState *env, uint32_t reg); -static void fdctrl_write_tape (CPUState *env, uint32_t reg, uint32_t value); -static uint32_t fdctrl_read_main_status (CPUState *env, uint32_t reg); -static void fdctrl_write_rate (CPUState *env, uint32_t reg, uint32_t value); -static uint32_t fdctrl_read_data (CPUState *env, uint32_t reg); -static void fdctrl_write_data (CPUState *env, uint32_t reg, uint32_t value); -static uint32_t fdctrl_read_dir (CPUState *env, uint32_t reg); +static uint32_t fdctrl_read_statusB (void *opaque, uint32_t reg); +static uint32_t fdctrl_read_dor (void *opaque, uint32_t reg); +static void fdctrl_write_dor (void *opaque, uint32_t reg, uint32_t value); +static uint32_t fdctrl_read_tape (void *opaque, uint32_t reg); +static void fdctrl_write_tape (void *opaque, uint32_t reg, uint32_t value); +static uint32_t fdctrl_read_main_status (void *opaque, uint32_t reg); +static void fdctrl_write_rate (void *opaque, uint32_t reg, uint32_t value); +static uint32_t fdctrl_read_data (void *opaque, uint32_t reg); +static void fdctrl_write_data (void *opaque, uint32_t reg, uint32_t value); +static uint32_t fdctrl_read_dir (void *opaque, uint32_t reg); enum { FD_CTRL_ACTIVE = 0x01, @@ -295,7 +308,7 @@ typedef struct fdctrl_t { static fdctrl_t fdctrl; void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, - char boot_device) + BlockDriverState **fds) { // int io_mem; int i; @@ -312,8 +325,11 @@ void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, } else { fdctrl.dma_en = 0; } - for (i = 0; i < MAX_FD; i++) - fd_init(&fdctrl.drives[i]); + for (i = 0; i < MAX_FD; i++) { + fd_init(&fdctrl.drives[i], fds[i]); + if (fds[i]) + bdrv_set_change_cb(fds[i], fd_change_cb, &fdctrl.drives[i]); + } fdctrl_reset(0); fdctrl.state = FD_CTRL_ACTIVE; if (mem_mapped) { @@ -323,51 +339,27 @@ void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, cpu_register_physical_memory(base, 0x08, io_mem); #endif } else { - register_ioport_read(base + 0x01, 1, fdctrl_read_statusB, 1); - register_ioport_read(base + 0x02, 1, fdctrl_read_dor, 1); - register_ioport_write(base + 0x02, 1, fdctrl_write_dor, 1); - register_ioport_read(base + 0x03, 1, fdctrl_read_tape, 1); - register_ioport_write(base + 0x03, 1, fdctrl_write_tape, 1); - register_ioport_read(base + 0x04, 1, fdctrl_read_main_status, 1); - register_ioport_write(base + 0x04, 1, fdctrl_write_rate, 1); - register_ioport_read(base + 0x05, 1, fdctrl_read_data, 1); - register_ioport_write(base + 0x05, 1, fdctrl_write_data, 1); - register_ioport_read(base + 0x07, 1, fdctrl_read_dir, 1); + register_ioport_read(base + 0x01, 1, 1, fdctrl_read_statusB, NULL); + register_ioport_read(base + 0x02, 1, 1, fdctrl_read_dor, NULL); + register_ioport_write(base + 0x02, 1, 1, fdctrl_write_dor, NULL); + register_ioport_read(base + 0x03, 1, 1, fdctrl_read_tape, NULL); + register_ioport_write(base + 0x03, 1, 1, fdctrl_write_tape, NULL); + register_ioport_read(base + 0x04, 1, 1, fdctrl_read_main_status, NULL); + register_ioport_write(base + 0x04, 1, 1, fdctrl_write_rate, NULL); + register_ioport_read(base + 0x05, 1, 1, fdctrl_read_data, NULL); + register_ioport_write(base + 0x05, 1, 1, fdctrl_write_data, NULL); + register_ioport_read(base + 0x07, 1, 1, fdctrl_read_dir, NULL); } - if (boot_device == 'b') - fdctrl.bootsel = 1; - else - fdctrl.bootsel = 0; -#if defined (TARGET_I386) - cmos_register_fd(fdctrl.drives[0].drive, fdctrl.drives[1].drive); -#endif -} - -int fdctrl_disk_change (int idx, const unsigned char *filename, int ro) -{ - fdrive_t *drv; + fdctrl.bootsel = 0; - if (idx < 0 || idx > 1) - return -1; - FLOPPY_DPRINTF("disk %d change: %s (%s)\n", idx, filename, - ro == 0 ? "rw" : "ro"); - drv = &fdctrl.drives[idx]; - if (fd_table[idx] != NULL) { - bdrv_close(fd_table[idx]); - fd_table[idx] = NULL; + for (i = 0; i < MAX_FD; i++) { + fd_revalidate(&fdctrl.drives[i]); } - fd_table[idx] = bdrv_open(filename, ro); - drv->bs = fd_table[idx]; - if (fd_table[idx] == NULL) - return -1; - fd_revalidate(drv, ro); -#if 0 - fd_recalibrate(drv); - fdctrl_reset_fifo(); - fdctrl_raise_irq(0x20); -#endif +} - return 0; +int fdctrl_get_drive_type(int drive_num) +{ + return fdctrl.drives[drive_num].drive; } /* Change IRQ state */ @@ -411,7 +403,7 @@ static void fdctrl_reset (int do_irq) } /* Status B register : 0x01 (read-only) */ -static uint32_t fdctrl_read_statusB (CPUState *env, uint32_t reg) +static uint32_t fdctrl_read_statusB (void *opaque, uint32_t reg) { fdctrl_reset_irq(); FLOPPY_DPRINTF("status register: 0x00\n"); @@ -420,7 +412,7 @@ static uint32_t fdctrl_read_statusB (CPUState *env, uint32_t reg) } /* Digital output register : 0x02 */ -static uint32_t fdctrl_read_dor (CPUState *env, uint32_t reg) +static uint32_t fdctrl_read_dor (void *opaque, uint32_t reg) { fdrive_t *cur_drv, *drv0, *drv1; uint32_t retval = 0; @@ -442,7 +434,7 @@ static uint32_t fdctrl_read_dor (CPUState *env, uint32_t reg) return retval; } -static void fdctrl_write_dor (CPUState *env, uint32_t reg, uint32_t value) +static void fdctrl_write_dor (void *opaque, uint32_t reg, uint32_t value) { fdrive_t *drv0, *drv1; @@ -489,7 +481,7 @@ static void fdctrl_write_dor (CPUState *env, uint32_t reg, uint32_t value) } /* Tape drive register : 0x03 */ -static uint32_t fdctrl_read_tape (CPUState *env, uint32_t reg) +static uint32_t fdctrl_read_tape (void *opaque, uint32_t reg) { uint32_t retval = 0; @@ -502,7 +494,7 @@ static uint32_t fdctrl_read_tape (CPUState *env, uint32_t reg) return retval; } -static void fdctrl_write_tape (CPUState *env, uint32_t reg, uint32_t value) +static void fdctrl_write_tape (void *opaque, uint32_t reg, uint32_t value) { fdctrl_reset_irq(); /* Reset mode */ @@ -517,7 +509,7 @@ static void fdctrl_write_tape (CPUState *env, uint32_t reg, uint32_t value) } /* Main status register : 0x04 (read) */ -static uint32_t fdctrl_read_main_status (CPUState *env, uint32_t reg) +static uint32_t fdctrl_read_main_status (void *opaque, uint32_t reg) { uint32_t retval = 0; @@ -541,7 +533,7 @@ static uint32_t fdctrl_read_main_status (CPUState *env, uint32_t reg) } /* Data select rate register : 0x04 (write) */ -static void fdctrl_write_rate (CPUState *env, uint32_t reg, uint32_t value) +static void fdctrl_write_rate (void *opaque, uint32_t reg, uint32_t value) { fdctrl_reset_irq(); /* Reset mode */ @@ -566,7 +558,7 @@ static void fdctrl_write_rate (CPUState *env, uint32_t reg, uint32_t value) } /* Digital input register : 0x07 (read-only) */ -static uint32_t fdctrl_read_dir (CPUState *env, uint32_t reg) +static uint32_t fdctrl_read_dir (void *opaque, uint32_t reg) { fdrive_t *drv0, *drv1; uint32_t retval = 0; @@ -872,7 +864,7 @@ transfer_error: } /* Data register : 0x05 */ -static uint32_t fdctrl_read_data (CPUState *env, uint32_t reg) +static uint32_t fdctrl_read_data (void *opaque, uint32_t reg) { fdrive_t *cur_drv, *drv0, *drv1; uint32_t retval = 0; @@ -914,7 +906,7 @@ static uint32_t fdctrl_read_data (CPUState *env, uint32_t reg) return retval; } -static void fdctrl_write_data (CPUState *env, uint32_t reg, uint32_t value) +static void fdctrl_write_data (void *opaque, uint32_t reg, uint32_t value) { fdrive_t *cur_drv, *drv0, *drv1; diff --git a/hw/ide.c b/hw/ide.c index 82e8fba88..a132d1c52 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -314,10 +314,10 @@ struct IDEState; typedef void EndTransferFunc(struct IDEState *); +/* NOTE: IDEState represents in fact one drive */ typedef struct IDEState { /* ide config */ int is_cdrom; - int cdrom_locked; int cylinders, heads, sectors; int64_t nb_sectors; int mult_sectors; @@ -351,14 +351,6 @@ typedef struct IDEState { uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; } IDEState; -IDEState ide_state[MAX_DISKS]; -IDEState *ide_table[0x400 >> 3]; - -static inline IDEState *get_ide_interface(uint32_t addr) -{ - return ide_table[addr >> 3]; -} - static void padstr(char *str, const char *src, int len) { int i, v; @@ -815,7 +807,7 @@ static void ide_atapi_cmd(IDEState *s) #endif switch(s->io_buffer[0]) { case GPCMD_TEST_UNIT_READY: - if (s->bs) { + if (bdrv_is_inserted(s->bs)) { ide_atapi_cmd_ok(s); } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, @@ -867,7 +859,7 @@ static void ide_atapi_cmd(IDEState *s) buf[12] = 0x70; buf[13] = 3 << 5; buf[14] = (1 << 0) | (1 << 3) | (1 << 5); - if (s->cdrom_locked) + if (bdrv_is_locked(s->bs)) buf[6] |= 1 << 1; buf[15] = 0x00; cpu_to_ube16(&buf[16], 706); @@ -907,8 +899,8 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 18, max_len); break; case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - if (s->bs) { - s->cdrom_locked = packet[4] & 1; + if (bdrv_is_inserted(s->bs)) { + bdrv_set_locked(s->bs, packet[4] & 1); ide_atapi_cmd_ok(s); } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, @@ -920,7 +912,7 @@ static void ide_atapi_cmd(IDEState *s) { int nb_sectors, lba; - if (!s->bs) { + if (!bdrv_is_inserted(s->bs)) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; @@ -945,7 +937,7 @@ static void ide_atapi_cmd(IDEState *s) case GPCMD_SEEK: { int lba; - if (!s->bs) { + if (!bdrv_is_inserted(s->bs)) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; @@ -965,7 +957,10 @@ static void ide_atapi_cmd(IDEState *s) start = packet[4] & 1; eject = (packet[4] >> 1) & 1; - /* XXX: currently none implemented */ + if (eject && !start) { + /* eject the disk */ + bdrv_close(s->bs); + } ide_atapi_cmd_ok(s); } break; @@ -986,7 +981,7 @@ static void ide_atapi_cmd(IDEState *s) { int format, msf, start_track, len; - if (!s->bs) { + if (!bdrv_is_inserted(s->bs)) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; @@ -1019,7 +1014,7 @@ static void ide_atapi_cmd(IDEState *s) } break; case GPCMD_READ_CDVD_CAPACITY: - if (!s->bs) { + if (!bdrv_is_inserted(s->bs)) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; @@ -1051,9 +1046,20 @@ static void ide_atapi_cmd(IDEState *s) } } -static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +/* called when the inserted state of the media has changed */ +static void cdrom_change_cb(void *opaque) { - IDEState *ide_if = get_ide_interface(addr); + IDEState *s = opaque; + int64_t nb_sectors; + + /* XXX: send interrupt too */ + bdrv_get_geometry(s->bs, &nb_sectors); + s->nb_sectors = nb_sectors; +} + +static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + IDEState *ide_if = opaque; IDEState *s = ide_if->cur_drive; int unit, n; @@ -1210,9 +1216,9 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } } -static uint32_t ide_ioport_read(CPUState *env, uint32_t addr1) +static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) { - IDEState *s = get_ide_interface(addr1)->cur_drive; + IDEState *s = ((IDEState *)opaque)->cur_drive; uint32_t addr; int ret; @@ -1251,9 +1257,9 @@ static uint32_t ide_ioport_read(CPUState *env, uint32_t addr1) return ret; } -static uint32_t ide_status_read(CPUState *env, uint32_t addr) +static uint32_t ide_status_read(void *opaque, uint32_t addr) { - IDEState *s = get_ide_interface(addr)->cur_drive; + IDEState *s = ((IDEState *)opaque)->cur_drive; int ret; ret = s->status; #ifdef DEBUG_IDE @@ -1262,9 +1268,9 @@ static uint32_t ide_status_read(CPUState *env, uint32_t addr) return ret; } -static void ide_cmd_write(CPUState *env, uint32_t addr, uint32_t val) +static void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val) { - IDEState *ide_if = get_ide_interface(addr); + IDEState *ide_if = opaque; IDEState *s; int i; @@ -1297,9 +1303,9 @@ static void ide_cmd_write(CPUState *env, uint32_t addr, uint32_t val) ide_if[1].cmd = val; } -static void ide_data_writew(CPUState *env, uint32_t addr, uint32_t val) +static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val) { - IDEState *s = get_ide_interface(addr)->cur_drive; + IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; p = s->data_ptr; @@ -1310,9 +1316,9 @@ static void ide_data_writew(CPUState *env, uint32_t addr, uint32_t val) s->end_transfer_func(s); } -static uint32_t ide_data_readw(CPUState *env, uint32_t addr) +static uint32_t ide_data_readw(void *opaque, uint32_t addr) { - IDEState *s = get_ide_interface(addr)->cur_drive; + IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; int ret; p = s->data_ptr; @@ -1324,9 +1330,9 @@ static uint32_t ide_data_readw(CPUState *env, uint32_t addr) return ret; } -static void ide_data_writel(CPUState *env, uint32_t addr, uint32_t val) +static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val) { - IDEState *s = get_ide_interface(addr)->cur_drive; + IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; p = s->data_ptr; @@ -1337,9 +1343,9 @@ static void ide_data_writel(CPUState *env, uint32_t addr, uint32_t val) s->end_transfer_func(s); } -static uint32_t ide_data_readl(CPUState *env, uint32_t addr) +static uint32_t ide_data_readl(void *opaque, uint32_t addr) { - IDEState *s = get_ide_interface(addr)->cur_drive; + IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; int ret; @@ -1407,64 +1413,64 @@ static void ide_guess_geometry(IDEState *s) } } -void ide_init(void) +void ide_init(int iobase, int iobase2, int irq, + BlockDriverState *hd0, BlockDriverState *hd1) { - IDEState *s; - int i, cylinders, iobase, iobase2; + IDEState *s, *ide_state; + int i, cylinders, heads, secs; int64_t nb_sectors; - static const int ide_iobase[2] = { 0x1f0, 0x170 }; - static const int ide_iobase2[2] = { 0x3f6, 0x376 }; - static const int ide_irq[2] = { 14, 15 }; - for(i = 0; i < MAX_DISKS; i++) { - s = &ide_state[i]; - s->bs = bs_table[i]; + ide_state = qemu_mallocz(sizeof(IDEState) * 2); + if (!ide_state) + return; + + for(i = 0; i < 2; i++) { + s = ide_state + i; + if (i == 0) + s->bs = hd0; + else + s->bs = hd1; if (s->bs) { bdrv_get_geometry(s->bs, &nb_sectors); s->nb_sectors = nb_sectors; - ide_guess_geometry(s); - if (s->cylinders == 0) { - /* if no geometry, use a LBA compatible one */ - cylinders = nb_sectors / (16 * 63); - if (cylinders > 16383) - cylinders = 16383; - else if (cylinders < 2) - cylinders = 2; + /* if a geometry hint is available, use it */ + bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); + if (cylinders != 0) { s->cylinders = cylinders; - s->heads = 16; - s->sectors = 63; + s->heads = heads; + s->sectors = secs; + } else { + ide_guess_geometry(s); + if (s->cylinders == 0) { + /* if no geometry, use a LBA compatible one */ + cylinders = nb_sectors / (16 * 63); + if (cylinders > 16383) + cylinders = 16383; + else if (cylinders < 2) + cylinders = 2; + s->cylinders = cylinders; + s->heads = 16; + s->sectors = 63; + } + } + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { + s->is_cdrom = 1; + bdrv_set_change_cb(s->bs, cdrom_change_cb, s); } } - s->irq = ide_irq[i >> 1]; + s->irq = irq; ide_reset(s); } - for(i = 0; i < (MAX_DISKS / 2); i++) { - iobase = ide_iobase[i]; - iobase2 = ide_iobase2[i]; - ide_table[iobase >> 3] = &ide_state[2 * i]; - if (ide_iobase2[i]) - ide_table[iobase2 >> 3] = &ide_state[2 * i]; - register_ioport_write(iobase, 8, ide_ioport_write, 1); - register_ioport_read(iobase, 8, ide_ioport_read, 1); - register_ioport_read(iobase2, 1, ide_status_read, 1); - register_ioport_write(iobase2, 1, ide_cmd_write, 1); - - /* data ports */ - register_ioport_write(iobase, 2, ide_data_writew, 2); - register_ioport_read(iobase, 2, ide_data_readw, 2); - register_ioport_write(iobase, 4, ide_data_writel, 4); - register_ioport_read(iobase, 4, ide_data_readl, 4); + register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state); + register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state); + if (iobase2) { + register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state); + register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state); } -} - -void ide_set_geometry(int n, int cyls, int heads, int secs) -{ - ide_state[n].cylinders = cyls; - ide_state[n].heads = heads; - ide_state[n].sectors = secs; -} - -void ide_set_cdrom(int n, int is_cdrom) -{ - ide_state[n].is_cdrom = is_cdrom; + + /* data ports */ + register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state); + register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state); + register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state); + register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state); } -- cgit v1.2.3 From 07d898662d9aa173ac2d5c0aa4c9a1cf39caa703 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:41:12 +0000 Subject: added qemu_mallocz() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@660 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osdep.c b/osdep.c index d4d336462..f843e562f 100644 --- a/osdep.c +++ b/osdep.c @@ -281,6 +281,16 @@ void *qemu_malloc(size_t size) #endif +void *qemu_mallocz(size_t size) +{ + void *ptr; + ptr = qemu_malloc(size); + if (!ptr) + return NULL; + memset(ptr, 0, size); + return ptr; +} + /****************************************************************/ /* printf support */ -- cgit v1.2.3 From 7d977de7e19b04c4bb0c95d5afe6d4350d4068e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:41:34 +0000 Subject: io port API change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@661 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 24 ++++++++++++------------ hw/sb16.c | 20 ++++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index 2c85b6e7b..3d010f316 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -78,7 +78,7 @@ enum { }; -static void write_page (CPUState *env, uint32_t nport, uint32_t data) +static void write_page (void *opaque, uint32_t nport, uint32_t data) { int ichan; int ncont; @@ -113,7 +113,7 @@ static inline int getff (int ncont) return ff; } -static uint32_t read_chan (CPUState *env, uint32_t nport) +static uint32_t read_chan (void *opaque, uint32_t nport) { int ff; int ncont, ichan, nreg; @@ -135,7 +135,7 @@ static uint32_t read_chan (CPUState *env, uint32_t nport) return (val >> (ncont + (ff << 3))) & 0xff; } -static void write_chan (CPUState *env, uint32_t nport, uint32_t data) +static void write_chan (void *opaque, uint32_t nport, uint32_t data) { int ncont, ichan, nreg; struct dma_regs *r; @@ -153,7 +153,7 @@ static void write_chan (CPUState *env, uint32_t nport, uint32_t data) } } -static void write_cont (CPUState *env, uint32_t nport, uint32_t data) +static void write_cont (void *opaque, uint32_t nport, uint32_t data) { int iport, ichan, ncont; struct dma_cont *d; @@ -345,22 +345,22 @@ void DMA_init (void) int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; for (i = 0; i < 8; i++) { - register_ioport_write (i, 1, write_chan, 1); + register_ioport_write (i, 1, 1, write_chan, NULL); - register_ioport_write (0xc0 + (i << 1), 1, write_chan, 1); + register_ioport_write (0xc0 + (i << 1), 1, 1, write_chan, NULL); - register_ioport_read (i, 1, read_chan, 1); - register_ioport_read (0xc0 + (i << 1), 1, read_chan, 1); + register_ioport_read (i, 1, 1, read_chan, NULL); + register_ioport_read (0xc0 + (i << 1), 1, 1, read_chan, NULL); } for (i = 0; i < LENOFA (page_port_list); i++) { - register_ioport_write (page_port_list[i] + 0x80, 1, write_page, 1); - register_ioport_write (page_port_list[i] + 0x88, 1, write_page, 1); + register_ioport_write (page_port_list[i] + 0x80, 1, 1, write_page, NULL); + register_ioport_write (page_port_list[i] + 0x88, 1, 1, write_page, NULL); } for (i = 0; i < 8; i++) { - register_ioport_write (i + 8, 1, write_cont, 1); - register_ioport_write (0xd0 + (i << 1), 1, write_cont, 1); + register_ioport_write (i + 8, 1, 1, write_cont, NULL); + register_ioport_write (0xd0 + (i << 1), 1, 1, write_cont, NULL); } write_cont (NULL, 0x0d, 0); diff --git a/hw/sb16.c b/hw/sb16.c index 9fbf085f0..aee1d5fbd 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -50,9 +50,9 @@ #endif #define IO_READ_PROTO(name) \ - uint32_t name (struct CPUState *env, uint32_t nport) + uint32_t name (void *opaque, uint32_t nport) #define IO_WRITE_PROTO(name) \ - void name (struct CPUState *env, uint32_t nport, uint32_t val) + void name (void *opaque, uint32_t nport, uint32_t val) static struct { int ver_lo; @@ -550,8 +550,8 @@ static IO_WRITE_PROTO(mixer_write_datab) static IO_WRITE_PROTO(mixer_write_indexw) { - mixer_write_indexb (env, nport, val & 0xff); - mixer_write_datab (env, nport, (val >> 8) & 0xff); + mixer_write_indexb (opaque, nport, val & 0xff); + mixer_write_datab (opaque, nport, (val >> 8) & 0xff); } static IO_READ_PROTO(mixer_read) @@ -718,17 +718,17 @@ void SB16_init (void) } for (i = 0; i < LENOFA (dsp_write_ports); i++) { - register_ioport_write (sb.port + dsp_write_ports[i], 1, dsp_write, 1); + register_ioport_write (sb.port + dsp_write_ports[i], 1, 1, dsp_write, NULL); } for (i = 0; i < LENOFA (dsp_read_ports); i++) { - register_ioport_read (sb.port + dsp_read_ports[i], 1, dsp_read, 1); + register_ioport_read (sb.port + dsp_read_ports[i], 1, 1, dsp_read, NULL); } - register_ioport_write (sb.port + 0x4, 1, mixer_write_indexb, 1); - register_ioport_write (sb.port + 0x4, 1, mixer_write_indexw, 2); - register_ioport_read (sb.port + 0x5, 1, mixer_read, 1); - register_ioport_write (sb.port + 0x5, 1, mixer_write_datab, 1); + register_ioport_write (sb.port + 0x4, 1, 1, mixer_write_indexb, NULL); + register_ioport_write (sb.port + 0x4, 1, 2, mixer_write_indexw, NULL); + register_ioport_read (sb.port + 0x5, 1, 1, mixer_read, NULL); + register_ioport_write (sb.port + 0x5, 1, 1, mixer_write_datab, NULL); DMA_register_channel (sb.hdma, SB_read_DMA, NULL); DMA_register_channel (sb.dma, SB_read_DMA, NULL); -- cgit v1.2.3 From 0f35920cd8d323f77d553d18e1f4edd7e761aebf Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:42:10 +0000 Subject: io port API change - removed dumb console redraw (not useful) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@662 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 77 ++++++++++++++++++++-------------------------------------------- 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index b3c462ccb..452de61d0 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -40,9 +40,6 @@ #include #include -#define NO_THUNK_TYPE_SIZE -#include "thunk.h" - #include "cpu.h" #include "exec-all.h" @@ -260,9 +257,9 @@ static uint8_t expand4to8[16]; VGAState vga_state; int vga_io_memory; -static uint32_t vga_ioport_read(CPUState *env, uint32_t addr) +static uint32_t vga_ioport_read(void *opaque, uint32_t addr) { - VGAState *s = &vga_state; + VGAState *s = opaque; int val, index; /* check port range access depending on color/monochrome mode */ @@ -356,9 +353,9 @@ static uint32_t vga_ioport_read(CPUState *env, uint32_t addr) return val; } -static void vga_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - VGAState *s = &vga_state; + VGAState *s = opaque; int index, v; /* check port range access depending on color/monochrome mode */ @@ -506,9 +503,9 @@ static void vga_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } #ifdef CONFIG_BOCHS_VBE -static uint32_t vbe_ioport_read(CPUState *env, uint32_t addr) +static uint32_t vbe_ioport_read(void *opaque, uint32_t addr) { - VGAState *s = &vga_state; + VGAState *s = opaque; uint32_t val; addr &= 1; @@ -526,9 +523,9 @@ static uint32_t vbe_ioport_read(CPUState *env, uint32_t addr) return val; } -static void vbe_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - VGAState *s = &vga_state; + VGAState *s = opaque; addr &= 1; if (addr == 0) { @@ -1519,40 +1516,14 @@ static void vga_draw_graphic(VGAState *s, int full_update) } } -/* draw text terminal (very limited, just for simple boot debug - messages) */ -static int last_cursor_pos; - -void vga_draw_dumb(VGAState *s) -{ - int c, i, cursor_pos, eol; - - cursor_pos = s->cr[0x0f] | (s->cr[0x0e] << 8); - eol = 0; - for(i = last_cursor_pos; i < cursor_pos; i++) { - /* XXX: should use vga RAM */ - c = phys_ram_base[0xb8000 + (i) * 2]; - if (c >= ' ') { - putchar(c); - eol = 0; - } else { - if (!eol) - putchar('\n'); - eol = 1; - } - } - fflush(stdout); - last_cursor_pos = cursor_pos; -} - void vga_update_display(void) { VGAState *s = &vga_state; int full_update, graphic_mode; if (s->ds->depth == 0) { - vga_draw_dumb(s); - } else { + /* nothing to do */ + } else { full_update = 0; graphic_mode = s->gr[6] & 1; if (graphic_mode != s->graphic_mode) { @@ -1643,29 +1614,29 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, s->vram_size = vga_ram_size; s->ds = ds; - register_ioport_write(0x3c0, 16, vga_ioport_write, 1); + register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); - register_ioport_write(0x3b4, 2, vga_ioport_write, 1); - register_ioport_write(0x3d4, 2, vga_ioport_write, 1); - register_ioport_write(0x3ba, 1, vga_ioport_write, 1); - register_ioport_write(0x3da, 1, vga_ioport_write, 1); + register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s); + register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s); + register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s); + register_ioport_write(0x3da, 1, 1, vga_ioport_write, s); - register_ioport_read(0x3c0, 16, vga_ioport_read, 1); + register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s); - register_ioport_read(0x3b4, 2, vga_ioport_read, 1); - register_ioport_read(0x3d4, 2, vga_ioport_read, 1); - register_ioport_read(0x3ba, 1, vga_ioport_read, 1); - register_ioport_read(0x3da, 1, vga_ioport_read, 1); + register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s); + register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s); + register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); + register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); s->bank_offset = -0xa0000; #ifdef CONFIG_BOCHS_VBE s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0; s->vbe_bank_mask = ((s->vram_size >> 16) - 1); - register_ioport_read(0x1ce, 1, vbe_ioport_read, 2); - register_ioport_read(0x1cf, 1, vbe_ioport_read, 2); + register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s); + register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s); - register_ioport_write(0x1ce, 1, vbe_ioport_write, 2); - register_ioport_write(0x1cf, 1, vbe_ioport_write, 2); + register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s); + register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s); #endif vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); -- cgit v1.2.3 From c4b1fcc0f9594cae64d5bf172548a522db0c2545 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:44:30 +0000 Subject: added I/O API - io port API change - added multiple network interface support - redirect serial port to a pseudo terminal if using graphical mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@663 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 535 ++++++++++++++++++++++++++++++++++--------------------------------- vl.h | 100 +++++++++---- 2 files changed, 349 insertions(+), 286 deletions(-) diff --git a/vl.c b/vl.c index 432bc067a..8472f0a23 100644 --- a/vl.c +++ b/vl.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,7 @@ const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; CPUState *global_env; CPUState *cpu_single_env; +void *ioport_opaque[MAX_IOPORTS]; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD]; @@ -93,11 +95,14 @@ int boot_device = 'c'; static int ram_size; static char network_script[1024]; int pit_min_timer_count = 0; +int nb_nics; +NetDriverState nd_table[MAX_NICS]; +SerialState *serial_console; /***********************************************************/ /* x86 io ports */ -uint32_t default_ioport_readb(CPUState *env, uint32_t address) +uint32_t default_ioport_readb(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "inb: port=0x%04x\n", address); @@ -105,7 +110,7 @@ uint32_t default_ioport_readb(CPUState *env, uint32_t address) return 0xff; } -void default_ioport_writeb(CPUState *env, uint32_t address, uint32_t data) +void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data); @@ -113,21 +118,21 @@ void default_ioport_writeb(CPUState *env, uint32_t address, uint32_t data) } /* default is to make two byte accesses */ -uint32_t default_ioport_readw(CPUState *env, uint32_t address) +uint32_t default_ioport_readw(void *opaque, uint32_t address) { uint32_t data; - data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](env, address); - data |= ioport_read_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1) << 8; + data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](opaque, address); + data |= ioport_read_table[0][(address + 1) & (MAX_IOPORTS - 1)](opaque, address + 1) << 8; return data; } -void default_ioport_writew(CPUState *env, uint32_t address, uint32_t data) +void default_ioport_writew(void *opaque, uint32_t address, uint32_t data) { - ioport_write_table[0][address & (MAX_IOPORTS - 1)](env, address, data & 0xff); - ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1, (data >> 8) & 0xff); + ioport_write_table[0][address & (MAX_IOPORTS - 1)](opaque, address, data & 0xff); + ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](opaque, address + 1, (data >> 8) & 0xff); } -uint32_t default_ioport_readl(CPUState *env, uint32_t address) +uint32_t default_ioport_readl(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "inl: port=0x%04x\n", address); @@ -135,7 +140,7 @@ uint32_t default_ioport_readl(CPUState *env, uint32_t address) return 0xffffffff; } -void default_ioport_writel(CPUState *env, uint32_t address, uint32_t data) +void default_ioport_writel(void *opaque, uint32_t address, uint32_t data) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data); @@ -157,38 +162,52 @@ void init_ioports(void) } /* size is the word size in byte */ -int register_ioport_read(int start, int length, IOPortReadFunc *func, int size) +int register_ioport_read(int start, int length, int size, + IOPortReadFunc *func, void *opaque) { int i, bsize; - if (size == 1) + if (size == 1) { bsize = 0; - else if (size == 2) + } else if (size == 2) { bsize = 1; - else if (size == 4) + } else if (size == 4) { bsize = 2; - else + } else { + hw_error("register_ioport_read: invalid size"); return -1; - for(i = start; i < start + length; i += size) + } + for(i = start; i < start + length; i += size) { ioport_read_table[bsize][i] = func; + if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque) + hw_error("register_ioport_read: invalid opaque"); + ioport_opaque[i] = opaque; + } return 0; } /* size is the word size in byte */ -int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size) +int register_ioport_write(int start, int length, int size, + IOPortWriteFunc *func, void *opaque) { int i, bsize; - if (size == 1) + if (size == 1) { bsize = 0; - else if (size == 2) + } else if (size == 2) { bsize = 1; - else if (size == 4) + } else if (size == 4) { bsize = 2; - else + } else { + hw_error("register_ioport_write: invalid size"); return -1; - for(i = start; i < start + length; i += size) + } + for(i = start; i < start + length; i += size) { ioport_write_table[bsize][i] = func; + if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque) + hw_error("register_ioport_read: invalid opaque"); + ioport_opaque[i] = opaque; + } return 0; } @@ -238,32 +257,38 @@ int load_image(const char *filename, uint8_t *addr) void cpu_outb(CPUState *env, int addr, int val) { - ioport_write_table[0][addr & (MAX_IOPORTS - 1)](env, addr, val); + addr &= (MAX_IOPORTS - 1); + ioport_write_table[0][addr](ioport_opaque[addr], addr, val); } void cpu_outw(CPUState *env, int addr, int val) { - ioport_write_table[1][addr & (MAX_IOPORTS - 1)](env, addr, val); + addr &= (MAX_IOPORTS - 1); + ioport_write_table[1][addr](ioport_opaque[addr], addr, val); } void cpu_outl(CPUState *env, int addr, int val) { - ioport_write_table[2][addr & (MAX_IOPORTS - 1)](env, addr, val); + addr &= (MAX_IOPORTS - 1); + ioport_write_table[2][addr](ioport_opaque[addr], addr, val); } int cpu_inb(CPUState *env, int addr) { - return ioport_read_table[0][addr & (MAX_IOPORTS - 1)](env, addr); + addr &= (MAX_IOPORTS - 1); + return ioport_read_table[0][addr](ioport_opaque[addr], addr); } int cpu_inw(CPUState *env, int addr) { - return ioport_read_table[1][addr & (MAX_IOPORTS - 1)](env, addr); + addr &= (MAX_IOPORTS - 1); + return ioport_read_table[1][addr](ioport_opaque[addr], addr); } int cpu_inl(CPUState *env, int addr) { - return ioport_read_table[2][addr & (MAX_IOPORTS - 1)](env, addr); + addr &= (MAX_IOPORTS - 1); + return ioport_read_table[2][addr](ioport_opaque[addr], addr); } /***********************************************************/ @@ -389,171 +414,34 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) return res.ll; } -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ -static int term_got_escape, term_command; -static unsigned char term_cmd_buf[128]; - -typedef struct term_cmd_t { - const unsigned char *name; - void (*handler)(unsigned char *params); -} term_cmd_t; - -static void do_change_cdrom (unsigned char *params); -static void do_change_fd0 (unsigned char *params); -static void do_change_fd1 (unsigned char *params); - -static term_cmd_t term_cmds[] = { - { "changecd", &do_change_cdrom, }, - { "changefd0", &do_change_fd0, }, - { "changefd1", &do_change_fd1, }, - { NULL, NULL, }, -}; - -void term_print_help(void) -{ - printf("\n" - "C-a h print this help\n" - "C-a x exit emulatior\n" - "C-a d switch on/off debug log\n" - "C-a s save disk data back to file (if -snapshot)\n" - "C-a b send break (magic sysrq)\n" - "C-a c send qemu internal command\n" - "C-a C-a send C-a\n" - ); -} - -static void do_change_cdrom (unsigned char *params) -{ - /* Dunno how to do it... */ -} - -static void do_change_fd (int fd, unsigned char *params) -{ - unsigned char *name_start, *name_end, *ros; - int ro; - - for (name_start = params; - isspace(*name_start); name_start++) - continue; - if (*name_start == '\0') - return; - for (name_end = name_start; - !isspace(*name_end) && *name_end != '\0'; name_end++) - continue; - for (ros = name_end + 1; isspace(*ros); ros++) - continue; - if (ros[0] == 'r' && ros[1] == 'o') - ro = 1; - else - ro = 0; - *name_end = '\0'; - printf("Change fd %d to %s (%s)\n", fd, name_start, params); - fdctrl_disk_change(fd, name_start, ro); -} - -static void do_change_fd0 (unsigned char *params) -{ - do_change_fd(0, params); -} - -static void do_change_fd1 (unsigned char *params) -{ - do_change_fd(1, params); -} +/***********************************************************/ +/* serial device */ -static void term_treat_command(void) +int serial_open_device(void) { - unsigned char *cmd_start, *cmd_end; - int i; + char slave_name[1024]; + int master_fd, slave_fd; - for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++) - continue; - for (cmd_end = cmd_start; - !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++) - continue; - for (i = 0; term_cmds[i].name != NULL; i++) { - if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) && - memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) { - (*term_cmds[i].handler)(cmd_end + 1); - return; - } - } - *cmd_end = '\0'; - printf("Unknown term command: %s\n", cmd_start); -} - -extern FILE *logfile; - -/* called when a char is received */ -void term_received_byte(int ch) -{ - if (term_command) { - if (ch == '\n' || ch == '\r' || term_command == 127) { - printf("\n"); - term_treat_command(); - term_command = 0; - } else { - if (ch == 0x7F || ch == 0x08) { - if (term_command > 1) { - term_cmd_buf[--term_command - 1] = '\0'; - printf("\r " - " "); - printf("\r> %s", term_cmd_buf); - } - } else if (ch > 0x1f) { - term_cmd_buf[term_command++ - 1] = ch; - term_cmd_buf[term_command - 1] = '\0'; - printf("\r> %s", term_cmd_buf); - } - fflush(stdout); - } - } else if (term_got_escape) { - term_got_escape = 0; - switch(ch) { - case 'h': - term_print_help(); - break; - case 'x': - exit(0); - break; - case 's': - { - int i; - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) - bdrv_commit(bs_table[i]); - } - } - break; - case 'b': - serial_receive_break(); - break; - case 'c': - printf("> "); - fflush(stdout); - term_command = 1; - break; - case 'd': - cpu_set_log(CPU_LOG_ALL); - break; - case TERM_ESCAPE: - goto send_char; - } - } else if (ch == TERM_ESCAPE) { - term_got_escape = 1; + if (serial_console == NULL && nographic) { + /* use console for serial port */ + return 0; } else { - send_char: - serial_receive_byte(ch); + if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { + fprintf(stderr, "warning: could not create pseudo terminal for serial port\n"); + return -1; + } + fprintf(stderr, "Serial port redirected to %s\n", slave_name); + return master_fd; } } /***********************************************************/ /* Linux network device redirector */ -int net_init(void) +static int tun_open(char *ifname, int ifname_size) { struct ifreq ifr; - int fd, ret, pid, status; + int fd, ret; fd = open("/dev/net/tun", O_RDWR); if (fd < 0) { @@ -570,32 +458,62 @@ int net_init(void) return -1; } printf("Connected to host network interface: %s\n", ifr.ifr_name); + pstrcpy(ifname, ifname_size, ifr.ifr_name); fcntl(fd, F_SETFL, O_NONBLOCK); - net_fd = fd; + return fd; +} - /* try to launch network init script */ - pid = fork(); - if (pid >= 0) { - if (pid == 0) { - execl(network_script, network_script, ifr.ifr_name, NULL); - exit(1); +static int net_init(void) +{ + int pid, status, launch_script, i; + NetDriverState *nd; + char *args[MAX_NICS + 2]; + char **parg; + + launch_script = 0; + for(i = 0; i < nb_nics; i++) { + nd = &nd_table[i]; + if (nd->fd < 0) { + nd->fd = tun_open(nd->ifname, sizeof(nd->ifname)); + if (nd->fd >= 0) + launch_script = 1; } - while (waitpid(pid, &status, 0) != pid); - if (!WIFEXITED(status) || - WEXITSTATUS(status) != 0) { - fprintf(stderr, "%s: could not launch network script for '%s'\n", - network_script, ifr.ifr_name); + } + + if (launch_script) { + /* try to launch network init script */ + pid = fork(); + if (pid >= 0) { + if (pid == 0) { + parg = args; + *parg++ = network_script; + for(i = 0; i < nb_nics; i++) { + nd = &nd_table[i]; + if (nd->fd >= 0) { + *parg++ = nd->ifname; + } + } + *parg++ = NULL; + execv(network_script, args); + exit(1); + } + while (waitpid(pid, &status, 0) != pid); + if (!WIFEXITED(status) || + WEXITSTATUS(status) != 0) { + fprintf(stderr, "%s: could not launch network script\n", + network_script); + } } } return 0; } -void net_send_packet(int net_fd, const uint8_t *buf, int size) +void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size) { #ifdef DEBUG_NE2000 printf("NE2000: sending packet size=%d\n", size); #endif - write(net_fd, buf, size); + write(nd->fd, buf, size); } /***********************************************************/ @@ -702,6 +620,37 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, } } +#define MAX_IO_HANDLERS 64 + +typedef struct IOHandlerRecord { + int fd; + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *opaque; + /* temporary data */ + struct pollfd *ufd; + int max_size; +} IOHandlerRecord; + +static IOHandlerRecord io_handlers[MAX_IO_HANDLERS]; +static int nb_io_handlers = 0; + +int add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + IOHandlerRecord *ioh; + + if (nb_io_handlers >= MAX_IO_HANDLERS) + return -1; + ioh = &io_handlers[nb_io_handlers]; + ioh->fd = fd; + ioh->fd_can_read = fd_can_read; + ioh->fd_read = fd_read; + ioh->opaque = opaque; + nb_io_handlers++; + return 0; +} + /* main execution loop */ CPUState *cpu_gdbstub_get_env(void *opaque) @@ -711,12 +660,10 @@ CPUState *cpu_gdbstub_get_env(void *opaque) int main_loop(void *opaque) { - struct pollfd ufds[3], *pf, *serial_ufd, *gdb_ufd; -#if defined (TARGET_I386) - struct pollfd *net_ufd; -#endif - int ret, n, timeout, serial_ok; - uint8_t ch; + struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf, *gdb_ufd; + int ret, n, timeout, serial_ok, max_size, i; + uint8_t buf[4096]; + IOHandlerRecord *ioh; CPUState *env = global_env; if (!term_inited) { @@ -747,24 +694,26 @@ int main_loop(void *opaque) timeout = 10; else timeout = 0; + /* poll any events */ - serial_ufd = NULL; pf = ufds; - if (serial_ok && serial_can_receive()) { - serial_ufd = pf; - pf->fd = 0; - pf->events = POLLIN; - pf++; - } -#if defined (TARGET_I386) - net_ufd = NULL; - if (net_fd > 0 && ne2000_can_receive()) { - net_ufd = pf; - pf->fd = net_fd; - pf->events = POLLIN; - pf++; + ioh = io_handlers; + for(i = 0; i < nb_io_handlers; i++) { + max_size = ioh->fd_can_read(ioh->opaque); + if (max_size > 0) { + if (max_size > sizeof(buf)) + max_size = sizeof(buf); + pf->fd = ioh->fd; + pf->events = POLLIN; + ioh->ufd = pf; + pf++; + } else { + ioh->ufd = NULL; + } + ioh->max_size = max_size; + ioh++; } -#endif + gdb_ufd = NULL; if (gdbstub_fd > 0) { gdb_ufd = pf; @@ -775,29 +724,17 @@ int main_loop(void *opaque) ret = poll(ufds, pf - ufds, timeout); if (ret > 0) { - if (serial_ufd && (serial_ufd->revents & POLLIN)) { - n = read(0, &ch, 1); - if (n == 1) { - term_received_byte(ch); - } else { - /* Closed, stop polling. */ - serial_ok = 0; - } - } -#if defined (TARGET_I386) - if (net_ufd && (net_ufd->revents & POLLIN)) { - uint8_t buf[MAX_ETH_FRAME_SIZE]; - - n = read(net_fd, buf, MAX_ETH_FRAME_SIZE); - if (n > 0) { - if (n < 60) { - memset(buf + n, 0, 60 - n); - n = 60; + ioh = io_handlers; + for(i = 0; i < nb_io_handlers; i++) { + pf = ioh->ufd; + if (pf) { + n = read(ioh->fd, buf, ioh->max_size); + if (n > 0) { + ioh->fd_read(ioh->opaque, buf, n); } - ne2000_receive(buf, n); } + ioh++; } -#endif if (gdb_ufd && (gdb_ufd->revents & POLLIN)) { uint8_t buf[1]; /* stop emulation if requested by gdb */ @@ -845,15 +782,18 @@ void help(void) "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" - "-cdrom file use 'file' as IDE cdrom 2 image\n" + "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-boot [a|b|c|d] boot on floppy (a, b), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB\n" + "-nographic disable graphical output and redirect serial I/Os to console\n" + "\n" + "Network options:\n" "-n script set network init script [default=%s]\n" - "-tun-fd fd this fd talks to tap/tun, use it.\n" - "-nographic disable graphical output\n" + "-nics n simulate 'n' network interfaces [default=1]\n" + "-tun-fd fd0[,...] use these fds as already opened tap/tun interfaces\n" "\n" - "Linux boot specific (does not require PC BIOS):\n" + "Linux boot specific:\n" "-kernel bzImage use 'bzImage' as kernel image\n" "-append cmdline use 'cmdline' as kernel command line\n" "-initrd file use 'file' as initial ram disk\n" @@ -904,7 +844,8 @@ struct option long_options[] = { { "boot", 1, NULL, 0, }, { "fda", 1, NULL, 0, }, { "fdb", 1, NULL, 0, }, - { "no-code-copy", 0, NULL, 0}, + { "no-code-copy", 0, NULL, 0 }, + { "nics", 1, NULL, 0 }, { NULL, 0, NULL, 0 }, }; @@ -931,7 +872,7 @@ static uint8_t *signal_stack; int main(int argc, char **argv) { - int c, i, use_gdbstub, gdbstub_port, long_index; + int c, i, use_gdbstub, gdbstub_port, long_index, has_cdrom; int snapshot, linux_boot; struct sigaction act; struct itimerval itv; @@ -940,6 +881,7 @@ int main(int argc, char **argv) const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; + int cyls, heads, secs; /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); @@ -950,15 +892,29 @@ int main(int argc, char **argv) hd_filename[i] = NULL; ram_size = 32 * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; -#if defined (TARGET_I386) pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); -#endif use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; snapshot = 0; nographic = 0; kernel_filename = NULL; kernel_cmdline = ""; + has_cdrom = 1; + cyls = heads = secs = 0; + + nb_nics = 1; + for(i = 0; i < MAX_NICS; i++) { + NetDriverState *nd = &nd_table[i]; + nd->fd = -1; + /* init virtual mac address */ + nd->macaddr[0] = 0x52; + nd->macaddr[1] = 0x54; + nd->macaddr[2] = 0x00; + nd->macaddr[3] = 0x12; + nd->macaddr[4] = 0x34; + nd->macaddr[5] = 0x56 + i; + } + for(;;) { c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index); if (c == -1) @@ -980,7 +936,6 @@ int main(int argc, char **argv) break; case 4: { - int cyls, heads, secs; const char *p; p = optarg; cyls = strtol(p, (char **)&p, 0); @@ -992,10 +947,10 @@ int main(int argc, char **argv) goto chs_fail; p++; secs = strtol(p, (char **)&p, 0); - if (*p != '\0') - goto chs_fail; - ide_set_geometry(0, cyls, heads, secs); - chs_fail: ; + if (*p != '\0') { + chs_fail: + cyls = 0; + } } break; case 5: @@ -1007,20 +962,38 @@ int main(int argc, char **argv) case 7: kernel_cmdline = optarg; break; -#if defined (TARGET_I386) case 8: - net_fd = atoi(optarg); + { + const char *p; + int fd; + p = optarg; + nb_nics = 0; + for(;;) { + fd = strtol(p, (char **)&p, 0); + nd_table[nb_nics].fd = fd; + snprintf(nd_table[nb_nics].ifname, + sizeof(nd_table[nb_nics].ifname), + "fd%d", nb_nics); + nb_nics++; + if (*p == ',') { + p++; + } else if (*p != '\0') { + fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_nics); + exit(1); + } + } + } break; -#endif case 9: hd_filename[2] = optarg; + has_cdrom = 0; break; case 10: hd_filename[3] = optarg; break; case 11: hd_filename[2] = optarg; - ide_set_cdrom(2, 1); + has_cdrom = 1; break; case 12: boot_device = optarg[0]; @@ -1039,6 +1012,13 @@ int main(int argc, char **argv) case 15: code_copy_enabled = 0; break; + case 16: + nb_nics = atoi(optarg); + if (nb_nics < 1 || nb_nics > MAX_NICS) { + fprintf(stderr, "qemu: invalid number of network interfaces\n"); + exit(1); + } + break; } break; case 'h': @@ -1057,11 +1037,9 @@ int main(int argc, char **argv) case 'd': cpu_set_log(CPU_LOG_ALL); break; -#if defined (TARGET_I386) case 'n': pstrcpy(network_script, sizeof(network_script), optarg); break; -#endif case 's': use_gdbstub = 1; break; @@ -1102,11 +1080,8 @@ int main(int argc, char **argv) setvbuf(stdout, NULL, _IOLBF, 0); #endif - /* init network tun interface */ -#if defined (TARGET_I386) - if (net_fd < 0) - net_init(); -#endif + /* init host network redirectors */ + net_init(); /* init the memory */ phys_ram_size = ram_size + vga_ram_size; @@ -1151,15 +1126,49 @@ int main(int argc, char **argv) } #endif + /* we always create the cdrom drive, even if no disk is there */ + if (has_cdrom) { + bs_table[2] = bdrv_new("cdrom"); + bdrv_set_type_hint(bs_table[2], BDRV_TYPE_CDROM); + } + /* open the virtual block devices */ for(i = 0; i < MAX_DISKS; i++) { if (hd_filename[i]) { - bs_table[i] = bdrv_open(hd_filename[i], snapshot); if (!bs_table[i]) { + char buf[64]; + snprintf(buf, sizeof(buf), "hd%c", i + 'a'); + bs_table[i] = bdrv_new(buf); + } + if (bdrv_open(bs_table[i], hd_filename[i], snapshot) < 0) { fprintf(stderr, "qemu: could not open hard disk image '%s\n", hd_filename[i]); exit(1); } + if (i == 0 && cyls != 0) + bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); + } + } + + /* we always create at least one floppy disk */ + fd_table[0] = bdrv_new("fda"); + bdrv_set_type_hint(fd_table[0], BDRV_TYPE_FLOPPY); + + for(i = 0; i < MAX_FD; i++) { + if (fd_filename[i]) { + if (!fd_table[i]) { + char buf[64]; + snprintf(buf, sizeof(buf), "fd%c", i + 'a'); + fd_table[i] = bdrv_new(buf); + bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY); + } + if (fd_filename[i] != '\0') { + if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) { + fprintf(stderr, "qemu: could not open floppy disk image '%s\n", + fd_filename[i]); + exit(1); + } + } } } @@ -1190,6 +1199,10 @@ int main(int argc, char **argv) ppc_init(); #endif + /* launched after the device init so that it can display or not a + banner */ + monitor_init(); + /* setup cpu signal handlers for MMU / self modifying code handling */ #if !defined(CONFIG_SOFTMMU) diff --git a/vl.h b/vl.h index 026a5dee5..50e160987 100644 --- a/vl.h +++ b/vl.h @@ -31,16 +31,16 @@ extern int reset_requested; extern int64_t ticks_per_sec; extern int pit_min_timer_count; -typedef void (IOPortWriteFunc)(struct CPUState *env, uint32_t address, uint32_t data); -typedef uint32_t (IOPortReadFunc)(struct CPUState *env, uint32_t address); +typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); -int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); -int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); +int register_ioport_read(int start, int length, int size, + IOPortReadFunc *func, void *opaque); +int register_ioport_write(int start, int length, int size, + IOPortWriteFunc *func, void *opaque); int64_t cpu_get_ticks(void); uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); -void net_send_packet(int net_fd, const uint8_t *buf, int size); - void hw_error(const char *fmt, ...); int load_image(const char *filename, uint8_t *addr); @@ -49,10 +49,37 @@ extern const char *bios_dir; void pstrcpy(char *buf, int buf_size, const char *str); char *pstrcat(char *buf, int buf_size, const char *s); +int serial_open_device(void); + +/* network redirectors support */ + +#define MAX_NICS 8 + +typedef struct NetDriverState { + int fd; + uint8_t macaddr[6]; + char ifname[16]; +} NetDriverState; + +extern int nb_nics; +extern NetDriverState nd_table[MAX_NICS]; + +void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size); + +/* async I/O support */ + +typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); +typedef int IOCanRWHandler(void *opaque); + +int add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque); + /* block.c */ typedef struct BlockDriverState BlockDriverState; -BlockDriverState *bdrv_open(const char *filename, int snapshot); +BlockDriverState *bdrv_new(const char *device_name); +void bdrv_delete(BlockDriverState *bs); +int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot); void bdrv_close(BlockDriverState *bs); int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); @@ -62,6 +89,27 @@ void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); +#define BDRV_TYPE_HD 0 +#define BDRV_TYPE_CDROM 1 +#define BDRV_TYPE_FLOPPY 2 + +void bdrv_set_geometry_hint(BlockDriverState *bs, + int cyls, int heads, int secs); +void bdrv_set_type_hint(BlockDriverState *bs, int type); +void bdrv_get_geometry_hint(BlockDriverState *bs, + int *pcyls, int *pheads, int *psecs); +int bdrv_get_type_hint(BlockDriverState *bs); +int bdrv_is_removable(BlockDriverState *bs); +int bdrv_is_read_only(BlockDriverState *bs); +int bdrv_is_inserted(BlockDriverState *bs); +int bdrv_is_locked(BlockDriverState *bs); +void bdrv_set_locked(BlockDriverState *bs, int locked); +void bdrv_set_change_cb(BlockDriverState *bs, + void (*change_cb)(void *opaque), void *opaque); + +void bdrv_info(void); +BlockDriverState *bdrv_find(const char *name); + /* vga.c */ #define VGA_RAM_SIZE (4096 * 1024) @@ -97,9 +145,8 @@ void sdl_display_init(DisplayState *ds); extern BlockDriverState *bs_table[MAX_DISKS]; -void ide_init(void); -void ide_set_geometry(int n, int cyls, int heads, int secs); -void ide_set_cdrom(int n, int is_cdrom); +void ide_init(int iobase, int iobase2, int irq, + BlockDriverState *hd0, BlockDriverState *hd1); /* oss.c */ typedef enum { @@ -138,20 +185,13 @@ void SB16_init (void); #define MAX_FD 2 extern BlockDriverState *fd_table[MAX_FD]; -void cmos_register_fd (uint8_t fd0, uint8_t fd1); void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, - char boot_device); -int fdctrl_disk_change (int idx, const unsigned char *filename, int ro); + BlockDriverState **fds); +int fdctrl_get_drive_type(int drive_num); /* ne2000.c */ -#define MAX_ETH_FRAME_SIZE 1514 - -void ne2000_init(int base, int irq); -int ne2000_can_receive(void); -void ne2000_receive(uint8_t *buf, int size); - -extern int net_fd; +void ne2000_init(int base, int irq, NetDriverState *nd); /* pckbd.c */ @@ -179,10 +219,14 @@ void rtc_timer(void); /* serial.c */ -void serial_init(int base, int irq); -int serial_can_receive(void); -void serial_receive_byte(int ch); -void serial_receive_break(void); +typedef struct SerialState SerialState; + +extern SerialState *serial_console; + +SerialState *serial_init(int base, int irq, int fd); +int serial_can_receive(SerialState *s); +void serial_receive_byte(SerialState *s, int ch); +void serial_receive_break(SerialState *s); /* i8259.c */ @@ -206,7 +250,7 @@ typedef struct PITChannelState { extern PITChannelState pit_channels[3]; -void pit_init(void); +void pit_init(int base); void pit_set_gate(PITChannelState *s, int val); int pit_get_out(PITChannelState *s); int pit_get_out_edges(PITChannelState *s); @@ -217,4 +261,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); +/* monitor.c */ +void monitor_init(void); +void term_printf(const char *fmt, ...); +void term_flush(void); +void term_print_help(void); + #endif /* VL_H */ -- cgit v1.2.3 From b41a2cd1e4228c765e3b82ec6c89096528b4d7d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:46:48 +0000 Subject: io port API change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@664 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8254.c | 10 +++--- hw/i8259.c | 22 ++++++------ hw/mc146818rtc.c | 12 +++---- hw/ne2000.c | 90 +++++++++++++++++++++++++++---------------------- hw/pc.c | 100 ++++++++++++++++++++++++++++++------------------------- hw/pckbd.c | 36 ++++++++++---------- hw/serial.c | 81 ++++++++++++++++++++++++++------------------ 7 files changed, 193 insertions(+), 158 deletions(-) diff --git a/hw/i8254.c b/hw/i8254.c index 7dc5f3c25..6e9682501 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -201,7 +201,7 @@ static inline void pit_load_count(PITChannelState *s, int val) } } -void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) { int channel, access; PITChannelState *s; @@ -246,7 +246,7 @@ void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } } -uint32_t pit_ioport_read(CPUState *env, uint32_t addr) +static uint32_t pit_ioport_read(void *opaque, uint32_t addr) { int ret, count; PITChannelState *s; @@ -279,7 +279,7 @@ uint32_t pit_ioport_read(CPUState *env, uint32_t addr) return ret; } -void pit_init(void) +void pit_init(int base) { PITChannelState *s; int i; @@ -291,7 +291,7 @@ void pit_init(void) pit_load_count(s, 0); } - register_ioport_write(0x40, 4, pit_ioport_write, 1); - register_ioport_read(0x40, 3, pit_ioport_read, 1); + register_ioport_write(base, 4, 1, pit_ioport_write, NULL); + register_ioport_read(base, 3, 1, pit_ioport_read, NULL); } diff --git a/hw/i8259.c b/hw/i8259.c index 08c7be394..5ef1fa070 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -46,6 +46,8 @@ /* debug PIC */ //#define DEBUG_PIC +//#define DEBUG_IRQ_LATENCY + typedef struct PicState { uint8_t last_irr; /* edge detection */ uint8_t irr; /* interrupt request register */ @@ -220,15 +222,14 @@ int cpu_x86_get_pic_interrupt(CPUState *env) return intno; } -void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - PicState *s; + PicState *s = opaque; int priority, cmd, irq; #ifdef DEBUG_PIC printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); #endif - s = &pics[addr >> 7]; addr &= 1; if (addr == 0) { if (val & 0x10) { @@ -334,14 +335,13 @@ static uint32_t pic_poll_read (PicState *s, uint32_t addr1) return ret; } -uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) +static uint32_t pic_ioport_read(void *opaque, uint32_t addr1) { - PicState *s; + PicState *s = opaque; unsigned int addr; int ret; addr = addr1; - s = &pics[addr >> 7]; addr &= 1; if (s->poll) { ret = pic_poll_read(s, addr1); @@ -378,11 +378,9 @@ uint32_t pic_intack_read(CPUState *env) void pic_init(void) { -#if defined (TARGET_I386) || defined (TARGET_PPC) - register_ioport_write(0x20, 2, pic_ioport_write, 1); - register_ioport_read(0x20, 2, pic_ioport_read, 1); - register_ioport_write(0xa0, 2, pic_ioport_write, 1); - register_ioport_read(0xa0, 2, pic_ioport_read, 1); -#endif + register_ioport_write(0x20, 2, 1, pic_ioport_write, &pics[0]); + register_ioport_read(0x20, 2, 1, pic_ioport_read, &pics[0]); + register_ioport_write(0xa0, 2, 1, pic_ioport_write, &pics[1]); + register_ioport_read(0xa0, 2, 1, pic_ioport_read, &pics[1]); } diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index cab76cfab..7d94b25f5 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -69,9 +69,9 @@ RTCState rtc_state; -static void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) +static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) { - RTCState *s = &rtc_state; + RTCState *s = opaque; if ((addr & 1) == 0) { s->cmos_index = data & 0x7f; @@ -134,9 +134,9 @@ static void cmos_update_time(RTCState *s) s->cmos_data[REG_IBM_PS2_CENTURY_BYTE] = s->cmos_data[REG_IBM_CENTURY_BYTE]; } -static uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) +static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) { - RTCState *s = &rtc_state; + RTCState *s = opaque; int ret; if ((addr & 1) == 0) { return 0xff; @@ -197,7 +197,7 @@ void rtc_init(int base, int irq) s->cmos_data[RTC_REG_C] = 0x00; s->cmos_data[RTC_REG_D] = 0x80; - register_ioport_write(base, 2, cmos_ioport_write, 1); - register_ioport_read(base, 2, cmos_ioport_read, 1); + register_ioport_write(base, 2, 1, cmos_ioport_write, s); + register_ioport_read(base, 2, 1, cmos_ioport_read, s); } diff --git a/hw/ne2000.c b/hw/ne2000.c index 0b35495f9..3bb55171a 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -46,8 +46,7 @@ /* debug NE2000 card */ //#define DEBUG_NE2000 -/***********************************************************/ -/* ne2000 emulation */ +#define MAX_ETH_FRAME_SIZE 1514 #define E8390_CMD 0x00 /* The command register (for all pages) */ /* Page 0 register offsets. */ @@ -143,23 +142,16 @@ typedef struct NE2000State { uint8_t curpag; uint8_t mult[8]; /* multicast mask array */ int irq; + NetDriverState *nd; uint8_t mem[NE2000_MEM_SIZE]; } NE2000State; -static NE2000State ne2000_state; -int net_fd = -1; - static void ne2000_reset(NE2000State *s) { int i; s->isr = ENISR_RESET; - s->mem[0] = 0x52; - s->mem[1] = 0x54; - s->mem[2] = 0x00; - s->mem[3] = 0x12; - s->mem[4] = 0x34; - s->mem[5] = 0x56; + memcpy(s->mem, s->nd->macaddr, 6); s->mem[14] = 0x57; s->mem[15] = 0x57; @@ -180,10 +172,10 @@ static void ne2000_update_irq(NE2000State *s) pic_set_irq(s->irq, 0); } -/* return true if the NE2000 can receive more data */ -int ne2000_can_receive(void) +/* return the max buffer size if the NE2000 can receive more data */ +static int ne2000_can_receive(void *opaque) { - NE2000State *s = &ne2000_state; + NE2000State *s = opaque; int avail, index, boundary; if (s->cmd & E8390_STOP) @@ -196,19 +188,30 @@ int ne2000_can_receive(void) avail = (s->stop - s->start) - (index - boundary); if (avail < (MAX_ETH_FRAME_SIZE + 4)) return 0; - return 1; + return MAX_ETH_FRAME_SIZE; } -void ne2000_receive(uint8_t *buf, int size) +#define MIN_BUF_SIZE 60 + +static void ne2000_receive(void *opaque, const uint8_t *buf, int size) { - NE2000State *s = &ne2000_state; + NE2000State *s = opaque; uint8_t *p; int total_len, next, avail, len, index; - + uint8_t buf1[60]; + #if defined(DEBUG_NE2000) printf("NE2000: received len=%d\n", size); #endif + /* if too small buffer, then expand it */ + if (size < MIN_BUF_SIZE) { + memcpy(buf1, buf, size); + memset(buf1 + size, 0, MIN_BUF_SIZE - size); + buf = buf1; + size = MIN_BUF_SIZE; + } + index = s->curpag << 8; /* 4 bytes for header */ total_len = size + 4; @@ -244,9 +247,9 @@ void ne2000_receive(uint8_t *buf, int size) ne2000_update_irq(s); } -static void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - NE2000State *s = &ne2000_state; + NE2000State *s = opaque; int offset, page; addr &= 0xf; @@ -264,7 +267,7 @@ static void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) ne2000_update_irq(s); } if (val & E8390_TRANS) { - net_send_packet(net_fd, s->mem + (s->tpsr << 8), s->tcnt); + net_send_packet(s->nd, s->mem + (s->tpsr << 8), s->tcnt); /* signal end of transfert */ s->tsr = ENTSR_PTX; s->isr |= ENISR_TX; @@ -329,9 +332,9 @@ static void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } } -static uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) +static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) { - NE2000State *s = &ne2000_state; + NE2000State *s = opaque; int offset, page, ret; addr &= 0xf; @@ -370,9 +373,9 @@ static uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) return ret; } -static void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - NE2000State *s = &ne2000_state; + NE2000State *s = opaque; uint8_t *p; #ifdef DEBUG_NE2000 @@ -401,9 +404,9 @@ static void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } } -static uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) +static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) { - NE2000State *s = &ne2000_state; + NE2000State *s = opaque; uint8_t *p; int ret; @@ -433,33 +436,40 @@ static uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) return ret; } -static void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val) { /* nothing to do (end of reset pulse) */ } -static uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr) +static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) { - NE2000State *s = &ne2000_state; + NE2000State *s = opaque; ne2000_reset(s); return 0; } -void ne2000_init(int base, int irq) +void ne2000_init(int base, int irq, NetDriverState *nd) { - NE2000State *s = &ne2000_state; + NE2000State *s; - register_ioport_write(base, 16, ne2000_ioport_write, 1); - register_ioport_read(base, 16, ne2000_ioport_read, 1); + s = qemu_mallocz(sizeof(NE2000State)); + if (!s) + return; + + register_ioport_write(base, 16, 1, ne2000_ioport_write, s); + register_ioport_read(base, 16, 1, ne2000_ioport_read, s); - register_ioport_write(base + 0x10, 1, ne2000_asic_ioport_write, 1); - register_ioport_read(base + 0x10, 1, ne2000_asic_ioport_read, 1); - register_ioport_write(base + 0x10, 2, ne2000_asic_ioport_write, 2); - register_ioport_read(base + 0x10, 2, ne2000_asic_ioport_read, 2); + register_ioport_write(base + 0x10, 1, 1, ne2000_asic_ioport_write, s); + register_ioport_read(base + 0x10, 1, 1, ne2000_asic_ioport_read, s); + register_ioport_write(base + 0x10, 2, 2, ne2000_asic_ioport_write, s); + register_ioport_read(base + 0x10, 2, 2, ne2000_asic_ioport_read, s); - register_ioport_write(base + 0x1f, 1, ne2000_reset_ioport_write, 1); - register_ioport_read(base + 0x1f, 1, ne2000_reset_ioport_read, 1); + register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); + register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); s->irq = irq; + s->nd = nd; ne2000_reset(s); + + add_fd_read_handler(nd->fd, ne2000_can_receive, ne2000_receive, s); } diff --git a/hw/pc.c b/hw/pc.c index bee812c2b..071d84023 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -43,6 +43,9 @@ #include "cpu.h" #include "vl.h" +/* output Bochs bios info messages */ +//#define DEBUG_BIOS + #define BIOS_FILENAME "bios.bin" #define VGABIOS_FILENAME "vgabios.bin" #define LINUX_BOOT_FILENAME "linux_boot.bin" @@ -55,7 +58,7 @@ int speaker_data_on; int dummy_refresh_clock; -static void ioport80_write(CPUState *env, uint32_t addr, uint32_t data) +static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { } @@ -65,6 +68,7 @@ static void cmos_init(int ram_size, int boot_device) { RTCState *s = &rtc_state; int val; + int fd0, fd1, nb; /* various important CMOS locations needed by PC/Bochs bios */ @@ -99,12 +103,11 @@ static void cmos_init(int ram_size, int boot_device) s->cmos_data[0x3d] = 0x03; /* CD-ROM boot */ break; } -} -void cmos_register_fd (uint8_t fd0, uint8_t fd1) -{ - RTCState *s = &rtc_state; - int nb = 0; + /* floppy type */ + + fd0 = fdctrl_get_drive_type(0); + fd1 = fdctrl_get_drive_type(1); s->cmos_data[0x10] = 0; switch (fd0) { @@ -135,6 +138,7 @@ void cmos_register_fd (uint8_t fd0, uint8_t fd1) s->cmos_data[0x10] |= 0x02; break; } + nb = 0; if (fd0 < 3) nb++; if (fd1 < 3) @@ -151,13 +155,13 @@ void cmos_register_fd (uint8_t fd0, uint8_t fd1) } } -void speaker_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) { speaker_data_on = (val >> 1) & 1; pit_set_gate(&pit_channels[2], val & 1); } -uint32_t speaker_ioport_read(CPUState *env, uint32_t addr) +static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) { int out; out = pit_get_out(&pit_channels[2]); @@ -166,28 +170,10 @@ uint32_t speaker_ioport_read(CPUState *env, uint32_t addr) (dummy_refresh_clock << 4); } -/***********************************************************/ -/* PC floppy disk controler emulation glue */ -#define PC_FDC_DMA 0x2 -#define PC_FDC_IRQ 0x6 -#define PC_FDC_BASE 0x3F0 - -static void fdctrl_register (unsigned char **disknames, int ro, - char boot_device) -{ - int i; - - fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device); - for (i = 0; i < MAX_FD; i++) { - if (disknames[i] != NULL) - fdctrl_disk_change(i, disknames[i], ro); - } -} - /***********************************************************/ /* Bochs BIOS debug ports */ -void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) +void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) { switch(addr) { /* Bochs BIOS messages */ @@ -218,15 +204,15 @@ void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) void bochs_bios_init(void) { - register_ioport_write(0x400, 1, bochs_bios_write, 2); - register_ioport_write(0x401, 1, bochs_bios_write, 2); - register_ioport_write(0x402, 1, bochs_bios_write, 1); - register_ioport_write(0x403, 1, bochs_bios_write, 1); - - register_ioport_write(0x501, 1, bochs_bios_write, 2); - register_ioport_write(0x502, 1, bochs_bios_write, 2); - register_ioport_write(0x500, 1, bochs_bios_write, 1); - register_ioport_write(0x503, 1, bochs_bios_write, 1); + register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL); + register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); + register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL); + register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL); + + register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL); + register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); + register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL); + register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); } @@ -261,6 +247,15 @@ int load_kernel(const char *filename, uint8_t *addr, return -1; } +static const int ide_iobase[2] = { 0x1f0, 0x170 }; +static const int ide_iobase2[2] = { 0x3f6, 0x376 }; +static const int ide_irq[2] = { 14, 15 }; + +#define NE2000_NB_MAX 6 + +static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; +static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; + /* PC hardware initialisation */ void pc_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -268,7 +263,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; - int ret, linux_boot, initrd_size; + int ret, linux_boot, initrd_size, i, nb_nics1, fd; linux_boot = (kernel_filename != NULL); @@ -344,25 +339,38 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, } /* init basic PC hardware */ - register_ioport_write(0x80, 1, ioport80_write, 1); + register_ioport_write(0x80, 1, 1, ioport80_write, NULL); vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); rtc_init(0x70, 8); - cmos_init(ram_size, boot_device); - register_ioport_read(0x61, 1, speaker_ioport_read, 1); - register_ioport_write(0x61, 1, speaker_ioport_write, 1); + register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); + register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); pic_init(); - pit_init(); - serial_init(0x3f8, 4); - ne2000_init(0x300, 9); - ide_init(); + pit_init(0x40); + + fd = serial_open_device(); + serial_init(0x3f8, 4, fd); + + nb_nics1 = nb_nics; + if (nb_nics1 > NE2000_NB_MAX) + nb_nics1 = NE2000_NB_MAX; + for(i = 0; i < nb_nics1; i++) { + ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + } + + for(i = 0; i < 2; i++) { + ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + bs_table[2 * i], bs_table[2 * i + 1]); + } kbd_init(); AUD_init(); DMA_init(); SB16_init(); - fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device); + fdctrl_init(6, 2, 0, 0x3f0, fd_table); + + cmos_init(ram_size, boot_device); } diff --git a/hw/pckbd.c b/hw/pckbd.c index 8c0d3a72c..21524c8f4 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -189,7 +189,7 @@ static void kbd_update_irq(KBDState *s) static void kbd_queue(KBDState *s, int b, int aux) { - KBDQueue *q = &kbd_state.queues[aux]; + KBDQueue *q = &s->queues[aux]; #if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) if (aux) @@ -214,9 +214,9 @@ void kbd_put_keycode(int keycode) kbd_queue(s, keycode, 0); } -static uint32_t kbd_read_status(CPUState *env, uint32_t addr) +static uint32_t kbd_read_status(void *opaque, uint32_t addr) { - KBDState *s = &kbd_state; + KBDState *s = opaque; int val; val = s->status; #if defined(DEBUG_KBD) @@ -225,9 +225,9 @@ static uint32_t kbd_read_status(CPUState *env, uint32_t addr) return val; } -static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) +static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) { - KBDState *s = &kbd_state; + KBDState *s = opaque; #ifdef DEBUG_KBD printf("kbd: write cmd=0x%02x\n", val); @@ -285,10 +285,10 @@ static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) break; #ifdef TARGET_I386 case KBD_CCMD_ENABLE_A20: - cpu_x86_set_a20(env, 1); + cpu_x86_set_a20(cpu_single_env, 1); break; case KBD_CCMD_DISABLE_A20: - cpu_x86_set_a20(env, 0); + cpu_x86_set_a20(cpu_single_env, 0); break; #endif case KBD_CCMD_RESET: @@ -304,9 +304,9 @@ static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) } } -static uint32_t kbd_read_data(CPUState *env, uint32_t addr) +static uint32_t kbd_read_data(void *opaque, uint32_t addr) { - KBDState *s = &kbd_state; + KBDState *s = opaque; KBDQueue *q; int val, index; @@ -605,9 +605,9 @@ static void kbd_write_mouse(KBDState *s, int val) } } -void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val) +void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) { - KBDState *s = &kbd_state; + KBDState *s = opaque; #ifdef DEBUG_KBD printf("kbd: write data=0x%02x\n", val); @@ -629,7 +629,7 @@ void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val) break; case KBD_CCMD_WRITE_OUTPORT: #ifdef TARGET_I386 - cpu_x86_set_a20(env, (val >> 1) & 1); + cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1); #endif if (!(val & 1)) { reset_requested = 1; @@ -664,9 +664,11 @@ void kbd_reset(KBDState *s) void kbd_init(void) { - kbd_reset(&kbd_state); - register_ioport_read(0x60, 1, kbd_read_data, 1); - register_ioport_write(0x60, 1, kbd_write_data, 1); - register_ioport_read(0x64, 1, kbd_read_status, 1); - register_ioport_write(0x64, 1, kbd_write_command, 1); + KBDState *s = &kbd_state; + + kbd_reset(s); + register_ioport_read(0x60, 1, 1, kbd_read_data, s); + register_ioport_write(0x60, 1, 1, kbd_write_data, s); + register_ioport_read(0x64, 1, 1, kbd_read_status, s); + register_ioport_write(0x64, 1, 1, kbd_write_command, s); } diff --git a/hw/serial.c b/hw/serial.c index e1225ec40..60c311e55 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -90,7 +90,7 @@ #define UART_LSR_OE 0x02 /* Overrun error indicator */ #define UART_LSR_DR 0x01 /* Receiver data ready */ -typedef struct SerialState { +struct SerialState { uint8_t divider; uint8_t rbr; /* receive register */ uint8_t ier; @@ -104,14 +104,11 @@ typedef struct SerialState { it can be reset while reading iir */ int thr_ipending; int irq; -} SerialState; + int out_fd; +}; -SerialState serial_ports[1]; - -void serial_update_irq(void) +static void serial_update_irq(SerialState *s) { - SerialState *s = &serial_ports[0]; - if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { s->iir = UART_IIR_RDI; } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { @@ -126,9 +123,9 @@ void serial_update_irq(void) } } -void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) +static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - SerialState *s = &serial_ports[0]; + SerialState *s = opaque; unsigned char ch; int ret; @@ -144,16 +141,16 @@ void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } else { s->thr_ipending = 0; s->lsr &= ~UART_LSR_THRE; - serial_update_irq(); + serial_update_irq(s); ch = val; do { - ret = write(1, &ch, 1); + ret = write(s->out_fd, &ch, 1); } while (ret != 1); s->thr_ipending = 1; s->lsr |= UART_LSR_THRE; s->lsr |= UART_LSR_TEMT; - serial_update_irq(); + serial_update_irq(s); } break; case 1: @@ -161,7 +158,7 @@ void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) s->divider = (s->divider & 0x00ff) | (val << 8); } else { s->ier = val; - serial_update_irq(); + serial_update_irq(s); } break; case 2: @@ -183,9 +180,9 @@ void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) } } -uint32_t serial_ioport_read(CPUState *env, uint32_t addr) +static uint32_t serial_ioport_read(void *opaque, uint32_t addr) { - SerialState *s = &serial_ports[0]; + SerialState *s = opaque; uint32_t ret; addr &= 7; @@ -197,7 +194,7 @@ uint32_t serial_ioport_read(CPUState *env, uint32_t addr) } else { ret = s->rbr; s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); - serial_update_irq(); + serial_update_irq(s); } break; case 1: @@ -212,7 +209,7 @@ uint32_t serial_ioport_read(CPUState *env, uint32_t addr) /* reset THR pending bit */ if ((ret & 0x7) == UART_IIR_THRI) s->thr_ipending = 0; - serial_update_irq(); + serial_update_irq(s); break; case 3: ret = s->lcr; @@ -244,38 +241,58 @@ uint32_t serial_ioport_read(CPUState *env, uint32_t addr) return ret; } -int serial_can_receive(void) +int serial_can_receive(SerialState *s) { - SerialState *s = &serial_ports[0]; return !(s->lsr & UART_LSR_DR); } -void serial_receive_byte(int ch) +void serial_receive_byte(SerialState *s, int ch) { - SerialState *s = &serial_ports[0]; - s->rbr = ch; s->lsr |= UART_LSR_DR; - serial_update_irq(); + serial_update_irq(s); } -void serial_receive_break(void) +void serial_receive_break(SerialState *s) { - SerialState *s = &serial_ports[0]; - s->rbr = 0; s->lsr |= UART_LSR_BI | UART_LSR_DR; - serial_update_irq(); + serial_update_irq(s); } -void serial_init(int base, int irq) +static int serial_can_receive1(void *opaque) { - SerialState *s = &serial_ports[0]; + SerialState *s = opaque; + return serial_can_receive(s); +} + +static void serial_receive1(void *opaque, const uint8_t *buf, int size) +{ + SerialState *s = opaque; + serial_receive_byte(s, buf[0]); +} +/* If fd is zero, it means that the serial device uses the console */ +SerialState *serial_init(int base, int irq, int fd) +{ + SerialState *s; + + s = qemu_mallocz(sizeof(SerialState)); + if (!s) + return NULL; s->irq = irq; s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; - - register_ioport_write(base, 8, serial_ioport_write, 1); - register_ioport_read(base, 8, serial_ioport_read, 1); + + register_ioport_write(base, 8, 1, serial_ioport_write, s); + register_ioport_read(base, 8, 1, serial_ioport_read, s); + + if (fd != 0) { + add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); + s->out_fd = fd; + } else { + serial_console = s; + s->out_fd = 1; + } + return s; } -- cgit v1.2.3 From 0fb48229a73b39be02a78350547fa524c0d72c57 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:48:47 +0000 Subject: added qemu_mallocz() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@665 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.h | 1 + 1 file changed, 1 insertion(+) diff --git a/osdep.h b/osdep.h index 16148da1b..1c14de4c5 100644 --- a/osdep.h +++ b/osdep.h @@ -8,6 +8,7 @@ void qemu_vprintf(const char *fmt, va_list ap); void qemu_printf(const char *fmt, ...); void *qemu_malloc(size_t size); +void *qemu_mallocz(size_t size); void qemu_free(void *ptr); void *get_mmap_addr(unsigned long size); -- cgit v1.2.3 From 94fe4f9fa316d3710ce4bb2c5cdd226fa81e8eae Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Mar 2004 21:49:05 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@666 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index f714131b2..e7b2aca4d 100644 --- a/Changelog +++ b/Changelog @@ -6,10 +6,18 @@ version 0.5.3: - CPU interrupt fixes - fixed various TLB invalidation cases (NT install) - fixed cr0.WP semantics (XP install) - - direct chaining support for SPARC (3x faster) + - 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 version 0.5.2: -- cgit v1.2.3 From 4e463d8d508d93756b9684ae030b5c412f7ea891 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 16 Mar 2004 00:02:58 +0000 Subject: tun-fd option fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@667 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vl.c b/vl.c index 8472f0a23..f358dbed8 100644 --- a/vl.c +++ b/vl.c @@ -980,6 +980,8 @@ int main(int argc, char **argv) } else if (*p != '\0') { fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_nics); exit(1); + } else { + break; } } } -- cgit v1.2.3 From 59a983b921e8318ae8da357aacd496c3ab5bbc5b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Mar 2004 23:17:16 +0000 Subject: device independent VGA screen dump git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@668 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ monitor.c | 11 ++++++ vl.h | 1 + 3 files changed, 116 insertions(+), 23 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 452de61d0..5d2acc85f 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -737,7 +737,7 @@ static uint32_t vga_mem_readl(uint32_t addr) } /* called for accesses between 0xa0000 and 0xc0000 */ -void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) +static void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) { VGAState *s = &vga_state; int memory_map_mode, plane, write_mode, b, func_select; @@ -865,13 +865,13 @@ void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) } } -void vga_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr) +static void vga_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr) { vga_mem_writeb(addr, val & 0xff, vaddr); vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr); } -void vga_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr) +static void vga_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr) { vga_mem_writeb(addr, val & 0xff, vaddr); vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr); @@ -1523,7 +1523,23 @@ void vga_update_display(void) if (s->ds->depth == 0) { /* nothing to do */ - } else { + } else { + switch(s->ds->depth) { + case 8: + s->rgb_to_pixel = rgb_to_pixel8_dup; + break; + case 15: + s->rgb_to_pixel = rgb_to_pixel15_dup; + break; + default: + case 16: + s->rgb_to_pixel = rgb_to_pixel16_dup; + break; + case 32: + s->rgb_to_pixel = rgb_to_pixel32_dup; + break; + } + full_update = 0; graphic_mode = s->gr[6] & 1; if (graphic_mode != s->graphic_mode) { @@ -1537,7 +1553,7 @@ void vga_update_display(void) } } -void vga_reset(VGAState *s) +static void vga_reset(VGAState *s) { memset(s, 0, sizeof(VGAState)); #ifdef CONFIG_S3VGA @@ -1550,13 +1566,13 @@ void vga_reset(VGAState *s) s->graphic_mode = -1; /* force full update */ } -CPUReadMemoryFunc *vga_mem_read[3] = { +static CPUReadMemoryFunc *vga_mem_read[3] = { vga_mem_readb, vga_mem_readw, vga_mem_readl, }; -CPUWriteMemoryFunc *vga_mem_write[3] = { +static CPUWriteMemoryFunc *vga_mem_write[3] = { vga_mem_writeb, vga_mem_writew, vga_mem_writel, @@ -1593,22 +1609,6 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, vga_reset(s); - switch(ds->depth) { - case 8: - s->rgb_to_pixel = rgb_to_pixel8_dup; - break; - case 15: - s->rgb_to_pixel = rgb_to_pixel15_dup; - break; - default: - case 16: - s->rgb_to_pixel = rgb_to_pixel16_dup; - break; - case 32: - s->rgb_to_pixel = rgb_to_pixel32_dup; - break; - } - s->vram_ptr = vga_ram_base; s->vram_offset = vga_ram_offset; s->vram_size = vga_ram_size; @@ -1652,3 +1652,84 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, #endif return 0; } + +/********************************************************/ +/* vga screen dump */ + +static int vga_save_w, vga_save_h; + +static void vga_save_dpy_update(DisplayState *s, + int x, int y, int w, int h) +{ +} + +static void vga_save_dpy_resize(DisplayState *s, int w, int h) +{ + s->linesize = w * 4; + s->data = qemu_malloc(h * s->linesize); + vga_save_w = w; + vga_save_h = h; +} + +static void vga_save_dpy_refresh(DisplayState *s) +{ +} + +static int ppm_save(const char *filename, uint8_t *data, + int w, int h, int linesize) +{ + FILE *f; + uint8_t *d, *d1; + unsigned int v; + int y, x; + + f = fopen(filename, "wb"); + if (!f) + return -1; + fprintf(f, "P6\n%d %d\n%d\n", + w, h, 255); + d1 = data; + for(y = 0; y < h; y++) { + d = d1; + for(x = 0; x < w; x++) { + v = *(uint32_t *)d; + fputc((v >> 16) & 0xff, f); + fputc((v >> 8) & 0xff, f); + fputc((v) & 0xff, f); + d += 4; + } + d1 += linesize; + } + fclose(f); + return 0; +} + +/* save the vga display in a PPM image even if no display is + available */ +void vga_screen_dump(const char *filename) +{ + VGAState *s = &vga_state; + DisplayState *saved_ds, ds1, *ds = &ds1; + + /* XXX: this is a little hackish */ + s->last_width = -1; + s->last_height = -1; + saved_ds = s->ds; + + memset(ds, 0, sizeof(DisplayState)); + ds->dpy_update = vga_save_dpy_update; + ds->dpy_resize = vga_save_dpy_resize; + ds->dpy_refresh = vga_save_dpy_refresh; + ds->depth = 32; + + s->ds = ds; + s->graphic_mode = -1; + vga_update_display(); + + if (ds->data) { + ppm_save(filename, ds->data, vga_save_w, vga_save_h, + s->ds->linesize); + qemu_free(ds->data); + } + s->ds = saved_ds; +} diff --git a/monitor.c b/monitor.c index 633b89892..195a0b007 100644 --- a/monitor.c +++ b/monitor.c @@ -245,6 +245,15 @@ static void do_change(int argc, const char **argv) bdrv_open(bs, argv[2], 0); } +static void do_screen_dump(int argc, const char **argv) +{ + if (argc != 2) { + help_cmd(argv[0]); + return; + } + vga_screen_dump(argv[1]); +} + static term_cmd_t term_cmds[] = { { "help|?", do_help, "[cmd]", "show the help" }, @@ -258,6 +267,8 @@ static term_cmd_t term_cmds[] = { "[-f] device", "eject a removable media (use -f to force it)" }, { "change", do_change, "device filename", "change a removable media" }, + { "screendump", do_screen_dump, + "filename", "save screen into PPM image 'filename'" }, { NULL, NULL, }, }; diff --git a/vl.h b/vl.h index 50e160987..11d7aba41 100644 --- a/vl.h +++ b/vl.h @@ -136,6 +136,7 @@ static inline void dpy_resize(DisplayState *s, int w, int h) int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); void vga_update_display(void); +void vga_screen_dump(const char *filename); /* sdl.c */ void sdl_display_init(DisplayState *ds); -- cgit v1.2.3 From 5069146392ab358b106ed6a7a05440c69924448d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Mar 2004 23:44:10 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@669 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TODO b/TODO index 088d7bc2d..b44483980 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,10 @@ short term: ---------- -- XP install bug fix +- physical memory cache (reduce qemu-fast address space size to about 32 MB) +- better code fetch +- XP security bug - handle Self Modifying Code even if modifying current TB (BE OS 5 install) -- L4 Pistachio kernel boot fix +- cycle counter for all archs - TLB code protection support for PPC - add sysenter/sysexit and fxsr for L4 pistachio 686 - basic VGA optimizations @@ -10,7 +12,6 @@ short term: - see undefined flags for BTx insn - user/kernel PUSHL/POPL in helper.c - keyboard output buffer filling timing emulation -- verify tb_flush() with a20 and TLBs - return UD exception if LOCK prefix incorrectly used - cmos clock update and timers - test ldt limit < 7 ? @@ -26,8 +27,7 @@ lower priority: - suppress shift_mem ops - fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) - sysenter/sysexit emulation -- optimize FPU operations (evaluate x87 stack pointer statically) and - fix cr0.TS emulation +- optimize FPU operations (evaluate x87 stack pointer statically) - add IPC syscalls - use -msoft-float on ARM - use kernel traps for unaligned accesses on ARM ? -- cgit v1.2.3 From bc51c5c989c12b3936b78c5772a3308629a7484c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Mar 2004 23:46:04 +0000 Subject: initial x86-64 host support (Gwenole Beauchesne) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@670 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 11 + amd64.ld | 342 ++++ bswap.h | 2 +- configure | 6 + cpu-exec.c | 15 + dis-asm.h | 5 + disas.c | 5 +- dyngen-exec.h | 11 + dyngen.c | 43 + dyngen.h | 6 + exec-all.h | 14 + i386-dis.c | 4467 +++++++++++++++++++++++++++++++++++--------------- linux-user/mmap.c | 2 +- linux-user/syscall.c | 2 +- target-i386/cpu.h | 2 +- target-i386/helper.c | 4 +- 17 files changed, 3619 insertions(+), 1319 deletions(-) create mode 100644 amd64.ld diff --git a/Changelog b/Changelog index e7b2aca4d..321f5fd65 100644 --- a/Changelog +++ b/Changelog @@ -18,6 +18,7 @@ version 0.5.3: - generic removable device support - support of CD-ROM change - multiple network interface support + - initial x86-64 host support (Gwenole Beauchesne) version 0.5.2: diff --git a/Makefile.target b/Makefile.target index 769237ac9..f869aad5c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -80,6 +80,11 @@ LDFLAGS+=-Wl,-shared endif endif +ifeq ($(ARCH),amd64) +OP_CFLAGS=$(CFLAGS) -falign-functions=0 +LDFLAGS+=-Wl,-T,$(SRC_PATH)/amd64.ld +endif + ifeq ($(ARCH),ppc) OP_CFLAGS=$(CFLAGS) LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld @@ -174,6 +179,12 @@ 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 amd64, $(TARGET_ARCH) $(ARCH)),amd64) +USE_I386_DIS=y +endif +ifdef USE_I386_DIS LIBOBJS+=i386-dis.o endif ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha) diff --git a/amd64.ld b/amd64.ld new file mode 100644 index 000000000..c52a62559 --- /dev/null +++ b/amd64.ld @@ -0,0 +1,342 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); +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.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } + /* 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 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); +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.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } + /* 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 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/bswap.h b/bswap.h index 0632a9d9a..c52933e49 100644 --- a/bswap.h +++ b/bswap.h @@ -43,7 +43,7 @@ #endif /* !HAVE_BYTESWAP_H */ -#if defined(__alpha__) || defined (__ia64__) +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define HOST_LONG_BITS 64 #else #define HOST_LONG_BITS 32 diff --git a/configure b/configure index be8c8bcbc..f3f68b617 100755 --- a/configure +++ b/configure @@ -59,6 +59,9 @@ case "$cpu" in m68k) cpu="m68k" ;; + x86_64|amd64) + cpu="amd64" + ;; *) cpu="unknown" ;; @@ -253,6 +256,9 @@ echo "LDFLAGS=$LDFLAGS" >> $config_mak if test "$cpu" = "i386" ; then echo "ARCH=i386" >> $config_mak echo "#define HOST_I386 1" >> $config_h +elif test "$cpu" = "amd64" ; then + echo "ARCH=amd64" >> $config_mak + echo "#define HOST_AMD64 1" >> $config_h elif test "$cpu" = "armv4l" ; then echo "ARCH=arm" >> $config_mak echo "#define HOST_ARM 1" >> $config_h diff --git a/cpu-exec.c b/cpu-exec.c index c6f52f278..b6f3de1bb 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -785,6 +785,21 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, &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) int cpu_signal_handler(int host_signum, struct siginfo *info, diff --git a/dis-asm.h b/dis-asm.h index 3e6982f23..ebfb2993a 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -16,7 +16,9 @@ #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) enum bfd_flavour { bfd_target_unknown_flavour, @@ -105,6 +107,9 @@ enum bfd_architecture 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 */ diff --git a/disas.c b/disas.c index f274ac52d..f048348f5 100644 --- a/disas.c +++ b/disas.c @@ -140,9 +140,12 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) #else disasm_info.endian = BFD_ENDIAN_LITTLE; #endif -#ifdef __i386__ +#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__) diff --git a/dyngen-exec.h b/dyngen-exec.h index da23e0e6a..5e9bab6f9 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -68,6 +68,14 @@ extern int printf(const char *, ...); #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" @@ -188,6 +196,9 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ #define EXIT_TB() asm volatile ("ret") #endif +#ifdef __x86_64__ +#define EXIT_TB() asm volatile ("ret") +#endif #ifdef __powerpc__ #define EXIT_TB() asm volatile ("blr") #endif diff --git a/dyngen.c b/dyngen.c index 89e98245b..7c1c0e8ae 100644 --- a/dyngen.c +++ b/dyngen.c @@ -37,6 +37,13 @@ #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) #undef ELF_USES_RELOCA +#elif defined(HOST_AMD64) + +#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 @@ -446,6 +453,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, start_offset = offset; switch(ELF_ARCH) { case EM_386: + case EM_X86_64: { int len; len = p_end - p_start; @@ -766,6 +774,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#elif defined(HOST_AMD64) + { + char name[256]; + int type; + int addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && + rel->r_offset < start_offset + copy_size) { + sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + if (strstart(sym_name, "__op_param", &p)) { + snprintf(name, sizeof(name), "param%s", p); + } else { + snprintf(name, sizeof(name), "(long)(&%s)", sym_name); + } + type = ELF32_R_TYPE(rel->r_info); + addend = rel->r_addend; + switch(type) { + case R_X86_64_32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case R_X86_64_32S: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", + rel->r_offset - start_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", + rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + break; + default: + error("unsupported AMD64 relocation (%d)", type); + } + } + } + } #elif defined(HOST_PPC) { char name[256]; diff --git a/dyngen.h b/dyngen.h index f7f1d3aab..a00ded775 100644 --- a/dyngen.h +++ b/dyngen.h @@ -27,6 +27,12 @@ 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) { diff --git a/exec-all.h b/exec-all.h index 3c79eca91..9ecf2dca7 100644 --- a/exec-all.h +++ b/exec-all.h @@ -400,6 +400,20 @@ static inline int testandset (int *p) } #endif +#ifdef __x86_64__ +static inline int testandset (int *p) +{ + char ret; + int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (1), "m" (*p), "a" (0) + : "memory"); + return ret; +} +#endif + #ifdef __s390__ static inline int testandset (int *p) { diff --git a/i386-dis.c b/i386-dis.c index f9e907298..372f0a441 100644 --- a/i386-dis.c +++ b/i386-dis.c @@ -1,5 +1,6 @@ /* Print i386 instructions for GDB, the GNU debugger. - Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 97, 1998 + Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2001 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) * July 1988 * modified by John Hassey (hassey@dg-rtp.dg.com) + * x86-64 support added by Jan Hubicka (jh@suse.cz) */ /* @@ -29,33 +31,132 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 * Programmers Manual. Usually, there is a capital letter, followed * by a small letter. The capital letter tell the addressing mode, - * and the small letter tells about the operand size. Refer to + * and the small letter tells about the operand size. Refer to * the Intel manual for details. */ #include -#include - #include "dis-asm.h" #define MAXLEN 20 +#include + +#ifndef UNIXWARE_COMPAT +/* Set non-zero for broken, compatible instructions. Set to zero for + non-broken opcodes. */ +#define UNIXWARE_COMPAT 1 +#endif + static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); +static void ckprefix PARAMS ((void)); +static const char *prefix_name PARAMS ((int, int)); +static int print_insn PARAMS ((bfd_vma, disassemble_info *)); +static void dofloat PARAMS ((int)); +static void OP_ST PARAMS ((int, int)); +static void OP_STi PARAMS ((int, int)); +static int putop PARAMS ((const char *, int)); +static void oappend PARAMS ((const char *)); +static void append_seg PARAMS ((void)); +static void OP_indirE PARAMS ((int, int)); +static void print_operand_value PARAMS ((char *, int, bfd_vma)); +static void OP_E PARAMS ((int, int)); +static void OP_G PARAMS ((int, int)); +static bfd_vma get64 PARAMS ((void)); +static bfd_signed_vma get32 PARAMS ((void)); +static bfd_signed_vma get32s PARAMS ((void)); +static int get16 PARAMS ((void)); +static void set_op PARAMS ((bfd_vma, int)); +static void OP_REG PARAMS ((int, int)); +static void OP_IMREG PARAMS ((int, int)); +static void OP_I PARAMS ((int, int)); +static void OP_I64 PARAMS ((int, int)); +static void OP_sI PARAMS ((int, int)); +static void OP_J PARAMS ((int, int)); +static void OP_SEG PARAMS ((int, int)); +static void OP_DIR PARAMS ((int, int)); +static void OP_OFF PARAMS ((int, int)); +static void OP_OFF64 PARAMS ((int, int)); +static void ptr_reg PARAMS ((int, int)); +static void OP_ESreg PARAMS ((int, int)); +static void OP_DSreg PARAMS ((int, int)); +static void OP_C PARAMS ((int, int)); +static void OP_D PARAMS ((int, int)); +static void OP_T PARAMS ((int, int)); +static void OP_Rd PARAMS ((int, int)); +static void OP_MMX PARAMS ((int, int)); +static void OP_XMM PARAMS ((int, int)); +static void OP_EM PARAMS ((int, int)); +static void OP_EX PARAMS ((int, int)); +static void OP_MS PARAMS ((int, int)); +static void OP_XS PARAMS ((int, int)); +static void OP_3DNowSuffix PARAMS ((int, int)); +static void OP_SIMD_Suffix PARAMS ((int, int)); +static void SIMD_Fixup PARAMS ((int, int)); +static void BadOp PARAMS ((void)); -struct dis_private -{ +struct dis_private { /* Points to first byte not fetched. */ bfd_byte *max_fetched; bfd_byte the_buffer[MAXLEN]; bfd_vma insn_start; + int orig_sizeflag; jmp_buf bailout; }; +/* The opcode for the fwait instruction, which we treat as a prefix + when we can. */ +#define FWAIT_OPCODE (0x9b) + +/* Set to 1 for 64bit mode disassembly. */ +static int mode_64bit; + +/* Flags for the prefixes for the current instruction. See below. */ +static int prefixes; + +/* REX prefix the current instruction. See below. */ +static int rex; +/* Bits of REX we've already used. */ +static int rex_used; +#define REX_MODE64 8 +#define REX_EXTX 4 +#define REX_EXTY 2 +#define REX_EXTZ 1 +/* Mark parts used in the REX prefix. When we are testing for + empty prefix (for 8bit register REX extension), just mask it + out. Otherwise test for REX bit is excuse for existence of REX + only in case value is nonzero. */ +#define USED_REX(value) \ + { \ + if (value) \ + rex_used |= (rex & value) ? (value) | 0x40 : 0; \ + else \ + rex_used |= 0x40; \ + } + +/* Flags for prefixes which we somehow handled when printing the + current instruction. */ +static int used_prefixes; + +/* Flags stored in PREFIXES. */ +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADDR 0x400 +#define PREFIX_FWAIT 0x800 + /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) to ADDR (exclusive) are valid. Returns 1 for success, longjmps on error. */ #define FETCH_DATA(info, addr) \ - ((addr) <= ((struct dis_private *)(info->private_data))->max_fetched \ + ((addr) <= ((struct dis_private *) (info->private_data))->max_fetched \ ? 1 : fetch_data ((info), (addr))) static int @@ -64,7 +165,7 @@ fetch_data (info, addr) bfd_byte *addr; { int status; - struct dis_private *priv = (struct dis_private *)info->private_data; + struct dis_private *priv = (struct dis_private *) info->private_data; bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); status = (*info->read_memory_func) (start, @@ -73,7 +174,12 @@ fetch_data (info, addr) info); if (status != 0) { - (*info->memory_error_func) (status, start, info); + /* If we did manage to read at least one byte, then + print_insn_i386 will do something sensible. Otherwise, print + an error. We do that here because this is where we know + STATUS. */ + if (priv->max_fetched == priv->the_buffer) + (*info->memory_error_func) (status, start, info); longjmp (priv->bailout, 1); } else @@ -81,61 +187,95 @@ fetch_data (info, addr) return 1; } +#define XX NULL, 0 + #define Eb OP_E, b_mode -#define indirEb OP_indirE, b_mode -#define Gb OP_G, b_mode #define Ev OP_E, v_mode +#define Ed OP_E, d_mode +#define indirEb OP_indirE, b_mode #define indirEv OP_indirE, v_mode #define Ew OP_E, w_mode #define Ma OP_E, v_mode -#define M OP_E, 0 -#define Mp OP_E, 0 /* ? */ +#define M OP_E, 0 /* lea, lgdt, etc. */ +#define Mp OP_E, 0 /* 32 or 48 bit memory operand for LDS, LES etc */ +#define Gb OP_G, b_mode #define Gv OP_G, v_mode +#define Gd OP_G, d_mode #define Gw OP_G, w_mode -#define Rw OP_rm, w_mode -#define Rd OP_rm, d_mode +#define Rd OP_Rd, d_mode +#define Rm OP_Rd, m_mode #define Ib OP_I, b_mode #define sIb OP_sI, b_mode /* sign extened byte */ #define Iv OP_I, v_mode +#define Iq OP_I, q_mode +#define Iv64 OP_I64, v_mode #define Iw OP_I, w_mode #define Jb OP_J, b_mode #define Jv OP_J, v_mode -#if 0 -#define ONE OP_ONE, 0 -#endif -#define Cd OP_C, d_mode -#define Dd OP_D, d_mode +#define Cm OP_C, m_mode +#define Dm OP_D, m_mode #define Td OP_T, d_mode -#define eAX OP_REG, eAX_reg -#define eBX OP_REG, eBX_reg -#define eCX OP_REG, eCX_reg -#define eDX OP_REG, eDX_reg -#define eSP OP_REG, eSP_reg -#define eBP OP_REG, eBP_reg -#define eSI OP_REG, eSI_reg -#define eDI OP_REG, eDI_reg -#define AL OP_REG, al_reg -#define CL OP_REG, cl_reg -#define DL OP_REG, dl_reg -#define BL OP_REG, bl_reg -#define AH OP_REG, ah_reg -#define CH OP_REG, ch_reg -#define DH OP_REG, dh_reg -#define BH OP_REG, bh_reg -#define AX OP_REG, ax_reg -#define DX OP_REG, dx_reg -#define indirDX OP_REG, indir_dx_reg +#define RMeAX OP_REG, eAX_reg +#define RMeBX OP_REG, eBX_reg +#define RMeCX OP_REG, eCX_reg +#define RMeDX OP_REG, eDX_reg +#define RMeSP OP_REG, eSP_reg +#define RMeBP OP_REG, eBP_reg +#define RMeSI OP_REG, eSI_reg +#define RMeDI OP_REG, eDI_reg +#define RMrAX OP_REG, rAX_reg +#define RMrBX OP_REG, rBX_reg +#define RMrCX OP_REG, rCX_reg +#define RMrDX OP_REG, rDX_reg +#define RMrSP OP_REG, rSP_reg +#define RMrBP OP_REG, rBP_reg +#define RMrSI OP_REG, rSI_reg +#define RMrDI OP_REG, rDI_reg +#define RMAL OP_REG, al_reg +#define RMAL OP_REG, al_reg +#define RMCL OP_REG, cl_reg +#define RMDL OP_REG, dl_reg +#define RMBL OP_REG, bl_reg +#define RMAH OP_REG, ah_reg +#define RMCH OP_REG, ch_reg +#define RMDH OP_REG, dh_reg +#define RMBH OP_REG, bh_reg +#define RMAX OP_REG, ax_reg +#define RMDX OP_REG, dx_reg + +#define eAX OP_IMREG, eAX_reg +#define eBX OP_IMREG, eBX_reg +#define eCX OP_IMREG, eCX_reg +#define eDX OP_IMREG, eDX_reg +#define eSP OP_IMREG, eSP_reg +#define eBP OP_IMREG, eBP_reg +#define eSI OP_IMREG, eSI_reg +#define eDI OP_IMREG, eDI_reg +#define AL OP_IMREG, al_reg +#define AL OP_IMREG, al_reg +#define CL OP_IMREG, cl_reg +#define DL OP_IMREG, dl_reg +#define BL OP_IMREG, bl_reg +#define AH OP_IMREG, ah_reg +#define CH OP_IMREG, ch_reg +#define DH OP_IMREG, dh_reg +#define BH OP_IMREG, bh_reg +#define AX OP_IMREG, ax_reg +#define DX OP_IMREG, dx_reg +#define indirDX OP_IMREG, indir_dx_reg #define Sw OP_SEG, w_mode -#define Ap OP_DIR, lptr -#define Av OP_DIR, v_mode +#define Ap OP_DIR, 0 #define Ob OP_OFF, b_mode +#define Ob64 OP_OFF64, b_mode #define Ov OP_OFF, v_mode -#define Xb OP_DSSI, b_mode -#define Xv OP_DSSI, v_mode -#define Yb OP_ESDI, b_mode -#define Yv OP_ESDI, v_mode +#define Ov64 OP_OFF64, v_mode +#define Xb OP_DSreg, eSI_reg +#define Xv OP_DSreg, eSI_reg +#define Yb OP_ESreg, eDI_reg +#define Yv OP_ESreg, eDI_reg +#define DSBX OP_DSreg, eBX_reg #define es OP_REG, es_reg #define ss OP_REG, ss_reg @@ -145,48 +285,32 @@ fetch_data (info, addr) #define gs OP_REG, gs_reg #define MX OP_MMX, 0 +#define XM OP_XMM, 0 #define EM OP_EM, v_mode -#define MS OP_MS, b_mode - -typedef int (*op_rtn) PARAMS ((int bytemode, int aflag, int dflag)); - -static int OP_E PARAMS ((int, int, int)); -static int OP_G PARAMS ((int, int, int)); -static int OP_I PARAMS ((int, int, int)); -static int OP_indirE PARAMS ((int, int, int)); -static int OP_sI PARAMS ((int, int, int)); -static int OP_REG PARAMS ((int, int, int)); -static int OP_J PARAMS ((int, int, int)); -static int OP_DIR PARAMS ((int, int, int)); -static int OP_OFF PARAMS ((int, int, int)); -static int OP_ESDI PARAMS ((int, int, int)); -static int OP_DSSI PARAMS ((int, int, int)); -static int OP_SEG PARAMS ((int, int, int)); -static int OP_C PARAMS ((int, int, int)); -static int OP_D PARAMS ((int, int, int)); -static int OP_T PARAMS ((int, int, int)); -static int OP_rm PARAMS ((int, int, int)); -static int OP_ST PARAMS ((int, int, int)); -static int OP_STi PARAMS ((int, int, int)); -#if 0 -static int OP_ONE PARAMS ((int, int, int)); -#endif -static int OP_MMX PARAMS ((int, int, int)); -static int OP_EM PARAMS ((int, int, int)); -static int OP_MS PARAMS ((int, int, int)); - -static void append_prefix PARAMS ((void)); -static void set_op PARAMS ((int op)); -static void putop PARAMS ((char *template, int aflag, int dflag)); -static void dofloat PARAMS ((int aflag, int dflag)); -static int get16 PARAMS ((void)); -static int get32 PARAMS ((void)); -static void ckprefix PARAMS ((void)); +#define EX OP_EX, v_mode +#define MS OP_MS, v_mode +#define XS OP_XS, v_mode +#define None OP_E, 0 +#define OPSUF OP_3DNowSuffix, 0 +#define OPSIMD OP_SIMD_Suffix, 0 + +#define cond_jump_flag NULL, cond_jump_mode +#define loop_jcxz_flag NULL, loop_jcxz_mode + +/* bits in sizeflag */ +#define SUFFIX_ALWAYS 4 +#define AFLAG 2 +#define DFLAG 1 -#define b_mode 1 -#define v_mode 2 -#define w_mode 3 -#define d_mode 4 +#define b_mode 1 /* byte operand */ +#define v_mode 2 /* operand size depends on prefixes */ +#define w_mode 3 /* word operand */ +#define d_mode 4 /* double word operand */ +#define q_mode 5 /* quad word operand */ +#define x_mode 6 +#define m_mode 7 /* d_mode in 32bit, q_mode in 64bit mode. */ +#define cond_jump_mode 8 +#define loop_jcxz_mode 9 #define es_reg 100 #define cs_reg 101 @@ -194,16 +318,15 @@ static void ckprefix PARAMS ((void)); #define ds_reg 103 #define fs_reg 104 #define gs_reg 105 -#define eAX_reg 107 -#define eCX_reg 108 -#define eDX_reg 109 -#define eBX_reg 110 -#define eSP_reg 111 -#define eBP_reg 112 -#define eSI_reg 113 -#define eDI_reg 114 -#define lptr 115 +#define eAX_reg 108 +#define eCX_reg 109 +#define eDX_reg 110 +#define eBX_reg 111 +#define eSP_reg 112 +#define eBP_reg 113 +#define eSI_reg 114 +#define eDI_reg 115 #define al_reg 116 #define cl_reg 117 @@ -223,34 +346,82 @@ static void ckprefix PARAMS ((void)); #define si_reg 130 #define di_reg 131 +#define rAX_reg 132 +#define rCX_reg 133 +#define rDX_reg 134 +#define rBX_reg 135 +#define rSP_reg 136 +#define rBP_reg 137 +#define rSI_reg 138 +#define rDI_reg 139 + #define indir_dx_reg 150 -#define GRP1b NULL, NULL, 0 -#define GRP1S NULL, NULL, 1 -#define GRP1Ss NULL, NULL, 2 -#define GRP2b NULL, NULL, 3 -#define GRP2S NULL, NULL, 4 -#define GRP2b_one NULL, NULL, 5 -#define GRP2S_one NULL, NULL, 6 -#define GRP2b_cl NULL, NULL, 7 -#define GRP2S_cl NULL, NULL, 8 -#define GRP3b NULL, NULL, 9 -#define GRP3S NULL, NULL, 10 -#define GRP4 NULL, NULL, 11 -#define GRP5 NULL, NULL, 12 -#define GRP6 NULL, NULL, 13 -#define GRP7 NULL, NULL, 14 -#define GRP8 NULL, NULL, 15 -#define GRP9 NULL, NULL, 16 -#define GRP10 NULL, NULL, 17 -#define GRP11 NULL, NULL, 18 -#define GRP12 NULL, NULL, 19 - -#define FLOATCODE 50 -#define FLOAT NULL, NULL, FLOATCODE +#define FLOATCODE 1 +#define USE_GROUPS 2 +#define USE_PREFIX_USER_TABLE 3 +#define X86_64_SPECIAL 4 + +#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0 + +#define GRP1b NULL, NULL, USE_GROUPS, NULL, 0, NULL, 0 +#define GRP1S NULL, NULL, USE_GROUPS, NULL, 1, NULL, 0 +#define GRP1Ss NULL, NULL, USE_GROUPS, NULL, 2, NULL, 0 +#define GRP2b NULL, NULL, USE_GROUPS, NULL, 3, NULL, 0 +#define GRP2S NULL, NULL, USE_GROUPS, NULL, 4, NULL, 0 +#define GRP2b_one NULL, NULL, USE_GROUPS, NULL, 5, NULL, 0 +#define GRP2S_one NULL, NULL, USE_GROUPS, NULL, 6, NULL, 0 +#define GRP2b_cl NULL, NULL, USE_GROUPS, NULL, 7, NULL, 0 +#define GRP2S_cl NULL, NULL, USE_GROUPS, NULL, 8, NULL, 0 +#define GRP3b NULL, NULL, USE_GROUPS, NULL, 9, NULL, 0 +#define GRP3S NULL, NULL, USE_GROUPS, NULL, 10, NULL, 0 +#define GRP4 NULL, NULL, USE_GROUPS, NULL, 11, NULL, 0 +#define GRP5 NULL, NULL, USE_GROUPS, NULL, 12, NULL, 0 +#define GRP6 NULL, NULL, USE_GROUPS, NULL, 13, NULL, 0 +#define GRP7 NULL, NULL, USE_GROUPS, NULL, 14, NULL, 0 +#define GRP8 NULL, NULL, USE_GROUPS, NULL, 15, NULL, 0 +#define GRP9 NULL, NULL, USE_GROUPS, NULL, 16, NULL, 0 +#define GRP10 NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0 +#define GRP11 NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0 +#define GRP12 NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0 +#define GRP13 NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0 +#define GRP14 NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0 +#define GRPAMD NULL, NULL, USE_GROUPS, NULL, 22, NULL, 0 + +#define PREGRP0 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 0, NULL, 0 +#define PREGRP1 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 1, NULL, 0 +#define PREGRP2 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 2, NULL, 0 +#define PREGRP3 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 3, NULL, 0 +#define PREGRP4 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 4, NULL, 0 +#define PREGRP5 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 5, NULL, 0 +#define PREGRP6 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 6, NULL, 0 +#define PREGRP7 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 7, NULL, 0 +#define PREGRP8 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 8, NULL, 0 +#define PREGRP9 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 9, NULL, 0 +#define PREGRP10 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 10, NULL, 0 +#define PREGRP11 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 11, NULL, 0 +#define PREGRP12 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 12, NULL, 0 +#define PREGRP13 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 13, NULL, 0 +#define PREGRP14 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 14, NULL, 0 +#define PREGRP15 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 15, NULL, 0 +#define PREGRP16 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 16, NULL, 0 +#define PREGRP17 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 17, NULL, 0 +#define PREGRP18 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 18, NULL, 0 +#define PREGRP19 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 19, NULL, 0 +#define PREGRP20 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 20, NULL, 0 +#define PREGRP21 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 21, NULL, 0 +#define PREGRP22 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 22, NULL, 0 +#define PREGRP23 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 23, NULL, 0 +#define PREGRP24 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 24, NULL, 0 +#define PREGRP25 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 25, NULL, 0 +#define PREGRP26 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 26, NULL, 0 + +#define X86_64_0 NULL, NULL, X86_64_SPECIAL, NULL, 0, NULL, 0 + +typedef void (*op_rtn) PARAMS ((int bytemode, int sizeflag)); struct dis386 { - char *name; + const char *name; op_rtn op1; int bytemode1; op_rtn op2; @@ -259,250 +430,281 @@ struct dis386 { int bytemode3; }; -static struct dis386 dis386[] = { +/* Upper case letters in the instruction names here are macros. + 'A' => print 'b' if no register operands or suffix_always is true + 'B' => print 'b' if suffix_always is true + 'E' => print 'e' if 32-bit form of jcxz + 'F' => print 'w' or 'l' depending on address size prefix (loop insns) + 'H' => print ",pt" or ",pn" branch hint + 'L' => print 'l' if suffix_always is true + 'N' => print 'n' if instruction has no wait "prefix" + 'O' => print 'd', or 'o' + 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, + . or suffix_always is true. print 'q' if rex prefix is present. + 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always + . is true + 'R' => print 'w', 'l' or 'q' ("wd" or "dq" in intel mode) + 'S' => print 'w', 'l' or 'q' if suffix_always is true + 'T' => print 'q' in 64bit mode and behave as 'P' otherwise + 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise + 'X' => print 's', 'd' depending on data16 prefix (for XMM) + 'W' => print 'b' or 'w' ("w" or "de" in intel mode) + 'Y' => 'q' if instruction has an REX 64bit overwrite prefix + + Many of the above letters print nothing in Intel mode. See "putop" + for the details. + + Braces '{' and '}', and vertical bars '|', indicate alternative + mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel + modes. In cases where there are only two alternatives, the X86_64 + instruction is reserved, and "(bad)" is printed. +*/ + +static const struct dis386 dis386[] = { /* 00 */ - { "addb", Eb, Gb }, - { "addS", Ev, Gv }, - { "addb", Gb, Eb }, - { "addS", Gv, Ev }, - { "addb", AL, Ib }, - { "addS", eAX, Iv }, - { "pushS", es }, - { "popS", es }, + { "addB", Eb, Gb, XX }, + { "addS", Ev, Gv, XX }, + { "addB", Gb, Eb, XX }, + { "addS", Gv, Ev, XX }, + { "addB", AL, Ib, XX }, + { "addS", eAX, Iv, XX }, + { "push{T|}", es, XX, XX }, + { "pop{T|}", es, XX, XX }, /* 08 */ - { "orb", Eb, Gb }, - { "orS", Ev, Gv }, - { "orb", Gb, Eb }, - { "orS", Gv, Ev }, - { "orb", AL, Ib }, - { "orS", eAX, Iv }, - { "pushS", cs }, - { "(bad)" }, /* 0x0f extended opcode escape */ + { "orB", Eb, Gb, XX }, + { "orS", Ev, Gv, XX }, + { "orB", Gb, Eb, XX }, + { "orS", Gv, Ev, XX }, + { "orB", AL, Ib, XX }, + { "orS", eAX, Iv, XX }, + { "push{T|}", cs, XX, XX }, + { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ /* 10 */ - { "adcb", Eb, Gb }, - { "adcS", Ev, Gv }, - { "adcb", Gb, Eb }, - { "adcS", Gv, Ev }, - { "adcb", AL, Ib }, - { "adcS", eAX, Iv }, - { "pushS", ss }, - { "popS", ss }, + { "adcB", Eb, Gb, XX }, + { "adcS", Ev, Gv, XX }, + { "adcB", Gb, Eb, XX }, + { "adcS", Gv, Ev, XX }, + { "adcB", AL, Ib, XX }, + { "adcS", eAX, Iv, XX }, + { "push{T|}", ss, XX, XX }, + { "popT|}", ss, XX, XX }, /* 18 */ - { "sbbb", Eb, Gb }, - { "sbbS", Ev, Gv }, - { "sbbb", Gb, Eb }, - { "sbbS", Gv, Ev }, - { "sbbb", AL, Ib }, - { "sbbS", eAX, Iv }, - { "pushS", ds }, - { "popS", ds }, + { "sbbB", Eb, Gb, XX }, + { "sbbS", Ev, Gv, XX }, + { "sbbB", Gb, Eb, XX }, + { "sbbS", Gv, Ev, XX }, + { "sbbB", AL, Ib, XX }, + { "sbbS", eAX, Iv, XX }, + { "push{T|}", ds, XX, XX }, + { "pop{T|}", ds, XX, XX }, /* 20 */ - { "andb", Eb, Gb }, - { "andS", Ev, Gv }, - { "andb", Gb, Eb }, - { "andS", Gv, Ev }, - { "andb", AL, Ib }, - { "andS", eAX, Iv }, - { "(bad)" }, /* SEG ES prefix */ - { "daa" }, + { "andB", Eb, Gb, XX }, + { "andS", Ev, Gv, XX }, + { "andB", Gb, Eb, XX }, + { "andS", Gv, Ev, XX }, + { "andB", AL, Ib, XX }, + { "andS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG ES prefix */ + { "daa{|}", XX, XX, XX }, /* 28 */ - { "subb", Eb, Gb }, - { "subS", Ev, Gv }, - { "subb", Gb, Eb }, - { "subS", Gv, Ev }, - { "subb", AL, Ib }, - { "subS", eAX, Iv }, - { "(bad)" }, /* SEG CS prefix */ - { "das" }, + { "subB", Eb, Gb, XX }, + { "subS", Ev, Gv, XX }, + { "subB", Gb, Eb, XX }, + { "subS", Gv, Ev, XX }, + { "subB", AL, Ib, XX }, + { "subS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG CS prefix */ + { "das{|}", XX, XX, XX }, /* 30 */ - { "xorb", Eb, Gb }, - { "xorS", Ev, Gv }, - { "xorb", Gb, Eb }, - { "xorS", Gv, Ev }, - { "xorb", AL, Ib }, - { "xorS", eAX, Iv }, - { "(bad)" }, /* SEG SS prefix */ - { "aaa" }, + { "xorB", Eb, Gb, XX }, + { "xorS", Ev, Gv, XX }, + { "xorB", Gb, Eb, XX }, + { "xorS", Gv, Ev, XX }, + { "xorB", AL, Ib, XX }, + { "xorS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG SS prefix */ + { "aaa{|}", XX, XX, XX }, /* 38 */ - { "cmpb", Eb, Gb }, - { "cmpS", Ev, Gv }, - { "cmpb", Gb, Eb }, - { "cmpS", Gv, Ev }, - { "cmpb", AL, Ib }, - { "cmpS", eAX, Iv }, - { "(bad)" }, /* SEG DS prefix */ - { "aas" }, + { "cmpB", Eb, Gb, XX }, + { "cmpS", Ev, Gv, XX }, + { "cmpB", Gb, Eb, XX }, + { "cmpS", Gv, Ev, XX }, + { "cmpB", AL, Ib, XX }, + { "cmpS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG DS prefix */ + { "aas{|}", XX, XX, XX }, /* 40 */ - { "incS", eAX }, - { "incS", eCX }, - { "incS", eDX }, - { "incS", eBX }, - { "incS", eSP }, - { "incS", eBP }, - { "incS", eSI }, - { "incS", eDI }, + { "inc{S|}", RMeAX, XX, XX }, + { "inc{S|}", RMeCX, XX, XX }, + { "inc{S|}", RMeDX, XX, XX }, + { "inc{S|}", RMeBX, XX, XX }, + { "inc{S|}", RMeSP, XX, XX }, + { "inc{S|}", RMeBP, XX, XX }, + { "inc{S|}", RMeSI, XX, XX }, + { "inc{S|}", RMeDI, XX, XX }, /* 48 */ - { "decS", eAX }, - { "decS", eCX }, - { "decS", eDX }, - { "decS", eBX }, - { "decS", eSP }, - { "decS", eBP }, - { "decS", eSI }, - { "decS", eDI }, + { "dec{S|}", RMeAX, XX, XX }, + { "dec{S|}", RMeCX, XX, XX }, + { "dec{S|}", RMeDX, XX, XX }, + { "dec{S|}", RMeBX, XX, XX }, + { "dec{S|}", RMeSP, XX, XX }, + { "dec{S|}", RMeBP, XX, XX }, + { "dec{S|}", RMeSI, XX, XX }, + { "dec{S|}", RMeDI, XX, XX }, /* 50 */ - { "pushS", eAX }, - { "pushS", eCX }, - { "pushS", eDX }, - { "pushS", eBX }, - { "pushS", eSP }, - { "pushS", eBP }, - { "pushS", eSI }, - { "pushS", eDI }, + { "pushS", RMrAX, XX, XX }, + { "pushS", RMrCX, XX, XX }, + { "pushS", RMrDX, XX, XX }, + { "pushS", RMrBX, XX, XX }, + { "pushS", RMrSP, XX, XX }, + { "pushS", RMrBP, XX, XX }, + { "pushS", RMrSI, XX, XX }, + { "pushS", RMrDI, XX, XX }, /* 58 */ - { "popS", eAX }, - { "popS", eCX }, - { "popS", eDX }, - { "popS", eBX }, - { "popS", eSP }, - { "popS", eBP }, - { "popS", eSI }, - { "popS", eDI }, + { "popS", RMrAX, XX, XX }, + { "popS", RMrCX, XX, XX }, + { "popS", RMrDX, XX, XX }, + { "popS", RMrBX, XX, XX }, + { "popS", RMrSP, XX, XX }, + { "popS", RMrBP, XX, XX }, + { "popS", RMrSI, XX, XX }, + { "popS", RMrDI, XX, XX }, /* 60 */ - { "pusha" }, - { "popa" }, - { "boundS", Gv, Ma }, - { "arpl", Ew, Gw }, - { "(bad)" }, /* seg fs */ - { "(bad)" }, /* seg gs */ - { "(bad)" }, /* op size prefix */ - { "(bad)" }, /* adr size prefix */ + { "pusha{P|}", XX, XX, XX }, + { "popa{P|}", XX, XX, XX }, + { "bound{S|}", Gv, Ma, XX }, + { X86_64_0 }, + { "(bad)", XX, XX, XX }, /* seg fs */ + { "(bad)", XX, XX, XX }, /* seg gs */ + { "(bad)", XX, XX, XX }, /* op size prefix */ + { "(bad)", XX, XX, XX }, /* adr size prefix */ /* 68 */ - { "pushS", Iv }, /* 386 book wrong */ - { "imulS", Gv, Ev, Iv }, - { "pushS", sIb }, /* push of byte really pushes 2 or 4 bytes */ - { "imulS", Gv, Ev, Ib }, - { "insb", Yb, indirDX }, - { "insS", Yv, indirDX }, - { "outsb", indirDX, Xb }, - { "outsS", indirDX, Xv }, + { "pushT", Iq, XX, XX }, + { "imulS", Gv, Ev, Iv }, + { "pushT", sIb, XX, XX }, + { "imulS", Gv, Ev, sIb }, + { "ins{b||b|}", Yb, indirDX, XX }, + { "ins{R||R|}", Yv, indirDX, XX }, + { "outs{b||b|}", indirDX, Xb, XX }, + { "outs{R||R|}", indirDX, Xv, XX }, /* 70 */ - { "jo", Jb }, - { "jno", Jb }, - { "jb", Jb }, - { "jae", Jb }, - { "je", Jb }, - { "jne", Jb }, - { "jbe", Jb }, - { "ja", Jb }, + { "joH", Jb, XX, cond_jump_flag }, + { "jnoH", Jb, XX, cond_jump_flag }, + { "jbH", Jb, XX, cond_jump_flag }, + { "jaeH", Jb, XX, cond_jump_flag }, + { "jeH", Jb, XX, cond_jump_flag }, + { "jneH", Jb, XX, cond_jump_flag }, + { "jbeH", Jb, XX, cond_jump_flag }, + { "jaH", Jb, XX, cond_jump_flag }, /* 78 */ - { "js", Jb }, - { "jns", Jb }, - { "jp", Jb }, - { "jnp", Jb }, - { "jl", Jb }, - { "jnl", Jb }, - { "jle", Jb }, - { "jg", Jb }, + { "jsH", Jb, XX, cond_jump_flag }, + { "jnsH", Jb, XX, cond_jump_flag }, + { "jpH", Jb, XX, cond_jump_flag }, + { "jnpH", Jb, XX, cond_jump_flag }, + { "jlH", Jb, XX, cond_jump_flag }, + { "jgeH", Jb, XX, cond_jump_flag }, + { "jleH", Jb, XX, cond_jump_flag }, + { "jgH", Jb, XX, cond_jump_flag }, /* 80 */ { GRP1b }, { GRP1S }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, { GRP1Ss }, - { "testb", Eb, Gb }, - { "testS", Ev, Gv }, - { "xchgb", Eb, Gb }, - { "xchgS", Ev, Gv }, + { "testB", Eb, Gb, XX }, + { "testS", Ev, Gv, XX }, + { "xchgB", Eb, Gb, XX }, + { "xchgS", Ev, Gv, XX }, /* 88 */ - { "movb", Eb, Gb }, - { "movS", Ev, Gv }, - { "movb", Gb, Eb }, - { "movS", Gv, Ev }, - { "movS", Ev, Sw }, - { "leaS", Gv, M }, - { "movS", Sw, Ev }, - { "popS", Ev }, + { "movB", Eb, Gb, XX }, + { "movS", Ev, Gv, XX }, + { "movB", Gb, Eb, XX }, + { "movS", Gv, Ev, XX }, + { "movQ", Ev, Sw, XX }, + { "leaS", Gv, M, XX }, + { "movQ", Sw, Ev, XX }, + { "popU", Ev, XX, XX }, /* 90 */ - { "nop" }, - { "xchgS", eCX, eAX }, - { "xchgS", eDX, eAX }, - { "xchgS", eBX, eAX }, - { "xchgS", eSP, eAX }, - { "xchgS", eBP, eAX }, - { "xchgS", eSI, eAX }, - { "xchgS", eDI, eAX }, + { "nop", XX, XX, XX }, + /* FIXME: NOP with REPz prefix is called PAUSE. */ + { "xchgS", RMeCX, eAX, XX }, + { "xchgS", RMeDX, eAX, XX }, + { "xchgS", RMeBX, eAX, XX }, + { "xchgS", RMeSP, eAX, XX }, + { "xchgS", RMeBP, eAX, XX }, + { "xchgS", RMeSI, eAX, XX }, + { "xchgS", RMeDI, eAX, XX }, /* 98 */ - { "cWtS" }, - { "cStd" }, - { "lcall", Ap }, - { "(bad)" }, /* fwait */ - { "pushf" }, - { "popf" }, - { "sahf" }, - { "lahf" }, + { "cW{tR||tR|}", XX, XX, XX }, + { "cR{tO||tO|}", XX, XX, XX }, + { "lcall{T|}", Ap, XX, XX }, + { "(bad)", XX, XX, XX }, /* fwait */ + { "pushfT", XX, XX, XX }, + { "popfT", XX, XX, XX }, + { "sahf{|}", XX, XX, XX }, + { "lahf{|}", XX, XX, XX }, /* a0 */ - { "movb", AL, Ob }, - { "movS", eAX, Ov }, - { "movb", Ob, AL }, - { "movS", Ov, eAX }, - { "movsb", Yb, Xb }, - { "movsS", Yv, Xv }, - { "cmpsb", Yb, Xb }, - { "cmpsS", Yv, Xv }, + { "movB", AL, Ob64, XX }, + { "movS", eAX, Ov64, XX }, + { "movB", Ob64, AL, XX }, + { "movS", Ov64, eAX, XX }, + { "movs{b||b|}", Yb, Xb, XX }, + { "movs{R||R|}", Yv, Xv, XX }, + { "cmps{b||b|}", Xb, Yb, XX }, + { "cmps{R||R|}", Xv, Yv, XX }, /* a8 */ - { "testb", AL, Ib }, - { "testS", eAX, Iv }, - { "stosb", Yb, AL }, - { "stosS", Yv, eAX }, - { "lodsb", AL, Xb }, - { "lodsS", eAX, Xv }, - { "scasb", AL, Yb }, - { "scasS", eAX, Yv }, + { "testB", AL, Ib, XX }, + { "testS", eAX, Iv, XX }, + { "stosB", Yb, AL, XX }, + { "stosS", Yv, eAX, XX }, + { "lodsB", AL, Xb, XX }, + { "lodsS", eAX, Xv, XX }, + { "scasB", AL, Yb, XX }, + { "scasS", eAX, Yv, XX }, /* b0 */ - { "movb", AL, Ib }, - { "movb", CL, Ib }, - { "movb", DL, Ib }, - { "movb", BL, Ib }, - { "movb", AH, Ib }, - { "movb", CH, Ib }, - { "movb", DH, Ib }, - { "movb", BH, Ib }, + { "movB", RMAL, Ib, XX }, + { "movB", RMCL, Ib, XX }, + { "movB", RMDL, Ib, XX }, + { "movB", RMBL, Ib, XX }, + { "movB", RMAH, Ib, XX }, + { "movB", RMCH, Ib, XX }, + { "movB", RMDH, Ib, XX }, + { "movB", RMBH, Ib, XX }, /* b8 */ - { "movS", eAX, Iv }, - { "movS", eCX, Iv }, - { "movS", eDX, Iv }, - { "movS", eBX, Iv }, - { "movS", eSP, Iv }, - { "movS", eBP, Iv }, - { "movS", eSI, Iv }, - { "movS", eDI, Iv }, + { "movS", RMeAX, Iv64, XX }, + { "movS", RMeCX, Iv64, XX }, + { "movS", RMeDX, Iv64, XX }, + { "movS", RMeBX, Iv64, XX }, + { "movS", RMeSP, Iv64, XX }, + { "movS", RMeBP, Iv64, XX }, + { "movS", RMeSI, Iv64, XX }, + { "movS", RMeDI, Iv64, XX }, /* c0 */ { GRP2b }, { GRP2S }, - { "ret", Iw }, - { "ret" }, - { "lesS", Gv, Mp }, - { "ldsS", Gv, Mp }, - { "movb", Eb, Ib }, - { "movS", Ev, Iv }, + { "retT", Iw, XX, XX }, + { "retT", XX, XX, XX }, + { "les{S|}", Gv, Mp, XX }, + { "ldsS", Gv, Mp, XX }, + { "movA", Eb, Ib, XX }, + { "movQ", Ev, Iv, XX }, /* c8 */ - { "enter", Iw, Ib }, - { "leave" }, - { "lret", Iw }, - { "lret" }, - { "int3" }, - { "int", Ib }, - { "into" }, - { "iret" }, + { "enterT", Iw, Ib, XX }, + { "leaveT", XX, XX, XX }, + { "lretP", Iw, XX, XX }, + { "lretP", XX, XX, XX }, + { "int3", XX, XX, XX }, + { "int", Ib, XX, XX }, + { "into{|}", XX, XX, XX }, + { "iretP", XX, XX, XX }, /* d0 */ { GRP2b_one }, { GRP2S_one }, { GRP2b_cl }, { GRP2S_cl }, - { "aam", Ib }, - { "aad", Ib }, - { "(bad)" }, - { "xlat" }, + { "aam{|}", sIb, XX, XX }, + { "aad{|}", sIb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "xlat", DSBX, XX, XX }, /* d8 */ { FLOAT }, { FLOAT }, @@ -513,581 +715,974 @@ static struct dis386 dis386[] = { { FLOAT }, { FLOAT }, /* e0 */ - { "loopne", Jb }, - { "loope", Jb }, - { "loop", Jb }, - { "jCcxz", Jb }, - { "inb", AL, Ib }, - { "inS", eAX, Ib }, - { "outb", Ib, AL }, - { "outS", Ib, eAX }, + { "loopneFH", Jb, XX, loop_jcxz_flag }, + { "loopeFH", Jb, XX, loop_jcxz_flag }, + { "loopFH", Jb, XX, loop_jcxz_flag }, + { "jEcxzH", Jb, XX, loop_jcxz_flag }, + { "inB", AL, Ib, XX }, + { "inS", eAX, Ib, XX }, + { "outB", Ib, AL, XX }, + { "outS", Ib, eAX, XX }, /* e8 */ - { "call", Av }, - { "jmp", Jv }, - { "ljmp", Ap }, - { "jmp", Jb }, - { "inb", AL, indirDX }, - { "inS", eAX, indirDX }, - { "outb", indirDX, AL }, - { "outS", indirDX, eAX }, + { "callT", Jv, XX, XX }, + { "jmpT", Jv, XX, XX }, + { "ljmp{T|}", Ap, XX, XX }, + { "jmp", Jb, XX, XX }, + { "inB", AL, indirDX, XX }, + { "inS", eAX, indirDX, XX }, + { "outB", indirDX, AL, XX }, + { "outS", indirDX, eAX, XX }, /* f0 */ - { "(bad)" }, /* lock prefix */ - { "(bad)" }, - { "(bad)" }, /* repne */ - { "(bad)" }, /* repz */ - { "hlt" }, - { "cmc" }, + { "(bad)", XX, XX, XX }, /* lock prefix */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* repne */ + { "(bad)", XX, XX, XX }, /* repz */ + { "hlt", XX, XX, XX }, + { "cmc", XX, XX, XX }, { GRP3b }, { GRP3S }, /* f8 */ - { "clc" }, - { "stc" }, - { "cli" }, - { "sti" }, - { "cld" }, - { "std" }, + { "clc", XX, XX, XX }, + { "stc", XX, XX, XX }, + { "cli", XX, XX, XX }, + { "sti", XX, XX, XX }, + { "cld", XX, XX, XX }, + { "std", XX, XX, XX }, { GRP4 }, { GRP5 }, }; -static struct dis386 dis386_twobyte[] = { +static const struct dis386 dis386_twobyte[] = { /* 00 */ { GRP6 }, { GRP7 }, - { "larS", Gv, Ew }, - { "lslS", Gv, Ew }, - { "(bad)" }, - { "(bad)" }, - { "clts" }, - { "(bad)" }, + { "larS", Gv, Ew, XX }, + { "lslS", Gv, Ew, XX }, + { "(bad)", XX, XX, XX }, + { "syscall", XX, XX, XX }, + { "clts", XX, XX, XX }, + { "sysretP", XX, XX, XX }, /* 08 */ - { "invd" }, - { "wbinvd" }, - { "(bad)" }, { "ud2a" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "invd", XX, XX, XX }, + { "wbinvd", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "ud2a", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { GRPAMD }, + { "femms", XX, XX, XX }, + { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix. */ /* 10 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { PREGRP8 }, + { PREGRP9 }, + { "movlpX", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ + { "movlpX", EX, XM, SIMD_Fixup, 'h' }, + { "unpcklpX", XM, EX, XX }, + { "unpckhpX", XM, EX, XX }, + { "movhpX", XM, EX, SIMD_Fixup, 'l' }, + { "movhpX", EX, XM, SIMD_Fixup, 'l' }, /* 18 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { GRP14 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* 20 */ - /* these are all backward in appendix A of the intel book */ - { "movl", Rd, Cd }, - { "movl", Rd, Dd }, - { "movl", Cd, Rd }, - { "movl", Dd, Rd }, - { "movl", Rd, Td }, - { "(bad)" }, - { "movl", Td, Rd }, - { "(bad)" }, + { "movL", Rm, Cm, XX }, + { "movL", Rm, Dm, XX }, + { "movL", Cm, Rm, XX }, + { "movL", Dm, Rm, XX }, + { "movL", Rd, Td, XX }, + { "(bad)", XX, XX, XX }, + { "movL", Td, Rd, XX }, + { "(bad)", XX, XX, XX }, /* 28 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "movapX", XM, EX, XX }, + { "movapX", EX, XM, XX }, + { PREGRP2 }, + { "movntpX", Ev, XM, XX }, + { PREGRP4 }, + { PREGRP3 }, + { "ucomisX", XM,EX, XX }, + { "comisX", XM,EX, XX }, /* 30 */ - { "wrmsr" }, { "rdtsc" }, { "rdmsr" }, { "rdpmc" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "wrmsr", XX, XX, XX }, + { "rdtsc", XX, XX, XX }, + { "rdmsr", XX, XX, XX }, + { "rdpmc", XX, XX, XX }, + { "sysenter", XX, XX, XX }, + { "sysexit", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* 38 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* 40 */ - { "cmovo", Gv,Ev }, { "cmovno", Gv,Ev }, { "cmovb", Gv,Ev }, { "cmovae", Gv,Ev }, - { "cmove", Gv,Ev }, { "cmovne", Gv,Ev }, { "cmovbe", Gv,Ev }, { "cmova", Gv,Ev }, + { "cmovo", Gv, Ev, XX }, + { "cmovno", Gv, Ev, XX }, + { "cmovb", Gv, Ev, XX }, + { "cmovae", Gv, Ev, XX }, + { "cmove", Gv, Ev, XX }, + { "cmovne", Gv, Ev, XX }, + { "cmovbe", Gv, Ev, XX }, + { "cmova", Gv, Ev, XX }, /* 48 */ - { "cmovs", Gv,Ev }, { "cmovns", Gv,Ev }, { "cmovp", Gv,Ev }, { "cmovnp", Gv,Ev }, - { "cmovl", Gv,Ev }, { "cmovge", Gv,Ev }, { "cmovle", Gv,Ev }, { "cmovg", Gv,Ev }, + { "cmovs", Gv, Ev, XX }, + { "cmovns", Gv, Ev, XX }, + { "cmovp", Gv, Ev, XX }, + { "cmovnp", Gv, Ev, XX }, + { "cmovl", Gv, Ev, XX }, + { "cmovge", Gv, Ev, XX }, + { "cmovle", Gv, Ev, XX }, + { "cmovg", Gv, Ev, XX }, /* 50 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "movmskpX", Gd, XS, XX }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andpX", XM, EX, XX }, + { "andnpX", XM, EX, XX }, + { "orpX", XM, EX, XX }, + { "xorpX", XM, EX, XX }, /* 58 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { PREGRP0 }, + { PREGRP10 }, + { PREGRP17 }, + { PREGRP16 }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, /* 60 */ - { "punpcklbw", MX, EM }, - { "punpcklwd", MX, EM }, - { "punpckldq", MX, EM }, - { "packsswb", MX, EM }, - { "pcmpgtb", MX, EM }, - { "pcmpgtw", MX, EM }, - { "pcmpgtd", MX, EM }, - { "packuswb", MX, EM }, + { "punpcklbw", MX, EM, XX }, + { "punpcklwd", MX, EM, XX }, + { "punpckldq", MX, EM, XX }, + { "packsswb", MX, EM, XX }, + { "pcmpgtb", MX, EM, XX }, + { "pcmpgtw", MX, EM, XX }, + { "pcmpgtd", MX, EM, XX }, + { "packuswb", MX, EM, XX }, /* 68 */ - { "punpckhbw", MX, EM }, - { "punpckhwd", MX, EM }, - { "punpckhdq", MX, EM }, - { "packssdw", MX, EM }, - { "(bad)" }, { "(bad)" }, - { "movd", MX, Ev }, - { "movq", MX, EM }, + { "punpckhbw", MX, EM, XX }, + { "punpckhwd", MX, EM, XX }, + { "punpckhdq", MX, EM, XX }, + { "packssdw", MX, EM, XX }, + { PREGRP26 }, + { PREGRP24 }, + { "movd", MX, Ed, XX }, + { PREGRP19 }, /* 70 */ - { "(bad)" }, + { PREGRP22 }, { GRP10 }, { GRP11 }, { GRP12 }, - { "pcmpeqb", MX, EM }, - { "pcmpeqw", MX, EM }, - { "pcmpeqd", MX, EM }, - { "emms" }, + { "pcmpeqb", MX, EM, XX }, + { "pcmpeqw", MX, EM, XX }, + { "pcmpeqd", MX, EM, XX }, + { "emms", XX, XX, XX }, /* 78 */ - { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, - { "(bad)" }, { "(bad)" }, - { "movd", Ev, MX }, - { "movq", EM, MX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { PREGRP23 }, + { PREGRP20 }, /* 80 */ - { "jo", Jv }, - { "jno", Jv }, - { "jb", Jv }, - { "jae", Jv }, - { "je", Jv }, - { "jne", Jv }, - { "jbe", Jv }, - { "ja", Jv }, + { "joH", Jv, XX, cond_jump_flag }, + { "jnoH", Jv, XX, cond_jump_flag }, + { "jbH", Jv, XX, cond_jump_flag }, + { "jaeH", Jv, XX, cond_jump_flag }, + { "jeH", Jv, XX, cond_jump_flag }, + { "jneH", Jv, XX, cond_jump_flag }, + { "jbeH", Jv, XX, cond_jump_flag }, + { "jaH", Jv, XX, cond_jump_flag }, /* 88 */ - { "js", Jv }, - { "jns", Jv }, - { "jp", Jv }, - { "jnp", Jv }, - { "jl", Jv }, - { "jge", Jv }, - { "jle", Jv }, - { "jg", Jv }, + { "jsH", Jv, XX, cond_jump_flag }, + { "jnsH", Jv, XX, cond_jump_flag }, + { "jpH", Jv, XX, cond_jump_flag }, + { "jnpH", Jv, XX, cond_jump_flag }, + { "jlH", Jv, XX, cond_jump_flag }, + { "jgeH", Jv, XX, cond_jump_flag }, + { "jleH", Jv, XX, cond_jump_flag }, + { "jgH", Jv, XX, cond_jump_flag }, /* 90 */ - { "seto", Eb }, - { "setno", Eb }, - { "setb", Eb }, - { "setae", Eb }, - { "sete", Eb }, - { "setne", Eb }, - { "setbe", Eb }, - { "seta", Eb }, + { "seto", Eb, XX, XX }, + { "setno", Eb, XX, XX }, + { "setb", Eb, XX, XX }, + { "setae", Eb, XX, XX }, + { "sete", Eb, XX, XX }, + { "setne", Eb, XX, XX }, + { "setbe", Eb, XX, XX }, + { "seta", Eb, XX, XX }, /* 98 */ - { "sets", Eb }, - { "setns", Eb }, - { "setp", Eb }, - { "setnp", Eb }, - { "setl", Eb }, - { "setge", Eb }, - { "setle", Eb }, - { "setg", Eb }, + { "sets", Eb, XX, XX }, + { "setns", Eb, XX, XX }, + { "setp", Eb, XX, XX }, + { "setnp", Eb, XX, XX }, + { "setl", Eb, XX, XX }, + { "setge", Eb, XX, XX }, + { "setle", Eb, XX, XX }, + { "setg", Eb, XX, XX }, /* a0 */ - { "pushS", fs }, - { "popS", fs }, - { "cpuid" }, - { "btS", Ev, Gv }, - { "shldS", Ev, Gv, Ib }, - { "shldS", Ev, Gv, CL }, - { "(bad)" }, - { "(bad)" }, + { "pushT", fs, XX, XX }, + { "popT", fs, XX, XX }, + { "cpuid", XX, XX, XX }, + { "btS", Ev, Gv, XX }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* a8 */ - { "pushS", gs }, - { "popS", gs }, - { "rsm" }, - { "btsS", Ev, Gv }, - { "shrdS", Ev, Gv, Ib }, - { "shrdS", Ev, Gv, CL }, - { "(bad)" }, - { "imulS", Gv, Ev }, + { "pushT", gs, XX, XX }, + { "popT", gs, XX, XX }, + { "rsm", XX, XX, XX }, + { "btsS", Ev, Gv, XX }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { GRP13 }, + { "imulS", Gv, Ev, XX }, /* b0 */ - { "cmpxchgb", Eb, Gb }, - { "cmpxchgS", Ev, Gv }, - { "lssS", Gv, Mp }, /* 386 lists only Mp */ - { "btrS", Ev, Gv }, - { "lfsS", Gv, Mp }, /* 386 lists only Mp */ - { "lgsS", Gv, Mp }, /* 386 lists only Mp */ - { "movzbS", Gv, Eb }, - { "movzwS", Gv, Ew }, + { "cmpxchgB", Eb, Gb, XX }, + { "cmpxchgS", Ev, Gv, XX }, + { "lssS", Gv, Mp, XX }, + { "btrS", Ev, Gv, XX }, + { "lfsS", Gv, Mp, XX }, + { "lgsS", Gv, Mp, XX }, + { "movz{bR|x|bR|x}", Gv, Eb, XX }, + { "movz{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movzww ! */ /* b8 */ - { "ud2b" }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "ud2b", XX, XX, XX }, { GRP8 }, - { "btcS", Ev, Gv }, - { "bsfS", Gv, Ev }, - { "bsrS", Gv, Ev }, - { "movsbS", Gv, Eb }, - { "movswS", Gv, Ew }, + { "btcS", Ev, Gv, XX }, + { "bsfS", Gv, Ev, XX }, + { "bsrS", Gv, Ev, XX }, + { "movs{bR|x|bR|x}", Gv, Eb, XX }, + { "movs{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movsww ! */ /* c0 */ - { "xaddb", Eb, Gb }, - { "xaddS", Ev, Gv }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { GRP9 }, + { "xaddB", Eb, Gb, XX }, + { "xaddS", Ev, Gv, XX }, + { PREGRP1 }, + { "movntiS", Ev, Gv, XX }, + { "pinsrw", MX, Ed, Ib }, + { "pextrw", Gd, MS, Ib }, + { "shufpX", XM, EX, Ib }, + { GRP9 }, /* c8 */ - { "bswap", eAX }, - { "bswap", eCX }, - { "bswap", eDX }, - { "bswap", eBX }, - { "bswap", eSP }, - { "bswap", eBP }, - { "bswap", eSI }, - { "bswap", eDI }, + { "bswap", RMeAX, XX, XX }, + { "bswap", RMeCX, XX, XX }, + { "bswap", RMeDX, XX, XX }, + { "bswap", RMeBX, XX, XX }, + { "bswap", RMeSP, XX, XX }, + { "bswap", RMeBP, XX, XX }, + { "bswap", RMeSI, XX, XX }, + { "bswap", RMeDI, XX, XX }, /* d0 */ - { "(bad)" }, - { "psrlw", MX, EM }, - { "psrld", MX, EM }, - { "psrlq", MX, EM }, - { "(bad)" }, - { "pmullw", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "psrlw", MX, EM, XX }, + { "psrld", MX, EM, XX }, + { "psrlq", MX, EM, XX }, + { "paddq", MX, EM, XX }, + { "pmullw", MX, EM, XX }, + { PREGRP21 }, + { "pmovmskb", Gd, MS, XX }, /* d8 */ - { "psubusb", MX, EM }, - { "psubusw", MX, EM }, - { "(bad)" }, - { "pand", MX, EM }, - { "paddusb", MX, EM }, - { "paddusw", MX, EM }, - { "(bad)" }, - { "pandn", MX, EM }, + { "psubusb", MX, EM, XX }, + { "psubusw", MX, EM, XX }, + { "pminub", MX, EM, XX }, + { "pand", MX, EM, XX }, + { "paddusb", MX, EM, XX }, + { "paddusw", MX, EM, XX }, + { "pmaxub", MX, EM, XX }, + { "pandn", MX, EM, XX }, /* e0 */ - { "(bad)" }, - { "psraw", MX, EM }, - { "psrad", MX, EM }, - { "(bad)" }, - { "(bad)" }, - { "pmulhw", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "pavgb", MX, EM, XX }, + { "psraw", MX, EM, XX }, + { "psrad", MX, EM, XX }, + { "pavgw", MX, EM, XX }, + { "pmulhuw", MX, EM, XX }, + { "pmulhw", MX, EM, XX }, + { PREGRP15 }, + { PREGRP25 }, /* e8 */ - { "psubsb", MX, EM }, - { "psubsw", MX, EM }, - { "(bad)" }, - { "por", MX, EM }, - { "paddsb", MX, EM }, - { "paddsw", MX, EM }, - { "(bad)" }, - { "pxor", MX, EM }, + { "psubsb", MX, EM, XX }, + { "psubsw", MX, EM, XX }, + { "pminsw", MX, EM, XX }, + { "por", MX, EM, XX }, + { "paddsb", MX, EM, XX }, + { "paddsw", MX, EM, XX }, + { "pmaxsw", MX, EM, XX }, + { "pxor", MX, EM, XX }, /* f0 */ - { "(bad)" }, - { "psllw", MX, EM }, - { "pslld", MX, EM }, - { "psllq", MX, EM }, - { "(bad)" }, - { "pmaddwd", MX, EM }, - { "(bad)" }, { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "psllw", MX, EM, XX }, + { "pslld", MX, EM, XX }, + { "psllq", MX, EM, XX }, + { "pmuludq", MX, EM, XX }, + { "pmaddwd", MX, EM, XX }, + { "psadbw", MX, EM, XX }, + { PREGRP18 }, /* f8 */ - { "psubb", MX, EM }, - { "psubw", MX, EM }, - { "psubd", MX, EM }, - { "(bad)" }, - { "paddb", MX, EM }, - { "paddw", MX, EM }, - { "paddd", MX, EM }, - { "(bad)" } + { "psubb", MX, EM, XX }, + { "psubw", MX, EM, XX }, + { "psubd", MX, EM, XX }, + { "psubq", MX, EM, XX }, + { "paddb", MX, EM, XX }, + { "paddw", MX, EM, XX }, + { "paddd", MX, EM, XX }, + { "(bad)", XX, XX, XX } }; static const unsigned char onebyte_has_modrm[256] = { - 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, - 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, - 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, - 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, - 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ + /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ + /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ + /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ + /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ + /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ + /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ + /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ + /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; static const unsigned char twobyte_has_modrm[256] = { - /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ - /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ - /* 20 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 2f */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ - /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ - /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, /* 6f */ - /* 70 */ 0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ + /* 70 */ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ - /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ + /* a0 */ 0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1, /* af */ /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ - /* d0 */ 0,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1, /* df */ - /* e0 */ 0,1,1,0,0,1,0,0,1,1,0,1,1,1,0,1, /* ef */ - /* f0 */ 0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0 /* ff */ + /* d0 */ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_SSE_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ + /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; static char obuf[100]; static char *obufp; static char scratchbuf[100]; static unsigned char *start_codep; +static unsigned char *insn_codep; static unsigned char *codep; static disassemble_info *the_info; static int mod; static int rm; static int reg; -static void oappend PARAMS ((char *s)); +static unsigned char need_modrm; + +/* If we are accessing mod/rm/reg without need_modrm set, then the + values are stale. Hitting this abort likely indicates that you + need to update onebyte_has_modrm or twobyte_has_modrm. */ +#define MODRM_CHECK if (!need_modrm) abort () + +static const char **names64; +static const char **names32; +static const char **names16; +static const char **names8; +static const char **names8rex; +static const char **names_seg; +static const char **index16; + +static const char *intel_names64[] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; +static const char *intel_names32[] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" +}; +static const char *intel_names16[] = { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" +}; +static const char *intel_names8[] = { + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", +}; +static const char *intel_names8rex[] = { + "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" +}; +static const char *intel_names_seg[] = { + "es", "cs", "ss", "ds", "fs", "gs", "?", "?", +}; +static const char *intel_index16[] = { + "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" +}; -static char *names32[]={ - "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +static const char *att_names64[] = { + "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" +}; +static const char *att_names32[] = { + "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" }; -static char *names16[] = { - "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +static const char *att_names16[] = { + "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" }; -static char *names8[] = { - "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +static const char *att_names8[] = { + "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", }; -static char *names_seg[] = { - "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +static const char *att_names8rex[] = { + "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" }; -static char *index16[] = { - "bx+si","bx+di","bp+si","bp+di","si","di","bp","bx" +static const char *att_names_seg[] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", +}; +static const char *att_index16[] = { + "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" }; -static struct dis386 grps[][8] = { +static const struct dis386 grps[][8] = { /* GRP1b */ { - { "addb", Eb, Ib }, - { "orb", Eb, Ib }, - { "adcb", Eb, Ib }, - { "sbbb", Eb, Ib }, - { "andb", Eb, Ib }, - { "subb", Eb, Ib }, - { "xorb", Eb, Ib }, - { "cmpb", Eb, Ib } + { "addA", Eb, Ib, XX }, + { "orA", Eb, Ib, XX }, + { "adcA", Eb, Ib, XX }, + { "sbbA", Eb, Ib, XX }, + { "andA", Eb, Ib, XX }, + { "subA", Eb, Ib, XX }, + { "xorA", Eb, Ib, XX }, + { "cmpA", Eb, Ib, XX } }, /* GRP1S */ { - { "addS", Ev, Iv }, - { "orS", Ev, Iv }, - { "adcS", Ev, Iv }, - { "sbbS", Ev, Iv }, - { "andS", Ev, Iv }, - { "subS", Ev, Iv }, - { "xorS", Ev, Iv }, - { "cmpS", Ev, Iv } + { "addQ", Ev, Iv, XX }, + { "orQ", Ev, Iv, XX }, + { "adcQ", Ev, Iv, XX }, + { "sbbQ", Ev, Iv, XX }, + { "andQ", Ev, Iv, XX }, + { "subQ", Ev, Iv, XX }, + { "xorQ", Ev, Iv, XX }, + { "cmpQ", Ev, Iv, XX } }, /* GRP1Ss */ { - { "addS", Ev, sIb }, - { "orS", Ev, sIb }, - { "adcS", Ev, sIb }, - { "sbbS", Ev, sIb }, - { "andS", Ev, sIb }, - { "subS", Ev, sIb }, - { "xorS", Ev, sIb }, - { "cmpS", Ev, sIb } + { "addQ", Ev, sIb, XX }, + { "orQ", Ev, sIb, XX }, + { "adcQ", Ev, sIb, XX }, + { "sbbQ", Ev, sIb, XX }, + { "andQ", Ev, sIb, XX }, + { "subQ", Ev, sIb, XX }, + { "xorQ", Ev, sIb, XX }, + { "cmpQ", Ev, sIb, XX } }, /* GRP2b */ { - { "rolb", Eb, Ib }, - { "rorb", Eb, Ib }, - { "rclb", Eb, Ib }, - { "rcrb", Eb, Ib }, - { "shlb", Eb, Ib }, - { "shrb", Eb, Ib }, - { "(bad)" }, - { "sarb", Eb, Ib }, + { "rolA", Eb, Ib, XX }, + { "rorA", Eb, Ib, XX }, + { "rclA", Eb, Ib, XX }, + { "rcrA", Eb, Ib, XX }, + { "shlA", Eb, Ib, XX }, + { "shrA", Eb, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, Ib, XX }, }, /* GRP2S */ { - { "rolS", Ev, Ib }, - { "rorS", Ev, Ib }, - { "rclS", Ev, Ib }, - { "rcrS", Ev, Ib }, - { "shlS", Ev, Ib }, - { "shrS", Ev, Ib }, - { "(bad)" }, - { "sarS", Ev, Ib }, + { "rolQ", Ev, Ib, XX }, + { "rorQ", Ev, Ib, XX }, + { "rclQ", Ev, Ib, XX }, + { "rcrQ", Ev, Ib, XX }, + { "shlQ", Ev, Ib, XX }, + { "shrQ", Ev, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, Ib, XX }, }, /* GRP2b_one */ { - { "rolb", Eb }, - { "rorb", Eb }, - { "rclb", Eb }, - { "rcrb", Eb }, - { "shlb", Eb }, - { "shrb", Eb }, - { "(bad)" }, - { "sarb", Eb }, + { "rolA", Eb, XX, XX }, + { "rorA", Eb, XX, XX }, + { "rclA", Eb, XX, XX }, + { "rcrA", Eb, XX, XX }, + { "shlA", Eb, XX, XX }, + { "shrA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, XX, XX }, }, /* GRP2S_one */ { - { "rolS", Ev }, - { "rorS", Ev }, - { "rclS", Ev }, - { "rcrS", Ev }, - { "shlS", Ev }, - { "shrS", Ev }, - { "(bad)" }, - { "sarS", Ev }, + { "rolQ", Ev, XX, XX }, + { "rorQ", Ev, XX, XX }, + { "rclQ", Ev, XX, XX }, + { "rcrQ", Ev, XX, XX }, + { "shlQ", Ev, XX, XX }, + { "shrQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX}, + { "sarQ", Ev, XX, XX }, }, /* GRP2b_cl */ { - { "rolb", Eb, CL }, - { "rorb", Eb, CL }, - { "rclb", Eb, CL }, - { "rcrb", Eb, CL }, - { "shlb", Eb, CL }, - { "shrb", Eb, CL }, - { "(bad)" }, - { "sarb", Eb, CL }, + { "rolA", Eb, CL, XX }, + { "rorA", Eb, CL, XX }, + { "rclA", Eb, CL, XX }, + { "rcrA", Eb, CL, XX }, + { "shlA", Eb, CL, XX }, + { "shrA", Eb, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, CL, XX }, }, /* GRP2S_cl */ { - { "rolS", Ev, CL }, - { "rorS", Ev, CL }, - { "rclS", Ev, CL }, - { "rcrS", Ev, CL }, - { "shlS", Ev, CL }, - { "shrS", Ev, CL }, - { "(bad)" }, - { "sarS", Ev, CL } + { "rolQ", Ev, CL, XX }, + { "rorQ", Ev, CL, XX }, + { "rclQ", Ev, CL, XX }, + { "rcrQ", Ev, CL, XX }, + { "shlQ", Ev, CL, XX }, + { "shrQ", Ev, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, CL, XX } }, /* GRP3b */ { - { "testb", Eb, Ib }, - { "(bad)", Eb }, - { "notb", Eb }, - { "negb", Eb }, - { "mulb", AL, Eb }, - { "imulb", AL, Eb }, - { "divb", AL, Eb }, - { "idivb", AL, Eb } + { "testA", Eb, Ib, XX }, + { "(bad)", Eb, XX, XX }, + { "notA", Eb, XX, XX }, + { "negA", Eb, XX, XX }, + { "mulA", Eb, XX, XX }, /* Don't print the implicit %al register, */ + { "imulA", Eb, XX, XX }, /* to distinguish these opcodes from other */ + { "divA", Eb, XX, XX }, /* mul/imul opcodes. Do the same for div */ + { "idivA", Eb, XX, XX } /* and idiv for consistency. */ }, /* GRP3S */ { - { "testS", Ev, Iv }, - { "(bad)" }, - { "notS", Ev }, - { "negS", Ev }, - { "mulS", eAX, Ev }, - { "imulS", eAX, Ev }, - { "divS", eAX, Ev }, - { "idivS", eAX, Ev }, + { "testQ", Ev, Iv, XX }, + { "(bad)", XX, XX, XX }, + { "notQ", Ev, XX, XX }, + { "negQ", Ev, XX, XX }, + { "mulQ", Ev, XX, XX }, /* Don't print the implicit register. */ + { "imulQ", Ev, XX, XX }, + { "divQ", Ev, XX, XX }, + { "idivQ", Ev, XX, XX }, }, /* GRP4 */ { - { "incb", Eb }, - { "decb", Eb }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, + { "incA", Eb, XX, XX }, + { "decA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP5 */ { - { "incS", Ev }, - { "decS", Ev }, - { "call", indirEv }, - { "lcall", indirEv }, - { "jmp", indirEv }, - { "ljmp", indirEv }, - { "pushS", Ev }, - { "(bad)" }, + { "incQ", Ev, XX, XX }, + { "decQ", Ev, XX, XX }, + { "callT", indirEv, XX, XX }, + { "lcallT", indirEv, XX, XX }, + { "jmpT", indirEv, XX, XX }, + { "ljmpT", indirEv, XX, XX }, + { "pushU", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP6 */ { - { "sldt", Ew }, - { "str", Ew }, - { "lldt", Ew }, - { "ltr", Ew }, - { "verr", Ew }, - { "verw", Ew }, - { "(bad)" }, - { "(bad)" } + { "sldtQ", Ev, XX, XX }, + { "strQ", Ev, XX, XX }, + { "lldt", Ew, XX, XX }, + { "ltr", Ew, XX, XX }, + { "verr", Ew, XX, XX }, + { "verw", Ew, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX } }, /* GRP7 */ { - { "sgdt", Ew }, - { "sidt", Ew }, - { "lgdt", Ew }, - { "lidt", Ew }, - { "smsw", Ew }, - { "(bad)" }, - { "lmsw", Ew }, - { "invlpg", Ew }, + { "sgdtQ", M, XX, XX }, + { "sidtQ", M, XX, XX }, + { "lgdtQ", M, XX, XX }, + { "lidtQ", M, XX, XX }, + { "smswQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "lmsw", Ew, XX, XX }, + { "invlpg", Ew, XX, XX }, }, /* GRP8 */ { - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "btS", Ev, Ib }, - { "btsS", Ev, Ib }, - { "btrS", Ev, Ib }, - { "btcS", Ev, Ib }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "btQ", Ev, Ib, XX }, + { "btsQ", Ev, Ib, XX }, + { "btrQ", Ev, Ib, XX }, + { "btcQ", Ev, Ib, XX }, }, /* GRP9 */ { - { "(bad)" }, - { "cmpxchg8b", Ev }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "cmpxchg8b", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP10 */ { - { "(bad)" }, - { "(bad)" }, - { "psrlw", MS, Ib }, - { "(bad)" }, - { "psraw", MS, Ib }, - { "(bad)" }, - { "psllw", MS, Ib }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psraw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psllw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP11 */ { - { "(bad)" }, - { "(bad)" }, - { "psrld", MS, Ib }, - { "(bad)" }, - { "psrad", MS, Ib }, - { "(bad)" }, - { "pslld", MS, Ib }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psrad", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "pslld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, }, /* GRP12 */ { - { "(bad)" }, - { "(bad)" }, - { "psrlq", MS, Ib }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "psllq", MS, Ib }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlq", MS, Ib, XX }, + { "psrldq", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psllq", MS, Ib, XX }, + { "pslldq", MS, Ib, XX }, + }, + /* GRP13 */ + { + { "fxsave", Ev, XX, XX }, + { "fxrstor", Ev, XX, XX }, + { "ldmxcsr", Ev, XX, XX }, + { "stmxcsr", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "lfence", None, XX, XX }, + { "mfence", None, XX, XX }, + { "sfence", None, XX, XX }, + /* FIXME: the sfence with memory operand is clflush! */ + }, + /* GRP14 */ + { + { "prefetchnta", Ev, XX, XX }, + { "prefetcht0", Ev, XX, XX }, + { "prefetcht1", Ev, XX, XX }, + { "prefetcht2", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRPAMD */ + { + { "prefetch", Eb, XX, XX }, + { "prefetchw", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, } }; -#define PREFIX_REPZ 1 -#define PREFIX_REPNZ 2 -#define PREFIX_LOCK 4 -#define PREFIX_CS 8 -#define PREFIX_SS 0x10 -#define PREFIX_DS 0x20 -#define PREFIX_ES 0x40 -#define PREFIX_FS 0x80 -#define PREFIX_GS 0x100 -#define PREFIX_DATA 0x200 -#define PREFIX_ADR 0x400 -#define PREFIX_FWAIT 0x800 +static const struct dis386 prefix_user_table[][4] = { + /* PREGRP0 */ + { + { "addps", XM, EX, XX }, + { "addss", XM, EX, XX }, + { "addpd", XM, EX, XX }, + { "addsd", XM, EX, XX }, + }, + /* PREGRP1 */ + { + { "", XM, EX, OPSIMD }, /* See OP_SIMD_SUFFIX. */ + { "", XM, EX, OPSIMD }, + { "", XM, EX, OPSIMD }, + { "", XM, EX, OPSIMD }, + }, + /* PREGRP2 */ + { + { "cvtpi2ps", XM, EM, XX }, + { "cvtsi2ssY", XM, Ev, XX }, + { "cvtpi2pd", XM, EM, XX }, + { "cvtsi2sdY", XM, Ev, XX }, + }, + /* PREGRP3 */ + { + { "cvtps2pi", MX, EX, XX }, + { "cvtss2siY", Gv, EX, XX }, + { "cvtpd2pi", MX, EX, XX }, + { "cvtsd2siY", Gv, EX, XX }, + }, + /* PREGRP4 */ + { + { "cvttps2pi", MX, EX, XX }, + { "cvttss2siY", Gv, EX, XX }, + { "cvttpd2pi", MX, EX, XX }, + { "cvttsd2siY", Gv, EX, XX }, + }, + /* PREGRP5 */ + { + { "divps", XM, EX, XX }, + { "divss", XM, EX, XX }, + { "divpd", XM, EX, XX }, + { "divsd", XM, EX, XX }, + }, + /* PREGRP6 */ + { + { "maxps", XM, EX, XX }, + { "maxss", XM, EX, XX }, + { "maxpd", XM, EX, XX }, + { "maxsd", XM, EX, XX }, + }, + /* PREGRP7 */ + { + { "minps", XM, EX, XX }, + { "minss", XM, EX, XX }, + { "minpd", XM, EX, XX }, + { "minsd", XM, EX, XX }, + }, + /* PREGRP8 */ + { + { "movups", XM, EX, XX }, + { "movss", XM, EX, XX }, + { "movupd", XM, EX, XX }, + { "movsd", XM, EX, XX }, + }, + /* PREGRP9 */ + { + { "movups", EX, XM, XX }, + { "movss", EX, XM, XX }, + { "movupd", EX, XM, XX }, + { "movsd", EX, XM, XX }, + }, + /* PREGRP10 */ + { + { "mulps", XM, EX, XX }, + { "mulss", XM, EX, XX }, + { "mulpd", XM, EX, XX }, + { "mulsd", XM, EX, XX }, + }, + /* PREGRP11 */ + { + { "rcpps", XM, EX, XX }, + { "rcpss", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP12 */ + { + { "rsqrtps", XM, EX, XX }, + { "rsqrtss", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP13 */ + { + { "sqrtps", XM, EX, XX }, + { "sqrtss", XM, EX, XX }, + { "sqrtpd", XM, EX, XX }, + { "sqrtsd", XM, EX, XX }, + }, + /* PREGRP14 */ + { + { "subps", XM, EX, XX }, + { "subss", XM, EX, XX }, + { "subpd", XM, EX, XX }, + { "subsd", XM, EX, XX }, + }, + /* PREGRP15 */ + { + { "(bad)", XM, EX, XX }, + { "cvtdq2pd", XM, EX, XX }, + { "cvttpd2dq", XM, EX, XX }, + { "cvtpd2dq", XM, EX, XX }, + }, + /* PREGRP16 */ + { + { "cvtdq2ps", XM, EX, XX }, + { "cvttps2dq",XM, EX, XX }, + { "cvtps2dq",XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP17 */ + { + { "cvtps2pd", XM, EX, XX }, + { "cvtss2sd", XM, EX, XX }, + { "cvtpd2ps", XM, EX, XX }, + { "cvtsd2ss", XM, EX, XX }, + }, + /* PREGRP18 */ + { + { "maskmovq", MX, MS, XX }, + { "(bad)", XM, EX, XX }, + { "maskmovdqu", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP19 */ + { + { "movq", MX, EM, XX }, + { "movdqu", XM, EX, XX }, + { "movdqa", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP20 */ + { + { "movq", EM, MX, XX }, + { "movdqu", EX, XM, XX }, + { "movdqa", EX, XM, XX }, + { "(bad)", EX, XM, XX }, + }, + /* PREGRP21 */ + { + { "(bad)", EX, XM, XX }, + { "movq2dq", XM, MS, XX }, + { "movq", EX, XM, XX }, + { "movdq2q", MX, XS, XX }, + }, + /* PREGRP22 */ + { + { "pshufw", MX, EM, Ib }, + { "pshufhw", XM, EX, Ib }, + { "pshufd", XM, EX, Ib }, + { "pshuflw", XM, EX, Ib }, + }, + /* PREGRP23 */ + { + { "movd", Ed, MX, XX }, + { "movq", XM, EX, XX }, + { "movd", Ed, XM, XX }, + { "(bad)", Ed, XM, XX }, + }, + /* PREGRP24 */ + { + { "(bad)", MX, EX, XX }, + { "(bad)", XM, EX, XX }, + { "punpckhqdq", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, + /* PREGRP25 */ + { + { "movntq", Ev, MX, XX }, + { "(bad)", Ev, XM, XX }, + { "movntdq", Ev, XM, XX }, + { "(bad)", Ev, XM, XX }, + }, + /* PREGRP26 */ + { + { "(bad)", MX, EX, XX }, + { "(bad)", XM, EX, XX }, + { "punpcklqdq", XM, EX, XX }, + { "(bad)", XM, EX, XX }, + }, +}; -static int prefixes; +static const struct dis386 x86_64_table[][2] = { + { + { "arpl", Ew, Gw, XX }, + { "movs{||lq|xd}", Gv, Ed, XX }, + }, +}; + +#define INTERNAL_DISASSEMBLER_ERROR _("") static void ckprefix () { + int newrex; + rex = 0; prefixes = 0; + used_prefixes = 0; + rex_used = 0; while (1) { FETCH_DATA (the_info, codep + 1); + newrex = 0; switch (*codep) { + /* REX prefixes family. */ + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + if (mode_64bit) + newrex = *codep; + else + return; + break; case 0xf3: prefixes |= PREFIX_REPZ; break; @@ -1119,22 +1714,114 @@ ckprefix () prefixes |= PREFIX_DATA; break; case 0x67: - prefixes |= PREFIX_ADR; + prefixes |= PREFIX_ADDR; break; - case 0x9b: - prefixes |= PREFIX_FWAIT; + case FWAIT_OPCODE: + /* fwait is really an instruction. If there are prefixes + before the fwait, they belong to the fwait, *not* to the + following instruction. */ + if (prefixes) + { + prefixes |= PREFIX_FWAIT; + codep++; + return; + } + prefixes = PREFIX_FWAIT; break; default: return; } + /* Rex is ignored when followed by another prefix. */ + if (rex) + { + oappend (prefix_name (rex, 0)); + oappend (" "); + } + rex = newrex; codep++; } } -static char op1out[100], op2out[100], op3out[100]; -static int op_address[3], op_ad, op_index[3]; -static int start_pc; +/* Return the name of the prefix byte PREF, or NULL if PREF is not a + prefix byte. */ + +static const char * +prefix_name (pref, sizeflag) + int pref; + int sizeflag; +{ + switch (pref) + { + /* REX prefixes family. */ + case 0x40: + return "rex"; + case 0x41: + return "rexZ"; + case 0x42: + return "rexY"; + case 0x43: + return "rexYZ"; + case 0x44: + return "rexX"; + case 0x45: + return "rexXZ"; + case 0x46: + return "rexXY"; + case 0x47: + return "rexXYZ"; + case 0x48: + return "rex64"; + case 0x49: + return "rex64Z"; + case 0x4a: + return "rex64Y"; + case 0x4b: + return "rex64YZ"; + case 0x4c: + return "rex64X"; + case 0x4d: + return "rex64XZ"; + case 0x4e: + return "rex64XY"; + case 0x4f: + return "rex64XYZ"; + case 0xf3: + return "repz"; + case 0xf2: + return "repnz"; + case 0xf0: + return "lock"; + case 0x2e: + return "cs"; + case 0x36: + return "ss"; + case 0x3e: + return "ds"; + case 0x26: + return "es"; + case 0x64: + return "fs"; + case 0x65: + return "gs"; + case 0x66: + return (sizeflag & DFLAG) ? "data16" : "data32"; + case 0x67: + if (mode_64bit) + return (sizeflag & AFLAG) ? "addr32" : "addr64"; + else + return ((sizeflag & AFLAG) && !mode_64bit) ? "addr16" : "addr32"; + case FWAIT_OPCODE: + return "fwait"; + default: + return NULL; + } +} +static char op1out[100], op2out[100], op3out[100]; +static int op_ad, op_index[3]; +static bfd_vma op_address[3]; +static bfd_vma op_riprel[3]; +static bfd_vma start_pc; /* * On the 386's of 1988, the maximum length of an instruction is 15 bytes. @@ -1145,48 +1832,160 @@ static int start_pc; * The function returns the length of this instruction in bytes. */ -int print_insn_x86 PARAMS ((bfd_vma pc, disassemble_info *info, int aflag, - int dflag)); +static char intel_syntax; +static char open_char; +static char close_char; +static char separator_char; +static char scale_char; + +/* Here for backwards compatibility. When gdb stops using + print_insn_i386_att and print_insn_i386_intel these functions can + disappear, and print_insn_i386 be merged into print_insn. */ int -print_insn_i386 (pc, info) +print_insn_i386_att (pc, info) bfd_vma pc; disassemble_info *info; { - if (info->mach == bfd_mach_i386_i386) - return print_insn_x86 (pc, info, 1, 1); - else if (info->mach == bfd_mach_i386_i8086) - return print_insn_x86 (pc, info, 0, 0); - else - abort (); + intel_syntax = 0; + + return print_insn (pc, info); +} + +int +print_insn_i386_intel (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 1; + + return print_insn (pc, info); } int -print_insn_x86 (pc, info, aflag, dflag) +print_insn_i386 (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = -1; + + return print_insn (pc, info); +} + +static int +print_insn (pc, info) bfd_vma pc; disassemble_info *info; - int volatile aflag; - int volatile dflag; { - struct dis386 *dp; + const struct dis386 *dp; int i; - int enter_instruction; + int two_source_ops; char *first, *second, *third; int needcomma; - unsigned char need_modrm; - + unsigned char uses_SSE_prefix; + int sizeflag; + const char *p; struct dis_private priv; - bfd_byte *inbuf = priv.the_buffer; - /* The output looks better if we put 5 bytes on a line, since that - puts long word instructions on a single line. */ - info->bytes_per_line = 5; + mode_64bit = (info->mach == bfd_mach_x86_64_intel_syntax + || info->mach == bfd_mach_x86_64); + + if (intel_syntax == -1) + intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax); + + if (info->mach == bfd_mach_i386_i386 + || info->mach == bfd_mach_x86_64 + || info->mach == bfd_mach_i386_i386_intel_syntax + || info->mach == bfd_mach_x86_64_intel_syntax) + priv.orig_sizeflag = AFLAG | DFLAG; + else if (info->mach == bfd_mach_i386_i8086) + priv.orig_sizeflag = 0; + else + abort (); + + for (p = info->disassembler_options; p != NULL; ) + { + if (strncmp (p, "x86-64", 6) == 0) + { + mode_64bit = 1; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i386", 4) == 0) + { + mode_64bit = 0; + priv.orig_sizeflag = AFLAG | DFLAG; + } + else if (strncmp (p, "i8086", 5) == 0) + { + mode_64bit = 0; + priv.orig_sizeflag = 0; + } + else if (strncmp (p, "intel", 5) == 0) + { + intel_syntax = 1; + } + else if (strncmp (p, "att", 3) == 0) + { + intel_syntax = 0; + } + else if (strncmp (p, "addr", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~AFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= AFLAG; + } + else if (strncmp (p, "data", 4) == 0) + { + if (p[4] == '1' && p[5] == '6') + priv.orig_sizeflag &= ~DFLAG; + else if (p[4] == '3' && p[5] == '2') + priv.orig_sizeflag |= DFLAG; + } + else if (strncmp (p, "suffix", 6) == 0) + priv.orig_sizeflag |= SUFFIX_ALWAYS; + + p = strchr (p, ','); + if (p != NULL) + p++; + } + + if (intel_syntax) + { + names64 = intel_names64; + names32 = intel_names32; + names16 = intel_names16; + names8 = intel_names8; + names8rex = intel_names8rex; + names_seg = intel_names_seg; + index16 = intel_index16; + open_char = '['; + close_char = ']'; + separator_char = '+'; + scale_char = '*'; + } + else + { + names64 = att_names64; + names32 = att_names32; + names16 = att_names16; + names8 = att_names8; + names8rex = att_names8rex; + names_seg = att_names_seg; + index16 = att_index16; + open_char = '('; + close_char = ')'; + separator_char = ','; + scale_char = ','; + } + + /* The output looks better if we put 7 bytes on a line, since that + puts most long word instructions on a single line. */ + info->bytes_per_line = 7; info->private_data = (PTR) &priv; priv.max_fetched = priv.the_buffer; priv.insn_start = pc; - if (setjmp (priv.bailout) != 0) - /* Error return. */ - return -1; obuf[0] = 0; op1out[0] = 0; @@ -1197,59 +1996,116 @@ print_insn_x86 (pc, info, aflag, dflag) the_info = info; start_pc = pc; - start_codep = inbuf; - codep = inbuf; - + start_codep = priv.the_buffer; + codep = priv.the_buffer; + + if (setjmp (priv.bailout) != 0) + { + const char *name; + + /* Getting here means we tried for data but didn't get it. That + means we have an incomplete instruction of some sort. Just + print the first byte as a prefix or a .byte pseudo-op. */ + if (codep > priv.the_buffer) + { + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name != NULL) + (*info->fprintf_func) (info->stream, "%s", name); + else + { + /* Just print the first byte as a .byte instruction. */ + (*info->fprintf_func) (info->stream, ".byte 0x%x", + (unsigned int) priv.the_buffer[0]); + } + + return 1; + } + + return -1; + } + + obufp = obuf; ckprefix (); + insn_codep = codep; + sizeflag = priv.orig_sizeflag; + FETCH_DATA (info, codep + 1); - if (*codep == 0xc8) - enter_instruction = 1; - else - enter_instruction = 0; - - obufp = obuf; - - if (prefixes & PREFIX_REPZ) - oappend ("repz "); - if (prefixes & PREFIX_REPNZ) - oappend ("repnz "); - if (prefixes & PREFIX_LOCK) - oappend ("lock "); - + two_source_ops = (*codep == 0x62) || (*codep == 0xc8); + if ((prefixes & PREFIX_FWAIT) && ((*codep < 0xd8) || (*codep > 0xdf))) { - /* fwait not followed by floating point instruction */ - (*info->fprintf_func) (info->stream, "fwait"); - return (1); - } - - if (prefixes & PREFIX_DATA) - dflag ^= 1; - - if (prefixes & PREFIX_ADR) - { - aflag ^= 1; - if (aflag) - oappend ("addr32 "); - else - oappend ("addr16 "); + const char *name; + + /* fwait not followed by floating point instruction. Print the + first prefix, which is probably fwait itself. */ + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; } - + if (*codep == 0x0f) { FETCH_DATA (info, codep + 2); dp = &dis386_twobyte[*++codep]; need_modrm = twobyte_has_modrm[*codep]; + uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep]; } else { dp = &dis386[*codep]; need_modrm = onebyte_has_modrm[*codep]; + uses_SSE_prefix = 0; } codep++; + if (!uses_SSE_prefix && (prefixes & PREFIX_REPZ)) + { + oappend ("repz "); + used_prefixes |= PREFIX_REPZ; + } + if (!uses_SSE_prefix && (prefixes & PREFIX_REPNZ)) + { + oappend ("repnz "); + used_prefixes |= PREFIX_REPNZ; + } + if (prefixes & PREFIX_LOCK) + { + oappend ("lock "); + used_prefixes |= PREFIX_LOCK; + } + + if (prefixes & PREFIX_ADDR) + { + sizeflag ^= AFLAG; + if (dp->bytemode3 != loop_jcxz_mode || intel_syntax) + { + if ((sizeflag & AFLAG) || mode_64bit) + oappend ("addr32 "); + else + oappend ("addr16 "); + used_prefixes |= PREFIX_ADDR; + } + } + + if (!uses_SSE_prefix && (prefixes & PREFIX_DATA)) + { + sizeflag ^= DFLAG; + if (dp->bytemode3 == cond_jump_mode + && dp->bytemode1 == v_mode + && !intel_syntax) + { + if (sizeflag & DFLAG) + oappend ("data32 "); + else + oappend ("data16 "); + used_prefixes |= PREFIX_DATA; + } + } + if (need_modrm) { FETCH_DATA (info, codep + 1); @@ -1260,42 +2116,100 @@ print_insn_x86 (pc, info, aflag, dflag) if (dp->name == NULL && dp->bytemode1 == FLOATCODE) { - dofloat (aflag, dflag); + dofloat (sizeflag); } else { + int index; if (dp->name == NULL) - dp = &grps[dp->bytemode1][reg]; - - putop (dp->name, aflag, dflag); - - obufp = op1out; - op_ad = 2; - if (dp->op1) - (*dp->op1)(dp->bytemode1, aflag, dflag); - - obufp = op2out; - op_ad = 1; - if (dp->op2) - (*dp->op2)(dp->bytemode2, aflag, dflag); - - obufp = op3out; - op_ad = 0; - if (dp->op3) - (*dp->op3)(dp->bytemode3, aflag, dflag); + { + switch (dp->bytemode1) + { + case USE_GROUPS: + dp = &grps[dp->bytemode2][reg]; + break; + + case USE_PREFIX_USER_TABLE: + index = 0; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + index = 1; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + index = 2; + else + { + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + index = 3; + } + } + dp = &prefix_user_table[dp->bytemode2][index]; + break; + + case X86_64_SPECIAL: + dp = &x86_64_table[dp->bytemode2][mode_64bit]; + break; + + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + } + + if (putop (dp->name, sizeflag) == 0) + { + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1) (dp->bytemode1, sizeflag); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2) (dp->bytemode2, sizeflag); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3) (dp->bytemode3, sizeflag); + } + } + + /* See if any prefixes were not used. If so, print the first one + separately. If we don't do this, we'll wind up printing an + instruction stream which does not precisely correspond to the + bytes we are disassembling. */ + if ((prefixes & ~used_prefixes) != 0) + { + const char *name; + + name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + if (rex & ~rex_used) + { + const char *name; + name = prefix_name (rex | 0x40, priv.orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s ", name); } - + obufp = obuf + strlen (obuf); for (i = strlen (obuf); i < 6; i++) oappend (" "); oappend (" "); (*info->fprintf_func) (info->stream, "%s", obuf); - - /* enter instruction is printed with operands in the - * same order as the intel book; everything else - * is printed in reverse order - */ - if (enter_instruction) + + /* The enter and bound instructions are printed with operands in the same + order as the intel book; everything else is printed in reverse order. */ + if (intel_syntax || two_source_ops) { first = op1out; second = op2out; @@ -1313,8 +2227,8 @@ print_insn_x86 (pc, info, aflag, dflag) needcomma = 0; if (*first) { - if (op_index[0] != -1) - (*info->print_address_func) (op_address[op_index[0]], info); + if (op_index[0] != -1 && !op_riprel[0]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info); else (*info->fprintf_func) (info->stream, "%s", first); needcomma = 1; @@ -1323,8 +2237,8 @@ print_insn_x86 (pc, info, aflag, dflag) { if (needcomma) (*info->fprintf_func) (info->stream, ","); - if (op_index[1] != -1) - (*info->print_address_func) (op_address[op_index[1]], info); + if (op_index[1] != -1 && !op_riprel[1]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info); else (*info->fprintf_func) (info->stream, "%s", second); needcomma = 1; @@ -1333,65 +2247,72 @@ print_insn_x86 (pc, info, aflag, dflag) { if (needcomma) (*info->fprintf_func) (info->stream, ","); - if (op_index[2] != -1) - (*info->print_address_func) (op_address[op_index[2]], info); + if (op_index[2] != -1 && !op_riprel[2]) + (*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info); else (*info->fprintf_func) (info->stream, "%s", third); } - return (codep - inbuf); + for (i = 0; i < 3; i++) + if (op_index[i] != -1 && op_riprel[i]) + { + (*info->fprintf_func) (info->stream, " # "); + (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep + + op_address[op_index[i]]), info); + } + return codep - priv.the_buffer; } -static char *float_mem[] = { +static const char *float_mem[] = { /* d8 */ - "fadds", - "fmuls", - "fcoms", - "fcomps", - "fsubs", - "fsubrs", - "fdivs", - "fdivrs", + "fadd{s||s|}", + "fmul{s||s|}", + "fcom{s||s|}", + "fcomp{s||s|}", + "fsub{s||s|}", + "fsubr{s||s|}", + "fdiv{s||s|}", + "fdivr{s||s|}", /* d9 */ - "flds", + "fld{s||s|}", "(bad)", - "fsts", - "fstps", + "fst{s||s|}", + "fstp{s||s|}", "fldenv", "fldcw", "fNstenv", "fNstcw", /* da */ - "fiaddl", - "fimull", - "ficoml", - "ficompl", - "fisubl", - "fisubrl", - "fidivl", - "fidivrl", + "fiadd{l||l|}", + "fimul{l||l|}", + "ficom{l||l|}", + "ficomp{l||l|}", + "fisub{l||l|}", + "fisubr{l||l|}", + "fidiv{l||l|}", + "fidivr{l||l|}", /* db */ - "fildl", + "fild{l||l|}", "(bad)", - "fistl", - "fistpl", + "fist{l||l|}", + "fistp{l||l|}", "(bad)", - "fldt", + "fld{t||t|}", "(bad)", - "fstpt", + "fstp{t||t|}", /* dc */ - "faddl", - "fmull", - "fcoml", - "fcompl", - "fsubl", - "fsubrl", - "fdivl", - "fdivrl", + "fadd{l||l|}", + "fmul{l||l|}", + "fcom{l||l|}", + "fcomp{l||l|}", + "fsub{l||l|}", + "fsubr{l||l|}", + "fdiv{l||l|}", + "fdivr{l||l|}", /* dd */ - "fldl", + "fld{l||l|}", "(bad)", - "fstl", - "fstpl", + "fst{l||l|}", + "fstp{l||l|}", "frstor", "(bad)", "fNsave", @@ -1411,7 +2332,7 @@ static char *float_mem[] = { "fist", "fistp", "fbld", - "fildll", + "fild{ll||ll|}", "fbstp", "fistpll", }; @@ -1419,34 +2340,34 @@ static char *float_mem[] = { #define ST OP_ST, 0 #define STi OP_STi, 0 -#define FGRPd9_2 NULL, NULL, 0 -#define FGRPd9_4 NULL, NULL, 1 -#define FGRPd9_5 NULL, NULL, 2 -#define FGRPd9_6 NULL, NULL, 3 -#define FGRPd9_7 NULL, NULL, 4 -#define FGRPda_5 NULL, NULL, 5 -#define FGRPdb_4 NULL, NULL, 6 -#define FGRPde_3 NULL, NULL, 7 -#define FGRPdf_4 NULL, NULL, 8 - -static struct dis386 float_reg[][8] = { +#define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0 +#define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0 +#define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0 +#define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0 +#define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0 +#define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0 +#define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0 +#define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0 + +static const struct dis386 float_reg[][8] = { /* d8 */ { - { "fadd", ST, STi }, - { "fmul", ST, STi }, - { "fcom", STi }, - { "fcomp", STi }, - { "fsub", ST, STi }, - { "fsubr", ST, STi }, - { "fdiv", ST, STi }, - { "fdivr", ST, STi }, + { "fadd", ST, STi, XX }, + { "fmul", ST, STi, XX }, + { "fcom", STi, XX, XX }, + { "fcomp", STi, XX, XX }, + { "fsub", ST, STi, XX }, + { "fsubr", ST, STi, XX }, + { "fdiv", ST, STi, XX }, + { "fdivr", ST, STi, XX }, }, /* d9 */ { - { "fld", STi }, - { "fxch", STi }, + { "fld", STi, XX, XX }, + { "fxch", STi, XX, XX }, { FGRPd9_2 }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, { FGRPd9_4 }, { FGRPd9_5 }, { FGRPd9_6 }, @@ -1454,73 +2375,86 @@ static struct dis386 float_reg[][8] = { }, /* da */ { - { "fcmovb", ST, STi }, - { "fcmove", ST, STi }, - { "fcmovbe",ST, STi }, - { "fcmovu", ST, STi }, - { "(bad)" }, + { "fcmovb", ST, STi, XX }, + { "fcmove", ST, STi, XX }, + { "fcmovbe",ST, STi, XX }, + { "fcmovu", ST, STi, XX }, + { "(bad)", XX, XX, XX }, { FGRPda_5 }, - { "(bad)" }, - { "(bad)" }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* db */ { - { "fcmovnb",ST, STi }, - { "fcmovne",ST, STi }, - { "fcmovnbe",ST, STi }, - { "fcmovnu",ST, STi }, + { "fcmovnb",ST, STi, XX }, + { "fcmovne",ST, STi, XX }, + { "fcmovnbe",ST, STi, XX }, + { "fcmovnu",ST, STi, XX }, { FGRPdb_4 }, - { "fucomi", ST, STi }, - { "fcomi", ST, STi }, - { "(bad)" }, + { "fucomi", ST, STi, XX }, + { "fcomi", ST, STi, XX }, + { "(bad)", XX, XX, XX }, }, /* dc */ { - { "fadd", STi, ST }, - { "fmul", STi, ST }, - { "(bad)" }, - { "(bad)" }, - { "fsub", STi, ST }, - { "fsubr", STi, ST }, - { "fdiv", STi, ST }, - { "fdivr", STi, ST }, + { "fadd", STi, ST, XX }, + { "fmul", STi, ST, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, +#if UNIXWARE_COMPAT + { "fsub", STi, ST, XX }, + { "fsubr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, + { "fdivr", STi, ST, XX }, +#else + { "fsubr", STi, ST, XX }, + { "fsub", STi, ST, XX }, + { "fdivr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, +#endif }, /* dd */ { - { "ffree", STi }, - { "(bad)" }, - { "fst", STi }, - { "fstp", STi }, - { "fucom", STi }, - { "fucomp", STi }, - { "(bad)" }, - { "(bad)" }, + { "ffree", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "fst", STi, XX, XX }, + { "fstp", STi, XX, XX }, + { "fucom", STi, XX, XX }, + { "fucomp", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, }, /* de */ { - { "faddp", STi, ST }, - { "fmulp", STi, ST }, - { "(bad)" }, + { "faddp", STi, ST, XX }, + { "fmulp", STi, ST, XX }, + { "(bad)", XX, XX, XX }, { FGRPde_3 }, - { "fsubp", STi, ST }, - { "fsubrp", STi, ST }, - { "fdivp", STi, ST }, - { "fdivrp", STi, ST }, +#if UNIXWARE_COMPAT + { "fsubp", STi, ST, XX }, + { "fsubrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, +#else + { "fsubrp", STi, ST, XX }, + { "fsubp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, +#endif }, /* df */ { - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, - { "(bad)" }, + { "ffreep", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, { FGRPdf_4 }, - { "fucomip",ST, STi }, - { "fcomip", ST, STi }, - { "(bad)" }, + { "fucomip",ST, STi, XX }, + { "fcomip", ST, STi, XX }, + { "(bad)", XX, XX, XX }, }, }; - static char *fgrps[][8] = { /* d9_2 0 */ { @@ -1570,79 +2504,78 @@ static char *fgrps[][8] = { }; static void -dofloat (aflag, dflag) - int aflag; - int dflag; +dofloat (sizeflag) + int sizeflag; { - struct dis386 *dp; + const struct dis386 *dp; unsigned char floatop; - + floatop = codep[-1]; - + if (mod != 3) { - putop (float_mem[(floatop - 0xd8) * 8 + reg], aflag, dflag); + putop (float_mem[(floatop - 0xd8) * 8 + reg], sizeflag); obufp = op1out; - OP_E (v_mode, aflag, dflag); + if (floatop == 0xdb) + OP_E (x_mode, sizeflag); + else if (floatop == 0xdd) + OP_E (d_mode, sizeflag); + else + OP_E (v_mode, sizeflag); return; } + /* Skip mod/rm byte. */ + MODRM_CHECK; codep++; - + dp = &float_reg[floatop - 0xd8][reg]; if (dp->name == NULL) { - putop (fgrps[dp->bytemode1][rm], aflag, dflag); - /* instruction fnstsw is only one with strange arg */ - if (floatop == 0xdf - && FETCH_DATA (the_info, codep + 1) - && *codep == 0xe0) - strcpy (op1out, "%eax"); + putop (fgrps[dp->bytemode1][rm], sizeflag); + + /* Instruction fnstsw is only one with strange arg. */ + if (floatop == 0xdf && codep[-1] == 0xe0) + strcpy (op1out, names16[0]); } else { - putop (dp->name, aflag, dflag); + putop (dp->name, sizeflag); + obufp = op1out; if (dp->op1) - (*dp->op1)(dp->bytemode1, aflag, dflag); + (*dp->op1) (dp->bytemode1, sizeflag); obufp = op2out; if (dp->op2) - (*dp->op2)(dp->bytemode2, aflag, dflag); + (*dp->op2) (dp->bytemode2, sizeflag); } } -/* ARGSUSED */ -static int -OP_ST (ignore, aflag, dflag) - int ignore; - int aflag; - int dflag; +static void +OP_ST (bytemode, sizeflag) + int bytemode; + int sizeflag; { oappend ("%st"); - return (0); } -/* ARGSUSED */ -static int -OP_STi (ignore, aflag, dflag) - int ignore; - int aflag; - int dflag; +static void +OP_STi (bytemode, sizeflag) + int bytemode; + int sizeflag; { sprintf (scratchbuf, "%%st(%d)", rm); - oappend (scratchbuf); - return (0); + oappend (scratchbuf + intel_syntax); } - -/* capital letters in template are macros */ -static void -putop (template, aflag, dflag) - char *template; - int aflag; - int dflag; +/* Capital letters in template are macros. */ +static int +putop (template, sizeflag) + const char *template; + int sizeflag; { - char *p; - + const char *p; + int alt; + for (p = template; *p; p++) { switch (*p) @@ -1650,78 +2583,393 @@ putop (template, aflag, dflag) default: *obufp++ = *p; break; - case 'C': /* For jcxz/jecxz */ - if (aflag) - *obufp++ = 'e'; + case '{': + alt = 0; + if (intel_syntax) + alt += 1; + if (mode_64bit) + alt += 2; + while (alt != 0) + { + while (*++p != '|') + { + if (*p == '}') + { + /* Alternative not valid. */ + strcpy (obuf, "(bad)"); + obufp = obuf + 5; + return 1; + } + else if (*p == '\0') + abort (); + } + alt--; + } + break; + case '|': + while (*++p != '}') + { + if (*p == '\0') + abort (); + } + break; + case '}': + break; + case 'A': + if (intel_syntax) + break; + if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + *obufp++ = 'b'; + break; + case 'B': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'b'; + break; + case 'E': /* For jcxz/jecxz */ + if (mode_64bit) + { + if (sizeflag & AFLAG) + *obufp++ = 'r'; + else + *obufp++ = 'e'; + } + else + if (sizeflag & AFLAG) + *obufp++ = 'e'; + used_prefixes |= (prefixes & PREFIX_ADDR); + break; + case 'F': + if (intel_syntax) + break; + if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) + { + if (sizeflag & AFLAG) + *obufp++ = mode_64bit ? 'q' : 'l'; + else + *obufp++ = mode_64bit ? 'l' : 'w'; + used_prefixes |= (prefixes & PREFIX_ADDR); + } + break; + case 'H': + if (intel_syntax) + break; + if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS + || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) + { + used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); + *obufp++ = ','; + *obufp++ = 'p'; + if (prefixes & PREFIX_DS) + *obufp++ = 't'; + else + *obufp++ = 'n'; + } + break; + case 'L': + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'l'; break; case 'N': if ((prefixes & PREFIX_FWAIT) == 0) *obufp++ = 'n'; + else + used_prefixes |= PREFIX_FWAIT; + break; + case 'O': + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + *obufp++ = 'o'; + else + *obufp++ = 'd'; + break; + case 'T': + if (intel_syntax) + break; + if (mode_64bit) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'P': + if (intel_syntax) + break; + if ((prefixes & PREFIX_DATA) + || (rex & REX_MODE64) + || (sizeflag & SUFFIX_ALWAYS)) + { + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'U': + if (intel_syntax) + break; + if (mode_64bit) + { + *obufp++ = 'q'; + break; + } + /* Fall through. */ + case 'Q': + if (intel_syntax) + break; + USED_REX (REX_MODE64); + if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'R': + USED_REX (REX_MODE64); + if (intel_syntax) + { + if (rex & REX_MODE64) + { + *obufp++ = 'q'; + *obufp++ = 't'; + } + else if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'q'; + } + else + { + *obufp++ = 'w'; + *obufp++ = 'd'; + } + } + else + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + } + if (!(rex & REX_MODE64)) + used_prefixes |= (prefixes & PREFIX_DATA); break; case 'S': - /* operand size flag */ - if (dflag) - *obufp++ = 'l'; + if (intel_syntax) + break; + if (sizeflag & SUFFIX_ALWAYS) + { + if (rex & REX_MODE64) + *obufp++ = 'q'; + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + } + break; + case 'X': + if (prefixes & PREFIX_DATA) + *obufp++ = 'd'; else - *obufp++ = 'w'; + *obufp++ = 's'; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'Y': + if (intel_syntax) + break; + if (rex & REX_MODE64) + { + USED_REX (REX_MODE64); + *obufp++ = 'q'; + } break; + /* implicit operand size 'l' for i386 or 'q' for x86-64 */ case 'W': /* operand size flag for cwtl, cbtw */ - if (dflag) + USED_REX (0); + if (rex) + *obufp++ = 'l'; + else if (sizeflag & DFLAG) *obufp++ = 'w'; else *obufp++ = 'b'; + if (intel_syntax) + { + if (rex) + { + *obufp++ = 'q'; + *obufp++ = 'e'; + } + if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'e'; + } + else + { + *obufp++ = 'w'; + } + } + if (!rex) + used_prefixes |= (prefixes & PREFIX_DATA); break; } } *obufp = 0; + return 0; } static void oappend (s) - char *s; + const char *s; { strcpy (obufp, s); obufp += strlen (s); - *obufp = 0; } static void -append_prefix () +append_seg () { if (prefixes & PREFIX_CS) - oappend ("%cs:"); + { + used_prefixes |= PREFIX_CS; + oappend ("%cs:" + intel_syntax); + } if (prefixes & PREFIX_DS) - oappend ("%ds:"); + { + used_prefixes |= PREFIX_DS; + oappend ("%ds:" + intel_syntax); + } if (prefixes & PREFIX_SS) - oappend ("%ss:"); + { + used_prefixes |= PREFIX_SS; + oappend ("%ss:" + intel_syntax); + } if (prefixes & PREFIX_ES) - oappend ("%es:"); + { + used_prefixes |= PREFIX_ES; + oappend ("%es:" + intel_syntax); + } if (prefixes & PREFIX_FS) - oappend ("%fs:"); + { + used_prefixes |= PREFIX_FS; + oappend ("%fs:" + intel_syntax); + } if (prefixes & PREFIX_GS) - oappend ("%gs:"); + { + used_prefixes |= PREFIX_GS; + oappend ("%gs:" + intel_syntax); + } } -static int -OP_indirE (bytemode, aflag, dflag) +static void +OP_indirE (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - oappend ("*"); - return OP_E (bytemode, aflag, dflag); + if (!intel_syntax) + oappend ("*"); + OP_E (bytemode, sizeflag); } -static int -OP_E (bytemode, aflag, dflag) +static void +print_operand_value (buf, hex, disp) + char *buf; + int hex; + bfd_vma disp; +{ + if (mode_64bit) + { + if (hex) + { + char tmp[30]; + int i; + buf[0] = '0'; + buf[1] = 'x'; + sprintf_vma (tmp, disp); + for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); + strcpy (buf + 2, tmp + i); + } + else + { + bfd_signed_vma v = disp; + char tmp[30]; + int i; + if (v < 0) + { + *(buf++) = '-'; + v = -disp; + /* Check for possible overflow on 0x8000000000000000. */ + if (v < 0) + { + strcpy (buf, "9223372036854775808"); + return; + } + } + if (!v) + { + strcpy (buf, "0"); + return; + } + + i = 0; + tmp[29] = 0; + while (v) + { + tmp[28 - i] = (v % 10) + '0'; + v /= 10; + i++; + } + strcpy (buf, tmp + 29 - i); + } + } + else + { + if (hex) + sprintf (buf, "0x%x", (unsigned int) disp); + else + sprintf (buf, "%d", (int) disp); + } +} + +static void +OP_E (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - int disp; + bfd_vma disp; + int add = 0; + int riprel = 0; + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add += 8; - /* skip mod/rm byte */ + /* Skip mod/rm byte. */ + MODRM_CHECK; codep++; if (mod == 3) @@ -1729,28 +2977,54 @@ OP_E (bytemode, aflag, dflag) switch (bytemode) { case b_mode: - oappend (names8[rm]); + USED_REX (0); + if (rex) + oappend (names8rex[rm + add]); + else + oappend (names8[rm + add]); break; case w_mode: - oappend (names16[rm]); + oappend (names16[rm + add]); + break; + case d_mode: + oappend (names32[rm + add]); + break; + case q_mode: + oappend (names64[rm + add]); + break; + case m_mode: + if (mode_64bit) + oappend (names64[rm + add]); + else + oappend (names32[rm + add]); break; case v_mode: - if (dflag) - oappend (names32[rm]); + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + oappend (names64[rm + add]); + else if (sizeflag & DFLAG) + oappend (names32[rm + add]); else - oappend (names16[rm]); + oappend (names16[rm + add]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 0: + if (!(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */) + && !(codep[-2] == 0xAE && codep[-1] == 0xF0 /* mfence */) + && !(codep[-2] == 0xAE && codep[-1] == 0xe8 /* lfence */)) + BadOp (); /* bad sfence,lea,lds,les,lfs,lgs,lss modrm */ break; default: - oappend (""); + oappend (INTERNAL_DISASSEMBLER_ERROR); break; } - return 0; + return; } disp = 0; - append_prefix (); + append_seg (); - if (aflag) /* 32 bit address mode */ + if ((sizeflag & AFLAG) || mode_64bit) /* 32 bit address mode */ { int havesib; int havebase; @@ -1769,16 +3043,24 @@ OP_E (bytemode, aflag, dflag) scale = (*codep >> 6) & 3; index = (*codep >> 3) & 7; base = *codep & 7; + USED_REX (REX_EXTY); + USED_REX (REX_EXTZ); + if (rex & REX_EXTY) + index += 8; + if (rex & REX_EXTZ) + base += 8; codep++; } switch (mod) { case 0: - if (base == 5) + if ((base & 7) == 5) { havebase = 0; - disp = get32 (); + if (mode_64bit && !havesib && (sizeflag & AFLAG)) + riprel = 1; + disp = get32s (); } break; case 1: @@ -1788,40 +3070,139 @@ OP_E (bytemode, aflag, dflag) disp -= 0x100; break; case 2: - disp = get32 (); + disp = get32s (); break; } - if (mod != 0 || base == 5) - { - sprintf (scratchbuf, "0x%x", disp); - oappend (scratchbuf); - } + if (!intel_syntax) + if (mod != 0 || (base & 7) == 5) + { + print_operand_value (scratchbuf, !riprel, disp); + oappend (scratchbuf); + if (riprel) + { + set_op (disp, 1); + oappend ("(%rip)"); + } + } if (havebase || (havesib && (index != 4 || scale != 0))) { - oappend ("("); + if (intel_syntax) + { + switch (bytemode) + { + case b_mode: + oappend ("BYTE PTR "); + break; + case w_mode: + oappend ("WORD PTR "); + break; + case v_mode: + oappend ("DWORD PTR "); + break; + case d_mode: + oappend ("QWORD PTR "); + break; + case m_mode: + if (mode_64bit) + oappend ("DWORD PTR "); + else + oappend ("QWORD PTR "); + break; + case x_mode: + oappend ("XWORD PTR "); + break; + default: + break; + } + } + *obufp++ = open_char; + if (intel_syntax && riprel) + oappend ("rip + "); + *obufp = '\0'; + USED_REX (REX_EXTZ); + if (!havesib && (rex & REX_EXTZ)) + base += 8; if (havebase) - oappend (names32[base]); + oappend (mode_64bit && (sizeflag & AFLAG) + ? names64[base] : names32[base]); if (havesib) { if (index != 4) { - sprintf (scratchbuf, ",%s", names32[index]); + if (intel_syntax) + { + if (havebase) + { + *obufp++ = separator_char; + *obufp = '\0'; + } + sprintf (scratchbuf, "%s", + mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); + } + else + sprintf (scratchbuf, ",%s", + mode_64bit && (sizeflag & AFLAG) + ? names64[index] : names32[index]); oappend (scratchbuf); } - sprintf (scratchbuf, ",%d", 1 << scale); - oappend (scratchbuf); + if (!intel_syntax + || (intel_syntax + && bytemode != b_mode + && bytemode != w_mode + && bytemode != v_mode)) + { + *obufp++ = scale_char; + *obufp = '\0'; + sprintf (scratchbuf, "%d", 1 << scale); + oappend (scratchbuf); + } } - oappend (")"); + if (intel_syntax) + if (mod != 0 || (base & 7) == 5) + { + /* Don't print zero displacements. */ + if (disp != 0) + { + if ((bfd_signed_vma) disp > 0) + { + *obufp++ = '+'; + *obufp = '\0'; + } + + print_operand_value (scratchbuf, 0, disp); + oappend (scratchbuf); + } + } + + *obufp++ = close_char; + *obufp = '\0'; } + else if (intel_syntax) + { + if (mod != 0 || (base & 7) == 5) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + print_operand_value (scratchbuf, 1, disp); + oappend (scratchbuf); + } + } } else { /* 16 bit address mode */ switch (mod) { case 0: - if (rm == 6) + if ((rm & 7) == 6) { disp = get16 (); if ((disp & 0x8000) != 0) @@ -1841,63 +3222,119 @@ OP_E (bytemode, aflag, dflag) break; } - if (mod != 0 || rm == 6) - { - sprintf (scratchbuf, "0x%x", disp); - oappend (scratchbuf); - } + if (!intel_syntax) + if (mod != 0 || (rm & 7) == 6) + { + print_operand_value (scratchbuf, 0, disp); + oappend (scratchbuf); + } - if (mod != 0 || rm != 6) + if (mod != 0 || (rm & 7) != 6) { - oappend ("("); - oappend (index16[rm]); - oappend (")"); + *obufp++ = open_char; + *obufp = '\0'; + oappend (index16[rm + add]); + *obufp++ = close_char; + *obufp = '\0'; } } - return 0; } -static int -OP_G (bytemode, aflag, dflag) +static void +OP_G (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - switch (bytemode) + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add += 8; + switch (bytemode) { case b_mode: - oappend (names8[reg]); + USED_REX (0); + if (rex) + oappend (names8rex[reg + add]); + else + oappend (names8[reg + add]); break; case w_mode: - oappend (names16[reg]); + oappend (names16[reg + add]); break; case d_mode: - oappend (names32[reg]); + oappend (names32[reg + add]); + break; + case q_mode: + oappend (names64[reg + add]); break; case v_mode: - if (dflag) - oappend (names32[reg]); + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + oappend (names64[reg + add]); + else if (sizeflag & DFLAG) + oappend (names32[reg + add]); else - oappend (names16[reg]); + oappend (names16[reg + add]); + used_prefixes |= (prefixes & PREFIX_DATA); break; default: - oappend (""); + oappend (INTERNAL_DISASSEMBLER_ERROR); break; } - return (0); } -static int +static bfd_vma +get64 () +{ + bfd_vma x; +#ifdef BFD64 + unsigned int a; + unsigned int b; + + FETCH_DATA (the_info, codep + 8); + a = *codep++ & 0xff; + a |= (*codep++ & 0xff) << 8; + a |= (*codep++ & 0xff) << 16; + a |= (*codep++ & 0xff) << 24; + b = *codep++ & 0xff; + b |= (*codep++ & 0xff) << 8; + b |= (*codep++ & 0xff) << 16; + b |= (*codep++ & 0xff) << 24; + x = a + ((bfd_vma) b << 32); +#else + abort (); + x = 0; +#endif + return x; +} + +static bfd_signed_vma get32 () { - int x = 0; + bfd_signed_vma x = 0; FETCH_DATA (the_info, codep + 4); - x = *codep++ & 0xff; - x |= (*codep++ & 0xff) << 8; - x |= (*codep++ & 0xff) << 16; - x |= (*codep++ & 0xff) << 24; - return (x); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + return x; +} + +static bfd_signed_vma +get32s () +{ + bfd_signed_vma x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & (bfd_signed_vma) 0xff; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; + x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; + + x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); + + return x; } static int @@ -1908,137 +3345,306 @@ get16 () FETCH_DATA (the_info, codep + 2); x = *codep++ & 0xff; x |= (*codep++ & 0xff) << 8; - return (x); + return x; } static void -set_op (op) - int op; +set_op (op, riprel) + bfd_vma op; + int riprel; { op_index[op_ad] = op_ad; - op_address[op_ad] = op; + if (mode_64bit) + { + op_address[op_ad] = op; + op_riprel[op_ad] = riprel; + } + else + { + /* Mask to get a 32-bit address. */ + op_address[op_ad] = op & 0xffffffff; + op_riprel[op_ad] = riprel & 0xffffffff; + } } -static int -OP_REG (code, aflag, dflag) +static void +OP_REG (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + int add = 0; + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + + switch (code) + { + case indir_dx_reg: + if (intel_syntax) + s = "[dx]"; + else + s = "(%dx)"; + break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg + add]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg + add]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg + add]; + else + s = names8[code - al_reg]; + break; + case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: + case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: + if (mode_64bit) + { + s = names64[code - rAX_reg + add]; + break; + } + code += eAX_reg - rAX_reg; + /* Fall through. */ + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + s = names64[code - eAX_reg + add]; + else if (sizeflag & DFLAG) + s = names32[code - eAX_reg + add]; + else + s = names16[code - eAX_reg + add]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_IMREG (code, sizeflag) int code; - int aflag; - int dflag; + int sizeflag; { - char *s; - - switch (code) + const char *s; + + switch (code) { - case indir_dx_reg: s = "(%dx)"; break; - case ax_reg: case cx_reg: case dx_reg: case bx_reg: - case sp_reg: case bp_reg: case si_reg: case di_reg: - s = names16[code - ax_reg]; - break; - case es_reg: case ss_reg: case cs_reg: - case ds_reg: case fs_reg: case gs_reg: - s = names_seg[code - es_reg]; - break; - case al_reg: case ah_reg: case cl_reg: case ch_reg: - case dl_reg: case dh_reg: case bl_reg: case bh_reg: - s = names8[code - al_reg]; - break; - case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: - case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: - if (dflag) + case indir_dx_reg: + if (intel_syntax) + s = "[dx]"; + else + s = "(%dx)"; + break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + USED_REX (0); + if (rex) + s = names8rex[code - al_reg]; + else + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + s = names64[code - eAX_reg]; + else if (sizeflag & DFLAG) s = names32[code - eAX_reg]; else s = names16[code - eAX_reg]; + used_prefixes |= (prefixes & PREFIX_DATA); break; default: - s = ""; + s = INTERNAL_DISASSEMBLER_ERROR; break; } oappend (s); - return (0); } -static int -OP_I (bytemode, aflag, dflag) +static void +OP_I (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + mask = 0xff; + break; + case q_mode: + if (mode_64bit) + { + op = get32s (); + break; + } + /* Fall through. */ + case v_mode: + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } + else + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + mask = 0xfffff; + op = get16 (); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; +} + +static void +OP_I64 (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - int op; - - switch (bytemode) + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + if (!mode_64bit) + { + OP_I (bytemode, sizeflag); + return; + } + + switch (bytemode) { case b_mode: FETCH_DATA (the_info, codep + 1); - op = *codep++ & 0xff; + op = *codep++; + mask = 0xff; break; case v_mode: - if (dflag) - op = get32 (); + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get64 (); + else if (sizeflag & DFLAG) + { + op = get32 (); + mask = 0xffffffff; + } else - op = get16 (); + { + op = get16 (); + mask = 0xfffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); break; case w_mode: + mask = 0xfffff; op = get16 (); break; default: - oappend (""); - return (0); + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; } - sprintf (scratchbuf, "$0x%x", op); - oappend (scratchbuf); - return (0); + + op &= mask; + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); + scratchbuf[0] = '\0'; } -static int -OP_sI (bytemode, aflag, dflag) +static void +OP_sI (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - int op; - - switch (bytemode) + bfd_signed_vma op; + bfd_signed_vma mask = -1; + + switch (bytemode) { case b_mode: FETCH_DATA (the_info, codep + 1); op = *codep++; if ((op & 0x80) != 0) op -= 0x100; + mask = 0xffffffff; break; case v_mode: - if (dflag) - op = get32 (); + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + op = get32s (); + else if (sizeflag & DFLAG) + { + op = get32s (); + mask = 0xffffffff; + } else { - op = get16(); + mask = 0xffffffff; + op = get16 (); if ((op & 0x8000) != 0) op -= 0x10000; } + used_prefixes |= (prefixes & PREFIX_DATA); break; case w_mode: op = get16 (); + mask = 0xffffffff; if ((op & 0x8000) != 0) op -= 0x10000; break; default: - oappend (""); - return (0); + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; } - sprintf (scratchbuf, "$0x%x", op); - oappend (scratchbuf); - return (0); + + scratchbuf[0] = '$'; + print_operand_value (scratchbuf + 1, 1, op); + oappend (scratchbuf + intel_syntax); } -static int -OP_J (bytemode, aflag, dflag) +static void +OP_J (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - int disp; - int mask = -1; - - switch (bytemode) + bfd_vma disp; + bfd_vma mask = -1; + + switch (bytemode) { case b_mode: FETCH_DATA (the_info, codep + 1); @@ -2047,131 +3653,160 @@ OP_J (bytemode, aflag, dflag) disp -= 0x100; break; case v_mode: - if (dflag) - disp = get32 (); + if (sizeflag & DFLAG) + disp = get32s (); else { disp = get16 (); - if ((disp & 0x8000) != 0) - disp -= 0x10000; - /* for some reason, a data16 prefix on a jump instruction + /* For some reason, a data16 prefix on a jump instruction means that the pc is masked to 16 bits after the displacement is added! */ mask = 0xffff; } break; default: - oappend (""); - return (0); + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; } disp = (start_pc + codep - start_codep + disp) & mask; - set_op (disp); - sprintf (scratchbuf, "0x%x", disp); + set_op (disp, 0); + print_operand_value (scratchbuf, 1, disp); oappend (scratchbuf); - return (0); } -/* ARGSUSED */ -static int -OP_SEG (dummy, aflag, dflag) +static void +OP_SEG (dummy, sizeflag) int dummy; - int aflag; - int dflag; + int sizeflag; { - static char *sreg[] = { - "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", - }; - - oappend (sreg[reg]); - return (0); + oappend (names_seg[reg]); } -static int -OP_DIR (size, aflag, dflag) - int size; - int aflag; - int dflag; +static void +OP_DIR (dummy, sizeflag) + int dummy; + int sizeflag; { int seg, offset; - - switch (size) + + if (sizeflag & DFLAG) { - case lptr: - if (aflag) - { - offset = get32 (); - seg = get16 (); - } - else - { - offset = get16 (); - seg = get16 (); - } - sprintf (scratchbuf, "0x%x,0x%x", seg, offset); - oappend (scratchbuf); - break; - case v_mode: - if (aflag) - offset = get32 (); - else - { - offset = get16 (); - if ((offset & 0x8000) != 0) - offset -= 0x10000; - } - - offset = start_pc + codep - start_codep + offset; - set_op (offset); - sprintf (scratchbuf, "0x%x", offset); - oappend (scratchbuf); - break; - default: - oappend (""); - break; + offset = get32 (); + seg = get16 (); } - return (0); + else + { + offset = get16 (); + seg = get16 (); + } + used_prefixes |= (prefixes & PREFIX_DATA); + if (intel_syntax) + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + else + sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); + oappend (scratchbuf); } -/* ARGSUSED */ -static int -OP_OFF (bytemode, aflag, dflag) +static void +OP_OFF (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - int off; + bfd_vma off; - append_prefix (); + append_seg (); - if (aflag) + if ((sizeflag & AFLAG) || mode_64bit) off = get32 (); else off = get16 (); - - sprintf (scratchbuf, "0x%x", off); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, 1, off); oappend (scratchbuf); - return (0); } -/* ARGSUSED */ -static int -OP_ESDI (dummy, aflag, dflag) - int dummy; - int aflag; - int dflag; +static void +OP_OFF64 (bytemode, sizeflag) + int bytemode; + int sizeflag; { - oappend ("%es:("); - oappend (aflag ? "%edi" : "%di"); - oappend (")"); - return (0); + bfd_vma off; + + if (!mode_64bit) + { + OP_OFF (bytemode, sizeflag); + return; + } + + append_seg (); + + off = get64 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[ds_reg - es_reg]); + oappend (":"); + } + } + print_operand_value (scratchbuf, 1, off); + oappend (scratchbuf); } -/* ARGSUSED */ -static int -OP_DSSI (dummy, aflag, dflag) - int dummy; - int aflag; - int dflag; +static void +ptr_reg (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + if (intel_syntax) + oappend ("["); + else + oappend ("("); + + USED_REX (REX_MODE64); + if (rex & REX_MODE64) + { + if (!(sizeflag & AFLAG)) + s = names32[code - eAX_reg]; + else + s = names64[code - eAX_reg]; + } + else if (sizeflag & AFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + oappend (s); + if (intel_syntax) + oappend ("]"); + else + oappend (")"); +} + +static void +OP_ESreg (code, sizeflag) + int code; + int sizeflag; +{ + oappend ("%es:" + intel_syntax); + ptr_reg (code, sizeflag); +} + +static void +OP_DSreg (code, sizeflag) + int code; + int sizeflag; { if ((prefixes & (PREFIX_CS @@ -2181,120 +3816,328 @@ OP_DSSI (dummy, aflag, dflag) | PREFIX_FS | PREFIX_GS)) == 0) prefixes |= PREFIX_DS; - append_prefix (); - oappend ("("); - oappend (aflag ? "%esi" : "%si"); - oappend (")"); - return (0); + append_seg (); + ptr_reg (code, sizeflag); } -#if 0 -/* Not used. */ - -/* ARGSUSED */ -static int -OP_ONE (dummy, aflag, dflag) +static void +OP_C (dummy, sizeflag) int dummy; - int aflag; - int dflag; + int sizeflag; { - oappend ("1"); - return (0); + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + sprintf (scratchbuf, "%%cr%d", reg + add); + oappend (scratchbuf + intel_syntax); } -#endif - -/* ARGSUSED */ -static int -OP_C (dummy, aflag, dflag) +static void +OP_D (dummy, sizeflag) int dummy; - int aflag; - int dflag; + int sizeflag; { - codep++; /* skip mod/rm */ - sprintf (scratchbuf, "%%cr%d", reg); + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + if (intel_syntax) + sprintf (scratchbuf, "db%d", reg + add); + else + sprintf (scratchbuf, "%%db%d", reg + add); oappend (scratchbuf); - return (0); } -/* ARGSUSED */ -static int -OP_D (dummy, aflag, dflag) +static void +OP_T (dummy, sizeflag) int dummy; - int aflag; - int dflag; + int sizeflag; { - codep++; /* skip mod/rm */ - sprintf (scratchbuf, "%%db%d", reg); - oappend (scratchbuf); - return (0); + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf + intel_syntax); } -/* ARGSUSED */ -static int -OP_T (dummy, aflag, dflag) - int dummy; - int aflag; - int dflag; +static void +OP_Rd (bytemode, sizeflag) + int bytemode; + int sizeflag; { - codep++; /* skip mod/rm */ - sprintf (scratchbuf, "%%tr%d", reg); - oappend (scratchbuf); - return (0); + if (mod == 3) + OP_E (bytemode, sizeflag); + else + BadOp (); } -static int -OP_rm (bytemode, aflag, dflag) +static void +OP_MMX (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - switch (bytemode) - { - case d_mode: - oappend (names32[rm]); - break; - case w_mode: - oappend (names16[rm]); - break; - } - return (0); + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + sprintf (scratchbuf, "%%xmm%d", reg + add); + else + sprintf (scratchbuf, "%%mm%d", reg + add); + oappend (scratchbuf + intel_syntax); } -static int -OP_MMX (bytemode, aflag, dflag) +static void +OP_XMM (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - sprintf (scratchbuf, "%%mm%d", reg); - oappend (scratchbuf); - return 0; + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + sprintf (scratchbuf, "%%xmm%d", reg + add); + oappend (scratchbuf + intel_syntax); } -static int -OP_EM (bytemode, aflag, dflag) +static void +OP_EM (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { + int add = 0; if (mod != 3) - return OP_E (bytemode, aflag, dflag); + { + OP_E (bytemode, sizeflag); + return; + } + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + /* Skip mod/rm byte. */ + MODRM_CHECK; codep++; - sprintf (scratchbuf, "%%mm%d", rm); - oappend (scratchbuf); - return 0; + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + sprintf (scratchbuf, "%%xmm%d", rm + add); + else + sprintf (scratchbuf, "%%mm%d", rm + add); + oappend (scratchbuf + intel_syntax); } -static int -OP_MS (bytemode, aflag, dflag) +static void +OP_EX (bytemode, sizeflag) int bytemode; - int aflag; - int dflag; + int sizeflag; { - ++codep; - sprintf (scratchbuf, "%%mm%d", rm); - oappend (scratchbuf); - return 0; + int add = 0; + if (mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + + /* Skip mod/rm byte. */ + MODRM_CHECK; + codep++; + sprintf (scratchbuf, "%%xmm%d", rm + add); + oappend (scratchbuf + intel_syntax); +} + +static void +OP_MS (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_EM (bytemode, sizeflag); + else + BadOp (); +} + +static void +OP_XS (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_EX (bytemode, sizeflag); + else + BadOp (); +} + +static const char *Suffix3DNow[] = { +/* 00 */ NULL, NULL, NULL, NULL, +/* 04 */ NULL, NULL, NULL, NULL, +/* 08 */ NULL, NULL, NULL, NULL, +/* 0C */ "pi2fw", "pi2fd", NULL, NULL, +/* 10 */ NULL, NULL, NULL, NULL, +/* 14 */ NULL, NULL, NULL, NULL, +/* 18 */ NULL, NULL, NULL, NULL, +/* 1C */ "pf2iw", "pf2id", NULL, NULL, +/* 20 */ NULL, NULL, NULL, NULL, +/* 24 */ NULL, NULL, NULL, NULL, +/* 28 */ NULL, NULL, NULL, NULL, +/* 2C */ NULL, NULL, NULL, NULL, +/* 30 */ NULL, NULL, NULL, NULL, +/* 34 */ NULL, NULL, NULL, NULL, +/* 38 */ NULL, NULL, NULL, NULL, +/* 3C */ NULL, NULL, NULL, NULL, +/* 40 */ NULL, NULL, NULL, NULL, +/* 44 */ NULL, NULL, NULL, NULL, +/* 48 */ NULL, NULL, NULL, NULL, +/* 4C */ NULL, NULL, NULL, NULL, +/* 50 */ NULL, NULL, NULL, NULL, +/* 54 */ NULL, NULL, NULL, NULL, +/* 58 */ NULL, NULL, NULL, NULL, +/* 5C */ NULL, NULL, NULL, NULL, +/* 60 */ NULL, NULL, NULL, NULL, +/* 64 */ NULL, NULL, NULL, NULL, +/* 68 */ NULL, NULL, NULL, NULL, +/* 6C */ NULL, NULL, NULL, NULL, +/* 70 */ NULL, NULL, NULL, NULL, +/* 74 */ NULL, NULL, NULL, NULL, +/* 78 */ NULL, NULL, NULL, NULL, +/* 7C */ NULL, NULL, NULL, NULL, +/* 80 */ NULL, NULL, NULL, NULL, +/* 84 */ NULL, NULL, NULL, NULL, +/* 88 */ NULL, NULL, "pfnacc", NULL, +/* 8C */ NULL, NULL, "pfpnacc", NULL, +/* 90 */ "pfcmpge", NULL, NULL, NULL, +/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", +/* 98 */ NULL, NULL, "pfsub", NULL, +/* 9C */ NULL, NULL, "pfadd", NULL, +/* A0 */ "pfcmpgt", NULL, NULL, NULL, +/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", +/* A8 */ NULL, NULL, "pfsubr", NULL, +/* AC */ NULL, NULL, "pfacc", NULL, +/* B0 */ "pfcmpeq", NULL, NULL, NULL, +/* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", +/* B8 */ NULL, NULL, NULL, "pswapd", +/* BC */ NULL, NULL, NULL, "pavgusb", +/* C0 */ NULL, NULL, NULL, NULL, +/* C4 */ NULL, NULL, NULL, NULL, +/* C8 */ NULL, NULL, NULL, NULL, +/* CC */ NULL, NULL, NULL, NULL, +/* D0 */ NULL, NULL, NULL, NULL, +/* D4 */ NULL, NULL, NULL, NULL, +/* D8 */ NULL, NULL, NULL, NULL, +/* DC */ NULL, NULL, NULL, NULL, +/* E0 */ NULL, NULL, NULL, NULL, +/* E4 */ NULL, NULL, NULL, NULL, +/* E8 */ NULL, NULL, NULL, NULL, +/* EC */ NULL, NULL, NULL, NULL, +/* F0 */ NULL, NULL, NULL, NULL, +/* F4 */ NULL, NULL, NULL, NULL, +/* F8 */ NULL, NULL, NULL, NULL, +/* FC */ NULL, NULL, NULL, NULL, +}; + +static void +OP_3DNowSuffix (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + const char *mnemonic; + + FETCH_DATA (the_info, codep + 1); + /* AMD 3DNow! instructions are specified by an opcode suffix in the + place where an 8-bit immediate would normally go. ie. the last + byte of the instruction. */ + obufp = obuf + strlen (obuf); + mnemonic = Suffix3DNow[*codep++ & 0xff]; + if (mnemonic) + oappend (mnemonic); + else + { + /* Since a variable sized modrm/sib chunk is between the start + of the opcode (0x0f0f) and the opcode suffix, we need to do + all the modrm processing first, and don't know until now that + we have a bad opcode. This necessitates some cleaning up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp (); + } +} + +static const char *simd_cmp_op[] = { + "eq", + "lt", + "le", + "unord", + "neq", + "nlt", + "nle", + "ord" +}; + +static void +OP_SIMD_Suffix (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + unsigned int cmp_type; + + FETCH_DATA (the_info, codep + 1); + obufp = obuf + strlen (obuf); + cmp_type = *codep++ & 0xff; + if (cmp_type < 8) + { + char suffix1 = 'p', suffix2 = 's'; + used_prefixes |= (prefixes & PREFIX_REPZ); + if (prefixes & PREFIX_REPZ) + suffix1 = 's'; + else + { + used_prefixes |= (prefixes & PREFIX_DATA); + if (prefixes & PREFIX_DATA) + suffix2 = 'd'; + else + { + used_prefixes |= (prefixes & PREFIX_REPNZ); + if (prefixes & PREFIX_REPNZ) + suffix1 = 's', suffix2 = 'd'; + } + } + sprintf (scratchbuf, "cmp%s%c%c", + simd_cmp_op[cmp_type], suffix1, suffix2); + used_prefixes |= (prefixes & PREFIX_REPZ); + oappend (scratchbuf); + } + else + { + /* We have a bad extension byte. Clean up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp (); + } +} + +static void +SIMD_Fixup (extrachar, sizeflag) + int extrachar; + int sizeflag; +{ + /* Change movlps/movhps to movhlps/movlhps for 2 register operand + forms of these instructions. */ + if (mod == 3) + { + char *p = obuf + strlen (obuf); + *(p + 1) = '\0'; + *p = *(p - 1); + *(p - 1) = *(p - 2); + *(p - 2) = *(p - 3); + *(p - 3) = extrachar; + } +} + +static void +BadOp (void) +{ + /* Throw away prefixes and 1st. opcode byte. */ + codep = insn_codep + 1; + oappend ("(bad)"); } diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 0c2fe8dc1..4f937443e 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -188,7 +188,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, host_start = start & host_page_mask; if (!(flags & MAP_FIXED)) { -#if defined(__alpha__) || defined(__sparc__) +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) /* tell the kenel to search at the same place as i386 */ if (host_start == 0) host_start = 0x40000000; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0abe68503..f8b48d588 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -207,7 +207,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo -#if defined(__alpha__) || defined (__ia64__) +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek #endif diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 84b202659..1cabbe42c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -252,7 +252,7 @@ enum { CC_OP_NB, }; -#ifdef __i386__ +#if defined(__i386__) || defined(__x86_64__) #define USE_X86LDOUBLE #endif diff --git a/target-i386/helper.c b/target-i386/helper.c index 0c320836c..9bd1158b0 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1802,14 +1802,14 @@ void helper_invlpg(unsigned int addr) } /* rdtsc */ -#ifndef __i386__ +#if !defined(__i386__) && !defined(__x86_64__) uint64_t emu_time; #endif void helper_rdtsc(void) { uint64_t val; -#ifdef __i386__ +#if defined(__i386__) || defined(__x86_64__) asm("rdtsc" : "=A" (val)); #else /* better than nothing: the time increases */ -- cgit v1.2.3 From baca51faff03df59386c95d9478ede18b5be5ec8 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 19 Mar 2004 23:05:34 +0000 Subject: updated floppy driver: formatting code, disk geometry auto detect (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@671 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 1473 +++++++++++++++++++++++++++++++++++++++----------------------- hw/pc.c | 7 +- vl.h | 9 +- 3 files changed, 944 insertions(+), 545 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index d3c885401..97ac51c40 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -54,7 +54,8 @@ typedef enum fdisk_type_t { FDRIVE_DISK_288 = 0x01, /* 2.88 MB disk */ FDRIVE_DISK_144 = 0x02, /* 1.44 MB disk */ FDRIVE_DISK_720 = 0x03, /* 720 kB disk */ - FDRIVE_DISK_NONE = 0x04, /* No disk */ + FDRIVE_DISK_USER = 0x04, /* User defined geometry */ + FDRIVE_DISK_NONE = 0x05, /* No disk */ } fdisk_type_t; typedef enum fdrive_type_t { @@ -64,13 +65,21 @@ typedef enum fdrive_type_t { FDRIVE_DRV_NONE = 0x03, /* No drive connected */ } fdrive_type_t; +typedef enum fdrive_flags_t { + FDRIVE_MOTOR_ON = 0x01, /* motor on/off */ + FDRIVE_REVALIDATE = 0x02, /* Revalidated */ +} fdrive_flags_t; + +typedef enum fdisk_flags_t { + FDISK_DBL_SIDES = 0x01, +} fdisk_flags_t; + typedef struct fdrive_t { BlockDriverState *bs; /* Drive status */ fdrive_type_t drive; - uint8_t motor; /* on/off */ + fdrive_flags_t drflags; uint8_t perpendicular; /* 2.88 MB access mode */ - uint8_t rv; /* Revalidated */ /* Position */ uint8_t head; uint8_t track; @@ -80,8 +89,10 @@ typedef struct fdrive_t { uint8_t rw; /* Read/write */ /* Media */ fdisk_type_t disk; /* Disk type */ + fdisk_flags_t flags; uint8_t last_sect; /* Nb sector per track */ uint8_t max_track; /* Nb of tracks */ + uint16_t bps; /* Bytes per sector */ uint8_t ro; /* Is read-only */ } fdrive_t; @@ -93,12 +104,11 @@ static void fd_init (fdrive_t *drv, BlockDriverState *bs) drv->drive = FDRIVE_DRV_144; else drv->drive = FDRIVE_DRV_NONE; - drv->motor = 0; + drv->drflags = 0; drv->perpendicular = 0; - drv->rv = 0; /* Disk */ drv->disk = FDRIVE_DISK_NONE; - drv->last_sect = 1; + drv->last_sect = 0; drv->max_track = 0; } @@ -118,18 +128,25 @@ static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect, int enable_seek) { uint32_t sector; - - if (track > drv->max_track) { - FLOPPY_ERROR("try to read %d %02x %02x (max=%d %02x %02x)\n", - head, track, sect, 1, drv->max_track, drv->last_sect); + int ret; + + if (track > drv->max_track || + (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) { + FLOPPY_ERROR("try to read %d %02x %02x (max=%d %d %02x %02x)\n", + head, track, sect, 1, + (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, + drv->max_track, drv->last_sect); return 2; } if (sect > drv->last_sect) { - FLOPPY_ERROR("try to read %d %02x %02x (max=%d %02x %02x)\n", - head, track, sect, 1, drv->max_track, drv->last_sect); + FLOPPY_ERROR("try to read %d %02x %02x (max=%d %d %02x %02x)\n", + head, track, sect, 1, + (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, + drv->max_track, drv->last_sect); return 3; } sector = _fd_sector(head, track, sect, drv->last_sect); + ret = 0; if (sector != fd_sector(drv)) { #if 0 if (!enable_seek) { @@ -139,12 +156,13 @@ static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect, } #endif drv->head = head; + if (drv->track != track) + ret = 1; drv->track = track; drv->sect = sect; - return 1; } - return 0; + return ret; } /* Set drive back to track 0 */ @@ -162,60 +180,275 @@ static void fd_recalibrate (fdrive_t *drv) static void fd_revalidate (fdrive_t *drv) { int64_t nb_sectors; + int nb_heads, max_track, last_sect, ro; FLOPPY_DPRINTF("revalidate\n"); - drv->rv = 0; + drv->drflags &= ~FDRIVE_REVALIDATE; + /* if no drive present, cannot do more */ if (!drv->bs) return; - + if (bdrv_is_inserted(drv->bs)) { + ro = bdrv_is_read_only(drv->bs); + bdrv_get_geometry_hint(drv->bs, &max_track, &nb_heads, &last_sect); + if (nb_heads != 0 && max_track != 0 && last_sect != 0) { + drv->disk = FDRIVE_DISK_USER; + printf("User defined disk (%d %d %d)", + nb_heads - 1, max_track, last_sect); + if (nb_heads == 1) { + drv->flags &= ~FDISK_DBL_SIDES; + } else { + drv->flags |= FDISK_DBL_SIDES; + } + drv->max_track = max_track; + drv->last_sect = last_sect; + } else { bdrv_get_geometry(drv->bs, &nb_sectors); -#if 1 - if (nb_sectors > 2880) -#endif - { - /* Pretend we have a 2.88 MB disk */ + switch (nb_sectors) { + /* 2.88 MB 3"1/2 drive disks */ + case 7680: + printf("3.84 Mb 3\"1/2 disk (1 80 48)"); + drv->drive = FDRIVE_DRV_288; + drv->disk = FDRIVE_DISK_288; + drv->last_sect = 48; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 7040: + printf("3.52 Mb 3\"1/2 disk (1 80 44)"); + drv->drive = FDRIVE_DRV_288; + drv->disk = FDRIVE_DISK_288; + drv->last_sect = 44; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 6400: + printf("3.2 Mb 3\"1/2 disk (1 80 40)"); + drv->drive = FDRIVE_DRV_288; + drv->disk = FDRIVE_DISK_288; + drv->last_sect = 40; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 6240: + printf("3.12 Mb 3\"1/2 disk (1 80 39)"); + drv->drive = FDRIVE_DRV_288; + drv->disk = FDRIVE_DISK_288; + drv->last_sect = 39; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 5760: + printf("2.88 Mb 3\"1/2 disk (1 80 36)"); + drv->drive = FDRIVE_DRV_288; drv->disk = FDRIVE_DISK_288; drv->last_sect = 36; drv->max_track = 80; -#if 1 - } else if (nb_sectors > 1440) { - /* Pretend we have a 1.44 MB disk */ + drv->flags |= FDISK_DBL_SIDES; + break; + + /* 1.44 MB 3"1/2 drive disks */ + case 3840: + printf("1.92 Mb 3\"1/2 disk (1 80 24)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_144; + drv->last_sect = 24; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 3680: + printf("1.84 Mb 3\"1/2 disk (1 80 23)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_144; + drv->last_sect = 23; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 3520: + printf("1.76 Mb 3\"1/2 disk (1 80 22)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_144; + drv->last_sect = 22; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 3486: + printf("1.74 Mb 3\"1/2 disk (1 83 21)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_144; + drv->last_sect = 21; + drv->max_track = 83; + drv->flags |= FDISK_DBL_SIDES; + break; + case 3444: + printf("1.72 Mb 3\"1/2 disk (1 82 21)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_144; + drv->last_sect = 21; + drv->max_track = 82; + drv->flags |= FDISK_DBL_SIDES; + break; + case 3360: + printf("1.68 Mb 3\"1/2 disk (1 80 21)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_144; + drv->last_sect = 21; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 3200: + printf("1.6 Mb 3\"1/2 disk (1 80 20)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_144; + drv->last_sect = 20; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 2880: + default: + printf("1.44 Mb 3\"1/2 disk (1 80 18)"); + drv->drive = FDRIVE_DRV_144; drv->disk = FDRIVE_DISK_144; drv->last_sect = 18; drv->max_track = 80; - } else { - /* Pretend we have a 720 kB disk */ + drv->flags |= FDISK_DBL_SIDES; + break; + + /* 720 kB 3"1/2 drive disks */ + case 2240: + printf("1.12 Mb 3\"1/2 disk (1 80 14)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_720; + drv->last_sect = 14; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 2080: + printf("1.04 Mb 3\"1/2 disk (1 80 13)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_720; + drv->last_sect = 13; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 1660: + printf("830 kb 3\"1/2 disk (1 83 10)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_720; + drv->last_sect = 10; + drv->max_track = 83; + drv->flags |= FDISK_DBL_SIDES; + break; + case 1640: + printf("820 kb 3\"1/2 disk (1 82 10)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_720; + drv->last_sect = 10; + drv->max_track = 82; + drv->flags |= FDISK_DBL_SIDES; + break; + case 1600: + printf("800 kb 3\"1/2 disk (1 80 10)"); + drv->drive = FDRIVE_DRV_144; + drv->disk = FDRIVE_DISK_720; + drv->last_sect = 10; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + case 1440: + printf("720 kb 3\"1/2 disk (1 80 9)"); + drv->drive = FDRIVE_DRV_144; drv->disk = FDRIVE_DISK_720; drv->last_sect = 9; drv->max_track = 80; -#endif + drv->flags |= FDISK_DBL_SIDES; + break; + + /* 1.2 MB 5"1/4 drive disks */ + case 2988: + printf("1.49 Mb 5\"1/4 disk (1 83 18)"); + drv->drive = FDRIVE_DRV_120; + drv->disk = FDRIVE_DISK_144; /* ? */ + drv->last_sect = 18; + drv->max_track = 83; + drv->flags |= FDISK_DBL_SIDES; + break; + case 2952: + printf("1.48 Mb 5\"1/4 disk (1 82 18)"); + drv->drive = FDRIVE_DRV_120; + drv->disk = FDRIVE_DISK_144; /* ? */ + drv->last_sect = 18; + drv->max_track = 82; + drv->flags |= FDISK_DBL_SIDES; + break; + case 2400: + printf("1.2 Mb 5\"1/4 disk (1 80 15)"); + drv->drive = FDRIVE_DRV_120; + drv->disk = FDRIVE_DISK_144; /* ? */ + drv->last_sect = 15; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + + case 1760: + printf("880 kb 5\"1/4 disk (1 80 11)"); + drv->drive = FDRIVE_DRV_120; + drv->disk = FDRIVE_DISK_144; /* ? */ + drv->last_sect = 11; + drv->max_track = 80; + drv->flags |= FDISK_DBL_SIDES; + break; + + /* 360 kB 5"1/4 drive disks */ + case 840: + /* 420 kB 5"1/4 disk */ + printf("420 kb 5\"1/4 disk (1 42 10)"); + drv->drive = FDRIVE_DRV_120; + drv->disk = FDRIVE_DISK_144; /* ? */ + drv->last_sect = 10; + drv->max_track = 42; + drv->flags |= FDISK_DBL_SIDES; + case 820: + /* 410 kB 5"1/4 disk */ + printf("410 kb 5\"1/4 disk (1 41 10)"); + drv->drive = FDRIVE_DRV_120; + drv->disk = FDRIVE_DISK_144; /* ? */ + drv->last_sect = 10; + drv->max_track = 41; + drv->flags |= FDISK_DBL_SIDES; + case 720: + /* 360 kB 5"1/4 disk */ + printf("360 kb 5\"1/4 disk (1 40 9)"); + drv->drive = FDRIVE_DRV_120; + drv->disk = FDRIVE_DISK_144; /* ? */ + drv->last_sect = 9; + drv->max_track = 40; + drv->flags |= FDISK_DBL_SIDES; + break; } - drv->ro = bdrv_is_read_only(drv->bs); + printf(" %s\n", ro == 0 ? "rw" : "ro"); + } + drv->ro = ro; } else { + printf("No disk in drive\n"); drv->disk = FDRIVE_DISK_NONE; - drv->last_sect = 1; /* Avoid eventual divide by 0 bugs */ - drv->ro = 0; + drv->last_sect = 0; + drv->max_track = 0; + drv->flags &= ~FDISK_DBL_SIDES; } - drv->rv = 1; -} - -static void fd_change_cb (void *opaque) -{ - fdrive_t *drv = opaque; - fd_revalidate(drv); + drv->drflags |= FDRIVE_REVALIDATE; } /* Motor control */ static void fd_start (fdrive_t *drv) { - drv->motor = 1; + drv->drflags |= FDRIVE_MOTOR_ON; } static void fd_stop (fdrive_t *drv) { - drv->motor = 0; + drv->drflags &= ~FDRIVE_MOTOR_ON; } /* Re-initialise a drives (motor off, repositioned) */ @@ -228,21 +461,21 @@ static void fd_reset (fdrive_t *drv) /********************************************************/ /* Intel 82078 floppy disk controler emulation */ -static void fdctrl_reset (int do_irq); -static void fdctrl_reset_fifo (void); +static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq); +static void fdctrl_reset_fifo (fdctrl_t *fdctrl); static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size); -static void fdctrl_raise_irq (uint8_t status); - -static uint32_t fdctrl_read_statusB (void *opaque, uint32_t reg); -static uint32_t fdctrl_read_dor (void *opaque, uint32_t reg); -static void fdctrl_write_dor (void *opaque, uint32_t reg, uint32_t value); -static uint32_t fdctrl_read_tape (void *opaque, uint32_t reg); -static void fdctrl_write_tape (void *opaque, uint32_t reg, uint32_t value); -static uint32_t fdctrl_read_main_status (void *opaque, uint32_t reg); -static void fdctrl_write_rate (void *opaque, uint32_t reg, uint32_t value); -static uint32_t fdctrl_read_data (void *opaque, uint32_t reg); -static void fdctrl_write_data (void *opaque, uint32_t reg, uint32_t value); -static uint32_t fdctrl_read_dir (void *opaque, uint32_t reg); +static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status); + +static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl); +static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl); +static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value); +static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl); +static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value); +static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl); +static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value); +static uint32_t fdctrl_read_data (fdctrl_t *fdctrl); +static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value); +static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl); enum { FD_CTRL_ACTIVE = 0x01, @@ -267,18 +500,24 @@ enum { FD_STATE_STATE = 0x03, FD_STATE_MULTI = 0x10, FD_STATE_SEEK = 0x20, + FD_STATE_FORMAT = 0x40, }; #define FD_STATE(state) ((state) & FD_STATE_STATE) +#define FD_SET_STATE(state, new_state) \ +do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0) #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI) #define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK) +#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT) -typedef struct fdctrl_t { +struct fdctrl_t { + fdctrl_t *fdctrl; /* Controler's identification */ uint8_t version; /* HW */ int irq_lvl; int dma_chann; + uint32_t io_base; /* Controler state */ uint8_t state; uint8_t dma_en; @@ -303,35 +542,91 @@ typedef struct fdctrl_t { uint8_t pwrd; /* Floppy drives */ fdrive_t drives[2]; -} fdctrl_t; +}; + +static uint32_t fdctrl_read (void *opaque, uint32_t reg) +{ + fdctrl_t *fdctrl = opaque; + uint32_t retval; + + if (reg == fdctrl->io_base + 0x01) + retval = fdctrl_read_statusB(fdctrl); + else if (reg == fdctrl->io_base + 0x02) + retval = fdctrl_read_dor(fdctrl); + else if (reg == fdctrl->io_base + 0x03) + retval = fdctrl_read_tape(fdctrl); + else if (reg == fdctrl->io_base + 0x04) + retval = fdctrl_read_main_status(fdctrl); + else if (reg == fdctrl->io_base + 0x05) + retval = fdctrl_read_data(fdctrl); + else if (reg == fdctrl->io_base + 0x07) + retval = fdctrl_read_dir(fdctrl); + else + retval = (uint32_t)(-1); + + return retval; +} + +static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) +{ + fdctrl_t *fdctrl = opaque; + + if (reg == fdctrl->io_base + 0x02) + fdctrl_write_dor(fdctrl, value); + else if (reg == fdctrl->io_base + 0x03) + fdctrl_write_tape(fdctrl, value); + else if (reg == fdctrl->io_base + 0x04) + fdctrl_write_rate(fdctrl, value); + else if (reg == fdctrl->io_base + 0x05) + fdctrl_write_data(fdctrl, value); +} + +static void fd_change_cb (void *opaque) +{ + fdrive_t *drv = opaque; -static fdctrl_t fdctrl; + FLOPPY_DPRINTF("disk change\n"); + /* TODO: use command-line parameters to force geometry */ + fd_revalidate(drv); +#if 0 + fd_recalibrate(drv); + fdctrl_reset_fifo(drv->fdctrl); + fdctrl_raise_irq(drv->fdctrl, 0x20); +#endif +} -void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, - BlockDriverState **fds) +fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, + uint32_t io_base, + BlockDriverState **fds) { + fdctrl_t *fdctrl; // int io_mem; int i; FLOPPY_DPRINTF("init controler\n"); - memset(&fdctrl, 0, sizeof(fdctrl)); - fdctrl.version = 0x90; /* Intel 82078 controler */ - fdctrl.irq_lvl = irq_lvl; - fdctrl.dma_chann = dma_chann; - fdctrl.config = 0x40; /* Implicit seek, polling & FIFO enabled */ - if (fdctrl.dma_chann != -1) { - fdctrl.dma_en = 1; - DMA_register_channel(dma_chann, fdctrl_transfer_handler, &fdctrl); + fdctrl = qemu_mallocz(sizeof(fdctrl_t)); + if (!fdctrl) + return NULL; + fdctrl->version = 0x90; /* Intel 82078 controler */ + fdctrl->irq_lvl = irq_lvl; + fdctrl->dma_chann = dma_chann; + fdctrl->io_base = io_base; + fdctrl->config = 0x40; /* Implicit seek, polling & FIFO enabled */ + if (fdctrl->dma_chann != -1) { + fdctrl->dma_en = 1; + DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl); } else { - fdctrl.dma_en = 0; + fdctrl->dma_en = 0; } - for (i = 0; i < MAX_FD; i++) { - fd_init(&fdctrl.drives[i], fds[i]); - if (fds[i]) - bdrv_set_change_cb(fds[i], fd_change_cb, &fdctrl.drives[i]); + for (i = 0; i < 2; i++) { + fd_init(&fdctrl->drives[i], fds[i]); + if (fds[i]) { + bdrv_set_change_cb(fds[i], + &fd_change_cb, &fdctrl->drives[i]); + } } - fdctrl_reset(0); - fdctrl.state = FD_CTRL_ACTIVE; + fdctrl_reset(fdctrl, 0); + fdctrl->state = FD_CTRL_ACTIVE; if (mem_mapped) { FLOPPY_ERROR("memory mapped floppy not supported by now !\n"); #if 0 @@ -339,110 +634,113 @@ void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, cpu_register_physical_memory(base, 0x08, io_mem); #endif } else { - register_ioport_read(base + 0x01, 1, 1, fdctrl_read_statusB, NULL); - register_ioport_read(base + 0x02, 1, 1, fdctrl_read_dor, NULL); - register_ioport_write(base + 0x02, 1, 1, fdctrl_write_dor, NULL); - register_ioport_read(base + 0x03, 1, 1, fdctrl_read_tape, NULL); - register_ioport_write(base + 0x03, 1, 1, fdctrl_write_tape, NULL); - register_ioport_read(base + 0x04, 1, 1, fdctrl_read_main_status, NULL); - register_ioport_write(base + 0x04, 1, 1, fdctrl_write_rate, NULL); - register_ioport_read(base + 0x05, 1, 1, fdctrl_read_data, NULL); - register_ioport_write(base + 0x05, 1, 1, fdctrl_write_data, NULL); - register_ioport_read(base + 0x07, 1, 1, fdctrl_read_dir, NULL); + register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl); + register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl); + register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl); + register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl); } - fdctrl.bootsel = 0; - for (i = 0; i < MAX_FD; i++) { - fd_revalidate(&fdctrl.drives[i]); + fd_revalidate(&fdctrl->drives[i]); } + return fdctrl; } -int fdctrl_get_drive_type(int drive_num) +/* XXX: may change if moved to bdrv */ +int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num) { - return fdctrl.drives[drive_num].drive; + return fdctrl->drives[drive_num].drive; } /* Change IRQ state */ -static void fdctrl_reset_irq (void) +static void fdctrl_reset_irq (fdctrl_t *fdctrl) { - if (fdctrl.state & FD_CTRL_INTR) { - pic_set_irq(fdctrl.irq_lvl, 0); - fdctrl.state &= ~(FD_CTRL_INTR | FD_CTRL_SLEEP | FD_CTRL_BUSY); + if (fdctrl->state & FD_CTRL_INTR) { + pic_set_irq(fdctrl->irq_lvl, 0); + fdctrl->state &= ~(FD_CTRL_INTR | FD_CTRL_SLEEP | FD_CTRL_BUSY); } } -static void fdctrl_raise_irq (uint8_t status) +static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) { - if (~(fdctrl.state & FD_CTRL_INTR)) { - pic_set_irq(fdctrl.irq_lvl, 1); - fdctrl.state |= FD_CTRL_INTR; + if (~(fdctrl->state & FD_CTRL_INTR)) { + pic_set_irq(fdctrl->irq_lvl, 1); + fdctrl->state |= FD_CTRL_INTR; } FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status); - fdctrl.int_status = status; + fdctrl->int_status = status; } /* Reset controler */ -static void fdctrl_reset (int do_irq) +static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq) { int i; FLOPPY_DPRINTF("reset controler\n"); - fdctrl_reset_irq(); + fdctrl_reset_irq(fdctrl); /* Initialise controler */ - fdctrl.cur_drv = 0; + fdctrl->cur_drv = 0; /* FIFO state */ - fdctrl.data_pos = 0; - fdctrl.data_len = 0; - fdctrl.data_state = FD_STATE_CMD; - fdctrl.data_dir = FD_DIR_WRITE; + fdctrl->data_pos = 0; + fdctrl->data_len = 0; + fdctrl->data_state = FD_STATE_CMD; + fdctrl->data_dir = FD_DIR_WRITE; for (i = 0; i < MAX_FD; i++) - fd_reset(&fdctrl.drives[i]); - fdctrl_reset_fifo(); + fd_reset(&fdctrl->drives[i]); + fdctrl_reset_fifo(fdctrl); if (do_irq) - fdctrl_raise_irq(0x20); + fdctrl_raise_irq(fdctrl, 0x20); +} + +static inline fdrive_t *drv0 (fdctrl_t *fdctrl) +{ + return &fdctrl->drives[fdctrl->bootsel]; +} + +static inline fdrive_t *drv1 (fdctrl_t *fdctrl) +{ + return &fdctrl->drives[1 - fdctrl->bootsel]; +} + +static fdrive_t *get_cur_drv (fdctrl_t *fdctrl) +{ + return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl); } /* Status B register : 0x01 (read-only) */ -static uint32_t fdctrl_read_statusB (void *opaque, uint32_t reg) +static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl) { - fdctrl_reset_irq(); + fdctrl_reset_irq(fdctrl); FLOPPY_DPRINTF("status register: 0x00\n"); return 0; } /* Digital output register : 0x02 */ -static uint32_t fdctrl_read_dor (void *opaque, uint32_t reg) +static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl) { - fdrive_t *cur_drv, *drv0, *drv1; uint32_t retval = 0; - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; /* Drive motors state indicators */ - retval |= drv1->motor << 5; - retval |= drv0->motor << 4; + if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON) + retval |= 1 << 5; + if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON) + retval |= 1 << 4; /* DMA enable */ - retval |= fdctrl.dma_en << 3; + retval |= fdctrl->dma_en << 3; /* Reset indicator */ - retval |= (fdctrl.state & FD_CTRL_RESET) == 0 ? 0x04 : 0; + retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0; /* Selected drive */ - retval |= fdctrl.cur_drv; + retval |= fdctrl->cur_drv; FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval); return retval; } -static void fdctrl_write_dor (void *opaque, uint32_t reg, uint32_t value) +static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) { - fdrive_t *drv0, *drv1; - - fdctrl_reset_irq(); - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; + fdctrl_reset_irq(fdctrl); /* Reset mode */ - if (fdctrl.state & FD_CTRL_RESET) { + if (fdctrl->state & FD_CTRL_RESET) { if (!(value & 0x04)) { FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); return; @@ -451,81 +749,81 @@ static void fdctrl_write_dor (void *opaque, uint32_t reg, uint32_t value) FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value); /* Drive motors state indicators */ if (value & 0x20) - fd_start(drv1); + fd_start(drv1(fdctrl)); else - fd_stop(drv1); + fd_stop(drv1(fdctrl)); if (value & 0x10) - fd_start(drv0); + fd_start(drv0(fdctrl)); else - fd_stop(drv0); + fd_stop(drv0(fdctrl)); /* DMA enable */ #if 0 - if (fdctrl.dma_chann != -1) - fdctrl.dma_en = 1 - ((value >> 3) & 1); + if (fdctrl->dma_chann != -1) + fdctrl->dma_en = 1 - ((value >> 3) & 1); #endif /* Reset */ if (!(value & 0x04)) { - if (!(fdctrl.state & FD_CTRL_RESET)) { + if (!(fdctrl->state & FD_CTRL_RESET)) { FLOPPY_DPRINTF("controler enter RESET state\n"); - fdctrl.state |= FD_CTRL_RESET; - fdctrl_reset(1); + fdctrl->state |= FD_CTRL_RESET; + fdctrl_reset(fdctrl, 1); } } else { - if (fdctrl.state & FD_CTRL_RESET) { + if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("controler out of RESET state\n"); - fdctrl.state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); + fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); } } /* Selected drive */ - fdctrl.cur_drv = value & 1; + fdctrl->cur_drv = value & 1; } /* Tape drive register : 0x03 */ -static uint32_t fdctrl_read_tape (void *opaque, uint32_t reg) +static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl) { uint32_t retval = 0; - fdctrl_reset_irq(); + fdctrl_reset_irq(fdctrl); /* Disk boot selection indicator */ - retval |= fdctrl.bootsel << 2; + retval |= fdctrl->bootsel << 2; /* Tape indicators: never allowed */ FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval); return retval; } -static void fdctrl_write_tape (void *opaque, uint32_t reg, uint32_t value) +static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value) { - fdctrl_reset_irq(); + fdctrl_reset_irq(fdctrl); /* Reset mode */ - if (fdctrl.state & FD_CTRL_RESET) { + if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); return; } FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value); /* Disk boot selection indicator */ - fdctrl.bootsel = (value >> 2) & 1; + fdctrl->bootsel = (value >> 2) & 1; /* Tape indicators: never allow */ } /* Main status register : 0x04 (read) */ -static uint32_t fdctrl_read_main_status (void *opaque, uint32_t reg) +static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl) { uint32_t retval = 0; - fdctrl_reset_irq(); - fdctrl.state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET); - if (!(fdctrl.state & FD_CTRL_BUSY)) { + fdctrl_reset_irq(fdctrl); + fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET); + if (!(fdctrl->state & FD_CTRL_BUSY)) { /* Data transfer allowed */ retval |= 0x80; /* Data transfer direction indicator */ - if (fdctrl.data_dir == FD_DIR_READ) + if (fdctrl->data_dir == FD_DIR_READ) retval |= 0x40; } /* Should handle 0x20 for SPECIFY command */ /* Command busy indicator */ - if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA || - FD_STATE(fdctrl.data_state) == FD_STATE_STATUS) + if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA || + FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) retval |= 0x10; FLOPPY_DPRINTF("main status register: 0x%02x\n", retval); @@ -533,150 +831,142 @@ static uint32_t fdctrl_read_main_status (void *opaque, uint32_t reg) } /* Data select rate register : 0x04 (write) */ -static void fdctrl_write_rate (void *opaque, uint32_t reg, uint32_t value) +static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) { - fdctrl_reset_irq(); + fdctrl_reset_irq(fdctrl); /* Reset mode */ - if (fdctrl.state & FD_CTRL_RESET) { - if (reg != 0x2 || !(value & 0x04)) { + if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); return; } - } FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); /* Reset: autoclear */ if (value & 0x80) { - fdctrl.state |= FD_CTRL_RESET; - fdctrl_reset(1); - fdctrl.state &= ~FD_CTRL_RESET; + fdctrl->state |= FD_CTRL_RESET; + fdctrl_reset(fdctrl, 1); + fdctrl->state &= ~FD_CTRL_RESET; } if (value & 0x40) { - fdctrl.state |= FD_CTRL_SLEEP; - fdctrl_reset(1); + fdctrl->state |= FD_CTRL_SLEEP; + fdctrl_reset(fdctrl, 1); } // fdctrl.precomp = (value >> 2) & 0x07; } /* Digital input register : 0x07 (read-only) */ -static uint32_t fdctrl_read_dir (void *opaque, uint32_t reg) +static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl) { - fdrive_t *drv0, *drv1; uint32_t retval = 0; - fdctrl_reset_irq(); - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; - if (drv0->rv || drv1->rv) + fdctrl_reset_irq(fdctrl); + if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE || + drv1(fdctrl)->drflags & FDRIVE_REVALIDATE) retval |= 0x80; if (retval != 0) - FLOPPY_ERROR("Floppy digital input register: 0x%02x\n", retval); - drv0->rv = 0; - drv1->rv = 0; + FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval); + drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE; + drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE; return retval; } /* FIFO state control */ -static void fdctrl_reset_fifo (void) +static void fdctrl_reset_fifo (fdctrl_t *fdctrl) { - fdctrl.data_dir = FD_DIR_WRITE; - fdctrl.data_pos = 0; - fdctrl.data_state = FD_STATE_CMD; + fdctrl->data_dir = FD_DIR_WRITE; + fdctrl->data_pos = 0; + FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD); } /* Set FIFO status for the host to read */ -static void fdctrl_set_fifo (int fifo_len, int do_irq) +static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq) { - fdctrl.data_dir = FD_DIR_READ; - fdctrl.data_len = fifo_len; - fdctrl.data_pos = 0; - fdctrl.data_state = FD_STATE_STATUS; + fdctrl->data_dir = FD_DIR_READ; + fdctrl->data_len = fifo_len; + fdctrl->data_pos = 0; + FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS); if (do_irq) - fdctrl_raise_irq(0x00); + fdctrl_raise_irq(fdctrl, 0x00); } /* Set an error: unimplemented/unknown command */ -static void fdctrl_unimplemented (void) +static void fdctrl_unimplemented (fdctrl_t *fdctrl) { #if 0 - fdrive_t *cur_drv, *drv0, *drv1; - - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; - fdctrl.fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl.cur_drv; - fdctrl.fifo[1] = 0x00; - fdctrl.fifo[2] = 0x00; - fdctrl_set_fifo(3, 1); + fdrive_t *cur_drv; + + cur_drv = get_cur_drv(fdctrl); + fdctrl->fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl->cur_drv; + fdctrl->fifo[1] = 0x00; + fdctrl->fifo[2] = 0x00; + fdctrl_set_fifo(fdctrl, 3, 1); #else - fdctrl_reset_fifo(); + // fdctrl_reset_fifo(fdctrl); + fdctrl->fifo[0] = 0x80; + fdctrl_set_fifo(fdctrl, 1, 0); #endif } /* Callback for transfer end (stop or abort) */ -static void fdctrl_stop_transfer (uint8_t status0, uint8_t status1, - uint8_t status2) +static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, + uint8_t status1, uint8_t status2) { - fdrive_t *cur_drv, *drv0, *drv1; + fdrive_t *cur_drv; - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + cur_drv = get_cur_drv(fdctrl); FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", status0, status1, status2, - status0 | (cur_drv->head << 1) | fdctrl.cur_drv); - fdctrl.fifo[0] = status0 | (cur_drv->head << 1) | fdctrl.cur_drv; - fdctrl.fifo[1] = status1; - fdctrl.fifo[2] = status2; - fdctrl.fifo[3] = cur_drv->track; - fdctrl.fifo[4] = cur_drv->head; - fdctrl.fifo[5] = cur_drv->sect; - fdctrl.fifo[6] = FD_SECTOR_SC; - fdctrl.data_dir = FD_DIR_READ; - if (fdctrl.state & FD_CTRL_BUSY) - DMA_release_DREQ(fdctrl.dma_chann); - fdctrl_set_fifo(7, 1); + status0 | (cur_drv->head << 1) | fdctrl->cur_drv); + fdctrl->fifo[0] = status0 | (cur_drv->head << 1) | fdctrl->cur_drv; + fdctrl->fifo[1] = status1; + fdctrl->fifo[2] = status2; + fdctrl->fifo[3] = cur_drv->track; + fdctrl->fifo[4] = cur_drv->head; + fdctrl->fifo[5] = cur_drv->sect; + fdctrl->fifo[6] = FD_SECTOR_SC; + fdctrl->data_dir = FD_DIR_READ; + if (fdctrl->state & FD_CTRL_BUSY) + DMA_release_DREQ(fdctrl->dma_chann); + fdctrl_set_fifo(fdctrl, 7, 1); } /* Prepare a data transfer (either DMA or FIFO) */ -static void fdctrl_start_transfer (int direction) +static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) { - fdrive_t *cur_drv, *drv0, *drv1; + fdrive_t *cur_drv; uint8_t kh, kt, ks; int did_seek; - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; - fdctrl.cur_drv = fdctrl.fifo[1] & 1; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; - kt = fdctrl.fifo[2]; - kh = fdctrl.fifo[3]; - ks = fdctrl.fifo[4]; + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); + kt = fdctrl->fifo[2]; + kh = fdctrl->fifo[3]; + ks = fdctrl->fifo[4]; FLOPPY_DPRINTF("Start tranfert at %d %d %02x %02x (%d)\n", - fdctrl.cur_drv, kh, kt, ks, + fdctrl->cur_drv, kh, kt, ks, _fd_sector(kh, kt, ks, cur_drv->last_sect)); did_seek = 0; - switch (fd_seek(cur_drv, kh, kt, ks, fdctrl.config & 0x40)) { + switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) { case 2: /* sect too big */ - fdctrl_stop_transfer(0x40, 0x00, 0x00); - fdctrl.fifo[3] = kt; - fdctrl.fifo[4] = kh; - fdctrl.fifo[5] = ks; + fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; return; case 3: /* track too big */ - fdctrl_stop_transfer(0x40, 0x80, 0x00); - fdctrl.fifo[3] = kt; - fdctrl.fifo[4] = kh; - fdctrl.fifo[5] = ks; + fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; return; case 4: /* No seek enabled */ - fdctrl_stop_transfer(0x40, 0x00, 0x00); - fdctrl.fifo[3] = kt; - fdctrl.fifo[4] = kh; - fdctrl.fifo[5] = ks; + fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; return; case 1: did_seek = 1; @@ -685,299 +975,379 @@ static void fdctrl_start_transfer (int direction) break; } /* Set the FIFO state */ - fdctrl.data_dir = direction; - fdctrl.data_pos = 0; - fdctrl.data_state = FD_STATE_DATA; /* FIFO ready for data */ - if (fdctrl.fifo[0] & 0x80) - fdctrl.data_state |= FD_STATE_MULTI; + fdctrl->data_dir = direction; + fdctrl->data_pos = 0; + FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */ + if (fdctrl->fifo[0] & 0x80) + fdctrl->data_state |= FD_STATE_MULTI; + else + fdctrl->data_state &= ~FD_STATE_MULTI; if (did_seek) - fdctrl.data_state |= FD_STATE_SEEK; - if (fdctrl.dma_en) { + fdctrl->data_state |= FD_STATE_SEEK; + else + fdctrl->data_state &= ~FD_STATE_SEEK; + if (fdctrl->fifo[5] == 00) { + fdctrl->data_len = fdctrl->fifo[8]; + } else { + int tmp; + fdctrl->data_len = 128 << fdctrl->fifo[5]; + tmp = (cur_drv->last_sect - ks + 1); + if (fdctrl->fifo[0] & 0x80) + tmp += cur_drv->last_sect; + fdctrl->data_len *= tmp; + } + if (fdctrl->dma_en) { int dma_mode; /* DMA transfer are enabled. Check if DMA channel is well programmed */ - dma_mode = DMA_get_channel_mode(fdctrl.dma_chann); + dma_mode = DMA_get_channel_mode(fdctrl->dma_chann); dma_mode = (dma_mode >> 2) & 3; - FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d)\n", dma_mode, direction, - (128 << fdctrl.fifo[5]) * - (cur_drv->last_sect - ks + 1)); + FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n", + dma_mode, direction, + (128 << fdctrl->fifo[5]) * + (cur_drv->last_sect - ks + 1), fdctrl->data_len); if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL || direction == FD_DIR_SCANH) && dma_mode == 0) || (direction == FD_DIR_WRITE && dma_mode == 2) || (direction == FD_DIR_READ && dma_mode == 1)) { /* No access is allowed until DMA transfer has completed */ - fdctrl.state |= FD_CTRL_BUSY; + fdctrl->state |= FD_CTRL_BUSY; /* Now, we just have to wait for the DMA controler to * recall us... */ - DMA_hold_DREQ(fdctrl.dma_chann); - DMA_schedule(fdctrl.dma_chann); + DMA_hold_DREQ(fdctrl->dma_chann); + DMA_schedule(fdctrl->dma_chann); return; + } else { + FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction); } } FLOPPY_DPRINTF("start non-DMA transfer\n"); /* IO based transfer: calculate len */ - if (fdctrl.fifo[5] == 00) { - fdctrl.data_len = fdctrl.fifo[8]; - } else { - fdctrl.data_len = 128 << fdctrl.fifo[5]; - fdctrl.data_len *= (cur_drv->last_sect - ks + 1); - if (fdctrl.fifo[0] & 0x80) - fdctrl.data_len *= 2; - } - fdctrl_raise_irq(0x00); + fdctrl_raise_irq(fdctrl, 0x00); return; } /* Prepare a transfer of deleted data */ -static void fdctrl_start_transfer_del (int direction) +static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction) { /* We don't handle deleted data, * so we don't return *ANYTHING* */ - fdctrl_stop_transfer(0x60, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); } /* handlers for DMA transfers */ -/* XXX: the partial transfer logic seems to be broken */ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) { - fdrive_t *cur_drv, *drv0, *drv1; - int len; + fdctrl_t *fdctrl; + fdrive_t *cur_drv; + int len, start_pos, rel_pos; uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; - uint8_t tmpbuf[FD_SECTOR_LEN]; - fdctrl_reset_irq(); - if (!(fdctrl.state & FD_CTRL_BUSY)) { + fdctrl = opaque; + fdctrl_reset_irq(fdctrl); + if (!(fdctrl->state & FD_CTRL_BUSY)) { FLOPPY_DPRINTF("Not in DMA transfer mode !\n"); return 0; } - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; - if (fdctrl.data_dir == FD_DIR_SCANE || fdctrl.data_dir == FD_DIR_SCANL || - fdctrl.data_dir == FD_DIR_SCANH) + cur_drv = get_cur_drv(fdctrl); + if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL || + fdctrl->data_dir == FD_DIR_SCANH) status2 = 0x04; - for (fdctrl.data_len = size; fdctrl.data_pos < fdctrl.data_len; - fdctrl.data_pos += len) { - len = size - fdctrl.data_pos; - if (len > FD_SECTOR_LEN) - len = FD_SECTOR_LEN; - FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x " - "(%d-0x%08x)\n", len, size, fdctrl.data_pos, - fdctrl.data_len, fdctrl.cur_drv, cur_drv->head, - cur_drv->track, cur_drv->sect, fd_sector(cur_drv), - fd_sector(cur_drv) * 512); - if (fdctrl.data_dir != FD_DIR_WRITE) { - /* READ & SCAN commands */ + if (size > fdctrl->data_len) + size = fdctrl->data_len; if (cur_drv->bs == NULL) { - fdctrl_stop_transfer(0x40, 0x00, 0x00); + if (fdctrl->data_dir == FD_DIR_WRITE) + fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); + else + fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + len = 0; goto transfer_error; } - if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), tmpbuf, 1) < 0) { + rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; + for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) { + len = size - fdctrl->data_pos; + if (len + rel_pos > FD_SECTOR_LEN) + len = FD_SECTOR_LEN - rel_pos; + FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x " + "(%d-0x%08x 0x%08x)\n", len, size, fdctrl->data_pos, + fdctrl->data_len, fdctrl->cur_drv, cur_drv->head, + cur_drv->track, cur_drv->sect, fd_sector(cur_drv), + fd_sector(cur_drv) * 512, addr); + if (fdctrl->data_dir != FD_DIR_WRITE || + len < FD_SECTOR_LEN || rel_pos != 0) { + /* READ & SCAN commands and realign to a sector for WRITE */ + if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), + fdctrl->fifo, 1) < 0) { FLOPPY_DPRINTF("Floppy: error getting sector %d\n", fd_sector(cur_drv)); /* Sure, image size is too small... */ - memset(tmpbuf, 0, FD_SECTOR_LEN); + memset(fdctrl->fifo, 0, FD_SECTOR_LEN); } - if (fdctrl.data_dir == FD_DIR_READ) { - cpu_physical_memory_write(addr + fdctrl.data_pos, - tmpbuf, len); - if (len < FD_SECTOR_LEN) { - memcpy(&fdctrl.fifo[0], tmpbuf + len, FD_SECTOR_LEN - len); - memset(&fdctrl.fifo[FD_SECTOR_LEN - len], 0, len); } - } else { - int ret; - /* XXX: what to do if not enough data ? */ - cpu_physical_memory_read(addr + fdctrl.data_pos, - fdctrl.fifo, len); - if (len < FD_SECTOR_LEN) { - memset(&fdctrl.fifo[len], 0, FD_SECTOR_LEN - len); + switch (fdctrl->data_dir) { + case FD_DIR_READ: + /* READ commands */ + cpu_physical_memory_write(addr + fdctrl->data_pos, + fdctrl->fifo + rel_pos, len); + break; + case FD_DIR_WRITE: + /* WRITE commands */ + cpu_physical_memory_read(addr + fdctrl->data_pos, + fdctrl->fifo + rel_pos, len); + if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), + fdctrl->fifo, 1) < 0) { + FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); + fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); + goto transfer_error; } - ret = memcmp(tmpbuf, fdctrl.fifo, FD_SECTOR_LEN); + break; + default: + /* SCAN commands */ + { + uint8_t tmpbuf[FD_SECTOR_LEN]; + int ret; + cpu_physical_memory_read(addr + fdctrl->data_pos, + tmpbuf, len); + ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len); if (ret == 0) { status2 = 0x08; goto end_transfer; } - if ((ret < 0 && fdctrl.data_dir == FD_DIR_SCANL) || - (ret > 0 && fdctrl.data_dir == FD_DIR_SCANH)) { + if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) || + (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) { status2 = 0x00; goto end_transfer; } } - } else { - /* WRITE commands */ - cpu_physical_memory_read(addr + fdctrl.data_pos, tmpbuf, len); - if (len < FD_SECTOR_LEN) { - memset(tmpbuf + len, 0, FD_SECTOR_LEN - len); - } - if (cur_drv->bs == NULL || - bdrv_write(cur_drv->bs, fd_sector(cur_drv), tmpbuf, 1) < 0) { - FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); - fdctrl_stop_transfer(0x60, 0x00, 0x00); - goto transfer_error; - } + break; } - if (len == FD_SECTOR_LEN) { + fdctrl->data_pos += len; + rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; + if (rel_pos == 0) { /* Seek to next sector */ - if (cur_drv->sect == cur_drv->last_sect) { - if (cur_drv->head == 0) { + cur_drv->sect++; + FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", + cur_drv->head, cur_drv->track, cur_drv->sect, + fd_sector(cur_drv), + fdctrl->data_pos - size); + if (cur_drv->sect > cur_drv->last_sect) { + cur_drv->sect = 1; + if (FD_MULTI_TRACK(fdctrl->data_state)) { + if (cur_drv->head == 0 && + (cur_drv->flags & FDISK_DBL_SIDES) != 0) { cur_drv->head = 1; } else { - cur_drv->track++; cur_drv->head = 0; - } - cur_drv->sect = 1; - FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n", - cur_drv->head, cur_drv->track, cur_drv->sect, - fd_sector(cur_drv)); - if (cur_drv->head == 0) { - FLOPPY_DPRINTF("end transfer\n"); - goto end_transfer; - } - if (!FD_MULTI_TRACK(fdctrl.data_state)) { - /* Single track read */ - FLOPPY_DPRINTF("single track transfert: end transfer\n"); -// status1 |= 0x80; - goto end_transfer; + cur_drv->track++; + if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) + break; } } else { - cur_drv->sect++; - FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n", - cur_drv->head, cur_drv->track, cur_drv->sect, - fd_sector(cur_drv)); + cur_drv->track++; + break; + } + FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", + cur_drv->head, cur_drv->track, + cur_drv->sect, fd_sector(cur_drv)); } } } end_transfer: - if (fdctrl.data_dir == FD_DIR_SCANE || - fdctrl.data_dir == FD_DIR_SCANL || - fdctrl.data_dir == FD_DIR_SCANH) + len = fdctrl->data_pos - start_pos; + FLOPPY_DPRINTF("end transfer %d %d %d\n", + fdctrl->data_pos, len, fdctrl->data_len); + if (fdctrl->data_dir == FD_DIR_SCANE || + fdctrl->data_dir == FD_DIR_SCANL || + fdctrl->data_dir == FD_DIR_SCANH) status2 = 0x08; - if (FD_DID_SEEK(fdctrl.data_state)) + if (FD_DID_SEEK(fdctrl->data_state)) status0 |= 0x20; - fdctrl_stop_transfer(status0, status1, status2); + fdctrl->data_len -= len; + // if (fdctrl->data_len == 0) + fdctrl_stop_transfer(fdctrl, status0, status1, status2); transfer_error: - return fdctrl.data_pos; + return len; } /* Data register : 0x05 */ -static uint32_t fdctrl_read_data (void *opaque, uint32_t reg) +static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) { - fdrive_t *cur_drv, *drv0, *drv1; + fdrive_t *cur_drv; uint32_t retval = 0; int pos, len; - fdctrl_reset_irq(); - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; - fdctrl.state &= ~FD_CTRL_SLEEP; - if (FD_STATE(fdctrl.data_state) == FD_STATE_CMD) { + fdctrl_reset_irq(fdctrl); + cur_drv = get_cur_drv(fdctrl); + fdctrl->state &= ~FD_CTRL_SLEEP; + if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) { FLOPPY_ERROR("can't read data in CMD state\n"); return 0; } - pos = fdctrl.data_pos; - if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) { + pos = fdctrl->data_pos; + if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { pos %= FD_SECTOR_LEN; if (pos == 0) { - len = fdctrl.data_len - fdctrl.data_pos; + len = fdctrl->data_len - fdctrl->data_pos; if (len > FD_SECTOR_LEN) len = FD_SECTOR_LEN; bdrv_read(cur_drv->bs, fd_sector(cur_drv), - fdctrl.fifo, len); + fdctrl->fifo, len); } } - retval = fdctrl.fifo[pos]; - if (++fdctrl.data_pos == fdctrl.data_len) { - fdctrl.data_pos = 0; + retval = fdctrl->fifo[pos]; + if (++fdctrl->data_pos == fdctrl->data_len) { + fdctrl->data_pos = 0; /* Switch from transfert mode to status mode * then from status mode to command mode */ - if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) - fdctrl_stop_transfer(0x20, 0x00, 0x00); + if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) + fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); else - fdctrl_reset_fifo(); + fdctrl_reset_fifo(fdctrl); } FLOPPY_DPRINTF("data register: 0x%02x\n", retval); return retval; } -static void fdctrl_write_data (void *opaque, uint32_t reg, uint32_t value) +static void fdctrl_format_sector (fdctrl_t *fdctrl) { - fdrive_t *cur_drv, *drv0, *drv1; + fdrive_t *cur_drv; + uint8_t kh, kt, ks; + int did_seek; - fdctrl_reset_irq(); - drv0 = &fdctrl.drives[fdctrl.bootsel]; - drv1 = &fdctrl.drives[1 - fdctrl.bootsel]; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); + kt = fdctrl->fifo[6]; + kh = fdctrl->fifo[7]; + ks = fdctrl->fifo[8]; + FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n", + fdctrl->cur_drv, kh, kt, ks, + _fd_sector(kh, kt, ks, cur_drv->last_sect)); + did_seek = 0; + switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) { + case 2: + /* sect too big */ + fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; + return; + case 3: + /* track too big */ + fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; + return; + case 4: + /* No seek enabled */ + fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; + return; + case 1: + did_seek = 1; + fdctrl->data_state |= FD_STATE_SEEK; + break; + default: + break; + } + memset(fdctrl->fifo, 0, FD_SECTOR_LEN); + if (cur_drv->bs == NULL || + bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { + FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv)); + fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); + } else { + if (cur_drv->sect == cur_drv->last_sect) { + fdctrl->data_state &= ~FD_STATE_FORMAT; + /* Last sector done */ + if (FD_DID_SEEK(fdctrl->data_state)) + fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); + else + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); + } else { + /* More to do */ + fdctrl->data_pos = 0; + fdctrl->data_len = 4; + } + } +} + +static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) +{ + fdrive_t *cur_drv; + + fdctrl_reset_irq(fdctrl); + cur_drv = get_cur_drv(fdctrl); /* Reset mode */ - if (fdctrl.state & FD_CTRL_RESET) { + if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); return; } - fdctrl.state &= ~FD_CTRL_SLEEP; - if ((fdctrl.data_state & FD_STATE_STATE) == FD_STATE_STATUS) { + fdctrl->state &= ~FD_CTRL_SLEEP; + if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) { FLOPPY_ERROR("can't write data in status mode\n"); return; } /* Is it write command time ? */ - if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) { + if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { /* FIFO data write */ - fdctrl.fifo[fdctrl.data_pos++] = value; - if (fdctrl.data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) || - fdctrl.data_pos == fdctrl.data_len) { + fdctrl->fifo[fdctrl->data_pos++] = value; + if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) || + fdctrl->data_pos == fdctrl->data_len) { bdrv_write(cur_drv->bs, fd_sector(cur_drv), - fdctrl.fifo, FD_SECTOR_LEN); + fdctrl->fifo, FD_SECTOR_LEN); } /* Switch from transfert mode to status mode * then from status mode to command mode */ - if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) - fdctrl_stop_transfer(0x20, 0x00, 0x00); + if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) + fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); return; } - if (fdctrl.data_pos == 0) { + if (fdctrl->data_pos == 0) { /* Command */ switch (value & 0x5F) { case 0x46: /* READ variants */ FLOPPY_DPRINTF("READ command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; case 0x4C: /* READ_DELETED variants */ FLOPPY_DPRINTF("READ_DELETED command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; case 0x50: /* SCAN_EQUAL variants */ FLOPPY_DPRINTF("SCAN_EQUAL command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; case 0x56: /* VERIFY variants */ FLOPPY_DPRINTF("VERIFY command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; case 0x59: /* SCAN_LOW_OR_EQUAL variants */ FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; case 0x5D: /* SCAN_HIGH_OR_EQUAL variants */ FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; default: break; @@ -987,13 +1357,13 @@ static void fdctrl_write_data (void *opaque, uint32_t reg, uint32_t value) /* WRITE variants */ FLOPPY_DPRINTF("WRITE command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; case 0x49: /* WRITE_DELETED variants */ FLOPPY_DPRINTF("WRITE_DELETED command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; default: break; @@ -1003,422 +1373,447 @@ static void fdctrl_write_data (void *opaque, uint32_t reg, uint32_t value) /* SPECIFY */ FLOPPY_DPRINTF("SPECIFY command\n"); /* 1 parameter cmd */ - fdctrl.data_len = 3; + fdctrl->data_len = 3; goto enqueue; case 0x04: /* SENSE_DRIVE_STATUS */ FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n"); /* 1 parameter cmd */ - fdctrl.data_len = 2; + fdctrl->data_len = 2; goto enqueue; case 0x07: /* RECALIBRATE */ FLOPPY_DPRINTF("RECALIBRATE command\n"); /* 1 parameter cmd */ - fdctrl.data_len = 2; + fdctrl->data_len = 2; goto enqueue; case 0x08: /* SENSE_INTERRUPT_STATUS */ FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n", - fdctrl.int_status); + fdctrl->int_status); /* No parameters cmd: returns status if no interrupt */ - fdctrl.fifo[0] = - fdctrl.int_status | (cur_drv->head << 2) | fdctrl.cur_drv; - fdctrl.fifo[1] = cur_drv->track; - fdctrl_set_fifo(2, 0); + fdctrl->fifo[0] = + fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv; + fdctrl->fifo[1] = cur_drv->track; + fdctrl_set_fifo(fdctrl, 2, 0); + fdctrl_reset_irq(fdctrl); + fdctrl->int_status = 0xC0; return; case 0x0E: /* DUMPREG */ FLOPPY_DPRINTF("DUMPREG command\n"); /* Drives position */ - fdctrl.fifo[0] = drv0->track; - fdctrl.fifo[1] = drv1->track; - fdctrl.fifo[2] = 0; - fdctrl.fifo[3] = 0; + fdctrl->fifo[0] = drv0(fdctrl)->track; + fdctrl->fifo[1] = drv1(fdctrl)->track; + fdctrl->fifo[2] = 0; + fdctrl->fifo[3] = 0; /* timers */ - fdctrl.fifo[4] = fdctrl.timer0; - fdctrl.fifo[5] = (fdctrl.timer1 << 1) | fdctrl.dma_en; - fdctrl.fifo[6] = cur_drv->last_sect; - fdctrl.fifo[7] = (fdctrl.lock << 7) | + fdctrl->fifo[4] = fdctrl->timer0; + fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en; + fdctrl->fifo[6] = cur_drv->last_sect; + fdctrl->fifo[7] = (fdctrl->lock << 7) | (cur_drv->perpendicular << 2); - fdctrl.fifo[8] = fdctrl.config; - fdctrl.fifo[9] = fdctrl.precomp_trk; - fdctrl_set_fifo(10, 0); + fdctrl->fifo[8] = fdctrl->config; + fdctrl->fifo[9] = fdctrl->precomp_trk; + fdctrl_set_fifo(fdctrl, 10, 0); return; case 0x0F: /* SEEK */ FLOPPY_DPRINTF("SEEK command\n"); /* 2 parameters cmd */ - fdctrl.data_len = 3; + fdctrl->data_len = 3; goto enqueue; case 0x10: /* VERSION */ FLOPPY_DPRINTF("VERSION command\n"); /* No parameters cmd */ /* Controler's version */ - fdctrl.fifo[0] = fdctrl.version; - fdctrl_set_fifo(1, 1); + fdctrl->fifo[0] = fdctrl->version; + fdctrl_set_fifo(fdctrl, 1, 1); return; case 0x12: /* PERPENDICULAR_MODE */ FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n"); /* 1 parameter cmd */ - fdctrl.data_len = 2; + fdctrl->data_len = 2; goto enqueue; case 0x13: /* CONFIGURE */ FLOPPY_DPRINTF("CONFIGURE command\n"); /* 3 parameters cmd */ - fdctrl.data_len = 4; + fdctrl->data_len = 4; goto enqueue; case 0x14: /* UNLOCK */ FLOPPY_DPRINTF("UNLOCK command\n"); /* No parameters cmd */ - fdctrl.lock = 0; - fdctrl.fifo[0] = 0; - fdctrl_set_fifo(1, 0); + fdctrl->lock = 0; + fdctrl->fifo[0] = 0; + fdctrl_set_fifo(fdctrl, 1, 0); return; case 0x17: /* POWERDOWN_MODE */ FLOPPY_DPRINTF("POWERDOWN_MODE command\n"); /* 2 parameters cmd */ - fdctrl.data_len = 3; + fdctrl->data_len = 3; goto enqueue; case 0x18: /* PART_ID */ FLOPPY_DPRINTF("PART_ID command\n"); /* No parameters cmd */ - fdctrl.fifo[0] = 0x41; /* Stepping 1 */ - fdctrl_set_fifo(1, 0); + fdctrl->fifo[0] = 0x41; /* Stepping 1 */ + fdctrl_set_fifo(fdctrl, 1, 0); return; case 0x2C: /* SAVE */ FLOPPY_DPRINTF("SAVE command\n"); /* No parameters cmd */ - fdctrl.fifo[0] = 0; - fdctrl.fifo[1] = 0; + fdctrl->fifo[0] = 0; + fdctrl->fifo[1] = 0; /* Drives position */ - fdctrl.fifo[2] = drv0->track; - fdctrl.fifo[3] = drv1->track; - fdctrl.fifo[4] = 0; - fdctrl.fifo[5] = 0; + fdctrl->fifo[2] = drv0(fdctrl)->track; + fdctrl->fifo[3] = drv1(fdctrl)->track; + fdctrl->fifo[4] = 0; + fdctrl->fifo[5] = 0; /* timers */ - fdctrl.fifo[6] = fdctrl.timer0; - fdctrl.fifo[7] = fdctrl.timer1; - fdctrl.fifo[8] = cur_drv->last_sect; - fdctrl.fifo[9] = (fdctrl.lock << 7) | + fdctrl->fifo[6] = fdctrl->timer0; + fdctrl->fifo[7] = fdctrl->timer1; + fdctrl->fifo[8] = cur_drv->last_sect; + fdctrl->fifo[9] = (fdctrl->lock << 7) | (cur_drv->perpendicular << 2); - fdctrl.fifo[10] = fdctrl.config; - fdctrl.fifo[11] = fdctrl.precomp_trk; - fdctrl.fifo[12] = fdctrl.pwrd; - fdctrl.fifo[13] = 0; - fdctrl.fifo[14] = 0; - fdctrl_set_fifo(15, 1); + fdctrl->fifo[10] = fdctrl->config; + fdctrl->fifo[11] = fdctrl->precomp_trk; + fdctrl->fifo[12] = fdctrl->pwrd; + fdctrl->fifo[13] = 0; + fdctrl->fifo[14] = 0; + fdctrl_set_fifo(fdctrl, 15, 1); return; case 0x33: /* OPTION */ FLOPPY_DPRINTF("OPTION command\n"); /* 1 parameter cmd */ - fdctrl.data_len = 2; + fdctrl->data_len = 2; goto enqueue; case 0x42: /* READ_TRACK */ FLOPPY_DPRINTF("READ_TRACK command\n"); /* 8 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 9; goto enqueue; case 0x4A: /* READ_ID */ FLOPPY_DPRINTF("READ_ID command\n"); /* 1 parameter cmd */ - fdctrl.data_len = 2; + fdctrl->data_len = 2; goto enqueue; case 0x4C: /* RESTORE */ FLOPPY_DPRINTF("RESTORE command\n"); /* 17 parameters cmd */ - fdctrl.data_len = 18; + fdctrl->data_len = 18; goto enqueue; case 0x4D: /* FORMAT_TRACK */ FLOPPY_DPRINTF("FORMAT_TRACK command\n"); /* 5 parameters cmd */ - fdctrl.data_len = 9; + fdctrl->data_len = 6; goto enqueue; case 0x8E: /* DRIVE_SPECIFICATION_COMMAND */ FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n"); /* 5 parameters cmd */ - fdctrl.data_len = 6; + fdctrl->data_len = 6; goto enqueue; case 0x8F: /* RELATIVE_SEEK_OUT */ FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n"); /* 2 parameters cmd */ - fdctrl.data_len = 3; + fdctrl->data_len = 3; goto enqueue; case 0x94: /* LOCK */ FLOPPY_DPRINTF("LOCK command\n"); /* No parameters cmd */ - fdctrl.lock = 1; - fdctrl.fifo[0] = 0x10; - fdctrl_set_fifo(1, 1); + fdctrl->lock = 1; + fdctrl->fifo[0] = 0x10; + fdctrl_set_fifo(fdctrl, 1, 1); return; case 0xCD: /* FORMAT_AND_WRITE */ FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n"); /* 10 parameters cmd */ - fdctrl.data_len = 11; + fdctrl->data_len = 11; goto enqueue; case 0xCF: /* RELATIVE_SEEK_IN */ FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n"); /* 2 parameters cmd */ - fdctrl.data_len = 3; + fdctrl->data_len = 3; goto enqueue; default: /* Unknown command */ FLOPPY_ERROR("unknown command: 0x%02x\n", value); - fdctrl_unimplemented(); + fdctrl_unimplemented(fdctrl); return; } } enqueue: - fdctrl.fifo[fdctrl.data_pos] = value; - if (++fdctrl.data_pos == fdctrl.data_len) { + FLOPPY_DPRINTF("%s: %02x\n", __func__, value); + fdctrl->fifo[fdctrl->data_pos] = value; + if (++fdctrl->data_pos == fdctrl->data_len) { /* We now have all parameters * and will be able to treat the command */ - switch (fdctrl.fifo[0] & 0x1F) { + if (fdctrl->data_state & FD_STATE_FORMAT) { + fdctrl_format_sector(fdctrl); + return; + } + switch (fdctrl->fifo[0] & 0x1F) { case 0x06: { /* READ variants */ FLOPPY_DPRINTF("treat READ command\n"); - fdctrl_start_transfer(FD_DIR_READ); + fdctrl_start_transfer(fdctrl, FD_DIR_READ); return; } case 0x0C: /* READ_DELETED variants */ // FLOPPY_DPRINTF("treat READ_DELETED command\n"); FLOPPY_ERROR("treat READ_DELETED command\n"); - fdctrl_start_transfer_del(1); + fdctrl_start_transfer_del(fdctrl, FD_DIR_READ); return; case 0x16: /* VERIFY variants */ // FLOPPY_DPRINTF("treat VERIFY command\n"); FLOPPY_ERROR("treat VERIFY command\n"); - fdctrl_stop_transfer(0x20, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); return; case 0x10: /* SCAN_EQUAL variants */ // FLOPPY_DPRINTF("treat SCAN_EQUAL command\n"); FLOPPY_ERROR("treat SCAN_EQUAL command\n"); - fdctrl_start_transfer(FD_DIR_SCANE); + fdctrl_start_transfer(fdctrl, FD_DIR_SCANE); return; case 0x19: /* SCAN_LOW_OR_EQUAL variants */ // FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n"); FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n"); - fdctrl_start_transfer(FD_DIR_SCANL); + fdctrl_start_transfer(fdctrl, FD_DIR_SCANL); return; case 0x1D: /* SCAN_HIGH_OR_EQUAL variants */ // FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n"); FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n"); - fdctrl_start_transfer(FD_DIR_SCANH); + fdctrl_start_transfer(fdctrl, FD_DIR_SCANH); return; default: break; } - switch (fdctrl.fifo[0] & 0x3F) { + switch (fdctrl->fifo[0] & 0x3F) { case 0x05: /* WRITE variants */ - FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl.fifo[0]); - fdctrl_start_transfer(FD_DIR_WRITE); + FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]); + fdctrl_start_transfer(fdctrl, FD_DIR_WRITE); return; case 0x09: /* WRITE_DELETED variants */ // FLOPPY_DPRINTF("treat WRITE_DELETED command\n"); FLOPPY_ERROR("treat WRITE_DELETED command\n"); - fdctrl_start_transfer_del(FD_DIR_WRITE); + fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE); return; default: break; } - switch (fdctrl.fifo[0]) { + switch (fdctrl->fifo[0]) { case 0x03: /* SPECIFY */ FLOPPY_DPRINTF("treat SPECIFY command\n"); - fdctrl.timer0 = (fdctrl.fifo[1] >> 4) & 0xF; - fdctrl.timer1 = fdctrl.fifo[1] >> 1; + fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF; + fdctrl->timer1 = fdctrl->fifo[1] >> 1; + fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ; /* No result back */ - fdctrl_reset_fifo(); + fdctrl_reset_fifo(fdctrl); break; case 0x04: /* SENSE_DRIVE_STATUS */ FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n"); - fdctrl.cur_drv = fdctrl.fifo[1] & 1; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; - cur_drv->head = (fdctrl.fifo[1] >> 2) & 1; + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); + cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; /* 1 Byte status back */ - fdctrl.fifo[0] = (cur_drv->ro << 6) | + fdctrl->fifo[0] = (cur_drv->ro << 6) | (cur_drv->track == 0 ? 0x10 : 0x00) | - fdctrl.cur_drv; - fdctrl_set_fifo(1, 0); + fdctrl->cur_drv; + fdctrl_set_fifo(fdctrl, 1, 0); break; case 0x07: /* RECALIBRATE */ FLOPPY_DPRINTF("treat RECALIBRATE command\n"); - fdctrl.cur_drv = fdctrl.fifo[1] & 1; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); fd_recalibrate(cur_drv); - fdctrl_reset_fifo(); + fdctrl_reset_fifo(fdctrl); /* Raise Interrupt */ - fdctrl_raise_irq(0x20); + fdctrl_raise_irq(fdctrl, 0x20); break; case 0x0F: /* SEEK */ FLOPPY_DPRINTF("treat SEEK command\n"); - fdctrl.cur_drv = fdctrl.fifo[1] & 1; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; - if (fdctrl.fifo[2] <= cur_drv->track) + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); + fd_start(cur_drv); + if (fdctrl->fifo[2] <= cur_drv->track) cur_drv->dir = 1; else cur_drv->dir = 0; - cur_drv->head = (fdctrl.fifo[1] >> 2) & 1; - if (fdctrl.fifo[2] > cur_drv->max_track) { - fdctrl_raise_irq(0x60); + fdctrl_reset_fifo(fdctrl); + if (fdctrl->fifo[2] > cur_drv->max_track) { + fdctrl_raise_irq(fdctrl, 0x60); } else { - cur_drv->track = fdctrl.fifo[2]; - fdctrl_reset_fifo(); + cur_drv->track = fdctrl->fifo[2]; /* Raise Interrupt */ - fdctrl_raise_irq(0x20); + fdctrl_raise_irq(fdctrl, 0x20); } break; case 0x12: /* PERPENDICULAR_MODE */ FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n"); - if (fdctrl.fifo[1] & 0x80) - cur_drv->perpendicular = fdctrl.fifo[1] & 0x7; + if (fdctrl->fifo[1] & 0x80) + cur_drv->perpendicular = fdctrl->fifo[1] & 0x7; /* No result back */ - fdctrl_reset_fifo(); + fdctrl_reset_fifo(fdctrl); break; case 0x13: /* CONFIGURE */ FLOPPY_DPRINTF("treat CONFIGURE command\n"); - fdctrl.config = fdctrl.fifo[2]; - fdctrl.precomp_trk = fdctrl.fifo[3]; + fdctrl->config = fdctrl->fifo[2]; + fdctrl->precomp_trk = fdctrl->fifo[3]; /* No result back */ - fdctrl_reset_fifo(); + fdctrl_reset_fifo(fdctrl); break; case 0x17: /* POWERDOWN_MODE */ FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n"); - fdctrl.pwrd = fdctrl.fifo[1]; - fdctrl.fifo[0] = fdctrl.fifo[1]; - fdctrl_set_fifo(1, 1); + fdctrl->pwrd = fdctrl->fifo[1]; + fdctrl->fifo[0] = fdctrl->fifo[1]; + fdctrl_set_fifo(fdctrl, 1, 1); break; case 0x33: /* OPTION */ FLOPPY_DPRINTF("treat OPTION command\n"); /* No result back */ - fdctrl_reset_fifo(); + fdctrl_reset_fifo(fdctrl); break; case 0x42: /* READ_TRACK */ // FLOPPY_DPRINTF("treat READ_TRACK command\n"); FLOPPY_ERROR("treat READ_TRACK command\n"); - fdctrl_unimplemented(); + fdctrl_start_transfer(fdctrl, FD_DIR_READ); break; case 0x4A: /* READ_ID */ -// FLOPPY_DPRINTF("treat READ_ID command\n"); - FLOPPY_ERROR("treat READ_ID command\n"); - fdctrl_stop_transfer(0x00, 0x00, 0x00); + FLOPPY_DPRINTF("treat READ_ID command\n"); + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); break; case 0x4C: /* RESTORE */ FLOPPY_DPRINTF("treat RESTORE command\n"); /* Drives position */ - drv0->track = fdctrl.fifo[3]; - drv1->track = fdctrl.fifo[4]; + drv0(fdctrl)->track = fdctrl->fifo[3]; + drv1(fdctrl)->track = fdctrl->fifo[4]; /* timers */ - fdctrl.timer0 = fdctrl.fifo[7]; - fdctrl.timer1 = fdctrl.fifo[8]; - cur_drv->last_sect = fdctrl.fifo[9]; - fdctrl.lock = fdctrl.fifo[10] >> 7; - cur_drv->perpendicular = (fdctrl.fifo[10] >> 2) & 0xF; - fdctrl.config = fdctrl.fifo[11]; - fdctrl.precomp_trk = fdctrl.fifo[12]; - fdctrl.pwrd = fdctrl.fifo[13]; - fdctrl_reset_fifo(); + fdctrl->timer0 = fdctrl->fifo[7]; + fdctrl->timer1 = fdctrl->fifo[8]; + cur_drv->last_sect = fdctrl->fifo[9]; + fdctrl->lock = fdctrl->fifo[10] >> 7; + cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF; + fdctrl->config = fdctrl->fifo[11]; + fdctrl->precomp_trk = fdctrl->fifo[12]; + fdctrl->pwrd = fdctrl->fifo[13]; + fdctrl_reset_fifo(fdctrl); break; case 0x4D: /* FORMAT_TRACK */ -// FLOPPY_DPRINTF("treat FORMAT_TRACK command\n"); - FLOPPY_ERROR("treat FORMAT_TRACK command\n"); - fdctrl_unimplemented(); + FLOPPY_DPRINTF("treat FORMAT_TRACK command\n"); + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); + fdctrl->data_state |= FD_STATE_FORMAT; + if (fdctrl->fifo[0] & 0x80) + fdctrl->data_state |= FD_STATE_MULTI; + else + fdctrl->data_state &= ~FD_STATE_MULTI; + fdctrl->data_state &= ~FD_STATE_SEEK; + cur_drv->bps = + fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2]; +#if 0 + cur_drv->last_sect = + cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] : + fdctrl->fifo[3] / 2; +#else + cur_drv->last_sect = fdctrl->fifo[3]; +#endif + /* Bochs BIOS is buggy and don't send format informations + * for each sector. So, pretend all's done right now... + */ + fdctrl->data_state &= ~FD_STATE_FORMAT; + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); break; case 0x8E: /* DRIVE_SPECIFICATION_COMMAND */ FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n"); - if (fdctrl.fifo[fdctrl.data_pos - 1] & 0x80) { + if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) { /* Command parameters done */ - if (fdctrl.fifo[fdctrl.data_pos - 1] & 0x40) { - fdctrl.fifo[0] = fdctrl.fifo[1]; - fdctrl.fifo[2] = 0; - fdctrl.fifo[3] = 0; - fdctrl_set_fifo(4, 1); + if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) { + fdctrl->fifo[0] = fdctrl->fifo[1]; + fdctrl->fifo[2] = 0; + fdctrl->fifo[3] = 0; + fdctrl_set_fifo(fdctrl, 4, 1); } else { - fdctrl_reset_fifo(); + fdctrl_reset_fifo(fdctrl); } - } else if (fdctrl.data_len > 7) { + } else if (fdctrl->data_len > 7) { /* ERROR */ - fdctrl.fifo[0] = 0x80 | - (cur_drv->head << 2) | fdctrl.cur_drv; - fdctrl_set_fifo(1, 1); + fdctrl->fifo[0] = 0x80 | + (cur_drv->head << 2) | fdctrl->cur_drv; + fdctrl_set_fifo(fdctrl, 1, 1); } break; case 0x8F: /* RELATIVE_SEEK_OUT */ FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n"); - fdctrl.cur_drv = fdctrl.fifo[1] & 1; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; - cur_drv->head = (fdctrl.fifo[1] >> 2) & 1; - if (fdctrl.fifo[2] + cur_drv->track > cur_drv->max_track) { - /* ERROR */ - fdctrl_raise_irq(0x70); - } else { - cur_drv->track += fdctrl.fifo[2]; + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); + fd_start(cur_drv); cur_drv->dir = 0; - fdctrl_reset_fifo(); - fdctrl_raise_irq(0x20); + if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) { + cur_drv->track = cur_drv->max_track - 1; + } else { + cur_drv->track += fdctrl->fifo[2]; } + fdctrl_reset_fifo(fdctrl); + fdctrl_raise_irq(fdctrl, 0x20); break; case 0xCD: /* FORMAT_AND_WRITE */ // FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n"); FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n"); - fdctrl_unimplemented(); + fdctrl_unimplemented(fdctrl); break; case 0xCF: /* RELATIVE_SEEK_IN */ FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n"); - fdctrl.cur_drv = fdctrl.fifo[1] & 1; - cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1; - cur_drv->head = (fdctrl.fifo[1] >> 2) & 1; - if (fdctrl.fifo[2] > cur_drv->track) { - /* ERROR */ - fdctrl_raise_irq(0x60); - } else { - fdctrl_reset_fifo(); - cur_drv->track -= fdctrl.fifo[2]; + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); + fd_start(cur_drv); cur_drv->dir = 1; - /* Raise Interrupt */ - fdctrl_raise_irq(0x20); + if (fdctrl->fifo[2] > cur_drv->track) { + cur_drv->track = 0; + } else { + cur_drv->track -= fdctrl->fifo[2]; } + fdctrl_reset_fifo(fdctrl); + /* Raise Interrupt */ + fdctrl_raise_irq(fdctrl, 0x20); break; } } diff --git a/hw/pc.c b/hw/pc.c index 071d84023..2a8ee8a98 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -57,6 +57,7 @@ int speaker_data_on; int dummy_refresh_clock; +static fdctrl_t *floppy_controller; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -106,8 +107,8 @@ static void cmos_init(int ram_size, int boot_device) /* floppy type */ - fd0 = fdctrl_get_drive_type(0); - fd1 = fdctrl_get_drive_type(1); + fd0 = fdctrl_get_drive_type(floppy_controller, 0); + fd1 = fdctrl_get_drive_type(floppy_controller, 1); s->cmos_data[0x10] = 0; switch (fd0) { @@ -370,7 +371,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, DMA_init(); SB16_init(); - fdctrl_init(6, 2, 0, 0x3f0, fd_table); + floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); cmos_init(ram_size, boot_device); } diff --git a/vl.h b/vl.h index 11d7aba41..2377602dc 100644 --- a/vl.h +++ b/vl.h @@ -186,9 +186,12 @@ void SB16_init (void); #define MAX_FD 2 extern BlockDriverState *fd_table[MAX_FD]; -void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base, - BlockDriverState **fds); -int fdctrl_get_drive_type(int drive_num); +typedef struct fdctrl_t fdctrl_t; + +fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, + uint32_t io_base, + BlockDriverState **fds); +int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); /* ne2000.c */ -- cgit v1.2.3 From c45c3d0059d738c856fc730ee2e51bf5868815e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 20 Mar 2004 22:01:15 +0000 Subject: write to both IDE drives - return 0 for not present drives git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@672 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 57 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index a132d1c52..906c67f7a 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1060,7 +1060,7 @@ static void cdrom_change_cb(void *opaque) static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) { IDEState *ide_if = opaque; - IDEState *s = ide_if->cur_drive; + IDEState *s; int unit, n; #ifdef DEBUG_IDE @@ -1071,28 +1071,35 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0: break; case 1: - s->feature = val; + /* NOTE: data is written to the two drives */ + ide_if[0].feature = val; + ide_if[1].feature = val; break; case 2: if (val == 0) val = 256; - s->nsector = val; + ide_if[0].nsector = val; + ide_if[1].nsector = val; break; case 3: - s->sector = val; + ide_if[0].sector = val; + ide_if[1].sector = val; break; case 4: - s->lcyl = val; + ide_if[0].lcyl = val; + ide_if[1].lcyl = val; break; case 5: - s->hcyl = val; + ide_if[0].hcyl = val; + ide_if[1].hcyl = val; break; case 6: + ide_if[0].select = val & 0x4f; + ide_if[1].select = val & 0x4f; /* select drive */ unit = (val >> 4) & 1; s = ide_if + unit; ide_if->cur_drive = s; - s->select = val; break; default: case 7: @@ -1100,6 +1107,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) #if defined(DEBUG_IDE) printf("ide: CMD=%02x\n", val); #endif + s = ide_if->cur_drive; switch(val) { case WIN_IDENTIFY: if (s->bs && !s->is_cdrom) { @@ -1228,26 +1236,47 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = 0xff; break; case 1: - ret = s->error; + if (!s->bs) + ret = 0; + else + ret = s->error; break; case 2: - ret = s->nsector & 0xff; + if (!s->bs) + ret = 0; + else + ret = s->nsector & 0xff; break; case 3: - ret = s->sector; + if (!s->bs) + ret = 0; + else + ret = s->sector; break; case 4: - ret = s->lcyl; + if (!s->bs) + ret = 0; + else + ret = s->lcyl; break; case 5: - ret = s->hcyl; + if (!s->bs) + ret = 0; + else + ret = s->hcyl; break; case 6: - ret = s->select; + if (!s->bs) + ret = 0; + else + ret = s->select; break; default: case 7: - ret = s->status; + if (!s->bs) + ret = 0; + else + ret = s->status; pic_set_irq(s->irq, 0); break; } -- cgit v1.2.3 From 4afa64828b9a310f0348b430b9597e1cc6364760 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 20 Mar 2004 22:04:16 +0000 Subject: fixed protected lret imm insn (one more OS/2 fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@673 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/helper.c b/target-i386/helper.c index 9bd1158b0..6fc136763 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1705,6 +1705,8 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) validate_seg(R_DS, cpl); validate_seg(R_FS, cpl); validate_seg(R_GS, cpl); + + sp += addend; } ESP = (ESP & ~sp_mask) | (sp & sp_mask); env->eip = new_eip; -- cgit v1.2.3 From 3035f7ff83c9f072c0b9dc7a95789dba613b8750 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Mar 2004 17:02:00 +0000 Subject: use new directory layout git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@674 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile.target b/Makefile.target index f869aad5c..0d38b1d73 100644 --- a/Makefile.target +++ b/Makefile.target @@ -2,10 +2,14 @@ include config.mak TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw +DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH) +ifdef CONFIG_USER_ONLY +VPATH+=:$(SRC_PATH)/linux-user +DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) +endif CFLAGS=-Wall -O2 -g LDFLAGS=-g LIBS= -DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH) HELPER_CFLAGS=$(CFLAGS) DYNGEN=../dyngen # user emulator name @@ -149,7 +153,7 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o +OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o ifeq ($(TARGET_ARCH), i386) OBJS+= vm86.o endif @@ -162,7 +166,7 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a # cpu emulator library -LIBOBJS=thunk.o exec.o translate-all.o cpu-exec.o gdbstub.o \ +LIBOBJS=exec.o translate-all.o cpu-exec.o gdbstub.o \ translate.o op.o ifeq ($(TARGET_ARCH), i386) -- cgit v1.2.3 From f193c7979c2f7e4e021453689b5dd9c8abdcbbc4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Mar 2004 17:06:25 +0000 Subject: do not depend on thunk.h - more log items git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@675 c046a42c-6fe2-441c-8c8c-71466251a162 --- bswap.h | 8 ----- cpu-all.h | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- cpu-defs.h | 8 +++++ cpu-exec.c | 6 ++-- dyngen-exec.h | 10 ------ exec.c | 55 +++++++++++++++++++++++++++++++++ gdbstub.c | 22 +------------ monitor.c | 37 ++++++++++++++++++---- thunk.h | 77 --------------------------------------------- translate-all.c | 4 +-- vl.c | 20 +++++++++--- 11 files changed, 211 insertions(+), 132 deletions(-) diff --git a/bswap.h b/bswap.h index c52933e49..0df6efcb4 100644 --- a/bswap.h +++ b/bswap.h @@ -43,14 +43,6 @@ #endif /* !HAVE_BYTESWAP_H */ -#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) -#define HOST_LONG_BITS 64 -#else -#define HOST_LONG_BITS 32 -#endif - -#define HOST_LONG_SIZE (HOST_LONG_BITS / 8) - static inline uint16_t bswap16(uint16_t x) { return bswap_16(x); diff --git a/cpu-all.h b/cpu-all.h index 247674c63..b8beddbc3 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -37,6 +37,83 @@ * 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)) +#else +#define tswapl(s) tswap64(s) +#define tswapls(s) tswap64s((uint64_t *)(s)) +#endif + /* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ typedef union { double d; @@ -554,9 +631,26 @@ void cpu_single_step(CPUState *env, int enabled); if no page found. */ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr); -#define CPU_LOG_ALL 1 +#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 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 */ diff --git a/cpu-defs.h b/cpu-defs.h index 59a0c0f32..bbdb39009 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -41,6 +41,14 @@ typedef uint64_t target_ulong; #error TARGET_LONG_SIZE undefined #endif +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) +#define HOST_LONG_BITS 64 +#else +#define HOST_LONG_BITS 32 +#endif + +#define HOST_LONG_SIZE (HOST_LONG_BITS / 8) + #define EXCP_INTERRUPT 256 /* async interruption */ #define EXCP_HLT 257 /* hlt instruction reached */ #define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ diff --git a/cpu-exec.c b/cpu-exec.c index b6f3de1bb..cdbebd39b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -191,7 +191,7 @@ int cpu_exec(CPUState *env1) !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; intno = cpu_x86_get_pic_interrupt(env); - if (loglevel) { + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); } do_interrupt(intno, 0, 0, 0, 1); @@ -229,7 +229,7 @@ int cpu_exec(CPUState *env1) } } #ifdef DEBUG_EXEC - if (loglevel) { + if (loglevel & CPU_LOG_EXEC) { #if defined(TARGET_I386) /* restore flags in standard format */ env->regs[R_EAX] = EAX; @@ -362,7 +362,7 @@ int cpu_exec(CPUState *env1) spin_unlock(&tb_lock); } #ifdef DEBUG_EXEC - if (loglevel) { + if (loglevel & CPU_LOG_EXEC) { fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", (long)tb->tc_ptr, (long)tb->pc, lookup_symbol((void *)tb->pc)); diff --git a/dyngen-exec.h b/dyngen-exec.h index 5e9bab6f9..004ca71cd 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -45,16 +45,6 @@ typedef signed long long int64_t; #define UINT32_MAX (4294967295U) #define UINT64_MAX ((uint64_t)(18446744073709551615)) -#define bswap32(x) \ -({ \ - uint32_t __x = (x); \ - ((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ -}) - typedef struct FILE FILE; extern int fprintf(FILE *, const char *, ...); extern int printf(const char *, ...); diff --git a/exec.c b/exec.c index b945c8271..5d90476aa 100644 --- a/exec.c +++ b/exec.c @@ -1005,6 +1005,61 @@ void cpu_interrupt(CPUState *env, int mask) } } +CPULogItem cpu_log_items[] = { + { CPU_LOG_TB_OUT_ASM, "out_asm", + "show generated host assembly code for each compiled TB" }, + { CPU_LOG_TB_IN_ASM, "in_asm", + "show target assembly code for each compiled TB" }, + { CPU_LOG_TB_OP, "op", + "show micro ops for each compiled TB (only usable if 'in_asm' used)" }, +#ifdef TARGET_I386 + { CPU_LOG_TB_OP_OPT, "op_opt", + "show micro ops after optimization for each compiled TB" }, +#endif + { CPU_LOG_INT, "int", + "show interrupts/exceptions in short format" }, + { CPU_LOG_EXEC, "exec", + "show trace before each executed TB (lots of logs)" }, +#ifdef TARGET_I386 + { CPU_LOG_PCALL, "pcall", + "show protected mode far calls/returns/exceptions" }, +#endif + { 0, NULL, NULL }, +}; + +static int cmp1(const char *s1, int n, const char *s2) +{ + if (strlen(s2) != n) + return 0; + return memcmp(s1, s2, n) == 0; +} + +/* takes a comma separated list of log masks. Return 0 if error. */ +int cpu_str_to_log_mask(const char *str) +{ + CPULogItem *item; + int mask; + const char *p, *p1; + + p = str; + mask = 0; + for(;;) { + p1 = strchr(p, ','); + if (!p1) + p1 = p + strlen(p); + for(item = cpu_log_items; item->mask != 0; item++) { + if (cmp1(p, p1 - p, item->name)) + goto found; + } + return 0; + found: + mask |= item->mask; + if (*p1 != ',') + break; + p = p1 + 1; + } + return mask; +} void cpu_abort(CPUState *env, const char *fmt, ...) { diff --git a/gdbstub.c b/gdbstub.c index 29f73c9cb..8774a9d27 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -27,9 +27,7 @@ #include #include -#include "config.h" #include "cpu.h" -#include "thunk.h" #include "exec-all.h" //#define DEBUG_GDB @@ -525,26 +523,8 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) goto breakpoint_error; } break; - case 'Q': - if (!strncmp(p, "Tinit", 5)) { - /* init traces */ - put_packet("OK"); - } else if (!strncmp(p, "TStart", 6)) { - /* start log (gdb 'tstart' command) */ - env = cpu_gdbstub_get_env(opaque); - tb_flush(env); - cpu_set_log(CPU_LOG_ALL); - put_packet("OK"); - } else if (!strncmp(p, "TStop", 5)) { - /* stop log (gdb 'tstop' command) */ - cpu_set_log(0); - put_packet("OK"); - } else { - goto unknown_command; - } - break; default: - unknown_command: + // unknown_command: /* put empty packet */ buf[0] = '\0'; put_packet(buf); diff --git a/monitor.c b/monitor.c index 195a0b007..3d5db9701 100644 --- a/monitor.c +++ b/monitor.c @@ -118,6 +118,14 @@ static void help_cmd(const char *name) help_cmd1(info_cmds, "info ", NULL); } else { help_cmd1(term_cmds, "", name); + if (name && !strcmp(name, "log")) { + CPULogItem *item; + term_printf("Log items (comma separated):\n"); + term_printf("%-10s %s\n", "none", "remove all logs"); + for(item = cpu_log_items; item->mask != 0; item++) { + term_printf("%-10s %s\n", item->name, item->help); + } + } } } @@ -254,6 +262,25 @@ static void do_screen_dump(int argc, const char **argv) vga_screen_dump(argv[1]); } +static void do_log(int argc, const char **argv) +{ + int mask; + + if (argc != 2) + goto help; + if (!strcmp(argv[1], "none")) { + mask = 0; + } else { + mask = cpu_str_to_log_mask(argv[1]); + if (!mask) { + help: + help_cmd(argv[0]); + return; + } + } + cpu_set_log(mask); +} + static term_cmd_t term_cmds[] = { { "help|?", do_help, "[cmd]", "show the help" }, @@ -269,7 +296,9 @@ static term_cmd_t term_cmds[] = { "device filename", "change a removable media" }, { "screendump", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, - { NULL, NULL, }, + { "log", do_log, + "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, + { NULL, NULL, }, }; static term_cmd_t info_cmds[] = { @@ -488,7 +517,6 @@ void term_print_help(void) term_printf("\n" "C-a h print this help\n" "C-a x exit emulatior\n" - "C-a d switch on/off debug log\n" "C-a s save disk data back to file (if -snapshot)\n" "C-a b send break (magic sysrq)\n" "C-a c switch between console and monitor\n" @@ -533,9 +561,6 @@ static void term_received_byte(int ch) term_command = 0; } break; - case 'd': - cpu_set_log(CPU_LOG_ALL); - break; case TERM_ESCAPE: goto send_char; } @@ -558,7 +583,7 @@ static int term_can_read(void *opaque) if (serial_console) { return serial_can_receive(serial_console); } else { - return 1; + return 128; } } diff --git a/thunk.h b/thunk.h index b281319a5..42fd96f3a 100644 --- a/thunk.h +++ b/thunk.h @@ -23,83 +23,6 @@ #include #include "cpu.h" -#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)) -#else -#define tswapl(s) tswap64(s) -#define tswapls(s) tswap64s((uint64_t *)(s)) -#endif - /* types enums definitions */ typedef enum argtype { diff --git a/translate-all.c b/translate-all.c index dd314023b..f10fb6257 100644 --- a/translate-all.c +++ b/translate-all.c @@ -129,7 +129,7 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, } *gen_code_size_ptr = gen_code_size; #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel & CPU_LOG_TB_OUT_ASM) { fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); disas(logfile, tb->tc_ptr, *gen_code_size_ptr, 1, 0); fprintf(logfile, "\n"); @@ -186,7 +186,7 @@ int cpu_restore_state(TranslationBlock *tb, { int cc_op; #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel & CPU_LOG_TB_OP) { int i; fprintf(logfile, "RESTORE:\n"); for(i=0;i<=j; i++) { diff --git a/vl.c b/vl.c index f358dbed8..c3204eb71 100644 --- a/vl.c +++ b/vl.c @@ -47,7 +47,6 @@ #include #include "disas.h" -#include "thunk.h" #include "vl.h" @@ -801,7 +800,7 @@ void help(void) "Debug/Expert options:\n" "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" - "-d output log to %s\n" + "-d item1,... output log to %s (use -d ? for a list of log items)\n" "-hdachs c,h,s force hard disk 0 geometry (usually qemu can guess it)\n" "-L path set the directory for the BIOS and VGA BIOS\n" #ifdef USE_CODE_COPY @@ -916,7 +915,7 @@ int main(int argc, char **argv) } for(;;) { - c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index); + c = getopt_long_only(argc, argv, "hm:d:n:sp:L:", long_options, &long_index); if (c == -1) break; switch(c) { @@ -1037,7 +1036,20 @@ int main(int argc, char **argv) } break; case 'd': - cpu_set_log(CPU_LOG_ALL); + { + int mask; + CPULogItem *item; + + mask = cpu_str_to_log_mask(optarg); + if (!mask) { + printf("Log items (comma separated):\n"); + for(item = cpu_log_items; item->mask != 0; item++) { + printf("%-10s %s\n", item->name, item->help); + } + exit(1); + } + cpu_set_log(mask); + } break; case 'n': pstrcpy(network_script, sizeof(network_script), optarg); -- cgit v1.2.3 From e19e89a5d4e9416f054116765fc0c2674ddd371f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Mar 2004 17:08:23 +0000 Subject: more log items git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@676 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 13 ++++++- target-arm/translate.c | 13 ++++--- target-i386/helper.c | 89 +++++++++++++++++--------------------------- target-i386/translate-copy.c | 2 +- target-i386/translate.c | 14 +++---- target-sparc/translate.c | 10 +++-- 6 files changed, 68 insertions(+), 73 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 5a8292b12..21ddf7aeb 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -847,7 +847,18 @@ int main(int argc, char **argv) if (!strcmp(r, "-")) { break; } else if (!strcmp(r, "d")) { - cpu_set_log(CPU_LOG_ALL); + int mask; + CPULogItem *item; + + mask = cpu_str_to_log_mask(optarg); + if (!mask) { + printf("Log items (comma separated):\n"); + for(item = cpu_log_items; item->mask != 0; item++) { + printf("%-10s %s\n", item->name, item->help); + } + exit(1); + } + cpu_set_log(mask); } else if (!strcmp(r, "s")) { r = argv[optind++]; x86_stack_size = strtol(r, (char **)&r, 0); diff --git a/target-arm/translate.c b/target-arm/translate.c index 3efd55ee3..f405a232f 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -777,15 +777,16 @@ static inline int gen_intermediate_code_internal(CPUState *env, *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - disas(logfile, pc_start, dc->pc - pc_start, 0, 0); - fprintf(logfile, "\n"); - - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); + disas(logfile, pc_start, dc->pc - pc_start, 0, 0); fprintf(logfile, "\n"); + if (loglevel & (CPU_LOG_TB_OP)) { + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } } #endif if (!search_pc) diff --git a/target-i386/helper.c b/target-i386/helper.c index 6fc136763..d08de8a8b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -290,7 +290,7 @@ static void switch_tss(int tss_selector, type = (e2 >> DESC_TYPE_SHIFT) & 0xf; #ifdef DEBUG_PCALL - if (loglevel) + if (loglevel & CPU_LOG_PCALL) fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source); #endif @@ -858,68 +858,43 @@ void do_interrupt_user(int intno, int is_int, int error_code, } /* - * Begin excution of an interruption. is_int is TRUE if coming from + * Begin execution of an interruption. is_int is TRUE if coming from * the int instruction. next_eip is the EIP value AFTER the interrupt * instruction. It is only relevant if is_int is TRUE. */ void do_interrupt(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw) { -#if 0 - { - extern FILE *stdout; - static int count; - if (env->cr[0] & CR0_PE_MASK) { - fprintf(stdout, "%d: v=%02x e=%04x i=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x", +#ifdef DEBUG_PCALL + if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) { + if ((env->cr[0] & CR0_PE_MASK)) { + static int count; + fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x SP=%04x:%08x", count, intno, error_code, is_int, env->hflags & HF_CPL_MASK, env->segs[R_CS].selector, EIP, env->segs[R_SS].selector, ESP); if (intno == 0x0e) { - fprintf(stdout, " CR2=%08x", env->cr[2]); + fprintf(logfile, " CR2=%08x", env->cr[2]); } else { - fprintf(stdout, " EAX=%08x", env->regs[R_EAX]); + fprintf(logfile, " EAX=%08x", env->regs[R_EAX]); } - fprintf(stdout, "\n"); - - if (0) { - cpu_x86_dump_state(env, stdout, X86_DUMP_CCOP); + fprintf(logfile, "\n"); #if 0 - { - int i; - uint8_t *ptr; - fprintf(stdout, " code="); - ptr = env->segs[R_CS].base + env->eip; - for(i = 0; i < 16; i++) { - fprintf(stdout, " %02x", ldub(ptr + i)); - } - fprintf(stdout, "\n"); + cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); + { + int i; + uint8_t *ptr; + fprintf(logfile, " code="); + ptr = env->segs[R_CS].base + env->eip; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); } -#endif + fprintf(logfile, "\n"); } - count++; - } - } #endif -#ifdef DEBUG_PCALL - if (loglevel) { - static int count; - fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", - count, intno, error_code, is_int); - cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); -#if 0 - { - int i; - uint8_t *ptr; - fprintf(logfile, " code="); - ptr = env->segs[R_CS].base + env->eip; - for(i = 0; i < 16; i++) { - fprintf(logfile, " %02x", ldub(ptr + i)); - } - fprintf(logfile, "\n"); + count++; } -#endif - count++; } #endif if (env->cr[0] & CR0_PE_MASK) { @@ -1365,9 +1340,9 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) new_cs = T0; new_eip = T1; #ifdef DEBUG_PCALL - if (loglevel) { - fprintf(logfile, "lcall %04x:%08x\n", - new_cs, new_eip); + if (loglevel & CPU_LOG_PCALL) { + fprintf(logfile, "lcall %04x:%08x s=%d\n", + new_cs, new_eip, shift); cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); } #endif @@ -1377,7 +1352,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); cpl = env->hflags & HF_CPL_MASK; #ifdef DEBUG_PCALL - if (loglevel) { + if (loglevel & CPU_LOG_PCALL) { fprintf(logfile, "desc=%08x:%08x\n", e1, e2); } #endif @@ -1466,8 +1441,8 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) /* to inner priviledge */ get_ss_esp_from_tss(&ss, &sp, dpl); #ifdef DEBUG_PCALL - if (loglevel) - fprintf(logfile, "ss=%04x sp=%04x param_count=%d ESP=%x\n", + if (loglevel & CPU_LOG_PCALL) + fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=%x\n", ss, sp, param_count, ESP); #endif if ((ss & 0xfffc) == 0) @@ -1626,9 +1601,9 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) POPW(ssp, sp, sp_mask, new_eflags); } #ifdef DEBUG_PCALL - if (loglevel) { - fprintf(logfile, "lret new %04x:%08x addend=0x%x\n", - new_cs, new_eip, addend); + if (loglevel & CPU_LOG_PCALL) { + fprintf(logfile, "lret new %04x:%08x s=%d addend=0x%x\n", + new_cs, new_eip, shift, addend); cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); } #endif @@ -1673,6 +1648,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) POPW(ssp, sp, sp_mask, new_esp); POPW(ssp, sp, sp_mask, new_ss); } +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_PCALL) { + fprintf(logfile, "new ss:esp=%04x:%08x\n", + new_ss, new_esp); + } +#endif if ((new_ss & 3) != rpl) raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index 08775e618..fb0bcaa3c 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -1237,7 +1237,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, } #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "IN: COPY: %s fpu=%d\n", lookup_symbol(pc_start), diff --git a/target-i386/translate.c b/target-i386/translate.c index f9823a49d..12a74435f 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4595,16 +4595,16 @@ static inline int gen_intermediate_code_internal(CPUState *env, } #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32); fprintf(logfile, "\n"); -#if 0 - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); -#endif + if (loglevel & CPU_LOG_TB_OP) { + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } } #endif @@ -4612,7 +4612,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf); #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel & CPU_LOG_TB_OP_OPT) { fprintf(logfile, "AFTER FLAGS OPT:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 321b4eba4..41decb18f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -800,14 +800,16 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, } *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "--------------\n"); fprintf(logfile, "IN: %s\n", lookup_symbol((uint8_t *)pc_start)); disas(logfile, (uint8_t *)pc_start, last_pc + 4 - pc_start, 0, 0); fprintf(logfile, "\n"); - fprintf(logfile, "OP:\n"); - dump_ops(gen_opc_buf, gen_opparam_buf); - fprintf(logfile, "\n"); + if (loglevel & CPU_LOG_TB_OP) { + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } } #endif -- cgit v1.2.3 From d9d849fc5dc755e5bfeecd889cb28f00486510eb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Mar 2004 17:12:48 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@677 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 321f5fd65..95d997066 100644 --- a/Changelog +++ b/Changelog @@ -19,6 +19,7 @@ version 0.5.3: - 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) version 0.5.2: -- cgit v1.2.3 From 11774f549e2a85ddeb5b99a16bc3a31a0e753565 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Mar 2004 18:28:57 +0000 Subject: protected lret x86 'bug' emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@678 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index d08de8a8b..3d44cc86b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1679,7 +1679,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) ss_e2); cpu_x86_set_cpl(env, rpl); sp = new_esp; - /* XXX: change sp_mask according to old segment ? */ + sp_mask = get_sp_mask(ss_e2); /* validate data segments */ validate_seg(R_ES, cpl); -- cgit v1.2.3 From 5e2a64439961691d13835e9fdec9c6c972d8a4a5 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 23 Mar 2004 22:42:11 +0000 Subject: removed most of global context uses - removed unneeded abort() which cause problems during win95 hardware scan git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@679 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sb16.c | 288 ++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 138 insertions(+), 150 deletions(-) diff --git a/hw/sb16.c b/hw/sb16.c index aee1d5fbd..147d5c822 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -33,10 +33,6 @@ #define DEREF(x) (void)x #define log(...) fprintf (stderr, "sb16: " __VA_ARGS__) -#define Fail(...) do { \ - fprintf (stderr, "sb16: " __VA_ARGS__); \ - abort (); \ -} while (0) /* #define DEBUG_SB16 */ #ifdef DEBUG_SB16 @@ -66,12 +62,7 @@ static struct { static int mix_block, noirq; -static struct mixer { - int nreg; - uint8_t regs[0x83]; -} mixer; - -static struct dsp { +typedef struct SB16State { int in_index; int out_data_len; int fmt_stereo; @@ -94,24 +85,27 @@ static struct dsp { uint8_t out_data[10]; int left_till_irq; -} dsp; -#define nocmd ~0 + /* mixer state */ + int mixer_nreg; + uint8_t mixer_regs[0x83]; +} SB16State; -static void log_dsp (const char *cap) -{ - DEREF (cap); +/* XXX: suppress that and use a context */ +static struct SB16State dsp; +static void log_dsp (SB16State *dsp) +{ linfo ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n", - dsp.fmt_stereo ? 'S' : 'M', - dsp.fmt_signed ? 'S' : 'U', - dsp.fmt_bits, - dsp.dma_auto ? 'a' : 's', - dsp.dma_buffer_size, - dsp.dma_pos, - dsp.freq, - dsp.time_const, - dsp.speaker); + dsp->fmt_stereo ? 'S' : 'M', + dsp->fmt_signed ? 'S' : 'U', + dsp->fmt_bits, + dsp->dma_auto ? 'a' : 's', + dsp->dma_buffer_size, + dsp->dma_pos, + dsp->freq, + dsp->time_const, + dsp->speaker); } static void control (int hold) @@ -203,12 +197,8 @@ static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len) dsp.speaker = 1; } -static void command (uint8_t cmd) +static void command (SB16State *dsp, uint8_t cmd) { - char *msg; - - msg = (char *) -1; - linfo ("%#x\n", cmd); if (cmd > 0xaf && cmd < 0xd0) { @@ -220,10 +210,10 @@ static void command (uint8_t cmd) case 12: break; default: - msg = "wrong bits"; + log("%#x wrong bits", cmd); goto error; } - dsp.needed_bytes = 3; + dsp->needed_bytes = 3; } else { switch (cmd) { @@ -234,16 +224,16 @@ static void command (uint8_t cmd) return; case 0x10: - dsp.needed_bytes = 1; + dsp->needed_bytes = 1; break; case 0x14: - dsp.needed_bytes = 2; - dsp.dma_buffer_size = 0; + dsp->needed_bytes = 2; + dsp->dma_buffer_size = 0; break; case 0x20: - dsp.out_data[dsp.out_data_len++] = 0xff; + dsp->out_data[dsp->out_data_len++] = 0xff; break; case 0x35: @@ -251,23 +241,23 @@ static void command (uint8_t cmd) break; case 0x40: - dsp.freq = -1; - dsp.time_const = -1; - dsp.needed_bytes = 1; + dsp->freq = -1; + dsp->time_const = -1; + dsp->needed_bytes = 1; break; case 0x41: case 0x42: - dsp.freq = -1; - dsp.time_const = -1; - dsp.needed_bytes = 2; + dsp->freq = -1; + dsp->time_const = -1; + dsp->needed_bytes = 2; break; case 0x47: /* Continue Auto-Initialize DMA 16bit */ break; case 0x48: - dsp.needed_bytes = 2; + dsp->needed_bytes = 2; break; case 0x27: /* ????????? */ @@ -275,7 +265,7 @@ static void command (uint8_t cmd) return; case 0x80: - cmd = nocmd; + cmd = -1; break; case 0x90: @@ -284,10 +274,10 @@ static void command (uint8_t cmd) uint8_t d0; d0 = 4; - if (dsp.fmt_signed) d0 |= 16; - if (dsp.fmt_stereo) d0 |= 32; + if (dsp->fmt_signed) d0 |= 16; + if (dsp->fmt_stereo) d0 |= 32; dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1); - cmd = nocmd; + cmd = -1; break; } @@ -296,11 +286,11 @@ static void command (uint8_t cmd) return; case 0xd1: - dsp.speaker = 1; + dsp->speaker = 1; break; case 0xd3: - dsp.speaker = 0; + dsp->speaker = 0; return; case 0xd4: @@ -317,60 +307,59 @@ static void command (uint8_t cmd) case 0xd9: control (0); - dsp.dma_auto = 0; + dsp->dma_auto = 0; return; case 0xda: control (0); - dsp.dma_auto = 0; + dsp->dma_auto = 0; break; case 0xe0: - dsp.needed_bytes = 1; + dsp->needed_bytes = 1; break; case 0xe1: - dsp.out_data[dsp.out_data_len++] = sb.ver_lo; - dsp.out_data[dsp.out_data_len++] = sb.ver_hi; + dsp->out_data[dsp->out_data_len++] = sb.ver_lo; + dsp->out_data[dsp->out_data_len++] = sb.ver_hi; return; case 0xf2: - dsp.out_data[dsp.out_data_len++] = 0xaa; - mixer.regs[0x82] |= mixer.regs[0x80]; + dsp->out_data[dsp->out_data_len++] = 0xaa; + dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; pic_set_irq (sb.irq, 1); return; default: - msg = "is unknown"; + log("%#x is unknown", cmd); goto error; } } - dsp.cmd = cmd; + dsp->cmd = cmd; return; error: - Fail ("%#x %s", cmd, msg); return; } -static void complete (void) +static void complete (SB16State *dsp) { linfo ("complete command %#x, in_index %d, needed_bytes %d\n", - dsp.cmd, dsp.in_index, dsp.needed_bytes); + dsp->cmd, dsp->in_index, dsp->needed_bytes); - if (dsp.cmd > 0xaf && dsp.cmd < 0xd0) { + if (dsp->cmd > 0xaf && dsp->cmd < 0xd0) { int d0, d1, d2; - d0 = dsp.in_data[0]; - d1 = dsp.in_data[1]; - d2 = dsp.in_data[2]; + d0 = dsp->in_data[0]; + d1 = dsp->in_data[1]; + d2 = dsp->in_data[2]; ldebug ("d0 = %d, d1 = %d, d2 = %d\n", d0, d1, d2); - dma_cmd (dsp.cmd, d0, d1 + (d2 << 8)); + dma_cmd (dsp->cmd, d0, d1 + (d2 << 8)); } else { - switch (dsp.cmd) { + switch (dsp->cmd) { case 0x10: break; @@ -381,58 +370,57 @@ static void complete (void) int save_left; int save_pos; - d0 = dsp.in_data[0]; - d1 = dsp.in_data[1]; + d0 = dsp->in_data[0]; + d1 = dsp->in_data[1]; - save_left = dsp.left_till_irq; - save_pos = dsp.dma_pos; + save_left = dsp->left_till_irq; + save_pos = dsp->dma_pos; dma_cmd (0xc0, 0, d0 + (d1 << 8)); - dsp.left_till_irq = save_left; - dsp.dma_pos = save_pos; + dsp->left_till_irq = save_left; + dsp->dma_pos = save_pos; linfo ("set buffer size data[%d, %d] %d pos %d\n", - d0, d1, dsp.dma_buffer_size, dsp.dma_pos); + d0, d1, dsp->dma_buffer_size, dsp->dma_pos); break; } case 0x40: - dsp.time_const = dsp.in_data[0]; - linfo ("set time const %d\n", dsp.time_const); + dsp->time_const = dsp->in_data[0]; + linfo ("set time const %d\n", dsp->time_const); break; case 0x41: case 0x42: - dsp.freq = dsp.in_data[1] + (dsp.in_data[0] << 8); + dsp->freq = dsp->in_data[1] + (dsp->in_data[0] << 8); linfo ("set freq %#x, %#x = %d\n", - dsp.in_data[1], dsp.in_data[0], dsp.freq); + dsp->in_data[1], dsp->in_data[0], dsp->freq); break; case 0x48: - dsp.dma_buffer_size = dsp.in_data[1] + (dsp.in_data[0] << 8); + dsp->dma_buffer_size = dsp->in_data[1] + (dsp->in_data[0] << 8); linfo ("set dma len %#x, %#x = %d\n", - dsp.in_data[1], dsp.in_data[0], dsp.dma_buffer_size); + dsp->in_data[1], dsp->in_data[0], dsp->dma_buffer_size); break; case 0xe0: - dsp.out_data_len = 1; - linfo ("data = %#x\n", dsp.in_data[0]); - dsp.out_data[0] = dsp.in_data[0] ^ 0xff; + dsp->out_data_len = 1; + linfo ("data = %#x\n", dsp->in_data[0]); + dsp->out_data[0] = dsp->in_data[0] ^ 0xff; break; default: - goto error; + log ("unrecognized command %#x", dsp->cmd); + return; } } - dsp.cmd = -1; + dsp->cmd = -1; return; - - error: - Fail ("unrecognized command %#x", dsp.cmd); } static IO_WRITE_PROTO (dsp_write) { + SB16State *dsp = opaque; int iport; iport = nport - sb.port; @@ -440,44 +428,44 @@ static IO_WRITE_PROTO (dsp_write) switch (iport) { case 0x6: if (0 == val) - dsp.v2x6 = 0; - else if ((1 == val) && (0 == dsp.v2x6)) { - dsp.v2x6 = 1; - dsp.out_data[dsp.out_data_len++] = 0xaa; + dsp->v2x6 = 0; + else if ((1 == val) && (0 == dsp->v2x6)) { + dsp->v2x6 = 1; + dsp->out_data[dsp->out_data_len++] = 0xaa; } else - dsp.v2x6 = ~0; + dsp->v2x6 = ~0; break; case 0xc: /* write data or command | write status */ - if (0 == dsp.needed_bytes) { - command (val); - if (0 == dsp.needed_bytes) { - log_dsp (__func__); + if (0 == dsp->needed_bytes) { + command (dsp, val); + if (0 == dsp->needed_bytes) { + log_dsp (dsp); } } else { - dsp.in_data[dsp.in_index++] = val; - if (dsp.in_index == dsp.needed_bytes) { - dsp.needed_bytes = 0; - dsp.in_index = 0; - complete (); - log_dsp (__func__); + dsp->in_data[dsp->in_index++] = val; + if (dsp->in_index == dsp->needed_bytes) { + dsp->needed_bytes = 0; + dsp->in_index = 0; + complete (dsp); + log_dsp (dsp); } } break; default: - Fail ("(nport=%#x, val=%#x)", nport, val); + log ("(nport=%#x, val=%#x)", nport, val); + break; } } static IO_READ_PROTO (dsp_read) { - char *msg; + SB16State *dsp = opaque; int iport, retval; - msg = (char *) -1; iport = nport - sb.port; switch (iport) { @@ -486,17 +474,11 @@ static IO_READ_PROTO (dsp_read) return 0; case 0xa: /* read data */ - if (dsp.out_data_len) { - retval = dsp.out_data[--dsp.out_data_len]; - } - else { -#if 1 - lwarn ("empty output buffer\n"); - retval = 0; -#else - msg = "empty output buffer"; + if (dsp->out_data_len) { + retval = dsp->out_data[--dsp->out_data_len]; + } else { + log("empty output buffer\n"); goto error; -#endif } break; @@ -505,13 +487,14 @@ static IO_READ_PROTO (dsp_read) break; case 0xd: /* timer interrupt clear */ + log("timer interrupt clear\n"); goto error; case 0xe: /* data available status | irq 8 ack */ /* XXX drop pic irq line here? */ ldebug ("8 ack\n"); - retval = (0 == dsp.out_data_len) ? 0 : 0x80; - mixer.regs[0x82] &= ~mixer.regs[0x80]; + retval = (0 == dsp->out_data_len) ? 0 : 0x80; + dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80]; pic_set_irq (sb.irq, 0); break; @@ -519,7 +502,7 @@ static IO_READ_PROTO (dsp_read) /* XXX drop pic irq line here? */ ldebug ("16 ack\n"); retval = 0xff; - mixer.regs[0x82] &= ~mixer.regs[0x80]; + dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80]; pic_set_irq (sb.irq, 0); break; @@ -535,17 +518,19 @@ static IO_READ_PROTO (dsp_read) return retval; error: - Fail ("(nport=%#x) %s", nport, msg); + return 0; } static IO_WRITE_PROTO(mixer_write_indexb) { - mixer.nreg = val & 0xff; + SB16State *dsp = opaque; + dsp->mixer_nreg = val & 0xff; } static IO_WRITE_PROTO(mixer_write_datab) { - mixer.regs[mixer.nreg] = val; + SB16State *dsp = opaque; + dsp->mixer_regs[dsp->mixer_nreg] = val; } static IO_WRITE_PROTO(mixer_write_indexw) @@ -556,7 +541,8 @@ static IO_WRITE_PROTO(mixer_write_indexw) static IO_READ_PROTO(mixer_read) { - return mixer.regs[mixer.nreg]; + SB16State *dsp = opaque; + return dsp->mixer_regs[dsp->mixer_nreg]; } void SB16_run (void) @@ -607,20 +593,21 @@ static int write_audio (uint32_t addr, int len, int size) static int SB_read_DMA (void *opaque, target_ulong addr, int size) { + SB16State *dsp = opaque; int free, till, copy, written; - if (0 == dsp.speaker) + if (0 == dsp->speaker) return 0; - if (dsp.left_till_irq < 0) { - dsp.left_till_irq += dsp.dma_buffer_size; - return dsp.dma_pos; + if (dsp->left_till_irq < 0) { + dsp->left_till_irq += dsp->dma_buffer_size; + return dsp->dma_pos; } free = AUD_get_free (); if ((free <= 0) || (0 == size)) { - return dsp.dma_pos; + return dsp->dma_pos; } if (mix_block > 0) { @@ -630,41 +617,41 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) copy = free; } - till = dsp.left_till_irq; + till = dsp->left_till_irq; ldebug ("addr:%#010x free:%d till:%d size:%d\n", addr, free, till, size); if (till <= copy) { - if (0 == dsp.dma_auto) { + if (0 == dsp->dma_auto) { copy = till; } } written = write_audio (addr, size, copy); - dsp.left_till_irq -= written; + dsp->left_till_irq -= written; AUD_adjust_estimate (free - written); - if (dsp.left_till_irq <= 0) { - mixer.regs[0x82] |= mixer.regs[0x80]; + if (dsp->left_till_irq <= 0) { + dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; if (0 == noirq) { ldebug ("request irq\n"); pic_set_irq(sb.irq, 1); } - if (0 == dsp.dma_auto) { + if (0 == dsp->dma_auto) { control (0); } } ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n", - dsp.dma_pos, free, size, dsp.left_till_irq, copy, - dsp.dma_buffer_size); + dsp->dma_pos, free, size, dsp->left_till_irq, copy, + dsp->dma_buffer_size); - if (dsp.left_till_irq <= 0) { - dsp.left_till_irq += dsp.dma_buffer_size; + if (dsp->left_till_irq <= 0) { + dsp->left_till_irq += dsp->dma_buffer_size; } - return dsp.dma_pos; + return dsp->dma_pos; } static int magic_of_irq (int irq) @@ -703,33 +690,34 @@ static int irq_of_magic (int magic) void SB16_init (void) { + SB16State *s = &dsp; int i; static const uint8_t dsp_write_ports[] = {0x6, 0xc}; static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; - mixer.regs[0x0e] = ~0; - mixer.regs[0x80] = magic_of_irq (sb.irq); - mixer.regs[0x81] = 0x20 | (sb.dma << 1); + s->mixer_regs[0x0e] = ~0; + s->mixer_regs[0x80] = magic_of_irq (sb.irq); + s->mixer_regs[0x81] = 0x20 | (sb.dma << 1); DEREF (irq_of_magic); for (i = 0x30; i < 0x48; i++) { - mixer.regs[i] = 0x20; + s->mixer_regs[i] = 0x20; } for (i = 0; i < LENOFA (dsp_write_ports); i++) { - register_ioport_write (sb.port + dsp_write_ports[i], 1, 1, dsp_write, NULL); + register_ioport_write (sb.port + dsp_write_ports[i], 1, 1, dsp_write, s); } for (i = 0; i < LENOFA (dsp_read_ports); i++) { - register_ioport_read (sb.port + dsp_read_ports[i], 1, 1, dsp_read, NULL); + register_ioport_read (sb.port + dsp_read_ports[i], 1, 1, dsp_read, s); } - register_ioport_write (sb.port + 0x4, 1, 1, mixer_write_indexb, NULL); - register_ioport_write (sb.port + 0x4, 1, 2, mixer_write_indexw, NULL); - register_ioport_read (sb.port + 0x5, 1, 1, mixer_read, NULL); - register_ioport_write (sb.port + 0x5, 1, 1, mixer_write_datab, NULL); + register_ioport_write (sb.port + 0x4, 1, 1, mixer_write_indexb, s); + register_ioport_write (sb.port + 0x4, 1, 2, mixer_write_indexw, s); + register_ioport_read (sb.port + 0x5, 1, 1, mixer_read, s); + register_ioport_write (sb.port + 0x5, 1, 1, mixer_write_datab, s); - DMA_register_channel (sb.hdma, SB_read_DMA, NULL); - DMA_register_channel (sb.dma, SB_read_DMA, NULL); + DMA_register_channel (sb.hdma, SB_read_DMA, s); + DMA_register_channel (sb.dma, SB_read_DMA, s); } -- cgit v1.2.3 From 78ebca6e134ddb1da6d9623986c1c9990332eabc Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 23 Mar 2004 22:42:43 +0000 Subject: fixed IDE probe git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@680 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index 906c67f7a..430e5afd5 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1269,7 +1269,7 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) if (!s->bs) ret = 0; else - ret = s->select; + ret = s->select | 0xa0; break; default: case 7: -- cgit v1.2.3 From 883da8e21932b24630f87ed4d801ea1ad48b735b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 24 Mar 2004 00:50:26 +0000 Subject: task switch fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@681 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 3d44cc86b..623943631 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -277,7 +277,8 @@ static void tss_load_seg(int seg_reg, int selector) /* XXX: restore CPU state in registers (PowerPC case) */ static void switch_tss(int tss_selector, - uint32_t e1, uint32_t e2, int source) + uint32_t e1, uint32_t e2, int source, + uint32_t next_eip) { int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; uint8_t *tss_base; @@ -369,7 +370,7 @@ static void switch_tss(int tss_selector, if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { uint8_t *ptr; uint32_t e2; - ptr = env->gdt.base + (env->tr.selector << 3); + ptr = env->gdt.base + (env->tr.selector & ~7); e2 = ldl_kernel(ptr + 4); e2 &= ~DESC_TSS_BUSY_MASK; stl_kernel(ptr + 4, e2); @@ -381,7 +382,7 @@ static void switch_tss(int tss_selector, /* save the current state in the old TSS */ if (type & 8) { /* 32 bit */ - stl_kernel(env->tr.base + 0x20, env->eip); + stl_kernel(env->tr.base + 0x20, next_eip); stl_kernel(env->tr.base + 0x24, old_eflags); for(i = 0; i < 8; i++) stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]); @@ -389,7 +390,7 @@ static void switch_tss(int tss_selector, stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); } else { /* 16 bit */ - stw_kernel(env->tr.base + 0x0e, new_eip); + stw_kernel(env->tr.base + 0x0e, next_eip); stw_kernel(env->tr.base + 0x10, old_eflags); for(i = 0; i < 8; i++) stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]); @@ -409,7 +410,7 @@ static void switch_tss(int tss_selector, if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { uint8_t *ptr; uint32_t e2; - ptr = env->gdt.base + (tss_selector << 3); + ptr = env->gdt.base + (tss_selector & ~7); e2 = ldl_kernel(ptr + 4); e2 |= DESC_TSS_BUSY_MASK; stl_kernel(ptr + 4, e2); @@ -418,6 +419,7 @@ static void switch_tss(int tss_selector, /* set the new CPU state */ /* from this point, any exception which occurs can give problems */ env->cr[0] |= CR0_TS_MASK; + env->hflags |= HF_TS_MASK; env->tr.selector = tss_selector; env->tr.base = tss_base; env->tr.limit = tss_limit; @@ -486,6 +488,7 @@ static void switch_tss(int tss_selector, /* check that EIP is in the CS segment limits */ if (new_eip > env->segs[R_CS].limit) { + /* XXX: different exception if CALL ? */ raise_exception_err(EXCP0D_GPF, 0); } } @@ -603,6 +606,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, break; } } + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; dt = &env->idt; if (intno * 8 + 7 > dt->limit) @@ -617,7 +624,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, /* must do that check here to return the correct error code */ if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); - switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL); + switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); if (has_error_code) { int mask; /* push the error code */ @@ -713,10 +720,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, push_size += 8; push_size <<= shift; #endif - if (is_int) - old_eip = next_eip; - else - old_eip = env->eip; if (shift == 1) { if (new_stack) { if (env->eflags & VM_MASK) { @@ -1264,7 +1267,8 @@ void helper_ljmp_protected_T0_T1(void) case 5: /* task gate */ if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP); + /* XXX: check if it is really the current EIP */ + switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, env->eip); break; case 4: /* 286 call gate */ case 12: /* 386 call gate */ @@ -1405,7 +1409,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) case 5: /* task gate */ if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL); + switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); return; case 4: /* 286 call gate */ case 12: /* 386 call gate */ @@ -1744,7 +1748,8 @@ void helper_iret_protected(int shift) /* NOTE: we check both segment and busy TSS */ if (type != 3) raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); - switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET); + /* XXX: check if it is really the current EIP */ + switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, env->eip); } else { helper_ret_protected(shift, 1, 0); } -- cgit v1.2.3 From 08cea4eef8e17114dcdbce93f95cb111c9d622f6 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 26 Mar 2004 22:26:53 +0000 Subject: fixed ljmp and iret to TSS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@682 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 4 ++-- target-i386/helper.c | 10 ++++------ target-i386/op.c | 4 ++-- target-i386/translate.c | 4 ++-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 3f6ddf1b4..63010f745 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -123,11 +123,11 @@ typedef struct CCTable { extern CCTable cc_table[]; void load_seg(int seg_reg, int selector); -void helper_ljmp_protected_T0_T1(void); +void helper_ljmp_protected_T0_T1(int next_eip); void helper_lcall_real_T0_T1(int shift, int next_eip); void helper_lcall_protected_T0_T1(int shift, int next_eip); void helper_iret_real(int shift); -void helper_iret_protected(int shift); +void helper_iret_protected(int shift, int next_eip); void helper_lret_protected(int shift, int addend); void helper_lldt_T0(void); void helper_ltr_T0(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 623943631..dbdabd82e 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1219,7 +1219,7 @@ void load_seg(int seg_reg, int selector) } /* protected mode jump */ -void helper_ljmp_protected_T0_T1(void) +void helper_ljmp_protected_T0_T1(int next_eip) { int new_cs, new_eip, gate_cs, type; uint32_t e1, e2, cpl, dpl, rpl, limit; @@ -1267,8 +1267,7 @@ void helper_ljmp_protected_T0_T1(void) case 5: /* task gate */ if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - /* XXX: check if it is really the current EIP */ - switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, env->eip); + switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); break; case 4: /* 286 call gate */ case 12: /* 386 call gate */ @@ -1732,7 +1731,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) ESP = new_esp; } -void helper_iret_protected(int shift) +void helper_iret_protected(int shift, int next_eip) { int tss_selector, type; uint32_t e1, e2; @@ -1748,8 +1747,7 @@ void helper_iret_protected(int shift) /* NOTE: we check both segment and busy TSS */ if (type != 3) raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); - /* XXX: check if it is really the current EIP */ - switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, env->eip); + switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip); } else { helper_ret_protected(shift, 1, 0); } diff --git a/target-i386/op.c b/target-i386/op.c index f592b67a6..1169f121a 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -918,7 +918,7 @@ void OPPROTO op_arpl_update(void) /* T0: segment, T1:eip */ void OPPROTO op_ljmp_protected_T0_T1(void) { - helper_ljmp_protected_T0_T1(); + helper_ljmp_protected_T0_T1(PARAM1); } void OPPROTO op_lcall_real_T0_T1(void) @@ -938,7 +938,7 @@ void OPPROTO op_iret_real(void) void OPPROTO op_iret_protected(void) { - helper_iret_protected(PARAM1); + helper_iret_protected(PARAM1, PARAM2); } void OPPROTO op_lret_protected(void) diff --git a/target-i386/translate.c b/target-i386/translate.c index 12a74435f..4a1a2767a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2172,7 +2172,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_jmp_im(pc_start - s->cs_base); - gen_op_ljmp_protected_T0_T1(); + gen_op_ljmp_protected_T0_T1(s->pc - s->cs_base); } else { gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); gen_op_movl_T0_T1(); @@ -3453,7 +3453,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_jmp_im(pc_start - s->cs_base); - gen_op_iret_protected(s->dflag); + gen_op_iret_protected(s->dflag, s->pc - s->cs_base); s->cc_op = CC_OP_EFLAGS; } gen_eob(s); -- cgit v1.2.3 From 4bb2fcc7c9776d3a3732dc3731fd1107fb5b8c27 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 26 Mar 2004 22:38:57 +0000 Subject: gcc 2.95.4 compile fix (Petter Reinholdtsen) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@683 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 4a1a2767a..5866fe409 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -391,7 +391,7 @@ static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { }, static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { - DEF_ARITHC() + DEF_ARITHC( ) }; static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[9][2] = { @@ -420,7 +420,7 @@ static const int cc_op_arithb[8] = { static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { - DEF_CMPXCHG() + DEF_CMPXCHG( ) }; static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = { @@ -464,7 +464,7 @@ static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = { }, static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { - DEF_SHIFT() + DEF_SHIFT( ) }; static GenOpFunc *gen_op_shift_mem_T0_T1_cc[9][8] = { @@ -4277,7 +4277,7 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C, - DEF_READF() + DEF_READF( ) DEF_READF(_raw) #ifndef CONFIG_USER_ONLY DEF_READF(_kernel) @@ -4396,7 +4396,7 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC, - DEF_WRITEF() + DEF_WRITEF( ) DEF_WRITEF(_raw) #ifndef CONFIG_USER_ONLY DEF_WRITEF(_kernel) @@ -4435,7 +4435,7 @@ static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorw ## SUFFIX ## _T0_T1,\ [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorl ## SUFFIX ## _T0_T1, - DEF_SIMPLER() + DEF_SIMPLER( ) DEF_SIMPLER(_raw) #ifndef CONFIG_USER_ONLY DEF_SIMPLER(_kernel) -- cgit v1.2.3 From c101c49c546f407466a672dcb2c8dda6bf3cbf7f Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 26 Mar 2004 22:42:54 +0000 Subject: added qemu-mkcow man page git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@684 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- qemu-mkcow.1 | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 qemu-mkcow.1 diff --git a/Makefile b/Makefile index 11f791550..e55c072af 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ install: all install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/linux_boot.bin $(sharedir) mkdir -p $(mandir)/man1 - install qemu.1 $(mandir)/man1 + install qemu.1 qemu-mkcow.1 $(mandir)/man1 for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done diff --git a/qemu-mkcow.1 b/qemu-mkcow.1 new file mode 100644 index 000000000..5e1a6812b --- /dev/null +++ b/qemu-mkcow.1 @@ -0,0 +1,105 @@ +.\" $Header: /home/paul/qemu/svnmerge/qemu-cvs/qemu/qemu-mkcow.1,v 1.1 2004-03-26 22:42:54 bellard Exp $ +.\" +.\" transcript compatibility for postscript use. +.\" +.\" synopsis: .P! +.\" +.de P! +.fl +\!!1 setgray +.fl +\\&.\" +.fl +\!!0 setgray +.fl \" force out current output buffer +\!!save /psv exch def currentpoint translate 0 0 moveto +\!!/showpage{}def +.fl \" prolog +.sy sed -e 's/^/!/' \\$1\" bring in postscript file +\!!psv restore +. +.de pF +.ie \\*(f1 .ds f1 \\n(.f +.el .ie \\*(f2 .ds f2 \\n(.f +.el .ie \\*(f3 .ds f3 \\n(.f +.el .ie \\*(f4 .ds f4 \\n(.f +.el .tm ? font overflow +.ft \\$1 +.. +.de fP +.ie !\\*(f4 \{\ +. ft \\*(f4 +. ds f4\" +' br \} +.el .ie !\\*(f3 \{\ +. ft \\*(f3 +. ds f3\" +' br \} +.el .ie !\\*(f2 \{\ +. ft \\*(f2 +. ds f2\" +' br \} +.el .ie !\\*(f1 \{\ +. ft \\*(f1 +. ds f1\" +' br \} +.el .tm ? font underflow +.. +.ds f1\" +.ds f2\" +.ds f3\" +.ds f4\" +'\" t +.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n +.TH "QEMU" "8" +.SH "NAME" +qemu-mkcow \(em create a copy-on-write file for qemu +.SH "SYNOPSIS" +.PP +\fBqemu-mkcow\fR [\fB-h\fP] [\fB-f \fImaster_disk_image\fR\fP] [\fIcow_image\fR] [\fB\fIcow_size\fR\fP] +.SH "DESCRIPTION" +.PP +The \fBqemu-mkcow\fR command creates a +persistent copy-on-write file for \fBqemu\fR. + +.PP +\fBqemu\fR can be used in a "copy-on-write" mode, +where changes made by \fBqemu\fR do not actually +change the disk image file. One way is to invoke +\fBqemu\fR with -snapshot: these changes +are stored in a temporary file, which is discarded when +\fBqemu\fR exits. + +.PP +\fBqemu-mkcow\fR creates an explicit copy-on-write +file where changes are to be stored: this way, changes made +inside \fBqemu\fR will still be there next time you +run it, although the master disk image isn't ever changed. + +.PP +The usual method is to create the master image, then create a +copy-on-write file using \fBqemu-mkcow\fR with +\fB-f\fP. The filename of the master image is stored +inside the generated copy-on-write file: it must not be modified +after this is run! + +.PP +If no master file is specified, the effect is that of a +blank master of size \fIcow_size\fR. + +.SH "SEE ALSO" +.PP +qemu(1), qemu-fast(1). +.SH "AUTHOR" +.PP +This manual page was written by Paul Russell prussell@debian.org for +the \fBDebian\fP system (but may be used by others). Permission is +granted to copy, distribute and/or modify this document under +the terms of the GNU General Public License, Version 2 any +later version published by the Free Software Foundation. + +.PP +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL. + +.\" created by instant / docbook-to-man, Fri 12 Mar 2004, 05:58 -- cgit v1.2.3 From 9b14bb04ca9c747173ff947458c46f7416653dad Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 26 Mar 2004 22:43:34 +0000 Subject: install fix (Rusty Russel) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@685 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.target b/Makefile.target index 0d38b1d73..07fa4568d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -302,7 +302,9 @@ clean: rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o install: all +ifneq ($(PROGS),) install -m 755 -s $(PROGS) $(prefix)/bin +endif ifneq ($(wildcard .depend),) include .depend -- cgit v1.2.3 From 858693c63813f91ee3a0140bf3dfe5a069070eea Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 31 Mar 2004 18:52:07 +0000 Subject: moved gdbstub to qemu - new asynchronous gdbstub git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@686 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- cpu-all.h | 7 - gdbstub.c | 519 +++++++++++++++++++++++++++++++------------------------- 3 files changed, 291 insertions(+), 239 deletions(-) diff --git a/Makefile.target b/Makefile.target index 07fa4568d..7b79a8b09 100644 --- a/Makefile.target +++ b/Makefile.target @@ -166,7 +166,7 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a # cpu emulator library -LIBOBJS=exec.o translate-all.o cpu-exec.o gdbstub.o \ +LIBOBJS=exec.o translate-all.o cpu-exec.o\ translate.o op.o ifeq ($(TARGET_ARCH), i386) @@ -219,7 +219,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o \ +VL_OBJS=vl.o osdep.o block.o monitor.o gdbstub.o \ ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o ifeq ($(TARGET_ARCH), ppc) diff --git a/cpu-all.h b/cpu-all.h index b8beddbc3..71a300398 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -611,8 +611,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #endif /* SINGLE_CPU_DEFINES */ -#define DEFAULT_GDBSTUB_PORT 1234 - void cpu_abort(CPUState *env, const char *fmt, ...); extern CPUState *cpu_single_env; extern int code_copy_enabled; @@ -722,9 +720,4 @@ static inline void cpu_physical_memory_set_dirty(target_ulong addr) void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end); -/* gdb stub API */ -extern int gdbstub_fd; -CPUState *cpu_gdbstub_get_env(void *opaque); -int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port); - #endif /* CPU_ALL_H */ diff --git a/gdbstub.c b/gdbstub.c index 8774a9d27..0cf839555 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -26,70 +26,36 @@ #include #include #include +#include -#include "cpu.h" -#include "exec-all.h" +#include "vl.h" //#define DEBUG_GDB -int gdbstub_fd = -1; +enum RSState { + RS_IDLE, + RS_GETLINE, + RS_CHKSUM1, + RS_CHKSUM2, +}; -/* return 0 if OK */ -static int gdbstub_open(int port) -{ - struct sockaddr_in sockaddr; - socklen_t len; - int fd, val, ret; +static int gdbserver_fd; - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } +typedef struct GDBState { + enum RSState state; + int fd; + char line_buf[4096]; + int line_buf_index; + int line_csum; +} GDBState; - /* allow fast reuse */ - val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); - - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(port); - sockaddr.sin_addr.s_addr = 0; - ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); - if (ret < 0) { - perror("bind"); - return -1; - } - ret = listen(fd, 0); - if (ret < 0) { - perror("listen"); - return -1; - } - - /* now wait for one connection */ - for(;;) { - len = sizeof(sockaddr); - gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len); - if (gdbstub_fd < 0 && errno != EINTR) { - perror("accept"); - return -1; - } else if (gdbstub_fd >= 0) { - break; - } - } - - /* set short latency */ - val = 1; - setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); - return 0; -} - -static int get_char(void) +static int get_char(GDBState *s) { uint8_t ch; int ret; for(;;) { - ret = read(gdbstub_fd, &ch, 1); + ret = read(s->fd, &ch, 1); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return -1; @@ -102,12 +68,12 @@ static int get_char(void) return ch; } -static void put_buffer(const uint8_t *buf, int len) +static void put_buffer(GDBState *s, const uint8_t *buf, int len) { int ret; while (len > 0) { - ret = write(gdbstub_fd, buf, len); + ret = write(s->fd, buf, len); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return; @@ -161,59 +127,8 @@ static void hextomem(uint8_t *mem, const char *buf, int len) } } -/* return -1 if error or EOF */ -static int get_packet(char *buf, int buf_size) -{ - int ch, len, csum, csum1; - char reply[1]; - - for(;;) { - for(;;) { - ch = get_char(); - if (ch < 0) - return -1; - if (ch == '$') - break; - } - len = 0; - csum = 0; - for(;;) { - ch = get_char(); - if (ch < 0) - return -1; - if (ch == '#') - break; - if (len > buf_size - 1) - return -1; - buf[len++] = ch; - csum += ch; - } - buf[len] = '\0'; - ch = get_char(); - if (ch < 0) - return -1; - csum1 = fromhex(ch) << 4; - ch = get_char(); - if (ch < 0) - return -1; - csum1 |= fromhex(ch); - if ((csum & 0xff) != csum1) { - reply[0] = '-'; - put_buffer(reply, 1); - } else { - reply[0] = '+'; - put_buffer(reply, 1); - break; - } - } -#ifdef DEBUG_GDB - printf("command='%s'\n", buf); -#endif - return len; -} - /* return -1 if error, 0 if OK */ -static int put_packet(char *buf) +static int put_packet(GDBState *s, char *buf) { char buf1[3]; int len, csum, ch, i; @@ -224,9 +139,9 @@ static int put_packet(char *buf) for(;;) { buf1[0] = '$'; - put_buffer(buf1, 1); + put_buffer(s, buf1, 1); len = strlen(buf); - put_buffer(buf, len); + put_buffer(s, buf, len); csum = 0; for(i = 0; i < len; i++) { csum += buf[i]; @@ -235,9 +150,9 @@ static int put_packet(char *buf) buf1[1] = tohex((csum >> 4) & 0xf); buf1[2] = tohex((csum) & 0xf); - put_buffer(buf1, 3); + put_buffer(s, buf1, 3); - ch = get_char(); + ch = get_char(s); if (ch < 0) return -1; if (ch == '+') @@ -387,149 +302,293 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) #endif /* port = 0 means default port */ -int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) +static int gdb_handle_packet(GDBState *s, const char *line_buf) { - CPUState *env; + CPUState *env = cpu_single_env; const char *p; - int ret, ch, reg_size, type; + int ch, reg_size, type; char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; uint32_t addr, len; - printf("Waiting gdb connection on port %d\n", port); - if (gdbstub_open(port) < 0) - return -1; - printf("Connected\n"); - for(;;) { - ret = get_packet(buf, sizeof(buf)); - if (ret < 0) - break; - p = buf; - ch = *p++; - switch(ch) { - case '?': - snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); - put_packet(buf); - break; - case 'c': - if (*p != '\0') { - addr = strtoul(p, (char **)&p, 16); - env = cpu_gdbstub_get_env(opaque); +#ifdef DEBUG_GDB + printf("command='%s'\n", line_buf); +#endif + p = line_buf; + ch = *p++; + switch(ch) { + case '?': + snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); + put_packet(s, buf); + break; + case 'c': + if (*p != '\0') { + addr = strtoul(p, (char **)&p, 16); #if defined(TARGET_I386) - env->eip = addr; + env->eip = addr; #elif defined (TARGET_PPC) - env->nip = addr; + env->nip = addr; #endif - } - ret = main_loop(opaque); - if (ret == EXCP_DEBUG) - ret = SIGTRAP; - else - ret = 0; - snprintf(buf, sizeof(buf), "S%02x", ret); - put_packet(buf); - break; - case 's': - env = cpu_gdbstub_get_env(opaque); - if (*p != '\0') { - addr = strtoul(p, (char **)&p, 16); + } + vm_start(); + break; + case 's': + if (*p != '\0') { + addr = strtoul(p, (char **)&p, 16); #if defined(TARGET_I386) - env->eip = addr; + env->eip = addr; #elif defined (TARGET_PPC) - env->nip = addr; + env->nip = addr; #endif + } + cpu_single_step(env, 1); + vm_start(); + break; + case 'g': + reg_size = cpu_gdb_read_registers(env, mem_buf); + memtohex(buf, mem_buf, reg_size); + put_packet(s, buf); + break; + case 'G': + registers = (void *)mem_buf; + len = strlen(p) / 2; + hextomem((uint8_t *)registers, p, len); + cpu_gdb_write_registers(env, mem_buf, len); + put_packet(s, "OK"); + break; + case 'm': + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, NULL, 16); + if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) + memset(mem_buf, 0, len); + memtohex(buf, mem_buf, len); + put_packet(s, buf); + break; + case 'M': + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + hextomem(mem_buf, p, len); + if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) + put_packet(s, "ENN"); + else + put_packet(s, "OK"); + break; + case 'Z': + type = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + if (type == 0 || type == 1) { + if (cpu_breakpoint_insert(env, addr) < 0) + goto breakpoint_error; + put_packet(s, "OK"); + } else { + breakpoint_error: + put_packet(s, "ENN"); + } + break; + case 'z': + type = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + addr = strtoul(p, (char **)&p, 16); + if (*p == ',') + p++; + len = strtoul(p, (char **)&p, 16); + if (type == 0 || type == 1) { + cpu_breakpoint_remove(env, addr); + put_packet(s, "OK"); + } else { + goto breakpoint_error; + } + break; + default: + // unknown_command: + /* put empty packet */ + buf[0] = '\0'; + put_packet(s, buf); + break; + } + return RS_IDLE; +} + +static void gdb_vm_stopped(void *opaque, int reason) +{ + GDBState *s = opaque; + char buf[256]; + int ret; + + /* disable single step if it was enable */ + cpu_single_step(cpu_single_env, 0); + + if (reason == EXCP_DEBUG) + ret = SIGTRAP; + else + ret = 0; + snprintf(buf, sizeof(buf), "S%02x", ret); + put_packet(s, buf); +} + +static void gdb_read_byte(GDBState *s, int ch) +{ + int i, csum; + char reply[1]; + + if (vm_running) { + /* when the CPU is running, we cannot do anything except stop + it when receiving a char */ + vm_stop(EXCP_INTERRUPT); + } else { + switch(s->state) { + case RS_IDLE: + if (ch == '$') { + s->line_buf_index = 0; + s->state = RS_GETLINE; } - cpu_single_step(env, 1); - ret = main_loop(opaque); - cpu_single_step(env, 0); - if (ret == EXCP_DEBUG) - ret = SIGTRAP; - else - ret = 0; - snprintf(buf, sizeof(buf), "S%02x", ret); - put_packet(buf); - break; - case 'g': - env = cpu_gdbstub_get_env(opaque); - reg_size = cpu_gdb_read_registers(env, mem_buf); - memtohex(buf, mem_buf, reg_size); - put_packet(buf); break; - case 'G': - env = cpu_gdbstub_get_env(opaque); - registers = (void *)mem_buf; - len = strlen(p) / 2; - hextomem((uint8_t *)registers, p, len); - cpu_gdb_write_registers(env, mem_buf, len); - put_packet("OK"); - break; - case 'm': - env = cpu_gdbstub_get_env(opaque); - addr = strtoul(p, (char **)&p, 16); - if (*p == ',') - p++; - len = strtoul(p, NULL, 16); - if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) - memset(mem_buf, 0, len); - memtohex(buf, mem_buf, len); - put_packet(buf); - break; - case 'M': - env = cpu_gdbstub_get_env(opaque); - addr = strtoul(p, (char **)&p, 16); - if (*p == ',') - p++; - len = strtoul(p, (char **)&p, 16); - if (*p == ',') - p++; - hextomem(mem_buf, p, len); - if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) - put_packet("ENN"); - else - put_packet("OK"); - break; - case 'Z': - type = strtoul(p, (char **)&p, 16); - if (*p == ',') - p++; - addr = strtoul(p, (char **)&p, 16); - if (*p == ',') - p++; - len = strtoul(p, (char **)&p, 16); - if (type == 0 || type == 1) { - env = cpu_gdbstub_get_env(opaque); - if (cpu_breakpoint_insert(env, addr) < 0) - goto breakpoint_error; - put_packet("OK"); + case RS_GETLINE: + if (ch == '#') { + s->state = RS_CHKSUM1; + } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { + s->state = RS_IDLE; } else { - breakpoint_error: - put_packet("ENN"); + s->line_buf[s->line_buf_index++] = ch; } break; - case 'z': - type = strtoul(p, (char **)&p, 16); - if (*p == ',') - p++; - addr = strtoul(p, (char **)&p, 16); - if (*p == ',') - p++; - len = strtoul(p, (char **)&p, 16); - if (type == 0 || type == 1) { - env = cpu_gdbstub_get_env(opaque); - cpu_breakpoint_remove(env, addr); - put_packet("OK"); + case RS_CHKSUM1: + s->line_buf[s->line_buf_index] = '\0'; + s->line_csum = fromhex(ch) << 4; + s->state = RS_CHKSUM2; + break; + case RS_CHKSUM2: + s->line_csum |= fromhex(ch); + csum = 0; + for(i = 0; i < s->line_buf_index; i++) { + csum += s->line_buf[i]; + } + if (s->line_csum != (csum & 0xff)) { + reply[0] = '-'; + put_buffer(s, reply, 1); + s->state = RS_IDLE; } else { - goto breakpoint_error; + reply[0] = '+'; + put_buffer(s, reply, 1); + s->state = gdb_handle_packet(s, s->line_buf); } break; - default: - // unknown_command: - /* put empty packet */ - buf[0] = '\0'; - put_packet(buf); + } + } +} + +static int gdb_can_read(void *opaque) +{ + return 256; +} + +static void gdb_read(void *opaque, const uint8_t *buf, int size) +{ + GDBState *s = opaque; + int i; + if (size == 0) { + /* end of connection */ + qemu_del_vm_stop_handler(gdb_vm_stopped, s); + qemu_del_fd_read_handler(s->fd); + qemu_free(s); + vm_start(); + } else { + for(i = 0; i < size; i++) + gdb_read_byte(s, buf[i]); + } +} + +static void gdb_accept(void *opaque, const uint8_t *buf, int size) +{ + GDBState *s; + struct sockaddr_in sockaddr; + socklen_t len; + int val, fd; + + for(;;) { + len = sizeof(sockaddr); + fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len); + if (fd < 0 && errno != EINTR) { + perror("accept"); + return; + } else if (fd >= 0) { break; } } + + /* set short latency */ + val = 1; + setsockopt(fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); + + s = qemu_mallocz(sizeof(GDBState)); + if (!s) { + close(fd); + return; + } + s->fd = fd; + + fcntl(fd, F_SETFL, O_NONBLOCK); + + /* stop the VM */ + vm_stop(EXCP_INTERRUPT); + + /* start handling I/O */ + qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); + /* when the VM is stopped, the following callback is called */ + qemu_add_vm_stop_handler(gdb_vm_stopped, s); +} + +static int gdbserver_open(int port) +{ + struct sockaddr_in sockaddr; + int fd, val, ret; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + + /* allow fast reuse */ + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(port); + sockaddr.sin_addr.s_addr = 0; + ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); + if (ret < 0) { + perror("bind"); + return -1; + } + ret = listen(fd, 0); + if (ret < 0) { + perror("listen"); + return -1; + } + fcntl(fd, F_SETFL, O_NONBLOCK); + return fd; +} + +int gdbserver_start(int port) +{ + gdbserver_fd = gdbserver_open(port); + if (gdbserver_fd < 0) + return -1; + /* accept connections */ + qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); return 0; } -- cgit v1.2.3 From 1f1af9fd7f3fc83a3f933122f772d3a3f8663369 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 31 Mar 2004 18:56:43 +0000 Subject: added cpu_get_fp80() and cpu_set_fp80() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@687 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 4 ++++ target-i386/helper.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1cabbe42c..daa2133f8 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -408,6 +408,10 @@ static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) #endif } +/* used for debug or cpu save/restore */ +void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f); +CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper); + /* the following helpers are only usable in user mode simulation as they can trigger unexpected exceptions */ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); diff --git a/target-i386/helper.c b/target-i386/helper.c index dbdabd82e..e61b05dc5 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2005,8 +2005,6 @@ void helper_fstt_ST0_A0(void) /* BCD ops */ -#define MUL10(iv) ( iv + iv + (iv << 3) ) - void helper_fbld_ST0_A0(void) { CPU86_LDouble tmp; @@ -2431,6 +2429,64 @@ void helper_frstor(uint8_t *ptr, int data32) } } +/* XXX: merge with helper_fstt ? */ + +#ifndef USE_X86LDOUBLE + +void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) +{ + CPU86_LDoubleU temp; + int e; + + temp.d = f; + /* mantissa */ + *pmant = (MANTD(temp) << 11) | (1LL << 63); + /* exponent + sign */ + e = EXPD(temp) - EXPBIAS + 16383; + e |= SIGND(temp) >> 16; + *pexp = e; +} + +CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) +{ + CPU86_LDoubleU temp; + int e; + uint64_t ll; + + /* XXX: handle overflow ? */ + e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ + e |= (upper >> 4) & 0x800; /* sign */ + ll = (mant >> 11) & ((1LL << 52) - 1); +#ifdef __arm__ + temp.l.upper = (e << 20) | (ll >> 32); + temp.l.lower = ll; +#else + temp.ll = ll | ((uint64_t)e << 52); +#endif + return temp.d; +} + +#else + +void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f) +{ + CPU86_LDoubleU temp; + + temp.d = f; + *pmant = temp.l.lower; + *pexp = temp.l.upper; +} + +CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) +{ + CPU86_LDoubleU temp; + + temp.l.upper = upper; + temp.l.lower = mant; + return temp.d; +} +#endif + #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu -- cgit v1.2.3 From dff38e7b40b398dd713643d57d89f280c6d09ff1 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 31 Mar 2004 18:57:29 +0000 Subject: more precise RTC emulation (periodic timers + time updates) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@688 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mc146818rtc.c | 298 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 264 insertions(+), 34 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 7d94b25f5..4505fc958 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -63,11 +63,62 @@ #define RTC_REG_C 12 #define RTC_REG_D 13 -/* PC cmos mappings */ -#define REG_IBM_CENTURY_BYTE 0x32 -#define REG_IBM_PS2_CENTURY_BYTE 0x37 +#define REG_A_UIP 0x80 -RTCState rtc_state; +#define REG_B_SET 0x80 +#define REG_B_PIE 0x40 +#define REG_B_AIE 0x20 +#define REG_B_UIE 0x10 + +struct RTCState { + uint8_t cmos_data[128]; + uint8_t cmos_index; + int current_time; /* in seconds */ + int irq; + uint8_t buf_data[10]; /* buffered data */ + /* periodic timer */ + QEMUTimer *periodic_timer; + int64_t next_periodic_time; + /* second update */ + int64_t next_second_time; + QEMUTimer *second_timer; + QEMUTimer *second_timer2; +}; + +static void rtc_set_time(RTCState *s); +static void rtc_set_date_buf(RTCState *s, const struct tm *tm); +static void rtc_copy_date(RTCState *s); + +static void rtc_timer_update(RTCState *s, int64_t current_time) +{ + int period_code, period; + int64_t cur_clock, next_irq_clock; + + period_code = s->cmos_data[RTC_REG_A] & 0x0f; + if (period_code != 0 && + (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { + if (period_code <= 2) + period_code += 7; + /* period in 32 Khz cycles */ + period = 1 << (period_code - 1); + /* compute 32 khz clock */ + cur_clock = muldiv64(current_time, 32768, ticks_per_sec); + next_irq_clock = (cur_clock & ~(period - 1)) + period; + s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1; + qemu_mod_timer(s->periodic_timer, s->next_periodic_time); + } else { + qemu_del_timer(s->periodic_timer); + } +} + +static void rtc_periodic_timer(void *opaque) +{ + RTCState *s = opaque; + + rtc_timer_update(s, s->next_periodic_time); + s->cmos_data[RTC_REG_C] |= 0xc0; + pic_set_irq(s->irq, 1); +} static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) { @@ -80,7 +131,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) printf("cmos: write index=0x%02x val=0x%02x\n", s->cmos_index, data); #endif - switch(addr) { + switch(s->cmos_index) { case RTC_SECONDS_ALARM: case RTC_MINUTES_ALARM: case RTC_HOURS_ALARM: @@ -95,10 +146,30 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) case RTC_MONTH: case RTC_YEAR: s->cmos_data[s->cmos_index] = data; + /* if in set mode, do not update the time */ + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + rtc_set_time(s); + } break; case RTC_REG_A: + /* UIP bit is read only */ + s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | + (s->cmos_data[RTC_REG_A] & REG_A_UIP); + rtc_timer_update(s, qemu_get_clock(vm_clock)); + break; case RTC_REG_B: - s->cmos_data[s->cmos_index] = data; + if (data & REG_B_SET) { + /* set mode: reset UIP mode */ + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + data &= ~REG_B_UIE; + } else { + /* if disabling set mode, update the time */ + if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + rtc_set_time(s); + } + } + s->cmos_data[RTC_REG_B] = data; + rtc_timer_update(s, qemu_get_clock(vm_clock)); break; case RTC_REG_C: case RTC_REG_D: @@ -111,27 +182,104 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) } } -static inline int to_bcd(int a) +static inline int to_bcd(RTCState *s, int a) { - return ((a / 10) << 4) | (a % 10); + if (s->cmos_data[RTC_REG_B] & 0x04) { + return a; + } else { + return ((a / 10) << 4) | (a % 10); + } } -static void cmos_update_time(RTCState *s) +static inline int from_bcd(RTCState *s, int a) { - struct tm *tm; + if (s->cmos_data[RTC_REG_B] & 0x04) { + return a; + } else { + return ((a >> 4) * 10) + (a & 0x0f); + } +} + +static void rtc_set_time(RTCState *s) +{ + struct tm tm1, *tm = &tm1; + + tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]); + tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]); + tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS]); + tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]); + tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); + tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; + tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100; + + /* update internal state */ + s->buf_data[RTC_SECONDS] = s->cmos_data[RTC_SECONDS]; + s->buf_data[RTC_MINUTES] = s->cmos_data[RTC_MINUTES]; + s->buf_data[RTC_HOURS] = s->cmos_data[RTC_HOURS]; + s->buf_data[RTC_DAY_OF_WEEK] = s->cmos_data[RTC_DAY_OF_WEEK]; + s->buf_data[RTC_DAY_OF_MONTH] = s->cmos_data[RTC_DAY_OF_MONTH]; + s->buf_data[RTC_MONTH] = s->cmos_data[RTC_MONTH]; + s->buf_data[RTC_YEAR] = s->cmos_data[RTC_YEAR]; + s->current_time = mktime(tm); +} + +static void rtc_update_second(void *opaque) +{ + RTCState *s = opaque; + + /* if the oscillator is not in normal operation, we do not update */ + if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) { + s->next_second_time += ticks_per_sec; + qemu_mod_timer(s->second_timer, s->next_second_time); + } else { + s->current_time++; + + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + /* update in progress bit */ + s->cmos_data[RTC_REG_A] |= REG_A_UIP; + } + qemu_mod_timer(s->second_timer2, + s->next_second_time + (ticks_per_sec * 99) / 100); + } +} + +static void rtc_update_second2(void *opaque) +{ + RTCState *s = opaque; time_t ti; - ti = time(NULL); - tm = gmtime(&ti); - s->cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); - s->cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); - s->cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); - s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); - s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); - s->cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); - s->cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); - s->cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); - s->cmos_data[REG_IBM_PS2_CENTURY_BYTE] = s->cmos_data[REG_IBM_CENTURY_BYTE]; + ti = s->current_time; + rtc_set_date_buf(s, gmtime(&ti)); + + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + rtc_copy_date(s); + } + + /* check alarm */ + if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { + if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 || + s->cmos_data[RTC_SECONDS_ALARM] == s->buf_data[RTC_SECONDS]) && + ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 || + s->cmos_data[RTC_MINUTES_ALARM] == s->buf_data[RTC_MINUTES]) && + ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || + s->cmos_data[RTC_HOURS_ALARM] == s->buf_data[RTC_HOURS])) { + + s->cmos_data[RTC_REG_C] |= 0xa0; + pic_set_irq(s->irq, 1); + } + } + + /* update ended interrupt */ + if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { + s->cmos_data[RTC_REG_C] |= 0x90; + pic_set_irq(s->irq, 1); + } + + /* clear update in progress bit */ + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + + s->next_second_time += ticks_per_sec; + qemu_mod_timer(s->second_timer, s->next_second_time); } static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) @@ -149,16 +297,10 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_DAY_OF_MONTH: case RTC_MONTH: case RTC_YEAR: - case REG_IBM_CENTURY_BYTE: - case REG_IBM_PS2_CENTURY_BYTE: - cmos_update_time(s); ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_A: ret = s->cmos_data[s->cmos_index]; - /* toggle update-in-progress bit for Linux (same hack as - plex86) */ - s->cmos_data[RTC_REG_A] ^= 0x80; break; case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; @@ -177,19 +319,94 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) } } -void rtc_timer(void) +static void rtc_set_date_buf(RTCState *s, const struct tm *tm) { - RTCState *s = &rtc_state; - if (s->cmos_data[RTC_REG_B] & 0x50) { - pic_set_irq(s->irq, 1); + s->buf_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); + s->buf_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); + if (s->cmos_data[RTC_REG_B] & 0x02) { + /* 24 hour format */ + s->buf_data[RTC_HOURS] = to_bcd(s, tm->tm_hour); + } else { + /* 12 hour format */ + s->buf_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12); + if (tm->tm_hour >= 12) + s->buf_data[RTC_HOURS] |= 0x80; } + s->buf_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday); + s->buf_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday); + s->buf_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1); + s->buf_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100); +} + +static void rtc_copy_date(RTCState *s) +{ + s->cmos_data[RTC_SECONDS] = s->buf_data[RTC_SECONDS]; + s->cmos_data[RTC_MINUTES] = s->buf_data[RTC_MINUTES]; + s->cmos_data[RTC_HOURS] = s->buf_data[RTC_HOURS]; + s->cmos_data[RTC_DAY_OF_WEEK] = s->buf_data[RTC_DAY_OF_WEEK]; + s->cmos_data[RTC_DAY_OF_MONTH] = s->buf_data[RTC_DAY_OF_MONTH]; + s->cmos_data[RTC_MONTH] = s->buf_data[RTC_MONTH]; + s->cmos_data[RTC_YEAR] = s->buf_data[RTC_YEAR]; +} + +void rtc_set_memory(RTCState *s, int addr, int val) +{ + if (addr >= 0 && addr <= 127) + s->cmos_data[addr] = val; +} + +void rtc_set_date(RTCState *s, const struct tm *tm) +{ + s->current_time = mktime((struct tm *)tm); + rtc_set_date_buf(s, tm); + rtc_copy_date(s); +} + +static void rtc_save(QEMUFile *f, void *opaque) +{ + RTCState *s = opaque; + + qemu_put_buffer(f, s->cmos_data, 128); + qemu_put_8s(f, &s->cmos_index); + qemu_put_be32s(f, &s->current_time); + qemu_put_buffer(f, s->buf_data, 10); + + qemu_put_timer(f, s->periodic_timer); + qemu_put_be64s(f, &s->next_periodic_time); + + qemu_put_be64s(f, &s->next_second_time); + qemu_put_timer(f, s->second_timer); + qemu_put_timer(f, s->second_timer2); } -void rtc_init(int base, int irq) +static int rtc_load(QEMUFile *f, void *opaque, int version_id) { - RTCState *s = &rtc_state; + RTCState *s = opaque; + + if (version_id != 1) + return -EINVAL; - cmos_update_time(s); + qemu_get_buffer(f, s->cmos_data, 128); + qemu_get_8s(f, &s->cmos_index); + qemu_get_be32s(f, &s->current_time); + qemu_get_buffer(f, s->buf_data, 10); + + qemu_get_timer(f, s->periodic_timer); + qemu_get_be64s(f, &s->next_periodic_time); + + qemu_get_be64s(f, &s->next_second_time); + qemu_get_timer(f, s->second_timer); + qemu_get_timer(f, s->second_timer2); + return 0; +} + +RTCState *rtc_init(int base, int irq) +{ + RTCState *s; + + s = qemu_mallocz(sizeof(RTCState)); + if (!s) + return NULL; s->irq = irq; s->cmos_data[RTC_REG_A] = 0x26; @@ -197,7 +414,20 @@ void rtc_init(int base, int irq) s->cmos_data[RTC_REG_C] = 0x00; s->cmos_data[RTC_REG_D] = 0x80; + s->periodic_timer = qemu_new_timer(vm_clock, + rtc_periodic_timer, s); + s->second_timer = qemu_new_timer(vm_clock, + rtc_update_second, s); + s->second_timer2 = qemu_new_timer(vm_clock, + rtc_update_second2, s); + + s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100; + qemu_mod_timer(s->second_timer2, s->next_second_time); + register_ioport_write(base, 2, 1, cmos_ioport_write, s); register_ioport_read(base, 2, 1, cmos_ioport_read, s); + + register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); + return s; } -- cgit v1.2.3 From b0a21b5334fb31042d555bfb66de864291c53140 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 31 Mar 2004 18:58:38 +0000 Subject: use new timer API git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@689 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8254.c | 172 ++++++++++++++++++++++++++++++++++++++++++++---------------- hw/i8259.c | 62 +++++++++++++++++++--- hw/ne2000.c | 2 +- hw/pc.c | 78 ++++++++++++++++++--------- hw/serial.c | 2 +- hw/vga.c | 94 +++++++++++++++++++++++++++++++++ 6 files changed, 330 insertions(+), 80 deletions(-) diff --git a/hw/i8254.c b/hw/i8254.c index 6e9682501..cedaede1a 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -43,6 +43,8 @@ #include "cpu.h" #include "vl.h" +//#define DEBUG_PIT + #define RW_STATE_LSB 0 #define RW_STATE_MSB 1 #define RW_STATE_WORD0 2 @@ -52,12 +54,14 @@ PITChannelState pit_channels[3]; +static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); + static int pit_get_count(PITChannelState *s) { uint64_t d; int counter; - d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); + d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { case 0: case 1: @@ -77,12 +81,12 @@ static int pit_get_count(PITChannelState *s) } /* get pit output bit */ -int pit_get_out(PITChannelState *s) +int pit_get_out(PITChannelState *s, int64_t current_time) { uint64_t d; int out; - d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); + d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { default: case 0: @@ -108,53 +112,51 @@ int pit_get_out(PITChannelState *s) return out; } -/* get the number of 0 to 1 transitions we had since we call this - function */ -/* XXX: maybe better to use ticks precision to avoid getting edges - twice if checks are done at very small intervals */ -int pit_get_out_edges(PITChannelState *s) +/* return -1 if no transition will occur. */ +static int64_t pit_get_next_transition_time(PITChannelState *s, + int64_t current_time) { - uint64_t d1, d2; - int64_t ticks; - int ret, v; + uint64_t d, next_time, base; + int period2; - ticks = cpu_get_ticks(); - d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, - PIT_FREQ, ticks_per_sec); - d2 = muldiv64(ticks - s->count_load_time, - PIT_FREQ, ticks_per_sec); - s->count_last_edge_check_time = ticks; + d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec); switch(s->mode) { default: case 0: - if (d1 < s->count && d2 >= s->count) - ret = 1; - else - ret = 0; - break; case 1: - ret = 0; + if (d < s->count) + next_time = s->count; + else + return -1; break; case 2: - d1 /= s->count; - d2 /= s->count; - ret = d2 - d1; + base = (d / s->count) * s->count; + if ((d - base) == 0 && d != 0) + next_time = base + s->count; + else + next_time = base + s->count + 1; break; case 3: - v = s->count - ((s->count + 1) >> 1); - d1 = (d1 + v) / s->count; - d2 = (d2 + v) / s->count; - ret = d2 - d1; + base = (d / s->count) * s->count; + period2 = ((s->count + 1) >> 1); + if ((d - base) < period2) + next_time = base + period2; + else + next_time = base + s->count; break; case 4: case 5: - if (d1 < s->count && d2 >= s->count) - ret = 1; + if (d < s->count) + next_time = s->count; + else if (d == s->count) + next_time = s->count + 1; else - ret = 0; + return -1; break; } - return ret; + /* convert to timer units */ + next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ); + return next_time; } /* val must be 0 or 1 */ @@ -170,16 +172,16 @@ void pit_set_gate(PITChannelState *s, int val) case 5: if (s->gate < val) { /* restart counting on rising edge */ - s->count_load_time = cpu_get_ticks(); - s->count_last_edge_check_time = s->count_load_time; + s->count_load_time = qemu_get_clock(vm_clock); + pit_irq_timer_update(s, s->count_load_time); } break; case 2: case 3: if (s->gate < val) { /* restart counting on rising edge */ - s->count_load_time = cpu_get_ticks(); - s->count_last_edge_check_time = s->count_load_time; + s->count_load_time = qemu_get_clock(vm_clock); + pit_irq_timer_update(s, s->count_load_time); } /* XXX: disable/enable counting */ break; @@ -191,14 +193,9 @@ static inline void pit_load_count(PITChannelState *s, int val) { if (val == 0) val = 0x10000; - s->count_load_time = cpu_get_ticks(); - s->count_last_edge_check_time = s->count_load_time; + s->count_load_time = qemu_get_clock(vm_clock); s->count = val; - if (s == &pit_channels[0] && val <= pit_min_timer_count) { - fprintf(stderr, - "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", - PIT_FREQ / pit_min_timer_count); - } + pit_irq_timer_update(s, s->count_load_time); } static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) @@ -222,6 +219,7 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->mode = (val >> 1) & 7; s->bcd = val & 1; s->rw_state = access - 1 + RW_STATE_LSB; + /* XXX: update irq timer ? */ break; } } else { @@ -279,18 +277,100 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr) return ret; } -void pit_init(int base) +static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) +{ + int64_t expire_time; + int irq_level; + + if (!s->irq_timer) + return; + expire_time = pit_get_next_transition_time(s, current_time); + irq_level = pit_get_out(s, current_time); + pic_set_irq(s->irq, irq_level); +#ifdef DEBUG_PIT + printf("irq_level=%d next_delay=%f\n", + irq_level, + (double)(expire_time - current_time) / ticks_per_sec); +#endif + s->next_transition_time = expire_time; + if (expire_time != -1) + qemu_mod_timer(s->irq_timer, expire_time); + else + qemu_del_timer(s->irq_timer); +} + +static void pit_irq_timer(void *opaque) +{ + PITChannelState *s = opaque; + + pit_irq_timer_update(s, s->next_transition_time); +} + +static void pit_save(QEMUFile *f, void *opaque) +{ + PITChannelState *s; + int i; + + for(i = 0; i < 3; i++) { + s = &pit_channels[i]; + qemu_put_be32s(f, &s->count); + qemu_put_be16s(f, &s->latched_count); + qemu_put_8s(f, &s->rw_state); + qemu_put_8s(f, &s->mode); + qemu_put_8s(f, &s->bcd); + qemu_put_8s(f, &s->gate); + qemu_put_be64s(f, &s->count_load_time); + if (s->irq_timer) { + qemu_put_be64s(f, &s->next_transition_time); + qemu_put_timer(f, s->irq_timer); + } + } +} + +static int pit_load(QEMUFile *f, void *opaque, int version_id) +{ + PITChannelState *s; + int i; + + if (version_id != 1) + return -EINVAL; + + for(i = 0; i < 3; i++) { + s = &pit_channels[i]; + qemu_get_be32s(f, &s->count); + qemu_get_be16s(f, &s->latched_count); + qemu_get_8s(f, &s->rw_state); + qemu_get_8s(f, &s->mode); + qemu_get_8s(f, &s->bcd); + qemu_get_8s(f, &s->gate); + qemu_get_be64s(f, &s->count_load_time); + if (s->irq_timer) { + qemu_get_be64s(f, &s->next_transition_time); + qemu_get_timer(f, s->irq_timer); + } + } + return 0; +} + +void pit_init(int base, int irq) { PITChannelState *s; int i; for(i = 0;i < 3; i++) { s = &pit_channels[i]; + if (i == 0) { + /* the timer 0 is connected to an IRQ */ + s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s); + s->irq = irq; + } s->mode = 3; s->gate = (i != 2); pit_load_count(s, 0); } + register_savevm("i8254", base, 1, pit_save, pit_load, NULL); + register_ioport_write(base, 4, 1, pit_ioport_write, NULL); register_ioport_read(base, 3, 1, pit_ioport_read, NULL); } diff --git a/hw/i8259.c b/hw/i8259.c index 5ef1fa070..55488c681 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -122,7 +122,7 @@ static int pic_get_irq(PicState *s) /* raise irq to CPU if necessary. must be called every time the active irq may change */ -void pic_update_irq(void) +static void pic_update_irq(void) { int irq2, irq; @@ -160,7 +160,6 @@ void pic_update_irq(void) #ifdef DEBUG_IRQ_LATENCY int64_t irq_time[16]; -int64_t cpu_get_ticks(void); #endif #if defined(DEBUG_PIC) int irq_level[16]; @@ -376,11 +375,62 @@ uint32_t pic_intack_read(CPUState *env) return ret; } +static void pic_save(QEMUFile *f, void *opaque) +{ + PicState *s = opaque; + + qemu_put_8s(f, &s->last_irr); + qemu_put_8s(f, &s->irr); + qemu_put_8s(f, &s->imr); + qemu_put_8s(f, &s->isr); + qemu_put_8s(f, &s->priority_add); + qemu_put_8s(f, &s->irq_base); + qemu_put_8s(f, &s->read_reg_select); + qemu_put_8s(f, &s->poll); + qemu_put_8s(f, &s->special_mask); + qemu_put_8s(f, &s->init_state); + qemu_put_8s(f, &s->auto_eoi); + qemu_put_8s(f, &s->rotate_on_auto_eoi); + qemu_put_8s(f, &s->special_fully_nested_mode); + qemu_put_8s(f, &s->init4); +} + +static int pic_load(QEMUFile *f, void *opaque, int version_id) +{ + PicState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_8s(f, &s->last_irr); + qemu_get_8s(f, &s->irr); + qemu_get_8s(f, &s->imr); + qemu_get_8s(f, &s->isr); + qemu_get_8s(f, &s->priority_add); + qemu_get_8s(f, &s->irq_base); + qemu_get_8s(f, &s->read_reg_select); + qemu_get_8s(f, &s->poll); + qemu_get_8s(f, &s->special_mask); + qemu_get_8s(f, &s->init_state); + qemu_get_8s(f, &s->auto_eoi); + qemu_get_8s(f, &s->rotate_on_auto_eoi); + qemu_get_8s(f, &s->special_fully_nested_mode); + qemu_get_8s(f, &s->init4); + return 0; +} + +/* XXX: add generic master/slave system */ +static void pic_init1(int io_addr, PicState *s) +{ + register_ioport_write(io_addr, 2, 1, pic_ioport_write, s); + register_ioport_read(io_addr, 2, 1, pic_ioport_read, s); + + register_savevm("i8259", io_addr, 1, pic_save, pic_load, s); +} + void pic_init(void) { - register_ioport_write(0x20, 2, 1, pic_ioport_write, &pics[0]); - register_ioport_read(0x20, 2, 1, pic_ioport_read, &pics[0]); - register_ioport_write(0xa0, 2, 1, pic_ioport_write, &pics[1]); - register_ioport_read(0xa0, 2, 1, pic_ioport_read, &pics[1]); + pic_init1(0x20, &pics[0]); + pic_init1(0xa0, &pics[1]); } diff --git a/hw/ne2000.c b/hw/ne2000.c index 3bb55171a..bf76829ed 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -471,5 +471,5 @@ void ne2000_init(int base, int irq, NetDriverState *nd) ne2000_reset(s); - add_fd_read_handler(nd->fd, ne2000_can_receive, ne2000_receive, s); + qemu_add_fd_read_handler(nd->fd, ne2000_can_receive, ne2000_receive, s); } diff --git a/hw/pc.c b/hw/pc.c index 2a8ee8a98..03c34a285 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -58,50 +58,69 @@ int speaker_data_on; int dummy_refresh_clock; static fdctrl_t *floppy_controller; +static RTCState *rtc_state; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { } +/* PC cmos mappings */ + #define REG_EQUIPMENT_BYTE 0x14 +#define REG_IBM_CENTURY_BYTE 0x32 +#define REG_IBM_PS2_CENTURY_BYTE 0x37 + + +static inline int to_bcd(RTCState *s, int a) +{ + return ((a / 10) << 4) | (a % 10); +} static void cmos_init(int ram_size, int boot_device) { - RTCState *s = &rtc_state; + RTCState *s = rtc_state; int val; int fd0, fd1, nb; - - /* various important CMOS locations needed by PC/Bochs bios */ + time_t ti; + struct tm *tm; + + /* set the CMOS date */ + time(&ti); + tm = gmtime(&ti); + rtc_set_date(s, tm); + + val = to_bcd(s, (tm->tm_year / 100) + 19); + rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); + rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); - s->cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ - s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ + /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ val = (ram_size / 1024) - 1024; if (val > 65535) val = 65535; - s->cmos_data[0x17] = val; - s->cmos_data[0x18] = val >> 8; - s->cmos_data[0x30] = val; - s->cmos_data[0x31] = val >> 8; + rtc_set_memory(s, 0x17, val); + rtc_set_memory(s, 0x18, val >> 8); + rtc_set_memory(s, 0x30, val); + rtc_set_memory(s, 0x31, val >> 8); val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); if (val > 65535) val = 65535; - s->cmos_data[0x34] = val; - s->cmos_data[0x35] = val >> 8; + rtc_set_memory(s, 0x34, val); + rtc_set_memory(s, 0x35, val >> 8); switch(boot_device) { case 'a': case 'b': - s->cmos_data[0x3d] = 0x01; /* floppy boot */ + rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ break; default: case 'c': - s->cmos_data[0x3d] = 0x02; /* hard drive boot */ + rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */ break; case 'd': - s->cmos_data[0x3d] = 0x03; /* CD-ROM boot */ + rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */ break; } @@ -110,35 +129,38 @@ static void cmos_init(int ram_size, int boot_device) fd0 = fdctrl_get_drive_type(floppy_controller, 0); fd1 = fdctrl_get_drive_type(floppy_controller, 1); - s->cmos_data[0x10] = 0; + val = 0; switch (fd0) { case 0: /* 1.44 Mb 3"5 drive */ - s->cmos_data[0x10] |= 0x40; + val |= 0x40; break; case 1: /* 2.88 Mb 3"5 drive */ - s->cmos_data[0x10] |= 0x60; + val |= 0x60; break; case 2: /* 1.2 Mb 5"5 drive */ - s->cmos_data[0x10] |= 0x20; + val |= 0x20; break; } switch (fd1) { case 0: /* 1.44 Mb 3"5 drive */ - s->cmos_data[0x10] |= 0x04; + val |= 0x04; break; case 1: /* 2.88 Mb 3"5 drive */ - s->cmos_data[0x10] |= 0x06; + val |= 0x06; break; case 2: /* 1.2 Mb 5"5 drive */ - s->cmos_data[0x10] |= 0x02; + val |= 0x02; break; } + rtc_set_memory(s, 0x10, val); + + val = 0; nb = 0; if (fd0 < 3) nb++; @@ -148,12 +170,16 @@ static void cmos_init(int ram_size, int boot_device) case 0: break; case 1: - s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ + val |= 0x01; /* 1 drive, ready for boot */ break; case 2: - s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ + val |= 0x41; /* 2 drives, ready for boot */ break; } + val |= 0x02; /* FPU is there */ + val |= 0x04; /* PS/2 mouse installed */ + rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); + } static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) @@ -165,7 +191,7 @@ static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) { int out; - out = pit_get_out(&pit_channels[2]); + out = pit_get_out(&pit_channels[2], qemu_get_clock(vm_clock)); dummy_refresh_clock ^= 1; return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | (dummy_refresh_clock << 4); @@ -345,12 +371,12 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); - rtc_init(0x70, 8); + rtc_state = rtc_init(0x70, 8); register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); pic_init(); - pit_init(0x40); + pit_init(0x40, 0); fd = serial_open_device(); serial_init(0x3f8, 4, fd); diff --git a/hw/serial.c b/hw/serial.c index 60c311e55..e9bfd2a00 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -288,7 +288,7 @@ SerialState *serial_init(int base, int irq, int fd) register_ioport_read(base, 8, 1, serial_ioport_read, s); if (fd != 0) { - add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); + qemu_add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); s->out_fd = fd; } else { serial_console = s; diff --git a/hw/vga.c b/hw/vga.c index 5d2acc85f..ba936e305 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1578,6 +1578,98 @@ static CPUWriteMemoryFunc *vga_mem_write[3] = { vga_mem_writel, }; +static void vga_save(QEMUFile *f, void *opaque) +{ + VGAState *s = opaque; + int i; + + qemu_put_be32s(f, &s->latch); + qemu_put_8s(f, &s->sr_index); + qemu_put_buffer(f, s->sr, 8); + qemu_put_8s(f, &s->gr_index); + qemu_put_buffer(f, s->gr, 16); + qemu_put_8s(f, &s->ar_index); + qemu_put_buffer(f, s->ar, 21); + qemu_put_be32s(f, &s->ar_flip_flop); + qemu_put_8s(f, &s->cr_index); + qemu_put_buffer(f, s->cr, 256); + qemu_put_8s(f, &s->msr); + qemu_put_8s(f, &s->fcr); + qemu_put_8s(f, &s->st00); + qemu_put_8s(f, &s->st01); + + qemu_put_8s(f, &s->dac_state); + qemu_put_8s(f, &s->dac_sub_index); + qemu_put_8s(f, &s->dac_read_index); + qemu_put_8s(f, &s->dac_write_index); + qemu_put_buffer(f, s->dac_cache, 3); + qemu_put_buffer(f, s->palette, 768); + + qemu_put_be32s(f, &s->bank_offset); +#ifdef CONFIG_BOCHS_VBE + qemu_put_byte(f, 1); + qemu_put_be16s(f, &s->vbe_index); + for(i = 0; i < VBE_DISPI_INDEX_NB; i++) + qemu_put_be16s(f, &s->vbe_regs[i]); + qemu_put_be32s(f, &s->vbe_start_addr); + qemu_put_be32s(f, &s->vbe_line_offset); + qemu_put_be32s(f, &s->vbe_bank_mask); +#else + qemu_put_byte(f, 0); +#endif +} + +static int vga_load(QEMUFile *f, void *opaque, int version_id) +{ + VGAState *s = opaque; + int is_vbe, i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->latch); + qemu_get_8s(f, &s->sr_index); + qemu_get_buffer(f, s->sr, 8); + qemu_get_8s(f, &s->gr_index); + qemu_get_buffer(f, s->gr, 16); + qemu_get_8s(f, &s->ar_index); + qemu_get_buffer(f, s->ar, 21); + qemu_get_be32s(f, &s->ar_flip_flop); + qemu_get_8s(f, &s->cr_index); + qemu_get_buffer(f, s->cr, 256); + qemu_get_8s(f, &s->msr); + qemu_get_8s(f, &s->fcr); + qemu_get_8s(f, &s->st00); + qemu_get_8s(f, &s->st01); + + qemu_get_8s(f, &s->dac_state); + qemu_get_8s(f, &s->dac_sub_index); + qemu_get_8s(f, &s->dac_read_index); + qemu_get_8s(f, &s->dac_write_index); + qemu_get_buffer(f, s->dac_cache, 3); + qemu_get_buffer(f, s->palette, 768); + + qemu_get_be32s(f, &s->bank_offset); + is_vbe = qemu_get_byte(f); +#ifdef CONFIG_BOCHS_VBE + if (!is_vbe) + return -EINVAL; + qemu_get_be16s(f, &s->vbe_index); + for(i = 0; i < VBE_DISPI_INDEX_NB; i++) + qemu_get_be16s(f, &s->vbe_regs[i]); + qemu_get_be32s(f, &s->vbe_start_addr); + qemu_get_be32s(f, &s->vbe_line_offset); + qemu_get_be32s(f, &s->vbe_bank_mask); +#else + if (is_vbe) + return -EINVAL; +#endif + + /* force refresh */ + s->graphic_mode = -1; + return 0; +} + int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { @@ -1614,6 +1706,8 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, s->vram_size = vga_ram_size; s->ds = ds; + register_savevm("vga", 0, 1, vga_save, vga_load, s); + register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s); -- cgit v1.2.3 From 8a7ddc38a60648257dc0645ab4a05b33d6040063 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 31 Mar 2004 19:00:16 +0000 Subject: new timer API - new API to save/restore the virtual machine state git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@690 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 53 ++- oss.c | 4 +- sdl.c | 25 +- vl.c | 1062 +++++++++++++++++++++++++++++++++++++++++++++++++++---------- vl.h | 151 ++++++++- 5 files changed, 1104 insertions(+), 191 deletions(-) diff --git a/monitor.c b/monitor.c index 3d5db9701..8c016a8ac 100644 --- a/monitor.c +++ b/monitor.c @@ -281,6 +281,50 @@ static void do_log(int argc, const char **argv) cpu_set_log(mask); } +static void do_savevm(int argc, const char **argv) +{ + if (argc != 2) { + help_cmd(argv[0]); + return; + } + if (qemu_savevm(argv[1]) < 0) + term_printf("I/O error when saving VM to '%s'\n", argv[1]); +} + +static void do_loadvm(int argc, const char **argv) +{ + if (argc != 2) { + help_cmd(argv[0]); + return; + } + if (qemu_loadvm(argv[1]) < 0) + term_printf("I/O error when loading VM from '%s'\n", argv[1]); +} + +static void do_stop(int argc, const char **argv) +{ + vm_stop(EXCP_INTERRUPT); +} + +static void do_cont(int argc, const char **argv) +{ + vm_start(); +} + +static void do_gdbserver(int argc, const char **argv) +{ + int port; + + port = DEFAULT_GDBSTUB_PORT; + if (argc >= 2) + port = atoi(argv[1]); + if (gdbserver_start(port) < 0) { + qemu_printf("Could not open gdbserver socket on port %d\n", port); + } else { + qemu_printf("Waiting gdb connection on port %d\n", port); + } +} + static term_cmd_t term_cmds[] = { { "help|?", do_help, "[cmd]", "show the help" }, @@ -298,6 +342,13 @@ static term_cmd_t term_cmds[] = { "filename", "save screen into PPM image 'filename'" }, { "log", do_log, "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, + { "savevm", do_savevm, + "filename", "save the whole virtual machine state to 'filename'" }, + { "loadvm", do_loadvm, + "filename", "restore the whole virtual machine state from 'filename'" }, + { "stop", do_stop, "", "stop emulation", }, + { "c|cont", do_cont, "", "resume emulation", }, + { "gdbserver", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, { NULL, NULL, }, }; @@ -601,5 +652,5 @@ void monitor_init(void) QEMU_VERSION); term_show_prompt(); } - add_fd_read_handler(0, term_can_read, term_read, NULL); + qemu_add_fd_read_handler(0, term_can_read, term_read, NULL); } diff --git a/oss.c b/oss.c index 4210799eb..1922985c1 100644 --- a/oss.c +++ b/oss.c @@ -459,11 +459,11 @@ int AUD_get_free (void) uint64_t ua_elapsed; uint64_t al_elapsed; - ticks = cpu_get_ticks (); + ticks = qemu_get_clock(rt_clock); delta = ticks - old_ticks; old_ticks = ticks; - ua_elapsed = (delta * bytes_per_second) / ticks_per_sec; + ua_elapsed = (delta * bytes_per_second) / 1000; al_elapsed = ua_elapsed & ~3ULL; ldebug ("tid elapsed %llu bytes\n", ua_elapsed); diff --git a/sdl.c b/sdl.c index 5f1538f03..f705eb7fa 100644 --- a/sdl.c +++ b/sdl.c @@ -49,6 +49,7 @@ static SDL_Surface *screen; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ +static int last_vm_running; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { @@ -165,22 +166,35 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) } } +static void sdl_update_caption(void) +{ + char buf[1024]; + strcpy(buf, "QEMU"); + if (!vm_running) { + strcat(buf, " [Stopped]"); + } + if (gui_grab) { + strcat(buf, " - Press Ctrl-Shift to exit grab"); + } + SDL_WM_SetCaption(buf, "QEMU"); +} + static void sdl_grab_start(void) { - SDL_WM_SetCaption("QEMU - Press Ctrl-Shift to exit grab", "QEMU"); SDL_ShowCursor(0); SDL_WM_GrabInput(SDL_GRAB_ON); /* dummy read to avoid moving the mouse */ SDL_GetRelativeMouseState(NULL, NULL); gui_grab = 1; + sdl_update_caption(); } static void sdl_grab_end(void) { - SDL_WM_SetCaption("QEMU", "QEMU"); SDL_WM_GrabInput(SDL_GRAB_OFF); SDL_ShowCursor(1); gui_grab = 0; + sdl_update_caption(); } static void sdl_send_mouse_event(void) @@ -209,6 +223,11 @@ static void sdl_refresh(DisplayState *ds) { SDL_Event ev1, *ev = &ev1; + if (last_vm_running != vm_running) { + last_vm_running = vm_running; + sdl_update_caption(); + } + vga_update_display(); while (SDL_PollEvent(ev)) { switch (ev->type) { @@ -281,7 +300,7 @@ void sdl_display_init(DisplayState *ds) ds->dpy_refresh = sdl_refresh; sdl_resize(ds, 640, 400); - SDL_WM_SetCaption("QEMU", "QEMU"); + sdl_update_caption(); SDL_EnableKeyRepeat(250, 50); gui_grab = 0; diff --git a/vl.c b/vl.c index c3204eb71..92ddb8790 100644 --- a/vl.c +++ b/vl.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,7 @@ #include "disas.h" #include "vl.h" +#include "exec-all.h" #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" @@ -60,19 +62,8 @@ #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024) #endif -#if defined (TARGET_I386) -#elif defined (TARGET_PPC) -//#define USE_OPEN_FIRMWARE -#if !defined (USE_OPEN_FIRMWARE) -#define KERNEL_LOAD_ADDR 0x01000000 -#define KERNEL_STACK_ADDR 0x01200000 -#else -#define KERNEL_LOAD_ADDR 0x00000000 -#define KERNEL_STACK_ADDR 0x00400000 -#endif -#endif - -#define GUI_REFRESH_INTERVAL 30 +/* in ms */ +#define GUI_REFRESH_INTERVAL 30 /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 @@ -88,7 +79,6 @@ BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD]; int vga_ram_size; static DisplayState display_state; int nographic; -int term_inited; int64_t ticks_per_sec; int boot_device = 'c'; static int ram_size; @@ -97,6 +87,8 @@ int pit_min_timer_count = 0; int nb_nics; NetDriverState nd_table[MAX_NICS]; SerialState *serial_console; +QEMUTimer *gui_timer; +int vm_running; /***********************************************************/ /* x86 io ports */ @@ -308,6 +300,9 @@ void hw_error(const char *fmt, ...) abort(); } +/***********************************************************/ +/* timers */ + #if defined(__powerpc__) static inline uint32_t get_tbl(void) @@ -350,24 +345,34 @@ int64_t cpu_get_real_ticks(void) #endif static int64_t cpu_ticks_offset; -static int64_t cpu_ticks_last; +static int cpu_ticks_enabled; -int64_t cpu_get_ticks(void) +static inline int64_t cpu_get_ticks(void) { - return cpu_get_real_ticks() + cpu_ticks_offset; + if (!cpu_ticks_enabled) { + return cpu_ticks_offset; + } else { + return cpu_get_real_ticks() + cpu_ticks_offset; + } } /* enable cpu_get_ticks() */ void cpu_enable_ticks(void) { - cpu_ticks_offset = cpu_ticks_last - cpu_get_real_ticks(); + if (!cpu_ticks_enabled) { + cpu_ticks_offset -= cpu_get_real_ticks(); + cpu_ticks_enabled = 1; + } } /* disable cpu_get_ticks() : the clock is stopped. You must not call cpu_get_ticks() after that. */ void cpu_disable_ticks(void) { - cpu_ticks_last = cpu_get_ticks(); + if (cpu_ticks_enabled) { + cpu_ticks_offset = cpu_get_ticks(); + cpu_ticks_enabled = 0; + } } int64_t get_clock(void) @@ -382,10 +387,10 @@ void cpu_calibrate_ticks(void) int64_t usec, ticks; usec = get_clock(); - ticks = cpu_get_ticks(); + ticks = cpu_get_real_ticks(); usleep(50 * 1000); usec = get_clock() - usec; - ticks = cpu_get_ticks() - ticks; + ticks = cpu_get_real_ticks() - ticks; ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; } @@ -413,6 +418,239 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) return res.ll; } +#define QEMU_TIMER_REALTIME 0 +#define QEMU_TIMER_VIRTUAL 1 + +struct QEMUClock { + int type; + /* XXX: add frequency */ +}; + +struct QEMUTimer { + QEMUClock *clock; + int64_t expire_time; + QEMUTimerCB *cb; + void *opaque; + struct QEMUTimer *next; +}; + +QEMUClock *rt_clock; +QEMUClock *vm_clock; + +static QEMUTimer *active_timers[2]; +/* frequency of the times() clock tick */ +static int timer_freq; + +QEMUClock *qemu_new_clock(int type) +{ + QEMUClock *clock; + clock = qemu_mallocz(sizeof(QEMUClock)); + if (!clock) + return NULL; + clock->type = type; + return clock; +} + +QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque) +{ + QEMUTimer *ts; + + ts = qemu_mallocz(sizeof(QEMUTimer)); + ts->clock = clock; + ts->cb = cb; + ts->opaque = opaque; + return ts; +} + +void qemu_free_timer(QEMUTimer *ts) +{ + qemu_free(ts); +} + +/* stop a timer, but do not dealloc it */ +void qemu_del_timer(QEMUTimer *ts) +{ + QEMUTimer **pt, *t; + + /* NOTE: this code must be signal safe because + qemu_timer_expired() can be called from a signal. */ + pt = &active_timers[ts->clock->type]; + for(;;) { + t = *pt; + if (!t) + break; + if (t == ts) { + *pt = t->next; + break; + } + pt = &t->next; + } +} + +/* modify the current timer so that it will be fired when current_time + >= expire_time. The corresponding callback will be called. */ +void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) +{ + QEMUTimer **pt, *t; + + qemu_del_timer(ts); + + /* add the timer in the sorted list */ + /* NOTE: this code must be signal safe because + qemu_timer_expired() can be called from a signal. */ + pt = &active_timers[ts->clock->type]; + for(;;) { + t = *pt; + if (!t) + break; + if (t->expire_time > expire_time) + break; + pt = &t->next; + } + ts->expire_time = expire_time; + ts->next = *pt; + *pt = ts; +} + +int qemu_timer_pending(QEMUTimer *ts) +{ + QEMUTimer *t; + for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) { + if (t == ts) + return 1; + } + return 0; +} + +static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) +{ + if (!timer_head) + return 0; + return (timer_head->expire_time <= current_time); +} + +static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) +{ + QEMUTimer *ts; + + for(;;) { + ts = *ptimer_head; + if (ts->expire_time > current_time) + break; + /* remove timer from the list before calling the callback */ + *ptimer_head = ts->next; + ts->next = NULL; + + /* run the callback (the timer list can be modified) */ + ts->cb(ts->opaque); + } +} + +int64_t qemu_get_clock(QEMUClock *clock) +{ + switch(clock->type) { + case QEMU_TIMER_REALTIME: + /* XXX: portability among Linux hosts */ + if (timer_freq == 100) { + return times(NULL) * 10; + } else { + return ((int64_t)times(NULL) * 1000) / timer_freq; + } + default: + case QEMU_TIMER_VIRTUAL: + return cpu_get_ticks(); + } +} + +/* save a timer */ +void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) +{ + uint64_t expire_time; + + if (qemu_timer_pending(ts)) { + expire_time = ts->expire_time; + } else { + expire_time = -1; + } + qemu_put_be64(f, expire_time); +} + +void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) +{ + uint64_t expire_time; + + expire_time = qemu_get_be64(f); + if (expire_time != -1) { + qemu_mod_timer(ts, expire_time); + } else { + qemu_del_timer(ts); + } +} + +static void timer_save(QEMUFile *f, void *opaque) +{ + if (cpu_ticks_enabled) { + hw_error("cannot save state if virtual timers are running"); + } + qemu_put_be64s(f, &cpu_ticks_offset); + qemu_put_be64s(f, &ticks_per_sec); +} + +static int timer_load(QEMUFile *f, void *opaque, int version_id) +{ + if (version_id != 1) + return -EINVAL; + if (cpu_ticks_enabled) { + return -EINVAL; + } + qemu_get_be64s(f, &cpu_ticks_offset); + qemu_get_be64s(f, &ticks_per_sec); + return 0; +} + +static void host_alarm_handler(int host_signum) +{ + if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], + qemu_get_clock(vm_clock)) || + qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], + qemu_get_clock(rt_clock))) { + /* stop the cpu because a timer occured */ + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); + } +} + +static void init_timers(void) +{ + struct sigaction act; + struct itimerval itv; + + /* get times() syscall frequency */ + timer_freq = sysconf(_SC_CLK_TCK); + + rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); + vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL); + + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = 0; +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + act.sa_flags |= SA_ONSTACK; +#endif + act.sa_handler = host_alarm_handler; + sigaction(SIGALRM, &act, NULL); + + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 1000; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 10 * 1000; + setitimer(ITIMER_REAL, &itv, NULL); + /* we probe the tick duration of the kernel to inform the user if + the emulated kernel requested a too high timer frequency */ + getitimer(ITIMER_REAL, &itv); + pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / + 1000000; +} + /***********************************************************/ /* serial device */ @@ -588,36 +826,8 @@ static void host_segv_handler(int host_signum, siginfo_t *info, } #endif -static int timer_irq_pending; -static int timer_irq_count; - -static int timer_ms; -static int gui_refresh_pending, gui_refresh_count; - -static void host_alarm_handler(int host_signum, siginfo_t *info, - void *puc) -{ - /* NOTE: since usually the OS asks a 100 Hz clock, there can be - some drift between cpu_get_ticks() and the interrupt time. So - we queue some interrupts to avoid missing some */ - timer_irq_count += pit_get_out_edges(&pit_channels[0]); - if (timer_irq_count) { - if (timer_irq_count > 2) - timer_irq_count = 2; - timer_irq_count--; - timer_irq_pending = 1; - } - gui_refresh_count += timer_ms; - if (gui_refresh_count >= GUI_REFRESH_INTERVAL) { - gui_refresh_count = 0; - gui_refresh_pending = 1; - } - - if (gui_refresh_pending || timer_irq_pending) { - /* just exit from the cpu to have a chance to handle timers */ - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); - } -} +/***********************************************************/ +/* I/O handling */ #define MAX_IO_HANDLERS 64 @@ -629,142 +839,653 @@ typedef struct IOHandlerRecord { /* temporary data */ struct pollfd *ufd; int max_size; + struct IOHandlerRecord *next; } IOHandlerRecord; -static IOHandlerRecord io_handlers[MAX_IO_HANDLERS]; -static int nb_io_handlers = 0; +static IOHandlerRecord *first_io_handler; -int add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) { IOHandlerRecord *ioh; - if (nb_io_handlers >= MAX_IO_HANDLERS) + ioh = qemu_mallocz(sizeof(IOHandlerRecord)); + if (!ioh) return -1; - ioh = &io_handlers[nb_io_handlers]; ioh->fd = fd; ioh->fd_can_read = fd_can_read; ioh->fd_read = fd_read; ioh->opaque = opaque; - nb_io_handlers++; + ioh->next = first_io_handler; + first_io_handler = ioh; return 0; } -/* main execution loop */ +void qemu_del_fd_read_handler(int fd) +{ + IOHandlerRecord **pioh, *ioh; -CPUState *cpu_gdbstub_get_env(void *opaque) + pioh = &first_io_handler; + for(;;) { + ioh = *pioh; + if (ioh == NULL) + break; + if (ioh->fd == fd) { + *pioh = ioh->next; + break; + } + pioh = &ioh->next; + } +} + +/***********************************************************/ +/* savevm/loadvm support */ + +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) { - return global_env; + fwrite(buf, 1, size, f); } -int main_loop(void *opaque) +void qemu_put_byte(QEMUFile *f, int v) { - struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf, *gdb_ufd; - int ret, n, timeout, serial_ok, max_size, i; - uint8_t buf[4096]; - IOHandlerRecord *ioh; - CPUState *env = global_env; + fputc(v, f); +} + +void qemu_put_be16(QEMUFile *f, unsigned int v) +{ + qemu_put_byte(f, v >> 8); + qemu_put_byte(f, v); +} + +void qemu_put_be32(QEMUFile *f, unsigned int v) +{ + qemu_put_byte(f, v >> 24); + qemu_put_byte(f, v >> 16); + qemu_put_byte(f, v >> 8); + qemu_put_byte(f, v); +} + +void qemu_put_be64(QEMUFile *f, uint64_t v) +{ + qemu_put_be32(f, v >> 32); + qemu_put_be32(f, v); +} + +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) +{ + return fread(buf, 1, size, f); +} + +int qemu_get_byte(QEMUFile *f) +{ + int v; + v = fgetc(f); + if (v == EOF) + return 0; + else + return v; +} + +unsigned int qemu_get_be16(QEMUFile *f) +{ + unsigned int v; + v = qemu_get_byte(f) << 8; + v |= qemu_get_byte(f); + return v; +} + +unsigned int qemu_get_be32(QEMUFile *f) +{ + unsigned int v; + v = qemu_get_byte(f) << 24; + v |= qemu_get_byte(f) << 16; + v |= qemu_get_byte(f) << 8; + v |= qemu_get_byte(f); + return v; +} + +uint64_t qemu_get_be64(QEMUFile *f) +{ + uint64_t v; + v = (uint64_t)qemu_get_be32(f) << 32; + v |= qemu_get_be32(f); + return v; +} + +int64_t qemu_ftell(QEMUFile *f) +{ + return ftell(f); +} + +int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) +{ + if (fseek(f, pos, whence) < 0) + return -1; + return ftell(f); +} + +typedef struct SaveStateEntry { + char idstr[256]; + int instance_id; + int version_id; + SaveStateHandler *save_state; + LoadStateHandler *load_state; + void *opaque; + struct SaveStateEntry *next; +} SaveStateEntry; - if (!term_inited) { - /* initialize terminal only there so that the user has a - chance to stop QEMU with Ctrl-C before the gdb connection - is launched */ - term_inited = 1; - term_init(); +static SaveStateEntry *first_se; + +int register_savevm(const char *idstr, + int instance_id, + int version_id, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque) +{ + SaveStateEntry *se, **pse; + + se = qemu_malloc(sizeof(SaveStateEntry)); + if (!se) + return -1; + pstrcpy(se->idstr, sizeof(se->idstr), idstr); + se->instance_id = instance_id; + se->version_id = version_id; + se->save_state = save_state; + se->load_state = load_state; + se->opaque = opaque; + se->next = NULL; + + /* add at the end of list */ + pse = &first_se; + while (*pse != NULL) + pse = &(*pse)->next; + *pse = se; + return 0; +} + +#define QEMU_VM_FILE_MAGIC 0x5145564d +#define QEMU_VM_FILE_VERSION 0x00000001 + +int qemu_savevm(const char *filename) +{ + SaveStateEntry *se; + QEMUFile *f; + int len, len_pos, cur_pos, saved_vm_running, ret; + + saved_vm_running = vm_running; + vm_stop(0); + + f = fopen(filename, "wb"); + if (!f) { + ret = -1; + goto the_end; } - serial_ok = 1; - cpu_enable_ticks(); + qemu_put_be32(f, QEMU_VM_FILE_MAGIC); + qemu_put_be32(f, QEMU_VM_FILE_VERSION); + + for(se = first_se; se != NULL; se = se->next) { + /* ID string */ + len = strlen(se->idstr); + qemu_put_byte(f, len); + qemu_put_buffer(f, se->idstr, len); + + qemu_put_be32(f, se->instance_id); + qemu_put_be32(f, se->version_id); + + /* record size: filled later */ + len_pos = ftell(f); + qemu_put_be32(f, 0); + + se->save_state(f, se->opaque); + + /* fill record size */ + cur_pos = ftell(f); + len = ftell(f) - len_pos - 4; + fseek(f, len_pos, SEEK_SET); + qemu_put_be32(f, len); + fseek(f, cur_pos, SEEK_SET); + } + + fclose(f); + ret = 0; + the_end: + if (saved_vm_running) + vm_start(); + return ret; +} + +static SaveStateEntry *find_se(const char *idstr, int instance_id) +{ + SaveStateEntry *se; + + for(se = first_se; se != NULL; se = se->next) { + if (!strcmp(se->idstr, idstr) && + instance_id == se->instance_id) + return se; + } + return NULL; +} + +int qemu_loadvm(const char *filename) +{ + SaveStateEntry *se; + QEMUFile *f; + int len, cur_pos, ret, instance_id, record_len, version_id; + int saved_vm_running; + unsigned int v; + char idstr[256]; + + saved_vm_running = vm_running; + vm_stop(0); + + f = fopen(filename, "rb"); + if (!f) { + ret = -1; + goto the_end; + } + + v = qemu_get_be32(f); + if (v != QEMU_VM_FILE_MAGIC) + goto fail; + v = qemu_get_be32(f); + if (v != QEMU_VM_FILE_VERSION) { + fail: + fclose(f); + ret = -1; + goto the_end; + } for(;;) { -#if defined (DO_TB_FLUSH) - tb_flush(); -#endif - ret = cpu_exec(env); - if (reset_requested) { - ret = EXCP_INTERRUPT; + len = qemu_get_byte(f); + if (feof(f)) break; + qemu_get_buffer(f, idstr, len); + idstr[len] = '\0'; + instance_id = qemu_get_be32(f); + version_id = qemu_get_be32(f); + record_len = qemu_get_be32(f); +#if 0 + printf("idstr=%s instance=0x%x version=%d len=%d\n", + idstr, instance_id, version_id, record_len); +#endif + cur_pos = ftell(f); + se = find_se(idstr, instance_id); + if (!se) { + fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", + instance_id, idstr); + } else { + ret = se->load_state(f, se->opaque, version_id); + if (ret < 0) { + fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", + instance_id, idstr); + } } - if (ret == EXCP_DEBUG) { - ret = EXCP_DEBUG; - break; + /* always seek to exact end of record */ + qemu_fseek(f, cur_pos + record_len, SEEK_SET); + } + fclose(f); + ret = 0; + the_end: + if (saved_vm_running) + vm_start(); + return ret; +} + +/***********************************************************/ +/* cpu save/restore */ + +#if defined(TARGET_I386) + +static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) +{ + qemu_put_be32(f, (uint32_t)dt->base); + qemu_put_be32(f, dt->limit); + qemu_put_be32(f, dt->flags); +} + +static void cpu_get_seg(QEMUFile *f, SegmentCache *dt) +{ + dt->base = (uint8_t *)qemu_get_be32(f); + dt->limit = qemu_get_be32(f); + dt->flags = qemu_get_be32(f); +} + +void cpu_save(QEMUFile *f, void *opaque) +{ + CPUState *env = opaque; + uint16_t fptag, fpus, fpuc; + uint32_t hflags; + int i; + + for(i = 0; i < 8; i++) + qemu_put_be32s(f, &env->regs[i]); + qemu_put_be32s(f, &env->eip); + qemu_put_be32s(f, &env->eflags); + qemu_put_be32s(f, &env->eflags); + hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ + qemu_put_be32s(f, &hflags); + + /* FPU */ + fpuc = env->fpuc; + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for (i=7; i>=0; i--) { + fptag <<= 2; + if (env->fptags[i]) { + fptag |= 3; + } + } + + qemu_put_be16s(f, &fpuc); + qemu_put_be16s(f, &fpus); + qemu_put_be16s(f, &fptag); + + for(i = 0; i < 8; i++) { + uint64_t mant; + uint16_t exp; + cpu_get_fp80(&mant, &exp, env->fpregs[i]); + qemu_put_be64(f, mant); + qemu_put_be16(f, exp); + } + + for(i = 0; i < 6; i++) + cpu_put_seg(f, &env->segs[i]); + cpu_put_seg(f, &env->ldt); + cpu_put_seg(f, &env->tr); + cpu_put_seg(f, &env->gdt); + cpu_put_seg(f, &env->idt); + + qemu_put_be32s(f, &env->sysenter_cs); + qemu_put_be32s(f, &env->sysenter_esp); + qemu_put_be32s(f, &env->sysenter_eip); + + qemu_put_be32s(f, &env->cr[0]); + qemu_put_be32s(f, &env->cr[2]); + qemu_put_be32s(f, &env->cr[3]); + qemu_put_be32s(f, &env->cr[4]); + + for(i = 0; i < 8; i++) + qemu_put_be32s(f, &env->dr[i]); + + /* MMU */ + qemu_put_be32s(f, &env->a20_mask); +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + CPUState *env = opaque; + int i; + uint32_t hflags; + uint16_t fpus, fpuc, fptag; + + if (version_id != 1) + return -EINVAL; + for(i = 0; i < 8; i++) + qemu_get_be32s(f, &env->regs[i]); + qemu_get_be32s(f, &env->eip); + qemu_get_be32s(f, &env->eflags); + qemu_get_be32s(f, &env->eflags); + qemu_get_be32s(f, &hflags); + + qemu_get_be16s(f, &fpuc); + qemu_get_be16s(f, &fpus); + qemu_get_be16s(f, &fptag); + + for(i = 0; i < 8; i++) { + uint64_t mant; + uint16_t exp; + mant = qemu_get_be64(f); + exp = qemu_get_be16(f); + env->fpregs[i] = cpu_set_fp80(mant, exp); + } + + env->fpuc = fpuc; + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + for(i = 0; i < 8; i++) { + env->fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } + + for(i = 0; i < 6; i++) + cpu_get_seg(f, &env->segs[i]); + cpu_get_seg(f, &env->ldt); + cpu_get_seg(f, &env->tr); + cpu_get_seg(f, &env->gdt); + cpu_get_seg(f, &env->idt); + + qemu_get_be32s(f, &env->sysenter_cs); + qemu_get_be32s(f, &env->sysenter_esp); + qemu_get_be32s(f, &env->sysenter_eip); + + qemu_get_be32s(f, &env->cr[0]); + qemu_get_be32s(f, &env->cr[2]); + qemu_get_be32s(f, &env->cr[3]); + qemu_get_be32s(f, &env->cr[4]); + + for(i = 0; i < 8; i++) + qemu_get_be32s(f, &env->dr[i]); + + /* MMU */ + qemu_get_be32s(f, &env->a20_mask); + + /* XXX: compute hflags from scratch, except for CPL and IIF */ + env->hflags = hflags; + tlb_flush(env, 1); + return 0; +} + +#else + +#warning No CPU save/restore functions + +#endif + +/***********************************************************/ +/* ram save/restore */ + +/* we just avoid storing empty pages */ +static void ram_put_page(QEMUFile *f, const uint8_t *buf, int len) +{ + int i, v; + + v = buf[0]; + for(i = 1; i < len; i++) { + if (buf[i] != v) + goto normal_save; + } + qemu_put_byte(f, 1); + qemu_put_byte(f, v); + return; + normal_save: + qemu_put_byte(f, 0); + qemu_put_buffer(f, buf, len); +} + +static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) +{ + int v; + + v = qemu_get_byte(f); + switch(v) { + case 0: + if (qemu_get_buffer(f, buf, len) != len) + return -EIO; + break; + case 1: + v = qemu_get_byte(f); + memset(buf, v, len); + break; + default: + return -EINVAL; + } + return 0; +} + +static void ram_save(QEMUFile *f, void *opaque) +{ + int i; + qemu_put_be32(f, phys_ram_size); + for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) { + ram_put_page(f, phys_ram_base + i, TARGET_PAGE_SIZE); + } +} + +static int ram_load(QEMUFile *f, void *opaque, int version_id) +{ + int i, ret; + + if (version_id != 1) + return -EINVAL; + if (qemu_get_be32(f) != phys_ram_size) + return -EINVAL; + for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) { + ret = ram_get_page(f, phys_ram_base + i, TARGET_PAGE_SIZE); + if (ret) + return ret; + } + return 0; +} + +/***********************************************************/ +/* main execution loop */ + +void gui_update(void *opaque) +{ + display_state.dpy_refresh(&display_state); + qemu_mod_timer(gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock)); +} + +/* XXX: support several handlers */ +VMStopHandler *vm_stop_cb; +VMStopHandler *vm_stop_opaque; + +int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque) +{ + vm_stop_cb = cb; + vm_stop_opaque = opaque; + return 0; +} + +void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque) +{ + vm_stop_cb = NULL; +} + +void vm_start(void) +{ + if (!vm_running) { + cpu_enable_ticks(); + vm_running = 1; + } +} + +void vm_stop(int reason) +{ + if (vm_running) { + cpu_disable_ticks(); + vm_running = 0; + if (reason != 0) { + if (vm_stop_cb) { + vm_stop_cb(vm_stop_opaque, reason); + } } - /* if hlt instruction, we wait until the next IRQ */ - if (ret == EXCP_HLT) + } +} + +int main_loop(void) +{ + struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf; + int ret, n, timeout, max_size; + uint8_t buf[4096]; + IOHandlerRecord *ioh, *ioh_next; + CPUState *env = global_env; + + for(;;) { + if (vm_running) { + ret = cpu_exec(env); + if (reset_requested) { + ret = EXCP_INTERRUPT; + break; + } + if (ret == EXCP_DEBUG) { + vm_stop(EXCP_DEBUG); + } + /* if hlt instruction, we wait until the next IRQ */ + /* XXX: use timeout computed from timers */ + if (ret == EXCP_HLT) + timeout = 10; + else + timeout = 0; + } else { timeout = 10; - else - timeout = 0; + } /* poll any events */ + /* XXX: separate device handlers from system ones */ pf = ufds; - ioh = io_handlers; - for(i = 0; i < nb_io_handlers; i++) { - max_size = ioh->fd_can_read(ioh->opaque); - if (max_size > 0) { - if (max_size > sizeof(buf)) - max_size = sizeof(buf); + for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { + if (!ioh->fd_can_read) { + max_size = 0; pf->fd = ioh->fd; pf->events = POLLIN; ioh->ufd = pf; pf++; } else { - ioh->ufd = NULL; + max_size = ioh->fd_can_read(ioh->opaque); + if (max_size > 0) { + if (max_size > sizeof(buf)) + max_size = sizeof(buf); + pf->fd = ioh->fd; + pf->events = POLLIN; + ioh->ufd = pf; + pf++; + } else { + ioh->ufd = NULL; + } } ioh->max_size = max_size; - ioh++; - } - - gdb_ufd = NULL; - if (gdbstub_fd > 0) { - gdb_ufd = pf; - pf->fd = gdbstub_fd; - pf->events = POLLIN; - pf++; } ret = poll(ufds, pf - ufds, timeout); if (ret > 0) { - ioh = io_handlers; - for(i = 0; i < nb_io_handlers; i++) { + /* XXX: better handling of removal */ + for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { + ioh_next = ioh->next; pf = ioh->ufd; if (pf) { - n = read(ioh->fd, buf, ioh->max_size); - if (n > 0) { - ioh->fd_read(ioh->opaque, buf, n); + if (pf->revents & POLLIN) { + if (ioh->max_size == 0) { + /* just a read event */ + ioh->fd_read(ioh->opaque, NULL, 0); + } else { + n = read(ioh->fd, buf, ioh->max_size); + if (n >= 0) { + ioh->fd_read(ioh->opaque, buf, n); + } else if (errno != -EAGAIN) { + ioh->fd_read(ioh->opaque, NULL, -errno); + } + } } } - ioh++; - } - if (gdb_ufd && (gdb_ufd->revents & POLLIN)) { - uint8_t buf[1]; - /* stop emulation if requested by gdb */ - n = read(gdbstub_fd, buf, 1); - if (n == 1) { - ret = EXCP_INTERRUPT; - break; - } } } - /* timer IRQ */ - if (timer_irq_pending) { -#if defined (TARGET_I386) - pic_set_irq(0, 1); - pic_set_irq(0, 0); - timer_irq_pending = 0; - rtc_timer(); -#endif + if (vm_running) { + qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], + qemu_get_clock(vm_clock)); + + /* XXX: add explicit timer */ + SB16_run(); + + /* run dma transfers, if any */ + DMA_run(); } - /* XXX: add explicit timer */ - SB16_run(); - - /* run dma transfers, if any */ - DMA_run(); - /* VGA */ - if (gui_refresh_pending) { - display_state.dpy_refresh(&display_state); - gui_refresh_pending = 0; - } + /* real time timers */ + qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], + qemu_get_clock(rt_clock)); } cpu_disable_ticks(); return ret; @@ -873,8 +1594,6 @@ int main(int argc, char **argv) { int c, i, use_gdbstub, gdbstub_port, long_index, has_cdrom; int snapshot, linux_boot; - struct sigaction act; - struct itimerval itv; CPUState *env; const char *initrd_filename; const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; @@ -1186,11 +1905,17 @@ int main(int argc, char **argv) } } + init_timers(); + /* init CPU state */ env = cpu_init(); global_env = env; cpu_single_env = env; + register_savevm("timer", 0, 1, timer_save, timer_load, env); + register_savevm("cpu", 0, 1, cpu_save, cpu_load, env); + register_savevm("ram", 0, 1, ram_save, ram_load, NULL); + init_ioports(); cpu_calibrate_ticks(); @@ -1219,7 +1944,7 @@ int main(int argc, char **argv) /* setup cpu signal handlers for MMU / self modifying code handling */ #if !defined(CONFIG_SOFTMMU) - + #if defined (TARGET_I386) && defined(USE_CODE_COPY) { stack_t stk; @@ -1234,45 +1959,46 @@ int main(int argc, char **argv) } } #endif + { + struct sigaction act; - sigfillset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; + sigfillset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; #if defined (TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; + act.sa_flags |= SA_ONSTACK; #endif - act.sa_sigaction = host_segv_handler; - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGBUS, &act, NULL); + act.sa_sigaction = host_segv_handler; + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGBUS, &act, NULL); #if defined (TARGET_I386) && defined(USE_CODE_COPY) - sigaction(SIGFPE, &act, NULL); + sigaction(SIGFPE, &act, NULL); #endif + } #endif - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; -#endif - act.sa_sigaction = host_alarm_handler; - sigaction(SIGALRM, &act, NULL); + { + struct sigaction act; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + } - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 1000; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 10 * 1000; - setitimer(ITIMER_REAL, &itv, NULL); - /* we probe the tick duration of the kernel to inform the user if - the emulated kernel requested a too high timer frequency */ - getitimer(ITIMER_REAL, &itv); - timer_ms = itv.it_interval.tv_usec / 1000; - pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / - 1000000; + gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); + qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); if (use_gdbstub) { - cpu_gdbstub(NULL, main_loop, gdbstub_port); + if (gdbserver_start(gdbstub_port) < 0) { + fprintf(stderr, "Could not open gdbserver socket on port %d\n", + gdbstub_port); + exit(1); + } else { + printf("Waiting gdb connection on port %d\n", gdbstub_port); + } } else { - main_loop(NULL); + vm_start(); } + term_init(); + main_loop(); return 0; } diff --git a/vl.h b/vl.h index 2377602dc..2805853a7 100644 --- a/vl.h +++ b/vl.h @@ -24,12 +24,12 @@ #ifndef VL_H #define VL_H +#include + #include "cpu.h" /* vl.c */ extern int reset_requested; -extern int64_t ticks_per_sec; -extern int pit_min_timer_count; typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); @@ -38,7 +38,6 @@ int register_ioport_read(int start, int length, int size, IOPortReadFunc *func, void *opaque); int register_ioport_write(int start, int length, int size, IOPortWriteFunc *func, void *opaque); -int64_t cpu_get_ticks(void); uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); void hw_error(const char *fmt, ...); @@ -51,6 +50,16 @@ char *pstrcat(char *buf, int buf_size, const char *s); int serial_open_device(void); +extern int vm_running; + +typedef void VMStopHandler(void *opaque, int reason); + +int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque); +void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque); + +void vm_start(void); +void vm_stop(int reason); + /* network redirectors support */ #define MAX_NICS 8 @@ -71,8 +80,112 @@ void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size); typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); typedef int IOCanRWHandler(void *opaque); -int add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque); +int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque); +void qemu_del_fd_read_handler(int fd); + +/* timers */ + +typedef struct QEMUClock QEMUClock; +typedef struct QEMUTimer QEMUTimer; +typedef void QEMUTimerCB(void *opaque); + +/* The real time clock should be used only for stuff which does not + change the virtual machine state, as it is run even if the virtual + machine is stopped. The real time clock has a frequency or 1000 + Hz. */ +extern QEMUClock *rt_clock; + +/* Rge virtual clock is only run during the emulation. It is stopped + when the virtual machine is stopped. Virtual timers use a high + precision clock, usually cpu cycles (use ticks_per_sec). */ +extern QEMUClock *vm_clock; + +int64_t qemu_get_clock(QEMUClock *clock); + +QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); +void qemu_free_timer(QEMUTimer *ts); +void qemu_del_timer(QEMUTimer *ts); +void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); +int qemu_timer_pending(QEMUTimer *ts); + +extern int64_t ticks_per_sec; +extern int pit_min_timer_count; + +void cpu_enable_ticks(void); +void cpu_disable_ticks(void); + +/* VM Load/Save */ + +typedef FILE QEMUFile; + +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); +void qemu_put_byte(QEMUFile *f, int v); +void qemu_put_be16(QEMUFile *f, unsigned int v); +void qemu_put_be32(QEMUFile *f, unsigned int v); +void qemu_put_be64(QEMUFile *f, uint64_t v); +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); +int qemu_get_byte(QEMUFile *f); +unsigned int qemu_get_be16(QEMUFile *f); +unsigned int qemu_get_be32(QEMUFile *f); +uint64_t qemu_get_be64(QEMUFile *f); + +static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) +{ + qemu_put_be64(f, *pv); +} + +static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv) +{ + qemu_put_be32(f, *pv); +} + +static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv) +{ + qemu_put_be16(f, *pv); +} + +static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv) +{ + qemu_put_byte(f, *pv); +} + +static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv) +{ + *pv = qemu_get_be64(f); +} + +static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv) +{ + *pv = qemu_get_be32(f); +} + +static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv) +{ + *pv = qemu_get_be16(f); +} + +static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv) +{ + *pv = qemu_get_byte(f); +} + +int64_t qemu_ftell(QEMUFile *f); +int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); + +typedef void SaveStateHandler(QEMUFile *f, void *opaque); +typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); + +int qemu_loadvm(const char *filename); +int qemu_savevm(const char *filename); +int register_savevm(const char *idstr, + int instance_id, + int version_id, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque); +void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); +void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); /* block.c */ typedef struct BlockDriverState BlockDriverState; @@ -210,16 +323,11 @@ void kbd_init(void); /* mc146818rtc.c */ -typedef struct RTCState { - uint8_t cmos_data[128]; - uint8_t cmos_index; - int irq; -} RTCState; - -extern RTCState rtc_state; +typedef struct RTCState RTCState; -void rtc_init(int base, int irq); -void rtc_timer(void); +RTCState *rtc_init(int base, int irq); +void rtc_set_memory(RTCState *s, int addr, int val); +void rtc_set_date(RTCState *s, const struct tm *tm); /* serial.c */ @@ -249,14 +357,17 @@ typedef struct PITChannelState { uint8_t bcd; /* not supported */ uint8_t gate; /* timer start */ int64_t count_load_time; - int64_t count_last_edge_check_time; + /* irq handling */ + int64_t next_transition_time; + QEMUTimer *irq_timer; + int irq; } PITChannelState; extern PITChannelState pit_channels[3]; -void pit_init(int base); +void pit_init(int base, int irq); void pit_set_gate(PITChannelState *s, int val); -int pit_get_out(PITChannelState *s); +int pit_get_out(PITChannelState *s, int64_t current_time); int pit_get_out_edges(PITChannelState *s); /* pc.c */ @@ -271,4 +382,10 @@ void term_printf(const char *fmt, ...); void term_flush(void); void term_print_help(void); +/* gdbstub.c */ + +#define DEFAULT_GDBSTUB_PORT 1234 + +int gdbserver_start(int port); + #endif /* VL_H */ -- cgit v1.2.3 From bb27c19087ff0847484c111cbaf56a3fa7103684 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 31 Mar 2004 19:05:07 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@691 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 95d997066..451869ab1 100644 --- a/Changelog +++ b/Changelog @@ -20,7 +20,11 @@ version 0.5.3: - 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) + version 0.5.2: - improved soft MMU speed (assembly functions and specializing) -- cgit v1.2.3 From 67b915a5dd52a05f8030cd9edc005effd9c8eea5 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 31 Mar 2004 23:37:16 +0000 Subject: win32 port (initial patch by kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@692 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile | 11 +- Makefile.target | 12 +- TODO | 5 +- block.c | 54 +-- configure | 30 +- cpu-exec.c | 4 + dyngen.c | 1062 ++++++++++++++++++++++++++++-------------- exec-all.h | 12 +- exec.c | 12 +- gdbstub.c | 10 +- hw/dma.c | 5 - hw/fdc.c | 5 - hw/i8254.c | 20 - hw/i8259.c | 20 - hw/ide.c | 136 +++--- hw/mc146818rtc.c | 20 - hw/ne2000.c | 20 - hw/pc.c | 26 +- hw/pckbd.c | 20 - hw/sb16.c | 5 - hw/serial.c | 20 - hw/vga.c | 22 - monitor.c | 23 +- osdep.c | 5 +- oss.c | 44 +- qemu-mkcow.c | 5 - sdl.c | 29 +- target-i386/helper2.c | 9 +- target-i386/translate-copy.c | 9 +- target-i386/translate.c | 1 - vl.c | 185 ++++++-- vl.h | 69 +++ 33 files changed, 1154 insertions(+), 757 deletions(-) diff --git a/Changelog b/Changelog index 451869ab1..6a6329c5b 100644 --- a/Changelog +++ b/Changelog @@ -24,6 +24,7 @@ version 0.5.3: - 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: diff --git a/Makefile b/Makefile index e55c072af..f2be1f6f8 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,17 @@ include config-host.mak CFLAGS=-Wall -O2 -g +ifdef CONFIG_WIN32 +CFLAGS+=-fpack-struct +endif LDFLAGS=-g LIBS= DEFINES+=-D_GNU_SOURCE +ifndef CONFIG_WIN32 TOOLS=qemu-mkcow +endif -all: dyngen $(TOOLS) qemu-doc.html qemu.1 +all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu.1 for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done @@ -14,7 +19,7 @@ all: dyngen $(TOOLS) qemu-doc.html qemu.1 qemu-mkcow: qemu-mkcow.o $(HOST_CC) -o $@ $^ $(LIBS) -dyngen: dyngen.o +dyngen$(EXESUF): dyngen.o $(HOST_CC) -o $@ $^ $(LIBS) %.o: %.c @@ -23,7 +28,7 @@ dyngen: dyngen.o clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h - rm -f *.o *.a $(TOOLS) dyngen TAGS qemu.pod + rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS qemu.pod make -C tests clean for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ diff --git a/Makefile.target b/Makefile.target index 7b79a8b09..1b578d0fd 100644 --- a/Makefile.target +++ b/Makefile.target @@ -11,12 +11,12 @@ CFLAGS=-Wall -O2 -g LDFLAGS=-g LIBS= HELPER_CFLAGS=$(CFLAGS) -DYNGEN=../dyngen +DYNGEN=../dyngen$(EXESUF) # user emulator name QEMU_USER=qemu-$(TARGET_ARCH) # system emulator name ifdef CONFIG_SOFTMMU -QEMU_SYSTEM=qemu +QEMU_SYSTEM=qemu$(EXESUF) else QEMU_SYSTEM=qemu-fast endif @@ -146,6 +146,9 @@ endif DEFINES+=-D_GNU_SOURCE LIBS+=-lm +ifdef CONFIG_WIN32 +LIBS+=-lwinmm +endif # profiling code ifdef TARGET_GPROF @@ -219,9 +222,12 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o gdbstub.o \ +VL_OBJS=vl.o osdep.o block.o monitor.o \ ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o +ifdef CONFIG_GDBSTUB +VL_OBJS+=gdbstub.o +endif ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= hw.o endif diff --git a/TODO b/TODO index b44483980..8f66ee5c0 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,12 @@ short term: ---------- +- handle fast timers + add explicit clocks +- OS/2 install bug +- win 95 install bug +- handle Self Modifying Code even if modifying current TB (BE OS 5 install) - physical memory cache (reduce qemu-fast address space size to about 32 MB) - better code fetch - XP security bug -- handle Self Modifying Code even if modifying current TB (BE OS 5 install) - cycle counter for all archs - TLB code protection support for PPC - add sysenter/sysexit and fxsr for L4 pistachio 686 diff --git a/block.c b/block.c index 3886ec099..5ed7a02b3 100644 --- a/block.c +++ b/block.c @@ -21,29 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "vl.h" -#define NO_THUNK_TYPE_SIZE -#include "thunk.h" +#ifndef _WIN32 +#include +#endif #include "cow.h" @@ -97,11 +79,14 @@ BlockDriverState *bdrv_new(const char *device_name) int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) { - int fd, cow_fd; + int fd; int64_t size; - char template[] = "/tmp/vl.XXXXXX"; struct cow_header_v2 cow_header; +#ifndef _WIN32 + char template[] = "/tmp/vl.XXXXXX"; + int cow_fd; struct stat st; +#endif bs->read_only = 0; bs->fd = -1; @@ -110,10 +95,18 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) strcpy(bs->filename, filename); /* open standard HD image */ +#ifdef _WIN32 + fd = open(filename, O_RDWR | O_BINARY); +#else fd = open(filename, O_RDWR | O_LARGEFILE); +#endif if (fd < 0) { /* read only image on disk */ +#ifdef _WIN32 + fd = open(filename, O_RDONLY | O_BINARY); +#else fd = open(filename, O_RDONLY | O_LARGEFILE); +#endif if (fd < 0) { perror(filename); goto fail; @@ -128,8 +121,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) fprintf(stderr, "%s: could not read header\n", filename); goto fail; } - if (cow_header.magic == htonl(COW_MAGIC) && - cow_header.version == htonl(COW_VERSION)) { +#ifndef _WIN32 + if (be32_to_cpu(cow_header.magic) == COW_MAGIC && + be32_to_cpu(cow_header.version) == COW_VERSION) { /* cow image found */ size = cow_header.size; #ifndef WORDS_BIGENDIAN @@ -144,7 +138,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); goto fail; } - if (st.st_mtime != htonl(cow_header.mtime)) { + if (st.st_mtime != be32_to_cpu(cow_header.mtime)) { fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); goto fail; } @@ -164,13 +158,16 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header); bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; snapshot = 0; - } else { + } else +#endif + { /* standard raw image */ size = lseek64(fd, 0, SEEK_END); bs->total_sectors = size / 512; bs->fd = fd; } +#ifndef _WIN32 if (snapshot) { /* create a temporary COW file */ cow_fd = mkstemp(template); @@ -190,6 +187,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) bs->cow_bitmap = bs->cow_bitmap_addr; bs->cow_sectors_offset = 0; } +#endif bs->inserted = 1; @@ -206,9 +204,11 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) void bdrv_close(BlockDriverState *bs) { if (bs->inserted) { +#ifndef _WIN32 /* we unmap the mapping so that it is written to the COW file */ if (bs->cow_bitmap_addr) munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); +#endif if (bs->cow_fd >= 0) close(bs->cow_fd); if (bs->fd >= 0) diff --git a/configure b/configure index f3f68b617..75340eae1 100755 --- a/configure +++ b/configure @@ -68,10 +68,16 @@ case "$cpu" in esac gprof="no" bigendian="no" +mingw32="no" +EXESUF="" +gdbstub="yes" # OS specific targetos=`uname -s` case $targetos in +MINGW32*) +mingw32="yes" +;; *) ;; esac @@ -136,6 +142,8 @@ for opt do ;; --disable-sdl) sdl="no" ;; + --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" + ;; esac done @@ -148,6 +156,14 @@ cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" +if test "$mingw32" = "yes" ; then + host_cc="$cc" + target_list="i386-softmmu" + prefix="/c/Program Files/Qemu" + EXESUF=".exe" + gdbstub="no" +fi + if test -z "$cross_prefix" ; then # --- @@ -206,6 +222,7 @@ echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" echo " --cc=CC use C compiler CC [$cc]" echo " --make=MAKE use specified make [$make]" echo " --static enable static build [$static]" +echo " --enable-mingw32 enable Win32 cross compilation with mingw32" echo "" echo "NOTE: The object files are build at the place where configure is launched" exit 1 @@ -227,6 +244,8 @@ echo "target list $target_list" echo "gprof enabled $gprof" echo "static build $static" echo "SDL support $sdl" +echo "mingw32 support $mingw32" + if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support" fi @@ -253,6 +272,7 @@ echo "AR=$ar" >> $config_mak echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak echo "CFLAGS=$CFLAGS" >> $config_mak echo "LDFLAGS=$LDFLAGS" >> $config_mak +echo "EXESUF=$EXESUF" >> $config_mak if test "$cpu" = "i386" ; then echo "ARCH=i386" >> $config_mak echo "#define HOST_I386 1" >> $config_h @@ -294,7 +314,15 @@ if test "$bigendian" = "yes" ; then echo "WORDS_BIGENDIAN=yes" >> $config_mak echo "#define WORDS_BIGENDIAN 1" >> $config_h fi -echo "#define HAVE_BYTESWAP_H 1" >> $config_h +if test "$mingw32" = "yes" ; then + echo "CONFIG_WIN32=yes" >> $config_mak +else + echo "#define HAVE_BYTESWAP_H 1" >> $config_h +fi +if test "$gdbstub" = "yes" ; then + echo "CONFIG_GDBSTUB=yes" >> $config_mak + echo "#define CONFIG_GDBSTUB 1" >> $config_h +fi if test "$gprof" = "yes" ; then echo "TARGET_GPROF=yes" >> $config_mak echo "#define HAVE_GPROF 1" >> $config_h diff --git a/cpu-exec.c b/cpu-exec.c index cdbebd39b..9b049dc61 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -592,6 +592,8 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) #endif /* TARGET_I386 */ +#if !defined(CONFIG_SOFTMMU) + #undef EAX #undef ECX #undef EDX @@ -925,3 +927,5 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #error host CPU specific signal handler needed #endif + +#endif /* !defined(CONFIG_SOFTMMU) */ diff --git a/dyngen.c b/dyngen.c index 7c1c0e8ae..a817d62c9 100644 --- a/dyngen.c +++ b/dyngen.c @@ -3,6 +3,9 @@ * * Copyright (c) 2003 Fabrice Bellard * + * The COFF object format support was extracted from Kazu's QEMU port + * to Win32. + * * 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 @@ -27,6 +30,14 @@ #include "config-host.h" +#if defined(_WIN32) +#define CONFIG_FORMAT_COFF +#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) */ @@ -122,6 +133,40 @@ typedef uint64_t host_ulong; #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 */ + #include "bswap.h" enum { @@ -133,18 +178,67 @@ enum { /* all dynamically generated functions begin with this code */ #define OP_PREFIX "op_" -int elf_must_swap(struct elfhdr *h) +int do_swap; + +void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...) { - union { - uint32_t i; - uint8_t b[4]; - } swaptest; + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "dyngen: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} - swaptest.i = 1; - return (h->e_ident[EI_DATA] == ELFDATA2MSB) != - (swaptest.b[0] == 0); +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); @@ -160,6 +254,66 @@ void swab64s(uint64_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 */ @@ -212,122 +366,396 @@ void elf_swap_rel(ELF_RELOC *rel) #endif } -/* ELF file info */ -int do_swap; -struct elf_shdr *shdr; -uint8_t **sdata; -struct elfhdr ehdr; -ElfW(Sym) *symtab; -int nb_syms; -char *strtab; -int text_shndx; +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; -uint16_t get16(uint16_t *p) + 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) { - uint16_t val; - val = *p; - if (do_swap) - val = bswap16(val); - return val; + 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; } -uint32_t get32(uint32_t *p) +static char *get_rel_sym_name(EXE_RELOC *rel) { - uint32_t val; - val = *p; + 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) - val = bswap32(val); - return val; + 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 = 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 = 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'; + } } -void put16(uint16_t *p, uint16_t val) +char *name_for_dotdata(struct coff_rel *rel) { - if (do_swap) - val = bswap16(val); - *p = val; + 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; } -void put32(uint32_t *p, uint32_t val) +static char *get_sym_name(EXE_SYM *sym) { - if (do_swap) - val = bswap32(val); - *p = val; + return sym->st_name; } -void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...) +static char *get_rel_sym_name(EXE_RELOC *rel) { - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "dyngen: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(1); + char *name; + name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx)); + if (!strcmp(name, ".data")) + name = name_for_dotdata(rel); + return name; } - -struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, - const char *name) +struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name) { int i; const char *shname; - struct elf_shdr *sec; + struct external_scnhdr *sec; for(i = 0; i < shnum; i++) { sec = &shdr[i]; - if (!sec->sh_name) + if (!sec->s_name) continue; - shname = shstr + sec->sh_name; + shname = sec->s_name; if (!strcmp(shname, name)) return sec; } return NULL; } -int find_reloc(int sh_index) +/* load a coff object file */ +int load_object(const char *filename) { - struct elf_shdr *sec; + 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"); - for(i = 0; i < ehdr.e_shnum; i++) { + /* 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 (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) - return i; + if (!strstart(sec->s_name, ".bss", &p)) + sdata[i] = load_data(fd, sec->s_scnptr, sec->s_size); } - return 0; -} -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; + /* 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"); } - 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++; + + 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; } - if (ptr) - *ptr = p; - return 1; + + /* 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 HOST_ARM int arm_emit_ldr_info(const char *name, unsigned long start_offset, @@ -385,7 +813,7 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, relname[0] = '\0'; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset == (pc_offset + start_offset)) { - sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + sym_name = get_rel_sym_name(rel); /* the compiler leave some unnecessary references to the code */ if (strstart(sym_name, "__op_param", &p)) { snprintf(relname, sizeof(relname), "param%s", p); @@ -432,8 +860,7 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, /* generate op code */ void gen_code(const char *name, host_ulong offset, host_ulong size, - FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, - int gen_switch) + FILE *outfile, int gen_switch) { int copy_size = 0; uint8_t *p_start, *p_end; @@ -441,7 +868,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, int nb_args, i, n; uint8_t args_present[MAX_ARGS]; const char *sym_name, *p; - ELF_RELOC *rel; + EXE_RELOC *rel; /* Compute exact size excluding prologue and epilogue instructions. * Increment start_offset to skip epilogue instructions, then compute @@ -451,136 +878,141 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, p_start = text + offset; p_end = p_start + size; start_offset = offset; - switch(ELF_ARCH) { - case EM_386: - case EM_X86_64: - { - int len; - len = p_end - p_start; - if (len == 0) - error("empty code for %s", name); - if (p_end[-1] == 0xc3) { - len--; - } else { +#if defined(HOST_I386) || defined(HOST_AMD64) +#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 = len; } - break; - case EM_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; + 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); } - break; - case EM_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; - } - break; - case EM_ALPHA: - { - uint8_t *p; - p = p_end - 4; + 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); + /* 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; - } - break; - case EM_IA_64: - { - uint8_t *p; - p = (void *)(p_end - 4); - if (p == p_start) - error("empty code for %s", name); - /* br.ret.sptk.many b0;; */ - /* 08 00 84 00 */ - if (get32((uint32_t *)p) != 0x00840008) - error("br.ret.sptk.many b0;; expected at the end of %s", name); - copy_size = p - p_start; - } - break; - case EM_SPARC: - case EM_SPARC32PLUS: - { - uint32_t start_insn, end_insn1, end_insn2; - uint8_t *p; - p = (void *)(p_end - 8); - if (p <= p_start) - error("empty code for %s", name); - start_insn = get32((uint32_t *)(p_start + 0x0)); - end_insn1 = get32((uint32_t *)(p + 0x0)); - end_insn2 = get32((uint32_t *)(p + 0x4)); - if ((start_insn & ~0x1fff) == 0x9de3a000) { - p_start += 0x4; - start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -128) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) - error("ret; restore; not found at end of %s", name); - } else { - error("No save at the beginning of %s", name); - } + 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 - p_start; + } +#elif defined(HOST_SPARC) + { + 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) == 0x9de3a000) { + p_start += 0x4; + start_offset += 0x4; + if ((int)(start_insn | ~0x1fff) < -128) + error("Found bogus save at the start of %s", name); + if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + error("ret; restore; not found at end of %s", name); + } else { + error("No save at the beginning of %s", name); + } #if 0 - /* Skip a preceeding nop, if present. */ - if (p > p_start) { - skip_insn = get32((uint32_t *)(p - 0x4)); - if (skip_insn == 0x01000000) - p -= 4; - } + /* Skip a preceeding nop, if present. */ + if (p > p_start) { + skip_insn = get32((uint32_t *)(p - 0x4)); + if (skip_insn == 0x01000000) + p -= 4; + } #endif - copy_size = p - p_start; - } - break; - case EM_SPARCV9: - { - uint32_t start_insn, end_insn1, end_insn2, skip_insn; - uint8_t *p; - p = (void *)(p_end - 8); - if (p <= p_start) - error("empty code for %s", name); - start_insn = get32((uint32_t *)(p_start + 0x0)); - end_insn1 = get32((uint32_t *)(p + 0x0)); - end_insn2 = get32((uint32_t *)(p + 0x4)); - if ((start_insn & ~0x1fff) == 0x9de3a000) { - p_start += 0x4; - start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -256) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) - error("ret; restore; not found at end of %s", name); - } else { - error("No save at the beginning of %s", name); - } - - /* Skip a preceeding nop, if present. */ - if (p > p_start) { - skip_insn = get32((uint32_t *)(p - 0x4)); - if (skip_insn == 0x01000000) - p -= 4; - } - - copy_size = p - p_start; - } - break; -#ifdef HOST_ARM - case EM_ARM: + copy_size = p - p_start; + } +#elif defined(HOST_SPARC64) + { + uint32_t start_insn, end_insn1, end_insn2, skip_insn; + uint8_t *p; + p = (void *)(p_end - 8); + if (p <= p_start) + error("empty code for %s", name); + start_insn = get32((uint32_t *)(p_start + 0x0)); + end_insn1 = get32((uint32_t *)(p + 0x0)); + end_insn2 = get32((uint32_t *)(p + 0x4)); + if ((start_insn & ~0x1fff) == 0x9de3a000) { + p_start += 0x4; + start_offset += 0x4; + if ((int)(start_insn | ~0x1fff) < -256) + error("Found bogus save at the start of %s", name); + if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + error("ret; restore; not found at end of %s", name); + } else { + error("No save at the beginning of %s", name); + } + + /* Skip a preceeding nop, if present. */ + if (p > p_start) { + skip_insn = get32((uint32_t *)(p - 0x4)); + if (skip_insn == 0x01000000) + p -= 4; + } + + copy_size = p - p_start; + } +#elif defined(HOST_ARM) + { if ((p_end - p_start) <= 16) error("%s: function too small", name); if (get32((uint32_t *)p_start) != 0xe1a0c00d || @@ -591,26 +1023,24 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, start_offset += 12; copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, relocs, nb_relocs); - break; -#endif - case EM_68K: - { - 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; - } - break; - default: - error("unknown ELF architecture"); } +#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++) @@ -619,7 +1049,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && rel->r_offset < start_offset + (p_end - p_start)) { - sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + sym_name = get_rel_sym_name(rel); if (strstart(sym_name, "__op_param", &p)) { n = strtoul(p, NULL, 10); if (n > MAX_ARGS) @@ -657,7 +1087,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && rel->r_offset < start_offset + (p_end - p_start)) { - sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; + sym_name = get_rel_sym_name(rel); if (*sym_name && !strstart(sym_name, "__op_param", NULL) && !strstart(sym_name, "__op_jmp", NULL)) { @@ -678,20 +1108,30 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* emit code offset information */ { - ElfW(Sym) *sym; + 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 = strtab + sym->st_name; + 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; + } +#else ptr = sdata[sym->st_shndx]; +#endif if (!ptr) error("__op_labelN in invalid section"); offset = sym->st_value; @@ -739,7 +1179,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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; + sym_name = get_rel_sym_name(rel); if (strstart(sym_name, "__op_jmp", &p)) { int n; n = strtol(p, NULL, 10); @@ -757,8 +1197,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } else { snprintf(name, sizeof(name), "(long)(&%s)", sym_name); } - type = ELF32_R_TYPE(rel->r_info); 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", @@ -771,6 +1212,23 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, default: error("unsupported i386 relocation (%d)", type); } +#elif defined(CONFIG_FORMAT_COFF) + type = rel->r_type; + switch(type) { + case DIR32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + rel->r_offset - start_offset, name, addend); + break; + case DISP32: + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", + rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + break; + default: + error("unsupported i386 relocation (%d)", type); + } +#else +#error unsupport object format +#endif } } } @@ -1204,114 +1662,10 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } -/* load an elf object file */ -int load_elf(const char *filename, FILE *outfile, int out_type) +int gen_file(FILE *outfile, int out_type) { - int fd; - struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec; - int i, j; - ElfW(Sym) *sym; - char *shstr; - uint8_t *text; - ELF_RELOC *relocs; - int nb_relocs; - 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 = 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 = 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); - } - } + int i; + EXE_SYM *sym; if (out_type == OUT_INDEX_OP) { fprintf(outfile, "DEF(end, 0, 0)\n"); @@ -1321,10 +1675,9 @@ int load_elf(const char *filename, FILE *outfile, int out_type) fprintf(outfile, "DEF(nop3, 3, 0)\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name, *p; - name = strtab + sym->st_name; + name = get_sym_name(sym); if (strstart(name, OP_PREFIX, &p)) { - gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, 2); + gen_code(name, sym->st_value, sym->st_size, outfile, 2); } } } else if (out_type == OUT_GEN_OP) { @@ -1332,12 +1685,11 @@ int load_elf(const char *filename, FILE *outfile, int out_type) for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name; - name = strtab + sym->st_name; + name = get_sym_name(sym); if (strstart(name, OP_PREFIX, NULL)) { - if (sym->st_shndx != (text_sec - shdr)) + if (sym->st_shndx != text_shndx) error("invalid section for opcode (0x%x)", sym->st_shndx); - gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, 0); + gen_code(name, sym->st_value, sym->st_size, outfile, 0); } } @@ -1374,16 +1726,15 @@ fprintf(outfile, for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name; - name = strtab + sym->st_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 (sym->st_shndx != (text_sec - shdr)) + if (sym->st_shndx != text_shndx) error("invalid section for opcode (0x%x)", sym->st_shndx); - gen_code(name, sym->st_value, sym->st_size, outfile, - text, relocs, nb_relocs, 1); + gen_code(name, sym->st_value, sym->st_size, outfile, 1); } } @@ -1432,7 +1783,6 @@ fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ } - close(fd); return 0; } @@ -1480,7 +1830,9 @@ int main(int argc, char **argv) outfile = fopen(outfilename, "w"); if (!outfile) error("could not open '%s'", outfilename); - load_elf(filename, outfile, out_type); + + load_object(filename); + gen_file(outfile, out_type); fclose(outfile); return 0; } diff --git a/exec-all.h b/exec-all.h index 9ecf2dca7..bc16be11a 100644 --- a/exec-all.h +++ b/exec-all.h @@ -141,7 +141,7 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, #if defined(__powerpc__) #define USE_DIRECT_JUMP #endif -#if defined(__i386__) +#if defined(__i386__) && !defined(_WIN32) #define USE_DIRECT_JUMP #endif @@ -322,13 +322,19 @@ do {\ #elif defined(__i386__) && defined(USE_DIRECT_JUMP) +#ifdef _WIN32 +#define ASM_PREVIOUS_SECTION ".section .text\n" +#else +#define ASM_PREVIOUS_SECTION ".previous\n" +#endif + /* we patch the jump instruction directly */ #define JUMP_TB(opname, tbparam, n, eip)\ do {\ - asm volatile (".section \".data\"\n"\ + asm volatile (".section .data\n"\ "__op_label" #n "." stringify(opname) ":\n"\ ".long 1f\n"\ - ".previous\n"\ + ASM_PREVIOUS_SECTION \ "jmp __op_jmp" #n "\n"\ "1:\n");\ T0 = (long)(tbparam) + (n);\ diff --git a/exec.c b/exec.c index 5d90476aa..49cadcacd 100644 --- a/exec.c +++ b/exec.c @@ -17,6 +17,7 @@ * 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 #include #include @@ -24,9 +25,10 @@ #include #include #include +#if !defined(CONFIG_SOFTMMU) #include +#endif -#include "config.h" #include "cpu.h" #include "exec-all.h" @@ -121,7 +123,11 @@ static void page_init(void) { /* NOTE: we can always suppose that host_page_size >= TARGET_PAGE_SIZE */ +#ifdef _WIN32 + real_host_page_size = 4096; +#else real_host_page_size = getpagesize(); +#endif if (host_page_size == 0) host_page_size = real_host_page_size; if (host_page_size < TARGET_PAGE_SIZE) @@ -1369,14 +1375,14 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, index = (vaddr >> 12) & (CPU_TLB_SIZE - 1); addend -= vaddr; - if (prot & PROT_READ) { + if (prot & PAGE_READ) { env->tlb_read[is_user][index].address = address; env->tlb_read[is_user][index].addend = addend; } else { env->tlb_read[is_user][index].address = -1; env->tlb_read[is_user][index].addend = -1; } - if (prot & PROT_WRITE) { + if (prot & PAGE_WRITE) { if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { /* ROM: access is ignored (same as unassigned) */ env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM; diff --git a/gdbstub.c b/gdbstub.c index 0cf839555..07652d1ae 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -17,18 +17,12 @@ * 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 -#include -#include -#include -#include +#include "vl.h" + #include #include #include #include -#include - -#include "vl.h" //#define DEBUG_GDB diff --git a/hw/dma.c b/hw/dma.c index 3d010f316..6c1bc6160 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -21,11 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include - -#include "cpu.h" #include "vl.h" #define log(...) fprintf (stderr, "dma: " __VA_ARGS__) diff --git a/hw/fdc.c b/hw/fdc.c index 97ac51c40..7d7837b99 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -21,11 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include - #include "vl.h" /********************************************************/ diff --git a/hw/i8254.c b/hw/i8254.c index cedaede1a..20cca0ef8 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -21,26 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" //#define DEBUG_PIT diff --git a/hw/i8259.c b/hw/i8259.c index 55488c681..8fabaf765 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -21,26 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" /* debug PIC */ diff --git a/hw/ide.c b/hw/ide.c index 430e5afd5..9ee446915 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -21,31 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NO_THUNK_TYPE_SIZE -#include "thunk.h" - -#include "cpu.h" -#include "exec-all.h" - #include "vl.h" /* debug IDE devices */ @@ -375,6 +350,15 @@ static void padstr8(uint8_t *buf, int buf_size, const char *src) } } +static void put_le16(uint16_t *p, unsigned int v) +{ +#ifdef WORDS_BIGENDIAN + *p = bswap16(v); +#else + *p = v; +#endif +} + static void ide_identify(IDEState *s) { uint16_t *p; @@ -382,43 +366,43 @@ static void ide_identify(IDEState *s) memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; - stw_raw(p + 0, 0x0040); - stw_raw(p + 1, s->cylinders); - stw_raw(p + 3, s->heads); - stw_raw(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ - stw_raw(p + 5, 512); /* XXX: retired, remove ? */ - stw_raw(p + 6, s->sectors); + put_le16(p + 0, 0x0040); + put_le16(p + 1, s->cylinders); + put_le16(p + 3, s->heads); + put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ + put_le16(p + 5, 512); /* XXX: retired, remove ? */ + put_le16(p + 6, s->sectors); padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ - stw_raw(p + 20, 3); /* XXX: retired, remove ? */ - stw_raw(p + 21, 512); /* cache size in sectors */ - stw_raw(p + 22, 4); /* ecc bytes */ + put_le16(p + 20, 3); /* XXX: retired, remove ? */ + put_le16(p + 21, 512); /* cache size in sectors */ + put_le16(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ #if MAX_MULT_SECTORS > 1 - stw_raw(p + 47, 0x8000 | MAX_MULT_SECTORS); + put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); #endif - stw_raw(p + 48, 1); /* dword I/O */ - stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ - stw_raw(p + 51, 0x200); /* PIO transfer cycle */ - stw_raw(p + 52, 0x200); /* DMA transfer cycle */ - stw_raw(p + 53, 1); /* words 54-58 are valid */ - stw_raw(p + 54, s->cylinders); - stw_raw(p + 55, s->heads); - stw_raw(p + 56, s->sectors); + put_le16(p + 48, 1); /* dword I/O */ + put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */ + put_le16(p + 51, 0x200); /* PIO transfer cycle */ + put_le16(p + 52, 0x200); /* DMA transfer cycle */ + put_le16(p + 53, 1); /* words 54-58 are valid */ + put_le16(p + 54, s->cylinders); + put_le16(p + 55, s->heads); + put_le16(p + 56, s->sectors); oldsize = s->cylinders * s->heads * s->sectors; - stw_raw(p + 57, oldsize); - stw_raw(p + 58, oldsize >> 16); + put_le16(p + 57, oldsize); + put_le16(p + 58, oldsize >> 16); if (s->mult_sectors) - stw_raw(p + 59, 0x100 | s->mult_sectors); - stw_raw(p + 60, s->nb_sectors); - stw_raw(p + 61, s->nb_sectors >> 16); - stw_raw(p + 80, (1 << 1) | (1 << 2)); - stw_raw(p + 82, (1 << 14)); - stw_raw(p + 83, (1 << 14)); - stw_raw(p + 84, (1 << 14)); - stw_raw(p + 85, (1 << 14)); - stw_raw(p + 86, 0); - stw_raw(p + 87, (1 << 14)); + put_le16(p + 59, 0x100 | s->mult_sectors); + put_le16(p + 60, s->nb_sectors); + put_le16(p + 61, s->nb_sectors >> 16); + put_le16(p + 80, (1 << 1) | (1 << 2)); + put_le16(p + 82, (1 << 14)); + put_le16(p + 83, (1 << 14)); + put_le16(p + 84, (1 << 14)); + put_le16(p + 85, (1 << 14)); + put_le16(p + 86, 0); + put_le16(p + 87, (1 << 14)); } static void ide_atapi_identify(IDEState *s) @@ -428,32 +412,32 @@ static void ide_atapi_identify(IDEState *s) memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; /* Removable CDROM, 50us response, 12 byte packets */ - stw_raw(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); - stw_raw(p + 1, s->cylinders); - stw_raw(p + 3, s->heads); - stw_raw(p + 4, 512 * s->sectors); /* sectors */ - stw_raw(p + 5, 512); /* sector size */ - stw_raw(p + 6, s->sectors); + put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); + put_le16(p + 1, s->cylinders); + put_le16(p + 3, s->heads); + put_le16(p + 4, 512 * s->sectors); /* sectors */ + put_le16(p + 5, 512); /* sector size */ + put_le16(p + 6, s->sectors); padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ - stw_raw(p + 20, 3); /* buffer type */ - stw_raw(p + 21, 512); /* cache size in sectors */ - stw_raw(p + 22, 4); /* ecc bytes */ + put_le16(p + 20, 3); /* buffer type */ + put_le16(p + 21, 512); /* cache size in sectors */ + put_le16(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ - stw_raw(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ - stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */ - stw_raw(p + 53, 3); /* words 64-70, 54-58 valid */ - stw_raw(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ - stw_raw(p + 64, 1); /* PIO modes */ - stw_raw(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ - stw_raw(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ - stw_raw(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ - stw_raw(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ + put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ + put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */ + put_le16(p + 53, 3); /* words 64-70, 54-58 valid */ + put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ + put_le16(p + 64, 1); /* PIO modes */ + put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ + put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ + put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ + put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ - stw_raw(p + 71, 30); /* in ns */ - stw_raw(p + 72, 30); /* in ns */ + put_le16(p + 71, 30); /* in ns */ + put_le16(p + 72, 30); /* in ns */ - stw_raw(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ + put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ } static void ide_set_signature(IDEState *s) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 4505fc958..d5746835a 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -21,26 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" //#define DEBUG_CMOS diff --git a/hw/ne2000.c b/hw/ne2000.c index bf76829ed..63edf0352 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -21,26 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" /* debug NE2000 card */ diff --git a/hw/pc.c b/hw/pc.c index 03c34a285..5431a41ac 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -21,26 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" /* output Bochs bios info messages */ @@ -393,9 +373,13 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, bs_table[2 * i], bs_table[2 * i + 1]); } kbd_init(); - AUD_init(); DMA_init(); + +#ifndef _WIN32 + /* no audio supported yet for win32 */ + AUD_init(); SB16_init(); +#endif floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); diff --git a/hw/pckbd.c b/hw/pckbd.c index 21524c8f4..f9f633331 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -21,26 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" /* debug PC keyboard */ diff --git a/hw/sb16.c b/hw/sb16.c index 147d5c822..b2d20ded8 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -21,11 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include - -#include "cpu.h" #include "vl.h" #define MIN(a, b) ((a)>(b)?(b):(a)) diff --git a/hw/serial.c b/hw/serial.c index e9bfd2a00..c40965956 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -21,26 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" //#define DEBUG_SERIAL diff --git a/hw/vga.c b/hw/vga.c index ba936e305..ce1754f75 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -21,28 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" -#include "exec-all.h" - #include "vl.h" //#define DEBUG_VGA diff --git a/monitor.c b/monitor.c index 8c016a8ac..1aabd3ddd 100644 --- a/monitor.c +++ b/monitor.c @@ -21,25 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" //#define DEBUG @@ -311,6 +292,7 @@ static void do_cont(int argc, const char **argv) vm_start(); } +#ifdef CONFIG_GDBSTUB static void do_gdbserver(int argc, const char **argv) { int port; @@ -324,6 +306,7 @@ static void do_gdbserver(int argc, const char **argv) qemu_printf("Waiting gdb connection on port %d\n", port); } } +#endif static term_cmd_t term_cmds[] = { { "help|?", do_help, @@ -348,7 +331,9 @@ static term_cmd_t term_cmds[] = { "filename", "restore the whole virtual machine state from 'filename'" }, { "stop", do_stop, "", "stop emulation", }, { "c|cont", do_cont, "", "resume emulation", }, +#ifdef CONFIG_GDBSTUB { "gdbserver", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, +#endif { NULL, NULL, }, }; diff --git a/osdep.c b/osdep.c index f843e562f..aa061a90a 100644 --- a/osdep.c +++ b/osdep.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include #include @@ -34,6 +32,9 @@ #if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) +#include +#include + /* When not using soft mmu, libc independant functions are needed for the CPU core because it needs to use alternates stacks and libc/thread incompatibles settings */ diff --git a/oss.c b/oss.c index 1922985c1..81de93b5f 100644 --- a/oss.c +++ b/oss.c @@ -21,6 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "vl.h" + +#ifndef _WIN32 #include #include #include @@ -33,7 +36,6 @@ #include #include -#include "vl.h" /* http://www.df.lth.se/~john_e/gems/gem002d.html */ /* http://www.multi-platforms.com/Tips/PopCount.htm */ @@ -510,3 +512,43 @@ void AUD_init (void) conf_fragsize = lsbindex (fsp); } + +#else + +void AUD_run (void) +{ +} + +int AUD_write (void *in_buf, int size) +{ + return 0; +} + +void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) +{ +} + +void AUD_adjust_estimate (int _leftover) +{ +} + +int AUD_get_free (void) +{ + return 0; +} + +int AUD_get_live (void) +{ + return 0; +} + +int AUD_get_buffer_size (void) +{ + return 0; +} + +void AUD_init (void) +{ +} + +#endif diff --git a/qemu-mkcow.c b/qemu-mkcow.c index 7968bf972..d8678a29d 100644 --- a/qemu-mkcow.c +++ b/qemu-mkcow.c @@ -28,16 +28,11 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include #include -#include #include #include diff --git a/sdl.c b/sdl.c index f705eb7fa..f2dcfbc78 100644 --- a/sdl.c +++ b/sdl.c @@ -21,31 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "vl.h" #include -#include "cpu.h" -#include "exec-all.h" - -#include "vl.h" +#ifndef _WIN32 +#include +#endif static SDL_Surface *screen; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ @@ -291,9 +273,12 @@ void sdl_display_init(DisplayState *ds) fprintf(stderr, "Could not initialize SDL - exiting\n"); exit(1); } + +#ifndef _WIN32 /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); +#endif ds->dpy_update = sdl_update; ds->dpy_resize = sdl_resize; diff --git a/target-i386/helper2.c b/target-i386/helper2.c index c9c9d7e36..22e812e09 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "cpu.h" #include "exec-all.h" @@ -334,7 +333,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr; virt_addr = addr & TARGET_PAGE_MASK; - prot = PROT_READ | PROT_WRITE; + prot = PAGE_READ | PAGE_WRITE; page_size = 4096; goto do_mapping; } @@ -409,17 +408,17 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, } /* the page can be put in the TLB */ - prot = PROT_READ; + prot = PAGE_READ; if (pte & PG_DIRTY_MASK) { /* only set write access if already dirty... otherwise wait for dirty access */ if (is_user) { if (ptep & PG_RW_MASK) - prot |= PROT_WRITE; + prot |= PAGE_WRITE; } else { if (!(env->cr[0] & CR0_WP_MASK) || (ptep & PG_RW_MASK)) - prot |= PROT_WRITE; + prot |= PAGE_WRITE; } } diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index fb0bcaa3c..69927915e 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -17,15 +17,14 @@ * 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 #include #include #include #include -#include #include -#include -#include #include "cpu.h" #include "exec-all.h" @@ -33,6 +32,10 @@ #ifdef USE_CODE_COPY +#include +#include +#include + extern char exec_loop; /* operand size */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 5866fe409..3ef614652 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "cpu.h" #include "exec-all.h" diff --git a/vl.c b/vl.c index 92ddb8790..ed5c38015 100644 --- a/vl.c +++ b/vl.c @@ -21,35 +21,40 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include +#include "vl.h" + #include -#include #include -#include #include #include #include -#include #include -#include -#include #include +#include + +#ifndef _WIN32 +#include #include #include -#include - +#include +#include +#include #include #include #include #include +#endif + +#ifdef _WIN32 +#include +#include +#define getopt_long_only getopt_long +#define memalign(align, size) malloc(size) +#endif + #include "disas.h" -#include "vl.h" #include "exec-all.h" #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" @@ -375,11 +380,17 @@ void cpu_disable_ticks(void) } } -int64_t get_clock(void) +static int64_t get_clock(void) { +#ifdef _WIN32 + struct _timeb tb; + _ftime(&tb); + return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000; +#else struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000000LL + tv.tv_usec; +#endif } void cpu_calibrate_ticks(void) @@ -388,7 +399,11 @@ void cpu_calibrate_ticks(void) usec = get_clock(); ticks = cpu_get_real_ticks(); +#ifdef _WIN32 + Sleep(50); +#else usleep(50 * 1000); +#endif usec = get_clock() - usec; ticks = cpu_get_real_ticks() - ticks; ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; @@ -438,8 +453,10 @@ QEMUClock *rt_clock; QEMUClock *vm_clock; static QEMUTimer *active_timers[2]; +#ifndef _WIN32 /* frequency of the times() clock tick */ static int timer_freq; +#endif QEMUClock *qemu_new_clock(int type) { @@ -550,12 +567,16 @@ int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { case QEMU_TIMER_REALTIME: +#ifdef _WIN32 + return GetTickCount(); +#else /* XXX: portability among Linux hosts */ if (timer_freq == 100) { return times(NULL) * 10; } else { return ((int64_t)times(NULL) * 1000) / timer_freq; } +#endif default: case QEMU_TIMER_VIRTUAL: return cpu_get_ticks(); @@ -608,7 +629,12 @@ static int timer_load(QEMUFile *f, void *opaque, int version_id) return 0; } +#ifdef _WIN32 +void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, + DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) +#else static void host_alarm_handler(int host_signum) +#endif { if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)) || @@ -621,39 +647,66 @@ static void host_alarm_handler(int host_signum) static void init_timers(void) { - struct sigaction act; - struct itimerval itv; - - /* get times() syscall frequency */ - timer_freq = sysconf(_SC_CLK_TCK); - rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL); - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; +#ifdef _WIN32 + { + int count=0; + MMRESULT timerID = timeSetEvent(10, // interval (ms) + 0, // resolution + host_alarm_handler, // function + (DWORD)&count, // user parameter + TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + if( !timerID ) { + perror("failed timer alarm"); + exit(1); + } + } + pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; +#else + { + struct sigaction act; + struct itimerval itv; + + /* get times() syscall frequency */ + timer_freq = sysconf(_SC_CLK_TCK); + + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = 0; #if defined (TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; + act.sa_flags |= SA_ONSTACK; +#endif + act.sa_handler = host_alarm_handler; + sigaction(SIGALRM, &act, NULL); + + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 1000; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 10 * 1000; + setitimer(ITIMER_REAL, &itv, NULL); + /* we probe the tick duration of the kernel to inform the user if + the emulated kernel requested a too high timer frequency */ + getitimer(ITIMER_REAL, &itv); + pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / + 1000000; + } #endif - act.sa_handler = host_alarm_handler; - sigaction(SIGALRM, &act, NULL); - - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 1000; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 10 * 1000; - setitimer(ITIMER_REAL, &itv, NULL); - /* we probe the tick duration of the kernel to inform the user if - the emulated kernel requested a too high timer frequency */ - getitimer(ITIMER_REAL, &itv); - pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / - 1000000; } /***********************************************************/ /* serial device */ +#ifdef _WIN32 + +int serial_open_device(void) +{ + return -1; +} + +#else + int serial_open_device(void) { char slave_name[1024]; @@ -672,9 +725,24 @@ int serial_open_device(void) } } +#endif + /***********************************************************/ /* Linux network device redirector */ +#ifdef _WIN32 + +static int net_init(void) +{ + return 0; +} + +void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ +} + +#else + static int tun_open(char *ifname, int ifname_size) { struct ifreq ifr; @@ -753,9 +821,23 @@ void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size) write(nd->fd, buf, size); } +#endif + /***********************************************************/ /* dumb display */ +#ifdef _WIN32 + +static void term_exit(void) +{ +} + +static void term_init(void) +{ +} + +#else + /* init terminal so that we can grab keys */ static struct termios oldtty; @@ -790,6 +872,8 @@ static void term_init(void) fcntl(0, F_SETFL, O_NONBLOCK); } +#endif + static void dumb_update(DisplayState *ds, int x, int y, int w, int h) { } @@ -1396,10 +1480,13 @@ void vm_stop(int reason) int main_loop(void) { +#ifndef _WIN32 struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf; - int ret, n, timeout, max_size; - uint8_t buf[4096]; IOHandlerRecord *ioh, *ioh_next; + uint8_t buf[4096]; + int n, max_size; +#endif + int ret, timeout; CPUState *env = global_env; for(;;) { @@ -1422,6 +1509,7 @@ int main_loop(void) timeout = 10; } +#ifndef _WIN32 /* poll any events */ /* XXX: separate device handlers from system ones */ pf = ufds; @@ -1471,6 +1559,7 @@ int main_loop(void) } } } +#endif if (vm_running) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], @@ -1592,7 +1681,10 @@ static uint8_t *signal_stack; int main(int argc, char **argv) { - int c, i, use_gdbstub, gdbstub_port, long_index, has_cdrom; +#ifdef CONFIG_GDBSTUB + int use_gdbstub, gdbstub_port; +#endif + int c, i, long_index, has_cdrom; int snapshot, linux_boot; CPUState *env; const char *initrd_filename; @@ -1601,8 +1693,10 @@ int main(int argc, char **argv) DisplayState *ds = &display_state; int cyls, heads, secs; +#if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); +#endif initrd_filename = NULL; for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; @@ -1611,8 +1705,10 @@ int main(int argc, char **argv) ram_size = 32 * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); +#ifdef CONFIG_GDBSTUB use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; +#endif snapshot = 0; nographic = 0; kernel_filename = NULL; @@ -1773,12 +1869,14 @@ int main(int argc, char **argv) case 'n': pstrcpy(network_script, sizeof(network_script), optarg); break; +#ifdef CONFIG_GDBSTUB case 's': use_gdbstub = 1; break; case 'p': gdbstub_port = atoi(optarg); break; +#endif case 'L': bios_dir = optarg; break; @@ -1976,6 +2074,7 @@ int main(int argc, char **argv) } #endif +#ifndef _WIN32 { struct sigaction act; sigfillset(&act.sa_mask); @@ -1983,10 +2082,12 @@ int main(int argc, char **argv) act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); } +#endif gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); +#ifdef CONFIG_GDBSTUB if (use_gdbstub) { if (gdbserver_start(gdbstub_port) < 0) { fprintf(stderr, "Could not open gdbserver socket on port %d\n", @@ -1995,7 +2096,9 @@ int main(int argc, char **argv) } else { printf("Waiting gdb connection on port %d\n", gdbstub_port); } - } else { + } else +#endif + { vm_start(); } term_init(); diff --git a/vl.h b/vl.h index 2805853a7..afec99f88 100644 --- a/vl.h +++ b/vl.h @@ -24,10 +24,79 @@ #ifndef VL_H #define VL_H +/* we put basic includes here to avoid repeating them in device drivers */ +#include +#include +#include +#include +#include #include +#include +#include +#include +#include + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + +#ifdef _WIN32 +#define lseek64 lseek +#endif #include "cpu.h" +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#if defined(WORDS_BIGENDIAN) +static inline uint32_t be32_to_cpu(uint32_t v) +{ + return v; +} + +static inline uint16_t be16_to_cpu(uint16_t v) +{ + return v; +} + +static inline uint32_t le32_to_cpu(uint32_t v) +{ + return bswap32(v); +} + +static inline uint16_t le16_to_cpu(uint16_t v) +{ + return bswap16(v); +} + +#else +static inline uint32_t be32_to_cpu(uint32_t v) +{ + return bswap32(v); +} + +static inline uint16_t be16_to_cpu(uint16_t v) +{ + return bswap16(v); +} + +static inline uint32_t le32_to_cpu(uint32_t v) +{ + return v; +} + +static inline uint16_t le16_to_cpu(uint16_t v) +{ + return v; +} +#endif + + /* vl.c */ extern int reset_requested; -- cgit v1.2.3 From 0c607d572860b692db95543c0d37f202c707b09a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 31 Mar 2004 23:54:52 +0000 Subject: win32 port (initial patch by kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@693 c046a42c-6fe2-441c-8c8c-71466251a162 --- a.out.h | 431 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) create mode 100644 a.out.h diff --git a/a.out.h b/a.out.h new file mode 100644 index 000000000..500e14f3f --- /dev/null +++ b/a.out.h @@ -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 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_ */ + -- cgit v1.2.3 From 11d9f695e710b406a487daf3fb83f82dea314063 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 2 Apr 2004 20:55:59 +0000 Subject: win32 cross compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@694 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 27 +++++++++++----------- Makefile.target | 7 ++++-- configure | 69 +++++++++++++++++++++++++++++++++++++-------------------- dyngen.c | 4 +++- 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index f2be1f6f8..fc9d74f9c 100644 --- a/Makefile +++ b/Makefile @@ -16,14 +16,11 @@ all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu.1 make -C $$d $@ || exit 1 ; \ done -qemu-mkcow: qemu-mkcow.o - $(HOST_CC) -o $@ $^ $(LIBS) +qemu-mkcow: qemu-mkcow.c + $(CC) $(CFLAGS) $(DEFINES) -o $@ $^ $(LIBS) -dyngen$(EXESUF): dyngen.o - $(HOST_CC) -o $@ $^ $(LIBS) - -%.o: %.c - $(HOST_CC) $(CFLAGS) $(DEFINES) -c -o $@ $< +dyngen$(EXESUF): dyngen.c + $(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^ clean: # avoid old build problems by removing potentially incorrect old files @@ -41,13 +38,17 @@ distclean: clean done install: all - mkdir -p $(prefix)/bin - install -m 755 -s $(TOOLS) $(prefix)/bin - mkdir -p $(sharedir) + mkdir -p "$(bindir)" +ifndef CONFIG_WIN32 + install -m 755 -s $(TOOLS) "$(bindir)" +endif + mkdir -p "$(sharedir)" install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ - pc-bios/linux_boot.bin $(sharedir) - mkdir -p $(mandir)/man1 - install qemu.1 qemu-mkcow.1 $(mandir)/man1 + pc-bios/linux_boot.bin "$(sharedir)" +ifndef CONFIG_WIN32 + mkdir -p "$(mandir)/man1" + install qemu.1 qemu-mkcow.1 "$(mandir)/man1" +endif for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done diff --git a/Makefile.target b/Makefile.target index 1b578d0fd..9fe3e83ed 100644 --- a/Makefile.target +++ b/Makefile.target @@ -246,9 +246,12 @@ endif ifndef CONFIG_SOFTMMU VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld endif +ifndef CONFIG_WIN32 +VL_LIBS=-lutil +endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a - $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) -lutil + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS) sdl.o: sdl.c $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< @@ -309,7 +312,7 @@ clean: install: all ifneq ($(PROGS),) - install -m 755 -s $(PROGS) $(prefix)/bin + install -m 755 -s $(PROGS) "$(bindir)" endif ifneq ($(wildcard .depend),) diff --git a/configure b/configure index 75340eae1..4f66317e4 100755 --- a/configure +++ b/configure @@ -17,7 +17,7 @@ TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}" TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S" # default parameters -prefix="/usr/local" +prefix="" interp_prefix="/usr/gnemul/qemu-%M" static="no" cross_prefix="" @@ -81,26 +81,6 @@ mingw32="yes" *) ;; esac -########################################## -# SDL probe - -cat > $TMPC << EOF -#include -#undef main /* We don't want SDL to override our main() */ -int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } -EOF - -sdl_too_old=no -sdl=no -if $cc -o $TMPE `sdl-config --cflags` $TMPC `sdl-config --libs` 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 -fi - # find source path # XXX: we assume an absolute path is given when launching configure, # except in './configure' case. @@ -157,9 +137,7 @@ ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" if test "$mingw32" = "yes" ; then - host_cc="$cc" target_list="i386-softmmu" - prefix="/c/Program Files/Qemu" EXESUF=".exe" gdbstub="no" fi @@ -202,6 +180,31 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu have_gcc3_options="yes" fi +########################################## +# SDL probe + +sdl_too_old=no + +if test -z "$sdl" ; then + +cat > $TMPC << EOF +#include +#undef main /* We don't want SDL to override our main() */ +int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } +EOF + +sdl=no +if $cc -o $TMPE `sdl-config --cflags` $TMPC `sdl-config --libs` 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 +fi + +fi + if test x"$1" = x"-h" -o x"$1" = x"--help" ; then cat << EOF @@ -228,13 +231,29 @@ echo "NOTE: The object files are build at the place where configure is launched" exit 1 fi +if test "$mingw32" = "yes" ; then +if test -z "$prefix" ; then + prefix="/c/Program Files/Qemu" +fi +mandir="$prefix" +sharedir="$prefix" +bindir="$prefix" +else +if test -z "$prefix" ; then + prefix="/usr/local" +fi mandir="$prefix/share/man" sharedir="$prefix/share/qemu" +bindir="$prefix/bin" +fi echo "Install prefix $prefix" -echo "Manual directory $mandir" echo "BIOS directory $sharedir" +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 "make $make" @@ -259,6 +278,7 @@ echo "# Automatically generated by configure - do not modify" > $config_mak echo "/* Automatically generated by configure - do not modify */" > $config_h echo "prefix=$prefix" >> $config_mak +echo "bindir=$bindir" >> $config_mak echo "mandir=$mandir" >> $config_mak echo "sharedir=$sharedir" >> $config_mak echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h @@ -316,6 +336,7 @@ if test "$bigendian" = "yes" ; then fi if test "$mingw32" = "yes" ; then echo "CONFIG_WIN32=yes" >> $config_mak + echo "#define CONFIG_WIN32 1" >> $config_h else echo "#define HAVE_BYTESWAP_H 1" >> $config_h fi diff --git a/dyngen.c b/dyngen.c index a817d62c9..b10909e78 100644 --- a/dyngen.c +++ b/dyngen.c @@ -30,7 +30,9 @@ #include "config-host.h" -#if defined(_WIN32) +/* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross + compilation */ +#if defined(CONFIG_WIN32) #define CONFIG_FORMAT_COFF #else #define CONFIG_FORMAT_ELF -- cgit v1.2.3 From e463b581ead04c1e5004e08c3bfb16e7fde88e20 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 2 Apr 2004 20:57:58 +0000 Subject: rdtsc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@695 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 2 +- vl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index e61b05dc5..d7cb6849b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1796,7 +1796,7 @@ void helper_rdtsc(void) { uint64_t val; #if defined(__i386__) || defined(__x86_64__) - asm("rdtsc" : "=A" (val)); + asm volatile ("rdtsc" : "=A" (val)); #else /* better than nothing: the time increases */ val = emu_time++; diff --git a/vl.c b/vl.c index ed5c38015..24895508d 100644 --- a/vl.c +++ b/vl.c @@ -341,7 +341,7 @@ int64_t cpu_get_real_ticks(void) int64_t cpu_get_real_ticks(void) { int64_t val; - asm("rdtsc" : "=A" (val)); + asm volatile ("rdtsc" : "=A" (val)); return val; } -- cgit v1.2.3 From 1154e441aa19ce3bf15fb0cabab2a5656321b43f Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 2 Apr 2004 20:58:56 +0000 Subject: avoid rounding problems git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@696 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8254.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/i8254.c b/hw/i8254.c index 20cca0ef8..ad61a14af 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -136,6 +136,10 @@ static int64_t pit_get_next_transition_time(PITChannelState *s, } /* convert to timer units */ next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ); + /* fix potential rounding problems */ + /* XXX: better solution: use a clock at PIT_FREQ Hz */ + if (next_time <= current_time) + next_time = current_time + 1; return next_time; } -- cgit v1.2.3 From 702c651c4ae90ac399264c07aded66df2c0efacf Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 2 Apr 2004 21:21:32 +0000 Subject: added -macaddr option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@697 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 53 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/vl.c b/vl.c index 24895508d..cefe0e9ab 100644 --- a/vl.c +++ b/vl.c @@ -1600,6 +1600,7 @@ void help(void) "Network options:\n" "-n script set network init script [default=%s]\n" "-nics n simulate 'n' network interfaces [default=1]\n" + "-macaddr addr set the mac address of the first interface\n" "-tun-fd fd0[,...] use these fds as already opened tap/tun interfaces\n" "\n" "Linux boot specific:\n" @@ -1655,6 +1656,7 @@ struct option long_options[] = { { "fdb", 1, NULL, 0, }, { "no-code-copy", 0, NULL, 0 }, { "nics", 1, NULL, 0 }, + { "macaddr", 1, NULL, 0 }, { NULL, 0, NULL, 0 }, }; @@ -1692,6 +1694,7 @@ int main(int argc, char **argv) const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs; + uint8_t macaddr[6]; #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ @@ -1717,17 +1720,13 @@ int main(int argc, char **argv) cyls = heads = secs = 0; nb_nics = 1; - for(i = 0; i < MAX_NICS; i++) { - NetDriverState *nd = &nd_table[i]; - nd->fd = -1; - /* init virtual mac address */ - nd->macaddr[0] = 0x52; - nd->macaddr[1] = 0x54; - nd->macaddr[2] = 0x00; - nd->macaddr[3] = 0x12; - nd->macaddr[4] = 0x34; - nd->macaddr[5] = 0x56 + i; - } + /* default mac address of the first network interface */ + macaddr[0] = 0x52; + macaddr[1] = 0x54; + macaddr[2] = 0x00; + macaddr[3] = 0x12; + macaddr[4] = 0x34; + macaddr[5] = 0x56; for(;;) { c = getopt_long_only(argc, argv, "hm:d:n:sp:L:", long_options, &long_index); @@ -1835,6 +1834,27 @@ int main(int argc, char **argv) exit(1); } break; + case 17: + { + const char *p; + int i; + p = optarg; + for(i = 0; i < 6; i++) { + macaddr[i] = strtol(p, (char **)&p, 16); + if (i == 5) { + if (*p != '\0') + goto macaddr_error; + } else { + if (*p != ':') { + macaddr_error: + fprintf(stderr, "qemu: invalid syntax for ethernet address\n"); + exit(1); + } + p++; + } + } + } + break; } break; case 'h': @@ -1912,6 +1932,17 @@ int main(int argc, char **argv) #endif /* init host network redirectors */ + for(i = 0; i < MAX_NICS; i++) { + NetDriverState *nd = &nd_table[i]; + nd->fd = -1; + /* init virtual mac address */ + nd->macaddr[0] = macaddr[0]; + nd->macaddr[1] = macaddr[1]; + nd->macaddr[2] = macaddr[2]; + nd->macaddr[3] = macaddr[3]; + nd->macaddr[4] = macaddr[4]; + nd->macaddr[5] = macaddr[5] + i; + } net_init(); /* init the memory */ -- cgit v1.2.3 From a6e022ad139c695e60d1bcb6c298a67aaf5c2916 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 2 Apr 2004 21:55:47 +0000 Subject: fixed SDL probing for cross compilation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@698 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 4f66317e4..a82cf2b4d 100755 --- a/configure +++ b/configure @@ -187,15 +187,23 @@ sdl_too_old=no if test -z "$sdl" ; then +sdl_config="sdl-config" +sdl=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 #undef main /* We don't want SDL to override our main() */ int main( void ) { return SDL_Init (SDL_INIT_VIDEO); } EOF -sdl=no -if $cc -o $TMPE `sdl-config --cflags` $TMPC `sdl-config --libs` 2> /dev/null ; then -_sdlversion=`sdl-config --version | sed 's/[^0-9]//g'` +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 @@ -203,7 +211,8 @@ sdl=yes fi fi -fi +fi # cross compilation +fi # -z $sdl if test x"$1" = x"-h" -o x"$1" = x"--help" ; then cat << EOF @@ -355,15 +364,15 @@ fi if test "$sdl" = "yes" ; then echo "CONFIG_SDL=yes" >> $config_mak echo "#define CONFIG_SDL 1" >> $config_h - echo "SDL_LIBS=`sdl-config --libs`" >> $config_mak + echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak aa="no" - `sdl-config --static-libs | grep \\\-laa > /dev/null` && aa="yes" - echo -n "SDL_STATIC_LIBS=`sdl-config --static-libs`" >> $config_mak + `$sdl_config --static-libs | grep \\\-laa > /dev/null` && aa="yes" + echo -n "SDL_STATIC_LIBS=`$sdl_config --static-libs`" >> $config_mak if [ "${aa}" = "yes" ] ; then echo -n " `aalib-config --libs`" >> $config_mak ; fi echo "" >> $config_mak - echo -n "SDL_CFLAGS=`sdl-config --cflags`" >> $config_mak + echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak if [ "${aa}" = "yes" ] ; then echo -n " `aalib-config --cflags`" >> $config_mak ; fi -- cgit v1.2.3 From 4721c4575004f9436e3c167f4daa66e2a2d6a3ff Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 3 Apr 2004 12:27:31 +0000 Subject: UIP update fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@699 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mc146818rtc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index d5746835a..69addba0c 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -206,6 +206,7 @@ static void rtc_set_time(RTCState *s) static void rtc_update_second(void *opaque) { RTCState *s = opaque; + int64_t delay; /* if the oscillator is not in normal operation, we do not update */ if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) { @@ -218,8 +219,13 @@ static void rtc_update_second(void *opaque) /* update in progress bit */ s->cmos_data[RTC_REG_A] |= REG_A_UIP; } + /* should be 244 us = 8 / 32768 seconds, but currently the + timers do not have the necessary resolution. */ + delay = (ticks_per_sec * 1) / 100; + if (delay < 1) + delay = 1; qemu_mod_timer(s->second_timer2, - s->next_second_time + (ticks_per_sec * 99) / 100); + s->next_second_time + delay); } } -- cgit v1.2.3 From 0f2f1121569d37b3b332032a9604219b644c9e30 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Apr 2004 09:37:47 +0000 Subject: tun-fd fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@700 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index cefe0e9ab..72238efcd 100644 --- a/vl.c +++ b/vl.c @@ -1728,6 +1728,9 @@ int main(int argc, char **argv) macaddr[4] = 0x34; macaddr[5] = 0x56; + for(i = 0; i < MAX_NICS; i++) + nd_table[i].fd = -1; + for(;;) { c = getopt_long_only(argc, argv, "hm:d:n:sp:L:", long_options, &long_index); if (c == -1) @@ -1934,7 +1937,6 @@ int main(int argc, char **argv) /* init host network redirectors */ for(i = 0; i < MAX_NICS; i++) { NetDriverState *nd = &nd_table[i]; - nd->fd = -1; /* init virtual mac address */ nd->macaddr[0] = macaddr[0]; nd->macaddr[1] = macaddr[1]; -- cgit v1.2.3 From 6eaee4614437e3a99af817485963487efd84e771 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Apr 2004 12:55:00 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@701 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2411653a5..c52db9804 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.2 \ No newline at end of file +0.5.3 \ No newline at end of file -- cgit v1.2.3 From 40c3bac35a868c275e083cad9ff39d3119847707 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Apr 2004 12:56:28 +0000 Subject: win32 port (Kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@702 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 13 +++++++++++++ vl.c | 24 +++++++++++++++++------- vl.h | 5 ++++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/dyngen.c b/dyngen.c index b10909e78..ff441caec 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1215,6 +1215,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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: diff --git a/vl.c b/vl.c index 72238efcd..3af8a0ee7 100644 --- a/vl.c +++ b/vl.c @@ -238,7 +238,7 @@ char *pstrcat(char *buf, int buf_size, const char *s) int load_image(const char *filename, uint8_t *addr) { int fd, size; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; size = lseek(fd, 0, SEEK_END); @@ -453,7 +453,9 @@ QEMUClock *rt_clock; QEMUClock *vm_clock; static QEMUTimer *active_timers[2]; -#ifndef _WIN32 +#ifdef _WIN32 +static MMRESULT timerID; +#else /* frequency of the times() clock tick */ static int timer_freq; #endif @@ -653,11 +655,11 @@ static void init_timers(void) #ifdef _WIN32 { int count=0; - MMRESULT timerID = timeSetEvent(10, // interval (ms) - 0, // resolution - host_alarm_handler, // function - (DWORD)&count, // user parameter - TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + timerID = timeSetEvent(10, // interval (ms) + 0, // resolution + host_alarm_handler, // function + (DWORD)&count, // user parameter + TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if( !timerID ) { perror("failed timer alarm"); exit(1); @@ -695,6 +697,13 @@ static void init_timers(void) #endif } +void quit_timers(void) +{ +#ifdef _WIN32 + timeKillEvent(timerID); +#endif +} + /***********************************************************/ /* serial device */ @@ -2136,5 +2145,6 @@ int main(int argc, char **argv) } term_init(); main_loop(); + quit_timers(); return 0; } diff --git a/vl.h b/vl.h index afec99f88..65c8f08ae 100644 --- a/vl.h +++ b/vl.h @@ -39,6 +39,9 @@ #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif #ifdef _WIN32 #define lseek64 lseek @@ -447,7 +450,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, /* monitor.c */ void monitor_init(void); -void term_printf(const char *fmt, ...); +void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); void term_flush(void); void term_print_help(void); -- cgit v1.2.3 From 9307c4c1d93939db9b04117b654253af5113dc21 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Apr 2004 12:57:25 +0000 Subject: improved monitor: type check, expression evaluator, memory dump, disassembly git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@703 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 70 ++++- disas.h | 1 + monitor.c | 893 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 843 insertions(+), 121 deletions(-) diff --git a/disas.c b/disas.c index f048348f5..e315299cc 100644 --- a/disas.c +++ b/disas.c @@ -1,12 +1,12 @@ /* General "disassemble this chunk" code. Used for debugging. */ #include "config.h" #include "dis-asm.h" -#include "disas.h" #include "elf.h" #include #include "cpu.h" #include "exec-all.h" +#include "disas.h" /* Filled in by elfload.c. Simplistic, but will do for now. */ unsigned int disas_num_syms; @@ -219,3 +219,71 @@ const char *lookup_symbol(void *orig_addr) } return ""; } + +#if !defined(CONFIG_USER_ONLY) + +static int monitor_disas_is_physical; + +static int +monitor_read_memory (memaddr, myaddr, length, info) + bfd_vma memaddr; + bfd_byte *myaddr; + int length; + struct disassemble_info *info; +{ + if (monitor_disas_is_physical) { + cpu_physical_memory_rw(memaddr, myaddr, length, 0); + } else { + cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0); + } + return 0; +} + +void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) +{ + FILE *out; + int count, i; + struct disassemble_info disasm_info; + int (*print_insn)(bfd_vma pc, disassemble_info *info); + + out = stdout; + + INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); + + monitor_disas_is_physical = is_physical; + disasm_info.read_memory_func = monitor_read_memory; + + disasm_info.buffer_vma = pc; + +#ifdef TARGET_WORDS_BIGENDIAN + disasm_info.endian = BFD_ENDIAN_BIG; +#else + disasm_info.endian = BFD_ENDIAN_LITTLE; +#endif +#if defined(TARGET_I386) + if (!flags) + disasm_info.mach = bfd_mach_i386_i386; + else + disasm_info.mach = bfd_mach_i386_i8086; + print_insn = print_insn_i386; +#elif defined(TARGET_ARM) + print_insn = print_insn_arm; +#elif defined(TARGET_SPARC) + print_insn = print_insn_sparc; +#elif defined(TARGET_PPC) + print_insn = print_insn_ppc; +#else + fprintf(out, "Asm output not supported on this arch\n"); + return; +#endif + + for(i = 0; i < nb_insn; i++) { + fprintf(out, "0x%08lx: ", (unsigned long)pc); + count = print_insn(pc, &disasm_info); + fprintf(out, "\n"); + if (count < 0) + break; + pc += count; + } +} +#endif diff --git a/disas.h b/disas.h index 916b1357a..c4a251ff8 100644 --- a/disas.h +++ b/disas.h @@ -3,6 +3,7 @@ /* Disassemble this for me please... (debugging). */ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags); +void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags); /* Look up symbol for debugging purpose. Returns "" if unknown. */ const char *lookup_symbol(void *orig_addr); diff --git a/monitor.c b/monitor.c index 1aabd3ddd..fc05746a5 100644 --- a/monitor.c +++ b/monitor.c @@ -22,11 +22,15 @@ * THE SOFTWARE. */ #include "vl.h" +#include "disas.h" //#define DEBUG +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif + #define TERM_CMD_BUF_SIZE 4095 -#define MAX_ARGS 64 #define IS_NORM 0 #define IS_ESC 1 @@ -40,9 +44,22 @@ static int term_cmd_buf_size; static int term_esc_state; static int term_esc_param; +/* + * Supported types: + * + * 'F' filename + * 's' string (accept optional quote) + * 'i' integer + * '/' optional gdb-like print format (like "/10x") + * + * '?' optional type (for 'F', 's' and 'i') + * + */ + typedef struct term_cmd_t { const char *name; - void (*handler)(int argc, const char **argv); + const char *args_type; + void (*handler)(); const char *params; const char *help; } term_cmd_t; @@ -110,12 +127,12 @@ static void help_cmd(const char *name) } } -static void do_help(int argc, const char **argv) +static void do_help(const char *name) { - help_cmd(argv[1]); + help_cmd(name); } -static void do_commit(int argc, const char **argv) +static void do_commit(void) { int i; @@ -125,26 +142,24 @@ static void do_commit(int argc, const char **argv) } } -static void do_info(int argc, const char **argv) +static void do_info(const char *item) { term_cmd_t *cmd; - const char *item; - if (argc < 2) + if (!item) goto help; - item = argv[1]; for(cmd = info_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(argv[1], cmd->name)) + if (compare_cmd(item, cmd->name)) goto found; } help: - help_cmd(argv[0]); + help_cmd("info"); return; found: - cmd->handler(argc, argv); + cmd->handler(); } -static void do_info_network(int argc, const char **argv) +static void do_info_network(void) { int i, j; NetDriverState *nd; @@ -161,12 +176,21 @@ static void do_info_network(int argc, const char **argv) } } -static void do_info_block(int argc, const char **argv) +static void do_info_block(void) { bdrv_info(); } -static void do_quit(int argc, const char **argv) +static void do_info_registers(void) +{ +#ifdef TARGET_I386 + cpu_dump_state(cpu_single_env, stdout, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + cpu_dump_state(cpu_single_env, stdout, 0); +#endif +} + +static void do_quit(void) { exit(0); } @@ -189,26 +213,13 @@ static int eject_device(BlockDriverState *bs, int force) return 0; } -static void do_eject(int argc, const char **argv) +static void do_eject(int force, const char *filename) { BlockDriverState *bs; - const char **parg; - int force; - parg = argv + 1; - if (!*parg) { - fail: - help_cmd(argv[0]); - return; - } - force = 0; - if (!strcmp(*parg, "-f")) { - force = 1; - parg++; - } - if (!*parg) - goto fail; - bs = bdrv_find(*parg); + term_printf("%d %s\n", force, filename); + + bs = bdrv_find(filename); if (!bs) { term_printf("device not found\n"); return; @@ -216,90 +227,68 @@ static void do_eject(int argc, const char **argv) eject_device(bs, force); } -static void do_change(int argc, const char **argv) +static void do_change(const char *device, const char *filename) { BlockDriverState *bs; - if (argc != 3) { - help_cmd(argv[0]); - return; - } - bs = bdrv_find(argv[1]); + bs = bdrv_find(device); if (!bs) { term_printf("device not found\n"); return; } if (eject_device(bs, 0) < 0) return; - bdrv_open(bs, argv[2], 0); + bdrv_open(bs, filename, 0); } -static void do_screen_dump(int argc, const char **argv) +static void do_screen_dump(const char *filename) { - if (argc != 2) { - help_cmd(argv[0]); - return; - } - vga_screen_dump(argv[1]); + vga_screen_dump(filename); } -static void do_log(int argc, const char **argv) +static void do_log(const char *items) { int mask; - if (argc != 2) - goto help; - if (!strcmp(argv[1], "none")) { + if (!strcmp(items, "none")) { mask = 0; } else { - mask = cpu_str_to_log_mask(argv[1]); + mask = cpu_str_to_log_mask(items); if (!mask) { - help: - help_cmd(argv[0]); + help_cmd("log"); return; } } cpu_set_log(mask); } -static void do_savevm(int argc, const char **argv) +static void do_savevm(const char *filename) { - if (argc != 2) { - help_cmd(argv[0]); - return; - } - if (qemu_savevm(argv[1]) < 0) - term_printf("I/O error when saving VM to '%s'\n", argv[1]); + if (qemu_savevm(filename) < 0) + term_printf("I/O error when saving VM to '%s'\n", filename); } -static void do_loadvm(int argc, const char **argv) +static void do_loadvm(const char *filename) { - if (argc != 2) { - help_cmd(argv[0]); - return; - } - if (qemu_loadvm(argv[1]) < 0) - term_printf("I/O error when loading VM from '%s'\n", argv[1]); + if (qemu_loadvm(filename) < 0) + term_printf("I/O error when loading VM from '%s'\n", filename); } -static void do_stop(int argc, const char **argv) +static void do_stop(void) { vm_stop(EXCP_INTERRUPT); } -static void do_cont(int argc, const char **argv) +static void do_cont(void) { vm_start(); } #ifdef CONFIG_GDBSTUB -static void do_gdbserver(int argc, const char **argv) +static void do_gdbserver(int has_port, int port) { - int port; - - port = DEFAULT_GDBSTUB_PORT; - if (argc >= 2) - port = atoi(argv[1]); + if (!has_port) + port = DEFAULT_GDBSTUB_PORT; if (gdbserver_start(port) < 0) { qemu_printf("Could not open gdbserver socket on port %d\n", port); } else { @@ -308,90 +297,754 @@ static void do_gdbserver(int argc, const char **argv) } #endif +static void term_printc(int c) +{ + term_printf("'"); + switch(c) { + case '\'': + term_printf("\\'"); + break; + case '\\': + term_printf("\\\\"); + break; + case '\n': + term_printf("\\n"); + break; + case '\r': + term_printf("\\r"); + break; + default: + if (c >= 32 && c <= 126) { + term_printf("%c", c); + } else { + term_printf("\\x%02x", c); + } + break; + } + term_printf("'"); +} + +static void memory_dump(int count, int format, int wsize, + target_ulong addr, int is_physical) +{ + int nb_per_line, l, line_size, i, max_digits, len; + uint8_t buf[16]; + uint64_t v; + + if (format == 'i') { + int flags; + flags = 0; +#ifdef TARGET_I386 + /* we use the current CS size */ + if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK)) + flags = 1; +#endif + monitor_disas(addr, count, is_physical, flags); + return; + } + + len = wsize * count; + if (wsize == 1) + line_size = 8; + else + line_size = 16; + nb_per_line = line_size / wsize; + max_digits = 0; + + switch(format) { + case 'o': + max_digits = (wsize * 8 + 2) / 3; + break; + default: + case 'x': + max_digits = (wsize * 8) / 4; + break; + case 'u': + case 'd': + max_digits = (wsize * 8 * 10 + 32) / 33; + break; + case 'c': + wsize = 1; + break; + } + + while (len > 0) { + term_printf("0x%08x:", addr); + l = len; + if (l > line_size) + l = line_size; + if (is_physical) { + cpu_physical_memory_rw(addr, buf, l, 0); + } else { + cpu_memory_rw_debug(cpu_single_env, addr, buf, l, 0); + } + i = 0; + while (i < l) { + switch(wsize) { + default: + case 1: + v = ldub_raw(buf + i); + break; + case 2: + v = lduw_raw(buf + i); + break; + case 4: + v = ldl_raw(buf + i); + break; + case 8: + v = ldq_raw(buf + i); + break; + } + term_printf(" "); + switch(format) { + case 'o': + term_printf("%#*llo", max_digits, v); + break; + case 'x': + term_printf("0x%0*llx", max_digits, v); + break; + case 'u': + term_printf("%*llu", max_digits, v); + break; + case 'd': + term_printf("%*lld", max_digits, v); + break; + case 'c': + term_printc(v); + break; + } + i += wsize; + } + term_printf("\n"); + addr += l; + len -= l; + } +} + +static void do_memory_dump(int count, int format, int size, int addr) +{ + memory_dump(count, format, size, addr, 0); +} + +static void do_physical_memory_dump(int count, int format, int size, int addr) +{ + memory_dump(count, format, size, addr, 1); +} + +static void do_print(int count, int format, int size, int val) +{ + switch(format) { + case 'o': + term_printf("%#o", val); + break; + case 'x': + term_printf("%#x", val); + break; + case 'u': + term_printf("%u", val); + break; + default: + case 'd': + term_printf("%d", val); + break; + case 'c': + term_printc(val); + break; + } + term_printf("\n"); +} + static term_cmd_t term_cmds[] = { - { "help|?", do_help, + { "help|?", "s?", do_help, "[cmd]", "show the help" }, - { "commit", do_commit, + { "commit", "", do_commit, "", "commit changes to the disk images (if -snapshot is used)" }, - { "info", do_info, + { "info", "s?", do_info, "subcommand", "show various information about the system state" }, - { "q|quit", do_quit, + { "q|quit", "", do_quit, "", "quit the emulator" }, - { "eject", do_eject, + { "eject", "-fs", do_eject, "[-f] device", "eject a removable media (use -f to force it)" }, - { "change", do_change, + { "change", "sF", do_change, "device filename", "change a removable media" }, - { "screendump", do_screen_dump, + { "screendump", "F", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, - { "log", do_log, + { "log", "s", do_log, "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, - { "savevm", do_savevm, + { "savevm", "F", do_savevm, "filename", "save the whole virtual machine state to 'filename'" }, - { "loadvm", do_loadvm, + { "loadvm", "F", do_loadvm, "filename", "restore the whole virtual machine state from 'filename'" }, - { "stop", do_stop, "", "stop emulation", }, - { "c|cont", do_cont, "", "resume emulation", }, + { "stop", "", do_stop, + "", "stop emulation", }, + { "c|cont", "", do_cont, + "", "resume emulation", }, #ifdef CONFIG_GDBSTUB - { "gdbserver", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, + { "gdbserver", "i?", do_gdbserver, + "[port]", "start gdbserver session (default port=1234)", }, #endif + { "x", "/i", do_memory_dump, + "/fmt addr", "virtual memory dump starting at 'addr'", }, + { "xp", "/i", do_physical_memory_dump, + "/fmt addr", "physical memory dump starting at 'addr'", }, + { "p|print", "/i", do_print, + "/fmt expr", "print expression value (use $reg for CPU register access)", }, { NULL, NULL, }, }; static term_cmd_t info_cmds[] = { - { "network", do_info_network, + { "network", "", do_info_network, "", "show the network state" }, - { "block", do_info_block, + { "block", "", do_info_block, "", "show the block devices" }, + { "registers", "", do_info_registers, + "", "show the cpu registers" }, { NULL, NULL, }, }; -static void term_handle_command(char *cmdline) +/*******************************************************************/ + +static const char *pch; +static jmp_buf expr_env; + +typedef struct MonitorDef { + const char *name; + int offset; + int (*get_value)(struct MonitorDef *md); +} MonitorDef; + +static MonitorDef monitor_defs[] = { +#ifdef TARGET_I386 + { "eax", offsetof(CPUState, regs[0]) }, + { "ecx", offsetof(CPUState, regs[1]) }, + { "edx", offsetof(CPUState, regs[2]) }, + { "ebx", offsetof(CPUState, regs[3]) }, + { "esp|sp", offsetof(CPUState, regs[4]) }, + { "ebp|fp", offsetof(CPUState, regs[5]) }, + { "esi", offsetof(CPUState, regs[6]) }, + { "esi", offsetof(CPUState, regs[7]) }, + { "eflags", offsetof(CPUState, eflags) }, + { "eip|pc", offsetof(CPUState, eip) }, +#endif + { NULL }, +}; + +static void expr_error(const char *fmt) +{ + term_printf(fmt); + term_printf("\n"); + longjmp(expr_env, 1); +} + +static int get_monitor_def(int *pval, const char *name) +{ + MonitorDef *md; + for(md = monitor_defs; md->name != NULL; md++) { + if (compare_cmd(name, md->name)) { + if (md->get_value) { + *pval = md->get_value(md); + } else { + *pval = *(uint32_t *)((uint8_t *)cpu_single_env + md->offset); + } + return 0; + } + } + return -1; +} + +static void next(void) +{ + if (pch != '\0') { + pch++; + while (isspace(*pch)) + pch++; + } +} + +static int expr_sum(void); + +static int expr_unary(void) +{ + int n; + char *p; + + switch(*pch) { + case '+': + next(); + n = expr_unary(); + break; + case '-': + next(); + n = -expr_unary(); + break; + case '~': + next(); + n = ~expr_unary(); + break; + case '(': + next(); + n = expr_sum(); + if (*pch != ')') { + expr_error("')' expected"); + } + next(); + break; + case '$': + { + char buf[128], *q; + + pch++; + q = buf; + while ((*pch >= 'a' && *pch <= 'z') || + (*pch >= 'A' && *pch <= 'Z') || + (*pch >= '0' && *pch <= '9') || + *pch == '_') { + if ((q - buf) < sizeof(buf) - 1) + *q++ = *pch; + pch++; + } + while (isspace(*pch)) + pch++; + *q = 0; + if (get_monitor_def(&n, buf)) + expr_error("unknown register"); + } + break; + case '\0': + expr_error("unexpected end of expression"); + n = 0; + break; + default: + n = strtoul(pch, &p, 0); + if (pch == p) { + expr_error("invalid char in expression"); + } + pch = p; + while (isspace(*pch)) + pch++; + break; + } + return n; +} + + +static int expr_prod(void) +{ + int val, val2, op; + + val = expr_unary(); + for(;;) { + op = *pch; + if (op != '*' && op != '/' && op != '%') + break; + next(); + val2 = expr_unary(); + switch(op) { + default: + case '*': + val *= val2; + break; + case '/': + case '%': + if (val2 == 0) + expr_error("divison by zero"); + if (op == '/') + val /= val2; + else + val %= val2; + break; + } + } + return val; +} + +static int expr_logic(void) +{ + int val, val2, op; + + val = expr_prod(); + for(;;) { + op = *pch; + if (op != '&' && op != '|' && op != '^') + break; + next(); + val2 = expr_prod(); + switch(op) { + default: + case '&': + val &= val2; + break; + case '|': + val |= val2; + break; + case '^': + val ^= val2; + break; + } + } + return val; +} + +static int expr_sum(void) { - char *p, *pstart; - int argc; - const char *args[MAX_ARGS + 1]; + int val, val2, op; + + val = expr_logic(); + for(;;) { + op = *pch; + if (op != '+' && op != '-') + break; + next(); + val2 = expr_logic(); + if (op == '+') + val += val2; + else + val -= val2; + } + return val; +} + +static int get_expr(int *pval, const char **pp) +{ + pch = *pp; + if (setjmp(expr_env)) { + *pp = pch; + return -1; + } + while (isspace(*pch)) + pch++; + *pval = expr_sum(); + *pp = pch; + return 0; +} + +static int get_str(char *buf, int buf_size, const char **pp) +{ + const char *p; + char *q; + int c; + + p = *pp; + while (isspace(*p)) + p++; + if (*p == '\0') { + fail: + *pp = p; + return -1; + } + q = buf; + if (*p == '\"') { + p++; + while (*p != '\0' && *p != '\"') { + if (*p == '\\') { + p++; + c = *p++; + switch(c) { + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case '\\': + case '\'': + case '\"': + break; + default: + qemu_printf("unsupported escape code: '\\%c'\n", c); + goto fail; + } + if ((q - buf) < buf_size - 1) { + *q++ = c; + } + } else { + if ((q - buf) < buf_size - 1) { + *q++ = *p; + } + p++; + } + } + if (*p != '\"') { + qemu_printf("untermintated string\n"); + goto fail; + } + p++; + } else { + while (*p != '\0' && !isspace(*p)) { + if ((q - buf) < buf_size - 1) { + *q++ = *p; + } + p++; + } + *q = '\0'; + } + *pp = p; + return 0; +} + +static int default_fmt_format = 'x'; +static int default_fmt_size = 4; + +#define MAX_ARGS 16 + +static void term_handle_command(const char *cmdline) +{ + const char *p, *pstart, *typestr; + char *q; + int c, nb_args, len, i, has_arg; term_cmd_t *cmd; + char cmdname[256]; + char buf[1024]; + void *str_allocated[MAX_ARGS]; + void *args[MAX_ARGS]; #ifdef DEBUG term_printf("command='%s'\n", cmdline); #endif - /* split command in words */ - argc = 0; + /* extract the command name */ p = cmdline; + q = cmdname; + while (isspace(*p)) + p++; + if (*p == '\0') + return; + pstart = p; + while (*p != '\0' && *p != '/' && !isspace(*p)) + p++; + len = p - pstart; + if (len > sizeof(cmdname) - 1) + len = sizeof(cmdname) - 1; + memcpy(cmdname, pstart, len); + cmdname[len] = '\0'; + + /* find the command */ + for(cmd = term_cmds; cmd->name != NULL; cmd++) { + if (compare_cmd(cmdname, cmd->name)) + goto found; + } + term_printf("unknown command: '%s'\n", cmdname); + return; + found: + + for(i = 0; i < MAX_ARGS; i++) + str_allocated[i] = NULL; + + /* parse the parameters */ + typestr = cmd->args_type; + nb_args = 0; for(;;) { - while (isspace(*p)) - p++; - if (*p == '\0') + c = *typestr; + if (c == '\0') break; - pstart = p; - while (*p != '\0' && !isspace(*p)) - p++; - args[argc] = pstart; - argc++; - if (argc >= MAX_ARGS) + typestr++; + switch(c) { + case 'F': + case 's': + { + int ret; + char *str; + + while (isspace(*p)) + p++; + if (*typestr == '?') { + typestr++; + if (*p == '\0') { + /* no optional string: NULL argument */ + str = NULL; + goto add_str; + } + } + ret = get_str(buf, sizeof(buf), &p); + if (ret < 0) { + if (c == 'F') + term_printf("%s: filename expected\n", cmdname); + else + term_printf("%s: string expected\n", cmdname); + goto fail; + } + str = qemu_malloc(strlen(buf) + 1); + strcpy(str, buf); + str_allocated[nb_args] = str; + add_str: + if (nb_args >= MAX_ARGS) { + error_args: + term_printf("%s: too many arguments\n", cmdname); + goto fail; + } + args[nb_args++] = str; + } break; - if (*p == '\0') + case '/': + { + int count, format, size; + + while (isspace(*p)) + p++; + if (*p == '/') { + /* format found */ + p++; + count = 1; + if (isdigit(*p)) { + count = 0; + while (isdigit(*p)) { + count = count * 10 + (*p - '0'); + p++; + } + } + size = -1; + format = -1; + for(;;) { + switch(*p) { + case 'o': + case 'd': + case 'u': + case 'x': + case 'i': + case 'c': + format = *p++; + break; + case 'b': + size = 1; + p++; + break; + case 'h': + size = 2; + p++; + break; + case 'w': + size = 4; + p++; + break; + case 'g': + case 'L': + size = 8; + p++; + break; + default: + goto next; + } + } + next: + if (*p != '\0' && !isspace(*p)) { + term_printf("invalid char in format: '%c'\n", *p); + goto fail; + } + if (size < 0) + size = default_fmt_size; + if (format < 0) + format = default_fmt_format; + default_fmt_size = size; + default_fmt_format = format; + } else { + count = 1; + format = default_fmt_format; + size = default_fmt_size; + } + if (nb_args + 3 > MAX_ARGS) + goto error_args; + args[nb_args++] = (void*)count; + args[nb_args++] = (void*)format; + args[nb_args++] = (void*)size; + } + break; + case 'i': + { + int val; + while (isspace(*p)) + p++; + if (*typestr == '?') { + typestr++; + if (*p == '\0') + has_arg = 0; + else + has_arg = 1; + if (nb_args >= MAX_ARGS) + goto error_args; + args[nb_args++] = (void *)has_arg; + if (!has_arg) { + if (nb_args >= MAX_ARGS) + goto error_args; + val = -1; + goto add_num; + } + } + if (get_expr(&val, &p)) + goto fail; + add_num: + if (nb_args >= MAX_ARGS) + goto error_args; + args[nb_args++] = (void *)val; + } break; - *p++ = '\0'; + case '-': + { + int has_option; + /* option */ + + c = *typestr++; + if (c == '\0') + goto bad_type; + while (isspace(*p)) + p++; + has_option = 0; + if (*p == '-') { + p++; + if (*p != c) { + term_printf("%s: unsupported option -%c\n", + cmdname, *p); + goto fail; + } + p++; + has_option = 1; + } + if (nb_args >= MAX_ARGS) + goto error_args; + args[nb_args++] = (void *)has_option; + } + break; + default: + bad_type: + term_printf("%s: unknown type '%c'\n", cmdname, c); + goto fail; + } } - args[argc] = NULL; -#ifdef DEBUG - for(i=0;iname != NULL; cmd++) { - if (compare_cmd(args[0], cmd->name)) - goto found; + + switch(nb_args) { + case 0: + cmd->handler(); + break; + case 1: + cmd->handler(args[0]); + break; + case 2: + cmd->handler(args[0], args[1]); + break; + case 3: + cmd->handler(args[0], args[1], args[2]); + break; + case 4: + cmd->handler(args[0], args[1], args[2], args[3]); + break; + case 5: + cmd->handler(args[0], args[1], args[2], args[3], args[4]); + break; + default: + term_printf("unsupported number of arguments: %d\n", nb_args); + goto fail; } - term_printf("unknown command: '%s'\n", args[0]); + fail: + for(i = 0; i < MAX_ARGS; i++) + qemu_free(str_allocated[i]); return; - found: - cmd->handler(argc, args); } static void term_show_prompt(void) -- cgit v1.2.3 From aa455485c97afa6096a97b54b3bfdf784e5ea9fd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Apr 2004 13:07:25 +0000 Subject: history support (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@704 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/monitor.c b/monitor.c index fc05746a5..9e55c0cb5 100644 --- a/monitor.c +++ b/monitor.c @@ -31,6 +31,7 @@ #endif #define TERM_CMD_BUF_SIZE 4095 +#define TERM_MAX_CMDS 64 #define IS_NORM 0 #define IS_ESC 1 @@ -44,6 +45,9 @@ static int term_cmd_buf_size; static int term_esc_state; static int term_esc_param; +static char *term_history[TERM_MAX_CMDS]; +static int term_hist_entry; + /* * Supported types: * @@ -190,6 +194,17 @@ static void do_info_registers(void) #endif } +static void do_info_history (void) +{ + int i; + + for (i = 0; i < TERM_MAX_CMDS; i++) { + if (term_history[i] == NULL) + break; + term_printf("%d: '%s'\n", i, term_history[i]); + } +} + static void do_quit(void) { exit(0); @@ -499,6 +514,8 @@ static term_cmd_t info_cmds[] = { "", "show the block devices" }, { "registers", "", do_info_registers, "", "show the cpu registers" }, + { "history", "", do_info_history, + "", "show the command line history", }, { NULL, NULL, }, }; @@ -1056,6 +1073,13 @@ static void term_show_prompt(void) term_esc_state = IS_NORM; } +static void term_print_cmdline (const char *cmdline) +{ + term_show_prompt(); + term_printf(cmdline); + term_flush(); +} + static void term_insert_char(int ch) { if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) { @@ -1120,6 +1144,92 @@ static void term_eol(void) term_forward_char(); } +static void term_up_char(void) +{ + int idx; + + if (term_hist_entry == 0) + return; + if (term_hist_entry == -1) { + /* Find latest entry */ + for (idx = 0; idx < TERM_MAX_CMDS; idx++) { + if (term_history[idx] == NULL) + break; + } + term_hist_entry = idx; + } + term_hist_entry--; + if (term_hist_entry >= 0) { + strcpy(term_cmd_buf, term_history[term_hist_entry]); + term_printf("\n"); + term_print_cmdline(term_cmd_buf); + term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); + } +} + +static void term_down_char(void) +{ + if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1) + return; + if (term_history[++term_hist_entry] != NULL) { + strcpy(term_cmd_buf, term_history[term_hist_entry]); + } else { + term_hist_entry = -1; + } + term_printf("\n"); + term_print_cmdline(term_cmd_buf); + term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); +} + +static void term_hist_add(const char *cmdline) +{ + char *hist_entry, *new_entry; + int idx; + + if (cmdline[0] == '\0') + return; + new_entry = NULL; + if (term_hist_entry != -1) { + /* We were editing an existing history entry: replace it */ + hist_entry = term_history[term_hist_entry]; + idx = term_hist_entry; + if (strcmp(hist_entry, cmdline) == 0) { + goto same_entry; + } + } + /* Search cmdline in history buffers */ + for (idx = 0; idx < TERM_MAX_CMDS; idx++) { + hist_entry = term_history[idx]; + if (hist_entry == NULL) + break; + if (strcmp(hist_entry, cmdline) == 0) { + same_entry: + new_entry = hist_entry; + /* Put this entry at the end of history */ + memmove(&term_history[idx], &term_history[idx + 1], + &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]); + term_history[TERM_MAX_CMDS - 1] = NULL; + for (; idx < TERM_MAX_CMDS; idx++) { + if (term_history[idx] == NULL) + break; + } + break; + } + } + if (idx == TERM_MAX_CMDS) { + /* Need to get one free slot */ + free(term_history[0]); + memcpy(term_history, &term_history[1], + &term_history[TERM_MAX_CMDS] - &term_history[1]); + term_history[TERM_MAX_CMDS - 1] = NULL; + idx = TERM_MAX_CMDS - 1; + } + if (new_entry == NULL) + new_entry = strdup(cmdline); + term_history[idx] = new_entry; + term_hist_entry = -1; +} + /* return true if command handled */ static void term_handle_byte(int ch) { @@ -1135,6 +1245,7 @@ static void term_handle_byte(int ch) case 10: case 13: term_cmd_buf[term_cmd_buf_size] = '\0'; + term_hist_add(term_cmd_buf); term_printf("\n"); term_handle_command(term_cmd_buf); term_show_prompt(); @@ -1146,6 +1257,9 @@ static void term_handle_byte(int ch) case 8: term_backspace(); break; + case 155: + term_esc_state = IS_CSI; + break; default: if (ch >= 32) { term_insert_char(ch); @@ -1163,6 +1277,14 @@ static void term_handle_byte(int ch) break; case IS_CSI: switch(ch) { + case 'A': + case 'F': + term_up_char(); + break; + case 'B': + case 'E': + term_down_char(); + break; case 'D': term_backward_char(); break; @@ -1290,5 +1412,6 @@ void monitor_init(void) QEMU_VERSION); term_show_prompt(); } + term_hist_entry = -1; qemu_add_fd_read_handler(0, term_can_read, term_read, NULL); } -- cgit v1.2.3 From 1f673135acedadf942edb0c6c5238739313d718c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Apr 2004 15:21:17 +0000 Subject: doc update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@705 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 +- TODO | 1 - linux-2.6-qemu-fast.patch | 305 ++++++++++++ qemu-doc.texi | 1156 +++++++++++++++++++-------------------------- qemu-tech.texi | 506 ++++++++++++++++++++ 5 files changed, 1302 insertions(+), 670 deletions(-) create mode 100644 linux-2.6-qemu-fast.patch create mode 100644 qemu-tech.texi diff --git a/Makefile b/Makefile index fc9d74f9c..15506a19c 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ifndef CONFIG_WIN32 TOOLS=qemu-mkcow endif -all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu.1 +all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1 for d in $(TARGET_DIRS); do \ make -C $$d $@ || exit 1 ; \ done @@ -61,7 +61,7 @@ TAGS: etags *.[ch] tests/*.[ch] # documentation -qemu-doc.html: qemu-doc.texi +%.html: %.texi texi2html -monolithic -number $< qemu.1: qemu-doc.texi diff --git a/TODO b/TODO index 8f66ee5c0..3d8b0b805 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,6 @@ short term: ---------- - handle fast timers + add explicit clocks - OS/2 install bug -- win 95 install bug - handle Self Modifying Code even if modifying current TB (BE OS 5 install) - physical memory cache (reduce qemu-fast address space size to about 32 MB) - better code fetch diff --git a/linux-2.6-qemu-fast.patch b/linux-2.6-qemu-fast.patch new file mode 100644 index 000000000..34ca5a232 --- /dev/null +++ b/linux-2.6-qemu-fast.patch @@ -0,0 +1,305 @@ +diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/Kconfig .32324-linux-2.6.0.updated/arch/i386/Kconfig +--- .32324-linux-2.6.0/arch/i386/Kconfig 2003-10-09 18:02:48.000000000 +1000 ++++ .32324-linux-2.6.0.updated/arch/i386/Kconfig 2003-12-26 16:46:49.000000000 +1100 +@@ -307,6 +307,14 @@ config X86_GENERIC + when it has moderate overhead. This is intended for generic + distributions kernels. + ++config QEMU ++ bool "Kernel to run under QEMU" ++ depends on EXPERIMENTAL ++ help ++ Select this if you want to boot the kernel inside qemu-fast, ++ the non-mmu version of the x86 emulator. See ++ . Say N. ++ + # + # Define implied options from the CPU selection here + # +diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/Makefile .32324-linux-2.6.0.updated/arch/i386/kernel/Makefile +--- .32324-linux-2.6.0/arch/i386/kernel/Makefile 2003-09-29 10:25:15.000000000 +1000 ++++ .32324-linux-2.6.0.updated/arch/i386/kernel/Makefile 2003-12-26 16:46:49.000000000 +1100 +@@ -46,12 +46,14 @@ quiet_cmd_syscall = SYSCALL $@ + cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ + -Wl,-T,$(filter-out FORCE,$^) -o $@ + ++export AFLAGS_vsyscall.lds.o += -P -C -U$(ARCH) ++ + vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 + SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) + SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) + + $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \ +-$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE ++$(obj)/vsyscall-%.so: $(src)/vsyscall.lds.s $(obj)/vsyscall-%.o FORCE + $(call if_changed,syscall) + + # We also create a special relocatable object that should mirror the symbol +@@ -62,5 +64,5 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms. + $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o + + SYSCFLAGS_vsyscall-syms.o = -r +-$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE ++$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds.s $(obj)/vsyscall-sysenter.o FORCE + $(call if_changed,syscall) +diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vmlinux.lds.S .32324-linux-2.6.0.updated/arch/i386/kernel/vmlinux.lds.S +--- .32324-linux-2.6.0/arch/i386/kernel/vmlinux.lds.S 2003-09-22 10:27:28.000000000 +1000 ++++ .32324-linux-2.6.0.updated/arch/i386/kernel/vmlinux.lds.S 2003-12-26 16:46:49.000000000 +1100 +@@ -3,6 +3,7 @@ + */ + + #include ++#include + + OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") + OUTPUT_ARCH(i386) +@@ -10,7 +11,7 @@ ENTRY(startup_32) + jiffies = jiffies_64; + SECTIONS + { +- . = 0xC0000000 + 0x100000; ++ . = __PAGE_OFFSET + 0x100000; + /* read-only */ + _text = .; /* Text and read-only data */ + .text : { +diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds +--- .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds 2003-09-22 10:07:26.000000000 +1000 ++++ .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds 1970-01-01 10:00:00.000000000 +1000 +@@ -1,67 +0,0 @@ +-/* +- * Linker script for vsyscall DSO. The vsyscall page is an ELF shared +- * object prelinked to its virtual address, and with only one read-only +- * segment (that fits in one page). This script controls its layout. +- */ +- +-/* This must match . */ +-VSYSCALL_BASE = 0xffffe000; +- +-SECTIONS +-{ +- . = VSYSCALL_BASE + SIZEOF_HEADERS; +- +- .hash : { *(.hash) } :text +- .dynsym : { *(.dynsym) } +- .dynstr : { *(.dynstr) } +- .gnu.version : { *(.gnu.version) } +- .gnu.version_d : { *(.gnu.version_d) } +- .gnu.version_r : { *(.gnu.version_r) } +- +- /* This linker script is used both with -r and with -shared. +- For the layouts to match, we need to skip more than enough +- space for the dynamic symbol table et al. If this amount +- is insufficient, ld -shared will barf. Just increase it here. */ +- . = VSYSCALL_BASE + 0x400; +- +- .text : { *(.text) } :text =0x90909090 +- +- .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr +- .eh_frame : { KEEP (*(.eh_frame)) } :text +- .dynamic : { *(.dynamic) } :text :dynamic +- .useless : { +- *(.got.plt) *(.got) +- *(.data .data.* .gnu.linkonce.d.*) +- *(.dynbss) +- *(.bss .bss.* .gnu.linkonce.b.*) +- } :text +-} +- +-/* +- * We must supply the ELF program headers explicitly to get just one +- * PT_LOAD segment, and set the flags explicitly to make segments read-only. +- */ +-PHDRS +-{ +- text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ +- dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ +- eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ +-} +- +-/* +- * This controls what symbols we export from the DSO. +- */ +-VERSION +-{ +- LINUX_2.5 { +- global: +- __kernel_vsyscall; +- __kernel_sigreturn; +- __kernel_rt_sigreturn; +- +- local: *; +- }; +-} +- +-/* The ELF entry point can be used to set the AT_SYSINFO value. */ +-ENTRY(__kernel_vsyscall); +diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds.S .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds.S +--- .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds.S 1970-01-01 10:00:00.000000000 +1000 ++++ .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds.S 2003-12-26 16:46:49.000000000 +1100 +@@ -0,0 +1,67 @@ ++/* ++ * Linker script for vsyscall DSO. The vsyscall page is an ELF shared ++ * object prelinked to its virtual address, and with only one read-only ++ * segment (that fits in one page). This script controls its layout. ++ */ ++#include ++ ++VSYSCALL_BASE = __FIXADDR_TOP - 0x1000; ++ ++SECTIONS ++{ ++ . = VSYSCALL_BASE + SIZEOF_HEADERS; ++ ++ .hash : { *(.hash) } :text ++ .dynsym : { *(.dynsym) } ++ .dynstr : { *(.dynstr) } ++ .gnu.version : { *(.gnu.version) } ++ .gnu.version_d : { *(.gnu.version_d) } ++ .gnu.version_r : { *(.gnu.version_r) } ++ ++ /* This linker script is used both with -r and with -shared. ++ For the layouts to match, we need to skip more than enough ++ space for the dynamic symbol table et al. If this amount ++ is insufficient, ld -shared will barf. Just increase it here. */ ++ . = VSYSCALL_BASE + 0x400; ++ ++ .text : { *(.text) } :text =0x90909090 ++ ++ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr ++ .eh_frame : { KEEP (*(.eh_frame)) } :text ++ .dynamic : { *(.dynamic) } :text :dynamic ++ .useless : { ++ *(.got.plt) *(.got) ++ *(.data .data.* .gnu.linkonce.d.*) ++ *(.dynbss) ++ *(.bss .bss.* .gnu.linkonce.b.*) ++ } :text ++} ++ ++/* ++ * We must supply the ELF program headers explicitly to get just one ++ * PT_LOAD segment, and set the flags explicitly to make segments read-only. ++ */ ++PHDRS ++{ ++ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ ++ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ ++ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ ++} ++ ++/* ++ * This controls what symbols we export from the DSO. ++ */ ++VERSION ++{ ++ LINUX_2.5 { ++ global: ++ __kernel_vsyscall; ++ __kernel_sigreturn; ++ __kernel_rt_sigreturn; ++ ++ local: *; ++ }; ++} ++ ++/* The ELF entry point can be used to set the AT_SYSINFO value. */ ++ENTRY(__kernel_vsyscall); +diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/fixmap.h .32324-linux-2.6.0.updated/include/asm-i386/fixmap.h +--- .32324-linux-2.6.0/include/asm-i386/fixmap.h 2003-09-22 10:09:12.000000000 +1000 ++++ .32324-linux-2.6.0.updated/include/asm-i386/fixmap.h 2003-12-26 16:46:49.000000000 +1100 +@@ -14,6 +14,19 @@ + #define _ASM_FIXMAP_H + + #include ++ ++/* used by vmalloc.c, vsyscall.lds.S. ++ * ++ * Leave one empty page between vmalloc'ed areas and ++ * the start of the fixmap. ++ */ ++#ifdef CONFIG_QEMU ++#define __FIXADDR_TOP 0xa7fff000 ++#else ++#define __FIXADDR_TOP 0xfffff000 ++#endif ++ ++#ifndef __ASSEMBLY__ + #include + #include + #include +@@ -94,13 +107,8 @@ extern void __set_fixmap (enum fixed_add + #define clear_fixmap(idx) \ + __set_fixmap(idx, 0, __pgprot(0)) + +-/* +- * used by vmalloc.c. +- * +- * Leave one empty page between vmalloc'ed areas and +- * the start of the fixmap. +- */ +-#define FIXADDR_TOP (0xfffff000UL) ++#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP) ++ + #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) + #define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) + +@@ -145,4 +153,5 @@ static inline unsigned long virt_to_fix( + return __virt_to_fix(vaddr); + } + ++#endif /* !__ASSEMBLY__ */ + #endif +diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/page.h .32324-linux-2.6.0.updated/include/asm-i386/page.h +--- .32324-linux-2.6.0/include/asm-i386/page.h 2003-09-22 10:06:42.000000000 +1000 ++++ .32324-linux-2.6.0.updated/include/asm-i386/page.h 2003-12-26 16:46:49.000000000 +1100 +@@ -10,10 +10,10 @@ + #define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) + + #ifdef __KERNEL__ +-#ifndef __ASSEMBLY__ +- + #include + ++#ifndef __ASSEMBLY__ ++ + #ifdef CONFIG_X86_USE_3DNOW + + #include +@@ -115,12 +115,19 @@ static __inline__ int get_order(unsigned + #endif /* __ASSEMBLY__ */ + + #ifdef __ASSEMBLY__ ++#ifdef CONFIG_QEMU ++#define __PAGE_OFFSET (0x90000000) ++#else + #define __PAGE_OFFSET (0xC0000000) ++#endif /* QEMU */ ++#else ++#ifdef CONFIG_QEMU ++#define __PAGE_OFFSET (0x90000000UL) + #else + #define __PAGE_OFFSET (0xC0000000UL) ++#endif /* QEMU */ + #endif + +- + #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) + #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) + #define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/param.h .32324-linux-2.6.0.updated/include/asm-i386/param.h +--- .32324-linux-2.6.0/include/asm-i386/param.h 2003-09-21 17:26:06.000000000 +1000 ++++ .32324-linux-2.6.0.updated/include/asm-i386/param.h 2003-12-26 16:46:49.000000000 +1100 +@@ -2,7 +2,12 @@ + #define _ASMi386_PARAM_H + + #ifdef __KERNEL__ +-# define HZ 1000 /* Internal kernel timer frequency */ ++# include ++# ifdef CONFIG_QEMU ++# define HZ 100 ++# else ++# define HZ 1000 /* Internal kernel timer frequency */ ++# endif + # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ + # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ + #endif diff --git a/qemu-doc.texi b/qemu-doc.texi index 5ca8e8f3b..1f056065b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1,10 +1,10 @@ \input texinfo @c -*- texinfo -*- @iftex -@settitle QEMU CPU Emulator Reference Documentation +@settitle QEMU CPU Emulator User Documentation @titlepage @sp 7 -@center @titlefont{QEMU CPU Emulator Reference Documentation} +@center @titlefont{QEMU CPU Emulator User Documentation} @sp 3 @end titlepage @end iftex @@ -13,126 +13,39 @@ @section Features -QEMU is a FAST! processor emulator. By using dynamic translation it -achieves a reasonnable speed while being easy to port on new host -CPUs. +QEMU is a FAST! processor emulator using dynamic translation to +achieve good emulation speed. QEMU has two operating modes: @itemize @minus @item -User mode emulation. In this mode, QEMU can launch Linux processes -compiled for one CPU on another CPU. Linux system calls are converted -because of endianness and 32/64 bit mismatches. The Wine Windows API -emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator -(@url{http://www.dosemu.org}) are the main targets for QEMU. +Full system emulation. In this mode, QEMU emulates a full system (for +example a PC), including a processor and various peripherials. It can +be used to launch different Operating Systems without rebooting the +PC or to debug system code. @item -Full system emulation. In this mode, QEMU emulates a full -system, including a processor and various peripherials. Currently, it -is only used to launch an x86 Linux kernel on an x86 Linux system. It -enables easier testing and debugging of system code. It can also be -used to provide virtual hosting of several virtual PCs on a single -server. +User mode emulation (Linux host only). In this mode, QEMU can launch +Linux processes compiled for one CPU on another CPU. It can be used to +launch the Wine Windows API emulator (@url{http://www.winehq.org}) or +to ease cross-compilation and cross-debugging. @end itemize -As QEMU requires no host kernel patches to run, it is very safe and +As QEMU requires no host kernel driver to run, it is very safe and easy to use. -QEMU generic features: +For system emulation, only the x86 PC emulator is currently +usable. The PowerPC system emulator is being developped. -@itemize - -@item User space only or full system emulation. - -@item Using dynamic translation to native code for reasonnable speed. - -@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390. - -@item Self-modifying code support. - -@item Precise exceptions support. - -@item The virtual CPU is a library (@code{libqemu}) which can be used -in other projects. - -@end itemize - -QEMU user mode emulation features: -@itemize -@item Generic Linux system call converter, including most ioctls. - -@item clone() emulation using native CPU clone() to use Linux scheduler for threads. - -@item Accurate signal handling by remapping host signals to target signals. -@end itemize -@end itemize - -QEMU full system emulation features: -@itemize -@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU. -@end itemize - -@section x86 emulation - -QEMU x86 target features: - -@itemize - -@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. -LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU. - -@item Support of host page sizes bigger than 4KB in user mode emulation. - -@item QEMU can emulate itself on x86. - -@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}. -It can be used to test other x86 virtual CPUs. - -@end itemize - -Current QEMU limitations: - -@itemize - -@item No SSE/MMX support (yet). - -@item No x86-64 support. - -@item IPC syscalls are missing. - -@item The x86 segment limits and access rights are not tested at every -memory access. - -@item On non x86 host CPUs, @code{double}s are used instead of the non standard -10 byte @code{long double}s of x86 for floating point emulation to get -maximum performances. - -@item Some priviledged instructions or behaviors are missing, especially for segment protection testing (yet). - -@end itemize - -@section ARM emulation - -@itemize - -@item ARM emulation can currently launch small programs while using the -generic dynamic code generation architecture of QEMU. - -@item No FPU support (yet). - -@item No automatic regression testing (yet). - -@end itemize - -@section SPARC emulation - -The SPARC emulation is currently in development. +For user emulation, x86, PowerPC, ARM, and SPARC CPUs are supported. @chapter Installation +@section Linux + If you want to compile QEMU, please read the @file{README} which gives the related information. Otherwise just download the binary distribution (@file{qemu-XXX-i386.tar.gz}) and untar it as root in @@ -144,106 +57,69 @@ cd / tar zxvf /tmp/qemu-XXX-i386.tar.gz @end example -@chapter QEMU User space emulator invocation - -@section Quick Start - -In order to launch a Linux process, QEMU needs the process executable -itself and all the target (x86) dynamic libraries used by it. - +@section Windows +w @itemize +@item Install the current versions of MSYS and MinGW from +@url{http://www.mingw.org/}. You can find detailed installation +instructions in the download section and the FAQ. + +@item Download +the MinGW development library of SDL 1.2.x +(@file{SDL-devel-1.2.x-mingw32.tar.gz}) from +@url{http://www.libsdl.org}. Unpack it in a temporary place, and +unpack the archive @file{i386-mingw32msvc.tar.gz} in the MinGW tool +directory. Edit the @file{sdl-config} script so that it gives the +correct SDL directory when invoked. + +@item Extract the current version of QEMU. + +@item Start the MSYS shell (file @file{msys.bat}). -@item On x86, you can just try to launch any process by using the native -libraries: - -@example -qemu-i386 -L / /bin/ls -@end example - -@code{-L /} tells that the x86 dynamic linker must be searched with a -@file{/} prefix. - -@item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources): - -@example -qemu-i386 -L / qemu-i386 -L / /bin/ls -@end example - -@item On non x86 CPUs, you need first to download at least an x86 glibc -(@file{qemu-runtime-i386-XXX-.tar.gz} on the QEMU web page). Ensure that -@code{LD_LIBRARY_PATH} is not set: - -@example -unset LD_LIBRARY_PATH -@end example +@item Change to the QEMU directory. Launch @file{./configure} and +@file{make}. If you have problems using SDL, verify that +@file{sdl-config} can be launched from the MSYS command line. -Then you can launch the precompiled @file{ls} x86 executable: - -@example -qemu-i386 tests/i386/ls -@end example -You can look at @file{qemu-binfmt-conf.sh} so that -QEMU is automatically launched by the Linux kernel when you try to -launch x86 executables. It requires the @code{binfmt_misc} module in the -Linux kernel. - -@item The x86 version of QEMU is also included. You can try weird things such as: -@example -qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386 -@end example +@item You can install QEMU in @file{Program Files/Qemu} by typing +@file{make install}. Don't forget to copy @file{SDL.dll} in +@file{Program Files/Qemu}. @end itemize -@section Wine launch +@section Cross compilation for Windows with Linux @itemize +@item +Install the MinGW cross compilation tools available at +@url{http://www.mingw.org/}. -@item Ensure that you have a working QEMU with the x86 glibc -distribution (see previous section). In order to verify it, you must be -able to do: +@item +Install the Win32 version of SDL (@url{http://www.libsdl.org}) by +unpacking @file{i386-mingw32msvc.tar.gz}. Set up the PATH environment +variable so that @file{i386-mingw32msvc-sdl-config} can be launched by +the QEMU configuration script. +@item +Configure QEMU for Windows cross compilation: @example -qemu-i386 /usr/local/qemu-i386/bin/ls-i386 +./configure --enable-mingw32 @end example +If necessary, you can change the cross-prefix according to the prefix +choosen for the MinGW tools with --cross-prefix. You can also use +--prefix to set the Win32 install path. -@item Download the binary x86 Wine install -(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page). - -@item Configure Wine on your account. Look at the provided script -@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous -@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}. - -@item Then you can try the example @file{putty.exe}: - -@example -qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe -@end example +@item You can install QEMU in the installation directory by typing +@file{make install}. Don't forget to copy @file{SDL.dll} in the +installation directory. @end itemize -@section Command line options +Note: Currently, Wine does not seem able to launch +QEMU for Win32. -@example -usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] -@end example +@section Mac OS X -@table @option -@item -h -Print the help -@item -L path -Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) -@item -s size -Set the x86 stack size in bytes (default=524288) -@end table - -Debug options: - -@table @option -@item -d -Activate log (logfile=/tmp/qemu.log) -@item -p pagesize -Act as if the host page size was 'pagesize' bytes -@end table +Mac OS X is currently not supported. @chapter QEMU System emulator invocation @@ -251,9 +127,7 @@ Act as if the host page size was 'pagesize' bytes @c man begin DESCRIPTION -The QEMU System emulator simulates a complete PC. It can either boot -directly a Linux kernel (without any BIOS or boot loader) or boot like a -real PC with the included BIOS. +The QEMU System emulator simulates a complete PC. In order to meet specific user needs, two versions of QEMU are available: @@ -282,18 +156,14 @@ VGA (hardware level, including all non standard modes) PS/2 mouse and keyboard @item 2 IDE interfaces with hard disk and CD-ROM support +@item +Floppy disk @item -NE2000 network adapter (port=0x300, irq=9) +up to 6 NE2000 network adapters @item Serial port @item Soundblaster 16 card -@item -PIC (interrupt controler) -@item -PIT (timers) -@item -CMOS memory @end itemize @c man end @@ -308,157 +178,6 @@ qemu linux.img Linux should boot and give you a prompt. -@section Direct Linux Boot and Network emulation - -This section explains how to launch a Linux kernel inside QEMU without -having to make a full bootable image. It is very useful for fast Linux -kernel testing. The QEMU network configuration is also explained. - -@enumerate -@item -Download the archive @file{linux-test-xxx.tar.gz} containing a Linux -kernel and a disk image. - -@item Optional: If you want network support (for example to launch X11 examples), you -must copy the script @file{qemu-ifup} in @file{/etc} and configure -properly @code{sudo} so that the command @code{ifconfig} contained in -@file{qemu-ifup} can be executed as root. You must verify that your host -kernel supports the TUN/TAP network interfaces: the device -@file{/dev/net/tun} must be present. - -When network is enabled, there is a virtual network connection between -the host kernel and the emulated kernel. The emulated kernel is seen -from the host kernel at IP address 172.20.0.2 and the host kernel is -seen from the emulated kernel at IP address 172.20.0.1. - -@item Launch @code{qemu.sh}. You should have the following output: - -@example -> ./qemu.sh -Connected to host network interface: tun0 -Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 -BIOS-provided physical RAM map: - BIOS-e801: 0000000000000000 - 000000000009f000 (usable) - BIOS-e801: 0000000000100000 - 0000000002000000 (usable) -32MB LOWMEM available. -On node 0 totalpages: 8192 -zone(0): 4096 pages. -zone(1): 4096 pages. -zone(2): 0 pages. -Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe console=ttyS0 -ide_setup: ide2=noprobe -ide_setup: ide3=noprobe -ide_setup: ide4=noprobe -ide_setup: ide5=noprobe -Initializing CPU#0 -Detected 2399.621 MHz processor. -Console: colour EGA 80x25 -Calibrating delay loop... 4744.80 BogoMIPS -Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, 0k highmem) -Dentry cache hash table entries: 4096 (order: 3, 32768 bytes) -Inode cache hash table entries: 2048 (order: 2, 16384 bytes) -Mount cache hash table entries: 512 (order: 0, 4096 bytes) -Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes) -Page-cache hash table entries: 8192 (order: 3, 32768 bytes) -CPU: Intel Pentium Pro stepping 03 -Checking 'hlt' instruction... OK. -POSIX conformance testing by UNIFIX -Linux NET4.0 for Linux 2.4 -Based upon Swansea University Computer Society NET3.039 -Initializing RT netlink socket -apm: BIOS not found. -Starting kswapd -Journalled Block Device driver loaded -Detected PS/2 Mouse Port. -pty: 256 Unix98 ptys configured -Serial driver version 5.05c (2001-07-08) with no serial options enabled -ttyS00 at 0x03f8 (irq = 4) is a 16450 -ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com) -Last modified Nov 1, 2000 by Paul Gortmaker -NE*000 ethercard probe at 0x300: 52 54 00 12 34 56 -eth0: NE2000 found at 0x300, using IRQ 9. -RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize -Uniform Multi-Platform E-IDE driver Revision: 7.00beta4-2.4 -ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx -hda: QEMU HARDDISK, ATA DISK drive -ide0 at 0x1f0-0x1f7,0x3f6 on irq 14 -hda: attached ide-disk driver. -hda: 20480 sectors (10 MB) w/256KiB Cache, CHS=20/16/63 -Partition check: - hda: -Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996 -NET4: Linux TCP/IP 1.0 for NET4.0 -IP Protocols: ICMP, UDP, TCP, IGMP -IP: routing cache hash table of 512 buckets, 4Kbytes -TCP: Hash tables configured (established 2048 bind 4096) -NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. -EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended -VFS: Mounted root (ext2 filesystem). -Freeing unused kernel memory: 64k freed - -Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 - -QEMU Linux test distribution (based on Redhat 9) - -Type 'exit' to halt the system - -sh-2.05b# -@end example - -@item -Then you can play with the kernel inside the virtual serial console. You -can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help -about the keys you can type inside the virtual serial console. In -particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as -the Magic SysRq key. - -@item -If the network is enabled, launch the script @file{/etc/linuxrc} in the -emulator (don't forget the leading dot): -@example -. /etc/linuxrc -@end example - -Then enable X11 connections on your PC from the emulated Linux: -@example -xhost +172.20.0.2 -@end example - -You can now launch @file{xterm} or @file{xlogo} and verify that you have -a real Virtual Linux system ! - -@end enumerate - -NOTES: -@enumerate -@item -A 2.5.74 kernel is also included in the archive. Just -replace the bzImage in qemu.sh to try it. - -@item -qemu creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the -default) containing all the simulated PC memory. If possible, try to use -a temporary directory using the tmpfs filesystem to avoid too many -unnecessary disk accesses. - -@item -In order to exit cleanly from qemu, you can do a @emph{shutdown} inside -qemu. qemu will automatically exit when the Linux shutdown is done. - -@item -You can boot slightly faster by disabling the probe of non present IDE -interfaces. To do so, add the following options on the kernel command -line: -@example -ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe -@end example - -@item -The example disk image is a modified version of the one made by Kevin -Lawton for the plex86 Project (@url{www.plex86.org}). - -@end enumerate - @section Invocation @example @@ -486,8 +205,8 @@ Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}). Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and @option{-cdrom} at the same time). -@item -boot [a|b|c|d] -Boot on floppy (a, b), hard disk (c) or CD-ROM (d). Hard disk boot is +@item -boot [a|c|d] +Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is the default. @item -snapshot @@ -498,19 +217,9 @@ the write back by pressing @key{C-a s} (@xref{disk_images}). @item -m megs Set virtual RAM size to @var{megs} megabytes. -@item -n script -Set network init script [default=/etc/qemu-ifup]. This script is -launched to configure the host network interface (usually tun0) -corresponding to the virtual NE2000 card. - @item -initrd file Use @var{file} as initial ram disk. -@item -tun-fd fd -Assumes @var{fd} talks to tap/tun and use it. Read -@url{http://bellard.org/qemu/tetrinet.html} to have an example of its -use. - @item -nographic Normally, QEMU uses SDL to display the VGA output. With this option, @@ -521,7 +230,35 @@ with a serial console. @end table -Linux boot specific (does not require a full PC boot with a BIOS): +Network options: + +@table @option + +@item -n script +Set network init script [default=/etc/qemu-ifup]. This script is +launched to configure the host network interface (usually tun0) +corresponding to the virtual NE2000 card. + +@item nics n +Simulate @var{n} network interfaces (default=1). + +@item -macaddr addr + +Set the mac address of the first interface (the format is +aa:bb:cc:dd:ee:ff in hexa). The mac address is incremented for each +new network interface. + +@item -tun-fd fd1,... +Assumes @var{fd} talks to tap/tun and use it. Read +@url{http://bellard.org/qemu/tetrinet.html} to have an example of its +use. + +@end table + +Linux boot specific. When using this options, you can use a given +Linux kernel without installing it in the disk image. It can be useful +for easier testing of various kernels. + @table @option @item -kernel bzImage @@ -545,7 +282,8 @@ Change gdb connection port. Output log in /tmp/qemu.log @end table -During emulation, use @key{C-a h} to get terminal commands: +During emulation, if you are using the serial console, use @key{C-a h} +to get terminal commands: @table @key @item C-a h @@ -555,7 +293,9 @@ Exit emulatior @item C-a s Save disk data back to file (if -snapshot) @item C-a b -Send break (magic sysrq) +Send break (magic sysrq in Linux) +@item C-a c +Switch between console and monitor @item C-a C-a Send C-a @end table @@ -566,18 +306,165 @@ Send C-a @setfilename qemu @settitle QEMU System Emulator -@c man begin SEEALSO -The HTML documentation of QEMU for more precise information and Linux -user mode emulator invocation. -@c man end +@c man begin SEEALSO +The HTML documentation of QEMU for more precise information and Linux +user mode emulator invocation. +@c man end + +@c man begin AUTHOR +Fabrice Bellard +@c man end + +@end ignore + +@end ignore + + +@section QEMU Monitor + +The QEMU monitor is used to give complex commands to the QEMU +emulator. You can use it to: + +@itemize @minus + +@item +Remove or insert removable medias images +(such as CD-ROM or floppies) + +@item +Freeze/unfreeze the Virtual Machine (VM) and save or restore its state +from a disk file. + +@item Inspect the VM state without an external debugger. + +@end itemize + +@subsection Commands + +The following commands are available: + +@table @option + +@item help or ? [cmd] +Show the help for all commands or just for command @var{cmd}. + +@item commit +Commit changes to the disk images (if -snapshot is used) + +@item info subcommand +show various information about the system state + +@table @option +@item info network +show the network state +@item info block +show the block devices +@item info registers +show the cpu registers +@item info history +show the command line history +@end table + +@item q or quit +Quit the emulator. + +@item eject [-f] device +Eject a removable media (use -f to force it). + +@item change device filename +Change a removable media. + +@item screendump filename +Save screen into PPM image @var{filename}. + +@item log item1[,...] +Activate logging of the specified items to @file{/tmp/qemu.log}. + +@item savevm filename +Save the whole virtual machine state to @var{filename}. + +@item loadvm filename +Restore the whole virtual machine state from @var{filename}. + +@item stop +Stop emulation. + +@item c or cont +Resume emulation. + +@item gdbserver [port] +Start gdbserver session (default port=1234) + +@item x/fmt addr +Virtual memory dump starting at @var{addr}. + +@item xp /fmt addr +Physical memory dump starting at @var{addr}. + +@var{fmt} is a format which tells the command how to format the +data. Its syntax is: @option{/@{count@}@{format@}@{size@}} + +@table @var +@item count +is the number of items to be dumped. + +@item format +can be x (hexa), d (signed decimal), u (unsigned decimal), o (octal), +c (char) or i (asm instruction). + +@item size +can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits) + +@end table + +Examples: +@itemize +@item +Dump 10 instructions at the current instruction pointer: +@example +(qemu) x/10i $eip +0x90107063: ret +0x90107064: sti +0x90107065: lea 0x0(%esi,1),%esi +0x90107069: lea 0x0(%edi,1),%edi +0x90107070: ret +0x90107071: jmp 0x90107080 +0x90107073: nop +0x90107074: nop +0x90107075: nop +0x90107076: nop +@end example + +@item +Dump 80 16 bit values at the start of the video memory. +@example +(qemu) xp/80hx 0xb8000 +0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42 +0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41 +0x000b8020: 0x0b42 0x0b69 0x0b6f 0x0b73 0x0b20 0x0b63 0x0b75 0x0b72 +0x000b8030: 0x0b72 0x0b65 0x0b6e 0x0b74 0x0b2d 0x0b63 0x0b76 0x0b73 +0x000b8040: 0x0b20 0x0b30 0x0b35 0x0b20 0x0b4e 0x0b6f 0x0b76 0x0b20 +0x000b8050: 0x0b32 0x0b30 0x0b30 0x0b33 0x0720 0x0720 0x0720 0x0720 +0x000b8060: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 +0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 +0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 +0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 +@end example +@end itemize + +@item p or print/fmt expr + +Print expression value. Only the @var{format} part of @var{fmt} is +used. -@c man begin AUTHOR -Fabrice Bellard -@c man end +@end table -@end ignore +@subsection Integer expressions + +The monitor understands integers expressions for every integer +argument. You can use register names to get the value of specifics +CPU registers by prefixing them with @emph{$}. -@end ignore @node disk_images @section Disk Images @@ -649,13 +536,166 @@ Since holes are used, the displayed size of the COW disk image is not the real one. To know it, use the @code{ls -ls} command. @end enumerate +@section Direct Linux Boot and Network emulation + +This section explains how to launch a Linux kernel inside QEMU without +having to make a full bootable image. It is very useful for fast Linux +kernel testing. The QEMU network configuration is also explained. + +@enumerate +@item +Download the archive @file{linux-test-xxx.tar.gz} containing a Linux +kernel and a disk image. + +@item Optional: If you want network support (for example to launch X11 examples), you +must copy the script @file{qemu-ifup} in @file{/etc} and configure +properly @code{sudo} so that the command @code{ifconfig} contained in +@file{qemu-ifup} can be executed as root. You must verify that your host +kernel supports the TUN/TAP network interfaces: the device +@file{/dev/net/tun} must be present. + +When network is enabled, there is a virtual network connection between +the host kernel and the emulated kernel. The emulated kernel is seen +from the host kernel at IP address 172.20.0.2 and the host kernel is +seen from the emulated kernel at IP address 172.20.0.1. + +@item Launch @code{qemu.sh}. You should have the following output: + +@example +> ./qemu.sh +Connected to host network interface: tun0 +Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 +BIOS-provided physical RAM map: + BIOS-e801: 0000000000000000 - 000000000009f000 (usable) + BIOS-e801: 0000000000100000 - 0000000002000000 (usable) +32MB LOWMEM available. +On node 0 totalpages: 8192 +zone(0): 4096 pages. +zone(1): 4096 pages. +zone(2): 0 pages. +Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe console=ttyS0 +ide_setup: ide2=noprobe +ide_setup: ide3=noprobe +ide_setup: ide4=noprobe +ide_setup: ide5=noprobe +Initializing CPU#0 +Detected 2399.621 MHz processor. +Console: colour EGA 80x25 +Calibrating delay loop... 4744.80 BogoMIPS +Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, 0k highmem) +Dentry cache hash table entries: 4096 (order: 3, 32768 bytes) +Inode cache hash table entries: 2048 (order: 2, 16384 bytes) +Mount cache hash table entries: 512 (order: 0, 4096 bytes) +Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes) +Page-cache hash table entries: 8192 (order: 3, 32768 bytes) +CPU: Intel Pentium Pro stepping 03 +Checking 'hlt' instruction... OK. +POSIX conformance testing by UNIFIX +Linux NET4.0 for Linux 2.4 +Based upon Swansea University Computer Society NET3.039 +Initializing RT netlink socket +apm: BIOS not found. +Starting kswapd +Journalled Block Device driver loaded +Detected PS/2 Mouse Port. +pty: 256 Unix98 ptys configured +Serial driver version 5.05c (2001-07-08) with no serial options enabled +ttyS00 at 0x03f8 (irq = 4) is a 16450 +ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com) +Last modified Nov 1, 2000 by Paul Gortmaker +NE*000 ethercard probe at 0x300: 52 54 00 12 34 56 +eth0: NE2000 found at 0x300, using IRQ 9. +RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize +Uniform Multi-Platform E-IDE driver Revision: 7.00beta4-2.4 +ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx +hda: QEMU HARDDISK, ATA DISK drive +ide0 at 0x1f0-0x1f7,0x3f6 on irq 14 +hda: attached ide-disk driver. +hda: 20480 sectors (10 MB) w/256KiB Cache, CHS=20/16/63 +Partition check: + hda: +Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996 +NET4: Linux TCP/IP 1.0 for NET4.0 +IP Protocols: ICMP, UDP, TCP, IGMP +IP: routing cache hash table of 512 buckets, 4Kbytes +TCP: Hash tables configured (established 2048 bind 4096) +NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. +EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended +VFS: Mounted root (ext2 filesystem). +Freeing unused kernel memory: 64k freed + +Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 + +QEMU Linux test distribution (based on Redhat 9) + +Type 'exit' to halt the system + +sh-2.05b# +@end example + +@item +Then you can play with the kernel inside the virtual serial console. You +can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help +about the keys you can type inside the virtual serial console. In +particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as +the Magic SysRq key. + +@item +If the network is enabled, launch the script @file{/etc/linuxrc} in the +emulator (don't forget the leading dot): +@example +. /etc/linuxrc +@end example + +Then enable X11 connections on your PC from the emulated Linux: +@example +xhost +172.20.0.2 +@end example + +You can now launch @file{xterm} or @file{xlogo} and verify that you have +a real Virtual Linux system ! + +@end enumerate + +NOTES: +@enumerate +@item +A 2.5.74 kernel is also included in the archive. Just +replace the bzImage in qemu.sh to try it. + +@item +qemu-fast creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the +default) containing all the simulated PC memory. If possible, try to use +a temporary directory using the tmpfs filesystem to avoid too many +unnecessary disk accesses. + +@item +In order to exit cleanly from qemu, you can do a @emph{shutdown} inside +qemu. qemu will automatically exit when the Linux shutdown is done. + +@item +You can boot slightly faster by disabling the probe of non present IDE +interfaces. To do so, add the following options on the kernel command +line: +@example +ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe +@end example + +@item +The example disk image is a modified version of the one made by Kevin +Lawton for the plex86 Project (@url{www.plex86.org}). + +@end enumerate + @node linux_compile @section Linux Kernel Compilation You can use any linux kernel with QEMU. However, if you want to use -@code{qemu-fast} to get maximum performances, you should make the -following changes to the Linux kernel (only 2.4.x and 2.5.x were -tested): +@code{qemu-fast} to get maximum performances, you must use a modified +guest kernel. If you are using a 2.6 guest kernel, you can use +directly the patch @file{linux-2.6-qemu-fast.patch} made by Rusty +Russel available in the QEMU source archive. Otherwise, you can make the +following changes @emph{by hand} to the Linux kernel: @enumerate @item @@ -694,10 +734,10 @@ by use an SMP kernel with QEMU, it only supports one CPU. @item -If you are not using a 2.5 kernel as host kernel but if you use a target -2.5 kernel, you must also ensure that the 'HZ' define is set to 100 +If you are not using a 2.6 kernel as host kernel but if you use a target +2.6 kernel, you must also ensure that the 'HZ' define is set to 100 (1000 is the default) as QEMU cannot currently emulate timers at -frequencies greater than 100 Hz on host Linux systems < 2.5. In +frequencies greater than 100 Hz on host Linux systems < 2.6. In @file{include/asm/param.h}, replace: @example @@ -762,322 +802,104 @@ Use @code{set architecture i8086} to dump 16 bit code. Then use @code{x/10i $cs*16+*eip} to dump the code at the PC position. @end enumerate -@chapter QEMU Internals - -@section QEMU compared to other emulators - -Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than -bochs as it uses dynamic compilation and because it uses the host MMU to -simulate the x86 MMU. The downside is that currently the emulation is -not as accurate as bochs (for example, you cannot currently run Windows -inside QEMU). - -Like Valgrind [2], QEMU does user space emulation and dynamic -translation. Valgrind is mainly a memory debugger while QEMU has no -support for it (QEMU could be used to detect out of bound memory -accesses as Valgrind, but it has no support to track uninitialised data -as Valgrind does). The Valgrind dynamic translator generates better code -than QEMU (in particular it does register allocation) but it is closely -tied to an x86 host and target and has no support for precise exceptions -and system emulation. - -EM86 [4] is the closest project to user space QEMU (and QEMU still uses -some of its code, in particular the ELF file loader). EM86 was limited -to an alpha host and used a proprietary and slow interpreter (the -interpreter part of the FX!32 Digital Win32 code translator [5]). - -TWIN [6] is a Windows API emulator like Wine. It is less accurate than -Wine but includes a protected mode x86 interpreter to launch x86 Windows -executables. Such an approach as greater potential because most of the -Windows API is executed natively but it is far more difficult to develop -because all the data structures and function parameters exchanged -between the API and the x86 code must be converted. - -User mode Linux [7] was the only solution before QEMU to launch a Linux -kernel as a process while not needing any host kernel patches. However, -user mode Linux requires heavy kernel patches while QEMU accepts -unpatched Linux kernels. It would be interesting to compare the -performance of the two approaches. - -The new Plex86 [8] PC virtualizer is done in the same spirit as the QEMU -system emulator. It requires a patched Linux kernel to work (you cannot -launch the same kernel on your PC), but the patches are really small. As -it is a PC virtualizer (no emulation is done except for some priveledged -instructions), it has the potential of being faster than QEMU. The -downside is that a complicated (and potentially unsafe) host kernel -patch is needed. - -@section Portable dynamic translation - -QEMU is a dynamic translator. When it first encounters a piece of code, -it converts it to the host instruction set. Usually dynamic translators -are very complicated and highly CPU dependent. QEMU uses some tricks -which make it relatively easily portable and simple while achieving good -performances. - -The basic idea is to split every x86 instruction into fewer simpler -instructions. Each simple instruction is implemented by a piece of C -code (see @file{op-i386.c}). Then a compile time tool (@file{dyngen}) -takes the corresponding object file (@file{op-i386.o}) to generate a -dynamic code generator which concatenates the simple instructions to -build a function (see @file{op-i386.h:dyngen_code()}). - -In essence, the process is similar to [1], but more work is done at -compile time. - -A key idea to get optimal performances is that constant parameters can -be passed to the simple operations. For that purpose, dummy ELF -relocations are generated with gcc for each constant parameter. Then, -the tool (@file{dyngen}) can locate the relocations and generate the -appriopriate C code to resolve them when building the dynamic code. - -That way, QEMU is no more difficult to port than a dynamic linker. - -To go even faster, GCC static register variables are used to keep the -state of the virtual CPU. - -@section Register allocation - -Since QEMU uses fixed simple instructions, no efficient register -allocation can be done. However, because RISC CPUs have a lot of -register, most of the virtual CPU state can be put in registers without -doing complicated register allocation. - -@section Condition code optimisations - -Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a -critical point to get good performances. QEMU uses lazy condition code -evaluation: instead of computing the condition codes after each x86 -instruction, it just stores one operand (called @code{CC_SRC}), the -result (called @code{CC_DST}) and the type of operation (called -@code{CC_OP}). - -@code{CC_OP} is almost never explicitely set in the generated code -because it is known at translation time. - -In order to increase performances, a backward pass is performed on the -generated simple instructions (see -@code{translate-i386.c:optimize_flags()}). When it can be proved that -the condition codes are not needed by the next instructions, no -condition codes are computed at all. - -@section CPU state optimisations - -The x86 CPU has many internal states which change the way it evaluates -instructions. In order to achieve a good speed, the translation phase -considers that some state information of the virtual x86 CPU cannot -change in it. For example, if the SS, DS and ES segments have a zero -base, then the translator does not even generate an addition for the -segment base. - -[The FPU stack pointer register is not handled that way yet]. - -@section Translation cache - -A 2MByte cache holds the most recently used translations. For -simplicity, it is completely flushed when it is full. A translation unit -contains just a single basic block (a block of x86 instructions -terminated by a jump or by a virtual CPU state change which the -translator cannot deduce statically). - -@section Direct block chaining - -After each translated basic block is executed, QEMU uses the simulated -Program Counter (PC) and other cpu state informations (such as the CS -segment base value) to find the next basic block. - -In order to accelerate the most common cases where the new simulated PC -is known, QEMU can patch a basic block so that it jumps directly to the -next one. - -The most portable code uses an indirect jump. An indirect jump makes it -easier to make the jump target modification atomic. On some -architectures (such as PowerPC), the @code{JUMP} opcode is directly -patched so that the block chaining has no overhead. - -@section Self-modifying code and translated code invalidation - -Self-modifying code is a special challenge in x86 emulation because no -instruction cache invalidation is signaled by the application when code -is modified. - -When translated code is generated for a basic block, the corresponding -host page is write protected if it is not already read-only (with the -system call @code{mprotect()}). Then, if a write access is done to the -page, Linux raises a SEGV signal. QEMU then invalidates all the -translated code in the page and enables write accesses to the page. - -Correct translated code invalidation is done efficiently by maintaining -a linked list of every translated block contained in a given page. Other -linked lists are also maintained to undo direct block chaining. - -Although the overhead of doing @code{mprotect()} calls is important, -most MSDOS programs can be emulated at reasonnable speed with QEMU and -DOSEMU. - -Note that QEMU also invalidates pages of translated code when it detects -that memory mappings are modified with @code{mmap()} or @code{munmap()}. - -@section Exception support - -longjmp() is used when an exception such as division by zero is -encountered. - -The host SIGSEGV and SIGBUS signal handlers are used to get invalid -memory accesses. The exact CPU state can be retrieved because all the -x86 registers are stored in fixed host registers. The simulated program -counter is found by retranslating the corresponding basic block and by -looking where the host program counter was at the exception point. - -The virtual CPU cannot retrieve the exact @code{EFLAGS} register because -in some cases it is not computed because of condition code -optimisations. It is not a big concern because the emulated code can -still be restarted in any cases. - -@section Linux system call translation - -QEMU includes a generic system call translator for Linux. It means that -the parameters of the system calls can be converted to fix the -endianness and 32/64 bit issues. The IOCTLs are converted with a generic -type description system (see @file{ioctls.h} and @file{thunk.c}). +@chapter QEMU User space emulator invocation -QEMU supports host CPUs which have pages bigger than 4KB. It records all -the mappings the process does and try to emulated the @code{mmap()} -system calls in cases where the host @code{mmap()} call would fail -because of bad page alignment. +@section Quick Start -@section Linux signals +In order to launch a Linux process, QEMU needs the process executable +itself and all the target (x86) dynamic libraries used by it. -Normal and real-time signals are queued along with their information -(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt -request is done to the virtual CPU. When it is interrupted, one queued -signal is handled by generating a stack frame in the virtual CPU as the -Linux kernel does. The @code{sigreturn()} system call is emulated to return -from the virtual signal handler. +@itemize -Some signals (such as SIGALRM) directly come from the host. Other -signals are synthetized from the virtual CPU exceptions such as SIGFPE -when a division by zero is done (see @code{main.c:cpu_loop()}). +@item On x86, you can just try to launch any process by using the native +libraries: -The blocked signal mask is still handled by the host Linux kernel so -that most signal system calls can be redirected directly to the host -Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system -calls need to be fully emulated (see @file{signal.c}). +@example +qemu-i386 -L / /bin/ls +@end example -@section clone() system call and threads +@code{-L /} tells that the x86 dynamic linker must be searched with a +@file{/} prefix. -The Linux clone() system call is usually used to create a thread. QEMU -uses the host clone() system call so that real host threads are created -for each emulated thread. One virtual CPU instance is created for each -thread. +@item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources): -The virtual x86 CPU atomic operations are emulated with a global lock so -that their semantic is preserved. +@example +qemu-i386 -L / qemu-i386 -L / /bin/ls +@end example -Note that currently there are still some locking issues in QEMU. In -particular, the translated cache flush is not protected yet against -reentrancy. +@item On non x86 CPUs, you need first to download at least an x86 glibc +(@file{qemu-runtime-i386-XXX-.tar.gz} on the QEMU web page). Ensure that +@code{LD_LIBRARY_PATH} is not set: -@section Self-virtualization +@example +unset LD_LIBRARY_PATH +@end example -QEMU was conceived so that ultimately it can emulate itself. Although -it is not very useful, it is an important test to show the power of the -emulator. +Then you can launch the precompiled @file{ls} x86 executable: -Achieving self-virtualization is not easy because there may be address -space conflicts. QEMU solves this problem by being an executable ELF -shared object as the ld-linux.so ELF interpreter. That way, it can be -relocated at load time. +@example +qemu-i386 tests/i386/ls +@end example +You can look at @file{qemu-binfmt-conf.sh} so that +QEMU is automatically launched by the Linux kernel when you try to +launch x86 executables. It requires the @code{binfmt_misc} module in the +Linux kernel. -@section MMU emulation +@item The x86 version of QEMU is also included. You can try weird things such as: +@example +qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386 +@end example -For system emulation, QEMU uses the mmap() system call to emulate the -target CPU MMU. It works as long the emulated OS does not use an area -reserved by the host OS (such as the area above 0xc0000000 on x86 -Linux). +@end itemize -It is planned to add a slower but more precise MMU emulation -with a software MMU. +@section Wine launch -@section Bibliography +@itemize -@table @asis +@item Ensure that you have a working QEMU with the x86 glibc +distribution (see previous section). In order to verify it, you must be +able to do: -@item [1] -@url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing -direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio -Riccardi. +@example +qemu-i386 /usr/local/qemu-i386/bin/ls-i386 +@end example -@item [2] -@url{http://developer.kde.org/~sewardj/}, Valgrind, an open-source -memory debugger for x86-GNU/Linux, by Julian Seward. +@item Download the binary x86 Wine install +(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page). -@item [3] -@url{http://bochs.sourceforge.net/}, the Bochs IA-32 Emulator Project, -by Kevin Lawton et al. +@item Configure Wine on your account. Look at the provided script +@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous +@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}. -@item [4] -@url{http://www.cs.rose-hulman.edu/~donaldlf/em86/index.html}, the EM86 -x86 emulator on Alpha-Linux. +@item Then you can try the example @file{putty.exe}: -@item [5] -@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/full_papers/chernoff/chernoff.pdf}, -DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton -Chernoff and Ray Hookway. +@example +qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe +@end example -@item [6] -@url{http://www.willows.com/}, Windows API library emulation from -Willows Software. +@end itemize -@item [7] -@url{http://user-mode-linux.sourceforge.net/}, -The User-mode Linux Kernel. +@section Command line options -@item [8] -@url{http://www.plex86.org/}, -The new Plex86 project. +@example +usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] +@end example +@table @option +@item -h +Print the help +@item -L path +Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) +@item -s size +Set the x86 stack size in bytes (default=524288) @end table -@chapter Regression Tests - -In the directory @file{tests/}, various interesting testing programs -are available. There are used for regression testing. - -@section @file{test-i386} - -This program executes most of the 16 bit and 32 bit x86 instructions and -generates a text output. It can be compared with the output obtained with -a real CPU or another emulator. The target @code{make test} runs this -program and a @code{diff} on the generated output. - -The Linux system call @code{modify_ldt()} is used to create x86 selectors -to test some 16 bit addressing and 32 bit with segmentation cases. - -The Linux system call @code{vm86()} is used to test vm86 emulation. - -Various exceptions are raised to test most of the x86 user space -exception reporting. - -@section @file{linux-test} - -This program tests various Linux system calls. It is used to verify -that the system call parameters are correctly converted between target -and host CPUs. - -@section @file{hello-i386} - -Very simple statically linked x86 program, just to test QEMU during a -port to a new host CPU. - -@section @file{hello-arm} - -Very simple statically linked ARM program, just to test QEMU during a -port to a new host CPU. - -@section @file{sha1} +Debug options: -It is a simple benchmark. Care must be taken to interpret the results -because it mostly tests the ability of the virtual CPU to optimize the -@code{rol} x86 instruction and the condition code computations. +@table @option +@item -d +Activate log (logfile=/tmp/qemu.log) +@item -p pagesize +Act as if the host page size was 'pagesize' bytes +@end table diff --git a/qemu-tech.texi b/qemu-tech.texi new file mode 100644 index 000000000..018593475 --- /dev/null +++ b/qemu-tech.texi @@ -0,0 +1,506 @@ +\input texinfo @c -*- texinfo -*- + +@iftex +@settitle QEMU Internals +@titlepage +@sp 7 +@center @titlefont{QEMU Internals} +@sp 3 +@end titlepage +@end iftex + +@chapter Introduction + +@section Features + +QEMU is a FAST! processor emulator using a portable dynamic +translator. + +QEMU has two operating modes: + +@itemize @minus + +@item +Full system emulation. In this mode, QEMU emulates a full system +(usually a PC), including a processor and various peripherials. It can +be used to launch an different Operating System without rebooting the +PC or to debug system code. + +@item +User mode emulation (Linux host only). In this mode, QEMU can launch +Linux processes compiled for one CPU on another CPU. It can be used to +launch the Wine Windows API emulator (@url{http://www.winehq.org}) or +to ease cross-compilation and cross-debugging. + +@end itemize + +As QEMU requires no host kernel driver to run, it is very safe and +easy to use. + +QEMU generic features: + +@itemize + +@item User space only or full system emulation. + +@item Using dynamic translation to native code for reasonnable speed. + +@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390. + +@item Self-modifying code support. + +@item Precise exceptions support. + +@item The virtual CPU is a library (@code{libqemu}) which can be used +in other projects. + +@end itemize + +QEMU user mode emulation features: +@itemize +@item Generic Linux system call converter, including most ioctls. + +@item clone() emulation using native CPU clone() to use Linux scheduler for threads. + +@item Accurate signal handling by remapping host signals to target signals. +@end itemize +@end itemize + +QEMU full system emulation features: +@itemize +@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU. +@end itemize + +@section x86 emulation + +QEMU x86 target features: + +@itemize + +@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. +LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU. + +@item Support of host page sizes bigger than 4KB in user mode emulation. + +@item QEMU can emulate itself on x86. + +@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}. +It can be used to test other x86 virtual CPUs. + +@end itemize + +Current QEMU limitations: + +@itemize + +@item No SSE/MMX support (yet). + +@item No x86-64 support. + +@item IPC syscalls are missing. + +@item The x86 segment limits and access rights are not tested at every +memory access (yet). Hopefully, very few OSes seem to rely on that for +normal use. + +@item On non x86 host CPUs, @code{double}s are used instead of the non standard +10 byte @code{long double}s of x86 for floating point emulation to get +maximum performances. + +@end itemize + +@section ARM emulation + +@itemize + +@item Full ARM 7 user emulation. + +@item NWFPE FPU support included in user Linux emulation. + +@item Can run most ARM Linux binaries. + +@end itemize + +@section PowerPC emulation + +@itemize + +@item Full PowerPC 32 bit emulation, including priviledged instructions, +FPU and MMU. + +@item Can run most PowerPC Linux binaries. + +@end itemize + +@section SPARC emulation + +@itemize + +@item SPARC V8 user support, except FPU instructions. + +@item Can run some SPARC Linux binaries. + +@end itemize + +@chapter QEMU Internals + +@section QEMU compared to other emulators + +Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than +bochs as it uses dynamic compilation. Bochs is closely tied to x86 PC +emulation while QEMU can emulate several processors. + +Like Valgrind [2], QEMU does user space emulation and dynamic +translation. Valgrind is mainly a memory debugger while QEMU has no +support for it (QEMU could be used to detect out of bound memory +accesses as Valgrind, but it has no support to track uninitialised data +as Valgrind does). The Valgrind dynamic translator generates better code +than QEMU (in particular it does register allocation) but it is closely +tied to an x86 host and target and has no support for precise exceptions +and system emulation. + +EM86 [4] is the closest project to user space QEMU (and QEMU still uses +some of its code, in particular the ELF file loader). EM86 was limited +to an alpha host and used a proprietary and slow interpreter (the +interpreter part of the FX!32 Digital Win32 code translator [5]). + +TWIN [6] is a Windows API emulator like Wine. It is less accurate than +Wine but includes a protected mode x86 interpreter to launch x86 Windows +executables. Such an approach as greater potential because most of the +Windows API is executed natively but it is far more difficult to develop +because all the data structures and function parameters exchanged +between the API and the x86 code must be converted. + +User mode Linux [7] was the only solution before QEMU to launch a +Linux kernel as a process while not needing any host kernel +patches. However, user mode Linux requires heavy kernel patches while +QEMU accepts unpatched Linux kernels. The price to pay is that QEMU is +slower. + +The new Plex86 [8] PC virtualizer is done in the same spirit as the +qemu-fast system emulator. It requires a patched Linux kernel to work +(you cannot launch the same kernel on your PC), but the patches are +really small. As it is a PC virtualizer (no emulation is done except +for some priveledged instructions), it has the potential of being +faster than QEMU. The downside is that a complicated (and potentially +unsafe) host kernel patch is needed. + +The commercial PC Virtualizers (VMWare [9], VirtualPC [10], TwoOStwo +[11]) are faster than QEMU, but they all need specific, proprietary +and potentially unsafe host drivers. Moreover, they are unable to +provide cycle exact simulation as an emulator can. + +@section Portable dynamic translation + +QEMU is a dynamic translator. When it first encounters a piece of code, +it converts it to the host instruction set. Usually dynamic translators +are very complicated and highly CPU dependent. QEMU uses some tricks +which make it relatively easily portable and simple while achieving good +performances. + +The basic idea is to split every x86 instruction into fewer simpler +instructions. Each simple instruction is implemented by a piece of C +code (see @file{target-i386/op.c}). Then a compile time tool +(@file{dyngen}) takes the corresponding object file (@file{op.o}) +to generate a dynamic code generator which concatenates the simple +instructions to build a function (see @file{op.h:dyngen_code()}). + +In essence, the process is similar to [1], but more work is done at +compile time. + +A key idea to get optimal performances is that constant parameters can +be passed to the simple operations. For that purpose, dummy ELF +relocations are generated with gcc for each constant parameter. Then, +the tool (@file{dyngen}) can locate the relocations and generate the +appriopriate C code to resolve them when building the dynamic code. + +That way, QEMU is no more difficult to port than a dynamic linker. + +To go even faster, GCC static register variables are used to keep the +state of the virtual CPU. + +@section Register allocation + +Since QEMU uses fixed simple instructions, no efficient register +allocation can be done. However, because RISC CPUs have a lot of +register, most of the virtual CPU state can be put in registers without +doing complicated register allocation. + +@section Condition code optimisations + +Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a +critical point to get good performances. QEMU uses lazy condition code +evaluation: instead of computing the condition codes after each x86 +instruction, it just stores one operand (called @code{CC_SRC}), the +result (called @code{CC_DST}) and the type of operation (called +@code{CC_OP}). + +@code{CC_OP} is almost never explicitely set in the generated code +because it is known at translation time. + +In order to increase performances, a backward pass is performed on the +generated simple instructions (see +@code{target-i386/translate.c:optimize_flags()}). When it can be proved that +the condition codes are not needed by the next instructions, no +condition codes are computed at all. + +@section CPU state optimisations + +The x86 CPU has many internal states which change the way it evaluates +instructions. In order to achieve a good speed, the translation phase +considers that some state information of the virtual x86 CPU cannot +change in it. For example, if the SS, DS and ES segments have a zero +base, then the translator does not even generate an addition for the +segment base. + +[The FPU stack pointer register is not handled that way yet]. + +@section Translation cache + +A 2MByte cache holds the most recently used translations. For +simplicity, it is completely flushed when it is full. A translation unit +contains just a single basic block (a block of x86 instructions +terminated by a jump or by a virtual CPU state change which the +translator cannot deduce statically). + +@section Direct block chaining + +After each translated basic block is executed, QEMU uses the simulated +Program Counter (PC) and other cpu state informations (such as the CS +segment base value) to find the next basic block. + +In order to accelerate the most common cases where the new simulated PC +is known, QEMU can patch a basic block so that it jumps directly to the +next one. + +The most portable code uses an indirect jump. An indirect jump makes +it easier to make the jump target modification atomic. On some host +architectures (such as x86 or PowerPC), the @code{JUMP} opcode is +directly patched so that the block chaining has no overhead. + +@section Self-modifying code and translated code invalidation + +Self-modifying code is a special challenge in x86 emulation because no +instruction cache invalidation is signaled by the application when code +is modified. + +When translated code is generated for a basic block, the corresponding +host page is write protected if it is not already read-only (with the +system call @code{mprotect()}). Then, if a write access is done to the +page, Linux raises a SEGV signal. QEMU then invalidates all the +translated code in the page and enables write accesses to the page. + +Correct translated code invalidation is done efficiently by maintaining +a linked list of every translated block contained in a given page. Other +linked lists are also maintained to undo direct block chaining. + +Although the overhead of doing @code{mprotect()} calls is important, +most MSDOS programs can be emulated at reasonnable speed with QEMU and +DOSEMU. + +Note that QEMU also invalidates pages of translated code when it detects +that memory mappings are modified with @code{mmap()} or @code{munmap()}. + +When using a software MMU, the code invalidation is more efficient: if +a given code page is invalidated too often because of write accesses, +then a bitmap representing all the code inside the page is +built. Every store into that page checks the bitmap to see if the code +really needs to be invalidated. It avoids invalidating the code when +only data is modified in the page. + +@section Exception support + +longjmp() is used when an exception such as division by zero is +encountered. + +The host SIGSEGV and SIGBUS signal handlers are used to get invalid +memory accesses. The exact CPU state can be retrieved because all the +x86 registers are stored in fixed host registers. The simulated program +counter is found by retranslating the corresponding basic block and by +looking where the host program counter was at the exception point. + +The virtual CPU cannot retrieve the exact @code{EFLAGS} register because +in some cases it is not computed because of condition code +optimisations. It is not a big concern because the emulated code can +still be restarted in any cases. + +@section MMU emulation + +For system emulation, QEMU uses the mmap() system call to emulate the +target CPU MMU. It works as long the emulated OS does not use an area +reserved by the host OS (such as the area above 0xc0000000 on x86 +Linux). + +In order to be able to launch any OS, QEMU also supports a soft +MMU. In that mode, the MMU virtual to physical address translation is +done at every memory access. QEMU uses an address translation cache to +speed up the translation. + +In order to avoid flushing the translated code each time the MMU +mappings change, QEMU uses a physically indexed translation cache. It +means that each basic block is indexed with its physical address. + +When MMU mappings change, only the chaining of the basic blocks is +reset (i.e. a basic block can no longer jump directly to another one). + +@section Hardware interrupts + +In order to be faster, QEMU does not check at every basic block if an +hardware interrupt is pending. Instead, the user must asynchrously +call a specific function to tell that an interrupt is pending. This +function resets the chaining of the currently executing basic +block. It ensures that the execution will return soon in the main loop +of the CPU emulator. Then the main loop can test if the interrupt is +pending and handle it. + +@section User emulation specific details + +@subsection Linux system call translation + +QEMU includes a generic system call translator for Linux. It means that +the parameters of the system calls can be converted to fix the +endianness and 32/64 bit issues. The IOCTLs are converted with a generic +type description system (see @file{ioctls.h} and @file{thunk.c}). + +QEMU supports host CPUs which have pages bigger than 4KB. It records all +the mappings the process does and try to emulated the @code{mmap()} +system calls in cases where the host @code{mmap()} call would fail +because of bad page alignment. + +@subsection Linux signals + +Normal and real-time signals are queued along with their information +(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt +request is done to the virtual CPU. When it is interrupted, one queued +signal is handled by generating a stack frame in the virtual CPU as the +Linux kernel does. The @code{sigreturn()} system call is emulated to return +from the virtual signal handler. + +Some signals (such as SIGALRM) directly come from the host. Other +signals are synthetized from the virtual CPU exceptions such as SIGFPE +when a division by zero is done (see @code{main.c:cpu_loop()}). + +The blocked signal mask is still handled by the host Linux kernel so +that most signal system calls can be redirected directly to the host +Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system +calls need to be fully emulated (see @file{signal.c}). + +@subsection clone() system call and threads + +The Linux clone() system call is usually used to create a thread. QEMU +uses the host clone() system call so that real host threads are created +for each emulated thread. One virtual CPU instance is created for each +thread. + +The virtual x86 CPU atomic operations are emulated with a global lock so +that their semantic is preserved. + +Note that currently there are still some locking issues in QEMU. In +particular, the translated cache flush is not protected yet against +reentrancy. + +@subsection Self-virtualization + +QEMU was conceived so that ultimately it can emulate itself. Although +it is not very useful, it is an important test to show the power of the +emulator. + +Achieving self-virtualization is not easy because there may be address +space conflicts. QEMU solves this problem by being an executable ELF +shared object as the ld-linux.so ELF interpreter. That way, it can be +relocated at load time. + +@section Bibliography + +@table @asis + +@item [1] +@url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing +direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio +Riccardi. + +@item [2] +@url{http://developer.kde.org/~sewardj/}, Valgrind, an open-source +memory debugger for x86-GNU/Linux, by Julian Seward. + +@item [3] +@url{http://bochs.sourceforge.net/}, the Bochs IA-32 Emulator Project, +by Kevin Lawton et al. + +@item [4] +@url{http://www.cs.rose-hulman.edu/~donaldlf/em86/index.html}, the EM86 +x86 emulator on Alpha-Linux. + +@item [5] +@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/full_papers/chernoff/chernoff.pdf}, +DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton +Chernoff and Ray Hookway. + +@item [6] +@url{http://www.willows.com/}, Windows API library emulation from +Willows Software. + +@item [7] +@url{http://user-mode-linux.sourceforge.net/}, +The User-mode Linux Kernel. + +@item [8] +@url{http://www.plex86.org/}, +The new Plex86 project. + +@item [9] +@url{http://www.vmware.com/}, +The VMWare PC virtualizer. + +@item [10] +@url{http://www.microsoft.com/windowsxp/virtualpc/}, +The VirtualPC PC virtualizer. + +@item [11] +@url{http://www.twoostwo.org/}, +The TwoOStwo PC virtualizer. + +@end table + +@chapter Regression Tests + +In the directory @file{tests/}, various interesting testing programs +are available. There are used for regression testing. + +@section @file{test-i386} + +This program executes most of the 16 bit and 32 bit x86 instructions and +generates a text output. It can be compared with the output obtained with +a real CPU or another emulator. The target @code{make test} runs this +program and a @code{diff} on the generated output. + +The Linux system call @code{modify_ldt()} is used to create x86 selectors +to test some 16 bit addressing and 32 bit with segmentation cases. + +The Linux system call @code{vm86()} is used to test vm86 emulation. + +Various exceptions are raised to test most of the x86 user space +exception reporting. + +@section @file{linux-test} + +This program tests various Linux system calls. It is used to verify +that the system call parameters are correctly converted between target +and host CPUs. + +@section @file{hello-i386} + +Very simple statically linked x86 program, just to test QEMU during a +port to a new host CPU. + +@section @file{hello-arm} + +Very simple statically linked ARM program, just to test QEMU during a +port to a new host CPU. + +@section @file{sha1} + +It is a simple benchmark. Care must be taken to interpret the results +because it mostly tests the ability of the virtual CPU to optimize the +@code{rol} x86 instruction and the condition code computations. + -- cgit v1.2.3 From 73332e5ccdc760c9f0861dd8528dd7702afce088 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Apr 2004 20:22:28 +0000 Subject: qemu fast fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@706 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 54 ++++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/vl.c b/vl.c index 3af8a0ee7..1e1b5e3e6 100644 --- a/vl.c +++ b/vl.c @@ -52,6 +52,17 @@ #define memalign(align, size) malloc(size) #endif +#ifdef CONFIG_SDL +/* SDL use the pthreads and they modify sigaction. We don't + want that. */ +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) +extern void __libc_sigaction(); +#define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact) +#else +extern void __sigaction(); +#define sigaction(sig, act, oact) __sigaction(sig, act, oact) +#endif +#endif /* CONFIG_SDL */ #include "disas.h" @@ -1544,7 +1555,7 @@ int main_loop(void) } ioh->max_size = max_size; } - + ret = poll(ufds, pf - ufds, timeout); if (ret > 0) { /* XXX: better handling of removal */ @@ -1669,18 +1680,6 @@ struct option long_options[] = { { NULL, 0, NULL, 0 }, }; -#ifdef CONFIG_SDL -/* SDL use the pthreads and they modify sigaction. We don't - want that. */ -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) -extern void __libc_sigaction(); -#define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact) -#else -extern void __sigaction(); -#define sigaction(sig, act, oact) __sigaction(sig, act, oact) -#endif -#endif /* CONFIG_SDL */ - #if defined (TARGET_I386) && defined(USE_CODE_COPY) /* this stack is only used during signal handling */ @@ -2045,8 +2044,6 @@ int main(int argc, char **argv) } } - init_timers(); - /* init CPU state */ env = cpu_init(); global_env = env; @@ -2070,25 +2067,13 @@ int main(int argc, char **argv) #endif } -#if defined(TARGET_I386) - pc_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, initrd_filename); -#elif defined(TARGET_PPC) - ppc_init(); -#endif - - /* launched after the device init so that it can display or not a - banner */ - monitor_init(); - /* setup cpu signal handlers for MMU / self modifying code handling */ #if !defined(CONFIG_SOFTMMU) #if defined (TARGET_I386) && defined(USE_CODE_COPY) { stack_t stk; - signal_stack = malloc(SIGNAL_STACK_SIZE); + signal_stack = memalign(16, SIGNAL_STACK_SIZE); stk.ss_sp = signal_stack; stk.ss_size = SIGNAL_STACK_SIZE; stk.ss_flags = 0; @@ -2125,6 +2110,19 @@ int main(int argc, char **argv) sigaction(SIGPIPE, &act, NULL); } #endif + init_timers(); + +#if defined(TARGET_I386) + pc_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); +#elif defined(TARGET_PPC) + ppc_init(); +#endif + + /* launched after the device init so that it can display or not a + banner */ + monitor_init(); gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); -- cgit v1.2.3 From 57c30724825ac4601da66562ebe56d3147275b47 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Apr 2004 20:36:29 +0000 Subject: fixing free git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@707 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osdep.c b/osdep.c index aa061a90a..83f5a77cc 100644 --- a/osdep.c +++ b/osdep.c @@ -235,6 +235,8 @@ void qemu_free(void *ptr) { MemoryBlock *mb; + if (!ptr) + return; mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE); mb->next = first_free_block; first_free_block = mb; -- cgit v1.2.3 From e1a237441dbe31873d6d9c7d9eee2f1653b5f9e8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Apr 2004 20:26:03 +0000 Subject: port 92 access git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@708 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index 5431a41ac..e62d56da1 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -177,6 +177,17 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) (dummy_refresh_clock << 4); } +static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) +{ + cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1); + /* XXX: bit 0 is fast reset */ +} + +static uint32_t ioport92_read(void *opaque, uint32_t addr) +{ + return ((cpu_single_env->a20_mask >> 20) & 1) << 1; +} + /***********************************************************/ /* Bochs BIOS debug ports */ @@ -355,6 +366,9 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); + register_ioport_read(0x92, 1, 1, ioport92_read, NULL); + register_ioport_write(0x92, 1, 1, ioport92_write, NULL); + pic_init(); pit_init(0x40, 0); -- cgit v1.2.3 From 38e205a25b8f34916a4d3fdb7aef7424745fdd5a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Apr 2004 19:29:17 +0000 Subject: win32: do not use all cpu time git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@709 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 1e1b5e3e6..84e869889 100644 --- a/vl.c +++ b/vl.c @@ -1529,7 +1529,11 @@ int main_loop(void) timeout = 10; } -#ifndef _WIN32 +#ifdef _WIN32 + if (timeout > 0) + Sleep(timeout); +#else + /* poll any events */ /* XXX: separate device handlers from system ones */ pf = ufds; -- cgit v1.2.3 From aaba6c1516ce3babd09e2324c7c7571332bb150c Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Apr 2004 19:30:16 +0000 Subject: win32: correct keycode remapping git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@710 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sdl.c b/sdl.c index f2dcfbc78..f283d86cd 100644 --- a/sdl.c +++ b/sdl.c @@ -127,11 +127,18 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) /* XXX: not portable, but avoids complicated mappings */ keycode = ev->keysym.scancode; +#ifdef _WIN32 + if (keycode < 97) { + /* nothing to do */ + } else +#else if (keycode < 9) { keycode = 0; } else if (keycode < 97) { keycode -= 8; /* just an offset */ - } else if (keycode < 158) { + } else +#endif + if (keycode < 158) { /* use conversion table */ keycode = x_keycode_to_pc_keycode[keycode - 97]; } else { -- cgit v1.2.3 From 9eb153f18f69306d8b729c34e9f267bcacfe07c5 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Apr 2004 22:43:01 +0000 Subject: dma clean up - added missing read accesses git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@711 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 149 +++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 61 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index 6c1bc6160..24e90c4e6 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -55,6 +55,7 @@ static struct dma_cont { uint8_t command; uint8_t mask; uint8_t flip_flop; + int dshift; struct dma_regs regs[4]; } dma_controllers[2]; @@ -73,76 +74,87 @@ enum { }; +static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0}; + static void write_page (void *opaque, uint32_t nport, uint32_t data) { + struct dma_cont *d = opaque; int ichan; - int ncont; - static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0}; - ncont = nport > 0x87; - ichan = channels[nport - 0x80 - (ncont << 3)]; + ichan = channels[nport & 7]; if (-1 == ichan) { log ("invalid channel %#x %#x\n", nport, data); return; } + d->regs[ichan].page = data; +} + +static uint32_t read_page (void *opaque, uint32_t nport) +{ + struct dma_cont *d = opaque; + int ichan; - dma_controllers[ncont].regs[ichan].page = data; + ichan = channels[nport & 7]; + + if (-1 == ichan) { + log ("invalid channel read %#x\n", nport); + return 0; + } + return d->regs[ichan].page; } -static void init_chan (int ncont, int ichan) +static inline void init_chan (struct dma_cont *d, int ichan) { struct dma_regs *r; - r = dma_controllers[ncont].regs + ichan; - r->now[ADDR] = r->base[0] << ncont; + r = d->regs + ichan; + r->now[ADDR] = r->base[0] << d->dshift; r->now[COUNT] = 0; } -static inline int getff (int ncont) +static inline int getff (struct dma_cont *d) { int ff; - ff = dma_controllers[ncont].flip_flop; - dma_controllers[ncont].flip_flop = !ff; + ff = d->flip_flop; + d->flip_flop = !ff; return ff; } static uint32_t read_chan (void *opaque, uint32_t nport) { - int ff; - int ncont, ichan, nreg; + struct dma_cont *d = opaque; + int ichan, nreg, iport, ff, val; struct dma_regs *r; - int val; - - ncont = nport > 7; - ichan = (nport >> (1 + ncont)) & 3; - nreg = (nport >> ncont) & 1; - r = dma_controllers[ncont].regs + ichan; - ff = getff (ncont); + iport = (nport >> d->dshift) & 0x0f; + ichan = iport >> 1; + nreg = iport & 1; + r = d->regs + ichan; + ff = getff (d); if (nreg) - val = (r->base[COUNT] << ncont) - r->now[COUNT]; + val = (r->base[COUNT] << d->dshift) - r->now[COUNT]; else val = r->now[ADDR] + r->now[COUNT]; - return (val >> (ncont + (ff << 3))) & 0xff; + return (val >> (d->dshift + (ff << 3))) & 0xff; } static void write_chan (void *opaque, uint32_t nport, uint32_t data) { - int ncont, ichan, nreg; + struct dma_cont *d = opaque; + int iport, ichan, nreg; struct dma_regs *r; - ncont = nport > 7; - ichan = (nport >> (1 + ncont)) & 3; - nreg = (nport >> ncont) & 1; - r = dma_controllers[ncont].regs + ichan; - - if (getff (ncont)) { + iport = (nport >> d->dshift) & 0x0f; + ichan = iport >> 1; + nreg = iport & 1; + r = d->regs + ichan; + if (getff (d)) { r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00); - init_chan (ncont, ichan); + init_chan (d, ichan); } else { r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff); } @@ -150,20 +162,10 @@ static void write_chan (void *opaque, uint32_t nport, uint32_t data) static void write_cont (void *opaque, uint32_t nport, uint32_t data) { - int iport, ichan, ncont; - struct dma_cont *d; - - ncont = nport > 0xf; - ichan = -1; - - d = dma_controllers + ncont; - if (ncont) { - iport = ((nport - 0xd0) >> 1) + 8; - } - else { - iport = nport; - } + struct dma_cont *d = opaque; + int iport, ichan; + iport = (nport >> d->dshift) & 0x0f; switch (iport) { case 8: /* command */ if (data && (data | CMD_NOT_SUPPORTED)) { @@ -239,8 +241,8 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) #ifdef DEBUG_DMA if (0xc != iport) { - linfo ("nport %#06x, ncont %d, ichan % 2d, val %#06x\n", - nport, d != dma_controllers, ichan, data); + linfo ("nport %#06x, ichan % 2d, val %#06x\n", + nport, ichan, data); } #endif return; @@ -249,6 +251,27 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) abort (); } +static uint32_t read_cont (void *opaque, uint32_t nport) +{ + struct dma_cont *d = opaque; + int iport, val; + + iport = (nport >> d->dshift) & 0x0f; + switch (iport) { + case 0x08: /* status */ + val = d->status; + d->status &= 0xf0; + break; + case 0x0f: /* mask */ + val = d->mask; + break; + default: + val = 0; + break; + } + return val; +} + int DMA_get_channel_mode (int nchan) { return dma_controllers[nchan > 3].regs[nchan & 3].mode; @@ -334,30 +357,34 @@ void DMA_schedule(int nchan) cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } -void DMA_init (void) +/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ +static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base) { + const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; int i; - int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; + d->dshift = dshift; for (i = 0; i < 8; i++) { - register_ioport_write (i, 1, 1, write_chan, NULL); - - register_ioport_write (0xc0 + (i << 1), 1, 1, write_chan, NULL); - - register_ioport_read (i, 1, 1, read_chan, NULL); - register_ioport_read (0xc0 + (i << 1), 1, 1, read_chan, NULL); + register_ioport_write (base + (i << dshift), 1, 1, write_chan, d); + register_ioport_read (base + (i << dshift), 1, 1, read_chan, d); } - for (i = 0; i < LENOFA (page_port_list); i++) { - register_ioport_write (page_port_list[i] + 0x80, 1, 1, write_page, NULL); - register_ioport_write (page_port_list[i] + 0x88, 1, 1, write_page, NULL); + register_ioport_write (page_base + page_port_list[i], 1, 1, + write_page, d); + register_ioport_read (page_base + page_port_list[i], 1, 1, + read_page, d); } - for (i = 0; i < 8; i++) { - register_ioport_write (i + 8, 1, 1, write_cont, NULL); - register_ioport_write (0xd0 + (i << 1), 1, 1, write_cont, NULL); + register_ioport_write (base + ((i + 8) << dshift), 1, 1, + write_cont, d); + register_ioport_read (base + ((i + 8) << dshift), 1, 1, + read_cont, d); } + write_cont (d, base + (0x0d << dshift), 0); +} - write_cont (NULL, 0x0d, 0); - write_cont (NULL, 0xda, 0); +void DMA_init (void) +{ + dma_init2(&dma_controllers[0], 0x00, 0, 0x80); + dma_init2(&dma_controllers[1], 0xc0, 1, 0x88); } -- cgit v1.2.3 From bb058620c3b6bbddb99c9afff956dded7139897b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Apr 2004 20:21:16 +0000 Subject: refuse write accesses in BIOS area (aka EMM386.EXE fix) (Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@712 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/pc.c b/hw/pc.c index e62d56da1..496f365e6 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -302,6 +302,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, /* setup basic memory access */ cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); + cpu_register_physical_memory(0xd0000, 0x20000, IO_MEM_UNASSIGNED); cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); bochs_bios_init(); -- cgit v1.2.3 From eccabc6ee0da82a3cb6037537c145fae08c23041 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Apr 2004 20:31:38 +0000 Subject: vga 9 pixel wide text char fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@713 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 4 ++-- hw/vga_template.h | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index ce1754f75..f05dd1c57 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1138,7 +1138,7 @@ static void vga_draw_text(VGAState *s, int full_update) /* total width & height */ cheight = (s->cr[9] & 0x1f) + 1; cw = 8; - if (s->sr[1] & 0x01) + if (!(s->sr[1] & 0x01)) cw = 9; if (s->sr[1] & 0x08) cw = 16; /* NOTE: no 18 pixel wide */ @@ -1154,7 +1154,7 @@ static void vga_draw_text(VGAState *s, int full_update) height = (height + 1) / cheight; } if (width != s->last_width || height != s->last_height || - cw != s->last_cw || cw != s->last_cw) { + cw != s->last_cw || cheight != s->last_ch) { dpy_resize(s->ds, width * cw, height * cheight); s->last_width = width; s->last_height = height; diff --git a/hw/vga_template.h b/hw/vga_template.h index 810b4b128..766257c09 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -127,14 +127,14 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, else ((uint16_t *)d)[8] = bgcol; #else - ((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; - v = ((-(font_data >> 0) & 1) & xorcol) ^ bgcol; + ((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; + v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; ((uint32_t *)d)[7] = v; if (dup9) ((uint32_t *)d)[8] = v; -- cgit v1.2.3 From 333190eb9790ad585a8c18cbb380c07db20f35b4 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Apr 2004 20:51:30 +0000 Subject: base memory size in cmos git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@714 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index 496f365e6..83e614bbb 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -76,6 +76,10 @@ static void cmos_init(int ram_size, int boot_device) /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ + val = 640; /* base memory in K */ + rtc_set_memory(s, 0x15, val); + rtc_set_memory(s, 0x16, val >> 8); + val = (ram_size / 1024) - 1024; if (val > 65535) val = 65535; -- cgit v1.2.3 From 52302d72748bd6c574bf2fd7c8be7f19d12db467 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Apr 2004 21:01:17 +0000 Subject: fix the no device case git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@715 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/serial.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index c40965956..3cf43f4d1 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -123,10 +123,12 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->lsr &= ~UART_LSR_THRE; serial_update_irq(s); - ch = val; - do { - ret = write(s->out_fd, &ch, 1); - } while (ret != 1); + if (s->out_fd >= 0) { + ch = val; + do { + ret = write(s->out_fd, &ch, 1); + } while (ret != 1); + } s->thr_ipending = 1; s->lsr |= UART_LSR_THRE; s->lsr |= UART_LSR_TEMT; @@ -267,7 +269,10 @@ SerialState *serial_init(int base, int irq, int fd) register_ioport_write(base, 8, 1, serial_ioport_write, s); register_ioport_read(base, 8, 1, serial_ioport_read, s); - if (fd != 0) { + if (fd < 0) { + /* no associated device */ + s->out_fd = -1; + } else if (fd != 0) { qemu_add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); s->out_fd = fd; } else { -- cgit v1.2.3 From 41b9be476c2dc17dfb5182a829873644e981f9bc Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Apr 2004 21:30:08 +0000 Subject: preserve partition table when using -linux option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@716 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index 83e614bbb..d0fcb0f4c 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -313,6 +313,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, if (linux_boot) { uint8_t bootsect[512]; + uint8_t old_bootsect[512]; if (bs_table[0] == NULL) { fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); @@ -326,6 +327,11 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, exit(1); } + if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) { + /* copy the MSDOS partition table */ + memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40); + } + bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); /* now we can load the kernel */ -- cgit v1.2.3 From 7ae9862745abb67789a34d4354cc738ab172b377 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Apr 2004 22:13:51 +0000 Subject: ide select logic fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@717 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 9ee446915..f5efa8eb1 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1078,8 +1078,8 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) ide_if[1].hcyl = val; break; case 6: - ide_if[0].select = val & 0x4f; - ide_if[1].select = val & 0x4f; + ide_if[0].select = (val & ~0x10) | 0xa0; + ide_if[1].select = (val | 0x10) | 0xa0; /* select drive */ unit = (val >> 4) & 1; s = ide_if + unit; @@ -1210,7 +1210,8 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) { - IDEState *s = ((IDEState *)opaque)->cur_drive; + IDEState *ide_if = opaque; + IDEState *s = ide_if->cur_drive; uint32_t addr; int ret; @@ -1220,44 +1221,44 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = 0xff; break; case 1: - if (!s->bs) + if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else ret = s->error; break; case 2: - if (!s->bs) + if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else ret = s->nsector & 0xff; break; case 3: - if (!s->bs) + if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else ret = s->sector; break; case 4: - if (!s->bs) + if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else ret = s->lcyl; break; case 5: - if (!s->bs) + if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else ret = s->hcyl; break; case 6: - if (!s->bs) + if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else - ret = s->select | 0xa0; + ret = s->select; break; default: case 7: - if (!s->bs) + if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; else ret = s->status; @@ -1272,9 +1273,14 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) static uint32_t ide_status_read(void *opaque, uint32_t addr) { - IDEState *s = ((IDEState *)opaque)->cur_drive; + IDEState *ide_if = opaque; + IDEState *s = ide_if->cur_drive; int ret; - ret = s->status; + + if (!ide_if[0].bs && !ide_if[1].bs) + ret = 0; + else + ret = s->status; #ifdef DEBUG_IDE printf("ide: read status addr=0x%x val=%02x\n", addr, ret); #endif -- cgit v1.2.3 From 289e09e77bc4d48dd79798232ecb88a30196c737 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Apr 2004 19:04:48 +0000 Subject: fixed keyboard random bug (Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@718 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index f9f633331..ae2cf27f1 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -290,9 +290,9 @@ static uint32_t kbd_read_data(void *opaque, uint32_t addr) KBDQueue *q; int val, index; - q = &s->queues[0]; /* first check KBD data */ + q = &s->queues[1]; /* first check AUX data */ if (q->count == 0) - q = &s->queues[1]; /* then check AUX data */ + q = &s->queues[0]; /* then check KBD data */ if (q->count == 0) { /* NOTE: if no data left, we return the last keyboard one (needed for EMM386) */ -- cgit v1.2.3 From fd836909df6cfbb046a6ca0eea92ca7402a83f4e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Apr 2004 14:54:42 +0000 Subject: VM86 EIP masking fix (aka NT5 install fix) (Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@719 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index d7cb6849b..7e0e777af 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1727,7 +1727,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) load_seg_vm(R_FS, new_fs & 0xffff); load_seg_vm(R_GS, new_gs & 0xffff); - env->eip = new_eip; + env->eip = new_eip & 0xffff; ESP = new_esp; } -- cgit v1.2.3 From 2f0c934ef9cc6f9bbce0326cdd7fe2f993288705 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Apr 2004 14:55:01 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@720 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Changelog b/Changelog index 6a6329c5b..cec682114 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,11 @@ +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) + version 0.5.3: - added Bochs VESA VBE support -- cgit v1.2.3 From df475d18d890572b8456ebff327bb9debee6289a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Apr 2004 19:07:27 +0000 Subject: fixed invalid command test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@721 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index 24e90c4e6..bac6d95df 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -168,9 +168,9 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) iport = (nport >> d->dshift) & 0x0f; switch (iport) { case 8: /* command */ - if (data && (data | CMD_NOT_SUPPORTED)) { + if ((data != 0) && (data & CMD_NOT_SUPPORTED)) { log ("command %#x not supported\n", data); - goto error; + return; } d->command = data; break; @@ -236,7 +236,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) default: log ("dma: unknown iport %#x\n", iport); - goto error; + break; } #ifdef DEBUG_DMA @@ -245,10 +245,6 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) nport, ichan, data); } #endif - return; - - error: - abort (); } static uint32_t read_cont (void *opaque, uint32_t nport) -- cgit v1.2.3 From a541f297a37e64673aac52abc858e0904e316b48 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Apr 2004 20:39:29 +0000 Subject: PowerPC system emulation fixes (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@722 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 25 +- configure | 2 +- cpu-exec.c | 2 +- exec-all.h | 6 + exec.c | 6 +- gdbstub.c | 61 +-- hw/fdc.c | 379 ++++++------------ hw/i8259.c | 2 +- hw/m48t59.c | 486 +++++++++++++++++++++++ hw/m48t59.h | 9 + hw/ne2000.c | 4 + hw/ppc.c | 42 ++ hw/ppc_prep.c | 1007 ++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/main.c | 13 +- linux-user/syscall.c | 2 + monitor.c | 100 +++++ target-ppc/cpu.h | 50 ++- target-ppc/exec.h | 5 + target-ppc/helper.c | 349 ++++++++--------- target-ppc/hw.c | 935 -------------------------------------------- target-ppc/op.c | 21 +- target-ppc/op_helper.c | 50 +-- target-ppc/translate.c | 48 ++- translate-all.c | 3 + vl.c | 25 +- 25 files changed, 2146 insertions(+), 1486 deletions(-) create mode 100644 hw/m48t59.c create mode 100644 hw/m48t59.h create mode 100644 hw/ppc.c create mode 100644 hw/ppc_prep.c delete mode 100644 target-ppc/hw.c diff --git a/Makefile.target b/Makefile.target index 9fe3e83ed..e9c0304ff 100644 --- a/Makefile.target +++ b/Makefile.target @@ -16,8 +16,12 @@ DYNGEN=../dyngen$(EXESUF) QEMU_USER=qemu-$(TARGET_ARCH) # system emulator name ifdef CONFIG_SOFTMMU +ifeq ($(TARGET_ARCH), i386) QEMU_SYSTEM=qemu$(EXESUF) else +QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF) +endif +else QEMU_SYSTEM=qemu-fast endif @@ -222,14 +226,23 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o \ - ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ - fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o -ifdef CONFIG_GDBSTUB -VL_OBJS+=gdbstub.o +VL_OBJS=vl.o osdep.o block.o monitor.o + +ifeq ($(TARGET_ARCH), i386) +# Hardware support +VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o endif ifeq ($(TARGET_ARCH), ppc) -VL_OBJS+= hw.o +# Generic PPC support +VL_OBJS+= ppc.o +# PREP hardware support +VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o +VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o ppc_prep.o +#VL_OBJS+= hw.o of.o setup.o +endif +ifdef CONFIG_GDBSTUB +VL_OBJS+=gdbstub.o endif ifdef CONFIG_SDL VL_OBJS+=sdl.o diff --git a/configure b/configure index a82cf2b4d..059648c49 100755 --- a/configure +++ b/configure @@ -27,7 +27,7 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user" +target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" diff --git a/cpu-exec.c b/cpu-exec.c index 9b049dc61..6307e0c16 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -190,7 +190,7 @@ int cpu_exec(CPUState *env1) (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; - intno = cpu_x86_get_pic_interrupt(env); + intno = cpu_get_pic_interrupt(env); if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); } diff --git a/exec-all.h b/exec-all.h index bc16be11a..934808f10 100644 --- a/exec-all.h +++ b/exec-all.h @@ -578,7 +578,13 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) #endif if (__builtin_expect(env->tlb_read[is_user][index].address != (addr & TARGET_PAGE_MASK), 0)) { +#if defined (TARGET_PPC) + env->access_type = ACCESS_CODE; + ldub_code((void *)addr); + env->access_type = ACCESS_INT; +#else ldub_code((void *)addr); +#endif } return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; } diff --git a/exec.c b/exec.c index 49cadcacd..6136bf7b9 100644 --- a/exec.c +++ b/exec.c @@ -914,7 +914,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) { -#if defined(TARGET_I386) +#if defined(TARGET_I386) || defined(TARGET_PPC) int i; for(i = 0; i < env->nb_breakpoints; i++) { @@ -935,7 +935,7 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) /* remove a breakpoint */ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) { -#if defined(TARGET_I386) +#if defined(TARGET_I386) || defined(TARGET_PPC) int i; for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) @@ -957,7 +957,7 @@ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) CPU loop after each instruction */ void cpu_single_step(CPUState *env, int enabled) { -#if defined(TARGET_I386) +#if defined(TARGET_I386) || defined(TARGET_PPC) if (env->singlestep_enabled != enabled) { env->singlestep_enabled = enabled; /* must flush all the translated code to avoid inconsistancies */ diff --git a/gdbstub.c b/gdbstub.c index 07652d1ae..3560b269b 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -220,42 +220,49 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } #elif defined (TARGET_PPC) -static void to_le32(uint8_t *p, int v) +static void to_le32(uint32_t *buf, uint32_t v) { + uint8_t *p = (uint8_t *)buf; p[3] = v; p[2] = v >> 8; p[1] = v >> 16; p[0] = v >> 24; } +static uint32_t from_le32 (uint32_t *buf) +{ + uint8_t *p = (uint8_t *)buf; + + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { - uint32_t tmp; + uint32_t *registers = (uint32_t *)mem_buf, tmp; int i; /* fill in gprs */ - for(i = 0; i < 8; i++) { - to_le32(mem_buf + i * 4, env->gpr[i]); + for(i = 0; i < 32; i++) { + to_le32(®isters[i], env->gpr[i]); } /* fill in fprs */ for (i = 0; i < 32; i++) { - to_le32(mem_buf + (i * 2) + 32, *((uint32_t *)&env->fpr[i])); - to_le32(mem_buf + (i * 2) + 33, *((uint32_t *)&env->fpr[i] + 1)); + to_le32(®isters[(i * 2) + 32], *((uint32_t *)&env->fpr[i])); + to_le32(®isters[(i * 2) + 33], *((uint32_t *)&env->fpr[i] + 1)); } /* nip, msr, ccr, lnk, ctr, xer, mq */ - to_le32(mem_buf + 96, tswapl(env->nip)); - to_le32(mem_buf + 97, tswapl(_load_msr())); - to_le32(mem_buf + 98, 0); + to_le32(®isters[96], (uint32_t)env->nip/* - 4*/); + to_le32(®isters[97], _load_msr(env)); tmp = 0; for (i = 0; i < 8; i++) - tmp |= env->crf[i] << (32 - (i * 4)); - to_le32(mem_buf + 98, tmp); - to_le32(mem_buf + 99, tswapl(env->lr)); - to_le32(mem_buf + 100, tswapl(env->ctr)); - to_le32(mem_buf + 101, tswapl(_load_xer())); - to_le32(mem_buf + 102, 0); - - return 102; + tmp |= env->crf[i] << (32 - ((i + 1) * 4)); + to_le32(®isters[98], tmp); + to_le32(®isters[99], env->lr); + to_le32(®isters[100], env->ctr); + to_le32(®isters[101], _load_xer(env)); + to_le32(®isters[102], 0); + + return 103 * 4; } static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) @@ -265,22 +272,22 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) /* fill in gprs */ for (i = 0; i < 32; i++) { - env->gpr[i] = tswapl(registers[i]); + env->gpr[i] = from_le32(®isters[i]); } /* fill in fprs */ for (i = 0; i < 32; i++) { - *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]); - *((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]); + *((uint32_t *)&env->fpr[i]) = from_le32(®isters[(i * 2) + 32]); + *((uint32_t *)&env->fpr[i] + 1) = from_le32(®isters[(i * 2) + 33]); } /* nip, msr, ccr, lnk, ctr, xer, mq */ - env->nip = tswapl(registers[96]); - _store_msr(tswapl(registers[97])); - registers[98] = tswapl(registers[98]); + env->nip = from_le32(®isters[96]); + _store_msr(env, from_le32(®isters[97])); + registers[98] = from_le32(®isters[98]); for (i = 0; i < 8; i++) - env->crf[i] = (registers[98] >> (32 - (i * 4))) & 0xF; - env->lr = tswapl(registers[99]); - env->ctr = tswapl(registers[100]); - _store_xer(tswapl(registers[101])); + env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; + env->lr = from_le32(®isters[99]); + env->ctr = from_le32(®isters[100]); + _store_xer(env, from_le32(®isters[101])); } #else diff --git a/hw/fdc.c b/hw/fdc.c index 7d7837b99..0de5578bb 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -83,7 +83,6 @@ typedef struct fdrive_t { uint8_t dir; /* Direction */ uint8_t rw; /* Read/write */ /* Media */ - fdisk_type_t disk; /* Disk type */ fdisk_flags_t flags; uint8_t last_sect; /* Nb sector per track */ uint8_t max_track; /* Nb of tracks */ @@ -102,7 +101,6 @@ static void fd_init (fdrive_t *drv, BlockDriverState *bs) drv->drflags = 0; drv->perpendicular = 0; /* Disk */ - drv->disk = FDRIVE_DISK_NONE; drv->last_sect = 0; drv->max_track = 0; } @@ -171,26 +169,113 @@ static void fd_recalibrate (fdrive_t *drv) drv->rw = 0; } +/* Recognize floppy formats */ +typedef struct fd_format_t { + fdrive_type_t drive; + fdisk_type_t disk; + uint8_t last_sect; + uint8_t max_track; + uint8_t max_head; + const unsigned char *str; +} fd_format_t; + +static fd_format_t fd_formats[] = { + /* First entry is default format */ + /* 1.44 MB 3"1/2 floppy disks */ + { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", }, + /* 2.88 MB 3"1/2 floppy disks */ + { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", }, + { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", }, + { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", }, + { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", }, + { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", }, + /* 720 kB 3"1/2 floppy disks */ + { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", }, + { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", }, + /* 1.2 MB 5"1/4 floppy disks */ + { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", }, + /* 720 kB 5"1/4 floppy disks */ + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", }, + /* 360 kB 5"1/4 floppy disks */ + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", }, + /* 320 kB 5"1/4 floppy disks */ + { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", }, + { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", }, + /* 360 kB must match 5"1/4 better than 3"1/2... */ + { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", }, + /* end */ + { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, }, +}; + /* Revalidate a disk drive after a disk change */ static void fd_revalidate (fdrive_t *drv) { - int64_t nb_sectors; + fd_format_t *parse; + int64_t nb_sectors, size; + int i, first_match, match; int nb_heads, max_track, last_sect, ro; FLOPPY_DPRINTF("revalidate\n"); drv->drflags &= ~FDRIVE_REVALIDATE; - - /* if no drive present, cannot do more */ - if (!drv->bs) - return; - - if (bdrv_is_inserted(drv->bs)) { + if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { ro = bdrv_is_read_only(drv->bs); - bdrv_get_geometry_hint(drv->bs, &max_track, &nb_heads, &last_sect); + bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect); if (nb_heads != 0 && max_track != 0 && last_sect != 0) { - drv->disk = FDRIVE_DISK_USER; printf("User defined disk (%d %d %d)", nb_heads - 1, max_track, last_sect); + } else { + bdrv_get_geometry(drv->bs, &nb_sectors); + match = -1; + first_match = -1; + for (i = 0;; i++) { + parse = &fd_formats[i]; + if (parse->drive == FDRIVE_DRV_NONE) + break; + if (drv->drive == parse->drive || + drv->drive == FDRIVE_DRV_NONE) { + size = (parse->max_head + 1) * parse->max_track * + parse->last_sect; + if (nb_sectors == size) { + match = i; + break; + } + if (first_match == -1) + first_match = i; + } + } + if (match == -1) { + if (first_match == -1) + match = 1; + else + match = first_match; + parse = &fd_formats[match]; + } + nb_heads = parse->max_head + 1; + max_track = parse->max_track; + last_sect = parse->last_sect; + drv->drive = parse->drive; + printf("%s floppy disk (%d h %d t %d s) %s\n", parse->str, + nb_heads, max_track, last_sect, ro ? "ro" : "rw"); + } if (nb_heads == 1) { drv->flags &= ~FDISK_DBL_SIDES; } else { @@ -198,236 +283,9 @@ static void fd_revalidate (fdrive_t *drv) } drv->max_track = max_track; drv->last_sect = last_sect; - } else { - bdrv_get_geometry(drv->bs, &nb_sectors); - switch (nb_sectors) { - /* 2.88 MB 3"1/2 drive disks */ - case 7680: - printf("3.84 Mb 3\"1/2 disk (1 80 48)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 48; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 7040: - printf("3.52 Mb 3\"1/2 disk (1 80 44)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 44; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 6400: - printf("3.2 Mb 3\"1/2 disk (1 80 40)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 40; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 6240: - printf("3.12 Mb 3\"1/2 disk (1 80 39)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 39; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 5760: - printf("2.88 Mb 3\"1/2 disk (1 80 36)"); - drv->drive = FDRIVE_DRV_288; - drv->disk = FDRIVE_DISK_288; - drv->last_sect = 36; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - /* 1.44 MB 3"1/2 drive disks */ - case 3840: - printf("1.92 Mb 3\"1/2 disk (1 80 24)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 24; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3680: - printf("1.84 Mb 3\"1/2 disk (1 80 23)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 23; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3520: - printf("1.76 Mb 3\"1/2 disk (1 80 22)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 22; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3486: - printf("1.74 Mb 3\"1/2 disk (1 83 21)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 21; - drv->max_track = 83; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3444: - printf("1.72 Mb 3\"1/2 disk (1 82 21)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 21; - drv->max_track = 82; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3360: - printf("1.68 Mb 3\"1/2 disk (1 80 21)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 21; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 3200: - printf("1.6 Mb 3\"1/2 disk (1 80 20)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 20; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 2880: - default: - printf("1.44 Mb 3\"1/2 disk (1 80 18)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_144; - drv->last_sect = 18; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - /* 720 kB 3"1/2 drive disks */ - case 2240: - printf("1.12 Mb 3\"1/2 disk (1 80 14)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 14; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 2080: - printf("1.04 Mb 3\"1/2 disk (1 80 13)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 13; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 1660: - printf("830 kb 3\"1/2 disk (1 83 10)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 10; - drv->max_track = 83; - drv->flags |= FDISK_DBL_SIDES; - break; - case 1640: - printf("820 kb 3\"1/2 disk (1 82 10)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 10; - drv->max_track = 82; - drv->flags |= FDISK_DBL_SIDES; - break; - case 1600: - printf("800 kb 3\"1/2 disk (1 80 10)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 10; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - case 1440: - printf("720 kb 3\"1/2 disk (1 80 9)"); - drv->drive = FDRIVE_DRV_144; - drv->disk = FDRIVE_DISK_720; - drv->last_sect = 9; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - /* 1.2 MB 5"1/4 drive disks */ - case 2988: - printf("1.49 Mb 5\"1/4 disk (1 83 18)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 18; - drv->max_track = 83; - drv->flags |= FDISK_DBL_SIDES; - break; - case 2952: - printf("1.48 Mb 5\"1/4 disk (1 82 18)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 18; - drv->max_track = 82; - drv->flags |= FDISK_DBL_SIDES; - break; - case 2400: - printf("1.2 Mb 5\"1/4 disk (1 80 15)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 15; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - case 1760: - printf("880 kb 5\"1/4 disk (1 80 11)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 11; - drv->max_track = 80; - drv->flags |= FDISK_DBL_SIDES; - break; - - /* 360 kB 5"1/4 drive disks */ - case 840: - /* 420 kB 5"1/4 disk */ - printf("420 kb 5\"1/4 disk (1 42 10)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 10; - drv->max_track = 42; - drv->flags |= FDISK_DBL_SIDES; - case 820: - /* 410 kB 5"1/4 disk */ - printf("410 kb 5\"1/4 disk (1 41 10)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 10; - drv->max_track = 41; - drv->flags |= FDISK_DBL_SIDES; - case 720: - /* 360 kB 5"1/4 disk */ - printf("360 kb 5\"1/4 disk (1 40 9)"); - drv->drive = FDRIVE_DRV_120; - drv->disk = FDRIVE_DISK_144; /* ? */ - drv->last_sect = 9; - drv->max_track = 40; - drv->flags |= FDISK_DBL_SIDES; - break; - } - printf(" %s\n", ro == 0 ? "rw" : "ro"); - } drv->ro = ro; } else { printf("No disk in drive\n"); - drv->disk = FDRIVE_DISK_NONE; drv->last_sect = 0; drv->max_track = 0; drv->flags &= ~FDISK_DBL_SIDES; @@ -544,20 +402,29 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) fdctrl_t *fdctrl = opaque; uint32_t retval; - if (reg == fdctrl->io_base + 0x01) + switch (reg & 0x07) { + case 0x01: retval = fdctrl_read_statusB(fdctrl); - else if (reg == fdctrl->io_base + 0x02) + break; + case 0x02: retval = fdctrl_read_dor(fdctrl); - else if (reg == fdctrl->io_base + 0x03) + break; + case 0x03: retval = fdctrl_read_tape(fdctrl); - else if (reg == fdctrl->io_base + 0x04) + break; + case 0x04: retval = fdctrl_read_main_status(fdctrl); - else if (reg == fdctrl->io_base + 0x05) + break; + case 0x05: retval = fdctrl_read_data(fdctrl); - else if (reg == fdctrl->io_base + 0x07) + break; + case 0x07: retval = fdctrl_read_dir(fdctrl); - else + break; + default: retval = (uint32_t)(-1); + break; + } return retval; } @@ -566,14 +433,22 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) { fdctrl_t *fdctrl = opaque; - if (reg == fdctrl->io_base + 0x02) + switch (reg & 0x07) { + case 0x02: fdctrl_write_dor(fdctrl, value); - else if (reg == fdctrl->io_base + 0x03) + break; + case 0x03: fdctrl_write_tape(fdctrl, value); - else if (reg == fdctrl->io_base + 0x04) + break; + case 0x04: fdctrl_write_rate(fdctrl, value); - else if (reg == fdctrl->io_base + 0x05) + break; + case 0x05: fdctrl_write_data(fdctrl, value); + break; + default: + break; + } } static void fd_change_cb (void *opaque) @@ -581,7 +456,6 @@ static void fd_change_cb (void *opaque) fdrive_t *drv = opaque; FLOPPY_DPRINTF("disk change\n"); - /* TODO: use command-line parameters to force geometry */ fd_revalidate(drv); #if 0 fd_recalibrate(drv); @@ -606,7 +480,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl->irq_lvl = irq_lvl; fdctrl->dma_chann = dma_chann; fdctrl->io_base = io_base; - fdctrl->config = 0x40; /* Implicit seek, polling & FIFO enabled */ + fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */ if (fdctrl->dma_chann != -1) { fdctrl->dma_en = 1; DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl); @@ -634,9 +508,10 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl); register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl); } - for (i = 0; i < MAX_FD; i++) { + for (i = 0; i < 2; i++) { fd_revalidate(&fdctrl->drives[i]); } + return fdctrl; } diff --git a/hw/i8259.c b/hw/i8259.c index 8fabaf765..adc9cedff 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -174,7 +174,7 @@ static inline void pic_intack(PicState *s, int irq) s->irr &= ~(1 << irq); } -int cpu_x86_get_pic_interrupt(CPUState *env) +int cpu_get_pic_interrupt(CPUState *env) { int irq, irq2, intno; diff --git a/hw/m48t59.c b/hw/m48t59.c new file mode 100644 index 000000000..fbee94fa6 --- /dev/null +++ b/hw/m48t59.c @@ -0,0 +1,486 @@ +/* + * QEMU M48T59 NVRAM emulation for PPC PREP platform + * + * Copyright (c) 2003-2004 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include /* needed by vl.h */ +#include +#include +#include + +#include "vl.h" + +//#define NVRAM_DEBUG + +#if defined(NVRAM_DEBUG) +#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) +#else +#define NVRAM_PRINTF(fmt, args...) do { } while (0) +#endif + +typedef struct m48t59_t { + /* Hardware parameters */ + int IRQ; + uint32_t io_base; + uint16_t size; + /* RTC management */ + time_t time_offset; + time_t stop_time; + /* Alarm & watchdog */ + time_t alarm; + struct QEMUTimer *alrm_timer; + struct QEMUTimer *wd_timer; + /* NVRAM storage */ + uint16_t addr; + uint8_t *buffer; +} m48t59_t; + +static m48t59_t *NVRAMs; +static int nb_NVRAMs; + +/* Fake timer functions */ +/* Generic helpers for BCD */ +static inline uint8_t toBCD (uint8_t value) +{ + return (((value / 10) % 10) << 4) | (value % 10); +} + +static inline uint8_t fromBCD (uint8_t BCD) +{ + return ((BCD >> 4) * 10) + (BCD & 0x0F); +} + +/* RTC management helpers */ +static void get_time (m48t59_t *NVRAM, struct tm *tm) +{ + time_t t; + + t = time(NULL) + NVRAM->time_offset; + localtime_r(&t, tm); +} + +static void set_time (m48t59_t *NVRAM, struct tm *tm) +{ + time_t now, new_time; + + new_time = mktime(tm); + now = time(NULL); + NVRAM->time_offset = new_time - now; +} + +/* Alarm management */ +static void alarm_cb (void *opaque) +{ + struct tm tm, tm_now; + uint64_t next_time; + m48t59_t *NVRAM = opaque; + + pic_set_irq(NVRAM->IRQ, 1); + if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && + (NVRAM->buffer[0x1FF4] & 0x80) == 0 && + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { + /* Repeat once a month */ + get_time(NVRAM, &tm_now); + memcpy(&tm, &tm_now, sizeof(struct tm)); + tm.tm_mon++; + if (tm.tm_mon == 13) { + tm.tm_mon = 1; + tm.tm_year++; + } + next_time = mktime(&tm); + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && + (NVRAM->buffer[0x1FF4] & 0x80) == 0 && + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { + /* Repeat once a day */ + next_time = 24 * 60 * 60 + mktime(&tm_now); + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && + (NVRAM->buffer[0x1FF4] & 0x80) != 0 && + (NVRAM->buffer[0x1FF3] & 0x80) == 0 && + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { + /* Repeat once an hour */ + next_time = 60 * 60 + mktime(&tm_now); + } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && + (NVRAM->buffer[0x1FF4] & 0x80) != 0 && + (NVRAM->buffer[0x1FF3] & 0x80) != 0 && + (NVRAM->buffer[0x1FF2] & 0x80) == 0) { + /* Repeat once a minute */ + next_time = 60 + mktime(&tm_now); + } else { + /* Repeat once a second */ + next_time = 1 + mktime(&tm_now); + } + qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); + pic_set_irq(NVRAM->IRQ, 0); +} + + +static void get_alarm (m48t59_t *NVRAM, struct tm *tm) +{ + localtime_r(&NVRAM->alarm, tm); +} + +static void set_alarm (m48t59_t *NVRAM, struct tm *tm) +{ + NVRAM->alarm = mktime(tm); + if (NVRAM->alrm_timer != NULL) { + qemu_del_timer(NVRAM->alrm_timer); + NVRAM->alrm_timer = NULL; + } + if (NVRAM->alarm - time(NULL) > 0) + qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); +} + +/* Watchdog management */ +static void watchdog_cb (void *opaque) +{ + m48t59_t *NVRAM = opaque; + + NVRAM->buffer[0x1FF0] |= 0x80; + if (NVRAM->buffer[0x1FF7] & 0x80) { + NVRAM->buffer[0x1FF7] = 0x00; + NVRAM->buffer[0x1FFC] &= ~0x40; + // reset_CPU(); + } else { + pic_set_irq(NVRAM->IRQ, 1); + pic_set_irq(NVRAM->IRQ, 0); + } +} + +static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) +{ + uint64_t interval; /* in 1/16 seconds */ + + if (NVRAM->wd_timer != NULL) { + qemu_del_timer(NVRAM->wd_timer); + NVRAM->wd_timer = NULL; + } + NVRAM->buffer[0x1FF0] &= ~0x80; + if (value != 0) { + interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); + qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + + ((interval * 1000) >> 4)); + } +} + +/* Direct access to NVRAM */ +void m48t59_write (void *opaque, uint32_t val) +{ + m48t59_t *NVRAM = opaque; + struct tm tm; + int tmp; + + if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000) + NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); + switch (NVRAM->addr) { + case 0x1FF0: + /* flags register : read-only */ + break; + case 0x1FF1: + /* unused */ + break; + case 0x1FF2: + /* alarm seconds */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_alarm(NVRAM, &tm); + tm.tm_sec = tmp; + NVRAM->buffer[0x1FF2] = val; + set_alarm(NVRAM, &tm); + } + break; + case 0x1FF3: + /* alarm minutes */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_alarm(NVRAM, &tm); + tm.tm_min = tmp; + NVRAM->buffer[0x1FF3] = val; + set_alarm(NVRAM, &tm); + } + break; + case 0x1FF4: + /* alarm hours */ + tmp = fromBCD(val & 0x3F); + if (tmp >= 0 && tmp <= 23) { + get_alarm(NVRAM, &tm); + tm.tm_hour = tmp; + NVRAM->buffer[0x1FF4] = val; + set_alarm(NVRAM, &tm); + } + break; + case 0x1FF5: + /* alarm date */ + tmp = fromBCD(val & 0x1F); + if (tmp != 0) { + get_alarm(NVRAM, &tm); + tm.tm_mday = tmp; + NVRAM->buffer[0x1FF5] = val; + set_alarm(NVRAM, &tm); + } + break; + case 0x1FF6: + /* interrupts */ + NVRAM->buffer[0x1FF6] = val; + break; + case 0x1FF7: + /* watchdog */ + NVRAM->buffer[0x1FF7] = val; + set_up_watchdog(NVRAM, val); + break; + case 0x1FF8: + /* control */ + NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; + break; + case 0x1FF9: + /* seconds (BCD) */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_time(NVRAM, &tm); + tm.tm_sec = tmp; + set_time(NVRAM, &tm); + } + if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) { + if (val & 0x80) { + NVRAM->stop_time = time(NULL); + } else { + NVRAM->time_offset += NVRAM->stop_time - time(NULL); + NVRAM->stop_time = 0; + } + } + NVRAM->buffer[0x1FF9] = val & 0x80; + break; + case 0x1FFA: + /* minutes (BCD) */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_time(NVRAM, &tm); + tm.tm_min = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFB: + /* hours (BCD) */ + tmp = fromBCD(val & 0x3F); + if (tmp >= 0 && tmp <= 23) { + get_time(NVRAM, &tm); + tm.tm_hour = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFC: + /* day of the week / century */ + tmp = fromBCD(val & 0x07); + get_time(NVRAM, &tm); + tm.tm_wday = tmp; + set_time(NVRAM, &tm); + NVRAM->buffer[0x1FFC] = val & 0x40; + break; + case 0x1FFD: + /* date */ + tmp = fromBCD(val & 0x1F); + if (tmp != 0) { + get_time(NVRAM, &tm); + tm.tm_mday = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFE: + /* month */ + tmp = fromBCD(val & 0x1F); + if (tmp >= 1 && tmp <= 12) { + get_time(NVRAM, &tm); + tm.tm_mon = tmp - 1; + set_time(NVRAM, &tm); + } + break; + case 0x1FFF: + /* year */ + tmp = fromBCD(val); + if (tmp >= 0 && tmp <= 99) { + get_time(NVRAM, &tm); + tm.tm_year = fromBCD(val); + set_time(NVRAM, &tm); + } + break; + default: + if (NVRAM->addr < 0x1FF0 || + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { + NVRAM->buffer[NVRAM->addr] = val & 0xFF; + } + break; + } +} + +uint32_t m48t59_read (void *opaque) +{ + m48t59_t *NVRAM = opaque; + struct tm tm; + uint32_t retval = 0xFF; + + switch (NVRAM->addr) { + case 0x1FF0: + /* flags register */ + goto do_read; + case 0x1FF1: + /* unused */ + retval = 0; + break; + case 0x1FF2: + /* alarm seconds */ + goto do_read; + case 0x1FF3: + /* alarm minutes */ + goto do_read; + case 0x1FF4: + /* alarm hours */ + goto do_read; + case 0x1FF5: + /* alarm date */ + goto do_read; + case 0x1FF6: + /* interrupts */ + goto do_read; + case 0x1FF7: + /* A read resets the watchdog */ + set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]); + goto do_read; + case 0x1FF8: + /* control */ + goto do_read; + case 0x1FF9: + /* seconds (BCD) */ + get_time(NVRAM, &tm); + retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec); + break; + case 0x1FFA: + /* minutes (BCD) */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_min); + break; + case 0x1FFB: + /* hours (BCD) */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_hour); + break; + case 0x1FFC: + /* day of the week / century */ + get_time(NVRAM, &tm); + retval = NVRAM->buffer[0x1FFC] | tm.tm_wday; + break; + case 0x1FFD: + /* date */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_mday); + break; + case 0x1FFE: + /* month */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_mon + 1); + break; + case 0x1FFF: + /* year */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_year); + break; + default: + if (NVRAM->addr < 0x1FF0 || + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { + do_read: + retval = NVRAM->buffer[NVRAM->addr]; + } + break; + } + if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000) + NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); + + return retval; +} + +void m48t59_set_addr (void *opaque, uint32_t addr) +{ + m48t59_t *NVRAM = opaque; + + NVRAM->addr = addr; +} + +/* IO access to NVRAM */ +static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) +{ + m48t59_t *NVRAM = opaque; + + addr -= NVRAM->io_base; + switch (addr) { + case 0: + NVRAM->addr &= ~0x00FF; + NVRAM->addr |= val; + break; + case 1: + NVRAM->addr &= ~0xFF00; + NVRAM->addr |= val << 8; + break; + case 3: + m48t59_write(NVRAM, val); + NVRAM->addr = 0x0000; + break; + default: + break; + } +} + +static uint32_t NVRAM_readb (void *opaque, uint32_t addr) +{ + m48t59_t *NVRAM = opaque; + + if (addr == NVRAM->io_base + 3) + return m48t59_read(NVRAM); + + return 0xFF; +} + +/* Initialisation routine */ +void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) +{ + m48t59_t *tmp; + + tmp = realloc(NVRAMs, (nb_NVRAMs + 1) * sizeof(m48t59_t)); + if (tmp == NULL) + return NULL; + NVRAMs = tmp; + tmp[nb_NVRAMs].buffer = malloc(size); + if (tmp[nb_NVRAMs].buffer == NULL) + return NULL; + memset(tmp[nb_NVRAMs].buffer, 0, size); + tmp[nb_NVRAMs].IRQ = IRQ; + tmp[nb_NVRAMs].size = size; + tmp[nb_NVRAMs].io_base = io_base; + tmp[nb_NVRAMs].addr = 0; + register_ioport_read(io_base, 0x04, 1, NVRAM_readb, &NVRAMs[nb_NVRAMs]); + register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, &NVRAMs[nb_NVRAMs]); + tmp[nb_NVRAMs].alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, + &tmp[nb_NVRAMs]); + tmp[nb_NVRAMs].wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, + &tmp[nb_NVRAMs]); + return &NVRAMs[nb_NVRAMs++]; +} diff --git a/hw/m48t59.h b/hw/m48t59.h new file mode 100644 index 000000000..f73846d98 --- /dev/null +++ b/hw/m48t59.h @@ -0,0 +1,9 @@ +#if !defined (__M48T59_H__) +#define __M48T59_H__ + +void m48t59_write (void *opaque, uint32_t val); +uint32_t m48t59_read (void *opaque); +void m48t59_set_addr (void *opaque, uint32_t addr); +void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size); + +#endif /* !defined (__M48T59_H__) */ diff --git a/hw/ne2000.c b/hw/ne2000.c index 63edf0352..e9ad6f9f8 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -146,6 +146,10 @@ static void ne2000_update_irq(NE2000State *s) { int isr; isr = s->isr & s->imr; +#if defined(DEBUG_NE2000) + printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n", + s->irq, isr ? 1 : 0, s->isr, s->imr); +#endif if (isr) pic_set_irq(s->irq, 1); else diff --git a/hw/ppc.c b/hw/ppc.c new file mode 100644 index 000000000..cd485bc84 --- /dev/null +++ b/hw/ppc.c @@ -0,0 +1,42 @@ +/* + * QEMU generic PPC hardware System Emulator + * + * Copyright (c) 2003-2004 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "vl.h" + +void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + +void ppc_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + /* For now, only PREP is supported */ + return ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, + initrd_filename); +} diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c new file mode 100644 index 000000000..32b2ce805 --- /dev/null +++ b/hw/ppc_prep.c @@ -0,0 +1,1007 @@ +/* + * QEMU PPC PREP hardware System Emulator + * + * Copyright (c) 2003-2004 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "vl.h" +#include "m48t59.h" + +//#define HARD_DEBUG_PPC_IO +//#define DEBUG_PPC_IO + +extern int loglevel; +extern FILE *logfile; + +#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO) +#define DEBUG_PPC_IO +#endif + +#if defined (HARD_DEBUG_PPC_IO) +#define PPC_IO_DPRINTF(fmt, args...) \ +do { \ + if (loglevel > 0) { \ + fprintf(logfile, "%s: " fmt, __func__ , ##args); \ + } else { \ + printf("%s : " fmt, __func__ , ##args); \ + } \ +} while (0) +#elif defined (DEBUG_PPC_IO) +#define PPC_IO_DPRINTF(fmt, args...) \ +do { \ + if (loglevel > 0) { \ + fprintf(logfile, "%s: " fmt, __func__ , ##args); \ + } \ +} while (0) +#else +#define PPC_IO_DPRINTF(fmt, args...) do { } while (0) +#endif + +#define BIOS_FILENAME "ppc_rom.bin" +#define LINUX_BOOT_FILENAME "linux_boot.bin" + +#define KERNEL_LOAD_ADDR 0x00000000 +#define KERNEL_STACK_ADDR 0x00400000 +#define INITRD_LOAD_ADDR 0x00800000 + +int load_kernel(const char *filename, uint8_t *addr, + uint8_t *real_addr) +{ + int fd, size; + int setup_sects; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + + /* load 16 bit code */ + if (read(fd, real_addr, 512) != 512) + goto fail; + setup_sects = real_addr[0x1F1]; + if (!setup_sects) + setup_sects = 4; + if (read(fd, real_addr + 512, setup_sects * 512) != + setup_sects * 512) + goto fail; + + /* load 32 bit code */ + size = read(fd, addr, 16 * 1024 * 1024); + if (size < 0) + goto fail; + close(fd); + return size; + fail: + close(fd); + return -1; +} + +static const int ide_iobase[2] = { 0x1f0, 0x170 }; +static const int ide_iobase2[2] = { 0x3f6, 0x376 }; +static const int ide_irq[2] = { 13, 13 }; + +#define NE2000_NB_MAX 6 + +static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; +static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; + +/* IO ports emulation */ +#define PPC_IO_BASE 0x80000000 + +static void PPC_io_writeb (uint32_t addr, uint32_t value, uint32_t vaddr) +{ + /* Don't polute serial port output */ +#if 0 + if ((addr < 0x800003F0 || addr > 0x80000400) && + (addr < 0x80000074 || addr > 0x80000077) && + (addr < 0x80000020 || addr > 0x80000021) && + (addr < 0x800000a0 || addr > 0x800000a1) && + (addr < 0x800001f0 || addr > 0x800001f7) && + (addr < 0x80000170 || addr > 0x80000177)) +#endif + { + PPC_IO_DPRINTF("0x%08x => 0x%02x\n", addr - PPC_IO_BASE, value); + } + cpu_outb(NULL, addr - PPC_IO_BASE, value); +} + +static uint32_t PPC_io_readb (uint32_t addr) +{ + uint32_t ret = cpu_inb(NULL, addr - PPC_IO_BASE); + +#if 0 + if ((addr < 0x800003F0 || addr > 0x80000400) && + (addr < 0x80000074 || addr > 0x80000077) && + (addr < 0x80000020 || addr > 0x80000021) && + (addr < 0x800000a0 || addr > 0x800000a1) && + (addr < 0x800001f0 || addr > 0x800001f7) && + (addr < 0x80000170 || addr > 0x80000177) && + (addr < 0x8000060 || addr > 0x8000064)) +#endif + { + PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); + } + + return ret; +} + +static void PPC_io_writew (uint32_t addr, uint32_t value, uint32_t vaddr) +{ + if ((addr < 0x800001f0 || addr > 0x800001f7) && + (addr < 0x80000170 || addr > 0x80000177)) { + PPC_IO_DPRINTF("0x%08x => 0x%04x\n", addr - PPC_IO_BASE, value); + } + cpu_outw(NULL, addr - PPC_IO_BASE, value); +} + +static uint32_t PPC_io_readw (uint32_t addr) +{ + uint32_t ret = cpu_inw(NULL, addr - PPC_IO_BASE); + + if ((addr < 0x800001f0 || addr > 0x800001f7) && + (addr < 0x80000170 || addr > 0x80000177)) { + PPC_IO_DPRINTF("0x%08x <= 0x%04x\n", addr - PPC_IO_BASE, ret); + } + + return ret; +} + +static void PPC_io_writel (uint32_t addr, uint32_t value, uint32_t vaddr) +{ + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); + cpu_outl(NULL, addr - PPC_IO_BASE, value); +} + +static uint32_t PPC_io_readl (uint32_t addr) +{ + uint32_t ret = cpu_inl(NULL, addr - PPC_IO_BASE); + + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, ret); + + return ret; +} + +static CPUWriteMemoryFunc *PPC_io_write[] = { + &PPC_io_writeb, + &PPC_io_writew, + &PPC_io_writel, +}; + +static CPUReadMemoryFunc *PPC_io_read[] = { + &PPC_io_readb, + &PPC_io_readw, + &PPC_io_readl, +}; + +uint32_t pic_intack_read(CPUState *env); + +/* Read-only register (?) */ +static void _PPC_ioB_write (uint32_t addr, uint32_t value, uint32_t vaddr) +{ + // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); +} + +static uint32_t _PPC_ioB_read (uint32_t addr) +{ + uint32_t retval = 0; + + if (addr == 0xBFFFFFF0) + retval = pic_intack_read(NULL); + // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); + + return retval; +} + +static CPUWriteMemoryFunc *PPC_ioB_write[] = { + &_PPC_ioB_write, + &_PPC_ioB_write, + &_PPC_ioB_write, +}; + +static CPUReadMemoryFunc *PPC_ioB_read[] = { + &_PPC_ioB_read, + &_PPC_ioB_read, + &_PPC_ioB_read, +}; + +#if 0 +static CPUWriteMemoryFunc *PPC_io3_write[] = { + &PPC_io3_writeb, + &PPC_io3_writew, + &PPC_io3_writel, +}; + +static CPUReadMemoryFunc *PPC_io3_read[] = { + &PPC_io3_readb, + &PPC_io3_readw, + &PPC_io3_readl, +}; +#endif + +/* Fake super-io ports for PREP platform (Intel 82378ZB) */ +static uint8_t PREP_fake_io[2]; +static uint8_t NVRAM_lock; + +static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) +{ + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, val); + PREP_fake_io[addr - 0x0398] = val; +} + +static uint32_t PREP_io_read (void *opaque, uint32_t addr) +{ + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, PREP_fake_io[addr - 0x0398]); + return PREP_fake_io[addr - 0x0398]; +} + +static uint8_t syscontrol; + +static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) +{ + PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, val); + switch (addr) { + case 0x0092: + /* Special port 92 */ + /* Check soft reset asked */ + if (val & 0x80) { + printf("Soft reset asked... Stop emulation\n"); + abort(); + } + /* Check LE mode */ + if (val & 0x40) { + printf("Little Endian mode isn't supported (yet ?)\n"); + abort(); + } + break; + case 0x0808: + /* Hardfile light register: don't care */ + break; + case 0x0810: + /* Password protect 1 register */ + NVRAM_lock ^= 0x01; + break; + case 0x0812: + /* Password protect 2 register */ + NVRAM_lock ^= 0x02; + break; + case 0x0814: + /* L2 invalidate register: don't care */ + break; + case 0x081C: + /* system control register */ + syscontrol = val; + break; + case 0x0850: + /* I/O map type register */ + if (val & 0x80) { + printf("No support for non-continuous I/O map mode\n"); + abort(); + } + break; + default: + break; + } +} + +static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) +{ + uint32_t retval = 0xFF; + + switch (addr) { + case 0x0092: + /* Special port 92 */ + retval = 0x40; + break; + case 0x080C: + /* Equipment present register: + * no L2 cache + * no upgrade processor + * no cards in PCI slots + * SCSI fuse is bad + */ + retval = 0xFC; + break; + case 0x0818: + /* Keylock */ + retval = 0x00; + break; + case 0x081C: + /* system control register + * 7 - 6 / 1 - 0: L2 cache enable + */ + retval = syscontrol; + break; + case 0x0823: + /* */ + retval = 0x03; /* no L2 cache */ + break; + case 0x0850: + /* I/O map type register */ + retval = 0x00; + break; + default: + break; + } + PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, retval); + + return retval; +} + +#define NVRAM_SIZE 0x2000 +#define NVRAM_END 0x1FF0 +#define NVRAM_OSAREA_SIZE 512 +#define NVRAM_CONFSIZE 1024 + +static inline void NVRAM_set_byte (void *opaque, uint32_t addr, uint8_t value) +{ + m48t59_set_addr(opaque, addr); + m48t59_write(opaque, value); +} + +static inline uint8_t NVRAM_get_byte (void *opaque, uint32_t addr) +{ + m48t59_set_addr(opaque, addr); + return m48t59_read(opaque); +} + +static inline void NVRAM_set_word (void *opaque, uint32_t addr, uint16_t value) +{ + m48t59_set_addr(opaque, addr); + m48t59_write(opaque, value >> 8); + m48t59_set_addr(opaque, addr + 1); + m48t59_write(opaque, value & 0xFF); +} + +static inline uint16_t NVRAM_get_word (void *opaque, uint32_t addr) +{ + uint16_t tmp; + + m48t59_set_addr(opaque, addr); + tmp = m48t59_read(opaque) << 8; + m48t59_set_addr(opaque, addr + 1); + tmp |= m48t59_read(opaque); + + return tmp; +} + +static inline void NVRAM_set_lword (void *opaque, uint32_t addr, + uint32_t value) +{ + m48t59_set_addr(opaque, addr); + m48t59_write(opaque, value >> 24); + m48t59_set_addr(opaque, addr + 1); + m48t59_write(opaque, (value >> 16) & 0xFF); + m48t59_set_addr(opaque, addr + 2); + m48t59_write(opaque, (value >> 8) & 0xFF); + m48t59_set_addr(opaque, addr + 3); + m48t59_write(opaque, value & 0xFF); +} + +static inline uint32_t NVRAM_get_lword (void *opaque, uint32_t addr) +{ + uint32_t tmp; + + m48t59_set_addr(opaque, addr); + tmp = m48t59_read(opaque) << 24; + m48t59_set_addr(opaque, addr + 1); + tmp |= m48t59_read(opaque) << 16; + m48t59_set_addr(opaque, addr + 2); + tmp |= m48t59_read(opaque) << 8; + m48t59_set_addr(opaque, addr + 3); + tmp |= m48t59_read(opaque); + + return tmp; +} + +static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) +{ + uint16_t tmp; + uint16_t pd, pd1, pd2; + + tmp = prev >> 8; + pd = prev ^ value; + pd1 = pd & 0x000F; + pd2 = ((pd >> 4) & 0x000F) ^ pd1; + tmp ^= (pd1 << 3) | (pd1 << 8); + tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); + + return tmp; +} + +static void NVRAM_set_crc (void *opaque, uint32_t addr, + uint32_t start, uint32_t count) +{ + uint32_t i; + uint16_t crc = 0xFFFF; + int odd = 0; + + if (count & 1) + odd = 1; + count &= ~1; + for (i = 0; i != count; i++) { + crc = NVRAM_crc_update(crc, NVRAM_get_word(opaque, start + i)); + } + if (odd) { + crc = NVRAM_crc_update(crc, NVRAM_get_byte(opaque, start + i) << 8); + } + NVRAM_set_word(opaque, addr, crc); +} + +static void prep_NVRAM_init (void) +{ + void *opaque; + + opaque = m48t59_init(8, 0x0074, NVRAM_SIZE); + /* NVRAM header */ + /* 0x00: NVRAM size in kB */ + NVRAM_set_word(opaque, 0x00, NVRAM_SIZE >> 10); + /* 0x02: NVRAM version */ + NVRAM_set_byte(opaque, 0x02, 0x01); + /* 0x03: NVRAM revision */ + NVRAM_set_byte(opaque, 0x03, 0x01); + /* 0x08: last OS */ + NVRAM_set_byte(opaque, 0x08, 0x00); /* Unknown */ + /* 0x09: endian */ + NVRAM_set_byte(opaque, 0x09, 'B'); /* Big-endian */ + /* 0x0A: OSArea usage */ + NVRAM_set_byte(opaque, 0x0A, 0x00); /* Empty */ + /* 0x0B: PM mode */ + NVRAM_set_byte(opaque, 0x0B, 0x00); /* Normal */ + /* Restart block description record */ + /* 0x0C: restart block version */ + NVRAM_set_word(opaque, 0x0C, 0x01); + /* 0x0E: restart block revision */ + NVRAM_set_word(opaque, 0x0E, 0x01); + /* 0x20: restart address */ + NVRAM_set_lword(opaque, 0x20, 0x00); + /* 0x24: save area address */ + NVRAM_set_lword(opaque, 0x24, 0x00); + /* 0x28: save area length */ + NVRAM_set_lword(opaque, 0x28, 0x00); + /* 0x1C: checksum of restart block */ + NVRAM_set_crc(opaque, 0x1C, 0x0C, 32); + + /* Security section */ + /* Set all to zero */ + /* 0xC4: pointer to global environment area */ + NVRAM_set_lword(opaque, 0xC4, 0x0100); + /* 0xC8: size of global environment area */ + NVRAM_set_lword(opaque, 0xC8, + NVRAM_END - NVRAM_OSAREA_SIZE - NVRAM_CONFSIZE - 0x0100); + /* 0xD4: pointer to configuration area */ + NVRAM_set_lword(opaque, 0xD4, NVRAM_END - NVRAM_CONFSIZE); + /* 0xD8: size of configuration area */ + NVRAM_set_lword(opaque, 0xD8, NVRAM_CONFSIZE); + /* 0xE8: pointer to OS specific area */ + NVRAM_set_lword(opaque, 0xE8, + NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); + /* 0xD8: size of OS specific area */ + NVRAM_set_lword(opaque, 0xEC, NVRAM_OSAREA_SIZE); + + /* Configuration area */ + /* RTC init */ + // NVRAM_set_lword(opaque, 0x1FFC, 0x50); + + /* 0x04: checksum 0 => OS area */ + NVRAM_set_crc(opaque, 0x04, 0x00, + NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); + /* 0x06: checksum of config area */ + NVRAM_set_crc(opaque, 0x06, NVRAM_END - NVRAM_CONFSIZE, NVRAM_CONFSIZE); +} + +int load_initrd (const char *filename, uint8_t *addr) +{ + int fd, size; + + printf("Load initrd\n"); + fd = open(filename, O_RDONLY); + if (fd < 0) + return -1; + size = read(fd, addr, 16 * 1024 * 1024); + if (size < 0) + goto fail; + close(fd); + printf("Load initrd: %d\n", size); + return size; + fail: + close(fd); + printf("Load initrd failed\n"); + return -1; +} + +/* Quick hack for PPC memory infos... */ +static void put_long (void *addr, uint32_t l) +{ + char *pos = addr; + pos[0] = (l >> 24) & 0xFF; + pos[1] = (l >> 16) & 0xFF; + pos[2] = (l >> 8) & 0xFF; + pos[3] = l & 0xFF; +} + +/* bootloader infos are in the form: + * uint32_t TAG + * uint32_t TAG_size (from TAG to next TAG). + * data + * .... + */ +#if !defined (USE_OPEN_FIRMWARE) +static void *set_bootinfo_tag (void *addr, uint32_t tag, uint32_t size, + void *data) +{ + char *pos = addr; + + put_long(pos, tag); + pos += 4; + put_long(pos, size + 8); + pos += 4; + memcpy(pos, data, size); + pos += size; + + return pos; +} +#endif + +typedef struct boot_dev_t { + const unsigned char *name; + int major; + int minor; +} boot_dev_t; + +static boot_dev_t boot_devs[] = +{ + { "/dev/fd0", 2, 0, }, + { "/dev/fd1", 2, 1, }, + { "/dev/hda", 3, 1, }, +// { "/dev/ide/host0/bus0/target0/lun0/part1", 3, 1, }, +// { "/dev/hdc", 22, 0, }, + { "/dev/hdc", 22, 1, }, + { "/dev/ram0 init=/linuxrc", 1, 0, }, +}; + +/* BATU: + * BEPI : bloc virtual address + * BL : area size bits (128 kB is 0, 256 1, 512 3, ... + * Vs/Vp + * BATL: + * BPRN : bloc real address align on 4MB boundary + * WIMG : cache access mode : not used + * PP : protection bits + */ +static void setup_BAT (CPUPPCState *env, int BAT, + uint32_t virtual, uint32_t physical, + uint32_t size, int Vs, int Vp, int PP) +{ + uint32_t sz_bits, tmp_sz, align, tmp; + + sz_bits = 0; + align = 131072; + for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) { + sz_bits = (sz_bits << 1) + 1; + align = align << 1; + } + tmp = virtual & ~(align - 1); /* Align virtual area start */ + tmp |= sz_bits << 2; /* Fix BAT size */ + tmp |= Vs << 1; /* Supervisor access */ + tmp |= Vp; /* User access */ + env->DBAT[0][BAT] = tmp; + env->IBAT[0][BAT] = tmp; + tmp = physical & ~(align - 1); /* Align physical area start */ + tmp |= 0; /* Don't care about WIMG */ + tmp |= PP; /* Protection */ + env->DBAT[1][BAT] = tmp; + env->IBAT[1][BAT] = tmp; + printf("Set BATU0 to 0x%08x BATL0 to 0x%08x\n", + env->DBAT[0][BAT], env->DBAT[1][BAT]); +} + +static void VGA_printf (uint8_t *s) +{ + uint16_t *arg_ptr; + unsigned int format_width, i; + int in_format; + uint16_t arg, digit, nibble; + uint8_t c; + + arg_ptr = (uint16_t *)((void *)&s); + in_format = 0; + format_width = 0; + while ((c = *s) != '\0') { + if (c == '%') { + in_format = 1; + format_width = 0; + } else if (in_format) { + if ((c >= '0') && (c <= '9')) { + format_width = (format_width * 10) + (c - '0'); + } else if (c == 'x') { + arg_ptr++; // increment to next arg + arg = *arg_ptr; + if (format_width == 0) + format_width = 4; + digit = format_width - 1; + for (i = 0; i < format_width; i++) { + nibble = (arg >> (4 * digit)) & 0x000f; + if (nibble <= 9) + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0', 0); + else + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A', 0); + digit--; + } + in_format = 0; + } + //else if (c == 'd') { + // in_format = 0; + // } + } else { + PPC_io_writeb(PPC_IO_BASE + 0x500, c, 0); + } + s++; + } +} + +static void VGA_init (void) +{ + /* Basic VGA init, inspired by plex86 VGAbios */ + printf("Init VGA...\n"); +#if 1 + /* switch to color mode and enable CPU access 480 lines */ + PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3, 0); + /* more than 64k 3C4/04 */ + PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04, 0); + PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02, 0); +#endif + VGA_printf("PPC VGA BIOS...\n"); +} + +extern CPUPPCState *global_env; + +void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, + uint32_t kernel_addr, uint32_t kernel_size, + uint32_t stack_addr, int boot_device, + const unsigned char *initrd_file) +{ + CPUPPCState *env = global_env; + char *p; +#if !defined (USE_OPEN_FIRMWARE) + char *tmp; + uint32_t tmpi[2]; +#endif + + printf("RAM size: %u 0x%08x (%u)\n", mem_size, mem_size, mem_size >> 20); +#if defined (USE_OPEN_FIRMWARE) + setup_memory(env, mem_size); +#endif + + /* Fake bootloader */ + { +#if 1 + uint32_t offset = + *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); +#else + uint32_t offset = 12; +#endif + env->nip = kernel_addr + offset; + printf("Start address: 0x%08x\n", env->nip); + } + /* Set up msr according to PREP specification */ + msr_ee = 0; + msr_fp = 1; + msr_pr = 0; /* Start in supervisor mode */ + msr_me = 1; + msr_fe0 = msr_fe1 = 0; + msr_ip = 0; + msr_ir = msr_dr = 1; +// msr_sf = 0; + msr_le = msr_ile = 0; + env->gpr[1] = stack_addr; /* Let's have a stack */ + env->gpr[2] = 0; + env->gpr[8] = kernel_addr; + /* There is a bug in 2.4 kernels: + * if a decrementer exception is pending when it enables msr_ee, + * it's not ready to handle it... + */ + env->decr = 0xFFFFFFFF; + p = (void *)(phys_ram_base + kernel_addr); +#if !defined (USE_OPEN_FIRMWARE) + /* Let's register the whole memory available only in supervisor mode */ + setup_BAT(env, 0, 0x00000000, 0x00000000, mem_size, 1, 0, 2); + /* Avoid open firmware init call (to get a console) + * This will make the kernel think we are a PREP machine... + */ + put_long(p, 0xdeadc0de); + /* Build a real stack room */ + p = (void *)(phys_ram_base + stack_addr); + put_long(p, stack_addr); + p -= 32; + env->gpr[1] -= 32; + /* Pretend there are no residual data */ + env->gpr[3] = 0; + if (initrd_file != NULL) { + int size; + env->gpr[4] = (kernel_addr + kernel_size + 4095) & ~4095; + size = load_initrd(initrd_file, + (void *)((uint32_t)phys_ram_base + env->gpr[4])); + if (size < 0) { + /* No initrd */ + env->gpr[4] = env->gpr[5] = 0; + } else { + env->gpr[5] = size; + boot_device = 'e'; + } + printf("Initrd loaded at 0x%08x (%d) (0x%08x 0x%08x)\n", + env->gpr[4], env->gpr[5], kernel_addr, kernel_size); + } else { + env->gpr[4] = env->gpr[5] = 0; + } + /* We have to put bootinfos after the BSS + * The BSS starts after the kernel end. + */ +#if 0 + p = (void *)(((uint32_t)phys_ram_base + kernel_addr + + kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); +#else + p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); +#endif + if (loglevel > 0) { + fprintf(logfile, "bootinfos: %p 0x%08x\n", + p, (uint32_t)p - (uint32_t)phys_ram_base); + } else { + printf("bootinfos: %p 0x%08x\n", + p, (uint32_t)p - (uint32_t)phys_ram_base); + } + /* Command line: let's put it after bootinfos */ +#if 0 + sprintf(p + 0x1000, "console=ttyS0,9600 root=%02x%02x mem=%dM", + boot_devs[boot_device - 'a'].major, + boot_devs[boot_device - 'a'].minor, + mem_size >> 20); +#else + sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM", + boot_devs[boot_device - 'a'].name, + mem_size >> 20); +#endif + env->gpr[6] = (uint32_t)p + 0x1000 - (uint32_t)phys_ram_base; + env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); + if (loglevel > 0) { + fprintf(logfile, "cmdline: %p 0x%08x [%s]\n", + p + 0x1000, env->gpr[6], p + 0x1000); + } else { + printf("cmdline: %p 0x%08x [%s]\n", + p + 0x1000, env->gpr[6], p + 0x1000); + } + /* BI_FIRST */ + p = set_bootinfo_tag(p, 0x1010, 0, 0); + /* BI_CMD_LINE */ + p = set_bootinfo_tag(p, 0x1012, env->gpr[7] - env->gpr[6], + (void *)(env->gpr[6] + (uint32_t)phys_ram_base)); + /* BI_MEM_SIZE */ + tmp = (void *)tmpi; + tmp[0] = (mem_size >> 24) & 0xFF; + tmp[1] = (mem_size >> 16) & 0xFF; + tmp[2] = (mem_size >> 8) & 0xFF; + tmp[3] = mem_size & 0xFF; + p = set_bootinfo_tag(p, 0x1017, 4, tmpi); + /* BI_INITRD */ + tmp[0] = (env->gpr[4] >> 24) & 0xFF; + tmp[1] = (env->gpr[4] >> 16) & 0xFF; + tmp[2] = (env->gpr[4] >> 8) & 0xFF; + tmp[3] = env->gpr[4] & 0xFF; + tmp[4] = (env->gpr[5] >> 24) & 0xFF; + tmp[5] = (env->gpr[5] >> 16) & 0xFF; + tmp[6] = (env->gpr[5] >> 8) & 0xFF; + tmp[7] = env->gpr[5] & 0xFF; + p = set_bootinfo_tag(p, 0x1014, 8, tmpi); + env->gpr[4] = env->gpr[5] = 0; + /* BI_LAST */ + p = set_bootinfo_tag(p, 0x1011, 0, 0); +#else + /* Set up MMU: + * kernel is loaded at kernel_addr and wants to be seen at 0x01000000 + */ + setup_BAT(env, 0, 0x01000000, kernel_addr, 0x00400000, 1, 0, 2); + { +#if 0 + uint32_t offset = + *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); +#else + uint32_t offset = 12; +#endif + env->nip = 0x01000000 | (kernel_addr + offset); + printf("Start address: 0x%08x\n", env->nip); + } + env->gpr[1] = env->nip + (1 << 22); + p = (void *)(phys_ram_base + stack_addr); + put_long(p - 32, stack_addr); + env->gpr[1] -= 32; + printf("Kernel starts at 0x%08x stack 0x%08x\n", env->nip, env->gpr[1]); + /* We want all lower address not to be translated */ + setup_BAT(env, 1, 0x00000000, 0x00000000, 0x010000000, 1, 1, 2); + /* We also need a BAT to access OF */ + setup_BAT(env, 2, 0xFFFE0000, mem_size - 131072, 131072, 1, 0, 1); + /* Setup OF entry point */ + { + char *p; + p = (char *)phys_ram_base + mem_size - 131072; + /* Special opcode to call OF */ + *p++ = 0x18; *p++ = 0x00; *p++ = 0x00; *p++ = 0x02; + /* blr */ + *p++ = 0x4E; *p++ = 0x80; *p++ = 0x00; *p++ = 0x20; + } + env->gpr[5] = 0xFFFE0000; + /* Register translations */ + { + OF_transl_t translations[3] = { + { 0x01000000, 0x00400000, kernel_addr, 0x00000002, }, + { 0x00000000, 0x01000000, 0x00000000, 0x00000002, }, + { 0xFFFE0000, 0x00020000, mem_size - (128 * 1024), + 0x00000001, }, + }; + OF_register_translations(3, translations); + } + /* Quite artificial, for now */ + OF_register_bus("isa", "isa"); + OF_register_serial("isa", "serial", 4, 0x3f8); + OF_register_stdio("serial", "serial"); + /* Set up RTAS service */ + RTAS_init(); + /* Command line: let's put it just over the stack */ +#if 0 +#if 0 + p = (void *)(((uint32_t)phys_ram_base + kernel_addr + + kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); +#else + p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); +#endif +#if 1 + sprintf(p, "console=ttyS0,9600 root=%02x%02x mem=%dM", + boot_devs[boot_device - 'a'].major, + boot_devs[boot_device - 'a'].minor, + mem_size >> 20); +#else + sprintf(p, "console=ttyS0,9600 root=%s mem=%dM ne2000=0x300,9", + boot_devs[boot_device - 'a'].name, + mem_size >> 20); +#endif + OF_register_bootargs(p); +#endif +#endif +} + +void PPC_end_init (void) +{ + VGA_init(); +} + +/* PC hardware initialisation */ +void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + char buf[1024]; + int PPC_io_memory; + int ret, linux_boot, initrd_size, i, nb_nics1, fd; + + linux_boot = (kernel_filename != NULL); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, 0); + + if (linux_boot) { + /* now we can load the kernel */ + ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + /* load initrd */ + initrd_size = 0; +#if 0 + if (initrd_filename) { + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } +#endif + PPC_init_hw(/*env,*/ ram_size, KERNEL_LOAD_ADDR, ret, + KERNEL_STACK_ADDR, boot_device, initrd_filename); + } else { + /* allocate ROM */ + // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); + printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); + ret = load_image(buf, phys_ram_base + 0x000f0000); + if (ret != 0x10000) { + fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", + buf, ret); + exit(1); + } + } + + /* init basic PC hardware */ + vga_initialize(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + rtc_init(0x70, 8); + pic_init(); + // pit_init(0x40, 0); + + fd = serial_open_device(); + serial_init(0x3f8, 4, fd); +#if 1 + nb_nics1 = nb_nics; + if (nb_nics1 > NE2000_NB_MAX) + nb_nics1 = NE2000_NB_MAX; + for(i = 0; i < nb_nics1; i++) { + ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + } +#endif + + for(i = 0; i < 2; i++) { + ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + bs_table[2 * i], bs_table[2 * i + 1]); + } + kbd_init(); + AUD_init(); + DMA_init(); + // SB16_init(); + + fdctrl_init(6, 2, 0, 0x3f0, fd_table); + + /* Register 64 kB of IO space */ + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); + cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); + /* Register fake IO ports for PREP */ + register_ioport_read(0x398, 2, 1, &PREP_io_read, NULL); + register_ioport_write(0x398, 2, 1, &PREP_io_write, NULL); + /* System control ports */ + register_ioport_write(0x0092, 0x1, 1, &PREP_io_800_writeb, NULL); + register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, NULL); + register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, NULL); + /* PCI intack location (0xfef00000 / 0xbffffff0) */ + PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); + cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); + // cpu_register_physical_memory(0xFEF00000, 0x4, PPC_io_memory); + prep_NVRAM_init(); + + PPC_end_init(); +} diff --git a/linux-user/main.c b/linux-user/main.c index 21ddf7aeb..601829230 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -94,15 +94,15 @@ int cpu_inl(CPUState *env, int addr) return 0; } -#ifdef TARGET_I386 -/***********************************************************/ -/* CPUX86 core interface */ - -int cpu_x86_get_pic_interrupt(CPUState *env) +int cpu_get_pic_interrupt(CPUState *env) { return -1; } +#ifdef TARGET_I386 +/***********************************************************/ +/* CPUX86 core interface */ + static void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags) { @@ -441,7 +441,6 @@ void cpu_loop (CPUSPARCState *env) #endif #ifdef TARGET_PPC - void cpu_loop(CPUPPCState *env) { target_siginfo_t info; @@ -769,6 +768,8 @@ void cpu_loop(CPUPPCState *env) case EXCP_INTERRUPT: /* Don't know why this should ever happen... */ break; + case EXCP_DEBUG: + break; default: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f8b48d588..95806454d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2475,6 +2475,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } #endif break; +#ifdef TARGET_NR_getdents64 case TARGET_NR_getdents64: { struct dirent64 *dirp = (void *)arg2; @@ -2498,6 +2499,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#endif /* TARGET_NR_getdents64 */ case TARGET_NR__newselect: ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, (void *)arg5); diff --git a/monitor.c b/monitor.c index 9e55c0cb5..8a00ee9bc 100644 --- a/monitor.c +++ b/monitor.c @@ -530,6 +530,47 @@ typedef struct MonitorDef { int (*get_value)(struct MonitorDef *md); } MonitorDef; +#if defined(TARGET_PPC) +static int monitor_get_ccr (struct MonitorDef *md) +{ + unsigned int u; + int i; + + u = 0; + for (i = 0; i < 8; i++) + u |= cpu_single_env->crf[i] << (32 - (4 * i)); + + return u; +} + +static int monitor_get_msr (struct MonitorDef *md) +{ + return (cpu_single_env->msr[MSR_POW] << MSR_POW) | + (cpu_single_env->msr[MSR_ILE] << MSR_ILE) | + (cpu_single_env->msr[MSR_EE] << MSR_EE) | + (cpu_single_env->msr[MSR_PR] << MSR_PR) | + (cpu_single_env->msr[MSR_FP] << MSR_FP) | + (cpu_single_env->msr[MSR_ME] << MSR_ME) | + (cpu_single_env->msr[MSR_FE0] << MSR_FE0) | + (cpu_single_env->msr[MSR_SE] << MSR_SE) | + (cpu_single_env->msr[MSR_BE] << MSR_BE) | + (cpu_single_env->msr[MSR_FE1] << MSR_FE1) | + (cpu_single_env->msr[MSR_IP] << MSR_IP) | + (cpu_single_env->msr[MSR_IR] << MSR_IR) | + (cpu_single_env->msr[MSR_DR] << MSR_DR) | + (cpu_single_env->msr[MSR_RI] << MSR_RI) | + (cpu_single_env->msr[MSR_LE] << MSR_LE); +} + +static int monitor_get_xer (struct MonitorDef *md) +{ + return (cpu_single_env->xer[XER_SO] << XER_SO) | + (cpu_single_env->xer[XER_OV] << XER_OV) | + (cpu_single_env->xer[XER_CA] << XER_CA) | + (cpu_single_env->xer[XER_BC] << XER_BC); +} +#endif + static MonitorDef monitor_defs[] = { #ifdef TARGET_I386 { "eax", offsetof(CPUState, regs[0]) }, @@ -542,6 +583,65 @@ static MonitorDef monitor_defs[] = { { "esi", offsetof(CPUState, regs[7]) }, { "eflags", offsetof(CPUState, eflags) }, { "eip|pc", offsetof(CPUState, eip) }, +#elif defined(TARGET_PPC) + { "r0", offsetof(CPUState, gpr[0]) }, + { "r1", offsetof(CPUState, gpr[1]) }, + { "r2", offsetof(CPUState, gpr[2]) }, + { "r3", offsetof(CPUState, gpr[3]) }, + { "r4", offsetof(CPUState, gpr[4]) }, + { "r5", offsetof(CPUState, gpr[5]) }, + { "r6", offsetof(CPUState, gpr[6]) }, + { "r7", offsetof(CPUState, gpr[7]) }, + { "r8", offsetof(CPUState, gpr[8]) }, + { "r9", offsetof(CPUState, gpr[9]) }, + { "r10", offsetof(CPUState, gpr[10]) }, + { "r11", offsetof(CPUState, gpr[11]) }, + { "r12", offsetof(CPUState, gpr[12]) }, + { "r13", offsetof(CPUState, gpr[13]) }, + { "r14", offsetof(CPUState, gpr[14]) }, + { "r15", offsetof(CPUState, gpr[15]) }, + { "r16", offsetof(CPUState, gpr[16]) }, + { "r17", offsetof(CPUState, gpr[17]) }, + { "r18", offsetof(CPUState, gpr[18]) }, + { "r19", offsetof(CPUState, gpr[19]) }, + { "r20", offsetof(CPUState, gpr[20]) }, + { "r21", offsetof(CPUState, gpr[21]) }, + { "r22", offsetof(CPUState, gpr[22]) }, + { "r23", offsetof(CPUState, gpr[23]) }, + { "r24", offsetof(CPUState, gpr[24]) }, + { "r25", offsetof(CPUState, gpr[25]) }, + { "r26", offsetof(CPUState, gpr[26]) }, + { "r27", offsetof(CPUState, gpr[27]) }, + { "r28", offsetof(CPUState, gpr[28]) }, + { "r29", offsetof(CPUState, gpr[29]) }, + { "r30", offsetof(CPUState, gpr[30]) }, + { "r31", offsetof(CPUState, gpr[31]) }, + { "lr", offsetof(CPUState, lr) }, + { "ctr", offsetof(CPUState, ctr) }, + { "decr", offsetof(CPUState, decr) }, + { "ccr", 0, &monitor_get_ccr, }, + { "msr", 0, &monitor_get_msr, }, + { "xer", 0, &monitor_get_xer, }, + { "tbu", offsetof(CPUState, tb[0]) }, + { "tbl", offsetof(CPUState, tb[1]) }, + { "sdr1", offsetof(CPUState, sdr1) }, + { "sr0", offsetof(CPUState, sr[0]) }, + { "sr1", offsetof(CPUState, sr[1]) }, + { "sr2", offsetof(CPUState, sr[2]) }, + { "sr3", offsetof(CPUState, sr[3]) }, + { "sr4", offsetof(CPUState, sr[4]) }, + { "sr5", offsetof(CPUState, sr[5]) }, + { "sr6", offsetof(CPUState, sr[6]) }, + { "sr7", offsetof(CPUState, sr[7]) }, + { "sr8", offsetof(CPUState, sr[8]) }, + { "sr9", offsetof(CPUState, sr[9]) }, + { "sr10", offsetof(CPUState, sr[10]) }, + { "sr11", offsetof(CPUState, sr[11]) }, + { "sr12", offsetof(CPUState, sr[12]) }, + { "sr13", offsetof(CPUState, sr[13]) }, + { "sr14", offsetof(CPUState, sr[14]) }, + { "sr15", offsetof(CPUState, sr[15]) }, + /* Too lazy to put BATs and SPRs ... */ #endif { NULL }, }; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3809f2014..6cd08950f 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -20,9 +20,6 @@ #if !defined (__CPU_PPC_H__) #define __CPU_PPC_H__ -#include -#include - #define TARGET_LONG_BITS 32 #include "cpu-defs.h" @@ -157,14 +154,26 @@ typedef struct CPUPPCState { int error_code; int access_type; /* when a memory exception occurs, the access type is stored here */ +#if 0 /* TODO */ + uint32_t pending_exceptions; /* For external & decr exception, + * that can be delayed */ +#else uint32_t exceptions; /* exception queue */ - uint32_t errors[16]; + uint32_t errors[32]; +#endif int user_mode_only; /* user mode only simulation */ struct TranslationBlock *current_tb; /* currently executing TB */ /* soft mmu support */ - /* 0 = kernel, 1 = user */ + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + + /* ice debug support */ + uint32_t breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; + int brkstate; + int singlestep_enabled; + /* user data */ void *opaque; } CPUPPCState; @@ -179,14 +188,21 @@ struct siginfo; int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, void *puc); -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); +void do_interrupt (CPUPPCState *env); void cpu_loop_exit(void); + +void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); void dump_stack (CPUPPCState *env); -uint32_t _load_xer (void); -void _store_xer (uint32_t value); -uint32_t _load_msr (void); -void _store_msr (uint32_t value); -void do_interrupt (CPUPPCState *env); + +uint32_t _load_xer (CPUPPCState *env); +void _store_xer (CPUPPCState *env, uint32_t value); +uint32_t _load_msr (CPUPPCState *env); +void _store_msr (CPUPPCState *env, uint32_t value); + +void PPC_init_hw (uint32_t mem_size, + uint32_t kernel_addr, uint32_t kernel_size, + uint32_t stack_addr, int boot_device, + const unsigned char *initrd_file); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" @@ -277,14 +293,6 @@ void do_interrupt (CPUPPCState *env); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" -CPUPPCState *cpu_ppc_init(void); -int cpu_ppc_exec(CPUPPCState *s); -void cpu_ppc_close(CPUPPCState *s); -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); -void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, - uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device); - /* Memory access type : * may be needed for precise access rights control and precise exceptions. */ @@ -351,12 +359,14 @@ enum { /* flags for EXCP_DSI */ EXCP_DSI_DIRECT = 0x10, EXCP_DSI_STORE = 0x20, - EXCP_ECXW = 0x40, + EXCP_DSI_ECXW = 0x40, /* Exception subtypes for EXCP_ISI */ EXCP_ISI_TRANSLATE = 0x01, /* Code address can't be translated */ EXCP_ISI_NOEXEC = 0x02, /* Try to fetch from a data segment */ EXCP_ISI_GUARD = 0x03, /* Fetch from guarded memory */ EXCP_ISI_PROT = 0x04, /* Memory protection violation */ + EXCP_ISI_DIRECT = 0x05, /* Trying to fetch from * + * a direct store segment */ /* Exception subtypes for EXCP_ALIGN */ EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 8a255ec6f..72bd03e36 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -36,7 +36,11 @@ register uint32_t T2 asm(AREG3); #define FTS1 ((float)env->ft1) #define FTS2 ((float)env->ft2) +#if defined (DEBUG_OP) +#define RETURN() __asm__ __volatile__("nop"); +#else #define RETURN() __asm__ __volatile__(""); +#endif #include "cpu.h" #include "exec-all.h" @@ -149,6 +153,7 @@ void do_icbi (void); void do_tlbia (void); void do_tlbie (void); +void dump_state (void); void dump_rfi (void); void dump_store_sr (int srnum); void dump_store_ibat (int ul, int nr); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4e8206e72..e4bc0545b 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -21,6 +21,7 @@ #include "exec.h" #if defined (USE_OPEN_FIRMWARE) +#include #include "of.h" #endif @@ -28,7 +29,7 @@ //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS -extern FILE *logfile, *stderr; +extern FILE *logfile, *stdout, *stderr; void exit (int); void abort (void); @@ -74,6 +75,9 @@ int check_exception_state (CPUState *env) /*****************************************************************************/ /* PPC MMU emulation */ +int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu); + /* Perform BAT hit & translation */ static int get_bat (CPUState *env, uint32_t *real, int *prot, uint32_t virtual, int rw, int type) @@ -88,8 +92,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } - printf("%s: %cBAT v 0x%08x\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); #endif switch (type) { case ACCESS_CODE: @@ -106,8 +108,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } - printf("%s...: %cBAT v 0x%08x\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); #endif base = virtual & 0xFFFC0000; for (i = 0; i < 4; i++) { @@ -121,10 +121,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); - } else { - printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", - __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, - *BATu, *BATl); } #endif if ((virtual & 0xF0000000) == BEPIu && @@ -135,7 +131,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, /* Get physical address */ *real = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | - (virtual & 0x0001FFFF); + (virtual & 0x0001F000); if (*BATl & 0x00000001) *prot = PROT_READ; if (*BATl & 0x00000002) @@ -145,10 +141,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", i, *real, *prot & PROT_READ ? 'R' : '-', *prot & PROT_WRITE ? 'W' : '-'); - } else { - printf("BAT %d match: 0x%08x => 0x%08x prot=%c%c\n", - i, virtual, *real, *prot & PROT_READ ? 'R' : '-', - *prot & PROT_WRITE ? 'W' : '-'); } #endif ret = 0; @@ -181,7 +173,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, int h, int key, int rw) { - uint32_t pte0, pte1, keep = 0; + uint32_t pte0, pte1, keep = 0, access = 0; int i, good = -1, store = 0; int ret = -1; /* No entry found */ @@ -189,85 +181,97 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8))); pte1 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4)); #if defined (DEBUG_MMU) - printf("Load pte from 0x%08x => 0x%08x 0x%08x\n", base + (i * 8), - pte0, pte1); + if (loglevel > 0) { + fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " + "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, + pte0 >> 31, h, (pte0 >> 6) & 1, va); + } #endif /* Check validity and table match */ if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) { -#if defined (DEBUG_MMU) - printf("PTE is valid and table matches... compare 0x%08x:%08x\n", - pte0 & 0x7FFFFFBF, va); -#endif /* Check vsid & api */ if ((pte0 & 0x7FFFFFBF) == va) { -#if defined (DEBUG_MMU) - printf("PTE match !\n"); -#endif if (good == -1) { good = i; keep = pte1; } else { /* All matches should have equal RPN, WIMG & PP */ if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) { - printf("Bad RPN/WIMG/PP\n"); + if (loglevel > 0) + fprintf(logfile, "Bad RPN/WIMG/PP\n"); return -1; } } /* Check access rights */ if (key == 0) { - *prot = PROT_READ; + access = PROT_READ; if ((pte1 & 0x00000003) != 0x3) - *prot |= PROT_WRITE; + access |= PROT_WRITE; } else { switch (pte1 & 0x00000003) { case 0x0: - *prot = 0; + access = 0; break; case 0x1: case 0x3: - *prot = PROT_READ; + access = PROT_READ; break; case 0x2: - *prot = PROT_READ | PROT_WRITE; + access = PROT_READ | PROT_WRITE; break; } } - if ((rw == 0 && *prot != 0) || - (rw == 1 && (*prot & PROT_WRITE))) { + if (ret < 0) { + if ((rw == 0 && (access & PROT_READ)) || + (rw == 1 && (access & PROT_WRITE))) { #if defined (DEBUG_MMU) - printf("PTE access granted !\n"); + if (loglevel > 0) + fprintf(logfile, "PTE access granted !\n"); #endif good = i; keep = pte1; ret = 0; - } else if (ret == -1) { - ret = -2; /* Access right violation */ + } else { + /* Access right violation */ + ret = -2; #if defined (DEBUG_MMU) - printf("PTE access rejected\n"); + if (loglevel > 0) + fprintf(logfile, "PTE access rejected\n"); #endif } + *prot = access; + } } } } if (good != -1) { *RPN = keep & 0xFFFFF000; #if defined (DEBUG_MMU) - printf("found PTE at addr 0x%08x prot=0x%01x ret=%d\n", + if (loglevel > 0) { + fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", *RPN, *prot, ret); + } #endif /* Update page flags */ if (!(keep & 0x00000100)) { + /* Access flag */ keep |= 0x00000100; store = 1; } - if (rw) { if (!(keep & 0x00000080)) { + if (rw && ret == 0) { + /* Change flag */ keep |= 0x00000080; store = 1; + } else { + /* Force page fault for first write access */ + *prot &= ~PROT_WRITE; } } - if (store) - stl_raw((void *)(base + (good * 2) + 1), keep); + if (store) { + stl_raw((void *)((uint32_t)phys_ram_base + base + (good * 8) + 4), + keep); + } } return ret; @@ -290,29 +294,37 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, sr = env->sr[virtual >> 28]; #if defined (DEBUG_MMU) - printf("Check segment v=0x%08x %d 0x%08x nip=0x%08x lr=0x%08x ir=%d dr=%d " - "pr=%d t=%d\n", virtual, virtual >> 28, sr, env->nip, - env->lr, msr_ir, msr_dr, msr_pr, type); + if (loglevel > 0) { + fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x " + "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n", + virtual, virtual >> 28, sr, env->nip, + env->lr, msr_ir, msr_dr, msr_pr, rw, type); + } #endif - key = ((sr & 0x20000000) && msr_pr == 1) || - ((sr & 0x40000000) && msr_pr == 0) ? 1 : 0; + key = (((sr & 0x20000000) && msr_pr == 1) || + ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; if ((sr & 0x80000000) == 0) { #if defined (DEBUG_MMU) - printf("pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000); + if (loglevel > 0) + fprintf(logfile, "pte segment: key=%d n=0x%08x\n", + key, sr & 0x10000000); #endif /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { /* Page address translation */ vsid = sr & 0x00FFFFFF; pgidx = (virtual >> 12) & 0xFFFF; - sdr = env->spr[SDR1]; - hash = ((vsid ^ pgidx) & 0x07FFFF) << 6; + sdr = env->sdr1; + hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6; mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; pg_addr = get_pgaddr(sdr, hash, mask); ptem = (vsid << 7) | (pgidx >> 10); #if defined (DEBUG_MMU) - printf("0 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%07x " - "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); + if (loglevel > 0) { + fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x " + "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, + pg_addr); + } #endif /* Primary table lookup */ ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw); @@ -321,25 +333,27 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, hash = (~hash) & 0x01FFFFC0; pg_addr = get_pgaddr(sdr, hash, mask); #if defined (DEBUG_MMU) - printf("1 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%05x " - "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); + if (virtual != 0xEFFFFFFF && loglevel > 0) { + fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x " + "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx, + hash, pg_addr); + } #endif ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw); if (ret2 != -1) ret = ret2; } - if (ret != -1) - *real |= (virtual & 0x00000FFF); - if (ret == -2 && type == ACCESS_CODE && (sr & 0x10000000)) - ret = -3; } else { #if defined (DEBUG_MMU) - printf("No access allowed\n"); + if (loglevel > 0) + fprintf(logfile, "No access allowed\n"); #endif + ret = -3; } } else { #if defined (DEBUG_MMU) - printf("direct store...\n"); + if (loglevel > 0) + fprintf(logfile, "direct store...\n"); #endif /* Direct-store segment : absolutely *BUGGY* for now */ switch (type) { @@ -393,9 +407,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, if (loglevel > 0) { fprintf(logfile, "%s\n", __func__); } + if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) { /* No address translation */ - *physical = address; + *physical = address & ~0xFFF; *prot = PROT_READ | PROT_WRITE; ret = 0; } else { @@ -406,6 +421,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, ret = get_segment(env, physical, prot, address, rw, access_type); } } + if (loglevel > 0) { + fprintf(logfile, "%s address %08x => %08x\n", + __func__, address, *physical); + } return ret; } @@ -448,18 +467,17 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) +void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; - int ret, is_user; - unsigned long pc; CPUState *saved_env; + unsigned long pc; + int ret; /* XXX: hack to restore env in all cases, even if not called from generated code */ saved_env = env; env = cpu_single_env; - is_user = flags & 0x01; { unsigned long tlb_addrr, tlb_addrw; int index; @@ -474,7 +492,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); #endif } - ret = cpu_handle_mmu_fault(env, addr, is_write, flags, 1); + ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); if (ret) { if (retaddr) { /* now we have a real cpu fault */ @@ -506,7 +524,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) env = saved_env; } -void cpu_ppc_init_mmu(CPUPPCState *env) +void cpu_ppc_init_mmu(CPUState *env) { /* Nothing to do: all translation are disabled */ } @@ -514,59 +532,36 @@ void cpu_ppc_init_mmu(CPUPPCState *env) /* Perform address translation */ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, - int flags, int is_softmmu) + int is_user, int is_softmmu) { uint32_t physical; int prot; int exception = 0, error_code = 0; - int is_user, access_type; + int access_type; int ret = 0; // printf("%s 0\n", __func__); - is_user = flags & 0x01; access_type = env->access_type; if (env->user_mode_only) { /* user mode only emulation */ ret = -1; goto do_fault; } + /* NASTY BUG workaround */ + if (access_type == ACCESS_CODE && rw) { + // printf("%s: ERROR WRITE CODE ACCESS\n", __func__); + access_type = ACCESS_INT; + } ret = get_physical_address(env, &physical, &prot, address, rw, access_type); if (ret == 0) { - ret = tlb_set_page(env, address, physical, prot, is_user, is_softmmu); + ret = tlb_set_page(env, address & ~0xFFF, physical, prot, + is_user, is_softmmu); } else if (ret < 0) { do_fault: #if defined (DEBUG_MMU) - printf("%s 5\n", __func__); - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x TBL=0x%08x\n", - env->nip, env->lr, env->ctr, /*msr*/0, env->tb[0]); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); + if (loglevel > 0) + cpu_ppc_dump_state(env, logfile, 0); #endif if (access_type == ACCESS_CODE) { exception = EXCP_ISI; @@ -580,13 +575,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, error_code = EXCP_ISI_PROT; break; case -3: + /* No execute protection violation */ error_code = EXCP_ISI_NOEXEC; break; case -4: /* Direct store exception */ /* No code fetch is allowed in direct-store areas */ - exception = EXCP_ISI; - error_code = EXCP_ISI_NOEXEC; + error_code = EXCP_ISI_DIRECT; break; } } else { @@ -612,15 +607,15 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, /* lwarx, ldarx or srwcx. */ exception = EXCP_DSI; error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT; - if (rw) - error_code |= EXCP_DSI_STORE; break; case ACCESS_EXT: /* eciwx or ecowx */ exception = EXCP_DSI; - error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | EXCP_ECXW; + error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | + EXCP_DSI_ECXW; break; default: + printf("DSI: invalid exception (%d)\n", ret); exception = EXCP_PROGRAM; error_code = EXCP_INVAL | EXCP_INVAL_INVAL; break; @@ -628,27 +623,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, } if (rw) error_code |= EXCP_DSI_STORE; - /* Should find a better solution: - * this will be invalid for some exception if more than one - * exception occurs for one instruction - */ - env->spr[DSISR] = 0; - if (error_code & EXCP_DSI_DIRECT) { - env->spr[DSISR] |= 0x80000000; - if (access_type == ACCESS_EXT || - access_type == ACCESS_RES) - env->spr[DSISR] |= 0x04000000; - } - if ((error_code & 0xF) == EXCP_DSI_TRANSLATE) - env->spr[DSISR] |= 0x40000000; - if (error_code & EXCP_DSI_PROT) - env->spr[DSISR] |= 0x08000000; - if (error_code & EXCP_DSI_STORE) - env->spr[DSISR] |= 0x02000000; - if ((error_code & 0xF) == EXCP_DSI_DABR) - env->spr[DSISR] |= 0x00400000; - if (access_type == ACCESS_EXT) - env->spr[DSISR] |= 0x00100000; + /* Store fault address */ + env->spr[DAR] = address; } #if 0 printf("%s: set exception to %d %02x\n", @@ -656,15 +632,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, #endif env->exception_index = exception; env->error_code = error_code; - /* Store fault address */ - env->spr[DAR] = address; ret = 1; } return ret; } -uint32_t _load_xer (void) +uint32_t _load_xer (CPUState *env) { return (xer_so << XER_SO) | (xer_ov << XER_OV) | @@ -672,7 +646,7 @@ uint32_t _load_xer (void) (xer_bc << XER_BC); } -void _store_xer (uint32_t value) +void _store_xer (CPUState *env, uint32_t value) { xer_so = (value >> XER_SO) & 0x01; xer_ov = (value >> XER_OV) & 0x01; @@ -680,7 +654,7 @@ void _store_xer (uint32_t value) xer_bc = (value >> XER_BC) & 0x1f; } -uint32_t _load_msr (void) +uint32_t _load_msr (CPUState *env) { return (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | @@ -699,8 +673,13 @@ uint32_t _load_msr (void) (msr_le << MSR_LE); } -void _store_msr (uint32_t value) +void _store_msr (CPUState *env, uint32_t value) { + if (((T0 >> MSR_IR) & 0x01) != msr_ir || + ((T0 >> MSR_DR) & 0x01) != msr_dr) { + /* Flush all tlb when changing translation mode or privilege level */ + do_tlbia(); + } msr_pow = (value >> MSR_POW) & 0x03; msr_ile = (value >> MSR_ILE) & 0x01; msr_ee = (value >> MSR_EE) & 0x01; @@ -729,47 +708,16 @@ void do_interrupt (CPUState *env) /* Dequeue PPC exceptions */ if (excp < EXCP_PPC_MAX) env->exceptions &= ~(1 << excp); - msr = _load_msr(); + msr = _load_msr(env); #if defined (DEBUG_EXCEPTIONS) - if (excp != EXCP_DECR && excp == EXCP_PROGRAM && excp < EXCP_PPC_MAX) + if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { if (loglevel > 0) { fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", env->nip, excp << 8, env->error_code); - } else { - printf("Raise exception at 0x%08x => 0x%08x (%02x)\n", - env->nip, excp << 8, env->error_code); - } - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x DECR=0x%08x\n", - env->nip, env->lr, env->ctr, msr, env->decr); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("XER 0x%08x SRR0 0x%08x SRR1 0x%08x\n", - _load_xer(), env->spr[SRR0], env->spr[SRR1]); + if (loglevel > 0) + cpu_ppc_dump_state(env, logfile, 0); } #endif /* Generate informations in save/restore registers */ @@ -812,26 +760,63 @@ void do_interrupt (CPUState *env) /* data location address has been stored * when the fault has been detected */ - goto store_current; + msr &= ~0xFFFF0000; + env->spr[DSISR] = 0; + if (env->error_code & EXCP_DSI_TRANSLATE) + env->spr[DSISR] |= 0x40000000; + else if (env->error_code & EXCP_DSI_PROT) + env->spr[DSISR] |= 0x08000000; + else if (env->error_code & EXCP_DSI_NOTSUP) { + env->spr[DSISR] |= 0x80000000; + if (env->error_code & EXCP_DSI_DIRECT) + env->spr[DSISR] |= 0x04000000; + } + if (env->error_code & EXCP_DSI_STORE) + env->spr[DSISR] |= 0x02000000; + if ((env->error_code & 0xF) == EXCP_DSI_DABR) + env->spr[DSISR] |= 0x00400000; + if (env->error_code & EXCP_DSI_ECXW) + env->spr[DSISR] |= 0x00100000; +#if defined (DEBUG_EXCEPTIONS) + if (loglevel) { + fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", + env->spr[DSISR], env->spr[DAR]); + } else { + printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", + env->spr[DSISR], env->spr[DAR], env->nip); + } +#endif + goto store_next; case EXCP_ISI: /* Store exception cause */ + msr &= ~0xFFFF0000; if (env->error_code == EXCP_ISI_TRANSLATE) msr |= 0x40000000; else if (env->error_code == EXCP_ISI_NOEXEC || - env->error_code == EXCP_ISI_GUARD) + env->error_code == EXCP_ISI_GUARD || + env->error_code == EXCP_ISI_DIRECT) msr |= 0x10000000; else msr |= 0x08000000; +#if defined (DEBUG_EXCEPTIONS) + if (loglevel) { + fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", + msr, env->nip); + } else { + printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n", + msr, env->nip, env->spr[V_TBL]); + } +#endif goto store_next; case EXCP_EXTERNAL: if (msr_ee == 0) { #if defined (DEBUG_EXCEPTIONS) if (loglevel > 0) { fprintf(logfile, "Skipping hardware interrupt\n"); - } else { - printf("Skipping hardware interrupt\n"); } #endif + /* Requeue it */ + do_queue_exception(EXCP_EXTERNAL); return; } goto store_next; @@ -863,6 +848,7 @@ void do_interrupt (CPUState *env) env->fpscr[7] |= 0x4; break; case EXCP_INVAL: + printf("Invalid instruction at 0x%08x\n", env->nip); msr |= 0x00080000; break; case EXCP_PRIV: @@ -888,8 +874,17 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_SYSCALL: #if defined (DEBUG_EXCEPTIONS) - printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", - env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); + if (msr_pr) { + if (loglevel) { + fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", + env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6]); + } else { + printf("syscall %d from 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + env->gpr[0], env->nip, env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6]); + } + } #endif goto store_next; case EXCP_TRACE: @@ -898,20 +893,16 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_MTMSR: /* Nothing to do */ -#if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_MTMSR\n", __func__); -#endif return; case EXCP_BRANCH: /* Nothing to do */ -#if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_BRANCH\n", __func__); -#endif return; case EXCP_RFI: /* Restore user-mode state */ + tb_flush(env); #if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_RFI\n", __func__); + if (msr_pr == 1) + printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); #endif return; store_current: diff --git a/target-ppc/hw.c b/target-ppc/hw.c deleted file mode 100644 index 090b610c3..000000000 --- a/target-ppc/hw.c +++ /dev/null @@ -1,935 +0,0 @@ -/* - * Hardware simulation for PPC target. - * For now, this is only a 'minimal' collection of hacks needed to boot Linux. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" -#include "vl.h" - -//#define HARD_DEBUG_PPC_IO -#define DEBUG_PPC_IO - -extern int loglevel; -extern FILE *logfile; - -#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO) -#define DEBUG_PPC_IO -#endif - -#if defined (HARD_DEBUG_PPC_IO) -#define PPC_IO_DPRINTF(fmt, args...) \ -do { \ - if (loglevel > 0) { \ - fprintf(logfile, "%s: " fmt, __func__ , ##args); \ - } else { \ - printf("%s : " fmt, __func__ , ##args); \ - } \ -} while (0) -#elif defined (DEBUG_PPC_IO) -#define PPC_IO_DPRINTF(fmt, args...) \ -do { \ - if (loglevel > 0) { \ - fprintf(logfile, "%s: " fmt, __func__ , ##args); \ - } \ -} while (0) -#else -#define PPC_IO_DPRINTF(fmt, args...) do { } while (0) -#endif - -#if defined (USE_OPEN_FIRMWARE) -#include "of.h" -#else -#define NVRAM_SIZE 0x2000 -#endif - -/* IO ports emulation */ -#define PPC_IO_BASE 0x80000000 - -static void PPC_io_writeb (uint32_t addr, uint32_t value) -{ - /* Don't polute serial port output */ - if ((addr < 0x800003F0 || addr > 0x80000400) && - (addr < 0x80000074 || addr > 0x80000077) && - (addr < 0x80000020 || addr > 0x80000021) && - (addr < 0x800000a0 || addr > 0x800000a1) && - (addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x => 0x%02x\n", addr - PPC_IO_BASE, value); - } - cpu_outb(NULL, addr - PPC_IO_BASE, value); -} - -static uint32_t PPC_io_readb (uint32_t addr) -{ - uint32_t ret = cpu_inb(NULL, addr - PPC_IO_BASE); - - if ((addr < 0x800003F0 || addr > 0x80000400) && - (addr < 0x80000074 || addr > 0x80000077) && - (addr < 0x80000020 || addr > 0x80000021) && - (addr < 0x800000a0 || addr > 0x800000a1) && - (addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177) && - (addr < 0x8000060 || addr > 0x8000064)) { -// PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); - } - - return ret; -} - -static void PPC_io_writew (uint32_t addr, uint32_t value) -{ - if ((addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x => 0x%04x\n", addr - PPC_IO_BASE, value); - } - cpu_outw(NULL, addr - PPC_IO_BASE, value); -} - -static uint32_t PPC_io_readw (uint32_t addr) -{ - uint32_t ret = cpu_inw(NULL, addr - PPC_IO_BASE); - - if ((addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x <= 0x%04x\n", addr - PPC_IO_BASE, ret); - } - - return ret; -} - -static void PPC_io_writel (uint32_t addr, uint32_t value) -{ - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); - cpu_outl(NULL, addr - PPC_IO_BASE, value); -} - -static uint32_t PPC_io_readl (uint32_t addr) -{ - uint32_t ret = cpu_inl(NULL, addr - PPC_IO_BASE); - - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, ret); - - return ret; -} - -static CPUWriteMemoryFunc *PPC_io_write[] = { - &PPC_io_writeb, - &PPC_io_writew, - &PPC_io_writel, -}; - -static CPUReadMemoryFunc *PPC_io_read[] = { - &PPC_io_readb, - &PPC_io_readw, - &PPC_io_readl, -}; - -uint32_t pic_intack_read(CPUState *env); - -/* Read-only register (?) */ -static void _PPC_ioB_write (uint32_t addr, uint32_t value) -{ - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr, value); -} - -static uint32_t _PPC_ioB_read (uint32_t addr) -{ - uint32_t retval = 0; - - if (addr == 0xBFFFFFF0) - retval = pic_intack_read(NULL); - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr, retval); - - return retval; -} - -static CPUWriteMemoryFunc *PPC_ioB_write[] = { - &_PPC_ioB_write, - &_PPC_ioB_write, - &_PPC_ioB_write, -}; - -static CPUReadMemoryFunc *PPC_ioB_read[] = { - &_PPC_ioB_read, - &_PPC_ioB_read, - &_PPC_ioB_read, -}; - -#if 0 -static CPUWriteMemoryFunc *PPC_io3_write[] = { - &PPC_io3_writeb, - &PPC_io3_writew, - &PPC_io3_writel, -}; - -static CPUReadMemoryFunc *PPC_io3_read[] = { - &PPC_io3_readb, - &PPC_io3_readw, - &PPC_io3_readl, -}; -#endif - -/* Fake super-io ports for PREP platform (Intel 82378ZB) */ -static uint8_t PREP_fake_io[2]; -static uint8_t NVRAM_lock; - -static void PREP_io_write (CPUState *env, uint32_t addr, uint32_t val) -{ - PREP_fake_io[addr - 0x0398] = val; -} - -static uint32_t PREP_io_read (CPUState *env, uint32_t addr) -{ - return PREP_fake_io[addr - 0x0398]; -} - -static uint8_t syscontrol; - -static void PREP_io_800_writeb (CPUState *env, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x0092: - /* Special port 92 */ - /* Check soft reset asked */ - if (val & 0x80) { - printf("Soft reset asked... Stop emulation\n"); - abort(); - } - /* Check LE mode */ - if (val & 0x40) { - printf("Little Endian mode isn't supported (yet ?)\n"); - abort(); - } - break; - case 0x0808: - /* Hardfile light register: don't care */ - break; - case 0x0810: - /* Password protect 1 register */ - NVRAM_lock ^= 0x01; - break; - case 0x0812: - /* Password protect 2 register */ - NVRAM_lock ^= 0x02; - break; - case 0x0814: - /* L2 invalidate register: don't care */ - break; - case 0x081C: - /* system control register */ - syscontrol = val; - break; - case 0x0850: - /* I/O map type register */ - if (val & 0x80) { - printf("No support for non-continuous I/O map mode\n"); - abort(); - } - break; - default: - break; - } -} - -static uint32_t PREP_io_800_readb (CPUState *env, uint32_t addr) -{ - uint32_t retval = 0xFF; - - switch (addr) { - case 0x0092: - /* Special port 92 */ - retval = 0x40; - break; - case 0x080C: - /* Equipment present register: - * no L2 cache - * no upgrade processor - * no cards in PCI slots - * SCSI fuse is bad - */ - retval = 0xFC; - break; - case 0x0818: - /* Keylock */ - retval = 0x00; - break; - case 0x081C: - /* system control register - * 7 - 6 / 1 - 0: L2 cache enable - */ - retval = syscontrol; - break; - case 0x0823: - /* */ - retval = 0x03; /* no L2 cache */ - break; - case 0x0850: - /* I/O map type register */ - retval = 0x00; - break; - default: - break; - } - - return retval; -} - -/* M48T59 NVRAM/RTC emulation */ -static uint8_t NVRAM[NVRAM_SIZE]; - -/* RTC */ -static time_t time_offset; - -time_t get_time (void) -{ - return time(NULL) + time_offset; -} - -void set_time_offset (time_t new_time) -{ - time_t now = time(NULL); - - time_offset = new_time - now; -} - -static void NVRAM_init (void) -{ - /* NVRAM header */ - /* 0x00: NVRAM size in kB */ - NVRAM[0x00] = (NVRAM_SIZE >> 12) & 0xFF; - NVRAM[0x01] = (NVRAM_SIZE >> 10) & 0xFF; - /* 0x02: NVRAM version */ - NVRAM[0x02] = 0x01; - /* 0x03: NVRAM revision */ - NVRAM[0x03] = 0x00; - /* 0x04: checksum 0 => OS area */ - /* 0x06: checksum of config area */ - /* 0x08: last OS */ - NVRAM[0x08] = 0x00; /* Unknown */ - /* 0x09: endian */ - NVRAM[0x09] = 'B'; - /* 0x0B: PM mode */ - NVRAM[0x0B] = 0x00; - /* Restart block description record */ - /* 0x0C: restart block version */ - NVRAM[0x0C] = 0x00; - NVRAM[0x0D] = 0x01; - /* 0x0E: restart block revision */ - NVRAM[0x0E] = 0x00; - NVRAM[0x0F] = 0x00; - /* 0x1C: checksum of restart block */ - /* 0x20: restart address */ - NVRAM[0x20] = 0x00; - NVRAM[0x21] = 0x00; - NVRAM[0x22] = 0x00; - NVRAM[0x23] = 0x00; - /* 0x24: save area address */ - NVRAM[0x24] = 0x00; - NVRAM[0x25] = 0x00; - NVRAM[0x26] = 0x00; - NVRAM[0x27] = 0x00; - /* 0x28: save area length */ - NVRAM[0x28] = 0x00; - NVRAM[0x29] = 0x00; - NVRAM[0x2A] = 0x00; - NVRAM[0x2B] = 0x00; - /* Security section */ - /* Set all to zero */ - /* 0xC4: pointer to global environment area */ - NVRAM[0xC4] = 0x00; - NVRAM[0xC5] = 0x00; - NVRAM[0xC6] = 0x01; - NVRAM[0xC7] = 0x00; - /* 0xC8: size of global environment area */ - NVRAM[0xC8] = 0x00; - NVRAM[0xC9] = 0x00; - NVRAM[0xCA] = 0x07; - NVRAM[0xCB] = 0x00; - /* 0xD4: pointer to configuration area */ - NVRAM[0xD4] = 0x00; - NVRAM[0xD5] = 0x00; - NVRAM[0xD6] = 0x08; - NVRAM[0xD7] = 0x00; - /* 0xD8: size of configuration area */ - NVRAM[0xD8] = 0x00; - NVRAM[0xD9] = 0x00; - NVRAM[0xDA] = 0x08; - NVRAM[0xDB] = 0x00; - /* 0xE8: pointer to OS specific area */ - NVRAM[0xE8] = 0x00; - NVRAM[0xE9] = 0x00; - NVRAM[0xEA] = 0x10; - NVRAM[0xEB] = 0x00; - /* 0xD8: size of OS specific area */ - NVRAM[0xEC] = 0x00; - NVRAM[0xED] = 0x00; - NVRAM[0xEE] = 0x0F; - NVRAM[0xEF] = 0xF0; - /* CRC */ - /* RTC init */ - NVRAM[0x1FFC] = 0x50; -} - -static uint16_t NVRAM_addr; - -/* Direct access to NVRAM */ -void NVRAM_write (CPUState *env, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x1FF0: - /* flags register */ - break; - case 0x1FF1: - /* unused */ - break; - case 0x1FF2: - /* alarm seconds */ - break; - case 0x1FF3: - /* alarm minutes */ - break; - case 0x1FF4: - /* alarm hours */ - break; - case 0x1FF5: - /* alarm date */ - break; - case 0x1FF6: - /* interrupts */ - break; - case 0x1FF7: - /* watchdog */ - break; - case 0x1FF8: - /* control */ - break; - case 0x1FF9: - /* seconds (BCD) */ - break; - case 0x1FFA: - /* minutes (BCD) */ - break; - case 0x1FFB: - /* hours (BCD) */ - break; - case 0x1FFC: - /* day of the week / century */ - NVRAM[0x1FFC] = val & 0x50; - break; - case 0x1FFD: - /* date */ - break; - case 0x1FFE: - /* month */ - break; - case 0x1FFF: - /* year */ - break; - default: - if (addr < NVRAM_SIZE) - NVRAM[addr] = val & 0xFF; - break; - } -} - -uint32_t NVRAM_read (CPUState *env, uint32_t addr) -{ - struct tm tm; - time_t t; - uint32_t retval = 0xFF; - - switch (addr) { - case 0x1FF0: - /* flags register */ - break; - case 0x1FF1: - /* unused */ - break; - case 0x1FF2: - /* alarm seconds */ - break; - case 0x1FF3: - /* alarm minutes */ - break; - case 0x1FF4: - /* alarm hours */ - break; - case 0x1FF5: - /* alarm date */ - break; - case 0x1FF6: - /* interrupts */ - break; - case 0x1FF7: - /* watchdog */ - break; - case 0x1FF8: - /* control */ - break; - case 0x1FF9: - /* seconds (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_sec / 10) << 4) | (tm.tm_sec % 10); -// printf("return seconds=%d\n", tm.tm_sec); - break; - case 0x1FFA: - /* minutes (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_min / 10) << 4) | (tm.tm_min % 10); - break; - case 0x1FFB: - /* hours (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_hour / 10) << 4) | (tm.tm_hour % 10); - break; - case 0x1FFC: - /* day of the week / century */ - t = get_time(); - localtime_r(&t, &tm); - retval = (NVRAM[0x1FFC] & 0x50) | tm.tm_wday; - break; - case 0x1FFD: - /* date */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_mday / 10) << 4) | (tm.tm_mday % 10); - break; - case 0x1FFE: - /* month */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_mon / 10) << 4) | (tm.tm_mon % 10); - break; - case 0x1FFF: - /* year */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_year / 10) << 4) | (tm.tm_year % 10); - break; - default: - if (NVRAM_addr < NVRAM_SIZE) - retval = NVRAM[NVRAM_addr]; - break; - } - - return retval; -} - -/* IO access to NVRAM */ -static void NVRAM_writeb (CPUState *env, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x74: - NVRAM_addr &= ~0x00FF; - NVRAM_addr |= val; - break; - case 0x75: - NVRAM_addr &= ~0xFF00; - NVRAM_addr |= val << 8; - break; - case 0x77: - NVRAM_write(env, NVRAM_addr, val); - NVRAM_addr = 0x0000; - break; - default: - break; - } -} - -static uint32_t NVRAM_readb (CPUState *env, uint32_t addr) -{ - if (addr == 0x77) - return NVRAM_read(env, NVRAM_addr); - - return 0xFF; -} - -int load_initrd (const char *filename, uint8_t *addr) -{ - int fd, size; - - printf("Load initrd\n"); - fd = open(filename, O_RDONLY); - if (fd < 0) - return -1; - size = read(fd, addr, 16 * 1024 * 1024); - if (size < 0) - goto fail; - close(fd); - printf("Load initrd: %d\n", size); - return size; - fail: - close(fd); - printf("Load initrd failed\n"); - return -1; -} - -/* Quick hack for PPC memory infos... */ -static void put_long (void *addr, uint32_t l) -{ - char *pos = addr; - pos[0] = (l >> 24) & 0xFF; - pos[1] = (l >> 16) & 0xFF; - pos[2] = (l >> 8) & 0xFF; - pos[3] = l & 0xFF; -} - -/* bootloader infos are in the form: - * uint32_t TAG - * uint32_t TAG_size (from TAG to next TAG). - * datas - * .... - */ -#if !defined (USE_OPEN_FIRMWARE) -static void *set_bootinfo_tag (void *addr, uint32_t tag, uint32_t size, - void *data) -{ - char *pos = addr; - - put_long(pos, tag); - pos += 4; - put_long(pos, size + 8); - pos += 4; - memcpy(pos, data, size); - pos += size; - - return pos; -} -#endif - -typedef struct boot_dev_t { - const unsigned char *name; - int major; - int minor; -} boot_dev_t; - -static boot_dev_t boot_devs[] = -{ - { "/dev/fd0", 2, 0, }, - { "/dev/fd1", 2, 1, }, - { "/dev/hda1", 3, 1, }, -// { "/dev/ide/host0/bus0/target0/lun0/part1", 3, 1, }, - { "/dev/hdc", 22, 0, }, - { "/dev/ram0 init=/linuxrc", 1, 0, }, -}; - -/* BATU: - * BEPI : bloc virtual address - * BL : area size bits (128 kB is 0, 256 1, 512 3, ... - * Vs/Vp - * BATL: - * BPRN : bloc real address align on 4MB boundary - * WIMG : cache access mode : not used - * PP : protection bits - */ -static void setup_BAT (CPUPPCState *env, int BAT, - uint32_t virtual, uint32_t physical, - uint32_t size, int Vs, int Vp, int PP) -{ - uint32_t sz_bits, tmp_sz, align, tmp; - - sz_bits = 0; - align = 131072; - for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) { - sz_bits = (sz_bits << 1) + 1; - align = align << 1; - } - tmp = virtual & ~(align - 1); /* Align virtual area start */ - tmp |= sz_bits << 2; /* Fix BAT size */ - tmp |= Vs << 1; /* Supervisor access */ - tmp |= Vp; /* User access */ - env->DBAT[0][BAT] = tmp; - env->IBAT[0][BAT] = tmp; - tmp = physical & ~(align - 1); /* Align physical area start */ - tmp |= 0; /* Don't care about WIMG */ - tmp |= PP; /* Protection */ - env->DBAT[1][BAT] = tmp; - env->IBAT[1][BAT] = tmp; - printf("Set BATU0 to 0x%08x BATL0 to 0x%08x\n", - env->DBAT[0][BAT], env->DBAT[1][BAT]); -} - -static void VGA_printf (uint8_t *s) -{ - uint16_t *arg_ptr; - unsigned int format_width, i; - int in_format; - uint16_t arg, digit, nibble; - uint8_t c; - - arg_ptr = (uint16_t *)(&s); - in_format = 0; - format_width = 0; - while ((c = *s) != '\0') { - if (c == '%') { - in_format = 1; - format_width = 0; - } else if (in_format) { - if ((c >= '0') && (c <= '9')) { - format_width = (format_width * 10) + (c - '0'); - } else if (c == 'x') { - arg_ptr++; // increment to next arg - arg = *arg_ptr; - if (format_width == 0) - format_width = 4; - digit = format_width - 1; - for (i = 0; i < format_width; i++) { - nibble = (arg >> (4 * digit)) & 0x000f; - if (nibble <= 9) - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0'); - else - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A'); - digit--; - } - in_format = 0; - } - //else if (c == 'd') { - // in_format = 0; - // } - } else { - PPC_io_writeb(PPC_IO_BASE + 0x500, c); - } - s++; - } -} - -static void VGA_init (void) -{ - /* Basic VGA init, inspired by plex86 VGAbios */ - printf("Init VGA...\n"); - /* switch to color mode and enable CPU access 480 lines */ - PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); - /* more than 64k 3C4/04 */ - PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04); - PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02); - VGA_printf("PPC VGA BIOS...\n"); -} - -void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, - uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device) -{ - char *p; -#if !defined (USE_OPEN_FIRMWARE) - char *tmp; - uint32_t tmpi[2]; -#endif - int PPC_io_memory; - -#if defined (USE_OPEN_FIRMWARE) - setup_memory(env, mem_size); -#endif - /* Register 64 kB of IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); - cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); - /* Register fake IO ports for PREP */ - register_ioport_read(0x398, 2, PREP_io_read, 1); - register_ioport_write(0x398, 2, PREP_io_write, 1); - /* System control ports */ - register_ioport_write(0x0092, 0x1, PREP_io_800_writeb, 1); - register_ioport_read(0x0800, 0x52, PREP_io_800_readb, 1); - register_ioport_write(0x0800, 0x52, PREP_io_800_writeb, 1); - /* PCI intack location */ - PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); - cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); - /* NVRAM ports */ - NVRAM_init(); - register_ioport_read(0x0074, 0x04, NVRAM_readb, 1); - register_ioport_write(0x0074, 0x04, NVRAM_writeb, 1); - - /* Fake bootloader */ - env->nip = kernel_addr + (3 * sizeof(uint32_t)); - /* Set up msr according to PREP specification */ - msr_ee = 0; - msr_fp = 1; - msr_pr = 0; /* Start in supervisor mode */ - msr_me = 1; - msr_fe0 = msr_fe1 = 0; - msr_ip = 0; - msr_ir = msr_dr = 1; -// msr_sf = 0; - msr_le = msr_ile = 0; - env->gpr[1] = stack_addr; /* Let's have a stack */ - env->gpr[2] = 0; - env->gpr[8] = kernel_addr; - /* There is a bug in 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee, - * it's not ready to handle it... - */ - env->decr = 0xFFFFFFFF; - p = (void *)(phys_ram_base + kernel_addr); -#if !defined (USE_OPEN_FIRMWARE) - /* Let's register the whole memory available only in supervisor mode */ - setup_BAT(env, 0, 0x00000000, 0x00000000, mem_size, 1, 0, 2); - /* Avoid open firmware init call (to get a console) - * This will make the kernel think we are a PREP machine... - */ - put_long(p, 0xdeadc0de); - /* Build a real stack room */ - p = (void *)(phys_ram_base + stack_addr); - put_long(p, stack_addr); - p -= 32; - env->gpr[1] -= 32; - /* Pretend there are no residual data */ - env->gpr[3] = 0; -#if 1 - { - int size; - env->gpr[4] = 0x00800000; - size = load_initrd("initrd", - (void *)((uint32_t)phys_ram_base + env->gpr[4])); - if (size < 0) { - /* No initrd */ - env->gpr[4] = env->gpr[5] = 0; - } else { - env->gpr[5] = size; - boot_device = 'e'; - } - printf("Initrd loaded at 0x%08x (%d)\n", env->gpr[4], env->gpr[5]); - } -#else - env->gpr[4] = env->gpr[5] = 0; -#endif - /* We have to put bootinfos after the BSS - * The BSS starts after the kernel end. - */ -#if 0 - p = (void *)(((uint32_t)phys_ram_base + kernel_addr + - kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); -#else - p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); -#endif - if (loglevel > 0) { - fprintf(logfile, "bootinfos: %p 0x%08x\n", - p, (uint32_t)p - (uint32_t)phys_ram_base); - } else { - printf("bootinfos: %p 0x%08x\n", - p, (uint32_t)p - (uint32_t)phys_ram_base); - } - /* Command line: let's put it after bootinfos */ -#if 0 - sprintf(p + 0x1000, "console=ttyS0,9600 root=%02x%02x mem=%dM", - boot_devs[boot_device - 'a'].major, - boot_devs[boot_device - 'a'].minor, - phys_ram_size >> 20); -#else - sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM load_ramdisk=1", - boot_devs[boot_device - 'a'].name, - phys_ram_size >> 20); -#endif - env->gpr[6] = (uint32_t)p + 0x1000 - (uint32_t)phys_ram_base; - env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); - if (loglevel > 0) { - fprintf(logfile, "cmdline: %p 0x%08x [%s]\n", - p + 0x1000, env->gpr[6], p + 0x1000); - } else { - printf("cmdline: %p 0x%08x [%s]\n", - p + 0x1000, env->gpr[6], p + 0x1000); - } - /* BI_FIRST */ - p = set_bootinfo_tag(p, 0x1010, 0, 0); - /* BI_CMD_LINE */ - p = set_bootinfo_tag(p, 0x1012, env->gpr[7] - env->gpr[6], - (void *)(env->gpr[6] + (uint32_t)phys_ram_base)); - /* BI_MEM_SIZE */ - tmp = (void *)tmpi; - tmp[0] = (phys_ram_size >> 24) & 0xFF; - tmp[1] = (phys_ram_size >> 16) & 0xFF; - tmp[2] = (phys_ram_size >> 8) & 0xFF; - tmp[3] = phys_ram_size & 0xFF; - p = set_bootinfo_tag(p, 0x1017, 4, tmpi); - /* BI_INITRD */ - tmp[0] = (env->gpr[4] >> 24) & 0xFF; - tmp[1] = (env->gpr[4] >> 16) & 0xFF; - tmp[2] = (env->gpr[4] >> 8) & 0xFF; - tmp[3] = env->gpr[4] & 0xFF; - tmp[4] = (env->gpr[5] >> 24) & 0xFF; - tmp[5] = (env->gpr[5] >> 16) & 0xFF; - tmp[6] = (env->gpr[5] >> 8) & 0xFF; - tmp[7] = env->gpr[5] & 0xFF; - p = set_bootinfo_tag(p, 0x1014, 8, tmpi); - /* BI_LAST */ - p = set_bootinfo_tag(p, 0x1011, 0, 0); -#else - /* Set up MMU: - * kernel is loaded at kernel_addr and wants to be seen at 0x01000000 - */ - setup_BAT(env, 0, 0x01000000, kernel_addr, 0x00400000, 1, 0, 2); - { -#if 0 - uint32_t offset = - *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); -#else - uint32_t offset = 12; -#endif - env->nip = 0x01000000 | (kernel_addr + offset); - printf("Start address: 0x%08x\n", env->nip); - } - env->gpr[1] = env->nip + (1 << 22); - p = (void *)(phys_ram_base + stack_addr); - put_long(p - 32, stack_addr); - env->gpr[1] -= 32; - printf("Kernel starts at 0x%08x stack 0x%08x\n", env->nip, env->gpr[1]); - /* We want all lower address not to be translated */ - setup_BAT(env, 1, 0x00000000, 0x00000000, 0x010000000, 1, 1, 2); - /* We also need a BAT to access OF */ - setup_BAT(env, 2, 0xFFFE0000, mem_size - 131072, 131072, 1, 0, 1); - /* Setup OF entry point */ - { - char *p; - p = (char *)phys_ram_base + mem_size - 131072; - /* Special opcode to call OF */ - *p++ = 0x18; *p++ = 0x00; *p++ = 0x00; *p++ = 0x02; - /* blr */ - *p++ = 0x4E; *p++ = 0x80; *p++ = 0x00; *p++ = 0x20; - } - env->gpr[5] = 0xFFFE0000; - /* Register translations */ - { - OF_transl_t translations[3] = { - { 0x01000000, 0x00400000, kernel_addr, 0x00000002, }, - { 0x00000000, 0x01000000, 0x00000000, 0x00000002, }, - { 0xFFFE0000, 0x00020000, mem_size - (128 * 1024), - 0x00000001, }, - }; - OF_register_translations(3, translations); - } - /* Quite artificial, for now */ - OF_register_bus("isa", "isa"); - OF_register_serial("isa", "serial", 4, 0x3f8); - OF_register_stdio("serial", "serial"); - /* Set up RTAS service */ - RTAS_init(); - /* Command line: let's put it just over the stack */ -#if 1 - sprintf(p, "console=ttyS0,9600 root=%02x%02x mem=%dM", - boot_devs[boot_device - 'a'].major, - boot_devs[boot_device - 'a'].minor, - phys_ram_size >> 20); -#else - sprintf(p, "console=ttyS0,9600 root=%s mem=%dM ne2000=0x300,9", - boot_devs[boot_device - 'a'].name, - phys_ram_size >> 20); -#endif - OF_register_bootargs(p); -#endif -} - -void PPC_end_init (void) -{ - VGA_init(); -} diff --git a/target-ppc/op.c b/target-ppc/op.c index e47e245af..12c92891c 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -18,11 +18,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +//#define DEBUG_OP + #include "config.h" #include "exec.h" -//#define DEBUG_OP - #define regs (env) #define Ts0 (int32_t)T0 #define Ts1 (int32_t)T1 @@ -226,6 +226,17 @@ PPC_OP(process_exceptions) } } +PPC_OP(debug) +{ + env->nip = PARAM(1); + env->brkstate = 1; +#if defined (DEBUG_OP) + dump_state(); +#endif + do_queue_exception(EXCP_DEBUG); + RETURN(); +} + /* Segment registers load and store with immediate index */ PPC_OP(load_srin) { @@ -1443,10 +1454,9 @@ PPC_OP(fneg) } /* Load and store */ -#if defined(CONFIG_USER_ONLY) #define MEMSUFFIX _raw #include "op_mem.h" -#else +#if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user #include "op_mem.h" @@ -1460,8 +1470,11 @@ PPC_OP(rfi) T0 = regs->spr[SRR1] & ~0xFFFF0000; do_store_msr(); do_tlbia(); +#if defined (DEBUG_OP) dump_rfi(); +#endif regs->nip = regs->spr[SRR0] & ~0x00000003; + do_queue_exception(EXCP_RFI); if (env->exceptions != 0) { do_check_exception_state(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5bd138da5..0bb48e7a3 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -20,10 +20,9 @@ #include #include "exec.h" -#if defined(CONFIG_USER_ONLY) #define MEMSUFFIX _raw #include "op_helper_mem.h" -#else +#if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user #include "op_helper_mem.h" #define MEMSUFFIX _kernel @@ -122,8 +121,7 @@ void do_load_msr (void) void do_store_msr (void) { if (((T0 >> MSR_IR) & 0x01) != msr_ir || - ((T0 >> MSR_DR) & 0x01) != msr_dr || - ((T0 >> MSR_PR) & 0x01) != msr_pr) { + ((T0 >> MSR_DR) & 0x01) != msr_dr) { /* Flush all tlb when changing translation mode or privilege level */ do_tlbia(); } @@ -371,44 +369,18 @@ void do_tlbie (void) /*****************************************************************************/ /* Special helpers for debug */ +extern FILE *stdout; + +void dump_state (void) +{ + cpu_ppc_dump_state(env, stdout, 0); +} + void dump_rfi (void) { #if 0 - printf("Return from interrupt\n"); - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x\n", - env->nip, env->lr, env->ctr, - (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | (msr_ee << MSR_EE) | - (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_me << MSR_ME) | - (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | (msr_be << MSR_BE) | - (msr_fe1 << MSR_FE1) | (msr_ip << MSR_IP) | (msr_ir << MSR_IR) | - (msr_dr << MSR_DR) | (msr_ri << MSR_RI) | (msr_le << MSR_LE)); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); + printf("Return from interrupt %d => 0x%08x\n", pos, env->nip); + // cpu_ppc_dump_state(env, stdout, 0); #endif } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 97a0d27a2..bd0dc67d4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2168,22 +2168,48 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) /* dcbf */ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); } /* dcbi (Supervisor only) */ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) { -#if !defined(CONFIG_USER_ONLY) - if (!ctx->supervisor) -#endif - { +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(); +#else + if (!ctx->supervisor) { RET_PRIVOPC(); } + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); + op_ldst(stb); +#endif } /* dcdst */ GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); } /* dcbt */ @@ -2863,7 +2889,7 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x " "MSR=0x%08x\n", env->nip, env->lr, env->ctr, - _load_xer(), _load_msr()); + _load_xer(env), _load_msr(env)); for (i = 0; i < 32; i++) { if ((i & 7) == 0) fprintf(f, "GPR%02d:", i); @@ -2894,8 +2920,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) if ((i & 3) == 3) fprintf(f, "\n"); } - fprintf(f, "SRR0 0x%08x SRR1 0x%08x\n", - env->spr[SRR0], env->spr[SRR1]); + fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n", + env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions); fprintf(f, "reservation 0x%08x\n", env->reserve); fflush(f); } @@ -2934,6 +2960,7 @@ CPUPPCState *cpu_ppc_init(void) #if defined(CONFIG_USER_ONLY) msr_pr = 1; #endif + env->access_type = ACCESS_INT; return env; } @@ -2977,6 +3004,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, /* Single step trace mode */ msr_se = 1; #endif + env->access_type = ACCESS_CODE; /* Set env in case of segfault during code fetch */ while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { if (search_pc) { @@ -3073,9 +3101,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.exception = EXCP_TRACE; } } - /* if too long translation, stop generation too */ - if (gen_opc_ptr >= gen_opc_end || - ((uint32_t)ctx.nip - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + /* if we reach a page boundary, stop generation */ + if (((uint32_t)ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { if (ctx.exception == EXCP_NONE) { gen_op_b((long)ctx.tb, (uint32_t)ctx.nip); ctx.exception = EXCP_BRANCH; @@ -3111,6 +3138,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { tb->size = (uint32_t)ctx.nip - pc_start; } + env->access_type = ACCESS_INT; #ifdef DEBUG_DISAS if (loglevel > 0) { fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); diff --git a/translate-all.c b/translate-all.c index f10fb6257..137fdcad1 100644 --- a/translate-all.c +++ b/translate-all.c @@ -230,6 +230,9 @@ int cpu_restore_state(TranslationBlock *tb, CASE3(lfs): type = ACCESS_FLOAT; break; + CASE3(lwarx): + type = ACCESS_RES; + break; CASE3(stwcx): type = ACCESS_RES; break; diff --git a/vl.c b/vl.c index 84e869889..9463bd654 100644 --- a/vl.c +++ b/vl.c @@ -68,6 +68,8 @@ extern void __sigaction(); #include "exec-all.h" +//#define DO_TB_FLUSH + #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" //#define DEBUG_UNUSED_IOPORT @@ -1201,6 +1203,9 @@ int qemu_loadvm(const char *filename) goto the_end; } for(;;) { +#if defined (DO_TB_FLUSH) + tb_flush(); +#endif len = qemu_get_byte(f); if (feof(f)) break; @@ -1380,6 +1385,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) return 0; } +#elif defined(TARGET_PPC) +void cpu_save(QEMUFile *f, void *opaque) +{ +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} #else #warning No CPU save/restore functions @@ -1706,6 +1720,7 @@ int main(int argc, char **argv) const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs; + int start_emulation = 1; uint8_t macaddr[6]; #if !defined(CONFIG_SOFTMMU) @@ -1744,7 +1759,7 @@ int main(int argc, char **argv) nd_table[i].fd = -1; for(;;) { - c = getopt_long_only(argc, argv, "hm:d:n:sp:L:", long_options, &long_index); + c = getopt_long_only(argc, argv, "hm:d:n:sp:L:S", long_options, &long_index); if (c == -1) break; switch(c) { @@ -1915,6 +1930,9 @@ int main(int argc, char **argv) case 'L': bios_dir = optarg; break; + case 'S': + start_emulation = 0; + break; } } @@ -2121,7 +2139,9 @@ int main(int argc, char **argv) ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, initrd_filename); #elif defined(TARGET_PPC) - ppc_init(); + ppc_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); #endif /* launched after the device init so that it can display or not a @@ -2142,6 +2162,7 @@ int main(int argc, char **argv) } } else #endif + if (start_emulation) { vm_start(); } -- cgit v1.2.3 From c5df018e56855cd6ede7ab7b07fb69703d581383 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Apr 2004 20:54:52 +0000 Subject: ppc: suppressed unneeded globals and headers - added explicit type for ppc nvram git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@723 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 63 ++++++++++--------------- hw/m48t59.h | 10 ++-- hw/ppc.c | 2 - hw/ppc_prep.c | 146 +++++++++++++++++++++++++--------------------------------- vl.h | 1 + 5 files changed, 93 insertions(+), 129 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index fbee94fa6..dd303d21f 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -21,14 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - -#include -#include /* needed by vl.h */ -#include -#include -#include - #include "vl.h" +#include "m48t59.h" //#define NVRAM_DEBUG @@ -38,7 +32,7 @@ #define NVRAM_PRINTF(fmt, args...) do { } while (0) #endif -typedef struct m48t59_t { +struct m48t59_t { /* Hardware parameters */ int IRQ; uint32_t io_base; @@ -53,10 +47,7 @@ typedef struct m48t59_t { /* NVRAM storage */ uint16_t addr; uint8_t *buffer; -} m48t59_t; - -static m48t59_t *NVRAMs; -static int nb_NVRAMs; +}; /* Fake timer functions */ /* Generic helpers for BCD */ @@ -185,9 +176,8 @@ static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) } /* Direct access to NVRAM */ -void m48t59_write (void *opaque, uint32_t val) +void m48t59_write (m48t59_t *NVRAM, uint32_t val) { - m48t59_t *NVRAM = opaque; struct tm tm; int tmp; @@ -333,9 +323,8 @@ void m48t59_write (void *opaque, uint32_t val) } } -uint32_t m48t59_read (void *opaque) +uint32_t m48t59_read (m48t59_t *NVRAM) { - m48t59_t *NVRAM = opaque; struct tm tm; uint32_t retval = 0xFF; @@ -418,10 +407,8 @@ uint32_t m48t59_read (void *opaque) return retval; } -void m48t59_set_addr (void *opaque, uint32_t addr) +void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr) { - m48t59_t *NVRAM = opaque; - NVRAM->addr = addr; } @@ -460,27 +447,25 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) } /* Initialisation routine */ -void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) +m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) { - m48t59_t *tmp; + m48t59_t *s; - tmp = realloc(NVRAMs, (nb_NVRAMs + 1) * sizeof(m48t59_t)); - if (tmp == NULL) + s = qemu_mallocz(sizeof(m48t59_t)); + if (!s) return NULL; - NVRAMs = tmp; - tmp[nb_NVRAMs].buffer = malloc(size); - if (tmp[nb_NVRAMs].buffer == NULL) - return NULL; - memset(tmp[nb_NVRAMs].buffer, 0, size); - tmp[nb_NVRAMs].IRQ = IRQ; - tmp[nb_NVRAMs].size = size; - tmp[nb_NVRAMs].io_base = io_base; - tmp[nb_NVRAMs].addr = 0; - register_ioport_read(io_base, 0x04, 1, NVRAM_readb, &NVRAMs[nb_NVRAMs]); - register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, &NVRAMs[nb_NVRAMs]); - tmp[nb_NVRAMs].alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, - &tmp[nb_NVRAMs]); - tmp[nb_NVRAMs].wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, - &tmp[nb_NVRAMs]); - return &NVRAMs[nb_NVRAMs++]; + s->buffer = qemu_mallocz(size); + if (!s->buffer) { + qemu_free(s); + return NULL; + } + s->IRQ = IRQ; + s->size = size; + s->io_base = io_base; + s->addr = 0; + register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); + register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); + s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); + s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); + return s; } diff --git a/hw/m48t59.h b/hw/m48t59.h index f73846d98..4b801bca3 100644 --- a/hw/m48t59.h +++ b/hw/m48t59.h @@ -1,9 +1,11 @@ #if !defined (__M48T59_H__) #define __M48T59_H__ -void m48t59_write (void *opaque, uint32_t val); -uint32_t m48t59_read (void *opaque); -void m48t59_set_addr (void *opaque, uint32_t addr); -void *m48t59_init (int IRQ, uint32_t io_base, uint16_t size); +typedef struct m48t59_t m48t59_t; + +void m48t59_write (m48t59_t *NVRAM, uint32_t val); +uint32_t m48t59_read (m48t59_t *NVRAM); +void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr); +m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size); #endif /* !defined (__M48T59_H__) */ diff --git a/hw/ppc.c b/hw/ppc.c index cd485bc84..7cba03b36 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -21,8 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - -#include #include "vl.h" void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 32b2ce805..dd2369162 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -21,26 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" #include "vl.h" #include "m48t59.h" @@ -209,8 +189,6 @@ static CPUReadMemoryFunc *PPC_io_read[] = { &PPC_io_readl, }; -uint32_t pic_intack_read(CPUState *env); - /* Read-only register (?) */ static void _PPC_ioB_write (uint32_t addr, uint32_t value, uint32_t vaddr) { @@ -368,63 +346,63 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) #define NVRAM_OSAREA_SIZE 512 #define NVRAM_CONFSIZE 1024 -static inline void NVRAM_set_byte (void *opaque, uint32_t addr, uint8_t value) +static inline void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) { - m48t59_set_addr(opaque, addr); - m48t59_write(opaque, value); + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value); } -static inline uint8_t NVRAM_get_byte (void *opaque, uint32_t addr) +static inline uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) { - m48t59_set_addr(opaque, addr); - return m48t59_read(opaque); + m48t59_set_addr(nvram, addr); + return m48t59_read(nvram); } -static inline void NVRAM_set_word (void *opaque, uint32_t addr, uint16_t value) +static inline void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) { - m48t59_set_addr(opaque, addr); - m48t59_write(opaque, value >> 8); - m48t59_set_addr(opaque, addr + 1); - m48t59_write(opaque, value & 0xFF); + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value >> 8); + m48t59_set_addr(nvram, addr + 1); + m48t59_write(nvram, value & 0xFF); } -static inline uint16_t NVRAM_get_word (void *opaque, uint32_t addr) +static inline uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) { uint16_t tmp; - m48t59_set_addr(opaque, addr); - tmp = m48t59_read(opaque) << 8; - m48t59_set_addr(opaque, addr + 1); - tmp |= m48t59_read(opaque); + m48t59_set_addr(nvram, addr); + tmp = m48t59_read(nvram) << 8; + m48t59_set_addr(nvram, addr + 1); + tmp |= m48t59_read(nvram); return tmp; } -static inline void NVRAM_set_lword (void *opaque, uint32_t addr, +static inline void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) { - m48t59_set_addr(opaque, addr); - m48t59_write(opaque, value >> 24); - m48t59_set_addr(opaque, addr + 1); - m48t59_write(opaque, (value >> 16) & 0xFF); - m48t59_set_addr(opaque, addr + 2); - m48t59_write(opaque, (value >> 8) & 0xFF); - m48t59_set_addr(opaque, addr + 3); - m48t59_write(opaque, value & 0xFF); + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value >> 24); + m48t59_set_addr(nvram, addr + 1); + m48t59_write(nvram, (value >> 16) & 0xFF); + m48t59_set_addr(nvram, addr + 2); + m48t59_write(nvram, (value >> 8) & 0xFF); + m48t59_set_addr(nvram, addr + 3); + m48t59_write(nvram, value & 0xFF); } -static inline uint32_t NVRAM_get_lword (void *opaque, uint32_t addr) +static inline uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) { uint32_t tmp; - m48t59_set_addr(opaque, addr); - tmp = m48t59_read(opaque) << 24; - m48t59_set_addr(opaque, addr + 1); - tmp |= m48t59_read(opaque) << 16; - m48t59_set_addr(opaque, addr + 2); - tmp |= m48t59_read(opaque) << 8; - m48t59_set_addr(opaque, addr + 3); - tmp |= m48t59_read(opaque); + m48t59_set_addr(nvram, addr); + tmp = m48t59_read(nvram) << 24; + m48t59_set_addr(nvram, addr + 1); + tmp |= m48t59_read(nvram) << 16; + m48t59_set_addr(nvram, addr + 2); + tmp |= m48t59_read(nvram) << 8; + m48t59_set_addr(nvram, addr + 3); + tmp |= m48t59_read(nvram); return tmp; } @@ -444,7 +422,7 @@ static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) return tmp; } -static void NVRAM_set_crc (void *opaque, uint32_t addr, +static void NVRAM_set_crc (m48t59_t *nvram, uint32_t addr, uint32_t start, uint32_t count) { uint32_t i; @@ -455,74 +433,74 @@ static void NVRAM_set_crc (void *opaque, uint32_t addr, odd = 1; count &= ~1; for (i = 0; i != count; i++) { - crc = NVRAM_crc_update(crc, NVRAM_get_word(opaque, start + i)); + crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); } if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(opaque, start + i) << 8); + crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); } - NVRAM_set_word(opaque, addr, crc); + NVRAM_set_word(nvram, addr, crc); } static void prep_NVRAM_init (void) { - void *opaque; + m48t59_t *nvram; - opaque = m48t59_init(8, 0x0074, NVRAM_SIZE); + nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); /* NVRAM header */ /* 0x00: NVRAM size in kB */ - NVRAM_set_word(opaque, 0x00, NVRAM_SIZE >> 10); + NVRAM_set_word(nvram, 0x00, NVRAM_SIZE >> 10); /* 0x02: NVRAM version */ - NVRAM_set_byte(opaque, 0x02, 0x01); + NVRAM_set_byte(nvram, 0x02, 0x01); /* 0x03: NVRAM revision */ - NVRAM_set_byte(opaque, 0x03, 0x01); + NVRAM_set_byte(nvram, 0x03, 0x01); /* 0x08: last OS */ - NVRAM_set_byte(opaque, 0x08, 0x00); /* Unknown */ + NVRAM_set_byte(nvram, 0x08, 0x00); /* Unknown */ /* 0x09: endian */ - NVRAM_set_byte(opaque, 0x09, 'B'); /* Big-endian */ + NVRAM_set_byte(nvram, 0x09, 'B'); /* Big-endian */ /* 0x0A: OSArea usage */ - NVRAM_set_byte(opaque, 0x0A, 0x00); /* Empty */ + NVRAM_set_byte(nvram, 0x0A, 0x00); /* Empty */ /* 0x0B: PM mode */ - NVRAM_set_byte(opaque, 0x0B, 0x00); /* Normal */ + NVRAM_set_byte(nvram, 0x0B, 0x00); /* Normal */ /* Restart block description record */ /* 0x0C: restart block version */ - NVRAM_set_word(opaque, 0x0C, 0x01); + NVRAM_set_word(nvram, 0x0C, 0x01); /* 0x0E: restart block revision */ - NVRAM_set_word(opaque, 0x0E, 0x01); + NVRAM_set_word(nvram, 0x0E, 0x01); /* 0x20: restart address */ - NVRAM_set_lword(opaque, 0x20, 0x00); + NVRAM_set_lword(nvram, 0x20, 0x00); /* 0x24: save area address */ - NVRAM_set_lword(opaque, 0x24, 0x00); + NVRAM_set_lword(nvram, 0x24, 0x00); /* 0x28: save area length */ - NVRAM_set_lword(opaque, 0x28, 0x00); + NVRAM_set_lword(nvram, 0x28, 0x00); /* 0x1C: checksum of restart block */ - NVRAM_set_crc(opaque, 0x1C, 0x0C, 32); + NVRAM_set_crc(nvram, 0x1C, 0x0C, 32); /* Security section */ /* Set all to zero */ /* 0xC4: pointer to global environment area */ - NVRAM_set_lword(opaque, 0xC4, 0x0100); + NVRAM_set_lword(nvram, 0xC4, 0x0100); /* 0xC8: size of global environment area */ - NVRAM_set_lword(opaque, 0xC8, + NVRAM_set_lword(nvram, 0xC8, NVRAM_END - NVRAM_OSAREA_SIZE - NVRAM_CONFSIZE - 0x0100); /* 0xD4: pointer to configuration area */ - NVRAM_set_lword(opaque, 0xD4, NVRAM_END - NVRAM_CONFSIZE); + NVRAM_set_lword(nvram, 0xD4, NVRAM_END - NVRAM_CONFSIZE); /* 0xD8: size of configuration area */ - NVRAM_set_lword(opaque, 0xD8, NVRAM_CONFSIZE); + NVRAM_set_lword(nvram, 0xD8, NVRAM_CONFSIZE); /* 0xE8: pointer to OS specific area */ - NVRAM_set_lword(opaque, 0xE8, + NVRAM_set_lword(nvram, 0xE8, NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); /* 0xD8: size of OS specific area */ - NVRAM_set_lword(opaque, 0xEC, NVRAM_OSAREA_SIZE); + NVRAM_set_lword(nvram, 0xEC, NVRAM_OSAREA_SIZE); /* Configuration area */ /* RTC init */ - // NVRAM_set_lword(opaque, 0x1FFC, 0x50); + // NVRAM_set_lword(nvram, 0x1FFC, 0x50); /* 0x04: checksum 0 => OS area */ - NVRAM_set_crc(opaque, 0x04, 0x00, + NVRAM_set_crc(nvram, 0x04, 0x00, NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); /* 0x06: checksum of config area */ - NVRAM_set_crc(opaque, 0x06, NVRAM_END - NVRAM_CONFSIZE, NVRAM_CONFSIZE); + NVRAM_set_crc(nvram, 0x06, NVRAM_END - NVRAM_CONFSIZE, NVRAM_CONFSIZE); } int load_initrd (const char *filename, uint8_t *addr) diff --git a/vl.h b/vl.h index 65c8f08ae..cd49e97a9 100644 --- a/vl.h +++ b/vl.h @@ -416,6 +416,7 @@ void serial_receive_break(SerialState *s); void pic_set_irq(int irq, int level); void pic_init(void); +uint32_t pic_intack_read(CPUState *env); /* i8254.c */ -- cgit v1.2.3 From f186904281e40152e1882dbc41653b6560014501 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Apr 2004 20:58:23 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@724 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c52db9804..167b000b4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.3 \ No newline at end of file +0.5.4 \ No newline at end of file -- cgit v1.2.3 From 95917e3f575cb98fd00d88fd6991f5e3fa399b51 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 15 Apr 2004 22:13:27 +0000 Subject: suppressed no longer needed vm86 segment hack (Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@725 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 7e0e777af..27a7a5559 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -758,23 +758,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (new_stack) { if (env->eflags & VM_MASK) { - /* XXX: explain me why W2K hangs if the whole segment cache is - reset ? */ -#if 1 - env->segs[R_ES].selector = 0; - env->segs[R_ES].flags = 0; - env->segs[R_DS].selector = 0; - env->segs[R_DS].flags = 0; - env->segs[R_FS].selector = 0; - env->segs[R_FS].flags = 0; - env->segs[R_GS].selector = 0; - env->segs[R_GS].flags = 0; -#else cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0, 0); cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0, 0); cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0, 0); cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0, 0); -#endif } ss = (ss & ~3) | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, -- cgit v1.2.3 From 2aebb3eb2b939d996ef6a905b42c70931e02a8ba Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 15 Apr 2004 22:28:04 +0000 Subject: blanking support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@726 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index f05dd1c57..1321f7b24 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -109,7 +109,8 @@ typedef struct VGAState { uint32_t line_compare; uint32_t start_addr; uint8_t last_cw, last_ch; - uint32_t last_width, last_height; + uint32_t last_width, last_height; /* in chars or pixels */ + uint32_t last_scr_width, last_scr_height; /* in pixels */ uint8_t cursor_start, cursor_end; uint32_t cursor_offset; unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); @@ -1155,7 +1156,9 @@ static void vga_draw_text(VGAState *s, int full_update) } if (width != s->last_width || height != s->last_height || cw != s->last_cw || cheight != s->last_ch) { - dpy_resize(s->ds, width * cw, height * cheight); + s->last_scr_width = width * cw; + s->last_scr_height = height * cheight; + dpy_resize(s->ds, s->last_scr_width, s->last_scr_height); s->last_width = width; s->last_height = height; s->last_ch = cheight; @@ -1412,6 +1415,8 @@ static void vga_draw_graphic(VGAState *s, int full_update) if (disp_width != s->last_width || height != s->last_height) { dpy_resize(s->ds, disp_width, height); + s->last_scr_width = disp_width; + s->last_scr_height = height; s->last_width = disp_width; s->last_height = height; full_update = 1; @@ -1494,6 +1499,33 @@ static void vga_draw_graphic(VGAState *s, int full_update) } } +static void vga_draw_blank(VGAState *s, int full_update) +{ + int i, w, val; + uint8_t *d; + + if (!full_update) + return; + if (s->last_scr_width <= 0 || s->last_scr_height <= 0) + return; + if (s->ds->depth == 8) + val = s->rgb_to_pixel(0, 0, 0); + else + val = 0; + w = s->last_scr_width * ((s->ds->depth + 7) >> 3); + d = s->ds->data; + for(i = 0; i < s->last_scr_height; i++) { + memset(d, val, w); + d += s->ds->linesize; + } + dpy_update(s->ds, 0, 0, + s->last_scr_width, s->last_scr_height); +} + +#define GMODE_TEXT 0 +#define GMODE_GRAPH 1 +#define GMODE_BLANK 2 + void vga_update_display(void) { VGAState *s = &vga_state; @@ -1519,15 +1551,27 @@ void vga_update_display(void) } full_update = 0; - graphic_mode = s->gr[6] & 1; + if (!(s->ar_index & 0x20)) { + graphic_mode = GMODE_BLANK; + } else { + graphic_mode = s->gr[6] & 1; + } if (graphic_mode != s->graphic_mode) { s->graphic_mode = graphic_mode; full_update = 1; } - if (graphic_mode) - vga_draw_graphic(s, full_update); - else + switch(graphic_mode) { + case GMODE_TEXT: vga_draw_text(s, full_update); + break; + case GMODE_GRAPH: + vga_draw_graphic(s, full_update); + break; + case GMODE_BLANK: + default: + vga_draw_blank(s, full_update); + break; + } } } -- cgit v1.2.3 From 3294b949eb97f41e29432830370eba62a6d5f28d Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 15 Apr 2004 22:35:16 +0000 Subject: avoid segfault if transient invalid text resolution git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@727 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/vga.c b/hw/vga.c index 1321f7b24..3a634a4d5 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1154,6 +1154,11 @@ static void vga_draw_text(VGAState *s, int full_update) ((s->cr[0x07] & 0x40) << 3); height = (height + 1) / cheight; } + if ((height * width) > CH_ATTR_SIZE) { + /* better than nothing: exit if transient size is too big */ + return; + } + if (width != s->last_width || height != s->last_height || cw != s->last_cw || cheight != s->last_ch) { s->last_scr_width = width * cw; -- cgit v1.2.3 From 202a456a2b2f6f331ee97618a485d8a74599a047 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 Apr 2004 22:09:02 +0000 Subject: safer sb16 code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@728 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sb16.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/hw/sb16.c b/hw/sb16.c index b2d20ded8..472d4c566 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -26,7 +26,6 @@ #define MIN(a, b) ((a)>(b)?(b):(a)) #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) -#define DEREF(x) (void)x #define log(...) fprintf (stderr, "sb16: " __VA_ARGS__) /* #define DEBUG_SB16 */ @@ -83,7 +82,7 @@ typedef struct SB16State { /* mixer state */ int mixer_nreg; - uint8_t mixer_regs[0x83]; + uint8_t mixer_regs[256]; } SB16State; /* XXX: suppress that and use a context */ @@ -192,6 +191,12 @@ static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len) dsp.speaker = 1; } +static inline void dsp_out_data(SB16State *dsp, int val) +{ + if (dsp->out_data_len < sizeof(dsp->out_data)) + dsp->out_data[dsp->out_data_len++] = val; +} + static void command (SB16State *dsp, uint8_t cmd) { linfo ("%#x\n", cmd); @@ -228,7 +233,7 @@ static void command (SB16State *dsp, uint8_t cmd) break; case 0x20: - dsp->out_data[dsp->out_data_len++] = 0xff; + dsp_out_data(dsp, 0xff); break; case 0x35: @@ -315,12 +320,12 @@ static void command (SB16State *dsp, uint8_t cmd) break; case 0xe1: - dsp->out_data[dsp->out_data_len++] = sb.ver_lo; - dsp->out_data[dsp->out_data_len++] = sb.ver_hi; + dsp_out_data(dsp, sb.ver_lo); + dsp_out_data(dsp, sb.ver_hi); return; case 0xf2: - dsp->out_data[dsp->out_data_len++] = 0xaa; + dsp_out_data(dsp, 0xaa); dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; pic_set_irq (sb.irq, 1); return; @@ -398,9 +403,9 @@ static void complete (SB16State *dsp) break; case 0xe0: - dsp->out_data_len = 1; + dsp->out_data_len = 0; linfo ("data = %#x\n", dsp->in_data[0]); - dsp->out_data[0] = dsp->in_data[0] ^ 0xff; + dsp_out_data(dsp, dsp->in_data[0] ^ 0xff); break; default: @@ -426,7 +431,7 @@ static IO_WRITE_PROTO (dsp_write) dsp->v2x6 = 0; else if ((1 == val) && (0 == dsp->v2x6)) { dsp->v2x6 = 1; - dsp->out_data[dsp->out_data_len++] = 0xaa; + dsp_out_data(dsp, 0xaa); } else dsp->v2x6 = ~0; @@ -519,12 +524,15 @@ static IO_READ_PROTO (dsp_read) static IO_WRITE_PROTO(mixer_write_indexb) { SB16State *dsp = opaque; - dsp->mixer_nreg = val & 0xff; + dsp->mixer_nreg = val; } static IO_WRITE_PROTO(mixer_write_datab) { SB16State *dsp = opaque; + + if (dsp->mixer_nreg > 0x83) + return; dsp->mixer_regs[dsp->mixer_nreg] = val; } @@ -666,6 +674,7 @@ static int magic_of_irq (int irq) } } +#if 0 static int irq_of_magic (int magic) { switch (magic) { @@ -682,6 +691,7 @@ static int irq_of_magic (int magic) return 2; } } +#endif void SB16_init (void) { @@ -690,12 +700,12 @@ void SB16_init (void) static const uint8_t dsp_write_ports[] = {0x6, 0xc}; static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; + memset(s->mixer_regs, 0xff, sizeof(s->mixer_regs)); + s->mixer_regs[0x0e] = ~0; s->mixer_regs[0x80] = magic_of_irq (sb.irq); s->mixer_regs[0x81] = 0x20 | (sb.dma << 1); - DEREF (irq_of_magic); - for (i = 0x30; i < 0x48; i++) { s->mixer_regs[i] = 0x20; } -- cgit v1.2.3 From 92cb7d5423ed30a51ed9c9ea60cc674d4fa68820 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 Apr 2004 22:17:49 +0000 Subject: NT mouse fix (Mark Jonckheere) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@729 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/pckbd.c b/hw/pckbd.c index ae2cf27f1..2328d209f 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -445,6 +445,10 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) s->mouse_dx += dx; s->mouse_dy -= dy; s->mouse_dz += dz; + /* XXX: SDL sometimes generates nul events: we delete them */ + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && + s->mouse_buttons == buttons_state) + return; s->mouse_buttons = buttons_state; if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && -- cgit v1.2.3 From c20709aa32045c79e21905c4c009aae53d008af5 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 21 Apr 2004 23:27:19 +0000 Subject: initial user mode network support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@730 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 7 ++ vl.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++--------------- vl.h | 33 ++++--- 3 files changed, 266 insertions(+), 84 deletions(-) diff --git a/configure b/configure index 059648c49..b5f3e7a4f 100755 --- a/configure +++ b/configure @@ -71,6 +71,7 @@ bigendian="no" mingw32="no" EXESUF="" gdbstub="yes" +slirp="no" # OS specific targetos=`uname -s` @@ -124,6 +125,8 @@ for opt do ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ;; + --enable-slirp) slirp="yes" + ;; esac done @@ -378,6 +381,10 @@ if test "$sdl" = "yes" ; then fi echo "" >> $config_mak fi +if test "$slirp" = "yes" ; then + echo "CONFIG_SLIRP=yes" >> $config_mak + echo "#define CONFIG_SLIRP 1" >> $config_h +fi echo -n "VERSION=" >>$config_mak head $source_path/VERSION >>$config_mak echo "" >>$config_mak diff --git a/vl.c b/vl.c index 9463bd654..a2eb8c3f7 100644 --- a/vl.c +++ b/vl.c @@ -45,6 +45,10 @@ #include #endif +#if defined(CONFIG_SLIRP) +#include "libslirp.h" +#endif + #ifdef _WIN32 #include #include @@ -750,20 +754,121 @@ int serial_open_device(void) #endif /***********************************************************/ -/* Linux network device redirector */ +/* Linux network device redirectors */ -#ifdef _WIN32 +void hex_dump(FILE *f, const uint8_t *buf, int size) +{ + int len, i, j, c; + + for(i=0;i 16) + len = 16; + fprintf(f, "%08x ", i); + for(j=0;j<16;j++) { + if (j < len) + fprintf(f, " %02x", buf[i+j]); + else + fprintf(f, " "); + } + fprintf(f, " "); + for(j=0;j '~') + c = '.'; + fprintf(f, "%c", c); + } + fprintf(f, "\n"); + } +} + +void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ + nd->send_packet(nd, buf, size); +} -static int net_init(void) +void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) { + nd->add_read_packet(nd, fd_can_read, fd_read, opaque); +} + +/* dummy network adapter */ + +static void dummy_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ +} + +static void dummy_add_read_packet(NetDriverState *nd, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ +} + +static int net_dummy_init(NetDriverState *nd) +{ + nd->send_packet = dummy_send_packet; + nd->add_read_packet = dummy_add_read_packet; + pstrcpy(nd->ifname, sizeof(nd->ifname), "dummy"); return 0; } -void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +#if defined(CONFIG_SLIRP) + +/* slirp network adapter */ + +static void *slirp_fd_opaque; +static IOCanRWHandler *slirp_fd_can_read; +static IOReadHandler *slirp_fd_read; +static int slirp_inited; + +int slirp_can_output(void) +{ + return slirp_fd_can_read(slirp_fd_opaque); +} + +void slirp_output(const uint8_t *pkt, int pkt_len) { +#if 0 + printf("output:\n"); + hex_dump(stdout, pkt, pkt_len); +#endif + slirp_fd_read(slirp_fd_opaque, pkt, pkt_len); } -#else +static void slirp_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ +#if 0 + printf("input:\n"); + hex_dump(stdout, buf, size); +#endif + slirp_input(buf, size); +} + +static void slirp_add_read_packet(NetDriverState *nd, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + slirp_fd_opaque = opaque; + slirp_fd_can_read = fd_can_read; + slirp_fd_read = fd_read; +} + +static int net_slirp_init(NetDriverState *nd) +{ + if (!slirp_inited) { + slirp_inited = 1; + slirp_init(); + } + nd->send_packet = slirp_send_packet; + nd->add_read_packet = slirp_add_read_packet; + pstrcpy(nd->ifname, sizeof(nd->ifname), "slirp"); + return 0; +} + +#endif /* CONFIG_SLIRP */ + +#if !defined(_WIN32) static int tun_open(char *ifname, int ifname_size) { @@ -790,60 +895,61 @@ static int tun_open(char *ifname, int ifname_size) return fd; } -static int net_init(void) +static void tun_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ + write(nd->fd, buf, size); +} + +static void tun_add_read_packet(NetDriverState *nd, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) { - int pid, status, launch_script, i; - NetDriverState *nd; - char *args[MAX_NICS + 2]; + qemu_add_fd_read_handler(nd->fd, fd_can_read, fd_read, opaque); +} + +static int net_tun_init(NetDriverState *nd) +{ + int pid, status; + char *args[3]; char **parg; - launch_script = 0; - for(i = 0; i < nb_nics; i++) { - nd = &nd_table[i]; - if (nd->fd < 0) { - nd->fd = tun_open(nd->ifname, sizeof(nd->ifname)); - if (nd->fd >= 0) - launch_script = 1; - } - } + nd->fd = tun_open(nd->ifname, sizeof(nd->ifname)); + if (nd->fd < 0) + return -1; - if (launch_script) { - /* try to launch network init script */ - pid = fork(); - if (pid >= 0) { - if (pid == 0) { - parg = args; - *parg++ = network_script; - for(i = 0; i < nb_nics; i++) { - nd = &nd_table[i]; - if (nd->fd >= 0) { - *parg++ = nd->ifname; - } - } - *parg++ = NULL; - execv(network_script, args); - exit(1); - } - while (waitpid(pid, &status, 0) != pid); - if (!WIFEXITED(status) || - WEXITSTATUS(status) != 0) { - fprintf(stderr, "%s: could not launch network script\n", - network_script); - } + /* try to launch network init script */ + pid = fork(); + if (pid >= 0) { + if (pid == 0) { + parg = args; + *parg++ = network_script; + *parg++ = nd->ifname; + *parg++ = NULL; + execv(network_script, args); + exit(1); + } + while (waitpid(pid, &status, 0) != pid); + if (!WIFEXITED(status) || + WEXITSTATUS(status) != 0) { + fprintf(stderr, "%s: could not launch network script\n", + network_script); } } + nd->send_packet = tun_send_packet; + nd->add_read_packet = tun_add_read_packet; return 0; } -void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +static int net_fd_init(NetDriverState *nd, int fd) { -#ifdef DEBUG_NE2000 - printf("NE2000: sending packet size=%d\n", size); -#endif - write(nd->fd, buf, size); + nd->fd = fd; + nd->send_packet = tun_send_packet; + nd->add_read_packet = tun_add_read_packet; + pstrcpy(nd->ifname, sizeof(nd->ifname), "tunfd"); + return 0; } -#endif +#endif /* !_WIN32 */ /***********************************************************/ /* dumb display */ @@ -1597,6 +1703,28 @@ int main_loop(void) } } } + +#if defined(CONFIG_SLIRP) + /* XXX: merge with poll() */ + if (slirp_inited) { + fd_set rfds, wfds, xfds; + int nfds; + struct timeval tv; + + nfds = -1; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + slirp_select_fill(&nfds, &rfds, &wfds, &xfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); + if (ret >= 0) { + slirp_select_poll(&rfds, &wfds, &xfds); + } + } +#endif + #endif if (vm_running) { @@ -1636,10 +1764,14 @@ void help(void) "-nographic disable graphical output and redirect serial I/Os to console\n" "\n" "Network options:\n" - "-n script set network init script [default=%s]\n" - "-nics n simulate 'n' network interfaces [default=1]\n" + "-nics n simulate 'n' network cards [default=1]\n" "-macaddr addr set the mac address of the first interface\n" - "-tun-fd fd0[,...] use these fds as already opened tap/tun interfaces\n" + "-n script set tap/tun network init script [default=%s]\n" + "-tun-fd fd use this fd as already opened tap/tun interface\n" +#ifdef CONFIG_SLIRP + "-user-net use user mode network stack [default if no tap/tun script]\n" +#endif + "-dummy-net use dummy network stack\n" "\n" "Linux boot specific:\n" "-kernel bzImage use 'bzImage' as kernel image\n" @@ -1695,6 +1827,8 @@ struct option long_options[] = { { "no-code-copy", 0, NULL, 0 }, { "nics", 1, NULL, 0 }, { "macaddr", 1, NULL, 0 }, + { "user-net", 1, NULL, 0 }, + { "dummy-net", 1, NULL, 0 }, { NULL, 0, NULL, 0 }, }; @@ -1707,6 +1841,10 @@ static uint8_t *signal_stack; #endif +#define NET_IF_TUN 0 +#define NET_IF_USER 1 +#define NET_IF_DUMMY 2 + int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB @@ -1722,7 +1860,8 @@ int main(int argc, char **argv) int cyls, heads, secs; int start_emulation = 1; uint8_t macaddr[6]; - + int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; + #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); @@ -1746,6 +1885,8 @@ int main(int argc, char **argv) has_cdrom = 1; cyls = heads = secs = 0; + nb_tun_fds = 0; + net_if_type = -1; nb_nics = 1; /* default mac address of the first network interface */ macaddr[0] = 0x52; @@ -1754,10 +1895,8 @@ int main(int argc, char **argv) macaddr[3] = 0x12; macaddr[4] = 0x34; macaddr[5] = 0x56; - - for(i = 0; i < MAX_NICS; i++) - nd_table[i].fd = -1; - + + for(;;) { c = getopt_long_only(argc, argv, "hm:d:n:sp:L:S", long_options, &long_index); if (c == -1) @@ -1809,23 +1948,13 @@ int main(int argc, char **argv) { const char *p; int fd; - p = optarg; - nb_nics = 0; - for(;;) { - fd = strtol(p, (char **)&p, 0); - nd_table[nb_nics].fd = fd; - snprintf(nd_table[nb_nics].ifname, - sizeof(nd_table[nb_nics].ifname), - "fd%d", nb_nics); - nb_nics++; - if (*p == ',') { - p++; - } else if (*p != '\0') { - fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_nics); + if (nb_tun_fds < MAX_NICS) { + fd = strtol(optarg, (char **)&p, 0); + if (*p != '\0') { + fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_tun_fds); exit(1); - } else { - break; } + tun_fds[nb_tun_fds++] = fd; } } break; @@ -1885,6 +2014,12 @@ int main(int argc, char **argv) } } break; + case 18: + net_if_type = NET_IF_USER; + break; + case 19: + net_if_type = NET_IF_DUMMY; + break; } break; case 'h': @@ -1965,8 +2100,18 @@ int main(int argc, char **argv) #endif /* init host network redirectors */ - for(i = 0; i < MAX_NICS; i++) { + if (net_if_type == -1) { + net_if_type = NET_IF_TUN; +#if defined(CONFIG_SLIRP) + if (access(network_script, R_OK) < 0) { + net_if_type = NET_IF_USER; + } +#endif + } + + for(i = 0; i < nb_nics; i++) { NetDriverState *nd = &nd_table[i]; + nd->index = i; /* init virtual mac address */ nd->macaddr[0] = macaddr[0]; nd->macaddr[1] = macaddr[1]; @@ -1974,8 +2119,27 @@ int main(int argc, char **argv) nd->macaddr[3] = macaddr[3]; nd->macaddr[4] = macaddr[4]; nd->macaddr[5] = macaddr[5] + i; + switch(net_if_type) { +#if defined(CONFIG_SLIRP) + case NET_IF_USER: + net_slirp_init(nd); + break; +#endif +#if !defined(_WIN32) + case NET_IF_TUN: + if (i < nb_tun_fds) { + net_fd_init(nd, tun_fds[i]); + } else { + net_tun_init(nd); + } + break; +#endif + case NET_IF_DUMMY: + default: + net_dummy_init(nd); + break; + } } - net_init(); /* init the memory */ phys_ram_size = ram_size + vga_ram_size; @@ -2058,7 +2222,7 @@ int main(int argc, char **argv) } if (fd_filename[i] != '\0') { if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) { - fprintf(stderr, "qemu: could not open floppy disk image '%s\n", + fprintf(stderr, "qemu: could not open floppy disk image '%s'\n", fd_filename[i]); exit(1); } diff --git a/vl.h b/vl.h index cd49e97a9..19681ab95 100644 --- a/vl.h +++ b/vl.h @@ -132,29 +132,39 @@ void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque); void vm_start(void); void vm_stop(int reason); +/* async I/O support */ + +typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); +typedef int IOCanRWHandler(void *opaque); + +int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque); +void qemu_del_fd_read_handler(int fd); + /* network redirectors support */ #define MAX_NICS 8 typedef struct NetDriverState { - int fd; + int index; /* index number in QEMU */ uint8_t macaddr[6]; char ifname[16]; + void (*send_packet)(struct NetDriverState *nd, + const uint8_t *buf, int size); + void (*add_read_packet)(struct NetDriverState *nd, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque); + /* tun specific data */ + int fd; + /* slirp specific data */ } NetDriverState; extern int nb_nics; extern NetDriverState nd_table[MAX_NICS]; -void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size); - -/* async I/O support */ - -typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); -typedef int IOCanRWHandler(void *opaque); - -int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque); -void qemu_del_fd_read_handler(int fd); +void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size); +void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque); /* timers */ @@ -417,6 +427,7 @@ void serial_receive_break(SerialState *s); void pic_set_irq(int irq, int level); void pic_init(void); uint32_t pic_intack_read(CPUState *env); +void pic_info(void); /* i8254.c */ -- cgit v1.2.3 From ee9dbb297db6adcac1df966e160e33b166b5a92a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 21 Apr 2004 23:29:33 +0000 Subject: NE2000 fixes for windows (Renzo Davoli) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@731 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index e9ad6f9f8..5997e8865 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -103,7 +103,10 @@ #define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ #define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ -#define NE2000_MEM_SIZE 32768 +#define NE2000_PMEM_SIZE (32*1024) +#define NE2000_PMEM_START (16*1024) +#define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START) +#define NE2000_MEM_SIZE NE2000_PMEM_END typedef struct NE2000State { uint8_t cmd; @@ -244,6 +247,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* control register */ s->cmd = val; if (val & E8390_START) { + s->isr &= ~ENISR_RESET; /* test specific case: zero length transfert */ if ((val & (E8390_RREAD | E8390_RWRITE)) && s->rcnt == 0) { @@ -251,7 +255,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) ne2000_update_irq(s); } if (val & E8390_TRANS) { - net_send_packet(s->nd, s->mem + (s->tpsr << 8), s->tcnt); + qemu_send_packet(s->nd, s->mem + (s->tpsr << 8), s->tcnt); /* signal end of transfert */ s->tsr = ENTSR_PTX; s->isr |= ENISR_TX; @@ -300,7 +304,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->dcfg = val; break; case EN0_ISR: - s->isr &= ~val; + s->isr &= ~(val & 0x7f); ne2000_update_irq(s); break; case EN1_PHYS ... EN1_PHYS + 5: @@ -337,6 +341,12 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) case EN0_ISR: ret = s->isr; break; + case EN0_RSARLO: + ret = s->rsar & 0x00ff; + break; + case EN0_RSARHI: + ret = s->rsar >> 8; + break; case EN1_PHYS ... EN1_PHYS + 5: ret = s->phys[offset - EN1_PHYS]; break; @@ -357,24 +367,64 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) return ret; } +static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, + uint32_t val) +{ + if (addr < 32 || + (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { + s->mem[addr] = val; + } +} + +static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, + uint32_t val) +{ + addr &= ~1; /* XXX: check exact behaviour if not even */ + if (addr < 32 || + (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { + s->mem[addr] = val; + s->mem[addr + 1] = val >> 8; + } +} + +static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr) +{ + if (addr < 32 || + (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { + return s->mem[addr]; + } else { + return 0xff; + } +} + +static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr) +{ + addr &= ~1; /* XXX: check exact behaviour if not even */ + if (addr < 32 || + (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { + return s->mem[addr] | (s->mem[addr + 1] << 8); + } else { + return 0xffff; + } +} + static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) { NE2000State *s = opaque; - uint8_t *p; #ifdef DEBUG_NE2000 printf("NE2000: asic write val=0x%04x\n", val); #endif - p = s->mem + s->rsar; + if (s->rcnt == 0) + return; if (s->dcfg & 0x01) { /* 16 bit access */ - p[0] = val; - p[1] = val >> 8; + ne2000_mem_writew(s, s->rsar, val); s->rsar += 2; s->rcnt -= 2; } else { /* 8 bit access */ - p[0] = val; + ne2000_mem_writeb(s, s->rsar, val); s->rsar++; s->rcnt--; } @@ -391,18 +441,16 @@ static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) { NE2000State *s = opaque; - uint8_t *p; int ret; - p = s->mem + s->rsar; if (s->dcfg & 0x01) { /* 16 bit access */ - ret = p[0] | (p[1] << 8); + ret = ne2000_mem_readw(s, s->rsar); s->rsar += 2; s->rcnt -= 2; } else { /* 8 bit access */ - ret = p[0]; + ret = ne2000_mem_readb(s, s->rsar); s->rsar++; s->rcnt--; } @@ -455,5 +503,5 @@ void ne2000_init(int base, int irq, NetDriverState *nd) ne2000_reset(s); - qemu_add_fd_read_handler(nd->fd, ne2000_can_receive, ne2000_receive, s); + qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); } -- cgit v1.2.3 From 7c1f25b46a7c9c4b953976631ae94a07e4ba531a Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 22 Apr 2004 00:02:08 +0000 Subject: probe static SDL link git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@732 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 10 ++++++--- configure | 65 ++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/Makefile.target b/Makefile.target index e9c0304ff..b68183b8e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -246,9 +246,13 @@ VL_OBJS+=gdbstub.o endif ifdef CONFIG_SDL VL_OBJS+=sdl.o -ifdef CONFIG_STATIC -SDL_LIBS:=$(SDL_STATIC_LIBS) endif +ifdef CONFIG_SLIRP +DEFINES+=-I$(SRC_PATH)/slirp +SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \ +slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \ +tcp_subr.o tcp_timer.o udp.o bootp.o debug.o +VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS)) endif VL_LDFLAGS= @@ -321,7 +325,7 @@ endif $(CC) $(DEFINES) -c -o $@ $< clean: - rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o + rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o install: all ifneq ($(PROGS),) diff --git a/configure b/configure index b5f3e7a4f..ef519c8e8 100755 --- a/configure +++ b/configure @@ -192,6 +192,7 @@ 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 @@ -212,8 +213,24 @@ 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 --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 @@ -275,16 +292,20 @@ echo "target list $target_list" echo "gprof enabled $gprof" echo "static build $static" echo "SDL support $sdl" +echo "SDL static link $sdl_static" echo "mingw32 support $mingw32" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have FFplay/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 "Creating $config_mak and $config_h" echo "# Automatically generated by configure - do not modify" > $config_mak echo "/* Automatically generated by configure - do not modify */" > $config_h @@ -364,23 +385,6 @@ if test "$static" = "yes" ; then echo "CONFIG_STATIC=yes" >> $config_mak echo "#define CONFIG_STATIC 1" >> $config_h fi -if test "$sdl" = "yes" ; then - echo "CONFIG_SDL=yes" >> $config_mak - echo "#define CONFIG_SDL 1" >> $config_h - echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak - aa="no" - `$sdl_config --static-libs | grep \\\-laa > /dev/null` && aa="yes" - echo -n "SDL_STATIC_LIBS=`$sdl_config --static-libs`" >> $config_mak - if [ "${aa}" = "yes" ] ; then - echo -n " `aalib-config --libs`" >> $config_mak ; - fi - echo "" >> $config_mak - echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak - if [ "${aa}" = "yes" ] ; then - echo -n " `aalib-config --cflags`" >> $config_mak ; - fi - echo "" >> $config_mak -fi if test "$slirp" = "yes" ; then echo "CONFIG_SLIRP=yes" >> $config_mak echo "#define CONFIG_SLIRP 1" >> $config_h @@ -413,7 +417,7 @@ if expr $target : '.*-user' > /dev/null ; then target_user_only="yes" fi -echo "Creating $config_mak, $config_h and $target_dir/Makefile" +#echo "Creating $config_mak, $config_h and $target_dir/Makefile" mkdir -p $target_dir if test "$target" = "arm-user" ; then @@ -465,6 +469,29 @@ if test "$target_user_only" = "yes" ; then echo "#define CONFIG_USER_ONLY 1" >> $config_h fi +# sdl defines + +if test "$target_user_only" = "no"; then + if test "$target_softmmu" = "no" -o "$static" = "yes"; then + if test "$sdl_static" = "yes" ; then + echo "#define CONFIG_SDL 1" >> $config_h + echo "CONFIG_SDL=yes" >> $config_mak + echo "SDL_LIBS=$sdl_static_libs" >> $config_mak + fi + else + if test "$sdl" = "yes" ; then + echo "#define CONFIG_SDL 1" >> $config_h + echo "CONFIG_SDL=yes" >> $config_mak + echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak + fi + fi + echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak + if [ "${aa}" = "yes" ] ; then + echo -n " `aalib-config --cflags`" >> $config_mak ; + fi + echo "" >> $config_mak +fi + done # for target in $targets # build tree in object directory if source path is different from current one -- cgit v1.2.3 From f0cbd3ec9f4a3de1a9ef94deda09704543889f44 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 22 Apr 2004 00:10:48 +0000 Subject: initial user mode network support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@733 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/bootp.c | 212 ++++++ slirp/bootp.h | 113 ++++ slirp/cksum.c | 141 ++++ slirp/ctl.h | 7 + slirp/debug.c | 376 +++++++++++ slirp/debug.h | 50 ++ slirp/icmp_var.h | 69 ++ slirp/if.c | 320 +++++++++ slirp/if.h | 50 ++ slirp/ip.h | 317 +++++++++ slirp/ip_icmp.c | 376 +++++++++++ slirp/ip_icmp.h | 164 +++++ slirp/ip_input.c | 697 ++++++++++++++++++++ slirp/ip_output.c | 205 ++++++ slirp/libslirp.h | 19 + slirp/main.h | 54 ++ slirp/mbuf.c | 245 +++++++ slirp/mbuf.h | 147 +++++ slirp/misc.c | 925 ++++++++++++++++++++++++++ slirp/misc.h | 87 +++ slirp/sbuf.c | 201 ++++++ slirp/sbuf.h | 31 + slirp/slirp.c | 550 ++++++++++++++++ slirp/slirp.h | 308 +++++++++ slirp/slirp_config.h | 186 ++++++ slirp/socket.c | 696 ++++++++++++++++++++ slirp/socket.h | 104 +++ slirp/tcp.h | 169 +++++ slirp/tcp_input.c | 1745 ++++++++++++++++++++++++++++++++++++++++++++++++++ slirp/tcp_output.c | 608 ++++++++++++++++++ slirp/tcp_subr.c | 1325 ++++++++++++++++++++++++++++++++++++++ slirp/tcp_timer.c | 329 ++++++++++ slirp/tcp_timer.h | 142 ++++ slirp/tcp_var.h | 252 ++++++++ slirp/tcpip.h | 74 +++ slirp/udp.c | 654 +++++++++++++++++++ slirp/udp.h | 109 ++++ 37 files changed, 12057 insertions(+) create mode 100644 slirp/bootp.c create mode 100644 slirp/bootp.h create mode 100644 slirp/cksum.c create mode 100644 slirp/ctl.h create mode 100644 slirp/debug.c create mode 100644 slirp/debug.h create mode 100644 slirp/icmp_var.h create mode 100644 slirp/if.c create mode 100644 slirp/if.h create mode 100644 slirp/ip.h create mode 100644 slirp/ip_icmp.c create mode 100644 slirp/ip_icmp.h create mode 100644 slirp/ip_input.c create mode 100644 slirp/ip_output.c create mode 100644 slirp/libslirp.h create mode 100644 slirp/main.h create mode 100644 slirp/mbuf.c create mode 100644 slirp/mbuf.h create mode 100644 slirp/misc.c create mode 100644 slirp/misc.h create mode 100644 slirp/sbuf.c create mode 100644 slirp/sbuf.h create mode 100644 slirp/slirp.c create mode 100644 slirp/slirp.h create mode 100644 slirp/slirp_config.h create mode 100644 slirp/socket.c create mode 100644 slirp/socket.h create mode 100644 slirp/tcp.h create mode 100644 slirp/tcp_input.c create mode 100644 slirp/tcp_output.c create mode 100644 slirp/tcp_subr.c create mode 100644 slirp/tcp_timer.c create mode 100644 slirp/tcp_timer.h create mode 100644 slirp/tcp_var.h create mode 100644 slirp/tcpip.h create mode 100644 slirp/udp.c create mode 100644 slirp/udp.h diff --git a/slirp/bootp.c b/slirp/bootp.c new file mode 100644 index 000000000..7e4b5bab0 --- /dev/null +++ b/slirp/bootp.c @@ -0,0 +1,212 @@ +/* + * QEMU BOOTP/DHCP server + * + * 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 + +/* XXX: only DHCP is supported */ + +#define NB_ADDR 16 + +#define START_ADDR 15 + +#define LEASE_TIME (24 * 3600) + +typedef struct { + uint8_t allocated; +} BOOTPClient; + +BOOTPClient bootp_clients[NB_ADDR]; + +static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; + +#ifdef DEBUG +#define dprintf(fmt, args...) \ +if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## args); fflush(dfd); } +#else +#define dprintf(fmt, args...) +#endif + +static BOOTPClient *get_new_addr(struct in_addr *paddr) +{ + BOOTPClient *bc; + int i; + + for(i = 0; i < NB_ADDR; i++) { + if (!bootp_clients[i].allocated) + goto found; + } + return NULL; + found: + bc = &bootp_clients[i]; + bc->allocated = 1; + paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + return bc; +} + +static void dhcp_decode(const uint8_t *buf, int size, + int *pmsg_type) +{ + const uint8_t *p, *p_end; + int len, tag; + + *pmsg_type = 0; + + p = buf; + p_end = buf + size; + if (size < 5) + return; + if (memcmp(p, rfc1533_cookie, 4) != 0) + return; + p += 4; + while (p < p_end) { + tag = p[0]; + if (tag == RFC1533_PAD) { + p++; + } else if (tag == RFC1533_END) { + break; + } else { + p++; + if (p >= p_end) + break; + len = *p++; + dprintf("dhcp: tag=0x%02x len=%d\n", tag, len); + + switch(tag) { + case RFC2132_MSG_TYPE: + if (len >= 1) + *pmsg_type = p[0]; + break; + default: + break; + } + p += len; + } + } +} + +static void bootp_reply(struct bootp_t *bp) +{ + BOOTPClient *bc; + struct mbuf *m; + struct bootp_t *rbp; + struct sockaddr_in saddr, daddr; + struct in_addr dns_addr; + int dhcp_msg_type, val; + uint8_t *q; + + /* extract exact DHCP msg type */ + dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); + dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type); + + if (dhcp_msg_type != DHCPDISCOVER && + dhcp_msg_type != DHCPREQUEST) + return; + /* XXX: this is a hack to get the client mac address */ + memcpy(client_ethaddr, bp->bp_hwaddr, 6); + + if ((m = m_get()) == NULL) + return; + m->m_data += if_maxlinkhdr; + rbp = (struct bootp_t *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + memset(rbp, 0, sizeof(struct bootp_t)); + + bc = get_new_addr(&daddr.sin_addr); + if (!bc) { + dprintf("no address left\n"); + return; + } + dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr)); + + saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); + saddr.sin_port = htons(BOOTP_SERVER); + + daddr.sin_port = htons(BOOTP_CLIENT); + + rbp->bp_op = BOOTP_REPLY; + rbp->bp_xid = bp->bp_xid; + rbp->bp_htype = 1; + rbp->bp_hlen = 6; + memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); + + rbp->bp_yiaddr = daddr.sin_addr; /* IP address */ + + q = rbp->bp_vend; + memcpy(q, rfc1533_cookie, 4); + q += 4; + + if (dhcp_msg_type == DHCPDISCOVER) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPOFFER; + } else if (dhcp_msg_type == DHCPREQUEST) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPACK; + } + + if (dhcp_msg_type == DHCPDISCOVER || + dhcp_msg_type == DHCPREQUEST) { + *q++ = RFC2132_SRV_ID; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_NETMASK; + *q++ = 4; + *q++ = 0xff; + *q++ = 0xff; + *q++ = 0xff; + *q++ = 0x00; + + *q++ = RFC1533_GATEWAY; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_DNS; + *q++ = 4; + dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); + memcpy(q, &dns_addr, 4); + q += 4; + + *q++ = RFC2132_LEASE_TIME; + *q++ = 4; + val = htonl(LEASE_TIME); + memcpy(q, &val, 4); + q += 4; + } + *q++ = RFC1533_END; + + m->m_len = sizeof(struct bootp_t); + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); +} + +void bootp_input(struct mbuf *m) +{ + struct bootp_t *bp = (struct bootp_t *)m->m_data; + + if (bp->bp_op == BOOTP_REQUEST) { + bootp_reply(bp); + } +} diff --git a/slirp/bootp.h b/slirp/bootp.h new file mode 100644 index 000000000..d3b2baa04 --- /dev/null +++ b/slirp/bootp.h @@ -0,0 +1,113 @@ +/* bootp/dhcp defines */ + +#define BOOTP_SERVER 67 +#define BOOTP_CLIENT 68 + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define RFC1533_COOKIE 99, 130, 83, 99 +#define RFC1533_PAD 0 +#define RFC1533_NETMASK 1 +#define RFC1533_TIMEOFFSET 2 +#define RFC1533_GATEWAY 3 +#define RFC1533_TIMESERVER 4 +#define RFC1533_IEN116NS 5 +#define RFC1533_DNS 6 +#define RFC1533_LOGSERVER 7 +#define RFC1533_COOKIESERVER 8 +#define RFC1533_LPRSERVER 9 +#define RFC1533_IMPRESSSERVER 10 +#define RFC1533_RESOURCESERVER 11 +#define RFC1533_HOSTNAME 12 +#define RFC1533_BOOTFILESIZE 13 +#define RFC1533_MERITDUMPFILE 14 +#define RFC1533_DOMAINNAME 15 +#define RFC1533_SWAPSERVER 16 +#define RFC1533_ROOTPATH 17 +#define RFC1533_EXTENSIONPATH 18 +#define RFC1533_IPFORWARDING 19 +#define RFC1533_IPSOURCEROUTING 20 +#define RFC1533_IPPOLICYFILTER 21 +#define RFC1533_IPMAXREASSEMBLY 22 +#define RFC1533_IPTTL 23 +#define RFC1533_IPMTU 24 +#define RFC1533_IPMTUPLATEAU 25 +#define RFC1533_INTMTU 26 +#define RFC1533_INTLOCALSUBNETS 27 +#define RFC1533_INTBROADCAST 28 +#define RFC1533_INTICMPDISCOVER 29 +#define RFC1533_INTICMPRESPOND 30 +#define RFC1533_INTROUTEDISCOVER 31 +#define RFC1533_INTROUTESOLICIT 32 +#define RFC1533_INTSTATICROUTES 33 +#define RFC1533_LLTRAILERENCAP 34 +#define RFC1533_LLARPCACHETMO 35 +#define RFC1533_LLETHERNETENCAP 36 +#define RFC1533_TCPTTL 37 +#define RFC1533_TCPKEEPALIVETMO 38 +#define RFC1533_TCPKEEPALIVEGB 39 +#define RFC1533_NISDOMAIN 40 +#define RFC1533_NISSERVER 41 +#define RFC1533_NTPSERVER 42 +#define RFC1533_VENDOR 43 +#define RFC1533_NBNS 44 +#define RFC1533_NBDD 45 +#define RFC1533_NBNT 46 +#define RFC1533_NBSCOPE 47 +#define RFC1533_XFS 48 +#define RFC1533_XDM 49 + +#define RFC2132_REQ_ADDR 50 +#define RFC2132_LEASE_TIME 51 +#define RFC2132_MSG_TYPE 53 +#define RFC2132_SRV_ID 54 +#define RFC2132_PARAM_LIST 55 +#define RFC2132_MAX_SIZE 57 +#define RFC2132_RENEWAL_TIME 58 +#define RFC2132_REBIND_TIME 59 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPACK 5 + +#define RFC1533_VENDOR_MAJOR 0 +#define RFC1533_VENDOR_MINOR 0 + +#define RFC1533_VENDOR_MAGIC 128 +#define RFC1533_VENDOR_ADDPARM 129 +#define RFC1533_VENDOR_ETHDEV 130 +#define RFC1533_VENDOR_HOWTO 132 +#define RFC1533_VENDOR_MNUOPTS 160 +#define RFC1533_VENDOR_SELECTION 176 +#define RFC1533_VENDOR_MOTD 184 +#define RFC1533_VENDOR_NUMOFMOTD 8 +#define RFC1533_VENDOR_IMG 192 +#define RFC1533_VENDOR_NUMOFIMG 16 + +#define RFC1533_END 255 +#define BOOTP_VENDOR_LEN 64 +#define DHCP_OPT_LEN 312 + +struct bootp_t { + struct ip ip; + struct udphdr udp; + uint8_t bp_op; + uint8_t bp_htype; + uint8_t bp_hlen; + uint8_t bp_hops; + unsigned long bp_xid; + unsigned short bp_secs; + unsigned short unused; + struct in_addr bp_ciaddr; + struct in_addr bp_yiaddr; + struct in_addr bp_siaddr; + struct in_addr bp_giaddr; + uint8_t bp_hwaddr[16]; + uint8_t bp_sname[64]; + uint8_t bp_file[128]; + uint8_t bp_vend[DHCP_OPT_LEN]; +}; + +void bootp_input(struct mbuf *m); diff --git a/slirp/cksum.c b/slirp/cksum.c new file mode 100644 index 000000000..f8f7512b6 --- /dev/null +++ b/slirp/cksum.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 + * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp + */ + +#include + +/* + * Checksum routine for Internet Protocol family headers (Portable Version). + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * XXX Since we will never span more than 1 mbuf, we can optimise this + */ + +#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) +#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} + +int cksum(struct mbuf *m, int len) +{ + register u_int16_t *w; + register int sum = 0; + register int mlen = 0; + int byte_swapped = 0; + + union { + u_int8_t c[2]; + u_int16_t s; + } s_util; + union { + u_int16_t s[2]; + u_int32_t l; + } l_util; + + if (m->m_len == 0) + goto cont; + w = mtod(m, u_int16_t *); + + mlen = m->m_len; + + if (len < mlen) + mlen = len; + len -= mlen; + /* + * Force to even boundary. + */ + if ((1 & (long) w) && (mlen > 0)) { + REDUCE; + sum <<= 8; + s_util.c[0] = *(u_int8_t *)w; + w = (u_int16_t *)((int8_t *)w + 1); + mlen--; + byte_swapped = 1; + } + /* + * Unroll the loop to make overhead from + * branches &c small. + */ + while ((mlen -= 32) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; + sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; + sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; + w += 16; + } + mlen += 32; + while ((mlen -= 8) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + w += 4; + } + mlen += 8; + if (mlen == 0 && byte_swapped == 0) + goto cont; + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + + if (byte_swapped) { + REDUCE; + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + s_util.c[1] = *(u_int8_t *)w; + sum += s_util.s; + mlen = 0; + } else + + mlen = -1; + } else if (mlen == -1) + s_util.c[0] = *(u_int8_t *)w; + +cont: +#ifdef DEBUG + if (len) { + DEBUG_ERROR((dfd, "cksum: out of data\n")); + DEBUG_ERROR((dfd, " len = %d\n", len)); + } +#endif + if (mlen == -1) { + /* The last mbuf has odd # of bytes. Follow the + standard (the odd byte may be shifted left by 8 bits + or not as determined by endian-ness of the machine) */ + s_util.c[1] = 0; + sum += s_util.s; + } + REDUCE; + return (~sum & 0xffff); +} diff --git a/slirp/ctl.h b/slirp/ctl.h new file mode 100644 index 000000000..4a8576dc1 --- /dev/null +++ b/slirp/ctl.h @@ -0,0 +1,7 @@ +#define CTL_CMD 0 +#define CTL_EXEC 1 +#define CTL_ALIAS 2 +#define CTL_DNS 3 + +#define CTL_SPECIAL "10.0.2.0" +#define CTL_LOCAL "10.0.2.15" diff --git a/slirp/debug.c b/slirp/debug.c new file mode 100644 index 000000000..d3d8c5796 --- /dev/null +++ b/slirp/debug.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * Portions copyright (c) 2000 Kelly Price. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include + +FILE *dfd = NULL; +#ifdef DEBUG +int dostats = 1; +#else +int dostats = 0; +#endif +int slirp_debug = 0; + +extern char *strerror _P((int)); + +/* Carry over one item from main.c so that the tty's restored. + * Only done when the tty being used is /dev/tty --RedWolf */ +extern struct termios slirp_tty_settings; +extern int slirp_tty_restore; + + +void +debug_init(file, dbg) + char *file; + int dbg; +{ + /* Close the old debugging file */ + if (dfd) + fclose(dfd); + + dfd = fopen(file,"w"); + if (dfd != NULL) { +#if 0 + fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION); +#endif + fprintf(dfd,"Debugging Started level %i.\r\n",dbg); + fflush(dfd); + slirp_debug = dbg; + } else { + lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n", + file, strerror(errno)); + } +} + +/* + * Dump a packet in the same format as tcpdump -x + */ +#ifdef DEBUG +void +dump_packet(dat, n) + void *dat; + int n; +{ + u_char *pptr = (u_char *)dat; + int j,k; + + n /= 16; + n++; + DEBUG_MISC((dfd, "PACKET DUMPED: \n")); + for(j = 0; j < n; j++) { + for(k = 0; k < 6; k++) + DEBUG_MISC((dfd, "%02x ", *pptr++)); + DEBUG_MISC((dfd, "\n")); + fflush(dfd); + } +} +#endif + +#if 0 +/* + * Statistic routines + * + * These will print statistics to the screen, the debug file (dfd), or + * a buffer, depending on "type", so that the stats can be sent over + * the link as well. + */ + +void +ttystats(ttyp) + struct ttys *ttyp; +{ + struct slirp_ifstats *is = &ttyp->ifstats; + char buff[512]; + + lprint(" \r\n"); + + if (if_comp & IF_COMPRESS) + strcpy(buff, "on"); + else if (if_comp & IF_NOCOMPRESS) + strcpy(buff, "off"); + else + strcpy(buff, "off (for now)"); + lprint("Unit %d:\r\n", ttyp->unit); + lprint(" using %s encapsulation (VJ compression is %s)\r\n", ( +#ifdef USE_PPP + ttyp->proto==PROTO_PPP?"PPP": +#endif + "SLIP"), buff); + lprint(" %d baudrate\r\n", ttyp->baud); + lprint(" interface is %s\r\n", ttyp->up?"up":"down"); + lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid); +#ifndef FULL_BOLT + lprint(" towrite is %d bytes\r\n", ttyp->towrite); +#endif + if (ttyp->zeros) + lprint(" %d zeros have been typed\r\n", ttyp->zeros); + else if (ttyp->ones) + lprint(" %d ones have been typed\r\n", ttyp->ones); + lprint("Interface stats:\r\n"); + lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes); + lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes); + lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes); + lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes); + lprint(" %6d bad input packets\r\n", is->in_mbad); +} + +void +allttystats() +{ + struct ttys *ttyp; + + for (ttyp = ttys; ttyp; ttyp = ttyp->next) + ttystats(ttyp); +} +#endif + +void +ipstats() +{ + lprint(" \r\n"); + + lprint("IP stats:\r\n"); + lprint(" %6d total packets received (%d were unaligned)\r\n", + ipstat.ips_total, ipstat.ips_unaligned); + lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers); + lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum); + lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort); + lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall); + lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen); + lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen); + lprint(" %6d fragments received\r\n", ipstat.ips_fragments); + lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped); + lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout); + lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled); + lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented); + lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments); + lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto); + lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered); +} + +#if 0 +void +vjstats() +{ + lprint(" \r\n"); + + lprint("VJ compression stats:\r\n"); + + lprint(" %6d outbound packets (%d compressed)\r\n", + comp_s.sls_packets, comp_s.sls_compressed); + lprint(" %6d searches for connection stats (%d misses)\r\n", + comp_s.sls_searches, comp_s.sls_misses); + lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin); + lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin); + lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin); + lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed); +} +#endif + +void +tcpstats() +{ + lprint(" \r\n"); + + lprint("TCP stats:\r\n"); + + lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal); + lprint(" %6d data packets (%d bytes)\r\n", + tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte); + lprint(" %6d data packets retransmitted (%d bytes)\r\n", + tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte); + lprint(" %6d ack-only packets (%d delayed)\r\n", + tcpstat.tcps_sndacks, tcpstat.tcps_delack); + lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg); + lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe); + lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup); + lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); + lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); + + lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); + lprint(" %6d acks (for %d bytes)\r\n", + tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); + lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); + lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch); + lprint(" %6d packets received in sequence (%d bytes)\r\n", + tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte); + lprint(" %6d completely duplicate packets (%d bytes)\r\n", + tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte); + + lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n", + tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte); + lprint(" %6d out-of-order packets (%d bytes)\r\n", + tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte); + lprint(" %6d packets of data after window (%d bytes)\r\n", + tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin); + lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe); + lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd); + lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose); + lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum); + lprint(" %6d discarded for bad header offset fields\r\n", + tcpstat.tcps_rcvbadoff); + + lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt); + lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts); + lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects); + lprint(" %6d connections closed (including %d drop)\r\n", + tcpstat.tcps_closed, tcpstat.tcps_drops); + lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops); + lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n", + tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated); + lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo); + lprint(" %6d connections dropped by rxmt timeout\r\n", + tcpstat.tcps_timeoutdrop); + lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo); + lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo); + lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe); + lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops); + lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack); + lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat); + lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss); + + +/* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */ +/* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */ + +} + +void +udpstats() +{ + lprint(" \r\n"); + + lprint("UDP stats:\r\n"); + lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets); + lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops); + lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum); + lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen); + lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss); + lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets); +} + +void +icmpstats() +{ + lprint(" \r\n"); + lprint("ICMP stats:\r\n"); + lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received); + lprint(" %6d were too short\r\n", icmpstat.icps_tooshort); + lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum); + lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp); + lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype); + lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect); +} + +void +mbufstats() +{ + struct mbuf *m; + int i; + + lprint(" \r\n"); + + lprint("Mbuf stats:\r\n"); + + lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max); + + i = 0; + for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next) + i++; + lprint(" %6d mbufs on free list\r\n", i); + + i = 0; + for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) + i++; + lprint(" %6d mbufs on used list\r\n", i); + lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued); +} + +void +sockstats() +{ + char buff[256]; + int n; + struct socket *so; + + lprint(" \r\n"); + + lprint( + "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + lprint("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + lprint("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } + + for (so = udb.so_next; so != &udb; so = so->so_next) { + + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + lprint("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + lprint("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } +} + +#if 0 +void +slirp_exit(exit_status) + int exit_status; +{ + struct ttys *ttyp; + + DEBUG_CALL("slirp_exit"); + DEBUG_ARG("exit_status = %d", exit_status); + + if (dostats) { + lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; + if (!dfd) + debug_init("slirp_stats", 0xf); + lprint_arg = (char **)&dfd; + + ipstats(); + tcpstats(); + udpstats(); + icmpstats(); + mbufstats(); + sockstats(); + allttystats(); + vjstats(); + } + + for (ttyp = ttys; ttyp; ttyp = ttyp->next) + tty_detached(ttyp, 1); + + if (slirp_forked) { + /* Menendez time */ + if (kill(getppid(), SIGQUIT) < 0) + lprint("Couldn't kill parent process %ld!\n", + (long) getppid()); + } + + /* Restore the terminal if we gotta */ + if(slirp_tty_restore) + tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */ + exit(exit_status); +} +#endif diff --git a/slirp/debug.h b/slirp/debug.h new file mode 100644 index 000000000..6e8444dab --- /dev/null +++ b/slirp/debug.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define PRN_STDERR 1 +#define PRN_SPRINTF 2 + +extern FILE *dfd; +extern FILE *lfd; +extern int dostats; +extern int slirp_debug; + +#define DBG_CALL 0x1 +#define DBG_MISC 0x2 +#define DBG_ERROR 0x4 +#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR + +#ifdef DEBUG +#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } +#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } +#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } +#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } +#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } + + +#else + +#define DEBUG_CALL(x) +#define DEBUG_ARG(x, y) +#define DEBUG_ARGS(x) +#define DEBUG_MISC(x) +#define DEBUG_ERROR(x) + +#endif + +void debug_init _P((char *, int)); +//void ttystats _P((struct ttys *)); +void allttystats _P((void)); +void ipstats _P((void)); +void vjstats _P((void)); +void tcpstats _P((void)); +void udpstats _P((void)); +void icmpstats _P((void)); +void mbufstats _P((void)); +void sockstats _P((void)); +void slirp_exit _P((int)); + diff --git a/slirp/icmp_var.h b/slirp/icmp_var.h new file mode 100644 index 000000000..03fc8c3ac --- /dev/null +++ b/slirp/icmp_var.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 + * icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp + */ + +#ifndef _NETINET_ICMP_VAR_H_ +#define _NETINET_ICMP_VAR_H_ + +/* + * Variables related to this implementation + * of the internet control message protocol. + */ +struct icmpstat { +/* statistics related to input messages processed */ + u_long icps_received; /* #ICMP packets received */ + u_long icps_tooshort; /* packet < ICMP_MINLEN */ + u_long icps_checksum; /* bad checksum */ + u_long icps_notsupp; /* #ICMP packets not supported */ + u_long icps_badtype; /* #with bad type feild */ + u_long icps_reflect; /* number of responses */ +}; + +/* + * Names for ICMP sysctl objects + */ +#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ +#define ICMPCTL_STATS 2 /* statistics (read-only) */ +#define ICMPCTL_MAXID 3 + +#define ICMPCTL_NAMES { \ + { 0, 0 }, \ + { "maskrepl", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT }, \ +} + +extern struct icmpstat icmpstat; + +#endif diff --git a/slirp/if.c b/slirp/if.c new file mode 100644 index 000000000..282b674c5 --- /dev/null +++ b/slirp/if.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include + +int if_mtu, if_mru; +int if_comp; +int if_maxlinkhdr; +int if_queued = 0; /* Number of packets queued so far */ +int if_thresh = 10; /* Number of packets queued before we start sending + * (to prevent allocing too many mbufs) */ + +struct mbuf if_fastq; /* fast queue (for interactive data) */ +struct mbuf if_batchq; /* queue for non-interactive data */ +struct mbuf *next_m; /* Pointer to next mbuf to output */ + +#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) + +void +ifs_insque(ifm, ifmhead) + struct mbuf *ifm, *ifmhead; +{ + ifm->ifs_next = ifmhead->ifs_next; + ifmhead->ifs_next = ifm; + ifm->ifs_prev = ifmhead; + ifm->ifs_next->ifs_prev = ifm; +} + +void +ifs_remque(ifm) + struct mbuf *ifm; +{ + ifm->ifs_prev->ifs_next = ifm->ifs_next; + ifm->ifs_next->ifs_prev = ifm->ifs_prev; +} + +void +if_init() +{ +#if 0 + /* + * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, + * and 8 bytes for PPP, but need to have it on an 8byte boundary + */ +#ifdef USE_PPP + if_maxlinkhdr = 48; +#else + if_maxlinkhdr = 40; +#endif +#else + /* 14 for ethernet + 40 */ + if_maxlinkhdr = 14 + 40; +#endif + if_mtu = 1500; + if_mru = 1500; + if_comp = IF_AUTOCOMP; + if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq; + if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq; + // sl_compress_init(&comp_s); + next_m = &if_batchq; +} + +#if 0 +/* + * This shouldn't be needed since the modem is blocking and + * we don't expect any signals, but what the hell.. + */ +inline int +writen(fd, bptr, n) + int fd; + char *bptr; + int n; +{ + int ret; + int total; + + /* This should succeed most of the time */ + ret = write(fd, bptr, n); + if (ret == n || ret <= 0) + return ret; + + /* Didn't write everything, go into the loop */ + total = ret; + while (n > total) { + ret = write(fd, bptr+total, n-total); + if (ret <= 0) + return ret; + total += ret; + } + return total; +} + +/* + * if_input - read() the tty, do "top level" processing (ie: check for any escapes), + * and pass onto (*ttyp->if_input) + * + * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet. + */ +#define INBUFF_SIZE 2048 /* XXX */ +void +if_input(ttyp) + struct ttys *ttyp; +{ + u_char if_inbuff[INBUFF_SIZE]; + int if_n; + + DEBUG_CALL("if_input"); + DEBUG_ARG("ttyp = %lx", (long)ttyp); + + if_n = read(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE); + + DEBUG_MISC((dfd, " read %d bytes\n", if_n)); + + if (if_n <= 0) { + if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) { + if (ttyp->up) + link_up--; + tty_detached(ttyp, 0); + } + return; + } + if (if_n == 1) { + if (*if_inbuff == '0') { + ttyp->ones = 0; + if (++ttyp->zeros >= 5) + slirp_exit(0); + return; + } + if (*if_inbuff == '1') { + ttyp->zeros = 0; + if (++ttyp->ones >= 5) + tty_detached(ttyp, 0); + return; + } + } + ttyp->ones = ttyp->zeros = 0; + + (*ttyp->if_input)(ttyp, if_inbuff, if_n); +} +#endif + +/* + * if_output: Queue packet into an output queue. + * There are 2 output queue's, if_fastq and if_batchq. + * Each output queue is a doubly linked list of double linked lists + * of mbufs, each list belonging to one "session" (socket). This + * way, we can output packets fairly by sending one packet from each + * session, instead of all the packets from one session, then all packets + * from the next session, etc. Packets on the if_fastq get absolute + * priority, but if one session hogs the link, it gets "downgraded" + * to the batchq until it runs out of packets, then it'll return + * to the fastq (eg. if the user does an ls -alR in a telnet session, + * it'll temporarily get downgraded to the batchq) + */ +void +if_output(so, ifm) + struct socket *so; + struct mbuf *ifm; +{ + struct mbuf *ifq; + int on_fastq = 1; + + DEBUG_CALL("if_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("ifm = %lx", (long)ifm); + + /* + * First remove the mbuf from m_usedlist, + * since we're gonna use m_next and m_prev ourselves + * XXX Shouldn't need this, gotta change dtom() etc. + */ + if (ifm->m_flags & M_USEDLIST) { + remque(ifm); + ifm->m_flags &= ~M_USEDLIST; + } + + /* + * See if there's already a batchq list for this session. + * This can include an interactive session, which should go on fastq, + * but gets too greedy... hence it'll be downgraded from fastq to batchq. + * We mustn't put this packet back on the fastq (or we'll send it out of order) + * XXX add cache here? + */ + for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) { + if (so == ifq->ifq_so) { + /* A match! */ + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } + + /* No match, check which queue to put it on */ + if (so && (so->so_iptos & IPTOS_LOWDELAY)) { + ifq = if_fastq.ifq_prev; + on_fastq = 1; + /* + * Check if this packet is a part of the last + * packet's session + */ + if (ifq->ifq_so == so) { + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } else + ifq = if_batchq.ifq_prev; + + /* Create a new doubly linked list for this session */ + ifm->ifq_so = so; + ifs_init(ifm); + insque(ifm, ifq); + +diddit: + ++if_queued; + + if (so) { + /* Update *_queued */ + so->so_queued++; + so->so_nqueued++; + /* + * Check if the interactive session should be downgraded to + * the batchq. A session is downgraded if it has queued 6 + * packets without pausing, and at least 3 of those packets + * have been sent over the link + * (XXX These are arbitrary numbers, probably not optimal..) + */ + if (on_fastq && ((so->so_nqueued >= 6) && + (so->so_nqueued - so->so_queued) >= 3)) { + + /* Remove from current queue... */ + remque(ifm->ifs_next); + + /* ...And insert in the new. That'll teach ya! */ + insque(ifm->ifs_next, &if_batchq); + } + } + +#ifndef FULL_BOLT + /* + * This prevents us from malloc()ing too many mbufs + */ + if (link_up) { + /* if_start will check towrite */ + if_start(); + } +#endif +} + +/* + * Send a packet + * We choose a packet based on it's position in the output queues; + * If there are packets on the fastq, they are sent FIFO, before + * everything else. Otherwise we choose the first packet from the + * batchq and send it. the next packet chosen will be from the session + * after this one, then the session after that one, and so on.. So, + * for example, if there are 3 ftp session's fighting for bandwidth, + * one packet will be sent from the first session, then one packet + * from the second session, then one packet from the third, then back + * to the first, etc. etc. + */ +void +if_start(void) +{ + struct mbuf *ifm, *ifqt; + + DEBUG_CALL("if_start"); + + if (if_queued == 0) + return; /* Nothing to do */ + + again: + /* check if we can really output */ + if (!slirp_can_output()) + return; + + /* + * See which queue to get next packet from + * If there's something in the fastq, select it immediately + */ + if (if_fastq.ifq_next != &if_fastq) { + ifm = if_fastq.ifq_next; + } else { + /* Nothing on fastq, see if next_m is valid */ + if (next_m != &if_batchq) + ifm = next_m; + else + ifm = if_batchq.ifq_next; + + /* Set which packet to send on next iteration */ + next_m = ifm->ifq_next; + } + /* Remove it from the queue */ + ifqt = ifm->ifq_prev; + remque(ifm); + --if_queued; + + /* If there are more packets for this session, re-queue them */ + if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { + insque(ifm->ifs_next, ifqt); + ifs_remque(ifm); + } + + /* Update so_queued */ + if (ifm->ifq_so) { + if (--ifm->ifq_so->so_queued == 0) + /* If there's no more queued, reset nqueued */ + ifm->ifq_so->so_nqueued = 0; + } + + /* Encapsulate the packet for sending */ + if_encap(ifm->m_data, ifm->m_len); + + if (if_queued) + goto again; +} diff --git a/slirp/if.h b/slirp/if.h new file mode 100644 index 000000000..5d96a9034 --- /dev/null +++ b/slirp/if.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _IF_H_ +#define _IF_H_ + +#define IF_COMPRESS 0x01 /* We want compression */ +#define IF_NOCOMPRESS 0x02 /* Do not do compression */ +#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ +#define IF_NOCIDCOMP 0x08 /* CID compression */ + +/* Needed for FreeBSD */ +#undef if_mtu +extern int if_mtu; +extern int if_mru; /* MTU and MRU */ +extern int if_comp; /* Flags for compression */ +extern int if_maxlinkhdr; +extern int if_queued; /* Number of packets queued so far */ +extern int if_thresh; /* Number of packets queued before we start sending + * (to prevent allocing too many mbufs) */ + +extern struct mbuf if_fastq; /* fast queue (for interactive data) */ +extern struct mbuf if_batchq; /* queue for non-interactive data */ +extern struct mbuf *next_m; + +#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) + +/* Interface statistics */ +struct slirp_ifstats { + u_int out_pkts; /* Output packets */ + u_int out_bytes; /* Output bytes */ + u_int out_errpkts; /* Output Error Packets */ + u_int out_errbytes; /* Output Error Bytes */ + u_int in_pkts; /* Input packets */ + u_int in_bytes; /* Input bytes */ + u_int in_errpkts; /* Input Error Packets */ + u_int in_errbytes; /* Input Error Bytes */ + + u_int bytes_saved; /* Number of bytes that compression "saved" */ + /* ie: number of bytes that didn't need to be sent over the link + * because of compression */ + + u_int in_mbad; /* Bad incoming packets */ +}; + +#endif diff --git a/slirp/ip.h b/slirp/ip.h new file mode 100644 index 000000000..8280e55b8 --- /dev/null +++ b/slirp/ip.h @@ -0,0 +1,317 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)ip.h 8.1 (Berkeley) 6/10/93 + * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp + */ + +#ifndef _IP_H_ +#define _IP_H_ + +#ifdef WORDS_BIGENDIAN +# ifndef NTOHL +# define NTOHL(d) +# endif +# ifndef NTOHS +# define NTOHS(d) +# endif +# ifndef HTONL +# define HTONL(d) +# endif +# ifndef HTONS +# define HTONS(d) +# endif +#else +# ifndef NTOHL +# define NTOHL(d) ((d) = ntohl((d))) +# endif +# ifndef NTOHS +# define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) +# endif +# ifndef HTONL +# define HTONL(d) ((d) = htonl((d))) +# endif +# ifndef HTONS +# define HTONS(d) ((d) = htons((u_int16_t)(d))) +# endif +#endif + +typedef u_int32_t n_long; /* long as received from the net */ + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ +#define IPVERSION 4 + +/* + * Structure of an internet header, naked of options. + * + * We declare ip_len and ip_off to be short, rather than u_short + * pragmatically since otherwise unsigned comparisons can result + * against negative integers quite easily, and fail in subtle ways. + */ +struct ip { +#ifdef WORDS_BIGENDIAN + u_int ip_v:4, /* version */ + ip_hl:4; /* header length */ +#else + u_int ip_hl:4, /* header length */ + ip_v:4; /* version */ +#endif + u_int8_t ip_tos; /* type of service */ + int16_t ip_len; /* total length */ + u_int16_t ip_id; /* identification */ + int16_t ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* don't fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_int8_t ip_ttl; /* time to live */ + u_int8_t ip_p; /* protocol */ + u_int16_t ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +}; + +#define IP_MAXPACKET 65535 /* maximum packet size */ + +/* + * Definitions for IP type of service (ip_tos) + */ +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 + +/* + * Definitions for options. + */ +#define IPOPT_COPIED(o) ((o)&0x80) +#define IPOPT_CLASS(o) ((o)&0x60) +#define IPOPT_NUMBER(o) ((o)&0x1f) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 /* end of option list */ +#define IPOPT_NOP 1 /* no operation */ + +#define IPOPT_RR 7 /* record packet route */ +#define IPOPT_TS 68 /* timestamp */ +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#define IPOPT_LSRR 131 /* loose source route */ +#define IPOPT_SATID 136 /* satnet id */ +#define IPOPT_SSRR 137 /* strict source route */ + +/* + * Offsets to fields in options other than EOL and NOP. + */ +#define IPOPT_OPTVAL 0 /* option ID */ +#define IPOPT_OLEN 1 /* option length */ +#define IPOPT_OFFSET 2 /* offset within option */ +#define IPOPT_MINOFF 4 /* min value of above */ + +/* + * Time stamp option structure. + */ +struct ip_timestamp { + u_int8_t ipt_code; /* IPOPT_TS */ + u_int8_t ipt_len; /* size of structure (variable) */ + u_int8_t ipt_ptr; /* index of current entry */ +#ifdef WORDS_BIGENDIAN + u_int ipt_oflw:4, /* overflow counter */ + ipt_flg:4; /* flags, see below */ +#else + u_int ipt_flg:4, /* flags, see below */ + ipt_oflw:4; /* overflow counter */ +#endif + union ipt_timestamp { + n_long ipt_time[1]; + struct ipt_ta { + struct in_addr ipt_addr; + n_long ipt_time; + } ipt_ta[1]; + } ipt_timestamp; +}; + +/* flag bits for ipt_flg */ +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* bits for security (not byte swapped) */ +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +/* + * Internet implementation parameters. + */ +#define MAXTTL 255 /* maximum time to live (seconds) */ +#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60 /* time to live for frags, slowhz */ +#define IPTTLDEC 1 /* subtracted when forwarding */ + +#define IP_MSS 576 /* default maximum segment size */ + +#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ +#include +#else +#if SIZEOF_CHAR_P == 4 +typedef caddr_t caddr32_t; +#else +typedef u_int32_t caddr32_t; +#endif +#endif + +#if SIZEOF_CHAR_P == 4 +typedef struct ipq *ipqp_32; +typedef struct ipasfrag *ipasfragp_32; +#else +typedef caddr32_t ipqp_32; +typedef caddr32_t ipasfragp_32; +#endif + +/* + * Overlay for ip header used by other protocols (tcp, udp). + */ +struct ipovly { + caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ + u_int8_t ih_x1; /* (unused) */ + u_int8_t ih_pr; /* protocol */ + int16_t ih_len; /* protocol length */ + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ +}; + +/* + * Ip reassembly queue structure. Each fragment + * being reassembled is attached to one of these structures. + * They are timed out after ipq_ttl drops to 0, and may also + * be reclaimed if memory becomes tight. + * size 28 bytes + */ +struct ipq { + ipqp_32 next,prev; /* to other reass headers */ + u_int8_t ipq_ttl; /* time for reass q to live */ + u_int8_t ipq_p; /* protocol of this fragment */ + u_int16_t ipq_id; /* sequence id for reassembly */ + ipasfragp_32 ipq_next,ipq_prev; + /* to ip headers of fragments */ + struct in_addr ipq_src,ipq_dst; +}; + +/* + * Ip header, when holding a fragment. + * + * Note: ipf_next must be at same offset as ipq_next above + */ +struct ipasfrag { +#ifdef WORDS_BIGENDIAN + u_int ip_v:4, + ip_hl:4; +#else + u_int ip_hl:4, + ip_v:4; +#endif + /* BUG : u_int changed to u_int8_t. + * sizeof(u_int)==4 on linux 2.0 + */ + u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit + * to avoid destroying tos (PPPDTRuu); + * copied from (ip_off&IP_MF) */ + int16_t ip_len; + u_int16_t ip_id; + int16_t ip_off; + u_int8_t ip_ttl; + u_int8_t ip_p; + u_int16_t ip_sum; + ipasfragp_32 ipf_next; /* next fragment */ + ipasfragp_32 ipf_prev; /* previous fragment */ +}; + +/* + * Structure stored in mbuf in inpcb.ip_options + * and passed to ip_output when ip options are in use. + * The actual length of the options (including ipopt_dst) + * is in m_len. + */ +#define MAX_IPOPTLEN 40 + +struct ipoption { + struct in_addr ipopt_dst; /* first-hop dst if source routed */ + int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ +}; + +/* + * Structure attached to inpcb.ip_moptions and + * passed to ip_output when IP multicast options are in use. + */ + +struct ipstat { + u_long ips_total; /* total packets received */ + u_long ips_badsum; /* checksum bad */ + u_long ips_tooshort; /* packet too short */ + u_long ips_toosmall; /* not enough data */ + u_long ips_badhlen; /* ip header length < data size */ + u_long ips_badlen; /* ip length < ip header length */ + u_long ips_fragments; /* fragments received */ + u_long ips_fragdropped; /* frags dropped (dups, out of space) */ + u_long ips_fragtimeout; /* fragments timed out */ + u_long ips_forward; /* packets forwarded */ + u_long ips_cantforward; /* packets rcvd for unreachable dest */ + u_long ips_redirectsent; /* packets forwarded on same net */ + u_long ips_noproto; /* unknown or unsupported protocol */ + u_long ips_delivered; /* datagrams delivered to upper level*/ + u_long ips_localout; /* total ip packets generated here */ + u_long ips_odropped; /* lost packets due to nobufs, etc. */ + u_long ips_reassembled; /* total packets reassembled ok */ + u_long ips_fragmented; /* datagrams successfully fragmented */ + u_long ips_ofragments; /* output fragments created */ + u_long ips_cantfrag; /* don't fragment flag was set, etc. */ + u_long ips_badoptions; /* error in option processing */ + u_long ips_noroute; /* packets discarded due to no route */ + u_long ips_badvers; /* ip version != 4 */ + u_long ips_rawout; /* total raw ip packets generated */ + u_long ips_unaligned; /* times the ip packet was not aligned */ +}; + +extern struct ipstat ipstat; +extern struct ipq ipq; /* ip reass. queue */ +extern u_int16_t ip_id; /* ip packet ctr, for ids */ +extern int ip_defttl; /* default IP ttl */ + +#endif diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c new file mode 100644 index 000000000..8bc97a078 --- /dev/null +++ b/slirp/ip_icmp.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 + * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp + */ + +#include "slirp.h" +#include "ip_icmp.h" + +struct icmpstat icmpstat; + +/* The message sent when emulating PING */ +/* Be nice and tell them it's just a psuedo-ping packet */ +char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; + +/* list of actions for icmp_error() on RX of an icmp message */ +static int icmp_flush[19] = { +/* ECHO REPLY (0) */ 0, + 1, + 1, +/* DEST UNREACH (3) */ 1, +/* SOURCE QUENCH (4)*/ 1, +/* REDIRECT (5) */ 1, + 1, + 1, +/* ECHO (8) */ 0, +/* ROUTERADVERT (9) */ 1, +/* ROUTERSOLICIT (10) */ 1, +/* TIME EXCEEDED (11) */ 1, +/* PARAMETER PROBLEM (12) */ 1, +/* TIMESTAMP (13) */ 0, +/* TIMESTAMP REPLY (14) */ 0, +/* INFO (15) */ 0, +/* INFO REPLY (16) */ 0, +/* ADDR MASK (17) */ 0, +/* ADDR MASK REPLY (18) */ 0 +}; + +/* + * Process a received ICMP message. + */ +void +icmp_input(m, hlen) + struct mbuf *m; + int hlen; +{ + register struct icmp *icp; + register struct ip *ip=mtod(m, struct ip *); + int icmplen=ip->ip_len; + /* int code; */ + + DEBUG_CALL("icmp_input"); + DEBUG_ARG("m = %lx", (long )m); + DEBUG_ARG("m_len = %d", m->m_len); + + icmpstat.icps_received++; + + /* + * Locate icmp structure in mbuf, and check + * that its not corrupted and of at least minimum length. + */ + if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ + icmpstat.icps_tooshort++; + freeit: + m_freem(m); + goto end_error; + } + + m->m_len -= hlen; + m->m_data += hlen; + icp = mtod(m, struct icmp *); + if (cksum(m, icmplen)) { + icmpstat.icps_checksum++; + goto freeit; + } + m->m_len += hlen; + m->m_data -= hlen; + + /* icmpstat.icps_inhist[icp->icmp_type]++; */ + /* code = icp->icmp_code; */ + + DEBUG_ARG("icmp_type = %d", icp->icmp_type); + switch (icp->icmp_type) { + case ICMP_ECHO: + icp->icmp_type = ICMP_ECHOREPLY; + ip->ip_len += hlen; /* since ip_input subtracts this */ + if (ip->ip_dst.s_addr == our_addr.s_addr || + (ip->ip_dst.s_addr == (special_addr.s_addr|htonl(CTL_ALIAS))) ) { + icmp_reflect(m); + } else { + struct socket *so; + struct sockaddr_in addr; + if ((so = socreate()) == NULL) goto freeit; + if(udp_attach(so) == -1) { + DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", + errno,strerror(errno))); + sofree(so); + m_free(m); + goto end_error; + } + so->so_m = m; + so->so_faddr = ip->ip_dst; + so->so_fport = htons(7); + so->so_laddr = ip->ip_src; + so->so_lport = htons(9); + so->so_iptos = ip->ip_tos; + so->so_type = IPPROTO_ICMP; + so->so_state = SS_ISFCONNECTED; + + /* Send the packet */ + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else { + addr.sin_addr = so->so_faddr; + } + addr.sin_port = so->so_fport; + if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, + (struct sockaddr *)&addr, sizeof(addr)) == -1) { + DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", + errno,strerror(errno))); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + udp_detach(so); + } + } /* if ip->ip_dst.s_addr == our_addr.s_addr */ + break; + case ICMP_UNREACH: + /* XXX? report error? close socket? */ + case ICMP_TIMXCEED: + case ICMP_PARAMPROB: + case ICMP_SOURCEQUENCH: + case ICMP_TSTAMP: + case ICMP_MASKREQ: + case ICMP_REDIRECT: + icmpstat.icps_notsupp++; + m_freem(m); + break; + + default: + icmpstat.icps_badtype++; + m_freem(m); + } /* swith */ + +end_error: + /* m is m_free()'d xor put in a socket xor or given to ip_send */ + return; +} + + +/* + * Send an ICMP message in response to a situation + * + * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). + * MUST NOT change this header information. + * MUST NOT reply to a multicast/broadcast IP address. + * MUST NOT reply to a multicast/broadcast MAC address. + * MUST reply to only the first fragment. + */ +/* + * Send ICMP_UNREACH back to the source regarding msrc. + * mbuf *msrc is used as a template, but is NOT m_free()'d. + * It is reported as the bad ip packet. The header should + * be fully correct and in host byte order. + * ICMP fragmentation is illegal. All machines must accept 576 bytes in one + * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 + */ + +#define ICMP_MAXDATALEN (IP_MSS-28) +void +icmp_error(msrc, type, code, minsize, message) + struct mbuf *msrc; + u_char type; + u_char code; + int minsize; + char *message; +{ + unsigned hlen, shlen, s_ip_len; + register struct ip *ip; + register struct icmp *icp; + register struct mbuf *m; + + DEBUG_CALL("icmp_error"); + DEBUG_ARG("msrc = %lx", (long )msrc); + DEBUG_ARG("msrc_len = %d", msrc->m_len); + + if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; + + /* check msrc */ + if(!msrc) goto end_error; + ip = mtod(msrc, struct ip *); +#if DEBUG + { char bufa[20], bufb[20]; + strcpy(bufa, inet_ntoa(ip->ip_src)); + strcpy(bufb, inet_ntoa(ip->ip_dst)); + DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); + } +#endif + if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ + + shlen=ip->ip_hl << 2; + s_ip_len=ip->ip_len; + if(ip->ip_p == IPPROTO_ICMP) { + icp = (struct icmp *)((char *)ip + shlen); + /* + * Assume any unknown ICMP type is an error. This isn't + * specified by the RFC, but think about it.. + */ + if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; + } + + /* make a copy */ + if(!(m=m_get())) goto end_error; /* get mbuf */ + { int new_m_size; + new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; + if(new_m_size>m->m_size) m_inc(m, new_m_size); + } + memcpy(m->m_data, msrc->m_data, msrc->m_len); + m->m_len = msrc->m_len; /* copy msrc to m */ + + /* make the header of the reply packet */ + ip = mtod(m, struct ip *); + hlen= sizeof(struct ip ); /* no options in reply */ + + /* fill in icmp */ + m->m_data += hlen; + m->m_len -= hlen; + + icp = mtod(m, struct icmp *); + + if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ + else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ + s_ip_len=ICMP_MAXDATALEN; + + m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ + + /* min. size = 8+sizeof(struct ip)+8 */ + + icp->icmp_type = type; + icp->icmp_code = code; + icp->icmp_id = 0; + icp->icmp_seq = 0; + + memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ + HTONS(icp->icmp_ip.ip_len); + HTONS(icp->icmp_ip.ip_id); + HTONS(icp->icmp_ip.ip_off); + +#if DEBUG + if(message) { /* DEBUG : append message to ICMP packet */ + int message_len; + char *cpnt; + message_len=strlen(message); + if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; + cpnt=(char *)m->m_data+m->m_len; + memcpy(cpnt, message, message_len); + m->m_len+=message_len; + } +#endif + + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, m->m_len); + + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + ip->ip_hl = hlen >> 2; + ip->ip_len = m->m_len; + + ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ + + ip->ip_ttl = MAXTTL; + ip->ip_p = IPPROTO_ICMP; + ip->ip_dst = ip->ip_src; /* ip adresses */ + ip->ip_src = our_addr; + + (void ) ip_output((struct socket *)NULL, m); + + icmpstat.icps_reflect++; + +end_error: + return; +} +#undef ICMP_MAXDATALEN + +/* + * Reflect the ip packet back to the source + */ +void +icmp_reflect(m) + struct mbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + int hlen = ip->ip_hl << 2; + int optlen = hlen - sizeof(struct ip ); + register struct icmp *icp; + + /* + * Send an icmp packet back to the ip level, + * after supplying a checksum. + */ + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); + + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, ip->ip_len - hlen); + + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + if (optlen > 0) { + /* + * Strip out original options by copying rest of first + * mbuf's data back, and adjust the IP length. + */ + memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen, + (unsigned )(m->m_len - hlen)); + hlen -= optlen; + ip->ip_hl = hlen >> 2; + ip->ip_len -= optlen; + m->m_len -= optlen; + } + + ip->ip_ttl = MAXTTL; + { /* swap */ + struct in_addr icmp_dst; + icmp_dst = ip->ip_dst; + ip->ip_dst = ip->ip_src; + ip->ip_src = icmp_dst; + } + + (void ) ip_output((struct socket *)NULL, m); + + icmpstat.icps_reflect++; +} diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h new file mode 100644 index 000000000..7ddaaf8f3 --- /dev/null +++ b/slirp/ip_icmp.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp + */ + +#ifndef _NETINET_IP_ICMP_H_ +#define _NETINET_IP_ICMP_H_ + +/* + * Interface Control Message Protocol Definitions. + * Per RFC 792, September 1981. + */ + +typedef u_int32_t n_time; + +/* + * Structure of an icmp header. + */ +struct icmp { + u_char icmp_type; /* type of message, see below */ + u_char icmp_code; /* type sub code */ + u_short icmp_cksum; /* ones complement cksum of struct */ + union { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + u_short icd_id; + u_short icd_seq; + } ih_idseq; + int ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu { + u_short ipm_void; + u_short ipm_nextmtu; + } ih_pmtu; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + u_long id_mask; + char id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; + +/* + * Lower bounds on packet lengths for various types. + * For the error advice packets must first insure that the + * packet is large enought to contain the returned ip header. + * Only then can we do the check to see if 64 bits of packet + * data have been returned, since we need to check the returned + * ip header length. + */ +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + /* N.B.: must separately check that ip_hl >= 5 */ + +/* + * Definition of type and code field values. + */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ + +#define ICMP_MAXTYPE 18 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ + (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + +void icmp_input _P((struct mbuf *, int)); +void icmp_error _P((struct mbuf *, u_char, u_char, int, char *)); +void icmp_reflect _P((struct mbuf *)); + +#endif diff --git a/slirp/ip_input.c b/slirp/ip_input.c new file mode 100644 index 000000000..74b922316 --- /dev/null +++ b/slirp/ip_input.c @@ -0,0 +1,697 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 + * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp + */ + +/* + * Changes and additions relating to SLiRP are + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "ip_icmp.h" + +int ip_defttl; +struct ipstat ipstat; +struct ipq ipq; + +/* + * IP initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. + */ +void +ip_init() +{ + ipq.next = ipq.prev = (ipqp_32)&ipq; + ip_id = tt.tv_sec & 0xffff; + udp_init(); + tcp_init(); + ip_defttl = IPDEFTTL; +} + +/* + * Ip input routine. Checksum and byte swap header. If fragmented + * try to reassemble. Process options. Pass to next level. + */ +void +ip_input(m) + struct mbuf *m; +{ + register struct ip *ip; + int hlen; + + DEBUG_CALL("ip_input"); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("m_len = %d", m->m_len); + + ipstat.ips_total++; + + if (m->m_len < sizeof (struct ip)) { + ipstat.ips_toosmall++; + return; + } + + ip = mtod(m, struct ip *); + + if (ip->ip_v != IPVERSION) { + ipstat.ips_badvers++; + goto bad; + } + + hlen = ip->ip_hl << 2; + if (hlenm->m_len) {/* min header length */ + ipstat.ips_badhlen++; /* or packet too short */ + goto bad; + } + + /* keep ip header intact for ICMP reply + * ip->ip_sum = cksum(m, hlen); + * if (ip->ip_sum) { + */ + if(cksum(m,hlen)) { + ipstat.ips_badsum++; + goto bad; + } + + /* + * Convert fields to host representation. + */ + NTOHS(ip->ip_len); + if (ip->ip_len < hlen) { + ipstat.ips_badlen++; + goto bad; + } + NTOHS(ip->ip_id); + NTOHS(ip->ip_off); + + /* + * Check that the amount of data in the buffers + * is as at least much as the IP header would have us expect. + * Trim mbufs if longer than we expect. + * Drop packet if shorter than we expect. + */ + if (m->m_len < ip->ip_len) { + ipstat.ips_tooshort++; + goto bad; + } + /* Should drop packet if mbuf too long? hmmm... */ + if (m->m_len > ip->ip_len) + m_adj(m, ip->ip_len - m->m_len); + + /* check ip_ttl for a correct ICMP reply */ + if(ip->ip_ttl==0 || ip->ip_ttl==1) { + icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); + goto bad; + } + + /* + * Process options and, if not destined for us, + * ship it on. ip_dooptions returns 1 when an + * error was detected (causing an icmp message + * to be sent and the original packet to be freed). + */ +/* We do no IP options */ +/* if (hlen > sizeof (struct ip) && ip_dooptions(m)) + * goto next; + */ + /* + * If offset or IP_MF are set, must reassemble. + * Otherwise, nothing need be done. + * (We could look in the reassembly queue to see + * if the packet was previously fragmented, + * but it's not worth the time; just let them time out.) + * + * XXX This should fail, don't fragment yet + */ + if (ip->ip_off &~ IP_DF) { + register struct ipq *fp; + /* + * Look for queue of fragments + * of this datagram. + */ + for (fp = (struct ipq *) ipq.next; fp != &ipq; + fp = (struct ipq *) fp->next) + if (ip->ip_id == fp->ipq_id && + ip->ip_src.s_addr == fp->ipq_src.s_addr && + ip->ip_dst.s_addr == fp->ipq_dst.s_addr && + ip->ip_p == fp->ipq_p) + goto found; + fp = 0; + found: + + /* + * Adjust ip_len to not reflect header, + * set ip_mff if more fragments are expected, + * convert offset of this to bytes. + */ + ip->ip_len -= hlen; + if (ip->ip_off & IP_MF) + ((struct ipasfrag *)ip)->ipf_mff |= 1; + else + ((struct ipasfrag *)ip)->ipf_mff &= ~1; + + ip->ip_off <<= 3; + + /* + * If datagram marked as having more fragments + * or if this is not the first fragment, + * attempt reassembly; if it succeeds, proceed. + */ + if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { + ipstat.ips_fragments++; + ip = ip_reass((struct ipasfrag *)ip, fp); + if (ip == 0) + return; + ipstat.ips_reassembled++; + m = dtom(ip); + } else + if (fp) + ip_freef(fp); + + } else + ip->ip_len -= hlen; + + /* + * Switch out to protocol's input routine. + */ + ipstat.ips_delivered++; + switch (ip->ip_p) { + case IPPROTO_TCP: + tcp_input(m, hlen, (struct socket *)NULL); + break; + case IPPROTO_UDP: + udp_input(m, hlen); + break; + case IPPROTO_ICMP: + icmp_input(m, hlen); + break; + default: + ipstat.ips_noproto++; + m_free(m); + } + return; +bad: + m_freem(m); + return; +} + +/* + * Take incoming datagram fragment and try to + * reassemble it into whole datagram. If a chain for + * reassembly of this datagram already exists, then it + * is given as fp; otherwise have to make a chain. + */ +struct ip * +ip_reass(ip, fp) + register struct ipasfrag *ip; + register struct ipq *fp; +{ + register struct mbuf *m = dtom(ip); + register struct ipasfrag *q; + int hlen = ip->ip_hl << 2; + int i, next; + + DEBUG_CALL("ip_reass"); + DEBUG_ARG("ip = %lx", (long)ip); + DEBUG_ARG("fp = %lx", (long)fp); + DEBUG_ARG("m = %lx", (long)m); + + /* + * Presence of header sizes in mbufs + * would confuse code below. + * Fragment m_data is concatenated. + */ + m->m_data += hlen; + m->m_len -= hlen; + + /* + * If first fragment to arrive, create a reassembly queue. + */ + if (fp == 0) { + struct mbuf *t; + if ((t = m_get()) == NULL) goto dropfrag; + fp = mtod(t, struct ipq *); + insque_32(fp, &ipq); + fp->ipq_ttl = IPFRAGTTL; + fp->ipq_p = ip->ip_p; + fp->ipq_id = ip->ip_id; + fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; + fp->ipq_src = ((struct ip *)ip)->ip_src; + fp->ipq_dst = ((struct ip *)ip)->ip_dst; + q = (struct ipasfrag *)fp; + goto insert; + } + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; + q = (struct ipasfrag *)q->ipf_next) + if (q->ip_off > ip->ip_off) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if (q->ipf_prev != (ipasfragp_32)fp) { + i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + + ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; + if (i > 0) { + if (i >= ip->ip_len) + goto dropfrag; + m_adj(dtom(ip), i); + ip->ip_off += i; + ip->ip_len -= i; + } + } + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { + i = (ip->ip_off + ip->ip_len) - q->ip_off; + if (i < q->ip_len) { + q->ip_len -= i; + q->ip_off += i; + m_adj(dtom(q), i); + break; + } + q = (struct ipasfrag *) q->ipf_next; + m_freem(dtom((struct ipasfrag *) q->ipf_prev)); + ip_deq((struct ipasfrag *) q->ipf_prev); + } + +insert: + /* + * Stick new segment in its place; + * check for complete reassembly. + */ + ip_enq(ip, (struct ipasfrag *) q->ipf_prev); + next = 0; + for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + q = (struct ipasfrag *) q->ipf_next) { + if (q->ip_off != next) + return (0); + next += q->ip_len; + } + if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) + return (0); + + /* + * Reassembly is complete; concatenate fragments. + */ + q = (struct ipasfrag *) fp->ipq_next; + m = dtom(q); + + q = (struct ipasfrag *) q->ipf_next; + while (q != (struct ipasfrag *)fp) { + struct mbuf *t; + t = dtom(q); + m_cat(m, t); + q = (struct ipasfrag *) q->ipf_next; + } + + /* + * Create header for new ip packet by + * modifying header of first packet; + * dequeue and discard fragment reassembly header. + * Make header visible. + */ + ip = (struct ipasfrag *) fp->ipq_next; + + /* + * If the fragments concatenated to an mbuf that's + * bigger than the total size of the fragment, then and + * m_ext buffer was alloced. But fp->ipq_next points to + * the old buffer (in the mbuf), so we must point ip + * into the new buffer. + */ + if (m->m_flags & M_EXT) { + int delta; + delta = (char *)ip - m->m_dat; + ip = (struct ipasfrag *)(m->m_ext + delta); + } + + /* DEBUG_ARG("ip = %lx", (long)ip); + * ip=(struct ipasfrag *)m->m_data; */ + + ip->ip_len = next; + ip->ipf_mff &= ~1; + ((struct ip *)ip)->ip_src = fp->ipq_src; + ((struct ip *)ip)->ip_dst = fp->ipq_dst; + remque_32(fp); + (void) m_free(dtom(fp)); + m = dtom(ip); + m->m_len += (ip->ip_hl << 2); + m->m_data -= (ip->ip_hl << 2); + + return ((struct ip *)ip); + +dropfrag: + ipstat.ips_fragdropped++; + m_freem(m); + return (0); +} + +/* + * Free a fragment reassembly header and all + * associated datagrams. + */ +void +ip_freef(fp) + struct ipq *fp; +{ + register struct ipasfrag *q, *p; + + for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + q = p) { + p = (struct ipasfrag *) q->ipf_next; + ip_deq(q); + m_freem(dtom(q)); + } + remque_32(fp); + (void) m_free(dtom(fp)); +} + +/* + * Put an ip fragment on a reassembly chain. + * Like insque, but pointers in middle of structure. + */ +void +ip_enq(p, prev) + register struct ipasfrag *p, *prev; +{ + DEBUG_CALL("ip_enq"); + DEBUG_ARG("prev = %lx", (long)prev); + p->ipf_prev = (ipasfragp_32) prev; + p->ipf_next = prev->ipf_next; + ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; + prev->ipf_next = (ipasfragp_32) p; +} + +/* + * To ip_enq as remque is to insque. + */ +void +ip_deq(p) + register struct ipasfrag *p; +{ + ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; + ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; +} + +/* + * IP timer processing; + * if a timer expires on a reassembly + * queue, discard it. + */ +void +ip_slowtimo() +{ + register struct ipq *fp; + + DEBUG_CALL("ip_slowtimo"); + + fp = (struct ipq *) ipq.next; + if (fp == 0) + return; + + while (fp != &ipq) { + --fp->ipq_ttl; + fp = (struct ipq *) fp->next; + if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { + ipstat.ips_fragtimeout++; + ip_freef((struct ipq *) fp->prev); + } + } +} + +/* + * Do option processing on a datagram, + * possibly discarding it if bad options are encountered, + * or forwarding it if source-routed. + * Returns 1 if packet has been forwarded/freed, + * 0 if the packet should be processed further. + */ + +#ifdef notdef + +int +ip_dooptions(m) + struct mbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + register u_char *cp; + register struct ip_timestamp *ipt; + register struct in_ifaddr *ia; +/* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */ + int opt, optlen, cnt, off, code, type, forward = 0; + struct in_addr *sin, dst; +typedef u_int32_t n_time; + n_time ntime; + + dst = ip->ip_dst; + cp = (u_char *)(ip + 1); + cnt = (ip->ip_hl << 2) - sizeof (struct ip); + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + optlen = cp[IPOPT_OLEN]; + if (optlen <= 0 || optlen > cnt) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + } + switch (opt) { + + default: + break; + + /* + * Source routing with record. + * Find interface with current destination address. + * If none on this machine then drop if strictly routed, + * or do nothing if loosely routed. + * Record interface address and bring up next address + * component. If strictly routed make sure next + * address is on directly accessible net. + */ + case IPOPT_LSRR: + case IPOPT_SSRR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + ipaddr.sin_addr = ip->ip_dst; + ia = (struct in_ifaddr *) + ifa_ifwithaddr((struct sockaddr *)&ipaddr); + if (ia == 0) { + if (opt == IPOPT_SSRR) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + /* + * Loose routing, and not at next destination + * yet; nothing to do except forward. + */ + break; + } + off--; / * 0 origin * / + if (off > optlen - sizeof(struct in_addr)) { + /* + * End of source route. Should be for us. + */ + save_rte(cp, ip->ip_src); + break; + } + /* + * locate outgoing interface + */ + bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, + sizeof(ipaddr.sin_addr)); + if (opt == IPOPT_SSRR) { +#define INA struct in_ifaddr * +#define SA struct sockaddr * + if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) + ia = (INA)ifa_ifwithnet((SA)&ipaddr); + } else + ia = ip_rtaddr(ipaddr.sin_addr); + if (ia == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + ip->ip_dst = ipaddr.sin_addr; + bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), + (caddr_t)(cp + off), sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + /* + * Let ip_intr's mcast routing check handle mcast pkts + */ + forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); + break; + + case IPOPT_RR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + /* + * If no space remains, ignore. + */ + off--; * 0 origin * + if (off > optlen - sizeof(struct in_addr)) + break; + bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, + sizeof(ipaddr.sin_addr)); + /* + * locate outgoing interface; if we're the destination, + * use the incoming interface (should be same). + */ + if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && + (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + goto bad; + } + bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), + (caddr_t)(cp + off), sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + break; + + case IPOPT_TS: + code = cp - (u_char *)ip; + ipt = (struct ip_timestamp *)cp; + if (ipt->ipt_len < 5) + goto bad; + if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { + if (++ipt->ipt_oflw == 0) + goto bad; + break; + } + sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); + switch (ipt->ipt_flg) { + + case IPOPT_TS_TSONLY: + break; + + case IPOPT_TS_TSANDADDR: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + ipaddr.sin_addr = dst; + ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr, + m->m_pkthdr.rcvif); + if (ia == 0) + continue; + bcopy((caddr_t)&IA_SIN(ia)->sin_addr, + (caddr_t)sin, sizeof(struct in_addr)); + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + case IPOPT_TS_PRESPEC: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, + sizeof(struct in_addr)); + if (ifa_ifwithaddr((SA)&ipaddr) == 0) + continue; + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + default: + goto bad; + } + ntime = iptime(); + bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, + sizeof(n_time)); + ipt->ipt_ptr += sizeof(n_time); + } + } + if (forward) { + ip_forward(m, 1); + return (1); + } + } + } + return (0); +bad: + /* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */ + +/* Not yet */ + icmp_error(m, type, code, 0, 0); + + ipstat.ips_badoptions++; + return (1); +} + +#endif /* notdef */ + +/* + * Strip out IP options, at higher + * level protocol in the kernel. + * Second argument is buffer to which options + * will be moved, and return value is their length. + * (XXX) should be deleted; last arg currently ignored. + */ +void +ip_stripoptions(m, mopt) + register struct mbuf *m; + struct mbuf *mopt; +{ + register int i; + struct ip *ip = mtod(m, struct ip *); + register caddr_t opts; + int olen; + + olen = (ip->ip_hl<<2) - sizeof (struct ip); + opts = (caddr_t)(ip + 1); + i = m->m_len - (sizeof (struct ip) + olen); + memcpy(opts, opts + olen, (unsigned)i); + m->m_len -= olen; + + ip->ip_hl = sizeof(struct ip) >> 2; +} diff --git a/slirp/ip_output.c b/slirp/ip_output.c new file mode 100644 index 000000000..f3dc9b70e --- /dev/null +++ b/slirp/ip_output.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 + * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp + */ + +/* + * Changes and additions relating to SLiRP are + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include + +u_int16_t ip_id; + +/* + * IP output. The packet in mbuf chain m contains a skeletal IP + * header (with len, off, ttl, proto, tos, src, dst). + * The mbuf chain containing the packet will be freed. + * The mbuf opt, if present, will not be freed. + */ +int +ip_output(so, m0) + struct socket *so; + struct mbuf *m0; +{ + register struct ip *ip; + register struct mbuf *m = m0; + register int hlen = sizeof(struct ip ); + int len, off, error = 0; + + DEBUG_CALL("ip_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m0 = %lx", (long)m0); + + /* We do no options */ +/* if (opt) { + * m = ip_insertoptions(m, opt, &len); + * hlen = len; + * } + */ + ip = mtod(m, struct ip *); + /* + * Fill in IP header. + */ + ip->ip_v = IPVERSION; + ip->ip_off &= IP_DF; + ip->ip_id = htons(ip_id++); + ip->ip_hl = hlen >> 2; + ipstat.ips_localout++; + + /* + * Verify that we have any chance at all of being able to queue + * the packet or packet fragments + */ + /* XXX Hmmm... */ +/* if (if_queued > if_thresh && towrite <= 0) { + * error = ENOBUFS; + * goto bad; + * } + */ + + /* + * If small enough for interface, can just send directly. + */ + if ((u_int16_t)ip->ip_len <= if_mtu) { + ip->ip_len = htons((u_int16_t)ip->ip_len); + ip->ip_off = htons((u_int16_t)ip->ip_off); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); + + if_output(so, m); + goto done; + } + + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) { + error = -1; + ipstat.ips_cantfrag++; + goto bad; + } + + len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ + if (len < 8) { + error = -1; + goto bad; + } + + { + int mhlen, firstlen = len; + struct mbuf **mnext = &m->m_nextpkt; + + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + */ + m0 = m; + mhlen = sizeof (struct ip); + for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) { + register struct ip *mhip; + m = m_get(); + if (m == 0) { + error = -1; + ipstat.ips_odropped++; + goto sendorfree; + } + m->m_data += if_maxlinkhdr; + mhip = mtod(m, struct ip *); + *mhip = *ip; + + /* No options */ +/* if (hlen > sizeof (struct ip)) { + * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); + * mhip->ip_hl = mhlen >> 2; + * } + */ + m->m_len = mhlen; + mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); + if (ip->ip_off & IP_MF) + mhip->ip_off |= IP_MF; + if (off + len >= (u_int16_t)ip->ip_len) + len = (u_int16_t)ip->ip_len - off; + else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((u_int16_t)(len + mhlen)); + + if (m_copy(m, m0, off, len) < 0) { + error = -1; + goto sendorfree; + } + + mhip->ip_off = htons((u_int16_t)mhip->ip_off); + mhip->ip_sum = 0; + mhip->ip_sum = cksum(m, mhlen); + *mnext = m; + mnext = &m->m_nextpkt; + ipstat.ips_ofragments++; + } + /* + * Update first fragment by trimming what's been copied out + * and updating header, then send each fragment (in order). + */ + m = m0; + m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len); + ip->ip_len = htons((u_int16_t)m->m_len); + ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); +sendorfree: + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = 0; + if (error == 0) + if_output(so, m); + else + m_freem(m); + } + + if (error == 0) + ipstat.ips_fragmented++; + } + +done: + return (error); + +bad: + m_freem(m0); + goto done; +} diff --git a/slirp/libslirp.h b/slirp/libslirp.h new file mode 100644 index 000000000..31ddaea4d --- /dev/null +++ b/slirp/libslirp.h @@ -0,0 +1,19 @@ +#ifndef _LIBSLIRP_H +#define _LIBSLIRP_H + +#include + +void slirp_init(void); + +void slirp_select_fill(int *pnfds, + fd_set *readfds, fd_set *writefds, fd_set *xfds); + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); + +void slirp_input(const uint8_t *pkt, int pkt_len); + +/* you must provide the following functions: */ +int slirp_can_output(void); +void slirp_output(const uint8_t *pkt, int pkt_len); + +#endif diff --git a/slirp/main.h b/slirp/main.h new file mode 100644 index 000000000..dc06d6fe7 --- /dev/null +++ b/slirp/main.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#define TOWRITEMAX 512 +#define min(x,y) ((x) < (y) ? (x) : (y)) + +extern struct timeval tt; +extern int link_up; +extern int slirp_socket; +extern int slirp_socket_unit; +extern int slirp_socket_port; +extern u_int32_t slirp_socket_addr; +extern char *slirp_socket_passwd; +extern int ctty_closed; + +/* + * Get the difference in 2 times from updtim() + * Allow for wraparound times, "just in case" + * x is the greater of the 2 (current time) and y is + * what it's being compared against. + */ +#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) + +extern char *slirp_tty; +extern char *exec_shell; +extern u_int curtime; +extern fd_set *global_readfds, *global_writefds, *global_xfds; +extern struct in_addr ctl_addr; +extern struct in_addr special_addr; +extern struct in_addr our_addr; +extern struct in_addr loopback_addr; +extern struct in_addr dns_addr; +extern char *username; +extern char *socket_path; +extern int towrite_max; +extern int ppp_exit; +extern int so_options; +extern int tcp_keepintvl; +extern uint8_t client_ethaddr[6]; + +#define PROTO_SLIP 0x1 +#ifdef USE_PPP +#define PROTO_PPP 0x2 +#endif + +void if_encap(const uint8_t *ip_data, int ip_data_len); diff --git a/slirp/mbuf.c b/slirp/mbuf.c new file mode 100644 index 000000000..fa36d8950 --- /dev/null +++ b/slirp/mbuf.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 1995 Danny Gasparovski + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +/* + * mbuf's in SLiRP are much simpler than the real mbufs in + * FreeBSD. They are fixed size, determined by the MTU, + * so that one whole packet can fit. Mbuf's cannot be + * chained together. If there's more data than the mbuf + * could hold, an external malloced buffer is pointed to + * by m_ext (and the data pointers) and M_EXT is set in + * the flags + */ + +#include + +struct mbuf *mbutl; +char *mclrefcnt; +int mbuf_alloced = 0; +struct mbuf m_freelist, m_usedlist; +int mbuf_thresh = 30; +int mbuf_max = 0; +int msize; + +void +m_init() +{ + m_freelist.m_next = m_freelist.m_prev = &m_freelist; + m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; + msize_init(); +} + +void +msize_init() +{ + /* + * Find a nice value for msize + * XXX if_maxlinkhdr already in mtu + */ + msize = (if_mtu>if_mru?if_mtu:if_mru) + + if_maxlinkhdr + sizeof(struct m_hdr ) + 6; +} + +/* + * Get an mbuf from the free list, if there are none + * malloc one + * + * Because fragmentation can occur if we alloc new mbufs and + * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, + * which tells m_free to actually free() it + */ +struct mbuf * +m_get() +{ + register struct mbuf *m; + int flags = 0; + + DEBUG_CALL("m_get"); + + if (m_freelist.m_next == &m_freelist) { + m = (struct mbuf *)malloc(msize); + if (m == NULL) goto end_error; + mbuf_alloced++; + if (mbuf_alloced > mbuf_thresh) + flags = M_DOFREE; + if (mbuf_alloced > mbuf_max) + mbuf_max = mbuf_alloced; + } else { + m = m_freelist.m_next; + remque(m); + } + + /* Insert it in the used list */ + insque(m,&m_usedlist); + m->m_flags = (flags | M_USEDLIST); + + /* Initialise it */ + m->m_size = msize - sizeof(struct m_hdr); + m->m_data = m->m_dat; + m->m_len = 0; + m->m_nextpkt = 0; + m->m_prevpkt = 0; +end_error: + DEBUG_ARG("m = %lx", (long )m); + return m; +} + +void +m_free(m) + struct mbuf *m; +{ + + DEBUG_CALL("m_free"); + DEBUG_ARG("m = %lx", (long )m); + + if(m) { + /* Remove from m_usedlist */ + if (m->m_flags & M_USEDLIST) + remque(m); + + /* If it's M_EXT, free() it */ + if (m->m_flags & M_EXT) + free(m->m_ext); + + /* + * Either free() it or put it on the free list + */ + if (m->m_flags & M_DOFREE) { + free(m); + mbuf_alloced--; + } else if ((m->m_flags & M_FREELIST) == 0) { + insque(m,&m_freelist); + m->m_flags = M_FREELIST; /* Clobber other flags */ + } + } /* if(m) */ +} + +/* + * Copy data from one mbuf to the end of + * the other.. if result is too big for one mbuf, malloc() + * an M_EXT data segment + */ +void +m_cat(m, n) + register struct mbuf *m, *n; +{ + /* + * If there's no room, realloc + */ + if (M_FREEROOM(m) < n->m_len) + m_inc(m,m->m_size+MINCSIZE); + + memcpy(m->m_data+m->m_len, n->m_data, n->m_len); + m->m_len += n->m_len; + + m_free(n); +} + + +/* make m size bytes large */ +void +m_inc(m, size) + struct mbuf *m; + int size; +{ + /* some compiles throw up on gotos. This one we can fake. */ + if(m->m_size>size) return; + + if (m->m_flags & M_EXT) { + /* datasize = m->m_data - m->m_ext; */ + m->m_ext = (char *)realloc(m->m_ext,size); +/* if (m->m_ext == NULL) + * return (struct mbuf *)NULL; + */ + /* m->m_data = m->m_ext + datasize; */ + } else { + int datasize; + char *dat; + datasize = m->m_data - m->m_dat; + dat = (char *)malloc(size); +/* if (dat == NULL) + * return (struct mbuf *)NULL; + */ + memcpy(dat, m->m_dat, m->m_size); + + m->m_ext = dat; + m->m_data = m->m_ext + datasize; + m->m_flags |= M_EXT; + } + + m->m_size = size; + +} + + + +void +m_adj(m, len) + struct mbuf *m; + int len; +{ + if (m == NULL) + return; + if (len >= 0) { + /* Trim from head */ + m->m_data += len; + m->m_len -= len; + } else { + /* Trim from tail */ + len = -len; + m->m_len -= len; + } +} + + +/* + * Copy len bytes from m, starting off bytes into n + */ +int +m_copy(n, m, off, len) + struct mbuf *n, *m; + int off, len; +{ + if (len > M_FREEROOM(n)) + return -1; + + memcpy((n->m_data + n->m_len), (m->m_data + off), len); + n->m_len += len; + return 0; +} + + +/* + * Given a pointer into an mbuf, return the mbuf + * XXX This is a kludge, I should eliminate the need for it + * Fortunately, it's not used often + */ +struct mbuf * +dtom(dat) + void *dat; +{ + struct mbuf *m; + + DEBUG_CALL("dtom"); + DEBUG_ARG("dat = %lx", (long )dat); + + /* bug corrected for M_EXT buffers */ + for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) { + if (m->m_flags & M_EXT) { + if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) + return m; + } else { + if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) + return m; + } + } + + DEBUG_ERROR((dfd, "dtom failed")); + + return (struct mbuf *)0; +} + diff --git a/slirp/mbuf.h b/slirp/mbuf.h new file mode 100644 index 000000000..8cc292bbf --- /dev/null +++ b/slirp/mbuf.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 + * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp + */ + +#ifndef _MBUF_H_ +#define _MBUF_H_ + +#define m_freem m_free + + +#define MINCSIZE 4096 /* Amount to increase mbuf if too small */ + +/* + * Macros for type conversion + * mtod(m,t) - convert mbuf pointer to data pointer of correct type + * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) + */ +#define mtod(m,t) ((t)(m)->m_data) +/* #define dtom(x) ((struct mbuf *)((int)(x) & ~(M_SIZE-1))) */ + +/* XXX About mbufs for slirp: + * Only one mbuf is ever used in a chain, for each "cell" of data. + * m_nextpkt points to the next packet, if fragmented. + * If the data is too large, the M_EXT is used, and a larger block + * is alloced. Therefore, m_free[m] must check for M_EXT and if set + * free the m_ext. This is inefficient memory-wise, but who cares. + */ + +/* XXX should union some of these! */ +/* header at beginning of each mbuf: */ +struct m_hdr { + struct mbuf *mh_next; /* Linked list of mbufs */ + struct mbuf *mh_prev; + struct mbuf *mh_nextpkt; /* Next packet in queue/record */ + struct mbuf *mh_prevpkt; /* Flags aren't used in the output queue */ + int mh_flags; /* Misc flags */ + + int mh_size; /* Size of data */ + struct socket *mh_so; + + caddr_t mh_data; /* Location of data */ + int mh_len; /* Amount of data in this mbuf */ +}; + +/* + * How much room is in the mbuf, from m_data to the end of the mbuf + */ +#define M_ROOM(m) ((m->m_flags & M_EXT)? \ + (((m)->m_ext + (m)->m_size) - (m)->m_data) \ + : \ + (((m)->m_dat + (m)->m_size) - (m)->m_data)) + +/* + * How much free room there is + */ +#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) +#define M_TRAILINGSPACE M_FREEROOM + +struct mbuf { + struct m_hdr m_hdr; + union M_dat { + char m_dat_[1]; /* ANSI don't like 0 sized arrays */ + char *m_ext_; + } M_dat; +}; + +#define m_next m_hdr.mh_next +#define m_prev m_hdr.mh_prev +#define m_nextpkt m_hdr.mh_nextpkt +#define m_prevpkt m_hdr.mh_prevpkt +#define m_flags m_hdr.mh_flags +#define m_len m_hdr.mh_len +#define m_data m_hdr.mh_data +#define m_size m_hdr.mh_size +#define m_dat M_dat.m_dat_ +#define m_ext M_dat.m_ext_ +#define m_so m_hdr.mh_so + +#define ifq_prev m_prev +#define ifq_next m_next +#define ifs_prev m_prevpkt +#define ifs_next m_nextpkt +#define ifq_so m_so + +#define M_EXT 0x01 /* m_ext points to more (malloced) data */ +#define M_FREELIST 0x02 /* mbuf is on free list */ +#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ +#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() + * it rather than putting it on the free list */ + +/* + * Mbuf statistics. XXX + */ + +struct mbstat { + int mbs_alloced; /* Number of mbufs allocated */ + +}; + +extern struct mbstat mbstat; +extern int mbuf_alloced; +extern struct mbuf m_freelist, m_usedlist; +extern int mbuf_max; + +void m_init _P((void)); +void msize_init _P((void)); +struct mbuf * m_get _P((void)); +void m_free _P((struct mbuf *)); +void m_cat _P((register struct mbuf *, register struct mbuf *)); +void m_inc _P((struct mbuf *, int)); +void m_adj _P((struct mbuf *, int)); +int m_copy _P((struct mbuf *, struct mbuf *, int, int)); +struct mbuf * dtom _P((void *)); + +#endif diff --git a/slirp/misc.c b/slirp/misc.c new file mode 100644 index 000000000..7f6448dff --- /dev/null +++ b/slirp/misc.c @@ -0,0 +1,925 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include + +u_int curtime, time_fasttimo, last_slowtimo, detach_time; +u_int detach_wait = 600000; /* 10 minutes */ + +#if 0 +int x_port = -1; +int x_display = 0; +int x_screen = 0; + +int +show_x(buff, inso) + char *buff; + struct socket *inso; +{ + if (x_port < 0) { + lprint("X Redir: X not being redirected.\r\n"); + } else { + lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n", + inet_ntoa(our_addr), x_port, x_screen); + lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n", + inet_ntoa(our_addr), x_port, x_screen); + if (x_display) + lprint("X Redir: Redirecting to display %d\r\n", x_display); + } + + return CFG_OK; +} + + +/* + * XXX Allow more than one X redirection? + */ +void +redir_x(inaddr, start_port, display, screen) + u_int32_t inaddr; + int start_port; + int display; + int screen; +{ + int i; + + if (x_port >= 0) { + lprint("X Redir: X already being redirected.\r\n"); + show_x(0, 0); + } else { + for (i = 6001 + (start_port-1); i <= 6100; i++) { + if (solisten(htons(i), inaddr, htons(6000 + display), 0)) { + /* Success */ + x_port = i - 6000; + x_display = display; + x_screen = screen; + show_x(0, 0); + return; + } + } + lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n"); + } +} +#endif + +#ifndef HAVE_INET_ATON +int +inet_aton(cp, ia) + const char *cp; + struct in_addr *ia; +{ + u_int32_t addr = inet_addr(cp); + if (addr == 0xffffffff) + return 0; + ia->s_addr = addr; + return 1; +} +#endif + +/* + * Get our IP address and put it in our_addr + */ +void +getouraddr() +{ + char buff[256]; + struct hostent *he; + + if (gethostname(buff,256) < 0) + return; + + if ((he = gethostbyname(buff)) == NULL) + return; + + our_addr = *(struct in_addr *)he->h_addr; +} + +#if SIZEOF_CHAR_P == 8 + +struct quehead_32 { + u_int32_t qh_link; + u_int32_t qh_rlink; +}; + +inline void +insque_32(a, b) + void *a; + void *b; +{ + register struct quehead_32 *element = (struct quehead_32 *) a; + register struct quehead_32 *head = (struct quehead_32 *) b; + element->qh_link = head->qh_link; + head->qh_link = (u_int32_t)element; + element->qh_rlink = (u_int32_t)head; + ((struct quehead_32 *)(element->qh_link))->qh_rlink + = (u_int32_t)element; +} + +inline void +remque_32(a) + void *a; +{ + register struct quehead_32 *element = (struct quehead_32 *) a; + ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#endif /* SIZEOF_CHAR_P == 8 */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +inline void +insque(a, b) + void *a, *b; +{ + register struct quehead *element = (struct quehead *) a; + register struct quehead *head = (struct quehead *) b; + element->qh_link = head->qh_link; + head->qh_link = (struct quehead *)element; + element->qh_rlink = (struct quehead *)head; + ((struct quehead *)(element->qh_link))->qh_rlink + = (struct quehead *)element; +} + +inline void +remque(a) + void *a; +{ + register struct quehead *element = (struct quehead *) a; + ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = NULL; + /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */ +} + +/* #endif */ + + +int +add_exec(ex_ptr, do_pty, exec, addr, port) + struct ex_list **ex_ptr; + int do_pty; + char *exec; + int addr; + int port; +{ + struct ex_list *tmp_ptr; + + /* First, check if the port is "bound" */ + for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { + if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr) + return -1; + } + + tmp_ptr = *ex_ptr; + *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); + (*ex_ptr)->ex_fport = port; + (*ex_ptr)->ex_addr = addr; + (*ex_ptr)->ex_pty = do_pty; + (*ex_ptr)->ex_exec = strdup(exec); + (*ex_ptr)->ex_next = tmp_ptr; + return 0; +} + +#ifndef HAVE_STRERROR + +/* + * For systems with no strerror + */ + +extern int sys_nerr; +extern char *sys_errlist[]; + +char * +strerror(error) + int error; +{ + if (error < sys_nerr) + return sys_errlist[error]; + else + return "Unknown error."; +} + +#endif + + +#if 0 +int +openpty(amaster, aslave) + int *amaster, *aslave; +{ + register int master, slave; + +#ifdef HAVE_GRANTPT + char *ptr; + + if ((master = open("/dev/ptmx", O_RDWR)) < 0 || + grantpt(master) < 0 || + unlockpt(master) < 0 || + (ptr = ptsname(master)) == NULL) { + close(master); + return -1; + } + + if ((slave = open(ptr, O_RDWR)) < 0 || + ioctl(slave, I_PUSH, "ptem") < 0 || + ioctl(slave, I_PUSH, "ldterm") < 0 || + ioctl(slave, I_PUSH, "ttcompat") < 0) { + close(master); + close(slave); + return -1; + } + + *amaster = master; + *aslave = slave; + return 0; + +#else + + static char line[] = "/dev/ptyXX"; + register const char *cp1, *cp2; + + for (cp1 = "pqrsPQRS"; *cp1; cp1++) { + line[8] = *cp1; + for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { + line[9] = *cp2; + if ((master = open(line, O_RDWR, 0)) == -1) { + if (errno == ENOENT) + return (-1); /* out of ptys */ + } else { + line[5] = 't'; + /* These will fail */ + (void) chown(line, getuid(), 0); + (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); +#ifdef HAVE_REVOKE + (void) revoke(line); +#endif + if ((slave = open(line, O_RDWR, 0)) != -1) { + *amaster = master; + *aslave = slave; + return 0; + } + (void) close(master); + line[5] = 'p'; + } + } + } + errno = ENOENT; /* out of ptys */ + return (-1); +#endif +} + +/* + * XXX This is ugly + * We create and bind a socket, then fork off to another + * process, which connects to this socket, after which we + * exec the wanted program. If something (strange) happens, + * the accept() call could block us forever. + * + * do_pty = 0 Fork/exec inetd style + * do_pty = 1 Fork/exec using slirp.telnetd + * do_ptr = 2 Fork/exec using pty + */ +int +fork_exec(so, ex, do_pty) + struct socket *so; + char *ex; + int do_pty; +{ + int s; + struct sockaddr_in addr; + int addrlen = sizeof(addr); + int opt; + int master; + char *argv[256]; + char buff[256]; + /* don't want to clobber the original */ + char *bptr; + char *curarg; + int c, i; + + DEBUG_CALL("fork_exec"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("ex = %lx", (long)ex); + DEBUG_ARG("do_pty = %lx", (long)do_pty); + + if (do_pty == 2) { + if (openpty(&master, &s) == -1) { + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } + } else { + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || + bind(s, (struct sockaddr *)&addr, addrlen) < 0 || + listen(s, 1) < 0) { + lprint("Error: inet socket: %s\n", strerror(errno)); + close(s); + + return 0; + } + } + + switch(fork()) { + case -1: + lprint("Error: fork failed: %s\n", strerror(errno)); + close(s); + if (do_pty == 2) + close(master); + return 0; + + case 0: + /* Set the DISPLAY */ + if (do_pty == 2) { + (void) close(master); +#ifdef TIOCSCTTY /* XXXXX */ + (void) setsid(); + ioctl(s, TIOCSCTTY, (char *)NULL); +#endif + } else { + getsockname(s, (struct sockaddr *)&addr, &addrlen); + close(s); + /* + * Connect to the socket + * XXX If any of these fail, we're in trouble! + */ + s = socket(AF_INET, SOCK_STREAM, 0); + addr.sin_addr = loopback_addr; + connect(s, (struct sockaddr *)&addr, addrlen); + } + + if (x_port >= 0) { +#ifdef HAVE_SETENV + sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + setenv("DISPLAY", buff, 1); +#else + sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + putenv(buff); +#endif + } + + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + for (s = 3; s <= 255; s++) + close(s); + + i = 0; + bptr = strdup(ex); /* No need to free() this */ + if (do_pty == 1) { + /* Setup "slirp.telnetd -x" */ + argv[i++] = "slirp.telnetd"; + argv[i++] = "-x"; + argv[i++] = bptr; + } else + do { + /* Change the string into argv[] */ + curarg = bptr; + while (*bptr != ' ' && *bptr != (char)0) + bptr++; + c = *bptr; + *bptr++ = (char)0; + argv[i++] = strdup(curarg); + } while (c); + + argv[i] = 0; + execvp(argv[0], argv); + + /* Ooops, failed, let's tell the user why */ + { + char buff[256]; + + sprintf(buff, "Error: execvp of %s failed: %s\n", + argv[0], strerror(errno)); + write(2, buff, strlen(buff)+1); + } + close(0); close(1); close(2); /* XXX */ + exit(1); + + default: + if (do_pty == 2) { + close(s); + so->s = master; + } else { + /* + * XXX this could block us... + * XXX Should set a timer here, and if accept() doesn't + * return after X seconds, declare it a failure + * The only reason this will block forever is if socket() + * of connect() fail in the child process + */ + so->s = accept(s, (struct sockaddr *)&addr, &addrlen); + close(s); + opt = 1; + setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + } + fd_nonblock(so->s); + + /* Append the telnet options now */ + if (so->so_m != 0 && do_pty == 1) { + sbappend(so, so->so_m); + so->so_m = 0; + } + + return 1; + } +} +#endif + +#ifndef HAVE_STRDUP +char * +strdup(str) + const char *str; +{ + char *bptr; + + bptr = (char *)malloc(strlen(str)+1); + strcpy(bptr, str); + + return bptr; +} +#endif + +#if 0 +void +snooze_hup(num) + int num; +{ + int s, ret; +#ifndef NO_UNIX_SOCKETS + struct sockaddr_un sock_un; +#endif + struct sockaddr_in sock_in; + char buff[256]; + + ret = -1; + if (slirp_socket_passwd) { + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + slirp_exit(1); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = slirp_socket_addr; + sock_in.sin_port = htons(slirp_socket_port); + if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) + slirp_exit(1); /* just exit...*/ + sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); + write(s, buff, strlen(buff)+1); + } +#ifndef NO_UNIX_SOCKETS + else { + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) + slirp_exit(1); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, socket_path); + if (connect(s, (struct sockaddr *)&sock_un, + sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0) + slirp_exit(1); + sprintf(buff, "kill none:%d", slirp_socket_unit); + write(s, buff, strlen(buff)+1); + } +#endif + slirp_exit(0); +} + + +void +snooze() +{ + sigset_t s; + int i; + + /* Don't need our data anymore */ + /* XXX This makes SunOS barf */ +/* brk(0); */ + + /* Close all fd's */ + for (i = 255; i >= 0; i--) + close(i); + + signal(SIGQUIT, slirp_exit); + signal(SIGHUP, snooze_hup); + sigemptyset(&s); + + /* Wait for any signal */ + sigsuspend(&s); + + /* Just in case ... */ + exit(255); +} + +void +relay(s) + int s; +{ + char buf[8192]; + int n; + fd_set readfds; + struct ttys *ttyp; + + /* Don't need our data anymore */ + /* XXX This makes SunOS barf */ +/* brk(0); */ + + signal(SIGQUIT, slirp_exit); + signal(SIGHUP, slirp_exit); + signal(SIGINT, slirp_exit); + signal(SIGTERM, slirp_exit); + + /* Fudge to get term_raw and term_restore to work */ + if (NULL == (ttyp = tty_attach (0, slirp_tty))) { + lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); + slirp_exit (1); + } + ttyp->fd = 0; + ttyp->flags |= TTY_CTTY; + term_raw(ttyp); + + while (1) { + FD_ZERO(&readfds); + + FD_SET(0, &readfds); + FD_SET(s, &readfds); + + n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); + + if (n <= 0) + slirp_exit(0); + + if (FD_ISSET(0, &readfds)) { + n = read(0, buf, 8192); + if (n <= 0) + slirp_exit(0); + n = writen(s, buf, n); + if (n <= 0) + slirp_exit(0); + } + + if (FD_ISSET(s, &readfds)) { + n = read(s, buf, 8192); + if (n <= 0) + slirp_exit(0); + n = writen(0, buf, n); + if (n <= 0) + slirp_exit(0); + } + } + + /* Just in case.... */ + exit(1); +} +#endif + +int (*lprint_print) _P((void *, const char *, va_list)); +char *lprint_ptr, *lprint_ptr2, **lprint_arg; + +void +#ifdef __STDC__ +lprint(const char *format, ...) +#else +lprint(va_alist) va_dcl +#endif +{ + va_list args; + +#ifdef __STDC__ + va_start(args, format); +#else + char *format; + va_start(args); + format = va_arg(args, char *); +#endif +#if 0 + /* If we're printing to an sbuf, make sure there's enough room */ + /* XXX +100? */ + if (lprint_sb) { + if ((lprint_ptr - lprint_sb->sb_wptr) >= + (lprint_sb->sb_datalen - (strlen(format) + 100))) { + int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; + int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; + int deltap = lprint_ptr - lprint_sb->sb_data; + + lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, + lprint_sb->sb_datalen + TCP_SNDSPACE); + + /* Adjust all values */ + lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; + lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; + lprint_ptr = lprint_sb->sb_data + deltap; + + lprint_sb->sb_datalen += TCP_SNDSPACE; + } + } +#endif + if (lprint_print) + lprint_ptr += (*lprint_print)(*lprint_arg, format, args); + + /* Check if they want output to be logged to file as well */ + if (lfd) { + /* + * Remove \r's + * otherwise you'll get ^M all over the file + */ + int len = strlen(format); + char *bptr1, *bptr2; + + bptr1 = bptr2 = strdup(format); + + while (len--) { + if (*bptr1 == '\r') + memcpy(bptr1, bptr1+1, len+1); + else + bptr1++; + } + vfprintf(lfd, bptr2, args); + free(bptr2); + } + va_end(args); +} + +void +add_emu(buff) + char *buff; +{ + u_int lport, fport; + u_int8_t tos = 0, emu = 0; + char buff1[256], buff2[256], buff4[128]; + char *buff3 = buff4; + struct emu_t *emup; + struct socket *so; + + if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { + lprint("Error: Bad arguments\r\n"); + return; + } + + if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { + lport = 0; + if (sscanf(buff1, "%d", &fport) != 1) { + lprint("Error: Bad first argument\r\n"); + return; + } + } + + if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { + buff3 = 0; + if (sscanf(buff2, "%256s", buff1) != 1) { + lprint("Error: Bad second argument\r\n"); + return; + } + } + + if (buff3) { + if (strcmp(buff3, "lowdelay") == 0) + tos = IPTOS_LOWDELAY; + else if (strcmp(buff3, "throughput") == 0) + tos = IPTOS_THROUGHPUT; + else { + lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); + return; + } + } + + if (strcmp(buff1, "ftp") == 0) + emu = EMU_FTP; + else if (strcmp(buff1, "irc") == 0) + emu = EMU_IRC; + else if (strcmp(buff1, "none") == 0) + emu = EMU_NONE; /* ie: no emulation */ + else { + lprint("Error: Unknown service\r\n"); + return; + } + + /* First, check that it isn't already emulated */ + for (emup = tcpemu; emup; emup = emup->next) { + if (emup->lport == lport && emup->fport == fport) { + lprint("Error: port already emulated\r\n"); + return; + } + } + + /* link it */ + emup = (struct emu_t *)malloc(sizeof (struct emu_t)); + emup->lport = (u_int16_t)lport; + emup->fport = (u_int16_t)fport; + emup->tos = tos; + emup->emu = emu; + emup->next = tcpemu; + tcpemu = emup; + + /* And finally, mark all current sessions, if any, as being emulated */ + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + if ((lport && lport == ntohs(so->so_lport)) || + (fport && fport == ntohs(so->so_fport))) { + if (emu) + so->so_emu = emu; + if (tos) + so->so_iptos = tos; + } + } + + lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); +} + +#ifdef BAD_SPRINTF + +#undef vsprintf +#undef sprintf + +/* + * Some BSD-derived systems have a sprintf which returns char * + */ + +int +vsprintf_len(string, format, args) + char *string; + const char *format; + va_list args; +{ + vsprintf(string, format, args); + return strlen(string); +} + +int +#ifdef __STDC__ +sprintf_len(char *string, const char *format, ...) +#else +sprintf_len(va_alist) va_dcl +#endif +{ + va_list args; +#ifdef __STDC__ + va_start(args, format); +#else + char *string; + char *format; + va_start(args); + string = va_arg(args, char *); + format = va_arg(args, char *); +#endif + vsprintf(string, format, args); + return strlen(string); +} + +#endif + +void +u_sleep(usec) + int usec; +{ + struct timeval t; + fd_set fdset; + + FD_ZERO(&fdset); + + t.tv_sec = 0; + t.tv_usec = usec * 1000; + + select(0, &fdset, &fdset, &fdset, &t); +} + +/* + * Set fd blocking and non-blocking + */ + +void +fd_nonblock(fd) + int fd; +{ +#ifdef FIONBIO + int opt = 1; + + ioctl(fd, FIONBIO, &opt); +#else + int opt; + + opt = fcntl(fd, F_GETFL, 0); + opt |= O_NONBLOCK; + fcntl(fd, F_SETFL, opt); +#endif +} + +void +fd_block(fd) + int fd; +{ +#ifdef FIONBIO + int opt = 0; + + ioctl(fd, FIONBIO, &opt); +#else + int opt; + + opt = fcntl(fd, F_GETFL, 0); + opt &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, opt); +#endif +} + + +#if 0 +/* + * invoke RSH + */ +int +rsh_exec(so,ns, user, host, args) + struct socket *so; + struct socket *ns; + char *user; + char *host; + char *args; +{ + int fd[2]; + int fd0[2]; + int s; + char buff[256]; + + DEBUG_CALL("rsh_exec"); + DEBUG_ARG("so = %lx", (long)so); + + if (pipe(fd)<0) { + lprint("Error: pipe failed: %s\n", strerror(errno)); + return 0; + } +/* #ifdef HAVE_SOCKETPAIR */ +#if 1 + if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) { + close(fd[0]); + close(fd[1]); + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } +#else + if (openpty(&fd0[0], &fd0[1]) == -1) { + close(fd[0]); + close(fd[1]); + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } +#endif + + switch(fork()) { + case -1: + lprint("Error: fork failed: %s\n", strerror(errno)); + close(fd[0]); + close(fd[1]); + close(fd0[0]); + close(fd0[1]); + return 0; + + case 0: + close(fd[0]); + close(fd0[0]); + + /* Set the DISPLAY */ + if (x_port >= 0) { +#ifdef HAVE_SETENV + sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + setenv("DISPLAY", buff, 1); +#else + sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + putenv(buff); +#endif + } + + dup2(fd0[1], 0); + dup2(fd0[1], 1); + dup2(fd[1], 2); + for (s = 3; s <= 255; s++) + close(s); + + execlp("rsh","rsh","-l", user, host, args, NULL); + + /* Ooops, failed, let's tell the user why */ + + sprintf(buff, "Error: execlp of %s failed: %s\n", + "rsh", strerror(errno)); + write(2, buff, strlen(buff)+1); + close(0); close(1); close(2); /* XXX */ + exit(1); + + default: + close(fd[1]); + close(fd0[1]); + ns->s=fd[0]; + so->s=fd0[0]; + + return 1; + } +} +#endif diff --git a/slirp/misc.h b/slirp/misc.h new file mode 100644 index 000000000..8e2819b99 --- /dev/null +++ b/slirp/misc.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _MISC_H_ +#define _MISC_H_ + +struct ex_list { + int ex_pty; /* Do we want a pty? */ + int ex_addr; /* The last byte of the address */ + int ex_fport; /* Port to telnet to */ + char *ex_exec; /* Command line of what to exec */ + struct ex_list *ex_next; +}; + +extern struct ex_list *exec_list; +extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait; + +extern int (*lprint_print) _P((void *, const char *, va_list)); +extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; +extern struct sbuf *lprint_sb; + +#ifndef HAVE_STRDUP +char *strdup _P((const char *)); +#endif + +void do_wait _P((int)); + +#define EMU_NONE 0x0 + +/* TCP emulations */ +#define EMU_CTL 0x1 +#define EMU_FTP 0x2 +#define EMU_KSH 0x3 +#define EMU_IRC 0x4 +#define EMU_REALAUDIO 0x5 +#define EMU_RLOGIN 0x6 +#define EMU_IDENT 0x7 +#define EMU_RSH 0x8 + +#define EMU_NOCONNECT 0x10 /* Don't connect */ + +/* UDP emulations */ +#define EMU_TALK 0x1 +#define EMU_NTALK 0x2 +#define EMU_CUSEEME 0x3 + +struct tos_t { + u_int16_t lport; + u_int16_t fport; + u_int8_t tos; + u_int8_t emu; +}; + +struct emu_t { + u_int16_t lport; + u_int16_t fport; + u_int8_t tos; + u_int8_t emu; + struct emu_t *next; +}; + +extern struct emu_t *tcpemu; + +extern int x_port, x_server, x_display; + +int show_x _P((char *, struct socket *)); +void redir_x _P((u_int32_t, int, int, int)); +void getouraddr _P((void)); +inline void slirp_insque _P((void *, void *)); +inline void slirp_remque _P((void *)); +int add_exec _P((struct ex_list **, int, char *, int, int)); +int openpty _P((int *, int *)); +int fork_exec _P((struct socket *, char *, int)); +void snooze_hup _P((int)); +void snooze _P((void)); +void relay _P((int)); +void add_emu _P((char *)); +void u_sleep _P((int)); +void fd_nonblock _P((int)); +void fd_block _P((int)); +int rsh_exec _P((struct socket *, struct socket *, char *, char *, char *)); + +#endif diff --git a/slirp/sbuf.c b/slirp/sbuf.c new file mode 100644 index 000000000..04fb97ddc --- /dev/null +++ b/slirp/sbuf.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include + +/* Done as a macro in socket.h */ +/* int + * sbspace(struct sockbuff *sb) + * { + * return SB_DATALEN - sb->sb_cc; + * } + */ + +void +sbfree(sb) + struct sbuf *sb; +{ + free(sb->sb_data); +} + +void +sbdrop(sb, num) + struct sbuf *sb; + int num; +{ + /* + * We can only drop how much we have + * This should never succeed + */ + if(num > sb->sb_cc) + num = sb->sb_cc; + sb->sb_cc -= num; + sb->sb_rptr += num; + if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) + sb->sb_rptr -= sb->sb_datalen; + +} + +void +sbreserve(sb, size) + struct sbuf *sb; + int size; +{ + if (sb->sb_data) { + /* Already alloced, realloc if necessary */ + if (sb->sb_datalen != size) { + sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size); + sb->sb_cc = 0; + if (sb->sb_wptr) + sb->sb_datalen = size; + else + sb->sb_datalen = 0; + } + } else { + sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size); + sb->sb_cc = 0; + if (sb->sb_wptr) + sb->sb_datalen = size; + else + sb->sb_datalen = 0; + } +} + +/* + * Try and write() to the socket, whatever doesn't get written + * append to the buffer... for a host with a fast net connection, + * this prevents an unnecessary copy of the data + * (the socket is non-blocking, so we won't hang) + */ +void +sbappend(so, m) + struct socket *so; + struct mbuf *m; +{ + int ret = 0; + + DEBUG_CALL("sbappend"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("m->m_len = %d", m->m_len); + + /* Shouldn't happen, but... e.g. foreign host closes connection */ + if (m->m_len <= 0) { + m_free(m); + return; + } + + /* + * If there is urgent data, call sosendoob + * if not all was sent, sowrite will take care of the rest + * (The rest of this function is just an optimisation) + */ + if (so->so_urgc) { + sbappendsb(&so->so_rcv, m); + m_free(m); + sosendoob(so); + return; + } + + /* + * We only write if there's nothing in the buffer, + * ottherwise it'll arrive out of order, and hence corrupt + */ + if (!so->so_rcv.sb_cc) + ret = write(so->s, m->m_data, m->m_len); + + if (ret <= 0) { + /* + * Nothing was written + * It's possible that the socket has closed, but + * we don't need to check because if it has closed, + * it will be detected in the normal way by soread() + */ + sbappendsb(&so->so_rcv, m); + } else if (ret != m->m_len) { + /* + * Something was written, but not everything.. + * sbappendsb the rest + */ + m->m_len -= ret; + m->m_data += ret; + sbappendsb(&so->so_rcv, m); + } /* else */ + /* Whatever happened, we free the mbuf */ + m_free(m); +} + +/* + * Copy the data from m into sb + * The caller is responsible to make sure there's enough room + */ +void +sbappendsb(sb, m) + struct sbuf *sb; + struct mbuf *m; +{ + int len, n, nn; + + len = m->m_len; + + if (sb->sb_wptr < sb->sb_rptr) { + n = sb->sb_rptr - sb->sb_wptr; + if (n > len) n = len; + memcpy(sb->sb_wptr, m->m_data, n); + } else { + /* Do the right edge first */ + n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; + if (n > len) n = len; + memcpy(sb->sb_wptr, m->m_data, n); + len -= n; + if (len) { + /* Now the left edge */ + nn = sb->sb_rptr - sb->sb_data; + if (nn > len) nn = len; + memcpy(sb->sb_data,m->m_data+n,nn); + n += nn; + } + } + + sb->sb_cc += n; + sb->sb_wptr += n; + if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) + sb->sb_wptr -= sb->sb_datalen; +} + +/* + * Copy data from sbuf to a normal, straight buffer + * Don't update the sbuf rptr, this will be + * done in sbdrop when the data is acked + */ +void +sbcopy(sb, off, len, to) + struct sbuf *sb; + int off; + int len; + char *to; +{ + char *from; + + from = sb->sb_rptr + off; + if (from >= sb->sb_data + sb->sb_datalen) + from -= sb->sb_datalen; + + if (from < sb->sb_wptr) { + if (len > sb->sb_cc) len = sb->sb_cc; + memcpy(to,from,len); + } else { + /* re-use off */ + off = (sb->sb_data + sb->sb_datalen) - from; + if (off > len) off = len; + memcpy(to,from,off); + len -= off; + if (len) + memcpy(to+off,sb->sb_data,len); + } +} + diff --git a/slirp/sbuf.h b/slirp/sbuf.h new file mode 100644 index 000000000..161e0bb76 --- /dev/null +++ b/slirp/sbuf.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _SBUF_H_ +#define _SBUF_H_ + +#define sbflush(sb) sbdrop((sb),(sb)->sb_cc) +#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) + +struct sbuf { + u_int sb_cc; /* actual chars in buffer */ + u_int sb_datalen; /* Length of data */ + char *sb_wptr; /* write pointer. points to where the next + * bytes should be written in the sbuf */ + char *sb_rptr; /* read pointer. points to where the next + * byte should be read from the sbuf */ + char *sb_data; /* Actual data */ +}; + +void sbfree _P((struct sbuf *)); +void sbdrop _P((struct sbuf *, int)); +void sbreserve _P((struct sbuf *, int)); +void sbappend _P((struct socket *, struct mbuf *)); +void sbappendsb _P((struct sbuf *, struct mbuf *)); +void sbcopy _P((struct sbuf *, int, int, char *)); + +#endif diff --git a/slirp/slirp.c b/slirp/slirp.c new file mode 100644 index 000000000..48b45a39c --- /dev/null +++ b/slirp/slirp.c @@ -0,0 +1,550 @@ +#include "slirp.h" + +/* host address */ +struct in_addr our_addr; +/* host dns address */ +struct in_addr dns_addr; +/* host loopback address */ +struct in_addr loopback_addr; + +/* address for slirp virtual addresses */ +struct in_addr special_addr; + +const uint8_t special_ethaddr[6] = { + 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 +}; + +uint8_t client_ethaddr[6]; + +int do_slowtimo; +int link_up; +struct timeval tt; +FILE *lfd; + +/* XXX: suppress those select globals */ +fd_set *global_readfds, *global_writefds, *global_xfds; + +#ifdef _WIN32 + +static int get_dns_addr(struct in_addr *pdns_addr) +{ + /* XXX: add it */ + return -1; +} + +#else + +static int get_dns_addr(struct in_addr *pdns_addr) +{ + char buff[512]; + char buff2[256]; + FILE *f; + int found = 0; + struct in_addr tmp_addr; + + f = fopen("/etc/resolv.conf", "r"); + if (!f) + return -1; + + lprint("IP address of your DNS(s): "); + while (fgets(buff, 512, f) != NULL) { + if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { + if (!inet_aton(buff2, &tmp_addr)) + continue; + if (tmp_addr.s_addr == loopback_addr.s_addr) + tmp_addr = our_addr; + /* If it's the first one, set it to dns_addr */ + if (!found) + *pdns_addr = tmp_addr; + else + lprint(", "); + if (++found > 3) { + lprint("(more)"); + break; + } else + lprint("%s", inet_ntoa(tmp_addr)); + } + } + if (!found) + return -1; + return 0; +} + +#endif + +void slirp_init(void) +{ + debug_init("/tmp/slirp.log", DEBUG_DEFAULT); + + link_up = 1; + + if_init(); + ip_init(); + + /* Initialise mbufs *after* setting the MTU */ + m_init(); + + /* set default addresses */ + getouraddr(); + inet_aton("127.0.0.1", &loopback_addr); + + if (get_dns_addr(&dns_addr) < 0) { + fprintf(stderr, "Could not get DNS address\n"); + exit(1); + } + + inet_aton(CTL_SPECIAL, &special_addr); +} + +#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define UPD_NFDS(x) if (nfds < (x)) nfds = (x) + +/* + * curtime kept to an accuracy of 1ms + */ +static void updtime(void) +{ + gettimeofday(&tt, 0); + + curtime = (u_int)tt.tv_sec * (u_int)1000; + curtime += (u_int)tt.tv_usec / (u_int)1000; + + if ((tt.tv_usec % 1000) >= 500) + curtime++; +} + +void slirp_select_fill(int *pnfds, + fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + struct socket *so, *so_next; + struct timeval timeout; + int nfds; + int tmp_time; + + /* fail safe */ + global_readfds = NULL; + global_writefds = NULL; + global_xfds = NULL; + + nfds = *pnfds; + /* + * First, TCP sockets + */ + do_slowtimo = 0; + if (link_up) { + /* + * *_slowtimo needs calling if there are IP fragments + * in the fragment queue, or there are TCP connections active + */ + do_slowtimo = ((tcb.so_next != &tcb) || + ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); + + for (so = tcb.so_next; so != &tcb; so = so_next) { + so_next = so->so_next; + + /* + * See if we need a tcp_fasttimo + */ + if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) + time_fasttimo = curtime; /* Flag when we want a fasttimo */ + + /* + * NOFDREF can include still connecting to local-host, + * newly socreated() sockets etc. Don't want to select these. + */ + if (so->so_state & SS_NOFDREF || so->s == -1) + continue; + + /* + * Set for reading sockets which are accepting + */ + if (so->so_state & SS_FACCEPTCONN) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + continue; + } + + /* + * Set for writing sockets which are connecting + */ + if (so->so_state & SS_ISFCONNECTING) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + continue; + } + + /* + * Set for writing if we are connected, can send more, and + * we have something to send + */ + if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + } + + /* + * Set for reading (and urgent data) if we are connected, can + * receive more, and we have room for it XXX /2 ? + */ + if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { + FD_SET(so->s, readfds); + FD_SET(so->s, xfds); + UPD_NFDS(so->s); + } + } + + /* + * UDP sockets + */ + for (so = udb.so_next; so != &udb; so = so_next) { + so_next = so->so_next; + + /* + * See if it's timed out + */ + if (so->so_expire) { + if (so->so_expire <= curtime) { + udp_detach(so); + continue; + } else + do_slowtimo = 1; /* Let socket expire */ + } + + /* + * When UDP packets are received from over the + * link, they're sendto()'d straight away, so + * no need for setting for writing + * Limit the number of packets queued by this session + * to 4. Note that even though we try and limit this + * to 4 packets, the session could have more queued + * if the packets needed to be fragmented + * (XXX <= 4 ?) + */ + if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + } + } + } + + /* + * Setup timeout to use minimum CPU usage, especially when idle + */ + + /* + * First, see the timeout needed by *timo + */ + timeout.tv_sec = 0; + timeout.tv_usec = -1; + /* + * If a slowtimo is needed, set timeout to 500ms from the last + * slow timeout. If a fast timeout is needed, set timeout within + * 200ms of when it was requested. + */ + if (do_slowtimo) { + /* XXX + 10000 because some select()'s aren't that accurate */ + timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000; + if (timeout.tv_usec < 0) + timeout.tv_usec = 0; + else if (timeout.tv_usec > 510000) + timeout.tv_usec = 510000; + + /* Can only fasttimo if we also slowtimo */ + if (time_fasttimo) { + tmp_time = (200 - (curtime - time_fasttimo)) * 1000; + if (tmp_time < 0) + tmp_time = 0; + + /* Choose the smallest of the 2 */ + if (tmp_time < timeout.tv_usec) + timeout.tv_usec = (u_int)tmp_time; + } + } + *pnfds = nfds; +} + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + struct socket *so, *so_next; + int ret; + + global_readfds = readfds; + global_writefds = writefds; + global_xfds = xfds; + + /* Update time */ + updtime(); + + /* + * See if anything has timed out + */ + if (link_up) { + if (time_fasttimo && ((curtime - time_fasttimo) >= 199)) { + tcp_fasttimo(); + time_fasttimo = 0; + } + if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) { + ip_slowtimo(); + tcp_slowtimo(); + last_slowtimo = curtime; + } + } + + /* + * Check sockets + */ + if (link_up) { + /* + * Check TCP sockets + */ + for (so = tcb.so_next; so != &tcb; so = so_next) { + so_next = so->so_next; + + /* + * FD_ISSET is meaningless on these sockets + * (and they can crash the program) + */ + if (so->so_state & SS_NOFDREF || so->s == -1) + continue; + + /* + * Check for URG data + * This will soread as well, so no need to + * test for readfds below if this succeeds + */ + if (FD_ISSET(so->s, xfds)) + sorecvoob(so); + /* + * Check sockets for reading + */ + else if (FD_ISSET(so->s, readfds)) { + /* + * Check for incoming connections + */ + if (so->so_state & SS_FACCEPTCONN) { + tcp_connect(so); + continue; + } /* else */ + ret = soread(so); + + /* Output it if we read something */ + if (ret > 0) + tcp_output(sototcpcb(so)); + } + + /* + * Check sockets for writing + */ + if (FD_ISSET(so->s, writefds)) { + /* + * Check for non-blocking, still-connecting sockets + */ + if (so->so_state & SS_ISFCONNECTING) { + /* Connected */ + so->so_state &= ~SS_ISFCONNECTING; + + ret = write(so->s, &ret, 0); + if (ret < 0) { + /* XXXXX Must fix, zero bytes is a NOP */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; + + /* else failed */ + so->so_state = SS_NOFDREF; + } + /* else so->so_state &= ~SS_ISFCONNECTING; */ + + /* + * Continue tcp_input + */ + tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); + /* continue; */ + } else + ret = sowrite(so); + /* + * XXXXX If we wrote something (a lot), there + * could be a need for a window update. + * In the worst case, the remote will send + * a window probe to get things going again + */ + } + + /* + * Probe a still-connecting, non-blocking socket + * to check if it's still alive + */ +#ifdef PROBE_CONN + if (so->so_state & SS_ISFCONNECTING) { + ret = read(so->s, (char *)&ret, 0); + + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; /* Still connecting, continue */ + + /* else failed */ + so->so_state = SS_NOFDREF; + + /* tcp_input will take care of it */ + } else { + ret = write(so->s, &ret, 0); + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; + /* else failed */ + so->so_state = SS_NOFDREF; + } else + so->so_state &= ~SS_ISFCONNECTING; + + } + tcp_input((struct mbuf *)NULL, sizeof(struct ip),so); + } /* SS_ISFCONNECTING */ +#endif + } + + /* + * Now UDP sockets. + * Incoming packets are sent straight away, they're not buffered. + * Incoming UDP data isn't buffered either. + */ + for (so = udb.so_next; so != &udb; so = so_next) { + so_next = so->so_next; + + if (so->s != -1 && FD_ISSET(so->s, readfds)) { + sorecvfrom(so); + } + } + } + + /* + * See if we can start outputting + */ + if (if_queued && link_up) + if_start(); +} + +#define ETH_ALEN 6 +#define ETH_HLEN 14 + +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_ARP 0x0806 /* Address Resolution packet */ + +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ + +struct ethhdr +{ + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned short h_proto; /* packet type ID field */ +}; + +struct arphdr +{ + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +}; + +void arp_input(const uint8_t *pkt, int pkt_len) +{ + struct ethhdr *eh = (struct ethhdr *)pkt; + struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); + uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; + struct ethhdr *reh = (struct ethhdr *)arp_reply; + struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); + int ar_op; + + ar_op = ntohs(ah->ar_op); + switch(ar_op) { + case ARPOP_REQUEST: + if (!memcmp(ah->ar_tip, &special_addr, 3) && + (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)) { + + /* XXX: make an ARP request to have the client address */ + memcpy(client_ethaddr, eh->h_source, ETH_ALEN); + + /* ARP request for alias/dns mac address */ + memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); + reh->h_source[5] = ah->ar_tip[3]; + reh->h_proto = htons(ETH_P_ARP); + + rah->ar_hrd = htons(1); + rah->ar_pro = htons(ETH_P_IP); + rah->ar_hln = ETH_ALEN; + rah->ar_pln = 4; + rah->ar_op = htons(ARPOP_REPLY); + memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); + memcpy(rah->ar_sip, ah->ar_tip, 4); + memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); + memcpy(rah->ar_tip, ah->ar_sip, 4); + slirp_output(arp_reply, sizeof(arp_reply)); + } + break; + default: + break; + } +} + +void slirp_input(const uint8_t *pkt, int pkt_len) +{ + struct mbuf *m; + int proto; + + if (pkt_len < ETH_HLEN) + return; + + proto = ntohs(*(uint16_t *)(pkt + 12)); + switch(proto) { + case ETH_P_ARP: + arp_input(pkt, pkt_len); + break; + case ETH_P_IP: + m = m_get(); + if (!m) + return; + m->m_len = pkt_len; + memcpy(m->m_data, pkt, pkt_len); + + m->m_data += ETH_HLEN; + m->m_len -= ETH_HLEN; + + ip_input(m); + break; + default: + break; + } +} + +/* output the IP packet to the ethernet device */ +void if_encap(const uint8_t *ip_data, int ip_data_len) +{ + uint8_t buf[1600]; + struct ethhdr *eh = (struct ethhdr *)buf; + + if (ip_data_len + ETH_HLEN > sizeof(buf)) + return; + + memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); + memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); + eh->h_source[5] = CTL_ALIAS; + eh->h_proto = htons(ETH_P_IP); + memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); + slirp_output(buf, ip_data_len + ETH_HLEN); +} diff --git a/slirp/slirp.h b/slirp/slirp.h new file mode 100644 index 000000000..c2fa86e99 --- /dev/null +++ b/slirp/slirp.h @@ -0,0 +1,308 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#define CONFIG_QEMU + +#define DEBUG 1 + +#ifndef CONFIG_QEMU +#include "version.h" +#endif +#include "config.h" +#include "slirp_config.h" + +#include +#ifdef HAVE_SYS_BITYPES_H +# include +#endif + +#ifdef NEED_TYPEDEFS +typedef char int8_t; +typedef unsigned char u_int8_t; + +# if SIZEOF_SHORT == 2 + typedef short int16_t; + typedef unsigned short u_int16_t; +# else +# if SIZEOF_INT == 2 + typedef int int16_t; + typedef unsigned int u_int16_t; +# else + #error Cannot find a type with sizeof() == 2 +# endif +# endif + +# if SIZEOF_SHORT == 4 + typedef short int32_t; + typedef unsigned short u_int32_t; +# else +# if SIZEOF_INT == 4 + typedef int int32_t; + typedef unsigned int u_int32_t; +# else + #error Cannot find a type with sizeof() == 4 +# endif +# endif +#endif /* NEED_TYPEDEFS */ + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif + +#include +#include + +#ifndef HAVE_MEMMOVE +#define memmove(x, y, z) bcopy(y, x, z) +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifdef HAVE_STRING_H +# include +#else +# include +#endif + +#include + +#ifndef _P +#ifndef NO_PROTOTYPES +# define _P(x) x +#else +# define _P(x) () +#endif +#endif + +#include +#include + +#ifdef GETTIMEOFDAY_ONE_ARG +#define gettimeofday(x, y) gettimeofday(x) +#endif + +/* Systems lacking strdup() definition in . */ +#if defined(ultrix) +char *strdup _P((const char *)); +#endif + +/* Systems lacking malloc() definition in . */ +#if defined(ultrix) || defined(hcx) +void *malloc _P((size_t arg)); +void free _P((void *ptr)); +#endif + +#ifndef HAVE_INET_ATON +int inet_aton _P((const char *cp, struct in_addr *ia)); +#endif + +#include +#ifndef NO_UNIX_SOCKETS +#include +#endif +#include +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#include + +#if defined(WANT_SYS_IOCTL_H) && defined(HAVE_SYS_IOCTL_H) +# include +#else +# define WANT_SYS_TERMIOS_H +#endif + +#ifdef WANT_SYS_TERMIOS_H +# ifndef INCLUDED_TERMIOS_H +# ifdef HAVE_TERMIOS_H +# include +# else +# include +# endif +# define INCLUDED_TERMIOS_H +# endif +#endif + + + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#ifdef HAVE_SYS_FILIO_H +# include +#endif + +#ifdef USE_PPP +#include +#endif + +#ifdef __STDC__ +#include +#else +#include +#endif + +#include + +/* Avoid conflicting with the libc insque() and remque(), which + have different prototypes. */ +#define insque slirp_insque +#define remque slirp_remque + +#ifdef HAVE_SYS_STROPTS_H +#include +#endif + +#include "debug.h" + +#include "ip.h" +#include "tcp.h" +#include "tcp_timer.h" +#include "tcp_var.h" +#include "tcpip.h" +#include "udp.h" +#include "icmp_var.h" +#include "mbuf.h" +#include "sbuf.h" +#include "socket.h" +#include "if.h" +#include "main.h" +#include "misc.h" +#include "ctl.h" +#ifdef USE_PPP +#include "ppp/pppd.h" +#include "ppp/ppp.h" +#endif + +#include "bootp.h" +#include "libslirp.h" + +extern struct ttys *ttys_unit[MAX_INTERFACES]; + +#ifndef NULL +#define NULL (void *)0 +#endif + +#ifndef FULL_BOLT +void if_start _P((void)); +#else +void if_start _P((struct ttys *)); +#endif + +#ifdef BAD_SPRINTF +# define vsprintf vsprintf_len +# define sprintf sprintf_len + extern int vsprintf_len _P((char *, const char *, va_list)); + extern int sprintf_len _P((char *, const char *, ...)); +#endif + +#ifdef DECLARE_SPRINTF +# ifndef BAD_SPRINTF + extern int vsprintf _P((char *, const char *, va_list)); +# endif + extern int vfprintf _P((FILE *, const char *, va_list)); +#endif + +#ifndef HAVE_STRERROR + extern char *strerror _P((int error)); +#endif + +#ifndef HAVE_INDEX + char *index _P((const char *, int)); +#endif + +#ifndef HAVE_GETHOSTID + long gethostid _P((void)); +#endif + +void lprint _P((const char *, ...)); + +extern int do_echo; + +#if SIZEOF_CHAR_P == 4 +# define insque_32 insque +# define remque_32 remque +#else + inline void insque_32 _P((void *, void *)); + inline void remque_32 _P((void *)); +#endif + +#include +#include + +#define DEFAULT_BAUD 115200 + +/* cksum.c */ +int cksum(struct mbuf *m, int len); + +/* if.c */ +void if_init _P((void)); +void if_output _P((struct socket *, struct mbuf *)); + +/* ip_input.c */ +void ip_init _P((void)); +void ip_input _P((struct mbuf *)); +struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); +void ip_freef _P((struct ipq *)); +void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); +void ip_deq _P((register struct ipasfrag *)); +void ip_slowtimo _P((void)); +void ip_stripoptions _P((register struct mbuf *, struct mbuf *)); + +/* ip_output.c */ +int ip_output _P((struct socket *, struct mbuf *)); + +/* tcp_input.c */ +int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct mbuf *)); +void tcp_input _P((register struct mbuf *, int, struct socket *)); +void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *)); +void tcp_xmit_timer _P((register struct tcpcb *, int)); +int tcp_mss _P((register struct tcpcb *, u_int)); + +/* tcp_output.c */ +int tcp_output _P((register struct tcpcb *)); +void tcp_setpersist _P((register struct tcpcb *)); + +/* tcp_subr.c */ +void tcp_init _P((void)); +void tcp_template _P((struct tcpcb *)); +void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int)); +struct tcpcb * tcp_newtcpcb _P((struct socket *)); +struct tcpcb * tcp_close _P((register struct tcpcb *)); +void tcp_drain _P((void)); +void tcp_sockclosed _P((struct tcpcb *)); +int tcp_fconnect _P((struct socket *)); +void tcp_connect _P((struct socket *)); +int tcp_attach _P((struct socket *)); +u_int8_t tcp_tos _P((struct socket *)); +int tcp_emu _P((struct socket *, struct mbuf *)); +int tcp_ctl _P((struct socket *)); +struct tcpcb *tcp_drop(struct tcpcb *tp, int errno); + +#ifdef USE_PPP +#define MIN_MRU MINMRU +#define MAX_MRU MAXMRU +#else +#define MIN_MRU 128 +#define MAX_MRU 16384 +#endif + +#endif diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h new file mode 100644 index 000000000..51fc95157 --- /dev/null +++ b/slirp/slirp_config.h @@ -0,0 +1,186 @@ +/* + * User definable configuration options + */ + +/* Undefine if you don't want talk emulation */ +#undef EMULATE_TALK + +/* Define if you want the connection to be probed */ +/* XXX Not working yet, so ignore this for now */ +#undef PROBE_CONN + +/* Define to 1 if you want KEEPALIVE timers */ +#define DO_KEEPALIVE 0 + +/* Define to MAX interfaces you expect to use at once */ +/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ +/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ +#define MAX_INTERFACES 1 +#define MAX_PPP_INTERFACES 1 + +/* Define if you want slirp's socket in /tmp */ +/* XXXXXX Do this in ./configure */ +#undef USE_TMPSOCKET + +/* Define if you want slirp to use cfsetXspeed() on the terminal */ +#undef DO_CFSETSPEED + +/* Define this if you want slirp to write to the tty as fast as it can */ +/* This should only be set if you are using load-balancing, slirp does a */ +/* pretty good job on single modems already, and seting this will make */ +/* interactive sessions less responsive */ +/* XXXXX Talk about having fast modem as unit 0 */ +#undef FULL_BOLT + +/* + * Define if you want slirp to use less CPU + * You will notice a small lag in interactive sessions, but it's not that bad + * Things like Netscape/ftp/etc. are completely unaffected + * This is mainly for sysadmins who have many slirp users + */ +#undef USE_LOWCPU + +/* Define this if your compiler doesn't like prototypes */ +#ifndef __STDC__ +#define NO_PROTOTYPES +#endif + +/*********************************************************/ +/* + * Autoconf defined configuration options + * You shouldn't need to touch any of these + */ + +/* Ignore this */ +#undef DUMMY_PPP + +/* Define if you have unistd.h */ +#define HAVE_UNISTD_H + +/* Define if you have stdlib.h */ +#define HAVE_STDLIB_H + +/* Define if you have sys/ioctl.h */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have sys/filio.h */ +#undef HAVE_SYS_FILIO_H + +/* Define if you have strerror */ +#define HAVE_STRERROR + +/* Define if you have strdup() */ +#define HAVE_STRDUP + +/* Define according to how time.h should be included */ +#define TIME_WITH_SYS_TIME 0 +#undef HAVE_SYS_TIME_H + +/* Define if you have sys/bitypes.h */ +#undef HAVE_SYS_BITYPES_H + +/* Define if the machine is big endian */ +//#undef WORDS_BIGENDIAN + +/* Define if your sprintf returns char * instead of int */ +#undef BAD_SPRINTF + +/* Define if you have readv */ +#undef HAVE_READV + +/* Define if iovec needs to be declared */ +#undef DECLARE_IOVEC + +/* Define if a declaration of sprintf/fprintf is needed */ +#undef DECLARE_SPRINTF + +/* Define if you have a POSIX.1 sys/wait.h */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have sys/select.h */ +#define HAVE_SYS_SELECT_H + +/* Define if you have strings.h */ +#define HAVE_STRING_H + +/* Define if you have arpa/inet.h */ +#define HAVE_ARPA_INET_H + +/* Define if you have sys/signal.h */ +#undef HAVE_SYS_SIGNAL_H + +/* Define if you have sys/stropts.h */ +#undef HAVE_SYS_STROPTS_H + +/* Define to whatever your compiler thinks inline should be */ +#define inline inline + +/* Define to whatever your compiler thinks const should be */ +#define const const + +/* Define if your compiler doesn't like prototypes */ +#undef NO_PROTOTYPES + +/* Define if you don't have u_int32_t etc. typedef'd */ +#undef NEED_TYPEDEFS + +/* Define to sizeof(char) */ +#define SIZEOF_CHAR 1 + +/* Define to sizeof(short) */ +#define SIZEOF_SHORT 2 + +/* Define to sizeof(int) */ +#define SIZEOF_INT 4 + +/* Define to sizeof(char *) */ +/* XXX: patch it */ +#define SIZEOF_CHAR_P 4 + +/* Define if you have random() */ +#undef HAVE_RANDOM + +/* Define if you have srandom() */ +#undef HAVE_SRANDOM + +/* Define if you have inet_aton */ +#define HAVE_INET_ATON + +/* Define if you have setenv */ +#undef HAVE_SETENV + +/* Define if you have index() */ +#undef HAVE_INDEX + +/* Define if you have bcmp() */ +#undef HAVE_BCMP + +/* Define if you have drand48 */ +#undef HAVE_DRAND48 + +/* Define if you have memmove */ +#define HAVE_MEMMOVE + +/* Define if you have */ +#undef HAVE_TERMIOS_H + +/* Define if you have gethostid */ +#undef HAVE_GETHOSTID + +/* Define if you DON'T have unix-domain sockets */ +#undef NO_UNIX_SOCKETS + +/* Define if gettimeofday only takes one argument */ +#undef GETTIMEOFDAY_ONE_ARG + +/* Define if you have revoke() */ +#undef HAVE_REVOKE + +/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ +#undef HAVE_GRANTPT + +/* Define if you have fchmod */ +#undef HAVE_FCHMOD + +/* Define if you have */ +#undef HAVE_SYS_TYPES32_H diff --git a/slirp/socket.c b/slirp/socket.c new file mode 100644 index 000000000..396fb4ac7 --- /dev/null +++ b/slirp/socket.c @@ -0,0 +1,696 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#include "ip_icmp.h" +#include "main.h" + +void +so_init() +{ + /* Nothing yet */ +} + + +struct socket * +solookup(head, laddr, lport, faddr, fport) + struct socket *head; + struct in_addr laddr; + u_int lport; + struct in_addr faddr; + u_int fport; +{ + struct socket *so; + + for (so = head->so_next; so != head; so = so->so_next) { + if (so->so_lport == lport && + so->so_laddr.s_addr == laddr.s_addr && + so->so_faddr.s_addr == faddr.s_addr && + so->so_fport == fport) + break; + } + + if (so == head) + return (struct socket *)NULL; + return so; + +} + +/* + * Create a new socket, initialise the fields + * It is the responsibility of the caller to + * insque() it into the correct linked-list + */ +struct socket * +socreate() +{ + struct socket *so; + + so = (struct socket *)malloc(sizeof(struct socket)); + if(so) { + memset(so, 0, sizeof(struct socket)); + so->so_state = SS_NOFDREF; + so->s = -1; + } + return(so); +} + +/* + * remque and free a socket, clobber cache + */ +void +sofree(so) + struct socket *so; +{ + if (so->so_emu==EMU_RSH && so->extra) { + sofree(so->extra); + so->extra=NULL; + } + if (so == tcp_last_so) + tcp_last_so = &tcb; + else if (so == udp_last_so) + udp_last_so = &udb; + + m_free(so->so_m); + + if(so->so_next && so->so_prev) + remque(so); /* crashes if so is not in a queue */ + + free(so); +} + +/* + * Read from so's socket into sb_snd, updating all relevant sbuf fields + * NOTE: This will only be called if it is select()ed for reading, so + * a read() of 0 (or less) means it's disconnected + */ +int +soread(so) + struct socket *so; +{ + int n, nn, lss, total; + struct sbuf *sb = &so->so_snd; + int len = sb->sb_datalen - sb->sb_cc; + struct iovec iov[2]; + int mss = so->so_tcpcb->t_maxseg; + + DEBUG_CALL("soread"); + DEBUG_ARG("so = %lx", (long )so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + + len = sb->sb_datalen - sb->sb_cc; + + iov[0].iov_base = sb->sb_wptr; + if (sb->sb_wptr < sb->sb_rptr) { + iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) + iov[0].iov_len = len; + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len%mss; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_rptr - sb->sb_data; + if(iov[1].iov_len > len) + iov[1].iov_len = len; + total = iov[0].iov_len + iov[1].iov_len; + if (total > mss) { + lss = total%mss; + if (iov[1].iov_len > lss) { + iov[1].iov_len -= lss; + n = 2; + } else { + lss -= iov[1].iov_len; + iov[0].iov_len -= lss; + n = 1; + } + } else + n = 2; + } else { + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len%mss; + n = 1; + } + } + +#ifdef HAVE_READV + nn = readv(so->s, (struct iovec *)iov, n); + DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); +#else + nn = read(so->s, iov[0].iov_base, iov[0].iov_len); +#endif + if (nn <= 0) { + if (nn < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + else { + DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno))); + sofcantrcvmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; + } + } + +#ifndef HAVE_READV + /* + * If there was no error, try and read the second time round + * We read again if n = 2 (ie, there's another part of the buffer) + * and we read as much as we could in the first read + * We don't test for <= 0 this time, because there legitimately + * might not be any more data (since the socket is non-blocking), + * a close will be detected on next iteration. + * A return of -1 wont (shouldn't) happen, since it didn't happen above + */ + if (n == 2 && nn == iov[0].iov_len) + nn += read(so->s, iov[1].iov_base, iov[1].iov_len); + + DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); +#endif + + /* Update fields */ + sb->sb_cc += nn; + sb->sb_wptr += nn; + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_wptr -= sb->sb_datalen; + return nn; +} + +/* + * Get urgent data + * + * When the socket is created, we set it SO_OOBINLINE, + * so when OOB data arrives, we soread() it and everything + * in the send buffer is sent as urgent data + */ +void +sorecvoob(so) + struct socket *so; +{ + struct tcpcb *tp = sototcpcb(so); + + DEBUG_CALL("sorecvoob"); + DEBUG_ARG("so = %lx", (long)so); + + /* + * We take a guess at how much urgent data has arrived. + * In most situations, when urgent data arrives, the next + * read() should get all the urgent data. This guess will + * be wrong however if more data arrives just after the + * urgent data, or the read() doesn't return all the + * urgent data. + */ + soread(so); + tp->snd_up = tp->snd_una + so->so_snd.sb_cc; + tp->t_force = 1; + tcp_output(tp); + tp->t_force = 0; +} + +/* + * Send urgent data + * There's a lot duplicated code here, but... + */ +int +sosendoob(so) + struct socket *so; +{ + struct sbuf *sb = &so->so_rcv; + char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ + + int n, len; + + DEBUG_CALL("sosendoob"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); + + if (so->so_urgc > 2048) + so->so_urgc = 2048; /* XXXX */ + + if (sb->sb_rptr < sb->sb_wptr) { + /* We can send it directly */ + n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ + so->so_urgc -= n; + + DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); + } else { + /* + * Since there's no sendv or sendtov like writev, + * we must copy all data to a linear buffer then + * send it all + */ + len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (len > so->so_urgc) len = so->so_urgc; + memcpy(buff, sb->sb_rptr, len); + so->so_urgc -= len; + if (so->so_urgc) { + n = sb->sb_wptr - sb->sb_data; + if (n > so->so_urgc) n = so->so_urgc; + memcpy((buff + len), sb->sb_data, n); + so->so_urgc -= n; + len += n; + } + n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ +#ifdef DEBUG + if (n != len) + DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); +#endif + DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); + } + + sb->sb_cc -= n; + sb->sb_rptr += n; + if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_rptr -= sb->sb_datalen; + + return n; +} + +/* + * Write data from so_rcv to so's socket, + * updating all sbuf field as necessary + */ +int +sowrite(so) + struct socket *so; +{ + int n,nn; + struct sbuf *sb = &so->so_rcv; + int len = sb->sb_cc; + struct iovec iov[2]; + + DEBUG_CALL("sowrite"); + DEBUG_ARG("so = %lx", (long)so); + + if (so->so_urgc) { + sosendoob(so); + if (sb->sb_cc == 0) + return 0; + } + + /* + * No need to check if there's something to write, + * sowrite wouldn't have been called otherwise + */ + + len = sb->sb_cc; + + iov[0].iov_base = sb->sb_rptr; + if (sb->sb_rptr < sb->sb_wptr) { + iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) iov[0].iov_len = len; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (iov[0].iov_len > len) iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_wptr - sb->sb_data; + if (iov[1].iov_len > len) iov[1].iov_len = len; + n = 2; + } else + n = 1; + } + /* Check if there's urgent data to send, and if so, send it */ + +#ifdef HAVE_READV + nn = writev(so->s, (const struct iovec *)iov, n); + + DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); +#else + nn = write(so->s, iov[0].iov_base, iov[0].iov_len); +#endif + /* This should never happen, but people tell me it does *shrug* */ + if (nn < 0 && (errno == EAGAIN || errno == EINTR)) + return 0; + + if (nn <= 0) { + DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n", + so->so_state, errno)); + sofcantsendmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; + } + +#ifndef HAVE_READV + if (n == 2 && nn == iov[0].iov_len) + nn += write(so->s, iov[1].iov_base, iov[1].iov_len); + DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); +#endif + + /* Update sbuf */ + sb->sb_cc -= nn; + sb->sb_rptr += nn; + if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_rptr -= sb->sb_datalen; + + /* + * If in DRAIN mode, and there's no more data, set + * it CANTSENDMORE + */ + if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) + sofcantsendmore(so); + + return nn; +} + +/* + * recvfrom() a UDP socket + */ +void +sorecvfrom(so) + struct socket *so; +{ + struct sockaddr_in addr; + int addrlen = sizeof(struct sockaddr_in); + + DEBUG_CALL("sorecvfrom"); + DEBUG_ARG("so = %lx", (long)so); + + if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ + char buff[256]; + int len; + + len = recvfrom(so->s, buff, 256, 0, + (struct sockaddr *)&addr, &addrlen); + /* XXX Check if reply is "correct"? */ + + if(len == -1 || len == 0) { + u_char code=ICMP_UNREACH_PORT; + + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; + + DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", + errno,strerror(errno))); + icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); + } else { + icmp_reflect(so->so_m); + so->so_m = 0; /* Don't m_free() it again! */ + } + /* No need for this socket anymore, udp_detach it */ + udp_detach(so); + } else { /* A "normal" UDP packet */ + struct mbuf *m; + int len, n; + + if (!(m = m_get())) return; + m->m_data += if_maxlinkhdr; + + /* + * XXX Shouldn't FIONREAD packets destined for port 53, + * but I don't know the max packet size for DNS lookups + */ + len = M_FREEROOM(m); + /* if (so->so_fport != htons(53)) { */ + ioctl(so->s, FIONREAD, &n); + + if (n > len) { + n = (m->m_data - m->m_dat) + m->m_len + n + 1; + m_inc(m, n); + len = M_FREEROOM(m); + } + /* } */ + + m->m_len = recvfrom(so->s, m->m_data, len, 0, + (struct sockaddr *)&addr, &addrlen); + DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", + m->m_len, errno,strerror(errno))); + if(m->m_len<0) { + u_char code=ICMP_UNREACH_PORT; + + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; + + DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); + icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); + m_free(m); + } else { + /* + * Hack: domain name lookup will be used the most for UDP, + * and since they'll only be used once there's no need + * for the 4 minute (or whatever) timeout... So we time them + * out much quicker (10 seconds for now...) + */ + if (so->so_expire) { + if (so->so_fport == htons(53)) + so->so_expire = curtime + SO_EXPIREFAST; + else + so->so_expire = curtime + SO_EXPIRE; + } + + /* if (m->m_len == len) { + * m_inc(m, MINCSIZE); + * m->m_len = 0; + * } + */ + + /* + * If this packet was destined for CTL_ADDR, + * make it look like that's where it came from, done by udp_output + */ + udp_output(so, m, &addr); + } /* rx error */ + } /* if ping packet */ +} + +/* + * sendto() a socket + */ +int +sosendto(so, m) + struct socket *so; + struct mbuf *m; +{ + int ret; + struct sockaddr_in addr; + + DEBUG_CALL("sosendto"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else + addr.sin_addr = so->so_faddr; + addr.sin_port = so->so_fport; + + DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); + + /* Don't care what port we get */ + ret = sendto(so->s, m->m_data, m->m_len, 0, + (struct sockaddr *)&addr, sizeof (struct sockaddr)); + if (ret < 0) + return -1; + + /* + * Kill the socket if there's no reply in 4 minutes, + * but only if it's an expirable socket + */ + if (so->so_expire) + so->so_expire = curtime + SO_EXPIRE; + so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */ + return 0; +} + +/* + * XXX This should really be tcp_listen + */ +struct socket * +solisten(port, laddr, lport, flags) + u_int port; + u_int32_t laddr; + u_int lport; + int flags; +{ + struct sockaddr_in addr; + struct socket *so; + int s, addrlen = sizeof(addr), opt = 1; + + DEBUG_CALL("solisten"); + DEBUG_ARG("port = %d", port); + DEBUG_ARG("laddr = %x", laddr); + DEBUG_ARG("lport = %d", lport); + DEBUG_ARG("flags = %x", flags); + + if ((so = socreate()) == NULL) { + /* free(so); Not sofree() ??? free(NULL) == NOP */ + return NULL; + } + + /* Don't tcp_attach... we don't need so_snd nor so_rcv */ + if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { + free(so); + return NULL; + } + insque(so,&tcb); + + /* + * SS_FACCEPTONCE sockets must time out. + */ + if (flags & SS_FACCEPTONCE) + so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; + + so->so_state = (SS_FACCEPTCONN|flags); + so->so_lport = lport; /* Kept in network format */ + so->so_laddr.s_addr = laddr; /* Ditto */ + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = port; + + if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || + (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || + (listen(s,1) < 0)) { + int tmperrno = errno; /* Don't clobber the real reason we failed */ + + close(s); + sofree(so); + /* Restore the real errno */ + errno = tmperrno; + return NULL; + } + setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + + getsockname(s,(struct sockaddr *)&addr,&addrlen); + so->so_fport = addr.sin_port; + if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) + so->so_faddr = our_addr; + else + so->so_faddr = addr.sin_addr; + + so->s = s; + return so; +} + +/* + * Data is available in so_rcv + * Just write() the data to the socket + * XXX not yet... + */ +void +sorwakeup(so) + struct socket *so; +{ +/* sowrite(so); */ +/* FD_CLR(so->s,&writefds); */ +} + +/* + * Data has been freed in so_snd + * We have room for a read() if we want to + * For now, don't read, it'll be done in the main loop + */ +void +sowwakeup(so) + struct socket *so; +{ + /* Nothing, yet */ +} + +/* + * Various session state calls + * XXX Should be #define's + * The socket state stuff needs work, these often get call 2 or 3 + * times each when only 1 was needed + */ +void +soisfconnecting(so) + register struct socket *so; +{ + so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| + SS_FCANTSENDMORE|SS_FWDRAIN); + so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ +} + +void +soisfconnected(so) + register struct socket *so; +{ + so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); + so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ +} + +void +sofcantrcvmore(so) + struct socket *so; +{ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s,0); + FD_CLR(so->s, global_writefds); + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTSENDMORE) + so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */ + else + so->so_state |= SS_FCANTRCVMORE; +} + +void +sofcantsendmore(so) + struct socket *so; +{ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s,1); /* send FIN to fhost */ + FD_CLR(so->s, global_readfds); + FD_CLR(so->s, global_xfds); + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTRCVMORE) + so->so_state = SS_NOFDREF; /* as above */ + else + so->so_state |= SS_FCANTSENDMORE; +} + +void +soisfdisconnected(so) + struct socket *so; +{ +/* so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */ +/* close(so->s); */ +/* so->so_state = SS_ISFDISCONNECTED; */ + /* + * XXX Do nothing ... ? + */ +} + +/* + * Set write drain mode + * Set CANTSENDMORE once all data has been write()n + */ +void +sofwdrain(so) + struct socket *so; +{ + if (so->so_rcv.sb_cc) + so->so_state |= SS_FWDRAIN; + else + sofcantsendmore(so); +} + diff --git a/slirp/socket.h b/slirp/socket.h new file mode 100644 index 000000000..d05354c8c --- /dev/null +++ b/slirp/socket.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +/* MINE */ + +#ifndef _SLIRP_SOCKET_H_ +#define _SLIRP_SOCKET_H_ + +#define SO_EXPIRE 240000 +#define SO_EXPIREFAST 10000 + +/* + * Our socket structure + */ + +struct socket { + struct socket *so_next,*so_prev; /* For a linked list of sockets */ + + int s; /* The actual socket */ + + /* XXX union these with not-yet-used sbuf params */ + struct mbuf *so_m; /* Pointer to the original SYN packet, + * for non-blocking connect()'s, and + * PING reply's */ + struct tcpiphdr *so_ti; /* Pointer to the original ti within + * so_mconn, for non-blocking connections */ + int so_urgc; + struct in_addr so_faddr; /* foreign host table entry */ + struct in_addr so_laddr; /* local host table entry */ + u_int16_t so_fport; /* foreign port */ + u_int16_t so_lport; /* local port */ + + u_int8_t so_iptos; /* Type of service */ + u_int8_t so_emu; /* Is the socket emulated? */ + + u_char so_type; /* Type of socket, UDP or TCP */ + int so_state; /* internal state flags SS_*, below */ + + struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ + u_int so_expire; /* When the socket will expire */ + + int so_queued; /* Number of packets queued from this socket */ + int so_nqueued; /* Number of packets queued in a row + * Used to determine when to "downgrade" a session + * from fastq to batchq */ + + struct sbuf so_rcv; /* Receive buffer */ + struct sbuf so_snd; /* Send buffer */ + void * extra; /* Extra pointer */ +}; + + +/* + * Socket state bits. (peer means the host on the Internet, + * local host means the host on the other end of the modem) + */ +#define SS_NOFDREF 0x001 /* No fd reference */ + +#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ +#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ +#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ +#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ +/* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ +#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ + +#define SS_CTL 0x080 +#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */ +#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ + +extern struct socket tcb; + + +#if defined(DECLARE_IOVEC) && !defined(HAVE_READV) +struct iovec { + char *iov_base; + size_t iov_len; +}; +#endif + +void so_init _P((void)); +struct socket * solookup _P((struct socket *, struct in_addr, u_int, struct in_addr, u_int)); +struct socket * socreate _P((void)); +void sofree _P((struct socket *)); +int soread _P((struct socket *)); +void sorecvoob _P((struct socket *)); +int sosendoob _P((struct socket *)); +int sowrite _P((struct socket *)); +void sorecvfrom _P((struct socket *)); +int sosendto _P((struct socket *, struct mbuf *)); +struct socket * solisten _P((u_int, u_int32_t, u_int, int)); +void sorwakeup _P((struct socket *)); +void sowwakeup _P((struct socket *)); +void soisfconnecting _P((register struct socket *)); +void soisfconnected _P((register struct socket *)); +void sofcantrcvmore _P((struct socket *)); +void sofcantsendmore _P((struct socket *)); +void soisfdisconnected _P((struct socket *)); +void sofwdrain _P((struct socket *)); + +#endif /* _SOCKET_H_ */ diff --git a/slirp/tcp.h b/slirp/tcp.h new file mode 100644 index 000000000..3e0b4dd8f --- /dev/null +++ b/slirp/tcp.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)tcp.h 8.1 (Berkeley) 6/10/93 + * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp + */ + +#ifndef _TCP_H_ +#define _TCP_H_ + +typedef u_int32_t tcp_seq; + +#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ +#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ + +extern int tcp_rcvspace; +extern int tcp_sndspace; +extern struct socket *tcp_last_so; + +#define TCP_SNDSPACE 8192 +#define TCP_RCVSPACE 8192 + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +struct tcphdr { + u_int16_t th_sport; /* source port */ + u_int16_t th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ +#ifdef WORDS_BIGENDIAN + u_int th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#else + u_int th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif + u_int8_t th_flags; +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 + u_int16_t th_win; /* window */ + u_int16_t th_sum; /* checksum */ + u_int16_t th_urp; /* urgent pointer */ +}; + +#include "tcp_var.h" + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOLEN_MAXSEG 4 +#define TCPOPT_WINDOW 3 +#define TCPOLEN_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOPT_SACK 5 /* Experimental */ +#define TCPOPT_TIMESTAMP 8 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ + +#define TCPOPT_TSTAMP_HDR \ + (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) + +/* + * Default maximum segment size for TCP. + * With an IP MSS of 576, this is 536, + * but 512 is probably more convenient. + * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). + */ +#define TCP_MSS 512 + +#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ + +#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ + +/* + * User-settable options (used with setsockopt). + */ +/* #define TCP_NODELAY 0x01 */ /* don't delay send to coalesce packets */ +/* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ + +/* + * TCP FSM state definitions. + * Per RFC793, September, 1981. + */ + +#define TCP_NSTATES 11 + +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ + +#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) +#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) +#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) + +/* + * TCP sequence numbers are 32 bit integers operated + * on with modular arithmetic. These macros can be + * used to compare such integers. + */ +#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Macros to initialize tcp sequence numbers for + * send and receive from initial send and receive + * sequence numbers. + */ +#define tcp_rcvseqinit(tp) \ + (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 + +#define tcp_sendseqinit(tp) \ + (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss + +#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ + +extern tcp_seq tcp_iss; /* tcp initial send seq # */ + +extern char *tcpstates[]; + +#endif diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c new file mode 100644 index 000000000..eeee98597 --- /dev/null +++ b/slirp/tcp_input.c @@ -0,0 +1,1745 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)tcp_input.c 8.5 (Berkeley) 4/10/94 + * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "ip_icmp.h" + +struct socket tcb; + +#define min(x,y) ((x) < (y) ? (x) : (y)) +#define max(x,y) ((x) > (y) ? (x) : (y)) + +int tcprexmtthresh = 3; +struct socket *tcp_last_so = &tcb; + +tcp_seq tcp_iss; /* tcp initial send seq # */ + +#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) + +/* for modulo comparisons of timestamps */ +#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) +#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Insert segment ti into reassembly queue of tcp with + * control block tp. Return TH_FIN if reassembly now includes + * a segment with FIN. The macro form does the common case inline + * (segment is the next to be received on an established connection, + * and the queue is empty), avoiding linkage into and removal + * from the queue and repetition of various conversions. + * Set DELACK for segments received in order, but ack immediately + * when segments are out of order (so fast retransmit can work). + */ +#ifdef TCP_ACK_HACK +#define TCP_REASS(tp, ti, m, so, flags) {\ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) {\ + if (ti->ti_flags & TH_PUSH) \ + tp->t_flags |= TF_ACKNOW; \ + else \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + if (so->so_emu) { \ + if (tcp_emu((so),(m))) sbappend((so), (m)); \ + } else \ + sbappend((so), (m)); \ +/* sorwakeup(so); */ \ + } else {\ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#else +#define TCP_REASS(tp, ti, m, so, flags) { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + if (so->so_emu) { \ + if (tcp_emu((so),(m))) sbappend(so, (m)); \ + } else \ + sbappend((so), (m)); \ +/* sorwakeup(so); */ \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#endif + +int +tcp_reass(tp, ti, m) + register struct tcpcb *tp; + register struct tcpiphdr *ti; + struct mbuf *m; +{ + register struct tcpiphdr *q; + struct socket *so = tp->t_socket; + int flags; + + /* + * Call with ti==0 after become established to + * force pre-ESTABLISHED data up to user socket. + */ + if (ti == 0) + goto present; + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; + q = (struct tcpiphdr *)q->ti_next) + if (SEQ_GT(q->ti_seq, ti->ti_seq)) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { + register int i; + q = (struct tcpiphdr *)q->ti_prev; + /* conversion to int (in i) handles seq wraparound */ + i = q->ti_seq + q->ti_len - ti->ti_seq; + if (i > 0) { + if (i >= ti->ti_len) { + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += ti->ti_len; + m_freem(m); + /* + * Try to present any queued data + * at the left window edge to the user. + * This is needed after the 3-WHS + * completes. + */ + goto present; /* ??? */ + } + m_adj(m, i); + ti->ti_len -= i; + ti->ti_seq += i; + } + q = (struct tcpiphdr *)(q->ti_next); + } + tcpstat.tcps_rcvoopack++; + tcpstat.tcps_rcvoobyte += ti->ti_len; + REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct tcpiphdr *)tp) { + register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; + if (i <= 0) + break; + if (i < q->ti_len) { + q->ti_seq += i; + q->ti_len -= i; + m_adj((struct mbuf *) REASS_MBUF(q), i); + break; + } + q = (struct tcpiphdr *)q->ti_next; + m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); + remque_32((void *)(q->ti_prev)); + m_freem(m); + } + + /* + * Stick new segment in its place. + */ + insque_32(ti, (void *)(q->ti_prev)); + +present: + /* + * Present data to user, advancing rcv_nxt through + * completed sequence space. + */ + if (!TCPS_HAVEESTABLISHED(tp->t_state)) + return (0); + ti = (struct tcpiphdr *) tp->seg_next; + if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) + return (0); + if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) + return (0); + do { + tp->rcv_nxt += ti->ti_len; + flags = ti->ti_flags & TH_FIN; + remque_32(ti); + m = (struct mbuf *) REASS_MBUF(ti); /* XXX */ + ti = (struct tcpiphdr *)ti->ti_next; +/* if (so->so_state & SS_FCANTRCVMORE) */ + if (so->so_state & SS_FCANTSENDMORE) + m_freem(m); + else { + if (so->so_emu) { + if (tcp_emu(so,m)) sbappend(so, m); + } else + sbappend(so, m); + } + } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); +/* sorwakeup(so); */ + return (flags); +} + +/* + * TCP input routine, follows pages 65-76 of the + * protocol specification dated September, 1981 very closely. + */ +void +tcp_input(m, iphlen, inso) + register struct mbuf *m; + int iphlen; + struct socket *inso; +{ + struct ip save_ip, *ip; + register struct tcpiphdr *ti; + caddr_t optp = NULL; + int optlen = 0; + int len, tlen, off; + register struct tcpcb *tp = 0; + register int tiflags; + struct socket *so = 0; + int todrop, acked, ourfinisacked, needoutput = 0; +/* int dropsocket = 0; */ + int iss = 0; + u_long tiwin; + int ret; +/* int ts_present = 0; */ + + DEBUG_CALL("tcp_input"); + DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", + (long )m, iphlen, (long )inso )); + + /* + * If called with m == 0, then we're continuing the connect + */ + if (m == NULL) { + so = inso; + + /* Re-set a few variables */ + tp = sototcpcb(so); + m = so->so_m; + so->so_m = 0; + ti = so->so_ti; + tiwin = ti->ti_win; + tiflags = ti->ti_flags; + + goto cont_conn; + } + + + tcpstat.tcps_rcvtotal++; + /* + * Get IP and TCP header together in first mbuf. + * Note: IP leaves IP header in first mbuf. + */ + ti = mtod(m, struct tcpiphdr *); + if (iphlen > sizeof(struct ip )) { + ip_stripoptions(m, (struct mbuf *)0); + iphlen=sizeof(struct ip ); + } + /* XXX Check if too short */ + + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + ip=mtod(m, struct ip *); + save_ip = *ip; + save_ip.ip_len+= iphlen; + + /* + * Checksum extended TCP header and data. + */ + tlen = ((struct ip *)ti)->ip_len; + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_len = htons((u_int16_t)tlen); + len = sizeof(struct ip ) + tlen; + /* keep checksum for ICMP reply + * ti->ti_sum = cksum(m, len); + * if (ti->ti_sum) { */ + if(cksum(m, len)) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } + + /* + * Check that TCP offset makes sense, + * pull out TCP options and adjust length. XXX + */ + off = ti->ti_off << 2; + if (off < sizeof (struct tcphdr) || off > tlen) { + tcpstat.tcps_rcvbadoff++; + goto drop; + } + tlen -= off; + ti->ti_len = tlen; + if (off > sizeof (struct tcphdr)) { + optlen = off - sizeof (struct tcphdr); + optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr); + + /* + * Do quick retrieval of timestamp options ("options + * prediction?"). If timestamp is the only option and it's + * formatted as recommended in RFC 1323 appendix A, we + * quickly get the values now and not bother calling + * tcp_dooptions(), etc. + */ +/* if ((optlen == TCPOLEN_TSTAMP_APPA || + * (optlen > TCPOLEN_TSTAMP_APPA && + * optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && + * *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) && + * (ti->ti_flags & TH_SYN) == 0) { + * ts_present = 1; + * ts_val = ntohl(*(u_int32_t *)(optp + 4)); + * ts_ecr = ntohl(*(u_int32_t *)(optp + 8)); + * optp = NULL; / * we've parsed the options * / + * } + */ + } + tiflags = ti->ti_flags; + + /* + * Convert TCP protocol specific fields to host format. + */ + NTOHL(ti->ti_seq); + NTOHL(ti->ti_ack); + NTOHS(ti->ti_win); + NTOHS(ti->ti_urp); + + /* + * Drop TCP, IP headers and TCP options. + */ + m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + + /* + * Locate pcb for segment. + */ +findso: + so = tcp_last_so; + if (so->so_fport != ti->ti_dport || + so->so_lport != ti->ti_sport || + so->so_laddr.s_addr != ti->ti_src.s_addr || + so->so_faddr.s_addr != ti->ti_dst.s_addr) { + so = solookup(&tcb, ti->ti_src, ti->ti_sport, + ti->ti_dst, ti->ti_dport); + if (so) + tcp_last_so = so; + ++tcpstat.tcps_socachemiss; + } + + /* + * If the state is CLOSED (i.e., TCB does not exist) then + * all data in the incoming segment is discarded. + * If the TCB exists but is in CLOSED state, it is embryonic, + * but should either do a listen or a connect soon. + * + * state == CLOSED means we've done socreate() but haven't + * attached it to a protocol yet... + * + * XXX If a TCB does not exist, and the TH_SYN flag is + * the only flag set, then create a session, mark it + * as if it was LISTENING, and continue... + */ + if (so == 0) { + if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN) + goto dropwithreset; + + if ((so = socreate()) == NULL) + goto dropwithreset; + if (tcp_attach(so) < 0) { + free(so); /* Not sofree (if it failed, it's not insqued) */ + goto dropwithreset; + } + + sbreserve(&so->so_snd, tcp_sndspace); + sbreserve(&so->so_rcv, tcp_rcvspace); + + /* tcp_last_so = so; */ /* XXX ? */ + /* tp = sototcpcb(so); */ + + so->so_laddr = ti->ti_src; + so->so_lport = ti->ti_sport; + so->so_faddr = ti->ti_dst; + so->so_fport = ti->ti_dport; + + if ((so->so_iptos = tcp_tos(so)) == 0) + so->so_iptos = ((struct ip *)ti)->ip_tos; + + tp = sototcpcb(so); + tp->t_state = TCPS_LISTEN; + } + + /* + * If this is a still-connecting socket, this probably + * a retransmit of the SYN. Whether it's a retransmit SYN + * or something else, we nuke it. + */ + if (so->so_state & SS_ISFCONNECTING) + goto drop; + + tp = sototcpcb(so); + + /* XXX Should never fail */ + if (tp == 0) + goto dropwithreset; + if (tp->t_state == TCPS_CLOSED) + goto drop; + + /* Unscale the window into a 32-bit value. */ +/* if ((tiflags & TH_SYN) == 0) + * tiwin = ti->ti_win << tp->snd_scale; + * else + */ + tiwin = ti->ti_win; + + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + */ + tp->t_idle = 0; + if (so_options) + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + + /* + * Process options if not in LISTEN state, + * else do it below (after getting remote address). + */ + if (optp && tp->t_state != TCPS_LISTEN) + tcp_dooptions(tp, (u_char *)optp, optlen, ti); +/* , */ +/* &ts_present, &ts_val, &ts_ecr); */ + + /* + * Header prediction: check for the two common cases + * of a uni-directional data xfer. If the packet has + * no control flags, is in-sequence, the window didn't + * change and we're not retransmitting, it's a + * candidate. If the length is zero and the ack moved + * forward, we're the sender side of the xfer. Just + * free the data acked & wake any higher level process + * that was blocked waiting for space. If the length + * is non-zero and the ack didn't move, we're the + * receiver side. If we're getting packets in-order + * (the reassembly queue is empty), add the data to + * the socket buffer and note that we need a delayed ack. + * + * XXX Some of these tests are not needed + * eg: the tiwin == tp->snd_wnd prevents many more + * predictions.. with no *real* advantage.. + */ + if (tp->t_state == TCPS_ESTABLISHED && + (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && +/* (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && */ + ti->ti_seq == tp->rcv_nxt && + tiwin && tiwin == tp->snd_wnd && + tp->snd_nxt == tp->snd_max) { + /* + * If last ACK falls within this segment's sequence numbers, + * record the timestamp. + */ +/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && + * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { + * tp->ts_recent_age = tcp_now; + * tp->ts_recent = ts_val; + * } + */ + if (ti->ti_len == 0) { + if (SEQ_GT(ti->ti_ack, tp->snd_una) && + SEQ_LEQ(ti->ti_ack, tp->snd_max) && + tp->snd_cwnd >= tp->snd_wnd) { + /* + * this is a pure ack for outstanding data. + */ + ++tcpstat.tcps_predack; +/* if (ts_present) + * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); + * else + */ if (tp->t_rtt && + SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp, tp->t_rtt); + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + sbdrop(&so->so_snd, acked); + tp->snd_una = ti->ti_ack; + m_freem(m); + + /* + * If all outstanding data are acked, stop + * retransmit timer, otherwise restart timer + * using current (possibly backed-off) value. + * If process is waiting for space, + * wakeup/selwakeup/signal. If data + * are ready to send, let tcp_output + * decide between more output or persist. + */ + if (tp->snd_una == tp->snd_max) + tp->t_timer[TCPT_REXMT] = 0; + else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + + /* + * There's room in so_snd, sowwakup will read() + * from the socket if we can + */ +/* if (so->so_snd.sb_flags & SB_NOTIFY) + * sowwakeup(so); + */ + /* + * This is called because sowwakeup might have + * put data into so_snd. Since we don't so sowwakeup, + * we don't need this.. XXX??? + */ + if (so->so_snd.sb_cc) + (void) tcp_output(tp); + + return; + } + } else if (ti->ti_ack == tp->snd_una && + tp->seg_next == (tcpiphdrp_32)tp && + ti->ti_len <= sbspace(&so->so_rcv)) { + /* + * this is a pure, in-sequence data packet + * with nothing on the reassembly queue and + * we have enough buffer space to take it. + */ + ++tcpstat.tcps_preddat; + tp->rcv_nxt += ti->ti_len; + tcpstat.tcps_rcvpack++; + tcpstat.tcps_rcvbyte += ti->ti_len; + /* + * Add data to socket buffer. + */ + if (so->so_emu) { + if (tcp_emu(so,m)) sbappend(so, m); + } else + sbappend(so, m); + + /* + * XXX This is called when data arrives. Later, check + * if we can actually write() to the socket + * XXX Need to check? It's be NON_BLOCKING + */ +/* sorwakeup(so); */ + + /* + * If this is a short packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + * + * Here are 3 interpretations of what should happen. + * The best (for me) is to delay-ack everything except + * if it's a one-byte packet containing an ESC + * (this means it's an arrow key (or similar) sent using + * Nagel, hence there will be no echo) + * The first of these is the original, the second is the + * middle ground between the other 2 + */ +/* if (((unsigned)ti->ti_len < tp->t_maxseg)) { + */ +/* if (((unsigned)ti->ti_len < tp->t_maxseg && + * (so->so_iptos & IPTOS_LOWDELAY) == 0) || + * ((so->so_iptos & IPTOS_LOWDELAY) && + * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { + */ + if ((unsigned)ti->ti_len == 1 && + ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { + tp->t_flags |= TF_ACKNOW; + tcp_output(tp); + } else { + tp->t_flags |= TF_DELACK; + } + return; + } + } /* header prediction */ + /* + * Calculate amount of space in receive window, + * and then do TCP input processing. + * Receive window is amount of space in rcv queue, + * but not less than advertised window. + */ + { int win; + win = sbspace(&so->so_rcv); + if (win < 0) + win = 0; + tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); + } + + switch (tp->t_state) { + + /* + * If the state is LISTEN then ignore segment if it contains an RST. + * If the segment contains an ACK then it is bad and send a RST. + * If it does not contain a SYN then it is not interesting; drop it. + * Don't bother responding if the destination was a broadcast. + * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial + * tp->iss, and send a segment: + * + * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. + * Fill in remote peer address fields if not previously specified. + * Enter SYN_RECEIVED state, and process any other fields of this + * segment in this state. + */ + case TCPS_LISTEN: { + + if (tiflags & TH_RST) + goto drop; + if (tiflags & TH_ACK) + goto dropwithreset; + if ((tiflags & TH_SYN) == 0) + goto drop; + + /* + * This has way too many gotos... + * But a bit of spaghetti code never hurt anybody :) + */ + + /* + * If this is destined for the control address, then flag to + * tcp_ctl once connected, otherwise connect + */ + if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) { + int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff; + if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) { +#if 0 + if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) { + /* Command or exec adress */ + so->so_state |= SS_CTL; + } else { + /* May be an add exec */ + struct ex_list *ex_ptr; + + for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if(ex_ptr->ex_fport == so->so_fport && + lastbyte == ex_ptr->ex_addr) { + so->so_state |= SS_CTL; + break; + } + } + } + if(so->so_state & SS_CTL) goto cont_input; +#endif + } + /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ + } + + if (so->so_emu & EMU_NOCONNECT) { + so->so_emu &= ~EMU_NOCONNECT; + goto cont_input; + } + + if(tcp_fconnect(so) == -1 && errno != EINPROGRESS) { + u_char code=ICMP_UNREACH_NET; + DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", + errno,strerror(errno))); + if(errno == ECONNREFUSED) { + /* ACK the SYN, send RST to refuse the connection */ + tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0, + TH_RST|TH_ACK); + } else { + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + HTONL(ti->ti_seq); /* restore tcp header */ + HTONL(ti->ti_ack); + HTONS(ti->ti_win); + HTONS(ti->ti_urp); + m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + *ip=save_ip; + icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); + } + tp = tcp_close(tp); + m_free(m); + } else { + /* + * Haven't connected yet, save the current mbuf + * and ti, and return + * XXX Some OS's don't tell us whether the connect() + * succeeded or not. So we must time it out. + */ + so->so_m = m; + so->so_ti = ti; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->t_state = TCPS_SYN_RECEIVED; + } + return; + + cont_conn: + /* m==NULL + * Check if the connect succeeded + */ + if (so->so_state & SS_NOFDREF) { + tp = tcp_close(tp); + goto dropwithreset; + } + cont_input: + tcp_template(tp); + + if (optp) + tcp_dooptions(tp, (u_char *)optp, optlen, ti); + /* , */ + /* &ts_present, &ts_val, &ts_ecr); */ + + if (iss) + tp->iss = iss; + else + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tp->irs = ti->ti_seq; + tcp_sendseqinit(tp); + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + tp->t_state = TCPS_SYN_RECEIVED; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tcpstat.tcps_accepts++; + goto trimthenstep6; + } /* case TCPS_LISTEN */ + + /* + * If the state is SYN_SENT: + * if seg contains an ACK, but not for our SYN, drop the input. + * if seg contains a RST, then drop the connection. + * if seg does not contain SYN, then drop it. + * Otherwise this is an acceptable SYN segment + * initialize tp->rcv_nxt and tp->irs + * if seg contains ack then advance tp->snd_una + * if SYN has been acked change to ESTABLISHED else SYN_RCVD state + * arrange for segment to be acked (eventually) + * continue processing rest of data/controls, beginning with URG + */ + case TCPS_SYN_SENT: + if ((tiflags & TH_ACK) && + (SEQ_LEQ(ti->ti_ack, tp->iss) || + SEQ_GT(ti->ti_ack, tp->snd_max))) + goto dropwithreset; + + if (tiflags & TH_RST) { + if (tiflags & TH_ACK) + tp = tcp_drop(tp,0); /* XXX Check t_softerror! */ + goto drop; + } + + if ((tiflags & TH_SYN) == 0) + goto drop; + if (tiflags & TH_ACK) { + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + } + + tp->t_timer[TCPT_REXMT] = 0; + tp->irs = ti->ti_seq; + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { + tcpstat.tcps_connects++; + soisfconnected(so); + tp->t_state = TCPS_ESTABLISHED; + + /* Do window scaling on this connection? */ +/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + * (TF_RCVD_SCALE|TF_REQ_SCALE)) { + * tp->snd_scale = tp->requested_s_scale; + * tp->rcv_scale = tp->request_r_scale; + * } + */ + (void) tcp_reass(tp, (struct tcpiphdr *)0, + (struct mbuf *)0); + /* + * if we didn't have to retransmit the SYN, + * use its rtt as our initial srtt & rtt var. + */ + if (tp->t_rtt) + tcp_xmit_timer(tp, tp->t_rtt); + } else + tp->t_state = TCPS_SYN_RECEIVED; + +trimthenstep6: + /* + * Advance ti->ti_seq to correspond to first data byte. + * If data, trim to stay within window, + * dropping FIN if necessary. + */ + ti->ti_seq++; + if (ti->ti_len > tp->rcv_wnd) { + todrop = ti->ti_len - tp->rcv_wnd; + m_adj(m, -todrop); + ti->ti_len = tp->rcv_wnd; + tiflags &= ~TH_FIN; + tcpstat.tcps_rcvpackafterwin++; + tcpstat.tcps_rcvbyteafterwin += todrop; + } + tp->snd_wl1 = ti->ti_seq - 1; + tp->rcv_up = ti->ti_seq; + goto step6; + } /* switch tp->t_state */ + /* + * States other than LISTEN or SYN_SENT. + * First check timestamp, if present. + * Then check that at least some bytes of segment are within + * receive window. If segment begins before rcv_nxt, + * drop leading data (and SYN); if nothing left, just ack. + * + * RFC 1323 PAWS: If we have a timestamp reply on this segment + * and it's less than ts_recent, drop it. + */ +/* if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && + * TSTMP_LT(ts_val, tp->ts_recent)) { + * + */ /* Check to see if ts_recent is over 24 days old. */ +/* if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { + */ /* + * * Invalidate ts_recent. If this segment updates + * * ts_recent, the age will be reset later and ts_recent + * * will get a valid value. If it does not, setting + * * ts_recent to zero will at least satisfy the + * * requirement that zero be placed in the timestamp + * * echo reply when ts_recent isn't valid. The + * * age isn't reset until we get a valid ts_recent + * * because we don't want out-of-order segments to be + * * dropped when ts_recent is old. + * */ +/* tp->ts_recent = 0; + * } else { + * tcpstat.tcps_rcvduppack++; + * tcpstat.tcps_rcvdupbyte += ti->ti_len; + * tcpstat.tcps_pawsdrop++; + * goto dropafterack; + * } + * } + */ + + todrop = tp->rcv_nxt - ti->ti_seq; + if (todrop > 0) { + if (tiflags & TH_SYN) { + tiflags &= ~TH_SYN; + ti->ti_seq++; + if (ti->ti_urp > 1) + ti->ti_urp--; + else + tiflags &= ~TH_URG; + todrop--; + } + /* + * Following if statement from Stevens, vol. 2, p. 960. + */ + if (todrop > ti->ti_len + || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { + /* + * Any valid FIN must be to the left of the window. + * At this point the FIN must be a duplicate or out + * of sequence; drop it. + */ + tiflags &= ~TH_FIN; + + /* + * Send an ACK to resynchronize and drop any data. + * But keep on processing for RST or ACK. + */ + tp->t_flags |= TF_ACKNOW; + todrop = ti->ti_len; + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += todrop; + } else { + tcpstat.tcps_rcvpartduppack++; + tcpstat.tcps_rcvpartdupbyte += todrop; + } + m_adj(m, todrop); + ti->ti_seq += todrop; + ti->ti_len -= todrop; + if (ti->ti_urp > todrop) + ti->ti_urp -= todrop; + else { + tiflags &= ~TH_URG; + ti->ti_urp = 0; + } + } + /* + * If new data are received on a connection after the + * user processes are gone, then RST the other end. + */ + if ((so->so_state & SS_NOFDREF) && + tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { + tp = tcp_close(tp); + tcpstat.tcps_rcvafterclose++; + goto dropwithreset; + } + + /* + * If segment ends after window, drop trailing data + * (and PUSH and FIN); if nothing left, just ACK. + */ + todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); + if (todrop > 0) { + tcpstat.tcps_rcvpackafterwin++; + if (todrop >= ti->ti_len) { + tcpstat.tcps_rcvbyteafterwin += ti->ti_len; + /* + * If a new connection request is received + * while in TIME_WAIT, drop the old connection + * and start over if the sequence numbers + * are above the previous ones. + */ + if (tiflags & TH_SYN && + tp->t_state == TCPS_TIME_WAIT && + SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { + iss = tp->rcv_nxt + TCP_ISSINCR; + tp = tcp_close(tp); + goto findso; + } + /* + * If window is closed can only take segments at + * window edge, and have to drop data and PUSH from + * incoming segments. Continue processing, but + * remember to ack. Otherwise, drop segment + * and ack. + */ + if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_rcvwinprobe++; + } else + goto dropafterack; + } else + tcpstat.tcps_rcvbyteafterwin += todrop; + m_adj(m, -todrop); + ti->ti_len -= todrop; + tiflags &= ~(TH_PUSH|TH_FIN); + } + + /* + * If last ACK falls within this segment's sequence numbers, + * record its timestamp. + */ +/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && + * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + + * ((tiflags & (TH_SYN|TH_FIN)) != 0))) { + * tp->ts_recent_age = tcp_now; + * tp->ts_recent = ts_val; + * } + */ + + /* + * If the RST bit is set examine the state: + * SYN_RECEIVED STATE: + * If passive open, return to LISTEN state. + * If active open, inform user that connection was refused. + * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: + * Inform user that connection was reset, and close tcb. + * CLOSING, LAST_ACK, TIME_WAIT STATES + * Close the tcb. + */ + if (tiflags&TH_RST) switch (tp->t_state) { + + case TCPS_SYN_RECEIVED: +/* so->so_error = ECONNREFUSED; */ + goto close; + + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: +/* so->so_error = ECONNRESET; */ + close: + tp->t_state = TCPS_CLOSED; + tcpstat.tcps_drops++; + tp = tcp_close(tp); + goto drop; + + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + tp = tcp_close(tp); + goto drop; + } + + /* + * If a SYN is in the window, then this is an + * error and we send an RST and drop the connection. + */ + if (tiflags & TH_SYN) { + tp = tcp_drop(tp,0); + goto dropwithreset; + } + + /* + * If the ACK bit is off we drop the segment and return. + */ + if ((tiflags & TH_ACK) == 0) goto drop; + + /* + * Ack processing. + */ + switch (tp->t_state) { + /* + * In SYN_RECEIVED state if the ack ACKs our SYN then enter + * ESTABLISHED state and continue processing, otherwise + * send an RST. una<=ack<=max + */ + case TCPS_SYN_RECEIVED: + + if (SEQ_GT(tp->snd_una, ti->ti_ack) || + SEQ_GT(ti->ti_ack, tp->snd_max)) + goto dropwithreset; + tcpstat.tcps_connects++; + tp->t_state = TCPS_ESTABLISHED; + /* + * The sent SYN is ack'ed with our sequence number +1 + * The first data byte already in the buffer will get + * lost if no correction is made. This is only needed for + * SS_CTL since the buffer is empty otherwise. + * tp->snd_una++; or: + */ + tp->snd_una=ti->ti_ack; + if (so->so_state & SS_CTL) { + /* So tcp_ctl reports the right state */ + ret = tcp_ctl(so); + if (ret == 1) { + soisfconnected(so); + so->so_state &= ~SS_CTL; /* success XXX */ + } else if (ret == 2) { + so->so_state = SS_NOFDREF; /* CTL_CMD */ + } else { + needoutput = 1; + tp->t_state = TCPS_FIN_WAIT_1; + } + } else { + soisfconnected(so); + } + + /* Do window scaling? */ +/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + * (TF_RCVD_SCALE|TF_REQ_SCALE)) { + * tp->snd_scale = tp->requested_s_scale; + * tp->rcv_scale = tp->request_r_scale; + * } + */ + (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0); + tp->snd_wl1 = ti->ti_seq - 1; + /* Avoid ack processing; snd_una==ti_ack => dup ack */ + goto synrx_to_est; + /* fall into ... */ + + /* + * In ESTABLISHED state: drop duplicate ACKs; ACK out of range + * ACKs. If the ack is in the range + * tp->snd_una < ti->ti_ack <= tp->snd_max + * then advance tp->snd_una to ti->ti_ack and drop + * data from the retransmission queue. If this ACK reflects + * more up to date window information we update our window information. + */ + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + + if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { + if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { + tcpstat.tcps_rcvdupack++; + DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", + (long )m, (long )so)); + /* + * If we have outstanding data (other than + * a window probe), this is a completely + * duplicate ack (ie, window info didn't + * change), the ack is the biggest we've + * seen and we've seen exactly our rexmt + * threshold of them, assume a packet + * has been dropped and retransmit it. + * Kludge snd_nxt & the congestion + * window so we send only this one + * packet. + * + * We know we're losing at the current + * window size so do congestion avoidance + * (set ssthresh to half the current window + * and pull our congestion window back to + * the new ssthresh). + * + * Dup acks mean that packets have left the + * network (they're now cached at the receiver) + * so bump cwnd by the amount in the receiver + * to keep a constant cwnd packets in the + * network. + */ + if (tp->t_timer[TCPT_REXMT] == 0 || + ti->ti_ack != tp->snd_una) + tp->t_dupacks = 0; + else if (++tp->t_dupacks == tcprexmtthresh) { + tcp_seq onxt = tp->snd_nxt; + u_int win = + min(tp->snd_wnd, tp->snd_cwnd) / 2 / + tp->t_maxseg; + + if (win < 2) + win = 2; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_timer[TCPT_REXMT] = 0; + tp->t_rtt = 0; + tp->snd_nxt = ti->ti_ack; + tp->snd_cwnd = tp->t_maxseg; + (void) tcp_output(tp); + tp->snd_cwnd = tp->snd_ssthresh + + tp->t_maxseg * tp->t_dupacks; + if (SEQ_GT(onxt, tp->snd_nxt)) + tp->snd_nxt = onxt; + goto drop; + } else if (tp->t_dupacks > tcprexmtthresh) { + tp->snd_cwnd += tp->t_maxseg; + (void) tcp_output(tp); + goto drop; + } + } else + tp->t_dupacks = 0; + break; + } + synrx_to_est: + /* + * If the congestion window was inflated to account + * for the other side's cached packets, retract it. + */ + if (tp->t_dupacks > tcprexmtthresh && + tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; + tp->t_dupacks = 0; + if (SEQ_GT(ti->ti_ack, tp->snd_max)) { + tcpstat.tcps_rcvacktoomuch++; + goto dropafterack; + } + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + + /* + * If we have a timestamp reply, update smoothed + * round trip time. If no timestamp is present but + * transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * Since we now have an rtt measurement, cancel the + * timer backoff (cf., Phil Karn's retransmit alg.). + * Recompute the initial retransmit timer. + */ +/* if (ts_present) + * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); + * else + */ + if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp,tp->t_rtt); + + /* + * If all outstanding data is acked, stop retransmit + * timer and remember to restart (more output or persist). + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value. + */ + if (ti->ti_ack == tp->snd_max) { + tp->t_timer[TCPT_REXMT] = 0; + needoutput = 1; + } else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * When new data is acked, open the congestion window. + * If the window gives us less than ssthresh packets + * in flight, open exponentially (maxseg per packet). + * Otherwise open linearly: maxseg per window + * (maxseg^2 / cwnd per packet). + */ + { + register u_int cw = tp->snd_cwnd; + register u_int incr = tp->t_maxseg; + + if (cw > tp->snd_ssthresh) + incr = incr * incr / cw; + tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); + } + if (acked > so->so_snd.sb_cc) { + tp->snd_wnd -= so->so_snd.sb_cc; + sbdrop(&so->so_snd, (int )so->so_snd.sb_cc); + ourfinisacked = 1; + } else { + sbdrop(&so->so_snd, acked); + tp->snd_wnd -= acked; + ourfinisacked = 0; + } + /* + * XXX sowwakup is called when data is acked and there's room for + * for more data... it should read() the socket + */ +/* if (so->so_snd.sb_flags & SB_NOTIFY) + * sowwakeup(so); + */ + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + + switch (tp->t_state) { + + /* + * In FIN_WAIT_1 STATE in addition to the processing + * for the ESTABLISHED state if our FIN is now acknowledged + * then enter FIN_WAIT_2. + */ + case TCPS_FIN_WAIT_1: + if (ourfinisacked) { + /* + * If we can't receive any more + * data, then closing user can proceed. + * Starting the timer is contrary to the + * specification, but if we don't get a FIN + * we'll hang forever. + */ + if (so->so_state & SS_FCANTRCVMORE) { + soisfdisconnected(so); + tp->t_timer[TCPT_2MSL] = tcp_maxidle; + } + tp->t_state = TCPS_FIN_WAIT_2; + } + break; + + /* + * In CLOSING STATE in addition to the processing for + * the ESTABLISHED state if the ACK acknowledges our FIN + * then enter the TIME-WAIT state, otherwise ignore + * the segment. + */ + case TCPS_CLOSING: + if (ourfinisacked) { + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisfdisconnected(so); + } + break; + + /* + * In LAST_ACK, we may still be waiting for data to drain + * and/or to be acked, as well as for the ack of our FIN. + * If our FIN is now acknowledged, delete the TCB, + * enter the closed state and return. + */ + case TCPS_LAST_ACK: + if (ourfinisacked) { + tp = tcp_close(tp); + goto drop; + } + break; + + /* + * In TIME_WAIT state the only thing that should arrive + * is a retransmission of the remote FIN. Acknowledge + * it and restart the finack timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + goto dropafterack; + } + } /* switch(tp->t_state) */ + +step6: + /* + * Update window information. + * Don't look at window if no ACK: TAC's send garbage on first SYN. + */ + if ((tiflags & TH_ACK) && + (SEQ_LT(tp->snd_wl1, ti->ti_seq) || + (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || + (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { + /* keep track of pure window updates */ + if (ti->ti_len == 0 && + tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) + tcpstat.tcps_rcvwinupd++; + tp->snd_wnd = tiwin; + tp->snd_wl1 = ti->ti_seq; + tp->snd_wl2 = ti->ti_ack; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + needoutput = 1; + } + + /* + * Process segments with URG. + */ + if ((tiflags & TH_URG) && ti->ti_urp && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * This is a kludge, but if we receive and accept + * random urgent pointers, we'll crash in + * soreceive. It's hard to imagine someone + * actually wanting to send this much urgent data. + */ + if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) { + ti->ti_urp = 0; + tiflags &= ~TH_URG; + goto dodata; + } + /* + * If this segment advances the known urgent pointer, + * then mark the data stream. This should not happen + * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since + * a FIN has been received from the remote side. + * In these states we ignore the URG. + * + * According to RFC961 (Assigned Protocols), + * the urgent pointer points to the last octet + * of urgent data. We continue, however, + * to consider it to indicate the first octet + * of data past the urgent section as the original + * spec states (in one of two places). + */ + if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { + tp->rcv_up = ti->ti_seq + ti->ti_urp; + so->so_urgc = so->so_rcv.sb_cc + + (tp->rcv_up - tp->rcv_nxt); /* -1; */ + tp->rcv_up = ti->ti_seq + ti->ti_urp; + + } + } else + /* + * If no out of band data is expected, + * pull receive urgent pointer along + * with the receive window. + */ + if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) + tp->rcv_up = tp->rcv_nxt; +dodata: + + /* + * Process the segment text, merging it into the TCP sequencing queue, + * and arranging for acknowledgment of receipt if necessary. + * This process logically involves adjusting tp->rcv_wnd as data + * is presented to the user (this happens in tcp_usrreq.c, + * case PRU_RCVD). If a FIN has already been received on this + * connection then we just ignore the text. + */ + if ((ti->ti_len || (tiflags&TH_FIN)) && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + TCP_REASS(tp, ti, m, so, tiflags); + /* + * Note the amount of data that peer has sent into + * our window, in order to estimate the sender's + * buffer size. + */ + len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt); + } else { + m_free(m); + tiflags &= ~TH_FIN; + } + + /* + * If FIN is received ACK the FIN and let the user know + * that the connection is closing. + */ + if (tiflags & TH_FIN) { + if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * If we receive a FIN we can't send more data, + * set it SS_FDRAIN + * Shutdown the socket if there is no rx data in the + * buffer. + * soread() is called on completion of shutdown() and + * will got to TCPS_LAST_ACK, and use tcp_output() + * to send the FIN. + */ +/* sofcantrcvmore(so); */ + sofwdrain(so); + + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt++; + } + switch (tp->t_state) { + + /* + * In SYN_RECEIVED and ESTABLISHED STATES + * enter the CLOSE_WAIT state. + */ + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + if(so->so_emu == EMU_CTL) /* no shutdown on socket */ + tp->t_state = TCPS_LAST_ACK; + else + tp->t_state = TCPS_CLOSE_WAIT; + break; + + /* + * If still in FIN_WAIT_1 STATE FIN has not been acked so + * enter the CLOSING state. + */ + case TCPS_FIN_WAIT_1: + tp->t_state = TCPS_CLOSING; + break; + + /* + * In FIN_WAIT_2 state enter the TIME_WAIT state, + * starting the time-wait timer, turning off the other + * standard timers. + */ + case TCPS_FIN_WAIT_2: + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisfdisconnected(so); + break; + + /* + * In TIME_WAIT state restart the 2 MSL time_wait timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + break; + } + } + + /* + * If this is a small packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + * + * See above. + */ +/* if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) { + */ +/* if ((ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg && + * (so->so_iptos & IPTOS_LOWDELAY) == 0) || + * ((so->so_iptos & IPTOS_LOWDELAY) && + * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { + */ + if (ti->ti_len && (unsigned)ti->ti_len <= 5 && + ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { + tp->t_flags |= TF_ACKNOW; + } + + /* + * Return any desired output. + */ + if (needoutput || (tp->t_flags & TF_ACKNOW)) { + (void) tcp_output(tp); + } + return; + +dropafterack: + /* + * Generate an ACK dropping incoming segment if it occupies + * sequence space, where the ACK reflects our state. + */ + if (tiflags & TH_RST) + goto drop; + m_freem(m); + tp->t_flags |= TF_ACKNOW; + (void) tcp_output(tp); + return; + +dropwithreset: + /* reuses m if m!=NULL, m_free() unnecessary */ + if (tiflags & TH_ACK) + tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); + else { + if (tiflags & TH_SYN) ti->ti_len++; + tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, + TH_RST|TH_ACK); + } + + return; + +drop: + /* + * Drop space held by incoming segment and return. + */ + m_free(m); + + return; +} + + /* , ts_present, ts_val, ts_ecr) */ +/* int *ts_present; + * u_int32_t *ts_val, *ts_ecr; + */ +void +tcp_dooptions(tp, cp, cnt, ti) + struct tcpcb *tp; + u_char *cp; + int cnt; + struct tcpiphdr *ti; +{ + u_int16_t mss; + int opt, optlen; + + DEBUG_CALL("tcp_dooptions"); + DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt)); + + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == TCPOPT_EOL) + break; + if (opt == TCPOPT_NOP) + optlen = 1; + else { + optlen = cp[1]; + if (optlen <= 0) + break; + } + switch (opt) { + + default: + continue; + + case TCPOPT_MAXSEG: + if (optlen != TCPOLEN_MAXSEG) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + memcpy((char *) &mss, (char *) cp + 2, sizeof(mss)); + NTOHS(mss); + (void) tcp_mss(tp, mss); /* sets t_maxseg */ + break; + +/* case TCPOPT_WINDOW: + * if (optlen != TCPOLEN_WINDOW) + * continue; + * if (!(ti->ti_flags & TH_SYN)) + * continue; + * tp->t_flags |= TF_RCVD_SCALE; + * tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); + * break; + */ +/* case TCPOPT_TIMESTAMP: + * if (optlen != TCPOLEN_TIMESTAMP) + * continue; + * *ts_present = 1; + * memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val)); + * NTOHL(*ts_val); + * memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr)); + * NTOHL(*ts_ecr); + * + */ /* + * * A timestamp received in a SYN makes + * * it ok to send timestamp requests and replies. + * */ +/* if (ti->ti_flags & TH_SYN) { + * tp->t_flags |= TF_RCVD_TSTMP; + * tp->ts_recent = *ts_val; + * tp->ts_recent_age = tcp_now; + * } + */ break; + } + } +} + + +/* + * Pull out of band byte out of a segment so + * it doesn't appear in the user's data queue. + * It is still reflected in the segment length for + * sequencing purposes. + */ + +#ifdef notdef + +void +tcp_pulloutofband(so, ti, m) + struct socket *so; + struct tcpiphdr *ti; + register struct mbuf *m; +{ + int cnt = ti->ti_urp - 1; + + while (cnt >= 0) { + if (m->m_len > cnt) { + char *cp = mtod(m, caddr_t) + cnt; + struct tcpcb *tp = sototcpcb(so); + + tp->t_iobc = *cp; + tp->t_oobflags |= TCPOOB_HAVEDATA; + memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1)); + m->m_len--; + return; + } + cnt -= m->m_len; + m = m->m_next; /* XXX WRONG! Fix it! */ + if (m == 0) + break; + } + panic("tcp_pulloutofband"); +} + +#endif /* notdef */ + +/* + * Collect new round-trip time estimate + * and update averages and current timeout. + */ + +void +tcp_xmit_timer(tp, rtt) + register struct tcpcb *tp; + int rtt; +{ + register short delta; + + DEBUG_CALL("tcp_xmit_timer"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("rtt = %d", rtt); + + tcpstat.tcps_rttupdated++; + if (tp->t_srtt != 0) { + /* + * srtt is stored as fixed point with 3 bits after the + * binary point (i.e., scaled by 8). The following magic + * is equivalent to the smoothing algorithm in rfc793 with + * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed + * point). Adjust rtt to origin 0. + */ + delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT); + if ((tp->t_srtt += delta) <= 0) + tp->t_srtt = 1; + /* + * We accumulate a smoothed rtt variance (actually, a + * smoothed mean difference), then set the retransmit + * timer to smoothed rtt + 4 times the smoothed variance. + * rttvar is stored as fixed point with 2 bits after the + * binary point (scaled by 4). The following is + * equivalent to rfc793 smoothing with an alpha of .75 + * (rttvar = rttvar*3/4 + |delta| / 4). This replaces + * rfc793's wired-in beta. + */ + if (delta < 0) + delta = -delta; + delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); + if ((tp->t_rttvar += delta) <= 0) + tp->t_rttvar = 1; + } else { + /* + * No rtt measurement yet - use the unsmoothed rtt. + * Set the variance to half the rtt (so our first + * retransmit happens at 3*rtt). + */ + tp->t_srtt = rtt << TCP_RTT_SHIFT; + tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); + } + tp->t_rtt = 0; + tp->t_rxtshift = 0; + + /* + * the retransmit should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + */ + TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), + (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ + + /* + * We received an ack for a packet that wasn't retransmitted; + * it is probably safe to discard any error indications we've + * received recently. This isn't quite right, but close enough + * for now (a route might have failed after we sent a segment, + * and the return path might not be symmetrical). + */ + tp->t_softerror = 0; +} + +/* + * Determine a reasonable value for maxseg size. + * If the route is known, check route for mtu. + * If none, use an mss that can be handled on the outgoing + * interface without forcing IP to fragment; if bigger than + * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES + * to utilize large mbufs. If no route is found, route has no mtu, + * or the destination isn't local, use a default, hopefully conservative + * size (usually 512 or the default IP max size, but no more than the mtu + * of the interface), as we can't discover anything about intervening + * gateways or networks. We also initialize the congestion/slow start + * window to be a single segment if the destination isn't local. + * While looking at the routing entry, we also initialize other path-dependent + * parameters from pre-set or cached values in the routing entry. + */ + +int +tcp_mss(tp, offer) + register struct tcpcb *tp; + u_int offer; +{ + struct socket *so = tp->t_socket; + int mss; + + DEBUG_CALL("tcp_mss"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("offer = %d", offer); + + mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr); + if (offer) + mss = min(mss, offer); + mss = max(mss, 32); + if (mss < tp->t_maxseg || offer != 0) + tp->t_maxseg = mss; + + tp->snd_cwnd = mss; + + sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0)); + sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0)); + + DEBUG_MISC((dfd, " returning mss = %d\n", mss)); + + return mss; +} diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c new file mode 100644 index 000000000..0f05dfadc --- /dev/null +++ b/slirp/tcp_output.c @@ -0,0 +1,608 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93 + * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include + +#define max(x,y) ((x) > (y) ? (x) : (y)) +#define min(x,y) ((x) < (y) ? (x) : (y)) + +/* + * Since this is only used in "stats socket", we give meaning + * names instead of the REAL names + */ +char *tcpstates[] = { +/* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */ + "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", + "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", + "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", +}; + +u_char tcp_outflags[TCP_NSTATES] = { + TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, + TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, + TH_FIN|TH_ACK, TH_ACK, TH_ACK, +}; + + +#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ + +/* + * Tcp output routine: figure out what should be sent and send it. + */ +int +tcp_output(tp) + register struct tcpcb *tp; +{ + register struct socket *so = tp->t_socket; + register long len, win; + int off, flags, error; + register struct mbuf *m; + register struct tcpiphdr *ti; + u_char opt[MAX_TCPOPTLEN]; + unsigned optlen, hdrlen; + int idle, sendalot; + + DEBUG_CALL("tcp_output"); + DEBUG_ARG("tp = %lx", (long )tp); + + /* + * Determine length of data that should be transmitted, + * and flags that will be used. + * If there is some data or critical controls (SYN, RST) + * to send, then transmit; otherwise, investigate further. + */ + idle = (tp->snd_max == tp->snd_una); + if (idle && tp->t_idle >= tp->t_rxtcur) + /* + * We have been idle for "a while" and no acks are + * expected to clock out any data we send -- + * slow start to get ack "clock" running again. + */ + tp->snd_cwnd = tp->t_maxseg; +again: + sendalot = 0; + off = tp->snd_nxt - tp->snd_una; + win = min(tp->snd_wnd, tp->snd_cwnd); + + flags = tcp_outflags[tp->t_state]; + + DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags)); + + /* + * If in persist timeout with window of 0, send 1 byte. + * Otherwise, if window is small but nonzero + * and timer expired, we will send what we can + * and go to transmit state. + */ + if (tp->t_force) { + if (win == 0) { + /* + * If we still have some data to send, then + * clear the FIN bit. Usually this would + * happen below when it realizes that we + * aren't sending all the data. However, + * if we have exactly 1 byte of unset data, + * then it won't clear the FIN bit below, + * and if we are in persist state, we wind + * up sending the packet without recording + * that we sent the FIN bit. + * + * We can't just blindly clear the FIN bit, + * because if we don't have any more data + * to send then the probe will be the FIN + * itself. + */ + if (off < so->so_snd.sb_cc) + flags &= ~TH_FIN; + win = 1; + } else { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + + len = min(so->so_snd.sb_cc, win) - off; + + if (len < 0) { + /* + * If FIN has been sent but not acked, + * but we haven't been called to retransmit, + * len will be -1. Otherwise, window shrank + * after we sent into it. If window shrank to 0, + * cancel pending retransmit and pull snd_nxt + * back to (closed) window. We will enter persist + * state below. If the window didn't close completely, + * just wait for an ACK. + */ + len = 0; + if (win == 0) { + tp->t_timer[TCPT_REXMT] = 0; + tp->snd_nxt = tp->snd_una; + } + } + + if (len > tp->t_maxseg) { + len = tp->t_maxseg; + sendalot = 1; + } + if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) + flags &= ~TH_FIN; + + win = sbspace(&so->so_rcv); + + /* + * Sender silly window avoidance. If connection is idle + * and can send all data, a maximum segment, + * at least a maximum default-size segment do it, + * or are forced, do it; otherwise don't bother. + * If peer's buffer is tiny, then send + * when window is at least half open. + * If retransmitting (possibly after persist timer forced us + * to send into a small window), then must resend. + */ + if (len) { + if (len == tp->t_maxseg) + goto send; + if ((1 || idle || tp->t_flags & TF_NODELAY) && + len + off >= so->so_snd.sb_cc) + goto send; + if (tp->t_force) + goto send; + if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) + goto send; + if (SEQ_LT(tp->snd_nxt, tp->snd_max)) + goto send; + } + + /* + * Compare available window to amount of window + * known to peer (as advertised window less + * next expected input). If the difference is at least two + * max size segments, or at least 50% of the maximum possible + * window, then want to send a window update to peer. + */ + if (win > 0) { + /* + * "adv" is the amount we can increase the window, + * taking into account that we are limited by + * TCP_MAXWIN << tp->rcv_scale. + */ + long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - + (tp->rcv_adv - tp->rcv_nxt); + + if (adv >= (long) (2 * tp->t_maxseg)) + goto send; + if (2 * adv >= (long) so->so_rcv.sb_datalen) + goto send; + } + + /* + * Send if we owe peer an ACK. + */ + if (tp->t_flags & TF_ACKNOW) + goto send; + if (flags & (TH_SYN|TH_RST)) + goto send; + if (SEQ_GT(tp->snd_up, tp->snd_una)) + goto send; + /* + * If our state indicates that FIN should be sent + * and we have not yet done so, or we're retransmitting the FIN, + * then we need to send. + */ + if (flags & TH_FIN && + ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) + goto send; + + /* + * TCP window updates are not reliable, rather a polling protocol + * using ``persist'' packets is used to insure receipt of window + * updates. The three ``states'' for the output side are: + * idle not doing retransmits or persists + * persisting to move a small or zero window + * (re)transmitting and thereby not persisting + * + * tp->t_timer[TCPT_PERSIST] + * is set when we are in persist state. + * tp->t_force + * is set when we are called to send a persist packet. + * tp->t_timer[TCPT_REXMT] + * is set when we are retransmitting + * The output side is idle when both timers are zero. + * + * If send window is too small, there is data to transmit, and no + * retransmit or persist is pending, then go to persist state. + * If nothing happens soon, send when timer expires: + * if window is nonzero, transmit what we can, + * otherwise force out a byte. + */ + if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && + tp->t_timer[TCPT_PERSIST] == 0) { + tp->t_rxtshift = 0; + tcp_setpersist(tp); + } + + /* + * No reason to send a segment, just return. + */ + tcpstat.tcps_didnuttin++; + + return (0); + +send: + /* + * Before ESTABLISHED, force sending of initial options + * unless TCP set not to do any options. + * NOTE: we assume that the IP/TCP header plus TCP options + * always fit in a single mbuf, leaving room for a maximum + * link header, i.e. + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN + */ + optlen = 0; + hdrlen = sizeof (struct tcpiphdr); + if (flags & TH_SYN) { + tp->snd_nxt = tp->iss; + if ((tp->t_flags & TF_NOOPT) == 0) { + u_int16_t mss; + + opt[0] = TCPOPT_MAXSEG; + opt[1] = 4; + mss = htons((u_int16_t) tcp_mss(tp, 0)); + memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss)); + optlen = 4; + +/* if ((tp->t_flags & TF_REQ_SCALE) && + * ((flags & TH_ACK) == 0 || + * (tp->t_flags & TF_RCVD_SCALE))) { + * *((u_int32_t *) (opt + optlen)) = htonl( + * TCPOPT_NOP << 24 | + * TCPOPT_WINDOW << 16 | + * TCPOLEN_WINDOW << 8 | + * tp->request_r_scale); + * optlen += 4; + * } + */ + } + } + + /* + * Send a timestamp and echo-reply if this is a SYN and our side + * wants to use timestamps (TF_REQ_TSTMP is set) or both our side + * and our peer have sent timestamps in our SYN's. + */ +/* if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && + * (flags & TH_RST) == 0 && + * ((flags & (TH_SYN|TH_ACK)) == TH_SYN || + * (tp->t_flags & TF_RCVD_TSTMP))) { + * u_int32_t *lp = (u_int32_t *)(opt + optlen); + * + * / * Form timestamp option as shown in appendix A of RFC 1323. * / + * *lp++ = htonl(TCPOPT_TSTAMP_HDR); + * *lp++ = htonl(tcp_now); + * *lp = htonl(tp->ts_recent); + * optlen += TCPOLEN_TSTAMP_APPA; + * } + */ + hdrlen += optlen; + + /* + * Adjust data length if insertion of options will + * bump the packet length beyond the t_maxseg length. + */ + if (len > tp->t_maxseg - optlen) { + len = tp->t_maxseg - optlen; + sendalot = 1; + } + + /* + * Grab a header mbuf, attaching a copy of data to + * be transmitted, and initialize the header from + * the template for sends on this connection. + */ + if (len) { + if (tp->t_force && len == 1) + tcpstat.tcps_sndprobe++; + else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { + tcpstat.tcps_sndrexmitpack++; + tcpstat.tcps_sndrexmitbyte += len; + } else { + tcpstat.tcps_sndpack++; + tcpstat.tcps_sndbyte += len; + } + + m = m_get(); + if (m == NULL) { +/* error = ENOBUFS; */ + error = 1; + goto out; + } + m->m_data += if_maxlinkhdr; + m->m_len = hdrlen; + + /* + * This will always succeed, since we make sure our mbufs + * are big enough to hold one MSS packet + header + ... etc. + */ +/* if (len <= MHLEN - hdrlen - max_linkhdr) { */ + + sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen); + m->m_len += len; + +/* } else { + * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); + * if (m->m_next == 0) + * len = 0; + * } + */ + /* + * If we're sending everything we've got, set PUSH. + * (This will keep happy those implementations which only + * give data to the user when a buffer fills or + * a PUSH comes in.) + */ + if (off + len == so->so_snd.sb_cc) + flags |= TH_PUSH; + } else { + if (tp->t_flags & TF_ACKNOW) + tcpstat.tcps_sndacks++; + else if (flags & (TH_SYN|TH_FIN|TH_RST)) + tcpstat.tcps_sndctrl++; + else if (SEQ_GT(tp->snd_up, tp->snd_una)) + tcpstat.tcps_sndurg++; + else + tcpstat.tcps_sndwinup++; + + m = m_get(); + if (m == NULL) { +/* error = ENOBUFS; */ + error = 1; + goto out; + } + m->m_data += if_maxlinkhdr; + m->m_len = hdrlen; + } + + ti = mtod(m, struct tcpiphdr *); + + memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); + + /* + * Fill in fields, remembering maximum advertised + * window for use in delaying messages about window sizes. + * If resending a FIN, be sure not to use a new sequence number. + */ + if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && + tp->snd_nxt == tp->snd_max) + tp->snd_nxt--; + /* + * If we are doing retransmissions, then snd_nxt will + * not reflect the first unsent octet. For ACK only + * packets, we do not want the sequence number of the + * retransmitted packet, we want the sequence number + * of the next unsent octet. So, if there is no data + * (and no SYN or FIN), use snd_max instead of snd_nxt + * when filling in ti_seq. But if we are in persist + * state, snd_max might reflect one byte beyond the + * right edge of the window, so use snd_nxt in that + * case, since we know we aren't doing a retransmission. + * (retransmit and persist are mutually exclusive...) + */ + if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) + ti->ti_seq = htonl(tp->snd_nxt); + else + ti->ti_seq = htonl(tp->snd_max); + ti->ti_ack = htonl(tp->rcv_nxt); + if (optlen) { + memcpy((caddr_t)(ti + 1), (caddr_t)opt, optlen); + ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; + } + ti->ti_flags = flags; + /* + * Calculate receive window. Don't shrink window, + * but avoid silly window syndrome. + */ + if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) + win = 0; + if (win > (long)TCP_MAXWIN << tp->rcv_scale) + win = (long)TCP_MAXWIN << tp->rcv_scale; + if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) + win = (long)(tp->rcv_adv - tp->rcv_nxt); + ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); + + if (SEQ_GT(tp->snd_up, tp->snd_una)) { + ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); +#ifdef notdef + if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { + ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); +#endif + ti->ti_flags |= TH_URG; + } else + /* + * If no urgent pointer to send, then we pull + * the urgent pointer to the left edge of the send window + * so that it doesn't drift into the send window on sequence + * number wraparound. + */ + tp->snd_up = tp->snd_una; /* drag it along */ + + /* + * Put TCP length in extended header, and then + * checksum extended header and data. + */ + if (len + optlen) + ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + + optlen + len)); + ti->ti_sum = cksum(m, (int)(hdrlen + len)); + + /* + * In transmit state, time the transmission and arrange for + * the retransmit. In persist state, just set snd_max. + */ + if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { + tcp_seq startseq = tp->snd_nxt; + + /* + * Advance snd_nxt over sequence space of this segment. + */ + if (flags & (TH_SYN|TH_FIN)) { + if (flags & TH_SYN) + tp->snd_nxt++; + if (flags & TH_FIN) { + tp->snd_nxt++; + tp->t_flags |= TF_SENTFIN; + } + } + tp->snd_nxt += len; + if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { + tp->snd_max = tp->snd_nxt; + /* + * Time this transmission if not a retransmission and + * not currently timing anything. + */ + if (tp->t_rtt == 0) { + tp->t_rtt = 1; + tp->t_rtseq = startseq; + tcpstat.tcps_segstimed++; + } + } + + /* + * Set retransmit timer if not currently set, + * and not doing an ack or a keep-alive probe. + * Initial value for retransmit timer is smoothed + * round-trip time + 2 * round-trip time variance. + * Initialize shift counter which is used for backoff + * of retransmit time. + */ + if (tp->t_timer[TCPT_REXMT] == 0 && + tp->snd_nxt != tp->snd_una) { + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + if (tp->t_timer[TCPT_PERSIST]) { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + } else + if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) + tp->snd_max = tp->snd_nxt + len; + + /* + * Fill in IP length and desired time to live and + * send to IP level. There should be a better way + * to handle ttl and tos; we could keep them in + * the template, but need a way to checksum without them. + */ + m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ + + { + + ((struct ip *)ti)->ip_len = m->m_len; + + ((struct ip *)ti)->ip_ttl = ip_defttl; + ((struct ip *)ti)->ip_tos = so->so_iptos; + +/* #if BSD >= 43 */ + /* Don't do IP options... */ +/* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, + * so->so_options & SO_DONTROUTE, 0); + */ + error = ip_output(so, m); + +/* #else + * error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, + * so->so_options & SO_DONTROUTE); + * #endif + */ + } + if (error) { +out: +/* if (error == ENOBUFS) { + * tcp_quench(tp->t_inpcb, 0); + * return (0); + * } + */ +/* if ((error == EHOSTUNREACH || error == ENETDOWN) + * && TCPS_HAVERCVDSYN(tp->t_state)) { + * tp->t_softerror = error; + * return (0); + * } + */ + return (error); + } + tcpstat.tcps_sndtotal++; + + /* + * Data sent (as far as we can tell). + * If this advertises a larger window than any other segment, + * then remember the size of the advertised window. + * Any pending ACK has now been sent. + */ + if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) + tp->rcv_adv = tp->rcv_nxt + win; + tp->last_ack_sent = tp->rcv_nxt; + tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); + if (sendalot) + goto again; + + return (0); +} + +void +tcp_setpersist(tp) + register struct tcpcb *tp; +{ + int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; + +/* if (tp->t_timer[TCPT_REXMT]) + * panic("tcp_output REXMT"); + */ + /* + * Start/restart persistence timer. + */ + TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], + t * tcp_backoff[tp->t_rxtshift], + TCPTV_PERSMIN, TCPTV_PERSMAX); + if (tp->t_rxtshift < TCP_MAXRXTSHIFT) + tp->t_rxtshift++; +} diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c new file mode 100644 index 000000000..bf8a2026f --- /dev/null +++ b/slirp/tcp_subr.c @@ -0,0 +1,1325 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 + * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include + +/* patchable/settable parameters for tcp */ +int tcp_mssdflt = TCP_MSS; +int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; +int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ +int tcp_rcvspace; /* You may want to change this */ +int tcp_sndspace; /* Keep small if you have an error prone link */ + +/* + * Tcp initialization + */ +void +tcp_init() +{ + tcp_iss = 1; /* wrong */ + tcb.so_next = tcb.so_prev = &tcb; + + /* tcp_rcvspace = our Window we advertise to the remote */ + tcp_rcvspace = TCP_RCVSPACE; + tcp_sndspace = TCP_SNDSPACE; + + /* Make sure tcp_sndspace is at least 2*MSS */ + if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) + tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); +} + +/* + * Create template to be used to send tcp packets on a connection. + * Call after host entry created, fills + * in a skeletal tcp/ip header, minimizing the amount of work + * necessary when the connection is used. + */ +/* struct tcpiphdr * */ +void +tcp_template(tp) + struct tcpcb *tp; +{ + struct socket *so = tp->t_socket; + register struct tcpiphdr *n = &tp->t_template; + + n->ti_next = n->ti_prev = 0; + n->ti_x1 = 0; + n->ti_pr = IPPROTO_TCP; + n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); + n->ti_src = so->so_faddr; + n->ti_dst = so->so_laddr; + n->ti_sport = so->so_fport; + n->ti_dport = so->so_lport; + + n->ti_seq = 0; + n->ti_ack = 0; + n->ti_x2 = 0; + n->ti_off = 5; + n->ti_flags = 0; + n->ti_win = 0; + n->ti_sum = 0; + n->ti_urp = 0; +} + +/* + * Send a single message to the TCP at address specified by + * the given TCP/IP header. If m == 0, then we make a copy + * of the tcpiphdr at ti and send directly to the addressed host. + * This is used to force keep alive messages out using the TCP + * template for a connection tp->t_template. If flags are given + * then we send a message back to the TCP which originated the + * segment ti, and discard the mbuf containing it and any other + * attached mbufs. + * + * In any case the ack and sequence number of the transmitted + * segment are as specified by the parameters. + */ +void +tcp_respond(tp, ti, m, ack, seq, flags) + struct tcpcb *tp; + register struct tcpiphdr *ti; + register struct mbuf *m; + tcp_seq ack, seq; + int flags; +{ + register int tlen; + int win = 0; + + DEBUG_CALL("tcp_respond"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("ti = %lx", (long)ti); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("ack = %u", ack); + DEBUG_ARG("seq = %u", seq); + DEBUG_ARG("flags = %x", flags); + + if (tp) + win = sbspace(&tp->t_socket->so_rcv); + if (m == 0) { + if ((m = m_get()) == NULL) + return; +#ifdef TCP_COMPAT_42 + tlen = 1; +#else + tlen = 0; +#endif + m->m_data += if_maxlinkhdr; + *mtod(m, struct tcpiphdr *) = *ti; + ti = mtod(m, struct tcpiphdr *); + flags = TH_ACK; + } else { + /* + * ti points into m so the next line is just making + * the mbuf point to ti + */ + m->m_data = (caddr_t)ti; + + m->m_len = sizeof (struct tcpiphdr); + tlen = 0; +#define xchg(a,b,type) { type t; t=a; a=b; b=t; } + xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t); + xchg(ti->ti_dport, ti->ti_sport, u_int16_t); +#undef xchg + } + ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); + tlen += sizeof (struct tcpiphdr); + m->m_len = tlen; + + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_seq = htonl(seq); + ti->ti_ack = htonl(ack); + ti->ti_x2 = 0; + ti->ti_off = sizeof (struct tcphdr) >> 2; + ti->ti_flags = flags; + if (tp) + ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale)); + else + ti->ti_win = htons((u_int16_t)win); + ti->ti_urp = 0; + ti->ti_sum = 0; + ti->ti_sum = cksum(m, tlen); + ((struct ip *)ti)->ip_len = tlen; + + if(flags & TH_RST) + ((struct ip *)ti)->ip_ttl = MAXTTL; + else + ((struct ip *)ti)->ip_ttl = ip_defttl; + + (void) ip_output((struct socket *)0, m); +} + +/* + * Create a new TCP control block, making an + * empty reassembly queue and hooking it to the argument + * protocol control block. + */ +struct tcpcb * +tcp_newtcpcb(so) + struct socket *so; +{ + register struct tcpcb *tp; + + tp = (struct tcpcb *)malloc(sizeof(*tp)); + if (tp == NULL) + return ((struct tcpcb *)0); + + memset((char *) tp, 0, sizeof(struct tcpcb)); + tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; + tp->t_maxseg = tcp_mssdflt; + + tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; + tp->t_socket = so; + + /* + * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no + * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives + * reasonable initial retransmit time. + */ + tp->t_srtt = TCPTV_SRTTBASE; + tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; + tp->t_rttmin = TCPTV_MIN; + + TCPT_RANGESET(tp->t_rxtcur, + ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, + TCPTV_MIN, TCPTV_REXMTMAX); + + tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->t_state = TCPS_CLOSED; + + so->so_tcpcb = tp; + + return (tp); +} + +/* + * Drop a TCP connection, reporting + * the specified error. If connection is synchronized, + * then send a RST to peer. + */ +struct tcpcb *tcp_drop(struct tcpcb *tp, int errno) +{ +/* tcp_drop(tp, errno) + register struct tcpcb *tp; + int errno; +{ +*/ + + DEBUG_CALL("tcp_drop"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("errno = %d", errno); + + if (TCPS_HAVERCVDSYN(tp->t_state)) { + tp->t_state = TCPS_CLOSED; + (void) tcp_output(tp); + tcpstat.tcps_drops++; + } else + tcpstat.tcps_conndrops++; +/* if (errno == ETIMEDOUT && tp->t_softerror) + * errno = tp->t_softerror; + */ +/* so->so_error = errno; */ + return (tcp_close(tp)); +} + +/* + * Close a TCP control block: + * discard all space held by the tcp + * discard internet protocol block + * wake up any sleepers + */ +struct tcpcb * +tcp_close(tp) + register struct tcpcb *tp; +{ + register struct tcpiphdr *t; + struct socket *so = tp->t_socket; + register struct mbuf *m; + + DEBUG_CALL("tcp_close"); + DEBUG_ARG("tp = %lx", (long )tp); + + /* free the reassembly queue, if any */ + t = (struct tcpiphdr *) tp->seg_next; + while (t != (struct tcpiphdr *)tp) { + t = (struct tcpiphdr *)t->ti_next; + m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); + remque_32((struct tcpiphdr *) t->ti_prev); + m_freem(m); + } + /* It's static */ +/* if (tp->t_template) + * (void) m_free(dtom(tp->t_template)); + */ +/* free(tp, M_PCB); */ + free(tp); + so->so_tcpcb = 0; + soisfdisconnected(so); + /* clobber input socket cache if we're closing the cached connection */ + if (so == tcp_last_so) + tcp_last_so = &tcb; + close(so->s); + sbfree(&so->so_rcv); + sbfree(&so->so_snd); + sofree(so); + tcpstat.tcps_closed++; + return ((struct tcpcb *)0); +} + +void +tcp_drain() +{ + /* XXX */ +} + +/* + * When a source quench is received, close congestion window + * to one segment. We will gradually open it again as we proceed. + */ + +#ifdef notdef + +void +tcp_quench(i, errno) + + int errno; +{ + struct tcpcb *tp = intotcpcb(inp); + + if (tp) + tp->snd_cwnd = tp->t_maxseg; +} + +#endif /* notdef */ + +/* + * TCP protocol interface to socket abstraction. + */ + +/* + * User issued close, and wish to trail through shutdown states: + * if never received SYN, just forget it. If got a SYN from peer, + * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. + * If already got a FIN from peer, then almost done; go to LAST_ACK + * state. In all other cases, have already sent FIN to peer (e.g. + * after PRU_SHUTDOWN), and just have to play tedious game waiting + * for peer to send FIN or not respond to keep-alives, etc. + * We can let the user exit from the close as soon as the FIN is acked. + */ +void +tcp_sockclosed(tp) + struct tcpcb *tp; +{ + + DEBUG_CALL("tcp_sockclosed"); + DEBUG_ARG("tp = %lx", (long)tp); + + switch (tp->t_state) { + + case TCPS_CLOSED: + case TCPS_LISTEN: + case TCPS_SYN_SENT: + tp->t_state = TCPS_CLOSED; + tp = tcp_close(tp); + break; + + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + tp->t_state = TCPS_FIN_WAIT_1; + break; + + case TCPS_CLOSE_WAIT: + tp->t_state = TCPS_LAST_ACK; + break; + } +/* soisfdisconnecting(tp->t_socket); */ + if (tp && tp->t_state >= TCPS_FIN_WAIT_2) + soisfdisconnected(tp->t_socket); + if (tp) + tcp_output(tp); +} + +/* + * Connect to a host on the Internet + * Called by tcp_input + * Only do a connect, the tcp fields will be set in tcp_input + * return 0 if there's a result of the connect, + * else return -1 means we're still connecting + * The return value is almost always -1 since the socket is + * nonblocking. Connect returns after the SYN is sent, and does + * not wait for ACK+SYN. + */ +int tcp_fconnect(so) + struct socket *so; +{ + int ret=0; + + DEBUG_CALL("tcp_fconnect"); + DEBUG_ARG("so = %lx", (long )so); + + if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) { + int opt, s=so->s; + struct sockaddr_in addr; + + fd_nonblock(s); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); + + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else + addr.sin_addr = so->so_faddr; + addr.sin_port = so->so_fport; + + DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " + "addr.sin_addr.s_addr=%.16s\n", + ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); + /* We don't care what port we get */ + ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); + + /* + * If it's not in progress, it failed, so we just return 0, + * without clearing SS_NOFDREF + */ + soisfconnecting(so); + } + + return(ret); +} + +/* + * Accept the socket and connect to the local-host + * + * We have a problem. The correct thing to do would be + * to first connect to the local-host, and only if the + * connection is accepted, then do an accept() here. + * But, a) we need to know who's trying to connect + * to the socket to be able to SYN the local-host, and + * b) we are already connected to the foreign host by + * the time it gets to accept(), so... We simply accept + * here and SYN the local-host. + */ +void +tcp_connect(inso) + struct socket *inso; +{ + struct socket *so; + struct sockaddr_in addr; + int addrlen = sizeof(struct sockaddr_in); + struct tcpcb *tp; + int s, opt; + + DEBUG_CALL("tcp_connect"); + DEBUG_ARG("inso = %lx", (long)inso); + + /* + * If it's an SS_ACCEPTONCE socket, no need to socreate() + * another socket, just use the accept() socket. + */ + if (inso->so_state & SS_FACCEPTONCE) { + /* FACCEPTONCE already have a tcpcb */ + so = inso; + } else { + if ((so = socreate()) == NULL) { + /* If it failed, get rid of the pending connection */ + close(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); + return; + } + if (tcp_attach(so) < 0) { + free(so); /* NOT sofree */ + return; + } + so->so_laddr = inso->so_laddr; + so->so_lport = inso->so_lport; + } + + (void) tcp_mss(sototcpcb(so), 0); + + if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { + tcp_close(sototcpcb(so)); /* This will sofree() as well */ + return; + } + fd_nonblock(s); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + + so->so_fport = addr.sin_port; + so->so_faddr = addr.sin_addr; + /* Translate connections from localhost to the real hostname */ + if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) + so->so_faddr = our_addr; + + /* Close the accept() socket, set right state */ + if (inso->so_state & SS_FACCEPTONCE) { + close(so->s); /* If we only accept once, close the accept() socket */ + so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ + /* if it's not FACCEPTONCE, it's already NOFDREF */ + } + so->s = s; + + so->so_iptos = tcp_tos(so); + tp = sototcpcb(so); + + tcp_template(tp); + + /* Compute window scaling to request. */ +/* while (tp->request_r_scale < TCP_MAX_WINSHIFT && + * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) + * tp->request_r_scale++; + */ + +/* soisconnecting(so); */ /* NOFDREF used instead */ + tcpstat.tcps_connattempt++; + + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + tcp_output(tp); +} + +/* + * Attach a TCPCB to a socket. + */ +int +tcp_attach(so) + struct socket *so; +{ + if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) + return -1; + + insque(so, &tcb); + + return 0; +} + +/* + * Set the socket's type of service field + */ +struct tos_t tcptos[] = { + {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ + {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ + {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ + {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ + {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ + {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ + {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ + {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ + {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ + {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ + {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ + {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ + {0, 0, 0, 0} +}; + +struct emu_t *tcpemu = 0; + +/* + * Return TOS according to the above table + */ +u_int8_t +tcp_tos(so) + struct socket *so; +{ + int i = 0; + struct emu_t *emup; + + while(tcptos[i].tos) { + if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || + (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { + so->so_emu = tcptos[i].emu; + return tcptos[i].tos; + } + i++; + } + + /* Nope, lets see if there's a user-added one */ + for (emup = tcpemu; emup; emup = emup->next) { + if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || + (emup->lport && (ntohs(so->so_lport) == emup->lport))) { + so->so_emu = emup->emu; + return emup->tos; + } + } + + return 0; +} + +int do_echo = -1; + +/* + * Emulate programs that try and connect to us + * This includes ftp (the data connection is + * initiated by the server) and IRC (DCC CHAT and + * DCC SEND) for now + * + * NOTE: It's possible to crash SLiRP by sending it + * unstandard strings to emulate... if this is a problem, + * more checks are needed here + * + * XXX Assumes the whole command came in one packet + * + * XXX Some ftp clients will have their TOS set to + * LOWDELAY and so Nagel will kick in. Because of this, + * we'll get the first letter, followed by the rest, so + * we simply scan for ORT instead of PORT... + * DCC doesn't have this problem because there's other stuff + * in the packet before the DCC command. + * + * Return 1 if the mbuf m is still valid and should be + * sbappend()ed + * + * NOTE: if you return 0 you MUST m_free() the mbuf! + */ +int +tcp_emu(so, m) + struct socket *so; + struct mbuf *m; +{ + u_int n1, n2, n3, n4, n5, n6; + char buff[256]; + u_int32_t laddr; + u_int lport; + char *bptr; + + DEBUG_CALL("tcp_emu"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + + switch(so->so_emu) { + int x, i; + + case EMU_IDENT: + /* + * Identification protocol as per rfc-1413 + */ + + { + struct socket *tmpso; + struct sockaddr_in addr; + int addrlen = sizeof(struct sockaddr_in); + struct sbuf *so_rcv = &so->so_rcv; + + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m->m_data[m->m_len] = 0; /* NULL terminate */ + if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { + if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { + HTONS(n1); + HTONS(n2); + /* n2 is the one on our host */ + for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { + if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && + tmpso->so_lport == n2 && + tmpso->so_faddr.s_addr == so->so_faddr.s_addr && + tmpso->so_fport == n1) { + if (getsockname(tmpso->s, + (struct sockaddr *)&addr, &addrlen) == 0) + n2 = ntohs(addr.sin_port); + break; + } + } + } + so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); + so_rcv->sb_rptr = so_rcv->sb_data; + so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; + } + m_free(m); + return 0; + } + +#if 0 + case EMU_RLOGIN: + /* + * Rlogin emulation + * First we accumulate all the initial option negotiation, + * then fork_exec() rlogin according to the options + */ + { + int i, i2, n; + char *ptr; + char args[100]; + char term[100]; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* First check if they have a priveladged port, or too much data has arrived */ + if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || + (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + m_free(m); + return 0; + } + + /* Append the current data */ + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m_free(m); + + /* + * Check if we have all the initial options, + * and build argument list to rlogin while we're here + */ + n = 0; + ptr = so_rcv->sb_data; + args[0] = 0; + term[0] = 0; + while (ptr < so_rcv->sb_wptr) { + if (*ptr++ == 0) { + n++; + if (n == 2) { + sprintf(args, "rlogin -l %s %s", + ptr, inet_ntoa(so->so_faddr)); + } else if (n == 3) { + i2 = so_rcv->sb_wptr - ptr; + for (i = 0; i < i2; i++) { + if (ptr[i] == '/') { + ptr[i] = 0; +#ifdef HAVE_SETENV + sprintf(term, "%s", ptr); +#else + sprintf(term, "TERM=%s", ptr); +#endif + ptr[i] = '/'; + break; + } + } + } + } + } + + if (n != 4) + return 0; + + /* We have it, set our term variable and fork_exec() */ +#ifdef HAVE_SETENV + setenv("TERM", term, 1); +#else + putenv(term); +#endif + fork_exec(so, args, 2); + term[0] = 0; + so->so_emu = 0; + + /* And finally, send the client a 0 character */ + so_snd->sb_wptr[0] = 0; + so_snd->sb_wptr++; + so_snd->sb_cc++; + + return 0; + } + + case EMU_RSH: + /* + * rsh emulation + * First we accumulate all the initial option negotiation, + * then rsh_exec() rsh according to the options + */ + { + int n; + char *ptr; + char *user; + char *args; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* First check if they have a priveladged port, or too much data has arrived */ + if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || + (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + m_free(m); + return 0; + } + + /* Append the current data */ + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m_free(m); + + /* + * Check if we have all the initial options, + * and build argument list to rlogin while we're here + */ + n = 0; + ptr = so_rcv->sb_data; + user=""; + args=""; + if (so->extra==NULL) { + struct socket *ns; + struct tcpcb* tp; + int port=atoi(ptr); + if (port <= 0) return 0; + if (port > 1023 || port < 512) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + return 0; + } + if ((ns=socreate()) == NULL) + return 0; + if (tcp_attach(ns)<0) { + free(ns); + return 0; + } + + ns->so_laddr=so->so_laddr; + ns->so_lport=htons(port); + + (void) tcp_mss(sototcpcb(ns), 0); + + ns->so_faddr=so->so_faddr; + ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */ + + if (ns->so_faddr.s_addr == 0 || + ns->so_faddr.s_addr == loopback_addr.s_addr) + ns->so_faddr = our_addr; + + ns->so_iptos = tcp_tos(ns); + tp = sototcpcb(ns); + + tcp_template(tp); + + /* Compute window scaling to request. */ + /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && + * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) + * tp->request_r_scale++; + */ + + /*soisfconnecting(ns);*/ + + tcpstat.tcps_connattempt++; + + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + tcp_output(tp); + so->extra=ns; + } + while (ptr < so_rcv->sb_wptr) { + if (*ptr++ == 0) { + n++; + if (n == 2) { + user=ptr; + } else if (n == 3) { + args=ptr; + } + } + } + + if (n != 4) + return 0; + + rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); + so->so_emu = 0; + so->extra=NULL; + + /* And finally, send the client a 0 character */ + so_snd->sb_wptr[0] = 0; + so_snd->sb_wptr++; + so_snd->sb_cc++; + + return 0; + } + + case EMU_CTL: + { + int num; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* + * If there is binary data here, we save it in so->so_m + */ + if (!so->so_m) { + int rxlen; + char *rxdata; + rxdata=mtod(m, char *); + for (rxlen=m->m_len; rxlen; rxlen--) { + if (*rxdata++ & 0x80) { + so->so_m = m; + return 0; + } + } + } /* if(so->so_m==NULL) */ + + /* + * Append the line + */ + sbappendsb(so_rcv, m); + + /* To avoid going over the edge of the buffer, we reset it */ + if (so_snd->sb_cc == 0) + so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; + + /* + * A bit of a hack: + * If the first packet we get here is 1 byte long, then it + * was done in telnet character mode, therefore we must echo + * the characters as they come. Otherwise, we echo nothing, + * because in linemode, the line is already echoed + * XXX two or more control connections won't work + */ + if (do_echo == -1) { + if (m->m_len == 1) do_echo = 1; + else do_echo = 0; + } + if (do_echo) { + sbappendsb(so_snd, m); + m_free(m); + tcp_output(sototcpcb(so)); /* XXX */ + } else + m_free(m); + + num = 0; + while (num < so->so_rcv.sb_cc) { + if (*(so->so_rcv.sb_rptr + num) == '\n' || + *(so->so_rcv.sb_rptr + num) == '\r') { + int n; + + *(so_rcv->sb_rptr + num) = 0; + if (ctl_password && !ctl_password_ok) { + /* Need a password */ + if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) { + if (strcmp(buff, ctl_password) == 0) { + ctl_password_ok = 1; + n = sprintf(so_snd->sb_wptr, + "Password OK.\r\n"); + goto do_prompt; + } + } + n = sprintf(so_snd->sb_wptr, + "Error: Password required, log on with \"pass PASSWORD\"\r\n"); + goto do_prompt; + } + cfg_quitting = 0; + n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF); + if (!cfg_quitting) { + /* Register the printed data */ +do_prompt: + so_snd->sb_cc += n; + so_snd->sb_wptr += n; + /* Add prompt */ + n = sprintf(so_snd->sb_wptr, "Slirp> "); + so_snd->sb_cc += n; + so_snd->sb_wptr += n; + } + /* Drop so_rcv data */ + so_rcv->sb_cc = 0; + so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data; + tcp_output(sototcpcb(so)); /* Send the reply */ + } + num++; + } + return 0; + } +#endif + case EMU_FTP: /* ftp */ + *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ + if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { + /* + * Need to emulate the PORT command + */ + x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", + &n1, &n2, &n3, &n4, &n5, &n6, buff); + if (x < 6) + return 1; + + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); + lport = htons((n5 << 8) | (n6)); + + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) + return 1; + + n6 = ntohs(so->so_fport); + + n5 = (n6 >> 8) & 0xff; + n6 &= 0xff; + + laddr = ntohl(so->so_faddr.s_addr); + + n1 = ((laddr >> 24) & 0xff); + n2 = ((laddr >> 16) & 0xff); + n3 = ((laddr >> 8) & 0xff); + n4 = (laddr & 0xff); + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", + n1, n2, n3, n4, n5, n6, x==7?buff:""); + return 1; + } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { + /* + * Need to emulate the PASV response + */ + x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]", + &n1, &n2, &n3, &n4, &n5, &n6, buff); + if (x < 6) + return 1; + + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); + lport = htons((n5 << 8) | (n6)); + + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) + return 1; + + n6 = ntohs(so->so_fport); + + n5 = (n6 >> 8) & 0xff; + n6 &= 0xff; + + laddr = ntohl(so->so_faddr.s_addr); + + n1 = ((laddr >> 24) & 0xff); + n2 = ((laddr >> 16) & 0xff); + n3 = ((laddr >> 8) & 0xff); + n4 = (laddr & 0xff); + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", + n1, n2, n3, n4, n5, n6, x==7?buff:""); + + return 1; + } + + return 1; + + case EMU_KSH: + /* + * The kshell (Kerberos rsh) and shell services both pass + * a local port port number to carry signals to the server + * and stderr to the client. It is passed at the beginning + * of the connection as a NUL-terminated decimal ASCII string. + */ + so->so_emu = 0; + for (lport = 0, i = 0; i < m->m_len-1; ++i) { + if (m->m_data[i] < '0' || m->m_data[i] > '9') + return 1; /* invalid number */ + lport *= 10; + lport += m->m_data[i] - '0'; + } + if (m->m_data[m->m_len-1] == '\0' && lport != 0 && + (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) + m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; + return 1; + + case EMU_IRC: + /* + * Need to emulate DCC CHAT, DCC SEND and DCC MOVE + */ + *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ + if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) + return 1; + + /* The %256s is for the broken mIRC */ + if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), 1); + } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", + buff, (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", + buff, (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } + return 1; + + case EMU_REALAUDIO: + /* + * RealAudio emulation - JP. We must try to parse the incoming + * data and try to find the two characters that contain the + * port number. Then we redirect an udp port and replace the + * number with the real port we got. + * + * The 1.0 beta versions of the player are not supported + * any more. + * + * A typical packet for player version 1.0 (release version): + * + * 0000:50 4E 41 00 05 + * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .......glc..P + * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH + * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v + * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB + * + * Now the port number 0x1BD7 is found at offset 0x04 of the + * Now the port number 0x1BD7 is found at offset 0x04 of the + * second packet. This time we received five bytes first and + * then the rest. You never know how many bytes you get. + * + * A typical packet for player version 2.0 (beta): + * + * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA............ + * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxc..Win2.0.0 + * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ + * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas + * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B + * + * Port number 0x1BC1 is found at offset 0x0d. + * + * This is just a horrible switch statement. Variable ra tells + * us where we're going. + */ + + bptr = m->m_data; + while (bptr < m->m_data + m->m_len) { + u_short p; + static int ra = 0; + char ra_tbl[4]; + + ra_tbl[0] = 0x50; + ra_tbl[1] = 0x4e; + ra_tbl[2] = 0x41; + ra_tbl[3] = 0; + + switch (ra) { + case 0: + case 2: + case 3: + if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 1: + /* + * We may get 0x50 several times, ignore them + */ + if (*bptr == 0x50) { + ra = 1; + bptr++; + continue; + } else if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 4: + /* + * skip version number + */ + bptr++; + break; + + case 5: + /* + * The difference between versions 1.0 and + * 2.0 is here. For future versions of + * the player this may need to be modified. + */ + if (*(bptr + 1) == 0x02) + bptr += 8; + else + bptr += 4; + break; + + case 6: + /* This is the field containing the port + * number that RA-player is listening to. + */ + lport = (((u_char*)bptr)[0] << 8) + + ((u_char *)bptr)[1]; + if (lport < 6970) + lport += 256; /* don't know why */ + if (lport < 6970 || lport > 7170) + return 1; /* failed */ + + /* try to get udp port between 6970 - 7170 */ + for (p = 6970; p < 7071; p++) { + if (udp_listen( htons(p), + so->so_laddr.s_addr, + htons(lport), + SS_FACCEPTONCE)) { + break; + } + } + if (p == 7071) + p = 0; + *(u_char *)bptr++ = (p >> 8) & 0xff; + *(u_char *)bptr++ = p & 0xff; + ra = 0; + return 1; /* port redirected, we're done */ + break; + + default: + ra = 0; + } + ra++; + } + return 1; + + default: + /* Ooops, not emulated, won't call tcp_emu again */ + so->so_emu = 0; + return 1; + } +} + +/* + * Do misc. config of SLiRP while its running. + * Return 0 if this connections is to be closed, 1 otherwise, + * return 2 if this is a command-line connection + */ +int +tcp_ctl(so) + struct socket *so; +{ +#if 0 + struct sbuf *sb = &so->so_snd; + int command; + struct ex_list *ex_ptr; + int do_pty; + struct socket *tmpso; + + DEBUG_CALL("tcp_ctl"); + DEBUG_ARG("so = %lx", (long )so); + + /* + * Check if they're authorised + */ + if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) { + sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n"); + sb->sb_wptr += sb->sb_cc; + return 0; + } + + command = (ntohl(so->so_faddr.s_addr) & 0xff); + + switch(command) { + default: /* Check for exec's */ + + /* + * Check if it's pty_exec + */ + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_fport == so->so_fport && + command == ex_ptr->ex_addr) { + do_pty = ex_ptr->ex_pty; + goto do_exec; + } + } + + /* + * Nothing bound.. + */ + /* tcp_fconnect(so); */ + + /* FALLTHROUGH */ + case CTL_ALIAS: + sb->sb_cc = sprintf(sb->sb_wptr, + "Error: No application configured.\r\n"); + sb->sb_wptr += sb->sb_cc; + return(0); + + do_exec: + DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); + return(fork_exec(so, ex_ptr->ex_exec, do_pty)); + + case CTL_CMD: + for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { + if (tmpso->so_emu == EMU_CTL && + !(tmpso->so_tcpcb? + (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK)) + :0)) { + /* Ooops, control connection already active */ + sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n"); + sb->sb_wptr += sb->sb_cc; + return 0; + } + } + so->so_emu = EMU_CTL; + ctl_password_ok = 0; + sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> "); + sb->sb_wptr += sb->sb_cc; + do_echo=-1; + return(2); + } +#else + return 0; +#endif +} diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c new file mode 100644 index 000000000..166979a3e --- /dev/null +++ b/slirp/tcp_timer.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93 + * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp + */ + +#include + +#define max(x,y) ((x) > (y) ? (x) : (y)) +#define min(x,y) ((x) < (y) ? (x) : (y)) + +int tcp_keepidle = TCPTV_KEEP_IDLE; +int tcp_keepintvl = TCPTV_KEEPINTVL; +int tcp_maxidle; +int so_options = DO_KEEPALIVE; + +struct tcpstat tcpstat; /* tcp statistics */ +u_int32_t tcp_now; /* for RFC 1323 timestamps */ + +/* + * Fast timeout routine for processing delayed acks + */ +void +tcp_fasttimo() +{ + register struct socket *so; + register struct tcpcb *tp; + + DEBUG_CALL("tcp_fasttimo"); + + so = tcb.so_next; + if (so) + for (; so != &tcb; so = so->so_next) + if ((tp = (struct tcpcb *)so->so_tcpcb) && + (tp->t_flags & TF_DELACK)) { + tp->t_flags &= ~TF_DELACK; + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_delack++; + (void) tcp_output(tp); + } +} + +/* + * Tcp protocol timeout routine called every 500 ms. + * Updates the timers in all active tcb's and + * causes finite state machine actions if timers expire. + */ +void +tcp_slowtimo() +{ + register struct socket *ip, *ipnxt; + register struct tcpcb *tp; + register int i; + + DEBUG_CALL("tcp_slowtimo"); + + tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; + /* + * Search through tcb's and update active timers. + */ + ip = tcb.so_next; + if (ip == 0) + return; + for (; ip != &tcb; ip = ipnxt) { + ipnxt = ip->so_next; + tp = sototcpcb(ip); + if (tp == 0) + continue; + for (i = 0; i < TCPT_NTIMERS; i++) { + if (tp->t_timer[i] && --tp->t_timer[i] == 0) { + tcp_timers(tp,i); + if (ipnxt->so_prev != ip) + goto tpgone; + } + } + tp->t_idle++; + if (tp->t_rtt) + tp->t_rtt++; +tpgone: + ; + } + tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ +#ifdef TCP_COMPAT_42 + if ((int)tcp_iss < 0) + tcp_iss = 0; /* XXX */ +#endif + tcp_now++; /* for timestamps */ +} + +/* + * Cancel all timers for TCP tp. + */ +void +tcp_canceltimers(tp) + struct tcpcb *tp; +{ + register int i; + + for (i = 0; i < TCPT_NTIMERS; i++) + tp->t_timer[i] = 0; +} + +int tcp_backoff[TCP_MAXRXTSHIFT + 1] = + { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; + +/* + * TCP timer processing. + */ +struct tcpcb * +tcp_timers(tp, timer) + register struct tcpcb *tp; + int timer; +{ + register int rexmt; + + DEBUG_CALL("tcp_timers"); + + switch (timer) { + + /* + * 2 MSL timeout in shutdown went off. If we're closed but + * still waiting for peer to close and connection has been idle + * too long, or if 2MSL time is up from TIME_WAIT, delete connection + * control block. Otherwise, check again in a bit. + */ + case TCPT_2MSL: + if (tp->t_state != TCPS_TIME_WAIT && + tp->t_idle <= tcp_maxidle) + tp->t_timer[TCPT_2MSL] = tcp_keepintvl; + else + tp = tcp_close(tp); + break; + + /* + * Retransmission timer went off. Message has not + * been acked within retransmit interval. Back off + * to a longer retransmit interval and retransmit one segment. + */ + case TCPT_REXMT: + + /* + * XXXXX If a packet has timed out, then remove all the queued + * packets for that session. + */ + + if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { + /* + * This is a hack to suit our terminal server here at the uni of canberra + * since they have trouble with zeroes... It usually lets them through + * unharmed, but under some conditions, it'll eat the zeros. If we + * keep retransmitting it, it'll keep eating the zeroes, so we keep + * retransmitting, and eventually the connection dies... + * (this only happens on incoming data) + * + * So, if we were gonna drop the connection from too many retransmits, + * don't... instead halve the t_maxseg, which might break up the NULLs and + * let them through + * + * *sigh* + */ + + tp->t_maxseg >>= 1; + if (tp->t_maxseg < 32) { + /* + * We tried our best, now the connection must die! + */ + tp->t_rxtshift = TCP_MAXRXTSHIFT; + tcpstat.tcps_timeoutdrop++; + tp = tcp_drop(tp, tp->t_softerror); + /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ + return (tp); /* XXX */ + } + + /* + * Set rxtshift to 6, which is still at the maximum + * backoff time + */ + tp->t_rxtshift = 6; + } + tcpstat.tcps_rexmttimeo++; + rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; + TCPT_RANGESET(tp->t_rxtcur, rexmt, + (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * If losing, let the lower level know and try for + * a better route. Also, if we backed off this far, + * our srtt estimate is probably bogus. Clobber it + * so we'll take the next rtt measurement as our srtt; + * move the current srtt into rttvar to keep the current + * retransmit times until then. + */ + if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { +/* in_losing(tp->t_inpcb); */ + tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); + tp->t_srtt = 0; + } + tp->snd_nxt = tp->snd_una; + /* + * If timing a segment in this window, stop the timer. + */ + tp->t_rtt = 0; + /* + * Close the congestion window down to one segment + * (we'll open it by one segment for each ack we get). + * Since we probably have a window's worth of unacked + * data accumulated, this "slow start" keeps us from + * dumping all that data as back-to-back packets (which + * might overwhelm an intermediate gateway). + * + * There are two phases to the opening: Initially we + * open by one mss on each ack. This makes the window + * size increase exponentially with time. If the + * window is larger than the path can handle, this + * exponential growth results in dropped packet(s) + * almost immediately. To get more time between + * drops but still "push" the network to take advantage + * of improving conditions, we switch from exponential + * to linear window opening at some threshold size. + * For a threshold, we use half the current window + * size, truncated to a multiple of the mss. + * + * (the minimum cwnd that will give us exponential + * growth is 2 mss. We don't allow the threshold + * to go below this.) + */ + { + u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; + if (win < 2) + win = 2; + tp->snd_cwnd = tp->t_maxseg; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_dupacks = 0; + } + (void) tcp_output(tp); + break; + + /* + * Persistence timer into zero window. + * Force a byte to be output, if possible. + */ + case TCPT_PERSIST: + tcpstat.tcps_persisttimeo++; + tcp_setpersist(tp); + tp->t_force = 1; + (void) tcp_output(tp); + tp->t_force = 0; + break; + + /* + * Keep-alive timer went off; send something + * or drop connection if idle for too long. + */ + case TCPT_KEEP: + tcpstat.tcps_keeptimeo++; + if (tp->t_state < TCPS_ESTABLISHED) + goto dropit; + +/* if (tp->t_socket->so_options & SO_KEEPALIVE && */ + if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { + if (tp->t_idle >= tcp_keepidle + tcp_maxidle) + goto dropit; + /* + * Send a packet designed to force a response + * if the peer is up and reachable: + * either an ACK if the connection is still alive, + * or an RST if the peer has closed the connection + * due to timeout or reboot. + * Using sequence number tp->snd_una-1 + * causes the transmitted zero-length segment + * to lie outside the receive window; + * by the protocol spec, this requires the + * correspondent TCP to respond. + */ + tcpstat.tcps_keepprobe++; +#ifdef TCP_COMPAT_42 + /* + * The keepalive packet must have nonzero length + * to get a 4.2 host to respond. + */ + tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, + tp->rcv_nxt - 1, tp->snd_una - 1, 0); +#else + tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, + tp->rcv_nxt, tp->snd_una - 1, 0); +#endif + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + } else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + break; + + dropit: + tcpstat.tcps_keepdrops++; + tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ + break; + } + + return (tp); +} diff --git a/slirp/tcp_timer.h b/slirp/tcp_timer.h new file mode 100644 index 000000000..59933bc1b --- /dev/null +++ b/slirp/tcp_timer.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 + * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp + */ + +#ifndef _TCP_TIMER_H_ +#define _TCP_TIMER_H_ + +/* + * Definitions of the TCP timers. These timers are counted + * down PR_SLOWHZ times a second. + */ +#define TCPT_NTIMERS 4 + +#define TCPT_REXMT 0 /* retransmit */ +#define TCPT_PERSIST 1 /* retransmit persistence */ +#define TCPT_KEEP 2 /* keep alive */ +#define TCPT_2MSL 3 /* 2*msl quiet time timer */ + +/* + * The TCPT_REXMT timer is used to force retransmissions. + * The TCP has the TCPT_REXMT timer set whenever segments + * have been sent for which ACKs are expected but not yet + * received. If an ACK is received which advances tp->snd_una, + * then the retransmit timer is cleared (if there are no more + * outstanding segments) or reset to the base value (if there + * are more ACKs expected). Whenever the retransmit timer goes off, + * we retransmit one unacknowledged segment, and do a backoff + * on the retransmit timer. + * + * The TCPT_PERSIST timer is used to keep window size information + * flowing even if the window goes shut. If all previous transmissions + * have been acknowledged (so that there are no retransmissions in progress), + * and the window is too small to bother sending anything, then we start + * the TCPT_PERSIST timer. When it expires, if the window is nonzero, + * we go to transmit state. Otherwise, at intervals send a single byte + * into the peer's window to force him to update our window information. + * We do this at most as often as TCPT_PERSMIN time intervals, + * but no more frequently than the current estimate of round-trip + * packet time. The TCPT_PERSIST timer is cleared whenever we receive + * a window update from the peer. + * + * The TCPT_KEEP timer is used to keep connections alive. If an + * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, + * but not yet established, then we drop the connection. Once the connection + * is established, if the connection is idle for TCPTV_KEEP_IDLE time + * (and keepalives have been enabled on the socket), we begin to probe + * the connection. We force the peer to send us a segment by sending: + * + * This segment is (deliberately) outside the window, and should elicit + * an ack segment in response from the peer. If, despite the TCPT_KEEP + * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE + * amount of time probing, then we drop the connection. + */ + +/* + * Time constants. + */ +#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ + +#define TCPTV_SRTTBASE 0 /* base roundtrip time; + if 0, no idea yet */ +#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ + +#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ +#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ + +#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ +#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ +#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ +#define TCPTV_KEEPCNT 8 /* max probes before drop */ + +#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ +/* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ +#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ + +#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ + +#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ + + +#ifdef TCPTIMERS +char *tcptimers[] = + { "REXMT", "PERSIST", "KEEP", "2MSL" }; +#endif + +/* + * Force a time value to be in a certain range. + */ +#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ + (tv) = (value); \ + if ((tv) < (tvmin)) \ + (tv) = (tvmin); \ + else if ((tv) > (tvmax)) \ + (tv) = (tvmax); \ +} + +extern int tcp_keepidle; /* time before keepalive probes begin */ +extern int tcp_keepintvl; /* time between keepalive probes */ +extern int tcp_maxidle; /* time to drop after starting probes */ +extern int tcp_ttl; /* time to live for TCP segs */ +extern int tcp_backoff[]; + +struct tcpcb; + +void tcp_fasttimo _P((void)); +void tcp_slowtimo _P((void)); +void tcp_canceltimers _P((struct tcpcb *)); +struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); + +#endif diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h new file mode 100644 index 000000000..0d6cd245e --- /dev/null +++ b/slirp/tcp_var.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 1982, 1986, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94 + * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp + */ + +#ifndef _TCP_VAR_H_ +#define _TCP_VAR_H_ + +#include "tcpip.h" +#include "tcp_timer.h" + +#if SIZEOF_CHAR_P == 4 + typedef struct tcpiphdr *tcpiphdrp_32; +#else + typedef u_int32_t tcpiphdrp_32; +#endif + +/* + * Tcp control block, one per tcp; fields: + */ +struct tcpcb { + tcpiphdrp_32 seg_next; /* sequencing queue */ + tcpiphdrp_32 seg_prev; + short t_state; /* state of this connection */ + short t_timer[TCPT_NTIMERS]; /* tcp timers */ + short t_rxtshift; /* log(2) of rexmt exp. backoff */ + short t_rxtcur; /* current retransmit value */ + short t_dupacks; /* consecutive dup acks recd */ + u_short t_maxseg; /* maximum segment size */ + char t_force; /* 1 if forcing out a byte */ + u_short t_flags; +#define TF_ACKNOW 0x0001 /* ack peer immediately */ +#define TF_DELACK 0x0002 /* ack, but try to delay it */ +#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ +#define TF_NOOPT 0x0008 /* don't use tcp options */ +#define TF_SENTFIN 0x0010 /* have sent FIN */ +#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ +#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ +#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ +#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ +#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ + + /* Make it static for now */ +/* struct tcpiphdr *t_template; / * skeletal packet for transmit */ + struct tcpiphdr t_template; + + struct socket *t_socket; /* back pointer to socket */ +/* + * The following fields are used as in the protocol specification. + * See RFC783, Dec. 1981, page 21. + */ +/* send sequence variables */ + tcp_seq snd_una; /* send unacknowledged */ + tcp_seq snd_nxt; /* send next */ + tcp_seq snd_up; /* send urgent pointer */ + tcp_seq snd_wl1; /* window update seg seq number */ + tcp_seq snd_wl2; /* window update seg ack number */ + tcp_seq iss; /* initial send sequence number */ + u_int32_t snd_wnd; /* send window */ +/* receive sequence variables */ + u_int32_t rcv_wnd; /* receive window */ + tcp_seq rcv_nxt; /* receive next */ + tcp_seq rcv_up; /* receive urgent pointer */ + tcp_seq irs; /* initial receive sequence number */ +/* + * Additional variables for this implementation. + */ +/* receive variables */ + tcp_seq rcv_adv; /* advertised window */ +/* retransmit variables */ + tcp_seq snd_max; /* highest sequence number sent; + * used to recognize retransmits + */ +/* congestion control (for slow start, source quench, retransmit after loss) */ + u_int32_t snd_cwnd; /* congestion-controlled window */ + u_int32_t snd_ssthresh; /* snd_cwnd size threshold for + * for slow start exponential to + * linear switch + */ +/* + * transmit timing stuff. See below for scale of srtt and rttvar. + * "Variance" is actually smoothed difference. + */ + short t_idle; /* inactivity time */ + short t_rtt; /* round trip time */ + tcp_seq t_rtseq; /* sequence number being timed */ + short t_srtt; /* smoothed round-trip time */ + short t_rttvar; /* variance in round-trip time */ + u_short t_rttmin; /* minimum rtt allowed */ + u_int32_t max_sndwnd; /* largest window peer has offered */ + +/* out-of-band data */ + char t_oobflags; /* have some */ + char t_iobc; /* input character */ +#define TCPOOB_HAVEDATA 0x01 +#define TCPOOB_HADDATA 0x02 + short t_softerror; /* possible error not yet reported */ + +/* RFC 1323 variables */ + u_char snd_scale; /* window scaling for send window */ + u_char rcv_scale; /* window scaling for recv window */ + u_char request_r_scale; /* pending window scaling */ + u_char requested_s_scale; + u_int32_t ts_recent; /* timestamp echo data */ + u_int32_t ts_recent_age; /* when last updated */ + tcp_seq last_ack_sent; + +}; + +#define sototcpcb(so) ((so)->so_tcpcb) + +/* + * The smoothed round-trip time and estimated variance + * are stored as fixed point numbers scaled by the values below. + * For convenience, these scales are also used in smoothing the average + * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). + * With these scales, srtt has 3 bits to the right of the binary point, + * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the + * binary point, and is smoothed with an ALPHA of 0.75. + */ +#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ +#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ +#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ +#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ + +/* + * The initial retransmission should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + * This macro assumes that the value of TCP_RTTVAR_SCALE + * is the same as the multiplier for rttvar. + */ +#define TCP_REXMTVAL(tp) \ + (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) + +/* XXX + * We want to avoid doing m_pullup on incoming packets but that + * means avoiding dtom on the tcp reassembly code. That in turn means + * keeping an mbuf pointer in the reassembly queue (since we might + * have a cluster). As a quick hack, the source & destination + * port numbers (which are no longer needed once we've located the + * tcpcb) are overlayed with an mbuf pointer. + */ +#if SIZEOF_CHAR_P == 4 +typedef struct mbuf *mbufp_32; +#else +typedef u_int32_t mbufp_32; +#endif +#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) + +/* + * TCP statistics. + * Many of these should be kept per connection, + * but that's inconvenient at the moment. + */ +struct tcpstat { + u_long tcps_connattempt; /* connections initiated */ + u_long tcps_accepts; /* connections accepted */ + u_long tcps_connects; /* connections established */ + u_long tcps_drops; /* connections dropped */ + u_long tcps_conndrops; /* embryonic connections dropped */ + u_long tcps_closed; /* conn. closed (includes drops) */ + u_long tcps_segstimed; /* segs where we tried to get rtt */ + u_long tcps_rttupdated; /* times we succeeded */ + u_long tcps_delack; /* delayed acks sent */ + u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ + u_long tcps_rexmttimeo; /* retransmit timeouts */ + u_long tcps_persisttimeo; /* persist timeouts */ + u_long tcps_keeptimeo; /* keepalive timeouts */ + u_long tcps_keepprobe; /* keepalive probes sent */ + u_long tcps_keepdrops; /* connections dropped in keepalive */ + + u_long tcps_sndtotal; /* total packets sent */ + u_long tcps_sndpack; /* data packets sent */ + u_long tcps_sndbyte; /* data bytes sent */ + u_long tcps_sndrexmitpack; /* data packets retransmitted */ + u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ + u_long tcps_sndacks; /* ack-only packets sent */ + u_long tcps_sndprobe; /* window probes sent */ + u_long tcps_sndurg; /* packets sent with URG only */ + u_long tcps_sndwinup; /* window update-only packets sent */ + u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ + + u_long tcps_rcvtotal; /* total packets received */ + u_long tcps_rcvpack; /* packets received in sequence */ + u_long tcps_rcvbyte; /* bytes received in sequence */ + u_long tcps_rcvbadsum; /* packets received with ccksum errs */ + u_long tcps_rcvbadoff; /* packets received with bad offset */ +/* u_long tcps_rcvshort; */ /* packets received too short */ + u_long tcps_rcvduppack; /* duplicate-only packets received */ + u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ + u_long tcps_rcvpartduppack; /* packets with some duplicate data */ + u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ + u_long tcps_rcvoopack; /* out-of-order packets received */ + u_long tcps_rcvoobyte; /* out-of-order bytes received */ + u_long tcps_rcvpackafterwin; /* packets with data after window */ + u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ + u_long tcps_rcvafterclose; /* packets rcvd after "close" */ + u_long tcps_rcvwinprobe; /* rcvd window probe packets */ + u_long tcps_rcvdupack; /* rcvd duplicate acks */ + u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ + u_long tcps_rcvackpack; /* rcvd ack packets */ + u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ + u_long tcps_rcvwinupd; /* rcvd window update packets */ +/* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */ + u_long tcps_predack; /* times hdr predict ok for acks */ + u_long tcps_preddat; /* times hdr predict ok for data pkts */ + u_long tcps_socachemiss; /* tcp_last_so misses */ + u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */ +}; + +extern struct tcpstat tcpstat; /* tcp statistics */ +extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ + +#endif diff --git a/slirp/tcpip.h b/slirp/tcpip.h new file mode 100644 index 000000000..82708b09c --- /dev/null +++ b/slirp/tcpip.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 + * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp + */ + +#ifndef _TCPIP_H_ +#define _TCPIP_H_ + +/* + * Tcp+ip header, after ip options removed. + */ +struct tcpiphdr { + struct ipovly ti_i; /* overlaid ip structure */ + struct tcphdr ti_t; /* tcp header */ +}; +#define ti_next ti_i.ih_next +#define ti_prev ti_i.ih_prev +#define ti_x1 ti_i.ih_x1 +#define ti_pr ti_i.ih_pr +#define ti_len ti_i.ih_len +#define ti_src ti_i.ih_src +#define ti_dst ti_i.ih_dst +#define ti_sport ti_t.th_sport +#define ti_dport ti_t.th_dport +#define ti_seq ti_t.th_seq +#define ti_ack ti_t.th_ack +#define ti_x2 ti_t.th_x2 +#define ti_off ti_t.th_off +#define ti_flags ti_t.th_flags +#define ti_win ti_t.th_win +#define ti_sum ti_t.th_sum +#define ti_urp ti_t.th_urp + +/* + * Just a clean way to get to the first byte + * of the packet + */ +struct tcpiphdr_2 { + struct tcpiphdr dummy; + char first_char; +}; + +#endif diff --git a/slirp/udp.c b/slirp/udp.c new file mode 100644 index 000000000..76a4fcc97 --- /dev/null +++ b/slirp/udp.c @@ -0,0 +1,654 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 + * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "ip_icmp.h" + +struct udpstat udpstat; + +struct socket udb; + +/* + * UDP protocol implementation. + * Per RFC 768, August, 1980. + */ +#ifndef COMPAT_42 +int udpcksum = 1; +#else +int udpcksum = 0; /* XXX */ +#endif + +struct socket *udp_last_so = &udb; + +void +udp_init() +{ + udb.so_next = udb.so_prev = &udb; +} +/* m->m_data points at ip packet header + * m->m_len length ip packet + * ip->ip_len length data (IPDU) + */ +void +udp_input(m, iphlen) + register struct mbuf *m; + int iphlen; +{ + register struct ip *ip; + register struct udphdr *uh; +/* struct mbuf *opts = 0;*/ + int len; + struct ip save_ip; + struct socket *so; + + DEBUG_CALL("udp_input"); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("iphlen = %d", iphlen); + + udpstat.udps_ipackets++; + + /* + * Strip IP options, if any; should skip this, + * make available to user, and use on returned packets, + * but we don't yet have a way to check the checksum + * with options still present. + */ + if(iphlen > sizeof(struct ip)) { + ip_stripoptions(m, (struct mbuf *)0); + iphlen = sizeof(struct ip); + } + + /* + * Get IP and UDP header together in first mbuf. + */ + ip = mtod(m, struct ip *); + uh = (struct udphdr *)((caddr_t)ip + iphlen); + + /* + * Make mbuf data length reflect UDP length. + * If not enough data to reflect UDP length, drop. + */ + len = ntohs((u_int16_t)uh->uh_ulen); + + if (ip->ip_len != len) { + if (len > ip->ip_len) { + udpstat.udps_badlen++; + goto bad; + } + m_adj(m, len - ip->ip_len); + ip->ip_len = len; + } + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip = *ip; + save_ip.ip_len+= iphlen; /* tcp_input subtracts this */ + + /* + * Checksum extended UDP header and data. + */ + if (udpcksum && uh->uh_sum) { + ((struct ipovly *)ip)->ih_next = 0; + ((struct ipovly *)ip)->ih_prev = 0; + ((struct ipovly *)ip)->ih_x1 = 0; + ((struct ipovly *)ip)->ih_len = uh->uh_ulen; + /* keep uh_sum for ICMP reply + * uh->uh_sum = cksum(m, len + sizeof (struct ip)); + * if (uh->uh_sum) { + */ + if(cksum(m, len + sizeof(struct ip))) { + udpstat.udps_badsum++; + goto bad; + } + } + + /* + * handle DHCP/BOOTP + */ + if (ntohs(uh->uh_dport) == BOOTP_SERVER) { + bootp_input(m); + goto bad; + } + + /* + * Locate pcb for datagram. + */ + so = udp_last_so; + if (so->so_lport != uh->uh_sport || + so->so_laddr.s_addr != ip->ip_src.s_addr) { + struct socket *tmp; + + for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { + if (tmp->so_lport == uh->uh_sport && + tmp->so_laddr.s_addr == ip->ip_src.s_addr) { + tmp->so_faddr.s_addr = ip->ip_dst.s_addr; + tmp->so_fport = uh->uh_dport; + so = tmp; + break; + } + } + if (tmp == &udb) { + so = NULL; + } else { + udpstat.udpps_pcbcachemiss++; + udp_last_so = so; + } + } + + if (so == NULL) { + /* + * If there's no socket for this packet, + * create one + */ + if ((so = socreate()) == NULL) goto bad; + if(udp_attach(so) == -1) { + DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", + errno,strerror(errno))); + sofree(so); + goto bad; + } + + /* + * Setup fields + */ + /* udp_last_so = so; */ + so->so_laddr = ip->ip_src; + so->so_lport = uh->uh_sport; + so->so_faddr = ip->ip_dst; /* XXX */ + so->so_fport = uh->uh_dport; /* XXX */ + + if ((so->so_iptos = udp_tos(so)) == 0) + so->so_iptos = ip->ip_tos; + + /* + * XXXXX Here, check if it's in udpexec_list, + * and if it is, do the fork_exec() etc. + */ + } + + iphlen += sizeof(struct udphdr); + m->m_len -= iphlen; + m->m_data += iphlen; + + /* + * Now we sendto() the packet. + */ + if (so->so_emu) + udp_emu(so, m); + + if(sosendto(so,m) == -1) { + m->m_len += iphlen; + m->m_data -= iphlen; + *ip=save_ip; + DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + } + + m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ + + /* restore the orig mbuf packet */ + m->m_len += iphlen; + m->m_data -= iphlen; + *ip=save_ip; + so->so_m=m; /* ICMP backup */ + + return; +bad: + m_freem(m); + /* if (opts) m_freem(opts); */ + return; +} + +int udp_output2(struct socket *so, struct mbuf *m, + struct sockaddr_in *saddr, struct sockaddr_in *daddr, + int iptos) +{ + register struct udpiphdr *ui; + int error = 0; + + DEBUG_CALL("udp_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr); + DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr); + + /* + * Adjust for header + */ + m->m_data -= sizeof(struct udpiphdr); + m->m_len += sizeof(struct udpiphdr); + + /* + * Fill in mbuf with extended UDP header + * and addresses and length put into network format. + */ + ui = mtod(m, struct udpiphdr *); + ui->ui_next = ui->ui_prev = 0; + ui->ui_x1 = 0; + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ + /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ + ui->ui_src = saddr->sin_addr; + ui->ui_dst = daddr->sin_addr; + ui->ui_sport = saddr->sin_port; + ui->ui_dport = daddr->sin_port; + ui->ui_ulen = ui->ui_len; + + /* + * Stuff checksum and output datagram. + */ + ui->ui_sum = 0; + if (udpcksum) { + if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) + ui->ui_sum = 0xffff; + } + ((struct ip *)ui)->ip_len = m->m_len; + + ((struct ip *)ui)->ip_ttl = ip_defttl; + ((struct ip *)ui)->ip_tos = iptos; + + udpstat.udps_opackets++; + + error = ip_output(so, m); + + return (error); +} + +int udp_output(struct socket *so, struct mbuf *m, + struct sockaddr_in *addr) + +{ + struct sockaddr_in saddr, daddr; + + saddr = *addr; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) + saddr.sin_addr.s_addr = so->so_faddr.s_addr; + daddr.sin_addr = so->so_laddr; + daddr.sin_port = so->so_lport; + + return udp_output2(so, m, &saddr, &daddr, so->so_iptos); +} + +int +udp_attach(so) + struct socket *so; +{ + struct sockaddr_in addr; + + if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { + /* + * Here, we bind() the socket. Although not really needed + * (sendto() on an unbound socket will bind it), it's done + * here so that emulation of ytalk etc. don't have to do it + */ + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { + int lasterrno=errno; + close(so->s); + so->s=-1; + errno=lasterrno; + } else { + /* success, insert in queue */ + so->so_expire = curtime + SO_EXPIRE; + insque(so,&udb); + } + } + return(so->s); +} + +void +udp_detach(so) + struct socket *so; +{ + close(so->s); + /* if (so->so_m) m_free(so->so_m); done by sofree */ + + sofree(so); +} + +struct tos_t udptos[] = { + {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ + {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ + {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ + {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ + {0, 0, 0, 0} +}; + +u_int8_t +udp_tos(so) + struct socket *so; +{ + int i = 0; + + while(udptos[i].tos) { + if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || + (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { + so->so_emu = udptos[i].emu; + return udptos[i].tos; + } + i++; + } + + return 0; +} + +#ifdef EMULATE_TALK +#include "talkd.h" +#endif + +/* + * Here, talk/ytalk/ntalk requests must be emulated + */ +void +udp_emu(so, m) + struct socket *so; + struct mbuf *m; +{ + struct sockaddr_in addr; + int addrlen = sizeof(addr); +#ifdef EMULATE_TALK + CTL_MSG_OLD *omsg; + CTL_MSG *nmsg; + char buff[sizeof(CTL_MSG)]; + u_char type; + +struct talk_request { + struct talk_request *next; + struct socket *udp_so; + struct socket *tcp_so; +} *req; + + static struct talk_request *req_tbl = 0; + +#endif + +struct cu_header { + char dest[8]; + short family; + u_short port; + u_long addr; +} *cu_head; + + switch(so->so_emu) { + +#ifdef EMULATE_TALK + case EMU_TALK: + case EMU_NTALK: + /* + * Talk emulation. We always change the ctl_addr to get + * some answers from the daemon. When an ANNOUNCE comes, + * we send LEAVE_INVITE to the local daemons. Also when a + * DELETE comes, we send copies to the local daemons. + */ + if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) + return; + +#define IS_OLD (so->so_emu == EMU_TALK) + +#define COPY_MSG(dest, src) { dest->type = src->type; \ + dest->id_num = src->id_num; \ + dest->pid = src->pid; \ + dest->addr = src->addr; \ + dest->ctl_addr = src->ctl_addr; \ + memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ + memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ + memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } + +#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) +/* old_sockaddr to sockaddr_in */ + + + if (IS_OLD) { /* old talk */ + omsg = mtod(m, CTL_MSG_OLD*); + nmsg = (CTL_MSG *) buff; + type = omsg->type; + OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; + OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; + strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD); + } else { /* new talk */ + omsg = (CTL_MSG_OLD *) buff; + nmsg = mtod(m, CTL_MSG *); + type = nmsg->type; + OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; + OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; + strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); + } + + if (type == LOOK_UP) + return; /* for LOOK_UP this is enough */ + + if (IS_OLD) { /* make a copy of the message */ + COPY_MSG(nmsg, omsg); + nmsg->vers = 1; + nmsg->answer = 0; + } else + COPY_MSG(omsg, nmsg); + + /* + * If if is an ANNOUNCE message, we go through the + * request table to see if a tcp port has already + * been redirected for this socket. If not, we solisten() + * a new socket and add this entry to the table. + * The port number of the tcp socket and our IP + * are put to the addr field of the message structures. + * Then a LEAVE_INVITE is sent to both local daemon + * ports, 517 and 518. This is why we have two copies + * of the message, one in old talk and one in new talk + * format. + */ + + if (type == ANNOUNCE) { + int s; + u_short temp_port; + + for(req = req_tbl; req; req = req->next) + if (so == req->udp_so) + break; /* found it */ + + if (!req) { /* no entry for so, create new */ + req = (struct talk_request *) + malloc(sizeof(struct talk_request)); + req->udp_so = so; + req->tcp_so = solisten(0, + OTOSIN(omsg, addr)->sin_addr.s_addr, + OTOSIN(omsg, addr)->sin_port, + SS_FACCEPTONCE); + req->next = req_tbl; + req_tbl = req; + } + + /* replace port number in addr field */ + addrlen = sizeof(addr); + getsockname(req->tcp_so->s, + (struct sockaddr *) &addr, + &addrlen); + OTOSIN(omsg, addr)->sin_port = addr.sin_port; + OTOSIN(omsg, addr)->sin_addr = our_addr; + OTOSIN(nmsg, addr)->sin_port = addr.sin_port; + OTOSIN(nmsg, addr)->sin_addr = our_addr; + + /* send LEAVE_INVITEs */ + temp_port = OTOSIN(omsg, ctl_addr)->sin_port; + OTOSIN(omsg, ctl_addr)->sin_port = 0; + OTOSIN(nmsg, ctl_addr)->sin_port = 0; + omsg->type = nmsg->type = LEAVE_INVITE; + + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + addr.sin_addr = our_addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(517); + sendto(s, (char *)omsg, sizeof(*omsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + addr.sin_port = htons(518); + sendto(s, (char *)nmsg, sizeof(*nmsg), 0, + (struct sockaddr *) &addr, sizeof(addr)); + close(s) ; + + omsg->type = nmsg->type = ANNOUNCE; + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; + OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; + } + + /* + * If it is a DELETE message, we send a copy to the + * local daemons. Then we delete the entry corresponding + * to our socket from the request table. + */ + + if (type == DELETE) { + struct talk_request *temp_req, *req_next; + int s; + u_short temp_port; + + temp_port = OTOSIN(omsg, ctl_addr)->sin_port; + OTOSIN(omsg, ctl_addr)->sin_port = 0; + OTOSIN(nmsg, ctl_addr)->sin_port = 0; + + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + addr.sin_addr = our_addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(517); + sendto(s, (char *)omsg, sizeof(*omsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + addr.sin_port = htons(518); + sendto(s, (char *)nmsg, sizeof(*nmsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + close(s); + + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; + OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; + + /* delete table entry */ + if (so == req_tbl->udp_so) { + temp_req = req_tbl; + req_tbl = req_tbl->next; + free(temp_req); + } else { + temp_req = req_tbl; + for(req = req_tbl->next; req; req = req_next) { + req_next = req->next; + if (so == req->udp_so) { + temp_req->next = req_next; + free(req); + break; + } else { + temp_req = req; + } + } + } + } + + return; +#endif + + case EMU_CUSEEME: + + /* + * Cu-SeeMe emulation. + * Hopefully the packet is more that 16 bytes long. We don't + * do any other tests, just replace the address and port + * fields. + */ + if (m->m_len >= sizeof (*cu_head)) { + if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) + return; + cu_head = mtod(m, struct cu_header *); + cu_head->port = addr.sin_port; + cu_head->addr = (u_long) our_addr.s_addr; + } + + return; + } +} + +struct socket * +udp_listen(port, laddr, lport, flags) + u_int port; + u_int32_t laddr; + u_int lport; + int flags; +{ + struct sockaddr_in addr; + struct socket *so; + int addrlen = sizeof(struct sockaddr_in), opt = 1; + + if ((so = socreate()) == NULL) { + free(so); + return NULL; + } + so->s = socket(AF_INET,SOCK_DGRAM,0); + so->so_expire = curtime + SO_EXPIRE; + insque(so,&udb); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = port; + + if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { + udp_detach(so); + return NULL; + } + setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); +/* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ + + getsockname(so->s,(struct sockaddr *)&addr,&addrlen); + so->so_fport = addr.sin_port; + if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) + so->so_faddr = our_addr; + else + so->so_faddr = addr.sin_addr; + + so->so_lport = lport; + so->so_laddr.s_addr = laddr; + if (flags != SS_FACCEPTONCE) + so->so_expire = 0; + + so->so_state = SS_ISFCONNECTED; + + return so; +} diff --git a/slirp/udp.h b/slirp/udp.h new file mode 100644 index 000000000..195b1bfff --- /dev/null +++ b/slirp/udp.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)udp.h 8.1 (Berkeley) 6/10/93 + * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp + */ + +#ifndef _UDP_H_ +#define _UDP_H_ + +#define UDP_TTL 0x60 +#define UDP_UDPDATALEN 16192 + +extern struct socket *udp_last_so; + +/* + * Udp protocol header. + * Per RFC 768, September, 1981. + */ +struct udphdr { + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ +}; + +/* + * UDP kernel structures and variables. + */ +struct udpiphdr { + struct ipovly ui_i; /* overlaid ip structure */ + struct udphdr ui_u; /* udp header */ +}; +#define ui_next ui_i.ih_next +#define ui_prev ui_i.ih_prev +#define ui_x1 ui_i.ih_x1 +#define ui_pr ui_i.ih_pr +#define ui_len ui_i.ih_len +#define ui_src ui_i.ih_src +#define ui_dst ui_i.ih_dst +#define ui_sport ui_u.uh_sport +#define ui_dport ui_u.uh_dport +#define ui_ulen ui_u.uh_ulen +#define ui_sum ui_u.uh_sum + +struct udpstat { + /* input statistics: */ + u_long udps_ipackets; /* total input packets */ + u_long udps_hdrops; /* packet shorter than header */ + u_long udps_badsum; /* checksum error */ + u_long udps_badlen; /* data length larger than packet */ + u_long udps_noport; /* no socket on port */ + u_long udps_noportbcast; /* of above, arrived as broadcast */ + u_long udps_fullsock; /* not delivered, input socket full */ + u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ + /* output statistics: */ + u_long udps_opackets; /* total output packets */ +}; + +/* + * Names for UDP sysctl objects + */ +#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ +#define UDPCTL_MAXID 2 + +extern struct udpstat udpstat; +extern struct socket udb; + +void udp_init _P((void)); +void udp_input _P((register struct mbuf *, int)); +int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *)); +int udp_attach _P((struct socket *)); +void udp_detach _P((struct socket *)); +u_int8_t udp_tos _P((struct socket *)); +void udp_emu _P((struct socket *, struct mbuf *)); +struct socket * udp_listen _P((u_int, u_int32_t, u_int, int)); +int udp_output2(struct socket *so, struct mbuf *m, + struct sockaddr_in *saddr, struct sockaddr_in *daddr, + int iptos); +#endif -- cgit v1.2.3 From f6bac3809f0a27e9b2d6f85571d02420d1fe70d4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 22 Apr 2004 00:35:09 +0000 Subject: fixed options definition git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@734 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index a2eb8c3f7..18bdd0d54 100644 --- a/vl.c +++ b/vl.c @@ -1827,8 +1827,8 @@ struct option long_options[] = { { "no-code-copy", 0, NULL, 0 }, { "nics", 1, NULL, 0 }, { "macaddr", 1, NULL, 0 }, - { "user-net", 1, NULL, 0 }, - { "dummy-net", 1, NULL, 0 }, + { "user-net", 0, NULL, 0 }, + { "dummy-net", 0, NULL, 0 }, { NULL, 0, NULL, 0 }, }; -- cgit v1.2.3 From d64477afa1e2589febd78a681809b361330f2ca9 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 22 Apr 2004 21:34:25 +0000 Subject: imul imm8 fix - 0x82 opcode support (Hidemi KAWAI) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@735 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate-copy.c | 2 ++ target-i386/translate.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index 69927915e..500475a74 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -389,6 +389,7 @@ static int disas_insn(DisasContext *s) case 0x80: /* GRP1 */ case 0x81: + case 0x82: case 0x83: { if ((b & 1) == 0) @@ -403,6 +404,7 @@ static int disas_insn(DisasContext *s) default: case 0x80: case 0x81: + case 0x82: insn_get(s, ot); break; case 0x83: diff --git a/target-i386/translate.c b/target-i386/translate.c index 3ef614652..4bddba56a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1938,6 +1938,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x80: /* GRP1 */ case 0x81: + case 0x82: case 0x83: { int val; @@ -1963,6 +1964,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) default: case 0x80: case 0x81: + case 0x82: val = insn_get(s, ot); break; case 0x83: @@ -2242,7 +2244,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) val = insn_get(s, ot); gen_op_movl_T1_im(val); } else if (b == 0x6b) { - val = insn_get(s, OT_BYTE); + val = (int8_t)insn_get(s, OT_BYTE); gen_op_movl_T1_im(val); } else { gen_op_mov_TN_reg[ot][1][reg](); -- cgit v1.2.3 From 91caaa612a837f01d84ddce12d659108bd3cefdd Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 22 Apr 2004 21:36:13 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@736 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index cec682114..c2660c12a 100644 --- a/Changelog +++ b/Changelog @@ -5,6 +5,9 @@ version 0.5.4: - 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) version 0.5.3: -- cgit v1.2.3 From b5075d29a88017705c252a0695f279f982f59a6f Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 22 Apr 2004 21:37:55 +0000 Subject: more imul tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@737 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 4 ++++ tests/test-i386.c | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/tests/Makefile b/tests/Makefile index c22450430..25742e2ae 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -38,6 +38,10 @@ test: endif $(QEMU) test-i386 > test-i386.out @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi +ifeq ($(ARCH),i386) + $(QEMU) -no-code-copy test-i386 > test-i386.out + @if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK (no code copy)"; fi +endif # generic Linux and CPU test linux-test: linux-test.c diff --git a/tests/test-i386.c b/tests/test-i386.c index ce1213a7d..3e10a9931 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -401,6 +401,23 @@ void test_imull2(int op0, int op1) "imull", s0, s1, res, flags & CC_MASK); } +#define TEST_IMUL_IM(size, size1, op0, op1)\ +{\ + int res, flags;\ + flags = 0;\ + res = 0;\ + asm ("push %3\n\t"\ + "popf\n\t"\ + "imul" size " $" #op0 ", %" size1 "2, %" size1 "0\n\t" \ + "pushf\n\t"\ + "popl %1\n\t"\ + : "=r" (res), "=g" (flags)\ + : "r" (op1), "1" (flags), "0" (res));\ + printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",\ + "imul" size, op0, op1, res, flags & CC_MASK);\ +} + + #undef CC_MASK #define CC_MASK (0) @@ -452,6 +469,16 @@ void test_mul(void) test_imull2(0x80000000, 0x80000000); test_imull2(0x10000, 0x10000); + TEST_IMUL_IM("w", "w", 45, 0x1234); + TEST_IMUL_IM("w", "w", -45, 23); + TEST_IMUL_IM("w", "w", 0x8000, 0x80000000); + TEST_IMUL_IM("w", "w", 0x7fff, 0x1000); + + TEST_IMUL_IM("l", "", 45, 0x1234); + TEST_IMUL_IM("l", "", -45, 23); + TEST_IMUL_IM("l", "", 0x8000, 0x80000000); + TEST_IMUL_IM("l", "", 0x7fff, 0x1000); + test_idivb(0x12341678, 0x127e); test_idivb(0x43210123, -5); test_idivb(0x12340004, -1); -- cgit v1.2.3 From a7e61ed44693062abac4cc3d7a72794545969111 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 22 Apr 2004 21:46:47 +0000 Subject: create slirp directory git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@738 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure b/configure index ef519c8e8..2c8dddbc4 100755 --- a/configure +++ b/configure @@ -423,6 +423,9 @@ mkdir -p $target_dir if test "$target" = "arm-user" ; then mkdir -p $target_dir/nwfpe fi +if test "$target_user_only" = "no" ; then + mkdir -p $target_dir/slirp +fi ln -sf $source_path/Makefile.target $target_dir/Makefile -- cgit v1.2.3 From 039d3da3653a76cc00c67be273799c4f0b007f88 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Apr 2004 00:11:51 +0000 Subject: added user mode libqemu usage example git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@739 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 5 + tests/pi_10.com | Bin 0 -> 54 bytes tests/qruncom.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 tests/pi_10.com create mode 100644 tests/qruncom.c diff --git a/tests/Makefile b/tests/Makefile index 25742e2ae..511629456 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -62,6 +62,11 @@ speed: sha1 sha1-i386 runcom: runcom.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< +# NOTE: -fomit-frame-pointer is currently needed : this is a bug in libqemu +qruncom: qruncom.c ../i386-user/libqemu.a + $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -I../target-i386 -I.. -I../i386-user \ + -o $@ $< -L../i386-user -lqemu -lm + # arm test hello-arm: hello-arm.o arm-linux-ld -o $@ $< diff --git a/tests/pi_10.com b/tests/pi_10.com new file mode 100644 index 000000000..8993ba1a5 Binary files /dev/null and b/tests/pi_10.com differ diff --git a/tests/qruncom.c b/tests/qruncom.c new file mode 100644 index 000000000..491ecbc60 --- /dev/null +++ b/tests/qruncom.c @@ -0,0 +1,303 @@ +/* + * Example of use of user mode libqemu: launch a basic .com DOS + * executable + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" + +//#define SIGTEST + +CPUState *cpu_single_env = NULL; + +void cpu_outb(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); +} + +void cpu_outw(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); +} + +void cpu_outl(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); +} + +int cpu_inb(CPUState *env, int addr) +{ + fprintf(stderr, "inb: port=0x%04x\n", addr); + return 0; +} + +int cpu_inw(CPUState *env, int addr) +{ + fprintf(stderr, "inw: port=0x%04x\n", addr); + return 0; +} + +int cpu_inl(CPUState *env, int addr) +{ + fprintf(stderr, "inl: port=0x%04x\n", addr); + return 0; +} + +int cpu_get_pic_interrupt(CPUState *env) +{ + return -1; +} + +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, + unsigned long addr, unsigned int sel) +{ + unsigned int e1, e2; + e1 = (addr & 0xffff) | (sel << 16); + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); + stl((uint8_t *)ptr, e1); + stl((uint8_t *)ptr + 4, e2); +} + +uint64_t idt_table[256]; + +/* only dpl matters as we do only user space emulation */ +static void set_idt(int n, unsigned int dpl) +{ + set_gate(idt_table + n, 0, dpl, 0, 0); +} + +void qemu_free(void *ptr) +{ + free(ptr); +} + +void *qemu_malloc(size_t size) +{ + return malloc(size); +} + +void qemu_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +/* XXX: this is a bug in helper2.c */ +int errno; + +/**********************************************/ + +#define COM_BASE_ADDR 0x10100 + +void usage(void) +{ + printf("qruncom version 0.1 (c) 2003 Fabrice Bellard\n" + "usage: qruncom file.com\n" + "user mode libqemu demo: run simple .com DOS executables\n"); + exit(1); +} + +static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) +{ + return (uint8_t *)((seg << 4) + (reg & 0xffff)); +} + +static inline void pushw(CPUState *env, int val) +{ + env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | ((env->regs[R_ESP] - 2) & 0xffff); + *(uint16_t *)seg_to_linear(env->segs[R_SS].selector, env->regs[R_ESP]) = val; +} + +static void host_segv_handler(int host_signum, siginfo_t *info, + void *puc) +{ + if (cpu_signal_handler(host_signum, info, puc)) { + return; + } + abort(); +} + +int main(int argc, char **argv) +{ + uint8_t *vm86_mem; + const char *filename; + int fd, ret, seg; + CPUState *env; + + if (argc != 2) + usage(); + filename = argv[1]; + + vm86_mem = mmap((void *)0x00000000, 0x110000, + PROT_WRITE | PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); + if (vm86_mem == MAP_FAILED) { + perror("mmap"); + exit(1); + } + + /* load the MSDOS .com executable */ + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(1); + } + ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256); + if (ret < 0) { + perror("read"); + exit(1); + } + close(fd); + + /* install exception handler for CPU emulator */ + { + struct sigaction act; + + sigfillset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + // act.sa_flags |= SA_ONSTACK; + + act.sa_sigaction = host_segv_handler; + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGBUS, &act, NULL); +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + sigaction(SIGFPE, &act, NULL); +#endif + } + + // cpu_set_log(CPU_LOG_TB_IN_ASM | CPU_LOG_TB_OUT_ASM | CPU_LOG_EXEC); + + env = cpu_init(); + + /* disable code copy to simplify debugging */ + code_copy_enabled = 0; + + /* set user mode state (XXX: should be done automatically by + cpu_init ?) */ + env->user_mode_only = 1; + + cpu_x86_set_cpl(env, 3); + + env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; + /* NOTE: hflags duplicates some of the virtual CPU state */ + env->hflags |= HF_PE_MASK | VM_MASK; + + /* flags setup : we activate the IRQs by default as in user + mode. We also activate the VM86 flag to run DOS code */ + env->eflags |= IF_MASK | VM_MASK; + + /* init basic registers */ + env->eip = 0x100; + env->regs[R_ESP] = 0xfffe; + seg = (COM_BASE_ADDR - 0x100) >> 4; + + cpu_x86_load_seg_cache(env, R_CS, seg, + (uint8_t *)(seg << 4), 0xffff, 0); + cpu_x86_load_seg_cache(env, R_SS, seg, + (uint8_t *)(seg << 4), 0xffff, 0); + cpu_x86_load_seg_cache(env, R_DS, seg, + (uint8_t *)(seg << 4), 0xffff, 0); + cpu_x86_load_seg_cache(env, R_ES, seg, + (uint8_t *)(seg << 4), 0xffff, 0); + cpu_x86_load_seg_cache(env, R_FS, seg, + (uint8_t *)(seg << 4), 0xffff, 0); + cpu_x86_load_seg_cache(env, R_GS, seg, + (uint8_t *)(seg << 4), 0xffff, 0); + + /* exception support */ + env->idt.base = (void *)idt_table; + env->idt.limit = sizeof(idt_table) - 1; + set_idt(0, 0); + set_idt(1, 0); + set_idt(2, 0); + set_idt(3, 3); + set_idt(4, 3); + set_idt(5, 3); + set_idt(6, 0); + set_idt(7, 0); + set_idt(8, 0); + set_idt(9, 0); + set_idt(10, 0); + set_idt(11, 0); + set_idt(12, 0); + set_idt(13, 0); + set_idt(14, 0); + set_idt(15, 0); + set_idt(16, 0); + set_idt(17, 0); + set_idt(18, 0); + set_idt(19, 0); + + /* put return code */ + *seg_to_linear(env->segs[R_CS].selector, 0) = 0xb4; /* mov ah, $0 */ + *seg_to_linear(env->segs[R_CS].selector, 1) = 0x00; + *seg_to_linear(env->segs[R_CS].selector, 2) = 0xcd; /* int $0x21 */ + *seg_to_linear(env->segs[R_CS].selector, 3) = 0x21; + pushw(env, 0x0000); + + /* the value of these registers seem to be assumed by pi_10.com */ + env->regs[R_ESI] = 0x100; + env->regs[R_ECX] = 0xff; + env->regs[R_EBP] = 0x0900; + env->regs[R_EDI] = 0xfffe; + + /* inform the emulator of the mmaped memory */ + page_set_flags(0x00000000, 0x110000, + PAGE_WRITE | PAGE_READ | PAGE_EXEC | PAGE_VALID); + + for(;;) { + ret = cpu_x86_exec(env); + switch(ret) { + case EXCP0D_GPF: + { + int int_num, ah; + int_num = *(env->segs[R_CS].base + env->eip + 1); + if (int_num != 0x21) + goto unknown_int; + ah = (env->regs[R_EAX] >> 8) & 0xff; + switch(ah) { + case 0x00: /* exit */ + exit(0); + case 0x02: /* write char */ + { + uint8_t c = env->regs[R_EDX]; + write(1, &c, 1); + } + break; + case 0x09: /* write string */ + { + uint8_t c; + for(;;) { + c = *seg_to_linear(env->segs[R_DS].selector, env->regs[R_EAX]); + if (c == '$') + break; + write(1, &c, 1); + } + env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | '$'; + } + break; + default: + unknown_int: + fprintf(stderr, "unsupported int 0x%02x\n", int_num); + cpu_dump_state(env, stderr, 0); + // exit(1); + } + env->eip += 2; + } + break; + default: + fprintf(stderr, "unhandled cpu_exec return code (0x%x)\n", ret); + cpu_dump_state(env, stderr, 0); + exit(1); + } + } +} -- cgit v1.2.3 From ad6a4837f88756fbc11d779fb81d96c3e35280bf Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Apr 2004 00:16:28 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@740 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-tech.texi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index 018593475..659cd203e 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -52,7 +52,8 @@ QEMU generic features: @item Precise exceptions support. @item The virtual CPU is a library (@code{libqemu}) which can be used -in other projects. +in other projects (look at @file{qemu/tests/qruncom.c} to have an +example of user mode @code{libqemu} usage). @end itemize -- cgit v1.2.3 From bfbc9133eb419906fc2ed83c99d2a6049a2ad966 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 14:43:10 +0000 Subject: 64 bit seek for win32 (Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@741 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.h b/vl.h index 19681ab95..59ac6935b 100644 --- a/vl.h +++ b/vl.h @@ -44,7 +44,7 @@ #endif #ifdef _WIN32 -#define lseek64 lseek +#define lseek64 _lseeki64 #endif #include "cpu.h" -- cgit v1.2.3 From 1190935d98ec8a8e2e2438858bee8bd5e49ee324 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 17:54:32 +0000 Subject: precise self modifying code test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@742 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 3e10a9931..27a899830 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1580,8 +1580,23 @@ uint8_t code[] = { 0xc3, /* ret */ }; -typedef int FuncType(void); +asm("smc_code2:\n" + "movl 4(%esp), %eax\n" + "movl %eax, smc_patch_addr2 + 1\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "nop\n" + "smc_patch_addr2:\n" + "movl $1, %eax\n" + "ret\n"); +typedef int FuncType(void); +extern int smc_code2(int); void test_self_modifying_code(void) { int i; @@ -1592,6 +1607,13 @@ void test_self_modifying_code(void) code[1] = i; printf("func%d = 0x%x\n", i, ((FuncType *)code)()); } + + /* more difficult test : the modified code is just after the + modifying instruction. It is forbidden in Intel specs, but it + is used by old DOS programs */ + for(i = 2; i <= 4; i++) { + printf("smc_code2(%d) = %d\n", i, smc_code2(i)); + } } static void *call_end __init_call = NULL; -- cgit v1.2.3 From 658138bcbcde308472bc6980957b6b9dbd9348f3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 17:56:08 +0000 Subject: flush insn support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@743 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 1 + target-sparc/op.c | 4 ++++ target-sparc/translate.c | 9 ++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 72e4588f6..6b49ca79a 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -13,4 +13,5 @@ register uint32_t T2 asm(AREG3); void cpu_lock(void); void cpu_unlock(void); void cpu_loop_exit(void); +void helper_flush(target_ulong addr); #endif diff --git a/target-sparc/op.c b/target-sparc/op.c index 1ce3f9509..946c11ec4 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -683,3 +683,7 @@ void OPPROTO op_generic_branch(void) FORCE_RET(); } +void OPPROTO op_flush_T0(void) +{ + helper_flush(T0); +} diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 41decb18f..bcc810b20 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -650,7 +650,8 @@ static void disas_sparc_insn(DisasContext * dc) } goto jmp_insn; case 0x3b: /* flush */ - /* nothing to do */ + gen_op_add_T1_T0(); + gen_op_flush_T0(); break; case 0x3c: /* save */ save_state(dc); @@ -878,3 +879,9 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } + +void helper_flush(target_ulong addr) +{ + addr &= ~7; + tb_invalidate_page_range(addr, addr + 8); +} -- cgit v1.2.3 From eeab3a558f89e30ee93ef628bcbd6a3f64b9b8a6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 17:56:46 +0000 Subject: dump A20 state git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@744 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 22e812e09..4cdde09c2 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -170,7 +170,7 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) eflags = env->eflags; fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d\n", + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], env->eip, eflags, @@ -182,7 +182,8 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) eflags & CC_P ? 'P' : '-', eflags & CC_C ? 'C' : '-', env->hflags & HF_CPL_MASK, - (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1); + (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, + (env->a20_mask >> 20) & 1); for(i = 0; i < 6; i++) { SegmentCache *sc = &env->segs[i]; fprintf(f, "%s =%04x %08x %08x %08x\n", -- cgit v1.2.3 From d720b93d0bcfe1beb729245b9ed1e5f071a24bd5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 17:57:43 +0000 Subject: precise self modifying code support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@745 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 3 +- exec.c | 319 +++++++++++++++++++++++++++---------------- softmmu_template.h | 20 +-- target-arm/cpu.h | 7 + target-i386/cpu.h | 18 ++- target-i386/translate-copy.c | 2 + target-i386/translate.c | 6 +- target-ppc/cpu.h | 7 + target-sparc/cpu.h | 8 ++ 9 files changed, 260 insertions(+), 130 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 71a300398..8f05e666c 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -681,8 +681,7 @@ extern uint8_t *phys_ram_dirty; #define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */ #define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ -/* NOTE: vaddr is only used internally. Never use it except if you know what you do */ -typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value, uint32_t vaddr); +typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(uint32_t addr); void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, diff --git a/exec.c b/exec.c index 6136bf7b9..45572e9b0 100644 --- a/exec.c +++ b/exec.c @@ -168,7 +168,6 @@ static inline PageDesc *page_find(unsigned int index) #if !defined(CONFIG_USER_ONLY) static void tlb_protect_code(CPUState *env, uint32_t addr); -static void tlb_unprotect_code(CPUState *env, uint32_t addr); static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr); static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) @@ -533,30 +532,78 @@ static void build_page_bitmap(PageDesc *p) } } +#ifdef TARGET_HAS_PRECISE_SMC + +static void tb_gen_code(CPUState *env, + target_ulong pc, target_ulong cs_base, int flags, + int cflags) +{ + TranslationBlock *tb; + uint8_t *tc_ptr; + target_ulong phys_pc, phys_page2, virt_page2; + int code_gen_size; + + phys_pc = get_phys_addr_code(env, (unsigned long)pc); + tb = tb_alloc((unsigned long)pc); + if (!tb) { + /* flush must be done */ + tb_flush(env); + /* cannot fail at this point */ + tb = tb_alloc((unsigned long)pc); + } + tc_ptr = code_gen_ptr; + tb->tc_ptr = tc_ptr; + tb->cs_base = cs_base; + tb->flags = flags; + tb->cflags = cflags; + 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 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK; + phys_page2 = -1; + if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) { + phys_page2 = get_phys_addr_code(env, virt_page2); + } + tb_link_phys(tb, phys_pc, phys_page2); +} +#endif + /* invalidate all TBs which intersect with the target physical page starting in range [start;end[. NOTE: start and end must refer to - the same physical page. 'vaddr' is a virtual address referencing - the physical page of code. It is only used an a hint if there is no - code left. */ -static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, - target_ulong vaddr) -{ - int n; + the same physical page. 'is_cpu_write_access' should be true if called + from a real cpu write access: the virtual CPU will exit the current + TB if code is modified inside this TB. */ +void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, + int is_cpu_write_access) +{ + int n, current_tb_modified, current_tb_not_found, current_flags; +#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY) + CPUState *env = cpu_single_env; +#endif PageDesc *p; - TranslationBlock *tb, *tb_next; + TranslationBlock *tb, *tb_next, *current_tb; target_ulong tb_start, tb_end; + target_ulong current_pc, current_cs_base; p = page_find(start >> TARGET_PAGE_BITS); if (!p) return; if (!p->code_bitmap && - ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) { + ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD && + is_cpu_write_access) { /* build code bitmap */ build_page_bitmap(p); } /* we remove all the TBs in the range [start, end[ */ /* XXX: see if in some cases it could be faster to invalidate all the code */ + current_tb_not_found = is_cpu_write_access; + current_tb_modified = 0; + current_tb = NULL; /* avoid warning */ + current_pc = 0; /* avoid warning */ + current_cs_base = 0; /* avoid warning */ + current_flags = 0; /* avoid warning */ tb = p->first_tb; while (tb != NULL) { n = (long)tb & 3; @@ -573,6 +620,36 @@ static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); } if (!(tb_end <= start || tb_start >= end)) { +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_not_found) { + current_tb_not_found = 0; + current_tb = NULL; + if (env->mem_write_pc) { + /* now we have a real cpu fault */ + current_tb = tb_find_pc(env->mem_write_pc); + } + } + if (current_tb == tb && + !(current_tb->cflags & CF_SINGLE_INSN)) { + /* If we are modifying the current TB, we must stop + its execution. We could be more precise by checking + that the modification is after the current PC, but it + would require a specialized function to partially + restore the CPU state */ + + current_tb_modified = 1; + cpu_restore_state(current_tb, env, + env->mem_write_pc, NULL); +#if defined(TARGET_I386) + current_flags = env->hflags; + current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); + current_cs_base = (target_ulong)env->segs[R_CS].base; + current_pc = current_cs_base + env->eip; +#else +#error unsupported CPU +#endif + } +#endif /* TARGET_HAS_PRECISE_SMC */ tb_phys_invalidate(tb, -1); } tb = tb_next; @@ -581,13 +658,25 @@ static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, /* if no code remaining, no need to continue to use slow writes */ if (!p->first_tb) { invalidate_page_bitmap(p); - tlb_unprotect_code_phys(cpu_single_env, start, vaddr); + if (is_cpu_write_access) { + tlb_unprotect_code_phys(env, start, env->mem_write_vaddr); + } + } +#endif +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_modified) { + /* we generate a block containing just the instruction + modifying the memory. It will ensure that it cannot modify + itself */ + tb_gen_code(env, current_pc, current_cs_base, current_flags, + CF_SINGLE_INSN); + cpu_resume_from_signal(env, NULL); } #endif } /* len must be <= 8 and start must be a multiple of len */ -static inline void tb_invalidate_phys_page_fast(target_ulong start, int len, target_ulong vaddr) +static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) { PageDesc *p; int offset, b; @@ -608,77 +697,75 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len, tar goto do_invalidate; } else { do_invalidate: - tb_invalidate_phys_page_range(start, start + len, vaddr); + tb_invalidate_phys_page_range(start, start + len, 1); } } -/* invalidate all TBs which intersect with the target virtual page - starting in range [start;end[. This function is usually used when - the target processor flushes its I-cache. NOTE: start and end must - refer to the same physical page */ -void tb_invalidate_page_range(target_ulong start, target_ulong end) -{ - int n; - PageDesc *p; - TranslationBlock *tb, *tb_next; - target_ulong pc; - target_ulong phys_start; - -#if !defined(CONFIG_USER_ONLY) - { - VirtPageDesc *vp; - vp = virt_page_find(start >> TARGET_PAGE_BITS); - if (!vp) - return; - if (vp->valid_tag != virt_valid_tag) - return; - phys_start = vp->phys_addr + (start & ~TARGET_PAGE_MASK); - } -#else - phys_start = start; -#endif - p = page_find(phys_start >> TARGET_PAGE_BITS); - if (!p) - return; - /* we remove all the TBs in the range [start, end[ */ - /* XXX: see if in some cases it could be faster to invalidate all the code */ - tb = p->first_tb; - while (tb != NULL) { - n = (long)tb & 3; - tb = (TranslationBlock *)((long)tb & ~3); - tb_next = tb->page_next[n]; - pc = tb->pc; - if (!((pc + tb->size) <= start || pc >= end)) { - tb_phys_invalidate(tb, -1); - } - tb = tb_next; - } -#if !defined(CONFIG_USER_ONLY) - /* if no code remaining, no need to continue to use slow writes */ - if (!p->first_tb) - tlb_unprotect_code(cpu_single_env, start); -#endif -} - #if !defined(CONFIG_SOFTMMU) -static void tb_invalidate_phys_page(target_ulong addr) +static void tb_invalidate_phys_page(target_ulong addr, + unsigned long pc, void *puc) { - int n; + int n, current_flags, current_tb_modified; + target_ulong current_pc, current_cs_base; PageDesc *p; - TranslationBlock *tb; + TranslationBlock *tb, *current_tb; +#ifdef TARGET_HAS_PRECISE_SMC + CPUState *env = cpu_single_env; +#endif addr &= TARGET_PAGE_MASK; p = page_find(addr >> TARGET_PAGE_BITS); if (!p) return; tb = p->first_tb; + current_tb_modified = 0; + current_tb = NULL; + current_pc = 0; /* avoid warning */ + current_cs_base = 0; /* avoid warning */ + current_flags = 0; /* avoid warning */ +#ifdef TARGET_HAS_PRECISE_SMC + if (tb && pc != 0) { + current_tb = tb_find_pc(pc); + } +#endif while (tb != NULL) { n = (long)tb & 3; tb = (TranslationBlock *)((long)tb & ~3); +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb == tb && + !(current_tb->cflags & CF_SINGLE_INSN)) { + /* If we are modifying the current TB, we must stop + its execution. We could be more precise by checking + that the modification is after the current PC, but it + would require a specialized function to partially + restore the CPU state */ + + current_tb_modified = 1; + cpu_restore_state(current_tb, env, pc, puc); +#if defined(TARGET_I386) + current_flags = env->hflags; + current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); + current_cs_base = (target_ulong)env->segs[R_CS].base; + current_pc = current_cs_base + env->eip; +#else +#error unsupported CPU +#endif + } +#endif /* TARGET_HAS_PRECISE_SMC */ tb_phys_invalidate(tb, addr); tb = tb->page_next[n]; } p->first_tb = NULL; +#ifdef TARGET_HAS_PRECISE_SMC + if (current_tb_modified) { + /* we generate a block containing just the instruction + modifying the memory. It will ensure that it cannot modify + itself */ + tb_gen_code(env, current_pc, current_cs_base, current_flags, + CF_SINGLE_INSN); + cpu_resume_from_signal(env, puc); + } +#endif } #endif @@ -696,6 +783,8 @@ static inline void tb_alloc_page(TranslationBlock *tb, p->first_tb = (TranslationBlock *)((long)tb | n); invalidate_page_bitmap(p); +#ifdef TARGET_HAS_SMC + #if defined(CONFIG_USER_ONLY) if (p->flags & PAGE_WRITE) { unsigned long host_start, host_end, addr; @@ -727,6 +816,8 @@ static inline void tb_alloc_page(TranslationBlock *tb, tlb_protect_code(cpu_single_env, virt_addr); } #endif + +#endif /* TARGET_HAS_SMC */ } /* Allocate a new translation block. Flush the translation buffer if @@ -910,13 +1001,21 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } +static void breakpoint_invalidate(CPUState *env, target_ulong pc) +{ + target_ulong phys_addr; + + phys_addr = cpu_get_phys_page_debug(env, pc); + tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0); +} + /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) { #if defined(TARGET_I386) || defined(TARGET_PPC) int i; - + for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) return 0; @@ -925,7 +1024,8 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) if (env->nb_breakpoints >= MAX_BREAKPOINTS) return -1; env->breakpoints[env->nb_breakpoints++] = pc; - tb_invalidate_page_range(pc, pc + 1); + + breakpoint_invalidate(env, pc); return 0; #else return -1; @@ -946,7 +1046,8 @@ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) memmove(&env->breakpoints[i], &env->breakpoints[i + 1], (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); env->nb_breakpoints--; - tb_invalidate_page_range(pc, pc + 1); + + breakpoint_invalidate(env, pc); return 0; #else return -1; @@ -1197,27 +1298,6 @@ static void tlb_protect_code(CPUState *env, uint32_t addr) #endif } -static inline void tlb_unprotect_code1(CPUTLBEntry *tlb_entry, uint32_t addr) -{ - if (addr == (tlb_entry->address & - (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && - (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE) { - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; - } -} - -/* update the TLB so that writes in virtual page 'addr' are no longer - tested self modifying code */ -static void tlb_unprotect_code(CPUState *env, uint32_t addr) -{ - int i; - - addr &= TARGET_PAGE_MASK; - i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_unprotect_code1(&env->tlb_write[0][i], addr); - tlb_unprotect_code1(&env->tlb_write[1][i], addr); -} - static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, uint32_t phys_addr) { @@ -1387,12 +1467,18 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, /* ROM: access is ignored (same as unassigned) */ env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM; env->tlb_write[is_user][index].addend = addend; - } else if (first_tb) { + } else + /* XXX: the PowerPC code seems not ready to handle + self modifying code with DCBI */ +#if defined(TARGET_HAS_SMC) || 1 + if (first_tb) { /* if code is present, we use a specific memory handler. It works only for physical memory access */ env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE; env->tlb_write[is_user][index].addend = addend; - } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + } else +#endif + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd)) { env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY; env->tlb_write[is_user][index].addend = addend; @@ -1420,7 +1506,9 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, } else { if (prot & PROT_WRITE) { if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || +#if defined(TARGET_HAS_SMC) || 1 first_tb || +#endif ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd))) { /* ROM: we do as if code was inside */ @@ -1450,7 +1538,7 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, /* called from signal handler: invalidate the code and unprotect the page. Return TRUE if the fault was succesfully handled. */ -int page_unprotect(unsigned long addr) +int page_unprotect(unsigned long addr, unsigned long pc, void *puc) { #if !defined(CONFIG_SOFTMMU) VirtPageDesc *vp; @@ -1476,13 +1564,13 @@ int page_unprotect(unsigned long addr) printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", addr, vp->phys_addr, vp->prot); #endif - /* set the dirty bit */ - phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1; - /* flush the code inside */ - tb_invalidate_phys_page(vp->phys_addr); if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0) cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n", (unsigned long)addr, vp->prot); + /* set the dirty bit */ + phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1; + /* flush the code inside */ + tb_invalidate_phys_page(vp->phys_addr, pc, puc); return 1; #else return 0; @@ -1582,7 +1670,7 @@ void page_set_flags(unsigned long start, unsigned long end, int flags) if (!(p->flags & PAGE_WRITE) && (flags & PAGE_WRITE) && p->first_tb) { - tb_invalidate_phys_page(addr); + tb_invalidate_phys_page(addr, 0, NULL); } p->flags = flags; } @@ -1591,7 +1679,7 @@ void page_set_flags(unsigned long start, unsigned long end, int flags) /* called from signal handler: invalidate the code and unprotect the page. Return TRUE if the fault was succesfully handled. */ -int page_unprotect(unsigned long address) +int page_unprotect(unsigned long address, unsigned long pc, void *puc) { unsigned int page_index, prot, pindex; PageDesc *p, *p1; @@ -1619,7 +1707,7 @@ int page_unprotect(unsigned long address) p1[pindex].flags |= PAGE_WRITE; /* and since the content will be modified, we must invalidate the corresponding translated code. */ - tb_invalidate_phys_page(address); + tb_invalidate_phys_page(address, pc, puc); #ifdef DEBUG_TB_CHECK tb_invalidate_check(address); #endif @@ -1639,14 +1727,13 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size) start &= TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { - page_unprotect(addr); + page_unprotect(addr, 0, NULL); } } static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) { } - #endif /* defined(CONFIG_USER_ONLY) */ /* register physical memory. 'size' must be a multiple of the target @@ -1672,7 +1759,7 @@ static uint32_t unassigned_mem_readb(uint32_t addr) return 0; } -static void unassigned_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) +static void unassigned_mem_writeb(uint32_t addr, uint32_t val) { } @@ -1691,37 +1778,37 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = { /* self modifying code support in soft mmu mode : writing to a page containing code comes to these functions */ -static void code_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) +static void code_mem_writeb(uint32_t addr, uint32_t val) { unsigned long phys_addr; phys_addr = addr - (long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(phys_addr, 1, vaddr); + tb_invalidate_phys_page_fast(phys_addr, 1); #endif stb_raw((uint8_t *)addr, val); phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } -static void code_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr) +static void code_mem_writew(uint32_t addr, uint32_t val) { unsigned long phys_addr; phys_addr = addr - (long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(phys_addr, 2, vaddr); + tb_invalidate_phys_page_fast(phys_addr, 2); #endif stw_raw((uint8_t *)addr, val); phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } -static void code_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr) +static void code_mem_writel(uint32_t addr, uint32_t val) { unsigned long phys_addr; phys_addr = addr - (long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(phys_addr, 4, vaddr); + tb_invalidate_phys_page_fast(phys_addr, 4); #endif stl_raw((uint8_t *)addr, val); phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; @@ -1739,22 +1826,22 @@ static CPUWriteMemoryFunc *code_mem_write[3] = { code_mem_writel, }; -static void notdirty_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) +static void notdirty_mem_writeb(uint32_t addr, uint32_t val) { stb_raw((uint8_t *)addr, val); - tlb_set_dirty(addr, vaddr); + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static void notdirty_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr) +static void notdirty_mem_writew(uint32_t addr, uint32_t val) { stw_raw((uint8_t *)addr, val); - tlb_set_dirty(addr, vaddr); + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static void notdirty_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr) +static void notdirty_mem_writel(uint32_t addr, uint32_t val) { stl_raw((uint8_t *)addr, val); - tlb_set_dirty(addr, vaddr); + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } static CPUWriteMemoryFunc *notdirty_mem_write[3] = { @@ -1861,17 +1948,17 @@ void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ val = ldl_raw(buf); - io_mem_write[io_index][2](addr, val, 0); + io_mem_write[io_index][2](addr, val); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { /* 16 bit read access */ val = lduw_raw(buf); - io_mem_write[io_index][1](addr, val, 0); + io_mem_write[io_index][1](addr, val); l = 2; } else { /* 8 bit access */ val = ldub_raw(buf); - io_mem_write[io_index][0](addr, val, 0); + io_mem_write[io_index][0](addr, val); l = 1; } } else { diff --git a/softmmu_template.h b/softmmu_template.h index 2203c5a5c..413c5997b 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -70,20 +70,23 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, static inline void glue(io_write, SUFFIX)(unsigned long physaddr, DATA_TYPE val, - unsigned long tlb_addr) + unsigned long tlb_addr, + void *retaddr) { int index; index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + env->mem_write_vaddr = tlb_addr; + env->mem_write_pc = (unsigned long)retaddr; #if SHIFT <= 2 - io_mem_write[index][SHIFT](physaddr, val, tlb_addr); + io_mem_write[index][SHIFT](physaddr, val); #else #ifdef TARGET_WORDS_BIGENDIAN - io_mem_write[index][2](physaddr, val >> 32, tlb_addr); - io_mem_write[index][2](physaddr + 4, val, tlb_addr); + io_mem_write[index][2](physaddr, val >> 32); + io_mem_write[index][2](physaddr + 4, val); #else - io_mem_write[index][2](physaddr, val, tlb_addr); - io_mem_write[index][2](physaddr + 4, val >> 32, tlb_addr); + io_mem_write[index][2](physaddr, val); + io_mem_write[index][2](physaddr + 4, val >> 32); #endif #endif /* SHIFT > 2 */ } @@ -193,7 +196,8 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; - glue(io_write, SUFFIX)(physaddr, val, tlb_addr); + retaddr = GETPC(); + glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr); } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: retaddr = GETPC(); @@ -229,7 +233,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; - glue(io_write, SUFFIX)(physaddr, val, tlb_addr); + glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr); } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* XXX: not efficient, but simple */ diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 174f60db6..df25c5791 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -43,6 +43,13 @@ typedef struct CPUARMState { struct TranslationBlock *current_tb; int user_mode_only; + /* 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 */ + unsigned long mem_write_vaddr; /* target virtual addr at which the + memory was written */ /* user data */ void *opaque; } CPUARMState; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index daa2133f8..6b2a89bb9 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -22,6 +22,12 @@ #define TARGET_LONG_BITS 32 +/* target supports implicit self modifying code */ +#define TARGET_HAS_SMC +/* support for self modifying code even if the modified instruction is + close to the modifying instruction */ +#define TARGET_HAS_PRECISE_SMC + #include "cpu-defs.h" #if defined(__i386__) && !defined(CONFIG_SOFTMMU) @@ -331,8 +337,16 @@ typedef struct CPUX86State { int interrupt_request; int user_mode_only; /* user mode only simulation */ - /* soft mmu support */ uint32_t a20_mask; + + /* 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 */ + unsigned long mem_write_vaddr; /* target virtual addr at which the + memory was written */ /* 0 = kernel, 1 = user */ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; @@ -358,7 +372,7 @@ int cpu_x86_inl(CPUX86State *env, int addr); CPUX86State *cpu_x86_init(void); int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); -int cpu_x86_get_pic_interrupt(CPUX86State *s); +int cpu_get_pic_interrupt(CPUX86State *s); /* this function must always be used to load data in the segment cache: it synchronizes the hflags with the segment cache values */ diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index 500475a74..e6f9198ab 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -1189,6 +1189,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, return -1; if (!(flags & HF_SS32_MASK)) return -1; + if (tb->cflags & CF_SINGLE_INSN) + return -1; gen_code_end = gen_code_ptr + GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE; dc->gen_code_ptr = gen_code_ptr; diff --git a/target-i386/translate.c b/target-i386/translate.c index 4bddba56a..a1a4c633d 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4491,7 +4491,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, DisasContext dc1, *dc = &dc1; uint8_t *pc_ptr; uint16_t *gen_opc_end; - int flags, j, lj; + int flags, j, lj, cflags; uint8_t *pc_start; uint8_t *cs_base; @@ -4499,6 +4499,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, pc_start = (uint8_t *)tb->pc; cs_base = (uint8_t *)tb->cs_base; flags = tb->flags; + cflags = tb->cflags; dc->pe = (flags >> HF_PE_SHIFT) & 1; dc->code32 = (flags >> HF_CS32_SHIFT) & 1; @@ -4573,7 +4574,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, the flag and abort the translation to give the irqs a change to be happen */ if (dc->tf || dc->singlestep_enabled || - (flags & HF_INHIBIT_IRQ_MASK)) { + (flags & HF_INHIBIT_IRQ_MASK) || + (cflags & CF_SINGLE_INSN)) { gen_op_jmp_im(pc_ptr - dc->cs_base); gen_eob(dc); break; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6cd08950f..e6cb0946d 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -164,6 +164,13 @@ typedef struct CPUPPCState { int user_mode_only; /* user mode only simulation */ 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 */ + unsigned long mem_write_vaddr; /* target virtual addr at which the + memory was written */ /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index af5ecb508..e86fae9e7 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -43,6 +43,14 @@ typedef struct CPUSPARCState { void *opaque; /* NOTE: we allow 8 more registers to handle wrapping */ uint32_t regbase[NWINDOWS * 16 + 8]; + + /* 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 */ + unsigned long mem_write_vaddr; /* target virtual addr at which the + memory was written */ } CPUSPARCState; CPUSPARCState *cpu_sparc_init(void); -- cgit v1.2.3 From 1b8eb456ebd74aefeca5eb5204e85582b59f581e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 17:58:25 +0000 Subject: avoid error if too many sectors in non LBA mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@746 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index f5efa8eb1..0bef2888e 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -517,7 +517,7 @@ static void ide_set_sector(IDEState *s, int64_t sector_num) r = sector_num % (s->heads * s->sectors); s->hcyl = cyl >> 8; s->lcyl = cyl; - s->select = (s->select & 0xf0) | (r / s->sectors); + s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f); s->sector = (r % s->sectors) + 1; } } -- cgit v1.2.3 From 5467a722943adaa3d11e97656cf789586e31ee93 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 17:59:00 +0000 Subject: disabled S3 VGA git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@747 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 54 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 3a634a4d5..5a2a73b3c 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -30,7 +30,8 @@ //#define DEBUG_S3 //#define DEBUG_BOCHS_VBE -#define CONFIG_S3VGA +/* S3 VGA is deprecated - another graphic card will be emulated */ +//#define CONFIG_S3VGA #define MSR_COLOR_EMULATION 0x01 #define MSR_PAGE_SELECT 0x20 @@ -335,7 +336,7 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) { VGAState *s = opaque; - int index, v; + int index; /* check port range access depending on color/monochrome mode */ if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || @@ -453,15 +454,21 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case 0x31: /* update start address */ - s->cr[s->cr_index] = val; - v = (val >> 4) & 3; - s->cr[0x69] = (s->cr[69] & ~0x03) | v; + { + int v; + s->cr[s->cr_index] = val; + v = (val >> 4) & 3; + s->cr[0x69] = (s->cr[69] & ~0x03) | v; + } break; case 0x51: /* update start address */ - s->cr[s->cr_index] = val; - v = val & 3; - s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2); + { + int v; + s->cr[s->cr_index] = val; + v = val & 3; + s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2); + } break; #endif default: @@ -716,7 +723,7 @@ static uint32_t vga_mem_readl(uint32_t addr) } /* called for accesses between 0xa0000 and 0xc0000 */ -static void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) +static void vga_mem_writeb(uint32_t addr, uint32_t val) { VGAState *s = &vga_state; int memory_map_mode, plane, write_mode, b, func_select; @@ -844,18 +851,18 @@ static void vga_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr) } } -static void vga_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr) +static void vga_mem_writew(uint32_t addr, uint32_t val) { - vga_mem_writeb(addr, val & 0xff, vaddr); - vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr); + vga_mem_writeb(addr, val & 0xff); + vga_mem_writeb(addr + 1, (val >> 8) & 0xff); } -static void vga_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr) +static void vga_mem_writel(uint32_t addr, uint32_t val) { - vga_mem_writeb(addr, val & 0xff, vaddr); - vga_mem_writeb(addr + 1, (val >> 8) & 0xff, vaddr); - vga_mem_writeb(addr + 2, (val >> 16) & 0xff, vaddr); - vga_mem_writeb(addr + 3, (val >> 24) & 0xff, vaddr); + vga_mem_writeb(addr, val & 0xff); + vga_mem_writeb(addr + 1, (val >> 8) & 0xff); + vga_mem_writeb(addr + 2, (val >> 16) & 0xff); + vga_mem_writeb(addr + 3, (val >> 24) & 0xff); } typedef void vga_draw_glyph8_func(uint8_t *d, int linesize, @@ -992,7 +999,7 @@ static int update_palette256(VGAState *s) static int update_basic_params(VGAState *s) { int full_update; - uint32_t start_addr, line_offset, line_compare, v; + uint32_t start_addr, line_offset, line_compare; full_update = 0; @@ -1006,10 +1013,13 @@ static int update_basic_params(VGAState *s) /* compute line_offset in bytes */ line_offset = s->cr[0x13]; #ifdef CONFIG_S3VGA - v = (s->cr[0x51] >> 4) & 3; /* S3 extension */ - if (v == 0) - v = (s->cr[0x43] >> 2) & 1; /* S3 extension */ - line_offset |= (v << 8); + { + uinr32_t v; + v = (s->cr[0x51] >> 4) & 3; /* S3 extension */ + if (v == 0) + v = (s->cr[0x43] >> 2) & 1; /* S3 extension */ + line_offset |= (v << 8); + } #endif line_offset <<= 3; -- cgit v1.2.3 From 6f1f31c069b20611f8df768bd4cc484a49624d62 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 18:00:45 +0000 Subject: ARM cache flush support (untested) - '-d' option fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@748 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/syscall.h | 2 ++ linux-user/main.c | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index 34153c998..0ced33ee5 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -26,3 +26,5 @@ struct target_pt_regs { #define ARM_ORIG_r0 uregs[17] #define ARM_SYSCALL_BASE 0x900000 + +#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) diff --git a/linux-user/main.c b/linux-user/main.c index 601829230..2af888fdd 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -246,6 +246,27 @@ void cpu_loop(CPUX86State *env) #ifdef TARGET_ARM +/* XXX: find a better solution */ +extern void tb_invalidate_page_range(target_ulong start, target_ulong end); + +static void arm_cache_flush(target_ulong start, target_ulong last) +{ + target_ulong addr, last1; + + if (last < start) + return; + addr = start; + for(;;) { + last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1; + if (last1 > last) + last1 = last; + tb_invalidate_page_range(addr, last1 + 1); + if (last1 == last) + break; + addr = last1 + 1; + } +} + void cpu_loop(CPUARMState *env) { int trapnr; @@ -281,7 +302,9 @@ void cpu_loop(CPUARMState *env) /* system call */ insn = ldl((void *)(env->regs[15] - 4)); n = insn & 0xffffff; - if (n >= ARM_SYSCALL_BASE) { + if (n == ARM_NR_cacheflush) { + arm_cache_flush(env->regs[0], env->regs[1]); + } else if (n >= ARM_SYSCALL_BASE) { /* linux syscall */ n -= ARM_SYSCALL_BASE; env->regs[0] = do_syscall(env, @@ -792,7 +815,7 @@ void cpu_loop(CPUPPCState *env) void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: qemu-" TARGET_ARCH " [-h] [-d] [-L path] [-s size] program [arguments...]\n" + "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" "-h print this help\n" @@ -803,7 +826,7 @@ void usage(void) #ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n" #endif - "-d activate log (logfile=%s)\n" + "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n", TARGET_ARCH, interp_prefix, @@ -850,8 +873,12 @@ int main(int argc, char **argv) } else if (!strcmp(r, "d")) { int mask; CPULogItem *item; + + if (optind >= argc) + break; - mask = cpu_str_to_log_mask(optarg); + r = argv[optind++]; + mask = cpu_str_to_log_mask(r); if (!mask) { printf("Log items (comma separated):\n"); for(item = cpu_log_items; item->mask != 0; item++) { -- cgit v1.2.3 From ba91cd80d5a267c3a25770efc4590bf807c56376 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 18:03:53 +0000 Subject: fixed very unlikely irq bug git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@749 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/hw/i8259.c b/hw/i8259.c index adc9cedff..5d20e04db 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -46,8 +46,8 @@ typedef struct PicState { } PicState; /* 0 is master pic, 1 is slave pic */ -PicState pics[2]; -int pic_irq_requested; +static PicState pics[2]; +static int pic_irq_requested; /* set irq level. If an edge is detected, then the IRR is set to 1 */ static inline void pic_set_irq1(PicState *s, int irq, int level) @@ -198,6 +198,7 @@ int cpu_get_pic_interrupt(CPUState *env) intno = pics[0].irq_base + irq; } pic_intack(&pics[0], irq); + pic_update_irq(); return intno; } @@ -408,6 +409,19 @@ static void pic_init1(int io_addr, PicState *s) register_savevm("i8259", io_addr, 1, pic_save, pic_load, s); } +void pic_info(void) +{ + int i; + PicState *s; + + for(i=0;i<2;i++) { + s = &pics[i]; + term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d\n", + i, s->irr, s->imr, s->isr, s->priority_add, s->irq_base, s->read_reg_select); + } +} + + void pic_init(void) { pic_init1(0x20, &pics[0]); -- cgit v1.2.3 From 4c27ba27c5dd810fdcfbe82e3998a174a6e793f2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 18:05:08 +0000 Subject: added 'info pic' - added 16/32 bit x86 instruction dump git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@750 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/monitor.c b/monitor.c index 8a00ee9bc..8b03a7e1a 100644 --- a/monitor.c +++ b/monitor.c @@ -350,10 +350,17 @@ static void memory_dump(int count, int format, int wsize, int flags; flags = 0; #ifdef TARGET_I386 - /* we use the current CS size */ - if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK)) + if (wsize == 2) { flags = 1; -#endif + } else if (wsize == 4) { + flags = 0; + } else { + /* as default we use the current CS size */ + flags = 0; + if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK)) + flags = 1; + } +#endif monitor_disas(addr, count, is_physical, flags); return; } @@ -516,6 +523,8 @@ static term_cmd_t info_cmds[] = { "", "show the cpu registers" }, { "history", "", do_info_history, "", "show the command line history", }, + { "pic", "", pic_info, + "", "show i8259 (PIC) state", }, { NULL, NULL, }, }; @@ -1047,16 +1056,23 @@ static void term_handle_command(const char *cmdline) term_printf("invalid char in format: '%c'\n", *p); goto fail; } - if (size < 0) - size = default_fmt_size; if (format < 0) format = default_fmt_format; + if (format != 'i') { + /* for 'i', not specifying a size gives -1 as size */ + if (size < 0) + size = default_fmt_size; + } default_fmt_size = size; default_fmt_format = format; } else { count = 1; format = default_fmt_format; - size = default_fmt_size; + if (format != 'i') { + size = default_fmt_size; + } else { + size = -1; + } } if (nb_args + 3 > MAX_ARGS) goto error_args; -- cgit v1.2.3 From 57206fd42a0ce94525686b0ea18d0e23d58a89e3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 18:54:52 +0000 Subject: more register values in monitor git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@751 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/monitor.c b/monitor.c index 8b03a7e1a..f5cde7491 100644 --- a/monitor.c +++ b/monitor.c @@ -539,6 +539,13 @@ typedef struct MonitorDef { int (*get_value)(struct MonitorDef *md); } MonitorDef; +#if defined(TARGET_I386) +static int monitor_get_pc (struct MonitorDef *md) +{ + return cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base; +} +#endif + #if defined(TARGET_PPC) static int monitor_get_ccr (struct MonitorDef *md) { @@ -582,6 +589,12 @@ static int monitor_get_xer (struct MonitorDef *md) static MonitorDef monitor_defs[] = { #ifdef TARGET_I386 + +#define SEG(name, seg) \ + { name, offsetof(CPUState, segs[seg].selector) },\ + { name ".base", offsetof(CPUState, segs[seg].base) },\ + { name ".limit", offsetof(CPUState, segs[seg].limit) }, + { "eax", offsetof(CPUState, regs[0]) }, { "ecx", offsetof(CPUState, regs[1]) }, { "edx", offsetof(CPUState, regs[2]) }, @@ -591,7 +604,13 @@ static MonitorDef monitor_defs[] = { { "esi", offsetof(CPUState, regs[6]) }, { "esi", offsetof(CPUState, regs[7]) }, { "eflags", offsetof(CPUState, eflags) }, - { "eip|pc", offsetof(CPUState, eip) }, + { "eip", offsetof(CPUState, eip) }, + SEG("cs", R_CS) + SEG("ds", R_DS) + SEG("es", R_ES) + SEG("fs", R_FS) + SEG("gs", R_GS) + { "pc", 0, monitor_get_pc, }, #elif defined(TARGET_PPC) { "r0", offsetof(CPUState, gpr[0]) }, { "r1", offsetof(CPUState, gpr[1]) }, @@ -625,6 +644,7 @@ static MonitorDef monitor_defs[] = { { "r29", offsetof(CPUState, gpr[29]) }, { "r30", offsetof(CPUState, gpr[30]) }, { "r31", offsetof(CPUState, gpr[31]) }, + { "nip|pc", offsetof(CPUState, nip) }, { "lr", offsetof(CPUState, lr) }, { "ctr", offsetof(CPUState, ctr) }, { "decr", offsetof(CPUState, decr) }, @@ -724,7 +744,7 @@ static int expr_unary(void) while ((*pch >= 'a' && *pch <= 'z') || (*pch >= 'A' && *pch <= 'Z') || (*pch >= '0' && *pch <= '9') || - *pch == '_') { + *pch == '_' || *pch == '.') { if ((q - buf) < sizeof(buf) - 1) *q++ = *pch; pch++; -- cgit v1.2.3 From 1115dde7194fc1c383e2b374697485ec20269cce Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 18:57:49 +0000 Subject: x86-64 port (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@752 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/vl.c b/vl.c index 18bdd0d54..8206706f6 100644 --- a/vl.c +++ b/vl.c @@ -362,6 +362,19 @@ int64_t cpu_get_real_ticks(void) return val; } +#elif defined(__x86_64__) + +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; +} + #else #error unsupported CPU #endif -- cgit v1.2.3 From 75dfaa1e64bcaf2f26e280e308a73b146478120c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 19:04:19 +0000 Subject: x86-64 port (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@753 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile.target b/Makefile.target index b68183b8e..84f9df8a5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -56,6 +56,12 @@ PROGS+=$(QEMU_SYSTEM) endif endif # ARCH = i386 +ifeq ($(ARCH), amd64) +ifdef CONFIG_SOFTMMU +PROGS+=$(QEMU_SYSTEM) +endif +endif # ARCH = amd64 + endif # TARGET_ARCH = ppc endif # !CONFIG_USER_ONLY -- cgit v1.2.3 From 046d6672e2238342b1c174e45c41005be78285a7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 21:15:35 +0000 Subject: avoid unneeded casts git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@754 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 7 +++--- target-ppc/translate.c | 60 +++++++++++++++++++++++++------------------------- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index e4bc0545b..ccfd2ea92 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -178,8 +178,8 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, int ret = -1; /* No entry found */ for (i = 0; i < 8; i++) { - pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8))); - pte1 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4)); + pte0 = ldl_raw(phys_ram_base + base + (i * 8)); + pte1 = ldl_raw(phys_ram_base + base + (i * 8) + 4); #if defined (DEBUG_MMU) if (loglevel > 0) { fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " @@ -269,8 +269,7 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, } } if (store) { - stl_raw((void *)((uint32_t)phys_ram_base + base + (good * 8) + 4), - keep); + stl_raw(phys_ram_base + base + (good * 8) + 4, keep); } } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index bd0dc67d4..35bd660d4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -127,7 +127,7 @@ static uint8_t spr_access[1024 / 2]; /* internal defines */ typedef struct DisasContext { struct TranslationBlock *tb; - uint32_t *nip; + uint32_t nip; uint32_t opcode; uint32_t exception; /* Time base offset */ @@ -1509,13 +1509,13 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) gen_op_update_tb(ctx->tb_offset); gen_op_update_decr(ctx->decr_offset); - gen_op_process_exceptions((uint32_t)ctx->nip - 4); + gen_op_process_exceptions(ctx->nip - 4); if (AA(ctx->opcode) == 0) - target = (uint32_t)ctx->nip + li - 4; + target = ctx->nip + li - 4; else target = li; if (LK(ctx->opcode)) { - gen_op_setlr((uint32_t)ctx->nip); + gen_op_setlr(ctx->nip); } gen_op_b((long)ctx->tb, target); ctx->exception = EXCP_BRANCH; @@ -1535,7 +1535,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_op_update_tb(ctx->tb_offset); gen_op_update_decr(ctx->decr_offset); - gen_op_process_exceptions((uint32_t)ctx->nip - 4); + gen_op_process_exceptions(ctx->nip - 4); if ((bo & 0x4) == 0) gen_op_dec_ctr(); @@ -1543,7 +1543,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) case BCOND_IM: li = s_ext16(BD(ctx->opcode)); if (AA(ctx->opcode) == 0) { - target = (uint32_t)ctx->nip + li - 4; + target = ctx->nip + li - 4; } else { target = li; } @@ -1557,7 +1557,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) break; } if (LK(ctx->opcode)) { - gen_op_setlr((uint32_t)ctx->nip); + gen_op_setlr(ctx->nip); } if (bo & 0x10) { /* No CR condition */ @@ -1612,9 +1612,9 @@ static inline void gen_bcond(DisasContext *ctx, int type) } } if (type == BCOND_IM) { - gen_op_btest((long)ctx->tb, target, (uint32_t)ctx->nip); + gen_op_btest((long)ctx->tb, target, ctx->nip); } else { - gen_op_btest_T1((uint32_t)ctx->nip); + gen_op_btest_T1(ctx->nip); } no_test: ctx->exception = EXCP_BRANCH; @@ -2989,7 +2989,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; - ctx.nip = (uint32_t *)pc_start; + ctx.nip = pc_start; ctx.tb_offset = 0; ctx.decr_offset = 0; ctx.tb = tb; @@ -3015,18 +3015,18 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, lj++; while (lj < j) gen_opc_instr_start[lj++] = 0; - gen_opc_pc[lj] = (uint32_t)ctx.nip; + gen_opc_pc[lj] = ctx.nip; gen_opc_instr_start[lj] = 1; } } #if defined DEBUG_DISAS if (loglevel > 0) { fprintf(logfile, "----------------\n"); - fprintf(logfile, "nip=%p super=%d ir=%d\n", + fprintf(logfile, "nip=%08x super=%d ir=%d\n", ctx.nip, 1 - msr_pr, msr_ir); } #endif - ctx.opcode = ldl_code(ctx.nip); + ctx.opcode = ldl_code((void *)ctx.nip); #if defined DEBUG_DISAS if (loglevel > 0) { fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", @@ -3034,7 +3034,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, opc3(ctx.opcode)); } #endif - ctx.nip++; + ctx.nip += 4; ctx.tb_offset++; /* Check decrementer exception */ if (++ctx.decr_offset == env->decr + 1) @@ -3054,28 +3054,28 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (loglevel > 0) { if (handler->handler == &gen_invalid) { fprintf(logfile, "invalid/unsupported opcode: " - "%02x -%02x - %02x (%08x) %p\n", + "%02x -%02x - %02x (%08x) 0x%08x\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 1); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } else { fprintf(logfile, "invalid bits: %08x for opcode: " - "%02x -%02x - %02x (0x%08x) (%p)\n", + "%02x -%02x - %02x (0x%08x) (0x%08x)\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), - ctx.opcode, ctx.nip - 1); + ctx.opcode, ctx.nip - 4); } } else { if (handler->handler == &gen_invalid) { printf("invalid/unsupported opcode: " - "%02x -%02x - %02x (%08x) %p\n", + "%02x -%02x - %02x (%08x) 0x%08x\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 1); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } else { printf("invalid bits: %08x for opcode: " - "%02x -%02x - %02x (0x%08x) (%p)\n", + "%02x -%02x - %02x (0x%08x) (0x%08x)\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), - ctx.opcode, ctx.nip - 1); + ctx.opcode, ctx.nip - 4); } } (*gen_invalid)(&ctx); @@ -3089,9 +3089,9 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, * - rfi, trap or syscall * - first instruction of an exception handler */ - (msr_se && ((uint32_t)ctx.nip < 0x100 || - (uint32_t)ctx.nip > 0xF00 || - ((uint32_t)ctx.nip & 0xFC) != 0x04) && + (msr_se && (ctx.nip < 0x100 || + ctx.nip > 0xF00 || + (ctx.nip & 0xFC) != 0x04) && ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI && ctx.exception != EXCP_TRAP)) { #if !defined(CONFIG_USER_ONLY) @@ -3102,9 +3102,9 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } } /* if we reach a page boundary, stop generation */ - if (((uint32_t)ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { + if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { if (ctx.exception == EXCP_NONE) { - gen_op_b((long)ctx.tb, (uint32_t)ctx.nip); + gen_op_b((long)ctx.tb, ctx.nip); ctx.exception = EXCP_BRANCH; } } @@ -3113,7 +3113,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (ctx.exception != EXCP_BRANCH && ctx.exception != EXCP_RFI) { gen_op_update_tb(ctx.tb_offset); gen_op_update_decr(ctx.decr_offset); - gen_op_process_exceptions((uint32_t)ctx.nip); + gen_op_process_exceptions(ctx.nip); } #if 1 /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump @@ -3136,7 +3136,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } #endif } else { - tb->size = (uint32_t)ctx.nip - pc_start; + tb->size = ctx.nip - pc_start; } env->access_type = ACCESS_INT; #ifdef DEBUG_DISAS @@ -3144,7 +3144,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); cpu_ppc_dump_state(env, logfile, 0); fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); - disas(logfile, (void *)pc_start, (uint32_t)ctx.nip - pc_start, 0, 0); + disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0); fprintf(logfile, "\n"); fprintf(logfile, "OP:\n"); -- cgit v1.2.3 From fbf9eeb34dfd9f9eb805410d90ffbb9ca2c0fbd1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 21:21:33 +0000 Subject: added cpu_resume_from_signal() - irq fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@755 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 72 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 6307e0c16..12e848b13 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -21,6 +21,20 @@ #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 +#include +#endif + int tb_invalidated_flag; //#define DEBUG_EXEC @@ -34,6 +48,28 @@ void cpu_loop_exit(void) } #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); +} + /* main execution loop */ int cpu_exec(CPUState *env1) @@ -190,12 +226,12 @@ int cpu_exec(CPUState *env1) (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); - env->interrupt_request &= ~CPU_INTERRUPT_HARD; /* ensure that no TB jump will be modified as the program flow was changed */ #ifdef __sparc__ @@ -548,6 +584,15 @@ int cpu_exec(CPUState *env1) 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) +{ + target_ulong phys_addr; + phys_addr = get_phys_addr_code(env, start); + tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0); +} + #if defined(TARGET_I386) && defined(CONFIG_USER_ONLY) void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) @@ -594,18 +639,6 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) #if !defined(CONFIG_SOFTMMU) -#undef EAX -#undef ECX -#undef EDX -#undef EBX -#undef ESP -#undef EBP -#undef ESI -#undef EDI -#undef EIP -#include -#include - #if defined(TARGET_I386) /* 'pc' is the host PC at which the exception was raised. 'address' is @@ -626,9 +659,10 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address)) { + if (is_write && page_unprotect(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); @@ -655,8 +689,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } else { /* activate soft MMU for this block */ env->hflags |= HF_SOFTMMU_MASK; - sigprocmask(SIG_SETMASK, old_set, NULL); - cpu_loop_exit(); + cpu_resume_from_signal(env, puc); } /* never comes here */ return 1; @@ -676,7 +709,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, void *puc) { /* XXX: locking issue */ - if (is_write && page_unprotect(address)) { + if (is_write && page_unprotect(address, pc, puc)) { return 1; } return 0; @@ -698,7 +731,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address)) { + if (is_write && page_unprotect(address, pc, puc)) { return 1; } @@ -727,8 +760,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, do_queue_exception_err(env->exception_index, env->error_code); } else { /* activate soft MMU for this block */ - sigprocmask(SIG_SETMASK, old_set, NULL); - cpu_loop_exit(); + cpu_resume_from_signal(env, puc); } /* never comes here */ return 1; -- cgit v1.2.3 From ab6d960ffa1271db6866fc2b27e97e99a73598d2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 21:25:15 +0000 Subject: added target_phys_addr_t git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@756 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cpu-defs.h b/cpu-defs.h index bbdb39009..2e643e6e2 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -29,8 +29,13 @@ #error TARGET_LONG_BITS must be defined before including this header #endif +#ifndef TARGET_PHYS_ADDR_BITS +#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS +#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; @@ -41,6 +46,16 @@ typedef uint64_t target_ulong; #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') */ +#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 + #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define HOST_LONG_BITS 64 #else -- cgit v1.2.3 From 52c00a5f1560525089c17d3277a235fe38c1ca78 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 21:27:03 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@757 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + TODO | 12 +++++------ qemu-doc.texi | 66 ++++++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/Changelog b/Changelog index c2660c12a..17d23015a 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,7 @@ version 0.5.4: - 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: diff --git a/TODO b/TODO index 3d8b0b805..6b9004787 100644 --- a/TODO +++ b/TODO @@ -1,21 +1,20 @@ short term: ---------- +- physical memory cache (reduce qemu-fast address space size to about 32 MB) +- better code fetch (different exception handling + CS.limit support) +- do not resize vga if invalid size. +- avoid looping if only exceptions - handle fast timers + add explicit clocks - OS/2 install bug -- handle Self Modifying Code even if modifying current TB (BE OS 5 install) -- physical memory cache (reduce qemu-fast address space size to about 32 MB) -- better code fetch -- XP security bug - cycle counter for all archs - TLB code protection support for PPC - add sysenter/sysexit and fxsr for L4 pistachio 686 - basic VGA optimizations -- disable SMC handling for ARM/SPARC/PPC +- 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 -- cmos clock update and timers - test ldt limit < 7 ? - tests for each target CPU - fix CCOP optimisation @@ -26,6 +25,7 @@ short term: lower priority: -------------- +- HDD geometry in CMOS (not used except for very old DOS programs) - suppress shift_mem ops - fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) - sysenter/sysexit emulation diff --git a/qemu-doc.texi b/qemu-doc.texi index 1f056065b..57cf8f8d3 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -37,8 +37,11 @@ to ease cross-compilation and cross-debugging. As QEMU requires no host kernel driver to run, it is very safe and easy to use. -For system emulation, only the x86 PC emulator is currently -usable. The PowerPC system emulator is being developped. +For system emulation, the following hardware targets are supported: +@itemize +@item PC (x86 processor) +@item PREP (PowerPC processor) +@end itemize For user emulation, x86, PowerPC, ARM, and SPARC CPUs are supported. @@ -121,13 +124,13 @@ QEMU for Win32. Mac OS X is currently not supported. -@chapter QEMU System emulator invocation +@chapter QEMU PC System emulator invocation @section Introduction @c man begin DESCRIPTION -The QEMU System emulator simulates a complete PC. +The QEMU System emulator simulates a complete PC. In order to meet specific user needs, two versions of QEMU are available: @@ -235,23 +238,28 @@ Network options: @table @option @item -n script -Set network init script [default=/etc/qemu-ifup]. This script is -launched to configure the host network interface (usually tun0) +Set TUN/TAP network init script [default=/etc/qemu-ifup]. This script +is launched to configure the host network interface (usually tun0) corresponding to the virtual NE2000 card. -@item nics n -Simulate @var{n} network interfaces (default=1). - @item -macaddr addr Set the mac address of the first interface (the format is aa:bb:cc:dd:ee:ff in hexa). The mac address is incremented for each new network interface. -@item -tun-fd fd1,... -Assumes @var{fd} talks to tap/tun and use it. Read -@url{http://bellard.org/qemu/tetrinet.html} to have an example of its -use. +@item -tun-fd fd +Assumes @var{fd} talks to a tap/tun host network interface and use +it. Read @url{http://bellard.org/qemu/tetrinet.html} to have an +example of its use. + +@item -user-net +(Experimental) Use the user mode network stack. This is the default if +no tun/tap network init script is found. + +@item -dummy-net +Use the dummy network stack: no packet will be received on the network +cards. @end table @@ -278,6 +286,8 @@ Debug options: Wait gdb connection to port 1234 (@xref{gdb_usage}). @item -p port Change gdb connection port. +@item -S +Do not start CPU at startup (you must type 'c' in the monitor). @item -d Output log in /tmp/qemu.log @end table @@ -413,7 +423,9 @@ can be x (hexa), d (signed decimal), u (unsigned decimal), o (octal), c (char) or i (asm instruction). @item size -can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits) +can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86, +@code{h} or @code{w} can be specified with the @code{i} format to +respectively select 16 or 32 bit code instruction size. @end table @@ -802,6 +814,32 @@ Use @code{set architecture i8086} to dump 16 bit code. Then use @code{x/10i $cs*16+*eip} to dump the code at the PC position. @end enumerate +@chapter QEMU PREP PowerPC System emulator invocation + +Use the executable @file{qemu-system-ppc} to simulate a complete PREP +PowerPC system. + +QEMU emulates the following PREP peripherials: + +@itemize @minus +@item +2 IDE interfaces with hard disk and CD-ROM support +@item +Floppy disk +@item +up to 6 NE2000 network adapters +@item +Serial port +@item +PREP Non Volatile RAM +@end itemize + +You can read the qemu PC system emulation chapter to have more +informations about QEMU usage. + +More information is available at +@url{http://jocelyn.mayer.free.fr/qemu-ppc/}. + @chapter QEMU User space emulator invocation @section Quick Start -- cgit v1.2.3 From 2e12669a4c06c7d26351b0c250db9b1ad72ba76f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 21:28:44 +0000 Subject: consistent use of target_ulong and target_phys_addr_t git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@758 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 23 ++++++++++++----------- exec-all.h | 20 ++++++++++++-------- exec.c | 42 +++++++++++++++++++++--------------------- hw/ppc_prep.c | 32 ++++++++++++++++---------------- hw/vga.c | 12 ++++++------ 5 files changed, 67 insertions(+), 62 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 8f05e666c..77a801c86 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -620,8 +620,8 @@ extern int code_copy_enabled; #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ void cpu_interrupt(CPUState *s, int mask); -int cpu_breakpoint_insert(CPUState *env, uint32_t pc); -int cpu_breakpoint_remove(CPUState *env, uint32_t pc); +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); /* Return the physical page corresponding to a virtual one. Use it @@ -681,24 +681,25 @@ extern uint8_t *phys_ram_dirty; #define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */ #define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ -typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); -typedef uint32_t CPUReadMemoryFunc(uint32_t addr); +typedef void CPUWriteMemoryFunc(target_phys_addr_t addr, uint32_t value); +typedef uint32_t CPUReadMemoryFunc(target_phys_addr_t addr); -void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, - long phys_offset); +void cpu_register_physical_memory(target_phys_addr_t start_addr, + unsigned long size, + unsigned long phys_offset); int cpu_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write); -void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, +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_ulong addr, uint8_t *buf, - int len) +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_ulong addr, const uint8_t *buf, - int len) +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); } diff --git a/exec-all.h b/exec-all.h index 934808f10..20c7d3ba3 100644 --- a/exec-all.h +++ b/exec-all.h @@ -86,13 +86,16 @@ int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb, int cpu_restore_state_copy(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); +void cpu_resume_from_signal(CPUState *env1, void *puc); void cpu_exec_init(void); -int page_unprotect(unsigned long address); +int page_unprotect(unsigned long address, unsigned long pc, void *puc); +void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, + int is_cpu_write_access); void tb_invalidate_page_range(target_ulong start, target_ulong end); -void tlb_flush_page(CPUState *env, uint32_t addr); -void tlb_flush_page_write(CPUState *env, uint32_t addr); +void tlb_flush_page(CPUState *env, target_ulong addr); void tlb_flush(CPUState *env, int flush_global); -int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, +int tlb_set_page(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, int is_user, int is_softmmu); #define CODE_GEN_MAX_SIZE 65536 @@ -146,8 +149,8 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, #endif typedef struct TranslationBlock { - unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ - unsigned long cs_base; /* CS base for this block */ + target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ + target_ulong cs_base; /* CS base for this block */ unsigned int flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ @@ -155,6 +158,7 @@ typedef struct TranslationBlock { #define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */ #define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */ #define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */ +#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */ uint8_t *tc_ptr; /* pointer to the translated code */ struct TranslationBlock *hash_next; /* next matching tb for virtual address */ @@ -206,8 +210,8 @@ extern uint8_t *code_gen_ptr; /* find a translation block in the translation cache. If not found, return NULL and the pointer to the last element of the list in pptb */ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, - unsigned long pc, - unsigned long cs_base, + target_ulong pc, + target_ulong cs_base, unsigned int flags) { TranslationBlock **ptb, *tb; diff --git a/exec.c b/exec.c index 45572e9b0..ae6165ba6 100644 --- a/exec.c +++ b/exec.c @@ -64,7 +64,7 @@ uint8_t *phys_ram_base; uint8_t *phys_ram_dirty; typedef struct PageDesc { - /* offset in memory of the page + io_index in the low 12 bits */ + /* offset in host memory of the page + io_index in the low 12 bits */ unsigned long phys_offset; /* list of TBs intersecting this physical page */ TranslationBlock *first_tb; @@ -1011,7 +1011,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a breakpoint is reached */ -int cpu_breakpoint_insert(CPUState *env, uint32_t pc) +int cpu_breakpoint_insert(CPUState *env, target_ulong pc) { #if defined(TARGET_I386) || defined(TARGET_PPC) int i; @@ -1033,7 +1033,7 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) } /* remove a breakpoint */ -int cpu_breakpoint_remove(CPUState *env, uint32_t pc) +int cpu_breakpoint_remove(CPUState *env, target_ulong pc) { #if defined(TARGET_I386) || defined(TARGET_PPC) int i; @@ -1221,7 +1221,7 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) tlb_entry->address = -1; } -void tlb_flush_page(CPUState *env, uint32_t addr) +void tlb_flush_page(CPUState *env, target_ulong addr) { int i, n; VirtPageDesc *vp; @@ -1415,7 +1415,8 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) is permitted. Return 0 if OK or 2 if the page could not be mapped (can only happen in non SOFTMMU mode for I/O pages or pages conflicting with the host address space). */ -int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, +int tlb_set_page(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, int is_user, int is_softmmu) { PageDesc *p; @@ -1583,15 +1584,12 @@ void tlb_flush(CPUState *env, int flush_global) { } -void tlb_flush_page(CPUState *env, uint32_t addr) +void tlb_flush_page(CPUState *env, target_ulong addr) { } -void tlb_flush_page_write(CPUState *env, uint32_t addr) -{ -} - -int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, +int tlb_set_page(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, int is_user, int is_softmmu) { return 0; @@ -1739,8 +1737,9 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) /* register physical memory. 'size' must be a multiple of the target page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an io memory page */ -void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, - long phys_offset) +void cpu_register_physical_memory(target_phys_addr_t start_addr, + unsigned long size, + unsigned long phys_offset) { unsigned long addr, end_addr; PageDesc *p; @@ -1754,12 +1753,12 @@ void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, } } -static uint32_t unassigned_mem_readb(uint32_t addr) +static uint32_t unassigned_mem_readb(target_phys_addr_t addr) { return 0; } -static void unassigned_mem_writeb(uint32_t addr, uint32_t val) +static void unassigned_mem_writeb(target_phys_addr_t addr, uint32_t val) { } @@ -1778,7 +1777,7 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = { /* self modifying code support in soft mmu mode : writing to a page containing code comes to these functions */ -static void code_mem_writeb(uint32_t addr, uint32_t val) +static void code_mem_writeb(target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; @@ -1790,7 +1789,7 @@ static void code_mem_writeb(uint32_t addr, uint32_t val) phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } -static void code_mem_writew(uint32_t addr, uint32_t val) +static void code_mem_writew(target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; @@ -1802,7 +1801,7 @@ static void code_mem_writew(uint32_t addr, uint32_t val) phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } -static void code_mem_writel(uint32_t addr, uint32_t val) +static void code_mem_writel(target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; @@ -1892,7 +1891,7 @@ int cpu_register_io_memory(int io_index, /* physical memory access (slow version, mainly for debug) */ #if defined(CONFIG_USER_ONLY) -void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { int l, flags; @@ -1921,13 +1920,14 @@ void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, } } #else -void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { int l, io_index; uint8_t *ptr; uint32_t val; - target_ulong page, pd; + target_phys_addr_t page; + unsigned long pd; PageDesc *p; while (len > 0) { diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index dd2369162..42ae22e86 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -104,7 +104,7 @@ static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; /* IO ports emulation */ #define PPC_IO_BASE 0x80000000 -static void PPC_io_writeb (uint32_t addr, uint32_t value, uint32_t vaddr) +static void PPC_io_writeb (target_phys_addr_t addr, uint32_t value) { /* Don't polute serial port output */ #if 0 @@ -121,7 +121,7 @@ static void PPC_io_writeb (uint32_t addr, uint32_t value, uint32_t vaddr) cpu_outb(NULL, addr - PPC_IO_BASE, value); } -static uint32_t PPC_io_readb (uint32_t addr) +static uint32_t PPC_io_readb (target_phys_addr_t addr) { uint32_t ret = cpu_inb(NULL, addr - PPC_IO_BASE); @@ -141,7 +141,7 @@ static uint32_t PPC_io_readb (uint32_t addr) return ret; } -static void PPC_io_writew (uint32_t addr, uint32_t value, uint32_t vaddr) +static void PPC_io_writew (target_phys_addr_t addr, uint32_t value) { if ((addr < 0x800001f0 || addr > 0x800001f7) && (addr < 0x80000170 || addr > 0x80000177)) { @@ -150,7 +150,7 @@ static void PPC_io_writew (uint32_t addr, uint32_t value, uint32_t vaddr) cpu_outw(NULL, addr - PPC_IO_BASE, value); } -static uint32_t PPC_io_readw (uint32_t addr) +static uint32_t PPC_io_readw (target_phys_addr_t addr) { uint32_t ret = cpu_inw(NULL, addr - PPC_IO_BASE); @@ -162,13 +162,13 @@ static uint32_t PPC_io_readw (uint32_t addr) return ret; } -static void PPC_io_writel (uint32_t addr, uint32_t value, uint32_t vaddr) +static void PPC_io_writel (target_phys_addr_t addr, uint32_t value) { PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); cpu_outl(NULL, addr - PPC_IO_BASE, value); } -static uint32_t PPC_io_readl (uint32_t addr) +static uint32_t PPC_io_readl (target_phys_addr_t addr) { uint32_t ret = cpu_inl(NULL, addr - PPC_IO_BASE); @@ -190,12 +190,12 @@ static CPUReadMemoryFunc *PPC_io_read[] = { }; /* Read-only register (?) */ -static void _PPC_ioB_write (uint32_t addr, uint32_t value, uint32_t vaddr) +static void _PPC_ioB_write (target_phys_addr_t addr, uint32_t value) { // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); } -static uint32_t _PPC_ioB_read (uint32_t addr) +static uint32_t _PPC_ioB_read (target_phys_addr_t addr) { uint32_t retval = 0; @@ -636,9 +636,9 @@ static void VGA_printf (uint8_t *s) for (i = 0; i < format_width; i++) { nibble = (arg >> (4 * digit)) & 0x000f; if (nibble <= 9) - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0', 0); + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0'); else - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A', 0); + PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A'); digit--; } in_format = 0; @@ -647,7 +647,7 @@ static void VGA_printf (uint8_t *s) // in_format = 0; // } } else { - PPC_io_writeb(PPC_IO_BASE + 0x500, c, 0); + PPC_io_writeb(PPC_IO_BASE + 0x500, c); } s++; } @@ -659,10 +659,10 @@ static void VGA_init (void) printf("Init VGA...\n"); #if 1 /* switch to color mode and enable CPU access 480 lines */ - PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3, 0); + PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); /* more than 64k 3C4/04 */ - PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04, 0); - PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02, 0); + PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04); + PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02); #endif VGA_printf("PPC VGA BIOS...\n"); } @@ -690,7 +690,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, { #if 1 uint32_t offset = - *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); + *((uint32_t *)(phys_ram_base + kernel_addr)); #else uint32_t offset = 12; #endif @@ -816,7 +816,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, { #if 0 uint32_t offset = - *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); + *((uint32_t *)(phys_ram_base + kernel_addr)); #else uint32_t offset = 12; #endif diff --git a/hw/vga.c b/hw/vga.c index 5a2a73b3c..710254b99 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -648,7 +648,7 @@ static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val) #endif /* called for accesses between 0xa0000 and 0xc0000 */ -static uint32_t vga_mem_readb(uint32_t addr) +static uint32_t vga_mem_readb(target_phys_addr_t addr) { VGAState *s = &vga_state; int memory_map_mode, plane; @@ -704,7 +704,7 @@ static uint32_t vga_mem_readb(uint32_t addr) return ret; } -static uint32_t vga_mem_readw(uint32_t addr) +static uint32_t vga_mem_readw(target_phys_addr_t addr) { uint32_t v; v = vga_mem_readb(addr); @@ -712,7 +712,7 @@ static uint32_t vga_mem_readw(uint32_t addr) return v; } -static uint32_t vga_mem_readl(uint32_t addr) +static uint32_t vga_mem_readl(target_phys_addr_t addr) { uint32_t v; v = vga_mem_readb(addr); @@ -723,7 +723,7 @@ static uint32_t vga_mem_readl(uint32_t addr) } /* called for accesses between 0xa0000 and 0xc0000 */ -static void vga_mem_writeb(uint32_t addr, uint32_t val) +static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val) { VGAState *s = &vga_state; int memory_map_mode, plane, write_mode, b, func_select; @@ -851,13 +851,13 @@ static void vga_mem_writeb(uint32_t addr, uint32_t val) } } -static void vga_mem_writew(uint32_t addr, uint32_t val) +static void vga_mem_writew(target_phys_addr_t addr, uint32_t val) { vga_mem_writeb(addr, val & 0xff); vga_mem_writeb(addr + 1, (val >> 8) & 0xff); } -static void vga_mem_writel(uint32_t addr, uint32_t val) +static void vga_mem_writel(target_phys_addr_t addr, uint32_t val) { vga_mem_writeb(addr, val & 0xff); vga_mem_writeb(addr + 1, (val >> 8) & 0xff); -- cgit v1.2.3 From 165c6fc8ce3026eeeef2e8a1235b0bd08b51f03e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 22:08:49 +0000 Subject: more endianness macros git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@759 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/vl.h b/vl.h index 59ac6935b..e47f7020b 100644 --- a/vl.h +++ b/vl.h @@ -67,6 +67,16 @@ static inline uint16_t be16_to_cpu(uint16_t v) return v; } +static inline uint32_t cpu_to_be32(uint32_t v) +{ + return v; +} + +static inline uint16_t cpu_to_be16(uint16_t v) +{ + return v; +} + static inline uint32_t le32_to_cpu(uint32_t v) { return bswap32(v); @@ -77,7 +87,18 @@ static inline uint16_t le16_to_cpu(uint16_t v) return bswap16(v); } +static inline uint32_t cpu_to_le32(uint32_t v) +{ + return bswap32(v); +} + +static inline uint16_t cpu_to_le16(uint16_t v) +{ + return bswap16(v); +} + #else + static inline uint32_t be32_to_cpu(uint32_t v) { return bswap32(v); @@ -88,6 +109,16 @@ static inline uint16_t be16_to_cpu(uint16_t v) return bswap16(v); } +static inline uint32_t cpu_to_be32(uint32_t v) +{ + return bswap32(v); +} + +static inline uint16_t cpu_to_be16(uint16_t v) +{ + return bswap16(v); +} + static inline uint32_t le32_to_cpu(uint32_t v) { return v; @@ -97,6 +128,16 @@ static inline uint16_t le16_to_cpu(uint16_t v) { return v; } + +static inline uint32_t cpu_to_le32(uint32_t v) +{ + return v; +} + +static inline uint16_t cpu_to_le16(uint16_t v) +{ + return v; +} #endif -- cgit v1.2.3 From 0c4ad8dc2aa144a6269b9c19200c40b67c873d5b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 22:09:16 +0000 Subject: ide endianness fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@760 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 0bef2888e..9bd32e097 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -352,11 +352,7 @@ static void padstr8(uint8_t *buf, int buf_size, const char *src) static void put_le16(uint16_t *p, unsigned int v) { -#ifdef WORDS_BIGENDIAN - *p = bswap16(v); -#else - *p = v; -#endif + *p = cpu_to_le16(v); } static void ide_identify(IDEState *s) @@ -1328,7 +1324,7 @@ static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val) uint8_t *p; p = s->data_ptr; - *(uint16_t *)p = tswap16(val); + *(uint16_t *)p = le16_to_cpu(val); p += 2; s->data_ptr = p; if (p >= s->data_end) @@ -1341,7 +1337,7 @@ static uint32_t ide_data_readw(void *opaque, uint32_t addr) uint8_t *p; int ret; p = s->data_ptr; - ret = tswap16(*(uint16_t *)p); + ret = cpu_to_le16(*(uint16_t *)p); p += 2; s->data_ptr = p; if (p >= s->data_end) @@ -1355,7 +1351,7 @@ static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val) uint8_t *p; p = s->data_ptr; - *(uint32_t *)p = tswap32(val); + *(uint32_t *)p = le32_to_cpu(val); p += 4; s->data_ptr = p; if (p >= s->data_end) @@ -1369,7 +1365,7 @@ static uint32_t ide_data_readl(void *opaque, uint32_t addr) int ret; p = s->data_ptr; - ret = tswap32(*(uint32_t *)p); + ret = cpu_to_le32(*(uint32_t *)p); p += 4; s->data_ptr = p; if (p >= s->data_end) @@ -1417,7 +1413,7 @@ static void ide_guess_geometry(IDEState *s) return; for(i = 0; i < 4; i++) { p = ((struct partition *)(buf + 0x1be)) + i; - nr_sects = tswap32(p->nr_sects); + nr_sects = le32_to_cpu(p->nr_sects); if (nr_sects && p->end_head) { /* We make the assumption that the partition terminates on a cylinder boundary */ -- cgit v1.2.3 From f658b4db792285d0ddc044d7532451b8ec3c4a08 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Apr 2004 22:10:09 +0000 Subject: isa bridge endianness fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@761 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 42ae22e86..dab8a571e 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -137,7 +137,6 @@ static uint32_t PPC_io_readb (target_phys_addr_t addr) { PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); } - return ret; } @@ -147,24 +146,31 @@ static void PPC_io_writew (target_phys_addr_t addr, uint32_t value) (addr < 0x80000170 || addr > 0x80000177)) { PPC_IO_DPRINTF("0x%08x => 0x%04x\n", addr - PPC_IO_BASE, value); } +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif cpu_outw(NULL, addr - PPC_IO_BASE, value); } static uint32_t PPC_io_readw (target_phys_addr_t addr) { uint32_t ret = cpu_inw(NULL, addr - PPC_IO_BASE); - +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap16(ret); +#endif if ((addr < 0x800001f0 || addr > 0x800001f7) && (addr < 0x80000170 || addr > 0x80000177)) { PPC_IO_DPRINTF("0x%08x <= 0x%04x\n", addr - PPC_IO_BASE, ret); } - return ret; } static void PPC_io_writel (target_phys_addr_t addr, uint32_t value) { PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif cpu_outl(NULL, addr - PPC_IO_BASE, value); } @@ -172,8 +178,10 @@ static uint32_t PPC_io_readl (target_phys_addr_t addr) { uint32_t ret = cpu_inl(NULL, addr - PPC_IO_BASE); +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap32(ret); +#endif PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, ret); - return ret; } -- cgit v1.2.3 From 4f2ac237840677ffcb1b3ca30d04a4c2d360f7c7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 19:44:02 +0000 Subject: amd64 port (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@762 c046a42c-6fe2-441c-8c8c-71466251a162 --- amd64.ld | 171 --------------------------------------------------- cpu-all.h | 4 +- cpu-defs.h | 26 +++++--- dyngen-exec.h | 9 +++ exec.c | 25 ++++---- hw/vga.c | 2 +- linux-user/mmap.c | 9 ++- linux-user/syscall.c | 5 ++ translate-all.c | 2 +- 9 files changed, 55 insertions(+), 198 deletions(-) diff --git a/amd64.ld b/amd64.ld index c52a62559..878dafbe7 100644 --- a/amd64.ld +++ b/amd64.ld @@ -169,174 +169,3 @@ SECTIONS .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } -/* Default linker script, for normal executables */ -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") -OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) -SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); -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.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0x90909090 - .plt : { *(.plt) } - .text : - { - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0x90909090 - .fini : - { - KEEP (*(.fini)) - } =0x90909090 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } - /* 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 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(64 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array : { *(.preinit_array) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { *(.init_array) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { *(.fini_array) } - PROVIDE (__fini_array_end = .); - .data : - { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } - .dynamic : { *(.dynamic) } - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - /* We don't want to include the .ctor section from - from the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .got : { *(.got.plt) *(.got) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(64 / 8); - } - . = ALIGN(64 / 8); - _end = .; - PROVIDE (end = .); - . = DATA_SEGMENT_END (.); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} diff --git a/cpu-all.h b/cpu-all.h index 77a801c86..145059cc1 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -335,7 +335,7 @@ static inline int ldsw_raw(void *ptr) static inline int ldl_raw(void *ptr) { -#if defined(__i386__) +#if defined(__i386__) || defined(__x86_64__) int val; asm volatile ("movl %1, %0\n" "bswap %0\n" @@ -372,7 +372,7 @@ static inline void stw_raw(void *ptr, int v) static inline void stl_raw(void *ptr, int v) { -#if defined(__i386__) +#if defined(__i386__) || defined(__x86_64__) asm volatile ("bswap %0\n" "movl %0, %1\n" : "=r" (v) diff --git a/cpu-defs.h b/cpu-defs.h index 2e643e6e2..388d4abdb 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -29,8 +29,18 @@ #error TARGET_LONG_BITS must be defined before including this header #endif +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) +#define HOST_LONG_BITS 64 +#else +#define HOST_LONG_BITS 32 +#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) @@ -47,7 +57,11 @@ typedef uint64_t target_ulong; #endif /* target_phys_addr_t is the type of a physical address (its size can - be different from 'target_ulong') */ + 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 @@ -56,12 +70,6 @@ typedef uint64_t target_phys_addr_t; #error TARGET_PHYS_ADDR_BITS undefined #endif -#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) -#define HOST_LONG_BITS 64 -#else -#define HOST_LONG_BITS 32 -#endif - #define HOST_LONG_SIZE (HOST_LONG_BITS / 8) #define EXCP_INTERRUPT 256 /* async interruption */ @@ -79,9 +87,9 @@ typedef struct CPUTLBEntry { bit 3 : indicates that the entry is invalid bit 2..0 : zero */ - uint32_t address; + target_ulong address; /* addend to virtual address to get physical address */ - uint32_t addend; + target_phys_addr_t addend; } CPUTLBEntry; #endif diff --git a/dyngen-exec.h b/dyngen-exec.h index 004ca71cd..ea20e395d 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -25,12 +25,21 @@ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; +/* XXX may be done for all 64 bits targets ? */ +#if defined (__x86_64__) +typedef unsigned long uint64_t; +#else typedef unsigned long long uint64_t; +#endif typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; +#if defined (__x86_64__) +typedef signed long int64_t; +#else typedef signed long long int64_t; +#endif #define INT8_MIN (-128) #define INT16_MIN (-32767-1) diff --git a/exec.c b/exec.c index ae6165ba6..f6d5396fa 100644 --- a/exec.c +++ b/exec.c @@ -167,8 +167,8 @@ static inline PageDesc *page_find(unsigned int index) } #if !defined(CONFIG_USER_ONLY) -static void tlb_protect_code(CPUState *env, uint32_t addr); -static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr); +static void tlb_protect_code(CPUState *env, target_ulong addr); +static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr); static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) { @@ -1270,7 +1270,7 @@ void tlb_flush_page(CPUState *env, target_ulong addr) #endif } -static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr) +static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr) { if (addr == (tlb_entry->address & (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && @@ -1282,7 +1282,7 @@ static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr) /* update the TLBs so that writes to code in the virtual page 'addr' can be detected */ -static void tlb_protect_code(CPUState *env, uint32_t addr) +static void tlb_protect_code(CPUState *env, target_ulong addr) { int i; @@ -1299,7 +1299,7 @@ static void tlb_protect_code(CPUState *env, uint32_t addr) } static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, - uint32_t phys_addr) + unsigned long phys_addr) { if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE && ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) { @@ -1309,7 +1309,7 @@ static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, /* update the TLB so that writes in physical page 'phys_addr' are no longer tested self modifying code */ -static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr) +static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr) { int i; @@ -1335,7 +1335,7 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end) { CPUState *env; - target_ulong length, start1; + unsigned long length, start1; int i; start &= TARGET_PAGE_MASK; @@ -1420,10 +1420,11 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, int is_user, int is_softmmu) { PageDesc *p; - target_ulong pd; + unsigned long pd; TranslationBlock *first_tb; unsigned int index; - target_ulong address, addend; + target_ulong address; + unsigned long addend; int ret; p = page_find(paddr >> TARGET_PAGE_BITS); @@ -1825,19 +1826,19 @@ static CPUWriteMemoryFunc *code_mem_write[3] = { code_mem_writel, }; -static void notdirty_mem_writeb(uint32_t addr, uint32_t val) +static void notdirty_mem_writeb(target_phys_addr_t addr, uint32_t val) { stb_raw((uint8_t *)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static void notdirty_mem_writew(uint32_t addr, uint32_t val) +static void notdirty_mem_writew(target_phys_addr_t addr, uint32_t val) { stw_raw((uint8_t *)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static void notdirty_mem_writel(uint32_t addr, uint32_t val) +static void notdirty_mem_writel(target_phys_addr_t addr, uint32_t val) { stl_raw((uint8_t *)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); diff --git a/hw/vga.c b/hw/vga.c index 710254b99..05d16b8cf 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -92,7 +92,7 @@ typedef struct VGAState { uint8_t dac_write_index; uint8_t dac_cache[3]; /* used when writing */ uint8_t palette[768]; - uint32_t bank_offset; + int32_t bank_offset; #ifdef CONFIG_BOCHS_VBE uint16_t vbe_index; uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 4f937443e..312af9b1d 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -152,6 +152,9 @@ long target_mmap(unsigned long start, unsigned long len, int prot, int flags, int fd, unsigned long offset) { unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) + static unsigned long last_start = 0x40000000; +#endif #ifdef DEBUG_MMAP { @@ -190,8 +193,10 @@ long target_mmap(unsigned long start, unsigned long len, int prot, if (!(flags & MAP_FIXED)) { #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) /* tell the kenel to search at the same place as i386 */ - if (host_start == 0) - host_start = 0x40000000; + if (host_start == 0) { + host_start = last_start; + last_start += HOST_PAGE_ALIGN(len); + } #endif if (host_page_size != real_host_page_size) { /* NOTE: this code is only for debugging with '-p' option */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 95806454d..79d239ffa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2402,9 +2402,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; case TARGET_NR__llseek: { +#if defined (__x86_64__) + ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5)); + *(int64_t *)arg4 = ret; +#else int64_t res; ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5)); *(int64_t *)arg4 = tswap64(res); +#endif } break; case TARGET_NR_getdents: diff --git a/translate-all.c b/translate-all.c index 137fdcad1..be3039c2c 100644 --- a/translate-all.c +++ b/translate-all.c @@ -194,7 +194,7 @@ int cpu_restore_state(TranslationBlock *tb, fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]); } } - fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%lx cs_base=%lx\n", + fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%x cs_base=%x\n", searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base); } #endif -- cgit v1.2.3 From d927637dca36c564a2911dc4bc0d7969b654cd0c Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 19:44:57 +0000 Subject: init dummy net if tun/tap network error git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@763 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 8206706f6..68ccbcad1 100644 --- a/vl.c +++ b/vl.c @@ -1323,7 +1323,7 @@ int qemu_loadvm(const char *filename) } for(;;) { #if defined (DO_TB_FLUSH) - tb_flush(); + tb_flush(global_env); #endif len = qemu_get_byte(f); if (feof(f)) @@ -2143,7 +2143,8 @@ int main(int argc, char **argv) if (i < nb_tun_fds) { net_fd_init(nd, tun_fds[i]); } else { - net_tun_init(nd); + if (net_tun_init(nd) < 0) + net_dummy_init(nd); } break; #endif -- cgit v1.2.3 From 7fd7b91fac396fcc3d72ecadbcb49f5736755d23 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 19:46:45 +0000 Subject: amd64 port git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@764 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index dab8a571e..c5c151075 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -55,7 +55,6 @@ do { \ #endif #define BIOS_FILENAME "ppc_rom.bin" -#define LINUX_BOOT_FILENAME "linux_boot.bin" #define KERNEL_LOAD_ADDR 0x00000000 #define KERNEL_STACK_ADDR 0x00400000 @@ -677,13 +676,18 @@ static void VGA_init (void) extern CPUPPCState *global_env; +static uint32_t get_le32 (void *addr) +{ + return le32_to_cpu(*((uint32_t *)addr)); +} + void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, uint32_t kernel_addr, uint32_t kernel_size, uint32_t stack_addr, int boot_device, const unsigned char *initrd_file) { CPUPPCState *env = global_env; - char *p; + uint8_t *p; #if !defined (USE_OPEN_FIRMWARE) char *tmp; uint32_t tmpi[2]; @@ -697,8 +701,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, /* Fake bootloader */ { #if 1 - uint32_t offset = - *((uint32_t *)(phys_ram_base + kernel_addr)); + uint32_t offset = get_le32(phys_ram_base + kernel_addr); #else uint32_t offset = 12; #endif @@ -723,7 +726,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, * it's not ready to handle it... */ env->decr = 0xFFFFFFFF; - p = (void *)(phys_ram_base + kernel_addr); + p = phys_ram_base + kernel_addr; #if !defined (USE_OPEN_FIRMWARE) /* Let's register the whole memory available only in supervisor mode */ setup_BAT(env, 0, 0x00000000, 0x00000000, mem_size, 1, 0, 2); @@ -732,7 +735,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, */ put_long(p, 0xdeadc0de); /* Build a real stack room */ - p = (void *)(phys_ram_base + stack_addr); + p = phys_ram_base + stack_addr; put_long(p, stack_addr); p -= 32; env->gpr[1] -= 32; @@ -742,7 +745,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, int size; env->gpr[4] = (kernel_addr + kernel_size + 4095) & ~4095; size = load_initrd(initrd_file, - (void *)((uint32_t)phys_ram_base + env->gpr[4])); + phys_ram_base + env->gpr[4]); if (size < 0) { /* No initrd */ env->gpr[4] = env->gpr[5] = 0; @@ -759,17 +762,17 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, * The BSS starts after the kernel end. */ #if 0 - p = (void *)(((uint32_t)phys_ram_base + kernel_addr + - kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); + p = phys_ram_base + kernel_addr + + kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1); #else - p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); + p = phys_ram_base + kernel_addr + 0x400000; #endif if (loglevel > 0) { fprintf(logfile, "bootinfos: %p 0x%08x\n", - p, (uint32_t)p - (uint32_t)phys_ram_base); + p, (int)(p - phys_ram_base)); } else { printf("bootinfos: %p 0x%08x\n", - p, (uint32_t)p - (uint32_t)phys_ram_base); + p, (int)(p - phys_ram_base)); } /* Command line: let's put it after bootinfos */ #if 0 @@ -782,7 +785,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, boot_devs[boot_device - 'a'].name, mem_size >> 20); #endif - env->gpr[6] = (uint32_t)p + 0x1000 - (uint32_t)phys_ram_base; + env->gpr[6] = p + 0x1000 - phys_ram_base; env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); if (loglevel > 0) { fprintf(logfile, "cmdline: %p 0x%08x [%s]\n", @@ -795,7 +798,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, p = set_bootinfo_tag(p, 0x1010, 0, 0); /* BI_CMD_LINE */ p = set_bootinfo_tag(p, 0x1012, env->gpr[7] - env->gpr[6], - (void *)(env->gpr[6] + (uint32_t)phys_ram_base)); + env->gpr[6] + phys_ram_base); /* BI_MEM_SIZE */ tmp = (void *)tmpi; tmp[0] = (mem_size >> 24) & 0xFF; @@ -823,8 +826,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, setup_BAT(env, 0, 0x01000000, kernel_addr, 0x00400000, 1, 0, 2); { #if 0 - uint32_t offset = - *((uint32_t *)(phys_ram_base + kernel_addr)); + uint32_t offset = get_le32(phys_ram_base + kernel_addr); #else uint32_t offset = 12; #endif @@ -832,7 +834,7 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, printf("Start address: 0x%08x\n", env->nip); } env->gpr[1] = env->nip + (1 << 22); - p = (void *)(phys_ram_base + stack_addr); + p = phys_ram_base + stack_addr; put_long(p - 32, stack_addr); env->gpr[1] -= 32; printf("Kernel starts at 0x%08x stack 0x%08x\n", env->nip, env->gpr[1]); @@ -869,10 +871,10 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, /* Command line: let's put it just over the stack */ #if 0 #if 0 - p = (void *)(((uint32_t)phys_ram_base + kernel_addr + - kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); + p = phys_ram_base + kernel_addr + + kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1); #else - p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); + p = phys_ram_base + kernel_addr + 0x400000; #endif #if 1 sprintf(p, "console=ttyS0,9600 root=%02x%02x mem=%dM", -- cgit v1.2.3 From 1ef59d0acf7c71e9b863bff904ceac74ce9bd107 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 19:48:05 +0000 Subject: ppc fixes (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@765 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/exec.h | 2 ++ target-ppc/helper.c | 13 ++++++------- target-ppc/op.c | 12 ++++++++---- target-ppc/op_helper.c | 10 ++++++++++ target-ppc/translate.c | 6 ++++-- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 72bd03e36..f4d20a8ad 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -139,6 +139,8 @@ void do_sraw(void); void do_fctiw (void); void do_fctiwz (void); +void do_fnmadds (void); +void do_fnmsubs (void); void do_fsqrt (void); void do_fsqrts (void); void do_fres (void); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index ccfd2ea92..dc2737ea7 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -163,7 +163,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, *BATu, *BATl, BEPIu, BEPIl, bl); } #endif - env->spr[DAR] = virtual; } /* No hit */ return ret; @@ -543,12 +542,12 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, access_type = env->access_type; if (env->user_mode_only) { /* user mode only emulation */ - ret = -1; + ret = -2; goto do_fault; } /* NASTY BUG workaround */ if (access_type == ACCESS_CODE && rw) { - // printf("%s: ERROR WRITE CODE ACCESS\n", __func__); + printf("%s: ERROR WRITE CODE ACCESS\n", __func__); access_type = ACCESS_INT; } ret = get_physical_address(env, &physical, &prot, @@ -674,10 +673,10 @@ uint32_t _load_msr (CPUState *env) void _store_msr (CPUState *env, uint32_t value) { - if (((T0 >> MSR_IR) & 0x01) != msr_ir || - ((T0 >> MSR_DR) & 0x01) != msr_dr) { + if (((value >> MSR_IR) & 0x01) != msr_ir || + ((value >> MSR_DR) & 0x01) != msr_dr) { /* Flush all tlb when changing translation mode or privilege level */ - do_tlbia(); + tlb_flush(env, 1); } msr_pow = (value >> MSR_POW) & 0x03; msr_ile = (value >> MSR_ILE) & 0x01; @@ -931,7 +930,7 @@ void do_interrupt (CPUState *env) env->nip = excp << 8; env->exception_index = EXCP_NONE; /* Invalidate all TLB as we may have changed translation mode */ - do_tlbia(); + tlb_flush(env, 1); /* ensure that no TB jump will be modified as the program flow was changed */ #ifdef __sparc__ diff --git a/target-ppc/op.c b/target-ppc/op.c index 12c92891c..de7e24735 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1368,28 +1368,32 @@ PPC_OP(fmsubs) /* fnmadd - fnmadd. - fnmadds - fnmadds. */ PPC_OP(fnmadd) { - FT0 = -((FT0 * FT1) + FT2); + FT0 *= FT1; + FT0 += FT2; + FT0 = -FT0; RETURN(); } /* fnmadds - fnmadds. */ PPC_OP(fnmadds) { - FTS0 = -((FTS0 * FTS1) + FTS2); + do_fnmadds(); RETURN(); } /* fnmsub - fnmsub. */ PPC_OP(fnmsub) { - FT0 = -((FT0 * FT1) - FT2); + FT0 *= FT1; + FT0 -= FT2; + FT0 = -FT0; RETURN(); } /* fnmsubs - fnmsubs. */ PPC_OP(fnmsubs) { - FTS0 = -((FTS0 * FTS1) - FTS2); + do_fnmsubs(); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 0bb48e7a3..ae3d254d9 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -267,6 +267,16 @@ void do_fctiwz (void) fesetround(cround); } +void do_fnmadds (void) +{ + FTS0 = -((FTS0 * FTS1) + FTS2); +} + +void do_fnmsubs (void) +{ + FTS0 = -((FTS0 * FTS1) - FTS2); +} + void do_fsqrt (void) { FT0 = sqrt(FT0); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 35bd660d4..50d1ec158 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -276,7 +276,7 @@ static inline uint32_t MASK (uint32_t start, uint32_t end) } #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ -__attribute__ ((section(".opcodes"), unused)) \ +__attribute__ ((section(".opcodes"), unused, aligned (8) )) \ static opcode_t opc_##name = { \ .opc1 = op1, \ .opc2 = op2, \ @@ -289,7 +289,7 @@ static opcode_t opc_##name = { \ } #define GEN_OPCODE_MARK(name) \ -__attribute__ ((section(".opcodes"), unused)) \ +__attribute__ ((section(".opcodes"), unused, aligned (8) )) \ static opcode_t opc_##name = { \ .opc1 = 0xFF, \ .opc2 = 0xFF, \ @@ -3144,7 +3144,9 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); cpu_ppc_dump_state(env, logfile, 0); fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); +#if defined(CONFIG_USER_ONLY) disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0); +#endif fprintf(logfile, "\n"); fprintf(logfile, "OP:\n"); -- cgit v1.2.3 From 9fafc9eaf0d1cf3894b0b611f2104ef376f2594f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 19:50:09 +0000 Subject: avoid errno variable name git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@766 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.h | 2 +- slirp/tcp_subr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/slirp/slirp.h b/slirp/slirp.h index c2fa86e99..116748505 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -295,7 +295,7 @@ int tcp_attach _P((struct socket *)); u_int8_t tcp_tos _P((struct socket *)); int tcp_emu _P((struct socket *, struct mbuf *)); int tcp_ctl _P((struct socket *)); -struct tcpcb *tcp_drop(struct tcpcb *tp, int errno); +struct tcpcb *tcp_drop(struct tcpcb *tp, int err); #ifdef USE_PPP #define MIN_MRU MINMRU diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index bf8a2026f..07cfc0e4f 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -240,7 +240,7 @@ tcp_newtcpcb(so) * the specified error. If connection is synchronized, * then send a RST to peer. */ -struct tcpcb *tcp_drop(struct tcpcb *tp, int errno) +struct tcpcb *tcp_drop(struct tcpcb *tp, int err) { /* tcp_drop(tp, errno) register struct tcpcb *tp; -- cgit v1.2.3 From 9d4fb82e3caf33f353cee7b71a238fb5dd8e5efb Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 20:55:38 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@767 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 57cf8f8d3..51f4d7c05 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -548,7 +548,55 @@ Since holes are used, the displayed size of the COW disk image is not the real one. To know it, use the @code{ls -ls} command. @end enumerate -@section Direct Linux Boot and Network emulation +@section Network emulation + +QEMU simulates up to 6 networks cards (NE2000 boards). Each card can +be connected to a specific host network interface. + +@subsection Using tun/tap network interface + +This is the standard way to emulate network. QEMU adds a virtual +network device on your host (called @code{tun0}), and you can then +configure it as if it was a real ethernet card. + +As an example, you can download the @file{linux-test-xxx.tar.gz} +archive and copy the script @file{qemu-ifup} in @file{/etc} and +configure properly @code{sudo} so that the command @code{ifconfig} +contained in @file{qemu-ifup} can be executed as root. You must verify +that your host kernel supports the TUN/TAP network interfaces: the +device @file{/dev/net/tun} must be present. + +See @ref{direct_linux_boot} to have an example of network use with a +Linux distribution. + +@subsection Using the user mode network stack + +This is @emph{experimental} (version 0.5.4). You must configure qemu +with @code{--enable-slirp}. Then by using the option +@option{-user-net} or if you have no tun/tap init script, QEMU uses a +completely user mode network stack (you don't need root priviledge to +use the virtual network). The virtual network configuration is the +following: + +@example + +QEMU Virtual Machine <------> Firewall/DHCP server <-----> Internet + (10.0.2.x) | (10.0.2.2) + | + ----> DNS + (10.0.2.3) +@end example + +The QEMU VM behaves as if it was behind a firewall which blocks all +incoming connections. You can use a DHCP client to automatically +configure the network in the QEMU VM. + +In order to check that the user mode network is working, you can ping +the address 10.0.2.2 and verify that you got an address in the range +10.0.2.x from the QEMU virtual DHCP server. + +@node direct_linux_boot +@section Direct Linux Boot This section explains how to launch a Linux kernel inside QEMU without having to make a full bootable image. It is very useful for fast Linux -- cgit v1.2.3 From aaaa7df6250f28e1eb1d3311140d01cd03641412 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 20:56:53 +0000 Subject: added temporary option -enable-audio git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@768 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 8 +++++--- vl.c | 14 +++++++++++--- vl.h | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index d0fcb0f4c..261eda992 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -401,9 +401,11 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, DMA_init(); #ifndef _WIN32 - /* no audio supported yet for win32 */ - AUD_init(); - SB16_init(); + if (audio_enabled) { + /* no audio supported yet for win32 */ + AUD_init(); + SB16_init(); + } #endif floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); diff --git a/vl.c b/vl.c index 68ccbcad1..498bd27bd 100644 --- a/vl.c +++ b/vl.c @@ -111,6 +111,7 @@ NetDriverState nd_table[MAX_NICS]; SerialState *serial_console; QEMUTimer *gui_timer; int vm_running; +int audio_enabled = 0; /***********************************************************/ /* x86 io ports */ @@ -1744,8 +1745,10 @@ int main_loop(void) qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)); - /* XXX: add explicit timer */ - SB16_run(); + if (audio_enabled) { + /* XXX: add explicit timer */ + SB16_run(); + } /* run dma transfers, if any */ DMA_run(); @@ -1761,7 +1764,7 @@ int main_loop(void) void help(void) { - printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" "\n" "'disk_image' is a raw hard image image for IDE hard disk 0\n" @@ -1775,6 +1778,7 @@ void help(void) "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB\n" "-nographic disable graphical output and redirect serial I/Os to console\n" + "-enable-audio enable audio support\n" "\n" "Network options:\n" "-nics n simulate 'n' network cards [default=1]\n" @@ -1842,6 +1846,7 @@ struct option long_options[] = { { "macaddr", 1, NULL, 0 }, { "user-net", 0, NULL, 0 }, { "dummy-net", 0, NULL, 0 }, + { "enable-audio", 0, NULL, 0 }, { NULL, 0, NULL, 0 }, }; @@ -2033,6 +2038,9 @@ int main(int argc, char **argv) case 19: net_if_type = NET_IF_DUMMY; break; + case 20: + audio_enabled = 1; + break; } break; case 'h': diff --git a/vl.h b/vl.h index e47f7020b..c037aa285 100644 --- a/vl.h +++ b/vl.h @@ -173,6 +173,8 @@ void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque); void vm_start(void); void vm_stop(int reason); +extern int audio_enabled; + /* async I/O support */ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); -- cgit v1.2.3 From 4606bb3f062eee892043dcbefe0dba148ade1627 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 20:58:11 +0000 Subject: copyright update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@769 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 2af888fdd..ae4f6a5ac 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -814,7 +814,7 @@ void cpu_loop(CPUPPCState *env) void usage(void) { - printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" -- cgit v1.2.3 From a8c490cda5859961d06db2066ef1f19147527c58 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 20:59:17 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@770 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 51f4d7c05..9dd02edd2 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -231,6 +231,11 @@ command line application. The emulated serial port is redirected on the console. Therefore, you can still use QEMU to debug a Linux kernel with a serial console. +@item -enable-audio + +The SB16 emulation is disabled by default as it may give problems with +Windows. You can enable it manually with this option. + @end table Network options: -- cgit v1.2.3 From bbc9d348390d0fe9dbc2c055b0e9764c4bc9514b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Apr 2004 21:15:11 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@771 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 + tests/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 15506a19c..df44a5e61 100644 --- a/Makefile +++ b/Makefile @@ -81,6 +81,7 @@ tar: tarbin: ( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \ $(prefix)/bin/qemu $(prefix)/bin/qemu-fast \ + $(prefix)/bin/qemu-system-ppc \ $(prefix)/bin/qemu-i386 \ $(prefix)/bin/qemu-arm \ $(prefix)/bin/qemu-sparc \ diff --git a/tests/Makefile b/tests/Makefile index 511629456..1142deaed 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -81,4 +81,4 @@ test2: done clean: - rm -f *~ *.o test-i386.out test-i386.ref $(TESTS) + rm -f *~ *.o test-i386.out test-i386.ref qruncom $(TESTS) -- cgit v1.2.3 From 8e9c4afe707426487db85e462a3b0c4d15e39261 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 28 Apr 2004 19:33:40 +0000 Subject: full screen support (initial patch by malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@772 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/sdl.c b/sdl.c index f283d86cd..01d9617a3 100644 --- a/sdl.c +++ b/sdl.c @@ -32,6 +32,10 @@ static SDL_Surface *screen; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static int last_vm_running; +static int gui_saved_grab; +static int gui_fullscreen; +static int gui_key_modifier_pressed; +static int gui_keysym; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { @@ -47,6 +51,8 @@ static void sdl_resize(DisplayState *ds, int w, int h) flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; flags |= SDL_RESIZABLE; + if (gui_fullscreen) + flags |= SDL_FULLSCREEN; screen = SDL_SetVideoMode(w, h, 0, flags); if (!screen) { fprintf(stderr, "Could not open SDL display\n"); @@ -208,10 +214,26 @@ static void sdl_send_mouse_event(void) kbd_mouse_event(dx, dy, dz, buttons); } +static void toggle_full_screen(DisplayState *ds) +{ + gui_fullscreen = !gui_fullscreen; + sdl_resize(ds, screen->w, screen->h); + if (gui_fullscreen) { + gui_saved_grab = gui_grab; + sdl_grab_start(); + } else { + if (!gui_saved_grab) + sdl_grab_end(); + } + vga_update_display(); + sdl_update(ds, 0, 0, screen->w, screen->h); +} + static void sdl_refresh(DisplayState *ds) { SDL_Event ev1, *ev = &ev1; - + int mod_state; + if (last_vm_running != vm_running) { last_vm_running = vm_running; sdl_update_caption(); @@ -226,13 +248,32 @@ static void sdl_refresh(DisplayState *ds) case SDL_KEYDOWN: case SDL_KEYUP: if (ev->type == SDL_KEYDOWN) { - if ((SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) == - (KMOD_LSHIFT | KMOD_LCTRL)) { - /* exit/enter grab if pressing Ctrl-Shift */ - if (!gui_grab) - sdl_grab_start(); - else - sdl_grab_end(); + mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) == + (KMOD_LSHIFT | KMOD_LCTRL); + gui_key_modifier_pressed = mod_state; + if (gui_key_modifier_pressed && + ev->key.keysym.sym == SDLK_f) { + gui_keysym = ev->key.keysym.sym; + } + } else if (ev->type == SDL_KEYUP) { + mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)); + if (!mod_state) { + if (gui_key_modifier_pressed) { + switch(gui_keysym) { + case SDLK_f: + toggle_full_screen(ds); + break; + case 0: + /* exit/enter grab if pressing Ctrl-Shift */ + if (!gui_grab) + sdl_grab_start(); + else + sdl_grab_end(); + break; + } + gui_key_modifier_pressed = 0; + gui_keysym = 0; + } } } sdl_process_key(&ev->key); -- cgit v1.2.3 From 26aa7d72cc3ff586ca4b5bd79f63b0066fe21b0f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 28 Apr 2004 22:26:05 +0000 Subject: isa memory remapping support (aka PPC PREP VGA support) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@773 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 4 +++- hw/vga.c | 29 ++++++++++++++--------------- vl.c | 4 +++- vl.h | 25 ++++++++++++++++++------- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index c5c151075..8499ba3d1 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -896,7 +896,7 @@ void PPC_end_init (void) VGA_init(); } -/* PC hardware initialisation */ +/* PowerPC PREP hardware initialisation */ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -911,6 +911,8 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); + isa_mem_base = 0xc0000000; + if (linux_boot) { /* now we can load the kernel */ ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); diff --git a/hw/vga.c b/hw/vga.c index 05d16b8cf..a6220f3e1 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -549,7 +549,7 @@ static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val) case VBE_DISPI_INDEX_BANK: val &= s->vbe_bank_mask; s->vbe_regs[s->vbe_index] = val; - s->bank_offset = (val << 16) - 0xa0000; + s->bank_offset = (val << 16); break; case VBE_DISPI_INDEX_ENABLE: if (val & VBE_DISPI_ENABLED) { @@ -603,7 +603,7 @@ static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->vbe_regs[s->vbe_index] = val; } else { /* XXX: the bios should do that */ - s->bank_offset = -0xa0000; + s->bank_offset = 0; } break; case VBE_DISPI_INDEX_VIRT_WIDTH: @@ -656,23 +656,23 @@ static uint32_t vga_mem_readb(target_phys_addr_t addr) /* convert to VGA memory offset */ memory_map_mode = (s->gr[6] >> 2) & 3; + addr &= 0x1ffff; switch(memory_map_mode) { case 0: - addr -= 0xa0000; break; case 1: - if (addr >= 0xb0000) + if (addr >= 0x10000) return 0xff; addr += s->bank_offset; break; case 2: - addr -= 0xb0000; + addr -= 0x10000; if (addr >= 0x8000) return 0xff; break; default: case 3: - addr -= 0xb8000; + addr -= 0x18000; if (addr >= 0x8000) return 0xff; break; @@ -734,23 +734,23 @@ static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val) #endif /* convert to VGA memory offset */ memory_map_mode = (s->gr[6] >> 2) & 3; + addr &= 0x1ffff; switch(memory_map_mode) { case 0: - addr -= 0xa0000; break; case 1: - if (addr >= 0xb0000) + if (addr >= 0x10000) return; addr += s->bank_offset; break; case 2: - addr -= 0xb0000; + addr -= 0x10000; if (addr >= 0x8000) return; break; default: case 3: - addr -= 0xb8000; + addr -= 0x18000; if (addr >= 0x8000) return; break; @@ -1758,7 +1758,7 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s); register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); - s->bank_offset = -0xa0000; + s->bank_offset = 0; #ifdef CONFIG_BOCHS_VBE s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0; @@ -1771,15 +1771,14 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, #endif vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); -#if defined (TARGET_I386) - cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory); + cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, + vga_io_memory); #ifdef CONFIG_BOCHS_VBE +#if defined (TARGET_I386) /* XXX: use optimized standard vga accesses */ cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, vga_ram_size, vga_ram_offset); #endif -#elif defined (TARGET_PPC) - cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory); #endif return 0; } diff --git a/vl.c b/vl.c index 498bd27bd..e89091d0f 100644 --- a/vl.c +++ b/vl.c @@ -114,7 +114,9 @@ int vm_running; int audio_enabled = 0; /***********************************************************/ -/* x86 io ports */ +/* x86 ISA bus support */ + +target_phys_addr_t isa_mem_base = 0; uint32_t default_ioport_readb(void *opaque, uint32_t address) { diff --git a/vl.h b/vl.h index c037aa285..7fb81c839 100644 --- a/vl.h +++ b/vl.h @@ -144,13 +144,6 @@ static inline uint16_t cpu_to_le16(uint16_t v) /* vl.c */ extern int reset_requested; -typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); -typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); - -int register_ioport_read(int start, int length, int size, - IOPortReadFunc *func, void *opaque); -int register_ioport_write(int start, int length, int size, - IOPortWriteFunc *func, void *opaque); uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); void hw_error(const char *fmt, ...); @@ -348,6 +341,18 @@ void bdrv_set_change_cb(BlockDriverState *bs, void bdrv_info(void); BlockDriverState *bdrv_find(const char *name); +/* ISA bus */ + +extern target_phys_addr_t isa_mem_base; + +typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); + +int register_ioport_read(int start, int length, int size, + IOPortReadFunc *func, void *opaque); +int register_ioport_write(int start, int length, int size, + IOPortWriteFunc *func, void *opaque); + /* vga.c */ #define VGA_RAM_SIZE (4096 * 1024) @@ -503,6 +508,12 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); +/* ppc.c */ +void ppc_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + /* monitor.c */ void monitor_init(void); void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -- cgit v1.2.3 From 646be93b4cc87635ffa03e044d1d21f5c80403c1 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 28 Apr 2004 22:38:47 +0000 Subject: Bochs VBE emulation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@774 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/vga.c b/hw/vga.c index a6220f3e1..5838d3fc0 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -597,6 +597,7 @@ static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->sr[0x01] &= ~8; /* no double line */ } else { shift_control = 2; + s->sr[4] |= 0x08; /* set chain 4 mode */ } s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5); s->cr[0x09] &= ~0x9f; /* no double scan */ @@ -1768,6 +1769,13 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s); register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s); + + /* old Bochs IO ports */ + register_ioport_read(0xff80, 1, 2, vbe_ioport_read, s); + register_ioport_read(0xff81, 1, 2, vbe_ioport_read, s); + + register_ioport_write(0xff80, 1, 2, vbe_ioport_write, s); + register_ioport_write(0xff81, 1, 2, vbe_ioport_write, s); #endif vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); -- cgit v1.2.3 From 141253b2548a0af64dfd38cd6aa8cd4e80240702 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 Apr 2004 19:21:16 +0000 Subject: Bochs VBE emulation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@775 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/vga.c b/hw/vga.c index 5838d3fc0..62c7c404c 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -598,14 +598,15 @@ static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val) } else { shift_control = 2; s->sr[4] |= 0x08; /* set chain 4 mode */ + s->sr[2] |= 0x0f; /* activate all planes */ } s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5); s->cr[0x09] &= ~0x9f; /* no double scan */ - s->vbe_regs[s->vbe_index] = val; } else { /* XXX: the bios should do that */ s->bank_offset = 0; } + s->vbe_regs[s->vbe_index] = val; break; case VBE_DISPI_INDEX_VIRT_WIDTH: { -- cgit v1.2.3 From d8d8aa4e2cc8e56d9e651e97ad16144289b00154 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 Apr 2004 20:14:07 +0000 Subject: SDL static config fix (Roman Zippel) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@776 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 2c8dddbc4..4facab5fd 100755 --- a/configure +++ b/configure @@ -220,7 +220,7 @@ 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 --libs`" + 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 -- cgit v1.2.3 From 0294ffb9c848ed411c40cb0074ee5e16b7706f53 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 Apr 2004 22:15:15 +0000 Subject: disable grab if the window no longer has the focus (Windows case) (Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@777 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sdl.c b/sdl.c index 01d9617a3..ee809daa6 100644 --- a/sdl.c +++ b/sdl.c @@ -301,6 +301,11 @@ static void sdl_refresh(DisplayState *ds) } } break; + case SDL_ACTIVEEVENT: + if (gui_grab && (ev->active.gain & SDL_ACTIVEEVENTMASK) == 0) { + sdl_grab_end(); + } + break; default: break; } -- cgit v1.2.3 From 6f51f6b593e0a0065f83bcebb6f9e4aa05a4c8b3 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 Apr 2004 22:23:55 +0000 Subject: keyboard irq generation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@778 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index 2328d209f..ee83e0f77 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -111,12 +111,13 @@ #define KBD_QUEUE_SIZE 256 typedef struct { + uint8_t aux[KBD_QUEUE_SIZE]; uint8_t data[KBD_QUEUE_SIZE]; int rptr, wptr, count; } KBDQueue; typedef struct KBDState { - KBDQueue queues[2]; + KBDQueue queue; uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ uint8_t status; uint8_t mode; @@ -145,15 +146,15 @@ int reset_requested; incorrect, but it avoids having to simulate exact delays */ static void kbd_update_irq(KBDState *s) { + KBDQueue *q = &s->queue; int irq12_level, irq1_level; irq1_level = 0; irq12_level = 0; s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); - if (s->queues[0].count != 0 || - s->queues[1].count != 0) { + if (q->count != 0) { s->status |= KBD_STAT_OBF; - if (s->queues[1].count != 0) { + if (q->aux[q->rptr]) { s->status |= KBD_STAT_MOUSE_OBF; if (s->mode & KBD_MODE_MOUSE_INT) irq12_level = 1; @@ -169,7 +170,7 @@ static void kbd_update_irq(KBDState *s) static void kbd_queue(KBDState *s, int b, int aux) { - KBDQueue *q = &s->queues[aux]; + KBDQueue *q = &s->queue; #if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) if (aux) @@ -181,6 +182,7 @@ static void kbd_queue(KBDState *s, int b, int aux) #endif if (q->count >= KBD_QUEUE_SIZE) return; + q->aux[q->wptr] = aux; q->data[q->wptr] = b; if (++q->wptr == KBD_QUEUE_SIZE) q->wptr = 0; @@ -288,30 +290,28 @@ static uint32_t kbd_read_data(void *opaque, uint32_t addr) { KBDState *s = opaque; KBDQueue *q; - int val, index; + int val, index, aux; - q = &s->queues[1]; /* first check AUX data */ - if (q->count == 0) - q = &s->queues[0]; /* then check KBD data */ + q = &s->queue; if (q->count == 0) { /* NOTE: if no data left, we return the last keyboard one (needed for EMM386) */ /* XXX: need a timer to do things correctly */ - q = &s->queues[0]; index = q->rptr - 1; if (index < 0) index = KBD_QUEUE_SIZE - 1; val = q->data[index]; } else { + aux = q->aux[q->rptr]; val = q->data[q->rptr]; if (++q->rptr == KBD_QUEUE_SIZE) q->rptr = 0; q->count--; /* reading deasserts IRQ */ - if (q == &s->queues[0]) - pic_set_irq(1, 0); - else + if (aux) pic_set_irq(12, 0); + else + pic_set_irq(1, 0); } /* reassert IRQs if data left */ kbd_update_irq(s); @@ -452,7 +452,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) s->mouse_buttons = buttons_state; if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && - (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { + (s->queue.count < (KBD_QUEUE_SIZE - 16))) { for(;;) { /* if not remote, send event. Multiple events are sent if too big deltas */ @@ -632,18 +632,15 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) void kbd_reset(KBDState *s) { KBDQueue *q; - int i; s->kbd_write_cmd = -1; s->mouse_write_cmd = -1; s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; - for(i = 0; i < 2; i++) { - q = &s->queues[i]; - q->rptr = 0; - q->wptr = 0; - q->count = 0; - } + q = &s->queue; + q->rptr = 0; + q->wptr = 0; + q->count = 0; } void kbd_init(void) -- cgit v1.2.3 From b06eddd39de08025a17cee1fd43c31458dfeb69f Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 29 Apr 2004 22:34:24 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@779 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changelog b/Changelog index 17d23015a..d61e3f0ea 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +version 0.5.5: + + - SDL full screen support (initial patch by malc) + - VGA support on PowerPC PREP + - VBE fixes (Matthew Mastracci) + version 0.5.4: - qemu-fast fixes -- cgit v1.2.3 From f72e8ff4a698c13c69b9f3f06a56b60ca5af3a78 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 May 2004 19:23:07 +0000 Subject: utime fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@780 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 79d239ffa..37d644dd9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1729,11 +1729,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_utime: { - struct utimbuf tbuf; + struct utimbuf tbuf, *tbuf1; struct target_utimbuf *target_tbuf = (void *)arg2; - tbuf.actime = tswapl(target_tbuf->actime); - tbuf.modtime = tswapl(target_tbuf->modtime); - ret = get_errno(utime((const char *)arg1, &tbuf)); + if (target_tbuf) { + get_user(tbuf.actime, &target_tbuf->actime); + get_user(tbuf.modtime, &target_tbuf->modtime); + tbuf1 = &tbuf; + } else { + tbuf1 = NULL; + } + ret = get_errno(utime((const char *)arg1, tbuf1)); } break; #ifdef TARGET_NR_stty -- cgit v1.2.3 From ec844b96c083340a4c04849c2c1cdc09e85e0595 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 May 2004 23:18:25 +0000 Subject: pit fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@781 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + hw/i8254.c | 227 ++++++++++++++++++++++++++++++++++++++++++++----------------- hw/pc.c | 9 +-- vl.h | 26 ++----- 4 files changed, 175 insertions(+), 88 deletions(-) diff --git a/Changelog b/Changelog index d61e3f0ea..ca6d0e66f 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,7 @@ 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 timer bug) version 0.5.4: diff --git a/hw/i8254.c b/hw/i8254.c index ad61a14af..1eb4a1860 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -25,14 +25,36 @@ //#define DEBUG_PIT -#define RW_STATE_LSB 0 -#define RW_STATE_MSB 1 -#define RW_STATE_WORD0 2 -#define RW_STATE_WORD1 3 -#define RW_STATE_LATCHED_WORD0 4 -#define RW_STATE_LATCHED_WORD1 5 +#define RW_STATE_LSB 1 +#define RW_STATE_MSB 2 +#define RW_STATE_WORD0 3 +#define RW_STATE_WORD1 4 -PITChannelState pit_channels[3]; +typedef struct PITChannelState { + int count; /* can be 65536 */ + uint16_t latched_count; + uint8_t count_latched; + uint8_t status_latched; + uint8_t status; + uint8_t read_state; + uint8_t write_state; + uint8_t write_latch; + uint8_t rw_mode; + uint8_t mode; + uint8_t bcd; /* not supported */ + uint8_t gate; /* timer start */ + int64_t count_load_time; + /* irq handling */ + int64_t next_transition_time; + QEMUTimer *irq_timer; + int irq; +} PITChannelState; + +struct PITState { + PITChannelState channels[3]; +}; + +static PITState pit_state; static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); @@ -61,7 +83,7 @@ static int pit_get_count(PITChannelState *s) } /* get pit output bit */ -int pit_get_out(PITChannelState *s, int64_t current_time) +static int pit_get_out1(PITChannelState *s, int64_t current_time) { uint64_t d; int out; @@ -92,6 +114,12 @@ int pit_get_out(PITChannelState *s, int64_t current_time) return out; } +int pit_get_out(PITState *pit, int channel, int64_t current_time) +{ + PITChannelState *s = &pit->channels[channel]; + return pit_get_out1(s, current_time); +} + /* return -1 if no transition will occur. */ static int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time) @@ -144,8 +172,10 @@ static int64_t pit_get_next_transition_time(PITChannelState *s, } /* val must be 0 or 1 */ -void pit_set_gate(PITChannelState *s, int val) +void pit_set_gate(PITState *pit, int channel, int val) { + PITChannelState *s = &pit->channels[channel]; + switch(s->mode) { default: case 0: @@ -173,6 +203,12 @@ void pit_set_gate(PITChannelState *s, int val) s->gate = val; } +int pit_get_gate(PITState *pit, int channel) +{ + PITChannelState *s = &pit->channels[channel]; + return s->gate; +} + static inline void pit_load_count(PITChannelState *s, int val) { if (val == 0) @@ -182,33 +218,62 @@ static inline void pit_load_count(PITChannelState *s, int val) pit_irq_timer_update(s, s->count_load_time); } +/* if already latched, do not latch again */ +static void pit_latch_count(PITChannelState *s) +{ + if (!s->count_latched) { + s->latched_count = pit_get_count(s); + s->count_latched = s->rw_mode; + } +} + static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) { + PITState *pit = opaque; int channel, access; PITChannelState *s; addr &= 3; if (addr == 3) { channel = val >> 6; - if (channel == 3) - return; - s = &pit_channels[channel]; - access = (val >> 4) & 3; - switch(access) { - case 0: - s->latched_count = pit_get_count(s); - s->rw_state = RW_STATE_LATCHED_WORD0; - break; - default: - s->mode = (val >> 1) & 7; - s->bcd = val & 1; - s->rw_state = access - 1 + RW_STATE_LSB; - /* XXX: update irq timer ? */ - break; + if (channel == 3) { + /* read back command */ + for(channel = 0; channel < 3; channel++) { + s = &pit->channels[channel]; + if (val & (2 << channel)) { + if (!(val & 0x20)) { + pit_latch_count(s); + } + if (!(val & 0x10) && !s->status_latched) { + /* status latch */ + /* XXX: add BCD and null count */ + s->status = (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) | + (s->rw_mode << 4) | + (s->mode << 1) | + s->bcd; + s->status_latched = 1; + } + } + } + } else { + s = &pit->channels[channel]; + access = (val >> 4) & 3; + if (access == 0) { + pit_latch_count(s); + } else { + s->rw_mode = access; + s->read_state = access; + s->write_state = access; + + s->mode = (val >> 1) & 7; + s->bcd = val & 1; + /* XXX: update irq timer ? */ + } } } else { - s = &pit_channels[addr]; - switch(s->rw_state) { + s = &pit->channels[addr]; + switch(s->write_state) { + default: case RW_STATE_LSB: pit_load_count(s, val); break; @@ -216,13 +281,12 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) pit_load_count(s, val << 8); break; case RW_STATE_WORD0: + s->write_latch = val; + s->write_state = RW_STATE_WORD1; + break; case RW_STATE_WORD1: - if (s->rw_state & 1) { - pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); - } else { - s->latched_count = val; - } - s->rw_state ^= 1; + pit_load_count(s, s->write_latch | (val << 8)); + s->write_state = RW_STATE_WORD0; break; } } @@ -230,33 +294,53 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) static uint32_t pit_ioport_read(void *opaque, uint32_t addr) { + PITState *pit = opaque; int ret, count; PITChannelState *s; addr &= 3; - s = &pit_channels[addr]; - switch(s->rw_state) { - case RW_STATE_LSB: - case RW_STATE_MSB: - case RW_STATE_WORD0: - case RW_STATE_WORD1: - count = pit_get_count(s); - if (s->rw_state & 1) - ret = (count >> 8) & 0xff; - else - ret = count & 0xff; - if (s->rw_state & 2) - s->rw_state ^= 1; - break; - default: - case RW_STATE_LATCHED_WORD0: - case RW_STATE_LATCHED_WORD1: - if (s->rw_state & 1) + s = &pit->channels[addr]; + if (s->status_latched) { + s->status_latched = 0; + ret = s->status; + } else if (s->count_latched) { + switch(s->count_latched) { + default: + case RW_STATE_LSB: + ret = s->latched_count & 0xff; + s->count_latched = 0; + break; + case RW_STATE_MSB: ret = s->latched_count >> 8; - else + s->count_latched = 0; + break; + case RW_STATE_WORD0: ret = s->latched_count & 0xff; - s->rw_state ^= 1; - break; + s->count_latched = RW_STATE_MSB; + break; + } + } else { + switch(s->read_state) { + default: + case RW_STATE_LSB: + count = pit_get_count(s); + ret = count & 0xff; + break; + case RW_STATE_MSB: + count = pit_get_count(s); + ret = (count >> 8) & 0xff; + break; + case RW_STATE_WORD0: + count = pit_get_count(s); + ret = count & 0xff; + s->read_state = RW_STATE_WORD1; + break; + case RW_STATE_WORD1: + count = pit_get_count(s); + ret = (count >> 8) & 0xff; + s->read_state = RW_STATE_WORD0; + break; + } } return ret; } @@ -269,7 +353,7 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) if (!s->irq_timer) return; expire_time = pit_get_next_transition_time(s, current_time); - irq_level = pit_get_out(s, current_time); + irq_level = pit_get_out1(s, current_time); pic_set_irq(s->irq, irq_level); #ifdef DEBUG_PIT printf("irq_level=%d next_delay=%f\n", @@ -292,14 +376,21 @@ static void pit_irq_timer(void *opaque) static void pit_save(QEMUFile *f, void *opaque) { + PITState *pit = opaque; PITChannelState *s; int i; for(i = 0; i < 3; i++) { - s = &pit_channels[i]; + s = &pit->channels[i]; qemu_put_be32s(f, &s->count); qemu_put_be16s(f, &s->latched_count); - qemu_put_8s(f, &s->rw_state); + qemu_put_8s(f, &s->count_latched); + qemu_put_8s(f, &s->status_latched); + qemu_put_8s(f, &s->status); + qemu_put_8s(f, &s->read_state); + qemu_put_8s(f, &s->write_state); + qemu_put_8s(f, &s->write_latch); + qemu_put_8s(f, &s->rw_mode); qemu_put_8s(f, &s->mode); qemu_put_8s(f, &s->bcd); qemu_put_8s(f, &s->gate); @@ -313,6 +404,7 @@ static void pit_save(QEMUFile *f, void *opaque) static int pit_load(QEMUFile *f, void *opaque, int version_id) { + PITState *pit = opaque; PITChannelState *s; int i; @@ -320,10 +412,16 @@ static int pit_load(QEMUFile *f, void *opaque, int version_id) return -EINVAL; for(i = 0; i < 3; i++) { - s = &pit_channels[i]; + s = &pit->channels[i]; qemu_get_be32s(f, &s->count); qemu_get_be16s(f, &s->latched_count); - qemu_get_8s(f, &s->rw_state); + qemu_get_8s(f, &s->count_latched); + qemu_get_8s(f, &s->status_latched); + qemu_get_8s(f, &s->status); + qemu_get_8s(f, &s->read_state); + qemu_get_8s(f, &s->write_state); + qemu_get_8s(f, &s->write_latch); + qemu_get_8s(f, &s->rw_mode); qemu_get_8s(f, &s->mode); qemu_get_8s(f, &s->bcd); qemu_get_8s(f, &s->gate); @@ -336,13 +434,14 @@ static int pit_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void pit_init(int base, int irq) +PITState *pit_init(int base, int irq) { + PITState *pit = &pit_state; PITChannelState *s; int i; for(i = 0;i < 3; i++) { - s = &pit_channels[i]; + s = &pit->channels[i]; if (i == 0) { /* the timer 0 is connected to an IRQ */ s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s); @@ -353,9 +452,9 @@ void pit_init(int base, int irq) pit_load_count(s, 0); } - register_savevm("i8254", base, 1, pit_save, pit_load, NULL); + register_savevm("i8254", base, 1, pit_save, pit_load, pit); - register_ioport_write(base, 4, 1, pit_ioport_write, NULL); - register_ioport_read(base, 3, 1, pit_ioport_read, NULL); + register_ioport_write(base, 4, 1, pit_ioport_write, pit); + register_ioport_read(base, 3, 1, pit_ioport_read, pit); + return pit; } - diff --git a/hw/pc.c b/hw/pc.c index 261eda992..e1293aad4 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -39,6 +39,7 @@ int speaker_data_on; int dummy_refresh_clock; static fdctrl_t *floppy_controller; static RTCState *rtc_state; +static PITState *pit; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -169,15 +170,15 @@ static void cmos_init(int ram_size, int boot_device) static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) { speaker_data_on = (val >> 1) & 1; - pit_set_gate(&pit_channels[2], val & 1); + pit_set_gate(pit, 2, val & 1); } static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) { int out; - out = pit_get_out(&pit_channels[2], qemu_get_clock(vm_clock)); + out = pit_get_out(pit, 2, qemu_get_clock(vm_clock)); dummy_refresh_clock ^= 1; - return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | + return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | (dummy_refresh_clock << 4); } @@ -381,7 +382,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, register_ioport_write(0x92, 1, 1, ioport92_write, NULL); pic_init(); - pit_init(0x40, 0); + pit = pit_init(0x40, 0); fd = serial_open_device(); serial_init(0x3f8, 4, fd); diff --git a/vl.h b/vl.h index 7fb81c839..639b473cd 100644 --- a/vl.h +++ b/vl.h @@ -481,26 +481,12 @@ void pic_info(void); #define PIT_FREQ 1193182 -typedef struct PITChannelState { - int count; /* can be 65536 */ - uint16_t latched_count; - uint8_t rw_state; - uint8_t mode; - uint8_t bcd; /* not supported */ - uint8_t gate; /* timer start */ - int64_t count_load_time; - /* irq handling */ - int64_t next_transition_time; - QEMUTimer *irq_timer; - int irq; -} PITChannelState; - -extern PITChannelState pit_channels[3]; - -void pit_init(int base, int irq); -void pit_set_gate(PITChannelState *s, int val); -int pit_get_out(PITChannelState *s, int64_t current_time); -int pit_get_out_edges(PITChannelState *s); +typedef struct PITState PITState; + +PITState *pit_init(int base, int irq); +void pit_set_gate(PITState *pit, int channel, int val); +int pit_get_gate(PITState *pit, int channel); +int pit_get_out(PITState *pit, int channel, int64_t current_time); /* pc.c */ void pc_init(int ram_size, int vga_ram_size, int boot_device, -- cgit v1.2.3 From 66201e2ddff787d7ddff123baa56661a95be7c4b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 May 2004 01:29:51 +0000 Subject: ide slave fixes (aka Win98 CD-ROM detection fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@782 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + hw/ide.c | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Changelog b/Changelog index ca6d0e66f..86d9d9277 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ version 0.5.5: - VGA support on PowerPC PREP - VBE fixes (Matthew Mastracci) - PIT fixes (aka Win98 hardware probe and timer bug) + - IDE master only fixes (aka Win98 CD-ROM probe bug) version 0.5.4: diff --git a/hw/ide.c b/hw/ide.c index 9bd32e097..6c92bedbb 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -409,11 +409,6 @@ static void ide_atapi_identify(IDEState *s) p = (uint16_t *)s->io_buffer; /* Removable CDROM, 50us response, 12 byte packets */ put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); - put_le16(p + 1, s->cylinders); - put_le16(p + 3, s->heads); - put_le16(p + 4, 512 * s->sectors); /* sectors */ - put_le16(p + 5, 512); /* sector size */ - put_le16(p + 6, s->sectors); padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ put_le16(p + 20, 3); /* buffer type */ put_le16(p + 21, 512); /* cache size in sectors */ @@ -1088,6 +1083,9 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("ide: CMD=%02x\n", val); #endif s = ide_if->cur_drive; + /* ignore commands to non existant slave */ + if (s != ide_if && !s->bs) + break; switch(val) { case WIN_IDENTIFY: if (s->bs && !s->is_cdrom) { @@ -1254,7 +1252,8 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) break; default: case 7: - if (!ide_if[0].bs && !ide_if[1].bs) + if ((!ide_if[0].bs && !ide_if[1].bs) || + (s != ide_if && !s->bs)) ret = 0; else ret = s->status; @@ -1273,7 +1272,8 @@ static uint32_t ide_status_read(void *opaque, uint32_t addr) IDEState *s = ide_if->cur_drive; int ret; - if (!ide_if[0].bs && !ide_if[1].bs) + if ((!ide_if[0].bs && !ide_if[1].bs) || + (s != ide_if && !s->bs)) ret = 0; else ret = s->status; -- cgit v1.2.3 From fb6cf1d09cccd6bc288d5f1569132d91ff953dfc Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 May 2004 02:04:17 +0000 Subject: fixed floppy reset (aka win98 floppy probe fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@783 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/fdc.c b/hw/fdc.c index 0de5578bb..dceee8fc7 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -636,11 +636,11 @@ static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) if (!(fdctrl->state & FD_CTRL_RESET)) { FLOPPY_DPRINTF("controler enter RESET state\n"); fdctrl->state |= FD_CTRL_RESET; - fdctrl_reset(fdctrl, 1); } } else { if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("controler out of RESET state\n"); + fdctrl_reset(fdctrl, 1); fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); } } -- cgit v1.2.3 From 512176dbd81b0afb7185416ab2a28a340978b85b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 May 2004 03:14:47 +0000 Subject: fixed dhcp for windows client git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@784 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/bootp.c | 35 +++++++++++++++++++++++++++++++---- slirp/slirp.c | 2 +- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/slirp/bootp.c b/slirp/bootp.c index 7e4b5bab0..755072db8 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -33,6 +33,7 @@ typedef struct { uint8_t allocated; + uint8_t macaddr[6]; } BOOTPClient; BOOTPClient bootp_clients[NB_ADDR]; @@ -63,6 +64,23 @@ static BOOTPClient *get_new_addr(struct in_addr *paddr) return bc; } +static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr) +{ + BOOTPClient *bc; + int i; + + for(i = 0; i < NB_ADDR; i++) { + if (!memcmp(macaddr, bootp_clients[i].macaddr, 6)) + goto found; + } + return NULL; + found: + bc = &bootp_clients[i]; + bc->allocated = 1; + paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + return bc; +} + static void dhcp_decode(const uint8_t *buf, int size, int *pmsg_type) { @@ -131,10 +149,19 @@ static void bootp_reply(struct bootp_t *bp) m->m_data += sizeof(struct udpiphdr); memset(rbp, 0, sizeof(struct bootp_t)); - bc = get_new_addr(&daddr.sin_addr); - if (!bc) { - dprintf("no address left\n"); - return; + if (dhcp_msg_type == DHCPDISCOVER) { + bc = get_new_addr(&daddr.sin_addr); + if (!bc) { + dprintf("no address left\n"); + return; + } + memcpy(bc->macaddr, client_ethaddr, 6); + } else { + bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); + if (!bc) { + dprintf("no address assigned\n"); + return; + } } dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr)); diff --git a/slirp/slirp.c b/slirp/slirp.c index 48b45a39c..f9c4f159e 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -74,7 +74,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) void slirp_init(void) { - debug_init("/tmp/slirp.log", DEBUG_DEFAULT); + // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); link_up = 1; -- cgit v1.2.3 From beddab753d0b3e971bfe46f165524a1c24229c29 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 5 May 2004 18:36:10 +0000 Subject: arm load/store half word fix (Ulrich Hecht) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@785 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index f405a232f..00bdbb98a 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -543,7 +543,8 @@ static void disas_arm_insn(DisasContext *s) rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; gen_movl_T1_reg(s, rn); - gen_add_datah_offset(s, insn); + if (insn & (1 << 24)) + gen_add_datah_offset(s, insn); if (insn & (1 << 20)) { /* load */ switch(sh) { -- cgit v1.2.3 From bee32909369039337b030395a63ba5d2e05fca77 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 5 May 2004 18:50:02 +0000 Subject: typo git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@786 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-mkcow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-mkcow.c b/qemu-mkcow.c index d8678a29d..ee41ec8a1 100644 --- a/qemu-mkcow.c +++ b/qemu-mkcow.c @@ -80,8 +80,8 @@ int cow_create(int cow_fd, const char *image_filename, void help(void) { - printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n" + printf("qemu-mkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + "usage: qemu-mkcow [-h] [-f disk_image] cow_image [cow_size]\n" "Create a Copy On Write disk image from an optional raw disk image\n" "\n" "-f disk_image set the raw disk image name\n" -- cgit v1.2.3 From ed5fd2cce48520e4c0d4eec016743017df93e43a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 13:14:18 +0000 Subject: timer for READ_ID (win98 floppy fix) - simpler irq handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@787 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 80 +++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index dceee8fc7..ada3ad265 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -125,17 +125,17 @@ static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect, if (track > drv->max_track || (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) { - FLOPPY_ERROR("try to read %d %02x %02x (max=%d %d %02x %02x)\n", - head, track, sect, 1, - (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, - drv->max_track, drv->last_sect); + FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n", + head, track, sect, 1, + (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, + drv->max_track, drv->last_sect); return 2; } if (sect > drv->last_sect) { - FLOPPY_ERROR("try to read %d %02x %02x (max=%d %d %02x %02x)\n", - head, track, sect, 1, - (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, - drv->max_track, drv->last_sect); + FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n", + head, track, sect, 1, + (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, + drv->max_track, drv->last_sect); return 3; } sector = _fd_sector(head, track, sect, drv->last_sect); @@ -240,8 +240,8 @@ static void fd_revalidate (fdrive_t *drv) ro = bdrv_is_read_only(drv->bs); bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect); if (nb_heads != 0 && max_track != 0 && last_sect != 0) { - printf("User defined disk (%d %d %d)", - nb_heads - 1, max_track, last_sect); + FLOPPY_DPRINTF("User defined disk (%d %d %d)", + nb_heads - 1, max_track, last_sect); } else { bdrv_get_geometry(drv->bs, &nb_sectors); match = -1; @@ -273,8 +273,8 @@ static void fd_revalidate (fdrive_t *drv) max_track = parse->max_track; last_sect = parse->last_sect; drv->drive = parse->drive; - printf("%s floppy disk (%d h %d t %d s) %s\n", parse->str, - nb_heads, max_track, last_sect, ro ? "ro" : "rw"); + FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str, + nb_heads, max_track, last_sect, ro ? "ro" : "rw"); } if (nb_heads == 1) { drv->flags &= ~FDISK_DBL_SIDES; @@ -285,7 +285,7 @@ static void fd_revalidate (fdrive_t *drv) drv->last_sect = last_sect; drv->ro = ro; } else { - printf("No disk in drive\n"); + FLOPPY_DPRINTF("No disk in drive\n"); drv->last_sect = 0; drv->max_track = 0; drv->flags &= ~FDISK_DBL_SIDES; @@ -318,6 +318,7 @@ static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq); static void fdctrl_reset_fifo (fdctrl_t *fdctrl); static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size); static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status); +static void fdctrl_result_timer(void *opaque); static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl); static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl); @@ -331,10 +332,10 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value); static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl); enum { - FD_CTRL_ACTIVE = 0x01, + FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */ FD_CTRL_RESET = 0x02, - FD_CTRL_SLEEP = 0x04, - FD_CTRL_BUSY = 0x08, + FD_CTRL_SLEEP = 0x04, /* XXX: suppress that */ + FD_CTRL_BUSY = 0x08, /* dma transfer in progress */ FD_CTRL_INTR = 0x10, }; @@ -372,6 +373,7 @@ struct fdctrl_t { int dma_chann; uint32_t io_base; /* Controler state */ + QEMUTimer *result_timer; uint8_t state; uint8_t dma_en; uint8_t cur_drv; @@ -425,6 +427,7 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) retval = (uint32_t)(-1); break; } + FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval); return retval; } @@ -433,6 +436,8 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) { fdctrl_t *fdctrl = opaque; + FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value); + switch (reg & 0x07) { case 0x02: fdctrl_write_dor(fdctrl, value); @@ -476,6 +481,9 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl = qemu_mallocz(sizeof(fdctrl_t)); if (!fdctrl) return NULL; + fdctrl->result_timer = qemu_new_timer(vm_clock, + fdctrl_result_timer, fdctrl); + fdctrl->version = 0x90; /* Intel 82078 controler */ fdctrl->irq_lvl = irq_lvl; fdctrl->dma_chann = dma_chann; @@ -524,10 +532,9 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num) /* Change IRQ state */ static void fdctrl_reset_irq (fdctrl_t *fdctrl) { - if (fdctrl->state & FD_CTRL_INTR) { - pic_set_irq(fdctrl->irq_lvl, 0); - fdctrl->state &= ~(FD_CTRL_INTR | FD_CTRL_SLEEP | FD_CTRL_BUSY); - } + FLOPPY_DPRINTF("Reset interrupt\n"); + pic_set_irq(fdctrl->irq_lvl, 0); + fdctrl->state &= ~FD_CTRL_INTR; } static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) @@ -558,7 +565,7 @@ static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq) fd_reset(&fdctrl->drives[i]); fdctrl_reset_fifo(fdctrl); if (do_irq) - fdctrl_raise_irq(fdctrl, 0x20); + fdctrl_raise_irq(fdctrl, 0xc0); } static inline fdrive_t *drv0 (fdctrl_t *fdctrl) @@ -579,9 +586,7 @@ static fdrive_t *get_cur_drv (fdctrl_t *fdctrl) /* Status B register : 0x01 (read-only) */ static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl) { - fdctrl_reset_irq(fdctrl); FLOPPY_DPRINTF("status register: 0x00\n"); - return 0; } @@ -608,7 +613,6 @@ static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl) static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) { - fdctrl_reset_irq(fdctrl); /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { if (!(value & 0x04)) { @@ -653,7 +657,6 @@ static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl) { uint32_t retval = 0; - fdctrl_reset_irq(fdctrl); /* Disk boot selection indicator */ retval |= fdctrl->bootsel << 2; /* Tape indicators: never allowed */ @@ -664,7 +667,6 @@ static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl) static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value) { - fdctrl_reset_irq(fdctrl); /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); @@ -681,7 +683,6 @@ static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl) { uint32_t retval = 0; - fdctrl_reset_irq(fdctrl); fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET); if (!(fdctrl->state & FD_CTRL_BUSY)) { /* Data transfer allowed */ @@ -703,7 +704,6 @@ static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl) /* Data select rate register : 0x04 (write) */ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) { - fdctrl_reset_irq(fdctrl); /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); @@ -728,7 +728,6 @@ static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl) { uint32_t retval = 0; - fdctrl_reset_irq(fdctrl); if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE || drv1(fdctrl)->drflags & FDRIVE_REVALIDATE) retval |= 0x80; @@ -795,8 +794,10 @@ static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, fdctrl->fifo[5] = cur_drv->sect; fdctrl->fifo[6] = FD_SECTOR_SC; fdctrl->data_dir = FD_DIR_READ; - if (fdctrl->state & FD_CTRL_BUSY) + if (fdctrl->state & FD_CTRL_BUSY) { DMA_release_DREQ(fdctrl->dma_chann); + fdctrl->state &= ~FD_CTRL_BUSY; + } fdctrl_set_fifo(fdctrl, 7, 1); } @@ -916,7 +917,6 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; fdctrl = opaque; - fdctrl_reset_irq(fdctrl); if (!(fdctrl->state & FD_CTRL_BUSY)) { FLOPPY_DPRINTF("Not in DMA transfer mode !\n"); return 0; @@ -1049,7 +1049,6 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) uint32_t retval = 0; int pos, len; - fdctrl_reset_irq(fdctrl); cur_drv = get_cur_drv(fdctrl); fdctrl->state &= ~FD_CTRL_SLEEP; if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) { @@ -1073,10 +1072,12 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) /* Switch from transfert mode to status mode * then from status mode to command mode */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) + if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); - else + } else { fdctrl_reset_fifo(fdctrl); + fdctrl_reset_irq(fdctrl); + } } FLOPPY_DPRINTF("data register: 0x%02x\n", retval); @@ -1152,7 +1153,6 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) { fdrive_t *cur_drv; - fdctrl_reset_irq(fdctrl); cur_drv = get_cur_drv(fdctrl); /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { @@ -1583,7 +1583,9 @@ enqueue: case 0x4A: /* READ_ID */ FLOPPY_DPRINTF("treat READ_ID command\n"); - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); + /* XXX: should set main status register to busy */ + qemu_mod_timer(fdctrl->result_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); break; case 0x4C: /* RESTORE */ @@ -1688,3 +1690,9 @@ enqueue: } } } + +static void fdctrl_result_timer(void *opaque) +{ + fdctrl_t *fdctrl = opaque; + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); +} -- cgit v1.2.3 From a1b74fe8fea8ff7b48a6339407451ceca02b8c5e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 13:26:35 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@788 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 +++- VERSION | 2 +- qemu-doc.texi | 24 ++++++++++++++++-------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Changelog b/Changelog index 86d9d9277..bd72f9704 100644 --- a/Changelog +++ b/Changelog @@ -3,8 +3,10 @@ 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 timer bug) + - 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: diff --git a/VERSION b/VERSION index 167b000b4..389faccca 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.4 \ No newline at end of file +0.5.5 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index 9dd02edd2..e769879d1 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -297,22 +297,30 @@ Do not start CPU at startup (you must type 'c' in the monitor). Output log in /tmp/qemu.log @end table +During the graphical emulation, you can use the following keys: +@table @key +@item Ctrl+Shift +Toggle mouse and keyboard grab. +@item Ctrl+Shift-f +Toggle full screen +@end table + During emulation, if you are using the serial console, use @key{C-a h} to get terminal commands: @table @key -@item C-a h +@item Ctrl-a h Print this help -@item C-a x +@item Ctrl-a x Exit emulatior -@item C-a s +@item Ctrl-a s Save disk data back to file (if -snapshot) -@item C-a b +@item Ctrl-a b Send break (magic sysrq in Linux) -@item C-a c +@item Ctrl-a c Switch between console and monitor -@item C-a C-a -Send C-a +@item Ctrl-a Ctrl-a +Send Ctrl-a @end table @c man end @@ -490,7 +498,7 @@ CPU registers by prefixing them with @emph{$}. The disk images can simply be raw images of the hard disk. You can create them with the command: @example -dd if=/dev/zero of=myimage bs=1024 count=mysize +dd of=myimage bs=1024 seek=mysize count=0 @end example where @var{myimage} is the image filename and @var{mysize} is its size in kilobytes. -- cgit v1.2.3 From 1f50f8d1d4b7c3c6e86b149e1beba12da0b9cd27 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 14:44:43 +0000 Subject: better install git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@789 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 13 +++++++++++-- configure | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index df44a5e61..808608da7 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,9 @@ DEFINES+=-D_GNU_SOURCE ifndef CONFIG_WIN32 TOOLS=qemu-mkcow endif +ifdef CONFIG_STATIC +LDFLAGS+=-static +endif all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1 for d in $(TARGET_DIRS); do \ @@ -17,7 +20,7 @@ all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1 done qemu-mkcow: qemu-mkcow.c - $(CC) $(CFLAGS) $(DEFINES) -o $@ $^ $(LIBS) + $(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS) dyngen$(EXESUF): dyngen.c $(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^ @@ -45,6 +48,8 @@ endif mkdir -p "$(sharedir)" install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/linux_boot.bin "$(sharedir)" + mkdir -p "$(docdir)" + install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" ifndef CONFIG_WIN32 mkdir -p "$(mandir)/man1" install qemu.1 qemu-mkcow.1 "$(mandir)/man1" @@ -86,9 +91,13 @@ tarbin: $(prefix)/bin/qemu-arm \ $(prefix)/bin/qemu-sparc \ $(prefix)/bin/qemu-ppc \ + $(prefix)/bin/qemu-mkcow \ $(sharedir)/bios.bin \ $(sharedir)/vgabios.bin \ - $(mandir)/man1/qemu.1 ) + $(sharedir)/linux_boot.bin \ + $(docdir)/qemu-doc.html \ + $(docdir)/qemu-tech.html \ + $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-mkcow.1 ) ifneq ($(wildcard .depend),) include .depend diff --git a/configure b/configure index 4facab5fd..843e1490f 100755 --- a/configure +++ b/configure @@ -266,6 +266,7 @@ if test -z "$prefix" ; then fi mandir="$prefix" sharedir="$prefix" +docdir="$prefix" bindir="$prefix" else if test -z "$prefix" ; then @@ -273,6 +274,7 @@ if test -z "$prefix" ; then fi mandir="$prefix/share/man" sharedir="$prefix/share/qemu" +docdir="$prefix/share/doc/qemu" bindir="$prefix/bin" fi @@ -314,6 +316,7 @@ echo "prefix=$prefix" >> $config_mak echo "bindir=$bindir" >> $config_mak echo "mandir=$mandir" >> $config_mak echo "sharedir=$sharedir" >> $config_mak +echo "docdir=$docdir" >> $config_mak echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h echo "MAKE=$make" >> $config_mak echo "CC=$cc" >> $config_mak -- cgit v1.2.3 From 2b64948eb5ff24d2aed530b2fc5a25217cdc72f7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 15:27:20 +0000 Subject: 64 bit fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@790 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block.c b/block.c index 5ed7a02b3..c1267888c 100644 --- a/block.c +++ b/block.c @@ -170,7 +170,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) #ifndef _WIN32 if (snapshot) { /* create a temporary COW file */ - cow_fd = mkstemp(template); + cow_fd = mkstemp64(template); if (cow_fd < 0) goto fail; bs->cow_fd = cow_fd; -- cgit v1.2.3 From 10d315a8f2ad9123aa44315cb2d6761de25cf8e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 21:00:00 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@791 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index e769879d1..cc0350772 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -299,9 +299,9 @@ Output log in /tmp/qemu.log During the graphical emulation, you can use the following keys: @table @key -@item Ctrl+Shift +@item Ctrl-Shift Toggle mouse and keyboard grab. -@item Ctrl+Shift-f +@item Ctrl-Shift-f Toggle full screen @end table -- cgit v1.2.3 From e309de25a617b683a86d6a42df4977bde22b8b26 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 21:01:23 +0000 Subject: SPECIFY command fix (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@792 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/fdc.c b/hw/fdc.c index ada3ad265..97f8805b9 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1499,7 +1499,7 @@ enqueue: /* SPECIFY */ FLOPPY_DPRINTF("treat SPECIFY command\n"); fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF; - fdctrl->timer1 = fdctrl->fifo[1] >> 1; + fdctrl->timer1 = fdctrl->fifo[2] >> 1; fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ; /* No result back */ fdctrl_reset_fifo(fdctrl); -- cgit v1.2.3 From f929aad6e397060983d5d61911110ef1e75d4af4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 21:03:41 +0000 Subject: MSDOS compatibility mode FPU exception support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@793 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index e1293aad4..239777756 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -45,6 +45,18 @@ static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { } +/* MSDOS compatibility mode FPU exception support */ +/* XXX: add IGNNE support */ +void cpu_set_ferr(CPUX86State *s) +{ + pic_set_irq(13, 1); +} + +static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) +{ + pic_set_irq(13, 0); +} + /* PC cmos mappings */ #define REG_EQUIPMENT_BYTE 0x14 @@ -371,6 +383,8 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, /* init basic PC hardware */ register_ioport_write(0x80, 1, 1, ioport80_write, NULL); + register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); + vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); -- cgit v1.2.3 From 28c3ee3fed3bb51c45320bec1ede3585cd36f8a4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 21:05:19 +0000 Subject: cr0.ET fix (Win95 boot fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@794 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 4cdde09c2..e0d917a73 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -265,7 +265,7 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) { tlb_flush(env, 1); } - env->cr[0] = new_cr0; + env->cr[0] = new_cr0 | CR0_ET_MASK; /* update PE flag in hidden flags */ pe_state = (env->cr[0] & CR0_PE_MASK); -- cgit v1.2.3 From 2ee73ac3a855fb0cfba3db91fdd1ecebdbc6f971 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 21:08:41 +0000 Subject: division by zero FPU exception support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@795 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 3 +++ target-i386/exec.h | 14 ++++++++++++++ target-i386/helper.c | 31 +++++++++++++++++++++++++++++-- target-i386/op.c | 17 +++++++++++++---- target-i386/translate.c | 5 +++++ 5 files changed, 64 insertions(+), 6 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 6b2a89bb9..6939a2c6e 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -143,6 +143,7 @@ #define CR0_MP_MASK (1 << 1) #define CR0_EM_MASK (1 << 2) #define CR0_TS_MASK (1 << 3) +#define CR0_ET_MASK (1 << 4) #define CR0_NE_MASK (1 << 5) #define CR0_WP_MASK (1 << 16) #define CR0_AM_MASK (1 << 18) @@ -373,6 +374,8 @@ CPUX86State *cpu_x86_init(void); int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); int cpu_get_pic_interrupt(CPUX86State *s); +/* MSDOS compatibility mode FPU exception support */ +void cpu_set_ferr(CPUX86State *s); /* this function must always be used to load data in the segment cache: it synchronizes the hflags with the segment cache values */ diff --git a/target-i386/exec.h b/target-i386/exec.h index 63010f745..fb9cc772f 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -478,10 +478,24 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) #endif /* USE_X86LDOUBLE */ +#define FPUS_IE (1 << 0) +#define FPUS_DE (1 << 1) +#define FPUS_ZE (1 << 2) +#define FPUS_OE (1 << 3) +#define FPUS_UE (1 << 4) +#define FPUS_PE (1 << 5) +#define FPUS_SF (1 << 6) +#define FPUS_SE (1 << 7) +#define FPUS_B (1 << 15) + +#define FPUC_EM 0x3f + const CPU86_LDouble f15rk[7]; void helper_fldt_ST0_A0(void); void helper_fstt_ST0_A0(void); +void fpu_raise_exception(void); +CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b); void helper_fbld_ST0_A0(void); void helper_fbst_ST0_A0(void); void helper_f2xm1(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 27a7a5559..f2305e32c 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -24,7 +24,7 @@ #if 0 #define raise_exception_err(a, b)\ do {\ - printf("raise_exception line=%d\n", __LINE__);\ + fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ (raise_exception_err)(a, b);\ } while (0) #endif @@ -859,10 +859,11 @@ void do_interrupt(int intno, int is_int, int error_code, if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) { if ((env->cr[0] & CR0_PE_MASK)) { static int count; - fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x SP=%04x:%08x", + fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x pc=%08x SP=%04x:%08x", count, intno, error_code, is_int, env->hflags & HF_CPL_MASK, env->segs[R_CS].selector, EIP, + (int)env->segs[R_CS].base + EIP, env->segs[R_SS].selector, ESP); if (intno == 0x0e) { fprintf(logfile, " CR2=%08x", env->cr[2]); @@ -1990,6 +1991,32 @@ void helper_fstt_ST0_A0(void) helper_fstt(ST0, (uint8_t *)A0); } +void fpu_set_exception(int mask) +{ + env->fpus |= mask; + if (env->fpus & (~env->fpuc & FPUC_EM)) + env->fpus |= FPUS_SE | FPUS_B; +} + +CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) +{ + if (b == 0.0) + fpu_set_exception(FPUS_ZE); + return a / b; +} + +void fpu_raise_exception(void) +{ + if (env->cr[0] & CR0_NE_MASK) { + raise_exception(EXCP10_COPR); + } +#if !defined(CONFIG_USER_ONLY) + else { + cpu_set_ferr(env); + } +#endif +} + /* BCD ops */ void helper_fbld_ST0_A0(void) diff --git a/target-i386/op.c b/target-i386/op.c index 1169f121a..37823319d 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1738,12 +1738,12 @@ void OPPROTO op_fsubr_ST0_FT0(void) void OPPROTO op_fdiv_ST0_FT0(void) { - ST0 /= FT0; + ST0 = helper_fdiv(ST0, FT0); } void OPPROTO op_fdivr_ST0_FT0(void) { - ST0 = FT0 / ST0; + ST0 = helper_fdiv(FT0, ST0); } /* fp operations between STN and ST0 */ @@ -1772,14 +1772,16 @@ void OPPROTO op_fsubr_STN_ST0(void) void OPPROTO op_fdiv_STN_ST0(void) { - ST(PARAM1) /= ST0; + CPU86_LDouble *p; + p = &ST(PARAM1); + *p = helper_fdiv(*p, ST0); } void OPPROTO op_fdivr_STN_ST0(void) { CPU86_LDouble *p; p = &ST(PARAM1); - *p = ST0 / *p; + *p = helper_fdiv(ST0, *p); } /* misc FPU operations */ @@ -1959,6 +1961,13 @@ void OPPROTO op_fclex(void) env->fpus &= 0x7f00; } +void OPPROTO op_fwait(void) +{ + if (env->fpus & FPUS_SE) + fpu_raise_exception(); + FORCE_RET(); +} + void OPPROTO op_fninit(void) { env->fpus = 0; diff --git a/target-i386/translate.c b/target-i386/translate.c index a1a4c633d..c6aa5030e 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3761,6 +3761,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == (HF_MP_MASK | HF_TS_MASK)) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_fwait(); } break; case 0xcc: /* int3 */ -- cgit v1.2.3 From 44c513c4c9660b594a6934faecf4a7420805cb62 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 May 2004 21:24:35 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@796 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changelog b/Changelog index bd72f9704..64c175d14 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,8 @@ +version 0.5.6: + + - minimalist FPU exception support (NetBSD FPU probe fix) + - cr0.ET fix (Win95 boot) + version 0.5.5: - SDL full screen support (initial patch by malc) -- cgit v1.2.3 From 7efa43875d6f0f476f6e8d6af08087d4f295afcf Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 May 2004 18:54:06 +0000 Subject: better packaging support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@797 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 24 ++++++++++++------------ configure | 10 +++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 808608da7..7645c0857 100644 --- a/Makefile +++ b/Makefile @@ -45,9 +45,9 @@ install: all ifndef CONFIG_WIN32 install -m 755 -s $(TOOLS) "$(bindir)" endif - mkdir -p "$(sharedir)" + mkdir -p "$(datadir)" install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ - pc-bios/linux_boot.bin "$(sharedir)" + pc-bios/linux_boot.bin "$(datadir)" mkdir -p "$(docdir)" install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" ifndef CONFIG_WIN32 @@ -85,16 +85,16 @@ tar: # generate a binary distribution tarbin: ( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \ - $(prefix)/bin/qemu $(prefix)/bin/qemu-fast \ - $(prefix)/bin/qemu-system-ppc \ - $(prefix)/bin/qemu-i386 \ - $(prefix)/bin/qemu-arm \ - $(prefix)/bin/qemu-sparc \ - $(prefix)/bin/qemu-ppc \ - $(prefix)/bin/qemu-mkcow \ - $(sharedir)/bios.bin \ - $(sharedir)/vgabios.bin \ - $(sharedir)/linux_boot.bin \ + $(bindir)/qemu $(bindir)/qemu-fast \ + $(bindir)/qemu-system-ppc \ + $(bindir)/qemu-i386 \ + $(bindir)/qemu-arm \ + $(bindir)/qemu-sparc \ + $(bindir)/qemu-ppc \ + $(bindir)/qemu-mkcow \ + $(datadir)/bios.bin \ + $(datadir)/vgabios.bin \ + $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-mkcow.1 ) diff --git a/configure b/configure index 843e1490f..765b23428 100755 --- a/configure +++ b/configure @@ -265,7 +265,7 @@ if test -z "$prefix" ; then prefix="/c/Program Files/Qemu" fi mandir="$prefix" -sharedir="$prefix" +datadir="$prefix" docdir="$prefix" bindir="$prefix" else @@ -273,13 +273,13 @@ if test -z "$prefix" ; then prefix="/usr/local" fi mandir="$prefix/share/man" -sharedir="$prefix/share/qemu" +datadir="$prefix/share/qemu" docdir="$prefix/share/doc/qemu" bindir="$prefix/bin" fi echo "Install prefix $prefix" -echo "BIOS directory $sharedir" +echo "BIOS directory $datadir" echo "binary directory $bindir" if test "$mingw32" = "no" ; then echo "Manual directory $mandir" @@ -315,9 +315,9 @@ 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 "sharedir=$sharedir" >> $config_mak +echo "datadir=$datadir" >> $config_mak echo "docdir=$docdir" >> $config_mak -echo "#define CONFIG_QEMU_SHAREDIR \"$sharedir\"" >> $config_h +echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h echo "MAKE=$make" >> $config_mak echo "CC=$cc" >> $config_mak if test "$have_gcc3_options" = "yes" ; then -- cgit v1.2.3 From 8cd0ac2fe108f77027415063c145e9baa54b153d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 May 2004 19:09:16 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@798 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index cc0350772..afb61ddd6 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -61,7 +61,7 @@ tar zxvf /tmp/qemu-XXX-i386.tar.gz @end example @section Windows -w + @itemize @item Install the current versions of MSYS and MinGW from @url{http://www.mingw.org/}. You can find detailed installation -- cgit v1.2.3 From fd872598d8d8cf78c1f12ed9661baf9ac0943c04 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 May 2004 19:11:15 +0000 Subject: primitive ioport debug - /dev/rtc fast timer support (needed for better simulation accuracy with Linux 2.4) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@799 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + exec.c | 2 ++ vl.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 88 insertions(+), 6 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 145059cc1..6ee93dc39 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -636,6 +636,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr); #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 log items */ typedef struct CPULogItem { diff --git a/exec.c b/exec.c index f6d5396fa..441c5626f 100644 --- a/exec.c +++ b/exec.c @@ -1131,6 +1131,8 @@ CPULogItem cpu_log_items[] = { { CPU_LOG_PCALL, "pcall", "show protected mode far calls/returns/exceptions" }, #endif + { CPU_LOG_IOPORT, "ioport", + "show all i/o ports accesses" }, { 0, NULL, NULL }, }; diff --git a/vl.c b/vl.c index e89091d0f..05c6f0f1c 100644 --- a/vl.c +++ b/vl.c @@ -43,6 +43,7 @@ #include #include #include +#include #endif #if defined(CONFIG_SLIRP) @@ -77,6 +78,7 @@ extern void __sigaction(); #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" //#define DEBUG_UNUSED_IOPORT +//#define DEBUG_IOPORT #if !defined(CONFIG_SOFTMMU) #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) @@ -274,37 +276,67 @@ int load_image(const char *filename, uint8_t *addr) void cpu_outb(CPUState *env, int addr, int val) { addr &= (MAX_IOPORTS - 1); +#ifdef DEBUG_IOPORT + if (loglevel & CPU_LOG_IOPORT) + fprintf(logfile, "outb: %04x %02x\n", addr, val); +#endif ioport_write_table[0][addr](ioport_opaque[addr], addr, val); } void cpu_outw(CPUState *env, int addr, int val) { addr &= (MAX_IOPORTS - 1); +#ifdef DEBUG_IOPORT + if (loglevel & CPU_LOG_IOPORT) + fprintf(logfile, "outw: %04x %04x\n", addr, val); +#endif ioport_write_table[1][addr](ioport_opaque[addr], addr, val); } void cpu_outl(CPUState *env, int addr, int val) { addr &= (MAX_IOPORTS - 1); +#ifdef DEBUG_IOPORT + if (loglevel & CPU_LOG_IOPORT) + fprintf(logfile, "outl: %04x %08x\n", addr, val); +#endif ioport_write_table[2][addr](ioport_opaque[addr], addr, val); } int cpu_inb(CPUState *env, int addr) { + int val; addr &= (MAX_IOPORTS - 1); - return ioport_read_table[0][addr](ioport_opaque[addr], addr); + val = ioport_read_table[0][addr](ioport_opaque[addr], addr); +#ifdef DEBUG_IOPORT + if (loglevel & CPU_LOG_IOPORT) + fprintf(logfile, "inb : %04x %02x\n", addr, val); +#endif + return val; } int cpu_inw(CPUState *env, int addr) { + int val; addr &= (MAX_IOPORTS - 1); - return ioport_read_table[1][addr](ioport_opaque[addr], addr); + val = ioport_read_table[1][addr](ioport_opaque[addr], addr); +#ifdef DEBUG_IOPORT + if (loglevel & CPU_LOG_IOPORT) + fprintf(logfile, "inw : %04x %04x\n", addr, val); +#endif + return val; } int cpu_inl(CPUState *env, int addr) { + int val; addr &= (MAX_IOPORTS - 1); - return ioport_read_table[2][addr](ioport_opaque[addr], addr); + val = ioport_read_table[2][addr](ioport_opaque[addr], addr); +#ifdef DEBUG_IOPORT + if (loglevel & CPU_LOG_IOPORT) + fprintf(logfile, "inl : %04x %08x\n", addr, val); +#endif + return val; } /***********************************************************/ @@ -680,6 +712,34 @@ static void host_alarm_handler(int host_signum) } } +#ifndef _WIN32 + +#define RTC_FREQ 1024 + +static int rtc_fd; + +static int start_rtc_timer(void) +{ + rtc_fd = open("/dev/rtc", O_RDONLY); + if (rtc_fd < 0) + return -1; + if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { + fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n" + "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n" + "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n"); + goto fail; + } + if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) { + fail: + close(rtc_fd); + return -1; + } + pit_min_timer_count = PIT_FREQ / RTC_FREQ; + return 0; +} + +#endif + static void init_timers(void) { rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); @@ -715,7 +775,7 @@ static void init_timers(void) #endif act.sa_handler = host_alarm_handler; sigaction(SIGALRM, &act, NULL); - + itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 1000; itv.it_value.tv_sec = 0; @@ -724,8 +784,27 @@ static void init_timers(void) /* we probe the tick duration of the kernel to inform the user if the emulated kernel requested a too high timer frequency */ getitimer(ITIMER_REAL, &itv); - pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / - 1000000; + + if (itv.it_interval.tv_usec > 1000) { + /* try to use /dev/rtc to have a faster timer */ + if (start_rtc_timer() < 0) + goto use_itimer; + /* disable itimer */ + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 0; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &itv, NULL); + + /* use the RTC */ + sigaction(SIGIO, &act, NULL); + fcntl(rtc_fd, F_SETFL, O_ASYNC); + fcntl(rtc_fd, F_SETOWN, getpid()); + } else { + use_itimer: + pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * + PIT_FREQ) / 1000000; + } } #endif } -- cgit v1.2.3 From 7d3505c55aae54c9610e8be1ff476ec8849c98e6 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 May 2004 19:32:15 +0000 Subject: bsd port (Markus Niemisto) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@800 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 10 +++++----- configure | 20 ++++++++++++++++++- dyngen-exec.h | 4 ++++ gdbstub.c | 2 +- target-i386/cpu.h | 2 +- target-i386/exec.h | 6 ++++++ target-i386/op.c | 19 ++++++++++++++++++ vl.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++-------- vl.h | 8 ++++++++ 9 files changed, 111 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 7645c0857..0f64aae5a 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ endif all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1 for d in $(TARGET_DIRS); do \ - make -C $$d $@ || exit 1 ; \ + $(MAKE) -C $$d $@ || exit 1 ; \ done qemu-mkcow: qemu-mkcow.c @@ -29,9 +29,9 @@ 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 qemu.pod - make -C tests clean + $(MAKE) -C tests clean for d in $(TARGET_DIRS); do \ - make -C $$d $@ || exit 1 ; \ + $(MAKE) -C $$d $@ || exit 1 ; \ done distclean: clean @@ -55,12 +55,12 @@ ifndef CONFIG_WIN32 install qemu.1 qemu-mkcow.1 "$(mandir)/man1" endif for d in $(TARGET_DIRS); do \ - make -C $$d $@ || exit 1 ; \ + $(MAKE) -C $$d $@ || exit 1 ; \ done # various test targets test speed test2: all - make -C tests $@ + $(MAKE) -C tests $@ TAGS: etags *.[ch] tests/*.[ch] diff --git a/configure b/configure index 765b23428..055f50ee9 100755 --- a/configure +++ b/configure @@ -79,9 +79,23 @@ case $targetos in MINGW32*) mingw32="yes" ;; +FreeBSD) +bsd="yes" +;; +NetBSD) +bsd="yes" +;; +OpenBSD) +bsd="yes" +;; *) ;; esac +if [ "$bsd" = "yes" ] ; then + make="gmake" + target_list="i386-softmmu" +fi + # find source path # XXX: we assume an absolute path is given when launching configure, # except in './configure' case. @@ -373,7 +387,7 @@ fi if test "$mingw32" = "yes" ; then echo "CONFIG_WIN32=yes" >> $config_mak echo "#define CONFIG_WIN32 1" >> $config_h -else +elif test -f "/usr/include/byteswap.h" ; then echo "#define HAVE_BYTESWAP_H 1" >> $config_h fi if test "$gdbstub" = "yes" ; then @@ -402,6 +416,10 @@ echo "\"" >> $config_h echo "SRC_PATH=$source_path" >> $config_mak echo "TARGET_DIRS=$target_list" >> $config_mak +if [ "$bsd" = "yes" ] ; then + echo "#define _BSD 1" >> $config_h +fi + for target in $target_list; do target_dir="$target" diff --git a/dyngen-exec.h b/dyngen-exec.h index ea20e395d..2d5209bc8 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -59,7 +59,11 @@ extern int fprintf(FILE *, const char *, ...); extern int printf(const char *, ...); #undef NULL #define NULL 0 +#ifdef _BSD +#include +#else #include +#endif #ifdef __i386__ #define AREG0 "ebp" diff --git a/gdbstub.c b/gdbstub.c index 3560b269b..19623102d 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -532,7 +532,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) /* set short latency */ val = 1; - setsockopt(fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); s = qemu_mallocz(sizeof(GDBState)); if (!s) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 6939a2c6e..19340d257 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -259,7 +259,7 @@ enum { CC_OP_NB, }; -#if defined(__i386__) || defined(__x86_64__) +#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD) #define USE_X86LDOUBLE #endif diff --git a/target-i386/exec.h b/target-i386/exec.h index fb9cc772f..f5b03fbe5 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -17,6 +17,7 @@ * 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 "dyngen-exec.h" /* at least 4 register variables are defines */ @@ -307,8 +308,13 @@ static inline void stfl(void *ptr, float v) #define rint rintl #endif +#if !defined(_BSD) extern int lrint(CPU86_LDouble x); extern int64_t llrint(CPU86_LDouble x); +#else +#define lrint(d) ((int)rint(d)) +#define llrint(d) ((int)rint(d)) +#endif extern CPU86_LDouble fabs(CPU86_LDouble x); extern CPU86_LDouble sin(CPU86_LDouble x); extern CPU86_LDouble cos(CPU86_LDouble x); diff --git a/target-i386/op.c b/target-i386/op.c index 37823319d..fad8a730e 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1938,6 +1938,24 @@ void OPPROTO op_fldcw_A0(void) int rnd_type; env->fpuc = lduw((void *)A0); /* set rounding mode */ +#ifdef _BSD + switch(env->fpuc & RC_MASK) { + default: + case RC_NEAR: + rnd_type = FP_RN; + break; + case RC_DOWN: + rnd_type = FP_RM; + break; + case RC_UP: + rnd_type = FP_RP; + break; + case RC_CHOP: + rnd_type = FP_RZ; + break; + } + fpsetround(rnd_type); +#else switch(env->fpuc & RC_MASK) { default: case RC_NEAR: @@ -1954,6 +1972,7 @@ void OPPROTO op_fldcw_A0(void) break; } fesetround(rnd_type); +#endif } void OPPROTO op_fclex(void) diff --git a/vl.c b/vl.c index 05c6f0f1c..448905610 100644 --- a/vl.c +++ b/vl.c @@ -28,29 +28,35 @@ #include #include #include -#include #include #include #ifndef _WIN32 #include #include -#include #include #include #include #include #include +#ifdef _BSD +#include +#include +#else #include #include +#include +#include #include #endif +#endif #if defined(CONFIG_SLIRP) #include "libslirp.h" #endif #ifdef _WIN32 +#include #include #include #define getopt_long_only getopt_long @@ -58,15 +64,17 @@ #endif #ifdef CONFIG_SDL +#if defined(__linux__) /* SDL use the pthreads and they modify sigaction. We don't want that. */ -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) +#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) extern void __libc_sigaction(); #define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact) #else extern void __sigaction(); #define sigaction(sig, act, oact) __sigaction(sig, act, oact) #endif +#endif /* __linux__ */ #endif /* CONFIG_SDL */ #include "disas.h" @@ -637,11 +645,17 @@ int64_t qemu_get_clock(QEMUClock *clock) #ifdef _WIN32 return GetTickCount(); #else - /* XXX: portability among Linux hosts */ - if (timer_freq == 100) { - return times(NULL) * 10; - } else { - return ((int64_t)times(NULL) * 1000) / timer_freq; + { + struct tms tp; + + /* Note that using gettimeofday() is not a good solution + for timers because its value change when the date is + modified. */ + if (timer_freq == 100) { + return times(&tp) * 10; + } else { + return ((int64_t)times(&tp) * 1000) / timer_freq; + } } #endif default: @@ -964,7 +978,27 @@ static int net_slirp_init(NetDriverState *nd) #endif /* CONFIG_SLIRP */ #if !defined(_WIN32) +#ifdef _BSD +static int tun_open(char *ifname, int ifname_size) +{ + int fd; + char *dev; + struct stat s; + fd = open("/dev/tap", O_RDWR); + if (fd < 0) { + fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n"); + return -1; + } + + fstat(fd, &s); + dev = devname(s.st_rdev, S_IFCHR); + pstrcpy(ifname, ifname_size, dev); + + fcntl(fd, F_SETFL, O_NONBLOCK); + return fd; +} +#else static int tun_open(char *ifname, int ifname_size) { struct ifreq ifr; @@ -989,6 +1023,7 @@ static int tun_open(char *ifname, int ifname_size) fcntl(fd, F_SETFL, O_NONBLOCK); return fd; } +#endif static void tun_send_packet(NetDriverState *nd, const uint8_t *buf, int size) { @@ -2248,7 +2283,12 @@ int main(int argc, char **argv) phys_ram_size = ram_size + vga_ram_size; #ifdef CONFIG_SOFTMMU +#ifdef _BSD + /* mallocs are always aligned on BSD. */ + phys_ram_base = malloc(phys_ram_size); +#else phys_ram_base = memalign(TARGET_PAGE_SIZE, phys_ram_size); +#endif if (!phys_ram_base) { fprintf(stderr, "Could not allocate physical memory\n"); exit(1); diff --git a/vl.h b/vl.h index 639b473cd..b640ad4e7 100644 --- a/vl.h +++ b/vl.h @@ -35,6 +35,7 @@ #include #include #include +#include #ifndef O_LARGEFILE #define O_LARGEFILE 0 @@ -49,6 +50,13 @@ #include "cpu.h" +#ifdef _BSD +#define lseek64 lseek +#define ftruncate64 ftruncate +#define mkstemp64 mkstemp +#define MAP_ANONYMOUS MAP_ANON +#endif + #ifndef glue #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) -- cgit v1.2.3 From db45c29a651ee955a5aad87af4c6676bc33ef6f8 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 May 2004 19:50:26 +0000 Subject: faster I/Os - default 16 bit I/O fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@801 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/vl.c b/vl.c index 448905610..807215e76 100644 --- a/vl.c +++ b/vl.c @@ -147,15 +147,17 @@ void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data) uint32_t default_ioport_readw(void *opaque, uint32_t address) { uint32_t data; - data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](opaque, address); - data |= ioport_read_table[0][(address + 1) & (MAX_IOPORTS - 1)](opaque, address + 1) << 8; + data = ioport_read_table[0][address](ioport_opaque[address], address); + address = (address + 1) & (MAX_IOPORTS - 1); + data |= ioport_read_table[0][address](ioport_opaque[address], address) << 8; return data; } void default_ioport_writew(void *opaque, uint32_t address, uint32_t data) { - ioport_write_table[0][address & (MAX_IOPORTS - 1)](opaque, address, data & 0xff); - ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](opaque, address + 1, (data >> 8) & 0xff); + ioport_write_table[0][address](ioport_opaque[address], address, data & 0xff); + address = (address + 1) & (MAX_IOPORTS - 1); + ioport_write_table[0][address](ioport_opaque[address], address, (data >> 8) & 0xff); } uint32_t default_ioport_readl(void *opaque, uint32_t address) @@ -283,7 +285,6 @@ int load_image(const char *filename, uint8_t *addr) void cpu_outb(CPUState *env, int addr, int val) { - addr &= (MAX_IOPORTS - 1); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outb: %04x %02x\n", addr, val); @@ -293,7 +294,6 @@ void cpu_outb(CPUState *env, int addr, int val) void cpu_outw(CPUState *env, int addr, int val) { - addr &= (MAX_IOPORTS - 1); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outw: %04x %04x\n", addr, val); @@ -303,7 +303,6 @@ void cpu_outw(CPUState *env, int addr, int val) void cpu_outl(CPUState *env, int addr, int val) { - addr &= (MAX_IOPORTS - 1); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outl: %04x %08x\n", addr, val); @@ -314,7 +313,6 @@ void cpu_outl(CPUState *env, int addr, int val) int cpu_inb(CPUState *env, int addr) { int val; - addr &= (MAX_IOPORTS - 1); val = ioport_read_table[0][addr](ioport_opaque[addr], addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) @@ -326,7 +324,6 @@ int cpu_inb(CPUState *env, int addr) int cpu_inw(CPUState *env, int addr) { int val; - addr &= (MAX_IOPORTS - 1); val = ioport_read_table[1][addr](ioport_opaque[addr], addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) @@ -338,7 +335,6 @@ int cpu_inw(CPUState *env, int addr) int cpu_inl(CPUState *env, int addr) { int val; - addr &= (MAX_IOPORTS - 1); val = ioport_read_table[2][addr](ioport_opaque[addr], addr); #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) -- cgit v1.2.3 From 3a1bc175ea78fed181fae643fef47de06ce9a412 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 May 2004 19:54:43 +0000 Subject: allow '-nics 0' git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@802 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 807215e76..18f957dcc 100644 --- a/vl.c +++ b/vl.c @@ -2118,7 +2118,7 @@ int main(int argc, char **argv) break; case 16: nb_nics = atoi(optarg); - if (nb_nics < 1 || nb_nics > MAX_NICS) { + if (nb_nics < 0 || nb_nics > MAX_NICS) { fprintf(stderr, "qemu: invalid number of network interfaces\n"); exit(1); } -- cgit v1.2.3 From d6b86f4d85d71432bae9f3a0a514954dc1e33af9 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 May 2004 19:59:20 +0000 Subject: -tun-fd option fix (Renzo Davoli) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@803 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.c b/vl.c index 18f957dcc..7db288177 100644 --- a/vl.c +++ b/vl.c @@ -2078,6 +2078,7 @@ int main(int argc, char **argv) { const char *p; int fd; + net_if_type = NET_IF_TUN; if (nb_tun_fds < MAX_NICS) { fd = strtol(optarg, (char **)&p, 0); if (*p != '\0') { -- cgit v1.2.3 From b939777cecc47793fe4fc73dc77645e35c7c56eb Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 May 2004 22:07:40 +0000 Subject: floppy fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@804 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index 97f8805b9..504e9deee 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -94,10 +94,7 @@ static void fd_init (fdrive_t *drv, BlockDriverState *bs) { /* Drive */ drv->bs = bs; - if (bs) - drv->drive = FDRIVE_DRV_144; - else - drv->drive = FDRIVE_DRV_NONE; + drv->drive = FDRIVE_DRV_NONE; drv->drflags = 0; drv->perpendicular = 0; /* Disk */ -- cgit v1.2.3 From cd6f11693a3c0438fefd86af0a10b57b59d19369 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 May 2004 22:02:20 +0000 Subject: custom option parsing to have same behavior on all OSes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@805 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 273 +++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 176 insertions(+), 97 deletions(-) diff --git a/vl.c b/vl.c index 7db288177..2ad182df6 100644 --- a/vl.c +++ b/vl.c @@ -23,7 +23,6 @@ */ #include "vl.h" -#include #include #include #include @@ -1908,6 +1907,7 @@ void help(void) "-initrd file use 'file' as initial ram disk\n" "\n" "Debug/Expert options:\n" + "-S freeze CPU at startup (use 'c' to start execution)\n" "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" "-d item1,... output log to %s (use -d ? for a list of log items)\n" @@ -1937,29 +1937,85 @@ void help(void) exit(1); } -struct option long_options[] = { - { "initrd", 1, NULL, 0, }, - { "hda", 1, NULL, 0, }, - { "hdb", 1, NULL, 0, }, - { "snapshot", 0, NULL, 0, }, - { "hdachs", 1, NULL, 0, }, - { "nographic", 0, NULL, 0, }, - { "kernel", 1, NULL, 0, }, - { "append", 1, NULL, 0, }, - { "tun-fd", 1, NULL, 0, }, - { "hdc", 1, NULL, 0, }, - { "hdd", 1, NULL, 0, }, - { "cdrom", 1, NULL, 0, }, - { "boot", 1, NULL, 0, }, - { "fda", 1, NULL, 0, }, - { "fdb", 1, NULL, 0, }, - { "no-code-copy", 0, NULL, 0 }, - { "nics", 1, NULL, 0 }, - { "macaddr", 1, NULL, 0 }, - { "user-net", 0, NULL, 0 }, - { "dummy-net", 0, NULL, 0 }, - { "enable-audio", 0, NULL, 0 }, - { NULL, 0, NULL, 0 }, +#define HAS_ARG 0x0001 + +enum { + QEMU_OPTION_h, + + QEMU_OPTION_fda, + QEMU_OPTION_fdb, + QEMU_OPTION_hda, + QEMU_OPTION_hdb, + QEMU_OPTION_hdc, + QEMU_OPTION_hdd, + QEMU_OPTION_cdrom, + QEMU_OPTION_boot, + QEMU_OPTION_snapshot, + QEMU_OPTION_m, + QEMU_OPTION_nographic, + QEMU_OPTION_enable_audio, + + QEMU_OPTION_nics, + QEMU_OPTION_macaddr, + QEMU_OPTION_n, + QEMU_OPTION_tun_fd, + QEMU_OPTION_user_net, + QEMU_OPTION_dummy_net, + + QEMU_OPTION_kernel, + QEMU_OPTION_append, + QEMU_OPTION_initrd, + + QEMU_OPTION_S, + QEMU_OPTION_s, + QEMU_OPTION_p, + QEMU_OPTION_d, + QEMU_OPTION_hdachs, + QEMU_OPTION_L, + QEMU_OPTION_no_code_copy, +}; + +typedef struct QEMUOption { + const char *name; + int flags; + int index; +} QEMUOption; + +const QEMUOption qemu_options[] = { + { "h", 0, QEMU_OPTION_h }, + + { "fda", HAS_ARG, QEMU_OPTION_fda }, + { "fdb", HAS_ARG, QEMU_OPTION_fdb }, + { "hda", HAS_ARG, QEMU_OPTION_hda }, + { "hdb", HAS_ARG, QEMU_OPTION_hdb }, + { "hdc", HAS_ARG, QEMU_OPTION_hdc }, + { "hdd", HAS_ARG, QEMU_OPTION_hdd }, + { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, + { "boot", HAS_ARG, QEMU_OPTION_boot }, + { "snapshot", 0, QEMU_OPTION_snapshot }, + { "m", HAS_ARG, QEMU_OPTION_m }, + { "nographic", 0, QEMU_OPTION_nographic }, + { "enable-audio", 0, QEMU_OPTION_enable_audio }, + + { "nics", HAS_ARG, QEMU_OPTION_nics}, + { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, + { "n", HAS_ARG, QEMU_OPTION_d }, + { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, + { "user-net", 0, QEMU_OPTION_user_net }, + { "dummy-net", 0, QEMU_OPTION_dummy_net }, + + { "kernel", HAS_ARG, QEMU_OPTION_kernel }, + { "append", HAS_ARG, QEMU_OPTION_append }, + { "initrd", HAS_ARG, QEMU_OPTION_initrd }, + + { "S", 0, QEMU_OPTION_S }, + { "s", 0, QEMU_OPTION_s }, + { "p", HAS_ARG, QEMU_OPTION_p }, + { "d", HAS_ARG, QEMU_OPTION_d }, + { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, + { "L", HAS_ARG, QEMU_OPTION_L }, + { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, + { NULL }, }; #if defined (TARGET_I386) && defined(USE_CODE_COPY) @@ -1980,7 +2036,7 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB int use_gdbstub, gdbstub_port; #endif - int c, i, long_index, has_cdrom; + int i, has_cdrom; int snapshot, linux_boot; CPUState *env; const char *initrd_filename; @@ -1991,7 +2047,9 @@ int main(int argc, char **argv) int start_emulation = 1; uint8_t macaddr[6]; int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; - + int optind; + const char *r, *optarg; + #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); @@ -2026,27 +2084,53 @@ int main(int argc, char **argv) macaddr[4] = 0x34; macaddr[5] = 0x56; - + optind = 1; for(;;) { - c = getopt_long_only(argc, argv, "hm:d:n:sp:L:S", long_options, &long_index); - if (c == -1) + if (optind >= argc) break; - switch(c) { - case 0: - switch(long_index) { - case 0: + r = argv[optind]; + if (r[0] != '-') { + hd_filename[0] = argv[optind++]; + } else { + const QEMUOption *popt; + + optind++; + popt = qemu_options; + for(;;) { + if (!popt->name) { + fprintf(stderr, "%s: invalid option -- '%s'\n", + argv[0], r); + exit(1); + } + if (!strcmp(popt->name, r + 1)) + break; + popt++; + } + if (popt->flags & HAS_ARG) { + if (optind >= argc) { + fprintf(stderr, "%s: option '%s' requires an argument\n", + argv[0], r); + exit(1); + } + optarg = argv[optind++]; + } else { + optarg = NULL; + } + + switch(popt->index) { + case QEMU_OPTION_initrd: initrd_filename = optarg; break; - case 1: + case QEMU_OPTION_hda: hd_filename[0] = optarg; break; - case 2: + case QEMU_OPTION_hdb: hd_filename[1] = optarg; break; - case 3: + case QEMU_OPTION_snapshot: snapshot = 1; break; - case 4: + case QEMU_OPTION_hdachs: { const char *p; p = optarg; @@ -2065,16 +2149,16 @@ int main(int argc, char **argv) } } break; - case 5: + case QEMU_OPTION_nographic: nographic = 1; break; - case 6: + case QEMU_OPTION_kernel: kernel_filename = optarg; break; - case 7: + case QEMU_OPTION_append: kernel_cmdline = optarg; break; - case 8: + case QEMU_OPTION_tun_fd: { const char *p; int fd; @@ -2089,18 +2173,18 @@ int main(int argc, char **argv) } } break; - case 9: + case QEMU_OPTION_hdc: hd_filename[2] = optarg; has_cdrom = 0; break; - case 10: + case QEMU_OPTION_hdd: hd_filename[3] = optarg; break; - case 11: + case QEMU_OPTION_cdrom: hd_filename[2] = optarg; has_cdrom = 1; break; - case 12: + case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && boot_device != 'b' && boot_device != 'c' && boot_device != 'd') { @@ -2108,23 +2192,23 @@ int main(int argc, char **argv) exit(1); } break; - case 13: + case QEMU_OPTION_fda: fd_filename[0] = optarg; break; - case 14: + case QEMU_OPTION_fdb: fd_filename[1] = optarg; break; - case 15: + case QEMU_OPTION_no_code_copy: code_copy_enabled = 0; break; - case 16: + case QEMU_OPTION_nics: nb_nics = atoi(optarg); if (nb_nics < 0 || nb_nics > MAX_NICS) { fprintf(stderr, "qemu: invalid number of network interfaces\n"); exit(1); } break; - case 17: + case QEMU_OPTION_macaddr: { const char *p; int i; @@ -2145,70 +2229,65 @@ int main(int argc, char **argv) } } break; - case 18: + case QEMU_OPTION_user_net: net_if_type = NET_IF_USER; break; - case 19: + case QEMU_OPTION_dummy_net: net_if_type = NET_IF_DUMMY; break; - case 20: + case QEMU_OPTION_enable_audio: audio_enabled = 1; break; - } - break; - case 'h': - help(); - break; - case 'm': - ram_size = atoi(optarg) * 1024 * 1024; - if (ram_size <= 0) + case QEMU_OPTION_h: help(); - if (ram_size > PHYS_RAM_MAX_SIZE) { - fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", - PHYS_RAM_MAX_SIZE / (1024 * 1024)); - exit(1); - } - break; - case 'd': - { - int mask; - CPULogItem *item; - - mask = cpu_str_to_log_mask(optarg); - if (!mask) { - printf("Log items (comma separated):\n"); + break; + case QEMU_OPTION_m: + ram_size = atoi(optarg) * 1024 * 1024; + if (ram_size <= 0) + help(); + if (ram_size > PHYS_RAM_MAX_SIZE) { + fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", + PHYS_RAM_MAX_SIZE / (1024 * 1024)); + exit(1); + } + break; + case QEMU_OPTION_d: + { + int mask; + CPULogItem *item; + + mask = cpu_str_to_log_mask(optarg); + if (!mask) { + printf("Log items (comma separated):\n"); for(item = cpu_log_items; item->mask != 0; item++) { printf("%-10s %s\n", item->name, item->help); } exit(1); + } + cpu_set_log(mask); } - cpu_set_log(mask); - } - break; - case 'n': - pstrcpy(network_script, sizeof(network_script), optarg); - break; + break; + case QEMU_OPTION_n: + pstrcpy(network_script, sizeof(network_script), optarg); + break; #ifdef CONFIG_GDBSTUB - case 's': - use_gdbstub = 1; - break; - case 'p': - gdbstub_port = atoi(optarg); - break; + case QEMU_OPTION_s: + use_gdbstub = 1; + break; + case QEMU_OPTION_p: + gdbstub_port = atoi(optarg); + break; #endif - case 'L': - bios_dir = optarg; - break; - case 'S': - start_emulation = 0; - break; + case QEMU_OPTION_L: + bios_dir = optarg; + break; + case QEMU_OPTION_S: + start_emulation = 0; + break; + } } } - if (optind < argc) { - hd_filename[0] = argv[optind++]; - } - linux_boot = (kernel_filename != NULL); if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0' && -- cgit v1.2.3 From 1a084f3d51a66d43b65e91004f9964fe32f98323 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 May 2004 22:34:49 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@806 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index afb61ddd6..5d780be47 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -875,6 +875,44 @@ Use @code{set architecture i8086} to dump 16 bit code. Then use @code{x/10i $cs*16+*eip} to dump the code at the PC position. @end enumerate +@section Target OS specific information + +@subsection Linux + +To have access to SVGA graphic modes under X11, use the @code{vesa} +X11 driver. For optimal performances, use the same depth as your +native display. + +@subsection Windows + +If you have a slow host, using Windows 95 is better as it gives the +best speed. Windows 2000 is also a good choice. + +SVGA graphic modes support: QEMU currently supports the Bochs VESA VBE +extensions. It supports color depths of 8, 15, 16 and 32 bits per +pixel in 640x480, 800x600 and 1024x768. For optimal performances, use +the same depth as your native display. + +@itemize + +@item Windows XP: it should be automatically detected. + +@item Windows NT4 or 2000: use the driver +@url{http://www.volny.cz/xnavara/qemuvid_bin.zip} by Filip Navara. + +@item Windows 95/98/Me: no clean solution yet (but it will change +soon). You can however use the shareware driver from SciTech. Here are +the steps recommended by Christophe Bothamy on the Bochs mailing list: + +@itemize +@item install win95 with the VGA driver. +@item download sdd 7 beta from @url{http://www.majorgeeks.com/download382.html} +@item download pmhelp.vxd from @url{http://unununium.org/viewcvs/snap/redist/release/pmhelp.vxd} +@item copy pmhelp.vxd to the win95 system directory +@item install sdd7 +@end itemize +@end itemize + @chapter QEMU PREP PowerPC System emulator invocation Use the executable @file{qemu-system-ppc} to simulate a complete PREP -- cgit v1.2.3 From 3f433d2c87d666e446b1cd45c52390d61edd189b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 May 2004 14:21:17 +0000 Subject: int13 CDROM BIOS fix (aka Solaris x86 install CD fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@807 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 3 ++- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 pc-bios/bios.diff diff --git a/pc-bios/README b/pc-bios/README index 508801dce..b5f0bc9e2 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -1,4 +1,5 @@ - The PC BIOS comes from the Bochs project - (http://bochs.sourceforge.net/). + (http://bochs.sourceforge.net/). A patch from bios.diff was applied. + - The VGA BIOS comes from the LGPL VGA bios project (http://www.nongnu.org/vgabios/). diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index ae2240b2a..21ef81607 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff new file mode 100644 index 000000000..e53b8c733 --- /dev/null +++ b/pc-bios/bios.diff @@ -0,0 +1,43 @@ +Index: rombios.c +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v +retrieving revision 1.108 +diff -u -w -r1.108 rombios.c +--- rombios.c 9 Feb 2004 16:48:50 -0000 1.108 ++++ rombios.c 16 May 2004 13:44:26 -0000 +@@ -2254,6 +2254,7 @@ + type = read_byte(get_SS(),buffer+1) & 0x1f; + removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; + mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16; ++ blksize = 2048; + + write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type); + write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable); +@@ -3781,7 +3782,17 @@ + write_word(ebda_seg, 0x0022, mouse_driver_offset); + write_word(ebda_seg, 0x0024, mouse_driver_seg); + mouse_flags_2 = read_byte(ebda_seg, 0x0027); ++ if (mouse_driver_offset == 0 && ++ mouse_driver_seg == 0) { ++ /* remove handler */ ++ if ( (mouse_flags_2 & 0x80) != 0 ) { ++ mouse_flags_2 &= ~0x80; ++ inhibit_mouse_int_and_events(); // disable IRQ12 and packets ++ } ++ } else { ++ /* install handler */ + mouse_flags_2 |= 0x80; ++ } + write_byte(ebda_seg, 0x0027, mouse_flags_2); + CLEAR_CF(); + regs.u.r8.ah = 0; +@@ -4409,7 +4420,8 @@ + mouse_flags_2 = read_byte(ebda_seg, 0x0027); + + if ( (mouse_flags_2 & 0x80) != 0x80 ) { +- BX_PANIC("int74_function:\n"); ++ // BX_PANIC("int74_function:\n"); ++ return; + } + + package_count = mouse_flags_2 & 0x07; -- cgit v1.2.3 From 5b1214a48ed5564e35e367864b744d81a6d4d660 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 May 2004 15:52:12 +0000 Subject: int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@808 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 23 ++++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 21ef81607..7d87cb03c 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index e53b8c733..1ed70484c 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -4,7 +4,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.108 diff -u -w -r1.108 rombios.c --- rombios.c 9 Feb 2004 16:48:50 -0000 1.108 -+++ rombios.c 16 May 2004 13:44:26 -0000 ++++ rombios.c 16 May 2004 15:16:57 -0000 @@ -2254,6 +2254,7 @@ type = read_byte(get_SS(),buffer+1) & 0x1f; removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; @@ -13,7 +13,24 @@ diff -u -w -r1.108 rombios.c write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type); write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable); -@@ -3781,7 +3782,17 @@ +@@ -3378,6 +3379,8 @@ + and al,#0x10 + mov ah, al + ++ or ecx, ecx ++ je int1586_tick_end + int1586_tick: + in al, #0x61 + and al,#0x10 +@@ -3386,6 +3389,7 @@ + mov ah, al + dec ecx + jnz int1586_tick ++int1586_tick_end: + ASM_END + + break; +@@ -3781,7 +3785,17 @@ write_word(ebda_seg, 0x0022, mouse_driver_offset); write_word(ebda_seg, 0x0024, mouse_driver_seg); mouse_flags_2 = read_byte(ebda_seg, 0x0027); @@ -31,7 +48,7 @@ diff -u -w -r1.108 rombios.c write_byte(ebda_seg, 0x0027, mouse_flags_2); CLEAR_CF(); regs.u.r8.ah = 0; -@@ -4409,7 +4420,8 @@ +@@ -4409,7 +4423,8 @@ mouse_flags_2 = read_byte(ebda_seg, 0x0027); if ( (mouse_flags_2 & 0x80) != 0x80 ) { -- cgit v1.2.3 From 686f3f266b829b06c7b170db7b4ce97abfbfc517 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 May 2004 15:56:04 +0000 Subject: BSR/BSF undefined behaviour fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@809 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_template.h | 4 ++-- target-i386/translate.c | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 037c4306a..2ff1f6664 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -513,7 +513,7 @@ void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) count++; res >>= 1; } - T0 = count; + T1 = count; CC_DST = 1; /* ZF = 0 */ } else { CC_DST = 0; /* ZF = 1 */ @@ -531,7 +531,7 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) count--; res <<= 1; } - T0 = count; + T1 = count; CC_DST = 1; /* ZF = 0 */ } else { CC_DST = 0; /* ZF = 1 */ diff --git a/target-i386/translate.c b/target-i386/translate.c index c6aa5030e..514399d93 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3708,10 +3708,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + /* NOTE: in order to handle the 0 case, we must load the + result. It could be optimized with a generated jump */ + gen_op_mov_TN_reg[ot][1][reg](); gen_op_bsx_T0_cc[ot - OT_WORD][b & 1](); - /* NOTE: we always write back the result. Intel doc says it is - undefined if T0 == 0 */ - gen_op_mov_reg_T0[ot][reg](); + gen_op_mov_reg_T1[ot][reg](); s->cc_op = CC_OP_LOGICB + ot; break; /************************/ -- cgit v1.2.3 From f528bfd45d3456716bf49baa960142b3c8f32806 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 May 2004 15:57:26 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@810 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changelog b/Changelog index 64c175d14..6f8b3591e 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,12 @@ version 0.5.6: - 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 version 0.5.5: -- cgit v1.2.3 From 7f5e1452121a64380c56577c86163621f3adfd37 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 May 2004 16:02:40 +0000 Subject: BSR/BSF 'undefined behaviour' test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@811 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 27a899830..f7e268652 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -512,10 +512,12 @@ void test_mul(void) {\ int res, val, resz;\ val = op0;\ - asm("xorl %1, %1 ; " #op " %" size "2, %" size "0 ; setz %b1" \ + asm("xorl %1, %1\n"\ + "movl $0x12345678, %0\n"\ + #op " %" size "2, %" size "0 ; setz %b1" \ : "=r" (res), "=q" (resz)\ : "g" (val));\ - printf("%-10s A=%08x R=%08x %d\n", #op, val, resz ? 0 : res, resz);\ + printf("%-10s A=%08x R=%08x %d\n", #op, val, res, resz);\ } void test_bsx(void) -- cgit v1.2.3 From aedf53821fef9f662c2f4fc0a83bc09e0768ed54 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 May 2004 19:56:47 +0000 Subject: different serial number for each drive (initial patch by Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@812 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 6c92bedbb..6f0db4aaa 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -297,6 +297,7 @@ typedef struct IDEState { int64_t nb_sectors; int mult_sectors; int irq; + int drive_serial; /* ide regs */ uint8_t feature; uint8_t error; @@ -359,6 +360,7 @@ static void ide_identify(IDEState *s) { uint16_t *p; unsigned int oldsize; + char buf[20]; memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; @@ -368,7 +370,8 @@ static void ide_identify(IDEState *s) put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ put_le16(p + 5, 512); /* XXX: retired, remove ? */ put_le16(p + 6, s->sectors); - padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ + snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); + padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ put_le16(p + 20, 3); /* XXX: retired, remove ? */ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ @@ -404,12 +407,14 @@ static void ide_identify(IDEState *s) static void ide_atapi_identify(IDEState *s) { uint16_t *p; + char buf[20]; memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; /* Removable CDROM, 50us response, 12 byte packets */ put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); - padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */ + snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); + padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ put_le16(p + 20, 3); /* buffer type */ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ @@ -1432,6 +1437,7 @@ void ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1) { IDEState *s, *ide_state; + static int drive_serial = 1; int i, cylinders, heads, secs; int64_t nb_sectors; @@ -1473,6 +1479,7 @@ void ide_init(int iobase, int iobase2, int irq, bdrv_set_change_cb(s->bs, cdrom_change_cb, s); } } + s->drive_serial = drive_serial++; s->irq = irq; ide_reset(s); } -- cgit v1.2.3 From 47cea614a15371f50df11964e5642a427fed0c5b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 May 2004 20:06:42 +0000 Subject: vmdk2raw: convert VMware disk images to raw images git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@813 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 7 ++- vmdk.h | 52 ++++++++++++++++++ vmdk2raw.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 vmdk.h create mode 100644 vmdk2raw.c diff --git a/Makefile b/Makefile index 0f64aae5a..4137e9b95 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ LDFLAGS=-g LIBS= DEFINES+=-D_GNU_SOURCE ifndef CONFIG_WIN32 -TOOLS=qemu-mkcow +TOOLS=qemu-mkcow vmdk2raw endif ifdef CONFIG_STATIC LDFLAGS+=-static @@ -22,6 +22,9 @@ all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1 qemu-mkcow: qemu-mkcow.c $(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS) +vmdk2raw: vmdk2raw.c + $(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS) + dyngen$(EXESUF): dyngen.c $(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^ @@ -91,7 +94,7 @@ tarbin: $(bindir)/qemu-arm \ $(bindir)/qemu-sparc \ $(bindir)/qemu-ppc \ - $(bindir)/qemu-mkcow \ + $(bindir)/qemu-mkcow $(bindir)/vmdk2raw \ $(datadir)/bios.bin \ $(datadir)/vgabios.bin \ $(datadir)/linux_boot.bin \ diff --git a/vmdk.h b/vmdk.h new file mode 100644 index 000000000..a847f8b15 --- /dev/null +++ b/vmdk.h @@ -0,0 +1,52 @@ +/* + Copyright (C) Matthew Chapman 2003 + + 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. +*/ + +#define SECTOR_BITS 9 +#define SECTOR_SIZE (1 << SECTOR_BITS) +#define SECTOR_MASK (SECTOR_SIZE - 1) + +#define L1_BITS (SECTOR_BITS - 3) +#define L1_SIZE (1 << L1_BITS) +#define L1_MASK (L1_SIZE - 1) + +#define L2_BITS SECTOR_BITS +#define L2_SIZE (1 << L2_BITS) +#define L2_MASK (L2_SIZE - 1) + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) + +struct cowdisk_header +{ + char magic[4]; /* COWD */ + uint32_t version; + uint32_t flags; + uint32_t disk_sectors; + uint32_t granularity; + uint32_t l1dir_sector; + uint32_t l1dir_size; + uint32_t file_sectors; + uint32_t cylinders; + uint32_t heads; + uint32_t sectors_per_track; +}; + +struct cowdisk_header2 +{ + uint32_t parent_ts; + uint32_t timestamp; +}; diff --git a/vmdk2raw.c b/vmdk2raw.c new file mode 100644 index 000000000..8bf5eea38 --- /dev/null +++ b/vmdk2raw.c @@ -0,0 +1,182 @@ +/* + vmdk2raw: convert vmware images to raw disk images + Copyright (C) Net Integration Technologies 2004 + Copyright (C) Matthew Chapman 2003 + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "vmdk.h" +#include "config-host.h" + +struct cowdisk_header header; +struct cowdisk_header2 header2; +off_t disk_base, disk_limit; +unsigned int granule_size; +uint32_t l1dir[L1_SIZE]; + +unsigned int cached_l2dir; +uint32_t l2dir[L2_SIZE]; + +size_t read_physical(int fd, off64_t offset, size_t length, void *buffer) +{ + size_t n; + + if (lseek64(fd, offset, SEEK_SET) == -1) + { + perror("lseek"); + return -1; + } + + n = read(fd, buffer, length); + if (n == -1) + { + perror("read from disk"); + return -1; + } + + return n; +} + +size_t copy_virtual(int in_fd, int out_fd, off64_t offset, void *buffer, size_t length) +{ + unsigned int granule_index, granule_offset; + unsigned int l1index, l2index; + + granule_index = offset / granule_size; + granule_offset = offset % granule_size; + length = MIN(length, granule_size - granule_offset); + length = MIN(length, disk_limit - offset); + + l1index = (granule_index >> L2_BITS) & L1_MASK; + l2index = granule_index & L2_MASK; + + if (l1dir[l1index] == 0) + goto zero_fill; + + if (l1index != cached_l2dir) + { + if (read_physical(in_fd, (l1dir[l1index] << SECTOR_BITS), sizeof(l2dir), (char *)l2dir) != sizeof(l2dir)) + return 0; + + cached_l2dir = l1index; + } + + if (l2dir[l2index] == 0) + goto zero_fill; + + if (read_physical(in_fd, (l2dir[l2index] << SECTOR_BITS) + granule_offset, length, buffer) != length) + return 0; + + write(out_fd, buffer, length); + return length; + +zero_fill: + /* the last chunk of the file can not be sparse + * or the file will be truncated */ + if (offset + length < disk_limit) { + memset(buffer, 0, length); + write(out_fd, buffer, length); + } else { + if (lseek(out_fd, length, SEEK_CUR) == (off_t)-1) + perror("lseek"); + } + return length; +} + + +int open_vmdk(const char *filename) +{ + int fd = open(filename, O_RDONLY); + if (fd == -1) + { + perror(filename); + return -1; + } + + if (read(fd, &header, sizeof(header)) != sizeof(header)) + { + perror("read from disk"); + return -1; + } + + if (memcmp(header.magic, "COWD", 4) != 0) + { + fprintf(stderr, "%s is not a VMware virtual disk image\n", filename); + return -1; + } + + granule_size = header.granularity << SECTOR_BITS; + if (read_physical(fd, header.l1dir_sector << SECTOR_BITS, sizeof(l1dir), (char *)l1dir) != sizeof(l1dir)) + return -1; + + disk_limit = header.disk_sectors << SECTOR_BITS; + + cached_l2dir = -1; + return fd; +} + +void help(void) +{ + printf("vmdk2raw\n" + "usage: vmdk2raw vmware_image output_image\n" + "\n" + "vmware_image a vmware 2.x/3.x cow image\n" + "output_image the created disk image\n" + ); + exit(1); +} + +#define BUF_SIZE granule_size +void copy_disk(in_fd, out_fd) +{ + char buf[BUF_SIZE]; + off64_t i = 0; + while (i < disk_limit) { + i += copy_virtual(in_fd, out_fd, i, buf, sizeof(buf)); + } +} + +int main(int argc, char **argv) +{ + int out_fd, in_fd; + + if (argc < 3) + help(); + + in_fd = open_vmdk(argv[1]); + if (in_fd < 0) { + return -1; + } + + out_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (out_fd < 0) { + perror(argv[2]); + return -1; + } + + copy_disk(in_fd, out_fd); + close(out_fd); + return 0; +} -- cgit v1.2.3 From ef792f9ddb82cd58a24ef024b6022f6cfb9f6cd2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 May 2004 20:19:32 +0000 Subject: added CPU_INTERRUPT_TIMER git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@814 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cpu-all.h b/cpu-all.h index 6ee93dc39..0ed5d00f4 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -618,6 +618,7 @@ extern int code_copy_enabled; #define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ +#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */ void cpu_interrupt(CPUState *s, int mask); int cpu_breakpoint_insert(CPUState *env, target_ulong pc); -- cgit v1.2.3 From 13ab5daa86d3b802fc3a2e5959ecc8cb1aadd310 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 May 2004 20:21:49 +0000 Subject: NVRAM fixes (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@815 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index dd303d21f..62cd301e5 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -24,9 +24,9 @@ #include "vl.h" #include "m48t59.h" -//#define NVRAM_DEBUG +//#define DEBUG_NVRAM -#if defined(NVRAM_DEBUG) +#if defined(DEBUG_NVRAM) #define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) #else #define NVRAM_PRINTF(fmt, args...) do { } while (0) @@ -45,6 +45,7 @@ struct m48t59_t { struct QEMUTimer *alrm_timer; struct QEMUTimer *wd_timer; /* NVRAM storage */ + uint8_t lock; uint16_t addr; uint8_t *buffer; }; @@ -152,7 +153,10 @@ static void watchdog_cb (void *opaque) if (NVRAM->buffer[0x1FF7] & 0x80) { NVRAM->buffer[0x1FF7] = 0x00; NVRAM->buffer[0x1FFC] &= ~0x40; - // reset_CPU(); + /* May it be a hw CPU Reset instead ? */ + reset_requested = 1; + printf("Watchdog reset...\n"); + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } else { pic_set_irq(NVRAM->IRQ, 1); pic_set_irq(NVRAM->IRQ, 0); @@ -315,6 +319,11 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val) } break; default: + /* Check lock registers state */ + if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) + break; + if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) + break; if (NVRAM->addr < 0x1FF0 || (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { NVRAM->buffer[NVRAM->addr] = val & 0xFF; @@ -394,6 +403,11 @@ uint32_t m48t59_read (m48t59_t *NVRAM) retval = toBCD(tm.tm_year); break; default: + /* Check lock registers state */ + if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) + break; + if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) + break; if (NVRAM->addr < 0x1FF0 || (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { do_read: @@ -412,12 +426,18 @@ void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr) NVRAM->addr = addr; } +void m48t59_toggle_lock (m48t59_t *NVRAM, int lock) +{ + NVRAM->lock ^= 1 << lock; +} + /* IO access to NVRAM */ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) { m48t59_t *NVRAM = opaque; addr -= NVRAM->io_base; + NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val); switch (addr) { case 0: NVRAM->addr &= ~0x00FF; @@ -439,11 +459,20 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) static uint32_t NVRAM_readb (void *opaque, uint32_t addr) { m48t59_t *NVRAM = opaque; + uint32_t retval; - if (addr == NVRAM->io_base + 3) - return m48t59_read(NVRAM); + addr -= NVRAM->io_base; + switch (addr) { + case 3: + retval = m48t59_read(NVRAM); + break; + default: + retval = -1; + break; + } + NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval); - return 0xFF; + return retval; } /* Initialisation routine */ @@ -467,5 +496,7 @@ m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); + s->lock = 0; + return s; } -- cgit v1.2.3 From e63c59cb34fdad20f70c83dd4bfe938fb37433ab Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 May 2004 21:05:06 +0000 Subject: ppc fix (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@816 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 50d1ec158..e410cb2d1 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2004,7 +2004,6 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) gen_op_store_xer(); break; case LR: - gen_op_andi_(~0x03); gen_op_store_lr(); break; case CTR: @@ -2296,7 +2295,7 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) } /* mtsr */ -GEN_HANDLER(mtsr, 0x1F, 0x12, 0x02, 0x0010F801, PPC_SEGMENT) +GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) RET_PRIVREG(); @@ -2356,7 +2355,7 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) } /* tlbsync */ -GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFFC01, PPC_MEM) +GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(); -- cgit v1.2.3 From 158156d13df1828b9ee7def9c14688285900c2dc Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 May 2004 21:13:42 +0000 Subject: -user-net is optional - EAGAIN fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@817 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 2ad182df6..45836fea5 100644 --- a/vl.c +++ b/vl.c @@ -1820,7 +1820,7 @@ int main_loop(void) n = read(ioh->fd, buf, ioh->max_size); if (n >= 0) { ioh->fd_read(ioh->opaque, buf, n); - } else if (errno != -EAGAIN) { + } else if (errno != EAGAIN) { ioh->fd_read(ioh->opaque, NULL, -errno); } } @@ -2001,7 +2001,9 @@ const QEMUOption qemu_options[] = { { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, { "n", HAS_ARG, QEMU_OPTION_d }, { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, +#ifdef CONFIG_SLIRP { "user-net", 0, QEMU_OPTION_user_net }, +#endif { "dummy-net", 0, QEMU_OPTION_dummy_net }, { "kernel", HAS_ARG, QEMU_OPTION_kernel }, -- cgit v1.2.3 From 69b910399a3c40620a5213adaeb14a37366d97ac Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 May 2004 23:05:28 +0000 Subject: PCI support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@818 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 + Makefile.target | 2 +- hw/ide.c | 110 +++++++++++++++-- hw/ne2000.c | 152 ++++++++++++++++++++++- hw/pc.c | 37 ++++-- hw/pci.c | 367 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pci2isa.c | 107 +++++++++++++++++ hw/ppc_prep.c | 6 +- vl.c | 23 +++- vl.h | 65 +++++++++- 10 files changed, 842 insertions(+), 30 deletions(-) create mode 100644 hw/pci.c create mode 100644 hw/pci2isa.c diff --git a/Changelog b/Changelog index 6f8b3591e..c55362c28 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,9 @@ version 0.5.6: - 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 version 0.5.5: diff --git a/Makefile.target b/Makefile.target index 84f9df8a5..949af323a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -232,7 +232,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o +VL_OBJS=vl.o osdep.o block.o monitor.o pci.o pci2isa.o ifeq ($(TARGET_ARCH), i386) # Hardware support diff --git a/hw/ide.c b/hw/ide.c index 6f0db4aaa..b2d902f20 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1433,18 +1433,14 @@ static void ide_guess_geometry(IDEState *s) } } -void ide_init(int iobase, int iobase2, int irq, - BlockDriverState *hd0, BlockDriverState *hd1) +static void ide_init2(IDEState *ide_state, int irq, + BlockDriverState *hd0, BlockDriverState *hd1) { - IDEState *s, *ide_state; + IDEState *s; static int drive_serial = 1; int i, cylinders, heads, secs; int64_t nb_sectors; - ide_state = qemu_mallocz(sizeof(IDEState) * 2); - if (!ide_state) - return; - for(i = 0; i < 2; i++) { s = ide_state + i; if (i == 0) @@ -1483,6 +1479,22 @@ void ide_init(int iobase, int iobase2, int irq, s->irq = irq; ide_reset(s); } +} + +/***********************************************************/ +/* ISA IDE definitions */ + +void isa_ide_init(int iobase, int iobase2, int irq, + BlockDriverState *hd0, BlockDriverState *hd1) +{ + IDEState *ide_state; + + ide_state = qemu_mallocz(sizeof(IDEState) * 2); + if (!ide_state) + return; + + ide_init2(ide_state, irq, hd0, hd1); + register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state); register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state); if (iobase2) { @@ -1496,3 +1508,87 @@ void ide_init(int iobase, int iobase2, int irq, register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state); register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state); } + +/***********************************************************/ +/* PCI IDE definitions */ + +typedef struct PCIIDEState { + PCIDevice dev; + IDEState ide_if[4]; +} PCIIDEState; + +static uint32_t ide_read_config(PCIDevice *d, + uint32_t address, int len) +{ + uint32_t val; + val = 0; + memcpy(&val, d->config + address, len); + return val; +} + +static void ide_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + memcpy(d->config + address, &val, len); +} + +static void ide_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIIDEState *d = (PCIIDEState *)pci_dev; + IDEState *ide_state; + + if (region_num <= 3) { + ide_state = &d->ide_if[(region_num >> 1) * 2]; + if (region_num & 1) { + register_ioport_read(addr + 2, 1, 1, ide_status_read, ide_state); + register_ioport_write(addr + 2, 1, 1, ide_cmd_write, ide_state); + } else { + register_ioport_write(addr, 8, 1, ide_ioport_write, ide_state); + register_ioport_read(addr, 8, 1, ide_ioport_read, ide_state); + + /* data ports */ + register_ioport_write(addr, 2, 2, ide_data_writew, ide_state); + register_ioport_read(addr, 2, 2, ide_data_readw, ide_state); + register_ioport_write(addr, 4, 4, ide_data_writel, ide_state); + register_ioport_read(addr, 4, 4, ide_data_readl, ide_state); + } + } +} + +/* hd_table must contain 4 block drivers */ +void pci_ide_init(BlockDriverState **hd_table) +{ + PCIIDEState *d; + uint8_t *pci_conf; + + d = (PCIIDEState *)pci_register_device("IDE", sizeof(PCIIDEState), + 0, -1, + ide_read_config, + ide_write_config); + pci_conf = d->dev.config; + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x00; // fake + pci_conf[0x03] = 0x01; // fake + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE + pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic + + pci_conf[0x2c] = 0x86; // subsys vendor + pci_conf[0x2d] = 0x80; // subsys vendor + pci_conf[0x2e] = 0x00; // fake + pci_conf[0x2f] = 0x01; // fake + + pci_register_io_region((PCIDevice *)d, 0, 0x8, + PCI_ADDRESS_SPACE_IO, ide_map); + pci_register_io_region((PCIDevice *)d, 1, 0x4, + PCI_ADDRESS_SPACE_IO, ide_map); + pci_register_io_region((PCIDevice *)d, 2, 0x8, + PCI_ADDRESS_SPACE_IO, ide_map); + pci_register_io_region((PCIDevice *)d, 3, 0x4, + PCI_ADDRESS_SPACE_IO, ide_map); + + ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]); + ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]); +} diff --git a/hw/ne2000.c b/hw/ne2000.c index 5997e8865..8ecbf55fc 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -368,7 +368,7 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) } static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, - uint32_t val) + uint32_t val) { if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { @@ -382,8 +382,17 @@ static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, addr &= ~1; /* XXX: check exact behaviour if not even */ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - s->mem[addr] = val; - s->mem[addr + 1] = val >> 8; + *(uint16_t *)(s->mem + addr) = cpu_to_le16(val); + } +} + +static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, + uint32_t val) +{ + addr &= ~3; /* XXX: check exact behaviour if not even */ + if (addr < 32 || + (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { + *(uint32_t *)(s->mem + addr) = cpu_to_le32(val); } } @@ -402,12 +411,23 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr) addr &= ~1; /* XXX: check exact behaviour if not even */ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - return s->mem[addr] | (s->mem[addr + 1] << 8); + return le16_to_cpu(*(uint16_t *)(s->mem + addr)); } else { return 0xffff; } } +static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr) +{ + addr &= ~3; /* XXX: check exact behaviour if not even */ + if (addr < 32 || + (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { + return le32_to_cpu(*(uint32_t *)(s->mem + addr)); + } else { + return 0xffffffff; + } +} + static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) { NE2000State *s = opaque; @@ -468,6 +488,53 @@ static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) return ret; } +static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +{ + NE2000State *s = opaque; + +#ifdef DEBUG_NE2000 + printf("NE2000: asic writel val=0x%04x\n", val); +#endif + if (s->rcnt == 0) + return; + /* 32 bit access */ + ne2000_mem_writel(s, s->rsar, val); + s->rsar += 4; + s->rcnt -= 4; + /* wrap */ + if (s->rsar == s->stop) + s->rsar = s->start; + if (s->rcnt == 0) { + /* signal end of transfert */ + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } +} + +static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr) +{ + NE2000State *s = opaque; + int ret; + + /* 32 bit access */ + ret = ne2000_mem_readl(s, s->rsar); + s->rsar += 4; + s->rcnt -= 4; + + /* wrap */ + if (s->rsar == s->stop) + s->rsar = s->start; + if (s->rcnt == 0) { + /* signal end of transfert */ + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } +#ifdef DEBUG_NE2000 + printf("NE2000: asic readl val=0x%04x\n", ret); +#endif + return ret; +} + static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val) { /* nothing to do (end of reset pulse) */ @@ -480,7 +547,7 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) return 0; } -void ne2000_init(int base, int irq, NetDriverState *nd) +void isa_ne2000_init(int base, int irq, NetDriverState *nd) { NE2000State *s; @@ -505,3 +572,78 @@ void ne2000_init(int base, int irq, NetDriverState *nd) qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); } + +/***********************************************************/ +/* PCI NE2000 definitions */ + +typedef struct PCINE2000State { + PCIDevice dev; + NE2000State ne2000; +} PCINE2000State; + +static uint32_t ne2000_read_config(PCIDevice *d, + uint32_t address, int len) +{ + uint32_t val; + val = 0; + memcpy(&val, d->config + address, len); + return val; +} + +static void ne2000_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + memcpy(d->config + address, &val, len); +} + +static void ne2000_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCINE2000State *d = (PCINE2000State *)pci_dev; + NE2000State *s = &d->ne2000; + + register_ioport_write(addr, 16, 1, ne2000_ioport_write, s); + register_ioport_read(addr, 16, 1, ne2000_ioport_read, s); + + register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s); + register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s); + register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s); + register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s); + register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s); + register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s); + + register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s); + register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); +} + +void pci_ne2000_init(NetDriverState *nd) +{ + PCINE2000State *d; + NE2000State *s; + uint8_t *pci_conf; + + d = (PCINE2000State *)pci_register_device("NE2000", sizeof(PCINE2000State), + 0, -1, + ne2000_read_config, + ne2000_write_config); + pci_conf = d->dev.config; + pci_conf[0x00] = 0xec; // Realtek 8029 + pci_conf[0x01] = 0x10; + pci_conf[0x02] = 0x29; + pci_conf[0x03] = 0x80; + pci_conf[0x0a] = 0x00; // ethernet network controller + pci_conf[0x0b] = 0x02; + pci_conf[0x0e] = 0x00; // header_type + + /* XXX: do that in the BIOS */ + pci_conf[0x3c] = 11; // interrupt line + pci_conf[0x3d] = 1; // interrupt pin + + pci_register_io_region((PCIDevice *)d, 0, 0x100, + PCI_ADDRESS_SPACE_IO, ne2000_map); + s = &d->ne2000; + s->irq = 11; + s->nd = nd; + ne2000_reset(s); + qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); +} diff --git a/hw/pc.c b/hw/pc.c index 239777756..1139781a0 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -380,6 +380,11 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); } + if (pci_enabled) { + i440fx_init(); + piix3_init(); + } + /* init basic PC hardware */ register_ioport_write(0x80, 1, 1, ioport80_write, NULL); @@ -401,17 +406,25 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, fd = serial_open_device(); serial_init(0x3f8, 4, fd); - nb_nics1 = nb_nics; - if (nb_nics1 > NE2000_NB_MAX) - nb_nics1 = NE2000_NB_MAX; - for(i = 0; i < nb_nics1; i++) { - ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); - } + if (pci_enabled) { + for(i = 0; i < nb_nics; i++) { + pci_ne2000_init(&nd_table[i]); + } + pci_ide_init(bs_table); + } else { + nb_nics1 = nb_nics; + if (nb_nics1 > NE2000_NB_MAX) + nb_nics1 = NE2000_NB_MAX; + for(i = 0; i < nb_nics1; i++) { + isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + } - for(i = 0; i < 2; i++) { - ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], - bs_table[2 * i], bs_table[2 * i + 1]); + for(i = 0; i < 2; i++) { + isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + bs_table[2 * i], bs_table[2 * i + 1]); + } } + kbd_init(); DMA_init(); @@ -426,4 +439,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); cmos_init(ram_size, boot_device); + + /* must be done after all PCI devices are instanciated */ + /* XXX: should be done in the Bochs BIOS */ + if (pci_enabled) { + pci_bios_init(); + } } diff --git a/hw/pci.c b/hw/pci.c new file mode 100644 index 000000000..2c5f30b15 --- /dev/null +++ b/hw/pci.c @@ -0,0 +1,367 @@ +/* + * QEMU PCI bus manager + * + * 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_PCI + +typedef struct PCIBridge { + uint32_t config_reg; + PCIDevice **pci_bus[256]; +} PCIBridge; + +static PCIBridge pci_bridge; +target_phys_addr_t pci_mem_base; + +/* -1 for devfn means auto assign */ +PCIDevice *pci_register_device(const char *name, int instance_size, + int bus_num, int devfn, + PCIConfigReadFunc *config_read, + PCIConfigWriteFunc *config_write) +{ + PCIBridge *s = &pci_bridge; + PCIDevice *pci_dev, **bus; + + if (!s->pci_bus[bus_num]) { + s->pci_bus[bus_num] = qemu_mallocz(256 * sizeof(PCIDevice *)); + if (!s->pci_bus[bus_num]) + return NULL; + } + bus = s->pci_bus[bus_num]; + if (devfn < 0) { + for(devfn = 0 ; devfn < 256; devfn += 8) { + if (!bus[devfn]) + goto found; + } + return NULL; + found: ; + } + pci_dev = qemu_mallocz(instance_size); + if (!pci_dev) + return NULL; + pci_dev->bus_num = bus_num; + pci_dev->devfn = devfn; + pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); + pci_dev->config_read = config_read; + pci_dev->config_write = config_write; + bus[devfn] = pci_dev; + return pci_dev; +} + +void pci_register_io_region(PCIDevice *pci_dev, int region_num, + uint32_t size, int type, + PCIMapIORegionFunc *map_func) +{ + PCIIORegion *r; + + if ((unsigned int)region_num >= 6) + return; + r = &pci_dev->io_regions[region_num]; + r->addr = -1; + r->size = size; + r->type = type; + r->map_func = map_func; +} + +static void pci_config_writel(void* opaque, uint32_t addr, uint32_t val) +{ + PCIBridge *s = opaque; + s->config_reg = val; +} + +static uint32_t pci_config_readl(void* opaque, uint32_t addr) +{ + PCIBridge *s = opaque; + return s->config_reg; +} + +static void unmap_region(PCIIORegion *r) +{ + if (r->addr == -1) + return; +#ifdef DEBUG_PCI + printf("unmap addr=%08x size=%08x\n", r->addr, r->size); +#endif + if (r->type & PCI_ADDRESS_SPACE_IO) { + isa_unassign_ioport(r->addr, r->size); + } else { + cpu_register_physical_memory(r->addr + pci_mem_base, r->size, + IO_MEM_UNASSIGNED); + } +} + +static void pci_data_write(void *opaque, uint32_t addr, + uint32_t val, int len) +{ + PCIBridge *s = opaque; + PCIDevice **bus, *pci_dev; + int config_addr, reg; + +#if defined(DEBUG_PCI) && 0 + printf("pci_data_write: addr=%08x val=%08x len=%d\n", + s->config_reg, val, len); +#endif + if (!(s->config_reg & (1 << 31))) { + return; + } + if ((s->config_reg & 0x3) != 0) { + return; + } + bus = s->pci_bus[(s->config_reg >> 16) & 0xff]; + if (!bus) + return; + pci_dev = bus[(s->config_reg >> 8) & 0xff]; + if (!pci_dev) + return; + config_addr = (s->config_reg & 0xfc) | (addr & 3); + +#if defined(DEBUG_PCI) + printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", + pci_dev->name, config_addr, val, len); +#endif + if (len == 4 && (config_addr >= 0x10 && config_addr < 0x10 + 4 * 6)) { + PCIIORegion *r; + reg = (config_addr - 0x10) >> 2; + r = &pci_dev->io_regions[reg]; + if (r->size == 0) + goto default_config; + if (val != 0xffffffff && val != 0) { + /* XXX: the memory assignment should be global to handle + overlaps, but it is not needed at this stage */ + /* first unmap the old region */ + unmap_region(r); + /* change the address */ + if (r->type & PCI_ADDRESS_SPACE_IO) + r->addr = val & ~0x3; + else + r->addr = val & ~0xf; +#ifdef DEBUG_PCI + printf("map addr=%08x size=%08x type=%d\n", + r->addr, r->size, r->type); +#endif + r->map_func(pci_dev, reg, r->addr, r->size, r->type); + } + /* now compute the stored value */ + val &= ~(r->size - 1); + val |= r->type; + *(uint32_t *)(pci_dev->config + 0x10 + reg * 4) = cpu_to_le32(val); + } else { + default_config: + pci_dev->config_write(pci_dev, config_addr, val, len); + } +} + +static uint32_t pci_data_read(void *opaque, uint32_t addr, + int len) +{ + PCIBridge *s = opaque; + PCIDevice **bus, *pci_dev; + int config_addr; + uint32_t val; + + if (!(s->config_reg & (1 << 31))) + goto fail; + if ((s->config_reg & 0x3) != 0) + goto fail; + bus = s->pci_bus[(s->config_reg >> 16) & 0xff]; + if (!bus) + goto fail; + pci_dev = bus[(s->config_reg >> 8) & 0xff]; + if (!pci_dev) { + fail: + val = 0; + goto the_end; + } + config_addr = (s->config_reg & 0xfc) | (addr & 3); + val = pci_dev->config_read(pci_dev, config_addr, len); +#if defined(DEBUG_PCI) + printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n", + pci_dev->name, config_addr, val, len); +#endif + the_end: +#if defined(DEBUG_PCI) && 0 + printf("pci_data_read: addr=%08x val=%08x len=%d\n", + s->config_reg, val, len); +#endif + return val; +} + +static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val) +{ + pci_data_write(opaque, addr, val, 1); +} + +static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val) +{ + pci_data_write(opaque, addr, val, 2); +} + +static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val) +{ + pci_data_write(opaque, addr, val, 4); +} + +static uint32_t pci_data_readb(void* opaque, uint32_t addr) +{ + return pci_data_read(opaque, addr, 1); +} + +static uint32_t pci_data_readw(void* opaque, uint32_t addr) +{ + return pci_data_read(opaque, addr, 2); +} + +static uint32_t pci_data_readl(void* opaque, uint32_t addr) +{ + return pci_data_read(opaque, addr, 4); +} + +/* i440FX PCI bridge */ + +static uint32_t i440_read_config(PCIDevice *d, + uint32_t address, int len) +{ + uint32_t val; + val = 0; + memcpy(&val, d->config + address, len); + return val; +} + +static void i440_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + memcpy(d->config + address, &val, len); +} + +void i440fx_init(void) +{ + PCIBridge *s = &pci_bridge; + PCIDevice *d; + + register_ioport_write(0xcf8, 4, 4, pci_config_writel, s); + register_ioport_read(0xcf8, 4, 4, pci_config_readl, s); + + register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); + register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); + register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); + register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); + register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); + register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); + + d = pci_register_device("i440FX", sizeof(PCIDevice), 0, 0, + i440_read_config, i440_write_config); + + d->config[0x00] = 0x86; // vendor_id + d->config[0x01] = 0x80; + d->config[0x02] = 0x37; // device_id + d->config[0x03] = 0x12; + d->config[0x08] = 0x02; // revision + d->config[0x0a] = 0x04; // class_sub = pci2pci + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0c] = 0x01; // line_size in 32 bit words + d->config[0x0e] = 0x01; // header_type +} + +/* NOTE: the following should be done by the BIOS */ + +static uint32_t pci_bios_io_addr; +static uint32_t pci_bios_mem_addr; + +static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) +{ + PCIBridge *s = &pci_bridge; + PCIIORegion *r; + + s->config_reg = 0x80000000 | (d->bus_num << 16) | + (d->devfn << 8) | (0x10 + region_num * 4); + pci_data_write(s, 0, addr, 4); + r = &d->io_regions[region_num]; + + /* enable memory mappings */ + if (r->type & PCI_ADDRESS_SPACE_IO) + d->config[0x04] |= 1; + else + d->config[0x04] |= 2; +} + + +static void pci_bios_init_device(PCIDevice *d) +{ + int class; + PCIIORegion *r; + uint32_t *paddr; + int i; + + class = d->config[0x0a] | (d->config[0x0b] << 8); + switch(class) { + case 0x0101: + /* IDE: we map it as in ISA mode */ + pci_set_io_region_addr(d, 0, 0x1f0); + pci_set_io_region_addr(d, 1, 0x3f4); + pci_set_io_region_addr(d, 2, 0x170); + pci_set_io_region_addr(d, 3, 0x374); + break; + default: + /* default memory mappings */ + for(i = 0; i < 6; i++) { + r = &d->io_regions[i]; + if (r->size) { + if (r->type & PCI_ADDRESS_SPACE_IO) + paddr = &pci_bios_io_addr; + else + paddr = &pci_bios_mem_addr; + *paddr = (*paddr + r->size - 1) & ~(r->size - 1); + pci_set_io_region_addr(d, i, *paddr); + *paddr += r->size; + } + } + break; + } +} + +/* + * This function initializes the PCI devices as a normal PCI BIOS + * would do. It is provided just in case the BIOS has no support for + * PCI. + */ +void pci_bios_init(void) +{ + PCIBridge *s = &pci_bridge; + PCIDevice **bus; + int bus_num, devfn; + + pci_bios_io_addr = 0xc000; + pci_bios_mem_addr = 0xf0000000; + + for(bus_num = 0; bus_num < 256; bus_num++) { + bus = s->pci_bus[bus_num]; + if (bus) { + for(devfn = 0; devfn < 256; devfn++) { + if (bus[devfn]) + pci_bios_init_device(bus[devfn]); + } + } + } +} + + diff --git a/hw/pci2isa.c b/hw/pci2isa.c new file mode 100644 index 000000000..939a90db4 --- /dev/null +++ b/hw/pci2isa.c @@ -0,0 +1,107 @@ +/* + * QEMU PCI to ISA bridge + * + * 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_PCI + +typedef struct PIIX3State { + PCIDevice dev; + uint8_t elcr1; + uint8_t elcr2; +} PIIX3State; + +static void piix3_reset(PIIX3State *d) +{ + uint8_t *pci_conf = d->dev.config; + + pci_conf[0x04] = 0x07; // master, memory and I/O + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x00; + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium + pci_conf[0x4c] = 0x4d; + pci_conf[0x4e] = 0x03; + pci_conf[0x4f] = 0x00; + pci_conf[0x60] = 0x80; + pci_conf[0x69] = 0x02; + pci_conf[0x70] = 0x80; + pci_conf[0x76] = 0x0c; + pci_conf[0x77] = 0x0c; + pci_conf[0x78] = 0x02; + pci_conf[0x79] = 0x00; + pci_conf[0x80] = 0x00; + pci_conf[0x82] = 0x00; + pci_conf[0xa0] = 0x08; + pci_conf[0xa0] = 0x08; + pci_conf[0xa2] = 0x00; + pci_conf[0xa3] = 0x00; + pci_conf[0xa4] = 0x00; + pci_conf[0xa5] = 0x00; + pci_conf[0xa6] = 0x00; + pci_conf[0xa7] = 0x00; + pci_conf[0xa8] = 0x0f; + pci_conf[0xaa] = 0x00; + pci_conf[0xab] = 0x00; + pci_conf[0xac] = 0x00; + pci_conf[0xae] = 0x00; + + d->elcr1 = 0x00; + d->elcr2 = 0x00; +} + +static uint32_t piix3_read_config(PCIDevice *d, + uint32_t address, int len) +{ + uint32_t val; + val = 0; + memcpy(&val, d->config + address, len); + return val; +} + +static void piix3_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + memcpy(d->config + address, &val, len); +} + +void piix3_init(void) +{ + PIIX3State *d; + uint8_t *pci_conf; + + d = (PIIX3State *)pci_register_device("PIIX3", sizeof(PIIX3State), + 0, -1, + piix3_read_config, + piix3_write_config); + pci_conf = d->dev.config; + + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) + pci_conf[0x03] = 0x70; + pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA + pci_conf[0x0b] = 0x06; // class_base = PCI_bridge + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic + + piix3_reset(d); +} diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 8499ba3d1..02c7f0d45 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -962,13 +962,13 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; for(i = 0; i < nb_nics1; i++) { - ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); } #endif for(i = 0; i < 2; i++) { - ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], - bs_table[2 * i], bs_table[2 * i + 1]); + isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + bs_table[2 * i], bs_table[2 * i + 1]); } kbd_init(); AUD_init(); diff --git a/vl.c b/vl.c index 45836fea5..baa09e58a 100644 --- a/vl.c +++ b/vl.c @@ -121,6 +121,7 @@ SerialState *serial_console; QEMUTimer *gui_timer; int vm_running; int audio_enabled = 0; +int pci_enabled = 0; /***********************************************************/ /* x86 ISA bus support */ @@ -238,6 +239,21 @@ int register_ioport_write(int start, int length, int size, return 0; } +void isa_unassign_ioport(int start, int length) +{ + int i; + + for(i = start; i < start + length; i++) { + ioport_read_table[0][i] = default_ioport_readb; + ioport_read_table[1][i] = default_ioport_readw; + ioport_read_table[2][i] = default_ioport_readl; + + ioport_write_table[0][i] = default_ioport_writeb; + ioport_write_table[1][i] = default_ioport_writew; + ioport_write_table[2][i] = default_ioport_writel; + } +} + void pstrcpy(char *buf, int buf_size, const char *str) { int c; @@ -1973,6 +1989,7 @@ enum { QEMU_OPTION_hdachs, QEMU_OPTION_L, QEMU_OPTION_no_code_copy, + QEMU_OPTION_pci, }; typedef struct QEMUOption { @@ -1999,7 +2016,7 @@ const QEMUOption qemu_options[] = { { "nics", HAS_ARG, QEMU_OPTION_nics}, { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, - { "n", HAS_ARG, QEMU_OPTION_d }, + { "n", HAS_ARG, QEMU_OPTION_n }, { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, #ifdef CONFIG_SLIRP { "user-net", 0, QEMU_OPTION_user_net }, @@ -2017,6 +2034,7 @@ const QEMUOption qemu_options[] = { { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, { "L", HAS_ARG, QEMU_OPTION_L }, { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, + { "pci", 0, QEMU_OPTION_pci }, { NULL }, }; @@ -2286,6 +2304,9 @@ int main(int argc, char **argv) case QEMU_OPTION_S: start_emulation = 0; break; + case QEMU_OPTION_pci: + pci_enabled = 1; + break; } } } diff --git a/vl.h b/vl.h index b640ad4e7..0cac4abd2 100644 --- a/vl.h +++ b/vl.h @@ -218,7 +218,7 @@ typedef void QEMUTimerCB(void *opaque); /* The real time clock should be used only for stuff which does not change the virtual machine state, as it is run even if the virtual - machine is stopped. The real time clock has a frequency or 1000 + machine is stopped. The real time clock has a frequency of 1000 Hz. */ extern QEMUClock *rt_clock; @@ -360,6 +360,61 @@ int register_ioport_read(int start, int length, int size, IOPortReadFunc *func, void *opaque); int register_ioport_write(int start, int length, int size, IOPortWriteFunc *func, void *opaque); +void isa_unassign_ioport(int start, int length); + +/* PCI bus */ + +extern int pci_enabled; + +extern target_phys_addr_t pci_mem_base; + +typedef struct PCIDevice PCIDevice; + +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, + uint32_t address, uint32_t data, int len); +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, + uint32_t address, int len); +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type); + +#define PCI_ADDRESS_SPACE_MEM 0x00 +#define PCI_ADDRESS_SPACE_IO 0x01 +#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08 + +typedef struct PCIIORegion { + uint32_t addr; + uint32_t size; + uint8_t type; + PCIMapIORegionFunc *map_func; +} PCIIORegion; + +struct PCIDevice { + /* PCI config space */ + uint8_t config[256]; + + /* the following fields are read only */ + int bus_num; + int devfn; + char name[64]; + PCIIORegion io_regions[6]; + + /* do not access the following fields */ + PCIConfigReadFunc *config_read; + PCIConfigWriteFunc *config_write; +}; + +PCIDevice *pci_register_device(const char *name, int instance_size, + int bus_num, int devfn, + PCIConfigReadFunc *config_read, + PCIConfigWriteFunc *config_write); + +void pci_register_io_region(PCIDevice *pci_dev, int region_num, + uint32_t size, int type, + PCIMapIORegionFunc *map_func); + +void i440fx_init(void); +void piix3_init(void); +void pci_bios_init(void); /* vga.c */ @@ -397,8 +452,9 @@ void sdl_display_init(DisplayState *ds); extern BlockDriverState *bs_table[MAX_DISKS]; -void ide_init(int iobase, int iobase2, int irq, - BlockDriverState *hd0, BlockDriverState *hd1); +void isa_ide_init(int iobase, int iobase2, int irq, + BlockDriverState *hd0, BlockDriverState *hd1); +void pci_ide_init(BlockDriverState **hd_table); /* oss.c */ typedef enum { @@ -446,7 +502,8 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); /* ne2000.c */ -void ne2000_init(int base, int irq, NetDriverState *nd); +void isa_ne2000_init(int base, int irq, NetDriverState *nd); +void pci_ne2000_init(NetDriverState *nd); /* pckbd.c */ -- cgit v1.2.3 From 69135b5c04541a8f130a374ae2c063eeeca873e3 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:40:26 +0000 Subject: suppressed pci2isa.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@819 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/pci2isa.c | 107 -------------------------------------------------------- 2 files changed, 1 insertion(+), 108 deletions(-) delete mode 100644 hw/pci2isa.c diff --git a/Makefile.target b/Makefile.target index 949af323a..0abe89494 100644 --- a/Makefile.target +++ b/Makefile.target @@ -232,7 +232,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o pci.o pci2isa.o +VL_OBJS=vl.o osdep.o block.o monitor.o pci.o ifeq ($(TARGET_ARCH), i386) # Hardware support diff --git a/hw/pci2isa.c b/hw/pci2isa.c deleted file mode 100644 index 939a90db4..000000000 --- a/hw/pci2isa.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * QEMU PCI to ISA bridge - * - * 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_PCI - -typedef struct PIIX3State { - PCIDevice dev; - uint8_t elcr1; - uint8_t elcr2; -} PIIX3State; - -static void piix3_reset(PIIX3State *d) -{ - uint8_t *pci_conf = d->dev.config; - - pci_conf[0x04] = 0x07; // master, memory and I/O - pci_conf[0x05] = 0x00; - pci_conf[0x06] = 0x00; - pci_conf[0x07] = 0x02; // PCI_status_devsel_medium - pci_conf[0x4c] = 0x4d; - pci_conf[0x4e] = 0x03; - pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x80; - pci_conf[0x69] = 0x02; - pci_conf[0x70] = 0x80; - pci_conf[0x76] = 0x0c; - pci_conf[0x77] = 0x0c; - pci_conf[0x78] = 0x02; - pci_conf[0x79] = 0x00; - pci_conf[0x80] = 0x00; - pci_conf[0x82] = 0x00; - pci_conf[0xa0] = 0x08; - pci_conf[0xa0] = 0x08; - pci_conf[0xa2] = 0x00; - pci_conf[0xa3] = 0x00; - pci_conf[0xa4] = 0x00; - pci_conf[0xa5] = 0x00; - pci_conf[0xa6] = 0x00; - pci_conf[0xa7] = 0x00; - pci_conf[0xa8] = 0x0f; - pci_conf[0xaa] = 0x00; - pci_conf[0xab] = 0x00; - pci_conf[0xac] = 0x00; - pci_conf[0xae] = 0x00; - - d->elcr1 = 0x00; - d->elcr2 = 0x00; -} - -static uint32_t piix3_read_config(PCIDevice *d, - uint32_t address, int len) -{ - uint32_t val; - val = 0; - memcpy(&val, d->config + address, len); - return val; -} - -static void piix3_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len) -{ - memcpy(d->config + address, &val, len); -} - -void piix3_init(void) -{ - PIIX3State *d; - uint8_t *pci_conf; - - d = (PIIX3State *)pci_register_device("PIIX3", sizeof(PIIX3State), - 0, -1, - piix3_read_config, - piix3_write_config); - pci_conf = d->dev.config; - - pci_conf[0x00] = 0x86; // Intel - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) - pci_conf[0x03] = 0x70; - pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA - pci_conf[0x0b] = 0x06; // class_base = PCI_bridge - pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic - - piix3_reset(d); -} -- cgit v1.2.3 From 660de33686226402a064e3fbab9cc6dfed06b087 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:41:21 +0000 Subject: PIIX ELCR register support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@820 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/hw/i8259.c b/hw/i8259.c index 5d20e04db..e09bc9f31 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -43,6 +43,8 @@ typedef struct PicState { uint8_t rotate_on_auto_eoi; uint8_t special_fully_nested_mode; uint8_t init4; /* true if 4 byte init */ + uint8_t elcr; /* PIIX edge/trigger selection*/ + uint8_t elcr_mask; } PicState; /* 0 is master pic, 1 is slave pic */ @@ -54,12 +56,24 @@ static inline void pic_set_irq1(PicState *s, int irq, int level) { int mask; mask = 1 << irq; - if (level) { - if ((s->last_irr & mask) == 0) + if (s->elcr & mask) { + /* level triggered */ + if (level) { s->irr |= mask; - s->last_irr |= mask; + s->last_irr |= mask; + } else { + s->irr &= ~mask; + s->last_irr &= ~mask; + } } else { - s->last_irr &= ~mask; + /* edge triggered */ + if (level) { + if ((s->last_irr & mask) == 0) + s->irr |= mask; + s->last_irr |= mask; + } else { + s->last_irr &= ~mask; + } } } @@ -205,7 +219,7 @@ int cpu_get_pic_interrupt(CPUState *env) static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) { PicState *s = opaque; - int priority, cmd, irq; + int priority, cmd, irq, tmp; #ifdef DEBUG_PIC printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); @@ -214,7 +228,10 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (addr == 0) { if (val & 0x10) { /* init */ + tmp = s->elcr_mask; memset(s, 0, sizeof(PicState)); + s->elcr_mask = tmp; + s->init_state = 1; s->init4 = val & 1; if (val & 0x02) @@ -356,6 +373,18 @@ uint32_t pic_intack_read(CPUState *env) return ret; } +static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + PicState *s = opaque; + s->elcr = val & s->elcr_mask; +} + +static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1) +{ + PicState *s = opaque; + return s->elcr; +} + static void pic_save(QEMUFile *f, void *opaque) { PicState *s = opaque; @@ -374,6 +403,7 @@ static void pic_save(QEMUFile *f, void *opaque) qemu_put_8s(f, &s->rotate_on_auto_eoi); qemu_put_8s(f, &s->special_fully_nested_mode); qemu_put_8s(f, &s->init4); + qemu_put_8s(f, &s->elcr); } static int pic_load(QEMUFile *f, void *opaque, int version_id) @@ -397,15 +427,19 @@ static int pic_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->rotate_on_auto_eoi); qemu_get_8s(f, &s->special_fully_nested_mode); qemu_get_8s(f, &s->init4); + qemu_get_8s(f, &s->elcr); return 0; } /* XXX: add generic master/slave system */ -static void pic_init1(int io_addr, PicState *s) +static void pic_init1(int io_addr, int elcr_addr, PicState *s) { register_ioport_write(io_addr, 2, 1, pic_ioport_write, s); register_ioport_read(io_addr, 2, 1, pic_ioport_read, s); - + if (elcr_addr >= 0) { + register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s); + register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s); + } register_savevm("i8259", io_addr, 1, pic_save, pic_load, s); } @@ -416,15 +450,18 @@ void pic_info(void) for(i=0;i<2;i++) { s = &pics[i]; - term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d\n", - i, s->irr, s->imr, s->isr, s->priority_add, s->irq_base, s->read_reg_select); + term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x\n", + i, s->irr, s->imr, s->isr, s->priority_add, + s->irq_base, s->read_reg_select, s->elcr); } } void pic_init(void) { - pic_init1(0x20, &pics[0]); - pic_init1(0xa0, &pics[1]); + pic_init1(0x20, 0x4d0, &pics[0]); + pic_init1(0xa0, 0x4d1, &pics[1]); + pics[0].elcr_mask = 0xf8; + pics[1].elcr_mask = 0xde; } -- cgit v1.2.3 From 73c11f630be97e8098c8b4dd2a827a8097838a2b Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:42:19 +0000 Subject: cleanup git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@821 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index b2d902f20..35a064811 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1517,21 +1517,6 @@ typedef struct PCIIDEState { IDEState ide_if[4]; } PCIIDEState; -static uint32_t ide_read_config(PCIDevice *d, - uint32_t address, int len) -{ - uint32_t val; - val = 0; - memcpy(&val, d->config + address, len); - return val; -} - -static void ide_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len) -{ - memcpy(d->config + address, &val, len); -} - static void ide_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { @@ -1564,8 +1549,7 @@ void pci_ide_init(BlockDriverState **hd_table) d = (PCIIDEState *)pci_register_device("IDE", sizeof(PCIIDEState), 0, -1, - ide_read_config, - ide_write_config); + NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0x86; // Intel pci_conf[0x01] = 0x80; -- cgit v1.2.3 From 4a9c9687c62f10bdd9a4ba24933f3d4830d4a6b9 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:43:25 +0000 Subject: PCI irq support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@822 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 8ecbf55fc..6897bafd4 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -125,6 +125,7 @@ typedef struct NE2000State { uint8_t curpag; uint8_t mult[8]; /* multicast mask array */ int irq; + PCIDevice *pci_dev; NetDriverState *nd; uint8_t mem[NE2000_MEM_SIZE]; } NE2000State; @@ -153,10 +154,13 @@ static void ne2000_update_irq(NE2000State *s) printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n", s->irq, isr ? 1 : 0, s->isr, s->imr); #endif - if (isr) - pic_set_irq(s->irq, 1); - else - pic_set_irq(s->irq, 0); + if (s->irq == 16) { + /* PCI irq */ + pci_set_irq(s->pci_dev, 0, (isr != 0)); + } else { + /* ISA irq */ + pic_set_irq(s->irq, (isr != 0)); + } } /* return the max buffer size if the NE2000 can receive more data */ @@ -581,21 +585,6 @@ typedef struct PCINE2000State { NE2000State ne2000; } PCINE2000State; -static uint32_t ne2000_read_config(PCIDevice *d, - uint32_t address, int len) -{ - uint32_t val; - val = 0; - memcpy(&val, d->config + address, len); - return val; -} - -static void ne2000_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len) -{ - memcpy(d->config + address, &val, len); -} - static void ne2000_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { @@ -624,8 +613,7 @@ void pci_ne2000_init(NetDriverState *nd) d = (PCINE2000State *)pci_register_device("NE2000", sizeof(PCINE2000State), 0, -1, - ne2000_read_config, - ne2000_write_config); + NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0xec; // Realtek 8029 pci_conf[0x01] = 0x10; @@ -634,15 +622,13 @@ void pci_ne2000_init(NetDriverState *nd) pci_conf[0x0a] = 0x00; // ethernet network controller pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; // header_type - - /* XXX: do that in the BIOS */ - pci_conf[0x3c] = 11; // interrupt line - pci_conf[0x3d] = 1; // interrupt pin + pci_conf[0x3d] = 1; // interrupt pin 0 pci_register_io_region((PCIDevice *)d, 0, 0x100, PCI_ADDRESS_SPACE_IO, ne2000_map); s = &d->ne2000; - s->irq = 11; + s->irq = 16; // PCI interrupt + s->pci_dev = (PCIDevice *)d; s->nd = nd; ne2000_reset(s); qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); -- cgit v1.2.3 From 0ac32c837507260009d170af15f4ae9652a9ea97 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:45:00 +0000 Subject: PCI interrupt support - PCI BIOS interrupt remapping - more accurate memory mapping - 'info pci' monitor command git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@823 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 543 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 469 insertions(+), 74 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 2c5f30b15..ff5a44efb 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -25,6 +25,21 @@ //#define DEBUG_PCI +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ +#define PCI_MIN_GNT 0x3e /* 8 bits */ +#define PCI_MAX_LAT 0x3f /* 8 bits */ + +/* just used for simpler irq handling. */ +#define PCI_DEVICES_MAX 64 +#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) + typedef struct PCIBridge { uint32_t config_reg; PCIDevice **pci_bus[256]; @@ -32,6 +47,8 @@ typedef struct PCIBridge { static PCIBridge pci_bridge; target_phys_addr_t pci_mem_base; +static int pci_irq_index; +static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; /* -1 for devfn means auto assign */ PCIDevice *pci_register_device(const char *name, int instance_size, @@ -42,6 +59,9 @@ PCIDevice *pci_register_device(const char *name, int instance_size, PCIBridge *s = &pci_bridge; PCIDevice *pci_dev, **bus; + if (pci_irq_index >= PCI_DEVICES_MAX) + return NULL; + if (!s->pci_bus[bus_num]) { s->pci_bus[bus_num] = qemu_mallocz(256 * sizeof(PCIDevice *)); if (!s->pci_bus[bus_num]) @@ -62,8 +82,14 @@ PCIDevice *pci_register_device(const char *name, int instance_size, pci_dev->bus_num = bus_num; pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); + + if (!config_read) + config_read = pci_default_read_config; + if (!config_write) + config_write = pci_default_write_config; pci_dev->config_read = config_read; pci_dev->config_write = config_write; + pci_dev->irq_index = pci_irq_index++; bus[devfn] = pci_dev; return pci_dev; } @@ -83,30 +109,160 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, r->map_func = map_func; } -static void pci_config_writel(void* opaque, uint32_t addr, uint32_t val) +static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val) { PCIBridge *s = opaque; s->config_reg = val; } -static uint32_t pci_config_readl(void* opaque, uint32_t addr) +static uint32_t pci_addr_readl(void* opaque, uint32_t addr) { PCIBridge *s = opaque; return s->config_reg; } -static void unmap_region(PCIIORegion *r) +static void pci_update_mappings(PCIDevice *d) +{ + PCIIORegion *r; + int cmd, i; + uint32_t last_addr, new_addr; + + cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND)); + for(i = 0; i < 6; i++) { + r = &d->io_regions[i]; + if (r->size != 0) { + if (r->type & PCI_ADDRESS_SPACE_IO) { + if (cmd & PCI_COMMAND_IO) { + new_addr = le32_to_cpu(*(uint32_t *)(d->config + + 0x10 + i * 4)); + new_addr = new_addr & ~(r->size - 1); + last_addr = new_addr + r->size - 1; + /* NOTE: we have only 64K ioports on PC */ + if (last_addr <= new_addr || new_addr == 0 || + last_addr >= 0x10000) { + new_addr = -1; + } + } else { + new_addr = -1; + } + } else { + if (cmd & PCI_COMMAND_MEMORY) { + new_addr = le32_to_cpu(*(uint32_t *)(d->config + + 0x10 + i * 4)); + new_addr = new_addr & ~(r->size - 1); + last_addr = new_addr + r->size - 1; + /* NOTE: we do not support wrapping */ + /* XXX: as we cannot support really dynamic + mappings, we handle specific values as invalid + mappings. */ + if (last_addr <= new_addr || new_addr == 0 || + last_addr == -1) { + new_addr = -1; + } + } else { + new_addr = -1; + } + } + /* now do the real mapping */ + if (new_addr != r->addr) { + if (r->addr != -1) { + if (r->type & PCI_ADDRESS_SPACE_IO) { + int class; + /* NOTE: specific hack for IDE in PC case: + only one byte must be mapped. */ + class = d->config[0x0a] | (d->config[0x0b] << 8); + if (class == 0x0101 && r->size == 4) { + isa_unassign_ioport(r->addr + 2, 1); + } else { + isa_unassign_ioport(r->addr, r->size); + } + } else { + cpu_register_physical_memory(r->addr + pci_mem_base, + r->size, + IO_MEM_UNASSIGNED); + } + } + r->addr = new_addr; + if (r->addr != -1) { + r->map_func(d, i, r->addr, r->size, r->type); + } + } + } + } +} + +uint32_t pci_default_read_config(PCIDevice *d, + uint32_t address, int len) { - if (r->addr == -1) + uint32_t val; + switch(len) { + case 1: + val = d->config[address]; + break; + case 2: + val = le16_to_cpu(*(uint16_t *)(d->config + address)); + break; + default: + case 4: + val = le32_to_cpu(*(uint32_t *)(d->config + address)); + break; + } + return val; +} + +void pci_default_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + int can_write, i; + uint32_t end; + + if (len == 4 && (address >= 0x10 && address < 0x10 + 4 * 6)) { + PCIIORegion *r; + int reg; + + reg = (address - 0x10) >> 2; + r = &d->io_regions[reg]; + if (r->size == 0) + goto default_config; + /* compute the stored value */ + val &= ~(r->size - 1); + val |= r->type; + *(uint32_t *)(d->config + 0x10 + reg * 4) = cpu_to_le32(val); + pci_update_mappings(d); return; -#ifdef DEBUG_PCI - printf("unmap addr=%08x size=%08x\n", r->addr, r->size); -#endif - if (r->type & PCI_ADDRESS_SPACE_IO) { - isa_unassign_ioport(r->addr, r->size); - } else { - cpu_register_physical_memory(r->addr + pci_mem_base, r->size, - IO_MEM_UNASSIGNED); + } + default_config: + /* not efficient, but simple */ + for(i = 0; i < len; i++) { + /* default read/write accesses */ + switch(address) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0e: + case 0x3d: + can_write = 0; + break; + default: + can_write = 1; + break; + } + if (can_write) { + d->config[address] = val; + } + address++; + val >>= 8; + } + + end = address + len; + if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) { + /* if the command register is modified, we must modify the mappings */ + pci_update_mappings(d); } } @@ -115,7 +271,7 @@ static void pci_data_write(void *opaque, uint32_t addr, { PCIBridge *s = opaque; PCIDevice **bus, *pci_dev; - int config_addr, reg; + int config_addr; #if defined(DEBUG_PCI) && 0 printf("pci_data_write: addr=%08x val=%08x len=%d\n", @@ -134,41 +290,11 @@ static void pci_data_write(void *opaque, uint32_t addr, if (!pci_dev) return; config_addr = (s->config_reg & 0xfc) | (addr & 3); - #if defined(DEBUG_PCI) printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len); #endif - if (len == 4 && (config_addr >= 0x10 && config_addr < 0x10 + 4 * 6)) { - PCIIORegion *r; - reg = (config_addr - 0x10) >> 2; - r = &pci_dev->io_regions[reg]; - if (r->size == 0) - goto default_config; - if (val != 0xffffffff && val != 0) { - /* XXX: the memory assignment should be global to handle - overlaps, but it is not needed at this stage */ - /* first unmap the old region */ - unmap_region(r); - /* change the address */ - if (r->type & PCI_ADDRESS_SPACE_IO) - r->addr = val & ~0x3; - else - r->addr = val & ~0xf; -#ifdef DEBUG_PCI - printf("map addr=%08x size=%08x type=%d\n", - r->addr, r->size, r->type); -#endif - r->map_func(pci_dev, reg, r->addr, r->size, r->type); - } - /* now compute the stored value */ - val &= ~(r->size - 1); - val |= r->type; - *(uint32_t *)(pci_dev->config + 0x10 + reg * 4) = cpu_to_le32(val); - } else { - default_config: - pci_dev->config_write(pci_dev, config_addr, val, len); - } + pci_dev->config_write(pci_dev, config_addr, val, len); } static uint32_t pci_data_read(void *opaque, uint32_t addr, @@ -238,28 +364,13 @@ static uint32_t pci_data_readl(void* opaque, uint32_t addr) /* i440FX PCI bridge */ -static uint32_t i440_read_config(PCIDevice *d, - uint32_t address, int len) -{ - uint32_t val; - val = 0; - memcpy(&val, d->config + address, len); - return val; -} - -static void i440_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len) -{ - memcpy(d->config + address, &val, len); -} - void i440fx_init(void) { PCIBridge *s = &pci_bridge; PCIDevice *d; - register_ioport_write(0xcf8, 4, 4, pci_config_writel, s); - register_ioport_read(0xcf8, 4, 4, pci_config_readl, s); + register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); + register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); @@ -269,7 +380,7 @@ void i440fx_init(void) register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); d = pci_register_device("i440FX", sizeof(PCIDevice), 0, 0, - i440_read_config, i440_write_config); + NULL, NULL); d->config[0x00] = 0x86; // vendor_id d->config[0x01] = 0x80; @@ -282,35 +393,295 @@ void i440fx_init(void) d->config[0x0e] = 0x01; // header_type } -/* NOTE: the following should be done by the BIOS */ +/* PIIX3 PCI to ISA bridge */ + +typedef struct PIIX3State { + PCIDevice dev; +} PIIX3State; + +PIIX3State *piix3_state; + +static void piix3_reset(PIIX3State *d) +{ + uint8_t *pci_conf = d->dev.config; + + pci_conf[0x04] = 0x07; // master, memory and I/O + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x00; + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium + pci_conf[0x4c] = 0x4d; + pci_conf[0x4e] = 0x03; + pci_conf[0x4f] = 0x00; + pci_conf[0x60] = 0x80; + pci_conf[0x69] = 0x02; + pci_conf[0x70] = 0x80; + pci_conf[0x76] = 0x0c; + pci_conf[0x77] = 0x0c; + pci_conf[0x78] = 0x02; + pci_conf[0x79] = 0x00; + pci_conf[0x80] = 0x00; + pci_conf[0x82] = 0x00; + pci_conf[0xa0] = 0x08; + pci_conf[0xa0] = 0x08; + pci_conf[0xa2] = 0x00; + pci_conf[0xa3] = 0x00; + pci_conf[0xa4] = 0x00; + pci_conf[0xa5] = 0x00; + pci_conf[0xa6] = 0x00; + pci_conf[0xa7] = 0x00; + pci_conf[0xa8] = 0x0f; + pci_conf[0xaa] = 0x00; + pci_conf[0xab] = 0x00; + pci_conf[0xac] = 0x00; + pci_conf[0xae] = 0x00; +} + +void piix3_init(void) +{ + PIIX3State *d; + uint8_t *pci_conf; + + d = (PIIX3State *)pci_register_device("PIIX3", sizeof(PIIX3State), + 0, -1, + NULL, NULL); + piix3_state = d; + pci_conf = d->dev.config; + + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) + pci_conf[0x03] = 0x70; + pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA + pci_conf[0x0b] = 0x06; // class_base = PCI_bridge + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic + + piix3_reset(d); +} + +/***********************************************************/ +/* generic PCI irq support */ + +/* return the global irq number corresponding to a given device irq + pin. We could also use the bus number to have a more precise + mapping. */ +static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + int slot_addend; + slot_addend = (pci_dev->devfn >> 3); + return (irq_num + slot_addend) & 3; +} + +/* 0 <= irq_num <= 3. level must be 0 or 1 */ +void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) +{ + int irq_index, shift, pic_irq, pic_level; + uint32_t *p; + + irq_num = pci_slot_get_pirq(pci_dev, irq_num); + irq_index = pci_dev->irq_index; + p = &pci_irq_levels[irq_num][irq_index >> 5]; + shift = (irq_index & 0x1f); + *p = (*p & ~(1 << shift)) | (level << shift); + + /* now we change the pic irq level according to the piix irq mappings */ + pic_irq = piix3_state->dev.config[0x60 + irq_num]; + if (pic_irq < 16) { + /* the pic level is the logical OR of all the PCI irqs mapped + to it */ + pic_level = 0; +#if (PCI_IRQ_WORDS == 2) + pic_level = ((pci_irq_levels[irq_num][0] | + pci_irq_levels[irq_num][1]) != 0); +#else + { + int i; + pic_level = 0; + for(i = 0; i < PCI_IRQ_WORDS; i++) { + if (pci_irq_levels[irq_num][i]) { + pic_level = 1; + break; + } + } + } +#endif + pic_set_irq(pic_irq, pic_level); + } +} + +/***********************************************************/ +/* monitor info on PCI */ + +static void pci_info_device(PCIDevice *d) +{ + int i, class; + PCIIORegion *r; + + printf(" Bus %2d, device %3d, function %d:\n", + d->bus_num, d->devfn >> 3, d->devfn & 7); + class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); + printf(" "); + switch(class) { + case 0x0101: + printf("IDE controller"); + break; + case 0x0200: + printf("Ethernet controller"); + break; + case 0x0300: + printf("VGA controller"); + break; + default: + printf("Class %04x", class); + break; + } + printf(": PCI device %04x:%04x\n", + le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), + le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID)))); + + if (d->config[PCI_INTERRUPT_PIN] != 0) { + printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); + } + for(i = 0;i < 6; i++) { + r = &d->io_regions[i]; + if (r->size != 0) { + printf(" BAR%d: ", i); + if (r->type & PCI_ADDRESS_SPACE_IO) { + printf("I/O at 0x%04x [0x%04x].\n", + r->addr, r->addr + r->size - 1); + } else { + printf("32 bit memory at 0x%08x [0x%08x].\n", + r->addr, r->addr + r->size - 1); + } + } + } +} + +void pci_info(void) +{ + PCIBridge *s = &pci_bridge; + PCIDevice **bus; + int bus_num, devfn; + + for(bus_num = 0; bus_num < 256; bus_num++) { + bus = s->pci_bus[bus_num]; + if (bus) { + for(devfn = 0; devfn < 256; devfn++) { + if (bus[devfn]) + pci_info_device(bus[devfn]); + } + } + } +} + +/***********************************************************/ +/* XXX: the following should be moved to the PC BIOS */ + +static uint32_t isa_inb(uint32_t addr) +{ + return cpu_inb(cpu_single_env, addr); +} + +static void isa_outb(uint32_t val, uint32_t addr) +{ + cpu_outb(cpu_single_env, addr, val); +} + +static uint32_t isa_inw(uint32_t addr) +{ + return cpu_inw(cpu_single_env, addr); +} + +static void isa_outw(uint32_t val, uint32_t addr) +{ + cpu_outw(cpu_single_env, addr, val); +} + +static uint32_t isa_inl(uint32_t addr) +{ + return cpu_inl(cpu_single_env, addr); +} + +static void isa_outl(uint32_t val, uint32_t addr) +{ + cpu_outl(cpu_single_env, addr, val); +} + +static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; + s->config_reg = 0x80000000 | (d->bus_num << 16) | + (d->devfn << 8) | addr; + pci_data_write(s, 0, val, 4); +} + +static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; + s->config_reg = 0x80000000 | (d->bus_num << 16) | + (d->devfn << 8) | (addr & ~3); + pci_data_write(s, addr & 3, val, 2); +} + +static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; + s->config_reg = 0x80000000 | (d->bus_num << 16) | + (d->devfn << 8) | (addr & ~3); + pci_data_write(s, addr & 3, val, 1); +} + +static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) +{ + PCIBridge *s = &pci_bridge; + s->config_reg = 0x80000000 | (d->bus_num << 16) | + (d->devfn << 8) | addr; + return pci_data_read(s, 0, 4); +} + +static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) +{ + PCIBridge *s = &pci_bridge; + s->config_reg = 0x80000000 | (d->bus_num << 16) | + (d->devfn << 8) | (addr & ~3); + return pci_data_read(s, addr & 3, 2); +} + +static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) +{ + PCIBridge *s = &pci_bridge; + s->config_reg = 0x80000000 | (d->bus_num << 16) | + (d->devfn << 8) | (addr & ~3); + return pci_data_read(s, addr & 3, 1); +} static uint32_t pci_bios_io_addr; static uint32_t pci_bios_mem_addr; +/* host irqs corresponding to PCI irqs A-D */ +static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) { - PCIBridge *s = &pci_bridge; PCIIORegion *r; + uint16_t cmd; - s->config_reg = 0x80000000 | (d->bus_num << 16) | - (d->devfn << 8) | (0x10 + region_num * 4); - pci_data_write(s, 0, addr, 4); + pci_config_writel(d, 0x10 + region_num * 4, addr); r = &d->io_regions[region_num]; /* enable memory mappings */ + cmd = pci_config_readw(d, PCI_COMMAND); if (r->type & PCI_ADDRESS_SPACE_IO) - d->config[0x04] |= 1; + cmd |= 1; else - d->config[0x04] |= 2; + cmd |= 2; + pci_config_writew(d, PCI_COMMAND, cmd); } - static void pci_bios_init_device(PCIDevice *d) { int class; PCIIORegion *r; uint32_t *paddr; - int i; + int i, pin, pic_irq; class = d->config[0x0a] | (d->config[0x0b] << 8); switch(class) { @@ -321,6 +692,10 @@ static void pci_bios_init_device(PCIDevice *d) pci_set_io_region_addr(d, 2, 0x170); pci_set_io_region_addr(d, 3, 0x374); break; + case 0x0300: + /* VGA: map frame buffer to default Bochs VBE address */ + pci_set_io_region_addr(d, 0, 0xE0000000); + break; default: /* default memory mappings */ for(i = 0; i < 6; i++) { @@ -337,6 +712,14 @@ static void pci_bios_init_device(PCIDevice *d) } break; } + + /* map the interrupt */ + pin = pci_config_readb(d, PCI_INTERRUPT_PIN); + if (pin != 0) { + pin = pci_slot_get_pirq(d, pin - 1); + pic_irq = pci_irqs[pin]; + pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); + } } /* @@ -348,11 +731,25 @@ void pci_bios_init(void) { PCIBridge *s = &pci_bridge; PCIDevice **bus; - int bus_num, devfn; + int bus_num, devfn, i, irq; + uint8_t elcr[2]; pci_bios_io_addr = 0xc000; pci_bios_mem_addr = 0xf0000000; + /* activate IRQ mappings */ + elcr[0] = 0x00; + elcr[1] = 0x00; + for(i = 0; i < 4; i++) { + irq = pci_irqs[i]; + /* set to trigger level */ + elcr[irq >> 3] |= (1 << (irq & 7)); + /* activate irq remapping in PIIX */ + pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); + } + isa_outb(elcr[0], 0x4d0); + isa_outb(elcr[1], 0x4d1); + for(bus_num = 0; bus_num < 256; bus_num++) { bus = s->pci_bus[bus_num]; if (bus) { @@ -363,5 +760,3 @@ void pci_bios_init(void) } } } - - -- cgit v1.2.3 From 1078f663ae65cb4e053b8cb7adff5908c4c7b8de Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:46:38 +0000 Subject: dummy VGA PCI support - VGA font selection fix (Daniel Serpell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@824 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 62c7c404c..64769d157 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1129,14 +1129,14 @@ static void vga_draw_text(VGAState *s, int full_update) /* compute font data address (in plane 2) */ v = s->sr[3]; - offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2; + offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; if (offset != s->font_offsets[0]) { s->font_offsets[0] = offset; full_update = 1; } font_base[0] = s->vram_ptr + offset; - offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; + offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2; font_base[1] = s->vram_ptr + offset; if (offset != s->font_offsets[1]) { s->font_offsets[1] = offset; @@ -1709,8 +1709,17 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static void vga_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + VGAState *s = &vga_state; + + cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); +} + int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size) + unsigned long vga_ram_offset, int vga_ram_size, + int is_pci) { VGAState *s = &vga_state; int i, j, v, b; @@ -1782,13 +1791,36 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, vga_io_memory); + + if (is_pci) { + PCIDevice *d; + uint8_t *pci_conf; + + d = pci_register_device("VGA", + sizeof(PCIDevice), + 0, -1, + NULL, NULL); + pci_conf = d->config; + pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID) + pci_conf[0x01] = 0x12; + pci_conf[0x02] = 0x11; + pci_conf[0x03] = 0x11; + pci_conf[0x0a] = 0x00; // VGA controller + pci_conf[0x0b] = 0x03; + pci_conf[0x0e] = 0x00; // header_type + + /* XXX: vga_ram_size must be a power of two */ + pci_register_io_region(d, 0, vga_ram_size, + PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); + } else { #ifdef CONFIG_BOCHS_VBE #if defined (TARGET_I386) - /* XXX: use optimized standard vga accesses */ - cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, - vga_ram_size, vga_ram_offset); + /* XXX: use optimized standard vga accesses */ + cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, + vga_ram_size, vga_ram_offset); #endif #endif + } return 0; } -- cgit v1.2.3 From 5768f5aca6ebe81b203b580c7ab812dd0c2bcfa7 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:47:45 +0000 Subject: PCI interrupt support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@825 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/vl.h b/vl.h index 0cac4abd2..42a29bdcf 100644 --- a/vl.h +++ b/vl.h @@ -382,7 +382,7 @@ typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08 typedef struct PCIIORegion { - uint32_t addr; + uint32_t addr; /* current PCI mapping address. -1 means not mapped */ uint32_t size; uint8_t type; PCIMapIORegionFunc *map_func; @@ -401,6 +401,7 @@ struct PCIDevice { /* do not access the following fields */ PCIConfigReadFunc *config_read; PCIConfigWriteFunc *config_write; + int irq_index; }; PCIDevice *pci_register_device(const char *name, int instance_size, @@ -412,9 +413,17 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, uint32_t size, int type, PCIMapIORegionFunc *map_func); +void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level); + +uint32_t pci_default_read_config(PCIDevice *d, + uint32_t address, int len); +void pci_default_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len); + void i440fx_init(void); void piix3_init(void); void pci_bios_init(void); +void pci_info(void); /* vga.c */ @@ -440,7 +449,8 @@ static inline void dpy_resize(DisplayState *s, int w, int h) } int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size); + unsigned long vga_ram_offset, int vga_ram_size, + int is_pci); void vga_update_display(void); void vga_screen_dump(const char *filename); -- cgit v1.2.3 From 5ce276a11a2c92f2a5922c340452fc47d306dfe7 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:48:53 +0000 Subject: VGA PCI support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@826 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- hw/ppc_prep.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 1139781a0..895f3e1bd 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -391,7 +391,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + vga_ram_size, pci_enabled); rtc_state = rtc_init(0x70, 8); register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 02c7f0d45..f64649cf5 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -950,7 +950,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* init basic PC hardware */ vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + vga_ram_size, 0); rtc_init(0x70, 8); pic_init(); // pit_init(0x40, 0); -- cgit v1.2.3 From 86e0c04896df5adf04f543aee4036b835a3338e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:49:21 +0000 Subject: info pci command git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@827 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monitor.c b/monitor.c index f5cde7491..2dc94b44a 100644 --- a/monitor.c +++ b/monitor.c @@ -525,6 +525,8 @@ static term_cmd_t info_cmds[] = { "", "show the command line history", }, { "pic", "", pic_info, "", "show i8259 (PIC) state", }, + { "pci", "", pci_info, + "", "show PCI info", }, { NULL, NULL, }, }; -- cgit v1.2.3 From 04a3b84c839538715b1bd3c93dd3aff46840e23a Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 12:51:57 +0000 Subject: 64 bit support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@828 c046a42c-6fe2-441c-8c8c-71466251a162 --- vmdk2raw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vmdk2raw.c b/vmdk2raw.c index 8bf5eea38..4a63e76e9 100644 --- a/vmdk2raw.c +++ b/vmdk2raw.c @@ -108,7 +108,7 @@ zero_fill: int open_vmdk(const char *filename) { - int fd = open(filename, O_RDONLY); + int fd = open(filename, O_RDONLY | O_LARGEFILE); if (fd == -1) { perror(filename); -- cgit v1.2.3 From b71e95fc2c030428c768de20332f9d857b9aed41 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 13:08:06 +0000 Subject: win32 patch (kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@829 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/sdl.c b/sdl.c index ee809daa6..7b3c3b5ea 100644 --- a/sdl.c +++ b/sdl.c @@ -87,20 +87,20 @@ static const uint32_t x_keycode_to_pc_keycode[61] = { 0x0, /* 117 */ 0x0, /* 118 */ 0x0, /* 119 */ - 0x0, /* 120 */ + 0x70, /* 120 Hiragana_Katakana */ 0x0, /* 121 */ 0x0, /* 122 */ - 0x0, /* 123 */ + 0x73, /* 123 backslash */ 0x0, /* 124 */ 0x0, /* 125 */ 0x0, /* 126 */ 0x0, /* 127 */ 0x0, /* 128 */ - 0x0, /* 129 */ + 0x79, /* 129 Henkan */ 0x0, /* 130 */ - 0x0, /* 131 */ + 0x7b, /* 131 Muhenkan */ 0x0, /* 132 */ - 0x0, /* 133 */ + 0x7d, /* 133 Yen */ 0x0, /* 134 */ 0x0, /* 135 */ 0x47, /* 136 KP_7 */ @@ -133,23 +133,19 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) /* XXX: not portable, but avoids complicated mappings */ keycode = ev->keysym.scancode; -#ifdef _WIN32 - if (keycode < 97) { - /* nothing to do */ - } else -#else + +#ifndef _WIN32 if (keycode < 9) { keycode = 0; } else if (keycode < 97) { keycode -= 8; /* just an offset */ - } else -#endif - if (keycode < 158) { + } else if (keycode < 158) { /* use conversion table */ keycode = x_keycode_to_pc_keycode[keycode - 97]; } else { keycode = 0; } +#endif /* now send the key code */ while (keycode != 0) { -- cgit v1.2.3 From c6a1c22ba68d1731dd3a593fe71e4399f080bd56 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 13:10:49 +0000 Subject: fixed invalid includes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@830 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e410cb2d1..009097302 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -17,9 +17,14 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "dyngen-exec.h" +#include +#include +#include +#include +#include + #include "cpu.h" -#include "exec.h" +#include "exec-all.h" #include "disas.h" //#define DO_SINGLE_STEP -- cgit v1.2.3 From 829309c70c47926cb1c05727118ebe77c417eecc Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 13:20:12 +0000 Subject: BSD fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@831 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 15 +++++++++++++-- vl.h | 7 ------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/vl.c b/vl.c index baa09e58a..84ac49d91 100644 --- a/vl.c +++ b/vl.c @@ -739,10 +739,12 @@ static void host_alarm_handler(int host_signum) #ifndef _WIN32 +#if defined(__linux__) + #define RTC_FREQ 1024 static int rtc_fd; - + static int start_rtc_timer(void) { rtc_fd = open("/dev/rtc", O_RDONLY); @@ -763,7 +765,16 @@ static int start_rtc_timer(void) return 0; } -#endif +#else + +static int start_rtc_timer(void) +{ + return -1; +} + +#endif /* !defined(__linux__) */ + +#endif /* !defined(_WIN32) */ static void init_timers(void) { diff --git a/vl.h b/vl.h index 42a29bdcf..ace401fbb 100644 --- a/vl.h +++ b/vl.h @@ -50,13 +50,6 @@ #include "cpu.h" -#ifdef _BSD -#define lseek64 lseek -#define ftruncate64 ftruncate -#define mkstemp64 mkstemp -#define MAP_ANONYMOUS MAP_ANON -#endif - #ifndef glue #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) -- cgit v1.2.3 From 5f21aef2b0e53b9c179d36cba6004df785500ac1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 13:20:55 +0000 Subject: suppressed unneeded header git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@832 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index dc2737ea7..09c0eebbe 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -17,8 +17,6 @@ * 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 - #include "exec.h" #if defined (USE_OPEN_FIRMWARE) #include @@ -133,14 +131,14 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | (virtual & 0x0001F000); if (*BATl & 0x00000001) - *prot = PROT_READ; + *prot = PAGE_READ; if (*BATl & 0x00000002) - *prot = PROT_WRITE | PROT_READ; + *prot = PAGE_WRITE | PAGE_READ; #if defined (DEBUG_BATS) if (loglevel > 0) { fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", - i, *real, *prot & PROT_READ ? 'R' : '-', - *prot & PROT_WRITE ? 'W' : '-'); + i, *real, *prot & PAGE_READ ? 'R' : '-', + *prot & PAGE_WRITE ? 'W' : '-'); } #endif ret = 0; @@ -203,9 +201,9 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, } /* Check access rights */ if (key == 0) { - access = PROT_READ; + access = PAGE_READ; if ((pte1 & 0x00000003) != 0x3) - access |= PROT_WRITE; + access |= PAGE_WRITE; } else { switch (pte1 & 0x00000003) { case 0x0: @@ -213,16 +211,16 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, break; case 0x1: case 0x3: - access = PROT_READ; + access = PAGE_READ; break; case 0x2: - access = PROT_READ | PROT_WRITE; + access = PAGE_READ | PAGE_WRITE; break; } } if (ret < 0) { - if ((rw == 0 && (access & PROT_READ)) || - (rw == 1 && (access & PROT_WRITE))) { + if ((rw == 0 && (access & PAGE_READ)) || + (rw == 1 && (access & PAGE_WRITE))) { #if defined (DEBUG_MMU) if (loglevel > 0) fprintf(logfile, "PTE access granted !\n"); @@ -264,7 +262,7 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, store = 1; } else { /* Force page fault for first write access */ - *prot &= ~PROT_WRITE; + *prot &= ~PAGE_WRITE; } } if (store) { @@ -409,7 +407,7 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) { /* No address translation */ *physical = address & ~0xFFF; - *prot = PROT_READ | PROT_WRITE; + *prot = PAGE_READ | PAGE_WRITE; ret = 0; } else { /* Try to find a BAT */ -- cgit v1.2.3 From d157e205e94931f5870b1b3bf2b1f149a87c5aa7 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 13:22:36 +0000 Subject: win32 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@833 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index 62cd301e5..9f0a128d5 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -68,7 +68,11 @@ static void get_time (m48t59_t *NVRAM, struct tm *tm) time_t t; t = time(NULL) + NVRAM->time_offset; - localtime_r(&t, tm); +#ifdef _WIN32 + memcpy(tm,localtime(&t),sizeof(*tm)); +#else + localtime_r (&t, tm) ; +#endif } static void set_time (m48t59_t *NVRAM, struct tm *tm) @@ -130,7 +134,11 @@ static void alarm_cb (void *opaque) static void get_alarm (m48t59_t *NVRAM, struct tm *tm) { - localtime_r(&NVRAM->alarm, tm); +#ifdef _WIN32 + memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm)); +#else + localtime_r (&NVRAM->alarm, tm); +#endif } static void set_alarm (m48t59_t *NVRAM, struct tm *tm) -- cgit v1.2.3 From 43003046cba8134bbfa7b405b9fde3bf16bc5478 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 13:23:39 +0000 Subject: BSD fix + ppc-softmmu support for win32 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@834 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 055f50ee9..e4ffbac81 100755 --- a/configure +++ b/configure @@ -154,7 +154,7 @@ ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" if test "$mingw32" = "yes" ; then - target_list="i386-softmmu" + target_list="i386-softmmu ppc-softmmu" EXESUF=".exe" gdbstub="no" fi @@ -417,6 +417,10 @@ echo "SRC_PATH=$source_path" >> $config_mak echo "TARGET_DIRS=$target_list" >> $config_mak if [ "$bsd" = "yes" ] ; then + echo "#define O_LARGEFILE 0" >> $config_h + echo "#define lseek64 lseek" >> $config_h + echo "#define ftruncate64 ftruncate" >> $config_h + echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h echo "#define _BSD 1" >> $config_h fi -- cgit v1.2.3 From 4399059e4dd7ee742c80f44421b84f1f697ec932 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 13:24:37 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@835 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index c55362c28..a1df55cf0 100644 --- a/Changelog +++ b/Changelog @@ -11,6 +11,8 @@ version 0.5.6: - vmdk2raw: convert VMware disk images to raw images - PCI support - NE2K PCI support + - dummy VGA PCI support + - VGA font selection fix (Daniel Serpell) version 0.5.5: -- cgit v1.2.3 From b54ad0498e58cd81f35f815ecb887af2f44ab6f6 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 13:42:52 +0000 Subject: PIC reset fix (initial patch by Hidemi KAWAI) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@836 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + cpu-all.h | 5 +---- exec.c | 5 +++++ hw/i8259.c | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Changelog b/Changelog index a1df55cf0..a4717afbb 100644 --- a/Changelog +++ b/Changelog @@ -13,6 +13,7 @@ version 0.5.6: - NE2K PCI support - dummy VGA PCI support - VGA font selection fix (Daniel Serpell) + - PIC reset fix (Hidemi KAWAI) version 0.5.5: diff --git a/cpu-all.h b/cpu-all.h index 0ed5d00f4..69b6e7c36 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -569,7 +569,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_init cpu_x86_init #define cpu_exec cpu_x86_exec #define cpu_gen_code cpu_x86_gen_code -#define cpu_interrupt cpu_x86_interrupt #define cpu_signal_handler cpu_x86_signal_handler #define cpu_dump_state cpu_x86_dump_state @@ -579,7 +578,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_init cpu_arm_init #define cpu_exec cpu_arm_exec #define cpu_gen_code cpu_arm_gen_code -#define cpu_interrupt cpu_arm_interrupt #define cpu_signal_handler cpu_arm_signal_handler #define cpu_dump_state cpu_arm_dump_state @@ -589,7 +587,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_init cpu_sparc_init #define cpu_exec cpu_sparc_exec #define cpu_gen_code cpu_sparc_gen_code -#define cpu_interrupt cpu_sparc_interrupt #define cpu_signal_handler cpu_sparc_signal_handler #define cpu_dump_state cpu_sparc_dump_state @@ -599,7 +596,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_init cpu_ppc_init #define cpu_exec cpu_ppc_exec #define cpu_gen_code cpu_ppc_gen_code -#define cpu_interrupt cpu_ppc_interrupt #define cpu_signal_handler cpu_ppc_signal_handler #define cpu_dump_state cpu_ppc_dump_state @@ -620,6 +616,7 @@ extern int code_copy_enabled; #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ #define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */ void cpu_interrupt(CPUState *s, int mask); +void cpu_reset_interrupt(CPUState *env, int mask); int cpu_breakpoint_insert(CPUState *env, target_ulong pc); int cpu_breakpoint_remove(CPUState *env, target_ulong pc); diff --git a/exec.c b/exec.c index 441c5626f..5357dcdfb 100644 --- a/exec.c +++ b/exec.c @@ -1112,6 +1112,11 @@ void cpu_interrupt(CPUState *env, int mask) } } +void cpu_reset_interrupt(CPUState *env, int mask) +{ + env->interrupt_request &= ~mask; +} + CPULogItem cpu_log_items[] = { { CPU_LOG_TB_OUT_ASM, "out_asm", "show generated host assembly code for each compiled TB" }, diff --git a/hw/i8259.c b/hw/i8259.c index e09bc9f31..809ea95a5 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -231,6 +231,8 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) tmp = s->elcr_mask; memset(s, 0, sizeof(PicState)); s->elcr_mask = tmp; + /* deassert a pending interrupt */ + cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); s->init_state = 1; s->init4 = val & 1; -- cgit v1.2.3 From 28ab0e2edb36685da7280b24e665962754d9e4ff Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 14:02:14 +0000 Subject: added cpu_get_tsc() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@837 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 7 +++++++ linux-user/main.c | 40 ++++++++++++++++++++++++++++++++++++++++ target-i386/cpu.h | 2 ++ target-i386/helper.c | 13 ++----------- tests/qruncom.c | 5 +++++ 5 files changed, 56 insertions(+), 11 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 895f3e1bd..75a590bfb 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -57,6 +57,13 @@ static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) pic_set_irq(13, 0); } +/* TSC handling */ + +uint64_t cpu_get_tsc(CPUX86State *env) +{ + return qemu_get_clock(vm_clock); +} + /* PC cmos mappings */ #define REG_EQUIPMENT_BYTE 0x14 diff --git a/linux-user/main.c b/linux-user/main.c index ae4f6a5ac..c0759bfef 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -99,10 +99,50 @@ int cpu_get_pic_interrupt(CPUState *env) return -1; } +/* timers for rdtsc */ + +#if defined(__i386__) + +int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("rdtsc" : "=A" (val)); + return val; +} + +#elif defined(__x86_64__) + +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; +} + +#else + +static uint64_t emu_time; + +int64_t cpu_get_real_ticks(void) +{ + return emu_time++; +} + +#endif + #ifdef TARGET_I386 /***********************************************************/ /* CPUX86 core interface */ +uint64_t cpu_get_tsc(CPUX86State *env) +{ + return cpu_get_real_ticks(); +} + static void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 19340d257..9f16a487f 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -443,6 +443,8 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, void *puc); void cpu_x86_set_a20(CPUX86State *env, int a20_state); +uint64_t cpu_get_tsc(CPUX86State *env); + /* will be suppressed */ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); diff --git a/target-i386/helper.c b/target-i386/helper.c index f2305e32c..5782babc2 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1775,20 +1775,11 @@ void helper_invlpg(unsigned int addr) cpu_x86_flush_tlb(env, addr); } -/* rdtsc */ -#if !defined(__i386__) && !defined(__x86_64__) -uint64_t emu_time; -#endif - void helper_rdtsc(void) { uint64_t val; -#if defined(__i386__) || defined(__x86_64__) - asm volatile ("rdtsc" : "=A" (val)); -#else - /* better than nothing: the time increases */ - val = emu_time++; -#endif + + val = cpu_get_tsc(env); EAX = val; EDX = val >> 32; } diff --git a/tests/qruncom.c b/tests/qruncom.c index 491ecbc60..fcc069f6d 100644 --- a/tests/qruncom.c +++ b/tests/qruncom.c @@ -55,6 +55,11 @@ int cpu_get_pic_interrupt(CPUState *env) return -1; } +uint64_t cpu_get_tsc(CPUState *env) +{ + return 0; +} + static void set_gate(void *ptr, unsigned int type, unsigned int dpl, unsigned long addr, unsigned int sel) { -- cgit v1.2.3 From 15aeac38055aadc788b85eb1e66385723942ba8a Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 16:12:05 +0000 Subject: PIC spurious irq support (aka Solaris install bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@838 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + hw/i8259.c | 51 ++++++++++++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Changelog b/Changelog index a4717afbb..0f232e3ec 100644 --- a/Changelog +++ b/Changelog @@ -14,6 +14,7 @@ version 0.5.6: - dummy VGA PCI support - VGA font selection fix (Daniel Serpell) - PIC reset fix (Hidemi KAWAI) + - PIC spurious irq support (aka Solaris install bug) version 0.5.5: diff --git a/hw/i8259.c b/hw/i8259.c index 809ea95a5..7532d5c67 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -49,7 +49,6 @@ typedef struct PicState { /* 0 is master pic, 1 is slave pic */ static PicState pics[2]; -static int pic_irq_requested; /* set irq level. If an edge is detected, then the IRR is set to 1 */ static inline void pic_set_irq1(PicState *s, int irq, int level) @@ -130,13 +129,6 @@ static void pic_update_irq(void) /* look at requested irq */ irq = pic_get_irq(&pics[0]); if (irq >= 0) { - if (irq == 2) { - /* from slave pic */ - pic_irq_requested = 8 + irq2; - } else { - /* from master pic */ - pic_irq_requested = irq; - } #if defined(DEBUG_PIC) { int i; @@ -192,8 +184,31 @@ int cpu_get_pic_interrupt(CPUState *env) { int irq, irq2, intno; - /* signal the pic that the irq was acked by the CPU */ - irq = pic_irq_requested; + /* read the irq from the PIC */ + + irq = pic_get_irq(&pics[0]); + if (irq >= 0) { + pic_intack(&pics[0], irq); + if (irq == 2) { + irq2 = pic_get_irq(&pics[1]); + if (irq2 >= 0) { + pic_intack(&pics[1], irq2); + } else { + /* spurious IRQ on slave controller */ + irq2 = 7; + } + intno = pics[1].irq_base + irq2; + irq = irq2 + 8; + } else { + intno = pics[0].irq_base + irq; + } + } else { + /* spurious IRQ on host controller */ + irq = 7; + intno = pics[0].irq_base + irq; + } + pic_update_irq(); + #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", irq, @@ -202,17 +217,6 @@ int cpu_get_pic_interrupt(CPUState *env) #if defined(DEBUG_PIC) printf("pic_interrupt: irq=%d\n", irq); #endif - - if (irq >= 8) { - irq2 = irq & 7; - pic_intack(&pics[1], irq2); - irq = 2; - intno = pics[1].irq_base + irq2; - } else { - intno = pics[0].irq_base + irq; - } - pic_intack(&pics[0], irq); - pic_update_irq(); return intno; } @@ -452,9 +456,10 @@ void pic_info(void) for(i=0;i<2;i++) { s = &pics[i]; - term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x\n", + term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", i, s->irr, s->imr, s->isr, s->priority_add, - s->irq_base, s->read_reg_select, s->elcr); + s->irq_base, s->read_reg_select, s->elcr, + s->special_fully_nested_mode); } } -- cgit v1.2.3 From 274da6b24b93e98119de92f22fff24f79ba173ba Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 20 May 2004 21:56:27 +0000 Subject: 64 bit fix (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@839 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 8 +- linux-user/elfload.c | 2 +- ppc-dis.c | 245 ++++++++++++++++++++++++++------------------------- 3 files changed, 129 insertions(+), 126 deletions(-) diff --git a/exec.c b/exec.c index 5357dcdfb..b484dc6d5 100644 --- a/exec.c +++ b/exec.c @@ -1221,7 +1221,7 @@ void tlb_flush(CPUState *env, int flush_global) #endif } -static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr) +static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) { if (addr == (tlb_entry->address & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) @@ -1789,7 +1789,7 @@ static void code_mem_writeb(target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; - phys_addr = addr - (long)phys_ram_base; + phys_addr = addr - (unsigned long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 1); #endif @@ -1801,7 +1801,7 @@ static void code_mem_writew(target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; - phys_addr = addr - (long)phys_ram_base; + phys_addr = addr - (unsigned long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 2); #endif @@ -1813,7 +1813,7 @@ static void code_mem_writel(target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; - phys_addr = addr - (long)phys_ram_base; + phys_addr = addr - (unsigned long)phys_ram_base; #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 4); #endif diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 980ab6ba0..899e085c5 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -127,7 +127,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i */ #define ELF_PLAT_INIT(_r) \ do { \ - unsigned long *pos = (unsigned long *)bprm->p, tmp = 1; \ + target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \ _r->gpr[3] = bprm->argc; \ _r->gpr[4] = (unsigned long)++pos; \ for (; tmp != 0; pos++) \ diff --git a/ppc-dis.c b/ppc-dis.c index d01dcd6d1..354b2ac8c 100644 --- a/ppc-dis.c +++ b/ppc-dis.c @@ -48,18 +48,18 @@ struct powerpc_opcode /* The opcode itself. Those bits which will be filled in with operands are zeroes. */ - unsigned long opcode; + uint32_t 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 long mask; + uint32_t mask; /* One bit flags for the opcode. These are used to indicate which specific processors support the instructions. The defined values are listed below. */ - unsigned long flags; + uint32_t flags; /* An array of operand codes. Each code is an index into the operand table. They appear in the order which the operands must @@ -124,7 +124,7 @@ struct powerpc_operand 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 long (*insert)(unsigned long instruction, long op, + unsigned long (*insert)(uint32_t instruction, int32_t op, const char **errmsg); /* Extraction function. This is used by the disassembler. To @@ -144,10 +144,10 @@ struct powerpc_operand 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. */ - long (*extract) (unsigned long instruction, int *invalid); + long (*extract) (uint32_t instruction, int *invalid); /* One bit syntax flags. */ - unsigned long flags; + uint32_t flags; }; /* Elements in the table are retrieved by indexing with values from @@ -244,7 +244,7 @@ struct powerpc_macro /* One bit flags for the opcode. These are used to indicate which specific processors support the instructions. The values are the same as those for the struct powerpc_opcode flags field. */ - unsigned long flags; + uint32_t flags; /* A format string to turn the macro into a normal instruction. Each %N in the string is replaced with operand number N (zero @@ -288,43 +288,43 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * /* Local insertion and extraction functions. */ -static unsigned long insert_bat (unsigned long, long, const char **); -static long extract_bat(unsigned long, int *); -static unsigned long insert_bba(unsigned long, long, const char **); -static long extract_bba(unsigned long, int *); -static unsigned long insert_bd(unsigned long, long, const char **); -static long extract_bd(unsigned long, int *); -static unsigned long insert_bdm(unsigned long, long, const char **); -static long extract_bdm(unsigned long, int *); -static unsigned long insert_bdp(unsigned long, long, const char **); -static long extract_bdp(unsigned long, int *); -static unsigned long insert_bo(unsigned long, long, const char **); -static long extract_bo(unsigned long, int *); -static unsigned long insert_boe(unsigned long, long, const char **); -static long extract_boe(unsigned long, int *); -static unsigned long insert_ds(unsigned long, long, const char **); -static long extract_ds(unsigned long, int *); -static unsigned long insert_li(unsigned long, long, const char **); -static long extract_li(unsigned long, int *); -static unsigned long insert_mbe(unsigned long, long, const char **); -static long extract_mbe(unsigned long, int *); -static unsigned long insert_mb6(unsigned long, long, const char **); -static long extract_mb6(unsigned long, int *); -static unsigned long insert_nb(unsigned long, long, const char **); -static long extract_nb(unsigned long, int *); -static unsigned long insert_nsi(unsigned long, long, const char **); -static long extract_nsi(unsigned long, int *); -static unsigned long insert_ral(unsigned long, long, const char **); -static unsigned long insert_ram(unsigned long, long, const char **); -static unsigned long insert_ras(unsigned long, long, const char **); -static unsigned long insert_rbs(unsigned long, long, const char **); -static long extract_rbs(unsigned long, int *); -static unsigned long insert_sh6(unsigned long, long, const char **); -static long extract_sh6(unsigned long, int *); -static unsigned long insert_spr(unsigned long, long, const char **); -static long extract_spr(unsigned long, int *); -static unsigned long insert_tbr(unsigned long, long, const char **); -static long extract_tbr(unsigned long, int *); +static unsigned long insert_bat (uint32_t, int32_t, const char **); +static long extract_bat(uint32_t, int *); +static unsigned long insert_bba(uint32_t, int32_t, const char **); +static long extract_bba(uint32_t, int *); +static unsigned long insert_bd(uint32_t, int32_t, const char **); +static long extract_bd(uint32_t, int *); +static unsigned long insert_bdm(uint32_t, int32_t, const char **); +static long extract_bdm(uint32_t, int *); +static unsigned long insert_bdp(uint32_t, int32_t, const char **); +static long extract_bdp(uint32_t, int *); +static unsigned long insert_bo(uint32_t, int32_t, const char **); +static long extract_bo(uint32_t, int *); +static unsigned long insert_boe(uint32_t, int32_t, const char **); +static long extract_boe(uint32_t, int *); +static unsigned long insert_ds(uint32_t, int32_t, const char **); +static long extract_ds(uint32_t, int *); +static unsigned long insert_li(uint32_t, int32_t, const char **); +static long extract_li(uint32_t, int *); +static unsigned long insert_mbe(uint32_t, int32_t, const char **); +static long extract_mbe(uint32_t, int *); +static unsigned long insert_mb6(uint32_t, int32_t, const char **); +static long extract_mb6(uint32_t, int *); +static unsigned long insert_nb(uint32_t, int32_t, const char **); +static long extract_nb(uint32_t, int *); +static unsigned long insert_nsi(uint32_t, int32_t, const char **); +static long extract_nsi(uint32_t, int *); +static unsigned long insert_ral(uint32_t, int32_t, const char **); +static unsigned long insert_ram(uint32_t, int32_t, const char **); +static unsigned long insert_ras(uint32_t, int32_t, const char **); +static unsigned long insert_rbs(uint32_t, int32_t, const char **); +static long extract_rbs(uint32_t, int *); +static unsigned long insert_sh6(uint32_t, int32_t, const char **); +static long extract_sh6(uint32_t, int *); +static unsigned long insert_spr(uint32_t, int32_t, const char **); +static long extract_spr(uint32_t, int *); +static unsigned long insert_tbr(uint32_t, int32_t, const char **); +static long extract_tbr(uint32_t, int *); /* The operands table. @@ -648,8 +648,8 @@ const struct powerpc_operand powerpc_operands[] = /*ARGSUSED*/ static unsigned long insert_bat (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | (((insn >> 21) & 0x1f) << 16); @@ -657,7 +657,7 @@ insert_bat (insn, value, errmsg) static long extract_bat (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if (invalid != (int *) NULL @@ -675,8 +675,8 @@ extract_bat (insn, invalid) /*ARGSUSED*/ static unsigned long insert_bba (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | (((insn >> 16) & 0x1f) << 11); @@ -684,7 +684,7 @@ insert_bba (insn, value, errmsg) static long extract_bba (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if (invalid != (int *) NULL @@ -699,8 +699,8 @@ extract_bba (insn, invalid) /*ARGSUSED*/ static unsigned long insert_bd (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | (value & 0xfffc); @@ -709,7 +709,7 @@ insert_bd (insn, value, errmsg) /*ARGSUSED*/ static long extract_bd (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if ((insn & 0x8000) != 0) @@ -728,8 +728,8 @@ extract_bd (insn, invalid) /*ARGSUSED*/ static unsigned long insert_bdm (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if ((value & 0x8000) != 0) @@ -739,7 +739,7 @@ insert_bdm (insn, value, errmsg) static long extract_bdm (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if (invalid != (int *) NULL @@ -759,8 +759,8 @@ extract_bdm (insn, invalid) /*ARGSUSED*/ static unsigned long insert_bdp (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if ((value & 0x8000) == 0) @@ -770,7 +770,7 @@ insert_bdp (insn, value, errmsg) static long extract_bdp (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if (invalid != (int *) NULL @@ -786,7 +786,7 @@ extract_bdp (insn, invalid) /* Check for legal values of a BO field. */ static int -valid_bo (long value) +valid_bo (int32_t value) { /* Certain encodings have bits that are required to be zero. These are (z must be zero, y may be anything): @@ -815,8 +815,8 @@ valid_bo (long value) static unsigned long insert_bo (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if (errmsg != (const char **) NULL @@ -827,10 +827,10 @@ insert_bo (insn, value, errmsg) static long extract_bo (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { - long value; + int32_t value; value = (insn >> 21) & 0x1f; if (invalid != (int *) NULL @@ -845,8 +845,8 @@ extract_bo (insn, invalid) static unsigned long insert_boe (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if (errmsg != (const char **) NULL) @@ -861,10 +861,10 @@ insert_boe (insn, value, errmsg) static long extract_boe (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { - long value; + int32_t value; value = (insn >> 21) & 0x1f; if (invalid != (int *) NULL @@ -879,8 +879,8 @@ extract_boe (insn, invalid) /*ARGSUSED*/ static unsigned long insert_ds (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | (value & 0xfffc); @@ -889,7 +889,7 @@ insert_ds (insn, value, errmsg) /*ARGSUSED*/ static long extract_ds (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if ((insn & 0x8000) != 0) @@ -904,8 +904,8 @@ extract_ds (insn, invalid) /*ARGSUSED*/ static unsigned long insert_li (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | (value & 0x3fffffc); @@ -914,7 +914,7 @@ insert_li (insn, value, errmsg) /*ARGSUSED*/ static long extract_li (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if ((insn & 0x2000000) != 0) @@ -930,11 +930,11 @@ extract_li (insn, invalid) static unsigned long insert_mbe (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { - unsigned long uval; + uint32_t uval; int mb, me; uval = value; @@ -972,7 +972,7 @@ insert_mbe (insn, value, errmsg) static long extract_mbe (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { long ret; @@ -996,8 +996,8 @@ extract_mbe (insn, invalid) /*ARGSUSED*/ static unsigned long insert_mb6 (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | ((value & 0x1f) << 6) | (value & 0x20); @@ -1006,7 +1006,7 @@ insert_mb6 (insn, value, errmsg) /*ARGSUSED*/ static long extract_mb6 (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { return ((insn >> 6) & 0x1f) | (insn & 0x20); @@ -1017,8 +1017,8 @@ extract_mb6 (insn, invalid) static unsigned long insert_nb (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if (value < 0 || value > 32) @@ -1031,7 +1031,7 @@ insert_nb (insn, value, errmsg) /*ARGSUSED*/ static long extract_nb (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { long ret; @@ -1050,8 +1050,8 @@ extract_nb (insn, invalid) /*ARGSUSED*/ static unsigned long insert_nsi (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | ((- value) & 0xffff); @@ -1059,7 +1059,7 @@ insert_nsi (insn, value, errmsg) static long extract_nsi (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if (invalid != (int *) NULL) @@ -1076,8 +1076,8 @@ extract_nsi (insn, invalid) static unsigned long insert_ral (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if (value == 0 @@ -1091,8 +1091,8 @@ insert_ral (insn, value, errmsg) static unsigned long insert_ram (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if (value >= ((insn >> 21) & 0x1f)) @@ -1106,8 +1106,8 @@ insert_ram (insn, value, errmsg) static unsigned long insert_ras (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if (value == 0) @@ -1124,8 +1124,8 @@ insert_ras (insn, value, errmsg) /*ARGSUSED*/ static unsigned long insert_rbs (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | (((insn >> 21) & 0x1f) << 11); @@ -1133,7 +1133,7 @@ insert_rbs (insn, value, errmsg) static long extract_rbs (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { if (invalid != (int *) NULL @@ -1147,8 +1147,8 @@ extract_rbs (insn, invalid) /*ARGSUSED*/ static unsigned long insert_sh6 (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4); @@ -1157,7 +1157,7 @@ insert_sh6 (insn, value, errmsg) /*ARGSUSED*/ static long extract_sh6 (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20); @@ -1168,8 +1168,8 @@ extract_sh6 (insn, invalid) static unsigned long insert_spr (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); @@ -1177,7 +1177,7 @@ insert_spr (insn, value, errmsg) static long extract_spr (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); @@ -1195,8 +1195,8 @@ extract_spr (insn, invalid) static unsigned long insert_tbr (insn, value, errmsg) - unsigned long insn; - long value; + uint32_t insn; + int32_t value; const char **errmsg; { if (value == 0) @@ -1206,7 +1206,7 @@ insert_tbr (insn, value, errmsg) static long extract_tbr (insn, invalid) - unsigned long insn; + uint32_t insn; int *invalid; { long ret; @@ -3067,27 +3067,30 @@ const struct powerpc_macro powerpc_macros[] = { const int powerpc_num_macros = sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); -static int print_insn_powerpc(FILE *, unsigned long insn, unsigned memaddr, int dialect); +static int print_insn_powerpc(FILE *, uint32_t insn, unsigned memaddr, int dialect); /* Print a big endian PowerPC instruction. For convenience, also disassemble instructions supported by the Motorola PowerPC 601. */ +#include "cpu.h" int print_insn_ppc (bfd_vma pc, disassemble_info *info) { - return print_insn_powerpc (info->stream, - (unsigned int)bfd_getb32((bfd_byte *)pc), pc, - PPC_OPCODE_PPC | PPC_OPCODE_601); + uint32_t opc; + + (*info->read_memory_func)(pc, (bfd_byte *)(&opc), 4, info); + return print_insn_powerpc (info->stream, tswap32(opc), pc, + PPC | B32 | M601); } /* Print a PowerPC or POWER instruction. */ -static int -print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, +int +print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr, int dialect) { const struct powerpc_opcode *opcode; const struct powerpc_opcode *opcode_end; - unsigned long op; + uint32_t op; /* Get the major opcode of the instruction. */ op = PPC_OP (insn); @@ -3097,7 +3100,7 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, opcode_end = powerpc_opcodes + powerpc_num_opcodes; for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) { - unsigned long table_op; + uint32_t table_op; const unsigned char *opindex; const struct powerpc_operand *operand; int invalid; @@ -3137,7 +3140,7 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, need_paren = 0; for (opindex = opcode->operands; *opindex != 0; opindex++) { - long value; + int32_t value; operand = powerpc_operands + *opindex; @@ -3173,20 +3176,20 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, /* Print the operand as directed by the flags. */ if ((operand->flags & PPC_OPERAND_GPR) != 0) - fprintf(out, "r%ld", value); + fprintf(out, "r%d", value); else if ((operand->flags & PPC_OPERAND_FPR) != 0) - fprintf(out, "f%ld", value); + fprintf(out, "f%d", value); else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) - fprintf(out, "%08lX", memaddr + value); + fprintf(out, "%08X", memaddr + value); else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) - fprintf(out, "%08lX", value & 0xffffffff); + fprintf(out, "%08X", value & 0xffffffff); else if ((operand->flags & PPC_OPERAND_CR) == 0 || (dialect & PPC_OPCODE_PPC) == 0) - fprintf(out, "%ld", value); + fprintf(out, "%d", value); else { if (operand->bits == 3) - fprintf(out, "cr%ld", value); + fprintf(out, "cr%d", value); else { static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; @@ -3226,7 +3229,7 @@ print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, } /* We could not find a match. */ - fprintf(out, ".long 0x%lx", insn); + fprintf(out, ".long 0x%x", insn); return 4; } -- cgit v1.2.3 From 4a0fb71e67df4774d79eb788f0d1bd7a78801e6d Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 21 May 2004 11:39:07 +0000 Subject: irq statistics code (initial patch by Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@840 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 35 +++++++++++++++++++++++++++++++---- monitor.c | 2 ++ vl.h | 1 + 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/hw/i8259.c b/hw/i8259.c index 7532d5c67..62e11f0ef 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -27,6 +27,7 @@ //#define DEBUG_PIC //#define DEBUG_IRQ_LATENCY +//#define DEBUG_IRQ_COUNT typedef struct PicState { uint8_t last_irr; /* edge detection */ @@ -50,6 +51,13 @@ typedef struct PicState { /* 0 is master pic, 1 is slave pic */ static PicState pics[2]; +#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT) +static int irq_level[16]; +#endif +#ifdef DEBUG_IRQ_COUNT +static uint64_t irq_count[16]; +#endif + /* set irq level. If an edge is detected, then the IRR is set to 1 */ static inline void pic_set_irq1(PicState *s, int irq, int level) { @@ -147,16 +155,19 @@ static void pic_update_irq(void) #ifdef DEBUG_IRQ_LATENCY int64_t irq_time[16]; #endif -#if defined(DEBUG_PIC) -int irq_level[16]; -#endif void pic_set_irq(int irq, int level) { -#if defined(DEBUG_PIC) +#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq]) { +#if defined(DEBUG_PIC) printf("pic_set_irq: irq=%d level=%d\n", irq, level); +#endif irq_level[irq] = level; +#ifdef DEBUG_IRQ_COUNT + if (level == 1) + irq_count[irq]++; +#endif } #endif #ifdef DEBUG_IRQ_LATENCY @@ -463,6 +474,22 @@ void pic_info(void) } } +void irq_info(void) +{ +#ifndef DEBUG_IRQ_COUNT + term_printf("irq statistic code not compiled.\n"); +#else + int i; + int64_t count; + + term_printf("IRQ statistics:\n"); + for (i = 0; i < 16; i++) { + count = irq_count[i]; + if (count > 0) + term_printf("%2d: %lld\n", i, count); + } +#endif +} void pic_init(void) { diff --git a/monitor.c b/monitor.c index 2dc94b44a..f5ab04336 100644 --- a/monitor.c +++ b/monitor.c @@ -523,6 +523,8 @@ static term_cmd_t info_cmds[] = { "", "show the cpu registers" }, { "history", "", do_info_history, "", "show the command line history", }, + { "irq", "", irq_info, + "", "show the interrupts statistics (if available)", }, { "pic", "", pic_info, "", "show i8259 (PIC) state", }, { "pci", "", pci_info, diff --git a/vl.h b/vl.h index ace401fbb..8026dec65 100644 --- a/vl.h +++ b/vl.h @@ -544,6 +544,7 @@ void pic_set_irq(int irq, int level); void pic_init(void); uint32_t pic_intack_read(CPUState *env); void pic_info(void); +void irq_info(void); /* i8254.c */ -- cgit v1.2.3 From 9fddaa0c0cabb610947146a79b4a9a38b0a216e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 21 May 2004 12:59:32 +0000 Subject: PowerPC merge: real time TB and decrementer - faster and simpler exception handling (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@841 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 5 +- cpu-exec.c | 20 +++- exec.c | 2 + hw/ppc.c | 175 +++++++++++++++++++++++++++++++++++ hw/ppc_prep.c | 7 +- linux-user/main.c | 50 ++++++++-- monitor.c | 24 ++++- target-ppc/cpu.h | 35 +++---- target-ppc/exec.h | 8 +- target-ppc/helper.c | 54 ++--------- target-ppc/op.c | 77 +++++----------- target-ppc/op_helper.c | 52 +++++------ target-ppc/op_mem.h | 9 +- target-ppc/translate.c | 242 ++++++++++++++++++++++++------------------------- 14 files changed, 463 insertions(+), 297 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 69b6e7c36..bb6e74a3f 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -627,14 +627,15 @@ void cpu_single_step(CPUState *env, int enabled); 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_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 { diff --git a/cpu-exec.c b/cpu-exec.c index 12e848b13..58468859d 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -241,11 +241,25 @@ int cpu_exec(CPUState *env1) #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)) { - do_queue_exception(EXCP_EXTERNAL); - if (check_exception_state(env)) + /* Raise it */ + env->exception_index = EXCP_EXTERNAL; + env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; + } 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; + } } #endif if (interrupt_request & CPU_INTERRUPT_EXITTB) { @@ -757,7 +771,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); - do_queue_exception_err(env->exception_index, env->error_code); + do_raise_exception_err(env->exception_index, env->error_code); } else { /* activate soft MMU for this block */ cpu_resume_from_signal(env, puc); diff --git a/exec.c b/exec.c index b484dc6d5..695779ab2 100644 --- a/exec.c +++ b/exec.c @@ -1132,6 +1132,8 @@ CPULogItem cpu_log_items[] = { "show interrupts/exceptions in short format" }, { CPU_LOG_EXEC, "exec", "show trace before each executed TB (lots of logs)" }, + { CPU_LOG_TB_CPU, "cpu", + "show CPU state before bloc translation" }, #ifdef TARGET_I386 { CPU_LOG_PCALL, "pcall", "show protected mode far calls/returns/exceptions" }, diff --git a/hw/ppc.c b/hw/ppc.c index 7cba03b36..3858952a5 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -28,6 +28,181 @@ void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); +/*****************************************************************************/ +/* PPC time base and decrementer emulation */ +//#define DEBUG_TB + +struct ppc_tb_t { + /* Time base management */ + int64_t tb_offset; /* Compensation */ + uint32_t tb_freq; /* TB frequency */ + /* Decrementer management */ + uint64_t decr_next; /* Tick for next decr interrupt */ + struct QEMUTimer *decr_timer; +}; + +static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env) +{ + /* TB time in tb periods */ + return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, + tb_env->tb_freq, ticks_per_sec); +} + +uint32_t cpu_ppc_load_tbl (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env); +#ifdef DEBUG_TB + { + static int last_time; + int now; + now = time(NULL); + if (last_time != now) { + last_time = now; + printf("%s: tb=0x%016lx %d %08lx\n", + __func__, tb, now, tb_env->tb_offset); + } + } +#endif + + return tb & 0xFFFFFFFF; +} + +uint32_t cpu_ppc_load_tbu (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env); +#ifdef DEBUG_TB + printf("%s: tb=0x%016lx\n", __func__, tb); +#endif + return tb >> 32; +} + +static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) +{ + tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) + - qemu_get_clock(vm_clock); +#ifdef DEBUG_TB + printf("%s: tb=0x%016lx offset=%08x\n", __func__, value); +#endif +} + +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + + cpu_ppc_store_tb(tb_env, + ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); +} + +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + + cpu_ppc_store_tb(tb_env, + ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); +} + +uint32_t cpu_ppc_load_decr (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint32_t decr; + + decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock), + tb_env->tb_freq, ticks_per_sec); +#ifdef DEBUG_TB + printf("%s: 0x%08x\n", __func__, decr); +#endif + + return decr; +} + +/* When decrementer expires, + * all we need to do is generate or queue a CPU exception + */ +static inline void cpu_ppc_decr_excp (CPUState *env) +{ + /* Raise it */ +#ifdef DEBUG_TB + printf("raise decrementer exception\n"); +#endif + cpu_interrupt(env, CPU_INTERRUPT_TIMER); +} + +static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, + uint32_t value, int is_excp) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t now, next; + +#ifdef DEBUG_TB + printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value); +#endif + now = qemu_get_clock(vm_clock); + next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); + if (is_excp) + next += tb_env->decr_next - now; + if (next == now) + next++; + tb_env->decr_next = next; + /* Adjust timer */ + qemu_mod_timer(tb_env->decr_timer, next); + /* If we set a negative value and the decrementer was positive, + * raise an exception. + */ + if ((value & 0x80000000) && !(decr & 0x80000000)) + cpu_ppc_decr_excp(env); +} + +void cpu_ppc_store_decr (CPUState *env, uint32_t value) +{ + _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0); +} + +static void cpu_ppc_decr_cb (void *opaque) +{ + _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); +} + +/* Set up (once) timebase frequency (in Hz) */ +ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq) +{ + ppc_tb_t *tb_env; + + tb_env = qemu_mallocz(sizeof(ppc_tb_t)); + if (tb_env == NULL) + return NULL; + env->tb_env = tb_env; + if (tb_env->tb_freq == 0 || 1) { + tb_env->tb_freq = freq; + /* Create new timer */ + tb_env->decr_timer = + qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); + /* There is a bug in 2.4 kernels: + * if a decrementer exception is pending when it enables msr_ee, + * it's not ready to handle it... + */ + _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); + } + + return tb_env; +} + +#if 0 +/*****************************************************************************/ +/* Handle system reset (for now, just stop emulation) */ +void cpu_ppc_reset (CPUState *env) +{ + printf("Reset asked... Stop emulation\n"); + abort(); +} +#endif + +/*****************************************************************************/ void ppc_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index f64649cf5..05783992b 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -24,6 +24,9 @@ #include "vl.h" #include "m48t59.h" +/* XXX: move all TB related stuff in ppc_prep.c and suppress ppc.c ? */ +ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); + //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO @@ -663,7 +666,6 @@ static void VGA_printf (uint8_t *s) static void VGA_init (void) { /* Basic VGA init, inspired by plex86 VGAbios */ - printf("Init VGA...\n"); #if 1 /* switch to color mode and enable CPU access 480 lines */ PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); @@ -725,7 +727,6 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, * if a decrementer exception is pending when it enables msr_ee, * it's not ready to handle it... */ - env->decr = 0xFFFFFFFF; p = phys_ram_base + kernel_addr; #if !defined (USE_OPEN_FIRMWARE) /* Let's register the whole memory available only in supervisor mode */ @@ -948,6 +949,8 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, } } + cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); + /* init basic PC hardware */ vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0); diff --git a/linux-user/main.c b/linux-user/main.c index c0759bfef..2275b01f9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -504,6 +504,49 @@ void cpu_loop (CPUSPARCState *env) #endif #ifdef TARGET_PPC + +static inline uint64_t cpu_ppc_get_tb (CPUState *env) +{ + /* TO FIX */ + return 0; +} + +uint32_t cpu_ppc_load_tbl (CPUState *env) +{ + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; +} + +uint32_t cpu_ppc_load_tbu (CPUState *env) +{ + return cpu_ppc_get_tb(env) >> 32; +} + +static void cpu_ppc_store_tb (CPUState *env, uint64_t value) +{ + /* TO FIX */ +} + +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); +} + +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); +} + +uint32_t cpu_ppc_load_decr (CPUState *env) +{ + /* TO FIX */ + return -1; +} + +void cpu_ppc_store_decr (CPUState *env, uint32_t value) +{ + /* TO FIX */ +} + void cpu_loop(CPUPPCState *env) { target_siginfo_t info; @@ -812,7 +855,7 @@ void cpu_loop(CPUPPCState *env) abort(); case EXCP_MTMSR: /* We reloaded the msr, just go on */ - if (msr_pr) { + if (msr_pr == 0) { fprintf(stderr, "Tried to go into supervisor mode !\n"); if (loglevel) fprintf(logfile, "Tried to go into supervisor mode !\n"); @@ -842,12 +885,7 @@ void cpu_loop(CPUPPCState *env) } abort(); } - if (trapnr < EXCP_PPC_MAX) - env->exceptions &= ~(1 << trapnr); process_pending_signals(env); - if (env->exceptions != 0) { - check_exception_state(env); - } } } #endif diff --git a/monitor.c b/monitor.c index f5ab04336..ab1c842bc 100644 --- a/monitor.c +++ b/monitor.c @@ -589,6 +589,24 @@ static int monitor_get_xer (struct MonitorDef *md) (cpu_single_env->xer[XER_CA] << XER_CA) | (cpu_single_env->xer[XER_BC] << XER_BC); } + +uint32_t cpu_ppc_load_decr (CPUState *env); +static int monitor_get_decr (struct MonitorDef *md) +{ + return cpu_ppc_load_decr(cpu_single_env); +} + +uint32_t cpu_ppc_load_tbu (CPUState *env); +static int monitor_get_tbu (struct MonitorDef *md) +{ + return cpu_ppc_load_tbu(cpu_single_env); +} + +uint32_t cpu_ppc_load_tbl (CPUState *env); +static int monitor_get_tbl (struct MonitorDef *md) +{ + return cpu_ppc_load_tbl(cpu_single_env); +} #endif static MonitorDef monitor_defs[] = { @@ -651,12 +669,12 @@ static MonitorDef monitor_defs[] = { { "nip|pc", offsetof(CPUState, nip) }, { "lr", offsetof(CPUState, lr) }, { "ctr", offsetof(CPUState, ctr) }, - { "decr", offsetof(CPUState, decr) }, + { "decr", 0, &monitor_get_decr, }, { "ccr", 0, &monitor_get_ccr, }, { "msr", 0, &monitor_get_msr, }, { "xer", 0, &monitor_get_xer, }, - { "tbu", offsetof(CPUState, tb[0]) }, - { "tbl", offsetof(CPUState, tb[1]) }, + { "tbu", 0, &monitor_get_tbu, }, + { "tbl", 0, &monitor_get_tbl, }, { "sdr1", offsetof(CPUState, sdr1) }, { "sr0", offsetof(CPUState, sr[0]) }, { "sr1", offsetof(CPUState, sr[1]) }, diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e6cb0946d..bd430aff5 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -78,6 +78,8 @@ enum { #define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT) +typedef struct ppc_tb_t ppc_tb_t; + /* Supervisor mode registers */ /* Machine state register */ #define MSR_POW 18 @@ -134,10 +136,6 @@ typedef struct CPUPPCState { /* special purpose registers */ uint32_t lr; uint32_t ctr; - /* Time base */ - uint32_t tb[2]; - /* decrementer */ - uint32_t decr; /* BATs */ uint32_t DBAT[2][8]; uint32_t IBAT[2][8]; @@ -154,13 +152,6 @@ typedef struct CPUPPCState { int error_code; int access_type; /* when a memory exception occurs, the access type is stored here */ -#if 0 /* TODO */ - uint32_t pending_exceptions; /* For external & decr exception, - * that can be delayed */ -#else - uint32_t exceptions; /* exception queue */ - uint32_t errors[32]; -#endif int user_mode_only; /* user mode only simulation */ struct TranslationBlock *current_tb; /* currently executing TB */ /* soft mmu support */ @@ -178,8 +169,13 @@ typedef struct CPUPPCState { /* ice debug support */ uint32_t breakpoints[MAX_BREAKPOINTS]; int nb_breakpoints; - int brkstate; - int singlestep_enabled; + int singlestep_enabled; /* XXX: should use CPU single step mode instead */ + + /* Time base and decrementer */ + ppc_tb_t *tb_env; + + /* Power management */ + int power_mode; /* user data */ void *opaque; @@ -206,10 +202,15 @@ void _store_xer (CPUPPCState *env, uint32_t value); uint32_t _load_msr (CPUPPCState *env); void _store_msr (CPUPPCState *env, uint32_t value); -void PPC_init_hw (uint32_t mem_size, - uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device, - const unsigned char *initrd_file); +/* Time-base and decrementer management */ +#ifndef NO_CPU_IO_DEFS +uint32_t cpu_ppc_load_tbl (CPUPPCState *env); +uint32_t cpu_ppc_load_tbu (CPUPPCState *env); +void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); +void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); +uint32_t cpu_ppc_load_decr (CPUPPCState *env); +void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); +#endif #define TARGET_PAGE_BITS 12 #include "cpu-all.h" diff --git a/target-ppc/exec.h b/target-ppc/exec.h index f4d20a8ad..edb73ef05 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -119,12 +119,8 @@ static inline uint32_t rotl (uint32_t i, int n) #endif /* !defined(CONFIG_USER_ONLY) */ -int check_exception_state (CPUState *env); - -void do_queue_exception_err (uint32_t exception, int error_code); -void do_queue_exception (uint32_t exception); -void do_process_exceptions (void); -void do_check_exception_state (void); +void do_raise_exception_err (uint32_t exception, int error_code); +void do_raise_exception (uint32_t exception); void do_load_cr (void); void do_store_cr (uint32_t mask); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 09c0eebbe..e8b776b07 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -27,49 +27,10 @@ //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS -extern FILE *logfile, *stdout, *stderr; -void exit (int); +extern FILE *stdout, *stderr; void abort (void); -void cpu_loop_exit(void) -{ - longjmp(env->jmp_env, 1); -} - -void do_process_exceptions (void) -{ - cpu_loop_exit(); -} - -int check_exception_state (CPUState *env) -{ - int i; - - /* Process PPC exceptions */ - for (i = 1; i < EXCP_PPC_MAX; i++) { - if (env->exceptions & (1 << i)) { - switch (i) { - case EXCP_EXTERNAL: - case EXCP_DECR: - if (msr_ee == 0) - return 0; - break; - case EXCP_PROGRAM: - if (env->errors[EXCP_PROGRAM] == EXCP_FP && - msr_fe0 == 0 && msr_fe1 == 0) - return 0; - break; - default: - break; - } - env->exception_index = i; - env->error_code = env->errors[i]; - return 1; - } - } - - return 0; -} +/*****************************************************************************/ /*****************************************************************************/ /* PPC MMU emulation */ @@ -500,8 +461,7 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) cpu_restore_state(tb, env, pc, NULL); } } - do_queue_exception_err(env->exception_index, env->error_code); - do_process_exceptions(); + do_raise_exception_err(env->exception_index, env->error_code); } { unsigned long tlb_addrr, tlb_addrw; @@ -701,9 +661,6 @@ void do_interrupt (CPUState *env) uint32_t msr; int excp = env->exception_index; - /* Dequeue PPC exceptions */ - if (excp < EXCP_PPC_MAX) - env->exceptions &= ~(1 << excp); msr = _load_msr(env); #if defined (DEBUG_EXCEPTIONS) if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) @@ -812,7 +769,7 @@ void do_interrupt (CPUState *env) } #endif /* Requeue it */ - do_queue_exception(EXCP_EXTERNAL); + do_raise_exception(EXCP_EXTERNAL); return; } goto store_next; @@ -864,7 +821,7 @@ void do_interrupt (CPUState *env) case EXCP_DECR: if (msr_ee == 0) { /* Requeue it */ - do_queue_exception(EXCP_DECR); + do_raise_exception(EXCP_DECR); return; } goto store_next; @@ -937,4 +894,5 @@ void do_interrupt (CPUState *env) T0 = 0; #endif #endif + env->exception_index = -1; } diff --git a/target-ppc/op.c b/target-ppc/op.c index de7e24735..38eae7f74 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -208,32 +208,28 @@ PPC_OP(set_T2) } /* Generate exceptions */ -PPC_OP(queue_exception_err) +PPC_OP(raise_exception_err) { - do_queue_exception_err(PARAM(1), PARAM(2)); + do_raise_exception_err(PARAM(1), PARAM(2)); } -PPC_OP(queue_exception) +PPC_OP(raise_exception) { - do_queue_exception(PARAM(1)); + do_raise_exception(PARAM(1)); } -PPC_OP(process_exceptions) +PPC_OP(update_nip) { env->nip = PARAM(1); - if (env->exceptions != 0) { - do_check_exception_state(); - } } PPC_OP(debug) { env->nip = PARAM(1); - env->brkstate = 1; #if defined (DEBUG_OP) dump_state(); #endif - do_queue_exception(EXCP_DEBUG); + do_raise_exception(EXCP_DEBUG); RETURN(); } @@ -364,58 +360,38 @@ PPC_OP(store_ctr) RETURN(); } -/* Update time base */ -PPC_OP(update_tb) +PPC_OP(load_tbl) { - T0 = regs->tb[0]; - T1 = T0; - T0 += PARAM(1); -#if defined (DEBUG_OP) - dump_update_tb(PARAM(1)); -#endif - if (T0 < T1) { - T1 = regs->tb[1] + 1; - regs->tb[1] = T1; - } - regs->tb[0] = T0; + T0 = cpu_ppc_load_tbl(regs); RETURN(); } -PPC_OP(load_tb) +PPC_OP(load_tbu) { - T0 = regs->tb[PARAM(1)]; + T0 = cpu_ppc_load_tbu(regs); RETURN(); } -PPC_OP(store_tb) +PPC_OP(store_tbl) { - regs->tb[PARAM(1)] = T0; -#if defined (DEBUG_OP) - dump_store_tb(PARAM(1)); -#endif + cpu_ppc_store_tbl(regs, T0); RETURN(); } -/* Update decrementer */ -PPC_OP(update_decr) +PPC_OP(store_tbu) { - T0 = regs->decr; - T1 = T0; - T0 -= PARAM(1); - regs->decr = T0; - if (PARAM(1) > T1) { - do_queue_exception(EXCP_DECR); - } + cpu_ppc_store_tbu(regs, T0); RETURN(); } -PPC_OP(store_decr) +PPC_OP(load_decr) { - T1 = regs->decr; - regs->decr = T0; - if (Ts0 < 0 && Ts1 > 0) { - do_queue_exception(EXCP_DECR); + T0 = cpu_ppc_load_decr(regs); } + +PPC_OP(store_decr) +{ + cpu_ppc_store_decr(regs, T0); RETURN(); } @@ -1471,17 +1447,14 @@ PPC_OP(fneg) /* Return from interrupt */ PPC_OP(rfi) { + regs->nip = regs->spr[SRR0] & ~0x00000003; T0 = regs->spr[SRR1] & ~0xFFFF0000; do_store_msr(); - do_tlbia(); #if defined (DEBUG_OP) dump_rfi(); #endif - regs->nip = regs->spr[SRR0] & ~0x00000003; - do_queue_exception(EXCP_RFI); - if (env->exceptions != 0) { - do_check_exception_state(); - } + // do_tlbia(); + do_raise_exception(EXCP_RFI); RETURN(); } @@ -1493,7 +1466,7 @@ PPC_OP(tw) (Ts0 == Ts1 && (PARAM(1) & 0x04)) || (T0 < T1 && (PARAM(1) & 0x02)) || (T0 > T1 && (PARAM(1) & 0x01))) - do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP); + do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); RETURN(); } @@ -1504,7 +1477,7 @@ PPC_OP(twi) (Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) || (T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) || (T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01))) - do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP); + do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index ae3d254d9..3ddda1e33 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -31,31 +31,38 @@ /*****************************************************************************/ /* Exceptions processing helpers */ -void do_queue_exception_err (uint32_t exception, int error_code) +void cpu_loop_exit(void) { - /* Queue real PPC exceptions */ - if (exception < EXCP_PPC_MAX) { - env->exceptions |= 1 << exception; - env->errors[exception] = error_code; - } else { - /* Preserve compatibility with qemu core */ - env->exceptions |= 1; - env->exception_index = exception; - env->error_code = error_code; - } + longjmp(env->jmp_env, 1); } -void do_queue_exception (uint32_t exception) +void do_raise_exception_err (uint32_t exception, int error_code) { - do_queue_exception_err(exception, 0); -} - -void do_check_exception_state (void) -{ - if ((env->exceptions & 1) == 1 || check_exception_state(env)) { - env->exceptions &= ~1; +#if 0 + printf("Raise exception %3x code : %d\n", exception, error_code); +#endif + switch (exception) { + case EXCP_EXTERNAL: + case EXCP_DECR: + printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n"); + if (msr_ee == 0) + return; + break; + case EXCP_PROGRAM: + if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) + return; + break; + default: + break; +} + env->exception_index = exception; + env->error_code = error_code; cpu_loop_exit(); } + +void do_raise_exception (uint32_t exception) +{ + do_raise_exception_err(exception, 0); } /*****************************************************************************/ @@ -125,13 +132,6 @@ void do_store_msr (void) /* Flush all tlb when changing translation mode or privilege level */ do_tlbia(); } -#if 0 - if ((T0 >> MSR_IP) & 0x01) { - printf("Halting CPU. Stop emulation\n"); - do_queue_exception(EXCP_HLT); - cpu_loop_exit(); - } -#endif msr_pow = (T0 >> MSR_POW) & 0x03; msr_ile = (T0 >> MSR_ILE) & 0x01; msr_ee = (T0 >> MSR_EE) & 0x01; diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 52f55c91b..b5d10cecb 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -97,8 +97,7 @@ PPC_OP(glue(lswx, MEMSUFFIX)) if (T1 > 0) { if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) || (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) { - do_queue_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); - do_process_exceptions(); + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); } else { glue(do_lsw, MEMSUFFIX)(PARAM(1)); } @@ -138,8 +137,7 @@ PPC_LDF_OP(fs, ldfl); PPC_OP(glue(lwarx, MEMSUFFIX)) { if (T0 & 0x03) { - do_queue_exception(EXCP_ALIGN); - do_process_exceptions(); + do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ldl, MEMSUFFIX)((void *)T0); regs->reserve = T0; @@ -151,8 +149,7 @@ PPC_OP(glue(lwarx, MEMSUFFIX)) PPC_OP(glue(stwcx, MEMSUFFIX)) { if (T0 & 0x03) { - do_queue_exception(EXCP_ALIGN); - do_process_exceptions(); + do_raise_exception(EXCP_ALIGN); } else { if (regs->reserve != T0) { env->crf[0] = xer_ov; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 009097302..021cc7413 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -30,6 +30,7 @@ //#define DO_SINGLE_STEP //#define DO_STEP_FLUSH //#define DEBUG_DISAS +//#define PPC_DEBUG_DISAS enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, @@ -135,10 +136,6 @@ typedef struct DisasContext { uint32_t nip; uint32_t opcode; uint32_t exception; - /* Time base offset */ - uint32_t tb_offset; - /* Decrementer offset */ - uint32_t decr_offset; /* Execution mode */ #if !defined(CONFIG_USER_ONLY) int supervisor; @@ -156,21 +153,26 @@ typedef struct opc_handler_t { void (*handler)(DisasContext *ctx); } opc_handler_t; -#define RET_EXCP(excp, error) \ +#define RET_EXCP(ctx, excp, error) \ do { \ - gen_op_queue_exception_err(excp, error); \ - ctx->exception = excp; \ - return; \ + if ((ctx)->exception == EXCP_NONE) { \ + gen_op_update_nip((ctx)->nip); \ + } \ + gen_op_raise_exception_err((excp), (error)); \ + ctx->exception = (excp); \ } while (0) -#define RET_INVAL() \ -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) +#define RET_INVAL(ctx) \ +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) + +#define RET_PRIVOPC(ctx) \ +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) -#define RET_PRIVOPC() \ -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) +#define RET_PRIVREG(ctx) \ +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) -#define RET_PRIVREG() \ -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) +#define RET_MTMSR(ctx) \ +RET_EXCP((ctx), EXCP_MTMSR, 0) #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ static void gen_##name (DisasContext *ctx); \ @@ -312,29 +314,26 @@ GEN_OPCODE_MARK(start); /* Invalid instruction */ GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE) { - RET_INVAL(); + RET_INVAL(ctx); } /* Special opcode to stop emulation */ GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON) { - gen_op_queue_exception(EXCP_HLT); - ctx->exception = EXCP_HLT; + RET_EXCP(ctx, EXCP_HLT, 0); } /* Special opcode to call open-firmware */ GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON) { - gen_op_queue_exception(EXCP_OFCALL); - ctx->exception = EXCP_OFCALL; + RET_EXCP(ctx, EXCP_OFCALL, 0); } /* Special opcode to call RTAS */ GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON) { printf("RTAS entry point !\n"); - gen_op_queue_exception(EXCP_RTASCALL); - ctx->exception = EXCP_RTASCALL; + RET_EXCP(ctx, EXCP_RTASCALL, 0); } static opc_handler_t invalid_handler = { @@ -1010,7 +1009,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ if (simm != 0) \ @@ -1025,7 +1025,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -1086,7 +1087,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ if (simm != 0) \ @@ -1100,7 +1102,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -1236,7 +1239,8 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) nr = nb / 4; if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) || ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) { - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + return; } if (ra == 0) { gen_op_set_T0(0); @@ -1376,7 +1380,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ if (simm != 0) \ @@ -1391,7 +1396,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -1448,7 +1454,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (rA(ctx->opcode) == 0) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ if (simm != 0) \ @@ -1462,7 +1469,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ if (rA(ctx->opcode) == 0) { \ - RET_INVAL(); \ + RET_INVAL(ctx); \ + return; \ } \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -1502,7 +1510,7 @@ GEN_STFS(fs, 0x14); /* stfiwx */ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) { - RET_INVAL(); + RET_INVAL(ctx); } /*** Branch ***/ @@ -1512,9 +1520,6 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { uint32_t li = s_ext24(LI(ctx->opcode)), target; - gen_op_update_tb(ctx->tb_offset); - gen_op_update_decr(ctx->decr_offset); - gen_op_process_exceptions(ctx->nip - 4); if (AA(ctx->opcode) == 0) target = ctx->nip + li - 4; else @@ -1538,10 +1543,6 @@ static inline void gen_bcond(DisasContext *ctx, int type) uint32_t mask; uint32_t li; - gen_op_update_tb(ctx->tb_offset); - gen_op_update_decr(ctx->decr_offset); - gen_op_process_exceptions(ctx->nip - 4); - if ((bo & 0x4) == 0) gen_op_dec_ctr(); switch(type) { @@ -1683,14 +1684,15 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else /* Restore CPU state */ if (!ctx->supervisor) { - RET_PRIVOPC(); + RET_PRIVOPC(ctx); + return; } gen_op_rfi(); - ctx->exception = EXCP_RFI; + RET_EXCP(ctx, EXCP_RFI, 0); #endif } @@ -1698,11 +1700,10 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) { #if defined(CONFIG_USER_ONLY) - gen_op_queue_exception(EXCP_SYSCALL_USER); + RET_EXCP(ctx, EXCP_SYSCALL_USER, 0); #else - gen_op_queue_exception(EXCP_SYSCALL); + RET_EXCP(ctx, EXCP_SYSCALL, 0); #endif - ctx->exception = EXCP_SYSCALL; } /*** Trap ***/ @@ -1770,10 +1771,11 @@ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC) GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_msr(); gen_op_store_T0_gpr(rD(ctx->opcode)); @@ -1792,11 +1794,11 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) #endif { case -1: - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); - break; + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + return; case 0: - RET_PRIVREG(); - break; + RET_PRIVREG(ctx); + return; default: break; } @@ -1910,19 +1912,13 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) gen_op_load_sdr1(); break; case V_TBL: - gen_op_update_tb(ctx->tb_offset); - ctx->tb_offset = 0; - /* TBL is still in T0 */ + gen_op_load_tbl(); break; case V_TBU: - gen_op_update_tb(ctx->tb_offset); - ctx->tb_offset = 0; - gen_op_load_tb(1); + gen_op_load_tbu(); break; case DECR: - gen_op_update_decr(ctx->decr_offset); - ctx->decr_offset = 0; - /* decr is still in T0 */ + gen_op_load_decr(); break; default: gen_op_load_spr(sprn); @@ -1939,18 +1935,16 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) /* We need to update the time base before reading it */ switch (sprn) { case V_TBL: - gen_op_update_tb(ctx->tb_offset); /* TBL is still in T0 */ + gen_op_load_tbl(); break; case V_TBU: - gen_op_update_tb(ctx->tb_offset); - gen_op_load_tb(1); + gen_op_load_tbu(); break; default: - RET_INVAL(); - break; + RET_INVAL(ctx); + return; } - ctx->tb_offset = 0; gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -1965,15 +1959,16 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC) GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - ctx->exception = EXCP_MTMSR; + RET_MTMSR(ctx); #endif } @@ -1995,10 +1990,10 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) #endif { case -1: - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); break; case 0: - RET_PRIVREG(); + RET_PRIVREG(ctx); break; default: break; @@ -2147,16 +2142,13 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) gen_op_tlbia(); break; case O_TBL: - gen_op_store_tb(0); - ctx->tb_offset = 0; + gen_op_store_tbl(); break; case O_TBU: - gen_op_store_tb(1); - ctx->tb_offset = 0; + gen_op_store_tbu(); break; case DECR: gen_op_store_decr(); - ctx->decr_offset = 0; break; default: gen_op_store_spr(sprn); @@ -2186,10 +2178,11 @@ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else if (!ctx->supervisor) { - RET_PRIVOPC(); + RET_PRIVOPC(ctx); + return; } if (rA(ctx->opcode) == 0) { gen_op_load_gpr_T0(rB(ctx->opcode)); @@ -2274,10 +2267,11 @@ GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT) GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_sr(SR(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); @@ -2288,10 +2282,11 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_load_srin(); @@ -2303,14 +2298,18 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_sr(SR(ctx->opcode)); +#if 0 gen_op_tlbia(); + RET_MTMSR(ctx); +#endif #endif } @@ -2318,10 +2317,11 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(); + RET_PRIVREG(ctx); #else if (!ctx->supervisor) { - RET_PRIVREG(); + RET_PRIVREG(ctx); + return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); @@ -2336,10 +2336,13 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else if (!ctx->supervisor) { - RET_PRIVOPC(); + if (loglevel) + fprintf(logfile, "%s: ! supervisor\n", __func__); + RET_PRIVOPC(ctx); + return; } gen_op_tlbia(); #endif @@ -2349,10 +2352,11 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else if (!ctx->supervisor) { - RET_PRIVOPC(); + RET_PRIVOPC(ctx); + return; } gen_op_load_gpr_T0(rB(ctx->opcode)); gen_op_tlbie(); @@ -2363,10 +2367,11 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(); + RET_PRIVOPC(ctx); #else if (!ctx->supervisor) { - RET_PRIVOPC(); + RET_PRIVOPC(ctx); + return; } /* This has no effect: it should ensure that all previous * tlbie have completed @@ -2916,7 +2921,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } fprintf(f, " ] "); - fprintf(f, "TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); + fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env), + cpu_ppc_load_tbl(env)); for (i = 0; i < 16; i++) { if ((i & 3) == 0) fprintf(f, "FPR%02d:", i); @@ -2924,8 +2930,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) if ((i & 3) == 3) fprintf(f, "\n"); } - fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n", - env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions); + fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n", + env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env)); fprintf(f, "reservation 0x%08x\n", env->reserve); fflush(f); } @@ -2952,7 +2958,6 @@ CPUPPCState *cpu_ppc_init(void) // env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */ // env->spr[PVR] = 0x00070100; /* IBM 750FX */ #endif - env->decr = 0xFFFFFFFF; if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) return NULL; init_spr_rights(env->spr[PVR]); @@ -2976,14 +2981,13 @@ void cpu_ppc_close(CPUPPCState *env) } /*****************************************************************************/ -void raise_exception_err (int exception_index, int error_code); int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, int dialect); int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) { - DisasContext ctx; + DisasContext ctx, *ctxp = &ctx; opc_handler_t **table, *handler; uint32_t pc_start; uint16_t *gen_opc_end; @@ -2994,8 +2998,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; ctx.nip = pc_start; - ctx.tb_offset = 0; - ctx.decr_offset = 0; ctx.tb = tb; ctx.exception = EXCP_NONE; #if defined(CONFIG_USER_ONLY) @@ -3023,26 +3025,22 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_instr_start[lj] = 1; } } -#if defined DEBUG_DISAS - if (loglevel > 0) { +#if defined PPC_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "nip=%08x super=%d ir=%d\n", ctx.nip, 1 - msr_pr, msr_ir); } #endif ctx.opcode = ldl_code((void *)ctx.nip); -#if defined DEBUG_DISAS - if (loglevel > 0) { +#if defined PPC_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode)); } #endif ctx.nip += 4; - ctx.tb_offset++; - /* Check decrementer exception */ - if (++ctx.decr_offset == env->decr + 1) - ctx.exception = EXCP_DECR; table = ppc_opcodes; handler = table[opc1(ctx.opcode)]; if (is_indirect_opcode(handler)) { @@ -3098,26 +3096,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, (ctx.nip & 0xFC) != 0x04) && ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI && ctx.exception != EXCP_TRAP)) { -#if !defined(CONFIG_USER_ONLY) - gen_op_queue_exception(EXCP_TRACE); -#endif - if (ctx.exception == EXCP_NONE) { - ctx.exception = EXCP_TRACE; - } + RET_EXCP(ctxp, EXCP_TRACE, 0); } /* if we reach a page boundary, stop generation */ if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { - if (ctx.exception == EXCP_NONE) { - gen_op_b((long)ctx.tb, ctx.nip); - ctx.exception = EXCP_BRANCH; - } + RET_EXCP(ctxp, EXCP_BRANCH, 0); } } - /* In case of branch, this has already been done *BEFORE* the branch */ - if (ctx.exception != EXCP_BRANCH && ctx.exception != EXCP_RFI) { - gen_op_update_tb(ctx.tb_offset); - gen_op_update_decr(ctx.decr_offset); - gen_op_process_exceptions(ctx.nip); + if (ctx.exception == EXCP_NONE) { + gen_op_b((unsigned long)ctx.tb, ctx.nip); + } else if (ctx.exception != EXCP_BRANCH) { + gen_op_set_T0(0); } #if 1 /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump @@ -3144,15 +3133,16 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } env->access_type = ACCESS_INT; #ifdef DEBUG_DISAS - if (loglevel > 0) { + if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); cpu_ppc_dump_state(env, logfile, 0); + } + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); -#if defined(CONFIG_USER_ONLY) disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0); -#endif fprintf(logfile, "\n"); - + } + if (loglevel & CPU_LOG_TB_OP) { fprintf(logfile, "OP:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); -- cgit v1.2.3 From 92e873b996adb4cdc8ec9ab7e49d1c88d8749127 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 21 May 2004 14:52:29 +0000 Subject: support for non continuous RAM or ROM git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@842 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/exec.c b/exec.c index 695779ab2..c0b6a8f32 100644 --- a/exec.c +++ b/exec.c @@ -64,9 +64,7 @@ uint8_t *phys_ram_base; uint8_t *phys_ram_dirty; typedef struct PageDesc { - /* offset in host memory of the page + io_index in the low 12 bits */ - unsigned long phys_offset; - /* list of TBs intersecting this physical page */ + /* list of TBs intersecting this ram page */ TranslationBlock *first_tb; /* in order to optimize self modifying code, we count the number of lookups we do to a given page to use a bitmap */ @@ -77,6 +75,11 @@ typedef struct PageDesc { #endif } PageDesc; +typedef struct PhysPageDesc { + /* offset in host memory of the page + io_index in the low 12 bits */ + unsigned long phys_offset; +} PhysPageDesc; + typedef struct VirtPageDesc { /* physical address of code page. It is valid only if 'valid_tag' matches 'virt_valid_tag' */ @@ -102,7 +105,9 @@ unsigned long host_page_bits; unsigned long host_page_size; unsigned long host_page_mask; +/* XXX: for system emulation, it could just be an array */ static PageDesc *l1_map[L1_SIZE]; +static PhysPageDesc *l1_phys_map[L1_SIZE]; #if !defined(CONFIG_USER_ONLY) static VirtPageDesc *l1_virt_map[L1_SIZE]; @@ -166,6 +171,31 @@ static inline PageDesc *page_find(unsigned int index) return p + (index & (L2_SIZE - 1)); } +static inline PhysPageDesc *phys_page_find_alloc(unsigned int index) +{ + PhysPageDesc **lp, *p; + + lp = &l1_phys_map[index >> L2_BITS]; + p = *lp; + if (!p) { + /* allocate if not found */ + p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE); + memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE); + *lp = p; + } + return p + (index & (L2_SIZE - 1)); +} + +static inline PhysPageDesc *phys_page_find(unsigned int index) +{ + PhysPageDesc *p; + + p = l1_phys_map[index >> L2_BITS]; + if (!p) + return 0; + return p + (index & (L2_SIZE - 1)); +} + #if !defined(CONFIG_USER_ONLY) static void tlb_protect_code(CPUState *env, target_ulong addr); static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr); @@ -1428,7 +1458,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, target_phys_addr_t paddr, int prot, int is_user, int is_softmmu) { - PageDesc *p; + PhysPageDesc *p; unsigned long pd; TranslationBlock *first_tb; unsigned int index; @@ -1436,13 +1466,18 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, unsigned long addend; int ret; - p = page_find(paddr >> TARGET_PAGE_BITS); + p = phys_page_find(paddr >> TARGET_PAGE_BITS); + first_tb = NULL; if (!p) { pd = IO_MEM_UNASSIGNED; - first_tb = NULL; } else { + PageDesc *p1; pd = p->phys_offset; - first_tb = p->first_tb; + if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) { + /* NOTE: we also allocate the page at this stage */ + p1 = page_find_alloc(pd >> TARGET_PAGE_BITS); + first_tb = p1->first_tb; + } } #if defined(DEBUG_TLB) printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n", @@ -1752,11 +1787,11 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long phys_offset) { unsigned long addr, end_addr; - PageDesc *p; + PhysPageDesc *p; end_addr = start_addr + size; for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { - p = page_find_alloc(addr >> TARGET_PAGE_BITS); + p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS); p->phys_offset = phys_offset; if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) phys_offset += TARGET_PAGE_SIZE; @@ -1938,14 +1973,14 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, uint32_t val; target_phys_addr_t page; unsigned long pd; - PageDesc *p; + PhysPageDesc *p; while (len > 0) { page = addr & TARGET_PAGE_MASK; l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - p = page_find(page >> TARGET_PAGE_BITS); + p = phys_page_find(page >> TARGET_PAGE_BITS); if (!p) { pd = IO_MEM_UNASSIGNED; } else { -- cgit v1.2.3 From fb9f9444588d2f7f1af9692499b3953432151e64 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 May 2004 16:27:00 +0000 Subject: PCI BIOS fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@843 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 1 deletion(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 7d87cb03c..6c2717514 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 1ed70484c..dee62e012 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -4,7 +4,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.108 diff -u -w -r1.108 rombios.c --- rombios.c 9 Feb 2004 16:48:50 -0000 1.108 -+++ rombios.c 16 May 2004 15:16:57 -0000 ++++ rombios.c 22 May 2004 15:47:51 -0000 @@ -2254,6 +2254,7 @@ type = read_byte(get_SS(),buffer+1) & 0x1f; removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; @@ -58,3 +58,175 @@ diff -u -w -r1.108 rombios.c } package_count = mouse_flags_2 & 0x07; +@@ -8401,57 +8416,69 @@ + cmp al, #0x08 + jne pci_pro_f09 + call pci_pro_select_reg ++ push edx + mov dx, di + and dx, #0x03 + add dx, #0x0cfc + in al, dx ++ pop edx + mov cl, al + jmp pci_pro_ok + pci_pro_f09: ;; read configuration word + cmp al, #0x09 + jne pci_pro_f0a + call pci_pro_select_reg ++ push edx + mov dx, di + and dx, #0x02 + add dx, #0x0cfc + in ax, dx ++ pop edx + mov cx, ax + jmp pci_pro_ok + pci_pro_f0a: ;; read configuration dword + cmp al, #0x0a + jne pci_pro_f0b + call pci_pro_select_reg ++ push edx + mov dx, #0x0cfc + in eax, dx ++ pop edx + mov ecx, eax + jmp pci_pro_ok + pci_pro_f0b: ;; write configuration byte + cmp al, #0x0b + jne pci_pro_f0c + call pci_pro_select_reg ++ push edx + mov dx, di + and dx, #0x03 + add dx, #0x0cfc + mov al, cl + out dx, al ++ pop edx + jmp pci_pro_ok + pci_pro_f0c: ;; write configuration word + cmp al, #0x0c + jne pci_pro_f0d + call pci_pro_select_reg ++ push edx + mov dx, di + and dx, #0x02 + add dx, #0x0cfc + mov ax, cx + out dx, ax ++ pop edx + jmp pci_pro_ok + pci_pro_f0d: ;; write configuration dword + cmp al, #0x0d + jne pci_pro_unknown + call pci_pro_select_reg ++ push edx + mov dx, #0x0cfc + mov eax, ecx + out dx, eax ++ pop edx + jmp pci_pro_ok + pci_pro_unknown: + mov ah, #0x81 +@@ -8468,6 +8495,7 @@ + retf + + pci_pro_select_reg: ++ push edx + mov eax, #0x800000 + mov ax, bx + shl eax, #8 +@@ -8476,6 +8504,7 @@ + and al, #0xfc + mov dx, #0x0cf8 + out dx, eax ++ pop edx + ret + + use16 386 +@@ -8536,57 +8565,69 @@ + cmp al, #0x08 + jne pci_real_f09 + call pci_real_select_reg ++ push dx + mov dx, di + and dx, #0x03 + add dx, #0x0cfc + in al, dx ++ pop dx + mov cl, al + jmp pci_real_ok + pci_real_f09: ;; read configuration word + cmp al, #0x09 + jne pci_real_f0a + call pci_real_select_reg ++ push dx + mov dx, di + and dx, #0x02 + add dx, #0x0cfc + in ax, dx ++ pop dx + mov cx, ax + jmp pci_real_ok + pci_real_f0a: ;; read configuration dword + cmp al, #0x0a + jne pci_real_f0b + call pci_real_select_reg ++ push dx + mov dx, #0x0cfc + in eax, dx ++ pop dx + mov ecx, eax + jmp pci_real_ok + pci_real_f0b: ;; write configuration byte + cmp al, #0x0b + jne pci_real_f0c + call pci_real_select_reg ++ push dx + mov dx, di + and dx, #0x03 + add dx, #0x0cfc + mov al, cl + out dx, al ++ pop dx + jmp pci_real_ok + pci_real_f0c: ;; write configuration word + cmp al, #0x0c + jne pci_real_f0d + call pci_real_select_reg ++ push dx + mov dx, di + and dx, #0x02 + add dx, #0x0cfc + mov ax, cx + out dx, ax ++ pop dx + jmp pci_real_ok + pci_real_f0d: ;; write configuration dword + cmp al, #0x0d + jne pci_real_unknown + call pci_real_select_reg ++ push dx + mov dx, #0x0cfc + mov eax, ecx + out dx, eax ++ pop dx + jmp pci_real_ok + pci_real_unknown: + mov ah, #0x81 +@@ -8599,6 +8640,7 @@ + ret + + pci_real_select_reg: ++ push dx + mov eax, #0x800000 + mov ax, bx + shl eax, #8 +@@ -8607,6 +8649,7 @@ + and al, #0xfc + mov dx, #0x0cf8 + out dx, eax ++ pop dx + ret + + .align 16 -- cgit v1.2.3 From 7bf5be70f78b10cb9e679217db1c770e607bb2fb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 May 2004 16:28:18 +0000 Subject: pci memory mapping fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@844 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index ff5a44efb..2d8fcbcc5 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -214,7 +214,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { int can_write, i; - uint32_t end; + uint32_t end, addr; if (len == 4 && (address >= 0x10 && address < 0x10 + 4 * 6)) { PCIIORegion *r; @@ -233,9 +233,10 @@ void pci_default_write_config(PCIDevice *d, } default_config: /* not efficient, but simple */ + addr = address; for(i = 0; i < len; i++) { /* default read/write accesses */ - switch(address) { + switch(addr) { case 0x00: case 0x01: case 0x02: @@ -253,9 +254,9 @@ void pci_default_write_config(PCIDevice *d, break; } if (can_write) { - d->config[address] = val; + d->config[addr] = val; } - address++; + addr++; val >>= 8; } -- cgit v1.2.3 From 8d6c7eb896fddb4d4361fc97ec90dda41e825df8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 May 2004 16:52:29 +0000 Subject: receive status register support (aka GRUB netboot fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@845 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 6897bafd4..9a04c921d 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -118,6 +118,7 @@ typedef struct NE2000State { uint16_t tcnt; uint16_t rcnt; uint32_t rsar; + uint8_t rsr; uint8_t isr; uint8_t dcfg; uint8_t imr; @@ -212,7 +213,11 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) next -= (s->stop - s->start); /* prepare packet header */ p = s->mem + index; - p[0] = ENRSR_RXOK; /* receive status */ + s->rsr = ENRSR_RXOK; /* receive status */ + /* XXX: check this */ + if (buf[0] & 0x01) + s->rsr |= ENRSR_PHY; + p[0] = s->rsr; p[1] = next >> 8; p[2] = total_len; p[3] = total_len >> 8; @@ -232,7 +237,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) size -= len; } s->curpag = next >> 8; - + /* now we can signal we have receive something */ s->isr |= ENISR_RX; ne2000_update_irq(s); @@ -360,6 +365,9 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) case EN1_MULT ... EN1_MULT + 7: ret = s->mult[offset - EN1_MULT]; break; + case EN0_RSR: + ret = s->rsr; + break; default: ret = 0x00; break; -- cgit v1.2.3 From 25b42e9d53c0c2b8bce02483d0e80c9ae90e2f53 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 May 2004 18:30:22 +0000 Subject: added missing copyright file git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@846 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/COPYRIGHT | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 slirp/COPYRIGHT diff --git a/slirp/COPYRIGHT b/slirp/COPYRIGHT new file mode 100644 index 000000000..2e868624f --- /dev/null +++ b/slirp/COPYRIGHT @@ -0,0 +1,64 @@ +Slirp was written by Danny Gasparovski. +Copyright (c), 1995,1996 All Rights Reserved. + +Slirp is maintained by Kelly Price + +Slirp is free software; "free" as in you don't have to pay for it, and you +are free to do whatever you want with it. I do not accept any donations, +monetary or otherwise, for Slirp. Instead, I would ask you to pass this +potential donation to your favorite charity. In fact, I encourage +*everyone* who finds Slirp useful to make a small donation to their +favorite charity (for example, GreenPeace). This is not a requirement, but +a suggestion from someone who highly values the service they provide. + +The copyright terms and conditions: + +---BEGIN--- + + Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this software + must display the following acknowledgment: + This product includes software developed by Danny Gasparovski. + + THIS SOFTWARE IS PROVIDED ``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 + DANNY GASPAROVSKI 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. + +---END--- + +This basically means you can do anything you want with the software, except +1) call it your own, and 2) claim warranty on it. There is no warranty for +this software. None. Nada. If you lose a million dollars while using +Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. + +If these conditions cannot be met due to legal restrictions (E.g. where it +is against the law to give out Software without warranty), you must cease +using the software and delete all copies you have. + +Slirp uses code that is copyrighted by the following people/organizations: + +Juha Pirkola. +Gregory M. Christy. +The Regents of the University of California. +Carnegie Mellon University. +The Australian National University. +RSA Data Security, Inc. + +Please read the top of each source file for the details on the various +copyrights. -- cgit v1.2.3 From a00bad7ed468da05916a9344f8ee0eed647e2b32 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 May 2004 21:39:06 +0000 Subject: default ram size define (Pavel Janik) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@847 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index 84ac49d91..13aa9dfbe 100644 --- a/vl.c +++ b/vl.c @@ -93,6 +93,8 @@ extern void __sigaction(); #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024) #endif +#define DEFAULT_RAM_SIZE 32 + /* in ms */ #define GUI_REFRESH_INTERVAL 30 @@ -1914,7 +1916,7 @@ void help(void) "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-boot [a|b|c|d] boot on floppy (a, b), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" - "-m megs set virtual RAM size to megs MB\n" + "-m megs set virtual RAM size to megs MB [default=%d]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" "-enable-audio enable audio support\n" "\n" @@ -1951,7 +1953,8 @@ void help(void) #else "qemu-fast", #endif - DEFAULT_NETWORK_SCRIPT, + DEFAULT_RAM_SIZE, + DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); term_print_help(); @@ -2090,7 +2093,7 @@ int main(int argc, char **argv) fd_filename[i] = NULL; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; - ram_size = 32 * 1024 * 1024; + ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); #ifdef CONFIG_GDBSTUB -- cgit v1.2.3 From 5b60212f2addaf6ccc7c5884c0605a1ccd413c48 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 May 2004 21:41:05 +0000 Subject: typos (Pavel Janik) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@848 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monitor.c b/monitor.c index ab1c842bc..524a281c9 100644 --- a/monitor.c +++ b/monitor.c @@ -815,7 +815,7 @@ static int expr_prod(void) case '/': case '%': if (val2 == 0) - expr_error("divison by zero"); + expr_error("division by zero"); if (op == '/') val /= val2; else @@ -933,7 +933,7 @@ static int get_str(char *buf, int buf_size, const char **pp) } } if (*p != '\"') { - qemu_printf("untermintated string\n"); + qemu_printf("unterminated string\n"); goto fail; } p++; -- cgit v1.2.3 From 777428f2d23cfc62326933398c009b7955eed011 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 16:26:20 +0000 Subject: fixed 2.88 MB boot (aka FreeBSD 5.2.1 boot fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@849 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 54 +++++++++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 75a590bfb..d39127662 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -76,6 +76,30 @@ static inline int to_bcd(RTCState *s, int a) return ((a / 10) << 4) | (a % 10); } +static int cmos_get_fd_drive_type(int fd0) +{ + int val; + + switch (fd0) { + case 0: + /* 1.44 Mb 3"5 drive */ + val = 4; + break; + case 1: + /* 2.88 Mb 3"5 drive */ + val = 5; + break; + case 2: + /* 1.2 Mb 5"5 drive */ + val = 2; + break; + default: + val = 0; + break; + } + return val; +} + static void cmos_init(int ram_size, int boot_device) { RTCState *s = rtc_state; @@ -133,35 +157,7 @@ static void cmos_init(int ram_size, int boot_device) fd0 = fdctrl_get_drive_type(floppy_controller, 0); fd1 = fdctrl_get_drive_type(floppy_controller, 1); - val = 0; - switch (fd0) { - case 0: - /* 1.44 Mb 3"5 drive */ - val |= 0x40; - break; - case 1: - /* 2.88 Mb 3"5 drive */ - val |= 0x60; - break; - case 2: - /* 1.2 Mb 5"5 drive */ - val |= 0x20; - break; - } - switch (fd1) { - case 0: - /* 1.44 Mb 3"5 drive */ - val |= 0x04; - break; - case 1: - /* 2.88 Mb 3"5 drive */ - val |= 0x06; - break; - case 2: - /* 1.2 Mb 5"5 drive */ - val |= 0x02; - break; - } + val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1); rtc_set_memory(s, 0x10, val); val = 0; -- cgit v1.2.3 From e58a7c24acc72b57ae87101b936924d7d61dfe91 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 16:28:35 +0000 Subject: int13 cdrom 32 bit register update fix (aka FreeBSD CDROM boot) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@850 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 42 +++++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 6c2717514..a8c407a58 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index dee62e012..24a22b9bf 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -4,7 +4,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.108 diff -u -w -r1.108 rombios.c --- rombios.c 9 Feb 2004 16:48:50 -0000 1.108 -+++ rombios.c 22 May 2004 15:47:51 -0000 ++++ rombios.c 23 May 2004 15:48:52 -0000 @@ -2254,6 +2254,7 @@ type = read_byte(get_SS(),buffer+1) & 0x1f; removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; @@ -58,7 +58,35 @@ diff -u -w -r1.108 rombios.c } package_count = mouse_flags_2 & 0x07; -@@ -8401,57 +8416,69 @@ +@@ -4833,8 +4848,10 @@ + // --------------------------------------------------------------------------- + + void +-int13_cdrom(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS) +- Bit16u DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS; ++int13_cdrom(DI, DIH, SI, SIH, BP, BPH, SP, SPH, BX, BXH, DX, DXH, CX, CXH, AX, AXH, ++ DS, ES, FLAGS) ++ Bit16u DI, DIH, SI, SIH, BP, BPH, SP, SPH, BX, BXH, DX, DXH, CX, CXH, AX, AXH, ++ DS, ES, FLAGS; + { + Bit16u ebda_seg=read_word(0x0040,0x000E); + Bit8u device, status, locks; +@@ -7692,9 +7709,12 @@ + push ds + push ss + pop ds +- pusha ++ // ebx is modified: BSD 5.2.1 boot loader problem, so we save all ++ // the 32 bit registers. It should be done in all the bios or no 32 ++ // bit register should be used without saving it first. ++ pushad + call _int13_cdrom +- popa ++ popad + pop ds + pop es + popf +@@ -8401,57 +8421,69 @@ cmp al, #0x08 jne pci_pro_f09 call pci_pro_select_reg @@ -128,7 +156,7 @@ diff -u -w -r1.108 rombios.c jmp pci_pro_ok pci_pro_unknown: mov ah, #0x81 -@@ -8468,6 +8495,7 @@ +@@ -8468,6 +8500,7 @@ retf pci_pro_select_reg: @@ -136,7 +164,7 @@ diff -u -w -r1.108 rombios.c mov eax, #0x800000 mov ax, bx shl eax, #8 -@@ -8476,6 +8504,7 @@ +@@ -8476,6 +8509,7 @@ and al, #0xfc mov dx, #0x0cf8 out dx, eax @@ -144,7 +172,7 @@ diff -u -w -r1.108 rombios.c ret use16 386 -@@ -8536,57 +8565,69 @@ +@@ -8536,57 +8570,69 @@ cmp al, #0x08 jne pci_real_f09 call pci_real_select_reg @@ -214,7 +242,7 @@ diff -u -w -r1.108 rombios.c jmp pci_real_ok pci_real_unknown: mov ah, #0x81 -@@ -8599,6 +8640,7 @@ +@@ -8599,6 +8645,7 @@ ret pci_real_select_reg: @@ -222,7 +250,7 @@ diff -u -w -r1.108 rombios.c mov eax, #0x800000 mov ax, bx shl eax, #8 -@@ -8607,6 +8649,7 @@ +@@ -8607,6 +8654,7 @@ and al, #0xfc mov dx, #0x0cf8 out dx, eax -- cgit v1.2.3 From 9995c51ffd8c7801c0b99b801d859288f8d911fe Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 19:09:22 +0000 Subject: pixx3 ide controller git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@851 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vl.h b/vl.h index 8026dec65..6bb131cb4 100644 --- a/vl.h +++ b/vl.h @@ -413,6 +413,8 @@ uint32_t pci_default_read_config(PCIDevice *d, void pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len); +extern struct PIIX3State *piix3_state; + void i440fx_init(void); void piix3_init(void); void pci_bios_init(void); @@ -458,6 +460,7 @@ extern BlockDriverState *bs_table[MAX_DISKS]; void isa_ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1); void pci_ide_init(BlockDriverState **hd_table); +void pci_piix3_ide_init(BlockDriverState **hd_table); /* oss.c */ typedef enum { -- cgit v1.2.3 From 34e538ae5d87d263c024d1b803ccef4983807556 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 19:10:26 +0000 Subject: added PIIX3 like IDE controller - PCI irq generation - SETFEATURES IDE command support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@852 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 35a064811..45974aeb3 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -297,6 +297,7 @@ typedef struct IDEState { int64_t nb_sectors; int mult_sectors; int irq; + PCIDevice *pci_dev; int drive_serial; /* ide regs */ uint8_t feature; @@ -463,7 +464,10 @@ static inline void ide_abort_command(IDEState *s) static inline void ide_set_irq(IDEState *s) { if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { - pic_set_irq(s->irq, 1); + if (s->irq == 16) + pci_set_irq(s->pci_dev, 0, 1); + else + pic_set_irq(s->irq, 1); } } @@ -1169,7 +1173,22 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->status = READY_STAT; ide_set_irq(s); break; - + case WIN_SETFEATURES: + if (!s->bs) + goto abort_cmd; + /* XXX: valid for CDROM ? */ + switch(s->feature) { + case 0x02: /* write cache enable */ + case 0x82: /* write cache disable */ + case 0xaa: /* read look-ahead enable */ + case 0x55: /* read look-ahead disable */ + s->status = READY_STAT; + ide_set_irq(s); + break; + default: + goto abort_cmd; + } + break; /* ATAPI commands */ case WIN_PIDENTIFY: if (s->is_cdrom) { @@ -1262,7 +1281,10 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = 0; else ret = s->status; - pic_set_irq(s->irq, 0); + if (s->irq == 16) + pci_set_irq(s->pci_dev, 0, 0); + else + pic_set_irq(s->irq, 0); break; } #ifdef DEBUG_IDE @@ -1481,20 +1503,8 @@ static void ide_init2(IDEState *ide_state, int irq, } } -/***********************************************************/ -/* ISA IDE definitions */ - -void isa_ide_init(int iobase, int iobase2, int irq, - BlockDriverState *hd0, BlockDriverState *hd1) +static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2) { - IDEState *ide_state; - - ide_state = qemu_mallocz(sizeof(IDEState) * 2); - if (!ide_state) - return; - - ide_init2(ide_state, irq, hd0, hd1); - register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state); register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state); if (iobase2) { @@ -1509,6 +1519,22 @@ void isa_ide_init(int iobase, int iobase2, int irq, register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state); } +/***********************************************************/ +/* ISA IDE definitions */ + +void isa_ide_init(int iobase, int iobase2, int irq, + BlockDriverState *hd0, BlockDriverState *hd1) +{ + IDEState *ide_state; + + ide_state = qemu_mallocz(sizeof(IDEState) * 2); + if (!ide_state) + return; + + ide_init2(ide_state, irq, hd0, hd1); + ide_init_ioport(ide_state, iobase, iobase2); +} + /***********************************************************/ /* PCI IDE definitions */ @@ -1546,7 +1572,8 @@ void pci_ide_init(BlockDriverState **hd_table) { PCIIDEState *d; uint8_t *pci_conf; - + int i; + d = (PCIIDEState *)pci_register_device("IDE", sizeof(PCIIDEState), 0, -1, NULL, NULL); @@ -1573,6 +1600,38 @@ void pci_ide_init(BlockDriverState **hd_table) pci_register_io_region((PCIDevice *)d, 3, 0x4, PCI_ADDRESS_SPACE_IO, ide_map); + pci_conf[0x3d] = 0x01; // interrupt on pin 1 + + for(i = 0; i < 4; i++) + d->ide_if[i].pci_dev = (PCIDevice *)d; + ide_init2(&d->ide_if[0], 16, hd_table[0], hd_table[1]); + ide_init2(&d->ide_if[2], 16, hd_table[2], hd_table[3]); +} + +/* hd_table must contain 4 block drivers */ +/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ +void pci_piix3_ide_init(BlockDriverState **hd_table) +{ + PCIIDEState *d; + uint8_t *pci_conf; + + /* register a function 1 of PIIX3 */ + d = (PCIIDEState *)pci_register_device("PIIX3 IDE", sizeof(PCIIDEState), + 0, ((PCIDevice *)piix3_state)->devfn + 1, + NULL, NULL); + pci_conf = d->dev.config; + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x10; + pci_conf[0x03] = 0x70; + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE + pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage + pci_conf[0x0e] = 0x00; // header_type + + /* XXX: must add BMDMA support to be fully compliant */ + ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]); ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]); + ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); + ide_init_ioport(&d->ide_if[2], 0x170, 0x376); } -- cgit v1.2.3 From e1c485be842d0cd633bb795d1efd61bbb4a5789b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 19:10:46 +0000 Subject: use PIIX3 like IDE controller git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@853 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index d39127662..815d47fe5 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -413,7 +413,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < nb_nics; i++) { pci_ne2000_init(&nd_table[i]); } - pci_ide_init(bs_table); + pci_piix3_ide_init(bs_table); } else { nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) -- cgit v1.2.3 From 63ce9e0a42503fbdb40eb8fb4b0933a058213925 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 19:12:03 +0000 Subject: pci empty device read fix - piix3 ide init git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@854 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 2d8fcbcc5..651c01d5d 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -316,7 +316,18 @@ static uint32_t pci_data_read(void *opaque, uint32_t addr, pci_dev = bus[(s->config_reg >> 8) & 0xff]; if (!pci_dev) { fail: - val = 0; + switch(len) { + case 1: + val = 0xff; + break; + case 2: + val = 0xffff; + break; + default: + case 4: + val = 0xffffffff; + break; + } goto the_end; } config_addr = (s->config_reg & 0xfc) | (addr & 3); @@ -682,16 +693,24 @@ static void pci_bios_init_device(PCIDevice *d) int class; PCIIORegion *r; uint32_t *paddr; - int i, pin, pic_irq; + int i, pin, pic_irq, vendor_id, device_id; - class = d->config[0x0a] | (d->config[0x0b] << 8); + class = pci_config_readw(d, PCI_CLASS_DEVICE); switch(class) { case 0x0101: - /* IDE: we map it as in ISA mode */ - pci_set_io_region_addr(d, 0, 0x1f0); - pci_set_io_region_addr(d, 1, 0x3f4); - pci_set_io_region_addr(d, 2, 0x170); - pci_set_io_region_addr(d, 3, 0x374); + vendor_id = pci_config_readw(d, PCI_VENDOR_ID); + device_id = pci_config_readw(d, PCI_DEVICE_ID); + if (vendor_id == 0x8086 && device_id == 0x7010) { + /* PIIX3 IDE */ + pci_config_writew(d, PCI_COMMAND, PCI_COMMAND_IO); + pci_config_writew(d, 0x40, 0x8000); // enable IDE0 + } else { + /* IDE: we map it as in ISA mode */ + pci_set_io_region_addr(d, 0, 0x1f0); + pci_set_io_region_addr(d, 1, 0x3f4); + pci_set_io_region_addr(d, 2, 0x170); + pci_set_io_region_addr(d, 3, 0x374); + } break; case 0x0300: /* VGA: map frame buffer to default Bochs VBE address */ -- cgit v1.2.3 From f18ac341fe80e450c11f36683924af19a859accc Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 21:00:55 +0000 Subject: cleanup git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@855 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 021cc7413..c6e45416b 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -184,10 +184,6 @@ typedef struct opcode_t { opc_handler_t handler; } opcode_t; -/* XXX: move that elsewhere */ -extern FILE *logfile; -extern int loglevel; - /*** Instruction decoding ***/ #define EXTRACT_HELPER(name, shift, nb) \ static inline uint32_t name (uint32_t opcode) \ @@ -2890,7 +2886,6 @@ static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr) /*****************************************************************************/ /* Misc PPC helpers */ -FILE *stdout; void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) { -- cgit v1.2.3 From b415a4078d8ddae8338a8ba65206777331022a54 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 21:04:06 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@856 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 5d780be47..0e3f617b7 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -608,6 +608,10 @@ In order to check that the user mode network is working, you can ping the address 10.0.2.2 and verify that you got an address in the range 10.0.2.x from the QEMU virtual DHCP server. +Note that @code{ping} is not supported reliably to the internet as it +would require root priviledges. It means you can only ping the local +router (10.0.2.2). + @node direct_linux_boot @section Direct Linux Boot -- cgit v1.2.3 From 0ced6589701ec3716f7df86dbaf29db154a6a0d7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 21:06:12 +0000 Subject: PowerPC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@857 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 ++++-- vl.h | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 13aa9dfbe..85c6623a0 100644 --- a/vl.c +++ b/vl.c @@ -110,11 +110,12 @@ IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD]; int vga_ram_size; +int bios_size; static DisplayState display_state; int nographic; int64_t ticks_per_sec; int boot_device = 'c'; -static int ram_size; +int ram_size; static char network_script[1024]; int pit_min_timer_count = 0; int nb_nics; @@ -2095,6 +2096,7 @@ int main(int argc, char **argv) hd_filename[i] = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; + bios_size = BIOS_SIZE; pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); #ifdef CONFIG_GDBSTUB use_gdbstub = 0; @@ -2393,7 +2395,7 @@ int main(int argc, char **argv) } /* init the memory */ - phys_ram_size = ram_size + vga_ram_size; + phys_ram_size = ram_size + vga_ram_size + bios_size; #ifdef CONFIG_SOFTMMU #ifdef _BSD diff --git a/vl.h b/vl.h index 6bb131cb4..ebe715f27 100644 --- a/vl.h +++ b/vl.h @@ -168,6 +168,15 @@ void vm_start(void); void vm_stop(int reason); extern int audio_enabled; +extern int ram_size; +extern int bios_size; + +/* XXX: make it dynamic */ +#if defined (TARGET_PPC) +#define BIOS_SIZE (512 * 1024) +#else +#define BIOS_SIZE 0 +#endif /* async I/O support */ -- cgit v1.2.3 From 5fd386f698e71955b03742eb6e85f5de2b213e6e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 21:11:22 +0000 Subject: PowerPC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@858 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index c0b6a8f32..9a6d81a95 100644 --- a/exec.c +++ b/exec.c @@ -1789,8 +1789,9 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long addr, end_addr; PhysPageDesc *p; + size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; end_addr = start_addr + size; - for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { + for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS); p->phys_offset = phys_offset; if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) -- cgit v1.2.3 From b69fedff841fc01fd96843ab38912031e1defb33 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 21:17:08 +0000 Subject: PowerPC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@859 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/m48t59.h b/hw/m48t59.h index 4b801bca3..e68057b84 100644 --- a/hw/m48t59.h +++ b/hw/m48t59.h @@ -6,6 +6,7 @@ typedef struct m48t59_t m48t59_t; void m48t59_write (m48t59_t *NVRAM, uint32_t val); uint32_t m48t59_read (m48t59_t *NVRAM); void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr); +void m48t59_toggle_lock (m48t59_t *NVRAM, int lock); m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size); #endif /* !defined (__M48T59_H__) */ -- cgit v1.2.3 From 85c4adf65f20437c428a1ebf2d3293dd56a53596 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 21:25:39 +0000 Subject: PowerPC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@860 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index bd430aff5..122ec9946 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -74,6 +74,10 @@ enum { #define PPC_COMMON (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ PPC_RES | PPC_CACHE | PPC_MISC | PPC_SEGMENT) +/* PPC 604 */ +#define PPC_604 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ + PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT \ + PPC_MEM_OPT) /* PPC 740/745/750/755 (aka G3) has external access instructions */ #define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT) @@ -202,6 +206,8 @@ void _store_xer (CPUPPCState *env, uint32_t value); uint32_t _load_msr (CPUPPCState *env); void _store_msr (CPUPPCState *env, uint32_t value); +int cpu_ppc_register (CPUPPCState *env, uint32_t pvr); + /* Time-base and decrementer management */ #ifndef NO_CPU_IO_DEFS uint32_t cpu_ppc_load_tbl (CPUPPCState *env); @@ -235,7 +241,10 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); #define xer_ca env->xer[1] #define xer_bc env->xer[0] +#define MQ SPR_ENCODE(0) #define XER SPR_ENCODE(1) +#define RTCUR SPR_ENCODE(4) +#define RTCLR SPR_ENCODE(5) #define LR SPR_ENCODE(8) #define CTR SPR_ENCODE(9) /* VEA mode SPR */ @@ -244,6 +253,8 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); /* supervisor mode SPR */ #define DSISR SPR_ENCODE(18) #define DAR SPR_ENCODE(19) +#define RTCUW SPR_ENCODE(20) +#define RTCLW SPR_ENCODE(21) #define DECR SPR_ENCODE(22) #define SDR1 SPR_ENCODE(25) #define SRR0 SPR_ENCODE(26) @@ -293,14 +304,50 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); #define DBAT6L SPR_ENCODE(573) #define DBAT7U SPR_ENCODE(574) #define DBAT7L SPR_ENCODE(575) +#define UMMCR0 SPR_ENCODE(936) +#define UPMC1 SPR_ENCODE(937) +#define UPMC2 SPR_ENCODE(938) +#define USIA SPR_ENCODE(939) +#define UMMCR1 SPR_ENCODE(940) +#define UPMC3 SPR_ENCODE(941) +#define UPMC4 SPR_ENCODE(942) +#define MMCR0 SPR_ENCODE(952) +#define PMC1 SPR_ENCODE(953) +#define PMC2 SPR_ENCODE(954) +#define SIA SPR_ENCODE(955) +#define MMCR1 SPR_ENCODE(956) +#define PMC3 SPR_ENCODE(957) +#define PMC4 SPR_ENCODE(958) +#define SDA SPR_ENCODE(959) +#define DMISS SPR_ENCODE(976) +#define DCMP SPR_ENCODE(977) +#define DHASH1 SPR_ENCODE(978) +#define DHASH2 SPR_ENCODE(979) +#define IMISS SPR_ENCODE(980) +#define ICMP SPR_ENCODE(981) +#define RPA SPR_ENCODE(982) +#define TCR SPR_ENCODE(984) +#define IBR SPR_ENCODE(986) +#define ESASRR SPR_ENCODE(987) +#define SEBR SPR_ENCODE(990) +#define SER SPR_ENCODE(991) +#define HID0 SPR_ENCODE(1008) +#define HID1 SPR_ENCODE(1009) +#define IABR SPR_ENCODE(1010) +#define HID2 SPR_ENCODE(1011) #define DABR SPR_ENCODE(1013) +#define L2PM SPR_ENCODE(1016) +#define L2CR SPR_ENCODE(1017) +#define ICTC SPR_ENCODE(1019) +#define THRM1 SPR_ENCODE(1020) +#define THRM2 SPR_ENCODE(1021) +#define THRM3 SPR_ENCODE(1022) +#define SP SPR_ENCODE(1021) +#define LP SPR_ENCODE(1022) #define DABR_MASK 0xFFFFFFF8 #define FPECR SPR_ENCODE(1022) #define PIR SPR_ENCODE(1023) -#define TARGET_PAGE_BITS 12 -#include "cpu-all.h" - /* Memory access type : * may be needed for precise access rights control and precise exceptions. */ -- cgit v1.2.3 From 4b3686faeefab6279f6d395fcf56ea5405d040da Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 22:18:12 +0000 Subject: PowerPC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@861 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/exec.h | 6 ++ target-ppc/helper.c | 27 +++--- target-ppc/op.c | 34 +++---- target-ppc/op_helper.c | 105 ++++++++++++++++++-- target-ppc/op_template.h | 5 +- target-ppc/translate.c | 247 +++++++++++++++++++++++++++-------------------- 6 files changed, 274 insertions(+), 150 deletions(-) diff --git a/target-ppc/exec.h b/target-ppc/exec.h index edb73ef05..637790768 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -135,6 +135,8 @@ void do_sraw(void); void do_fctiw (void); void do_fctiwz (void); +void do_fnmadd (void); +void do_fnmsub (void); void do_fnmadds (void); void do_fnmsubs (void); void do_fsqrt (void); @@ -147,7 +149,11 @@ void do_fcmpo (void); void do_fabs (void); void do_fnabs (void); +void do_check_reservation (void); void do_icbi (void); +void do_store_sr (uint32_t srnum); +void do_store_ibat (int ul, int nr); +void do_store_dbat (int ul, int nr); void do_tlbia (void); void do_tlbie (void); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index e8b776b07..ef3e22d66 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -28,9 +28,6 @@ //#define DEBUG_EXCEPTIONS extern FILE *stdout, *stderr; -void abort (void); - -/*****************************************************************************/ /*****************************************************************************/ /* PPC MMU emulation */ @@ -365,7 +362,8 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, fprintf(logfile, "%s\n", __func__); } - if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) { + if ((access_type == ACCESS_CODE && msr_ir == 0) || + (access_type != ACCESS_CODE && msr_dr == 0)) { /* No address translation */ *physical = address & ~0xFFF; *prot = PAGE_READ | PAGE_WRITE; @@ -441,12 +439,15 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_addrr = env->tlb_read[is_user][index].address; tlb_addrw = env->tlb_write[is_user][index].address; -#if 0 - printf("%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " +#if 1 + if (loglevel) { + fprintf(logfile, + "%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " "(0x%08lx 0x%08lx)\n", __func__, env, &env->tlb_read[is_user][index], index, addr, tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); + } #endif } ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); @@ -631,11 +632,14 @@ uint32_t _load_msr (CPUState *env) void _store_msr (CPUState *env, uint32_t value) { +#if 0 // TRY if (((value >> MSR_IR) & 0x01) != msr_ir || - ((value >> MSR_DR) & 0x01) != msr_dr) { + ((value >> MSR_DR) & 0x01) != msr_dr) + { /* Flush all tlb when changing translation mode or privilege level */ tlb_flush(env, 1); } +#endif msr_pow = (value >> MSR_POW) & 0x03; msr_ile = (value >> MSR_ILE) & 0x01; msr_ee = (value >> MSR_EE) & 0x01; @@ -699,13 +703,8 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_MACHINE_CHECK: if (msr_me == 0) { - printf("Machine check exception while not allowed !\n"); - if (loglevel) { - fprintf(logfile, - "Machine check exception while not allowed !\n"); + cpu_abort(env, "Machine check exception while not allowed\n"); } - abort(); - } msr_me = 0; break; case EXCP_DSI: @@ -801,7 +800,7 @@ void do_interrupt (CPUState *env) env->fpscr[7] |= 0x4; break; case EXCP_INVAL: - printf("Invalid instruction at 0x%08x\n", env->nip); + // printf("Invalid instruction at 0x%08x\n", env->nip); msr |= 0x00080000; break; case EXCP_PRIV: diff --git a/target-ppc/op.c b/target-ppc/op.c index 38eae7f74..f439a81df 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -242,10 +242,7 @@ PPC_OP(load_srin) PPC_OP(store_srin) { -#if defined (DEBUG_OP) - dump_store_sr(T1 >> 28); -#endif - regs->sr[T1 >> 28] = T0; + do_store_sr(T1 >> 28); RETURN(); } @@ -402,10 +399,7 @@ PPC_OP(load_ibat) PPC_OP(store_ibat) { -#if defined (DEBUG_OP) - dump_store_ibat(PARAM(1), PARAM(2)); -#endif - regs->IBAT[PARAM(1)][PARAM(2)] = T0; + do_store_ibat(PARAM(1), PARAM(2)); } PPC_OP(load_dbat) @@ -415,10 +409,7 @@ PPC_OP(load_dbat) PPC_OP(store_dbat) { -#if defined (DEBUG_OP) - dump_store_dbat(PARAM(1), PARAM(2)); -#endif - regs->DBAT[PARAM(1)][PARAM(2)] = T0; + do_store_dbat(PARAM(1), PARAM(2)); } /* FPSCR */ @@ -1344,9 +1335,7 @@ PPC_OP(fmsubs) /* fnmadd - fnmadd. - fnmadds - fnmadds. */ PPC_OP(fnmadd) { - FT0 *= FT1; - FT0 += FT2; - FT0 = -FT0; + do_fnmadd(); RETURN(); } @@ -1360,9 +1349,7 @@ PPC_OP(fnmadds) /* fnmsub - fnmsub. */ PPC_OP(fnmsub) { - FT0 *= FT1; - FT0 -= FT2; - FT0 = -FT0; + do_fnmsub(); RETURN(); } @@ -1444,11 +1431,22 @@ PPC_OP(fneg) #include "op_mem.h" #endif +/* Special op to check and maybe clear reservation */ +PPC_OP(check_reservation) +{ + do_check_reservation(); + RETURN(); +} + /* Return from interrupt */ PPC_OP(rfi) { regs->nip = regs->spr[SRR0] & ~0x00000003; +#if 1 // TRY + T0 = regs->spr[SRR1] & ~0xFFF00000; +#else T0 = regs->spr[SRR1] & ~0xFFFF0000; +#endif do_store_msr(); #if defined (DEBUG_OP) dump_rfi(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 3ddda1e33..d761a8d2b 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -127,11 +127,14 @@ void do_load_msr (void) void do_store_msr (void) { +#if 1 // TRY if (((T0 >> MSR_IR) & 0x01) != msr_ir || - ((T0 >> MSR_DR) & 0x01) != msr_dr) { - /* Flush all tlb when changing translation mode or privilege level */ + ((T0 >> MSR_DR) & 0x01) != msr_dr || + ((T0 >> MSR_PR) & 0x01) != msr_pr) + { do_tlbia(); } +#endif msr_pow = (T0 >> MSR_POW) & 0x03; msr_ile = (T0 >> MSR_ILE) & 0x01; msr_ee = (T0 >> MSR_EE) & 0x01; @@ -157,14 +160,18 @@ void do_sraw (void) xer_ca = 0; if (T1 & 0x20) { ret = (-1) * (T0 >> 31); - if (ret < 0) + if (ret < 0 && (T0 & ~0x80000000) != 0) xer_ca = 1; +#if 1 // TRY + } else if (T1 == 0) { + ret = T0; +#endif } else { ret = (int32_t)T0 >> (T1 & 0x1f); if (ret < 0 && ((int32_t)T0 & ((1 << T1) - 1)) != 0) xer_ca = 1; } - (int32_t)T0 = ret; + T0 = ret; } /* Floating point operations helpers */ @@ -267,14 +274,24 @@ void do_fctiwz (void) fesetround(cround); } +void do_fnmadd (void) +{ + FT0 = -((FT0 * FT1) + FT2); +} + +void do_fnmsub (void) +{ + FT0 = -((FT0 * FT1) - FT2); +} + void do_fnmadds (void) { - FTS0 = -((FTS0 * FTS1) + FTS2); + FT0 = -((FTS0 * FTS1) + FTS2); } void do_fnmsubs (void) { - FTS0 = -((FTS0 * FTS1) - FTS2); + FT0 = -((FTS0 * FTS1) - FTS2); } void do_fsqrt (void) @@ -307,7 +324,6 @@ void do_fsel (void) void do_fcmpu (void) { - env->fpscr[4] &= ~0x1; if (isnan(FT0) || isnan(FT1)) { T0 = 0x01; env->fpscr[4] |= 0x1; @@ -319,7 +335,7 @@ void do_fcmpu (void) } else { T0 = 0x02; } - env->fpscr[3] |= T0; + env->fpscr[3] = T0; } void do_fcmpo (void) @@ -343,7 +359,7 @@ void do_fcmpo (void) } else { T0 = 0x02; } - env->fpscr[3] |= T0; + env->fpscr[3] = T0; } void do_fabs (void) @@ -359,6 +375,12 @@ void do_fnabs (void) /* Instruction cache invalidation helper */ #define ICACHE_LINE_SIZE 32 +void do_check_reservation (void) +{ + if ((env->reserve & ~(ICACHE_LINE_SIZE - 1)) == T0) + env->reserve = -1; +} + void do_icbi (void) { /* Invalidate one cache line */ @@ -377,6 +399,69 @@ void do_tlbie (void) tlb_flush_page(env, T0); } +void do_store_sr (uint32_t srnum) +{ +#if defined (DEBUG_OP) + dump_store_sr(srnum); +#endif +#if 0 // TRY + { + uint32_t base, page; + + base = srnum << 28; + for (page = base; page != base + 0x100000000; page += 0x1000) + tlb_flush_page(env, page); + } +#else + tlb_flush(env, 1); +#endif + env->sr[srnum] = T0; +} + +/* For BATs, we may not invalidate any TLBs if the change is only on + * protection bits for user mode. + */ +void do_store_ibat (int ul, int nr) +{ +#if defined (DEBUG_OP) + dump_store_ibat(ul, nr); +#endif +#if 0 // TRY + { + uint32_t base, length, page; + + base = env->IBAT[0][nr]; + length = (((base >> 2) & 0x000007FF) + 1) << 17; + base &= 0xFFFC0000; + for (page = base; page != base + length; page += 0x1000) + tlb_flush_page(env, page); + } +#else + tlb_flush(env, 1); +#endif + env->IBAT[ul][nr] = T0; +} + +void do_store_dbat (int ul, int nr) +{ +#if defined (DEBUG_OP) + dump_store_dbat(ul, nr); +#endif +#if 0 // TRY + { + uint32_t base, length, page; + base = env->DBAT[0][nr]; + length = (((base >> 2) & 0x000007FF) + 1) << 17; + base &= 0xFFFC0000; + for (page = base; page != base + length; page += 0x1000) + tlb_flush_page(env, page); + } +#else + tlb_flush(env, 1); +#endif + env->DBAT[ul][nr] = T0; +} + /*****************************************************************************/ /* Special helpers for debug */ extern FILE *stdout; @@ -389,7 +474,7 @@ void dump_state (void) void dump_rfi (void) { #if 0 - printf("Return from interrupt %d => 0x%08x\n", pos, env->nip); + printf("Return from interrupt => 0x%08x\n", env->nip); // cpu_ppc_dump_state(env, stdout, 0); #endif } diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 5ba4dfcbe..338b7aa23 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -175,10 +175,7 @@ void OPPROTO glue(op_load_sr, REG)(void) void OPPROTO glue(op_store_sr, REG)(void) { -#if defined (DEBUG_OP) - dump_store_sr(REG); -#endif - env->sr[REG] = T0; + do_store_sr(REG); RETURN(); } #endif diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c6e45416b..1489c462f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -28,8 +28,6 @@ #include "disas.h" //#define DO_SINGLE_STEP -//#define DO_STEP_FLUSH -//#define DEBUG_DISAS //#define PPC_DEBUG_DISAS enum { @@ -639,7 +637,7 @@ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) } gen_op_load_gpr_T0(rS(ctx->opcode)); if (uimm != 0) - gen_op_xori(UIMM(ctx->opcode)); + gen_op_xori(uimm); gen_op_store_T0_gpr(rA(ctx->opcode)); } @@ -654,7 +652,7 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) } gen_op_load_gpr_T0(rS(ctx->opcode)); if (uimm != 0) - gen_op_xori(UIMM(ctx->opcode) << 16); + gen_op_xori(uimm << 16); gen_op_store_T0_gpr(rA(ctx->opcode)); } @@ -682,25 +680,29 @@ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) mb = MB(ctx->opcode); me = ME(ctx->opcode); gen_op_load_gpr_T0(rS(ctx->opcode)); +#if 1 // TRY + if (sh == 0) { + gen_op_andi_(MASK(mb, me)); + goto store; + } +#endif if (mb == 0) { if (me == 31) { gen_op_rotlwi(sh); goto store; +#if 0 } else if (me == (31 - sh)) { gen_op_slwi(sh); goto store; - } else if (sh == 0) { - gen_op_andi_(MASK(0, me)); - goto store; +#endif } } else if (me == 31) { +#if 0 if (sh == (32 - mb)) { gen_op_srwi(mb); goto store; - } else if (sh == 0) { - gen_op_andi_(MASK(mb, 31)); - goto store; } +#endif } gen_op_rlwinm(sh, MASK(mb, me)); store: @@ -1268,12 +1270,16 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) /* stswi */ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) { + int nb = NB(ctx->opcode); + if (rA(ctx->opcode) == 0) { gen_op_set_T0(0); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); } - gen_op_set_T1(NB(ctx->opcode)); + if (nb == 0) + nb = 32; + gen_op_set_T1(nb); op_ldsts(stsw, rS(ctx->opcode)); } @@ -1931,7 +1937,6 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) /* We need to update the time base before reading it */ switch (sprn) { case V_TBL: - /* TBL is still in T0 */ gen_op_load_tbl(); break; case V_TBU: @@ -2007,135 +2012,135 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) break; case IBAT0U: gen_op_store_ibat(0, 0); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT1U: gen_op_store_ibat(0, 1); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT2U: gen_op_store_ibat(0, 2); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT3U: gen_op_store_ibat(0, 3); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT4U: gen_op_store_ibat(0, 4); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT5U: gen_op_store_ibat(0, 5); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT6U: gen_op_store_ibat(0, 6); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT7U: gen_op_store_ibat(0, 7); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT0L: gen_op_store_ibat(1, 0); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT1L: gen_op_store_ibat(1, 1); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT2L: gen_op_store_ibat(1, 2); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT3L: gen_op_store_ibat(1, 3); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT4L: gen_op_store_ibat(1, 4); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT5L: gen_op_store_ibat(1, 5); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT6L: gen_op_store_ibat(1, 6); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case IBAT7L: gen_op_store_ibat(1, 7); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT0U: gen_op_store_dbat(0, 0); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT1U: gen_op_store_dbat(0, 1); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT2U: gen_op_store_dbat(0, 2); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT3U: gen_op_store_dbat(0, 3); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT4U: gen_op_store_dbat(0, 4); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT5U: gen_op_store_dbat(0, 5); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT6U: gen_op_store_dbat(0, 6); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT7U: gen_op_store_dbat(0, 7); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT0L: gen_op_store_dbat(1, 0); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT1L: gen_op_store_dbat(1, 1); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT2L: gen_op_store_dbat(1, 2); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT3L: gen_op_store_dbat(1, 3); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT4L: gen_op_store_dbat(1, 4); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT5L: gen_op_store_dbat(1, 5); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT6L: gen_op_store_dbat(1, 6); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case DBAT7L: gen_op_store_dbat(1, 7); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case SDR1: gen_op_store_sdr1(); - gen_op_tlbia(); + RET_MTMSR(ctx); break; case O_TBL: gen_op_store_tbl(); @@ -2146,6 +2151,11 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) case DECR: gen_op_store_decr(); break; +#if 0 + case HID0: + gen_op_store_hid0(); + break; +#endif default: gen_op_store_spr(sprn); break; @@ -2236,6 +2246,7 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) gen_op_add(); } op_dcbz(); + gen_op_check_reservation(); } /* icbi */ @@ -2302,10 +2313,6 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_sr(SR(ctx->opcode)); -#if 0 - gen_op_tlbia(); - RET_MTMSR(ctx); -#endif #endif } @@ -2322,7 +2329,6 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_store_srin(); - gen_op_tlbia(); #endif } @@ -2341,6 +2347,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) return; } gen_op_tlbia(); + RET_MTMSR(ctx); #endif } @@ -2356,6 +2363,7 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) } gen_op_load_gpr_T0(rB(ctx->opcode)); gen_op_tlbie(); + RET_MTMSR(ctx); #endif } @@ -2372,6 +2380,7 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) /* This has no effect: it should ensure that all previous * tlbie have completed */ + RET_MTMSR(ctx); #endif } @@ -2692,59 +2701,78 @@ static void init_spr_rights (uint32_t pvr) spr_set_rights(DBAT3U, SPR_SR | SPR_SW); /* DBAT3L (SPR 543) */ spr_set_rights(DBAT3L, SPR_SR | SPR_SW); - /* DABR (SPR 1013) */ - spr_set_rights(DABR, SPR_SR | SPR_SW); /* FPECR (SPR 1022) */ spr_set_rights(FPECR, SPR_SR | SPR_SW); - /* PIR (SPR 1023) */ + /* Special registers for PPC 604 */ + if ((pvr & 0xFFFF0000) == 0x00040000) { + /* IABR */ + spr_set_rights(IABR , SPR_SR | SPR_SW); + /* DABR (SPR 1013) */ + spr_set_rights(DABR, SPR_SR | SPR_SW); + /* HID0 */ + spr_set_rights(HID0, SPR_SR | SPR_SW); + /* PIR */ spr_set_rights(PIR, SPR_SR | SPR_SW); + /* PMC1 */ + spr_set_rights(PMC1, SPR_SR | SPR_SW); + /* PMC2 */ + spr_set_rights(PMC2, SPR_SR | SPR_SW); + /* MMCR0 */ + spr_set_rights(MMCR0, SPR_SR | SPR_SW); + /* SIA */ + spr_set_rights(SIA, SPR_SR | SPR_SW); + /* SDA */ + spr_set_rights(SDA, SPR_SR | SPR_SW); + } /* Special registers for MPC740/745/750/755 (aka G3) & IBM 750 */ if ((pvr & 0xFFFF0000) == 0x00080000 || (pvr & 0xFFFF0000) == 0x70000000) { /* HID0 */ - spr_set_rights(SPR_ENCODE(1008), SPR_SR | SPR_SW); + spr_set_rights(HID0, SPR_SR | SPR_SW); /* HID1 */ - spr_set_rights(SPR_ENCODE(1009), SPR_SR | SPR_SW); + spr_set_rights(HID1, SPR_SR | SPR_SW); /* IABR */ - spr_set_rights(SPR_ENCODE(1010), SPR_SR | SPR_SW); + spr_set_rights(IABR, SPR_SR | SPR_SW); /* ICTC */ - spr_set_rights(SPR_ENCODE(1019), SPR_SR | SPR_SW); + spr_set_rights(ICTC, SPR_SR | SPR_SW); /* L2CR */ - spr_set_rights(SPR_ENCODE(1017), SPR_SR | SPR_SW); + spr_set_rights(L2CR, SPR_SR | SPR_SW); /* MMCR0 */ - spr_set_rights(SPR_ENCODE(952), SPR_SR | SPR_SW); + spr_set_rights(MMCR0, SPR_SR | SPR_SW); /* MMCR1 */ - spr_set_rights(SPR_ENCODE(956), SPR_SR | SPR_SW); + spr_set_rights(MMCR1, SPR_SR | SPR_SW); /* PMC1 */ - spr_set_rights(SPR_ENCODE(953), SPR_SR | SPR_SW); + spr_set_rights(PMC1, SPR_SR | SPR_SW); /* PMC2 */ - spr_set_rights(SPR_ENCODE(954), SPR_SR | SPR_SW); + spr_set_rights(PMC2, SPR_SR | SPR_SW); /* PMC3 */ - spr_set_rights(SPR_ENCODE(957), SPR_SR | SPR_SW); + spr_set_rights(PMC3, SPR_SR | SPR_SW); /* PMC4 */ - spr_set_rights(SPR_ENCODE(958), SPR_SR | SPR_SW); + spr_set_rights(PMC4, SPR_SR | SPR_SW); /* SIA */ - spr_set_rights(SPR_ENCODE(955), SPR_SR | SPR_SW); + spr_set_rights(SIA, SPR_SR | SPR_SW); + /* SDA */ + spr_set_rights(SDA, SPR_SR | SPR_SW); /* THRM1 */ - spr_set_rights(SPR_ENCODE(1020), SPR_SR | SPR_SW); + spr_set_rights(THRM1, SPR_SR | SPR_SW); /* THRM2 */ - spr_set_rights(SPR_ENCODE(1021), SPR_SR | SPR_SW); + spr_set_rights(THRM2, SPR_SR | SPR_SW); /* THRM3 */ - spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW); + spr_set_rights(THRM3, SPR_SR | SPR_SW); /* UMMCR0 */ - spr_set_rights(SPR_ENCODE(936), SPR_UR | SPR_UW); + spr_set_rights(UMMCR0, SPR_UR | SPR_UW); /* UMMCR1 */ - spr_set_rights(SPR_ENCODE(940), SPR_UR | SPR_UW); + spr_set_rights(UMMCR1, SPR_UR | SPR_UW); /* UPMC1 */ - spr_set_rights(SPR_ENCODE(937), SPR_UR | SPR_UW); + spr_set_rights(UPMC1, SPR_UR | SPR_UW); /* UPMC2 */ - spr_set_rights(SPR_ENCODE(938), SPR_UR | SPR_UW); + spr_set_rights(UPMC2, SPR_UR | SPR_UW); /* UPMC3 */ - spr_set_rights(SPR_ENCODE(941), SPR_UR | SPR_UW); + spr_set_rights(UPMC3, SPR_UR | SPR_UW); /* UPMC4 */ - spr_set_rights(SPR_ENCODE(942), SPR_UR | SPR_UW); + spr_set_rights(UPMC4, SPR_UR | SPR_UW); /* USIA */ - spr_set_rights(SPR_ENCODE(939), SPR_UR | SPR_UW); + spr_set_rights(USIA, SPR_UR | SPR_UW); } /* MPC755 has special registers */ if (pvr == 0x00083100) { @@ -2789,23 +2817,23 @@ static void init_spr_rights (uint32_t pvr) /* DBAT7L */ spr_set_rights(DBAT7L, SPR_SR | SPR_SW); /* DMISS */ - spr_set_rights(SPR_ENCODE(976), SPR_SR | SPR_SW); + spr_set_rights(DMISS, SPR_SR | SPR_SW); /* DCMP */ - spr_set_rights(SPR_ENCODE(977), SPR_SR | SPR_SW); + spr_set_rights(DCMP, SPR_SR | SPR_SW); /* DHASH1 */ - spr_set_rights(SPR_ENCODE(978), SPR_SR | SPR_SW); + spr_set_rights(DHASH1, SPR_SR | SPR_SW); /* DHASH2 */ - spr_set_rights(SPR_ENCODE(979), SPR_SR | SPR_SW); + spr_set_rights(DHASH2, SPR_SR | SPR_SW); /* IMISS */ - spr_set_rights(SPR_ENCODE(980), SPR_SR | SPR_SW); + spr_set_rights(IMISS, SPR_SR | SPR_SW); /* ICMP */ - spr_set_rights(SPR_ENCODE(981), SPR_SR | SPR_SW); + spr_set_rights(ICMP, SPR_SR | SPR_SW); /* RPA */ - spr_set_rights(SPR_ENCODE(982), SPR_SR | SPR_SW); + spr_set_rights(RPA, SPR_SR | SPR_SW); /* HID2 */ - spr_set_rights(SPR_ENCODE(1011), SPR_SR | SPR_SW); + spr_set_rights(HID2, SPR_SR | SPR_SW); /* L2PM */ - spr_set_rights(SPR_ENCODE(1016), SPR_SR | SPR_SW); + spr_set_rights(L2PM, SPR_SR | SPR_SW); } } @@ -2941,10 +2969,9 @@ CPUPPCState *cpu_ppc_init(void) cpu_exec_init(); - env = malloc(sizeof(CPUPPCState)); + env = qemu_mallocz(sizeof(CPUPPCState)); if (!env) return NULL; - memset(env, 0, sizeof(CPUPPCState)); #if !defined(CONFIG_USER_ONLY) && defined (USE_OPEN_FIRMWARE) setup_machine(env, 0); #else @@ -2953,22 +2980,34 @@ CPUPPCState *cpu_ppc_init(void) // env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */ // env->spr[PVR] = 0x00070100; /* IBM 750FX */ #endif - if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) - return NULL; - init_spr_rights(env->spr[PVR]); tlb_flush(env, 1); #if defined (DO_SINGLE_STEP) /* Single step trace mode */ msr_se = 1; #endif + msr_fp = 1; /* Allow floating point exceptions */ + msr_me = 1; /* Allow machine check exceptions */ #if defined(CONFIG_USER_ONLY) msr_pr = 1; + cpu_ppc_register(env, 0x00080000); +#else + env->nip = 0xFFFFFFFC; #endif env->access_type = ACCESS_INT; return env; } +int cpu_ppc_register (CPUPPCState *env, uint32_t pvr) +{ + env->spr[PVR] = pvr; + if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) + return -1; + init_spr_rights(env->spr[PVR]); + + return 0; +} + void cpu_ppc_close(CPUPPCState *env) { /* Should also remove all opcode tables... */ @@ -3047,26 +3086,26 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } } /* Is opcode *REALLY* valid ? */ - if ((ctx.opcode & handler->inval) != 0) { - if (loglevel > 0) { if (handler->handler == &gen_invalid) { + if (loglevel > 0) { fprintf(logfile, "invalid/unsupported opcode: " - "%02x -%02x - %02x (%08x) 0x%08x\n", + "%02x - %02x - %02x (%08x) 0x%08x %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); + } else { + printf("invalid/unsupported opcode: " + "%02x - %02x - %02x (%08x) 0x%08x %d\n", + opc1(ctx.opcode), opc2(ctx.opcode), + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); + } } else { + if ((ctx.opcode & handler->inval) != 0) { + if (loglevel > 0) { fprintf(logfile, "invalid bits: %08x for opcode: " "%02x -%02x - %02x (0x%08x) (0x%08x)\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); - } - } else { - if (handler->handler == &gen_invalid) { - printf("invalid/unsupported opcode: " - "%02x -%02x - %02x (%08x) 0x%08x\n", - opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } else { printf("invalid bits: %08x for opcode: " "%02x -%02x - %02x (0x%08x) (0x%08x)\n", @@ -3074,11 +3113,11 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } + RET_INVAL(ctxp); + break; } - (*gen_invalid)(&ctx); - } else { - (*(handler->handler))(&ctx); } + (*(handler->handler))(&ctx); /* Check trace mode exceptions */ if ((msr_be && ctx.exception == EXCP_BRANCH) || /* Check in single step trace mode @@ -3126,7 +3165,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { tb->size = ctx.nip - pc_start; } - env->access_type = ACCESS_INT; #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); @@ -3143,6 +3181,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, fprintf(logfile, "\n"); } #endif + env->access_type = ACCESS_INT; return 0; } -- cgit v1.2.3 From a2a444d6e097d0890a47e83ca6cf7dab35d043e2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 May 2004 22:34:16 +0000 Subject: PowerPC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@862 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 05783992b..4b50a1788 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -937,18 +937,28 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, PPC_init_hw(/*env,*/ ram_size, KERNEL_LOAD_ADDR, ret, KERNEL_STACK_ADDR, boot_device, initrd_filename); } else { + int bios_ram_offset; + +#define BIOS_START 0x00800000 + /* allocate ROM */ - // snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - snprintf(buf, sizeof(buf), "%s", BIOS_FILENAME); - printf("load BIOS at %p\n", phys_ram_base + 0x000f0000); - ret = load_image(buf, phys_ram_base + 0x000f0000); - if (ret != 0x10000) { + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + bios_ram_offset = ram_size + vga_ram_size; + printf("load BIOS at 0x%08x\n", BIOS_START); + ret = load_image(buf, phys_ram_base + bios_ram_offset); + if (ret != BIOS_SIZE) { fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", buf, ret); exit(1); } + global_env->nip = BIOS_START + BIOS_SIZE - 4; + cpu_register_physical_memory(BIOS_START, BIOS_SIZE, + IO_MEM_ROM | bios_ram_offset); } + /* Register CPU as a 74x/75x */ + cpu_ppc_register(cpu_single_env, 0x00080000); + /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); /* init basic PC hardware */ -- cgit v1.2.3 From 77d4bc349abd61ba2e12327e40f95bfc4069f2a0 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 May 2004 22:13:53 +0000 Subject: PowerPC prep/chrp/pmac support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@863 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 20 ++++- vl.h | 22 +++++ 3 files changed, 341 insertions(+), 1 deletion(-) diff --git a/hw/pci.c b/hw/pci.c index 651c01d5d..93d33d926 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -470,6 +470,259 @@ void piix3_init(void) piix3_reset(d); } +/* PREP pci init */ + +static inline void set_config(PCIBridge *s, target_phys_addr_t addr) +{ + int devfn, i; + + for(i = 0; i < 11; i++) { + if ((addr & (1 << (11 + i))) != 0) + break; + } + devfn = ((addr >> 8) & 7) | (i << 3); + s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8); +} + +static void PPC_PCIIO_writeb (target_phys_addr_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; + set_config(s, addr); + pci_data_write(s, addr, val, 1); +} + +static void PPC_PCIIO_writew (target_phys_addr_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; + set_config(s, addr); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + pci_data_write(s, addr, val, 2); +} + +static void PPC_PCIIO_writel (target_phys_addr_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; + set_config(s, addr); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_data_write(s, addr, val, 4); +} + +static uint32_t PPC_PCIIO_readb (target_phys_addr_t addr) +{ + PCIBridge *s = &pci_bridge; + uint32_t val; + set_config(s, addr); + val = pci_data_read(s, addr, 1); + return val; +} + +static uint32_t PPC_PCIIO_readw (target_phys_addr_t addr) +{ + PCIBridge *s = &pci_bridge; + uint32_t val; + set_config(s, addr); + val = pci_data_read(s, addr, 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t PPC_PCIIO_readl (target_phys_addr_t addr) +{ + PCIBridge *s = &pci_bridge; + uint32_t val; + set_config(s, addr); + val = pci_data_read(s, addr, 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { + &PPC_PCIIO_writeb, + &PPC_PCIIO_writew, + &PPC_PCIIO_writel, +}; + +static CPUReadMemoryFunc *PPC_PCIIO_read[] = { + &PPC_PCIIO_readb, + &PPC_PCIIO_readw, + &PPC_PCIIO_readl, +}; + +void pci_prep_init(void) +{ + PCIDevice *d; + int PPC_io_memory; + + PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, PPC_PCIIO_write); + cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); + + d = pci_register_device("PREP PCI Bridge", sizeof(PCIDevice), 0, 0, + NULL, NULL); + + /* XXX: put correct IDs */ + d->config[0x00] = 0x11; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x26; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x02; // revision + d->config[0x0a] = 0x04; // class_sub = pci2pci + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x01; // header_type +} + + +/* pmac pci init */ + +static void pci_pmac_config_writel (target_phys_addr_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + s->config_reg = val; +} + +static uint32_t pci_pmac_config_readl (target_phys_addr_t addr) +{ + PCIBridge *s = &pci_bridge; + uint32_t val; + + val = s->config_reg; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *pci_pmac_config_write[] = { + &pci_pmac_config_writel, + &pci_pmac_config_writel, + &pci_pmac_config_writel, +}; + +static CPUReadMemoryFunc *pci_pmac_config_read[] = { + &pci_pmac_config_readl, + &pci_pmac_config_readl, + &pci_pmac_config_readl, +}; + +static void pci_pmac_writeb (target_phys_addr_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; + pci_data_write(s, addr, val, 1); +} + +static void pci_pmac_writew (target_phys_addr_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + pci_data_write(s, addr, val, 2); +} + +static void pci_pmac_writel (target_phys_addr_t addr, uint32_t val) +{ + PCIBridge *s = &pci_bridge; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_data_write(s, addr, val, 4); +} + +static uint32_t pci_pmac_readb (target_phys_addr_t addr) +{ + PCIBridge *s = &pci_bridge; + uint32_t val; + val = pci_data_read(s, addr, 1); + return val; +} + +static uint32_t pci_pmac_readw (target_phys_addr_t addr) +{ + PCIBridge *s = &pci_bridge; + uint32_t val; + val = pci_data_read(s, addr, 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t pci_pmac_readl (target_phys_addr_t addr) +{ + PCIBridge *s = &pci_bridge; + uint32_t val; + + val = pci_data_read(s, addr, 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *pci_pmac_write[] = { + &pci_pmac_writeb, + &pci_pmac_writew, + &pci_pmac_writel, +}; + +static CPUReadMemoryFunc *pci_pmac_read[] = { + &pci_pmac_readb, + &pci_pmac_readw, + &pci_pmac_readl, +}; + +void pci_pmac_init(void) +{ + PCIDevice *d; + int pci_mem_config, pci_mem_data; + + pci_mem_config = cpu_register_io_memory(0, pci_pmac_config_read, + pci_pmac_config_write); + pci_mem_data = cpu_register_io_memory(0, pci_pmac_read, pci_pmac_write); + + cpu_register_physical_memory(0xfec00000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xfee00000, 0x1000, pci_mem_data); + + d = pci_register_device("MPC106", sizeof(PCIDevice), 0, 0, + NULL, NULL); + + /* same values as PearPC - check this */ + d->config[0x00] = 0x11; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x26; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x02; // revision + d->config[0x0a] = 0x04; // class_sub = pci2pci + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x01; // header_type + + d->config[0x18] = 0x0; // primary_bus + d->config[0x19] = 0x1; // secondary_bus + d->config[0x1a] = 0x1; // subordinate_bus + d->config[0x1c] = 0x10; // io_base + d->config[0x1d] = 0x20; // io_limit + + d->config[0x20] = 0x80; // memory_base + d->config[0x21] = 0x80; + d->config[0x22] = 0x90; // memory_limit + d->config[0x23] = 0x80; + + d->config[0x24] = 0x00; // prefetchable_memory_base + d->config[0x25] = 0x84; + d->config[0x26] = 0x00; // prefetchable_memory_limit + d->config[0x27] = 0x85; +} + /***********************************************************/ /* generic PCI irq support */ @@ -484,6 +737,11 @@ static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) } /* 0 <= irq_num <= 3. level must be 0 or 1 */ +#ifdef TARGET_PPC +void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) +{ +} +#else void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) { int irq_index, shift, pic_irq, pic_level; @@ -519,6 +777,7 @@ void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) pic_set_irq(pic_irq, pic_level); } } +#endif /***********************************************************/ /* monitor info on PCI */ @@ -780,3 +1039,44 @@ void pci_bios_init(void) } } } + +/* + * This function initializes the PCI devices as a normal PCI BIOS + * would do. It is provided just in case the BIOS has no support for + * PCI. + */ +void pci_ppc_bios_init(void) +{ + PCIBridge *s = &pci_bridge; + PCIDevice **bus; + int bus_num, devfn, i, irq; + uint8_t elcr[2]; + + pci_bios_io_addr = 0xc000; + pci_bios_mem_addr = 0xc0000000; + +#if 0 + /* activate IRQ mappings */ + elcr[0] = 0x00; + elcr[1] = 0x00; + for(i = 0; i < 4; i++) { + irq = pci_irqs[i]; + /* set to trigger level */ + elcr[irq >> 3] |= (1 << (irq & 7)); + /* activate irq remapping in PIIX */ + pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); + } + isa_outb(elcr[0], 0x4d0); + isa_outb(elcr[1], 0x4d1); +#endif + + for(bus_num = 0; bus_num < 256; bus_num++) { + bus = s->pci_bus[bus_num]; + if (bus) { + for(devfn = 0; devfn < 256; devfn++) { + if (bus[devfn]) + pci_bios_init_device(bus[devfn]); + } + } + } +} diff --git a/vl.c b/vl.c index 85c6623a0..6faf19f0e 100644 --- a/vl.c +++ b/vl.c @@ -93,8 +93,11 @@ extern void __sigaction(); #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024) #endif +#ifdef TARGET_PPC +#define DEFAULT_RAM_SIZE 144 +#else #define DEFAULT_RAM_SIZE 32 - +#endif /* in ms */ #define GUI_REFRESH_INTERVAL 30 @@ -125,6 +128,7 @@ QEMUTimer *gui_timer; int vm_running; int audio_enabled = 0; int pci_enabled = 0; +int prep_enabled = 0; /***********************************************************/ /* x86 ISA bus support */ @@ -876,12 +880,17 @@ int serial_open_device(void) /* use console for serial port */ return 0; } else { +#if 0 + /* Not satisfying */ if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { fprintf(stderr, "warning: could not create pseudo terminal for serial port\n"); return -1; } fprintf(stderr, "Serial port redirected to %s\n", slave_name); return master_fd; +#else + return -1; +#endif } } @@ -2005,6 +2014,7 @@ enum { QEMU_OPTION_L, QEMU_OPTION_no_code_copy, QEMU_OPTION_pci, + QEMU_OPTION_prep, }; typedef struct QEMUOption { @@ -2049,7 +2059,12 @@ const QEMUOption qemu_options[] = { { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, { "L", HAS_ARG, QEMU_OPTION_L }, { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, + + /* temporary options */ { "pci", 0, QEMU_OPTION_pci }, +#ifdef TARGET_PPC + { "prep", 0, QEMU_OPTION_prep }, +#endif { NULL }, }; @@ -2323,6 +2338,9 @@ int main(int argc, char **argv) case QEMU_OPTION_pci: pci_enabled = 1; break; + case QEMU_OPTION_prep: + prep_enabled = 1; + break; } } } diff --git a/vl.h b/vl.h index ebe715f27..b163baf5c 100644 --- a/vl.h +++ b/vl.h @@ -429,6 +429,11 @@ void piix3_init(void); void pci_bios_init(void); void pci_info(void); +/* temporary: will be moved in platform specific file */ +void pci_prep_init(void); +void pci_pmac_init(void); +void pci_ppc_bios_init(void); + /* vga.c */ #define VGA_RAM_SIZE (4096 * 1024) @@ -580,6 +585,23 @@ void ppc_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); +void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); +void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); +ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); +struct sysctrl_t; +int prep_NVRAM_init (struct sysctrl_t *sysctrl, uint32_t RAM_size, + uint32_t BIOS_size, int boot_device, + uint32_t kernel_image); + +extern CPUWriteMemoryFunc *PPC_io_write[]; +extern CPUReadMemoryFunc *PPC_io_read[]; +extern int prep_enabled; /* monitor.c */ void monitor_init(void); -- cgit v1.2.3 From 2444ca413b1431d7249b6430172e4009ae368ad5 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 May 2004 22:16:35 +0000 Subject: trace fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@864 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/i8259.c b/hw/i8259.c index 62e11f0ef..622f0bb75 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -146,7 +146,7 @@ static void pic_update_irq(void) } } - printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); + printf("pic: cpu_interrupt\n"); #endif cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); } @@ -172,7 +172,7 @@ void pic_set_irq(int irq, int level) #endif #ifdef DEBUG_IRQ_LATENCY if (level) { - irq_time[irq] = cpu_get_ticks(); + irq_time[irq] = qemu_get_clock(vm_clock); } #endif pic_set_irq1(&pics[irq >> 3], irq & 7, level); @@ -223,7 +223,7 @@ int cpu_get_pic_interrupt(CPUState *env) #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", irq, - (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); + (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec); #endif #if defined(DEBUG_PIC) printf("pic_interrupt: irq=%d\n", irq); -- cgit v1.2.3 From 642012017c13f7562fc2e0d1ce92272814e3010c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 May 2004 22:55:16 +0000 Subject: PowerPC prep/chrp/pmac support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@865 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/ppc.c | 248 +++++++++++++- hw/ppc_chrp.c | 107 ++++++ hw/ppc_prep.c | 1030 ++++++++++++++++--------------------------------------- vl.h | 27 +- 5 files changed, 658 insertions(+), 758 deletions(-) create mode 100644 hw/ppc_chrp.c diff --git a/Makefile.target b/Makefile.target index 0abe89494..51c17e522 100644 --- a/Makefile.target +++ b/Makefile.target @@ -244,8 +244,8 @@ ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= ppc.o # PREP hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o -VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o ppc_prep.o -#VL_OBJS+= hw.o of.o setup.o +VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o +VL_OBJS+= ppc_prep.o ppc_chrp.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/hw/ppc.c b/hw/ppc.c index 3858952a5..7793cbd44 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -23,11 +23,6 @@ */ #include "vl.h" -void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename); - /*****************************************************************************/ /* PPC time base and decrementer emulation */ //#define DEBUG_TB @@ -202,14 +197,249 @@ void cpu_ppc_reset (CPUState *env) } #endif +static void PPC_io_writeb (target_phys_addr_t addr, uint32_t value) +{ + cpu_outb(NULL, addr & 0xffff, value); +} + +static uint32_t PPC_io_readb (target_phys_addr_t addr) +{ + uint32_t ret = cpu_inb(NULL, addr & 0xffff); + return ret; +} + +static void PPC_io_writew (target_phys_addr_t addr, uint32_t value) +{ +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif + cpu_outw(NULL, addr & 0xffff, value); +} + +static uint32_t PPC_io_readw (target_phys_addr_t addr) +{ + uint32_t ret = cpu_inw(NULL, addr & 0xffff); +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap16(ret); +#endif + return ret; +} + +static void PPC_io_writel (target_phys_addr_t addr, uint32_t value) +{ +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif + cpu_outl(NULL, addr & 0xffff, value); +} + +static uint32_t PPC_io_readl (target_phys_addr_t addr) +{ + uint32_t ret = cpu_inl(NULL, addr & 0xffff); + +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap32(ret); +#endif + return ret; +} + +CPUWriteMemoryFunc *PPC_io_write[] = { + &PPC_io_writeb, + &PPC_io_writew, + &PPC_io_writel, +}; + +CPUReadMemoryFunc *PPC_io_read[] = { + &PPC_io_readb, + &PPC_io_readw, + &PPC_io_readl, +}; + +/*****************************************************************************/ +/* Debug port */ +void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val) +{ + addr &= 0xF; + switch (addr) { + case 0: + printf("%c", val); + break; + case 1: + printf("\n"); + fflush(stdout); + break; + case 2: + printf("Set loglevel to %04x\n", val); + cpu_set_log(val); + break; + } +} + +/*****************************************************************************/ +/* NVRAM helpers */ +void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) +{ + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value); +} + +uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) +{ + m48t59_set_addr(nvram, addr); + return m48t59_read(nvram); +} + +void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) +{ + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value >> 8); + m48t59_set_addr(nvram, addr + 1); + m48t59_write(nvram, value & 0xFF); +} + +uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) +{ + uint16_t tmp; + + m48t59_set_addr(nvram, addr); + tmp = m48t59_read(nvram) << 8; + m48t59_set_addr(nvram, addr + 1); + tmp |= m48t59_read(nvram); + + return tmp; +} + +void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) +{ + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value >> 24); + m48t59_set_addr(nvram, addr + 1); + m48t59_write(nvram, (value >> 16) & 0xFF); + m48t59_set_addr(nvram, addr + 2); + m48t59_write(nvram, (value >> 8) & 0xFF); + m48t59_set_addr(nvram, addr + 3); + m48t59_write(nvram, value & 0xFF); +} + +uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) +{ + uint32_t tmp; + + m48t59_set_addr(nvram, addr); + tmp = m48t59_read(nvram) << 24; + m48t59_set_addr(nvram, addr + 1); + tmp |= m48t59_read(nvram) << 16; + m48t59_set_addr(nvram, addr + 2); + tmp |= m48t59_read(nvram) << 8; + m48t59_set_addr(nvram, addr + 3); + tmp |= m48t59_read(nvram); + + return tmp; +} + +void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, + const unsigned char *str, uint32_t max) +{ + int i; + + for (i = 0; i < max && str[i] != '\0'; i++) { + m48t59_set_addr(nvram, addr + i); + m48t59_write(nvram, str[i]); + } + m48t59_set_addr(nvram, addr + max - 1); + m48t59_write(nvram, '\0'); +} + +int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) +{ + int i; + + memset(dst, 0, max); + for (i = 0; i < max; i++) { + dst[i] = NVRAM_get_byte(nvram, addr + i); + if (dst[i] == '\0') + break; + } + + return i; +} + +static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) +{ + uint16_t tmp; + uint16_t pd, pd1, pd2; + + tmp = prev >> 8; + pd = prev ^ value; + pd1 = pd & 0x000F; + pd2 = ((pd >> 4) & 0x000F) ^ pd1; + tmp ^= (pd1 << 3) | (pd1 << 8); + tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); + + return tmp; +} + +uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) +{ + uint32_t i; + uint16_t crc = 0xFFFF; + int odd; + + odd = count & 1; + count &= ~1; + for (i = 0; i != count; i++) { + crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); + } + if (odd) { + crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); + } + + return crc; +} + +int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, + const unsigned char *arch, + uint32_t RAM_size, int boot_device, + uint32_t kernel_image, uint32_t kernel_size, + uint32_t cmdline, uint32_t cmdline_size, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image) +{ + uint16_t crc; + + /* Set parameters for Open Hack'Ware BIOS */ + NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); + NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ + NVRAM_set_word(nvram, 0x14, NVRAM_size); + NVRAM_set_string(nvram, 0x20, arch, 16); + NVRAM_set_lword(nvram, 0x30, RAM_size); + NVRAM_set_byte(nvram, 0x34, boot_device); + NVRAM_set_lword(nvram, 0x38, kernel_image); + NVRAM_set_lword(nvram, 0x3C, kernel_size); + NVRAM_set_lword(nvram, 0x40, cmdline); + NVRAM_set_lword(nvram, 0x44, cmdline_size); + NVRAM_set_lword(nvram, 0x48, initrd_image); + NVRAM_set_lword(nvram, 0x4C, initrd_size); + NVRAM_set_lword(nvram, 0x50, NVRAM_image); + crc = NVRAM_compute_crc(nvram, 0x00, 0x5C); + NVRAM_set_word(nvram, 0x5C, crc); + + return 0; + } + /*****************************************************************************/ void ppc_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) { - /* For now, only PREP is supported */ - return ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, - snapshot, kernel_filename, kernel_cmdline, - initrd_filename); + if (prep_enabled) { + ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, + initrd_filename); + } else { + ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, + initrd_filename); + } } diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c new file mode 100644 index 000000000..380fb6e53 --- /dev/null +++ b/hw/ppc_chrp.c @@ -0,0 +1,107 @@ +/* + * QEMU PPC CHRP/PMAC hardware System Emulator + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#define BIOS_FILENAME "ppc_rom.bin" +#define NVRAM_SIZE 0x2000 + +/* PowerPC PREP hardware initialisation */ +void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + char buf[1024]; + m48t59_t *nvram; + int PPC_io_memory; + int ret, linux_boot, i, fd; + unsigned long bios_offset; + + linux_boot = (kernel_filename != NULL); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + /* allocate and load BIOS */ + bios_offset = ram_size + vga_ram_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret != BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf); + exit(1); + } + cpu_register_physical_memory((uint32_t)(-BIOS_SIZE), + BIOS_SIZE, bios_offset | IO_MEM_ROM); + cpu_single_env->nip = 0xfffffffc; + + /* Register CPU as a 74x/75x */ + cpu_ppc_register(cpu_single_env, 0x00080000); + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); + + isa_mem_base = 0xc0000000; + pci_pmac_init(); + + /* Register 64 KB of ISA IO space */ + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); + cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); + // cpu_register_physical_memory(0xfe000000, 0xfe010000, PPC_io_memory); + + /* init basic PC hardware */ + vga_initialize(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size, 1); + // openpic = openpic_init(0x00000000, 0xF0000000, 1); + // pic_init(openpic); + pic_init(); + // pit = pit_init(0x40, 0); + + /* XXX: use Mac Serial port */ + fd = serial_open_device(); + serial_init(0x3f8, 4, fd); + + for(i = 0; i < nb_nics; i++) { + pci_ne2000_init(&nd_table[i]); + } + + pci_ide_init(bs_table); + + kbd_init(); + + nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); + + PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, + 0, 0, + 0, + 0, + 0, 0, + /* XXX: need an option to load a NVRAM image */ + 0 + ); + + /* Special port to get debug messages from Open-Firmware */ + register_ioport_write(0xFF00, 0x04, 1, &PREP_debug_write, NULL); + register_ioport_write(0xFF00, 0x04, 2, &PREP_debug_write, NULL); + + pci_ppc_bios_init(); +} diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 4b50a1788..4a866ef5f 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -22,14 +22,13 @@ * THE SOFTWARE. */ #include "vl.h" -#include "m48t59.h" - -/* XXX: move all TB related stuff in ppc_prep.c and suppress ppc.c ? */ -ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO +#define KERNEL_LOAD_ADDR 0x01000000; +#define INITRD_LOAD_ADDR 0x01800000; + extern int loglevel; extern FILE *logfile; @@ -58,42 +57,7 @@ do { \ #endif #define BIOS_FILENAME "ppc_rom.bin" - -#define KERNEL_LOAD_ADDR 0x00000000 -#define KERNEL_STACK_ADDR 0x00400000 -#define INITRD_LOAD_ADDR 0x00800000 - -int load_kernel(const char *filename, uint8_t *addr, - uint8_t *real_addr) -{ - int fd, size; - int setup_sects; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return -1; - - /* load 16 bit code */ - if (read(fd, real_addr, 512) != 512) - goto fail; - setup_sects = real_addr[0x1F1]; - if (!setup_sects) - setup_sects = 4; - if (read(fd, real_addr + 512, setup_sects * 512) != - setup_sects * 512) - goto fail; - - /* load 32 bit code */ - size = read(fd, addr, 16 * 1024 * 1024); - if (size < 0) - goto fail; - close(fd); - return size; - fail: - close(fd); - return -1; -} - +/* Constants for devices init */ static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 13, 13 }; @@ -103,218 +67,300 @@ static const int ide_irq[2] = { 13, 13 }; static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; -/* IO ports emulation */ +//static PITState *pit; + +/* ISA IO ports bridge */ #define PPC_IO_BASE 0x80000000 -static void PPC_io_writeb (target_phys_addr_t addr, uint32_t value) +/* Speaker port 0x61 */ +int speaker_data_on; +int dummy_refresh_clock; + +static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - /* Don't polute serial port output */ #if 0 - if ((addr < 0x800003F0 || addr > 0x80000400) && - (addr < 0x80000074 || addr > 0x80000077) && - (addr < 0x80000020 || addr > 0x80000021) && - (addr < 0x800000a0 || addr > 0x800000a1) && - (addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) + speaker_data_on = (val >> 1) & 1; + pit_set_gate(pit, 2, val & 1); #endif - { - PPC_IO_DPRINTF("0x%08x => 0x%02x\n", addr - PPC_IO_BASE, value); - } - cpu_outb(NULL, addr - PPC_IO_BASE, value); } -static uint32_t PPC_io_readb (target_phys_addr_t addr) +static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) { - uint32_t ret = cpu_inb(NULL, addr - PPC_IO_BASE); - #if 0 - if ((addr < 0x800003F0 || addr > 0x80000400) && - (addr < 0x80000074 || addr > 0x80000077) && - (addr < 0x80000020 || addr > 0x80000021) && - (addr < 0x800000a0 || addr > 0x800000a1) && - (addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177) && - (addr < 0x8000060 || addr > 0x8000064)) + int out; + out = pit_get_out(pit, 2, qemu_get_clock(vm_clock)); + dummy_refresh_clock ^= 1; + return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | + (dummy_refresh_clock << 4); #endif - { - PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); - } - return ret; + return 0; } -static void PPC_io_writew (target_phys_addr_t addr, uint32_t value) +/* PCI intack register */ +/* Read-only register (?) */ +static void _PPC_intack_write (target_phys_addr_t addr, uint32_t value) +{ + // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); +} + +static inline uint32_t _PPC_intack_read (target_phys_addr_t addr) +{ + uint32_t retval = 0; + + if (addr == 0xBFFFFFF0) + retval = pic_intack_read(NULL); + // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); + + return retval; +} + +static uint32_t PPC_intack_readb (target_phys_addr_t addr) +{ + return _PPC_intack_read(addr); +} + +static uint32_t PPC_intack_readw (target_phys_addr_t addr) { - if ((addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x => 0x%04x\n", addr - PPC_IO_BASE, value); - } #ifdef TARGET_WORDS_BIGENDIAN - value = bswap16(value); + return bswap16(_PPC_intack_read(addr)); +#else + return _PPC_intack_read(addr); #endif - cpu_outw(NULL, addr - PPC_IO_BASE, value); } -static uint32_t PPC_io_readw (target_phys_addr_t addr) +static uint32_t PPC_intack_readl (target_phys_addr_t addr) { - uint32_t ret = cpu_inw(NULL, addr - PPC_IO_BASE); #ifdef TARGET_WORDS_BIGENDIAN - ret = bswap16(ret); + return bswap32(_PPC_intack_read(addr)); +#else + return _PPC_intack_read(addr); #endif - if ((addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x <= 0x%04x\n", addr - PPC_IO_BASE, ret); - } - return ret; } -static void PPC_io_writel (target_phys_addr_t addr, uint32_t value) +static CPUWriteMemoryFunc *PPC_intack_write[] = { + &_PPC_intack_write, + &_PPC_intack_write, + &_PPC_intack_write, +}; + +static CPUReadMemoryFunc *PPC_intack_read[] = { + &PPC_intack_readb, + &PPC_intack_readw, + &PPC_intack_readl, +}; + +/* PowerPC control and status registers */ +#if 0 // Not used +static struct { + /* IDs */ + uint32_t veni_devi; + uint32_t revi; + /* Control and status */ + uint32_t gcsr; + uint32_t xcfr; + uint32_t ct32; + uint32_t mcsr; + /* General purpose registers */ + uint32_t gprg[6]; + /* Exceptions */ + uint32_t feen; + uint32_t fest; + uint32_t fema; + uint32_t fecl; + uint32_t eeen; + uint32_t eest; + uint32_t eecl; + uint32_t eeint; + uint32_t eemck0; + uint32_t eemck1; + /* Error diagnostic */ +} XCSR; +#endif + +static void PPC_XCSR_writeb (target_phys_addr_t addr, uint32_t value) +{ + printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); +} + +static void PPC_XCSR_writew (target_phys_addr_t addr, uint32_t value) { - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); #ifdef TARGET_WORDS_BIGENDIAN - value = bswap32(value); + value = bswap16(value); #endif - cpu_outl(NULL, addr - PPC_IO_BASE, value); + printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); } -static uint32_t PPC_io_readl (target_phys_addr_t addr) +static void PPC_XCSR_writel (target_phys_addr_t addr, uint32_t value) { - uint32_t ret = cpu_inl(NULL, addr - PPC_IO_BASE); - #ifdef TARGET_WORDS_BIGENDIAN - ret = bswap32(ret); + value = bswap32(value); #endif - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, ret); - return ret; + printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); } -static CPUWriteMemoryFunc *PPC_io_write[] = { - &PPC_io_writeb, - &PPC_io_writew, - &PPC_io_writel, -}; +static uint32_t PPC_XCSR_readb (target_phys_addr_t addr) +{ + uint32_t retval = 0; -static CPUReadMemoryFunc *PPC_io_read[] = { - &PPC_io_readb, - &PPC_io_readw, - &PPC_io_readl, -}; + printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); -/* Read-only register (?) */ -static void _PPC_ioB_write (target_phys_addr_t addr, uint32_t value) + return retval; +} + +static uint32_t PPC_XCSR_readw (target_phys_addr_t addr) { - // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); + uint32_t retval = 0; + + printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); +#ifdef TARGET_WORDS_BIGENDIAN + retval = bswap16(retval); +#endif + + return retval; } -static uint32_t _PPC_ioB_read (target_phys_addr_t addr) +static uint32_t PPC_XCSR_readl (target_phys_addr_t addr) { uint32_t retval = 0; - if (addr == 0xBFFFFFF0) - retval = pic_intack_read(NULL); - // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); + printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); +#ifdef TARGET_WORDS_BIGENDIAN + retval = bswap32(retval); +#endif return retval; } -static CPUWriteMemoryFunc *PPC_ioB_write[] = { - &_PPC_ioB_write, - &_PPC_ioB_write, - &_PPC_ioB_write, +static CPUWriteMemoryFunc *PPC_XCSR_write[] = { + &PPC_XCSR_writeb, + &PPC_XCSR_writew, + &PPC_XCSR_writel, }; -static CPUReadMemoryFunc *PPC_ioB_read[] = { - &_PPC_ioB_read, - &_PPC_ioB_read, - &_PPC_ioB_read, +static CPUReadMemoryFunc *PPC_XCSR_read[] = { + &PPC_XCSR_readb, + &PPC_XCSR_readw, + &PPC_XCSR_readl, }; -#if 0 -static CPUWriteMemoryFunc *PPC_io3_write[] = { - &PPC_io3_writeb, - &PPC_io3_writew, - &PPC_io3_writel, -}; +/* Fake super-io ports for PREP platform (Intel 82378ZB) */ +typedef struct sysctrl_t { + m48t59_t *nvram; + uint8_t state; + uint8_t syscontrol; + uint8_t fake_io[2]; +} sysctrl_t; -static CPUReadMemoryFunc *PPC_io3_read[] = { - &PPC_io3_readb, - &PPC_io3_readw, - &PPC_io3_readl, +enum { + STATE_HARDFILE = 0x01, }; -#endif -/* Fake super-io ports for PREP platform (Intel 82378ZB) */ -static uint8_t PREP_fake_io[2]; -static uint8_t NVRAM_lock; +static sysctrl_t *sysctrl; static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) { - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, val); - PREP_fake_io[addr - 0x0398] = val; + sysctrl_t *sysctrl = opaque; + + PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val); + sysctrl->fake_io[addr - 0x0398] = val; } static uint32_t PREP_io_read (void *opaque, uint32_t addr) { - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, PREP_fake_io[addr - 0x0398]); - return PREP_fake_io[addr - 0x0398]; -} + sysctrl_t *sysctrl = opaque; -static uint8_t syscontrol; + PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, + sysctrl->fake_io[addr - 0x0398]); + return sysctrl->fake_io[addr - 0x0398]; +} static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) { - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, val); + sysctrl_t *sysctrl = opaque; + + PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val); switch (addr) { case 0x0092: /* Special port 92 */ /* Check soft reset asked */ - if (val & 0x80) { - printf("Soft reset asked... Stop emulation\n"); - abort(); + if (val & 0x01) { + // cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET); } /* Check LE mode */ - if (val & 0x40) { + if (val & 0x02) { printf("Little Endian mode isn't supported (yet ?)\n"); abort(); } break; + case 0x0800: + /* Motorola CPU configuration register : read-only */ + break; + case 0x0802: + /* Motorola base module feature register : read-only */ + break; + case 0x0803: + /* Motorola base module status register : read-only */ + break; case 0x0808: - /* Hardfile light register: don't care */ + /* Hardfile light register */ + if (val & 1) + sysctrl->state |= STATE_HARDFILE; + else + sysctrl->state &= ~STATE_HARDFILE; break; case 0x0810: /* Password protect 1 register */ - NVRAM_lock ^= 0x01; + if (sysctrl->nvram != NULL) + m48t59_toggle_lock(sysctrl->nvram, 1); break; case 0x0812: /* Password protect 2 register */ - NVRAM_lock ^= 0x02; + if (sysctrl->nvram != NULL) + m48t59_toggle_lock(sysctrl->nvram, 2); break; case 0x0814: - /* L2 invalidate register: don't care */ + /* L2 invalidate register */ + // tlb_flush(cpu_single_env, 1); break; case 0x081C: /* system control register */ - syscontrol = val; + sysctrl->syscontrol = val & 0x0F; break; case 0x0850: /* I/O map type register */ - if (val & 0x80) { + if (!(val & 0x01)) { printf("No support for non-continuous I/O map mode\n"); abort(); } break; default: + printf("ERROR: unaffected IO port write: %04lx => %02x\n", + (long)addr, val); break; } } static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) { + sysctrl_t *sysctrl = opaque; uint32_t retval = 0xFF; switch (addr) { case 0x0092: /* Special port 92 */ - retval = 0x40; + retval = 0x00; + break; + case 0x0800: + /* Motorola CPU configuration register */ + retval = 0xEF; /* MPC750 */ + break; + case 0x0802: + /* Motorola Base module feature register */ + retval = 0xAD; /* No ESCC, PMC slot neither ethernet */ + break; + case 0x0803: + /* Motorola base module status register */ + retval = 0xE0; /* Standard MPC750 */ break; case 0x080C: /* Equipment present register: @@ -323,7 +369,11 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) * no cards in PCI slots * SCSI fuse is bad */ - retval = 0xFC; + retval = 0x3C; + break; + case 0x0810: + /* Motorola base module extended feature register */ + retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */ break; case 0x0818: /* Keylock */ @@ -333,7 +383,7 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) /* system control register * 7 - 6 / 1 - 0: L2 cache enable */ - retval = syscontrol; + retval = sysctrl->syscontrol; break; case 0x0823: /* */ @@ -341,561 +391,20 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) break; case 0x0850: /* I/O map type register */ - retval = 0x00; + retval = 0x01; break; default: + printf("ERROR: unaffected IO port: %04lx read\n", (long)addr); break; } - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, retval); + PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, retval); return retval; } -#define NVRAM_SIZE 0x2000 -#define NVRAM_END 0x1FF0 -#define NVRAM_OSAREA_SIZE 512 -#define NVRAM_CONFSIZE 1024 - -static inline void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) -{ - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value); -} - -static inline uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) -{ - m48t59_set_addr(nvram, addr); - return m48t59_read(nvram); -} - -static inline void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) -{ - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value >> 8); - m48t59_set_addr(nvram, addr + 1); - m48t59_write(nvram, value & 0xFF); -} - -static inline uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) -{ - uint16_t tmp; - - m48t59_set_addr(nvram, addr); - tmp = m48t59_read(nvram) << 8; - m48t59_set_addr(nvram, addr + 1); - tmp |= m48t59_read(nvram); - - return tmp; -} - -static inline void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, - uint32_t value) -{ - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value >> 24); - m48t59_set_addr(nvram, addr + 1); - m48t59_write(nvram, (value >> 16) & 0xFF); - m48t59_set_addr(nvram, addr + 2); - m48t59_write(nvram, (value >> 8) & 0xFF); - m48t59_set_addr(nvram, addr + 3); - m48t59_write(nvram, value & 0xFF); -} - -static inline uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) -{ - uint32_t tmp; - - m48t59_set_addr(nvram, addr); - tmp = m48t59_read(nvram) << 24; - m48t59_set_addr(nvram, addr + 1); - tmp |= m48t59_read(nvram) << 16; - m48t59_set_addr(nvram, addr + 2); - tmp |= m48t59_read(nvram) << 8; - m48t59_set_addr(nvram, addr + 3); - tmp |= m48t59_read(nvram); - - return tmp; -} - -static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) -{ - uint16_t tmp; - uint16_t pd, pd1, pd2; - - tmp = prev >> 8; - pd = prev ^ value; - pd1 = pd & 0x000F; - pd2 = ((pd >> 4) & 0x000F) ^ pd1; - tmp ^= (pd1 << 3) | (pd1 << 8); - tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); - - return tmp; -} - -static void NVRAM_set_crc (m48t59_t *nvram, uint32_t addr, - uint32_t start, uint32_t count) -{ - uint32_t i; - uint16_t crc = 0xFFFF; - int odd = 0; - - if (count & 1) - odd = 1; - count &= ~1; - for (i = 0; i != count; i++) { - crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); - } - if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); - } - NVRAM_set_word(nvram, addr, crc); -} - -static void prep_NVRAM_init (void) -{ - m48t59_t *nvram; - - nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); - /* NVRAM header */ - /* 0x00: NVRAM size in kB */ - NVRAM_set_word(nvram, 0x00, NVRAM_SIZE >> 10); - /* 0x02: NVRAM version */ - NVRAM_set_byte(nvram, 0x02, 0x01); - /* 0x03: NVRAM revision */ - NVRAM_set_byte(nvram, 0x03, 0x01); - /* 0x08: last OS */ - NVRAM_set_byte(nvram, 0x08, 0x00); /* Unknown */ - /* 0x09: endian */ - NVRAM_set_byte(nvram, 0x09, 'B'); /* Big-endian */ - /* 0x0A: OSArea usage */ - NVRAM_set_byte(nvram, 0x0A, 0x00); /* Empty */ - /* 0x0B: PM mode */ - NVRAM_set_byte(nvram, 0x0B, 0x00); /* Normal */ - /* Restart block description record */ - /* 0x0C: restart block version */ - NVRAM_set_word(nvram, 0x0C, 0x01); - /* 0x0E: restart block revision */ - NVRAM_set_word(nvram, 0x0E, 0x01); - /* 0x20: restart address */ - NVRAM_set_lword(nvram, 0x20, 0x00); - /* 0x24: save area address */ - NVRAM_set_lword(nvram, 0x24, 0x00); - /* 0x28: save area length */ - NVRAM_set_lword(nvram, 0x28, 0x00); - /* 0x1C: checksum of restart block */ - NVRAM_set_crc(nvram, 0x1C, 0x0C, 32); - - /* Security section */ - /* Set all to zero */ - /* 0xC4: pointer to global environment area */ - NVRAM_set_lword(nvram, 0xC4, 0x0100); - /* 0xC8: size of global environment area */ - NVRAM_set_lword(nvram, 0xC8, - NVRAM_END - NVRAM_OSAREA_SIZE - NVRAM_CONFSIZE - 0x0100); - /* 0xD4: pointer to configuration area */ - NVRAM_set_lword(nvram, 0xD4, NVRAM_END - NVRAM_CONFSIZE); - /* 0xD8: size of configuration area */ - NVRAM_set_lword(nvram, 0xD8, NVRAM_CONFSIZE); - /* 0xE8: pointer to OS specific area */ - NVRAM_set_lword(nvram, 0xE8, - NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); - /* 0xD8: size of OS specific area */ - NVRAM_set_lword(nvram, 0xEC, NVRAM_OSAREA_SIZE); - - /* Configuration area */ - /* RTC init */ - // NVRAM_set_lword(nvram, 0x1FFC, 0x50); - - /* 0x04: checksum 0 => OS area */ - NVRAM_set_crc(nvram, 0x04, 0x00, - NVRAM_END - NVRAM_CONFSIZE - NVRAM_OSAREA_SIZE); - /* 0x06: checksum of config area */ - NVRAM_set_crc(nvram, 0x06, NVRAM_END - NVRAM_CONFSIZE, NVRAM_CONFSIZE); -} - -int load_initrd (const char *filename, uint8_t *addr) -{ - int fd, size; - - printf("Load initrd\n"); - fd = open(filename, O_RDONLY); - if (fd < 0) - return -1; - size = read(fd, addr, 16 * 1024 * 1024); - if (size < 0) - goto fail; - close(fd); - printf("Load initrd: %d\n", size); - return size; - fail: - close(fd); - printf("Load initrd failed\n"); - return -1; -} - -/* Quick hack for PPC memory infos... */ -static void put_long (void *addr, uint32_t l) -{ - char *pos = addr; - pos[0] = (l >> 24) & 0xFF; - pos[1] = (l >> 16) & 0xFF; - pos[2] = (l >> 8) & 0xFF; - pos[3] = l & 0xFF; -} - -/* bootloader infos are in the form: - * uint32_t TAG - * uint32_t TAG_size (from TAG to next TAG). - * data - * .... - */ -#if !defined (USE_OPEN_FIRMWARE) -static void *set_bootinfo_tag (void *addr, uint32_t tag, uint32_t size, - void *data) -{ - char *pos = addr; - - put_long(pos, tag); - pos += 4; - put_long(pos, size + 8); - pos += 4; - memcpy(pos, data, size); - pos += size; - - return pos; -} -#endif - -typedef struct boot_dev_t { - const unsigned char *name; - int major; - int minor; -} boot_dev_t; - -static boot_dev_t boot_devs[] = -{ - { "/dev/fd0", 2, 0, }, - { "/dev/fd1", 2, 1, }, - { "/dev/hda", 3, 1, }, -// { "/dev/ide/host0/bus0/target0/lun0/part1", 3, 1, }, -// { "/dev/hdc", 22, 0, }, - { "/dev/hdc", 22, 1, }, - { "/dev/ram0 init=/linuxrc", 1, 0, }, -}; - -/* BATU: - * BEPI : bloc virtual address - * BL : area size bits (128 kB is 0, 256 1, 512 3, ... - * Vs/Vp - * BATL: - * BPRN : bloc real address align on 4MB boundary - * WIMG : cache access mode : not used - * PP : protection bits - */ -static void setup_BAT (CPUPPCState *env, int BAT, - uint32_t virtual, uint32_t physical, - uint32_t size, int Vs, int Vp, int PP) -{ - uint32_t sz_bits, tmp_sz, align, tmp; - - sz_bits = 0; - align = 131072; - for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) { - sz_bits = (sz_bits << 1) + 1; - align = align << 1; - } - tmp = virtual & ~(align - 1); /* Align virtual area start */ - tmp |= sz_bits << 2; /* Fix BAT size */ - tmp |= Vs << 1; /* Supervisor access */ - tmp |= Vp; /* User access */ - env->DBAT[0][BAT] = tmp; - env->IBAT[0][BAT] = tmp; - tmp = physical & ~(align - 1); /* Align physical area start */ - tmp |= 0; /* Don't care about WIMG */ - tmp |= PP; /* Protection */ - env->DBAT[1][BAT] = tmp; - env->IBAT[1][BAT] = tmp; - printf("Set BATU0 to 0x%08x BATL0 to 0x%08x\n", - env->DBAT[0][BAT], env->DBAT[1][BAT]); -} - -static void VGA_printf (uint8_t *s) -{ - uint16_t *arg_ptr; - unsigned int format_width, i; - int in_format; - uint16_t arg, digit, nibble; - uint8_t c; - - arg_ptr = (uint16_t *)((void *)&s); - in_format = 0; - format_width = 0; - while ((c = *s) != '\0') { - if (c == '%') { - in_format = 1; - format_width = 0; - } else if (in_format) { - if ((c >= '0') && (c <= '9')) { - format_width = (format_width * 10) + (c - '0'); - } else if (c == 'x') { - arg_ptr++; // increment to next arg - arg = *arg_ptr; - if (format_width == 0) - format_width = 4; - digit = format_width - 1; - for (i = 0; i < format_width; i++) { - nibble = (arg >> (4 * digit)) & 0x000f; - if (nibble <= 9) - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0'); - else - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A'); - digit--; - } - in_format = 0; - } - //else if (c == 'd') { - // in_format = 0; - // } - } else { - PPC_io_writeb(PPC_IO_BASE + 0x500, c); - } - s++; - } -} - -static void VGA_init (void) -{ - /* Basic VGA init, inspired by plex86 VGAbios */ -#if 1 - /* switch to color mode and enable CPU access 480 lines */ - PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); - /* more than 64k 3C4/04 */ - PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04); - PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02); -#endif - VGA_printf("PPC VGA BIOS...\n"); -} - extern CPUPPCState *global_env; -static uint32_t get_le32 (void *addr) -{ - return le32_to_cpu(*((uint32_t *)addr)); -} - -void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, - uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device, - const unsigned char *initrd_file) -{ - CPUPPCState *env = global_env; - uint8_t *p; -#if !defined (USE_OPEN_FIRMWARE) - char *tmp; - uint32_t tmpi[2]; -#endif - - printf("RAM size: %u 0x%08x (%u)\n", mem_size, mem_size, mem_size >> 20); -#if defined (USE_OPEN_FIRMWARE) - setup_memory(env, mem_size); -#endif - - /* Fake bootloader */ - { -#if 1 - uint32_t offset = get_le32(phys_ram_base + kernel_addr); -#else - uint32_t offset = 12; -#endif - env->nip = kernel_addr + offset; - printf("Start address: 0x%08x\n", env->nip); - } - /* Set up msr according to PREP specification */ - msr_ee = 0; - msr_fp = 1; - msr_pr = 0; /* Start in supervisor mode */ - msr_me = 1; - msr_fe0 = msr_fe1 = 0; - msr_ip = 0; - msr_ir = msr_dr = 1; -// msr_sf = 0; - msr_le = msr_ile = 0; - env->gpr[1] = stack_addr; /* Let's have a stack */ - env->gpr[2] = 0; - env->gpr[8] = kernel_addr; - /* There is a bug in 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee, - * it's not ready to handle it... - */ - p = phys_ram_base + kernel_addr; -#if !defined (USE_OPEN_FIRMWARE) - /* Let's register the whole memory available only in supervisor mode */ - setup_BAT(env, 0, 0x00000000, 0x00000000, mem_size, 1, 0, 2); - /* Avoid open firmware init call (to get a console) - * This will make the kernel think we are a PREP machine... - */ - put_long(p, 0xdeadc0de); - /* Build a real stack room */ - p = phys_ram_base + stack_addr; - put_long(p, stack_addr); - p -= 32; - env->gpr[1] -= 32; - /* Pretend there are no residual data */ - env->gpr[3] = 0; - if (initrd_file != NULL) { - int size; - env->gpr[4] = (kernel_addr + kernel_size + 4095) & ~4095; - size = load_initrd(initrd_file, - phys_ram_base + env->gpr[4]); - if (size < 0) { - /* No initrd */ - env->gpr[4] = env->gpr[5] = 0; - } else { - env->gpr[5] = size; - boot_device = 'e'; - } - printf("Initrd loaded at 0x%08x (%d) (0x%08x 0x%08x)\n", - env->gpr[4], env->gpr[5], kernel_addr, kernel_size); - } else { - env->gpr[4] = env->gpr[5] = 0; - } - /* We have to put bootinfos after the BSS - * The BSS starts after the kernel end. - */ -#if 0 - p = phys_ram_base + kernel_addr + - kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1); -#else - p = phys_ram_base + kernel_addr + 0x400000; -#endif - if (loglevel > 0) { - fprintf(logfile, "bootinfos: %p 0x%08x\n", - p, (int)(p - phys_ram_base)); - } else { - printf("bootinfos: %p 0x%08x\n", - p, (int)(p - phys_ram_base)); - } - /* Command line: let's put it after bootinfos */ -#if 0 - sprintf(p + 0x1000, "console=ttyS0,9600 root=%02x%02x mem=%dM", - boot_devs[boot_device - 'a'].major, - boot_devs[boot_device - 'a'].minor, - mem_size >> 20); -#else - sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM", - boot_devs[boot_device - 'a'].name, - mem_size >> 20); -#endif - env->gpr[6] = p + 0x1000 - phys_ram_base; - env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); - if (loglevel > 0) { - fprintf(logfile, "cmdline: %p 0x%08x [%s]\n", - p + 0x1000, env->gpr[6], p + 0x1000); - } else { - printf("cmdline: %p 0x%08x [%s]\n", - p + 0x1000, env->gpr[6], p + 0x1000); - } - /* BI_FIRST */ - p = set_bootinfo_tag(p, 0x1010, 0, 0); - /* BI_CMD_LINE */ - p = set_bootinfo_tag(p, 0x1012, env->gpr[7] - env->gpr[6], - env->gpr[6] + phys_ram_base); - /* BI_MEM_SIZE */ - tmp = (void *)tmpi; - tmp[0] = (mem_size >> 24) & 0xFF; - tmp[1] = (mem_size >> 16) & 0xFF; - tmp[2] = (mem_size >> 8) & 0xFF; - tmp[3] = mem_size & 0xFF; - p = set_bootinfo_tag(p, 0x1017, 4, tmpi); - /* BI_INITRD */ - tmp[0] = (env->gpr[4] >> 24) & 0xFF; - tmp[1] = (env->gpr[4] >> 16) & 0xFF; - tmp[2] = (env->gpr[4] >> 8) & 0xFF; - tmp[3] = env->gpr[4] & 0xFF; - tmp[4] = (env->gpr[5] >> 24) & 0xFF; - tmp[5] = (env->gpr[5] >> 16) & 0xFF; - tmp[6] = (env->gpr[5] >> 8) & 0xFF; - tmp[7] = env->gpr[5] & 0xFF; - p = set_bootinfo_tag(p, 0x1014, 8, tmpi); - env->gpr[4] = env->gpr[5] = 0; - /* BI_LAST */ - p = set_bootinfo_tag(p, 0x1011, 0, 0); -#else - /* Set up MMU: - * kernel is loaded at kernel_addr and wants to be seen at 0x01000000 - */ - setup_BAT(env, 0, 0x01000000, kernel_addr, 0x00400000, 1, 0, 2); - { -#if 0 - uint32_t offset = get_le32(phys_ram_base + kernel_addr); -#else - uint32_t offset = 12; -#endif - env->nip = 0x01000000 | (kernel_addr + offset); - printf("Start address: 0x%08x\n", env->nip); - } - env->gpr[1] = env->nip + (1 << 22); - p = phys_ram_base + stack_addr; - put_long(p - 32, stack_addr); - env->gpr[1] -= 32; - printf("Kernel starts at 0x%08x stack 0x%08x\n", env->nip, env->gpr[1]); - /* We want all lower address not to be translated */ - setup_BAT(env, 1, 0x00000000, 0x00000000, 0x010000000, 1, 1, 2); - /* We also need a BAT to access OF */ - setup_BAT(env, 2, 0xFFFE0000, mem_size - 131072, 131072, 1, 0, 1); - /* Setup OF entry point */ - { - char *p; - p = (char *)phys_ram_base + mem_size - 131072; - /* Special opcode to call OF */ - *p++ = 0x18; *p++ = 0x00; *p++ = 0x00; *p++ = 0x02; - /* blr */ - *p++ = 0x4E; *p++ = 0x80; *p++ = 0x00; *p++ = 0x20; - } - env->gpr[5] = 0xFFFE0000; - /* Register translations */ - { - OF_transl_t translations[3] = { - { 0x01000000, 0x00400000, kernel_addr, 0x00000002, }, - { 0x00000000, 0x01000000, 0x00000000, 0x00000002, }, - { 0xFFFE0000, 0x00020000, mem_size - (128 * 1024), - 0x00000001, }, - }; - OF_register_translations(3, translations); - } - /* Quite artificial, for now */ - OF_register_bus("isa", "isa"); - OF_register_serial("isa", "serial", 4, 0x3f8); - OF_register_stdio("serial", "serial"); - /* Set up RTAS service */ - RTAS_init(); - /* Command line: let's put it just over the stack */ -#if 0 -#if 0 - p = phys_ram_base + kernel_addr + - kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1); -#else - p = phys_ram_base + kernel_addr + 0x400000; -#endif -#if 1 - sprintf(p, "console=ttyS0,9600 root=%02x%02x mem=%dM", - boot_devs[boot_device - 'a'].major, - boot_devs[boot_device - 'a'].minor, - mem_size >> 20); -#else - sprintf(p, "console=ttyS0,9600 root=%s mem=%dM ne2000=0x300,9", - boot_devs[boot_device - 'a'].name, - mem_size >> 20); -#endif - OF_register_bootargs(p); -#endif -#endif -} - -void PPC_end_init (void) -{ - VGA_init(); -} +#define NVRAM_SIZE 0x2000 /* PowerPC PREP hardware initialisation */ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, @@ -904,56 +413,63 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; + // void *openpic; + m48t59_t *nvram; int PPC_io_memory; - int ret, linux_boot, initrd_size, i, nb_nics1, fd; + int ret, linux_boot, i, nb_nics1, fd; + unsigned long bios_offset; + uint32_t kernel_base, kernel_size, initrd_base, initrd_size; + + sysctrl = qemu_mallocz(sizeof(sysctrl_t)); + if (sysctrl == NULL) + return; linux_boot = (kernel_filename != NULL); /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); - - isa_mem_base = 0xc0000000; + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + /* allocate and load BIOS */ + bios_offset = ram_size + vga_ram_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret != BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf); + exit(1); + } + cpu_register_physical_memory((uint32_t)(-BIOS_SIZE), + BIOS_SIZE, bios_offset | IO_MEM_ROM); + cpu_single_env->nip = 0xfffffffc; if (linux_boot) { + kernel_base = KERNEL_LOAD_ADDR; /* now we can load the kernel */ - ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (ret < 0) { + kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); + if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } /* load initrd */ - initrd_size = 0; -#if 0 if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_base); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } + } else { + initrd_base = 0; + initrd_size = 0; } -#endif - PPC_init_hw(/*env,*/ ram_size, KERNEL_LOAD_ADDR, ret, - KERNEL_STACK_ADDR, boot_device, initrd_filename); + boot_device = 'm'; } else { - int bios_ram_offset; - -#define BIOS_START 0x00800000 - - /* allocate ROM */ - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - bios_ram_offset = ram_size + vga_ram_size; - printf("load BIOS at 0x%08x\n", BIOS_START); - ret = load_image(buf, phys_ram_base + bios_ram_offset); - if (ret != BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PPC bios '%s' (%d)\n%m\n", - buf, ret); - exit(1); - } - global_env->nip = BIOS_START + BIOS_SIZE - 4; - cpu_register_physical_memory(BIOS_START, BIOS_SIZE, - IO_MEM_ROM | bios_ram_offset); + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; } /* Register CPU as a 74x/75x */ @@ -961,50 +477,78 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); + isa_mem_base = 0xc0000000; + pci_prep_init(); + /* Register 64 KB of ISA IO space */ + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); + cpu_register_physical_memory(0x80000000, 0x00010000, PPC_io_memory); + /* init basic PC hardware */ vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0); + vga_ram_size, 1); rtc_init(0x70, 8); + // openpic = openpic_init(0x00000000, 0xF0000000, 1); + // pic_init(openpic); pic_init(); - // pit_init(0x40, 0); + // pit = pit_init(0x40, 0); fd = serial_open_device(); serial_init(0x3f8, 4, fd); -#if 1 nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; for(i = 0; i < nb_nics1; i++) { isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); } -#endif for(i = 0; i < 2; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], bs_table[2 * i], bs_table[2 * i + 1]); } kbd_init(); - AUD_init(); DMA_init(); + // AUD_init(); // SB16_init(); fdctrl_init(6, 2, 0, 0x3f0, fd_table); - /* Register 64 kB of IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); - cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); + /* Register speaker port */ + register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); + register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); /* Register fake IO ports for PREP */ - register_ioport_read(0x398, 2, 1, &PREP_io_read, NULL); - register_ioport_write(0x398, 2, 1, &PREP_io_write, NULL); + register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl); + register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl); /* System control ports */ - register_ioport_write(0x0092, 0x1, 1, &PREP_io_800_writeb, NULL); - register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, NULL); - register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, NULL); - /* PCI intack location (0xfef00000 / 0xbffffff0) */ - PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); + register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl); + register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl); + register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl); + register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl); + /* PCI intack location */ + PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read, + PPC_intack_write); cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); - // cpu_register_physical_memory(0xFEF00000, 0x4, PPC_io_memory); - prep_NVRAM_init(); + /* PowerPC control and status register group */ + PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write); + cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); - PPC_end_init(); + nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); + if (nvram == NULL) + return; + sysctrl->nvram = nvram; + + /* Initialise NVRAM */ + PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, + kernel_base, kernel_size, + (uint32_t)(long)kernel_cmdline, + strlen(kernel_cmdline), + initrd_base, initrd_size, + /* XXX: need an option to load a NVRAM image */ + 0 + ); + + /* Special port to get debug messages from Open-Firmware */ + register_ioport_write(0xFF00, 0x04, 1, &PREP_debug_write, NULL); + register_ioport_write(0xFF00, 0x04, 2, &PREP_debug_write, NULL); + + pci_ppc_bios_init(); } diff --git a/vl.h b/vl.h index b163baf5c..d658aa897 100644 --- a/vl.h +++ b/vl.h @@ -594,15 +594,34 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); -struct sysctrl_t; -int prep_NVRAM_init (struct sysctrl_t *sysctrl, uint32_t RAM_size, - uint32_t BIOS_size, int boot_device, - uint32_t kernel_image); +void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); extern CPUWriteMemoryFunc *PPC_io_write[]; extern CPUReadMemoryFunc *PPC_io_read[]; extern int prep_enabled; +/* NVRAM helpers */ +#include "hw/m48t59.h" + +void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value); +uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value); +uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value); +uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr); +void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, + const unsigned char *str, uint32_t max); +int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max); +void NVRAM_set_crc (m48t59_t *nvram, uint32_t addr, + uint32_t start, uint32_t count); +int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, + const unsigned char *arch, + uint32_t RAM_size, int boot_device, + uint32_t kernel_image, uint32_t kernel_size, + uint32_t cmdline, uint32_t cmdline_size, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image); + /* monitor.c */ void monitor_init(void); void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -- cgit v1.2.3 From 09a79b4974fbeee660660d79ab45bd37ec416741 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 May 2004 22:58:01 +0000 Subject: partial big endian fixes - change VESA VBE ports for non i386 targets to avoid unaligned accesses git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@866 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 90 +++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 64769d157..30dead00d 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -489,34 +489,40 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) } #ifdef CONFIG_BOCHS_VBE -static uint32_t vbe_ioport_read(void *opaque, uint32_t addr) +static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) { VGAState *s = opaque; uint32_t val; + val = s->vbe_index; + return val; +} - addr &= 1; - if (addr == 0) { - val = s->vbe_index; - } else { - if (s->vbe_index <= VBE_DISPI_INDEX_NB) - val = s->vbe_regs[s->vbe_index]; - else - val = 0; +static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) +{ + VGAState *s = opaque; + uint32_t val; + + if (s->vbe_index <= VBE_DISPI_INDEX_NB) + val = s->vbe_regs[s->vbe_index]; + else + val = 0; #ifdef DEBUG_BOCHS_VBE - printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); + printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); #endif - } return val; } -static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) +{ + VGAState *s = opaque; + s->vbe_index = val; +} + +static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) { VGAState *s = opaque; - addr &= 1; - if (addr == 0) { - s->vbe_index = val; - } else if (s->vbe_index <= VBE_DISPI_INDEX_NB) { + if (s->vbe_index <= VBE_DISPI_INDEX_NB) { #ifdef DEBUG_BOCHS_VBE printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val); #endif @@ -709,18 +715,30 @@ static uint32_t vga_mem_readb(target_phys_addr_t addr) static uint32_t vga_mem_readw(target_phys_addr_t addr) { uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = vga_mem_readb(addr) << 8; + v |= vga_mem_readb(addr + 1); +#else v = vga_mem_readb(addr); v |= vga_mem_readb(addr + 1) << 8; +#endif return v; } static uint32_t vga_mem_readl(target_phys_addr_t addr) { uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = vga_mem_readb(addr) << 24; + v |= vga_mem_readb(addr + 1) << 16; + v |= vga_mem_readb(addr + 2) << 8; + v |= vga_mem_readb(addr + 3); +#else v = vga_mem_readb(addr); v |= vga_mem_readb(addr + 1) << 8; v |= vga_mem_readb(addr + 2) << 16; v |= vga_mem_readb(addr + 3) << 24; +#endif return v; } @@ -855,16 +873,28 @@ static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val) static void vga_mem_writew(target_phys_addr_t addr, uint32_t val) { +#ifdef TARGET_WORDS_BIGENDIAN + vga_mem_writeb(addr, (val >> 8) & 0xff); + vga_mem_writeb(addr + 1, val & 0xff); +#else vga_mem_writeb(addr, val & 0xff); vga_mem_writeb(addr + 1, (val >> 8) & 0xff); +#endif } static void vga_mem_writel(target_phys_addr_t addr, uint32_t val) { +#ifdef TARGET_WORDS_BIGENDIAN + vga_mem_writeb(addr, (val >> 24) & 0xff); + vga_mem_writeb(addr + 1, (val >> 16) & 0xff); + vga_mem_writeb(addr + 2, (val >> 8) & 0xff); + vga_mem_writeb(addr + 3, val & 0xff); +#else vga_mem_writeb(addr, val & 0xff); vga_mem_writeb(addr + 1, (val >> 8) & 0xff); vga_mem_writeb(addr + 2, (val >> 16) & 0xff); vga_mem_writeb(addr + 3, (val >> 24) & 0xff); +#endif } typedef void vga_draw_glyph8_func(uint8_t *d, int linesize, @@ -1366,7 +1396,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) ((s->cr[0x07] & 0x40) << 3); height = (height + 1); disp_width = width; - + shift_control = (s->gr[0x05] >> 5) & 3; double_scan = (s->cr[0x09] & 0x80); if (shift_control > 1) { @@ -1774,19 +1804,27 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, #ifdef CONFIG_BOCHS_VBE s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0; s->vbe_bank_mask = ((s->vram_size >> 16) - 1); - register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s); - register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s); +#if defined (TARGET_I386) + register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s); + register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s); - register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s); - register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s); + register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s); + register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s); /* old Bochs IO ports */ - register_ioport_read(0xff80, 1, 2, vbe_ioport_read, s); - register_ioport_read(0xff81, 1, 2, vbe_ioport_read, s); + register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s); + register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s); - register_ioport_write(0xff80, 1, 2, vbe_ioport_write, s); - register_ioport_write(0xff81, 1, 2, vbe_ioport_write, s); + register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s); + register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); +#else + register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s); + register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s); + + register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s); + register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s); #endif +#endif /* CONFIG_BOCHS_VBE */ vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, @@ -1814,11 +1852,9 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); } else { #ifdef CONFIG_BOCHS_VBE -#if defined (TARGET_I386) /* XXX: use optimized standard vga accesses */ cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, vga_ram_size, vga_ram_offset); -#endif #endif } return 0; -- cgit v1.2.3 From 8cc43feffcbd0fbe37a4410836632c698f143241 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 May 2004 23:29:15 +0000 Subject: compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@867 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.h b/vl.h index d658aa897..05b0a1f4d 100644 --- a/vl.h +++ b/vl.h @@ -593,7 +593,9 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); -ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); +#ifdef TARGET_PPC +ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); +#endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); extern CPUWriteMemoryFunc *PPC_io_write[]; -- cgit v1.2.3 From f66723fab9eab2695a1b3cf15b55ffc2936b6418 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 May 2004 11:04:25 +0000 Subject: put ready it after write command (aka FreeBSD HD access fix) - access 16 mult sector count git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@868 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 45974aeb3..8b5f63e6d 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -185,7 +185,7 @@ #define DISABLE_SEAGATE 0xFB /* set to 1 set disable mult support */ -#define MAX_MULT_SECTORS 8 +#define MAX_MULT_SECTORS 16 /* ATAPI defines */ @@ -1142,7 +1142,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case WIN_WRITE: case WIN_WRITE_ONCE: s->error = 0; - s->status = SEEK_STAT; + s->status = SEEK_STAT | READY_STAT; s->req_nb_sectors = 1; ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); break; @@ -1156,7 +1156,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (!s->mult_sectors) goto abort_cmd; s->error = 0; - s->status = SEEK_STAT; + s->status = SEEK_STAT | READY_STAT; s->req_nb_sectors = s->mult_sectors; n = s->nsector; if (n > s->req_nb_sectors) -- cgit v1.2.3 From 023fe10d24acd124d0b7c5c5ac8edd41d6cc08f2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 May 2004 11:08:52 +0000 Subject: fnop FPU exception support (aka FreeBSD FPU probe) - sysenter/sysexit support (untested, not enabled in cpuid) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@869 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 2 ++ target-i386/helper.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ target-i386/op.c | 10 ++++++++++ target-i386/translate.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+) diff --git a/target-i386/exec.h b/target-i386/exec.h index f5b03fbe5..4410069a3 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -167,6 +167,8 @@ void helper_divl_EAX_T0(uint32_t eip); void helper_idivl_EAX_T0(uint32_t eip); void helper_cmpxchg8b(void); void helper_cpuid(void); +void helper_sysenter(void); +void helper_sysexit(void); void helper_rdtsc(void); void helper_rdmsr(void); void helper_wrmsr(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 5782babc2..9a88275f2 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1746,6 +1746,50 @@ void helper_lret_protected(int shift, int addend) helper_ret_protected(shift, 0, addend); } +void helper_sysenter(void) +{ + if (env->sysenter_cs == 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); + cpu_x86_set_cpl(env, 0); + cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, + NULL, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, + NULL, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + ESP = env->sysenter_esp; + EIP = env->sysenter_eip; +} + +void helper_sysexit(void) +{ + int cpl; + + cpl = env->hflags & HF_CPL_MASK; + if (env->sysenter_cs == 0 || cpl != 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + cpu_x86_set_cpl(env, 3); + cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, + NULL, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, + NULL, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + ESP = ECX; + EIP = EDX; +} + void helper_movl_crN_T0(int reg) { switch(reg) { diff --git a/target-i386/op.c b/target-i386/op.c index fad8a730e..3f9afb17d 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -700,6 +700,16 @@ void OPPROTO op_cpuid(void) helper_cpuid(); } +void OPPROTO op_sysenter(void) +{ + helper_sysenter(); +} + +void OPPROTO op_sysexit(void) +{ + helper_sysexit(); +} + void OPPROTO op_rdmsr(void) { helper_rdmsr(); diff --git a/target-i386/translate.c b/target-i386/translate.c index 514399d93..ee4f05ad3 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2973,6 +2973,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x0a: /* grp d9/2 */ switch(rm) { case 0: /* fnop */ + /* check exceptions (FreeBSD FPU probe) */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_fwait(); break; default: goto illegal_op; @@ -3881,6 +3886,32 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x131: /* rdtsc */ gen_op_rdtsc(); break; + case 0x134: /* sysenter */ + if (!s->pe) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_sysenter(); + gen_eob(s); + } + break; + case 0x135: /* sysexit */ + if (!s->pe) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_sysexit(); + gen_eob(s); + } + break; case 0x1a2: /* cpuid */ gen_op_cpuid(); break; -- cgit v1.2.3 From be3edd95908863ae39936d1b0608f0727256a3c3 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 12:48:45 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@870 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + qemu-doc.texi | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 0f232e3ec..95b456267 100644 --- a/Changelog +++ b/Changelog @@ -15,6 +15,7 @@ version 0.5.6: - VGA font selection fix (Daniel Serpell) - PIC reset fix (Hidemi KAWAI) - PIC spurious irq support (aka Solaris install bug) + - added '-localtime' option version 0.5.5: diff --git a/qemu-doc.texi b/qemu-doc.texi index 0e3f617b7..395f39a3f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -196,7 +196,8 @@ General options: @table @option @item -fda file @item -fdb file -Use @var{file} as floppy disk 0/1 image (@xref{disk_images}). +Use @var{file} as floppy disk 0/1 image (@xref{disk_images}). You can +use the host floppy by using @file{/dev/fd0} as filename. @item -hda file @item -hdb file @@ -206,7 +207,8 @@ Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}). @item -cdrom file Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and -@option{-cdrom} at the same time). +@option{-cdrom} at the same time). You can use the host CD-ROM by +using @file{/dev/cdrom} as filename. @item -boot [a|c|d] Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is -- cgit v1.2.3 From ee22c2f7dbcc59d9b0c0c9e08fafc9c4759b37fc Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 12:49:50 +0000 Subject: -localtime option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@871 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 5 ++++- vl.c | 6 ++++++ vl.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index 815d47fe5..eef120e0e 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -110,7 +110,10 @@ static void cmos_init(int ram_size, int boot_device) /* set the CMOS date */ time(&ti); - tm = gmtime(&ti); + if (rtc_utc) + tm = gmtime(&ti); + else + tm = localtime(&ti); rtc_set_date(s, tm); val = to_bcd(s, (tm->tm_year / 100) + 19); diff --git a/vl.c b/vl.c index 6faf19f0e..445066fa0 100644 --- a/vl.c +++ b/vl.c @@ -129,6 +129,7 @@ int vm_running; int audio_enabled = 0; int pci_enabled = 0; int prep_enabled = 0; +int rtc_utc = 1; /***********************************************************/ /* x86 ISA bus support */ @@ -2015,6 +2016,7 @@ enum { QEMU_OPTION_no_code_copy, QEMU_OPTION_pci, QEMU_OPTION_prep, + QEMU_OPTION_localtime, }; typedef struct QEMUOption { @@ -2065,6 +2067,7 @@ const QEMUOption qemu_options[] = { #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, #endif + { "localtime", 0, QEMU_OPTION_localtime }, { NULL }, }; @@ -2341,6 +2344,9 @@ int main(int argc, char **argv) case QEMU_OPTION_prep: prep_enabled = 1; break; + case QEMU_OPTION_localtime: + rtc_utc = 0; + break; } } } diff --git a/vl.h b/vl.h index 05b0a1f4d..54f6cdd29 100644 --- a/vl.h +++ b/vl.h @@ -170,6 +170,7 @@ void vm_stop(int reason); extern int audio_enabled; extern int ram_size; extern int bios_size; +extern int rtc_utc; /* XXX: make it dynamic */ #if defined (TARGET_PPC) -- cgit v1.2.3 From 43f493afb43f041919f46c6fb781baffbf53dbd0 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 12:51:19 +0000 Subject: more accurate emulation (do not depend on localtime() or gmtime() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@872 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mc146818rtc.c | 160 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 58 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 69addba0c..9d4cbed90 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -53,9 +53,8 @@ struct RTCState { uint8_t cmos_data[128]; uint8_t cmos_index; - int current_time; /* in seconds */ + struct tm current_tm; int irq; - uint8_t buf_data[10]; /* buffered data */ /* periodic timer */ QEMUTimer *periodic_timer; int64_t next_periodic_time; @@ -66,7 +65,6 @@ struct RTCState { }; static void rtc_set_time(RTCState *s); -static void rtc_set_date_buf(RTCState *s, const struct tm *tm); static void rtc_copy_date(RTCState *s); static void rtc_timer_update(RTCState *s, int64_t current_time) @@ -182,27 +180,96 @@ static inline int from_bcd(RTCState *s, int a) static void rtc_set_time(RTCState *s) { - struct tm tm1, *tm = &tm1; + struct tm *tm = &s->current_tm; tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]); tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]); - tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS]); + tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f); + if (!(s->cmos_data[RTC_REG_B] & 0x02) && + (s->cmos_data[RTC_HOURS] & 0x80)) { + tm->tm_hour += 12; + } tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]); tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100; +} + +static void rtc_copy_date(RTCState *s) +{ + const struct tm *tm = &s->current_tm; - /* update internal state */ - s->buf_data[RTC_SECONDS] = s->cmos_data[RTC_SECONDS]; - s->buf_data[RTC_MINUTES] = s->cmos_data[RTC_MINUTES]; - s->buf_data[RTC_HOURS] = s->cmos_data[RTC_HOURS]; - s->buf_data[RTC_DAY_OF_WEEK] = s->cmos_data[RTC_DAY_OF_WEEK]; - s->buf_data[RTC_DAY_OF_MONTH] = s->cmos_data[RTC_DAY_OF_MONTH]; - s->buf_data[RTC_MONTH] = s->cmos_data[RTC_MONTH]; - s->buf_data[RTC_YEAR] = s->cmos_data[RTC_YEAR]; - s->current_time = mktime(tm); + s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); + s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); + if (s->cmos_data[RTC_REG_B] & 0x02) { + /* 24 hour format */ + s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour); + } else { + /* 12 hour format */ + s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12); + if (tm->tm_hour >= 12) + s->cmos_data[RTC_HOURS] |= 0x80; + } + s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday); + s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday); + s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1); + s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100); +} + +/* month is between 0 and 11. */ +static int get_days_in_month(int month, int year) +{ + static const int days_tab[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + int d; + if ((unsigned )month >= 12) + return 31; + d = days_tab[month]; + if (month == 1) { + if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) + d++; + } + return d; +} + +/* update 'tm' to the next second */ +static void rtc_next_second(struct tm *tm) +{ + int days_in_month; + + tm->tm_sec++; + if ((unsigned)tm->tm_sec >= 60) { + tm->tm_sec = 0; + tm->tm_min++; + if ((unsigned)tm->tm_min >= 60) { + tm->tm_min = 0; + tm->tm_hour++; + if ((unsigned)tm->tm_hour >= 24) { + tm->tm_hour = 0; + /* next day */ + tm->tm_wday++; + if ((unsigned)tm->tm_wday >= 7) + tm->tm_wday = 0; + days_in_month = get_days_in_month(tm->tm_mon, + tm->tm_year + 1900); + tm->tm_mday++; + if (tm->tm_mday < 1) { + tm->tm_mday = 1; + } else if (tm->tm_mday > days_in_month) { + tm->tm_mday = 1; + tm->tm_mon++; + if (tm->tm_mon >= 12) { + tm->tm_mon = 0; + tm->tm_year++; + } + } + } + } + } } + static void rtc_update_second(void *opaque) { RTCState *s = opaque; @@ -213,7 +280,7 @@ static void rtc_update_second(void *opaque) s->next_second_time += ticks_per_sec; qemu_mod_timer(s->second_timer, s->next_second_time); } else { - s->current_time++; + rtc_next_second(&s->current_tm); if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { /* update in progress bit */ @@ -232,10 +299,6 @@ static void rtc_update_second(void *opaque) static void rtc_update_second2(void *opaque) { RTCState *s = opaque; - time_t ti; - - ti = s->current_time; - rtc_set_date_buf(s, gmtime(&ti)); if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { rtc_copy_date(s); @@ -244,11 +307,11 @@ static void rtc_update_second2(void *opaque) /* check alarm */ if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 || - s->cmos_data[RTC_SECONDS_ALARM] == s->buf_data[RTC_SECONDS]) && + s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) && ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 || - s->cmos_data[RTC_MINUTES_ALARM] == s->buf_data[RTC_MINUTES]) && + s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) && ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || - s->cmos_data[RTC_HOURS_ALARM] == s->buf_data[RTC_HOURS])) { + s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) { s->cmos_data[RTC_REG_C] |= 0xa0; pic_set_irq(s->irq, 1); @@ -305,36 +368,6 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) } } -static void rtc_set_date_buf(RTCState *s, const struct tm *tm) -{ - s->buf_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); - s->buf_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); - if (s->cmos_data[RTC_REG_B] & 0x02) { - /* 24 hour format */ - s->buf_data[RTC_HOURS] = to_bcd(s, tm->tm_hour); - } else { - /* 12 hour format */ - s->buf_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12); - if (tm->tm_hour >= 12) - s->buf_data[RTC_HOURS] |= 0x80; - } - s->buf_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday); - s->buf_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday); - s->buf_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1); - s->buf_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100); -} - -static void rtc_copy_date(RTCState *s) -{ - s->cmos_data[RTC_SECONDS] = s->buf_data[RTC_SECONDS]; - s->cmos_data[RTC_MINUTES] = s->buf_data[RTC_MINUTES]; - s->cmos_data[RTC_HOURS] = s->buf_data[RTC_HOURS]; - s->cmos_data[RTC_DAY_OF_WEEK] = s->buf_data[RTC_DAY_OF_WEEK]; - s->cmos_data[RTC_DAY_OF_MONTH] = s->buf_data[RTC_DAY_OF_MONTH]; - s->cmos_data[RTC_MONTH] = s->buf_data[RTC_MONTH]; - s->cmos_data[RTC_YEAR] = s->buf_data[RTC_YEAR]; -} - void rtc_set_memory(RTCState *s, int addr, int val) { if (addr >= 0 && addr <= 127) @@ -343,8 +376,7 @@ void rtc_set_memory(RTCState *s, int addr, int val) void rtc_set_date(RTCState *s, const struct tm *tm) { - s->current_time = mktime((struct tm *)tm); - rtc_set_date_buf(s, tm); + s->current_tm = *tm; rtc_copy_date(s); } @@ -354,8 +386,14 @@ static void rtc_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, s->cmos_data, 128); qemu_put_8s(f, &s->cmos_index); - qemu_put_be32s(f, &s->current_time); - qemu_put_buffer(f, s->buf_data, 10); + + qemu_put_be32s(f, &s->current_tm.tm_sec); + qemu_put_be32s(f, &s->current_tm.tm_min); + qemu_put_be32s(f, &s->current_tm.tm_hour); + qemu_put_be32s(f, &s->current_tm.tm_wday); + qemu_put_be32s(f, &s->current_tm.tm_mday); + qemu_put_be32s(f, &s->current_tm.tm_mon); + qemu_put_be32s(f, &s->current_tm.tm_year); qemu_put_timer(f, s->periodic_timer); qemu_put_be64s(f, &s->next_periodic_time); @@ -374,8 +412,14 @@ static int rtc_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, s->cmos_data, 128); qemu_get_8s(f, &s->cmos_index); - qemu_get_be32s(f, &s->current_time); - qemu_get_buffer(f, s->buf_data, 10); + + qemu_get_be32s(f, &s->current_tm.tm_sec); + qemu_get_be32s(f, &s->current_tm.tm_min); + qemu_get_be32s(f, &s->current_tm.tm_hour); + qemu_get_be32s(f, &s->current_tm.tm_wday); + qemu_get_be32s(f, &s->current_tm.tm_mday); + qemu_get_be32s(f, &s->current_tm.tm_mon); + qemu_get_be32s(f, &s->current_tm.tm_year); qemu_get_timer(f, s->periodic_timer); qemu_get_be64s(f, &s->next_periodic_time); -- cgit v1.2.3 From 170c6f8705710229af47f0cc9640a6cc4a1a0a3a Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 12:53:17 +0000 Subject: header fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@873 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slirp/slirp.h b/slirp/slirp.h index 116748505..5b9cfdec8 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -16,6 +16,8 @@ # include #endif +#include + #ifdef NEED_TYPEDEFS typedef char int8_t; typedef unsigned char u_int8_t; -- cgit v1.2.3 From a4193c8a4bb36f64311d7d706e343ffabd9eb076 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 14:01:43 +0000 Subject: support for opaque data on memory I/Os git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@874 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 1 + exec.c | 52 +++++++++++++++++++++++------------------- hw/ppc.c | 12 +++++----- hw/ppc_chrp.c | 2 +- hw/ppc_prep.c | 26 ++++++++++----------- hw/vga.c | 66 +++++++++++++++++++++++++++--------------------------- softmmu_template.h | 20 ++++++++--------- 7 files changed, 93 insertions(+), 86 deletions(-) diff --git a/exec-all.h b/exec-all.h index 20c7d3ba3..8167d1a27 100644 --- a/exec-all.h +++ b/exec-all.h @@ -377,6 +377,7 @@ do {\ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; #ifdef __powerpc__ static inline int testandset (int *p) diff --git a/exec.c b/exec.c index 9a6d81a95..617dea13c 100644 --- a/exec.c +++ b/exec.c @@ -117,6 +117,7 @@ static unsigned int virt_valid_tag; /* io memory support */ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +void *io_mem_opaque[IO_MEM_NB_ENTRIES]; static int io_mem_nb; /* log support */ @@ -711,10 +712,13 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) PageDesc *p; int offset, b; #if 0 - if (cpu_single_env->cr[0] & CR0_PE_MASK) { - printf("modifying code at 0x%x size=%d EIP=%x\n", - (vaddr & TARGET_PAGE_MASK) | (start & ~TARGET_PAGE_MASK), len, - cpu_single_env->eip); + if (1) { + if (loglevel) { + fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", + cpu_single_env->mem_write_vaddr, len, + cpu_single_env->eip, + cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); + } } #endif p = page_find(start >> TARGET_PAGE_BITS); @@ -1799,12 +1803,12 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, } } -static uint32_t unassigned_mem_readb(target_phys_addr_t addr) +static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) { return 0; } -static void unassigned_mem_writeb(target_phys_addr_t addr, uint32_t val) +static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { } @@ -1823,7 +1827,7 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = { /* self modifying code support in soft mmu mode : writing to a page containing code comes to these functions */ -static void code_mem_writeb(target_phys_addr_t addr, uint32_t val) +static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; @@ -1835,7 +1839,7 @@ static void code_mem_writeb(target_phys_addr_t addr, uint32_t val) phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } -static void code_mem_writew(target_phys_addr_t addr, uint32_t val) +static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; @@ -1847,7 +1851,7 @@ static void code_mem_writew(target_phys_addr_t addr, uint32_t val) phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } -static void code_mem_writel(target_phys_addr_t addr, uint32_t val) +static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { unsigned long phys_addr; @@ -1871,19 +1875,19 @@ static CPUWriteMemoryFunc *code_mem_write[3] = { code_mem_writel, }; -static void notdirty_mem_writeb(target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { stb_raw((uint8_t *)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static void notdirty_mem_writew(target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { stw_raw((uint8_t *)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static void notdirty_mem_writel(target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { stl_raw((uint8_t *)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); @@ -1897,10 +1901,10 @@ static CPUWriteMemoryFunc *notdirty_mem_write[3] = { static void io_mem_init(void) { - cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write); - cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write); - cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write); - cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write); + cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL); + cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL); io_mem_nb = 5; /* alloc dirty bits array */ @@ -1915,7 +1919,8 @@ static void io_mem_init(void) cpu_register_physical_memory(). (-1) is returned if error. */ int cpu_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, - CPUWriteMemoryFunc **mem_write) + CPUWriteMemoryFunc **mem_write, + void *opaque) { int i; @@ -1932,6 +1937,7 @@ int cpu_register_io_memory(int io_index, io_mem_read[io_index][i] = mem_read[i]; io_mem_write[io_index][i] = mem_write[i]; } + io_mem_opaque[io_index] = opaque; return io_index << IO_MEM_SHIFT; } @@ -1994,17 +2000,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ val = ldl_raw(buf); - io_mem_write[io_index][2](addr, val); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { /* 16 bit read access */ val = lduw_raw(buf); - io_mem_write[io_index][1](addr, val); + io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); l = 2; } else { /* 8 bit access */ val = ldub_raw(buf); - io_mem_write[io_index][0](addr, val); + io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); l = 1; } } else { @@ -2025,17 +2031,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ - val = io_mem_read[io_index][2](addr); + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); stl_raw(buf, val); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { /* 16 bit read access */ - val = io_mem_read[io_index][1](addr); + val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr); stw_raw(buf, val); l = 2; } else { /* 8 bit access */ - val = io_mem_read[io_index][0](addr); + val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr); stb_raw(buf, val); l = 1; } diff --git a/hw/ppc.c b/hw/ppc.c index 7793cbd44..2c3912103 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -197,18 +197,18 @@ void cpu_ppc_reset (CPUState *env) } #endif -static void PPC_io_writeb (target_phys_addr_t addr, uint32_t value) +static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { cpu_outb(NULL, addr & 0xffff, value); } -static uint32_t PPC_io_readb (target_phys_addr_t addr) +static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr) { uint32_t ret = cpu_inb(NULL, addr & 0xffff); return ret; } -static void PPC_io_writew (target_phys_addr_t addr, uint32_t value) +static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef TARGET_WORDS_BIGENDIAN value = bswap16(value); @@ -216,7 +216,7 @@ static void PPC_io_writew (target_phys_addr_t addr, uint32_t value) cpu_outw(NULL, addr & 0xffff, value); } -static uint32_t PPC_io_readw (target_phys_addr_t addr) +static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr) { uint32_t ret = cpu_inw(NULL, addr & 0xffff); #ifdef TARGET_WORDS_BIGENDIAN @@ -225,7 +225,7 @@ static uint32_t PPC_io_readw (target_phys_addr_t addr) return ret; } -static void PPC_io_writel (target_phys_addr_t addr, uint32_t value) +static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); @@ -233,7 +233,7 @@ static void PPC_io_writel (target_phys_addr_t addr, uint32_t value) cpu_outl(NULL, addr & 0xffff, value); } -static uint32_t PPC_io_readl (target_phys_addr_t addr) +static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr) { uint32_t ret = cpu_inl(NULL, addr & 0xffff); diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 380fb6e53..d2ab1709c 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -64,7 +64,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pci_pmac_init(); /* Register 64 KB of ISA IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); // cpu_register_physical_memory(0xfe000000, 0xfe010000, PPC_io_memory); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 4a866ef5f..45b5853a6 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -98,7 +98,7 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) /* PCI intack register */ /* Read-only register (?) */ -static void _PPC_intack_write (target_phys_addr_t addr, uint32_t value) +static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value) { // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); } @@ -114,12 +114,12 @@ static inline uint32_t _PPC_intack_read (target_phys_addr_t addr) return retval; } -static uint32_t PPC_intack_readb (target_phys_addr_t addr) +static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr) { return _PPC_intack_read(addr); } -static uint32_t PPC_intack_readw (target_phys_addr_t addr) +static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr) { #ifdef TARGET_WORDS_BIGENDIAN return bswap16(_PPC_intack_read(addr)); @@ -128,7 +128,7 @@ static uint32_t PPC_intack_readw (target_phys_addr_t addr) #endif } -static uint32_t PPC_intack_readl (target_phys_addr_t addr) +static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr) { #ifdef TARGET_WORDS_BIGENDIAN return bswap32(_PPC_intack_read(addr)); @@ -177,12 +177,12 @@ static struct { } XCSR; #endif -static void PPC_XCSR_writeb (target_phys_addr_t addr, uint32_t value) +static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); } -static void PPC_XCSR_writew (target_phys_addr_t addr, uint32_t value) +static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef TARGET_WORDS_BIGENDIAN value = bswap16(value); @@ -190,7 +190,7 @@ static void PPC_XCSR_writew (target_phys_addr_t addr, uint32_t value) printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); } -static void PPC_XCSR_writel (target_phys_addr_t addr, uint32_t value) +static void PPC_XCSR_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); @@ -198,7 +198,7 @@ static void PPC_XCSR_writel (target_phys_addr_t addr, uint32_t value) printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); } -static uint32_t PPC_XCSR_readb (target_phys_addr_t addr) +static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr) { uint32_t retval = 0; @@ -207,7 +207,7 @@ static uint32_t PPC_XCSR_readb (target_phys_addr_t addr) return retval; } -static uint32_t PPC_XCSR_readw (target_phys_addr_t addr) +static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr) { uint32_t retval = 0; @@ -219,7 +219,7 @@ static uint32_t PPC_XCSR_readw (target_phys_addr_t addr) return retval; } -static uint32_t PPC_XCSR_readl (target_phys_addr_t addr) +static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr) { uint32_t retval = 0; @@ -480,7 +480,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, isa_mem_base = 0xc0000000; pci_prep_init(); /* Register 64 KB of ISA IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); cpu_register_physical_memory(0x80000000, 0x00010000, PPC_io_memory); /* init basic PC hardware */ @@ -525,10 +525,10 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl); /* PCI intack location */ PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read, - PPC_intack_write); + PPC_intack_write, NULL); cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); /* PowerPC control and status register group */ - PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write); + PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL); cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); diff --git a/hw/vga.c b/hw/vga.c index 30dead00d..8d8ad9baf 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -656,9 +656,9 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) #endif /* called for accesses between 0xa0000 and 0xc0000 */ -static uint32_t vga_mem_readb(target_phys_addr_t addr) +static uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) { - VGAState *s = &vga_state; + VGAState *s = opaque; int memory_map_mode, plane; uint32_t ret; @@ -712,40 +712,40 @@ static uint32_t vga_mem_readb(target_phys_addr_t addr) return ret; } -static uint32_t vga_mem_readw(target_phys_addr_t addr) +static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr) { uint32_t v; #ifdef TARGET_WORDS_BIGENDIAN - v = vga_mem_readb(addr) << 8; - v |= vga_mem_readb(addr + 1); + v = vga_mem_readb(opaque, addr) << 8; + v |= vga_mem_readb(opaque, addr + 1); #else - v = vga_mem_readb(addr); - v |= vga_mem_readb(addr + 1) << 8; + v = vga_mem_readb(opaque, addr); + v |= vga_mem_readb(opaque, addr + 1) << 8; #endif return v; } -static uint32_t vga_mem_readl(target_phys_addr_t addr) +static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr) { uint32_t v; #ifdef TARGET_WORDS_BIGENDIAN - v = vga_mem_readb(addr) << 24; - v |= vga_mem_readb(addr + 1) << 16; - v |= vga_mem_readb(addr + 2) << 8; - v |= vga_mem_readb(addr + 3); + v = vga_mem_readb(opaque, addr) << 24; + v |= vga_mem_readb(opaque, addr + 1) << 16; + v |= vga_mem_readb(opaque, addr + 2) << 8; + v |= vga_mem_readb(opaque, addr + 3); #else - v = vga_mem_readb(addr); - v |= vga_mem_readb(addr + 1) << 8; - v |= vga_mem_readb(addr + 2) << 16; - v |= vga_mem_readb(addr + 3) << 24; + v = vga_mem_readb(opaque, addr); + v |= vga_mem_readb(opaque, addr + 1) << 8; + v |= vga_mem_readb(opaque, addr + 2) << 16; + v |= vga_mem_readb(opaque, addr + 3) << 24; #endif return v; } /* called for accesses between 0xa0000 and 0xc0000 */ -static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val) +static void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { - VGAState *s = &vga_state; + VGAState *s = opaque; int memory_map_mode, plane, write_mode, b, func_select; uint32_t write_mask, bit_mask, set_mask; @@ -871,29 +871,29 @@ static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val) } } -static void vga_mem_writew(target_phys_addr_t addr, uint32_t val) +static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { #ifdef TARGET_WORDS_BIGENDIAN - vga_mem_writeb(addr, (val >> 8) & 0xff); - vga_mem_writeb(addr + 1, val & 0xff); + vga_mem_writeb(opaque, addr, (val >> 8) & 0xff); + vga_mem_writeb(opaque, addr + 1, val & 0xff); #else - vga_mem_writeb(addr, val & 0xff); - vga_mem_writeb(addr + 1, (val >> 8) & 0xff); + vga_mem_writeb(opaque, addr, val & 0xff); + vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); #endif } -static void vga_mem_writel(target_phys_addr_t addr, uint32_t val) +static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { #ifdef TARGET_WORDS_BIGENDIAN - vga_mem_writeb(addr, (val >> 24) & 0xff); - vga_mem_writeb(addr + 1, (val >> 16) & 0xff); - vga_mem_writeb(addr + 2, (val >> 8) & 0xff); - vga_mem_writeb(addr + 3, val & 0xff); + vga_mem_writeb(opaque, addr, (val >> 24) & 0xff); + vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); + vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); + vga_mem_writeb(opaque, addr + 3, val & 0xff); #else - vga_mem_writeb(addr, val & 0xff); - vga_mem_writeb(addr + 1, (val >> 8) & 0xff); - vga_mem_writeb(addr + 2, (val >> 16) & 0xff); - vga_mem_writeb(addr + 3, (val >> 24) & 0xff); + vga_mem_writeb(opaque, addr, val & 0xff); + vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); + vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); + vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); #endif } @@ -1826,7 +1826,7 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, #endif #endif /* CONFIG_BOCHS_VBE */ - vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write); + vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, vga_io_memory); diff --git a/softmmu_template.h b/softmmu_template.h index 413c5997b..73fdbecb3 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -55,14 +55,14 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); #if SHIFT <= 2 - res = io_mem_read[index][SHIFT](physaddr); + res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr); #else #ifdef TARGET_WORDS_BIGENDIAN - res = (uint64_t)io_mem_read[index][2](physaddr) << 32; - res |= io_mem_read[index][2](physaddr + 4); + res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32; + res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4); #else - res = io_mem_read[index][2](physaddr); - res |= (uint64_t)io_mem_read[index][2](physaddr + 4) << 32; + res = io_mem_read[index][2](io_mem_opaque[index], physaddr); + res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32; #endif #endif /* SHIFT > 2 */ return res; @@ -79,14 +79,14 @@ static inline void glue(io_write, SUFFIX)(unsigned long physaddr, env->mem_write_vaddr = tlb_addr; env->mem_write_pc = (unsigned long)retaddr; #if SHIFT <= 2 - io_mem_write[index][SHIFT](physaddr, val); + io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); #else #ifdef TARGET_WORDS_BIGENDIAN - io_mem_write[index][2](physaddr, val >> 32); - io_mem_write[index][2](physaddr + 4, val); + io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32); + io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val); #else - io_mem_write[index][2](physaddr, val); - io_mem_write[index][2](physaddr + 4, val >> 32); + io_mem_write[index][2](io_mem_opaque[index], physaddr, val); + io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32); #endif #endif /* SHIFT > 2 */ } -- cgit v1.2.3 From 89980284975679f8f338006eb8d2d8d4f19cd0fd Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 14:04:03 +0000 Subject: -localtime option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@875 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.c b/vl.c index 445066fa0..52f300f64 100644 --- a/vl.c +++ b/vl.c @@ -1930,6 +1930,7 @@ void help(void) "-m megs set virtual RAM size to megs MB [default=%d]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" "-enable-audio enable audio support\n" + "-localtime set the real time clock to local time [default=utc]\n" "\n" "Network options:\n" "-nics n simulate 'n' network cards [default=1]\n" -- cgit v1.2.3 From 8a8696a3c4c2bc977a202fc80890aa170ff70812 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 14:06:32 +0000 Subject: support for opaque data on memory I/Os - PCI ROM memory support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@876 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 121 +++++++++++++++++++++++++++++++++++++++------------------------ vl.h | 4 ++- 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 93d33d926..2d13dfc41 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -100,7 +100,7 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, { PCIIORegion *r; - if ((unsigned int)region_num >= 6) + if ((unsigned int)region_num >= PCI_NUM_REGIONS) return; r = &pci_dev->io_regions[region_num]; r->addr = -1; @@ -125,16 +125,21 @@ static void pci_update_mappings(PCIDevice *d) { PCIIORegion *r; int cmd, i; - uint32_t last_addr, new_addr; + uint32_t last_addr, new_addr, config_ofs; cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND)); - for(i = 0; i < 6; i++) { + for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; + if (i == PCI_ROM_SLOT) { + config_ofs = 0x30; + } else { + config_ofs = 0x10 + i * 4; + } if (r->size != 0) { if (r->type & PCI_ADDRESS_SPACE_IO) { if (cmd & PCI_COMMAND_IO) { new_addr = le32_to_cpu(*(uint32_t *)(d->config + - 0x10 + i * 4)); + config_ofs)); new_addr = new_addr & ~(r->size - 1); last_addr = new_addr + r->size - 1; /* NOTE: we have only 64K ioports on PC */ @@ -148,7 +153,10 @@ static void pci_update_mappings(PCIDevice *d) } else { if (cmd & PCI_COMMAND_MEMORY) { new_addr = le32_to_cpu(*(uint32_t *)(d->config + - 0x10 + i * 4)); + config_ofs)); + /* the ROM slot has a specific enable bit */ + if (i == PCI_ROM_SLOT && !(new_addr & 1)) + goto no_mem_map; new_addr = new_addr & ~(r->size - 1); last_addr = new_addr + r->size - 1; /* NOTE: we do not support wrapping */ @@ -160,6 +168,7 @@ static void pci_update_mappings(PCIDevice *d) new_addr = -1; } } else { + no_mem_map: new_addr = -1; } } @@ -216,18 +225,28 @@ void pci_default_write_config(PCIDevice *d, int can_write, i; uint32_t end, addr; - if (len == 4 && (address >= 0x10 && address < 0x10 + 4 * 6)) { + if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || + (address >= 0x30 && address < 0x34))) { PCIIORegion *r; int reg; - reg = (address - 0x10) >> 2; + if ( address >= 0x30 ) { + reg = PCI_ROM_SLOT; + }else{ + reg = (address - 0x10) >> 2; + } r = &d->io_regions[reg]; if (r->size == 0) goto default_config; /* compute the stored value */ - val &= ~(r->size - 1); - val |= r->type; - *(uint32_t *)(d->config + 0x10 + reg * 4) = cpu_to_le32(val); + if (reg == PCI_ROM_SLOT) { + /* keep ROM enable bit */ + val &= (~(r->size - 1)) | 1; + } else { + val &= ~(r->size - 1); + val |= r->type; + } + *(uint32_t *)(d->config + address) = cpu_to_le32(val); pci_update_mappings(d); return; } @@ -484,16 +503,16 @@ static inline void set_config(PCIBridge *s, target_phys_addr_t addr) s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8); } -static void PPC_PCIIO_writeb (target_phys_addr_t addr, uint32_t val) +static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; set_config(s, addr); pci_data_write(s, addr, val, 1); } -static void PPC_PCIIO_writew (target_phys_addr_t addr, uint32_t val) +static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; set_config(s, addr); #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); @@ -501,9 +520,9 @@ static void PPC_PCIIO_writew (target_phys_addr_t addr, uint32_t val) pci_data_write(s, addr, val, 2); } -static void PPC_PCIIO_writel (target_phys_addr_t addr, uint32_t val) +static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; set_config(s, addr); #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); @@ -511,18 +530,18 @@ static void PPC_PCIIO_writel (target_phys_addr_t addr, uint32_t val) pci_data_write(s, addr, val, 4); } -static uint32_t PPC_PCIIO_readb (target_phys_addr_t addr) +static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; uint32_t val; set_config(s, addr); val = pci_data_read(s, addr, 1); return val; } -static uint32_t PPC_PCIIO_readw (target_phys_addr_t addr) +static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; uint32_t val; set_config(s, addr); val = pci_data_read(s, addr, 2); @@ -532,9 +551,9 @@ static uint32_t PPC_PCIIO_readw (target_phys_addr_t addr) return val; } -static uint32_t PPC_PCIIO_readl (target_phys_addr_t addr) +static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; uint32_t val; set_config(s, addr); val = pci_data_read(s, addr, 4); @@ -558,10 +577,12 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = { void pci_prep_init(void) { + PCIBridge *s = &pci_bridge; PCIDevice *d; int PPC_io_memory; - PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, PPC_PCIIO_write); + PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, + PPC_PCIIO_write, s); cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); d = pci_register_device("PREP PCI Bridge", sizeof(PCIDevice), 0, 0, @@ -581,18 +602,18 @@ void pci_prep_init(void) /* pmac pci init */ -static void pci_pmac_config_writel (target_phys_addr_t addr, uint32_t val) +static void pci_pmac_config_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif s->config_reg = val; } -static uint32_t pci_pmac_config_readl (target_phys_addr_t addr) +static uint32_t pci_pmac_config_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; uint32_t val; val = s->config_reg; @@ -614,41 +635,41 @@ static CPUReadMemoryFunc *pci_pmac_config_read[] = { &pci_pmac_config_readl, }; -static void pci_pmac_writeb (target_phys_addr_t addr, uint32_t val) +static void pci_pmac_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; pci_data_write(s, addr, val, 1); } -static void pci_pmac_writew (target_phys_addr_t addr, uint32_t val) +static void pci_pmac_writew (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); #endif pci_data_write(s, addr, val, 2); } -static void pci_pmac_writel (target_phys_addr_t addr, uint32_t val) +static void pci_pmac_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif pci_data_write(s, addr, val, 4); } -static uint32_t pci_pmac_readb (target_phys_addr_t addr) +static uint32_t pci_pmac_readb (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; uint32_t val; val = pci_data_read(s, addr, 1); return val; } -static uint32_t pci_pmac_readw (target_phys_addr_t addr) +static uint32_t pci_pmac_readw (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; uint32_t val; val = pci_data_read(s, addr, 2); #ifdef TARGET_WORDS_BIGENDIAN @@ -657,9 +678,9 @@ static uint32_t pci_pmac_readw (target_phys_addr_t addr) return val; } -static uint32_t pci_pmac_readl (target_phys_addr_t addr) +static uint32_t pci_pmac_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = opaque; uint32_t val; val = pci_data_read(s, addr, 4); @@ -683,12 +704,13 @@ static CPUReadMemoryFunc *pci_pmac_read[] = { void pci_pmac_init(void) { + PCIBridge *s = &pci_bridge; PCIDevice *d; int pci_mem_config, pci_mem_data; pci_mem_config = cpu_register_io_memory(0, pci_pmac_config_read, - pci_pmac_config_write); - pci_mem_data = cpu_register_io_memory(0, pci_pmac_read, pci_pmac_write); + pci_pmac_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_pmac_read, pci_pmac_write, s); cpu_register_physical_memory(0xfec00000, 0x1000, pci_mem_config); cpu_register_physical_memory(0xfee00000, 0x1000, pci_mem_data); @@ -812,7 +834,7 @@ static void pci_info_device(PCIDevice *d) if (d->config[PCI_INTERRUPT_PIN] != 0) { printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); } - for(i = 0;i < 6; i++) { + for(i = 0;i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; if (r->size != 0) { printf(" BAR%d: ", i); @@ -934,13 +956,22 @@ static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) { PCIIORegion *r; uint16_t cmd; + uint32_t ofs; + + if ( region_num == PCI_ROM_SLOT ) { + ofs = 0x30; + }else{ + ofs = 0x10 + region_num * 4; + } - pci_config_writel(d, 0x10 + region_num * 4, addr); + pci_config_writel(d, ofs, addr); r = &d->io_regions[region_num]; /* enable memory mappings */ cmd = pci_config_readw(d, PCI_COMMAND); - if (r->type & PCI_ADDRESS_SPACE_IO) + if ( region_num == PCI_ROM_SLOT ) + cmd |= 2; + else if (r->type & PCI_ADDRESS_SPACE_IO) cmd |= 1; else cmd |= 2; @@ -977,7 +1008,7 @@ static void pci_bios_init_device(PCIDevice *d) break; default: /* default memory mappings */ - for(i = 0; i < 6; i++) { + for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; if (r->size) { if (r->type & PCI_ADDRESS_SPACE_IO) diff --git a/vl.h b/vl.h index 54f6cdd29..e8f8a30a7 100644 --- a/vl.h +++ b/vl.h @@ -391,6 +391,8 @@ typedef struct PCIIORegion { PCIMapIORegionFunc *map_func; } PCIIORegion; +#define PCI_ROM_SLOT 6 +#define PCI_NUM_REGIONS 7 struct PCIDevice { /* PCI config space */ uint8_t config[256]; @@ -399,7 +401,7 @@ struct PCIDevice { int bus_num; int devfn; char name[64]; - PCIIORegion io_regions[6]; + PCIIORegion io_regions[PCI_NUM_REGIONS]; /* do not access the following fields */ PCIConfigReadFunc *config_read; -- cgit v1.2.3 From 7727994d21eea75859df8f2fcfa7163a1d6f64e4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 14:08:36 +0000 Subject: support for opaque data on memory I/Os git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@877 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index bb6e74a3f..eec101c7b 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -681,15 +681,16 @@ extern uint8_t *phys_ram_dirty; #define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */ #define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ -typedef void CPUWriteMemoryFunc(target_phys_addr_t addr, uint32_t value); -typedef uint32_t CPUReadMemoryFunc(target_phys_addr_t addr); +typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); +typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long size, unsigned long phys_offset); int cpu_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, - CPUWriteMemoryFunc **mem_write); + CPUWriteMemoryFunc **mem_write, + void *opaque); void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write); -- cgit v1.2.3 From 1f62d9383f9236cd9cf8f017371800cdfe56a195 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 16:40:20 +0000 Subject: fixed PCI config default write permissions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@878 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 2d13dfc41..d5b8d4f44 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -255,21 +255,49 @@ void pci_default_write_config(PCIDevice *d, addr = address; for(i = 0; i < len; i++) { /* default read/write accesses */ - switch(addr) { + switch(d->config[0x0e]) { case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0e: - case 0x3d: - can_write = 0; + case 0x80: + switch(addr) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0e: + case 0x10 ... 0x27: /* base */ + case 0x30 ... 0x33: /* rom */ + case 0x3d: + can_write = 0; + break; + default: + can_write = 1; + break; + } break; default: - can_write = 1; + case 0x01: + switch(addr) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0e: + case 0x38 ... 0x3b: /* rom */ + case 0x3d: + can_write = 0; + break; + default: + can_write = 1; + break; + } break; } if (can_write) { @@ -986,10 +1014,10 @@ static void pci_bios_init_device(PCIDevice *d) int i, pin, pic_irq, vendor_id, device_id; class = pci_config_readw(d, PCI_CLASS_DEVICE); + vendor_id = pci_config_readw(d, PCI_VENDOR_ID); + device_id = pci_config_readw(d, PCI_DEVICE_ID); switch(class) { case 0x0101: - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); if (vendor_id == 0x8086 && device_id == 0x7010) { /* PIIX3 IDE */ pci_config_writew(d, PCI_COMMAND, PCI_COMMAND_IO); @@ -1006,6 +1034,12 @@ static void pci_bios_init_device(PCIDevice *d) /* VGA: map frame buffer to default Bochs VBE address */ pci_set_io_region_addr(d, 0, 0xE0000000); break; + case 0xff00: + if (vendor_id == 0x0106b && device_id == 0x0017) { + /* macio bridge */ + pci_set_io_region_addr(d, 0, 0x80800000); + } + break; default: /* default memory mappings */ for(i = 0; i < PCI_NUM_REGIONS; i++) { -- cgit v1.2.3 From caf9a12e9ad9cdd89e9b13a01b359673f25b6313 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 18:35:40 +0000 Subject: CUDA + ADB support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@879 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 51c17e522..1d73b3b69 100644 --- a/Makefile.target +++ b/Makefile.target @@ -245,7 +245,7 @@ VL_OBJS+= ppc.o # PREP hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o -VL_OBJS+= ppc_prep.o ppc_chrp.o +VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o -- cgit v1.2.3 From 63066f4f13b024ac0a45486f06dafbbf944fe4c6 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 18:45:02 +0000 Subject: hid event handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@880 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 12 ++++++++---- vl.c | 35 +++++++++++++++++++++++++++++++++++ vl.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 93 insertions(+), 11 deletions(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index ee83e0f77..8b809bd82 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -190,9 +190,9 @@ static void kbd_queue(KBDState *s, int b, int aux) kbd_update_irq(s); } -void kbd_put_keycode(int keycode) +static void pc_kbd_put_keycode(void *opaque, int keycode) { - KBDState *s = &kbd_state; + KBDState *s = opaque; kbd_queue(s, keycode, 0); } @@ -434,9 +434,10 @@ static void kbd_mouse_send_packet(KBDState *s) s->mouse_dz -= dz1; } -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) +static void pc_kbd_mouse_event(void *opaque, + int dx, int dy, int dz, int buttons_state) { - KBDState *s = &kbd_state; + KBDState *s = opaque; /* check if deltas are recorded when disabled */ if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) @@ -652,4 +653,7 @@ void kbd_init(void) register_ioport_write(0x60, 1, 1, kbd_write_data, s); register_ioport_read(0x64, 1, 1, kbd_read_status, s); register_ioport_write(0x64, 1, 1, kbd_write_command, s); + + qemu_add_kbd_event_handler(pc_kbd_put_keycode, s); + qemu_add_mouse_event_handler(pc_kbd_mouse_event, s); } diff --git a/vl.c b/vl.c index 52f300f64..b424ed11e 100644 --- a/vl.c +++ b/vl.c @@ -384,6 +384,41 @@ void hw_error(const char *fmt, ...) abort(); } +/***********************************************************/ +/* keyboard/mouse */ + +static QEMUPutKBDEvent *qemu_put_kbd_event; +static void *qemu_put_kbd_event_opaque; +static QEMUPutMouseEvent *qemu_put_mouse_event; +static void *qemu_put_mouse_event_opaque; + +void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) +{ + qemu_put_kbd_event_opaque = opaque; + qemu_put_kbd_event = func; +} + +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque) +{ + qemu_put_mouse_event_opaque = opaque; + qemu_put_mouse_event = func; +} + +void kbd_put_keycode(int keycode) +{ + if (qemu_put_kbd_event) { + qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode); + } +} + +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) +{ + if (qemu_put_mouse_event) { + qemu_put_mouse_event(qemu_put_mouse_event_opaque, + dx, dy, dz, buttons_state); + } +} + /***********************************************************/ /* timers */ diff --git a/vl.h b/vl.h index e8f8a30a7..9dbb5b41a 100644 --- a/vl.h +++ b/vl.h @@ -179,6 +179,21 @@ extern int rtc_utc; #define BIOS_SIZE 0 #endif +/* keyboard/mouse support */ + +#define MOUSE_EVENT_LBUTTON 0x01 +#define MOUSE_EVENT_RBUTTON 0x02 +#define MOUSE_EVENT_MBUTTON 0x04 + +typedef void QEMUPutKBDEvent(void *opaque, int keycode); +typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); + +void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque); + +void kbd_put_keycode(int keycode); +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); + /* async I/O support */ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); @@ -530,13 +545,6 @@ void pci_ne2000_init(NetDriverState *nd); /* pckbd.c */ -void kbd_put_keycode(int keycode); - -#define MOUSE_EVENT_LBUTTON 0x01 -#define MOUSE_EVENT_RBUTTON 0x02 -#define MOUSE_EVENT_MBUTTON 0x04 -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); - void kbd_init(void); /* mc146818rtc.c */ @@ -627,6 +635,41 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, uint32_t initrd_image, uint32_t initrd_size, uint32_t NVRAM_image); +/* adb.c */ + +#define MAX_ADB_DEVICES 16 + +typedef struct ADBDevice ADBDevice; + +typedef void ADBDeviceReceivePacket(ADBDevice *d, const uint8_t *buf, int len); + +struct ADBDevice { + struct ADBBusState *bus; + int devaddr; + int handler; + ADBDeviceReceivePacket *receive_packet; + void *opaque; +}; + +typedef struct ADBBusState { + ADBDevice devices[MAX_ADB_DEVICES]; + int nb_devices; +} ADBBusState; + +void adb_receive_packet(ADBBusState *s, const uint8_t *buf, int len); +void adb_send_packet(ADBBusState *s, const uint8_t *buf, int len); + +ADBDevice *adb_register_device(ADBBusState *s, int devaddr, + ADBDeviceReceivePacket *receive_packet, + void *opaque); +void adb_kbd_init(ADBBusState *bus); +void adb_mouse_init(ADBBusState *bus); + +/* cuda.c */ + +extern ADBBusState adb_bus; +int cuda_init(void); + /* monitor.c */ void monitor_init(void); void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -- cgit v1.2.3 From 267002cd28318c6ca246205c9b8c42c3cca48960 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 18:46:20 +0000 Subject: CUDA + ADB support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@881 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adb.c | 308 +++++++++++++++++++++++++++++++++++ hw/cuda.c | 507 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/ppc_chrp.c | 88 +++++++++- 3 files changed, 902 insertions(+), 1 deletion(-) create mode 100644 hw/adb.c create mode 100644 hw/cuda.c diff --git a/hw/adb.c b/hw/adb.c new file mode 100644 index 000000000..6442d796b --- /dev/null +++ b/hw/adb.c @@ -0,0 +1,308 @@ +/* + * QEMU ADB support + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* ADB commands */ +#define ADB_BUSRESET 0x00 +#define ADB_FLUSH 0x01 +#define ADB_WRITEREG 0x08 +#define ADB_READREG 0x0c + +/* ADB device commands */ +#define ADB_CMD_SELF_TEST 0xff +#define ADB_CMD_CHANGE_ID 0xfe +#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd +#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00 + +/* ADB default device IDs (upper 4 bits of ADB command byte) */ +#define ADB_DONGLE 1 +#define ADB_KEYBOARD 2 +#define ADB_MOUSE 3 +#define ADB_TABLET 4 +#define ADB_MODEM 5 +#define ADB_MISC 7 + +#define ADB_RET_OK 0 +#define ADB_RET_INUSE 1 +#define ADB_RET_NOTPRESENT 2 +#define ADB_RET_TIMEOUT 3 +#define ADB_RET_UNEXPECTED_RESULT 4 +#define ADB_RET_REQUEST_ERROR 5 +#define ADB_RET_BUS_ERROR 6 + + +static void adb_send_packet1(ADBBusState *s, uint8_t reply) +{ + adb_send_packet(s, &reply, 1); +} + +void adb_receive_packet(ADBBusState *s, const uint8_t *buf, int len) +{ + ADBDevice *d; + int devaddr, cmd, i; + uint8_t obuf[4]; + + cmd = buf[1] & 0xf; + devaddr = buf[1] >> 4; + if (buf[1] == ADB_BUSRESET) { + obuf[0] = 0x00; + obuf[1] = 0x00; + adb_send_packet(s, obuf, 2); + return; + } + if (cmd == ADB_FLUSH) { + obuf[0] = 0x00; + obuf[1] = 0x00; + adb_send_packet(s, obuf, 2); + return; + } + + for(i = 0; i < s->nb_devices; i++) { + d = &s->devices[i]; + if (d->devaddr == devaddr) { + d->receive_packet(d, buf, len); + return; + } + } + adb_send_packet1(s, ADB_RET_NOTPRESENT); +} + +ADBDevice *adb_register_device(ADBBusState *s, int devaddr, + ADBDeviceReceivePacket *receive_packet, + void *opaque) +{ + ADBDevice *d; + if (s->nb_devices >= MAX_ADB_DEVICES) + return NULL; + d = &s->devices[s->nb_devices++]; + d->bus = s; + d->devaddr = devaddr; + d->receive_packet = receive_packet; + d->opaque = opaque; + return d; +} + +/***************************************************************/ +/* Keyboard ADB device */ + +static const uint8_t pc_to_adb_keycode[256] = { + 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, + 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, + 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, + 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, + 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, + 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, + 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117, + 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 95, 55, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static void adb_kbd_put_keycode(void *opaque, int keycode) +{ + static int ext_keycode; + ADBDevice *d = opaque; + uint8_t buf[4]; + int adb_keycode; + + if (keycode == 0xe0) { + ext_keycode = 1; + } else { + + if (ext_keycode) + adb_keycode = pc_to_adb_keycode[keycode | 0x80]; + else + adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; + + buf[0] = 0x40; + buf[1] = (d->devaddr << 4) | 0x0c; + buf[2] = adb_keycode | (keycode & 0x80); + buf[3] = 0xff; + adb_send_packet(d->bus, buf, 4); + ext_keycode = 0; + } +} + +static void adb_kbd_receive_packet(ADBDevice *d, const uint8_t *buf, int len) +{ + int cmd, reg; + uint8_t obuf[4]; + + cmd = buf[0] & 0xc; + reg = buf[0] & 0x3; + switch(cmd) { + case ADB_WRITEREG: + switch(reg) { + case 2: + /* LED status */ + adb_send_packet1(d->bus, ADB_RET_OK); + break; + case 3: + switch(buf[2]) { + case ADB_CMD_SELF_TEST: + adb_send_packet1(d->bus, ADB_RET_OK); + break; + case ADB_CMD_CHANGE_ID: + case ADB_CMD_CHANGE_ID_AND_ACT: + case ADB_CMD_CHANGE_ID_AND_ENABLE: + d->devaddr = buf[1] & 0xf; + adb_send_packet1(d->bus, ADB_RET_OK); + break; + default: + /* XXX: check this */ + d->devaddr = buf[1] & 0xf; + d->handler = buf[2]; + adb_send_packet1(d->bus, ADB_RET_OK); + break; + } + } + break; + case ADB_READREG: + switch(reg) { + case 1: + adb_send_packet1(d->bus, ADB_RET_OK); + break; + case 2: + obuf[0] = ADB_RET_OK; + obuf[1] = 0x00; /* XXX: check this */ + obuf[2] = 0x07; /* led status */ + adb_send_packet(d->bus, obuf, 3); + break; + case 3: + obuf[0] = ADB_RET_OK; + obuf[1] = d->handler; + obuf[2] = d->devaddr; + adb_send_packet(d->bus, obuf, 3); + break; + } + break; + } +} + +void adb_kbd_init(ADBBusState *bus) +{ + ADBDevice *d; + + d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_receive_packet, NULL); + qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); +} + +/***************************************************************/ +/* Mouse ADB device */ + +static void adb_mouse_event(void *opaque, + int dx1, int dy1, int dz1, int buttons_state) +{ + ADBDevice *d = opaque; + uint8_t buf[4]; + int dx, dy; + + dx = dx1; + if (dx < -63) + dx = -63; + else if (dx > 63) + dx = 63; + + dy = dy1; + if (dy < -63) + dy = -63; + else if (dy > 63) + dy = 63; + + dx &= 0x7f; + dy &= 0x7f; + + if (buttons_state & MOUSE_EVENT_LBUTTON) + dy |= 0x80; + if (buttons_state & MOUSE_EVENT_RBUTTON) + dx |= 0x80; + + buf[0] = 0x40; + buf[1] = (d->devaddr << 4) | 0x0c; + buf[2] = dy; + buf[3] = dx; + adb_send_packet(d->bus, buf, 4); +} + +static void adb_mouse_receive_packet(ADBDevice *d, const uint8_t *buf, int len) +{ + int cmd, reg; + uint8_t obuf[4]; + + cmd = buf[0] & 0xc; + reg = buf[0] & 0x3; + switch(cmd) { + case ADB_WRITEREG: + switch(reg) { + case 2: + adb_send_packet1(d->bus, ADB_RET_OK); + break; + case 3: + switch(buf[2]) { + case ADB_CMD_SELF_TEST: + adb_send_packet1(d->bus, ADB_RET_OK); + break; + case ADB_CMD_CHANGE_ID: + case ADB_CMD_CHANGE_ID_AND_ACT: + case ADB_CMD_CHANGE_ID_AND_ENABLE: + d->devaddr = buf[1] & 0xf; + adb_send_packet1(d->bus, ADB_RET_OK); + break; + default: + /* XXX: check this */ + d->devaddr = buf[1] & 0xf; + adb_send_packet1(d->bus, ADB_RET_OK); + break; + } + } + break; + case ADB_READREG: + switch(reg) { + case 1: + adb_send_packet1(d->bus, ADB_RET_OK); + break; + case 3: + obuf[0] = ADB_RET_OK; + obuf[1] = d->handler; + obuf[2] = d->devaddr; + adb_send_packet(d->bus, obuf, 3); + break; + } + break; + } +} + +void adb_mouse_init(ADBBusState *bus) +{ + ADBDevice *d; + + d = adb_register_device(bus, ADB_MOUSE, adb_mouse_receive_packet, NULL); + qemu_add_mouse_event_handler(adb_mouse_event, d); +} diff --git a/hw/cuda.c b/hw/cuda.c new file mode 100644 index 000000000..a75de834e --- /dev/null +++ b/hw/cuda.c @@ -0,0 +1,507 @@ +/* + * QEMU CUDA support + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* Bits in B data register: all active low */ +#define TREQ 0x08 /* Transfer request (input) */ +#define TACK 0x10 /* Transfer acknowledge (output) */ +#define TIP 0x20 /* Transfer in progress (output) */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#define SR_EXT 0x0c /* Shift on external clock */ +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET 0x80 /* set bits in IER */ +#define IER_CLR 0 /* clear bits in IER */ +#define SR_INT 0x04 /* Shift register full/empty */ +#define T1_INT 0x40 /* Timer 1 interrupt */ + +/* Bits in ACR */ +#define T1MODE 0xc0 /* Timer 1 mode */ +#define T1MODE_CONT 0x40 /* continuous interrupts */ + +/* commands (1st byte) */ +#define ADB_PACKET 0 +#define CUDA_PACKET 1 +#define ERROR_PACKET 2 +#define TIMER_PACKET 3 +#define POWER_PACKET 4 +#define MACIIC_PACKET 5 +#define PMU_PACKET 6 + + +/* CUDA commands (2nd byte) */ +#define CUDA_WARM_START 0x0 +#define CUDA_AUTOPOLL 0x1 +#define CUDA_GET_6805_ADDR 0x2 +#define CUDA_GET_TIME 0x3 +#define CUDA_GET_PRAM 0x7 +#define CUDA_SET_6805_ADDR 0x8 +#define CUDA_SET_TIME 0x9 +#define CUDA_POWERDOWN 0xa +#define CUDA_POWERUP_TIME 0xb +#define CUDA_SET_PRAM 0xc +#define CUDA_MS_RESET 0xd +#define CUDA_SEND_DFAC 0xe +#define CUDA_BATTERY_SWAP_SENSE 0x10 +#define CUDA_RESET_SYSTEM 0x11 +#define CUDA_SET_IPL 0x12 +#define CUDA_FILE_SERVER_FLAG 0x13 +#define CUDA_SET_AUTO_RATE 0x14 +#define CUDA_GET_AUTO_RATE 0x16 +#define CUDA_SET_DEVICE_LIST 0x19 +#define CUDA_GET_DEVICE_LIST 0x1a +#define CUDA_SET_ONE_SECOND_MODE 0x1b +#define CUDA_SET_POWER_MESSAGES 0x21 +#define CUDA_GET_SET_IIC 0x22 +#define CUDA_WAKEUP 0x23 +#define CUDA_TIMER_TICKLE 0x24 +#define CUDA_COMBINED_FORMAT_IIC 0x25 + +#define CUDA_TIMER_FREQ (4700000 / 6) + +typedef struct CUDATimer { + unsigned int latch; + uint16_t counter_value; /* counter value at load time */ + int64_t load_time; + int64_t next_irq_time; + QEMUTimer *timer; +} CUDATimer; + +typedef struct CUDAState { + /* cuda registers */ + uint8_t b; /* B-side data */ + uint8_t a; /* A-side data */ + uint8_t dirb; /* B-side direction (1=output) */ + uint8_t dira; /* A-side direction (1=output) */ + uint8_t sr; /* Shift register */ + uint8_t acr; /* Auxiliary control register */ + uint8_t pcr; /* Peripheral control register */ + uint8_t ifr; /* Interrupt flag register */ + uint8_t ier; /* Interrupt enable register */ + uint8_t anh; /* A-side data, no handshake */ + + CUDATimer timers[2]; + + uint8_t last_b; /* last value of B register */ + uint8_t last_acr; /* last value of B register */ + + int data_in_size; + int data_in_index; + int data_out_index; + + int irq; + uint8_t autopoll; + uint8_t data_in[128]; + uint8_t data_out[16]; +} CUDAState; + +static CUDAState cuda_state; +ADBBusState adb_bus; + +static void cuda_update(CUDAState *s); +static void cuda_receive_packet_from_host(CUDAState *s, + const uint8_t *data, int len); + +static void cuda_update_irq(CUDAState *s) +{ + if (s->ifr & s->ier & SR_INT) { + pic_set_irq(s->irq, 1); + } else { + pic_set_irq(s->irq, 0); + } +} + +static unsigned int get_counter(CUDATimer *s) +{ + int64_t d; + unsigned int counter; + + d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, + CUDA_TIMER_FREQ, ticks_per_sec); + if (d <= s->counter_value) { + counter = d; + } else { + counter = s->latch - 1 - ((d - s->counter_value) % s->latch); + } + return counter; +} + +static void set_counter(CUDATimer *s, unsigned int val) +{ + s->load_time = qemu_get_clock(vm_clock); + s->counter_value = val; +} + +static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) +{ + int64_t d, next_time, base; + /* current counter value */ + d = muldiv64(current_time - s->load_time, + CUDA_TIMER_FREQ, ticks_per_sec); + if (d <= s->counter_value) { + next_time = s->counter_value + 1; + } else { + base = ((d - s->counter_value) % s->latch); + base = (base * s->latch) + s->counter_value; + next_time = base + s->latch; + } + next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + + s->load_time; + if (next_time <= current_time) + next_time = current_time + 1; + return next_time; +} + +static void cuda_timer1(void *opaque) +{ + CUDAState *s = opaque; + CUDATimer *ti = &s->timers[0]; + + ti->next_irq_time = get_next_irq_time(ti, ti->next_irq_time); + qemu_mod_timer(ti->timer, ti->next_irq_time); + s->ifr |= T1_INT; + cuda_update_irq(s); +} + +static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) +{ + CUDAState *s = opaque; + uint32_t val; + + addr = (addr >> 9) & 0xf; + switch(addr) { + case 0: + val = s->b; + break; + case 1: + val = s->a; + break; + case 2: + val = s->dirb; + break; + case 3: + val = s->dira; + break; + case 4: + val = get_counter(&s->timers[0]) & 0xff; + s->ifr &= ~T1_INT; + cuda_update_irq(s); + break; + case 5: + val = get_counter(&s->timers[0]) >> 8; + s->ifr &= ~T1_INT; + cuda_update_irq(s); + break; + case 6: + val = s->timers[0].latch & 0xff; + break; + case 7: + val = (s->timers[0].latch >> 8) & 0xff; + break; + case 8: + val = get_counter(&s->timers[1]) & 0xff; + break; + case 9: + val = get_counter(&s->timers[1]) >> 8; + break; + case 10: + if (s->data_in_index < s->data_in_size) { + val = s->data_in[s->data_in_index]; + } else { + val = 0; + } + break; + case 11: + val = s->acr; + break; + case 12: + val = s->pcr; + break; + case 13: + val = s->ifr; + break; + case 14: + val = s->ier; + break; + default: + case 15: + val = s->anh; + break; + } +#ifdef DEBUG_CUDA + printf("cuda: read: reg=0x%x val=%02x\n", addr, val); +#endif + return val; +} + +static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + CUDAState *s = opaque; + + addr = (addr >> 9) & 0xf; +#ifdef DEBUG_CUDA + printf("cuda: write: reg=0x%x val=%02x\n", addr, val); +#endif + + switch(addr) { + case 0: + s->b = val; + cuda_update(s); + break; + case 1: + s->a = val; + break; + case 2: + s->dirb = val; + break; + case 3: + s->dira = val; + break; + case 4: + val = val | (get_counter(&s->timers[0]) & 0xff00); + set_counter(&s->timers[0], val); + break; + case 5: + val = (val << 8) | (get_counter(&s->timers[0]) & 0xff); + set_counter(&s->timers[0], val); + break; + case 6: + s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; + break; + case 7: + s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); + break; + case 8: + val = val | (get_counter(&s->timers[1]) & 0xff00); + set_counter(&s->timers[1], val); + break; + case 9: + val = (val << 8) | (get_counter(&s->timers[1]) & 0xff); + set_counter(&s->timers[1], val); + break; + case 10: + s->sr = val; + break; + case 11: + s->acr = val; + if ((s->acr & T1MODE) == T1MODE_CONT) { + if ((s->last_acr & T1MODE) != T1MODE_CONT) { + CUDATimer *ti = &s->timers[0]; + /* activate timer interrupt */ + ti->next_irq_time = get_next_irq_time(ti, qemu_get_clock(vm_clock)); + qemu_mod_timer(ti->timer, ti->next_irq_time); + } + } else { + if ((s->last_acr & T1MODE) == T1MODE_CONT) { + CUDATimer *ti = &s->timers[0]; + qemu_del_timer(ti->timer); + } + } + cuda_update(s); + break; + case 12: + s->pcr = val; + break; + case 13: + /* reset bits */ + s->ifr &= ~val; + cuda_update_irq(s); + break; + case 14: + if (val & IER_SET) { + /* set bits */ + s->ier |= val & 0x7f; + } else { + /* reset bits */ + s->ier &= ~val; + } + cuda_update_irq(s); + break; + default: + case 15: + s->anh = val; + break; + } +} + +/* NOTE: TIP and TREQ are negated */ +static void cuda_update(CUDAState *s) +{ + if (s->data_in_index < s->data_in_size) { + /* data input */ + if (!(s->b & TIP) && + (s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { + s->sr = s->data_in[s->data_in_index++]; + s->ifr |= SR_INT; + cuda_update_irq(s); + } + } + if (s->data_in_index < s->data_in_size) { + /* there is some data to read */ + s->b = (s->b & ~TREQ); + } else { + s->b = (s->b | TREQ); + } + + if (s->acr & SR_OUT) { + /* data output */ + if (!(s->b & TIP) && + (s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { + if (s->data_out_index < sizeof(s->data_out)) { + s->data_out[s->data_out_index++] = s->sr; + } + s->ifr |= SR_INT; + cuda_update_irq(s); + } + } + + /* check end of data output */ + if (!(s->acr & SR_OUT) && (s->last_acr & SR_OUT)) { + if (s->data_out_index > 0) + cuda_receive_packet_from_host(s, s->data_out, s->data_out_index); + s->data_out_index = 0; + } + s->last_acr = s->acr; + s->last_b = s->b; +} + +static void cuda_send_packet_to_host(CUDAState *s, + const uint8_t *data, int len) +{ + memcpy(s->data_in, data, len); + s->data_in_size = len; + s->data_in_index = 0; + cuda_update(s); + s->ifr |= SR_INT; + cuda_update_irq(s); +} + +void adb_send_packet(ADBBusState *bus, const uint8_t *buf, int len) +{ + CUDAState *s = &cuda_state; + uint8_t data[16]; + + memcpy(data + 1, buf, len); + data[0] = ADB_PACKET; + cuda_send_packet_to_host(s, data, len + 1); +} + +static void cuda_receive_packet(CUDAState *s, + const uint8_t *data, int len) +{ + uint8_t obuf[16]; + int ti; + + switch(data[0]) { + case CUDA_AUTOPOLL: + s->autopoll = data[1]; + obuf[0] = CUDA_PACKET; + obuf[1] = data[1]; + cuda_send_packet_to_host(s, obuf, 2); + break; + case CUDA_GET_TIME: + /* XXX: add time support ? */ + ti = 0; + obuf[0] = CUDA_PACKET; + obuf[1] = 0; + obuf[2] = 0; + obuf[3] = ti >> 24; + obuf[4] = ti >> 16; + obuf[5] = ti >> 8; + obuf[6] = ti; + cuda_send_packet_to_host(s, obuf, 7); + break; + case CUDA_SET_TIME: + case CUDA_FILE_SERVER_FLAG: + case CUDA_SET_DEVICE_LIST: + case CUDA_SET_AUTO_RATE: + case CUDA_SET_POWER_MESSAGES: + obuf[0] = CUDA_PACKET; + obuf[1] = 0; + cuda_send_packet_to_host(s, obuf, 2); + break; + default: + break; + } +} + +static void cuda_receive_packet_from_host(CUDAState *s, + const uint8_t *data, int len) +{ + switch(data[0]) { + case ADB_PACKET: + adb_receive_packet(&adb_bus, data + 1, len - 1); + break; + case CUDA_PACKET: + cuda_receive_packet(s, data + 1, len - 1); + break; + } +} + +static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ +} + +static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ +} + +static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static CPUWriteMemoryFunc *cuda_write[] = { + &cuda_writeb, + &cuda_writew, + &cuda_writel, +}; + +static CPUReadMemoryFunc *cuda_read[] = { + &cuda_readb, + &cuda_readw, + &cuda_readl, +}; + +int cuda_init(void) +{ + CUDAState *s = &cuda_state; + int cuda_mem_index; + + s->timers[0].latch = 0x10000; + set_counter(&s->timers[0], 0xffff); + s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); + s->timers[1].latch = 0x10000; + set_counter(&s->timers[1], 0xffff); + cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); + return cuda_mem_index; +} diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index d2ab1709c..481bed7a7 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -26,6 +26,86 @@ #define BIOS_FILENAME "ppc_rom.bin" #define NVRAM_SIZE 0x2000 +/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA, + NVRAM (not implemented). */ + +static int dbdma_mem_index; +static int cuda_mem_index; + +/* DBDMA: currently no op - should suffice right now */ + +static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ +} + +static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ +} + +static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ +} + +static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static CPUWriteMemoryFunc *dbdma_write[] = { + &dbdma_writeb, + &dbdma_writew, + &dbdma_writel, +}; + +static CPUReadMemoryFunc *dbdma_read[] = { + &dbdma_readb, + &dbdma_readw, + &dbdma_readl, +}; + +static void macio_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index); + cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index); +} + +static void macio_init(void) +{ + PCIDevice *d; + + d = pci_register_device("macio", sizeof(PCIDevice), + 0, -1, + NULL, NULL); + /* Note: this code is strongly inspirated from the corresponding code + in PearPC */ + d->config[0x00] = 0x6b; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x17; + d->config[0x03] = 0x00; + + d->config[0x0a] = 0x00; // class_sub = pci2pci + d->config[0x0b] = 0xff; // class_base = bridge + d->config[0x0e] = 0x00; // header_type + + d->config[0x3d] = 0x01; // interrupt on pin 1 + + dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL); + + pci_register_io_region(d, 0, 0x80000, + PCI_ADDRESS_SPACE_MEM, macio_map); +} + /* PowerPC PREP hardware initialisation */ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -86,7 +166,13 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pci_ide_init(bs_table); - kbd_init(); + /* cuda also initialize ADB */ + cuda_mem_index = cuda_init(); + + adb_kbd_init(&adb_bus); + adb_mouse_init(&adb_bus); + + macio_init(); nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); -- cgit v1.2.3 From ab2572d7eacf5d70b7fa76a4912fe9739544f6d6 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Jun 2004 19:07:57 +0000 Subject: added -fno-strict-aliasing git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@882 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 1d73b3b69..ac52093d1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -7,7 +7,7 @@ ifdef CONFIG_USER_ONLY VPATH+=:$(SRC_PATH)/linux-user DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) endif -CFLAGS=-Wall -O2 -g +CFLAGS=-Wall -O2 -g -fno-strict-aliasing LDFLAGS=-g LIBS= HELPER_CFLAGS=$(CFLAGS) -- cgit v1.2.3 From a3a91a355bc6107b7d06d722fb97d2b80065ee0b Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 4 Jun 2004 11:06:21 +0000 Subject: sendkey command git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@883 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-doc.texi | 11 ++++ 2 files changed, 168 insertions(+) diff --git a/monitor.c b/monitor.c index 524a281c9..6094f7ba0 100644 --- a/monitor.c +++ b/monitor.c @@ -476,6 +476,161 @@ static void do_print(int count, int format, int size, int val) term_printf("\n"); } +typedef struct { + int keycode; + const char *name; +} KeyDef; + +static const KeyDef key_defs[] = { + { 0x2a, "shift" }, + { 0x36, "shift_r" }, + + { 0x38, "alt" }, + { 0xb8, "alt_r" }, + { 0x1d, "ctrl" }, + { 0x9d, "ctrl_r" }, + + { 0xdd, "menu" }, + + { 0x01, "esc" }, + + { 0x02, "1" }, + { 0x03, "2" }, + { 0x04, "3" }, + { 0x05, "4" }, + { 0x06, "5" }, + { 0x07, "6" }, + { 0x08, "7" }, + { 0x09, "8" }, + { 0x0a, "9" }, + { 0x0b, "0" }, + { 0x0e, "backspace" }, + + { 0x0f, "tab" }, + { 0x10, "q" }, + { 0x11, "w" }, + { 0x12, "e" }, + { 0x13, "r" }, + { 0x14, "t" }, + { 0x15, "y" }, + { 0x16, "u" }, + { 0x17, "i" }, + { 0x18, "o" }, + { 0x19, "p" }, + + { 0x1c, "ret" }, + + { 0x1e, "a" }, + { 0x1f, "s" }, + { 0x20, "d" }, + { 0x21, "f" }, + { 0x22, "g" }, + { 0x23, "h" }, + { 0x24, "j" }, + { 0x25, "k" }, + { 0x26, "l" }, + + { 0x2c, "z" }, + { 0x2d, "x" }, + { 0x2e, "c" }, + { 0x2f, "v" }, + { 0x30, "b" }, + { 0x31, "n" }, + { 0x32, "m" }, + + { 0x39, "spc" }, + + { 0x3b, "f1" }, + { 0x3c, "f2" }, + { 0x3d, "f3" }, + { 0x3e, "f4" }, + { 0x3f, "f5" }, + { 0x40, "f6" }, + { 0x41, "f7" }, + { 0x42, "f8" }, + { 0x43, "f9" }, + { 0x44, "f10" }, + + { 0x46, "scroll_lock" }, + + { 0x56, "<" }, + + { 0x57, "f11" }, + { 0x58, "f12" }, + + { 0xb7, "print" }, + + { 0xc7, "home" }, + { 0xc9, "pgup" }, + { 0xd1, "pgdn" }, + { 0xcf, "end" }, + + { 0xcb, "left" }, + { 0xc8, "up" }, + { 0xd0, "down" }, + { 0xcd, "right" }, + + { 0xd2, "insert" }, + { 0xd3, "delete" }, + { 0, NULL }, +}; + +static int get_keycode(const char *key) +{ + const KeyDef *p; + + for(p = key_defs; p->name != NULL; p++) { + if (!strcmp(key, p->name)) + return p->keycode; + } + return -1; +} + +static void do_send_key(const char *string) +{ + char keybuf[16], *q; + uint8_t keycodes[16]; + const char *p; + int nb_keycodes, keycode, i; + + nb_keycodes = 0; + p = string; + while (*p != '\0') { + q = keybuf; + while (*p != '\0' && *p != '-') { + if ((q - keybuf) < sizeof(keybuf) - 1) { + *q++ = *p; + } + p++; + } + *q = '\0'; + keycode = get_keycode(keybuf); + if (keycode < 0) { + term_printf("unknown key: '%s'\n", keybuf); + return; + } + keycodes[nb_keycodes++] = keycode; + if (*p == '\0') + break; + p++; + } + /* key down events */ + for(i = 0; i < nb_keycodes; i++) { + keycode = keycodes[i]; + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode & 0x7f); + } + /* key up events */ + for(i = nb_keycodes - 1; i >= 0; i--) { + keycode = keycodes[i]; + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode | 0x80); + } +} + + static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -511,6 +666,8 @@ static term_cmd_t term_cmds[] = { "/fmt addr", "physical memory dump starting at 'addr'", }, { "p|print", "/i", do_print, "/fmt expr", "print expression value (use $reg for CPU register access)", }, + { "sendkey", "s", do_send_key, + "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, { NULL, NULL, }, }; diff --git a/qemu-doc.texi b/qemu-doc.texi index 395f39a3f..94c1ccf19 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -484,6 +484,17 @@ Dump 80 16 bit values at the start of the video memory. Print expression value. Only the @var{format} part of @var{fmt} is used. +@item sendkey keys + +Send @var{keys} to the emulator. Use @code{-} to press several keys +simultaneously. Example: +@example +sendkey ctrl-alt-f1 +@end example + +This command is useful to send keys that your graphical user interface +intercepts at low level, such as @code{ctrl-alt-f1} in X Window. + @end table @subsection Integer expressions -- cgit v1.2.3 From 443f1376bc5f35159d09b043c0fdca3a1c4e0af1 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 4 Jun 2004 11:13:20 +0000 Subject: slirp is enabled by default git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@884 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 5 +++-- qemu-doc.texi | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/configure b/configure index e4ffbac81..8e0cff852 100755 --- a/configure +++ b/configure @@ -71,7 +71,7 @@ bigendian="no" mingw32="no" EXESUF="" gdbstub="yes" -slirp="no" +slirp="yes" # OS specific targetos=`uname -s` @@ -139,7 +139,7 @@ for opt do ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ;; - --enable-slirp) slirp="yes" + --disable-slirp) slirp="no" ;; esac done @@ -157,6 +157,7 @@ if test "$mingw32" = "yes" ; then target_list="i386-softmmu ppc-softmmu" EXESUF=".exe" gdbstub="no" + slirp="no" fi if test -z "$cross_prefix" ; then diff --git a/qemu-doc.texi b/qemu-doc.texi index 94c1ccf19..dfa363927 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -597,12 +597,10 @@ Linux distribution. @subsection Using the user mode network stack -This is @emph{experimental} (version 0.5.4). You must configure qemu -with @code{--enable-slirp}. Then by using the option -@option{-user-net} or if you have no tun/tap init script, QEMU uses a -completely user mode network stack (you don't need root priviledge to -use the virtual network). The virtual network configuration is the -following: +By using the option @option{-user-net} or if you have no tun/tap init +script, QEMU uses a completely user mode network stack (you don't need +root priviledge to use the virtual network). The virtual network +configuration is the following: @example @@ -625,6 +623,8 @@ Note that @code{ping} is not supported reliably to the internet as it would require root priviledges. It means you can only ping the local router (10.0.2.2). +The user mode network is currently only supported on a Unix host. + @node direct_linux_boot @section Direct Linux Boot -- cgit v1.2.3 From 710c15a2e9078931f496424d8e10241f4930f940 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 4 Jun 2004 11:20:49 +0000 Subject: lmsw fix (aka dos4gw bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@885 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index 3f9afb17d..8b2800707 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -980,8 +980,9 @@ void OPPROTO op_movl_drN_T0(void) void OPPROTO op_lmsw_T0(void) { - /* only 4 lower bits of CR0 are modified */ - T0 = (env->cr[0] & ~0xf) | (T0 & 0xf); + /* only 4 lower bits of CR0 are modified. PE cannot be set to zero + if already set to one. */ + T0 = (env->cr[0] & ~0xe) | (T0 & 0xf); helper_movl_crN_T0(0); } -- cgit v1.2.3 From de2200d36d70acf874dd806e6bee8a2793e7edc6 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 4 Jun 2004 13:15:06 +0000 Subject: fixed window switch - fixed caps lock and num lock - simplified keycodes (initial idea by Mark Jonckheere) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@886 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 27 deletions(-) diff --git a/sdl.c b/sdl.c index 7b3c3b5ea..bc6d60da3 100644 --- a/sdl.c +++ b/sdl.c @@ -63,25 +63,24 @@ static void sdl_resize(DisplayState *ds, int w, int h) ds->depth = screen->format->BitsPerPixel; } -static const uint32_t x_keycode_to_pc_keycode[61] = { - 0x47e0, /* 97 Home */ - 0x48e0, /* 98 Up */ - 0x49e0, /* 99 PgUp */ - 0x4be0, /* 100 Left */ +static const uint8_t x_keycode_to_pc_keycode[61] = { + 0xc7, /* 97 Home */ + 0xc8, /* 98 Up */ + 0xc9, /* 99 PgUp */ + 0xcb, /* 100 Left */ 0x4c, /* 101 KP-5 */ - 0x4de0, /* 102 Right */ - 0x4fe0, /* 103 End */ - 0x50e0, /* 104 Down */ - 0x51e0, /* 105 PgDn */ - 0x52e0, /* 106 Ins */ - 0x53e0, /* 107 Del */ - 0x1ce0, /* 108 Enter */ - 0x1de0, /* 109 Ctrl-R */ - 0x451de1, /* 110 Pause */ - 0x37e0, /* 111 Print */ - 0x35e0, /* 112 Divide */ - 0x38e0, /* 113 Alt-R */ - 0x46e0, /* 114 Break */ + 0xcd, /* 102 Right */ + 0xcf, /* 103 End */ + 0xd0, /* 104 Down */ + 0xd1, /* 105 PgDn */ + 0xd2, /* 106 Ins */ + 0xd3, /* 107 Del */ + 0x9c, /* 108 Enter */ + 0x9d, /* 109 Ctrl-R */ + 0xb7, /* 111 Print */ + 0xb5, /* 112 Divide */ + 0xb8, /* 113 Alt-R */ + 0xc6, /* 114 Break */ 0x0, /* 115 */ 0x0, /* 116 */ 0x0, /* 117 */ @@ -129,11 +128,25 @@ static const uint32_t x_keycode_to_pc_keycode[61] = { static void sdl_process_key(SDL_KeyboardEvent *ev) { - int keycode, v; - + int keycode, v, i; + static uint8_t modifiers_state[256]; + + if (ev->keysym.sym == SDLK_PAUSE) { + /* specific case */ + v = 0; + if (ev->type == SDL_KEYUP) + v |= 0x80; + kbd_put_keycode(0xe1); + kbd_put_keycode(0x1d | v); + kbd_put_keycode(0x45 | v); + return; + } + /* XXX: not portable, but avoids complicated mappings */ keycode = ev->keysym.scancode; + /* XXX: windows version may not work: 0xe0/0xe1 should be trapped + ? */ #ifndef _WIN32 if (keycode < 9) { keycode = 0; @@ -146,15 +159,44 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) keycode = 0; } #endif - - /* now send the key code */ - while (keycode != 0) { - v = keycode & 0xff; + + switch(keycode) { + case 0x00: + /* sent when leaving window: reset the modifiers state */ + for(i = 0; i < 256; i++) { + if (modifiers_state[i]) { + if (i & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(i | 0x80); + } + } + return; + case 0x2a: /* Left Shift */ + case 0x36: /* Right Shift */ + case 0x1d: /* Left CTRL */ + case 0x9d: /* Right CTRL */ + case 0x38: /* Left ALT */ + case 0xb8: /* Right ALT */ if (ev->type == SDL_KEYUP) - v |= 0x80; - kbd_put_keycode(v); - keycode >>= 8; + modifiers_state[keycode] = 0; + else + modifiers_state[keycode] = 1; + break; + case 0x45: /* num lock */ + case 0x3a: /* caps lock */ + /* SDL does not send the key up event, so we generate it */ + kbd_put_keycode(keycode); + kbd_put_keycode(keycode | 0x80); + return; } + + /* now send the key code */ + if (keycode & 0x80) + kbd_put_keycode(0xe0); + if (ev->type == SDL_KEYUP) + kbd_put_keycode(keycode | 0x80); + else + kbd_put_keycode(keycode & 0x7f); } static void sdl_update_caption(void) -- cgit v1.2.3 From 00ffa62a91a0b5af20f69819f0d30b2cd08cda99 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 4 Jun 2004 13:25:15 +0000 Subject: added some keys git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@887 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monitor.c b/monitor.c index 6094f7ba0..b7ce550cf 100644 --- a/monitor.c +++ b/monitor.c @@ -539,7 +539,7 @@ static const KeyDef key_defs[] = { { 0x32, "m" }, { 0x39, "spc" }, - + { 0x3a, "caps_lock" }, { 0x3b, "f1" }, { 0x3c, "f2" }, { 0x3d, "f3" }, @@ -550,7 +550,7 @@ static const KeyDef key_defs[] = { { 0x42, "f8" }, { 0x43, "f9" }, { 0x44, "f10" }, - + { 0x45, "num_lock" }, { 0x46, "scroll_lock" }, { 0x56, "<" }, -- cgit v1.2.3 From 44bbf73f921100140d905e96ccebc2af51b2ac7a Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 4 Jun 2004 15:30:48 +0000 Subject: dhcp packet size fix (aka pump fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@888 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/bootp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slirp/bootp.c b/slirp/bootp.c index 755072db8..30cb05e95 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -225,7 +225,8 @@ static void bootp_reply(struct bootp_t *bp) } *q++ = RFC1533_END; - m->m_len = sizeof(struct bootp_t); + m->m_len = sizeof(struct bootp_t) - + sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); } -- cgit v1.2.3 From 22a56b8a87b2990c8684b6ca8a37d935dae76591 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 08:32:36 +0000 Subject: sdl keyboard fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@889 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sdl.c b/sdl.c index bc6d60da3..dce81e120 100644 --- a/sdl.c +++ b/sdl.c @@ -77,6 +77,7 @@ static const uint8_t x_keycode_to_pc_keycode[61] = { 0xd3, /* 107 Del */ 0x9c, /* 108 Enter */ 0x9d, /* 109 Ctrl-R */ + 0x0, /* 110 Pause */ 0xb7, /* 111 Print */ 0xb5, /* 112 Divide */ 0xb8, /* 113 Alt-R */ -- cgit v1.2.3 From 798b0c25ccf5711e491d2e4c712e7c37936c79cd Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 10:30:49 +0000 Subject: generic VGA API layer git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@890 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 196 +++++++++++++++++++++-------------------------------------- hw/vga_int.h | 122 +++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 127 deletions(-) create mode 100644 hw/vga_int.h diff --git a/hw/vga.c b/hw/vga.c index 8d8ad9baf..5ec78ed24 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include "vga_int.h" //#define DEBUG_VGA //#define DEBUG_VGA_MEM @@ -33,96 +34,8 @@ /* S3 VGA is deprecated - another graphic card will be emulated */ //#define CONFIG_S3VGA -#define MSR_COLOR_EMULATION 0x01 -#define MSR_PAGE_SELECT 0x20 - -#define ST01_V_RETRACE 0x08 -#define ST01_DISP_ENABLE 0x01 - -/* bochs VBE support */ -#define CONFIG_BOCHS_VBE - -#define VBE_DISPI_MAX_XRES 1024 -#define VBE_DISPI_MAX_YRES 768 - -#define VBE_DISPI_INDEX_ID 0x0 -#define VBE_DISPI_INDEX_XRES 0x1 -#define VBE_DISPI_INDEX_YRES 0x2 -#define VBE_DISPI_INDEX_BPP 0x3 -#define VBE_DISPI_INDEX_ENABLE 0x4 -#define VBE_DISPI_INDEX_BANK 0x5 -#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 -#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 -#define VBE_DISPI_INDEX_X_OFFSET 0x8 -#define VBE_DISPI_INDEX_Y_OFFSET 0x9 -#define VBE_DISPI_INDEX_NB 0xa - -#define VBE_DISPI_ID0 0xB0C0 -#define VBE_DISPI_ID1 0xB0C1 -#define VBE_DISPI_ID2 0xB0C2 - -#define VBE_DISPI_DISABLED 0x00 -#define VBE_DISPI_ENABLED 0x01 -#define VBE_DISPI_LFB_ENABLED 0x40 -#define VBE_DISPI_NOCLEARMEM 0x80 - -#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 - -typedef struct VGAState { - uint8_t *vram_ptr; - unsigned long vram_offset; - unsigned int vram_size; - uint32_t latch; - uint8_t sr_index; - uint8_t sr[8]; - uint8_t gr_index; - uint8_t gr[16]; - uint8_t ar_index; - uint8_t ar[21]; - int ar_flip_flop; - uint8_t cr_index; - uint8_t cr[256]; /* CRT registers */ - uint8_t msr; /* Misc Output Register */ - uint8_t fcr; /* Feature Control Register */ - uint8_t st00; /* status 0 */ - uint8_t st01; /* status 1 */ - uint8_t dac_state; - uint8_t dac_sub_index; - uint8_t dac_read_index; - uint8_t dac_write_index; - uint8_t dac_cache[3]; /* used when writing */ - uint8_t palette[768]; - int32_t bank_offset; -#ifdef CONFIG_BOCHS_VBE - uint16_t vbe_index; - uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; - uint32_t vbe_start_addr; - uint32_t vbe_line_offset; - uint32_t vbe_bank_mask; -#endif - /* display refresh support */ - DisplayState *ds; - uint32_t font_offsets[2]; - int graphic_mode; - uint8_t shift_control; - uint8_t double_scan; - uint32_t line_offset; - uint32_t line_compare; - uint32_t start_addr; - uint8_t last_cw, last_ch; - uint32_t last_width, last_height; /* in chars or pixels */ - uint32_t last_scr_width, last_scr_height; /* in pixels */ - uint8_t cursor_start, cursor_end; - uint32_t cursor_offset; - unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); - /* tell for each page if it has been updated since the last time */ - uint32_t last_palette[256]; -#define CH_ATTR_SIZE (160 * 100) - uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ -} VGAState; - /* force some bits to zero */ -static const uint8_t sr_mask[8] = { +const uint8_t sr_mask[8] = { (uint8_t)~0xfc, (uint8_t)~0xc2, (uint8_t)~0xf0, @@ -133,7 +46,7 @@ static const uint8_t sr_mask[8] = { (uint8_t)~0x00, }; -static const uint8_t gr_mask[16] = { +const uint8_t gr_mask[16] = { (uint8_t)~0xf0, /* 0x00 */ (uint8_t)~0xf0, /* 0x01 */ (uint8_t)~0xf0, /* 0x02 */ @@ -656,7 +569,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) #endif /* called for accesses between 0xa0000 and 0xc0000 */ -static uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) +uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) { VGAState *s = opaque; int memory_map_mode, plane; @@ -743,7 +656,7 @@ static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr) } /* called for accesses between 0xa0000 and 0xc0000 */ -static void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { VGAState *s = opaque; int memory_map_mode, plane, write_mode, b, func_select; @@ -1027,14 +940,11 @@ static int update_palette256(VGAState *s) return full_update; } -/* update start_addr and line_offset. Return TRUE if modified */ -static int update_basic_params(VGAState *s) +static void vga_get_offsets(VGAState *s, + uint32_t *pline_offset, + uint32_t *pstart_addr) { - int full_update; - uint32_t start_addr, line_offset, line_compare; - - full_update = 0; - + uint32_t start_addr, line_offset; #ifdef CONFIG_BOCHS_VBE if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { line_offset = s->vbe_line_offset; @@ -1061,7 +971,19 @@ static int update_basic_params(VGAState *s) start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */ #endif } + *pline_offset = line_offset; + *pstart_addr = start_addr; +} + +/* update start_addr and line_offset. Return TRUE if modified */ +static int update_basic_params(VGAState *s) +{ + int full_update; + uint32_t start_addr, line_offset, line_compare; + full_update = 0; + + s->get_offsets(s, &line_offset, &start_addr); /* line compare */ line_compare = s->cr[0x18] | ((s->cr[0x07] & 0x10) << 4) | @@ -1373,6 +1295,20 @@ static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = { vga_draw_line32_32, }; +static int vga_get_bpp(VGAState *s) +{ + int ret; +#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; + } else +#endif + { + ret = 0; + } + return ret; +} + /* * graphic modes * Missing: @@ -1429,32 +1365,28 @@ static void vga_draw_graphic(VGAState *s, int full_update) v = VGA_DRAW_LINE2; } } else { -#ifdef CONFIG_BOCHS_VBE - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { - switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) { - default: - case 8: - full_update |= update_palette256(s); - v = VGA_DRAW_LINE8; - break; - case 15: - v = VGA_DRAW_LINE15; - break; - case 16: - v = VGA_DRAW_LINE16; - break; - case 24: - v = VGA_DRAW_LINE24; - break; - case 32: - v = VGA_DRAW_LINE32; - break; - } - } else -#endif - { + switch(s->get_bpp(s)) { + default: + case 0: full_update |= update_palette256(s); v = VGA_DRAW_LINE8D2; + break; + case 8: + full_update |= update_palette256(s); + v = VGA_DRAW_LINE8; + break; + case 15: + v = VGA_DRAW_LINE15; + break; + case 16: + v = VGA_DRAW_LINE16; + break; + case 24: + v = VGA_DRAW_LINE24; + break; + case 32: + v = VGA_DRAW_LINE32; + break; } } vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; @@ -1747,11 +1679,9 @@ static void vga_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); } -int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size, - int is_pci) +void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size) { - VGAState *s = &vga_state; int i, j, v, b; for(i = 0;i < 256; i++) { @@ -1783,6 +1713,18 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, s->vram_offset = vga_ram_offset; s->vram_size = vga_ram_size; s->ds = ds; + s->get_bpp = vga_get_bpp; + s->get_offsets = vga_get_offsets; +} + + +int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size, + int is_pci) +{ + VGAState *s = &vga_state; + + vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); register_savevm("vga", 0, 1, vga_save, vga_load, s); diff --git a/hw/vga_int.h b/hw/vga_int.h new file mode 100644 index 000000000..73618ab59 --- /dev/null +++ b/hw/vga_int.h @@ -0,0 +1,122 @@ +/* + * QEMU internal VGA defines. + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define MSR_COLOR_EMULATION 0x01 +#define MSR_PAGE_SELECT 0x20 + +#define ST01_V_RETRACE 0x08 +#define ST01_DISP_ENABLE 0x01 + +/* bochs VBE support */ +#define CONFIG_BOCHS_VBE + +#define VBE_DISPI_MAX_XRES 1024 +#define VBE_DISPI_MAX_YRES 768 + +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_NB 0xa + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 + +typedef struct VGAState { + uint8_t *vram_ptr; + unsigned long vram_offset; + unsigned int vram_size; + uint32_t latch; + uint8_t sr_index; + uint8_t sr[256]; + uint8_t gr_index; + uint8_t gr[256]; + uint8_t ar_index; + uint8_t ar[21]; + int ar_flip_flop; + uint8_t cr_index; + uint8_t cr[256]; /* CRT registers */ + uint8_t msr; /* Misc Output Register */ + uint8_t fcr; /* Feature Control Register */ + uint8_t st00; /* status 0 */ + uint8_t st01; /* status 1 */ + uint8_t dac_state; + uint8_t dac_sub_index; + uint8_t dac_read_index; + uint8_t dac_write_index; + uint8_t dac_cache[3]; /* used when writing */ + uint8_t palette[768]; + int32_t bank_offset; + int (*get_bpp)(struct VGAState *s); + void (*get_offsets)(struct VGAState *s, + uint32_t *pline_offset, + uint32_t *pstart_addr); +#ifdef CONFIG_BOCHS_VBE + uint16_t vbe_index; + uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; + uint32_t vbe_start_addr; + uint32_t vbe_line_offset; + uint32_t vbe_bank_mask; +#endif + /* display refresh support */ + DisplayState *ds; + uint32_t font_offsets[2]; + int graphic_mode; + uint8_t shift_control; + uint8_t double_scan; + uint32_t line_offset; + uint32_t line_compare; + uint32_t start_addr; + uint8_t last_cw, last_ch; + uint32_t last_width, last_height; /* in chars or pixels */ + uint32_t last_scr_width, last_scr_height; /* in pixels */ + uint8_t cursor_start, cursor_end; + uint32_t cursor_offset; + unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); + /* tell for each page if it has been updated since the last time */ + uint32_t last_palette[256]; +#define CH_ATTR_SIZE (160 * 100) + uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ +} VGAState; + +void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); +uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr); +void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val); + +extern const uint8_t sr_mask[8]; +extern const uint8_t gr_mask[16]; -- cgit v1.2.3 From e6e5ad80d8c48934205092f8b6d5a5dbcd56658d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 10:31:55 +0000 Subject: Cirrus VGA emulation (initial patch by Suzu - heavily modified for easier merge) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@891 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 2705 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2705 insertions(+) create mode 100644 hw/cirrus_vga.c diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c new file mode 100644 index 000000000..39485bb71 --- /dev/null +++ b/hw/cirrus_vga.c @@ -0,0 +1,2705 @@ +/* + * QEMU Cirrus VGA Emulator. + * + * Copyright (c) 2004 Fabrice Bellard + * Copyright (c) 2004 Suzu + * + * 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 "vga_int.h" + +/*************************************** + * + * definitions + * + ***************************************/ + +#define qemu_MIN(a,b) ((a) < (b) ? (a) : (b)) + +// ID +#define CIRRUS_ID_CLGD5422 (0x23<<2) +#define CIRRUS_ID_CLGD5426 (0x24<<2) +#define CIRRUS_ID_CLGD5424 (0x25<<2) +#define CIRRUS_ID_CLGD5428 (0x26<<2) +#define CIRRUS_ID_CLGD5430 (0x28<<2) +#define CIRRUS_ID_CLGD5434 (0x2A<<2) +#define CIRRUS_ID_CLGD5446 (0x2E<<2) + +// sequencer 0x07 +#define CIRRUS_SR7_BPP_VGA 0x00 +#define CIRRUS_SR7_BPP_SVGA 0x01 +#define CIRRUS_SR7_BPP_MASK 0x0e +#define CIRRUS_SR7_BPP_8 0x00 +#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02 +#define CIRRUS_SR7_BPP_24 0x04 +#define CIRRUS_SR7_BPP_16 0x06 +#define CIRRUS_SR7_BPP_32 0x08 +#define CIRRUS_SR7_ISAADDR_MASK 0xe0 + +// sequencer 0x0f +#define CIRRUS_MEMSIZE_512k 0x08 +#define CIRRUS_MEMSIZE_1M 0x10 +#define CIRRUS_MEMSIZE_2M 0x18 +#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80 // bank switching is enabled. + +// sequencer 0x12 +#define CIRRUS_CURSOR_SHOW 0x01 +#define CIRRUS_CURSOR_HIDDENPEL 0x02 +#define CIRRUS_CURSOR_LARGE 0x04 // 64x64 if set, 32x32 if clear + +// sequencer 0x17 +#define CIRRUS_BUSTYPE_VLBFAST 0x10 +#define CIRRUS_BUSTYPE_PCI 0x20 +#define CIRRUS_BUSTYPE_VLBSLOW 0x30 +#define CIRRUS_BUSTYPE_ISA 0x38 +#define CIRRUS_MMIO_ENABLE 0x04 +#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared. +#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 + +// control 0x0b +#define CIRRUS_BANKING_DUAL 0x01 +#define CIRRUS_BANKING_GRANULARITY_16K 0x20 // set:16k, clear:4k + +// control 0x30 +#define CIRRUS_BLTMODE_BACKWARDS 0x01 +#define CIRRUS_BLTMODE_MEMSYSDEST 0x02 +#define CIRRUS_BLTMODE_MEMSYSSRC 0x04 +#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08 +#define CIRRUS_BLTMODE_PATTERNCOPY 0x40 +#define CIRRUS_BLTMODE_COLOREXPAND 0x80 +#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30 +#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00 +#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10 +#define CIRRUS_BLTMODE_PIXELWIDTH24 0x20 +#define CIRRUS_BLTMODE_PIXELWIDTH32 0x30 + +// control 0x31 +#define CIRRUS_BLT_BUSY 0x01 +#define CIRRUS_BLT_START 0x02 +#define CIRRUS_BLT_RESET 0x04 +#define CIRRUS_BLT_FIFOUSED 0x10 + +// control 0x32 +#define CIRRUS_ROP_0 0x00 +#define CIRRUS_ROP_SRC_AND_DST 0x05 +#define CIRRUS_ROP_NOP 0x06 +#define CIRRUS_ROP_SRC_AND_NOTDST 0x09 +#define CIRRUS_ROP_NOTDST 0x0b +#define CIRRUS_ROP_SRC 0x0d +#define CIRRUS_ROP_1 0x0e +#define CIRRUS_ROP_NOTSRC_AND_DST 0x50 +#define CIRRUS_ROP_SRC_XOR_DST 0x59 +#define CIRRUS_ROP_SRC_OR_DST 0x6d +#define CIRRUS_ROP_NOTSRC_OR_NOTDST 0x90 +#define CIRRUS_ROP_SRC_NOTXOR_DST 0x95 +#define CIRRUS_ROP_SRC_OR_NOTDST 0xad +#define CIRRUS_ROP_NOTSRC 0xd0 +#define CIRRUS_ROP_NOTSRC_OR_DST 0xd6 +#define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda + +// memory-mapped IO +#define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword +#define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword +#define CIRRUS_MMIO_BLTWIDTH 0x08 // word +#define CIRRUS_MMIO_BLTHEIGHT 0x0a // word +#define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word +#define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word +#define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword +#define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword +#define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte +#define CIRRUS_MMIO_BLTMODE 0x18 // byte +#define CIRRUS_MMIO_BLTROP 0x1a // byte +#define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte +#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c // word? +#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20 // word? +#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24 // word +#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26 // word +#define CIRRUS_MMIO_LINEARDRAW_END_X 0x28 // word +#define CIRRUS_MMIO_LINEARDRAW_END_Y 0x2a // word +#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c // byte +#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte +#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e // byte +#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f // byte +#define CIRRUS_MMIO_BRESENHAM_K1 0x30 // word +#define CIRRUS_MMIO_BRESENHAM_K3 0x32 // word +#define CIRRUS_MMIO_BRESENHAM_ERROR 0x34 // word +#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word +#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38 // byte +#define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte +#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte + +// PCI 0x00: vendor, 0x02: device +#define PCI_VENDOR_CIRRUS 0x1013 +#define PCI_DEVICE_CLGD5430 0x00a0 // CLGD5430 or CLGD5440 +#define PCI_DEVICE_CLGD5434 0x00a8 +#define PCI_DEVICE_CLGD5436 0x00ac +#define PCI_DEVICE_CLGD5446 0x00b8 +#define PCI_DEVICE_CLGD5462 0x00d0 +#define PCI_DEVICE_CLGD5465 0x00d6 +// PCI 0x04: command(word), 0x06(word): status +#define PCI_COMMAND_IOACCESS 0x0001 +#define PCI_COMMAND_MEMACCESS 0x0002 +#define PCI_COMMAND_BUSMASTER 0x0004 +#define PCI_COMMAND_SPECIALCYCLE 0x0008 +#define PCI_COMMAND_MEMWRITEINVALID 0x0010 +#define PCI_COMMAND_PALETTESNOOPING 0x0020 +#define PCI_COMMAND_PARITYDETECTION 0x0040 +#define PCI_COMMAND_ADDRESSDATASTEPPING 0x0080 +#define PCI_COMMAND_SERR 0x0100 +#define PCI_COMMAND_BACKTOBACKTRANS 0x0200 +// PCI 0x08, 0xff000000 (0x09-0x0b:class,0x08:rev) +#define PCI_CLASS_BASE_DISPLAY 0x03 +// PCI 0x08, 0x00ff0000 +#define PCI_CLASS_SUB_VGA 0x00 +// PCI 0x0c, 0x00ff0000 (0x0c:cacheline,0x0d:latency,0x0e:headertype,0x0f:Built-in self test) +#define PCI_CLASS_HEADERTYPE_00h 0x00 +// 0x10-0x3f (headertype 00h) +// PCI 0x10,0x14,0x18,0x1c,0x20,0x24: base address mapping registers +// 0x10: MEMBASE, 0x14: IOBASE(hard-coded in XFree86 3.x) +#define PCI_MAP_MEM 0x0 +#define PCI_MAP_IO 0x1 +#define PCI_MAP_MEM_ADDR_MASK (~0xf) +#define PCI_MAP_IO_ADDR_MASK (~0x3) +#define PCI_MAP_MEMFLAGS_32BIT 0x0 +#define PCI_MAP_MEMFLAGS_32BIT_1M 0x1 +#define PCI_MAP_MEMFLAGS_64BIT 0x4 +#define PCI_MAP_MEMFLAGS_CACHEABLE 0x8 +// PCI 0x28: cardbus CIS pointer +// PCI 0x2c: subsystem vendor id, 0x2e: subsystem id +// PCI 0x30: expansion ROM base address +#define PCI_ROMBIOS_ENABLED 0x1 +// PCI 0x34: 0xffffff00=reserved, 0x000000ff=capabilities pointer +// PCI 0x38: reserved +// PCI 0x3c: 0x3c=int-line, 0x3d=int-pin, 0x3e=min-gnt, 0x3f=maax-lat + +#define CIRRUS_PNPMMIO_SIZE 0x800 + + +/* I/O and memory hook */ +#define CIRRUS_HOOK_NOT_HANDLED 0 +#define CIRRUS_HOOK_HANDLED 1 + +typedef void (*cirrus_bitblt_rop_t) (uint8_t * dst, const uint8_t * src, + int dstpitch, int srcpitch, + int bltwidth, int bltheight); + +typedef void (*cirrus_bitblt_handler_t) (void *opaque); + +typedef struct CirrusVGAState { + /* XXX: we use the anonymous struct/union gcc 3.x extension */ + struct VGAState; + + int cirrus_linear_io_addr; + int cirrus_mmio_io_addr; + uint32_t cirrus_addr_mask; + uint8_t cirrus_shadow_gr0; + uint8_t cirrus_shadow_gr1; + uint8_t cirrus_hidden_dac_lockindex; + uint8_t cirrus_hidden_dac_data; + uint32_t cirrus_bank_base[2]; + uint32_t cirrus_bank_limit[2]; + uint8_t cirrus_hidden_palette[48]; + uint32_t cirrus_hw_cursor_x; + uint32_t cirrus_hw_cursor_y; + int cirrus_blt_pixelwidth; + int cirrus_blt_width; + int cirrus_blt_height; + int cirrus_blt_dstpitch; + int cirrus_blt_srcpitch; + uint32_t cirrus_blt_dstaddr; + uint32_t cirrus_blt_srcaddr; + uint8_t cirrus_blt_mode; + cirrus_bitblt_rop_t cirrus_rop; +#define CIRRUS_BLTBUFSIZE 256 + uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE]; + uint8_t *cirrus_srcptr; + uint8_t *cirrus_srcptr_end; + uint32_t cirrus_srccounter; + uint8_t *cirrus_dstptr; + uint8_t *cirrus_dstptr_end; + uint32_t cirrus_dstcounter; + cirrus_bitblt_handler_t cirrus_blt_handler; + int cirrus_blt_horz_counter; +} CirrusVGAState; + +typedef struct PCICirrusVGAState { + PCIDevice dev; + CirrusVGAState cirrus_vga; +} PCICirrusVGAState; + +/*************************************** + * + * prototypes. + * + ***************************************/ + + +static void cirrus_bitblt_reset(CirrusVGAState * s); + +/*************************************** + * + * raster operations + * + ***************************************/ + +#define IMPLEMENT_FORWARD_BITBLT(name,opline) \ + static void \ + cirrus_bitblt_rop_fwd_##name( \ + uint8_t *dst,const uint8_t *src, \ + int dstpitch,int srcpitch, \ + int bltwidth,int bltheight) \ + { \ + int x,y; \ + dstpitch -= bltwidth; \ + srcpitch -= bltwidth; \ + for (y = 0; y < bltheight; y++) { \ + for (x = 0; x < bltwidth; x++) { \ + opline; \ + dst++; \ + src++; \ + } \ + dst += dstpitch; \ + src += srcpitch; \ + } \ + } + +#define IMPLEMENT_BACKWARD_BITBLT(name,opline) \ + static void \ + cirrus_bitblt_rop_bkwd_##name( \ + uint8_t *dst,const uint8_t *src, \ + int dstpitch,int srcpitch, \ + int bltwidth,int bltheight) \ + { \ + int x,y; \ + dstpitch += bltwidth; \ + srcpitch += bltwidth; \ + for (y = 0; y < bltheight; y++) { \ + for (x = 0; x < bltwidth; x++) { \ + opline; \ + dst--; \ + src--; \ + } \ + dst += dstpitch; \ + src += srcpitch; \ + } \ + } + +IMPLEMENT_FORWARD_BITBLT(0, *dst = 0) + IMPLEMENT_FORWARD_BITBLT(src_and_dst, *dst = (*src) & (*dst)) + IMPLEMENT_FORWARD_BITBLT(nop, (void) 0) + IMPLEMENT_FORWARD_BITBLT(src_and_notdst, *dst = (*src) & (~(*dst))) + IMPLEMENT_FORWARD_BITBLT(notdst, *dst = ~(*dst)) + IMPLEMENT_FORWARD_BITBLT(src, *dst = *src) + IMPLEMENT_FORWARD_BITBLT(1, *dst = 0xff) + IMPLEMENT_FORWARD_BITBLT(notsrc_and_dst, *dst = (~(*src)) & (*dst)) + IMPLEMENT_FORWARD_BITBLT(src_xor_dst, *dst = (*src) ^ (*dst)) + IMPLEMENT_FORWARD_BITBLT(src_or_dst, *dst = (*src) | (*dst)) + IMPLEMENT_FORWARD_BITBLT(notsrc_or_notdst, *dst = (~(*src)) | (~(*dst))) + IMPLEMENT_FORWARD_BITBLT(src_notxor_dst, *dst = ~((*src) ^ (*dst))) + IMPLEMENT_FORWARD_BITBLT(src_or_notdst, *dst = (*src) | (~(*dst))) + IMPLEMENT_FORWARD_BITBLT(notsrc, *dst = (~(*src))) + IMPLEMENT_FORWARD_BITBLT(notsrc_or_dst, *dst = (~(*src)) | (*dst)) + IMPLEMENT_FORWARD_BITBLT(notsrc_and_notdst, *dst = (~(*src)) & (~(*dst))) + + IMPLEMENT_BACKWARD_BITBLT(0, *dst = 0) + IMPLEMENT_BACKWARD_BITBLT(src_and_dst, *dst = (*src) & (*dst)) + IMPLEMENT_BACKWARD_BITBLT(nop, (void) 0) + IMPLEMENT_BACKWARD_BITBLT(src_and_notdst, *dst = (*src) & (~(*dst))) + IMPLEMENT_BACKWARD_BITBLT(notdst, *dst = ~(*dst)) + IMPLEMENT_BACKWARD_BITBLT(src, *dst = *src) + IMPLEMENT_BACKWARD_BITBLT(1, *dst = 0xff) + IMPLEMENT_BACKWARD_BITBLT(notsrc_and_dst, *dst = (~(*src)) & (*dst)) + IMPLEMENT_BACKWARD_BITBLT(src_xor_dst, *dst = (*src) ^ (*dst)) + IMPLEMENT_BACKWARD_BITBLT(src_or_dst, *dst = (*src) | (*dst)) + IMPLEMENT_BACKWARD_BITBLT(notsrc_or_notdst, *dst = (~(*src)) | (~(*dst))) + IMPLEMENT_BACKWARD_BITBLT(src_notxor_dst, *dst = ~((*src) ^ (*dst))) + IMPLEMENT_BACKWARD_BITBLT(src_or_notdst, *dst = (*src) | (~(*dst))) + IMPLEMENT_BACKWARD_BITBLT(notsrc, *dst = (~(*src))) + IMPLEMENT_BACKWARD_BITBLT(notsrc_or_dst, *dst = (~(*src)) | (*dst)) + IMPLEMENT_BACKWARD_BITBLT(notsrc_and_notdst, *dst = (~(*src)) & (~(*dst))) + +static cirrus_bitblt_rop_t cirrus_get_fwd_rop_handler(uint8_t rop) +{ + cirrus_bitblt_rop_t rop_handler = cirrus_bitblt_rop_fwd_nop; + + switch (rop) { + case CIRRUS_ROP_0: + rop_handler = cirrus_bitblt_rop_fwd_0; + break; + case CIRRUS_ROP_SRC_AND_DST: + rop_handler = cirrus_bitblt_rop_fwd_src_and_dst; + break; + case CIRRUS_ROP_NOP: + rop_handler = cirrus_bitblt_rop_fwd_nop; + break; + case CIRRUS_ROP_SRC_AND_NOTDST: + rop_handler = cirrus_bitblt_rop_fwd_src_and_notdst; + break; + case CIRRUS_ROP_NOTDST: + rop_handler = cirrus_bitblt_rop_fwd_notdst; + break; + case CIRRUS_ROP_SRC: + rop_handler = cirrus_bitblt_rop_fwd_src; + break; + case CIRRUS_ROP_1: + rop_handler = cirrus_bitblt_rop_fwd_1; + break; + case CIRRUS_ROP_NOTSRC_AND_DST: + rop_handler = cirrus_bitblt_rop_fwd_notsrc_and_dst; + break; + case CIRRUS_ROP_SRC_XOR_DST: + rop_handler = cirrus_bitblt_rop_fwd_src_xor_dst; + break; + case CIRRUS_ROP_SRC_OR_DST: + rop_handler = cirrus_bitblt_rop_fwd_src_or_dst; + break; + case CIRRUS_ROP_NOTSRC_OR_NOTDST: + rop_handler = cirrus_bitblt_rop_fwd_notsrc_or_notdst; + break; + case CIRRUS_ROP_SRC_NOTXOR_DST: + rop_handler = cirrus_bitblt_rop_fwd_src_notxor_dst; + break; + case CIRRUS_ROP_SRC_OR_NOTDST: + rop_handler = cirrus_bitblt_rop_fwd_src_or_notdst; + break; + case CIRRUS_ROP_NOTSRC: + rop_handler = cirrus_bitblt_rop_fwd_notsrc; + break; + case CIRRUS_ROP_NOTSRC_OR_DST: + rop_handler = cirrus_bitblt_rop_fwd_notsrc_or_dst; + break; + case CIRRUS_ROP_NOTSRC_AND_NOTDST: + rop_handler = cirrus_bitblt_rop_fwd_notsrc_and_notdst; + break; + default: +#ifdef DEBUG_CIRRUS + printf("unknown ROP %02x\n", rop); +#endif + break; + } + + return rop_handler; +} + +static cirrus_bitblt_rop_t cirrus_get_bkwd_rop_handler(uint8_t rop) +{ + cirrus_bitblt_rop_t rop_handler = cirrus_bitblt_rop_bkwd_nop; + + switch (rop) { + case CIRRUS_ROP_0: + rop_handler = cirrus_bitblt_rop_bkwd_0; + break; + case CIRRUS_ROP_SRC_AND_DST: + rop_handler = cirrus_bitblt_rop_bkwd_src_and_dst; + break; + case CIRRUS_ROP_NOP: + rop_handler = cirrus_bitblt_rop_bkwd_nop; + break; + case CIRRUS_ROP_SRC_AND_NOTDST: + rop_handler = cirrus_bitblt_rop_bkwd_src_and_notdst; + break; + case CIRRUS_ROP_NOTDST: + rop_handler = cirrus_bitblt_rop_bkwd_notdst; + break; + case CIRRUS_ROP_SRC: + rop_handler = cirrus_bitblt_rop_bkwd_src; + break; + case CIRRUS_ROP_1: + rop_handler = cirrus_bitblt_rop_bkwd_1; + break; + case CIRRUS_ROP_NOTSRC_AND_DST: + rop_handler = cirrus_bitblt_rop_bkwd_notsrc_and_dst; + break; + case CIRRUS_ROP_SRC_XOR_DST: + rop_handler = cirrus_bitblt_rop_bkwd_src_xor_dst; + break; + case CIRRUS_ROP_SRC_OR_DST: + rop_handler = cirrus_bitblt_rop_bkwd_src_or_dst; + break; + case CIRRUS_ROP_NOTSRC_OR_NOTDST: + rop_handler = cirrus_bitblt_rop_bkwd_notsrc_or_notdst; + break; + case CIRRUS_ROP_SRC_NOTXOR_DST: + rop_handler = cirrus_bitblt_rop_bkwd_src_notxor_dst; + break; + case CIRRUS_ROP_SRC_OR_NOTDST: + rop_handler = cirrus_bitblt_rop_bkwd_src_or_notdst; + break; + case CIRRUS_ROP_NOTSRC: + rop_handler = cirrus_bitblt_rop_bkwd_notsrc; + break; + case CIRRUS_ROP_NOTSRC_OR_DST: + rop_handler = cirrus_bitblt_rop_bkwd_notsrc_or_dst; + break; + case CIRRUS_ROP_NOTSRC_AND_NOTDST: + rop_handler = cirrus_bitblt_rop_bkwd_notsrc_and_notdst; + break; + default: +#ifdef DEBUG_CIRRUS + printf("unknown ROP %02x\n", rop); +#endif + break; + } + + return rop_handler; +} + +/*************************************** + * + * color expansion + * + ***************************************/ + +static void +cirrus_colorexpand_8(CirrusVGAState * s, uint8_t * dst, + const uint8_t * src, int count) +{ + int x; + uint8_t colors[2]; + unsigned bits; + unsigned bitmask; + int srcskipleft = 0; + + colors[0] = s->gr[0x00]; + colors[1] = s->gr[0x01]; + + bitmask = 0x80 >> srcskipleft; + bits = *src++; + for (x = 0; x < count; x++) { + if ((bitmask & 0xff) == 0) { + bitmask = 0x80; + bits = *src++; + } + *dst++ = colors[!!(bits & bitmask)]; + bitmask >>= 1; + } +} + +static void +cirrus_colorexpand_16(CirrusVGAState * s, uint8_t * dst, + const uint8_t * src, int count) +{ + int x; + uint8_t colors[2][2]; + unsigned bits; + unsigned bitmask; + unsigned index; + int srcskipleft = 0; + + colors[0][0] = s->gr[0x00]; + colors[0][1] = s->gr[0x10]; + colors[1][0] = s->gr[0x01]; + colors[1][1] = s->gr[0x11]; + + bitmask = 0x80 >> srcskipleft; + bits = *src++; + for (x = 0; x < count; x++) { + if ((bitmask & 0xff) == 0) { + bitmask = 0x80; + bits = *src++; + } + index = !!(bits & bitmask); + *dst++ = colors[index][0]; + *dst++ = colors[index][1]; + bitmask >>= 1; + } +} + +static void +cirrus_colorexpand_24(CirrusVGAState * s, uint8_t * dst, + const uint8_t * src, int count) +{ + int x; + uint8_t colors[2][3]; + unsigned bits; + unsigned bitmask; + unsigned index; + int srcskipleft = 0; + + colors[0][0] = s->gr[0x00]; + colors[0][1] = s->gr[0x10]; + colors[0][2] = s->gr[0x12]; + colors[1][0] = s->gr[0x01]; + colors[1][1] = s->gr[0x11]; + colors[1][2] = s->gr[0x13]; + + bitmask = 0x80 << srcskipleft; + bits = *src++; + for (x = 0; x < count; x++) { + if ((bitmask & 0xff) == 0) { + bitmask = 0x80; + bits = *src++; + } + index = !!(bits & bitmask); + *dst++ = colors[index][0]; + *dst++ = colors[index][1]; + *dst++ = colors[index][2]; + bitmask >>= 1; + } +} + +static void +cirrus_colorexpand_32(CirrusVGAState * s, uint8_t * dst, + const uint8_t * src, int count) +{ + int x; + uint8_t colors[2][4]; + unsigned bits; + unsigned bitmask; + unsigned index; + int srcskipleft = 0; + + colors[0][0] = s->gr[0x00]; + colors[0][1] = s->gr[0x10]; + colors[0][2] = s->gr[0x12]; + colors[0][3] = s->gr[0x14]; + colors[1][0] = s->gr[0x01]; + colors[1][1] = s->gr[0x11]; + colors[1][2] = s->gr[0x13]; + colors[1][3] = s->gr[0x15]; + + bitmask = 0x80 << srcskipleft; + bits = *src++; + for (x = 0; x < count; x++) { + if ((bitmask & 0xff) == 0) { + bitmask = 0x80; + bits = *src++; + } + index = !!(bits & bitmask); + *dst++ = colors[index][0]; + *dst++ = colors[index][1]; + *dst++ = colors[index][2]; + *dst++ = colors[index][3]; + bitmask >>= 1; + } +} + +static void +cirrus_colorexpand(CirrusVGAState * s, uint8_t * dst, const uint8_t * src, + int count) +{ + switch (s->cirrus_blt_pixelwidth) { + case 1: + cirrus_colorexpand_8(s, dst, src, count); + break; + case 2: + cirrus_colorexpand_16(s, dst, src, count); + break; + case 3: + cirrus_colorexpand_24(s, dst, src, count); + break; + case 4: + cirrus_colorexpand_32(s, dst, src, count); + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: COLOREXPAND pixelwidth %d - unimplemented\n", + s->cirrus_blt_pixelwidth); +#endif + break; + } +} + +static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, + int off_pitch, int bytesperline, + int lines) +{ + int y; + int off_cur; + int off_cur_end; + + for (y = 0; y < lines; y++) { + off_cur = off_begin; + off_cur_end = off_cur + bytesperline; + off_cur &= TARGET_PAGE_MASK; + while (off_cur < off_cur_end) { + cpu_physical_memory_set_dirty(s->vram_offset + off_cur); + off_cur += TARGET_PAGE_SIZE; + } + off_begin += off_pitch; + } +} + + + +static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, + const uint8_t * src) +{ + uint8_t work_colorexp[256]; + uint8_t *dst; + uint8_t *dstc; + int x, y; + int tilewidth, tileheight; + int patternbytes = s->cirrus_blt_pixelwidth * 8; + + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { + cirrus_colorexpand(s, work_colorexp, src, 8 * 8); + src = work_colorexp; + s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_COLOREXPAND; + } + if (s->cirrus_blt_mode & ~CIRRUS_BLTMODE_PATTERNCOPY) { +#ifdef DEBUG_CIRRUS + printf("cirrus: blt mode %02x (pattercopy) - unimplemented\n", + s->cirrus_blt_mode); +#endif + return 0; + } + + dst = s->vram_ptr + s->cirrus_blt_dstaddr; + for (y = 0; y < s->cirrus_blt_height; y += 8) { + dstc = dst; + tileheight = qemu_MIN(8, s->cirrus_blt_height - y); + for (x = 0; x < s->cirrus_blt_width; x += patternbytes) { + tilewidth = qemu_MIN(patternbytes, s->cirrus_blt_width - x); + (*s->cirrus_rop) (dstc, src, + s->cirrus_blt_dstpitch, patternbytes, + tilewidth, tileheight); + dstc += patternbytes; + } + dst += s->cirrus_blt_dstpitch * 8; + } + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); + return 1; +} + +/*************************************** + * + * bitblt (video-to-video) + * + ***************************************/ + +static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) +{ + return cirrus_bitblt_common_patterncopy(s, + s->vram_ptr + + s->cirrus_blt_srcaddr); +} + +static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) +{ + if ((s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) != 0) { +#ifdef DEBUG_CIRRUS + printf("cirrus: CIRRUS_BLTMODE_COLOREXPAND - unimplemented\n"); +#endif + return 0; + } + if ((s->cirrus_blt_mode & (~CIRRUS_BLTMODE_BACKWARDS)) != 0) { +#ifdef DEBUG_CIRRUS + printf("cirrus: blt mode %02x - unimplemented\n", + s->cirrus_blt_mode); +#endif + return 0; + } + + (*s->cirrus_rop) (s->vram_ptr + s->cirrus_blt_dstaddr, + s->vram_ptr + s->cirrus_blt_srcaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); + return 1; +} + +/*************************************** + * + * bitblt (cpu-to-video) + * + ***************************************/ + +static void cirrus_bitblt_cputovideo_patterncopy(void *opaque) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + int data_count; + + data_count = s->cirrus_srcptr - &s->cirrus_bltbuf[0]; + + if (data_count > 0) { + if (data_count != s->cirrus_srccounter) { +#ifdef DEBUG_CIRRUS + printf("cirrus: internal error\n"); +#endif + } else { + cirrus_bitblt_common_patterncopy(s, &s->cirrus_bltbuf[0]); + } + cirrus_bitblt_reset(s); + } +} + +static void cirrus_bitblt_cputovideo_copy(void *opaque) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + int data_count; + int data_avail; + uint8_t work_colorexp[256]; + uint8_t *src_ptr = NULL; + int src_avail = 0; + int src_processing; + int src_linepad = 0; + + if (s->cirrus_blt_height <= 0) { + s->cirrus_srcptr = s->cirrus_srcptr_end; + return; + } + + s->cirrus_srcptr = &s->cirrus_bltbuf[0]; + while (1) { + /* get BLT source. */ + if (src_avail <= 0) { + data_count = s->cirrus_srcptr_end - s->cirrus_srcptr; + if (data_count <= 0) + break; + + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (s->cirrus_blt_mode & ~CIRRUS_BLTMODE_COLOREXPAND) { +#ifdef DEBUG_CIRRUS + printf("cirrus: unsupported\n"); +#endif + cirrus_bitblt_reset(s); + return; + } + data_avail = qemu_MIN(data_count, 256 / 32); + cirrus_colorexpand(s, work_colorexp, s->cirrus_srcptr, + data_avail * 8); + src_ptr = &work_colorexp[0]; + src_avail = data_avail * 8 * s->cirrus_blt_pixelwidth; + s->cirrus_srcptr += data_avail; + src_linepad = + ((s->cirrus_blt_width + 7) / 8) * 8 - + s->cirrus_blt_width; + src_linepad *= s->cirrus_blt_pixelwidth; + } else { + if (s->cirrus_blt_mode != 0) { +#ifdef DEBUG_CIRRUS + printf("cirrus: unsupported\n"); +#endif + cirrus_bitblt_reset(s); + return; + } + src_ptr = s->cirrus_srcptr; + src_avail = + data_count / s->cirrus_blt_pixelwidth * + s->cirrus_blt_pixelwidth; + s->cirrus_srcptr += src_avail; + } + if (src_avail <= 0) + break; + } + + /* 1-line BLT */ + src_processing = + s->cirrus_blt_srcpitch - s->cirrus_blt_horz_counter; + src_processing = qemu_MIN(src_avail, src_processing); + (*s->cirrus_rop) (s->vram_ptr + s->cirrus_blt_dstaddr, + src_ptr, 0, 0, src_processing, 1); + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, + src_processing, 1); + + s->cirrus_blt_dstaddr += src_processing; + src_ptr += src_processing; + src_avail -= src_processing; + s->cirrus_blt_horz_counter += src_processing; + if (s->cirrus_blt_horz_counter >= s->cirrus_blt_srcpitch) { + src_ptr += src_linepad; + src_avail -= src_linepad; + s->cirrus_blt_dstaddr += + s->cirrus_blt_dstpitch - s->cirrus_blt_srcpitch; + s->cirrus_blt_horz_counter = 0; + s->cirrus_blt_height--; + if (s->cirrus_blt_height <= 0) { + s->cirrus_srcptr = s->cirrus_srcptr_end; + return; + } + } + } +} + +static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) +{ + int copy_count; + int avail_count; + + s->cirrus_blt_handler(s); + + if (s->cirrus_srccounter > 0) { + s->cirrus_srccounter -= s->cirrus_srcptr - &s->cirrus_bltbuf[0]; + copy_count = s->cirrus_srcptr_end - s->cirrus_srcptr; + memmove(&s->cirrus_bltbuf[0], s->cirrus_srcptr, copy_count); + avail_count = qemu_MIN(CIRRUS_BLTBUFSIZE, s->cirrus_srccounter); + s->cirrus_srcptr = &s->cirrus_bltbuf[0]; + s->cirrus_srcptr_end = s->cirrus_srcptr + avail_count; + if (s->cirrus_srccounter <= 0) { + cirrus_bitblt_reset(s); + } + } +} + +/*************************************** + * + * bitblt wrapper + * + ***************************************/ + +static void cirrus_bitblt_reset(CirrusVGAState * s) +{ + s->gr[0x31] &= + ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED); + s->cirrus_srcptr = &s->cirrus_bltbuf[0]; + s->cirrus_srcptr_end = &s->cirrus_bltbuf[0]; + s->cirrus_srccounter = 0; + s->cirrus_dstptr = &s->cirrus_bltbuf[0]; + s->cirrus_dstptr_end = &s->cirrus_bltbuf[0]; + s->cirrus_dstcounter = 0; + s->cirrus_blt_handler = NULL; +} + +static int cirrus_bitblt_cputovideo(CirrusVGAState * s) +{ + s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC; + s->cirrus_srcptr = &s->cirrus_bltbuf[0]; + s->cirrus_srcptr_end = &s->cirrus_bltbuf[0]; + + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { + s->cirrus_srccounter = 8; + } else { + s->cirrus_srccounter = 8 * 8 * s->cirrus_blt_pixelwidth; + } + s->cirrus_blt_srcpitch = 0; + s->cirrus_blt_handler = cirrus_bitblt_cputovideo_patterncopy; + } else { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { + s->cirrus_srccounter = + ((s->cirrus_blt_width + 7) / 8) * s->cirrus_blt_height; + s->cirrus_blt_srcpitch = + s->cirrus_blt_width * s->cirrus_blt_pixelwidth; + } else { + s->cirrus_srccounter = + s->cirrus_blt_width * s->cirrus_blt_height; + s->cirrus_blt_srcpitch = s->cirrus_blt_width; + } + /* 4-byte alignment */ + s->cirrus_srccounter = (s->cirrus_srccounter + 3) & (~3); + + s->cirrus_blt_handler = cirrus_bitblt_cputovideo_copy; + s->cirrus_blt_horz_counter = 0; + } + + cirrus_bitblt_cputovideo_next(s); + return 1; +} + +static int cirrus_bitblt_videotocpu(CirrusVGAState * s) +{ + /* XXX */ +#ifdef DEBUG_CIRRUS + printf("cirrus: bitblt (video to cpu) is not implemented yet\n"); +#endif + return 0; +} + +static int cirrus_bitblt_videotovideo(CirrusVGAState * s) +{ + int ret; + + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { + ret = cirrus_bitblt_videotovideo_patterncopy(s); + } else { + ret = cirrus_bitblt_videotovideo_copy(s); + } + + if (ret) + cirrus_bitblt_reset(s); + return ret; +} + +static void cirrus_bitblt_start(CirrusVGAState * s) +{ + uint8_t blt_rop; + + s->cirrus_blt_width = (s->gr[0x20] | (s->gr[0x21] << 8)) + 1; + s->cirrus_blt_height = (s->gr[0x22] | (s->gr[0x23] << 8)) + 1; + s->cirrus_blt_dstpitch = (s->gr[0x24] | (s->gr[0x25] << 8)); + s->cirrus_blt_srcpitch = (s->gr[0x26] | (s->gr[0x27] << 8)); + s->cirrus_blt_dstaddr = + (s->gr[0x28] | (s->gr[0x29] << 8) | (s->gr[0x2a] << 16)); + s->cirrus_blt_srcaddr = + (s->gr[0x2c] | (s->gr[0x2d] << 8) | (s->gr[0x2e] << 16)); + s->cirrus_blt_mode = s->gr[0x30]; + blt_rop = s->gr[0x32]; + + switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + s->cirrus_blt_pixelwidth = 1; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + s->cirrus_blt_pixelwidth = 2; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + s->cirrus_blt_pixelwidth = 3; + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + s->cirrus_blt_pixelwidth = 4; + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: bitblt - pixel width is unknown\n"); +#endif + goto bitblt_ignore; + } + s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK; + + if ((s-> + cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC | + CIRRUS_BLTMODE_MEMSYSDEST)) + == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) { +#ifdef DEBUG_CIRRUS + printf("cirrus: bitblt - memory-to-memory copy is requested\n"); +#endif + goto bitblt_ignore; + } + + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_get_bkwd_rop_handler(blt_rop); + } else { + s->cirrus_rop = cirrus_get_fwd_rop_handler(blt_rop); + } + + // setup bitblt engine. + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!cirrus_bitblt_cputovideo(s)) + goto bitblt_ignore; + } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) { + if (!cirrus_bitblt_videotocpu(s)) + goto bitblt_ignore; + } else { + if (!cirrus_bitblt_videotovideo(s)) + goto bitblt_ignore; + } + + return; + bitblt_ignore:; + cirrus_bitblt_reset(s); +} + +static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value) +{ + unsigned old_value; + + old_value = s->gr[0x31]; + s->gr[0x31] = reg_value; + + if (((old_value & CIRRUS_BLT_RESET) != 0) && + ((reg_value & CIRRUS_BLT_RESET) == 0)) { + cirrus_bitblt_reset(s); + } else if (((old_value & CIRRUS_BLT_START) == 0) && + ((reg_value & CIRRUS_BLT_START) != 0)) { + s->gr[0x31] |= CIRRUS_BLT_BUSY; + cirrus_bitblt_start(s); + } +} + + +/*************************************** + * + * basic parameters + * + ***************************************/ + +static void cirrus_get_offsets(VGAState *s1, + uint32_t *pline_offset, + uint32_t *pstart_addr) +{ + CirrusVGAState * s = (CirrusVGAState *)s1; + uint32_t start_addr; + uint32_t line_offset; + + line_offset = s->cr[0x13] + | ((s->cr[0x1b] & 0x10) << 8); + line_offset <<= 3; + *pline_offset = line_offset; + + start_addr = (s->cr[0x0c] << 8) + | s->cr[0x0d] + | ((s->cr[0x1b] & 0x01) << 16) + | ((s->cr[0x1b] & 0x0c) << 15) + | ((s->cr[0x1d] & 0x80) << 12); + *pstart_addr = start_addr; +} + +static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s) +{ + uint32_t ret = 16; + + switch (s->cirrus_hidden_dac_data & 0xf) { + case 0: + ret = 15; + break; /* Sierra HiColor */ + case 1: + ret = 16; + break; /* XGA HiColor */ + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: invalid DAC value %x in 16bpp\n", + (s->cirrus_hidden_dac_data & 0xf)); +#endif + ret = 15; /* XXX */ + break; + } + return ret; +} + +static int cirrus_get_bpp(VGAState *s1) +{ + CirrusVGAState * s = (CirrusVGAState *)s1; + uint32_t ret = 8; + + if ((s->sr[0x07] & 0x01) != 0) { + /* Cirrus SVGA */ + switch (s->sr[0x07] & CIRRUS_SR7_BPP_MASK) { + case CIRRUS_SR7_BPP_8: + ret = 8; + break; + case CIRRUS_SR7_BPP_16_DOUBLEVCLK: + ret = cirrus_get_bpp16_depth(s); + break; + case CIRRUS_SR7_BPP_24: + ret = 24; + break; + case CIRRUS_SR7_BPP_16: + ret = cirrus_get_bpp16_depth(s); + break; + case CIRRUS_SR7_BPP_32: + ret = 32; + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: unknown bpp - sr7=%x\n", s->sr[0x7]); +#endif + ret = 8; + break; + } + } else { + /* VGA */ + ret = 8; + } + + return ret; +} + +/*************************************** + * + * bank memory + * + ***************************************/ + +static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index) +{ + unsigned offset; + unsigned limit; + + if ((s->gr[0x0b] & 0x01) != 0) /* dual bank */ + offset = s->gr[0x09 + bank_index]; + else /* single bank */ + offset = s->gr[0x09]; + + if ((s->gr[0x0b] & 0x20) != 0) + offset <<= 14; + else + offset <<= 12; + + if (s->vram_size <= offset) + limit = 0; + else + limit = s->vram_size - offset; + + if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) { + if (limit > 0x8000) { + offset += 0x8000; + limit -= 0x8000; + } else { + limit = 0; + } + } + + if (limit > 0) { + s->cirrus_bank_base[bank_index] = offset; + s->cirrus_bank_limit[bank_index] = limit; + } else { + s->cirrus_bank_base[bank_index] = 0; + s->cirrus_bank_limit[bank_index] = 0; + } +} + +/*************************************** + * + * I/O access between 0x3c4-0x3c5 + * + ***************************************/ + +static int +cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value) +{ + switch (reg_index) { + case 0x00: // Standard VGA + case 0x01: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + return CIRRUS_HOOK_NOT_HANDLED; + case 0x06: // Unlock Cirrus extensions + *reg_value = s->sr[reg_index]; + break; + case 0x05: // ??? + case 0x07: // Extended Sequencer Mode + case 0x08: // EEPROM Control + case 0x09: // Scratch Register 0 + case 0x0a: // Scratch Register 1 + case 0x0b: // VCLK 0 + case 0x0c: // VCLK 1 + case 0x0d: // VCLK 2 + case 0x0e: // VCLK 3 + case 0x0f: // DRAM Control + case 0x10: + case 0x30: + case 0x50: + case 0x70: // Graphics Cursor X + case 0x90: + case 0xb0: + case 0xd0: + case 0xf0: // Graphics Cursor X + case 0x11: + case 0x31: + case 0x51: + case 0x71: // Graphics Cursor Y + case 0x91: + case 0xb1: + case 0xd1: + case 0xf1: // Graphics Cursor Y + case 0x12: // Graphics Cursor Attribute + case 0x13: // Graphics Cursor Pattern Address + case 0x14: // Scratch Register 2 + case 0x15: // Scratch Register 3 + case 0x16: // Performance Tuning Register + case 0x17: // Configuration Readback and Extended Control + case 0x18: // Signature Generator Control + case 0x19: // Signal Generator Result + case 0x1a: // Signal Generator Result + case 0x1b: // VCLK 0 Denominator & Post + case 0x1c: // VCLK 1 Denominator & Post + case 0x1d: // VCLK 2 Denominator & Post + case 0x1e: // VCLK 3 Denominator & Post + case 0x1f: // BIOS Write Enable and MCLK select +#ifdef DEBUG_CIRRUS + printf("cirrus: handled inport sr_index %02x\n", reg_index); +#endif + *reg_value = s->sr[reg_index]; + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: inport sr_index %02x\n", reg_index); +#endif + *reg_value = 0xff; + break; + } + + return CIRRUS_HOOK_HANDLED; +} + +static int +cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) +{ + switch (reg_index) { + case 0x00: // Standard VGA + case 0x01: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + return CIRRUS_HOOK_NOT_HANDLED; + case 0x06: // Unlock Cirrus extensions + reg_value &= 0x17; + if (reg_value == 0x12) { + s->sr[reg_index] = 0x12; + } else { + s->sr[reg_index] = 0x0f; + } + break; + case 0x10: + case 0x30: + case 0x50: + case 0x70: // Graphics Cursor X + case 0x90: + case 0xb0: + case 0xd0: + case 0xf0: // Graphics Cursor X + s->sr[0x10] = reg_value; + s->cirrus_hw_cursor_x = ((reg_index << 3) & 0x700) | reg_value; + break; + case 0x11: + case 0x31: + case 0x51: + case 0x71: // Graphics Cursor Y + case 0x91: + case 0xb1: + case 0xd1: + case 0xf1: // Graphics Cursor Y + s->sr[0x11] = reg_value; + s->cirrus_hw_cursor_y = ((reg_index << 3) & 0x700) | reg_value; + break; + case 0x07: // Extended Sequencer Mode + case 0x08: // EEPROM Control + case 0x09: // Scratch Register 0 + case 0x0a: // Scratch Register 1 + case 0x0b: // VCLK 0 + case 0x0c: // VCLK 1 + case 0x0d: // VCLK 2 + case 0x0e: // VCLK 3 + case 0x0f: // DRAM Control + case 0x12: // Graphics Cursor Attribute + case 0x13: // Graphics Cursor Pattern Address + case 0x14: // Scratch Register 2 + case 0x15: // Scratch Register 3 + case 0x16: // Performance Tuning Register + case 0x17: // Configuration Readback and Extended Control + case 0x18: // Signature Generator Control + case 0x19: // Signature Generator Result + case 0x1a: // Signature Generator Result + case 0x1b: // VCLK 0 Denominator & Post + case 0x1c: // VCLK 1 Denominator & Post + case 0x1d: // VCLK 2 Denominator & Post + case 0x1e: // VCLK 3 Denominator & Post + case 0x1f: // BIOS Write Enable and MCLK select + s->sr[reg_index] = reg_value; +#ifdef DEBUG_CIRRUS + printf("cirrus: handled outport sr_index %02x, sr_value %02x\n", + reg_index, reg_value); +#endif + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index, + reg_value); +#endif + break; + } + + return CIRRUS_HOOK_HANDLED; +} + +/*************************************** + * + * I/O access at 0x3c6 + * + ***************************************/ + +static void cirrus_read_hidden_dac(CirrusVGAState * s, int *reg_value) +{ + *reg_value = 0xff; + if (s->cirrus_hidden_dac_lockindex < 5) { + if (s->cirrus_hidden_dac_lockindex == 4) { + *reg_value = s->cirrus_hidden_dac_data; + } + s->cirrus_hidden_dac_lockindex++; + } +} + +static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value) +{ + if (s->cirrus_hidden_dac_lockindex == 4) { + s->cirrus_hidden_dac_data = reg_value; +#ifdef DEBUG_CIRRUS + printf("cirrus: outport hidden DAC, value %02x\n", reg_value); +#endif + } + s->cirrus_hidden_dac_lockindex = 0; +} + +/*************************************** + * + * I/O access at 0x3c9 + * + ***************************************/ + +static int cirrus_hook_read_palette(CirrusVGAState * s, int *reg_value) +{ + if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) + return CIRRUS_HOOK_NOT_HANDLED; + if (s->dac_read_index < 0x10) { + *reg_value = + s->cirrus_hidden_palette[s->dac_read_index * 3 + + s->dac_sub_index]; + } else { + *reg_value = 0xff; /* XXX */ + } + if (++s->dac_sub_index == 3) { + s->dac_sub_index = 0; + s->dac_read_index++; + } + return CIRRUS_HOOK_HANDLED; +} + +static int cirrus_hook_write_palette(CirrusVGAState * s, int reg_value) +{ + if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) + return CIRRUS_HOOK_NOT_HANDLED; + s->dac_cache[s->dac_sub_index] = reg_value; + if (++s->dac_sub_index == 3) { + if (s->dac_read_index < 0x10) { + memcpy(&s->cirrus_hidden_palette[s->dac_write_index * 3], + s->dac_cache, 3); + /* XXX update cursor */ + } + s->dac_sub_index = 0; + s->dac_write_index++; + } + return CIRRUS_HOOK_HANDLED; +} + +/*************************************** + * + * I/O access between 0x3ce-0x3cf + * + ***************************************/ + +static int +cirrus_hook_read_gr(CirrusVGAState * s, unsigned reg_index, int *reg_value) +{ + switch (reg_index) { + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + case 0x06: // Standard VGA + case 0x07: // Standard VGA + case 0x08: // Standard VGA + return CIRRUS_HOOK_NOT_HANDLED; + case 0x05: // Standard VGA, Cirrus extended mode + default: + break; + } + + if (reg_index < 0x3a) { + *reg_value = s->gr[reg_index]; + } else { +#ifdef DEBUG_CIRRUS + printf("cirrus: inport gr_index %02x\n", reg_index); +#endif + *reg_value = 0xff; + } + + return CIRRUS_HOOK_HANDLED; +} + +static int +cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) +{ + switch (reg_index) { + case 0x00: // Standard VGA, BGCOLOR 0x000000ff + s->gr[0x00] = reg_value; + return CIRRUS_HOOK_NOT_HANDLED; + case 0x01: // Standard VGA, FGCOLOR 0x000000ff + s->gr[0x01] = reg_value; + return CIRRUS_HOOK_NOT_HANDLED; + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + case 0x06: // Standard VGA + case 0x07: // Standard VGA + case 0x08: // Standard VGA + return CIRRUS_HOOK_NOT_HANDLED; + case 0x05: // Standard VGA, Cirrus extended mode + s->gr[reg_index] = reg_value & 0x7f; + break; + case 0x09: // bank offset #0 + case 0x0A: // bank offset #1 + case 0x0B: + s->gr[reg_index] = reg_value; + cirrus_update_bank_ptr(s, 0); + cirrus_update_bank_ptr(s, 1); + break; + case 0x10: // BGCOLOR 0x0000ff00 + case 0x11: // FGCOLOR 0x0000ff00 + case 0x12: // BGCOLOR 0x00ff0000 + case 0x13: // FGCOLOR 0x00ff0000 + case 0x14: // BGCOLOR 0xff000000 + case 0x15: // FGCOLOR 0xff000000 + case 0x20: // BLT WIDTH 0x0000ff + case 0x22: // BLT HEIGHT 0x0000ff + case 0x24: // BLT DEST PITCH 0x0000ff + case 0x26: // BLT SRC PITCH 0x0000ff + case 0x28: // BLT DEST ADDR 0x0000ff + case 0x29: // BLT DEST ADDR 0x00ff00 + case 0x2c: // BLT SRC ADDR 0x0000ff + case 0x2d: // BLT SRC ADDR 0x00ff00 + case 0x30: // BLT MODE + case 0x32: // RASTER OP + case 0x34: // BLT TRANSPARENT COLOR 0x00ff + case 0x35: // BLT TRANSPARENT COLOR 0xff00 + case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff + case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00 + s->gr[reg_index] = reg_value; + break; + case 0x21: // BLT WIDTH 0x001f00 + case 0x23: // BLT HEIGHT 0x001f00 + case 0x25: // BLT DEST PITCH 0x001f00 + case 0x27: // BLT SRC PITCH 0x001f00 + s->gr[reg_index] = reg_value & 0x1f; + break; + case 0x2a: // BLT DEST ADDR 0x3f0000 + case 0x2e: // BLT SRC ADDR 0x3f0000 + s->gr[reg_index] = reg_value & 0x3f; + break; + case 0x31: // BLT STATUS/START + cirrus_write_bitblt(s, reg_value); + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index, + reg_value); +#endif + break; + } + + return CIRRUS_HOOK_HANDLED; +} + +/*************************************** + * + * I/O access between 0x3d4-0x3d5 + * + ***************************************/ + +static int +cirrus_hook_read_cr(CirrusVGAState * s, unsigned reg_index, int *reg_value) +{ + switch (reg_index) { + case 0x00: // Standard VGA + case 0x01: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + case 0x05: // Standard VGA + case 0x06: // Standard VGA + case 0x07: // Standard VGA + case 0x08: // Standard VGA + case 0x09: // Standard VGA + case 0x0a: // Standard VGA + case 0x0b: // Standard VGA + case 0x0c: // Standard VGA + case 0x0d: // Standard VGA + case 0x0e: // Standard VGA + case 0x0f: // Standard VGA + case 0x10: // Standard VGA + case 0x11: // Standard VGA + case 0x12: // Standard VGA + case 0x13: // Standard VGA + case 0x14: // Standard VGA + case 0x15: // Standard VGA + case 0x16: // Standard VGA + case 0x17: // Standard VGA + case 0x18: // Standard VGA + return CIRRUS_HOOK_NOT_HANDLED; + case 0x19: // Interlace End + case 0x1a: // Miscellaneous Control + case 0x1b: // Extended Display Control + case 0x1c: // Sync Adjust and Genlock + case 0x1d: // Overlay Extended Control + case 0x22: // Graphics Data Latches Readback (R) + case 0x24: // Attribute Controller Toggle Readback (R) + case 0x25: // Part Status + case 0x27: // Part ID (R) + *reg_value = s->cr[reg_index]; + break; + case 0x26: // Attribute Controller Index Readback (R) + *reg_value = s->ar_index & 0x3f; + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: inport cr_index %02x\n", reg_index); + *reg_value = 0xff; +#endif + break; + } + + return CIRRUS_HOOK_HANDLED; +} + +static int +cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value) +{ + switch (reg_index) { + case 0x00: // Standard VGA + case 0x01: // Standard VGA + case 0x02: // Standard VGA + case 0x03: // Standard VGA + case 0x04: // Standard VGA + case 0x05: // Standard VGA + case 0x06: // Standard VGA + case 0x07: // Standard VGA + case 0x08: // Standard VGA + case 0x09: // Standard VGA + case 0x0a: // Standard VGA + case 0x0b: // Standard VGA + case 0x0c: // Standard VGA + case 0x0d: // Standard VGA + case 0x0e: // Standard VGA + case 0x0f: // Standard VGA + case 0x10: // Standard VGA + case 0x11: // Standard VGA + case 0x12: // Standard VGA + case 0x13: // Standard VGA + case 0x14: // Standard VGA + case 0x15: // Standard VGA + case 0x16: // Standard VGA + case 0x17: // Standard VGA + case 0x18: // Standard VGA + return CIRRUS_HOOK_NOT_HANDLED; + case 0x19: // Interlace End + case 0x1a: // Miscellaneous Control + case 0x1b: // Extended Display Control + case 0x1c: // Sync Adjust and Genlock + s->cr[reg_index] = reg_value; +#ifdef DEBUG_CIRRUS + printf("cirrus: handled outport cr_index %02x, cr_value %02x\n", + reg_index, reg_value); +#endif + break; + case 0x22: // Graphics Data Latches Readback (R) + case 0x24: // Attribute Controller Toggle Readback (R) + case 0x26: // Attribute Controller Index Readback (R) + case 0x27: // Part ID (R) + break; + case 0x1d: // Overlay Extended Control + case 0x25: // Part Status + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: outport cr_index %02x, cr_value %02x\n", reg_index, + reg_value); +#endif + break; + } + + return CIRRUS_HOOK_HANDLED; +} + +/*************************************** + * + * memory-mapped I/O (bitblt) + * + ***************************************/ + +static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address) +{ + int value = 0xff; + + switch (address) { + case (CIRRUS_MMIO_BLTBGCOLOR + 0): + cirrus_hook_read_gr(s, 0x00, &value); + break; + case (CIRRUS_MMIO_BLTBGCOLOR + 1): + cirrus_hook_read_gr(s, 0x10, &value); + break; + case (CIRRUS_MMIO_BLTBGCOLOR + 2): + cirrus_hook_read_gr(s, 0x12, &value); + break; + case (CIRRUS_MMIO_BLTBGCOLOR + 3): + cirrus_hook_read_gr(s, 0x14, &value); + break; + case (CIRRUS_MMIO_BLTFGCOLOR + 0): + cirrus_hook_read_gr(s, 0x01, &value); + break; + case (CIRRUS_MMIO_BLTFGCOLOR + 1): + cirrus_hook_read_gr(s, 0x11, &value); + break; + case (CIRRUS_MMIO_BLTFGCOLOR + 2): + cirrus_hook_read_gr(s, 0x13, &value); + break; + case (CIRRUS_MMIO_BLTFGCOLOR + 3): + cirrus_hook_read_gr(s, 0x15, &value); + break; + case (CIRRUS_MMIO_BLTWIDTH + 0): + cirrus_hook_read_gr(s, 0x20, &value); + break; + case (CIRRUS_MMIO_BLTWIDTH + 1): + cirrus_hook_read_gr(s, 0x21, &value); + break; + case (CIRRUS_MMIO_BLTHEIGHT + 0): + cirrus_hook_read_gr(s, 0x22, &value); + break; + case (CIRRUS_MMIO_BLTHEIGHT + 1): + cirrus_hook_read_gr(s, 0x23, &value); + break; + case (CIRRUS_MMIO_BLTDESTPITCH + 0): + cirrus_hook_read_gr(s, 0x24, &value); + break; + case (CIRRUS_MMIO_BLTDESTPITCH + 1): + cirrus_hook_read_gr(s, 0x25, &value); + break; + case (CIRRUS_MMIO_BLTSRCPITCH + 0): + cirrus_hook_read_gr(s, 0x26, &value); + break; + case (CIRRUS_MMIO_BLTSRCPITCH + 1): + cirrus_hook_read_gr(s, 0x27, &value); + break; + case (CIRRUS_MMIO_BLTDESTADDR + 0): + cirrus_hook_read_gr(s, 0x28, &value); + break; + case (CIRRUS_MMIO_BLTDESTADDR + 1): + cirrus_hook_read_gr(s, 0x29, &value); + break; + case (CIRRUS_MMIO_BLTDESTADDR + 2): + cirrus_hook_read_gr(s, 0x2a, &value); + break; + case (CIRRUS_MMIO_BLTSRCADDR + 0): + cirrus_hook_read_gr(s, 0x2c, &value); + break; + case (CIRRUS_MMIO_BLTSRCADDR + 1): + cirrus_hook_read_gr(s, 0x2d, &value); + break; + case (CIRRUS_MMIO_BLTSRCADDR + 2): + cirrus_hook_read_gr(s, 0x2e, &value); + break; + case CIRRUS_MMIO_BLTWRITEMASK: + cirrus_hook_read_gr(s, 0x2f, &value); + break; + case CIRRUS_MMIO_BLTMODE: + cirrus_hook_read_gr(s, 0x30, &value); + break; + case CIRRUS_MMIO_BLTROP: + cirrus_hook_read_gr(s, 0x32, &value); + break; + case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0): + cirrus_hook_read_gr(s, 0x34, &value); + break; + case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1): + cirrus_hook_read_gr(s, 0x35, &value); + break; + case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0): + cirrus_hook_read_gr(s, 0x38, &value); + break; + case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1): + cirrus_hook_read_gr(s, 0x39, &value); + break; + case CIRRUS_MMIO_BLTSTATUS: + cirrus_hook_read_gr(s, 0x31, &value); + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: mmio read - address 0x%04x\n", address); +#endif + break; + } + + return (uint8_t) value; +} + +static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address, + uint8_t value) +{ + switch (address) { + case (CIRRUS_MMIO_BLTBGCOLOR + 0): + cirrus_hook_write_gr(s, 0x00, value); + break; + case (CIRRUS_MMIO_BLTBGCOLOR + 1): + cirrus_hook_write_gr(s, 0x10, value); + break; + case (CIRRUS_MMIO_BLTBGCOLOR + 2): + cirrus_hook_write_gr(s, 0x12, value); + break; + case (CIRRUS_MMIO_BLTBGCOLOR + 3): + cirrus_hook_write_gr(s, 0x14, value); + break; + case (CIRRUS_MMIO_BLTFGCOLOR + 0): + cirrus_hook_write_gr(s, 0x01, value); + break; + case (CIRRUS_MMIO_BLTFGCOLOR + 1): + cirrus_hook_write_gr(s, 0x11, value); + break; + case (CIRRUS_MMIO_BLTFGCOLOR + 2): + cirrus_hook_write_gr(s, 0x13, value); + break; + case (CIRRUS_MMIO_BLTFGCOLOR + 3): + cirrus_hook_write_gr(s, 0x15, value); + break; + case (CIRRUS_MMIO_BLTWIDTH + 0): + cirrus_hook_write_gr(s, 0x20, value); + break; + case (CIRRUS_MMIO_BLTWIDTH + 1): + cirrus_hook_write_gr(s, 0x21, value); + break; + case (CIRRUS_MMIO_BLTHEIGHT + 0): + cirrus_hook_write_gr(s, 0x22, value); + break; + case (CIRRUS_MMIO_BLTHEIGHT + 1): + cirrus_hook_write_gr(s, 0x23, value); + break; + case (CIRRUS_MMIO_BLTDESTPITCH + 0): + cirrus_hook_write_gr(s, 0x24, value); + break; + case (CIRRUS_MMIO_BLTDESTPITCH + 1): + cirrus_hook_write_gr(s, 0x25, value); + break; + case (CIRRUS_MMIO_BLTSRCPITCH + 0): + cirrus_hook_write_gr(s, 0x26, value); + break; + case (CIRRUS_MMIO_BLTSRCPITCH + 1): + cirrus_hook_write_gr(s, 0x27, value); + break; + case (CIRRUS_MMIO_BLTDESTADDR + 0): + cirrus_hook_write_gr(s, 0x28, value); + break; + case (CIRRUS_MMIO_BLTDESTADDR + 1): + cirrus_hook_write_gr(s, 0x29, value); + break; + case (CIRRUS_MMIO_BLTDESTADDR + 2): + cirrus_hook_write_gr(s, 0x2a, value); + break; + case (CIRRUS_MMIO_BLTDESTADDR + 3): + /* ignored */ + break; + case (CIRRUS_MMIO_BLTSRCADDR + 0): + cirrus_hook_write_gr(s, 0x2c, value); + break; + case (CIRRUS_MMIO_BLTSRCADDR + 1): + cirrus_hook_write_gr(s, 0x2d, value); + break; + case (CIRRUS_MMIO_BLTSRCADDR + 2): + cirrus_hook_write_gr(s, 0x2e, value); + break; + case CIRRUS_MMIO_BLTWRITEMASK: + cirrus_hook_write_gr(s, 0x2f, value); + break; + case CIRRUS_MMIO_BLTMODE: + cirrus_hook_write_gr(s, 0x30, value); + break; + case CIRRUS_MMIO_BLTROP: + cirrus_hook_write_gr(s, 0x32, value); + break; + case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0): + cirrus_hook_write_gr(s, 0x34, value); + break; + case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1): + cirrus_hook_write_gr(s, 0x35, value); + break; + case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0): + cirrus_hook_write_gr(s, 0x38, value); + break; + case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1): + cirrus_hook_write_gr(s, 0x39, value); + break; + case CIRRUS_MMIO_BLTSTATUS: + cirrus_hook_write_gr(s, 0x31, value); + break; + default: +#ifdef DEBUG_CIRRUS + printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n", + address, value); +#endif + break; + } +} + +/*************************************** + * + * memory-mapped I/O (vga) + * + ***************************************/ + +static uint8_t cirrus_mmio_vga_read(CirrusVGAState * s, unsigned address) +{ +#ifdef DEBUG_CIRRUS + printf("cirrus: mmio vga read (unimplemented) - address 0x%04x\n", + address); +#endif + return 0xff; +} + +static void cirrus_mmio_vga_write(CirrusVGAState * s, unsigned address, + uint8_t value) +{ +#ifdef DEBUG_CIRRUS + printf + ("cirrus: mmio vga write (unimplemented) - address 0x%04x, value 0x%02x\n", + address, value); +#endif +} + +/*************************************** + * + * write mode 4/5 + * + * assume TARGET_PAGE_SIZE >= 16 + * + ***************************************/ + +static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, + unsigned mode, + unsigned offset, + uint32_t mem_value) +{ + int x; + unsigned val = mem_value; + uint8_t *dst; + + dst = s->vram_ptr + offset; + for (x = 0; x < 8; x++) { + if (val & 0x80) { + *dst++ = s->gr[0x01]; + } else if (mode == 5) { + *dst++ = s->gr[0x00]; + } + val <<= 1; + } + cpu_physical_memory_set_dirty(s->vram_offset + offset); + cpu_physical_memory_set_dirty(s->vram_offset + offset + 7); +} + +static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, + unsigned mode, + unsigned offset, + uint32_t mem_value) +{ + int x; + unsigned val = mem_value; + uint8_t *dst; + + dst = s->vram_ptr + offset; + for (x = 0; x < 8; x++) { + if (val & 0x80) { + *dst++ = s->gr[0x01]; + *dst++ = s->gr[0x11]; + } else if (mode == 5) { + *dst++ = s->gr[0x00]; + *dst++ = s->gr[0x10]; + } + val <<= 1; + } + cpu_physical_memory_set_dirty(s->vram_offset + offset); + cpu_physical_memory_set_dirty(s->vram_offset + offset + 15); +} + +/*************************************** + * + * memory access between 0xa0000-0xbffff + * + ***************************************/ + +static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr) +{ + CirrusVGAState *s = opaque; + unsigned bank_index; + unsigned bank_offset; + uint32_t val; + + if ((s->sr[0x07] & 0x01) == 0) { + return vga_mem_readb(s, addr); + } + + if (addr < 0x10000) { + /* XXX handle bitblt */ + /* video memory */ + bank_index = addr >> 15; + bank_offset = addr & 0x7fff; + if (bank_offset < s->cirrus_bank_limit[bank_index]) { + bank_offset += s->cirrus_bank_base[bank_index]; + if ((s->gr[0x0B] & 0x14) == 0x14) { + bank_offset <<= 4; + } else if (s->gr[0x0B] & 0x02) { + bank_offset <<= 3; + } + bank_offset &= s->cirrus_addr_mask; + val = *(s->vram_ptr + bank_offset); + } else + val = 0xff; + } else if (addr >= 0x18000 && addr < 0x18100) { + /* memory-mapped I/O */ + val = 0xff; + if ((s->sr[0x17] & 0x44) == 0x04) { + val = cirrus_mmio_blt_read(s, addr & 0xff); + } + } else { + val = 0xff; +#ifdef DEBUG_CIRRUS + printf("cirrus: mem_readb %06x\n", addr); +#endif + } + return val; +} + +static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_vga_mem_readb(opaque, addr) << 8; + v |= cirrus_vga_mem_readb(opaque, addr + 1); +#else + v = cirrus_vga_mem_readb(opaque, addr); + v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8; +#endif + return v; +} + +static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_vga_mem_readb(opaque, addr) << 24; + v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16; + v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8; + v |= cirrus_vga_mem_readb(opaque, addr + 3); +#else + v = cirrus_vga_mem_readb(opaque, addr); + v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8; + v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16; + v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24; +#endif + return v; +} + +static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t mem_value) +{ + CirrusVGAState *s = opaque; + unsigned bank_index; + unsigned bank_offset; + unsigned mode; + + if ((s->sr[0x07] & 0x01) == 0) { + vga_mem_writeb(s, addr, mem_value); + return; + } + + if (addr < 0x10000) { + if (s->cirrus_srcptr != s->cirrus_srcptr_end) { + /* bitblt */ + *s->cirrus_srcptr++ = (uint8_t) mem_value; + if (s->cirrus_srcptr == s->cirrus_srcptr_end) { + cirrus_bitblt_cputovideo_next(s); + } + } else { + /* video memory */ + bank_index = addr >> 15; + bank_offset = addr & 0x7fff; + if (bank_offset < s->cirrus_bank_limit[bank_index]) { + bank_offset += s->cirrus_bank_base[bank_index]; + if ((s->gr[0x0B] & 0x14) == 0x14) { + bank_offset <<= 4; + } else if (s->gr[0x0B] & 0x02) { + bank_offset <<= 3; + } + bank_offset &= s->cirrus_addr_mask; + mode = s->gr[0x05] & 0x7; + if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { + *(s->vram_ptr + bank_offset) = mem_value; + cpu_physical_memory_set_dirty(s->vram_offset + + bank_offset); + } else { + if ((s->gr[0x0B] & 0x14) != 0x14) { + cirrus_mem_writeb_mode4and5_8bpp(s, mode, + bank_offset, + mem_value); + } else { + cirrus_mem_writeb_mode4and5_16bpp(s, mode, + bank_offset, + mem_value); + } + } + } + } + } else if (addr >= 0x18000 && addr < 0x18100) { + /* memory-mapped I/O */ + if ((s->sr[0x17] & 0x44) == 0x04) { + cirrus_mmio_blt_write(s, addr & 0xff, mem_value); + } + } else { +#ifdef DEBUG_CIRRUS + printf("cirrus: mem_writeb %06x value %02x\n", addr, mem_value); +#endif + } +} + +static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff); + cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff); +#else + cirrus_vga_mem_writeb(opaque, addr, val & 0xff); + cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); +#endif +} + +static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff); + cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); + cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); + cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff); +#else + cirrus_vga_mem_writeb(opaque, addr, val & 0xff); + cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); + cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); + cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); +#endif +} + +static CPUReadMemoryFunc *cirrus_vga_mem_read[3] = { + cirrus_vga_mem_readb, + cirrus_vga_mem_readw, + cirrus_vga_mem_readl, +}; + +static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = { + cirrus_vga_mem_writeb, + cirrus_vga_mem_writew, + cirrus_vga_mem_writel, +}; + +/*************************************** + * + * LFB memory access + * + ***************************************/ + +static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + uint32_t ret; + + /* XXX: s->vram_size must be a power of two */ + addr &= s->cirrus_addr_mask; + + if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & 0x1fff00) == 0x1fff00)) { + /* memory-mapped I/O */ + ret = cirrus_mmio_blt_read(s, addr & 0xff); + } else if (0) { + /* XXX handle bitblt */ + ret = 0xff; + } else { + /* video memory */ + if ((s->gr[0x0B] & 0x14) == 0x14) { + addr <<= 4; + } else if (s->gr[0x0B] & 0x02) { + addr <<= 3; + } + addr &= s->cirrus_addr_mask; + ret = *(s->vram_ptr + addr); + } + + return ret; +} + +static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_linear_readb(opaque, addr) << 8; + v |= cirrus_linear_readb(opaque, addr + 1); +#else + v = cirrus_linear_readb(opaque, addr); + v |= cirrus_linear_readb(opaque, addr + 1) << 8; +#endif + return v; +} + +static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_linear_readb(opaque, addr) << 24; + v |= cirrus_linear_readb(opaque, addr + 1) << 16; + v |= cirrus_linear_readb(opaque, addr + 2) << 8; + v |= cirrus_linear_readb(opaque, addr + 3); +#else + v = cirrus_linear_readb(opaque, addr); + v |= cirrus_linear_readb(opaque, addr + 1) << 8; + v |= cirrus_linear_readb(opaque, addr + 2) << 16; + v |= cirrus_linear_readb(opaque, addr + 3) << 24; +#endif + return v; +} + +static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + unsigned mode; + + addr &= s->cirrus_addr_mask; + + if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & 0x1fff00) == 0x1fff00)) { + /* memory-mapped I/O */ + cirrus_mmio_blt_write(s, addr & 0xff, val); + } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { + /* bitblt */ + *s->cirrus_srcptr++ = (uint8_t) val; + if (s->cirrus_srcptr == s->cirrus_srcptr_end) { + cirrus_bitblt_cputovideo_next(s); + } + } else { + /* video memory */ + if ((s->gr[0x0B] & 0x14) == 0x14) { + addr <<= 4; + } else if (s->gr[0x0B] & 0x02) { + addr <<= 3; + } + addr &= s->cirrus_addr_mask; + + mode = s->gr[0x05] & 0x7; + if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { + *(s->vram_ptr + addr) = (uint8_t) val; + cpu_physical_memory_set_dirty(s->vram_offset + addr); + } else { + if ((s->gr[0x0B] & 0x14) != 0x14) { + cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val); + } else { + cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val); + } + } + } +} + +static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff); + cirrus_linear_writeb(opaque, addr + 1, val & 0xff); +#else + cirrus_linear_writeb(opaque, addr, val & 0xff); + cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff); +#endif +} + +static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff); + cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff); + cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff); + cirrus_linear_writeb(opaque, addr + 3, val & 0xff); +#else + cirrus_linear_writeb(opaque, addr, val & 0xff); + cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff); + cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff); + cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff); +#endif +} + + +static CPUReadMemoryFunc *cirrus_linear_read[3] = { + cirrus_linear_readb, + cirrus_linear_readw, + cirrus_linear_readl, +}; + +static CPUWriteMemoryFunc *cirrus_linear_write[3] = { + cirrus_linear_writeb, + cirrus_linear_writew, + cirrus_linear_writel, +}; + +/*************************************** + * + * memory-mapped I/O access + * + ***************************************/ + +static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= CIRRUS_PNPMMIO_SIZE - 1; + /* ??? Does CLGD5430 have memory-mapped VGA registers ??? */ + return (addr >= 0x100) ? + cirrus_mmio_blt_read(s, addr - 0x100) : + cirrus_mmio_vga_read(s, addr); +} + +static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_mmio_readb(opaque, addr) << 8; + v |= cirrus_mmio_readb(opaque, addr + 1); +#else + v = cirrus_mmio_readb(opaque, addr); + v |= cirrus_mmio_readb(opaque, addr + 1) << 8; +#endif + return v; +} + +static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_mmio_readb(opaque, addr) << 24; + v |= cirrus_mmio_readb(opaque, addr + 1) << 16; + v |= cirrus_mmio_readb(opaque, addr + 2) << 8; + v |= cirrus_mmio_readb(opaque, addr + 3); +#else + v = cirrus_mmio_readb(opaque, addr); + v |= cirrus_mmio_readb(opaque, addr + 1) << 8; + v |= cirrus_mmio_readb(opaque, addr + 2) << 16; + v |= cirrus_mmio_readb(opaque, addr + 3) << 24; +#endif + return v; +} + +static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= CIRRUS_PNPMMIO_SIZE - 1; + /* ??? Does CLGD5430 have memory-mapped VGA registers ??? */ + if (addr >= 0x100) { + cirrus_mmio_blt_write(s, addr - 0x100, val); + } else { + cirrus_mmio_vga_write(s, addr, val); + } +} + +static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff); + cirrus_mmio_writeb(opaque, addr + 1, val & 0xff); +#else + cirrus_mmio_writeb(opaque, addr, val & 0xff); + cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); +#endif +} + +static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff); + cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff); + cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff); + cirrus_mmio_writeb(opaque, addr + 3, val & 0xff); +#else + cirrus_mmio_writeb(opaque, addr, val & 0xff); + cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); + cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff); + cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff); +#endif +} + + +static CPUReadMemoryFunc *cirrus_mmio_read[3] = { + cirrus_mmio_readb, + cirrus_mmio_readw, + cirrus_mmio_readl, +}; + +static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { + cirrus_mmio_writeb, + cirrus_mmio_writew, + cirrus_mmio_writel, +}; + +/* I/O ports */ + +static uint32_t vga_ioport_read(void *opaque, uint32_t addr) +{ + CirrusVGAState *s = opaque; + int val, index; + + /* check port range access depending on color/monochrome mode */ + if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) + || (addr >= 0x3d0 && addr <= 0x3df + && !(s->msr & MSR_COLOR_EMULATION))) { + val = 0xff; + } else { + switch (addr) { + case 0x3c0: + if (s->ar_flip_flop == 0) { + val = s->ar_index; + } else { + val = 0; + } + break; + case 0x3c1: + index = s->ar_index & 0x1f; + if (index < 21) + val = s->ar[index]; + else + val = 0; + break; + case 0x3c2: + val = s->st00; + break; + case 0x3c4: + val = s->sr_index; + break; + case 0x3c5: + if (cirrus_hook_read_sr(s, s->sr_index, &val)) + break; + val = s->sr[s->sr_index]; +#ifdef DEBUG_VGA_REG + printf("vga: read SR%x = 0x%02x\n", s->sr_index, val); +#endif + break; + case 0x3c6: + cirrus_read_hidden_dac(s, &val); + break; + case 0x3c7: + val = s->dac_state; + break; + case 0x3c9: + if (cirrus_hook_read_palette(s, &val)) + break; + val = s->palette[s->dac_read_index * 3 + s->dac_sub_index]; + if (++s->dac_sub_index == 3) { + s->dac_sub_index = 0; + s->dac_read_index++; + } + break; + case 0x3ca: + val = s->fcr; + break; + case 0x3cc: + val = s->msr; + break; + case 0x3ce: + val = s->gr_index; + break; + case 0x3cf: + if (cirrus_hook_read_gr(s, s->gr_index, &val)) + break; + val = s->gr[s->gr_index]; +#ifdef DEBUG_VGA_REG + printf("vga: read GR%x = 0x%02x\n", s->gr_index, val); +#endif + break; + case 0x3b4: + case 0x3d4: + val = s->cr_index; + break; + case 0x3b5: + case 0x3d5: + if (cirrus_hook_read_cr(s, s->cr_index, &val)) + break; + val = s->cr[s->cr_index]; +#ifdef DEBUG_VGA_REG + printf("vga: read CR%x = 0x%02x\n", s->cr_index, val); +#endif +#ifdef DEBUG_S3 + if (s->cr_index >= 0x20) + printf("S3: CR read index=0x%x val=0x%x\n", + s->cr_index, val); +#endif + break; + case 0x3ba: + case 0x3da: + /* just toggle to fool polling */ + s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; + val = s->st01; + s->ar_flip_flop = 0; + break; + default: + val = 0x00; + break; + } + } +#if defined(DEBUG_VGA) + printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val); +#endif + return val; +} + +static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + CirrusVGAState *s = opaque; + int index; + + /* check port range access depending on color/monochrome mode */ + if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) + || (addr >= 0x3d0 && addr <= 0x3df + && !(s->msr & MSR_COLOR_EMULATION))) + return; + +#ifdef DEBUG_VGA + printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val); +#endif + + switch (addr) { + case 0x3c0: + if (s->ar_flip_flop == 0) { + val &= 0x3f; + s->ar_index = val; + } else { + index = s->ar_index & 0x1f; + switch (index) { + case 0x00 ... 0x0f: + s->ar[index] = val & 0x3f; + break; + case 0x10: + s->ar[index] = val & ~0x10; + break; + case 0x11: + s->ar[index] = val; + break; + case 0x12: + s->ar[index] = val & ~0xc0; + break; + case 0x13: + s->ar[index] = val & ~0xf0; + break; + case 0x14: + s->ar[index] = val & ~0xf0; + break; + default: + break; + } + } + s->ar_flip_flop ^= 1; + break; + case 0x3c2: + s->msr = val & ~0x10; + break; + case 0x3c4: + s->sr_index = val; + break; + case 0x3c5: + if (cirrus_hook_write_sr(s, s->sr_index, val)) + break; +#ifdef DEBUG_VGA_REG + printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); +#endif + s->sr[s->sr_index] = val & sr_mask[s->sr_index]; + break; + case 0x3c6: + cirrus_write_hidden_dac(s, val); + break; + case 0x3c7: + s->dac_read_index = val; + s->dac_sub_index = 0; + s->dac_state = 3; + break; + case 0x3c8: + s->dac_write_index = val; + s->dac_sub_index = 0; + s->dac_state = 0; + break; + case 0x3c9: + if (cirrus_hook_write_palette(s, val)) + break; + s->dac_cache[s->dac_sub_index] = val; + if (++s->dac_sub_index == 3) { + memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3); + s->dac_sub_index = 0; + s->dac_write_index++; + } + break; + case 0x3ce: + s->gr_index = val; + break; + case 0x3cf: + if (cirrus_hook_write_gr(s, s->gr_index, val)) + break; +#ifdef DEBUG_VGA_REG + printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); +#endif + s->gr[s->gr_index] = val & gr_mask[s->gr_index]; + break; + case 0x3b4: + case 0x3d4: + s->cr_index = val; + break; + case 0x3b5: + case 0x3d5: + if (cirrus_hook_write_cr(s, s->cr_index, val)) + break; +#ifdef DEBUG_VGA_REG + printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); +#endif + /* handle CR0-7 protection */ + if ((s->cr[11] & 0x80) && s->cr_index <= 7) { + /* can always write bit 4 of CR7 */ + if (s->cr_index == 7) + s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); + return; + } + switch (s->cr_index) { + case 0x01: /* horizontal display end */ + case 0x07: + case 0x09: + case 0x0c: + case 0x0d: + case 0x12: /* veritcal display end */ + s->cr[s->cr_index] = val; + break; + + default: + s->cr[s->cr_index] = val; + break; + } + break; + case 0x3ba: + case 0x3da: + s->fcr = val & 0x10; + break; + } +} + +/*************************************** + * + * initialize + * + ***************************************/ + +static void cirrus_init_common(CirrusVGAState * s) +{ + int vga_io_memory; + + register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); + + register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s); + register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s); + register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s); + register_ioport_write(0x3da, 1, 1, vga_ioport_write, s); + + register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s); + + register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s); + register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s); + register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); + register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); + + vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read, + cirrus_vga_mem_write, s); + cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, + vga_io_memory); + + s->sr[0x06] = 0x0f; + s->sr[0x0F] = CIRRUS_MEMSIZE_2M; + s->sr[0x1F] = 0x22; // MemClock + + s->cr[0x27] = CIRRUS_ID_CLGD5430; + + s->cirrus_hidden_dac_lockindex = 5; + s->cirrus_hidden_dac_data = 0; + + /* I/O handler for LFB */ + s->cirrus_linear_io_addr = + cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write, + s); + /* I/O handler for memory-mapped I/O */ + s->cirrus_mmio_io_addr = + cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s); + + /* XXX: s->vram_size must be a power of two */ + s->cirrus_addr_mask = s->vram_size - 1; + + s->get_bpp = cirrus_get_bpp; + s->get_offsets = cirrus_get_offsets; +} + +/*************************************** + * + * ISA bus support + * + ***************************************/ + +void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size) +{ + CirrusVGAState *s; + + s = qemu_mallocz(sizeof(CirrusVGAState)); + + vga_common_init((VGAState *)s, + ds, vga_ram_base, vga_ram_offset, vga_ram_size); + cirrus_init_common(s); + s->sr[0x17] = CIRRUS_BUSTYPE_ISA; + /* XXX ISA-LFB support */ +} + +/*************************************** + * + * PCI bus support + * + ***************************************/ + +static void cirrus_pci_lfb_map(PCIDevice *d, int region_num, + uint32_t addr, uint32_t size, int type) +{ + CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga; + + cpu_register_physical_memory(addr, s->vram_size, + s->cirrus_linear_io_addr); +} + +static void cirrus_pci_mmio_map(PCIDevice *d, int region_num, + uint32_t addr, uint32_t size, int type) +{ + CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga; + + cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE, + s->cirrus_mmio_io_addr); +} + +void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size) +{ + PCICirrusVGAState *d; + uint8_t *pci_conf; + CirrusVGAState *s; + + /* setup PCI configuration registers */ + d = (PCICirrusVGAState *)pci_register_device("Cirrus VGA", + sizeof(PCICirrusVGAState), + 0, -1, NULL, NULL); + pci_conf = d->dev.config; + pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff); + pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8); + pci_conf[0x02] = (uint8_t) (PCI_DEVICE_CLGD5430 & 0xff); + pci_conf[0x03] = (uint8_t) (PCI_DEVICE_CLGD5430 >> 8); + pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS; + pci_conf[0x0a] = PCI_CLASS_SUB_VGA; + pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY; + pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h; + + /* setup VGA */ + s = &d->cirrus_vga; + vga_common_init((VGAState *)s, + ds, vga_ram_base, vga_ram_offset, vga_ram_size); + cirrus_init_common(s); + s->sr[0x17] = CIRRUS_BUSTYPE_PCI; + + /* setup memory space */ + /* memory #0 LFB */ + /* memory #1 memory-mapped I/O */ + /* XXX: s->vram_size must be a power of two */ + pci_register_io_region((PCIDevice *)d, 0, s->vram_size, + PCI_ADDRESS_SPACE_MEM, cirrus_pci_lfb_map); + pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, + PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map); + /* XXX: ROM BIOS */ +} -- cgit v1.2.3 From d6bfa22f729500d1bc7f90a560ef278c22a2e291 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 10:32:30 +0000 Subject: Cirrus VGA emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@892 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 ++- vl.h | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index ac52093d1..c8ef71682 100644 --- a/Makefile.target +++ b/Makefile.target @@ -237,7 +237,8 @@ VL_OBJS=vl.o osdep.o block.o monitor.o pci.o ifeq ($(TARGET_ARCH), i386) # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o +VL_OBJS+= cirrus_vga.o endif ifeq ($(TARGET_ARCH), ppc) # Generic PPC support diff --git a/vl.h b/vl.h index 9dbb5b41a..1b5c3cfd4 100644 --- a/vl.h +++ b/vl.h @@ -481,6 +481,13 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, void vga_update_display(void); void vga_screen_dump(const char *filename); +/* cirrus_vga.c */ +void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); + +void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); + /* sdl.c */ void sdl_display_init(DisplayState *ds); -- cgit v1.2.3 From 7b17d41e968bd0826b914ec7ed036cf9c6a51615 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 11:06:28 +0000 Subject: Cirrus VGA display fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@893 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 5ec78ed24..4adba3cdd 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -147,7 +147,7 @@ static uint32_t expand4[256]; static uint16_t expand2[256]; static uint8_t expand4to8[16]; -VGAState vga_state; +VGAState *vga_state; int vga_io_memory; static uint32_t vga_ioport_read(void *opaque, uint32_t addr) @@ -1507,7 +1507,7 @@ static void vga_draw_blank(VGAState *s, int full_update) void vga_update_display(void) { - VGAState *s = &vga_state; + VGAState *s = vga_state; int full_update, graphic_mode; if (s->ds->depth == 0) { @@ -1674,7 +1674,7 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) static void vga_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { - VGAState *s = &vga_state; + VGAState *s = vga_state; cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); } @@ -1715,6 +1715,8 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, s->ds = ds; s->get_bpp = vga_get_bpp; s->get_offsets = vga_get_offsets; + /* XXX: currently needed for display */ + vga_state = s; } @@ -1722,7 +1724,11 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size, int is_pci) { - VGAState *s = &vga_state; + VGAState *s; + + s = qemu_mallocz(sizeof(VGAState)); + if (!s) + return -1; vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); @@ -1857,7 +1863,7 @@ static int ppm_save(const char *filename, uint8_t *data, available */ void vga_screen_dump(const char *filename) { - VGAState *s = &vga_state; + VGAState *s = vga_state; DisplayState *saved_ds, ds1, *ds = &ds1; /* XXX: this is a little hackish */ -- cgit v1.2.3 From e36f36e15fbd0fca6074461a256a9c9ab4ea0afa Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 12:47:01 +0000 Subject: mmio support for vga registers - line offset fix - (aka XFree86 4.3.0 fixes) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@894 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 237 ++++++++++++++++++++++++++------------------------------ 1 file changed, 108 insertions(+), 129 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 39485bb71..0bf8e9f17 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -25,6 +25,8 @@ #include "vl.h" #include "vga_int.h" +//#define DEBUG_CIRRUS + /*************************************** * * definitions @@ -204,7 +206,7 @@ typedef void (*cirrus_bitblt_handler_t) (void *opaque); typedef struct CirrusVGAState { /* XXX: we use the anonymous struct/union gcc 3.x extension */ - struct VGAState; + __extension__ struct VGAState; int cirrus_linear_io_addr; int cirrus_mmio_io_addr; @@ -1036,7 +1038,7 @@ static void cirrus_get_offsets(VGAState *s1, uint32_t line_offset; line_offset = s->cr[0x13] - | ((s->cr[0x1b] & 0x10) << 8); + | ((s->cr[0x1b] & 0x10) << 4); line_offset <<= 3; *pline_offset = line_offset; @@ -1819,31 +1821,6 @@ static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address, } } -/*************************************** - * - * memory-mapped I/O (vga) - * - ***************************************/ - -static uint8_t cirrus_mmio_vga_read(CirrusVGAState * s, unsigned address) -{ -#ifdef DEBUG_CIRRUS - printf("cirrus: mmio vga read (unimplemented) - address 0x%04x\n", - address); -#endif - return 0xff; -} - -static void cirrus_mmio_vga_write(CirrusVGAState * s, unsigned address, - uint8_t value) -{ -#ifdef DEBUG_CIRRUS - printf - ("cirrus: mmio vga write (unimplemented) - address 0x%04x, value 0x%02x\n", - address, value); -#endif -} - /*************************************** * * write mode 4/5 @@ -2221,108 +2198,6 @@ static CPUWriteMemoryFunc *cirrus_linear_write[3] = { cirrus_linear_writel, }; -/*************************************** - * - * memory-mapped I/O access - * - ***************************************/ - -static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - - addr &= CIRRUS_PNPMMIO_SIZE - 1; - /* ??? Does CLGD5430 have memory-mapped VGA registers ??? */ - return (addr >= 0x100) ? - cirrus_mmio_blt_read(s, addr - 0x100) : - cirrus_mmio_vga_read(s, addr); -} - -static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_mmio_readb(opaque, addr) << 8; - v |= cirrus_mmio_readb(opaque, addr + 1); -#else - v = cirrus_mmio_readb(opaque, addr); - v |= cirrus_mmio_readb(opaque, addr + 1) << 8; -#endif - return v; -} - -static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_mmio_readb(opaque, addr) << 24; - v |= cirrus_mmio_readb(opaque, addr + 1) << 16; - v |= cirrus_mmio_readb(opaque, addr + 2) << 8; - v |= cirrus_mmio_readb(opaque, addr + 3); -#else - v = cirrus_mmio_readb(opaque, addr); - v |= cirrus_mmio_readb(opaque, addr + 1) << 8; - v |= cirrus_mmio_readb(opaque, addr + 2) << 16; - v |= cirrus_mmio_readb(opaque, addr + 3) << 24; -#endif - return v; -} - -static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - - addr &= CIRRUS_PNPMMIO_SIZE - 1; - /* ??? Does CLGD5430 have memory-mapped VGA registers ??? */ - if (addr >= 0x100) { - cirrus_mmio_blt_write(s, addr - 0x100, val); - } else { - cirrus_mmio_vga_write(s, addr, val); - } -} - -static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, val & 0xff); -#else - cirrus_mmio_writeb(opaque, addr, val & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif -} - -static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_mmio_writeb(opaque, addr + 3, val & 0xff); -#else - cirrus_mmio_writeb(opaque, addr, val & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); - cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff); - cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif -} - - -static CPUReadMemoryFunc *cirrus_mmio_read[3] = { - cirrus_mmio_readb, - cirrus_mmio_readw, - cirrus_mmio_readl, -}; - -static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { - cirrus_mmio_writeb, - cirrus_mmio_writew, - cirrus_mmio_writel, -}; - /* I/O ports */ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) @@ -2568,6 +2443,110 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } +/*************************************** + * + * memory-mapped I/O access + * + ***************************************/ + +static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= CIRRUS_PNPMMIO_SIZE - 1; + + if (addr >= 0x100) { + return cirrus_mmio_blt_read(s, addr - 0x100); + } else { + return vga_ioport_read(s, addr + 0x3c0); + } +} + +static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_mmio_readb(opaque, addr) << 8; + v |= cirrus_mmio_readb(opaque, addr + 1); +#else + v = cirrus_mmio_readb(opaque, addr); + v |= cirrus_mmio_readb(opaque, addr + 1) << 8; +#endif + return v; +} + +static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_mmio_readb(opaque, addr) << 24; + v |= cirrus_mmio_readb(opaque, addr + 1) << 16; + v |= cirrus_mmio_readb(opaque, addr + 2) << 8; + v |= cirrus_mmio_readb(opaque, addr + 3); +#else + v = cirrus_mmio_readb(opaque, addr); + v |= cirrus_mmio_readb(opaque, addr + 1) << 8; + v |= cirrus_mmio_readb(opaque, addr + 2) << 16; + v |= cirrus_mmio_readb(opaque, addr + 3) << 24; +#endif + return v; +} + +static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= CIRRUS_PNPMMIO_SIZE - 1; + + if (addr >= 0x100) { + cirrus_mmio_blt_write(s, addr - 0x100, val); + } else { + vga_ioport_write(s, addr + 0x3c0, val); + } +} + +static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff); + cirrus_mmio_writeb(opaque, addr + 1, val & 0xff); +#else + cirrus_mmio_writeb(opaque, addr, val & 0xff); + cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); +#endif +} + +static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff); + cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff); + cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff); + cirrus_mmio_writeb(opaque, addr + 3, val & 0xff); +#else + cirrus_mmio_writeb(opaque, addr, val & 0xff); + cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); + cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff); + cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff); +#endif +} + + +static CPUReadMemoryFunc *cirrus_mmio_read[3] = { + cirrus_mmio_readb, + cirrus_mmio_readw, + cirrus_mmio_readl, +}; + +static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { + cirrus_mmio_writeb, + cirrus_mmio_writew, + cirrus_mmio_writel, +}; + /*************************************** * * initialize -- cgit v1.2.3 From 358c6407216f4c3b86f91352f7a1fdc19b4494e4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 12:49:34 +0000 Subject: host bridge config fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@895 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index d5b8d4f44..1e8466ef1 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -446,10 +446,9 @@ void i440fx_init(void) d->config[0x02] = 0x37; // device_id d->config[0x03] = 0x12; d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x04; // class_sub = pci2pci + d->config[0x0a] = 0x00; // class_sub = host2pci d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0c] = 0x01; // line_size in 32 bit words - d->config[0x0e] = 0x01; // header_type + d->config[0x0e] = 0x00; // header_type } /* PIIX3 PCI to ISA bridge */ -- cgit v1.2.3 From 4e3e9d0b4d31cc7966147543634c3476aec52d21 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 13:18:45 +0000 Subject: avoid using anonymous struct extension (not supported by all gcc 3.x) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@896 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 3 +- hw/vga_int.h | 117 ++++++++++++++++++++++++++++++++------------------------ 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 0bf8e9f17..eae0804ea 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -205,8 +205,7 @@ typedef void (*cirrus_bitblt_rop_t) (uint8_t * dst, const uint8_t * src, typedef void (*cirrus_bitblt_handler_t) (void *opaque); typedef struct CirrusVGAState { - /* XXX: we use the anonymous struct/union gcc 3.x extension */ - __extension__ struct VGAState; + VGA_STATE_COMMON int cirrus_linear_io_addr; int cirrus_mmio_io_addr; diff --git a/hw/vga_int.h b/hw/vga_int.h index 73618ab59..8fb78a0df 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -56,61 +56,76 @@ #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 -typedef struct VGAState { - uint8_t *vram_ptr; - unsigned long vram_offset; - unsigned int vram_size; - uint32_t latch; - uint8_t sr_index; - uint8_t sr[256]; - uint8_t gr_index; - uint8_t gr[256]; - uint8_t ar_index; - uint8_t ar[21]; - int ar_flip_flop; - uint8_t cr_index; - uint8_t cr[256]; /* CRT registers */ - uint8_t msr; /* Misc Output Register */ - uint8_t fcr; /* Feature Control Register */ - uint8_t st00; /* status 0 */ - uint8_t st01; /* status 1 */ - uint8_t dac_state; - uint8_t dac_sub_index; - uint8_t dac_read_index; - uint8_t dac_write_index; - uint8_t dac_cache[3]; /* used when writing */ - uint8_t palette[768]; - int32_t bank_offset; - int (*get_bpp)(struct VGAState *s); - void (*get_offsets)(struct VGAState *s, - uint32_t *pline_offset, - uint32_t *pstart_addr); #ifdef CONFIG_BOCHS_VBE - uint16_t vbe_index; - uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; - uint32_t vbe_start_addr; - uint32_t vbe_line_offset; + +#define VGA_STATE_COMMON_BOCHS_VBE \ + uint16_t vbe_index; \ + uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; \ + uint32_t vbe_start_addr; \ + uint32_t vbe_line_offset; \ uint32_t vbe_bank_mask; -#endif - /* display refresh support */ - DisplayState *ds; - uint32_t font_offsets[2]; - int graphic_mode; - uint8_t shift_control; - uint8_t double_scan; - uint32_t line_offset; - uint32_t line_compare; - uint32_t start_addr; - uint8_t last_cw, last_ch; - uint32_t last_width, last_height; /* in chars or pixels */ - uint32_t last_scr_width, last_scr_height; /* in pixels */ - uint8_t cursor_start, cursor_end; - uint32_t cursor_offset; - unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b); - /* tell for each page if it has been updated since the last time */ - uint32_t last_palette[256]; + +#else + +#define VGA_STATE_COMMON_BOCHS_VBE + +#endif /* !CONFIG_BOCHS_VBE */ + #define CH_ATTR_SIZE (160 * 100) + +#define VGA_STATE_COMMON \ + uint8_t *vram_ptr; \ + unsigned long vram_offset; \ + unsigned int vram_size; \ + uint32_t latch; \ + uint8_t sr_index; \ + uint8_t sr[256]; \ + uint8_t gr_index; \ + uint8_t gr[256]; \ + uint8_t ar_index; \ + uint8_t ar[21]; \ + int ar_flip_flop; \ + uint8_t cr_index; \ + uint8_t cr[256]; /* CRT registers */ \ + uint8_t msr; /* Misc Output Register */ \ + uint8_t fcr; /* Feature Control Register */ \ + uint8_t st00; /* status 0 */ \ + uint8_t st01; /* status 1 */ \ + uint8_t dac_state; \ + uint8_t dac_sub_index; \ + uint8_t dac_read_index; \ + uint8_t dac_write_index; \ + uint8_t dac_cache[3]; /* used when writing */ \ + uint8_t palette[768]; \ + int32_t bank_offset; \ + int (*get_bpp)(struct VGAState *s); \ + void (*get_offsets)(struct VGAState *s, \ + uint32_t *pline_offset, \ + uint32_t *pstart_addr); \ + VGA_STATE_COMMON_BOCHS_VBE \ + /* display refresh support */ \ + DisplayState *ds; \ + uint32_t font_offsets[2]; \ + int graphic_mode; \ + uint8_t shift_control; \ + uint8_t double_scan; \ + uint32_t line_offset; \ + uint32_t line_compare; \ + uint32_t start_addr; \ + uint8_t last_cw, last_ch; \ + uint32_t last_width, last_height; /* in chars or pixels */ \ + uint32_t last_scr_width, last_scr_height; /* in pixels */ \ + uint8_t cursor_start, cursor_end; \ + uint32_t cursor_offset; \ + unsigned int (*rgb_to_pixel)(unsigned int r, \ + unsigned int g, unsigned b); \ + /* tell for each page if it has been updated since the last time */ \ + uint32_t last_palette[256]; \ uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ + + +typedef struct VGAState { + VGA_STATE_COMMON } VGAState; void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, -- cgit v1.2.3 From 1f04275ec1d2db4baab3fe638ccbaa5862cdc0df Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 13:46:47 +0000 Subject: -cirrusvga option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@897 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 14 ++++++++++++-- vl.c | 12 +++++++++--- vl.h | 1 + 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index eef120e0e..788854b29 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -396,8 +396,18 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); - vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, pci_enabled); + if (cirrus_vga_enabled) { + if (pci_enabled) { + pci_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + } else { + isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + } + } else { + vga_initialize(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size, pci_enabled); + } rtc_state = rtc_init(0x70, 8); register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); diff --git a/vl.c b/vl.c index b424ed11e..cdebcc203 100644 --- a/vl.c +++ b/vl.c @@ -130,6 +130,7 @@ int audio_enabled = 0; int pci_enabled = 0; int prep_enabled = 0; int rtc_utc = 1; +int cirrus_vga_enabled = 0; /***********************************************************/ /* x86 ISA bus support */ @@ -2053,6 +2054,7 @@ enum { QEMU_OPTION_pci, QEMU_OPTION_prep, QEMU_OPTION_localtime, + QEMU_OPTION_cirrusvga, }; typedef struct QEMUOption { @@ -2097,13 +2099,14 @@ const QEMUOption qemu_options[] = { { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, { "L", HAS_ARG, QEMU_OPTION_L }, { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, - - /* temporary options */ - { "pci", 0, QEMU_OPTION_pci }, #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, #endif { "localtime", 0, QEMU_OPTION_localtime }, + + /* temporary options */ + { "pci", 0, QEMU_OPTION_pci }, + { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, { NULL }, }; @@ -2383,6 +2386,9 @@ int main(int argc, char **argv) case QEMU_OPTION_localtime: rtc_utc = 0; break; + case QEMU_OPTION_cirrusvga: + cirrus_vga_enabled = 1; + break; } } } diff --git a/vl.h b/vl.h index 1b5c3cfd4..fc16f47c6 100644 --- a/vl.h +++ b/vl.h @@ -171,6 +171,7 @@ extern int audio_enabled; extern int ram_size; extern int bios_size; extern int rtc_utc; +extern int cirrus_vga_enabled; /* XXX: make it dynamic */ #if defined (TARGET_PPC) -- cgit v1.2.3 From aeb3c85f59bc35371c76f285f0761f01245dc3cd Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 14:26:11 +0000 Subject: Cirrus fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@898 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 77 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index eae0804ea..0a408aa13 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -1,8 +1,8 @@ /* - * QEMU Cirrus VGA Emulator. + * QEMU Cirrus CLGD 54xx VGA Emulator. * * Copyright (c) 2004 Fabrice Bellard - * Copyright (c) 2004 Suzu + * Copyright (c) 2004 Makoto Suzuki (suzu) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,6 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +/* + * Reference: Finn Thogersons' VGADOC4b + * available at http://home.worldonline.dk/~finth/ + */ #include "vl.h" #include "vga_int.h" @@ -478,8 +482,8 @@ cirrus_colorexpand_8(CirrusVGAState * s, uint8_t * dst, unsigned bitmask; int srcskipleft = 0; - colors[0] = s->gr[0x00]; - colors[1] = s->gr[0x01]; + colors[0] = s->cirrus_shadow_gr0; + colors[1] = s->cirrus_shadow_gr1; bitmask = 0x80 >> srcskipleft; bits = *src++; @@ -504,9 +508,9 @@ cirrus_colorexpand_16(CirrusVGAState * s, uint8_t * dst, unsigned index; int srcskipleft = 0; - colors[0][0] = s->gr[0x00]; + colors[0][0] = s->cirrus_shadow_gr0; colors[0][1] = s->gr[0x10]; - colors[1][0] = s->gr[0x01]; + colors[1][0] = s->cirrus_shadow_gr1; colors[1][1] = s->gr[0x11]; bitmask = 0x80 >> srcskipleft; @@ -534,10 +538,10 @@ cirrus_colorexpand_24(CirrusVGAState * s, uint8_t * dst, unsigned index; int srcskipleft = 0; - colors[0][0] = s->gr[0x00]; + colors[0][0] = s->cirrus_shadow_gr0; colors[0][1] = s->gr[0x10]; colors[0][2] = s->gr[0x12]; - colors[1][0] = s->gr[0x01]; + colors[1][0] = s->cirrus_shadow_gr1; colors[1][1] = s->gr[0x11]; colors[1][2] = s->gr[0x13]; @@ -567,11 +571,11 @@ cirrus_colorexpand_32(CirrusVGAState * s, uint8_t * dst, unsigned index; int srcskipleft = 0; - colors[0][0] = s->gr[0x00]; + colors[0][0] = s->cirrus_shadow_gr0; colors[0][1] = s->gr[0x10]; colors[0][2] = s->gr[0x12]; colors[0][3] = s->gr[0x14]; - colors[1][0] = s->gr[0x01]; + colors[1][0] = s->cirrus_shadow_gr1; colors[1][1] = s->gr[0x11]; colors[1][2] = s->gr[0x13]; colors[1][3] = s->gr[0x15]; @@ -1103,7 +1107,7 @@ static int cirrus_get_bpp(VGAState *s1) } } else { /* VGA */ - ret = 8; + ret = 0; } return ret; @@ -1172,16 +1176,6 @@ cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value) case 0x06: // Unlock Cirrus extensions *reg_value = s->sr[reg_index]; break; - case 0x05: // ??? - case 0x07: // Extended Sequencer Mode - case 0x08: // EEPROM Control - case 0x09: // Scratch Register 0 - case 0x0a: // Scratch Register 1 - case 0x0b: // VCLK 0 - case 0x0c: // VCLK 1 - case 0x0d: // VCLK 2 - case 0x0e: // VCLK 3 - case 0x0f: // DRAM Control case 0x10: case 0x30: case 0x50: @@ -1190,6 +1184,8 @@ cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value) case 0xb0: case 0xd0: case 0xf0: // Graphics Cursor X + *reg_value = s->sr[0x10]; + break; case 0x11: case 0x31: case 0x51: @@ -1197,6 +1193,18 @@ cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value) case 0x91: case 0xb1: case 0xd1: + *reg_value = s->sr[0x11]; + break; + case 0x05: // ??? + case 0x07: // Extended Sequencer Mode + case 0x08: // EEPROM Control + case 0x09: // Scratch Register 0 + case 0x0a: // Scratch Register 1 + case 0x0b: // VCLK 0 + case 0x0c: // VCLK 1 + case 0x0d: // VCLK 2 + case 0x0e: // VCLK 3 + case 0x0f: // DRAM Control case 0xf1: // Graphics Cursor Y case 0x12: // Graphics Cursor Attribute case 0x13: // Graphics Cursor Pattern Address @@ -1387,6 +1395,12 @@ static int cirrus_hook_read_gr(CirrusVGAState * s, unsigned reg_index, int *reg_value) { switch (reg_index) { + case 0x00: // Standard VGA, BGCOLOR 0x000000ff + *reg_value = s->cirrus_shadow_gr0; + return CIRRUS_HOOK_HANDLED; + case 0x01: // Standard VGA, FGCOLOR 0x000000ff + *reg_value = s->cirrus_shadow_gr1; + return CIRRUS_HOOK_HANDLED; case 0x02: // Standard VGA case 0x03: // Standard VGA case 0x04: // Standard VGA @@ -1416,10 +1430,10 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) { switch (reg_index) { case 0x00: // Standard VGA, BGCOLOR 0x000000ff - s->gr[0x00] = reg_value; + s->cirrus_shadow_gr0 = reg_value; return CIRRUS_HOOK_NOT_HANDLED; case 0x01: // Standard VGA, FGCOLOR 0x000000ff - s->gr[0x01] = reg_value; + s->cirrus_shadow_gr1 = reg_value; return CIRRUS_HOOK_NOT_HANDLED; case 0x02: // Standard VGA case 0x03: // Standard VGA @@ -1840,9 +1854,9 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, dst = s->vram_ptr + offset; for (x = 0; x < 8; x++) { if (val & 0x80) { - *dst++ = s->gr[0x01]; + *dst++ = s->cirrus_shadow_gr1; } else if (mode == 5) { - *dst++ = s->gr[0x00]; + *dst++ = s->cirrus_shadow_gr0; } val <<= 1; } @@ -1862,10 +1876,10 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, dst = s->vram_ptr + offset; for (x = 0; x < 8; x++) { if (val & 0x80) { - *dst++ = s->gr[0x01]; + *dst++ = s->cirrus_shadow_gr1; *dst++ = s->gr[0x11]; } else if (mode == 5) { - *dst++ = s->gr[0x00]; + *dst++ = s->cirrus_shadow_gr0; *dst++ = s->gr[0x10]; } val <<= 1; @@ -1891,6 +1905,8 @@ static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr) return vga_mem_readb(s, addr); } + addr &= 0x1ffff; + if (addr < 0x10000) { /* XXX handle bitblt */ /* video memory */ @@ -1965,6 +1981,8 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, return; } + addr &= 0x1ffff; + if (addr < 0x10000) { if (s->cirrus_srcptr != s->cirrus_srcptr_end) { /* bitblt */ @@ -2282,11 +2300,6 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) val = s->cr[s->cr_index]; #ifdef DEBUG_VGA_REG printf("vga: read CR%x = 0x%02x\n", s->cr_index, val); -#endif -#ifdef DEBUG_S3 - if (s->cr_index >= 0x20) - printf("S3: CR read index=0x%x val=0x%x\n", - s->cr_index, val); #endif break; case 0x3ba: -- cgit v1.2.3 From a21ae81d8ad647cb9b7869367edf646f37e4e4e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 17:59:37 +0000 Subject: change ID to CLGD5446 - added solidfill support - fixed hidden dac access git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@899 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 278 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 205 insertions(+), 73 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 0a408aa13..6305c9493 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -30,6 +30,7 @@ #include "vga_int.h" //#define DEBUG_CIRRUS +//#define DEBUG_BITBLT /*************************************** * @@ -46,8 +47,14 @@ #define CIRRUS_ID_CLGD5428 (0x26<<2) #define CIRRUS_ID_CLGD5430 (0x28<<2) #define CIRRUS_ID_CLGD5434 (0x2A<<2) +#define CIRRUS_ID_CLGD5436 (0x2B<<2) #define CIRRUS_ID_CLGD5446 (0x2E<<2) +/* this define is used to select the exact CLGD implementation we + emulate. */ +//#define CIRRUS_ID CIRRUS_ID_CLGD5430 +#define CIRRUS_ID CIRRUS_ID_CLGD5446 + // sequencer 0x07 #define CIRRUS_SR7_BPP_VGA 0x00 #define CIRRUS_SR7_BPP_SVGA 0x01 @@ -120,6 +127,9 @@ #define CIRRUS_ROP_NOTSRC_OR_DST 0xd6 #define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda +// control 0x33 +#define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 + // memory-mapped IO #define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword #define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword @@ -153,12 +163,10 @@ // PCI 0x00: vendor, 0x02: device #define PCI_VENDOR_CIRRUS 0x1013 -#define PCI_DEVICE_CLGD5430 0x00a0 // CLGD5430 or CLGD5440 -#define PCI_DEVICE_CLGD5434 0x00a8 -#define PCI_DEVICE_CLGD5436 0x00ac -#define PCI_DEVICE_CLGD5446 0x00b8 +#define PCI_DEVICE_ID CIRRUS_ID #define PCI_DEVICE_CLGD5462 0x00d0 #define PCI_DEVICE_CLGD5465 0x00d6 + // PCI 0x04: command(word), 0x06(word): status #define PCI_COMMAND_IOACCESS 0x0001 #define PCI_COMMAND_MEMACCESS 0x0002 @@ -195,7 +203,7 @@ // PCI 0x38: reserved // PCI 0x3c: 0x3c=int-line, 0x3d=int-pin, 0x3e=min-gnt, 0x3f=maax-lat -#define CIRRUS_PNPMMIO_SIZE 0x800 +#define CIRRUS_PNPMMIO_SIZE 0x1000 /* I/O and memory hook */ @@ -264,7 +272,7 @@ static void cirrus_bitblt_reset(CirrusVGAState * s); * ***************************************/ -#define IMPLEMENT_FORWARD_BITBLT(name,opline) \ +#define IMPLEMENT_BITBLT(name,opline) \ static void \ cirrus_bitblt_rop_fwd_##name( \ uint8_t *dst,const uint8_t *src, \ @@ -283,9 +291,8 @@ static void cirrus_bitblt_reset(CirrusVGAState * s); dst += dstpitch; \ src += srcpitch; \ } \ - } - -#define IMPLEMENT_BACKWARD_BITBLT(name,opline) \ + } \ + \ static void \ cirrus_bitblt_rop_bkwd_##name( \ uint8_t *dst,const uint8_t *src, \ @@ -306,39 +313,22 @@ static void cirrus_bitblt_reset(CirrusVGAState * s); } \ } -IMPLEMENT_FORWARD_BITBLT(0, *dst = 0) - IMPLEMENT_FORWARD_BITBLT(src_and_dst, *dst = (*src) & (*dst)) - IMPLEMENT_FORWARD_BITBLT(nop, (void) 0) - IMPLEMENT_FORWARD_BITBLT(src_and_notdst, *dst = (*src) & (~(*dst))) - IMPLEMENT_FORWARD_BITBLT(notdst, *dst = ~(*dst)) - IMPLEMENT_FORWARD_BITBLT(src, *dst = *src) - IMPLEMENT_FORWARD_BITBLT(1, *dst = 0xff) - IMPLEMENT_FORWARD_BITBLT(notsrc_and_dst, *dst = (~(*src)) & (*dst)) - IMPLEMENT_FORWARD_BITBLT(src_xor_dst, *dst = (*src) ^ (*dst)) - IMPLEMENT_FORWARD_BITBLT(src_or_dst, *dst = (*src) | (*dst)) - IMPLEMENT_FORWARD_BITBLT(notsrc_or_notdst, *dst = (~(*src)) | (~(*dst))) - IMPLEMENT_FORWARD_BITBLT(src_notxor_dst, *dst = ~((*src) ^ (*dst))) - IMPLEMENT_FORWARD_BITBLT(src_or_notdst, *dst = (*src) | (~(*dst))) - IMPLEMENT_FORWARD_BITBLT(notsrc, *dst = (~(*src))) - IMPLEMENT_FORWARD_BITBLT(notsrc_or_dst, *dst = (~(*src)) | (*dst)) - IMPLEMENT_FORWARD_BITBLT(notsrc_and_notdst, *dst = (~(*src)) & (~(*dst))) - - IMPLEMENT_BACKWARD_BITBLT(0, *dst = 0) - IMPLEMENT_BACKWARD_BITBLT(src_and_dst, *dst = (*src) & (*dst)) - IMPLEMENT_BACKWARD_BITBLT(nop, (void) 0) - IMPLEMENT_BACKWARD_BITBLT(src_and_notdst, *dst = (*src) & (~(*dst))) - IMPLEMENT_BACKWARD_BITBLT(notdst, *dst = ~(*dst)) - IMPLEMENT_BACKWARD_BITBLT(src, *dst = *src) - IMPLEMENT_BACKWARD_BITBLT(1, *dst = 0xff) - IMPLEMENT_BACKWARD_BITBLT(notsrc_and_dst, *dst = (~(*src)) & (*dst)) - IMPLEMENT_BACKWARD_BITBLT(src_xor_dst, *dst = (*src) ^ (*dst)) - IMPLEMENT_BACKWARD_BITBLT(src_or_dst, *dst = (*src) | (*dst)) - IMPLEMENT_BACKWARD_BITBLT(notsrc_or_notdst, *dst = (~(*src)) | (~(*dst))) - IMPLEMENT_BACKWARD_BITBLT(src_notxor_dst, *dst = ~((*src) ^ (*dst))) - IMPLEMENT_BACKWARD_BITBLT(src_or_notdst, *dst = (*src) | (~(*dst))) - IMPLEMENT_BACKWARD_BITBLT(notsrc, *dst = (~(*src))) - IMPLEMENT_BACKWARD_BITBLT(notsrc_or_dst, *dst = (~(*src)) | (*dst)) - IMPLEMENT_BACKWARD_BITBLT(notsrc_and_notdst, *dst = (~(*src)) & (~(*dst))) +IMPLEMENT_BITBLT(0, *dst = 0) +IMPLEMENT_BITBLT(src_and_dst, *dst = (*src) & (*dst)) +IMPLEMENT_BITBLT(nop, (void) 0) +IMPLEMENT_BITBLT(src_and_notdst, *dst = (*src) & (~(*dst))) +IMPLEMENT_BITBLT(notdst, *dst = ~(*dst)) +IMPLEMENT_BITBLT(src, *dst = *src) +IMPLEMENT_BITBLT(1, *dst = 0xff) +IMPLEMENT_BITBLT(notsrc_and_dst, *dst = (~(*src)) & (*dst)) +IMPLEMENT_BITBLT(src_xor_dst, *dst = (*src) ^ (*dst)) +IMPLEMENT_BITBLT(src_or_dst, *dst = (*src) | (*dst)) +IMPLEMENT_BITBLT(notsrc_or_notdst, *dst = (~(*src)) | (~(*dst))) +IMPLEMENT_BITBLT(src_notxor_dst, *dst = ~((*src) ^ (*dst))) +IMPLEMENT_BITBLT(src_or_notdst, *dst = (*src) | (~(*dst))) +IMPLEMENT_BITBLT(notsrc, *dst = (~(*src))) +IMPLEMENT_BITBLT(notsrc_or_dst, *dst = (~(*src)) | (*dst)) +IMPLEMENT_BITBLT(notsrc_and_notdst, *dst = (~(*src)) & (~(*dst))) static cirrus_bitblt_rop_t cirrus_get_fwd_rop_handler(uint8_t rop) { @@ -666,7 +656,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, #endif return 0; } - + dst = s->vram_ptr + s->cirrus_blt_dstaddr; for (y = 0; y < s->cirrus_blt_height; y += 8) { dstc = dst; @@ -686,6 +676,120 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, return 1; } +/* fill */ + +static void cirrus_fill_8(CirrusVGAState *s, + uint8_t *dst, int dst_pitch, int width, int height) +{ + uint8_t *d, *d1; + uint32_t val; + int x, y; + + val = s->cirrus_shadow_gr1; + + d1 = dst; + for(y = 0; y < height; y++) { + d = d1; + for(x = 0; x < width; x++) { + *d++ = val; + } + d1 += dst_pitch; + } +} + +static void cirrus_fill_16(CirrusVGAState *s, + uint8_t *dst, int dst_pitch, int width, int height) +{ + uint8_t *d, *d1; + uint32_t val; + int x, y; + + val = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8); + val = le16_to_cpu(val); + width >>= 1; + + d1 = dst; + for(y = 0; y < height; y++) { + d = d1; + for(x = 0; x < width; x++) { + ((uint16_t *)d)[0] = val; + d += 2; + } + d1 += dst_pitch; + } +} + +static void cirrus_fill_24(CirrusVGAState *s, + uint8_t *dst, int dst_pitch, int width, int height) +{ + uint8_t *d, *d1; + int x, y; + + d1 = dst; + for(y = 0; y < height; y++) { + d = d1; + for(x = 0; x < width; x += 3) { + *d++ = s->cirrus_shadow_gr1; + *d++ = s->gr[0x11]; + *d++ = s->gr[0x13]; + } + d1 += dst_pitch; + } +} + +static void cirrus_fill_32(CirrusVGAState *s, + uint8_t *dst, int dst_pitch, int width, int height) +{ + uint8_t *d, *d1; + uint32_t val; + int x, y; + + val = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) | + (s->gr[0x13] << 8) | (s->gr[0x15] << 8); + val = le32_to_cpu(val); + width >>= 2; + + d1 = dst; + for(y = 0; y < height; y++) { + d = d1; + for(x = 0; x < width; x++) { + ((uint32_t *)d)[0] = val; + d += 4; + } + d1 += dst_pitch; + } +} + +static int cirrus_bitblt_solidfill(CirrusVGAState *s) +{ + uint8_t *dst; + dst = s->vram_ptr + s->cirrus_blt_dstaddr; + switch (s->cirrus_blt_pixelwidth) { + case 1: + cirrus_fill_8(s, dst, s->cirrus_blt_dstpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + break; + case 2: + cirrus_fill_16(s, dst, s->cirrus_blt_dstpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + break; + case 3: + cirrus_fill_24(s, dst, s->cirrus_blt_dstpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + break; + default: + case 4: + cirrus_fill_32(s, dst, s->cirrus_blt_dstpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + break; + } + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); + cirrus_bitblt_reset(s); + return 1; +} + /*************************************** * * bitblt (video-to-video) @@ -952,6 +1056,19 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_blt_mode = s->gr[0x30]; blt_rop = s->gr[0x32]; +#ifdef DEBUG_BITBLT + printf("rop=%02x mode=%02x modeext=%02x w=%d h=%d dpitch=%d spicth=%d daddr=%08x saddr=%08x\n", + blt_rop, + s->cirrus_blt_mode, + s->gr[0x33], + s->cirrus_blt_width, + s->cirrus_blt_height, + s->cirrus_blt_dstpitch, + s->cirrus_blt_srcpitch, + s->cirrus_blt_dstaddr, + s->cirrus_blt_srcaddr); +#endif + switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { case CIRRUS_BLTMODE_PIXELWIDTH8: s->cirrus_blt_pixelwidth = 1; @@ -983,26 +1100,34 @@ static void cirrus_bitblt_start(CirrusVGAState * s) goto bitblt_ignore; } - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { - s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; - s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; - s->cirrus_rop = cirrus_get_bkwd_rop_handler(blt_rop); + if ((s->gr[0x33] & CIRRUS_BLTMODEEXT_SOLIDFILL) && + (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST | + CIRRUS_BLTMODE_TRANSPARENTCOMP | + CIRRUS_BLTMODE_PATTERNCOPY | + CIRRUS_BLTMODE_COLOREXPAND)) == + (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) { + cirrus_bitblt_solidfill(s); } else { - s->cirrus_rop = cirrus_get_fwd_rop_handler(blt_rop); + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_get_bkwd_rop_handler(blt_rop); + } else { + s->cirrus_rop = cirrus_get_fwd_rop_handler(blt_rop); + } + + // setup bitblt engine. + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!cirrus_bitblt_cputovideo(s)) + goto bitblt_ignore; + } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) { + if (!cirrus_bitblt_videotocpu(s)) + goto bitblt_ignore; + } else { + if (!cirrus_bitblt_videotovideo(s)) + goto bitblt_ignore; + } } - - // setup bitblt engine. - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (!cirrus_bitblt_cputovideo(s)) - goto bitblt_ignore; - } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) { - if (!cirrus_bitblt_videotocpu(s)) - goto bitblt_ignore; - } else { - if (!cirrus_bitblt_videotovideo(s)) - goto bitblt_ignore; - } - return; bitblt_ignore:; cirrus_bitblt_reset(s); @@ -1325,11 +1450,9 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) static void cirrus_read_hidden_dac(CirrusVGAState * s, int *reg_value) { *reg_value = 0xff; - if (s->cirrus_hidden_dac_lockindex < 5) { - if (s->cirrus_hidden_dac_lockindex == 4) { - *reg_value = s->cirrus_hidden_dac_data; - } - s->cirrus_hidden_dac_lockindex++; + if (++s->cirrus_hidden_dac_lockindex == 5) { + *reg_value = s->cirrus_hidden_dac_data; + s->cirrus_hidden_dac_lockindex = 0; } } @@ -1337,7 +1460,7 @@ static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value) { if (s->cirrus_hidden_dac_lockindex == 4) { s->cirrus_hidden_dac_data = reg_value; -#ifdef DEBUG_CIRRUS +#if defined(DEBUG_CIRRUS) printf("cirrus: outport hidden DAC, value %02x\n", reg_value); #endif } @@ -1468,6 +1591,7 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) case 0x2d: // BLT SRC ADDR 0x00ff00 case 0x30: // BLT MODE case 0x32: // RASTER OP + case 0x33: // BLT MODEEXT case 0x34: // BLT TRANSPARENT COLOR 0x00ff case 0x35: // BLT TRANSPARENT COLOR 0xff00 case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff @@ -1703,6 +1827,9 @@ static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address) case CIRRUS_MMIO_BLTROP: cirrus_hook_read_gr(s, 0x32, &value); break; + case CIRRUS_MMIO_BLTMODEEXT: + cirrus_hook_read_gr(s, 0x33, &value); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0): cirrus_hook_read_gr(s, 0x34, &value); break; @@ -1810,6 +1937,9 @@ static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address, case CIRRUS_MMIO_BLTROP: cirrus_hook_write_gr(s, 0x32, value); break; + case CIRRUS_MMIO_BLTMODEEXT: + cirrus_hook_write_gr(s, 0x33, value); + break; case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0): cirrus_hook_write_gr(s, 0x34, value); break; @@ -2592,7 +2722,7 @@ static void cirrus_init_common(CirrusVGAState * s) s->sr[0x0F] = CIRRUS_MEMSIZE_2M; s->sr[0x1F] = 0x22; // MemClock - s->cr[0x27] = CIRRUS_ID_CLGD5430; + s->cr[0x27] = CIRRUS_ID; s->cirrus_hidden_dac_lockindex = 5; s->cirrus_hidden_dac_data = 0; @@ -2670,8 +2800,8 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, pci_conf = d->dev.config; pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff); pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8); - pci_conf[0x02] = (uint8_t) (PCI_DEVICE_CLGD5430 & 0xff); - pci_conf[0x03] = (uint8_t) (PCI_DEVICE_CLGD5430 >> 8); + pci_conf[0x02] = (uint8_t) (PCI_DEVICE_ID & 0xff); + pci_conf[0x03] = (uint8_t) (PCI_DEVICE_ID >> 8); pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS; pci_conf[0x0a] = PCI_CLASS_SUB_VGA; pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY; @@ -2689,8 +2819,10 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, /* memory #1 memory-mapped I/O */ /* XXX: s->vram_size must be a power of two */ pci_register_io_region((PCIDevice *)d, 0, s->vram_size, - PCI_ADDRESS_SPACE_MEM, cirrus_pci_lfb_map); - pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, - PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map); + PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map); + if (CIRRUS_ID == CIRRUS_ID_CLGD5446) { + pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, + PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map); + } /* XXX: ROM BIOS */ } -- cgit v1.2.3 From 4c7634bcb3643f83405501d328a5e6dd5cb42719 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 18:49:26 +0000 Subject: init VGA with default config git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@900 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/pci.c b/hw/pci.c index 1e8466ef1..e72071590 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1030,6 +1030,8 @@ static void pci_bios_init_device(PCIDevice *d) } break; case 0x0300: + if (vendor_id != 0x1234) + goto default_map; /* VGA: map frame buffer to default Bochs VBE address */ pci_set_io_region_addr(d, 0, 0xE0000000); break; @@ -1040,6 +1042,7 @@ static void pci_bios_init_device(PCIDevice *d) } break; default: + default_map: /* default memory mappings */ for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; -- cgit v1.2.3 From 20ba3ae101c64c03d31b2e92abf7abe10250a45e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Jun 2004 18:50:58 +0000 Subject: better to use different ID for ISA and PCI git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@901 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 6305c9493..7fe5ff4ca 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -50,11 +50,6 @@ #define CIRRUS_ID_CLGD5436 (0x2B<<2) #define CIRRUS_ID_CLGD5446 (0x2E<<2) -/* this define is used to select the exact CLGD implementation we - emulate. */ -//#define CIRRUS_ID CIRRUS_ID_CLGD5430 -#define CIRRUS_ID CIRRUS_ID_CLGD5446 - // sequencer 0x07 #define CIRRUS_SR7_BPP_VGA 0x00 #define CIRRUS_SR7_BPP_SVGA 0x01 @@ -163,7 +158,6 @@ // PCI 0x00: vendor, 0x02: device #define PCI_VENDOR_CIRRUS 0x1013 -#define PCI_DEVICE_ID CIRRUS_ID #define PCI_DEVICE_CLGD5462 0x00d0 #define PCI_DEVICE_CLGD5465 0x00d6 @@ -2695,7 +2689,7 @@ static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { * ***************************************/ -static void cirrus_init_common(CirrusVGAState * s) +static void cirrus_init_common(CirrusVGAState * s, int device_id) { int vga_io_memory; @@ -2722,7 +2716,7 @@ static void cirrus_init_common(CirrusVGAState * s) s->sr[0x0F] = CIRRUS_MEMSIZE_2M; s->sr[0x1F] = 0x22; // MemClock - s->cr[0x27] = CIRRUS_ID; + s->cr[0x27] = device_id; s->cirrus_hidden_dac_lockindex = 5; s->cirrus_hidden_dac_data = 0; @@ -2757,7 +2751,7 @@ void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - cirrus_init_common(s); + cirrus_init_common(s, CIRRUS_ID_CLGD5430); s->sr[0x17] = CIRRUS_BUSTYPE_ISA; /* XXX ISA-LFB support */ } @@ -2792,6 +2786,9 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, PCICirrusVGAState *d; uint8_t *pci_conf; CirrusVGAState *s; + int device_id; + + device_id = CIRRUS_ID_CLGD5446; /* setup PCI configuration registers */ d = (PCICirrusVGAState *)pci_register_device("Cirrus VGA", @@ -2800,8 +2797,8 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, pci_conf = d->dev.config; pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff); pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8); - pci_conf[0x02] = (uint8_t) (PCI_DEVICE_ID & 0xff); - pci_conf[0x03] = (uint8_t) (PCI_DEVICE_ID >> 8); + pci_conf[0x02] = (uint8_t) (device_id & 0xff); + pci_conf[0x03] = (uint8_t) (device_id >> 8); pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS; pci_conf[0x0a] = PCI_CLASS_SUB_VGA; pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY; @@ -2811,7 +2808,7 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, s = &d->cirrus_vga; vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - cirrus_init_common(s); + cirrus_init_common(s, device_id); s->sr[0x17] = CIRRUS_BUSTYPE_PCI; /* setup memory space */ @@ -2820,7 +2817,7 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, /* XXX: s->vram_size must be a power of two */ pci_register_io_region((PCIDevice *)d, 0, s->vram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map); - if (CIRRUS_ID == CIRRUS_ID_CLGD5446) { + if (device_id == CIRRUS_ID_CLGD5446) { pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map); } -- cgit v1.2.3 From a5082316e97abb65d3e10085c50b6497473a9265 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Jun 2004 15:16:19 +0000 Subject: hardware cursor support - fill with rop support - color expand and color expand with transparent support - various optimisations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@902 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 1276 ++++++++++++++++++++++++++------------------------ hw/cirrus_vga_rop.h | 78 +++ hw/cirrus_vga_rop2.h | 140 ++++++ 3 files changed, 873 insertions(+), 621 deletions(-) create mode 100644 hw/cirrus_vga_rop.h create mode 100644 hw/cirrus_vga_rop2.h diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 7fe5ff4ca..f0b22e77c 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -29,6 +29,14 @@ #include "vl.h" #include "vga_int.h" +/* + * TODO: + * - add support for WRITEMASK (GR2F) + * - add support for scanline modulo in pattern fill + * - optimize linear mappings + * - optimize bitblt functions + */ + //#define DEBUG_CIRRUS //#define DEBUG_BITBLT @@ -103,6 +111,7 @@ #define CIRRUS_BLT_START 0x02 #define CIRRUS_BLT_RESET 0x04 #define CIRRUS_BLT_FIFOUSED 0x10 +#define CIRRUS_BLT_AUTOSTART 0x80 // control 0x32 #define CIRRUS_ROP_0 0x00 @@ -122,8 +131,12 @@ #define CIRRUS_ROP_NOTSRC_OR_DST 0xd6 #define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda +#define CIRRUS_ROP_NOP_INDEX 2 +#define CIRRUS_ROP_SRC_INDEX 5 + // control 0x33 -#define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 +#define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 +#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 // memory-mapped IO #define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword @@ -204,16 +217,19 @@ #define CIRRUS_HOOK_NOT_HANDLED 0 #define CIRRUS_HOOK_HANDLED 1 -typedef void (*cirrus_bitblt_rop_t) (uint8_t * dst, const uint8_t * src, +struct CirrusVGAState; +typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, + uint8_t * dst, const uint8_t * src, int dstpitch, int srcpitch, int bltwidth, int bltheight); - -typedef void (*cirrus_bitblt_handler_t) (void *opaque); +typedef void (*cirrus_fill_t)(struct CirrusVGAState *s, + uint8_t *dst, int dst_pitch, int width, int height); typedef struct CirrusVGAState { VGA_STATE_COMMON int cirrus_linear_io_addr; + int cirrus_linear_bitblt_io_addr; int cirrus_mmio_io_addr; uint32_t cirrus_addr_mask; uint8_t cirrus_shadow_gr0; @@ -223,18 +239,21 @@ typedef struct CirrusVGAState { uint32_t cirrus_bank_base[2]; uint32_t cirrus_bank_limit[2]; uint8_t cirrus_hidden_palette[48]; - uint32_t cirrus_hw_cursor_x; - uint32_t cirrus_hw_cursor_y; + uint32_t hw_cursor_x; + uint32_t hw_cursor_y; int cirrus_blt_pixelwidth; int cirrus_blt_width; int cirrus_blt_height; int cirrus_blt_dstpitch; int cirrus_blt_srcpitch; + uint32_t cirrus_blt_fgcol; + uint32_t cirrus_blt_bgcol; uint32_t cirrus_blt_dstaddr; uint32_t cirrus_blt_srcaddr; uint8_t cirrus_blt_mode; + uint8_t cirrus_blt_modeext; cirrus_bitblt_rop_t cirrus_rop; -#define CIRRUS_BLTBUFSIZE 256 +#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */ uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE]; uint8_t *cirrus_srcptr; uint8_t *cirrus_srcptr_end; @@ -242,8 +261,12 @@ typedef struct CirrusVGAState { uint8_t *cirrus_dstptr; uint8_t *cirrus_dstptr_end; uint32_t cirrus_dstcounter; - cirrus_bitblt_handler_t cirrus_blt_handler; - int cirrus_blt_horz_counter; + /* hwcursor display state */ + int last_hw_cursor_size; + int last_hw_cursor_x; + int last_hw_cursor_y; + int last_hw_cursor_y_start; + int last_hw_cursor_y_end; } CirrusVGAState; typedef struct PCICirrusVGAState { @@ -251,6 +274,8 @@ typedef struct PCICirrusVGAState { CirrusVGAState cirrus_vga; } PCICirrusVGAState; +static uint8_t rop_to_index[256]; + /*************************************** * * prototypes. @@ -266,343 +291,233 @@ static void cirrus_bitblt_reset(CirrusVGAState * s); * ***************************************/ -#define IMPLEMENT_BITBLT(name,opline) \ - static void \ - cirrus_bitblt_rop_fwd_##name( \ - uint8_t *dst,const uint8_t *src, \ - int dstpitch,int srcpitch, \ - int bltwidth,int bltheight) \ - { \ - int x,y; \ - dstpitch -= bltwidth; \ - srcpitch -= bltwidth; \ - for (y = 0; y < bltheight; y++) { \ - for (x = 0; x < bltwidth; x++) { \ - opline; \ - dst++; \ - src++; \ - } \ - dst += dstpitch; \ - src += srcpitch; \ - } \ - } \ - \ - static void \ - cirrus_bitblt_rop_bkwd_##name( \ - uint8_t *dst,const uint8_t *src, \ - int dstpitch,int srcpitch, \ - int bltwidth,int bltheight) \ - { \ - int x,y; \ - dstpitch += bltwidth; \ - srcpitch += bltwidth; \ - for (y = 0; y < bltheight; y++) { \ - for (x = 0; x < bltwidth; x++) { \ - opline; \ - dst--; \ - src--; \ - } \ - dst += dstpitch; \ - src += srcpitch; \ - } \ - } - -IMPLEMENT_BITBLT(0, *dst = 0) -IMPLEMENT_BITBLT(src_and_dst, *dst = (*src) & (*dst)) -IMPLEMENT_BITBLT(nop, (void) 0) -IMPLEMENT_BITBLT(src_and_notdst, *dst = (*src) & (~(*dst))) -IMPLEMENT_BITBLT(notdst, *dst = ~(*dst)) -IMPLEMENT_BITBLT(src, *dst = *src) -IMPLEMENT_BITBLT(1, *dst = 0xff) -IMPLEMENT_BITBLT(notsrc_and_dst, *dst = (~(*src)) & (*dst)) -IMPLEMENT_BITBLT(src_xor_dst, *dst = (*src) ^ (*dst)) -IMPLEMENT_BITBLT(src_or_dst, *dst = (*src) | (*dst)) -IMPLEMENT_BITBLT(notsrc_or_notdst, *dst = (~(*src)) | (~(*dst))) -IMPLEMENT_BITBLT(src_notxor_dst, *dst = ~((*src) ^ (*dst))) -IMPLEMENT_BITBLT(src_or_notdst, *dst = (*src) | (~(*dst))) -IMPLEMENT_BITBLT(notsrc, *dst = (~(*src))) -IMPLEMENT_BITBLT(notsrc_or_dst, *dst = (~(*src)) | (*dst)) -IMPLEMENT_BITBLT(notsrc_and_notdst, *dst = (~(*src)) & (~(*dst))) - -static cirrus_bitblt_rop_t cirrus_get_fwd_rop_handler(uint8_t rop) -{ - cirrus_bitblt_rop_t rop_handler = cirrus_bitblt_rop_fwd_nop; - - switch (rop) { - case CIRRUS_ROP_0: - rop_handler = cirrus_bitblt_rop_fwd_0; - break; - case CIRRUS_ROP_SRC_AND_DST: - rop_handler = cirrus_bitblt_rop_fwd_src_and_dst; - break; - case CIRRUS_ROP_NOP: - rop_handler = cirrus_bitblt_rop_fwd_nop; - break; - case CIRRUS_ROP_SRC_AND_NOTDST: - rop_handler = cirrus_bitblt_rop_fwd_src_and_notdst; - break; - case CIRRUS_ROP_NOTDST: - rop_handler = cirrus_bitblt_rop_fwd_notdst; - break; - case CIRRUS_ROP_SRC: - rop_handler = cirrus_bitblt_rop_fwd_src; - break; - case CIRRUS_ROP_1: - rop_handler = cirrus_bitblt_rop_fwd_1; - break; - case CIRRUS_ROP_NOTSRC_AND_DST: - rop_handler = cirrus_bitblt_rop_fwd_notsrc_and_dst; - break; - case CIRRUS_ROP_SRC_XOR_DST: - rop_handler = cirrus_bitblt_rop_fwd_src_xor_dst; - break; - case CIRRUS_ROP_SRC_OR_DST: - rop_handler = cirrus_bitblt_rop_fwd_src_or_dst; - break; - case CIRRUS_ROP_NOTSRC_OR_NOTDST: - rop_handler = cirrus_bitblt_rop_fwd_notsrc_or_notdst; - break; - case CIRRUS_ROP_SRC_NOTXOR_DST: - rop_handler = cirrus_bitblt_rop_fwd_src_notxor_dst; - break; - case CIRRUS_ROP_SRC_OR_NOTDST: - rop_handler = cirrus_bitblt_rop_fwd_src_or_notdst; - break; - case CIRRUS_ROP_NOTSRC: - rop_handler = cirrus_bitblt_rop_fwd_notsrc; - break; - case CIRRUS_ROP_NOTSRC_OR_DST: - rop_handler = cirrus_bitblt_rop_fwd_notsrc_or_dst; - break; - case CIRRUS_ROP_NOTSRC_AND_NOTDST: - rop_handler = cirrus_bitblt_rop_fwd_notsrc_and_notdst; - break; - default: -#ifdef DEBUG_CIRRUS - printf("unknown ROP %02x\n", rop); -#endif - break; - } - - return rop_handler; +static void cirrus_bitblt_rop_nop(CirrusVGAState *s, + uint8_t *dst,const uint8_t *src, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) +{ } -static cirrus_bitblt_rop_t cirrus_get_bkwd_rop_handler(uint8_t rop) +static void cirrus_bitblt_fill_nop(CirrusVGAState *s, + uint8_t *dst, + int dstpitch, int bltwidth,int bltheight) { - cirrus_bitblt_rop_t rop_handler = cirrus_bitblt_rop_bkwd_nop; +} - switch (rop) { - case CIRRUS_ROP_0: - rop_handler = cirrus_bitblt_rop_bkwd_0; - break; - case CIRRUS_ROP_SRC_AND_DST: - rop_handler = cirrus_bitblt_rop_bkwd_src_and_dst; - break; - case CIRRUS_ROP_NOP: - rop_handler = cirrus_bitblt_rop_bkwd_nop; - break; - case CIRRUS_ROP_SRC_AND_NOTDST: - rop_handler = cirrus_bitblt_rop_bkwd_src_and_notdst; - break; - case CIRRUS_ROP_NOTDST: - rop_handler = cirrus_bitblt_rop_bkwd_notdst; - break; - case CIRRUS_ROP_SRC: - rop_handler = cirrus_bitblt_rop_bkwd_src; - break; - case CIRRUS_ROP_1: - rop_handler = cirrus_bitblt_rop_bkwd_1; - break; - case CIRRUS_ROP_NOTSRC_AND_DST: - rop_handler = cirrus_bitblt_rop_bkwd_notsrc_and_dst; - break; - case CIRRUS_ROP_SRC_XOR_DST: - rop_handler = cirrus_bitblt_rop_bkwd_src_xor_dst; - break; - case CIRRUS_ROP_SRC_OR_DST: - rop_handler = cirrus_bitblt_rop_bkwd_src_or_dst; - break; - case CIRRUS_ROP_NOTSRC_OR_NOTDST: - rop_handler = cirrus_bitblt_rop_bkwd_notsrc_or_notdst; - break; - case CIRRUS_ROP_SRC_NOTXOR_DST: - rop_handler = cirrus_bitblt_rop_bkwd_src_notxor_dst; - break; - case CIRRUS_ROP_SRC_OR_NOTDST: - rop_handler = cirrus_bitblt_rop_bkwd_src_or_notdst; - break; - case CIRRUS_ROP_NOTSRC: - rop_handler = cirrus_bitblt_rop_bkwd_notsrc; - break; - case CIRRUS_ROP_NOTSRC_OR_DST: - rop_handler = cirrus_bitblt_rop_bkwd_notsrc_or_dst; - break; - case CIRRUS_ROP_NOTSRC_AND_NOTDST: - rop_handler = cirrus_bitblt_rop_bkwd_notsrc_and_notdst; - break; - default: -#ifdef DEBUG_CIRRUS - printf("unknown ROP %02x\n", rop); -#endif - break; - } +#define ROP_NAME 0 +#define ROP_OP(d, s) d = 0 +#include "cirrus_vga_rop.h" - return rop_handler; -} +#define ROP_NAME src_and_dst +#define ROP_OP(d, s) d = (s) & (d) +#include "cirrus_vga_rop.h" -/*************************************** - * - * color expansion - * - ***************************************/ +#define ROP_NAME src_and_notdst +#define ROP_OP(d, s) d = (s) & (~(d)) +#include "cirrus_vga_rop.h" -static void -cirrus_colorexpand_8(CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, int count) -{ - int x; - uint8_t colors[2]; - unsigned bits; - unsigned bitmask; - int srcskipleft = 0; - - colors[0] = s->cirrus_shadow_gr0; - colors[1] = s->cirrus_shadow_gr1; - - bitmask = 0x80 >> srcskipleft; - bits = *src++; - for (x = 0; x < count; x++) { - if ((bitmask & 0xff) == 0) { - bitmask = 0x80; - bits = *src++; - } - *dst++ = colors[!!(bits & bitmask)]; - bitmask >>= 1; - } -} +#define ROP_NAME notdst +#define ROP_OP(d, s) d = ~(d) +#include "cirrus_vga_rop.h" -static void -cirrus_colorexpand_16(CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, int count) -{ - int x; - uint8_t colors[2][2]; - unsigned bits; - unsigned bitmask; - unsigned index; - int srcskipleft = 0; - - colors[0][0] = s->cirrus_shadow_gr0; - colors[0][1] = s->gr[0x10]; - colors[1][0] = s->cirrus_shadow_gr1; - colors[1][1] = s->gr[0x11]; - - bitmask = 0x80 >> srcskipleft; - bits = *src++; - for (x = 0; x < count; x++) { - if ((bitmask & 0xff) == 0) { - bitmask = 0x80; - bits = *src++; - } - index = !!(bits & bitmask); - *dst++ = colors[index][0]; - *dst++ = colors[index][1]; - bitmask >>= 1; - } -} +#define ROP_NAME src +#define ROP_OP(d, s) d = s +#include "cirrus_vga_rop.h" -static void -cirrus_colorexpand_24(CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, int count) -{ - int x; - uint8_t colors[2][3]; - unsigned bits; - unsigned bitmask; - unsigned index; - int srcskipleft = 0; - - colors[0][0] = s->cirrus_shadow_gr0; - colors[0][1] = s->gr[0x10]; - colors[0][2] = s->gr[0x12]; - colors[1][0] = s->cirrus_shadow_gr1; - colors[1][1] = s->gr[0x11]; - colors[1][2] = s->gr[0x13]; - - bitmask = 0x80 << srcskipleft; - bits = *src++; - for (x = 0; x < count; x++) { - if ((bitmask & 0xff) == 0) { - bitmask = 0x80; - bits = *src++; - } - index = !!(bits & bitmask); - *dst++ = colors[index][0]; - *dst++ = colors[index][1]; - *dst++ = colors[index][2]; - bitmask >>= 1; - } -} +#define ROP_NAME 1 +#define ROP_OP(d, s) d = 0xff +#include "cirrus_vga_rop.h" + +#define ROP_NAME notsrc_and_dst +#define ROP_OP(d, s) d = (~(s)) & (d) +#include "cirrus_vga_rop.h" + +#define ROP_NAME src_xor_dst +#define ROP_OP(d, s) d = (s) ^ (d) +#include "cirrus_vga_rop.h" + +#define ROP_NAME src_or_dst +#define ROP_OP(d, s) d = (s) | (d) +#include "cirrus_vga_rop.h" + +#define ROP_NAME notsrc_or_notdst +#define ROP_OP(d, s) d = (~(s)) | (~(d)) +#include "cirrus_vga_rop.h" + +#define ROP_NAME src_notxor_dst +#define ROP_OP(d, s) d = ~((s) ^ (d)) +#include "cirrus_vga_rop.h" -static void -cirrus_colorexpand_32(CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, int count) +#define ROP_NAME src_or_notdst +#define ROP_OP(d, s) d = (s) | (~(d)) +#include "cirrus_vga_rop.h" + +#define ROP_NAME notsrc +#define ROP_OP(d, s) d = (~(s)) +#include "cirrus_vga_rop.h" + +#define ROP_NAME notsrc_or_dst +#define ROP_OP(d, s) d = (~(s)) | (d) +#include "cirrus_vga_rop.h" + +#define ROP_NAME notsrc_and_notdst +#define ROP_OP(d, s) d = (~(s)) & (~(d)) +#include "cirrus_vga_rop.h" + +static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = { + cirrus_bitblt_rop_fwd_0, + cirrus_bitblt_rop_fwd_src_and_dst, + cirrus_bitblt_rop_nop, + cirrus_bitblt_rop_fwd_src_and_notdst, + cirrus_bitblt_rop_fwd_notdst, + cirrus_bitblt_rop_fwd_src, + cirrus_bitblt_rop_fwd_1, + cirrus_bitblt_rop_fwd_notsrc_and_dst, + cirrus_bitblt_rop_fwd_src_xor_dst, + cirrus_bitblt_rop_fwd_src_or_dst, + cirrus_bitblt_rop_fwd_notsrc_or_notdst, + cirrus_bitblt_rop_fwd_src_notxor_dst, + cirrus_bitblt_rop_fwd_src_or_notdst, + cirrus_bitblt_rop_fwd_notsrc, + cirrus_bitblt_rop_fwd_notsrc_or_dst, + cirrus_bitblt_rop_fwd_notsrc_and_notdst, +}; + +static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = { + cirrus_bitblt_rop_bkwd_0, + cirrus_bitblt_rop_bkwd_src_and_dst, + cirrus_bitblt_rop_nop, + cirrus_bitblt_rop_bkwd_src_and_notdst, + cirrus_bitblt_rop_bkwd_notdst, + cirrus_bitblt_rop_bkwd_src, + cirrus_bitblt_rop_bkwd_1, + cirrus_bitblt_rop_bkwd_notsrc_and_dst, + cirrus_bitblt_rop_bkwd_src_xor_dst, + cirrus_bitblt_rop_bkwd_src_or_dst, + cirrus_bitblt_rop_bkwd_notsrc_or_notdst, + cirrus_bitblt_rop_bkwd_src_notxor_dst, + cirrus_bitblt_rop_bkwd_src_or_notdst, + cirrus_bitblt_rop_bkwd_notsrc, + cirrus_bitblt_rop_bkwd_notsrc_or_dst, + cirrus_bitblt_rop_bkwd_notsrc_and_notdst, +}; + +#define ROP2(name) {\ + name ## _8,\ + name ## _16,\ + name ## _24,\ + name ## _32,\ + } + +#define ROP_NOP2(func) {\ + func,\ + func,\ + func,\ + func,\ + } + +static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = { + ROP2(cirrus_colorexpand_transp_0), + ROP2(cirrus_colorexpand_transp_src_and_dst), + ROP_NOP2(cirrus_bitblt_rop_nop), + ROP2(cirrus_colorexpand_transp_src_and_notdst), + ROP2(cirrus_colorexpand_transp_notdst), + ROP2(cirrus_colorexpand_transp_src), + ROP2(cirrus_colorexpand_transp_1), + ROP2(cirrus_colorexpand_transp_notsrc_and_dst), + ROP2(cirrus_colorexpand_transp_src_xor_dst), + ROP2(cirrus_colorexpand_transp_src_or_dst), + ROP2(cirrus_colorexpand_transp_notsrc_or_notdst), + ROP2(cirrus_colorexpand_transp_src_notxor_dst), + ROP2(cirrus_colorexpand_transp_src_or_notdst), + ROP2(cirrus_colorexpand_transp_notsrc), + ROP2(cirrus_colorexpand_transp_notsrc_or_dst), + ROP2(cirrus_colorexpand_transp_notsrc_and_notdst), +}; + +static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = { + ROP2(cirrus_colorexpand_0), + ROP2(cirrus_colorexpand_src_and_dst), + ROP_NOP2(cirrus_bitblt_rop_nop), + ROP2(cirrus_colorexpand_src_and_notdst), + ROP2(cirrus_colorexpand_notdst), + ROP2(cirrus_colorexpand_src), + ROP2(cirrus_colorexpand_1), + ROP2(cirrus_colorexpand_notsrc_and_dst), + ROP2(cirrus_colorexpand_src_xor_dst), + ROP2(cirrus_colorexpand_src_or_dst), + ROP2(cirrus_colorexpand_notsrc_or_notdst), + ROP2(cirrus_colorexpand_src_notxor_dst), + ROP2(cirrus_colorexpand_src_or_notdst), + ROP2(cirrus_colorexpand_notsrc), + ROP2(cirrus_colorexpand_notsrc_or_dst), + ROP2(cirrus_colorexpand_notsrc_and_notdst), +}; + +static const cirrus_fill_t cirrus_fill[16][4] = { + ROP2(cirrus_fill_0), + ROP2(cirrus_fill_src_and_dst), + ROP_NOP2(cirrus_bitblt_fill_nop), + ROP2(cirrus_fill_src_and_notdst), + ROP2(cirrus_fill_notdst), + ROP2(cirrus_fill_src), + ROP2(cirrus_fill_1), + ROP2(cirrus_fill_notsrc_and_dst), + ROP2(cirrus_fill_src_xor_dst), + ROP2(cirrus_fill_src_or_dst), + ROP2(cirrus_fill_notsrc_or_notdst), + ROP2(cirrus_fill_src_notxor_dst), + ROP2(cirrus_fill_src_or_notdst), + ROP2(cirrus_fill_notsrc), + ROP2(cirrus_fill_notsrc_or_dst), + ROP2(cirrus_fill_notsrc_and_notdst), +}; + +static inline void cirrus_bitblt_fgcol(CirrusVGAState *s) { - int x; - uint8_t colors[2][4]; - unsigned bits; - unsigned bitmask; - unsigned index; - int srcskipleft = 0; - - colors[0][0] = s->cirrus_shadow_gr0; - colors[0][1] = s->gr[0x10]; - colors[0][2] = s->gr[0x12]; - colors[0][3] = s->gr[0x14]; - colors[1][0] = s->cirrus_shadow_gr1; - colors[1][1] = s->gr[0x11]; - colors[1][2] = s->gr[0x13]; - colors[1][3] = s->gr[0x15]; - - bitmask = 0x80 << srcskipleft; - bits = *src++; - for (x = 0; x < count; x++) { - if ((bitmask & 0xff) == 0) { - bitmask = 0x80; - bits = *src++; - } - index = !!(bits & bitmask); - *dst++ = colors[index][0]; - *dst++ = colors[index][1]; - *dst++ = colors[index][2]; - *dst++ = colors[index][3]; - bitmask >>= 1; + unsigned int color; + switch (s->cirrus_blt_pixelwidth) { + case 1: + s->cirrus_blt_fgcol = s->cirrus_shadow_gr1; + break; + case 2: + color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8); + s->cirrus_blt_fgcol = le16_to_cpu(color); + break; + case 3: + s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 | + (s->gr[0x11] << 8) | (s->gr[0x13] << 16); + break; + default: + case 4: + color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) | + (s->gr[0x13] << 16) | (s->gr[0x15] << 24); + s->cirrus_blt_fgcol = le32_to_cpu(color); + break; } } -static void -cirrus_colorexpand(CirrusVGAState * s, uint8_t * dst, const uint8_t * src, - int count) +static inline void cirrus_bitblt_bgcol(CirrusVGAState *s) { + unsigned int color; switch (s->cirrus_blt_pixelwidth) { case 1: - cirrus_colorexpand_8(s, dst, src, count); - break; + s->cirrus_blt_bgcol = s->cirrus_shadow_gr0; + break; case 2: - cirrus_colorexpand_16(s, dst, src, count); - break; + color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8); + s->cirrus_blt_bgcol = le16_to_cpu(color); + break; case 3: - cirrus_colorexpand_24(s, dst, src, count); - break; - case 4: - cirrus_colorexpand_32(s, dst, src, count); - break; + s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 | + (s->gr[0x10] << 8) | (s->gr[0x12] << 16); + break; default: -#ifdef DEBUG_CIRRUS - printf("cirrus: COLOREXPAND pixelwidth %d - unimplemented\n", - s->cirrus_blt_pixelwidth); -#endif - break; + case 4: + color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8) | + (s->gr[0x12] << 16) | (s->gr[0x14] << 24); + s->cirrus_blt_bgcol = le32_to_cpu(color); + break; } } @@ -626,8 +541,6 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, } } - - static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, const uint8_t * src) { @@ -639,12 +552,16 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, int patternbytes = s->cirrus_blt_pixelwidth * 8; if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - cirrus_colorexpand(s, work_colorexp, src, 8 * 8); + cirrus_bitblt_rop_t rop_func; + cirrus_bitblt_fgcol(s); + cirrus_bitblt_bgcol(s); + rop_func = cirrus_colorexpand[CIRRUS_ROP_SRC_INDEX][s->cirrus_blt_pixelwidth - 1]; + rop_func(s, work_colorexp, src, patternbytes, 1, patternbytes, 8); src = work_colorexp; s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_COLOREXPAND; } if (s->cirrus_blt_mode & ~CIRRUS_BLTMODE_PATTERNCOPY) { -#ifdef DEBUG_CIRRUS +#ifdef DEBUG_BITBLT printf("cirrus: blt mode %02x (pattercopy) - unimplemented\n", s->cirrus_blt_mode); #endif @@ -657,7 +574,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, tileheight = qemu_MIN(8, s->cirrus_blt_height - y); for (x = 0; x < s->cirrus_blt_width; x += patternbytes) { tilewidth = qemu_MIN(patternbytes, s->cirrus_blt_width - x); - (*s->cirrus_rop) (dstc, src, + (*s->cirrus_rop) (s, dstc, src, s->cirrus_blt_dstpitch, patternbytes, tilewidth, tileheight); dstc += patternbytes; @@ -672,111 +589,14 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, /* fill */ -static void cirrus_fill_8(CirrusVGAState *s, - uint8_t *dst, int dst_pitch, int width, int height) +static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) { - uint8_t *d, *d1; - uint32_t val; - int x, y; + cirrus_fill_t rop_func; - val = s->cirrus_shadow_gr1; - - d1 = dst; - for(y = 0; y < height; y++) { - d = d1; - for(x = 0; x < width; x++) { - *d++ = val; - } - d1 += dst_pitch; - } -} - -static void cirrus_fill_16(CirrusVGAState *s, - uint8_t *dst, int dst_pitch, int width, int height) -{ - uint8_t *d, *d1; - uint32_t val; - int x, y; - - val = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8); - val = le16_to_cpu(val); - width >>= 1; - - d1 = dst; - for(y = 0; y < height; y++) { - d = d1; - for(x = 0; x < width; x++) { - ((uint16_t *)d)[0] = val; - d += 2; - } - d1 += dst_pitch; - } -} - -static void cirrus_fill_24(CirrusVGAState *s, - uint8_t *dst, int dst_pitch, int width, int height) -{ - uint8_t *d, *d1; - int x, y; - - d1 = dst; - for(y = 0; y < height; y++) { - d = d1; - for(x = 0; x < width; x += 3) { - *d++ = s->cirrus_shadow_gr1; - *d++ = s->gr[0x11]; - *d++ = s->gr[0x13]; - } - d1 += dst_pitch; - } -} - -static void cirrus_fill_32(CirrusVGAState *s, - uint8_t *dst, int dst_pitch, int width, int height) -{ - uint8_t *d, *d1; - uint32_t val; - int x, y; - - val = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) | - (s->gr[0x13] << 8) | (s->gr[0x15] << 8); - val = le32_to_cpu(val); - width >>= 2; - - d1 = dst; - for(y = 0; y < height; y++) { - d = d1; - for(x = 0; x < width; x++) { - ((uint32_t *)d)[0] = val; - d += 4; - } - d1 += dst_pitch; - } -} - -static int cirrus_bitblt_solidfill(CirrusVGAState *s) -{ - uint8_t *dst; - dst = s->vram_ptr + s->cirrus_blt_dstaddr; - switch (s->cirrus_blt_pixelwidth) { - case 1: - cirrus_fill_8(s, dst, s->cirrus_blt_dstpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - break; - case 2: - cirrus_fill_16(s, dst, s->cirrus_blt_dstpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - break; - case 3: - cirrus_fill_24(s, dst, s->cirrus_blt_dstpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - break; - default: - case 4: - cirrus_fill_32(s, dst, s->cirrus_blt_dstpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - break; - } + rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, + s->cirrus_blt_dstpitch, + s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_width, s->cirrus_blt_height); @@ -799,21 +619,7 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) { - if ((s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) != 0) { -#ifdef DEBUG_CIRRUS - printf("cirrus: CIRRUS_BLTMODE_COLOREXPAND - unimplemented\n"); -#endif - return 0; - } - if ((s->cirrus_blt_mode & (~CIRRUS_BLTMODE_BACKWARDS)) != 0) { -#ifdef DEBUG_CIRRUS - printf("cirrus: blt mode %02x - unimplemented\n", - s->cirrus_blt_mode); -#endif - return 0; - } - - (*s->cirrus_rop) (s->vram_ptr + s->cirrus_blt_dstaddr, + (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, s->vram_ptr + s->cirrus_blt_srcaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_width, s->cirrus_blt_height); @@ -829,130 +635,38 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) * ***************************************/ -static void cirrus_bitblt_cputovideo_patterncopy(void *opaque) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - int data_count; - - data_count = s->cirrus_srcptr - &s->cirrus_bltbuf[0]; - - if (data_count > 0) { - if (data_count != s->cirrus_srccounter) { -#ifdef DEBUG_CIRRUS - printf("cirrus: internal error\n"); -#endif - } else { - cirrus_bitblt_common_patterncopy(s, &s->cirrus_bltbuf[0]); - } - cirrus_bitblt_reset(s); - } -} - -static void cirrus_bitblt_cputovideo_copy(void *opaque) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - int data_count; - int data_avail; - uint8_t work_colorexp[256]; - uint8_t *src_ptr = NULL; - int src_avail = 0; - int src_processing; - int src_linepad = 0; - - if (s->cirrus_blt_height <= 0) { - s->cirrus_srcptr = s->cirrus_srcptr_end; - return; - } - - s->cirrus_srcptr = &s->cirrus_bltbuf[0]; - while (1) { - /* get BLT source. */ - if (src_avail <= 0) { - data_count = s->cirrus_srcptr_end - s->cirrus_srcptr; - if (data_count <= 0) - break; - - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - if (s->cirrus_blt_mode & ~CIRRUS_BLTMODE_COLOREXPAND) { -#ifdef DEBUG_CIRRUS - printf("cirrus: unsupported\n"); -#endif - cirrus_bitblt_reset(s); - return; - } - data_avail = qemu_MIN(data_count, 256 / 32); - cirrus_colorexpand(s, work_colorexp, s->cirrus_srcptr, - data_avail * 8); - src_ptr = &work_colorexp[0]; - src_avail = data_avail * 8 * s->cirrus_blt_pixelwidth; - s->cirrus_srcptr += data_avail; - src_linepad = - ((s->cirrus_blt_width + 7) / 8) * 8 - - s->cirrus_blt_width; - src_linepad *= s->cirrus_blt_pixelwidth; - } else { - if (s->cirrus_blt_mode != 0) { -#ifdef DEBUG_CIRRUS - printf("cirrus: unsupported\n"); -#endif - cirrus_bitblt_reset(s); - return; - } - src_ptr = s->cirrus_srcptr; - src_avail = - data_count / s->cirrus_blt_pixelwidth * - s->cirrus_blt_pixelwidth; - s->cirrus_srcptr += src_avail; - } - if (src_avail <= 0) - break; - } - - /* 1-line BLT */ - src_processing = - s->cirrus_blt_srcpitch - s->cirrus_blt_horz_counter; - src_processing = qemu_MIN(src_avail, src_processing); - (*s->cirrus_rop) (s->vram_ptr + s->cirrus_blt_dstaddr, - src_ptr, 0, 0, src_processing, 1); - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, - src_processing, 1); - - s->cirrus_blt_dstaddr += src_processing; - src_ptr += src_processing; - src_avail -= src_processing; - s->cirrus_blt_horz_counter += src_processing; - if (s->cirrus_blt_horz_counter >= s->cirrus_blt_srcpitch) { - src_ptr += src_linepad; - src_avail -= src_linepad; - s->cirrus_blt_dstaddr += - s->cirrus_blt_dstpitch - s->cirrus_blt_srcpitch; - s->cirrus_blt_horz_counter = 0; - s->cirrus_blt_height--; - if (s->cirrus_blt_height <= 0) { - s->cirrus_srcptr = s->cirrus_srcptr_end; - return; - } - } - } -} - static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) { int copy_count; - int avail_count; - - s->cirrus_blt_handler(s); - + uint8_t *end_ptr; + if (s->cirrus_srccounter > 0) { - s->cirrus_srccounter -= s->cirrus_srcptr - &s->cirrus_bltbuf[0]; - copy_count = s->cirrus_srcptr_end - s->cirrus_srcptr; - memmove(&s->cirrus_bltbuf[0], s->cirrus_srcptr, copy_count); - avail_count = qemu_MIN(CIRRUS_BLTBUFSIZE, s->cirrus_srccounter); - s->cirrus_srcptr = &s->cirrus_bltbuf[0]; - s->cirrus_srcptr_end = s->cirrus_srcptr + avail_count; - if (s->cirrus_srccounter <= 0) { - cirrus_bitblt_reset(s); - } + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { + cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf); + the_end: + s->cirrus_srccounter = 0; + cirrus_bitblt_reset(s); + } else { + /* at least one scan line */ + do { + (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr, + s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, + s->cirrus_blt_width, 1); + s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; + s->cirrus_srccounter -= s->cirrus_blt_srcpitch; + if (s->cirrus_srccounter <= 0) + goto the_end; + /* more bytes than needed can be transfered because of + word alignment, so we keep them for the next line */ + /* XXX: keep alignment to speed up transfer */ + end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; + copy_count = s->cirrus_srcptr_end - end_ptr; + memmove(s->cirrus_bltbuf, end_ptr, copy_count); + s->cirrus_srcptr = s->cirrus_bltbuf + copy_count; + s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; + } while (s->cirrus_srcptr >= s->cirrus_srcptr_end); + } } } @@ -972,49 +686,44 @@ static void cirrus_bitblt_reset(CirrusVGAState * s) s->cirrus_dstptr = &s->cirrus_bltbuf[0]; s->cirrus_dstptr_end = &s->cirrus_bltbuf[0]; s->cirrus_dstcounter = 0; - s->cirrus_blt_handler = NULL; } static int cirrus_bitblt_cputovideo(CirrusVGAState * s) { + int w; + s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC; s->cirrus_srcptr = &s->cirrus_bltbuf[0]; s->cirrus_srcptr_end = &s->cirrus_bltbuf[0]; if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - s->cirrus_srccounter = 8; + s->cirrus_blt_srcpitch = 8; } else { - s->cirrus_srccounter = 8 * 8 * s->cirrus_blt_pixelwidth; + s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth; } - s->cirrus_blt_srcpitch = 0; - s->cirrus_blt_handler = cirrus_bitblt_cputovideo_patterncopy; + s->cirrus_srccounter = s->cirrus_blt_srcpitch; } else { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - s->cirrus_srccounter = - ((s->cirrus_blt_width + 7) / 8) * s->cirrus_blt_height; - s->cirrus_blt_srcpitch = - s->cirrus_blt_width * s->cirrus_blt_pixelwidth; + w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth; + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + s->cirrus_blt_srcpitch = ((w + 31) >> 5); + else + s->cirrus_blt_srcpitch = ((w + 7) >> 3); } else { - s->cirrus_srccounter = - s->cirrus_blt_width * s->cirrus_blt_height; s->cirrus_blt_srcpitch = s->cirrus_blt_width; } - /* 4-byte alignment */ - s->cirrus_srccounter = (s->cirrus_srccounter + 3) & (~3); - - s->cirrus_blt_handler = cirrus_bitblt_cputovideo_copy; - s->cirrus_blt_horz_counter = 0; + s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height; } - - cirrus_bitblt_cputovideo_next(s); + s->cirrus_srcptr = s->cirrus_bltbuf; + s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; return 1; } static int cirrus_bitblt_videotocpu(CirrusVGAState * s) { /* XXX */ -#ifdef DEBUG_CIRRUS +#ifdef DEBUG_BITBLT printf("cirrus: bitblt (video to cpu) is not implemented yet\n"); #endif return 0; @@ -1029,7 +738,6 @@ static int cirrus_bitblt_videotovideo(CirrusVGAState * s) } else { ret = cirrus_bitblt_videotovideo_copy(s); } - if (ret) cirrus_bitblt_reset(s); return ret; @@ -1039,6 +747,8 @@ static void cirrus_bitblt_start(CirrusVGAState * s) { uint8_t blt_rop; + s->gr[0x31] |= CIRRUS_BLT_BUSY; + s->cirrus_blt_width = (s->gr[0x20] | (s->gr[0x21] << 8)) + 1; s->cirrus_blt_height = (s->gr[0x22] | (s->gr[0x23] << 8)) + 1; s->cirrus_blt_dstpitch = (s->gr[0x24] | (s->gr[0x25] << 8)); @@ -1048,19 +758,21 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_blt_srcaddr = (s->gr[0x2c] | (s->gr[0x2d] << 8) | (s->gr[0x2e] << 16)); s->cirrus_blt_mode = s->gr[0x30]; + s->cirrus_blt_modeext = s->gr[0x33]; blt_rop = s->gr[0x32]; #ifdef DEBUG_BITBLT - printf("rop=%02x mode=%02x modeext=%02x w=%d h=%d dpitch=%d spicth=%d daddr=%08x saddr=%08x\n", + printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spicth=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", blt_rop, s->cirrus_blt_mode, - s->gr[0x33], + s->cirrus_blt_modeext, s->cirrus_blt_width, s->cirrus_blt_height, s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_dstaddr, - s->cirrus_blt_srcaddr); + s->cirrus_blt_srcaddr, + s->sr[0x2f]); #endif switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { @@ -1077,7 +789,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_blt_pixelwidth = 4; break; default: -#ifdef DEBUG_CIRRUS +#ifdef DEBUG_BITBLT printf("cirrus: bitblt - pixel width is unknown\n"); #endif goto bitblt_ignore; @@ -1088,26 +800,41 @@ static void cirrus_bitblt_start(CirrusVGAState * s) cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) { -#ifdef DEBUG_CIRRUS +#ifdef DEBUG_BITBLT printf("cirrus: bitblt - memory-to-memory copy is requested\n"); #endif goto bitblt_ignore; } - if ((s->gr[0x33] & CIRRUS_BLTMODEEXT_SOLIDFILL) && + if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) && (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST | CIRRUS_BLTMODE_TRANSPARENTCOMP | CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) { - cirrus_bitblt_solidfill(s); + cirrus_bitblt_fgcol(s); + cirrus_bitblt_solidfill(s, blt_rop); } else { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { - s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; - s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; - s->cirrus_rop = cirrus_get_bkwd_rop_handler(blt_rop); + if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND | + CIRRUS_BLTMODE_PATTERNCOPY)) == + CIRRUS_BLTMODE_COLOREXPAND) { + + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { + cirrus_bitblt_fgcol(s); + s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } else { + cirrus_bitblt_fgcol(s); + cirrus_bitblt_bgcol(s); + s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } } else { - s->cirrus_rop = cirrus_get_fwd_rop_handler(blt_rop); + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]]; + } else { + s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]]; + } } // setup bitblt engine. @@ -1139,7 +866,6 @@ static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value) cirrus_bitblt_reset(s); } else if (((old_value & CIRRUS_BLT_START) == 0) && ((reg_value & CIRRUS_BLT_START) != 0)) { - s->gr[0x31] |= CIRRUS_BLT_BUSY; cirrus_bitblt_start(s); } } @@ -1312,6 +1038,7 @@ cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value) case 0x91: case 0xb1: case 0xd1: + case 0xf1: // Graphics Cursor Y *reg_value = s->sr[0x11]; break; case 0x05: // ??? @@ -1324,7 +1051,6 @@ cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value) case 0x0d: // VCLK 2 case 0x0e: // VCLK 3 case 0x0f: // DRAM Control - case 0xf1: // Graphics Cursor Y case 0x12: // Graphics Cursor Attribute case 0x13: // Graphics Cursor Pattern Address case 0x14: // Scratch Register 2 @@ -1382,7 +1108,7 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) case 0xd0: case 0xf0: // Graphics Cursor X s->sr[0x10] = reg_value; - s->cirrus_hw_cursor_x = ((reg_index << 3) & 0x700) | reg_value; + s->hw_cursor_x = (reg_value << 3) | (reg_index >> 5); break; case 0x11: case 0x31: @@ -1393,7 +1119,7 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) case 0xd1: case 0xf1: // Graphics Cursor Y s->sr[0x11] = reg_value; - s->cirrus_hw_cursor_y = ((reg_index << 3) & 0x700) | reg_value; + s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5); break; case 0x07: // Extended Sequencer Mode case 0x08: // EEPROM Control @@ -1471,13 +1197,9 @@ static int cirrus_hook_read_palette(CirrusVGAState * s, int *reg_value) { if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) return CIRRUS_HOOK_NOT_HANDLED; - if (s->dac_read_index < 0x10) { - *reg_value = - s->cirrus_hidden_palette[s->dac_read_index * 3 + - s->dac_sub_index]; - } else { - *reg_value = 0xff; /* XXX */ - } + *reg_value = + s->cirrus_hidden_palette[(s->dac_read_index & 0x0f) * 3 + + s->dac_sub_index]; if (++s->dac_sub_index == 3) { s->dac_sub_index = 0; s->dac_read_index++; @@ -1491,11 +1213,9 @@ static int cirrus_hook_write_palette(CirrusVGAState * s, int reg_value) return CIRRUS_HOOK_NOT_HANDLED; s->dac_cache[s->dac_sub_index] = reg_value; if (++s->dac_sub_index == 3) { - if (s->dac_read_index < 0x10) { - memcpy(&s->cirrus_hidden_palette[s->dac_write_index * 3], - s->dac_cache, 3); - /* XXX update cursor */ - } + memcpy(&s->cirrus_hidden_palette[(s->dac_write_index & 0x0f) * 3], + s->dac_cache, 3); + /* XXX update cursor */ s->dac_sub_index = 0; s->dac_write_index++; } @@ -1545,6 +1265,9 @@ cirrus_hook_read_gr(CirrusVGAState * s, unsigned reg_index, int *reg_value) static int cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) { +#if defined(DEBUG_BITBLT) && 0 + printf("gr%02x: %02x\n", reg_index, reg_value); +#endif switch (reg_index) { case 0x00: // Standard VGA, BGCOLOR 0x000000ff s->cirrus_shadow_gr0 = reg_value; @@ -1583,6 +1306,7 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) case 0x29: // BLT DEST ADDR 0x00ff00 case 0x2c: // BLT SRC ADDR 0x0000ff case 0x2d: // BLT SRC ADDR 0x00ff00 + case 0x2f: // BLT WRITEMASK case 0x30: // BLT MODE case 0x32: // RASTER OP case 0x33: // BLT MODEEXT @@ -1599,6 +1323,12 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) s->gr[reg_index] = reg_value & 0x1f; break; case 0x2a: // BLT DEST ADDR 0x3f0000 + s->gr[reg_index] = reg_value & 0x3f; + /* if auto start mode, starts bit blt now */ + if (s->gr[0x31] & CIRRUS_BLT_AUTOSTART) { + cirrus_bitblt_start(s); + } + break; case 0x2e: // BLT SRC ADDR 0x3f0000 s->gr[reg_index] = reg_value & 0x3f; break; @@ -2111,7 +1841,7 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, if (s->cirrus_srcptr != s->cirrus_srcptr_end) { /* bitblt */ *s->cirrus_srcptr++ = (uint8_t) mem_value; - if (s->cirrus_srcptr == s->cirrus_srcptr_end) { + if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { cirrus_bitblt_cputovideo_next(s); } } else { @@ -2194,6 +1924,176 @@ static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = { cirrus_vga_mem_writel, }; +/*************************************** + * + * hardware cursor + * + ***************************************/ + +static inline void invalidate_cursor1(CirrusVGAState *s) +{ + if (s->last_hw_cursor_size) { + vga_invalidate_scanlines((VGAState *)s, + s->last_hw_cursor_y + s->last_hw_cursor_y_start, + s->last_hw_cursor_y + s->last_hw_cursor_y_end); + } +} + +static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s) +{ + const uint8_t *src; + uint32_t content; + int y, y_min, y_max; + + src = s->vram_ptr + 0x200000 - 16 * 1024; + if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { + src += (s->sr[0x13] & 0x3c) * 256; + y_min = 64; + y_max = -1; + for(y = 0; y < 64; y++) { + content = ((uint32_t *)src)[0] | + ((uint32_t *)src)[1] | + ((uint32_t *)src)[2] | + ((uint32_t *)src)[3]; + if (content) { + if (y < y_min) + y_min = y; + if (y > y_max) + y_max = y; + } + src += 16; + } + } else { + src += (s->sr[0x13] & 0x3f) * 256; + y_min = 32; + y_max = -1; + for(y = 0; y < 32; y++) { + content = ((uint32_t *)src)[0] | + ((uint32_t *)(src + 128))[0]; + if (content) { + if (y < y_min) + y_min = y; + if (y > y_max) + y_max = y; + } + src += 4; + } + } + if (y_min > y_max) { + s->last_hw_cursor_y_start = 0; + s->last_hw_cursor_y_end = 0; + } else { + s->last_hw_cursor_y_start = y_min; + s->last_hw_cursor_y_end = y_max + 1; + } +} + +/* NOTE: we do not currently handle the cursor bitmap change, so we + update the cursor only if it moves. */ +static void cirrus_cursor_invalidate(VGAState *s1) +{ + CirrusVGAState *s = (CirrusVGAState *)s1; + int size; + + if (!s->sr[0x12] & CIRRUS_CURSOR_SHOW) { + size = 0; + } else { + if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) + size = 64; + else + size = 32; + } + /* invalidate last cursor and new cursor if any change */ + if (s->last_hw_cursor_size != size || + s->last_hw_cursor_x != s->hw_cursor_x || + s->last_hw_cursor_y != s->hw_cursor_y) { + + invalidate_cursor1(s); + + s->last_hw_cursor_size = size; + s->last_hw_cursor_x = s->hw_cursor_x; + s->last_hw_cursor_y = s->hw_cursor_y; + /* compute the real cursor min and max y */ + cirrus_cursor_compute_yrange(s); + invalidate_cursor1(s); + } +} + +static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) +{ + CirrusVGAState *s = (CirrusVGAState *)s1; + int w, h, bpp, x1, x2, poffset; + unsigned int color0, color1; + const uint8_t *palette, *src; + uint32_t content; + + if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW)) + return; + /* fast test to see if the cursor intersects with the scan line */ + if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { + h = 64; + } else { + h = 32; + } + if (scr_y < s->hw_cursor_y || + scr_y >= (s->hw_cursor_y + h)) + return; + + src = s->vram_ptr + 0x200000 - 16 * 1024; + if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { + src += (s->sr[0x13] & 0x3c) * 256; + src += (scr_y - s->hw_cursor_y) * 16; + poffset = 8; + content = ((uint32_t *)src)[0] | + ((uint32_t *)src)[1] | + ((uint32_t *)src)[2] | + ((uint32_t *)src)[3]; + } else { + src += (s->sr[0x13] & 0x3f) * 256; + src += (scr_y - s->hw_cursor_y) * 4; + poffset = 128; + content = ((uint32_t *)src)[0] | + ((uint32_t *)(src + 128))[0]; + } + /* if nothing to draw, no need to continue */ + if (!content) + return; + w = h; + + x1 = s->hw_cursor_x; + if (x1 >= s->last_scr_width) + return; + x2 = s->hw_cursor_x + w; + if (x2 > s->last_scr_width) + x2 = s->last_scr_width; + w = x2 - x1; + palette = s->cirrus_hidden_palette; + color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]), + c6_to_8(palette[0x0 * 3 + 1]), + c6_to_8(palette[0x0 * 3 + 2])); + color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]), + c6_to_8(palette[0xf * 3 + 1]), + c6_to_8(palette[0xf * 3 + 2])); + bpp = ((s->ds->depth + 7) >> 3); + d1 += x1 * bpp; + switch(s->ds->depth) { + default: + break; + case 8: + vga_draw_cursor_line_8(d1, src, poffset, w, color0, color1, 0xff); + break; + case 15: + vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0x7fff); + break; + case 16: + vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0xffff); + break; + case 32: + vga_draw_cursor_line_32(d1, src, poffset, w, color0, color1, 0xffffff); + break; + } +} + /*************************************** * * LFB memory access @@ -2272,7 +2172,7 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr, } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { /* bitblt */ *s->cirrus_srcptr++ = (uint8_t) val; - if (s->cirrus_srcptr == s->cirrus_srcptr_end) { + if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { cirrus_bitblt_cputovideo_next(s); } } else { @@ -2339,6 +2239,107 @@ static CPUWriteMemoryFunc *cirrus_linear_write[3] = { cirrus_linear_writel, }; +/*************************************** + * + * system to screen memory access + * + ***************************************/ + + +static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + + /* XXX handle bitblt */ + ret = 0xff; + return ret; +} + +static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_linear_bitblt_readb(opaque, addr) << 8; + v |= cirrus_linear_bitblt_readb(opaque, addr + 1); +#else + v = cirrus_linear_bitblt_readb(opaque, addr); + v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8; +#endif + return v; +} + +static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = cirrus_linear_bitblt_readb(opaque, addr) << 24; + v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 16; + v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 8; + v |= cirrus_linear_bitblt_readb(opaque, addr + 3); +#else + v = cirrus_linear_bitblt_readb(opaque, addr); + v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8; + v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16; + v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24; +#endif + return v; +} + +static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + if (s->cirrus_srcptr != s->cirrus_srcptr_end) { + /* bitblt */ + *s->cirrus_srcptr++ = (uint8_t) val; + if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { + cirrus_bitblt_cputovideo_next(s); + } + } +} + +static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_linear_bitblt_writeb(opaque, addr, (val >> 8) & 0xff); + cirrus_linear_bitblt_writeb(opaque, addr + 1, val & 0xff); +#else + cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff); + cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff); +#endif +} + +static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + cirrus_linear_bitblt_writeb(opaque, addr, (val >> 24) & 0xff); + cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 16) & 0xff); + cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 8) & 0xff); + cirrus_linear_bitblt_writeb(opaque, addr + 3, val & 0xff); +#else + cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff); + cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff); + cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff); + cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff); +#endif +} + + +static CPUReadMemoryFunc *cirrus_linear_bitblt_read[3] = { + cirrus_linear_bitblt_readb, + cirrus_linear_bitblt_readw, + cirrus_linear_bitblt_readl, +}; + +static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = { + cirrus_linear_bitblt_writeb, + cirrus_linear_bitblt_writew, + cirrus_linear_bitblt_writel, +}; + /* I/O ports */ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) @@ -2691,7 +2692,30 @@ static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { static void cirrus_init_common(CirrusVGAState * s, int device_id) { - int vga_io_memory; + int vga_io_memory, i; + static int inited; + + if (!inited) { + inited = 1; + for(i = 0;i < 256; i++) + rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */ + rop_to_index[CIRRUS_ROP_0] = 0; + rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1; + rop_to_index[CIRRUS_ROP_NOP] = 2; + rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3; + rop_to_index[CIRRUS_ROP_NOTDST] = 4; + rop_to_index[CIRRUS_ROP_SRC] = 5; + rop_to_index[CIRRUS_ROP_1] = 6; + rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7; + rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8; + rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9; + rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10; + rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11; + rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12; + rop_to_index[CIRRUS_ROP_NOTSRC] = 13; + rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14; + rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15; + } register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); @@ -2725,6 +2749,11 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id) s->cirrus_linear_io_addr = cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write, s); + /* I/O handler for LFB */ + s->cirrus_linear_bitblt_io_addr = + cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write, + s); + /* I/O handler for memory-mapped I/O */ s->cirrus_mmio_io_addr = cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s); @@ -2734,6 +2763,8 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id) s->get_bpp = cirrus_get_bpp; s->get_offsets = cirrus_get_offsets; + s->cursor_invalidate = cirrus_cursor_invalidate; + s->cursor_draw_line = cirrus_cursor_draw_line; } /*************************************** @@ -2767,8 +2798,11 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num, { CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga; + /* XXX: add byte swapping apertures */ cpu_register_physical_memory(addr, s->vram_size, s->cirrus_linear_io_addr); + cpu_register_physical_memory(addr + 0x1000000, 0x400000, + s->cirrus_linear_bitblt_io_addr); } static void cirrus_pci_mmio_map(PCIDevice *d, int region_num, @@ -2815,7 +2849,7 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, /* memory #0 LFB */ /* memory #1 memory-mapped I/O */ /* XXX: s->vram_size must be a power of two */ - pci_register_io_region((PCIDevice *)d, 0, s->vram_size, + pci_register_io_region((PCIDevice *)d, 0, 0x2000000, PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map); if (device_id == CIRRUS_ID_CLGD5446) { pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h new file mode 100644 index 000000000..c54f1258b --- /dev/null +++ b/hw/cirrus_vga_rop.h @@ -0,0 +1,78 @@ +/* + * QEMU Cirrus CLGD 54xx VGA Emulator. + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static void +glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s, + uint8_t *dst,const uint8_t *src, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) +{ + int x,y; + dstpitch -= bltwidth; + srcpitch -= bltwidth; + for (y = 0; y < bltheight; y++) { + for (x = 0; x < bltwidth; x++) { + ROP_OP(*dst, *src); + dst++; + src++; + } + dst += dstpitch; + src += srcpitch; + } +} + +static void +glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s, + uint8_t *dst,const uint8_t *src, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) +{ + int x,y; + dstpitch += bltwidth; + srcpitch += bltwidth; + for (y = 0; y < bltheight; y++) { + for (x = 0; x < bltwidth; x++) { + ROP_OP(*dst, *src); + dst--; + src--; + } + dst += dstpitch; + src += srcpitch; + } +} + +#define DEPTH 8 +#include "cirrus_vga_rop2.h" + +#define DEPTH 16 +#include "cirrus_vga_rop2.h" + +#define DEPTH 24 +#include "cirrus_vga_rop2.h" + +#define DEPTH 32 +#include "cirrus_vga_rop2.h" + +#undef ROP_NAME +#undef ROP_OP diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h new file mode 100644 index 000000000..682662741 --- /dev/null +++ b/hw/cirrus_vga_rop2.h @@ -0,0 +1,140 @@ +/* + * QEMU Cirrus CLGD 54xx VGA Emulator. + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if DEPTH == 8 +#define PUTPIXEL() ROP_OP(d[0], col) +#elif DEPTH == 16 +#define PUTPIXEL() ROP_OP(((uint16_t *)d)[0], col); +#elif DEPTH == 24 +#define PUTPIXEL() ROP_OP(d[0], col); \ + ROP_OP(d[1], (col >> 8)); \ + ROP_OP(d[2], (col >> 16)) +#elif DEPTH == 32 +#define PUTPIXEL() ROP_OP(((uint32_t *)d)[0], col) +#else +#error unsupported DEPTH +#endif + +static void +glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) + (CirrusVGAState * s, uint8_t * dst, + const uint8_t * src1, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) +{ + const uint8_t *src; + uint8_t *d; + int x, y; + unsigned bits; + unsigned int col; + unsigned bitmask; + unsigned index; + int srcskipleft = 0; + + col = s->cirrus_blt_fgcol; + for(y = 0; y < bltheight; y++) { + src = src1; + bitmask = 0x80 >> srcskipleft; + bits = *src++; + d = dst; + for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + if ((bitmask & 0xff) == 0) { + bitmask = 0x80; + bits = *src++; + } + index = (bits & bitmask); + if (index) { + PUTPIXEL(); + } + d += (DEPTH / 8); + bitmask >>= 1; + } + src1 += srcpitch; + dst += dstpitch; + } +} + +static void +glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) + (CirrusVGAState * s, uint8_t * dst, + const uint8_t * src1, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) +{ + const uint8_t *src; + uint32_t colors[2]; + uint8_t *d; + int x, y; + unsigned bits; + unsigned int col; + unsigned bitmask; + int srcskipleft = 0; + + colors[0] = s->cirrus_blt_bgcol; + colors[1] = s->cirrus_blt_fgcol; + for(y = 0; y < bltheight; y++) { + src = src1; + bitmask = 0x80 >> srcskipleft; + bits = *src++; + d = dst; + for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + if ((bitmask & 0xff) == 0) { + bitmask = 0x80; + bits = *src++; + } + col = colors[!!(bits & bitmask)]; + PUTPIXEL(); + d += (DEPTH / 8); + bitmask >>= 1; + } + src1 += srcpitch; + dst += dstpitch; + } +} + +static void +glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH) + (CirrusVGAState *s, + uint8_t *dst, int dst_pitch, + int width, int height) +{ + uint8_t *d, *d1; + uint32_t col; + int x, y; + + col = s->cirrus_blt_fgcol; + + d1 = dst; + for(y = 0; y < height; y++) { + d = d1; + for(x = 0; x < width; x += (DEPTH / 8)) { + PUTPIXEL(); + d += (DEPTH / 8); + } + d1 += dst_pitch; + } +} + +#undef DEPTH +#undef PUTPIXEL -- cgit v1.2.3 From a8aa669ba406a0d6530f48e0c87a358ba614aa95 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Jun 2004 15:17:19 +0000 Subject: generic hardware cursor support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@903 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 32 ++++++++++++++++---------- hw/vga_int.h | 27 ++++++++++++++++++++++ hw/vga_template.h | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 12 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 4adba3cdd..23695f506 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -852,14 +852,6 @@ static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsign #define DEPTH 32 #include "vga_template.h" -static inline int c6_to_8(int v) -{ - int b; - v &= 0x3f; - b = v & 1; - return (v << 2) | (b << 1) | b; -} - static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) { unsigned int col; @@ -1309,11 +1301,20 @@ static int vga_get_bpp(VGAState *s) return ret; } +void vga_invalidate_scanlines(VGAState *s, int y1, int y2) +{ + int y; + if (y1 >= VGA_MAX_HEIGHT) + return; + if (y2 >= VGA_MAX_HEIGHT) + y2 = VGA_MAX_HEIGHT; + for(y = y1; y < y2; y++) { + s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f); + } +} + /* * graphic modes - * Missing: - * - double scan - * - double width */ static void vga_draw_graphic(VGAState *s, int full_update) { @@ -1400,7 +1401,9 @@ static void vga_draw_graphic(VGAState *s, int full_update) s->last_height = height; full_update = 1; } - + if (s->cursor_invalidate) + s->cursor_invalidate(s); + line_offset = s->line_offset; #if 0 printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n", @@ -1433,6 +1436,8 @@ static void vga_draw_graphic(VGAState *s, int full_update) /* if wide line, can use another page */ update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE); } + /* explicit invalidation for the hardware cursor */ + update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; if (update) { if (y_start < 0) y_start = y; @@ -1441,6 +1446,8 @@ static void vga_draw_graphic(VGAState *s, int full_update) if (page1 > page_max) page_max = page1; vga_draw_line(s, d, s->vram_ptr + addr, width); + if (s->cursor_draw_line) + s->cursor_draw_line(s, d, y); } else { if (y_start >= 0) { /* flush to display */ @@ -1476,6 +1483,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) if (page_max != -1) { cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE); } + memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4); } static void vga_draw_blank(VGAState *s, int full_update) diff --git a/hw/vga_int.h b/hw/vga_int.h index 8fb78a0df..0d0f3edee 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -72,6 +72,7 @@ #endif /* !CONFIG_BOCHS_VBE */ #define CH_ATTR_SIZE (160 * 100) +#define VGA_MAX_HEIGHT 1024 #define VGA_STATE_COMMON \ uint8_t *vram_ptr; \ @@ -119,6 +120,10 @@ uint32_t cursor_offset; \ unsigned int (*rgb_to_pixel)(unsigned int r, \ unsigned int g, unsigned b); \ + /* hardware mouse cursor support */ \ + uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \ + void (*cursor_invalidate)(struct VGAState *s); \ + void (*cursor_draw_line)(struct VGAState *s, uint8_t *d, int y); \ /* tell for each page if it has been updated since the last time */ \ uint32_t last_palette[256]; \ uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ @@ -128,10 +133,32 @@ typedef struct VGAState { VGA_STATE_COMMON } VGAState; +static inline int c6_to_8(int v) +{ + int b; + v &= 0x3f; + b = v & 1; + return (v << 2) | (b << 1) | b; +} + void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr); void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val); +void vga_invalidate_scanlines(VGAState *s, int y1, int y2); + +void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1, + int poffset, int w, + unsigned int color0, unsigned int color1, + unsigned int color_xor); +void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1, + int poffset, int w, + unsigned int color0, unsigned int color1, + unsigned int color_xor); +void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1, + int poffset, int w, + unsigned int color0, unsigned int color1, + unsigned int color_xor); extern const uint8_t sr_mask[8]; extern const uint8_t gr_mask[16]; diff --git a/hw/vga_template.h b/hw/vga_template.h index 766257c09..721abcb82 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -434,6 +434,74 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, #endif } +#if DEPTH != 15 +void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, + const uint8_t *src1, + int poffset, int w, + unsigned int color0, + unsigned int color1, + unsigned int color_xor) +{ + const uint8_t *plane0, *plane1; + int x, b0, b1; + uint8_t *d; + + d = d1; + plane0 = src1; + plane1 = src1 + poffset; + for(x = 0; x < w; x++) { + b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1; + b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1; +#if DEPTH == 8 + switch(b0 | (b1 << 1)) { + case 0: + break; + case 1: + d[0] ^= color_xor; + break; + case 2: + d[0] = color0; + break; + case 3: + d[0] = color1; + break; + } +#elif DEPTH == 16 + switch(b0 | (b1 << 1)) { + case 0: + break; + case 1: + ((uint16_t *)d)[0] ^= color_xor; + break; + case 2: + ((uint16_t *)d)[0] = color0; + break; + case 3: + ((uint16_t *)d)[0] = color1; + break; + } +#elif DEPTH == 32 + switch(b0 | (b1 << 1)) { + case 0: + break; + case 1: + ((uint32_t *)d)[0] ^= color_xor; + break; + case 2: + ((uint32_t *)d)[0] = color0; + break; + case 3: + ((uint32_t *)d)[0] = color1; + break; + } +#else +#error unsupported depth +#endif + d += (DEPTH / 8); + } +} +#endif + #undef PUT_PIXEL2 #undef DEPTH #undef BPP -- cgit v1.2.3 From 37f53b4c05e504decb408c931178c403807148cb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Jun 2004 15:48:55 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@904 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 95b456267..b9eea8211 100644 --- a/Changelog +++ b/Changelog @@ -16,6 +16,7 @@ version 0.5.6: - PIC reset fix (Hidemi KAWAI) - PIC spurious irq support (aka Solaris install bug) - added '-localtime' option + - preliminary Cirrus CLGD 54xx VGA support (Makoto Suzuki (suzu)) version 0.5.5: -- cgit v1.2.3 From de9258a87f8cf142b8d565a3c14d3db7a5a1c14b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Jun 2004 15:50:03 +0000 Subject: specific VGA BIOS for Cirrus VGA Card git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@905 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 ++ hw/pc.c | 7 ++++++- pc-bios/README | 4 ++++ pc-bios/vgabios-cirrus.bin | Bin 0 -> 26784 bytes 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 pc-bios/vgabios-cirrus.bin diff --git a/Makefile b/Makefile index 4137e9b95..d4c4b0ffe 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,7 @@ ifndef CONFIG_WIN32 endif mkdir -p "$(datadir)" install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ + pc-bios/vgabios-cirrus.bin \ pc-bios/linux_boot.bin "$(datadir)" mkdir -p "$(docdir)" install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" @@ -97,6 +98,7 @@ tarbin: $(bindir)/qemu-mkcow $(bindir)/vmdk2raw \ $(datadir)/bios.bin \ $(datadir)/vgabios.bin \ + $(datadir)/vgabios-cirrus.bin \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff --git a/hw/pc.c b/hw/pc.c index 788854b29..a40e1d03f 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -28,6 +28,7 @@ #define BIOS_FILENAME "bios.bin" #define VGABIOS_FILENAME "vgabios.bin" +#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin" #define LINUX_BOOT_FILENAME "linux_boot.bin" #define KERNEL_LOAD_ADDR 0x00100000 @@ -320,7 +321,11 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, } /* VGA BIOS load */ - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); + if (cirrus_vga_enabled) { + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME); + } else { + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); + } ret = load_image(buf, phys_ram_base + 0x000c0000); /* setup basic memory access */ diff --git a/pc-bios/README b/pc-bios/README index b5f0bc9e2..b5e9bf709 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -3,3 +3,7 @@ - The VGA BIOS comes from the LGPL VGA bios project (http://www.nongnu.org/vgabios/). + +- The Cirrus VGA BIOS comes from the LGPL VGA bios project with + patches from http://ebisa.hp.infoseek.co.jp/bochs/index.shtml. + \ No newline at end of file diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin new file mode 100644 index 000000000..f393404b6 Binary files /dev/null and b/pc-bios/vgabios-cirrus.bin differ -- cgit v1.2.3 From 1cc98a5f045fefd4d0243a8f868c8a331839def0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Jun 2004 16:06:33 +0000 Subject: hardware cursor depth = 15 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@906 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga_template.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vga_template.h b/hw/vga_template.h index 721abcb82..349d58858 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -497,7 +497,7 @@ void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, #else #error unsupported depth #endif - d += (DEPTH / 8); + d += BPP; } } #endif -- cgit v1.2.3 From 4c8732d71b61d2950a57dbb758517de536125175 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Jun 2004 19:46:45 +0000 Subject: cirrus blitter fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@907 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 31 ++++++++++++++++++++++++++++--- hw/cirrus_vga_rop2.h | 48 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index f0b22e77c..55a866a2e 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -136,6 +136,7 @@ // control 0x33 #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 +#define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 #define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 // memory-mapped IO @@ -325,7 +326,7 @@ static void cirrus_bitblt_fill_nop(CirrusVGAState *s, #include "cirrus_vga_rop.h" #define ROP_NAME 1 -#define ROP_OP(d, s) d = 0xff +#define ROP_OP(d, s) d = ~0 #include "cirrus_vga_rop.h" #define ROP_NAME notsrc_and_dst @@ -435,6 +436,25 @@ static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = { ROP2(cirrus_colorexpand_transp_notsrc_and_notdst), }; +static const cirrus_bitblt_rop_t cirrus_colorexpand_transp_inv[16][4] = { + ROP2(cirrus_colorexpand_transp_inv_0), + ROP2(cirrus_colorexpand_transp_inv_src_and_dst), + ROP_NOP2(cirrus_bitblt_rop_nop), + ROP2(cirrus_colorexpand_transp_inv_src_and_notdst), + ROP2(cirrus_colorexpand_transp_inv_notdst), + ROP2(cirrus_colorexpand_transp_inv_src), + ROP2(cirrus_colorexpand_transp_inv_1), + ROP2(cirrus_colorexpand_transp_inv_notsrc_and_dst), + ROP2(cirrus_colorexpand_transp_inv_src_xor_dst), + ROP2(cirrus_colorexpand_transp_inv_src_or_dst), + ROP2(cirrus_colorexpand_transp_inv_notsrc_or_notdst), + ROP2(cirrus_colorexpand_transp_inv_src_notxor_dst), + ROP2(cirrus_colorexpand_transp_inv_src_or_notdst), + ROP2(cirrus_colorexpand_transp_inv_notsrc), + ROP2(cirrus_colorexpand_transp_inv_notsrc_or_dst), + ROP2(cirrus_colorexpand_transp_inv_notsrc_and_notdst), +}; + static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = { ROP2(cirrus_colorexpand_0), ROP2(cirrus_colorexpand_src_and_dst), @@ -820,8 +840,13 @@ static void cirrus_bitblt_start(CirrusVGAState * s) CIRRUS_BLTMODE_COLOREXPAND) { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { - cirrus_bitblt_fgcol(s); - s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + cirrus_bitblt_bgcol(s); + s->cirrus_rop = cirrus_colorexpand_transp_inv[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } else { + cirrus_bitblt_fgcol(s); + s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } } else { cirrus_bitblt_fgcol(s); cirrus_bitblt_bgcol(s); diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h index 682662741..c7514d316 100644 --- a/hw/cirrus_vga_rop2.h +++ b/hw/cirrus_vga_rop2.h @@ -36,14 +36,14 @@ #error unsupported DEPTH #endif +/* NOTE: srcpitch is ignored */ static void glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src1, + const uint8_t * src, int dstpitch, int srcpitch, int bltwidth, int bltheight) { - const uint8_t *src; uint8_t *d; int x, y; unsigned bits; @@ -54,7 +54,6 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) col = s->cirrus_blt_fgcol; for(y = 0; y < bltheight; y++) { - src = src1; bitmask = 0x80 >> srcskipleft; bits = *src++; d = dst; @@ -70,7 +69,43 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) d += (DEPTH / 8); bitmask >>= 1; } - src1 += srcpitch; + dst += dstpitch; + } +} + +/* NOTE: srcpitch is ignored */ +static void +glue(glue(glue(cirrus_colorexpand_transp_inv_, ROP_NAME), _),DEPTH) + (CirrusVGAState * s, uint8_t * dst, + const uint8_t * src, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) +{ + uint8_t *d; + int x, y; + unsigned bits; + unsigned int col; + unsigned bitmask; + unsigned index; + int srcskipleft = 0; + + col = s->cirrus_blt_bgcol; + for(y = 0; y < bltheight; y++) { + bitmask = 0x80 >> srcskipleft; + bits = *src++; + d = dst; + for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + if ((bitmask & 0xff) == 0) { + bitmask = 0x80; + bits = *src++; + } + index = (bits & bitmask); + if (!index) { + PUTPIXEL(); + } + d += (DEPTH / 8); + bitmask >>= 1; + } dst += dstpitch; } } @@ -78,11 +113,10 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src1, + const uint8_t * src, int dstpitch, int srcpitch, int bltwidth, int bltheight) { - const uint8_t *src; uint32_t colors[2]; uint8_t *d; int x, y; @@ -94,7 +128,6 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) colors[0] = s->cirrus_blt_bgcol; colors[1] = s->cirrus_blt_fgcol; for(y = 0; y < bltheight; y++) { - src = src1; bitmask = 0x80 >> srcskipleft; bits = *src++; d = dst; @@ -108,7 +141,6 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) d += (DEPTH / 8); bitmask >>= 1; } - src1 += srcpitch; dst += dstpitch; } } -- cgit v1.2.3 From eb26db16d77fc4f2b4c6e09b0376c3e547600fe3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Jun 2004 20:43:57 +0000 Subject: endianness functions for unaligned memory accesses git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@908 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/vl.h b/vl.h index fc16f47c6..50116e8f1 100644 --- a/vl.h +++ b/vl.h @@ -141,6 +141,68 @@ static inline uint16_t cpu_to_le16(uint16_t v) } #endif +static inline void cpu_to_le16w(uint16_t *p, uint16_t v) +{ + *p = cpu_to_le16(v); +} + +static inline void cpu_to_le32w(uint32_t *p, uint32_t v) +{ + *p = cpu_to_le32(v); +} + +static inline uint16_t le16_to_cpup(const uint16_t *p) +{ + return le16_to_cpu(*p); +} + +static inline uint32_t le32_to_cpup(const uint32_t *p) +{ + return le32_to_cpu(*p); +} + +/* 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) + +#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); +} + +#endif /* vl.c */ extern int reset_requested; -- cgit v1.2.3 From 57ccbabecb4101200a48bfd748a6aa33ff3c27b0 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Jun 2004 20:45:42 +0000 Subject: allow 32 but unaligned access (aka Win PCI network bug - initial patch by Renzo Davoli) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@909 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 9a04c921d..9f35f1991 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -401,10 +401,10 @@ static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, uint32_t val) { - addr &= ~3; /* XXX: check exact behaviour if not even */ + addr &= ~1; /* XXX: check exact behaviour if not even */ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - *(uint32_t *)(s->mem + addr) = cpu_to_le32(val); + cpu_to_le32wu((uint32_t *)(s->mem + addr), val); } } @@ -431,10 +431,10 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr) static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr) { - addr &= ~3; /* XXX: check exact behaviour if not even */ + addr &= ~1; /* XXX: check exact behaviour if not even */ if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - return le32_to_cpu(*(uint32_t *)(s->mem + addr)); + return le32_to_cpupu((uint32_t *)(s->mem + addr)); } else { return 0xffffffff; } -- cgit v1.2.3 From 7ebb5e4139b92e3dfe6dd3e6271244a06ab456c3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Jun 2004 20:51:58 +0000 Subject: debug git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@910 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/dma.c b/hw/dma.c index bac6d95df..0ebb7533d 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -23,6 +23,8 @@ */ #include "vl.h" +//#define DEBUG_DMA + #define log(...) fprintf (stderr, "dma: " __VA_ARGS__) #ifdef DEBUG_DMA #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__) -- cgit v1.2.3 From d329a6fb2213e53008a9b1cd186fe2ff258fa272 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Jun 2004 20:58:31 +0000 Subject: audip fixes (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@911 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sb16.c | 50 ++++++-- oss.c | 423 ++++++++++++++++++++++++++++++++++---------------------------- 2 files changed, 275 insertions(+), 198 deletions(-) diff --git a/hw/sb16.c b/hw/sb16.c index 472d4c566..260718cdc 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -26,7 +26,10 @@ #define MIN(a, b) ((a)>(b)?(b):(a)) #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) -#define log(...) fprintf (stderr, "sb16: " __VA_ARGS__) +#define log(...) do { \ + fprintf (stderr, "sb16: " __VA_ARGS__); \ + fputc ('\n', stderr); \ +} while (0) /* #define DEBUG_SB16 */ #ifdef DEBUG_SB16 @@ -44,6 +47,8 @@ #define IO_WRITE_PROTO(name) \ void name (void *opaque, uint32_t nport, uint32_t val) +static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; + static struct { int ver_lo; int ver_hi; @@ -76,7 +81,7 @@ typedef struct SB16State { int v2x6; uint8_t in_data[10]; - uint8_t out_data[10]; + uint8_t out_data[50]; int left_till_irq; @@ -223,6 +228,20 @@ static void command (SB16State *dsp, uint8_t cmd) /* IMS uses those when probing for sound devices */ return; + case 0x04: + dsp->needed_bytes = 1; + break; + + case 0x05: + case 0x0e: + dsp->needed_bytes = 2; + break; + + case 0x0f: + dsp->needed_bytes = 1; + dsp_out_data (dsp, 0); + break; + case 0x10: dsp->needed_bytes = 1; break; @@ -274,8 +293,8 @@ static void command (SB16State *dsp, uint8_t cmd) uint8_t d0; d0 = 4; - if (dsp->fmt_signed) d0 |= 16; - if (dsp->fmt_stereo) d0 |= 32; + /* if (dsp->fmt_signed) d0 |= 16; */ + /* if (dsp->fmt_stereo) d0 |= 32; */ dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1); cmd = -1; break; @@ -324,6 +343,14 @@ static void command (SB16State *dsp, uint8_t cmd) dsp_out_data(dsp, sb.ver_hi); return; + case 0xe3: + { + int i; + for (i = sizeof (e3) - 1; i >= 0; --i) + dsp_out_data (dsp, e3[i]); + return; + } + case 0xf2: dsp_out_data(dsp, 0xaa); dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; @@ -360,6 +387,11 @@ static void complete (SB16State *dsp) } else { switch (dsp->cmd) { + case 0x05: + case 0x04: + case 0x0e: + case 0x0f: + break; case 0x10: break; @@ -425,8 +457,10 @@ static IO_WRITE_PROTO (dsp_write) iport = nport - sb.port; + ldebug ("write %#x %#x\n", nport, iport); switch (iport) { case 0x6: + control (0); if (0 == val) dsp->v2x6 = 0; else if ((1 == val) && (0 == dsp->v2x6)) { @@ -477,7 +511,7 @@ static IO_READ_PROTO (dsp_read) if (dsp->out_data_len) { retval = dsp->out_data[--dsp->out_data_len]; } else { - log("empty output buffer\n"); + log("empty output buffer"); goto error; } break; @@ -487,7 +521,7 @@ static IO_READ_PROTO (dsp_read) break; case 0xd: /* timer interrupt clear */ - log("timer interrupt clear\n"); + log("timer interrupt clear"); goto error; case 0xe: /* data available status | irq 8 ack */ @@ -669,7 +703,7 @@ static int magic_of_irq (int irq) case 10: return 8; default: - log ("bad irq %d\n", irq); + log ("bad irq %d", irq); return 2; } } @@ -687,7 +721,7 @@ static int irq_of_magic (int magic) case 8: return 10; default: - log ("bad irq magic %d\n", magic); + log ("bad irq magic %d", magic); return 2; } } diff --git a/oss.c b/oss.c index 81de93b5f..f0a74bde0 100644 --- a/oss.c +++ b/oss.c @@ -24,6 +24,7 @@ #include "vl.h" #ifndef _WIN32 +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -90,25 +92,38 @@ static inline uint32_t lsbindex (uint32_t u) ldebug ("ioctl " #args " = %d\n", ret); \ } while (0) -static int audio_fd = -1; -static int freq; -static int conf_nfrags = 4; -static int conf_fragsize; -static int nfrags; -static int fragsize; -static int bufsize; -static int nchannels; -static int fmt; -static int rpos; -static int wpos; -static int atom; -static int live; -static int leftover; -static int bytes_per_second; -static void *buf; -static enum {DONT, DSP, TID} estimate = TID; - -static void (*copy_fn)(void *, void *, int); +static struct { + int fd; + int freq; + int bits16; + int nchannels; + int rpos; + int wpos; + int live; + int oss_fmt; + int bytes_per_second; + int is_mapped; + void *buf; + int bufsize; + int nfrags; + int fragsize; + int old_optr; + int leftover; + uint64_t old_ticks; + void (*copy_fn)(void *, void *, int); +} oss = { .fd = -1 }; + +static struct { + int try_mmap; + int nfrags; + int fragsize; +} conf = { + .try_mmap = 0, + .nfrags = 4, + .fragsize = 4096 +}; + +static enum {DONT, DSP, TID} est = DONT; static void copy_no_conversion (void *dst, void *src, int size) { @@ -141,70 +156,124 @@ static void pab (struct audio_buf_info *abinfo) rpos, wpos, live); } -void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) +static void do_open () { - int fmt_; - int bits16; + int mmmmssss; + audio_buf_info abinfo; + int fmt, freq, nchannels; - if (-1 == audio_fd) { - AUD_open (rfreq, rnchannels, rfmt); - return; + if (oss.buf) { + if (-1 == munmap (oss.buf, oss.bufsize)) { + ERRFail ("failed to unmap audio buffer %p %d", + oss.buf, oss.bufsize); + } + oss.buf = NULL; } - switch (rfmt) { - case AUD_FMT_U8: - bits16 = 0; - fmt_ = AFMT_U8; - copy_fn = copy_no_conversion; - atom = 1; - break; + if (-1 != oss.fd) + close (oss.fd); - case AUD_FMT_S8: - Fail ("can not play 8bit signed"); + oss.fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK); + if (-1 == oss.fd) { + ERRFail ("can not open /dev/dsp"); + } - case AUD_FMT_S16: - bits16 = 1; - fmt_ = AFMT_S16_LE; - copy_fn = copy_no_conversion; - atom = 2; - break; + fmt = oss.oss_fmt; + freq = oss.freq; + nchannels = oss.nchannels; + + IOCTL ((oss.fd, SNDCTL_DSP_RESET, 1)); + IOCTL ((oss.fd, SNDCTL_DSP_SAMPLESIZE, &fmt)); + IOCTL ((oss.fd, SNDCTL_DSP_CHANNELS, &nchannels)); + IOCTL ((oss.fd, SNDCTL_DSP_SPEED, &freq)); + IOCTL ((oss.fd, SNDCTL_DSP_NONBLOCK)); + + mmmmssss = (conf.nfrags << 16) | conf.fragsize; + IOCTL ((oss.fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); + + if ((oss.oss_fmt != fmt) + || (oss.nchannels != nchannels) + || (oss.freq != freq)) { + Fail ("failed to set audio parameters\n" + "parameter | requested value | obtained value\n" + "format | %10d | %10d\n" + "channels | %10d | %10d\n" + "frequency | %10d | %10d\n", + oss.oss_fmt, fmt, + oss.nchannels, nchannels, + oss.freq, freq); + } - case AUD_FMT_U16: - bits16 = 1; - fmt_ = AFMT_S16_LE; - copy_fn = copy_u16_to_s16; - atom = 2; - break; + IOCTL ((oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo)); - default: - abort (); - } + oss.nfrags = abinfo.fragstotal; + oss.fragsize = abinfo.fragsize; + oss.bufsize = oss.nfrags * oss.fragsize; + oss.old_optr = 0; - if ((fmt_ == fmt) && (bits16 + 1 == nchannels) && (rfreq == freq)) - return; + oss.bytes_per_second = (freq << (nchannels >> 1)) << oss.bits16; + + linfo ("bytes per second %d\n", oss.bytes_per_second); + + linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", + abinfo.fragments, + abinfo.fragstotal, + abinfo.fragsize, + abinfo.bytes, + oss.bufsize); + + oss.buf = MAP_FAILED; + oss.is_mapped = 0; + + if (conf.try_mmap) { + oss.buf = mmap (NULL, oss.bufsize, PROT_WRITE, MAP_SHARED, oss.fd, 0); + if (MAP_FAILED == oss.buf) { + int err; + + err = errno; + log ("failed to mmap audio, size %d, fd %d\n" + "syserr: %s\n", + oss.bufsize, oss.fd, strerror (err)); + } else { - AUD_open (rfreq, rnchannels, rfmt); + est = TID; + oss.is_mapped = 1; + } + } + + if (MAP_FAILED == oss.buf) { + est = TID; + oss.buf = mmap (NULL, oss.bufsize, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (MAP_FAILED == oss.buf) { + ERRFail ("mmap audio buf, size %d", oss.bufsize); + } + } + + oss.rpos = 0; + oss.wpos = 0; + oss.live = 0; + + if (oss.is_mapped) { + int trig; + + trig = 0; + IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); + trig = PCM_ENABLE_OUTPUT; + IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); } } -void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) +static void maybe_open (int req_freq, int req_nchannels, + audfmt_e req_fmt, int force_open) { - int fmt_; - int mmmmssss; - struct audio_buf_info abinfo; - int _fmt; - int _freq; - int _nchannels; - int bits16; + int oss_fmt, bits16; - bits16 = 0; - - switch (rfmt) { + switch (req_fmt) { case AUD_FMT_U8: bits16 = 0; - fmt_ = AFMT_U8; - copy_fn = copy_no_conversion; - atom = 1; + oss_fmt = AFMT_U8; + oss.copy_fn = copy_no_conversion; break; case AUD_FMT_S8: @@ -212,111 +281,42 @@ void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) case AUD_FMT_S16: bits16 = 1; - fmt_ = AFMT_S16_LE; - copy_fn = copy_no_conversion; - atom = 2; + oss_fmt = AFMT_S16_LE; + oss.copy_fn = copy_no_conversion; break; case AUD_FMT_U16: bits16 = 1; - fmt_ = AFMT_S16_LE; - copy_fn = copy_u16_to_s16; - atom = 2; + oss_fmt = AFMT_S16_LE; + oss.copy_fn = copy_u16_to_s16; break; default: abort (); } - if (buf) { - free (buf); - buf = 0; - } - - if (-1 != audio_fd) - close (audio_fd); - - audio_fd = open ("/dev/dsp", O_WRONLY | O_NONBLOCK); - if (-1 == audio_fd) { - ERRFail ("can not open /dev/dsp"); - } - - _fmt = fmt_; - _freq = rfreq; - _nchannels = rnchannels; - - IOCTL ((audio_fd, SNDCTL_DSP_RESET, 1)); - IOCTL ((audio_fd, SNDCTL_DSP_SAMPLESIZE, &_fmt)); - IOCTL ((audio_fd, SNDCTL_DSP_CHANNELS, &_nchannels)); - IOCTL ((audio_fd, SNDCTL_DSP_SPEED, &_freq)); - IOCTL ((audio_fd, SNDCTL_DSP_NONBLOCK)); - - /* from oss.pdf: - - The argument to this call is an integer encoded as 0xMMMMSSSS (in - hex). The 16 least significant bits determine the fragment - size. The size is 2^SSSS. For examp le SSSS=0008 gives fragment - size of 256 bytes (2^8). The minimum is 16 bytes (SSSS=4) and the - maximum is total_buffer_size/2. Some devices or processor - architectures may require larger fragments - in this case the - requested fragment size is automatically increased. - - So ahem... 4096 = 2^12, and grand total 0x0004000c - */ - - mmmmssss = (conf_nfrags << 16) | conf_fragsize; - IOCTL ((audio_fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); - - linfo ("_fmt = %d, fmt = %d\n" - "_channels = %d, rnchannels = %d\n" - "_freq = %d, freq = %d\n", - _fmt, fmt_, - _nchannels, rnchannels, - _freq, rfreq); - - if (_fmt != fmt_) { - Fail ("format %d != %d", _fmt, fmt_); - } - - if (_nchannels != rnchannels) { - Fail ("channels %d != %d", _nchannels, rnchannels); + if (force_open + || (-1 == oss.fd) + || (oss_fmt != oss.oss_fmt) + || (req_nchannels != oss.nchannels) + || (req_freq != oss.freq) + || (bits16 != oss.bits16)) { + oss.oss_fmt = oss_fmt; + oss.nchannels = req_nchannels; + oss.freq = req_freq; + oss.bits16 = bits16; + do_open (); } +} - if (_freq != rfreq) { - Fail ("freq %d != %d", _freq, rfreq); - } - - IOCTL ((audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo)); - - nfrags = abinfo.fragstotal; - fragsize = abinfo.fragsize; - freq = _freq; - fmt = _fmt; - nchannels = rnchannels; - atom <<= nchannels >> 1; - bufsize = nfrags * fragsize; - - bytes_per_second = (freq << (nchannels >> 1)) << bits16; - - linfo ("bytes per second %d\n", bytes_per_second); - - linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", - abinfo.fragments, - abinfo.fragstotal, - abinfo.fragsize, - abinfo.bytes, - bufsize); - - if (NULL == buf) { - buf = malloc (bufsize); - if (NULL == buf) { - abort (); - } - } +void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) +{ + maybe_open (req_freq, req_nchannels, req_fmt, 0); +} - rpos = 0; - wpos = 0; - live = 0; +void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) +{ + maybe_open (req_freq, req_nchannels, req_fmt, 1); } int AUD_write (void *in_buf, int size) @@ -324,27 +324,27 @@ int AUD_write (void *in_buf, int size) int to_copy, temp; uint8_t *in, *out; - to_copy = MIN (bufsize - live, size); + to_copy = MIN (oss.bufsize - oss.live, size); temp = to_copy; in = in_buf; - out = buf; + out = oss.buf; while (temp) { int copy; - copy = MIN (temp, bufsize - wpos); - copy_fn (out + wpos, in, copy); + copy = MIN (temp, oss.bufsize - oss.wpos); + oss.copy_fn (out + oss.wpos, in, copy); - wpos += copy; - if (wpos == bufsize) { - wpos = 0; + oss.wpos += copy; + if (oss.wpos == oss.bufsize) { + oss.wpos = 0; } temp -= copy; in += copy; - live += copy; + oss.live += copy; } return to_copy; @@ -356,10 +356,34 @@ void AUD_run (void) int bytes; struct audio_buf_info abinfo; - if (0 == live) + if (0 == oss.live) return; - res = ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo); + if (oss.is_mapped) { + count_info info; + + res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); + if (-1 == res) { + int err; + + err = errno; + lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err)); + return; + } + + if (info.ptr > oss.old_optr) { + bytes = info.ptr - oss.old_optr; + } + else { + bytes = oss.bufsize + info.ptr - oss.old_optr; + } + + oss.old_optr = info.ptr; + oss.live -= bytes; + return; + } + + res = ioctl (oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo); if (-1 == res) { int err; @@ -369,7 +393,7 @@ void AUD_run (void) } bytes = abinfo.bytes; - bytes = MIN (live, bytes); + bytes = MIN (oss.live, bytes); #if 0 bytes = (bytes / fragsize) * fragsize; #endif @@ -377,9 +401,9 @@ void AUD_run (void) while (bytes) { int left, play, written; - left = bufsize - rpos; + left = oss.bufsize - oss.rpos; play = MIN (left, bytes); - written = write (audio_fd, (void *) ((uint32_t) buf + rpos), play); + written = write (oss.fd, (void *) ((uint32_t) oss.buf + oss.rpos), play); if (-1 == written) { if (EAGAIN == errno || EINTR == errno) { @@ -391,12 +415,12 @@ void AUD_run (void) } play = written; - live -= play; - rpos += play; + oss.live -= play; + oss.rpos += play; bytes -= play; - if (rpos == bufsize) { - rpos = 0; + if (oss.rpos == oss.bufsize) { + oss.rpos = 0; } } } @@ -406,7 +430,7 @@ static int get_dsp_bytes (void) int res; struct count_info info; - res = ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &info); + res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); if (-1 == res) { int err; @@ -420,22 +444,22 @@ static int get_dsp_bytes (void) } } -void AUD_adjust_estimate (int _leftover) +void AUD_adjust_estimate (int leftover) { - leftover = _leftover; + oss.leftover = leftover; } int AUD_get_free (void) { int free, elapsed; - free = bufsize - live; + free = oss.bufsize - oss.live; if (0 == free) return 0; elapsed = free; - switch (estimate) { + switch (est) { case DONT: break; @@ -456,16 +480,15 @@ int AUD_get_free (void) case TID: { - static uint64_t old_ticks; uint64_t ticks, delta; uint64_t ua_elapsed; uint64_t al_elapsed; ticks = qemu_get_clock(rt_clock); - delta = ticks - old_ticks; - old_ticks = ticks; + delta = ticks - oss.old_ticks; + oss.old_ticks = ticks; - ua_elapsed = (delta * bytes_per_second) / 1000; + ua_elapsed = (delta * oss.bytes_per_second) / 1000; al_elapsed = ua_elapsed & ~3ULL; ldebug ("tid elapsed %llu bytes\n", ua_elapsed); @@ -475,7 +498,7 @@ int AUD_get_free (void) else elapsed = al_elapsed; - elapsed += leftover; + elapsed += oss.leftover; } } @@ -490,27 +513,47 @@ int AUD_get_free (void) int AUD_get_live (void) { - return live; + return oss.live; } int AUD_get_buffer_size (void) { - return bufsize; + return oss.bufsize; +} + +#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" +#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" +#define QC_OSS_MMAP "QEMU_OSS_MMAP" + +static int get_conf_val (const char *key, int defval) +{ + int val = defval; + char *strval; + + strval = getenv (key); + if (strval) { + val = atoi (strval); + } + + return val; } void AUD_init (void) { int fsp; - int _fragsize = 4096; DEREF (pab); - fsp = _fragsize; + conf.fragsize = get_conf_val (QC_OSS_FRAGSIZE, conf.fragsize); + conf.nfrags = get_conf_val (QC_OSS_NFRAGS, conf.nfrags); + conf.try_mmap = get_conf_val (QC_OSS_MMAP, conf.try_mmap); + + fsp = conf.fragsize; if (0 != (fsp & (fsp - 1))) { Fail ("fragment size %d is not power of 2", fsp); } - conf_fragsize = lsbindex (fsp); + conf.fragsize = lsbindex (fsp); } #else -- cgit v1.2.3 From 3440557b6d979e0dddddb8c2440d7bf4375e80a7 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 8 Jun 2004 00:55:58 +0000 Subject: ioport read command git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@912 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/monitor.c b/monitor.c index b7ce550cf..d3c51e657 100644 --- a/monitor.c +++ b/monitor.c @@ -630,6 +630,35 @@ static void do_send_key(const char *string) } } +static void do_ioport_read(int count, int format, int size, int addr, int has_index, int index) +{ + uint32_t val; + int suffix; + + if (has_index) { + cpu_outb(NULL, addr & 0xffff, index & 0xff); + addr++; + } + addr &= 0xffff; + + switch(size) { + default: + case 1: + val = cpu_inb(NULL, addr); + suffix = 'b'; + break; + case 2: + val = cpu_inw(NULL, addr); + suffix = 'w'; + break; + case 4: + val = cpu_inl(NULL, addr); + suffix = 'l'; + break; + } + term_printf("port%c[0x%04x] = %#0*x\n", + suffix, addr, size * 2, val); +} static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, @@ -666,6 +695,9 @@ static term_cmd_t term_cmds[] = { "/fmt addr", "physical memory dump starting at 'addr'", }, { "p|print", "/i", do_print, "/fmt expr", "print expression value (use $reg for CPU register access)", }, + { "i", "/ii.", do_ioport_read, + "/fmt addr", "I/O port read" }, + { "sendkey", "s", do_send_key, "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, { NULL, NULL, }, @@ -1285,12 +1317,23 @@ static void term_handle_command(const char *cmdline) int val; while (isspace(*p)) p++; - if (*typestr == '?') { + if (*typestr == '?' || *typestr == '.') { typestr++; - if (*p == '\0') - has_arg = 0; - else - has_arg = 1; + if (*typestr == '?') { + if (*p == '\0') + has_arg = 0; + else + has_arg = 1; + } else { + if (*p == '.') { + p++; + while (isspace(*p)) + p++; + has_arg = 1; + } else { + has_arg = 0; + } + } if (nb_args >= MAX_ARGS) goto error_args; args[nb_args++] = (void *)has_arg; @@ -1369,6 +1412,9 @@ static void term_handle_command(const char *cmdline) case 5: cmd->handler(args[0], args[1], args[2], args[3], args[4]); break; + case 6: + cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]); + break; default: term_printf("unsupported number of arguments: %d\n", nb_args); goto fail; -- cgit v1.2.3 From ee38b4c8134caccffd62614579fe8befc7d100e6 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 8 Jun 2004 00:56:42 +0000 Subject: fixed full screen refresh git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@913 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 2 +- vl.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sdl.c b/sdl.c index dce81e120..ceb00ddf6 100644 --- a/sdl.c +++ b/sdl.c @@ -264,8 +264,8 @@ static void toggle_full_screen(DisplayState *ds) if (!gui_saved_grab) sdl_grab_end(); } + vga_invalidate_display(); vga_update_display(); - sdl_update(ds, 0, 0, screen->w, screen->h); } static void sdl_refresh(DisplayState *ds) diff --git a/vl.h b/vl.h index 50116e8f1..dde4e5dfb 100644 --- a/vl.h +++ b/vl.h @@ -542,6 +542,7 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size, int is_pci); void vga_update_display(void); +void vga_invalidate_display(void); void vga_screen_dump(const char *filename); /* cirrus_vga.c */ -- cgit v1.2.3 From 78e127efdbac82f148ed4f7b42f8f4f2873b4c5b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 8 Jun 2004 00:58:26 +0000 Subject: set memory size to 4MB for 5446 - fixed memory size probe (aka Win2000 bug) - fixed interlace support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@914 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 55a866a2e..a883d52b7 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -31,6 +31,7 @@ /* * TODO: + * - fix 24 bpp pattern fills (source is 32 bpp in that case) * - add support for WRITEMASK (GR2F) * - add support for scanline modulo in pattern fill * - optimize linear mappings @@ -233,6 +234,7 @@ typedef struct CirrusVGAState { int cirrus_linear_bitblt_io_addr; int cirrus_mmio_io_addr; uint32_t cirrus_addr_mask; + uint32_t linear_mmio_mask; uint8_t cirrus_shadow_gr0; uint8_t cirrus_shadow_gr1; uint8_t cirrus_hidden_dac_lockindex; @@ -268,6 +270,7 @@ typedef struct CirrusVGAState { int last_hw_cursor_y; int last_hw_cursor_y_start; int last_hw_cursor_y_end; + int real_vram_size; /* XXX: suppress that */ } CirrusVGAState; typedef struct PCICirrusVGAState { @@ -983,6 +986,22 @@ static int cirrus_get_bpp(VGAState *s1) return ret; } +static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight) +{ + int width, height; + + width = (s->cr[0x01] + 1) * 8; + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | + ((s->cr[0x07] & 0x40) << 3); + height = (height + 1); + /* interlace support */ + if (s->cr[0x1a] & 0x01) + height = height * 2; + *pwidth = width; + *pheight = height; +} + /*************************************** * * bank memory @@ -1970,7 +1989,7 @@ static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s) uint32_t content; int y, y_min, y_max; - src = s->vram_ptr + 0x200000 - 16 * 1024; + src = s->vram_ptr + s->real_vram_size - 16 * 1024; if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { src += (s->sr[0x13] & 0x3c) * 256; y_min = 64; @@ -2064,7 +2083,7 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) scr_y >= (s->hw_cursor_y + h)) return; - src = s->vram_ptr + 0x200000 - 16 * 1024; + src = s->vram_ptr + s->real_vram_size - 16 * 1024; if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { src += (s->sr[0x13] & 0x3c) * 256; src += (scr_y - s->hw_cursor_y) * 16; @@ -2130,10 +2149,10 @@ static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr) CirrusVGAState *s = (CirrusVGAState *) opaque; uint32_t ret; - /* XXX: s->vram_size must be a power of two */ addr &= s->cirrus_addr_mask; - if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & 0x1fff00) == 0x1fff00)) { + if (((s->sr[0x17] & 0x44) == 0x44) && + ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { /* memory-mapped I/O */ ret = cirrus_mmio_blt_read(s, addr & 0xff); } else if (0) { @@ -2190,8 +2209,9 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr, unsigned mode; addr &= s->cirrus_addr_mask; - - if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & 0x1fff00) == 0x1fff00)) { + + if (((s->sr[0x17] & 0x44) == 0x44) && + ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { /* memory-mapped I/O */ cirrus_mmio_blt_write(s, addr & 0xff, val); } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { @@ -2715,7 +2735,7 @@ static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { * ***************************************/ -static void cirrus_init_common(CirrusVGAState * s, int device_id) +static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) { int vga_io_memory, i; static int inited; @@ -2762,11 +2782,35 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id) vga_io_memory); s->sr[0x06] = 0x0f; - s->sr[0x0F] = CIRRUS_MEMSIZE_2M; s->sr[0x1F] = 0x22; // MemClock - + if (device_id == CIRRUS_ID_CLGD5446) { + /* 4MB 64 bit memory config, always PCI */ +#if 1 + s->sr[0x0f] = 0x98; + s->sr[0x17] = 0x20; + s->sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */ + s->real_vram_size = 4096 * 1024; +#else + s->sr[0x0f] = 0x18; + s->sr[0x17] = 0x20; + s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */ + s->real_vram_size = 2048 * 1024; +#endif + } else { + s->sr[0x0F] = CIRRUS_MEMSIZE_2M; + if (is_pci) + s->sr[0x17] = CIRRUS_BUSTYPE_PCI; + else + s->sr[0x17] = CIRRUS_BUSTYPE_ISA; + s->real_vram_size = 2048 * 1024; + s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */ + } s->cr[0x27] = device_id; + /* Win2K seems to assume that the pattern buffer is at 0xff + initially ! */ + memset(s->vram_ptr, 0xff, s->real_vram_size); + s->cirrus_hidden_dac_lockindex = 5; s->cirrus_hidden_dac_data = 0; @@ -2784,10 +2828,12 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id) cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s); /* XXX: s->vram_size must be a power of two */ - s->cirrus_addr_mask = s->vram_size - 1; + s->cirrus_addr_mask = s->real_vram_size - 1; + s->linear_mmio_mask = s->real_vram_size - 256; s->get_bpp = cirrus_get_bpp; s->get_offsets = cirrus_get_offsets; + s->get_resolution = cirrus_get_resolution; s->cursor_invalidate = cirrus_cursor_invalidate; s->cursor_draw_line = cirrus_cursor_draw_line; } @@ -2807,8 +2853,7 @@ void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - cirrus_init_common(s, CIRRUS_ID_CLGD5430); - s->sr[0x17] = CIRRUS_BUSTYPE_ISA; + cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0); /* XXX ISA-LFB support */ } @@ -2867,8 +2912,7 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, s = &d->cirrus_vga; vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - cirrus_init_common(s, device_id); - s->sr[0x17] = CIRRUS_BUSTYPE_PCI; + cirrus_init_common(s, device_id, 1); /* setup memory space */ /* memory #0 LFB */ -- cgit v1.2.3 From a130a41e69bd0d71574fa7c5b955f3850496fe76 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 8 Jun 2004 00:59:19 +0000 Subject: interlace support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@915 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 32 +++++++++++++++++++++++++------- hw/vga_int.h | 3 +++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 23695f506..57bad8fcb 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1301,6 +1301,19 @@ static int vga_get_bpp(VGAState *s) return ret; } +static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight) +{ + int width, height; + + width = (s->cr[0x01] + 1) * 8; + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | + ((s->cr[0x07] & 0x40) << 3); + height = (height + 1); + *pwidth = width; + *pheight = height; +} + void vga_invalidate_scanlines(VGAState *s, int y1, int y2) { int y; @@ -1327,11 +1340,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) full_update |= update_basic_params(s); - width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); - height = (height + 1); + s->get_resolution(s, &width, &height); disp_width = width; shift_control = (s->gr[0x05] >> 5) & 3; @@ -1562,6 +1571,15 @@ void vga_update_display(void) } } +/* force a full display refresh */ +void vga_invalidate_display(void) +{ + VGAState *s = vga_state; + + s->last_width = -1; + s->last_height = -1; +} + static void vga_reset(VGAState *s) { memset(s, 0, sizeof(VGAState)); @@ -1723,6 +1741,7 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, s->ds = ds; s->get_bpp = vga_get_bpp; s->get_offsets = vga_get_offsets; + s->get_resolution = vga_get_resolution; /* XXX: currently needed for display */ vga_state = s; } @@ -1875,8 +1894,7 @@ void vga_screen_dump(const char *filename) DisplayState *saved_ds, ds1, *ds = &ds1; /* XXX: this is a little hackish */ - s->last_width = -1; - s->last_height = -1; + vga_invalidate_display(); saved_ds = s->ds; memset(ds, 0, sizeof(DisplayState)); diff --git a/hw/vga_int.h b/hw/vga_int.h index 0d0f3edee..b86219cc1 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -103,6 +103,9 @@ void (*get_offsets)(struct VGAState *s, \ uint32_t *pline_offset, \ uint32_t *pstart_addr); \ + void (*get_resolution)(struct VGAState *s, \ + int *pwidth, \ + int *pheight); \ VGA_STATE_COMMON_BOCHS_VBE \ /* display refresh support */ \ DisplayState *ds; \ -- cgit v1.2.3 From 7f647cf68f8da27a3d7b2436d545dded3d0f30dd Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jun 2004 21:28:36 +0000 Subject: IDE1 init fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@916 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/pci.c b/hw/pci.c index e72071590..b05d5d9f5 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1021,6 +1021,7 @@ static void pci_bios_init_device(PCIDevice *d) /* PIIX3 IDE */ pci_config_writew(d, PCI_COMMAND, PCI_COMMAND_IO); pci_config_writew(d, 0x40, 0x8000); // enable IDE0 + pci_config_writew(d, 0x42, 0x8000); // enable IDE1 } else { /* IDE: we map it as in ISA mode */ pci_set_io_region_addr(d, 0, 0x1f0); -- cgit v1.2.3 From e69390cee7c7a0526eac5189fc98a05c0a39ce85 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Jun 2004 23:12:09 +0000 Subject: pattern fill fixes and optimization git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@917 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 49 ++++++++++++++++++++++++++++--------------------- hw/cirrus_vga_rop2.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index a883d52b7..655db9db4 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -31,9 +31,7 @@ /* * TODO: - * - fix 24 bpp pattern fills (source is 32 bpp in that case) * - add support for WRITEMASK (GR2F) - * - add support for scanline modulo in pattern fill * - optimize linear mappings * - optimize bitblt functions */ @@ -420,6 +418,25 @@ static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = { func,\ } +static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = { + ROP2(cirrus_patternfill_0), + ROP2(cirrus_patternfill_src_and_dst), + ROP_NOP2(cirrus_bitblt_rop_nop), + ROP2(cirrus_patternfill_src_and_notdst), + ROP2(cirrus_patternfill_notdst), + ROP2(cirrus_patternfill_src), + ROP2(cirrus_patternfill_1), + ROP2(cirrus_patternfill_notsrc_and_dst), + ROP2(cirrus_patternfill_src_xor_dst), + ROP2(cirrus_patternfill_src_or_dst), + ROP2(cirrus_patternfill_notsrc_or_notdst), + ROP2(cirrus_patternfill_src_notxor_dst), + ROP2(cirrus_patternfill_src_or_notdst), + ROP2(cirrus_patternfill_notsrc), + ROP2(cirrus_patternfill_notsrc_or_dst), + ROP2(cirrus_patternfill_notsrc_and_notdst), +}; + static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = { ROP2(cirrus_colorexpand_transp_0), ROP2(cirrus_colorexpand_transp_src_and_dst), @@ -569,9 +586,6 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, { uint8_t work_colorexp[256]; uint8_t *dst; - uint8_t *dstc; - int x, y; - int tilewidth, tileheight; int patternbytes = s->cirrus_blt_pixelwidth * 8; if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { @@ -592,21 +606,12 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, } dst = s->vram_ptr + s->cirrus_blt_dstaddr; - for (y = 0; y < s->cirrus_blt_height; y += 8) { - dstc = dst; - tileheight = qemu_MIN(8, s->cirrus_blt_height - y); - for (x = 0; x < s->cirrus_blt_width; x += patternbytes) { - tilewidth = qemu_MIN(patternbytes, s->cirrus_blt_width - x); - (*s->cirrus_rop) (s, dstc, src, - s->cirrus_blt_dstpitch, patternbytes, - tilewidth, tileheight); - dstc += patternbytes; - } - dst += s->cirrus_blt_dstpitch * 8; - } + (*s->cirrus_rop) (s, dst, src, + s->cirrus_blt_dstpitch, 0, + s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); return 1; } @@ -636,8 +641,8 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) { return cirrus_bitblt_common_patterncopy(s, - s->vram_ptr + - s->cirrus_blt_srcaddr); + s->vram_ptr + + (s->cirrus_blt_srcaddr & ~7)); } static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) @@ -855,6 +860,8 @@ static void cirrus_bitblt_start(CirrusVGAState * s) cirrus_bitblt_bgcol(s); s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; } + } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { + s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; } else { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h index c7514d316..540e308e8 100644 --- a/hw/cirrus_vga_rop2.h +++ b/hw/cirrus_vga_rop2.h @@ -36,6 +36,49 @@ #error unsupported DEPTH #endif +static void +glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) + (CirrusVGAState * s, uint8_t * dst, + const uint8_t * src, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) +{ + uint8_t *d; + int x, y, pattern_y, pattern_pitch, pattern_x; + unsigned int col; + const uint8_t *src1; + +#if DEPTH == 8 + pattern_pitch = 8; +#elif DEPTH == 16 + pattern_pitch = 16; +#else + pattern_pitch = 32; +#endif + pattern_y = s->cirrus_blt_srcaddr & 7; + pattern_x = 0; + for(y = 0; y < bltheight; y++) { + d = dst; + src1 = src + pattern_y * pattern_pitch; + for (x = 0; x < bltwidth; x += (DEPTH / 8)) { +#if DEPTH == 8 + col = src1[pattern_x]; + pattern_x = (pattern_x + 1) & 7; +#elif DEPTH == 16 + col = ((uint16_t *)(src1 + pattern_x))[0]; + pattern_x = (pattern_x + 2) & 15; +#else + col = ((uint32_t *)(src1 + pattern_x))[0]; + pattern_x = (pattern_x + 4) & 31; +#endif + PUTPIXEL(); + d += (DEPTH / 8); + } + pattern_y = (pattern_y + 1) & 7; + dst += dstpitch; + } +} + /* NOTE: srcpitch is ignored */ static void glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) -- cgit v1.2.3 From 5fef40fb4d7ec8386c8c0c704782f2b1fed3d438 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Jun 2004 11:34:10 +0000 Subject: added ffree git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@918 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-i386/op.c b/target-i386/op.c index 8b2800707..f7276ca67 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1639,6 +1639,11 @@ void OPPROTO op_fincstp(void) env->fpus &= (~0x4700); } +void OPPROTO op_ffree_STN(void) +{ + env->fptags[(env->fpstt + PARAM1) & 7] = 1; +} + void OPPROTO op_fmov_ST0_FT0(void) { ST0 = FT0; -- cgit v1.2.3 From 658c8bdadc04fc3d66bad80c1234fea8cc7cca41 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Jun 2004 11:35:12 +0000 Subject: added ffree - added cpu log option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@919 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index ee4f05ad3..811356baf 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3166,6 +3166,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fcomi_ST0_FT0(); s->cc_op = CC_OP_EFLAGS; break; + case 0x28: /* ffree sti */ + gen_op_ffree_STN(opreg); + break; case 0x2a: /* fst sti */ gen_op_fmov_STN_ST0(opreg); break; @@ -4635,6 +4638,9 @@ static inline int gen_intermediate_code_internal(CPUState *env, } #ifdef DEBUG_DISAS + if (loglevel & CPU_LOG_TB_CPU) { + cpu_dump_state(env, logfile, X86_DUMP_CCOP); + } if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); -- cgit v1.2.3 From 665656a99becf2aa688f434de137be4a530021eb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Jun 2004 11:38:00 +0000 Subject: ffree test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@920 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index f7e268652..73a701fcf 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -688,6 +688,14 @@ void test_fenv(void) TEST_ENV(&float_env16, "data16 fnsave", "data16 frstor"); TEST_ENV(&float_env32, "fnstenv", "fldenv"); TEST_ENV(&float_env32, "fnsave", "frstor"); + + /* test for ffree */ + for(i=0;i<5;i++) + asm volatile ("fldl %0" : : "m" (dtab[i])); + asm volatile("ffree %st(2)"); + asm volatile ("fnstenv %0\n" : : "m" (float_env32)); + asm volatile ("fninit"); + printf("fptag=%04x\n", float_env32.fptag); } -- cgit v1.2.3 From 2a2820560ddca9da787e6baccd169ad47c617d7c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Jun 2004 22:23:16 +0000 Subject: IDE ATA identify fix (aka FreeBSD 4.10 fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@921 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index 8b5f63e6d..fc0e13efa 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1099,7 +1099,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case WIN_IDENTIFY: if (s->bs && !s->is_cdrom) { ide_identify(s); - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); } else { if (s->is_cdrom) { -- cgit v1.2.3 From dc196a57e3e2e00e0c5f887390b1191787990193 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jun 2004 13:26:14 +0000 Subject: fixed 16 bit segment optimisations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@922 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 6 ++++-- target-i386/translate.c | 16 +++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9f16a487f..94f621cd1 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -116,7 +116,7 @@ /* 16 or 32 segments */ #define HF_CS32_SHIFT 4 #define HF_SS32_SHIFT 5 -/* zero base for DS, ES and SS */ +/* zero base for DS, ES and SS : can be '0' only in 32 bit CS segment */ #define HF_ADDSEG_SHIFT 6 /* copy of CR0.PE (protected mode) */ #define HF_PE_SHIFT 7 @@ -398,7 +398,9 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, >> (DESC_B_SHIFT - HF_CS32_SHIFT); new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) >> (DESC_B_SHIFT - HF_SS32_SHIFT); - if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + if (!(env->cr[0] & CR0_PE_MASK) || + (env->eflags & VM_MASK) || + !(new_hflags & HF_CS32_MASK)) { /* XXX: try to avoid this test. The problem comes from the fact that is real mode or vm86 mode we only modify the 'base' and 'selector' fields of the segment cache to go diff --git a/target-i386/translate.c b/target-i386/translate.c index 811356baf..13840bbf9 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1538,15 +1538,17 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) gen_op_set_cc_op(s->cc_op); gen_op_jmp_im(cur_eip); gen_op_movl_seg_T0(seg_reg); + /* abort translation because the addseg value may change or + because ss32 may change. For R_SS, translation must always + stop as a special handling must be done to disable hardware + interrupts for the next instruction */ + if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS)) + s->is_jmp = 3; } else { gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); + if (seg_reg == R_SS) + s->is_jmp = 3; } - /* abort translation because the register may have a non zero base - or because ss32 may change. For R_SS, translation must always - stop as a special handling must be done to disable hardware - interrupts for the next instruction */ - if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) - s->is_jmp = 3; } static inline void gen_stack_update(DisasContext *s, int addend) @@ -4572,7 +4574,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, ); #if 0 /* check addseg logic */ - if (!dc->addseg && (dc->vm86 || !dc->pe)) + if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32)) printf("ERROR addseg\n"); #endif -- cgit v1.2.3 From 516633dc42a2cd92347f1bd2ba365b4043b6e8e3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Jun 2004 15:20:01 +0000 Subject: jump to gate fix (aka OS/2 Warp install bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@923 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 9a88275f2..46aa7b1ca 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1264,6 +1264,9 @@ void helper_ljmp_protected_T0_T1(int next_eip) if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); gate_cs = e1 >> 16; + new_eip = (e1 & 0xffff); + if (type == 12) + new_eip |= (e2 & 0xffff0000); if (load_segment(&e1, &e2, gate_cs) != 0) raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; @@ -1276,9 +1279,6 @@ void helper_ljmp_protected_T0_T1(int next_eip) raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); - new_eip = (e1 & 0xffff); - if (type == 12) - new_eip |= (e2 & 0xffff0000); limit = get_seg_limit(e1, e2); if (new_eip > limit) raise_exception_err(EXCP0D_GPF, 0); -- cgit v1.2.3 From ea1c18022edd0e2c45552d6fc2da6e15a3486b33 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 14 Jun 2004 18:56:36 +0000 Subject: fixed self modifying code in case of asynchronous interrupt git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@924 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 617dea13c..91694a53a 100644 --- a/exec.c +++ b/exec.c @@ -613,7 +613,7 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, CPUState *env = cpu_single_env; #endif PageDesc *p; - TranslationBlock *tb, *tb_next, *current_tb; + TranslationBlock *tb, *tb_next, *current_tb, *saved_tb; target_ulong tb_start, tb_end; target_ulong current_pc, current_cs_base; @@ -681,7 +681,12 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, #endif } #endif /* TARGET_HAS_PRECISE_SMC */ + saved_tb = env->current_tb; + env->current_tb = NULL; tb_phys_invalidate(tb, -1); + env->current_tb = saved_tb; + if (env->interrupt_request && env->current_tb) + cpu_interrupt(env, env->interrupt_request); } tb = tb_next; } @@ -699,6 +704,7 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, /* we generate a block containing just the instruction modifying the memory. It will ensure that it cannot modify itself */ + env->current_tb = NULL; tb_gen_code(env, current_pc, current_cs_base, current_flags, CF_SINGLE_INSN); cpu_resume_from_signal(env, NULL); @@ -795,6 +801,7 @@ static void tb_invalidate_phys_page(target_ulong addr, /* we generate a block containing just the instruction modifying the memory. It will ensure that it cannot modify itself */ + env->current_tb = NULL; tb_gen_code(env, current_pc, current_cs_base, current_flags, CF_SINGLE_INSN); cpu_resume_from_signal(env, puc); -- cgit v1.2.3 From a0497918559b49a2453eb0fb7289d06897ddf74d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 14 Jun 2004 19:33:16 +0000 Subject: compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@925 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/exec.c b/exec.c index 91694a53a..45b723f6d 100644 --- a/exec.c +++ b/exec.c @@ -609,9 +609,7 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, int is_cpu_write_access) { int n, current_tb_modified, current_tb_not_found, current_flags; -#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY) CPUState *env = cpu_single_env; -#endif PageDesc *p; TranslationBlock *tb, *tb_next, *current_tb, *saved_tb; target_ulong tb_start, tb_end; -- cgit v1.2.3 From dbda808a4ad5744fded19bf6a750e7aecbf993d8 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Jun 2004 21:38:40 +0000 Subject: OpenPIC support (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@926 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/openpic.c | 998 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 998 insertions(+) create mode 100644 hw/openpic.c diff --git a/hw/openpic.c b/hw/openpic.c new file mode 100644 index 000000000..bd0661858 --- /dev/null +++ b/hw/openpic.c @@ -0,0 +1,998 @@ +/* + * OpenPIC emulation + * + * Copyright (c) 2004 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* + * + * Based on OpenPic implementations: + * - Intel GW80314 I/O compagnion chip developper's manual + * - Motorola MPC8245 & MPC8540 user manuals. + * - Motorola MCP750 (aka Raven) programmer manual. + * - Motorola Harrier programmer manuel + * + * Serial interrupts, as implemented in Raven chipset are not supported yet. + * + */ +#include "vl.h" + +#define DEBUG_OPENPIC + +#ifdef DEBUG_OPENPIC +#define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do { } while (0) +#endif +#define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0) + +#define USE_MPCxxx /* Intel model is broken, for now */ + +#if defined (USE_INTEL_GW80314) +/* Intel GW80314 I/O Companion chip */ + +#define MAX_CPU 4 +#define MAX_IRQ 32 +#define MAX_DBL 4 +#define MAX_MBX 4 +#define MAX_TMR 4 +#define VECTOR_BITS 8 +#define MAX_IPI 0 + +#define VID (0x00000000) + +#define OPENPIC_LITTLE_ENDIAN 1 +#define OPENPIC_BIG_ENDIAN 0 + +#elif defined(USE_MPCxxx) + +#define MAX_CPU 2 +#define MAX_IRQ 64 +#define EXT_IRQ 16 +#define MAX_DBL 0 +#define MAX_MBX 0 +#define MAX_TMR 4 +#define VECTOR_BITS 8 +#define MAX_IPI 4 +#define VID 0x03 /* MPIC version ID */ +#define VENI 0x00000000 /* Vendor ID */ + +enum { + IRQ_IPVP = 0, + IRQ_IDE, +}; + +#define OPENPIC_LITTLE_ENDIAN 1 +#define OPENPIC_BIG_ENDIAN 0 + +#else +#error "Please select which OpenPic implementation is to be emulated" +#endif + +#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \ + (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN) +#define OPENPIC_SWAP +#endif + +/* Interrupt definitions */ +#define IRQ_FE (EXT_IRQ) /* Internal functional IRQ */ +#define IRQ_ERR (EXT_IRQ + 1) /* Error IRQ */ +#define IRQ_TIM0 (EXT_IRQ + 2) /* First timer IRQ */ +#if MAX_IPI > 0 +#define IRQ_IPI0 (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */ +#define IRQ_DBL0 (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */ +#else +#define IRQ_DBL0 (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */ +#define IRQ_MBX0 (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */ +#endif + +#define BF_WIDTH(_bits_) \ +(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) + +static inline void set_bit (uint32_t *field, int bit) +{ + field[bit >> 5] |= 1 << (bit & 0x1F); +} + +static inline void reset_bit (uint32_t *field, int bit) +{ + field[bit >> 5] &= ~(1 << (bit & 0x1F)); +} + +static inline int test_bit (uint32_t *field, int bit) +{ + return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; +} + +enum { + IRQ_EXTERNAL = 0x01, + IRQ_INTERNAL = 0x02, + IRQ_TIMER = 0x04, + IRQ_SPECIAL = 0x08, +} IRQ_src_type; + +typedef struct IRQ_queue_t { + uint32_t queue[BF_WIDTH(MAX_IRQ)]; + int next; + int priority; +} IRQ_queue_t; + +typedef struct IRQ_src_t { + uint32_t ipvp; /* IRQ vector/priority register */ + uint32_t ide; /* IRQ destination register */ + int type; + int last_cpu; + int waited_acks; +} IRQ_src_t; + +enum IPVP_bits { + IPVP_MASK = 31, + IPVP_ACTIVITY = 30, + IPVP_MODE = 29, + IPVP_POLARITY = 23, + IPVP_SENSE = 22, +}; +#define IPVP_PRIORITY_MASK (0x1F << 16) +#define IPVP_PRIORITY(_ipvpr_) (((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16) +#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) +#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) + +typedef struct IRQ_dst_t { + uint32_t pctp; /* CPU current task priority */ + uint32_t pcsr; /* CPU sensitivity register */ + IRQ_queue_t raised; + IRQ_queue_t servicing; + CPUState *env; /* Needed if we did SMP */ +} IRQ_dst_t; + +typedef struct openpic_t { + PCIDevice pci_dev; + /* Global registers */ + uint32_t frep; /* Feature reporting register */ + uint32_t glbc; /* Global configuration register */ + uint32_t micr; /* MPIC interrupt configuration register */ + uint32_t veni; /* Vendor identification register */ + uint32_t spve; /* Spurious vector register */ + uint32_t tifr; /* Timer frequency reporting register */ + /* Source registers */ + IRQ_src_t src[MAX_IRQ]; + /* Local registers per output pin */ + IRQ_dst_t dst[MAX_CPU]; + int nb_cpus; + /* Timer registers */ + struct { + uint32_t ticc; /* Global timer current count register */ + uint32_t tibc; /* Global timer base count register */ + } timers[MAX_TMR]; +#if MAX_DBL > 0 + /* Doorbell registers */ + uint32_t dar; /* Doorbell activate register */ + struct { + uint32_t dmr; /* Doorbell messaging register */ + } doorbells[MAX_DBL]; +#endif +#if MAX_MBX > 0 + /* Mailbox registers */ + struct { + uint32_t mbr; /* Mailbox register */ + } mailboxes[MAX_MAILBOXES]; +#endif +} openpic_t; + +static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) +{ + set_bit(q->queue, n_IRQ); +} + +static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ) +{ + reset_bit(q->queue, n_IRQ); +} + +static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ) +{ + return test_bit(q->queue, n_IRQ); +} + +static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) +{ + int next, i; + int priority; + + next = -1; + priority = -1; + for (i = 0; i < MAX_IRQ; i++) { + if (IRQ_testbit(q, i)) { + if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { + next = i; + priority = IPVP_PRIORITY(opp->src[i].ipvp); + } + } + } + q->next = next; + q->priority = priority; +} + +static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) +{ + if (q->next == -1) { + if (q->queue == 0) { + /* No more IRQ */ + return -1; + } + IRQ_check(opp, q); + } + + return q->next; +} + +static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) +{ + IRQ_dst_t *dst; + IRQ_src_t *src; + int priority; + + dst = &opp->dst[n_CPU]; + src = &opp->src[n_IRQ]; + priority = IPVP_PRIORITY(src->ipvp); + if (priority <= dst->pctp) { + /* Too low priority */ + return; + } + if (IRQ_testbit(&dst->raised, n_IRQ)) { + /* Interrupt miss */ + return; + } + set_bit(&src->ipvp, IPVP_ACTIVITY); + IRQ_setbit(&dst->raised, n_IRQ); + if (priority > dst->raised.priority) { + IRQ_get_next(opp, &dst->raised); + DPRINTF("Raise CPU IRQ\n"); + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } +} + +void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level) +{ + IRQ_src_t *src; + int i; + + src = &opp->src[n_IRQ]; + if (!test_bit(&src->ipvp, IPVP_MASK)) { + /* Interrupt source is disabled */ + return; + } + if (IPVP_PRIORITY(src->ipvp) == 0) { + /* Priority set to zero */ + return; + } + if (src->ide == 0x00000000) { + /* No target */ + return; + } + if (level == 0) { + if (test_bit(&src->ipvp, IPVP_ACTIVITY) && + test_bit(&src->ipvp, IPVP_SENSE)) { + /* Inactivate a active level-sensitive IRQ */ + reset_bit(&src->ipvp, IPVP_ACTIVITY); + } + } else { + if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { + /* Interrupt already pending */ + return; + } + if (!test_bit(&src->ipvp, IPVP_MODE) || + src->ide == (1 << src->last_cpu)) { + /* Directed delivery mode */ + for (i = 0; i < opp->nb_cpus; i++) { + if (test_bit(&src->ide, i)) + IRQ_local_pipe(opp, i, n_IRQ); + } + } else { + /* Distributed delivery mode */ + for (i = src->last_cpu; i < src->last_cpu; i++) { + if (i == MAX_IRQ) + i = 0; + if (test_bit(&src->ide, i)) { + IRQ_local_pipe(opp, i, n_IRQ); + src->last_cpu = i; + break; + } + } + } + } +} + +static void openpic_reset (openpic_t *opp) +{ + int i; + + opp->glbc = 0x80000000; + /* Initialise controler registers */ + opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; + opp->veni = VENI; + opp->spve = 0x000000FF; + opp->tifr = 0x003F7A00; + /* ? */ + opp->micr = 0x00000000; + /* Initialise IRQ sources */ + for (i = 0; i < MAX_IRQ; i++) { + opp->src[i].ipvp = 0xA0000000; + opp->src[i].ide = 0x00000000; + } + /* Initialise IRQ destinations */ + for (i = 0; i < opp->nb_cpus; i++) { + opp->dst[i].pctp = 0x0000000F; + opp->dst[i].pcsr = 0x00000000; + memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); + memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); + } + /* Initialise timers */ + for (i = 0; i < MAX_TMR; i++) { + opp->timers[i].ticc = 0x00000000; + opp->timers[i].tibc = 0x80000000; + } + /* Initialise doorbells */ +#if MAX_DBL > 0 + opp->dar = 0x00000000; + for (i = 0; i < MAX_DBL; i++) { + opp->doorbells[i].dmr = 0x00000000; + } +#endif + /* Initialise mailboxes */ +#if MAX_MBX > 0 + for (i = 0; i < MAX_MBX; i++) { /* ? */ + opp->mailboxes[i].mbr = 0x00000000; + } +#endif + /* Go out of RESET state */ + opp->glbc = 0x00000000; +} + +static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg) +{ + uint32_t retval; + + switch (reg) { + case IRQ_IPVP: + retval = opp->src[n_IRQ].ipvp; + break; + case IRQ_IDE: + retval = opp->src[n_IRQ].ide; + break; + } + + return retval; +} + +static inline void write_IRQreg (openpic_t *opp, int n_IRQ, + uint32_t reg, uint32_t val) +{ + uint32_t tmp; + + switch (reg) { + case IRQ_IPVP: + tmp = opp->src[n_IRQ].ipvp & 0x40000000; + if (tmp == 0) { + tmp |= val & 0x80000000; + if ((opp->src[n_IRQ].type & IRQ_EXTERNAL) != 0) + tmp |= val & 0x40C00000; + else if ((opp->src[n_IRQ].type & IRQ_TIMER) != 0) + tmp |= val & 0x00F00000; + } else { + tmp |= val & 0x80000000; + } + opp->src[n_IRQ].ipvp = tmp | (val & 0x000F00FF); + DPRINTF("Set IPVP %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ipvp); + break; + case IRQ_IDE: + tmp = val & 0xC0000000; + tmp |= val & ((1 << MAX_CPU) - 1); + opp->src[n_IRQ].ide = tmp; + DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); + break; + } +} + +#if 0 // Code provision for Intel model +#if MAX_DBL > 0 +static uint32_t read_doorbell_register (openpic_t *opp, + int n_dbl, uint32_t offset) +{ + uint32_t retval; + + switch (offset) { + case DBL_IPVP_OFFSET: + retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP); + break; + case DBL_IDE_OFFSET: + retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE); + break; + case DBL_DMR_OFFSET: + retval = opp->doorbells[n_dbl].dmr; + break; + } + + return retval; +} + +static void write_doorbell_register (penpic_t *opp, int n_dbl, + uint32_t offset, uint32_t value) +{ + switch (offset) { + case DBL_IVPR_OFFSET: + write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value); + break; + case DBL_IDE_OFFSET: + write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value); + break; + case DBL_DMR_OFFSET: + opp->doorbells[n_dbl].dmr = value; + break; + } +} +#endif + +#if MAX_MBX > 0 +static uint32_t read_mailbox_register (openpic_t *opp, + int n_mbx, uint32_t offset) +{ + uint32_t retval; + + switch (offset) { + case MBX_MBR_OFFSET: + retval = opp->mailboxes[n_mbx].mbr; + break; + case MBX_IVPR_OFFSET: + retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP); + break; + case MBX_DMR_OFFSET: + retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE); + break; + } + + return retval; +} + +static void write_mailbox_register (openpic_t *opp, int n_mbx, + uint32_t address, uint32_t value) +{ + switch (offset) { + case MBX_MBR_OFFSET: + opp->mailboxes[n_mbx].mbr = value; + break; + case MBX_IVPR_OFFSET: + write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value); + break; + case MBX_DMR_OFFSET: + write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value); + break; + } +} +#endif +#endif /* 0 : Code provision for Intel model */ + +static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) +{ + openpic_t *opp = opaque; + + DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + if (addr & 0xF) + return; +#if defined OPENPIC_SWAP + val = bswap32(val); +#endif + addr &= 0xFF; + switch (addr) { + case 0x00: /* FREP */ + break; + case 0x20: /* GLBC */ + if (val & 0x80000000) + openpic_reset(opp); + opp->glbc = val & ~0x80000000; + break; + case 0x80: /* VENI */ + break; + case 0x90: /* PINT */ + /* XXX: Should be able to reset any CPU */ + if (val & 1) { + DPRINTF("Reset CPU IRQ\n"); + // cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET); + } + break; +#if MAX_IPI > 0 + case 0xA0: /* IPI_IPVP */ + case 0xB0: + case 0xC0: + case 0xD0: + { + int idx; + idx = (addr - 0xA0) >> 4; + write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val); + } + break; +#endif + case 0xE0: /* SPVE */ + opp->spve = val & 0x000000FF; + break; + case 0xF0: /* TIFR */ + opp->tifr = val; + break; + default: + break; + } +} + +static uint32_t openpic_gbl_read (void *opaque, uint32_t addr) +{ + openpic_t *opp = opaque; + uint32_t retval; + + DPRINTF("%s: addr %08x\n", __func__, addr); + retval = 0xFFFFFFFF; + if (addr & 0xF) + return retval; + addr &= 0xFF; + switch (addr) { + case 0x00: /* FREP */ + retval = opp->frep; + break; + case 0x20: /* GLBC */ + retval = opp->glbc; + break; + case 0x80: /* VENI */ + retval = opp->veni; + break; + case 0x90: /* PINT */ + retval = 0x00000000; + break; +#if MAX_IPI > 0 + case 0xA0: /* IPI_IPVP */ + case 0xB0: + case 0xC0: + case 0xD0: + { + int idx; + idx = (addr - 0xA0) >> 4; + retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP); + } + break; +#endif + case 0xE0: /* SPVE */ + retval = opp->spve; + break; + case 0xF0: /* TIFR */ + retval = opp->tifr; + break; + default: + break; + } + DPRINTF("%s: => %08x\n", __func__, retval); +#if defined OPENPIC_SWAP + retval = bswap32(retval); +#endif + + return retval; +} + +static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) +{ + openpic_t *opp = opaque; + int idx; + + DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + if (addr & 0xF) + return; +#if defined OPENPIC_SWAP + val = bswap32(val); +#endif + addr -= 0x1100; + addr &= 0xFFFF; + idx = (addr & 0xFFF0) >> 6; + addr = addr & 0x30; + switch (addr) { + case 0x00: /* TICC */ + break; + case 0x10: /* TIBC */ + if ((opp->timers[idx].ticc & 0x80000000) != 0 && + (val & 0x800000000) == 0 && + (opp->timers[idx].tibc & 0x80000000) != 0) + opp->timers[idx].ticc &= ~0x80000000; + opp->timers[idx].tibc = val; + break; + case 0x20: /* TIVP */ + write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val); + break; + case 0x30: /* TIDE */ + write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val); + break; + } +} + +static uint32_t openpic_timer_read (void *opaque, uint32_t addr) +{ + openpic_t *opp = opaque; + uint32_t retval; + int idx; + + DPRINTF("%s: addr %08x\n", __func__, addr); + retval = 0xFFFFFFFF; + if (addr & 0xF) + return retval; + addr -= 0x1100; + addr &= 0xFFFF; + idx = (addr & 0xFFF0) >> 6; + addr = addr & 0x30; + switch (addr) { + case 0x00: /* TICC */ + retval = opp->timers[idx].ticc; + break; + case 0x10: /* TIBC */ + retval = opp->timers[idx].tibc; + break; + case 0x20: /* TIPV */ + retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP); + break; + case 0x30: /* TIDE */ + retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE); + break; + } + DPRINTF("%s: => %08x\n", __func__, retval); +#if defined OPENPIC_SWAP + retval = bswap32(retval); +#endif + + return retval; +} + +static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val) +{ + openpic_t *opp = opaque; + int idx; + + DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + if (addr & 0xF) + return; +#if defined OPENPIC_SWAP + val = tswap32(val); +#endif + addr = addr & 0xFFF0; + idx = addr >> 5; + if (addr & 0x10) { + /* EXDE / IFEDE / IEEDE */ + write_IRQreg(opp, idx, IRQ_IDE, val); + } else { + /* EXVP / IFEVP / IEEVP */ + write_IRQreg(opp, idx, IRQ_IPVP, val); + } +} + +static uint32_t openpic_src_read (void *opaque, uint32_t addr) +{ + openpic_t *opp = opaque; + uint32_t retval; + int idx; + + DPRINTF("%s: addr %08x\n", __func__, addr); + retval = 0xFFFFFFFF; + if (addr & 0xF) + return retval; + addr = addr & 0xFFF0; + idx = addr >> 5; + if (addr & 0x10) { + /* EXDE / IFEDE / IEEDE */ + retval = read_IRQreg(opp, idx, IRQ_IDE); + } else { + /* EXVP / IFEVP / IEEVP */ + retval = read_IRQreg(opp, idx, IRQ_IPVP); + } + DPRINTF("%s: => %08x\n", __func__, retval); +#if defined OPENPIC_SWAP + retval = tswap32(retval); +#endif + + return retval; +} + +static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) +{ + openpic_t *opp = opaque; + IRQ_src_t *src; + IRQ_dst_t *dst; + int idx, n_IRQ; + + DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + if (addr & 0xF) + return; +#if defined OPENPIC_SWAP + val = bswap32(val); +#endif + addr &= 0x1FFF0; + idx = addr / 0x1000; + dst = &opp->dst[idx]; + addr &= 0xFF0; + switch (addr) { +#if MAX_IPI > 0 + case 0x40: /* PIPD */ + case 0x50: + case 0x60: + case 0x70: + idx = (addr - 0x40) >> 4; + write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val); + openpic_set_IRQ(opp, IRQ_IPI0 + idx, 1); + openpic_set_IRQ(opp, IRQ_IPI0 + idx, 0); + break; +#endif + case 0x80: /* PCTP */ + dst->pctp = val & 0x0000000F; + break; + case 0x90: /* WHOAMI */ + /* Read-only register */ + break; + case 0xA0: /* PIAC */ + /* Read-only register */ + break; + case 0xB0: /* PEOI */ + DPRINTF("PEOI\n"); + n_IRQ = IRQ_get_next(opp, &dst->servicing); + IRQ_resetbit(&dst->servicing, n_IRQ); + dst->servicing.next = -1; + src = &opp->src[n_IRQ]; + /* Set up next servicing IRQ */ + IRQ_get_next(opp, &dst->servicing); + /* Check queued interrupts. */ + n_IRQ = IRQ_get_next(opp, &dst->raised); + if (n_IRQ != -1) { + src = &opp->src[n_IRQ]; + if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { + DPRINTF("Raise CPU IRQ\n"); + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } + } + break; + default: + break; + } +} + +static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) +{ + openpic_t *opp = opaque; + IRQ_src_t *src; + IRQ_dst_t *dst; + uint32_t retval; + int idx, n_IRQ; + + DPRINTF("%s: addr %08x\n", __func__, addr); + retval = 0xFFFFFFFF; + if (addr & 0xF) + return retval; + addr &= 0x1FFF0; + idx = addr / 0x1000; + dst = &opp->dst[idx]; + addr &= 0xFF0; + switch (addr) { + case 0x80: /* PCTP */ + retval = dst->pctp; + break; + case 0x90: /* WHOAMI */ + retval = idx; + break; + case 0xA0: /* PIAC */ + n_IRQ = IRQ_get_next(opp, &dst->raised); + DPRINTF("PIAC: irq=%d\n", n_IRQ); + if (n_IRQ == -1) { + /* No more interrupt pending */ + retval = opp->spve; + } else { + src = &opp->src[n_IRQ]; + if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || + !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { + /* - Spurious level-sensitive IRQ + * - Priorities has been changed + * and the pending IRQ isn't allowed anymore + */ + reset_bit(&src->ipvp, IPVP_ACTIVITY); + retval = IPVP_VECTOR(opp->spve); + } else { + /* IRQ enter servicing state */ + IRQ_setbit(&dst->servicing, n_IRQ); + retval = IPVP_VECTOR(src->ipvp); + } + IRQ_resetbit(&dst->raised, n_IRQ); + dst->raised.next = -1; + if (!test_bit(&src->ipvp, IPVP_SENSE)) + reset_bit(&src->ipvp, IPVP_ACTIVITY); + } + break; + case 0xB0: /* PEOI */ + retval = 0; + break; +#if MAX_IPI > 0 + case 0x40: /* IDE */ + case 0x50: + idx = (addr - 0x40) >> 4; + retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE); + break; +#endif + default: + break; + } + DPRINTF("%s: => %08x\n", __func__, retval); +#if defined OPENPIC_SWAP + retval= bswap32(retval); +#endif + + return retval; +} + +static void openpic_buggy_write (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + printf("Invalid OPENPIC write access !\n"); +} + +static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr) +{ + printf("Invalid OPENPIC read access !\n"); + + return -1; +} + +static void openpic_writel (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + openpic_t *opp = opaque; + + addr &= 0x3FFFF; + DPRINTF("%s: offset %08lx val: %08x\n", __func__, addr, val); + if (addr < 0x1100) { + /* Global registers */ + openpic_gbl_write(opp, addr, val); + } else if (addr < 0x10000) { + /* Timers registers */ + openpic_timer_write(opp, addr, val); + } else if (addr < 0x20000) { + /* Source registers */ + openpic_src_write(opp, addr, val); + } else { + /* CPU registers */ + openpic_cpu_write(opp, addr, val); + } +} + +static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr) +{ + openpic_t *opp = opaque; + uint32_t retval; + + addr &= 0x3FFFF; + DPRINTF("%s: offset %08lx\n", __func__, addr); + if (addr < 0x1100) { + /* Global registers */ + retval = openpic_gbl_read(opp, addr); + } else if (addr < 0x10000) { + /* Timers registers */ + retval = openpic_timer_read(opp, addr); + } else if (addr < 0x20000) { + /* Source registers */ + retval = openpic_src_read(opp, addr); + } else { + /* CPU registers */ + retval = openpic_cpu_read(opp, addr); + } + + return retval; +} + +static CPUWriteMemoryFunc *openpic_write[] = { + &openpic_buggy_write, + &openpic_buggy_write, + &openpic_writel, +}; + +static CPUReadMemoryFunc *openpic_read[] = { + &openpic_buggy_read, + &openpic_buggy_read, + &openpic_readl, +}; + +static void openpic_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + openpic_t *opp; + int opp_io_memory; + + DPRINTF("Map OpenPIC\n"); + opp = (openpic_t *)pci_dev; + /* Global registers */ + DPRINTF("Register OPENPIC gbl %08x => %08x\n", + addr + 0x1000, addr + 0x1000 + 0x100); + /* Timer registers */ + DPRINTF("Register OPENPIC timer %08x => %08x\n", + addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR); + /* Interrupt source registers */ + DPRINTF("Register OPENPIC src %08x => %08x\n", + addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2)); + /* Per CPU registers */ + DPRINTF("Register OPENPIC dst %08x => %08x\n", + addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU); + opp_io_memory = cpu_register_io_memory(0, openpic_read, + openpic_write, opp); + cpu_register_physical_memory(addr, 0x40000, opp_io_memory); +#if 0 // Don't implement ISU for now + opp_io_memory = cpu_register_io_memory(0, openpic_src_read, + openpic_src_write); + cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2), + opp_io_memory); +#endif +} + +openpic_t *openpic_init (uint32_t isu_base, uint32_t idu_base, int nb_cpus) +{ + openpic_t *opp; + uint8_t *pci_conf; + int i, m; + + /* XXX: for now, only one CPU is supported */ + if (nb_cpus != 1) + return NULL; + opp = (openpic_t *)pci_register_device("OpenPIC", sizeof(openpic_t), + 0, -1, NULL, NULL); + if (opp == NULL) + return NULL; + pci_conf = opp->pci_dev.config; + pci_conf[0x00] = 0x14; // IBM MPIC2 + pci_conf[0x01] = 0x10; + pci_conf[0x02] = 0xFF; + pci_conf[0x03] = 0xFF; + pci_conf[0x0a] = 0x80; // PIC + pci_conf[0x0b] = 0x08; + pci_conf[0x0e] = 0x00; // header_type + pci_conf[0x3d] = 0x00; // no interrupt pin + + /* Register I/O spaces */ + pci_register_io_region((PCIDevice *)opp, 0, 0x40000, + PCI_ADDRESS_SPACE_MEM, &openpic_map); + + isu_base &= 0xFFFC0000; + opp->nb_cpus = nb_cpus; + /* Set IRQ types */ + for (i = 0; i < EXT_IRQ; i++) { + opp->src[i].type = IRQ_EXTERNAL; + } + for (; i < IRQ_TIM0; i++) { + opp->src[i].type = IRQ_SPECIAL; + } +#if MAX_IPI > 0 + m = IRQ_IPI0; +#else + m = IRQ_DBL0; +#endif + for (; i < m; i++) { + opp->src[i].type = IRQ_TIMER; + } + for (; i < MAX_IRQ; i++) { + opp->src[i].type = IRQ_INTERNAL; + } + openpic_reset(opp); + + return opp; +} -- cgit v1.2.3 From 05efe46eaa337ce7680a22c5e034686957dc3032 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 16 Jun 2004 20:34:33 +0000 Subject: VMware 4 disk images support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@927 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 8 +++ vmdk.h | 24 +++++++- vmdk2raw.c | 195 +++++++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 167 insertions(+), 60 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index dfa363927..5c4487973 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -574,6 +574,14 @@ Since holes are used, the displayed size of the COW disk image is not the real one. To know it, use the @code{ls -ls} command. @end enumerate +@subsection Convert VMware disk images to raw disk images + +You can use the tool @file{vmdk2raw} to convert VMware disk images to +raw disk images directly usable by QEMU. The syntax is: +@example +vmdk2raw vmware_image output_image +@end example + @section Network emulation QEMU simulates up to 6 networks cards (NE2000 boards). Each card can diff --git a/vmdk.h b/vmdk.h index a847f8b15..dbb352d49 100644 --- a/vmdk.h +++ b/vmdk.h @@ -32,12 +32,11 @@ struct cowdisk_header { - char magic[4]; /* COWD */ uint32_t version; uint32_t flags; uint32_t disk_sectors; uint32_t granularity; - uint32_t l1dir_sector; + uint32_t l1dir_offset; uint32_t l1dir_size; uint32_t file_sectors; uint32_t cylinders; @@ -50,3 +49,24 @@ struct cowdisk_header2 uint32_t parent_ts; uint32_t timestamp; }; + +/* based on vdk 3.1 10-11-2003 by Ken Kato */ + +struct vmdisk_header +{ + 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]; +}; diff --git a/vmdk2raw.c b/vmdk2raw.c index 4a63e76e9..b2454c2d5 100644 --- a/vmdk2raw.c +++ b/vmdk2raw.c @@ -30,131 +30,210 @@ #include "vmdk.h" #include "config-host.h" -struct cowdisk_header header; -struct cowdisk_header2 header2; -off_t disk_base, disk_limit; -unsigned int granule_size; -uint32_t l1dir[L1_SIZE]; - -unsigned int cached_l2dir; -uint32_t l2dir[L2_SIZE]; - -size_t read_physical(int fd, off64_t offset, size_t length, void *buffer) +static struct cowdisk_header header; +static struct vmdisk_header header4; +static off64_t disk_limit; +static unsigned int granule_size; +static uint32_t *l1dir; + +static unsigned int cached_l2dir; +static uint32_t l2dir[L2_SIZE]; + +static struct vmdk_prm { + uint32_t grain_table_size; + uint32_t sectors_per_grain; + uint32_t sectors_per_table; + uint32_t directory_size; +} vdsk; + +static size_t read_physical(int fd, off64_t offset, size_t length, void *buffer) { size_t n; - if (lseek64(fd, offset, SEEK_SET) == -1) - { - perror("lseek"); + if (lseek64(fd, offset, SEEK_SET) == -1) { + printf(" error trying to seek lseek to %lld", offset); return -1; } n = read(fd, buffer, length); - if (n == -1) - { - perror("read from disk"); + + if (n == -1) { + printf("read from disk %lld", offset); return -1; } return n; } -size_t copy_virtual(int in_fd, int out_fd, off64_t offset, void *buffer, size_t length) +static int read_l1dir(int fd, size_t offset, int num) +{ + l1dir = malloc(sizeof(*l1dir) * num); + if (!l1dir) + return -1; + return read_physical(fd, offset << SECTOR_BITS, sizeof(*l1dir) * num, (char *)l1dir) != (sizeof(*l1dir) * num); +} + +static int read_l2dir(int fd, size_t offset, int num) { - unsigned int granule_index, granule_offset; - unsigned int l1index, l2index; + return read_physical(fd, offset << SECTOR_BITS, sizeof(l2dir[0]) * num, (char *)l2dir) != sizeof(l2dir); +} - granule_index = offset / granule_size; +static size_t copy_virtual(struct vmdk_prm *dsk, int in_fd, int out_fd, off64_t offset, void *buffer, size_t length) +{ + + unsigned int granule_offset; + unsigned int grain_index; + unsigned int sector_map_idx; + granule_offset = offset % granule_size; length = MIN(length, granule_size - granule_offset); length = MIN(length, disk_limit - offset); - l1index = (granule_index >> L2_BITS) & L1_MASK; - l2index = granule_index & L2_MASK; + sector_map_idx = (offset >> SECTOR_BITS) / dsk->sectors_per_table; + + if (sector_map_idx >= dsk->directory_size) { + fprintf(stderr, "cannot locate grain table for %d in %d\n", sector_map_idx, dsk->directory_size); + return -1; + } - if (l1dir[l1index] == 0) + if (l1dir[sector_map_idx] == 0) goto zero_fill; + + if (sector_map_idx != cached_l2dir) { + if (read_l2dir(in_fd, l1dir[sector_map_idx], dsk->grain_table_size)) { + fprintf(stderr, "read failed\n"); + return -1; + } + cached_l2dir = sector_map_idx; + } - if (l1index != cached_l2dir) - { - if (read_physical(in_fd, (l1dir[l1index] << SECTOR_BITS), sizeof(l2dir), (char *)l2dir) != sizeof(l2dir)) - return 0; - - cached_l2dir = l1index; + grain_index = ((offset >> SECTOR_BITS) % dsk->sectors_per_table) / dsk->sectors_per_grain; + + if (grain_index >= dsk->grain_table_size) { + fprintf(stderr, "grain to large"); + return -1; } - if (l2dir[l2index] == 0) + if (l2dir[grain_index] == 0) goto zero_fill; - if (read_physical(in_fd, (l2dir[l2index] << SECTOR_BITS) + granule_offset, length, buffer) != length) - return 0; - + if (read_physical(in_fd, (l2dir[grain_index] << SECTOR_BITS) + granule_offset, length, buffer) != length) { + fprintf(stderr, "read error 2\n"); + return -1; + } + write(out_fd, buffer, length); return length; zero_fill: /* the last chunk of the file can not be sparse * or the file will be truncated */ - if (offset + length < disk_limit) { - memset(buffer, 0, length); - write(out_fd, buffer, length); + if (offset + length >= disk_limit) { + if (lseek64(out_fd, length-1, SEEK_CUR) == (off_t)-1) + perror("lseek"); + /* write the last NULL byte instead of seeking */ + const char nil = 0; + write(out_fd, &nil, 1); } else { - if (lseek(out_fd, length, SEEK_CUR) == (off_t)-1) + if (lseek64(out_fd, length, SEEK_CUR) == (off_t)-1) perror("lseek"); } return length; } - -int open_vmdk(const char *filename) +static int open_vmdk4(int fd) { - int fd = open(filename, O_RDONLY | O_LARGEFILE); - if (fd == -1) - { - perror(filename); + if (read(fd, &header4, sizeof(header4)) != sizeof(header4)) { + perror("read from disk"); return -1; } + + granule_size = header4.granularity << SECTOR_BITS; + disk_limit = header4.capacity << SECTOR_BITS; + + cached_l2dir = -1; + vdsk.grain_table_size = header4.num_gtes_per_gte; + vdsk.sectors_per_grain = header4.granularity; + vdsk.sectors_per_table = vdsk.grain_table_size * vdsk.sectors_per_grain; + vdsk.directory_size = (header4.capacity + vdsk.sectors_per_table - 1) / vdsk.sectors_per_table + 1; - if (read(fd, &header, sizeof(header)) != sizeof(header)) - { - perror("read from disk"); + if (read_l1dir(fd, header4.rgd_offset, vdsk.directory_size)) return -1; - } + + return 0; + +} - if (memcmp(header.magic, "COWD", 4) != 0) - { - fprintf(stderr, "%s is not a VMware virtual disk image\n", filename); +static int open_vmdk3(int fd) +{ + if (read(fd, &header, sizeof(header)) != sizeof(header)) { + perror("read from disk\n"); return -1; } - granule_size = header.granularity << SECTOR_BITS; - if (read_physical(fd, header.l1dir_sector << SECTOR_BITS, sizeof(l1dir), (char *)l1dir) != sizeof(l1dir)) + vdsk.sectors_per_grain = header.granularity; + vdsk.grain_table_size = L2_SIZE; + vdsk.sectors_per_table = vdsk.grain_table_size * vdsk.sectors_per_grain; + vdsk.directory_size = L1_SIZE; + if (read_l1dir(fd, header.l1dir_offset, L1_SIZE)) return -1; disk_limit = header.disk_sectors << SECTOR_BITS; + return fd; +} + +static int open_vmdk(const char *filename) +{ + int fd = open(filename, O_RDONLY | O_LARGEFILE); + if (fd == -1) { + perror(filename); + return -1; + } + + char magic[4]; + if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) { + perror("read from disk"); + return -1; + } + + if (!memcmp(magic, "KDMV", sizeof(magic))) { + open_vmdk4(fd); + } else if (!memcmp(magic, "COWD", sizeof(magic))) { + open_vmdk3(fd); + } else { + fprintf(stderr, "%s is not a VMware virtual disk image\n", filename); + return -1; + } + cached_l2dir = -1; return fd; } -void help(void) +static void help(void) { printf("vmdk2raw\n" "usage: vmdk2raw vmware_image output_image\n" "\n" - "vmware_image a vmware 2.x/3.x cow image\n" + "vmware_image a vmware cow image\n" "output_image the created disk image\n" ); exit(1); } -#define BUF_SIZE granule_size -void copy_disk(in_fd, out_fd) +#define BUF_SIZE 0x10000 +static void copy_disk(in_fd, out_fd) { char buf[BUF_SIZE]; off64_t i = 0; + int ret; while (i < disk_limit) { - i += copy_virtual(in_fd, out_fd, i, buf, sizeof(buf)); + ret = copy_virtual(&vdsk, in_fd, out_fd, i, buf, sizeof(buf)); + if (ret < 0) { + fprintf(stderr, "copying failed\n"); + exit(-1); + } + i += ret; } } @@ -170,7 +249,7 @@ int main(int argc, char **argv) return -1; } - out_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + out_fd = open(argv[2], O_WRONLY | O_LARGEFILE | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (out_fd < 0) { perror(argv[2]); return -1; -- cgit v1.2.3 From d69d1fa01ad5e64821ea2a6dd6bb018f6d570111 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Jun 2004 16:57:17 +0000 Subject: const fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@928 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index be95ff918..2331c419d 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -155,16 +155,16 @@ int target_msync(unsigned long start, unsigned long len, int flags); int size = sizeof(*ptr);\ switch(size) {\ case 1:\ - x = (typeof(*ptr))ldub(ptr);\ + x = (typeof(*ptr))ldub((void *)ptr);\ break;\ case 2:\ - x = (typeof(*ptr))lduw(ptr);\ + x = (typeof(*ptr))lduw((void *)ptr);\ break;\ case 4:\ - x = (typeof(*ptr))ldl(ptr);\ + x = (typeof(*ptr))ldl((void *)ptr);\ break;\ case 8:\ - x = (typeof(*ptr))ldq(ptr);\ + x = (typeof(*ptr))ldq((void *)ptr);\ break;\ default:\ abort();\ -- cgit v1.2.3 From 9231944d9669595cecee8dda969546216470d6ad Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Jun 2004 16:58:13 +0000 Subject: sigset_t endianness fix in signal context git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@929 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 113 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 46 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 41affb56e..bde492237 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -109,7 +109,8 @@ static inline int target_to_host_signal(int sig) return target_to_host_signal_table[sig]; } -void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) +static void host_to_target_sigset_internal(target_sigset_t *d, + const sigset_t *s) { int i; unsigned long sigmask; @@ -122,25 +123,35 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1); } #if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 - d->sig[0] = tswapl(target_sigmask); + d->sig[0] = target_sigmask; for(i = 1;i < TARGET_NSIG_WORDS; i++) { - d->sig[i] = tswapl(((unsigned long *)s)[i]); + d->sig[i] = ((unsigned long *)s)[i]; } #elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 - d->sig[0] = tswapl(target_sigmask); - d->sig[1] = tswapl(sigmask >> 32); + d->sig[0] = target_sigmask; + d->sig[1] = sigmask >> 32; #else #error host_to_target_sigset #endif } -void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) +void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) +{ + target_sigset_t d1; + int i; + + host_to_target_sigset_internal(&d1, s); + for(i = 0;i < TARGET_NSIG_WORDS; i++) + __put_user(d1.sig[i], &d->sig[i]); +} + +void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) { int i; unsigned long sigmask; target_ulong target_sigmask; - target_sigmask = tswapl(s->sig[0]); + target_sigmask = s->sig[0]; sigmask = 0; for(i = 0; i < 32; i++) { if (target_sigmask & (1 << i)) @@ -149,15 +160,25 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) #if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 ((unsigned long *)d)[0] = sigmask; for(i = 1;i < TARGET_NSIG_WORDS; i++) { - ((unsigned long *)d)[i] = tswapl(s->sig[i]); + ((unsigned long *)d)[i] = s->sig[i]; } #elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 - ((unsigned long *)d)[0] = sigmask | ((unsigned long)tswapl(s->sig[1]) << 32); + ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32); #else #error target_to_host_sigset #endif /* TARGET_LONG_BITS */ } +void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) +{ + target_sigset_t s1; + int i; + + for(i = 0;i < TARGET_NSIG_WORDS; i++) + __get_user(s1.sig[i], &s->sig[i]); + target_to_host_sigset_internal(d, &s1); +} + void host_to_target_old_sigset(target_ulong *old_sigset, const sigset_t *sigset) { @@ -640,7 +661,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, target_sigset_t *set, CPUX86State *env) { struct sigframe *frame; - int err = 0; + int i, err = 0; frame = get_sigframe(ka, env, sizeof(*frame)); @@ -659,12 +680,10 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, if (err) goto give_sigsegv; - if (TARGET_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); - } - if (err) - goto give_sigsegv; + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->extramask[i - 1])) + goto give_sigsegv; + } /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -704,7 +723,7 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, target_sigset_t *set, CPUX86State *env) { struct rt_sigframe *frame; - int err = 0; + int i, err = 0; frame = get_sigframe(ka, env, sizeof(*frame)); @@ -732,9 +751,10 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, env, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - if (err) - goto give_sigsegv; + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i])) + goto give_sigsegv; + } /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -829,11 +849,14 @@ long do_sigreturn(CPUX86State *env) fprintf(stderr, "do_sigreturn\n"); #endif /* set blocked signals */ - target_set.sig[0] = frame->sc.oldmask; - for(i = 1; i < TARGET_NSIG_WORDS; i++) - target_set.sig[i] = frame->extramask[i - 1]; + if (__get_user(target_set.sig[0], &frame->sc.oldmask)) + goto badframe; + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__get_user(target_set.sig[i], &frame->extramask[i - 1])) + goto badframe; + } - target_to_host_sigset(&set, &target_set); + target_to_host_sigset_internal(&set, &target_set); sigprocmask(SIG_SETMASK, &set, NULL); /* restore registers */ @@ -849,7 +872,6 @@ badframe: long do_rt_sigreturn(CPUX86State *env) { struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4); - target_sigset_t target_set; sigset_t set; // stack_t st; int eax; @@ -858,9 +880,7 @@ long do_rt_sigreturn(CPUX86State *env) if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; #endif - memcpy(&target_set, &frame->uc.uc_sigmask, sizeof(target_sigset_t)); - - target_to_host_sigset(&set, &target_set); + target_to_host_sigset(&set, &frame->uc.uc_sigmask); sigprocmask(SIG_SETMASK, &set, NULL); if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax)) @@ -1084,13 +1104,13 @@ static void setup_frame(int usig, struct emulated_sigaction *ka, target_sigset_t *set, CPUState *regs) { struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); - int err = 0; + int i, err = 0; err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); - if (TARGET_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->extramask[i - 1])) + return; } if (err == 0) @@ -1103,7 +1123,7 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, target_sigset_t *set, CPUState *env) { struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame)); - int err = 0; + int i, err = 0; if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) return /* 1 */; @@ -1117,7 +1137,10 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ env, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i])) + return; + } if (err == 0) err = setup_return(env, ka, &frame->retcode, frame, usig); @@ -1170,6 +1193,7 @@ long do_sigreturn(CPUState *env) struct sigframe *frame; target_sigset_t set; sigset_t host_set; + int i; /* * Since we stacked the signal on a 64-bit boundary, @@ -1185,13 +1209,14 @@ long do_sigreturn(CPUState *env) if (verify_area(VERIFY_READ, frame, sizeof (*frame))) goto badframe; #endif - if (__get_user(set.sig[0], &frame->sc.oldmask) - || (TARGET_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, - sizeof(frame->extramask)))) - goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask)) + goto badframe; + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__get_user(set.sig[i], &frame->extramask[i - 1])) + goto badframe; + } - target_to_host_sigset(&host_set, &set); + target_to_host_sigset_internal(&host_set, &set); sigprocmask(SIG_SETMASK, &host_set, NULL); if (restore_sigcontext(env, &frame->sc)) @@ -1212,7 +1237,6 @@ badframe: long do_rt_sigreturn(CPUState *env) { struct rt_sigframe *frame; - target_sigset_t set; sigset_t host_set; /* @@ -1229,10 +1253,7 @@ long do_rt_sigreturn(CPUState *env) if (verify_area(VERIFY_READ, frame, sizeof (*frame))) goto badframe; #endif - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - target_to_host_sigset(&host_set, &set); + target_to_host_sigset(&host_set, &frame->uc.uc_sigmask); sigprocmask(SIG_SETMASK, &host_set, NULL); if (restore_sigcontext(env, &frame->uc.uc_mcontext)) @@ -1335,7 +1356,7 @@ void process_pending_signals(void *cpu_env) sigprocmask(SIG_BLOCK, &set, &old_set); /* save the previous blocked signal state to restore it at the end of the signal execution (see do_sigreturn) */ - host_to_target_sigset(&target_old_set, &old_set); + host_to_target_sigset_internal(&target_old_set, &old_set); /* if the CPU is in VM86 mode, we restore the 32 bit values */ #ifdef TARGET_I386 -- cgit v1.2.3 From a5448a7de5bb35553a97c4e337ef2ef6fe8d3ccc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Jun 2004 16:59:03 +0000 Subject: sysinfo syscall (Francois Guimond) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@930 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 25 ++++++++++++++++++++++++- linux-user/syscall_defs.h | 17 +++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 37d644dd9..5b1f7a4ce 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -43,6 +43,7 @@ #include #include #include +#include //#include #include #include @@ -2348,7 +2349,29 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(swapoff((const char *)arg1)); break; case TARGET_NR_sysinfo: - goto unimplemented; + { + struct target_sysinfo *target_value = (void *)arg1; + struct sysinfo value; + ret = get_errno(sysinfo(&value)); + if (!is_error(ret) && target_value) + { + __put_user(value.uptime, &target_value->uptime); + __put_user(value.loads[0], &target_value->loads[0]); + __put_user(value.loads[1], &target_value->loads[1]); + __put_user(value.loads[2], &target_value->loads[2]); + __put_user(value.totalram, &target_value->totalram); + __put_user(value.freeram, &target_value->freeram); + __put_user(value.sharedram, &target_value->sharedram); + __put_user(value.bufferram, &target_value->bufferram); + __put_user(value.totalswap, &target_value->totalswap); + __put_user(value.freeswap, &target_value->freeswap); + __put_user(value.procs, &target_value->procs); + __put_user(value.totalhigh, &target_value->totalhigh); + __put_user(value.freehigh, &target_value->freehigh); + __put_user(value.mem_unit, &target_value->mem_unit); + } + } + break; case TARGET_NR_ipc: ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); break; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 356e6fd96..91e1fe538 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1133,3 +1133,20 @@ struct target_flock64 { /* vfat ioctls */ #define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1) #define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2) + +struct target_sysinfo { + target_long uptime; /* Seconds since boot */ + target_ulong loads[3]; /* 1, 5, and 15 minute load averages */ + target_ulong totalram; /* Total usable main memory size */ + target_ulong freeram; /* Available memory size */ + target_ulong sharedram; /* Amount of shared memory */ + target_ulong bufferram; /* Memory used by buffers */ + target_ulong totalswap; /* Total swap space size */ + target_ulong freeswap; /* swap space still available */ + unsigned short procs; /* Number of current processes */ + unsigned short pad; /* explicit padding for m68k */ + target_ulong totalhigh; /* Total high memory size */ + target_ulong freehigh; /* Available high memory size */ + unsigned int mem_unit; /* Memory unit size in bytes */ + char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */ +}; -- cgit v1.2.3 From 95ce326e5b47b4b841849f8a2ac7b96d6e204dfb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Jun 2004 17:22:53 +0000 Subject: buffer overflow fix - printf format fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@931 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index d3c51e657..a17e45af3 100644 --- a/monitor.c +++ b/monitor.c @@ -1437,7 +1437,7 @@ static void term_show_prompt(void) static void term_print_cmdline (const char *cmdline) { term_show_prompt(); - term_printf(cmdline); + term_printf("%s", cmdline); term_flush(); } @@ -1521,7 +1521,8 @@ static void term_up_char(void) } term_hist_entry--; if (term_hist_entry >= 0) { - strcpy(term_cmd_buf, term_history[term_hist_entry]); + pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), + term_history[term_hist_entry]); term_printf("\n"); term_print_cmdline(term_cmd_buf); term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); @@ -1533,7 +1534,8 @@ static void term_down_char(void) if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1) return; if (term_history[++term_hist_entry] != NULL) { - strcpy(term_cmd_buf, term_history[term_hist_entry]); + pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), + term_history[term_hist_entry]); } else { term_hist_entry = -1; } -- cgit v1.2.3 From eba2af633fb8fa3b20ad578184d79e1f0eabcefe Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Jun 2004 17:23:39 +0000 Subject: buffer overflow fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@932 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 2 +- linux-user/elfload.c | 2 +- target-i386/helper2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index c1267888c..e71adda19 100644 --- a/block.c +++ b/block.c @@ -92,7 +92,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) bs->fd = -1; bs->cow_fd = -1; bs->cow_bitmap = NULL; - strcpy(bs->filename, filename); + pstrcpy(bs->filename, sizeof(bs->filename), filename); /* open standard HD image */ #ifdef _WIN32 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 899e085c5..21261e2c0 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1067,7 +1067,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r char * passed_p; if (interpreter_type == INTERPRETER_AOUT) { - sprintf(passed_fileno, "%d", bprm->fd); + snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); passed_p = passed_fileno; if (elf_interpreter) { diff --git a/target-i386/helper2.c b/target-i386/helper2.c index e0d917a73..1d5bdc17e 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -212,7 +212,7 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) if (flags & X86_DUMP_CCOP) { if ((unsigned)env->cc_op < CC_OP_NB) - strcpy(cc_op_name, cc_op_str[env->cc_op]); + snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]); else snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", -- cgit v1.2.3 From 53ad66e8c370700595ba59f840f3545a5f54dff4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Jun 2004 17:35:07 +0000 Subject: print error messages if boot error git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@933 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index a8c407a58..0bf5d1d46 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ -- cgit v1.2.3 From d95dc32d1336a480941d0a298d2a659466547cda Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 12:35:26 +0000 Subject: added cpu_reset() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@934 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cpu-all.h b/cpu-all.h index eec101c7b..12e6d3ca2 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -621,6 +621,7 @@ 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 -- cgit v1.2.3 From e4f9082b9ae64a9ed413fb1a4498afa7f4cfcd63 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 12:35:44 +0000 Subject: added system_reset command git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@935 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/monitor.c b/monitor.c index a17e45af3..3c55c6265 100644 --- a/monitor.c +++ b/monitor.c @@ -660,6 +660,11 @@ static void do_ioport_read(int count, int format, int size, int addr, int has_in suffix, addr, size * 2, val); } +static void do_system_reset(void) +{ + qemu_system_reset_request(); +} + static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -700,6 +705,8 @@ static term_cmd_t term_cmds[] = { { "sendkey", "s", do_send_key, "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, + { "system_reset", "", do_system_reset, + "", "reset the system" }, { NULL, NULL, }, }; -- cgit v1.2.3 From 979a54fb20c6461669d8e620cd9760544c84254b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 12:36:04 +0000 Subject: new reset API git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@936 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdl.c b/sdl.c index ceb00ddf6..981922102 100644 --- a/sdl.c +++ b/sdl.c @@ -318,7 +318,7 @@ static void sdl_refresh(DisplayState *ds) sdl_process_key(&ev->key); break; case SDL_QUIT: - reset_requested = 1; + qemu_system_shutdown_request(); break; case SDL_MOUSEMOTION: if (gui_grab) { -- cgit v1.2.3 From bb0c6722b6606ad34da75d093d95a9bdfe42bc98 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 12:37:32 +0000 Subject: reset and shutdown support - PCI is now the default git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@937 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- vl.h | 8 +++++-- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index cdebcc203..fb073c24a 100644 --- a/vl.c +++ b/vl.c @@ -127,7 +127,7 @@ SerialState *serial_console; QEMUTimer *gui_timer; int vm_running; int audio_enabled = 0; -int pci_enabled = 0; +int pci_enabled = 1; int prep_enabled = 0; int rtc_utc = 1; int cirrus_vga_enabled = 0; @@ -1819,6 +1819,62 @@ void vm_stop(int reason) } } +/* reset/shutdown handler */ + +typedef struct QEMUResetEntry { + QEMUResetHandler *func; + void *opaque; + struct QEMUResetEntry *next; +} QEMUResetEntry; + +static QEMUResetEntry *first_reset_entry; +static int reset_requested; +static int shutdown_requested; + +void qemu_register_reset(QEMUResetHandler *func, void *opaque) +{ + QEMUResetEntry **pre, *re; + + pre = &first_reset_entry; + while (*pre != NULL) + pre = &(*pre)->next; + re = qemu_mallocz(sizeof(QEMUResetEntry)); + re->func = func; + re->opaque = opaque; + re->next = NULL; + *pre = re; +} + +void qemu_system_reset(void) +{ + QEMUResetEntry *re; + + /* reset all devices */ + for(re = first_reset_entry; re != NULL; re = re->next) { + re->func(re->opaque); + } +} + +void qemu_system_reset_request(void) +{ + reset_requested = 1; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); +} + +void qemu_system_shutdown_request(void) +{ + shutdown_requested = 1; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); +} + +static void main_cpu_reset(void *opaque) +{ +#ifdef TARGET_I386 + CPUState *env = opaque; + cpu_reset(env); +#endif +} + int main_loop(void) { #ifndef _WIN32 @@ -1833,10 +1889,15 @@ int main_loop(void) for(;;) { if (vm_running) { ret = cpu_exec(env); - if (reset_requested) { + if (shutdown_requested) { ret = EXCP_INTERRUPT; break; } + if (reset_requested) { + reset_requested = 0; + qemu_system_reset(); + ret = EXCP_INTERRUPT; + } if (ret == EXCP_DEBUG) { vm_stop(EXCP_DEBUG); } @@ -1967,6 +2028,9 @@ void help(void) "-nographic disable graphical output and redirect serial I/Os to console\n" "-enable-audio enable audio support\n" "-localtime set the real time clock to local time [default=utc]\n" +#ifdef TARGET_PPC + "-prep Simulate a PREP system (default is PowerMAC)\n" +#endif "\n" "Network options:\n" "-nics n simulate 'n' network cards [default=1]\n" @@ -1993,7 +2057,9 @@ void help(void) #ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n" #endif - +#ifdef TARGET_I386 + "-isa simulate an ISA-only system (default is PCI system)\n" +#endif "\n" "During emulation, use C-a h to get terminal commands:\n", #ifdef CONFIG_SOFTMMU @@ -2052,6 +2118,7 @@ enum { QEMU_OPTION_L, QEMU_OPTION_no_code_copy, QEMU_OPTION_pci, + QEMU_OPTION_isa, QEMU_OPTION_prep, QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, @@ -2103,6 +2170,7 @@ const QEMUOption qemu_options[] = { { "prep", 0, QEMU_OPTION_prep }, #endif { "localtime", 0, QEMU_OPTION_localtime }, + { "isa", 0, QEMU_OPTION_isa }, /* temporary options */ { "pci", 0, QEMU_OPTION_pci }, @@ -2380,6 +2448,9 @@ int main(int argc, char **argv) case QEMU_OPTION_pci: pci_enabled = 1; break; + case QEMU_OPTION_isa: + pci_enabled = 0; + break; case QEMU_OPTION_prep: prep_enabled = 1; break; @@ -2562,6 +2633,7 @@ int main(int argc, char **argv) register_savevm("timer", 0, 1, timer_save, timer_load, env); register_savevm("cpu", 0, 1, cpu_save, cpu_load, env); register_savevm("ram", 0, 1, ram_save, ram_load, NULL); + qemu_register_reset(main_cpu_reset, global_env); init_ioports(); cpu_calibrate_ticks(); diff --git a/vl.h b/vl.h index dde4e5dfb..fd2340509 100644 --- a/vl.h +++ b/vl.h @@ -205,8 +205,6 @@ static inline uint32_t le32_to_cpupu(const uint32_t *p) #endif /* vl.c */ -extern int reset_requested; - uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); void hw_error(const char *fmt, ...); @@ -229,6 +227,12 @@ void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque); void vm_start(void); void vm_stop(int reason); +typedef void QEMUResetHandler(void *opaque); + +void qemu_register_reset(QEMUResetHandler *func, void *opaque); +void qemu_system_reset_request(void); +void qemu_system_shutdown_request(void); + extern int audio_enabled; extern int ram_size; extern int bios_size; -- cgit v1.2.3 From d7d02e3c3a50782c0fa6b17d16f9957f1cc82a65 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 12:58:36 +0000 Subject: new reset API git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@938 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 9 ++++++++- hw/i8254.c | 24 +++++++++++++++++------- hw/i8259.c | 17 +++++++++++++---- hw/m48t59.c | 4 +--- hw/pckbd.c | 11 +++++------ 5 files changed, 44 insertions(+), 21 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index 0ebb7533d..29f2aeccc 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -355,6 +355,12 @@ void DMA_schedule(int nchan) cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } +static void dma_reset(void *opaque) +{ + struct dma_cont *d = opaque; + write_cont (d, (0x0d << d->dshift), 0); +} + /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base) { @@ -378,7 +384,8 @@ static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base) register_ioport_read (base + ((i + 8) << dshift), 1, 1, read_cont, d); } - write_cont (d, base + (0x0d << dshift), 0); + qemu_register_reset(dma_reset, d); + dma_reset(d); } void DMA_init (void) diff --git a/hw/i8254.c b/hw/i8254.c index 1eb4a1860..6f0516827 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -434,27 +434,37 @@ static int pit_load(QEMUFile *f, void *opaque, int version_id) return 0; } -PITState *pit_init(int base, int irq) +static void pit_reset(void *opaque) { - PITState *pit = &pit_state; + PITState *pit = opaque; PITChannelState *s; int i; for(i = 0;i < 3; i++) { s = &pit->channels[i]; - if (i == 0) { - /* the timer 0 is connected to an IRQ */ - s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s); - s->irq = irq; - } s->mode = 3; s->gate = (i != 2); pit_load_count(s, 0); } +} + +PITState *pit_init(int base, int irq) +{ + PITState *pit = &pit_state; + PITChannelState *s; + + s = &pit->channels[0]; + /* the timer 0 is connected to an IRQ */ + s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s); + s->irq = irq; register_savevm("i8254", base, 1, pit_save, pit_load, pit); + qemu_register_reset(pit_reset, pit); register_ioport_write(base, 4, 1, pit_ioport_write, pit); register_ioport_read(base, 3, 1, pit_ioport_read, pit); + + pit_reset(pit); + return pit; } diff --git a/hw/i8259.c b/hw/i8259.c index 622f0bb75..c21f0d306 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -231,10 +231,20 @@ int cpu_get_pic_interrupt(CPUState *env) return intno; } +static void pic_reset(void *opaque) +{ + PicState *s = opaque; + int tmp; + + tmp = s->elcr_mask; + memset(s, 0, sizeof(PicState)); + s->elcr_mask = tmp; +} + static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) { PicState *s = opaque; - int priority, cmd, irq, tmp; + int priority, cmd, irq; #ifdef DEBUG_PIC printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); @@ -243,9 +253,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (addr == 0) { if (val & 0x10) { /* init */ - tmp = s->elcr_mask; - memset(s, 0, sizeof(PicState)); - s->elcr_mask = tmp; + pic_reset(s); /* deassert a pending interrupt */ cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); @@ -458,6 +466,7 @@ static void pic_init1(int io_addr, int elcr_addr, PicState *s) register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s); } register_savevm("i8259", io_addr, 1, pic_save, pic_load, s); + qemu_register_reset(pic_reset, s); } void pic_info(void) diff --git a/hw/m48t59.c b/hw/m48t59.c index 9f0a128d5..445bc7179 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -162,9 +162,7 @@ static void watchdog_cb (void *opaque) NVRAM->buffer[0x1FF7] = 0x00; NVRAM->buffer[0x1FFC] &= ~0x40; /* May it be a hw CPU Reset instead ? */ - reset_requested = 1; - printf("Watchdog reset...\n"); - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + qemu_system_reset_request(); } else { pic_set_irq(NVRAM->IRQ, 1); pic_set_irq(NVRAM->IRQ, 0); diff --git a/hw/pckbd.c b/hw/pckbd.c index 8b809bd82..0d7b5ff09 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -139,7 +139,6 @@ typedef struct KBDState { } KBDState; KBDState kbd_state; -int reset_requested; /* update irq and KBD_STAT_[MOUSE_]OBF */ /* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be @@ -274,8 +273,7 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) break; #endif case KBD_CCMD_RESET: - reset_requested = 1; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + qemu_system_reset_request(); break; case 0xff: /* ignore that - I don't know what is its use */ @@ -617,8 +615,7 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1); #endif if (!(val & 1)) { - reset_requested = 1; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + qemu_system_reset_request(); } break; case KBD_CCMD_WRITE_MOUSE: @@ -630,8 +627,9 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) s->write_cmd = 0; } -void kbd_reset(KBDState *s) +static void kbd_reset(void *opaque) { + KBDState *s = opaque; KBDQueue *q; s->kbd_write_cmd = -1; @@ -656,4 +654,5 @@ void kbd_init(void) qemu_add_kbd_event_handler(pc_kbd_put_keycode, s); qemu_add_mouse_event_handler(pc_kbd_mouse_event, s); + qemu_register_reset(kbd_reset, s); } -- cgit v1.2.3 From a2f659ee48edc5de6f7ca1064a4f2af6227323a6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 13:00:26 +0000 Subject: new reset API - shutdown support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@939 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index a40e1d03f..4e2be2531 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -217,6 +217,9 @@ static uint32_t ioport92_read(void *opaque, uint32_t addr) void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) { + static const char shutdown_str[8] = "Shutdown"; + static int shutdown_index = 0; + switch(addr) { /* Bochs BIOS messages */ case 0x400: @@ -229,6 +232,18 @@ void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) fprintf(stderr, "%c", val); #endif break; + case 0x8900: + /* same as Bochs power off */ + if (val == shutdown_str[shutdown_index]) { + shutdown_index++; + if (shutdown_index == 8) { + shutdown_index = 0; + qemu_system_shutdown_request(); + } + } else { + shutdown_index = 0; + } + break; /* LGPL'ed VGA BIOS messages */ case 0x501: @@ -250,6 +265,7 @@ void bochs_bios_init(void) register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL); register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL); + register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL); register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL); register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); -- cgit v1.2.3 From ffddfee3793240d91e9d23fd436fb9e8d66d1069 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 13:01:25 +0000 Subject: added cpu_reset() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@940 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 1 + target-i386/helper2.c | 66 +++++++++++++++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 94f621cd1..2a1e73605 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -352,6 +352,7 @@ typedef struct CPUX86State { CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + /* from this point: preserved by CPU reset */ /* ice debug support */ uint32_t breakpoints[MAX_BREAKPOINTS]; int nb_breakpoints; diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 1d5bdc17e..03e3db30a 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -45,7 +45,6 @@ _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) CPUX86State *cpu_x86_init(void) { CPUX86State *env; - int i; static int inited; cpu_exec_init(); @@ -54,10 +53,46 @@ CPUX86State *cpu_x86_init(void) if (!env) return NULL; memset(env, 0, sizeof(CPUX86State)); + /* init various static tables */ + if (!inited) { + inited = 1; + optimize_flags_init(); + } +#ifdef USE_CODE_COPY + /* testing code for code copy case */ + { + struct modify_ldt_ldt_s ldt; - /* init to reset state */ + ldt.entry_number = 1; + ldt.base_addr = (unsigned long)env; + ldt.limit = (sizeof(CPUState) + 0xfff) >> 12; + ldt.seg_32bit = 1; + ldt.contents = MODIFY_LDT_CONTENTS_DATA; + ldt.read_exec_only = 0; + ldt.limit_in_pages = 1; + ldt.seg_not_present = 0; + ldt.useable = 1; + modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ + + asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); + cpu_single_env = env; + } +#endif + cpu_reset(env); + return env; +} + +/* NOTE: must be called outside the CPU execute loop */ +void cpu_reset(CPUX86State *env) +{ + int i; + + memset(env, 0, offsetof(CPUX86State, breakpoints)); tlb_flush(env, 1); + + /* init to reset state */ + #ifdef CONFIG_SOFTMMU env->hflags |= HF_SOFTMMU_MASK; #endif @@ -89,33 +124,6 @@ CPUX86State *cpu_x86_init(void) for(i = 0;i < 8; i++) env->fptags[i] = 1; env->fpuc = 0x37f; - - /* init various static tables */ - if (!inited) { - inited = 1; - optimize_flags_init(); - } -#ifdef USE_CODE_COPY - /* testing code for code copy case */ - { - struct modify_ldt_ldt_s ldt; - - ldt.entry_number = 1; - ldt.base_addr = (unsigned long)env; - ldt.limit = (sizeof(CPUState) + 0xfff) >> 12; - ldt.seg_32bit = 1; - ldt.contents = MODIFY_LDT_CONTENTS_DATA; - ldt.read_exec_only = 0; - ldt.limit_in_pages = 1; - ldt.seg_not_present = 0; - ldt.useable = 1; - modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - - asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); - cpu_single_env = env; - } -#endif - return env; } void cpu_x86_close(CPUX86State *env) -- cgit v1.2.3 From 987c1c6921cff548bfcc0bfe09d3394d5ef7f4c1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 13:02:46 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@941 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index b9eea8211..0b6aa80bf 100644 --- a/Changelog +++ b/Changelog @@ -16,7 +16,10 @@ version 0.5.6: - PIC reset fix (Hidemi KAWAI) - PIC spurious irq support (aka Solaris install bug) - added '-localtime' option - - preliminary Cirrus CLGD 54xx VGA support (Makoto Suzuki (suzu)) + - Cirrus CLGD 54xx VGA support (initial patch by Makoto Suzuki + (suzu)) + - APM and system shutdown support + - Fixed system reset version 0.5.5: -- cgit v1.2.3 From 9e57f14d60fd72fd0859e01635473d2963fb459f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 13:06:36 +0000 Subject: added APM support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@942 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 0bf5d1d46..b87e10b58 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ -- cgit v1.2.3 From 678f2df60fefdf75a880a606fb66d0238ecefbc2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 13:12:23 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@943 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.diff | 340 +++++++++++++++--------------------------------------- 1 file changed, 92 insertions(+), 248 deletions(-) diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 24a22b9bf..443236a24 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,260 +1,104 @@ Index: rombios.c =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v -retrieving revision 1.108 -diff -u -w -r1.108 rombios.c ---- rombios.c 9 Feb 2004 16:48:50 -0000 1.108 -+++ rombios.c 23 May 2004 15:48:52 -0000 -@@ -2254,6 +2254,7 @@ - type = read_byte(get_SS(),buffer+1) & 0x1f; - removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; - mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16; -+ blksize = 2048; +retrieving revision 1.110 +diff -u -w -r1.110 rombios.c +--- rombios.c 31 May 2004 13:11:27 -0000 1.110 ++++ rombios.c 20 Jun 2004 13:10:07 -0000 +@@ -137,6 +137,7 @@ + #define DEBUG_INT16 0 + #define DEBUG_INT1A 0 + #define DEBUG_INT74 0 ++#define DEBUG_APM 0 - write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type); - write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable); -@@ -3378,6 +3379,8 @@ - and al,#0x10 - mov ah, al + #define BX_CPU 3 + #define BX_USE_PS2_MOUSE 1 +@@ -145,6 +146,7 @@ + #define BX_SUPPORT_FLOPPY 1 + #define BX_FLOPPY_ON_CNT 37 // 2 seconds + #define BX_PCIBIOS 1 ++#define BX_APM 1 -+ or ecx, ecx -+ je int1586_tick_end - int1586_tick: - in al, #0x61 - and al,#0x10 -@@ -3386,6 +3389,7 @@ - mov ah, al - dec ecx - jnz int1586_tick -+int1586_tick_end: - ASM_END - - break; -@@ -3781,7 +3785,17 @@ - write_word(ebda_seg, 0x0022, mouse_driver_offset); - write_word(ebda_seg, 0x0024, mouse_driver_seg); - mouse_flags_2 = read_byte(ebda_seg, 0x0027); -+ if (mouse_driver_offset == 0 && -+ mouse_driver_seg == 0) { -+ /* remove handler */ -+ if ( (mouse_flags_2 & 0x80) != 0 ) { -+ mouse_flags_2 &= ~0x80; -+ inhibit_mouse_int_and_events(); // disable IRQ12 and packets -+ } -+ } else { -+ /* install handler */ - mouse_flags_2 |= 0x80; -+ } - write_byte(ebda_seg, 0x0027, mouse_flags_2); - CLEAR_CF(); - regs.u.r8.ah = 0; -@@ -4409,7 +4423,8 @@ - mouse_flags_2 = read_byte(ebda_seg, 0x0027); + #define BX_USE_ATADRV 1 + #define BX_ELTORITO_BOOT 1 +@@ -230,17 +232,6 @@ + out dx,ax + MEND - if ( (mouse_flags_2 & 0x80) != 0x80 ) { -- BX_PANIC("int74_function:\n"); -+ // BX_PANIC("int74_function:\n"); -+ return; +-MACRO HALT2 +- ;; the HALT macro is called with the line number of the HALT call. +- ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex +- ;; to print a BX_PANIC message. This will normally halt the simulation +- ;; with a message such as "BIOS panic at rombios.c, line 4091". +- ;; However, users can choose to make panics non-fatal and continue. +- mov dx,#PANIC_PORT2 +- mov ax,#?1 +- out dx,ax +-MEND +- + MACRO JMP_AP + db 0xea + dw ?2 +@@ -1543,15 +1534,12 @@ } - package_count = mouse_flags_2 & 0x07; -@@ -4833,8 +4848,10 @@ - // --------------------------------------------------------------------------- + if (action & BIOS_PRINTF_HALT) { +- // freeze in a busy loop. If I do a HLT instruction, then in versions +- // 1.3.pre1 and earlier, it will panic without ever updating the VGA +- // display, so the panic message will not be visible. By waiting +- // forever, you are certain to see the panic message on screen. +- // After a few more versions have passed, we can turn this back into +- // a halt or something. +- // do {} while (1); ++ // freeze in a busy loop. + ASM_START +- HALT2(__LINE__) ++ cli ++ halt2_loop: ++ hlt ++ jmp halt2_loop + ASM_END + } + } +@@ -8344,6 +8332,19 @@ + pop ax + iret - void --int13_cdrom(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS) -- Bit16u DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS; -+int13_cdrom(DI, DIH, SI, SIH, BP, BPH, SP, SPH, BX, BXH, DX, DXH, CX, CXH, AX, AXH, -+ DS, ES, FLAGS) -+ Bit16u DI, DIH, SI, SIH, BP, BPH, SP, SPH, BX, BXH, DX, DXH, CX, CXH, AX, AXH, -+ DS, ES, FLAGS; - { - Bit16u ebda_seg=read_word(0x0040,0x000E); - Bit8u device, status, locks; -@@ -7692,9 +7709,12 @@ ++ ++;-------------------- ++#if BX_APM ++use32 386 ++#define APM_PROT32 ++#include "apmbios.S" ++use16 386 ++ ++#define APM_REAL ++#include "apmbios.S" ++ ++#endif ++ + ;-------------------- + #if BX_PCIBIOS + use32 386 +@@ -9560,6 +9561,10 @@ + .org 0xf859 ; INT 15h System Services Entry Point + int15_handler: + pushf ++#if BX_APM ++ cmp ah, #0x53 ++ je apm_call ++#endif push ds - push ss - pop ds -- pusha -+ // ebx is modified: BSD 5.2.1 boot loader problem, so we save all -+ // the 32 bit registers. It should be done in all the bios or no 32 -+ // bit register should be used without saving it first. -+ pushad - call _int13_cdrom -- popa -+ popad - pop ds - pop es + push es + pushad +@@ -9570,6 +9575,10 @@ popf -@@ -8401,57 +8421,69 @@ - cmp al, #0x08 - jne pci_pro_f09 - call pci_pro_select_reg -+ push edx - mov dx, di - and dx, #0x03 - add dx, #0x0cfc - in al, dx -+ pop edx - mov cl, al - jmp pci_pro_ok - pci_pro_f09: ;; read configuration word - cmp al, #0x09 - jne pci_pro_f0a - call pci_pro_select_reg -+ push edx - mov dx, di - and dx, #0x02 - add dx, #0x0cfc - in ax, dx -+ pop edx - mov cx, ax - jmp pci_pro_ok - pci_pro_f0a: ;; read configuration dword - cmp al, #0x0a - jne pci_pro_f0b - call pci_pro_select_reg -+ push edx - mov dx, #0x0cfc - in eax, dx -+ pop edx - mov ecx, eax - jmp pci_pro_ok - pci_pro_f0b: ;; write configuration byte - cmp al, #0x0b - jne pci_pro_f0c - call pci_pro_select_reg -+ push edx - mov dx, di - and dx, #0x03 - add dx, #0x0cfc - mov al, cl - out dx, al -+ pop edx - jmp pci_pro_ok - pci_pro_f0c: ;; write configuration word - cmp al, #0x0c - jne pci_pro_f0d - call pci_pro_select_reg -+ push edx - mov dx, di - and dx, #0x02 - add dx, #0x0cfc - mov ax, cx - out dx, ax -+ pop edx - jmp pci_pro_ok - pci_pro_f0d: ;; write configuration dword - cmp al, #0x0d - jne pci_pro_unknown - call pci_pro_select_reg -+ push edx - mov dx, #0x0cfc - mov eax, ecx - out dx, eax -+ pop edx - jmp pci_pro_ok - pci_pro_unknown: - mov ah, #0x81 -@@ -8468,6 +8500,7 @@ - retf - - pci_pro_select_reg: -+ push edx - mov eax, #0x800000 - mov ax, bx - shl eax, #8 -@@ -8476,6 +8509,7 @@ - and al, #0xfc - mov dx, #0x0cf8 - out dx, eax -+ pop edx - ret - - use16 386 -@@ -8536,57 +8570,69 @@ - cmp al, #0x08 - jne pci_real_f09 - call pci_real_select_reg -+ push dx - mov dx, di - and dx, #0x03 - add dx, #0x0cfc - in al, dx -+ pop dx - mov cl, al - jmp pci_real_ok - pci_real_f09: ;; read configuration word - cmp al, #0x09 - jne pci_real_f0a - call pci_real_select_reg -+ push dx - mov dx, di - and dx, #0x02 - add dx, #0x0cfc - in ax, dx -+ pop dx - mov cx, ax - jmp pci_real_ok - pci_real_f0a: ;; read configuration dword - cmp al, #0x0a - jne pci_real_f0b - call pci_real_select_reg -+ push dx - mov dx, #0x0cfc - in eax, dx -+ pop dx - mov ecx, eax - jmp pci_real_ok - pci_real_f0b: ;; write configuration byte - cmp al, #0x0b - jne pci_real_f0c - call pci_real_select_reg -+ push dx - mov dx, di - and dx, #0x03 - add dx, #0x0cfc - mov al, cl - out dx, al -+ pop dx - jmp pci_real_ok - pci_real_f0c: ;; write configuration word - cmp al, #0x0c - jne pci_real_f0d - call pci_real_select_reg -+ push dx - mov dx, di - and dx, #0x02 - add dx, #0x0cfc - mov ax, cx - out dx, ax -+ pop dx - jmp pci_real_ok - pci_real_f0d: ;; write configuration dword - cmp al, #0x0d - jne pci_real_unknown - call pci_real_select_reg -+ push dx - mov dx, #0x0cfc - mov eax, ecx - out dx, eax -+ pop dx - jmp pci_real_ok - pci_real_unknown: - mov ah, #0x81 -@@ -8599,6 +8645,7 @@ - ret + //JMPL(iret_modify_cf) + jmp iret_modify_cf ++#if BX_APM ++apm_call: ++ jmp _apmreal_entry ++#endif - pci_real_select_reg: -+ push dx - mov eax, #0x800000 - mov ax, bx - shl eax, #8 -@@ -8607,6 +8654,7 @@ - and al, #0xfc - mov dx, #0x0cf8 - out dx, eax -+ pop dx - ret - - .align 16 + ;; Protected mode IDT descriptor + ;; -- cgit v1.2.3 From 63b7e036978df6323345bcfa16dba7771e351a85 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 13:38:54 +0000 Subject: boot to top of 4GB space git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@944 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 03e3db30a..455b348a0 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -107,8 +107,7 @@ void cpu_reset(CPUX86State *env) env->tr.limit = 0xffff; env->tr.flags = DESC_P_MASK; - /* not correct (CS base=0xffff0000) */ - cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0xffff0000, 0xffff, 0); cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0); cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0); cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0); -- cgit v1.2.3 From 70867490723b3a5b342f95ff9fa496376f0b0dd7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 13:42:16 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@945 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 0b6aa80bf..e92283c9b 100644 --- a/Changelog +++ b/Changelog @@ -20,6 +20,7 @@ version 0.5.6: (suzu)) - APM and system shutdown support - Fixed system reset + - Support for other PC BIOSes version 0.5.5: -- cgit v1.2.3 From 7587cf44019d593bb12703e7046bd7738996c55c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Jun 2004 13:43:27 +0000 Subject: accept bigger PC BIOSes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@946 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 38 +++++++++++++++++++++++++++++++------- vl.c | 12 ++++++++++++ vl.h | 3 ++- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 4e2be2531..30e823b36 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -322,6 +322,8 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; int ret, linux_boot, initrd_size, i, nb_nics1, fd; + unsigned long bios_offset, vga_bios_offset; + int bios_size, isa_bios_size; linux_boot = (kernel_filename != NULL); @@ -329,25 +331,47 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0, ram_size, 0); /* BIOS load */ + bios_offset = ram_size + vga_ram_size; + vga_bios_offset = bios_offset + 256 * 1024; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - ret = load_image(buf, phys_ram_base + 0x000f0000); - if (ret != 0x10000) { + bios_size = get_image_size(buf); + if (bios_size <= 0 || + (bios_size % 65536) != 0 || + bios_size > (256 * 1024)) { + goto bios_error; + } + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret != bios_size) { + bios_error: fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); exit(1); } - + /* VGA BIOS load */ if (cirrus_vga_enabled) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME); } else { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); } - ret = load_image(buf, phys_ram_base + 0x000c0000); + ret = load_image(buf, phys_ram_base + vga_bios_offset); /* setup basic memory access */ - cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); - cpu_register_physical_memory(0xd0000, 0x20000, IO_MEM_UNASSIGNED); - cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); + cpu_register_physical_memory(0xc0000, 0x10000, + vga_bios_offset | IO_MEM_ROM); + + /* map the last 128KB of the BIOS in ISA space */ + isa_bios_size = bios_size; + if (isa_bios_size > (128 * 1024)) + isa_bios_size = 128 * 1024; + cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, + IO_MEM_UNASSIGNED); + cpu_register_physical_memory(0x100000 - isa_bios_size, + isa_bios_size, + (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); + /* map all the bios at the top of memory */ + cpu_register_physical_memory((uint32_t)(-bios_size), + bios_size, bios_offset | IO_MEM_ROM); bochs_bios_init(); diff --git a/vl.c b/vl.c index fb073c24a..b2ef506de 100644 --- a/vl.c +++ b/vl.c @@ -290,6 +290,18 @@ char *pstrcat(char *buf, int buf_size, const char *s) return buf; } +/* return the size or -1 if error */ +int get_image_size(const char *filename) +{ + int fd, size; + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return -1; + size = lseek(fd, 0, SEEK_END); + close(fd); + return size; +} + /* return the size or -1 if error */ int load_image(const char *filename, uint8_t *addr) { diff --git a/vl.h b/vl.h index fd2340509..130bf0504 100644 --- a/vl.h +++ b/vl.h @@ -209,6 +209,7 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); void hw_error(const char *fmt, ...); +int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); extern const char *bios_dir; @@ -243,7 +244,7 @@ extern int cirrus_vga_enabled; #if defined (TARGET_PPC) #define BIOS_SIZE (512 * 1024) #else -#define BIOS_SIZE 0 +#define BIOS_SIZE ((256 + 64) * 1024) #endif /* keyboard/mouse support */ -- cgit v1.2.3 From 95ea3fa19ccb934aff809abf45ef947079934429 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:44:21 +0000 Subject: added open pic for PPC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@947 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Makefile.target b/Makefile.target index c8ef71682..1134256c8 100644 --- a/Makefile.target +++ b/Makefile.target @@ -241,12 +241,9 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o VL_OBJS+= cirrus_vga.o endif ifeq ($(TARGET_ARCH), ppc) -# Generic PPC support -VL_OBJS+= ppc.o -# PREP hardware support -VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o +VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o 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 +VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o -- cgit v1.2.3 From e9b137c2dd3fca222634e82cbec8a7b69abf392b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:46:10 +0000 Subject: added -g option for OF initial resolution git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@948 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/vl.c b/vl.c index b2ef506de..3dee9d32c 100644 --- a/vl.c +++ b/vl.c @@ -131,6 +131,9 @@ int pci_enabled = 1; int prep_enabled = 0; int rtc_utc = 1; int cirrus_vga_enabled = 0; +int graphic_width = 640; +int graphic_height = 480; +int graphic_depth = 15; /***********************************************************/ /* x86 ISA bus support */ @@ -2042,6 +2045,7 @@ void help(void) "-localtime set the real time clock to local time [default=utc]\n" #ifdef TARGET_PPC "-prep Simulate a PREP system (default is PowerMAC)\n" + "-g WxH[xDEPTH] Set the initial VGA graphic mode\n" #endif "\n" "Network options:\n" @@ -2134,6 +2138,7 @@ enum { QEMU_OPTION_prep, QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, + QEMU_OPTION_g, }; typedef struct QEMUOption { @@ -2180,6 +2185,7 @@ const QEMUOption qemu_options[] = { { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, + { "g", 1, QEMU_OPTION_g }, #endif { "localtime", 0, QEMU_OPTION_localtime }, { "isa", 0, QEMU_OPTION_isa }, @@ -2472,6 +2478,40 @@ int main(int argc, char **argv) case QEMU_OPTION_cirrusvga: cirrus_vga_enabled = 1; break; + case QEMU_OPTION_g: + { + const char *p; + int w, h, depth; + p = optarg; + w = strtol(p, (char **)&p, 10); + if (w <= 0) { + graphic_error: + fprintf(stderr, "qemu: invalid resolution or depth\n"); + exit(1); + } + if (*p != 'x') + goto graphic_error; + p++; + h = strtol(p, (char **)&p, 10); + if (h <= 0) + goto graphic_error; + if (*p == 'x') { + p++; + depth = strtol(p, (char **)&p, 10); + if (depth != 8 && depth != 15 && depth != 16 && + depth != 24 && depth != 32) + goto graphic_error; + } else if (*p == '\0') { + depth = graphic_depth; + } else { + goto graphic_error; + } + + graphic_width = w; + graphic_height = h; + graphic_depth = depth; + } + break; } } } -- cgit v1.2.3 From 28b9b5af25ec8c3f4235c20bb8c53c0fe1242e5f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:46:35 +0000 Subject: ppc update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@949 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/vl.h b/vl.h index 130bf0504..1573df7fd 100644 --- a/vl.h +++ b/vl.h @@ -239,6 +239,9 @@ extern int ram_size; extern int bios_size; extern int rtc_utc; extern int cirrus_vga_enabled; +extern int graphic_width; +extern int graphic_height; +extern int graphic_depth; /* XXX: make it dynamic */ #if defined (TARGET_PPC) @@ -520,6 +523,11 @@ void pci_prep_init(void); void pci_pmac_init(void); void pci_ppc_bios_init(void); +/* openpic.c */ +typedef struct openpic_t openpic_t; +void openpic_set_irq (openpic_t *opp, int n_IRQ, int level); +openpic_t *openpic_init (uint32_t isu_base, uint32_t idu_base, int nb_cpus); + /* vga.c */ #define VGA_RAM_SIZE (4096 * 1024) @@ -569,6 +577,8 @@ void isa_ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1); void pci_ide_init(BlockDriverState **hd_table); void pci_piix3_ide_init(BlockDriverState **hd_table); +int pmac_ide_init (BlockDriverState **hd_table, + openpic_t *openpic, int irq); /* oss.c */ typedef enum { @@ -595,7 +605,7 @@ void DMA_hold_DREQ (int nchan); void DMA_release_DREQ (int nchan); void DMA_schedule(int nchan); void DMA_run (void); -void DMA_init (void); +void DMA_init (int high_page_enable); void DMA_register_channel (int nchan, DMA_transfer_handler transfer_handler, void *opaque); @@ -707,9 +717,10 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, const unsigned char *arch, uint32_t RAM_size, int boot_device, uint32_t kernel_image, uint32_t kernel_size, - uint32_t cmdline, uint32_t cmdline_size, + const char *cmdline, uint32_t initrd_image, uint32_t initrd_size, - uint32_t NVRAM_image); + uint32_t NVRAM_image, + int width, int height, int depth); /* adb.c */ @@ -744,7 +755,7 @@ void adb_mouse_init(ADBBusState *bus); /* cuda.c */ extern ADBBusState adb_bus; -int cuda_init(void); +int cuda_init(openpic_t *openpic, int irq); /* monitor.c */ void monitor_init(void); -- cgit v1.2.3 From 819e712bfe40f0706689a98f9968f842e3aaccd1 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:47:13 +0000 Subject: cuda fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@950 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adb.c | 4 +- hw/cuda.c | 200 ++++++++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 138 insertions(+), 66 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index 6442d796b..2d230a697 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -63,8 +63,8 @@ void adb_receive_packet(ADBBusState *s, const uint8_t *buf, int len) int devaddr, cmd, i; uint8_t obuf[4]; - cmd = buf[1] & 0xf; - devaddr = buf[1] >> 4; + cmd = buf[0] & 0xf; + devaddr = buf[0] >> 4; if (buf[1] == ADB_BUSRESET) { obuf[0] = 0x00; obuf[1] = 0x00; diff --git a/hw/cuda.c b/hw/cuda.c index a75de834e..544158f9c 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -23,6 +23,9 @@ */ #include "vl.h" +//#define DEBUG_CUDA +//#define DEBUG_CUDA_PACKET + /* Bits in B data register: all active low */ #define TREQ 0x08 /* Transfer request (input) */ #define TACK 0x10 /* Transfer acknowledge (output) */ @@ -114,6 +117,7 @@ typedef struct CUDAState { int data_out_index; int irq; + openpic_t *openpic; uint8_t autopoll; uint8_t data_in[128]; uint8_t data_out[16]; @@ -125,13 +129,15 @@ ADBBusState adb_bus; static void cuda_update(CUDAState *s); static void cuda_receive_packet_from_host(CUDAState *s, const uint8_t *data, int len); +static void cuda_timer_update(CUDAState *s, CUDATimer *ti, + int64_t current_time); static void cuda_update_irq(CUDAState *s) { - if (s->ifr & s->ier & SR_INT) { - pic_set_irq(s->irq, 1); + if (s->ifr & s->ier & (SR_INT | T1_INT)) { + openpic_set_irq(s->openpic, s->irq, 1); } else { - pic_set_irq(s->irq, 0); + openpic_set_irq(s->openpic, s->irq, 0); } } @@ -150,10 +156,15 @@ static unsigned int get_counter(CUDATimer *s) return counter; } -static void set_counter(CUDATimer *s, unsigned int val) +static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) { - s->load_time = qemu_get_clock(vm_clock); - s->counter_value = val; +#ifdef DEBUG_CUDA + printf("cuda: T%d.counter=%d\n", + 1 + (ti->timer == NULL), val); +#endif + ti->load_time = qemu_get_clock(vm_clock); + ti->counter_value = val; + cuda_timer_update(s, ti, ti->load_time); } static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) @@ -165,10 +176,14 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) if (d <= s->counter_value) { next_time = s->counter_value + 1; } else { - base = ((d - s->counter_value) % s->latch); + base = ((d - s->counter_value) / s->latch); base = (base * s->latch) + s->counter_value; next_time = base + s->latch; } +#ifdef DEBUG_CUDA + printf("latch=%d counter=%lld delta_next=%lld\n", + s->latch, d, next_time - d); +#endif next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + s->load_time; if (next_time <= current_time) @@ -176,13 +191,25 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) return next_time; } +static void cuda_timer_update(CUDAState *s, CUDATimer *ti, + int64_t current_time) +{ + if (!ti->timer) + return; + if ((s->acr & T1MODE) != T1MODE_CONT) { + qemu_del_timer(ti->timer); + } else { + ti->next_irq_time = get_next_irq_time(ti, current_time); + qemu_mod_timer(ti->timer, ti->next_irq_time); + } +} + static void cuda_timer1(void *opaque) { CUDAState *s = opaque; CUDATimer *ti = &s->timers[0]; - ti->next_irq_time = get_next_irq_time(ti, ti->next_irq_time); - qemu_mod_timer(ti->timer, ti->next_irq_time); + cuda_timer_update(s, ti, ti->next_irq_time); s->ifr |= T1_INT; cuda_update_irq(s); } @@ -229,11 +256,9 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) val = get_counter(&s->timers[1]) >> 8; break; case 10: - if (s->data_in_index < s->data_in_size) { - val = s->data_in[s->data_in_index]; - } else { - val = 0; - } + val = s->sr; + s->ifr &= ~SR_INT; + cuda_update_irq(s); break; case 11: val = s->acr; @@ -253,7 +278,8 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) break; } #ifdef DEBUG_CUDA - printf("cuda: read: reg=0x%x val=%02x\n", addr, val); + if (addr != 13 || val != 0) + printf("cuda: read: reg=0x%x val=%02x\n", addr, val); #endif return val; } @@ -283,44 +309,34 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 4: val = val | (get_counter(&s->timers[0]) & 0xff00); - set_counter(&s->timers[0], val); + set_counter(s, &s->timers[0], val); break; case 5: val = (val << 8) | (get_counter(&s->timers[0]) & 0xff); - set_counter(&s->timers[0], val); + set_counter(s, &s->timers[0], val); break; case 6: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); break; case 7: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); break; case 8: val = val | (get_counter(&s->timers[1]) & 0xff00); - set_counter(&s->timers[1], val); + set_counter(s, &s->timers[1], val); break; case 9: val = (val << 8) | (get_counter(&s->timers[1]) & 0xff); - set_counter(&s->timers[1], val); + set_counter(s, &s->timers[1], val); break; case 10: s->sr = val; break; case 11: s->acr = val; - if ((s->acr & T1MODE) == T1MODE_CONT) { - if ((s->last_acr & T1MODE) != T1MODE_CONT) { - CUDATimer *ti = &s->timers[0]; - /* activate timer interrupt */ - ti->next_irq_time = get_next_irq_time(ti, qemu_get_clock(vm_clock)); - qemu_mod_timer(ti->timer, ti->next_irq_time); - } - } else { - if ((s->last_acr & T1MODE) == T1MODE_CONT) { - CUDATimer *ti = &s->timers[0]; - qemu_del_timer(ti->timer); - } - } + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); cuda_update(s); break; case 12: @@ -351,47 +367,90 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) /* NOTE: TIP and TREQ are negated */ static void cuda_update(CUDAState *s) { - if (s->data_in_index < s->data_in_size) { - /* data input */ - if (!(s->b & TIP) && - (s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { - s->sr = s->data_in[s->data_in_index++]; - s->ifr |= SR_INT; - cuda_update_irq(s); - } - } - if (s->data_in_index < s->data_in_size) { - /* there is some data to read */ - s->b = (s->b & ~TREQ); - } else { - s->b = (s->b | TREQ); - } + int packet_received, len; + + packet_received = 0; + if (!(s->b & TIP)) { + /* transfer requested from host */ - if (s->acr & SR_OUT) { - /* data output */ - if (!(s->b & TIP) && - (s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { - if (s->data_out_index < sizeof(s->data_out)) { - s->data_out[s->data_out_index++] = s->sr; + if (s->acr & SR_OUT) { + /* data output */ + if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { + if (s->data_out_index < sizeof(s->data_out)) { +#ifdef DEBUG_CUDA + printf("cuda: send: %02x\n", s->sr); +#endif + s->data_out[s->data_out_index++] = s->sr; + s->ifr |= SR_INT; + cuda_update_irq(s); + } + } + } else { + if (s->data_in_index < s->data_in_size) { + /* data input */ + if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { + s->sr = s->data_in[s->data_in_index++]; +#ifdef DEBUG_CUDA + printf("cuda: recv: %02x\n", s->sr); +#endif + /* indicate end of transfer */ + if (s->data_in_index >= s->data_in_size) { + s->b = (s->b | TREQ); + } + s->ifr |= SR_INT; + cuda_update_irq(s); + } } + } + } else { + /* no transfer requested: handle sync case */ + if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) { + /* update TREQ state each time TACK change state */ + if (s->b & TACK) + s->b = (s->b | TREQ); + else + s->b = (s->b & ~TREQ); s->ifr |= SR_INT; cuda_update_irq(s); + } else { + if (!(s->last_b & TIP)) { + /* handle end of host to cuda transfert */ + packet_received = (s->data_out_index > 0); + /* always an IRQ at the end of transfert */ + s->ifr |= SR_INT; + cuda_update_irq(s); + } + /* signal if there is data to read */ + if (s->data_in_index < s->data_in_size) { + s->b = (s->b & ~TREQ); + } } } - /* check end of data output */ - if (!(s->acr & SR_OUT) && (s->last_acr & SR_OUT)) { - if (s->data_out_index > 0) - cuda_receive_packet_from_host(s, s->data_out, s->data_out_index); - s->data_out_index = 0; - } s->last_acr = s->acr; s->last_b = s->b; + + /* NOTE: cuda_receive_packet_from_host() can call cuda_update() + recursively */ + if (packet_received) { + len = s->data_out_index; + s->data_out_index = 0; + cuda_receive_packet_from_host(s, s->data_out, len); + } } static void cuda_send_packet_to_host(CUDAState *s, const uint8_t *data, int len) { +#ifdef DEBUG_CUDA_PACKET + { + int i; + printf("cuda_send_packet_to_host:\n"); + for(i = 0; i < len; i++) + printf(" %02x", data[i]); + printf("\n"); + } +#endif memcpy(s->data_in, data, len); s->data_in_size = len; s->data_in_index = 0; @@ -425,7 +484,7 @@ static void cuda_receive_packet(CUDAState *s, break; case CUDA_GET_TIME: /* XXX: add time support ? */ - ti = 0; + ti = time(NULL); obuf[0] = CUDA_PACKET; obuf[1] = 0; obuf[2] = 0; @@ -452,6 +511,15 @@ static void cuda_receive_packet(CUDAState *s, static void cuda_receive_packet_from_host(CUDAState *s, const uint8_t *data, int len) { +#ifdef DEBUG_CUDA_PACKET + { + int i; + printf("cuda_receive_packet_to_host:\n"); + for(i = 0; i < len; i++) + printf(" %02x", data[i]); + printf("\n"); + } +#endif switch(data[0]) { case ADB_PACKET: adb_receive_packet(&adb_bus, data + 1, len - 1); @@ -492,16 +560,20 @@ static CPUReadMemoryFunc *cuda_read[] = { &cuda_readl, }; -int cuda_init(void) +int cuda_init(openpic_t *openpic, int irq) { CUDAState *s = &cuda_state; int cuda_mem_index; - s->timers[0].latch = 0x10000; - set_counter(&s->timers[0], 0xffff); + s->openpic = openpic; + s->irq = irq; + s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); + s->timers[0].latch = 0x10000; + set_counter(s, &s->timers[0], 0xffff); s->timers[1].latch = 0x10000; - set_counter(&s->timers[1], 0xffff); + s->ier = T1_INT | SR_INT; + set_counter(s, &s->timers[1], 0xffff); cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); return cuda_mem_index; } -- cgit v1.2.3 From b0bda528c37d7a772343a5eee8772dc56c8470f7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:47:42 +0000 Subject: high page register support for PPC PREP git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@951 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index 29f2aeccc..e0c5bf100 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -43,6 +43,7 @@ struct dma_regs { uint16_t base[2]; uint8_t mode; uint8_t page; + uint8_t pageh; uint8_t dack; uint8_t eop; DMA_transfer_handler transfer_handler; @@ -84,7 +85,6 @@ static void write_page (void *opaque, uint32_t nport, uint32_t data) int ichan; ichan = channels[nport & 7]; - if (-1 == ichan) { log ("invalid channel %#x %#x\n", nport, data); return; @@ -92,13 +92,25 @@ static void write_page (void *opaque, uint32_t nport, uint32_t data) d->regs[ichan].page = data; } -static uint32_t read_page (void *opaque, uint32_t nport) +static void write_pageh (void *opaque, uint32_t nport, uint32_t data) { struct dma_cont *d = opaque; int ichan; ichan = channels[nport & 7]; + if (-1 == ichan) { + log ("invalid channel %#x %#x\n", nport, data); + return; + } + d->regs[ichan].pageh = data; +} +static uint32_t read_page (void *opaque, uint32_t nport) +{ + struct dma_cont *d = opaque; + int ichan; + + ichan = channels[nport & 7]; if (-1 == ichan) { log ("invalid channel read %#x\n", nport); return 0; @@ -106,6 +118,19 @@ static uint32_t read_page (void *opaque, uint32_t nport) return d->regs[ichan].page; } +static uint32_t read_pageh (void *opaque, uint32_t nport) +{ + struct dma_cont *d = opaque; + int ichan; + + ichan = channels[nport & 7]; + if (-1 == ichan) { + log ("invalid channel read %#x\n", nport); + return 0; + } + return d->regs[ichan].pageh; +} + static inline void init_chan (struct dma_cont *d, int ichan) { struct dma_regs *r; @@ -306,7 +331,8 @@ static void channel_run (int ncont, int ichan) /* ai = r->mode & 16; */ /* dir = r->mode & 32 ? -1 : 1; */ - addr = (r->page << 16) | r->now[ADDR]; + /* NOTE: pageh is only used by PPC PREP */ + addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; n = r->transfer_handler (r->opaque, addr, (r->base[COUNT] << ncont) + (1 << ncont)); r->now[COUNT] = n; @@ -362,7 +388,8 @@ static void dma_reset(void *opaque) } /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ -static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base) +static void dma_init2(struct dma_cont *d, int base, int dshift, + int page_base, int pageh_base) { const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; int i; @@ -377,6 +404,12 @@ static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base) write_page, d); register_ioport_read (page_base + page_port_list[i], 1, 1, read_page, d); + if (pageh_base >= 0) { + register_ioport_write (pageh_base + page_port_list[i], 1, 1, + write_pageh, d); + register_ioport_read (pageh_base + page_port_list[i], 1, 1, + read_pageh, d); + } } for (i = 0; i < 8; i++) { register_ioport_write (base + ((i + 8) << dshift), 1, 1, @@ -388,8 +421,10 @@ static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base) dma_reset(d); } -void DMA_init (void) +void DMA_init (int high_page_enable) { - dma_init2(&dma_controllers[0], 0x00, 0, 0x80); - dma_init2(&dma_controllers[1], 0xc0, 1, 0x88); + dma_init2(&dma_controllers[0], 0x00, 0, 0x80, + high_page_enable ? 0x480 : -1); + dma_init2(&dma_controllers[1], 0xc0, 1, 0x88, + high_page_enable ? 0x488 : -1); } -- cgit v1.2.3 From 1ade1de2237ca43c101117130ec41b5bdfbeeeab Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:48:36 +0000 Subject: pmac macio based ide support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@952 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index fc0e13efa..090873765 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -297,6 +297,7 @@ typedef struct IDEState { int64_t nb_sectors; int mult_sectors; int irq; + openpic_t *openpic; PCIDevice *pci_dev; int drive_serial; /* ide regs */ @@ -464,6 +465,11 @@ static inline void ide_abort_command(IDEState *s) static inline void ide_set_irq(IDEState *s) { if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { +#ifdef TARGET_PPC + if (s->openpic) + openpic_set_irq(s->openpic, s->irq, 1); + else +#endif if (s->irq == 16) pci_set_irq(s->pci_dev, 0, 1); else @@ -1281,6 +1287,11 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = 0; else ret = s->status; +#ifdef TARGET_PPC + if (s->openpic) + openpic_set_irq(s->openpic, s->irq, 0); + else +#endif if (s->irq == 16) pci_set_irq(s->pci_dev, 0, 0); else @@ -1635,3 +1646,131 @@ void pci_piix3_ide_init(BlockDriverState **hd_table) ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); ide_init_ioport(&d->ide_if[2], 0x170, 0x376); } + +/***********************************************************/ +/* MacIO based PowerPC IDE */ + +/* PowerMac IDE memory IO */ +static void pmac_ide_writeb (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + addr = (addr & 0xFFF) >> 4; + switch (addr) { + case 1 ... 7: + ide_ioport_write(opaque, addr, val); + break; + case 8: + case 22: + ide_cmd_write(opaque, 0, val); + break; + default: + break; + } +} + +static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr) +{ + uint8_t retval; + + addr = (addr & 0xFFF) >> 4; + switch (addr) { + case 1 ... 7: + retval = ide_ioport_read(opaque, addr); + break; + case 8: + case 22: + retval = ide_status_read(opaque, 0); + break; + default: + retval = 0xFF; + break; + } + return retval; +} + +static void pmac_ide_writew (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + addr = (addr & 0xFFF) >> 4; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + if (addr == 0) { + ide_data_writew(opaque, 0, val); + } +} + +static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) +{ + uint16_t retval; + + addr = (addr & 0xFFF) >> 4; + if (addr == 0) { + retval = ide_data_readw(opaque, 0); + } else { + retval = 0xFFFF; + } +#ifdef TARGET_WORDS_BIGENDIAN + retval = bswap16(retval); +#endif + return retval; +} + +static void pmac_ide_writel (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + addr = (addr & 0xFFF) >> 4; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + if (addr == 0) { + ide_data_writel(opaque, 0, val); + } +} + +static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr) +{ + uint32_t retval; + + addr = (addr & 0xFFF) >> 4; + if (addr == 0) { + retval = ide_data_readl(opaque, 0); + } else { + retval = 0xFFFFFFFF; + } +#ifdef TARGET_WORDS_BIGENDIAN + retval = bswap32(retval); +#endif + return retval; +} + +static CPUWriteMemoryFunc *pmac_ide_write[] = { + pmac_ide_writeb, + pmac_ide_writew, + pmac_ide_writel, +}; + +static CPUReadMemoryFunc *pmac_ide_read[] = { + pmac_ide_readb, + pmac_ide_readw, + pmac_ide_readl, +}; + +/* hd_table must contain 4 block drivers */ +/* PowerMac uses memory mapped registers, not I/O. Return the memory + I/O index to access the ide. */ +int pmac_ide_init (BlockDriverState **hd_table, + openpic_t *openpic, int irq) +{ + IDEState *ide_if; + int pmac_ide_memory; + + ide_if = qemu_mallocz(sizeof(IDEState) * 2); + ide_init2(&ide_if[0], irq, hd_table[0], hd_table[1]); + ide_if[0].openpic = openpic; + ide_if[1].openpic = openpic; + + pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, + pmac_ide_write, &ide_if[0]); + return pmac_ide_memory; +} -- cgit v1.2.3 From e1bb04f74027d4b6f029f851aa59abf049891a22 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:49:53 +0000 Subject: memory mapped NVRAM (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@953 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/m48t59.h | 3 +- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index 445bc7179..5ab58160a 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -35,6 +35,8 @@ struct m48t59_t { /* Hardware parameters */ int IRQ; + int mem_index; + uint32_t mem_base; uint32_t io_base; uint16_t size; /* RTC management */ @@ -481,8 +483,95 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) return retval; } +static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t59_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + if (addr < 0x1FF0) + NVRAM->buffer[addr] = value; +} + +static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t59_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + if (addr < 0x1FF0) { + NVRAM->buffer[addr] = value >> 8; + NVRAM->buffer[addr + 1] = value; + } +} + +static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t59_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + if (addr < 0x1FF0) { + NVRAM->buffer[addr] = value >> 24; + NVRAM->buffer[addr + 1] = value >> 16; + NVRAM->buffer[addr + 2] = value >> 8; + NVRAM->buffer[addr + 3] = value; + } +} + +static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) +{ + m48t59_t *NVRAM = opaque; + uint32_t retval = 0; + + addr -= NVRAM->mem_base; + if (addr < 0x1FF0) + retval = NVRAM->buffer[addr]; + + return retval; +} + +static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) +{ + m48t59_t *NVRAM = opaque; + uint32_t retval = 0; + + addr -= NVRAM->mem_base; + if (addr < 0x1FF0) { + retval = NVRAM->buffer[addr] << 8; + retval |= NVRAM->buffer[addr + 1]; + } + + return retval; +} + +static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) +{ + m48t59_t *NVRAM = opaque; + uint32_t retval = 0; + + addr -= NVRAM->mem_base; + if (addr < 0x1FF0) { + retval = NVRAM->buffer[addr] << 24; + retval |= NVRAM->buffer[addr + 1] << 16; + retval |= NVRAM->buffer[addr + 2] << 8; + retval |= NVRAM->buffer[addr + 3]; + } + + return retval; +} + +static CPUWriteMemoryFunc *nvram_write[] = { + &nvram_writeb, + &nvram_writew, + &nvram_writel, +}; + +static CPUReadMemoryFunc *nvram_read[] = { + &nvram_readb, + &nvram_readw, + &nvram_readl, +}; /* Initialisation routine */ -m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) +m48t59_t *m48t59_init (int IRQ, uint32_t mem_base, + uint32_t io_base, uint16_t size) { m48t59_t *s; @@ -496,10 +585,15 @@ m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) } s->IRQ = IRQ; s->size = size; + s->mem_base = mem_base; s->io_base = io_base; s->addr = 0; register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); + if (mem_base != 0) { + s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); + } s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); s->lock = 0; diff --git a/hw/m48t59.h b/hw/m48t59.h index e68057b84..03d8ea3b9 100644 --- a/hw/m48t59.h +++ b/hw/m48t59.h @@ -7,6 +7,7 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val); uint32_t m48t59_read (m48t59_t *NVRAM); void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr); void m48t59_toggle_lock (m48t59_t *NVRAM, int lock); -m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size); +m48t59_t *m48t59_init (int IRQ, uint32_t io_base, + uint32_t mem_base, uint16_t size); #endif /* !defined (__M48T59_H__) */ -- cgit v1.2.3 From 611493d96655e9d529d637421713de95939c030f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:50:43 +0000 Subject: openpic fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@954 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/openpic.c | 135 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 58 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index bd0661858..cc2137eba 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -34,7 +34,7 @@ */ #include "vl.h" -#define DEBUG_OPENPIC +//#define DEBUG_OPENPIC #ifdef DEBUG_OPENPIC #define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) @@ -65,7 +65,7 @@ #define MAX_CPU 2 #define MAX_IRQ 64 -#define EXT_IRQ 16 +#define EXT_IRQ 48 #define MAX_DBL 0 #define MAX_MBX 0 #define MAX_TMR 4 @@ -139,7 +139,7 @@ typedef struct IRQ_src_t { uint32_t ide; /* IRQ destination register */ int type; int last_cpu; - int waited_acks; + int pending; /* TRUE if IRQ is pending */ } IRQ_src_t; enum IPVP_bits { @@ -150,7 +150,7 @@ enum IPVP_bits { IPVP_SENSE = 22, }; #define IPVP_PRIORITY_MASK (0x1F << 16) -#define IPVP_PRIORITY(_ipvpr_) (((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16) +#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) @@ -162,7 +162,7 @@ typedef struct IRQ_dst_t { CPUState *env; /* Needed if we did SMP */ } IRQ_dst_t; -typedef struct openpic_t { +struct openpic_t { PCIDevice pci_dev; /* Global registers */ uint32_t frep; /* Feature reporting register */ @@ -194,7 +194,7 @@ typedef struct openpic_t { uint32_t mbr; /* Mailbox register */ } mailboxes[MAX_MAILBOXES]; #endif -} openpic_t; +}; static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) { @@ -220,6 +220,8 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) priority = -1; for (i = 0; i < MAX_IRQ; i++) { if (IRQ_testbit(q, i)) { + DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", + i, IPVP_PRIORITY(opp->src[i].ipvp), priority); if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { next = i; priority = IPVP_PRIORITY(opp->src[i].ipvp); @@ -233,10 +235,7 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) { if (q->next == -1) { - if (q->queue == 0) { - /* No more IRQ */ - return -1; - } + /* XXX: optimize */ IRQ_check(opp, q); } @@ -269,13 +268,19 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) } } -void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level) +/* update pic state because registers for n_IRQ have changed value */ +static void openpic_update_irq(openpic_t *opp, int n_IRQ) { IRQ_src_t *src; int i; src = &opp->src[n_IRQ]; - if (!test_bit(&src->ipvp, IPVP_MASK)) { + + if (!src->pending) { + /* no irq pending */ + return; + } + if (test_bit(&src->ipvp, IPVP_MASK)) { /* Interrupt source is disabled */ return; } @@ -283,41 +288,55 @@ void openpic_set_IRQ (openpic_t *opp, int n_IRQ, int level) /* Priority set to zero */ return; } + if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { + /* IRQ already active */ + return; + } if (src->ide == 0x00000000) { /* No target */ return; } - if (level == 0) { - if (test_bit(&src->ipvp, IPVP_ACTIVITY) && - test_bit(&src->ipvp, IPVP_SENSE)) { - /* Inactivate a active level-sensitive IRQ */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); - } + + if (!test_bit(&src->ipvp, IPVP_MODE) || + src->ide == (1 << src->last_cpu)) { + /* Directed delivery mode */ + for (i = 0; i < opp->nb_cpus; i++) { + if (test_bit(&src->ide, i)) + IRQ_local_pipe(opp, i, n_IRQ); + } } else { - if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { - /* Interrupt already pending */ - return; - } - if (!test_bit(&src->ipvp, IPVP_MODE) || - src->ide == (1 << src->last_cpu)) { - /* Directed delivery mode */ - for (i = 0; i < opp->nb_cpus; i++) { - if (test_bit(&src->ide, i)) - IRQ_local_pipe(opp, i, n_IRQ); - } - } else { - /* Distributed delivery mode */ - for (i = src->last_cpu; i < src->last_cpu; i++) { - if (i == MAX_IRQ) - i = 0; - if (test_bit(&src->ide, i)) { - IRQ_local_pipe(opp, i, n_IRQ); - src->last_cpu = i; - break; - } - } - } + /* Distributed delivery mode */ + /* XXX: incorrect code */ + for (i = src->last_cpu; i < src->last_cpu; i++) { + if (i == MAX_IRQ) + i = 0; + if (test_bit(&src->ide, i)) { + IRQ_local_pipe(opp, i, n_IRQ); + src->last_cpu = i; + break; + } + } + } +} + +void openpic_set_irq(openpic_t *opp, int n_IRQ, int level) +{ + IRQ_src_t *src; + + src = &opp->src[n_IRQ]; + DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", + n_IRQ, level, src->ipvp); + if (test_bit(&src->ipvp, IPVP_SENSE)) { + /* level-sensitive irq */ + src->pending = level; + if (!level) + reset_bit(&src->ipvp, IPVP_ACTIVITY); + } else { + /* edge-sensitive irq */ + if (level) + src->pending = 1; } + openpic_update_irq(opp, n_IRQ); } static void openpic_reset (openpic_t *opp) @@ -389,18 +408,15 @@ static inline void write_IRQreg (openpic_t *opp, int n_IRQ, switch (reg) { case IRQ_IPVP: - tmp = opp->src[n_IRQ].ipvp & 0x40000000; - if (tmp == 0) { - tmp |= val & 0x80000000; - if ((opp->src[n_IRQ].type & IRQ_EXTERNAL) != 0) - tmp |= val & 0x40C00000; - else if ((opp->src[n_IRQ].type & IRQ_TIMER) != 0) - tmp |= val & 0x00F00000; - } else { - tmp |= val & 0x80000000; - } - opp->src[n_IRQ].ipvp = tmp | (val & 0x000F00FF); - DPRINTF("Set IPVP %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ipvp); + /* NOTE: not fully accurate for special IRQs, but simple and + sufficient */ + /* ACTIVITY bit is read-only */ + opp->src[n_IRQ].ipvp = + (opp->src[n_IRQ].ipvp & 0x40000000) | + (val & 0x800F00FF); + openpic_update_irq(opp, n_IRQ); + DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", + n_IRQ, val, opp->src[n_IRQ].ipvp); break; case IRQ_IDE: tmp = val & 0xC0000000; @@ -736,8 +752,8 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) case 0x70: idx = (addr - 0x40) >> 4; write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val); - openpic_set_IRQ(opp, IRQ_IPI0 + idx, 1); - openpic_set_IRQ(opp, IRQ_IPI0 + idx, 0); + openpic_set_irq(opp, IRQ_IPI0 + idx, 1); + openpic_set_irq(opp, IRQ_IPI0 + idx, 0); break; #endif case 0x80: /* PCTP */ @@ -818,8 +834,11 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) } IRQ_resetbit(&dst->raised, n_IRQ); dst->raised.next = -1; - if (!test_bit(&src->ipvp, IPVP_SENSE)) + if (!test_bit(&src->ipvp, IPVP_SENSE)) { + /* edge-sensitive IRQ */ reset_bit(&src->ipvp, IPVP_ACTIVITY); + src->pending = 0; + } } break; case 0xB0: /* PEOI */ @@ -862,7 +881,7 @@ static void openpic_writel (void *opaque, openpic_t *opp = opaque; addr &= 0x3FFFF; - DPRINTF("%s: offset %08lx val: %08x\n", __func__, addr, val); + DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val); if (addr < 0x1100) { /* Global registers */ openpic_gbl_write(opp, addr, val); @@ -884,7 +903,7 @@ static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr) uint32_t retval; addr &= 0x3FFFF; - DPRINTF("%s: offset %08lx\n", __func__, addr); + DPRINTF("%s: offset %08x\n", __func__, (int)addr); if (addr < 0x1100) { /* Global registers */ retval = openpic_gbl_read(opp, addr); -- cgit v1.2.3 From f2aa58c6f4a208350d05f0994e2e5422acc13c65 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:52:24 +0000 Subject: UniNorth PCI bridge support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@955 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 455 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 407 insertions(+), 48 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index b05d5d9f5..de97cb965 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -45,7 +45,7 @@ typedef struct PCIBridge { PCIDevice **pci_bus[256]; } PCIBridge; -static PCIBridge pci_bridge; +static PCIBridge pci_bridge[3]; target_phys_addr_t pci_mem_base; static int pci_irq_index; static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; @@ -56,7 +56,7 @@ PCIDevice *pci_register_device(const char *name, int instance_size, PCIConfigReadFunc *config_read, PCIConfigWriteFunc *config_write) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; PCIDevice *pci_dev, **bus; if (pci_irq_index >= PCI_DEVICES_MAX) @@ -70,6 +70,10 @@ PCIDevice *pci_register_device(const char *name, int instance_size, bus = s->pci_bus[bus_num]; if (devfn < 0) { for(devfn = 0 ; devfn < 256; devfn += 8) { +#ifdef TARGET_PPC + if ((devfn >> 3) < 11) + continue; +#endif if (!bus[devfn]) goto found; } @@ -425,7 +429,7 @@ static uint32_t pci_data_readl(void* opaque, uint32_t addr) void i440fx_init(void) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; PCIDevice *d; register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); @@ -604,7 +608,7 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = { void pci_prep_init(void) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; PCIDevice *d; int PPC_io_memory; @@ -629,7 +633,9 @@ void pci_prep_init(void) /* pmac pci init */ -static void pci_pmac_config_writel (void *opaque, target_phys_addr_t addr, uint32_t val) +/* Grackle PCI host */ +static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) { PCIBridge *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN @@ -638,7 +644,7 @@ static void pci_pmac_config_writel (void *opaque, target_phys_addr_t addr, uint3 s->config_reg = val; } -static uint32_t pci_pmac_config_readl (void *opaque, target_phys_addr_t addr) +static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) { PCIBridge *s = opaque; uint32_t val; @@ -650,25 +656,27 @@ static uint32_t pci_pmac_config_readl (void *opaque, target_phys_addr_t addr) return val; } -static CPUWriteMemoryFunc *pci_pmac_config_write[] = { - &pci_pmac_config_writel, - &pci_pmac_config_writel, - &pci_pmac_config_writel, +static CPUWriteMemoryFunc *pci_grackle_config_write[] = { + &pci_grackle_config_writel, + &pci_grackle_config_writel, + &pci_grackle_config_writel, }; -static CPUReadMemoryFunc *pci_pmac_config_read[] = { - &pci_pmac_config_readl, - &pci_pmac_config_readl, - &pci_pmac_config_readl, +static CPUReadMemoryFunc *pci_grackle_config_read[] = { + &pci_grackle_config_readl, + &pci_grackle_config_readl, + &pci_grackle_config_readl, }; -static void pci_pmac_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) +static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr, + uint32_t val) { PCIBridge *s = opaque; pci_data_write(s, addr, val, 1); } -static void pci_pmac_writew (void *opaque, target_phys_addr_t addr, uint32_t val) +static void pci_grackle_writew (void *opaque, target_phys_addr_t addr, + uint32_t val) { PCIBridge *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN @@ -677,7 +685,8 @@ static void pci_pmac_writew (void *opaque, target_phys_addr_t addr, uint32_t val pci_data_write(s, addr, val, 2); } -static void pci_pmac_writel (void *opaque, target_phys_addr_t addr, uint32_t val) +static void pci_grackle_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) { PCIBridge *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN @@ -686,7 +695,7 @@ static void pci_pmac_writel (void *opaque, target_phys_addr_t addr, uint32_t val pci_data_write(s, addr, val, 4); } -static uint32_t pci_pmac_readb (void *opaque, target_phys_addr_t addr) +static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr) { PCIBridge *s = opaque; uint32_t val; @@ -694,7 +703,7 @@ static uint32_t pci_pmac_readb (void *opaque, target_phys_addr_t addr) return val; } -static uint32_t pci_pmac_readw (void *opaque, target_phys_addr_t addr) +static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr) { PCIBridge *s = opaque; uint32_t val; @@ -705,7 +714,131 @@ static uint32_t pci_pmac_readw (void *opaque, target_phys_addr_t addr) return val; } -static uint32_t pci_pmac_readl (void *opaque, target_phys_addr_t addr) +static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr) +{ + PCIBridge *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr, 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *pci_grackle_write[] = { + &pci_grackle_writeb, + &pci_grackle_writew, + &pci_grackle_writel, +}; + +static CPUReadMemoryFunc *pci_grackle_read[] = { + &pci_grackle_readb, + &pci_grackle_readw, + &pci_grackle_readl, +}; + +/* Uninorth PCI host (for all Mac99 and newer machines */ +static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBridge *s = opaque; + int i; + +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + for (i = 11; i < 32; i++) { + if ((val & (1 << i)) != 0) + break; + } +#if 0 + s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); +#else + s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); +#endif +} + +static uint32_t pci_unin_main_config_readl (void *opaque, + target_phys_addr_t addr) +{ + PCIBridge *s = opaque; + uint32_t val; + int devfn; + + devfn = (s->config_reg >> 8) & 0xFF; + val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + return val; +} + +static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { + &pci_unin_main_config_writel, + &pci_unin_main_config_writel, + &pci_unin_main_config_writel, +}; + +static CPUReadMemoryFunc *pci_unin_main_config_read[] = { + &pci_unin_main_config_readl, + &pci_unin_main_config_readl, + &pci_unin_main_config_readl, +}; + +static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBridge *s = opaque; + pci_data_write(s, addr & 7, val, 1); +} + +static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBridge *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + pci_data_write(s, addr & 7, val, 2); +} + +static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBridge *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_data_write(s, addr & 7, val, 4); +} + +static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr) +{ + PCIBridge *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr & 7, 1); + + return val; +} + +static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr) +{ + PCIBridge *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr & 7, 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + + return val; +} + +static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr) { PCIBridge *s = opaque; uint32_t val; @@ -714,37 +847,246 @@ static uint32_t pci_pmac_readl (void *opaque, target_phys_addr_t addr) #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif + + return val; +} + +static CPUWriteMemoryFunc *pci_unin_main_write[] = { + &pci_unin_main_writeb, + &pci_unin_main_writew, + &pci_unin_main_writel, +}; + +static CPUReadMemoryFunc *pci_unin_main_read[] = { + &pci_unin_main_readb, + &pci_unin_main_readw, + &pci_unin_main_readl, +}; + +static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBridge *s = opaque; + +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + s->config_reg = 0x80000000 | (val & ~0x00000001); +} + +static uint32_t pci_unin_config_readl (void *opaque, + target_phys_addr_t addr) +{ + PCIBridge *s = opaque; + uint32_t val; + + val = (s->config_reg | 0x00000001) & ~0x80000000; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + return val; +} + +static CPUWriteMemoryFunc *pci_unin_config_write[] = { + &pci_unin_config_writel, + &pci_unin_config_writel, + &pci_unin_config_writel, +}; + +static CPUReadMemoryFunc *pci_unin_config_read[] = { + &pci_unin_config_readl, + &pci_unin_config_readl, + &pci_unin_config_readl, +}; + +static void pci_unin_writeb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBridge *s = opaque; + pci_data_write(s, addr & 3, val, 1); +} + +static void pci_unin_writew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBridge *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + pci_data_write(s, addr & 3, val, 2); +} + +static void pci_unin_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBridge *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_data_write(s, addr & 3, val, 4); +} + +static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr) +{ + PCIBridge *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr & 3, 1); + + return val; +} + +static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr) +{ + PCIBridge *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr & 3, 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + + return val; +} + +static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr) +{ + PCIBridge *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr & 3, 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; } -static CPUWriteMemoryFunc *pci_pmac_write[] = { - &pci_pmac_writeb, - &pci_pmac_writew, - &pci_pmac_writel, +static CPUWriteMemoryFunc *pci_unin_write[] = { + &pci_unin_writeb, + &pci_unin_writew, + &pci_unin_writel, }; -static CPUReadMemoryFunc *pci_pmac_read[] = { - &pci_pmac_readb, - &pci_pmac_readw, - &pci_pmac_readl, +static CPUReadMemoryFunc *pci_unin_read[] = { + &pci_unin_readb, + &pci_unin_readw, + &pci_unin_readl, }; void pci_pmac_init(void) { - PCIBridge *s = &pci_bridge; + PCIBridge *s; PCIDevice *d; int pci_mem_config, pci_mem_data; - pci_mem_config = cpu_register_io_memory(0, pci_pmac_config_read, - pci_pmac_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_pmac_read, pci_pmac_write, s); - - cpu_register_physical_memory(0xfec00000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xfee00000, 0x1000, pci_mem_data); - - d = pci_register_device("MPC106", sizeof(PCIDevice), 0, 0, + /* Use values found on a real PowerMac */ + /* Uninorth main bus */ + s = &pci_bridge[0]; + pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, + pci_unin_main_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, + pci_unin_main_write, s); + cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); + + d = pci_register_device("Uni-north main", sizeof(PCIDevice), 0, 11 << 3, NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x1F; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer + +#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly + /* pci-to-pci bridge */ + d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, + NULL, NULL); + d->config[0x00] = 0x11; // vendor_id : TI + d->config[0x01] = 0x10; + d->config[0x02] = 0x26; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x05; // revision + d->config[0x0A] = 0x04; // class_sub = pci2pci + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x20; // latency_timer + d->config[0x0E] = 0x01; // header_type + + d->config[0x18] = 0x01; // primary_bus + d->config[0x19] = 0x02; // secondary_bus + d->config[0x1A] = 0x02; // subordinate_bus + d->config[0x1B] = 0x20; // secondary_latency_timer + d->config[0x1C] = 0x11; // io_base + d->config[0x1D] = 0x01; // io_limit + d->config[0x20] = 0x00; // memory_base + d->config[0x21] = 0x80; + d->config[0x22] = 0x00; // memory_limit + d->config[0x23] = 0x80; + d->config[0x24] = 0x01; // prefetchable_memory_base + d->config[0x25] = 0x80; + d->config[0x26] = 0xF1; // prefectchable_memory_limit + d->config[0x27] = 0x7F; + // d->config[0x34] = 0xdc // capabilities_pointer +#endif +#if 0 // XXX: not needed for now + /* Uninorth AGP bus */ + s = &pci_bridge[1]; + pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_unin_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_read, + pci_unin_write, s); + cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); + + d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, + NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x20; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + // d->config[0x34] = 0x80; // capabilities_pointer +#endif +#if 0 // XXX: not needed for now + /* Uninorth internal bus */ + s = &pci_bridge[2]; + pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_unin_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_read, + pci_unin_write, s); + cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); + + d = pci_register_device("Uni-north internal", sizeof(PCIDevice), + 3, 11 << 3, NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x1E; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer +#endif + +#if 0 // Grackle ? /* same values as PearPC - check this */ d->config[0x00] = 0x11; // vendor_id d->config[0x01] = 0x10; @@ -770,6 +1112,7 @@ void pci_pmac_init(void) d->config[0x25] = 0x84; d->config[0x26] = 0x00; // prefetchable_memory_limit d->config[0x27] = 0x85; +#endif } /***********************************************************/ @@ -878,7 +1221,7 @@ static void pci_info_device(PCIDevice *d) void pci_info(void) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; PCIDevice **bus; int bus_num, devfn; @@ -928,7 +1271,7 @@ static void isa_outl(uint32_t val, uint32_t addr) static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; s->config_reg = 0x80000000 | (d->bus_num << 16) | (d->devfn << 8) | addr; pci_data_write(s, 0, val, 4); @@ -936,7 +1279,7 @@ static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; s->config_reg = 0x80000000 | (d->bus_num << 16) | (d->devfn << 8) | (addr & ~3); pci_data_write(s, addr & 3, val, 2); @@ -944,7 +1287,7 @@ static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; s->config_reg = 0x80000000 | (d->bus_num << 16) | (d->devfn << 8) | (addr & ~3); pci_data_write(s, addr & 3, val, 1); @@ -952,7 +1295,7 @@ static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; s->config_reg = 0x80000000 | (d->bus_num << 16) | (d->devfn << 8) | addr; return pci_data_read(s, 0, 4); @@ -960,7 +1303,7 @@ static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; s->config_reg = 0x80000000 | (d->bus_num << 16) | (d->devfn << 8) | (addr & ~3); return pci_data_read(s, addr & 3, 2); @@ -968,7 +1311,7 @@ static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; s->config_reg = 0x80000000 | (d->bus_num << 16) | (d->devfn << 8) | (addr & ~3); return pci_data_read(s, addr & 3, 1); @@ -1036,8 +1379,21 @@ static void pci_bios_init_device(PCIDevice *d) /* VGA: map frame buffer to default Bochs VBE address */ pci_set_io_region_addr(d, 0, 0xE0000000); break; + case 0x0800: + /* PIC */ + vendor_id = pci_config_readw(d, PCI_VENDOR_ID); + device_id = pci_config_readw(d, PCI_DEVICE_ID); + if (vendor_id == 0x1014) { + /* IBM */ + if (device_id == 0x0046 || device_id == 0xFFFF) { + /* MPIC & MPIC2 */ + pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); + } + } + break; case 0xff00: - if (vendor_id == 0x0106b && device_id == 0x0017) { + if (vendor_id == 0x0106b && + (device_id == 0x0017 || device_id == 0x0022)) { /* macio bridge */ pci_set_io_region_addr(d, 0, 0x80800000); } @@ -1076,7 +1432,7 @@ static void pci_bios_init_device(PCIDevice *d) */ void pci_bios_init(void) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; PCIDevice **bus; int bus_num, devfn, i, irq; uint8_t elcr[2]; @@ -1115,10 +1471,13 @@ void pci_bios_init(void) */ void pci_ppc_bios_init(void) { - PCIBridge *s = &pci_bridge; + PCIBridge *s = &pci_bridge[0]; PCIDevice **bus; - int bus_num, devfn, i, irq; + int bus_num, devfn; +#if 0 + int i, irq; uint8_t elcr[2]; +#endif pci_bios_io_addr = 0xc000; pci_bios_mem_addr = 0xc0000000; -- cgit v1.2.3 From fd0bbb12c3de53b52f2ac7bf6e55fd7233c6f476 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:53:42 +0000 Subject: cmdline init fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@956 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 2c3912103..5f992290e 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include "m48t59.h" /*****************************************************************************/ /* PPC time base and decrementer emulation */ @@ -109,7 +110,7 @@ uint32_t cpu_ppc_load_decr (CPUState *env) decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock), tb_env->tb_freq, ticks_per_sec); -#ifdef DEBUG_TB +#if defined(DEBUG_TB) printf("%s: 0x%08x\n", __func__, decr); #endif @@ -257,7 +258,7 @@ CPUReadMemoryFunc *PPC_io_read[] = { /*****************************************************************************/ /* Debug port */ -void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val) +void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) { addr &= 0xF; switch (addr) { @@ -270,7 +271,7 @@ void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val) break; case 2: printf("Set loglevel to %04x\n", val); - cpu_set_log(val); + cpu_set_log(val | 0x100); break; } } @@ -397,13 +398,16 @@ uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) return crc; } +#define CMDLINE_ADDR 0x017ff000 + int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, const unsigned char *arch, uint32_t RAM_size, int boot_device, uint32_t kernel_image, uint32_t kernel_size, - uint32_t cmdline, uint32_t cmdline_size, + const char *cmdline, uint32_t initrd_image, uint32_t initrd_size, - uint32_t NVRAM_image) + uint32_t NVRAM_image, + int width, int height, int depth) { uint16_t crc; @@ -416,13 +420,24 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, NVRAM_set_byte(nvram, 0x34, boot_device); NVRAM_set_lword(nvram, 0x38, kernel_image); NVRAM_set_lword(nvram, 0x3C, kernel_size); - NVRAM_set_lword(nvram, 0x40, cmdline); - NVRAM_set_lword(nvram, 0x44, cmdline_size); + if (cmdline) { + /* XXX: put the cmdline in NVRAM too ? */ + strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); + NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR); + NVRAM_set_lword(nvram, 0x44, strlen(cmdline)); + } else { + NVRAM_set_lword(nvram, 0x40, 0); + NVRAM_set_lword(nvram, 0x44, 0); + } NVRAM_set_lword(nvram, 0x48, initrd_image); NVRAM_set_lword(nvram, 0x4C, initrd_size); NVRAM_set_lword(nvram, 0x50, NVRAM_image); - crc = NVRAM_compute_crc(nvram, 0x00, 0x5C); - NVRAM_set_word(nvram, 0x5C, crc); + + NVRAM_set_word(nvram, 0x54, width); + NVRAM_set_word(nvram, 0x56, height); + NVRAM_set_word(nvram, 0x58, depth); + crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); + NVRAM_set_word(nvram, 0xFC, crc); return 0; } @@ -442,4 +457,6 @@ void ppc_init (int ram_size, int vga_ram_size, int boot_device, snapshot, kernel_filename, kernel_cmdline, initrd_filename); } + /* Special port to get debug messages from Open-Firmware */ + register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); } -- cgit v1.2.3 From b6b8bd1819ffe95ff3b04c66610af5a4d7ba605f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:55:53 +0000 Subject: ppc init fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@957 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 86 ++++++++++++++++++++++++++++++++++++++++++----------------- hw/ppc_prep.c | 30 +++++++++------------ 2 files changed, 75 insertions(+), 41 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 481bed7a7..5411806fc 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -26,16 +26,22 @@ #define BIOS_FILENAME "ppc_rom.bin" #define NVRAM_SIZE 0x2000 +#define KERNEL_LOAD_ADDR 0x01000000 +#define INITRD_LOAD_ADDR 0x01800000 + /* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA, NVRAM (not implemented). */ static int dbdma_mem_index; static int cuda_mem_index; +static int ide0_mem_index; +static int ide1_mem_index; /* DBDMA: currently no op - should suffice right now */ static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { + printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value); } static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value) @@ -48,6 +54,7 @@ static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) { + printf("%s: 0x%08x => 0x00000000\n", __func__, addr); return 0; } @@ -78,6 +85,8 @@ static void macio_map(PCIDevice *pci_dev, int region_num, { cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index); cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index); + cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index); + cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); } static void macio_init(void) @@ -91,7 +100,7 @@ static void macio_init(void) in PearPC */ d->config[0x00] = 0x6b; // vendor_id d->config[0x01] = 0x10; - d->config[0x02] = 0x17; + d->config[0x02] = 0x22; d->config[0x03] = 0x00; d->config[0x0a] = 0x00; // class_sub = pci2pci @@ -113,10 +122,12 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; + openpic_t *openpic; m48t59_t *nvram; int PPC_io_memory; int ret, linux_boot, i, fd; unsigned long bios_offset; + uint32_t kernel_base, kernel_size, initrd_base, initrd_size; linux_boot = (kernel_filename != NULL); @@ -135,26 +146,55 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, BIOS_SIZE, bios_offset | IO_MEM_ROM); cpu_single_env->nip = 0xfffffffc; + if (linux_boot) { + kernel_base = KERNEL_LOAD_ADDR; + /* now we can load the kernel */ + kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + /* load initrd */ + if (initrd_filename) { + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_base); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + boot_device = 'm'; + } else { + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; + } /* Register CPU as a 74x/75x */ cpu_ppc_register(cpu_single_env, 0x00080000); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); - isa_mem_base = 0xc0000000; + isa_mem_base = 0x80000000; pci_pmac_init(); - /* Register 64 KB of ISA IO space */ + /* Register 8 MB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); - cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); - // cpu_register_physical_memory(0xfe000000, 0xfe010000, PPC_io_memory); + cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory); /* init basic PC hardware */ vga_initialize(ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 1); - // openpic = openpic_init(0x00000000, 0xF0000000, 1); - // pic_init(openpic); + openpic = openpic_init(0x00000000, 0xF0000000, 1); + + /* XXX: suppress that */ pic_init(); - // pit = pit_init(0x40, 0); /* XXX: use Mac Serial port */ fd = serial_open_device(); @@ -164,30 +204,28 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pci_ne2000_init(&nd_table[i]); } - pci_ide_init(bs_table); + ide0_mem_index = pmac_ide_init(&bs_table[0], openpic, 0x13); + ide1_mem_index = pmac_ide_init(&bs_table[2], openpic, 0x13); /* cuda also initialize ADB */ - cuda_mem_index = cuda_init(); + cuda_mem_index = cuda_init(openpic, 0x19); adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); macio_init(); - nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); + nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); + + if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) + graphic_depth = 15; - PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, - 0, 0, - 0, - 0, - 0, 0, + PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "CHRP", ram_size, boot_device, + kernel_base, kernel_size, + kernel_cmdline, + initrd_base, initrd_size, /* XXX: need an option to load a NVRAM image */ - 0 - ); - - /* Special port to get debug messages from Open-Firmware */ - register_ioport_write(0xFF00, 0x04, 1, &PREP_debug_write, NULL); - register_ioport_write(0xFF00, 0x04, 2, &PREP_debug_write, NULL); - - pci_ppc_bios_init(); + 0, + graphic_width, graphic_height, graphic_depth); + /* No PCI init: the BIOS will do it */ } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 45b5853a6..8d4e9801a 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -26,8 +26,9 @@ //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO -#define KERNEL_LOAD_ADDR 0x01000000; -#define INITRD_LOAD_ADDR 0x01800000; +#define BIOS_FILENAME "ppc_rom.bin" +#define KERNEL_LOAD_ADDR 0x01000000 +#define INITRD_LOAD_ADDR 0x01800000 extern int loglevel; extern FILE *logfile; @@ -39,7 +40,7 @@ extern FILE *logfile; #if defined (HARD_DEBUG_PPC_IO) #define PPC_IO_DPRINTF(fmt, args...) \ do { \ - if (loglevel > 0) { \ + if (loglevel & CPU_LOG_IOPORT) { \ fprintf(logfile, "%s: " fmt, __func__ , ##args); \ } else { \ printf("%s : " fmt, __func__ , ##args); \ @@ -48,7 +49,7 @@ do { \ #elif defined (DEBUG_PPC_IO) #define PPC_IO_DPRINTF(fmt, args...) \ do { \ - if (loglevel > 0) { \ + if (loglevel & CPU_LOG_IOPORT) { \ fprintf(logfile, "%s: " fmt, __func__ , ##args); \ } \ } while (0) @@ -56,7 +57,6 @@ do { \ #define PPC_IO_DPRINTF(fmt, args...) do { } while (0) #endif -#define BIOS_FILENAME "ppc_rom.bin" /* Constants for devices init */ static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; @@ -175,7 +175,6 @@ static struct { uint32_t eemck1; /* Error diagnostic */ } XCSR; -#endif static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { @@ -242,6 +241,7 @@ static CPUReadMemoryFunc *PPC_XCSR_read[] = { &PPC_XCSR_readw, &PPC_XCSR_readl, }; +#endif /* Fake super-io ports for PREP platform (Intel 82378ZB) */ typedef struct sysctrl_t { @@ -413,7 +413,6 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; - // void *openpic; m48t59_t *nvram; int PPC_io_memory; int ret, linux_boot, i, nb_nics1, fd; @@ -506,7 +505,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, bs_table[2 * i], bs_table[2 * i + 1]); } kbd_init(); - DMA_init(); + DMA_init(1); // AUD_init(); // SB16_init(); @@ -528,10 +527,12 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, PPC_intack_write, NULL); cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); /* PowerPC control and status register group */ +#if 0 PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL); cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); +#endif - nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); + nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE); if (nvram == NULL) return; sysctrl->nvram = nvram; @@ -539,16 +540,11 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* Initialise NVRAM */ PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, kernel_base, kernel_size, - (uint32_t)(long)kernel_cmdline, - strlen(kernel_cmdline), + kernel_cmdline, initrd_base, initrd_size, /* XXX: need an option to load a NVRAM image */ - 0 - ); - - /* Special port to get debug messages from Open-Firmware */ - register_ioport_write(0xFF00, 0x04, 1, &PREP_debug_write, NULL); - register_ioport_write(0xFF00, 0x04, 2, &PREP_debug_write, NULL); + 0, + graphic_width, graphic_height, graphic_depth); pci_ppc_bios_init(); } -- cgit v1.2.3 From 53c862a88e209ecfb42d47a16ce92f92daf68c0a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:56:45 +0000 Subject: endianness fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@958 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga_template.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/hw/vga_template.h b/hw/vga_template.h index 349d58858..51302b349 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -346,7 +346,7 @@ static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { -#if DEPTH == 15 && !defined(WORDS_BIGENDIAN) +#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) memcpy(d, s, width * 2); #else int w; @@ -371,7 +371,7 @@ static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d, static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { -#if DEPTH == 16 && !defined(WORDS_BIGENDIAN) +#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) memcpy(d, s, width * 2); #else int w; @@ -401,9 +401,15 @@ static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d, w = width; do { +#if defined(TARGET_WORDS_BIGENDIAN) + r = s[0]; + g = s[1]; + b = s[2]; +#else b = s[0]; g = s[1]; r = s[2]; +#endif ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); s += 3; d += BPP; @@ -416,7 +422,7 @@ static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d, static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { -#if DEPTH == 32 && !defined(WORDS_BIGENDIAN) +#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) memcpy(d, s, width * 4); #else int w; @@ -424,9 +430,15 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, w = width; do { +#if defined(TARGET_WORDS_BIGENDIAN) + r = s[1]; + g = s[2]; + b = s[3]; +#else b = s[0]; g = s[1]; r = s[2]; +#endif ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); s += 4; d += BPP; -- cgit v1.2.3 From 514fb8c10e76fd861301719d14d6bae95125b54a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:57:45 +0000 Subject: removed traces git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@959 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index ef3e22d66..dab858560 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -357,11 +357,11 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, uint32_t address, int rw, int access_type) { int ret; - +#if 0 if (loglevel > 0) { fprintf(logfile, "%s\n", __func__); } - +#endif if ((access_type == ACCESS_CODE && msr_ir == 0) || (access_type != ACCESS_CODE && msr_dr == 0)) { /* No address translation */ @@ -376,11 +376,12 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, ret = get_segment(env, physical, prot, address, rw, access_type); } } +#if 0 if (loglevel > 0) { fprintf(logfile, "%s address %08x => %08x\n", __func__, address, *physical); } - +#endif return ret; } @@ -439,7 +440,7 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_addrr = env->tlb_read[is_user][index].address; tlb_addrw = env->tlb_write[is_user][index].address; -#if 1 +#if 0 if (loglevel) { fprintf(logfile, "%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " -- cgit v1.2.3 From 7c29d0c0cff07660e8f012f0befb01962ac5f7f6 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 16:58:50 +0000 Subject: dma init fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@960 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index 30e823b36..233f028db 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -487,7 +487,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, } kbd_init(); - DMA_init(); + DMA_init(0); #ifndef _WIN32 if (audio_enabled) { -- cgit v1.2.3 From 46e50e9d58aa0fd6ab8f5cadceb8b55ee7e1d806 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 19:43:00 +0000 Subject: added PCI bus git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@961 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 6 +++--- hw/ide.c | 13 +++++++------ hw/ne2000.c | 7 ++++--- hw/openpic.c | 7 ++++--- hw/pc.c | 20 ++++++++++++-------- hw/ppc_chrp.c | 25 +++++++++++++------------ hw/ppc_prep.c | 9 ++++----- hw/vga.c | 12 +++++------- vl.h | 35 ++++++++++++++++++----------------- 9 files changed, 70 insertions(+), 64 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 655db9db4..2707f9386 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2891,7 +2891,7 @@ static void cirrus_pci_mmio_map(PCIDevice *d, int region_num, s->cirrus_mmio_io_addr); } -void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, +void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { PCICirrusVGAState *d; @@ -2902,9 +2902,9 @@ void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, device_id = CIRRUS_ID_CLGD5446; /* setup PCI configuration registers */ - d = (PCICirrusVGAState *)pci_register_device("Cirrus VGA", + d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA", sizeof(PCICirrusVGAState), - 0, -1, NULL, NULL); + -1, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff); pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8); diff --git a/hw/ide.c b/hw/ide.c index 090873765..c352c63fc 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1579,14 +1579,14 @@ static void ide_map(PCIDevice *pci_dev, int region_num, } /* hd_table must contain 4 block drivers */ -void pci_ide_init(BlockDriverState **hd_table) +void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table) { PCIIDEState *d; uint8_t *pci_conf; int i; - d = (PCIIDEState *)pci_register_device("IDE", sizeof(PCIIDEState), - 0, -1, + d = (PCIIDEState *)pci_register_device(bus, "IDE", sizeof(PCIIDEState), + -1, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0x86; // Intel @@ -1621,14 +1621,15 @@ void pci_ide_init(BlockDriverState **hd_table) /* hd_table must contain 4 block drivers */ /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ -void pci_piix3_ide_init(BlockDriverState **hd_table) +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) { PCIIDEState *d; uint8_t *pci_conf; /* register a function 1 of PIIX3 */ - d = (PCIIDEState *)pci_register_device("PIIX3 IDE", sizeof(PCIIDEState), - 0, ((PCIDevice *)piix3_state)->devfn + 1, + d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", + sizeof(PCIIDEState), + ((PCIDevice *)piix3_state)->devfn + 1, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0x86; // Intel diff --git a/hw/ne2000.c b/hw/ne2000.c index 9f35f1991..50a34173f 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -613,14 +613,15 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); } -void pci_ne2000_init(NetDriverState *nd) +void pci_ne2000_init(PCIBus *bus, NetDriverState *nd) { PCINE2000State *d; NE2000State *s; uint8_t *pci_conf; - d = (PCINE2000State *)pci_register_device("NE2000", sizeof(PCINE2000State), - 0, -1, + d = (PCINE2000State *)pci_register_device(bus, + "NE2000", sizeof(PCINE2000State), + -1, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0xec; // Realtek 8029 diff --git a/hw/openpic.c b/hw/openpic.c index cc2137eba..eab6d0811 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -964,7 +964,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, #endif } -openpic_t *openpic_init (uint32_t isu_base, uint32_t idu_base, int nb_cpus) +openpic_t *openpic_init (PCIBus *bus, + uint32_t isu_base, uint32_t idu_base, int nb_cpus) { openpic_t *opp; uint8_t *pci_conf; @@ -973,8 +974,8 @@ openpic_t *openpic_init (uint32_t isu_base, uint32_t idu_base, int nb_cpus) /* XXX: for now, only one CPU is supported */ if (nb_cpus != 1) return NULL; - opp = (openpic_t *)pci_register_device("OpenPIC", sizeof(openpic_t), - 0, -1, NULL, NULL); + opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t), + -1, NULL, NULL); if (opp == NULL) return NULL; pci_conf = opp->pci_dev.config; diff --git a/hw/pc.c b/hw/pc.c index 233f028db..f5783250b 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -324,7 +324,8 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, int ret, linux_boot, initrd_size, i, nb_nics1, fd; unsigned long bios_offset, vga_bios_offset; int bios_size, isa_bios_size; - + PCIBus *pci_bus; + linux_boot = (kernel_filename != NULL); /* allocate RAM */ @@ -432,8 +433,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, } if (pci_enabled) { - i440fx_init(); - piix3_init(); + pci_bus = i440fx_init(); + piix3_init(pci_bus); + } else { + pci_bus = NULL; } /* init basic PC hardware */ @@ -443,15 +446,16 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, if (cirrus_vga_enabled) { if (pci_enabled) { - pci_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size, + pci_cirrus_vga_init(pci_bus, + ds, phys_ram_base + ram_size, ram_size, vga_ram_size); } else { isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); } } else { - vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, pci_enabled); + vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); } rtc_state = rtc_init(0x70, 8); @@ -469,9 +473,9 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled) { for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(&nd_table[i]); + pci_ne2000_init(pci_bus, &nd_table[i]); } - pci_piix3_ide_init(bs_table); + pci_piix3_ide_init(pci_bus, bs_table); } else { nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 5411806fc..fce434832 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -89,13 +89,12 @@ static void macio_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); } -static void macio_init(void) +static void macio_init(PCIBus *bus) { PCIDevice *d; - d = pci_register_device("macio", sizeof(PCIDevice), - 0, -1, - NULL, NULL); + d = pci_register_device(bus, "macio", sizeof(PCIDevice), + -1, NULL, NULL); /* Note: this code is strongly inspirated from the corresponding code in PearPC */ d->config[0x00] = 0x6b; // vendor_id @@ -128,7 +127,8 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, int ret, linux_boot, i, fd; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; - + PCIBus *pci_bus; + linux_boot = (kernel_filename != NULL); /* allocate RAM */ @@ -182,17 +182,18 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); isa_mem_base = 0x80000000; - pci_pmac_init(); + pci_bus = pci_pmac_init(); /* Register 8 MB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory); /* init basic PC hardware */ - vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 1); - openpic = openpic_init(0x00000000, 0xF0000000, 1); - + vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + openpic = openpic_init(pci_bus, 0x00000000, 0xF0000000, 1); + pci_pmac_set_openpic(pci_bus, openpic); + /* XXX: suppress that */ pic_init(); @@ -201,7 +202,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, serial_init(0x3f8, 4, fd); for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(&nd_table[i]); + pci_ne2000_init(pci_bus, &nd_table[i]); } ide0_mem_index = pmac_ide_init(&bs_table[0], openpic, 0x13); @@ -213,7 +214,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - macio_init(); + macio_init(pci_bus); nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 8d4e9801a..88dcac838 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -418,6 +418,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, int ret, linux_boot, i, nb_nics1, fd; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; + PCIBus *pci_bus; sysctrl = qemu_mallocz(sizeof(sysctrl_t)); if (sysctrl == NULL) @@ -477,14 +478,14 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); isa_mem_base = 0xc0000000; - pci_prep_init(); + pci_bus = pci_prep_init(); /* Register 64 KB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); cpu_register_physical_memory(0x80000000, 0x00010000, PPC_io_memory); /* init basic PC hardware */ - vga_initialize(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 1); + vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); rtc_init(0x70, 8); // openpic = openpic_init(0x00000000, 0xF0000000, 1); // pic_init(openpic); @@ -545,6 +546,4 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* XXX: need an option to load a NVRAM image */ 0, graphic_width, graphic_height, graphic_depth); - - pci_ppc_bios_init(); } diff --git a/hw/vga.c b/hw/vga.c index 57bad8fcb..1a559750a 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1747,9 +1747,8 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, } -int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size, - int is_pci) +int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size) { VGAState *s; @@ -1805,14 +1804,13 @@ int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, vga_io_memory); - if (is_pci) { + if (bus) { PCIDevice *d; uint8_t *pci_conf; - d = pci_register_device("VGA", + d = pci_register_device(bus, "VGA", sizeof(PCIDevice), - 0, -1, - NULL, NULL); + -1, NULL, NULL); pci_conf = d->config; pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID) pci_conf[0x01] = 0x12; diff --git a/vl.h b/vl.h index 1573df7fd..aa99c2753 100644 --- a/vl.h +++ b/vl.h @@ -457,6 +457,7 @@ extern int pci_enabled; extern target_phys_addr_t pci_mem_base; +typedef struct PCIBus PCIBus; typedef struct PCIDevice PCIDevice; typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, @@ -484,7 +485,7 @@ struct PCIDevice { uint8_t config[256]; /* the following fields are read only */ - int bus_num; + PCIBus *bus; int devfn; char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; @@ -495,8 +496,8 @@ struct PCIDevice { int irq_index; }; -PCIDevice *pci_register_device(const char *name, int instance_size, - int bus_num, int devfn, +PCIDevice *pci_register_device(PCIBus *bus, const char *name, + int instance_size, int devfn, PCIConfigReadFunc *config_read, PCIConfigWriteFunc *config_write); @@ -513,20 +514,22 @@ void pci_default_write_config(PCIDevice *d, extern struct PIIX3State *piix3_state; -void i440fx_init(void); -void piix3_init(void); +PCIBus *i440fx_init(void); +void piix3_init(PCIBus *bus); void pci_bios_init(void); void pci_info(void); /* temporary: will be moved in platform specific file */ -void pci_prep_init(void); -void pci_pmac_init(void); -void pci_ppc_bios_init(void); +PCIBus *pci_prep_init(void); +struct openpic_t; +void pci_pmac_set_openpic(PCIBus *bus, struct openpic_t *openpic); +PCIBus *pci_pmac_init(void); /* openpic.c */ typedef struct openpic_t openpic_t; void openpic_set_irq (openpic_t *opp, int n_IRQ, int level); -openpic_t *openpic_init (uint32_t isu_base, uint32_t idu_base, int nb_cpus); +openpic_t *openpic_init (PCIBus *bus, + uint32_t isu_base, uint32_t idu_base, int nb_cpus); /* vga.c */ @@ -551,17 +554,15 @@ static inline void dpy_resize(DisplayState *s, int w, int h) s->dpy_resize(s, w, h); } -int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size, - int is_pci); +int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); void vga_update_display(void); void vga_invalidate_display(void); void vga_screen_dump(const char *filename); /* cirrus_vga.c */ -void pci_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, +void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); - void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); @@ -575,8 +576,8 @@ extern BlockDriverState *bs_table[MAX_DISKS]; void isa_ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1); -void pci_ide_init(BlockDriverState **hd_table); -void pci_piix3_ide_init(BlockDriverState **hd_table); +void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table); +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table); int pmac_ide_init (BlockDriverState **hd_table, openpic_t *openpic, int irq); @@ -627,7 +628,7 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); /* ne2000.c */ void isa_ne2000_init(int base, int irq, NetDriverState *nd); -void pci_ne2000_init(NetDriverState *nd); +void pci_ne2000_init(PCIBus *bus, NetDriverState *nd); /* pckbd.c */ -- cgit v1.2.3 From 30468f786c127fc027d84c0aec6155e3e59475bb Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 19:45:35 +0000 Subject: added PCI bus - added IRQ support for PowerPC bridges - suppressed PREP PCI bios init git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@962 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 425 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 210 insertions(+), 215 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index de97cb965..919b9028f 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -40,41 +40,42 @@ #define PCI_DEVICES_MAX 64 #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) -typedef struct PCIBridge { - uint32_t config_reg; - PCIDevice **pci_bus[256]; -} PCIBridge; +struct PCIBus { + int bus_num; + int devfn_min; + void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level); + uint32_t config_reg; /* XXX: suppress */ + openpic_t *openpic; /* XXX: suppress */ + PCIDevice *devices[256]; +}; -static PCIBridge pci_bridge[3]; target_phys_addr_t pci_mem_base; static int pci_irq_index; static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; +static PCIBus *first_bus; + +static PCIBus *pci_register_bus(void) +{ + PCIBus *bus; + bus = qemu_mallocz(sizeof(PCIBus)); + first_bus = bus; + return bus; +} /* -1 for devfn means auto assign */ -PCIDevice *pci_register_device(const char *name, int instance_size, - int bus_num, int devfn, +PCIDevice *pci_register_device(PCIBus *bus, const char *name, + int instance_size, int devfn, PCIConfigReadFunc *config_read, PCIConfigWriteFunc *config_write) { - PCIBridge *s = &pci_bridge[0]; - PCIDevice *pci_dev, **bus; + PCIDevice *pci_dev; if (pci_irq_index >= PCI_DEVICES_MAX) return NULL; - if (!s->pci_bus[bus_num]) { - s->pci_bus[bus_num] = qemu_mallocz(256 * sizeof(PCIDevice *)); - if (!s->pci_bus[bus_num]) - return NULL; - } - bus = s->pci_bus[bus_num]; if (devfn < 0) { - for(devfn = 0 ; devfn < 256; devfn += 8) { -#ifdef TARGET_PPC - if ((devfn >> 3) < 11) - continue; -#endif - if (!bus[devfn]) + for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { + if (!bus->devices[devfn]) goto found; } return NULL; @@ -83,7 +84,7 @@ PCIDevice *pci_register_device(const char *name, int instance_size, pci_dev = qemu_mallocz(instance_size); if (!pci_dev) return NULL; - pci_dev->bus_num = bus_num; + pci_dev->bus = bus; pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); @@ -94,7 +95,7 @@ PCIDevice *pci_register_device(const char *name, int instance_size, pci_dev->config_read = config_read; pci_dev->config_write = config_write; pci_dev->irq_index = pci_irq_index++; - bus[devfn] = pci_dev; + bus->devices[devfn] = pci_dev; return pci_dev; } @@ -115,13 +116,13 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; s->config_reg = val; } static uint32_t pci_addr_readl(void* opaque, uint32_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; return s->config_reg; } @@ -321,9 +322,9 @@ void pci_default_write_config(PCIDevice *d, static void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) { - PCIBridge *s = opaque; - PCIDevice **bus, *pci_dev; - int config_addr; + PCIBus *s = opaque; + PCIDevice *pci_dev; + int config_addr, bus_num; #if defined(DEBUG_PCI) && 0 printf("pci_data_write: addr=%08x val=%08x len=%d\n", @@ -335,10 +336,10 @@ static void pci_data_write(void *opaque, uint32_t addr, if ((s->config_reg & 0x3) != 0) { return; } - bus = s->pci_bus[(s->config_reg >> 16) & 0xff]; - if (!bus) + bus_num = (s->config_reg >> 16) & 0xff; + if (bus_num != 0) return; - pci_dev = bus[(s->config_reg >> 8) & 0xff]; + pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; if (!pci_dev) return; config_addr = (s->config_reg & 0xfc) | (addr & 3); @@ -352,19 +353,19 @@ static void pci_data_write(void *opaque, uint32_t addr, static uint32_t pci_data_read(void *opaque, uint32_t addr, int len) { - PCIBridge *s = opaque; - PCIDevice **bus, *pci_dev; - int config_addr; + PCIBus *s = opaque; + PCIDevice *pci_dev; + int config_addr, bus_num; uint32_t val; if (!(s->config_reg & (1 << 31))) goto fail; if ((s->config_reg & 0x3) != 0) goto fail; - bus = s->pci_bus[(s->config_reg >> 16) & 0xff]; - if (!bus) + bus_num = (s->config_reg >> 16) & 0xff; + if (bus_num != 0) goto fail; - pci_dev = bus[(s->config_reg >> 8) & 0xff]; + pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; if (!pci_dev) { fail: switch(len) { @@ -427,11 +428,16 @@ static uint32_t pci_data_readl(void* opaque, uint32_t addr) /* i440FX PCI bridge */ -void i440fx_init(void) +static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level); + +PCIBus *i440fx_init(void) { - PCIBridge *s = &pci_bridge[0]; + PCIBus *s; PCIDevice *d; + s = pci_register_bus(); + s->set_irq = piix3_set_irq; + register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); @@ -442,7 +448,7 @@ void i440fx_init(void) register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); - d = pci_register_device("i440FX", sizeof(PCIDevice), 0, 0, + d = pci_register_device(s, "i440FX", sizeof(PCIDevice), 0, NULL, NULL); d->config[0x00] = 0x86; // vendor_id @@ -453,6 +459,7 @@ void i440fx_init(void) d->config[0x0a] = 0x00; // class_sub = host2pci d->config[0x0b] = 0x06; // class_base = PCI_bridge d->config[0x0e] = 0x00; // header_type + return s; } /* PIIX3 PCI to ISA bridge */ @@ -463,6 +470,52 @@ typedef struct PIIX3State { PIIX3State *piix3_state; +/* return the global irq number corresponding to a given device irq + pin. We could also use the bus number to have a more precise + mapping. */ +static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + int slot_addend; + slot_addend = (pci_dev->devfn >> 3); + return (irq_num + slot_addend) & 3; +} + +static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level) +{ + int irq_index, shift, pic_irq, pic_level; + uint32_t *p; + + irq_num = pci_slot_get_pirq(pci_dev, irq_num); + irq_index = pci_dev->irq_index; + p = &pci_irq_levels[irq_num][irq_index >> 5]; + shift = (irq_index & 0x1f); + *p = (*p & ~(1 << shift)) | (level << shift); + + /* now we change the pic irq level according to the piix irq mappings */ + pic_irq = piix3_state->dev.config[0x60 + irq_num]; + if (pic_irq < 16) { + /* the pic level is the logical OR of all the PCI irqs mapped + to it */ + pic_level = 0; +#if (PCI_IRQ_WORDS == 2) + pic_level = ((pci_irq_levels[irq_num][0] | + pci_irq_levels[irq_num][1]) != 0); +#else + { + int i; + pic_level = 0; + for(i = 0; i < PCI_IRQ_WORDS; i++) { + if (pci_irq_levels[irq_num][i]) { + pic_level = 1; + break; + } + } + } +#endif + pic_set_irq(pic_irq, pic_level); + } +} + static void piix3_reset(PIIX3State *d) { uint8_t *pci_conf = d->dev.config; @@ -498,14 +551,13 @@ static void piix3_reset(PIIX3State *d) pci_conf[0xae] = 0x00; } -void piix3_init(void) +void piix3_init(PCIBus *bus) { PIIX3State *d; uint8_t *pci_conf; - d = (PIIX3State *)pci_register_device("PIIX3", sizeof(PIIX3State), - 0, -1, - NULL, NULL); + d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State), + -1, NULL, NULL); piix3_state = d; pci_conf = d->dev.config; @@ -522,7 +574,7 @@ void piix3_init(void) /* PREP pci init */ -static inline void set_config(PCIBridge *s, target_phys_addr_t addr) +static inline void set_config(PCIBus *s, target_phys_addr_t addr) { int devfn, i; @@ -536,14 +588,14 @@ static inline void set_config(PCIBridge *s, target_phys_addr_t addr) static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; set_config(s, addr); pci_data_write(s, addr, val, 1); } static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; set_config(s, addr); #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); @@ -553,7 +605,7 @@ static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t va static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; set_config(s, addr); #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); @@ -563,7 +615,7 @@ static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t va static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; set_config(s, addr); val = pci_data_read(s, addr, 1); @@ -572,7 +624,7 @@ static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; set_config(s, addr); val = pci_data_read(s, addr, 2); @@ -584,7 +636,7 @@ static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; set_config(s, addr); val = pci_data_read(s, addr, 4); @@ -606,17 +658,27 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = { &PPC_PCIIO_readl, }; -void pci_prep_init(void) +static void prep_set_irq(PCIDevice *d, int irq_num, int level) +{ + /* XXX: we do not simulate the hardware - we rely on the BIOS to + set correctly for irq line field */ + pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_prep_init(void) { - PCIBridge *s = &pci_bridge[0]; + PCIBus *s; PCIDevice *d; int PPC_io_memory; + s = pci_register_bus(); + s->set_irq = prep_set_irq; + PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, PPC_PCIIO_write, s); cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); - d = pci_register_device("PREP PCI Bridge", sizeof(PCIDevice), 0, 0, + d = pci_register_device(s, "PREP PCI Bridge", sizeof(PCIDevice), 0, NULL, NULL); /* XXX: put correct IDs */ @@ -628,16 +690,18 @@ void pci_prep_init(void) d->config[0x0a] = 0x04; // class_sub = pci2pci d->config[0x0b] = 0x06; // class_base = PCI_bridge d->config[0x0e] = 0x01; // header_type + return s; } /* pmac pci init */ +#if 0 /* Grackle PCI host */ static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif @@ -646,7 +710,7 @@ static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = s->config_reg; @@ -671,14 +735,14 @@ static CPUReadMemoryFunc *pci_grackle_config_read[] = { static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; pci_data_write(s, addr, val, 1); } static void pci_grackle_writew (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); #endif @@ -688,7 +752,7 @@ static void pci_grackle_writew (void *opaque, target_phys_addr_t addr, static void pci_grackle_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif @@ -697,7 +761,7 @@ static void pci_grackle_writel (void *opaque, target_phys_addr_t addr, static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr, 1); return val; @@ -705,7 +769,7 @@ static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr) static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr, 2); #ifdef TARGET_WORDS_BIGENDIAN @@ -716,7 +780,7 @@ static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr) static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr, 4); @@ -737,12 +801,13 @@ static CPUReadMemoryFunc *pci_grackle_read[] = { &pci_grackle_readw, &pci_grackle_readl, }; +#endif /* Uninorth PCI host (for all Mac99 and newer machines */ static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; int i; #ifdef TARGET_WORDS_BIGENDIAN @@ -763,7 +828,7 @@ static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, static uint32_t pci_unin_main_config_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; int devfn; @@ -791,14 +856,14 @@ static CPUReadMemoryFunc *pci_unin_main_config_read[] = { static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; pci_data_write(s, addr & 7, val, 1); } static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); #endif @@ -808,7 +873,7 @@ static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr, static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif @@ -817,7 +882,7 @@ static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr, static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr & 7, 1); @@ -827,7 +892,7 @@ static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr) static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr & 7, 2); @@ -840,7 +905,7 @@ static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr) static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr, 4); @@ -863,10 +928,12 @@ static CPUReadMemoryFunc *pci_unin_main_read[] = { &pci_unin_main_readl, }; +#if 0 + static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); @@ -877,7 +944,7 @@ static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, static uint32_t pci_unin_config_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = (s->config_reg | 0x00000001) & ~0x80000000; @@ -903,14 +970,14 @@ static CPUReadMemoryFunc *pci_unin_config_read[] = { static void pci_unin_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; pci_data_write(s, addr & 3, val, 1); } static void pci_unin_writew (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); #endif @@ -920,7 +987,7 @@ static void pci_unin_writew (void *opaque, target_phys_addr_t addr, static void pci_unin_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - PCIBridge *s = opaque; + PCIBus *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif @@ -929,7 +996,7 @@ static void pci_unin_writel (void *opaque, target_phys_addr_t addr, static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr & 3, 1); @@ -939,7 +1006,7 @@ static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr) static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr & 3, 2); @@ -952,7 +1019,7 @@ static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr) static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr) { - PCIBridge *s = opaque; + PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr & 3, 4); @@ -974,25 +1041,45 @@ static CPUReadMemoryFunc *pci_unin_read[] = { &pci_unin_readw, &pci_unin_readl, }; +#endif + +static void pmac_set_irq(PCIDevice *d, int irq_num, int level) +{ + openpic_t *openpic; + /* XXX: we do not simulate the hardware - we rely on the BIOS to + set correctly for irq line field */ + openpic = d->bus->openpic; +#ifdef TARGET_PPC + if (openpic) + openpic_set_irq(openpic, d->config[PCI_INTERRUPT_LINE], level); +#endif +} + +void pci_pmac_set_openpic(PCIBus *bus, openpic_t *openpic) +{ + bus->openpic = openpic; +} -void pci_pmac_init(void) +PCIBus *pci_pmac_init(void) { - PCIBridge *s; + PCIBus *s; PCIDevice *d; int pci_mem_config, pci_mem_data; /* Use values found on a real PowerMac */ /* Uninorth main bus */ - s = &pci_bridge[0]; + s = pci_register_bus(); + s->set_irq = pmac_set_irq; + pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, pci_unin_main_config_write, s); pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, pci_unin_main_write, s); cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north main", sizeof(PCIDevice), 0, 11 << 3, - NULL, NULL); + s->devfn_min = 11 << 3; + d = pci_register_device(s, "Uni-north main", sizeof(PCIDevice), + 11 << 3, NULL, NULL); d->config[0x00] = 0x6b; // vendor_id : Apple d->config[0x01] = 0x10; d->config[0x02] = 0x1F; // device_id @@ -1113,63 +1200,18 @@ void pci_pmac_init(void) d->config[0x26] = 0x00; // prefetchable_memory_limit d->config[0x27] = 0x85; #endif + return s; } /***********************************************************/ /* generic PCI irq support */ -/* return the global irq number corresponding to a given device irq - pin. We could also use the bus number to have a more precise - mapping. */ -static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) -{ - int slot_addend; - slot_addend = (pci_dev->devfn >> 3); - return (irq_num + slot_addend) & 3; -} - /* 0 <= irq_num <= 3. level must be 0 or 1 */ -#ifdef TARGET_PPC void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) { + PCIBus *bus = pci_dev->bus; + bus->set_irq(pci_dev, irq_num, level); } -#else -void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) -{ - int irq_index, shift, pic_irq, pic_level; - uint32_t *p; - - irq_num = pci_slot_get_pirq(pci_dev, irq_num); - irq_index = pci_dev->irq_index; - p = &pci_irq_levels[irq_num][irq_index >> 5]; - shift = (irq_index & 0x1f); - *p = (*p & ~(1 << shift)) | (level << shift); - - /* now we change the pic irq level according to the piix irq mappings */ - pic_irq = piix3_state->dev.config[0x60 + irq_num]; - if (pic_irq < 16) { - /* the pic level is the logical OR of all the PCI irqs mapped - to it */ - pic_level = 0; -#if (PCI_IRQ_WORDS == 2) - pic_level = ((pci_irq_levels[irq_num][0] | - pci_irq_levels[irq_num][1]) != 0); -#else - { - int i; - pic_level = 0; - for(i = 0; i < PCI_IRQ_WORDS; i++) { - if (pci_irq_levels[irq_num][i]) { - pic_level = 1; - break; - } - } - } -#endif - pic_set_irq(pic_irq, pic_level); - } -} -#endif /***********************************************************/ /* monitor info on PCI */ @@ -1180,7 +1222,7 @@ static void pci_info_device(PCIDevice *d) PCIIORegion *r; printf(" Bus %2d, device %3d, function %d:\n", - d->bus_num, d->devfn >> 3, d->devfn & 7); + d->bus->bus_num, d->devfn >> 3, d->devfn & 7); class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); printf(" "); switch(class) { @@ -1221,17 +1263,15 @@ static void pci_info_device(PCIDevice *d) void pci_info(void) { - PCIBridge *s = &pci_bridge[0]; - PCIDevice **bus; - int bus_num, devfn; + PCIBus *bus = first_bus; + PCIDevice *d; + int devfn; - for(bus_num = 0; bus_num < 256; bus_num++) { - bus = s->pci_bus[bus_num]; - if (bus) { - for(devfn = 0; devfn < 256; devfn++) { - if (bus[devfn]) - pci_info_device(bus[devfn]); - } + if (bus) { + for(devfn = 0; devfn < 256; devfn++) { + d = bus->devices[devfn]; + if (d) + pci_info_device(d); } } } @@ -1239,7 +1279,7 @@ void pci_info(void) /***********************************************************/ /* XXX: the following should be moved to the PC BIOS */ -static uint32_t isa_inb(uint32_t addr) +static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) { return cpu_inb(cpu_single_env, addr); } @@ -1249,70 +1289,70 @@ static void isa_outb(uint32_t val, uint32_t addr) cpu_outb(cpu_single_env, addr, val); } -static uint32_t isa_inw(uint32_t addr) +static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) { return cpu_inw(cpu_single_env, addr); } -static void isa_outw(uint32_t val, uint32_t addr) +static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) { cpu_outw(cpu_single_env, addr, val); } -static uint32_t isa_inl(uint32_t addr) +static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) { return cpu_inl(cpu_single_env, addr); } -static void isa_outl(uint32_t val, uint32_t addr) +static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) { cpu_outl(cpu_single_env, addr, val); } static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge[0]; - s->config_reg = 0x80000000 | (d->bus_num << 16) | + PCIBus *s = d->bus; + s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | addr; pci_data_write(s, 0, val, 4); } static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge[0]; - s->config_reg = 0x80000000 | (d->bus_num << 16) | + PCIBus *s = d->bus; + s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | (addr & ~3); pci_data_write(s, addr & 3, val, 2); } static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) { - PCIBridge *s = &pci_bridge[0]; - s->config_reg = 0x80000000 | (d->bus_num << 16) | + PCIBus *s = d->bus; + s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | (addr & ~3); pci_data_write(s, addr & 3, val, 1); } -static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) +static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) { - PCIBridge *s = &pci_bridge[0]; - s->config_reg = 0x80000000 | (d->bus_num << 16) | + PCIBus *s = d->bus; + s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | addr; return pci_data_read(s, 0, 4); } static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) { - PCIBridge *s = &pci_bridge[0]; - s->config_reg = 0x80000000 | (d->bus_num << 16) | + PCIBus *s = d->bus; + s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | (addr & ~3); return pci_data_read(s, addr & 3, 2); } static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) { - PCIBridge *s = &pci_bridge[0]; - s->config_reg = 0x80000000 | (d->bus_num << 16) | + PCIBus *s = d->bus; + s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | (addr & ~3); return pci_data_read(s, addr & 3, 1); } @@ -1432,9 +1472,9 @@ static void pci_bios_init_device(PCIDevice *d) */ void pci_bios_init(void) { - PCIBridge *s = &pci_bridge[0]; - PCIDevice **bus; - int bus_num, devfn, i, irq; + PCIBus *bus; + PCIDevice *d; + int devfn, i, irq; uint8_t elcr[2]; pci_bios_io_addr = 0xc000; @@ -1453,57 +1493,12 @@ void pci_bios_init(void) isa_outb(elcr[0], 0x4d0); isa_outb(elcr[1], 0x4d1); - for(bus_num = 0; bus_num < 256; bus_num++) { - bus = s->pci_bus[bus_num]; - if (bus) { - for(devfn = 0; devfn < 256; devfn++) { - if (bus[devfn]) - pci_bios_init_device(bus[devfn]); - } - } - } -} - -/* - * This function initializes the PCI devices as a normal PCI BIOS - * would do. It is provided just in case the BIOS has no support for - * PCI. - */ -void pci_ppc_bios_init(void) -{ - PCIBridge *s = &pci_bridge[0]; - PCIDevice **bus; - int bus_num, devfn; -#if 0 - int i, irq; - uint8_t elcr[2]; -#endif - - pci_bios_io_addr = 0xc000; - pci_bios_mem_addr = 0xc0000000; - -#if 0 - /* activate IRQ mappings */ - elcr[0] = 0x00; - elcr[1] = 0x00; - for(i = 0; i < 4; i++) { - irq = pci_irqs[i]; - /* set to trigger level */ - elcr[irq >> 3] |= (1 << (irq & 7)); - /* activate irq remapping in PIIX */ - pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); - } - isa_outb(elcr[0], 0x4d0); - isa_outb(elcr[1], 0x4d1); -#endif - - for(bus_num = 0; bus_num < 256; bus_num++) { - bus = s->pci_bus[bus_num]; - if (bus) { - for(devfn = 0; devfn < 256; devfn++) { - if (bus[devfn]) - pci_bios_init_device(bus[devfn]); - } + bus = first_bus; + if (bus) { + for(devfn = 0; devfn < 256; devfn++) { + d = bus->devices[devfn]; + if (d) + pci_bios_init_device(d); } } } -- cgit v1.2.3 From 638260eb8e69d7fc1b52f2ea898d7bdb7e7f90d3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 19:54:19 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@963 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index e92283c9b..614e18cf4 100644 --- a/Changelog +++ b/Changelog @@ -21,6 +21,8 @@ version 0.5.6: - APM and system shutdown support - Fixed system reset - Support for other PC BIOSes + - Initial PowerMac hardware emulation + - PowerMac/PREP OpenFirmware compatible BIOS (Jocelyn Mayer) version 0.5.5: -- cgit v1.2.3 From 637f6cd7352ad2570a77267e7d254785349a4a1f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 19:54:47 +0000 Subject: ppc bios git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@964 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 ++ pc-bios/ppc_rom.bin | Bin 0 -> 524288 bytes 2 files changed, 2 insertions(+) create mode 100644 pc-bios/ppc_rom.bin diff --git a/Makefile b/Makefile index d4c4b0ffe..4d76abc94 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ endif mkdir -p "$(datadir)" install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/vgabios-cirrus.bin \ + pc-bios/ppc_rom.bin \ pc-bios/linux_boot.bin "$(datadir)" mkdir -p "$(docdir)" install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" @@ -99,6 +100,7 @@ tarbin: $(datadir)/bios.bin \ $(datadir)/vgabios.bin \ $(datadir)/vgabios-cirrus.bin \ + $(datadir)/ppc_rom.bin \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin new file mode 100644 index 000000000..c2beb6227 Binary files /dev/null and b/pc-bios/ppc_rom.bin differ -- cgit v1.2.3 From e2733d20b2c8fade7e81aebb34e4e1db821d472f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 22:46:10 +0000 Subject: ADB fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@965 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adb.c | 248 ++++++++++++++++++++++++++++++++++++++------------------------ hw/cuda.c | 50 ++++++++++++- vl.h | 20 +++-- 3 files changed, 210 insertions(+), 108 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index 2d230a697..de06f8789 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -43,53 +43,53 @@ #define ADB_MODEM 5 #define ADB_MISC 7 -#define ADB_RET_OK 0 -#define ADB_RET_INUSE 1 -#define ADB_RET_NOTPRESENT 2 -#define ADB_RET_TIMEOUT 3 -#define ADB_RET_UNEXPECTED_RESULT 4 -#define ADB_RET_REQUEST_ERROR 5 -#define ADB_RET_BUS_ERROR 6 - - -static void adb_send_packet1(ADBBusState *s, uint8_t reply) -{ - adb_send_packet(s, &reply, 1); -} - -void adb_receive_packet(ADBBusState *s, const uint8_t *buf, int len) +int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) { ADBDevice *d; int devaddr, cmd, i; - uint8_t obuf[4]; cmd = buf[0] & 0xf; devaddr = buf[0] >> 4; if (buf[1] == ADB_BUSRESET) { obuf[0] = 0x00; obuf[1] = 0x00; - adb_send_packet(s, obuf, 2); - return; + return 2; } if (cmd == ADB_FLUSH) { obuf[0] = 0x00; obuf[1] = 0x00; - adb_send_packet(s, obuf, 2); - return; + return 2; } for(i = 0; i < s->nb_devices; i++) { d = &s->devices[i]; if (d->devaddr == devaddr) { - d->receive_packet(d, buf, len); - return; + return d->devreq(d, obuf, buf, len); } } - adb_send_packet1(s, ADB_RET_NOTPRESENT); + return 0; +} + +int adb_poll(ADBBusState *s, uint8_t *obuf) +{ + ADBDevice *d; + int olen, i; + + olen = 0; + for(i = 0; i < s->nb_devices; i++) { + if (s->poll_index >= s->nb_devices) + s->poll_index = 0; + d = &s->devices[s->poll_index]; + olen = d->devreq(d, obuf, NULL, 0); + s->poll_index++; + if (olen) + break; + } + return olen; } ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceReceivePacket *receive_packet, + ADBDeviceRequest *devreq, void *opaque) { ADBDevice *d; @@ -98,7 +98,7 @@ ADBDevice *adb_register_device(ADBBusState *s, int devaddr, d = &s->devices[s->nb_devices++]; d->bus = s; d->devaddr = devaddr; - d->receive_packet = receive_packet; + d->devreq = devreq; d->opaque = opaque; return d; } @@ -106,80 +106,108 @@ ADBDevice *adb_register_device(ADBBusState *s, int devaddr, /***************************************************************/ /* Keyboard ADB device */ +typedef struct KBDState { + uint8_t data[128]; + int rptr, wptr, count; +} KBDState; + static const uint8_t pc_to_adb_keycode[256] = { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, - 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117, - 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 95, 55, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119, + 61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static void adb_kbd_put_keycode(void *opaque, int keycode) { - static int ext_keycode; ADBDevice *d = opaque; - uint8_t buf[4]; - int adb_keycode; - - if (keycode == 0xe0) { - ext_keycode = 1; - } else { - - if (ext_keycode) - adb_keycode = pc_to_adb_keycode[keycode | 0x80]; - else - adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; - - buf[0] = 0x40; - buf[1] = (d->devaddr << 4) | 0x0c; - buf[2] = adb_keycode | (keycode & 0x80); - buf[3] = 0xff; - adb_send_packet(d->bus, buf, 4); - ext_keycode = 0; + KBDState *s = d->opaque; + + if (s->count < sizeof(s->data)) { + s->data[s->wptr] = keycode; + if (++s->wptr == sizeof(s->data)) + s->wptr = 0; + s->count++; } } -static void adb_kbd_receive_packet(ADBDevice *d, const uint8_t *buf, int len) +static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) { - int cmd, reg; - uint8_t obuf[4]; + static int ext_keycode; + KBDState *s = d->opaque; + int adb_keycode, keycode; + int olen; + + olen = 0; + for(;;) { + if (s->count == 0) + break; + keycode = s->data[s->rptr]; + if (++s->rptr == sizeof(s->data)) + s->rptr = 0; + s->count--; + + if (keycode == 0xe0) { + ext_keycode = 1; + } else { + if (ext_keycode) + adb_keycode = pc_to_adb_keycode[keycode | 0x80]; + else + adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; + obuf[0] = (d->devaddr << 4) | 0x0c; + obuf[1] = adb_keycode | (keycode & 0x80); + obuf[2] = 0xff; + olen = 3; + ext_keycode = 0; + break; + } + } + return olen; +} + +static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, + const uint8_t *buf, int len) +{ + int cmd, reg, olen; + + if (!buf) { + return adb_kbd_poll(d, obuf); + } cmd = buf[0] & 0xc; reg = buf[0] & 0x3; + olen = 0; switch(cmd) { case ADB_WRITEREG: switch(reg) { case 2: /* LED status */ - adb_send_packet1(d->bus, ADB_RET_OK); break; case 3: switch(buf[2]) { case ADB_CMD_SELF_TEST: - adb_send_packet1(d->bus, ADB_RET_OK); break; case ADB_CMD_CHANGE_ID: case ADB_CMD_CHANGE_ID_AND_ACT: case ADB_CMD_CHANGE_ID_AND_ENABLE: d->devaddr = buf[1] & 0xf; - adb_send_packet1(d->bus, ADB_RET_OK); break; default: /* XXX: check this */ d->devaddr = buf[1] & 0xf; d->handler = buf[2]; - adb_send_packet1(d->bus, ADB_RET_OK); break; } } @@ -187,98 +215,122 @@ static void adb_kbd_receive_packet(ADBDevice *d, const uint8_t *buf, int len) case ADB_READREG: switch(reg) { case 1: - adb_send_packet1(d->bus, ADB_RET_OK); break; case 2: - obuf[0] = ADB_RET_OK; - obuf[1] = 0x00; /* XXX: check this */ - obuf[2] = 0x07; /* led status */ - adb_send_packet(d->bus, obuf, 3); + obuf[0] = 0x00; /* XXX: check this */ + obuf[1] = 0x07; /* led status */ + olen = 2; break; case 3: - obuf[0] = ADB_RET_OK; - obuf[1] = d->handler; - obuf[2] = d->devaddr; - adb_send_packet(d->bus, obuf, 3); + obuf[0] = d->handler; + obuf[1] = d->devaddr; + olen = 2; break; } break; } + return olen; } void adb_kbd_init(ADBBusState *bus) { ADBDevice *d; - - d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_receive_packet, NULL); + KBDState *s; + s = qemu_mallocz(sizeof(KBDState)); + d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, s); + d->handler = 1; qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); } /***************************************************************/ /* Mouse ADB device */ +typedef struct MouseState { + int buttons_state, last_buttons_state; + int dx, dy, dz; +} MouseState; + static void adb_mouse_event(void *opaque, int dx1, int dy1, int dz1, int buttons_state) { ADBDevice *d = opaque; - uint8_t buf[4]; + MouseState *s = d->opaque; + + s->dx += dx1; + s->dy += dy1; + s->dz += dz1; + s->buttons_state = buttons_state; +} + + +static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) +{ + MouseState *s = d->opaque; int dx, dy; - dx = dx1; + if (s->last_buttons_state == s->buttons_state && + s->dx == 0 && s->dy == 0) + return 0; + + dx = s->dx; if (dx < -63) dx = -63; else if (dx > 63) dx = 63; - - dy = dy1; + + dy = s->dy; if (dy < -63) dy = -63; else if (dy > 63) dy = 63; - + + s->dx -= dx; + s->dy -= dy; + s->last_buttons_state = s->buttons_state; + dx &= 0x7f; dy &= 0x7f; - - if (buttons_state & MOUSE_EVENT_LBUTTON) + + if (s->buttons_state & MOUSE_EVENT_LBUTTON) dy |= 0x80; - if (buttons_state & MOUSE_EVENT_RBUTTON) + if (s->buttons_state & MOUSE_EVENT_RBUTTON) dx |= 0x80; - - buf[0] = 0x40; - buf[1] = (d->devaddr << 4) | 0x0c; - buf[2] = dy; - buf[3] = dx; - adb_send_packet(d->bus, buf, 4); + + obuf[0] = (d->devaddr << 4) | 0x0c; + obuf[1] = dy; + obuf[2] = dx; + return 3; } -static void adb_mouse_receive_packet(ADBDevice *d, const uint8_t *buf, int len) +static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, + const uint8_t *buf, int len) { - int cmd, reg; - uint8_t obuf[4]; + int cmd, reg, olen; + + if (!buf) { + return adb_mouse_poll(d, obuf); + } cmd = buf[0] & 0xc; reg = buf[0] & 0x3; + olen = 0; switch(cmd) { case ADB_WRITEREG: switch(reg) { case 2: - adb_send_packet1(d->bus, ADB_RET_OK); break; case 3: switch(buf[2]) { case ADB_CMD_SELF_TEST: - adb_send_packet1(d->bus, ADB_RET_OK); break; case ADB_CMD_CHANGE_ID: case ADB_CMD_CHANGE_ID_AND_ACT: case ADB_CMD_CHANGE_ID_AND_ENABLE: d->devaddr = buf[1] & 0xf; - adb_send_packet1(d->bus, ADB_RET_OK); break; default: /* XXX: check this */ d->devaddr = buf[1] & 0xf; - adb_send_packet1(d->bus, ADB_RET_OK); break; } } @@ -286,23 +338,25 @@ static void adb_mouse_receive_packet(ADBDevice *d, const uint8_t *buf, int len) case ADB_READREG: switch(reg) { case 1: - adb_send_packet1(d->bus, ADB_RET_OK); break; case 3: - obuf[0] = ADB_RET_OK; - obuf[1] = d->handler; - obuf[2] = d->devaddr; - adb_send_packet(d->bus, obuf, 3); + obuf[0] = d->handler; + obuf[1] = d->devaddr; + olen = 2; break; } break; } + return olen; } void adb_mouse_init(ADBBusState *bus) { ADBDevice *d; + MouseState *s; - d = adb_register_device(bus, ADB_MOUSE, adb_mouse_receive_packet, NULL); + s = qemu_mallocz(sizeof(MouseState)); + d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, s); + d->handler = 2; qemu_add_mouse_event_handler(adb_mouse_event, d); } diff --git a/hw/cuda.c b/hw/cuda.c index 544158f9c..8194016d6 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -85,6 +85,7 @@ #define CUDA_COMBINED_FORMAT_IIC 0x25 #define CUDA_TIMER_FREQ (4700000 / 6) +#define CUDA_ADB_POLL_FREQ 50 typedef struct CUDATimer { unsigned int latch; @@ -121,6 +122,7 @@ typedef struct CUDAState { uint8_t autopoll; uint8_t data_in[128]; uint8_t data_out[16]; + QEMUTimer *adb_poll_timer; } CUDAState; static CUDAState cuda_state; @@ -469,15 +471,42 @@ void adb_send_packet(ADBBusState *bus, const uint8_t *buf, int len) cuda_send_packet_to_host(s, data, len + 1); } +void cuda_adb_poll(void *opaque) +{ + CUDAState *s = opaque; + uint8_t obuf[ADB_MAX_OUT_LEN + 2]; + int olen; + + olen = adb_poll(&adb_bus, obuf + 2); + if (olen > 0) { + obuf[0] = ADB_PACKET; + obuf[1] = 0x40; /* polled data */ + cuda_send_packet_to_host(s, obuf, olen + 2); + } + qemu_mod_timer(s->adb_poll_timer, + qemu_get_clock(vm_clock) + + (ticks_per_sec / CUDA_ADB_POLL_FREQ)); +} + static void cuda_receive_packet(CUDAState *s, const uint8_t *data, int len) { uint8_t obuf[16]; - int ti; + int ti, autopoll; switch(data[0]) { case CUDA_AUTOPOLL: - s->autopoll = data[1]; + autopoll = (data[1] != 0); + if (autopoll != s->autopoll) { + s->autopoll = autopoll; + if (autopoll) { + qemu_mod_timer(s->adb_poll_timer, + qemu_get_clock(vm_clock) + + (ticks_per_sec / CUDA_ADB_POLL_FREQ)); + } else { + qemu_del_timer(s->adb_poll_timer); + } + } obuf[0] = CUDA_PACKET; obuf[1] = data[1]; cuda_send_packet_to_host(s, obuf, 2); @@ -522,7 +551,20 @@ static void cuda_receive_packet_from_host(CUDAState *s, #endif switch(data[0]) { case ADB_PACKET: - adb_receive_packet(&adb_bus, data + 1, len - 1); + { + uint8_t obuf[ADB_MAX_OUT_LEN + 2]; + int olen; + olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1); + if (olen != 0) { + obuf[0] = ADB_PACKET; + obuf[1] = 0x00; + } else { + /* empty reply */ + obuf[0] = ADB_PACKET; + obuf[1] = 0x02; + } + cuda_send_packet_to_host(s, obuf, olen + 2); + } break; case CUDA_PACKET: cuda_receive_packet(s, data + 1, len - 1); @@ -574,6 +616,8 @@ int cuda_init(openpic_t *openpic, int irq) s->timers[1].latch = 0x10000; s->ier = T1_INT | SR_INT; set_counter(s, &s->timers[1], 0xffff); + + s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s); cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); return cuda_mem_index; } diff --git a/vl.h b/vl.h index aa99c2753..583e8433d 100644 --- a/vl.h +++ b/vl.h @@ -528,8 +528,7 @@ PCIBus *pci_pmac_init(void); /* openpic.c */ typedef struct openpic_t openpic_t; void openpic_set_irq (openpic_t *opp, int n_IRQ, int level); -openpic_t *openpic_init (PCIBus *bus, - uint32_t isu_base, uint32_t idu_base, int nb_cpus); +openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus); /* vga.c */ @@ -727,28 +726,33 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, #define MAX_ADB_DEVICES 16 -typedef struct ADBDevice ADBDevice; +#define ADB_MAX_OUT_LEN 16 -typedef void ADBDeviceReceivePacket(ADBDevice *d, const uint8_t *buf, int len); +typedef struct ADBDevice ADBDevice; +/* buf = NULL means polling */ +typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, + const uint8_t *buf, int len); struct ADBDevice { struct ADBBusState *bus; int devaddr; int handler; - ADBDeviceReceivePacket *receive_packet; + ADBDeviceRequest *devreq; void *opaque; }; typedef struct ADBBusState { ADBDevice devices[MAX_ADB_DEVICES]; int nb_devices; + int poll_index; } ADBBusState; -void adb_receive_packet(ADBBusState *s, const uint8_t *buf, int len); -void adb_send_packet(ADBBusState *s, const uint8_t *buf, int len); +int adb_request(ADBBusState *s, uint8_t *buf_out, + const uint8_t *buf, int len); +int adb_poll(ADBBusState *s, uint8_t *buf_out); ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceReceivePacket *receive_packet, + ADBDeviceRequest *devreq, void *opaque); void adb_kbd_init(ADBBusState *bus); void adb_mouse_init(ADBBusState *bus); -- cgit v1.2.3 From 91d848ebf3bc7fd73fb1a4fc11bdb04225b3f37d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Jun 2004 22:46:48 +0000 Subject: disable PCI device for PMAC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@966 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/openpic.c | 57 +++++++++++++++++++++++++++++++-------------------------- hw/ppc_chrp.c | 4 +++- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index eab6d0811..d193cfe6f 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -164,6 +164,7 @@ typedef struct IRQ_dst_t { struct openpic_t { PCIDevice pci_dev; + int mem_index; /* Global registers */ uint32_t frep; /* Feature reporting register */ uint32_t glbc; /* Global configuration register */ @@ -937,7 +938,6 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { openpic_t *opp; - int opp_io_memory; DPRINTF("Map OpenPIC\n"); opp = (openpic_t *)pci_dev; @@ -953,9 +953,7 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, /* Per CPU registers */ DPRINTF("Register OPENPIC dst %08x => %08x\n", addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU); - opp_io_memory = cpu_register_io_memory(0, openpic_read, - openpic_write, opp); - cpu_register_physical_memory(addr, 0x40000, opp_io_memory); + cpu_register_physical_memory(addr, 0x40000, opp->mem_index); #if 0 // Don't implement ISU for now opp_io_memory = cpu_register_io_memory(0, openpic_src_read, openpic_src_write); @@ -964,8 +962,7 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, #endif } -openpic_t *openpic_init (PCIBus *bus, - uint32_t isu_base, uint32_t idu_base, int nb_cpus) +openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus) { openpic_t *opp; uint8_t *pci_conf; @@ -974,25 +971,32 @@ openpic_t *openpic_init (PCIBus *bus, /* XXX: for now, only one CPU is supported */ if (nb_cpus != 1) return NULL; - opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t), - -1, NULL, NULL); - if (opp == NULL) - return NULL; - pci_conf = opp->pci_dev.config; - pci_conf[0x00] = 0x14; // IBM MPIC2 - pci_conf[0x01] = 0x10; - pci_conf[0x02] = 0xFF; - pci_conf[0x03] = 0xFF; - pci_conf[0x0a] = 0x80; // PIC - pci_conf[0x0b] = 0x08; - pci_conf[0x0e] = 0x00; // header_type - pci_conf[0x3d] = 0x00; // no interrupt pin - - /* Register I/O spaces */ - pci_register_io_region((PCIDevice *)opp, 0, 0x40000, - PCI_ADDRESS_SPACE_MEM, &openpic_map); - - isu_base &= 0xFFFC0000; + if (bus) { + opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t), + -1, NULL, NULL); + if (opp == NULL) + return NULL; + pci_conf = opp->pci_dev.config; + pci_conf[0x00] = 0x14; // IBM MPIC2 + pci_conf[0x01] = 0x10; + pci_conf[0x02] = 0xFF; + pci_conf[0x03] = 0xFF; + pci_conf[0x0a] = 0x80; // PIC + pci_conf[0x0b] = 0x08; + pci_conf[0x0e] = 0x00; // header_type + pci_conf[0x3d] = 0x00; // no interrupt pin + + /* Register I/O spaces */ + pci_register_io_region((PCIDevice *)opp, 0, 0x40000, + PCI_ADDRESS_SPACE_MEM, &openpic_map); + } else { + opp = qemu_mallocz(sizeof(openpic_t)); + } + + opp->mem_index = cpu_register_io_memory(0, openpic_read, + openpic_write, opp); + + // isu_base &= 0xFFFC0000; opp->nb_cpus = nb_cpus; /* Set IRQ types */ for (i = 0; i < EXT_IRQ; i++) { @@ -1013,6 +1017,7 @@ openpic_t *openpic_init (PCIBus *bus, opp->src[i].type = IRQ_INTERNAL; } openpic_reset(opp); - + if (pmem_index) + *pmem_index = opp->mem_index; return opp; } diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index fce434832..93835322f 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -36,6 +36,7 @@ static int dbdma_mem_index; static int cuda_mem_index; static int ide0_mem_index; static int ide1_mem_index; +static int openpic_mem_index; /* DBDMA: currently no op - should suffice right now */ @@ -87,6 +88,7 @@ static void macio_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index); cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index); cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); + cpu_register_physical_memory(addr + 0x40000, 0x40000, openpic_mem_index); } static void macio_init(PCIBus *bus) @@ -191,7 +193,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, /* init basic PC hardware */ vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); - openpic = openpic_init(pci_bus, 0x00000000, 0xF0000000, 1); + openpic = openpic_init(NULL, &openpic_mem_index, 1); pci_pmac_set_openpic(pci_bus, openpic); /* XXX: suppress that */ -- cgit v1.2.3 From 7496f5266c568ceef2d4a3a2d0af381cf1810e30 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Jun 2004 10:56:50 +0000 Subject: cpu_single_env init git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@967 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 1 + target-i386/helper2.c | 2 +- target-ppc/translate.c | 2 +- target-sparc/translate.c | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 00bdbb98a..3185286bb 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -815,6 +815,7 @@ CPUARMState *cpu_arm_init(void) if (!env) return NULL; memset(env, 0, sizeof(CPUARMState)); + cpu_single_env = env; return env; } diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 455b348a0..06c732edc 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -75,9 +75,9 @@ CPUX86State *cpu_x86_init(void) modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); - cpu_single_env = env; } #endif + cpu_single_env = env; cpu_reset(env); return env; } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1489c462f..a3133fdfc 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2994,7 +2994,7 @@ CPUPPCState *cpu_ppc_init(void) env->nip = 0xFFFFFFFC; #endif env->access_type = ACCESS_INT; - + cpu_single_env = env; return env; } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index bcc810b20..fe37c0748 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -840,6 +840,7 @@ CPUSPARCState *cpu_sparc_init(void) env->wim = 1; env->regwptr = env->regbase + (env->cwp * 16); env->user_mode_only = 1; + cpu_single_env = env; return (env); } -- cgit v1.2.3 From dc5d0b3d1b2e0fdb48fcf4033058bc351580959d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Jun 2004 18:43:30 +0000 Subject: disable buggy tb_invalidate_page_range() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@968 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpu-exec.c b/cpu-exec.c index 58468859d..aa713c9a6 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -602,9 +602,13 @@ int cpu_exec(CPUState *env1) 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) -- cgit v1.2.3 From 107db44327c4af0e406b08b3a635bea8ac7d75cc Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Jun 2004 18:48:46 +0000 Subject: consider that all archs have SMC (workaround) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@969 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 45b723f6d..9d1306d54 100644 --- a/exec.c +++ b/exec.c @@ -822,7 +822,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, p->first_tb = (TranslationBlock *)((long)tb | n); invalidate_page_bitmap(p); -#ifdef TARGET_HAS_SMC +#if defined(TARGET_HAS_SMC) || 1 #if defined(CONFIG_USER_ONLY) if (p->flags & PAGE_WRITE) { -- cgit v1.2.3 From 02ba45c5362011ce323c69f04b49fe61663a68e3 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 25 Jun 2004 14:46:23 +0000 Subject: use RT signal for /dev/rtc - restore stdin flags (Bob Barry) - cpu save fix (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@970 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index 3dee9d32c..2c3c72dca 100644 --- a/vl.c +++ b/vl.c @@ -787,6 +787,35 @@ void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, static void host_alarm_handler(int host_signum) #endif { +#if 0 +#define DISP_FREQ 1000 + { + static int64_t delta_min = INT64_MAX; + static int64_t delta_max, delta_cum, last_clock, delta, ti; + static int count; + ti = qemu_get_clock(vm_clock); + if (last_clock != 0) { + delta = ti - last_clock; + if (delta < delta_min) + delta_min = delta; + if (delta > delta_max) + delta_max = delta; + delta_cum += delta; + if (++count == DISP_FREQ) { + printf("timer: min=%lld us max=%lld us avg=%lld us avg_freq=%0.3f Hz\n", + muldiv64(delta_min, 1000000, ticks_per_sec), + muldiv64(delta_max, 1000000, ticks_per_sec), + muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec), + (double)ticks_per_sec / ((double)delta_cum / DISP_FREQ)); + count = 0; + delta_min = INT64_MAX; + delta_max = 0; + delta_cum = 0; + } + } + last_clock = ti; + } +#endif if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], @@ -892,7 +921,8 @@ static void init_timers(void) setitimer(ITIMER_REAL, &itv, NULL); /* use the RTC */ - sigaction(SIGIO, &act, NULL); + sigaction(SIGRTMIN, &act, NULL); + fcntl(rtc_fd, F_SETSIG, SIGRTMIN); fcntl(rtc_fd, F_SETFL, O_ASYNC); fcntl(rtc_fd, F_SETOWN, getpid()); } else { @@ -1184,10 +1214,12 @@ static void term_init(void) /* init terminal so that we can grab keys */ static struct termios oldtty; +static int old_fd0_flags; static void term_exit(void) { tcsetattr (0, TCSANOW, &oldtty); + fcntl(0, F_SETFL, old_fd0_flags); } static void term_init(void) @@ -1196,6 +1228,7 @@ static void term_init(void) tcgetattr (0, &tty); oldtty = tty; + old_fd0_flags = fcntl(0, F_GETFL); tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); @@ -1570,6 +1603,7 @@ int qemu_loadvm(const char *filename) static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) { + qemu_put_be32(f, dt->selector); qemu_put_be32(f, (uint32_t)dt->base); qemu_put_be32(f, dt->limit); qemu_put_be32(f, dt->flags); @@ -1577,6 +1611,7 @@ static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) static void cpu_get_seg(QEMUFile *f, SegmentCache *dt) { + dt->selector = qemu_get_be32(f); dt->base = (uint8_t *)qemu_get_be32(f); dt->limit = qemu_get_be32(f); dt->flags = qemu_get_be32(f); @@ -1650,7 +1685,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) uint32_t hflags; uint16_t fpus, fpuc, fptag; - if (version_id != 1) + if (version_id != 2) return -EINVAL; for(i = 0; i < 8; i++) qemu_get_be32s(f, &env->regs[i]); @@ -2683,7 +2718,7 @@ int main(int argc, char **argv) cpu_single_env = env; register_savevm("timer", 0, 1, timer_save, timer_load, env); - register_savevm("cpu", 0, 1, cpu_save, cpu_load, env); + register_savevm("cpu", 0, 2, cpu_save, cpu_load, env); register_savevm("ram", 0, 1, ram_save, ram_load, NULL); qemu_register_reset(main_cpu_reset, global_env); -- cgit v1.2.3 From 98087450722d974b814e19a056ea82699440c0a7 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 25 Jun 2004 14:54:19 +0000 Subject: BMDMA support - CDROM fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@971 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 572 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 546 insertions(+), 26 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index c352c63fc..9d5988575 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -299,6 +299,7 @@ typedef struct IDEState { int irq; openpic_t *openpic; PCIDevice *pci_dev; + struct BMDMAState *bmdma; int drive_serial; /* ide regs */ uint8_t feature; @@ -321,7 +322,11 @@ typedef struct IDEState { int elementary_transfer_size; int io_buffer_index; int lba; - /* transfer handling */ + int cd_sector_size; + int atapi_dma; /* true if dma is requested for the packet cmd */ + /* ATA DMA state */ + int io_buffer_size; + /* PIO transfer handling */ int req_nb_sectors; /* number of sectors per interrupt */ EndTransferFunc *end_transfer_func; uint8_t *data_ptr; @@ -329,6 +334,34 @@ typedef struct IDEState { uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; } IDEState; +#define BM_STATUS_DMAING 0x01 +#define BM_STATUS_ERROR 0x02 +#define BM_STATUS_INT 0x04 + +#define BM_CMD_START 0x01 +#define BM_CMD_READ 0x08 + +typedef int IDEDMAFunc(IDEState *s, + target_phys_addr_t phys_addr, + int transfer_size1); + +typedef struct BMDMAState { + uint8_t cmd; + uint8_t status; + uint32_t addr; + /* current transfer state */ + IDEState *ide_if; + IDEDMAFunc *dma_cb; +} BMDMAState; + +typedef struct PCIIDEState { + PCIDevice dev; + IDEState ide_if[4]; + BMDMAState bmdma[2]; +} PCIIDEState; + +static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb); + static void padstr(char *str, const char *src, int len) { int i, v; @@ -554,6 +587,59 @@ static void ide_sector_read(IDEState *s) } } +static int ide_read_dma_cb(IDEState *s, + target_phys_addr_t phys_addr, + int transfer_size1) +{ + int len, transfer_size, n; + int64_t sector_num; + + transfer_size = transfer_size1; + while (transfer_size > 0) { + len = s->io_buffer_size - s->io_buffer_index; + if (len <= 0) { + /* transfert next data */ + n = s->nsector; + if (n == 0) + break; + if (n > MAX_MULT_SECTORS) + n = MAX_MULT_SECTORS; + sector_num = ide_get_sector(s); + bdrv_read(s->bs, sector_num, s->io_buffer, n); + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; + len = s->io_buffer_size; + sector_num += n; + ide_set_sector(s, sector_num); + s->nsector -= n; + } + if (len > transfer_size) + len = transfer_size; + cpu_physical_memory_write(phys_addr, + s->io_buffer + s->io_buffer_index, len); + s->io_buffer_index += len; + transfer_size -= len; + phys_addr += len; + } + if (s->io_buffer_index >= s->io_buffer_size && s->nsector == 0) { + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); +#ifdef DEBUG_IDE_ATAPI + printf("dma status=0x%x\n", s->status); +#endif + return 0; + } + return transfer_size1 - transfer_size; +} + +static void ide_sector_read_dma(IDEState *s) +{ + s->status = READY_STAT | SEEK_STAT | DRQ_STAT; + s->io_buffer_index = 0; + s->io_buffer_size = 0; + ide_dma_start(s, ide_read_dma_cb); +} + static void ide_sector_write(IDEState *s) { int64_t sector_num; @@ -582,6 +668,62 @@ static void ide_sector_write(IDEState *s) ide_set_irq(s); } +static int ide_write_dma_cb(IDEState *s, + target_phys_addr_t phys_addr, + int transfer_size1) +{ + int len, transfer_size, n; + int64_t sector_num; + + transfer_size = transfer_size1; + for(;;) { + len = s->io_buffer_size - s->io_buffer_index; + if (len == 0) { + n = s->io_buffer_size >> 9; + sector_num = ide_get_sector(s); + bdrv_write(s->bs, sector_num, s->io_buffer, + s->io_buffer_size >> 9); + sector_num += n; + ide_set_sector(s, sector_num); + s->nsector -= n; + n = s->nsector; + if (n == 0) { + /* end of transfer */ + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + return 0; + } + if (n > MAX_MULT_SECTORS) + n = MAX_MULT_SECTORS; + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; + len = s->io_buffer_size; + } + if (transfer_size <= 0) + break; + if (len > transfer_size) + len = transfer_size; + cpu_physical_memory_read(phys_addr, + s->io_buffer + s->io_buffer_index, len); + s->io_buffer_index += len; + transfer_size -= len; + phys_addr += len; + } + return transfer_size1 - transfer_size; +} + +static void ide_sector_write_dma(IDEState *s) +{ + int n; + s->status = READY_STAT | SEEK_STAT | DRQ_STAT; + n = s->nsector; + if (n > MAX_MULT_SECTORS) + n = MAX_MULT_SECTORS; + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; + ide_dma_start(s, ide_write_dma_cb); +} + static void ide_atapi_cmd_ok(IDEState *s) { s->error = 0; @@ -627,6 +769,41 @@ static inline int ube32_to_cpu(const uint8_t *buf) return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; } +static void lba_to_msf(uint8_t *buf, int lba) +{ + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; +} + +static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, + int sector_size) +{ + switch(sector_size) { + case 2048: + bdrv_read(bs, (int64_t)lba << 2, buf, 4); + break; + case 2352: + /* sync bytes */ + buf[0] = 0x00; + memset(buf + 1, 0xff, 11); + buf += 12; + /* MSF */ + lba_to_msf(buf, lba); + buf[3] = 0x01; /* mode 1 data */ + buf += 4; + /* data */ + bdrv_read(bs, (int64_t)lba << 2, buf, 4); + buf += 2048; + /* ECC */ + memset(buf, 0, 288); + break; + default: + break; + } +} + /* The whole ATAPI transfer logic is handled in this function */ static void ide_atapi_cmd_reply_end(IDEState *s) { @@ -648,15 +825,15 @@ static void ide_atapi_cmd_reply_end(IDEState *s) #endif } else { /* see if a new sector must be read */ - if (s->lba != -1 && s->io_buffer_index >= 2048) { - bdrv_read(s->bs, (int64_t)s->lba << 2, s->io_buffer, 4); + if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { + cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); s->lba++; s->io_buffer_index = 0; } if (s->elementary_transfer_size > 0) { /* there are some data left to transmit in this elementary transfer */ - size = 2048 - s->io_buffer_index; + size = s->cd_sector_size - s->io_buffer_index; if (size > s->elementary_transfer_size) size = s->elementary_transfer_size; ide_transfer_start(s, s->io_buffer + s->io_buffer_index, @@ -685,8 +862,8 @@ static void ide_atapi_cmd_reply_end(IDEState *s) s->elementary_transfer_size = size; /* we cannot transmit more than one sector at a time */ if (s->lba != -1) { - if (size > (2048 - s->io_buffer_index)) - size = (2048 - s->io_buffer_index); + if (size > (s->cd_sector_size - s->io_buffer_index)) + size = (s->cd_sector_size - s->io_buffer_index); } ide_transfer_start(s, s->io_buffer + s->io_buffer_index, size, ide_atapi_cmd_reply_end); @@ -716,21 +893,88 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) } /* start a CD-CDROM read command */ -static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors) +static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, + int sector_size) { -#ifdef DEBUG_IDE_ATAPI - printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); -#endif s->lba = lba; - s->packet_transfer_size = nb_sectors * 2048; + s->packet_transfer_size = nb_sectors * sector_size; s->elementary_transfer_size = 0; - s->io_buffer_index = 2048; + s->io_buffer_index = sector_size; + s->cd_sector_size = sector_size; s->status = READY_STAT; ide_atapi_cmd_reply_end(s); } +/* ATAPI DMA support */ +static int ide_atapi_cmd_read_dma_cb(IDEState *s, + target_phys_addr_t phys_addr, + int transfer_size1) +{ + int len, transfer_size; + + transfer_size = transfer_size1; + while (transfer_size > 0) { + if (s->packet_transfer_size <= 0) + break; + len = s->cd_sector_size - s->io_buffer_index; + if (len <= 0) { + /* transfert next data */ + cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); + s->lba++; + s->io_buffer_index = 0; + len = s->cd_sector_size; + } + if (len > transfer_size) + len = transfer_size; + cpu_physical_memory_write(phys_addr, + s->io_buffer + s->io_buffer_index, len); + s->packet_transfer_size -= len; + s->io_buffer_index += len; + transfer_size -= len; + phys_addr += len; + } + if (s->packet_transfer_size <= 0) { + s->status = READY_STAT; + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; + ide_set_irq(s); +#ifdef DEBUG_IDE_ATAPI + printf("dma status=0x%x\n", s->status); +#endif + return 0; + } + return transfer_size1 - transfer_size; +} + +/* start a CD-CDROM read command with DMA */ +/* XXX: test if DMA is available */ +static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, + int sector_size) +{ + s->lba = lba; + s->packet_transfer_size = nb_sectors * sector_size; + s->io_buffer_index = sector_size; + s->cd_sector_size = sector_size; + + s->status = READY_STAT | DRQ_STAT; + ide_dma_start(s, ide_atapi_cmd_read_dma_cb); +} + +static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, + int sector_size) +{ +#ifdef DEBUG_IDE_ATAPI + printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); +#endif + if (s->atapi_dma) { + ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); + } else { + ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size); + } +} + /* same toc as bochs. Return -1 if error or the toc length */ +/* XXX: check this */ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) { uint8_t *q; @@ -739,8 +983,8 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) if (start_track > 1 && start_track != 0xaa) return -1; q = buf + 2; - *q++ = 1; - *q++ = 1; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ if (start_track <= 1) { *q++ = 0; /* reserved */ *q++ = 0x14; /* ADR, control */ @@ -765,9 +1009,8 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) nb_sectors = s->nb_sectors >> 2; if (msf) { *q++ = 0; /* reserved */ - *q++ = ((nb_sectors + 150) / 75) / 60; - *q++ = ((nb_sectors + 150) / 75) % 60; - *q++ = (nb_sectors + 150) % 75; + lba_to_msf(q, nb_sectors); + q += 3; } else { cpu_to_ube32(q, nb_sectors); q += 4; @@ -777,6 +1020,75 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) return len; } +/* mostly same info as PearPc */ +static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf, + int session_num) +{ + uint8_t *q; + int nb_sectors, len; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* first track */ + *q++ = 0x00; /* disk type */ + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa1; + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* last track */ + *q++ = 0x00; + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa2; /* lead-out */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + nb_sectors = s->nb_sectors >> 2; + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, nb_sectors); + q += 3; + } else { + cpu_to_ube32(q, nb_sectors); + q += 4; + } + + *q++ = 1; /* session number */ + *q++ = 0x14; /* ADR, control */ + *q++ = 0; /* track number */ + *q++ = 1; /* point */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + + len = q - buf; + cpu_to_ube16(buf, len - 2); + return len; +} + static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -921,7 +1233,48 @@ static void ide_atapi_cmd(IDEState *s) ASC_LOGICAL_BLOCK_OOR); break; } - ide_atapi_cmd_read(s, lba, nb_sectors); + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); + } + break; + case GPCMD_READ_CD: + { + int nb_sectors, lba, transfer_request; + + if (!bdrv_is_inserted(s->bs)) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; + lba = ube32_to_cpu(packet + 2); + if (nb_sectors == 0) { + ide_atapi_cmd_ok(s); + break; + } + if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + break; + } + transfer_request = packet[9]; + switch(transfer_request & 0xf8) { + case 0x00: + /* nothing */ + ide_atapi_cmd_ok(s); + break; + case 0x10: + /* normal read */ + ide_atapi_cmd_read(s, lba, nb_sectors, 2048); + break; + case 0xf8: + /* read all data */ + ide_atapi_cmd_read(s, lba, nb_sectors, 2352); + break; + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } } break; case GPCMD_SEEK: @@ -995,6 +1348,12 @@ static void ide_atapi_cmd(IDEState *s) buf[3] = 0x01; ide_atapi_cmd_reply(s, 12, max_len); break; + case 2: + len = cdrom_read_toc_raw(s, buf, msf, start_track); + if (len < 0) + goto error_cmd; + ide_atapi_cmd_reply(s, len, max_len); + break; default: error_cmd: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, @@ -1169,6 +1528,18 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) n = s->req_nb_sectors; ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); break; + case WIN_READDMA: + case WIN_READDMA_ONCE: + if (!s->bs) + goto abort_cmd; + ide_sector_read_dma(s); + break; + case WIN_WRITEDMA: + case WIN_WRITEDMA_ONCE: + if (!s->bs) + goto abort_cmd; + ide_sector_write_dma(s); + break; case WIN_READ_NATIVE_MAX: ide_set_sector(s, s->nb_sectors - 1); s->status = READY_STAT; @@ -1185,6 +1556,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* XXX: valid for CDROM ? */ switch(s->feature) { case 0x02: /* write cache enable */ + case 0x03: /* set transfer mode */ case 0x82: /* write cache disable */ case 0xaa: /* read look-ahead enable */ case 0x55: /* read look-ahead disable */ @@ -1216,9 +1588,10 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case WIN_PACKETCMD: if (!s->is_cdrom) goto abort_cmd; - /* DMA or overlapping commands not supported */ - if ((s->feature & 0x03) != 0) + /* overlapping commands not supported */ + if (s->feature & 0x02) goto abort_cmd; + s->atapi_dma = s->feature & 1; s->nsector = 1; ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, ide_atapi_cmd); @@ -1549,11 +1922,6 @@ void isa_ide_init(int iobase, int iobase2, int irq, /***********************************************************/ /* PCI IDE definitions */ -typedef struct PCIIDEState { - PCIDevice dev; - IDEState ide_if[4]; -} PCIIDEState; - static void ide_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { @@ -1578,6 +1946,155 @@ static void ide_map(PCIDevice *pci_dev, int region_num, } } +/* XXX: full callback usage to prepare non blocking I/Os support - + error handling */ +static void ide_dma_loop(BMDMAState *bm) +{ + struct { + uint32_t addr; + uint32_t size; + } prd; + target_phys_addr_t cur_addr; + int len, i, len1; + + cur_addr = bm->addr; + /* at most one page to avoid hanging if erroneous parameters */ + for(i = 0; i < 512; i++) { + cpu_physical_memory_read(cur_addr, (uint8_t *)&prd, 8); + prd.addr = le32_to_cpu(prd.addr); + prd.size = le32_to_cpu(prd.size); +#ifdef DEBUG_IDE + printf("ide: dma: prd: %08x: addr=0x%08x size=0x%08x\n", + (int)cur_addr, prd.addr, prd.size); +#endif + len = prd.size & 0xfffe; + if (len == 0) + len = 0x10000; + while (len > 0) { + len1 = bm->dma_cb(bm->ide_if, prd.addr, len); + if (len1 == 0) + goto the_end; + prd.addr += len1; + len -= len1; + } + /* end of transfer */ + if (prd.size & 0x80000000) + break; + cur_addr += 8; + } + /* end of transfer */ + the_end: + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + bm->dma_cb = NULL; + bm->ide_if = NULL; +} + +static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb) +{ + BMDMAState *bm = s->bmdma; + if(!bm) + return; + bm->ide_if = s; + bm->dma_cb = dma_cb; + if (bm->status & BM_STATUS_DMAING) { + ide_dma_loop(bm); + } +} + +static uint32_t bmdma_cmd_readb(void *opaque, uint32_t addr) +{ + BMDMAState *bm = opaque; + uint32_t val; + val = bm->cmd; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + return val; +} + +static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + BMDMAState *bm = opaque; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + if (!(val & BM_CMD_START)) { + /* XXX: do it better */ + bm->status &= ~BM_STATUS_DMAING; + bm->cmd = val & 0x09; + } else { + bm->status |= BM_STATUS_DMAING; + bm->cmd = val & 0x09; + /* start dma transfer if possible */ + if (bm->dma_cb) + ide_dma_loop(bm); + } +} + +static uint32_t bmdma_status_readb(void *opaque, uint32_t addr) +{ + BMDMAState *bm = opaque; + uint32_t val; + val = bm->status; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + return val; +} + +static void bmdma_status_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + BMDMAState *bm = opaque; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); +} + +static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr) +{ + BMDMAState *bm = opaque; + uint32_t val; + val = bm->addr; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + return val; +} + +static void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val) +{ + BMDMAState *bm = opaque; +#ifdef DEBUG_IDE + printf("%s: 0x%08x\n", __func__, val); +#endif + bm->addr = val & ~3; +} + +static void bmdma_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIIDEState *d = (PCIIDEState *)pci_dev; + int i; + + for(i = 0;i < 2; i++) { + BMDMAState *bm = &d->bmdma[i]; + d->ide_if[2 * i].bmdma = bm; + d->ide_if[2 * i + 1].bmdma = bm; + + register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); + register_ioport_read(addr, 1, 1, bmdma_cmd_readb, bm); + + register_ioport_write(addr + 2, 1, 1, bmdma_status_writeb, bm); + register_ioport_read(addr + 2, 1, 1, bmdma_status_readb, bm); + + register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); + register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); + addr += 8; + } +} + /* hd_table must contain 4 block drivers */ void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table) { @@ -1610,6 +2127,8 @@ void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table) PCI_ADDRESS_SPACE_IO, ide_map); pci_register_io_region((PCIDevice *)d, 3, 0x4, PCI_ADDRESS_SPACE_IO, ide_map); + pci_register_io_region((PCIDevice *)d, 4, 0x10, + PCI_ADDRESS_SPACE_IO, bmdma_map); pci_conf[0x3d] = 0x01; // interrupt on pin 1 @@ -1640,7 +2159,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage pci_conf[0x0e] = 0x00; // header_type - /* XXX: must add BMDMA support to be fully compliant */ + pci_register_io_region((PCIDevice *)d, 4, 0x10, + PCI_ADDRESS_SPACE_IO, bmdma_map); ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]); ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]); -- cgit v1.2.3 From d187d4b2187a485c6b5819cbb6f5dbef95e2e331 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 25 Jun 2004 14:55:10 +0000 Subject: configure BMDMA git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@972 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci.c b/hw/pci.c index 919b9028f..a6f452f42 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1402,9 +1402,9 @@ static void pci_bios_init_device(PCIDevice *d) case 0x0101: if (vendor_id == 0x8086 && device_id == 0x7010) { /* PIIX3 IDE */ - pci_config_writew(d, PCI_COMMAND, PCI_COMMAND_IO); pci_config_writew(d, 0x40, 0x8000); // enable IDE0 pci_config_writew(d, 0x42, 0x8000); // enable IDE1 + goto default_map; } else { /* IDE: we map it as in ISA mode */ pci_set_io_region_addr(d, 0, 0x1f0); -- cgit v1.2.3 From acf5feac80a3edb2d6cfaee40ae53ac90f789578 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 25 Jun 2004 14:58:58 +0000 Subject: hlt instruction fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@973 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-i386/op.c b/target-i386/op.c index f7276ca67..b9aef6aae 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -433,6 +433,7 @@ void OPPROTO op_jmp_im(void) void OPPROTO op_hlt(void) { + env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ env->exception_index = EXCP_HLT; cpu_loop_exit(); } -- cgit v1.2.3 From 7f5d44e0ff1343f990567417a7f152a1588522d1 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 25 Jun 2004 15:02:13 +0000 Subject: new Cirrus VGA BIOS from the LGPL'ed VGA BIOS project including VESA support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@974 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 8 ++------ pc-bios/vgabios-cirrus.bin | Bin 26784 -> 30849 bytes 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index b5e9bf709..d81dd767b 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -1,9 +1,5 @@ - The PC BIOS comes from the Bochs project (http://bochs.sourceforge.net/). A patch from bios.diff was applied. -- The VGA BIOS comes from the LGPL VGA bios project - (http://www.nongnu.org/vgabios/). - -- The Cirrus VGA BIOS comes from the LGPL VGA bios project with - patches from http://ebisa.hp.infoseek.co.jp/bochs/index.shtml. - \ No newline at end of file +- The VGA BIOS and the Cirrus VGA BIOS come from the LGPL VGA bios + project (http://www.nongnu.org/vgabios/). diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index f393404b6..3d3575762 100644 Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ -- cgit v1.2.3 From a1968d719648b7406076f921ca6410c805b8815e Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 25 Jun 2004 17:06:27 +0000 Subject: RT signal may not be a good idea git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@975 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 2c3c72dca..5f1322ed0 100644 --- a/vl.c +++ b/vl.c @@ -921,8 +921,7 @@ static void init_timers(void) setitimer(ITIMER_REAL, &itv, NULL); /* use the RTC */ - sigaction(SIGRTMIN, &act, NULL); - fcntl(rtc_fd, F_SETSIG, SIGRTMIN); + sigaction(SIGIO, &act, NULL); fcntl(rtc_fd, F_SETFL, O_ASYNC); fcntl(rtc_fd, F_SETOWN, getpid()); } else { -- cgit v1.2.3 From 9da98861213c8e5e675a8544019dd1c763a20922 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jun 2004 15:53:17 +0000 Subject: fixed case where ram < 16 MB git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@976 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index f5783250b..11b282792 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -136,7 +136,10 @@ static void cmos_init(int ram_size, int boot_device) rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); - val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); + if (ram_size > (16 * 1024 * 1024)) + val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); + else + val = 0; if (val > 65535) val = 65535; rtc_set_memory(s, 0x34, val); -- cgit v1.2.3 From e6eccb38ebf52bc87c957ff128dc60ea81d3e2d4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jun 2004 16:12:26 +0000 Subject: dac write index register is r/w (Volker Ruppert) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@977 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/vga.c b/hw/vga.c index 1a559750a..2a0a9c3d0 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -190,6 +190,9 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) case 0x3c7: val = s->dac_state; break; + case 0x3c8: + val = s->dac_write_index; + break; case 0x3c9: val = s->palette[s->dac_read_index * 3 + s->dac_sub_index]; if (++s->dac_sub_index == 3) { -- cgit v1.2.3 From ae184e4ab773aaef59226412ddf602a790170dc3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Jun 2004 16:13:19 +0000 Subject: dac write index register is r/w - CR1D access fix (Volker Ruppert) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@978 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 2707f9386..8ec63d3c2 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -1492,6 +1492,7 @@ cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value) case 0x1a: // Miscellaneous Control case 0x1b: // Extended Display Control case 0x1c: // Sync Adjust and Genlock + case 0x1d: // Overlay Extended Control s->cr[reg_index] = reg_value; #ifdef DEBUG_CIRRUS printf("cirrus: handled outport cr_index %02x, cr_value %02x\n", @@ -1503,7 +1504,6 @@ cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value) case 0x26: // Attribute Controller Index Readback (R) case 0x27: // Part ID (R) break; - case 0x1d: // Overlay Extended Control case 0x25: // Part Status default: #ifdef DEBUG_CIRRUS @@ -2440,7 +2440,11 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) case 0x3c7: val = s->dac_state; break; - case 0x3c9: + case 0x3c8: + val = s->dac_write_index; + s->cirrus_hidden_dac_lockindex = 0; + break; + case 0x3c9: if (cirrus_hook_read_palette(s, &val)) break; val = s->palette[s->dac_read_index * 3 + s->dac_sub_index]; -- cgit v1.2.3 From 1d43a717730346de2c664c0eccf0592eb4ba2cd8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jul 2004 21:18:42 +0000 Subject: forgot fclose() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@979 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slirp/slirp.c b/slirp/slirp.c index f9c4f159e..ad10516a0 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -65,6 +65,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) lprint("%s", inet_ntoa(tmp_addr)); } } + fclose(f); if (!found) return -1; return 0; @@ -75,7 +76,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) void slirp_init(void) { // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); - + link_up = 1; if_init(); -- cgit v1.2.3 From 83fb7adf6c653a0285a89d51b746cb642d2859cf Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jul 2004 21:25:26 +0000 Subject: Darwin patch (initial patch by Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@980 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 +++ Makefile.target | 7 ++++++ configure | 17 +++++++++++++-- cpu-all.h | 10 ++++----- cpu-exec.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++------ dyngen-exec.h | 8 ++++++- exec.c | 42 ++++++++++++++++++------------------ linux-user/elfload.c | 32 ++++++++++++++++++---------- linux-user/main.c | 15 ++++++++----- linux-user/mmap.c | 56 ++++++++++++++++++++++++------------------------ oss.c | 2 +- target-i386/exec.h | 8 +++---- target-i386/op.c | 19 ----------------- vl.c | 12 ++++++++--- 14 files changed, 185 insertions(+), 106 deletions(-) diff --git a/Makefile b/Makefile index 4d76abc94..e27d1fe3b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ include config-host.mak CFLAGS=-Wall -O2 -g +ifdef CONFIG_DARWIN +CFLAGS+= -mdynamic-no-pic +endif ifdef CONFIG_WIN32 CFLAGS+=-fpack-struct endif diff --git a/Makefile.target b/Makefile.target index 1134256c8..3303b0ce5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -100,6 +100,7 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/amd64.ld endif ifeq ($(ARCH),ppc) +CFLAGS+= -D__powerpc__ OP_CFLAGS=$(CFLAGS) LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld endif @@ -152,6 +153,10 @@ ifeq ($(HAVE_GCC3_OPTIONS),yes) OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls endif +ifeq ($(CONFIG_DARWIN),yes) +OP_CFLAGS+= -mdynamic-no-pic +endif + ######################################################### DEFINES+=-D_GNU_SOURCE @@ -267,9 +272,11 @@ endif ifndef CONFIG_SOFTMMU VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld endif +ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 VL_LIBS=-lutil endif +endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS) diff --git a/configure b/configure index 8e0cff852..d93d78ccc 100755 --- a/configure +++ b/configure @@ -88,12 +88,18 @@ bsd="yes" OpenBSD) bsd="yes" ;; +Darwin) +bsd="yes" +darwin="yes" +;; *) ;; esac if [ "$bsd" = "yes" ] ; then - make="gmake" - target_list="i386-softmmu" + if [ ! "$darwin" = "yes" ] ; then + make="gmake" + fi + target_list="i386-softmmu ppc-softmmu" fi # find source path @@ -391,6 +397,10 @@ if test "$mingw32" = "yes" ; then elif test -f "/usr/include/byteswap.h" ; then echo "#define HAVE_BYTESWAP_H 1" >> $config_h fi +if test "$darwin" = "yes" ; then + echo "CONFIG_DARWIN=yes" >> $config_mak + echo "#define CONFIG_DARWIN 1" >> $config_h +fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak echo "#define CONFIG_GDBSTUB 1" >> $config_h @@ -417,10 +427,13 @@ echo "\"" >> $config_h echo "SRC_PATH=$source_path" >> $config_mak echo "TARGET_DIRS=$target_list" >> $config_mak +# XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "#define O_LARGEFILE 0" >> $config_h echo "#define lseek64 lseek" >> $config_h + echo "#define mkstemp64 mkstemp" >> $config_h echo "#define ftruncate64 ftruncate" >> $config_h + echo "#define off64_t off_t" >> $config_h echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h echo "#define _BSD 1" >> $config_h fi diff --git a/cpu-all.h b/cpu-all.h index 12e6d3ca2..04b5be386 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -538,12 +538,12 @@ static inline void stfq_raw(void *ptr, double v) #define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1) #define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK) -extern unsigned long real_host_page_size; -extern unsigned long host_page_bits; -extern unsigned long host_page_size; -extern unsigned long host_page_mask; +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) + host_page_size - 1) & 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 diff --git a/cpu-exec.c b/cpu-exec.c index aa713c9a6..0f317574f 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -852,24 +852,72 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, &uc->uc_sigmask, puc); } -#elif defined(__powerpc) +#elif defined(__powerpc__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +/*********************************************************************** + * 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 +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, siginfo *info, void *puc) { struct ucontext *uc = puc; - struct pt_regs *regs = uc->uc_mcontext.regs; unsigned long pc; int is_write; - pc = regs->nip; + pc = IAR_sig(uc); is_write = 0; #if 0 /* ppc 4xx case */ - if (regs->dsisr & 0x00800000) + if (DSISR_sig(uc) & 0x00800000) is_write = 1; #else - if (regs->trap != 0x400 && (regs->dsisr & 0x02000000)) + if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) is_write = 1; #endif return handle_cpu_signal(pc, (unsigned long)info->si_addr, diff --git a/dyngen-exec.h b/dyngen-exec.h index 2d5209bc8..907771e4a 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -59,8 +59,14 @@ extern int fprintf(FILE *, const char *, ...); extern int printf(const char *, ...); #undef NULL #define NULL 0 -#ifdef _BSD +#if defined(_BSD) && !defined(__APPLE__) #include + +#define FE_TONEAREST FP_RN +#define FE_DOWNWARD FP_RM +#define FE_UPWARD FP_RP +#define FE_TOWARDZERO FP_RZ +#define fesetround(x) fpsetround(x) #else #include #endif diff --git a/exec.c b/exec.c index 9d1306d54..9c86765f7 100644 --- a/exec.c +++ b/exec.c @@ -100,10 +100,10 @@ typedef struct VirtPageDesc { static void io_mem_init(void); -unsigned long real_host_page_size; -unsigned long host_page_bits; -unsigned long host_page_size; -unsigned long host_page_mask; +unsigned long qemu_real_host_page_size; +unsigned long qemu_host_page_bits; +unsigned long qemu_host_page_size; +unsigned long qemu_host_page_mask; /* XXX: for system emulation, it could just be an array */ static PageDesc *l1_map[L1_SIZE]; @@ -127,21 +127,21 @@ int loglevel; static void page_init(void) { - /* NOTE: we can always suppose that host_page_size >= + /* NOTE: we can always suppose that qemu_host_page_size >= TARGET_PAGE_SIZE */ #ifdef _WIN32 - real_host_page_size = 4096; + qemu_real_host_page_size = 4096; #else - real_host_page_size = getpagesize(); + qemu_real_host_page_size = getpagesize(); #endif - if (host_page_size == 0) - host_page_size = real_host_page_size; - if (host_page_size < TARGET_PAGE_SIZE) - host_page_size = TARGET_PAGE_SIZE; - host_page_bits = 0; - while ((1 << host_page_bits) < host_page_size) - host_page_bits++; - host_page_mask = ~(host_page_size - 1); + if (qemu_host_page_size == 0) + qemu_host_page_size = qemu_real_host_page_size; + if (qemu_host_page_size < TARGET_PAGE_SIZE) + qemu_host_page_size = TARGET_PAGE_SIZE; + qemu_host_page_bits = 0; + while ((1 << qemu_host_page_bits) < qemu_host_page_size) + qemu_host_page_bits++; + qemu_host_page_mask = ~(qemu_host_page_size - 1); #if !defined(CONFIG_USER_ONLY) virt_valid_tag = 1; #endif @@ -831,12 +831,12 @@ static inline void tb_alloc_page(TranslationBlock *tb, /* force the host page as non writable (writes will have a page fault + mprotect overhead) */ - host_start = page_addr & host_page_mask; - host_end = host_start + host_page_size; + host_start = page_addr & qemu_host_page_mask; + host_end = host_start + qemu_host_page_size; prot = 0; for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) prot |= page_get_flags(addr); - mprotect((void *)host_start, host_page_size, + mprotect((void *)host_start, qemu_host_page_size, (prot & PAGE_BITS) & ~PAGE_WRITE); #ifdef DEBUG_TB_INVALIDATE printf("protecting code page: 0x%08lx\n", @@ -1737,12 +1737,12 @@ int page_unprotect(unsigned long address, unsigned long pc, void *puc) PageDesc *p, *p1; unsigned long host_start, host_end, addr; - host_start = address & host_page_mask; + host_start = address & qemu_host_page_mask; page_index = host_start >> TARGET_PAGE_BITS; p1 = page_find(page_index); if (!p1) return 0; - host_end = host_start + host_page_size; + host_end = host_start + qemu_host_page_size; p = p1; prot = 0; for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) { @@ -1754,7 +1754,7 @@ int page_unprotect(unsigned long address, unsigned long pc, void *puc) if (prot & PAGE_WRITE_ORG) { pindex = (address - host_start) >> TARGET_PAGE_BITS; if (!(p1[pindex].flags & PAGE_WRITE)) { - mprotect((void *)host_start, host_page_size, + mprotect((void *)host_start, qemu_host_page_size, (prot & PAGE_BITS) | PAGE_WRITE); p1[pindex].flags |= PAGE_WRITE; /* and since the content will be modified, we must invalidate diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 21261e2c0..cfc425697 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -13,6 +13,16 @@ #include "qemu.h" #include "disas.h" +/* this flag is uneffective under linux too, should be deleted */ +#ifndef MAP_DENYWRITE +#define MAP_DENYWRITE 0 +#endif + +/* should probably go in elf.h */ +#ifndef ELIBBAD +#define ELIBBAD 80 +#endif + #ifdef TARGET_I386 #define ELF_START_MMAP 0x80000000 @@ -332,7 +342,7 @@ static void * get_free_page(void) /* User-space version of kernel get_free_page. Returns a page-aligned * page-sized chunk of memory. */ - retval = (void *)target_mmap(0, host_page_size, PROT_READ|PROT_WRITE, + retval = (void *)target_mmap(0, qemu_host_page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if((long)retval == -1) { @@ -346,7 +356,7 @@ static void * get_free_page(void) static void free_page(void * pageaddr) { - target_munmap((unsigned long)pageaddr, host_page_size); + target_munmap((unsigned long)pageaddr, qemu_host_page_size); } /* @@ -502,7 +512,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; error = target_mmap(0, - size + host_page_size, + size + qemu_host_page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -511,7 +521,7 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, exit(-1); } /* we reserve one extra page at the top of the stack as guard */ - target_mprotect(error + size, host_page_size, PROT_NONE); + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; p += stack_base; @@ -562,10 +572,10 @@ static void padzero(unsigned long elf_bss) of the file may not be mapped. A better fix would be to patch target_mmap(), but it is more complicated as the file size must be known */ - if (real_host_page_size < host_page_size) { + if (qemu_real_host_page_size < qemu_host_page_size) { unsigned long end_addr, end_addr1; - end_addr1 = (elf_bss + real_host_page_size - 1) & - ~(real_host_page_size - 1); + end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & + ~(qemu_real_host_page_size - 1); end_addr = HOST_PAGE_ALIGN(elf_bss); if (end_addr1 < end_addr) { mmap((void *)end_addr1, end_addr - end_addr1, @@ -574,9 +584,9 @@ static void padzero(unsigned long elf_bss) } } - nbyte = elf_bss & (host_page_size-1); + nbyte = elf_bss & (qemu_host_page_size-1); if (nbyte) { - nbyte = host_page_size - nbyte; + nbyte = qemu_host_page_size - nbyte; fpnt = (char *) elf_bss; do { *fpnt++ = 0; @@ -811,7 +821,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, * bss page. */ padzero(elf_bss); - elf_bss = TARGET_ELF_PAGESTART(elf_bss + host_page_size - 1); /* What we have mapped so far */ + elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ if (last_bss > elf_bss) { @@ -1252,7 +1262,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ - mapped_addr = target_mmap(0, host_page_size, PROT_READ | PROT_EXEC, + mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, -1, 0); } diff --git a/linux-user/main.c b/linux-user/main.c index 2275b01f9..00afaafa7 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -28,6 +28,11 @@ #define DEBUG_LOGFILE "/tmp/qemu.log" +#ifdef __APPLE__ +#include +# define environ (*_NSGetEnviron()) +#endif + static const char *interp_prefix = CONFIG_QEMU_PREFIX; #if defined(__i386__) && !defined(CONFIG_STATIC) @@ -977,9 +982,9 @@ int main(int argc, char **argv) } else if (!strcmp(r, "L")) { interp_prefix = argv[optind++]; } else if (!strcmp(r, "p")) { - host_page_size = atoi(argv[optind++]); - if (host_page_size == 0 || - (host_page_size & (host_page_size - 1)) != 0) { + qemu_host_page_size = atoi(argv[optind++]); + if (qemu_host_page_size == 0 || + (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { fprintf(stderr, "page size must be a power of two\n"); exit(1); } @@ -1006,8 +1011,8 @@ int main(int argc, char **argv) /* Scan interp_prefix dir for replacement files. */ init_paths(interp_prefix); - /* NOTE: we need to init the CPU at this stage to get the - host_page_size */ + /* NOTE: we need to init the CPU at this stage to get + qemu_host_page_size */ env = cpu_init(); if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 312af9b1d..81233035d 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -53,7 +53,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) if (len == 0) return 0; - host_start = start & host_page_mask; + host_start = start & qemu_host_page_mask; host_end = HOST_PAGE_ALIGN(end); if (start > host_start) { /* handle host page containing start */ @@ -61,27 +61,27 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } - if (host_end == host_start + host_page_size) { + if (host_end == host_start + qemu_host_page_size) { for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } end = host_end; } - ret = mprotect((void *)host_start, host_page_size, prot1 & PAGE_BITS); + ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) return ret; - host_start += host_page_size; + host_start += qemu_host_page_size; } if (end < host_end) { prot1 = prot; for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } - ret = mprotect((void *)(host_end - host_page_size), host_page_size, + ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) return ret; - host_end -= host_page_size; + host_end -= qemu_host_page_size; } /* handle the pages in the middle */ @@ -102,7 +102,7 @@ int mmap_frag(unsigned long host_start, unsigned long host_end, ret, addr; int prot1, prot_new; - host_end = host_start + host_page_size; + host_end = host_start + qemu_host_page_size; /* get the protection of the target pages outside the mapping */ prot1 = 0; @@ -113,7 +113,7 @@ int mmap_frag(unsigned long host_start, if (prot1 == 0) { /* no page was there, so we allocate one */ - ret = (long)mmap((void *)host_start, host_page_size, prot, + ret = (long)mmap((void *)host_start, qemu_host_page_size, prot, flags | MAP_ANONYMOUS, -1, 0); if (ret == -1) return ret; @@ -130,18 +130,18 @@ int mmap_frag(unsigned long host_start, /* adjust protection to be able to read */ if (!(prot1 & PROT_WRITE)) - mprotect((void *)host_start, host_page_size, prot1 | PROT_WRITE); + mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE); /* read the corresponding file data */ pread(fd, (void *)start, end - start, offset); /* put final protection */ if (prot_new != (prot1 | PROT_WRITE)) - mprotect((void *)host_start, host_page_size, prot_new); + mprotect((void *)host_start, qemu_host_page_size, prot_new); } else { /* just update the protection */ if (prot_new != prot1) { - mprotect((void *)host_start, host_page_size, prot_new); + mprotect((void *)host_start, qemu_host_page_size, prot_new); } } return 0; @@ -188,7 +188,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, len = TARGET_PAGE_ALIGN(len); if (len == 0) return start; - host_start = start & host_page_mask; + host_start = start & qemu_host_page_mask; if (!(flags & MAP_FIXED)) { #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) @@ -198,10 +198,10 @@ long target_mmap(unsigned long start, unsigned long len, int prot, last_start += HOST_PAGE_ALIGN(len); } #endif - if (host_page_size != real_host_page_size) { + if (qemu_host_page_size != qemu_real_host_page_size) { /* NOTE: this code is only for debugging with '-p' option */ /* reserve a memory area */ - host_len = HOST_PAGE_ALIGN(len) + host_page_size - TARGET_PAGE_SIZE; + host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; host_start = (long)mmap((void *)host_start, host_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (host_start == -1) @@ -217,7 +217,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, flags |= MAP_FIXED; } else { /* if not fixed, no need to do anything */ - host_offset = offset & host_page_mask; + host_offset = offset & qemu_host_page_mask; host_len = len + offset - host_offset; start = (long)mmap((void *)host_start, host_len, prot, flags, fd, host_offset); @@ -238,7 +238,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, /* worst case: we cannot map the file because the offset is not aligned, so we read it */ if (!(flags & MAP_ANONYMOUS) && - (offset & ~host_page_mask) != (start & ~host_page_mask)) { + (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { /* msync() won't work here, so we return an error if write is possible while it is a shared mapping */ if ((flags & MAP_TYPE) == MAP_SHARED && @@ -260,7 +260,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, /* handle the start of the mapping */ if (start > host_start) { - if (host_end == host_start + host_page_size) { + if (host_end == host_start + qemu_host_page_size) { /* one single host page */ ret = mmap_frag(host_start, start, end, prot, flags, fd, offset); @@ -268,21 +268,21 @@ long target_mmap(unsigned long start, unsigned long len, int prot, return ret; goto the_end1; } - ret = mmap_frag(host_start, start, host_start + host_page_size, + ret = mmap_frag(host_start, start, host_start + qemu_host_page_size, prot, flags, fd, offset); if (ret == -1) return ret; - host_start += host_page_size; + host_start += qemu_host_page_size; } /* handle the end of the mapping */ if (end < host_end) { - ret = mmap_frag(host_end - host_page_size, - host_end - host_page_size, host_end, + ret = mmap_frag(host_end - qemu_host_page_size, + host_end - qemu_host_page_size, host_end, prot, flags, fd, - offset + host_end - host_page_size - start); + offset + host_end - qemu_host_page_size - start); if (ret == -1) return ret; - host_end -= host_page_size; + host_end -= qemu_host_page_size; } /* map the middle (easier) */ @@ -322,7 +322,7 @@ int target_munmap(unsigned long start, unsigned long len) if (len == 0) return -EINVAL; end = start + len; - host_start = start & host_page_mask; + host_start = start & qemu_host_page_mask; host_end = HOST_PAGE_ALIGN(end); if (start > host_start) { @@ -331,14 +331,14 @@ int target_munmap(unsigned long start, unsigned long len) for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } - if (host_end == host_start + host_page_size) { + if (host_end == host_start + qemu_host_page_size) { for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } end = host_end; } if (prot != 0) - host_start += host_page_size; + host_start += qemu_host_page_size; } if (end < host_end) { prot = 0; @@ -346,7 +346,7 @@ int target_munmap(unsigned long start, unsigned long len) prot |= page_get_flags(addr); } if (prot != 0) - host_end -= host_page_size; + host_end -= qemu_host_page_size; } /* unmap what we can */ @@ -391,7 +391,7 @@ int target_msync(unsigned long start, unsigned long len, int flags) if (end == start) return 0; - start &= host_page_mask; + start &= qemu_host_page_mask; return msync((void *)start, end - start, flags); } diff --git a/oss.c b/oss.c index f0a74bde0..de655ce9b 100644 --- a/oss.c +++ b/oss.c @@ -23,7 +23,7 @@ */ #include "vl.h" -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(__APPLE__) #include #include #include diff --git a/target-i386/exec.h b/target-i386/exec.h index 4410069a3..680e580b7 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -498,7 +498,7 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) #define FPUC_EM 0x3f -const CPU86_LDouble f15rk[7]; +extern const CPU86_LDouble f15rk[7]; void helper_fldt_ST0_A0(void); void helper_fstt_ST0_A0(void); @@ -528,9 +528,9 @@ void helper_frstor(uint8_t *ptr, int data32); void restore_native_fp_state(CPUState *env); void save_native_fp_state(CPUState *env); -const uint8_t parity_table[256]; -const uint8_t rclw_table[32]; -const uint8_t rclb_table[32]; +extern const uint8_t parity_table[256]; +extern const uint8_t rclw_table[32]; +extern const uint8_t rclb_table[32]; static inline uint32_t compute_eflags(void) { diff --git a/target-i386/op.c b/target-i386/op.c index b9aef6aae..2438499ec 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1955,24 +1955,6 @@ void OPPROTO op_fldcw_A0(void) int rnd_type; env->fpuc = lduw((void *)A0); /* set rounding mode */ -#ifdef _BSD - switch(env->fpuc & RC_MASK) { - default: - case RC_NEAR: - rnd_type = FP_RN; - break; - case RC_DOWN: - rnd_type = FP_RM; - break; - case RC_UP: - rnd_type = FP_RP; - break; - case RC_CHOP: - rnd_type = FP_RZ; - break; - } - fpsetround(rnd_type); -#else switch(env->fpuc & RC_MASK) { default: case RC_NEAR: @@ -1989,7 +1971,6 @@ void OPPROTO op_fldcw_A0(void) break; } fesetround(rnd_type); -#endif } void OPPROTO op_fclex(void) diff --git a/vl.c b/vl.c index 5f1322ed0..eebc6e6f5 100644 --- a/vl.c +++ b/vl.c @@ -40,7 +40,9 @@ #include #ifdef _BSD #include +#ifndef __APPLE__ #include +#endif #else #include #include @@ -63,6 +65,7 @@ #endif #ifdef CONFIG_SDL +#include #if defined(__linux__) /* SDL use the pthreads and they modify sigaction. We don't want that. */ @@ -909,6 +912,7 @@ static void init_timers(void) the emulated kernel requested a too high timer frequency */ getitimer(ITIMER_REAL, &itv); +#if defined(__linux__) if (itv.it_interval.tv_usec > 1000) { /* try to use /dev/rtc to have a faster timer */ if (start_rtc_timer() < 0) @@ -924,7 +928,9 @@ static void init_timers(void) sigaction(SIGIO, &act, NULL); fcntl(rtc_fd, F_SETFL, O_ASYNC); fcntl(rtc_fd, F_SETOWN, getpid()); - } else { + } else +#endif /* defined(__linux__) */ + { use_itimer: pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / 1000000; @@ -2622,8 +2628,8 @@ int main(int argc, char **argv) #ifdef CONFIG_SOFTMMU #ifdef _BSD - /* mallocs are always aligned on BSD. */ - phys_ram_base = malloc(phys_ram_size); + /* mallocs are always aligned on BSD. valloc is better for correctness */ + phys_ram_base = valloc(phys_ram_size); #else phys_ram_base = memalign(TARGET_PAGE_SIZE, phys_ram_size); #endif -- cgit v1.2.3 From d549f7d98f2d4764064fff66926bcd01eb1b71a0 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jul 2004 21:47:44 +0000 Subject: Darwin patch (initial patch by Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@981 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/exec-all.h b/exec-all.h index 8167d1a27..65d26fdfb 100644 --- a/exec-all.h +++ b/exec-all.h @@ -303,16 +303,29 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif +#if defined(_WIN32) +#define ASM_DATA_SECTION ".section \".data\"\n" +#define ASM_PREVIOUS_SECTION ".section .text\n" +#elif defined(__APPLE__) +#define ASM_DATA_SECTION ".data\n" +#define ASM_PREVIOUS_SECTION ".text\n" +#define ASM_NAME(x) "_" #x +#else +#define ASM_DATA_SECTION ".section \".data\"\n" +#define ASM_PREVIOUS_SECTION ".previous\n" +#define ASM_NAME(x) stringify(x) +#endif + #if defined(__powerpc__) /* we patch the jump instruction directly */ #define JUMP_TB(opname, tbparam, n, eip)\ do {\ - asm volatile (".section \".data\"\n"\ - "__op_label" #n "." stringify(opname) ":\n"\ + asm volatile (ASM_DATA_SECTION\ + ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\ ".long 1f\n"\ - ".previous\n"\ - "b __op_jmp" #n "\n"\ + ASM_PREVIOUS_SECTION \ + "b " ASM_NAME(__op_jmp) #n "\n"\ "1:\n");\ T0 = (long)(tbparam) + (n);\ EIP = eip;\ @@ -321,25 +334,19 @@ do {\ #define JUMP_TB2(opname, tbparam, n)\ do {\ - asm volatile ("b __op_jmp" #n "\n");\ + asm volatile ("b " ASM_NAME(__op_jmp) #n "\n");\ } while (0) #elif defined(__i386__) && defined(USE_DIRECT_JUMP) -#ifdef _WIN32 -#define ASM_PREVIOUS_SECTION ".section .text\n" -#else -#define ASM_PREVIOUS_SECTION ".previous\n" -#endif - /* we patch the jump instruction directly */ #define JUMP_TB(opname, tbparam, n, eip)\ do {\ asm volatile (".section .data\n"\ - "__op_label" #n "." stringify(opname) ":\n"\ + ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\ ".long 1f\n"\ ASM_PREVIOUS_SECTION \ - "jmp __op_jmp" #n "\n"\ + "jmp " ASM_NAME(__op_jmp) #n "\n"\ "1:\n");\ T0 = (long)(tbparam) + (n);\ EIP = eip;\ @@ -348,7 +355,7 @@ do {\ #define JUMP_TB2(opname, tbparam, n)\ do {\ - asm volatile ("jmp __op_jmp" #n "\n");\ + asm volatile ("jmp " ASM_NAME(__op_jmp) #n "\n");\ } while (0) #else -- cgit v1.2.3 From e58d12ed5b22ca78b46cc4e36392f4e763008eb9 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Jul 2004 22:13:07 +0000 Subject: Darwin patch git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@982 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 146 insertions(+), 16 deletions(-) diff --git a/sdl.c b/sdl.c index 981922102..e4e6bc43a 100644 --- a/sdl.c +++ b/sdl.c @@ -29,6 +29,10 @@ #include #endif +#if defined(__APPLE__) +#define CONFIG_SDL_GENERIC_KBD +#endif + static SDL_Surface *screen; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static int last_vm_running; @@ -63,6 +67,126 @@ static void sdl_resize(DisplayState *ds, int w, int h) ds->depth = screen->format->BitsPerPixel; } +#ifdef CONFIG_SDL_GENERIC_KBD + +/* XXX: use keymap tables defined in the VNC patch because the + following code suppose you have a US keyboard. */ + +static const uint8_t scancodes[SDLK_LAST] = { + [SDLK_ESCAPE] = 0x01, + [SDLK_1] = 0x02, + [SDLK_2] = 0x03, + [SDLK_3] = 0x04, + [SDLK_4] = 0x05, + [SDLK_5] = 0x06, + [SDLK_6] = 0x07, + [SDLK_7] = 0x08, + [SDLK_8] = 0x09, + [SDLK_9] = 0x0a, + [SDLK_0] = 0x0b, + [SDLK_MINUS] = 0x0c, + [SDLK_EQUALS] = 0x0d, + [SDLK_BACKSPACE] = 0x0e, + [SDLK_TAB] = 0x0f, + [SDLK_q] = 0x10, + [SDLK_w] = 0x11, + [SDLK_e] = 0x12, + [SDLK_r] = 0x13, + [SDLK_t] = 0x14, + [SDLK_y] = 0x15, + [SDLK_u] = 0x16, + [SDLK_i] = 0x17, + [SDLK_o] = 0x18, + [SDLK_p] = 0x19, + [SDLK_LEFTBRACKET] = 0x1a, + [SDLK_RIGHTBRACKET] = 0x1b, + [SDLK_RETURN] = 0x1c, + [SDLK_LCTRL] = 0x1d, + [SDLK_a] = 0x1e, + [SDLK_s] = 0x1f, + [SDLK_d] = 0x20, + [SDLK_f] = 0x21, + [SDLK_g] = 0x22, + [SDLK_h] = 0x23, + [SDLK_j] = 0x24, + [SDLK_k] = 0x25, + [SDLK_l] = 0x26, + [SDLK_SEMICOLON] = 0x27, + [SDLK_QUOTE] = 0x28, + [SDLK_BACKQUOTE] = 0x29, + [SDLK_LSHIFT] = 0x2a, + [SDLK_BACKSLASH] = 0x2b, + [SDLK_z] = 0x2c, + [SDLK_x] = 0x2d, + [SDLK_c] = 0x2e, + [SDLK_v] = 0x2f, + [SDLK_b] = 0x30, + [SDLK_n] = 0x31, + [SDLK_m] = 0x32, + [SDLK_COMMA] = 0x33, + [SDLK_PERIOD] = 0x34, + [SDLK_SLASH] = 0x35, + [SDLK_KP_MULTIPLY] = 0x37, + [SDLK_LALT] = 0x38, + [SDLK_SPACE] = 0x39, + [SDLK_CAPSLOCK] = 0x3a, + [SDLK_F1] = 0x3b, + [SDLK_F2] = 0x3c, + [SDLK_F3] = 0x3d, + [SDLK_F4] = 0x3e, + [SDLK_F5] = 0x3f, + [SDLK_F6] = 0x40, + [SDLK_F7] = 0x41, + [SDLK_F8] = 0x42, + [SDLK_F9] = 0x43, + [SDLK_F10] = 0x44, + [SDLK_NUMLOCK] = 0x45, + [SDLK_SCROLLOCK] = 0x46, + [SDLK_KP7] = 0x47, + [SDLK_KP8] = 0x48, + [SDLK_KP9] = 0x49, + [SDLK_KP_MINUS] = 0x4a, + [SDLK_KP4] = 0x4b, + [SDLK_KP5] = 0x4c, + [SDLK_KP6] = 0x4d, + [SDLK_KP_PLUS] = 0x4e, + [SDLK_KP1] = 0x4f, + [SDLK_KP2] = 0x50, + [SDLK_KP3] = 0x51, + [SDLK_KP0] = 0x52, + [SDLK_KP_PERIOD] = 0x53, + [SDLK_PRINT] = 0x54, + [SDLK_LMETA] = 0x56, + + [SDLK_KP_ENTER] = 0x9c, + [SDLK_KP_DIVIDE] = 0xb5, + + [SDLK_UP] = 0xc8, + [SDLK_DOWN] = 0xd0, + [SDLK_RIGHT] = 0xcd, + [SDLK_LEFT] = 0xcb, + [SDLK_INSERT] = 0xd2, + [SDLK_HOME] = 0xc7, + [SDLK_END] = 0xcf, + [SDLK_PAGEUP] = 0xc9, + [SDLK_PAGEDOWN] = 0xd1, + [SDLK_DELETE] = 0xd3, +}; + +static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) +{ + return scancodes[ev->keysym.sym]; +} + +#elif defined(_WIN32) + +static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) +{ + return ev->keysym.scancode; +} + +#else + static const uint8_t x_keycode_to_pc_keycode[61] = { 0xc7, /* 97 Home */ 0xc8, /* 98 Up */ @@ -127,6 +251,27 @@ static const uint8_t x_keycode_to_pc_keycode[61] = { 0x53, /* 157 KP_Del */ }; +static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) +{ + int keycode; + + keycode = ev->keysym.scancode; + + if (keycode < 9) { + keycode = 0; + } else if (keycode < 97) { + keycode -= 8; /* just an offset */ + } else if (keycode < 158) { + /* use conversion table */ + keycode = x_keycode_to_pc_keycode[keycode - 97]; + } else { + keycode = 0; + } + return keycode; +} + +#endif + static void sdl_process_key(SDL_KeyboardEvent *ev) { int keycode, v, i; @@ -144,22 +289,7 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) } /* XXX: not portable, but avoids complicated mappings */ - keycode = ev->keysym.scancode; - - /* XXX: windows version may not work: 0xe0/0xe1 should be trapped - ? */ -#ifndef _WIN32 - if (keycode < 9) { - keycode = 0; - } else if (keycode < 97) { - keycode -= 8; /* just an offset */ - } else if (keycode < 158) { - /* use conversion table */ - keycode = x_keycode_to_pc_keycode[keycode - 97]; - } else { - keycode = 0; - } -#endif + keycode = sdl_keyevent_to_keycode(ev); switch(keycode) { case 0x00: -- cgit v1.2.3 From 81ca79911ae0ade4b802331f18623c0eed1891ef Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Jul 2004 01:47:47 +0000 Subject: 24 bpp mode fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@983 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/vgabios-cirrus.bin | Bin 30849 -> 30852 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 3d3575762..58572b643 100644 Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ -- cgit v1.2.3 From b30d4608dae994cf57cab4824f3307de026fd373 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Jul 2004 01:50:49 +0000 Subject: 24 bpp fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@984 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 105 +++++++++++++++++++++++++++++---------------------- hw/cirrus_vga_rop2.h | 93 +++++++++++++++++++++++++++++++++------------ 2 files changed, 129 insertions(+), 69 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 8ec63d3c2..d354fadd2 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -456,25 +456,6 @@ static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = { ROP2(cirrus_colorexpand_transp_notsrc_and_notdst), }; -static const cirrus_bitblt_rop_t cirrus_colorexpand_transp_inv[16][4] = { - ROP2(cirrus_colorexpand_transp_inv_0), - ROP2(cirrus_colorexpand_transp_inv_src_and_dst), - ROP_NOP2(cirrus_bitblt_rop_nop), - ROP2(cirrus_colorexpand_transp_inv_src_and_notdst), - ROP2(cirrus_colorexpand_transp_inv_notdst), - ROP2(cirrus_colorexpand_transp_inv_src), - ROP2(cirrus_colorexpand_transp_inv_1), - ROP2(cirrus_colorexpand_transp_inv_notsrc_and_dst), - ROP2(cirrus_colorexpand_transp_inv_src_xor_dst), - ROP2(cirrus_colorexpand_transp_inv_src_or_dst), - ROP2(cirrus_colorexpand_transp_inv_notsrc_or_notdst), - ROP2(cirrus_colorexpand_transp_inv_src_notxor_dst), - ROP2(cirrus_colorexpand_transp_inv_src_or_notdst), - ROP2(cirrus_colorexpand_transp_inv_notsrc), - ROP2(cirrus_colorexpand_transp_inv_notsrc_or_dst), - ROP2(cirrus_colorexpand_transp_inv_notsrc_and_notdst), -}; - static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = { ROP2(cirrus_colorexpand_0), ROP2(cirrus_colorexpand_src_and_dst), @@ -494,6 +475,44 @@ static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = { ROP2(cirrus_colorexpand_notsrc_and_notdst), }; +static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = { + ROP2(cirrus_colorexpand_pattern_transp_0), + ROP2(cirrus_colorexpand_pattern_transp_src_and_dst), + ROP_NOP2(cirrus_bitblt_rop_nop), + ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst), + ROP2(cirrus_colorexpand_pattern_transp_notdst), + ROP2(cirrus_colorexpand_pattern_transp_src), + ROP2(cirrus_colorexpand_pattern_transp_1), + ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst), + ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst), + ROP2(cirrus_colorexpand_pattern_transp_src_or_dst), + ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst), + ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst), + ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst), + ROP2(cirrus_colorexpand_pattern_transp_notsrc), + ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst), + ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst), +}; + +static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = { + ROP2(cirrus_colorexpand_pattern_0), + ROP2(cirrus_colorexpand_pattern_src_and_dst), + ROP_NOP2(cirrus_bitblt_rop_nop), + ROP2(cirrus_colorexpand_pattern_src_and_notdst), + ROP2(cirrus_colorexpand_pattern_notdst), + ROP2(cirrus_colorexpand_pattern_src), + ROP2(cirrus_colorexpand_pattern_1), + ROP2(cirrus_colorexpand_pattern_notsrc_and_dst), + ROP2(cirrus_colorexpand_pattern_src_xor_dst), + ROP2(cirrus_colorexpand_pattern_src_or_dst), + ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst), + ROP2(cirrus_colorexpand_pattern_src_notxor_dst), + ROP2(cirrus_colorexpand_pattern_src_or_notdst), + ROP2(cirrus_colorexpand_pattern_notsrc), + ROP2(cirrus_colorexpand_pattern_notsrc_or_dst), + ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst), +}; + static const cirrus_fill_t cirrus_fill[16][4] = { ROP2(cirrus_fill_0), ROP2(cirrus_fill_src_and_dst), @@ -584,27 +603,8 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, const uint8_t * src) { - uint8_t work_colorexp[256]; uint8_t *dst; - int patternbytes = s->cirrus_blt_pixelwidth * 8; - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - cirrus_bitblt_rop_t rop_func; - cirrus_bitblt_fgcol(s); - cirrus_bitblt_bgcol(s); - rop_func = cirrus_colorexpand[CIRRUS_ROP_SRC_INDEX][s->cirrus_blt_pixelwidth - 1]; - rop_func(s, work_colorexp, src, patternbytes, 1, patternbytes, 8); - src = work_colorexp; - s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_COLOREXPAND; - } - if (s->cirrus_blt_mode & ~CIRRUS_BLTMODE_PATTERNCOPY) { -#ifdef DEBUG_BITBLT - printf("cirrus: blt mode %02x (pattercopy) - unimplemented\n", - s->cirrus_blt_mode); -#endif - return 0; - } - dst = s->vram_ptr + s->cirrus_blt_dstaddr; (*s->cirrus_rop) (s, dst, src, s->cirrus_blt_dstpitch, 0, @@ -728,6 +728,7 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s) if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { s->cirrus_blt_srcpitch = 8; } else { + /* XXX: check for 24 bpp */ s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth; } s->cirrus_srccounter = s->cirrus_blt_srcpitch; @@ -848,20 +849,32 @@ static void cirrus_bitblt_start(CirrusVGAState * s) CIRRUS_BLTMODE_COLOREXPAND) { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) cirrus_bitblt_bgcol(s); - s->cirrus_rop = cirrus_colorexpand_transp_inv[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } else { + else cirrus_bitblt_fgcol(s); - s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } + s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; } else { cirrus_bitblt_fgcol(s); cirrus_bitblt_bgcol(s); s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; } } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { - s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) + cirrus_bitblt_bgcol(s); + else + cirrus_bitblt_fgcol(s); + s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } else { + cirrus_bitblt_fgcol(s); + cirrus_bitblt_bgcol(s); + s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } + } else { + s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } } else { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; @@ -2793,9 +2806,10 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) vga_io_memory); s->sr[0x06] = 0x0f; - s->sr[0x1F] = 0x22; // MemClock if (device_id == CIRRUS_ID_CLGD5446) { /* 4MB 64 bit memory config, always PCI */ + s->sr[0x1F] = 0x2d; // MemClock + s->gr[0x18] = 0x0f; // fastest memory configuration #if 1 s->sr[0x0f] = 0x98; s->sr[0x17] = 0x20; @@ -2808,6 +2822,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) s->real_vram_size = 2048 * 1024; #endif } else { + s->sr[0x1F] = 0x22; // MemClock s->sr[0x0F] = CIRRUS_MEMSIZE_2M; if (is_pci) s->sr[0x17] = CIRRUS_BUSTYPE_PCI; diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h index 540e308e8..5521870c8 100644 --- a/hw/cirrus_vga_rop2.h +++ b/hw/cirrus_vga_rop2.h @@ -67,6 +67,12 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) #elif DEPTH == 16 col = ((uint16_t *)(src1 + pattern_x))[0]; pattern_x = (pattern_x + 2) & 15; +#elif DEPTH == 24 + { + const uint8_t *src2 = src1 + pattern_x * 3; + col = src2[0] | (src2[1] << 8) | (src2[2] << 16); + pattern_x = (pattern_x + 1) & 7; + } #else col = ((uint32_t *)(src1 + pattern_x))[0]; pattern_x = (pattern_x + 4) & 31; @@ -89,21 +95,28 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) { uint8_t *d; int x, y; - unsigned bits; + unsigned bits, bits_xor; unsigned int col; unsigned bitmask; unsigned index; int srcskipleft = 0; - col = s->cirrus_blt_fgcol; + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + bits_xor = 0xff; + col = s->cirrus_blt_bgcol; + } else { + bits_xor = 0x00; + col = s->cirrus_blt_fgcol; + } + for(y = 0; y < bltheight; y++) { bitmask = 0x80 >> srcskipleft; - bits = *src++; + bits = *src++ ^ bits_xor; d = dst; for (x = 0; x < bltwidth; x += (DEPTH / 8)) { if ((bitmask & 0xff) == 0) { bitmask = 0x80; - bits = *src++; + bits = *src++ ^ bits_xor; } index = (bits & bitmask); if (index) { @@ -116,23 +129,23 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) } } -/* NOTE: srcpitch is ignored */ static void -glue(glue(glue(cirrus_colorexpand_transp_inv_, ROP_NAME), _),DEPTH) +glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, const uint8_t * src, int dstpitch, int srcpitch, int bltwidth, int bltheight) { + uint32_t colors[2]; uint8_t *d; int x, y; unsigned bits; unsigned int col; unsigned bitmask; - unsigned index; int srcskipleft = 0; - col = s->cirrus_blt_bgcol; + colors[0] = s->cirrus_blt_bgcol; + colors[1] = s->cirrus_blt_fgcol; for(y = 0; y < bltheight; y++) { bitmask = 0x80 >> srcskipleft; bits = *src++; @@ -142,19 +155,54 @@ glue(glue(glue(cirrus_colorexpand_transp_inv_, ROP_NAME), _),DEPTH) bitmask = 0x80; bits = *src++; } - index = (bits & bitmask); - if (!index) { + col = colors[!!(bits & bitmask)]; + PUTPIXEL(); + d += (DEPTH / 8); + bitmask >>= 1; + } + dst += dstpitch; + } +} + +static void +glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) + (CirrusVGAState * s, uint8_t * dst, + const uint8_t * src, + int dstpitch, int srcpitch, + int bltwidth, int bltheight) +{ + uint8_t *d; + int x, y, bitpos, pattern_y; + unsigned int bits, bits_xor; + unsigned int col; + + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + bits_xor = 0xff; + col = s->cirrus_blt_bgcol; + } else { + bits_xor = 0x00; + col = s->cirrus_blt_fgcol; + } + pattern_y = s->cirrus_blt_srcaddr & 7; + + for(y = 0; y < bltheight; y++) { + bits = src[pattern_y] ^ bits_xor; + bitpos = 7; + d = dst; + for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + if ((bits >> bitpos) & 1) { PUTPIXEL(); } d += (DEPTH / 8); - bitmask >>= 1; + bitpos = (bitpos - 1) & 7; } + pattern_y = (pattern_y + 1) & 7; dst += dstpitch; } } static void -glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) +glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, const uint8_t * src, int dstpitch, int srcpitch, @@ -162,28 +210,25 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) { uint32_t colors[2]; uint8_t *d; - int x, y; - unsigned bits; + int x, y, bitpos, pattern_y; + unsigned int bits; unsigned int col; - unsigned bitmask; - int srcskipleft = 0; colors[0] = s->cirrus_blt_bgcol; colors[1] = s->cirrus_blt_fgcol; + pattern_y = s->cirrus_blt_srcaddr & 7; + for(y = 0; y < bltheight; y++) { - bitmask = 0x80 >> srcskipleft; - bits = *src++; + bits = src[pattern_y]; + bitpos = 7; d = dst; for (x = 0; x < bltwidth; x += (DEPTH / 8)) { - if ((bitmask & 0xff) == 0) { - bitmask = 0x80; - bits = *src++; - } - col = colors[!!(bits & bitmask)]; + col = colors[(bits >> bitpos) & 1]; PUTPIXEL(); d += (DEPTH / 8); - bitmask >>= 1; + bitpos = (bitpos - 1) & 7; } + pattern_y = (pattern_y + 1) & 7; dst += dstpitch; } } -- cgit v1.2.3 From 7db4eea691f9368c33346064a9c46663d140938d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Jul 2004 20:57:47 +0000 Subject: removed unused code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@985 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cuda.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/hw/cuda.c b/hw/cuda.c index 8194016d6..1e4915f77 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -461,17 +461,7 @@ static void cuda_send_packet_to_host(CUDAState *s, cuda_update_irq(s); } -void adb_send_packet(ADBBusState *bus, const uint8_t *buf, int len) -{ - CUDAState *s = &cuda_state; - uint8_t data[16]; - - memcpy(data + 1, buf, len); - data[0] = ADB_PACKET; - cuda_send_packet_to_host(s, data, len + 1); -} - -void cuda_adb_poll(void *opaque) +static void cuda_adb_poll(void *opaque) { CUDAState *s = opaque; uint8_t obuf[ADB_MAX_OUT_LEN + 2]; -- cgit v1.2.3 From e02aa6869e31385381ebadd8770895d8d5b8b3a4 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Jul 2004 22:04:21 +0000 Subject: suppressed unused function git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@986 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 122ec9946..99ed1bd7a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -43,15 +43,6 @@ static inline int32_t s_ext16 (uint16_t value) return *tmp; } -/* 24 to 32 bits */ -static inline int32_t s_ext24 (uint32_t value) -{ - uint16_t utmp = (value >> 8) & 0xFFFF; - int16_t *tmp = &utmp; - - return (*tmp << 8) | (value & 0xFF); -} - #include "config.h" #include -- cgit v1.2.3 From 38a64f9dfe3555daac62b436d1750f097da05b3e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Jul 2004 22:06:01 +0000 Subject: fixed b[l] decoding git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@987 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index a3133fdfc..e09e9a7fd 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1520,7 +1520,10 @@ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) /* b ba bl bla */ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { - uint32_t li = s_ext24(LI(ctx->opcode)), target; + uint32_t li, target; + + /* sign extend LI */ + li = ((int32_t)LI(ctx->opcode) << 6) >> 6; if (AA(ctx->opcode) == 0) target = ctx->nip + li - 4; -- cgit v1.2.3 From 7e71f16f9abc44423c2eef92addcc8cd49ccd37e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Jul 2004 21:16:21 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@988 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 ++-- VERSION | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index 614e18cf4..bd8d41b1f 100644 --- a/Changelog +++ b/Changelog @@ -16,13 +16,13 @@ version 0.5.6: - PIC reset fix (Hidemi KAWAI) - PIC spurious irq support (aka Solaris install bug) - added '-localtime' option - - Cirrus CLGD 54xx VGA support (initial patch by Makoto Suzuki - (suzu)) + - 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) + - Set the default memory size for PC emulation to 128 MB version 0.5.5: diff --git a/VERSION b/VERSION index 389faccca..09a3acfa1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.5 \ No newline at end of file +0.6.0 \ No newline at end of file -- cgit v1.2.3 From 1bfe856eb2c9920e4fb107b1b44037b07b4c118f Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Jul 2004 21:17:50 +0000 Subject: Cirrus VGA is the default - 128 MB default memory - 800x600 default PPC resolution git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@989 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/vl.c b/vl.c index eebc6e6f5..6fdb7d2aa 100644 --- a/vl.c +++ b/vl.c @@ -99,7 +99,7 @@ extern void __sigaction(); #ifdef TARGET_PPC #define DEFAULT_RAM_SIZE 144 #else -#define DEFAULT_RAM_SIZE 32 +#define DEFAULT_RAM_SIZE 128 #endif /* in ms */ #define GUI_REFRESH_INTERVAL 30 @@ -133,9 +133,9 @@ int audio_enabled = 0; int pci_enabled = 1; int prep_enabled = 0; int rtc_utc = 1; -int cirrus_vga_enabled = 0; -int graphic_width = 640; -int graphic_height = 480; +int cirrus_vga_enabled = 1; +int graphic_width = 800; +int graphic_height = 600; int graphic_depth = 15; /***********************************************************/ @@ -960,14 +960,14 @@ int serial_open_device(void) int serial_open_device(void) { - char slave_name[1024]; - int master_fd, slave_fd; - if (serial_console == NULL && nographic) { /* use console for serial port */ return 0; } else { #if 0 + char slave_name[1024]; + int master_fd, slave_fd; + /* Not satisfying */ if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { fprintf(stderr, "warning: could not create pseudo terminal for serial port\n"); @@ -2115,6 +2115,8 @@ void help(void) #endif #ifdef TARGET_I386 "-isa simulate an ISA-only system (default is PCI system)\n" + "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" + " (default is CL-GD5446 PCI VGA)\n" #endif "\n" "During emulation, use C-a h to get terminal commands:\n", @@ -2179,6 +2181,7 @@ enum { QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, QEMU_OPTION_g, + QEMU_OPTION_std_vga, }; typedef struct QEMUOption { @@ -2229,6 +2232,7 @@ const QEMUOption qemu_options[] = { #endif { "localtime", 0, QEMU_OPTION_localtime }, { "isa", 0, QEMU_OPTION_isa }, + { "std-vga", 0, QEMU_OPTION_std_vga }, /* temporary options */ { "pci", 0, QEMU_OPTION_pci }, @@ -2518,6 +2522,9 @@ int main(int argc, char **argv) case QEMU_OPTION_cirrusvga: cirrus_vga_enabled = 1; break; + case QEMU_OPTION_std_vga: + cirrus_vga_enabled = 0; + break; case QEMU_OPTION_g: { const char *p; -- cgit v1.2.3 From 15a34c63642d8b70ad90bfbb2c2f823753e2dbf4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Jul 2004 21:26:26 +0000 Subject: doc update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@990 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 275 ++++++++++++++++++++++++++++++++++++--------------------- qemu-tech.texi | 19 +--- 2 files changed, 176 insertions(+), 118 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 5c4487973..530dbf178 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -41,18 +41,19 @@ For system emulation, the following hardware targets are supported: @itemize @item PC (x86 processor) @item PREP (PowerPC processor) +@item PowerMac (PowerPC processor, in progress) @end itemize For user emulation, x86, PowerPC, ARM, and SPARC CPUs are supported. @chapter Installation +If you want to compile QEMU yourself, see @ref{compilation}. + @section Linux -If you want to compile QEMU, please read the @file{README} which gives -the related information. Otherwise just download the binary -distribution (@file{qemu-XXX-i386.tar.gz}) and untar it as root in -@file{/}: +Download the binary distribution (@file{qemu-XXX-i386.tar.gz}) and +untar it as root in @file{/}: @example su @@ -62,67 +63,13 @@ tar zxvf /tmp/qemu-XXX-i386.tar.gz @section Windows -@itemize -@item Install the current versions of MSYS and MinGW from -@url{http://www.mingw.org/}. You can find detailed installation -instructions in the download section and the FAQ. - -@item Download -the MinGW development library of SDL 1.2.x -(@file{SDL-devel-1.2.x-mingw32.tar.gz}) from -@url{http://www.libsdl.org}. Unpack it in a temporary place, and -unpack the archive @file{i386-mingw32msvc.tar.gz} in the MinGW tool -directory. Edit the @file{sdl-config} script so that it gives the -correct SDL directory when invoked. - -@item Extract the current version of QEMU. - -@item Start the MSYS shell (file @file{msys.bat}). - -@item Change to the QEMU directory. Launch @file{./configure} and -@file{make}. If you have problems using SDL, verify that -@file{sdl-config} can be launched from the MSYS command line. - -@item You can install QEMU in @file{Program Files/Qemu} by typing -@file{make install}. Don't forget to copy @file{SDL.dll} in -@file{Program Files/Qemu}. - -@end itemize - -@section Cross compilation for Windows with Linux - -@itemize -@item -Install the MinGW cross compilation tools available at -@url{http://www.mingw.org/}. - -@item -Install the Win32 version of SDL (@url{http://www.libsdl.org}) by -unpacking @file{i386-mingw32msvc.tar.gz}. Set up the PATH environment -variable so that @file{i386-mingw32msvc-sdl-config} can be launched by -the QEMU configuration script. - -@item -Configure QEMU for Windows cross compilation: -@example -./configure --enable-mingw32 -@end example -If necessary, you can change the cross-prefix according to the prefix -choosen for the MinGW tools with --cross-prefix. You can also use ---prefix to set the Win32 install path. - -@item You can install QEMU in the installation directory by typing -@file{make install}. Don't forget to copy @file{SDL.dll} in the -installation directory. - -@end itemize - -Note: Currently, Wine does not seem able to launch -QEMU for Win32. +Download the experimental binary installer at +@url{http://www.freeoszoo.org/download.php}. @section Mac OS X -Mac OS X is currently not supported. +Download the experimental binary installer at +@url{http://www.freeoszoo.org/download.php}. @chapter QEMU PC System emulator invocation @@ -138,11 +85,11 @@ available: @enumerate @item -@code{qemu-fast} uses the host Memory Management Unit (MMU) to simulate -the x86 MMU. It is @emph{fast} but has limitations because the whole 4 GB -address space cannot be used and some memory mapped peripherials -cannot be emulated accurately yet. Therefore, a specific Linux kernel -must be used (@xref{linux_compile}). +@code{qemu-fast} uses the host Memory Management Unit (MMU) to +simulate the x86 MMU. It is @emph{fast} but has limitations because +the whole 4 GB address space cannot be used and some memory mapped +peripherials cannot be emulated accurately yet. Therefore, a specific +guest Linux kernel can be used (@xref{linux_compile}) as guest OS. @item @code{qemu} uses a software MMU. It is about @emph{two times @@ -153,22 +100,28 @@ slower} but gives a more accurate emulation. QEMU emulates the following PC peripherials: @itemize @minus +@item +i440FX host PCI bridge and PIIX3 PCI to ISA bridge @item -VGA (hardware level, including all non standard modes) +Cirrus CLGD 5446 PCI VGA card or dummy VGA card with Bochs VESA +extensions (hardware level, including all non standard modes). @item PS/2 mouse and keyboard @item -2 IDE interfaces with hard disk and CD-ROM support +2 PCI IDE interfaces with hard disk and CD-ROM support @item Floppy disk @item -up to 6 NE2000 network adapters +NE2000 PCI network adapters @item Serial port @item Soundblaster 16 card @end itemize +QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL +VGA BIOS. + @c man end @section Quick Start @@ -220,7 +173,7 @@ the raw disk image you use is not written back. You can however force the write back by pressing @key{C-a s} (@xref{disk_images}). @item -m megs -Set virtual RAM size to @var{megs} megabytes. +Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. @item -initrd file Use @var{file} as initial ram disk. @@ -238,6 +191,11 @@ with a serial console. The SB16 emulation is disabled by default as it may give problems with Windows. You can enable it manually with this option. +@item -localtime +Set the real time clock to local time (the default is to UTC +time). This option is needed to have correct date in MS-DOS or +Windows. + @end table Network options: @@ -261,11 +219,11 @@ it. Read @url{http://bellard.org/qemu/tetrinet.html} to have an example of its use. @item -user-net -(Experimental) Use the user mode network stack. This is the default if -no tun/tap network init script is found. +Use the user mode network stack. This is the default if no tun/tap +network init script is found. @item -dummy-net -Use the dummy network stack: no packet will be received on the network +Use the dummy network stack: no packet will be received by the network cards. @end table @@ -287,7 +245,7 @@ Use @var{file} as initial ram disk. @end table -Debug options: +Debug/Expert options: @table @option @item -s Wait gdb connection to port 1234 (@xref{gdb_usage}). @@ -297,6 +255,12 @@ Change gdb connection port. Do not start CPU at startup (you must type 'c' in the monitor). @item -d Output log in /tmp/qemu.log +@item -isa +Simulate an ISA-only system (default is PCI system). +@item -std-vga +Simulate a standard VGA card with Bochs VBE extensions (default is +Cirrus Logic GD5446 PCI VGA) + @end table During the graphical emulation, you can use the following keys: @@ -495,6 +459,10 @@ sendkey ctrl-alt-f1 This command is useful to send keys that your graphical user interface intercepts at low level, such as @code{ctrl-alt-f1} in X Window. +@item system_reset + +Reset the system. + @end table @subsection Integer expressions @@ -904,63 +872,93 @@ Use @code{set architecture i8086} to dump 16 bit code. Then use @subsection Linux -To have access to SVGA graphic modes under X11, use the @code{vesa} -X11 driver. For optimal performances, use the same depth as your -native display. +To have access to SVGA graphic modes under X11, use the @code{vesa} or +the @code{cirrus} X11 driver. For optimal performances, use 16 bit +color depth in the guest and the host OS. @subsection Windows If you have a slow host, using Windows 95 is better as it gives the best speed. Windows 2000 is also a good choice. -SVGA graphic modes support: QEMU currently supports the Bochs VESA VBE -extensions. It supports color depths of 8, 15, 16 and 32 bits per -pixel in 640x480, 800x600 and 1024x768. For optimal performances, use -the same depth as your native display. +SVGA graphic modes support: QEMU emulates a Cirrus Logic GD5446 Video +card. All Windows versions starting from Windows 95 should recognize +and use this graphic card. For optimal performances, use 16 bit color +depth in the guest and the host OS. -@itemize +CPU usage reduction: Windows 9x does not correctly use the CPU HLT +instruction. The result is that it takes host CPU cycles even when +idle. You can install the utility from +@url{http://www.user.cityline.ru/~maxamn/amnhltm.zip} to solve this +problem. Note that no such tool is needed for NT, 2000 or XP. -@item Windows XP: it should be automatically detected. +@chapter QEMU PowerPC System emulator invocation -@item Windows NT4 or 2000: use the driver -@url{http://www.volny.cz/xnavara/qemuvid_bin.zip} by Filip Navara. +Use the executable @file{qemu-system-ppc} to simulate a complete PREP +or PowerMac PowerPC system. -@item Windows 95/98/Me: no clean solution yet (but it will change -soon). You can however use the shareware driver from SciTech. Here are -the steps recommended by Christophe Bothamy on the Bochs mailing list: +QEMU emulates the following PowerMac peripherials: -@itemize -@item install win95 with the VGA driver. -@item download sdd 7 beta from @url{http://www.majorgeeks.com/download382.html} -@item download pmhelp.vxd from @url{http://unununium.org/viewcvs/snap/redist/release/pmhelp.vxd} -@item copy pmhelp.vxd to the win95 system directory -@item install sdd7 -@end itemize +@itemize @minus +@item +UniNorth PCI Bridge +@item +PCI VGA compatible card with VESA Bochs Extensions +@item +2 PMAC IDE interfaces with hard disk and CD-ROM support +@item +NE2000 PCI adapters +@item +Non Volatile RAM +@item +VIA-CUDA with ADB keyboard and mouse. @end itemize -@chapter QEMU PREP PowerPC System emulator invocation - -Use the executable @file{qemu-system-ppc} to simulate a complete PREP -PowerPC system. - QEMU emulates the following PREP peripherials: @itemize @minus @item +PCI Bridge +@item +PCI VGA compatible card with VESA Bochs Extensions +@item 2 IDE interfaces with hard disk and CD-ROM support @item Floppy disk @item -up to 6 NE2000 network adapters +NE2000 network adapters @item Serial port @item PREP Non Volatile RAM +@item +PC compatible keyboard and mouse. @end itemize +QEMU uses the Open Hack'Ware Open Firmware Compatible BIOS available at +@url{http://site.voila.fr/jmayer/OpenHackWare/index.htm}. + You can read the qemu PC system emulation chapter to have more informations about QEMU usage. +@c man begin OPTIONS + +The following options are specific to the PowerPC emulation: + +@table @option + +@item -prep +Simulate a PREP system (default is PowerMAC) + +@item -g WxH[xDEPTH] + +Set the initial VGA graphic mode. The default is 800x600x15. + +@end table + +@c man end + + More information is available at @url{http://jocelyn.mayer.free.fr/qemu-ppc/}. @@ -1065,3 +1063,76 @@ Activate log (logfile=/tmp/qemu.log) Act as if the host page size was 'pagesize' bytes @end table +@node compilation +@chapter Compilation from the sources + +@section Linux/BSD + +Read the @file{README} which gives the related information. + +@section Windows + +@itemize +@item Install the current versions of MSYS and MinGW from +@url{http://www.mingw.org/}. You can find detailed installation +instructions in the download section and the FAQ. + +@item Download +the MinGW development library of SDL 1.2.x +(@file{SDL-devel-1.2.x-mingw32.tar.gz}) from +@url{http://www.libsdl.org}. Unpack it in a temporary place, and +unpack the archive @file{i386-mingw32msvc.tar.gz} in the MinGW tool +directory. Edit the @file{sdl-config} script so that it gives the +correct SDL directory when invoked. + +@item Extract the current version of QEMU. + +@item Start the MSYS shell (file @file{msys.bat}). + +@item Change to the QEMU directory. Launch @file{./configure} and +@file{make}. If you have problems using SDL, verify that +@file{sdl-config} can be launched from the MSYS command line. + +@item You can install QEMU in @file{Program Files/Qemu} by typing +@file{make install}. Don't forget to copy @file{SDL.dll} in +@file{Program Files/Qemu}. + +@end itemize + +@section Cross compilation for Windows with Linux + +@itemize +@item +Install the MinGW cross compilation tools available at +@url{http://www.mingw.org/}. + +@item +Install the Win32 version of SDL (@url{http://www.libsdl.org}) by +unpacking @file{i386-mingw32msvc.tar.gz}. Set up the PATH environment +variable so that @file{i386-mingw32msvc-sdl-config} can be launched by +the QEMU configuration script. + +@item +Configure QEMU for Windows cross compilation: +@example +./configure --enable-mingw32 +@end example +If necessary, you can change the cross-prefix according to the prefix +choosen for the MinGW tools with --cross-prefix. You can also use +--prefix to set the Win32 install path. + +@item You can install QEMU in the installation directory by typing +@file{make install}. Don't forget to copy @file{SDL.dll} in the +installation directory. + +@end itemize + +Note: Currently, Wine does not seem able to launch +QEMU for Win32. + +@section Mac OS X + +The Mac OS X patches are not fully merged in QEMU, so you should look +at the QEMU mailing list archive to have all the necessary +information. + diff --git a/qemu-tech.texi b/qemu-tech.texi index 659cd203e..0df2a0b96 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -258,7 +258,7 @@ segment base. @section Translation cache -A 2MByte cache holds the most recently used translations. For +A 16 MByte cache holds the most recently used translations. For simplicity, it is completely flushed when it is full. A translation unit contains just a single basic block (a block of x86 instructions terminated by a jump or by a virtual CPU state change which the @@ -489,19 +489,6 @@ This program tests various Linux system calls. It is used to verify that the system call parameters are correctly converted between target and host CPUs. -@section @file{hello-i386} - -Very simple statically linked x86 program, just to test QEMU during a -port to a new host CPU. - -@section @file{hello-arm} - -Very simple statically linked ARM program, just to test QEMU during a -port to a new host CPU. - -@section @file{sha1} - -It is a simple benchmark. Care must be taken to interpret the results -because it mostly tests the ability of the virtual CPU to optimize the -@code{rol} x86 instruction and the condition code computations. +@section @file{qruncom.c} +Example of usage of @code{libqemu} to emulate a user mode i386 CPU. -- cgit v1.2.3 From 675376f2b450e22cba45e0617f34ab8454219ef5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 13:39:53 +0000 Subject: kbd save/restore git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@991 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/hw/pckbd.c b/hw/pckbd.c index 0d7b5ff09..730b57337 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -642,11 +642,59 @@ static void kbd_reset(void *opaque) q->count = 0; } +static void kbd_save(QEMUFile* f, void* opaque) +{ + KBDState *s = (KBDState*)opaque; + + qemu_put_8s(f, &s->write_cmd); + qemu_put_8s(f, &s->status); + qemu_put_8s(f, &s->mode); + qemu_put_be32s(f, &s->kbd_write_cmd); + qemu_put_be32s(f, &s->scan_enabled); + qemu_put_be32s(f, &s->mouse_write_cmd); + qemu_put_8s(f, &s->mouse_status); + qemu_put_8s(f, &s->mouse_resolution); + qemu_put_8s(f, &s->mouse_sample_rate); + qemu_put_8s(f, &s->mouse_wrap); + qemu_put_8s(f, &s->mouse_type); + qemu_put_8s(f, &s->mouse_detect_state); + qemu_put_be32s(f, &s->mouse_dx); + qemu_put_be32s(f, &s->mouse_dy); + qemu_put_be32s(f, &s->mouse_dz); + qemu_put_8s(f, &s->mouse_buttons); +} + +static int kbd_load(QEMUFile* f, void* opaque, int version_id) +{ + KBDState *s = (KBDState*)opaque; + + if (version_id != 1) + return -EINVAL; + qemu_get_8s(f, &s->write_cmd); + qemu_get_8s(f, &s->status); + qemu_get_8s(f, &s->mode); + qemu_get_be32s(f, &s->kbd_write_cmd); + qemu_get_be32s(f, &s->scan_enabled); + qemu_get_be32s(f, &s->mouse_write_cmd); + qemu_get_8s(f, &s->mouse_status); + qemu_get_8s(f, &s->mouse_resolution); + qemu_get_8s(f, &s->mouse_sample_rate); + qemu_get_8s(f, &s->mouse_wrap); + qemu_get_8s(f, &s->mouse_type); + qemu_get_8s(f, &s->mouse_detect_state); + qemu_get_be32s(f, &s->mouse_dx); + qemu_get_be32s(f, &s->mouse_dy); + qemu_get_be32s(f, &s->mouse_dz); + qemu_get_8s(f, &s->mouse_buttons); + return 0; +} + void kbd_init(void) { KBDState *s = &kbd_state; kbd_reset(s); + register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s); register_ioport_read(0x60, 1, 1, kbd_read_data, s); register_ioport_write(0x60, 1, 1, kbd_write_data, s); register_ioport_read(0x64, 1, 1, kbd_read_status, s); -- cgit v1.2.3 From 2c6ab8329e870c4e4c00caa2169db421f9b42b86 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 13:41:46 +0000 Subject: load/save state support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@992 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index d354fadd2..bd2355bae 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2753,6 +2753,95 @@ static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { cirrus_mmio_writel, }; +/* load/save state */ + +static void cirrus_vga_save(QEMUFile *f, void *opaque) +{ + CirrusVGAState *s = opaque; + + qemu_put_be32s(f, &s->latch); + qemu_put_8s(f, &s->sr_index); + qemu_put_buffer(f, s->sr, 256); + qemu_put_8s(f, &s->gr_index); + qemu_put_8s(f, &s->cirrus_shadow_gr0); + qemu_put_8s(f, &s->cirrus_shadow_gr1); + qemu_put_buffer(f, s->gr + 2, 254); + qemu_put_8s(f, &s->ar_index); + qemu_put_buffer(f, s->ar, 21); + qemu_put_be32s(f, &s->ar_flip_flop); + qemu_put_8s(f, &s->cr_index); + qemu_put_buffer(f, s->cr, 256); + qemu_put_8s(f, &s->msr); + qemu_put_8s(f, &s->fcr); + qemu_put_8s(f, &s->st00); + qemu_put_8s(f, &s->st01); + + qemu_put_8s(f, &s->dac_state); + qemu_put_8s(f, &s->dac_sub_index); + qemu_put_8s(f, &s->dac_read_index); + qemu_put_8s(f, &s->dac_write_index); + qemu_put_buffer(f, s->dac_cache, 3); + qemu_put_buffer(f, s->palette, 768); + + qemu_put_be32s(f, &s->bank_offset); + + qemu_put_8s(f, &s->cirrus_hidden_dac_lockindex); + qemu_put_8s(f, &s->cirrus_hidden_dac_data); + + qemu_put_be32s(f, &s->hw_cursor_x); + qemu_put_be32s(f, &s->hw_cursor_y); + /* XXX: we do not save the bitblt state - we assume we do not save + the state when the blitter is active */ +} + +static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) +{ + CirrusVGAState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->latch); + qemu_get_8s(f, &s->sr_index); + qemu_get_buffer(f, s->sr, 256); + qemu_get_8s(f, &s->gr_index); + qemu_get_8s(f, &s->cirrus_shadow_gr0); + qemu_get_8s(f, &s->cirrus_shadow_gr1); + s->gr[0x00] = s->cirrus_shadow_gr0 & 0x0f; + s->gr[0x01] = s->cirrus_shadow_gr1 & 0x0f; + qemu_get_buffer(f, s->gr + 2, 254); + qemu_get_8s(f, &s->ar_index); + qemu_get_buffer(f, s->ar, 21); + qemu_get_be32s(f, &s->ar_flip_flop); + qemu_get_8s(f, &s->cr_index); + qemu_get_buffer(f, s->cr, 256); + qemu_get_8s(f, &s->msr); + qemu_get_8s(f, &s->fcr); + qemu_get_8s(f, &s->st00); + qemu_get_8s(f, &s->st01); + + qemu_get_8s(f, &s->dac_state); + qemu_get_8s(f, &s->dac_sub_index); + qemu_get_8s(f, &s->dac_read_index); + qemu_get_8s(f, &s->dac_write_index); + qemu_get_buffer(f, s->dac_cache, 3); + qemu_get_buffer(f, s->palette, 768); + + qemu_get_be32s(f, &s->bank_offset); + + qemu_get_8s(f, &s->cirrus_hidden_dac_lockindex); + qemu_get_8s(f, &s->cirrus_hidden_dac_data); + + qemu_get_be32s(f, &s->hw_cursor_x); + qemu_get_be32s(f, &s->hw_cursor_y); + + /* force refresh */ + s->graphic_mode = -1; + cirrus_update_bank_ptr(s, 0); + cirrus_update_bank_ptr(s, 1); + return 0; +} + /*************************************** * * initialize @@ -2862,6 +2951,8 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) s->get_resolution = cirrus_get_resolution; s->cursor_invalidate = cirrus_cursor_invalidate; s->cursor_draw_line = cirrus_cursor_draw_line; + + register_savevm("cirrus_vga", 0, 1, cirrus_vga_save, cirrus_vga_load, s); } /*************************************** -- cgit v1.2.3 From 3df3f6fd7b5d45bae588ceb17233187ba5ec5c8a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 14:45:19 +0000 Subject: odd memory access fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@993 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 73 ++++++++++++++++++++++--------------------------------------- 1 file changed, 26 insertions(+), 47 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 50a34173f..0b094d1e3 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -440,6 +440,24 @@ static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr) } } +static inline void ne2000_dma_update(NE2000State *s, int len) +{ + s->rsar += len; + /* wrap */ + /* XXX: check what to do if rsar > stop */ + if (s->rsar == s->stop) + s->rsar = s->start; + + if (s->rcnt <= len) { + s->rcnt = 0; + /* signal end of transfert */ + s->isr |= ENISR_RDC; + ne2000_update_irq(s); + } else { + s->rcnt -= len; + } +} + static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) { NE2000State *s = opaque; @@ -448,25 +466,15 @@ static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("NE2000: asic write val=0x%04x\n", val); #endif if (s->rcnt == 0) - return; + return; if (s->dcfg & 0x01) { /* 16 bit access */ ne2000_mem_writew(s, s->rsar, val); - s->rsar += 2; - s->rcnt -= 2; + ne2000_dma_update(s, 2); } else { /* 8 bit access */ ne2000_mem_writeb(s, s->rsar, val); - s->rsar++; - s->rcnt--; - } - /* wrap */ - if (s->rsar == s->stop) - s->rsar = s->start; - if (s->rcnt == 0) { - /* signal end of transfert */ - s->isr |= ENISR_RDC; - ne2000_update_irq(s); + ne2000_dma_update(s, 1); } } @@ -478,21 +486,11 @@ static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) if (s->dcfg & 0x01) { /* 16 bit access */ ret = ne2000_mem_readw(s, s->rsar); - s->rsar += 2; - s->rcnt -= 2; + ne2000_dma_update(s, 2); } else { /* 8 bit access */ ret = ne2000_mem_readb(s, s->rsar); - s->rsar++; - s->rcnt--; - } - /* wrap */ - if (s->rsar == s->stop) - s->rsar = s->start; - if (s->rcnt == 0) { - /* signal end of transfert */ - s->isr |= ENISR_RDC; - ne2000_update_irq(s); + ne2000_dma_update(s, 1); } #ifdef DEBUG_NE2000 printf("NE2000: asic read val=0x%04x\n", ret); @@ -508,19 +506,10 @@ static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val) printf("NE2000: asic writel val=0x%04x\n", val); #endif if (s->rcnt == 0) - return; + return; /* 32 bit access */ ne2000_mem_writel(s, s->rsar, val); - s->rsar += 4; - s->rcnt -= 4; - /* wrap */ - if (s->rsar == s->stop) - s->rsar = s->start; - if (s->rcnt == 0) { - /* signal end of transfert */ - s->isr |= ENISR_RDC; - ne2000_update_irq(s); - } + ne2000_dma_update(s, 4); } static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr) @@ -530,17 +519,7 @@ static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr) /* 32 bit access */ ret = ne2000_mem_readl(s, s->rsar); - s->rsar += 4; - s->rcnt -= 4; - - /* wrap */ - if (s->rsar == s->stop) - s->rsar = s->start; - if (s->rcnt == 0) { - /* signal end of transfert */ - s->isr |= ENISR_RDC; - ne2000_update_irq(s); - } + ne2000_dma_update(s, 4); #ifdef DEBUG_NE2000 printf("NE2000: asic readl val=0x%04x\n", ret); #endif -- cgit v1.2.3 From 02e1ec9bc4f9bb54f88840e6cdcc3c15953dd898 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 15:15:39 +0000 Subject: Mac OS X port (Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@994 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/exec-all.h b/exec-all.h index 65d26fdfb..b6853a1af 100644 --- a/exec-all.h +++ b/exec-all.h @@ -391,11 +391,11 @@ static inline int testandset (int *p) { int ret; __asm__ __volatile__ ( - "0: lwarx %0,0,%1 ;" - " xor. %0,%3,%0;" - " bne 1f;" - " stwcx. %2,0,%1;" - " bne- 0b;" + "0: lwarx %0,0,%1\n" + " xor. %0,%3,%0\n" + " bne 1f\n" + " stwcx. %2,0,%1\n" + " bne- 0b\n" "1: " : "=&r" (ret) : "r" (p), "r" (1), "r" (0) -- cgit v1.2.3 From bbbc4663d1b771b1095d2e1b2053c4ea9fdad43a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 15:27:59 +0000 Subject: removed unused definitions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@995 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index dab858560..55fe2b224 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -27,8 +27,6 @@ //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS -extern FILE *stdout, *stderr; - /*****************************************************************************/ /* PPC MMU emulation */ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, -- cgit v1.2.3 From 6d463de2b3e261e95f224767605eef02acbd2701 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 15:28:48 +0000 Subject: removed stdout reference (not portable) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@996 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index d761a8d2b..30905d98a 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -464,11 +464,9 @@ void do_store_dbat (int ul, int nr) /*****************************************************************************/ /* Special helpers for debug */ -extern FILE *stdout; - void dump_state (void) { - cpu_ppc_dump_state(env, stdout, 0); + // cpu_ppc_dump_state(env, stdout, 0); } void dump_rfi (void) -- cgit v1.2.3 From 1e6cae953d6a37216359b79e05d23e1bf4dc6bbe Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 15:31:19 +0000 Subject: comment git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@997 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dyngen-exec.h b/dyngen-exec.h index 907771e4a..d10e78840 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -20,6 +20,9 @@ #if !defined(__DYNGEN_EXEC_H__) #define __DYNGEN_EXEC_H__ +/* NOTE: standard headers should be used with special care at this + point because host CPU registers are used as global variables. Some + host headers do not allow that. */ #include typedef unsigned char uint8_t; -- cgit v1.2.3 From 933dc6ebc4b908be93929ac80399ba315ba626cd Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 15:33:29 +0000 Subject: Mac OS X port git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@998 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e09e9a7fd..c3706f007 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -276,9 +276,15 @@ static inline uint32_t MASK (uint32_t start, uint32_t end) return ret; } +#if defined(__linux__) +#define OPCODES_SECTION \ + __attribute__ ((section(".opcodes"), unused, aligned (8) )) +#else +#define OPCODES_SECTION +#endif + #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ -__attribute__ ((section(".opcodes"), unused, aligned (8) )) \ -static opcode_t opc_##name = { \ +OPCODES_SECTION static opcode_t opc_##name = { \ .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ @@ -290,8 +296,7 @@ static opcode_t opc_##name = { \ } #define GEN_OPCODE_MARK(name) \ -__attribute__ ((section(".opcodes"), unused, aligned (8) )) \ -static opcode_t opc_##name = { \ +OPCODES_SECTION static opcode_t opc_##name = { \ .opc1 = 0xFF, \ .opc2 = 0xFF, \ .opc3 = 0xFF, \ -- cgit v1.2.3 From 82eec0a1740cead905de40fc9970cdc1ad2ea51b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 16:22:18 +0000 Subject: Mac OS X port (Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@999 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 553 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 546 insertions(+), 7 deletions(-) diff --git a/dyngen.c b/dyngen.c index ff441caec..ad0e83410 100644 --- a/dyngen.c +++ b/dyngen.c @@ -6,6 +6,8 @@ * 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 @@ -34,6 +36,8 @@ compilation */ #if defined(CONFIG_WIN32) #define CONFIG_FORMAT_COFF +#elif defined(CONFIG_DARWIN) +#define CONFIG_FORMAT_MACH #else #define CONFIG_FORMAT_ELF #endif @@ -169,6 +173,35 @@ typedef struct coff_rel { #endif /* CONFIG_FORMAT_COFF */ +#ifdef CONFIG_FORMAT_MACH + +#include +#include +#include +#include + +# 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 { @@ -399,6 +432,11 @@ int find_reloc(int sh_index) 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; @@ -600,6 +638,11 @@ static char *get_rel_sym_name(EXE_RELOC *rel) 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; @@ -758,6 +801,390 @@ int load_object(const char *filename) #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 = (sectoffset & 0xffff); + break; + case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (other_half & 0xffff); + break; + case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (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); insects * 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++) { + const char *name; + struct nlist *sym_follow, *sym_next = 0; + unsigned int j; + name = find_str_by_index(sym->n_un.n_strx); + memset(sym, 0, sizeof(*sym)); + + if ( sym->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 */ + #ifdef HOST_ARM int arm_emit_ldr_info(const char *name, unsigned long start_offset, @@ -1049,9 +1476,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, args_present[i] = 0; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= start_offset && - rel->r_offset < start_offset + (p_end - p_start)) { + 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)) { n = strtoul(p, NULL, 10); if (n > MAX_ARGS) @@ -1087,9 +1517,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, fprintf(outfile, " extern void %s();\n", name); for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= start_offset && - rel->r_offset < start_offset + (p_end - p_start)) { + 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)) { @@ -1101,12 +1534,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; } #endif +#ifdef __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); +#else fprintf(outfile, "extern char %s;\n", sym_name); +#endif } } } - fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, start_offset - offset, copy_size); + fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", + name, (int)(start_offset - offset), copy_size); /* emit code offset information */ { @@ -1131,12 +1570,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } 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 { @@ -1284,6 +1730,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_PPC) { +#ifdef CONFIG_FORMAT_ELF char name[256]; int type; int addend; @@ -1337,6 +1784,94 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#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 */ + } + + if (strstart(sym_name, "__op_param", &p)) { + snprintf(final_sym_name, sizeof(final_sym_name), "param%s", p); + } else { + snprintf(final_sym_name, sizeof(final_sym_name), "(long)(&%s)", sym_name); + } + + switch(type) { + case PPC_RELOC_BR24: + 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"); + 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) { @@ -1689,9 +2224,9 @@ int gen_file(FILE *outfile, int out_type) 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, *p; + const char *name; name = get_sym_name(sym); - if (strstart(name, OP_PREFIX, &p)) { + if (strstart(name, OP_PREFIX, NULL)) { gen_code(name, sym->st_value, sym->st_size, outfile, 2); } } @@ -1702,8 +2237,10 @@ int gen_file(FILE *outfile, int out_type) 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); } } @@ -1747,8 +2284,10 @@ fprintf(outfile, 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); } } -- cgit v1.2.3 From e3371e62f3ca085d784a2bb848e94111ad4b42e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 16:26:02 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1000 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 530dbf178..7829f3f49 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -876,22 +876,55 @@ To have access to SVGA graphic modes under X11, use the @code{vesa} or the @code{cirrus} X11 driver. For optimal performances, use 16 bit color depth in the guest and the host OS. +When using a 2.6 guest Linux kernel, you should add the option +@code{clock=pit} on the kernel command line because the 2.6 Linux +kernels make very strict real time clock checks by default that QEMU +cannot simulate exactly. + @subsection Windows If you have a slow host, using Windows 95 is better as it gives the best speed. Windows 2000 is also a good choice. -SVGA graphic modes support: QEMU emulates a Cirrus Logic GD5446 Video +@subsubsection SVGA graphic modes support + +QEMU emulates a Cirrus Logic GD5446 Video card. All Windows versions starting from Windows 95 should recognize and use this graphic card. For optimal performances, use 16 bit color depth in the guest and the host OS. -CPU usage reduction: Windows 9x does not correctly use the CPU HLT +@subsubsection CPU usage reduction + +Windows 9x does not correctly use the CPU HLT instruction. The result is that it takes host CPU cycles even when idle. You can install the utility from @url{http://www.user.cityline.ru/~maxamn/amnhltm.zip} to solve this problem. Note that no such tool is needed for NT, 2000 or XP. +@subsubsection Windows 2000 disk full problems + +Currently (release 0.6.0) QEMU has a bug which gives a @code{disk +full} error during installation of some releases of Windows 2000. The +workaround is to stop QEMU as soon as you notice that your disk image +size is growing too fast (monitor it with @code{ls -ls}). Then +relaunch QEMU to continue the installation. If you still experience +the problem, relaunch QEMU again. + +Future QEMU releases are likely to correct this bug. + +@subsubsection Windows XP security problems + +Some releases of Windows XP install correctly but give a security +error when booting: +@example +A problem is preventing Windows from accurately checking the +license for this computer. Error code: 0x800703e6. +@end example +The only known workaround is to boot in Safe mode +without networking support. + +Future QEMU releases are likely to correct this bug. + @chapter QEMU PowerPC System emulator invocation Use the executable @file{qemu-system-ppc} to simulate a complete PREP -- cgit v1.2.3 From 96bcd4f884c98fa74efe5e82a551a2289d46e1ea Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 16:26:15 +0000 Subject: Mac OS X port git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1001 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vl.c b/vl.c index 6fdb7d2aa..81782b085 100644 --- a/vl.c +++ b/vl.c @@ -65,7 +65,9 @@ #endif #ifdef CONFIG_SDL +#ifdef __APPLE__ #include +#endif #if defined(__linux__) /* SDL use the pthreads and they modify sigaction. We don't want that. */ -- cgit v1.2.3 From fcc941fe20879fc08edec8606fcec3d37c074926 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 16:28:35 +0000 Subject: added .cvsignore git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1002 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .cvsignore diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 000000000..39a56bcf3 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,15 @@ +arm-user +config-host.* +dyngen +i386 +i386-softmmu +i386-user +ppc-softmmu +ppc-user +qemu-doc.html +qemu-mkcow +qemu-tech.html +qemu.1 +qemu.pod +sparc-user +vmdk2raw -- cgit v1.2.3 From d08c49aae0fe7d5507c73d042486c9d9701a34b3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 16:40:19 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1003 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 ++- TODO | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index bd8d41b1f..011f47458 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -version 0.5.6: +version 0.6.0: - minimalist FPU exception support (NetBSD FPU probe fix) - cr0.ET fix (Win95 boot) @@ -22,6 +22,7 @@ version 0.5.6: - 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: diff --git a/TODO b/TODO index 6b9004787..c3a000043 100644 --- a/TODO +++ b/TODO @@ -5,7 +5,6 @@ short term: - do not resize vga if invalid size. - avoid looping if only exceptions - handle fast timers + add explicit clocks -- OS/2 install bug - cycle counter for all archs - TLB code protection support for PPC - add sysenter/sysexit and fxsr for L4 pistachio 686 -- cgit v1.2.3 From fa36761d7f9f374777d63ac299bb0acb64bd8a20 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 16:57:29 +0000 Subject: ppc bios version 0.3 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1004 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 3 +++ pc-bios/ppc_rom.bin | Bin 524288 -> 524288 bytes 2 files changed, 3 insertions(+) diff --git a/pc-bios/README b/pc-bios/README index d81dd767b..31f91f3ce 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -3,3 +3,6 @@ - The VGA BIOS and the Cirrus VGA BIOS come from the LGPL VGA bios project (http://www.nongnu.org/vgabios/). + +- The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is + available at http://site.voila.fr/jmayer/OpenHackWare/index.htm. diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin index c2beb6227..d882dee3e 100644 Binary files a/pc-bios/ppc_rom.bin and b/pc-bios/ppc_rom.bin differ -- cgit v1.2.3 From fbf59244b87852ffac7c3ab6a6d57b3a6326f37c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Jul 2004 18:18:19 +0000 Subject: static build fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1005 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 00afaafa7..bd2445252 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -43,7 +43,7 @@ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; /* for recent libc, we add these dummy symbols which are not declared when generating a linked object (bug in ld ?) */ -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) +#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC) long __preinit_array_start[0]; long __preinit_array_end[0]; long __init_array_start[0]; -- cgit v1.2.3 From 1b039c09fe69c9f9c72a4671de60562fb564c02a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 18:39:45 +0000 Subject: OS X port git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1007 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c3706f007..a2ac41900 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -276,11 +276,12 @@ static inline uint32_t MASK (uint32_t start, uint32_t end) return ret; } -#if defined(__linux__) +#if defined(__APPLE__) #define OPCODES_SECTION \ - __attribute__ ((section(".opcodes"), unused, aligned (8) )) + __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (8) )) #else -#define OPCODES_SECTION +#define OPCODES_SECTION \ + __attribute__ ((section(".opcodes"), unused, aligned (8) )) #endif #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ -- cgit v1.2.3 From cab84d984420800e57dfab42a7c6dd95f951698a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 18:51:50 +0000 Subject: Mac OS X port (Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1008 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index d10e78840..86087ca62 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -184,7 +184,7 @@ extern int printf(const char *, ...); #define __hidden #endif -#ifdef __alpha__ +#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 @@ -197,11 +197,15 @@ extern int __op_param3 __hidden; #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 +#endif /* !defined(__alpha__) */ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; -- cgit v1.2.3 From bec9d989dba24e5ce4f94fcbccc841769a510bae Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 20:15:26 +0000 Subject: fixed register 0 usage - fixed mouse buttons git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1009 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adb.c | 86 +++++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index de06f8789..36c4aecd2 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -43,53 +43,62 @@ #define ADB_MODEM 5 #define ADB_MISC 7 +/* error codes */ +#define ADB_RET_NOTPRESENT (-2) + int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) { ADBDevice *d; int devaddr, cmd, i; cmd = buf[0] & 0xf; - devaddr = buf[0] >> 4; - if (buf[1] == ADB_BUSRESET) { - obuf[0] = 0x00; - obuf[1] = 0x00; - return 2; - } - if (cmd == ADB_FLUSH) { - obuf[0] = 0x00; - obuf[1] = 0x00; - return 2; + if (cmd == ADB_BUSRESET) { + for(i = 0; i < s->nb_devices; i++) { + d = &s->devices[i]; + if (d->devreset) { + d->devreset(d); + } + } + return 0; } - + devaddr = buf[0] >> 4; for(i = 0; i < s->nb_devices; i++) { d = &s->devices[i]; if (d->devaddr == devaddr) { return d->devreq(d, obuf, buf, len); } } - return 0; + return ADB_RET_NOTPRESENT; } +/* XXX: move that to cuda ? */ int adb_poll(ADBBusState *s, uint8_t *obuf) { ADBDevice *d; int olen, i; + uint8_t buf[1]; olen = 0; for(i = 0; i < s->nb_devices; i++) { if (s->poll_index >= s->nb_devices) s->poll_index = 0; d = &s->devices[s->poll_index]; - olen = d->devreq(d, obuf, NULL, 0); - s->poll_index++; - if (olen) + buf[0] = ADB_READREG | (d->devaddr << 4); + olen = adb_request(s, obuf + 1, buf, 1); + /* if there is data, we poll again the same device */ + if (olen > 0) { + obuf[0] = buf[0]; + olen++; break; + } + s->poll_index++; } return olen; } ADBDevice *adb_register_device(ADBBusState *s, int devaddr, ADBDeviceRequest *devreq, + ADBDeviceReset *devreset, void *opaque) { ADBDevice *d; @@ -99,6 +108,7 @@ ADBDevice *adb_register_device(ADBBusState *s, int devaddr, d->bus = s; d->devaddr = devaddr; d->devreq = devreq; + d->devreset = devreset; d->opaque = opaque; return d; } @@ -166,10 +176,10 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) adb_keycode = pc_to_adb_keycode[keycode | 0x80]; else adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; - obuf[0] = (d->devaddr << 4) | 0x0c; - obuf[1] = adb_keycode | (keycode & 0x80); - obuf[2] = 0xff; - olen = 3; + obuf[0] = adb_keycode | (keycode & 0x80); + /* NOTE: could put a second keycode if needed */ + obuf[1] = 0xff; + olen = 2; ext_keycode = 0; break; } @@ -180,10 +190,13 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, const uint8_t *buf, int len) { + KBDState *s = d->opaque; int cmd, reg, olen; - if (!buf) { - return adb_kbd_poll(d, obuf); + if ((buf[0] & 0x0f) == ADB_FLUSH) { + /* flush keyboard fifo */ + s->wptr = s->rptr = s->count = 0; + return 0; } cmd = buf[0] & 0xc; @@ -214,6 +227,9 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, break; case ADB_READREG: switch(reg) { + case 0: + olen = adb_kbd_poll(d, obuf); + break; case 1: break; case 2: @@ -237,7 +253,7 @@ void adb_kbd_init(ADBBusState *bus) ADBDevice *d; KBDState *s; s = qemu_mallocz(sizeof(KBDState)); - d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, s); + d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, NULL, s); d->handler = 1; qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); } @@ -291,24 +307,29 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) dx &= 0x7f; dy &= 0x7f; - if (s->buttons_state & MOUSE_EVENT_LBUTTON) + if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) dy |= 0x80; - if (s->buttons_state & MOUSE_EVENT_RBUTTON) + if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) dx |= 0x80; - obuf[0] = (d->devaddr << 4) | 0x0c; - obuf[1] = dy; - obuf[2] = dx; - return 3; + obuf[0] = dy; + obuf[1] = dx; + return 2; } static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, const uint8_t *buf, int len) { + MouseState *s = d->opaque; int cmd, reg, olen; - if (!buf) { - return adb_mouse_poll(d, obuf); + if ((buf[0] & 0x0f) == ADB_FLUSH) { + /* flush mouse fifo */ + s->buttons_state = s->last_buttons_state; + s->dx = 0; + s->dy = 0; + s->dz = 0; + return 0; } cmd = buf[0] & 0xc; @@ -337,6 +358,9 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, break; case ADB_READREG: switch(reg) { + case 0: + olen = adb_mouse_poll(d, obuf); + break; case 1: break; case 3: @@ -356,7 +380,7 @@ void adb_mouse_init(ADBBusState *bus) MouseState *s; s = qemu_mallocz(sizeof(MouseState)); - d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, s); + d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, NULL, s); d->handler = 2; qemu_add_mouse_event_handler(adb_mouse_event, d); } -- cgit v1.2.3 From 38f0b147a57c1d64d068d3a15efde83322a5c90e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 20:16:00 +0000 Subject: fixed ADB error reporting git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1010 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cuda.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/cuda.c b/hw/cuda.c index 1e4915f77..c05cdeb5f 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -545,13 +545,14 @@ static void cuda_receive_packet_from_host(CUDAState *s, uint8_t obuf[ADB_MAX_OUT_LEN + 2]; int olen; olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1); - if (olen != 0) { + if (olen > 0) { obuf[0] = ADB_PACKET; obuf[1] = 0x00; } else { - /* empty reply */ + /* error */ obuf[0] = ADB_PACKET; - obuf[1] = 0x02; + obuf[1] = -olen; + olen = 0; } cuda_send_packet_to_host(s, obuf, olen + 2); } -- cgit v1.2.3 From 12c28fed49a4011fdec440d78ef8f031317c402a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 20:26:20 +0000 Subject: adb fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1011 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vl.h b/vl.h index 583e8433d..15004c010 100644 --- a/vl.h +++ b/vl.h @@ -733,11 +733,14 @@ typedef struct ADBDevice ADBDevice; /* buf = NULL means polling */ typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, const uint8_t *buf, int len); +typedef int ADBDeviceReset(ADBDevice *d); + struct ADBDevice { struct ADBBusState *bus; int devaddr; int handler; ADBDeviceRequest *devreq; + ADBDeviceReset *devreset; void *opaque; }; @@ -753,6 +756,7 @@ int adb_poll(ADBBusState *s, uint8_t *buf_out); ADBDevice *adb_register_device(ADBBusState *s, int devaddr, ADBDeviceRequest *devreq, + ADBDeviceReset *devreset, void *opaque); void adb_kbd_init(ADBBusState *bus); void adb_mouse_init(ADBBusState *bus); -- cgit v1.2.3 From 6b65279459acab4b4ad50451b73436a357e7b1b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 20:33:47 +0000 Subject: comment git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1012 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2a1e73605..14e7943da 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -248,7 +248,7 @@ enum { CC_OP_DECW, CC_OP_DECL, - CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ + CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.msb = C */ CC_OP_SHLW, CC_OP_SHLL, -- cgit v1.2.3 From 354ff22657efbe48b4334bc8a77fa10faa51ca48 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 20:40:05 +0000 Subject: avoid warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1013 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-i386/helper.c b/target-i386/helper.c index 46aa7b1ca..3a6568e05 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1574,6 +1574,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) sp_mask = get_sp_mask(env->segs[R_SS].flags); sp = ESP; ssp = env->segs[R_SS].base; + new_eflags = 0; /* avoid warning */ if (shift == 1) { /* 32 bits */ POPL(ssp, sp, sp_mask, new_eip); -- cgit v1.2.3 From ee2654ac243748284eadd63523c65cae5bfdcf90 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 21:11:45 +0000 Subject: removed unused includes - BSD port git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1014 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.h | 17 +---------------- slirp/slirp_config.h | 8 ++++---- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/slirp/slirp.h b/slirp/slirp.h index 5b9cfdec8..eecef5916 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -121,25 +121,10 @@ int inet_aton _P((const char *cp, struct in_addr *ia)); #endif #include -#if defined(WANT_SYS_IOCTL_H) && defined(HAVE_SYS_IOCTL_H) +#if defined(HAVE_SYS_IOCTL_H) # include -#else -# define WANT_SYS_TERMIOS_H -#endif - -#ifdef WANT_SYS_TERMIOS_H -# ifndef INCLUDED_TERMIOS_H -# ifdef HAVE_TERMIOS_H -# include -# else -# include -# endif -# define INCLUDED_TERMIOS_H -# endif #endif - - #ifdef HAVE_SYS_SELECT_H # include #endif diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h index 51fc95157..5b014f275 100644 --- a/slirp/slirp_config.h +++ b/slirp/slirp_config.h @@ -61,10 +61,13 @@ #define HAVE_STDLIB_H /* Define if you have sys/ioctl.h */ -#undef HAVE_SYS_IOCTL_H +#define HAVE_SYS_IOCTL_H /* Define if you have sys/filio.h */ #undef HAVE_SYS_FILIO_H +#ifdef __APPLE__ +#define HAVE_SYS_FILIO_H +#endif /* Define if you have strerror */ #define HAVE_STRERROR @@ -161,9 +164,6 @@ /* Define if you have memmove */ #define HAVE_MEMMOVE -/* Define if you have */ -#undef HAVE_TERMIOS_H - /* Define if you have gethostid */ #undef HAVE_GETHOSTID -- cgit v1.2.3 From ce93da6ffee7f27044c5b49b096ebdec27075110 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 21:21:31 +0000 Subject: win32 compile git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1015 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 99ed1bd7a..951c9715b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -334,7 +334,7 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); #define THRM2 SPR_ENCODE(1021) #define THRM3 SPR_ENCODE(1022) #define SP SPR_ENCODE(1021) -#define LP SPR_ENCODE(1022) +#define SPR_LP SPR_ENCODE(1022) #define DABR_MASK 0xFFFFFFF8 #define FPECR SPR_ENCODE(1022) #define PIR SPR_ENCODE(1023) -- cgit v1.2.3 From 379ff53dc964ee1dc9442dac230c87a595e06a12 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Jul 2004 22:33:07 +0000 Subject: win32 compile git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1016 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/libslirp.h | 4 +++ slirp/main.h | 1 - slirp/misc.c | 8 +++--- slirp/sbuf.c | 2 +- slirp/slirp.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-- slirp/slirp.h | 38 ++++++++++++++++++++++++++- slirp/slirp_config.h | 18 +++++++++++++ slirp/socket.c | 2 +- slirp/tcp_input.c | 3 --- slirp/tcp_output.c | 3 --- slirp/tcp_subr.c | 6 ++--- slirp/tcp_timer.c | 3 --- slirp/udp.c | 8 +++--- 13 files changed, 142 insertions(+), 26 deletions(-) diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 31ddaea4d..47824b241 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -1,7 +1,11 @@ #ifndef _LIBSLIRP_H #define _LIBSLIRP_H +#ifdef _WIN32 +#include +#else #include +#endif void slirp_init(void); diff --git a/slirp/main.h b/slirp/main.h index dc06d6fe7..2d6f43bcc 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -10,7 +10,6 @@ #endif #define TOWRITEMAX 512 -#define min(x,y) ((x) < (y) ? (x) : (y)) extern struct timeval tt; extern int link_up; diff --git a/slirp/misc.c b/slirp/misc.c index 7f6448dff..64bd9ee2f 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -326,7 +326,7 @@ fork_exec(so, ex, do_pty) bind(s, (struct sockaddr *)&addr, addrlen) < 0 || listen(s, 1) < 0) { lprint("Error: inet socket: %s\n", strerror(errno)); - close(s); + closesocket(s); return 0; } @@ -421,7 +421,7 @@ fork_exec(so, ex, do_pty) * of connect() fail in the child process */ so->s = accept(s, (struct sockaddr *)&addr, &addrlen); - close(s); + closesocket(s); opt = 1; setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); opt = 1; @@ -804,7 +804,7 @@ fd_nonblock(fd) #ifdef FIONBIO int opt = 1; - ioctl(fd, FIONBIO, &opt); + ioctlsocket(fd, FIONBIO, &opt); #else int opt; @@ -821,7 +821,7 @@ fd_block(fd) #ifdef FIONBIO int opt = 0; - ioctl(fd, FIONBIO, &opt); + ioctlsocket(fd, FIONBIO, &opt); #else int opt; diff --git a/slirp/sbuf.c b/slirp/sbuf.c index 04fb97ddc..d6726c94d 100644 --- a/slirp/sbuf.c +++ b/slirp/sbuf.c @@ -106,7 +106,7 @@ sbappend(so, m) * ottherwise it'll arrive out of order, and hence corrupt */ if (!so->so_rcv.sb_cc) - ret = write(so->s, m->m_data, m->m_len); + ret = send(so->s, m->m_data, m->m_len, 0); if (ret <= 0) { /* diff --git a/slirp/slirp.c b/slirp/slirp.c index ad10516a0..405647b48 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -28,8 +28,50 @@ fd_set *global_readfds, *global_writefds, *global_xfds; static int get_dns_addr(struct in_addr *pdns_addr) { - /* XXX: add it */ - return -1; + FIXED_INFO *FixedInfo=NULL; + ULONG BufLen; + DWORD ret; + IP_ADDR_STRING *pIPAddr; + struct in_addr tmp_addr; + + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); + BufLen = sizeof(FIXED_INFO); + + if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + FixedInfo = GlobalAlloc(GPTR, BufLen); + } + + if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { + printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + return -1; + } + + pIPAddr = &(FixedInfo->DnsServerList); + inet_aton(pIPAddr->IpAddress.String, &tmp_addr); + *pdns_addr = tmp_addr; +#if 0 + printf( "DNS Servers:\n" ); + printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String ); + + pIPAddr = FixedInfo -> DnsServerList.Next; + while ( pIPAddr ) { + printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String ); + pIPAddr = pIPAddr ->Next; + } +#endif + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + return 0; } #else @@ -73,10 +115,25 @@ static int get_dns_addr(struct in_addr *pdns_addr) #endif +#ifdef _WIN32 +void slirp_cleanup(void) +{ + WSACleanup(); +} +#endif + void slirp_init(void) { // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); +#ifdef _WIN32 + { + WSADATA Data; + WSAStartup(MAKEWORD(2,0), &Data); + atexit(slirp_cleanup); + } +#endif + link_up = 1; if_init(); @@ -104,6 +161,16 @@ void slirp_init(void) /* * curtime kept to an accuracy of 1ms */ +#ifdef _WIN32 +static void updtime(void) +{ + struct _timeb tb; + + _ftime(&tb); + curtime = (u_int)tb.time * (u_int)1000; + curtime += (u_int)tb.millitm; +} +#else static void updtime(void) { gettimeofday(&tt, 0); @@ -114,6 +181,7 @@ static void updtime(void) if ((tt.tv_usec % 1000) >= 500) curtime++; } +#endif void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds) diff --git a/slirp/slirp.h b/slirp/slirp.h index eecef5916..f5c93c5ee 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -11,6 +11,30 @@ #include "config.h" #include "slirp_config.h" +#ifdef _WIN32 +# include + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; +typedef char *caddr_t; + +# include +# include +# include + +# define EWOULDBLOCK WSAEWOULDBLOCK +# define EINPROGRESS WSAEINPROGRESS +# define ENOTCONN WSAENOTCONN +# define EHOSTUNREACH WSAEHOSTUNREACH +# define ENETUNREACH WSAENETUNREACH +# define ECONNREFUSED WSAECONNREFUSED +#else +# define ioctlsocket ioctl +# define closesocket(s) close(s) +#endif + #include #ifdef HAVE_SYS_BITYPES_H # include @@ -79,7 +103,9 @@ typedef unsigned char u_int8_t; # include #endif +#ifndef _WIN32 #include +#endif #ifndef _P #ifndef NO_PROTOTYPES @@ -89,8 +115,10 @@ typedef unsigned char u_int8_t; #endif #endif +#ifndef _WIN32 #include #include +#endif #ifdef GETTIMEOFDAY_ONE_ARG #define gettimeofday(x, y) gettimeofday(x) @@ -119,7 +147,9 @@ int inet_aton _P((const char *cp, struct in_addr *ia)); #ifdef HAVE_SYS_SIGNAL_H # include #endif +#ifndef _WIN32 #include +#endif #if defined(HAVE_SYS_IOCTL_H) # include @@ -232,8 +262,9 @@ extern int do_echo; inline void remque_32 _P((void *)); #endif -#include +#ifndef _WIN32 #include +#endif #define DEFAULT_BAUD 115200 @@ -292,4 +323,9 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err); #define MAX_MRU 16384 #endif +#ifndef _WIN32 +#define min(x,y) ((x) < (y) ? (x) : (y)) +#define max(x,y) ((x) > (y) ? (x) : (y)) +#endif + #endif diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h index 5b014f275..856c31567 100644 --- a/slirp/slirp_config.h +++ b/slirp/slirp_config.h @@ -61,7 +61,10 @@ #define HAVE_STDLIB_H /* Define if you have sys/ioctl.h */ +#undef HAVE_SYS_IOCTL_H +#ifndef _WIN32 #define HAVE_SYS_IOCTL_H +#endif /* Define if you have sys/filio.h */ #undef HAVE_SYS_FILIO_H @@ -93,6 +96,9 @@ /* Define if iovec needs to be declared */ #undef DECLARE_IOVEC +#ifdef _WIN32 +#define DECLARE_IOVEC +#endif /* Define if a declaration of sprintf/fprintf is needed */ #undef DECLARE_SPRINTF @@ -101,13 +107,19 @@ #undef HAVE_SYS_WAIT_H /* Define if you have sys/select.h */ +#undef HAVE_SYS_SELECT_H +#ifndef _WIN32 #define HAVE_SYS_SELECT_H +#endif /* Define if you have strings.h */ #define HAVE_STRING_H /* Define if you have arpa/inet.h */ +#undef HAVE_ARPA_INET_H +#ifndef _WIN32 #define HAVE_ARPA_INET_H +#endif /* Define if you have sys/signal.h */ #undef HAVE_SYS_SIGNAL_H @@ -147,7 +159,10 @@ #undef HAVE_SRANDOM /* Define if you have inet_aton */ +#undef HAVE_INET_ATON +#ifndef _WIN32 #define HAVE_INET_ATON +#endif /* Define if you have setenv */ #undef HAVE_SETENV @@ -169,6 +184,9 @@ /* Define if you DON'T have unix-domain sockets */ #undef NO_UNIX_SOCKETS +#ifdef _WIN32 +#define NO_UNIX_SOCKETS +#endif /* Define if gettimeofday only takes one argument */ #undef GETTIMEOFDAY_ONE_ARG diff --git a/slirp/socket.c b/slirp/socket.c index 396fb4ac7..7286b5e19 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -418,7 +418,7 @@ sorecvfrom(so) */ len = M_FREEROOM(m); /* if (so->so_fport != htons(53)) { */ - ioctl(so->s, FIONREAD, &n); + ioctlsocket(so->s, FIONREAD, &n); if (n > len) { n = (m->m_data - m->m_dat) + m->m_len + n + 1; diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index eeee98597..4f74d0cdb 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -47,9 +47,6 @@ struct socket tcb; -#define min(x,y) ((x) < (y) ? (x) : (y)) -#define max(x,y) ((x) > (y) ? (x) : (y)) - int tcprexmtthresh = 3; struct socket *tcp_last_so = &tcb; diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c index 0f05dfadc..b79bcf127 100644 --- a/slirp/tcp_output.c +++ b/slirp/tcp_output.c @@ -44,9 +44,6 @@ #include -#define max(x,y) ((x) > (y) ? (x) : (y)) -#define min(x,y) ((x) < (y) ? (x) : (y)) - /* * Since this is only used in "stats socket", we give meaning * names instead of the REAL names diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 07cfc0e4f..c29dc604f 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -301,7 +301,7 @@ tcp_close(tp) /* clobber input socket cache if we're closing the cached connection */ if (so == tcp_last_so) tcp_last_so = &tcb; - close(so->s); + closesocket(so->s); sbfree(&so->so_rcv); sbfree(&so->so_snd); sofree(so); @@ -477,7 +477,7 @@ tcp_connect(inso) } else { if ((so = socreate()) == NULL) { /* If it failed, get rid of the pending connection */ - close(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); + closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); return; } if (tcp_attach(so) < 0) { @@ -508,7 +508,7 @@ tcp_connect(inso) /* Close the accept() socket, set right state */ if (inso->so_state & SS_FACCEPTONCE) { - close(so->s); /* If we only accept once, close the accept() socket */ + closesocket(so->s); /* If we only accept once, close the accept() socket */ so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ /* if it's not FACCEPTONCE, it's already NOFDREF */ } diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c index 166979a3e..d3146db58 100644 --- a/slirp/tcp_timer.c +++ b/slirp/tcp_timer.c @@ -36,9 +36,6 @@ #include -#define max(x,y) ((x) > (y) ? (x) : (y)) -#define min(x,y) ((x) < (y) ? (x) : (y)) - int tcp_keepidle = TCPTV_KEEP_IDLE; int tcp_keepintvl = TCPTV_KEEPINTVL; int tcp_maxidle; diff --git a/slirp/udp.c b/slirp/udp.c index 76a4fcc97..67a05090f 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -329,7 +329,7 @@ udp_attach(so) addr.sin_addr.s_addr = INADDR_ANY; if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { int lasterrno=errno; - close(so->s); + closesocket(so->s); so->s=-1; errno=lasterrno; } else { @@ -345,7 +345,7 @@ void udp_detach(so) struct socket *so; { - close(so->s); + closesocket(so->s); /* if (so->so_m) m_free(so->so_m); done by sofree */ sofree(so); @@ -527,7 +527,7 @@ struct cu_header { addr.sin_port = htons(518); sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *) &addr, sizeof(addr)); - close(s) ; + closesocket(s) ; omsg->type = nmsg->type = ANNOUNCE; OTOSIN(omsg, ctl_addr)->sin_port = temp_port; @@ -558,7 +558,7 @@ struct cu_header { addr.sin_port = htons(518); sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *)&addr, sizeof(addr)); - close(s); + closesocket(s); OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; -- cgit v1.2.3 From 3db38e87a0e90d4fd2d8c999434feaac6ddb1289 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:19:55 +0000 Subject: virtual console support - slirp for win32 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1017 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index 3303b0ce5..d565e1dd9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -162,7 +162,7 @@ endif DEFINES+=-D_GNU_SOURCE LIBS+=-lm ifdef CONFIG_WIN32 -LIBS+=-lwinmm +LIBS+=-lwinmm -lws2_32 -liphlpapi endif # profiling code @@ -237,7 +237,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o pci.o +VL_OBJS=vl.o osdep.o block.o monitor.o pci.o console.o ifeq ($(TARGET_ARCH), i386) # Hardware support -- cgit v1.2.3 From 450e18b8b82121ff8ce5b6c823b92d87679752ef Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:20:11 +0000 Subject: slirp for win32 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1018 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index d93d78ccc..9cf6a2ec5 100755 --- a/configure +++ b/configure @@ -163,7 +163,6 @@ if test "$mingw32" = "yes" ; then target_list="i386-softmmu ppc-softmmu" EXESUF=".exe" gdbstub="no" - slirp="no" fi if test -z "$cross_prefix" ; then -- cgit v1.2.3 From d1d9f42119b2eb10e86f062e9e62dfcec3e199b1 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:20:55 +0000 Subject: compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1019 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 0f317574f..053c0cc5d 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -903,7 +903,7 @@ typedef struct ucontext SIGCONTEXT; # define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */ #endif /* __APPLE__ */ -int cpu_signal_handler(int host_signum, siginfo *info, +int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) { struct ucontext *uc = puc; -- cgit v1.2.3 From 81d0912d2d221c41d649d2c36812afddf74634d2 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:21:37 +0000 Subject: completion support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1020 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 9 ++ monitor.c | 452 ++++++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 348 insertions(+), 113 deletions(-) diff --git a/block.c b/block.c index e71adda19..894656402 100644 --- a/block.c +++ b/block.c @@ -470,6 +470,15 @@ BlockDriverState *bdrv_find(const char *name) 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); + } +} + void bdrv_info(void) { BlockDriverState *bs; diff --git a/monitor.c b/monitor.c index 3c55c6265..47b047a49 100644 --- a/monitor.c +++ b/monitor.c @@ -23,8 +23,10 @@ */ #include "vl.h" #include "disas.h" +#include //#define DEBUG +//#define DEBUG_COMPLETION #ifndef offsetof #define offsetof(type, field) ((size_t) &((type *)0)->field) @@ -32,6 +34,7 @@ #define TERM_CMD_BUF_SIZE 4095 #define TERM_MAX_CMDS 64 +#define NB_COMPLETIONS_MAX 256 #define IS_NORM 0 #define IS_ESC 1 @@ -42,16 +45,28 @@ static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1]; static int term_cmd_buf_index; static int term_cmd_buf_size; + +static char term_last_cmd_buf[TERM_CMD_BUF_SIZE + 1]; +static int term_last_cmd_buf_index; +static int term_last_cmd_buf_size; + static int term_esc_state; static int term_esc_param; static char *term_history[TERM_MAX_CMDS]; static int term_hist_entry; +static CharDriverState *monitor_hd; + +static int nb_completions; +static int completion_index; +static char *completions[NB_COMPLETIONS_MAX]; + /* * Supported types: * * 'F' filename + * 'B' block device name * 's' string (accept optional quote) * 'i' integer * '/' optional gdb-like print format (like "/10x") @@ -71,17 +86,20 @@ typedef struct term_cmd_t { static term_cmd_t term_cmds[]; static term_cmd_t info_cmds[]; +static void add_completion(const char *str); + void term_printf(const char *fmt, ...) { + char buf[4096]; va_list ap; va_start(ap, fmt); - vprintf(fmt, ap); + vsnprintf(buf, sizeof(buf), fmt, ap); + qemu_chr_write(monitor_hd, buf, strlen(buf)); va_end(ap); } void term_flush(void) { - fflush(stdout); } static int compare_cmd(const char *name, const char *list) @@ -232,8 +250,6 @@ static void do_eject(int force, const char *filename) { BlockDriverState *bs; - term_printf("%d %s\n", force, filename); - bs = bdrv_find(filename); if (!bs) { term_printf("device not found\n"); @@ -674,9 +690,9 @@ static term_cmd_t term_cmds[] = { "subcommand", "show various information about the system state" }, { "q|quit", "", do_quit, "", "quit the emulator" }, - { "eject", "-fs", do_eject, + { "eject", "-fB", do_eject, "[-f] device", "eject a removable media (use -f to force it)" }, - { "change", "sF", do_change, + { "change", "BF", do_change, "device filename", "change a removable media" }, { "screendump", "F", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, @@ -953,6 +969,16 @@ static int expr_unary(void) } next(); break; + case '\'': + pch++; + if (*pch == '\0') + expr_error("character constant expected"); + n = *pch; + pch++; + if (*pch != '\'') + expr_error("missing terminating \' character"); + next(); + break; case '$': { char buf[128], *q; @@ -1088,15 +1114,16 @@ static int get_str(char *buf, int buf_size, const char **pp) char *q; int c; + q = buf; p = *pp; while (isspace(*p)) p++; if (*p == '\0') { fail: + *q = '\0'; *pp = p; return -1; } - q = buf; if (*p == '\"') { p++; while (*p != '\0' && *p != '\"') { @@ -1140,8 +1167,8 @@ static int get_str(char *buf, int buf_size, const char **pp) } p++; } - *q = '\0'; } + *q = '\0'; *pp = p; return 0; } @@ -1204,6 +1231,7 @@ static void term_handle_command(const char *cmdline) typestr++; switch(c) { case 'F': + case 'B': case 's': { int ret; @@ -1221,10 +1249,17 @@ static void term_handle_command(const char *cmdline) } ret = get_str(buf, sizeof(buf), &p); if (ret < 0) { - if (c == 'F') + switch(c) { + case 'F': term_printf("%s: filename expected\n", cmdname); - else + break; + case 'B': + term_printf("%s: block device name expected\n", cmdname); + break; + default: term_printf("%s: string expected\n", cmdname); + break; + } goto fail; } str = qemu_malloc(strlen(buf) + 1); @@ -1432,19 +1467,232 @@ static void term_handle_command(const char *cmdline) return; } -static void term_show_prompt(void) +static void cmd_completion(const char *name, const char *list) +{ + const char *p, *pstart; + char cmd[128]; + int len; + + p = list; + for(;;) { + pstart = p; + p = strchr(p, '|'); + if (!p) + p = pstart + strlen(pstart); + len = p - pstart; + if (len > sizeof(cmd) - 2) + len = sizeof(cmd) - 2; + memcpy(cmd, pstart, len); + cmd[len] = '\0'; + if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) { + add_completion(cmd); + } + if (*p == '\0') + break; + p++; + } +} + +static void file_completion(const char *input) +{ + DIR *ffs; + struct dirent *d; + char path[1024]; + char file[1024], file_prefix[1024]; + int input_path_len; + const char *p; + + p = strrchr(input, '/'); + if (!p) { + input_path_len = 0; + pstrcpy(file_prefix, sizeof(file_prefix), input); + strcpy(path, "."); + } else { + input_path_len = p - input + 1; + memcpy(path, input, input_path_len); + if (input_path_len > sizeof(path) - 1) + input_path_len = sizeof(path) - 1; + path[input_path_len] = '\0'; + pstrcpy(file_prefix, sizeof(file_prefix), p + 1); + } +#ifdef DEBUG_COMPLETION + term_printf("input='%s' path='%s' prefix='%s'\n", input, path, file_prefix); +#endif + ffs = opendir(path); + if (!ffs) + return; + for(;;) { + struct stat sb; + d = readdir(ffs); + if (!d) + break; + if (strstart(d->d_name, file_prefix, NULL)) { + memcpy(file, input, input_path_len); + strcpy(file + input_path_len, d->d_name); + /* stat the file to find out if it's a directory. + * In that case add a slash to speed up typing long paths + */ + stat(file, &sb); + if(S_ISDIR(sb.st_mode)) + strcat(file, "/"); + add_completion(file); + } + } + closedir(ffs); +} + +static void block_completion_it(void *opaque, const char *name) +{ + const char *input = opaque; + + if (input[0] == '\0' || + !strncmp(name, (char *)input, strlen(input))) { + add_completion(name); + } +} + +/* NOTE: this parser is an approximate form of the real command parser */ +static void parse_cmdline(const char *cmdline, + int *pnb_args, char **args) +{ + const char *p; + int nb_args, ret; + char buf[1024]; + + p = cmdline; + nb_args = 0; + for(;;) { + while (isspace(*p)) + p++; + if (*p == '\0') + break; + if (nb_args >= MAX_ARGS) + break; + ret = get_str(buf, sizeof(buf), &p); + args[nb_args] = qemu_strdup(buf); + nb_args++; + if (ret < 0) + break; + } + *pnb_args = nb_args; +} + +static void find_completion(const char *cmdline) +{ + const char *cmdname; + char *args[MAX_ARGS]; + int nb_args, i, len; + const char *ptype, *str; + term_cmd_t *cmd; + + parse_cmdline(cmdline, &nb_args, args); +#ifdef DEBUG_COMPLETION + for(i = 0; i < nb_args; i++) { + term_printf("arg%d = '%s'\n", i, (char *)args[i]); + } +#endif + + /* if the line ends with a space, it means we want to complete the + next arg */ + len = strlen(cmdline); + if (len > 0 && isspace(cmdline[len - 1])) { + if (nb_args >= MAX_ARGS) + return; + args[nb_args++] = qemu_strdup(""); + } + if (nb_args <= 1) { + /* command completion */ + if (nb_args == 0) + cmdname = ""; + else + cmdname = args[0]; + completion_index = strlen(cmdname); + for(cmd = term_cmds; cmd->name != NULL; cmd++) { + cmd_completion(cmdname, cmd->name); + } + } else { + /* find the command */ + for(cmd = term_cmds; cmd->name != NULL; cmd++) { + if (compare_cmd(args[0], cmd->name)) + goto found; + } + return; + found: + ptype = cmd->args_type; + for(i = 0; i < nb_args - 2; i++) { + if (*ptype != '\0') { + ptype++; + while (*ptype == '?') + ptype++; + } + } + str = args[nb_args - 1]; + switch(*ptype) { + case 'F': + /* file completion */ + completion_index = strlen(str); + file_completion(str); + break; + case 'B': + /* block device name completion */ + completion_index = strlen(str); + bdrv_iterate(block_completion_it, (void *)str); + break; + default: + break; + } + } + for(i = 0; i < nb_args; i++) + qemu_free(args[i]); +} + +static void term_show_prompt2(void) { term_printf("(qemu) "); fflush(stdout); + term_last_cmd_buf_index = 0; + term_last_cmd_buf_size = 0; + term_esc_state = IS_NORM; +} + +static void term_show_prompt(void) +{ + term_show_prompt2(); term_cmd_buf_index = 0; term_cmd_buf_size = 0; - term_esc_state = IS_NORM; } -static void term_print_cmdline (const char *cmdline) +/* update the displayed command line */ +static void term_update(void) { - term_show_prompt(); - term_printf("%s", cmdline); + int i, delta; + + if (term_cmd_buf_size != term_last_cmd_buf_size || + memcmp(term_cmd_buf, term_last_cmd_buf, term_cmd_buf_size) != 0) { + for(i = 0; i < term_last_cmd_buf_index; i++) { + term_printf("\033[D"); + } + term_cmd_buf[term_cmd_buf_size] = '\0'; + term_printf("%s", term_cmd_buf); + term_printf("\033[K"); + memcpy(term_last_cmd_buf, term_cmd_buf, term_cmd_buf_size); + term_last_cmd_buf_size = term_cmd_buf_size; + term_last_cmd_buf_index = term_cmd_buf_size; + } + if (term_cmd_buf_index != term_last_cmd_buf_index) { + delta = term_cmd_buf_index - term_last_cmd_buf_index; + if (delta > 0) { + for(i = 0;i < delta; i++) { + term_printf("\033[C"); + } + } else { + delta = -delta; + for(i = 0;i < delta; i++) { + term_printf("\033[D"); + } + } + term_last_cmd_buf_index = term_cmd_buf_index; + } term_flush(); } @@ -1456,9 +1704,7 @@ static void term_insert_char(int ch) term_cmd_buf_size - term_cmd_buf_index); term_cmd_buf[term_cmd_buf_index] = ch; term_cmd_buf_size++; - term_printf("\033[@%c", ch); term_cmd_buf_index++; - term_flush(); } } @@ -1466,8 +1712,6 @@ static void term_backward_char(void) { if (term_cmd_buf_index > 0) { term_cmd_buf_index--; - term_printf("\033[D"); - term_flush(); } } @@ -1475,8 +1719,6 @@ static void term_forward_char(void) { if (term_cmd_buf_index < term_cmd_buf_size) { term_cmd_buf_index++; - term_printf("\033[C"); - term_flush(); } } @@ -1486,9 +1728,7 @@ static void term_delete_char(void) memmove(term_cmd_buf + term_cmd_buf_index, term_cmd_buf + term_cmd_buf_index + 1, term_cmd_buf_size - term_cmd_buf_index - 1); - term_printf("\033[P"); term_cmd_buf_size--; - term_flush(); } } @@ -1502,14 +1742,12 @@ static void term_backspace(void) static void term_bol(void) { - while (term_cmd_buf_index > 0) - term_backward_char(); + term_cmd_buf_index = 0; } static void term_eol(void) { - while (term_cmd_buf_index < term_cmd_buf_size) - term_forward_char(); + term_cmd_buf_index = term_cmd_buf_size; } static void term_up_char(void) @@ -1530,8 +1768,6 @@ static void term_up_char(void) if (term_hist_entry >= 0) { pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), term_history[term_hist_entry]); - term_printf("\n"); - term_print_cmdline(term_cmd_buf); term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); } } @@ -1546,8 +1782,6 @@ static void term_down_char(void) } else { term_hist_entry = -1; } - term_printf("\n"); - term_print_cmdline(term_cmd_buf); term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); } @@ -1600,6 +1834,67 @@ static void term_hist_add(const char *cmdline) term_hist_entry = -1; } +/* completion support */ + +static void add_completion(const char *str) +{ + if (nb_completions < NB_COMPLETIONS_MAX) { + completions[nb_completions++] = qemu_strdup(str); + } +} + +static void term_completion(void) +{ + int len, i, j, max_width, nb_cols; + char *cmdline; + + nb_completions = 0; + + cmdline = qemu_malloc(term_cmd_buf_index + 1); + if (!cmdline) + return; + memcpy(cmdline, term_cmd_buf, term_cmd_buf_index); + cmdline[term_cmd_buf_index] = '\0'; + find_completion(cmdline); + qemu_free(cmdline); + + /* no completion found */ + if (nb_completions <= 0) + return; + if (nb_completions == 1) { + len = strlen(completions[0]); + for(i = completion_index; i < len; i++) { + term_insert_char(completions[0][i]); + } + /* extra space for next argument. XXX: make it more generic */ + if (len > 0 && completions[0][len - 1] != '/') + term_insert_char(' '); + } else { + term_printf("\n"); + max_width = 0; + for(i = 0; i < nb_completions; i++) { + len = strlen(completions[i]); + if (len > max_width) + max_width = len; + } + max_width += 2; + if (max_width < 10) + max_width = 10; + else if (max_width > 80) + max_width = 80; + nb_cols = 80 / max_width; + j = 0; + for(i = 0; i < nb_completions; i++) { + term_printf("%-*s", max_width, completions[i]); + if (++j == nb_cols || i == (nb_completions - 1)) { + term_printf("\n"); + j = 0; + } + } + term_show_prompt2(); + } +} + /* return true if command handled */ static void term_handle_byte(int ch) { @@ -1609,9 +1904,15 @@ static void term_handle_byte(int ch) case 1: term_bol(); break; + case 4: + term_delete_char(); + break; case 5: term_eol(); break; + case 9: + term_completion(); + break; case 10: case 13: term_cmd_buf[term_cmd_buf_size] = '\0'; @@ -1684,104 +1985,29 @@ static void term_handle_byte(int ch) the_end: break; } -} - -/*************************************************************/ -/* serial console support */ - -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ - -static int term_got_escape, term_command; - -void term_print_help(void) -{ - term_printf("\n" - "C-a h print this help\n" - "C-a x exit emulatior\n" - "C-a s save disk data back to file (if -snapshot)\n" - "C-a b send break (magic sysrq)\n" - "C-a c switch between console and monitor\n" - "C-a C-a send C-a\n" - ); -} - -/* called when a char is received */ -static void term_received_byte(int ch) -{ - if (!serial_console) { - /* if no serial console, handle every command */ - term_handle_byte(ch); - } else { - if (term_got_escape) { - term_got_escape = 0; - switch(ch) { - case 'h': - term_print_help(); - break; - case 'x': - exit(0); - break; - case 's': - { - int i; - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) - bdrv_commit(bs_table[i]); - } - } - break; - case 'b': - if (serial_console) - serial_receive_break(serial_console); - break; - case 'c': - if (!term_command) { - term_show_prompt(); - term_command = 1; - } else { - term_command = 0; - } - break; - case TERM_ESCAPE: - goto send_char; - } - } else if (ch == TERM_ESCAPE) { - term_got_escape = 1; - } else { - send_char: - if (term_command) { - term_handle_byte(ch); - } else { - if (serial_console) - serial_receive_byte(serial_console, ch); - } - } - } + term_update(); } static int term_can_read(void *opaque) { - if (serial_console) { - return serial_can_receive(serial_console); - } else { - return 128; - } + return 128; } static void term_read(void *opaque, const uint8_t *buf, int size) { int i; for(i = 0; i < size; i++) - term_received_byte(buf[i]); + term_handle_byte(buf[i]); } -void monitor_init(void) +void monitor_init(CharDriverState *hd, int show_banner) { - if (!serial_console) { + monitor_hd = hd; + if (show_banner) { term_printf("QEMU %s monitor - type 'help' for more information\n", QEMU_VERSION); term_show_prompt(); } term_hist_entry = -1; - qemu_add_fd_read_handler(0, term_can_read, term_read, NULL); + qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL); } -- cgit v1.2.3 From 2571929a77c2d1c77c9fd28341994eb69acda7b6 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:21:57 +0000 Subject: added qemu_strdup() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1021 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 10 ++++++++++ osdep.h | 1 + 2 files changed, 11 insertions(+) diff --git a/osdep.c b/osdep.c index 83f5a77cc..76bfa2663 100644 --- a/osdep.c +++ b/osdep.c @@ -294,6 +294,16 @@ void *qemu_mallocz(size_t size) return ptr; } +char *qemu_strdup(const char *str) +{ + char *ptr; + ptr = qemu_malloc(strlen(str) + 1); + if (!ptr) + return NULL; + strcpy(ptr, str); + return ptr; +} + /****************************************************************/ /* printf support */ diff --git a/osdep.h b/osdep.h index 1c14de4c5..dfe80bcf9 100644 --- a/osdep.h +++ b/osdep.h @@ -10,6 +10,7 @@ void qemu_printf(const char *fmt, ...); void *qemu_malloc(size_t size); void *qemu_mallocz(size_t size); void qemu_free(void *ptr); +char *qemu_strdup(const char *str); void *get_mmap_addr(unsigned long size); -- cgit v1.2.3 From 457831f4bcf20d1fd5d80d7a0b946bdaf6f56059 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:22:33 +0000 Subject: virtual console support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1022 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/sdl.c b/sdl.c index e4e6bc43a..fc23ea9ea 100644 --- a/sdl.c +++ b/sdl.c @@ -65,6 +65,8 @@ static void sdl_resize(DisplayState *ds, int w, int h) ds->data = screen->pixels; ds->linesize = screen->pitch; ds->depth = screen->format->BitsPerPixel; + ds->width = w; + ds->height = h; } #ifdef CONFIG_SDL_GENERIC_KBD @@ -408,7 +410,9 @@ static void sdl_refresh(DisplayState *ds) sdl_update_caption(); } - vga_update_display(); + if (is_active_console(vga_console)) + vga_update_display(); + while (SDL_PollEvent(ev)) { switch (ev->type) { case SDL_VIDEOEXPOSE: @@ -420,19 +424,68 @@ static void sdl_refresh(DisplayState *ds) mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) == (KMOD_LSHIFT | KMOD_LCTRL); gui_key_modifier_pressed = mod_state; - if (gui_key_modifier_pressed && - ev->key.keysym.sym == SDLK_f) { - gui_keysym = ev->key.keysym.sym; + if (gui_key_modifier_pressed) { + switch(ev->key.keysym.sym) { + case SDLK_f: + toggle_full_screen(ds); + gui_keysym = 1; + break; + case SDLK_F1 ... SDLK_F12: + console_select(ev->key.keysym.sym - SDLK_F1); + if (is_active_console(vga_console)) { + /* tell the vga console to redisplay itself */ + vga_invalidate_display(); + } else { + /* display grab if going to a text console */ + if (gui_grab) + sdl_grab_end(); + } + gui_keysym = 1; + break; + default: + break; + } + } + if (!is_active_console(vga_console)) { + int keysym; + keysym = 0; + if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { + switch(ev->key.keysym.sym) { + case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break; + case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break; + case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break; + case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break; + case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break; + case SDLK_END: keysym = QEMU_KEY_CTRL_END; break; + case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break; + case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break; + default: break; + } + } else { + switch(ev->key.keysym.sym) { + case SDLK_UP: keysym = QEMU_KEY_UP; break; + case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break; + case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break; + case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break; + case SDLK_HOME: keysym = QEMU_KEY_HOME; break; + case SDLK_END: keysym = QEMU_KEY_END; break; + case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break; + case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break; + case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break; case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break; + default: break; + } + } + if (keysym) { + kbd_put_keysym(keysym); + } else if (ev->key.keysym.unicode != 0) { + kbd_put_keysym(ev->key.keysym.unicode); + } } } else if (ev->type == SDL_KEYUP) { mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)); if (!mod_state) { if (gui_key_modifier_pressed) { - switch(gui_keysym) { - case SDLK_f: - toggle_full_screen(ds); - break; - case 0: + if (gui_keysym == 0) { /* exit/enter grab if pressing Ctrl-Shift */ if (!gui_grab) sdl_grab_start(); @@ -445,7 +498,8 @@ static void sdl_refresh(DisplayState *ds) } } } - sdl_process_key(&ev->key); + if (is_active_console(vga_console)) + sdl_process_key(&ev->key); break; case SDL_QUIT: qemu_system_shutdown_request(); @@ -495,7 +549,6 @@ void sdl_display_init(DisplayState *ds) fprintf(stderr, "Could not initialize SDL - exiting\n"); exit(1); } - #ifndef _WIN32 /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */ signal(SIGINT, SIG_DFL); @@ -509,6 +562,7 @@ void sdl_display_init(DisplayState *ds) sdl_resize(ds, 640, 400); sdl_update_caption(); SDL_EnableKeyRepeat(250, 50); + SDL_EnableUNICODE(1); gui_grab = 0; atexit(sdl_cleanup); -- cgit v1.2.3 From 82c643ff50dfdd82b89e9c5361fd132c79e0872c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:28:13 +0000 Subject: char device support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1023 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 5 +- hw/ppc_chrp.c | 5 +- hw/ppc_prep.c | 5 +- hw/serial.c | 41 +++---- vl.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ vl.h | 81 ++++++++++++-- 6 files changed, 408 insertions(+), 76 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 11b282792..0fd7b87b2 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -324,7 +324,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; - int ret, linux_boot, initrd_size, i, nb_nics1, fd; + int ret, linux_boot, initrd_size, i, nb_nics1; unsigned long bios_offset, vga_bios_offset; int bios_size, isa_bios_size; PCIBus *pci_bus; @@ -471,8 +471,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, pic_init(); pit = pit_init(0x40, 0); - fd = serial_open_device(); - serial_init(0x3f8, 4, fd); + serial_init(0x3f8, 4, serial_hd); if (pci_enabled) { for(i = 0; i < nb_nics; i++) { diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 93835322f..f532fe101 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -126,7 +126,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, openpic_t *openpic; m48t59_t *nvram; int PPC_io_memory; - int ret, linux_boot, i, fd; + int ret, linux_boot, i; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; PCIBus *pci_bus; @@ -200,8 +200,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pic_init(); /* XXX: use Mac Serial port */ - fd = serial_open_device(); - serial_init(0x3f8, 4, fd); + serial_init(0x3f8, 4, serial_hd); for(i = 0; i < nb_nics; i++) { pci_ne2000_init(pci_bus, &nd_table[i]); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 88dcac838..eeb5a3609 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -415,7 +415,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, char buf[1024]; m48t59_t *nvram; int PPC_io_memory; - int ret, linux_boot, i, nb_nics1, fd; + int ret, linux_boot, i, nb_nics1; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; PCIBus *pci_bus; @@ -492,8 +492,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, pic_init(); // pit = pit_init(0x40, 0); - fd = serial_open_device(); - serial_init(0x3f8, 4, fd); + serial_init(0x3f8, 4, serial_hd); nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; diff --git a/hw/serial.c b/hw/serial.c index 3cf43f4d1..0fc1ccb9d 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -84,7 +84,7 @@ struct SerialState { it can be reset while reading iir */ int thr_ipending; int irq; - int out_fd; + CharDriverState *chr; }; static void serial_update_irq(SerialState *s) @@ -107,7 +107,6 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) { SerialState *s = opaque; unsigned char ch; - int ret; addr &= 7; #ifdef DEBUG_SERIAL @@ -122,13 +121,8 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->thr_ipending = 0; s->lsr &= ~UART_LSR_THRE; serial_update_irq(s); - - if (s->out_fd >= 0) { - ch = val; - do { - ret = write(s->out_fd, &ch, 1); - } while (ret != 1); - } + ch = val; + qemu_chr_write(s->chr, &ch, 1); s->thr_ipending = 1; s->lsr |= UART_LSR_THRE; s->lsr |= UART_LSR_TEMT; @@ -223,19 +217,19 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) return ret; } -int serial_can_receive(SerialState *s) +static int serial_can_receive(SerialState *s) { return !(s->lsr & UART_LSR_DR); } -void serial_receive_byte(SerialState *s, int ch) +static void serial_receive_byte(SerialState *s, int ch) { s->rbr = ch; s->lsr |= UART_LSR_DR; serial_update_irq(s); } -void serial_receive_break(SerialState *s) +static void serial_receive_break(SerialState *s) { s->rbr = 0; s->lsr |= UART_LSR_BI | UART_LSR_DR; @@ -254,8 +248,15 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) serial_receive_byte(s, buf[0]); } +static void serial_event(void *opaque, int event) +{ + SerialState *s = opaque; + if (event == CHR_EVENT_BREAK) + serial_receive_break(s); +} + /* If fd is zero, it means that the serial device uses the console */ -SerialState *serial_init(int base, int irq, int fd) +SerialState *serial_init(int base, int irq, CharDriverState *chr) { SerialState *s; @@ -268,16 +269,8 @@ SerialState *serial_init(int base, int irq, int fd) register_ioport_write(base, 8, 1, serial_ioport_write, s); register_ioport_read(base, 8, 1, serial_ioport_read, s); - - if (fd < 0) { - /* no associated device */ - s->out_fd = -1; - } else if (fd != 0) { - qemu_add_fd_read_handler(fd, serial_can_receive1, serial_receive1, s); - s->out_fd = fd; - } else { - serial_console = s; - s->out_fd = 1; - } + s->chr = chr; + qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s); + qemu_chr_add_event_handler(chr, serial_event); return s; } diff --git a/vl.c b/vl.c index 81782b085..3d64188b6 100644 --- a/vl.c +++ b/vl.c @@ -128,7 +128,6 @@ static char network_script[1024]; int pit_min_timer_count = 0; int nb_nics; NetDriverState nd_table[MAX_NICS]; -SerialState *serial_console; QEMUTimer *gui_timer; int vm_running; int audio_enabled = 0; @@ -139,6 +138,7 @@ int cirrus_vga_enabled = 1; int graphic_width = 800; int graphic_height = 600; int graphic_depth = 15; +TextConsole *vga_console; /***********************************************************/ /* x86 ISA bus support */ @@ -298,6 +298,22 @@ char *pstrcat(char *buf, int buf_size, const char *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; +} + /* return the size or -1 if error */ int get_image_size(const char *filename) { @@ -949,42 +965,273 @@ void quit_timers(void) } /***********************************************************/ -/* serial device */ +/* character device */ -#ifdef _WIN32 +int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) +{ + return s->chr_write(s, buf, len); +} -int serial_open_device(void) +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) { - return -1; + char buf[4096]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + qemu_chr_write(s, buf, strlen(buf)); + va_end(ap); } -#else +void qemu_chr_add_read_handler(CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + s->chr_add_read_handler(s, fd_can_read, fd_read, opaque); +} + +void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event) +{ + s->chr_event = chr_event; +} -int serial_open_device(void) +static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { - if (serial_console == NULL && nographic) { - /* use console for serial port */ - return 0; + return len; +} + +static void null_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ +} + +CharDriverState *qemu_chr_open_null(void) +{ + CharDriverState *chr; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + chr->chr_write = null_chr_write; + chr->chr_add_read_handler = null_chr_add_read_handler; + return chr; +} + +#ifndef _WIN32 + +typedef struct { + int fd_in, fd_out; + /* for nographic stdio only */ + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *fd_opaque; +} FDCharDriver; + +#define STDIO_MAX_CLIENTS 2 + +static int stdio_nb_clients; +static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; + +static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + FDCharDriver *s = chr->opaque; + return write(s->fd_out, buf, len); +} + +static void fd_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + FDCharDriver *s = chr->opaque; + + if (nographic && s->fd_in == 0) { + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->fd_opaque = opaque; } else { -#if 0 - char slave_name[1024]; - int master_fd, slave_fd; - - /* Not satisfying */ - if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { - fprintf(stderr, "warning: could not create pseudo terminal for serial port\n"); - return -1; + qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque); + } +} + +/* open a character device to a unix fd */ +CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) +{ + CharDriverState *chr; + FDCharDriver *s; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(FDCharDriver)); + if (!s) { + free(chr); + return NULL; + } + s->fd_in = fd_in; + s->fd_out = fd_out; + chr->opaque = s; + chr->chr_write = fd_chr_write; + chr->chr_add_read_handler = fd_chr_add_read_handler; + return chr; +} + +/* for STDIO, we handle the case where several clients use it + (nographic mode) */ + +#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ + +static int term_got_escape, client_index; + +void term_print_help(void) +{ + printf("\n" + "C-a h print this help\n" + "C-a x exit emulator\n" + "C-a s save disk data back to file (if -snapshot)\n" + "C-a b send break (magic sysrq)\n" + "C-a c switch between console and monitor\n" + "C-a C-a send C-a\n" + ); +} + +/* called when a char is received */ +static void stdio_received_byte(int ch) +{ + if (term_got_escape) { + term_got_escape = 0; + switch(ch) { + case 'h': + term_print_help(); + break; + case 'x': + exit(0); + break; + case 's': + { + int i; + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) + bdrv_commit(bs_table[i]); + } + } + break; + case 'b': + if (client_index < stdio_nb_clients) { + CharDriverState *chr; + FDCharDriver *s; + + chr = stdio_clients[client_index]; + s = chr->opaque; + chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK); + } + break; + case 'c': + client_index++; + if (client_index >= stdio_nb_clients) + client_index = 0; + if (client_index == 0) { + /* send a new line in the monitor to get the prompt */ + ch = '\r'; + goto send_char; + } + break; + case TERM_ESCAPE: + goto send_char; + } + } else if (ch == TERM_ESCAPE) { + term_got_escape = 1; + } else { + send_char: + if (client_index < stdio_nb_clients) { + uint8_t buf[1]; + CharDriverState *chr; + FDCharDriver *s; + + chr = stdio_clients[client_index]; + s = chr->opaque; + buf[0] = ch; + /* XXX: should queue the char if the device is not + ready */ + if (s->fd_can_read(s->fd_opaque) > 0) + s->fd_read(s->fd_opaque, buf, 1); } - fprintf(stderr, "Serial port redirected to %s\n", slave_name); - return master_fd; -#else - return -1; -#endif } } +static int stdio_can_read(void *opaque) +{ + /* XXX: not strictly correct */ + return 1; +} + +static void stdio_read(void *opaque, const uint8_t *buf, int size) +{ + int i; + for(i = 0; i < size; i++) + stdio_received_byte(buf[i]); +} + +CharDriverState *qemu_chr_open_stdio(void) +{ + CharDriverState *chr; + + if (nographic) { + if (stdio_nb_clients >= STDIO_MAX_CLIENTS) + return NULL; + chr = qemu_chr_open_fd(0, 1); + if (stdio_nb_clients == 0) + qemu_add_fd_read_handler(0, stdio_can_read, stdio_read, NULL); + client_index = stdio_nb_clients; + } else { + if (stdio_nb_clients != 0) + return NULL; + chr = qemu_chr_open_fd(0, 1); + } + stdio_clients[stdio_nb_clients++] = chr; + return chr; +} + +#if defined(__linux__) +CharDriverState *qemu_chr_open_pty(void) +{ + char slave_name[1024]; + int master_fd, slave_fd; + + /* Not satisfying */ + if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { + return NULL; + } + fprintf(stderr, "char device redirected to %s\n", slave_name); + return qemu_chr_open_fd(master_fd, master_fd); +} +#else +CharDriverState *qemu_chr_open_pty(void) +{ + return NULL; +} #endif +#endif /* !defined(_WIN32) */ + +CharDriverState *qemu_chr_open(const char *filename) +{ + if (!strcmp(filename, "vc")) { + return text_console_init(&display_state); + } else if (!strcmp(filename, "null")) { + return qemu_chr_open_null(); + } else +#ifndef _WIN32 + if (!strcmp(filename, "pty")) { + return qemu_chr_open_pty(); + } else if (!strcmp(filename, "stdio")) { + return qemu_chr_open_stdio(); + } else +#endif + { + return NULL; + } +} + /***********************************************************/ /* Linux network device redirectors */ @@ -2106,6 +2353,8 @@ void help(void) "-initrd file use 'file' as initial ram disk\n" "\n" "Debug/Expert options:\n" + "-monitor dev redirect the monitor to char device 'dev'\n" + "-serial dev redirect the serial port to char device 'dev'\n" "-S freeze CPU at startup (use 'c' to start execution)\n" "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" @@ -2121,7 +2370,13 @@ void help(void) " (default is CL-GD5446 PCI VGA)\n" #endif "\n" - "During emulation, use C-a h to get terminal commands:\n", + "During emulation, the following keys are useful:\n" + "ctrl-shift-f toggle full screen\n" + "ctrl-shift-Fn switch to virtual console 'n'\n" + "ctrl-shift toggle mouse and keyboard grab\n" + "\n" + "When using -nographic, press 'ctrl-a h' to get some help.\n" + , #ifdef CONFIG_SOFTMMU "qemu", #else @@ -2131,7 +2386,6 @@ void help(void) DEFAULT_NETWORK_SCRIPT, DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); - term_print_help(); #ifndef CONFIG_SOFTMMU printf("\n" "NOTE: this version of QEMU is faster but it needs slightly patched OSes to\n" @@ -2184,6 +2438,8 @@ enum { QEMU_OPTION_cirrusvga, QEMU_OPTION_g, QEMU_OPTION_std_vga, + QEMU_OPTION_monitor, + QEMU_OPTION_serial, }; typedef struct QEMUOption { @@ -2235,7 +2491,9 @@ const QEMUOption qemu_options[] = { { "localtime", 0, QEMU_OPTION_localtime }, { "isa", 0, QEMU_OPTION_isa }, { "std-vga", 0, QEMU_OPTION_std_vga }, - + { "monitor", 1, QEMU_OPTION_monitor }, + { "serial", 1, QEMU_OPTION_serial }, + /* temporary options */ { "pci", 0, QEMU_OPTION_pci }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, @@ -2273,6 +2531,9 @@ int main(int argc, char **argv) int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; int optind; const char *r, *optarg; + CharDriverState *monitor_hd; + char monitor_device[128]; + char serial_device[128]; #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ @@ -2297,6 +2558,8 @@ int main(int argc, char **argv) kernel_cmdline = ""; has_cdrom = 1; cyls = heads = secs = 0; + pstrcpy(monitor_device, sizeof(monitor_device), "vc"); + pstrcpy(serial_device, sizeof(serial_device), "vc"); nb_tun_fds = 0; net_if_type = -1; @@ -2308,7 +2571,7 @@ int main(int argc, char **argv) macaddr[3] = 0x12; macaddr[4] = 0x34; macaddr[5] = 0x56; - + optind = 1; for(;;) { if (optind >= argc) @@ -2375,6 +2638,8 @@ int main(int argc, char **argv) } break; case QEMU_OPTION_nographic: + pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); + pstrcpy(serial_device, sizeof(serial_device), "stdio"); nographic = 1; break; case QEMU_OPTION_kernel: @@ -2561,6 +2826,12 @@ int main(int argc, char **argv) graphic_depth = depth; } break; + case QEMU_OPTION_monitor: + pstrcpy(monitor_device, sizeof(monitor_device), optarg); + break; + case QEMU_OPTION_serial: + pstrcpy(serial_device, sizeof(serial_device), optarg); + break; } } } @@ -2750,6 +3021,24 @@ int main(int argc, char **argv) #endif } + vga_console = graphic_console_init(ds); + + monitor_hd = qemu_chr_open(monitor_device); + if (!monitor_hd) { + fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); + exit(1); + } + monitor_init(monitor_hd, !nographic); + + serial_hd = qemu_chr_open(serial_device); + if (!serial_hd) { + fprintf(stderr, "qemu: could not open serial device '%s'\n", serial_device); + exit(1); + } + if (!strcmp(serial_device, "vc")) + qemu_chr_printf(serial_hd, "serial0 console\n"); + + /* setup cpu signal handlers for MMU / self modifying code handling */ #if !defined(CONFIG_SOFTMMU) @@ -2805,10 +3094,6 @@ int main(int argc, char **argv) kernel_filename, kernel_cmdline, initrd_filename); #endif - /* launched after the device init so that it can display or not a - banner */ - monitor_init(); - gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); diff --git a/vl.h b/vl.h index 15004c010..a37981a50 100644 --- a/vl.h +++ b/vl.h @@ -215,8 +215,7 @@ extern const char *bios_dir; void pstrcpy(char *buf, int buf_size, const char *str); char *pstrcat(char *buf, int buf_size, const char *s); - -int serial_open_device(void); +int strstart(const char *str, const char *val, const char **ptr); extern int vm_running; @@ -265,6 +264,31 @@ void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque); void kbd_put_keycode(int keycode); void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); +/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx + constants) */ +#define QEMU_KEY_ESC1(c) ((c) | 0xe100) +#define QEMU_KEY_BACKSPACE 0x007f +#define QEMU_KEY_UP QEMU_KEY_ESC1('A') +#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B') +#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C') +#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D') +#define QEMU_KEY_HOME QEMU_KEY_ESC1(1) +#define QEMU_KEY_END QEMU_KEY_ESC1(4) +#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5) +#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6) +#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3) + +#define QEMU_KEY_CTRL_UP 0xe400 +#define QEMU_KEY_CTRL_DOWN 0xe401 +#define QEMU_KEY_CTRL_LEFT 0xe402 +#define QEMU_KEY_CTRL_RIGHT 0xe403 +#define QEMU_KEY_CTRL_HOME 0xe404 +#define QEMU_KEY_CTRL_END 0xe405 +#define QEMU_KEY_CTRL_PAGEUP 0xe406 +#define QEMU_KEY_CTRL_PAGEDOWN 0xe407 + +void kbd_put_keysym(int keysym); + /* async I/O support */ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); @@ -274,6 +298,42 @@ int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque); void qemu_del_fd_read_handler(int fd); +/* character device */ + +#define CHR_EVENT_BREAK 0 /* serial break char */ + +typedef void IOEventHandler(void *opaque, int event); + +typedef struct CharDriverState { + int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); + void (*chr_add_read_handler)(struct CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque); + IOEventHandler *chr_event; + void *opaque; +} CharDriverState; + +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); +int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); +void qemu_chr_add_read_handler(CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque); +void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); + +CharDriverState *serial_hd; + +/* consoles */ + +typedef struct DisplayState DisplayState; +typedef struct TextConsole TextConsole; + +extern TextConsole *vga_console; + +TextConsole *graphic_console_init(DisplayState *ds); +int is_active_console(TextConsole *s); +CharDriverState *text_console_init(DisplayState *ds); +void console_select(unsigned int index); + /* network redirectors support */ #define MAX_NICS 8 @@ -437,6 +497,7 @@ void bdrv_set_change_cb(BlockDriverState *bs, void bdrv_info(void); BlockDriverState *bdrv_find(const char *name); +void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); /* ISA bus */ @@ -534,14 +595,16 @@ openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus); #define VGA_RAM_SIZE (4096 * 1024) -typedef struct DisplayState { +struct DisplayState { uint8_t *data; int linesize; int depth; + int width; + int height; void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); void (*dpy_resize)(struct DisplayState *s, int w, int h); void (*dpy_refresh)(struct DisplayState *s); -} DisplayState; +}; static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) { @@ -644,13 +707,7 @@ void rtc_set_date(RTCState *s, const struct tm *tm); /* serial.c */ typedef struct SerialState SerialState; - -extern SerialState *serial_console; - -SerialState *serial_init(int base, int irq, int fd); -int serial_can_receive(SerialState *s); -void serial_receive_byte(SerialState *s, int ch); -void serial_receive_break(SerialState *s); +SerialState *serial_init(int base, int irq, CharDriverState *chr); /* i8259.c */ @@ -767,7 +824,7 @@ extern ADBBusState adb_bus; int cuda_init(openpic_t *openpic, int irq); /* monitor.c */ -void monitor_init(void); +void monitor_init(CharDriverState *hd, int show_banner); void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); void term_flush(void); void term_print_help(void); -- cgit v1.2.3 From e7f0ad58c12b907ace1b263f06f2a2bdecfbde9f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:28:59 +0000 Subject: virtual console git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1024 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 711 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 711 insertions(+) create mode 100644 console.c diff --git a/console.c b/console.c new file mode 100644 index 000000000..b688e931c --- /dev/null +++ b/console.c @@ -0,0 +1,711 @@ +/* + * QEMU graphical console + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#define DEFAULT_BACKSCROLL 512 +#define MAX_CONSOLES 12 + +#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define RGB(r, g, b) RGBA(r, g, b, 0xff) + +typedef struct TextCell { + uint8_t ch; + uint8_t bgcol:4; + uint8_t fgcol:4; +} TextCell; + +#define MAX_ESC_PARAMS 3 + +enum TTYState { + TTY_STATE_NORM, + TTY_STATE_ESC, + TTY_STATE_CSI, +}; + +struct TextConsole { + int text_console; /* true if text console */ + DisplayState *ds; + int g_width, g_height; + int width; + int height; + int total_height; + int backscroll_height; + int fgcol; + int bgcol; + int x, y; + int y_displayed; + int y_base; + TextCell *cells; + + enum TTYState state; + int esc_params[MAX_ESC_PARAMS]; + int nb_esc_params; + + /* kbd read handler */ + IOReadHandler *fd_read; + void *fd_opaque; +}; + +static TextConsole *active_console; +static TextConsole *consoles[MAX_CONSOLES]; +static int nb_consoles = 0; + +/* convert a RGBA color to a color index usable in graphic primitives */ +static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) +{ + unsigned int r, g, b, color; + + switch(ds->depth) { +#if 0 + case 8: + r = (rgba >> 16) & 0xff; + g = (rgba >> 8) & 0xff; + b = (rgba) & 0xff; + color = (rgb_to_index[r] * 6 * 6) + + (rgb_to_index[g] * 6) + + (rgb_to_index[b]); + break; +#endif + case 15: + r = (rgba >> 16) & 0xff; + g = (rgba >> 8) & 0xff; + b = (rgba) & 0xff; + color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); + break; + case 16: + r = (rgba >> 16) & 0xff; + g = (rgba >> 8) & 0xff; + b = (rgba) & 0xff; + color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); + break; + case 32: + default: + color = rgba; + break; + } + return color; +} + +static void vga_fill_rect (DisplayState *ds, + int posx, int posy, int width, int height, uint32_t color) +{ + uint8_t *d, *d1; + int x, y, bpp; + + bpp = (ds->depth + 7) >> 3; + d1 = ds->data + + ds->linesize * posy + bpp * posx; + for (y = 0; y < height; y++) { + d = d1; + switch(bpp) { + case 1: + for (x = 0; x < width; x++) { + *((uint8_t *)d) = color; + d++; + } + break; + case 2: + for (x = 0; x < width; x++) { + *((uint16_t *)d) = color; + d += 2; + } + break; + case 4: + for (x = 0; x < width; x++) { + *((uint32_t *)d) = color; + d += 4; + } + break; + } + d1 += ds->linesize; + } +} + +/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */ +static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h) +{ + const uint8_t *s; + uint8_t *d; + int wb, y, bpp; + + bpp = (ds->depth + 7) >> 3; + wb = w * bpp; + if (yd <= ys) { + s = ds->data + + ds->linesize * ys + bpp * xs; + d = ds->data + + ds->linesize * yd + bpp * xd; + for (y = 0; y < h; y++) { + memmove(d, s, wb); + d += ds->linesize; + s += ds->linesize; + } + } else { + s = ds->data + + ds->linesize * (ys + h - 1) + bpp * xs; + d = ds->data + + ds->linesize * (yd + h - 1) + bpp * xd; + for (y = 0; y < h; y++) { + memmove(d, s, wb); + d -= ds->linesize; + s -= ds->linesize; + } + } +} + +/***********************************************************/ +/* basic char display */ + +#define FONT_HEIGHT 16 +#define FONT_WIDTH 8 + +#include "vgafont.h" + +#define cbswap_32(__x) \ +((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) + +#ifdef WORDS_BIGENDIAN +#define PAT(x) x +#else +#define PAT(x) cbswap_32(x) +#endif + +static const uint32_t dmask16[16] = { + PAT(0x00000000), + PAT(0x000000ff), + PAT(0x0000ff00), + PAT(0x0000ffff), + PAT(0x00ff0000), + PAT(0x00ff00ff), + PAT(0x00ffff00), + PAT(0x00ffffff), + PAT(0xff000000), + PAT(0xff0000ff), + PAT(0xff00ff00), + PAT(0xff00ffff), + PAT(0xffff0000), + PAT(0xffff00ff), + PAT(0xffffff00), + PAT(0xffffffff), +}; + +static const uint32_t dmask4[4] = { + PAT(0x00000000), + PAT(0x0000ffff), + PAT(0xffff0000), + PAT(0xffffffff), +}; + +static uint32_t color_table[8]; + +static const uint32_t color_table_rgb[8] = { + RGB(0x00, 0x00, 0x00), + RGB(0xff, 0x00, 0x00), + RGB(0x00, 0xff, 0x00), + RGB(0xff, 0xff, 0x00), + RGB(0x00, 0x00, 0xff), + RGB(0xff, 0x00, 0xff), + RGB(0x00, 0xff, 0xff), + RGB(0xff, 0xff, 0xff), +}; + +static inline unsigned int col_expand(DisplayState *ds, unsigned int col) +{ + switch(ds->depth) { + case 8: + col |= col << 8; + col |= col << 16; + break; + case 15: + case 16: + col |= col << 16; + break; + default: + break; + } + + return col; +} + +static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, + unsigned int fgcol, unsigned int bgcol) +{ + uint8_t *d; + const uint8_t *font_ptr; + unsigned int font_data, linesize, xorcol, bpp; + int i; + + bpp = (ds->depth + 7) >> 3; + d = ds->data + + ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH; + linesize = ds->linesize; + font_ptr = vgafont16 + FONT_HEIGHT * ch; + xorcol = bgcol ^ fgcol; + switch(ds->depth) { + case 8: + for(i = 0; i < FONT_HEIGHT; i++) { + font_data = *font_ptr++; + ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; + ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; + d += linesize; + } + break; + case 16: + case 15: + for(i = 0; i < FONT_HEIGHT; i++) { + font_data = *font_ptr++; + ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; + ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol; + ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol; + ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; + d += linesize; + } + break; + case 32: + for(i = 0; i < FONT_HEIGHT; i++) { + font_data = *font_ptr++; + ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; + ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; + ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; + ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; + ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; + ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; + ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; + ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; + d += linesize; + } + break; + } +} + +static void text_console_resize(TextConsole *s) +{ + TextCell *cells, *c, *c1; + int w1, x, y, last_width; + + last_width = s->width; + s->width = s->g_width / FONT_WIDTH; + s->height = s->g_height / FONT_HEIGHT; + + w1 = last_width; + if (s->width < w1) + w1 = s->width; + + cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell)); + for(y = 0; y < s->total_height; y++) { + c = &cells[y * s->width]; + if (w1 > 0) { + c1 = &s->cells[y * last_width]; + for(x = 0; x < w1; x++) { + *c++ = *c1++; + } + } + for(x = w1; x < s->width; x++) { + c->ch = ' '; + c->fgcol = 7; + c->bgcol = 0; + c++; + } + } + free(s->cells); + s->cells = cells; +} + +static void update_xy(TextConsole *s, int x, int y) +{ + TextCell *c; + int y1, y2; + + if (s == active_console) { + y1 = (s->y_base + y) % s->total_height; + y2 = y1 - s->y_displayed; + if (y2 < 0) + y2 += s->total_height; + if (y2 < s->height) { + c = &s->cells[y1 * s->width + x]; + vga_putcharxy(s->ds, x, y2, c->ch, + color_table[c->fgcol], color_table[c->bgcol]); + dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, + FONT_WIDTH, FONT_HEIGHT); + } + } +} + +static void console_show_cursor(TextConsole *s, int show) +{ + TextCell *c; + int y, y1; + + if (s == active_console) { + y1 = (s->y_base + s->y) % s->total_height; + y = y1 - s->y_displayed; + if (y < 0) + y += s->total_height; + if (y < s->height) { + c = &s->cells[y1 * s->width + s->x]; + if (show) { + vga_putcharxy(s->ds, s->x, y, c->ch, + color_table[0], color_table[7]); + } else { + vga_putcharxy(s->ds, s->x, y, c->ch, + color_table[c->fgcol], color_table[c->bgcol]); + } + dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, + FONT_WIDTH, FONT_HEIGHT); + } + } +} + +static void console_refresh(TextConsole *s) +{ + TextCell *c; + int x, y, y1; + + if (s != active_console) + return; + + vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, + color_table[0]); + y1 = s->y_displayed; + for(y = 0; y < s->height; y++) { + c = s->cells + y1 * s->width; + for(x = 0; x < s->width; x++) { + vga_putcharxy(s->ds, x, y, c->ch, + color_table[c->fgcol], color_table[c->bgcol]); + c++; + } + if (++y1 == s->total_height) + y1 = 0; + } + dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height); + console_show_cursor(s, 1); +} + +static void console_scroll(int ydelta) +{ + TextConsole *s; + int i, y1; + + s = active_console; + if (!s || !s->text_console) + return; + + if (ydelta > 0) { + for(i = 0; i < ydelta; i++) { + if (s->y_displayed == s->y_base) + break; + if (++s->y_displayed == s->total_height) + s->y_displayed = 0; + } + } else { + ydelta = -ydelta; + i = s->backscroll_height; + if (i > s->total_height - s->height) + i = s->total_height - s->height; + y1 = s->y_base - i; + if (y1 < 0) + y1 += s->total_height; + for(i = 0; i < ydelta; i++) { + if (s->y_displayed == y1) + break; + if (--s->y_displayed < 0) + s->y_displayed = s->total_height - 1; + } + } + console_refresh(s); +} + +static void console_put_lf(TextConsole *s) +{ + TextCell *c; + int x, y1; + + s->x = 0; + s->y++; + if (s->y >= s->height) { + s->y = s->height - 1; + + if (s->y_displayed == s->y_base) { + if (++s->y_displayed == s->total_height) + s->y_displayed = 0; + } + if (++s->y_base == s->total_height) + s->y_base = 0; + if (s->backscroll_height < s->total_height) + s->backscroll_height++; + y1 = (s->y_base + s->height - 1) % s->total_height; + c = &s->cells[y1 * s->width]; + for(x = 0; x < s->width; x++) { + c->ch = ' '; + c->fgcol = s->fgcol; + c->bgcol = s->bgcol; + c++; + } + if (s == active_console && s->y_displayed == s->y_base) { + vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, + s->width * FONT_WIDTH, + (s->height - 1) * FONT_HEIGHT); + vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT, + s->width * FONT_WIDTH, FONT_HEIGHT, + color_table[s->bgcol]); + dpy_update(s->ds, 0, 0, + s->width * FONT_WIDTH, s->height * FONT_HEIGHT); + } + } +} + +static void console_putchar(TextConsole *s, int ch) +{ + TextCell *c; + int y1, i, x; + + switch(s->state) { + case TTY_STATE_NORM: + switch(ch) { + case '\r': + s->x = 0; + break; + case '\n': + console_put_lf(s); + break; + case 27: + s->state = TTY_STATE_ESC; + break; + default: + y1 = (s->y_base + s->y) % s->total_height; + c = &s->cells[y1 * s->width + s->x]; + c->ch = ch; + c->fgcol = s->fgcol; + c->bgcol = s->bgcol; + update_xy(s, s->x, s->y); + s->x++; + if (s->x >= s->width) + console_put_lf(s); + break; + } + break; + case TTY_STATE_ESC: + if (ch == '[') { + for(i=0;iesc_params[i] = 0; + s->nb_esc_params = 0; + s->state = TTY_STATE_CSI; + } else { + s->state = TTY_STATE_NORM; + } + break; + case TTY_STATE_CSI: + if (ch >= '0' && ch <= '9') { + if (s->nb_esc_params < MAX_ESC_PARAMS) { + s->esc_params[s->nb_esc_params] = + s->esc_params[s->nb_esc_params] * 10 + ch - '0'; + } + } else { + s->nb_esc_params++; + if (ch == ';') + break; + s->state = TTY_STATE_NORM; + switch(ch) { + case 'D': + if (s->x > 0) + s->x--; + break; + case 'C': + if (s->x < (s->width - 1)) + s->x++; + break; + case 'K': + /* clear to eol */ + y1 = (s->y_base + s->y) % s->total_height; + for(x = s->x; x < s->width; x++) { + c = &s->cells[y1 * s->width + x]; + c->ch = ' '; + c->fgcol = s->fgcol; + c->bgcol = s->bgcol; + c++; + update_xy(s, x, s->y); + } + break; + default: + break; + } + break; + } + } +} + +void console_select(unsigned int index) +{ + TextConsole *s; + + if (index >= MAX_CONSOLES) + return; + s = consoles[index]; + if (s) { + active_console = s; + if (s->text_console) { + if (s->g_width != s->ds->width || + s->g_height != s->ds->height) + text_console_resize(s); + console_refresh(s); + } + } +} + +static int console_puts(CharDriverState *chr, const uint8_t *buf, int len) +{ + TextConsole *s = chr->opaque; + int i; + + console_show_cursor(s, 0); + for(i = 0; i < len; i++) { + console_putchar(s, buf[i]); + } + console_show_cursor(s, 1); + return len; +} + +static void console_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + TextConsole *s = chr->opaque; + s->fd_read = fd_read; + s->fd_opaque = opaque; +} + +/* called when an ascii key is pressed */ +void kbd_put_keysym(int keysym) +{ + TextConsole *s; + uint8_t buf[16], *q; + int c; + + s = active_console; + if (!s || !s->text_console) + return; + + switch(keysym) { + case QEMU_KEY_CTRL_UP: + console_scroll(-1); + break; + case QEMU_KEY_CTRL_DOWN: + console_scroll(1); + break; + case QEMU_KEY_CTRL_PAGEUP: + console_scroll(-10); + break; + case QEMU_KEY_CTRL_PAGEDOWN: + console_scroll(10); + break; + default: + if (s->fd_read) { + /* convert the QEMU keysym to VT100 key string */ + q = buf; + if (keysym >= 0xe100 && keysym <= 0xe11f) { + *q++ = '\033'; + *q++ = '['; + c = keysym - 0xe100; + if (c >= 10) + *q++ = '0' + (c / 10); + *q++ = '0' + (c % 10); + *q++ = '~'; + } else if (keysym >= 0xe120 && keysym <= 0xe17f) { + *q++ = '\033'; + *q++ = '['; + *q++ = keysym & 0xff; + } else { + *q++ = keysym; + } + s->fd_read(s->fd_opaque, buf, q - buf); + } + break; + } +} + +TextConsole *graphic_console_init(DisplayState *ds) +{ + TextConsole *s; + + if (nb_consoles >= MAX_CONSOLES) + return NULL; + s = qemu_mallocz(sizeof(TextConsole)); + if (!s) { + return NULL; + } + if (!active_console) + active_console = s; + s->ds = ds; + consoles[nb_consoles++] = s; + return s; +} + +int is_active_console(TextConsole *s) +{ + return s == active_console; +} + +CharDriverState *text_console_init(DisplayState *ds) +{ + CharDriverState *chr; + TextConsole *s; + int i; + static int color_inited; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = graphic_console_init(ds); + if (!s) { + free(chr); + return NULL; + } + s->text_console = 1; + chr->opaque = s; + chr->chr_write = console_puts; + chr->chr_add_read_handler = console_chr_add_read_handler; + if (!color_inited) { + color_inited = 1; + for(i = 0; i < 8; i++) { + color_table[i] = col_expand(s->ds, + vga_get_color(s->ds, color_table_rgb[i])); + } + } + s->y_displayed = 0; + s->y_base = 0; + s->total_height = DEFAULT_BACKSCROLL; + s->x = 0; + s->y = 0; + s->fgcol = 7; + s->bgcol = 0; + s->g_width = s->ds->width; + s->g_height = s->ds->height; + text_console_resize(s); + + return chr; +} -- cgit v1.2.3 From 49b3b9fb1ae5b630d61fe84ce77532b8b223ef33 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:31:32 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1025 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changelog b/Changelog index 011f47458..5658c0bd0 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,8 @@ +version 0.6.1: + + - Mac OS X port (Pierre d'Herbemont) + - Virtual console support + version 0.6.0: - minimalist FPU exception support (NetBSD FPU probe fix) -- cgit v1.2.3 From a0a821a4c07305dee50557b8b32fbf5642a74795 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:38:57 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1026 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 7829f3f49..efaaa8a11 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -247,6 +247,29 @@ Use @var{file} as initial ram disk. Debug/Expert options: @table @option + +@item -serial dev +Redirect the virtual serial port to host device @var{dev}. Available +devices are: +@table @code +@item vc +Virtual console +@item pty +[Linux only] Pseudo TTY (a new PTY is automatically allocated) +@item null +void device +@item stdio +[Unix only] standard input/output +@end table +The default device is @code{vc} in graphical mode and @code{stdio} in +non graphical mode. + +@item -monitor dev +Redirect the monitor to host device @var{dev} (same devices as the +serial port). +The default device is @code{vc} in graphical mode and @code{stdio} in +non graphical mode. + @item -s Wait gdb connection to port 1234 (@xref{gdb_usage}). @item -p port @@ -265,14 +288,26 @@ Cirrus Logic GD5446 PCI VGA) During the graphical emulation, you can use the following keys: @table @key -@item Ctrl-Shift -Toggle mouse and keyboard grab. @item Ctrl-Shift-f Toggle full screen + +@item Ctrl-Shift-Fn +Switch to virtual console 'n'. Standard console mappings are: +@table @emph +@item 1 +Target system display +@item 2 +Monitor +@item 3 +Serial port @end table -During emulation, if you are using the serial console, use @key{C-a h} -to get terminal commands: +@item Ctrl-Shift +Toggle mouse and keyboard grab. +@end table + +During emulation, if you are using the @option{-nographic} option, use +@key{Ctrl-a h} to get terminal commands: @table @key @item Ctrl-a h @@ -925,6 +960,15 @@ without networking support. Future QEMU releases are likely to correct this bug. +@subsection MS-DOS and FreeDOS + +@subsubsection CPU usage reduction + +DOS does not correctly use the CPU HLT instruction. The result is that +it takes host CPU cycles even when idle. You can install the utility +from @url{http://www.vmware.com/software/dosidle210.zip} to solve this +problem. + @chapter QEMU PowerPC System emulator invocation Use the executable @file{qemu-system-ppc} to simulate a complete PREP -- cgit v1.2.3 From c6f37d0e4feeb264a699eda289d3cc69405100b0 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:39:50 +0000 Subject: virtual console git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1027 c046a42c-6fe2-441c-8c8c-71466251a162 --- vgafont.h | 4611 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4611 insertions(+) create mode 100644 vgafont.h diff --git a/vgafont.h b/vgafont.h new file mode 100644 index 000000000..bb75796be --- /dev/null +++ b/vgafont.h @@ -0,0 +1,4611 @@ +static uint8_t vgafont16[256 * 16] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 11 0x0b '^K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x1a, /* 00011010 */ + 0x32, /* 00110010 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0c '^L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0d '^M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0e '^N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe7, /* 11100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0f '^O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0xf0, /* 11110000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0e, /* 00001110 */ + 0x1e, /* 00011110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x1e, /* 00011110 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x86, /* 10000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 42 0x2a '*' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2b '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2c ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 45 0x2d '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2e '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2f '/' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x02, /* 00000010 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x78, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x1c, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfc, /* 11111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3a ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3b ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 60 0x3c '<' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3d '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3e '>' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3f '?' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xde, /* 11011110 */ + 0xdc, /* 11011100 */ + 0xc0, /* 11000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xde, /* 11011110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x66, /* 01100110 */ + 0x3a, /* 00111010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4a 'J' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4b 'K' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe6, /* 11100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4c 'L' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4d 'M' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xee, /* 11101110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4e 'N' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4f 'O' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xde, /* 11011110 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfc, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x5a, /* 01011010 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0xee, /* 11101110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5a 'Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc2, /* 11000010 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5b '[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 92 0x5c '\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x80, /* 10000000 */ + 0xc0, /* 11000000 */ + 0xe0, /* 11100000 */ + 0x70, /* 01110000 */ + 0x38, /* 00111000 */ + 0x1c, /* 00011100 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 93 0x5d ']' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 94 0x5e '^' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5f '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x36, /* 00110110 */ + 0x32, /* 00110010 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x6c, /* 01101100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6a 'j' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* 107 0x6b 'k' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xe0, /* 11100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x78, /* 01111000 */ + 0x78, /* 01111000 */ + 0x6c, /* 01101100 */ + 0x66, /* 01100110 */ + 0xe6, /* 11100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6c 'l' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6d 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6e 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6f 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x7c, /* 01111100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x1e, /* 00011110 */ + 0x00, /* 00000000 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x66, /* 01100110 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x38, /* 00111000 */ + 0x0c, /* 00001100 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0xfc, /* 11111100 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x36, /* 00110110 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xd6, /* 11010110 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + + /* 122 0x7a 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7b '{' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 124 0x7c '|' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 125 0x7d '}' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x70, /* 01110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0e, /* 00001110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 126 0x7e '~' */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '€' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0xc2, /* 11000010 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc2, /* 11000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 129 0x81 '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '‚' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 'ƒ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '„' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '…' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '†' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '‡' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 136 0x88 'ˆ' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '‰' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8a 'Š' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8b '‹' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8c 'Œ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8d '' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8e 'Ž' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8f '' */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '' */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x66, /* 01100110 */ + 0x62, /* 01100010 */ + 0x68, /* 01101000 */ + 0x78, /* 01111000 */ + 0x68, /* 01101000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '‘' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xec, /* 11101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x6e, /* 01101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '’' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3e, /* 00111110 */ + 0x6c, /* 01101100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xfe, /* 11111110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xce, /* 11001110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '“' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '”' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '•' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '–' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '—' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '˜' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7e, /* 01111110 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + + /* 153 0x99 '™' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9a 'š' */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9b '›' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 156 0x9c 'œ' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x64, /* 01100100 */ + 0x60, /* 01100000 */ + 0xf0, /* 11110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xe6, /* 11100110 */ + 0xfc, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9d '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9e 'ž' */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xf8, /* 11111000 */ + 0xc4, /* 11000100 */ + 0xcc, /* 11001100 */ + 0xde, /* 11011110 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9f 'Ÿ' */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xa0 ' ' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x7c, /* 01111100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xa1 '¡' */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xa2 '¢' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xa3 '£' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xa4 '¤' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xdc, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xa5 '¥' */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0xc6, /* 11000110 */ + 0xe6, /* 11100110 */ + 0xf6, /* 11110110 */ + 0xfe, /* 11111110 */ + 0xde, /* 11011110 */ + 0xce, /* 11001110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xa6 '¦' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xa7 '§' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xa8 '¨' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xa9 '©' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xaa 'ª' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xab '«' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xdc, /* 11011100 */ + 0x86, /* 10000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x3e, /* 00111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 172 0xac '¬' */ + 0x00, /* 00000000 */ + 0x60, /* 01100000 */ + 0xe0, /* 11100000 */ + 0x62, /* 01100010 */ + 0x66, /* 01100110 */ + 0x6c, /* 01101100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x66, /* 01100110 */ + 0xce, /* 11001110 */ + 0x9a, /* 10011010 */ + 0x3f, /* 00111111 */ + 0x06, /* 00000110 */ + 0x06, /* 00000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 173 0xad '­' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xae '®' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xaf '¯' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xd8, /* 11011000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x6c, /* 01101100 */ + 0xd8, /* 11011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xb0 '°' */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + 0x11, /* 00010001 */ + 0x44, /* 01000100 */ + + /* 177 0xb1 '±' */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + + /* 178 0xb2 '²' */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + + /* 179 0xb3 '³' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 180 0xb4 '´' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 181 0xb5 'µ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 182 0xb6 '¶' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 183 0xb7 '·' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 184 0xb8 '¸' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 185 0xb9 '¹' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 186 0xba 'º' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 187 0xbb '»' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x06, /* 00000110 */ + 0xf6, /* 11110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 188 0xbc '¼' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf6, /* 11110110 */ + 0x06, /* 00000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xbd '½' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xbe '¾' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xbf '¿' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xf8, /* 11111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 192 0xc0 'À' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xc1 'Á' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xc2 'Â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 195 0xc3 'Ã' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 196 0xc4 'Ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xc5 'Å' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 198 0xc6 'Æ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 199 0xc7 'Ç' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 200 0xc8 'È' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xc9 'É' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 202 0xca 'Ê' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xcb 'Ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 204 0xcc 'Ì' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x37, /* 00110111 */ + 0x30, /* 00110000 */ + 0x37, /* 00110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 205 0xcd 'Í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xce 'Î' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xf7, /* 11110111 */ + 0x00, /* 00000000 */ + 0xf7, /* 11110111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 207 0xcf 'Ï' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xd0 'Ð' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xd1 'Ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 210 0xd2 'Ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 211 0xd3 'Ó' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x3f, /* 00111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xd4 'Ô' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xd5 'Õ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 214 0xd6 'Ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 00111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 215 0xd7 '×' */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0xff, /* 11111111 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + + /* 216 0xd8 'Ø' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 217 0xd9 'Ù' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xf8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xda 'Ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 00011111 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 219 0xdb 'Û' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 220 0xdc 'Ü' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + + /* 221 0xdd 'Ý' */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + 0xf0, /* 11110000 */ + + /* 222 0xde 'Þ' */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + 0x0f, /* 00001111 */ + + /* 223 0xdf 'ß' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xe0 'à' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xdc, /* 11011100 */ + 0x76, /* 01110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xe1 'á' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xd8, /* 11011000 */ + 0xcc, /* 11001100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xcc, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 226 0xe2 'â' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xe3 'ã' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xe4 'ä' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xe5 'å' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xe6 'æ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + + /* 231 0xe7 'ç' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xe8 'è' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xe9 'é' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xea 'ê' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0xee, /* 11101110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xeb 'ë' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 00011110 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x3e, /* 00111110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xec 'ì' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xed 'í' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x03, /* 00000011 */ + 0x06, /* 00000110 */ + 0x7e, /* 01111110 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xf3, /* 11110011 */ + 0x7e, /* 01111110 */ + 0x60, /* 01100000 */ + 0xc0, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xee 'î' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00011100 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x7c, /* 01111100 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xef 'ï' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7c, /* 01111100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xf0 'ð' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xf1 'ñ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xf2 'ò' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x06, /* 00000110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xf3 'ó' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xf4 'ô' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* 245 0xf5 'õ' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0xd8, /* 11011000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 246 0xf6 'ö' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xf7 '÷' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x76, /* 01110110 */ + 0xdc, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xf8 'ø' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xf9 'ù' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xfa 'ú' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xfb 'û' */ + 0x00, /* 00000000 */ + 0x0f, /* 00001111 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0x0c, /* 00001100 */ + 0xec, /* 11101100 */ + 0x6c, /* 01101100 */ + 0x6c, /* 01101100 */ + 0x3c, /* 00111100 */ + 0x1c, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xfc 'ü' */ + 0x00, /* 00000000 */ + 0x6c, /* 01101100 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x36, /* 00110110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xfd 'ý' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x32, /* 00110010 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xfe 'þ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xff 'ÿ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + +}; -- cgit v1.2.3 From 3e11db9a0c82851a8c13e45c654856cdea2294d7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 17:47:14 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1028 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index efaaa8a11..e74e793ed 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -286,6 +286,12 @@ Cirrus Logic GD5446 PCI VGA) @end table +@c man end + +@section Keys + +@c man begin OPTIONS + During the graphical emulation, you can use the following keys: @table @key @item Ctrl-Shift-f @@ -306,6 +312,9 @@ Serial port Toggle mouse and keyboard grab. @end table +In the virtual consoles, you can use @key{Ctrl-Up}, @key{Ctrl-Down}, +@key{Ctrl-PageUp} and @key{Ctrl-PageDown} to move in the back log. + During emulation, if you are using the @option{-nographic} option, use @key{Ctrl-a h} to get terminal commands: -- cgit v1.2.3 From 3eb2619fe55aa7b040aba4fbf9242c50d0a9672e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jul 2004 19:20:07 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1029 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index e74e793ed..d3c0a1625 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -89,11 +89,17 @@ available: simulate the x86 MMU. It is @emph{fast} but has limitations because the whole 4 GB address space cannot be used and some memory mapped peripherials cannot be emulated accurately yet. Therefore, a specific -guest Linux kernel can be used (@xref{linux_compile}) as guest OS. +guest Linux kernel can be used (@xref{linux_compile}) as guest +OS. + +Moreover there is no separation between the host and target address +spaces, so it offers no security (the target OS can modify the +@code{qemu-fast} code by writing at the right addresses). @item -@code{qemu} uses a software MMU. It is about @emph{two times -slower} but gives a more accurate emulation. +@code{qemu} uses a software MMU. It is about @emph{two times slower} +but gives a more accurate emulation and a complete separation between +the host and target address spaces. @end enumerate -- cgit v1.2.3 From b932caba32c6eb627470d29e7ba1933589b4f8a0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 21:46:49 +0000 Subject: new disk image layer git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1030 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 15 +++++---------- Makefile.target | 6 +++++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index e27d1fe3b..b9d8e690c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ include config-host.mak -CFLAGS=-Wall -O2 -g +CFLAGS=-Wall -O2 -g -fno-strict-aliasing ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic endif @@ -10,9 +10,7 @@ endif LDFLAGS=-g LIBS= DEFINES+=-D_GNU_SOURCE -ifndef CONFIG_WIN32 -TOOLS=qemu-mkcow vmdk2raw -endif +TOOLS=qemu-img ifdef CONFIG_STATIC LDFLAGS+=-static endif @@ -22,11 +20,8 @@ all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1 $(MAKE) -C $$d $@ || exit 1 ; \ done -qemu-mkcow: qemu-mkcow.c - $(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS) - -vmdk2raw: vmdk2raw.c - $(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS) +qemu-img: qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c + $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c $(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^ @@ -99,7 +94,7 @@ tarbin: $(bindir)/qemu-arm \ $(bindir)/qemu-sparc \ $(bindir)/qemu-ppc \ - $(bindir)/qemu-mkcow $(bindir)/vmdk2raw \ + $(bindir)/qemu-img \ $(datadir)/bios.bin \ $(datadir)/vgabios.bin \ $(datadir)/vgabios-cirrus.bin \ diff --git a/Makefile.target b/Makefile.target index d565e1dd9..9c9cfcfea 100644 --- a/Makefile.target +++ b/Makefile.target @@ -161,6 +161,9 @@ endif DEFINES+=-D_GNU_SOURCE LIBS+=-lm +ifndef CONFIG_USER_ONLY +LIBS+=-lz +endif ifdef CONFIG_WIN32 LIBS+=-lwinmm -lws2_32 -liphlpapi endif @@ -237,7 +240,8 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o monitor.o pci.o console.o +VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o ifeq ($(TARGET_ARCH), i386) # Hardware support -- cgit v1.2.3 From af8ffdfd2b3b0894a54cb6333217f9f3ae6eaa81 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 21:48:12 +0000 Subject: byte swap functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1031 c046a42c-6fe2-441c-8c8c-71466251a162 --- bswap.h | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/bswap.h b/bswap.h index 0df6efcb4..180cc638f 100644 --- a/bswap.h +++ b/bswap.h @@ -73,4 +73,103 @@ 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) + +#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); +} + +#endif + +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps + #endif /* BSWAP_H */ -- cgit v1.2.3 From 6fcfafb742459e29e29fd61ed174108064643915 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 21:48:30 +0000 Subject: console focus support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1032 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/console.c b/console.c index b688e931c..171d2a937 100644 --- a/console.c +++ b/console.c @@ -599,6 +599,21 @@ static void console_chr_add_read_handler(CharDriverState *chr, s->fd_opaque = opaque; } +static void console_send_event(CharDriverState *chr, int event) +{ + TextConsole *s = chr->opaque; + int i; + + if (event == CHR_EVENT_FOCUS) { + for(i = 0; i < nb_consoles; i++) { + if (consoles[i] == s) { + console_select(i); + break; + } + } + } +} + /* called when an ascii key is pressed */ void kbd_put_keysym(int keysym) { @@ -689,6 +704,8 @@ CharDriverState *text_console_init(DisplayState *ds) chr->opaque = s; chr->chr_write = console_puts; chr->chr_add_read_handler = console_chr_add_read_handler; + chr->chr_send_event = console_send_event; + if (!color_inited) { color_inited = 1; for(i = 0; i < 8; i++) { -- cgit v1.2.3 From 3d2cfdf169da61ef5571aad8e7ae3ee0486b6060 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 21:49:07 +0000 Subject: output disassembled code to monitor console git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1033 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/disas.c b/disas.c index e315299cc..ccdcd2450 100644 --- a/disas.c +++ b/disas.c @@ -222,6 +222,9 @@ const char *lookup_symbol(void *orig_addr) #if !defined(CONFIG_USER_ONLY) +void term_vprintf(const char *fmt, va_list ap); +void term_printf(const char *fmt, ...); + static int monitor_disas_is_physical; static int @@ -239,16 +242,22 @@ monitor_read_memory (memaddr, myaddr, length, info) return 0; } +static int monitor_fprintf(FILE *stream, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + term_vprintf(fmt, ap); + va_end(ap); + return 0; +} + void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) { - FILE *out; int count, i; struct disassemble_info disasm_info; int (*print_insn)(bfd_vma pc, disassemble_info *info); - out = stdout; - - INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); + INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf); monitor_disas_is_physical = is_physical; disasm_info.read_memory_func = monitor_read_memory; @@ -278,9 +287,9 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) #endif for(i = 0; i < nb_insn; i++) { - fprintf(out, "0x%08lx: ", (unsigned long)pc); + term_printf("0x%08lx: ", (unsigned long)pc); count = print_insn(pc, &disasm_info); - fprintf(out, "\n"); + term_printf("\n"); if (count < 0) break; pc += count; -- cgit v1.2.3 From 7e2515e87c41e2e658aaed466e11cbdf1ea8bcb1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 21:52:19 +0000 Subject: separated readline from monitor code - added password input support - added output buffer git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1034 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 481 ++++++++++++------------------------------------------------- readline.c | 425 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 521 insertions(+), 385 deletions(-) create mode 100644 readline.c diff --git a/monitor.c b/monitor.c index 47b047a49..89285c1a5 100644 --- a/monitor.c +++ b/monitor.c @@ -32,36 +32,6 @@ #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif -#define TERM_CMD_BUF_SIZE 4095 -#define TERM_MAX_CMDS 64 -#define NB_COMPLETIONS_MAX 256 - -#define IS_NORM 0 -#define IS_ESC 1 -#define IS_CSI 2 - -#define printf do_not_use_printf - -static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1]; -static int term_cmd_buf_index; -static int term_cmd_buf_size; - -static char term_last_cmd_buf[TERM_CMD_BUF_SIZE + 1]; -static int term_last_cmd_buf_index; -static int term_last_cmd_buf_size; - -static int term_esc_state; -static int term_esc_param; - -static char *term_history[TERM_MAX_CMDS]; -static int term_hist_entry; -static CharDriverState *monitor_hd; - -static int nb_completions; -static int completion_index; -static char *completions[NB_COMPLETIONS_MAX]; - - /* * Supported types: * @@ -83,23 +53,52 @@ typedef struct term_cmd_t { const char *help; } term_cmd_t; +static CharDriverState *monitor_hd; + static term_cmd_t term_cmds[]; static term_cmd_t info_cmds[]; -static void add_completion(const char *str); +static char term_outbuf[1024]; +static int term_outbuf_index; -void term_printf(const char *fmt, ...) +static void monitor_start_input(void); + +void term_flush(void) +{ + if (term_outbuf_index > 0) { + qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); + term_outbuf_index = 0; + } +} + +/* flush at every end of line or if the buffer is full */ +void term_puts(const char *str) +{ + int c; + for(;;) { + c = *str++; + if (c == '\0') + break; + term_outbuf[term_outbuf_index++] = c; + if (term_outbuf_index >= sizeof(term_outbuf) || + c == '\n') + term_flush(); + } +} + +void term_vprintf(const char *fmt, va_list ap) { char buf[4096]; - va_list ap; - va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); - qemu_chr_write(monitor_hd, buf, strlen(buf)); - va_end(ap); + term_puts(buf); } -void term_flush(void) +void term_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + term_vprintf(fmt, ap); + va_end(ap); } static int compare_cmd(const char *name, const char *list) @@ -159,8 +158,9 @@ static void do_commit(void) int i; for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) + if (bs_table[i]) { bdrv_commit(bs_table[i]); + } } } @@ -215,11 +215,14 @@ static void do_info_registers(void) static void do_info_history (void) { int i; - - for (i = 0; i < TERM_MAX_CMDS; i++) { - if (term_history[i] == NULL) - break; - term_printf("%d: '%s'\n", i, term_history[i]); + const char *str; + + i = 0; + for(;;) { + str = readline_get_history(i); + if (!str) + break; + term_printf("%d: '%s'\n", i, str); } } @@ -261,6 +264,8 @@ static void do_eject(int force, const char *filename) static void do_change(const char *device, const char *filename) { BlockDriverState *bs; + int i; + char password[256]; bs = bdrv_find(device); if (!bs) { @@ -270,6 +275,15 @@ static void do_change(const char *device, const char *filename) if (eject_device(bs, 0) < 0) return; bdrv_open(bs, filename, 0); + if (bdrv_is_encrypted(bs)) { + term_printf("%s is encrypted.\n", device); + for(i = 0; i < 3; i++) { + monitor_readline("Password: ", 1, password, sizeof(password)); + if (bdrv_set_key(bs, password) == 0) + break; + term_printf("invalid password\n"); + } + } } static void do_screen_dump(const char *filename) @@ -1178,7 +1192,7 @@ static int default_fmt_size = 4; #define MAX_ARGS 16 -static void term_handle_command(const char *cmdline) +static void monitor_handle_command(const char *cmdline) { const char *p, *pstart, *typestr; char *q; @@ -1577,7 +1591,7 @@ static void parse_cmdline(const char *cmdline, *pnb_args = nb_args; } -static void find_completion(const char *cmdline) +void readline_find_completion(const char *cmdline) { const char *cmdname; char *args[MAX_ARGS]; @@ -1646,368 +1660,65 @@ static void find_completion(const char *cmdline) qemu_free(args[i]); } -static void term_show_prompt2(void) -{ - term_printf("(qemu) "); - fflush(stdout); - term_last_cmd_buf_index = 0; - term_last_cmd_buf_size = 0; - term_esc_state = IS_NORM; -} - -static void term_show_prompt(void) -{ - term_show_prompt2(); - term_cmd_buf_index = 0; - term_cmd_buf_size = 0; -} - -/* update the displayed command line */ -static void term_update(void) -{ - int i, delta; - - if (term_cmd_buf_size != term_last_cmd_buf_size || - memcmp(term_cmd_buf, term_last_cmd_buf, term_cmd_buf_size) != 0) { - for(i = 0; i < term_last_cmd_buf_index; i++) { - term_printf("\033[D"); - } - term_cmd_buf[term_cmd_buf_size] = '\0'; - term_printf("%s", term_cmd_buf); - term_printf("\033[K"); - memcpy(term_last_cmd_buf, term_cmd_buf, term_cmd_buf_size); - term_last_cmd_buf_size = term_cmd_buf_size; - term_last_cmd_buf_index = term_cmd_buf_size; - } - if (term_cmd_buf_index != term_last_cmd_buf_index) { - delta = term_cmd_buf_index - term_last_cmd_buf_index; - if (delta > 0) { - for(i = 0;i < delta; i++) { - term_printf("\033[C"); - } - } else { - delta = -delta; - for(i = 0;i < delta; i++) { - term_printf("\033[D"); - } - } - term_last_cmd_buf_index = term_cmd_buf_index; - } - term_flush(); -} - -static void term_insert_char(int ch) -{ - if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) { - memmove(term_cmd_buf + term_cmd_buf_index + 1, - term_cmd_buf + term_cmd_buf_index, - term_cmd_buf_size - term_cmd_buf_index); - term_cmd_buf[term_cmd_buf_index] = ch; - term_cmd_buf_size++; - term_cmd_buf_index++; - } -} - -static void term_backward_char(void) -{ - if (term_cmd_buf_index > 0) { - term_cmd_buf_index--; - } -} - -static void term_forward_char(void) -{ - if (term_cmd_buf_index < term_cmd_buf_size) { - term_cmd_buf_index++; - } -} - -static void term_delete_char(void) -{ - if (term_cmd_buf_index < term_cmd_buf_size) { - memmove(term_cmd_buf + term_cmd_buf_index, - term_cmd_buf + term_cmd_buf_index + 1, - term_cmd_buf_size - term_cmd_buf_index - 1); - term_cmd_buf_size--; - } -} - -static void term_backspace(void) +static int term_can_read(void *opaque) { - if (term_cmd_buf_index > 0) { - term_backward_char(); - term_delete_char(); - } + return 128; } -static void term_bol(void) +static void term_read(void *opaque, const uint8_t *buf, int size) { - term_cmd_buf_index = 0; + int i; + for(i = 0; i < size; i++) + readline_handle_byte(buf[i]); } -static void term_eol(void) -{ - term_cmd_buf_index = term_cmd_buf_size; -} +static void monitor_start_input(void); -static void term_up_char(void) +static void monitor_handle_command1(void *opaque, const char *cmdline) { - int idx; - - if (term_hist_entry == 0) - return; - if (term_hist_entry == -1) { - /* Find latest entry */ - for (idx = 0; idx < TERM_MAX_CMDS; idx++) { - if (term_history[idx] == NULL) - break; - } - term_hist_entry = idx; - } - term_hist_entry--; - if (term_hist_entry >= 0) { - pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), - term_history[term_hist_entry]); - term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); - } + monitor_handle_command(cmdline); + monitor_start_input(); } -static void term_down_char(void) +static void monitor_start_input(void) { - if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1) - return; - if (term_history[++term_hist_entry] != NULL) { - pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), - term_history[term_hist_entry]); - } else { - term_hist_entry = -1; - } - term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); + readline_start("(qemu) ", 0, monitor_handle_command1, NULL); } -static void term_hist_add(const char *cmdline) +void monitor_init(CharDriverState *hd, int show_banner) { - char *hist_entry, *new_entry; - int idx; - - if (cmdline[0] == '\0') - return; - new_entry = NULL; - if (term_hist_entry != -1) { - /* We were editing an existing history entry: replace it */ - hist_entry = term_history[term_hist_entry]; - idx = term_hist_entry; - if (strcmp(hist_entry, cmdline) == 0) { - goto same_entry; - } - } - /* Search cmdline in history buffers */ - for (idx = 0; idx < TERM_MAX_CMDS; idx++) { - hist_entry = term_history[idx]; - if (hist_entry == NULL) - break; - if (strcmp(hist_entry, cmdline) == 0) { - same_entry: - new_entry = hist_entry; - /* Put this entry at the end of history */ - memmove(&term_history[idx], &term_history[idx + 1], - &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]); - term_history[TERM_MAX_CMDS - 1] = NULL; - for (; idx < TERM_MAX_CMDS; idx++) { - if (term_history[idx] == NULL) - break; - } - break; - } - } - if (idx == TERM_MAX_CMDS) { - /* Need to get one free slot */ - free(term_history[0]); - memcpy(term_history, &term_history[1], - &term_history[TERM_MAX_CMDS] - &term_history[1]); - term_history[TERM_MAX_CMDS - 1] = NULL; - idx = TERM_MAX_CMDS - 1; + monitor_hd = hd; + if (show_banner) { + term_printf("QEMU %s monitor - type 'help' for more information\n", + QEMU_VERSION); } - if (new_entry == NULL) - new_entry = strdup(cmdline); - term_history[idx] = new_entry; - term_hist_entry = -1; + qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL); + monitor_start_input(); } -/* completion support */ - -static void add_completion(const char *str) -{ - if (nb_completions < NB_COMPLETIONS_MAX) { - completions[nb_completions++] = qemu_strdup(str); - } -} +/* XXX: use threads ? */ +/* modal monitor readline */ +static int monitor_readline_started; +static char *monitor_readline_buf; +static int monitor_readline_buf_size; -static void term_completion(void) +static void monitor_readline_cb(void *opaque, const char *input) { - int len, i, j, max_width, nb_cols; - char *cmdline; - - nb_completions = 0; - - cmdline = qemu_malloc(term_cmd_buf_index + 1); - if (!cmdline) - return; - memcpy(cmdline, term_cmd_buf, term_cmd_buf_index); - cmdline[term_cmd_buf_index] = '\0'; - find_completion(cmdline); - qemu_free(cmdline); - - /* no completion found */ - if (nb_completions <= 0) - return; - if (nb_completions == 1) { - len = strlen(completions[0]); - for(i = completion_index; i < len; i++) { - term_insert_char(completions[0][i]); - } - /* extra space for next argument. XXX: make it more generic */ - if (len > 0 && completions[0][len - 1] != '/') - term_insert_char(' '); - } else { - term_printf("\n"); - max_width = 0; - for(i = 0; i < nb_completions; i++) { - len = strlen(completions[i]); - if (len > max_width) - max_width = len; - } - max_width += 2; - if (max_width < 10) - max_width = 10; - else if (max_width > 80) - max_width = 80; - nb_cols = 80 / max_width; - j = 0; - for(i = 0; i < nb_completions; i++) { - term_printf("%-*s", max_width, completions[i]); - if (++j == nb_cols || i == (nb_completions - 1)) { - term_printf("\n"); - j = 0; - } - } - term_show_prompt2(); - } + pstrcpy(monitor_readline_buf, monitor_readline_buf_size, input); + monitor_readline_started = 0; } -/* return true if command handled */ -static void term_handle_byte(int ch) +void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size) { - switch(term_esc_state) { - case IS_NORM: - switch(ch) { - case 1: - term_bol(); - break; - case 4: - term_delete_char(); - break; - case 5: - term_eol(); - break; - case 9: - term_completion(); - break; - case 10: - case 13: - term_cmd_buf[term_cmd_buf_size] = '\0'; - term_hist_add(term_cmd_buf); - term_printf("\n"); - term_handle_command(term_cmd_buf); - term_show_prompt(); - break; - case 27: - term_esc_state = IS_ESC; - break; - case 127: - case 8: - term_backspace(); - break; - case 155: - term_esc_state = IS_CSI; - break; - default: - if (ch >= 32) { - term_insert_char(ch); - } - break; - } - break; - case IS_ESC: - if (ch == '[') { - term_esc_state = IS_CSI; - term_esc_param = 0; - } else { - term_esc_state = IS_NORM; - } - break; - case IS_CSI: - switch(ch) { - case 'A': - case 'F': - term_up_char(); - break; - case 'B': - case 'E': - term_down_char(); - break; - case 'D': - term_backward_char(); - break; - case 'C': - term_forward_char(); - break; - case '0' ... '9': - term_esc_param = term_esc_param * 10 + (ch - '0'); - goto the_end; - case '~': - switch(term_esc_param) { - case 1: - term_bol(); - break; - case 3: - term_delete_char(); - break; - case 4: - term_eol(); - break; - } - break; - default: - break; - } - term_esc_state = IS_NORM; - the_end: - break; + if (is_password) { + qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS); } - term_update(); -} - -static int term_can_read(void *opaque) -{ - return 128; -} - -static void term_read(void *opaque, const uint8_t *buf, int size) -{ - int i; - for(i = 0; i < size; i++) - term_handle_byte(buf[i]); -} - -void monitor_init(CharDriverState *hd, int show_banner) -{ - monitor_hd = hd; - if (show_banner) { - term_printf("QEMU %s monitor - type 'help' for more information\n", - QEMU_VERSION); - term_show_prompt(); + readline_start(prompt, is_password, monitor_readline_cb, NULL); + monitor_readline_buf = buf; + monitor_readline_buf_size = buf_size; + monitor_readline_started = 1; + while (monitor_readline_started) { + main_loop_wait(10); } - term_hist_entry = -1; - qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL); } diff --git a/readline.c b/readline.c new file mode 100644 index 000000000..cbe33dbdd --- /dev/null +++ b/readline.c @@ -0,0 +1,425 @@ +/* + * QEMU readline utility + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#define TERM_CMD_BUF_SIZE 4095 +#define TERM_MAX_CMDS 64 +#define NB_COMPLETIONS_MAX 256 + +#define IS_NORM 0 +#define IS_ESC 1 +#define IS_CSI 2 + +#define printf do_not_use_printf + +static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1]; +static int term_cmd_buf_index; +static int term_cmd_buf_size; + +static char term_last_cmd_buf[TERM_CMD_BUF_SIZE + 1]; +static int term_last_cmd_buf_index; +static int term_last_cmd_buf_size; + +static int term_esc_state; +static int term_esc_param; + +static char *term_history[TERM_MAX_CMDS]; +static int term_hist_entry = -1; + +static int nb_completions; +int completion_index; +static char *completions[NB_COMPLETIONS_MAX]; + +static ReadLineFunc *term_readline_func; +static int term_is_password; +static char term_prompt[256]; +static void *term_readline_opaque; + +static void term_show_prompt2(void) +{ + term_printf("%s", term_prompt); + term_flush(); + term_last_cmd_buf_index = 0; + term_last_cmd_buf_size = 0; + term_esc_state = IS_NORM; +} + +static void term_show_prompt(void) +{ + term_show_prompt2(); + term_cmd_buf_index = 0; + term_cmd_buf_size = 0; +} + +/* update the displayed command line */ +static void term_update(void) +{ + int i, delta, len; + + if (term_cmd_buf_size != term_last_cmd_buf_size || + memcmp(term_cmd_buf, term_last_cmd_buf, term_cmd_buf_size) != 0) { + for(i = 0; i < term_last_cmd_buf_index; i++) { + term_printf("\033[D"); + } + term_cmd_buf[term_cmd_buf_size] = '\0'; + if (term_is_password) { + len = strlen(term_cmd_buf); + for(i = 0; i < len; i++) + term_printf("*"); + } else { + term_printf("%s", term_cmd_buf); + } + term_printf("\033[K"); + memcpy(term_last_cmd_buf, term_cmd_buf, term_cmd_buf_size); + term_last_cmd_buf_size = term_cmd_buf_size; + term_last_cmd_buf_index = term_cmd_buf_size; + } + if (term_cmd_buf_index != term_last_cmd_buf_index) { + delta = term_cmd_buf_index - term_last_cmd_buf_index; + if (delta > 0) { + for(i = 0;i < delta; i++) { + term_printf("\033[C"); + } + } else { + delta = -delta; + for(i = 0;i < delta; i++) { + term_printf("\033[D"); + } + } + term_last_cmd_buf_index = term_cmd_buf_index; + } + term_flush(); +} + +static void term_insert_char(int ch) +{ + if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) { + memmove(term_cmd_buf + term_cmd_buf_index + 1, + term_cmd_buf + term_cmd_buf_index, + term_cmd_buf_size - term_cmd_buf_index); + term_cmd_buf[term_cmd_buf_index] = ch; + term_cmd_buf_size++; + term_cmd_buf_index++; + } +} + +static void term_backward_char(void) +{ + if (term_cmd_buf_index > 0) { + term_cmd_buf_index--; + } +} + +static void term_forward_char(void) +{ + if (term_cmd_buf_index < term_cmd_buf_size) { + term_cmd_buf_index++; + } +} + +static void term_delete_char(void) +{ + if (term_cmd_buf_index < term_cmd_buf_size) { + memmove(term_cmd_buf + term_cmd_buf_index, + term_cmd_buf + term_cmd_buf_index + 1, + term_cmd_buf_size - term_cmd_buf_index - 1); + term_cmd_buf_size--; + } +} + +static void term_backspace(void) +{ + if (term_cmd_buf_index > 0) { + term_backward_char(); + term_delete_char(); + } +} + +static void term_bol(void) +{ + term_cmd_buf_index = 0; +} + +static void term_eol(void) +{ + term_cmd_buf_index = term_cmd_buf_size; +} + +static void term_up_char(void) +{ + int idx; + + if (term_hist_entry == 0) + return; + if (term_hist_entry == -1) { + /* Find latest entry */ + for (idx = 0; idx < TERM_MAX_CMDS; idx++) { + if (term_history[idx] == NULL) + break; + } + term_hist_entry = idx; + } + term_hist_entry--; + if (term_hist_entry >= 0) { + pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), + term_history[term_hist_entry]); + term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); + } +} + +static void term_down_char(void) +{ + if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1) + return; + if (term_history[++term_hist_entry] != NULL) { + pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), + term_history[term_hist_entry]); + } else { + term_hist_entry = -1; + } + term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); +} + +static void term_hist_add(const char *cmdline) +{ + char *hist_entry, *new_entry; + int idx; + + if (cmdline[0] == '\0') + return; + new_entry = NULL; + if (term_hist_entry != -1) { + /* We were editing an existing history entry: replace it */ + hist_entry = term_history[term_hist_entry]; + idx = term_hist_entry; + if (strcmp(hist_entry, cmdline) == 0) { + goto same_entry; + } + } + /* Search cmdline in history buffers */ + for (idx = 0; idx < TERM_MAX_CMDS; idx++) { + hist_entry = term_history[idx]; + if (hist_entry == NULL) + break; + if (strcmp(hist_entry, cmdline) == 0) { + same_entry: + new_entry = hist_entry; + /* Put this entry at the end of history */ + memmove(&term_history[idx], &term_history[idx + 1], + &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]); + term_history[TERM_MAX_CMDS - 1] = NULL; + for (; idx < TERM_MAX_CMDS; idx++) { + if (term_history[idx] == NULL) + break; + } + break; + } + } + if (idx == TERM_MAX_CMDS) { + /* Need to get one free slot */ + free(term_history[0]); + memcpy(term_history, &term_history[1], + &term_history[TERM_MAX_CMDS] - &term_history[1]); + term_history[TERM_MAX_CMDS - 1] = NULL; + idx = TERM_MAX_CMDS - 1; + } + if (new_entry == NULL) + new_entry = strdup(cmdline); + term_history[idx] = new_entry; + term_hist_entry = -1; +} + +/* completion support */ + +void add_completion(const char *str) +{ + if (nb_completions < NB_COMPLETIONS_MAX) { + completions[nb_completions++] = qemu_strdup(str); + } +} + +static void term_completion(void) +{ + int len, i, j, max_width, nb_cols; + char *cmdline; + + nb_completions = 0; + + cmdline = qemu_malloc(term_cmd_buf_index + 1); + if (!cmdline) + return; + memcpy(cmdline, term_cmd_buf, term_cmd_buf_index); + cmdline[term_cmd_buf_index] = '\0'; + readline_find_completion(cmdline); + qemu_free(cmdline); + + /* no completion found */ + if (nb_completions <= 0) + return; + if (nb_completions == 1) { + len = strlen(completions[0]); + for(i = completion_index; i < len; i++) { + term_insert_char(completions[0][i]); + } + /* extra space for next argument. XXX: make it more generic */ + if (len > 0 && completions[0][len - 1] != '/') + term_insert_char(' '); + } else { + term_printf("\n"); + max_width = 0; + for(i = 0; i < nb_completions; i++) { + len = strlen(completions[i]); + if (len > max_width) + max_width = len; + } + max_width += 2; + if (max_width < 10) + max_width = 10; + else if (max_width > 80) + max_width = 80; + nb_cols = 80 / max_width; + j = 0; + for(i = 0; i < nb_completions; i++) { + term_printf("%-*s", max_width, completions[i]); + if (++j == nb_cols || i == (nb_completions - 1)) { + term_printf("\n"); + j = 0; + } + } + term_show_prompt2(); + } +} + +/* return true if command handled */ +void readline_handle_byte(int ch) +{ + switch(term_esc_state) { + case IS_NORM: + switch(ch) { + case 1: + term_bol(); + break; + case 4: + term_delete_char(); + break; + case 5: + term_eol(); + break; + case 9: + term_completion(); + break; + case 10: + case 13: + term_cmd_buf[term_cmd_buf_size] = '\0'; + if (!term_is_password) + term_hist_add(term_cmd_buf); + term_printf("\n"); + /* NOTE: readline_start can be called here */ + term_readline_func(term_readline_opaque, term_cmd_buf); + break; + case 27: + term_esc_state = IS_ESC; + break; + case 127: + case 8: + term_backspace(); + break; + case 155: + term_esc_state = IS_CSI; + break; + default: + if (ch >= 32) { + term_insert_char(ch); + } + break; + } + break; + case IS_ESC: + if (ch == '[') { + term_esc_state = IS_CSI; + term_esc_param = 0; + } else { + term_esc_state = IS_NORM; + } + break; + case IS_CSI: + switch(ch) { + case 'A': + case 'F': + term_up_char(); + break; + case 'B': + case 'E': + term_down_char(); + break; + case 'D': + term_backward_char(); + break; + case 'C': + term_forward_char(); + break; + case '0' ... '9': + term_esc_param = term_esc_param * 10 + (ch - '0'); + goto the_end; + case '~': + switch(term_esc_param) { + case 1: + term_bol(); + break; + case 3: + term_delete_char(); + break; + case 4: + term_eol(); + break; + } + break; + default: + break; + } + term_esc_state = IS_NORM; + the_end: + break; + } + term_update(); +} + +void readline_start(const char *prompt, int is_password, + ReadLineFunc *readline_func, void *opaque) +{ + pstrcpy(term_prompt, sizeof(term_prompt), prompt); + term_readline_func = readline_func; + term_readline_opaque = opaque; + term_is_password = is_password; + term_show_prompt(); +} + +const char *readline_get_history(unsigned int index) +{ + if (index >= TERM_MAX_CMDS) + return NULL; + return term_history[index]; +} + + -- cgit v1.2.3 From 5905b2e5fd051b046bf531c9b251fd6559145497 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 21:53:26 +0000 Subject: password input support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1035 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 36 deletions(-) diff --git a/vl.c b/vl.c index 3d64188b6..484d4becc 100644 --- a/vl.c +++ b/vl.c @@ -982,6 +982,12 @@ void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) va_end(ap); } +void qemu_chr_send_event(CharDriverState *s, int event) +{ + if (s->chr_send_event) + s->chr_send_event(s, event); +} + void qemu_chr_add_read_handler(CharDriverState *s, IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque) @@ -2179,7 +2185,7 @@ static void main_cpu_reset(void *opaque) #endif } -int main_loop(void) +void main_loop_wait(int timeout) { #ifndef _WIN32 struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf; @@ -2187,39 +2193,12 @@ int main_loop(void) uint8_t buf[4096]; int n, max_size; #endif - int ret, timeout; - CPUState *env = global_env; - - for(;;) { - if (vm_running) { - ret = cpu_exec(env); - if (shutdown_requested) { - ret = EXCP_INTERRUPT; - break; - } - if (reset_requested) { - reset_requested = 0; - qemu_system_reset(); - ret = EXCP_INTERRUPT; - } - if (ret == EXCP_DEBUG) { - vm_stop(EXCP_DEBUG); - } - /* if hlt instruction, we wait until the next IRQ */ - /* XXX: use timeout computed from timers */ - if (ret == EXCP_HLT) - timeout = 10; - else - timeout = 0; - } else { - timeout = 10; - } + int ret; #ifdef _WIN32 if (timeout > 0) Sleep(timeout); #else - /* poll any events */ /* XXX: separate device handlers from system ones */ pf = ufds; @@ -2269,7 +2248,7 @@ int main_loop(void) } } } - +#endif /* !defined(_WIN32) */ #if defined(CONFIG_SLIRP) /* XXX: merge with poll() */ if (slirp_inited) { @@ -2289,8 +2268,6 @@ int main_loop(void) slirp_select_poll(&rfds, &wfds, &xfds); } } -#endif - #endif if (vm_running) { @@ -2309,6 +2286,38 @@ int main_loop(void) /* real time timers */ qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock)); +} + +int main_loop(void) +{ + int ret, timeout; + CPUState *env = global_env; + + for(;;) { + if (vm_running) { + ret = cpu_exec(env); + if (shutdown_requested) { + ret = EXCP_INTERRUPT; + break; + } + if (reset_requested) { + reset_requested = 0; + qemu_system_reset(); + ret = EXCP_INTERRUPT; + } + if (ret == EXCP_DEBUG) { + vm_stop(EXCP_DEBUG); + } + /* if hlt instruction, we wait until the next IRQ */ + /* XXX: use timeout computed from timers */ + if (ret == EXCP_HLT) + timeout = 10; + else + timeout = 0; + } else { + timeout = 10; + } + main_loop_wait(timeout); } cpu_disable_ticks(); return ret; @@ -2509,6 +2518,43 @@ static uint8_t *signal_stack; #endif +/* password input */ + +static BlockDriverState *get_bdrv(int index) +{ + BlockDriverState *bs; + + if (index < 4) { + bs = bs_table[index]; + } else if (index < 6) { + bs = fd_table[index - 4]; + } else { + bs = NULL; + } + return bs; +} + +static void read_passwords(void) +{ + BlockDriverState *bs; + int i, j; + char password[256]; + + for(i = 0; i < 6; i++) { + bs = get_bdrv(i); + if (bs && bdrv_is_encrypted(bs)) { + term_printf("%s is encrypted.\n", bdrv_get_device_name(bs)); + for(j = 0; j < 3; j++) { + monitor_readline("Password: ", + 1, password, sizeof(password)); + if (bdrv_set_key(bs, password) == 0) + break; + term_printf("invalid password\n"); + } + } + } +} + #define NET_IF_TUN 0 #define NET_IF_USER 1 #define NET_IF_DUMMY 2 @@ -2952,6 +2998,7 @@ int main(int argc, char **argv) #endif /* we always create the cdrom drive, even if no disk is there */ + bdrv_init(); if (has_cdrom) { bs_table[2] = bdrv_new("cdrom"); bdrv_set_type_hint(bs_table[2], BDRV_TYPE_CDROM); @@ -2966,7 +3013,7 @@ int main(int argc, char **argv) bs_table[i] = bdrv_new(buf); } if (bdrv_open(bs_table[i], hd_filename[i], snapshot) < 0) { - fprintf(stderr, "qemu: could not open hard disk image '%s\n", + fprintf(stderr, "qemu: could not open hard disk image '%s'\n", hd_filename[i]); exit(1); } @@ -3106,13 +3153,17 @@ int main(int argc, char **argv) } else { printf("Waiting gdb connection on port %d\n", gdbstub_port); } + term_init(); } else #endif - if (start_emulation) { - vm_start(); + term_init(); + /* XXX: simplify init */ + read_passwords(); + if (start_emulation) { + vm_start(); + } } - term_init(); main_loop(); quit_timers(); return 0; -- cgit v1.2.3 From e4d4fe3c34cdd6e26f9b9975efec7d1e81ad00b6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 21:54:53 +0000 Subject: AES crypto support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1036 c046a42c-6fe2-441c-8c8c-71466251a162 --- aes.c | 1317 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ aes.h | 26 ++ 2 files changed, 1343 insertions(+) create mode 100644 aes.c create mode 100644 aes.h diff --git a/aes.c b/aes.c new file mode 100644 index 000000000..cd4484ff9 --- /dev/null +++ b/aes.c @@ -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 + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * 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 + +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); + } + } +} diff --git a/aes.h b/aes.h new file mode 100644 index 000000000..a0167eb7d --- /dev/null +++ b/aes.h @@ -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 -- cgit v1.2.3 From ea2384d36e1e5f6dfd44b748d290762181c38350 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 21:59:26 +0000 Subject: new disk image layer git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1037 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-cow.c | 263 +++++++++++++++++++++++ block-qcow.c | 677 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ block-vmdk.c | 278 ++++++++++++++++++++++++ block.c | 601 +++++++++++++++++++++++++++++----------------------- block_int.h | 77 +++++++ qemu-img.c | 677 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 209 ++++++------------ 7 files changed, 2372 insertions(+), 410 deletions(-) create mode 100644 block-cow.c create mode 100644 block-qcow.c create mode 100644 block-vmdk.c create mode 100644 block_int.h create mode 100644 qemu-img.c diff --git a/block-cow.c b/block-cow.c new file mode 100644 index 000000000..ab62c2a86 --- /dev/null +++ b/block-cow.c @@ -0,0 +1,263 @@ +/* + * 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 + +/**************************************************************/ +/* 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 (be32_to_cpu(cow_header->magic) == COW_MAGIC && + be32_to_cpu(cow_header->version) == COW_VERSION) + return 100; + else + return 0; +} + +static int cow_open(BlockDriverState *bs, const char *filename) +{ + BDRVCowState *s = bs->opaque; + int fd; + struct cow_header_v2 cow_header; + int64_t size; + + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) + return -1; + } + s->fd = fd; + /* see if it is a cow image */ + if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { + goto fail; + } + + if (be32_to_cpu(cow_header.magic) != COW_MAGIC || + be32_to_cpu(cow_header.version) != COW_VERSION) { + goto fail; + } + + /* cow image found */ + size = be64_to_cpu(cow_header.size); + bs->total_sectors = size / 512; + + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + cow_header.backing_file); + +#if 0 + if (cow_header.backing_file[0] != '\0') { + if (stat(cow_header.backing_file, &st) != 0) { + fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); + goto fail; + } + if (st.st_mtime != be32_to_cpu(cow_header.mtime)) { + fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); + goto fail; + } + fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); + if (fd < 0) + goto fail; + bs->fd = fd; + } +#endif + /* mmap the bitmap */ + s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); + s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size), + s->cow_bitmap_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, s->fd, 0); + if (s->cow_bitmap_addr == MAP_FAILED) + goto fail; + s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header); + s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511; + return 0; + fail: + close(fd); + return -1; +} + +static inline void 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)) { + lseek64(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); + ret = read(s->fd, buf, n * 512); + if (ret != n * 512) + return -1; + } else { + memset(buf, 0, n * 512); + } + nb_sectors -= n; + sector_num += n; + buf += n * 512; + } + return 0; +} + +static int cow_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BDRVCowState *s = bs->opaque; + int ret, i; + + lseek64(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++) + set_bit(s->cow_bitmap, sector_num + i); + return 0; +} + +static int cow_close(BlockDriverState *bs) +{ + BDRVCowState *s = bs->opaque; + munmap(s->cow_bitmap_addr, s->cow_bitmap_size); + close(s->fd); +} + +static int cow_create(const char *filename, int64_t image_sectors, + const char *image_filename, int flags) +{ + int fd, cow_fd; + struct cow_header_v2 cow_header; + struct stat st; + + if (flags) + return -ENOTSUP; + + cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, + 0644); + if (cow_fd < 0) + return -1; + memset(&cow_header, 0, sizeof(cow_header)); + cow_header.magic = cpu_to_be32(COW_MAGIC); + cow_header.version = cpu_to_be32(COW_VERSION); + if (image_filename) { + fd = open(image_filename, O_RDONLY | O_BINARY); + if (fd < 0) { + close(cow_fd); + return -1; + } + if (fstat(fd, &st) != 0) { + close(fd); + return -1; + } + close(fd); + cow_header.mtime = cpu_to_be32(st.st_mtime); + realpath(image_filename, cow_header.backing_file); + } + cow_header.sectorsize = cpu_to_be32(512); + cow_header.size = cpu_to_be64(image_sectors * 512); + write(cow_fd, &cow_header, sizeof(cow_header)); + /* resize to include at least all the bitmap */ + ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); + close(cow_fd); + return 0; +} + +BlockDriver bdrv_cow = { + "cow", + sizeof(BDRVCowState), + cow_probe, + cow_open, + cow_read, + cow_write, + cow_close, + cow_create, + cow_is_allocated, +}; +#endif diff --git a/block-qcow.c b/block-qcow.c new file mode 100644 index 000000000..ed6359f74 --- /dev/null +++ b/block-qcow.c @@ -0,0 +1,677 @@ +/* + * Block driver for the QCOW format + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "block_int.h" +#include "zlib.h" +#include "aes.h" + +/**************************************************************/ +/* QEMU COW block driver with compression and encryption support */ + +#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) +#define QCOW_VERSION 1 + +#define QCOW_CRYPT_NONE 0 +#define QCOW_CRYPT_AES 1 + +#define QCOW_OFLAG_COMPRESSED (1LL << 63) + +typedef struct QCowHeader { + uint32_t magic; + uint32_t version; + uint64_t backing_file_offset; + uint32_t backing_file_size; + uint32_t mtime; + uint64_t size; /* in bytes */ + uint8_t cluster_bits; + uint8_t l2_bits; + uint32_t crypt_method; + uint64_t l1_table_offset; +} QCowHeader; + +#define L2_CACHE_SIZE 16 + +typedef struct BDRVQcowState { + int fd; + int cluster_bits; + int cluster_size; + int cluster_sectors; + int l2_bits; + int l2_size; + int l1_size; + uint64_t cluster_offset_mask; + uint64_t l1_table_offset; + uint64_t *l1_table; + uint64_t *l2_cache; + uint64_t l2_cache_offsets[L2_CACHE_SIZE]; + uint32_t l2_cache_counts[L2_CACHE_SIZE]; + uint8_t *cluster_cache; + uint8_t *cluster_data; + uint64_t cluster_cache_offset; + uint32_t crypt_method; /* current crypt method, 0 if no key yet */ + uint32_t crypt_method_header; + AES_KEY aes_encrypt_key; + AES_KEY aes_decrypt_key; +} BDRVQcowState; + +static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); + +static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + const QCowHeader *cow_header = (const void *)buf; + + if (be32_to_cpu(cow_header->magic) == QCOW_MAGIC && + be32_to_cpu(cow_header->version) == QCOW_VERSION) + return 100; + else + return 0; +} + +static int qcow_open(BlockDriverState *bs, const char *filename) +{ + BDRVQcowState *s = bs->opaque; + int fd, len, i, shift; + QCowHeader header; + + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) + return -1; + } + s->fd = fd; + if (read(fd, &header, sizeof(header)) != sizeof(header)) + goto fail; + be32_to_cpus(&header.magic); + be32_to_cpus(&header.version); + be64_to_cpus(&header.backing_file_offset); + be32_to_cpus(&header.backing_file_size); + be32_to_cpus(&header.mtime); + be64_to_cpus(&header.size); + be32_to_cpus(&header.crypt_method); + be64_to_cpus(&header.l1_table_offset); + + if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) + goto fail; + if (header.size <= 1 || header.cluster_bits < 9) + goto fail; + if (header.crypt_method > QCOW_CRYPT_AES) + goto fail; + s->crypt_method_header = header.crypt_method; + if (s->crypt_method_header) + bs->encrypted = 1; + s->cluster_bits = header.cluster_bits; + s->cluster_size = 1 << s->cluster_bits; + s->cluster_sectors = 1 << (s->cluster_bits - 9); + s->l2_bits = header.l2_bits; + s->l2_size = 1 << s->l2_bits; + bs->total_sectors = header.size / 512; + s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1; + + /* read the level 1 table */ + shift = s->cluster_bits + s->l2_bits; + s->l1_size = (header.size + (1LL << shift) - 1) >> shift; + + s->l1_table_offset = header.l1_table_offset; + s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); + if (!s->l1_table) + goto fail; + lseek64(fd, s->l1_table_offset, SEEK_SET); + if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) != + s->l1_size * sizeof(uint64_t)) + goto fail; + for(i = 0;i < s->l1_size; i++) { + be64_to_cpus(&s->l1_table[i]); + } + /* alloc L2 cache */ + s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); + if (!s->l2_cache) + goto fail; + s->cluster_cache = qemu_malloc(s->cluster_size); + if (!s->cluster_cache) + goto fail; + s->cluster_data = qemu_malloc(s->cluster_size); + if (!s->cluster_data) + goto fail; + s->cluster_cache_offset = -1; + + /* read the backing file name */ + if (header.backing_file_offset != 0) { + len = header.backing_file_size; + if (len > 1023) + len = 1023; + lseek64(fd, header.backing_file_offset, SEEK_SET); + if (read(fd, bs->backing_file, len) != len) + goto fail; + bs->backing_file[len] = '\0'; + } + return 0; + + fail: + qemu_free(s->l1_table); + qemu_free(s->l2_cache); + qemu_free(s->cluster_cache); + qemu_free(s->cluster_data); + close(fd); + return -1; +} + +static int qcow_set_key(BlockDriverState *bs, const char *key) +{ + BDRVQcowState *s = bs->opaque; + uint8_t keybuf[16]; + int len, i; + + memset(keybuf, 0, 16); + len = strlen(key); + if (len > 16) + len = 16; + /* XXX: we could compress the chars to 7 bits to increase + entropy */ + for(i = 0;i < len;i++) { + keybuf[i] = key[i]; + } + s->crypt_method = s->crypt_method_header; + + if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0) + return -1; + if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0) + return -1; +#if 0 + /* test */ + { + uint8_t in[16]; + uint8_t out[16]; + uint8_t tmp[16]; + for(i=0;i<16;i++) + in[i] = i; + AES_encrypt(in, tmp, &s->aes_encrypt_key); + AES_decrypt(tmp, out, &s->aes_decrypt_key); + for(i = 0; i < 16; i++) + printf(" %02x", tmp[i]); + printf("\n"); + for(i = 0; i < 16; i++) + printf(" %02x", out[i]); + printf("\n"); + } +#endif + return 0; +} + +/* The crypt function is compatible with the linux cryptoloop + algorithm for < 4 GB images. NOTE: out_buf == in_buf is + supported */ +static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num, + uint8_t *out_buf, const uint8_t *in_buf, + int nb_sectors, int enc, + const AES_KEY *key) +{ + union { + uint64_t ll[2]; + uint8_t b[16]; + } ivec; + int i; + + for(i = 0; i < nb_sectors; i++) { + ivec.ll[0] = cpu_to_le64(sector_num); + ivec.ll[1] = 0; + AES_cbc_encrypt(in_buf, out_buf, 512, key, + ivec.b, enc); + sector_num++; + in_buf += 512; + out_buf += 512; + } +} + +/* 'allocate' is: + * + * 0 to not allocate. + * + * 1 to allocate a normal cluster (for sector indexes 'n_start' to + * 'n_end') + * + * 2 to allocate a compressed cluster of size + * 'compressed_size'. 'compressed_size' must be > 0 and < + * cluster_size + * + * return 0 if not allocated. + */ +static uint64_t get_cluster_offset(BlockDriverState *bs, + uint64_t offset, int allocate, + int compressed_size, + int n_start, int n_end) +{ + BDRVQcowState *s = bs->opaque; + int min_index, i, j, l1_index, l2_index; + uint64_t l2_offset, *l2_table, cluster_offset, tmp; + uint32_t min_count; + int new_l2_table; + + l1_index = offset >> (s->l2_bits + s->cluster_bits); + l2_offset = s->l1_table[l1_index]; + new_l2_table = 0; + if (!l2_offset) { + if (!allocate) + return 0; + /* allocate a new l2 entry */ + l2_offset = lseek64(s->fd, 0, SEEK_END); + /* round to cluster size */ + l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); + /* update the L1 entry */ + s->l1_table[l1_index] = l2_offset; + tmp = cpu_to_be64(l2_offset); + lseek64(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET); + if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp)) + return 0; + new_l2_table = 1; + } + for(i = 0; i < L2_CACHE_SIZE; i++) { + if (l2_offset == s->l2_cache_offsets[i]) { + /* increment the hit count */ + if (++s->l2_cache_counts[i] == 0xffffffff) { + for(j = 0; j < L2_CACHE_SIZE; j++) { + s->l2_cache_counts[j] >>= 1; + } + } + l2_table = s->l2_cache + (i << s->l2_bits); + goto found; + } + } + /* not found: load a new entry in the least used one */ + min_index = 0; + min_count = 0xffffffff; + for(i = 0; i < L2_CACHE_SIZE; i++) { + if (s->l2_cache_counts[i] < min_count) { + min_count = s->l2_cache_counts[i]; + min_index = i; + } + } + l2_table = s->l2_cache + (min_index << s->l2_bits); + lseek(s->fd, l2_offset, SEEK_SET); + if (new_l2_table) { + memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); + if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return 0; + } else { + if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return 0; + } + s->l2_cache_offsets[min_index] = l2_offset; + s->l2_cache_counts[min_index] = 1; + found: + l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); + cluster_offset = be64_to_cpu(l2_table[l2_index]); + if (!cluster_offset || + ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) { + if (!allocate) + return 0; + /* allocate a new cluster */ + if ((cluster_offset & QCOW_OFLAG_COMPRESSED) && + (n_end - n_start) < s->cluster_sectors) { + /* if the cluster is already compressed, we must + decompress it in the case it is not completely + overwritten */ + if (decompress_cluster(s, cluster_offset) < 0) + return 0; + cluster_offset = lseek64(s->fd, 0, SEEK_END); + cluster_offset = (cluster_offset + s->cluster_size - 1) & + ~(s->cluster_size - 1); + /* write the cluster content */ + lseek64(s->fd, cluster_offset, SEEK_SET); + if (write(s->fd, s->cluster_cache, s->cluster_size) != + s->cluster_size) + return -1; + } else { + cluster_offset = lseek64(s->fd, 0, SEEK_END); + if (allocate == 1) { + /* round to cluster size */ + cluster_offset = (cluster_offset + s->cluster_size - 1) & + ~(s->cluster_size - 1); + ftruncate(s->fd, cluster_offset + s->cluster_size); + /* if encrypted, we must initialize the cluster + content which won't be written */ + if (s->crypt_method && + (n_end - n_start) < s->cluster_sectors) { + uint64_t start_sect; + start_sect = (offset & ~(s->cluster_size - 1)) >> 9; + memset(s->cluster_data + 512, 0xaa, 512); + for(i = 0; i < s->cluster_sectors; i++) { + if (i < n_start || i >= n_end) { + encrypt_sectors(s, start_sect + i, + s->cluster_data, + s->cluster_data + 512, 1, 1, + &s->aes_encrypt_key); + lseek64(s->fd, cluster_offset + i * 512, SEEK_SET); + if (write(s->fd, s->cluster_data, 512) != 512) + return -1; + } + } + } + } else { + cluster_offset |= QCOW_OFLAG_COMPRESSED | + (uint64_t)compressed_size << (63 - s->cluster_bits); + } + } + /* update L2 table */ + tmp = cpu_to_be64(cluster_offset); + l2_table[l2_index] = tmp; + lseek64(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET); + if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp)) + return 0; + } + return cluster_offset; +} + +static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum) +{ + BDRVQcowState *s = bs->opaque; + int index_in_cluster, n; + uint64_t cluster_offset; + + cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); + index_in_cluster = sector_num & (s->cluster_sectors - 1); + n = s->cluster_sectors - index_in_cluster; + if (n > nb_sectors) + n = nb_sectors; + *pnum = n; + return (cluster_offset != 0); +} + +static int decompress_buffer(uint8_t *out_buf, int out_buf_size, + const uint8_t *buf, int buf_size) +{ + z_stream strm1, *strm = &strm1; + int ret, out_len; + + memset(strm, 0, sizeof(*strm)); + + strm->next_in = (uint8_t *)buf; + strm->avail_in = buf_size; + strm->next_out = out_buf; + strm->avail_out = out_buf_size; + + ret = inflateInit2(strm, -12); + if (ret != Z_OK) + return -1; + ret = inflate(strm, Z_FINISH); + out_len = strm->next_out - out_buf; + if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || + out_len != out_buf_size) { + inflateEnd(strm); + return -1; + } + inflateEnd(strm); + return 0; +} + +static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) +{ + int ret, csize; + uint64_t coffset; + + coffset = cluster_offset & s->cluster_offset_mask; + if (s->cluster_cache_offset != coffset) { + csize = cluster_offset >> (63 - s->cluster_bits); + csize &= (s->cluster_size - 1); + lseek64(s->fd, coffset, SEEK_SET); + ret = read(s->fd, s->cluster_data, csize); + if (ret != csize) + return -1; + if (decompress_buffer(s->cluster_cache, s->cluster_size, + s->cluster_data, csize) < 0) { + return -1; + } + s->cluster_cache_offset = coffset; + } + return 0; +} + +static int qcow_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVQcowState *s = bs->opaque; + int ret, index_in_cluster, n; + uint64_t cluster_offset; + + while (nb_sectors > 0) { + cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); + index_in_cluster = sector_num & (s->cluster_sectors - 1); + n = s->cluster_sectors - index_in_cluster; + if (n > nb_sectors) + n = nb_sectors; + if (!cluster_offset) { + memset(buf, 0, 512 * n); + } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { + if (decompress_cluster(s, cluster_offset) < 0) + return -1; + memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); + } else { + lseek64(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); + ret = read(s->fd, buf, n * 512); + if (ret != n * 512) + return -1; + if (s->crypt_method) { + encrypt_sectors(s, sector_num, buf, buf, n, 0, + &s->aes_decrypt_key); + } + } + nb_sectors -= n; + sector_num += n; + buf += n * 512; + } + return 0; +} + +static int qcow_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BDRVQcowState *s = bs->opaque; + int ret, index_in_cluster, n; + uint64_t cluster_offset; + + while (nb_sectors > 0) { + index_in_cluster = sector_num & (s->cluster_sectors - 1); + n = s->cluster_sectors - index_in_cluster; + if (n > nb_sectors) + n = nb_sectors; + cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, + index_in_cluster, + index_in_cluster + n); + if (!cluster_offset) + return -1; + lseek64(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); + if (s->crypt_method) { + encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1, + &s->aes_encrypt_key); + ret = write(s->fd, s->cluster_data, n * 512); + } else { + ret = write(s->fd, buf, n * 512); + } + if (ret != n * 512) + return -1; + nb_sectors -= n; + sector_num += n; + buf += n * 512; + } + s->cluster_cache_offset = -1; /* disable compressed cache */ + return 0; +} + +static int qcow_close(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + qemu_free(s->l1_table); + qemu_free(s->l2_cache); + qemu_free(s->cluster_cache); + qemu_free(s->cluster_data); + close(s->fd); +} + +static int qcow_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + int fd, header_size, backing_filename_len, l1_size, i, shift; + QCowHeader header; + char backing_filename[1024]; + uint64_t tmp; + struct stat st; + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, + 0644); + if (fd < 0) + return -1; + memset(&header, 0, sizeof(header)); + header.magic = cpu_to_be32(QCOW_MAGIC); + header.version = cpu_to_be32(QCOW_VERSION); + header.size = cpu_to_be64(total_size * 512); + header_size = sizeof(header); + backing_filename_len = 0; + if (backing_file) { + realpath(backing_file, backing_filename); + if (stat(backing_filename, &st) != 0) { + return -1; + } + header.mtime = cpu_to_be32(st.st_mtime); + header.backing_file_offset = cpu_to_be64(header_size); + backing_filename_len = strlen(backing_filename); + header.backing_file_size = cpu_to_be32(backing_filename_len); + header_size += backing_filename_len; + header.cluster_bits = 9; /* 512 byte cluster to avoid copying + unmodifyed sectors */ + header.l2_bits = 12; /* 32 KB L2 tables */ + } else { + header.cluster_bits = 12; /* 4 KB clusters */ + header.l2_bits = 9; /* 4 KB L2 tables */ + } + header_size = (header_size + 7) & ~7; + shift = header.cluster_bits + header.l2_bits; + l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift; + + header.l1_table_offset = cpu_to_be64(header_size); + if (flags) { + header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); + } else { + header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); + } + + /* write all the data */ + write(fd, &header, sizeof(header)); + if (backing_file) { + write(fd, backing_filename, backing_filename_len); + } + lseek(fd, header_size, SEEK_SET); + tmp = 0; + for(i = 0;i < l1_size; i++) { + write(fd, &tmp, sizeof(tmp)); + } + close(fd); + return 0; +} + +int qcow_get_cluster_size(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + if (bs->drv != &bdrv_qcow) + return -1; + return s->cluster_size; +} + +/* XXX: put compressed sectors first, then all the cluster aligned + tables to avoid losing bytes in alignment */ +int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf) +{ + BDRVQcowState *s = bs->opaque; + z_stream strm; + int ret, out_len; + uint8_t *out_buf; + uint64_t cluster_offset; + + if (bs->drv != &bdrv_qcow) + return -1; + + out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128); + if (!out_buf) + return -1; + + /* best compression, small window, no zlib header */ + memset(&strm, 0, sizeof(strm)); + ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, + Z_DEFLATED, -12, + 9, Z_DEFAULT_STRATEGY); + if (ret != 0) { + qemu_free(out_buf); + return -1; + } + + strm.avail_in = s->cluster_size; + strm.next_in = (uint8_t *)buf; + strm.avail_out = s->cluster_size; + strm.next_out = out_buf; + + ret = deflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END && ret != Z_OK) { + qemu_free(out_buf); + deflateEnd(&strm); + return -1; + } + out_len = strm.next_out - out_buf; + + deflateEnd(&strm); + + if (ret != Z_STREAM_END || out_len >= s->cluster_size) { + /* could not compress: write normal cluster */ + qcow_write(bs, sector_num, buf, s->cluster_sectors); + } else { + cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, + out_len, 0, 0); + cluster_offset &= s->cluster_offset_mask; + lseek64(s->fd, cluster_offset, SEEK_SET); + if (write(s->fd, out_buf, out_len) != out_len) { + qemu_free(out_buf); + return -1; + } + } + + qemu_free(out_buf); + return 0; +} + +BlockDriver bdrv_qcow = { + "qcow", + sizeof(BDRVQcowState), + qcow_probe, + qcow_open, + qcow_read, + qcow_write, + qcow_close, + qcow_create, + qcow_is_allocated, + qcow_set_key, +}; + + diff --git a/block-vmdk.c b/block-vmdk.c new file mode 100644 index 000000000..d1414e430 --- /dev/null +++ b/block-vmdk.c @@ -0,0 +1,278 @@ +/* + * Block driver for the VMDK format + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "block_int.h" + +/* XXX: this code is untested */ +/* XXX: add write support */ + +#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]; +} VMDK4Header; + +#define L2_CACHE_SIZE 16 + +typedef struct BDRVVmdkState { + int fd; + int64_t l1_table_offset; + uint32_t *l1_table; + unsigned int l1_size; + uint32_t l1_entry_sectors; + + unsigned int l2_size; + uint32_t *l2_cache; + uint32_t l2_cache_offsets[L2_CACHE_SIZE]; + uint32_t l2_cache_counts[L2_CACHE_SIZE]; + + unsigned int cluster_sectors; +} BDRVVmdkState; + +static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + uint32_t magic; + + if (buf_size < 4) + return 0; + magic = be32_to_cpu(*(uint32_t *)buf); + if (magic == VMDK3_MAGIC || + magic == VMDK4_MAGIC) + return 100; + else + return 0; +} + +static int vmdk_open(BlockDriverState *bs, const char *filename) +{ + BDRVVmdkState *s = bs->opaque; + int fd, i; + uint32_t magic; + int l1_size; + + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) + return -1; + if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) + goto fail; + magic = le32_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) * 512; + s->l1_entry_sectors = s->l2_size * s->cluster_sectors; + } else if (magic == VMDK4_MAGIC) { + VMDK4Header header; + + if (read(fd, &header, sizeof(header)) != sizeof(header)) + goto fail; + bs->total_sectors = le32_to_cpu(header.capacity); + s->cluster_sectors = le32_to_cpu(header.granularity); + s->l2_size = le32_to_cpu(header.num_gtes_per_gte); + s->l1_entry_sectors = s->l2_size * s->cluster_sectors; + if (s->l1_entry_sectors <= 0) + goto fail; + s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1) + / s->l1_entry_sectors; + s->l1_table_offset = le64_to_cpu(header.rgd_offset) * 512; + } 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 (read(s->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]); + } + + s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t)); + if (!s->l2_cache) + goto fail; + s->fd = fd; + /* XXX: currently only read only */ + bs->read_only = 1; + return 0; + fail: + 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) +{ + BDRVVmdkState *s = bs->opaque; + unsigned int l1_index, l2_offset, l2_index; + int min_index, i, j; + uint32_t min_count, *l2_table; + 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]); + 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); + 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); + 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 { + lseek64(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) +{ + return -1; +} + +static int vmdk_close(BlockDriverState *bs) +{ + BDRVVmdkState *s = bs->opaque; + qemu_free(s->l1_table); + qemu_free(s->l2_cache); + close(s->fd); +} + +BlockDriver bdrv_vmdk = { + "vmdk", + sizeof(BDRVVmdkState), + vmdk_probe, + vmdk_open, + vmdk_read, + vmdk_write, + vmdk_close, + NULL, /* no create yet */ + vmdk_is_allocated, +}; diff --git a/block.c b/block.c index 894656402..43b018814 100644 --- a/block.c +++ b/block.c @@ -22,43 +22,16 @@ * THE SOFTWARE. */ #include "vl.h" - -#ifndef _WIN32 -#include -#endif - -#include "cow.h" - -struct BlockDriverState { - int fd; /* if -1, only COW mappings */ - int64_t total_sectors; - int read_only; /* if true, the media is read only */ - int inserted; /* if true, the media is present */ - int removable; /* if true, the media can be removed */ - int locked; /* if true, the media cannot temporarily be ejected */ - /* event callback when inserting/removing */ - void (*change_cb)(void *opaque); - void *change_opaque; - - uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ - uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ - int cow_bitmap_size; - int cow_fd; - int64_t cow_sectors_offset; - int boot_sector_enabled; - uint8_t boot_sector_data[512]; - - char filename[1024]; - - /* NOTE: the following infos are only hints for real hardware - drivers. They are not used by the block driver */ - int cyls, heads, secs; - int type; - char device_name[32]; - BlockDriverState *next; -}; +#include "block_int.h" static BlockDriverState *bdrv_first; +static BlockDriver *first_drv; + +void bdrv_register(BlockDriver *bdrv) +{ + bdrv->next = first_drv; + first_drv = bdrv; +} /* create a new block device (by default it is empty) */ BlockDriverState *bdrv_new(const char *device_name) @@ -69,126 +42,149 @@ BlockDriverState *bdrv_new(const char *device_name) if(!bs) return NULL; pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); - /* insert at the end */ - pbs = &bdrv_first; - while (*pbs != NULL) - pbs = &(*pbs)->next; - *pbs = bs; + if (device_name[0] != '\0') { + /* insert at the end */ + pbs = &bdrv_first; + while (*pbs != NULL) + pbs = &(*pbs)->next; + *pbs = bs; + } return bs; } -int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) +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); +} + +/* XXX: race condition possible */ +static void get_tmp_filename(char *filename, int size) { int fd; - int64_t size; - struct cow_header_v2 cow_header; -#ifndef _WIN32 - char template[] = "/tmp/vl.XXXXXX"; - int cow_fd; - struct stat st; -#endif + pstrcpy(filename, size, "/tmp/vl.XXXXXX"); + fd = mkstemp(filename); + close(fd); +} - bs->read_only = 0; - bs->fd = -1; - bs->cow_fd = -1; - bs->cow_bitmap = NULL; - pstrcpy(bs->filename, sizeof(bs->filename), filename); +static BlockDriver *find_image_format(const char *filename) +{ + int fd, ret, score, score_max; + BlockDriver *drv1, *drv; + uint8_t buf[1024]; - /* open standard HD image */ -#ifdef _WIN32 - fd = open(filename, O_RDWR | O_BINARY); -#else - fd = open(filename, O_RDWR | O_LARGEFILE); -#endif - if (fd < 0) { - /* read only image on disk */ -#ifdef _WIN32 - fd = open(filename, O_RDONLY | O_BINARY); -#else - fd = open(filename, O_RDONLY | O_LARGEFILE); -#endif - if (fd < 0) { - perror(filename); - goto fail; + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) + return NULL; + ret = read(fd, buf, sizeof(buf)); + if (ret < 0) { + close(fd); + return NULL; + } + close(fd); + + drv = NULL; + score_max = 0; + for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { + score = drv1->bdrv_probe(buf, ret, filename); + if (score > score_max) { + score_max = score; + drv = drv1; } - if (!snapshot) - bs->read_only = 1; } - bs->fd = fd; + return drv; +} + +int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) +{ + return bdrv_open2(bs, filename, snapshot, NULL); +} + +int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, + BlockDriver *drv) +{ + int ret; + char tmp_filename[1024]; + + bs->read_only = 0; + bs->is_temporary = 0; + bs->encrypted = 0; + + if (snapshot) { + BlockDriverState *bs1; + int64_t total_size; + + /* if snapshot, we create a temporary backing file and open it + instead of opening 'filename' directly */ - /* see if it is a cow image */ - if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { - fprintf(stderr, "%s: could not read header\n", filename); - goto fail; + /* if there is a backing file, use it */ + bs1 = bdrv_new(""); + if (!bs1) { + return -1; + } + if (bdrv_open(bs1, filename, 0) < 0) { + bdrv_delete(bs1); + return -1; + } + total_size = bs1->total_sectors; + bdrv_delete(bs1); + + get_tmp_filename(tmp_filename, sizeof(tmp_filename)); + /* XXX: use cow for linux as it is more efficient ? */ + if (bdrv_create(&bdrv_qcow, tmp_filename, + total_size, filename, 0) < 0) { + return -1; + } + filename = tmp_filename; + bs->is_temporary = 1; + } + + pstrcpy(bs->filename, sizeof(bs->filename), filename); + if (!drv) { + drv = find_image_format(filename); + if (!drv) + return -1; + } + bs->drv = drv; + bs->opaque = qemu_mallocz(drv->instance_size); + if (bs->opaque == NULL && drv->instance_size > 0) + return -1; + + ret = drv->bdrv_open(bs, filename); + if (ret < 0) { + qemu_free(bs->opaque); + return -1; } #ifndef _WIN32 - if (be32_to_cpu(cow_header.magic) == COW_MAGIC && - be32_to_cpu(cow_header.version) == COW_VERSION) { - /* cow image found */ - size = cow_header.size; -#ifndef WORDS_BIGENDIAN - size = bswap64(size); -#endif - bs->total_sectors = size / 512; - - bs->cow_fd = fd; - bs->fd = -1; - if (cow_header.backing_file[0] != '\0') { - if (stat(cow_header.backing_file, &st) != 0) { - fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); - goto fail; - } - if (st.st_mtime != be32_to_cpu(cow_header.mtime)) { - fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); - goto fail; - } - fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); - if (fd < 0) - goto fail; - bs->fd = fd; + if (bs->is_temporary) { + unlink(filename); + } +#endif + if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { + /* if there is a backing file, use it */ + bs->backing_hd = bdrv_new(""); + if (!bs->backing_hd) { + fail: + bdrv_close(bs); + return -1; } - /* mmap the bitmap */ - bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); - bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), - bs->cow_bitmap_size, - PROT_READ | PROT_WRITE, - MAP_SHARED, bs->cow_fd, 0); - if (bs->cow_bitmap_addr == MAP_FAILED) + if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) goto fail; - bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header); - bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; - snapshot = 0; - } else -#endif - { - /* standard raw image */ - size = lseek64(fd, 0, SEEK_END); - bs->total_sectors = size / 512; - bs->fd = fd; } -#ifndef _WIN32 - if (snapshot) { - /* create a temporary COW file */ - cow_fd = mkstemp64(template); - if (cow_fd < 0) - goto fail; - bs->cow_fd = cow_fd; - unlink(template); - - /* just need to allocate bitmap */ - bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3; - bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), - bs->cow_bitmap_size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (bs->cow_bitmap_addr == MAP_FAILED) - goto fail; - bs->cow_bitmap = bs->cow_bitmap_addr; - bs->cow_sectors_offset = 0; - } -#endif - bs->inserted = 1; /* call the change callback */ @@ -196,23 +192,22 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) bs->change_cb(bs->change_opaque); return 0; - fail: - bdrv_close(bs); - return -1; } void bdrv_close(BlockDriverState *bs) { if (bs->inserted) { -#ifndef _WIN32 - /* we unmap the mapping so that it is written to the COW file */ - if (bs->cow_bitmap_addr) - munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); + if (bs->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 - if (bs->cow_fd >= 0) - close(bs->cow_fd); - if (bs->fd >= 0) - close(bs->fd); + bs->opaque = NULL; + bs->drv = NULL; bs->inserted = 0; /* call the change callback */ @@ -223,85 +218,45 @@ void bdrv_close(BlockDriverState *bs) void bdrv_delete(BlockDriverState *bs) { + /* XXX: remove the driver list */ bdrv_close(bs); qemu_free(bs); } -static inline void set_bit(uint8_t *bitmap, int64_t bitnum) -{ - bitmap[bitnum / 8] |= (1 << (bitnum%8)); -} - -static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) -{ - return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); -} - - -/* Return true if first block has been changed (ie. current version is - * in COW file). Set the number of continuous blocks for which that - * is true. */ -static int is_changed(uint8_t *bitmap, - int64_t sector_num, int nb_sectors, - int *num_same) -{ - int changed; - - if (!bitmap || nb_sectors == 0) { - *num_same = nb_sectors; - return 0; - } - - changed = is_bit_set(bitmap, sector_num); - for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { - if (is_bit_set(bitmap, sector_num + *num_same) != changed) - break; - } - - return changed; -} - /* commit COW file into the raw image */ int bdrv_commit(BlockDriverState *bs) { int64_t i; - uint8_t *cow_bitmap; + int n, j; + unsigned char sector[512]; if (!bs->inserted) - return -1; - - if (!bs->cow_bitmap) { - fprintf(stderr, "Already committed to %s\n", bs->filename); - return 0; - } + return -ENOENT; if (bs->read_only) { - fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename); - return -1; + return -EACCES; } - cow_bitmap = bs->cow_bitmap; - for (i = 0; i < bs->total_sectors; i++) { - if (is_bit_set(cow_bitmap, i)) { - unsigned char sector[512]; - if (bdrv_read(bs, i, sector, 1) != 0) { - fprintf(stderr, "Error reading sector %lli: aborting commit\n", - (long long)i); - return -1; - } + if (!bs->backing_hd) { + return -ENOTSUP; + } - /* Make bdrv_write write to real file for a moment. */ - bs->cow_bitmap = NULL; - if (bdrv_write(bs, i, sector, 1) != 0) { - fprintf(stderr, "Error writing sector %lli: aborting commit\n", - (long long)i); - bs->cow_bitmap = cow_bitmap; - return -1; + for (i = 0; i < bs->total_sectors;) { + if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { + for(j = 0; j < n; j++) { + if (bdrv_read(bs, i, sector, 1) != 0) { + return -EIO; + } + + if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { + return -EIO; + } + i++; } - bs->cow_bitmap = cow_bitmap; - } + } else { + i += n; + } } - fprintf(stderr, "Committed snapshot to %s\n", bs->filename); return 0; } @@ -309,37 +264,34 @@ int bdrv_commit(BlockDriverState *bs) int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { - int ret, n, fd; - int64_t offset; - + int ret, n; + BlockDriver *drv = bs->drv; + if (!bs->inserted) return -1; while (nb_sectors > 0) { - if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) { - fd = bs->cow_fd; - offset = bs->cow_sectors_offset; - } else if (sector_num == 0 && bs->boot_sector_enabled) { + if (sector_num == 0 && bs->boot_sector_enabled) { memcpy(buf, bs->boot_sector_data, 512); n = 1; - goto next; - } else { - fd = bs->fd; - offset = 0; - } - - if (fd < 0) { - /* no file, just return empty sectors */ - memset(buf, 0, n * 512); + } else if (bs->backing_hd) { + if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { + ret = drv->bdrv_read(bs, sector_num, buf, n); + if (ret < 0) + return -1; + } else { + /* read from the base image */ + ret = bdrv_read(bs->backing_hd, sector_num, buf, n); + if (ret < 0) + return -1; + } } else { - offset += sector_num * 512; - lseek64(fd, offset, SEEK_SET); - ret = read(fd, buf, n * 512); - if (ret != n * 512) { + ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); + if (ret < 0) return -1; - } + /* no need to loop */ + break; } - next: nb_sectors -= n; sector_num += n; buf += n * 512; @@ -351,37 +303,11 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - int ret, fd, i; - int64_t offset, retl; - if (!bs->inserted) return -1; if (bs->read_only) return -1; - - if (bs->cow_bitmap) { - fd = bs->cow_fd; - offset = bs->cow_sectors_offset; - } else { - fd = bs->fd; - offset = 0; - } - - offset += sector_num * 512; - retl = lseek64(fd, offset, SEEK_SET); - if (retl == -1) { - return -1; - } - ret = write(fd, buf, nb_sectors * 512); - if (ret != nb_sectors * 512) { - return -1; - } - - if (bs->cow_bitmap) { - for (i = 0; i < nb_sectors; i++) - set_bit(bs->cow_bitmap, sector_num + i); - } - return 0; + return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); } void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) @@ -459,6 +385,47 @@ void bdrv_set_change_cb(BlockDriverState *bs, bs->change_opaque = opaque; } +int bdrv_is_encrypted(BlockDriverState *bs) +{ + if (bs->backing_hd && bs->backing_hd->encrypted) + return 1; + return bs->encrypted; +} + +int bdrv_set_key(BlockDriverState *bs, const char *key) +{ + int ret; + if (bs->backing_hd && bs->backing_hd->encrypted) { + ret = bdrv_set_key(bs->backing_hd, key); + if (ret < 0) + return ret; + if (!bs->encrypted) + return 0; + } + if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) + return -1; + return bs->drv->bdrv_set_key(bs, key); +} + +void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) +{ + if (!bs->inserted || !bs->drv) { + buf[0] = '\0'; + } else { + pstrcpy(buf, buf_size, bs->drv->format_name); + } +} + +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), + void *opaque) +{ + BlockDriver *drv; + + for (drv = first_drv; drv != NULL; drv = drv->next) { + it(opaque, drv->format_name); + } +} + BlockDriverState *bdrv_find(const char *name) { BlockDriverState *bs; @@ -479,6 +446,11 @@ void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) } } +const char *bdrv_get_device_name(BlockDriverState *bs) +{ + return bs->device_name; +} + void bdrv_info(void) { BlockDriverState *bs; @@ -503,10 +475,117 @@ void bdrv_info(void) } if (bs->inserted) { term_printf(" file=%s", bs->filename); + if (bs->backing_file[0] != '\0') + term_printf(" backing_file=%s", bs->backing_file); term_printf(" ro=%d", bs->read_only); + term_printf(" drv=%s", bs->drv->format_name); + if (bs->encrypted) + term_printf(" encrypted"); } else { term_printf(" [not inserted]"); } term_printf("\n"); } } + + +/**************************************************************/ +/* RAW block driver */ + +typedef struct BDRVRawState { + int fd; +} BDRVRawState; + +static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + return 1; /* maybe */ +} + +static int raw_open(BlockDriverState *bs, const char *filename) +{ + BDRVRawState *s = bs->opaque; + int fd; + int64_t size; + + 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; + } + size = lseek64(fd, 0, SEEK_END); + bs->total_sectors = size / 512; + s->fd = fd; + return 0; +} + +static int raw_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVRawState *s = bs->opaque; + int ret; + + lseek64(s->fd, sector_num * 512, SEEK_SET); + ret = read(s->fd, buf, nb_sectors * 512); + if (ret != nb_sectors * 512) + return -1; + return 0; +} + +static int raw_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BDRVRawState *s = bs->opaque; + int ret; + + lseek64(s->fd, sector_num * 512, SEEK_SET); + ret = write(s->fd, buf, nb_sectors * 512); + if (ret != nb_sectors * 512) + return -1; + return 0; +} + +static int raw_close(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + close(s->fd); +} + +static int raw_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + int fd; + + if (flags || backing_file) + return -ENOTSUP; + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, + 0644); + if (fd < 0) + return -EIO; + ftruncate64(fd, total_size * 512); + close(fd); + return 0; +} + +BlockDriver bdrv_raw = { + "raw", + sizeof(BDRVRawState), + raw_probe, + raw_open, + raw_read, + raw_write, + raw_close, + raw_create, +}; + +void bdrv_init(void) +{ + bdrv_register(&bdrv_raw); +#ifndef _WIN32 + bdrv_register(&bdrv_cow); +#endif + bdrv_register(&bdrv_qcow); + bdrv_register(&bdrv_vmdk); +} diff --git a/block_int.h b/block_int.h new file mode 100644 index 000000000..36a88ed0a --- /dev/null +++ b/block_int.h @@ -0,0 +1,77 @@ +/* + * QEMU System Emulator block driver + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef BLOCK_INT_H +#define BLOCK_INT_H + +struct BlockDriver { + const char *format_name; + int instance_size; + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); + int (*bdrv_open)(BlockDriverState *bs, const char *filename); + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); + int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + int (*bdrv_close)(BlockDriverState *bs); + int (*bdrv_create)(const char *filename, int64_t total_sectors, + const char *backing_file, int flags); + int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum); + int (*bdrv_set_key)(BlockDriverState *bs, const char *key); + struct BlockDriver *next; +}; + +struct BlockDriverState { + int64_t total_sectors; + int read_only; /* if true, the media is read only */ + int inserted; /* if true, the media is present */ + int removable; /* if true, the media can be removed */ + int locked; /* if true, the media cannot temporarily be ejected */ + int encrypted; /* if true, the media is encrypted */ + /* event callback when inserting/removing */ + void (*change_cb)(void *opaque); + void *change_opaque; + + BlockDriver *drv; + void *opaque; + + int boot_sector_enabled; + uint8_t boot_sector_data[512]; + + char filename[1024]; + char backing_file[1024]; /* if non zero, the image is a diff of + this file image */ + int is_temporary; + + BlockDriverState *backing_hd; + + /* NOTE: the following infos are only hints for real hardware + drivers. They are not used by the block driver */ + int cyls, heads, secs; + int type; + char device_name[32]; + BlockDriverState *next; +}; + +#endif /* BLOCK_INT_H */ diff --git a/qemu-img.c b/qemu-img.c new file mode 100644 index 000000000..480dff95f --- /dev/null +++ b/qemu-img.c @@ -0,0 +1,677 @@ +/* + * create a COW disk image + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +void *get_mmap_addr(unsigned long size) +{ + return NULL; +} + +void qemu_free(void *ptr) +{ + free(ptr); +} + +void *qemu_malloc(size_t size) +{ + return malloc(size); +} + +void *qemu_mallocz(size_t size) +{ + void *ptr; + ptr = qemu_malloc(size); + if (!ptr) + return NULL; + memset(ptr, 0, size); + return ptr; +} + +char *qemu_strdup(const char *str) +{ + char *ptr; + ptr = qemu_malloc(strlen(str) + 1); + if (!ptr) + return NULL; + strcpy(ptr, str); + return ptr; +} + +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; +} + +void term_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +void __attribute__((noreturn)) error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "qemuimg: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + exit(1); + va_end(ap); +} + +static void format_print(void *opaque, const char *name) +{ + printf(" %s", name); +} + +void help(void) +{ + printf("qemuimg version " QEMU_VERSION ", Copyright (c) 2004 Fabrice Bellard\n" + "usage: qemuimg command [command options]\n" + "QEMU disk image utility\n" + "\n" + "Command syntax:\n" + " create [-e] [-b base_image] [-f fmt] filename [size]\n" + " commit [-f fmt] filename\n" + " convert [-c] [-e] [-f fmt] filename [-O output_fmt] output_filename\n" + " info [-f fmt] filename\n" + "\n" + "Command parameters:\n" + " 'filename' is a disk image filename\n" + " 'base_image' is the read-only disk image which is used as base for a copy on\n" + " write image; the copy on write image only stores the modified data\n" + " 'fmt' is the disk image format. It is guessed automatically in most cases\n" + " 'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n" + " and 'G' (gigabyte) are supported\n" + " 'output_filename' is the destination disk image filename\n" + " 'output_fmt' is the destination format\n" + " '-c' indicates that target image must be compressed (qcow format only)\n" + " '-e' indicates that the target image must be encrypted (qcow format only)\n" + ); + printf("\nSupported format:"); + bdrv_iterate_format(format_print, NULL); + printf("\n"); + exit(1); +} + + +#define NB_SUFFIXES 4 + +static void get_human_readable_size(char *buf, int buf_size, int64_t size) +{ + char suffixes[NB_SUFFIXES] = "KMGT"; + int64_t base; + int i; + + if (size <= 999) { + snprintf(buf, buf_size, "%lld", 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, "%lld%c", + (size + (base >> 1)) / base, + suffixes[i]); + break; + } + base = base * 1024; + } + } +} + +#if defined(WIN32) +/* XXX: put correct support for win32 */ +static int read_password(char *buf, int buf_size) +{ + int c, i; + printf("Password: "); + fflush(stdout); + i = 0; + for(;;) { + c = getchar(); + if (c == '\n') + break; + if (i < (buf_size - 1)) + buf[i++] = c; + } + buf[i] = '\0'; + return 0; +} + +#else + +#include + +static struct termios oldtty; + +static void term_exit(void) +{ + tcsetattr (0, TCSANOW, &oldtty); +} + +static void term_init(void) +{ + struct termios tty; + + tcgetattr (0, &tty); + oldtty = tty; + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + tcsetattr (0, TCSANOW, &tty); + + atexit(term_exit); +} + +int read_password(char *buf, int buf_size) +{ + uint8_t ch; + int i, ret; + + printf("password: "); + fflush(stdout); + term_init(); + i = 0; + for(;;) { + ret = read(0, &ch, 1); + if (ret == -1) { + if (errno == EAGAIN || errno == EINTR) { + continue; + } else { + ret = -1; + break; + } + } else if (ret == 0) { + ret = -1; + break; + } else { + if (ch == '\r') { + ret = 0; + break; + } + if (i < (buf_size - 1)) + buf[i++] = ch; + } + } + term_exit(); + buf[i] = '\0'; + printf("\n"); + return ret; +} +#endif + +static int img_create(int argc, char **argv) +{ + int c, ret, encrypted; + const char *fmt = "raw"; + const char *filename; + const char *base_filename = NULL; + int64_t size; + const char *p; + BlockDriver *drv; + + encrypted = 0; + for(;;) { + c = getopt(argc, argv, "b:f:he"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 'b': + base_filename = optarg; + break; + case 'f': + fmt = optarg; + break; + case 'e': + encrypted = 1; + break; + } + } + optind++; + if (optind >= argc) + help(); + filename = argv[optind++]; + size = 0; + if (!base_filename) { + if (optind >= argc) + help(); + p = argv[optind]; + size = strtoul(p, (char **)&p, 0); + if (*p == 'M') { + size *= 1024 * 1024; + } else if (*p == 'G') { + size *= 1024 * 1024 * 1024; + } else if (*p == 'k' || *p == 'K' || *p == '\0') { + size *= 1024; + } else { + help(); + } + } + drv = bdrv_find_format(fmt); + if (!drv) + error("Unknown file format '%s'", fmt); + printf("Formating '%s', fmt=%s", + filename, fmt); + if (encrypted) + printf(", encrypted"); + if (base_filename) + printf(", backing_file=%s\n", + base_filename); + else + printf(", size=%lld kB\n", size / 1024); + ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted); + if (ret < 0) { + if (ret == -ENOTSUP) { + error("Formatting or formatting option not suppored for file format '%s'", fmt); + } else { + error("Error while formatting"); + } + } + return 0; +} + +static int img_commit(int argc, char **argv) +{ + int c, ret; + const char *filename, *fmt; + BlockDriver *drv; + BlockDriverState *bs; + + fmt = NULL; + for(;;) { + c = getopt(argc, argv, "f:h"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 'f': + fmt = optarg; + break; + } + } + optind++; + if (optind >= argc) + help(); + filename = argv[optind++]; + + bs = bdrv_new(""); + if (!bs) + error("Not enough memory"); + if (fmt) { + drv = bdrv_find_format(fmt); + if (!drv) + error("Unknown file format '%s'", fmt); + } else { + drv = NULL; + } + if (bdrv_open2(bs, filename, 0, drv) < 0) { + error("Could not open '%s'", filename); + } + ret = bdrv_commit(bs); + switch(ret) { + case 0: + printf("Image committed.\n"); + break; + case -ENOENT: + error("No disk inserted"); + break; + case -EACCES: + error("Image is read-only"); + break; + case -ENOTSUP: + error("Image is already committed"); + break; + default: + error("Error while committing image"); + break; + } + + bdrv_delete(bs); + return 0; +} + +static int is_not_zero(const uint8_t *sector, int len) +{ + int i; + len >>= 2; + for(i = 0;i < len; i++) { + if (((uint32_t *)sector)[i] != 0) + return 1; + } + return 0; +} + +static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum) +{ + int v, i; + + if (n <= 0) { + *pnum = 0; + return 0; + } + v = is_not_zero(buf, 512); + for(i = 1; i < n; i++) { + buf += 512; + if (v != is_not_zero(buf, 512)) + break; + } + *pnum = i; + return v; +} + +static BlockDriverState *bdrv_new_open(const char *filename, + const char *fmt) +{ + BlockDriverState *bs; + BlockDriver *drv; + char password[256]; + + bs = bdrv_new(""); + if (!bs) + error("Not enough memory"); + if (fmt) { + drv = bdrv_find_format(fmt); + if (!drv) + error("Unknown file format '%s'", fmt); + } else { + drv = NULL; + } + if (bdrv_open2(bs, filename, 0, drv) < 0) { + error("Could not open '%s'", filename); + } + if (bdrv_is_encrypted(bs)) { + printf("Disk image '%s' is encrypted.\n", filename); + if (read_password(password, sizeof(password)) < 0) + error("No password given"); + if (bdrv_set_key(bs, password) < 0) + error("invalid password"); + } + return bs; +} + +#define IO_BUF_SIZE 65536 + +static int img_convert(int argc, char **argv) +{ + int c, ret, n, n1, compress, cluster_size, cluster_sectors, encrypt; + const char *filename, *fmt, *out_fmt, *out_filename; + BlockDriver *drv; + BlockDriverState *bs, *out_bs; + int64_t total_sectors, nb_sectors, sector_num; + uint8_t buf[IO_BUF_SIZE]; + const uint8_t *buf1; + + fmt = NULL; + out_fmt = "raw"; + compress = 0; + encrypt = 0; + for(;;) { + c = getopt(argc, argv, "f:O:hce"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 'f': + fmt = optarg; + break; + case 'O': + out_fmt = optarg; + break; + case 'c': + compress = 1; + break; + case 'e': + encrypt = 1; + break; + } + } + optind++; + if (optind >= argc) + help(); + filename = argv[optind++]; + if (optind >= argc) + help(); + out_filename = argv[optind++]; + + bs = bdrv_new_open(filename, fmt); + + drv = bdrv_find_format(out_fmt); + if (!drv) + error("Unknown file format '%s'", fmt); + if (compress && drv != &bdrv_qcow) + error("Compression not supported for this file format"); + if (encrypt && drv != &bdrv_qcow) + error("Encryption not supported for this file format"); + if (compress && encrypt) + error("Compression and encryption not supported at the same time"); + bdrv_get_geometry(bs, &total_sectors); + ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt); + if (ret < 0) { + if (ret == -ENOTSUP) { + error("Formatting not suppored for file format '%s'", fmt); + } else { + error("Error while formatting '%s'", out_filename); + } + } + + out_bs = bdrv_new_open(out_filename, out_fmt); + + if (compress) { + cluster_size = qcow_get_cluster_size(out_bs); + if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) + error("invalid cluster size"); + cluster_sectors = cluster_size >> 9; + sector_num = 0; + for(;;) { + nb_sectors = total_sectors - sector_num; + if (nb_sectors <= 0) + break; + if (nb_sectors >= cluster_sectors) + n = cluster_sectors; + else + n = nb_sectors; + if (bdrv_read(bs, sector_num, buf, n) < 0) + error("error while reading"); + if (n < cluster_sectors) + memset(buf + n * 512, 0, cluster_size - n * 512); + if (is_not_zero(buf, cluster_size)) { + if (qcow_compress_cluster(out_bs, sector_num, buf) != 0) + error("error while compressing sector %lld", sector_num); + } + sector_num += n; + } + } else { + sector_num = 0; + for(;;) { + nb_sectors = total_sectors - sector_num; + if (nb_sectors <= 0) + break; + if (nb_sectors >= (IO_BUF_SIZE / 512)) + n = (IO_BUF_SIZE / 512); + else + n = nb_sectors; + if (bdrv_read(bs, sector_num, buf, n) < 0) + error("error while reading"); + /* NOTE: at the same time we convert, we do not write zero + sectors to have a chance to compress the image. Ideally, we + should add a specific call to have the info to go faster */ + buf1 = buf; + while (n > 0) { + if (is_allocated_sectors(buf1, n, &n1)) { + if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) + error("error while writing"); + } + sector_num += n1; + n -= n1; + buf1 += n1 * 512; + } + } + } + bdrv_delete(out_bs); + bdrv_delete(bs); + return 0; +} + +static int img_info(int argc, char **argv) +{ + int c; + const char *filename, *fmt; + BlockDriver *drv; + BlockDriverState *bs; + char fmt_name[128], size_buf[128], dsize_buf[128]; + int64_t total_sectors; + struct stat st; + + fmt = NULL; + for(;;) { + c = getopt(argc, argv, "f:h"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 'f': + fmt = optarg; + break; + } + } + optind++; + if (optind >= argc) + help(); + filename = argv[optind++]; + + bs = bdrv_new(""); + if (!bs) + error("Not enough memory"); + if (fmt) { + drv = bdrv_find_format(fmt); + if (!drv) + error("Unknown file format '%s'", fmt); + } else { + drv = NULL; + } + if (bdrv_open2(bs, filename, 0, drv) < 0) { + error("Could not open '%s'", filename); + } + bdrv_get_format(bs, fmt_name, sizeof(fmt_name)); + bdrv_get_geometry(bs, &total_sectors); + get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); + if (stat(filename, &st) < 0) + error("Could not stat '%s'", filename); + get_human_readable_size(dsize_buf, sizeof(dsize_buf), + (int64_t)st.st_blocks * 512); + printf("image: %s\n" + "file format: %s\n" + "virtual size: %s (%lld bytes)\n" + "disk size: %s\n", + filename, fmt_name, size_buf, + total_sectors * 512, + dsize_buf); + if (bdrv_is_encrypted(bs)) + printf("encrypted: yes\n"); + bdrv_delete(bs); + return 0; +} + +int main(int argc, char **argv) +{ + const char *cmd; + + bdrv_init(); + if (argc < 2) + help(); + cmd = argv[1]; + if (!strcmp(cmd, "create")) { + img_create(argc, argv); + } else if (!strcmp(cmd, "commit")) { + img_commit(argc, argv); + } else if (!strcmp(cmd, "convert")) { + img_convert(argc, argv); + } else if (!strcmp(cmd, "info")) { + img_info(argc, argv); + } else { + help(); + } + return 0; +} diff --git a/vl.h b/vl.h index a37981a50..04638a869 100644 --- a/vl.h +++ b/vl.h @@ -48,8 +48,21 @@ #define lseek64 _lseeki64 #endif +#ifdef QEMU_TOOL + +/* we use QEMU_TOOL in the command line tools which do not depend on + the target CPU type */ +#include "config-host.h" +#include +#include "osdep.h" +#include "bswap.h" + +#else + #include "cpu.h" +#endif /* !defined(QEMU_TOOL) */ + #ifndef glue #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) @@ -57,153 +70,6 @@ #define tostring(s) #s #endif -#if defined(WORDS_BIGENDIAN) -static inline uint32_t be32_to_cpu(uint32_t v) -{ - return v; -} - -static inline uint16_t be16_to_cpu(uint16_t v) -{ - return v; -} - -static inline uint32_t cpu_to_be32(uint32_t v) -{ - return v; -} - -static inline uint16_t cpu_to_be16(uint16_t v) -{ - return v; -} - -static inline uint32_t le32_to_cpu(uint32_t v) -{ - return bswap32(v); -} - -static inline uint16_t le16_to_cpu(uint16_t v) -{ - return bswap16(v); -} - -static inline uint32_t cpu_to_le32(uint32_t v) -{ - return bswap32(v); -} - -static inline uint16_t cpu_to_le16(uint16_t v) -{ - return bswap16(v); -} - -#else - -static inline uint32_t be32_to_cpu(uint32_t v) -{ - return bswap32(v); -} - -static inline uint16_t be16_to_cpu(uint16_t v) -{ - return bswap16(v); -} - -static inline uint32_t cpu_to_be32(uint32_t v) -{ - return bswap32(v); -} - -static inline uint16_t cpu_to_be16(uint16_t v) -{ - return bswap16(v); -} - -static inline uint32_t le32_to_cpu(uint32_t v) -{ - return v; -} - -static inline uint16_t le16_to_cpu(uint16_t v) -{ - return v; -} - -static inline uint32_t cpu_to_le32(uint32_t v) -{ - return v; -} - -static inline uint16_t cpu_to_le16(uint16_t v) -{ - return v; -} -#endif - -static inline void cpu_to_le16w(uint16_t *p, uint16_t v) -{ - *p = cpu_to_le16(v); -} - -static inline void cpu_to_le32w(uint32_t *p, uint32_t v) -{ - *p = cpu_to_le32(v); -} - -static inline uint16_t le16_to_cpup(const uint16_t *p) -{ - return le16_to_cpu(*p); -} - -static inline uint32_t le32_to_cpup(const uint32_t *p) -{ - return le32_to_cpu(*p); -} - -/* 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) - -#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); -} - -#endif - /* vl.c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); @@ -233,6 +99,8 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque); void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); +void main_loop_wait(int timeout); + extern int audio_enabled; extern int ram_size; extern int bios_size; @@ -301,6 +169,7 @@ void qemu_del_fd_read_handler(int fd); /* character device */ #define CHR_EVENT_BREAK 0 /* serial break char */ +#define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */ typedef void IOEventHandler(void *opaque, int event); @@ -310,11 +179,13 @@ typedef struct CharDriverState { IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque); IOEventHandler *chr_event; + IOEventHandler *chr_send_event; void *opaque; } CharDriverState; void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); +void qemu_chr_send_event(CharDriverState *s, int event); void qemu_chr_add_read_handler(CharDriverState *s, IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque); @@ -464,10 +335,23 @@ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); /* block.c */ typedef struct BlockDriverState BlockDriverState; - +typedef struct BlockDriver BlockDriver; + +extern BlockDriver bdrv_raw; +extern BlockDriver bdrv_cow; +extern BlockDriver bdrv_qcow; +extern BlockDriver bdrv_vmdk; + +void bdrv_init(void); +BlockDriver *bdrv_find_format(const char *format_name); +int bdrv_create(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, int flags); BlockDriverState *bdrv_new(const char *device_name); void bdrv_delete(BlockDriverState *bs); int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot); +int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, + BlockDriver *drv); void bdrv_close(BlockDriverState *bs); int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); @@ -494,11 +378,21 @@ int bdrv_is_locked(BlockDriverState *bs); void bdrv_set_locked(BlockDriverState *bs, int locked); void bdrv_set_change_cb(BlockDriverState *bs, void (*change_cb)(void *opaque), void *opaque); - +void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); void bdrv_info(void); BlockDriverState *bdrv_find(const char *name); void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); +int bdrv_is_encrypted(BlockDriverState *bs); +int bdrv_set_key(BlockDriverState *bs, const char *key); +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), + void *opaque); +const char *bdrv_get_device_name(BlockDriverState *bs); +int qcow_get_cluster_size(BlockDriverState *bs); +int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf); + +#ifndef QEMU_TOOL /* ISA bus */ extern target_phys_addr_t isa_mem_base; @@ -823,11 +717,28 @@ void adb_mouse_init(ADBBusState *bus); extern ADBBusState adb_bus; int cuda_init(openpic_t *openpic, int irq); +#endif /* defined(QEMU_TOOL) */ + /* monitor.c */ void monitor_init(CharDriverState *hd, int show_banner); +void term_puts(const char *str); +void term_vprintf(const char *fmt, va_list ap); void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); void term_flush(void); void term_print_help(void); +void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size); + +/* readline.c */ +typedef void ReadLineFunc(void *opaque, const char *str); + +extern int completion_index; +void add_completion(const char *str); +void readline_handle_byte(int ch); +void readline_find_completion(const char *cmdline); +const char *readline_get_history(unsigned int index); +void readline_start(const char *prompt, int is_password, + ReadLineFunc *readline_func, void *opaque); /* gdbstub.c */ -- cgit v1.2.3 From a3fb0cf9072c4aa89776526592b359b7caea1bb9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 22:00:34 +0000 Subject: removed unneeded tools git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1038 c046a42c-6fe2-441c-8c8c-71466251a162 --- cow.h | 13 --- qemu-mkcow.c | 146 --------------------------------- vmdk.h | 72 ----------------- vmdk2raw.c | 261 ----------------------------------------------------------- 4 files changed, 492 deletions(-) delete mode 100644 cow.h delete mode 100644 qemu-mkcow.c delete mode 100644 vmdk.h delete mode 100644 vmdk2raw.c diff --git a/cow.h b/cow.h deleted file mode 100644 index 5b5f497ed..000000000 --- a/cow.h +++ /dev/null @@ -1,13 +0,0 @@ -/* 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; -}; - diff --git a/qemu-mkcow.c b/qemu-mkcow.c deleted file mode 100644 index ee41ec8a1..000000000 --- a/qemu-mkcow.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * create a COW disk image - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cow.h" - -#include "bswap.h" - -int cow_create(int cow_fd, const char *image_filename, - int64_t image_sectors) -{ - struct cow_header_v2 cow_header; - int fd; - struct stat st; - - memset(&cow_header, 0, sizeof(cow_header)); - cow_header.magic = htonl(COW_MAGIC); - cow_header.version = htonl(COW_VERSION); - if (image_filename) { - fd = open(image_filename, O_RDONLY); - if (fd < 0) { - perror(image_filename); - exit(1); - } - image_sectors = lseek64(fd, 0, SEEK_END); - if (fstat(fd, &st) != 0) { - close(fd); - return -1; - } - close(fd); - image_sectors /= 512; - cow_header.mtime = htonl(st.st_mtime); - realpath(image_filename, cow_header.backing_file); - } - cow_header.sectorsize = htonl(512); - cow_header.size = image_sectors * 512; -#ifndef WORDS_BIGENDIAN - cow_header.size = bswap64(cow_header.size); -#endif - write(cow_fd, &cow_header, sizeof(cow_header)); - /* resize to include at least all the bitmap */ - ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); - lseek(cow_fd, 0, SEEK_SET); - return 0; -} - -void help(void) -{ - printf("qemu-mkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" - "usage: qemu-mkcow [-h] [-f disk_image] cow_image [cow_size]\n" - "Create a Copy On Write disk image from an optional raw disk image\n" - "\n" - "-f disk_image set the raw disk image name\n" - "cow_image the created cow_image\n" - "cow_size the create cow_image size in MB if no raw disk image is used\n" - "\n" - "Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n" - ); - exit(1); -} - -int main(int argc, char **argv) -{ - const char *image_filename, *cow_filename; - int cow_fd, c, nb_args, simple_image; - int64_t image_size; - - image_filename = NULL; - image_size = 0; - simple_image = 0; - for(;;) { - c = getopt(argc, argv, "hf:s"); - if (c == -1) - break; - switch(c) { - case 'h': - help(); - break; - case 'f': - image_filename = optarg; - break; - case 's': - simple_image = 1; - break; - } - } - if (!image_filename) - nb_args = 2; - else - nb_args = 1; - if (optind + nb_args != argc) - help(); - - cow_filename = argv[optind]; - if (nb_args == 2) { - image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024; - } - - cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); - if (!cow_fd < 0) - return -1; - if (simple_image) { - ftruncate64(cow_fd, image_size * 512); - } else { - if (cow_create(cow_fd, image_filename, image_size) < 0) { - fprintf(stderr, "%s: error while formating\n", cow_filename); - exit(1); - } - } - close(cow_fd); - return 0; -} diff --git a/vmdk.h b/vmdk.h deleted file mode 100644 index dbb352d49..000000000 --- a/vmdk.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - Copyright (C) Matthew Chapman 2003 - - 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. -*/ - -#define SECTOR_BITS 9 -#define SECTOR_SIZE (1 << SECTOR_BITS) -#define SECTOR_MASK (SECTOR_SIZE - 1) - -#define L1_BITS (SECTOR_BITS - 3) -#define L1_SIZE (1 << L1_BITS) -#define L1_MASK (L1_SIZE - 1) - -#define L2_BITS SECTOR_BITS -#define L2_SIZE (1 << L2_BITS) -#define L2_MASK (L2_SIZE - 1) - -#define MIN(x,y) (((x) < (y)) ? (x) : (y)) - -struct cowdisk_header -{ - 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; -}; - -struct cowdisk_header2 -{ - uint32_t parent_ts; - uint32_t timestamp; -}; - -/* based on vdk 3.1 10-11-2003 by Ken Kato */ - -struct vmdisk_header -{ - 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]; -}; diff --git a/vmdk2raw.c b/vmdk2raw.c deleted file mode 100644 index b2454c2d5..000000000 --- a/vmdk2raw.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - vmdk2raw: convert vmware images to raw disk images - Copyright (C) Net Integration Technologies 2004 - Copyright (C) Matthew Chapman 2003 - - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "vmdk.h" -#include "config-host.h" - -static struct cowdisk_header header; -static struct vmdisk_header header4; -static off64_t disk_limit; -static unsigned int granule_size; -static uint32_t *l1dir; - -static unsigned int cached_l2dir; -static uint32_t l2dir[L2_SIZE]; - -static struct vmdk_prm { - uint32_t grain_table_size; - uint32_t sectors_per_grain; - uint32_t sectors_per_table; - uint32_t directory_size; -} vdsk; - -static size_t read_physical(int fd, off64_t offset, size_t length, void *buffer) -{ - size_t n; - - if (lseek64(fd, offset, SEEK_SET) == -1) { - printf(" error trying to seek lseek to %lld", offset); - return -1; - } - - n = read(fd, buffer, length); - - if (n == -1) { - printf("read from disk %lld", offset); - return -1; - } - - return n; -} - -static int read_l1dir(int fd, size_t offset, int num) -{ - l1dir = malloc(sizeof(*l1dir) * num); - if (!l1dir) - return -1; - return read_physical(fd, offset << SECTOR_BITS, sizeof(*l1dir) * num, (char *)l1dir) != (sizeof(*l1dir) * num); -} - -static int read_l2dir(int fd, size_t offset, int num) -{ - return read_physical(fd, offset << SECTOR_BITS, sizeof(l2dir[0]) * num, (char *)l2dir) != sizeof(l2dir); -} - -static size_t copy_virtual(struct vmdk_prm *dsk, int in_fd, int out_fd, off64_t offset, void *buffer, size_t length) -{ - - unsigned int granule_offset; - unsigned int grain_index; - unsigned int sector_map_idx; - - granule_offset = offset % granule_size; - length = MIN(length, granule_size - granule_offset); - length = MIN(length, disk_limit - offset); - - sector_map_idx = (offset >> SECTOR_BITS) / dsk->sectors_per_table; - - if (sector_map_idx >= dsk->directory_size) { - fprintf(stderr, "cannot locate grain table for %d in %d\n", sector_map_idx, dsk->directory_size); - return -1; - } - - if (l1dir[sector_map_idx] == 0) - goto zero_fill; - - if (sector_map_idx != cached_l2dir) { - if (read_l2dir(in_fd, l1dir[sector_map_idx], dsk->grain_table_size)) { - fprintf(stderr, "read failed\n"); - return -1; - } - cached_l2dir = sector_map_idx; - } - - grain_index = ((offset >> SECTOR_BITS) % dsk->sectors_per_table) / dsk->sectors_per_grain; - - if (grain_index >= dsk->grain_table_size) { - fprintf(stderr, "grain to large"); - return -1; - } - - if (l2dir[grain_index] == 0) - goto zero_fill; - - if (read_physical(in_fd, (l2dir[grain_index] << SECTOR_BITS) + granule_offset, length, buffer) != length) { - fprintf(stderr, "read error 2\n"); - return -1; - } - - write(out_fd, buffer, length); - return length; - -zero_fill: - /* the last chunk of the file can not be sparse - * or the file will be truncated */ - if (offset + length >= disk_limit) { - if (lseek64(out_fd, length-1, SEEK_CUR) == (off_t)-1) - perror("lseek"); - /* write the last NULL byte instead of seeking */ - const char nil = 0; - write(out_fd, &nil, 1); - } else { - if (lseek64(out_fd, length, SEEK_CUR) == (off_t)-1) - perror("lseek"); - } - return length; -} - -static int open_vmdk4(int fd) -{ - if (read(fd, &header4, sizeof(header4)) != sizeof(header4)) { - perror("read from disk"); - return -1; - } - - granule_size = header4.granularity << SECTOR_BITS; - disk_limit = header4.capacity << SECTOR_BITS; - - cached_l2dir = -1; - vdsk.grain_table_size = header4.num_gtes_per_gte; - vdsk.sectors_per_grain = header4.granularity; - vdsk.sectors_per_table = vdsk.grain_table_size * vdsk.sectors_per_grain; - vdsk.directory_size = (header4.capacity + vdsk.sectors_per_table - 1) / vdsk.sectors_per_table + 1; - - if (read_l1dir(fd, header4.rgd_offset, vdsk.directory_size)) - return -1; - - return 0; - -} - -static int open_vmdk3(int fd) -{ - if (read(fd, &header, sizeof(header)) != sizeof(header)) { - perror("read from disk\n"); - return -1; - } - granule_size = header.granularity << SECTOR_BITS; - vdsk.sectors_per_grain = header.granularity; - vdsk.grain_table_size = L2_SIZE; - vdsk.sectors_per_table = vdsk.grain_table_size * vdsk.sectors_per_grain; - vdsk.directory_size = L1_SIZE; - if (read_l1dir(fd, header.l1dir_offset, L1_SIZE)) - return -1; - - disk_limit = header.disk_sectors << SECTOR_BITS; - - return fd; -} - -static int open_vmdk(const char *filename) -{ - int fd = open(filename, O_RDONLY | O_LARGEFILE); - if (fd == -1) { - perror(filename); - return -1; - } - - char magic[4]; - if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) { - perror("read from disk"); - return -1; - } - - if (!memcmp(magic, "KDMV", sizeof(magic))) { - open_vmdk4(fd); - } else if (!memcmp(magic, "COWD", sizeof(magic))) { - open_vmdk3(fd); - } else { - fprintf(stderr, "%s is not a VMware virtual disk image\n", filename); - return -1; - } - - cached_l2dir = -1; - return fd; -} - -static void help(void) -{ - printf("vmdk2raw\n" - "usage: vmdk2raw vmware_image output_image\n" - "\n" - "vmware_image a vmware cow image\n" - "output_image the created disk image\n" - ); - exit(1); -} - -#define BUF_SIZE 0x10000 -static void copy_disk(in_fd, out_fd) -{ - char buf[BUF_SIZE]; - off64_t i = 0; - int ret; - while (i < disk_limit) { - ret = copy_virtual(&vdsk, in_fd, out_fd, i, buf, sizeof(buf)); - if (ret < 0) { - fprintf(stderr, "copying failed\n"); - exit(-1); - } - i += ret; - } -} - -int main(int argc, char **argv) -{ - int out_fd, in_fd; - - if (argc < 3) - help(); - - in_fd = open_vmdk(argv[1]); - if (in_fd < 0) { - return -1; - } - - out_fd = open(argv[2], O_WRONLY | O_LARGEFILE | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (out_fd < 0) { - perror(argv[2]); - return -1; - } - - copy_disk(in_fd, out_fd); - close(out_fd); - return 0; -} -- cgit v1.2.3 From 11c0315f9bd7d5e0e368f058c4ea58fb6c798728 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Aug 2004 22:05:00 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1039 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.cvsignore b/.cvsignore index 39a56bcf3..9fad653e3 100644 --- a/.cvsignore +++ b/.cvsignore @@ -7,9 +7,8 @@ i386-user ppc-softmmu ppc-user qemu-doc.html -qemu-mkcow qemu-tech.html qemu.1 qemu.pod sparc-user -vmdk2raw +qemu-img -- cgit v1.2.3 From d5249393efe472d50eb027e286566a57ba868bf2 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Aug 2004 21:14:23 +0000 Subject: 64 bit file I/O by default git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1040 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- Makefile.target | 2 +- block-cow.c | 4 ++-- block-qcow.c | 26 +++++++++++++------------- block-vmdk.c | 2 +- block.c | 18 +++++++++++++----- configure | 4 ---- 7 files changed, 32 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index b9d8e690c..17ee44980 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ include config-host.mak -CFLAGS=-Wall -O2 -g -fno-strict-aliasing +CFLAGS=-Wall -O2 -g -fno-strict-aliasing ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic endif @@ -9,7 +9,7 @@ CFLAGS+=-fpack-struct endif LDFLAGS=-g LIBS= -DEFINES+=-D_GNU_SOURCE +DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE TOOLS=qemu-img ifdef CONFIG_STATIC LDFLAGS+=-static diff --git a/Makefile.target b/Makefile.target index 9c9cfcfea..0e7006511 100644 --- a/Makefile.target +++ b/Makefile.target @@ -159,7 +159,7 @@ endif ######################################################### -DEFINES+=-D_GNU_SOURCE +DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS+=-lm ifndef CONFIG_USER_ONLY LIBS+=-lz diff --git a/block-cow.c b/block-cow.c index ab62c2a86..affeefa3f 100644 --- a/block-cow.c +++ b/block-cow.c @@ -173,7 +173,7 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num, while (nb_sectors > 0) { if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) { - lseek64(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); + 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; @@ -193,7 +193,7 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num, BDRVCowState *s = bs->opaque; int ret, i; - lseek64(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); + 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; diff --git a/block-qcow.c b/block-qcow.c index ed6359f74..953f42c7b 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -137,7 +137,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename) s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); if (!s->l1_table) goto fail; - lseek64(fd, s->l1_table_offset, SEEK_SET); + lseek(fd, s->l1_table_offset, SEEK_SET); if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) != s->l1_size * sizeof(uint64_t)) goto fail; @@ -161,7 +161,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename) len = header.backing_file_size; if (len > 1023) len = 1023; - lseek64(fd, header.backing_file_offset, SEEK_SET); + lseek(fd, header.backing_file_offset, SEEK_SET); if (read(fd, bs->backing_file, len) != len) goto fail; bs->backing_file[len] = '\0'; @@ -275,13 +275,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, if (!allocate) return 0; /* allocate a new l2 entry */ - l2_offset = lseek64(s->fd, 0, SEEK_END); + l2_offset = lseek(s->fd, 0, SEEK_END); /* round to cluster size */ l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); /* update the L1 entry */ s->l1_table[l1_index] = l2_offset; tmp = cpu_to_be64(l2_offset); - lseek64(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET); + lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET); if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp)) return 0; new_l2_table = 1; @@ -336,16 +336,16 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, overwritten */ if (decompress_cluster(s, cluster_offset) < 0) return 0; - cluster_offset = lseek64(s->fd, 0, SEEK_END); + cluster_offset = lseek(s->fd, 0, SEEK_END); cluster_offset = (cluster_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); /* write the cluster content */ - lseek64(s->fd, cluster_offset, SEEK_SET); + lseek(s->fd, cluster_offset, SEEK_SET); if (write(s->fd, s->cluster_cache, s->cluster_size) != s->cluster_size) return -1; } else { - cluster_offset = lseek64(s->fd, 0, SEEK_END); + cluster_offset = lseek(s->fd, 0, SEEK_END); if (allocate == 1) { /* round to cluster size */ cluster_offset = (cluster_offset + s->cluster_size - 1) & @@ -364,7 +364,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, s->cluster_data, s->cluster_data + 512, 1, 1, &s->aes_encrypt_key); - lseek64(s->fd, cluster_offset + i * 512, SEEK_SET); + lseek(s->fd, cluster_offset + i * 512, SEEK_SET); if (write(s->fd, s->cluster_data, 512) != 512) return -1; } @@ -378,7 +378,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* update L2 table */ tmp = cpu_to_be64(cluster_offset); l2_table[l2_index] = tmp; - lseek64(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET); + lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET); if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp)) return 0; } @@ -437,7 +437,7 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) if (s->cluster_cache_offset != coffset) { csize = cluster_offset >> (63 - s->cluster_bits); csize &= (s->cluster_size - 1); - lseek64(s->fd, coffset, SEEK_SET); + lseek(s->fd, coffset, SEEK_SET); ret = read(s->fd, s->cluster_data, csize); if (ret != csize) return -1; @@ -470,7 +470,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, return -1; memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); } else { - lseek64(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); + lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); ret = read(s->fd, buf, n * 512); if (ret != n * 512) return -1; @@ -503,7 +503,7 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, index_in_cluster + n); if (!cluster_offset) return -1; - lseek64(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); + lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); if (s->crypt_method) { encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1, &s->aes_encrypt_key); @@ -650,7 +650,7 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, out_len, 0, 0); cluster_offset &= s->cluster_offset_mask; - lseek64(s->fd, cluster_offset, SEEK_SET); + lseek(s->fd, cluster_offset, SEEK_SET); if (write(s->fd, out_buf, out_len) != out_len) { qemu_free(out_buf); return -1; diff --git a/block-vmdk.c b/block-vmdk.c index d1414e430..36653fb2f 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -239,7 +239,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, if (!cluster_offset) { memset(buf, 0, 512 * n); } else { - lseek64(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); + lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); ret = read(s->fd, buf, n * 512); if (ret != n * 512) return -1; diff --git a/block.c b/block.c index 43b018814..8dea3c932 100644 --- a/block.c +++ b/block.c @@ -71,14 +71,22 @@ int bdrv_create(BlockDriver *drv, return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); } -/* XXX: race condition possible */ +#ifdef _WIN32 +static void get_tmp_filename(char *filename, int size) +{ + /* XXX: find a better function */ + tmpnam(filename); +} +#else static void get_tmp_filename(char *filename, int size) { int fd; + /* XXX: race condition possible */ pstrcpy(filename, size, "/tmp/vl.XXXXXX"); fd = mkstemp(filename); close(fd); } +#endif static BlockDriver *find_image_format(const char *filename) { @@ -514,7 +522,7 @@ static int raw_open(BlockDriverState *bs, const char *filename) return -1; bs->read_only = 1; } - size = lseek64(fd, 0, SEEK_END); + size = lseek(fd, 0, SEEK_END); bs->total_sectors = size / 512; s->fd = fd; return 0; @@ -526,7 +534,7 @@ static int raw_read(BlockDriverState *bs, int64_t sector_num, BDRVRawState *s = bs->opaque; int ret; - lseek64(s->fd, sector_num * 512, SEEK_SET); + lseek(s->fd, sector_num * 512, SEEK_SET); ret = read(s->fd, buf, nb_sectors * 512); if (ret != nb_sectors * 512) return -1; @@ -539,7 +547,7 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num, BDRVRawState *s = bs->opaque; int ret; - lseek64(s->fd, sector_num * 512, SEEK_SET); + lseek(s->fd, sector_num * 512, SEEK_SET); ret = write(s->fd, buf, nb_sectors * 512); if (ret != nb_sectors * 512) return -1; @@ -564,7 +572,7 @@ static int raw_create(const char *filename, int64_t total_size, 0644); if (fd < 0) return -EIO; - ftruncate64(fd, total_size * 512); + ftruncate(fd, total_size * 512); close(fd); return 0; } diff --git a/configure b/configure index 9cf6a2ec5..54f1a9fbd 100755 --- a/configure +++ b/configure @@ -429,10 +429,6 @@ echo "TARGET_DIRS=$target_list" >> $config_mak # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "#define O_LARGEFILE 0" >> $config_h - echo "#define lseek64 lseek" >> $config_h - echo "#define mkstemp64 mkstemp" >> $config_h - echo "#define ftruncate64 ftruncate" >> $config_h - echo "#define off64_t off_t" >> $config_h echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h echo "#define _BSD 1" >> $config_h fi -- cgit v1.2.3 From 57d1a2b62c3a89533bf50297a606ed028068e18e Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Aug 2004 21:15:11 +0000 Subject: win32 port git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1041 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 34 ++++++++++++++++++++++++++-------- vl.h | 11 ++++++++++- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 480dff95f..cdb0ea124 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -113,7 +113,7 @@ void __attribute__((noreturn)) error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(stderr, "qemuimg: "); + fprintf(stderr, "qemu-img: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); exit(1); @@ -127,8 +127,8 @@ static void format_print(void *opaque, const char *name) void help(void) { - printf("qemuimg version " QEMU_VERSION ", Copyright (c) 2004 Fabrice Bellard\n" - "usage: qemuimg command [command options]\n" + printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004 Fabrice Bellard\n" + "usage: qemu-img command [command options]\n" "QEMU disk image utility\n" "\n" "Command syntax:\n" @@ -592,6 +592,24 @@ static int img_convert(int argc, char **argv) return 0; } +#ifdef _WIN32 +static int64_t get_allocated_file_size(const char *filename) +{ + struct _stati64 st; + if (_stati64(filename, &st) < 0) + return -1; + return st.st_size; +} +#else +static int64_t get_allocated_file_size(const char *filename) +{ + struct stat st; + if (stat(filename, &st) < 0) + return -1; + return (int64_t)st.st_blocks * 512; +} +#endif + static int img_info(int argc, char **argv) { int c; @@ -599,8 +617,7 @@ static int img_info(int argc, char **argv) BlockDriver *drv; BlockDriverState *bs; char fmt_name[128], size_buf[128], dsize_buf[128]; - int64_t total_sectors; - struct stat st; + int64_t total_sectors, allocated_size; fmt = NULL; for(;;) { @@ -637,10 +654,11 @@ static int img_info(int argc, char **argv) bdrv_get_format(bs, fmt_name, sizeof(fmt_name)); bdrv_get_geometry(bs, &total_sectors); get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); - if (stat(filename, &st) < 0) - error("Could not stat '%s'", filename); + allocated_size = get_allocated_file_size(filename); + if (allocated_size < 0) + error("Could not get file size '%s'", filename); get_human_readable_size(dsize_buf, sizeof(dsize_buf), - (int64_t)st.st_blocks * 512); + allocated_size); printf("image: %s\n" "file format: %s\n" "virtual size: %s (%lld bytes)\n" diff --git a/vl.h b/vl.h index 04638a869..485ccc020 100644 --- a/vl.h +++ b/vl.h @@ -45,7 +45,16 @@ #endif #ifdef _WIN32 -#define lseek64 _lseeki64 +#define lseek _lseeki64 +#define ENOTSUP 4096 +/* XXX: find 64 bit version */ +#define ftruncate chsize + +static inline char *realpath(const char *path, char *resolved_path) +{ + _fullpath(resolved_path, path, _MAX_PATH); + return resolved_path; +} #endif #ifdef QEMU_TOOL -- cgit v1.2.3 From 0f6e3eb211fafeadd598e960a35bfa3a3b8bfc50 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Aug 2004 21:37:41 +0000 Subject: enabled asm memory helpers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1042 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index 2438499ec..9ea00a757 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -18,13 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* XXX: must use this define because the soft mmu macros have huge - register constraints so they cannot be used in any C code. gcc 3.3 - does not seem to be able to handle some constraints in rol - operations, so we disable it. */ -#if !(__GNUC__ == 3 && __GNUC_MINOR__ == 3) #define ASM_SOFTMMU -#endif #include "exec.h" /* n must be a constant to be efficient */ -- cgit v1.2.3 From 3611a29c090fc74faee3ce05b8ede7287f609e44 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Aug 2004 21:42:45 +0000 Subject: -fno-gcse option for opcodes to use asm macros with gcc >= 3.3 on i386 (Piotr Krysik) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1043 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 0e7006511..6d5849071 100644 --- a/Makefile.target +++ b/Makefile.target @@ -73,7 +73,7 @@ ifeq ($(ARCH),i386) CFLAGS+=-fomit-frame-pointer OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2 ifeq ($(HAVE_GCC3_OPTIONS),yes) -OP_CFLAGS+= -falign-functions=0 +OP_CFLAGS+= -falign-functions=0 -fno-gcse else OP_CFLAGS+= -malign-functions=0 endif -- cgit v1.2.3 From d2bfb39ad220a6431e366bdff72353b09f60e3db Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 3 Aug 2004 22:09:30 +0000 Subject: use the kernel sigaction syscall to avoid relying on glibc one git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1044 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 16 ++++++++++++++++ osdep.h | 23 +++++++++++++++++++++++ vl.c | 11 ----------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/osdep.c b/osdep.c index 76bfa2663..087a5c218 100644 --- a/osdep.c +++ b/osdep.c @@ -143,6 +143,22 @@ void *shmat(int shmid, const void *shmaddr, int shmflg) return ptr; } +/****************************************************************/ +/* sigaction bypassing the threads */ + +static int kernel_sigaction(int signum, const struct qemu_sigaction *act, + struct qemu_sigaction *oldact, + int sigsetsize) +{ + QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize); +} + +int qemu_sigaction(int signum, const struct qemu_sigaction *act, + struct qemu_sigaction *oldact) +{ + return kernel_sigaction(signum, act, oldact, 8); +} + /****************************************************************/ /* memory allocation */ diff --git a/osdep.h b/osdep.h index dfe80bcf9..f1d18202b 100644 --- a/osdep.h +++ b/osdep.h @@ -22,6 +22,29 @@ void *get_mmap_addr(unsigned long size); extern void __longjmp(jmp_buf env, int val); #define longjmp __longjmp +#include + +/* NOTE: it works only because the glibc sigset_t is >= kernel sigset_t */ +struct qemu_sigaction { + union { + void (*_sa_handler)(int); + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +int qemu_sigaction(int signum, const struct qemu_sigaction *act, + struct qemu_sigaction *oldact); + +#undef sigaction +#undef sa_handler +#undef sa_sigaction +#define sigaction qemu_sigaction +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + #endif #endif diff --git a/vl.c b/vl.c index 484d4becc..646d1ff94 100644 --- a/vl.c +++ b/vl.c @@ -68,17 +68,6 @@ #ifdef __APPLE__ #include #endif -#if defined(__linux__) -/* SDL use the pthreads and they modify sigaction. We don't - want that. */ -#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) -extern void __libc_sigaction(); -#define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact) -#else -extern void __sigaction(); -#define sigaction(sig, act, oact) __sigaction(sig, act, oact) -#endif -#endif /* __linux__ */ #endif /* CONFIG_SDL */ #include "disas.h" -- cgit v1.2.3 From e82d8ade13e313a457ea2859470e1da56cc8bca9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Aug 2004 14:47:30 +0000 Subject: fixed bound memory reference git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1045 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 73a701fcf..29f0dfa1f 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1364,7 +1364,7 @@ void test_exceptions(void) /* bound exception */ tab[0] = 1; tab[1] = 10; - asm volatile ("bound %0, %1" : : "r" (11), "m" (tab)); + asm volatile ("bound %0, %1" : : "r" (11), "m" (tab[0])); } printf("segment exceptions:\n"); -- cgit v1.2.3 From cabf23c380ed0e46172f9503017bb636554276a9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 15 Aug 2004 14:51:07 +0000 Subject: bound instruction fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1046 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 13840bbf9..111b88914 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3844,7 +3844,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; - gen_op_mov_reg_T0[ot][reg](); + gen_op_mov_TN_reg[ot][0][reg](); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (ot == OT_WORD) gen_op_boundw(pc_start - s->cs_base); -- cgit v1.2.3 From 05d5818c5c9a5f90d7bc069ed1e8c9d8d77381d0 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Aug 2004 21:12:04 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1047 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 6 ++++++ qemu-doc.texi | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 5658c0bd0..9d18ec65f 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,12 @@ 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 version 0.6.0: diff --git a/qemu-doc.texi b/qemu-doc.texi index d3c0a1625..ba3ade861 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -120,8 +120,8 @@ Floppy disk @item NE2000 PCI network adapters @item -Serial port -@item +Serial ports +@item Soundblaster 16 card @end itemize @@ -270,6 +270,9 @@ void device The default device is @code{vc} in graphical mode and @code{stdio} in non graphical mode. +This option can be used several times to simulate up to 4 serials +ports. + @item -monitor dev Redirect the monitor to host device @var{dev} (same devices as the serial port). -- cgit v1.2.3 From 8d11df9e5aa58497e27e3481cca119809c76afc6 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Aug 2004 21:13:40 +0000 Subject: multiple serial port support - terminal init fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1048 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 11 ++++- hw/ppc_chrp.c | 2 +- hw/ppc_prep.c | 2 +- vl.c | 137 ++++++++++++++++++++++++++++++---------------------------- vl.h | 8 +++- 5 files changed, 88 insertions(+), 72 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 0fd7b87b2..f59ea2397 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -314,9 +314,12 @@ static const int ide_irq[2] = { 14, 15 }; #define NE2000_NB_MAX 6 -static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; +static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; +static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; +static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; + /* PC hardware initialisation */ void pc_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -471,7 +474,11 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, pic_init(); pit = pit_init(0x40, 0); - serial_init(0x3f8, 4, serial_hd); + for(i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + serial_init(serial_io[i], serial_irq[i], serial_hds[i]); + } + } if (pci_enabled) { for(i = 0; i < nb_nics; i++) { diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index f532fe101..cf3a5f32f 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -200,7 +200,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pic_init(); /* XXX: use Mac Serial port */ - serial_init(0x3f8, 4, serial_hd); + serial_init(0x3f8, 4, serial_hds[0]); for(i = 0; i < nb_nics; i++) { pci_ne2000_init(pci_bus, &nd_table[i]); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index eeb5a3609..c93b72fae 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -492,7 +492,7 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, pic_init(); // pit = pit_init(0x40, 0); - serial_init(0x3f8, 4, serial_hd); + serial_init(0x3f8, 4, serial_hds[0]); nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; diff --git a/vl.c b/vl.c index 646d1ff94..4d274478e 100644 --- a/vl.c +++ b/vl.c @@ -128,6 +128,7 @@ int graphic_width = 800; int graphic_height = 600; int graphic_depth = 15; TextConsole *vga_console; +CharDriverState *serial_hds[MAX_SERIAL_PORTS]; /***********************************************************/ /* x86 ISA bus support */ @@ -1166,6 +1167,43 @@ static void stdio_read(void *opaque, const uint8_t *buf, int size) stdio_received_byte(buf[i]); } +/* init terminal so that we can grab keys */ +static struct termios oldtty; +static int old_fd0_flags; + +static void term_exit(void) +{ + tcsetattr (0, TCSANOW, &oldtty); + fcntl(0, F_SETFL, old_fd0_flags); +} + +static void term_init(void) +{ + struct termios tty; + + tcgetattr (0, &tty); + oldtty = tty; + old_fd0_flags = fcntl(0, F_GETFL); + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + /* if graphical mode, we allow Ctrl-C handling */ + if (nographic) + tty.c_lflag &= ~ISIG; + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + tcsetattr (0, TCSANOW, &tty); + + atexit(term_exit); + + fcntl(0, F_SETFL, O_NONBLOCK); +} + CharDriverState *qemu_chr_open_stdio(void) { CharDriverState *chr; @@ -1183,6 +1221,10 @@ CharDriverState *qemu_chr_open_stdio(void) chr = qemu_chr_open_fd(0, 1); } stdio_clients[stdio_nb_clients++] = chr; + if (stdio_nb_clients == 1) { + /* set the terminal in raw mode */ + term_init(); + } return chr; } @@ -1449,57 +1491,6 @@ static int net_fd_init(NetDriverState *nd, int fd) /***********************************************************/ /* dumb display */ -#ifdef _WIN32 - -static void term_exit(void) -{ -} - -static void term_init(void) -{ -} - -#else - -/* init terminal so that we can grab keys */ -static struct termios oldtty; -static int old_fd0_flags; - -static void term_exit(void) -{ - tcsetattr (0, TCSANOW, &oldtty); - fcntl(0, F_SETFL, old_fd0_flags); -} - -static void term_init(void) -{ - struct termios tty; - - tcgetattr (0, &tty); - oldtty = tty; - old_fd0_flags = fcntl(0, F_GETFL); - - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - /* if graphical mode, we allow Ctrl-C handling */ - if (nographic) - tty.c_lflag &= ~ISIG; - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; - - tcsetattr (0, TCSANOW, &tty); - - atexit(term_exit); - - fcntl(0, F_SETFL, O_NONBLOCK); -} - -#endif - static void dumb_update(DisplayState *ds, int x, int y, int w, int h) { } @@ -1531,7 +1522,8 @@ static void host_segv_handler(int host_signum, siginfo_t *info, { if (cpu_signal_handler(host_signum, info, puc)) return; - term_exit(); + if (stdio_nb_clients > 0) + term_exit(); abort(); } #endif @@ -2568,8 +2560,9 @@ int main(int argc, char **argv) const char *r, *optarg; CharDriverState *monitor_hd; char monitor_device[128]; - char serial_device[128]; - + char serial_devices[MAX_SERIAL_PORTS][128]; + int serial_device_index; + #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); @@ -2594,8 +2587,12 @@ int main(int argc, char **argv) has_cdrom = 1; cyls = heads = secs = 0; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); - pstrcpy(serial_device, sizeof(serial_device), "vc"); + pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "vc"); + for(i = 1; i < MAX_SERIAL_PORTS; i++) + serial_devices[i][0] = '\0'; + serial_device_index = 0; + nb_tun_fds = 0; net_if_type = -1; nb_nics = 1; @@ -2674,7 +2671,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_nographic: pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); - pstrcpy(serial_device, sizeof(serial_device), "stdio"); + pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); nographic = 1; break; case QEMU_OPTION_kernel: @@ -2865,7 +2862,13 @@ int main(int argc, char **argv) pstrcpy(monitor_device, sizeof(monitor_device), optarg); break; case QEMU_OPTION_serial: - pstrcpy(serial_device, sizeof(serial_device), optarg); + if (serial_device_index >= MAX_SERIAL_PORTS) { + fprintf(stderr, "qemu: too many serial ports\n"); + exit(1); + } + pstrcpy(serial_devices[serial_device_index], + sizeof(serial_devices[0]), optarg); + serial_device_index++; break; } } @@ -3066,14 +3069,18 @@ int main(int argc, char **argv) } monitor_init(monitor_hd, !nographic); - serial_hd = qemu_chr_open(serial_device); - if (!serial_hd) { - fprintf(stderr, "qemu: could not open serial device '%s'\n", serial_device); - exit(1); + for(i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_devices[i][0] != '\0') { + serial_hds[i] = qemu_chr_open(serial_devices[i]); + if (!serial_hds[i]) { + fprintf(stderr, "qemu: could not open serial device '%s'\n", + serial_devices[i]); + exit(1); + } + if (!strcmp(serial_devices[i], "vc")) + qemu_chr_printf(serial_hds[i], "serial%d console\n", i); + } } - if (!strcmp(serial_device, "vc")) - qemu_chr_printf(serial_hd, "serial0 console\n"); - /* setup cpu signal handlers for MMU / self modifying code handling */ #if !defined(CONFIG_SOFTMMU) @@ -3142,11 +3149,9 @@ int main(int argc, char **argv) } else { printf("Waiting gdb connection on port %d\n", gdbstub_port); } - term_init(); } else #endif { - term_init(); /* XXX: simplify init */ read_passwords(); if (start_emulation) { diff --git a/vl.h b/vl.h index 485ccc020..1f1e9e424 100644 --- a/vl.h +++ b/vl.h @@ -200,8 +200,6 @@ void qemu_chr_add_read_handler(CharDriverState *s, IOReadHandler *fd_read, void *opaque); void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); -CharDriverState *serial_hd; - /* consoles */ typedef struct DisplayState DisplayState; @@ -214,6 +212,12 @@ int is_active_console(TextConsole *s); CharDriverState *text_console_init(DisplayState *ds); void console_select(unsigned int index); +/* serial ports */ + +#define MAX_SERIAL_PORTS 4 + +extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; + /* network redirectors support */ #define MAX_NICS 8 -- cgit v1.2.3 From 60e336dbb837ef4d5053433f9ee391feb102be36 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Aug 2004 21:55:28 +0000 Subject: serial interrupt fix (Hampa Hug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1049 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/serial.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index 0fc1ccb9d..3fe482c39 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -133,7 +133,10 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (s->lcr & UART_LCR_DLAB) { s->divider = (s->divider & 0x00ff) | (val << 8); } else { - s->ier = val; + s->ier = val & 0x0f; + if (s->lsr & UART_LSR_THRE) { + s->thr_ipending = 1; + } serial_update_irq(s); } break; @@ -143,7 +146,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->lcr = val; break; case 4: - s->mcr = val; + s->mcr = val & 0x1f; break; case 5: break; -- cgit v1.2.3 From c7f746434f28c06faf9f3ebaac4973502468c4d3 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Aug 2004 21:57:12 +0000 Subject: TFTP support (Magnus Damm) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1050 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 2 +- slirp/slirp.h | 1 + slirp/tftp.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ slirp/tftp.h | 34 ++++++ slirp/udp.c | 8 ++ vl.c | 11 ++ 7 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 slirp/tftp.c create mode 100644 slirp/tftp.h diff --git a/Changelog b/Changelog index 9d18ec65f..4b6f315be 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,7 @@ version 0.6.1: transparent decompression - VMware 3 and 4 read-only disk image support (untested) - Support for up to 4 serial ports + - TFTP server support (Magnus Damm) version 0.6.0: diff --git a/Makefile.target b/Makefile.target index 6d5849071..5ac50dc09 100644 --- a/Makefile.target +++ b/Makefile.target @@ -264,7 +264,7 @@ ifdef CONFIG_SLIRP DEFINES+=-I$(SRC_PATH)/slirp SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \ slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o \ -tcp_subr.o tcp_timer.o udp.o bootp.o debug.o +tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS)) endif diff --git a/slirp/slirp.h b/slirp/slirp.h index f5c93c5ee..b52044a65 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -210,6 +210,7 @@ int inet_aton _P((const char *cp, struct in_addr *ia)); #endif #include "bootp.h" +#include "tftp.h" #include "libslirp.h" extern struct ttys *ttys_unit[MAX_INTERFACES]; diff --git a/slirp/tftp.c b/slirp/tftp.c new file mode 100644 index 000000000..1bcc70fa5 --- /dev/null +++ b/slirp/tftp.c @@ -0,0 +1,339 @@ +/* + * tftp.c - a simple, read-only tftp server for qemu + * + * Copyright (c) 2004 Magnus Damm + * + * 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 + +struct tftp_session { + int in_use; + unsigned char filename[TFTP_FILENAME_MAX]; + + struct in_addr client_ip; + u_int16_t client_port; + + struct timeval timestamp; +}; + +struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; + +char *tftp_prefix; + +static void tftp_session_update(struct tftp_session *spt) +{ + gettimeofday(&spt->timestamp, 0); + spt->in_use = 1; +} + +static void tftp_session_terminate(struct tftp_session *spt) +{ + spt->in_use = 0; +} + +static int tftp_session_allocate(struct tftp_t *tp) +{ + struct tftp_session *spt; + struct timeval tv; + int k; + + gettimeofday(&tv, 0); + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &tftp_sessions[k]; + + if (!spt->in_use) { + goto found; + } + + /* sessions time out after 5 inactive seconds */ + + if (tv.tv_sec > (spt->timestamp.tv_sec + 5)) { + goto found; + } + } + + return -1; + + found: + memset(spt, 0, sizeof(*spt)); + memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); + spt->client_port = tp->udp.uh_sport; + + tftp_session_update(spt); + + return k; +} + +static int tftp_session_find(struct tftp_t *tp) +{ + struct tftp_session *spt; + int k; + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &tftp_sessions[k]; + + if (spt->in_use) { + if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) { + if (spt->client_port == tp->udp.uh_sport) { + return k; + } + } + } + } + + return -1; +} + +static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, + u_int8_t *buf, int len) +{ + int fd; + int bytes_read = 0; + + fd = open(spt->filename, O_RDONLY); + + if (fd < 0) { + return -1; + } + + if (len) { + lseek(fd, block_nr * 512, SEEK_SET); + + bytes_read = read(fd, buf, len); + } + + close(fd); + + return bytes_read; +} + +static int tftp_send_error(struct tftp_session *spt, + u_int16_t errorcode, const char *msg, + struct tftp_t *recv_tp) +{ + struct sockaddr_in saddr, daddr; + struct mbuf *m; + struct tftp_t *tp; + int nobytes; + + m = m_get(); + + if (!m) { + return -1; + } + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_ERROR); + tp->x.tp_error.tp_error_code = htons(errorcode); + strcpy(tp->x.tp_error.tp_msg, msg); + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; + + daddr.sin_addr = spt->client_ip; + daddr.sin_port = spt->client_port; + + nobytes = 2; + + m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - + sizeof(struct ip) - sizeof(struct udphdr); + + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + tftp_session_terminate(spt); + + return 0; +} + +static int tftp_send_data(struct tftp_session *spt, + u_int16_t block_nr, + struct tftp_t *recv_tp) +{ + struct sockaddr_in saddr, daddr; + struct mbuf *m; + struct tftp_t *tp; + int nobytes; + + if (block_nr < 1) { + return -1; + } + + m = m_get(); + + if (!m) { + return -1; + } + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_DATA); + tp->x.tp_data.tp_block_nr = htons(block_nr); + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; + + daddr.sin_addr = spt->client_ip; + daddr.sin_port = spt->client_port; + + nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); + + if (nobytes < 0) { + m_free(m); + + /* send "file not found" error back */ + + tftp_send_error(spt, 1, "File not found", tp); + + return -1; + } + + m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - + sizeof(struct ip) - sizeof(struct udphdr); + + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + if (nobytes == 512) { + tftp_session_update(spt); + } + else { + tftp_session_terminate(spt); + } + + return 0; +} + +static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) +{ + struct tftp_session *spt; + int s, k, n; + u_int8_t *src, *dst; + + s = tftp_session_allocate(tp); + + if (s < 0) { + return; + } + + spt = &tftp_sessions[s]; + + src = tp->x.tp_buf; + dst = spt->filename; + n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); + + /* get name */ + + for (k = 0; k < n; k++) { + if (k < TFTP_FILENAME_MAX) { + dst[k] = src[k]; + } + else { + return; + } + + if (src[k] == '\0') { + break; + } + } + + if (k >= n) { + return; + } + + k++; + + /* check mode */ + if ((n - k) < 6) { + return; + } + + if (memcmp(&src[k], "octet\0", 6) != 0) { + tftp_send_error(spt, 4, "Unsupported transfer mode", tp); + return; + } + + /* do sanity checks on the filename */ + + if ((spt->filename[0] != '/') + || (spt->filename[strlen(spt->filename) - 1] == '/') + || strstr(spt->filename, "/../")) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + /* only allow exported prefixes */ + + if (!tftp_prefix + || (strncmp(spt->filename, tftp_prefix, strlen(tftp_prefix)) != 0)) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + /* check if the file exists */ + + if (tftp_read_data(spt, 0, spt->filename, 0) < 0) { + tftp_send_error(spt, 1, "File not found", tp); + return; + } + + tftp_send_data(spt, 1, tp); +} + +static void tftp_handle_ack(struct tftp_t *tp, int pktlen) +{ + int s; + + s = tftp_session_find(tp); + + if (s < 0) { + return; + } + + if (tftp_send_data(&tftp_sessions[s], + ntohs(tp->x.tp_data.tp_block_nr) + 1, + tp) < 0) { + return; + } +} + +void tftp_input(struct mbuf *m) +{ + struct tftp_t *tp = (struct tftp_t *)m->m_data; + + switch(ntohs(tp->tp_op)) { + case TFTP_RRQ: + tftp_handle_rrq(tp, m->m_len); + break; + + case TFTP_ACK: + tftp_handle_ack(tp, m->m_len); + break; + } +} diff --git a/slirp/tftp.h b/slirp/tftp.h new file mode 100644 index 000000000..3ee666a15 --- /dev/null +++ b/slirp/tftp.h @@ -0,0 +1,34 @@ +/* tftp defines */ + +#define TFTP_SESSIONS_MAX 3 + +#define TFTP_SERVER 69 + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 + +#define TFTP_FILENAME_MAX 512 + +struct tftp_t { + struct ip ip; + struct udphdr udp; + u_int16_t tp_op; + union { + struct { + u_int16_t tp_block_nr; + u_int8_t tp_buf[512]; + } tp_data; + struct { + u_int16_t tp_error_code; + u_int8_t tp_msg[512]; + } tp_error; + u_int8_t tp_buf[512 + 2]; + } x; +}; + +extern char *tftp_prefix; + +void tftp_input(struct mbuf *m); diff --git a/slirp/udp.c b/slirp/udp.c index 67a05090f..2dd51a39f 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -153,6 +153,14 @@ udp_input(m, iphlen) goto bad; } + /* + * handle TFTP + */ + if (ntohs(uh->uh_dport) == TFTP_SERVER) { + tftp_input(m); + goto bad; + } + /* * Locate pcb for datagram. */ diff --git a/vl.c b/vl.c index 4d274478e..f05d73a95 100644 --- a/vl.c +++ b/vl.c @@ -2334,6 +2334,7 @@ void help(void) "-tun-fd fd use this fd as already opened tap/tun interface\n" #ifdef CONFIG_SLIRP "-user-net use user mode network stack [default if no tap/tun script]\n" + "-tftp prefix allow tftp access to files starting with prefix [only with -user-net enabled]\n" #endif "-dummy-net use dummy network stack\n" "\n" @@ -2408,6 +2409,7 @@ enum { QEMU_OPTION_n, QEMU_OPTION_tun_fd, QEMU_OPTION_user_net, + QEMU_OPTION_tftp, QEMU_OPTION_dummy_net, QEMU_OPTION_kernel, @@ -2460,6 +2462,7 @@ const QEMUOption qemu_options[] = { { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, #ifdef CONFIG_SLIRP { "user-net", 0, QEMU_OPTION_user_net }, + { "tftp", HAS_ARG, QEMU_OPTION_tftp }, #endif { "dummy-net", 0, QEMU_OPTION_dummy_net }, @@ -2751,9 +2754,17 @@ int main(int argc, char **argv) } } break; +#ifdef CONFIG_SLIRP + case QEMU_OPTION_tftp: + { + extern const char *tftp_prefix; + tftp_prefix = optarg; + } + break; case QEMU_OPTION_user_net: net_if_type = NET_IF_USER; break; +#endif case QEMU_OPTION_dummy_net: net_if_type = NET_IF_DUMMY; break; -- cgit v1.2.3 From 4e8b5da233d453e60753a3c6326c807c73886c26 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 24 Aug 2004 22:06:03 +0000 Subject: MULSCC fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1051 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 946c11ec4..e2ef7ae7c 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -259,10 +259,10 @@ void OPPROTO op_smul_T1_T0(void) void OPPROTO op_mulscc_T1_T0(void) { - unsigned int b1, C, V, b2, src1; - C = FLAG_SET(PSR_CARRY); + unsigned int b1, N, V, b2, src1; + N = FLAG_SET(PSR_NEG); V = FLAG_SET(PSR_OVF); - b1 = C ^ V; + b1 = N ^ V; b2 = T0 & 1; T0 = (b1 << 31) | (T0 >> 1); if (!(env->y & 1)) -- cgit v1.2.3 From 7143c62c953628ced7c70715f67921ed6f13dfca Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Aug 2004 20:50:14 +0000 Subject: vmdk 3 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1052 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vmdk.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/block-vmdk.c b/block-vmdk.c index 36653fb2f..7193f959a 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -101,8 +101,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) return -1; if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) goto fail; - magic = le32_to_cpu(magic); - + magic = be32_to_cpu(magic); if (magic == VMDK3_MAGIC) { VMDK3Header header; if (read(fd, &header, sizeof(header)) != @@ -136,7 +135,9 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) s->l1_table = qemu_malloc(l1_size); if (!s->l1_table) goto fail; - if (read(s->fd, s->l1_table, l1_size) != l1_size) + 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]); -- cgit v1.2.3 From a3504c87cac0248996bc07d732761ad37ba45f34 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Aug 2004 20:55:44 +0000 Subject: removed gettimeofday usage git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1053 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/tftp.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/slirp/tftp.c b/slirp/tftp.c index 1bcc70fa5..e50d25539 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -25,13 +25,13 @@ #include struct tftp_session { - int in_use; - unsigned char filename[TFTP_FILENAME_MAX]; - - struct in_addr client_ip; - u_int16_t client_port; - - struct timeval timestamp; + int in_use; + unsigned char filename[TFTP_FILENAME_MAX]; + + struct in_addr client_ip; + u_int16_t client_port; + + int timestamp; }; struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; @@ -40,8 +40,8 @@ char *tftp_prefix; static void tftp_session_update(struct tftp_session *spt) { - gettimeofday(&spt->timestamp, 0); - spt->in_use = 1; + spt->timestamp = curtime; + spt->in_use = 1; } static void tftp_session_terminate(struct tftp_session *spt) @@ -52,23 +52,17 @@ static void tftp_session_terminate(struct tftp_session *spt) static int tftp_session_allocate(struct tftp_t *tp) { struct tftp_session *spt; - struct timeval tv; int k; - gettimeofday(&tv, 0); - for (k = 0; k < TFTP_SESSIONS_MAX; k++) { spt = &tftp_sessions[k]; - if (!spt->in_use) { - goto found; - } + if (!spt->in_use) + goto found; /* sessions time out after 5 inactive seconds */ - - if (tv.tv_sec > (spt->timestamp.tv_sec + 5)) { - goto found; - } + if ((int)(curtime - spt->timestamp) > 5000) + goto found; } return -1; -- cgit v1.2.3 From 9bf05444b24f10616b9e9b9f296bcfdcba4ff0df Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Aug 2004 22:12:49 +0000 Subject: port redirection support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1054 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + qemu-doc.texi | 45 ++++++++++++++++++++++++++++- slirp/libslirp.h | 7 +++++ slirp/slirp.c | 15 ++++++++++ slirp/tftp.c | 2 +- slirp/tftp.h | 2 -- vl.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 7 files changed, 149 insertions(+), 9 deletions(-) diff --git a/Changelog b/Changelog index 4b6f315be..430ef55c0 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,7 @@ version 0.6.1: - 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 version 0.6.0: diff --git a/qemu-doc.texi b/qemu-doc.texi index ba3ade861..7493d519d 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -228,6 +228,44 @@ example of its use. Use the user mode network stack. This is the default if no tun/tap network init script is found. +@item -tftp prefix +When using the user mode network stack, activate a built-in TFTP +server. All filenames beginning with @var{prefix} can be downloaded +from the host to the guest using a TFTP client. The TFTP client on the +guest must be configured in binary mode (use the command @code{bin} of +the Unix TFTP client). The host IP address on the guest is as usual +10.0.2.2. + +@item -redir [tcp|udp]:host-port:[guest-host]:guest-port + +When using the user mode network stack, redirect incoming TCP or UDP +connections to the host port @var{host-port} to the guest +@var{guest-host} on guest port @var{guest-port}. If @var{guest-host} +is not specified, its value is 10.0.2.15 (default address given by the +built-in DHCP server). + +For example, to redirect host X11 connection from screen 1 to guest +screen 0, use the following: + +@example +# on the host +qemu -redir tcp:6001::6000 [...] +# this host xterm should open in the guest X11 server +xterm -display :1 +@end example + +To redirect telnet connections from host port 5555 to telnet port on +the guest, use the following: + +@example +# on the host +qemu -redir tcp:5555::23 [...] +telnet localhost 5555 +@end example + +Then when you use on the host @code{telnet localhost 5555}, you +connect to the guest telnet server. + @item -dummy-net Use the dummy network stack: no packet will be received by the network cards. @@ -652,7 +690,12 @@ Note that @code{ping} is not supported reliably to the internet as it would require root priviledges. It means you can only ping the local router (10.0.2.2). -The user mode network is currently only supported on a Unix host. +When using the built-in TFTP server, the router is also the TFTP +server. + +When using the @option{-redir} option, TCP or UDP connections can be +redirected from the host to the guest. It allows for example to +redirect X11, telnet or SSH connections. @node direct_linux_boot @section Direct Linux Boot diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 47824b241..772427d11 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -3,8 +3,10 @@ #ifdef _WIN32 #include +int inet_aton(const char *cp, struct in_addr *ia); #else #include +#include #endif void slirp_init(void); @@ -20,4 +22,9 @@ void slirp_input(const uint8_t *pkt, int pkt_len); int slirp_can_output(void); void slirp_output(const uint8_t *pkt, int pkt_len); +int slirp_redir(int is_udp, int host_port, + struct in_addr guest_addr, int guest_port); + +extern const char *tftp_prefix; + #endif diff --git a/slirp/slirp.c b/slirp/slirp.c index 405647b48..bc2b15509 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -617,3 +617,18 @@ void if_encap(const uint8_t *ip_data, int ip_data_len) memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); slirp_output(buf, ip_data_len + ETH_HLEN); } + +int slirp_redir(int is_udp, int host_port, + struct in_addr guest_addr, int guest_port) +{ + if (is_udp) { + if (!udp_listen(htons(host_port), guest_addr.s_addr, + htons(guest_port), 0)) + return -1; + } else { + if (!solisten(htons(host_port), guest_addr.s_addr, + htons(guest_port), 0)) + return -1; + } + return 0; +} diff --git a/slirp/tftp.c b/slirp/tftp.c index e50d25539..90526625c 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -36,7 +36,7 @@ struct tftp_session { struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; -char *tftp_prefix; +const char *tftp_prefix; static void tftp_session_update(struct tftp_session *spt) { diff --git a/slirp/tftp.h b/slirp/tftp.h index 3ee666a15..f0560b6ab 100644 --- a/slirp/tftp.h +++ b/slirp/tftp.h @@ -29,6 +29,4 @@ struct tftp_t { } x; }; -extern char *tftp_prefix; - void tftp_input(struct mbuf *m); diff --git a/vl.c b/vl.c index f05d73a95..5ba5b97a5 100644 --- a/vl.c +++ b/vl.c @@ -1382,6 +1382,78 @@ static int net_slirp_init(NetDriverState *nd) return 0; } +static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) +{ + const char *p, *p1; + int len; + p = *pp; + p1 = strchr(p, sep); + if (!p1) + return -1; + len = p1 - p; + p1++; + if (buf_size > 0) { + if (len > buf_size - 1) + len = buf_size - 1; + memcpy(buf, p, len); + buf[len] = '\0'; + } + *pp = p1; + return 0; +} + +static void net_slirp_redir(const char *redir_str) +{ + int is_udp; + char buf[256], *r; + const char *p; + struct in_addr guest_addr; + int host_port, guest_port; + + if (!slirp_inited) { + slirp_inited = 1; + slirp_init(); + } + + p = redir_str; + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + if (!strcmp(buf, "tcp")) { + is_udp = 0; + } else if (!strcmp(buf, "udp")) { + is_udp = 1; + } else { + goto fail; + } + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + host_port = strtol(buf, &r, 0); + if (r == buf) + goto fail; + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + if (buf[0] == '\0') { + pstrcpy(buf, sizeof(buf), "10.0.2.15"); + } + if (!inet_aton(buf, &guest_addr)) + goto fail; + + guest_port = strtol(p, &r, 0); + if (r == p) + goto fail; + + if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { + fprintf(stderr, "qemu: could not set up redirection\n"); + exit(1); + } + return; + fail: + fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n"); + exit(1); +} + #endif /* CONFIG_SLIRP */ #if !defined(_WIN32) @@ -2334,7 +2406,9 @@ void help(void) "-tun-fd fd use this fd as already opened tap/tun interface\n" #ifdef CONFIG_SLIRP "-user-net use user mode network stack [default if no tap/tun script]\n" - "-tftp prefix allow tftp access to files starting with prefix [only with -user-net enabled]\n" + "-tftp prefix allow tftp access to files starting with prefix [-user-net]\n" + "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" + " redirect TCP or UDP connections from host to guest [-user-net]\n" #endif "-dummy-net use dummy network stack\n" "\n" @@ -2410,6 +2484,7 @@ enum { QEMU_OPTION_tun_fd, QEMU_OPTION_user_net, QEMU_OPTION_tftp, + QEMU_OPTION_redir, QEMU_OPTION_dummy_net, QEMU_OPTION_kernel, @@ -2463,6 +2538,7 @@ const QEMUOption qemu_options[] = { #ifdef CONFIG_SLIRP { "user-net", 0, QEMU_OPTION_user_net }, { "tftp", HAS_ARG, QEMU_OPTION_tftp }, + { "redir", HAS_ARG, QEMU_OPTION_redir }, #endif { "dummy-net", 0, QEMU_OPTION_dummy_net }, @@ -2756,14 +2832,14 @@ int main(int argc, char **argv) break; #ifdef CONFIG_SLIRP case QEMU_OPTION_tftp: - { - extern const char *tftp_prefix; tftp_prefix = optarg; - } - break; + break; case QEMU_OPTION_user_net: net_if_type = NET_IF_USER; break; + case QEMU_OPTION_redir: + net_slirp_redir(optarg); + break; #endif case QEMU_OPTION_dummy_net: net_if_type = NET_IF_DUMMY; -- cgit v1.2.3 From 7c08dbf325fc301e4889fd352222d94d9d6b0451 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 25 Aug 2004 22:30:56 +0000 Subject: endianness fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1055 c046a42c-6fe2-441c-8c8c-71466251a162 --- ppc-dis.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ppc-dis.c b/ppc-dis.c index 354b2ac8c..fcced1785 100644 --- a/ppc-dis.c +++ b/ppc-dis.c @@ -3076,15 +3076,20 @@ static int print_insn_powerpc(FILE *, uint32_t insn, unsigned memaddr, int diale int print_insn_ppc (bfd_vma pc, disassemble_info *info) { uint32_t opc; - - (*info->read_memory_func)(pc, (bfd_byte *)(&opc), 4, info); - return print_insn_powerpc (info->stream, tswap32(opc), pc, + bfd_byte buf[4]; + + (*info->read_memory_func)(pc, buf, 4, info); + if (info->endian == BFD_ENDIAN_BIG) + opc = bfd_getb32(buf); + else + opc = bfd_getl32(buf); + return print_insn_powerpc (info->stream, opc, pc, PPC | B32 | M601); } /* Print a PowerPC or POWER instruction. */ -int +static int print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr, int dialect) { -- cgit v1.2.3 From 75c238058423fba689599dda4bed2b5bb7634570 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 27 Aug 2004 21:28:58 +0000 Subject: fixed image creation with base filename git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1056 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 76 +++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index cdb0ea124..5f8362235 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -273,6 +273,36 @@ int read_password(char *buf, int buf_size) } #endif +static BlockDriverState *bdrv_new_open(const char *filename, + const char *fmt) +{ + BlockDriverState *bs; + BlockDriver *drv; + char password[256]; + + bs = bdrv_new(""); + if (!bs) + error("Not enough memory"); + if (fmt) { + drv = bdrv_find_format(fmt); + if (!drv) + error("Unknown file format '%s'", fmt); + } else { + drv = NULL; + } + if (bdrv_open2(bs, filename, 0, drv) < 0) { + error("Could not open '%s'", filename); + } + if (bdrv_is_encrypted(bs)) { + printf("Disk image '%s' is encrypted.\n", filename); + if (read_password(password, sizeof(password)) < 0) + error("No password given"); + if (bdrv_set_key(bs, password) < 0) + error("invalid password"); + } + return bs; +} + static int img_create(int argc, char **argv) { int c, ret, encrypted; @@ -308,7 +338,13 @@ static int img_create(int argc, char **argv) help(); filename = argv[optind++]; size = 0; - if (!base_filename) { + if (base_filename) { + BlockDriverState *bs; + bs = bdrv_new_open(base_filename, NULL); + bdrv_get_geometry(bs, &size); + size *= 512; + bdrv_delete(bs); + } else { if (optind >= argc) help(); p = argv[optind]; @@ -330,11 +366,11 @@ static int img_create(int argc, char **argv) filename, fmt); if (encrypted) printf(", encrypted"); - if (base_filename) - printf(", backing_file=%s\n", + if (base_filename) { + printf(", backing_file=%s", base_filename); - else - printf(", size=%lld kB\n", size / 1024); + } + printf(", size=%lld kB\n", size / 1024); ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted); if (ret < 0) { if (ret == -ENOTSUP) { @@ -437,36 +473,6 @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum) return v; } -static BlockDriverState *bdrv_new_open(const char *filename, - const char *fmt) -{ - BlockDriverState *bs; - BlockDriver *drv; - char password[256]; - - bs = bdrv_new(""); - if (!bs) - error("Not enough memory"); - if (fmt) { - drv = bdrv_find_format(fmt); - if (!drv) - error("Unknown file format '%s'", fmt); - } else { - drv = NULL; - } - if (bdrv_open2(bs, filename, 0, drv) < 0) { - error("Could not open '%s'", filename); - } - if (bdrv_is_encrypted(bs)) { - printf("Disk image '%s' is encrypted.\n", filename); - if (read_password(password, sizeof(password)) < 0) - error("No password given"); - if (bdrv_set_key(bs, password) < 0) - error("invalid password"); - } - return bs; -} - #define IO_BUF_SIZE 65536 static int img_convert(int argc, char **argv) -- cgit v1.2.3 From c4dfa5b7be790c58aca3381d0dbb72e6ad635b09 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 29 Aug 2004 13:10:18 +0000 Subject: removed duplicated option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1057 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 3 --- 1 file changed, 3 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 7493d519d..51fc12fa5 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -181,9 +181,6 @@ the write back by pressing @key{C-a s} (@xref{disk_images}). @item -m megs Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. -@item -initrd file -Use @var{file} as initial ram disk. - @item -nographic Normally, QEMU uses SDL to display the VGA output. With this option, -- cgit v1.2.3 From 36d54d15e1ef8287a7b306f06dc9f49178773c65 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Sep 2004 16:04:16 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1058 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-tech.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index 0df2a0b96..4e6f507c7 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -167,7 +167,7 @@ interpreter part of the FX!32 Digital Win32 code translator [5]). TWIN [6] is a Windows API emulator like Wine. It is less accurate than Wine but includes a protected mode x86 interpreter to launch x86 Windows -executables. Such an approach as greater potential because most of the +executables. Such an approach has greater potential because most of the Windows API is executed natively but it is far more difficult to develop because all the data structures and function parameters exchanged between the API and the x86 code must be converted. -- cgit v1.2.3 From 9d728e8c4ed000b1d6a77230d11b3761a7c8b5a1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Sep 2004 23:09:03 +0000 Subject: smb support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1059 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/vl.c b/vl.c index 5ba5b97a5..5fc35abc5 100644 --- a/vl.c +++ b/vl.c @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef _BSD #include #ifndef __APPLE__ @@ -1453,6 +1454,80 @@ static void net_slirp_redir(const char *redir_str) fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n"); exit(1); } + +char smb_dir[1024]; + +static void smb_exit(void) +{ + DIR *d; + struct dirent *de; + char filename[1024]; + + /* erase all the files in the directory */ + d = opendir(smb_dir); + for(;;) { + de = readdir(d); + if (!de) + break; + if (strcmp(de->d_name, ".") != 0 && + strcmp(de->d_name, "..") != 0) { + snprintf(filename, sizeof(filename), "%s/%s", + smb_dir, de->d_name); + unlink(filename); + } + } + rmdir(smb_dir); +} + +/* automatic user mode samba server configuration */ +void net_slirp_smb(const char *exported_dir) +{ + char smb_conf[1024]; + char smb_cmdline[1024]; + FILE *f; + + if (!slirp_inited) { + slirp_inited = 1; + slirp_init(); + } + + /* XXX: better tmp dir construction */ + snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%d", getpid()); + if (mkdir(smb_dir, 0700) < 0) { + fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir); + exit(1); + } + snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf"); + + f = fopen(smb_conf, "w"); + if (!f) { + fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf); + exit(1); + } + fprintf(f, + "[global]\n" + "pid directory=%s\n" + "lock directory=%s\n" + "log file=%s/log.smbd\n" + "smb passwd file=%s/smbpasswd\n" + "[qemu]\n" + "path=%s\n" + "read only=no\n" + "guest ok=yes\n", + smb_dir, + smb_dir, + smb_dir, + smb_dir, + exported_dir + ); + fclose(f); + atexit(smb_exit); + + snprintf(smb_cmdline, sizeof(smb_cmdline), "/usr/sbin/smbd -s %s", + smb_conf); + + slirp_add_exec(0, smb_cmdline, 4, 139); +} #endif /* CONFIG_SLIRP */ @@ -2407,6 +2482,7 @@ void help(void) #ifdef CONFIG_SLIRP "-user-net use user mode network stack [default if no tap/tun script]\n" "-tftp prefix allow tftp access to files starting with prefix [-user-net]\n" + "-smb dir allow SMB access to files in 'dir' [-user-net]\n" "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" " redirect TCP or UDP connections from host to guest [-user-net]\n" #endif @@ -2484,6 +2560,7 @@ enum { QEMU_OPTION_tun_fd, QEMU_OPTION_user_net, QEMU_OPTION_tftp, + QEMU_OPTION_smb, QEMU_OPTION_redir, QEMU_OPTION_dummy_net, @@ -2538,6 +2615,7 @@ const QEMUOption qemu_options[] = { #ifdef CONFIG_SLIRP { "user-net", 0, QEMU_OPTION_user_net }, { "tftp", HAS_ARG, QEMU_OPTION_tftp }, + { "smb", HAS_ARG, QEMU_OPTION_smb }, { "redir", HAS_ARG, QEMU_OPTION_redir }, #endif { "dummy-net", 0, QEMU_OPTION_dummy_net }, @@ -2834,6 +2912,9 @@ int main(int argc, char **argv) case QEMU_OPTION_tftp: tftp_prefix = optarg; break; + case QEMU_OPTION_smb: + net_slirp_smb(optarg); + break; case QEMU_OPTION_user_net: net_if_type = NET_IF_USER; break; -- cgit v1.2.3 From a3d4af03bbedccb5c777562284c1098b9df7fe8a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Sep 2004 23:10:26 +0000 Subject: allow inetd like program exec git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1060 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/libslirp.h | 2 ++ slirp/misc.c | 20 ++++++++++++++++++-- slirp/slirp.c | 22 +++++++++++++++++++--- slirp/tcp_input.c | 6 +++--- slirp/tcp_subr.c | 9 ++++----- 5 files changed, 46 insertions(+), 13 deletions(-) diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 772427d11..6a54eb14f 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -24,6 +24,8 @@ void slirp_output(const uint8_t *pkt, int pkt_len); int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port); +int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, + int guest_port); extern const char *tftp_prefix; diff --git a/slirp/misc.c b/slirp/misc.c index 64bd9ee2f..26f8eb578 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -212,7 +212,20 @@ strerror(error) #endif -#if 0 +#ifdef _WIN32 + +int +fork_exec(so, ex, do_pty) + struct socket *so; + char *ex; + int do_pty; +{ + /* not implemented */ + return 0; +} + +#else + int openpty(amaster, aslave) int *amaster, *aslave; @@ -301,7 +314,9 @@ fork_exec(so, ex, do_pty) int opt; int master; char *argv[256]; +#if 0 char buff[256]; +#endif /* don't want to clobber the original */ char *bptr; char *curarg; @@ -360,6 +375,7 @@ fork_exec(so, ex, do_pty) connect(s, (struct sockaddr *)&addr, addrlen); } +#if 0 if (x_port >= 0) { #ifdef HAVE_SETENV sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); @@ -369,7 +385,7 @@ fork_exec(so, ex, do_pty) putenv(buff); #endif } - +#endif dup2(s, 0); dup2(s, 1); dup2(s, 2); diff --git a/slirp/slirp.c b/slirp/slirp.c index bc2b15509..99f168740 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -20,6 +20,7 @@ int do_slowtimo; int link_up; struct timeval tt; FILE *lfd; +struct ex_list *exec_list; /* XXX: suppress those select globals */ fd_set *global_readfds, *global_writefds, *global_xfds; @@ -538,13 +539,20 @@ void arp_input(const uint8_t *pkt, int pkt_len) struct ethhdr *reh = (struct ethhdr *)arp_reply; struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); int ar_op; + struct ex_list *ex_ptr; ar_op = ntohs(ah->ar_op); switch(ar_op) { case ARPOP_REQUEST: - if (!memcmp(ah->ar_tip, &special_addr, 3) && - (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)) { - + if (!memcmp(ah->ar_tip, &special_addr, 3)) { + if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) + goto arp_ok; + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_addr == ah->ar_tip[3]) + goto arp_ok; + } + return; + arp_ok: /* XXX: make an ARP request to have the client address */ memcpy(client_ethaddr, eh->h_source, ETH_ALEN); @@ -612,6 +620,7 @@ void if_encap(const uint8_t *ip_data, int ip_data_len) memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); + /* XXX: not correct */ eh->h_source[5] = CTL_ALIAS; eh->h_proto = htons(ETH_P_IP); memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); @@ -632,3 +641,10 @@ int slirp_redir(int is_udp, int host_port, } return 0; } + +int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, + int guest_port) +{ + return add_exec(&exec_list, do_pty, (char *)args, + addr_low_byte, htons(guest_port)); +} diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 4f74d0cdb..42f02b3e6 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -658,10 +658,11 @@ findso: if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) { /* Command or exec adress */ so->so_state |= SS_CTL; - } else { + } else +#endif + { /* May be an add exec */ struct ex_list *ex_ptr; - for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if(ex_ptr->ex_fport == so->so_fport && lastbyte == ex_ptr->ex_addr) { @@ -671,7 +672,6 @@ findso: } } if(so->so_state & SS_CTL) goto cont_input; -#endif } /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ } diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index c29dc604f..b6fbbfaf0 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -1249,7 +1249,6 @@ int tcp_ctl(so) struct socket *so; { -#if 0 struct sbuf *sb = &so->so_snd; int command; struct ex_list *ex_ptr; @@ -1259,6 +1258,7 @@ tcp_ctl(so) DEBUG_CALL("tcp_ctl"); DEBUG_ARG("so = %lx", (long )so); +#if 0 /* * Check if they're authorised */ @@ -1267,7 +1267,7 @@ tcp_ctl(so) sb->sb_wptr += sb->sb_cc; return 0; } - +#endif command = (ntohl(so->so_faddr.s_addr) & 0xff); switch(command) { @@ -1300,6 +1300,7 @@ tcp_ctl(so) DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); return(fork_exec(so, ex_ptr->ex_exec, do_pty)); +#if 0 case CTL_CMD: for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { if (tmpso->so_emu == EMU_CTL && @@ -1318,8 +1319,6 @@ tcp_ctl(so) sb->sb_wptr += sb->sb_cc; do_echo=-1; return(2); - } -#else - return 0; #endif + } } -- cgit v1.2.3 From 03ffbb69a8e01eded2457ee5873e2fab6f4abf15 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 6 Sep 2004 00:14:04 +0000 Subject: smb config fix for NT git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1061 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vl.c b/vl.c index 5fc35abc5..e32c6d0c3 100644 --- a/vl.c +++ b/vl.c @@ -1476,6 +1476,7 @@ static void smb_exit(void) unlink(filename); } } + closedir(d); rmdir(smb_dir); } @@ -1510,6 +1511,7 @@ void net_slirp_smb(const char *exported_dir) "lock directory=%s\n" "log file=%s/log.smbd\n" "smb passwd file=%s/smbpasswd\n" + "security = share\n" "[qemu]\n" "path=%s\n" "read only=no\n" -- cgit v1.2.3 From 01038d2a7689aaedab55862e8d9691c8829355d3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 13 Sep 2004 21:36:46 +0000 Subject: monitor fix (Derek Fawcus) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1062 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index 89285c1a5..77426c529 100644 --- a/monitor.c +++ b/monitor.c @@ -850,12 +850,13 @@ static MonitorDef monitor_defs[] = { { "esp|sp", offsetof(CPUState, regs[4]) }, { "ebp|fp", offsetof(CPUState, regs[5]) }, { "esi", offsetof(CPUState, regs[6]) }, - { "esi", offsetof(CPUState, regs[7]) }, + { "edi", offsetof(CPUState, regs[7]) }, { "eflags", offsetof(CPUState, eflags) }, { "eip", offsetof(CPUState, eip) }, SEG("cs", R_CS) SEG("ds", R_DS) SEG("es", R_ES) + SEG("ss", R_SS) SEG("fs", R_FS) SEG("gs", R_GS) { "pc", 0, monitor_get_pc, }, -- cgit v1.2.3 From c94c8d6499690461a0aa0ae9245ce4b0715ed4a8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 13 Sep 2004 21:37:34 +0000 Subject: win32 + Mac OS X compile git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1063 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/vl.c b/vl.c index e32c6d0c3..958a432f7 100644 --- a/vl.c +++ b/vl.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #ifdef _BSD #include @@ -1455,6 +1456,8 @@ static void net_slirp_redir(const char *redir_str) exit(1); } +#ifndef _WIN32 + char smb_dir[1024]; static void smb_exit(void) @@ -1531,6 +1534,8 @@ void net_slirp_smb(const char *exported_dir) slirp_add_exec(0, smb_cmdline, 4, 139); } +#endif /* !defined(_WIN32) */ + #endif /* CONFIG_SLIRP */ #if !defined(_WIN32) @@ -2484,7 +2489,9 @@ void help(void) #ifdef CONFIG_SLIRP "-user-net use user mode network stack [default if no tap/tun script]\n" "-tftp prefix allow tftp access to files starting with prefix [-user-net]\n" +#ifndef _WIN32 "-smb dir allow SMB access to files in 'dir' [-user-net]\n" +#endif "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" " redirect TCP or UDP connections from host to guest [-user-net]\n" #endif @@ -2617,7 +2624,9 @@ const QEMUOption qemu_options[] = { #ifdef CONFIG_SLIRP { "user-net", 0, QEMU_OPTION_user_net }, { "tftp", HAS_ARG, QEMU_OPTION_tftp }, +#ifndef _WIN32 { "smb", HAS_ARG, QEMU_OPTION_smb }, +#endif { "redir", HAS_ARG, QEMU_OPTION_redir }, #endif { "dummy-net", 0, QEMU_OPTION_dummy_net }, @@ -2914,9 +2923,11 @@ int main(int argc, char **argv) case QEMU_OPTION_tftp: tftp_prefix = optarg; break; +#ifndef _WIN32 case QEMU_OPTION_smb: net_slirp_smb(optarg); break; +#endif case QEMU_OPTION_user_net: net_if_type = NET_IF_USER; break; -- cgit v1.2.3 From 6f28fb86c99226aea86023b27704b23c4ec3d5a5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 13 Sep 2004 21:39:32 +0000 Subject: zero file case (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1064 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/path.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-user/path.c b/linux-user/path.c index 9e49076dc..76809705a 100644 --- a/linux-user/path.c +++ b/linux-user/path.c @@ -101,7 +101,12 @@ void init_paths(const char *prefix) base = new_entry("", NULL, prefix+1); base = add_dir_maybe(base); - set_parents(base, base); + if (base->num_entries == 0) { + free (base); + base = NULL; + } else { + set_parents(base, base); + } } /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ -- cgit v1.2.3 From 29e619b1e8b1b79255009451e26c1bdbd9338fa6 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 13 Sep 2004 21:41:04 +0000 Subject: uname + sysctl fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1065 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5b1f7a4ce..9f1b32922 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2392,6 +2392,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_uname: /* no need to transcode because we use the linux syscall */ + { + struct new_utsname * buf; + + buf = (struct new_utsname *)arg1; + ret = get_errno(sys_uname(buf)); + if (!is_error(ret)) { + /* Overrite the native machine name with whatever is being + emulated. */ + strcpy (buf->machine, UNAME_MACHINE); + } + } ret = get_errno(sys_uname((struct new_utsname *)arg1)); break; #ifdef TARGET_I386 @@ -2600,7 +2611,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(fdatasync(arg1)); break; case TARGET_NR__sysctl: - goto unimplemented; + /* We don't implement this, but ENODIR is always a safe + return value. */ + return -ENOTDIR; case TARGET_NR_sched_setparam: { struct sched_param *target_schp = (void *)arg2; -- cgit v1.2.3 From cf720db33a6b46869a9c7c12d237a08d881e8bfb Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 13 Sep 2004 21:41:39 +0000 Subject: uname fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1066 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/syscall.h | 6 ++++++ linux-user/i386/syscall.h | 1 + linux-user/ppc/syscall.h | 1 + linux-user/sparc/syscall.h | 2 ++ 4 files changed, 10 insertions(+) diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index 0ced33ee5..645036174 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -28,3 +28,9 @@ struct target_pt_regs { #define ARM_SYSCALL_BASE 0x900000 #define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) + +#if defined(TARGET_WORDS_BIGENDIAN) +#define UNAME_MACHINE "armv4b" +#else +#define UNAME_MACHINE "armv4l" +#endif diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index e1f470d78..cc0942b81 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -218,3 +218,4 @@ union target_semun { unsigned int __pad; /* really void* */ }; +#define UNAME_MACHINE "i686" diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index e7ded9974..eea8a7c9a 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -127,3 +127,4 @@ union target_semun { unsigned int __pad; /* really void* */ }; +#define UNAME_MACHINE "ppc" diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index 474c87c30..5be90fa7f 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -5,3 +5,5 @@ struct target_pt_regs { target_ulong y; target_ulong u_regs[16]; }; + +#define UNAME_MACHINE "sun4" -- cgit v1.2.3 From c9a621176e479b8106056ed992fddf34d9d0d206 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 13 Sep 2004 21:42:51 +0000 Subject: memory leak fix (Juergen Keil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1067 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/if.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slirp/if.c b/slirp/if.c index 282b674c5..9317cbfe9 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -315,6 +315,8 @@ if_start(void) /* Encapsulate the packet for sending */ if_encap(ifm->m_data, ifm->m_len); + m_free(ifm); + if (if_queued) goto again; } -- cgit v1.2.3 From e2731add29e3c74a472dcb81f90bf9aa14f4b8e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 18 Sep 2004 19:32:11 +0000 Subject: fixed block close() method prototype git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1068 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-cow.c | 2 +- block-qcow.c | 2 +- block-vmdk.c | 2 +- block.c | 2 +- block_int.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/block-cow.c b/block-cow.c index affeefa3f..81bd334cc 100644 --- a/block-cow.c +++ b/block-cow.c @@ -202,7 +202,7 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num, return 0; } -static int cow_close(BlockDriverState *bs) +static void cow_close(BlockDriverState *bs) { BDRVCowState *s = bs->opaque; munmap(s->cow_bitmap_addr, s->cow_bitmap_size); diff --git a/block-qcow.c b/block-qcow.c index 953f42c7b..99c383295 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -521,7 +521,7 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, return 0; } -static int qcow_close(BlockDriverState *bs) +static void qcow_close(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; qemu_free(s->l1_table); diff --git a/block-vmdk.c b/block-vmdk.c index 7193f959a..1cc498853 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -258,7 +258,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, return -1; } -static int vmdk_close(BlockDriverState *bs) +static void vmdk_close(BlockDriverState *bs) { BDRVVmdkState *s = bs->opaque; qemu_free(s->l1_table); diff --git a/block.c b/block.c index 8dea3c932..389617cb4 100644 --- a/block.c +++ b/block.c @@ -554,7 +554,7 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num, return 0; } -static int raw_close(BlockDriverState *bs) +static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; close(s->fd); diff --git a/block_int.h b/block_int.h index 36a88ed0a..9d047c4ff 100644 --- a/block_int.h +++ b/block_int.h @@ -33,7 +33,7 @@ struct BlockDriver { uint8_t *buf, int nb_sectors); int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); - int (*bdrv_close)(BlockDriverState *bs); + void (*bdrv_close)(BlockDriverState *bs); int (*bdrv_create)(const char *filename, int64_t total_sectors, const char *backing_file, int flags); int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, -- cgit v1.2.3 From b86bda5bb193aa47ee95c43ec31d899b52b45645 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 18 Sep 2004 19:32:46 +0000 Subject: adde TLB dump git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1069 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/monitor.c b/monitor.c index 77426c529..ad0f31586 100644 --- a/monitor.c +++ b/monitor.c @@ -695,6 +695,117 @@ static void do_system_reset(void) qemu_system_reset_request(); } +#if defined(TARGET_I386) +static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask) +{ + term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n", + addr, + pte & mask, + pte & PG_GLOBAL_MASK ? 'G' : '-', + pte & PG_PSE_MASK ? 'P' : '-', + pte & PG_DIRTY_MASK ? 'D' : '-', + pte & PG_ACCESSED_MASK ? 'A' : '-', + pte & PG_PCD_MASK ? 'C' : '-', + pte & PG_PWT_MASK ? 'T' : '-', + pte & PG_USER_MASK ? 'U' : '-', + pte & PG_RW_MASK ? 'W' : '-'); +} + +static void tlb_info(void) +{ + CPUState *env = cpu_single_env; + int l1, l2; + uint32_t pgd, pde, pte; + + if (!(env->cr[0] & CR0_PG_MASK)) { + term_printf("PG disabled\n"); + return; + } + pgd = env->cr[3] & ~0xfff; + for(l1 = 0; l1 < 1024; l1++) { + cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + pde = le32_to_cpu(pde); + if (pde & PG_PRESENT_MASK) { + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + print_pte((l1 << 22), pde, ~((1 << 20) - 1)); + } else { + for(l2 = 0; l2 < 1024; l2++) { + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, + (uint8_t *)&pte, 4); + pte = le32_to_cpu(pte); + if (pte & PG_PRESENT_MASK) { + print_pte((l1 << 22) + (l2 << 12), + pte & ~PG_PSE_MASK, + ~0xfff); + } + } + } + } + } +} + +static void mem_print(uint32_t *pstart, int *plast_prot, + uint32_t end, int prot) +{ + if (prot != *plast_prot) { + if (*pstart != -1) { + term_printf("%08x-%08x %08x %c%c%c\n", + *pstart, end, end - *pstart, + prot & PG_USER_MASK ? 'u' : '-', + 'r', + prot & PG_RW_MASK ? 'w' : '-'); + } + if (prot != 0) + *pstart = end; + else + *pstart = -1; + *plast_prot = prot; + } +} + +static void mem_info(void) +{ + CPUState *env = cpu_single_env; + int l1, l2, prot, last_prot; + uint32_t pgd, pde, pte, start, end; + + if (!(env->cr[0] & CR0_PG_MASK)) { + term_printf("PG disabled\n"); + return; + } + pgd = env->cr[3] & ~0xfff; + last_prot = 0; + start = -1; + for(l1 = 0; l1 < 1024; l1++) { + cpu_physical_memory_read(pgd + l1 * 4, (uint8_t *)&pde, 4); + pde = le32_to_cpu(pde); + end = l1 << 22; + if (pde & PG_PRESENT_MASK) { + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + prot = pde & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK); + mem_print(&start, &last_prot, end, prot); + } else { + for(l2 = 0; l2 < 1024; l2++) { + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, + (uint8_t *)&pte, 4); + pte = le32_to_cpu(pte); + end = (l1 << 22) + (l2 << 12); + if (pte & PG_PRESENT_MASK) { + prot = pte & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK); + } else { + prot = 0; + } + mem_print(&start, &last_prot, end, prot); + } + } + } else { + prot = 0; + mem_print(&start, &last_prot, end, prot); + } + } +} +#endif + static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -755,6 +866,12 @@ static term_cmd_t info_cmds[] = { "", "show i8259 (PIC) state", }, { "pci", "", pci_info, "", "show PCI info", }, +#if defined(TARGET_I386) + { "tlb", "", tlb_info, + "", "show virtual to physical memory mappings", }, + { "mem", "", mem_info, + "", "show the active virtual memory mappings", }, +#endif { NULL, NULL, }, }; -- cgit v1.2.3 From eb45f5fec4deda4b2374984e64e5e20c63ab7af3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 18 Sep 2004 19:33:09 +0000 Subject: prototype fixed git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1070 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.h b/vl.h index 1f1e9e424..a8a70af5d 100644 --- a/vl.h +++ b/vl.h @@ -188,7 +188,7 @@ typedef struct CharDriverState { IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque); IOEventHandler *chr_event; - IOEventHandler *chr_send_event; + void (*chr_send_event)(struct CharDriverState *chr, int event); void *opaque; } CharDriverState; -- cgit v1.2.3 From 99679ececcc633be817cfc4d0bef5c2799ea2ad4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 18 Sep 2004 19:33:56 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1071 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/tcp_subr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index b6fbbfaf0..fd3f21a69 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -1253,7 +1253,7 @@ tcp_ctl(so) int command; struct ex_list *ex_ptr; int do_pty; - struct socket *tmpso; + // struct socket *tmpso; DEBUG_CALL("tcp_ctl"); DEBUG_ARG("so = %lx", (long )so); -- cgit v1.2.3 From 1d96905d761477826688e8bdb94373383539c36f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 18 Sep 2004 19:34:39 +0000 Subject: fixed stdio write git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1072 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 958a432f7..02edc7deb 100644 --- a/vl.c +++ b/vl.c @@ -1030,10 +1030,30 @@ typedef struct { static int stdio_nb_clients; static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; +static int unix_write(int fd, const uint8_t *buf, int len1) +{ + int ret, len; + + len = len1; + while (len > 0) { + ret = write(fd, buf, len); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) + return -1; + } else if (ret == 0) { + break; + } else { + buf += ret; + len -= ret; + } + } + return len1 - len; +} + static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { FDCharDriver *s = chr->opaque; - return write(s->fd_out, buf, len); + return unix_write(s->fd_out, buf, len); } static void fd_chr_add_read_handler(CharDriverState *chr, -- cgit v1.2.3 From 345fbaa3ca3e710dbcfdc7038c9c86b28353f830 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 18 Sep 2004 19:36:08 +0000 Subject: removed unused prototype git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1073 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index a2ac41900..7e684495d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3024,9 +3024,6 @@ void cpu_ppc_close(CPUPPCState *env) } /*****************************************************************************/ -int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, - int dialect); - int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) { -- cgit v1.2.3 From d5a8f07c52161a5d8021ace23029397475286eb2 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 29 Sep 2004 21:15:28 +0000 Subject: no data exec support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1074 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/exec.c b/exec.c index 9c86765f7..c33661bc4 100644 --- a/exec.c +++ b/exec.c @@ -18,6 +18,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" +#ifdef _WIN32 +#include +#else +#include +#endif #include #include #include @@ -25,9 +30,6 @@ #include #include #include -#if !defined(CONFIG_SOFTMMU) -#include -#endif #include "cpu.h" #include "exec-all.h" @@ -130,10 +132,33 @@ static void page_init(void) /* NOTE: we can always suppose that qemu_host_page_size >= TARGET_PAGE_SIZE */ #ifdef _WIN32 - qemu_real_host_page_size = 4096; + { + SYSTEM_INFO system_info; + DWORD old_protect; + + GetSystemInfo(&system_info); + qemu_real_host_page_size = system_info.dwPageSize; + + VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer), + PAGE_EXECUTE_READWRITE, &old_protect); + } #else qemu_real_host_page_size = getpagesize(); + { + unsigned long start, end; + + start = (unsigned long)code_gen_buffer; + start &= ~(qemu_real_host_page_size - 1); + + end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer); + end += qemu_real_host_page_size - 1; + end &= ~(qemu_real_host_page_size - 1); + + mprotect((void *)start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC); + } #endif + if (qemu_host_page_size == 0) qemu_host_page_size = qemu_real_host_page_size; if (qemu_host_page_size < TARGET_PAGE_SIZE) -- cgit v1.2.3 From 096b7ea42b5881de142781e86f06a6879cebd373 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 29 Sep 2004 21:19:16 +0000 Subject: win32 load_kernel() fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1075 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index f59ea2397..305ea1f5b 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -283,7 +283,7 @@ int load_kernel(const char *filename, uint8_t *addr, int fd, size; int setup_sects; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; -- cgit v1.2.3 From 3c56521b70ee2ee23c0df06e193147736d01b121 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 29 Sep 2004 21:29:14 +0000 Subject: cloop driver (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1076 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- Makefile.target | 2 +- block-cloop.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ block.c | 1 + qemu-img.c | 4 +- vl.h | 1 + 6 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 block-cloop.c diff --git a/Makefile b/Makefile index 17ee44980..f80db8be9 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1 $(MAKE) -C $$d $@ || exit 1 ; \ done -qemu-img: qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c +qemu-img: qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c diff --git a/Makefile.target b/Makefile.target index 5ac50dc09..28585c7e9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -241,7 +241,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o -VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o ifeq ($(TARGET_ARCH), i386) # Hardware support diff --git a/block-cloop.c b/block-cloop.c new file mode 100644 index 000000000..f22253daa --- /dev/null +++ b/block-cloop.c @@ -0,0 +1,167 @@ +/* + * QEMU System Emulator block driver + * + * 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 + +typedef struct BDRVCloopState { + int fd; + uint32_t block_size; + uint32_t n_blocks; + uint64_t* offsets; + uint32_t sectors_per_block; + uint32_t current_block; + char* compressed_block; + char* uncompressed_block; + z_stream zstream; +} BDRVCloopState; + +static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + const char* magic_version_2_0="#!/bin/sh\n" + "#V2.0 Format\n" + "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n"; + int length=strlen(magic_version_2_0); + if(length>buf_size) + length=buf_size; + if(!memcmp(magic_version_2_0,buf,length)) + return 2; + return 0; +} + +static int cloop_open(BlockDriverState *bs, const char *filename) +{ + BDRVCloopState *s = bs->opaque; + uint32_t offsets_size,max_compressed_block_size=1,i; + + s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (s->fd < 0) + return -1; + bs->read_only = 1; + + /* read header */ + if(lseek(s->fd,128,SEEK_SET)<0) { +cloop_close: + close(s->fd); + return -1; + } + if(read(s->fd,&s->block_size,4)<4) + goto cloop_close; + s->block_size=be32_to_cpu(s->block_size); + if(read(s->fd,&s->n_blocks,4)<4) + goto cloop_close; + s->n_blocks=be32_to_cpu(s->n_blocks); + + /* read offsets */ + offsets_size=s->n_blocks*sizeof(uint64_t); + if(!(s->offsets=(uint64_t*)malloc(offsets_size))) + goto cloop_close; + if(read(s->fd,s->offsets,offsets_size)n_blocks;i++) { + s->offsets[i]=be64_to_cpu(s->offsets[i]); + if(i>0) { + uint32_t size=s->offsets[i]-s->offsets[i-1]; + if(size>max_compressed_block_size) + max_compressed_block_size=size; + } + } + + /* initialize zlib engine */ + if(!(s->compressed_block=(char*)malloc(max_compressed_block_size+1))) + goto cloop_close; + if(!(s->uncompressed_block=(char*)malloc(s->block_size))) + goto cloop_close; + if(inflateInit(&s->zstream) != Z_OK) + goto cloop_close; + s->current_block=s->n_blocks; + + s->sectors_per_block = s->block_size/512; + bs->total_sectors = s->n_blocks*s->sectors_per_block; + return 0; +} + +static inline int cloop_read_block(BDRVCloopState *s,int block_num) +{ + if(s->current_block != block_num) { + int ret; + uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num]; + + lseek(s->fd, s->offsets[block_num], SEEK_SET); + ret = read(s->fd, s->compressed_block, bytes); + if (ret != bytes) + return -1; + + s->zstream.next_in = s->compressed_block; + s->zstream.avail_in = bytes; + s->zstream.next_out = s->uncompressed_block; + s->zstream.avail_out = s->block_size; + ret = inflateReset(&s->zstream); + if(ret != Z_OK) + return -1; + ret = inflate(&s->zstream, Z_FINISH); + if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size) + return -1; + + s->current_block = block_num; + } + return 0; +} + +static int cloop_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVCloopState *s = bs->opaque; + int i; + + for(i=0;isectors_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); + 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, +}; + + diff --git a/block.c b/block.c index 389617cb4..0e42b5e0d 100644 --- a/block.c +++ b/block.c @@ -596,4 +596,5 @@ void bdrv_init(void) #endif bdrv_register(&bdrv_qcow); bdrv_register(&bdrv_vmdk); + bdrv_register(&bdrv_cloop); } diff --git a/qemu-img.c b/qemu-img.c index 5f8362235..196e0287f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -374,7 +374,7 @@ static int img_create(int argc, char **argv) ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted); if (ret < 0) { if (ret == -ENOTSUP) { - error("Formatting or formatting option not suppored for file format '%s'", fmt); + error("Formatting or formatting option not supported for file format '%s'", fmt); } else { error("Error while formatting"); } @@ -534,7 +534,7 @@ static int img_convert(int argc, char **argv) ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt); if (ret < 0) { if (ret == -ENOTSUP) { - error("Formatting not suppored for file format '%s'", fmt); + error("Formatting not supported for file format '%s'", fmt); } else { error("Error while formatting '%s'", out_filename); } diff --git a/vl.h b/vl.h index a8a70af5d..4cfe9c005 100644 --- a/vl.h +++ b/vl.h @@ -354,6 +354,7 @@ extern BlockDriver bdrv_raw; extern BlockDriver bdrv_cow; extern BlockDriver bdrv_qcow; extern BlockDriver bdrv_vmdk; +extern BlockDriver bdrv_cloop; void bdrv_init(void); BlockDriver *bdrv_find_format(const char *format_name); -- cgit v1.2.3 From 28d34b82467c36c60395dbfc0e118537bc6b6963 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 29 Sep 2004 21:30:43 +0000 Subject: zlib.h is an external header git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1077 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-qcow.c b/block-qcow.c index 99c383295..a473298a8 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -23,7 +23,7 @@ */ #include "vl.h" #include "block_int.h" -#include "zlib.h" +#include #include "aes.h" /**************************************************************/ -- cgit v1.2.3 From 0ecf89aae327d545af6e10defd2315c97874cbd5 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 29 Sep 2004 21:55:52 +0000 Subject: level triggered IRQ fix (Steve Wormley) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1078 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/i8259.c b/hw/i8259.c index c21f0d306..221506b28 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -188,7 +188,9 @@ static inline void pic_intack(PicState *s, int irq) } else { s->isr |= (1 << irq); } - s->irr &= ~(1 << irq); + /* We don't clear a level sensitive interrupt here */ + if (!(s->elcr & (1 << irq))) + s->irr &= ~(1 << irq); } int cpu_get_pic_interrupt(CPUState *env) -- cgit v1.2.3 From 16c460b154e9cda4943106b0e7d260b6c483437b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 29 Sep 2004 21:56:51 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1079 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changelog b/Changelog index 430ef55c0..1e3f7256b 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,10 @@ version 0.6.1: - 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) version 0.6.0: -- cgit v1.2.3 From 4a4883b84ddc2bd8b438faf35e019f9a59b960c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 29 Sep 2004 22:47:43 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1080 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 09a3acfa1..7ceb04048 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.0 \ No newline at end of file +0.6.1 \ No newline at end of file -- cgit v1.2.3 From d981b88344e2c2b21683bea2af63a7bd519df21d Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Sep 2004 18:57:28 +0000 Subject: give a new address at DHCPREQUEST too (useful if the OS remembers its IP address git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1081 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/bootp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/slirp/bootp.c b/slirp/bootp.c index 30cb05e95..8ae68af46 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -150,6 +150,7 @@ static void bootp_reply(struct bootp_t *bp) memset(rbp, 0, sizeof(struct bootp_t)); if (dhcp_msg_type == DHCPDISCOVER) { + new_addr: bc = get_new_addr(&daddr.sin_addr); if (!bc) { dprintf("no address left\n"); @@ -159,8 +160,9 @@ static void bootp_reply(struct bootp_t *bp) } else { bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); if (!bc) { - dprintf("no address assigned\n"); - return; + /* if never assigned, behaves as if it was already + assigned (windows fix because it remembers its address) */ + goto new_addr; } } dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr)); -- cgit v1.2.3 From 525d67bcc81f34e5d9fe1ac89e9b065b891a1b97 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Sep 2004 18:58:48 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1082 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index 1e3f7256b..bf8efc5bd 100644 --- a/Changelog +++ b/Changelog @@ -14,6 +14,9 @@ version 0.6.1: - 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) version 0.6.0: -- cgit v1.2.3 From e8af50a30e89e5cfdc1b2a2fa8fab3ce463a4790 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Sep 2004 21:55:55 +0000 Subject: full system SPARC emulation (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1083 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 98 ++++++- target-sparc/exec.h | 90 +++++++ target-sparc/fop_template.h | 121 +++++++++ target-sparc/helper.c | 346 ++++++++++++++++++++++++ target-sparc/op.c | 417 +++++++++++++++++++++++++++-- target-sparc/op_helper.c | 135 ++++++++++ target-sparc/op_mem.h | 71 +++++ target-sparc/translate.c | 624 +++++++++++++++++++++++++++++++++++++++++--- 8 files changed, 1845 insertions(+), 57 deletions(-) create mode 100644 target-sparc/fop_template.h create mode 100644 target-sparc/helper.c create mode 100644 target-sparc/op_helper.c create mode 100644 target-sparc/op_mem.h diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e86fae9e7..ec9bba76a 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -9,8 +9,10 @@ /* trap definitions */ #define TT_ILL_INSN 0x02 +#define TT_PRIV_INSN 0x03 #define TT_WIN_OVF 0x05 #define TT_WIN_UNF 0x06 +#define TT_FP_EXCP 0x08 #define TT_DIV_ZERO 0x2a #define TT_TRAP 0x80 @@ -18,27 +20,101 @@ #define PSR_ZERO (1<<22) #define PSR_OVF (1<<21) #define PSR_CARRY (1<<20) +#define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY) +#define PSR_S (1<<7) +#define PSR_PS (1<<6) +#define PSR_ET (1<<5) +#define PSR_CWP 0x1f +/* Fake impl 0, version 4 */ +#define GET_PSR(env) ((0<<28) | (4<<24) | env->psr | (env->psrs? PSR_S : 0) | (env->psrs? PSR_PS : 0) |(env->psret? PSR_ET : 0) | env->cwp) + +/* Trap base register */ +#define TBR_BASE_MASK 0xfffff000 + +/* Fcc */ +#define FSR_RD1 (1<<31) +#define FSR_RD0 (1<<30) +#define FSR_RD_MASK (FSR_RD1 | FSR_RD0) +#define FSR_RD_NEAREST 0 +#define FSR_RD_ZERO FSR_RD0 +#define FSR_RD_POS FSR_RD1 +#define FSR_RD_NEG (FSR_RD1 | FSR_RD0) + +#define FSR_NVM (1<<27) +#define FSR_OFM (1<<26) +#define FSR_UFM (1<<25) +#define FSR_DZM (1<<24) +#define FSR_NXM (1<<23) +#define FSR_TEM_MASK (FSR_NVM | FSR_OFM | FSR_UFM | FSR_DZM | FSR_NXM) + +#define FSR_NVA (1<<9) +#define FSR_OFA (1<<8) +#define FSR_UFA (1<<7) +#define FSR_DZA (1<<6) +#define FSR_NXA (1<<5) +#define FSR_AEXC_MASK (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA) + +#define FSR_NVC (1<<4) +#define FSR_OFC (1<<3) +#define FSR_UFC (1<<2) +#define FSR_DZC (1<<1) +#define FSR_NXC (1<<0) +#define FSR_CEXC_MASK (FSR_NVC | FSR_OFC | FSR_UFC | FSR_DZC | FSR_NXC) + +#define FSR_FTT2 (1<<16) +#define FSR_FTT1 (1<<15) +#define FSR_FTT0 (1<<14) +#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) + +#define FSR_FCC1 (1<<11) +#define FSR_FCC0 (1<<10) + +/* MMU */ +#define MMU_E (1<<0) +#define MMU_NF (1<<1) + +#define PTE_ENTRYTYPE_MASK 3 +#define PTE_ACCESS_MASK 0x1c +#define PTE_ACCESS_SHIFT 2 +#define PTE_ADDR_MASK 0xffffff00 + +#define PG_ACCESSED_BIT 5 +#define PG_MODIFIED_BIT 6 +#define PG_CACHE_BIT 7 + +#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT) +#define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT) +#define PG_CACHE_MASK (1 << PG_CACHE_BIT) + +#define ACCESS_DATA 0 +#define ACCESS_CODE 1 +#define ACCESS_MMU 2 #define NWINDOWS 32 typedef struct CPUSPARCState { uint32_t gregs[8]; /* general registers */ uint32_t *regwptr; /* pointer to current register window */ - double *regfptr; /* floating point registers */ + float fpr[32]; /* floating point registers */ uint32_t pc; /* program counter */ uint32_t npc; /* next program counter */ - uint32_t sp; /* stack pointer */ uint32_t y; /* multiply/divide register */ uint32_t psr; /* processor state register */ + uint32_t fsr; /* FPU state register */ uint32_t T2; uint32_t cwp; /* index of current register window (extracted from PSR) */ uint32_t wim; /* window invalid mask */ + uint32_t tbr; /* trap base register */ + int psrs; /* supervisor mode (extracted from PSR) */ + int psrps; /* previous supervisor mode */ + int psret; /* enable traps */ jmp_buf jmp_env; int user_mode_only; int exception_index; int interrupt_index; int interrupt_request; + uint32_t exception_next_pc; struct TranslationBlock *current_tb; void *opaque; /* NOTE: we allow 8 more registers to handle wrapping */ @@ -51,6 +127,22 @@ typedef struct CPUSPARCState { written */ unsigned long mem_write_vaddr; /* target virtual addr at which the memory was written */ + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + int error_code; + int access_type; + /* MMU regs */ + uint32_t mmuregs[16]; + /* temporary float registers */ + float ft0, ft1, ft2; + double dt0, dt1, dt2; + + /* ice debug support */ + uint32_t breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; + int singlestep_enabled; /* XXX: should use CPU single step mode instead */ + } CPUSPARCState; CPUSPARCState *cpu_sparc_init(void); @@ -61,7 +153,7 @@ struct siginfo; int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags); -#define TARGET_PAGE_BITS 13 +#define TARGET_PAGE_BITS 12 /* 4k */ #include "cpu-all.h" #endif diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 6b49ca79a..f9fcf532a 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -6,6 +6,12 @@ register struct CPUSPARCState *env asm(AREG0); register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); register uint32_t T2 asm(AREG3); +#define FT0 (env->ft0) +#define FT1 (env->ft1) +#define FT2 (env->ft2) +#define DT0 (env->dt0) +#define DT1 (env->dt1) +#define DT2 (env->dt2) #include "cpu.h" #include "exec-all.h" @@ -14,4 +20,88 @@ void cpu_lock(void); void cpu_unlock(void); void cpu_loop_exit(void); void helper_flush(target_ulong addr); +void helper_ld_asi(int asi, int size, int sign); +void helper_st_asi(int asi, int size, int sign); +void helper_rett(void); +void helper_stfsr(void); +void set_cwp(int new_cwp); +void do_fabss(void); +void do_fsqrts(void); +void do_fsqrtd(void); +void do_fcmps(void); +void do_fcmpd(void); +void do_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip, int is_hw); +void raise_exception_err(int exception_index, int error_code); +void raise_exception(int tt); +void memcpy32(uint32_t *dst, const uint32_t *src); + +/* XXX: move that to a generic header */ +#if !defined(CONFIG_USER_ONLY) + +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel + +#define ACCESS_TYPE 0 +#define MEMSUFFIX _kernel +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ACCESS_TYPE 1 +#define MEMSUFFIX _user +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE 2 +#define MEMSUFFIX _data +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ldub(p) ldub_data(p) +#define ldsb(p) ldsb_data(p) +#define lduw(p) lduw_data(p) +#define ldsw(p) ldsw_data(p) +#define ldl(p) ldl_data(p) +#define ldq(p) ldq_data(p) + +#define stb(p, v) stb_data(p, v) +#define stw(p, v) stw_data(p, v) +#define stl(p, v) stl_data(p, v) +#define stq(p, v) stq_data(p, v) + +#endif /* !defined(CONFIG_USER_ONLY) */ #endif diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h new file mode 100644 index 000000000..2987b68d6 --- /dev/null +++ b/target-sparc/fop_template.h @@ -0,0 +1,121 @@ +/* + * SPARC micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* floating point registers moves */ +void OPPROTO glue(op_load_fpr_FT0_fpr, REGNAME)(void) +{ + FT0 = REG; +} + +void OPPROTO glue(op_store_FT0_fpr_fpr, REGNAME)(void) +{ + REG = FT0; +} + +void OPPROTO glue(op_load_fpr_FT1_fpr, REGNAME)(void) +{ + FT1 = REG; +} + +void OPPROTO glue(op_store_FT1_fpr_fpr, REGNAME)(void) +{ + REG = FT1; +} + +void OPPROTO glue(op_load_fpr_FT2_fpr, REGNAME)(void) +{ + FT2 = REG; +} + +void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void) +{ + REG = FT2; +} + +/* double floating point registers moves */ +#if 0 +#define CPU_DOUBLE_U_DEF +typedef union { + double d; + struct { + uint32_t lower; + uint32_t upper; + } l; + uint64_t ll; +} CPU_DoubleU; +#endif /* CPU_DOUBLE_U_DEF */ + +void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void) +{ + CPU_DoubleU u; + uint32_t *p = (uint32_t *)® + u.l.lower = *(p +1); + u.l.upper = *p; + DT0 = u.d; +} + +void OPPROTO glue(op_store_DT0_fpr_fpr, REGNAME)(void) +{ + CPU_DoubleU u; + uint32_t *p = (uint32_t *)® + u.d = DT0; + *(p +1) = u.l.lower; + *p = u.l.upper; +} + +void OPPROTO glue(op_load_fpr_DT1_fpr, REGNAME)(void) +{ + CPU_DoubleU u; + uint32_t *p = (uint32_t *)® + u.l.lower = *(p +1); + u.l.upper = *p; + DT1 = u.d; +} + +void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void) +{ + CPU_DoubleU u; + uint32_t *p = (uint32_t *)® + u.d = DT1; + *(p +1) = u.l.lower; + *p = u.l.upper; +} + +void OPPROTO glue(op_load_fpr_DT2_fpr, REGNAME)(void) +{ + CPU_DoubleU u; + uint32_t *p = (uint32_t *)® + u.l.lower = *(p +1); + u.l.upper = *p; + DT2 = u.d; +} + +void OPPROTO glue(op_store_DT2_fpr_fpr, REGNAME)(void) +{ + CPU_DoubleU u; + uint32_t *p = (uint32_t *)® + u.d = DT2; + *(p +1) = u.l.lower; + *p = u.l.upper; +} + +#undef REG +#undef REGNAME diff --git a/target-sparc/helper.c b/target-sparc/helper.c new file mode 100644 index 000000000..036720045 --- /dev/null +++ b/target-sparc/helper.c @@ -0,0 +1,346 @@ +/* + * sparc 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 + */ +#include "exec.h" + +#define DEBUG_PCALL + +#if 0 +#define raise_exception_err(a, b)\ +do {\ + fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ + (raise_exception_err)(a, b);\ +} while (0) +#endif + +/* Sparc MMU emulation */ +int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu); + + +/* thread support */ + +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void cpu_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void cpu_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + +#if 0 +void cpu_loop_exit(void) +{ + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ + longjmp(env->jmp_env, 1); +} +#endif + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + int ret; + unsigned long pc; + CPUState *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + + ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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, NULL); + } + } + raise_exception_err(ret, env->error_code); + } + env = saved_env; +} +#endif + +static const int access_table[8][8] = { + { 0, 0, 0, 0, 2, 0, 3, 3 }, + { 0, 0, 0, 0, 2, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 2, 3, 3 }, + { 2, 2, 0, 0, 0, 2, 0, 0 }, + { 2, 0, 2, 0, 2, 2, 3, 3 }, + { 2, 0, 2, 0, 2, 0, 2, 0 }, + { 2, 2, 2, 0, 2, 2, 3, 3 }, + { 2, 2, 2, 0, 2, 2, 2, 0 } +}; + +/* 1 = write OK */ +static const int rw_table[2][8] = { + { 0, 1, 0, 1, 0, 1, 0, 1 }, + { 0, 1, 0, 1, 0, 0, 0, 0 } +}; + + +/* Perform address translation */ +int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu) +{ + int exception = 0; + int access_type, access_perms = 0, access_index = 0; + uint8_t *pde_ptr; + uint32_t pde, virt_addr; + int error_code = 0, is_dirty, prot, ret = 0; + unsigned long paddr, vaddr, page_offset; + + access_type = env->access_type; + if (env->user_mode_only) { + /* user mode only emulation */ + ret = -2; + goto do_fault; + } + + virt_addr = address & TARGET_PAGE_MASK; + if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ + paddr = address; + page_offset = address & (TARGET_PAGE_SIZE - 1); + prot = PAGE_READ | PAGE_WRITE; + goto do_mapping; + } + + /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ + /* Context base + context number */ + pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + env->access_type = ACCESS_MMU; + pde = ldl_raw(pde_ptr); + + /* Ctx pde */ + switch (pde & PTE_ENTRYTYPE_MASK) { + case 0: /* Invalid */ + error_code = 1; + goto do_fault; + case 2: /* PTE, maybe should not happen? */ + case 3: /* Reserved */ + error_code = 4; + goto do_fault; + case 1: /* L1 PDE */ + pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4); + pde = ldl_raw(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + case 0: /* Invalid */ + error_code = 1; + goto do_fault; + case 3: /* Reserved */ + error_code = 4; + goto do_fault; + case 1: /* L2 PDE */ + pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + pde = ldl_raw(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + case 0: /* Invalid */ + error_code = 1; + goto do_fault; + case 3: /* Reserved */ + error_code = 4; + goto do_fault; + case 1: /* L3 PDE */ + pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + pde = ldl_raw(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + case 0: /* Invalid */ + error_code = 1; + goto do_fault; + case 1: /* PDE, should not happen */ + case 3: /* Reserved */ + error_code = 4; + goto do_fault; + case 2: /* L3 PTE */ + virt_addr = address & TARGET_PAGE_MASK; + page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1); + } + break; + case 2: /* L2 PTE */ + virt_addr = address & ~0x3ffff; + page_offset = address & 0x3ffff; + } + break; + case 2: /* L1 PTE */ + virt_addr = address & ~0xffffff; + page_offset = address & 0xffffff; + } + } + + /* update page modified and dirty bits */ + is_dirty = rw && !(pde & PG_MODIFIED_MASK); + if (!(pde & PG_ACCESSED_MASK) || is_dirty) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_MODIFIED_MASK; + stl_raw(pde_ptr, pde); + } + + /* check access */ + access_index = (rw << 2) | ((access_type == ACCESS_CODE)? 2 : 0) | (is_user? 0 : 1); + access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; + error_code = access_table[access_index][access_perms]; + if (error_code) + goto do_fault; + + /* the page can be put in the TLB */ + prot = PAGE_READ; + if (pde & PG_MODIFIED_MASK) { + /* only set write access if already dirty... otherwise wait + for dirty access */ + if (rw_table[is_user][access_perms]) + prot |= PAGE_WRITE; + } + + /* Even if large ptes, we map only one 4KB page in the cache to + avoid filling it too fast */ + virt_addr = address & TARGET_PAGE_MASK; + paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset; + + do_mapping: + env->access_type = access_type; + vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + + ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + return ret; + + do_fault: + env->access_type = access_type; + if (env->mmuregs[3]) /* Fault status register */ + env->mmuregs[3] = 1; /* overflow (not read before another fault) */ + env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2; + env->mmuregs[4] = address; /* Fault address register */ + + if (env->mmuregs[0] & MMU_NF) // No fault + return 0; + + env->exception_index = exception; + env->error_code = error_code; + return error_code; +} + +void memcpy32(uint32_t *dst, const uint32_t *src) +{ + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} + +void set_cwp(int new_cwp) +{ + /* put the modified wrap registers at their proper location */ + if (env->cwp == (NWINDOWS - 1)) + memcpy32(env->regbase, env->regbase + NWINDOWS * 16); + env->cwp = new_cwp; + /* put the wrap registers at their temporary location */ + if (new_cwp == (NWINDOWS - 1)) + memcpy32(env->regbase + NWINDOWS * 16, env->regbase); + env->regwptr = env->regbase + (new_cwp * 16); +} + +/* + * Begin execution of an interruption. is_int is TRUE if coming from + * the int instruction. next_eip is the EIP value AFTER the interrupt + * instruction. It is only relevant if is_int is TRUE. + */ +void do_interrupt(int intno, int is_int, int error_code, + unsigned int next_eip, int is_hw) +{ + int cwp; + +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_INT) { + static int count; + fprintf(logfile, "%6d: v=%02x e=%04x i=%d pc=%08x npc=%08x SP=%08x\n", + count, intno, error_code, is_int, + env->pc, + env->npc, env->gregs[7]); +#if 0 + cpu_sparc_dump_state(env, logfile, 0); + { + int i; + uint8_t *ptr; + fprintf(logfile, " code="); + ptr = env->pc; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } +#endif + count++; + } +#endif + env->psret = 0; + cwp = (env->cwp - 1) & (NWINDOWS - 1); + set_cwp(cwp); + env->regwptr[9] = env->pc; + env->regwptr[10] = env->npc; + env->psrps = env->psrs; + env->psrs = 1; + env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = 0; +} + +void raise_exception_err(int exception_index, int error_code) +{ + raise_exception(exception_index); +} diff --git a/target-sparc/op.c b/target-sparc/op.c index e2ef7ae7c..a2d37469d 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -117,9 +117,108 @@ #define REGNAME o7 #define REG (env->regwptr[7]) #include "op_template.h" + +#define REGNAME f0 +#define REG (env->fpr[0]) +#include "fop_template.h" +#define REGNAME f1 +#define REG (env->fpr[1]) +#include "fop_template.h" +#define REGNAME f2 +#define REG (env->fpr[2]) +#include "fop_template.h" +#define REGNAME f3 +#define REG (env->fpr[3]) +#include "fop_template.h" +#define REGNAME f4 +#define REG (env->fpr[4]) +#include "fop_template.h" +#define REGNAME f5 +#define REG (env->fpr[5]) +#include "fop_template.h" +#define REGNAME f6 +#define REG (env->fpr[6]) +#include "fop_template.h" +#define REGNAME f7 +#define REG (env->fpr[7]) +#include "fop_template.h" +#define REGNAME f8 +#define REG (env->fpr[8]) +#include "fop_template.h" +#define REGNAME f9 +#define REG (env->fpr[9]) +#include "fop_template.h" +#define REGNAME f10 +#define REG (env->fpr[10]) +#include "fop_template.h" +#define REGNAME f11 +#define REG (env->fpr[11]) +#include "fop_template.h" +#define REGNAME f12 +#define REG (env->fpr[12]) +#include "fop_template.h" +#define REGNAME f13 +#define REG (env->fpr[13]) +#include "fop_template.h" +#define REGNAME f14 +#define REG (env->fpr[14]) +#include "fop_template.h" +#define REGNAME f15 +#define REG (env->fpr[15]) +#include "fop_template.h" +#define REGNAME f16 +#define REG (env->fpr[16]) +#include "fop_template.h" +#define REGNAME f17 +#define REG (env->fpr[17]) +#include "fop_template.h" +#define REGNAME f18 +#define REG (env->fpr[18]) +#include "fop_template.h" +#define REGNAME f19 +#define REG (env->fpr[19]) +#include "fop_template.h" +#define REGNAME f20 +#define REG (env->fpr[20]) +#include "fop_template.h" +#define REGNAME f21 +#define REG (env->fpr[21]) +#include "fop_template.h" +#define REGNAME f22 +#define REG (env->fpr[22]) +#include "fop_template.h" +#define REGNAME f23 +#define REG (env->fpr[23]) +#include "fop_template.h" +#define REGNAME f24 +#define REG (env->fpr[24]) +#include "fop_template.h" +#define REGNAME f25 +#define REG (env->fpr[25]) +#include "fop_template.h" +#define REGNAME f26 +#define REG (env->fpr[26]) +#include "fop_template.h" +#define REGNAME f27 +#define REG (env->fpr[27]) +#include "fop_template.h" +#define REGNAME f28 +#define REG (env->fpr[28]) +#include "fop_template.h" +#define REGNAME f29 +#define REG (env->fpr[29]) +#include "fop_template.h" +#define REGNAME f30 +#define REG (env->fpr[30]) +#include "fop_template.h" +#define REGNAME f31 +#define REG (env->fpr[31]) +#include "fop_template.h" + #define EIP (env->pc) #define FLAG_SET(x) (env->psr&x)?1:0 +#define FFLAG_SET(x) ((env->fsr&x)?1:0) void OPPROTO op_movl_T0_0(void) { @@ -375,6 +474,7 @@ void OPPROTO op_sra(void) T0 = ((int32_t) T0) >> T1; } +#if 0 void OPPROTO op_st(void) { stl((void *) T0, T1); @@ -440,6 +540,51 @@ void OPPROTO op_ldd(void) T0 = ldl((void *) (T0 + 4)); } +void OPPROTO op_stf(void) +{ + stfl((void *) T0, FT0); +} + +void OPPROTO op_stdf(void) +{ + stfq((void *) T0, DT0); +} + +void OPPROTO op_ldf(void) +{ + FT0 = ldfl((void *) T0); +} + +void OPPROTO op_lddf(void) +{ + DT0 = ldfq((void *) T0); +} +#else +/* Load and store */ +#define MEMSUFFIX _raw +#include "op_mem.h" +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_mem.h" + +#define MEMSUFFIX _kernel +#include "op_mem.h" +#endif +#endif + +void OPPROTO op_ldfsr(void) +{ + env->fsr = *((uint32_t *) &FT0); + FORCE_RET(); +} + +void OPPROTO op_stfsr(void) +{ + *((uint32_t *) &FT0) = env->fsr; + helper_stfsr(); + FORCE_RET(); +} + void OPPROTO op_wry(void) { env->y = T0; @@ -450,36 +595,56 @@ void OPPROTO op_rdy(void) T0 = env->y; } -void raise_exception(int tt) +void OPPROTO op_rdwim(void) { - env->exception_index = tt; - cpu_loop_exit(); -} + T0 = env->wim; +} + +void OPPROTO op_wrwim(void) +{ + env->wim = T0; + FORCE_RET(); +} + +void OPPROTO op_rdpsr(void) +{ + T0 = GET_PSR(env); + FORCE_RET(); +} + +void OPPROTO op_wrpsr(void) +{ + env->psr = T0 & ~PSR_ICC; + env->psrs = (T0 & PSR_S)? 1 : 0; + env->psrps = (T0 & PSR_PS)? 1 : 0; + env->psret = (T0 & PSR_ET)? 1 : 0; + env->cwp = (T0 & PSR_CWP); + FORCE_RET(); +} + +void OPPROTO op_rdtbr(void) +{ + T0 = env->tbr; +} -void memcpy32(uint32_t *dst, const uint32_t *src) +void OPPROTO op_wrtbr(void) { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = src[3]; - dst[4] = src[4]; - dst[5] = src[5]; - dst[6] = src[6]; - dst[7] = src[7]; + env->tbr = T0; + FORCE_RET(); } -static inline void set_cwp(int new_cwp) +void OPPROTO op_rett(void) { - /* put the modified wrap registers at their proper location */ - if (env->cwp == (NWINDOWS - 1)) - memcpy32(env->regbase, env->regbase + NWINDOWS * 16); - env->cwp = new_cwp; - /* put the wrap registers at their temporary location */ - if (new_cwp == (NWINDOWS - 1)) - memcpy32(env->regbase + NWINDOWS * 16, env->regbase); - env->regwptr = env->regbase + (new_cwp * 16); + helper_rett(); + FORCE_RET(); } +void raise_exception(int tt) +{ + env->exception_index = tt; + cpu_loop_exit(); +} + /* XXX: use another pointer for %iN registers to avoid slow wrapping handling ? */ void OPPROTO op_save(void) @@ -525,6 +690,12 @@ void OPPROTO op_trapcc_T0(void) FORCE_RET(); } +void OPPROTO op_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + void OPPROTO op_exit_tb(void) { EXIT_TB(); @@ -612,6 +783,92 @@ void OPPROTO op_eval_bvc(void) T2 = !(env->psr & PSR_OVF); } +/* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */ + +void OPPROTO op_eval_fbne(void) +{ +// !0 + T2 = (env->fsr & (FSR_FCC1 | FSR_FCC0)); /* L or G or U */ +} + +void OPPROTO op_eval_fblg(void) +{ +// 1 or 2 + T2 = FFLAG_SET(FSR_FCC0) ^ FFLAG_SET(FSR_FCC1); +} + +void OPPROTO op_eval_fbul(void) +{ +// 1 or 3 + T2 = FFLAG_SET(FSR_FCC0); +} + +void OPPROTO op_eval_fbl(void) +{ +// 1 + T2 = FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); +} + +void OPPROTO op_eval_fbug(void) +{ +// 2 or 3 + T2 = FFLAG_SET(FSR_FCC1); +} + +void OPPROTO op_eval_fbg(void) +{ +// 2 + T2 = !FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); +} + +void OPPROTO op_eval_fbu(void) +{ +// 3 + T2 = FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); +} + +void OPPROTO op_eval_fbe(void) +{ +// 0 + T2 = !FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); +} + +void OPPROTO op_eval_fbue(void) +{ +// 0 or 3 + T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0)); +} + +void OPPROTO op_eval_fbge(void) +{ +// 0 or 2 + T2 = !FFLAG_SET(FSR_FCC0); +} + +void OPPROTO op_eval_fbuge(void) +{ +// !1 + T2 = !(FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1)); +} + +void OPPROTO op_eval_fble(void) +{ +// 0 or 1 + T2 = !FFLAG_SET(FSR_FCC1); +} + +void OPPROTO op_eval_fbule(void) +{ +// !2 + T2 = !(!FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); +} + +void OPPROTO op_eval_fbo(void) +{ +// !3 + T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); +} + void OPPROTO op_movl_T2_0(void) { T2 = 0; @@ -687,3 +944,119 @@ void OPPROTO op_flush_T0(void) { helper_flush(T0); } + +void OPPROTO op_fnegs(void) +{ + FT0 = -FT1; +} + +void OPPROTO op_fabss(void) +{ + do_fabss(); +} + +void OPPROTO op_fsqrts(void) +{ + do_fsqrts(); +} + +void OPPROTO op_fsqrtd(void) +{ + do_fsqrtd(); +} + +void OPPROTO op_fmuls(void) +{ + FT0 *= FT1; +} + +void OPPROTO op_fmuld(void) +{ + DT0 *= DT1; +} + +void OPPROTO op_fsmuld(void) +{ + DT0 = FT0 * FT1; +} + +void OPPROTO op_fadds(void) +{ + FT0 += FT1; +} + +void OPPROTO op_faddd(void) +{ + DT0 += DT1; +} + +void OPPROTO op_fsubs(void) +{ + FT0 -= FT1; +} + +void OPPROTO op_fsubd(void) +{ + DT0 -= DT1; +} + +void OPPROTO op_fdivs(void) +{ + FT0 /= FT1; +} + +void OPPROTO op_fdivd(void) +{ + DT0 /= DT1; +} + +void OPPROTO op_fcmps(void) +{ + do_fcmps(); +} + +void OPPROTO op_fcmpd(void) +{ + do_fcmpd(); +} + +void OPPROTO op_fitos(void) +{ + FT0 = (float) *((int32_t *)&FT1); +} + +void OPPROTO op_fdtos(void) +{ + FT0 = (float) DT1; +} + +void OPPROTO op_fitod(void) +{ + DT0 = (double) *((int32_t *)&FT1); +} + +void OPPROTO op_fstod(void) +{ + DT0 = (double) FT1; +} + +void OPPROTO op_fstoi(void) +{ + *((int32_t *)&FT0) = (int32_t) FT1; +} + +void OPPROTO op_fdtoi(void) +{ + *((int32_t *)&FT0) = (int32_t) DT1; +} + +void OPPROTO op_ld_asi() +{ + helper_ld_asi(PARAM1, PARAM2, PARAM3); +} + +void OPPROTO op_st_asi() +{ + helper_st_asi(PARAM1, PARAM2, PARAM3); +} + diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c new file mode 100644 index 000000000..253bcff6f --- /dev/null +++ b/target-sparc/op_helper.c @@ -0,0 +1,135 @@ +#include +#include +#include "exec.h" + +void OPPROTO do_fabss(void) +{ + FT0 = fabsf(FT1); +} + +void OPPROTO do_fsqrts(void) +{ + FT0 = sqrtf(FT1); +} + +void OPPROTO do_fsqrtd(void) +{ + DT0 = sqrt(DT1); +} + +void OPPROTO do_fcmps (void) +{ + if (isnan(FT0) || isnan(FT1)) { + T0 = FSR_FCC1 | FSR_FCC0; + } else if (FT0 < FT1) { + T0 = FSR_FCC0; + } else if (FT0 > FT1) { + T0 = FSR_FCC1; + } else { + T0 = 0; + } + env->fsr = T0; +} + +void OPPROTO do_fcmpd (void) +{ + if (isnan(DT0) || isnan(DT1)) { + T0 = FSR_FCC1 | FSR_FCC0; + } else if (DT0 < DT1) { + T0 = FSR_FCC0; + } else if (DT0 > DT1) { + T0 = FSR_FCC1; + } else { + T0 = 0; + } + env->fsr = T0; +} + +void OPPROTO helper_ld_asi(int asi, int size, int sign) +{ + switch(asi) { + case 3: /* MMU probe */ + T1 = 0; + return; + case 4: /* read MMU regs */ + { + int temp, reg = (T0 >> 8) & 0xf; + + temp = env->mmuregs[reg]; + if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/ + env->mmuregs[reg] = 0; + T1 = temp; + } + return; + case 0x20 ... 0x2f: /* MMU passthrough */ + { + int temp; + + cpu_physical_memory_read(T0, (void *) &temp, size); + bswap32s(&temp); + T1 = temp; + } + return; + default: + T1 = 0; + return; + } +} + +void OPPROTO helper_st_asi(int asi, int size, int sign) +{ + switch(asi) { + case 3: /* MMU flush */ + return; + case 4: /* write MMU regs */ + { + int reg = (T0 >> 8) & 0xf; + if (reg == 0) { + env->mmuregs[reg] &= ~(MMU_E | MMU_NF); + env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); + } else + env->mmuregs[reg] = T1; + return; + } + case 0x20 ... 0x2f: /* MMU passthrough */ + { + int temp = T1; + + bswap32s(&temp); + cpu_physical_memory_write(T0, (void *) &temp, size); + } + return; + default: + return; + } +} + +void OPPROTO helper_rett() +{ + int cwp; + env->psret = 1; + cwp = (env->cwp + 1) & (NWINDOWS - 1); + if (env->wim & (1 << cwp)) { + raise_exception(TT_WIN_UNF); + } + set_cwp(cwp); + env->psrs = env->psrps; +} + +void helper_stfsr(void) +{ + switch (env->fsr & FSR_RD_MASK) { + case FSR_RD_NEAREST: + fesetround(FE_TONEAREST); + break; + case FSR_RD_ZERO: + fesetround(FE_TOWARDZERO); + break; + case FSR_RD_POS: + fesetround(FE_UPWARD); + break; + case FSR_RD_NEG: + fesetround(FE_DOWNWARD); + break; + } +} diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h new file mode 100644 index 000000000..9c839a004 --- /dev/null +++ b/target-sparc/op_mem.h @@ -0,0 +1,71 @@ +/*** Integer load ***/ +#define SPARC_LD_OP(name, qp) \ +void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ +{ \ + T1 = glue(qp, MEMSUFFIX)((void *)T0); \ +} + +#define SPARC_ST_OP(name, op) \ +void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ +{ \ + glue(op, MEMSUFFIX)((void *)T0, T1); \ +} + +SPARC_LD_OP(ld, ldl); +SPARC_LD_OP(ldub, ldub); +SPARC_LD_OP(lduh, lduw); +SPARC_LD_OP(ldsb, ldsb); +SPARC_LD_OP(ldsh, ldsw); + +/*** Integer store ***/ +SPARC_ST_OP(st, stl); +SPARC_ST_OP(stb, stb); +SPARC_ST_OP(sth, stw); + +void OPPROTO glue(op_std, MEMSUFFIX)(void) +{ + glue(stl, MEMSUFFIX)((void *) T0, T1); + glue(stl, MEMSUFFIX)((void *) (T0 + 4), T2); +} + +void OPPROTO glue(op_ldstub, MEMSUFFIX)(void) +{ + T1 = glue(ldub, MEMSUFFIX)((void *) T0); + glue(stb, MEMSUFFIX)((void *) T0, 0xff); /* XXX: Should be Atomically */ +} + +void OPPROTO glue(op_swap, MEMSUFFIX)(void) +{ + unsigned int tmp = glue(ldl, MEMSUFFIX)((void *) T0); + glue(stl, MEMSUFFIX)((void *) T0, T1); /* XXX: Should be Atomically */ + T1 = tmp; +} + +void OPPROTO glue(op_ldd, MEMSUFFIX)(void) +{ + T1 = glue(ldl, MEMSUFFIX)((void *) T0); + T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4)); +} + +/*** Floating-point store ***/ +void OPPROTO glue(op_stf, MEMSUFFIX) (void) +{ + glue(stfl, MEMSUFFIX)((void *) T0, FT0); +} + +void OPPROTO glue(op_stdf, MEMSUFFIX) (void) +{ + glue(stfq, MEMSUFFIX)((void *) T0, DT0); +} + +/*** Floating-point load ***/ +void OPPROTO glue(op_ldf, MEMSUFFIX) (void) +{ + FT0 = glue(ldfl, MEMSUFFIX)((void *) T0); +} + +void OPPROTO glue(op_lddf, MEMSUFFIX) (void) +{ + DT0 = glue(ldfq, MEMSUFFIX)((void *) T0); +} +#undef MEMSUFFIX diff --git a/target-sparc/translate.c b/target-sparc/translate.c index fe37c0748..852507ab1 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -51,6 +51,7 @@ typedef struct DisasContext { target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ int is_br; + int mem_idx; struct TranslationBlock *tb; } DisasContext; @@ -257,6 +258,96 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] = { gen_op_movl_T2_im }; +#define GEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} + +/* floating point registers moves */ +GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fprf); +GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fprf); +GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fprf); +GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fprf); +GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fprf); +GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fprf); + +GEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fprf); +GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); +GEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fprf); +GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); +GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); +GEN32(gen_op_store_DT2_fpr, gen_op_store_DT2_fpr_fprf); + +#if defined(CONFIG_USER_ONLY) +#define gen_op_ldst(name) gen_op_##name##_raw() +#define OP_LD_TABLE(width) +#define supervisor(dc) 0 +#else +#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_##width[] = { \ + &gen_op_##width##_user, \ + &gen_op_##width##_kernel, \ +}; \ + \ +static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ +{ \ + int asi; \ + \ + asi = GET_FIELD(insn, 19, 26); \ + switch (asi) { \ + case 10: /* User data access */ \ + gen_op_##width##_user(); \ + break; \ + case 11: /* Supervisor data access */ \ + gen_op_##width##_kernel(); \ + break; \ + case 0x20 ... 0x2f: /* MMU passthrough */ \ + if (is_ld) \ + gen_op_ld_asi(asi, size, sign); \ + else \ + gen_op_st_asi(asi, size, sign); \ + break; \ + default: \ + if (is_ld) \ + gen_op_ld_asi(asi, size, sign); \ + else \ + gen_op_st_asi(asi, size, sign); \ + break; \ + } \ +} + +#define supervisor(dc) (dc->mem_idx == 1) +#endif + +OP_LD_TABLE(ld); +OP_LD_TABLE(st); +OP_LD_TABLE(ldub); +OP_LD_TABLE(lduh); +OP_LD_TABLE(ldsb); +OP_LD_TABLE(ldsh); +OP_LD_TABLE(stb); +OP_LD_TABLE(sth); +OP_LD_TABLE(std); +OP_LD_TABLE(ldstub); +OP_LD_TABLE(swap); +OP_LD_TABLE(ldd); +OP_LD_TABLE(stf); +OP_LD_TABLE(stdf); +OP_LD_TABLE(ldf); +OP_LD_TABLE(lddf); + static inline void gen_movl_imm_TN(int reg, int imm) { gen_op_movl_TN_im[reg] (imm); @@ -391,6 +482,60 @@ static void gen_cond(int cond) } } +static void gen_fcond(int cond) +{ + switch (cond) { + case 0x0: + gen_op_movl_T2_0(); + break; + case 0x1: + gen_op_eval_fbne(); + break; + case 0x2: + gen_op_eval_fblg(); + break; + case 0x3: + gen_op_eval_fbul(); + break; + case 0x4: + gen_op_eval_fbl(); + break; + case 0x5: + gen_op_eval_fbug(); + break; + case 0x6: + gen_op_eval_fbg(); + break; + case 0x7: + gen_op_eval_fbu(); + break; + case 0x8: + gen_op_movl_T2_1(); + break; + case 0x9: + gen_op_eval_fbe(); + break; + case 0xa: + gen_op_eval_fbue(); + break; + case 0xb: + gen_op_eval_fbge(); + break; + case 0xc: + gen_op_eval_fbuge(); + break; + case 0xd: + gen_op_eval_fble(); + break; + case 0xe: + gen_op_eval_fbule(); + break; + default: + case 0xf: + gen_op_eval_fbo(); + break; + } +} static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) { @@ -429,6 +574,50 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) } } +static void do_fbranch(DisasContext * dc, uint32_t target, uint32_t insn) +{ + unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); + target += (uint32_t) dc->pc; + if (cond == 0x0) { + /* unconditional not taken */ + if (a) { + dc->pc = dc->npc + 4; + dc->npc = dc->pc + 4; + } else { + dc->pc = dc->npc; + dc->npc = dc->pc + 4; + } + } else if (cond == 0x8) { + /* unconditional taken */ + if (a) { + dc->pc = target; + dc->npc = dc->pc + 4; + } else { + dc->pc = dc->npc; + dc->npc = target; + } + } else { + flush_T2(dc); + gen_fcond(cond); + if (a) { + gen_op_branch_a((long)dc->tb, target, dc->npc); + dc->is_br = 1; + } else { + dc->pc = dc->npc; + dc->jump_pc[0] = target; + dc->jump_pc[1] = dc->npc + 4; + dc->npc = JUMP_PC; + } + } +} + +static void gen_debug(DisasContext *s, uint32_t pc) +{ + gen_op_jmp_im(pc); + gen_op_debug(); + s->is_br = 1; +} + #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) static int sign_extend(int x, int len) @@ -454,6 +643,7 @@ static void disas_sparc_insn(DisasContext * dc) switch (xop) { case 0x0: case 0x1: /* UNIMPL */ + default: goto illegal_insn; case 0x2: /* BN+x */ { @@ -462,8 +652,13 @@ static void disas_sparc_insn(DisasContext * dc) do_branch(dc, target, insn); goto jmp_insn; } - case 0x3: /* FBN+x */ - break; + case 0x6: /* FBN+x */ + { + target <<= 2; + target = sign_extend(target, 22); + do_fbranch(dc, target, insn); + goto jmp_insn; + } case 0x4: /* SETHI */ gen_movl_imm_T0(target << 10); gen_movl_T0_reg(rd); @@ -492,12 +687,16 @@ static void disas_sparc_insn(DisasContext * dc) rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); if (IS_IMM) { - gen_movl_imm_T1(GET_FIELD(insn, 25, 31)); + rs2 = GET_FIELD(insn, 25, 31); + if (rs2 != 0) { + gen_movl_imm_T1(rs2); + gen_op_add_T1_T0(); + } } else { rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); } - gen_op_add_T1_T0(); save_state(dc); cond = GET_FIELD(insn, 3, 6); if (cond == 0x8) { @@ -514,11 +713,167 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_rdy(); gen_movl_T0_reg(rd); break; + case 15: /* stbar */ + break; /* no effect? */ default: goto illegal_insn; } +#if !defined(CONFIG_USER_ONLY) + } else if (xop == 0x29) { + if (!supervisor(dc)) + goto priv_insn; + gen_op_rdpsr(); + gen_movl_T0_reg(rd); + break; + } else if (xop == 0x2a) { + if (!supervisor(dc)) + goto priv_insn; + gen_op_rdwim(); + gen_movl_T0_reg(rd); + break; + } else if (xop == 0x2b) { + if (!supervisor(dc)) + goto priv_insn; + gen_op_rdtbr(); + gen_movl_T0_reg(rd); + break; +#endif } else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ - goto illegal_insn; + rs1 = GET_FIELD(insn, 13, 17); + rs2 = GET_FIELD(insn, 27, 31); + xop = GET_FIELD(insn, 18, 26); + switch (xop) { + case 0x1: /* fmovs */ + gen_op_load_fpr_FT0(rs2); + gen_op_store_FT0_fpr(rd); + break; + case 0x5: /* fnegs */ + gen_op_load_fpr_FT1(rs2); + gen_op_fnegs(); + gen_op_store_FT0_fpr(rd); + break; + case 0x9: /* fabss */ + gen_op_load_fpr_FT1(rs2); + gen_op_fabss(); + gen_op_store_FT0_fpr(rd); + break; + case 0x29: /* fsqrts */ + gen_op_load_fpr_FT1(rs2); + gen_op_fsqrts(); + gen_op_store_FT0_fpr(rd); + break; + case 0x2a: /* fsqrtd */ + gen_op_load_fpr_DT1(rs2); + gen_op_fsqrtd(); + gen_op_store_DT0_fpr(rd); + break; + case 0x41: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fadds(); + gen_op_store_FT0_fpr(rd); + break; + case 0x42: + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_faddd(); + gen_op_store_DT0_fpr(rd); + break; + case 0x45: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fsubs(); + gen_op_store_FT0_fpr(rd); + break; + case 0x46: + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fsubd(); + gen_op_store_DT0_fpr(rd); + break; + case 0x49: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fmuls(); + gen_op_store_FT0_fpr(rd); + break; + case 0x4a: + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fmuld(); + gen_op_store_DT0_fpr(rd); + break; + case 0x4d: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fdivs(); + gen_op_store_FT0_fpr(rd); + break; + case 0x4e: + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fdivd(); + gen_op_store_DT0_fpr(rd); + break; + case 0x51: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fcmps(); + break; + case 0x52: + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpd(); + break; + case 0x55: /* fcmpes */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fcmps(); /* XXX */ + break; + case 0x56: /* fcmped */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpd(); /* XXX */ + break; + case 0x69: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fsmuld(); + gen_op_store_DT0_fpr(rd); + break; + case 0xc4: + gen_op_load_fpr_FT1(rs2); + gen_op_fitos(); + gen_op_store_FT0_fpr(rd); + break; + case 0xc6: + gen_op_load_fpr_DT1(rs2); + gen_op_fdtos(); + gen_op_store_FT0_fpr(rd); + break; + case 0xc8: + gen_op_load_fpr_FT1(rs2); + gen_op_fitod(); + gen_op_store_DT0_fpr(rd); + break; + case 0xc9: + gen_op_load_fpr_FT1(rs2); + gen_op_fstod(); + gen_op_store_DT0_fpr(rd); + break; + case 0xd1: + gen_op_load_fpr_FT1(rs2); + gen_op_fstoi(); + gen_op_store_FT0_fpr(rd); + break; + case 0xd2: + gen_op_load_fpr_DT1(rs2); + gen_op_fdtoi(); + gen_op_store_FT0_fpr(rd); + break; + default: + goto illegal_insn; + } } else { rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); @@ -637,6 +992,32 @@ static void disas_sparc_insn(DisasContext * dc) } } break; +#if !defined(CONFIG_USER_ONLY) + case 0x31: + { + if (!supervisor(dc)) + goto priv_insn; + gen_op_xor_T1_T0(); + gen_op_wrpsr(); + } + break; + case 0x32: + { + if (!supervisor(dc)) + goto priv_insn; + gen_op_xor_T1_T0(); + gen_op_wrwim(); + } + break; + case 0x33: + { + if (!supervisor(dc)) + goto priv_insn; + gen_op_xor_T1_T0(); + gen_op_wrtbr(); + } + break; +#endif case 0x38: /* jmpl */ { gen_op_add_T1_T0(); @@ -649,6 +1030,24 @@ static void disas_sparc_insn(DisasContext * dc) dc->npc = DYNAMIC_PC; } goto jmp_insn; +#if !defined(CONFIG_USER_ONLY) + case 0x39: /* rett */ + { + if (!supervisor(dc)) + goto priv_insn; + gen_op_add_T1_T0(); + gen_op_movl_npc_T0(); + gen_op_rett(); +#if 0 + dc->pc = dc->npc; + dc->npc = DYNAMIC_PC; +#endif + } +#if 0 + goto jmp_insn; +#endif + break; +#endif case 0x3b: /* flush */ gen_op_add_T1_T0(); gen_op_flush_T0(); @@ -679,60 +1078,157 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); - gen_movl_imm_T1(rs2); + if (rs2 != 0) { + gen_movl_imm_T1(rs2); + gen_op_add_T1_T0(); + } } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); } - gen_op_add_T1_T0(); - if (xop < 4 || xop > 7) { + if (xop < 4 || (xop > 7 && xop < 0x14) || \ + (xop > 0x17 && xop < 0x20)) { switch (xop) { case 0x0: /* load word */ - gen_op_ld(); + gen_op_ldst(ld); break; case 0x1: /* load unsigned byte */ - gen_op_ldub(); + gen_op_ldst(ldub); break; case 0x2: /* load unsigned halfword */ - gen_op_lduh(); + gen_op_ldst(lduh); break; case 0x3: /* load double word */ - gen_op_ldd(); + gen_op_ldst(ldd); gen_movl_T0_reg(rd + 1); break; case 0x9: /* load signed byte */ - gen_op_ldsb(); + gen_op_ldst(ldsb); break; case 0xa: /* load signed halfword */ - gen_op_ldsh(); + gen_op_ldst(ldsh); break; case 0xd: /* ldstub -- XXX: should be atomically */ - gen_op_ldstub(); + gen_op_ldst(ldstub); break; case 0x0f: /* swap register with memory. Also atomically */ - gen_op_swap(); + gen_op_ldst(swap); + break; + case 0x10: /* load word alternate */ + if (!supervisor(dc)) + goto priv_insn; + gen_op_lda(insn, 1, 4, 0); + break; + case 0x11: /* load unsigned byte alternate */ + if (!supervisor(dc)) + goto priv_insn; + gen_op_lduba(insn, 1, 1, 0); + break; + case 0x12: /* load unsigned halfword alternate */ + if (!supervisor(dc)) + goto priv_insn; + gen_op_lduha(insn, 1, 2, 0); + break; + case 0x13: /* load double word alternate */ + if (!supervisor(dc)) + goto priv_insn; + gen_op_ldda(insn, 1, 8, 0); + gen_movl_T0_reg(rd + 1); + break; + case 0x19: /* load signed byte alternate */ + if (!supervisor(dc)) + goto priv_insn; + gen_op_ldsba(insn, 1, 1, 1); + break; + case 0x1a: /* load signed halfword alternate */ + if (!supervisor(dc)) + goto priv_insn; + gen_op_ldsha(insn, 1, 2 ,1); + break; + case 0x1d: /* ldstuba -- XXX: should be atomically */ + if (!supervisor(dc)) + goto priv_insn; + gen_op_ldstuba(insn, 1, 1, 0); + break; + case 0x1f: /* swap reg with alt. memory. Also atomically */ + if (!supervisor(dc)) + goto priv_insn; + gen_op_swapa(insn, 1, 4, 0); break; } gen_movl_T1_reg(rd); - } else if (xop < 8) { + } else if (xop >= 0x20 && xop < 0x24) { + switch (xop) { + case 0x20: /* load fpreg */ + gen_op_ldst(ldf); + gen_op_store_FT0_fpr(rd); + break; + case 0x21: /* load fsr */ + gen_op_ldfsr(); + break; + case 0x23: /* load double fpreg */ + gen_op_ldst(lddf); + gen_op_store_DT0_fpr(rd); + break; + } + } else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) { gen_movl_reg_T1(rd); switch (xop) { case 0x4: - gen_op_st(); + gen_op_ldst(st); break; case 0x5: - gen_op_stb(); + gen_op_ldst(stb); break; case 0x6: - gen_op_sth(); + gen_op_ldst(sth); break; case 0x7: flush_T2(dc); gen_movl_reg_T2(rd + 1); - gen_op_std(); + gen_op_ldst(std); + break; + case 0x14: + if (!supervisor(dc)) + goto priv_insn; + gen_op_sta(insn, 0, 4, 0); + break; + case 0x15: + if (!supervisor(dc)) + goto priv_insn; + gen_op_stba(insn, 0, 1, 0); + break; + case 0x16: + if (!supervisor(dc)) + goto priv_insn; + gen_op_stha(insn, 0, 2, 0); + break; + case 0x17: + if (!supervisor(dc)) + goto priv_insn; + flush_T2(dc); + gen_movl_reg_T2(rd + 1); + gen_op_stda(insn, 0, 8, 0); break; } - } + } else if (xop > 0x23 && xop < 0x28) { + switch (xop) { + case 0x24: + gen_op_load_fpr_FT0(rd); + gen_op_ldst(stf); + break; + case 0x25: + gen_op_stfsr(); + break; + case 0x27: + gen_op_load_fpr_DT0(rd); + gen_op_ldst(stdf); + break; + } + } else if (xop > 0x33 && xop < 0x38) { + /* Co-processor */ + } } } /* default case for non jump instructions */ @@ -753,30 +1249,59 @@ static void disas_sparc_insn(DisasContext * dc) save_state(dc); gen_op_exception(TT_ILL_INSN); dc->is_br = 1; + return; + priv_insn: + save_state(dc); + gen_op_exception(TT_PRIV_INSN); + dc->is_br = 1; } static inline int gen_intermediate_code_internal(TranslationBlock * tb, - int spc) + int spc, CPUSPARCState *env) { target_ulong pc_start, last_pc; uint16_t *gen_opc_end; DisasContext dc1, *dc = &dc1; + int j, lj = -1; memset(dc, 0, sizeof(DisasContext)); - if (spc) { - printf("SearchPC not yet supported\n"); - exit(0); - } dc->tb = tb; pc_start = tb->pc; dc->pc = pc_start; dc->npc = (target_ulong) tb->cs_base; - +#if defined(CONFIG_USER_ONLY) + dc->mem_idx = 0; +#else + dc->mem_idx = ((env->psrs) != 0); +#endif gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; + env->access_type = ACCESS_CODE; + do { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == dc->pc) { + gen_debug(dc, dc->pc); + break; + } + } + } + if (spc) { + if (loglevel > 0) + fprintf(logfile, "Search PC...\n"); + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + gen_opc_pc[lj] = dc->pc; + gen_opc_npc[lj] = dc->npc; + gen_opc_instr_start[lj] = 1; + } + } last_pc = dc->pc; disas_sparc_insn(dc); if (dc->is_br) @@ -800,6 +1325,20 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, } } *gen_opc_ptr = INDEX_op_end; + if (spc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + tb->size = 0; +#if 0 + if (loglevel > 0) { + page_dump(logfile); + } +#endif + } else { + tb->size = dc->npc - pc_start; + } #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "--------------\n"); @@ -814,17 +1353,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, } #endif + env->access_type = ACCESS_DATA; return 0; } int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) { - return gen_intermediate_code_internal(tb, 0); + return gen_intermediate_code_internal(tb, 0, env); } int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) { - return gen_intermediate_code_internal(tb, 1); + return gen_intermediate_code_internal(tb, 1, env); } CPUSPARCState *cpu_sparc_init(void) @@ -839,7 +1379,17 @@ CPUSPARCState *cpu_sparc_init(void) env->cwp = 0; env->wim = 1; env->regwptr = env->regbase + (env->cwp * 16); + env->access_type = ACCESS_DATA; +#if defined(CONFIG_USER_ONLY) env->user_mode_only = 1; +#else + /* Emulate Prom */ + env->psrs = 1; + env->pc = 0x4000; + env->npc = env->pc + 4; + env->mmuregs[0] = (0x10<<24) | MMU_E; /* Impl 1, ver 0, MMU Enabled */ + env->mmuregs[1] = 0x3000 >> 4; /* MMU Context table */ +#endif cpu_single_env = env; return (env); } @@ -870,10 +1420,20 @@ void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags) env->regwptr[i + x * 8]); fprintf(f, "\n"); } - fprintf(f, "psr: 0x%08x -> %c%c%c%c wim: 0x%08x\n", env->psr | env->cwp, + fprintf(f, "\nFloating Point Registers:\n"); + for (i = 0; i < 32; i++) { + if ((i & 3) == 0) + fprintf(f, "%%f%02d:", i); + fprintf(f, " %016lf", env->fpr[i]); + if ((i & 3) == 3) + fprintf(f, "\n"); + } + fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), - env->wim); + env->psrs?'S':'-', env->psrps?'P':'-', + env->psret?'E':'-', env->wim); + fprintf(f, "fsr: 0x%08x\n", env->fsr); } target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -- cgit v1.2.3 From 6d5e216de979afdc0a26410580ad31376f7107f7 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Sep 2004 22:04:13 +0000 Subject: SPARC fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1084 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 340 ++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 96 +++++++++++++ 2 files changed, 436 insertions(+) diff --git a/linux-user/signal.c b/linux-user/signal.c index bde492237..50f2ba10a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1271,6 +1271,346 @@ badframe: return 0; } +#elif defined(TARGET_SPARC) +#define __SUNOS_MAXWIN 31 + +/* This is what SunOS does, so shall I. */ +struct target_sigcontext { + target_ulong sigc_onstack; /* state to restore */ + + target_ulong sigc_mask; /* sigmask to restore */ + target_ulong sigc_sp; /* stack pointer */ + target_ulong sigc_pc; /* program counter */ + target_ulong sigc_npc; /* next program counter */ + target_ulong sigc_psr; /* for condition codes etc */ + target_ulong sigc_g1; /* User uses these two registers */ + target_ulong sigc_o0; /* within the trampoline code. */ + + /* Now comes information regarding the users window set + * at the time of the signal. + */ + target_ulong sigc_oswins; /* outstanding windows */ + + /* stack ptrs for each regwin buf */ + char *sigc_spbuf[__SUNOS_MAXWIN]; + + /* Windows to restore after signal */ + struct { + target_ulong locals[8]; + target_ulong ins[8]; + } sigc_wbuf[__SUNOS_MAXWIN]; +}; +/* A Sparc stack frame */ +struct sparc_stackf { + target_ulong locals[8]; + target_ulong ins[6]; + struct sparc_stackf *fp; + target_ulong callers_pc; + char *structptr; + target_ulong xargs[6]; + target_ulong xxargs[1]; +}; + +typedef struct { + struct { + target_ulong psr; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong u_regs[16]; /* globals and ins */ + } si_regs; + int si_mask; +} __siginfo_t; + +typedef struct { + unsigned long si_float_regs [32]; + unsigned long si_fsr; + unsigned long si_fpqdepth; + struct { + unsigned long *insn_addr; + unsigned long insn; + } si_fpqueue [16]; +} __siginfo_fpu_t; + + +struct target_signal_frame { + struct sparc_stackf ss; + __siginfo_t info; + __siginfo_fpu_t *fpu_save; + target_ulong insns[2] __attribute__ ((aligned (8))); + target_ulong extramask[TARGET_NSIG_WORDS - 1]; + target_ulong extra_size; /* Should be 0 */ + __siginfo_fpu_t fpu_state; +}; +struct target_rt_signal_frame { + struct sparc_stackf ss; + siginfo_t info; + target_ulong regs[20]; + sigset_t mask; + __siginfo_fpu_t *fpu_save; + unsigned int insns[2]; + stack_t stack; + unsigned int extra_size; /* Should be 0 */ + __siginfo_fpu_t fpu_state; +}; + +#define UREG_O0 0 +#define UREG_O6 6 +#define UREG_I0 16 +#define UREG_I1 17 +#define UREG_I2 18 +#define UREG_I6 22 +#define UREG_I7 23 +#define UREG_FP UREG_I6 +#define UREG_SP UREG_O6 + +static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, unsigned long framesize) +{ + unsigned long sp; + + sp = env->regwptr[UREG_FP]; +#if 0 + + /* This is the X/Open sanctioned signal stack switching. */ + if (sa->sa_flags & TARGET_SA_ONSTACK) { + if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) + sp = current->sas_ss_sp + current->sas_ss_size; + } +#endif + return (void *)(sp - framesize); +} + +static int +setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) +{ + int err = 0, i; + + fprintf(stderr, "2.a %lx psr: %lx regs: %lx\n", si, env->psr, si->si_regs.psr); + err |= __put_user(env->psr, &si->si_regs.psr); + fprintf(stderr, "2.a1 pc:%lx\n", si->si_regs.pc); + err |= __put_user(env->pc, &si->si_regs.pc); + err |= __put_user(env->npc, &si->si_regs.npc); + err |= __put_user(env->y, &si->si_regs.y); + fprintf(stderr, "2.b\n"); + for (i=0; i < 7; i++) { + err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]); + } + for (i=0; i < 7; i++) { + err |= __put_user(env->regwptr[i+16], &si->si_regs.u_regs[i+8]); + } + fprintf(stderr, "2.c\n"); + err |= __put_user(mask, &si->si_mask); + return err; +} +static int +setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ + CPUState *env, unsigned long mask) +{ + int err = 0; + + err |= __put_user(mask, &sc->sigc_mask); + err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp); + err |= __put_user(env->pc, &sc->sigc_pc); + err |= __put_user(env->npc, &sc->sigc_npc); + err |= __put_user(env->psr, &sc->sigc_psr); + err |= __put_user(env->gregs[1], &sc->sigc_g1); + err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0); + + return err; +} +#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + struct target_signal_frame *sf; + int sigframe_size, err, i; + + /* 1. Make sure everything is clean */ + //synchronize_user_stack(); + + sigframe_size = NF_ALIGNEDSZ; + + sf = (struct target_signal_frame *) + get_sigframe(ka, env, sigframe_size); + +#if 0 + if (invalid_frame_pointer(sf, sigframe_size)) + goto sigill_and_return; +#endif + /* 2. Save the current process state */ + err = setup___siginfo(&sf->info, env, set->sig[0]); + err |= __put_user(0, &sf->extra_size); + + //err |= save_fpu_state(regs, &sf->fpu_state); + //err |= __put_user(&sf->fpu_state, &sf->fpu_save); + + err |= __put_user(set->sig[0], &sf->info.si_mask); + for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { + err |= __put_user(set->sig[i + 1], &sf->extramask[i]); + } + + for (i = 0; i < 7; i++) { + err |= __put_user(env->regwptr[i + 8], &sf->ss.locals[i]); + } + for (i = 0; i < 7; i++) { + err |= __put_user(env->regwptr[i + 16], &sf->ss.ins[i]); + } + //err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], + // sizeof(struct reg_window)); + if (err) + goto sigsegv; + + /* 3. signal handler back-trampoline and parameters */ + env->regwptr[UREG_FP] = (target_ulong) sf; + env->regwptr[UREG_I0] = sig; + env->regwptr[UREG_I1] = (target_ulong) &sf->info; + env->regwptr[UREG_I2] = (target_ulong) &sf->info; + + /* 4. signal handler */ + env->pc = (unsigned long) ka->sa._sa_handler; + env->npc = (env->pc + 4); + /* 5. return to kernel instructions */ + if (ka->sa.sa_restorer) + env->regwptr[UREG_I7] = (unsigned long)ka->sa.sa_restorer; + else { + env->regwptr[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); + + /* mov __NR_sigreturn, %g1 */ + err |= __put_user(0x821020d8, &sf->insns[0]); + + /* t 0x10 */ + err |= __put_user(0x91d02010, &sf->insns[1]); + if (err) + goto sigsegv; + + /* Flush instruction space. */ + //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); + //tb_flush(env); + } + return; + +sigill_and_return: + force_sig(TARGET_SIGILL); +sigsegv: + force_sig(TARGET_SIGSEGV); +} +static inline int +restore_fpu_state(CPUState *env, __siginfo_fpu_t *fpu) +{ + int err; +#if 0 +#ifdef CONFIG_SMP + if (current->flags & PF_USEDFPU) + regs->psr &= ~PSR_EF; +#else + if (current == last_task_used_math) { + last_task_used_math = 0; + regs->psr &= ~PSR_EF; + } +#endif + current->used_math = 1; + current->flags &= ~PF_USEDFPU; +#endif +#if 0 + if (verify_area (VERIFY_READ, fpu, sizeof(*fpu))) + return -EFAULT; +#endif + + err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0], + (sizeof(unsigned long) * 32)); + err |= __get_user(env->fsr, &fpu->si_fsr); +#if 0 + err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth); + if (current->thread.fpqdepth != 0) + err |= __copy_from_user(¤t->thread.fpqueue[0], + &fpu->si_fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); +#endif + return err; +} + + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + struct target_signal_frame *sf; + unsigned long up_psr, pc, npc; + target_sigset_t set; + __siginfo_fpu_t *fpu_save; + int err; + + sf = (struct new_signal_frame *) env->regwptr[UREG_FP]; + fprintf(stderr, "sigreturn sf: %lx\n", &sf); + + /* 1. Make sure we are not getting garbage from the user */ +#if 0 + if (verify_area (VERIFY_READ, sf, sizeof (*sf))) + goto segv_and_exit; +#endif + + if (((uint) sf) & 3) + goto segv_and_exit; + + err = __get_user(pc, &sf->info.si_regs.pc); + err |= __get_user(npc, &sf->info.si_regs.npc); + + fprintf(stderr, "pc: %lx npc %lx\n", pc, npc); + if ((pc | npc) & 3) + goto segv_and_exit; + + /* 2. Restore the state */ + up_psr = env->psr; + //err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs) + //); + /* User can only change condition codes and FPU enabling in %psr. */ + env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */)) + | (env->psr & (PSR_ICC /* | PSR_EF */)); + fprintf(stderr, "psr: %lx\n", env->psr); + + err |= __get_user(fpu_save, &sf->fpu_save); + + if (fpu_save) + err |= restore_fpu_state(env, fpu_save); + + /* This is pretty much atomic, no amount locking would prevent + * the races which exist anyways. + */ + err |= __get_user(set.sig[0], &sf->info.si_mask); + //err |= __copy_from_user(&set.sig[1], &sf->extramask, + // (_NSIG_WORDS-1) * sizeof(unsigned int)); + + if (err) + goto segv_and_exit; + +#if 0 + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); +#endif + fprintf(stderr, "returning %lx\n", env->regwptr[0]); + return env->regwptr[0]; + +segv_and_exit: + force_sig(TARGET_SIGSEGV); +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + + #else static void setup_frame(int sig, struct emulated_sigaction *ka, diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 91e1fe538..ae212ec32 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -294,6 +294,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) +#if !defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 0x00000001 #define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ #define TARGET_SA_SIGINFO 0x00000004 @@ -302,6 +303,57 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SA_NODEFER 0x40000000 #define TARGET_SA_RESETHAND 0x80000000 #define TARGET_SA_RESTORER 0x04000000 +#else /* TARGET_SPARC */ +#define TARGET_SA_NOCLDSTOP 8u +#define TARGET_SA_NOCLDWAIT 0x100u +#define TARGET_SA_SIGINFO 0x200u +#define TARGET_SA_ONSTACK 1u +#define TARGET_SA_RESTART 2u +#define TARGET_SA_NODEFER 0x20u +#define TARGET_SA_RESETHAND 4u +#endif + +#if defined(TARGET_SPARC) + +#define TARGET_SIGHUP 1 +#define TARGET_SIGINT 2 +#define TARGET_SIGQUIT 3 +#define TARGET_SIGILL 4 +#define TARGET_SIGTRAP 5 +#define TARGET_SIGABRT 6 +#define TARGET_SIGIOT 6 +#define TARGET_SIGSTKFLT 7 /* actually EMT */ +#define TARGET_SIGFPE 8 +#define TARGET_SIGKILL 9 +#define TARGET_SIGBUS 10 +#define TARGET_SIGSEGV 11 +#define TARGET_SIGSYS 12 +#define TARGET_SIGPIPE 13 +#define TARGET_SIGALRM 14 +#define TARGET_SIGTERM 15 +#define TARGET_SIGURG 16 +#define TARGET_SIGSTOP 17 +#define TARGET_SIGTSTP 18 +#define TARGET_SIGCONT 19 +#define TARGET_SIGCHLD 20 +#define TARGET_SIGTTIN 21 +#define TARGET_SIGTTOU 22 +#define TARGET_SIGIO 23 +#define TARGET_SIGXCPU 24 +#define TARGET_SIGXFSZ 25 +#define TARGET_SIGVTALRM 26 +#define TARGET_SIGPROF 27 +#define TARGET_SIGWINCH 28 +#define TARGET_SIGPWR 29 +#define TARGET_SIGUSR1 30 +#define TARGET_SIGUSR2 31 +#define TARGET_SIGRTMIN 32 + +#define TARGET_SIG_BLOCK 0x01 /* for blocking signals */ +#define TARGET_SIG_UNBLOCK 0x02 /* for unblocking signals */ +#define TARGET_SIG_SETMASK 0x04 /* for setting the signal mask */ + +#else #define TARGET_SIGHUP 1 #define TARGET_SIGINT 2 @@ -341,6 +393,8 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */ #define TARGET_SIG_SETMASK 2 /* for setting the signal mask */ +#endif + struct target_old_sigaction { target_ulong _sa_handler; target_ulong sa_mask; @@ -359,6 +413,30 @@ typedef union target_sigval { int sival_int; target_ulong sival_ptr; } target_sigval_t; +#if 0 +#if defined (TARGET_SPARC) +typedef struct { + struct { + target_ulong psr; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong u_regs[16]; /* globals and ins */ + } si_regs; + int si_mask; +} __siginfo_t; + +typedef struct { + unsigned long si_float_regs [32]; + unsigned long si_fsr; + unsigned long si_fpqdepth; + struct { + unsigned long *insn_addr; + unsigned long insn; + } si_fpqueue [16]; +} __siginfo_fpu_t; +#endif +#endif #define TARGET_SI_MAX_SIZE 128 #define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3) @@ -954,6 +1032,24 @@ struct target_stat64 { #define TARGET_O_NOFOLLOW 0100000 /* don't follow links */ #define TARGET_O_LARGEFILE 0200000 #define TARGET_O_DIRECT 0400000 /* direct disk access hint */ +#elif defined (TARGET_SPARC) +#define TARGET_O_RDONLY 0x0000 +#define TARGET_O_WRONLY 0x0001 +#define TARGET_O_RDWR 0x0002 +#define TARGET_O_ACCMODE 0x0003 +#define TARGET_O_APPEND 0x0008 +#define TARGET_FASYNC 0x0040 /* fcntl, for BSD compatibility */ +#define TARGET_O_CREAT 0x0200 /* not fcntl */ +#define TARGET_O_TRUNC 0x0400 /* not fcntl */ +#define TARGET_O_EXCL 0x0800 /* not fcntl */ +#define TARGET_O_SYNC 0x2000 +#define TARGET_O_NONBLOCK 0x4000 +#define TARGET_O_NDELAY (0x0004 | O_NONBLOCK) +#define TARGET_O_NOCTTY 0x8000 /* not fcntl */ +#define TARGET_O_DIRECTORY 0x10000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */ +#define TARGET_O_LARGEFILE 0x40000 +#define TARGET_O_DIRECT 0x100000 /* direct disk access hint */ #else #define TARGET_O_ACCMODE 0003 #define TARGET_O_RDONLY 00 -- cgit v1.2.3 From 420557e8981347368427849ff89ecd3fe537dafa Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Sep 2004 22:13:50 +0000 Subject: full system SPARC emulation (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1085 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 221 ++++++++++++++++++++++++++ hw/lance.c | 472 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/m48t08.c | 391 ++++++++++++++++++++++++++++++++++++++++++++++ hw/m48t08.h | 12 ++ hw/magic-load.c | 341 ++++++++++++++++++++++++++++++++++++++++ hw/sched.c | 346 +++++++++++++++++++++++++++++++++++++++++ hw/sun4m.c | 130 ++++++++++++++++ hw/tcx.c | 176 +++++++++++++++++++++ 8 files changed, 2089 insertions(+) create mode 100644 hw/iommu.c create mode 100644 hw/lance.c create mode 100644 hw/m48t08.c create mode 100644 hw/m48t08.h create mode 100644 hw/magic-load.c create mode 100644 hw/sched.c create mode 100644 hw/sun4m.c create mode 100644 hw/tcx.c diff --git a/hw/iommu.c b/hw/iommu.c new file mode 100644 index 000000000..f00bb78b0 --- /dev/null +++ b/hw/iommu.c @@ -0,0 +1,221 @@ +/* + * QEMU SPARC iommu emulation + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* debug iommu */ +//#define DEBUG_IOMMU + +/* The IOMMU registers occupy three pages in IO space. */ +struct iommu_regs { + /* First page */ + volatile unsigned long control; /* IOMMU control */ + volatile unsigned long base; /* Physical base of iopte page table */ + volatile unsigned long _unused1[3]; + volatile unsigned long tlbflush; /* write only */ + volatile unsigned long pageflush; /* write only */ + volatile unsigned long _unused2[1017]; + /* Second page */ + volatile unsigned long afsr; /* Async-fault status register */ + volatile unsigned long afar; /* Async-fault physical address */ + volatile unsigned long _unused3[2]; + volatile unsigned long sbuscfg0; /* SBUS configuration registers, per-slot */ + volatile unsigned long sbuscfg1; + volatile unsigned long sbuscfg2; + volatile unsigned long sbuscfg3; + volatile unsigned long mfsr; /* Memory-fault status register */ + volatile unsigned long mfar; /* Memory-fault physical address */ + volatile unsigned long _unused4[1014]; + /* Third page */ + volatile unsigned long mid; /* IOMMU module-id */ +}; + +#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ +#define IOMMU_CTRL_VERS 0x0f000000 /* Version */ +#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ +#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */ +#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */ +#define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */ +#define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */ +#define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */ +#define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */ +#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */ +#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */ +#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */ + +#define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */ +#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after transaction */ +#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than 12.8 us. */ +#define IOMMU_AFSR_BE 0x10000000 /* Write access received error acknowledge */ +#define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */ +#define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */ +#define IOMMU_AFSR_RESV 0x00f00000 /* Reserver, forced to 0x8 by hardware */ +#define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */ +#define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */ +#define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */ + +#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */ +#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ +#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ +#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses + produced by this device as pure + physical. */ + +#define IOMMU_MFSR_ERR 0x80000000 /* One or more of PERR1 or PERR0 */ +#define IOMMU_MFSR_S 0x01000000 /* Sparc was in supervisor mode */ +#define IOMMU_MFSR_CPU 0x00800000 /* CPU transaction caused parity error */ +#define IOMMU_MFSR_ME 0x00080000 /* Multiple parity errors occurred */ +#define IOMMU_MFSR_PERR 0x00006000 /* high bit indicates parity error occurred + on the even word of the access, low bit + indicated odd word caused the parity error */ +#define IOMMU_MFSR_BM 0x00001000 /* Error occurred while in boot mode */ +#define IOMMU_MFSR_C 0x00000800 /* Address causing error was marked cacheable */ +#define IOMMU_MFSR_RTYP 0x000000f0 /* Memory request transaction type */ + +#define IOMMU_MID_SBAE 0x001f0000 /* SBus arbitration enable */ +#define IOMMU_MID_SE 0x00100000 /* Enables SCSI/ETHERNET arbitration */ +#define IOMMU_MID_SB3 0x00080000 /* Enable SBUS device 3 arbitration */ +#define IOMMU_MID_SB2 0x00040000 /* Enable SBUS device 2 arbitration */ +#define IOMMU_MID_SB1 0x00020000 /* Enable SBUS device 1 arbitration */ +#define IOMMU_MID_SB0 0x00010000 /* Enable SBUS device 0 arbitration */ +#define IOMMU_MID_MID 0x0000000f /* Module-id, hardcoded to 0x8 */ + +/* The format of an iopte in the page tables */ +#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ +#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ +#define IOPTE_WRITE 0x00000004 /* Writeable */ +#define IOPTE_VALID 0x00000002 /* IOPTE is valid */ +#define IOPTE_WAZ 0x00000001 /* Write as zeros */ + +#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (PAGE_SIZE - 1) + +typedef struct IOMMUState { + uint32_t regs[sizeof(struct iommu_regs)]; +} IOMMUState; + +static IOMMUState *ps; + +static int iommu_io_memory; + +static void iommu_reset(IOMMUState *s) +{ +} + +static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) +{ + IOMMUState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_IOMMU) >> 2; + switch (saddr) { + default: + return s->regs[saddr]; + break; + } + return 0; +} + +static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + IOMMUState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_IOMMU) >> 2; + switch (saddr) { + default: + s->regs[saddr] = val; + break; + } +} + +static CPUReadMemoryFunc *iommu_mem_read[3] = { + iommu_mem_readw, + iommu_mem_readw, + iommu_mem_readw, +}; + +static CPUWriteMemoryFunc *iommu_mem_write[3] = { + iommu_mem_writew, + iommu_mem_writew, + iommu_mem_writew, +}; + +uint32_t iommu_translate(uint32_t addr) +{ + uint32_t *iopte = (void *)(ps->regs[1] << 4), pa, iostart; + + switch (ps->regs[0] & IOMMU_CTRL_RNGE) { + case IOMMU_RNGE_16MB: + iostart = 0xff000000; + break; + case IOMMU_RNGE_32MB: + iostart = 0xfe000000; + break; + case IOMMU_RNGE_64MB: + iostart = 0xfc000000; + break; + case IOMMU_RNGE_128MB: + iostart = 0xf8000000; + break; + case IOMMU_RNGE_256MB: + iostart = 0xf0000000; + break; + case IOMMU_RNGE_512MB: + iostart = 0xe0000000; + break; + case IOMMU_RNGE_1GB: + iostart = 0xc0000000; + break; + default: + case IOMMU_RNGE_2GB: + iostart = 0x80000000; + break; + } + + iopte += ((addr - iostart) >> PAGE_SHIFT); + cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0); + bswap32s(&pa); + pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */ + //return pa + PAGE_SIZE; + return pa + (addr & PAGE_MASK); +} + +void iommu_init() +{ + IOMMUState *s; + + s = qemu_mallocz(sizeof(IOMMUState)); + if (!s) + return; + + iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_IOMMU, sizeof(struct iommu_regs), + iommu_io_memory); + + iommu_reset(s); + ps = s; +} + diff --git a/hw/lance.c b/hw/lance.c new file mode 100644 index 000000000..e461adead --- /dev/null +++ b/hw/lance.c @@ -0,0 +1,472 @@ +/* + * QEMU Lance emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* debug LANCE card */ +#define DEBUG_LANCE + +#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ +#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */ +#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */ + +#ifndef LANCE_LOG_TX_BUFFERS +#define LANCE_LOG_TX_BUFFERS 4 +#define LANCE_LOG_RX_BUFFERS 4 +#endif + +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ + + +#define LE_CSR0 0 +#define LE_CSR1 1 +#define LE_CSR2 2 +#define LE_CSR3 3 +#define LE_MAXREG (LE_CSR3 + 1) + +#define LE_RDP 0 +#define LE_RAP 1 + +#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ + +#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ +#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ +#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ +#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ +#define LE_C0_MERR 0x0800 /* ME: Memory error */ +#define LE_C0_RINT 0x0400 /* Received interrupt */ +#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ +#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ +#define LE_C0_INTR 0x0080 /* Interrupt or error */ +#define LE_C0_INEA 0x0040 /* Interrupt enable */ +#define LE_C0_RXON 0x0020 /* Receiver on */ +#define LE_C0_TXON 0x0010 /* Transmitter on */ +#define LE_C0_TDMD 0x0008 /* Transmitter demand */ +#define LE_C0_STOP 0x0004 /* Stop the card */ +#define LE_C0_STRT 0x0002 /* Start the card */ +#define LE_C0_INIT 0x0001 /* Init the card */ + +#define LE_C3_BSWP 0x4 /* SWAP */ +#define LE_C3_ACON 0x2 /* ALE Control */ +#define LE_C3_BCON 0x1 /* Byte control */ + +/* Receive message descriptor 1 */ +#define LE_R1_OWN 0x80 /* Who owns the entry */ +#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ +#define LE_R1_FRA 0x20 /* FRA: Frame error */ +#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUF 0x04 /* BUF: Buffer error */ +#define LE_R1_SOP 0x02 /* Start of packet */ +#define LE_R1_EOP 0x01 /* End of packet */ +#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ + +#define LE_T1_OWN 0x80 /* Lance owns the packet */ +#define LE_T1_ERR 0x40 /* Error summary */ +#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ +#define LE_T1_EONE 0x08 /* Error: one retry needed */ +#define LE_T1_EDEF 0x04 /* Error: deferred */ +#define LE_T1_SOP 0x02 /* Start of packet */ +#define LE_T1_EOP 0x01 /* End of packet */ +#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ + +#define LE_T3_BUF 0x8000 /* Buffer error */ +#define LE_T3_UFL 0x4000 /* Error underflow */ +#define LE_T3_LCOL 0x1000 /* Error late collision */ +#define LE_T3_CLOS 0x0800 /* Error carrier loss */ +#define LE_T3_RTY 0x0400 /* Error retry */ +#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ + +#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) +#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) + +#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) +#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) + +#define PKT_BUF_SZ 1544 +#define RX_BUFF_SIZE PKT_BUF_SZ +#define TX_BUFF_SIZE PKT_BUF_SZ + +struct lance_rx_desc { + unsigned short rmd0; /* low address of packet */ + unsigned char rmd1_bits; /* descriptor bits */ + unsigned char rmd1_hadr; /* high address of packet */ + short length; /* This length is 2s complement (negative)! + * Buffer length + */ + unsigned short mblength; /* This is the actual number of bytes received */ +}; + +struct lance_tx_desc { + unsigned short tmd0; /* low address of packet */ + unsigned char tmd1_bits; /* descriptor bits */ + unsigned char tmd1_hadr; /* high address of packet */ + short length; /* Length is 2s complement (negative)! */ + unsigned short misc; +}; + +/* The LANCE initialization block, described in databook. */ +/* On the Sparc, this block should be on a DMA region */ +struct lance_init_block { + unsigned short mode; /* Pre-set mode (reg. 15) */ + unsigned char phys_addr[6]; /* Physical ethernet address */ + unsigned filter[2]; /* Multicast filter. */ + + /* Receive and transmit ring base, along with extra bits. */ + unsigned short rx_ptr; /* receive descriptor addr */ + unsigned short rx_len; /* receive len and high addr */ + unsigned short tx_ptr; /* transmit descriptor addr */ + unsigned short tx_len; /* transmit len and high addr */ + + /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ + struct lance_rx_desc brx_ring[RX_RING_SIZE]; + struct lance_tx_desc btx_ring[TX_RING_SIZE]; + + char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE]; + char pad[2]; /* align rx_buf for copy_and_sum(). */ + char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE]; +}; + +#define LEDMA_REGS 4 +#if 0 +/* Structure to describe the current status of DMA registers on the Sparc */ +struct sparc_dma_registers { + uint32_t cond_reg; /* DMA condition register */ + uint32_t st_addr; /* Start address of this transfer */ + uint32_t cnt; /* How many bytes to transfer */ + uint32_t dma_test; /* DMA test register */ +}; +#endif + +typedef struct LEDMAState { + uint32_t regs[LEDMA_REGS]; +} LEDMAState; + +typedef struct LANCEState { + NetDriverState *nd; + uint32_t leptr; + uint16_t addr; + uint16_t regs[LE_MAXREG]; + uint8_t phys[6]; /* mac address */ + int irq; + LEDMAState *ledma; +} LANCEState; + +static int lance_io_memory; + +static unsigned int rxptr, txptr; + +static void lance_send(void *opaque); + +static void lance_reset(LANCEState *s) +{ + memcpy(s->phys, s->nd->macaddr, 6); + rxptr = 0; + txptr = 0; + s->regs[LE_CSR0] = LE_C0_STOP; +} + +static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) +{ + LANCEState *s = opaque; + uint32_t saddr; + + saddr = addr - PHYS_JJ_LE; + switch (saddr >> 1) { + case LE_RDP: + return s->regs[s->addr]; + case LE_RAP: + return s->addr; + default: + break; + } + return 0; +} + +static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LANCEState *s = opaque; + uint32_t saddr; + uint16_t clear, reg; + + saddr = addr - PHYS_JJ_LE; + switch (saddr >> 1) { + case LE_RDP: + switch(s->addr) { + case LE_CSR0: + if (val & LE_C0_STOP) { + s->regs[LE_CSR0] = LE_C0_STOP; + break; + } + + reg = s->regs[LE_CSR0]; + + // 1 = clear for some bits + reg &= ~(val & 0x7f00); + + // generated bits + reg &= ~(LE_C0_ERR | LE_C0_INTR); + if (reg & 0x7100) + reg |= LE_C0_ERR; + if (reg & 0x7f00) + reg |= LE_C0_INTR; + + // direct bit + reg &= ~LE_C0_INEA; + reg |= val & LE_C0_INEA; + + // exclusive bits + if (val & LE_C0_INIT) { + reg |= LE_C0_IDON | LE_C0_INIT; + reg &= ~LE_C0_STOP; + } + else if (val & LE_C0_STRT) { + reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; + reg &= ~LE_C0_STOP; + } + + s->regs[LE_CSR0] = reg; + + // trigger bits + //if (val & LE_C0_TDMD) + + if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) + pic_set_irq(s->irq, 1); + break; + case LE_CSR1: + s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); + s->regs[s->addr] = val; + break; + case LE_CSR2: + s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); + s->regs[s->addr] = val; + break; + case LE_CSR3: + s->regs[s->addr] = val; + break; + } + break; + case LE_RAP: + if (val < LE_MAXREG) + s->addr = val; + break; + default: + break; + } + lance_send(s); +} + +static CPUReadMemoryFunc *lance_mem_read[3] = { + lance_mem_readw, + lance_mem_readw, + lance_mem_readw, +}; + +static CPUWriteMemoryFunc *lance_mem_write[3] = { + lance_mem_writew, + lance_mem_writew, + lance_mem_writew, +}; + + +/* return the max buffer size if the LANCE can receive more data */ +static int lance_can_receive(void *opaque) +{ + LANCEState *s = opaque; + void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + struct lance_init_block *ib; + int i; + uint16_t temp; + + if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) + return 0; + + ib = (void *) iommu_translate(dmaptr); + + for (i = 0; i < RX_RING_SIZE; i++) { + cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + temp &= 0xff; + if (temp == (LE_R1_OWN)) { +#ifdef DEBUG_LANCE + fprintf(stderr, "lance: can receive %d\n", RX_BUFF_SIZE); +#endif + return RX_BUFF_SIZE; + } + } +#ifdef DEBUG_LANCE + fprintf(stderr, "lance: cannot receive\n"); +#endif + return 0; +} + +#define MIN_BUF_SIZE 60 + +static void lance_receive(void *opaque, const uint8_t *buf, int size) +{ + LANCEState *s = opaque; + void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + struct lance_init_block *ib; + unsigned int i, old_rxptr, j; + uint16_t temp; + + if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) + return; + + ib = (void *) iommu_translate(dmaptr); + + old_rxptr = rxptr; + for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { + cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + if (temp == (LE_R1_OWN)) { + rxptr = (rxptr + 1) & RX_RING_MOD_MASK; + temp = size; + bswap16s(&temp); + cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2); +#if 0 + cpu_physical_memory_write(&ib->rx_buf[i], buf, size); +#else + for (j = 0; j < size; j++) { + cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1); + } +#endif + temp = LE_R1_POK; + cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; + if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) + pic_set_irq(s->irq, 1); +#ifdef DEBUG_LANCE + fprintf(stderr, "lance: got packet, len %d\n", size); +#endif + return; + } + } +} + +static void lance_send(void *opaque) +{ + LANCEState *s = opaque; + void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + struct lance_init_block *ib; + unsigned int i, old_txptr, j; + uint16_t temp; + char pkt_buf[PKT_BUF_SZ]; + + if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) + return; + + ib = (void *) iommu_translate(dmaptr); + + old_txptr = txptr; + for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { + cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + if (temp == (LE_T1_POK|LE_T1_OWN)) { + cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2); + bswap16s(&temp); + temp = (~temp) + 1; +#if 0 + cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp); +#else + for (j = 0; j < temp; j++) { + cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1); + } +#endif + +#ifdef DEBUG_LANCE + fprintf(stderr, "lance: sending packet, len %d\n", temp); +#endif + qemu_send_packet(s->nd, pkt_buf, temp); + temp = LE_T1_POK; + cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + txptr = (txptr + 1) & TX_RING_MOD_MASK; + s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; + } + } +} + +static int ledma_io_memory; + +static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) +{ + LEDMAState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_LEDMA) >> 2; + if (saddr < LEDMA_REGS) + return s->regs[saddr]; + else + return 0; +} + +static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LEDMAState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_LEDMA) >> 2; + if (saddr < LEDMA_REGS) + s->regs[saddr] = val; +} + +static CPUReadMemoryFunc *ledma_mem_read[3] = { + ledma_mem_readl, + ledma_mem_readl, + ledma_mem_readl, +}; + +static CPUWriteMemoryFunc *ledma_mem_write[3] = { + ledma_mem_writel, + ledma_mem_writel, + ledma_mem_writel, +}; + +void lance_init(NetDriverState *nd, int irq) +{ + LANCEState *s; + LEDMAState *led; + + s = qemu_mallocz(sizeof(LANCEState)); + if (!s) + return; + + lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_LE, 8, + lance_io_memory); + led = qemu_mallocz(sizeof(LEDMAState)); + if (!led) + return; + + ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led); + cpu_register_physical_memory(PHYS_JJ_LEDMA, 16, + ledma_io_memory); + + s->nd = nd; + s->ledma = led; + s->irq = irq; + + lance_reset(s); + qemu_add_read_packet(nd, lance_can_receive, lance_receive, s); +} + diff --git a/hw/m48t08.c b/hw/m48t08.c new file mode 100644 index 000000000..c5b6e7a72 --- /dev/null +++ b/hw/m48t08.c @@ -0,0 +1,391 @@ +/* + * QEMU M48T08 NVRAM emulation for Sparc platform + * + * Copyright (c) 2003-2004 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "m48t08.h" + +//#define DEBUG_NVRAM + +#if defined(DEBUG_NVRAM) +#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) +#else +#define NVRAM_PRINTF(fmt, args...) do { } while (0) +#endif + +#define NVRAM_MAX_MEM 0xfff0 + +struct m48t08_t { + /* Hardware parameters */ + int mem_index; + uint32_t mem_base; + uint16_t size; + /* RTC management */ + time_t time_offset; + time_t stop_time; + /* NVRAM storage */ + uint8_t lock; + uint16_t addr; + uint8_t *buffer; +}; + +/* Fake timer functions */ +/* Generic helpers for BCD */ +static inline uint8_t toBCD (uint8_t value) +{ + return (((value / 10) % 10) << 4) | (value % 10); +} + +static inline uint8_t fromBCD (uint8_t BCD) +{ + return ((BCD >> 4) * 10) + (BCD & 0x0F); +} + +/* RTC management helpers */ +static void get_time (m48t08_t *NVRAM, struct tm *tm) +{ + time_t t; + + t = time(NULL) + NVRAM->time_offset; +#ifdef _WIN32 + memcpy(tm,localtime(&t),sizeof(*tm)); +#else + localtime_r (&t, tm) ; +#endif +} + +static void set_time (m48t08_t *NVRAM, struct tm *tm) +{ + time_t now, new_time; + + new_time = mktime(tm); + now = time(NULL); + NVRAM->time_offset = new_time - now; +} + +/* Direct access to NVRAM */ +void m48t08_write (m48t08_t *NVRAM, uint32_t val) +{ + struct tm tm; + int tmp; + + if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000) + NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); + switch (NVRAM->addr) { + case 0x1FF8: + /* control */ + NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; + break; + case 0x1FF9: + /* seconds (BCD) */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_time(NVRAM, &tm); + tm.tm_sec = tmp; + set_time(NVRAM, &tm); + } + if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) { + if (val & 0x80) { + NVRAM->stop_time = time(NULL); + } else { + NVRAM->time_offset += NVRAM->stop_time - time(NULL); + NVRAM->stop_time = 0; + } + } + NVRAM->buffer[0x1FF9] = val & 0x80; + break; + case 0x1FFA: + /* minutes (BCD) */ + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_time(NVRAM, &tm); + tm.tm_min = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFB: + /* hours (BCD) */ + tmp = fromBCD(val & 0x3F); + if (tmp >= 0 && tmp <= 23) { + get_time(NVRAM, &tm); + tm.tm_hour = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFC: + /* day of the week / century */ + tmp = fromBCD(val & 0x07); + get_time(NVRAM, &tm); + tm.tm_wday = tmp; + set_time(NVRAM, &tm); + NVRAM->buffer[0x1FFC] = val & 0x40; + break; + case 0x1FFD: + /* date */ + tmp = fromBCD(val & 0x1F); + if (tmp != 0) { + get_time(NVRAM, &tm); + tm.tm_mday = tmp; + set_time(NVRAM, &tm); + } + break; + case 0x1FFE: + /* month */ + tmp = fromBCD(val & 0x1F); + if (tmp >= 1 && tmp <= 12) { + get_time(NVRAM, &tm); + tm.tm_mon = tmp - 1; + set_time(NVRAM, &tm); + } + break; + case 0x1FFF: + /* year */ + tmp = fromBCD(val); + if (tmp >= 0 && tmp <= 99) { + get_time(NVRAM, &tm); + tm.tm_year = fromBCD(val); + set_time(NVRAM, &tm); + } + break; + default: + /* Check lock registers state */ + if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) + break; + if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) + break; + if (NVRAM->addr < NVRAM_MAX_MEM || + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { + NVRAM->buffer[NVRAM->addr] = val & 0xFF; + } + break; + } +} + +uint32_t m48t08_read (m48t08_t *NVRAM) +{ + struct tm tm; + uint32_t retval = 0xFF; + + switch (NVRAM->addr) { + case 0x1FF8: + /* control */ + goto do_read; + case 0x1FF9: + /* seconds (BCD) */ + get_time(NVRAM, &tm); + retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec); + break; + case 0x1FFA: + /* minutes (BCD) */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_min); + break; + case 0x1FFB: + /* hours (BCD) */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_hour); + break; + case 0x1FFC: + /* day of the week / century */ + get_time(NVRAM, &tm); + retval = NVRAM->buffer[0x1FFC] | tm.tm_wday; + break; + case 0x1FFD: + /* date */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_mday); + break; + case 0x1FFE: + /* month */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_mon + 1); + break; + case 0x1FFF: + /* year */ + get_time(NVRAM, &tm); + retval = toBCD(tm.tm_year); + break; + default: + /* Check lock registers state */ + if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) + break; + if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) + break; + if (NVRAM->addr < NVRAM_MAX_MEM || + (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { + do_read: + retval = NVRAM->buffer[NVRAM->addr]; + } + break; + } + if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000) + NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); + + return retval; +} + +void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr) +{ + NVRAM->addr = addr; +} + +void m48t08_toggle_lock (m48t08_t *NVRAM, int lock) +{ + NVRAM->lock ^= 1 << lock; +} + +static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t08_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + if (addr < NVRAM_MAX_MEM) + NVRAM->buffer[addr] = value; +} + +static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t08_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + if (addr < NVRAM_MAX_MEM) { + NVRAM->buffer[addr] = value >> 8; + NVRAM->buffer[addr + 1] = value; + } +} + +static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t08_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + if (addr < NVRAM_MAX_MEM) { + NVRAM->buffer[addr] = value >> 24; + NVRAM->buffer[addr + 1] = value >> 16; + NVRAM->buffer[addr + 2] = value >> 8; + NVRAM->buffer[addr + 3] = value; + } +} + +static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) +{ + m48t08_t *NVRAM = opaque; + uint32_t retval = 0; + + addr -= NVRAM->mem_base; + if (addr < NVRAM_MAX_MEM) + retval = NVRAM->buffer[addr]; + + return retval; +} + +static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) +{ + m48t08_t *NVRAM = opaque; + uint32_t retval = 0; + + addr -= NVRAM->mem_base; + if (addr < NVRAM_MAX_MEM) { + retval = NVRAM->buffer[addr] << 8; + retval |= NVRAM->buffer[addr + 1]; + } + + return retval; +} + +static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) +{ + m48t08_t *NVRAM = opaque; + uint32_t retval = 0; + + addr -= NVRAM->mem_base; + if (addr < NVRAM_MAX_MEM) { + retval = NVRAM->buffer[addr] << 24; + retval |= NVRAM->buffer[addr + 1] << 16; + retval |= NVRAM->buffer[addr + 2] << 8; + retval |= NVRAM->buffer[addr + 3]; + } + + return retval; +} + +static CPUWriteMemoryFunc *nvram_write[] = { + &nvram_writeb, + &nvram_writew, + &nvram_writel, +}; + +static CPUReadMemoryFunc *nvram_read[] = { + &nvram_readb, + &nvram_readw, + &nvram_readl, +}; + +/* Initialisation routine */ +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) +{ + m48t08_t *s; + int i; + unsigned char tmp = 0; + + s = qemu_mallocz(sizeof(m48t08_t)); + if (!s) + return NULL; + s->buffer = qemu_mallocz(size); + if (!s->buffer) { + qemu_free(s); + return NULL; + } + s->size = size; + s->mem_base = mem_base; + s->addr = 0; + if (mem_base != 0) { + s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); + } + s->lock = 0; + + i = 0x1fd8; + s->buffer[i++] = 0x01; + s->buffer[i++] = 0x80; /* Sun4m OBP */ + /* XXX: Ethernet address, etc */ + + /* Calculate checksum */ + for (i = 0x1fd8; i < 0x1fe7; i++) { + tmp ^= s->buffer[i]; + } + s->buffer[0x1fe7] = tmp; + return s; +} + +#if 0 +struct idprom +{ + unsigned char id_format; /* Format identifier (always 0x01) */ + unsigned char id_machtype; /* Machine type */ + unsigned char id_ethaddr[6]; /* Hardware ethernet address */ + long id_date; /* Date of manufacture */ + unsigned int id_sernum:24; /* Unique serial number */ + unsigned char id_cksum; /* Checksum - xor of the data bytes */ + unsigned char reserved[16]; +}; +#endif diff --git a/hw/m48t08.h b/hw/m48t08.h new file mode 100644 index 000000000..2a754b698 --- /dev/null +++ b/hw/m48t08.h @@ -0,0 +1,12 @@ +#if !defined (__M48T08_H__) +#define __M48T08_H__ + +typedef struct m48t08_t m48t08_t; + +void m48t08_write (m48t08_t *NVRAM, uint32_t val); +uint32_t m48t08_read (m48t08_t *NVRAM); +void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr); +void m48t08_toggle_lock (m48t08_t *NVRAM, int lock); +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size); + +#endif /* !defined (__M48T08_H__) */ diff --git a/hw/magic-load.c b/hw/magic-load.c new file mode 100644 index 000000000..7365183da --- /dev/null +++ b/hw/magic-load.c @@ -0,0 +1,341 @@ +/* This is the Linux kernel elf-loading code, ported into user space */ +#include "vl.h" +#include "disas.h" + +/* XXX: this code is not used as it is under the GPL license. Please + remove or recode it */ +//#define USE_ELF_LOADER + +#ifdef USE_ELF_LOADER +/* should probably go in elf.h */ +#ifndef ELIBBAD +#define ELIBBAD 80 +#endif + + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SPARC ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARC + +#include "elf.h" + +/* + * This structure is used to hold the arguments that are + * used when loading binaries. + */ +struct linux_binprm { + char buf[128]; + int fd; +}; + +#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE +#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) + +#ifdef BSWAP_NEEDED +static void bswap_ehdr(Elf32_Ehdr *ehdr) +{ + bswap16s(&ehdr->e_type); /* Object file type */ + bswap16s(&ehdr->e_machine); /* Architecture */ + bswap32s(&ehdr->e_version); /* Object file version */ + bswap32s(&ehdr->e_entry); /* Entry point virtual address */ + bswap32s(&ehdr->e_phoff); /* Program header table file offset */ + bswap32s(&ehdr->e_shoff); /* Section header table file offset */ + bswap32s(&ehdr->e_flags); /* Processor-specific flags */ + bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ + bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ +} + +static void bswap_phdr(Elf32_Phdr *phdr) +{ + bswap32s(&phdr->p_type); /* Segment type */ + bswap32s(&phdr->p_offset); /* Segment file offset */ + bswap32s(&phdr->p_vaddr); /* Segment virtual address */ + bswap32s(&phdr->p_paddr); /* Segment physical address */ + bswap32s(&phdr->p_filesz); /* Segment size in file */ + bswap32s(&phdr->p_memsz); /* Segment size in memory */ + bswap32s(&phdr->p_flags); /* Segment flags */ + bswap32s(&phdr->p_align); /* Segment alignment */ +} + +static void bswap_shdr(Elf32_Shdr *shdr) +{ + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswap32s(&shdr->sh_flags); + bswap32s(&shdr->sh_addr); + bswap32s(&shdr->sh_offset); + bswap32s(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswap32s(&shdr->sh_addralign); + bswap32s(&shdr->sh_entsize); +} + +static void bswap_sym(Elf32_Sym *sym) +{ + bswap32s(&sym->st_name); + bswap32s(&sym->st_value); + bswap32s(&sym->st_size); + bswap16s(&sym->st_shndx); +} +#endif + +static int prepare_binprm(struct linux_binprm *bprm) +{ + int retval; + + memset(bprm->buf, 0, sizeof(bprm->buf)); + retval = lseek(bprm->fd, 0L, SEEK_SET); + if(retval >= 0) { + retval = read(bprm->fd, bprm->buf, 128); + } + if(retval < 0) { + perror("prepare_binprm"); + exit(-1); + /* return(-errno); */ + } + else { + return(retval); + } +} + +/* Best attempt to load symbols from this ELF object. */ +static void load_symbols(struct elfhdr *hdr, int fd) +{ + unsigned int i; + struct elf_shdr sechdr, symtab, strtab; + char *strings; + + lseek(fd, hdr->e_shoff, SEEK_SET); + for (i = 0; i < hdr->e_shnum; i++) { + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&sechdr); +#endif + if (sechdr.sh_type == SHT_SYMTAB) { + symtab = sechdr; + lseek(fd, hdr->e_shoff + + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); + if (read(fd, &strtab, sizeof(strtab)) + != sizeof(strtab)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&strtab); +#endif + goto found; + } + } + return; /* Shouldn't happen... */ + + found: + /* Now know where the strtab and symtab are. Snarf them. */ + disas_symtab = qemu_malloc(symtab.sh_size); + disas_strtab = strings = qemu_malloc(strtab.sh_size); + if (!disas_symtab || !disas_strtab) + return; + + lseek(fd, symtab.sh_offset, SEEK_SET); + if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) + return; + +#ifdef BSWAP_NEEDED + for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) + bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); +#endif + + lseek(fd, strtab.sh_offset, SEEK_SET); + if (read(fd, strings, strtab.sh_size) != strtab.sh_size) + return; + disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); +} + +static int load_elf_binary(struct linux_binprm * bprm, uint8_t *addr) +{ + struct elfhdr elf_ex; + unsigned long startaddr = addr; + int i; + struct elf_phdr * elf_ppnt; + struct elf_phdr *elf_phdata; + int retval; + + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ +#ifdef BSWAP_NEEDED + bswap_ehdr(&elf_ex); +#endif + + if (elf_ex.e_ident[0] != 0x7f || + strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { + return -ENOEXEC; + } + + /* First of all, some simple consistency checks */ + if (! elf_check_arch(elf_ex.e_machine)) { + return -ENOEXEC; + } + + /* Now read in all of the header information */ + elf_phdata = (struct elf_phdr *)qemu_malloc(elf_ex.e_phentsize*elf_ex.e_phnum); + if (elf_phdata == NULL) { + return -ENOMEM; + } + + retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); + if(retval > 0) { + retval = read(bprm->fd, (char *) elf_phdata, + elf_ex.e_phentsize * elf_ex.e_phnum); + } + + if (retval < 0) { + perror("load_elf_binary"); + exit(-1); + qemu_free (elf_phdata); + return -errno; + } + +#ifdef BSWAP_NEEDED + elf_ppnt = elf_phdata; + for (i=0; ip_type != PT_LOAD) + continue; +#if 0 + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), + bprm->fd, + (elf_ppnt->p_offset - + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); +#endif + //offset = elf_ppnt->p_offset - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr); + offset = 0x4000; + lseek(bprm->fd, offset, SEEK_SET); + len = elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr); + error = read(bprm->fd, addr, len); + + if (error == -1) { + perror("mmap"); + exit(-1); + } + addr += len; + } + + qemu_free(elf_phdata); + + load_symbols(&elf_ex, bprm->fd); + + return addr-startaddr; +} + +int elf_exec(const char * filename, uint8_t *addr) +{ + struct linux_binprm bprm; + int retval; + + retval = open(filename, O_RDONLY); + if (retval < 0) + return retval; + bprm.fd = retval; + + retval = prepare_binprm(&bprm); + + if(retval>=0) { + retval = load_elf_binary(&bprm, addr); + } + return retval; +} +#endif + +int load_kernel(const char *filename, uint8_t *addr) +{ + int fd, size; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return -1; + /* load 32 bit code */ + size = read(fd, addr, 16 * 1024 * 1024); + if (size < 0) + goto fail; + close(fd); + return size; + fail: + close(fd); + return -1; +} + +static char saved_kfn[1024]; +static uint32_t saved_addr; +static int magic_state; + +static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr) +{ + int ret; + + if (magic_state == 0) { +#ifdef USE_ELF_LOADER + ret = elf_exec(saved_kfn, saved_addr); +#else + ret = load_kernel(saved_kfn, (uint8_t *)saved_addr); +#endif + if (ret < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + saved_kfn); + } + magic_state = 1; /* No more magic */ + tb_flush(); + } + return ret; +} + +static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +} + + +static CPUReadMemoryFunc *magic_mem_read[3] = { + magic_mem_readl, + magic_mem_readl, + magic_mem_readl, +}; + +static CPUWriteMemoryFunc *magic_mem_write[3] = { + magic_mem_writel, + magic_mem_writel, + magic_mem_writel, +}; + +void magic_init(const char *kfn, int kloadaddr) +{ + int magic_io_memory; + + strcpy(saved_kfn, kfn); + saved_addr = kloadaddr; + magic_state = 0; + magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, 0); + cpu_register_physical_memory(0x20000000, 4, + magic_io_memory); +} + diff --git a/hw/sched.c b/hw/sched.c new file mode 100644 index 000000000..c9a685d44 --- /dev/null +++ b/hw/sched.c @@ -0,0 +1,346 @@ +/* + * QEMU interrupt controller & timer emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#define PHYS_JJ_CLOCK 0x71D00000 +#define PHYS_JJ_CLOCK1 0x71D10000 +#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */ +#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ + +/* These registers are used for sending/receiving irqs from/to + * different cpu's. + */ +struct sun4m_intreg_percpu { + unsigned int tbt; /* Intrs pending for this cpu, by PIL. */ + /* These next two registers are WRITE-ONLY and are only + * "on bit" sensitive, "off bits" written have NO affect. + */ + unsigned int clear; /* Clear this cpus irqs here. */ + unsigned int set; /* Set this cpus irqs here. */ +}; +/* + * djhr + * Actually the clear and set fields in this struct are misleading.. + * according to the SLAVIO manual (and the same applies for the SEC) + * the clear field clears bits in the mask which will ENABLE that IRQ + * the set field sets bits in the mask to DISABLE the IRQ. + * + * Also the undirected_xx address in the SLAVIO is defined as + * RESERVED and write only.. + * + * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor + * sun4m machines, for MP the layout makes more sense. + */ +struct sun4m_intreg_master { + unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */ + unsigned int irqs; /* Master IRQ bits. */ + + /* Again, like the above, two these registers are WRITE-ONLY. */ + unsigned int clear; /* Clear master IRQ's by setting bits here. */ + unsigned int set; /* Set master IRQ's by setting bits here. */ + + /* This register is both READ and WRITE. */ + unsigned int undirected_target; /* Which cpu gets undirected irqs. */ +}; +/* + * Registers of hardware timer in sun4m. + */ +struct sun4m_timer_percpu { + volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ + volatile unsigned int l14_cur_count; +}; + +struct sun4m_timer_global { + volatile unsigned int l10_timer_limit; + volatile unsigned int l10_cur_count; +}; + +#define SUN4M_INT_ENABLE 0x80000000 +#define SUN4M_INT_E14 0x00000080 +#define SUN4M_INT_E10 0x00080000 + +#define SUN4M_HARD_INT(x) (0x000000001 << (x)) +#define SUN4M_SOFT_INT(x) (0x000010000 << (x)) + +#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ +#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ +#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ +#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ +#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ +#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ +#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ +#define SUN4M_INT_REALTIME 0x00080000 /* system timer */ +#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ +#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ +#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ +#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ +#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ + +#define SUN4M_INT_SBUS(x) (1 << (x+7)) +#define SUN4M_INT_VME(x) (1 << (x)) + +typedef struct SCHEDState { + uint32_t intreg_pending; + uint32_t intreg_enabled; + uint32_t intregm_pending; + uint32_t intregm_enabled; + uint32_t timer_regs[2]; + uint32_t timerm_regs[2]; +} SCHEDState; + +static SCHEDState *ps; + +static int intreg_io_memory, intregm_io_memory, + timer_io_memory, timerm_io_memory; + +static void sched_reset(SCHEDState *s) +{ +} + +static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_INTR0) >> 2; + switch (saddr) { + case 0: + return s->intreg_pending; + break; + default: + break; + } + return 0; +} + +static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_INTR0) >> 2; + switch (saddr) { + case 0: + s->intreg_pending = val; + break; + case 1: // clear + s->intreg_enabled &= ~val; + break; + case 2: // set + s->intreg_enabled |= val; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *intreg_mem_read[3] = { + intreg_mem_readl, + intreg_mem_readl, + intreg_mem_readl, +}; + +static CPUWriteMemoryFunc *intreg_mem_write[3] = { + intreg_mem_writel, + intreg_mem_writel, + intreg_mem_writel, +}; + +static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_INTR_G) >> 2; + switch (saddr) { + case 0: + return s->intregm_pending; + break; + case 1: + return s->intregm_enabled; + break; + default: + break; + } + return 0; +} + +static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_INTR_G) >> 2; + switch (saddr) { + case 0: + s->intregm_pending = val; + break; + case 1: + s->intregm_enabled = val; + break; + case 2: // clear + s->intregm_enabled &= ~val; + break; + case 3: // set + s->intregm_enabled |= val; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *intregm_mem_read[3] = { + intregm_mem_readl, + intregm_mem_readl, + intregm_mem_readl, +}; + +static CPUWriteMemoryFunc *intregm_mem_write[3] = { + intregm_mem_writel, + intregm_mem_writel, + intregm_mem_writel, +}; + +static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_CLOCK) >> 2; + switch (saddr) { + default: + return s->timer_regs[saddr]; + break; + } + return 0; +} + +static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_CLOCK) >> 2; + switch (saddr) { + default: + s->timer_regs[saddr] = val; + break; + } +} + +static CPUReadMemoryFunc *timer_mem_read[3] = { + timer_mem_readl, + timer_mem_readl, + timer_mem_readl, +}; + +static CPUWriteMemoryFunc *timer_mem_write[3] = { + timer_mem_writel, + timer_mem_writel, + timer_mem_writel, +}; + +static uint32_t timerm_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_CLOCK1) >> 2; + switch (saddr) { + default: + return s->timerm_regs[saddr]; + break; + } + return 0; +} + +static void timerm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SCHEDState *s = opaque; + uint32_t saddr; + + saddr = (addr - PHYS_JJ_CLOCK1) >> 2; + switch (saddr) { + default: + s->timerm_regs[saddr] = val; + break; + } +} + +static CPUReadMemoryFunc *timerm_mem_read[3] = { + timerm_mem_readl, + timerm_mem_readl, + timerm_mem_readl, +}; + +static CPUWriteMemoryFunc *timerm_mem_write[3] = { + timerm_mem_writel, + timerm_mem_writel, + timerm_mem_writel, +}; + +void pic_info() {} +void irq_info() {} + +static const unsigned int intr_to_mask[16] = { + 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +void pic_set_irq(int irq, int level) +{ + if (irq < 16) { + unsigned int mask = intr_to_mask[irq]; + ps->intreg_pending |= 1 << irq; + if (ps->intregm_enabled & mask) { + cpu_single_env->interrupt_index = irq; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } + } +} + +void sched_init() +{ + SCHEDState *s; + + s = qemu_mallocz(sizeof(SCHEDState)); + if (!s) + return; + + intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_INTR0, 3, intreg_io_memory); + + intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_INTR_G, 5, intregm_io_memory); + + timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_CLOCK, 2, timer_io_memory); + + timerm_io_memory = cpu_register_io_memory(0, timerm_mem_read, timerm_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_CLOCK1, 2, timerm_io_memory); + + sched_reset(s); + ps = s; +} + diff --git a/hw/sun4m.c b/hw/sun4m.c new file mode 100644 index 000000000..05dbd56a5 --- /dev/null +++ b/hw/sun4m.c @@ -0,0 +1,130 @@ +/* + * QEMU Sun4m System Emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "m48t08.h" + +#define KERNEL_LOAD_ADDR 0x00004000 +#define MMU_CONTEXT_TBL 0x00003000 +#define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400) +#define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800) +#define ROMVEC_DATA (MMU_CONTEXT_TBL + 0x1800) +#define PROM_ADDR 0xffd04000 +#define PROM_FILENAME "proll.bin" +#define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */ +#define PHYS_JJ_IDPROM_OFF 0x1FD8 +#define PHYS_JJ_EEPROM_SIZE 0x2000 + +/* TSC handling */ + +uint64_t cpu_get_tsc() +{ + return qemu_get_clock(vm_clock); +} + +void DMA_run() {} +void SB16_run() {} +void vga_invalidate_display() {} +void vga_screen_dump(const char *filename) {} +int serial_can_receive(SerialState *s) { return 0; } +void serial_receive_byte(SerialState *s, int ch) {} +void serial_receive_break(SerialState *s) {} + +static m48t08_t *nvram; + +/* Sun4m hardware initialisation */ +void sun4m_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + char buf[1024]; + int ret, linux_boot, bios_size; + unsigned long bios_offset; + + linux_boot = (kernel_filename != NULL); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, 0); + bios_offset = ram_size; + + iommu_init(); + sched_init(); + tcx_init(ds); + lance_init(&nd_table[0], 6); + nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); + + magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + +#if 0 + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); + bios_size = get_image_size(buf); + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret != bios_size) { + fprintf(stderr, "qemu: could not load prom '%s'\n", buf); + exit(1); + } + cpu_register_physical_memory(PROM_ADDR, + bios_size, bios_offset | IO_MEM_ROM); +#endif + + /* We load Proll as the kernel and start it. It will issue a magic + IO to load the real kernel */ + if (linux_boot) { + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); + ret = load_kernel(buf, + phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + buf); + exit(1); + } + } + /* Setup a MMU entry for entire address space */ + stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1); + stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1); +#if 0 + stl_raw(phys_ram_base + MMU_L1PTP + (0x50 << 2), (MMU_L2PTP >> 4) | 1); // frame buffer at 50.. +#endif + stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00.. + /* 3 = U:RWX S:RWX */ + stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2); +#if 0 + stl_raw(phys_ram_base + MMU_L2PTP + 0x84, (PHYS_JJ_TCX_FB >> 4) \ + | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf + stl_raw(phys_ram_base + MMU_L2PTP + 0x88, (PHYS_JJ_TCX_FB >> 4) \ + | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf + stl_raw(phys_ram_base + MMU_L2PTP + 0x140, (PHYS_JJ_TCX_FB >> 4) \ + | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf + // "Empirical constant" + stl_raw(phys_ram_base + ROMVEC_DATA, 0x10010407); + + // Version: V3 prom + stl_raw(phys_ram_base + ROMVEC_DATA + 4, 3); + + stl_raw(phys_ram_base + ROMVEC_DATA + 0x1c, ROMVEC_DATA+0x400); + stl_raw(phys_ram_base + ROMVEC_DATA + 0x400, ROMVEC_DATA+0x404); + stl_raw(phys_ram_base + ROMVEC_DATA + 0x404, 0x81c3e008); // retl + stl_raw(phys_ram_base + ROMVEC_DATA + 0x408, 0x01000000); // nop +#endif +} diff --git a/hw/tcx.c b/hw/tcx.c new file mode 100644 index 000000000..d9b91c68f --- /dev/null +++ b/hw/tcx.c @@ -0,0 +1,176 @@ +/* + * QEMU Sun4m System Emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */ +#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */ + +#define MAXX 1024 +#define MAXY 768 +#define XSZ (8*80) +#define YSZ (24*11) +#define XOFF (MAXX-XSZ) +#define YOFF (MAXY-YSZ) + +#define DEBUG_VGA_MEM + +typedef struct TCXState { + uint8_t *vram_ptr; + unsigned long vram_offset; + unsigned int vram_size; + DisplayState *ds; +} TCXState; + +static TCXState *ts; + +static int tcx_io_memory; + +void vga_update_display() +{ + dpy_update(ts->ds, 0, 0, XSZ, YSZ); +} + +static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr) +{ + TCXState *s = opaque; + uint32_t saddr; + unsigned int x, y; + char *sptr; + + saddr = addr - PHYS_JJ_TCX_FB - YOFF*MAXX - XOFF; + y = saddr / MAXX; + x = saddr - y * MAXX; + if (x < MAXX && y < MAXY) { + sptr = s->ds->data; + if (sptr) + return sptr[y * s->ds->linesize + x*4]; + } + return 0; +} + +static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = tcx_mem_readb(opaque, addr) << 8; + v |= tcx_mem_readb(opaque, addr + 1); +#else + v = tcx_mem_readb(opaque, addr); + v |= tcx_mem_readb(opaque, addr + 1) << 8; +#endif + return v; +} + +static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = tcx_mem_readb(opaque, addr) << 24; + v |= tcx_mem_readb(opaque, addr + 1) << 16; + v |= tcx_mem_readb(opaque, addr + 2) << 8; + v |= tcx_mem_readb(opaque, addr + 3); +#else + v = tcx_mem_readb(opaque, addr); + v |= tcx_mem_readb(opaque, addr + 1) << 8; + v |= tcx_mem_readb(opaque, addr + 2) << 16; + v |= tcx_mem_readb(opaque, addr + 3) << 24; +#endif + return v; +} + +/* called for accesses between 0xa0000 and 0xc0000 */ +static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + TCXState *s = opaque; + uint32_t saddr; + unsigned int x, y; + char *sptr; + + saddr = addr - PHYS_JJ_TCX_FB - YOFF*MAXX - XOFF; + y = saddr / MAXX; + x = saddr - y * MAXX; + if (x < MAXX && y < MAXY) { + sptr = s->ds->data; + if (sptr) { + sptr[y * s->ds->linesize + x*4] = val; + sptr[y * s->ds->linesize + x*4+1] = val; + sptr[y * s->ds->linesize + x*4+2] = val; + cpu_physical_memory_set_dirty(addr); + } + } +} + +static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff); + tcx_mem_writeb(opaque, addr + 1, val & 0xff); +#else + tcx_mem_writeb(opaque, addr, val & 0xff); + tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); +#endif +} + +static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff); + tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); + tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); + tcx_mem_writeb(opaque, addr + 3, val & 0xff); +#else + tcx_mem_writeb(opaque, addr, val & 0xff); + tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); + tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); + tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); +#endif +} + +static CPUReadMemoryFunc *tcx_mem_read[3] = { + tcx_mem_readb, + tcx_mem_readw, + tcx_mem_readl, +}; + +static CPUWriteMemoryFunc *tcx_mem_write[3] = { + tcx_mem_writeb, + tcx_mem_writew, + tcx_mem_writel, +}; + +void tcx_init(DisplayState *ds) +{ + TCXState *s; + + s = qemu_mallocz(sizeof(TCXState)); + if (!s) + return; + s->ds = ds; + ts = s; + tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s); + cpu_register_physical_memory(PHYS_JJ_TCX_FB, 0x100000, + tcx_io_memory); + dpy_resize(s->ds, XSZ, YSZ); +} + -- cgit v1.2.3 From 4971b827da65526bbe3e6a2ee2d9ba182f056ac5 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Sep 2004 22:19:55 +0000 Subject: pointer arith fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1086 c046a42c-6fe2-441c-8c8c-71466251a162 --- oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oss.c b/oss.c index de655ce9b..40c9462cf 100644 --- a/oss.c +++ b/oss.c @@ -403,7 +403,7 @@ void AUD_run (void) left = oss.bufsize - oss.rpos; play = MIN (left, bytes); - written = write (oss.fd, (void *) ((uint32_t) oss.buf + oss.rpos), play); + written = write (oss.fd, (uint8_t *)oss.buf + oss.rpos, play); if (-1 == written) { if (EAGAIN == errno || EINTR == errno) { -- cgit v1.2.3 From e95c8d51c2a47d7ccb422f83446cb91a18f8f37d Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Sep 2004 22:22:08 +0000 Subject: full system SPARC emulation (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1087 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + Changelog | 1 + Makefile.target | 29 +++++++++- configure | 6 +- cpu-exec.c | 13 +++++ exec-all.h | 6 +- exec.c | 6 +- gdbstub.c | 167 +++++++++++++++++++++++++++++++++++++------------------ monitor.c | 109 ++++++++++++++++++++++++++++++++---- slirp/bootp.c | 3 +- softmmu_header.h | 4 ++ translate-all.c | 3 + vl.c | 15 ++++- vl.h | 22 ++++++++ 14 files changed, 307 insertions(+), 78 deletions(-) diff --git a/.cvsignore b/.cvsignore index 9fad653e3..bca488238 100644 --- a/.cvsignore +++ b/.cvsignore @@ -12,3 +12,4 @@ qemu.1 qemu.pod sparc-user qemu-img +sparc-softmmu diff --git a/Changelog b/Changelog index bf8efc5bd..8bbe6d95f 100644 --- a/Changelog +++ b/Changelog @@ -17,6 +17,7 @@ version 0.6.1: - 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) version 0.6.0: diff --git a/Makefile.target b/Makefile.target index 28585c7e9..ff07be844 100644 --- a/Makefile.target +++ b/Makefile.target @@ -63,6 +63,26 @@ endif endif # ARCH = amd64 endif # TARGET_ARCH = ppc + +ifeq ($(TARGET_ARCH), sparc) + +ifeq ($(ARCH), ppc) +PROGS+=$(QEMU_SYSTEM) +endif + +ifeq ($(ARCH), i386) +ifdef CONFIG_SOFTMMU +PROGS+=$(QEMU_SYSTEM) +endif +endif # ARCH = i386 + +ifeq ($(ARCH), amd64) +ifdef CONFIG_SOFTMMU +PROGS+=$(QEMU_SYSTEM) +endif +endif # ARCH = amd64 + +endif # TARGET_ARCH = sparc endif # !CONFIG_USER_ONLY ifdef CONFIG_STATIC @@ -201,6 +221,10 @@ ifeq ($(TARGET_ARCH), ppc) LIBOBJS+= op_helper.o helper.o endif +ifeq ($(TARGET_ARCH), sparc) +LIBOBJS+= op_helper.o helper.o +endif + # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) @@ -254,6 +278,9 @@ VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o 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 endif +ifeq ($(TARGET_ARCH), sparc) +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o +endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o endif @@ -325,7 +352,7 @@ op.o: op.c op_template.h endif ifeq ($(TARGET_ARCH), sparc) -op.o: op.c op_template.h +op.o: op.c op_template.h op_mem.h endif ifeq ($(TARGET_ARCH), ppc) diff --git a/configure b/configure index 54f1a9fbd..5d7eed688 100755 --- a/configure +++ b/configure @@ -27,7 +27,7 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu" +target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu sparc-softmmu" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" @@ -99,7 +99,7 @@ if [ "$bsd" = "yes" ] ; then if [ ! "$darwin" = "yes" ] ; then make="gmake" fi - target_list="i386-softmmu ppc-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu" fi # find source path @@ -160,7 +160,7 @@ ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" if test "$mingw32" = "yes" ; then - target_list="i386-softmmu ppc-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu" EXESUF=".exe" gdbstub="no" fi diff --git a/cpu-exec.c b/cpu-exec.c index 053c0cc5d..930bd7bd8 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -208,6 +208,11 @@ int cpu_exec(CPUState *env1) env->exception_next_eip, 0); #elif defined(TARGET_PPC) do_interrupt(env); +#elif defined(TARGET_SPARC) + do_interrupt(env->exception_index, + 0, + env->error_code, + env->exception_next_pc, 0); #endif } env->exception_index = -1; @@ -261,6 +266,14 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_TIMER; } } +#elif defined(TARGET_SPARC) + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(0, 0, 0, 0, 0); + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + } else if (interrupt_request & CPU_INTERRUPT_TIMER) { + //do_interrupt(0, 0, 0, 0, 0); + env->interrupt_request &= ~CPU_INTERRUPT_TIMER; + } #endif if (interrupt_request & CPU_INTERRUPT_EXITTB) { env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; diff --git a/exec-all.h b/exec-all.h index b6853a1af..2e886e07c 100644 --- a/exec-all.h +++ b/exec-all.h @@ -56,6 +56,7 @@ struct TranslationBlock; extern uint16_t gen_opc_buf[OPC_BUF_SIZE]; extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; extern uint32_t gen_opc_pc[OPC_BUF_SIZE]; +extern uint32_t gen_opc_npc[OPC_BUF_SIZE]; extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; @@ -541,8 +542,7 @@ extern spinlock_t tb_lock; extern int tb_invalidated_flag; -#if (defined(TARGET_I386) || defined(TARGET_PPC)) && \ - !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr); @@ -585,6 +585,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) is_user = ((env->hflags & HF_CPL_MASK) == 3); #elif defined (TARGET_PPC) is_user = msr_pr; +#elif defined (TARGET_SPARC) + is_user = (env->psrs == 0); #else #error "Unimplemented !" #endif diff --git a/exec.c b/exec.c index c33661bc4..f266bb970 100644 --- a/exec.c +++ b/exec.c @@ -1077,7 +1077,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) { -#if defined(TARGET_I386) || defined(TARGET_PPC) +#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) int i; for(i = 0; i < env->nb_breakpoints; i++) { @@ -1099,7 +1099,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) /* remove a breakpoint */ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) { -#if defined(TARGET_I386) || defined(TARGET_PPC) +#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) int i; for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) @@ -1122,7 +1122,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) CPU loop after each instruction */ void cpu_single_step(CPUState *env, int enabled) { -#if defined(TARGET_I386) || defined(TARGET_PPC) +#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) if (env->singlestep_enabled != enabled) { env->singlestep_enabled = enabled; /* must flush all the translated code to avoid inconsistancies */ diff --git a/gdbstub.c b/gdbstub.c index 19623102d..e15216a59 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -157,42 +157,40 @@ static int put_packet(GDBState *s, char *buf) #if defined(TARGET_I386) -static void to_le32(uint8_t *p, int v) -{ - p[0] = v; - p[1] = v >> 8; - p[2] = v >> 16; - p[3] = v >> 24; -} - static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { + uint32_t *registers = (uint32_t *)mem_buf; int i, fpus; for(i = 0; i < 8; i++) { - to_le32(mem_buf + i * 4, env->regs[i]); + registers[i] = env->regs[i]; } - to_le32(mem_buf + 8 * 4, env->eip); - to_le32(mem_buf + 9 * 4, env->eflags); - to_le32(mem_buf + 10 * 4, env->segs[R_CS].selector); - to_le32(mem_buf + 11 * 4, env->segs[R_SS].selector); - to_le32(mem_buf + 12 * 4, env->segs[R_DS].selector); - to_le32(mem_buf + 13 * 4, env->segs[R_ES].selector); - to_le32(mem_buf + 14 * 4, env->segs[R_FS].selector); - to_le32(mem_buf + 15 * 4, env->segs[R_GS].selector); + registers[8] = env->eip; + registers[9] = env->eflags; + registers[10] = env->segs[R_CS].selector; + registers[11] = env->segs[R_SS].selector; + registers[12] = env->segs[R_DS].selector; + registers[13] = env->segs[R_ES].selector; + registers[14] = env->segs[R_FS].selector; + registers[15] = env->segs[R_GS].selector; /* XXX: convert floats */ for(i = 0; i < 8; i++) { memcpy(mem_buf + 16 * 4 + i * 10, &env->fpregs[i], 10); } - to_le32(mem_buf + 36 * 4, env->fpuc); + registers[36] = env->fpuc; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - to_le32(mem_buf + 37 * 4, fpus); - to_le32(mem_buf + 38 * 4, 0); /* XXX: convert tags */ - to_le32(mem_buf + 39 * 4, 0); /* fiseg */ - to_le32(mem_buf + 40 * 4, 0); /* fioff */ - to_le32(mem_buf + 41 * 4, 0); /* foseg */ - to_le32(mem_buf + 42 * 4, 0); /* fooff */ - to_le32(mem_buf + 43 * 4, 0); /* fop */ + registers[37] = fpus; + registers[38] = 0; /* XXX: convert tags */ + registers[39] = 0; /* fiseg */ + registers[40] = 0; /* fioff */ + registers[41] = 0; /* foseg */ + registers[42] = 0; /* fooff */ + registers[43] = 0; /* fop */ + + for(i = 0; i < 16; i++) + tswapls(®isters[i]); + for(i = 36; i < 44; i++) + tswapls(®isters[i]); return 44 * 4; } @@ -204,8 +202,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) for(i = 0; i < 8; i++) { env->regs[i] = tswapl(registers[i]); } - env->eip = registers[8]; - env->eflags = registers[9]; + env->eip = tswapl(registers[8]); + env->eflags = tswapl(registers[9]); #if defined(CONFIG_USER_ONLY) #define LOAD_SEG(index, sreg)\ if (tswapl(registers[index]) != env->segs[sreg].selector)\ @@ -220,15 +218,6 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } #elif defined (TARGET_PPC) -static void to_le32(uint32_t *buf, uint32_t v) -{ - uint8_t *p = (uint8_t *)buf; - p[3] = v; - p[2] = v >> 8; - p[1] = v >> 16; - p[0] = v >> 24; -} - static uint32_t from_le32 (uint32_t *buf) { uint8_t *p = (uint8_t *)buf; @@ -243,24 +232,24 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) /* fill in gprs */ for(i = 0; i < 32; i++) { - to_le32(®isters[i], env->gpr[i]); + registers[i] = tswapl(env->gpr[i]); } /* fill in fprs */ for (i = 0; i < 32; i++) { - to_le32(®isters[(i * 2) + 32], *((uint32_t *)&env->fpr[i])); - to_le32(®isters[(i * 2) + 33], *((uint32_t *)&env->fpr[i] + 1)); + registers[(i * 2) + 32] = tswapl(*((uint32_t *)&env->fpr[i])); + registers[(i * 2) + 33] = tswapl(*((uint32_t *)&env->fpr[i] + 1)); } /* nip, msr, ccr, lnk, ctr, xer, mq */ - to_le32(®isters[96], (uint32_t)env->nip/* - 4*/); - to_le32(®isters[97], _load_msr(env)); + registers[96] = tswapl(env->nip); + registers[97] = tswapl(_load_msr(env)); tmp = 0; for (i = 0; i < 8; i++) tmp |= env->crf[i] << (32 - ((i + 1) * 4)); - to_le32(®isters[98], tmp); - to_le32(®isters[99], env->lr); - to_le32(®isters[100], env->ctr); - to_le32(®isters[101], _load_xer(env)); - to_le32(®isters[102], 0); + registers[98] = tswapl(tmp); + registers[99] = tswapl(env->lr); + registers[100] = tswapl(env->ctr); + registers[101] = tswapl(_load_xer(env)); + registers[102] = 0; return 103 * 4; } @@ -272,22 +261,90 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) /* fill in gprs */ for (i = 0; i < 32; i++) { - env->gpr[i] = from_le32(®isters[i]); + env->gpr[i] = tswapl(registers[i]); } /* fill in fprs */ for (i = 0; i < 32; i++) { - *((uint32_t *)&env->fpr[i]) = from_le32(®isters[(i * 2) + 32]); - *((uint32_t *)&env->fpr[i] + 1) = from_le32(®isters[(i * 2) + 33]); + *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]); + *((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]); } /* nip, msr, ccr, lnk, ctr, xer, mq */ - env->nip = from_le32(®isters[96]); - _store_msr(env, from_le32(®isters[97])); - registers[98] = from_le32(®isters[98]); + env->nip = tswapl(registers[96]); + _store_msr(env, tswapl(registers[97])); + registers[98] = tswapl(registers[98]); for (i = 0; i < 8; i++) env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; - env->lr = from_le32(®isters[99]); - env->ctr = from_le32(®isters[100]); - _store_xer(env, from_le32(®isters[101])); + env->lr = tswapl(registers[99]); + env->ctr = tswapl(registers[100]); + _store_xer(env, tswapl(registers[101])); +} +#elif defined (TARGET_SPARC) +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + uint32_t *registers = (uint32_t *)mem_buf, tmp; + int i; + + /* fill in g0..g7 */ + for(i = 0; i < 7; i++) { + registers[i] = tswapl(env->gregs[i]); + } + /* fill in register window */ + for(i = 0; i < 24; i++) { + registers[i + 8] = tswapl(env->regwptr[i]); + } + /* fill in fprs */ + for (i = 0; i < 32; i++) { + registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i])); + } + /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + registers[64] = tswapl(env->y); + tmp = (0<<28) | (4<<24) | env->psr \ + | (env->psrs? PSR_S : 0) \ + | (env->psrs? PSR_PS : 0) \ + | (env->psret? PSR_ET : 0) \ + | env->cwp; + registers[65] = tswapl(tmp); + registers[66] = tswapl(env->wim); + registers[67] = tswapl(env->tbr); + registers[68] = tswapl(env->pc); + registers[69] = tswapl(env->npc); + registers[70] = tswapl(env->fsr); + registers[71] = 0; /* csr */ + registers[72] = 0; + + return 73 * 4; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + uint32_t *registers = (uint32_t *)mem_buf, tmp; + int i; + + /* fill in g0..g7 */ + for(i = 0; i < 7; i++) { + env->gregs[i] = tswapl(registers[i]); + } + /* fill in register window */ + for(i = 0; i < 24; i++) { + env->regwptr[i] = tswapl(registers[i]); + } + /* fill in fprs */ + for (i = 0; i < 32; i++) { + *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]); + } + /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + env->y = tswapl(registers[64]); + tmp = tswapl(registers[65]); + env->psr = tmp & ~PSR_ICC; + env->psrs = (tmp & PSR_S)? 1 : 0; + env->psrps = (tmp & PSR_PS)? 1 : 0; + env->psret = (tmp & PSR_ET)? 1 : 0; + env->cwp = (tmp & PSR_CWP); + env->wim = tswapl(registers[66]); + env->tbr = tswapl(registers[67]); + env->pc = tswapl(registers[68]); + env->npc = tswapl(registers[69]); + env->fsr = tswapl(registers[70]); } #else diff --git a/monitor.c b/monitor.c index ad0f31586..15b54d3e7 100644 --- a/monitor.c +++ b/monitor.c @@ -883,18 +883,18 @@ static jmp_buf expr_env; typedef struct MonitorDef { const char *name; int offset; - int (*get_value)(struct MonitorDef *md); + int (*get_value)(struct MonitorDef *md, int val); } MonitorDef; #if defined(TARGET_I386) -static int monitor_get_pc (struct MonitorDef *md) +static int monitor_get_pc (struct MonitorDef *md, int val) { return cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base; } #endif #if defined(TARGET_PPC) -static int monitor_get_ccr (struct MonitorDef *md) +static int monitor_get_ccr (struct MonitorDef *md, int val) { unsigned int u; int i; @@ -906,7 +906,7 @@ static int monitor_get_ccr (struct MonitorDef *md) return u; } -static int monitor_get_msr (struct MonitorDef *md) +static int monitor_get_msr (struct MonitorDef *md, int val) { return (cpu_single_env->msr[MSR_POW] << MSR_POW) | (cpu_single_env->msr[MSR_ILE] << MSR_ILE) | @@ -925,7 +925,7 @@ static int monitor_get_msr (struct MonitorDef *md) (cpu_single_env->msr[MSR_LE] << MSR_LE); } -static int monitor_get_xer (struct MonitorDef *md) +static int monitor_get_xer (struct MonitorDef *md, int val) { return (cpu_single_env->xer[XER_SO] << XER_SO) | (cpu_single_env->xer[XER_OV] << XER_OV) | @@ -933,25 +933,38 @@ static int monitor_get_xer (struct MonitorDef *md) (cpu_single_env->xer[XER_BC] << XER_BC); } -uint32_t cpu_ppc_load_decr (CPUState *env); -static int monitor_get_decr (struct MonitorDef *md) +static int monitor_get_decr (struct MonitorDef *md, int val) { return cpu_ppc_load_decr(cpu_single_env); } -uint32_t cpu_ppc_load_tbu (CPUState *env); -static int monitor_get_tbu (struct MonitorDef *md) +static int monitor_get_tbu (struct MonitorDef *md, int val) { return cpu_ppc_load_tbu(cpu_single_env); } -uint32_t cpu_ppc_load_tbl (CPUState *env); -static int monitor_get_tbl (struct MonitorDef *md) +static int monitor_get_tbl (struct MonitorDef *md, int val) { return cpu_ppc_load_tbl(cpu_single_env); } #endif +#if defined(TARGET_SPARC) +static int monitor_get_psr (struct MonitorDef *md, int val) +{ + return (0<<28) | (4<<24) | cpu_single_env->psr \ + | (cpu_single_env->psrs? PSR_S : 0) \ + | (cpu_single_env->psrs? PSR_PS : 0) \ + | (cpu_single_env->psret? PSR_ET : 0) \ + | cpu_single_env->cwp; +} + +static int monitor_get_reg(struct MonitorDef *md, int val) +{ + return cpu_single_env->regwptr[val]; +} +#endif + static MonitorDef monitor_defs[] = { #ifdef TARGET_I386 @@ -1037,6 +1050,78 @@ static MonitorDef monitor_defs[] = { { "sr14", offsetof(CPUState, sr[14]) }, { "sr15", offsetof(CPUState, sr[15]) }, /* Too lazy to put BATs and SPRs ... */ +#elif defined(TARGET_SPARC) + { "g0", offsetof(CPUState, gregs[0]) }, + { "g1", offsetof(CPUState, gregs[1]) }, + { "g2", offsetof(CPUState, gregs[2]) }, + { "g3", offsetof(CPUState, gregs[3]) }, + { "g4", offsetof(CPUState, gregs[4]) }, + { "g5", offsetof(CPUState, gregs[5]) }, + { "g6", offsetof(CPUState, gregs[6]) }, + { "g7", offsetof(CPUState, gregs[7]) }, + { "o0", 0, monitor_get_reg }, + { "o1", 1, monitor_get_reg }, + { "o2", 2, monitor_get_reg }, + { "o3", 3, monitor_get_reg }, + { "o4", 4, monitor_get_reg }, + { "o5", 5, monitor_get_reg }, + { "o6", 6, monitor_get_reg }, + { "o7", 7, monitor_get_reg }, + { "l0", 8, monitor_get_reg }, + { "l1", 9, monitor_get_reg }, + { "l2", 10, monitor_get_reg }, + { "l3", 11, monitor_get_reg }, + { "l4", 12, monitor_get_reg }, + { "l5", 13, monitor_get_reg }, + { "l6", 14, monitor_get_reg }, + { "l7", 15, monitor_get_reg }, + { "i0", 16, monitor_get_reg }, + { "i1", 17, monitor_get_reg }, + { "i2", 18, monitor_get_reg }, + { "i3", 19, monitor_get_reg }, + { "i4", 20, monitor_get_reg }, + { "i5", 21, monitor_get_reg }, + { "i6", 22, monitor_get_reg }, + { "i7", 23, monitor_get_reg }, + { "pc", offsetof(CPUState, pc) }, + { "npc", offsetof(CPUState, npc) }, + { "y", offsetof(CPUState, y) }, + { "psr", 0, &monitor_get_psr, }, + { "wim", offsetof(CPUState, wim) }, + { "tbr", offsetof(CPUState, tbr) }, + { "fsr", offsetof(CPUState, fsr) }, + { "f0", offsetof(CPUState, fpr[0]) }, + { "f1", offsetof(CPUState, fpr[1]) }, + { "f2", offsetof(CPUState, fpr[2]) }, + { "f3", offsetof(CPUState, fpr[3]) }, + { "f4", offsetof(CPUState, fpr[4]) }, + { "f5", offsetof(CPUState, fpr[5]) }, + { "f6", offsetof(CPUState, fpr[6]) }, + { "f7", offsetof(CPUState, fpr[7]) }, + { "f8", offsetof(CPUState, fpr[8]) }, + { "f9", offsetof(CPUState, fpr[9]) }, + { "f10", offsetof(CPUState, fpr[10]) }, + { "f11", offsetof(CPUState, fpr[11]) }, + { "f12", offsetof(CPUState, fpr[12]) }, + { "f13", offsetof(CPUState, fpr[13]) }, + { "f14", offsetof(CPUState, fpr[14]) }, + { "f15", offsetof(CPUState, fpr[15]) }, + { "f16", offsetof(CPUState, fpr[16]) }, + { "f17", offsetof(CPUState, fpr[17]) }, + { "f18", offsetof(CPUState, fpr[18]) }, + { "f19", offsetof(CPUState, fpr[19]) }, + { "f20", offsetof(CPUState, fpr[20]) }, + { "f21", offsetof(CPUState, fpr[21]) }, + { "f22", offsetof(CPUState, fpr[22]) }, + { "f23", offsetof(CPUState, fpr[23]) }, + { "f24", offsetof(CPUState, fpr[24]) }, + { "f25", offsetof(CPUState, fpr[25]) }, + { "f26", offsetof(CPUState, fpr[26]) }, + { "f27", offsetof(CPUState, fpr[27]) }, + { "f28", offsetof(CPUState, fpr[28]) }, + { "f29", offsetof(CPUState, fpr[29]) }, + { "f30", offsetof(CPUState, fpr[30]) }, + { "f31", offsetof(CPUState, fpr[31]) }, #endif { NULL }, }; @@ -1054,7 +1139,7 @@ static int get_monitor_def(int *pval, const char *name) for(md = monitor_defs; md->name != NULL; md++) { if (compare_cmd(name, md->name)) { if (md->get_value) { - *pval = md->get_value(md); + *pval = md->get_value(md, md->offset); } else { *pval = *(uint32_t *)((uint8_t *)cpu_single_env + md->offset); } diff --git a/slirp/bootp.c b/slirp/bootp.c index 8ae68af46..3924c1072 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -178,7 +178,8 @@ static void bootp_reply(struct bootp_t *bp) rbp->bp_hlen = 6; memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); - rbp->bp_yiaddr = daddr.sin_addr; /* IP address */ + rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ + rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ q = rbp->bp_vend; memcpy(q, rfc1533_cookie, 4); diff --git a/softmmu_header.h b/softmmu_header.h index 0bbc3681c..074d090ba 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -55,6 +55,8 @@ #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) #elif defined (TARGET_PPC) #define CPU_MEM_INDEX (msr_pr) +#elif defined (TARGET_SPARC) +#define CPU_MEM_INDEX ((env->psrs) == 0) #endif #define MMUSUFFIX _mmu @@ -64,6 +66,8 @@ #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) #elif defined (TARGET_PPC) #define CPU_MEM_INDEX (msr_pr) +#elif defined (TARGET_SPARC) +#define CPU_MEM_INDEX ((env->psrs) == 0) #endif #define MMUSUFFIX _cmmu diff --git a/translate-all.c b/translate-all.c index be3039c2c..1fbed4134 100644 --- a/translate-all.c +++ b/translate-all.c @@ -46,6 +46,8 @@ uint32_t gen_opc_pc[OPC_BUF_SIZE]; uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #if defined(TARGET_I386) uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; +#elif defined(TARGET_SPARC) +uint32_t gen_opc_npc[OPC_BUF_SIZE]; #endif int code_copy_enabled = 1; @@ -208,6 +210,7 @@ int cpu_restore_state(TranslationBlock *tb, #elif defined(TARGET_SPARC) /* XXX: restore npc too */ env->pc = gen_opc_pc[j]; + env->npc = gen_opc_npc[j]; #elif defined(TARGET_PPC) { int type; diff --git a/vl.c b/vl.c index 02edc7deb..22b14128f 100644 --- a/vl.c +++ b/vl.c @@ -710,7 +710,7 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) for(;;) { ts = *ptimer_head; - if (ts->expire_time > current_time) + if (!ts || ts->expire_time > current_time) break; /* remove timer from the list before calling the callback */ *ptimer_head = ts->next; @@ -2162,6 +2162,15 @@ void cpu_save(QEMUFile *f, void *opaque) { } +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} +#elif defined(TARGET_SPARC) +void cpu_save(QEMUFile *f, void *opaque) +{ +} + int cpu_load(QEMUFile *f, void *opaque, int version_id) { return 0; @@ -3336,6 +3345,10 @@ int main(int argc, char **argv) ppc_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, initrd_filename); +#elif defined(TARGET_SPARC) + sun4m_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); #endif gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); diff --git a/vl.h b/vl.h index 4cfe9c005..8151613a9 100644 --- a/vl.h +++ b/vl.h @@ -664,6 +664,28 @@ extern CPUWriteMemoryFunc *PPC_io_write[]; extern CPUReadMemoryFunc *PPC_io_read[]; extern int prep_enabled; +/* sun4m.c */ +void sun4m_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + +/* iommu.c */ +void iommu_init(); +uint32_t iommu_translate(uint32_t addr); + +/* lance.c */ +void lance_init(NetDriverState *nd, int irq); + +/* tcx.c */ +void tcx_init(DisplayState *ds); + +/* sched.c */ +void sched_init(); + +/* magic-load.c */ +void magic_init(const char *kfn, int kloadaddr); + /* NVRAM helpers */ #include "hw/m48t59.h" -- cgit v1.2.3 From 2518bd0dc210cfd167e3378c1bd9cfa5a89ebca2 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 30 Sep 2004 22:35:13 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1088 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + qemu-doc.texi | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 8bbe6d95f..150a52d06 100644 --- a/Changelog +++ b/Changelog @@ -18,6 +18,7 @@ version 0.6.1: 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. version 0.6.0: diff --git a/qemu-doc.texi b/qemu-doc.texi index 51fc12fa5..9e8eaf2f3 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -233,6 +233,24 @@ guest must be configured in binary mode (use the command @code{bin} of the Unix TFTP client). The host IP address on the guest is as usual 10.0.2.2. +@item -smb dir +When using the user mode network stack, activate a built-in SMB +server so that Windows OSes can access to the host files in @file{dir} +transparently. + +In the guest Windows OS, the line: +@example +10.0.2.4 smbserver +@end example +must be added in the file @file{C:\WINDOWS\LMHOSTS} (for windows 9x/Me) +or @file{C:\WINNT\SYSTEM32\DRIVERS\ETC\LMHOSTS} (Windows NT/2000). + +Then @file{dir} can be accessed in @file{\\smbserver\qemu}. + +Note that a SAMBA server must be installed on the host OS in +@file{/usr/sbin/smbd}. QEMU was tested succesfully with smbd version +2.2.7a from the Red Hat 9. + @item -redir [tcp|udp]:host-port:[guest-host]:guest-port When using the user mode network stack, redirect incoming TCP or UDP @@ -671,8 +689,9 @@ configuration is the following: QEMU Virtual Machine <------> Firewall/DHCP server <-----> Internet (10.0.2.x) | (10.0.2.2) | - ----> DNS - (10.0.2.3) + ----> DNS server (10.0.2.3) + | + ----> SMB server (10.0.2.4) @end example The QEMU VM behaves as if it was behind a firewall which blocks all -- cgit v1.2.3 From 487be8a1a76f5a47ebf1ecbdd8b6244432edd9d3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 11:44:41 +0000 Subject: hack for bootp support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1089 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/bootp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/slirp/bootp.c b/slirp/bootp.c index 3924c1072..56caf707e 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -136,6 +136,9 @@ static void bootp_reply(struct bootp_t *bp) dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type); + if (dhcp_msg_type == 0) + dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ + if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST) return; -- cgit v1.2.3 From d63d307f6e00856dae25e9cd3d96bc0ba31ff107 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 13:29:03 +0000 Subject: -loadvm and -full-screen options git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1090 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + qemu-doc.texi | 6 +++++- sdl.c | 11 +++++++++-- vl.c | 19 ++++++++++++++++++- vl.h | 2 +- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Changelog b/Changelog index 150a52d06..d3ed8892d 100644 --- a/Changelog +++ b/Changelog @@ -19,6 +19,7 @@ version 0.6.1: - 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 version 0.6.0: diff --git a/qemu-doc.texi b/qemu-doc.texi index 9e8eaf2f3..d7159a603 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -199,6 +199,9 @@ Set the real time clock to local time (the default is to UTC time). This option is needed to have correct date in MS-DOS or Windows. +@item -full-screen +Start in full screen. + @end table Network options: @@ -345,7 +348,8 @@ Simulate an ISA-only system (default is PCI system). @item -std-vga Simulate a standard VGA card with Bochs VBE extensions (default is Cirrus Logic GD5446 PCI VGA) - +@item -loadvm file +Start right away with a saved state (@code{loadvm} in monitor) @end table @c man end diff --git a/sdl.c b/sdl.c index fc23ea9ea..c089f56f4 100644 --- a/sdl.c +++ b/sdl.c @@ -40,6 +40,7 @@ static int gui_saved_grab; static int gui_fullscreen; static int gui_key_modifier_pressed; static int gui_keysym; +static int gui_fullscreen_initial_grab; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { @@ -525,7 +526,8 @@ static void sdl_refresh(DisplayState *ds) } break; case SDL_ACTIVEEVENT: - if (gui_grab && (ev->active.gain & SDL_ACTIVEEVENTMASK) == 0) { + if (gui_grab && (ev->active.gain & SDL_ACTIVEEVENTMASK) == 0 && + !gui_fullscreen_initial_grab) { sdl_grab_end(); } break; @@ -540,7 +542,7 @@ static void sdl_cleanup(void) SDL_Quit(); } -void sdl_display_init(DisplayState *ds) +void sdl_display_init(DisplayState *ds, int full_screen) { int flags; @@ -566,4 +568,9 @@ void sdl_display_init(DisplayState *ds) gui_grab = 0; atexit(sdl_cleanup); + if (full_screen) { + gui_fullscreen = 1; + gui_fullscreen_initial_grab = 1; + sdl_grab_start(); + } } diff --git a/vl.c b/vl.c index 22b14128f..9fc76c7d8 100644 --- a/vl.c +++ b/vl.c @@ -129,6 +129,7 @@ int cirrus_vga_enabled = 1; int graphic_width = 800; int graphic_height = 600; int graphic_depth = 15; +int full_screen = 0; TextConsole *vga_console; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; @@ -2505,6 +2506,7 @@ void help(void) "-nographic disable graphical output and redirect serial I/Os to console\n" "-enable-audio enable audio support\n" "-localtime set the real time clock to local time [default=utc]\n" + "-full-screen start in full screen\n" #ifdef TARGET_PPC "-prep Simulate a PREP system (default is PowerMAC)\n" "-g WxH[xDEPTH] Set the initial VGA graphic mode\n" @@ -2548,6 +2550,7 @@ void help(void) "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" #endif + "-loadvm file start right away with a saved state (loadvm in monitor)\n" "\n" "During emulation, the following keys are useful:\n" "ctrl-shift-f toggle full screen\n" @@ -2622,6 +2625,8 @@ enum { QEMU_OPTION_std_vga, QEMU_OPTION_monitor, QEMU_OPTION_serial, + QEMU_OPTION_loadvm, + QEMU_OPTION_full_screen, }; typedef struct QEMUOption { @@ -2680,6 +2685,8 @@ const QEMUOption qemu_options[] = { { "std-vga", 0, QEMU_OPTION_std_vga }, { "monitor", 1, QEMU_OPTION_monitor }, { "serial", 1, QEMU_OPTION_serial }, + { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, + { "full-screen", 0, QEMU_OPTION_full_screen }, /* temporary options */ { "pci", 0, QEMU_OPTION_pci }, @@ -2759,6 +2766,7 @@ int main(int argc, char **argv) char monitor_device[128]; char serial_devices[MAX_SERIAL_PORTS][128]; int serial_device_index; + const char *loadvm = NULL; #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ @@ -3080,6 +3088,12 @@ int main(int argc, char **argv) sizeof(serial_devices[0]), optarg); serial_device_index++; break; + case QEMU_OPTION_loadvm: + loadvm = optarg; + break; + case QEMU_OPTION_full_screen: + full_screen = 1; + break; } } } @@ -3264,7 +3278,7 @@ int main(int argc, char **argv) dumb_display_init(ds); } else { #ifdef CONFIG_SDL - sdl_display_init(ds); + sdl_display_init(ds, full_screen); #else dumb_display_init(ds); #endif @@ -3365,6 +3379,9 @@ int main(int argc, char **argv) } } else #endif + if (loadvm) + qemu_loadvm(loadvm); + { /* XXX: simplify init */ read_passwords(); diff --git a/vl.h b/vl.h index 8151613a9..3eb136723 100644 --- a/vl.h +++ b/vl.h @@ -537,7 +537,7 @@ void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); /* sdl.c */ -void sdl_display_init(DisplayState *ds); +void sdl_display_init(DisplayState *ds, int full_screen); /* ide.c */ #define MAX_DISKS 4 -- cgit v1.2.3 From 8a8a608f6e2dc3d258bd765afa0aea6e1c33475c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 13:36:49 +0000 Subject: use memset() (Daniel Egger) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1091 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/exec.c b/exec.c index f266bb970..5f2f69642 100644 --- a/exec.c +++ b/exec.c @@ -315,7 +315,6 @@ static void page_flush_tb(void) /* XXX: tb_flush is currently not thread safe */ void tb_flush(CPUState *env) { - int i; #if defined(DEBUG_FLUSH) printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", code_gen_ptr - code_gen_buffer, @@ -323,12 +322,10 @@ void tb_flush(CPUState *env) nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); #endif nb_tbs = 0; - for(i = 0;i < CODE_GEN_HASH_SIZE; i++) - tb_hash[i] = NULL; + memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); virt_page_flush(); - for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) - tb_phys_hash[i] = NULL; + memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); page_flush_tb(); code_gen_ptr = code_gen_buffer; @@ -1279,8 +1276,7 @@ void tlb_flush(CPUState *env, int flush_global) } virt_page_flush(); - for(i = 0;i < CODE_GEN_HASH_SIZE; i++) - tb_hash[i] = NULL; + memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); #if !defined(CONFIG_SOFTMMU) munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); -- cgit v1.2.3 From 30ca2aab8e7419d2c8cf597743633a6477840277 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 13:56:00 +0000 Subject: ne2000 savevm support (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1092 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/pci.c | 20 ++++++++++++++++++++ vl.h | 2 ++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 0b094d1e3..79d3026c0 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -538,6 +538,59 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) return 0; } +static void ne2000_save(QEMUFile* f,void* opaque) +{ + NE2000State* s=(NE2000State*)opaque; + + qemu_put_8s(f, &s->cmd); + qemu_put_be32s(f, &s->start); + qemu_put_be32s(f, &s->stop); + qemu_put_8s(f, &s->boundary); + qemu_put_8s(f, &s->tsr); + qemu_put_8s(f, &s->tpsr); + qemu_put_be16s(f, &s->tcnt); + qemu_put_be16s(f, &s->rcnt); + qemu_put_be32s(f, &s->rsar); + qemu_put_8s(f, &s->rsr); + qemu_put_8s(f, &s->isr); + qemu_put_8s(f, &s->dcfg); + qemu_put_8s(f, &s->imr); + qemu_put_buffer(f, s->phys, 6); + qemu_put_8s(f, &s->curpag); + qemu_put_buffer(f, s->mult, 8); + qemu_put_be32s(f, &s->irq); + qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE); +} + +static int ne2000_load(QEMUFile* f,void* opaque,int version_id) +{ + NE2000State* s=(NE2000State*)opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_8s(f, &s->cmd); + qemu_get_be32s(f, &s->start); + qemu_get_be32s(f, &s->stop); + qemu_get_8s(f, &s->boundary); + qemu_get_8s(f, &s->tsr); + qemu_get_8s(f, &s->tpsr); + qemu_get_be16s(f, &s->tcnt); + qemu_get_be16s(f, &s->rcnt); + qemu_get_be32s(f, &s->rsar); + qemu_get_8s(f, &s->rsr); + qemu_get_8s(f, &s->isr); + qemu_get_8s(f, &s->dcfg); + qemu_get_8s(f, &s->imr); + qemu_get_buffer(f, s->phys, 6); + qemu_get_8s(f, &s->curpag); + qemu_get_buffer(f, s->mult, 8); + qemu_get_be32s(f, &s->irq); + qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE); + + return 0; +} + void isa_ne2000_init(int base, int irq, NetDriverState *nd) { NE2000State *s; @@ -562,6 +615,9 @@ void isa_ne2000_init(int base, int irq, NetDriverState *nd) ne2000_reset(s); qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); + + register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); + } /***********************************************************/ @@ -612,7 +668,7 @@ void pci_ne2000_init(PCIBus *bus, NetDriverState *nd) pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 1; // interrupt pin 0 - pci_register_io_region((PCIDevice *)d, 0, 0x100, + pci_register_io_region(&d->dev, 0, 0x100, PCI_ADDRESS_SPACE_IO, ne2000_map); s = &d->ne2000; s->irq = 16; // PCI interrupt @@ -620,4 +676,9 @@ void pci_ne2000_init(PCIBus *bus, NetDriverState *nd) s->nd = nd; ne2000_reset(s); qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); + + /* XXX: instance number ? */ + register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); + register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, + &d->dev); } diff --git a/hw/pci.c b/hw/pci.c index a6f452f42..f159dc2cb 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -62,6 +62,24 @@ static PCIBus *pci_register_bus(void) return bus; } +void generic_pci_save(QEMUFile* f, void *opaque) +{ + PCIDevice* s=(PCIDevice*)opaque; + + qemu_put_buffer(f, s->config, 256); +} + +int generic_pci_load(QEMUFile* f, void *opaque, int version_id) +{ + PCIDevice* s=(PCIDevice*)opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_buffer(f, s->config, 256); + return 0; +} + /* -1 for devfn means auto assign */ PCIDevice *pci_register_device(PCIBus *bus, const char *name, int instance_size, int devfn, @@ -558,6 +576,8 @@ void piix3_init(PCIBus *bus) d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State), -1, NULL, NULL); + register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); + piix3_state = d; pci_conf = d->dev.config; diff --git a/vl.h b/vl.h index 3eb136723..8ebb268d2 100644 --- a/vl.h +++ b/vl.h @@ -480,6 +480,8 @@ uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len); void pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len); +void generic_pci_save(QEMUFile* f, void *opaque); +int generic_pci_load(QEMUFile* f, void *opaque, int version_id); extern struct PIIX3State *piix3_state; -- cgit v1.2.3 From f98593103b25750f69c0318a851e8182919eaa98 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 14:33:10 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1093 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ qemu-doc.texi | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index d3ed8892d..f0e8839c6 100644 --- a/Changelog +++ b/Changelog @@ -20,6 +20,9 @@ version 0.6.1: - 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. version 0.6.0: diff --git a/qemu-doc.texi b/qemu-doc.texi index d7159a603..c262ee7e9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -360,10 +360,10 @@ Start right away with a saved state (@code{loadvm} in monitor) During the graphical emulation, you can use the following keys: @table @key -@item Ctrl-Shift-f +@item Ctrl-Alt-f Toggle full screen -@item Ctrl-Shift-Fn +@item Ctrl-Alt-n Switch to virtual console 'n'. Standard console mappings are: @table @emph @item 1 @@ -374,7 +374,7 @@ Monitor Serial port @end table -@item Ctrl-Shift +@item Ctrl-Alt Toggle mouse and keyboard grab. @end table -- cgit v1.2.3 From 32ff25bf68e687a6c15bfef2d855faccb2740472 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 14:33:54 +0000 Subject: ctrl-alt is the default grab key - reset modifiers when toggling grab state git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1094 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/sdl.c b/sdl.c index c089f56f4..f1b4726cc 100644 --- a/sdl.c +++ b/sdl.c @@ -41,6 +41,8 @@ static int gui_fullscreen; static int gui_key_modifier_pressed; static int gui_keysym; static int gui_fullscreen_initial_grab; +static int gui_grab_code = KMOD_LALT | KMOD_LCTRL; +static uint8_t modifiers_state[256]; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { @@ -275,10 +277,22 @@ static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) #endif +static void reset_keys(void) +{ + int i; + for(i = 0; i < 256; i++) { + if (modifiers_state[i]) { + if (i & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(i | 0x80); + modifiers_state[i] = 0; + } + } +} + static void sdl_process_key(SDL_KeyboardEvent *ev) { - int keycode, v, i; - static uint8_t modifiers_state[256]; + int keycode, v; if (ev->keysym.sym == SDLK_PAUSE) { /* specific case */ @@ -297,13 +311,7 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) switch(keycode) { case 0x00: /* sent when leaving window: reset the modifiers state */ - for(i = 0; i < 256; i++) { - if (modifiers_state[i]) { - if (i & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(i | 0x80); - } - } + reset_keys(); return; case 0x2a: /* Left Shift */ case 0x36: /* Right Shift */ @@ -341,7 +349,7 @@ static void sdl_update_caption(void) strcat(buf, " [Stopped]"); } if (gui_grab) { - strcat(buf, " - Press Ctrl-Shift to exit grab"); + strcat(buf, " - Press Ctrl-Alt to exit grab"); } SDL_WM_SetCaption(buf, "QEMU"); } @@ -422,17 +430,19 @@ static void sdl_refresh(DisplayState *ds) case SDL_KEYDOWN: case SDL_KEYUP: if (ev->type == SDL_KEYDOWN) { - mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)) == - (KMOD_LSHIFT | KMOD_LCTRL); + mod_state = (SDL_GetModState() & gui_grab_code) == + gui_grab_code; gui_key_modifier_pressed = mod_state; if (gui_key_modifier_pressed) { - switch(ev->key.keysym.sym) { - case SDLK_f: + int keycode; + keycode = sdl_keyevent_to_keycode(&ev->key); + switch(keycode) { + case 0x21: /* 'f' key on US keyboard */ toggle_full_screen(ds); gui_keysym = 1; break; - case SDLK_F1 ... SDLK_F12: - console_select(ev->key.keysym.sym - SDLK_F1); + case 0x02 ... 0x0a: /* '1' to '9' keys */ + console_select(keycode - 0x02); if (is_active_console(vga_console)) { /* tell the vga console to redisplay itself */ vga_invalidate_display(); @@ -446,8 +456,7 @@ static void sdl_refresh(DisplayState *ds) default: break; } - } - if (!is_active_console(vga_console)) { + } else if (!is_active_console(vga_console)) { int keysym; keysym = 0; if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { @@ -483,15 +492,18 @@ static void sdl_refresh(DisplayState *ds) } } } else if (ev->type == SDL_KEYUP) { - mod_state = (SDL_GetModState() & (KMOD_LSHIFT | KMOD_LCTRL)); + mod_state = (SDL_GetModState() & gui_grab_code); if (!mod_state) { if (gui_key_modifier_pressed) { if (gui_keysym == 0) { - /* exit/enter grab if pressing Ctrl-Shift */ + /* exit/enter grab if pressing Ctrl-Alt */ if (!gui_grab) sdl_grab_start(); else sdl_grab_end(); + /* SDL does not send back all the + modifiers key, so we must correct it */ + reset_keys(); break; } gui_key_modifier_pressed = 0; -- cgit v1.2.3 From b769d8fef6c06ddb39ef0337882a4f8872b9c2bc Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 15:07:13 +0000 Subject: removed access_type hack git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1095 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 6 ----- exec.c | 1 + softmmu_template.h | 70 +++++++++++++++++++++++++++--------------------- target-i386/helper2.c | 3 ++- target-ppc/helper.c | 69 +++++++++++++++++++++++++++++------------------ target-ppc/translate.c | 6 ----- target-sparc/cpu.h | 5 ---- target-sparc/helper.c | 10 +++---- target-sparc/translate.c | 5 ---- 9 files changed, 89 insertions(+), 86 deletions(-) diff --git a/exec-all.h b/exec-all.h index 2e886e07c..8a47f1bb1 100644 --- a/exec-all.h +++ b/exec-all.h @@ -592,13 +592,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) #endif if (__builtin_expect(env->tlb_read[is_user][index].address != (addr & TARGET_PAGE_MASK), 0)) { -#if defined (TARGET_PPC) - env->access_type = ACCESS_CODE; - ldub_code((void *)addr); - env->access_type = ACCESS_INT; -#else ldub_code((void *)addr); -#endif } return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; } diff --git a/exec.c b/exec.c index 5f2f69642..8732377ab 100644 --- a/exec.c +++ b/exec.c @@ -2115,6 +2115,7 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, #define MMUSUFFIX _cmmu #define GETPC() NULL #define env cpu_single_env +#define SOFTMMU_CODE_ACCESS #define SHIFT 0 #include "softmmu_template.h" diff --git a/softmmu_template.h b/softmmu_template.h index 73fdbecb3..f1abee8ac 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -39,14 +39,15 @@ #error unsupported data size #endif +#ifdef SOFTMMU_CODE_ACCESS +#define READ_ACCESS_TYPE 2 +#else +#define READ_ACCESS_TYPE 0 +#endif + static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, int is_user, void *retaddr); -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, - DATA_TYPE val, - int is_user, - void *retaddr); - static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, unsigned long tlb_addr) { @@ -68,29 +69,6 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, return res; } -static inline void glue(io_write, SUFFIX)(unsigned long physaddr, - DATA_TYPE val, - unsigned long tlb_addr, - void *retaddr) -{ - int index; - - index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); - env->mem_write_vaddr = tlb_addr; - env->mem_write_pc = (unsigned long)retaddr; -#if SHIFT <= 2 - io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); -#else -#ifdef TARGET_WORDS_BIGENDIAN - io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32); - io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val); -#else - io_mem_write[index][2](io_mem_opaque[index], physaddr, val); - io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32); -#endif -#endif /* SHIFT > 2 */ -} - /* handle all cases except unaligned access which span two pages */ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, int is_user) @@ -125,7 +103,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); - tlb_fill(addr, 0, is_user, retaddr); + tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr); goto redo; } return res; @@ -172,12 +150,41 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, } } else { /* the page is not in the TLB : fill it */ - tlb_fill(addr, 0, is_user, retaddr); + tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr); goto redo; } return res; } +#ifndef SOFTMMU_CODE_ACCESS + +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, + DATA_TYPE val, + int is_user, + void *retaddr); + +static inline void glue(io_write, SUFFIX)(unsigned long physaddr, + DATA_TYPE val, + unsigned long tlb_addr, + void *retaddr) +{ + int index; + + index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + env->mem_write_vaddr = tlb_addr; + env->mem_write_pc = (unsigned long)retaddr; +#if SHIFT <= 2 + io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val); +#else +#ifdef TARGET_WORDS_BIGENDIAN + io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32); + io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val); +#else + io_mem_write[index][2](io_mem_opaque[index], physaddr, val); + io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32); +#endif +#endif /* SHIFT > 2 */ +} void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, DATA_TYPE val, @@ -257,6 +264,9 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, } } +#endif /* !defined(SOFTMMU_CODE_ACCESS) */ + +#undef READ_ACCESS_TYPE #undef SHIFT #undef DATA_TYPE #undef SUFFIX diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 06c732edc..0d5f439d1 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -331,7 +331,8 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", addr, is_write, is_user, env->eip); #endif - + is_write &= 1; + if (env->user_mode_only) { /* user mode only emulation */ error_code = 0; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 55fe2b224..1ed07e833 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -432,13 +432,13 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; +#if 0 { unsigned long tlb_addrr, tlb_addrw; int index; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_addrr = env->tlb_read[is_user][index].address; tlb_addrw = env->tlb_write[is_user][index].address; -#if 0 if (loglevel) { fprintf(logfile, "%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " @@ -447,8 +447,8 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); } -#endif } +#endif ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); if (ret) { if (retaddr) { @@ -463,20 +463,20 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) } do_raise_exception_err(env->exception_index, env->error_code); } +#if 0 { unsigned long tlb_addrr, tlb_addrw; int index; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_addrr = env->tlb_read[is_user][index].address; tlb_addrw = env->tlb_write[is_user][index].address; -#if 0 printf("%s 2 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " "(0x%08lx 0x%08lx)\n", __func__, env, &env->tlb_read[is_user][index], index, addr, tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); -#endif } +#endif env = saved_env; } @@ -496,18 +496,22 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, int access_type; int ret = 0; -// printf("%s 0\n", __func__); - access_type = env->access_type; + if (rw == 2) { + /* code access */ + rw = 0; + access_type = ACCESS_CODE; + } else { + /* data access */ + /* XXX: put correct access by using cpu_restore_state() + correctly */ + access_type = ACCESS_INT; + // access_type = env->access_type; + } if (env->user_mode_only) { /* user mode only emulation */ ret = -2; goto do_fault; } - /* NASTY BUG workaround */ - if (access_type == ACCESS_CODE && rw) { - printf("%s: ERROR WRITE CODE ACCESS\n", __func__); - access_type = ACCESS_INT; - } ret = get_physical_address(env, &physical, &prot, address, rw, access_type); if (ret == 0) { @@ -590,7 +594,6 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, env->error_code = error_code; ret = 1; } - return ret; } @@ -671,11 +674,15 @@ void do_interrupt (CPUState *env) if (loglevel > 0) { fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", env->nip, excp << 8, env->error_code); - } + } if (loglevel > 0) cpu_ppc_dump_state(env, logfile, 0); } #endif + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", + env->nip, excp << 8, env->error_code); + } /* Generate informations in save/restore registers */ switch (excp) { case EXCP_OFCALL: @@ -824,19 +831,29 @@ void do_interrupt (CPUState *env) } goto store_next; case EXCP_SYSCALL: -#if defined (DEBUG_EXCEPTIONS) - if (msr_pr) { - if (loglevel) { - fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", - env->gpr[0], env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6]); - } else { - printf("syscall %d from 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", - env->gpr[0], env->nip, env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6]); - } - } -#endif + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", + env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6]); + if (env->gpr[0] == 4 && env->gpr[3] == 1) { + int len, addr, i; + uint8_t c; + + fprintf(logfile, "write: "); + addr = env->gpr[4]; + len = env->gpr[5]; + if (len > 64) + len = 64; + for(i = 0; i < len; i++) { + c = 0; + cpu_memory_rw_debug(env, addr + i, &c, 1, 0); + if (c < 32 || c > 126) + c = '.'; + fprintf(logfile, "%c", c); + } + fprintf(logfile, "\n"); + } + } goto store_next; case EXCP_TRACE: goto store_next; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 7e684495d..fd52f73cc 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3002,7 +3002,6 @@ CPUPPCState *cpu_ppc_init(void) #else env->nip = 0xFFFFFFFC; #endif - env->access_type = ACCESS_INT; cpu_single_env = env; return env; } @@ -3050,12 +3049,9 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, /* Single step trace mode */ msr_se = 1; #endif - env->access_type = ACCESS_CODE; /* Set env in case of segfault during code fetch */ while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { if (search_pc) { - if (loglevel > 0) - fprintf(logfile, "Search PC...\n"); j = gen_opc_ptr - gen_opc_buf; if (lj < j) { lj++; @@ -3187,8 +3183,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, fprintf(logfile, "\n"); } #endif - env->access_type = ACCESS_INT; - return 0; } diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index ec9bba76a..4c23b924a 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -86,10 +86,6 @@ #define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT) #define PG_CACHE_MASK (1 << PG_CACHE_BIT) -#define ACCESS_DATA 0 -#define ACCESS_CODE 1 -#define ACCESS_MMU 2 - #define NWINDOWS 32 typedef struct CPUSPARCState { @@ -131,7 +127,6 @@ typedef struct CPUSPARCState { CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; int error_code; - int access_type; /* MMU regs */ uint32_t mmuregs[16]; /* temporary float registers */ diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 036720045..ae70595c5 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -132,13 +132,12 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, int is_user, int is_softmmu) { int exception = 0; - int access_type, access_perms = 0, access_index = 0; + int access_perms = 0, access_index = 0; uint8_t *pde_ptr; uint32_t pde, virt_addr; int error_code = 0, is_dirty, prot, ret = 0; unsigned long paddr, vaddr, page_offset; - access_type = env->access_type; if (env->user_mode_only) { /* user mode only emulation */ ret = -2; @@ -156,7 +155,6 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); - env->access_type = ACCESS_MMU; pde = ldl_raw(pde_ptr); /* Ctx pde */ @@ -219,7 +217,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, } /* update page modified and dirty bits */ - is_dirty = rw && !(pde & PG_MODIFIED_MASK); + is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); if (!(pde & PG_ACCESSED_MASK) || is_dirty) { pde |= PG_ACCESSED_MASK; if (is_dirty) @@ -228,7 +226,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, } /* check access */ - access_index = (rw << 2) | ((access_type == ACCESS_CODE)? 2 : 0) | (is_user? 0 : 1); + access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; error_code = access_table[access_index][access_perms]; if (error_code) @@ -249,14 +247,12 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset; do_mapping: - env->access_type = access_type; vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; do_fault: - env->access_type = access_type; if (env->mmuregs[3]) /* Fault status register */ env->mmuregs[3] = 1; /* overflow (not read before another fault) */ env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 852507ab1..d06886c84 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1278,8 +1278,6 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; - env->access_type = ACCESS_CODE; - do { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { @@ -1352,8 +1350,6 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, } } #endif - - env->access_type = ACCESS_DATA; return 0; } @@ -1379,7 +1375,6 @@ CPUSPARCState *cpu_sparc_init(void) env->cwp = 0; env->wim = 1; env->regwptr = env->regbase + (env->cwp * 16); - env->access_type = ACCESS_DATA; #if defined(CONFIG_USER_ONLY) env->user_mode_only = 1; #else -- cgit v1.2.3 From a5ba1ca6083aab0b628d03122e3553c92e3da3a5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 21:47:33 +0000 Subject: BIOS floppy fix for NT4 (Mike Nordell, Derek Fawcus) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1096 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 42 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index b87e10b58..dbac54005 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 443236a24..4e38d182c 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -4,7 +4,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.110 diff -u -w -r1.110 rombios.c --- rombios.c 31 May 2004 13:11:27 -0000 1.110 -+++ rombios.c 20 Jun 2004 13:10:07 -0000 ++++ rombios.c 3 Oct 2004 21:41:43 -0000 @@ -137,6 +137,7 @@ #define DEBUG_INT16 0 #define DEBUG_INT1A 0 @@ -60,6 +60,15 @@ diff -u -w -r1.110 rombios.c ASM_END } } +@@ -7880,7 +7868,7 @@ + mov al, #0x02 + out #0x0a, al ;; clear DMA-1 channel 2 mask bit + +- SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table) ++ SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2) + SET_INT_VECTOR(0x40, #0xF000, #int13_diskette) + SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6 + @@ -8344,6 +8332,19 @@ pop ax iret @@ -80,7 +89,34 @@ diff -u -w -r1.110 rombios.c ;-------------------- #if BX_PCIBIOS use32 386 -@@ -9560,6 +9561,10 @@ +@@ -9515,6 +9516,26 @@ + pop ds + iret + ++diskette_param_table2: ++;; New diskette parameter table adding 3 parameters from IBM ++;; Since no provisions are made for multiple drive types, most ++;; values in this table are ignored. I set parameters for 1.44M ++;; floppy here ++db 0xAF ++db 0x02 ;; head load time 0000001, DMA used ++db 0x25 ++db 0x02 ++db 18 ++db 0x1B ++db 0xFF ++db 0x6C ++db 0xF6 ++db 0x0F ++db 0x08 ++db 79 ;; maximum track ++db 0 ;; data transfer rate ++db 4 ;; drive type in cmos ++ + .org 0xf045 ; INT 10 Functions 0-Fh Entry Point + HALT(__LINE__) + iret +@@ -9560,6 +9581,10 @@ .org 0xf859 ; INT 15h System Services Entry Point int15_handler: pushf @@ -91,7 +127,7 @@ diff -u -w -r1.110 rombios.c push ds push es pushad -@@ -9570,6 +9575,10 @@ +@@ -9570,6 +9595,10 @@ popf //JMPL(iret_modify_cf) jmp iret_modify_cf -- cgit v1.2.3 From 023fcb9507b0d98d8dc98ffaa407e66d84bb6ea4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Oct 2004 21:48:00 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1097 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index f0e8839c6..f722162e6 100644 --- a/Changelog +++ b/Changelog @@ -23,6 +23,7 @@ version 0.6.1: - 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) version 0.6.0: -- cgit v1.2.3 From 8d5f07fa3bd3433e779d13eb1cda4fbb07acb67f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 4 Oct 2004 21:23:09 +0000 Subject: sparc merge (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1098 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 11 +- Makefile.target | 2 +- gdbstub.c | 6 + hw/iommu.c | 83 +++++----- hw/lance.c | 42 +++--- hw/m48t08.c | 4 +- hw/m48t08.h | 2 +- hw/magic-load.c | 385 +++++++++++++++++++++++------------------------ hw/sched.c | 150 +++++------------- hw/sun4m.c | 77 ++++------ hw/tcx.c | 81 +++++++--- monitor.c | 6 +- pc-bios/README | 5 + pc-bios/proll.bin | Bin 0 -> 56856 bytes pc-bios/proll.patch | 50 ++++++ target-sparc/cpu.h | 1 + target-sparc/exec.h | 5 +- target-sparc/helper.c | 22 +-- target-sparc/op.c | 96 +----------- target-sparc/op_helper.c | 23 ++- target-sparc/op_mem.h | 4 + tests/Makefile | 2 +- vl.h | 11 +- 23 files changed, 484 insertions(+), 584 deletions(-) create mode 100644 pc-bios/proll.bin create mode 100644 pc-bios/proll.patch diff --git a/Makefile b/Makefile index f80db8be9..d4d8028f3 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -include config-host.mak +-include config-host.mak CFLAGS=-Wall -O2 -g -fno-strict-aliasing ifdef CONFIG_DARWIN @@ -14,8 +14,9 @@ TOOLS=qemu-img ifdef CONFIG_STATIC LDFLAGS+=-static endif +DOCS=qemu-doc.html qemu-tech.html qemu.1 -all: dyngen$(EXESUF) $(TOOLS) qemu-doc.html qemu-tech.html qemu.1 +all: dyngen$(EXESUF) $(TOOLS) $(DOCS) for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ done @@ -29,14 +30,14 @@ dyngen$(EXESUF): dyngen.c 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 qemu.pod + rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS qemu.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 + rm -f config-host.mak config-host.h $(DOCS) for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ done @@ -50,6 +51,7 @@ endif install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/vgabios-cirrus.bin \ pc-bios/ppc_rom.bin \ + pc-bios/proll.bin \ pc-bios/linux_boot.bin "$(datadir)" mkdir -p "$(docdir)" install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" @@ -99,6 +101,7 @@ tarbin: $(datadir)/vgabios.bin \ $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ + $(datadir)/proll.bin \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff --git a/Makefile.target b/Makefile.target index ff07be844..6ac8d9f1b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -279,7 +279,7 @@ 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 endif ifeq ($(TARGET_ARCH), sparc) -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/gdbstub.c b/gdbstub.c index e15216a59..2491c2cd7 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -387,6 +387,9 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) env->eip = addr; #elif defined (TARGET_PPC) env->nip = addr; +#elif defined (TARGET_SPARC) + env->pc = addr; + env->npc = addr + 4; #endif } vm_start(); @@ -398,6 +401,9 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) env->eip = addr; #elif defined (TARGET_PPC) env->nip = addr; +#elif defined (TARGET_SPARC) + env->pc = addr; + env->npc = addr + 4; #endif } cpu_single_step(env, 1); diff --git a/hw/iommu.c b/hw/iommu.c index f00bb78b0..a9249c4ba 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -107,29 +107,24 @@ struct iommu_regs { #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ #define IOPTE_WAZ 0x00000001 /* Write as zeros */ -#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (PAGE_SIZE - 1) typedef struct IOMMUState { + uint32_t addr; uint32_t regs[sizeof(struct iommu_regs)]; + uint32_t iostart; } IOMMUState; static IOMMUState *ps; -static int iommu_io_memory; - -static void iommu_reset(IOMMUState *s) -{ -} - static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) { IOMMUState *s = opaque; uint32_t saddr; - saddr = (addr - PHYS_JJ_IOMMU) >> 2; + saddr = (addr - s->addr) >> 2; switch (saddr) { default: return s->regs[saddr]; @@ -143,8 +138,37 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val IOMMUState *s = opaque; uint32_t saddr; - saddr = (addr - PHYS_JJ_IOMMU) >> 2; + saddr = (addr - s->addr) >> 2; switch (saddr) { + case 0: + switch (val & IOMMU_CTRL_RNGE) { + case IOMMU_RNGE_16MB: + s->iostart = 0xff000000; + break; + case IOMMU_RNGE_32MB: + s->iostart = 0xfe000000; + break; + case IOMMU_RNGE_64MB: + s->iostart = 0xfc000000; + break; + case IOMMU_RNGE_128MB: + s->iostart = 0xf8000000; + break; + case IOMMU_RNGE_256MB: + s->iostart = 0xf0000000; + break; + case IOMMU_RNGE_512MB: + s->iostart = 0xe0000000; + break; + case IOMMU_RNGE_1GB: + s->iostart = 0xc0000000; + break; + default: + case IOMMU_RNGE_2GB: + s->iostart = 0x80000000; + break; + } + /* Fall through */ default: s->regs[saddr] = val; break; @@ -165,57 +189,30 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { uint32_t iommu_translate(uint32_t addr) { - uint32_t *iopte = (void *)(ps->regs[1] << 4), pa, iostart; - - switch (ps->regs[0] & IOMMU_CTRL_RNGE) { - case IOMMU_RNGE_16MB: - iostart = 0xff000000; - break; - case IOMMU_RNGE_32MB: - iostart = 0xfe000000; - break; - case IOMMU_RNGE_64MB: - iostart = 0xfc000000; - break; - case IOMMU_RNGE_128MB: - iostart = 0xf8000000; - break; - case IOMMU_RNGE_256MB: - iostart = 0xf0000000; - break; - case IOMMU_RNGE_512MB: - iostart = 0xe0000000; - break; - case IOMMU_RNGE_1GB: - iostart = 0xc0000000; - break; - default: - case IOMMU_RNGE_2GB: - iostart = 0x80000000; - break; - } + uint32_t *iopte = (void *)(ps->regs[1] << 4), pa; - iopte += ((addr - iostart) >> PAGE_SHIFT); + iopte += ((addr - ps->iostart) >> PAGE_SHIFT); cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0); bswap32s(&pa); pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */ - //return pa + PAGE_SIZE; return pa + (addr & PAGE_MASK); } -void iommu_init() +void iommu_init(uint32_t addr) { IOMMUState *s; + int iommu_io_memory; s = qemu_mallocz(sizeof(IOMMUState)); if (!s) return; + s->addr = addr; + iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); - cpu_register_physical_memory(PHYS_JJ_IOMMU, sizeof(struct iommu_regs), + cpu_register_physical_memory(addr, sizeof(struct iommu_regs), iommu_io_memory); - iommu_reset(s); ps = s; } diff --git a/hw/lance.c b/hw/lance.c index e461adead..25ad8c45b 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -24,11 +24,7 @@ #include "vl.h" /* debug LANCE card */ -#define DEBUG_LANCE - -#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ -#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */ -#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */ +//#define DEBUG_LANCE #ifndef LANCE_LOG_TX_BUFFERS #define LANCE_LOG_TX_BUFFERS 4 @@ -162,10 +158,12 @@ struct sparc_dma_registers { #endif typedef struct LEDMAState { + uint32_t addr; uint32_t regs[LEDMA_REGS]; } LEDMAState; typedef struct LANCEState { + uint32_t paddr; NetDriverState *nd; uint32_t leptr; uint16_t addr; @@ -175,8 +173,6 @@ typedef struct LANCEState { LEDMAState *ledma; } LANCEState; -static int lance_io_memory; - static unsigned int rxptr, txptr; static void lance_send(void *opaque); @@ -194,7 +190,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) LANCEState *s = opaque; uint32_t saddr; - saddr = addr - PHYS_JJ_LE; + saddr = addr - s->paddr; switch (saddr >> 1) { case LE_RDP: return s->regs[s->addr]; @@ -210,9 +206,9 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val { LANCEState *s = opaque; uint32_t saddr; - uint16_t clear, reg; + uint16_t reg; - saddr = addr - PHYS_JJ_LE; + saddr = addr - s->paddr; switch (saddr >> 1) { case LE_RDP: switch(s->addr) { @@ -406,14 +402,12 @@ static void lance_send(void *opaque) } } -static int ledma_io_memory; - static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) { LEDMAState *s = opaque; uint32_t saddr; - saddr = (addr - PHYS_JJ_LEDMA) >> 2; + saddr = (addr - s->addr) >> 2; if (saddr < LEDMA_REGS) return s->regs[saddr]; else @@ -425,7 +419,7 @@ static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val LEDMAState *s = opaque; uint32_t saddr; - saddr = (addr - PHYS_JJ_LEDMA) >> 2; + saddr = (addr - s->addr) >> 2; if (saddr < LEDMA_REGS) s->regs[saddr] = val; } @@ -442,29 +436,31 @@ static CPUWriteMemoryFunc *ledma_mem_write[3] = { ledma_mem_writel, }; -void lance_init(NetDriverState *nd, int irq) +void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) { LANCEState *s; LEDMAState *led; + int lance_io_memory, ledma_io_memory; s = qemu_mallocz(sizeof(LANCEState)); if (!s) return; + s->paddr = leaddr; + s->nd = nd; + s->irq = irq; + lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); - cpu_register_physical_memory(PHYS_JJ_LE, 8, - lance_io_memory); + cpu_register_physical_memory(leaddr, 8, lance_io_memory); + led = qemu_mallocz(sizeof(LEDMAState)); if (!led) return; - ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led); - cpu_register_physical_memory(PHYS_JJ_LEDMA, 16, - ledma_io_memory); - - s->nd = nd; s->ledma = led; - s->irq = irq; + led->addr = ledaddr; + ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led); + cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); lance_reset(s); qemu_add_read_packet(nd, lance_can_receive, lance_receive, s); diff --git a/hw/m48t08.c b/hw/m48t08.c index c5b6e7a72..46ec66557 100644 --- a/hw/m48t08.c +++ b/hw/m48t08.c @@ -341,7 +341,7 @@ static CPUReadMemoryFunc *nvram_read[] = { }; /* Initialisation routine */ -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr) { m48t08_t *s; int i; @@ -367,7 +367,7 @@ m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) i = 0x1fd8; s->buffer[i++] = 0x01; s->buffer[i++] = 0x80; /* Sun4m OBP */ - /* XXX: Ethernet address, etc */ + memcpy(&s->buffer[i], macaddr, 6); /* Calculate checksum */ for (i = 0x1fd8; i < 0x1fe7; i++) { diff --git a/hw/m48t08.h b/hw/m48t08.h index 2a754b698..9b44bc0d1 100644 --- a/hw/m48t08.h +++ b/hw/m48t08.h @@ -7,6 +7,6 @@ void m48t08_write (m48t08_t *NVRAM, uint32_t val); uint32_t m48t08_read (m48t08_t *NVRAM); void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr); void m48t08_toggle_lock (m48t08_t *NVRAM, int lock); -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size); +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr); #endif /* !defined (__M48T08_H__) */ diff --git a/hw/magic-load.c b/hw/magic-load.c index 7365183da..06a5f743a 100644 --- a/hw/magic-load.c +++ b/hw/magic-load.c @@ -1,41 +1,12 @@ -/* This is the Linux kernel elf-loading code, ported into user space */ #include "vl.h" #include "disas.h" -/* XXX: this code is not used as it is under the GPL license. Please - remove or recode it */ -//#define USE_ELF_LOADER - -#ifdef USE_ELF_LOADER -/* should probably go in elf.h */ -#ifndef ELIBBAD -#define ELIBBAD 80 -#endif - - -#define ELF_START_MMAP 0x80000000 - -#define elf_check_arch(x) ( (x) == EM_SPARC ) - #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_SPARC #include "elf.h" -/* - * This structure is used to hold the arguments that are - * used when loading binaries. - */ -struct linux_binprm { - char buf[128]; - int fd; -}; - -#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE -#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) -#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) - #ifdef BSWAP_NEEDED static void bswap_ehdr(Elf32_Ehdr *ehdr) { @@ -87,186 +58,192 @@ static void bswap_sym(Elf32_Sym *sym) bswap32s(&sym->st_size); bswap16s(&sym->st_shndx); } +#else +#define bswap_ehdr(e) do { } while (0) +#define bswap_phdr(e) do { } while (0) +#define bswap_shdr(e) do { } while (0) +#define bswap_sym(e) do { } while (0) #endif -static int prepare_binprm(struct linux_binprm *bprm) +static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type) { - int retval; - - memset(bprm->buf, 0, sizeof(bprm->buf)); - retval = lseek(bprm->fd, 0L, SEEK_SET); - if(retval >= 0) { - retval = read(bprm->fd, bprm->buf, 128); - } - if(retval < 0) { - perror("prepare_binprm"); - exit(-1); - /* return(-errno); */ - } - else { - return(retval); + int i, retval; + + retval = lseek(fd, ehdr->e_phoff, SEEK_SET); + if (retval < 0) + return -1; + + for (i = 0; i < ehdr->e_phnum; i++) { + retval = read(fd, phdr, sizeof(*phdr)); + if (retval < 0) + return -1; + bswap_phdr(phdr); + if (phdr->p_type == type) + return 0; } + return -1; } -/* Best attempt to load symbols from this ELF object. */ -static void load_symbols(struct elfhdr *hdr, int fd) +static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type) { - unsigned int i; - struct elf_shdr sechdr, symtab, strtab; - char *strings; - - lseek(fd, hdr->e_shoff, SEEK_SET); - for (i = 0; i < hdr->e_shnum; i++) { - if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) - return; -#ifdef BSWAP_NEEDED - bswap_shdr(&sechdr); -#endif - if (sechdr.sh_type == SHT_SYMTAB) { - symtab = sechdr; - lseek(fd, hdr->e_shoff - + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); - if (read(fd, &strtab, sizeof(strtab)) - != sizeof(strtab)) - return; -#ifdef BSWAP_NEEDED - bswap_shdr(&strtab); -#endif - goto found; - } + int i, retval; + + retval = lseek(fd, ehdr->e_shoff, SEEK_SET); + if (retval < 0) + return NULL; + + for (i = 0; i < ehdr->e_shnum; i++) { + retval = read(fd, shdr, sizeof(*shdr)); + if (retval < 0) + return NULL; + bswap_shdr(shdr); + if (shdr->sh_type == type) + return qemu_malloc(shdr->sh_size); } - return; /* Shouldn't happen... */ - - found: - /* Now know where the strtab and symtab are. Snarf them. */ - disas_symtab = qemu_malloc(symtab.sh_size); - disas_strtab = strings = qemu_malloc(strtab.sh_size); - if (!disas_symtab || !disas_strtab) - return; - - lseek(fd, symtab.sh_offset, SEEK_SET); - if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) - return; + return NULL; +} -#ifdef BSWAP_NEEDED - for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) - bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); -#endif +static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) +{ + int retval; - lseek(fd, strtab.sh_offset, SEEK_SET); - if (read(fd, strings, strtab.sh_size) != strtab.sh_size) - return; - disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); + if (retval < 0) + return -1; + + retval = read(fd, shdr, sizeof(*shdr)); + if (retval < 0) + return -1; + bswap_shdr(shdr); + if (shdr->sh_type == SHT_STRTAB) + return qemu_malloc(shdr->sh_size);; + return 0; } -static int load_elf_binary(struct linux_binprm * bprm, uint8_t *addr) +static int read_program(int fd, struct elf_phdr *phdr, void *dst) { - struct elfhdr elf_ex; - unsigned long startaddr = addr; - int i; - struct elf_phdr * elf_ppnt; - struct elf_phdr *elf_phdata; int retval; + retval = lseek(fd, 0x4000, SEEK_SET); + if (retval < 0) + return -1; + return read(fd, dst, phdr->p_filesz); +} - elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ -#ifdef BSWAP_NEEDED - bswap_ehdr(&elf_ex); -#endif +static int read_section(int fd, struct elf_shdr *s, void *dst) +{ + int retval; - if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { - return -ENOEXEC; - } + retval = lseek(fd, s->sh_offset, SEEK_SET); + if (retval < 0) + return -1; + retval = read(fd, dst, s->sh_size); + if (retval < 0) + return -1; + return 0; +} - /* First of all, some simple consistency checks */ - if (! elf_check_arch(elf_ex.e_machine)) { - return -ENOEXEC; - } +static void *process_section(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type) +{ + void *dst; + + dst = find_shdr(ehdr, fd, shdr, type); + if (!dst) + goto error; + + if (read_section(fd, shdr, dst)) + goto error; + return dst; + error: + qemu_free(dst); + return NULL; +} - /* Now read in all of the header information */ - elf_phdata = (struct elf_phdr *)qemu_malloc(elf_ex.e_phentsize*elf_ex.e_phnum); - if (elf_phdata == NULL) { - return -ENOMEM; - } +static void *process_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) +{ + void *dst; + + dst = find_strtab(ehdr, fd, shdr, symtab); + if (!dst) + goto error; + + if (read_section(fd, shdr, dst)) + goto error; + return dst; + error: + qemu_free(dst); + return NULL; +} - retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); - if(retval > 0) { - retval = read(bprm->fd, (char *) elf_phdata, - elf_ex.e_phentsize * elf_ex.e_phnum); - } +static void load_symbols(struct elfhdr *ehdr, int fd) +{ + struct elf_shdr symtab, strtab; + struct elf_sym *syms; + int nsyms, i; + char *str; + + /* Symbol table */ + syms = process_section(ehdr, fd, &symtab, SHT_SYMTAB); + if (!syms) + return; - if (retval < 0) { - perror("load_elf_binary"); - exit(-1); - qemu_free (elf_phdata); - return -errno; - } + nsyms = symtab.sh_size / sizeof(struct elf_sym); + for (i = 0; i < nsyms; i++) + bswap_sym(&syms[i]); + + /* String table */ + str = process_strtab(ehdr, fd, &strtab, &symtab); + if (!str) + goto error_freesyms; + + /* Commit */ + if (disas_symtab) + qemu_free(disas_symtab); /* XXX Merge with old symbols? */ + if (disas_strtab) + qemu_free(disas_strtab); + disas_symtab = syms; + disas_num_syms = nsyms; + disas_strtab = str; + return; + error_freesyms: + qemu_free(syms); + return; +} -#ifdef BSWAP_NEEDED - elf_ppnt = elf_phdata; - for (i=0; ip_type != PT_LOAD) - continue; -#if 0 - error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), - elf_prot, - (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), - bprm->fd, - (elf_ppnt->p_offset - - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); -#endif - //offset = elf_ppnt->p_offset - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr); - offset = 0x4000; - lseek(bprm->fd, offset, SEEK_SET); - len = elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr); - error = read(bprm->fd, addr, len); - - if (error == -1) { - perror("mmap"); - exit(-1); - } - addr += len; - } +int load_elf(const char * filename, uint8_t *addr) +{ + struct elfhdr ehdr; + struct elf_phdr phdr; + int retval, fd; - qemu_free(elf_phdata); + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + goto error; - load_symbols(&elf_ex, bprm->fd); + retval = read(fd, &ehdr, sizeof(ehdr)); + if (retval < 0) + goto error; - return addr-startaddr; -} + bswap_ehdr(&ehdr); -int elf_exec(const char * filename, uint8_t *addr) -{ - struct linux_binprm bprm; - int retval; + if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' + || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' + || ehdr.e_machine != EM_SPARC) + goto error; - retval = open(filename, O_RDONLY); - if (retval < 0) - return retval; - bprm.fd = retval; + if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) + goto error; + retval = read_program(fd, &phdr, addr); + if (retval < 0) + goto error; - retval = prepare_binprm(&bprm); + load_symbols(&ehdr, fd); - if(retval>=0) { - retval = load_elf_binary(&bprm, addr); - } - return retval; + close(fd); + return retval; + error: + close(fd); + return -1; } -#endif int load_kernel(const char *filename, uint8_t *addr) { @@ -286,28 +263,31 @@ int load_kernel(const char *filename, uint8_t *addr) return -1; } -static char saved_kfn[1024]; -static uint32_t saved_addr; -static int magic_state; +typedef struct MAGICState { + uint32_t addr; + uint32_t saved_addr; + int magic_state; + char saved_kfn[1024]; +} MAGICState; static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr) { int ret; + MAGICState *s = opaque; - if (magic_state == 0) { -#ifdef USE_ELF_LOADER - ret = elf_exec(saved_kfn, saved_addr); -#else - ret = load_kernel(saved_kfn, (uint8_t *)saved_addr); -#endif + if (s->magic_state == 0) { + ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr); + if (ret < 0) + ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr); if (ret < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", - saved_kfn); + s->saved_kfn); } - magic_state = 1; /* No more magic */ + s->magic_state = 1; /* No more magic */ tb_flush(); + return bswap32(ret); } - return ret; + return 0; } static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -327,15 +307,20 @@ static CPUWriteMemoryFunc *magic_mem_write[3] = { magic_mem_writel, }; -void magic_init(const char *kfn, int kloadaddr) +void magic_init(const char *kfn, int kloadaddr, uint32_t addr) { int magic_io_memory; - - strcpy(saved_kfn, kfn); - saved_addr = kloadaddr; - magic_state = 0; - magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, 0); - cpu_register_physical_memory(0x20000000, 4, - magic_io_memory); + MAGICState *s; + + s = qemu_mallocz(sizeof(MAGICState)); + if (!s) + return; + + strcpy(s->saved_kfn, kfn); + s->saved_addr = kloadaddr; + s->magic_state = 0; + s->addr = addr; + magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s); + cpu_register_physical_memory(addr, 4, magic_io_memory); } diff --git a/hw/sched.c b/hw/sched.c index c9a685d44..2ab966de4 100644 --- a/hw/sched.c +++ b/hw/sched.c @@ -1,5 +1,5 @@ /* - * QEMU interrupt controller & timer emulation + * QEMU interrupt controller emulation * * Copyright (c) 2003-2004 Fabrice Bellard * @@ -22,11 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" - -#define PHYS_JJ_CLOCK 0x71D00000 -#define PHYS_JJ_CLOCK1 0x71D10000 -#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */ -#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ +//#define DEBUG_IRQ_COUNT /* These registers are used for sending/receiving irqs from/to * different cpu's. @@ -63,18 +59,6 @@ struct sun4m_intreg_master { /* This register is both READ and WRITE. */ unsigned int undirected_target; /* Which cpu gets undirected irqs. */ }; -/* - * Registers of hardware timer in sun4m. - */ -struct sun4m_timer_percpu { - volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ - volatile unsigned int l14_cur_count; -}; - -struct sun4m_timer_global { - volatile unsigned int l10_timer_limit; - volatile unsigned int l10_cur_count; -}; #define SUN4M_INT_ENABLE 0x80000000 #define SUN4M_INT_E14 0x00000080 @@ -101,29 +85,25 @@ struct sun4m_timer_global { #define SUN4M_INT_VME(x) (1 << (x)) typedef struct SCHEDState { + uint32_t addr, addrg; uint32_t intreg_pending; uint32_t intreg_enabled; uint32_t intregm_pending; uint32_t intregm_enabled; - uint32_t timer_regs[2]; - uint32_t timerm_regs[2]; } SCHEDState; static SCHEDState *ps; -static int intreg_io_memory, intregm_io_memory, - timer_io_memory, timerm_io_memory; - -static void sched_reset(SCHEDState *s) -{ -} +#ifdef DEBUG_IRQ_COUNT +static uint64_t irq_count[32]; +#endif static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr) { SCHEDState *s = opaque; uint32_t saddr; - saddr = (addr - PHYS_JJ_INTR0) >> 2; + saddr = (addr - s->addr) >> 2; switch (saddr) { case 0: return s->intreg_pending; @@ -139,7 +119,7 @@ static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va SCHEDState *s = opaque; uint32_t saddr; - saddr = (addr - PHYS_JJ_INTR0) >> 2; + saddr = (addr - s->addr) >> 2; switch (saddr) { case 0: s->intreg_pending = val; @@ -172,7 +152,7 @@ static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr) SCHEDState *s = opaque; uint32_t saddr; - saddr = (addr - PHYS_JJ_INTR_G) >> 2; + saddr = (addr - s->addrg) >> 2; switch (saddr) { case 0: return s->intregm_pending; @@ -191,7 +171,7 @@ static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t v SCHEDState *s = opaque; uint32_t saddr; - saddr = (addr - PHYS_JJ_INTR_G) >> 2; + saddr = (addr - s->addrg) >> 2; switch (saddr) { case 0: s->intregm_pending = val; @@ -222,87 +202,29 @@ static CPUWriteMemoryFunc *intregm_mem_write[3] = { intregm_mem_writel, }; -static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr) +void pic_info(void) { - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - PHYS_JJ_CLOCK) >> 2; - switch (saddr) { - default: - return s->timer_regs[saddr]; - break; - } - return 0; + term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled); + term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled); } -static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +void irq_info(void) { - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - PHYS_JJ_CLOCK) >> 2; - switch (saddr) { - default: - s->timer_regs[saddr] = val; - break; +#ifndef DEBUG_IRQ_COUNT + term_printf("irq statistic code not compiled.\n"); +#else + int i; + int64_t count; + + term_printf("IRQ statistics:\n"); + for (i = 0; i < 32; i++) { + count = irq_count[i]; + if (count > 0) + term_printf("%2d: %lld\n", i, count); } +#endif } -static CPUReadMemoryFunc *timer_mem_read[3] = { - timer_mem_readl, - timer_mem_readl, - timer_mem_readl, -}; - -static CPUWriteMemoryFunc *timer_mem_write[3] = { - timer_mem_writel, - timer_mem_writel, - timer_mem_writel, -}; - -static uint32_t timerm_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - PHYS_JJ_CLOCK1) >> 2; - switch (saddr) { - default: - return s->timerm_regs[saddr]; - break; - } - return 0; -} - -static void timerm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - PHYS_JJ_CLOCK1) >> 2; - switch (saddr) { - default: - s->timerm_regs[saddr] = val; - break; - } -} - -static CPUReadMemoryFunc *timerm_mem_read[3] = { - timerm_mem_readl, - timerm_mem_readl, - timerm_mem_readl, -}; - -static CPUWriteMemoryFunc *timerm_mem_write[3] = { - timerm_mem_writel, - timerm_mem_writel, - timerm_mem_writel, -}; - -void pic_info() {} -void irq_info() {} - static const unsigned int intr_to_mask[16] = { 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -318,29 +240,29 @@ void pic_set_irq(int irq, int level) cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); } } +#ifdef DEBUG_IRQ_COUNT + if (level == 1) + irq_count[irq]++; +#endif } -void sched_init() +void sched_init(uint32_t addr, uint32_t addrg) { + int intreg_io_memory, intregm_io_memory; SCHEDState *s; s = qemu_mallocz(sizeof(SCHEDState)); if (!s) return; + s->addr = addr; + s->addrg = addrg; intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s); - cpu_register_physical_memory(PHYS_JJ_INTR0, 3, intreg_io_memory); + cpu_register_physical_memory(addr, 3, intreg_io_memory); intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s); - cpu_register_physical_memory(PHYS_JJ_INTR_G, 5, intregm_io_memory); - - timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s); - cpu_register_physical_memory(PHYS_JJ_CLOCK, 2, timer_io_memory); - - timerm_io_memory = cpu_register_io_memory(0, timerm_mem_read, timerm_mem_write, s); - cpu_register_physical_memory(PHYS_JJ_CLOCK1, 2, timerm_io_memory); + cpu_register_physical_memory(addrg, 5, intregm_io_memory); - sched_reset(s); ps = s; } diff --git a/hw/sun4m.c b/hw/sun4m.c index 05dbd56a5..80305e09c 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -28,12 +28,26 @@ #define MMU_CONTEXT_TBL 0x00003000 #define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400) #define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800) -#define ROMVEC_DATA (MMU_CONTEXT_TBL + 0x1800) #define PROM_ADDR 0xffd04000 -#define PROM_FILENAME "proll.bin" +#define PROM_FILENAMEB "proll.bin" +#define PROM_FILENAMEE "proll.elf" +#define PROLL_MAGIC_ADDR 0x20000000 #define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */ #define PHYS_JJ_IDPROM_OFF 0x1FD8 #define PHYS_JJ_EEPROM_SIZE 0x2000 +#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ +#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */ +#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */ +#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ +#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */ +#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */ +#define PHYS_JJ_LE_IRQ 6 +#define PHYS_JJ_CLOCK 0x71D00000 +#define PHYS_JJ_CLOCK_IRQ 10 +#define PHYS_JJ_CLOCK1 0x71D10000 +#define PHYS_JJ_CLOCK1_IRQ 14 +#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */ +#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ /* TSC handling */ @@ -44,8 +58,6 @@ uint64_t cpu_get_tsc() void DMA_run() {} void SB16_run() {} -void vga_invalidate_display() {} -void vga_screen_dump(const char *filename) {} int serial_can_receive(SerialState *s) { return 0; } void serial_receive_byte(SerialState *s, int ch) {} void serial_receive_break(SerialState *s) {} @@ -59,7 +71,7 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; - int ret, linux_boot, bios_size; + int ret, linux_boot; unsigned long bios_offset; linux_boot = (kernel_filename != NULL); @@ -68,32 +80,21 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0, ram_size, 0); bios_offset = ram_size; - iommu_init(); - sched_init(); - tcx_init(ds); - lance_init(&nd_table[0], 6); - nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); - - magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - -#if 0 - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - bios_size = get_image_size(buf); - ret = load_image(buf, phys_ram_base + bios_offset); - if (ret != bios_size) { - fprintf(stderr, "qemu: could not load prom '%s'\n", buf); - exit(1); - } - cpu_register_physical_memory(PROM_ADDR, - bios_size, bios_offset | IO_MEM_ROM); -#endif + iommu_init(PHYS_JJ_IOMMU); + sched_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); + tcx_init(ds, PHYS_JJ_TCX_FB); + lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); + nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE, &nd_table[0].macaddr); + timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ); + timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); + magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR, PROLL_MAGIC_ADDR); /* We load Proll as the kernel and start it. It will issue a magic IO to load the real kernel */ if (linux_boot) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); ret = load_kernel(buf, - phys_ram_base + KERNEL_LOAD_ADDR); + phys_ram_base + KERNEL_LOAD_ADDR); if (ret < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", buf); @@ -103,28 +104,10 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, /* Setup a MMU entry for entire address space */ stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1); stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1); -#if 0 - stl_raw(phys_ram_base + MMU_L1PTP + (0x50 << 2), (MMU_L2PTP >> 4) | 1); // frame buffer at 50.. -#endif + stl_raw(phys_ram_base + MMU_L1PTP + (0x01 << 2), (MMU_L2PTP >> 4) | 1); // 01.. == 00.. stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00.. + stl_raw(phys_ram_base + MMU_L1PTP + (0xf0 << 2), (MMU_L2PTP >> 4) | 1); // f0.. == 00.. /* 3 = U:RWX S:RWX */ stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2); -#if 0 - stl_raw(phys_ram_base + MMU_L2PTP + 0x84, (PHYS_JJ_TCX_FB >> 4) \ - | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf - stl_raw(phys_ram_base + MMU_L2PTP + 0x88, (PHYS_JJ_TCX_FB >> 4) \ - | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf - stl_raw(phys_ram_base + MMU_L2PTP + 0x140, (PHYS_JJ_TCX_FB >> 4) \ - | (3 << PTE_ACCESS_SHIFT) | 2); // frame buf - // "Empirical constant" - stl_raw(phys_ram_base + ROMVEC_DATA, 0x10010407); - - // Version: V3 prom - stl_raw(phys_ram_base + ROMVEC_DATA + 4, 3); - - stl_raw(phys_ram_base + ROMVEC_DATA + 0x1c, ROMVEC_DATA+0x400); - stl_raw(phys_ram_base + ROMVEC_DATA + 0x400, ROMVEC_DATA+0x404); - stl_raw(phys_ram_base + ROMVEC_DATA + 0x404, 0x81c3e008); // retl - stl_raw(phys_ram_base + ROMVEC_DATA + 0x408, 0x01000000); // nop -#endif + stl_raw(phys_ram_base + MMU_L2PTP, ((0x01 << PTE_PPN_SHIFT) >> 4 ) | (3 << PTE_ACCESS_SHIFT) | 2); } diff --git a/hw/tcx.c b/hw/tcx.c index d9b91c68f..7f979946f 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -23,9 +23,6 @@ */ #include "vl.h" -#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */ -#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */ - #define MAXX 1024 #define MAXY 768 #define XSZ (8*80) @@ -33,38 +30,32 @@ #define XOFF (MAXX-XSZ) #define YOFF (MAXY-YSZ) -#define DEBUG_VGA_MEM - typedef struct TCXState { - uint8_t *vram_ptr; - unsigned long vram_offset; - unsigned int vram_size; + uint32_t addr; DisplayState *ds; + uint8_t *vram; } TCXState; static TCXState *ts; -static int tcx_io_memory; - void vga_update_display() { dpy_update(ts->ds, 0, 0, XSZ, YSZ); } +void vga_invalidate_display() {} + static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr) { TCXState *s = opaque; uint32_t saddr; unsigned int x, y; - char *sptr; - saddr = addr - PHYS_JJ_TCX_FB - YOFF*MAXX - XOFF; + saddr = addr - s->addr - YOFF*MAXX - XOFF; y = saddr / MAXX; x = saddr - y * MAXX; - if (x < MAXX && y < MAXY) { - sptr = s->ds->data; - if (sptr) - return sptr[y * s->ds->linesize + x*4]; + if (x < XSZ && y < YSZ) { + return s->vram[y * XSZ + x]; } return 0; } @@ -99,7 +90,6 @@ static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr) return v; } -/* called for accesses between 0xa0000 and 0xc0000 */ static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { TCXState *s = opaque; @@ -107,17 +97,24 @@ static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) unsigned int x, y; char *sptr; - saddr = addr - PHYS_JJ_TCX_FB - YOFF*MAXX - XOFF; + saddr = addr - s->addr - YOFF*MAXX - XOFF; y = saddr / MAXX; x = saddr - y * MAXX; - if (x < MAXX && y < MAXY) { + if (x < XSZ && y < YSZ) { sptr = s->ds->data; if (sptr) { - sptr[y * s->ds->linesize + x*4] = val; - sptr[y * s->ds->linesize + x*4+1] = val; - sptr[y * s->ds->linesize + x*4+2] = val; - cpu_physical_memory_set_dirty(addr); + if (s->ds->depth == 24 || s->ds->depth == 32) { + /* XXX need to do CLUT translation */ + sptr[y * s->ds->linesize + x*4] = val & 0xff; + sptr[y * s->ds->linesize + x*4+1] = val & 0xff; + sptr[y * s->ds->linesize + x*4+2] = val & 0xff; + } + else if (s->ds->depth == 8) { + sptr[y * s->ds->linesize + x] = val & 0xff; + } } + cpu_physical_memory_set_dirty(addr); + s->vram[y * XSZ + x] = val & 0xff; } } @@ -159,18 +156,52 @@ static CPUWriteMemoryFunc *tcx_mem_write[3] = { tcx_mem_writel, }; -void tcx_init(DisplayState *ds) +void tcx_init(DisplayState *ds, uint32_t addr) { TCXState *s; + int tcx_io_memory; s = qemu_mallocz(sizeof(TCXState)); if (!s) return; s->ds = ds; + s->addr = addr; ts = s; tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s); - cpu_register_physical_memory(PHYS_JJ_TCX_FB, 0x100000, + cpu_register_physical_memory(addr, 0x100000, tcx_io_memory); + s->vram = qemu_mallocz(XSZ*YSZ); dpy_resize(s->ds, XSZ, YSZ); } +void vga_screen_dump(const char *filename) +{ + TCXState *s = ts; + FILE *f; + uint8_t *d, *d1; + unsigned int v; + int y, x; + + f = fopen(filename, "wb"); + if (!f) + return -1; + fprintf(f, "P6\n%d %d\n%d\n", + XSZ, YSZ, 255); + d1 = s->vram; + for(y = 0; y < YSZ; y++) { + d = d1; + for(x = 0; x < XSZ; x++) { + v = *d; + fputc((v) & 0xff, f); + fputc((v) & 0xff, f); + fputc((v) & 0xff, f); + d++; + } + d1 += XSZ; + } + fclose(f); + return; +} + + + diff --git a/monitor.c b/monitor.c index 15b54d3e7..c39f3b239 100644 --- a/monitor.c +++ b/monitor.c @@ -952,11 +952,7 @@ static int monitor_get_tbl (struct MonitorDef *md, int val) #if defined(TARGET_SPARC) static int monitor_get_psr (struct MonitorDef *md, int val) { - return (0<<28) | (4<<24) | cpu_single_env->psr \ - | (cpu_single_env->psrs? PSR_S : 0) \ - | (cpu_single_env->psrs? PSR_PS : 0) \ - | (cpu_single_env->psret? PSR_ET : 0) \ - | cpu_single_env->cwp; + return GET_PSR(cpu_single_env); } static int monitor_get_reg(struct MonitorDef *md, int val) diff --git a/pc-bios/README b/pc-bios/README index 31f91f3ce..a10a9f0df 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -6,3 +6,8 @@ - The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is available at http://site.voila.fr/jmayer/OpenHackWare/index.htm. + +- Proll is a GPL'd boot PROM for Sparc JavaStations + (http://people.redhat.com/zaitcev/linux/). + Applying proll.patch allows circumventing some bugs and enables + faster kernel load through a hack. diff --git a/pc-bios/proll.bin b/pc-bios/proll.bin new file mode 100644 index 000000000..0489cc245 Binary files /dev/null and b/pc-bios/proll.bin differ diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch new file mode 100644 index 000000000..b0860e26f --- /dev/null +++ b/pc-bios/proll.patch @@ -0,0 +1,50 @@ +diff -ru proll_18.orig/mrcoffee/main.c proll_18/mrcoffee/main.c +--- proll_18.orig/mrcoffee/main.c 2002-09-13 16:16:59.000000000 +0200 ++++ proll_18/mrcoffee/main.c 2004-09-26 11:52:23.000000000 +0200 +@@ -101,6 +101,7 @@ + le_probe(); + init_net(); + ++#ifdef ORIG + #if 0 /* RARP */ + if (rarp() != 0) fatal(); + /* printrarp(); */ +@@ -117,13 +118,20 @@ + xtoa(myipaddr, fname, 8); + if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); + #endif ++#endif + + romvec = init_openprom(bb.nbanks, bb.bankv, hiphybas); + + printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n", + PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024, + (int)cio.start, (int)cio.curp); ++#ifdef ORIG + set_timeout(5); while (!chk_timeout()) { } /* P3: let me read */ ++#else ++ printk("loading kernel:"); ++ i = ld_bypass(0x20000000); ++ printk(" done, size %d\n", i); ++#endif + + { + void (*entry)(void *, int) = (void (*)(void*, int)) LOADBASE; +diff -ru proll_18.orig/mrcoffee/openprom.c proll_18/mrcoffee/openprom.c +--- proll_18.orig/mrcoffee/openprom.c 2002-09-13 16:17:03.000000000 +0200 ++++ proll_18/mrcoffee/openprom.c 2004-09-21 21:27:16.000000000 +0200 +@@ -144,10 +144,14 @@ + }; + + static int cpu_nctx = NCTX_SWIFT; ++static int cpu_cache_line_size = 0x20; ++static int cpu_cache_nlines = 0x200; + static struct property propv_cpu[] = { + {"name", "STP1012PGA", sizeof("STP1012PGA") }, + {"device_type", "cpu", 4 }, + {"mmu-nctx", (char*)&cpu_nctx, sizeof(int)}, ++ {"cache-line-size", (char*)&cpu_cache_line_size, sizeof(int)}, ++ {"cache-nlines", (char*)&cpu_cache_nlines, sizeof(int)}, + {NULL, NULL, -1} + }; + diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 4c23b924a..03698df21 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -76,6 +76,7 @@ #define PTE_ENTRYTYPE_MASK 3 #define PTE_ACCESS_MASK 0x1c #define PTE_ACCESS_SHIFT 2 +#define PTE_PPN_SHIFT 7 #define PTE_ADDR_MASK 0xffffff00 #define PG_ACCESSED_BIT 5 diff --git a/target-sparc/exec.h b/target-sparc/exec.h index f9fcf532a..cea9616b3 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -23,13 +23,16 @@ void helper_flush(target_ulong addr); void helper_ld_asi(int asi, int size, int sign); void helper_st_asi(int asi, int size, int sign); void helper_rett(void); -void helper_stfsr(void); +void helper_ldfsr(void); void set_cwp(int new_cwp); void do_fabss(void); void do_fsqrts(void); void do_fsqrtd(void); void do_fcmps(void); void do_fcmpd(void); +void do_ldd_kernel(uint32_t addr); +void do_ldd_user(uint32_t addr); +void do_ldd_raw(uint32_t addr); void do_interrupt(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw); void raise_exception_err(int exception_index, int error_code); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index ae70595c5..63d08e77d 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -21,19 +21,10 @@ #define DEBUG_PCALL -#if 0 -#define raise_exception_err(a, b)\ -do {\ - fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ - (raise_exception_err)(a, b);\ -} while (0) -#endif - /* Sparc MMU emulation */ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, int is_user, int is_softmmu); - /* thread support */ spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; @@ -48,15 +39,6 @@ void cpu_unlock(void) spin_unlock(&global_cpu_lock); } -#if 0 -void cpu_loop_exit(void) -{ - /* NOTE: the register at this point must be saved by hand because - longjmp restore them */ - longjmp(env->jmp_env, 1); -} -#endif - #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu @@ -258,7 +240,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2; env->mmuregs[4] = address; /* Fault address register */ - if (env->mmuregs[0] & MMU_NF) // No fault + if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault return 0; env->exception_index = exception; @@ -306,7 +288,7 @@ void do_interrupt(int intno, int is_int, int error_code, fprintf(logfile, "%6d: v=%02x e=%04x i=%d pc=%08x npc=%08x SP=%08x\n", count, intno, error_code, is_int, env->pc, - env->npc, env->gregs[7]); + env->npc, env->regwptr[6]); #if 0 cpu_sparc_dump_state(env, logfile, 0); { diff --git a/target-sparc/op.c b/target-sparc/op.c index a2d37469d..042fd6199 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -474,92 +474,6 @@ void OPPROTO op_sra(void) T0 = ((int32_t) T0) >> T1; } -#if 0 -void OPPROTO op_st(void) -{ - stl((void *) T0, T1); -} - -void OPPROTO op_stb(void) -{ - stb((void *) T0, T1); -} - -void OPPROTO op_sth(void) -{ - stw((void *) T0, T1); -} - -void OPPROTO op_std(void) -{ - stl((void *) T0, T1); - stl((void *) (T0 + 4), T2); -} - -void OPPROTO op_ld(void) -{ - T1 = ldl((void *) T0); -} - -void OPPROTO op_ldub(void) -{ - T1 = ldub((void *) T0); -} - -void OPPROTO op_lduh(void) -{ - T1 = lduw((void *) T0); -} - -void OPPROTO op_ldsb(void) -{ - T1 = ldsb((void *) T0); -} - -void OPPROTO op_ldsh(void) -{ - T1 = ldsw((void *) T0); -} - -void OPPROTO op_ldstub(void) -{ - T1 = ldub((void *) T0); - stb((void *) T0, 0xff); /* XXX: Should be Atomically */ -} - -void OPPROTO op_swap(void) -{ - unsigned int tmp = ldl((void *) T0); - stl((void *) T0, T1); /* XXX: Should be Atomically */ - T1 = tmp; -} - -void OPPROTO op_ldd(void) -{ - T1 = ldl((void *) T0); - T0 = ldl((void *) (T0 + 4)); -} - -void OPPROTO op_stf(void) -{ - stfl((void *) T0, FT0); -} - -void OPPROTO op_stdf(void) -{ - stfq((void *) T0, DT0); -} - -void OPPROTO op_ldf(void) -{ - FT0 = ldfl((void *) T0); -} - -void OPPROTO op_lddf(void) -{ - DT0 = ldfq((void *) T0); -} -#else /* Load and store */ #define MEMSUFFIX _raw #include "op_mem.h" @@ -570,19 +484,16 @@ void OPPROTO op_lddf(void) #define MEMSUFFIX _kernel #include "op_mem.h" #endif -#endif void OPPROTO op_ldfsr(void) { env->fsr = *((uint32_t *) &FT0); - FORCE_RET(); + helper_ldfsr(); } void OPPROTO op_stfsr(void) { *((uint32_t *) &FT0) = env->fsr; - helper_stfsr(); - FORCE_RET(); } void OPPROTO op_wry(void) @@ -609,16 +520,17 @@ void OPPROTO op_wrwim(void) void OPPROTO op_rdpsr(void) { T0 = GET_PSR(env); - FORCE_RET(); } void OPPROTO op_wrpsr(void) { + int cwp; env->psr = T0 & ~PSR_ICC; env->psrs = (T0 & PSR_S)? 1 : 0; env->psrps = (T0 & PSR_PS)? 1 : 0; env->psret = (T0 & PSR_ET)? 1 : 0; - env->cwp = (T0 & PSR_CWP); + cwp = (T0 & PSR_CWP) & (NWINDOWS - 1); + set_cwp(cwp); FORCE_RET(); } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 253bcff6f..909639af0 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -104,6 +104,27 @@ void OPPROTO helper_st_asi(int asi, int size, int sign) } } +#if 0 +void do_ldd_raw(uint32_t addr) +{ + T1 = ldl_raw((void *) addr); + T0 = ldl_raw((void *) (addr + 4)); +} + +#if !defined(CONFIG_USER_ONLY) +void do_ldd_user(uint32_t addr) +{ + T1 = ldl_user((void *) addr); + T0 = ldl_user((void *) (addr + 4)); +} +void do_ldd_kernel(uint32_t addr) +{ + T1 = ldl_kernel((void *) addr); + T0 = ldl_kernel((void *) (addr + 4)); +} +#endif +#endif + void OPPROTO helper_rett() { int cwp; @@ -116,7 +137,7 @@ void OPPROTO helper_rett() env->psrs = env->psrps; } -void helper_stfsr(void) +void helper_ldfsr(void) { switch (env->fsr & FSR_RD_MASK) { case FSR_RD_NEAREST: diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 9c839a004..2ae74f2ce 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -43,8 +43,12 @@ void OPPROTO glue(op_swap, MEMSUFFIX)(void) void OPPROTO glue(op_ldd, MEMSUFFIX)(void) { +#if 1 T1 = glue(ldl, MEMSUFFIX)((void *) T0); T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4)); +#else + glue(do_ldd, MEMSUFFIX)(T0); +#endif } /*** Floating-point store ***/ diff --git a/tests/Makefile b/tests/Makefile index 1142deaed..c0ee7b2a0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -include ../config-host.mak +-include ../config-host.mak CFLAGS=-Wall -O2 -g LDFLAGS= diff --git a/vl.h b/vl.h index 8ebb268d2..f25bbaa5c 100644 --- a/vl.h +++ b/vl.h @@ -673,20 +673,23 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename); /* iommu.c */ -void iommu_init(); +void iommu_init(uint32_t addr); uint32_t iommu_translate(uint32_t addr); /* lance.c */ -void lance_init(NetDriverState *nd, int irq); +void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr); /* tcx.c */ -void tcx_init(DisplayState *ds); +void tcx_init(DisplayState *ds, uint32_t addr); /* sched.c */ void sched_init(); /* magic-load.c */ -void magic_init(const char *kfn, int kloadaddr); +void magic_init(const char *kfn, int kloadaddr, uint32_t addr); + +/* timer.c */ +void timer_init(uint32_t addr, int irq); /* NVRAM helpers */ #include "hw/m48t59.h" -- cgit v1.2.3 From 7993f8bc512f1f766aa35a87ac06eb62719d56c3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 4 Oct 2004 23:42:21 +0000 Subject: sparc merge (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1099 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/timer.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 hw/timer.c diff --git a/hw/timer.c b/hw/timer.c new file mode 100644 index 000000000..e393fa36f --- /dev/null +++ b/hw/timer.c @@ -0,0 +1,97 @@ +/* + * QEMU Sparc timer controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* + * Registers of hardware timer in sun4m. + */ +struct sun4m_timer_percpu { + volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ + volatile unsigned int l14_cur_count; +}; + +struct sun4m_timer_global { + volatile unsigned int l10_timer_limit; + volatile unsigned int l10_cur_count; +}; + +typedef struct TIMERState { + uint32_t addr; + uint32_t timer_regs[2]; + int irq; +} TIMERState; + +static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr) +{ + TIMERState *s = opaque; + uint32_t saddr; + + saddr = (addr - s->addr) >> 2; + switch (saddr) { + default: + return s->timer_regs[saddr]; + break; + } + return 0; +} + +static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + TIMERState *s = opaque; + uint32_t saddr; + + saddr = (addr - s->addr) >> 2; + switch (saddr) { + default: + s->timer_regs[saddr] = val; + break; + } +} + +static CPUReadMemoryFunc *timer_mem_read[3] = { + timer_mem_readl, + timer_mem_readl, + timer_mem_readl, +}; + +static CPUWriteMemoryFunc *timer_mem_write[3] = { + timer_mem_writel, + timer_mem_writel, + timer_mem_writel, +}; + +void timer_init(uint32_t addr, int irq) +{ + int timer_io_memory; + TIMERState *s; + + s = qemu_mallocz(sizeof(TIMERState)); + if (!s) + return; + s->addr = addr; + s->irq = irq; + + timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s); + cpu_register_physical_memory(addr, 2, timer_io_memory); +} -- cgit v1.2.3 From a4c4785b93b1947e775fb7ec86ed706ef98dbd2f Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Oct 2004 21:27:06 +0000 Subject: floppy fix from Volker Ruppert git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1100 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 24 +++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index dbac54005..fe9816e0a 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 4e38d182c..785076964 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -4,7 +4,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.110 diff -u -w -r1.110 rombios.c --- rombios.c 31 May 2004 13:11:27 -0000 1.110 -+++ rombios.c 3 Oct 2004 21:41:43 -0000 ++++ rombios.c 7 Oct 2004 21:23:50 -0000 @@ -137,6 +137,7 @@ #define DEBUG_INT16 0 #define DEBUG_INT1A 0 @@ -60,6 +60,28 @@ diff -u -w -r1.110 rombios.c ASM_END } } +@@ -5412,8 +5400,8 @@ + case 0x03: SET_BL( 0x06 ); break; + } + +- DI = 0xefc7; +- ES = 0xf000; ++ DI = read_word(0x00, 0x1e*4); // INT vector 0x1E ++ ES = read_word(0x00, 0x1e*4+2); + goto int13_success; + break; + +@@ -6984,8 +6972,8 @@ + } + + /* set es & di to point to 11 byte diskette param table in ROM */ +- DI = 0xefc7; +- ES = 0xf000; ++ DI = read_word(0x00, 0x1e*4); // INT vector 0x1E ++ ES = read_word(0x00, 0x1e*4+2); + CLEAR_CF(); // success + /* disk status not changed upon success */ + return; @@ -7880,7 +7868,7 @@ mov al, #0x02 out #0x0a, al ;; clear DMA-1 channel 2 mask bit -- cgit v1.2.3 From 890fa6bebbb540b9761aafc3fe37b87e26578346 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Oct 2004 23:10:29 +0000 Subject: floppy fixes (initial patch by Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1101 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index 504e9deee..da90d54e7 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1,5 +1,5 @@ /* - * QEMU Floppy disk emulator + * QEMU Floppy disk emulator (Intel 82078) * * Copyright (c) 2003 Jocelyn Mayer * @@ -382,6 +382,7 @@ struct fdctrl_t { uint8_t data_state; uint8_t data_dir; uint8_t int_status; + uint8_t eot; /* last wanted sector */ /* States kept only to be returned back */ /* Timers state */ uint8_t timer0; @@ -762,7 +763,7 @@ static void fdctrl_unimplemented (fdctrl_t *fdctrl) fdrive_t *cur_drv; cur_drv = get_cur_drv(fdctrl); - fdctrl->fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl->cur_drv; + fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv; fdctrl->fifo[1] = 0x00; fdctrl->fifo[2] = 0x00; fdctrl_set_fifo(fdctrl, 3, 1); @@ -782,8 +783,8 @@ static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, cur_drv = get_cur_drv(fdctrl); FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", status0, status1, status2, - status0 | (cur_drv->head << 1) | fdctrl->cur_drv); - fdctrl->fifo[0] = status0 | (cur_drv->head << 1) | fdctrl->cur_drv; + status0 | (cur_drv->head << 2) | fdctrl->cur_drv); + fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv; fdctrl->fifo[1] = status1; fdctrl->fifo[2] = status2; fdctrl->fifo[3] = cur_drv->track; @@ -810,7 +811,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) kt = fdctrl->fifo[2]; kh = fdctrl->fifo[3]; ks = fdctrl->fifo[4]; - FLOPPY_DPRINTF("Start tranfert at %d %d %02x %02x (%d)\n", + FLOPPY_DPRINTF("Start tranfer at %d %d %02x %02x (%d)\n", fdctrl->cur_drv, kh, kt, ks, _fd_sector(kh, kt, ks, cur_drv->last_sect)); did_seek = 0; @@ -864,6 +865,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) tmp += cur_drv->last_sect; fdctrl->data_len *= tmp; } + fdctrl->eot = fdctrl->fifo[6]; if (fdctrl->dma_en) { int dma_mode; /* DMA transfer are enabled. Check if DMA channel is well programmed */ @@ -924,14 +926,14 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) status2 = 0x04; if (size > fdctrl->data_len) size = fdctrl->data_len; - if (cur_drv->bs == NULL) { + if (cur_drv->bs == NULL) { if (fdctrl->data_dir == FD_DIR_WRITE) fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); else fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); len = 0; - goto transfer_error; - } + goto transfer_error; + } rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) { len = size - fdctrl->data_pos; @@ -952,7 +954,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) /* Sure, image size is too small... */ memset(fdctrl->fifo, 0, FD_SECTOR_LEN); } - } + } switch (fdctrl->data_dir) { case FD_DIR_READ: /* READ commands */ @@ -968,7 +970,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); goto transfer_error; - } + } break; default: /* SCAN commands */ @@ -994,30 +996,34 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; if (rel_pos == 0) { /* Seek to next sector */ - cur_drv->sect++; FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv), fdctrl->data_pos - size); - if (cur_drv->sect > cur_drv->last_sect) { + /* XXX: cur_drv->sect >= cur_drv->last_sect should be an + error in fact */ + if (cur_drv->sect >= cur_drv->last_sect || + cur_drv->sect == fdctrl->eot) { cur_drv->sect = 1; if (FD_MULTI_TRACK(fdctrl->data_state)) { if (cur_drv->head == 0 && (cur_drv->flags & FDISK_DBL_SIDES) != 0) { - cur_drv->head = 1; - } else { - cur_drv->head = 0; + cur_drv->head = 1; + } else { + cur_drv->head = 0; cur_drv->track++; if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) break; + } + } else { + cur_drv->track++; + break; } - } else { - cur_drv->track++; - break; - } FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv)); + } else { + cur_drv->sect++; } } } @@ -1033,7 +1039,7 @@ end_transfer: status0 |= 0x20; fdctrl->data_len -= len; // if (fdctrl->data_len == 0) - fdctrl_stop_transfer(fdctrl, status0, status1, status2); + fdctrl_stop_transfer(fdctrl, status0, status1, status2); transfer_error: return len; @@ -1066,7 +1072,7 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) retval = fdctrl->fifo[pos]; if (++fdctrl->data_pos == fdctrl->data_len) { fdctrl->data_pos = 0; - /* Switch from transfert mode to status mode + /* Switch from transfer mode to status mode * then from status mode to command mode */ if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { @@ -1170,7 +1176,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, FD_SECTOR_LEN); } - /* Switch from transfert mode to status mode + /* Switch from transfer mode to status mode * then from status mode to command mode */ if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) @@ -1510,7 +1516,9 @@ enqueue: /* 1 Byte status back */ fdctrl->fifo[0] = (cur_drv->ro << 6) | (cur_drv->track == 0 ? 0x10 : 0x00) | - fdctrl->cur_drv; + (cur_drv->head << 2) | + fdctrl->cur_drv | + 0x28; fdctrl_set_fifo(fdctrl, 1, 0); break; case 0x07: @@ -1581,6 +1589,7 @@ enqueue: /* READ_ID */ FLOPPY_DPRINTF("treat READ_ID command\n"); /* XXX: should set main status register to busy */ + cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; qemu_mod_timer(fdctrl->result_timer, qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); break; -- cgit v1.2.3 From 02d2c54cd3e1a65ce4eaf1555b7f73d0a50eaec4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Oct 2004 23:27:35 +0000 Subject: windows fixes (Gregory Alexander) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1102 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/if.c | 6 +++--- slirp/slirp.c | 15 ++++++++++++--- slirp/slirp.h | 4 ++++ slirp/socket.c | 26 ++++++++++++++++++-------- slirp/tcp_input.c | 2 +- slirp/udp.c | 4 ++++ 6 files changed, 42 insertions(+), 15 deletions(-) diff --git a/slirp/if.c b/slirp/if.c index 9317cbfe9..2ce9a6424 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -79,14 +79,14 @@ writen(fd, bptr, n) int total; /* This should succeed most of the time */ - ret = write(fd, bptr, n); + ret = send(fd, bptr, n,0); if (ret == n || ret <= 0) return ret; /* Didn't write everything, go into the loop */ total = ret; while (n > total) { - ret = write(fd, bptr+total, n-total); + ret = send(fd, bptr+total, n-total,0); if (ret <= 0) return ret; total += ret; @@ -111,7 +111,7 @@ if_input(ttyp) DEBUG_CALL("if_input"); DEBUG_ARG("ttyp = %lx", (long)ttyp); - if_n = read(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE); + if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0); DEBUG_MISC((dfd, " read %d bytes\n", if_n)); diff --git a/slirp/slirp.c b/slirp/slirp.c index 99f168740..3b840a82d 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -414,7 +414,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) /* Connected */ so->so_state &= ~SS_ISFCONNECTING; - ret = write(so->s, &ret, 0); + ret = send(so->s, &ret, 0, 0); if (ret < 0) { /* XXXXX Must fix, zero bytes is a NOP */ if (errno == EAGAIN || errno == EWOULDBLOCK || @@ -447,7 +447,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) */ #ifdef PROBE_CONN if (so->so_state & SS_ISFCONNECTING) { - ret = read(so->s, (char *)&ret, 0); + ret = recv(so->s, (char *)&ret, 0,0); if (ret < 0) { /* XXX */ @@ -460,7 +460,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) /* tcp_input will take care of it */ } else { - ret = write(so->s, &ret, 0); + ret = send(so->s, &ret, 0,0); if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || @@ -496,6 +496,15 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) */ if (if_queued && link_up) if_start(); + + /* clear global file descriptor sets. + * these reside on the stack in vl.c + * so they're unusable if we're not in + * slirp_select_fill or slirp_select_poll. + */ + global_readfds = NULL; + global_writefds = NULL; + global_xfds = NULL; } #define ETH_ALEN 6 diff --git a/slirp/slirp.h b/slirp/slirp.h index b52044a65..964d5e19b 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -329,4 +329,8 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err); #define max(x,y) ((x) > (y) ? (x) : (y)) #endif +#ifdef _WIN32 +#define errno (WSAGetLastError()) +#endif + #endif diff --git a/slirp/socket.c b/slirp/socket.c index 7286b5e19..fe03d448a 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -152,7 +152,7 @@ soread(so) nn = readv(so->s, (struct iovec *)iov, n); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #else - nn = read(so->s, iov[0].iov_base, iov[0].iov_len); + nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); #endif if (nn <= 0) { if (nn < 0 && (errno == EINTR || errno == EAGAIN)) @@ -176,7 +176,7 @@ soread(so) * A return of -1 wont (shouldn't) happen, since it didn't happen above */ if (n == 2 && nn == iov[0].iov_len) - nn += read(so->s, iov[1].iov_base, iov[1].iov_len); + nn += recv(so->s, iov[1].iov_base, iov[1].iov_len,0); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #endif @@ -333,7 +333,7 @@ sowrite(so) DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #else - nn = write(so->s, iov[0].iov_base, iov[0].iov_len); + nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); #endif /* This should never happen, but people tell me it does *shrug* */ if (nn < 0 && (errno == EAGAIN || errno == EINTR)) @@ -349,7 +349,7 @@ sowrite(so) #ifndef HAVE_READV if (n == 2 && nn == iov[0].iov_len) - nn += write(so->s, iov[1].iov_base, iov[1].iov_len); + nn += send(so->s, iov[1].iov_base, iov[1].iov_len,0); DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #endif @@ -572,7 +572,11 @@ solisten(port, laddr, lport, flags) close(s); sofree(so); /* Restore the real errno */ +#ifdef _WIN32 + WSASetLastError(tmperrno); +#else errno = tmperrno; +#endif return NULL; } setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); @@ -643,7 +647,9 @@ sofcantrcvmore(so) { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,0); - FD_CLR(so->s, global_writefds); + if(global_writefds) { + FD_CLR(so->s,global_writefds); + } } so->so_state &= ~(SS_ISFCONNECTING); if (so->so_state & SS_FCANTSENDMORE) @@ -657,9 +663,13 @@ sofcantsendmore(so) struct socket *so; { if ((so->so_state & SS_NOFDREF) == 0) { - shutdown(so->s,1); /* send FIN to fhost */ - FD_CLR(so->s, global_readfds); - FD_CLR(so->s, global_xfds); + shutdown(so->s,1); /* send FIN to fhost */ + if (global_readfds) { + FD_CLR(so->s,global_readfds); + } + if (global_xfds) { + FD_CLR(so->s,global_xfds); + } } so->so_state &= ~(SS_ISFCONNECTING); if (so->so_state & SS_FCANTRCVMORE) diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 42f02b3e6..8729d76a7 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -681,7 +681,7 @@ findso: goto cont_input; } - if(tcp_fconnect(so) == -1 && errno != EINPROGRESS) { + if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { u_char code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", errno,strerror(errno))); diff --git a/slirp/udp.c b/slirp/udp.c index 2dd51a39f..aefa0b749 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -339,7 +339,11 @@ udp_attach(so) int lasterrno=errno; closesocket(so->s); so->s=-1; +#ifdef _WIN32 + WSASetLastError(lasterrno); +#else errno=lasterrno; +#endif } else { /* success, insert in queue */ so->so_expire = curtime + SO_EXPIRE; -- cgit v1.2.3 From e388818682ebce3ae8132c1b8ed2089d6c8ec07c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 16:44:06 +0000 Subject: BSD getopt fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1103 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 196e0287f..132428cf6 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -333,7 +333,6 @@ static int img_create(int argc, char **argv) break; } } - optind++; if (optind >= argc) help(); filename = argv[optind++]; @@ -403,7 +402,6 @@ static int img_commit(int argc, char **argv) break; } } - optind++; if (optind >= argc) help(); filename = argv[optind++]; @@ -511,7 +509,6 @@ static int img_convert(int argc, char **argv) break; } } - optind++; if (optind >= argc) help(); filename = argv[optind++]; @@ -639,7 +636,6 @@ static int img_info(int argc, char **argv) break; } } - optind++; if (optind >= argc) help(); filename = argv[optind++]; @@ -686,6 +682,7 @@ int main(int argc, char **argv) if (argc < 2) help(); cmd = argv[1]; + optind++; if (!strcmp(cmd, "create")) { img_create(argc, argv); } else if (!strcmp(cmd, "commit")) { -- cgit v1.2.3 From 4b19ec0c2be507954352fdcc7172737c46348476 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 16:44:33 +0000 Subject: spelling fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1104 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index da90d54e7..9b4bfe76b 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -309,7 +309,7 @@ static void fd_reset (fdrive_t *drv) } /********************************************************/ -/* Intel 82078 floppy disk controler emulation */ +/* Intel 82078 floppy disk controller emulation */ static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq); static void fdctrl_reset_fifo (fdctrl_t *fdctrl); @@ -363,13 +363,13 @@ do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0) struct fdctrl_t { fdctrl_t *fdctrl; - /* Controler's identification */ + /* Controller's identification */ uint8_t version; /* HW */ int irq_lvl; int dma_chann; uint32_t io_base; - /* Controler state */ + /* Controller state */ QEMUTimer *result_timer; uint8_t state; uint8_t dma_en; @@ -475,14 +475,14 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, // int io_mem; int i; - FLOPPY_DPRINTF("init controler\n"); + FLOPPY_DPRINTF("init controller\n"); fdctrl = qemu_mallocz(sizeof(fdctrl_t)); if (!fdctrl) return NULL; fdctrl->result_timer = qemu_new_timer(vm_clock, fdctrl_result_timer, fdctrl); - fdctrl->version = 0x90; /* Intel 82078 controler */ + fdctrl->version = 0x90; /* Intel 82078 controller */ fdctrl->irq_lvl = irq_lvl; fdctrl->dma_chann = dma_chann; fdctrl->io_base = io_base; @@ -545,14 +545,14 @@ static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) fdctrl->int_status = status; } -/* Reset controler */ +/* Reset controller */ static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq) { int i; - FLOPPY_DPRINTF("reset controler\n"); + FLOPPY_DPRINTF("reset controller\n"); fdctrl_reset_irq(fdctrl); - /* Initialise controler */ + /* Initialise controller */ fdctrl->cur_drv = 0; /* FIFO state */ fdctrl->data_pos = 0; @@ -614,7 +614,7 @@ static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { if (!(value & 0x04)) { - FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } } @@ -636,12 +636,12 @@ static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) /* Reset */ if (!(value & 0x04)) { if (!(fdctrl->state & FD_CTRL_RESET)) { - FLOPPY_DPRINTF("controler enter RESET state\n"); + FLOPPY_DPRINTF("controller enter RESET state\n"); fdctrl->state |= FD_CTRL_RESET; } } else { if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("controler out of RESET state\n"); + FLOPPY_DPRINTF("controller out of RESET state\n"); fdctrl_reset(fdctrl, 1); fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); } @@ -667,7 +667,7 @@ static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value) { /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value); @@ -704,7 +704,7 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) { /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); @@ -811,7 +811,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) kt = fdctrl->fifo[2]; kh = fdctrl->fifo[3]; ks = fdctrl->fifo[4]; - FLOPPY_DPRINTF("Start tranfer at %d %d %02x %02x (%d)\n", + FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n", fdctrl->cur_drv, kh, kt, ks, _fd_sector(kh, kt, ks, cur_drv->last_sect)); did_seek = 0; @@ -881,7 +881,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) (direction == FD_DIR_READ && dma_mode == 1)) { /* No access is allowed until DMA transfer has completed */ fdctrl->state |= FD_CTRL_BUSY; - /* Now, we just have to wait for the DMA controler to + /* Now, we just have to wait for the DMA controller to * recall us... */ DMA_hold_DREQ(fdctrl->dma_chann); @@ -1159,7 +1159,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) cur_drv = get_cur_drv(fdctrl); /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } fdctrl->state &= ~FD_CTRL_SLEEP; @@ -1300,7 +1300,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) /* VERSION */ FLOPPY_DPRINTF("VERSION command\n"); /* No parameters cmd */ - /* Controler's version */ + /* Controller's version */ fdctrl->fifo[0] = fdctrl->version; fdctrl_set_fifo(fdctrl, 1, 1); return; -- cgit v1.2.3 From ba6c23778cd886688c7aef4fcdc53128816f566a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 16:47:59 +0000 Subject: cmos init for IDE (Ben Pfaf) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1105 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 305ea1f5b..74b3b8d68 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -101,13 +101,32 @@ static int cmos_get_fd_drive_type(int fd0) return val; } -static void cmos_init(int ram_size, int boot_device) +static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) +{ + RTCState *s = rtc_state; + int cylinders, heads, sectors; + bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors); + rtc_set_memory(s, type_ofs, 47); + rtc_set_memory(s, info_ofs, cylinders); + rtc_set_memory(s, info_ofs + 1, cylinders >> 8); + rtc_set_memory(s, info_ofs + 2, heads); + rtc_set_memory(s, info_ofs + 3, 0xff); + rtc_set_memory(s, info_ofs + 4, 0xff); + rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3)); + rtc_set_memory(s, info_ofs + 6, cylinders); + rtc_set_memory(s, info_ofs + 7, cylinders >> 8); + rtc_set_memory(s, info_ofs + 8, sectors); +} + +/* hd_table must contain 4 block drivers */ +static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table) { RTCState *s = rtc_state; int val; int fd0, fd1, nb; time_t ti; struct tm *tm; + int i; /* set the CMOS date */ time(&ti); @@ -187,6 +206,39 @@ static void cmos_init(int ram_size, int boot_device) val |= 0x04; /* PS/2 mouse installed */ rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); + /* hard drives */ + + rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0)); + if (hd_table[0]) + cmos_init_hd(0x19, 0x1b, hd_table[0]); + if (hd_table[1]) + cmos_init_hd(0x1a, 0x24, hd_table[1]); + + val = 0; + for (i = 0; i < 4; i++) + if (hd_table[i]) { + int cylinders, heads, sectors; + uint8_t translation; + + bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors); + if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { + /* No translation. */ + translation = 0; + } else if (cylinders * heads > 131072) { + /* LBA translation. */ + translation = 1; + } else { + /* LARGE translation. */ + translation = 2; + } + + val |= translation << (i * 2); + } + rtc_set_memory(s, 0x39, val); + + /* Disable check of 0x55AA signature on the last two bytes of + first sector of disk. XXX: make it the default ? */ + // rtc_set_memory(s, 0x38, 1); } static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) @@ -512,7 +564,7 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); - cmos_init(ram_size, boot_device); + cmos_init(ram_size, boot_device, bs_table); /* must be done after all PCI devices are instanciated */ /* XXX: should be done in the Bochs BIOS */ -- cgit v1.2.3 From 655aa52a90fd6bce4499bbc0eb4264ebd420b3bc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 16:48:17 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1106 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index f722162e6..5117b243e 100644 --- a/Changelog +++ b/Changelog @@ -23,7 +23,9 @@ version 0.6.1: - 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) + - 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) version 0.6.0: -- cgit v1.2.3 From 769bec7271eaaf908a21fb9c1e40937f04af3e90 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 16:48:57 +0000 Subject: IDE fix for NT4 (Ben Pfaf) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1107 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index 9d5988575..63db239c0 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1477,7 +1477,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case WIN_SPECIFY: case WIN_RECAL: s->error = 0; - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; case WIN_SETMULT: @@ -1875,6 +1875,7 @@ static void ide_init2(IDEState *ide_state, int irq, s->heads = 16; s->sectors = 63; } + bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, s->sectors); } if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { s->is_cdrom = 1; -- cgit v1.2.3 From d75d9f6be958f0245ed7794bbd2a31eaffae40da Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 17:20:54 +0000 Subject: SDL Audio support and SB16 fixes (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1108 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + hw/sb16.c | 365 +++++++++++++++++++++++++------ oss.c | 727 +++++++++++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 860 insertions(+), 233 deletions(-) diff --git a/Changelog b/Changelog index 5117b243e..73b85e5dd 100644 --- a/Changelog +++ b/Changelog @@ -26,6 +26,7 @@ version 0.6.1: - 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) version 0.6.0: diff --git a/hw/sb16.c b/hw/sb16.c index 260718cdc..f84cf8d4a 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -26,12 +26,10 @@ #define MIN(a, b) ((a)>(b)?(b):(a)) #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) -#define log(...) do { \ - fprintf (stderr, "sb16: " __VA_ARGS__); \ - fputc ('\n', stderr); \ -} while (0) +#define dolog(...) fprintf (stderr, "sb16: " __VA_ARGS__); /* #define DEBUG_SB16 */ + #ifdef DEBUG_SB16 #define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__) #define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__) @@ -47,7 +45,10 @@ #define IO_WRITE_PROTO(name) \ void name (void *opaque, uint32_t nport, uint32_t val) -static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; +static const char e3[] = + "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992\0" + "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1994-1997"; + /* "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1994."; */ static struct { int ver_lo; @@ -80,10 +81,13 @@ typedef struct SB16State { int v2x6; - uint8_t in_data[10]; - uint8_t out_data[50]; + uint8_t in2_data[10]; + uint8_t out_data[1024]; int left_till_irq; + uint64_t nzero; + uint8_t last_read_byte; + uint8_t test_reg; /* mixer state */ int mixer_nreg; @@ -95,7 +99,7 @@ static struct SB16State dsp; static void log_dsp (SB16State *dsp) { - linfo ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n", + ldebug ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n", dsp->fmt_stereo ? 'S' : 'M', dsp->fmt_signed ? 'S' : 'U', dsp->fmt_bits, @@ -191,6 +195,7 @@ static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len) mix_block = ((dsp.freq * align) / 100) & ~(align - 1); } + if (dsp.freq) AUD_reset (dsp.freq, 1 << dsp.fmt_stereo, fmt); control (1); dsp.speaker = 1; @@ -202,9 +207,17 @@ static inline void dsp_out_data(SB16State *dsp, int val) dsp->out_data[dsp->out_data_len++] = val; } +static inline uint8_t dsp_get_data(SB16State *dsp) +{ + if (dsp->in_index) + return dsp->in2_data[--dsp->in_index]; + else + return 0; +} + static void command (SB16State *dsp, uint8_t cmd) { - linfo ("%#x\n", cmd); + linfo ("command: %#x\n", cmd); if (cmd > 0xaf && cmd < 0xd0) { if (cmd & 8) @@ -215,7 +228,7 @@ static void command (SB16State *dsp, uint8_t cmd) case 12: break; default: - log("%#x wrong bits", cmd); + dolog ("command: %#x wrong bits specification\n", cmd); goto error; } dsp->needed_bytes = 3; @@ -223,23 +236,25 @@ static void command (SB16State *dsp, uint8_t cmd) else { switch (cmd) { case 0x00: - case 0x03: case 0xe7: /* IMS uses those when probing for sound devices */ return; + case 0x03: case 0x04: - dsp->needed_bytes = 1; - break; + dsp_out_data (dsp, 0); + return; case 0x05: + dsp->needed_bytes = 2; + break; + case 0x0e: dsp->needed_bytes = 2; break; case 0x0f: dsp->needed_bytes = 1; - dsp_out_data (dsp, 0); break; case 0x10: @@ -272,6 +287,8 @@ static void command (SB16State *dsp, uint8_t cmd) dsp->needed_bytes = 2; break; + case 0x45: + dsp_out_data (dsp, 0xaa); case 0x47: /* Continue Auto-Initialize DMA 16bit */ break; @@ -346,19 +363,39 @@ static void command (SB16State *dsp, uint8_t cmd) case 0xe3: { int i; - for (i = sizeof (e3) - 1; i >= 0; --i) + for (i = sizeof (e3) - 1; i >= 0; i--) dsp_out_data (dsp, e3[i]); return; } + case 0xe4: /* write test reg */ + dsp->needed_bytes = 1; + break; + + case 0xe8: /* read test reg */ + dsp_out_data (dsp, dsp->test_reg); + break; + case 0xf2: - dsp_out_data(dsp, 0xaa); + dsp_out_data (dsp, 0xaa); dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; pic_set_irq (sb.irq, 1); return; + case 0xf9: + dsp->needed_bytes = 1; + break; + + case 0xfa: + dsp_out_data (dsp, 0); + break; + + case 0xfc: /* FIXME */ + dsp_out_data (dsp, 0); + break; + default: - log("%#x is unknown", cmd); + dolog ("unrecognized command %#x\n", cmd); goto error; } } @@ -371,15 +408,14 @@ static void command (SB16State *dsp, uint8_t cmd) static void complete (SB16State *dsp) { + int d0, d1, d2; linfo ("complete command %#x, in_index %d, needed_bytes %d\n", dsp->cmd, dsp->in_index, dsp->needed_bytes); if (dsp->cmd > 0xaf && dsp->cmd < 0xd0) { - int d0, d1, d2; - - d0 = dsp->in_data[0]; - d1 = dsp->in_data[1]; - d2 = dsp->in_data[2]; + d2 = dsp_get_data (dsp); + d1 = dsp_get_data (dsp); + d0 = dsp_get_data (dsp); ldebug ("d0 = %d, d1 = %d, d2 = %d\n", d0, d1, d2); @@ -387,23 +423,29 @@ static void complete (SB16State *dsp) } else { switch (dsp->cmd) { - case 0x05: case 0x04: - case 0x0e: + case 0x10: + dsp_get_data (dsp); + break; + case 0x0f: + d0 = dsp_get_data (dsp); + dsp_out_data (dsp, 0xf8); break; - case 0x10: + case 0x05: + case 0x0e: + dsp_get_data (dsp); + dsp_get_data (dsp); break; case 0x14: { - int d0, d1; int save_left; int save_pos; - d0 = dsp->in_data[0]; - d1 = dsp->in_data[1]; + d1 = dsp_get_data (dsp); + d0 = dsp_get_data (dsp); save_left = dsp->left_till_irq; save_pos = dsp->dma_pos; @@ -417,35 +459,60 @@ static void complete (SB16State *dsp) } case 0x40: - dsp->time_const = dsp->in_data[0]; + dsp->time_const = dsp_get_data (dsp); linfo ("set time const %d\n", dsp->time_const); break; case 0x41: case 0x42: - dsp->freq = dsp->in_data[1] + (dsp->in_data[0] << 8); - linfo ("set freq %#x, %#x = %d\n", - dsp->in_data[1], dsp->in_data[0], dsp->freq); + d1 = dsp_get_data (dsp); + d0 = dsp_get_data (dsp); + + dsp->freq = d1 + (d0 << 8); + linfo ("set freq %#x, %#x = %d\n", d1, d0, dsp->freq); break; case 0x48: - dsp->dma_buffer_size = dsp->in_data[1] + (dsp->in_data[0] << 8); + d1 = dsp_get_data (dsp); + d0 = dsp_get_data (dsp); + dsp->dma_buffer_size = d1 + (d0 << 8); linfo ("set dma len %#x, %#x = %d\n", - dsp->in_data[1], dsp->in_data[0], dsp->dma_buffer_size); + d1, d0, dsp->dma_buffer_size); break; case 0xe0: + d0 = dsp_get_data (dsp); dsp->out_data_len = 0; - linfo ("data = %#x\n", dsp->in_data[0]); - dsp_out_data(dsp, dsp->in_data[0] ^ 0xff); + linfo ("data = %#x\n", d0); + dsp_out_data (dsp, d0 ^ 0xff); + break; + + case 0xe4: + dsp->test_reg = dsp_get_data (dsp); + break; + + + case 0xf9: + d0 = dsp_get_data (dsp); + ldebug ("f9 <- %#x\n", d0); + switch (d0) { + case 0x0e: dsp_out_data (dsp, 0xff); break; + case 0x0f: dsp_out_data (dsp, 0x07); break; + case 0xf9: dsp_out_data (dsp, 0x00); break; + case 0x37: + dsp_out_data (dsp, 0x38); break; + default: + dsp_out_data (dsp, 0); + } break; default: - log ("unrecognized command %#x", dsp->cmd); + dolog ("complete: unrecognized command %#x\n", dsp->cmd); return; } } + dsp->needed_bytes = 0; dsp->cmd = -1; return; } @@ -457,7 +524,7 @@ static IO_WRITE_PROTO (dsp_write) iport = nport - sb.port; - ldebug ("write %#x %#x\n", nport, iport); + ldebug ("dsp_write %#x <- %#x\n", nport, val); switch (iport) { case 0x6: control (0); @@ -465,6 +532,14 @@ static IO_WRITE_PROTO (dsp_write) dsp->v2x6 = 0; else if ((1 == val) && (0 == dsp->v2x6)) { dsp->v2x6 = 1; + dsp->dma_pos = 0; + dsp->dma_auto = 0; + dsp->in_index = 0; + dsp->out_data_len = 0; + dsp->left_till_irq = 0; + dsp->speaker = 0; + dsp->needed_bytes = 0; + pic_set_irq (sb.irq, 0); dsp_out_data(dsp, 0xaa); } else @@ -479,18 +554,22 @@ static IO_WRITE_PROTO (dsp_write) } } else { - dsp->in_data[dsp->in_index++] = val; + if (dsp->in_index == sizeof (dsp->in2_data)) { + dolog ("in data overrun\n"); + } + else { + dsp->in2_data[dsp->in_index++] = val; if (dsp->in_index == dsp->needed_bytes) { dsp->needed_bytes = 0; - dsp->in_index = 0; complete (dsp); log_dsp (dsp); } } + } break; default: - log ("(nport=%#x, val=%#x)", nport, val); + dolog ("dsp_write (nport=%#x, val=%#x)\n", nport, val); break; } } @@ -503,31 +582,36 @@ static IO_READ_PROTO (dsp_read) iport = nport - sb.port; switch (iport) { - case 0x6: /* reset */ - return 0; + control (0); + retval = 0; + dsp->speaker = 0; + break; case 0xa: /* read data */ if (dsp->out_data_len) { retval = dsp->out_data[--dsp->out_data_len]; + dsp->last_read_byte = retval; } else { - log("empty output buffer"); - goto error; + retval = dsp->last_read_byte; + dolog ("empty output buffer\n"); + /* goto error; */ } break; - case 0xc: /* 0 can write */ + case 0xc: /* 0xxxxxxx can write */ retval = 0; + if (dsp->out_data_len == sizeof (dsp->out_data)) retval |= 0x80; break; case 0xd: /* timer interrupt clear */ - log("timer interrupt clear"); + dolog ("timer interrupt clear\n"); goto error; case 0xe: /* data available status | irq 8 ack */ /* XXX drop pic irq line here? */ - ldebug ("8 ack\n"); - retval = (0 == dsp->out_data_len) ? 0 : 0x80; + /* ldebug ("8 ack\n"); */ + retval = dsp->out_data_len ? 0x80 : 0; dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80]; pic_set_irq (sb.irq, 0); break; @@ -544,15 +628,30 @@ static IO_READ_PROTO (dsp_read) goto error; } - if ((0xc != iport) && (0xe != iport)) { - ldebug ("nport=%#x iport %#x = %#x\n", + if (0xe == iport) { + if (0 == retval) { + if (!dsp->nzero) { + ldebug ("dsp_read (nport=%#x iport %#x) = %#x, %lld\n", + nport, iport, retval, dsp->nzero); + } + dsp->nzero += 1; + } + else { + ldebug ("dsp_read (nport=%#x iport %#x) = %#x, %lld\n", + nport, iport, retval, dsp->nzero); + dsp->nzero = 0; + } + } + else { + ldebug ("dsp_read (nport=%#x iport %#x) = %#x\n", nport, iport, retval); } return retval; error: - return 0; + printf ("dsp_read error %#x\n", nport); + return 0xff; } static IO_WRITE_PROTO(mixer_write_indexb) @@ -564,12 +663,100 @@ static IO_WRITE_PROTO(mixer_write_indexb) static IO_WRITE_PROTO(mixer_write_datab) { SB16State *dsp = opaque; + int i; - if (dsp->mixer_nreg > 0x83) + linfo ("mixer [%#x] <- %#x\n", dsp->mixer_nreg, val); + switch (dsp->mixer_nreg) { + case 0x00: + /* Bochs */ + dsp->mixer_regs[0x04] = 0xcc; + dsp->mixer_regs[0x0a] = 0x00; + dsp->mixer_regs[0x22] = 0xcc; + dsp->mixer_regs[0x26] = 0xcc; + dsp->mixer_regs[0x28] = 0x00; + dsp->mixer_regs[0x2e] = 0x00; + dsp->mixer_regs[0x3c] = 0x1f; + dsp->mixer_regs[0x3d] = 0x15; + dsp->mixer_regs[0x3e] = 0x0b; + + for (i = 0x30; i <= 0x35; i++) + dsp->mixer_regs[i] = 0xc0; + + for (i = 0x36; i <= 0x3b; i++) + dsp->mixer_regs[i] = 0x00; + + for (i = 0x3f; i <= 0x43; i++) + dsp->mixer_regs[i] = 0x00; + + for (i = 0x44; i <= 0x47; i++) + dsp->mixer_regs[i] = 0x80; + + for (i = 0x30; i < 0x48; i++) { + dsp->mixer_regs[i] = 0x20; + } + break; + + case 0x04: + case 0x0a: + case 0x22: + case 0x26: + case 0x28: + case 0x2e: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x80: + case 0x81: + break; + default: return; + } dsp->mixer_regs[dsp->mixer_nreg] = val; } +static IO_WRITE_PROTO(mpu_write) +{ + linfo ("mpu: %#x\n", val); +} + +static IO_WRITE_PROTO(adlib_write) +{ + linfo ("adlib: %#x\n", val); +} + +static IO_READ_PROTO(mpu_read) +{ + linfo ("mpu read: %#x\n", nport); + return 0x80; +} + +static IO_READ_PROTO(adlib_read) +{ + linfo ("adlib read: %#x\n", nport); + return 0; +} + static IO_WRITE_PROTO(mixer_write_indexw) { mixer_write_indexb (opaque, nport, val & 0xff); @@ -579,6 +766,7 @@ static IO_WRITE_PROTO(mixer_write_indexw) static IO_READ_PROTO(mixer_read) { SB16State *dsp = opaque; + linfo ("mixer [%#x] -> %#x\n", dsp->mixer_nreg, dsp->mixer_regs[dsp->mixer_nreg]); return dsp->mixer_regs[dsp->mixer_nreg]; } @@ -637,6 +825,8 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) return 0; if (dsp->left_till_irq < 0) { + ldebug ("left_till_irq < 0, %d, pos %d \n", + dsp->left_till_irq, dsp->dma_buffer_size); dsp->left_till_irq += dsp->dma_buffer_size; return dsp->dma_pos; } @@ -644,6 +834,7 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) free = AUD_get_free (); if ((free <= 0) || (0 == size)) { + ldebug ("returning, since free = %d and size = %d\n", free, size); return dsp->dma_pos; } @@ -656,8 +847,11 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) till = dsp->left_till_irq; +#ifdef DEBUG_SB16_MOST ldebug ("addr:%#010x free:%d till:%d size:%d\n", addr, free, till, size); +#endif + if (till <= copy) { if (0 == dsp->dma_auto) { copy = till; @@ -671,7 +865,8 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) if (dsp->left_till_irq <= 0) { dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; if (0 == noirq) { - ldebug ("request irq\n"); + ldebug ("request irq pos %d, left %d\n", + dsp->dma_pos, dsp->left_till_irq); pic_set_irq(sb.irq, 1); } @@ -680,9 +875,11 @@ static int SB_read_DMA (void *opaque, target_ulong addr, int size) } } +#ifdef DEBUG_SB16_MOST ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n", dsp->dma_pos, free, size, dsp->left_till_irq, copy, dsp->dma_buffer_size); +#endif if (dsp->left_till_irq <= 0) { dsp->left_till_irq += dsp->dma_buffer_size; @@ -703,7 +900,7 @@ static int magic_of_irq (int irq) case 10: return 8; default: - log ("bad irq %d", irq); + dolog ("bad irq %d\n", irq); return 2; } } @@ -721,12 +918,42 @@ static int irq_of_magic (int magic) case 8: return 10; default: - log ("bad irq magic %d", magic); + dolog ("bad irq magic %d\n", magic); return 2; } } #endif +#ifdef SB16_TRAP_ALL +static IO_READ_PROTO (trap_read) +{ + switch (nport) { + case 0x220: + return 0; + case 0x226: + case 0x22a: + case 0x22c: + case 0x22d: + case 0x22e: + case 0x22f: + return dsp_read (opaque, nport); + } + linfo ("trap_read: %#x\n", nport); + return 0xff; +} + +static IO_WRITE_PROTO (trap_write) +{ + switch (nport) { + case 0x226: + case 0x22c: + dsp_write (opaque, nport, val); + return; + } + linfo ("trap_write: %#x = %#x\n", nport, val); +} +#endif + void SB16_init (void) { SB16State *s = &dsp; @@ -736,13 +963,23 @@ void SB16_init (void) memset(s->mixer_regs, 0xff, sizeof(s->mixer_regs)); + s->mixer_regs[0x00] = 0; s->mixer_regs[0x0e] = ~0; s->mixer_regs[0x80] = magic_of_irq (sb.irq); - s->mixer_regs[0x81] = 0x20 | (sb.dma << 1); - - for (i = 0x30; i < 0x48; i++) { - s->mixer_regs[i] = 0x20; + s->mixer_regs[0x81] = 0x80 | 0x10 | (sb.dma << 1); + s->mixer_regs[0x82] = 0; + s->mixer_regs[0xfd] = 16; /* bochs */ + s->mixer_regs[0xfe] = 6; /* bochs */ + mixer_write_indexw (s, 0x224, 0); + +#ifdef SB16_TRAP_ALL + for (i = 0; i < 0x100; i++) { + if (i != 4 && i != 5) { + register_ioport_write (sb.port + i, 1, 1, trap_write, s); + register_ioport_read (sb.port + i, 1, 1, trap_read, s); + } } +#else for (i = 0; i < LENOFA (dsp_write_ports); i++) { register_ioport_write (sb.port + dsp_write_ports[i], 1, 1, dsp_write, s); @@ -751,12 +988,20 @@ void SB16_init (void) for (i = 0; i < LENOFA (dsp_read_ports); i++) { register_ioport_read (sb.port + dsp_read_ports[i], 1, 1, dsp_read, s); } +#endif register_ioport_write (sb.port + 0x4, 1, 1, mixer_write_indexb, s); register_ioport_write (sb.port + 0x4, 1, 2, mixer_write_indexw, s); register_ioport_read (sb.port + 0x5, 1, 1, mixer_read, s); register_ioport_write (sb.port + 0x5, 1, 1, mixer_write_datab, s); + for (i = 0; 4 < 4; i++) { + register_ioport_read (0x330 + i, 1, 1, mpu_read, s); + register_ioport_write (0x330 + i, 1, 1, mpu_write, s); + register_ioport_read (0x388 + i, 1, 1, adlib_read, s); + register_ioport_write (0x388 + i, 1, 1, adlib_write, s); + } + DMA_register_channel (sb.hdma, SB_read_DMA, s); DMA_register_channel (sb.dma, SB_read_DMA, s); } diff --git a/oss.c b/oss.c index 40c9462cf..91eb47e49 100644 --- a/oss.c +++ b/oss.c @@ -23,22 +23,446 @@ */ #include "vl.h" -#if !defined(_WIN32) && !defined(__APPLE__) -#include +#include +#include +#include +#include + +/* TODO: Graceful error handling */ + +#if defined(_WIN32) +#define USE_SDL_AUDIO +#endif + +#define MIN(a, b) ((a)>(b)?(b):(a)) +#define MAX(a, b) ((a)<(b)?(b):(a)) + +#define DEREF(x) (void)x +#define dolog(...) fprintf (stderr, "audio: " __VA_ARGS__) +#define ERRFail(...) do { \ + int _errno = errno; \ + fprintf (stderr, "audio: " __VA_ARGS__); \ + fprintf (stderr, "\nsystem error: %s\n", strerror (_errno)); \ + abort (); \ +} while (0) +#define Fail(...) do { \ + fprintf (stderr, "audio: " __VA_ARGS__); \ + fprintf (stderr, "\n"); \ + abort (); \ +} while (0) + +#ifdef DEBUG_AUDIO +#define lwarn(...) fprintf (stderr, "audio: " __VA_ARGS__) +#define linfo(...) fprintf (stderr, "audio: " __VA_ARGS__) +#define ldebug(...) fprintf (stderr, "audio: " __VA_ARGS__) +#else +#define lwarn(...) +#define linfo(...) +#define ldebug(...) +#endif + +static int get_conf_val (const char *key, int defval) +{ + int val = defval; + char *strval; + + strval = getenv (key); + if (strval) { + val = atoi (strval); + } + + return val; +} + +static void copy_no_conversion (void *dst, void *src, int size) +{ + memcpy (dst, src, size); +} + +static void copy_u16_to_s16 (void *dst, void *src, int size) +{ + int i; + uint16_t *out, *in; + + out = dst; + in = src; + + for (i = 0; i < size / 2; i++) { + out[i] = in[i] + 0x8000; + } +} + +#ifdef USE_SDL_AUDIO +#include +#include + +static struct { + int samples; +} conf = { + .samples = 4096 +}; + +typedef struct AudioState { + int freq; + int bits16; + int nchannels; + int rpos; + int wpos; + volatile int live; + volatile int exit; + int bytes_per_second; + Uint8 *buf; + int bufsize; + int leftover; + uint64_t old_ticks; + SDL_AudioSpec spec; + SDL_mutex *mutex; + SDL_sem *sem; + void (*copy_fn)(void *, void *, int); +} AudioState; + +static AudioState sdl_audio; + +void AUD_run (void) +{ +} + +static void own (AudioState *s) +{ + /* SDL_LockAudio (); */ + if (SDL_mutexP (s->mutex)) + dolog ("SDL_mutexP: %s\n", SDL_GetError ()); +} + +static void disown (AudioState *s) +{ + /* SDL_UnlockAudio (); */ + if (SDL_mutexV (s->mutex)) + dolog ("SDL_mutexV: %s\n", SDL_GetError ()); +} + +static void sem_wait (AudioState *s) +{ + if (SDL_SemWait (s->sem)) + dolog ("SDL_SemWait: %s\n", SDL_GetError ()); +} + +static void sem_post (AudioState *s) +{ + if (SDL_SemPost (s->sem)) + dolog ("SDL_SemPost: %s\n", SDL_GetError ()); +} + +static void audio_callback (void *data, Uint8 *stream, int len) +{ + int to_mix; + AudioState *s = data; + + if (s->exit) return; + while (len) { + sem_wait (s); + if (s->exit) return; + own (s); + to_mix = MIN (len, s->live); + len -= to_mix; + /* printf ("to_mix=%d len=%d live=%d\n", to_mix, len, s->live); */ + while (to_mix) { + int chunk = MIN (to_mix, s->bufsize - s->rpos); + /* SDL_MixAudio (stream, buf, chunk, SDL_MIX_MAXVOLUME); */ + memcpy (stream, s->buf + s->rpos, chunk); + + s->rpos += chunk; + s->live -= chunk; + + stream += chunk; + to_mix -= chunk; + + if (s->rpos == s->bufsize) s->rpos = 0; + } + disown (s); + } +} + +static void sem_zero (AudioState *s) +{ + int res; + + do { + res = SDL_SemTryWait (s->sem); + if (res < 0) { + dolog ("SDL_SemTryWait: %s\n", SDL_GetError ()); + return; + } + } while (res != SDL_MUTEX_TIMEDOUT); +} + +static void do_open (AudioState *s) +{ + int status; + SDL_AudioSpec obtained; + + SDL_PauseAudio (1); + if (s->buf) { + s->exit = 1; + sem_post (s); + SDL_CloseAudio (); + s->exit = 0; + qemu_free (s->buf); + s->buf = NULL; + sem_zero (s); + } + + s->bytes_per_second = (s->spec.freq << (s->spec.channels >> 1)) << s->bits16; + s->spec.samples = conf.samples; + s->spec.userdata = s; + s->spec.callback = audio_callback; + + status = SDL_OpenAudio (&s->spec, &obtained); + if (status < 0) { + dolog ("SDL_OpenAudio: %s\n", SDL_GetError ()); + goto exit; + } + + if (obtained.freq != s->spec.freq || + obtained.channels != s->spec.channels || + obtained.format != s->spec.format) { + dolog ("Audio spec mismatch requested obtained\n" + "freq %5d %5d\n" + "channels %5d %5d\n" + "fmt %5d %5d\n", + s->spec.freq, obtained.freq, + s->spec.channels, obtained.channels, + s->spec.format, obtained.format + ); + } + + s->bufsize = obtained.size; + s->buf = qemu_mallocz (s->bufsize); + if (!s->buf) { + dolog ("qemu_mallocz(%d)\n", s->bufsize); + goto exit; + } + SDL_PauseAudio (0); + +exit: + s->rpos = 0; + s->wpos = 0; + s->live = 0; +} + +int AUD_write (void *in_buf, int size) +{ + AudioState *s = &sdl_audio; + int to_copy, temp; + uint8_t *in, *out; + + own (s); + to_copy = MIN (s->bufsize - s->live, size); + + temp = to_copy; + + in = in_buf; + out = s->buf; + + while (temp) { + int copy; + + copy = MIN (temp, s->bufsize - s->wpos); + s->copy_fn (out + s->wpos, in, copy); + + s->wpos += copy; + if (s->wpos == s->bufsize) { + s->wpos = 0; + } + + temp -= copy; + in += copy; + s->live += copy; + } + + disown (s); + sem_post (s); + return to_copy; +} + +static void maybe_open (AudioState *s, int req_freq, int req_nchannels, + audfmt_e req_fmt, int force_open) +{ + int sdl_fmt, bits16; + + switch (req_fmt) { + case AUD_FMT_U8: + bits16 = 0; + sdl_fmt = AUDIO_U8; + s->copy_fn = copy_no_conversion; + break; + + case AUD_FMT_S8: + fprintf (stderr, "audio: can not play 8bit signed\n"); + return; + + case AUD_FMT_S16: + bits16 = 1; + sdl_fmt = AUDIO_S16; + s->copy_fn = copy_no_conversion; + break; + + case AUD_FMT_U16: + bits16 = 1; + sdl_fmt = AUDIO_S16; + s->copy_fn = copy_u16_to_s16; + break; + + default: + abort (); + } + + if (force_open + || (NULL == s->buf) + || (sdl_fmt != s->spec.format) + || (req_nchannels != s->spec.channels) + || (req_freq != s->spec.freq) + || (bits16 != s->bits16)) { + + s->spec.format = sdl_fmt; + s->spec.channels = req_nchannels; + s->spec.freq = req_freq; + s->bits16 = bits16; + do_open (s); + } +} + +void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) +{ + AudioState *s = &sdl_audio; + own (s); + maybe_open (s, req_freq, req_nchannels, req_fmt, 0); + disown (s); +} + +void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) +{ + AudioState *s = &sdl_audio; + own (s); + maybe_open (s, req_freq, req_nchannels, req_fmt, 1); + disown (s); +} + +void AUD_adjust_estimate (int leftover) +{ + AudioState *s = &sdl_audio; + own (s); + s->leftover = leftover; + disown (s); +} + +int AUD_get_free (void) +{ + int free, elapsed; + uint64_t ticks, delta; + uint64_t ua_elapsed; + uint64_t al_elapsed; + AudioState *s = &sdl_audio; + + own (s); + free = s->bufsize - s->live; + + if (0 == free) { + disown (s); + return 0; + } + + elapsed = free; + ticks = qemu_get_clock(rt_clock); + delta = ticks - s->old_ticks; + s->old_ticks = ticks; + + ua_elapsed = (delta * s->bytes_per_second) / 1000; + al_elapsed = ua_elapsed & ~3ULL; + + ldebug ("tid elapsed %llu bytes\n", ua_elapsed); + + if (al_elapsed > (uint64_t) INT_MAX) + elapsed = INT_MAX; + else + elapsed = al_elapsed; + + elapsed += s->leftover; + disown (s); + + if (elapsed > free) { + lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free); + return free; + } + else { + return elapsed; + } +} + +int AUD_get_live (void) +{ + int live; + AudioState *s = &sdl_audio; + + own (s); + live = s->live; + disown (s); + return live; +} + +int AUD_get_buffer_size (void) +{ + int bufsize; + AudioState *s = &sdl_audio; + + own (s); + bufsize = s->bufsize; + disown (s); + return bufsize; +} + +#define QC_SDL_NSAMPLES "QEMU_SDL_NSAMPLES" + +static void cleanup (void) +{ + AudioState *s = &sdl_audio; + own (s); + s->exit = 1; + sem_post (s); + disown (s); +} + +void AUD_init (void) +{ + AudioState *s = &sdl_audio; + + atexit (cleanup); + SDL_InitSubSystem (SDL_INIT_AUDIO); + s->mutex = SDL_CreateMutex (); + if (!s->mutex) { + dolog ("SDL_CreateMutex: %s\n", SDL_GetError ()); + return; + } + + s->sem = SDL_CreateSemaphore (0); + if (!s->sem) { + dolog ("SDL_CreateSemaphore: %s\n", SDL_GetError ()); + return; + } + + conf.samples = get_conf_val (QC_SDL_NSAMPLES, conf.samples); +} + +#elif !defined(_WIN32) && !defined(__APPLE__) + #include #include -#include #include -#include -#include -#include -#include #include #include #include #include - /* http://www.df.lth.se/~john_e/gems/gem002d.html */ /* http://www.multi-platforms.com/Tips/PopCount.htm */ static inline uint32_t popcount (uint32_t u) @@ -56,34 +480,6 @@ static inline uint32_t lsbindex (uint32_t u) return popcount ((u&-u)-1); } -#define MIN(a, b) ((a)>(b)?(b):(a)) -#define MAX(a, b) ((a)<(b)?(b):(a)) - -#define DEREF(x) (void)x -#define log(...) fprintf (stderr, "oss: " __VA_ARGS__) -#define ERRFail(...) do { \ - int _errno = errno; \ - fprintf (stderr, "oss: " __VA_ARGS__); \ - fprintf (stderr, "system error: %s\n", strerror (_errno)); \ - abort (); \ -} while (0) -#define Fail(...) do { \ - fprintf (stderr, "oss: " __VA_ARGS__); \ - fprintf (stderr, "\n"); \ - abort (); \ -} while (0) - -#ifdef DEBUG_OSS -#define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__) -#define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__) -#define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__) -#else -#define lwarn(...) -#define linfo(...) -#define ldebug(...) -#endif - - #define IOCTL(args) do { \ int ret = ioctl args; \ if (-1 == ret) { \ @@ -92,7 +488,7 @@ static inline uint32_t lsbindex (uint32_t u) ldebug ("ioctl " #args " = %d\n", ret); \ } while (0) -static struct { +typedef struct AudioState { int fd; int freq; int bits16; @@ -111,7 +507,9 @@ static struct { int leftover; uint64_t old_ticks; void (*copy_fn)(void *, void *, int); -} oss = { .fd = -1 }; +} AudioState; + +static AudioState oss_audio = { .fd = -1 }; static struct { int try_mmap; @@ -125,25 +523,7 @@ static struct { static enum {DONT, DSP, TID} est = DONT; -static void copy_no_conversion (void *dst, void *src, int size) -{ - memcpy (dst, src, size); -} - -static void copy_u16_to_s16 (void *dst, void *src, int size) -{ - int i; - uint16_t *out, *in; - - out = dst; - in = src; - - for (i = 0; i < size / 2; i++) { - out[i] = in[i] + 0x8000; - } -} - -static void pab (struct audio_buf_info *abinfo) +static void pab (AudioState *s, struct audio_buf_info *abinfo) { DEREF (abinfo); @@ -153,118 +533,122 @@ static void pab (struct audio_buf_info *abinfo) abinfo->fragstotal, abinfo->fragsize, abinfo->bytes, - rpos, wpos, live); + s->rpos, s->wpos, s->live); } -static void do_open () +static void do_open (AudioState *s) { int mmmmssss; audio_buf_info abinfo; int fmt, freq, nchannels; - if (oss.buf) { - if (-1 == munmap (oss.buf, oss.bufsize)) { + if (s->buf) { + if (s->is_mapped) { + if (-1 == munmap (s->buf, s->bufsize)) { ERRFail ("failed to unmap audio buffer %p %d", - oss.buf, oss.bufsize); + s->buf, s->bufsize); + } } - oss.buf = NULL; + else { + qemu_free (s->buf); + } + s->buf = NULL; } - if (-1 != oss.fd) - close (oss.fd); + if (-1 != s->fd) + close (s->fd); - oss.fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK); - if (-1 == oss.fd) { + s->fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK); + if (-1 == s->fd) { ERRFail ("can not open /dev/dsp"); } - fmt = oss.oss_fmt; - freq = oss.freq; - nchannels = oss.nchannels; + fmt = s->oss_fmt; + freq = s->freq; + nchannels = s->nchannels; - IOCTL ((oss.fd, SNDCTL_DSP_RESET, 1)); - IOCTL ((oss.fd, SNDCTL_DSP_SAMPLESIZE, &fmt)); - IOCTL ((oss.fd, SNDCTL_DSP_CHANNELS, &nchannels)); - IOCTL ((oss.fd, SNDCTL_DSP_SPEED, &freq)); - IOCTL ((oss.fd, SNDCTL_DSP_NONBLOCK)); + IOCTL ((s->fd, SNDCTL_DSP_RESET, 1)); + IOCTL ((s->fd, SNDCTL_DSP_SAMPLESIZE, &fmt)); + IOCTL ((s->fd, SNDCTL_DSP_CHANNELS, &nchannels)); + IOCTL ((s->fd, SNDCTL_DSP_SPEED, &freq)); + IOCTL ((s->fd, SNDCTL_DSP_NONBLOCK)); mmmmssss = (conf.nfrags << 16) | conf.fragsize; - IOCTL ((oss.fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); + IOCTL ((s->fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); - if ((oss.oss_fmt != fmt) - || (oss.nchannels != nchannels) - || (oss.freq != freq)) { + if ((s->oss_fmt != fmt) + || (s->nchannels != nchannels) + || (s->freq != freq)) { Fail ("failed to set audio parameters\n" "parameter | requested value | obtained value\n" "format | %10d | %10d\n" "channels | %10d | %10d\n" "frequency | %10d | %10d\n", - oss.oss_fmt, fmt, - oss.nchannels, nchannels, - oss.freq, freq); + s->oss_fmt, fmt, + s->nchannels, nchannels, + s->freq, freq); } - IOCTL ((oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo)); + IOCTL ((s->fd, SNDCTL_DSP_GETOSPACE, &abinfo)); - oss.nfrags = abinfo.fragstotal; - oss.fragsize = abinfo.fragsize; - oss.bufsize = oss.nfrags * oss.fragsize; - oss.old_optr = 0; + s->nfrags = abinfo.fragstotal; + s->fragsize = abinfo.fragsize; + s->bufsize = s->nfrags * s->fragsize; + s->old_optr = 0; - oss.bytes_per_second = (freq << (nchannels >> 1)) << oss.bits16; + s->bytes_per_second = (freq << (nchannels >> 1)) << s->bits16; - linfo ("bytes per second %d\n", oss.bytes_per_second); + linfo ("bytes per second %d\n", s->bytes_per_second); linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", abinfo.fragments, abinfo.fragstotal, abinfo.fragsize, abinfo.bytes, - oss.bufsize); + s->bufsize); - oss.buf = MAP_FAILED; - oss.is_mapped = 0; + s->buf = MAP_FAILED; + s->is_mapped = 0; if (conf.try_mmap) { - oss.buf = mmap (NULL, oss.bufsize, PROT_WRITE, MAP_SHARED, oss.fd, 0); - if (MAP_FAILED == oss.buf) { + s->buf = mmap (NULL, s->bufsize, PROT_WRITE, MAP_SHARED, s->fd, 0); + if (MAP_FAILED == s->buf) { int err; err = errno; - log ("failed to mmap audio, size %d, fd %d\n" + dolog ("failed to mmap audio, size %d, fd %d\n" "syserr: %s\n", - oss.bufsize, oss.fd, strerror (err)); + s->bufsize, s->fd, strerror (err)); } else { est = TID; - oss.is_mapped = 1; + s->is_mapped = 1; } } - if (MAP_FAILED == oss.buf) { + if (MAP_FAILED == s->buf) { est = TID; - oss.buf = mmap (NULL, oss.bufsize, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (MAP_FAILED == oss.buf) { - ERRFail ("mmap audio buf, size %d", oss.bufsize); + s->buf = qemu_mallocz (s->bufsize); + if (!s->buf) { + ERRFail ("audio buf malloc failed, size %d", s->bufsize); } } - oss.rpos = 0; - oss.wpos = 0; - oss.live = 0; + s->rpos = 0; + s->wpos = 0; + s->live = 0; - if (oss.is_mapped) { + if (s->is_mapped) { int trig; trig = 0; - IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); + IOCTL ((s->fd, SNDCTL_DSP_SETTRIGGER, &trig)); trig = PCM_ENABLE_OUTPUT; - IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); + IOCTL ((s->fd, SNDCTL_DSP_SETTRIGGER, &trig)); } } -static void maybe_open (int req_freq, int req_nchannels, +static void maybe_open (AudioState *s, int req_freq, int req_nchannels, audfmt_e req_fmt, int force_open) { int oss_fmt, bits16; @@ -273,7 +657,7 @@ static void maybe_open (int req_freq, int req_nchannels, case AUD_FMT_U8: bits16 = 0; oss_fmt = AFMT_U8; - oss.copy_fn = copy_no_conversion; + s->copy_fn = copy_no_conversion; break; case AUD_FMT_S8: @@ -282,13 +666,13 @@ static void maybe_open (int req_freq, int req_nchannels, case AUD_FMT_S16: bits16 = 1; oss_fmt = AFMT_S16_LE; - oss.copy_fn = copy_no_conversion; + s->copy_fn = copy_no_conversion; break; case AUD_FMT_U16: bits16 = 1; oss_fmt = AFMT_S16_LE; - oss.copy_fn = copy_u16_to_s16; + s->copy_fn = copy_u16_to_s16; break; default: @@ -296,55 +680,58 @@ static void maybe_open (int req_freq, int req_nchannels, } if (force_open - || (-1 == oss.fd) - || (oss_fmt != oss.oss_fmt) - || (req_nchannels != oss.nchannels) - || (req_freq != oss.freq) - || (bits16 != oss.bits16)) { - oss.oss_fmt = oss_fmt; - oss.nchannels = req_nchannels; - oss.freq = req_freq; - oss.bits16 = bits16; - do_open (); + || (-1 == s->fd) + || (oss_fmt != s->oss_fmt) + || (req_nchannels != s->nchannels) + || (req_freq != s->freq) + || (bits16 != s->bits16)) { + s->oss_fmt = oss_fmt; + s->nchannels = req_nchannels; + s->freq = req_freq; + s->bits16 = bits16; + do_open (s); } } void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) { - maybe_open (req_freq, req_nchannels, req_fmt, 0); + AudioState *s = &oss_audio; + maybe_open (s, req_freq, req_nchannels, req_fmt, 0); } void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) { - maybe_open (req_freq, req_nchannels, req_fmt, 1); + AudioState *s = &oss_audio; + maybe_open (s, req_freq, req_nchannels, req_fmt, 1); } int AUD_write (void *in_buf, int size) { + AudioState *s = &oss_audio; int to_copy, temp; uint8_t *in, *out; - to_copy = MIN (oss.bufsize - oss.live, size); + to_copy = MIN (s->bufsize - s->live, size); temp = to_copy; in = in_buf; - out = oss.buf; + out = s->buf; while (temp) { int copy; - copy = MIN (temp, oss.bufsize - oss.wpos); - oss.copy_fn (out + oss.wpos, in, copy); + copy = MIN (temp, s->bufsize - s->wpos); + s->copy_fn (out + s->wpos, in, copy); - oss.wpos += copy; - if (oss.wpos == oss.bufsize) { - oss.wpos = 0; + s->wpos += copy; + if (s->wpos == s->bufsize) { + s->wpos = 0; } temp -= copy; in += copy; - oss.live += copy; + s->live += copy; } return to_copy; @@ -355,15 +742,16 @@ void AUD_run (void) int res; int bytes; struct audio_buf_info abinfo; + AudioState *s = &oss_audio; - if (0 == oss.live) + if (0 == s->live) return; - if (oss.is_mapped) { + if (s->is_mapped) { count_info info; - res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); - if (-1 == res) { + res = ioctl (s->fd, SNDCTL_DSP_GETOPTR, &info); + if (res < 0) { int err; err = errno; @@ -371,29 +759,30 @@ void AUD_run (void) return; } - if (info.ptr > oss.old_optr) { - bytes = info.ptr - oss.old_optr; + if (info.ptr > s->old_optr) { + bytes = info.ptr - s->old_optr; } else { - bytes = oss.bufsize + info.ptr - oss.old_optr; + bytes = s->bufsize + info.ptr - s->old_optr; } - oss.old_optr = info.ptr; - oss.live -= bytes; + s->old_optr = info.ptr; + s->live -= bytes; return; } - res = ioctl (oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo); + res = ioctl (s->fd, SNDCTL_DSP_GETOSPACE, &abinfo); - if (-1 == res) { + if (res < 0) { int err; err = errno; lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err)); + return; } bytes = abinfo.bytes; - bytes = MIN (oss.live, bytes); + bytes = MIN (s->live, bytes); #if 0 bytes = (bytes / fragsize) * fragsize; #endif @@ -401,9 +790,9 @@ void AUD_run (void) while (bytes) { int left, play, written; - left = oss.bufsize - oss.rpos; + left = s->bufsize - s->rpos; play = MIN (left, bytes); - written = write (oss.fd, (uint8_t *)oss.buf + oss.rpos, play); + written = write (s->fd, (uint8_t *)s->buf + s->rpos, play); if (-1 == written) { if (EAGAIN == errno || EINTR == errno) { @@ -415,12 +804,12 @@ void AUD_run (void) } play = written; - oss.live -= play; - oss.rpos += play; + s->live -= play; + s->rpos += play; bytes -= play; - if (oss.rpos == oss.bufsize) { - oss.rpos = 0; + if (s->rpos == s->bufsize) { + s->rpos = 0; } } } @@ -429,8 +818,9 @@ static int get_dsp_bytes (void) { int res; struct count_info info; + AudioState *s = &oss_audio; - res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); + res = ioctl (s->fd, SNDCTL_DSP_GETOPTR, &info); if (-1 == res) { int err; @@ -446,16 +836,18 @@ static int get_dsp_bytes (void) void AUD_adjust_estimate (int leftover) { - oss.leftover = leftover; + AudioState *s = &oss_audio; + s->leftover = leftover; } int AUD_get_free (void) { int free, elapsed; + AudioState *s = &oss_audio; - free = oss.bufsize - oss.live; + free = s->bufsize - s->live; - if (0 == free) + if (free <= 0) return 0; elapsed = free; @@ -485,10 +877,10 @@ int AUD_get_free (void) uint64_t al_elapsed; ticks = qemu_get_clock(rt_clock); - delta = ticks - oss.old_ticks; - oss.old_ticks = ticks; + delta = ticks - s->old_ticks; + s->old_ticks = ticks; - ua_elapsed = (delta * oss.bytes_per_second) / 1000; + ua_elapsed = (delta * s->bytes_per_second) / 1000; al_elapsed = ua_elapsed & ~3ULL; ldebug ("tid elapsed %llu bytes\n", ua_elapsed); @@ -498,7 +890,7 @@ int AUD_get_free (void) else elapsed = al_elapsed; - elapsed += oss.leftover; + elapsed += s->leftover; } } @@ -513,31 +905,20 @@ int AUD_get_free (void) int AUD_get_live (void) { - return oss.live; + AudioState *s = &oss_audio; + return s->live; } int AUD_get_buffer_size (void) { - return oss.bufsize; + AudioState *s = &oss_audio; + return s->bufsize; } #define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" #define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" #define QC_OSS_MMAP "QEMU_OSS_MMAP" -static int get_conf_val (const char *key, int defval) -{ - int val = defval; - char *strval; - - strval = getenv (key); - if (strval) { - val = atoi (strval); - } - - return val; -} - void AUD_init (void) { int fsp; -- cgit v1.2.3 From 8e3a9fd28059821f819295fe9178435990141924 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 17:32:58 +0000 Subject: monitor fixes (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1109 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 5 ++++- exec.c | 8 ++++++++ hw/pci.c | 22 +++++++++++----------- monitor.c | 1 + 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/console.c b/console.c index 171d2a937..b99a3bf18 100644 --- a/console.c +++ b/console.c @@ -570,8 +570,11 @@ void console_select(unsigned int index) active_console = s; if (s->text_console) { if (s->g_width != s->ds->width || - s->g_height != s->ds->height) + 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); } } diff --git a/exec.c b/exec.c index 8732377ab..0dc8d1595 100644 --- a/exec.c +++ b/exec.c @@ -1199,8 +1199,10 @@ CPULogItem cpu_log_items[] = { { CPU_LOG_PCALL, "pcall", "show protected mode far calls/returns/exceptions" }, #endif +#ifdef DEBUG_IOPORT { CPU_LOG_IOPORT, "ioport", "show all i/o ports accesses" }, +#endif { 0, NULL, NULL }, }; @@ -1224,11 +1226,17 @@ int cpu_str_to_log_mask(const char *str) p1 = strchr(p, ','); if (!p1) p1 = p + strlen(p); + if(cmp1(p,p1-p,"all")) { + for(item = cpu_log_items; item->mask != 0; item++) { + mask |= item->mask; + } + } else { for(item = cpu_log_items; item->mask != 0; item++) { if (cmp1(p, p1 - p, item->name)) goto found; } return 0; + } found: mask |= item->mask; if (*p1 != ',') diff --git a/hw/pci.c b/hw/pci.c index f159dc2cb..2fed66f0a 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1241,40 +1241,40 @@ static void pci_info_device(PCIDevice *d) int i, class; PCIIORegion *r; - printf(" Bus %2d, device %3d, function %d:\n", + term_printf(" Bus %2d, device %3d, function %d:\n", d->bus->bus_num, d->devfn >> 3, d->devfn & 7); class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); - printf(" "); + term_printf(" "); switch(class) { case 0x0101: - printf("IDE controller"); + term_printf("IDE controller"); break; case 0x0200: - printf("Ethernet controller"); + term_printf("Ethernet controller"); break; case 0x0300: - printf("VGA controller"); + term_printf("VGA controller"); break; default: - printf("Class %04x", class); + term_printf("Class %04x", class); break; } - printf(": PCI device %04x:%04x\n", + term_printf(": PCI device %04x:%04x\n", le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID)))); if (d->config[PCI_INTERRUPT_PIN] != 0) { - printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); + term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); } for(i = 0;i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; if (r->size != 0) { - printf(" BAR%d: ", i); + term_printf(" BAR%d: ", i); if (r->type & PCI_ADDRESS_SPACE_IO) { - printf("I/O at 0x%04x [0x%04x].\n", + term_printf("I/O at 0x%04x [0x%04x].\n", r->addr, r->addr + r->size - 1); } else { - printf("32 bit memory at 0x%08x [0x%08x].\n", + term_printf("32 bit memory at 0x%08x [0x%08x].\n", r->addr, r->addr + r->size - 1); } } diff --git a/monitor.c b/monitor.c index c39f3b239..27e2619d1 100644 --- a/monitor.c +++ b/monitor.c @@ -223,6 +223,7 @@ static void do_info_history (void) if (!str) break; term_printf("%d: '%s'\n", i, str); + i++; } } -- cgit v1.2.3 From 7fe48483cd90401de2477733ce65037ee0ed0906 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 18:08:01 +0000 Subject: monitor fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1110 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 8 ++++---- cpu-exec.c | 8 ++++---- disas.c | 2 +- exec.c | 4 +++- linux-user/main.c | 6 +++--- monitor.c | 24 ++++++++++++++++++++++-- target-arm/cpu.h | 2 -- target-arm/translate.c | 12 +++++++----- target-i386/cpu.h | 1 - target-i386/helper.c | 6 +++--- target-i386/helper2.c | 24 +++++++++++++----------- target-i386/translate.c | 2 +- target-ppc/cpu.h | 1 - target-ppc/helper.c | 4 ++-- target-ppc/op_helper.c | 4 ++-- target-ppc/translate.c | 37 +++++++++++++++++++------------------ target-sparc/cpu.h | 1 - target-sparc/helper.c | 2 +- target-sparc/translate.c | 36 +++++++++++++++++++----------------- vl.c | 4 ++-- 20 files changed, 106 insertions(+), 82 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 04b5be386..2879c11e6 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -570,7 +570,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_exec cpu_x86_exec #define cpu_gen_code cpu_x86_gen_code #define cpu_signal_handler cpu_x86_signal_handler -#define cpu_dump_state cpu_x86_dump_state #elif defined(TARGET_ARM) @@ -579,7 +578,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_exec cpu_arm_exec #define cpu_gen_code cpu_arm_gen_code #define cpu_signal_handler cpu_arm_signal_handler -#define cpu_dump_state cpu_arm_dump_state #elif defined(TARGET_SPARC) @@ -588,7 +586,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_exec cpu_sparc_exec #define cpu_gen_code cpu_sparc_gen_code #define cpu_signal_handler cpu_sparc_signal_handler -#define cpu_dump_state cpu_sparc_dump_state #elif defined(TARGET_PPC) @@ -597,7 +594,6 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_exec cpu_ppc_exec #define cpu_gen_code cpu_ppc_gen_code #define cpu_signal_handler cpu_ppc_signal_handler -#define cpu_dump_state cpu_ppc_dump_state #else @@ -607,6 +603,10 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #endif /* SINGLE_CPU_DEFINES */ +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags); + void cpu_abort(CPUState *env, const char *fmt, ...); extern CPUState *cpu_single_env; extern int code_copy_enabled; diff --git a/cpu-exec.c b/cpu-exec.c index 930bd7bd8..5229eaa89 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -304,16 +304,16 @@ int cpu_exec(CPUState *env1) env->regs[R_EBP] = EBP; env->regs[R_ESP] = ESP; env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); - cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); + 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) env->cpsr = compute_cpsr(); - cpu_arm_dump_state(env, logfile, 0); + cpu_dump_state(env, logfile, fprintf, 0); env->cpsr &= ~0xf0000000; #elif defined(TARGET_SPARC) - cpu_sparc_dump_state (env, logfile, 0); + cpu_dump_state (env, logfile, fprintf, 0); #elif defined(TARGET_PPC) - cpu_ppc_dump_state(env, logfile, 0); + cpu_dump_state(env, logfile, fprintf, 0); #else #error unsupported target CPU #endif diff --git a/disas.c b/disas.c index ccdcd2450..86f29d245 100644 --- a/disas.c +++ b/disas.c @@ -282,7 +282,7 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) #elif defined(TARGET_PPC) print_insn = print_insn_ppc; #else - fprintf(out, "Asm output not supported on this arch\n"); + term_printf("Asm output not supported on this arch\n"); return; #endif diff --git a/exec.c b/exec.c index 0dc8d1595..95883beca 100644 --- a/exec.c +++ b/exec.c @@ -1255,7 +1255,9 @@ void cpu_abort(CPUState *env, const char *fmt, ...) vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); #ifdef TARGET_I386 - cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP); + cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + cpu_dump_state(env, stderr, fprintf, 0); #endif va_end(ap); abort(); diff --git a/linux-user/main.c b/linux-user/main.c index bd2445252..6ab024e0b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -372,7 +372,7 @@ void cpu_loop(CPUARMState *env) error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); - cpu_arm_dump_state(env, stderr, 0); + cpu_dump_state(env, stderr, fprintf, 0); abort(); } process_pending_signals(env); @@ -499,7 +499,7 @@ void cpu_loop (CPUSPARCState *env) break; default: printf ("Unhandled trap: 0x%x\n", trapnr); - cpu_sparc_dump_state(env, stderr, 0); + cpu_dump_state(env, stderr, fprintf, 0); exit (1); } process_pending_signals (env); @@ -563,7 +563,7 @@ void cpu_loop(CPUPPCState *env) if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && trapnr != EXCP_TRACE) { if (loglevel > 0) { - cpu_ppc_dump_state(env, logfile, 0); + cpu_dump_state(env, logfile, fprintf, 0); } } switch(trapnr) { diff --git a/monitor.c b/monitor.c index 27e2619d1..de47684bc 100644 --- a/monitor.c +++ b/monitor.c @@ -101,6 +101,15 @@ void term_printf(const char *fmt, ...) va_end(ap); } +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; +} + static int compare_cmd(const char *name, const char *list) { const char *p, *pstart; @@ -206,9 +215,11 @@ static void do_info_block(void) static void do_info_registers(void) { #ifdef TARGET_I386 - cpu_dump_state(cpu_single_env, stdout, X86_DUMP_FPU | X86_DUMP_CCOP); + cpu_dump_state(cpu_single_env, stdout, monitor_fprintf, + X86_DUMP_FPU | X86_DUMP_CCOP); #else - cpu_dump_state(cpu_single_env, stdout, 0); + cpu_dump_state(cpu_single_env, stdout, monitor_fprintf, + 0); #endif } @@ -1852,6 +1863,15 @@ void readline_find_completion(const char *cmdline) completion_index = strlen(str); bdrv_iterate(block_completion_it, (void *)str); break; + case 's': + /* XXX: more generic ? */ + if (!strcmp(cmd->name, "info")) { + completion_index = strlen(str); + for(cmd = info_cmds; cmd->name != NULL; cmd++) { + cmd_completion(str, cmd->name); + } + } + break; default: break; } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index df25c5791..7d34766b7 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -64,8 +64,6 @@ struct siginfo; int cpu_arm_signal_handler(int host_signum, struct siginfo *info, void *puc); -void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags); - #define TARGET_PAGE_BITS 12 #include "cpu-all.h" diff --git a/target-arm/translate.c b/target-arm/translate.c index 3185286bb..69bc8e224 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -824,18 +824,20 @@ void cpu_arm_close(CPUARMState *env) free(env); } -void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags) +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) { int i; for(i=0;i<16;i++) { - fprintf(f, "R%02d=%08x", i, env->regs[i]); + cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); if ((i % 4) == 3) - fprintf(f, "\n"); + cpu_fprintf(f, "\n"); else - fprintf(f, " "); + cpu_fprintf(f, " "); } - fprintf(f, "PSR=%08x %c%c%c%c\n", + cpu_fprintf(f, "PSR=%08x %c%c%c%c\n", env->cpsr, env->cpsr & (1 << 31) ? 'N' : '-', env->cpsr & (1 << 30) ? 'Z' : '-', diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 14e7943da..2b189ec8b 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -454,7 +454,6 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); /* used to debug */ #define X86_DUMP_FPU 0x0001 /* dump FPU state too */ #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" diff --git a/target-i386/helper.c b/target-i386/helper.c index 3a6568e05..7035e1cb9 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -872,7 +872,7 @@ void do_interrupt(int intno, int is_int, int error_code, } fprintf(logfile, "\n"); #if 0 - cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); { int i; uint8_t *ptr; @@ -1334,7 +1334,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (loglevel & CPU_LOG_PCALL) { fprintf(logfile, "lcall %04x:%08x s=%d\n", new_cs, new_eip, shift); - cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); } #endif if ((new_cs & 0xfffc) == 0) @@ -1596,7 +1596,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if (loglevel & CPU_LOG_PCALL) { fprintf(logfile, "lret new %04x:%08x s=%d addend=0x%x\n", new_cs, new_eip, shift, addend); - cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); } #endif if ((new_cs & 0xfffc) == 0) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 0d5f439d1..76401d448 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -168,14 +168,16 @@ static const char *cc_op_str[] = { "SARL", }; -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) { int eflags, i; char cc_op_name[32]; static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" }; eflags = env->eflags; - fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], @@ -193,28 +195,28 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) (env->a20_mask >> 20) & 1); for(i = 0; i < 6; i++) { SegmentCache *sc = &env->segs[i]; - fprintf(f, "%s =%04x %08x %08x %08x\n", + cpu_fprintf(f, "%s =%04x %08x %08x %08x\n", seg_name[i], sc->selector, (int)sc->base, sc->limit, sc->flags); } - fprintf(f, "LDT=%04x %08x %08x %08x\n", + cpu_fprintf(f, "LDT=%04x %08x %08x %08x\n", env->ldt.selector, (int)env->ldt.base, env->ldt.limit, env->ldt.flags); - fprintf(f, "TR =%04x %08x %08x %08x\n", + cpu_fprintf(f, "TR =%04x %08x %08x %08x\n", env->tr.selector, (int)env->tr.base, env->tr.limit, env->tr.flags); - fprintf(f, "GDT= %08x %08x\n", + cpu_fprintf(f, "GDT= %08x %08x\n", (int)env->gdt.base, env->gdt.limit); - fprintf(f, "IDT= %08x %08x\n", + cpu_fprintf(f, "IDT= %08x %08x\n", (int)env->idt.base, env->idt.limit); - fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", + cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", env->cr[0], env->cr[2], env->cr[3], env->cr[4]); if (flags & X86_DUMP_CCOP) { @@ -222,16 +224,16 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]); else snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); - fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", + cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", env->cc_src, env->cc_dst, cc_op_name); } if (flags & X86_DUMP_FPU) { - fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", + cpu_fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", (double)env->fpregs[0], (double)env->fpregs[1], (double)env->fpregs[2], (double)env->fpregs[3]); - fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", + cpu_fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", (double)env->fpregs[4], (double)env->fpregs[5], (double)env->fpregs[7], diff --git a/target-i386/translate.c b/target-i386/translate.c index 111b88914..bd2a61b0e 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4641,7 +4641,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { - cpu_dump_state(env, logfile, X86_DUMP_CCOP); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); } if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 951c9715b..3198c9b97 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -189,7 +189,6 @@ int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, void do_interrupt (CPUPPCState *env); void cpu_loop_exit(void); -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); void dump_stack (CPUPPCState *env); uint32_t _load_xer (CPUPPCState *env); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 1ed07e833..de646727a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -521,7 +521,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, do_fault: #if defined (DEBUG_MMU) if (loglevel > 0) - cpu_ppc_dump_state(env, logfile, 0); + cpu_dump_state(env, logfile, fprintf, 0); #endif if (access_type == ACCESS_CODE) { exception = EXCP_ISI; @@ -676,7 +676,7 @@ void do_interrupt (CPUState *env) env->nip, excp << 8, env->error_code); } if (loglevel > 0) - cpu_ppc_dump_state(env, logfile, 0); + cpu_dump_state(env, logfile, fprintf, 0); } #endif if (loglevel & CPU_LOG_INT) { diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 30905d98a..073ca37e1 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -466,14 +466,14 @@ void do_store_dbat (int ul, int nr) /* Special helpers for debug */ void dump_state (void) { - // cpu_ppc_dump_state(env, stdout, 0); + // cpu_dump_state(env, stdout, fprintf, 0); } void dump_rfi (void) { #if 0 printf("Return from interrupt => 0x%08x\n", env->nip); - // cpu_ppc_dump_state(env, stdout, 0); + // cpu_dump_state(env, stdout, fprintf, 0); #endif } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index fd52f73cc..4647c6e06 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2924,24 +2924,26 @@ static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr) /*****************************************************************************/ /* Misc PPC helpers */ -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) { int i; - fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x " + cpu_fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x " "MSR=0x%08x\n", env->nip, env->lr, env->ctr, _load_xer(env), _load_msr(env)); for (i = 0; i < 32; i++) { if ((i & 7) == 0) - fprintf(f, "GPR%02d:", i); - fprintf(f, " %08x", env->gpr[i]); + cpu_fprintf(f, "GPR%02d:", i); + cpu_fprintf(f, " %08x", env->gpr[i]); if ((i & 7) == 7) - fprintf(f, "\n"); + cpu_fprintf(f, "\n"); } - fprintf(f, "CR: 0x"); + cpu_fprintf(f, "CR: 0x"); for (i = 0; i < 8; i++) - fprintf(f, "%01x", env->crf[i]); - fprintf(f, " ["); + cpu_fprintf(f, "%01x", env->crf[i]); + cpu_fprintf(f, " ["); for (i = 0; i < 8; i++) { char a = '-'; if (env->crf[i] & 0x08) @@ -2950,22 +2952,21 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) a = 'G'; else if (env->crf[i] & 0x02) a = 'E'; - fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); + cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } - fprintf(f, " ] "); - fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env), + cpu_fprintf(f, " ] "); + cpu_fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)); for (i = 0; i < 16; i++) { if ((i & 3) == 0) - fprintf(f, "FPR%02d:", i); - fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i])); + cpu_fprintf(f, "FPR%02d:", i); + cpu_fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i])); if ((i & 3) == 3) - fprintf(f, "\n"); + cpu_fprintf(f, "\n"); } - fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n", + cpu_fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n", env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env)); - fprintf(f, "reservation 0x%08x\n", env->reserve); - fflush(f); + cpu_fprintf(f, "reservation 0x%08x\n", env->reserve); } #if !defined(CONFIG_USER_ONLY) && defined (USE_OPENFIRMWARE) @@ -3170,7 +3171,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); - cpu_ppc_dump_state(env, logfile, 0); + cpu_dump_state(env, logfile, fprintf, 0); } if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 03698df21..adf8df2c9 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -147,7 +147,6 @@ int cpu_sparc_close(CPUSPARCState *s); struct siginfo; int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); -void cpu_sparc_dump_state(CPUSPARCState *env, FILE *f, int flags); #define TARGET_PAGE_BITS 12 /* 4k */ #include "cpu-all.h" diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 63d08e77d..93ef930fb 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -290,7 +290,7 @@ void do_interrupt(int intno, int is_int, int error_code, env->pc, env->npc, env->regwptr[6]); #if 0 - cpu_sparc_dump_state(env, logfile, 0); + cpu_dump_state(env, logfile, fprintf, 0); { int i; uint8_t *ptr; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d06886c84..721a91d7f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1391,44 +1391,46 @@ CPUSPARCState *cpu_sparc_init(void) #define GET_FLAG(a,b) ((env->psr & a)?b:'-') -void cpu_sparc_dump_state(CPUSPARCState * env, FILE * f, int flags) +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) { int i, x; - fprintf(f, "pc: 0x%08x npc: 0x%08x\n", (int) env->pc, (int) env->npc); - fprintf(f, "General Registers:\n"); + cpu_fprintf(f, "pc: 0x%08x npc: 0x%08x\n", (int) env->pc, (int) env->npc); + cpu_fprintf(f, "General Registers:\n"); for (i = 0; i < 4; i++) - fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]); - fprintf(f, "\n"); + cpu_fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "\n"); for (; i < 8; i++) - fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]); - fprintf(f, "\nCurrent Register Window:\n"); + cpu_fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "\nCurrent Register Window:\n"); for (x = 0; x < 3; x++) { for (i = 0; i < 4; i++) - fprintf(f, "%%%c%d: 0x%08x\t", + cpu_fprintf(f, "%%%c%d: 0x%08x\t", (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, env->regwptr[i + x * 8]); - fprintf(f, "\n"); + cpu_fprintf(f, "\n"); for (; i < 8; i++) - fprintf(f, "%%%c%d: 0x%08x\t", + cpu_fprintf(f, "%%%c%d: 0x%08x\t", (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, env->regwptr[i + x * 8]); - fprintf(f, "\n"); + cpu_fprintf(f, "\n"); } - fprintf(f, "\nFloating Point Registers:\n"); + cpu_fprintf(f, "\nFloating Point Registers:\n"); for (i = 0; i < 32; i++) { if ((i & 3) == 0) - fprintf(f, "%%f%02d:", i); - fprintf(f, " %016lf", env->fpr[i]); + cpu_fprintf(f, "%%f%02d:", i); + cpu_fprintf(f, " %016lf", env->fpr[i]); if ((i & 3) == 3) - fprintf(f, "\n"); + cpu_fprintf(f, "\n"); } - fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), + cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), env->psrs?'S':'-', env->psrps?'P':'-', env->psret?'E':'-', env->wim); - fprintf(f, "fsr: 0x%08x\n", env->fsr); + cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr); } target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) diff --git a/vl.c b/vl.c index 9fc76c7d8..4569cda20 100644 --- a/vl.c +++ b/vl.c @@ -406,9 +406,9 @@ void hw_error(const char *fmt, ...) vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); #ifdef TARGET_I386 - cpu_x86_dump_state(global_env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP); + cpu_dump_state(global_env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); #else - cpu_dump_state(global_env, stderr, 0); + cpu_dump_state(global_env, stderr, fprintf, 0); #endif va_end(ap); abort(); -- cgit v1.2.3 From a7dfe172fa839a10667264a99f307d143eb2cc92 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 20:27:55 +0000 Subject: IDE standby fix for Linux 2.6 guest - segfault fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1111 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index 63db239c0..a7de3cd6d 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1567,6 +1567,10 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) goto abort_cmd; } break; + case WIN_STANDBYNOW1: + s->status = READY_STAT; + ide_set_irq(s); + break; /* ATAPI commands */ case WIN_PIDENTIFY: if (s->is_cdrom) { @@ -1784,6 +1788,16 @@ static uint32_t ide_data_readl(void *opaque, uint32_t addr) return ret; } +static void ide_dummy_transfer_stop(IDEState *s) +{ + s->data_ptr = s->io_buffer; + s->data_end = s->io_buffer; + s->io_buffer[0] = 0xff; + s->io_buffer[1] = 0xff; + s->io_buffer[2] = 0xff; + s->io_buffer[3] = 0xff; +} + static void ide_reset(IDEState *s) { s->mult_sectors = MAX_MULT_SECTORS; @@ -1791,6 +1805,10 @@ static void ide_reset(IDEState *s) s->select = 0xa0; s->status = READY_STAT; ide_set_signature(s); + /* init the transfer handler so that 0xffff is returned on data + accesses */ + s->end_transfer_func = ide_dummy_transfer_stop; + ide_dummy_transfer_stop(s); } struct partition { -- cgit v1.2.3 From 032a8c9e35e44b6e6d690e48ddc8429d12bc58e7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 22:56:44 +0000 Subject: help fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1112 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index 4569cda20..32474bfc7 100644 --- a/vl.c +++ b/vl.c @@ -2553,9 +2553,9 @@ void help(void) "-loadvm file start right away with a saved state (loadvm in monitor)\n" "\n" "During emulation, the following keys are useful:\n" - "ctrl-shift-f toggle full screen\n" - "ctrl-shift-Fn switch to virtual console 'n'\n" - "ctrl-shift toggle mouse and keyboard grab\n" + "ctrl-alt-f toggle full screen\n" + "ctrl-alt-n switch to virtual console 'n'\n" + "ctrl-alt toggle mouse and keyboard grab\n" "\n" "When using -nographic, press 'ctrl-a h' to get some help.\n" , -- cgit v1.2.3 From 6d46bf8ae368937ef65187623be9831a4ad0b1b4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Oct 2004 22:57:43 +0000 Subject: win32 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1113 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.h | 1 + slirp/tftp.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/slirp/slirp.h b/slirp/slirp.h index 964d5e19b..fb55ad9c3 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -33,6 +33,7 @@ typedef char *caddr_t; #else # define ioctlsocket ioctl # define closesocket(s) close(s) +# define O_BINARY 0 #endif #include diff --git a/slirp/tftp.c b/slirp/tftp.c index 90526625c..c9946d6bf 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -103,7 +103,7 @@ static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, int fd; int bytes_read = 0; - fd = open(spt->filename, O_RDONLY); + fd = open(spt->filename, O_RDONLY | O_BINARY); if (fd < 0) { return -1; -- cgit v1.2.3 From 8926b517e9ebe20a4348f445e9d0c7f11029eb57 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Oct 2004 15:14:20 +0000 Subject: faster Cirrus VGA VRAM access git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1114 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 2 ++ exec.c | 10 +++++++ hw/cirrus_vga.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 2879c11e6..e1bdc9133 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -692,6 +692,8 @@ 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); diff --git a/exec.c b/exec.c index 95883beca..5f2a87c23 100644 --- a/exec.c +++ b/exec.c @@ -1977,6 +1977,16 @@ int cpu_register_io_memory(int io_index, return io_index << IO_MEM_SHIFT; } +CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index) +{ + return io_mem_write[io_index >> IO_MEM_SHIFT]; +} + +CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index) +{ + return io_mem_read[io_index >> IO_MEM_SHIFT]; +} + /* physical memory access (slow version, mainly for debug) */ #if defined(CONFIG_USER_ONLY) void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index bd2355bae..9d8051519 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -259,9 +259,6 @@ typedef struct CirrusVGAState { uint8_t *cirrus_srcptr; uint8_t *cirrus_srcptr_end; uint32_t cirrus_srccounter; - uint8_t *cirrus_dstptr; - uint8_t *cirrus_dstptr_end; - uint32_t cirrus_dstcounter; /* hwcursor display state */ int last_hw_cursor_size; int last_hw_cursor_x; @@ -269,6 +266,7 @@ typedef struct CirrusVGAState { int last_hw_cursor_y_start; int last_hw_cursor_y_end; int real_vram_size; /* XXX: suppress that */ + CPUWriteMemoryFunc **cirrus_linear_write; } CirrusVGAState; typedef struct PCICirrusVGAState { @@ -285,7 +283,8 @@ static uint8_t rop_to_index[256]; ***************************************/ -static void cirrus_bitblt_reset(CirrusVGAState * s); +static void cirrus_bitblt_reset(CirrusVGAState *s); +static void cirrus_update_memory_access(CirrusVGAState *s); /*************************************** * @@ -711,9 +710,7 @@ static void cirrus_bitblt_reset(CirrusVGAState * s) s->cirrus_srcptr = &s->cirrus_bltbuf[0]; s->cirrus_srcptr_end = &s->cirrus_bltbuf[0]; s->cirrus_srccounter = 0; - s->cirrus_dstptr = &s->cirrus_bltbuf[0]; - s->cirrus_dstptr_end = &s->cirrus_bltbuf[0]; - s->cirrus_dstcounter = 0; + cirrus_update_memory_access(s); } static int cirrus_bitblt_cputovideo(CirrusVGAState * s) @@ -746,6 +743,7 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s) } s->cirrus_srcptr = s->cirrus_bltbuf; s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; + cirrus_update_memory_access(s); return 1; } @@ -1199,7 +1197,6 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) case 0x14: // Scratch Register 2 case 0x15: // Scratch Register 3 case 0x16: // Performance Tuning Register - case 0x17: // Configuration Readback and Extended Control case 0x18: // Signature Generator Control case 0x19: // Signature Generator Result case 0x1a: // Signature Generator Result @@ -1214,6 +1211,10 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) reg_index, reg_value); #endif break; + case 0x17: // Configuration Readback and Extended Control + s->sr[reg_index] = reg_value; + cirrus_update_memory_access(s); + break; default: #ifdef DEBUG_CIRRUS printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index, @@ -1348,13 +1349,19 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) return CIRRUS_HOOK_NOT_HANDLED; case 0x05: // Standard VGA, Cirrus extended mode s->gr[reg_index] = reg_value & 0x7f; + cirrus_update_memory_access(s); break; case 0x09: // bank offset #0 case 0x0A: // bank offset #1 + s->gr[reg_index] = reg_value; + cirrus_update_bank_ptr(s, 0); + cirrus_update_bank_ptr(s, 1); + break; case 0x0B: s->gr[reg_index] = reg_value; cirrus_update_bank_ptr(s, 0); cirrus_update_bank_ptr(s, 1); + cirrus_update_memory_access(s); break; case 0x10: // BGCOLOR 0x0000ff00 case 0x11: // FGCOLOR 0x0000ff00 @@ -2304,6 +2311,36 @@ static CPUWriteMemoryFunc *cirrus_linear_write[3] = { cirrus_linear_writel, }; +static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= s->cirrus_addr_mask; + *(s->vram_ptr + addr) = val; + cpu_physical_memory_set_dirty(s->vram_offset + addr); +} + +static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= s->cirrus_addr_mask; + cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val); + cpu_physical_memory_set_dirty(s->vram_offset + addr); +} + +static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + CirrusVGAState *s = (CirrusVGAState *) opaque; + + addr &= s->cirrus_addr_mask; + cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val); + cpu_physical_memory_set_dirty(s->vram_offset + addr); +} + /*************************************** * * system to screen memory access @@ -2405,6 +2442,37 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = { cirrus_linear_bitblt_writel, }; +/* Compute the memory access functions */ +static void cirrus_update_memory_access(CirrusVGAState *s) +{ + unsigned mode; + + if ((s->sr[0x17] & 0x44) == 0x44) { + goto generic_io; + } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { + goto generic_io; + } else { + if ((s->gr[0x0B] & 0x14) == 0x14) { + goto generic_io; + } else if (s->gr[0x0B] & 0x02) { + goto generic_io; + } + + mode = s->gr[0x05] & 0x7; + if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { + s->cirrus_linear_write[0] = cirrus_linear_mem_writeb; + s->cirrus_linear_write[1] = cirrus_linear_mem_writew; + s->cirrus_linear_write[2] = cirrus_linear_mem_writel; + } else { + generic_io: + s->cirrus_linear_write[0] = cirrus_linear_writeb; + s->cirrus_linear_write[1] = cirrus_linear_writew; + s->cirrus_linear_write[2] = cirrus_linear_writel; + } + } +} + + /* I/O ports */ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) @@ -2933,6 +3001,8 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) s->cirrus_linear_io_addr = cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write, s); + s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr); + /* I/O handler for LFB */ s->cirrus_linear_bitblt_io_addr = cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write, -- cgit v1.2.3 From 9bc9d1c75abf23b1a11c8e633fe5eeb3d6d4c8d3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Oct 2004 15:15:51 +0000 Subject: info version command git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1115 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/monitor.c b/monitor.c index de47684bc..ee1912845 100644 --- a/monitor.c +++ b/monitor.c @@ -190,6 +190,11 @@ static void do_info(const char *item) cmd->handler(); } +static void do_info_version(void) +{ + term_printf("%s\n", QEMU_VERSION); +} + static void do_info_network(void) { int i, j; @@ -864,6 +869,8 @@ static term_cmd_t term_cmds[] = { }; static term_cmd_t info_cmds[] = { + { "version", "", do_info_version, + "", "show the version of qemu" }, { "network", "", do_info_network, "", "show the network state" }, { "block", "", do_info_block, -- cgit v1.2.3 From 188d857911636fa43628eb8a7beeab4702636317 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Oct 2004 15:44:19 +0000 Subject: limited 8 bit support - removed unaligned memory accesses in VGA (initial patch by Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1116 c046a42c-6fe2-441c-8c8c-71466251a162 --- bswap.h | 27 +++++++++++++++++++++++++++ hw/vga.c | 3 +-- hw/vga_template.h | 15 +++++++-------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/bswap.h b/bswap.h index 180cc638f..37fb04ed9 100644 --- a/bswap.h +++ b/bswap.h @@ -133,6 +133,9 @@ CPU_CONVERT(le, 64, uint64_t) #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) @@ -165,6 +168,30 @@ static inline uint32_t le32_to_cpupu(const uint32_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 diff --git a/hw/vga.c b/hw/vga.c index 2a0a9c3d0..2660b0469 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -824,8 +824,7 @@ typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) { - /* XXX: TODO */ - return 0; + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); } static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) diff --git a/hw/vga_template.h b/hw/vga_template.h index 51302b349..909571ebb 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -44,7 +44,7 @@ static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, { #if BPP == 1 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; - ((uint32_t *)d)[3] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; + ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; #elif BPP == 2 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol; @@ -106,22 +106,21 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, xorcol = bgcol ^ fgcol; do { font_data = font_ptr[0]; - /* XXX: unaligned accesses are done */ #if BPP == 1 - ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; + cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol); v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; - ((uint32_t *)d)[3] = v; + cpu_to_32wu(((uint32_t *)d)+1, v); if (dup9) ((uint8_t *)d)[8] = v >> (24 * (1 - BIG)); else ((uint8_t *)d)[8] = bgcol; #elif BPP == 2 - ((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; + cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol); + cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol); + cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol); v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; - ((uint32_t *)d)[3] = v; + cpu_to_32wu(((uint32_t *)d)+3, v); if (dup9) ((uint16_t *)d)[8] = v >> (16 * (1 - BIG)); else -- cgit v1.2.3 From a0c4cb4a7026977266d08d3e6af27d4dd04ed1e4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Oct 2004 17:46:24 +0000 Subject: sparc fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1117 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 2 ++ target-sparc/op.c | 18 +++++++++++++++--- target-sparc/op_helper.c | 28 ++++++++++++++++++++-------- target-sparc/translate.c | 5 ++++- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index cea9616b3..941b22a74 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -25,6 +25,8 @@ void helper_st_asi(int asi, int size, int sign); void helper_rett(void); void helper_ldfsr(void); void set_cwp(int new_cwp); +void do_fitos(void); +void do_fitod(void); void do_fabss(void); void do_fsqrts(void); void do_fsqrtd(void); diff --git a/target-sparc/op.c b/target-sparc/op.c index 042fd6199..2cf4ed841 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -932,20 +932,32 @@ void OPPROTO op_fcmpd(void) do_fcmpd(); } +#ifdef USE_INT_TO_FLOAT_HELPERS void OPPROTO op_fitos(void) { - FT0 = (float) *((int32_t *)&FT1); + do_fitos(); } -void OPPROTO op_fdtos(void) +void OPPROTO op_fitod(void) { - FT0 = (float) DT1; + do_fitod(); +} +#else +void OPPROTO op_fitos(void) +{ + FT0 = (float) *((int32_t *)&FT1); } void OPPROTO op_fitod(void) { DT0 = (double) *((int32_t *)&FT1); } +#endif + +void OPPROTO op_fdtos(void) +{ + FT0 = (float) DT1; +} void OPPROTO op_fstod(void) { diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 909639af0..3a6de7cfc 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -2,22 +2,34 @@ #include #include "exec.h" -void OPPROTO do_fabss(void) +#ifdef USE_INT_TO_FLOAT_HELPERS +void do_fitos(void) +{ + FT0 = (float) *((int32_t *)&FT1); +} + +void do_fitod(void) +{ + DT0 = (double) *((int32_t *)&FT1); +} +#endif + +void do_fabss(void) { FT0 = fabsf(FT1); } -void OPPROTO do_fsqrts(void) +void do_fsqrts(void) { FT0 = sqrtf(FT1); } -void OPPROTO do_fsqrtd(void) +void do_fsqrtd(void) { DT0 = sqrt(DT1); } -void OPPROTO do_fcmps (void) +void do_fcmps (void) { if (isnan(FT0) || isnan(FT1)) { T0 = FSR_FCC1 | FSR_FCC0; @@ -31,7 +43,7 @@ void OPPROTO do_fcmps (void) env->fsr = T0; } -void OPPROTO do_fcmpd (void) +void do_fcmpd (void) { if (isnan(DT0) || isnan(DT1)) { T0 = FSR_FCC1 | FSR_FCC0; @@ -45,7 +57,7 @@ void OPPROTO do_fcmpd (void) env->fsr = T0; } -void OPPROTO helper_ld_asi(int asi, int size, int sign) +void helper_ld_asi(int asi, int size, int sign) { switch(asi) { case 3: /* MMU probe */ @@ -76,7 +88,7 @@ void OPPROTO helper_ld_asi(int asi, int size, int sign) } } -void OPPROTO helper_st_asi(int asi, int size, int sign) +void helper_st_asi(int asi, int size, int sign) { switch(asi) { case 3: /* MMU flush */ @@ -125,7 +137,7 @@ void do_ldd_kernel(uint32_t addr) #endif #endif -void OPPROTO helper_rett() +void helper_rett() { int cwp; env->psret = 1; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 721a91d7f..2440c0d22 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -291,7 +291,10 @@ GEN32(gen_op_store_DT2_fpr, gen_op_store_DT2_fpr_fprf); #if defined(CONFIG_USER_ONLY) #define gen_op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) +#define OP_LD_TABLE(width) \ +static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ +{ \ +} #define supervisor(dc) 0 #else #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() -- cgit v1.2.3 From 953569d21bd552408d9714b48fb76c6003de6fe3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Oct 2004 17:51:13 +0000 Subject: fdc fix (Mike Nordell) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1118 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/fdc.c b/hw/fdc.c index 9b4bfe76b..9375b913c 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1265,8 +1265,16 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n", fdctrl->int_status); /* No parameters cmd: returns status if no interrupt */ +#if 0 fdctrl->fifo[0] = fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv; +#else + /* XXX: int_status handling is broken for read/write + commands, so we do this hack. It should be suppressed + ASAP */ + fdctrl->fifo[0] = + 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv; +#endif fdctrl->fifo[1] = cur_drv->track; fdctrl_set_fifo(fdctrl, 2, 0); fdctrl_reset_irq(fdctrl); -- cgit v1.2.3 From f3ff649d3bf7c206460faa130d10406d1284bae0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Oct 2004 18:00:00 +0000 Subject: openpty fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1119 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/misc.c | 8 ++++---- slirp/misc.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/slirp/misc.c b/slirp/misc.c index 26f8eb578..5b809a853 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -227,8 +227,8 @@ fork_exec(so, ex, do_pty) #else int -openpty(amaster, aslave) - int *amaster, *aslave; +slirp_openpty(amaster, aslave) + int *amaster, *aslave; { register int master, slave; @@ -328,7 +328,7 @@ fork_exec(so, ex, do_pty) DEBUG_ARG("do_pty = %lx", (long)do_pty); if (do_pty == 2) { - if (openpty(&master, &s) == -1) { + if (slirp_openpty(&master, &s) == -1) { lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } @@ -881,7 +881,7 @@ rsh_exec(so,ns, user, host, args) return 0; } #else - if (openpty(&fd0[0], &fd0[1]) == -1) { + if (slirp_openpty(&fd0[0], &fd0[1]) == -1) { close(fd[0]); close(fd[1]); lprint("Error: openpty failed: %s\n", strerror(errno)); diff --git a/slirp/misc.h b/slirp/misc.h index 8e2819b99..8e6a606c9 100644 --- a/slirp/misc.h +++ b/slirp/misc.h @@ -73,7 +73,7 @@ void getouraddr _P((void)); inline void slirp_insque _P((void *, void *)); inline void slirp_remque _P((void *)); int add_exec _P((struct ex_list **, int, char *, int, int)); -int openpty _P((int *, int *)); +int slirp_openpty _P((int *, int *)); int fork_exec _P((struct socket *, char *, int)); void snooze_hup _P((int)); void snooze _P((void)); -- cgit v1.2.3 From 40b6ecc6bcfcf38f1d488d58c8407cce0b82b6d1 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 12 Oct 2004 21:50:05 +0000 Subject: no need to use LARGE translation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1120 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 74b3b8d68..cddd13618 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -215,25 +215,25 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table cmos_init_hd(0x1a, 0x24, hd_table[1]); val = 0; - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { if (hd_table[i]) { int cylinders, heads, sectors; uint8_t translation; - + /* NOTE: bdrv_get_geometry_hint() returns the geometry + that the hard disk returns. It is always such that: 1 <= + sects <= 63, 1 <= heads <= 16, 1 <= cylinders <= + 16383. The BIOS geometry can be different. */ bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors); if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { /* No translation. */ translation = 0; - } else if (cylinders * heads > 131072) { + } else { /* LBA translation. */ translation = 1; - } else { - /* LARGE translation. */ - translation = 2; } - val |= translation << (i * 2); } + } rtc_set_memory(s, 0x39, val); /* Disable check of 0x55AA signature on the last two bytes of -- cgit v1.2.3 From b8b5ac63765360aacf356fb2a488c8bbfe59c286 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 12 Oct 2004 21:52:40 +0000 Subject: do not assume signed char git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1121 c046a42c-6fe2-441c-8c8c-71466251a162 --- i386-dis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i386-dis.c b/i386-dis.c index 372f0a441..0496e141d 100644 --- a/i386-dis.c +++ b/i386-dis.c @@ -1832,7 +1832,7 @@ static bfd_vma start_pc; * The function returns the length of this instruction in bytes. */ -static char intel_syntax; +static int8_t intel_syntax; static char open_char; static char close_char; static char separator_char; -- cgit v1.2.3 From 0d1a29f9fcd161b07a02b9256446235208d379ca Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 12 Oct 2004 22:01:28 +0000 Subject: correct handling of saved host registers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1122 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 14 ++++------ dyngen-exec.h | 3 -- target-arm/exec.h | 8 ++++++ target-i386/exec.h | 57 +++++++++++++++++++++++++++++++++++++- target-i386/helper.c | 77 +++++++++++++++++++++++++++++----------------------- target-ppc/exec.h | 8 ++++++ target-sparc/exec.h | 9 ++++++ 7 files changed, 129 insertions(+), 47 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 5229eaa89..b98c22c58 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -123,37 +123,30 @@ int cpu_exec(CPUState *env1) #if defined(TARGET_I386) #ifdef reg_EAX saved_EAX = EAX; - EAX = env->regs[R_EAX]; #endif #ifdef reg_ECX saved_ECX = ECX; - ECX = env->regs[R_ECX]; #endif #ifdef reg_EDX saved_EDX = EDX; - EDX = env->regs[R_EDX]; #endif #ifdef reg_EBX saved_EBX = EBX; - EBX = env->regs[R_EBX]; #endif #ifdef reg_ESP saved_ESP = ESP; - ESP = env->regs[R_ESP]; #endif #ifdef reg_EBP saved_EBP = EBP; - EBP = env->regs[R_EBP]; #endif #ifdef reg_ESI saved_ESI = ESI; - ESI = env->regs[R_ESI]; #endif #ifdef reg_EDI saved_EDI = EDI; - EDI = env->regs[R_EDI]; #endif - + + 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)); @@ -353,6 +346,8 @@ int cpu_exec(CPUState *env1) 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, (unsigned long)pc); @@ -556,6 +551,7 @@ int cpu_exec(CPUState *env1) #endif } } else { + env_to_regs(); } } /* for(;;) */ diff --git a/dyngen-exec.h b/dyngen-exec.h index 86087ca62..1a3bb2a18 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -93,8 +93,6 @@ extern int printf(const char *, ...); #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" @@ -103,7 +101,6 @@ extern int printf(const char *, ...); #define AREG9 "r21" #define AREG10 "r22" #define AREG11 "r23" -#endif #define USE_INT_TO_FLOAT_HELPERS #define BUGGY_GCC_DIV64 #endif diff --git a/target-arm/exec.h b/target-arm/exec.h index 70afdc5d9..14e2072e6 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -38,3 +38,11 @@ static inline int compute_cpsr(void) return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | (env->CF << 29) | ((env->VF & 0x80000000) >> 3); } + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} diff --git a/target-i386/exec.h b/target-i386/exec.h index 680e580b7..61af5468e 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -20,7 +20,7 @@ #include "config.h" #include "dyngen-exec.h" -/* at least 4 register variables are defines */ +/* at least 4 register variables are defined */ register struct CPUX86State *env asm(AREG0); register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); @@ -546,3 +546,58 @@ static inline void load_eflags(int eflags, int update_mask) (eflags & update_mask); } +static inline void env_to_regs(void) +{ +#ifdef reg_EAX + EAX = env->regs[R_EAX]; +#endif +#ifdef reg_ECX + ECX = env->regs[R_ECX]; +#endif +#ifdef reg_EDX + EDX = env->regs[R_EDX]; +#endif +#ifdef reg_EBX + EBX = env->regs[R_EBX]; +#endif +#ifdef reg_ESP + ESP = env->regs[R_ESP]; +#endif +#ifdef reg_EBP + EBP = env->regs[R_EBP]; +#endif +#ifdef reg_ESI + ESI = env->regs[R_ESI]; +#endif +#ifdef reg_EDI + EDI = env->regs[R_EDI]; +#endif +} + +static inline void regs_to_env(void) +{ +#ifdef reg_EAX + env->regs[R_EAX] = EAX; +#endif +#ifdef reg_ECX + env->regs[R_ECX] = ECX; +#endif +#ifdef reg_EDX + env->regs[R_EDX] = EDX; +#endif +#ifdef reg_EBX + env->regs[R_EBX] = EBX; +#endif +#ifdef reg_ESP + env->regs[R_ESP] = ESP; +#endif +#ifdef reg_EBP + env->regs[R_EBP] = EBP; +#endif +#ifdef reg_ESI + env->regs[R_ESI] = ESI; +#endif +#ifdef reg_EDI + env->regs[R_EDI] = EDI; +#endif +} diff --git a/target-i386/helper.c b/target-i386/helper.c index 7035e1cb9..41ebaf221 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -109,30 +109,7 @@ void cpu_loop_exit(void) { /* NOTE: the register at this point must be saved by hand because longjmp restore them */ -#ifdef reg_EAX - env->regs[R_EAX] = EAX; -#endif -#ifdef reg_ECX - env->regs[R_ECX] = ECX; -#endif -#ifdef reg_EDX - env->regs[R_EDX] = EDX; -#endif -#ifdef reg_EBX - env->regs[R_EBX] = EBX; -#endif -#ifdef reg_ESP - env->regs[R_ESP] = ESP; -#endif -#ifdef reg_EBP - env->regs[R_EBP] = EBP; -#endif -#ifdef reg_ESI - env->regs[R_ESI] = ESI; -#endif -#ifdef reg_EDI - env->regs[R_EDI] = EDI; -#endif + regs_to_env(); longjmp(env->jmp_env, 1); } @@ -384,16 +361,28 @@ static void switch_tss(int tss_selector, /* 32 bit */ stl_kernel(env->tr.base + 0x20, next_eip); stl_kernel(env->tr.base + 0x24, old_eflags); - for(i = 0; i < 8; i++) - stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]); + stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX); + stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX); + stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX); + stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX); + stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP); + stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP); + stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI); + stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI); for(i = 0; i < 6; i++) stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); } else { /* 16 bit */ stw_kernel(env->tr.base + 0x0e, next_eip); stw_kernel(env->tr.base + 0x10, old_eflags); - for(i = 0; i < 8; i++) - stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]); + stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX); + stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX); + stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX); + stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX); + stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP); + stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP); + stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI); + stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI); for(i = 0; i < 4; i++) stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); } @@ -437,8 +426,15 @@ static void switch_tss(int tss_selector, if (!(type & 8)) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); - for(i = 0; i < 8; i++) - env->regs[i] = new_regs[i]; + /* XXX: what to do in 16 bit case ? */ + EAX = new_regs[0]; + ECX = new_regs[1]; + EDX = new_regs[2]; + EBX = new_regs[3]; + ESP = new_regs[4]; + EBP = new_regs[5]; + ESI = new_regs[6]; + EDI = new_regs[7]; if (new_eflags & VM_MASK) { for(i = 0; i < 6; i++) load_seg_vm(i, new_segs[i]); @@ -633,13 +629,13 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, mask = 0xffffffff; else mask = 0xffff; - esp = (env->regs[R_ESP] - (2 << shift)) & mask; + esp = (ESP - (2 << shift)) & mask; ssp = env->segs[R_SS].base + esp; if (shift) stl_kernel(ssp, error_code); else stw_kernel(ssp, error_code); - env->regs[R_ESP] = (esp & mask) | (env->regs[R_ESP] & ~mask); + ESP = (esp & mask) | (ESP & ~mask); } return; case 6: /* 286 interrupt gate */ @@ -868,7 +864,7 @@ void do_interrupt(int intno, int is_int, int error_code, if (intno == 0x0e) { fprintf(logfile, " CR2=%08x", env->cr[2]); } else { - fprintf(logfile, " EAX=%08x", env->regs[R_EAX]); + fprintf(logfile, " EAX=%08x", EAX); } fprintf(logfile, "\n"); #if 0 @@ -911,6 +907,16 @@ void raise_interrupt(int intno, int is_int, int error_code, cpu_loop_exit(); } +/* same as raise_exception_err, but do not restore global registers */ +static void raise_exception_err_norestore(int exception_index, int error_code) +{ + env->exception_index = exception_index; + env->error_code = error_code; + env->exception_is_int = 0; + env->exception_next_eip = 0; + longjmp(env->jmp_env, 1); +} + /* shortcuts to generate exceptions */ void (raise_exception_err)(int exception_index, int error_code) @@ -2584,7 +2590,10 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) cpu_restore_state(tb, env, pc, NULL); } } - raise_exception_err(EXCP0E_PAGE, env->error_code); + if (retaddr) + raise_exception_err(EXCP0E_PAGE, env->error_code); + else + raise_exception_err_norestore(EXCP0E_PAGE, env->error_code); } env = saved_env; } diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 637790768..50c51502c 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -165,4 +165,12 @@ void dump_store_dbat (int ul, int nr); void dump_store_tb (int ul); void dump_update_tb(uint32_t param); +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + #endif /* !defined (__PPC_H__) */ diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 941b22a74..1b3d9a080 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -109,4 +109,13 @@ void memcpy32(uint32_t *dst, const uint32_t *src); #define stq(p, v) stq_data(p, v) #endif /* !defined(CONFIG_USER_ONLY) */ + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + #endif -- cgit v1.2.3 From dbb2c92142346306dc132e441ffb7bc14f423cff Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Oct 2004 22:17:47 +0000 Subject: SDL config fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1123 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/configure b/configure index 5d7eed688..28cb708ca 100755 --- a/configure +++ b/configure @@ -510,23 +510,24 @@ fi if test "$target_user_only" = "no"; then if test "$target_softmmu" = "no" -o "$static" = "yes"; then - if test "$sdl_static" = "yes" ; then - echo "#define CONFIG_SDL 1" >> $config_h - echo "CONFIG_SDL=yes" >> $config_mak - echo "SDL_LIBS=$sdl_static_libs" >> $config_mak - fi + sdl1=$sdl_static else - if test "$sdl" = "yes" ; then - echo "#define CONFIG_SDL 1" >> $config_h - echo "CONFIG_SDL=yes" >> $config_mak + sdl1=$sdl + fi + if test "$sdl1" = "yes" ; then + echo "#define CONFIG_SDL 1" >> $config_h + echo "CONFIG_SDL=yes" >> $config_mak + if test "$target_softmmu" = "no" -o "$static" = "yes"; then + echo "SDL_LIBS=$sdl_static_libs" >> $config_mak + else echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak fi + echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak + if [ "${aa}" = "yes" ] ; then + echo -n " `aalib-config --cflags`" >> $config_mak ; + fi + echo "" >> $config_mak fi - echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak - if [ "${aa}" = "yes" ] ; then - echo -n " `aalib-config --cflags`" >> $config_mak ; - fi - echo "" >> $config_mak fi done # for target in $targets -- cgit v1.2.3 From 8f46820d920b9cd149559b5d32e6b306ee2e24ba Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Nov 2004 17:44:42 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1124 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/TODO b/TODO index c3a000043..bde7fcbd3 100644 --- a/TODO +++ b/TODO @@ -1,14 +1,25 @@ short term: ---------- +- debug option in 'configure' script + disable -fomit-frame-pointer +- VGA font change fix +- PIC spurious interrupt patch +- VNC keyboard patch +- merge Solaris patch +- merge ARM patches + self modifying code patch (Paul Brook) +- warning for OS/2: must not use 128 MB memory +- config file (at least for windows/Mac OS X) +- commit message if execution of code in IO memory +- update doc: PCI infos. +- VNC patch + Synaptic patch. +- basic VGA optimizations +- test sysenter/sysexit and fxsr for L4 pistachio 686 - physical memory cache (reduce qemu-fast address space size to about 32 MB) - better code fetch (different exception handling + CS.limit support) - do not resize vga if invalid size. - avoid looping if only exceptions -- handle fast timers + add explicit clocks - cycle counter for all archs - TLB code protection support for PPC -- add sysenter/sysexit and fxsr for L4 pistachio 686 -- basic VGA optimizations +- 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 @@ -22,8 +33,17 @@ short term: - fix arm fpu rounding (at least for float->integer conversions) - SMP support +ppc specific: +------------ +- TLB invalidate not needed if msr_pr changes +- endianness bugs in do_load_fpscr and do_store_fpscr +- SPR_ENCODE() not useful +- enable shift optimizations ? + lower priority: -------------- +- more friendly BIOS (logo) +- int15 ah=86: use better timing - HDD geometry in CMOS (not used except for very old DOS programs) - suppress shift_mem ops - fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) @@ -32,7 +52,7 @@ lower priority: - add IPC syscalls - use -msoft-float on ARM - use kernel traps for unaligned accesses on ARM ? -- handle rare page fault cases (in particular if page fault in heplers or +- handle rare page fault cases (in particular if page fault in helpers or in syscall emulation code). - fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID) - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit -- cgit v1.2.3 From 85571bc7415c3fa9390f5edc3720ec7975219a68 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Nov 2004 18:04:02 +0000 Subject: audio merge (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1125 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 39 +- audio/audio.c | 935 +++++++++++++++++++++++++++++++ audio/audio.h | 188 +++++++ audio/fmodaudio.c | 457 +++++++++++++++ audio/fmodaudio.h | 39 ++ audio/mixeng.c | 255 +++++++++ audio/mixeng.h | 39 ++ audio/mixeng_template.h | 111 ++++ audio/ossaudio.c | 466 ++++++++++++++++ audio/ossaudio.h | 40 ++ audio/sdlaudio.c | 323 +++++++++++ audio/sdlaudio.h | 34 ++ audio/wavaudio.c | 200 +++++++ audio/wavaudio.h | 38 ++ hw/adlib.c | 309 +++++++++++ hw/dma.c | 215 ++++++-- hw/fdc.c | 31 +- hw/fmopl.c | 1390 ++++++++++++++++++++++++++++++++++++++++++++++ hw/fmopl.h | 174 ++++++ hw/pc.c | 3 - hw/sb16.c | 1412 +++++++++++++++++++++++++++-------------------- oss.c | 978 -------------------------------- vl.c | 6 - vl.h | 30 +- 24 files changed, 6038 insertions(+), 1674 deletions(-) create mode 100644 audio/audio.c create mode 100644 audio/audio.h create mode 100644 audio/fmodaudio.c create mode 100644 audio/fmodaudio.h create mode 100644 audio/mixeng.c create mode 100644 audio/mixeng.h create mode 100644 audio/mixeng_template.h create mode 100644 audio/ossaudio.c create mode 100644 audio/ossaudio.h create mode 100644 audio/sdlaudio.c create mode 100644 audio/sdlaudio.h create mode 100644 audio/wavaudio.c create mode 100644 audio/wavaudio.h create mode 100644 hw/adlib.c create mode 100644 hw/fmopl.c create mode 100644 hw/fmopl.h delete mode 100644 oss.c diff --git a/Makefile.target b/Makefile.target index 6ac8d9f1b..280ffa1b3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -1,7 +1,17 @@ include config.mak +#After enabling Adlib and/or FMOD rebuild QEMU from scratch +#Uncomment following for adlib support +#USE_ADLIB=1 + +#Uncomment following and specify proper paths/names for FMOD support +#USE_FMOD=1 +#FMOD_INCLUDE=/net/include/fmod +#FMOD_LIBPATH=/net/lib +#FMOD_VERSION=3.74 + TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) -VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw +VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH) ifdef CONFIG_USER_ONLY VPATH+=:$(SRC_PATH)/linux-user @@ -267,16 +277,31 @@ endif VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o +SOUND_HW = sb16.o +AUDIODRV = audio.o ossaudio.o sdlaudio.o wavaudio.o + +ifeq ($(USE_ADLIB),1) +SOUND_HW += fmopl.o adlib.o +audio.o: DEFINES := -DUSE_ADLIB $(DEFINES) +endif + +ifeq ($(USE_FMOD),1) +AUDIODRV += fmodaudio.o +audio.o fmodaudio.o: DEFINES := -DUSE_FMOD_AUDIO -I$(FMOD_INCLUDE) $(DEFINES) +LDFLAGS += -L$(FMOD_LIBPATH) -Wl,-rpath,$(FMOD_LIBPATH) +LIBS += -lfmod-$(FMOD_VERSION) +endif + ifeq ($(TARGET_ARCH), i386) # Hardware support -VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o -VL_OBJS+= cirrus_vga.o +VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o +VL_OBJS+= cirrus_vga.o mixeng.o endif ifeq ($(TARGET_ARCH), ppc) -VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o +VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o -VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o +VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o endif ifeq ($(TARGET_ARCH), sparc) VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o @@ -360,6 +385,8 @@ op.o: op.c op_template.h op_mem.h op_helper.o: op_helper_mem.h endif +mixeng.o: mixeng.c mixeng.h mixeng_template.h + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< diff --git a/audio/audio.c b/audio/audio.c new file mode 100644 index 000000000..f55e1a28c --- /dev/null +++ b/audio/audio.c @@ -0,0 +1,935 @@ +/* + * QEMU Audio subsystem + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include "vl.h" + +#define AUDIO_CAP "audio" +#include "audio/audio.h" + +#define USE_SDL_AUDIO +#define USE_WAV_AUDIO + +#if defined __linux__ || (defined _BSD && !defined __APPLE__) +#define USE_OSS_AUDIO +#endif + +#ifdef USE_OSS_AUDIO +#include "audio/ossaudio.h" +#endif + +#ifdef USE_SDL_AUDIO +#include "audio/sdlaudio.h" +#endif + +#ifdef USE_WAV_AUDIO +#include "audio/wavaudio.h" +#endif + +#ifdef USE_FMOD_AUDIO +#include "audio/fmodaudio.h" +#endif + +#define QC_AUDIO_DRV "QEMU_AUDIO_DRV" +#define QC_VOICES "QEMU_VOICES" +#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT" +#define QC_FIXED_FREQ "QEMU_FIXED_FREQ" + +extern void SB16_init (void); + +#ifdef USE_ADLIB +extern void Adlib_init (void); +#endif + +#ifdef USE_GUS +extern void GUS_init (void); +#endif + +static void (*hw_ctors[]) (void) = { + SB16_init, +#ifdef USE_ADLIB + Adlib_init, +#endif +#ifdef USE_GUS + GUS_init, +#endif + NULL +}; + +static HWVoice *hw_voice; + +AudioState audio_state = { + 1, /* use fixed settings */ + 44100, /* fixed frequency */ + 2, /* fixed channels */ + AUD_FMT_S16, /* fixed format */ + 1, /* number of hw voices */ + -1 /* voice size */ +}; + +/* http://www.df.lth.se/~john_e/gems/gem002d.html */ +/* http://www.multi-platforms.com/Tips/PopCount.htm */ +uint32_t popcount (uint32_t u) +{ + u = ((u&0x55555555) + ((u>>1)&0x55555555)); + u = ((u&0x33333333) + ((u>>2)&0x33333333)); + u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); + u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); + u = ( u&0x0000ffff) + (u>>16); + return u; +} + +inline uint32_t lsbindex (uint32_t u) +{ + return popcount ((u&-u)-1); +} + +int audio_get_conf_int (const char *key, int defval) +{ + int val = defval; + char *strval; + + strval = getenv (key); + if (strval) { + val = atoi (strval); + } + + return val; +} + +const char *audio_get_conf_str (const char *key, const char *defval) +{ + const char *val = getenv (key); + if (!val) + return defval; + else + return val; +} + +void audio_log (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); +} + +/* + * Soft Voice + */ +void pcm_sw_free_resources (SWVoice *sw) +{ + if (sw->buf) qemu_free (sw->buf); + if (sw->rate) st_rate_stop (sw->rate); + sw->buf = NULL; + sw->rate = NULL; +} + +int pcm_sw_alloc_resources (SWVoice *sw) +{ + sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t)); + if (!sw->buf) + return -1; + + sw->rate = st_rate_start (sw->freq, sw->hw->freq); + if (!sw->rate) { + qemu_free (sw->buf); + sw->buf = NULL; + return -1; + } + return 0; +} + +void pcm_sw_fini (SWVoice *sw) +{ + pcm_sw_free_resources (sw); +} + +int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, + int nchannels, audfmt_e fmt) +{ + int bits = 8, sign = 0; + + switch (fmt) { + case AUD_FMT_S8: + sign = 1; + case AUD_FMT_U8: + break; + + case AUD_FMT_S16: + sign = 1; + case AUD_FMT_U16: + bits = 16; + break; + } + + sw->hw = hw; + sw->freq = freq; + sw->fmt = fmt; + sw->nchannels = nchannels; + sw->shift = (nchannels == 2) + (bits == 16); + sw->align = (1 << sw->shift) - 1; + sw->left = 0; + sw->pos = 0; + sw->wpos = 0; + sw->live = 0; + sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq; + sw->bytes_per_second = sw->freq << sw->shift; + sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16]; + + pcm_sw_free_resources (sw); + return pcm_sw_alloc_resources (sw); +} + +/* Hard voice */ +void pcm_hw_free_resources (HWVoice *hw) +{ + if (hw->mix_buf) + qemu_free (hw->mix_buf); + hw->mix_buf = NULL; +} + +int pcm_hw_alloc_resources (HWVoice *hw) +{ + hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); + if (!hw->mix_buf) + return -1; + return 0; +} + + +void pcm_hw_fini (HWVoice *hw) +{ + if (hw->active) { + ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt); + pcm_hw_free_resources (hw); + hw->pcm_ops->fini (hw); + memset (hw, 0, audio_state.drv->voice_size); + } +} + +void pcm_hw_gc (HWVoice *hw) +{ + if (hw->nb_voices) + return; + + pcm_hw_fini (hw); +} + +int pcm_hw_get_live (HWVoice *hw) +{ + int i, alive = 0, live = hw->samples; + + for (i = 0; i < hw->nb_voices; i++) { + if (hw->pvoice[i]->live) { + live = audio_MIN (hw->pvoice[i]->live, live); + alive += 1; + } + } + + if (alive) + return live; + else + return -1; +} + +int pcm_hw_get_live2 (HWVoice *hw, int *nb_active) +{ + int i, alive = 0, live = hw->samples; + + *nb_active = 0; + for (i = 0; i < hw->nb_voices; i++) { + if (hw->pvoice[i]->live) { + if (hw->pvoice[i]->live < live) { + *nb_active = hw->pvoice[i]->active != 0; + live = hw->pvoice[i]->live; + } + alive += 1; + } + } + + if (alive) + return live; + else + return -1; +} + +void pcm_hw_dec_live (HWVoice *hw, int decr) +{ + int i; + + for (i = 0; i < hw->nb_voices; i++) { + if (hw->pvoice[i]->live) { + hw->pvoice[i]->live -= decr; + } + } +} + +void pcm_hw_clear (HWVoice *hw, void *buf, int len) +{ + if (!len) + return; + + switch (hw->fmt) { + case AUD_FMT_S16: + case AUD_FMT_S8: + memset (buf, len << hw->shift, 0x00); + break; + + case AUD_FMT_U8: + memset (buf, len << hw->shift, 0x80); + break; + + case AUD_FMT_U16: + { + unsigned int i; + uint16_t *p = buf; + int shift = hw->nchannels - 1; + + for (i = 0; i < len << shift; i++) { + p[i] = INT16_MAX; + } + } + break; + } +} + +int pcm_hw_write (SWVoice *sw, void *buf, int size) +{ + int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck; + int ret = 0, pos = 0; + if (!sw) + return size; + + hwsamples = sw->hw->samples; + samples = size >> sw->shift; + + if (!sw->live) { + sw->wpos = sw->hw->rpos; + } + wpos = sw->wpos; + live = sw->live; + dead = hwsamples - live; + swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio; + swlim = audio_MIN (swlim, samples); + + ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n", + size, live, dead, swlim, wpos); + if (swlim) + sw->conv (sw->buf, buf, swlim); + + while (swlim) { + dead = hwsamples - live; + left = hwsamples - wpos; + blck = audio_MIN (dead, left); + if (!blck) { + /* dolog ("swlim=%d\n", swlim); */ + break; + } + isamp = swlim; + osamp = blck; + st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp); + ret += isamp; + swlim -= isamp; + pos += isamp; + live += osamp; + wpos = (wpos + osamp) % hwsamples; + } + + sw->wpos = wpos; + sw->live = live; + return ret << sw->shift; +} + +int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + int sign = 0, bits = 8; + + pcm_hw_fini (hw); + ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt); + if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) { + memset (hw, 0, audio_state.drv->voice_size); + return -1; + } + + switch (hw->fmt) { + case AUD_FMT_S8: + sign = 1; + case AUD_FMT_U8: + break; + + case AUD_FMT_S16: + sign = 1; + case AUD_FMT_U16: + bits = 16; + break; + } + + hw->nb_voices = 0; + hw->active = 1; + hw->shift = (hw->nchannels == 2) + (bits == 16); + hw->bytes_per_second = hw->freq << hw->shift; + hw->align = (1 << hw->shift) - 1; + hw->samples = hw->bufsize >> hw->shift; + hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16]; + if (pcm_hw_alloc_resources (hw)) { + pcm_hw_fini (hw); + return -1; + } + return 0; +} + +static int dist (void *hw) +{ + if (hw) { + return (((uint8_t *) hw - (uint8_t *) hw_voice) + / audio_state.voice_size) + 1; + } + else { + return 0; + } +} + +#define ADVANCE(hw) hw ? advance (hw, audio_state.voice_size) : hw_voice + +HWVoice *pcm_hw_find_any (HWVoice *hw) +{ + int i = dist (hw); + for (; i < audio_state.nb_hw_voices; i++) { + hw = ADVANCE (hw); + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_find_any_active (HWVoice *hw) +{ + int i = dist (hw); + for (; i < audio_state.nb_hw_voices; i++) { + hw = ADVANCE (hw); + if (hw->active) + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw) +{ + int i = dist (hw); + for (; i < audio_state.nb_hw_voices; i++) { + hw = ADVANCE (hw); + if (hw->active && hw->enabled) + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_find_any_passive (HWVoice *hw) +{ + int i = dist (hw); + for (; i < audio_state.nb_hw_voices; i++) { + hw = ADVANCE (hw); + if (!hw->active) + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq, + int nchannels, audfmt_e fmt) +{ + while ((hw = pcm_hw_find_any_active (hw))) { + if (hw->freq == freq && + hw->nchannels == nchannels && + hw->fmt == fmt) + return hw; + } + return NULL; +} + +HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt) +{ + HWVoice *hw; + + if (audio_state.fixed_format) { + freq = audio_state.fixed_freq; + nchannels = audio_state.fixed_channels; + fmt = audio_state.fixed_fmt; + } + + hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt); + + if (hw) + return hw; + + hw = pcm_hw_find_any_passive (NULL); + if (hw) { + hw->pcm_ops = audio_state.drv->pcm_ops; + if (!hw->pcm_ops) + return NULL; + + if (pcm_hw_init (hw, freq, nchannels, fmt)) { + pcm_hw_gc (hw); + return NULL; + } + else + return hw; + } + + return pcm_hw_find_any (NULL); +} + +int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw) +{ + SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw)); + if (!pvoice) + return -1; + + memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw)); + qemu_free (hw->pvoice); + hw->pvoice = pvoice; + hw->pvoice[hw->nb_voices++] = sw; + return 0; +} + +int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw) +{ + int i, j; + if (hw->nb_voices > 1) { + SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw)); + + if (!pvoice) { + dolog ("Can not maintain consistent state (not enough memory)\n"); + return -1; + } + + for (i = 0, j = 0; i < hw->nb_voices; i++) { + if (j >= hw->nb_voices - 1) { + dolog ("Can not maintain consistent state " + "(invariant violated)\n"); + return -1; + } + if (hw->pvoice[i] != sw) + pvoice[j++] = hw->pvoice[i]; + } + qemu_free (hw->pvoice); + hw->pvoice = pvoice; + hw->nb_voices -= 1; + } + else { + qemu_free (hw->pvoice); + hw->pvoice = NULL; + hw->nb_voices = 0; + } + return 0; +} + +SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt) +{ + SWVoice *sw; + HWVoice *hw; + + sw = qemu_mallocz (sizeof (*sw)); + if (!sw) + goto err1; + + hw = pcm_hw_add (freq, nchannels, fmt); + if (!hw) + goto err2; + + if (pcm_hw_add_sw (hw, sw)) + goto err3; + + if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) + goto err4; + + return sw; + +err4: + pcm_hw_del_sw (hw, sw); +err3: + pcm_hw_gc (hw); +err2: + qemu_free (sw); +err1: + return NULL; +} + +SWVoice *AUD_open (SWVoice *sw, const char *name, + int freq, int nchannels, audfmt_e fmt) +{ + if (!audio_state.drv) { + return NULL; + } + + if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) { + return sw; + } + + if (sw) { + ldebug ("Different format %s %d %d %d\n", + name, + sw->freq == freq, + sw->nchannels == nchannels, + sw->fmt == fmt); + } + + if (nchannels != 1 && nchannels != 2) { + dolog ("Bogus channel count %d for voice %s\n", nchannels, name); + return NULL; + } + + if (!audio_state.fixed_format && sw) { + pcm_sw_fini (sw); + pcm_hw_del_sw (sw->hw, sw); + pcm_hw_gc (sw->hw); + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } + qemu_free (sw); + sw = NULL; + } + + if (sw) { + HWVoice *hw = sw->hw; + if (!hw) { + dolog ("Internal logic error voice %s has no hardware store\n", + name); + return sw; + } + + if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) { + pcm_sw_fini (sw); + pcm_hw_del_sw (hw, sw); + pcm_hw_gc (hw); + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } + qemu_free (sw); + return NULL; + } + } + else { + sw = pcm_create_voice_pair (freq, nchannels, fmt); + if (!sw) { + dolog ("Failed to create voice %s\n", name); + return NULL; + } + } + + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } + sw->name = qemu_strdup (name); + return sw; +} + +int AUD_write (SWVoice *sw, void *buf, int size) +{ + int bytes; + + if (!sw->hw->enabled) + dolog ("Writing to disabled voice %s\n", sw->name); + bytes = sw->hw->pcm_ops->write (sw, buf, size); + return bytes; +} + +void AUD_run (void) +{ + HWVoice *hw = NULL; + + while ((hw = pcm_hw_find_any_active_enabled (hw))) { + int i; + if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) { + hw->enabled = 0; + hw->pcm_ops->ctl (hw, VOICE_DISABLE); + for (i = 0; i < hw->nb_voices; i++) { + hw->pvoice[i]->live = 0; + /* hw->pvoice[i]->old_ticks = 0; */ + } + continue; + } + + hw->pcm_ops->run (hw); + assert (hw->rpos < hw->samples); + for (i = 0; i < hw->nb_voices; i++) { + SWVoice *sw = hw->pvoice[i]; + if (!sw->active && !sw->live && sw->old_ticks) { + int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks; + if (delta > audio_state.ticks_threshold) { + ldebug ("resetting old_ticks for %s\n", sw->name); + sw->old_ticks = 0; + } + } + } + } +} + +int AUD_get_free (SWVoice *sw) +{ + int free; + + if (!sw) + return 4096; + + free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio + / INT_MAX; + + free &= ~sw->hw->align; + if (!free) return 0; + + return free; +} + +int AUD_get_buffer_size (SWVoice *sw) +{ + return sw->hw->bufsize; +} + +void AUD_adjust (SWVoice *sw, int bytes) +{ + if (!sw) + return; + sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second; +} + +void AUD_reset (SWVoice *sw) +{ + sw->active = 0; + sw->old_ticks = 0; +} + +int AUD_calc_elapsed (SWVoice *sw) +{ + int64_t now, delta, bytes; + int dead, swlim; + + if (!sw) + return 0; + + now = qemu_get_clock (vm_clock); + delta = now - sw->old_ticks; + bytes = (delta * sw->bytes_per_second) / ticks_per_sec; + if (delta < 0) { + dolog ("whoops delta(<0)=%lld\n", delta); + return 0; + } + + dead = sw->hw->samples - sw->live; + swlim = ((dead * (int64_t) INT_MAX) / sw->ratio); + + if (bytes > swlim) { + return swlim; + } + else { + return bytes; + } +} + +void AUD_enable (SWVoice *sw, int on) +{ + int i; + HWVoice *hw; + + if (!sw) + return; + + hw = sw->hw; + if (on) { + if (!sw->live) + sw->wpos = sw->hw->rpos; + if (!sw->old_ticks) { + sw->old_ticks = qemu_get_clock (vm_clock); + } + } + + if (sw->active != on) { + if (on) { + hw->pending_disable = 0; + if (!hw->enabled) { + hw->enabled = 1; + for (i = 0; i < hw->nb_voices; i++) { + ldebug ("resetting voice\n"); + sw = hw->pvoice[i]; + sw->old_ticks = qemu_get_clock (vm_clock); + } + hw->pcm_ops->ctl (hw, VOICE_ENABLE); + } + } + else { + if (hw->enabled && !hw->pending_disable) { + int nb_active = 0; + for (i = 0; i < hw->nb_voices; i++) { + nb_active += hw->pvoice[i]->active != 0; + } + + if (nb_active == 1) { + hw->pending_disable = 1; + } + } + } + sw->active = on; + } +} + +static struct audio_output_driver *drvtab[] = { +#ifdef USE_OSS_AUDIO + &oss_output_driver, +#endif +#ifdef USE_FMOD_AUDIO + &fmod_output_driver, +#endif +#ifdef USE_SDL_AUDIO + &sdl_output_driver, +#endif +#ifdef USE_WAV_AUDIO + &wav_output_driver, +#endif +}; + +static int voice_init (struct audio_output_driver *drv) +{ + audio_state.opaque = drv->init (); + if (audio_state.opaque) { + if (audio_state.nb_hw_voices > drv->max_voices) { + dolog ("`%s' does not support %d multiple hardware channels\n" + "Resetting to %d\n", + drv->name, audio_state.nb_hw_voices, drv->max_voices); + audio_state.nb_hw_voices = drv->max_voices; + } + hw_voice = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size); + if (hw_voice) { + audio_state.drv = drv; + return 1; + } + else { + dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n", + audio_state.nb_hw_voices, drv->name, drv->voice_size); + drv->fini (audio_state.opaque); + return 0; + } + } + else { + dolog ("Could not init `%s' audio\n", drv->name); + return 0; + } +} + +static void audio_vm_stop_handler (void *opaque, int reason) +{ + HWVoice *hw = NULL; + + while ((hw = pcm_hw_find_any (hw))) { + if (!hw->pcm_ops) + continue; + + hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE); + } +} + +static void audio_atexit (void) +{ + HWVoice *hw = NULL; + + while ((hw = pcm_hw_find_any (hw))) { + if (!hw->pcm_ops) + continue; + + hw->pcm_ops->ctl (hw, VOICE_DISABLE); + hw->pcm_ops->fini (hw); + } + audio_state.drv->fini (audio_state.opaque); +} + +static void audio_save (QEMUFile *f, void *opaque) +{ +} + +static int audio_load (QEMUFile *f, void *opaque, int version_id) +{ + if (version_id != 1) + return -EINVAL; + + return 0; +} + +void AUD_init (void) +{ + int i; + int done = 0; + const char *drvname; + + audio_state.fixed_format = + !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format); + audio_state.fixed_freq = + audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq); + audio_state.nb_hw_voices = + audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices); + + if (audio_state.nb_hw_voices <= 0) { + dolog ("Bogus number of voices %d, resetting to 1\n", + audio_state.nb_hw_voices); + } + + drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL); + if (drvname) { + int found = 0; + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { + if (!strcmp (drvname, drvtab[i]->name)) { + done = voice_init (drvtab[i]); + found = 1; + break; + } + } + if (!found) { + dolog ("Unknown audio driver `%s'\n", drvname); + } + } + + qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); + atexit (audio_atexit); + + if (!done) { + for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { + if (drvtab[i]->can_be_default) + done = voice_init (drvtab[i]); + } + } + + audio_state.ticks_threshold = ticks_per_sec / 50; + audio_state.freq_threshold = 100; + + register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); + if (!done) { + dolog ("Can not initialize audio subsystem\n"); + return; + } + + for (i = 0; hw_ctors[i]; i++) { + hw_ctors[i] (); + } +} diff --git a/audio/audio.h b/audio/audio.h new file mode 100644 index 000000000..926a1bac9 --- /dev/null +++ b/audio/audio.h @@ -0,0 +1,188 @@ +/* + * QEMU Audio subsystem header + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_AUDIO_H +#define QEMU_AUDIO_H + +#include "mixeng.h" + +#define dolog(...) fprintf (stderr, AUDIO_CAP ": " __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +typedef enum { + AUD_FMT_U8, + AUD_FMT_S8, + AUD_FMT_U16, + AUD_FMT_S16 +} audfmt_e; + +typedef struct HWVoice HWVoice; +struct audio_output_driver; + +typedef struct AudioState { + int fixed_format; + int fixed_freq; + int fixed_channels; + int fixed_fmt; + int nb_hw_voices; + int voice_size; + int64_t ticks_threshold; + int freq_threshold; + void *opaque; + struct audio_output_driver *drv; +} AudioState; + +extern AudioState audio_state; + +typedef struct SWVoice { + int freq; + audfmt_e fmt; + int nchannels; + + int shift; + int align; + + t_sample *conv; + + int left; + int pos; + int bytes_per_second; + int64_t ratio; + st_sample_t *buf; + void *rate; + + int wpos; + int live; + int active; + int64_t old_ticks; + HWVoice *hw; + char *name; +} SWVoice; + +#define VOICE_ENABLE 1 +#define VOICE_DISABLE 2 + +struct pcm_ops { + int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt); + void (*fini) (HWVoice *hw); + void (*run) (HWVoice *hw); + int (*write) (SWVoice *sw, void *buf, int size); + int (*ctl) (HWVoice *hw, int cmd, ...); +}; + +struct audio_output_driver { + const char *name; + void *(*init) (void); + void (*fini) (void *); + struct pcm_ops *pcm_ops; + int can_be_default; + int max_voices; + int voice_size; +}; + +struct HWVoice { + int active; + int enabled; + int pending_disable; + int valid; + int freq; + + f_sample *clip; + audfmt_e fmt; + int nchannels; + + int align; + int shift; + + int rpos; + int bufsize; + + int bytes_per_second; + st_sample_t *mix_buf; + + int samples; + int64_t old_ticks; + int nb_voices; + struct SWVoice **pvoice; + struct pcm_ops *pcm_ops; +}; + +void audio_log (const char *fmt, ...); +void pcm_sw_free_resources (SWVoice *sw); +int pcm_sw_alloc_resources (SWVoice *sw); +void pcm_sw_fini (SWVoice *sw); +int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, + int nchannels, audfmt_e fmt); + +void pcm_hw_clear (HWVoice *hw, void *buf, int len); +HWVoice * pcm_hw_find_any (HWVoice *hw); +HWVoice * pcm_hw_find_any_active (HWVoice *hw); +HWVoice * pcm_hw_find_any_passive (HWVoice *hw); +HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq, + int nchannels, audfmt_e fmt); +HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt); +int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw); +int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw); +SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt); + +void pcm_hw_free_resources (HWVoice *hw); +int pcm_hw_alloc_resources (HWVoice *hw); +void pcm_hw_fini (HWVoice *hw); +void pcm_hw_gc (HWVoice *hw); +int pcm_hw_get_live (HWVoice *hw); +int pcm_hw_get_live2 (HWVoice *hw, int *nb_active); +void pcm_hw_dec_live (HWVoice *hw, int decr); +int pcm_hw_write (SWVoice *sw, void *buf, int len); + +int audio_get_conf_int (const char *key, int defval); +const char *audio_get_conf_str (const char *key, const char *defval); + +/* Public API */ +SWVoice * AUD_open (SWVoice *sw, const char *name, int freq, + int nchannels, audfmt_e fmt); +int AUD_write (SWVoice *sw, void *pcm_buf, int size); +void AUD_adjust (SWVoice *sw, int leftover); +void AUD_reset (SWVoice *sw); +int AUD_get_free (SWVoice *sw); +int AUD_get_buffer_size (SWVoice *sw); +void AUD_run (void); +void AUD_enable (SWVoice *sw, int on); +int AUD_calc_elapsed (SWVoice *sw); + +static inline void *advance (void *p, int incr) +{ + uint8_t *d = p; + return (d + incr); +} + +uint32_t popcount (uint32_t u); +inline uint32_t lsbindex (uint32_t u); + +#define audio_MIN(a, b) ((a)>(b)?(b):(a)) +#define audio_MAX(a, b) ((a)<(b)?(b):(a)) + +#endif /* audio.h */ diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c new file mode 100644 index 000000000..7457033f9 --- /dev/null +++ b/audio/fmodaudio.c @@ -0,0 +1,457 @@ +/* + * QEMU FMOD audio output driver + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include "vl.h" + +#define AUDIO_CAP "fmod" +#include "audio/audio.h" +#include "audio/fmodaudio.h" + +#define QC_FMOD_DRV "QEMU_FMOD_DRV" +#define QC_FMOD_FREQ "QEMU_FMOD_FREQ" +#define QC_FMOD_SAMPLES "QEMU_FMOD_SAMPLES" +#define QC_FMOD_CHANNELS "QEMU_FMOD_CHANNELS" +#define QC_FMOD_BUFSIZE "QEMU_FMOD_BUFSIZE" +#define QC_FMOD_THRESHOLD "QEMU_FMOD_THRESHOLD" + +static struct { + int nb_samples; + int freq; + int nb_channels; + int bufsize; + int threshold; +} conf = { + 2048, + 44100, + 1, + 0, + 128 +}; + +#define errstr() FMOD_ErrorString (FSOUND_GetError ()) + +static int fmod_hw_write (SWVoice *sw, void *buf, int len) +{ + return pcm_hw_write (sw, buf, len); +} + +static void fmod_clear_sample (FMODVoice *fmd) +{ + HWVoice *hw = &fmd->hw; + int status; + void *p1 = 0, *p2 = 0; + unsigned int len1 = 0, len2 = 0; + + status = FSOUND_Sample_Lock ( + fmd->fmod_sample, + 0, + hw->samples << hw->shift, + &p1, + &p2, + &len1, + &len2 + ); + + if (!status) { + dolog ("Failed to lock sample\nReason: %s\n", errstr ()); + return; + } + + if ((len1 & hw->align) || (len2 & hw->align)) { + dolog ("Locking sample returned unaligned length %d, %d\n", + len1, len2); + goto fail; + } + + if (len1 + len2 != hw->samples << hw->shift) { + dolog ("Locking sample returned incomplete length %d, %d\n", + len1 + len2, hw->samples << hw->shift); + goto fail; + } + pcm_hw_clear (hw, p1, hw->samples); + + fail: + status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2); + if (!status) { + dolog ("Failed to unlock sample\nReason: %s\n", errstr ()); + } +} + +static int fmod_write_sample (HWVoice *hw, uint8_t *dst, st_sample_t *src, + int src_size, int src_pos, int dst_len) +{ + int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len; + st_sample_t *src1 = src + src_pos, *src2 = 0; + + if (src_pos + dst_len > src_size) { + src_len1 = src_size - src_pos; + src2 = src; + src_len2 = dst_len - src_len1; + pos = src_len2; + } + + if (src_len1) { + hw->clip (dst, src1, src_len1); + memset (src1, 0, src_len1 * sizeof (st_sample_t)); + advance (dst, src_len1); + } + + if (src_len2) { + hw->clip (dst, src2, src_len2); + memset (src2, 0, src_len2 * sizeof (st_sample_t)); + } + return pos; +} + +static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2, + unsigned int blen1, unsigned int blen2) +{ + int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2); + if (!status) { + dolog ("Failed to unlock sample\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int fmod_lock_sample (FMODVoice *fmd, int pos, int len, + void **p1, void **p2, + unsigned int *blen1, unsigned int *blen2) +{ + HWVoice *hw = &fmd->hw; + int status; + + status = FSOUND_Sample_Lock ( + fmd->fmod_sample, + pos << hw->shift, + len << hw->shift, + p1, + p2, + blen1, + blen2 + ); + + if (!status) { + dolog ("Failed to lock sample\nReason: %s\n", errstr ()); + return -1; + } + + if ((*blen1 & hw->align) || (*blen2 & hw->align)) { + dolog ("Locking sample returned unaligned length %d, %d\n", + *blen1, *blen2); + fmod_unlock_sample (fmd, *p1, *p2, *blen1, *blen2); + return -1; + } + return 0; +} + +static void fmod_hw_run (HWVoice *hw) +{ + FMODVoice *fmd = (FMODVoice *) hw; + int rpos, live, decr; + void *p1 = 0, *p2 = 0; + unsigned int blen1 = 0, blen2 = 0; + unsigned int len1 = 0, len2 = 0; + int nb_active; + + live = pcm_hw_get_live2 (hw, &nb_active); + if (live <= 0) { + return; + } + + if (!hw->pending_disable + && nb_active + && conf.threshold + && live <= conf.threshold) { + ldebug ("live=%d nb_active=%d\n", live, nb_active); + return; + } + + decr = live; + +#if 1 + if (fmd->channel >= 0) { + int pos2 = (fmd->old_pos + decr) % hw->samples; + int pos = FSOUND_GetCurrentPosition (fmd->channel); + + if (fmd->old_pos < pos && pos2 >= pos) { + decr = pos - fmd->old_pos - (pos2 == pos) - 1; + } + else if (fmd->old_pos > pos && pos2 >= pos && pos2 < fmd->old_pos) { + decr = (hw->samples - fmd->old_pos) + pos - (pos2 == pos) - 1; + } +/* ldebug ("pos=%d pos2=%d old=%d live=%d decr=%d\n", */ +/* pos, pos2, fmd->old_pos, live, decr); */ + } +#endif + + if (decr <= 0) { + return; + } + + if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) { + return; + } + + len1 = blen1 >> hw->shift; + len2 = blen2 >> hw->shift; + ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2); + decr = len1 + len2; + rpos = hw->rpos; + + if (len1) { + rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1); + } + + if (len2) { + rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2); + } + + fmod_unlock_sample (fmd, p1, p2, blen1, blen2); + + pcm_hw_dec_live (hw, decr); + hw->rpos = rpos % hw->samples; + fmd->old_pos = (fmd->old_pos + decr) % hw->samples; +} + +static int AUD_to_fmodfmt (audfmt_e fmt, int stereo) +{ + int mode = FSOUND_LOOP_NORMAL; + + switch (fmt) { + case AUD_FMT_S8: + mode |= FSOUND_SIGNED | FSOUND_8BITS; + break; + + case AUD_FMT_U8: + mode |= FSOUND_UNSIGNED | FSOUND_8BITS; + break; + + case AUD_FMT_S16: + mode |= FSOUND_SIGNED | FSOUND_16BITS; + break; + + case AUD_FMT_U16: + mode |= FSOUND_UNSIGNED | FSOUND_16BITS; + break; + + default: + dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt); + exit (EXIT_FAILURE); + } + mode |= stereo ? FSOUND_STEREO : FSOUND_MONO; + return mode; +} + +static void fmod_hw_fini (HWVoice *hw) +{ + FMODVoice *fmd = (FMODVoice *) hw; + + if (fmd->fmod_sample) { + FSOUND_Sample_Free (fmd->fmod_sample); + fmd->fmod_sample = 0; + + if (fmd->channel >= 0) { + FSOUND_StopSound (fmd->channel); + } + } +} + +static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + int bits16, mode, channel; + FMODVoice *fmd = (FMODVoice *) hw; + + mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0); + fmd->fmod_sample = FSOUND_Sample_Alloc ( + FSOUND_FREE, /* index */ + conf.nb_samples, /* length */ + mode, /* mode */ + freq, /* freq */ + 255, /* volume */ + 128, /* pan */ + 255 /* priority */ + ); + + if (!fmd->fmod_sample) { + dolog ("Failed to allocate FMOD sample\nReason: %s\n", errstr ()); + return -1; + } + + channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1); + if (channel < 0) { + dolog ("Failed to start playing sound\nReason: %s\n", errstr ()); + FSOUND_Sample_Free (fmd->fmod_sample); + return -1; + } + fmd->channel = channel; + + hw->freq = freq; + hw->fmt = fmt; + hw->nchannels = nchannels; + bits16 = fmt == AUD_FMT_U16 || fmt == AUD_FMT_S16; + hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16; + return 0; +} + +static int fmod_hw_ctl (HWVoice *hw, int cmd, ...) +{ + int status; + FMODVoice *fmd = (FMODVoice *) hw; + + switch (cmd) { + case VOICE_ENABLE: + fmod_clear_sample (fmd); + status = FSOUND_SetPaused (fmd->channel, 0); + if (!status) { + dolog ("Failed to resume channel %d\nReason: %s\n", + fmd->channel, errstr ()); + } + break; + + case VOICE_DISABLE: + status = FSOUND_SetPaused (fmd->channel, 1); + if (!status) { + dolog ("Failed to pause channel %d\nReason: %s\n", + fmd->channel, errstr ()); + } + break; + } + return 0; +} + +static struct { + const char *name; + int type; +} drvtab[] = { + {"none", FSOUND_OUTPUT_NOSOUND}, +#ifdef _WIN32 + {"winmm", FSOUND_OUTPUT_WINMM}, + {"dsound", FSOUND_OUTPUT_DSOUND}, + {"a3d", FSOUND_OUTPUT_A3D}, + {"asio", FSOUND_OUTPUT_ASIO}, +#endif +#ifdef __linux__ + {"oss", FSOUND_OUTPUT_OSS}, + {"alsa", FSOUND_OUTPUT_ALSA}, + {"esd", FSOUND_OUTPUT_ESD}, +#endif +#ifdef __APPLE__ + {"mac", FSOUND_OUTPUT_MAC}, +#endif +#if 0 + {"xbox", FSOUND_OUTPUT_XBOX}, + {"ps2", FSOUND_OUTPUT_PS2}, + {"gcube", FSOUND_OUTPUT_GC}, +#endif + {"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME} +}; + +static void *fmod_audio_init (void) +{ + int i; + double ver; + int status; + int output_type = -1; + const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL); + + ver = FSOUND_GetVersion (); + if (ver < FMOD_VERSION) { + dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION); + return NULL; + } + + if (drv) { + int found = 0; + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { + if (!strcmp (drv, drvtab[i].name)) { + output_type = drvtab[i].type; + found = 1; + break; + } + } + if (!found) { + dolog ("Unknown FMOD output driver `%s'\n", drv); + } + } + + if (output_type != -1) { + status = FSOUND_SetOutput (output_type); + if (!status) { + dolog ("FSOUND_SetOutput(%d) failed\nReason: %s\n", + output_type, errstr ()); + return NULL; + } + } + + conf.freq = audio_get_conf_int (QC_FMOD_FREQ, conf.freq); + conf.nb_samples = audio_get_conf_int (QC_FMOD_SAMPLES, conf.nb_samples); + conf.nb_channels = + audio_get_conf_int (QC_FMOD_CHANNELS, + (audio_state.nb_hw_voices > 1 + ? audio_state.nb_hw_voices + : conf.nb_channels)); + conf.bufsize = audio_get_conf_int (QC_FMOD_BUFSIZE, conf.bufsize); + conf.threshold = audio_get_conf_int (QC_FMOD_THRESHOLD, conf.threshold); + + if (conf.bufsize) { + status = FSOUND_SetBufferSize (conf.bufsize); + if (!status) { + dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n", + conf.bufsize, errstr ()); + } + } + + status = FSOUND_Init (conf.freq, conf.nb_channels, 0); + if (!status) { + dolog ("FSOUND_Init failed\nReason: %s\n", errstr ()); + return NULL; + } + + return &conf; +} + +static void fmod_audio_fini (void *opaque) +{ + FSOUND_Close (); +} + +struct pcm_ops fmod_pcm_ops = { + fmod_hw_init, + fmod_hw_fini, + fmod_hw_run, + fmod_hw_write, + fmod_hw_ctl +}; + +struct audio_output_driver fmod_output_driver = { + "fmod", + fmod_audio_init, + fmod_audio_fini, + &fmod_pcm_ops, + 1, + INT_MAX, + sizeof (FMODVoice) +}; diff --git a/audio/fmodaudio.h b/audio/fmodaudio.h new file mode 100644 index 000000000..9f85c3080 --- /dev/null +++ b/audio/fmodaudio.h @@ -0,0 +1,39 @@ +/* + * QEMU FMOD audio output driver header + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_FMODAUDIO_H +#define QEMU_FMODAUDIO_H + +#include + +typedef struct FMODVoice { + struct HWVoice hw; + unsigned int old_pos; + FSOUND_SAMPLE *fmod_sample; + int channel; +} FMODVoice; + +extern struct pcm_ops fmod_pcm_ops; +extern struct audio_output_driver fmod_output_driver; + +#endif /* fmodaudio.h */ diff --git a/audio/mixeng.c b/audio/mixeng.c new file mode 100644 index 000000000..b0bb412c6 --- /dev/null +++ b/audio/mixeng.c @@ -0,0 +1,255 @@ +/* + * QEMU Mixing engine + * + * Copyright (c) 2004 Vassili Karpov (malc) + * Copyright (c) 1998 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +//#define DEBUG_FP +#include "audio/mixeng.h" + +#define IN_T int8_t +#define IN_MIN CHAR_MIN +#define IN_MAX CHAR_MAX +#define SIGNED +#include "mixeng_template.h" +#undef SIGNED +#undef IN_MAX +#undef IN_MIN +#undef IN_T + +#define IN_T uint8_t +#define IN_MIN 0 +#define IN_MAX UCHAR_MAX +#include "mixeng_template.h" +#undef IN_MAX +#undef IN_MIN +#undef IN_T + +#define IN_T int16_t +#define IN_MIN SHRT_MIN +#define IN_MAX SHRT_MAX +#define SIGNED +#include "mixeng_template.h" +#undef SIGNED +#undef IN_MAX +#undef IN_MIN +#undef IN_T + +#define IN_T uint16_t +#define IN_MIN 0 +#define IN_MAX USHRT_MAX +#include "mixeng_template.h" +#undef IN_MAX +#undef IN_MIN +#undef IN_T + +t_sample *mixeng_conv[2][2][2] = { + { + { + conv_uint8_t_to_mono, + conv_uint16_t_to_mono + }, + { + conv_int8_t_to_mono, + conv_int16_t_to_mono + } + }, + { + { + conv_uint8_t_to_stereo, + conv_uint16_t_to_stereo + }, + { + conv_int8_t_to_stereo, + conv_int16_t_to_stereo + } + } +}; + +f_sample *mixeng_clip[2][2][2] = { + { + { + clip_uint8_t_from_mono, + clip_uint16_t_from_mono + }, + { + clip_int8_t_from_mono, + clip_int16_t_from_mono + } + }, + { + { + clip_uint8_t_from_stereo, + clip_uint16_t_from_stereo + }, + { + clip_int8_t_from_stereo, + clip_int16_t_from_stereo + } + } +}; + +/* + * August 21, 1998 + * Copyright 1998 Fabrice Bellard. + * + * [Rewrote completly the code of Lance Norskog And Sundry + * Contributors with a more efficient algorithm.] + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +/* + * Sound Tools rate change effect file. + */ +/* + * Linear Interpolation. + * + * The use of fractional increment allows us to use no buffer. It + * avoid the problems at the end of the buffer we had with the old + * method which stored a possibly big buffer of size + * lcm(in_rate,out_rate). + * + * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If + * the input & output frequencies are equal, a delay of one sample is + * introduced. Limited to processing 32-bit count worth of samples. + * + * 1 << FRAC_BITS evaluating to zero in several places. Changed with + * an (unsigned long) cast to make it safe. MarkMLl 2/1/99 + */ + +/* Private data */ +typedef struct ratestuff { + uint64_t opos; + uint64_t opos_inc; + uint32_t ipos; /* position in the input stream (integer) */ + st_sample_t ilast; /* last sample in the input stream */ +} *rate_t; + +/* + * Prepare processing. + */ +void *st_rate_start (int inrate, int outrate) +{ + rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff)); + + if (!rate) { + exit (EXIT_FAILURE); + } + + if (inrate == outrate) { + // exit (EXIT_FAILURE); + } + + if (inrate >= 65535 || outrate >= 65535) { + // exit (EXIT_FAILURE); + } + + rate->opos = 0; + + /* increment */ + rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate; + + rate->ipos = 0; + rate->ilast.l = 0; + rate->ilast.r = 0; + return rate; +} + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, + int *isamp, int *osamp) +{ + rate_t rate = (rate_t) opaque; + st_sample_t *istart, *iend; + st_sample_t *ostart, *oend; + st_sample_t ilast, icur, out; + int64_t t; + + ilast = rate->ilast; + + istart = ibuf; + iend = ibuf + *isamp; + + ostart = obuf; + oend = obuf + *osamp; + + if (rate->opos_inc == 1ULL << 32) { + int i, n = *isamp > *osamp ? *osamp : *isamp; + for (i = 0; i < n; i++) { + obuf[i].l += ibuf[i].r; + obuf[i].r += ibuf[i].r; + } + *isamp = n; + *osamp = n; + return; + } + + while (obuf < oend) { + + /* Safety catch to make sure we have input samples. */ + if (ibuf >= iend) + break; + + /* read as many input samples so that ipos > opos */ + + while (rate->ipos <= (rate->opos >> 32)) { + ilast = *ibuf++; + rate->ipos++; + /* See if we finished the input buffer yet */ + if (ibuf >= iend) goto the_end; + } + + icur = *ibuf; + + /* interpolate */ + t = rate->opos & 0xffffffff; + out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX; + out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX; + + /* output sample & increment position */ +#if 0 + *obuf++ = out; +#else + obuf->l += out.l; + obuf->r += out.r; + obuf += 1; +#endif + rate->opos += rate->opos_inc; + } + +the_end: + *isamp = ibuf - istart; + *osamp = obuf - ostart; + rate->ilast = ilast; +} + +void st_rate_stop (void *opaque) +{ + qemu_free (opaque); +} diff --git a/audio/mixeng.h b/audio/mixeng.h new file mode 100644 index 000000000..699435ea2 --- /dev/null +++ b/audio/mixeng.h @@ -0,0 +1,39 @@ +/* + * QEMU Mixing engine header + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_MIXENG_H +#define QEMU_MIXENG_H + +typedef void (t_sample) (void *dst, const void *src, int samples); +typedef void (f_sample) (void *dst, const void *src, int samples); +typedef struct { int64_t l; int64_t r; } st_sample_t; + +extern t_sample *mixeng_conv[2][2][2]; +extern f_sample *mixeng_clip[2][2][2]; + +void *st_rate_start (int inrate, int outrate); +void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, + int *isamp, int *osamp); +void st_rate_stop (void *opaque); + +#endif /* mixeng.h */ diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h new file mode 100644 index 000000000..f3b3f654f --- /dev/null +++ b/audio/mixeng_template.h @@ -0,0 +1,111 @@ +/* + * QEMU Mixing engine + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * Tusen tack till Mike Nordell + * dec++'ified by Dscho + */ + +#ifdef SIGNED +#define HALFT IN_MAX +#define HALF IN_MAX +#else +#define HALFT ((IN_MAX)>>1) +#define HALF HALFT +#endif + +static int64_t inline glue(conv_,IN_T) (IN_T v) +{ +#ifdef SIGNED + return (INT_MAX*(int64_t)v)/HALF; +#else + return (INT_MAX*((int64_t)v-HALFT))/HALF; +#endif +} + +static IN_T inline glue(clip_,IN_T) (int64_t v) +{ + if (v >= INT_MAX) + return IN_MAX; + else if (v < -INT_MAX) + return IN_MIN; + +#ifdef SIGNED + return (IN_T) (v*HALF/INT_MAX); +#else + return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX; +#endif +} + +static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src, + int samples) +{ + st_sample_t *out = (st_sample_t *) dst; + IN_T *in = (IN_T *) src; + while (samples--) { + out->l = glue(conv_,IN_T) (*in++); + out->r = glue(conv_,IN_T) (*in++); + out += 1; + } +} + +static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src, + int samples) +{ + st_sample_t *out = (st_sample_t *) dst; + IN_T *in = (IN_T *) src; + while (samples--) { + out->l = glue(conv_,IN_T) (in[0]); + out->r = out->l; + out += 1; + in += 1; + } +} + +static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src, + int samples) +{ + st_sample_t *in = (st_sample_t *) src; + IN_T *out = (IN_T *) dst; + while (samples--) { + *out++ = glue(clip_,IN_T) (in->l); + *out++ = glue(clip_,IN_T) (in->r); + in += 1; + } +} + +static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src, + int samples) +{ + st_sample_t *in = (st_sample_t *) src; + IN_T *out = (IN_T *) dst; + while (samples--) { + *out++ = glue(clip_,IN_T) (in->l + in->r); + in += 1; + } +} + +#undef HALF +#undef HALFT + diff --git a/audio/ossaudio.c b/audio/ossaudio.c new file mode 100644 index 000000000..9fefaa3a2 --- /dev/null +++ b/audio/ossaudio.c @@ -0,0 +1,466 @@ +/* + * QEMU OSS audio output driver + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* Temporary kludge */ +#if defined __linux__ || (defined _BSD && !defined __APPLE__) +#include +#include "vl.h" + +#include +#include +#include +#include + +#define AUDIO_CAP "oss" +#include "audio/audio.h" +#include "audio/ossaudio.h" + +#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" +#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" +#define QC_OSS_MMAP "QEMU_OSS_MMAP" +#define QC_OSS_DEV "QEMU_OSS_DEV" + +#define errstr() strerror (errno) + +static struct { + int try_mmap; + int nfrags; + int fragsize; + const char *dspname; +} conf = { + .try_mmap = 0, + .nfrags = 4, + .fragsize = 4096, + .dspname = "/dev/dsp" +}; + +struct oss_params { + int freq; + audfmt_e fmt; + int nchannels; + int nfrags; + int fragsize; +}; + +static int oss_hw_write (SWVoice *sw, void *buf, int len) +{ + return pcm_hw_write (sw, buf, len); +} + +static int AUD_to_ossfmt (audfmt_e fmt) +{ + switch (fmt) { + case AUD_FMT_S8: return AFMT_S8; + case AUD_FMT_U8: return AFMT_U8; + case AUD_FMT_S16: return AFMT_S16_LE; + case AUD_FMT_U16: return AFMT_U16_LE; + default: + dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt); + exit (EXIT_FAILURE); + } +} + +static int oss_to_audfmt (int fmt) +{ + switch (fmt) { + case AFMT_S8: return AUD_FMT_S8; + case AFMT_U8: return AUD_FMT_U8; + case AFMT_S16_LE: return AUD_FMT_S16; + case AFMT_U16_LE: return AUD_FMT_U16; + default: + dolog ("Internal logic error: Unrecognized OSS audio format %d\n" + "Aborting\n", + fmt); + exit (EXIT_FAILURE); + } +} + +#ifdef DEBUG_PCM +static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt) +{ + dolog ("parameter | requested value | obtained value\n"); + dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); + dolog ("channels | %10d | %10d\n", req->nchannels, obt->nchannels); + dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); + dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); + dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize); +} +#endif + +static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd) +{ + int fd; + int mmmmssss; + audio_buf_info abinfo; + int fmt, freq, nchannels; + const char *dspname = conf.dspname; + + fd = open (dspname, O_RDWR | O_NONBLOCK); + if (-1 == fd) { + dolog ("Could not initialize audio hardware. Failed to open `%s':\n" + "Reason:%s\n", + dspname, + errstr ()); + return -1; + } + + freq = req->freq; + nchannels = req->nchannels; + fmt = req->fmt; + + if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set sample size\n" + "Reason: %s\n", + errstr ()); + goto err; + } + + if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set number of channels\n" + "Reason: %s\n", + errstr ()); + goto err; + } + + if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set frequency\n" + "Reason: %s\n", + errstr ()); + goto err; + } + + if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set non-blocking mode\n" + "Reason: %s\n", + errstr ()); + goto err; + } + + mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize); + if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { + dolog ("Could not initialize audio hardware\n" + "Failed to set buffer length (%d, %d)\n" + "Reason:%s\n", + conf.nfrags, conf.fragsize, + errstr ()); + goto err; + } + + if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) { + dolog ("Could not initialize audio hardware\n" + "Failed to get buffer length\n" + "Reason:%s\n", + errstr ()); + goto err; + } + + obt->fmt = fmt; + obt->nchannels = nchannels; + obt->freq = freq; + obt->nfrags = abinfo.fragstotal; + obt->fragsize = abinfo.fragsize; + *pfd = fd; + + if ((req->fmt != obt->fmt) || + (req->nchannels != obt->nchannels) || + (req->freq != obt->freq) || + (req->fragsize != obt->fragsize) || + (req->nfrags != obt->nfrags)) { +#ifdef DEBUG_PCM + dolog ("Audio parameters mismatch\n"); + oss_dump_pcm_info (req, obt); +#endif + } + +#ifdef DEBUG_PCM + oss_dump_pcm_info (req, obt); +#endif + return 0; + +err: + close (fd); + return -1; +} + +static void oss_hw_run (HWVoice *hw) +{ + OSSVoice *oss = (OSSVoice *) hw; + int err, rpos, live, decr; + int samples; + uint8_t *dst; + st_sample_t *src; + struct audio_buf_info abinfo; + struct count_info cntinfo; + + live = pcm_hw_get_live (hw); + if (live <= 0) + return; + + if (oss->mmapped) { + int bytes; + + err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); + if (err < 0) { + dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ()); + return; + } + + if (cntinfo.ptr == oss->old_optr) { + if (abs (hw->samples - live) < 64) + dolog ("overrun\n"); + return; + } + + if (cntinfo.ptr > oss->old_optr) { + bytes = cntinfo.ptr - oss->old_optr; + } + else { + bytes = hw->bufsize + cntinfo.ptr - oss->old_optr; + } + + decr = audio_MIN (bytes >> hw->shift, live); + } + else { + err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo); + if (err < 0) { + dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ()); + return; + } + + decr = audio_MIN (abinfo.bytes >> hw->shift, live); + if (decr <= 0) + return; + } + + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int convert_samples = audio_MIN (samples, left_till_end_samples); + + src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); + dst = advance (oss->pcm_buf, rpos << hw->shift); + + hw->clip (dst, src, convert_samples); + if (!oss->mmapped) { + int written; + + written = write (oss->fd, dst, convert_samples << hw->shift); + /* XXX: follow errno recommendations ? */ + if (written == -1) { + dolog ("Failed to write audio\nReason: %s\n", errstr ()); + continue; + } + + if (written != convert_samples << hw->shift) { + int wsamples = written >> hw->shift; + int wbytes = wsamples << hw->shift; + if (wbytes != written) { + dolog ("Unaligned write %d, %d\n", wbytes, written); + } + memset (src, 0, wbytes); + decr -= samples; + rpos = (rpos + wsamples) % hw->samples; + break; + } + } + memset (src, 0, convert_samples * sizeof (st_sample_t)); + + rpos = (rpos + convert_samples) % hw->samples; + samples -= convert_samples; + } + if (oss->mmapped) { + oss->old_optr = cntinfo.ptr; + } + + pcm_hw_dec_live (hw, decr); + hw->rpos = rpos; +} + +static void oss_hw_fini (HWVoice *hw) +{ + int err; + OSSVoice *oss = (OSSVoice *) hw; + + ldebug ("oss_hw_fini\n"); + err = close (oss->fd); + if (err) { + dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ()); + } + oss->fd = -1; + + if (oss->pcm_buf) { + if (oss->mmapped) { + err = munmap (oss->pcm_buf, hw->bufsize); + if (err) { + dolog ("Failed to unmap OSS buffer\nReason: %s\n", + errstr ()); + } + } + else { + qemu_free (oss->pcm_buf); + } + oss->pcm_buf = NULL; + } +} + +static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + OSSVoice *oss = (OSSVoice *) hw; + struct oss_params req, obt; + + assert (!oss->fd); + req.fmt = AUD_to_ossfmt (fmt); + req.freq = freq; + req.nchannels = nchannels; + req.fragsize = conf.fragsize; + req.nfrags = conf.nfrags; + + if (oss_open (&req, &obt, &oss->fd)) + return -1; + + hw->freq = obt.freq; + hw->fmt = oss_to_audfmt (obt.fmt); + hw->nchannels = obt.nchannels; + + oss->nfrags = obt.nfrags; + oss->fragsize = obt.fragsize; + hw->bufsize = obt.nfrags * obt.fragsize; + + oss->mmapped = 0; + if (conf.try_mmap) { + oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE, + MAP_SHARED, oss->fd, 0); + if (oss->pcm_buf == MAP_FAILED) { + dolog ("Failed to mmap OSS device\nReason: %s\n", + errstr ()); + } + + for (;;) { + int err; + int trig = 0; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n", + errstr ()); + goto fail; + } + + trig = PCM_ENABLE_OUTPUT; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" + "Reason: %s\n", errstr ()); + goto fail; + } + oss->mmapped = 1; + break; + + fail: + err = munmap (oss->pcm_buf, hw->bufsize); + if (err) { + dolog ("Failed to unmap OSS device\nReason: %s\n", + errstr ()); + } + } + } + + if (!oss->mmapped) { + oss->pcm_buf = qemu_mallocz (hw->bufsize); + if (!oss->pcm_buf) { + close (oss->fd); + oss->fd = -1; + return -1; + } + } + + return 0; +} + +static int oss_hw_ctl (HWVoice *hw, int cmd, ...) +{ + int trig; + OSSVoice *oss = (OSSVoice *) hw; + + if (!oss->mmapped) + return 0; + + switch (cmd) { + case VOICE_ENABLE: + ldebug ("enabling voice\n"); + pcm_hw_clear (hw, oss->pcm_buf, hw->samples); + trig = PCM_ENABLE_OUTPUT; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" + "Reason: %s\n", errstr ()); + return -1; + } + break; + + case VOICE_DISABLE: + ldebug ("disabling voice\n"); + trig = 0; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n", + errstr ()); + return -1; + } + break; + } + return 0; +} + +static void *oss_audio_init (void) +{ + conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize); + conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags); + conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap); + conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname); + return &conf; +} + +static void oss_audio_fini (void *opaque) +{ +} + +struct pcm_ops oss_pcm_ops = { + oss_hw_init, + oss_hw_fini, + oss_hw_run, + oss_hw_write, + oss_hw_ctl +}; + +struct audio_output_driver oss_output_driver = { + "oss", + oss_audio_init, + oss_audio_fini, + &oss_pcm_ops, + 1, + INT_MAX, + sizeof (OSSVoice) +}; +#endif diff --git a/audio/ossaudio.h b/audio/ossaudio.h new file mode 100644 index 000000000..f7d3ebd52 --- /dev/null +++ b/audio/ossaudio.h @@ -0,0 +1,40 @@ +/* + * QEMU OSS audio output driver header + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_OSSAUDIO_H +#define QEMU_OSSAUDIO_H + +typedef struct OSSVoice { + struct HWVoice hw; + void *pcm_buf; + int fd; + int nfrags; + int fragsize; + int mmapped; + int old_optr; +} OSSVoice; + +extern struct pcm_ops oss_pcm_ops; +extern struct audio_output_driver oss_output_driver; + +#endif /* ossaudio.h */ diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c new file mode 100644 index 000000000..4d7585342 --- /dev/null +++ b/audio/sdlaudio.c @@ -0,0 +1,323 @@ +/* + * QEMU SDL audio output driver + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include "vl.h" + +#define AUDIO_CAP "sdl" +#include "audio/audio.h" +#include "audio/sdlaudio.h" + +#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES" + +#define errstr() SDL_GetError () + +static struct { + int nb_samples; +} conf = { + 1024 +}; + +struct SDLAudioState { + int exit; + SDL_mutex *mutex; + SDL_sem *sem; + int initialized; +} glob_sdl; +typedef struct SDLAudioState SDLAudioState; + +static void sdl_hw_run (HWVoice *hw) +{ + (void) hw; +} + +static int sdl_lock (SDLAudioState *s) +{ + if (SDL_LockMutex (s->mutex)) { + dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int sdl_unlock (SDLAudioState *s) +{ + if (SDL_UnlockMutex (s->mutex)) { + dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int sdl_post (SDLAudioState *s) +{ + if (SDL_SemPost (s->sem)) { + dolog ("SDL_SemPost failed\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int sdl_wait (SDLAudioState *s) +{ + if (SDL_SemWait (s->sem)) { + dolog ("SDL_SemWait failed\nReason: %s\n", errstr ()); + return -1; + } + return 0; +} + +static int sdl_unlock_and_post (SDLAudioState *s) +{ + if (sdl_unlock (s)) + return -1; + + return sdl_post (s); +} + +static int sdl_hw_write (SWVoice *sw, void *buf, int len) +{ + int ret; + SDLAudioState *s = &glob_sdl; + sdl_lock (s); + ret = pcm_hw_write (sw, buf, len); + sdl_unlock_and_post (s); + return ret; +} + +static int AUD_to_sdlfmt (audfmt_e fmt, int *shift) +{ + *shift = 0; + switch (fmt) { + case AUD_FMT_S8: return AUDIO_S8; + case AUD_FMT_U8: return AUDIO_U8; + case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB; + case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB; + default: + dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt); + exit (EXIT_FAILURE); + } +} + +static int sdl_to_audfmt (int fmt) +{ + switch (fmt) { + case AUDIO_S8: return AUD_FMT_S8; + case AUDIO_U8: return AUD_FMT_U8; + case AUDIO_S16LSB: return AUD_FMT_S16; + case AUDIO_U16LSB: return AUD_FMT_U16; + default: + dolog ("Internal logic error: Unrecognized SDL audio format %d\n" + "Aborting\n", fmt); + exit (EXIT_FAILURE); + } +} + +static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) +{ + int status; + + status = SDL_OpenAudio (req, obt); + if (status) { + dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ()); + } + return status; +} + +static void sdl_close (SDLAudioState *s) +{ + if (s->initialized) { + sdl_lock (s); + s->exit = 1; + sdl_unlock_and_post (s); + SDL_PauseAudio (1); + SDL_CloseAudio (); + s->initialized = 0; + } +} + +static void sdl_callback (void *opaque, Uint8 *buf, int len) +{ + SDLVoice *sdl = opaque; + SDLAudioState *s = &glob_sdl; + HWVoice *hw = &sdl->hw; + int samples = len >> hw->shift; + + if (s->exit) { + return; + } + + while (samples) { + int to_mix, live, decr; + + /* dolog ("in callback samples=%d\n", samples); */ + sdl_wait (s); + if (s->exit) { + return; + } + + sdl_lock (s); + live = pcm_hw_get_live (hw); + if (live <= 0) + goto again; + + /* dolog ("in callback live=%d\n", live); */ + to_mix = audio_MIN (samples, live); + decr = to_mix; + while (to_mix) { + int chunk = audio_MIN (to_mix, hw->samples - hw->rpos); + st_sample_t *src = hw->mix_buf + hw->rpos; + + /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ + hw->clip (buf, src, chunk); + memset (src, 0, chunk * sizeof (st_sample_t)); + hw->rpos = (hw->rpos + chunk) % hw->samples; + to_mix -= chunk; + buf += chunk << hw->shift; + } + samples -= decr; + pcm_hw_dec_live (hw, decr); + + again: + sdl_unlock (s); + } + /* dolog ("done len=%d\n", len); */ +} + +static void sdl_hw_fini (HWVoice *hw) +{ + ldebug ("sdl_hw_fini %d fixed=%d\n", + glob_sdl.initialized, audio_conf.fixed_format); + sdl_close (&glob_sdl); +} + +static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + SDLVoice *sdl = (SDLVoice *) hw; + SDLAudioState *s = &glob_sdl; + SDL_AudioSpec req, obt; + int shift; + + ldebug ("sdl_hw_init %d freq=%d fixed=%d\n", + s->initialized, freq, audio_conf.fixed_format); + + if (nchannels != 2) { + dolog ("Bogus channel count %d\n", nchannels); + return -1; + } + + req.freq = freq; + req.format = AUD_to_sdlfmt (fmt, &shift); + req.channels = nchannels; + req.samples = conf.nb_samples; + shift <<= nchannels == 2; + + req.callback = sdl_callback; + req.userdata = sdl; + + if (sdl_open (&req, &obt)) + return -1; + + hw->freq = obt.freq; + hw->fmt = sdl_to_audfmt (obt.format); + hw->nchannels = obt.channels; + hw->bufsize = obt.samples << shift; + + s->initialized = 1; + s->exit = 0; + SDL_PauseAudio (0); + return 0; +} + +static int sdl_hw_ctl (HWVoice *hw, int cmd, ...) +{ + (void) hw; + + switch (cmd) { + case VOICE_ENABLE: + SDL_PauseAudio (0); + break; + + case VOICE_DISABLE: + SDL_PauseAudio (1); + break; + } + return 0; +} + +static void *sdl_audio_init (void) +{ + SDLAudioState *s = &glob_sdl; + conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples); + + if (SDL_InitSubSystem (SDL_INIT_AUDIO)) { + dolog ("SDL failed to initialize audio subsystem\nReason: %s\n", + errstr ()); + return NULL; + } + + s->mutex = SDL_CreateMutex (); + if (!s->mutex) { + dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ()); + SDL_QuitSubSystem (SDL_INIT_AUDIO); + return NULL; + } + + s->sem = SDL_CreateSemaphore (0); + if (!s->sem) { + dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ()); + SDL_DestroyMutex (s->mutex); + SDL_QuitSubSystem (SDL_INIT_AUDIO); + return NULL; + } + + return s; +} + +static void sdl_audio_fini (void *opaque) +{ + SDLAudioState *s = opaque; + sdl_close (s); + SDL_DestroySemaphore (s->sem); + SDL_DestroyMutex (s->mutex); + SDL_QuitSubSystem (SDL_INIT_AUDIO); +} + +struct pcm_ops sdl_pcm_ops = { + sdl_hw_init, + sdl_hw_fini, + sdl_hw_run, + sdl_hw_write, + sdl_hw_ctl +}; + +struct audio_output_driver sdl_output_driver = { + "sdl", + sdl_audio_init, + sdl_audio_fini, + &sdl_pcm_ops, + 1, + 1, + sizeof (SDLVoice) +}; diff --git a/audio/sdlaudio.h b/audio/sdlaudio.h new file mode 100644 index 000000000..380d0da2a --- /dev/null +++ b/audio/sdlaudio.h @@ -0,0 +1,34 @@ +/* + * QEMU SDL audio output driver header + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_SDLAUDIO_H +#define QEMU_SDLAUDIO_H + +typedef struct SDLVoice { + struct HWVoice hw; +} SDLVoice; + +extern struct pcm_ops sdl_pcm_ops; +extern struct audio_output_driver sdl_output_driver; + +#endif /* sdlaudio.h */ diff --git a/audio/wavaudio.c b/audio/wavaudio.c new file mode 100644 index 000000000..dee4a060d --- /dev/null +++ b/audio/wavaudio.c @@ -0,0 +1,200 @@ +/* + * QEMU WAV audio output driver + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#define AUDIO_CAP "wav" +#include "audio/audio.h" +#include "audio/wavaudio.h" + +static struct { + const char *wav_path; +} conf = { + .wav_path = "qemu.wav" +}; + +static void wav_hw_run (HWVoice *hw) +{ + WAVVoice *wav = (WAVVoice *) hw; + int rpos, live, decr, samples; + uint8_t *dst; + st_sample_t *src; + int64_t now = qemu_get_clock (vm_clock); + int64_t ticks = now - wav->old_ticks; + int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; + wav->old_ticks = now; + + if (bytes > INT_MAX) + samples = INT_MAX >> hw->shift; + else + samples = bytes >> hw->shift; + + live = pcm_hw_get_live (hw); + if (live <= 0) + return; + + decr = audio_MIN (live, samples); + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int convert_samples = audio_MIN (samples, left_till_end_samples); + + src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); + dst = advance (wav->pcm_buf, rpos << hw->shift); + + hw->clip (dst, src, convert_samples); + qemu_put_buffer (wav->f, dst, convert_samples << hw->shift); + memset (src, 0, convert_samples * sizeof (st_sample_t)); + + rpos = (rpos + convert_samples) % hw->samples; + samples -= convert_samples; + wav->total_samples += convert_samples; + } + + pcm_hw_dec_live (hw, decr); + hw->rpos = rpos; +} + +static int wav_hw_write (SWVoice *sw, void *buf, int len) +{ + return pcm_hw_write (sw, buf, len); +} + + +/* VICE code: Store number as little endian. */ +static void le_store (uint8_t *buf, uint32_t val, int len) +{ + int i; + for (i = 0; i < len; i++) { + buf[i] = (uint8_t) (val & 0xff); + val >>= 8; + } +} + +static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + WAVVoice *wav = (WAVVoice *) hw; + int bits16 = 0, stereo = audio_state.fixed_channels == 2; + uint8_t hdr[] = { + 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, + 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, + 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 + }; + + switch (audio_state.fixed_fmt) { + case AUD_FMT_S8: + case AUD_FMT_U8: + break; + + case AUD_FMT_S16: + case AUD_FMT_U16: + bits16 = 1; + break; + } + + hdr[34] = bits16 ? 0x10 : 0x08; + hw->freq = 44100; + hw->nchannels = stereo ? 2 : 1; + hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; + hw->bufsize = 4096; + wav->pcm_buf = qemu_mallocz (hw->bufsize); + if (!wav->pcm_buf) + return -1; + + le_store (hdr + 22, hw->nchannels, 2); + le_store (hdr + 24, hw->freq, 4); + le_store (hdr + 28, hw->freq << (bits16 + stereo), 4); + le_store (hdr + 32, 1 << (bits16 + stereo), 2); + + wav->f = fopen (conf.wav_path, "wb"); + if (!wav->f) { + dolog ("failed to open wave file `%s'\nReason: %s\n", + conf.wav_path, strerror (errno)); + return -1; + } + + qemu_put_buffer (wav->f, hdr, sizeof (hdr)); + return 0; +} + +static void wav_hw_fini (HWVoice *hw) +{ + WAVVoice *wav = (WAVVoice *) hw; + int stereo = hw->nchannels == 2; + uint8_t rlen[4]; + uint8_t dlen[4]; + uint32_t rifflen = (wav->total_samples << stereo) + 36; + uint32_t datalen = wav->total_samples << stereo; + + if (!wav->f || !hw->active) + return; + + le_store (rlen, rifflen, 4); + le_store (dlen, datalen, 4); + + qemu_fseek (wav->f, 4, SEEK_SET); + qemu_put_buffer (wav->f, rlen, 4); + + qemu_fseek (wav->f, 32, SEEK_CUR); + qemu_put_buffer (wav->f, dlen, 4); + + fclose (wav->f); + wav->f = NULL; +} + +static int wav_hw_ctl (HWVoice *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +static void *wav_audio_init (void) +{ + return &conf; +} + +static void wav_audio_fini (void *opaque) +{ + ldebug ("wav_fini"); +} + +struct pcm_ops wav_pcm_ops = { + wav_hw_init, + wav_hw_fini, + wav_hw_run, + wav_hw_write, + wav_hw_ctl +}; + +struct audio_output_driver wav_output_driver = { + "wav", + wav_audio_init, + wav_audio_fini, + &wav_pcm_ops, + 1, + 1, + sizeof (WAVVoice) +}; diff --git a/audio/wavaudio.h b/audio/wavaudio.h new file mode 100644 index 000000000..0b6070be7 --- /dev/null +++ b/audio/wavaudio.h @@ -0,0 +1,38 @@ +/* + * QEMU WAV audio output driver header + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_WAVAUDIO_H +#define QEMU_WAVAUDIO_H + +typedef struct WAVVoice { + struct HWVoice hw; + QEMUFile *f; + int64_t old_ticks; + void *pcm_buf; + int total_samples; +} WAVVoice; + +extern struct pcm_ops wav_pcm_ops; +extern struct audio_output_driver wav_output_driver; + +#endif /* wavaudio.h */ diff --git a/hw/adlib.c b/hw/adlib.c new file mode 100644 index 000000000..a49b32b53 --- /dev/null +++ b/hw/adlib.c @@ -0,0 +1,309 @@ +/* + * QEMU Adlib emulation + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#define AUDIO_CAP "adlib" +#include "audio/audio.h" + +#ifdef USE_YMF262 +#define HAS_YMF262 1 +#include "ymf262.h" +void YMF262UpdateOneQEMU(int which, INT16 *dst, int length); +#define SHIFT 2 +#else +#include "fmopl.h" +#define SHIFT 1 +#endif + +#ifdef _WIN32 +#include +#define small_delay() Sleep (1) +#else +#define small_delay() usleep (1) +#endif + +#define IO_READ_PROTO(name) \ + uint32_t name (void *opaque, uint32_t nport) +#define IO_WRITE_PROTO(name) \ + void name (void *opaque, uint32_t nport, uint32_t val) + +static struct { + int port; + int freq; +} conf = {0x220, 44100}; + +typedef struct { + int enabled; + int active; + int cparam; + int64_t ticks; + int bufpos; + int16_t *mixbuf; + double interval; + QEMUTimer *ts, *opl_ts; + SWVoice *voice; + int left, pos, samples, bytes_per_second, old_free; + int refcount; +#ifndef USE_YMF262 + FM_OPL *opl; +#endif +} AdlibState; + +static AdlibState adlib; + +static IO_WRITE_PROTO(adlib_write) +{ + AdlibState *s = opaque; + int a = nport & 3; + int status; + + s->ticks = qemu_get_clock (vm_clock); + s->active = 1; + AUD_enable (s->voice, 1); + +#ifdef USE_YMF262 + status = YMF262Write (0, a, val); +#else + status = OPLWrite (s->opl, a, val); +#endif +} + +static IO_READ_PROTO(adlib_read) +{ + AdlibState *s = opaque; + uint8_t data; + int a = nport & 3; + +#ifdef USE_YMF262 + (void) s; + data = YMF262Read (0, a); +#else + data = OPLRead (s->opl, a); +#endif + return data; +} + +static void OPL_timer (void *opaque) +{ + AdlibState *s = opaque; +#ifdef USE_YMF262 + YMF262TimerOver (s->cparam >> 1, s->cparam & 1); +#else + OPLTimerOver (s->opl, s->cparam); +#endif + qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval); +} + +static void YMF262TimerHandler (int c, double interval_Sec) +{ + AdlibState *s = &adlib; + if (interval_Sec == 0.0) { + qemu_del_timer (s->opl_ts); + return; + } + s->cparam = c; + s->interval = ticks_per_sec * interval_Sec; + qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval); + small_delay (); +} + +static int write_audio (AdlibState *s, int samples) +{ + int net = 0; + int ss = samples; + while (samples) { + int nbytes = samples << SHIFT; + int wbytes = AUD_write (s->voice, + s->mixbuf + (s->pos << (SHIFT - 1)), + nbytes); + int wsampl = wbytes >> SHIFT; + samples -= wsampl; + s->pos = (s->pos + wsampl) % s->samples; + net += wsampl; + if (!wbytes) + break; + } + if (net > ss) { + dolog ("WARNING: net > ss\n"); + } + return net; +} + +static void timer (void *opaque) +{ + AdlibState *s = opaque; + int elapsed, samples, net = 0; + + if (s->refcount) + dolog ("refcount=%d\n", s->refcount); + + s->refcount += 1; + if (!(s->active && s->enabled)) + goto reset; + + AUD_run (); + + while (s->left) { + int written = write_audio (s, s->left); + net += written; + if (!written) + goto reset2; + s->left -= written; + } + s->pos = 0; + + elapsed = AUD_calc_elapsed (s->voice); + if (!elapsed) + goto reset2; + + /* elapsed = AUD_get_free (s->voice); */ + samples = elapsed >> SHIFT; + if (!samples) + goto reset2; + + samples = audio_MIN (samples, s->samples - s->pos); + if (s->left) + dolog ("left=%d samples=%d elapsed=%d free=%d\n", + s->left, samples, elapsed, AUD_get_free (s->voice)); + + if (!samples) + goto reset2; + +#ifdef USE_YMF262 + YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples); +#else + YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples); +#endif + + while (samples) { + int written = write_audio (s, samples); + net += written; + if (!written) + break; + samples -= written; + } + if (!samples) + s->pos = 0; + s->left = samples; + +reset2: + AUD_adjust (s->voice, net << SHIFT); +reset: + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + ticks_per_sec / 1024); + s->refcount -= 1; +} + +static void Adlib_fini (AdlibState *s) +{ +#ifdef USE_YMF262 + YMF262Shutdown (); +#else + if (s->opl) { + OPLDestroy (s->opl); + s->opl = NULL; + } +#endif + + if (s->opl_ts) + qemu_free_timer (s->opl_ts); + + if (s->ts) + qemu_free_timer (s->ts); + +#define maybe_free(p) if (p) qemu_free (p) + maybe_free (s->mixbuf); +#undef maybe_free + + s->active = 0; + s->enabled = 0; +} + +void Adlib_init (void) +{ + AdlibState *s = &adlib; + + memset (s, 0, sizeof (*s)); + +#ifdef USE_YMF262 + if (YMF262Init (1, 14318180, conf.freq)) { + dolog ("YMF262Init %d failed\n", conf.freq); + return; + } + else { + YMF262SetTimerHandler (0, YMF262TimerHandler, 0); + s->enabled = 1; + } +#else + s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq); + if (!s->opl) { + dolog ("OPLCreate %d failed\n", conf.freq); + return; + } + else { + OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0); + s->enabled = 1; + } +#endif + + s->opl_ts = qemu_new_timer (vm_clock, OPL_timer, s); + if (!s->opl_ts) { + dolog ("Can not get timer for adlib emulation\n"); + Adlib_fini (s); + return; + } + + s->ts = qemu_new_timer (vm_clock, timer, s); + if (!s->opl_ts) { + dolog ("Can not get timer for adlib emulation\n"); + Adlib_fini (s); + return; + } + + s->voice = AUD_open (s->voice, "adlib", conf.freq, SHIFT, AUD_FMT_S16); + if (!s->voice) { + Adlib_fini (s); + return; + } + + s->bytes_per_second = conf.freq << SHIFT; + s->samples = AUD_get_buffer_size (s->voice) >> SHIFT; + s->mixbuf = qemu_mallocz (s->samples << SHIFT); + + if (!s->mixbuf) { + dolog ("not enough memory for adlib mixing buffer (%d)\n", + s->samples << SHIFT); + Adlib_fini (s); + return; + } + register_ioport_read (0x388, 4, 1, adlib_read, s); + register_ioport_write (0x388, 4, 1, adlib_write, s); + + register_ioport_read (conf.port, 4, 1, adlib_read, s); + register_ioport_write (conf.port, 4, 1, adlib_write, s); + + register_ioport_read (conf.port + 8, 2, 1, adlib_read, s); + register_ioport_write (conf.port + 8, 2, 1, adlib_write, s); + + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); +} diff --git a/hw/dma.c b/hw/dma.c index e0c5bf100..989aac5d8 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -1,8 +1,8 @@ /* * QEMU DMA emulation - * - * Copyright (c) 2003 Vassili Karpov (malc) - * + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -23,9 +23,9 @@ */ #include "vl.h" -//#define DEBUG_DMA +/* #define DEBUG_DMA */ -#define log(...) fprintf (stderr, "dma: " __VA_ARGS__) +#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__) #ifdef DEBUG_DMA #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__) #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__) @@ -86,7 +86,7 @@ static void write_page (void *opaque, uint32_t nport, uint32_t data) ichan = channels[nport & 7]; if (-1 == ichan) { - log ("invalid channel %#x %#x\n", nport, data); + dolog ("invalid channel %#x %#x\n", nport, data); return; } d->regs[ichan].page = data; @@ -99,7 +99,7 @@ static void write_pageh (void *opaque, uint32_t nport, uint32_t data) ichan = channels[nport & 7]; if (-1 == ichan) { - log ("invalid channel %#x %#x\n", nport, data); + dolog ("invalid channel %#x %#x\n", nport, data); return; } d->regs[ichan].pageh = data; @@ -112,7 +112,7 @@ static uint32_t read_page (void *opaque, uint32_t nport) ichan = channels[nport & 7]; if (-1 == ichan) { - log ("invalid channel read %#x\n", nport); + dolog ("invalid channel read %#x\n", nport); return 0; } return d->regs[ichan].page; @@ -125,7 +125,7 @@ static uint32_t read_pageh (void *opaque, uint32_t nport) ichan = channels[nport & 7]; if (-1 == ichan) { - log ("invalid channel read %#x\n", nport); + dolog ("invalid channel read %#x\n", nport); return 0; } return d->regs[ichan].pageh; @@ -136,7 +136,7 @@ static inline void init_chan (struct dma_cont *d, int ichan) struct dma_regs *r; r = d->regs + ichan; - r->now[ADDR] = r->base[0] << d->dshift; + r->now[ADDR] = r->base[ADDR] << d->dshift; r->now[COUNT] = 0; } @@ -152,7 +152,7 @@ static inline int getff (struct dma_cont *d) static uint32_t read_chan (void *opaque, uint32_t nport) { struct dma_cont *d = opaque; - int ichan, nreg, iport, ff, val; + int ichan, nreg, iport, ff, val, dir; struct dma_regs *r; iport = (nport >> d->dshift) & 0x0f; @@ -160,12 +160,14 @@ static uint32_t read_chan (void *opaque, uint32_t nport) nreg = iport & 1; r = d->regs + ichan; + dir = ((r->mode >> 5) & 1) ? -1 : 1; ff = getff (d); if (nreg) val = (r->base[COUNT] << d->dshift) - r->now[COUNT]; else - val = r->now[ADDR] + r->now[COUNT]; + val = r->now[ADDR] + r->now[COUNT] * dir; + ldebug ("read_chan %#x -> %d\n", iport, val); return (val >> (d->dshift + (ff << 3))) & 0xff; } @@ -190,19 +192,19 @@ static void write_chan (void *opaque, uint32_t nport, uint32_t data) static void write_cont (void *opaque, uint32_t nport, uint32_t data) { struct dma_cont *d = opaque; - int iport, ichan; + int iport, ichan = 0; iport = (nport >> d->dshift) & 0x0f; switch (iport) { - case 8: /* command */ + case 0x08: /* command */ if ((data != 0) && (data & CMD_NOT_SUPPORTED)) { - log ("command %#x not supported\n", data); + dolog ("command %#x not supported\n", data); return; } d->command = data; break; - case 9: + case 0x09: ichan = data & 3; if (data & 4) { d->status |= 1 << (ichan + 4); @@ -213,22 +215,19 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) d->status &= ~(1 << ichan); break; - case 0xa: /* single mask */ + case 0x0a: /* single mask */ if (data & 4) d->mask |= 1 << (data & 3); else d->mask &= ~(1 << (data & 3)); break; - case 0xb: /* mode */ + case 0x0b: /* mode */ { ichan = data & 3; #ifdef DEBUG_DMA - int op; - int ai; - int dir; - int opmode; - + { + int op, ai, dir, opmode; op = (data >> 2) & 3; ai = (data >> 4) & 1; dir = (data >> 5) & 1; @@ -236,39 +235,39 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n", ichan, op, ai, dir, opmode); + } #endif - d->regs[ichan].mode = data; break; } - case 0xc: /* clear flip flop */ + case 0x0c: /* clear flip flop */ d->flip_flop = 0; break; - case 0xd: /* reset */ + case 0x0d: /* reset */ d->flip_flop = 0; d->mask = ~0; d->status = 0; d->command = 0; break; - case 0xe: /* clear mask for all channels */ + case 0x0e: /* clear mask for all channels */ d->mask = 0; break; - case 0xf: /* write mask for all channels */ + case 0x0f: /* write mask for all channels */ d->mask = data; break; default: - log ("dma: unknown iport %#x\n", iport); + dolog ("unknown iport %#x\n", iport); break; } #ifdef DEBUG_DMA if (0xc != iport) { - linfo ("nport %#06x, ichan % 2d, val %#06x\n", + linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n", nport, ichan, data); } #endif @@ -278,20 +277,22 @@ static uint32_t read_cont (void *opaque, uint32_t nport) { struct dma_cont *d = opaque; int iport, val; - + iport = (nport >> d->dshift) & 0x0f; switch (iport) { - case 0x08: /* status */ + case 0x08: /* status */ val = d->status; d->status &= 0xf0; break; - case 0x0f: /* mask */ + case 0x0f: /* mask */ val = d->mask; break; default: val = 0; break; } + + ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val); return val; } @@ -322,23 +323,27 @@ void DMA_release_DREQ (int nchan) static void channel_run (int ncont, int ichan) { - struct dma_regs *r; int n; - target_ulong addr; -/* int ai, dir; */ + struct dma_regs *r = &dma_controllers[ncont].regs[ichan]; +#ifdef DEBUG_DMA + int dir, opmode; - r = dma_controllers[ncont].regs + ichan; -/* ai = r->mode & 16; */ -/* dir = r->mode & 32 ? -1 : 1; */ + dir = (r->mode >> 5) & 1; + opmode = (r->mode >> 6) & 3; - /* NOTE: pageh is only used by PPC PREP */ - addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; - n = r->transfer_handler (r->opaque, addr, - (r->base[COUNT] << ncont) + (1 << ncont)); - r->now[COUNT] = n; + if (dir) { + dolog ("DMA in address decrement mode\n"); + } + if (opmode != 1) { + dolog ("DMA not in single mode select %#x\n", opmode); + } +#endif - ldebug ("dma_pos %d size %d\n", - n, (r->base[1] << ncont) + (1 << ncont)); + r = dma_controllers[ncont].regs + ichan; + n = r->transfer_handler (r->opaque, ichan + (ncont << 2), + r->now[COUNT], (r->base[COUNT] + 1) << ncont); + r->now[COUNT] = n; + ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont); } void DMA_run (void) @@ -361,7 +366,7 @@ void DMA_run (void) } void DMA_register_channel (int nchan, - DMA_transfer_handler transfer_handler, + DMA_transfer_handler transfer_handler, void *opaque) { struct dma_regs *r; @@ -375,6 +380,50 @@ void DMA_register_channel (int nchan, r->opaque = opaque; } +int DMA_read_memory (int nchan, void *buf, int pos, int len) +{ + struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3]; + target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; + + if (r->mode & 0x20) { + int i; + uint8_t *p = buf; + + cpu_physical_memory_read (addr - pos - len, buf, len); + /* What about 16bit transfers? */ + for (i = 0; i < len >> 1; i++) { + uint8_t b = p[len - i - 1]; + p[i] = b; + } + } + else + cpu_physical_memory_read (addr + pos, buf, len); + + return len; +} + +int DMA_write_memory (int nchan, void *buf, int pos, int len) +{ + struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3]; + target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; + + if (r->mode & 0x20) { + int i; + uint8_t *p = buf; + + cpu_physical_memory_write (addr - pos - len, buf, len); + /* What about 16bit transfers? */ + for (i = 0; i < len; i++) { + uint8_t b = p[len - i - 1]; + p[i] = b; + } + } + else + cpu_physical_memory_write (addr + pos, buf, len); + + return len; +} + /* request the emulator to transfer a new DMA memory block ASAP */ void DMA_schedule(int nchan) { @@ -388,7 +437,7 @@ static void dma_reset(void *opaque) } /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ -static void dma_init2(struct dma_cont *d, int base, int dshift, +static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base, int pageh_base) { const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; @@ -400,31 +449,87 @@ static void dma_init2(struct dma_cont *d, int base, int dshift, register_ioport_read (base + (i << dshift), 1, 1, read_chan, d); } for (i = 0; i < LENOFA (page_port_list); i++) { - register_ioport_write (page_base + page_port_list[i], 1, 1, + register_ioport_write (page_base + page_port_list[i], 1, 1, write_page, d); - register_ioport_read (page_base + page_port_list[i], 1, 1, + register_ioport_read (page_base + page_port_list[i], 1, 1, read_page, d); if (pageh_base >= 0) { - register_ioport_write (pageh_base + page_port_list[i], 1, 1, + register_ioport_write (pageh_base + page_port_list[i], 1, 1, write_pageh, d); - register_ioport_read (pageh_base + page_port_list[i], 1, 1, + register_ioport_read (pageh_base + page_port_list[i], 1, 1, read_pageh, d); } } for (i = 0; i < 8; i++) { - register_ioport_write (base + ((i + 8) << dshift), 1, 1, + register_ioport_write (base + ((i + 8) << dshift), 1, 1, write_cont, d); - register_ioport_read (base + ((i + 8) << dshift), 1, 1, + register_ioport_read (base + ((i + 8) << dshift), 1, 1, read_cont, d); } qemu_register_reset(dma_reset, d); dma_reset(d); } +static void dma_save (QEMUFile *f, void *opaque) +{ + struct dma_cont *d = opaque; + int i; + + /* qemu_put_8s (f, &d->status); */ + qemu_put_8s (f, &d->command); + qemu_put_8s (f, &d->mask); + qemu_put_8s (f, &d->flip_flop); + qemu_put_be32s (f, &d->dshift); + + for (i = 0; i < 4; ++i) { + struct dma_regs *r = &d->regs[i]; + qemu_put_be32s (f, &r->now[0]); + qemu_put_be32s (f, &r->now[1]); + qemu_put_be16s (f, &r->base[0]); + qemu_put_be16s (f, &r->base[1]); + qemu_put_8s (f, &r->mode); + qemu_put_8s (f, &r->page); + qemu_put_8s (f, &r->pageh); + qemu_put_8s (f, &r->dack); + qemu_put_8s (f, &r->eop); + } +} + +static int dma_load (QEMUFile *f, void *opaque, int version_id) +{ + struct dma_cont *d = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + /* qemu_get_8s (f, &d->status); */ + qemu_get_8s (f, &d->command); + qemu_get_8s (f, &d->mask); + qemu_get_8s (f, &d->flip_flop); + qemu_get_be32s (f, &d->dshift); + + for (i = 0; i < 4; ++i) { + struct dma_regs *r = &d->regs[i]; + qemu_get_be32s (f, &r->now[0]); + qemu_get_be32s (f, &r->now[1]); + qemu_get_be16s (f, &r->base[0]); + qemu_get_be16s (f, &r->base[1]); + qemu_get_8s (f, &r->mode); + qemu_get_8s (f, &r->page); + qemu_get_8s (f, &r->pageh); + qemu_get_8s (f, &r->dack); + qemu_get_8s (f, &r->eop); + } + return 0; +} + void DMA_init (int high_page_enable) { - dma_init2(&dma_controllers[0], 0x00, 0, 0x80, + dma_init2(&dma_controllers[0], 0x00, 0, 0x80, high_page_enable ? 0x480 : -1); dma_init2(&dma_controllers[1], 0xc0, 1, 0x88, high_page_enable ? 0x488 : -1); + register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]); + register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]); } diff --git a/hw/fdc.c b/hw/fdc.c index 9375b913c..d512b1ca9 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -313,7 +313,8 @@ static void fd_reset (fdrive_t *drv) static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq); static void fdctrl_reset_fifo (fdctrl_t *fdctrl); -static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size); +static int fdctrl_transfer_handler (void *opaque, int nchan, + int dma_pos, int dma_len); static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status); static void fdctrl_result_timer(void *opaque); @@ -908,7 +909,8 @@ static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction) } /* handlers for DMA transfers */ -static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) +static int fdctrl_transfer_handler (void *opaque, int nchan, + int dma_pos, int dma_len) { fdctrl_t *fdctrl; fdrive_t *cur_drv; @@ -924,8 +926,8 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL || fdctrl->data_dir == FD_DIR_SCANH) status2 = 0x04; - if (size > fdctrl->data_len) - size = fdctrl->data_len; + if (dma_len > fdctrl->data_len) + dma_len = fdctrl->data_len; if (cur_drv->bs == NULL) { if (fdctrl->data_dir == FD_DIR_WRITE) fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); @@ -935,8 +937,8 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) goto transfer_error; } rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; - for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) { - len = size - fdctrl->data_pos; + for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) { + len = dma_len - fdctrl->data_pos; if (len + rel_pos > FD_SECTOR_LEN) len = FD_SECTOR_LEN - rel_pos; FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x " @@ -958,13 +960,17 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) switch (fdctrl->data_dir) { case FD_DIR_READ: /* READ commands */ - cpu_physical_memory_write(addr + fdctrl->data_pos, - fdctrl->fifo + rel_pos, len); + DMA_write_memory (nchan, fdctrl->fifo + rel_pos, + fdctrl->data_pos, len); +/* cpu_physical_memory_write(addr + fdctrl->data_pos, */ +/* fdctrl->fifo + rel_pos, len); */ break; case FD_DIR_WRITE: /* WRITE commands */ - cpu_physical_memory_read(addr + fdctrl->data_pos, - fdctrl->fifo + rel_pos, len); + DMA_read_memory (nchan, fdctrl->fifo + rel_pos, + fdctrl->data_pos, len); +/* cpu_physical_memory_read(addr + fdctrl->data_pos, */ +/* fdctrl->fifo + rel_pos, len); */ if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); @@ -977,8 +983,9 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) { uint8_t tmpbuf[FD_SECTOR_LEN]; int ret; - cpu_physical_memory_read(addr + fdctrl->data_pos, - tmpbuf, len); + DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len); +/* cpu_physical_memory_read(addr + fdctrl->data_pos, */ +/* tmpbuf, len); */ ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len); if (ret == 0) { status2 = 0x08; diff --git a/hw/fmopl.c b/hw/fmopl.c new file mode 100644 index 000000000..2b0e82b0c --- /dev/null +++ b/hw/fmopl.c @@ -0,0 +1,1390 @@ +/* +** +** File: fmopl.c -- software implementation of FM sound generator +** +** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development +** +** Version 0.37a +** +*/ + +/* + preliminary : + Problem : + note: +*/ + +/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL. + * + * 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.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define INLINE __inline +#define HAS_YM3812 1 + +#include +#include +#include +#include +#include +//#include "driver.h" /* use M.A.M.E. */ +#include "fmopl.h" + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +/* -------------------- for debug --------------------- */ +/* #define OPL_OUTPUT_LOG */ +#ifdef OPL_OUTPUT_LOG +static FILE *opl_dbg_fp = NULL; +static FM_OPL *opl_dbg_opl[16]; +static int opl_dbg_maxchip,opl_dbg_chip; +#endif + +/* -------------------- preliminary define section --------------------- */ +/* attack/decay rate time rate */ +#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */ +#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */ + +#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */ + +#define FREQ_BITS 24 /* frequency turn */ + +/* counter bits = 20 , octerve 7 */ +#define FREQ_RATE (1<<(FREQ_BITS-20)) +#define TL_BITS (FREQ_BITS+2) + +/* final output shift , limit minimum and maximum */ +#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */ +#define OPL_MAXOUT (0x7fff<=LOG_LEVEL ) logerror x +#define LOG(n,x) + +/* --------------------- subroutines --------------------- */ + +INLINE int Limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + +/* status set and IRQ handling */ +INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) +{ + /* set status flag */ + OPL->status |= flag; + if(!(OPL->status & 0x80)) + { + if(OPL->status & OPL->statusmask) + { /* IRQ on */ + OPL->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) +{ + /* reset status flag */ + OPL->status &=~flag; + if((OPL->status & 0x80)) + { + if (!(OPL->status & OPL->statusmask) ) + { + OPL->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); + } + } +} + +/* IRQ mask set */ +INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) +{ + OPL->statusmask = flag; + /* IRQ handling check */ + OPL_STATUS_SET(OPL,0); + OPL_STATUS_RESET(OPL,0); +} + +/* ----- key on ----- */ +INLINE void OPL_KEYON(OPL_SLOT *SLOT) +{ + /* sin wave restart */ + SLOT->Cnt = 0; + /* set attack */ + SLOT->evm = ENV_MOD_AR; + SLOT->evs = SLOT->evsa; + SLOT->evc = EG_AST; + SLOT->eve = EG_AED; +} +/* ----- key off ----- */ +INLINE void OPL_KEYOFF(OPL_SLOT *SLOT) +{ + if( SLOT->evm > ENV_MOD_RR) + { + /* set envelope counter from envleope output */ + SLOT->evm = ENV_MOD_RR; + if( !(SLOT->evc&EG_DST) ) + //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<evc = EG_DST; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->evsr; + } +} + +/* ---------- calcrate Envelope Generator & Phase Generator ---------- */ +/* return : envelope output */ +INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) +{ + /* calcrate envelope generator */ + if( (SLOT->evc+=SLOT->evs) >= SLOT->eve ) + { + switch( SLOT->evm ){ + case ENV_MOD_AR: /* ATTACK -> DECAY1 */ + /* next DR */ + SLOT->evm = ENV_MOD_DR; + SLOT->evc = EG_DST; + SLOT->eve = SLOT->SL; + SLOT->evs = SLOT->evsd; + break; + case ENV_MOD_DR: /* DECAY -> SL or RR */ + SLOT->evc = SLOT->SL; + SLOT->eve = EG_DED; + if(SLOT->eg_typ) + { + SLOT->evs = 0; + } + else + { + SLOT->evm = ENV_MOD_RR; + SLOT->evs = SLOT->evsr; + } + break; + case ENV_MOD_RR: /* RR -> OFF */ + SLOT->evc = EG_OFF; + SLOT->eve = EG_OFF+1; + SLOT->evs = 0; + break; + } + } + /* calcrate envelope */ + return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0); +} + +/* set algorythm connection */ +static void set_algorythm( OPL_CH *CH) +{ + INT32 *carrier = &outd[0]; + CH->connect1 = CH->CON ? carrier : &feedback2; + CH->connect2 = carrier; +} + +/* ---------- frequency counter for operater update ---------- */ +INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) +{ + int ksr; + + /* frequency step counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + /* attack , decay rate recalcration */ + SLOT->evsa = SLOT->AR[ksr]; + SLOT->evsd = SLOT->DR[ksr]; + SLOT->evsr = SLOT->RR[ksr]; + } + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = MUL_TABLE[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_typ = (v&0x20)>>5; + SLOT->vib = (v&0x40); + SLOT->ams = (v&0x80); + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl & tl */ +INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TL = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */ + + if( !(OPL->mode&0x80) ) + { /* not CSM latch total level */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ar = v>>4; + int dr = v&0x0f; + + SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0; + SLOT->evsa = SLOT->AR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa; + + SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0; + SLOT->evsd = SLOT->DR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int sl = v>>4; + int rr = v & 0x0f; + + SLOT->SL = SL_TABLE[sl]; + if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL; + SLOT->RR = &OPL->DR_TABLE[rr<<2]; + SLOT->evsr = SLOT->RR[SLOT->ksr]; + if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr; +} + +/* operator output calcrator */ +#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env] +/* ---------- calcrate one of channel ---------- */ +INLINE void OPL_CALC_CH( OPL_CH *CH ) +{ + UINT32 env_out; + OPL_SLOT *SLOT; + + feedback2 = 0; + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + if(CH->FB) + { + int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; + CH->op1_out[1] = CH->op1_out[0]; + *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1); + } + else + { + *CH->connect1 += OP_OUT(SLOT,env_out,0); + } + }else + { + CH->op1_out[1] = CH->op1_out[0]; + CH->op1_out[0] = 0; + } + /* SLOT 2 */ + SLOT = &CH->SLOT[SLOT2]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + outd[0] += OP_OUT(SLOT,env_out, feedback2); + } +} + +/* ---------- calcrate rythm block ---------- */ +#define WHITE_NOISE_db 6.0 +INLINE void OPL_CALC_RH( OPL_CH *CH ) +{ + UINT32 env_tam,env_sd,env_top,env_hh; + int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); + INT32 tone8; + + OPL_SLOT *SLOT; + int env_out; + + /* BD : same as FM serial mode and output level is large */ + feedback2 = 0; + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + if(CH[6].FB) + { + int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB; + CH[6].op1_out[1] = CH[6].op1_out[0]; + feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1); + } + else + { + feedback2 = OP_OUT(SLOT,env_out,0); + } + }else + { + feedback2 = 0; + CH[6].op1_out[1] = CH[6].op1_out[0]; + CH[6].op1_out[0] = 0; + } + /* SLOT 2 */ + SLOT = &CH[6].SLOT[SLOT2]; + env_out=OPL_CALC_SLOT(SLOT); + if( env_out < EG_ENT-1 ) + { + /* PG */ + if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); + else SLOT->Cnt += SLOT->Incr; + /* connectoion */ + outd[0] += OP_OUT(SLOT,env_out, feedback2)*2; + } + + // SD (17) = mul14[fnum7] + white noise + // TAM (15) = mul15[fnum8] + // TOP (18) = fnum6(mul18[fnum8]+whitenoise) + // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise + env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise; + env_tam=OPL_CALC_SLOT(SLOT8_1); + env_top=OPL_CALC_SLOT(SLOT8_2); + env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise; + + /* PG */ + if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE); + else SLOT7_1->Cnt += 2*SLOT7_1->Incr; + if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE); + else SLOT7_2->Cnt += (CH[7].fc*8); + if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE); + else SLOT8_1->Cnt += SLOT8_1->Incr; + if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE); + else SLOT8_2->Cnt += (CH[8].fc*48); + + tone8 = OP_OUT(SLOT8_2,whitenoise,0 ); + + /* SD */ + if( env_sd < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8; + /* TAM */ + if( env_tam < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2; + /* TOP-CY */ + if( env_top < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2; + /* HH */ + if( env_hh < EG_ENT-1 ) + outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2; +} + +/* ----------- initialize time tabls ----------- */ +static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ) +{ + int i; + double rate; + + /* make attack rate & decay rate tables */ + for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0; + for (i = 4;i <= 60;i++){ + rate = OPL->freqbase; /* frequency rate */ + if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ + rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ + rate *= (double)(EG_ENT<AR_TABLE[i] = rate / ARRATE; + OPL->DR_TABLE[i] = rate / DRRATE; + } + for (i = 60;i < 76;i++) + { + OPL->AR_TABLE[i] = EG_AED-1; + OPL->DR_TABLE[i] = OPL->DR_TABLE[60]; + } +#if 0 + for (i = 0;i < 64 ;i++){ /* make for overflow area */ + LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i, + ((double)(EG_ENT<AR_TABLE[i]) * (1000.0 / OPL->rate), + ((double)(EG_ENT<DR_TABLE[i]) * (1000.0 / OPL->rate) )); + } +#endif +} + +/* ---------- generic table initialize ---------- */ +static int OPLOpenTable( void ) +{ + int s,t; + double rate; + int i,j; + double pom; + + /* allocate dynamic tables */ + if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL) + return 0; + if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL) + { + free(TL_TABLE); + return 0; + } + if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL) + { + free(TL_TABLE); + free(SIN_TABLE); + return 0; + } + if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL) + { + free(TL_TABLE); + free(SIN_TABLE); + free(AMS_TABLE); + return 0; + } + /* make total level table */ + for (t = 0;t < EG_ENT-1 ;t++){ + rate = ((1< voltage */ + TL_TABLE[ t] = (int)rate; + TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; +/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/ + } + /* fill volume off area */ + for ( t = EG_ENT-1; t < TL_MAX ;t++){ + TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0; + } + + /* make sinwave table (total level offet) */ + /* degree 0 = degree 180 = off */ + SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1]; + for (s = 1;s <= SIN_ENT/4;s++){ + pom = sin(2*PI*s/SIN_ENT); /* sin */ + pom = 20*log10(1/pom); /* decibel */ + j = pom / EG_STEP; /* TL_TABLE steps */ + + /* degree 0 - 90 , degree 180 - 90 : plus section */ + SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; + /* degree 180 - 270 , degree 360 - 270 : minus section */ + SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; +/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/ + } + for (s = 0;s < SIN_ENT;s++) + { + SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; + SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)]; + SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s]; + } + + /* envelope counter -> envelope output table */ + for (i=0; i= EG_ENT ) pom = EG_ENT-1; */ + ENV_CURVE[i] = (int)pom; + /* DECAY ,RELEASE curve */ + ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; + } + /* off */ + ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; + /* make LFO ams table */ + for (i=0; iSLOT[SLOT1]; + OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; + /* all key off */ + OPL_KEYOFF(slot1); + OPL_KEYOFF(slot2); + /* total level latch */ + slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); + slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); + /* key on */ + CH->op1_out[0] = CH->op1_out[1] = 0; + OPL_KEYON(slot1); + OPL_KEYON(slot2); +} + +/* ---------- opl initialize ---------- */ +static void OPL_initalize(FM_OPL *OPL) +{ + int fn; + + /* frequency base */ + OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; + /* Timer base time */ + OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 ); + /* make time tables */ + init_timetables( OPL , OPL_ARRATE , OPL_DRRATE ); + /* make fnumber -> increment counter table */ + for( fn=0 ; fn < 1024 ; fn++ ) + { + OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2; + } + /* LFO freq.table */ + OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<rate * 3.7 * ((double)OPL->clock/3600000) : 0; + OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<rate * 6.4 * ((double)OPL->clock/3600000) : 0; +} + +/* ---------- write a OPL registers ---------- */ +static void OPLWriteReg(FM_OPL *OPL, int r, int v) +{ + OPL_CH *CH; + int slot; + int block_fnum; + + switch(r&0xe0) + { + case 0x00: /* 00-1f:controll */ + switch(r&0x1f) + { + case 0x01: + /* wave selector enable */ + if(OPL->type&OPL_TYPE_WAVESEL) + { + OPL->wavesel = v&0x20; + if(!OPL->wavesel) + { + /* preset compatible mode */ + int c; + for(c=0;cmax_ch;c++) + { + OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; + OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; + } + } + } + return; + case 0x02: /* Timer 1 */ + OPL->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + OPL->T[1] = (256-v)*16; + return; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flag clear */ + OPL_STATUS_RESET(OPL,0x7f); + } + else + { /* set IRQ mask ,timer enable*/ + UINT8 st1 = v&1; + UINT8 st2 = (v>>1)&1; + /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ + OPL_STATUS_RESET(OPL,v&0x78); + OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); + /* timer 2 */ + if(OPL->st[1] != st2) + { + double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; + OPL->st[1] = st2; + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); + } + /* timer 1 */ + if(OPL->st[0] != st1) + { + double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; + OPL->st[0] = st1; + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); + } + } + return; +#if BUILD_Y8950 + case 0x06: /* Key Board OUT */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_w) + OPL->keyboardhandler_w(OPL->keyboard_param,v); + else + LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n")); + } + return; + case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + return; + case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ + OPL->mode = v; + v&=0x1f; /* for DELTA-T unit */ + case 0x09: /* START ADD */ + case 0x0a: + case 0x0b: /* STOP ADD */ + case 0x0c: + case 0x0d: /* PRESCALE */ + case 0x0e: + case 0x0f: /* ADPCM data */ + case 0x10: /* DELTA-N */ + case 0x11: /* DELTA-N */ + case 0x12: /* EG-CTRL */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + return; +#if 0 + case 0x15: /* DAC data */ + case 0x16: + case 0x17: /* SHIFT */ + return; + case 0x18: /* I/O CTRL (Direction) */ + if(OPL->type&OPL_TYPE_IO) + OPL->portDirection = v&0x0f; + return; + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + OPL->portLatch = v; + if(OPL->porthandler_w) + OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); + } + return; + case 0x1a: /* PCM data */ + return; +#endif +#endif + } + break; + case 0x20: /* am,vib,ksr,eg type,mul */ + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_mul(OPL,slot,v); + return; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_ksl_tl(OPL,slot,v); + return; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_ar_dr(OPL,slot,v); + return; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot == -1) return; + set_sl_rr(OPL,slot,v); + return; + case 0xa0: + switch(r) + { + case 0xbd: + /* amsep,vibdep,r,bd,sd,tom,tc,hh */ + { + UINT8 rkey = OPL->rythm^v; + OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; + OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; + OPL->rythm = v&0x3f; + if(OPL->rythm&0x20) + { +#if 0 + usrintf_showmessage("OPL Rythm mode select"); +#endif + /* BD key on/off */ + if(rkey&0x10) + { + if(v&0x10) + { + OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; + OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]); + OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]); + } + else + { + OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]); + OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]); + } + } + /* SD key on/off */ + if(rkey&0x08) + { + if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); + else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); + }/* TAM key on/off */ + if(rkey&0x04) + { + if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); + else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]); + } + /* TOP-CY key on/off */ + if(rkey&0x02) + { + if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); + else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); + } + /* HH key on/off */ + if(rkey&0x01) + { + if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); + else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); + } + } + } + return; + } + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + int keyon = (v>>5)&1; + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + if(CH->keyon != keyon) + { + if( (CH->keyon=keyon) ) + { + CH->op1_out[0] = CH->op1_out[1] = 0; + OPL_KEYON(&CH->SLOT[SLOT1]); + OPL_KEYON(&CH->SLOT[SLOT2]); + } + else + { + OPL_KEYOFF(&CH->SLOT[SLOT1]); + OPL_KEYOFF(&CH->SLOT[SLOT2]); + } + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + int blockRv = 7-(block_fnum>>10); + int fnum = block_fnum&0x3ff; + CH->block_fnum = block_fnum; + + CH->ksl_base = KSL_TABLE[block_fnum>>6]; + CH->fc = OPL->FN_TABLE[fnum]>>blockRv; + CH->kcode = CH->block_fnum>>9; + if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1; + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + return; + case 0xc0: + /* FB,C */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + { + int feedback = (v>>1)&7; + CH->FB = feedback ? (8+1) - feedback : 0; + CH->CON = v&1; + set_algorythm(CH); + } + return; + case 0xe0: /* wave type */ + slot = slot_array[r&0x1f]; + if(slot == -1) return; + CH = &OPL->P_CH[slot/2]; + if(OPL->wavesel) + { + /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */ + CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT]; + } + return; + } +} + +/* lock/unlock for common table */ +static int OPL_LockTable(void) +{ + num_lock++; + if(num_lock>1) return 0; + /* first time */ + cur_chip = NULL; + /* allocate total level table (128kb space) */ + if( !OPLOpenTable() ) + { + num_lock--; + return -1; + } + return 0; +} + +static void OPL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + /* last time */ + cur_chip = NULL; + OPLCloseTable(); +} + +#if (BUILD_YM3812 || BUILD_YM3526) +/*******************************************************************************/ +/* YM3812 local section */ +/*******************************************************************************/ + +/* ---------- update one of chip ----------- */ +void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) +{ + int i; + int data; + OPLSAMPLE *buf = buffer; + UINT32 amsCnt = OPL->amsCnt; + UINT32 vibCnt = OPL->vibCnt; + UINT8 rythm = OPL->rythm&0x20; + OPL_CH *CH,*R_CH; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* channel pointers */ + S_CH = OPL->P_CH; + E_CH = &S_CH[9]; + /* rythm slot */ + SLOT7_1 = &S_CH[7].SLOT[SLOT1]; + SLOT7_2 = &S_CH[7].SLOT[SLOT2]; + SLOT8_1 = &S_CH[8].SLOT[SLOT1]; + SLOT8_2 = &S_CH[8].SLOT[SLOT2]; + /* LFO state */ + amsIncr = OPL->amsIncr; + vibIncr = OPL->vibIncr; + ams_table = OPL->ams_table; + vib_table = OPL->vib_table; + } + R_CH = rythm ? &S_CH[6] : E_CH; + for( i=0; i < length ; i++ ) + { + /* channel A channel B channel C */ + /* LFO */ + ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; + vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; + outd[0] = 0; + /* FM part */ + for(CH=S_CH ; CH < R_CH ; CH++) + OPL_CALC_CH(CH); + /* Rythn part */ + if(rythm) + OPL_CALC_RH(S_CH); + /* limit check */ + data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); + /* store to sound buffer */ + buf[i] = data >> OPL_OUTSB; + } + + OPL->amsCnt = amsCnt; + OPL->vibCnt = vibCnt; +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + for(opl_dbg_chip=0;opl_dbg_chipamsCnt; + UINT32 vibCnt = OPL->vibCnt; + UINT8 rythm = OPL->rythm&0x20; + OPL_CH *CH,*R_CH; + YM_DELTAT *DELTAT = OPL->deltat; + + /* setup DELTA-T unit */ + YM_DELTAT_DECODE_PRESET(DELTAT); + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* channel pointers */ + S_CH = OPL->P_CH; + E_CH = &S_CH[9]; + /* rythm slot */ + SLOT7_1 = &S_CH[7].SLOT[SLOT1]; + SLOT7_2 = &S_CH[7].SLOT[SLOT2]; + SLOT8_1 = &S_CH[8].SLOT[SLOT1]; + SLOT8_2 = &S_CH[8].SLOT[SLOT2]; + /* LFO state */ + amsIncr = OPL->amsIncr; + vibIncr = OPL->vibIncr; + ams_table = OPL->ams_table; + vib_table = OPL->vib_table; + } + R_CH = rythm ? &S_CH[6] : E_CH; + for( i=0; i < length ; i++ ) + { + /* channel A channel B channel C */ + /* LFO */ + ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; + vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; + outd[0] = 0; + /* deltaT ADPCM */ + if( DELTAT->portstate ) + YM_DELTAT_ADPCM_CALC(DELTAT); + /* FM part */ + for(CH=S_CH ; CH < R_CH ; CH++) + OPL_CALC_CH(CH); + /* Rythn part */ + if(rythm) + OPL_CALC_RH(S_CH); + /* limit check */ + data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); + /* store to sound buffer */ + buf[i] = data >> OPL_OUTSB; + } + OPL->amsCnt = amsCnt; + OPL->vibCnt = vibCnt; + /* deltaT START flag */ + if( !DELTAT->portstate ) + OPL->status &= 0xfe; +} +#endif + +/* ---------- reset one of chip ---------- */ +void OPLResetChip(FM_OPL *OPL) +{ + int c,s; + int i; + + /* reset chip */ + OPL->mode = 0; /* normal mode */ + OPL_STATUS_RESET(OPL,0x7f); + /* reset with register write */ + OPLWriteReg(OPL,0x01,0); /* wabesel disable */ + OPLWriteReg(OPL,0x02,0); /* Timer1 */ + OPLWriteReg(OPL,0x03,0); /* Timer2 */ + OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + /* reset OPerator paramater */ + for( c = 0 ; c < OPL->max_ch ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + /* OPL->P_CH[c].PAN = OPN_CENTER; */ + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = &SIN_TABLE[0]; + /* CH->SLOT[s].evm = ENV_MOD_RR; */ + CH->SLOT[s].evc = EG_OFF; + CH->SLOT[s].eve = EG_OFF+1; + CH->SLOT[s].evs = 0; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = outd; + DELTAT->portshift = 5; + DELTAT->output_range = DELTAT_MIXING_LEVEL<P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch; +#if BUILD_Y8950 + if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT); +#endif + /* set channel state pointer */ + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + OPL->max_ch = max_ch; + /* init grobal tables */ + OPL_initalize(OPL); + /* reset chip */ + OPLResetChip(OPL); +#ifdef OPL_OUTPUT_LOG + if(!opl_dbg_fp) + { + opl_dbg_fp = fopen("opllog.opl","wb"); + opl_dbg_maxchip = 0; + } + if(opl_dbg_fp) + { + opl_dbg_opl[opl_dbg_maxchip] = OPL; + fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip, + type, + clock&0xff, + (clock/0x100)&0xff, + (clock/0x10000)&0xff, + (clock/0x1000000)&0xff); + opl_dbg_maxchip++; + } +#endif + return OPL; +} + +/* ---------- Destroy one of vietual YM3812 ---------- */ +void OPLDestroy(FM_OPL *OPL) +{ +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + fclose(opl_dbg_fp); + opl_dbg_fp = NULL; + } +#endif + OPL_UnLockTable(); + free(OPL); +} + +/* ---------- Option handlers ---------- */ + +void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) +{ + OPL->TimerHandler = TimerHandler; + OPL->TimerParam = channelOffset; +} +void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} +#if BUILD_Y8950 +void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) +{ + OPL->porthandler_w = PortHandler_w; + OPL->porthandler_r = PortHandler_r; + OPL->port_param = param; +} + +void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) +{ + OPL->keyboardhandler_w = KeyboardHandler_w; + OPL->keyboardhandler_r = KeyboardHandler_r; + OPL->keyboard_param = param; +} +#endif +/* ---------- YM3812 I/O interface ---------- */ +int OPLWrite(FM_OPL *OPL,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + OPL->address = v & 0xff; + } + else + { /* data port */ + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); +#ifdef OPL_OUTPUT_LOG + if(opl_dbg_fp) + { + for(opl_dbg_chip=0;opl_dbg_chipaddress,v); + } +#endif + OPLWriteReg(OPL,OPL->address,v); + } + return OPL->status>>7; +} + +unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { /* status port */ + return OPL->status & (OPL->statusmask|0x80); + } + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); + else + LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); + } + return 0; +#if 0 + case 0x0f: /* ADPCM-DATA */ + return 0; +#endif + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); + else + LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); + } + return 0; + case 0x1a: /* PCM-DATA */ + return 0; + } + return 0; +} + +int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + else + { /* Timer A */ + OPL_STATUS_SET(OPL,0x40); + /* CSM mode key,TL controll */ + if( OPL->mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + for(ch=0;ch<9;ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); + return OPL->status>>7; +} diff --git a/hw/fmopl.h b/hw/fmopl.h new file mode 100644 index 000000000..a01ff902c --- /dev/null +++ b/hw/fmopl.h @@ -0,0 +1,174 @@ +#ifndef __FMOPL_H_ +#define __FMOPL_H_ + +/* --- select emulation chips --- */ +#define BUILD_YM3812 (HAS_YM3812) +//#define BUILD_YM3526 (HAS_YM3526) +//#define BUILD_Y8950 (HAS_Y8950) + +/* --- system optimize --- */ +/* select bit size of output : 8 or 16 */ +#define OPL_OUTPUT_BIT 16 + +/* compiler dependence */ +#ifndef OSD_CPU_H +#define OSD_CPU_H +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +#if (OPL_OUTPUT_BIT==16) +typedef INT16 OPLSAMPLE; +#endif +#if (OPL_OUTPUT_BIT==8) +typedef unsigned char OPLSAMPLE; +#endif + + +#if BUILD_Y8950 +#include "ymdeltat.h" +#endif + +typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); +typedef void (*OPL_IRQHANDLER)(int param,int irq); +typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); +typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); +typedef unsigned char (*OPL_PORTHANDLER_R)(int param); + +/* !!!!! here is private section , do not access there member direct !!!!! */ + +#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ +#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ +#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ +#define OPL_TYPE_IO 0x08 /* I/O port */ + +/* Saving is necessary for member of the 'R' mark for suspend/resume */ +/* ---------- OPL one of slot ---------- */ +typedef struct fm_opl_slot { + INT32 TL; /* total level :TL << 8 */ + INT32 TLL; /* adjusted now TL */ + UINT8 KSR; /* key scale rate :(shift down bit) */ + INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */ + INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */ + INT32 SL; /* sustin level :SL_TALBE[SL] */ + INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */ + UINT8 ksl; /* keyscale level :(shift down bits) */ + UINT8 ksr; /* key scale rate :kcode>>KSR */ + UINT32 mul; /* multiple :ML_TABLE[ML] */ + UINT32 Cnt; /* frequency count : */ + UINT32 Incr; /* frequency step : */ + /* envelope generator state */ + UINT8 eg_typ; /* envelope type flag */ + UINT8 evm; /* envelope phase */ + INT32 evc; /* envelope counter */ + INT32 eve; /* envelope counter end point */ + INT32 evs; /* envelope counter step */ + INT32 evsa; /* envelope step for AR :AR[ksr] */ + INT32 evsd; /* envelope step for DR :DR[ksr] */ + INT32 evsr; /* envelope step for RR :RR[ksr] */ + /* LFO */ + UINT8 ams; /* ams flag */ + UINT8 vib; /* vibrate flag */ + /* wave selector */ + INT32 **wavetable; +}OPL_SLOT; + +/* ---------- OPL one of channel ---------- */ +typedef struct fm_opl_channel { + OPL_SLOT SLOT[2]; + UINT8 CON; /* connection type */ + UINT8 FB; /* feed back :(shift down bit) */ + INT32 *connect1; /* slot1 output pointer */ + INT32 *connect2; /* slot2 output pointer */ + INT32 op1_out[2]; /* slot1 output for selfeedback */ + /* phase generator state */ + UINT32 block_fnum; /* block+fnum : */ + UINT8 kcode; /* key code : KeyScaleCode */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 keyon; /* key on/off flag */ +} OPL_CH; + +/* OPL state */ +typedef struct fm_opl_f { + UINT8 type; /* chip type */ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + double TimerBase; /* Timer base time (==sampling time) */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT32 mode; /* Reg.08 : CSM , notesel,etc. */ + /* Timer */ + int T[2]; /* timer counter */ + UINT8 st[2]; /* timer enable */ + /* FM channel slots */ + OPL_CH *P_CH; /* pointer of CH */ + int max_ch; /* maximum channel */ + /* Rythm sention */ + UINT8 rythm; /* Rythm mode , key flag */ +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + YM_DELTAT *deltat; /* DELTA-T ADPCM */ +#endif + /* Keyboard / I/O interface unit (Y8950) */ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + int port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + int keyboard_param; + /* time tables */ + INT32 AR_TABLE[75]; /* atttack rate tables */ + INT32 DR_TABLE[75]; /* decay rate tables */ + UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */ + /* LFO */ + INT32 *ams_table; + INT32 *vib_table; + INT32 amsCnt; + INT32 amsIncr; + INT32 vibCnt; + INT32 vibIncr; + /* wave selector enable flag */ + UINT8 wavesel; + /* external event callback handler */ + OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ + int TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + int IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ + int UpdateParam; /* stream update parameter */ +} FM_OPL; + +/* ---------- Generic interface section ---------- */ +#define OPL_TYPE_YM3526 (0) +#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) +#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) + +FM_OPL *OPLCreate(int type, int clock, int rate); +void OPLDestroy(FM_OPL *OPL); +void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset); +void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param); +void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param); +/* Y8950 port handlers */ +void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param); +void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param); + +void OPLResetChip(FM_OPL *OPL); +int OPLWrite(FM_OPL *OPL,int a,int v); +unsigned char OPLRead(FM_OPL *OPL,int a); +int OPLTimerOver(FM_OPL *OPL,int c); + +/* YM3626/YM3812 local section */ +void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); + +void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); + +#endif diff --git a/hw/pc.c b/hw/pc.c index cddd13618..fbcd96980 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -554,13 +554,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, kbd_init(); DMA_init(0); -#ifndef _WIN32 if (audio_enabled) { /* no audio supported yet for win32 */ AUD_init(); - SB16_init(); } -#endif floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); diff --git a/hw/sb16.c b/hw/sb16.c index f84cf8d4a..d9320566a 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -1,7 +1,7 @@ /* * QEMU Soundblaster 16 emulation * - * Copyright (c) 2003 Vassili Karpov (malc) + * Copyright (c) 2003-2004 Vassili Karpov (malc) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,32 +23,20 @@ */ #include "vl.h" -#define MIN(a, b) ((a)>(b)?(b):(a)) -#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) - -#define dolog(...) fprintf (stderr, "sb16: " __VA_ARGS__); +/* #define DEBUG */ +#define AUDIO_CAP "sb16" +#include "audio/audio.h" -/* #define DEBUG_SB16 */ +#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) -#ifdef DEBUG_SB16 -#define lwarn(...) fprintf (stderr, "sb16: " __VA_ARGS__) -#define linfo(...) fprintf (stderr, "sb16: " __VA_ARGS__) -#define ldebug(...) fprintf (stderr, "sb16: " __VA_ARGS__) -#else -#define lwarn(...) -#define linfo(...) -#define ldebug(...) -#endif +/* #define DEBUG_SB16_MOST */ -#define IO_READ_PROTO(name) \ +#define IO_READ_PROTO(name) \ uint32_t name (void *opaque, uint32_t nport) -#define IO_WRITE_PROTO(name) \ +#define IO_WRITE_PROTO(name) \ void name (void *opaque, uint32_t nport, uint32_t val) -static const char e3[] = - "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992\0" - "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1994-1997"; - /* "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1994."; */ +static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; static struct { int ver_lo; @@ -57,38 +45,58 @@ static struct { int dma; int hdma; int port; - int mix_block; -} sb = {5, 4, 5, 1, 5, 0x220, -1}; - -static int mix_block, noirq; +} conf = {5, 4, 5, 1, 5, 0x220}; typedef struct SB16State { + int irq; + int dma; + int hdma; + int port; + int ver; + int in_index; int out_data_len; int fmt_stereo; int fmt_signed; int fmt_bits; + audfmt_e fmt; int dma_auto; - int dma_buffer_size; + int block_size; int fifo; int freq; int time_const; int speaker; int needed_bytes; int cmd; - int dma_pos; int use_hdma; + int highspeed; + int can_write; int v2x6; + uint8_t csp_param; + uint8_t csp_value; + uint8_t csp_mode; + uint8_t csp_regs[256]; + uint8_t csp_index; + uint8_t csp_reg83[4]; + int csp_reg83r; + int csp_reg83w; + uint8_t in2_data[10]; - uint8_t out_data[1024]; + uint8_t out_data[50]; + uint8_t test_reg; + uint8_t last_read_byte; + int nzero; int left_till_irq; - uint64_t nzero; - uint8_t last_read_byte; - uint8_t test_reg; + int dma_running; + int bytes_per_second; + int align; + SWVoice *voice; + + QEMUTimer *ts, *aux_ts; /* mixer state */ int mixer_nreg; uint8_t mixer_regs[256]; @@ -97,664 +105,853 @@ typedef struct SB16State { /* XXX: suppress that and use a context */ static struct SB16State dsp; +static int magic_of_irq (int irq) +{ + switch (irq) { + case 5: + return 2; + case 7: + return 4; + case 9: + return 1; + case 10: + return 8; + default: + dolog ("bad irq %d\n", irq); + return 2; + } +} + +static int irq_of_magic (int magic) +{ + switch (magic) { + case 1: + return 9; + case 2: + return 5; + case 4: + return 7; + case 8: + return 10; + default: + dolog ("bad irq magic %d\n", magic); + return -1; + } +} + +#if 0 static void log_dsp (SB16State *dsp) { - ldebug ("%c:%c:%d:%c:dmabuf=%d:pos=%d:freq=%d:timeconst=%d:speaker=%d\n", - dsp->fmt_stereo ? 'S' : 'M', - dsp->fmt_signed ? 'S' : 'U', - dsp->fmt_bits, - dsp->dma_auto ? 'a' : 's', - dsp->dma_buffer_size, - dsp->dma_pos, - dsp->freq, - dsp->time_const, - dsp->speaker); + ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n", + dsp->fmt_stereo ? "Stereo" : "Mono", + dsp->fmt_signed ? "Signed" : "Unsigned", + dsp->fmt_bits, + dsp->dma_auto ? "Auto" : "Single", + dsp->block_size, + dsp->freq, + dsp->time_const, + dsp->speaker); +} +#endif + +static void speaker (SB16State *s, int on) +{ + s->speaker = on; + /* AUD_enable (s->voice, on); */ } -static void control (int hold) +static void control (SB16State *s, int hold) { - linfo ("%d high %d\n", hold, dsp.use_hdma); + int dma = s->use_hdma ? s->hdma : s->dma; + s->dma_running = hold; + + ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma); + if (hold) { - if (dsp.use_hdma) - DMA_hold_DREQ (sb.hdma); - else - DMA_hold_DREQ (sb.dma); + DMA_hold_DREQ (dma); + AUD_enable (s->voice, 1); } else { - if (dsp.use_hdma) - DMA_release_DREQ (sb.hdma); - else - DMA_release_DREQ (sb.dma); + DMA_release_DREQ (dma); + AUD_enable (s->voice, 0); } } -static void dma_cmd (uint8_t cmd, uint8_t d0, int dma_len) +static void aux_timer (void *opaque) { - int bps; - audfmt_e fmt; + SB16State *s = opaque; + s->can_write = 1; + pic_set_irq (s->irq, 1); +} + +#define DMA8_AUTO 1 +#define DMA8_HIGH 2 + +static void dma_cmd8 (SB16State *s, int mask, int dma_len) +{ + s->fmt = AUD_FMT_U8; + s->use_hdma = 0; + s->fmt_bits = 8; + s->fmt_signed = 0; + s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0; + if (-1 == s->time_const) { + s->freq = 11025; + } + else { + int tmp = (256 - s->time_const); + s->freq = (1000000 + (tmp / 2)) / tmp; + } + + if (-1 != dma_len) + s->block_size = dma_len + 1; + + s->freq >>= s->fmt_stereo; + s->left_till_irq = s->block_size; + s->bytes_per_second = (s->freq << s->fmt_stereo); + /* s->highspeed = (mask & DMA8_HIGH) != 0; */ + s->dma_auto = (mask & DMA8_AUTO) != 0; + s->align = (1 << s->fmt_stereo) - 1; + + ldebug ("freq %d, stereo %d, sign %d, bits %d, " + "dma %d, auto %d, fifo %d, high %d\n", + s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, + s->block_size, s->dma_auto, s->fifo, s->highspeed); + + if (s->freq) + s->voice = AUD_open (s->voice, "sb16", s->freq, + 1 << s->fmt_stereo, s->fmt); + + control (s, 1); + speaker (s, 1); +} - dsp.use_hdma = cmd < 0xc0; - dsp.fifo = (cmd >> 1) & 1; - dsp.dma_auto = (cmd >> 2) & 1; +static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) +{ + s->use_hdma = cmd < 0xc0; + s->fifo = (cmd >> 1) & 1; + s->dma_auto = (cmd >> 2) & 1; + s->fmt_signed = (d0 >> 4) & 1; + s->fmt_stereo = (d0 >> 5) & 1; switch (cmd >> 4) { case 11: - dsp.fmt_bits = 16; + s->fmt_bits = 16; break; case 12: - dsp.fmt_bits = 8; + s->fmt_bits = 8; break; } - dsp.fmt_signed = (d0 >> 4) & 1; - dsp.fmt_stereo = (d0 >> 5) & 1; - - if (-1 != dsp.time_const) { - int tmp; - - tmp = 256 - dsp.time_const; - dsp.freq = (1000000 + (tmp / 2)) / tmp; + if (-1 != s->time_const) { +#if 1 + int tmp = 256 - s->time_const; + s->freq = (1000000 + (tmp / 2)) / tmp; +#else + /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */ + s->freq = 1000000 / ((255 - s->time_const)); +#endif + s->time_const = -1; } - bps = 1 << (16 == dsp.fmt_bits); - if (-1 != dma_len) - dsp.dma_buffer_size = (dma_len + 1) * bps; + s->block_size = dma_len + 1; + s->block_size <<= (s->fmt_bits == 16); + if (!s->dma_auto) /* Miles Sound System ? */ + s->block_size <<= s->fmt_stereo; - linfo ("frequency %d, stereo %d, signed %d, bits %d, size %d, auto %d\n", - dsp.freq, dsp.fmt_stereo, dsp.fmt_signed, dsp.fmt_bits, - dsp.dma_buffer_size, dsp.dma_auto); + ldebug ("freq %d, stereo %d, sign %d, bits %d, " + "dma %d, auto %d, fifo %d, high %d\n", + s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, + s->block_size, s->dma_auto, s->fifo, s->highspeed); - if (16 == dsp.fmt_bits) { - if (dsp.fmt_signed) { - fmt = AUD_FMT_S16; + if (16 == s->fmt_bits) { + if (s->fmt_signed) { + s->fmt = AUD_FMT_S16; } else { - fmt = AUD_FMT_U16; + s->fmt = AUD_FMT_U16; } } else { - if (dsp.fmt_signed) { - fmt = AUD_FMT_S8; + if (s->fmt_signed) { + s->fmt = AUD_FMT_S8; } else { - fmt = AUD_FMT_U8; + s->fmt = AUD_FMT_U8; } } - dsp.dma_pos = 0; - dsp.left_till_irq = dsp.dma_buffer_size; + s->left_till_irq = s->block_size; - if (sb.mix_block) { - mix_block = sb.mix_block; - } - else { - int align; + s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16); + s->highspeed = 0; + s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1; - align = bps << dsp.fmt_stereo; - mix_block = ((dsp.freq * align) / 100) & ~(align - 1); - } + if (s->freq) + s->voice = AUD_open (s->voice, "sb16", s->freq, + 1 << s->fmt_stereo, s->fmt); - if (dsp.freq) - AUD_reset (dsp.freq, 1 << dsp.fmt_stereo, fmt); - control (1); - dsp.speaker = 1; + control (s, 1); + speaker (s, 1); } -static inline void dsp_out_data(SB16State *dsp, int val) +static inline void dsp_out_data (SB16State *s, uint8_t val) { - if (dsp->out_data_len < sizeof(dsp->out_data)) - dsp->out_data[dsp->out_data_len++] = val; + ldebug ("outdata %#x\n", val); + if (s->out_data_len < sizeof (s->out_data)) + s->out_data[s->out_data_len++] = val; } -static inline uint8_t dsp_get_data(SB16State *dsp) +static inline uint8_t dsp_get_data (SB16State *s) { - if (dsp->in_index) - return dsp->in2_data[--dsp->in_index]; - else + if (s->in_index) + return s->in2_data[--s->in_index]; + else { + dolog ("buffer underflow\n"); return 0; + } } -static void command (SB16State *dsp, uint8_t cmd) +static void command (SB16State *s, uint8_t cmd) { - linfo ("command: %#x\n", cmd); + ldebug ("command %#x\n", cmd); if (cmd > 0xaf && cmd < 0xd0) { - if (cmd & 8) - goto error; + if (cmd & 8) { + dolog ("ADC not yet supported (command %#x)\n", cmd); + } switch (cmd >> 4) { case 11: case 12: break; default: - dolog ("command: %#x wrong bits specification\n", cmd); - goto error; + dolog ("%#x wrong bits\n", cmd); } - dsp->needed_bytes = 3; + s->needed_bytes = 3; } else { switch (cmd) { - case 0x00: - case 0xe7: - /* IMS uses those when probing for sound devices */ - return; - case 0x03: + dsp_out_data (s, 0x10); /* s->csp_param); */ + goto warn; + case 0x04: - dsp_out_data (dsp, 0); - return; + s->needed_bytes = 1; + goto warn; case 0x05: - dsp->needed_bytes = 2; - break; + s->needed_bytes = 2; + goto warn; + + case 0x08: + /* __asm__ ("int3"); */ + goto warn; case 0x0e: - dsp->needed_bytes = 2; - break; + s->needed_bytes = 2; + goto warn; + + case 0x09: + dsp_out_data (s, 0xf8); + goto warn; case 0x0f: - dsp->needed_bytes = 1; - break; + s->needed_bytes = 1; + goto warn; case 0x10: - dsp->needed_bytes = 1; - break; + s->needed_bytes = 1; + goto warn; case 0x14: - dsp->needed_bytes = 2; - dsp->dma_buffer_size = 0; + s->needed_bytes = 2; + s->block_size = 0; break; - case 0x20: - dsp_out_data(dsp, 0xff); - break; + case 0x20: /* Direct ADC, Juice/PL */ + dsp_out_data (s, 0xff); + goto warn; case 0x35: - lwarn ("MIDI commands not implemented\n"); + dolog ("MIDI command(0x35) not implemented\n"); break; case 0x40: - dsp->freq = -1; - dsp->time_const = -1; - dsp->needed_bytes = 1; + s->freq = -1; + s->time_const = -1; + s->needed_bytes = 1; break; case 0x41: - case 0x42: - dsp->freq = -1; - dsp->time_const = -1; - dsp->needed_bytes = 2; + s->freq = -1; + s->time_const = -1; + s->needed_bytes = 2; break; + case 0x42: + s->freq = -1; + s->time_const = -1; + s->needed_bytes = 2; + goto warn; + case 0x45: - dsp_out_data (dsp, 0xaa); + dsp_out_data (s, 0xaa); + goto warn; + case 0x47: /* Continue Auto-Initialize DMA 16bit */ break; case 0x48: - dsp->needed_bytes = 2; + s->needed_bytes = 2; break; - case 0x27: /* ????????? */ - case 0x4e: - return; - case 0x80: - cmd = -1; + s->needed_bytes = 2; break; case 0x90: case 0x91: - { - uint8_t d0; - - d0 = 4; - /* if (dsp->fmt_signed) d0 |= 16; */ - /* if (dsp->fmt_stereo) d0 |= 32; */ - dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1); - cmd = -1; - break; - } + dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1); + break; - case 0xd0: /* XXX */ - control (0); - return; + case 0xd0: /* halt DMA operation. 8bit */ + control (s, 0); + break; - case 0xd1: - dsp->speaker = 1; + case 0xd1: /* speaker on */ + speaker (s, 1); break; - case 0xd3: - dsp->speaker = 0; - return; + case 0xd3: /* speaker off */ + speaker (s, 0); + break; - case 0xd4: - control (1); + case 0xd4: /* continue DMA operation. 8bit */ + control (s, 1); break; - case 0xd5: - control (0); + case 0xd5: /* halt DMA operation. 16bit */ + control (s, 0); break; - case 0xd6: - control (1); + case 0xd6: /* continue DMA operation. 16bit */ + control (s, 1); break; - case 0xd9: - control (0); - dsp->dma_auto = 0; - return; + case 0xd9: /* exit auto-init DMA after this block. 16bit */ + s->dma_auto = 0; + break; - case 0xda: - control (0); - dsp->dma_auto = 0; + case 0xda: /* exit auto-init DMA after this block. 8bit */ + s->dma_auto = 0; break; case 0xe0: - dsp->needed_bytes = 1; - break; + s->needed_bytes = 1; + goto warn; case 0xe1: - dsp_out_data(dsp, sb.ver_lo); - dsp_out_data(dsp, sb.ver_hi); - return; + dsp_out_data (s, s->ver & 0xff); + dsp_out_data (s, s->ver >> 8); + break; + + case 0xe2: + s->needed_bytes = 1; + goto warn; case 0xe3: { int i; - for (i = sizeof (e3) - 1; i >= 0; i--) - dsp_out_data (dsp, e3[i]); - return; + for (i = sizeof (e3) - 1; i >= 0; --i) + dsp_out_data (s, e3[i]); } + break; case 0xe4: /* write test reg */ - dsp->needed_bytes = 1; + s->needed_bytes = 1; break; + case 0xe7: + dolog ("Attempt to probe for ESS (0xe7)?\n"); + return; + case 0xe8: /* read test reg */ - dsp_out_data (dsp, dsp->test_reg); + dsp_out_data (s, s->test_reg); break; case 0xf2: - dsp_out_data (dsp, 0xaa); - dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; - pic_set_irq (sb.irq, 1); - return; + case 0xf3: + dsp_out_data (s, 0xaa); + s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2; + pic_set_irq (s->irq, 1); + break; case 0xf9: - dsp->needed_bytes = 1; - break; + s->needed_bytes = 1; + goto warn; case 0xfa: - dsp_out_data (dsp, 0); - break; + dsp_out_data (s, 0); + goto warn; case 0xfc: /* FIXME */ - dsp_out_data (dsp, 0); - break; + dsp_out_data (s, 0); + goto warn; default: dolog ("unrecognized command %#x\n", cmd); - goto error; + return; } } - dsp->cmd = cmd; + + s->cmd = cmd; + if (!s->needed_bytes) + ldebug ("\n"); return; - error: + warn: + dolog ("warning command %#x,%d is not trully understood yet\n", + cmd, s->needed_bytes); + s->cmd = cmd; return; } -static void complete (SB16State *dsp) +static uint16_t dsp_get_lohi (SB16State *s) +{ + uint8_t hi = dsp_get_data (s); + uint8_t lo = dsp_get_data (s); + return (hi << 8) | lo; +} + +static uint16_t dsp_get_hilo (SB16State *s) +{ + uint8_t lo = dsp_get_data (s); + uint8_t hi = dsp_get_data (s); + return (hi << 8) | lo; +} + +static void complete (SB16State *s) { int d0, d1, d2; - linfo ("complete command %#x, in_index %d, needed_bytes %d\n", - dsp->cmd, dsp->in_index, dsp->needed_bytes); + ldebug ("complete command %#x, in_index %d, needed_bytes %d\n", + s->cmd, s->in_index, s->needed_bytes); - if (dsp->cmd > 0xaf && dsp->cmd < 0xd0) { - d2 = dsp_get_data (dsp); - d1 = dsp_get_data (dsp); - d0 = dsp_get_data (dsp); + if (s->cmd > 0xaf && s->cmd < 0xd0) { + d2 = dsp_get_data (s); + d1 = dsp_get_data (s); + d0 = dsp_get_data (s); - ldebug ("d0 = %d, d1 = %d, d2 = %d\n", - d0, d1, d2); - dma_cmd (dsp->cmd, d0, d1 + (d2 << 8)); + if (s->cmd & 8) { + dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", + s->cmd, d0, d1, d2); + } + else { + ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", + s->cmd, d0, d1, d2); + dma_cmd (s, s->cmd, d0, d1 + (d2 << 8)); + } } else { - switch (dsp->cmd) { + switch (s->cmd) { case 0x04: - case 0x10: - dsp_get_data (dsp); + s->csp_mode = dsp_get_data (s); + s->csp_reg83r = 0; + s->csp_reg83w = 0; + ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode); break; - case 0x0f: - d0 = dsp_get_data (dsp); - dsp_out_data (dsp, 0xf8); + case 0x05: + s->csp_param = dsp_get_data (s); + s->csp_value = dsp_get_data (s); + ldebug ("CSP command 0x05: param=%#x value=%#x\n", + s->csp_param, + s->csp_value); break; - case 0x05: case 0x0e: - dsp_get_data (dsp); - dsp_get_data (dsp); + d0 = dsp_get_data (s); + d1 = dsp_get_data (s); + ldebug ("write CSP register %d <- %#x\n", d1, d0); + if (d1 == 0x83) { + ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0); + s->csp_reg83[s->csp_reg83r % 4] = d0; + s->csp_reg83r += 1; + } + else + s->csp_regs[d1] = d0; break; - case 0x14: - { - int save_left; - int save_pos; - - d1 = dsp_get_data (dsp); - d0 = dsp_get_data (dsp); + case 0x0f: + d0 = dsp_get_data (s); + ldebug ("read CSP register %#x -> %#x, mode=%#x\n", + d0, s->csp_regs[d0], s->csp_mode); + if (d0 == 0x83) { + ldebug ("0x83[%d] -> %#x\n", + s->csp_reg83w, + s->csp_reg83[s->csp_reg83w % 4]); + dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]); + s->csp_reg83w += 1; + } + else + dsp_out_data (s, s->csp_regs[d0]); + break; - save_left = dsp->left_till_irq; - save_pos = dsp->dma_pos; - dma_cmd (0xc0, 0, d0 + (d1 << 8)); - dsp->left_till_irq = save_left; - dsp->dma_pos = save_pos; + case 0x10: + d0 = dsp_get_data (s); + dolog ("cmd 0x10 d0=%#x\n", d0); + break; - linfo ("set buffer size data[%d, %d] %d pos %d\n", - d0, d1, dsp->dma_buffer_size, dsp->dma_pos); - break; - } + case 0x14: + dma_cmd8 (s, 0, dsp_get_lohi (s)); + /* s->can_write = 0; */ + /* qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + (ticks_per_sec * 320) / 1000000); */ + break; case 0x40: - dsp->time_const = dsp_get_data (dsp); - linfo ("set time const %d\n", dsp->time_const); + s->time_const = dsp_get_data (s); + ldebug ("set time const %d\n", s->time_const); break; - case 0x41: - case 0x42: - d1 = dsp_get_data (dsp); - d0 = dsp_get_data (dsp); + case 0x42: /* FT2 sets output freq with this, go figure */ + dolog ("cmd 0x42 might not do what it think it should\n"); - dsp->freq = d1 + (d0 << 8); - linfo ("set freq %#x, %#x = %d\n", d1, d0, dsp->freq); + case 0x41: + s->freq = dsp_get_hilo (s); + ldebug ("set freq %d\n", s->freq); break; case 0x48: - d1 = dsp_get_data (dsp); - d0 = dsp_get_data (dsp); - dsp->dma_buffer_size = d1 + (d0 << 8); - linfo ("set dma len %#x, %#x = %d\n", - d1, d0, dsp->dma_buffer_size); + s->block_size = dsp_get_lohi (s); + /* s->highspeed = 1; */ + ldebug ("set dma block len %d\n", s->block_size); + break; + + case 0x80: + { + int samples, bytes; + int64_t ticks; + + if (-1 == s->freq) + s->freq = 11025; + samples = dsp_get_lohi (s); + bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); + ticks = ticks_per_sec / (s->freq / bytes); + if (ticks < ticks_per_sec / 1024) + pic_set_irq (s->irq, 1); + else + qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + ticks); + ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks); + } break; case 0xe0: - d0 = dsp_get_data (dsp); - dsp->out_data_len = 0; - linfo ("data = %#x\n", d0); - dsp_out_data (dsp, d0 ^ 0xff); + d0 = dsp_get_data (s); + s->out_data_len = 0; + ldebug ("E0 data = %#x\n", d0); + dsp_out_data(s, ~d0); break; - case 0xe4: - dsp->test_reg = dsp_get_data (dsp); + case 0xe2: + d0 = dsp_get_data (s); + dolog ("E2 = %#x\n", d0); break; + case 0xe4: + s->test_reg = dsp_get_data (s); + break; case 0xf9: - d0 = dsp_get_data (dsp); - ldebug ("f9 <- %#x\n", d0); + d0 = dsp_get_data (s); + ldebug ("command 0xf9 with %#x\n", d0); switch (d0) { - case 0x0e: dsp_out_data (dsp, 0xff); break; - case 0x0f: dsp_out_data (dsp, 0x07); break; - case 0xf9: dsp_out_data (dsp, 0x00); break; + case 0x0e: + dsp_out_data (s, 0xff); + break; + + case 0x0f: + dsp_out_data (s, 0x07); + break; + case 0x37: - dsp_out_data (dsp, 0x38); break; + dsp_out_data (s, 0x38); + break; + default: - dsp_out_data (dsp, 0); + dsp_out_data (s, 0x00); + break; } break; default: - dolog ("complete: unrecognized command %#x\n", dsp->cmd); + dolog ("complete: unrecognized command %#x\n", s->cmd); return; } } - dsp->needed_bytes = 0; - dsp->cmd = -1; + ldebug ("\n"); + s->cmd = -1; return; } +static void reset (SB16State *s) +{ + pic_set_irq (s->irq, 0); + if (s->dma_auto) { + pic_set_irq (s->irq, 1); + pic_set_irq (s->irq, 0); + } + + s->mixer_regs[0x82] = 0; + s->dma_auto = 0; + s->in_index = 0; + s->out_data_len = 0; + s->left_till_irq = 0; + s->needed_bytes = 0; + s->block_size = -1; + s->nzero = 0; + s->highspeed = 0; + s->v2x6 = 0; + + dsp_out_data(s, 0xaa); + speaker (s, 0); + control (s, 0); +} + static IO_WRITE_PROTO (dsp_write) { - SB16State *dsp = opaque; + SB16State *s = opaque; int iport; - iport = nport - sb.port; + iport = nport - s->port; - ldebug ("dsp_write %#x <- %#x\n", nport, val); + ldebug ("write %#x <- %#x\n", nport, val); switch (iport) { - case 0x6: - control (0); - if (0 == val) - dsp->v2x6 = 0; - else if ((1 == val) && (0 == dsp->v2x6)) { - dsp->v2x6 = 1; - dsp->dma_pos = 0; - dsp->dma_auto = 0; - dsp->in_index = 0; - dsp->out_data_len = 0; - dsp->left_till_irq = 0; - dsp->speaker = 0; - dsp->needed_bytes = 0; - pic_set_irq (sb.irq, 0); - dsp_out_data(dsp, 0xaa); + case 0x06: + switch (val) { + case 0x00: + if (s->v2x6 == 1) { + if (0 && s->highspeed) { + s->highspeed = 0; + pic_set_irq (s->irq, 0); + control (s, 0); + } + else + reset (s); + } + s->v2x6 = 0; + break; + + case 0x01: + case 0x03: /* FreeBSD kludge */ + s->v2x6 = 1; + break; + + case 0xc6: + s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */ + break; + + case 0xb8: /* Panic */ + reset (s); + break; + + case 0x39: + dsp_out_data (s, 0x38); + reset (s); + s->v2x6 = 0x39; + break; + + default: + s->v2x6 = val; + break; } - else - dsp->v2x6 = ~0; break; - case 0xc: /* write data or command | write status */ - if (0 == dsp->needed_bytes) { - command (dsp, val); - if (0 == dsp->needed_bytes) { - log_dsp (dsp); + case 0x0c: /* write data or command | write status */ +/* if (s->highspeed) */ +/* break; */ + + if (0 == s->needed_bytes) { + command (s, val); +#if 0 + if (0 == s->needed_bytes) { + log_dsp (s); } +#endif } else { - if (dsp->in_index == sizeof (dsp->in2_data)) { + if (s->in_index == sizeof (s->in2_data)) { dolog ("in data overrun\n"); } else { - dsp->in2_data[dsp->in_index++] = val; - if (dsp->in_index == dsp->needed_bytes) { - dsp->needed_bytes = 0; - complete (dsp); - log_dsp (dsp); + s->in2_data[s->in_index++] = val; + if (s->in_index == s->needed_bytes) { + s->needed_bytes = 0; + complete (s); +#if 0 + log_dsp (s); +#endif + } } } - } break; default: - dolog ("dsp_write (nport=%#x, val=%#x)\n", nport, val); + ldebug ("(nport=%#x, val=%#x)\n", nport, val); break; } } static IO_READ_PROTO (dsp_read) { - SB16State *dsp = opaque; - int iport, retval; + SB16State *s = opaque; + int iport, retval, ack = 0; - iport = nport - sb.port; + iport = nport - s->port; switch (iport) { - case 0x6: /* reset */ - control (0); - retval = 0; - dsp->speaker = 0; + case 0x06: /* reset */ + retval = 0xff; break; - case 0xa: /* read data */ - if (dsp->out_data_len) { - retval = dsp->out_data[--dsp->out_data_len]; - dsp->last_read_byte = retval; - } else { - retval = dsp->last_read_byte; + case 0x0a: /* read data */ + if (s->out_data_len) { + retval = s->out_data[--s->out_data_len]; + s->last_read_byte = retval; + } + else { dolog ("empty output buffer\n"); + retval = s->last_read_byte; /* goto error; */ } break; - case 0xc: /* 0xxxxxxx can write */ - retval = 0; - if (dsp->out_data_len == sizeof (dsp->out_data)) retval |= 0x80; + case 0x0c: /* 0 can write */ + retval = s->can_write ? 0 : 0x80; break; - case 0xd: /* timer interrupt clear */ - dolog ("timer interrupt clear\n"); - goto error; + case 0x0d: /* timer interrupt clear */ + /* dolog ("timer interrupt clear\n"); */ + retval = 0; + break; - case 0xe: /* data available status | irq 8 ack */ - /* XXX drop pic irq line here? */ - /* ldebug ("8 ack\n"); */ - retval = dsp->out_data_len ? 0x80 : 0; - dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80]; - pic_set_irq (sb.irq, 0); + case 0x0e: /* data available status | irq 8 ack */ + retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80; + if (s->mixer_regs[0x82] & 1) { + ack = 1; + s->mixer_regs[0x82] &= 1; + pic_set_irq (s->irq, 0); + } break; - case 0xf: /* irq 16 ack */ - /* XXX drop pic irq line here? */ - ldebug ("16 ack\n"); + case 0x0f: /* irq 16 ack */ retval = 0xff; - dsp->mixer_regs[0x82] &= ~dsp->mixer_regs[0x80]; - pic_set_irq (sb.irq, 0); + if (s->mixer_regs[0x82] & 2) { + ack = 1; + s->mixer_regs[0x82] &= 2; + pic_set_irq (s->irq, 0); + } break; default: goto error; } - if (0xe == iport) { - if (0 == retval) { - if (!dsp->nzero) { - ldebug ("dsp_read (nport=%#x iport %#x) = %#x, %lld\n", - nport, iport, retval, dsp->nzero); - } - dsp->nzero += 1; - } - else { - ldebug ("dsp_read (nport=%#x iport %#x) = %#x, %lld\n", - nport, iport, retval, dsp->nzero); - dsp->nzero = 0; - } - } - else { - ldebug ("dsp_read (nport=%#x iport %#x) = %#x\n", - nport, iport, retval); - } + if (!ack) + ldebug ("read %#x -> %#x\n", nport, retval); return retval; error: - printf ("dsp_read error %#x\n", nport); + dolog ("WARNING dsp_read %#x error\n", nport); return 0xff; } +static void reset_mixer (SB16State *s) +{ + int i; + + memset (s->mixer_regs, 0xff, 0x7f); + memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83); + + s->mixer_regs[0x02] = 4; /* master volume 3bits */ + s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */ + s->mixer_regs[0x08] = 0; /* CD volume 3bits */ + s->mixer_regs[0x0a] = 0; /* voice volume 2bits */ + + /* d5=input filt, d3=lowpass filt, d1,d2=input source */ + s->mixer_regs[0x0c] = 0; + + /* d5=output filt, d1=stereo switch */ + s->mixer_regs[0x0e] = 0; + + /* voice volume L d5,d7, R d1,d3 */ + s->mixer_regs[0x04] = (4 << 5) | (4 << 1); + /* master ... */ + s->mixer_regs[0x22] = (4 << 5) | (4 << 1); + /* MIDI ... */ + s->mixer_regs[0x26] = (4 << 5) | (4 << 1); + + for (i = 0x30; i < 0x48; i++) { + s->mixer_regs[i] = 0x20; + } +} + static IO_WRITE_PROTO(mixer_write_indexb) { - SB16State *dsp = opaque; - dsp->mixer_nreg = val; + SB16State *s = opaque; + s->mixer_nreg = val; } static IO_WRITE_PROTO(mixer_write_datab) { - SB16State *dsp = opaque; - int i; + SB16State *s = opaque; + + ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); + if (s->mixer_nreg > sizeof (s->mixer_regs)) + return; - linfo ("mixer [%#x] <- %#x\n", dsp->mixer_nreg, val); - switch (dsp->mixer_nreg) { + switch (s->mixer_nreg) { case 0x00: - /* Bochs */ - dsp->mixer_regs[0x04] = 0xcc; - dsp->mixer_regs[0x0a] = 0x00; - dsp->mixer_regs[0x22] = 0xcc; - dsp->mixer_regs[0x26] = 0xcc; - dsp->mixer_regs[0x28] = 0x00; - dsp->mixer_regs[0x2e] = 0x00; - dsp->mixer_regs[0x3c] = 0x1f; - dsp->mixer_regs[0x3d] = 0x15; - dsp->mixer_regs[0x3e] = 0x0b; - - for (i = 0x30; i <= 0x35; i++) - dsp->mixer_regs[i] = 0xc0; - - for (i = 0x36; i <= 0x3b; i++) - dsp->mixer_regs[i] = 0x00; - - for (i = 0x3f; i <= 0x43; i++) - dsp->mixer_regs[i] = 0x00; - - for (i = 0x44; i <= 0x47; i++) - dsp->mixer_regs[i] = 0x80; - - for (i = 0x30; i < 0x48; i++) { - dsp->mixer_regs[i] = 0x20; - } + reset_mixer (s); break; - case 0x04: - case 0x0a: - case 0x22: - case 0x26: - case 0x28: - case 0x2e: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3a: - case 0x3b: - case 0x3c: - case 0x3d: - case 0x3e: - case 0x3f: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: case 0x80: - case 0x81: + { + int irq = irq_of_magic (val); + ldebug ("setting irq to %d (val=%#x)\n", irq, val); + if (irq > 0) + s->irq = irq; + } break; - default: - return; - } - dsp->mixer_regs[dsp->mixer_nreg] = val; -} -static IO_WRITE_PROTO(mpu_write) -{ - linfo ("mpu: %#x\n", val); -} + case 0x81: + { + int dma, hdma; -static IO_WRITE_PROTO(adlib_write) -{ - linfo ("adlib: %#x\n", val); -} + dma = lsbindex (val & 0xf); + hdma = lsbindex (val & 0xf0); + dolog ("attempt to set DMA register 8bit %d, 16bit %d (val=%#x)\n", + dma, hdma, val); +#if 0 + s->dma = dma; + s->hdma = hdma; +#endif + } + break; -static IO_READ_PROTO(mpu_read) -{ - linfo ("mpu read: %#x\n", nport); - return 0x80; -} + case 0x82: + dolog ("attempt to write into IRQ status register (val=%#x)\n", + val); + return; -static IO_READ_PROTO(adlib_read) -{ - linfo ("adlib read: %#x\n", nport); - return 0; + default: + if (s->mixer_nreg >= 0x80) + dolog ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val); + break; + } + + s->mixer_regs[s->mixer_nreg] = val; } static IO_WRITE_PROTO(mixer_write_indexw) @@ -765,194 +962,229 @@ static IO_WRITE_PROTO(mixer_write_indexw) static IO_READ_PROTO(mixer_read) { - SB16State *dsp = opaque; - linfo ("mixer [%#x] -> %#x\n", dsp->mixer_nreg, dsp->mixer_regs[dsp->mixer_nreg]); - return dsp->mixer_regs[dsp->mixer_nreg]; -} - -void SB16_run (void) -{ - if (0 == dsp.speaker) - return; - - AUD_run (); + SB16State *s = opaque; + ldebug ("mixer_read[%#x] -> %#x\n", + s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); + return s->mixer_regs[s->mixer_nreg]; } -static int write_audio (uint32_t addr, int len, int size) +static int write_audio (SB16State *s, int nchan, int dma_pos, + int dma_len, int len) { int temp, net; uint8_t tmpbuf[4096]; - temp = size; - + temp = len; net = 0; while (temp) { - int left_till_end; - int to_copy; - int copied; + int left = dma_len - dma_pos; + int to_copy, copied; - left_till_end = len - dsp.dma_pos; - - to_copy = MIN (temp, left_till_end); + to_copy = audio_MIN (temp, left); if (to_copy > sizeof(tmpbuf)) to_copy = sizeof(tmpbuf); - cpu_physical_memory_read(addr + dsp.dma_pos, tmpbuf, to_copy); - copied = AUD_write (tmpbuf, to_copy); - temp -= copied; - dsp.dma_pos += copied; - - if (dsp.dma_pos == len) { - dsp.dma_pos = 0; - } + copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); + copied = AUD_write (s->voice, tmpbuf, copied); + temp -= copied; + dma_pos = (dma_pos + copied) % dma_len; net += copied; - if (copied != to_copy) - return net; + if (!copied) + break; } return net; } -static int SB_read_DMA (void *opaque, target_ulong addr, int size) +static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) { - SB16State *dsp = opaque; - int free, till, copy, written; - - if (0 == dsp->speaker) - return 0; + SB16State *s = opaque; + int free, rfree, till, copy, written, elapsed; - if (dsp->left_till_irq < 0) { - ldebug ("left_till_irq < 0, %d, pos %d \n", - dsp->left_till_irq, dsp->dma_buffer_size); - dsp->left_till_irq += dsp->dma_buffer_size; - return dsp->dma_pos; + if (s->left_till_irq < 0) { + s->left_till_irq = s->block_size; } - free = AUD_get_free (); - - if ((free <= 0) || (0 == size)) { - ldebug ("returning, since free = %d and size = %d\n", free, size); - return dsp->dma_pos; - } + elapsed = AUD_calc_elapsed (s->voice); + free = elapsed;/* AUD_get_free (s->voice); */ + rfree = free; + free = audio_MIN (free, elapsed) & ~s->align; - if (mix_block > 0) { - copy = MIN (free, mix_block); - } - else { - copy = free; + if ((free <= 0) || !dma_len) { + return dma_pos; } - till = dsp->left_till_irq; + copy = free; + till = s->left_till_irq; #ifdef DEBUG_SB16_MOST - ldebug ("addr:%#010x free:%d till:%d size:%d\n", - addr, free, till, size); + dolog ("pos:%06d free:%d,%d till:%d len:%d\n", + dma_pos, free, AUD_get_free (s->voice), till, dma_len); #endif if (till <= copy) { - if (0 == dsp->dma_auto) { + if (0 == s->dma_auto) { copy = till; } } - written = write_audio (addr, size, copy); - dsp->left_till_irq -= written; - AUD_adjust_estimate (free - written); + written = write_audio (s, nchan, dma_pos, dma_len, copy); + dma_pos = (dma_pos + written) % dma_len; + s->left_till_irq -= written; - if (dsp->left_till_irq <= 0) { - dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; - if (0 == noirq) { - ldebug ("request irq pos %d, left %d\n", - dsp->dma_pos, dsp->left_till_irq); - pic_set_irq(sb.irq, 1); - } - - if (0 == dsp->dma_auto) { - control (0); + if (s->left_till_irq <= 0) { + s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1; + pic_set_irq (s->irq, 1); + if (0 == s->dma_auto) { + control (s, 0); + speaker (s, 0); } } #ifdef DEBUG_SB16_MOST ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n", - dsp->dma_pos, free, size, dsp->left_till_irq, copy, - dsp->dma_buffer_size); + dma_pos, free, dma_len, s->left_till_irq, copy, s->block_size); #endif - if (dsp->left_till_irq <= 0) { - dsp->left_till_irq += dsp->dma_buffer_size; + while (s->left_till_irq <= 0) { + s->left_till_irq = s->block_size + s->left_till_irq; } - return dsp->dma_pos; -} - -static int magic_of_irq (int irq) -{ - switch (irq) { - case 2: - return 1; - case 5: - return 2; - case 7: - return 4; - case 10: - return 8; - default: - dolog ("bad irq %d\n", irq); - return 2; - } + AUD_adjust (s->voice, written); + return dma_pos; } -#if 0 -static int irq_of_magic (int magic) +void SB_timer (void *opaque) { - switch (magic) { - case 1: - return 2; - case 2: - return 5; - case 4: - return 7; - case 8: - return 10; - default: - dolog ("bad irq magic %d\n", magic); - return 2; - } + SB16State *s = opaque; + AUD_run (); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); } -#endif -#ifdef SB16_TRAP_ALL -static IO_READ_PROTO (trap_read) +static void SB_save (QEMUFile *f, void *opaque) { - switch (nport) { - case 0x220: - return 0; - case 0x226: - case 0x22a: - case 0x22c: - case 0x22d: - case 0x22e: - case 0x22f: - return dsp_read (opaque, nport); - } - linfo ("trap_read: %#x\n", nport); - return 0xff; + SB16State *s = opaque; + + qemu_put_be32s (f, &s->irq); + qemu_put_be32s (f, &s->dma); + qemu_put_be32s (f, &s->hdma); + qemu_put_be32s (f, &s->port); + qemu_put_be32s (f, &s->ver); + qemu_put_be32s (f, &s->in_index); + qemu_put_be32s (f, &s->out_data_len); + qemu_put_be32s (f, &s->fmt_stereo); + qemu_put_be32s (f, &s->fmt_signed); + qemu_put_be32s (f, &s->fmt_bits); + qemu_put_be32s (f, &s->fmt); + qemu_put_be32s (f, &s->dma_auto); + qemu_put_be32s (f, &s->block_size); + qemu_put_be32s (f, &s->fifo); + qemu_put_be32s (f, &s->freq); + qemu_put_be32s (f, &s->time_const); + qemu_put_be32s (f, &s->speaker); + qemu_put_be32s (f, &s->needed_bytes); + qemu_put_be32s (f, &s->cmd); + qemu_put_be32s (f, &s->use_hdma); + qemu_put_be32s (f, &s->highspeed); + qemu_put_be32s (f, &s->can_write); + qemu_put_be32s (f, &s->v2x6); + + qemu_put_8s (f, &s->csp_param); + qemu_put_8s (f, &s->csp_value); + qemu_put_8s (f, &s->csp_mode); + qemu_put_8s (f, &s->csp_param); + qemu_put_buffer (f, s->csp_regs, 256); + qemu_put_8s (f, &s->csp_index); + qemu_put_buffer (f, s->csp_reg83, 4); + qemu_put_be32s (f, &s->csp_reg83r); + qemu_put_be32s (f, &s->csp_reg83w); + + qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data)); + qemu_put_buffer (f, s->out_data, sizeof (s->out_data)); + qemu_put_8s (f, &s->test_reg); + qemu_put_8s (f, &s->last_read_byte); + + qemu_put_be32s (f, &s->nzero); + qemu_put_be32s (f, &s->left_till_irq); + qemu_put_be32s (f, &s->dma_running); + qemu_put_be32s (f, &s->bytes_per_second); + qemu_put_be32s (f, &s->align); + + qemu_put_be32s (f, &s->mixer_nreg); + qemu_put_buffer (f, s->mixer_regs, 256); } -static IO_WRITE_PROTO (trap_write) +static int SB_load (QEMUFile *f, void *opaque, int version_id) { - switch (nport) { - case 0x226: - case 0x22c: - dsp_write (opaque, nport, val); - return; + SB16State *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s (f, &s->irq); + qemu_get_be32s (f, &s->dma); + qemu_get_be32s (f, &s->hdma); + qemu_get_be32s (f, &s->port); + qemu_get_be32s (f, &s->ver); + qemu_get_be32s (f, &s->in_index); + qemu_get_be32s (f, &s->out_data_len); + qemu_get_be32s (f, &s->fmt_stereo); + qemu_get_be32s (f, &s->fmt_signed); + qemu_get_be32s (f, &s->fmt_bits); + qemu_get_be32s (f, &s->fmt); + qemu_get_be32s (f, &s->dma_auto); + qemu_get_be32s (f, &s->block_size); + qemu_get_be32s (f, &s->fifo); + qemu_get_be32s (f, &s->freq); + qemu_get_be32s (f, &s->time_const); + qemu_get_be32s (f, &s->speaker); + qemu_get_be32s (f, &s->needed_bytes); + qemu_get_be32s (f, &s->cmd); + qemu_get_be32s (f, &s->use_hdma); + qemu_get_be32s (f, &s->highspeed); + qemu_get_be32s (f, &s->can_write); + qemu_get_be32s (f, &s->v2x6); + + qemu_get_8s (f, &s->csp_param); + qemu_get_8s (f, &s->csp_value); + qemu_get_8s (f, &s->csp_mode); + qemu_get_8s (f, &s->csp_param); + qemu_get_buffer (f, s->csp_regs, 256); + qemu_get_8s (f, &s->csp_index); + qemu_get_buffer (f, s->csp_reg83, 4); + qemu_get_be32s (f, &s->csp_reg83r); + qemu_get_be32s (f, &s->csp_reg83w); + + qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data)); + qemu_get_buffer (f, s->out_data, sizeof (s->out_data)); + qemu_get_8s (f, &s->test_reg); + qemu_get_8s (f, &s->last_read_byte); + + qemu_get_be32s (f, &s->nzero); + qemu_get_be32s (f, &s->left_till_irq); + qemu_get_be32s (f, &s->dma_running); + qemu_get_be32s (f, &s->bytes_per_second); + qemu_get_be32s (f, &s->align); + + qemu_get_be32s (f, &s->mixer_nreg); + qemu_get_buffer (f, s->mixer_regs, 256); + + if (s->voice) + AUD_reset (s->voice); + + if (s->dma_running) { + if (s->freq) + s->voice = AUD_open (s->voice, "sb16", s->freq, + 1 << s->fmt_stereo, s->fmt); + + control (s, 1); + speaker (s, s->speaker); } - linfo ("trap_write: %#x = %#x\n", nport, val); + return 0; } -#endif void SB16_init (void) { @@ -961,47 +1193,45 @@ void SB16_init (void) static const uint8_t dsp_write_ports[] = {0x6, 0xc}; static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; - memset(s->mixer_regs, 0xff, sizeof(s->mixer_regs)); + s->ts = qemu_new_timer (vm_clock, SB_timer, s); + if (!s->ts) + return; + + s->irq = conf.irq; + s->dma = conf.dma; + s->hdma = conf.hdma; + s->port = conf.port; + s->ver = conf.ver_lo | (conf.ver_hi << 8); - s->mixer_regs[0x00] = 0; - s->mixer_regs[0x0e] = ~0; - s->mixer_regs[0x80] = magic_of_irq (sb.irq); - s->mixer_regs[0x81] = 0x80 | 0x10 | (sb.dma << 1); - s->mixer_regs[0x82] = 0; - s->mixer_regs[0xfd] = 16; /* bochs */ - s->mixer_regs[0xfe] = 6; /* bochs */ - mixer_write_indexw (s, 0x224, 0); - -#ifdef SB16_TRAP_ALL - for (i = 0; i < 0x100; i++) { - if (i != 4 && i != 5) { - register_ioport_write (sb.port + i, 1, 1, trap_write, s); - register_ioport_read (sb.port + i, 1, 1, trap_read, s); - } - } -#else + s->mixer_regs[0x80] = magic_of_irq (s->irq); + s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma); + s->mixer_regs[0x82] = 2 << 5; + + s->csp_regs[5] = 1; + s->csp_regs[9] = 0xf8; + + reset_mixer (s); + s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s); + if (!s->aux_ts) + return; for (i = 0; i < LENOFA (dsp_write_ports); i++) { - register_ioport_write (sb.port + dsp_write_ports[i], 1, 1, dsp_write, s); + register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s); } for (i = 0; i < LENOFA (dsp_read_ports); i++) { - register_ioport_read (sb.port + dsp_read_ports[i], 1, 1, dsp_read, s); + register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s); } -#endif - register_ioport_write (sb.port + 0x4, 1, 1, mixer_write_indexb, s); - register_ioport_write (sb.port + 0x4, 1, 2, mixer_write_indexw, s); - register_ioport_read (sb.port + 0x5, 1, 1, mixer_read, s); - register_ioport_write (sb.port + 0x5, 1, 1, mixer_write_datab, s); + register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s); + register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s); + register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s); + register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s); - for (i = 0; 4 < 4; i++) { - register_ioport_read (0x330 + i, 1, 1, mpu_read, s); - register_ioport_write (0x330 + i, 1, 1, mpu_write, s); - register_ioport_read (0x388 + i, 1, 1, adlib_read, s); - register_ioport_write (0x388 + i, 1, 1, adlib_write, s); - } + DMA_register_channel (s->hdma, SB_read_DMA, s); + DMA_register_channel (s->dma, SB_read_DMA, s); + s->can_write = 1; - DMA_register_channel (sb.hdma, SB_read_DMA, s); - DMA_register_channel (sb.dma, SB_read_DMA, s); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); + register_savevm ("sb16", 0, 1, SB_save, SB_load, s); } diff --git a/oss.c b/oss.c deleted file mode 100644 index 91eb47e49..000000000 --- a/oss.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - * QEMU OSS Audio output driver - * - * Copyright (c) 2003 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -#include -#include -#include -#include - -/* TODO: Graceful error handling */ - -#if defined(_WIN32) -#define USE_SDL_AUDIO -#endif - -#define MIN(a, b) ((a)>(b)?(b):(a)) -#define MAX(a, b) ((a)<(b)?(b):(a)) - -#define DEREF(x) (void)x -#define dolog(...) fprintf (stderr, "audio: " __VA_ARGS__) -#define ERRFail(...) do { \ - int _errno = errno; \ - fprintf (stderr, "audio: " __VA_ARGS__); \ - fprintf (stderr, "\nsystem error: %s\n", strerror (_errno)); \ - abort (); \ -} while (0) -#define Fail(...) do { \ - fprintf (stderr, "audio: " __VA_ARGS__); \ - fprintf (stderr, "\n"); \ - abort (); \ -} while (0) - -#ifdef DEBUG_AUDIO -#define lwarn(...) fprintf (stderr, "audio: " __VA_ARGS__) -#define linfo(...) fprintf (stderr, "audio: " __VA_ARGS__) -#define ldebug(...) fprintf (stderr, "audio: " __VA_ARGS__) -#else -#define lwarn(...) -#define linfo(...) -#define ldebug(...) -#endif - -static int get_conf_val (const char *key, int defval) -{ - int val = defval; - char *strval; - - strval = getenv (key); - if (strval) { - val = atoi (strval); - } - - return val; -} - -static void copy_no_conversion (void *dst, void *src, int size) -{ - memcpy (dst, src, size); -} - -static void copy_u16_to_s16 (void *dst, void *src, int size) -{ - int i; - uint16_t *out, *in; - - out = dst; - in = src; - - for (i = 0; i < size / 2; i++) { - out[i] = in[i] + 0x8000; - } -} - -#ifdef USE_SDL_AUDIO -#include -#include - -static struct { - int samples; -} conf = { - .samples = 4096 -}; - -typedef struct AudioState { - int freq; - int bits16; - int nchannels; - int rpos; - int wpos; - volatile int live; - volatile int exit; - int bytes_per_second; - Uint8 *buf; - int bufsize; - int leftover; - uint64_t old_ticks; - SDL_AudioSpec spec; - SDL_mutex *mutex; - SDL_sem *sem; - void (*copy_fn)(void *, void *, int); -} AudioState; - -static AudioState sdl_audio; - -void AUD_run (void) -{ -} - -static void own (AudioState *s) -{ - /* SDL_LockAudio (); */ - if (SDL_mutexP (s->mutex)) - dolog ("SDL_mutexP: %s\n", SDL_GetError ()); -} - -static void disown (AudioState *s) -{ - /* SDL_UnlockAudio (); */ - if (SDL_mutexV (s->mutex)) - dolog ("SDL_mutexV: %s\n", SDL_GetError ()); -} - -static void sem_wait (AudioState *s) -{ - if (SDL_SemWait (s->sem)) - dolog ("SDL_SemWait: %s\n", SDL_GetError ()); -} - -static void sem_post (AudioState *s) -{ - if (SDL_SemPost (s->sem)) - dolog ("SDL_SemPost: %s\n", SDL_GetError ()); -} - -static void audio_callback (void *data, Uint8 *stream, int len) -{ - int to_mix; - AudioState *s = data; - - if (s->exit) return; - while (len) { - sem_wait (s); - if (s->exit) return; - own (s); - to_mix = MIN (len, s->live); - len -= to_mix; - /* printf ("to_mix=%d len=%d live=%d\n", to_mix, len, s->live); */ - while (to_mix) { - int chunk = MIN (to_mix, s->bufsize - s->rpos); - /* SDL_MixAudio (stream, buf, chunk, SDL_MIX_MAXVOLUME); */ - memcpy (stream, s->buf + s->rpos, chunk); - - s->rpos += chunk; - s->live -= chunk; - - stream += chunk; - to_mix -= chunk; - - if (s->rpos == s->bufsize) s->rpos = 0; - } - disown (s); - } -} - -static void sem_zero (AudioState *s) -{ - int res; - - do { - res = SDL_SemTryWait (s->sem); - if (res < 0) { - dolog ("SDL_SemTryWait: %s\n", SDL_GetError ()); - return; - } - } while (res != SDL_MUTEX_TIMEDOUT); -} - -static void do_open (AudioState *s) -{ - int status; - SDL_AudioSpec obtained; - - SDL_PauseAudio (1); - if (s->buf) { - s->exit = 1; - sem_post (s); - SDL_CloseAudio (); - s->exit = 0; - qemu_free (s->buf); - s->buf = NULL; - sem_zero (s); - } - - s->bytes_per_second = (s->spec.freq << (s->spec.channels >> 1)) << s->bits16; - s->spec.samples = conf.samples; - s->spec.userdata = s; - s->spec.callback = audio_callback; - - status = SDL_OpenAudio (&s->spec, &obtained); - if (status < 0) { - dolog ("SDL_OpenAudio: %s\n", SDL_GetError ()); - goto exit; - } - - if (obtained.freq != s->spec.freq || - obtained.channels != s->spec.channels || - obtained.format != s->spec.format) { - dolog ("Audio spec mismatch requested obtained\n" - "freq %5d %5d\n" - "channels %5d %5d\n" - "fmt %5d %5d\n", - s->spec.freq, obtained.freq, - s->spec.channels, obtained.channels, - s->spec.format, obtained.format - ); - } - - s->bufsize = obtained.size; - s->buf = qemu_mallocz (s->bufsize); - if (!s->buf) { - dolog ("qemu_mallocz(%d)\n", s->bufsize); - goto exit; - } - SDL_PauseAudio (0); - -exit: - s->rpos = 0; - s->wpos = 0; - s->live = 0; -} - -int AUD_write (void *in_buf, int size) -{ - AudioState *s = &sdl_audio; - int to_copy, temp; - uint8_t *in, *out; - - own (s); - to_copy = MIN (s->bufsize - s->live, size); - - temp = to_copy; - - in = in_buf; - out = s->buf; - - while (temp) { - int copy; - - copy = MIN (temp, s->bufsize - s->wpos); - s->copy_fn (out + s->wpos, in, copy); - - s->wpos += copy; - if (s->wpos == s->bufsize) { - s->wpos = 0; - } - - temp -= copy; - in += copy; - s->live += copy; - } - - disown (s); - sem_post (s); - return to_copy; -} - -static void maybe_open (AudioState *s, int req_freq, int req_nchannels, - audfmt_e req_fmt, int force_open) -{ - int sdl_fmt, bits16; - - switch (req_fmt) { - case AUD_FMT_U8: - bits16 = 0; - sdl_fmt = AUDIO_U8; - s->copy_fn = copy_no_conversion; - break; - - case AUD_FMT_S8: - fprintf (stderr, "audio: can not play 8bit signed\n"); - return; - - case AUD_FMT_S16: - bits16 = 1; - sdl_fmt = AUDIO_S16; - s->copy_fn = copy_no_conversion; - break; - - case AUD_FMT_U16: - bits16 = 1; - sdl_fmt = AUDIO_S16; - s->copy_fn = copy_u16_to_s16; - break; - - default: - abort (); - } - - if (force_open - || (NULL == s->buf) - || (sdl_fmt != s->spec.format) - || (req_nchannels != s->spec.channels) - || (req_freq != s->spec.freq) - || (bits16 != s->bits16)) { - - s->spec.format = sdl_fmt; - s->spec.channels = req_nchannels; - s->spec.freq = req_freq; - s->bits16 = bits16; - do_open (s); - } -} - -void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) -{ - AudioState *s = &sdl_audio; - own (s); - maybe_open (s, req_freq, req_nchannels, req_fmt, 0); - disown (s); -} - -void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) -{ - AudioState *s = &sdl_audio; - own (s); - maybe_open (s, req_freq, req_nchannels, req_fmt, 1); - disown (s); -} - -void AUD_adjust_estimate (int leftover) -{ - AudioState *s = &sdl_audio; - own (s); - s->leftover = leftover; - disown (s); -} - -int AUD_get_free (void) -{ - int free, elapsed; - uint64_t ticks, delta; - uint64_t ua_elapsed; - uint64_t al_elapsed; - AudioState *s = &sdl_audio; - - own (s); - free = s->bufsize - s->live; - - if (0 == free) { - disown (s); - return 0; - } - - elapsed = free; - ticks = qemu_get_clock(rt_clock); - delta = ticks - s->old_ticks; - s->old_ticks = ticks; - - ua_elapsed = (delta * s->bytes_per_second) / 1000; - al_elapsed = ua_elapsed & ~3ULL; - - ldebug ("tid elapsed %llu bytes\n", ua_elapsed); - - if (al_elapsed > (uint64_t) INT_MAX) - elapsed = INT_MAX; - else - elapsed = al_elapsed; - - elapsed += s->leftover; - disown (s); - - if (elapsed > free) { - lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free); - return free; - } - else { - return elapsed; - } -} - -int AUD_get_live (void) -{ - int live; - AudioState *s = &sdl_audio; - - own (s); - live = s->live; - disown (s); - return live; -} - -int AUD_get_buffer_size (void) -{ - int bufsize; - AudioState *s = &sdl_audio; - - own (s); - bufsize = s->bufsize; - disown (s); - return bufsize; -} - -#define QC_SDL_NSAMPLES "QEMU_SDL_NSAMPLES" - -static void cleanup (void) -{ - AudioState *s = &sdl_audio; - own (s); - s->exit = 1; - sem_post (s); - disown (s); -} - -void AUD_init (void) -{ - AudioState *s = &sdl_audio; - - atexit (cleanup); - SDL_InitSubSystem (SDL_INIT_AUDIO); - s->mutex = SDL_CreateMutex (); - if (!s->mutex) { - dolog ("SDL_CreateMutex: %s\n", SDL_GetError ()); - return; - } - - s->sem = SDL_CreateSemaphore (0); - if (!s->sem) { - dolog ("SDL_CreateSemaphore: %s\n", SDL_GetError ()); - return; - } - - conf.samples = get_conf_val (QC_SDL_NSAMPLES, conf.samples); -} - -#elif !defined(_WIN32) && !defined(__APPLE__) - -#include -#include -#include -#include -#include -#include -#include - -/* http://www.df.lth.se/~john_e/gems/gem002d.html */ -/* http://www.multi-platforms.com/Tips/PopCount.htm */ -static inline uint32_t popcount (uint32_t u) -{ - u = ((u&0x55555555) + ((u>>1)&0x55555555)); - u = ((u&0x33333333) + ((u>>2)&0x33333333)); - u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); - u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); - u = ( u&0x0000ffff) + (u>>16); - return u; -} - -static inline uint32_t lsbindex (uint32_t u) -{ - return popcount ((u&-u)-1); -} - -#define IOCTL(args) do { \ - int ret = ioctl args; \ - if (-1 == ret) { \ - ERRFail (#args); \ - } \ - ldebug ("ioctl " #args " = %d\n", ret); \ -} while (0) - -typedef struct AudioState { - int fd; - int freq; - int bits16; - int nchannels; - int rpos; - int wpos; - int live; - int oss_fmt; - int bytes_per_second; - int is_mapped; - void *buf; - int bufsize; - int nfrags; - int fragsize; - int old_optr; - int leftover; - uint64_t old_ticks; - void (*copy_fn)(void *, void *, int); -} AudioState; - -static AudioState oss_audio = { .fd = -1 }; - -static struct { - int try_mmap; - int nfrags; - int fragsize; -} conf = { - .try_mmap = 0, - .nfrags = 4, - .fragsize = 4096 -}; - -static enum {DONT, DSP, TID} est = DONT; - -static void pab (AudioState *s, struct audio_buf_info *abinfo) -{ - DEREF (abinfo); - - ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n" - "rpos %d, wpos %d, live %d\n", - abinfo->fragments, - abinfo->fragstotal, - abinfo->fragsize, - abinfo->bytes, - s->rpos, s->wpos, s->live); -} - -static void do_open (AudioState *s) -{ - int mmmmssss; - audio_buf_info abinfo; - int fmt, freq, nchannels; - - if (s->buf) { - if (s->is_mapped) { - if (-1 == munmap (s->buf, s->bufsize)) { - ERRFail ("failed to unmap audio buffer %p %d", - s->buf, s->bufsize); - } - } - else { - qemu_free (s->buf); - } - s->buf = NULL; - } - - if (-1 != s->fd) - close (s->fd); - - s->fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK); - if (-1 == s->fd) { - ERRFail ("can not open /dev/dsp"); - } - - fmt = s->oss_fmt; - freq = s->freq; - nchannels = s->nchannels; - - IOCTL ((s->fd, SNDCTL_DSP_RESET, 1)); - IOCTL ((s->fd, SNDCTL_DSP_SAMPLESIZE, &fmt)); - IOCTL ((s->fd, SNDCTL_DSP_CHANNELS, &nchannels)); - IOCTL ((s->fd, SNDCTL_DSP_SPEED, &freq)); - IOCTL ((s->fd, SNDCTL_DSP_NONBLOCK)); - - mmmmssss = (conf.nfrags << 16) | conf.fragsize; - IOCTL ((s->fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); - - if ((s->oss_fmt != fmt) - || (s->nchannels != nchannels) - || (s->freq != freq)) { - Fail ("failed to set audio parameters\n" - "parameter | requested value | obtained value\n" - "format | %10d | %10d\n" - "channels | %10d | %10d\n" - "frequency | %10d | %10d\n", - s->oss_fmt, fmt, - s->nchannels, nchannels, - s->freq, freq); - } - - IOCTL ((s->fd, SNDCTL_DSP_GETOSPACE, &abinfo)); - - s->nfrags = abinfo.fragstotal; - s->fragsize = abinfo.fragsize; - s->bufsize = s->nfrags * s->fragsize; - s->old_optr = 0; - - s->bytes_per_second = (freq << (nchannels >> 1)) << s->bits16; - - linfo ("bytes per second %d\n", s->bytes_per_second); - - linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", - abinfo.fragments, - abinfo.fragstotal, - abinfo.fragsize, - abinfo.bytes, - s->bufsize); - - s->buf = MAP_FAILED; - s->is_mapped = 0; - - if (conf.try_mmap) { - s->buf = mmap (NULL, s->bufsize, PROT_WRITE, MAP_SHARED, s->fd, 0); - if (MAP_FAILED == s->buf) { - int err; - - err = errno; - dolog ("failed to mmap audio, size %d, fd %d\n" - "syserr: %s\n", - s->bufsize, s->fd, strerror (err)); - } - else { - est = TID; - s->is_mapped = 1; - } - } - - if (MAP_FAILED == s->buf) { - est = TID; - s->buf = qemu_mallocz (s->bufsize); - if (!s->buf) { - ERRFail ("audio buf malloc failed, size %d", s->bufsize); - } - } - - s->rpos = 0; - s->wpos = 0; - s->live = 0; - - if (s->is_mapped) { - int trig; - - trig = 0; - IOCTL ((s->fd, SNDCTL_DSP_SETTRIGGER, &trig)); - trig = PCM_ENABLE_OUTPUT; - IOCTL ((s->fd, SNDCTL_DSP_SETTRIGGER, &trig)); - } -} - -static void maybe_open (AudioState *s, int req_freq, int req_nchannels, - audfmt_e req_fmt, int force_open) -{ - int oss_fmt, bits16; - - switch (req_fmt) { - case AUD_FMT_U8: - bits16 = 0; - oss_fmt = AFMT_U8; - s->copy_fn = copy_no_conversion; - break; - - case AUD_FMT_S8: - Fail ("can not play 8bit signed"); - - case AUD_FMT_S16: - bits16 = 1; - oss_fmt = AFMT_S16_LE; - s->copy_fn = copy_no_conversion; - break; - - case AUD_FMT_U16: - bits16 = 1; - oss_fmt = AFMT_S16_LE; - s->copy_fn = copy_u16_to_s16; - break; - - default: - abort (); - } - - if (force_open - || (-1 == s->fd) - || (oss_fmt != s->oss_fmt) - || (req_nchannels != s->nchannels) - || (req_freq != s->freq) - || (bits16 != s->bits16)) { - s->oss_fmt = oss_fmt; - s->nchannels = req_nchannels; - s->freq = req_freq; - s->bits16 = bits16; - do_open (s); - } -} - -void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) -{ - AudioState *s = &oss_audio; - maybe_open (s, req_freq, req_nchannels, req_fmt, 0); -} - -void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) -{ - AudioState *s = &oss_audio; - maybe_open (s, req_freq, req_nchannels, req_fmt, 1); -} - -int AUD_write (void *in_buf, int size) -{ - AudioState *s = &oss_audio; - int to_copy, temp; - uint8_t *in, *out; - - to_copy = MIN (s->bufsize - s->live, size); - - temp = to_copy; - - in = in_buf; - out = s->buf; - - while (temp) { - int copy; - - copy = MIN (temp, s->bufsize - s->wpos); - s->copy_fn (out + s->wpos, in, copy); - - s->wpos += copy; - if (s->wpos == s->bufsize) { - s->wpos = 0; - } - - temp -= copy; - in += copy; - s->live += copy; - } - - return to_copy; -} - -void AUD_run (void) -{ - int res; - int bytes; - struct audio_buf_info abinfo; - AudioState *s = &oss_audio; - - if (0 == s->live) - return; - - if (s->is_mapped) { - count_info info; - - res = ioctl (s->fd, SNDCTL_DSP_GETOPTR, &info); - if (res < 0) { - int err; - - err = errno; - lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err)); - return; - } - - if (info.ptr > s->old_optr) { - bytes = info.ptr - s->old_optr; - } - else { - bytes = s->bufsize + info.ptr - s->old_optr; - } - - s->old_optr = info.ptr; - s->live -= bytes; - return; - } - - res = ioctl (s->fd, SNDCTL_DSP_GETOSPACE, &abinfo); - - if (res < 0) { - int err; - - err = errno; - lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err)); - return; - } - - bytes = abinfo.bytes; - bytes = MIN (s->live, bytes); -#if 0 - bytes = (bytes / fragsize) * fragsize; -#endif - - while (bytes) { - int left, play, written; - - left = s->bufsize - s->rpos; - play = MIN (left, bytes); - written = write (s->fd, (uint8_t *)s->buf + s->rpos, play); - - if (-1 == written) { - if (EAGAIN == errno || EINTR == errno) { - return; - } - else { - ERRFail ("write audio"); - } - } - - play = written; - s->live -= play; - s->rpos += play; - bytes -= play; - - if (s->rpos == s->bufsize) { - s->rpos = 0; - } - } -} - -static int get_dsp_bytes (void) -{ - int res; - struct count_info info; - AudioState *s = &oss_audio; - - res = ioctl (s->fd, SNDCTL_DSP_GETOPTR, &info); - if (-1 == res) { - int err; - - err = errno; - lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err)); - return -1; - } - else { - ldebug ("bytes %d\n", info.bytes); - return info.bytes; - } -} - -void AUD_adjust_estimate (int leftover) -{ - AudioState *s = &oss_audio; - s->leftover = leftover; -} - -int AUD_get_free (void) -{ - int free, elapsed; - AudioState *s = &oss_audio; - - free = s->bufsize - s->live; - - if (free <= 0) - return 0; - - elapsed = free; - switch (est) { - case DONT: - break; - - case DSP: - { - static int old_bytes; - int bytes; - - bytes = get_dsp_bytes (); - if (bytes <= 0) - return free; - - elapsed = bytes - old_bytes; - old_bytes = bytes; - ldebug ("dsp elapsed %d bytes\n", elapsed); - break; - } - - case TID: - { - uint64_t ticks, delta; - uint64_t ua_elapsed; - uint64_t al_elapsed; - - ticks = qemu_get_clock(rt_clock); - delta = ticks - s->old_ticks; - s->old_ticks = ticks; - - ua_elapsed = (delta * s->bytes_per_second) / 1000; - al_elapsed = ua_elapsed & ~3ULL; - - ldebug ("tid elapsed %llu bytes\n", ua_elapsed); - - if (al_elapsed > (uint64_t) INT_MAX) - elapsed = INT_MAX; - else - elapsed = al_elapsed; - - elapsed += s->leftover; - } - } - - if (elapsed > free) { - lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free); - return free; - } - else { - return elapsed; - } -} - -int AUD_get_live (void) -{ - AudioState *s = &oss_audio; - return s->live; -} - -int AUD_get_buffer_size (void) -{ - AudioState *s = &oss_audio; - return s->bufsize; -} - -#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" -#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" -#define QC_OSS_MMAP "QEMU_OSS_MMAP" - -void AUD_init (void) -{ - int fsp; - - DEREF (pab); - - conf.fragsize = get_conf_val (QC_OSS_FRAGSIZE, conf.fragsize); - conf.nfrags = get_conf_val (QC_OSS_NFRAGS, conf.nfrags); - conf.try_mmap = get_conf_val (QC_OSS_MMAP, conf.try_mmap); - - fsp = conf.fragsize; - if (0 != (fsp & (fsp - 1))) { - Fail ("fragment size %d is not power of 2", fsp); - } - - conf.fragsize = lsbindex (fsp); -} - -#else - -void AUD_run (void) -{ -} - -int AUD_write (void *in_buf, int size) -{ - return 0; -} - -void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) -{ -} - -void AUD_adjust_estimate (int _leftover) -{ -} - -int AUD_get_free (void) -{ - return 0; -} - -int AUD_get_live (void) -{ - return 0; -} - -int AUD_get_buffer_size (void) -{ - return 0; -} - -void AUD_init (void) -{ -} - -#endif diff --git a/vl.c b/vl.c index 32474bfc7..6710e30a4 100644 --- a/vl.c +++ b/vl.c @@ -2438,12 +2438,6 @@ void main_loop_wait(int timeout) if (vm_running) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)); - - if (audio_enabled) { - /* XXX: add explicit timer */ - SB16_run(); - } - /* run dma transfers, if any */ DMA_run(); } diff --git a/vl.h b/vl.h index f25bbaa5c..56927f34e 100644 --- a/vl.h +++ b/vl.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -553,39 +554,22 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table); int pmac_ide_init (BlockDriverState **hd_table, openpic_t *openpic, int irq); -/* oss.c */ -typedef enum { - AUD_FMT_U8, - AUD_FMT_S8, - AUD_FMT_U16, - AUD_FMT_S16 -} audfmt_e; - -void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt); -void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt); -int AUD_write (void *in_buf, int size); -void AUD_run (void); -void AUD_adjust_estimate (int _leftover); -int AUD_get_free (void); -int AUD_get_live (void); -int AUD_get_buffer_size (void); +/* audio.c */ void AUD_init (void); /* dma.c */ -typedef int (*DMA_transfer_handler) (void *opaque, target_ulong addr, int size); +typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); int DMA_get_channel_mode (int nchan); +int DMA_read_memory (int nchan, void *buf, int pos, int size); +int DMA_write_memory (int nchan, void *buf, int pos, int size); void DMA_hold_DREQ (int nchan); void DMA_release_DREQ (int nchan); void DMA_schedule(int nchan); void DMA_run (void); void DMA_init (int high_page_enable); void DMA_register_channel (int nchan, - DMA_transfer_handler transfer_handler, void *opaque); - -/* sb16.c */ -void SB16_run (void); -void SB16_init (void); - + DMA_transfer_handler transfer_handler, + void *opaque); /* fdc.c */ #define MAX_FD 2 extern BlockDriverState *fd_table[MAX_FD]; -- cgit v1.2.3 From 9bb34eac8b89f624776ce6604c22d7c3097a1e24 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Nov 2004 22:54:14 +0000 Subject: CRTC register write protection fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1126 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 2 +- pc-bios/vgabios-cirrus.bin | Bin 30852 -> 30868 bytes pc-bios/vgabios.bin | Bin 29673 -> 31533 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 9d8051519..7c34c5789 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2689,7 +2689,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); #endif /* handle CR0-7 protection */ - if ((s->cr[11] & 0x80) && s->cr_index <= 7) { + if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) { /* can always write bit 4 of CR7 */ if (s->cr_index == 7) s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 58572b643..4e3c82954 100644 Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index 88e99f6cb..ed31b12b1 100644 Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ -- cgit v1.2.3 From f6c958c8652ad63f772f738a8b7776d975bcd787 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Nov 2004 22:57:20 +0000 Subject: CRTC register write protection fix - line_compare, multi_scan and double_scan fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1127 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 2660b0469..3d4312de2 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -344,7 +344,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); #endif /* handle CR0-7 protection */ - if ((s->cr[11] & 0x80) && s->cr_index <= 7) { + if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) { /* can always write bit 4 of CR7 */ if (s->cr_index == 7) s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); @@ -1346,11 +1346,13 @@ static void vga_draw_graphic(VGAState *s, int full_update) disp_width = width; shift_control = (s->gr[0x05] >> 5) & 3; - double_scan = (s->cr[0x09] & 0x80); - if (shift_control > 1) { - multi_scan = (s->cr[0x09] & 0x1f); + double_scan = (s->cr[0x09] >> 7); + if (shift_control != 1) { + multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; } else { - multi_scan = 0; + /* in CGA modes, multi_scan is ignored */ + /* XXX: is it correct ? */ + multi_scan = double_scan; } multi_run = multi_scan; if (shift_control != s->shift_control || @@ -1417,7 +1419,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) line_offset = s->line_offset; #if 0 - printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n", + printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]); #endif addr1 = (s->start_addr * 4); @@ -1468,21 +1470,17 @@ static void vga_draw_graphic(VGAState *s, int full_update) } } if (!multi_run) { - if (!double_scan || (y & 1) != 0) { - if (y1 == s->line_compare) { - addr1 = 0; - } else { - mask = (s->cr[0x17] & 3) ^ 3; - if ((y1 & mask) == mask) - addr1 += line_offset; - } - y1++; - } + mask = (s->cr[0x17] & 3) ^ 3; + if ((y1 & mask) == mask) + addr1 += line_offset; + y1++; multi_run = multi_scan; } else { multi_run--; - y1++; } + /* line compare acts on the displayed lines */ + if (y == s->line_compare) + addr1 = 0; d += linesize; } if (y_start >= 0) { -- cgit v1.2.3 From e0fe67aa7240369b9ba3463df8c12c87955664c9 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 9 Nov 2004 22:04:05 +0000 Subject: enabled DMA git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1128 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index a7de3cd6d..bc7ebd320 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -416,10 +416,10 @@ static void ide_identify(IDEState *s) put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); #endif put_le16(p + 48, 1); /* dword I/O */ - put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */ + put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ put_le16(p + 51, 0x200); /* PIO transfer cycle */ put_le16(p + 52, 0x200); /* DMA transfer cycle */ - put_le16(p + 53, 1); /* words 54-58 are valid */ + put_le16(p + 53, 1 | 1 << 2); /* words 54-58,88 are valid */ put_le16(p + 54, s->cylinders); put_le16(p + 55, s->heads); put_le16(p + 56, s->sectors); @@ -437,6 +437,8 @@ static void ide_identify(IDEState *s) put_le16(p + 85, (1 << 14)); put_le16(p + 86, 0); put_le16(p + 87, (1 << 14)); + put_le16(p + 88, 0x1f | (1 << 13)); + put_le16(p + 93, 1 | (1 << 14) | 0x2000 | 0x4000); } static void ide_atapi_identify(IDEState *s) @@ -1560,7 +1562,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0x82: /* write cache disable */ case 0xaa: /* read look-ahead enable */ case 0x55: /* read look-ahead disable */ - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; default: -- cgit v1.2.3 From 7a987127f424912cd356c443f77e4e6147b57b80 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 9 Nov 2004 22:08:48 +0000 Subject: bit mask conversion fix (Harald Welte git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1129 c046a42c-6fe2-441c-8c8c-71466251a162 --- thunk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thunk.c b/thunk.c index b14fb1777..2dbc378cd 100644 --- a/thunk.c +++ b/thunk.c @@ -236,7 +236,7 @@ unsigned int host_to_target_bitmask(unsigned int alpha_mask, for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) { if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) { - x86_mask |= btp->x86_mask; + x86_mask |= btp->x86_bits; } } return(x86_mask); -- cgit v1.2.3 From bf71c9d9b64a70e56db351c38ff71e5e27d871e7 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 9 Nov 2004 22:12:08 +0000 Subject: disabled again register usage for ppc because my previous patch seems still buggy git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1130 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dyngen-exec.h b/dyngen-exec.h index 1a3bb2a18..86087ca62 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -93,6 +93,8 @@ extern int printf(const char *, ...); #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" @@ -101,6 +103,7 @@ extern int printf(const char *, ...); #define AREG9 "r21" #define AREG10 "r22" #define AREG11 "r23" +#endif #define USE_INT_TO_FLOAT_HELPERS #define BUGGY_GCC_DIV64 #endif -- cgit v1.2.3 From fb065187e4ee9e0d1709b344ec01bb426ff1e43b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 9 Nov 2004 23:09:44 +0000 Subject: audio clean up (initial patch by malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1131 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 17 +++--- audio/audio.c | 86 +++++++++++------------------ audio/audio.h | 133 ++------------------------------------------ audio/audio_int.h | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ audio/fmodaudio.c | 19 ++++++- audio/fmodaudio.h | 39 ------------- audio/ossaudio.c | 31 +++++++---- audio/sdlaudio.c | 15 ++++- audio/sdlaudio.h | 34 ------------ audio/wavaudio.c | 19 ++++++- audio/wavaudio.h | 38 ------------- configure | 20 ++++++- hw/adlib.c | 8 ++- hw/pc.c | 13 ++++- hw/sb16.c | 20 ++++--- vl.c | 3 + vl.h | 14 ++++- 17 files changed, 337 insertions(+), 333 deletions(-) create mode 100644 audio/audio_int.h delete mode 100644 audio/fmodaudio.h delete mode 100644 audio/sdlaudio.h delete mode 100644 audio/wavaudio.h diff --git a/Makefile.target b/Makefile.target index 280ffa1b3..5982f0837 100644 --- a/Makefile.target +++ b/Makefile.target @@ -1,9 +1,5 @@ include config.mak -#After enabling Adlib and/or FMOD rebuild QEMU from scratch -#Uncomment following for adlib support -#USE_ADLIB=1 - #Uncomment following and specify proper paths/names for FMOD support #USE_FMOD=1 #FMOD_INCLUDE=/net/include/fmod @@ -278,11 +274,18 @@ VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o SOUND_HW = sb16.o -AUDIODRV = audio.o ossaudio.o sdlaudio.o wavaudio.o +AUDIODRV = audio.o wavaudio.o +ifdef CONFIG_SDL +AUDIODRV += sdlaudio.o +endif +ifdef CONFIG_OSS +AUDIODRV += ossaudio.o +endif + +pc.o: DEFINES := -DUSE_SB16 $(DEFINES) -ifeq ($(USE_ADLIB),1) +ifdef CONFIG_ADLIB SOUND_HW += fmopl.o adlib.o -audio.o: DEFINES := -DUSE_ADLIB $(DEFINES) endif ifeq ($(USE_FMOD),1) diff --git a/audio/audio.c b/audio/audio.c index f55e1a28c..ec77c259e 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -22,62 +22,26 @@ * THE SOFTWARE. */ #include -#include #include "vl.h" -#define AUDIO_CAP "audio" -#include "audio/audio.h" - #define USE_SDL_AUDIO #define USE_WAV_AUDIO -#if defined __linux__ || (defined _BSD && !defined __APPLE__) -#define USE_OSS_AUDIO -#endif - -#ifdef USE_OSS_AUDIO -#include "audio/ossaudio.h" -#endif - -#ifdef USE_SDL_AUDIO -#include "audio/sdlaudio.h" -#endif - -#ifdef USE_WAV_AUDIO -#include "audio/wavaudio.h" -#endif +#include "audio/audio_int.h" -#ifdef USE_FMOD_AUDIO -#include "audio/fmodaudio.h" +#define dolog(...) AUD_log ("audio", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) #endif #define QC_AUDIO_DRV "QEMU_AUDIO_DRV" -#define QC_VOICES "QEMU_VOICES" +#define QC_VOICES "QEMU_VOICES" #define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT" #define QC_FIXED_FREQ "QEMU_FIXED_FREQ" -extern void SB16_init (void); - -#ifdef USE_ADLIB -extern void Adlib_init (void); -#endif - -#ifdef USE_GUS -extern void GUS_init (void); -#endif - -static void (*hw_ctors[]) (void) = { - SB16_init, -#ifdef USE_ADLIB - Adlib_init, -#endif -#ifdef USE_GUS - GUS_init, -#endif - NULL -}; - -static HWVoice *hw_voice; +static HWVoice *hw_voices; AudioState audio_state = { 1, /* use fixed settings */ @@ -127,9 +91,10 @@ const char *audio_get_conf_str (const char *key, const char *defval) return val; } -void audio_log (const char *fmt, ...) +void AUD_log (const char *cap, const char *fmt, ...) { va_list ap; + fprintf (stderr, "%s: ", cap); va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); @@ -403,7 +368,7 @@ int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) static int dist (void *hw) { if (hw) { - return (((uint8_t *) hw - (uint8_t *) hw_voice) + return (((uint8_t *) hw - (uint8_t *) hw_voices) / audio_state.voice_size) + 1; } else { @@ -411,7 +376,7 @@ static int dist (void *hw) } } -#define ADVANCE(hw) hw ? advance (hw, audio_state.voice_size) : hw_voice +#define ADVANCE(hw) hw ? advance (hw, audio_state.voice_size) : hw_voices HWVoice *pcm_hw_find_any (HWVoice *hw) { @@ -648,6 +613,21 @@ SWVoice *AUD_open (SWVoice *sw, const char *name, return sw; } +void AUD_close (SWVoice *sw) +{ + if (!sw) + return; + + pcm_sw_fini (sw); + pcm_hw_del_sw (sw->hw, sw); + pcm_hw_gc (sw->hw); + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } + qemu_free (sw); +} + int AUD_write (SWVoice *sw, void *buf, int size) { int bytes; @@ -797,13 +777,13 @@ void AUD_enable (SWVoice *sw, int on) } static struct audio_output_driver *drvtab[] = { -#ifdef USE_OSS_AUDIO +#ifdef CONFIG_OSS &oss_output_driver, #endif #ifdef USE_FMOD_AUDIO &fmod_output_driver, #endif -#ifdef USE_SDL_AUDIO +#ifdef CONFIG_SDL &sdl_output_driver, #endif #ifdef USE_WAV_AUDIO @@ -821,8 +801,8 @@ static int voice_init (struct audio_output_driver *drv) drv->name, audio_state.nb_hw_voices, drv->max_voices); audio_state.nb_hw_voices = drv->max_voices; } - hw_voice = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size); - if (hw_voice) { + hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size); + if (hw_voices) { audio_state.drv = drv; return 1; } @@ -928,8 +908,4 @@ void AUD_init (void) dolog ("Can not initialize audio subsystem\n"); return; } - - for (i = 0; hw_ctors[i]; i++) { - hw_ctors[i] (); - } } diff --git a/audio/audio.h b/audio/audio.h index 926a1bac9..7520383a4 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -26,13 +26,6 @@ #include "mixeng.h" -#define dolog(...) fprintf (stderr, AUDIO_CAP ": " __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif - typedef enum { AUD_FMT_U8, AUD_FMT_S8, @@ -40,130 +33,14 @@ typedef enum { AUD_FMT_S16 } audfmt_e; -typedef struct HWVoice HWVoice; -struct audio_output_driver; - -typedef struct AudioState { - int fixed_format; - int fixed_freq; - int fixed_channels; - int fixed_fmt; - int nb_hw_voices; - int voice_size; - int64_t ticks_threshold; - int freq_threshold; - void *opaque; - struct audio_output_driver *drv; -} AudioState; - -extern AudioState audio_state; - -typedef struct SWVoice { - int freq; - audfmt_e fmt; - int nchannels; - - int shift; - int align; - - t_sample *conv; - - int left; - int pos; - int bytes_per_second; - int64_t ratio; - st_sample_t *buf; - void *rate; - - int wpos; - int live; - int active; - int64_t old_ticks; - HWVoice *hw; - char *name; -} SWVoice; - -#define VOICE_ENABLE 1 -#define VOICE_DISABLE 2 - -struct pcm_ops { - int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt); - void (*fini) (HWVoice *hw); - void (*run) (HWVoice *hw); - int (*write) (SWVoice *sw, void *buf, int size); - int (*ctl) (HWVoice *hw, int cmd, ...); -}; - -struct audio_output_driver { - const char *name; - void *(*init) (void); - void (*fini) (void *); - struct pcm_ops *pcm_ops; - int can_be_default; - int max_voices; - int voice_size; -}; - -struct HWVoice { - int active; - int enabled; - int pending_disable; - int valid; - int freq; - - f_sample *clip; - audfmt_e fmt; - int nchannels; - - int align; - int shift; - - int rpos; - int bufsize; - - int bytes_per_second; - st_sample_t *mix_buf; - - int samples; - int64_t old_ticks; - int nb_voices; - struct SWVoice **pvoice; - struct pcm_ops *pcm_ops; -}; - -void audio_log (const char *fmt, ...); -void pcm_sw_free_resources (SWVoice *sw); -int pcm_sw_alloc_resources (SWVoice *sw); -void pcm_sw_fini (SWVoice *sw); -int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, - int nchannels, audfmt_e fmt); - -void pcm_hw_clear (HWVoice *hw, void *buf, int len); -HWVoice * pcm_hw_find_any (HWVoice *hw); -HWVoice * pcm_hw_find_any_active (HWVoice *hw); -HWVoice * pcm_hw_find_any_passive (HWVoice *hw); -HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq, - int nchannels, audfmt_e fmt); -HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt); -int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw); -int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw); -SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt); - -void pcm_hw_free_resources (HWVoice *hw); -int pcm_hw_alloc_resources (HWVoice *hw); -void pcm_hw_fini (HWVoice *hw); -void pcm_hw_gc (HWVoice *hw); -int pcm_hw_get_live (HWVoice *hw); -int pcm_hw_get_live2 (HWVoice *hw, int *nb_active); -void pcm_hw_dec_live (HWVoice *hw, int decr); -int pcm_hw_write (SWVoice *sw, void *buf, int len); - -int audio_get_conf_int (const char *key, int defval); -const char *audio_get_conf_str (const char *key, const char *defval); +typedef struct SWVoice SWVoice; -/* Public API */ SWVoice * AUD_open (SWVoice *sw, const char *name, int freq, int nchannels, audfmt_e fmt); +void AUD_init (void); +void AUD_log (const char *cap, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3)));; +void AUD_close (SWVoice *sw); int AUD_write (SWVoice *sw, void *pcm_buf, int size); void AUD_adjust (SWVoice *sw, int leftover); void AUD_reset (SWVoice *sw); diff --git a/audio/audio_int.h b/audio/audio_int.h new file mode 100644 index 000000000..599d3b061 --- /dev/null +++ b/audio/audio_int.h @@ -0,0 +1,161 @@ +/* + * QEMU Audio subsystem header + * + * Copyright (c) 2003-2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_AUDIO_INT_H +#define QEMU_AUDIO_INT_H + +#include "vl.h" + +struct pcm_ops; + +typedef struct HWVoice { + int active; + int enabled; + int pending_disable; + int valid; + int freq; + + f_sample *clip; + audfmt_e fmt; + int nchannels; + + int align; + int shift; + + int rpos; + int bufsize; + + int bytes_per_second; + st_sample_t *mix_buf; + + int samples; + int64_t old_ticks; + int nb_voices; + struct SWVoice **pvoice; + struct pcm_ops *pcm_ops; +} HWVoice; + +extern struct pcm_ops oss_pcm_ops; +extern struct audio_output_driver oss_output_driver; + +extern struct pcm_ops sdl_pcm_ops; +extern struct audio_output_driver sdl_output_driver; + +extern struct pcm_ops wav_pcm_ops; +extern struct audio_output_driver wav_output_driver; + +extern struct pcm_ops fmod_pcm_ops; +extern struct audio_output_driver fmod_output_driver; + +struct audio_output_driver { + const char *name; + void *(*init) (void); + void (*fini) (void *); + struct pcm_ops *pcm_ops; + int can_be_default; + int max_voices; + int voice_size; +}; + +typedef struct AudioState { + int fixed_format; + int fixed_freq; + int fixed_channels; + int fixed_fmt; + int nb_hw_voices; + int voice_size; + int64_t ticks_threshold; + int freq_threshold; + void *opaque; + struct audio_output_driver *drv; +} AudioState; +extern AudioState audio_state; + +struct SWVoice { + int freq; + audfmt_e fmt; + int nchannels; + + int shift; + int align; + + t_sample *conv; + + int left; + int pos; + int bytes_per_second; + int64_t ratio; + st_sample_t *buf; + void *rate; + + int wpos; + int live; + int active; + int64_t old_ticks; + HWVoice *hw; + char *name; +}; + +struct pcm_ops { + int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt); + void (*fini) (HWVoice *hw); + void (*run) (HWVoice *hw); + int (*write) (SWVoice *sw, void *buf, int size); + int (*ctl) (HWVoice *hw, int cmd, ...); +}; + +void pcm_sw_free_resources (SWVoice *sw); +int pcm_sw_alloc_resources (SWVoice *sw); +void pcm_sw_fini (SWVoice *sw); +int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, + int nchannels, audfmt_e fmt); + +void pcm_hw_clear (HWVoice *hw, void *buf, int len); +HWVoice * pcm_hw_find_any (HWVoice *hw); +HWVoice * pcm_hw_find_any_active (HWVoice *hw); +HWVoice * pcm_hw_find_any_passive (HWVoice *hw); +HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq, + int nchannels, audfmt_e fmt); +HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt); +int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw); +int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw); +SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt); + +void pcm_hw_free_resources (HWVoice *hw); +int pcm_hw_alloc_resources (HWVoice *hw); +void pcm_hw_fini (HWVoice *hw); +void pcm_hw_gc (HWVoice *hw); +int pcm_hw_get_live (HWVoice *hw); +int pcm_hw_get_live2 (HWVoice *hw, int *nb_active); +void pcm_hw_dec_live (HWVoice *hw, int decr); +int pcm_hw_write (SWVoice *sw, void *buf, int len); + +int audio_get_conf_int (const char *key, int defval); +const char *audio_get_conf_str (const char *key, const char *defval); + +struct audio_output_driver; + +#define VOICE_ENABLE 1 +#define VOICE_DISABLE 2 + +#endif /* audio_int.h */ diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index 7457033f9..8245f93fd 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -25,9 +25,22 @@ #include #include "vl.h" -#define AUDIO_CAP "fmod" -#include "audio/audio.h" -#include "audio/fmodaudio.h" +#include "audio/audio_int.h" + +typedef struct FMODVoice { + HWVoice hw; + unsigned int old_pos; + FSOUND_SAMPLE *fmod_sample; + int channel; +} FMODVoice; + + +#define dolog(...) AUD_log ("fmod", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif #define QC_FMOD_DRV "QEMU_FMOD_DRV" #define QC_FMOD_FREQ "QEMU_FMOD_FREQ" diff --git a/audio/fmodaudio.h b/audio/fmodaudio.h deleted file mode 100644 index 9f85c3080..000000000 --- a/audio/fmodaudio.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * QEMU FMOD audio output driver header - * - * Copyright (c) 2004 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_FMODAUDIO_H -#define QEMU_FMODAUDIO_H - -#include - -typedef struct FMODVoice { - struct HWVoice hw; - unsigned int old_pos; - FSOUND_SAMPLE *fmod_sample; - int channel; -} FMODVoice; - -extern struct pcm_ops fmod_pcm_ops; -extern struct audio_output_driver fmod_output_driver; - -#endif /* fmodaudio.h */ diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 9fefaa3a2..6bf8cc40c 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -21,20 +21,32 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - -/* Temporary kludge */ -#if defined __linux__ || (defined _BSD && !defined __APPLE__) -#include -#include "vl.h" - #include #include #include #include +#include +#include "vl.h" + +#include "audio/audio_int.h" + +typedef struct OSSVoice { + HWVoice hw; + void *pcm_buf; + int fd; + int nfrags; + int fragsize; + int mmapped; + int old_optr; +} OSSVoice; -#define AUDIO_CAP "oss" -#include "audio/audio.h" -#include "audio/ossaudio.h" + +#define dolog(...) AUD_log ("oss", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif #define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" #define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" @@ -463,4 +475,3 @@ struct audio_output_driver oss_output_driver = { INT_MAX, sizeof (OSSVoice) }; -#endif diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 4d7585342..6103c4511 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -25,9 +25,18 @@ #include #include "vl.h" -#define AUDIO_CAP "sdl" -#include "audio/audio.h" -#include "audio/sdlaudio.h" +#include "audio/audio_int.h" + +typedef struct SDLVoice { + HWVoice hw; +} SDLVoice; + +#define dolog(...) AUD_log ("sdl", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif #define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES" diff --git a/audio/sdlaudio.h b/audio/sdlaudio.h deleted file mode 100644 index 380d0da2a..000000000 --- a/audio/sdlaudio.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * QEMU SDL audio output driver header - * - * Copyright (c) 2004 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_SDLAUDIO_H -#define QEMU_SDLAUDIO_H - -typedef struct SDLVoice { - struct HWVoice hw; -} SDLVoice; - -extern struct pcm_ops sdl_pcm_ops; -extern struct audio_output_driver sdl_output_driver; - -#endif /* sdlaudio.h */ diff --git a/audio/wavaudio.c b/audio/wavaudio.c index dee4a060d..f8d6acb4a 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -23,9 +23,22 @@ */ #include "vl.h" -#define AUDIO_CAP "wav" -#include "audio/audio.h" -#include "audio/wavaudio.h" +#include "audio/audio_int.h" + +typedef struct WAVVoice { + HWVoice hw; + QEMUFile *f; + int64_t old_ticks; + void *pcm_buf; + int total_samples; +} WAVVoice; + +#define dolog(...) AUD_log ("wav", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif static struct { const char *wav_path; diff --git a/audio/wavaudio.h b/audio/wavaudio.h deleted file mode 100644 index 0b6070be7..000000000 --- a/audio/wavaudio.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * QEMU WAV audio output driver header - * - * Copyright (c) 2004 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_WAVAUDIO_H -#define QEMU_WAVAUDIO_H - -typedef struct WAVVoice { - struct HWVoice hw; - QEMUFile *f; - int64_t old_ticks; - void *pcm_buf; - int total_samples; -} WAVVoice; - -extern struct pcm_ops wav_pcm_ops; -extern struct audio_output_driver wav_output_driver; - -#endif /* wavaudio.h */ diff --git a/configure b/configure index 28cb708ca..9d45ab9db 100755 --- a/configure +++ b/configure @@ -72,6 +72,8 @@ mingw32="no" EXESUF="" gdbstub="yes" slirp="yes" +adlib="no" +oss="no" # OS specific targetos=`uname -s` @@ -81,18 +83,23 @@ mingw32="yes" ;; FreeBSD) bsd="yes" +oss="yes" ;; NetBSD) bsd="yes" +oss="yes" ;; OpenBSD) bsd="yes" +oss="yes" ;; Darwin) bsd="yes" darwin="yes" ;; -*) ;; +*) +oss="yes" +;; esac if [ "$bsd" = "yes" ] ; then @@ -147,6 +154,8 @@ for opt do ;; --disable-slirp) slirp="no" ;; + --enable-adlib) adlib="yes" + ;; esac done @@ -316,6 +325,7 @@ echo "static build $static" echo "SDL support $sdl" echo "SDL static link $sdl_static" echo "mingw32 support $mingw32" +echo "Adlib support $adlib" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support" @@ -416,6 +426,14 @@ 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 echo -n "VERSION=" >>$config_mak head $source_path/VERSION >>$config_mak echo "" >>$config_mak diff --git a/hw/adlib.c b/hw/adlib.c index a49b32b53..939a7ed03 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -23,8 +23,12 @@ */ #include "vl.h" -#define AUDIO_CAP "adlib" -#include "audio/audio.h" +#define dolog(...) AUD_log ("adlib", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif #ifdef USE_YMF262 #define HAS_YMF262 1 diff --git a/hw/pc.c b/hw/pc.c index fbcd96980..06ec7b1b6 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -555,8 +555,19 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, DMA_init(0); if (audio_enabled) { - /* no audio supported yet for win32 */ AUD_init(); +#ifdef USE_SB16 + if (sb16_enabled) + SB16_init (); +#endif +#ifdef CONFIG_ADLIB + if (adlib_enabled) + Adlib_init (); +#endif +#ifdef USE_GUS + if (gus_enabled) + GUS_init (); +#endif } floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); diff --git a/hw/sb16.c b/hw/sb16.c index d9320566a..a94e6899e 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -23,12 +23,16 @@ */ #include "vl.h" -/* #define DEBUG */ -#define AUDIO_CAP "sb16" -#include "audio/audio.h" - #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) +#define dolog(...) AUD_log ("sb16", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +/* #define DEBUG */ /* #define DEBUG_SB16_MOST */ #define IO_READ_PROTO(name) \ @@ -511,7 +515,7 @@ static void command (SB16State *s, uint8_t cmd) return; warn: - dolog ("warning command %#x,%d is not trully understood yet\n", + dolog ("warning: command %#x,%d is not trully understood yet\n", cmd, s->needed_bytes); s->cmd = cmd; return; @@ -1172,8 +1176,10 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) qemu_get_be32s (f, &s->mixer_nreg); qemu_get_buffer (f, s->mixer_regs, 256); - if (s->voice) - AUD_reset (s->voice); + if (s->voice) { + AUD_close (s->voice); + s->voice = NULL; + } if (s->dma_running) { if (s->freq) diff --git a/vl.c b/vl.c index 6710e30a4..ec56f7765 100644 --- a/vl.c +++ b/vl.c @@ -122,6 +122,9 @@ NetDriverState nd_table[MAX_NICS]; QEMUTimer *gui_timer; int vm_running; int audio_enabled = 0; +int sb16_enabled = 1; +int adlib_enabled = 1; +int gus_enabled = 1; int pci_enabled = 1; int prep_enabled = 0; int rtc_utc = 1; diff --git a/vl.h b/vl.h index 56927f34e..268f72c56 100644 --- a/vl.h +++ b/vl.h @@ -37,6 +37,7 @@ #include #include #include +#include "audio/audio.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 @@ -112,6 +113,9 @@ void qemu_system_shutdown_request(void); void main_loop_wait(int timeout); extern int audio_enabled; +extern int sb16_enabled; +extern int adlib_enabled; +extern int gus_enabled; extern int ram_size; extern int bios_size; extern int rtc_utc; @@ -554,8 +558,14 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table); int pmac_ide_init (BlockDriverState **hd_table, openpic_t *openpic, int irq); -/* audio.c */ -void AUD_init (void); +/* sb16.c */ +void SB16_init (void); + +/* adlib.c */ +void Adlib_init (void); + +/* gus.c */ +void GUS_init (void); /* dma.c */ typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); -- cgit v1.2.3 From d7382233d8408b2b32809f3783a5083cce14f291 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 10 Nov 2004 00:16:34 +0000 Subject: audio clean up (initial patch by malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1132 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/ossaudio.h | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 audio/ossaudio.h diff --git a/audio/ossaudio.h b/audio/ossaudio.h deleted file mode 100644 index f7d3ebd52..000000000 --- a/audio/ossaudio.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * QEMU OSS audio output driver header - * - * Copyright (c) 2003-2004 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_OSSAUDIO_H -#define QEMU_OSSAUDIO_H - -typedef struct OSSVoice { - struct HWVoice hw; - void *pcm_buf; - int fd; - int nfrags; - int fragsize; - int mmapped; - int old_optr; -} OSSVoice; - -extern struct pcm_ops oss_pcm_ops; -extern struct audio_output_driver oss_output_driver; - -#endif /* ossaudio.h */ -- cgit v1.2.3 From 7372f88dc171775c2918b3a874edf0a1d5266b19 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 11 Nov 2004 16:55:09 +0000 Subject: audio fixes (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1133 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- audio/audio.c | 4 +- audio/audio_int.h | 3 ++ audio/fmodaudio.c | 1 - audio/noaudio.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ audio/ossaudio.c | 5 +-- audio/wavaudio.c | 8 +++- hw/sb16.c | 4 +- 8 files changed, 145 insertions(+), 12 deletions(-) create mode 100644 audio/noaudio.c diff --git a/Makefile.target b/Makefile.target index 5982f0837..c76453850 100644 --- a/Makefile.target +++ b/Makefile.target @@ -274,7 +274,7 @@ VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o SOUND_HW = sb16.o -AUDIODRV = audio.o wavaudio.o +AUDIODRV = audio.o noaudio.o wavaudio.o ifdef CONFIG_SDL AUDIODRV += sdlaudio.o endif diff --git a/audio/audio.c b/audio/audio.c index ec77c259e..80170b96d 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -183,7 +183,6 @@ int pcm_hw_alloc_resources (HWVoice *hw) return 0; } - void pcm_hw_fini (HWVoice *hw) { if (hw->active) { @@ -786,6 +785,7 @@ static struct audio_output_driver *drvtab[] = { #ifdef CONFIG_SDL &sdl_output_driver, #endif + &no_output_driver, #ifdef USE_WAV_AUDIO &wav_output_driver, #endif @@ -906,6 +906,6 @@ void AUD_init (void) register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); if (!done) { dolog ("Can not initialize audio subsystem\n"); - return; + voice_init (&no_output_driver); } } diff --git a/audio/audio_int.h b/audio/audio_int.h index 599d3b061..db7fd1a7d 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -55,6 +55,9 @@ typedef struct HWVoice { struct pcm_ops *pcm_ops; } HWVoice; +extern struct pcm_ops no_pcm_ops; +extern struct audio_output_driver no_output_driver; + extern struct pcm_ops oss_pcm_ops; extern struct audio_output_driver oss_output_driver; diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index 8245f93fd..7b79026a8 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -34,7 +34,6 @@ typedef struct FMODVoice { int channel; } FMODVoice; - #define dolog(...) AUD_log ("fmod", __VA_ARGS__) #ifdef DEBUG #define ldebug(...) dolog (__VA_ARGS__) diff --git a/audio/noaudio.c b/audio/noaudio.c new file mode 100644 index 000000000..819de1e53 --- /dev/null +++ b/audio/noaudio.c @@ -0,0 +1,130 @@ +/* + * QEMU NULL audio output driver + * + * Copyright (c) 2004 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#include "audio/audio_int.h" + +typedef struct NoVoice { + HWVoice hw; + int64_t old_ticks; +} NoVoice; + +#define dolog(...) AUD_log ("noaudio", __VA_ARGS__) +#ifdef DEBUG +#define ldebug(...) dolog (__VA_ARGS__) +#else +#define ldebug(...) +#endif + +static void no_hw_run (HWVoice *hw) +{ + NoVoice *no = (NoVoice *) hw; + int rpos, live, decr, samples; + uint8_t *dst; + st_sample_t *src; + int64_t now = qemu_get_clock (vm_clock); + int64_t ticks = now - no->old_ticks; + int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; + + if (bytes > INT_MAX) + samples = INT_MAX >> hw->shift; + else + samples = bytes >> hw->shift; + + live = pcm_hw_get_live (hw); + if (live <= 0) + return; + + no->old_ticks = now; + decr = audio_MIN (live, samples); + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int convert_samples = audio_MIN (samples, left_till_end_samples); + + src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); + memset (src, 0, convert_samples * sizeof (st_sample_t)); + + rpos = (rpos + convert_samples) % hw->samples; + samples -= convert_samples; + } + + pcm_hw_dec_live (hw, decr); + hw->rpos = rpos; +} + +static int no_hw_write (SWVoice *sw, void *buf, int len) +{ + return pcm_hw_write (sw, buf, len); +} + +static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +{ + NoVoice *no = (NoVoice *) hw; + hw->freq = freq; + hw->nchannels = nchannels; + hw->fmt = fmt; + hw->bufsize = 4096; + return 0; +} + +static void no_hw_fini (HWVoice *hw) +{ + (void) hw; +} + +static int no_hw_ctl (HWVoice *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +static void *no_audio_init (void) +{ + return &no_audio_init; +} + +static void no_audio_fini (void *opaque) +{ +} + +struct pcm_ops no_pcm_ops = { + no_hw_init, + no_hw_fini, + no_hw_run, + no_hw_write, + no_hw_ctl +}; + +struct audio_output_driver no_output_driver = { + "none", + no_audio_init, + no_audio_fini, + &no_pcm_ops, + 1, + 1, + sizeof (NoVoice) +}; diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 6bf8cc40c..79b1e8a5b 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -40,7 +40,6 @@ typedef struct OSSVoice { int old_optr; } OSSVoice; - #define dolog(...) AUD_log ("oss", __VA_ARGS__) #ifdef DEBUG #define ldebug(...) dolog (__VA_ARGS__) @@ -371,9 +370,7 @@ static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) if (oss->pcm_buf == MAP_FAILED) { dolog ("Failed to mmap OSS device\nReason: %s\n", errstr ()); - } - - for (;;) { + } else for (;;) { int err; int trig = 0; if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { diff --git a/audio/wavaudio.c b/audio/wavaudio.c index f8d6acb4a..5680161c7 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -55,7 +55,6 @@ static void wav_hw_run (HWVoice *hw) int64_t now = qemu_get_clock (vm_clock); int64_t ticks = now - wav->old_ticks; int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; - wav->old_ticks = now; if (bytes > INT_MAX) samples = INT_MAX >> hw->shift; @@ -66,6 +65,7 @@ static void wav_hw_run (HWVoice *hw) if (live <= 0) return; + wav->old_ticks = now; decr = audio_MIN (live, samples); samples = decr; rpos = hw->rpos; @@ -94,7 +94,6 @@ static int wav_hw_write (SWVoice *sw, void *buf, int len) return pcm_hw_write (sw, buf, len); } - /* VICE code: Store number as little endian. */ static void le_store (uint8_t *buf, uint32_t val, int len) { @@ -145,6 +144,8 @@ static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) if (!wav->f) { dolog ("failed to open wave file `%s'\nReason: %s\n", conf.wav_path, strerror (errno)); + qemu_free (wav->pcm_buf); + wav->pcm_buf = NULL; return -1; } @@ -175,6 +176,9 @@ static void wav_hw_fini (HWVoice *hw) fclose (wav->f); wav->f = NULL; + + qemu_free (wav->pcm_buf); + wav->pcm_buf = NULL; } static int wav_hw_ctl (HWVoice *hw, int cmd, ...) diff --git a/hw/sb16.c b/hw/sb16.c index a94e6899e..8973c5ef2 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -640,8 +640,8 @@ static void complete (SB16State *s) s->freq = 11025; samples = dsp_get_lohi (s); bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); - ticks = ticks_per_sec / (s->freq / bytes); - if (ticks < ticks_per_sec / 1024) + ticks = bytes ? (ticks_per_sec / (s->freq / bytes)) : 0; + if (!bytes || ticks < ticks_per_sec / 1024) pic_set_irq (s->irq, 1); else qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + ticks); -- cgit v1.2.3 From 9746b15b4ecd4702410a2769f6d18a67dbd0872d Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 11 Nov 2004 18:30:24 +0000 Subject: 'info mem' monitor command fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1134 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index ee1912845..bb2124631 100644 --- a/monitor.c +++ b/monitor.c @@ -764,13 +764,15 @@ static void tlb_info(void) static void mem_print(uint32_t *pstart, int *plast_prot, uint32_t end, int prot) { - if (prot != *plast_prot) { + int prot1; + prot1 = *plast_prot; + if (prot != prot1) { if (*pstart != -1) { term_printf("%08x-%08x %08x %c%c%c\n", *pstart, end, end - *pstart, - prot & PG_USER_MASK ? 'u' : '-', + prot1 & PG_USER_MASK ? 'u' : '-', 'r', - prot & PG_RW_MASK ? 'w' : '-'); + prot1 & PG_RW_MASK ? 'w' : '-'); } if (prot != 0) *pstart = end; -- cgit v1.2.3 From 61a8c4ec3a39cf8547aba056f03574a5fac31fdd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 15:39:16 +0000 Subject: enter insn fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1135 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + target-i386/exec.h | 1 + target-i386/helper.c | 32 +++++++++++++++++++++++++++++++ target-i386/op.c | 5 +++++ target-i386/translate.c | 18 +++-------------- tests/test-i386.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 92 insertions(+), 16 deletions(-) diff --git a/Changelog b/Changelog index 73b85e5dd..5b2073a53 100644 --- a/Changelog +++ b/Changelog @@ -27,6 +27,7 @@ version 0.6.1: - 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) version 0.6.0: diff --git a/target-i386/exec.h b/target-i386/exec.h index 61af5468e..c0c8ca0db 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -167,6 +167,7 @@ void helper_divl_EAX_T0(uint32_t eip); void helper_idivl_EAX_T0(uint32_t eip); void helper_cmpxchg8b(void); void helper_cpuid(void); +void helper_enter_level(int level, int data32); void helper_sysenter(void); void helper_sysexit(void); void helper_rdtsc(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 41ebaf221..e6686da72 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1068,6 +1068,38 @@ void helper_cpuid(void) } } +void helper_enter_level(int level, int data32) +{ + uint8_t *ssp; + uint32_t esp_mask, esp, ebp; + + esp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + ebp = EBP; + esp = ESP; + if (data32) { + /* 32 bit */ + esp -= 4; + while (--level) { + esp -= 4; + ebp -= 4; + stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask))); + } + esp -= 4; + stl(ssp + (esp & esp_mask), T1); + } else { + /* 16 bit */ + esp -= 2; + while (--level) { + esp -= 2; + ebp -= 2; + stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); + } + esp -= 2; + stw(ssp + (esp & esp_mask), T1); + } +} + void helper_lldt_T0(void) { int selector; diff --git a/target-i386/op.c b/target-i386/op.c index 9ea00a757..21d4d8299 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -695,6 +695,11 @@ void OPPROTO op_cpuid(void) helper_cpuid(); } +void OPPROTO op_enter_level(void) +{ + helper_enter_level(PARAM1, PARAM2); +} + void OPPROTO op_sysenter(void) { helper_sysenter(); diff --git a/target-i386/translate.c b/target-i386/translate.c index bd2a61b0e..5b8f21312 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1690,15 +1690,12 @@ static void gen_popa(DisasContext *s) gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); } -/* NOTE: wrap around in 16 bit not fully handled */ -/* XXX: check this */ static void gen_enter(DisasContext *s, int esp_addend, int level) { - int ot, level1, addend, opsize; + int ot, opsize; ot = s->dflag + OT_WORD; level &= 0x1f; - level1 = level; opsize = 2 << s->dflag; gen_op_movl_A0_ESP(); @@ -1712,19 +1709,10 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); gen_op_st_T0_A0[ot + s->mem_index](); if (level) { - while (level--) { - gen_op_addl_A0_im(-opsize); - gen_op_addl_T0_im(-opsize); - gen_op_st_T0_A0[ot + s->mem_index](); - } - gen_op_addl_A0_im(-opsize); - gen_op_st_T1_A0[ot + s->mem_index](); + gen_op_enter_level(level, s->dflag); } gen_op_mov_reg_T1[ot][R_EBP](); - addend = -esp_addend; - if (level1) - addend -= opsize * (level1 + 1); - gen_op_addl_T1_im(addend); + gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); gen_op_mov_reg_T1[ot][R_ESP](); } diff --git a/tests/test-i386.c b/tests/test-i386.c index 29f0dfa1f..a4bfa34de 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1625,7 +1625,55 @@ void test_self_modifying_code(void) printf("smc_code2(%d) = %d\n", i, smc_code2(i)); } } - + +int enter_stack[4096]; + +#define TEST_ENTER(size, stack_type, level)\ +{\ + int esp_save, esp_val, ebp_val, ebp_save, i;\ + stack_type *ptr, *stack_end, *stack_ptr;\ + memset(enter_stack, 0, sizeof(enter_stack));\ + stack_end = stack_ptr = (stack_type *)(enter_stack + 4096);\ + ebp_val = (long)stack_ptr;\ + for(i=1;i<=32;i++)\ + *--stack_ptr = i;\ + esp_val = (long)stack_ptr;\ + asm("movl %%esp, %[esp_save]\n"\ + "movl %%ebp, %[ebp_save]\n"\ + "movl %[esp_val], %%esp\n"\ + "movl %[ebp_val], %%ebp\n"\ + "enter" size " $12, $" #level "\n"\ + "movl %%esp, %[esp_val]\n"\ + "movl %%ebp, %[ebp_val]\n"\ + "movl %[esp_save], %%esp\n"\ + "movl %[ebp_save], %%ebp\n"\ + : [esp_save] "=r" (esp_save),\ + [ebp_save] "=r" (ebp_save),\ + [esp_val] "=r" (esp_val),\ + [ebp_val] "=r" (ebp_val)\ + : "[esp_val]" (esp_val),\ + "[ebp_val]" (ebp_val));\ + printf("level=%d:\n", level);\ + printf("esp_val=0x%08lx\n", esp_val - (long)stack_end);\ + printf("ebp_val=0x%08lx\n", ebp_val - (long)stack_end);\ + for(ptr = (stack_type *)esp_val; ptr < stack_end; ptr++)\ + printf("%08x\n", ptr[0]);\ +} + +static void test_enter(void) +{ + TEST_ENTER("l", uint32_t, 0); + TEST_ENTER("l", uint32_t, 1); + TEST_ENTER("l", uint32_t, 2); + TEST_ENTER("l", uint32_t, 31); + + TEST_ENTER("w", uint16_t, 0); + TEST_ENTER("w", uint16_t, 1); + TEST_ENTER("w", uint16_t, 2); + TEST_ENTER("w", uint16_t, 31); +} + + static void *call_end __init_call = NULL; int main(int argc, char **argv) @@ -1653,5 +1701,6 @@ int main(int argc, char **argv) test_exceptions(); test_self_modifying_code(); test_single_step(); + test_enter(); return 0; } -- cgit v1.2.3 From 9e89a4be8e8da513d679110cd01062d546a518d2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 15:42:27 +0000 Subject: boot device 'b' is not supported git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1136 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index ec56f7765..6b24871dd 100644 --- a/vl.c +++ b/vl.c @@ -2497,7 +2497,7 @@ void help(void) "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" - "-boot [a|b|c|d] boot on floppy (a, b), hard disk (c) or CD-ROM (d)\n" + "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB [default=%d]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" @@ -2910,7 +2910,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_boot: boot_device = optarg[0]; - if (boot_device != 'a' && boot_device != 'b' && + if (boot_device != 'a' && boot_device != 'c' && boot_device != 'd') { fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device); exit(1); -- cgit v1.2.3 From 15b614700062dde8801762b1cfd4717a63a2cfd9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 16:02:09 +0000 Subject: audio fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1137 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sb16.c | 65 +++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/hw/sb16.c b/hw/sb16.c index 8973c5ef2..33026febb 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -26,15 +26,16 @@ #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) #define dolog(...) AUD_log ("sb16", __VA_ARGS__) + +/* #define DEBUG */ +/* #define DEBUG_SB16_MOST */ + #ifdef DEBUG #define ldebug(...) dolog (__VA_ARGS__) #else #define ldebug(...) #endif -/* #define DEBUG */ -/* #define DEBUG_SB16_MOST */ - #define IO_READ_PROTO(name) \ uint32_t name (void *opaque, uint32_t nport) #define IO_WRITE_PROTO(name) \ @@ -206,8 +207,18 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->freq = (1000000 + (tmp / 2)) / tmp; } - if (-1 != dma_len) - s->block_size = dma_len + 1; + if (dma_len != -1) + s->block_size = dma_len << s->fmt_stereo; + else { + /* This is apparently the only way to make both Act1/PL + and SecondReality/FC work + + Act1 sets block size via command 0x48 and it's an odd number + SR does the same with even number + Both use stereo, and Creatives own documentation states that + 0x48 sets block size in bytes less one.. go figure */ + s->block_size &= ~s->fmt_stereo; + } s->freq >>= s->fmt_stereo; s->left_till_irq = s->block_size; @@ -216,6 +227,9 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->dma_auto = (mask & DMA8_AUTO) != 0; s->align = (1 << s->fmt_stereo) - 1; + if (s->block_size & s->align) + dolog ("warning: unaligned buffer\n"); + ldebug ("freq %d, stereo %d, sign %d, bits %d, " "dma %d, auto %d, fifo %d, high %d\n", s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, @@ -260,8 +274,13 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) s->block_size = dma_len + 1; s->block_size <<= (s->fmt_bits == 16); - if (!s->dma_auto) /* Miles Sound System ? */ + if (!s->dma_auto) { + /* It is clear that for DOOM and auto-init this value + shouldn't take stereo into account, while Miles Sound Systems + setsound.exe with single transfer mode wouldn't work without it + wonders of SB16 yet again */ s->block_size <<= s->fmt_stereo; + } ldebug ("freq %d, stereo %d, sign %d, bits %d, " "dma %d, auto %d, fifo %d, high %d\n", @@ -290,6 +309,8 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16); s->highspeed = 0; s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1; + if (s->block_size & s->align) + dolog ("warning: unaligned buffer\n"); if (s->freq) s->voice = AUD_open (s->voice, "sb16", s->freq, @@ -373,6 +394,10 @@ static void command (SB16State *s, uint8_t cmd) s->block_size = 0; break; + case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */ + control (s, 1); + break; + case 0x20: /* Direct ADC, Juice/PL */ dsp_out_data (s, 0xff); goto warn; @@ -607,9 +632,7 @@ static void complete (SB16State *s) break; case 0x14: - dma_cmd8 (s, 0, dsp_get_lohi (s)); - /* s->can_write = 0; */ - /* qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + (ticks_per_sec * 320) / 1000000); */ + dma_cmd8 (s, 0, dsp_get_lohi (s) + 1); break; case 0x40: @@ -626,22 +649,20 @@ static void complete (SB16State *s) break; case 0x48: - s->block_size = dsp_get_lohi (s); - /* s->highspeed = 1; */ + s->block_size = dsp_get_lohi (s) + 1; ldebug ("set dma block len %d\n", s->block_size); break; case 0x80: { - int samples, bytes; + int freq, samples, bytes; int64_t ticks; - if (-1 == s->freq) - s->freq = 11025; - samples = dsp_get_lohi (s); + freq = s->freq > 0 ? s->freq : 11025; + samples = dsp_get_lohi (s) + 1; bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); - ticks = bytes ? (ticks_per_sec / (s->freq / bytes)) : 0; - if (!bytes || ticks < ticks_per_sec / 1024) + ticks = (bytes * ticks_per_sec) / freq; + if (ticks < ticks_per_sec / 1024) pic_set_irq (s->irq, 1); else qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + ticks); @@ -658,7 +679,7 @@ static void complete (SB16State *s) case 0xe2: d0 = dsp_get_data (s); - dolog ("E2 = %#x\n", d0); + ldebug ("E2 = %#x\n", d0); break; case 0xe4: @@ -967,6 +988,9 @@ static IO_WRITE_PROTO(mixer_write_indexw) static IO_READ_PROTO(mixer_read) { SB16State *s = opaque; +#ifndef DEBUG_SB16_MOST + if (s->mixer_nreg != 0x82) +#endif ldebug ("mixer_read[%#x] -> %#x\n", s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); return s->mixer_regs[s->mixer_nreg]; @@ -1049,8 +1073,9 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) } #ifdef DEBUG_SB16_MOST - ldebug ("pos %5d free %5d size %5d till % 5d copy %5d dma size %5d\n", - dma_pos, free, dma_len, s->left_till_irq, copy, s->block_size); + ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n", + dma_pos, free, dma_len, s->left_till_irq, copy, written, + s->block_size); #endif while (s->left_till_irq <= 0) { -- cgit v1.2.3 From 44a095a77ce7a4708e275df727667898e1e07c19 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 16:02:51 +0000 Subject: mmap audio fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1138 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/ossaudio.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 79b1e8a5b..ee897c9dd 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -370,29 +370,30 @@ static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) if (oss->pcm_buf == MAP_FAILED) { dolog ("Failed to mmap OSS device\nReason: %s\n", errstr ()); - } else for (;;) { + } else { int err; int trig = 0; if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n", errstr ()); - goto fail; } - - trig = PCM_ENABLE_OUTPUT; - if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" - "Reason: %s\n", errstr ()); - goto fail; + else { + trig = PCM_ENABLE_OUTPUT; + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" + "Reason: %s\n", errstr ()); + } + else { + oss->mmapped = 1; + } } - oss->mmapped = 1; - break; - fail: - err = munmap (oss->pcm_buf, hw->bufsize); - if (err) { - dolog ("Failed to unmap OSS device\nReason: %s\n", - errstr ()); + if (!oss->mmapped) { + err = munmap (oss->pcm_buf, hw->bufsize); + if (err) { + dolog ("Failed to unmap OSS device\nReason: %s\n", + errstr ()); + } } } } -- cgit v1.2.3 From a98d49b1368840a4fd3ec58d08b520cff4b1c583 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 16:22:05 +0000 Subject: Mac OS compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1139 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/exec.c b/exec.c index 5f2a87c23..a1553ba10 100644 --- a/exec.c +++ b/exec.c @@ -21,6 +21,7 @@ #ifdef _WIN32 #include #else +#include #include #endif #include -- cgit v1.2.3 From e875c40a15e266a16ff6ef5c2ef686e0799166b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 17:30:35 +0000 Subject: indent fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1140 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index 989aac5d8..ce828699f 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -63,17 +63,17 @@ static struct dma_cont { } dma_controllers[2]; enum { - CMD_MEMORY_TO_MEMORY = 0x01, - CMD_FIXED_ADDRESS = 0x02, - CMD_BLOCK_CONTROLLER = 0x04, - CMD_COMPRESSED_TIME = 0x08, - CMD_CYCLIC_PRIORITY = 0x10, - CMD_EXTENDED_WRITE = 0x20, - CMD_LOW_DREQ = 0x40, - CMD_LOW_DACK = 0x80, - CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS - | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE - | CMD_LOW_DREQ | CMD_LOW_DACK + CMD_MEMORY_TO_MEMORY = 0x01, + CMD_FIXED_ADDRESS = 0x02, + CMD_BLOCK_CONTROLLER = 0x04, + CMD_COMPRESSED_TIME = 0x08, + CMD_CYCLIC_PRIORITY = 0x10, + CMD_EXTENDED_WRITE = 0x20, + CMD_LOW_DREQ = 0x40, + CMD_LOW_DACK = 0x80, + CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS + | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE + | CMD_LOW_DREQ | CMD_LOW_DACK }; @@ -228,13 +228,13 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) #ifdef DEBUG_DMA { int op, ai, dir, opmode; - op = (data >> 2) & 3; - ai = (data >> 4) & 1; - dir = (data >> 5) & 1; - opmode = (data >> 6) & 3; + op = (data >> 2) & 3; + ai = (data >> 4) & 1; + dir = (data >> 5) & 1; + opmode = (data >> 6) & 3; - linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n", - ichan, op, ai, dir, opmode); + linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n", + ichan, op, ai, dir, opmode); } #endif d->regs[ichan].mode = data; -- cgit v1.2.3 From 546fa6abd13240365ffd7afb5fd8795617a9131e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 17:52:01 +0000 Subject: vga font change detection git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1141 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 21 ++++++++++++++++----- hw/vga_int.h | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 3d4312de2..db9e74f19 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -662,7 +662,7 @@ static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr) void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { VGAState *s = opaque; - int memory_map_mode, plane, write_mode, b, func_select; + int memory_map_mode, plane, write_mode, b, func_select, mask; uint32_t write_mask, bit_mask, set_mask; #ifdef DEBUG_VGA_MEM @@ -695,22 +695,26 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) if (s->sr[4] & 0x08) { /* chain 4 mode : simplest access */ plane = addr & 3; - if (s->sr[2] & (1 << plane)) { + mask = (1 << plane); + if (s->sr[2] & mask) { s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM printf("vga: chain4: [0x%x]\n", addr); #endif + s->plane_updated |= mask; /* only used to detect font change */ cpu_physical_memory_set_dirty(s->vram_offset + addr); } } else if (s->gr[5] & 0x10) { /* odd/even mode (aka text mode mapping) */ plane = (s->gr[4] & 2) | (addr & 1); - if (s->sr[2] & (1 << plane)) { + mask = (1 << plane); + if (s->sr[2] & mask) { addr = ((addr & ~1) << 1) | plane; s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM printf("vga: odd/even: [0x%x]\n", addr); #endif + s->plane_updated |= mask; /* only used to detect font change */ cpu_physical_memory_set_dirty(s->vram_offset + addr); } } else { @@ -775,7 +779,9 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) do_write: /* mask data according to sr[2] */ - write_mask = mask16[s->sr[2]]; + mask = s->sr[2]; + s->plane_updated |= mask; /* only used to detect font change */ + write_mask = mask16[mask]; ((uint32_t *)s->vram_ptr)[addr] = (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | (val & write_mask); @@ -1088,7 +1094,12 @@ static void vga_draw_text(VGAState *s, int full_update) s->font_offsets[1] = offset; full_update = 1; } - + if (s->plane_updated & (1 << 2)) { + /* if the plane 2 was modified since the last display, it + indicates the font may have been modified */ + s->plane_updated = 0; + full_update = 1; + } full_update |= update_basic_params(s); line_offset = s->line_offset; diff --git a/hw/vga_int.h b/hw/vga_int.h index b86219cc1..2e7fb30ef 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -116,6 +116,7 @@ uint32_t line_offset; \ uint32_t line_compare; \ uint32_t start_addr; \ + uint32_t plane_updated; \ uint8_t last_cw, last_ch; \ uint32_t last_width, last_height; /* in chars or pixels */ \ uint32_t last_scr_width, last_scr_height; /* in pixels */ \ -- cgit v1.2.3 From ef6ff6b71e9be413acaa5f34805990739077f336 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 18:58:04 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1142 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/slirp/slirp.h b/slirp/slirp.h index fb55ad9c3..1bb189d4b 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -331,6 +331,7 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err); #endif #ifdef _WIN32 +#undef errno #define errno (WSAGetLastError()) #endif -- cgit v1.2.3 From 53360e00e2a833b04554a359b2359e796a401eed Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 18:58:40 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1143 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/TODO b/TODO index bde7fcbd3..b8e973ce4 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,11 @@ short term: ---------- - debug option in 'configure' script + disable -fomit-frame-pointer -- VGA font change fix -- PIC spurious interrupt patch -- VNC keyboard patch +- Solaris display error with Cirrus VGA + (http://lists.gnu.org/archive/html/qemu-devel/2004-10/msg00390.html). +- Precise VGA timings for old games/demos (malc patch) +- merge PIC spurious interrupt patch +- merge VNC keyboard patch - merge Solaris patch - merge ARM patches + self modifying code patch (Paul Brook) - warning for OS/2: must not use 128 MB memory -- cgit v1.2.3 From 9f059eca52670b0fb2cc4562e97358331672fc0e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 18:59:52 +0000 Subject: win32/SDL build fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1144 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +++ audio/sdlaudio.c | 4 ++-- configure | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index c76453850..81a2dfb55 100644 --- a/Makefile.target +++ b/Makefile.target @@ -343,6 +343,9 @@ $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a sdl.o: sdl.c $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< +sdlaudio.o: sdlaudio.c + $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< + depend: $(SRCS) $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 6103c4511..d6e13d03c 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include +#include +#include #include "vl.h" #include "audio/audio_int.h" diff --git a/configure b/configure index 9d45ab9db..192cb56df 100755 --- a/configure +++ b/configure @@ -172,6 +172,7 @@ if test "$mingw32" = "yes" ; then target_list="i386-softmmu ppc-softmmu sparc-softmmu" EXESUF=".exe" gdbstub="no" + oss="no" fi if test -z "$cross_prefix" ; then -- cgit v1.2.3 From bf2b84e4a728cb33337762c331b2ef92248e711a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 19:46:35 +0000 Subject: better ctrl-alt handling, at least for SDL/X11 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1145 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdl.c b/sdl.c index f1b4726cc..344dfae68 100644 --- a/sdl.c +++ b/sdl.c @@ -492,7 +492,7 @@ static void sdl_refresh(DisplayState *ds) } } } else if (ev->type == SDL_KEYUP) { - mod_state = (SDL_GetModState() & gui_grab_code); + mod_state = (ev->key.keysym.mod & gui_grab_code); if (!mod_state) { if (gui_key_modifier_pressed) { if (gui_keysym == 0) { -- cgit v1.2.3 From c76338c34f807458c299c44f43e41d276d84e6e8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 19:52:18 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1146 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index 5b2073a53..cebbbc8a3 100644 --- a/Changelog +++ b/Changelog @@ -28,6 +28,8 @@ version 0.6.1: - 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: -- cgit v1.2.3 From 102a52e4712aeac3bad0ed25755ff2c96f4ff794 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 19:57:29 +0000 Subject: FMOD configure options (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1147 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 13 +++---------- audio/audio.c | 3 +-- configure | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Makefile.target b/Makefile.target index 81a2dfb55..5690adcdc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -1,11 +1,5 @@ include config.mak -#Uncomment following and specify proper paths/names for FMOD support -#USE_FMOD=1 -#FMOD_INCLUDE=/net/include/fmod -#FMOD_LIBPATH=/net/lib -#FMOD_VERSION=3.74 - TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH) @@ -288,11 +282,10 @@ ifdef CONFIG_ADLIB SOUND_HW += fmopl.o adlib.o endif -ifeq ($(USE_FMOD),1) +ifdef CONFIG_FMOD AUDIODRV += fmodaudio.o -audio.o fmodaudio.o: DEFINES := -DUSE_FMOD_AUDIO -I$(FMOD_INCLUDE) $(DEFINES) -LDFLAGS += -L$(FMOD_LIBPATH) -Wl,-rpath,$(FMOD_LIBPATH) -LIBS += -lfmod-$(FMOD_VERSION) +audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES) +LIBS += $(CONFIG_FMOD_LIB) endif ifeq ($(TARGET_ARCH), i386) diff --git a/audio/audio.c b/audio/audio.c index 80170b96d..661771e82 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -24,7 +24,6 @@ #include #include "vl.h" -#define USE_SDL_AUDIO #define USE_WAV_AUDIO #include "audio/audio_int.h" @@ -779,7 +778,7 @@ static struct audio_output_driver *drvtab[] = { #ifdef CONFIG_OSS &oss_output_driver, #endif -#ifdef USE_FMOD_AUDIO +#ifdef CONFIG_FMOD &fmod_output_driver, #endif #ifdef CONFIG_SDL diff --git a/configure b/configure index 192cb56df..bf7e0bf27 100755 --- a/configure +++ b/configure @@ -74,6 +74,9 @@ gdbstub="yes" slirp="yes" adlib="no" oss="no" +fmod="no" +fmod_lib="" +fmod_inc="" # OS specific targetos=`uname -s` @@ -150,6 +153,12 @@ for opt do ;; --disable-sdl) sdl="no" ;; + --enable-fmod) fmod="yes" + ;; + --fmod-lib=*) fmod_lib=${opt#--fmod-lib=} + ;; + --fmod-inc=*) fmod_inc=${opt#--fmod-inc=} + ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ;; --disable-slirp) slirp="no" @@ -285,6 +294,9 @@ echo " --cc=CC use C compiler CC [$cc]" echo " --make=MAKE use specified make [$make]" echo " --static enable static build [$static]" echo " --enable-mingw32 enable Win32 cross compilation with mingw32" +echo " --enable-fmod enable FMOD audio output driver" +echo " --fmod-lib path to FMOD library" +echo " --fmod-inc path to FMOD includes" echo "" echo "NOTE: The object files are build at the place where configure is launched" exit 1 @@ -327,6 +339,11 @@ echo "SDL support $sdl" echo "SDL static link $sdl_static" echo "mingw32 support $mingw32" echo "Adlib support $adlib" +echo -n "FMOD support $fmod" +if test $fmod = "yes"; then + echo -n " (lib='$fmod_lib' include='$fmod_inc')" +fi +echo "" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support" @@ -435,6 +452,12 @@ if test "$oss" = "yes" ; then echo "CONFIG_OSS=yes" >> $config_mak echo "#define CONFIG_OSS 1" >> $config_h fi +if test "$fmod" = "yes" ; then + echo "CONFIG_FMOD=yes" >> $config_mak + echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak + echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak + echo "#define CONFIG_FMOD 1" >> $config_h +fi echo -n "VERSION=" >>$config_mak head $source_path/VERSION >>$config_mak echo "" >>$config_mak -- cgit v1.2.3 From c72a345f5bf710009ad90f0b2a7e9df1e66996d1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 Nov 2004 20:52:54 +0000 Subject: do not remove docs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1148 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d4d8028f3..c9c7e9bc8 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ clean: done distclean: clean - rm -f config-host.mak config-host.h $(DOCS) + rm -f config-host.mak config-host.h for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ done -- cgit v1.2.3 From c9c0eae84e788a13321e92356ca1c69829bb271b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 15 Nov 2004 21:43:57 +0000 Subject: bitblt fix (aka Solaris display fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1150 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 7c34c5789..d3eba4a34 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -737,7 +737,8 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s) else s->cirrus_blt_srcpitch = ((w + 7) >> 3); } else { - s->cirrus_blt_srcpitch = s->cirrus_blt_width; + /* always align input size to 32 bits */ + s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3; } s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height; } -- cgit v1.2.3 From acd935ef62283a2469333db0975b7d55c42fd997 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 15 Nov 2004 22:57:26 +0000 Subject: doc update - added qemu-img manual page git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1151 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 2 + Makefile | 13 ++++-- qemu-doc.texi | 81 ++++++++----------------------------- qemu-img.texi | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-mkcow.1 | 105 ------------------------------------------------ 5 files changed, 155 insertions(+), 173 deletions(-) create mode 100644 qemu-img.texi delete mode 100644 qemu-mkcow.1 diff --git a/.cvsignore b/.cvsignore index bca488238..42bc1c754 100644 --- a/.cvsignore +++ b/.cvsignore @@ -10,6 +10,8 @@ qemu-doc.html qemu-tech.html qemu.1 qemu.pod +qemu-img.1 +qemu-img.pod sparc-user qemu-img sparc-softmmu diff --git a/Makefile b/Makefile index c9c7e9bc8..e42222872 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ TOOLS=qemu-img ifdef CONFIG_STATIC LDFLAGS+=-static endif -DOCS=qemu-doc.html qemu-tech.html qemu.1 +DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 all: dyngen$(EXESUF) $(TOOLS) $(DOCS) for d in $(TARGET_DIRS); do \ @@ -30,7 +30,7 @@ dyngen$(EXESUF): dyngen.c 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 qemu.pod *~ */*~ + rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~ $(MAKE) -C tests clean for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ @@ -57,7 +57,7 @@ endif install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" ifndef CONFIG_WIN32 mkdir -p "$(mandir)/man1" - install qemu.1 qemu-mkcow.1 "$(mandir)/man1" + install qemu.1 qemu-img.1 "$(mandir)/man1" endif for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ @@ -78,6 +78,10 @@ qemu.1: qemu-doc.texi ./texi2pod.pl $< qemu.pod pod2man --section=1 --center=" " --release=" " qemu.pod > $@ +qemu-img.1: qemu-img.texi + ./texi2pod.pl $< qemu-img.pod + pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@ + FILE=qemu-$(shell cat VERSION) # tar release (use 'make -k tar' on a checkouted tree) @@ -92,6 +96,7 @@ tarbin: ( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \ $(bindir)/qemu $(bindir)/qemu-fast \ $(bindir)/qemu-system-ppc \ + $(bindir)/qemu-system-sparc \ $(bindir)/qemu-i386 \ $(bindir)/qemu-arm \ $(bindir)/qemu-sparc \ @@ -105,7 +110,7 @@ tarbin: $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ - $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-mkcow.1 ) + $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 ) ifneq ($(wildcard .depend),) include .depend diff --git a/qemu-doc.texi b/qemu-doc.texi index c262ee7e9..732f40f36 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -584,81 +584,34 @@ CPU registers by prefixing them with @emph{$}. @node disk_images @section Disk Images -@subsection Raw disk images +Since version 0.6.1, QEMU supports many disk image formats, including +growable disk images (their size increase as non empty sectors are +written), compressed and encrypted disk images. -The disk images can simply be raw images of the hard disk. You can -create them with the command: +@subsection Quick start for disk image creation + +You can create a disk image with the command: @example -dd of=myimage bs=1024 seek=mysize count=0 +qemu-img create myimage.img mysize @end example -where @var{myimage} is the image filename and @var{mysize} is its size -in kilobytes. +where @var{myimage.img} is the disk image filename and @var{mysize} is its +size in kilobytes. You can add an @code{M} suffix to give the size in +megabytes and a @code{G} suffix for gigabytes. + +@xref{qemu_img_invocation} for more information. @subsection Snapshot mode If you use the option @option{-snapshot}, all disk images are considered as read only. When sectors in written, they are written in a temporary file created in @file{/tmp}. You can however force the -write back to the raw disk images by pressing @key{C-a s}. - -NOTE: The snapshot mode only works with raw disk images. - -@subsection Copy On Write disk images - -QEMU also supports user mode Linux -(@url{http://user-mode-linux.sourceforge.net/}) Copy On Write (COW) -disk images. The COW disk images are much smaller than normal images -as they store only modified sectors. They also permit the use of the -same disk image template for many users. - -To create a COW disk images, use the command: - -@example -qemu-mkcow -f myrawimage.bin mycowimage.cow -@end example - -@file{myrawimage.bin} is a raw image you want to use as original disk -image. It will never be written to. - -@file{mycowimage.cow} is the COW disk image which is created by -@code{qemu-mkcow}. You can use it directly with the @option{-hdx} -options. You must not modify the original raw disk image if you use -COW images, as COW images only store the modified sectors from the raw -disk image. QEMU stores the original raw disk image name and its -modified time in the COW disk image so that chances of mistakes are -reduced. - -If the raw disk image is not read-only, by pressing @key{C-a s} you -can flush the COW disk image back into the raw disk image, as in -snapshot mode. +write back to the raw disk images by using the @code{commit} monitor +command (or @key{C-a s} in the serial console). -COW disk images can also be created without a corresponding raw disk -image. It is useful to have a big initial virtual disk image without -using much disk space. Use: +@node qemu_img_invocation +@subsection @code{qemu-img} Invocation -@example -qemu-mkcow mycowimage.cow 1024 -@end example - -to create a 1 gigabyte empty COW disk image. - -NOTES: -@enumerate -@item -COW disk images must be created on file systems supporting -@emph{holes} such as ext2 or ext3. -@item -Since holes are used, the displayed size of the COW disk image is not -the real one. To know it, use the @code{ls -ls} command. -@end enumerate - -@subsection Convert VMware disk images to raw disk images - -You can use the tool @file{vmdk2raw} to convert VMware disk images to -raw disk images directly usable by QEMU. The syntax is: -@example -vmdk2raw vmware_image output_image -@end example +@include qemu-img.texi @section Network emulation diff --git a/qemu-img.texi b/qemu-img.texi new file mode 100644 index 000000000..3afd32085 --- /dev/null +++ b/qemu-img.texi @@ -0,0 +1,127 @@ +@example +@c man begin SYNOPSIS +usage: qemu-img command [command options] +@c man end +@end example + +@c man begin OPTIONS + +The following commands are supported: +@table @option +@item create [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] +@item commit [-f @var{fmt}] @var{filename} +@item convert [-c] [-e] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename} +@item info [-f @var{fmt}] @var{filename} +@end table + +Command parameters: +@table @var +@item filename + is a disk image filename +@item base_image +is the read-only disk image which is used as base for a copy on + write image; the copy on write image only stores the modified data + +@item fmt +is the disk image format. It is guessed automatically in most cases. The following formats are supported: + +@table @code +@item raw + +Raw disk image format (default). This format has the advantage of +being simple and easily exportable to all other emulators. If your file +system supports @emph{holes} (for example in ext2 or ext3 on Linux), +then only the written sectors will reserve space. Use @code{qemu-img +info} to know the real size used by the image or @code{ls -ls} on +Unix/Linux. + +@item qcow +QEMU image format, the most versatile format. Use it to have smaller +images (useful if your filesystem does not supports holes, for example +on Windows), optional AES encryption and zlib based compression. +@item cow +User Mode Linux Copy On Write image format. Used to be the only growable +image format in QEMU. It is supported only for compatibility with +previous versions. It does not work on win32. +@item vmdk +VMware 3 and 4 compatible image format. Currently only supported as +read-only. +@item cloop +Linux Compressed Loop image, useful only to reuse directly compressed +CD-ROM images present for example in the Knoppix CD-ROMs. +@end table + +@item size +is the disk image size in kilobytes. Optional suffixes @code{M} +(megabyte) and @code{G} (gigabyte) are supported + +@item output_filename +is the destination disk image filename + +@item output_fmt + is the destination format + +@item -c +indicates that target image must be compressed (qcow format only) +@item -e +indicates that the target image must be encrypted (qcow format only) +@end table + +Command description: + +@table @option +@item create [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] + +Create the new disk image @var{filename} of size @var{size} and format +@var{fmt}. + +If @var{base_image} is specified, then the image will record only the +differences from @var{base_image}. No size needs to be specified in +this case. @var{base_image} will never be modified unless you use the +@code{commit} monitor command. + +@item commit [-f @var{fmt}] @var{filename} + +Commit the changes recorded in @var{filename} in its base image. + +@item convert [-c] [-e] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename} + +Convert the disk image @var{filename} to disk image @var{output_filename} +using format @var{output_fmt}. It can be optionnaly encrypted +(@code{-e} option) or compressed (@code{-c} option). + +Only the format @code{qcow} supports encryption or compression. The +compression is read-only. It means that if a compressed sector is +rewritten, then it is rewritten as uncompressed data. + +Encryption uses the AES format which is very secure (128 bit keys). Use +a long password (16 characters) to get maximum protection. + +Image conversion is also useful to get smaller image when using a +growable format such as @code{qcow} or @code{cow}: the empty sectors +are detected and suppressed from the destination image. + +@item info [-f @var{fmt}] @var{filename} + +Give information about the disk image @var{filename}. Use it in +particular to know the size reserved on disk which can be different +from the displayed size. +@end table + +@c man end + +@ignore + +@setfilename qemu-img +@settitle QEMU disk image utility + +@c man begin SEEALSO +The HTML documentation of QEMU for more precise information and Linux +user mode emulator invocation. +@c man end + +@c man begin AUTHOR +Fabrice Bellard +@c man end + +@end ignore diff --git a/qemu-mkcow.1 b/qemu-mkcow.1 deleted file mode 100644 index 5e1a6812b..000000000 --- a/qemu-mkcow.1 +++ /dev/null @@ -1,105 +0,0 @@ -.\" $Header: /home/paul/qemu/svnmerge/qemu-cvs/qemu/qemu-mkcow.1,v 1.1 2004-03-26 22:42:54 bellard Exp $ -.\" -.\" transcript compatibility for postscript use. -.\" -.\" synopsis: .P! -.\" -.de P! -.fl -\!!1 setgray -.fl -\\&.\" -.fl -\!!0 setgray -.fl \" force out current output buffer -\!!save /psv exch def currentpoint translate 0 0 moveto -\!!/showpage{}def -.fl \" prolog -.sy sed -e 's/^/!/' \\$1\" bring in postscript file -\!!psv restore -. -.de pF -.ie \\*(f1 .ds f1 \\n(.f -.el .ie \\*(f2 .ds f2 \\n(.f -.el .ie \\*(f3 .ds f3 \\n(.f -.el .ie \\*(f4 .ds f4 \\n(.f -.el .tm ? font overflow -.ft \\$1 -.. -.de fP -.ie !\\*(f4 \{\ -. ft \\*(f4 -. ds f4\" -' br \} -.el .ie !\\*(f3 \{\ -. ft \\*(f3 -. ds f3\" -' br \} -.el .ie !\\*(f2 \{\ -. ft \\*(f2 -. ds f2\" -' br \} -.el .ie !\\*(f1 \{\ -. ft \\*(f1 -. ds f1\" -' br \} -.el .tm ? font underflow -.. -.ds f1\" -.ds f2\" -.ds f3\" -.ds f4\" -'\" t -.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n -.TH "QEMU" "8" -.SH "NAME" -qemu-mkcow \(em create a copy-on-write file for qemu -.SH "SYNOPSIS" -.PP -\fBqemu-mkcow\fR [\fB-h\fP] [\fB-f \fImaster_disk_image\fR\fP] [\fIcow_image\fR] [\fB\fIcow_size\fR\fP] -.SH "DESCRIPTION" -.PP -The \fBqemu-mkcow\fR command creates a -persistent copy-on-write file for \fBqemu\fR. - -.PP -\fBqemu\fR can be used in a "copy-on-write" mode, -where changes made by \fBqemu\fR do not actually -change the disk image file. One way is to invoke -\fBqemu\fR with -snapshot: these changes -are stored in a temporary file, which is discarded when -\fBqemu\fR exits. - -.PP -\fBqemu-mkcow\fR creates an explicit copy-on-write -file where changes are to be stored: this way, changes made -inside \fBqemu\fR will still be there next time you -run it, although the master disk image isn't ever changed. - -.PP -The usual method is to create the master image, then create a -copy-on-write file using \fBqemu-mkcow\fR with -\fB-f\fP. The filename of the master image is stored -inside the generated copy-on-write file: it must not be modified -after this is run! - -.PP -If no master file is specified, the effect is that of a -blank master of size \fIcow_size\fR. - -.SH "SEE ALSO" -.PP -qemu(1), qemu-fast(1). -.SH "AUTHOR" -.PP -This manual page was written by Paul Russell prussell@debian.org for -the \fBDebian\fP system (but may be used by others). Permission is -granted to copy, distribute and/or modify this document under -the terms of the GNU General Public License, Version 2 any -later version published by the Free Software Foundation. - -.PP -On Debian systems, the complete text of the GNU General Public -License can be found in /usr/share/common-licenses/GPL. - -.\" created by instant / docbook-to-man, Fri 12 Mar 2004, 05:58 -- cgit v1.2.3 From e35c55fe38faea68eb9356163f52a426e533d79b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 16 Nov 2004 01:44:03 +0000 Subject: windows install fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1152 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e42222872..094b39590 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ endif LDFLAGS=-g LIBS= DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -TOOLS=qemu-img +TOOLS=qemu-img$(EXESUF) ifdef CONFIG_STATIC LDFLAGS+=-static endif @@ -21,7 +21,7 @@ all: dyngen$(EXESUF) $(TOOLS) $(DOCS) $(MAKE) -C $$d $@ || exit 1 ; \ done -qemu-img: qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c +qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c @@ -44,9 +44,7 @@ distclean: clean install: all mkdir -p "$(bindir)" -ifndef CONFIG_WIN32 install -m 755 -s $(TOOLS) "$(bindir)" -endif mkdir -p "$(datadir)" install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/vgabios-cirrus.bin \ -- cgit v1.2.3 From 46d4767d93bcb2e84869ba6d2344ebff4382be86 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 16 Nov 2004 01:45:27 +0000 Subject: better BIOS ATA translation support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1153 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 10 ++++++++++ block_int.h | 2 +- hw/ide.c | 21 +++++++++++++++------ hw/pc.c | 28 ++++++++++++++++------------ qemu-doc.texi | 6 ++++++ vl.c | 31 ++++++++++++++++++++++++++----- vl.h | 5 +++++ 7 files changed, 79 insertions(+), 24 deletions(-) diff --git a/block.c b/block.c index 0e42b5e0d..a77a3e55b 100644 --- a/block.c +++ b/block.c @@ -348,6 +348,11 @@ void bdrv_set_type_hint(BlockDriverState *bs, int type) 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) { @@ -361,6 +366,11 @@ 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; diff --git a/block_int.h b/block_int.h index 9d047c4ff..03744f734 100644 --- a/block_int.h +++ b/block_int.h @@ -68,7 +68,7 @@ struct BlockDriverState { /* NOTE: the following infos are only hints for real hardware drivers. They are not used by the block driver */ - int cyls, heads, secs; + int cyls, heads, secs, translation; int type; char device_name[32]; BlockDriverState *next; diff --git a/hw/ide.c b/hw/ide.c index bc7ebd320..e922e7ba7 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1826,11 +1826,11 @@ struct partition { uint32_t nr_sects; /* nr of sectors in partition */ } __attribute__((packed)); -/* try to guess the IDE geometry from the MSDOS partition table */ +/* try to guess the IDE physical geometry from the MSDOS partition table */ static void ide_guess_geometry(IDEState *s) { uint8_t buf[512]; - int ret, i; + int ret, i, heads, sectors, cylinders; struct partition *p; uint32_t nr_sects; @@ -1848,9 +1848,18 @@ static void ide_guess_geometry(IDEState *s) if (nr_sects && p->end_head) { /* We make the assumption that the partition terminates on a cylinder boundary */ - s->heads = p->end_head + 1; - s->sectors = p->end_sector & 63; - s->cylinders = s->nb_sectors / (s->heads * s->sectors); + heads = p->end_head + 1; + if (heads < 1 || heads > 16) + continue; + sectors = p->end_sector & 63; + if (sectors == 0) + continue; + cylinders = s->nb_sectors / (heads * sectors); + if (cylinders < 1 || cylinders > 16383) + continue; + s->heads = heads; + s->sectors = sectors; + s->cylinders = cylinders; #if 0 printf("guessed partition: CHS=%d %d %d\n", s->cylinders, s->heads, s->sectors); @@ -1885,7 +1894,7 @@ static void ide_init2(IDEState *ide_state, int irq, } else { ide_guess_geometry(s); if (s->cylinders == 0) { - /* if no geometry, use a LBA compatible one */ + /* if no geometry, use a standard physical disk geometry */ cylinders = nb_sectors / (16 * 63); if (cylinders > 16383) cylinders = 16383; diff --git a/hw/pc.c b/hw/pc.c index 06ec7b1b6..64b6180a3 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -217,19 +217,23 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table val = 0; for (i = 0; i < 4; i++) { if (hd_table[i]) { - int cylinders, heads, sectors; - uint8_t translation; - /* NOTE: bdrv_get_geometry_hint() returns the geometry - that the hard disk returns. It is always such that: 1 <= - sects <= 63, 1 <= heads <= 16, 1 <= cylinders <= - 16383. The BIOS geometry can be different. */ - bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors); - if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { - /* No translation. */ - translation = 0; + int cylinders, heads, sectors, translation; + /* NOTE: bdrv_get_geometry_hint() returns the physical + geometry. It is always such that: 1 <= sects <= 63, 1 + <= heads <= 16, 1 <= cylinders <= 16383. The BIOS + geometry can be different if a translation is done. */ + translation = bdrv_get_translation_hint(hd_table[i]); + if (translation == BIOS_ATA_TRANSLATION_AUTO) { + bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors); + if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { + /* No translation. */ + translation = 0; + } else { + /* LBA translation. */ + translation = 1; + } } else { - /* LBA translation. */ - translation = 1; + translation--; } val |= translation << (i * 2); } diff --git a/qemu-doc.texi b/qemu-doc.texi index 732f40f36..9436965eb 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -343,6 +343,12 @@ Change gdb connection port. Do not start CPU at startup (you must type 'c' in the monitor). @item -d Output log in /tmp/qemu.log +@item -hdachs c,h,s,[,t] +Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= +@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS +translation mode (@var{t}=none, lba or auto). Usually QEMU can guess +all thoses parameters. This option is useful for old MS-DOS disk +images. @item -isa Simulate an ISA-only system (default is PCI system). @item -std-vga diff --git a/vl.c b/vl.c index 6b24871dd..018fc3143 100644 --- a/vl.c +++ b/vl.c @@ -2537,7 +2537,8 @@ void help(void) "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" "-d item1,... output log to %s (use -d ? for a list of log items)\n" - "-hdachs c,h,s force hard disk 0 geometry (usually qemu can guess it)\n" + "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n" + " translation (t=none or lba) (usually qemu can guess them)\n" "-L path set the directory for the BIOS and VGA BIOS\n" #ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n" @@ -2753,7 +2754,7 @@ int main(int argc, char **argv) const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; - int cyls, heads, secs; + int cyls, heads, secs, translation; int start_emulation = 1; uint8_t macaddr[6]; int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; @@ -2788,6 +2789,7 @@ int main(int argc, char **argv) kernel_cmdline = ""; has_cdrom = 1; cyls = heads = secs = 0; + translation = BIOS_ATA_TRANSLATION_AUTO; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "vc"); @@ -2857,17 +2859,34 @@ int main(int argc, char **argv) const char *p; p = optarg; cyls = strtol(p, (char **)&p, 0); + if (cyls < 1 || cyls > 16383) + goto chs_fail; if (*p != ',') goto chs_fail; p++; heads = strtol(p, (char **)&p, 0); + if (heads < 1 || heads > 16) + goto chs_fail; if (*p != ',') goto chs_fail; p++; secs = strtol(p, (char **)&p, 0); - if (*p != '\0') { + if (secs < 1 || secs > 63) + goto chs_fail; + if (*p == ',') { + p++; + if (!strcmp(p, "none")) + translation = BIOS_ATA_TRANSLATION_NONE; + else if (!strcmp(p, "lba")) + translation = BIOS_ATA_TRANSLATION_LBA; + else if (!strcmp(p, "auto")) + translation = BIOS_ATA_TRANSLATION_AUTO; + else + goto chs_fail; + } else if (*p != '\0') { chs_fail: - cyls = 0; + fprintf(stderr, "qemu: invalid physical CHS format\n"); + exit(1); } } break; @@ -3230,8 +3249,10 @@ int main(int argc, char **argv) hd_filename[i]); exit(1); } - if (i == 0 && cyls != 0) + if (i == 0 && cyls != 0) { bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); + bdrv_set_translation_hint(bs_table[i], translation); + } } } diff --git a/vl.h b/vl.h index 268f72c56..2f69899da 100644 --- a/vl.h +++ b/vl.h @@ -383,13 +383,18 @@ void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); #define BDRV_TYPE_HD 0 #define BDRV_TYPE_CDROM 1 #define BDRV_TYPE_FLOPPY 2 +#define BIOS_ATA_TRANSLATION_AUTO 0 +#define BIOS_ATA_TRANSLATION_NONE 1 +#define BIOS_ATA_TRANSLATION_LBA 2 void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs); void bdrv_set_type_hint(BlockDriverState *bs, int type); +void bdrv_set_translation_hint(BlockDriverState *bs, int translation); void bdrv_get_geometry_hint(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs); int bdrv_get_type_hint(BlockDriverState *bs); +int bdrv_get_translation_hint(BlockDriverState *bs); int bdrv_is_removable(BlockDriverState *bs); int bdrv_is_read_only(BlockDriverState *bs); int bdrv_is_inserted(BlockDriverState *bs); -- cgit v1.2.3 From bf1b938fce39c8837899d11d074e2df983592a5b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 17 Nov 2004 22:35:32 +0000 Subject: disable automatic BIOS translation if the logical disk geometry implies it git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1154 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index e922e7ba7..db7d73744 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1826,22 +1826,21 @@ struct partition { uint32_t nr_sects; /* nr of sectors in partition */ } __attribute__((packed)); -/* try to guess the IDE physical geometry from the MSDOS partition table */ -static void ide_guess_geometry(IDEState *s) +/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ +static int guess_disk_lchs(IDEState *s, + int *pcylinders, int *pheads, int *psectors) { uint8_t buf[512]; int ret, i, heads, sectors, cylinders; struct partition *p; uint32_t nr_sects; - if (s->cylinders != 0) - return; ret = bdrv_read(s->bs, 0, buf, 1); if (ret < 0) - return; + return -1; /* test msdos magic */ if (buf[510] != 0x55 || buf[511] != 0xaa) - return; + return -1; for(i = 0; i < 4; i++) { p = ((struct partition *)(buf + 0x1be)) + i; nr_sects = le32_to_cpu(p->nr_sects); @@ -1849,23 +1848,23 @@ static void ide_guess_geometry(IDEState *s) /* We make the assumption that the partition terminates on a cylinder boundary */ heads = p->end_head + 1; - if (heads < 1 || heads > 16) - continue; sectors = p->end_sector & 63; if (sectors == 0) continue; cylinders = s->nb_sectors / (heads * sectors); if (cylinders < 1 || cylinders > 16383) continue; - s->heads = heads; - s->sectors = sectors; - s->cylinders = cylinders; + *pheads = heads; + *psectors = sectors; + *pcylinders = cylinders; #if 0 - printf("guessed partition: CHS=%d %d %d\n", - s->cylinders, s->heads, s->sectors); + printf("guessed geometry: LCHS=%d %d %d\n", + cylinders, heads, sectors); #endif + return 0; } } + return -1; } static void ide_init2(IDEState *ide_state, int irq, @@ -1873,7 +1872,7 @@ static void ide_init2(IDEState *ide_state, int irq, { IDEState *s; static int drive_serial = 1; - int i, cylinders, heads, secs; + int i, cylinders, heads, secs, translation; int64_t nb_sectors; for(i = 0; i < 2; i++) { @@ -1892,8 +1891,26 @@ static void ide_init2(IDEState *ide_state, int irq, s->heads = heads; s->sectors = secs; } else { - ide_guess_geometry(s); - if (s->cylinders == 0) { + if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) { + if (heads > 16) { + /* if heads > 16, it means that a BIOS LBA + translation was active, so the default + hardware geometry is OK */ + goto default_geometry; + } else { + s->cylinders = cylinders; + s->heads = heads; + s->sectors = secs; + /* disable any translation to be in sync with + the logical geometry */ + translation = bdrv_get_translation_hint(s->bs); + if (translation == BIOS_ATA_TRANSLATION_AUTO) { + bdrv_set_translation_hint(s->bs, + BIOS_ATA_TRANSLATION_NONE); + } + } + } else { + default_geometry: /* if no geometry, use a standard physical disk geometry */ cylinders = nb_sectors / (16 * 63); if (cylinders > 16383) -- cgit v1.2.3 From 17444c9c84fd0c8679499198fd4ee3b155fb297f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Nov 2004 20:02:08 +0000 Subject: fixed invalid received length git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1155 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/socket.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/slirp/socket.c b/slirp/socket.c index fe03d448a..6713c4d5e 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -175,8 +175,12 @@ soread(so) * a close will be detected on next iteration. * A return of -1 wont (shouldn't) happen, since it didn't happen above */ - if (n == 2 && nn == iov[0].iov_len) - nn += recv(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (ret > 0) + nn += ret; + } DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #endif -- cgit v1.2.3 From c169c906a374774bde50834f360821ec6ba9b53a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 24 Nov 2004 19:28:52 +0000 Subject: added undocumented FPU ops support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1156 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index 5b8f21312..1e9bea572 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2958,6 +2958,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fmov_ST0_STN((opreg + 1) & 7); break; case 0x09: /* fxchg sti */ + case 0x29: /* fxchg4 sti, undocumented op */ + case 0x39: /* fxchg7 sti, undocumented op */ gen_op_fxchg_ST0_STN(opreg); break; case 0x0a: /* grp d9/2 */ @@ -3104,10 +3106,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0x02: /* fcom */ + case 0x22: /* fcom2, undocumented op */ gen_op_fmov_FT0_STN(opreg); gen_op_fcom_ST0_FT0(); break; case 0x03: /* fcomp */ + case 0x23: /* fcomp3, undocumented op */ + case 0x32: /* fcomp5, undocumented op */ gen_op_fmov_FT0_STN(opreg); gen_op_fcom_ST0_FT0(); gen_op_fpop(); @@ -3163,6 +3168,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_fmov_STN_ST0(opreg); break; case 0x2b: /* fstp sti */ + case 0x0b: /* fstp1 sti, undocumented op */ + case 0x3a: /* fstp8 sti, undocumented op */ + case 0x3b: /* fstp9 sti, undocumented op */ gen_op_fmov_STN_ST0(opreg); gen_op_fpop(); break; @@ -3187,6 +3195,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; } break; + case 0x38: /* ffreep sti, undocumented op */ + gen_op_ffree_STN(opreg); + gen_op_fpop(); + break; case 0x3c: /* df/4 */ switch(rm) { case 0: -- cgit v1.2.3 From bed5cd8048abbb8e02618082e7f285ff95fc5989 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 24 Nov 2004 19:31:52 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1157 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 6 ++++++ VERSION | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index cebbbc8a3..c89488c60 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +version 0.6.2: + + - better BIOS translation and HDD geometry auto-detection + - user mode networking bug fix + - undocumented FPU ops support + version 0.6.1: - Mac OS X port (Pierre d'Herbemont) diff --git a/VERSION b/VERSION index 7ceb04048..b1d7abc0d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.1 \ No newline at end of file +0.6.2 \ No newline at end of file -- cgit v1.2.3 From 3bc2175dcc62d699c4b0a0b9c6bb2ae37bcb66b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 24 Nov 2004 20:39:26 +0000 Subject: socket send fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1158 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/socket.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/slirp/socket.c b/slirp/socket.c index 6713c4d5e..47ed44b93 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -352,8 +352,12 @@ sowrite(so) } #ifndef HAVE_READV - if (n == 2 && nn == iov[0].iov_len) - nn += send(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (ret > 0) + nn += ret; + } DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #endif -- cgit v1.2.3 From 02cfb0b4f3049a1ce6544d7f04f76de51ad0a1cd Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Nov 2004 23:41:04 +0000 Subject: update to current vga bios version - Cirrus VGA: support for 1280x1024x[8,15,16] modes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1159 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/vgabios-cirrus.bin | Bin 30868 -> 32768 bytes pc-bios/vgabios.bin | Bin 31533 -> 32768 bytes pc-bios/vgabios.diff | 97 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 pc-bios/vgabios.diff diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 4e3c82954..4978e42cd 100644 Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index ed31b12b1..072f8bd2b 100644 Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ diff --git a/pc-bios/vgabios.diff b/pc-bios/vgabios.diff new file mode 100644 index 000000000..d3a3ef7a2 --- /dev/null +++ b/pc-bios/vgabios.diff @@ -0,0 +1,97 @@ +? biossums +? vgabios.cirrus.debug.txt +? vgabios.cirrus.txt +? vgabios.debug.txt +? vgabios.txt +? tests/Makefile +? tests/setmode.S +? tests/setmode.c +? tests/setmode.com +? tests/setmode.elf +Index: Makefile +=================================================================== +RCS file: /cvsroot/vgabios/vgabios/Makefile,v +retrieving revision 1.15 +diff -u -w -r1.15 Makefile +Index: VGABIOS-lgpl-latest.bin +=================================================================== +RCS file: /cvsroot/vgabios/vgabios/VGABIOS-lgpl-latest.bin,v +retrieving revision 1.60 +diff -u -w -r1.60 VGABIOS-lgpl-latest.bin +Binary files /tmp/cvsCahrMA and VGABIOS-lgpl-latest.bin differ +Index: VGABIOS-lgpl-latest.cirrus.bin +=================================================================== +RCS file: /cvsroot/vgabios/vgabios/VGABIOS-lgpl-latest.cirrus.bin,v +retrieving revision 1.12 +diff -u -w -r1.12 VGABIOS-lgpl-latest.cirrus.bin +Binary files /tmp/cvsewygNU and VGABIOS-lgpl-latest.cirrus.bin differ +Index: VGABIOS-lgpl-latest.cirrus.debug.bin +=================================================================== +RCS file: /cvsroot/vgabios/vgabios/VGABIOS-lgpl-latest.cirrus.debug.bin,v +retrieving revision 1.12 +diff -u -w -r1.12 VGABIOS-lgpl-latest.cirrus.debug.bin +Binary files /tmp/cvsey9TQf and VGABIOS-lgpl-latest.cirrus.debug.bin differ +Index: VGABIOS-lgpl-latest.debug.bin +=================================================================== +RCS file: /cvsroot/vgabios/vgabios/VGABIOS-lgpl-latest.debug.bin,v +retrieving revision 1.60 +diff -u -w -r1.60 VGABIOS-lgpl-latest.debug.bin +Binary files /tmp/cvskxbTbC and VGABIOS-lgpl-latest.debug.bin differ +Index: clext.c +=================================================================== +RCS file: /cvsroot/vgabios/vgabios/clext.c,v +retrieving revision 1.8 +diff -u -w -r1.8 clext.c +--- clext.c 8 Aug 2004 16:52:55 -0000 1.8 ++++ clext.c 30 Nov 2004 23:38:32 -0000 +@@ -222,7 +222,21 @@ + 0x001a,0x221b,0x001d, + 0xffff + }; +- ++/* 1280x1024x16 */ ++unsigned short cseq_1280x1024x16[] = { ++0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, ++0x760b,0x760c,0x760d,0x760e, ++0x0412,0x0013,0x2017, ++0x341b,0x341c,0x341d,0x341e, ++0xffff ++}; ++unsigned short ccrtc_1280x1024x16[] = { ++0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, ++0x6009,0x000c,0x000d, ++0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18, ++0x001a,0x321b,0x001d, ++0xffff ++}; + + cirrus_mode_t cirrus_modes[] = + { +@@ -269,6 +283,12 @@ + {0x6d,1280,1024,8,0x00, + cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8, + 4,0,0,0,0,0,0,0,0}, ++ {0x69,1280,1024,15,0xf0, ++ cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, ++ 6,5,10,5,5,5,0,1,15}, ++ {0x75,1280,1024,16,0xe1, ++ cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, ++ 6,5,11,6,5,5,0,0,0}, + + {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0, + 0xff,0,0,0,0,0,0,0,0}, +@@ -310,9 +330,13 @@ + // 1024x768x16 + 0x117, 0x74, + // 1024x768x24 +-//0x118, 0x79, ++ 0x118, 0x79, + // 1280x1024x8 + 0x107, 0x6d, ++// 1280x1024x15 ++ 0x119, 0x69, ++// 1280x1024x16 ++ 0x11a, 0x75, + // invalid + 0xffff,0xffff + }; -- cgit v1.2.3 From a07167d3d4022c3c754dff78b1889cbc4796e1e9 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 30 Nov 2004 23:41:30 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1160 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index c89488c60..e49086df9 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,7 @@ version 0.6.2: - 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 version 0.6.1: -- cgit v1.2.3 From c451ee717aceddabc636729c49de112b45af3741 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 2 Dec 2004 20:20:21 +0000 Subject: added WIN_IDLEIMMEDIATE and WIN_DIAGNOSE commands git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1161 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index db7d73744..3997a06e2 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1570,6 +1570,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) } break; case WIN_STANDBYNOW1: + case WIN_IDLEIMMEDIATE: s->status = READY_STAT; ide_set_irq(s); break; @@ -1584,6 +1585,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) } ide_set_irq(s); break; + case WIN_DIAGNOSE: + ide_set_signature(s); + s->status = 0x00; /* NOTE: READY is _not_ set */ + s->error = 0x01; + break; case WIN_SRST: if (!s->is_cdrom) goto abort_cmd; -- cgit v1.2.3 From 45aea85cef98ba64b7888f1323520b3e18b07230 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 2 Dec 2004 23:33:11 +0000 Subject: FRSP fix (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1162 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index f439a81df..b360bb6e1 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1364,7 +1364,7 @@ PPC_OP(fnmsubs) /* frsp - frsp. */ PPC_OP(frsp) { - FT0 = FTS0; + FTS0 = FT0; RETURN(); } -- cgit v1.2.3 From f7806f9467e059c128f7442b35ed366f2ccf06ce Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 6 Dec 2004 22:40:57 +0000 Subject: uname() fix (James Pellow) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1163 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9f1b32922..b2965bbbd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2403,7 +2403,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, strcpy (buf->machine, UNAME_MACHINE); } } - ret = get_errno(sys_uname((struct new_utsname *)arg1)); break; #ifdef TARGET_I386 case TARGET_NR_modify_ldt: -- cgit v1.2.3 From 978a66ff73add1f462903af92ccf9a34f6a513c2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 6 Dec 2004 22:58:05 +0000 Subject: utimes() support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1164 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/syscall_nr.h | 1 + linux-user/i386/syscall_nr.h | 1 + linux-user/syscall.c | 14 ++++++++++++++ 3 files changed, 16 insertions(+) diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index 13a9ee11f..195e459ec 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -259,3 +259,4 @@ /* 254 for set_thread_area */ /* 255 for get_thread_area */ /* 256 for set_tid_address */ +#define TARGET_NR_utimes (269) diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index c994381aa..9fa6be96a 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -271,3 +271,4 @@ #define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) #define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) +#define TARGET_NR_utimes 271 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b2965bbbd..2407400c1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1742,6 +1742,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(utime((const char *)arg1, tbuf1)); } break; + case TARGET_NR_utimes: + { + struct target_timeval *target_tvp = (struct target_timeval *)arg2; + struct timeval *tvp, tv[2]; + if (target_tvp) { + target_to_host_timeval(&tv[0], &target_tvp[0]); + target_to_host_timeval(&tv[1], &target_tvp[1]); + tvp = tv; + } else { + tvp = NULL; + } + ret = get_errno(utimes((const char *)arg1, tvp)); + } + break; #ifdef TARGET_NR_stty case TARGET_NR_stty: goto unimplemented; -- cgit v1.2.3 From fe2cece60e02262e64cfadcbcd0408720628ef2a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 6 Dec 2004 23:14:48 +0000 Subject: audio fixes (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1165 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/audio.c | 5 +++-- audio/audio_int.h | 1 - audio/noaudio.c | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 661771e82..0c0c8dd86 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -367,14 +367,15 @@ static int dist (void *hw) { if (hw) { return (((uint8_t *) hw - (uint8_t *) hw_voices) - / audio_state.voice_size) + 1; + / audio_state.drv->voice_size) + 1; } else { return 0; } } -#define ADVANCE(hw) hw ? advance (hw, audio_state.voice_size) : hw_voices +#define ADVANCE(hw) \ + ((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices) HWVoice *pcm_hw_find_any (HWVoice *hw) { diff --git a/audio/audio_int.h b/audio/audio_int.h index db7fd1a7d..0be2a6166 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -86,7 +86,6 @@ typedef struct AudioState { int fixed_channels; int fixed_fmt; int nb_hw_voices; - int voice_size; int64_t ticks_threshold; int freq_threshold; void *opaque; diff --git a/audio/noaudio.c b/audio/noaudio.c index 819de1e53..a192885a7 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -41,7 +41,6 @@ static void no_hw_run (HWVoice *hw) { NoVoice *no = (NoVoice *) hw; int rpos, live, decr, samples; - uint8_t *dst; st_sample_t *src; int64_t now = qemu_get_clock (vm_clock); int64_t ticks = now - no->old_ticks; @@ -82,7 +81,6 @@ static int no_hw_write (SWVoice *sw, void *buf, int len) static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) { - NoVoice *no = (NoVoice *) hw; hw->freq = freq; hw->nchannels = nchannels; hw->fmt = fmt; -- cgit v1.2.3 From f7cce898821ff2a050e3de7317fe05b1a3e155fb Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Dec 2004 22:21:25 +0000 Subject: -pidfile option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1166 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++++ vl.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 9436965eb..6338062cd 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -202,6 +202,10 @@ Windows. @item -full-screen Start in full screen. +@item -pidfile file +Store the QEMU process PID in @var{file}. It is useful if you launch QEMU +from a script. + @end table Network options: diff --git a/vl.c b/vl.c index 018fc3143..31d3a2052 100644 --- a/vl.c +++ b/vl.c @@ -1666,6 +1666,46 @@ static int net_fd_init(NetDriverState *nd, int fd) #endif /* !_WIN32 */ +/***********************************************************/ +/* pid file */ + +static char *pid_filename; + +/* Remove PID file. Called on normal exit */ + +static void remove_pidfile(void) +{ + unlink (pid_filename); +} + +static void create_pidfile(const char *filename) +{ + struct stat pidstat; + FILE *f; + + /* Try to write our PID to the named file */ + if (stat(filename, &pidstat) < 0) { + if (errno == ENOENT) { + if ((f = fopen (filename, "w")) == NULL) { + perror("Opening pidfile"); + exit(1); + } + fprintf(f, "%d\n", getpid()); + fclose(f); + pid_filename = qemu_strdup(filename); + if (!pid_filename) { + fprintf(stderr, "Could not save PID filename"); + exit(1); + } + atexit(remove_pidfile); + } + } else { + fprintf(stderr, "%s already exists. Remove it and try again.\n", + filename); + exit(1); + } +} + /***********************************************************/ /* dumb display */ @@ -2533,6 +2573,7 @@ void help(void) "Debug/Expert options:\n" "-monitor dev redirect the monitor to char device 'dev'\n" "-serial dev redirect the serial port to char device 'dev'\n" + "-pidfile file Write PID to 'file'\n" "-S freeze CPU at startup (use 'c' to start execution)\n" "-s wait gdb connection to port %d\n" "-p port change gdb connection port\n" @@ -2625,6 +2666,7 @@ enum { QEMU_OPTION_serial, QEMU_OPTION_loadvm, QEMU_OPTION_full_screen, + QEMU_OPTION_pidfile, }; typedef struct QEMUOption { @@ -2685,7 +2727,8 @@ const QEMUOption qemu_options[] = { { "serial", 1, QEMU_OPTION_serial }, { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, { "full-screen", 0, QEMU_OPTION_full_screen }, - + { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, + /* temporary options */ { "pci", 0, QEMU_OPTION_pci }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, @@ -3110,6 +3153,9 @@ int main(int argc, char **argv) case QEMU_OPTION_full_screen: full_screen = 1; break; + case QEMU_OPTION_pidfile: + create_pidfile(optarg); + break; } } } -- cgit v1.2.3 From 88920f344d5352dc0bb57539c4639344e9e0e0fe Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Dec 2004 22:28:39 +0000 Subject: ARM shift fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1167 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 13 +++++++++++++ target-arm/translate.c | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/target-arm/op.c b/target-arm/op.c index a27db0085..7545bb0f1 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -485,6 +485,11 @@ void OPPROTO op_rorl_T1_im(void) T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); } +void OPPROTO op_rrxl_T1(void) +{ + T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31); +} + /* T1 based, set C flag */ void OPPROTO op_shll_T1_im_cc(void) { @@ -512,6 +517,14 @@ void OPPROTO op_rorl_T1_im_cc(void) T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); } +void OPPROTO op_rrxl_T1_cc(void) +{ + uint32_t c; + c = T1 & 1; + T1 = ((uint32_t)T1 >> 1) | ((uint32_t)env->CF << 31); + env->CF = c; +} + /* T2 based */ void OPPROTO op_shll_T2_im(void) { diff --git a/target-arm/translate.c b/target-arm/translate.c index 69bc8e224..18caa8121 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -365,6 +365,11 @@ static void disas_arm_insn(DisasContext *s) } else { gen_shift_T1_im[shiftop](shift); } + } else if (shiftop == 3) { + if (logic_cc) + gen_op_rrxl_T1_cc(); + else + gen_op_rrxl_T1(); } } else { rs = (insn >> 8) & 0xf; -- cgit v1.2.3 From 1e8d4eec4859574e7773fa3243fcc61fe7b534e7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Dec 2004 23:40:14 +0000 Subject: more complete ARM shift fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1168 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 38 ++++++++++++++++++++++++++++++++++++++ target-arm/translate.c | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/target-arm/op.c b/target-arm/op.c index 7545bb0f1..6596de76f 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -463,6 +463,7 @@ void OPPROTO op_swpl_T0_T1(void) /* shifts */ /* T1 based */ + void OPPROTO op_shll_T1_im(void) { T1 = T1 << PARAM1; @@ -473,11 +474,21 @@ void OPPROTO op_shrl_T1_im(void) T1 = (uint32_t)T1 >> PARAM1; } +void OPPROTO op_shrl_T1_0(void) +{ + T1 = 0; +} + void OPPROTO op_sarl_T1_im(void) { T1 = (int32_t)T1 >> PARAM1; } +void OPPROTO op_sarl_T1_0(void) +{ + T1 = (int32_t)T1 >> 31; +} + void OPPROTO op_rorl_T1_im(void) { int shift; @@ -503,12 +514,24 @@ void OPPROTO op_shrl_T1_im_cc(void) T1 = (uint32_t)T1 >> PARAM1; } +void OPPROTO op_shrl_T1_0_cc(void) +{ + env->CF = (T1 >> 31) & 1; + T1 = 0; +} + void OPPROTO op_sarl_T1_im_cc(void) { env->CF = (T1 >> (PARAM1 - 1)) & 1; T1 = (int32_t)T1 >> PARAM1; } +void OPPROTO op_sarl_T1_0_cc(void) +{ + env->CF = (T1 >> 31) & 1; + T1 = (int32_t)T1 >> 31; +} + void OPPROTO op_rorl_T1_im_cc(void) { int shift; @@ -536,11 +559,21 @@ void OPPROTO op_shrl_T2_im(void) T2 = (uint32_t)T2 >> PARAM1; } +void OPPROTO op_shrl_T2_0(void) +{ + T2 = 0; +} + void OPPROTO op_sarl_T2_im(void) { T2 = (int32_t)T2 >> PARAM1; } +void OPPROTO op_sarl_T2_0(void) +{ + T2 = (int32_t)T2 >> 31; +} + void OPPROTO op_rorl_T2_im(void) { int shift; @@ -548,6 +581,11 @@ void OPPROTO op_rorl_T2_im(void) T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); } +void OPPROTO op_rrxl_T2(void) +{ + T2 = ((uint32_t)T2 >> 1) | ((uint32_t)env->CF << 31); +} + /* T1 based, use T0 as shift count */ void OPPROTO op_shll_T1_T0(void) diff --git a/target-arm/translate.c b/target-arm/translate.c index 18caa8121..56efa41e1 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -94,6 +94,13 @@ static GenOpFunc1 *gen_shift_T1_im[4] = { gen_op_rorl_T1_im, }; +static GenOpFunc *gen_shift_T1_0[4] = { + NULL, + gen_op_shrl_T1_0, + gen_op_sarl_T1_0, + gen_op_rrxl_T1, +}; + static GenOpFunc1 *gen_shift_T2_im[4] = { gen_op_shll_T2_im, gen_op_shrl_T2_im, @@ -101,6 +108,13 @@ static GenOpFunc1 *gen_shift_T2_im[4] = { gen_op_rorl_T2_im, }; +static GenOpFunc *gen_shift_T2_0[4] = { + NULL, + gen_op_shrl_T2_0, + gen_op_sarl_T2_0, + gen_op_rrxl_T2, +}; + static GenOpFunc1 *gen_shift_T1_im_cc[4] = { gen_op_shll_T1_im_cc, gen_op_shrl_T1_im_cc, @@ -108,6 +122,13 @@ static GenOpFunc1 *gen_shift_T1_im_cc[4] = { gen_op_rorl_T1_im_cc, }; +static GenOpFunc *gen_shift_T1_0_cc[4] = { + NULL, + gen_op_shrl_T1_0_cc, + gen_op_sarl_T1_0_cc, + gen_op_rrxl_T1_cc, +}; + static GenOpFunc *gen_shift_T1_T0[4] = { gen_op_shll_T1_T0, gen_op_shrl_T1_T0, @@ -272,7 +293,7 @@ static inline void gen_movl_reg_T1(DisasContext *s, int reg) static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) { - int val, rm, shift; + int val, rm, shift, shiftop; if (!(insn & (1 << 25))) { /* immediate */ @@ -286,8 +307,11 @@ static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) rm = (insn) & 0xf; shift = (insn >> 7) & 0x1f; gen_movl_T2_reg(s, rm); + shiftop = (insn >> 5) & 3; if (shift != 0) { - gen_shift_T2_im[(insn >> 5) & 3](shift); + gen_shift_T2_im[shiftop](shift); + } else if (shiftop != 0) { + gen_shift_T2_0[shiftop](); } if (!(insn & (1 << 23))) gen_op_subl_T1_T2(); @@ -365,11 +389,12 @@ static void disas_arm_insn(DisasContext *s) } else { gen_shift_T1_im[shiftop](shift); } - } else if (shiftop == 3) { - if (logic_cc) - gen_op_rrxl_T1_cc(); - else - gen_op_rrxl_T1(); + } else if (shiftop != 0) { + if (logic_cc) { + gen_shift_T1_0_cc[shiftop](); + } else { + gen_shift_T1_0[shiftop](); + } } } else { rs = (insn >> 8) & 0xf; -- cgit v1.2.3 From 6a78ece5c5add210059a26719c863d3af55befb0 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Dec 2004 23:47:30 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1169 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index e49086df9..1fa7b8b8b 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ version 0.6.2: - user mode networking bug fix - undocumented FPU ops support - Cirrus VGA: support for 1280x1024x[8,15,16] modes + - 'pidfile' option version 0.6.1: -- cgit v1.2.3 From a483b654b5663ee506b6ecb1fa4561d5f4a31e4b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Dec 2004 23:48:11 +0000 Subject: updated guest kernel patch for qemu-fast (Martin Koniczek) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1170 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-2.6-qemu-fast.patch | 305 -------------------------------------------- linux-2.6.9-qemu-fast.patch | 70 ++++++++++ 2 files changed, 70 insertions(+), 305 deletions(-) delete mode 100644 linux-2.6-qemu-fast.patch create mode 100644 linux-2.6.9-qemu-fast.patch diff --git a/linux-2.6-qemu-fast.patch b/linux-2.6-qemu-fast.patch deleted file mode 100644 index 34ca5a232..000000000 --- a/linux-2.6-qemu-fast.patch +++ /dev/null @@ -1,305 +0,0 @@ -diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/Kconfig .32324-linux-2.6.0.updated/arch/i386/Kconfig ---- .32324-linux-2.6.0/arch/i386/Kconfig 2003-10-09 18:02:48.000000000 +1000 -+++ .32324-linux-2.6.0.updated/arch/i386/Kconfig 2003-12-26 16:46:49.000000000 +1100 -@@ -307,6 +307,14 @@ config X86_GENERIC - when it has moderate overhead. This is intended for generic - distributions kernels. - -+config QEMU -+ bool "Kernel to run under QEMU" -+ depends on EXPERIMENTAL -+ help -+ Select this if you want to boot the kernel inside qemu-fast, -+ the non-mmu version of the x86 emulator. See -+ . Say N. -+ - # - # Define implied options from the CPU selection here - # -diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/Makefile .32324-linux-2.6.0.updated/arch/i386/kernel/Makefile ---- .32324-linux-2.6.0/arch/i386/kernel/Makefile 2003-09-29 10:25:15.000000000 +1000 -+++ .32324-linux-2.6.0.updated/arch/i386/kernel/Makefile 2003-12-26 16:46:49.000000000 +1100 -@@ -46,12 +46,14 @@ quiet_cmd_syscall = SYSCALL $@ - cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ - -Wl,-T,$(filter-out FORCE,$^) -o $@ - -+export AFLAGS_vsyscall.lds.o += -P -C -U$(ARCH) -+ - vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 - SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) - SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) - - $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \ --$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE -+$(obj)/vsyscall-%.so: $(src)/vsyscall.lds.s $(obj)/vsyscall-%.o FORCE - $(call if_changed,syscall) - - # We also create a special relocatable object that should mirror the symbol -@@ -62,5 +64,5 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms. - $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o - - SYSCFLAGS_vsyscall-syms.o = -r --$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE -+$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds.s $(obj)/vsyscall-sysenter.o FORCE - $(call if_changed,syscall) -diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vmlinux.lds.S .32324-linux-2.6.0.updated/arch/i386/kernel/vmlinux.lds.S ---- .32324-linux-2.6.0/arch/i386/kernel/vmlinux.lds.S 2003-09-22 10:27:28.000000000 +1000 -+++ .32324-linux-2.6.0.updated/arch/i386/kernel/vmlinux.lds.S 2003-12-26 16:46:49.000000000 +1100 -@@ -3,6 +3,7 @@ - */ - - #include -+#include - - OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") - OUTPUT_ARCH(i386) -@@ -10,7 +11,7 @@ ENTRY(startup_32) - jiffies = jiffies_64; - SECTIONS - { -- . = 0xC0000000 + 0x100000; -+ . = __PAGE_OFFSET + 0x100000; - /* read-only */ - _text = .; /* Text and read-only data */ - .text : { -diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds ---- .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds 2003-09-22 10:07:26.000000000 +1000 -+++ .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds 1970-01-01 10:00:00.000000000 +1000 -@@ -1,67 +0,0 @@ --/* -- * Linker script for vsyscall DSO. The vsyscall page is an ELF shared -- * object prelinked to its virtual address, and with only one read-only -- * segment (that fits in one page). This script controls its layout. -- */ -- --/* This must match . */ --VSYSCALL_BASE = 0xffffe000; -- --SECTIONS --{ -- . = VSYSCALL_BASE + SIZEOF_HEADERS; -- -- .hash : { *(.hash) } :text -- .dynsym : { *(.dynsym) } -- .dynstr : { *(.dynstr) } -- .gnu.version : { *(.gnu.version) } -- .gnu.version_d : { *(.gnu.version_d) } -- .gnu.version_r : { *(.gnu.version_r) } -- -- /* This linker script is used both with -r and with -shared. -- For the layouts to match, we need to skip more than enough -- space for the dynamic symbol table et al. If this amount -- is insufficient, ld -shared will barf. Just increase it here. */ -- . = VSYSCALL_BASE + 0x400; -- -- .text : { *(.text) } :text =0x90909090 -- -- .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr -- .eh_frame : { KEEP (*(.eh_frame)) } :text -- .dynamic : { *(.dynamic) } :text :dynamic -- .useless : { -- *(.got.plt) *(.got) -- *(.data .data.* .gnu.linkonce.d.*) -- *(.dynbss) -- *(.bss .bss.* .gnu.linkonce.b.*) -- } :text --} -- --/* -- * We must supply the ELF program headers explicitly to get just one -- * PT_LOAD segment, and set the flags explicitly to make segments read-only. -- */ --PHDRS --{ -- text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ -- dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ -- eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ --} -- --/* -- * This controls what symbols we export from the DSO. -- */ --VERSION --{ -- LINUX_2.5 { -- global: -- __kernel_vsyscall; -- __kernel_sigreturn; -- __kernel_rt_sigreturn; -- -- local: *; -- }; --} -- --/* The ELF entry point can be used to set the AT_SYSINFO value. */ --ENTRY(__kernel_vsyscall); -diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds.S .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds.S ---- .32324-linux-2.6.0/arch/i386/kernel/vsyscall.lds.S 1970-01-01 10:00:00.000000000 +1000 -+++ .32324-linux-2.6.0.updated/arch/i386/kernel/vsyscall.lds.S 2003-12-26 16:46:49.000000000 +1100 -@@ -0,0 +1,67 @@ -+/* -+ * Linker script for vsyscall DSO. The vsyscall page is an ELF shared -+ * object prelinked to its virtual address, and with only one read-only -+ * segment (that fits in one page). This script controls its layout. -+ */ -+#include -+ -+VSYSCALL_BASE = __FIXADDR_TOP - 0x1000; -+ -+SECTIONS -+{ -+ . = VSYSCALL_BASE + SIZEOF_HEADERS; -+ -+ .hash : { *(.hash) } :text -+ .dynsym : { *(.dynsym) } -+ .dynstr : { *(.dynstr) } -+ .gnu.version : { *(.gnu.version) } -+ .gnu.version_d : { *(.gnu.version_d) } -+ .gnu.version_r : { *(.gnu.version_r) } -+ -+ /* This linker script is used both with -r and with -shared. -+ For the layouts to match, we need to skip more than enough -+ space for the dynamic symbol table et al. If this amount -+ is insufficient, ld -shared will barf. Just increase it here. */ -+ . = VSYSCALL_BASE + 0x400; -+ -+ .text : { *(.text) } :text =0x90909090 -+ -+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr -+ .eh_frame : { KEEP (*(.eh_frame)) } :text -+ .dynamic : { *(.dynamic) } :text :dynamic -+ .useless : { -+ *(.got.plt) *(.got) -+ *(.data .data.* .gnu.linkonce.d.*) -+ *(.dynbss) -+ *(.bss .bss.* .gnu.linkonce.b.*) -+ } :text -+} -+ -+/* -+ * We must supply the ELF program headers explicitly to get just one -+ * PT_LOAD segment, and set the flags explicitly to make segments read-only. -+ */ -+PHDRS -+{ -+ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ -+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ -+ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ -+} -+ -+/* -+ * This controls what symbols we export from the DSO. -+ */ -+VERSION -+{ -+ LINUX_2.5 { -+ global: -+ __kernel_vsyscall; -+ __kernel_sigreturn; -+ __kernel_rt_sigreturn; -+ -+ local: *; -+ }; -+} -+ -+/* The ELF entry point can be used to set the AT_SYSINFO value. */ -+ENTRY(__kernel_vsyscall); -diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/fixmap.h .32324-linux-2.6.0.updated/include/asm-i386/fixmap.h ---- .32324-linux-2.6.0/include/asm-i386/fixmap.h 2003-09-22 10:09:12.000000000 +1000 -+++ .32324-linux-2.6.0.updated/include/asm-i386/fixmap.h 2003-12-26 16:46:49.000000000 +1100 -@@ -14,6 +14,19 @@ - #define _ASM_FIXMAP_H - - #include -+ -+/* used by vmalloc.c, vsyscall.lds.S. -+ * -+ * Leave one empty page between vmalloc'ed areas and -+ * the start of the fixmap. -+ */ -+#ifdef CONFIG_QEMU -+#define __FIXADDR_TOP 0xa7fff000 -+#else -+#define __FIXADDR_TOP 0xfffff000 -+#endif -+ -+#ifndef __ASSEMBLY__ - #include - #include - #include -@@ -94,13 +107,8 @@ extern void __set_fixmap (enum fixed_add - #define clear_fixmap(idx) \ - __set_fixmap(idx, 0, __pgprot(0)) - --/* -- * used by vmalloc.c. -- * -- * Leave one empty page between vmalloc'ed areas and -- * the start of the fixmap. -- */ --#define FIXADDR_TOP (0xfffff000UL) -+#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP) -+ - #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) - #define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) - -@@ -145,4 +153,5 @@ static inline unsigned long virt_to_fix( - return __virt_to_fix(vaddr); - } - -+#endif /* !__ASSEMBLY__ */ - #endif -diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/page.h .32324-linux-2.6.0.updated/include/asm-i386/page.h ---- .32324-linux-2.6.0/include/asm-i386/page.h 2003-09-22 10:06:42.000000000 +1000 -+++ .32324-linux-2.6.0.updated/include/asm-i386/page.h 2003-12-26 16:46:49.000000000 +1100 -@@ -10,10 +10,10 @@ - #define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) - - #ifdef __KERNEL__ --#ifndef __ASSEMBLY__ -- - #include - -+#ifndef __ASSEMBLY__ -+ - #ifdef CONFIG_X86_USE_3DNOW - - #include -@@ -115,12 +115,19 @@ static __inline__ int get_order(unsigned - #endif /* __ASSEMBLY__ */ - - #ifdef __ASSEMBLY__ -+#ifdef CONFIG_QEMU -+#define __PAGE_OFFSET (0x90000000) -+#else - #define __PAGE_OFFSET (0xC0000000) -+#endif /* QEMU */ -+#else -+#ifdef CONFIG_QEMU -+#define __PAGE_OFFSET (0x90000000UL) - #else - #define __PAGE_OFFSET (0xC0000000UL) -+#endif /* QEMU */ - #endif - -- - #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) - #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) - #define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) -diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .32324-linux-2.6.0/include/asm-i386/param.h .32324-linux-2.6.0.updated/include/asm-i386/param.h ---- .32324-linux-2.6.0/include/asm-i386/param.h 2003-09-21 17:26:06.000000000 +1000 -+++ .32324-linux-2.6.0.updated/include/asm-i386/param.h 2003-12-26 16:46:49.000000000 +1100 -@@ -2,7 +2,12 @@ - #define _ASMi386_PARAM_H - - #ifdef __KERNEL__ --# define HZ 1000 /* Internal kernel timer frequency */ -+# include -+# ifdef CONFIG_QEMU -+# define HZ 100 -+# else -+# define HZ 1000 /* Internal kernel timer frequency */ -+# endif - # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ - # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ - #endif diff --git a/linux-2.6.9-qemu-fast.patch b/linux-2.6.9-qemu-fast.patch new file mode 100644 index 000000000..f8ecd0b74 --- /dev/null +++ b/linux-2.6.9-qemu-fast.patch @@ -0,0 +1,70 @@ +--- linux-2.6.9/arch/i386/Kconfig 2004-10-18 23:53:22.000000000 +0200 ++++ linux-2.6.9-qemu/arch/i386/Kconfig 2004-12-07 21:56:49.000000000 +0100 +@@ -337,6 +337,14 @@ config X86_GENERIC + + endif + ++config QEMU ++ bool "Kernel to run under QEMU" ++ depends on EXPERIMENTAL ++ help ++ Select this if you want to boot the kernel inside qemu-fast, ++ the non-mmu version of the x86 emulator. See ++ . Say N. ++ + # + # Define implied options from the CPU selection here + # +--- linux-2.6.9/include/asm-i386/fixmap.h 2004-10-18 23:53:08.000000000 +0200 ++++ linux-2.6.9-qemu/include/asm-i386/fixmap.h 2004-12-07 23:16:11.000000000 +0100 +@@ -20,7 +20,11 @@ + * Leave one empty page between vmalloc'ed areas and + * the start of the fixmap. + */ ++#ifdef CONFIG_QEMU ++#define __FIXADDR_TOP 0xa7fff000 ++#else + #define __FIXADDR_TOP 0xfffff000 ++#endif + + #ifndef __ASSEMBLY__ + #include +--- linux-2.6.9/include/asm-i386/page.h 2004-10-18 23:53:22.000000000 +0200 ++++ linux-2.6.9-qemu/include/asm-i386/page.h 2004-12-07 21:56:49.000000000 +0100 +@@ -121,12 +121,19 @@ extern int sysctl_legacy_va_layout; + #endif /* __ASSEMBLY__ */ + + #ifdef __ASSEMBLY__ ++#ifdef CONFIG_QEMU ++#define __PAGE_OFFSET (0x90000000) ++#else + #define __PAGE_OFFSET (0xC0000000) ++#endif /* QEMU */ ++#else ++#ifdef CONFIG_QEMU ++#define __PAGE_OFFSET (0x90000000UL) + #else + #define __PAGE_OFFSET (0xC0000000UL) ++#endif /* QEMU */ + #endif + +- + #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) + #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) + #define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) +--- linux-2.6.9/include/asm-i386/param.h 2004-10-18 23:53:24.000000000 +0200 ++++ linux-2.6.9-qemu/include/asm-i386/param.h 2004-12-07 21:56:49.000000000 +0100 +@@ -2,7 +2,12 @@ + #define _ASMi386_PARAM_H + + #ifdef __KERNEL__ +-# define HZ 1000 /* Internal kernel timer frequency */ ++# include ++# ifdef CONFIG_QEMU ++# define HZ 100 ++# else ++# define HZ 1000 /* Internal kernel timer frequency */ ++# endif + # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ + # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ + #endif -- cgit v1.2.3 From 585d0ed98b032cdd062b9d43a6d0ef478fc914e8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 12 Dec 2004 11:24:44 +0000 Subject: .dmg disk image format support (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1171 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile | 2 +- Makefile.target | 2 +- block-cloop.c | 4 +- block-dmg.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ block.c | 1 + vl.h | 1 + 7 files changed, 301 insertions(+), 3 deletions(-) create mode 100644 block-dmg.c diff --git a/Changelog b/Changelog index 1fa7b8b8b..506675efd 100644 --- a/Changelog +++ b/Changelog @@ -5,6 +5,7 @@ version 0.6.2: - undocumented FPU ops support - Cirrus VGA: support for 1280x1024x[8,15,16] modes - 'pidfile' option + - .dmg disk image format support (Johannes Schindelin) version 0.6.1: diff --git a/Makefile b/Makefile index 094b39590..cbe56159b 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ all: dyngen$(EXESUF) $(TOOLS) $(DOCS) $(MAKE) -C $$d $@ || exit 1 ; \ done -qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c +qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c diff --git a/Makefile.target b/Makefile.target index 5690adcdc..a2cfad1f5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -265,7 +265,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o -VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o SOUND_HW = sb16.o AUDIODRV = audio.o noaudio.o wavaudio.o diff --git a/block-cloop.c b/block-cloop.c index f22253daa..de9085538 100644 --- a/block-cloop.c +++ b/block-cloop.c @@ -1,5 +1,5 @@ /* - * QEMU System Emulator block driver + * QEMU Block driver for CLOOP images * * Copyright (c) 2004 Johannes E. Schindelin * @@ -149,6 +149,8 @@ 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); diff --git a/block-dmg.c b/block-dmg.c new file mode 100644 index 000000000..af8b67b7a --- /dev/null +++ b/block-dmg.c @@ -0,0 +1,293 @@ +/* + * 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 + +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<=i4 && !strcmp(filename+len-4,".dmg")) + return 2; + return 0; +} + +static off_t read_off(int fd) +{ + uint64_t buffer; + if(read(fd,&buffer,8)<8) + return 0; + return be64_to_cpu(buffer); +} + +static off_t read_uint32(int fd) +{ + uint32_t buffer; + if(read(fd,&buffer,4)<4) + return 0; + return be32_to_cpu(buffer); +} + +static int dmg_open(BlockDriverState *bs, const char *filename) +{ + BDRVDMGState *s = bs->opaque; + off_t info_begin,info_end,last_in_offset,last_out_offset; + uint32_t count; + uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i; + + s->fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (s->fd < 0) + return -1; + bs->read_only = 1; + s->n_chunks = 0; + s->offsets = s->lengths = s->sectors = s->sectorcounts = 0; + + /* read offset of info blocks */ + if(lseek(s->fd,-0x1d8,SEEK_END)<0) { +dmg_close: + close(s->fd); + return -1; + } + 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)fd); + if(count==0) + goto dmg_close; + uint32_t 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;in_chunks+chunk_count;i++) { + s->types[i] = read_uint32(s->fd); + if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) { + if(s->types[i]==0xffffffff) { + last_in_offset = s->offsets[i-1]+s->lengths[i-1]; + last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1]; + } + chunk_count--; + i--; + if(lseek(s->fd,36,SEEK_CUR)<0) + goto dmg_close; + continue; + } + read_uint32(s->fd); + s->sectors[i] = last_out_offset+read_off(s->fd); + s->sectorcounts[i] = read_off(s->fd); + s->offsets[i] = last_in_offset+read_off(s->fd); + s->lengths[i] = read_off(s->fd); + if(s->lengths[i]>max_compressed_size) + max_compressed_size = s->lengths[i]; + if(s->sectorcounts[i]>max_sectors_per_chunk) + max_sectors_per_chunk = s->sectorcounts[i]; + } + s->n_chunks+=chunk_count; + } + } + + /* initialize zlib engine */ + if(!(s->compressed_chunk=(char*)malloc(max_compressed_size+1))) + goto dmg_close; + if(!(s->uncompressed_chunk=(char*)malloc(512*max_sectors_per_chunk))) + goto dmg_close; + if(inflateInit(&s->zstream) != Z_OK) + goto dmg_close; + + s->current_chunk = s->n_chunks; + + return 0; +} + +static inline int is_sector_in_chunk(BDRVDMGState* s, + uint32_t chunk_num,int sector_num) +{ + if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num || + s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num) + return 0; + else + return -1; +} + +static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num) +{ + /* binary search */ + uint32_t chunk1=0,chunk2=s->n_chunks,chunk3; + while(chunk1!=chunk2) { + chunk3 = (chunk1+chunk2)/2; + if(s->sectors[chunk3]>sector_num) + chunk2 = chunk3; + else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num) + return chunk3; + else + chunk1 = chunk3; + } + return s->n_chunks; /* error */ +} + +static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) +{ + if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) { + int ret; + uint32_t chunk = search_chunk(s,sector_num); + + if(chunk>=s->n_chunks) + return -1; + + s->current_chunk = s->n_chunks; + switch(s->types[chunk]) { + case 0x80000005: { /* zlib compressed */ + int i; + + ret = lseek(s->fd, s->offsets[chunk], SEEK_SET); + if(ret<0) + return -1; + + /* we need to buffer, because only the chunk as whole can be + * inflated. */ + i=0; + do { + ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i); + if(ret<0 && errno==EINTR) + ret=0; + i+=ret; + } while(ret>=0 && ret+ilengths[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;isectors[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, +}; + diff --git a/block.c b/block.c index a77a3e55b..a4433a898 100644 --- a/block.c +++ b/block.c @@ -607,4 +607,5 @@ void bdrv_init(void) bdrv_register(&bdrv_qcow); bdrv_register(&bdrv_vmdk); bdrv_register(&bdrv_cloop); + bdrv_register(&bdrv_dmg); } diff --git a/vl.h b/vl.h index 2f69899da..119769b5b 100644 --- a/vl.h +++ b/vl.h @@ -360,6 +360,7 @@ extern BlockDriver bdrv_cow; extern BlockDriver bdrv_qcow; extern BlockDriver bdrv_vmdk; extern BlockDriver bdrv_cloop; +extern BlockDriver bdrv_dmg; void bdrv_init(void); BlockDriver *bdrv_find_format(const char *format_name); -- cgit v1.2.3 From 7b91a17212a0a16dd56a8731c345ecf29c366855 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 12 Dec 2004 11:45:10 +0000 Subject: slirp fix for -smb command (Initial patch by Juergen Keil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1172 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/misc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/slirp/misc.c b/slirp/misc.c index 5b809a853..a58b63100 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -320,7 +320,7 @@ fork_exec(so, ex, do_pty) /* don't want to clobber the original */ char *bptr; char *curarg; - int c, i; + int c, i, ret; DEBUG_CALL("fork_exec"); DEBUG_ARG("so = %lx", (long)so); @@ -372,7 +372,9 @@ fork_exec(so, ex, do_pty) */ s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_addr = loopback_addr; - connect(s, (struct sockaddr *)&addr, addrlen); + do { + ret = connect(s, (struct sockaddr *)&addr, addrlen); + } while (ret < 0 && errno == EINTR); } #if 0 @@ -436,8 +438,10 @@ fork_exec(so, ex, do_pty) * The only reason this will block forever is if socket() * of connect() fail in the child process */ - so->s = accept(s, (struct sockaddr *)&addr, &addrlen); - closesocket(s); + do { + so->s = accept(s, (struct sockaddr *)&addr, &addrlen); + } while (so->s < 0 && errno == EINTR); + closesocket(s); opt = 1; setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); opt = 1; -- cgit v1.2.3 From 3d11d0eb33f0474f8299c2373f3a91bb416b81c6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 12 Dec 2004 16:56:30 +0000 Subject: keymaps support (initial patch by Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1173 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile | 2 + Makefile.target | 2 +- keymaps.c | 143 ++++++++++++++++++++++++++++ keymaps/ar | 98 +++++++++++++++++++ keymaps/common | 157 +++++++++++++++++++++++++++++++ keymaps/da | 120 ++++++++++++++++++++++++ keymaps/de | 114 ++++++++++++++++++++++ keymaps/de-ch | 169 +++++++++++++++++++++++++++++++++ keymaps/en-gb | 119 +++++++++++++++++++++++ keymaps/en-us | 35 +++++++ keymaps/es | 105 +++++++++++++++++++++ keymaps/et | 86 +++++++++++++++++ keymaps/fi | 124 ++++++++++++++++++++++++ keymaps/fo | 77 +++++++++++++++ keymaps/fr | 181 +++++++++++++++++++++++++++++++++++ keymaps/fr-be | 140 +++++++++++++++++++++++++++ keymaps/fr-ca | 50 ++++++++++ keymaps/fr-ch | 114 ++++++++++++++++++++++ keymaps/hr | 125 +++++++++++++++++++++++++ keymaps/hu | 115 +++++++++++++++++++++++ keymaps/is | 140 +++++++++++++++++++++++++++ keymaps/it | 115 +++++++++++++++++++++++ keymaps/ja | 104 +++++++++++++++++++++ keymaps/lt | 57 +++++++++++ keymaps/lv | 128 +++++++++++++++++++++++++ keymaps/mk | 101 ++++++++++++++++++++ keymaps/modifiers | 16 ++++ keymaps/nl | 60 ++++++++++++ keymaps/nl-be | 3 + keymaps/no | 119 +++++++++++++++++++++++ keymaps/pl | 122 ++++++++++++++++++++++++ keymaps/pt | 113 ++++++++++++++++++++++ keymaps/pt-br | 69 ++++++++++++++ keymaps/ru | 109 ++++++++++++++++++++++ keymaps/sl | 110 ++++++++++++++++++++++ keymaps/sv | 82 ++++++++++++++++ keymaps/th | 131 ++++++++++++++++++++++++++ keymaps/tr | 123 ++++++++++++++++++++++++ qemu-doc.texi | 16 ++++ sdl.c | 146 +++++++---------------------- sdl_keysym.h | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 7 ++ vl.h | 1 + 44 files changed, 4109 insertions(+), 115 deletions(-) create mode 100644 keymaps.c create mode 100644 keymaps/ar create mode 100644 keymaps/common create mode 100644 keymaps/da create mode 100644 keymaps/de create mode 100644 keymaps/de-ch create mode 100644 keymaps/en-gb create mode 100644 keymaps/en-us create mode 100644 keymaps/es create mode 100644 keymaps/et create mode 100644 keymaps/fi create mode 100644 keymaps/fo create mode 100644 keymaps/fr create mode 100644 keymaps/fr-be create mode 100644 keymaps/fr-ca create mode 100644 keymaps/fr-ch create mode 100644 keymaps/hr create mode 100644 keymaps/hu create mode 100644 keymaps/is create mode 100644 keymaps/it create mode 100644 keymaps/ja create mode 100644 keymaps/lt create mode 100644 keymaps/lv create mode 100644 keymaps/mk create mode 100644 keymaps/modifiers create mode 100644 keymaps/nl create mode 100644 keymaps/nl-be create mode 100644 keymaps/no create mode 100644 keymaps/pl create mode 100644 keymaps/pt create mode 100644 keymaps/pt-br create mode 100644 keymaps/ru create mode 100644 keymaps/sl create mode 100644 keymaps/sv create mode 100644 keymaps/th create mode 100644 keymaps/tr create mode 100644 sdl_keysym.h diff --git a/Changelog b/Changelog index 506675efd..eada6316e 100644 --- a/Changelog +++ b/Changelog @@ -6,6 +6,7 @@ version 0.6.2: - 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) version 0.6.1: diff --git a/Makefile b/Makefile index cbe56159b..eb353ba9a 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,8 @@ install: all ifndef CONFIG_WIN32 mkdir -p "$(mandir)/man1" install qemu.1 qemu-img.1 "$(mandir)/man1" + mkdir -p "$(datadir)/keymaps" + install -m 644 keymaps/* "$(datadir)" endif for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ diff --git a/Makefile.target b/Makefile.target index a2cfad1f5..a5c697ddc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -333,7 +333,7 @@ endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS) -sdl.o: sdl.c +sdl.o: sdl.c keymaps.c sdl_keysym.h $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< sdlaudio.o: sdlaudio.c diff --git a/keymaps.c b/keymaps.c new file mode 100644 index 000000000..c3de8d764 --- /dev/null +++ b/keymaps.c @@ -0,0 +1,143 @@ +/* + * QEMU keysym to keycode conversion using rdesktop keymaps + * + * Copyright (c) 2004 Johannes 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. + */ + +static int get_keysym(const char *name) +{ + name2keysym_t *p; + for(p = name2keysym; p->name != NULL; p++) { + if (!strcmp(p->name, name)) + return p->keysym; + } + return 0; +} + +#define MAX_NORMAL_KEYCODE 512 +#define MAX_EXTRA_COUNT 256 +typedef struct { + uint16_t keysym2keycode[MAX_NORMAL_KEYCODE]; + struct { + int keysym; + uint16_t keycode; + } keysym2keycode_extra[MAX_EXTRA_COUNT]; + int extra_count; +} kbd_layout_t; + +static kbd_layout_t *parse_keyboard_layout(const char *language, + kbd_layout_t * k) +{ + FILE *f; + char file_name[1024]; + char line[1024]; + int len; + + snprintf(file_name, sizeof(file_name), + "%s/keymaps/%s", bios_dir, language); + + if (!k) + k = qemu_mallocz(sizeof(kbd_layout_t)); + if (!k) + return 0; + if (!(f = fopen(file_name, "r"))) { + fprintf(stderr, + "Could not read keymap file: '%s'\n", file_name); + return 0; + } + for(;;) { + if (fgets(line, 1024, f) == NULL) + break; + len = strlen(line); + if (len > 0 && line[len - 1] == '\n') + line[len - 1] = '\0'; + if (line[0] == '#') + continue; + if (!strncmp(line, "map ", 4)) + continue; + if (!strncmp(line, "include ", 8)) { + parse_keyboard_layout(line + 8, k); + } else { + char *end_of_keysym = line; + while (*end_of_keysym != 0 && *end_of_keysym != ' ') + end_of_keysym++; + if (*end_of_keysym) { + int keysym; + *end_of_keysym = 0; + keysym = get_keysym(line); + if (keysym == 0) { + // fprintf(stderr, "Warning: unknown keysym %s\n", line); + } else { + const char *rest = end_of_keysym + 1; + int keycode = strtol(rest, NULL, 0); + /* if(keycode&0x80) + keycode=(keycode<<8)^0x80e0; */ + if (keysym < MAX_NORMAL_KEYCODE) { + //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode); + k->keysym2keycode[keysym] = keycode; + } else { + if (k->extra_count >= MAX_EXTRA_COUNT) { + fprintf(stderr, + "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n", + line, keysym); + } else { + fprintf(stderr, "Setting %d: %d,%d\n", + k->extra_count, keysym, keycode); + k->keysym2keycode_extra[k->extra_count]. + keysym = keysym; + k->keysym2keycode_extra[k->extra_count]. + keycode = keycode; + k->extra_count++; + } + } + } + } + } + } + fclose(f); + return k; +} + +static void *init_keyboard_layout(const char *language) +{ + return parse_keyboard_layout(language, 0); +} + +static int keysym2scancode(void *kbd_layout, int keysym) +{ + kbd_layout_t *k = kbd_layout; + if (keysym < MAX_NORMAL_KEYCODE) { + if (k->keysym2keycode[keysym] == 0) + fprintf(stderr, "Warning: no scancode found for keysym %d\n", + keysym); + return k->keysym2keycode[keysym]; + } else { + int i; +#ifdef XK_ISO_Left_Tab + if (keysym == XK_ISO_Left_Tab) + keysym = XK_Tab; +#endif + for (i = 0; i < k->extra_count; i++) + if (k->keysym2keycode_extra[i].keysym == keysym) + return k->keysym2keycode_extra[i].keycode; + } + return 0; +} diff --git a/keymaps/ar b/keymaps/ar new file mode 100644 index 000000000..c430c03bb --- /dev/null +++ b/keymaps/ar @@ -0,0 +1,98 @@ +# generated from XKB map ar +include common +map 0x401 +exclam 0x02 shift +at 0x03 shift +numbersign 0x04 shift +dollar 0x05 shift +percent 0x06 shift +asciicircum 0x07 shift +ampersand 0x08 shift +asterisk 0x09 shift +parenleft 0x0a shift +parenright 0x0b shift +minus 0x0c +underscore 0x0c shift +equal 0x0d +plus 0x0d shift +Arabic_dad 0x10 altgr +Arabic_fatha 0x10 shift altgr +Arabic_sad 0x11 altgr +Arabic_fathatan 0x11 shift altgr +Arabic_theh 0x12 altgr +Arabic_damma 0x12 shift altgr +Arabic_qaf 0x13 altgr +Arabic_dammatan 0x13 shift altgr +Arabic_feh 0x14 altgr +UFEF9 0x14 shift altgr +Arabic_ghain 0x15 altgr +Arabic_hamzaunderalef 0x15 shift altgr +Arabic_ain 0x16 altgr +grave 0x16 shift altgr +Arabic_ha 0x17 altgr +division 0x17 shift altgr +Arabic_khah 0x18 altgr +multiply 0x18 shift altgr +Arabic_hah 0x19 altgr +Arabic_semicolon 0x19 shift altgr +bracketleft 0x1a +braceleft 0x1a shift +Arabic_jeem 0x1a altgr +bracketright 0x1b +braceright 0x1b shift +Arabic_dal 0x1b altgr +Arabic_sheen 0x1e altgr +backslash 0x1e shift altgr +Arabic_seen 0x1f altgr +Arabic_yeh 0x20 altgr +bracketleft 0x20 shift altgr +Arabic_beh 0x21 altgr +bracketright 0x21 shift altgr +Arabic_lam 0x22 altgr +UFEF7 0x22 shift altgr +Arabic_alef 0x23 altgr +Arabic_hamzaonalef 0x23 shift altgr +Arabic_teh 0x24 altgr +Arabic_tatweel 0x24 shift altgr +Arabic_noon 0x25 altgr +Arabic_comma 0x25 shift altgr +Arabic_meem 0x26 altgr +slash 0x26 shift altgr +semicolon 0x27 +colon 0x27 shift +Arabic_kaf 0x27 altgr +apostrophe 0x28 +quotedbl 0x28 shift +Arabic_tah 0x28 altgr +grave 0x29 +asciitilde 0x29 shift +Arabic_thal 0x29 altgr +Arabic_shadda 0x29 shift altgr +backslash 0x2b +bar 0x2b shift +less 0x2b altgr +greater 0x2b shift altgr +Arabic_hamzaonyeh 0x2c altgr +asciitilde 0x2c shift altgr +Arabic_hamza 0x2d altgr +Arabic_sukun 0x2d shift altgr +Arabic_hamzaonwaw 0x2e altgr +Arabic_kasra 0x2e shift altgr +Arabic_ra 0x2f altgr +Arabic_kasratan 0x2f shift altgr +UFEFB 0x30 altgr +UFEF5 0x30 shift altgr +Arabic_alefmaksura 0x31 altgr +Arabic_maddaonalef 0x31 shift altgr +Arabic_tehmarbuta 0x32 altgr +apostrophe 0x32 shift altgr +comma 0x33 +less 0x33 shift +Arabic_waw 0x33 altgr +period 0x34 +greater 0x34 shift +Arabic_zain 0x34 altgr +slash 0x35 +question 0x35 shift +Arabic_zah 0x35 altgr +Arabic_question_mark 0x35 shift altgr diff --git a/keymaps/common b/keymaps/common new file mode 100644 index 000000000..0b53f1c25 --- /dev/null +++ b/keymaps/common @@ -0,0 +1,157 @@ +include modifiers + +# +# Top row +# +1 0x2 +2 0x3 +3 0x4 +4 0x5 +5 0x6 +6 0x7 +7 0x8 +8 0x9 +9 0xa +0 0xb +BackSpace 0xe + +# +# QWERTY first row +# +Tab 0xf localstate +ISO_Left_Tab 0xf shift +q 0x10 addupper +w 0x11 addupper +e 0x12 addupper +r 0x13 addupper +t 0x14 addupper +y 0x15 addupper +u 0x16 addupper +i 0x17 addupper +o 0x18 addupper +p 0x19 addupper + +# +# QWERTY second row +# +a 0x1e addupper +s 0x1f addupper +d 0x20 addupper +f 0x21 addupper +g 0x22 addupper +h 0x23 addupper +j 0x24 addupper +k 0x25 addupper +l 0x26 addupper +Return 0x1c localstate + +# +# QWERTY third row +# +z 0x2c addupper +x 0x2d addupper +c 0x2e addupper +v 0x2f addupper +b 0x30 addupper +n 0x31 addupper +m 0x32 addupper + +space 0x39 localstate + +less 0x56 +greater 0x56 shift +bar 0x56 altgr +brokenbar 0x56 shift altgr + +# +# Esc and Function keys +# +Escape 0x1 localstate +F1 0x3b localstate +F2 0x3c localstate +F3 0x3d localstate +F4 0x3e localstate +F5 0x3f localstate +F6 0x40 localstate +F7 0x41 localstate +F8 0x42 localstate +F9 0x43 localstate +F10 0x44 localstate +F11 0x57 localstate +F12 0x58 localstate + +# Printscreen, Scrollock and Pause +# Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37), +# but (0xe0, 0x37) seems to work. +Print 0xb7 localstate +Sys_Req 0xb7 localstate +Execute 0xb7 localstate +Scroll_Lock 0x46 + +# +# Insert - PgDown +# +Insert 0xd2 localstate +Delete 0xd3 localstate +Home 0xc7 localstate +End 0xcf localstate +Page_Up 0xc9 localstate +Page_Down 0xd1 localstate + +# +# Arrow keys +# +Left 0xcb localstate +Up 0xc8 localstate +Down 0xd0 localstate +Right 0xcd localstate + +# +# Numpad +# +Num_Lock 0x45 +KP_Divide 0xb5 +KP_Multiply 0x37 +KP_Subtract 0x4a +KP_Add 0x4e +KP_Enter 0x9c + +KP_Decimal 0x53 numlock +KP_Separator 0x53 numlock +KP_Delete 0x53 + +KP_0 0x52 numlock +KP_Insert 0x52 + +KP_1 0x4f numlock +KP_End 0x4f + +KP_2 0x50 numlock +KP_Down 0x50 + +KP_3 0x51 numlock +KP_Next 0x51 + +KP_4 0x4b numlock +KP_Left 0x4b + +KP_5 0x4c numlock +KP_Begin 0x4c + +KP_6 0x4d numlock +KP_Right 0x4d + +KP_7 0x47 numlock +KP_Home 0x47 + +KP_8 0x48 numlock +KP_Up 0x48 + +KP_9 0x49 numlock +KP_Prior 0x49 + +Caps_Lock 0x3a +# +# Inhibited keys +# +Multi_key 0x0 inhibit diff --git a/keymaps/da b/keymaps/da new file mode 100644 index 000000000..3884dcf14 --- /dev/null +++ b/keymaps/da @@ -0,0 +1,120 @@ +# generated from XKB map dk +include common +map 0x406 +exclam 0x02 shift +exclamdown 0x02 altgr +onesuperior 0x02 shift altgr +quotedbl 0x03 shift +at 0x03 altgr +twosuperior 0x03 shift altgr +numbersign 0x04 shift +sterling 0x04 altgr +threesuperior 0x04 shift altgr +currency 0x05 shift +dollar 0x05 altgr +onequarter 0x05 shift altgr +percent 0x06 shift +onehalf 0x06 altgr +cent 0x06 shift altgr +ampersand 0x07 shift +yen 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +division 0x08 shift altgr +parenleft 0x09 shift +bracketleft 0x09 altgr +guillemotleft 0x09 shift altgr +parenright 0x0a shift +bracketright 0x0a altgr +guillemotright 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +plus 0x0c +question 0x0c shift +plusminus 0x0c altgr +questiondown 0x0c shift altgr +dead_acute 0x0d +dead_grave 0x0d shift +bar 0x0d altgr +brokenbar 0x0d shift altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +cent 0x12 shift altgr +registered 0x13 altgr +thorn 0x14 altgr +THORN 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oe 0x18 altgr +OE 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +aring 0x1a +Aring 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +dead_diaeresis 0x1b +dead_circumflex 0x1b shift +dead_tilde 0x1b altgr +dead_caron 0x1b shift altgr +ordfeminine 0x1e altgr +masculine 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +ae 0x27 +AE 0x27 shift +oslash 0x28 +Ooblique 0x28 shift +dead_caron 0x28 shift altgr +onehalf 0x29 +section 0x29 shift +threequarters 0x29 altgr +paragraph 0x29 shift altgr +apostrophe 0x2b +asterisk 0x2b shift +dead_doubleacute 0x2b altgr +multiply 0x2b shift altgr +guillemotleft 0x2c altgr +guillemotright 0x2d altgr +copyright 0x2e altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +dead_cedilla 0x33 altgr +dead_ogonek 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +dead_abovedot 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +hyphen 0x35 altgr +macron 0x35 shift altgr +nobreakspace 0x39 altgr +less 0x56 +greater 0x56 shift +backslash 0x56 altgr +notsign 0x56 shift altgr diff --git a/keymaps/de b/keymaps/de new file mode 100644 index 000000000..ed929c743 --- /dev/null +++ b/keymaps/de @@ -0,0 +1,114 @@ +# generated from XKB map de +include common +map 0x407 +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +quotedbl 0x03 shift +twosuperior 0x03 altgr +oneeighth 0x03 shift altgr +section 0x04 shift +threesuperior 0x04 altgr +sterling 0x04 shift altgr +dollar 0x05 shift +onequarter 0x05 altgr +currency 0x05 shift altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +ampersand 0x07 shift +threequarters 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +parenleft 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +parenright 0x0a shift +bracketright 0x0a altgr +plusminus 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +ssharp 0x0c +question 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +acute 0x0d +dead_acute 0x0d +grave 0x0d shift +dead_grave 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +EuroSign 0x12 altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +z 0x15 addupper +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +udiaeresis 0x1a +Udiaeresis 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +plus 0x1b +asterisk 0x1b shift +asciitilde 0x1b altgr +dead_tilde 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +odiaeresis 0x27 +Odiaeresis 0x27 shift +dead_doubleacute 0x27 altgr +adiaeresis 0x28 +Adiaeresis 0x28 shift +dead_caron 0x28 shift altgr +asciicircum 0x29 +dead_circumflex 0x29 +degree 0x29 shift +notsign 0x29 altgr +numbersign 0x2b +apostrophe 0x2b shift +dead_breve 0x2b shift altgr +y 0x2c addupper +guillemotleft 0x2c altgr +guillemotright 0x2d altgr +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/keymaps/de-ch b/keymaps/de-ch new file mode 100644 index 000000000..f83837b44 --- /dev/null +++ b/keymaps/de-ch @@ -0,0 +1,169 @@ +# rdesktop Swiss-German (de-ch) keymap file +# 2003-06-03 by noldi@tristar.ch +# +include common +map 0x00000807 +# +# Scan Code 1 +section 0x29 +degree 0x29 shift +notsign 0x29 altgr inhibit +# +# Scan Code 2 +plus 0x2 shift +brokenbar 0x02 altgr +# +# Scan Code 3 +quotedbl 0x03 shift +at 0x03 altgr +# +# Scan Code 4 +asterisk 0x04 shift +numbersign 0x04 altgr +# +# Scan Code 5 +ccedilla 0x05 shift +onequarter 0x05 altgr inhibit +# +# Scan Code 6 +percent 0x06 shift +onehalf 0x06 altgr inhibit +# +# Scan Code 7 +ampersand 0x07 shift +notsign 0x07 altgr +# +# Scan Code 8 +slash 0x08 shift +bar 0x08 altgr +# +# Scan Code 9 +parenleft 0x09 shift +cent 0x09 altgr +# +# Scan Code 10 +parenright 0x0a shift +# +# Scan Code 11 +equal 0x0b shift +braceright 0x0b altgr inhibit +# +# Scan Code 12 +apostrophe 0x0c +question 0x0c shift +dead_acute 0x0c altgr +# +# Scan Code 13 +dead_circumflex 0x0d +dead_grave 0x0d shift +dead_tilde 0x0d altgr +# +# Scan Code 19 +EuroSign 0x12 altgr +# +# Scan Code 22 +z 0x15 addupper +# +# Scan Code 27 +udiaeresis 0x1a +egrave 0x1a shift +bracketleft 0x1a altgr +# +# Scan Code 28 +dead_diaeresis 0x1b +exclam 0x1b shift +bracketright 0x1b altgr +# +# Scan Code 40 +odiaeresis 0x27 +eacute 0x27 shift +# +# Scan Code 41 +adiaeresis 0x28 +agrave 0x28 shift +braceleft 0x28 altgr +# +# Scan Code 42 (only on international keyboards) +dollar 0x2b +sterling 0x2b shift +braceright 0x2b altgr +# +# Scan Code 45 (only on international keyboards) +backslash 0x56 altgr +# +# Scan Code 46 +y 0x2c addupper +# +# Scan Code 53 +comma 0x33 +semicolon 0x33 shift +# +# Scan Code 54 +period 0x34 +colon 0x34 shift +# +# Scan Code 55 +minus 0x35 +underscore 0x35 shift +# +# Suppress Windows unsupported AltGr keys +# +# Scan Code 17 +paragraph 0x10 altgr inhibit +# +# Scan Code 21 +tslash 0x14 altgr inhibit +# +# Scan Code 22 +leftarrow 0x15 altgr inhibit +# +# Scan Code 23 +downarrow 0x16 altgr inhibit +# +# Scan Code 24 +rightarrow 0x17 altgr inhibit +# +# Scan Code 25 +oslash 0x18 altgr inhibit +# +# Scan Code 26 +thorn 0x19 altgr inhibit +# +# Scan Code 31 +ae 0x1e altgr inhibit +# +# Scan Code 32 +ssharp 0x1f altgr inhibit +# +# Scan Code 33 +eth 0x20 altgr inhibit +# +# Scan Code 34 +dstroke 0x21 altgr inhibit +# +# Scan Code 35 +eng 0x22 altgr inhibit +# +# Scan Code 36 +hstroke 0x23 altgr inhibit +# +# Scan Code 38 +kra 0x25 altgr inhibit +# +# Scan Code 39 +lstroke 0x26 altgr inhibit +# +# Scan Code 46 +guillemotleft 0x2c altgr inhibit +# +# Scan Code 47 +guillemotright 0x2d altgr inhibit +# +# Scan Code 49 +leftdoublequotemark 0x2f altgr inhibit +# +# Scan Code 50 +rightdoublequotemark 0x30 altgr inhibit +# +# Scan Code 52 +mu 0x32 altgr inhibit diff --git a/keymaps/en-gb b/keymaps/en-gb new file mode 100644 index 000000000..b45f06c7c --- /dev/null +++ b/keymaps/en-gb @@ -0,0 +1,119 @@ +# generated from XKB map gb +include common +map 0x809 +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +quotedbl 0x03 shift +twosuperior 0x03 altgr +oneeighth 0x03 shift altgr +sterling 0x04 shift +threesuperior 0x04 altgr +dollar 0x05 shift +EuroSign 0x05 altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +asciicircum 0x07 shift +threequarters 0x07 altgr +fiveeighths 0x07 shift altgr +ampersand 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +asterisk 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +parenleft 0x0a shift +bracketright 0x0a altgr +plusminus 0x0a shift altgr +parenright 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +minus 0x0c +underscore 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +equal 0x0d +plus 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +bracketleft 0x1a +braceleft 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +bracketright 0x1b +braceright 0x1b shift +dead_tilde 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +semicolon 0x27 +colon 0x27 shift +dead_acute 0x27 altgr +dead_doubleacute 0x27 shift altgr +apostrophe 0x28 +at 0x28 shift +dead_circumflex 0x28 altgr +dead_caron 0x28 shift altgr +grave 0x29 +notsign 0x29 shift +bar 0x29 altgr +numbersign 0x2b +asciitilde 0x2b shift +dead_grave 0x2b altgr +dead_breve 0x2b shift altgr +guillemotleft 0x2c altgr +less 0x2c shift altgr +guillemotright 0x2d altgr +greater 0x2d shift altgr +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +less 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +greater 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +slash 0x35 +question 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr +backslash 0x56 +bar 0x56 shift diff --git a/keymaps/en-us b/keymaps/en-us new file mode 100644 index 000000000..f5784bbb3 --- /dev/null +++ b/keymaps/en-us @@ -0,0 +1,35 @@ +# generated from XKB map us +include common +map 0x409 +exclam 0x02 shift +at 0x03 shift +numbersign 0x04 shift +dollar 0x05 shift +percent 0x06 shift +asciicircum 0x07 shift +ampersand 0x08 shift +asterisk 0x09 shift +parenleft 0x0a shift +parenright 0x0b shift +minus 0x0c +underscore 0x0c shift +equal 0x0d +plus 0x0d shift +bracketleft 0x1a +braceleft 0x1a shift +bracketright 0x1b +braceright 0x1b shift +semicolon 0x27 +colon 0x27 shift +apostrophe 0x28 +quotedbl 0x28 shift +grave 0x29 +asciitilde 0x29 shift +backslash 0x2b +bar 0x2b shift +comma 0x33 +less 0x33 shift +period 0x34 +greater 0x34 shift +slash 0x35 +question 0x35 shift diff --git a/keymaps/es b/keymaps/es new file mode 100644 index 000000000..0c29eec5a --- /dev/null +++ b/keymaps/es @@ -0,0 +1,105 @@ +# generated from XKB map es +include common +map 0x40a +exclam 0x02 shift +bar 0x02 altgr +quotedbl 0x03 shift +at 0x03 altgr +oneeighth 0x03 shift altgr +periodcentered 0x04 shift +numbersign 0x04 altgr +sterling 0x04 shift altgr +dollar 0x05 shift +asciitilde 0x05 altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +ampersand 0x07 shift +notsign 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +seveneighths 0x08 shift altgr +parenleft 0x09 shift +trademark 0x09 shift altgr +parenright 0x0a shift +plusminus 0x0a shift altgr +equal 0x0b shift +degree 0x0b shift altgr +apostrophe 0x0c +question 0x0c shift +exclamdown 0x0d +questiondown 0x0d shift +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +dead_grave 0x1a +dead_circumflex 0x1a shift +bracketleft 0x1a altgr +dead_abovering 0x1a shift altgr +plus 0x1b +asterisk 0x1b shift +bracketright 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +ntilde 0x27 +Ntilde 0x27 shift +dead_doubleacute 0x27 shift altgr +dead_acute 0x28 +dead_diaeresis 0x28 shift +braceleft 0x28 altgr +masculine 0x29 +ordfeminine 0x29 shift +backslash 0x29 altgr +ccedilla 0x2b +Ccedilla 0x2b shift +braceright 0x2b altgr +dead_breve 0x2b shift altgr +guillemotleft 0x2c altgr +less 0x56 +greater 0x56 shift +guillemotright 0x2d altgr +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +comma 0x33 +semicolon 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +colon 0x34 shift +division 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/keymaps/et b/keymaps/et new file mode 100644 index 000000000..b5a73fef7 --- /dev/null +++ b/keymaps/et @@ -0,0 +1,86 @@ +map 0x00000425 +include common + +# +# Top row +# +dead_caron 0x29 +dead_tilde 0x29 shift + +# 1 +exclam 0x2 shift + +# 2 +quotedbl 0x3 shift +at 0x3 altgr + +# 3 +numbersign 0x4 shift +sterling 0x4 altgr +# 4 +currency 0x5 shift +dollar 0x5 altgr +# 5 +percent 0x6 shift +# 6 +ampersand 0x7 shift +# 7 +slash 0x8 shift +braceleft 0x8 altgr +# 8 +parenleft 0x9 shift +bracketleft 0x9 altgr +# 9 +parenright 0xa shift +bracketright 0xa altgr +# 0 +equal 0xb shift +braceright 0xb altgr + +plus 0xc +question 0xc shift +backslash 0xc altgr + +acute 0xd +dead_acute 0xd +grave 0xd shift +dead_grave 0xd shift + +# +# QWERTY first row +# +EuroSign 0x12 altgr +udiaeresis 0x1a +Udiaeresis 0x1a shift +otilde 0x1b +Otilde 0x1b shift +section 0x1b altgr + +# +# QWERTY second row +# +scaron 0x1f altgr +Scaron 0x1f altgr shift +odiaeresis 0x27 +Odiaeresis 0x27 shift +adiaeresis 0x28 +Adiaeresis 0x28 shift +asciicircum 0x28 altgr +apostrophe 0x2b +asterisk 0x2b shift +onehalf 0x2b altgr +# +# QWERTY third row +# +less 0x56 +greater 0x56 shift +bar 0x56 altgr +zcaron 0x2c altgr +Zcaron 0x2c altgr shift +comma 0x33 +semicolon 0x33 shift +period 0x34 +colon 0x34 shift +minus 0x35 +underscore 0x35 shift + diff --git a/keymaps/fi b/keymaps/fi new file mode 100644 index 000000000..2a4e0f045 --- /dev/null +++ b/keymaps/fi @@ -0,0 +1,124 @@ +# generated from XKB map se_FI +include common +map 0x40b +exclam 0x02 shift +exclamdown 0x02 altgr +onesuperior 0x02 shift altgr +quotedbl 0x03 shift +at 0x03 altgr +twosuperior 0x03 shift altgr +numbersign 0x04 shift +sterling 0x04 altgr +threesuperior 0x04 shift altgr +currency 0x05 shift +dollar 0x05 altgr +onequarter 0x05 shift altgr +percent 0x06 shift +onehalf 0x06 altgr +cent 0x06 shift altgr +ampersand 0x07 shift +yen 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +division 0x08 shift altgr +parenleft 0x09 shift +bracketleft 0x09 altgr +guillemotleft 0x09 shift altgr +parenright 0x0a shift +bracketright 0x0a altgr +guillemotright 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +plus 0x0c +question 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +dead_acute 0x0d +dead_grave 0x0d shift +plusminus 0x0d altgr +notsign 0x0d shift altgr +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +cent 0x12 shift altgr +registered 0x13 altgr +thorn 0x14 altgr +THORN 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oe 0x18 altgr +OE 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +aring 0x1a +Aring 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +dead_diaeresis 0x1b +dead_circumflex 0x1b shift +dead_tilde 0x1b altgr +dead_caron 0x1b shift altgr +ordfeminine 0x1e altgr +masculine 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +ampersand 0x25 shift altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +odiaeresis 0x27 +Odiaeresis 0x27 shift +oslash 0x27 altgr +Ooblique 0x27 shift altgr +adiaeresis 0x28 +Adiaeresis 0x28 shift +ae 0x28 altgr +AE 0x28 shift altgr +section 0x29 +onehalf 0x29 shift +paragraph 0x29 altgr +threequarters 0x29 shift altgr +apostrophe 0x2b +asterisk 0x2b shift +acute 0x2b altgr +multiply 0x2b shift altgr +guillemotleft 0x2c altgr +less 0x2c shift altgr +guillemotright 0x2d altgr +greater 0x2d shift altgr +copyright 0x2e altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +apostrophe 0x30 shift altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +dead_cedilla 0x33 altgr +dead_ogonek 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +dead_abovedot 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +hyphen 0x35 altgr +macron 0x35 shift altgr +nobreakspace 0x39 altgr diff --git a/keymaps/fo b/keymaps/fo new file mode 100644 index 000000000..83add423c --- /dev/null +++ b/keymaps/fo @@ -0,0 +1,77 @@ +map 0x438 +include common + +# +# Top row +# +onehalf 0x29 +section 0x29 shift + +# 1 +exclam 0x2 shift + +# 2 +quotedbl 0x3 shift +at 0x3 altgr + +# 3 +numbersign 0x4 shift +sterling 0x4 altgr +# 4 +currency 0x5 shift +dollar 0x5 altgr +# 5 +percent 0x6 shift +# 6 +ampersand 0x7 shift +# 7 +slash 0x8 shift +braceleft 0x8 altgr +# 8 +parenleft 0x9 shift +bracketleft 0x9 altgr +# 9 +parenright 0xa shift +bracketright 0xa altgr +# 0 +equal 0xb shift +braceright 0xb altgr + +plus 0xc +question 0xc shift +plusminus 0xc altgr + +bar 0xd altgr +dead_acute 0xd + +# +# QWERTY first row +# +EuroSign 0x12 altgr +aring 0x1a +Aring 0x1a shift +eth 0x1b addupper +asciitilde 0x1b altgr + +# +# QWERTY second row +# +ae 0x27 addupper +oslash 0x28 +Ooblique 0x28 shift +apostrophe 0x2b +asterisk 0x2b shift + +# +# QWERTY third row +# +less 0x56 +greater 0x56 shift +backslash 0x56 altgr +comma 0x33 +semicolon 0x33 shift +period 0x34 +colon 0x34 shift +minus 0x35 +underscore 0x35 shift + diff --git a/keymaps/fr b/keymaps/fr new file mode 100644 index 000000000..cbb45910f --- /dev/null +++ b/keymaps/fr @@ -0,0 +1,181 @@ +include common +map 0x40c +# +# Top row +# +twosuperior 0x29 +notsign 0x29 altgr + +ampersand 0x02 +1 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr + +eacute 0x03 +2 0x03 shift +asciitilde 0x03 altgr +oneeighth 0x03 shift altgr + +quotedbl 0x04 +3 0x04 shift +numbersign 0x04 altgr + +apostrophe 0x05 +4 0x05 shift +braceleft 0x05 altgr + +parenleft 0x06 +5 0x06 shift +bracketleft 0x06 altgr +threeeighths 0x06 shift altgr + +minus 0x07 +6 0x07 shift +bar 0x07 altgr +fiveeighths 0x07 shift altgr + +egrave 0x08 +7 0x08 shift +grave 0x08 altgr +seveneighths 0x08 shift altgr + +underscore 0x09 +8 0x09 shift +backslash 0x09 altgr +trademark 0x09 shift altgr + +ccedilla 0x0a +9 0x0a shift +asciicircum 0x0a altgr +plusminus 0x0a shift altgr + +agrave 0x0b +0 0x0b shift +at 0x0b altgr + +parenright 0x0c +degree 0x0c shift +bracketright 0x0c altgr +questiondown 0x0c shift altgr + +equal 0x0d +plus 0x0d shift +braceright 0x0d altgr +dead_ogonek 0x0d shift altgr + +# +# AZERTY first row +# + +a 0x10 addupper +ae 0x10 altgr +AE 0x10 shift altgr + +z 0x11 addupper +guillemotleft 0x11 altgr + +EuroSign 0x12 altgr + +paragraph 0x13 altgr +registered 0x13 shift altgr + +tslash 0x14 altgr +Tslash 0x14 shift altgr + +leftarrow 0x15 altgr +yen 0x15 shift altgr + +downarrow 0x16 altgr +uparrow 0x16 shift altgr + +rightarrow 0x17 altgr +idotless 0x17 shift altgr + +oslash 0x18 altgr +Ooblique 0x18 shift altgr + +thorn 0x19 altgr +THORN 0x19 shift altgr + +dead_circumflex 0x1a +dead_diaeresis 0x1a shift +dead_abovering 0x1a shift altgr + +dollar 0x1b +sterling 0x1b shift +currency 0x1b altgr +dead_macron 0x1b shift altgr + +# +# AZERTY second row +# +q 0x1e addupper +Greek_OMEGA 0x1e shift altgr + +ssharp 0x1f altgr + +eth 0x20 altgr +ETH 0x20 shift altgr + +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr + +eng 0x22 altgr +ENG 0x22 shift altgr + +hstroke 0x23 altgr +Hstroke 0x23 shift altgr + +kra 0x25 altgr + +lstroke 0x26 altgr +Lstroke 0x26 shift altgr + +m 0x27 addupper +masculine 0x27 shift altgr + +ugrave 0x28 +percent 0x28 shift +dead_caron 0x28 shift altgr + +asterisk 0x2b +mu 0x2b shift +dead_grave 0x2b altgr +dead_breve 0x2b shift altgr + +# +# AZERTY third row +# +less 0x56 +greater 0x56 shift + +w 0x2c addupper + +guillemotright 0x2d altgr + +cent 0x2e altgr +copyright 0x2e shift altgr + +leftdoublequotemark 0x2f altgr + +rightdoublequotemark 0x30 altgr + +comma 0x32 +question 0x32 shift +dead_acute 0x32 altgr +dead_doubleacute 0x32 shift altgr + +semicolon 0x33 +period 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr + +colon 0x34 +slash 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr + +exclam 0x35 +section 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/keymaps/fr-be b/keymaps/fr-be new file mode 100644 index 000000000..92d668eb6 --- /dev/null +++ b/keymaps/fr-be @@ -0,0 +1,140 @@ +# generated from XKB map be +include common +map 0x80c +ampersand 0x02 +1 0x02 shift +bar 0x02 altgr +exclamdown 0x02 shift altgr +eacute 0x03 +2 0x03 shift +at 0x03 altgr +oneeighth 0x03 shift altgr +quotedbl 0x04 +3 0x04 shift +numbersign 0x04 altgr +sterling 0x04 shift altgr +apostrophe 0x05 +4 0x05 shift +onequarter 0x05 altgr +dollar 0x05 shift altgr +parenleft 0x06 +5 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +section 0x07 +6 0x07 shift +asciicircum 0x07 altgr +fiveeighths 0x07 shift altgr +egrave 0x08 +7 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +exclam 0x09 +8 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +ccedilla 0x0a +9 0x0a shift +braceleft 0x0a altgr +plusminus 0x0a shift altgr +agrave 0x0b +0 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +parenright 0x0c +degree 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +minus 0x0d +underscore 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +a 0x10 addupper +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +z 0x11 addupper +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +cent 0x12 shift altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +dead_circumflex 0x1a +dead_diaeresis 0x1a shift +bracketleft 0x1a altgr +dead_abovering 0x1a shift altgr +dollar 0x1b +asterisk 0x1b shift +bracketright 0x1b altgr +dead_macron 0x1b shift altgr +q 0x1e addupper +ae 0x1e altgr +AE 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +ampersand 0x25 shift altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +m 0x27 addupper +dead_acute 0x27 altgr +dead_doubleacute 0x27 shift altgr +ugrave 0x28 +percent 0x28 shift +dead_acute 0x28 altgr +dead_caron 0x28 shift altgr +twosuperior 0x29 +threesuperior 0x29 shift +notsign 0x29 altgr +mu 0x2b +sterling 0x2b shift +dead_grave 0x2b altgr +dead_breve 0x2b shift altgr +w 0x2c addupper +guillemotleft 0x2c altgr +less 0x2c shift altgr +guillemotright 0x2d altgr +greater 0x2d shift altgr +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +apostrophe 0x30 shift altgr +comma 0x32 +question 0x32 shift +dead_cedilla 0x32 altgr +masculine 0x32 shift altgr +semicolon 0x33 +period 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +colon 0x34 +slash 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +equal 0x35 +plus 0x35 shift +dead_tilde 0x35 altgr +dead_abovedot 0x35 shift altgr +backslash 0x56 altgr diff --git a/keymaps/fr-ca b/keymaps/fr-ca new file mode 100644 index 000000000..b645208e4 --- /dev/null +++ b/keymaps/fr-ca @@ -0,0 +1,50 @@ +# Canadian French +# By Simon Germain +include common +map 0xc0c + +backslash 0x29 altgr +plusminus 0x2 altgr +at 0x3 altgr +sterling 0x4 altgr +cent 0x5 altgr +currency 0x6 altgr +notsign 0x7 altgr +bar 0x29 shift +twosuperior 0x9 altgr +threesuperior 0xa altgr +onequarter 0xb altgr +onehalf 0xc altgr +threequarters 0xd altgr +section 0x18 altgr +paragraph 0x19 altgr +bracketleft 0x1a altgr +bracketright 0x1b altgr +asciitilde 0x27 altgr +braceleft 0x28 altgr +braceright 0x2b altgr +less 0x2b +greater 0x2b shift +guillemotleft 0x56 +guillemotright 0x56 shift +degree 0x56 altgr +mu 0x32 altgr +eacute 0x35 +dead_acute 0x35 altgr +dead_grave 0x28 +dead_circumflex 0x1a +dead_circumflex 0x1a shift +dead_cedilla 0x1b +dead_diaeresis 0x1b shift +exclam 0x2 shift +quotedbl 0x3 shift +slash 0x4 shift +dollar 0x5 shift +percent 0x6 shift +question 0x7 shift +ampersand 0x8 shift +asterisk 0x9 shift +parenleft 0xa shift +parenright 0xb shift +underscore 0xc shift +plus 0xd shift diff --git a/keymaps/fr-ch b/keymaps/fr-ch new file mode 100644 index 000000000..4620d2033 --- /dev/null +++ b/keymaps/fr-ch @@ -0,0 +1,114 @@ +# generated from XKB map fr_CH +include common +map 0x100c +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +quotedbl 0x03 shift +twosuperior 0x03 altgr +oneeighth 0x03 shift altgr +section 0x04 shift +threesuperior 0x04 altgr +sterling 0x04 shift altgr +dollar 0x05 shift +onequarter 0x05 altgr +currency 0x05 shift altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +ampersand 0x07 shift +threequarters 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +parenleft 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +parenright 0x0a shift +bracketright 0x0a altgr +plusminus 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +ssharp 0x0c +question 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +acute 0x0d +dead_acute 0x0d +grave 0x0d shift +dead_grave 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +EuroSign 0x12 altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +z 0x15 addupper +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +udiaeresis 0x1a +Udiaeresis 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +plus 0x1b +asterisk 0x1b shift +asciitilde 0x1b altgr +dead_tilde 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +odiaeresis 0x27 +Odiaeresis 0x27 shift +dead_doubleacute 0x27 altgr +adiaeresis 0x28 +Adiaeresis 0x28 shift +dead_caron 0x28 shift altgr +asciicircum 0x29 +dead_circumflex 0x29 +degree 0x29 shift +notsign 0x29 altgr +numbersign 0x2b +apostrophe 0x2b shift +dead_breve 0x2b shift altgr +y 0x2c addupper +guillemotleft 0x2c altgr +guillemotright 0x2d altgr +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/keymaps/hr b/keymaps/hr new file mode 100644 index 000000000..613aa6925 --- /dev/null +++ b/keymaps/hr @@ -0,0 +1,125 @@ +# generated from XKB map hr +include common +map 0x41a +exclam 0x02 shift +asciitilde 0x02 altgr +dead_tilde 0x02 shift altgr +quotedbl 0x03 shift +dead_caron 0x03 altgr +caron 0x03 shift altgr +numbersign 0x04 shift +asciicircum 0x04 altgr +dead_circumflex 0x04 shift altgr +dollar 0x05 shift +dead_breve 0x05 altgr +breve 0x05 shift altgr +percent 0x06 shift +degree 0x06 altgr +dead_abovering 0x06 shift altgr +ampersand 0x07 shift +dead_ogonek 0x07 altgr +ogonek 0x07 shift altgr +slash 0x08 shift +grave 0x08 altgr +dead_grave 0x08 shift altgr +parenleft 0x09 shift +dead_abovedot 0x09 altgr +abovedot 0x09 shift altgr +parenright 0x0a shift +dead_acute 0x0a altgr +apostrophe 0x0a shift altgr +equal 0x0b shift +dead_doubleacute 0x0b altgr +doubleacute 0x0b shift altgr +apostrophe 0x0c +question 0x0c shift +dead_diaeresis 0x0c altgr +diaeresis 0x0c shift altgr +plus 0x0d +asterisk 0x0d shift +dead_cedilla 0x0d altgr +cedilla 0x0d shift altgr +backslash 0x10 altgr +Greek_OMEGA 0x10 shift altgr +bar 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +z 0x15 addupper +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +scaron 0x1a +Scaron 0x1a shift +division 0x1a altgr +dead_abovering 0x1a shift altgr +dstroke 0x1b +Dstroke 0x1b shift +multiply 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +bracketleft 0x21 altgr +ordfeminine 0x21 shift altgr +bracketright 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +lstroke 0x25 altgr +ampersand 0x25 shift altgr +Lstroke 0x26 altgr +ccaron 0x27 +Ccaron 0x27 shift +dead_acute 0x27 altgr +dead_doubleacute 0x27 shift altgr +cacute 0x28 +Cacute 0x28 shift +ssharp 0x28 altgr +dead_caron 0x28 shift altgr +dead_cedilla 0x29 +dead_diaeresis 0x29 shift +notsign 0x29 altgr +zcaron 0x2b +Zcaron 0x2b shift +currency 0x2b altgr +dead_breve 0x2b shift altgr +y 0x2c addupper +guillemotleft 0x2c altgr +less 0x2c shift altgr +guillemotright 0x2d altgr +greater 0x2d shift altgr +cent 0x2e altgr +copyright 0x2e shift altgr +at 0x2f altgr +grave 0x2f shift altgr +braceleft 0x30 altgr +apostrophe 0x30 shift altgr +braceright 0x31 altgr +section 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/keymaps/hu b/keymaps/hu new file mode 100644 index 000000000..8aba44441 --- /dev/null +++ b/keymaps/hu @@ -0,0 +1,115 @@ +# Hungarian keyboard layout (QWERTZ) +# Created by: The NeverGone + +include common +map 0x40e + + +# AltGr keys: +notsign 0x29 altgr +asciitilde 0x02 altgr +caron 0x03 altgr +asciicircum 0x04 altgr +breve 0x05 altgr +degree 0x06 altgr +ogonek 0x07 altgr +grave 0x08 altgr +abovedot 0x09 altgr +acute 0x0a altgr +doubleacute 0x0b altgr +diaeresis 0x0c altgr +cedilla 0x0d altgr +backslash 0x10 altgr +bar 0x11 altgr +EuroSign 0x12 altgr +Iacute 0x17 altgr +division 0x1a altgr +multiply 0x1b altgr +dstroke 0x1f altgr +Dstroke 0x20 altgr +bracketleft 0x21 altgr +bracketright 0x22 altgr +iacute 0x24 altgr +lstroke 0x25 altgr +Lstroke 0x26 altgr +dollar 0x27 altgr +ssharp 0x28 altgr +currency 0x2b altgr +less 0x56 altgr +greater 0x2c altgr +numbersign 0x2d altgr +ampersand 0x2e altgr +at 0x2f altgr +braceleft 0x30 altgr +braceright 0x31 altgr +semicolon 0x33 altgr +asterisk 0x35 altgr + + +# Shift keys: +section 0x29 shift +apostrophe 0x02 shift +quotedbl 0x03 shift +plus 0x04 shift +exclam 0x05 shift +percent 0x06 shift +slash 0x07 shift +equal 0x08 shift +parenleft 0x09 shift +parenright 0x0a shift +Odiaeresis 0x0b shift +Udiaeresis 0x0c shift +Oacute 0x0d shift +Z 0x15 shift +Odoubleacute 0x1a shift +Uacute 0x1b shift +Eacute 0x27 shift +Aacute 0x28 shift +Udoubleacute 0x2b shift +Y 0x2c shift +question 0x33 shift +colon 0x34 shift +underscore 0x35 shift +F13 0x3b shift +F14 0x3c shift +F15 0x3d shift +F16 0x3e shift +F17 0x3f shift +F18 0x40 shift +F19 0x41 shift +F20 0x42 shift +F21 0x43 shift +F22 0x44 shift +F23 0x57 shift +F24 0x58 shift + + +# Ctrl keys: +F25 0x3b ctrl +F26 0x3c ctrl +F27 0x3d ctrl +F28 0x3e ctrl +F29 0x3f ctrl +F30 0x40 ctrl +F31 0x41 ctrl +F32 0x42 ctrl +F33 0x43 ctrl +F34 0x44 ctrl +F35 0x57 ctrl +#NoSymbol 0x58 ctrl + + +0 0x29 +odiaeresis 0x0b +udiaeresis 0x0c +oacute 0x0d +z 0x15 +odoubleacute 0x1a +uacute 0x1b +eacute 0x27 +aacute 0x28 +udoubleacute 0x2b +y 0x2c +comma 0x33 +period 0x34 +minus 0x35 diff --git a/keymaps/is b/keymaps/is new file mode 100644 index 000000000..8fde40f19 --- /dev/null +++ b/keymaps/is @@ -0,0 +1,140 @@ +# 2004-03-16 Halldr Gumundsson and Morten Lange +# Keyboard definition file for the Icelandic keyboard +# to be used in rdesktop 1.3.x ( See rdesktop.org) +# generated from XKB map de, and changed manually +# Location for example /usr/local/share/rdesktop/keymaps/is +include common +map 0x40f +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +quotedbl 0x03 shift +twosuperior 0x03 altgr +oneeighth 0x03 shift altgr +#section 0x04 shift +numbersign 0x04 shift +threesuperior 0x04 altgr +sterling 0x04 shift altgr +dollar 0x05 shift +onequarter 0x05 altgr +currency 0x05 shift altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +ampersand 0x07 shift +threequarters 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +parenleft 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +parenright 0x0a shift +bracketright 0x0a altgr +plusminus 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +#ssharp 0x0c +odiaeresis 0x0c +#question 0x0c shift +Odiaeresis 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +#acute 0x0d +minus 0x0d +#dead_acute 0x0d +#grave 0x0d shift +#dead_grave 0x0d shift +underscore 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +EuroSign 0x12 altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +#z 0x15 addupper +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +#thorn 0x19 altgr +#THORN 0x19 shift altgr +#udiaeresis 0x1a +#Udiaeresis 0x1a shift +#dead_diaeresis 0x1a altgr +#dead_abovering 0x1a shift altgr +eth 0x1a +ETH 0x1a shift +apostrophe 0x1b +question 0x1b shift +#plus 0x1b +#asterisk 0x1b shift +asciitilde 0x1b altgr +#grave 0x1b altgr +#dead_tilde 0x1b altgr +#dead_macron 0x1b shift altgr +#ae 0x1e altgr +#AE 0x1e shift altgr +#eth 0x20 altgr +#eth 0x20 +#ETH 0x20 shift altgr +#ETH 0x20 shift +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +#adiaeresis 0x27 +#Adiaeresis 0x27 shift +ae 0x27 +AE 0x27 shift +dead_doubleacute 0x27 altgr +#adiaeresis 0x28 +#Adiaeresis 0x28 shift +#dead_caron 0x28 shift altgr +#asciicircum 0x29 +acute 0x28 +dead_acute 0x28 +#dead_circumflex 0x29 +#degree 0x29 shift +#notsign 0x29 altgr +plus 0x2b +asterisk 0x2b shift +grave 0x2b altgr +#numbersign 0x2b +#apostrophe 0x2b shift +#dead_breve 0x2b shift altgr +#y 0x2c addupper +guillemotleft 0x2c altgr +guillemotright 0x2d altgr +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +#minus 0x35 +#underscore 0x35 shift +thorn 0x35 +THORN 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr + diff --git a/keymaps/it b/keymaps/it new file mode 100644 index 000000000..00ca73a3e --- /dev/null +++ b/keymaps/it @@ -0,0 +1,115 @@ +# generated from XKB map it +include common +map 0x410 +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +quotedbl 0x03 shift +twosuperior 0x03 altgr +oneeighth 0x03 shift altgr +sterling 0x04 shift +threesuperior 0x04 altgr +dollar 0x05 shift +onequarter 0x05 altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +ampersand 0x07 shift +threequarters 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +parenleft 0x09 shift +trademark 0x09 shift altgr +parenright 0x0a shift +plusminus 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +apostrophe 0x0c +question 0x0c shift +grave 0x0c altgr +questiondown 0x0c shift altgr +igrave 0x0d +asciicircum 0x0d shift +asciitilde 0x0d altgr +dead_ogonek 0x0d shift altgr +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +cent 0x12 shift altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +egrave 0x1a +eacute 0x1a shift +bracketleft 0x1a altgr +dead_abovering 0x1a shift altgr +plus 0x1b +asterisk 0x1b shift +bracketright 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +ograve 0x27 +ccedilla 0x27 shift +at 0x27 altgr +dead_doubleacute 0x27 shift altgr +agrave 0x28 +degree 0x28 shift +numbersign 0x28 altgr +backslash 0x29 +bar 0x29 shift +notsign 0x29 altgr +ugrave 0x2b +section 0x2b shift +dead_grave 0x2b altgr +dead_breve 0x2b shift altgr +guillemotleft 0x2c altgr +guillemotright 0x2d altgr +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/keymaps/ja b/keymaps/ja new file mode 100644 index 000000000..8fd0b9ef1 --- /dev/null +++ b/keymaps/ja @@ -0,0 +1,104 @@ +# generated from XKB map jp106 +include common +map 0x411 +exclam 0x02 shift +kana_NU 0x02 altgr +quotedbl 0x03 shift +kana_FU 0x03 altgr +numbersign 0x04 shift +kana_A 0x04 altgr +kana_a 0x04 shift altgr +dollar 0x05 shift +kana_U 0x05 altgr +kana_u 0x05 shift altgr +percent 0x06 shift +kana_E 0x06 altgr +kana_e 0x06 shift altgr +ampersand 0x07 shift +kana_O 0x07 altgr +kana_o 0x07 shift altgr +apostrophe 0x08 shift +kana_YA 0x08 altgr +kana_ya 0x08 shift altgr +parenleft 0x09 shift +kana_YU 0x09 altgr +kana_yu 0x09 shift altgr +parenright 0x0a shift +kana_YO 0x0a altgr +kana_yo 0x0a shift altgr +asciitilde 0x0b shift +kana_WA 0x0b altgr +kana_WO 0x0b shift altgr +minus 0x0c +equal 0x0c shift +kana_HO 0x0c altgr +asciicircum 0x0d +asciitilde 0x0d shift +kana_HE 0x0d altgr +kana_TA 0x10 altgr +kana_TE 0x11 altgr +kana_I 0x12 altgr +kana_i 0x12 shift altgr +kana_SU 0x13 altgr +kana_KA 0x14 altgr +kana_N 0x15 altgr +kana_NA 0x16 altgr +kana_NI 0x17 altgr +kana_RA 0x18 altgr +kana_SE 0x19 altgr +at 0x1a +grave 0x1a shift +voicedsound 0x1a altgr +bracketleft 0x1b +braceleft 0x1b shift +semivoicedsound 0x1b altgr +kana_openingbracket 0x1b shift altgr +kana_CHI 0x1e altgr +kana_TO 0x1f altgr +kana_SHI 0x20 altgr +kana_HA 0x21 altgr +kana_KI 0x22 altgr +kana_KU 0x23 altgr +kana_MA 0x24 altgr +kana_NO 0x25 altgr +kana_RI 0x26 altgr +semicolon 0x27 +plus 0x27 shift +kana_RE 0x27 altgr +colon 0x28 +asterisk 0x28 shift +kana_KE 0x28 altgr +Zenkaku_Hankaku 0x29 +bracketright 0x2b +braceright 0x2b shift +kana_MU 0x2b altgr +kana_closingbracket 0x2b shift altgr +kana_TSU 0x2c altgr +kana_tsu 0x2c shift altgr +kana_SA 0x2d altgr +kana_SO 0x2e altgr +kana_HI 0x2f altgr +kana_KO 0x30 altgr +kana_MI 0x31 altgr +kana_MO 0x32 altgr +comma 0x33 +less 0x33 shift +kana_NE 0x33 altgr +kana_comma 0x33 shift altgr +period 0x34 +greater 0x34 shift +kana_RU 0x34 altgr +kana_fullstop 0x34 shift altgr +slash 0x35 +question 0x35 shift +kana_ME 0x35 altgr +kana_conjunctive 0x35 shift altgr +Eisu_toggle 0x3a shift +Execute 0x54 shift +Kanji 0x70 +backslash 0x73 +bar 0x7d shift +underscore 0x73 shift +Henkan_Mode 0x79 +Katakana 0x70 +Muhenkan 0x7b diff --git a/keymaps/lt b/keymaps/lt new file mode 100644 index 000000000..3d9d619ea --- /dev/null +++ b/keymaps/lt @@ -0,0 +1,57 @@ +# generated from XKB map lt +include common +map 0x427 +exclam 0x02 shift +aogonek 0x02 altgr +Aogonek 0x02 shift altgr +at 0x03 shift +ccaron 0x03 altgr +Ccaron 0x03 shift altgr +numbersign 0x04 shift +eogonek 0x04 altgr +Eogonek 0x04 shift altgr +dollar 0x05 shift +eabovedot 0x05 altgr +Eabovedot 0x05 shift altgr +percent 0x06 shift +iogonek 0x06 altgr +Iogonek 0x06 shift altgr +asciicircum 0x07 shift +scaron 0x07 altgr +Scaron 0x07 shift altgr +ampersand 0x08 shift +uogonek 0x08 altgr +Uogonek 0x08 shift altgr +asterisk 0x09 shift +umacron 0x09 altgr +Umacron 0x09 shift altgr +parenleft 0x0a shift +doublelowquotemark 0x0a altgr +parenright 0x0b shift +leftdoublequotemark 0x0b altgr +minus 0x0c +underscore 0x0c shift +equal 0x0d +plus 0x0d shift +zcaron 0x0d altgr +Zcaron 0x0d shift altgr +bracketleft 0x1a +braceleft 0x1a shift +bracketright 0x1b +braceright 0x1b shift +semicolon 0x27 +colon 0x27 shift +apostrophe 0x28 +quotedbl 0x28 shift +grave 0x29 +asciitilde 0x29 shift +backslash 0x2b +bar 0x2b shift +comma 0x33 +less 0x33 shift +period 0x34 +greater 0x34 shift +slash 0x35 +question 0x35 shift +endash 0x56 +EuroSign 0x56 shift diff --git a/keymaps/lv b/keymaps/lv new file mode 100644 index 000000000..1d9172791 --- /dev/null +++ b/keymaps/lv @@ -0,0 +1,128 @@ +# generated from XKB map lv +include common +map 0x426 +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +at 0x03 shift +twosuperior 0x03 altgr +oneeighth 0x03 shift altgr +numbersign 0x04 shift +threesuperior 0x04 altgr +sterling 0x04 shift altgr +dollar 0x05 shift +EuroSign 0x05 altgr +cent 0x05 shift altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +asciicircum 0x07 shift +threequarters 0x07 altgr +fiveeighths 0x07 shift altgr +ampersand 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +asterisk 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +parenleft 0x0a shift +bracketright 0x0a altgr +plusminus 0x0a shift altgr +parenright 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +minus 0x0c +underscore 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +equal 0x0d +plus 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +emacron 0x12 altgr +Emacron 0x12 shift altgr +rcedilla 0x13 altgr +Rcedilla 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +umacron 0x16 altgr +Umacron 0x16 shift altgr +imacron 0x17 altgr +Imacron 0x17 shift altgr +omacron 0x18 altgr +Omacron 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +bracketleft 0x1a +braceleft 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +bracketright 0x1b +braceright 0x1b shift +dead_tilde 0x1b altgr +dead_macron 0x1b shift altgr +ISO_Next_Group 0x1c shift +amacron 0x1e altgr +Amacron 0x1e shift altgr +scaron 0x1f altgr +Scaron 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +gcedilla 0x22 altgr +Gcedilla 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kcedilla 0x25 altgr +Kcedilla 0x25 shift altgr +lcedilla 0x26 altgr +Lcedilla 0x26 shift altgr +semicolon 0x27 +colon 0x27 shift +dead_acute 0x27 altgr +dead_doubleacute 0x27 shift altgr +apostrophe 0x28 +quotedbl 0x28 shift +leftdoublequotemark 0x28 altgr +doublelowquotemark 0x28 shift altgr +grave 0x29 +asciitilde 0x29 shift +notsign 0x29 altgr +backslash 0x2b +bar 0x2b shift +dead_grave 0x2b altgr +dead_breve 0x2b shift altgr +zcaron 0x2c altgr +Zcaron 0x2c shift altgr +guillemotright 0x2d altgr +greater 0x2d shift altgr +ccaron 0x2e altgr +Ccaron 0x2e shift altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +apostrophe 0x30 shift altgr +ncedilla 0x31 altgr +Ncedilla 0x31 shift altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +less 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +greater 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +slash 0x35 +question 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr +nobreakspace 0x39 altgr diff --git a/keymaps/mk b/keymaps/mk new file mode 100644 index 000000000..18c150484 --- /dev/null +++ b/keymaps/mk @@ -0,0 +1,101 @@ +# generated from XKB map mk +include common +map 0x42f +exclam 0x02 shift +at 0x03 shift +doublelowquotemark 0x03 shift altgr +numbersign 0x04 shift +leftdoublequotemark 0x04 shift altgr +dollar 0x05 shift +percent 0x06 shift +asciicircum 0x07 shift +ampersand 0x08 shift +asterisk 0x09 shift +parenleft 0x0a shift +parenright 0x0b shift +minus 0x0c +underscore 0x0c shift +equal 0x0d +plus 0x0d shift +Cyrillic_lje 0x10 altgr +Cyrillic_LJE 0x10 shift altgr +Cyrillic_nje 0x11 altgr +Cyrillic_NJE 0x11 shift altgr +Cyrillic_ie 0x12 altgr +Cyrillic_IE 0x12 shift altgr +Cyrillic_er 0x13 altgr +Cyrillic_ER 0x13 shift altgr +Cyrillic_te 0x14 altgr +Cyrillic_TE 0x14 shift altgr +Macedonia_dse 0x15 altgr +Macedonia_DSE 0x15 shift altgr +Cyrillic_u 0x16 altgr +Cyrillic_U 0x16 shift altgr +Cyrillic_i 0x17 altgr +Cyrillic_I 0x17 shift altgr +Cyrillic_o 0x18 altgr +Cyrillic_O 0x18 shift altgr +Cyrillic_pe 0x19 altgr +Cyrillic_PE 0x19 shift altgr +bracketleft 0x1a +braceleft 0x1a shift +Cyrillic_sha 0x1a altgr +Cyrillic_SHA 0x1a shift altgr +bracketright 0x1b +braceright 0x1b shift +Macedonia_gje 0x1b altgr +Macedonia_GJE 0x1b shift altgr +Cyrillic_a 0x1e altgr +Cyrillic_A 0x1e shift altgr +Cyrillic_es 0x1f altgr +Cyrillic_ES 0x1f shift altgr +Cyrillic_de 0x20 altgr +Cyrillic_DE 0x20 shift altgr +Cyrillic_ef 0x21 altgr +Cyrillic_EF 0x21 shift altgr +Cyrillic_ghe 0x22 altgr +Cyrillic_GHE 0x22 shift altgr +Cyrillic_ha 0x23 altgr +Cyrillic_HA 0x23 shift altgr +Cyrillic_je 0x24 altgr +Cyrillic_JE 0x24 shift altgr +Cyrillic_ka 0x25 altgr +Cyrillic_KA 0x25 shift altgr +Cyrillic_el 0x26 altgr +Cyrillic_EL 0x26 shift altgr +semicolon 0x27 +colon 0x27 shift +Cyrillic_che 0x27 altgr +Cyrillic_CHE 0x27 shift altgr +apostrophe 0x28 +quotedbl 0x28 shift +Macedonia_kje 0x28 altgr +Macedonia_KJE 0x28 shift altgr +grave 0x29 +asciitilde 0x29 shift +backslash 0x2b +bar 0x2b shift +Cyrillic_zhe 0x2b altgr +Cyrillic_ZHE 0x2b shift altgr +Cyrillic_ze 0x2c altgr +Cyrillic_ZE 0x2c shift altgr +Cyrillic_dzhe 0x2d altgr +Cyrillic_DZHE 0x2d shift altgr +Cyrillic_tse 0x2e altgr +Cyrillic_TSE 0x2e shift altgr +Cyrillic_ve 0x2f altgr +Cyrillic_VE 0x2f shift altgr +Cyrillic_be 0x30 altgr +Cyrillic_BE 0x30 shift altgr +Cyrillic_en 0x31 altgr +Cyrillic_EN 0x31 shift altgr +Cyrillic_em 0x32 altgr +Cyrillic_EM 0x32 shift altgr +comma 0x33 +less 0x33 shift +semicolon 0x33 shift altgr +period 0x34 +greater 0x34 shift +colon 0x34 shift altgr +slash 0x35 +question 0x35 shift diff --git a/keymaps/modifiers b/keymaps/modifiers new file mode 100644 index 000000000..06c43442e --- /dev/null +++ b/keymaps/modifiers @@ -0,0 +1,16 @@ +Shift_R 0x36 +Shift_L 0x2a + +Alt_R 0xb8 +Mode_switch 0xb8 +Alt_L 0x38 + +Control_R 0x9d +Control_L 0x1d + +# Translate Meta, Super and Hyper to Windows keys. +# This is hardcoded. See documentation for details. + +# Translate Menu to the Windows Application key. +# This one does not work either. +Menu 0xdd diff --git a/keymaps/nl b/keymaps/nl new file mode 100644 index 000000000..bc823bd2f --- /dev/null +++ b/keymaps/nl @@ -0,0 +1,60 @@ +# Dutch (Netherlands) +include common +map 0x413 + +exclam 0x02 shift +onesuperior 0x02 altgr +quotebl 0x03 shift +twosuperior 0x03 altgr +numbersign 0x04 shift +threesuperior 0x04 altgr +dollar 0x05 shift +onequarter 0x05 altgr +percent 0x06 shift +onehalf 0x06 altgr +ampersand 0x07 shift +threequarters 0x07 altgr +underscore 0x08 shift +sterling 0x08 altgr +parenleft 0x09 shift +braceleft 0x09 altgr +parenright 0x0a shift +braceright 0x0a altgr +apostrophe 0x0b shift +slash 0x0c +question 0x0c shift +backslash 0x0c altgr +degree 0x0d +dead_tilde 0x0d shift +dead_cedilla 0x0d altgr +EuroSign 0x12 altgr +paragraph 0x13 altgr +dead_diaeresis 0x1a +dead_circumflex 0x1a shift +asterisk 0x1b +bar 0x1b shift +ssharp 0x1f altgr +plus 0x27 +plusminus 0x27 shift +dead_acute 0x28 +dead_grave 0x28 shift +at 0x29 +section 0x29 shift +notsign 0x29 altgr +less 0x2b +greater 0x2b shift +guillemotleft 0x2c altgr +guillemotright 0x2d altgr +copyright 0x2e altgr +mu 0x32 altgr +comma 0x33 +semicolon 0x33 shift +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +hyphen 0x35 +equal 0x35 shift +bracketright 0x56 +bracketleft 0x56 shift +brokenbar 0x56 altgr + diff --git a/keymaps/nl-be b/keymaps/nl-be new file mode 100644 index 000000000..34fc881ad --- /dev/null +++ b/keymaps/nl-be @@ -0,0 +1,3 @@ +# Dutch (Belgium) +map 0x813 +include common diff --git a/keymaps/no b/keymaps/no new file mode 100644 index 000000000..40a64790d --- /dev/null +++ b/keymaps/no @@ -0,0 +1,119 @@ +# generated from XKB map no +include common +map 0x414 +exclam 0x02 shift +exclamdown 0x02 altgr +onesuperior 0x02 shift altgr +quotedbl 0x03 shift +at 0x03 altgr +twosuperior 0x03 shift altgr +numbersign 0x04 shift +sterling 0x04 altgr +threesuperior 0x04 shift altgr +currency 0x05 shift +dollar 0x05 altgr +onequarter 0x05 shift altgr +percent 0x06 shift +onehalf 0x06 altgr +cent 0x06 shift altgr +ampersand 0x07 shift +yen 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +division 0x08 shift altgr +parenleft 0x09 shift +bracketleft 0x09 altgr +guillemotleft 0x09 shift altgr +parenright 0x0a shift +bracketright 0x0a altgr +guillemotright 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +plus 0x0c +question 0x0c shift +plusminus 0x0c altgr +questiondown 0x0c shift altgr +backslash 0x0d +dead_grave 0x0d shift +dead_acute 0x0d altgr +notsign 0x0d shift altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +cent 0x12 shift altgr +registered 0x13 altgr +thorn 0x14 altgr +THORN 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oe 0x18 altgr +OE 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +aring 0x1a +Aring 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +dead_diaeresis 0x1b +dead_circumflex 0x1b shift +asciicircum 0x01b shift +dead_tilde 0x1b altgr +asciitilde 0x1b altgr +dead_caron 0x1b shift altgr +ordfeminine 0x1e altgr +masculine 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +oslash 0x27 +Ooblique 0x27 shift +dead_doubleacute 0x27 shift altgr +ae 0x28 +AE 0x28 shift +dead_caron 0x28 shift altgr +bar 0x29 +section 0x29 shift +brokenbar 0x29 altgr +paragraph 0x29 shift altgr +apostrophe 0x2b +asterisk 0x2b shift +multiply 0x2b shift altgr +guillemotleft 0x2c altgr +guillemotright 0x2d altgr +copyright 0x2e altgr +leftdoublequotemark 0x2f altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +dead_cedilla 0x33 altgr +dead_ogonek 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +dead_abovedot 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +hyphen 0x35 altgr +macron 0x35 shift altgr +nobreakspace 0x39 altgr +onehalf 0x56 altgr +threequarters 0x56 shift altgr diff --git a/keymaps/pl b/keymaps/pl new file mode 100644 index 000000000..09c600d35 --- /dev/null +++ b/keymaps/pl @@ -0,0 +1,122 @@ +# generated from XKB map pl +include common +map 0x415 +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +at 0x03 shift +twosuperior 0x03 altgr +oneeighth 0x03 shift altgr +numbersign 0x04 shift +threesuperior 0x04 altgr +sterling 0x04 shift altgr +dollar 0x05 shift +onequarter 0x05 altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +asciicircum 0x07 shift +threequarters 0x07 altgr +fiveeighths 0x07 shift altgr +ampersand 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +asterisk 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +parenleft 0x0a shift +bracketright 0x0a altgr +plusminus 0x0a shift altgr +parenright 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +minus 0x0c +underscore 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +equal 0x0d +plus 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +eogonek 0x12 altgr +Eogonek 0x12 shift altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +EuroSign 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oacute 0x18 altgr +Oacute 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +bracketleft 0x1a +braceleft 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +bracketright 0x1b +braceright 0x1b shift +dead_tilde 0x1b altgr +dead_macron 0x1b shift altgr +aogonek 0x1e altgr +Aogonek 0x1e shift altgr +sacute 0x1f altgr +Sacute 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +semicolon 0x27 +colon 0x27 shift +dead_acute 0x27 altgr +dead_doubleacute 0x27 shift altgr +apostrophe 0x28 +quotedbl 0x28 shift +dead_circumflex 0x28 altgr +dead_caron 0x28 shift altgr +grave 0x29 +asciitilde 0x29 shift +notsign 0x29 altgr +backslash 0x2b +bar 0x2b shift +dead_grave 0x2b altgr +dead_breve 0x2b shift altgr +zabovedot 0x2c altgr +Zabovedot 0x2c shift altgr +zacute 0x2d altgr +Zacute 0x2d shift altgr +cacute 0x2e altgr +Cacute 0x2e shift altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +nacute 0x31 altgr +Nacute 0x31 shift altgr +mu 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +less 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +greater 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +slash 0x35 +question 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/keymaps/pt b/keymaps/pt new file mode 100644 index 000000000..c6941f651 --- /dev/null +++ b/keymaps/pt @@ -0,0 +1,113 @@ +# generated from XKB map pt +include common +map 0x816 +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +quotedbl 0x03 shift +at 0x03 altgr +oneeighth 0x03 shift altgr +numbersign 0x04 shift +sterling 0x04 altgr +dollar 0x05 shift +section 0x05 altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +ampersand 0x07 shift +threequarters 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +parenleft 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +parenright 0x0a shift +bracketright 0x0a altgr +plusminus 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +apostrophe 0x0c +question 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +guillemotleft 0x0d +guillemotright 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +cent 0x12 shift altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +plus 0x1a +asterisk 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +dead_acute 0x1b +dead_grave 0x1b shift +dead_tilde 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +ssharp 0x1f altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +ccedilla 0x27 +Ccedilla 0x27 shift +dead_doubleacute 0x27 shift altgr +masculine 0x28 +ordfeminine 0x28 shift +dead_circumflex 0x28 altgr +dead_caron 0x28 shift altgr +backslash 0x29 +bar 0x29 shift +notsign 0x29 altgr +dead_tilde 0x2b +dead_circumflex 0x2b shift +dead_breve 0x2b shift altgr +less 0x56 +greater 0x56 shift +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +mu 0x32 altgr +comma 0x33 +semicolon 0x33 shift +horizconnector 0x33 altgr +multiply 0x33 shift altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +division 0x34 shift altgr +minus 0x35 +underscore 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/keymaps/pt-br b/keymaps/pt-br new file mode 100644 index 000000000..54bafc5dc --- /dev/null +++ b/keymaps/pt-br @@ -0,0 +1,69 @@ +# generated from XKB map br +include common +map 0x416 +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +at 0x03 shift +twosuperior 0x03 altgr +onehalf 0x03 shift altgr +numbersign 0x04 shift +threesuperior 0x04 altgr +threequarters 0x04 shift altgr +dollar 0x05 shift +sterling 0x05 altgr +onequarter 0x05 shift altgr +percent 0x06 shift +cent 0x06 altgr +dead_diaeresis 0x07 shift +notsign 0x07 altgr +diaeresis 0x07 shift altgr +ampersand 0x08 shift +braceleft 0x08 altgr +asterisk 0x09 shift +bracketleft 0x09 altgr +parenleft 0x0a shift +bracketright 0x0a altgr +parenright 0x0b shift +braceright 0x0b altgr +minus 0x0c +underscore 0x0c shift +backslash 0x0c altgr +equal 0x0d +plus 0x0d shift +section 0x0d altgr +EuroSign 0x12 altgr +registered 0x13 altgr +dead_acute 0x1a +dead_grave 0x1a shift +acute 0x1a altgr +grave 0x1a shift altgr +bracketleft 0x1b +braceleft 0x1b shift +ordfeminine 0x1b altgr +ccedilla 0x27 +Ccedilla 0x27 shift +dead_tilde 0x28 +dead_circumflex 0x28 shift +asciitilde 0x28 altgr +asciicircum 0x28 shift altgr +apostrophe 0x29 +quotedbl 0x29 shift +bracketright 0x2b +braceright 0x2b shift +masculine 0x2b altgr +copyright 0x2e altgr +mu 0x32 altgr +comma 0x33 +less 0x33 shift +period 0x34 +greater 0x34 shift +semicolon 0x35 +colon 0x35 shift +comma 0x53 numlock +backslash 0x56 +bar 0x56 shift +slash 0x73 +question 0x73 shift +degree 0x73 altgr +KP_Decimal 0x34 diff --git a/keymaps/ru b/keymaps/ru new file mode 100644 index 000000000..b3e7d24de --- /dev/null +++ b/keymaps/ru @@ -0,0 +1,109 @@ +# generated from XKB map ru +include common +map 0x419 +exclam 0x02 shift +at 0x03 shift +quotedbl 0x03 shift altgr +numbersign 0x04 shift +dollar 0x05 shift +asterisk 0x05 shift altgr +percent 0x06 shift +colon 0x06 shift altgr +asciicircum 0x07 shift +comma 0x07 shift altgr +ampersand 0x08 shift +period 0x08 shift altgr +asterisk 0x09 shift +semicolon 0x09 shift altgr +parenleft 0x0a shift +parenright 0x0b shift +minus 0x0c +underscore 0x0c shift +equal 0x0d +plus 0x0d shift +Cyrillic_shorti 0x10 altgr +Cyrillic_SHORTI 0x10 shift altgr +Cyrillic_tse 0x11 altgr +Cyrillic_TSE 0x11 shift altgr +Cyrillic_u 0x12 altgr +Cyrillic_U 0x12 shift altgr +Cyrillic_ka 0x13 altgr +Cyrillic_KA 0x13 shift altgr +Cyrillic_ie 0x14 altgr +Cyrillic_IE 0x14 shift altgr +Cyrillic_en 0x15 altgr +Cyrillic_EN 0x15 shift altgr +Cyrillic_ghe 0x16 altgr +Cyrillic_GHE 0x16 shift altgr +Cyrillic_sha 0x17 altgr +Cyrillic_SHA 0x17 shift altgr +Cyrillic_shcha 0x18 altgr +Cyrillic_SHCHA 0x18 shift altgr +Cyrillic_ze 0x19 altgr +Cyrillic_ZE 0x19 shift altgr +bracketleft 0x1a +braceleft 0x1a shift +Cyrillic_ha 0x1a altgr +Cyrillic_HA 0x1a shift altgr +bracketright 0x1b +braceright 0x1b shift +Cyrillic_hardsign 0x1b altgr +Cyrillic_HARDSIGN 0x1b shift altgr +Cyrillic_ef 0x1e altgr +Cyrillic_EF 0x1e shift altgr +Cyrillic_yeru 0x1f altgr +Cyrillic_YERU 0x1f shift altgr +Cyrillic_ve 0x20 altgr +Cyrillic_VE 0x20 shift altgr +Cyrillic_a 0x21 altgr +Cyrillic_A 0x21 shift altgr +Cyrillic_pe 0x22 altgr +Cyrillic_PE 0x22 shift altgr +Cyrillic_er 0x23 altgr +Cyrillic_ER 0x23 shift altgr +Cyrillic_o 0x24 altgr +Cyrillic_O 0x24 shift altgr +Cyrillic_el 0x25 altgr +Cyrillic_EL 0x25 shift altgr +Cyrillic_de 0x26 altgr +Cyrillic_DE 0x26 shift altgr +semicolon 0x27 +colon 0x27 shift +Cyrillic_zhe 0x27 altgr +Cyrillic_ZHE 0x27 shift altgr +apostrophe 0x28 +quotedbl 0x28 shift +Cyrillic_e 0x28 altgr +Cyrillic_E 0x28 shift altgr +grave 0x29 +asciitilde 0x29 shift +Cyrillic_io 0x29 altgr +Cyrillic_IO 0x29 shift altgr +backslash 0x2b +bar 0x2b shift +Cyrillic_ya 0x2c altgr +Cyrillic_YA 0x2c shift altgr +Cyrillic_che 0x2d altgr +Cyrillic_CHE 0x2d shift altgr +Cyrillic_es 0x2e altgr +Cyrillic_ES 0x2e shift altgr +Cyrillic_em 0x2f altgr +Cyrillic_EM 0x2f shift altgr +Cyrillic_i 0x30 altgr +Cyrillic_I 0x30 shift altgr +Cyrillic_te 0x31 altgr +Cyrillic_TE 0x31 shift altgr +Cyrillic_softsign 0x32 altgr +Cyrillic_SOFTSIGN 0x32 shift altgr +comma 0x33 +less 0x33 shift +Cyrillic_be 0x33 altgr +Cyrillic_BE 0x33 shift altgr +period 0x34 +greater 0x34 shift +Cyrillic_yu 0x34 altgr +Cyrillic_YU 0x34 shift altgr +slash 0x35 +question 0x35 shift +slash 0x56 altgr +bar 0x56 shift altgr diff --git a/keymaps/sl b/keymaps/sl new file mode 100644 index 000000000..56835a92c --- /dev/null +++ b/keymaps/sl @@ -0,0 +1,110 @@ +# generated from XKB map sl +include common +map 0x424 +exclam 0x02 shift +asciitilde 0x02 altgr +dead_tilde 0x02 shift altgr +quotedbl 0x03 shift +dead_caron 0x03 altgr +caron 0x03 shift altgr +numbersign 0x04 shift +asciicircum 0x04 altgr +dead_circumflex 0x04 shift altgr +dollar 0x05 shift +dead_breve 0x05 altgr +breve 0x05 shift altgr +percent 0x06 shift +degree 0x06 altgr +dead_abovering 0x06 shift altgr +ampersand 0x07 shift +dead_ogonek 0x07 altgr +ogonek 0x07 shift altgr +slash 0x08 shift +grave 0x08 altgr +dead_grave 0x08 shift altgr +parenleft 0x09 shift +dead_abovedot 0x09 altgr +abovedot 0x09 shift altgr +parenright 0x0a shift +dead_acute 0x0a altgr +equal 0x0b shift +dead_doubleacute 0x0b altgr +doubleacute 0x0b shift altgr +apostrophe 0x0c +question 0x0c shift +dead_diaeresis 0x0c altgr +diaeresis 0x0c shift altgr +plus 0x0d +asterisk 0x0d shift +dead_cedilla 0x0d altgr +cedilla 0x0d shift altgr +backslash 0x10 altgr +Greek_OMEGA 0x10 shift altgr +bar 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +z 0x15 addupper +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +rightarrow 0x17 altgr +idotless 0x17 shift altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +scaron 0x1a +Scaron 0x1a shift +division 0x1a altgr +dstroke 0x1b +Dstroke 0x1b shift +multiply 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +bracketleft 0x21 altgr +ordfeminine 0x21 shift altgr +bracketright 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +lstroke 0x25 altgr +Lstroke 0x26 altgr +ccaron 0x27 +Ccaron 0x27 shift +cacute 0x28 +Cacute 0x28 shift +ssharp 0x28 altgr +dead_cedilla 0x29 +notsign 0x29 altgr +zcaron 0x2b +Zcaron 0x2b shift +currency 0x2b altgr +y 0x2c addupper +guillemotleft 0x2c altgr +guillemotright 0x2d altgr +cent 0x2e altgr +copyright 0x2e shift altgr +at 0x2f altgr +braceleft 0x30 altgr +braceright 0x31 altgr +section 0x32 altgr +masculine 0x32 shift altgr +comma 0x33 +semicolon 0x33 shift +horizconnector 0x33 altgr +period 0x34 +colon 0x34 shift +periodcentered 0x34 altgr +minus 0x35 +underscore 0x35 shift +dead_belowdot 0x35 altgr diff --git a/keymaps/sv b/keymaps/sv new file mode 100644 index 000000000..736d637b3 --- /dev/null +++ b/keymaps/sv @@ -0,0 +1,82 @@ +map 0x0000041d +include common + +# +# Top row +# +section 0x29 +onehalf 0x29 shift + +# 1 +exclam 0x2 shift + +# 2 +quotedbl 0x3 shift +at 0x3 altgr + +# 3 +numbersign 0x4 shift +sterling 0x4 altgr +# 4 +currency 0x5 shift +dollar 0x5 altgr +# 5 +percent 0x6 shift +# 6 +ampersand 0x7 shift +# 7 +slash 0x8 shift +braceleft 0x8 altgr +# 8 +parenleft 0x9 shift +bracketleft 0x9 altgr +# 9 +parenright 0xa shift +bracketright 0xa altgr +# 0 +equal 0xb shift +braceright 0xb altgr + +plus 0xc +question 0xc shift +backslash 0xc altgr + +acute 0xd +dead_acute 0xd +grave 0xd shift +dead_grave 0xd shift + +# +# QWERTY first row +# +EuroSign 0x12 altgr +aring 0x1a +Aring 0x1a shift +dead_diaeresis 0x1b +dead_circumflex 0x1b shift +dead_tilde 0x1b altgr + +# +# QWERTY second row +# +odiaeresis 0x27 +Odiaeresis 0x27 shift +adiaeresis 0x28 +Adiaeresis 0x28 shift +apostrophe 0x2b +asterisk 0x2b shift + +# +# QWERTY third row +# +less 0x56 +greater 0x56 shift +bar 0x56 altgr +mu 0x32 altgr +comma 0x33 +semicolon 0x33 shift +period 0x34 +colon 0x34 shift +minus 0x35 +underscore 0x35 shift + diff --git a/keymaps/th b/keymaps/th new file mode 100644 index 000000000..b65b6da5d --- /dev/null +++ b/keymaps/th @@ -0,0 +1,131 @@ +# generated from XKB map th +include common +map 0x41e +exclam 0x02 shift +Thai_lakkhangyao 0x02 altgr +plus 0x02 shift altgr +at 0x03 shift +slash 0x03 altgr +Thai_leknung 0x03 shift altgr +numbersign 0x04 shift +minus 0x04 altgr +Thai_leksong 0x04 shift altgr +dollar 0x05 shift +Thai_phosamphao 0x05 altgr +Thai_leksam 0x05 shift altgr +percent 0x06 shift +Thai_thothung 0x06 altgr +Thai_leksi 0x06 shift altgr +asciicircum 0x07 shift +Thai_sarau 0x07 altgr +Thai_sarauu 0x07 shift altgr +ampersand 0x08 shift +Thai_saraue 0x08 altgr +Thai_baht 0x08 shift altgr +asterisk 0x09 shift +Thai_khokhwai 0x09 altgr +Thai_lekha 0x09 shift altgr +parenleft 0x0a shift +Thai_totao 0x0a altgr +Thai_lekhok 0x0a shift altgr +parenright 0x0b shift +Thai_chochan 0x0b altgr +Thai_lekchet 0x0b shift altgr +minus 0x0c +underscore 0x0c shift +Thai_khokhai 0x0c altgr +Thai_lekpaet 0x0c shift altgr +equal 0x0d +plus 0x0d shift +Thai_chochang 0x0d altgr +Thai_lekkao 0x0d shift altgr +Thai_maiyamok 0x10 altgr +Thai_leksun 0x10 shift altgr +Thai_saraaimaimalai 0x11 altgr +quotedbl 0x11 shift altgr +Thai_saraam 0x12 altgr +Thai_dochada 0x12 shift altgr +Thai_phophan 0x13 altgr +Thai_thonangmontho 0x13 shift altgr +Thai_saraa 0x14 altgr +Thai_thothong 0x14 shift altgr +Thai_maihanakat 0x15 altgr +Thai_nikhahit 0x15 shift altgr +Thai_saraii 0x16 altgr +Thai_maitri 0x16 shift altgr +Thai_rorua 0x17 altgr +Thai_nonen 0x17 shift altgr +Thai_nonu 0x18 altgr +Thai_paiyannoi 0x18 shift altgr +Thai_yoyak 0x19 altgr +Thai_yoying 0x19 shift altgr +bracketleft 0x1a +braceleft 0x1a shift +Thai_bobaimai 0x1a altgr +Thai_thothan 0x1a shift altgr +bracketright 0x1b +braceright 0x1b shift +Thai_loling 0x1b altgr +comma 0x1b shift altgr +Thai_fofan 0x1e altgr +Thai_ru 0x1e shift altgr +Thai_hohip 0x1f altgr +Thai_khorakhang 0x1f shift altgr +Thai_kokai 0x20 altgr +Thai_topatak 0x20 shift altgr +Thai_dodek 0x21 altgr +Thai_sarao 0x21 shift altgr +Thai_sarae 0x22 altgr +Thai_chochoe 0x22 shift altgr +Thai_maitho 0x23 altgr +Thai_maitaikhu 0x23 shift altgr +Thai_maiek 0x24 altgr +Thai_maichattawa 0x24 shift altgr +Thai_saraaa 0x25 altgr +Thai_sorusi 0x25 shift altgr +Thai_sosua 0x26 altgr +Thai_sosala 0x26 shift altgr +semicolon 0x27 +colon 0x27 shift +Thai_wowaen 0x27 altgr +Thai_soso 0x27 shift altgr +apostrophe 0x28 +quotedbl 0x28 shift +Thai_ngongu 0x28 altgr +period 0x28 shift altgr +grave 0x29 +asciitilde 0x29 shift +underscore 0x29 altgr +percent 0x29 shift altgr +ISO_First_Group 0x2a shift +backslash 0x2b +bar 0x2b shift +Thai_khokhuat 0x2b altgr +Thai_khokhon 0x2b shift altgr +Thai_phophung 0x2c altgr +parenleft 0x2c shift altgr +Thai_popla 0x2d altgr +parenright 0x2d shift altgr +Thai_saraae 0x2e altgr +Thai_choching 0x2e shift altgr +Thai_oang 0x2f altgr +Thai_honokhuk 0x2f shift altgr +Thai_sarai 0x30 altgr +Thai_phinthu 0x30 shift altgr +Thai_sarauee 0x31 altgr +Thai_thanthakhat 0x31 shift altgr +Thai_thothahan 0x32 altgr +question 0x32 shift altgr +comma 0x33 +less 0x33 shift +Thai_moma 0x33 altgr +Thai_thophuthao 0x33 shift altgr +period 0x34 +greater 0x34 shift +Thai_saraaimaimuan 0x34 altgr +Thai_lochula 0x34 shift altgr +slash 0x35 +question 0x35 shift +Thai_fofa 0x35 altgr +Thai_lu 0x35 shift altgr +ISO_Last_Group 0x36 shift diff --git a/keymaps/tr b/keymaps/tr new file mode 100644 index 000000000..5650e1e93 --- /dev/null +++ b/keymaps/tr @@ -0,0 +1,123 @@ +# generated from XKB map tr +include common +map 0x41f +exclam 0x02 shift +onesuperior 0x02 altgr +exclamdown 0x02 shift altgr +apostrophe 0x03 shift +at 0x03 altgr +oneeighth 0x03 shift altgr +dead_circumflex 0x04 shift +numbersign 0x04 altgr +sterling 0x04 shift altgr +plus 0x05 shift +dollar 0x05 altgr +percent 0x06 shift +onehalf 0x06 altgr +threeeighths 0x06 shift altgr +ampersand 0x07 shift +asciicircum 0x07 altgr +fiveeighths 0x07 shift altgr +slash 0x08 shift +braceleft 0x08 altgr +seveneighths 0x08 shift altgr +parenleft 0x09 shift +bracketleft 0x09 altgr +trademark 0x09 shift altgr +parenright 0x0a shift +bracketright 0x0a altgr +plusminus 0x0a shift altgr +equal 0x0b shift +braceright 0x0b altgr +degree 0x0b shift altgr +asterisk 0x0c +question 0x0c shift +backslash 0x0c altgr +questiondown 0x0c shift altgr +minus 0x0d +underscore 0x0d shift +dead_cedilla 0x0d altgr +dead_ogonek 0x0d shift altgr +at 0x10 altgr +Greek_OMEGA 0x10 shift altgr +lstroke 0x11 altgr +Lstroke 0x11 shift altgr +EuroSign 0x12 altgr +paragraph 0x13 altgr +registered 0x13 shift altgr +tslash 0x14 altgr +Tslash 0x14 shift altgr +leftarrow 0x15 altgr +yen 0x15 shift altgr +downarrow 0x16 altgr +uparrow 0x16 shift altgr +idotless 0x17 +I 0x17 shift +rightarrow 0x17 altgr +oslash 0x18 altgr +Ooblique 0x18 shift altgr +thorn 0x19 altgr +THORN 0x19 shift altgr +gbreve 0x1a +Gbreve 0x1a shift +dead_diaeresis 0x1a altgr +dead_abovering 0x1a shift altgr +udiaeresis 0x1b +Udiaeresis 0x1b shift +asciitilde 0x1b altgr +dead_macron 0x1b shift altgr +ae 0x1e altgr +AE 0x1e shift altgr +ssharp 0x1f altgr +section 0x1f shift altgr +eth 0x20 altgr +ETH 0x20 shift altgr +dstroke 0x21 altgr +ordfeminine 0x21 shift altgr +eng 0x22 altgr +ENG 0x22 shift altgr +hstroke 0x23 altgr +Hstroke 0x23 shift altgr +kra 0x25 altgr +ampersand 0x25 shift altgr +lstroke 0x26 altgr +Lstroke 0x26 shift altgr +scedilla 0x27 +Scedilla 0x27 shift +dead_acute 0x27 altgr +dead_doubleacute 0x27 shift altgr +i 0x28 +Iabovedot 0x28 shift +dead_circumflex 0x28 altgr +dead_caron 0x28 shift altgr +backslash 0x29 +quotedbl 0x29 shift +asciitilde 0x29 altgr +comma 0x2b +semicolon 0x2b shift +bar 0x2b altgr +dead_breve 0x2b shift altgr +guillemotleft 0x2c altgr +less 0x2c shift altgr +guillemotright 0x2d altgr +greater 0x2d shift altgr +cent 0x2e altgr +copyright 0x2e shift altgr +leftdoublequotemark 0x2f altgr +grave 0x2f shift altgr +rightdoublequotemark 0x30 altgr +apostrophe 0x30 shift altgr +mu 0x32 altgr +masculine 0x32 shift altgr +odiaeresis 0x33 +Odiaeresis 0x33 shift +less 0x33 altgr +multiply 0x33 shift altgr +ccedilla 0x34 +Ccedilla 0x34 shift +greater 0x34 altgr +division 0x34 shift altgr +period 0x35 +colon 0x35 shift +dead_belowdot 0x35 altgr +dead_abovedot 0x35 shift altgr diff --git a/qemu-doc.texi b/qemu-doc.texi index 6338062cd..e8e75a9ae 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -189,6 +189,22 @@ command line application. The emulated serial port is redirected on the console. Therefore, you can still use QEMU to debug a Linux kernel with a serial console. +@item -k language + +Use keyboard layout @var{language} (for example @code{fr} for +French). This option is only needed where it is not easy to get raw PC +keycodes (e.g. on Macs or with some X11 servers). You don't need to +use it on PC/Linux or PC/Windows hosts. + +The available layouts are: +@example +ar de-ch es fo fr-ca hu ja mk no pt-br sv +da en-gb et fr fr-ch is lt nl pl ru th +de en-us fi fr-be hr it lv nl-be pt sl tr +@end example + +The default is @code{en-us}. + @item -enable-audio The SB16 emulation is disabled by default as it may give problems with diff --git a/sdl.c b/sdl.c index 344dfae68..b061c8e59 100644 --- a/sdl.c +++ b/sdl.c @@ -29,10 +29,6 @@ #include #endif -#if defined(__APPLE__) -#define CONFIG_SDL_GENERIC_KBD -#endif - static SDL_Surface *screen; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static int last_vm_running; @@ -72,118 +68,26 @@ static void sdl_resize(DisplayState *ds, int w, int h) ds->height = h; } -#ifdef CONFIG_SDL_GENERIC_KBD - -/* XXX: use keymap tables defined in the VNC patch because the - following code suppose you have a US keyboard. */ - -static const uint8_t scancodes[SDLK_LAST] = { - [SDLK_ESCAPE] = 0x01, - [SDLK_1] = 0x02, - [SDLK_2] = 0x03, - [SDLK_3] = 0x04, - [SDLK_4] = 0x05, - [SDLK_5] = 0x06, - [SDLK_6] = 0x07, - [SDLK_7] = 0x08, - [SDLK_8] = 0x09, - [SDLK_9] = 0x0a, - [SDLK_0] = 0x0b, - [SDLK_MINUS] = 0x0c, - [SDLK_EQUALS] = 0x0d, - [SDLK_BACKSPACE] = 0x0e, - [SDLK_TAB] = 0x0f, - [SDLK_q] = 0x10, - [SDLK_w] = 0x11, - [SDLK_e] = 0x12, - [SDLK_r] = 0x13, - [SDLK_t] = 0x14, - [SDLK_y] = 0x15, - [SDLK_u] = 0x16, - [SDLK_i] = 0x17, - [SDLK_o] = 0x18, - [SDLK_p] = 0x19, - [SDLK_LEFTBRACKET] = 0x1a, - [SDLK_RIGHTBRACKET] = 0x1b, - [SDLK_RETURN] = 0x1c, - [SDLK_LCTRL] = 0x1d, - [SDLK_a] = 0x1e, - [SDLK_s] = 0x1f, - [SDLK_d] = 0x20, - [SDLK_f] = 0x21, - [SDLK_g] = 0x22, - [SDLK_h] = 0x23, - [SDLK_j] = 0x24, - [SDLK_k] = 0x25, - [SDLK_l] = 0x26, - [SDLK_SEMICOLON] = 0x27, - [SDLK_QUOTE] = 0x28, - [SDLK_BACKQUOTE] = 0x29, - [SDLK_LSHIFT] = 0x2a, - [SDLK_BACKSLASH] = 0x2b, - [SDLK_z] = 0x2c, - [SDLK_x] = 0x2d, - [SDLK_c] = 0x2e, - [SDLK_v] = 0x2f, - [SDLK_b] = 0x30, - [SDLK_n] = 0x31, - [SDLK_m] = 0x32, - [SDLK_COMMA] = 0x33, - [SDLK_PERIOD] = 0x34, - [SDLK_SLASH] = 0x35, - [SDLK_KP_MULTIPLY] = 0x37, - [SDLK_LALT] = 0x38, - [SDLK_SPACE] = 0x39, - [SDLK_CAPSLOCK] = 0x3a, - [SDLK_F1] = 0x3b, - [SDLK_F2] = 0x3c, - [SDLK_F3] = 0x3d, - [SDLK_F4] = 0x3e, - [SDLK_F5] = 0x3f, - [SDLK_F6] = 0x40, - [SDLK_F7] = 0x41, - [SDLK_F8] = 0x42, - [SDLK_F9] = 0x43, - [SDLK_F10] = 0x44, - [SDLK_NUMLOCK] = 0x45, - [SDLK_SCROLLOCK] = 0x46, - [SDLK_KP7] = 0x47, - [SDLK_KP8] = 0x48, - [SDLK_KP9] = 0x49, - [SDLK_KP_MINUS] = 0x4a, - [SDLK_KP4] = 0x4b, - [SDLK_KP5] = 0x4c, - [SDLK_KP6] = 0x4d, - [SDLK_KP_PLUS] = 0x4e, - [SDLK_KP1] = 0x4f, - [SDLK_KP2] = 0x50, - [SDLK_KP3] = 0x51, - [SDLK_KP0] = 0x52, - [SDLK_KP_PERIOD] = 0x53, - [SDLK_PRINT] = 0x54, - [SDLK_LMETA] = 0x56, - - [SDLK_KP_ENTER] = 0x9c, - [SDLK_KP_DIVIDE] = 0xb5, - - [SDLK_UP] = 0xc8, - [SDLK_DOWN] = 0xd0, - [SDLK_RIGHT] = 0xcd, - [SDLK_LEFT] = 0xcb, - [SDLK_INSERT] = 0xd2, - [SDLK_HOME] = 0xc7, - [SDLK_END] = 0xcf, - [SDLK_PAGEUP] = 0xc9, - [SDLK_PAGEDOWN] = 0xd1, - [SDLK_DELETE] = 0xd3, -}; +/* generic keyboard conversion */ -static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) +#include "sdl_keysym.h" +#include "keymaps.c" + +static kbd_layout_t *kbd_layout = NULL; + +static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev) { - return scancodes[ev->keysym.sym]; + int keysym; + /* workaround for X11+SDL bug with AltGR */ + keysym = ev->keysym.sym; + if (keysym == 0 && ev->keysym.scancode == 113) + keysym = SDLK_MODE; + return keysym2scancode(kbd_layout, keysym); } -#elif defined(_WIN32) +/* specific keyboard conversions from scan codes */ + +#if defined(_WIN32) static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) { @@ -305,8 +209,11 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) return; } - /* XXX: not portable, but avoids complicated mappings */ - keycode = sdl_keyevent_to_keycode(ev); + if (kbd_layout) { + keycode = sdl_keyevent_to_keycode_generic(ev); + } else { + keycode = sdl_keyevent_to_keycode(ev); + } switch(keycode) { case 0x00: @@ -558,6 +465,17 @@ void sdl_display_init(DisplayState *ds, int full_screen) { int flags; +#if defined(__APPLE__) + /* always use generic keymaps */ + if (!keyboard_layout) + keyboard_layout = "en-us"; +#endif + if(keyboard_layout) { + kbd_layout = init_keyboard_layout(keyboard_layout); + if (!kbd_layout) + exit(1); + } + flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; if (SDL_Init (flags)) { fprintf(stderr, "Could not initialize SDL - exiting\n"); diff --git a/sdl_keysym.h b/sdl_keysym.h new file mode 100644 index 000000000..07969bcb4 --- /dev/null +++ b/sdl_keysym.h @@ -0,0 +1,275 @@ +typedef struct { + const char* name; + int keysym; +} name2keysym_t; +static name2keysym_t name2keysym[]={ +/* ascii */ + { "space", 0x020}, + { "exclam", 0x021}, + { "quotedbl", 0x022}, + { "numbersign", 0x023}, + { "dollar", 0x024}, + { "percent", 0x025}, + { "ampersand", 0x026}, + { "apostrophe", 0x027}, + { "parenleft", 0x028}, + { "parenright", 0x029}, + { "asterisk", 0x02a}, + { "plus", 0x02b}, + { "comma", 0x02c}, + { "minus", 0x02d}, + { "period", 0x02e}, + { "slash", 0x02f}, + { "0", 0x030}, + { "1", 0x031}, + { "2", 0x032}, + { "3", 0x033}, + { "4", 0x034}, + { "5", 0x035}, + { "6", 0x036}, + { "7", 0x037}, + { "8", 0x038}, + { "9", 0x039}, + { "colon", 0x03a}, + { "semicolon", 0x03b}, + { "less", 0x03c}, + { "equal", 0x03d}, + { "greater", 0x03e}, + { "question", 0x03f}, + { "at", 0x040}, + { "A", 0x041}, + { "B", 0x042}, + { "C", 0x043}, + { "D", 0x044}, + { "E", 0x045}, + { "F", 0x046}, + { "G", 0x047}, + { "H", 0x048}, + { "I", 0x049}, + { "J", 0x04a}, + { "K", 0x04b}, + { "L", 0x04c}, + { "M", 0x04d}, + { "N", 0x04e}, + { "O", 0x04f}, + { "P", 0x050}, + { "Q", 0x051}, + { "R", 0x052}, + { "S", 0x053}, + { "T", 0x054}, + { "U", 0x055}, + { "V", 0x056}, + { "W", 0x057}, + { "X", 0x058}, + { "Y", 0x059}, + { "Z", 0x05a}, + { "bracketleft", 0x05b}, + { "backslash", 0x05c}, + { "bracketright", 0x05d}, + { "asciicircum", 0x05e}, + { "underscore", 0x05f}, + { "grave", 0x060}, + { "a", 0x061}, + { "b", 0x062}, + { "c", 0x063}, + { "d", 0x064}, + { "e", 0x065}, + { "f", 0x066}, + { "g", 0x067}, + { "h", 0x068}, + { "i", 0x069}, + { "j", 0x06a}, + { "k", 0x06b}, + { "l", 0x06c}, + { "m", 0x06d}, + { "n", 0x06e}, + { "o", 0x06f}, + { "p", 0x070}, + { "q", 0x071}, + { "r", 0x072}, + { "s", 0x073}, + { "t", 0x074}, + { "u", 0x075}, + { "v", 0x076}, + { "w", 0x077}, + { "x", 0x078}, + { "y", 0x079}, + { "z", 0x07a}, + { "braceleft", 0x07b}, + { "bar", 0x07c}, + { "braceright", 0x07d}, + { "asciitilde", 0x07e}, + +/* latin 1 extensions */ +{ "nobreakspace", 0x0a0}, +{ "exclamdown", 0x0a1}, +{ "cent", 0x0a2}, +{ "sterling", 0x0a3}, +{ "currency", 0x0a4}, +{ "yen", 0x0a5}, +{ "brokenbar", 0x0a6}, +{ "section", 0x0a7}, +{ "diaeresis", 0x0a8}, +{ "copyright", 0x0a9}, +{ "ordfeminine", 0x0aa}, +{ "guillemotleft", 0x0ab}, +{ "notsign", 0x0ac}, +{ "hyphen", 0x0ad}, +{ "registered", 0x0ae}, +{ "macron", 0x0af}, +{ "degree", 0x0b0}, +{ "plusminus", 0x0b1}, +{ "twosuperior", 0x0b2}, +{ "threesuperior", 0x0b3}, +{ "acute", 0x0b4}, +{ "mu", 0x0b5}, +{ "paragraph", 0x0b6}, +{ "periodcentered", 0x0b7}, +{ "cedilla", 0x0b8}, +{ "onesuperior", 0x0b9}, +{ "masculine", 0x0ba}, +{ "guillemotright", 0x0bb}, +{ "onequarter", 0x0bc}, +{ "onehalf", 0x0bd}, +{ "threequarters", 0x0be}, +{ "questiondown", 0x0bf}, +{ "Agrave", 0x0c0}, +{ "Aacute", 0x0c1}, +{ "Acircumflex", 0x0c2}, +{ "Atilde", 0x0c3}, +{ "Adiaeresis", 0x0c4}, +{ "Aring", 0x0c5}, +{ "AE", 0x0c6}, +{ "Ccedilla", 0x0c7}, +{ "Egrave", 0x0c8}, +{ "Eacute", 0x0c9}, +{ "Ecircumflex", 0x0ca}, +{ "Ediaeresis", 0x0cb}, +{ "Igrave", 0x0cc}, +{ "Iacute", 0x0cd}, +{ "Icircumflex", 0x0ce}, +{ "Idiaeresis", 0x0cf}, +{ "ETH", 0x0d0}, +{ "Eth", 0x0d0}, +{ "Ntilde", 0x0d1}, +{ "Ograve", 0x0d2}, +{ "Oacute", 0x0d3}, +{ "Ocircumflex", 0x0d4}, +{ "Otilde", 0x0d5}, +{ "Odiaeresis", 0x0d6}, +{ "multiply", 0x0d7}, +{ "Ooblique", 0x0d8}, +{ "Oslash", 0x0d8}, +{ "Ugrave", 0x0d9}, +{ "Uacute", 0x0da}, +{ "Ucircumflex", 0x0db}, +{ "Udiaeresis", 0x0dc}, +{ "Yacute", 0x0dd}, +{ "THORN", 0x0de}, +{ "Thorn", 0x0de}, +{ "ssharp", 0x0df}, +{ "agrave", 0x0e0}, +{ "aacute", 0x0e1}, +{ "acircumflex", 0x0e2}, +{ "atilde", 0x0e3}, +{ "adiaeresis", 0x0e4}, +{ "aring", 0x0e5}, +{ "ae", 0x0e6}, +{ "ccedilla", 0x0e7}, +{ "egrave", 0x0e8}, +{ "eacute", 0x0e9}, +{ "ecircumflex", 0x0ea}, +{ "ediaeresis", 0x0eb}, +{ "igrave", 0x0ec}, +{ "iacute", 0x0ed}, +{ "icircumflex", 0x0ee}, +{ "idiaeresis", 0x0ef}, +{ "eth", 0x0f0}, +{ "ntilde", 0x0f1}, +{ "ograve", 0x0f2}, +{ "oacute", 0x0f3}, +{ "ocircumflex", 0x0f4}, +{ "otilde", 0x0f5}, +{ "odiaeresis", 0x0f6}, +{ "division", 0x0f7}, +{ "oslash", 0x0f8}, +{ "ooblique", 0x0f8}, +{ "ugrave", 0x0f9}, +{ "uacute", 0x0fa}, +{ "ucircumflex", 0x0fb}, +{ "udiaeresis", 0x0fc}, +{ "yacute", 0x0fd}, +{ "thorn", 0x0fe}, +{ "ydiaeresis", 0x0ff}, +{"EuroSign", SDLK_EURO}, + + /* modifiers */ +{"Control_L", SDLK_LCTRL}, +{"Control_R", SDLK_RCTRL}, +{"Alt_L", SDLK_LALT}, +{"Alt_R", SDLK_RALT}, +{"Caps_Lock", SDLK_CAPSLOCK}, +{"Meta_L", SDLK_LMETA}, +{"Meta_R", SDLK_RMETA}, +{"Shift_L", SDLK_LSHIFT}, +{"Shift_R", SDLK_RSHIFT}, + + /* special keys */ +{"BackSpace", SDLK_BACKSPACE}, +{"Tab", SDLK_TAB}, +{"Return", SDLK_RETURN}, +{"Right", SDLK_RIGHT}, +{"Left", SDLK_LEFT}, +{"Up", SDLK_UP}, +{"Down", SDLK_DOWN}, +{"Page_Down", SDLK_PAGEDOWN}, +{"Page_Up", SDLK_PAGEUP}, +{"Insert", SDLK_INSERT}, +{"Delete", SDLK_DELETE}, +{"Home", SDLK_HOME}, +{"End", SDLK_END}, +{"Scroll_Lock", SDLK_SCROLLOCK}, +{"F1", SDLK_F1}, +{"F2", SDLK_F2}, +{"F3", SDLK_F3}, +{"F4", SDLK_F4}, +{"F5", SDLK_F5}, +{"F6", SDLK_F6}, +{"F7", SDLK_F7}, +{"F8", SDLK_F8}, +{"F9", SDLK_F9}, +{"F10", SDLK_F10}, +{"F11", SDLK_F11}, +{"F12", SDLK_F12}, +{"F13", SDLK_F13}, +{"F14", SDLK_F14}, +{"F15", SDLK_F15}, +{"Sys_Req", SDLK_SYSREQ}, +{"KP_0", SDLK_KP0}, +{"KP_1", SDLK_KP1}, +{"KP_2", SDLK_KP2}, +{"KP_3", SDLK_KP3}, +{"KP_4", SDLK_KP4}, +{"KP_5", SDLK_KP5}, +{"KP_6", SDLK_KP6}, +{"KP_7", SDLK_KP7}, +{"KP_8", SDLK_KP8}, +{"KP_9", SDLK_KP9}, +{"KP_Add", SDLK_KP_PLUS}, +{"KP_Decimal", SDLK_KP_PERIOD}, +{"KP_Divide", SDLK_KP_DIVIDE}, +{"KP_Enter", SDLK_KP_ENTER}, +{"KP_Equal", SDLK_KP_EQUALS}, +{"KP_Multiply", SDLK_KP_MULTIPLY}, +{"KP_Subtract", SDLK_KP_MINUS}, +{"help", SDLK_HELP}, +{"Menu", SDLK_MENU}, +{"Power", SDLK_POWER}, +{"Print", SDLK_PRINT}, +{"Mode_switch", SDLK_MODE}, +{"Multi_Key", SDLK_COMPOSE}, +{"Num_Lock", SDLK_NUMLOCK}, +{"Pause", SDLK_PAUSE}, + +{0,0}, +}; diff --git a/vl.c b/vl.c index 31d3a2052..a4da63fc9 100644 --- a/vl.c +++ b/vl.c @@ -112,6 +112,7 @@ int vga_ram_size; int bios_size; static DisplayState display_state; int nographic; +const char* keyboard_layout = NULL; int64_t ticks_per_sec; int boot_device = 'c'; int ram_size; @@ -2541,6 +2542,7 @@ void help(void) "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB [default=%d]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" + "-k language use keyboard layout (for example \"fr\" for French)\n" "-enable-audio enable audio support\n" "-localtime set the real time clock to local time [default=utc]\n" "-full-screen start in full screen\n" @@ -2658,6 +2660,7 @@ enum { QEMU_OPTION_pci, QEMU_OPTION_isa, QEMU_OPTION_prep, + QEMU_OPTION_k, QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, QEMU_OPTION_g, @@ -2689,6 +2692,7 @@ const QEMUOption qemu_options[] = { { "snapshot", 0, QEMU_OPTION_snapshot }, { "m", HAS_ARG, QEMU_OPTION_m }, { "nographic", 0, QEMU_OPTION_nographic }, + { "k", HAS_ARG, QEMU_OPTION_k }, { "enable-audio", 0, QEMU_OPTION_enable_audio }, { "nics", HAS_ARG, QEMU_OPTION_nics}, @@ -3092,6 +3096,9 @@ int main(int argc, char **argv) case QEMU_OPTION_prep: prep_enabled = 1; break; + case QEMU_OPTION_k: + keyboard_layout = optarg; + break; case QEMU_OPTION_localtime: rtc_utc = 0; break; diff --git a/vl.h b/vl.h index 119769b5b..3f3acf2ae 100644 --- a/vl.h +++ b/vl.h @@ -123,6 +123,7 @@ extern int cirrus_vga_enabled; extern int graphic_width; extern int graphic_height; extern int graphic_depth; +extern const char *keyboard_layout; /* XXX: make it dynamic */ #if defined (TARGET_PPC) -- cgit v1.2.3 From fed4a9adc0a2ef5ca5033797f1e5f3137b48a687 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 12 Dec 2004 22:18:34 +0000 Subject: keymap install fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1174 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eb353ba9a..c431acd18 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,10 @@ distclean: clean 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: all mkdir -p "$(bindir)" install -m 755 -s $(TOOLS) "$(bindir)" @@ -57,7 +61,7 @@ ifndef CONFIG_WIN32 mkdir -p "$(mandir)/man1" install qemu.1 qemu-img.1 "$(mandir)/man1" mkdir -p "$(datadir)/keymaps" - install -m 644 keymaps/* "$(datadir)" + install -m 644 $(addprefix keymaps/,$(KEYMAPS)) "$(datadir)/keymaps" endif for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ -- cgit v1.2.3 From 4ca0074c8c99a5bd89d326e1f76dcd518447e80b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 12 Dec 2004 22:20:04 +0000 Subject: no need to use -k for Windows git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1175 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vl.c b/vl.c index a4da63fc9..78f968eb1 100644 --- a/vl.c +++ b/vl.c @@ -2542,7 +2542,9 @@ void help(void) "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB [default=%d]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" +#ifndef _WIN32 "-k language use keyboard layout (for example \"fr\" for French)\n" +#endif "-enable-audio enable audio support\n" "-localtime set the real time clock to local time [default=utc]\n" "-full-screen start in full screen\n" -- cgit v1.2.3 From bc7712a4acd046561aa3a8699640c8d1ff7c8946 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 13 Dec 2004 19:38:08 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1176 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index e8e75a9ae..367beb80a 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -52,8 +52,8 @@ If you want to compile QEMU yourself, see @ref{compilation}. @section Linux -Download the binary distribution (@file{qemu-XXX-i386.tar.gz}) and -untar it as root in @file{/}: +Download the binary distribution (@file{qemu-XXX-i386.tar.gz}) in +@file{/tmp} and untar it as root from @file{/}: @example su -- cgit v1.2.3 From de06c511ff3dc672f5f4e7884683893a92712c99 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 19 Dec 2004 20:57:26 +0000 Subject: win32 qcow fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1177 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 --- a.out.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Makefile b/Makefile index c431acd18..3659819fb 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,6 @@ CFLAGS=-Wall -O2 -g -fno-strict-aliasing ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic endif -ifdef CONFIG_WIN32 -CFLAGS+=-fpack-struct -endif LDFLAGS=-g LIBS= DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE diff --git a/a.out.h b/a.out.h index 500e14f3f..1f978c1c0 100644 --- a/a.out.h +++ b/a.out.h @@ -151,7 +151,7 @@ struct external_lineno { #define E_FILNMLEN 14 /* # characters in a file name */ #define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ -struct external_syment +struct __attribute__((packed)) external_syment { union { char e_name[E_SYMNMLEN]; -- cgit v1.2.3 From 9772c73bbc9f24a66bf060e16c0625a258b1bb41 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 19 Dec 2004 23:03:29 +0000 Subject: fixed ins in case of page fault git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1178 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 1e9bea572..eba99052a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -874,8 +874,10 @@ static inline void gen_cmps(DisasContext *s, int ot) static inline void gen_ins(DisasContext *s, int ot) { - gen_op_in_DX_T0[ot](); gen_string_movl_A0_EDI(s); + gen_op_movl_T0_0(); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_in_DX_T0[ot](); gen_op_st_T0_A0[ot + s->mem_index](); gen_op_movl_T0_Dshift[ot](); if (s->aflag) { -- cgit v1.2.3 From e80cfcfc8884400e826328b772971913a14d0f44 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 19 Dec 2004 23:18:01 +0000 Subject: SPARC merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1179 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 +- Makefile.target | 3 +- cpu-exec.c | 2 +- disas.c | 34 +- disas.h | 10 +- gdbstub.c | 19 +- hw/fdc.c | 35 +- hw/iommu.c | 54 +- hw/lance.c | 127 +-- hw/m48t08.c | 161 ++-- hw/m48t08.h | 8 +- hw/magic-load.c | 179 ++-- hw/sched.c | 268 ------ hw/slavio_intctl.c | 299 +++++++ hw/slavio_serial.c | 364 ++++++++ hw/slavio_timer.c | 289 ++++++ hw/sun4m.c | 163 +++- hw/tcx.c | 297 +++--- hw/timer.c | 97 -- linux-user/elfload.c | 16 +- linux-user/main.c | 2 + linux-user/signal.c | 79 +- pc-bios/proll.bin | Bin 56856 -> 0 bytes pc-bios/proll.elf | Bin 0 -> 133338 bytes pc-bios/proll.patch | 2088 ++++++++++++++++++++++++++++++++++++++++++- qemu-doc.texi | 23 + qemu-tech.texi | 5 +- target-sparc/cpu.h | 28 +- target-sparc/exec.h | 3 + target-sparc/fop_template.h | 12 - target-sparc/helper.c | 255 ++++-- target-sparc/op.c | 29 +- target-sparc/op_helper.c | 176 +++- target-sparc/op_mem.h | 4 - target-sparc/translate.c | 396 +++++--- vl.c | 66 +- vl.h | 33 +- 37 files changed, 4490 insertions(+), 1138 deletions(-) delete mode 100644 hw/sched.c create mode 100644 hw/slavio_intctl.c create mode 100644 hw/slavio_serial.c create mode 100644 hw/slavio_timer.c delete mode 100644 hw/timer.c delete mode 100644 pc-bios/proll.bin create mode 100644 pc-bios/proll.elf diff --git a/Makefile b/Makefile index 3659819fb..3cf7e504c 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ install: all install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/vgabios-cirrus.bin \ pc-bios/ppc_rom.bin \ - pc-bios/proll.bin \ + pc-bios/proll.elf \ pc-bios/linux_boot.bin "$(datadir)" mkdir -p "$(docdir)" install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" @@ -107,7 +107,7 @@ tarbin: $(datadir)/vgabios.bin \ $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ - $(datadir)/proll.bin \ + $(datadir)/proll.elf \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff --git a/Makefile.target b/Makefile.target index a5c697ddc..edf76cffb 100644 --- a/Makefile.target +++ b/Makefile.target @@ -175,6 +175,7 @@ endif ifeq ($(CONFIG_DARWIN),yes) OP_CFLAGS+= -mdynamic-no-pic +LIBS+=-lmx endif ######################################################### @@ -300,7 +301,7 @@ 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 mixeng.o endif ifeq ($(TARGET_ARCH), sparc) -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/cpu-exec.c b/cpu-exec.c index b98c22c58..cc6324ca1 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -261,7 +261,7 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_SPARC) if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(0, 0, 0, 0, 0); + do_interrupt(env->interrupt_index, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_HARD; } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); diff --git a/disas.c b/disas.c index 86f29d245..bfab8c3bb 100644 --- a/disas.c +++ b/disas.c @@ -9,9 +9,7 @@ #include "disas.h" /* Filled in by elfload.c. Simplistic, but will do for now. */ -unsigned int disas_num_syms; -void *disas_symtab; -const char *disas_strtab; +struct syminfo *syminfos = NULL; /* Get LENGTH bytes from info's buffer, at target address memaddr. Transfer them to myaddr. */ @@ -203,19 +201,23 @@ const char *lookup_symbol(void *orig_addr) { unsigned int i; /* Hack, because we know this is x86. */ - Elf32_Sym *sym = disas_symtab; - - for (i = 0; i < disas_num_syms; i++) { - if (sym[i].st_shndx == SHN_UNDEF - || sym[i].st_shndx >= SHN_LORESERVE) - continue; - - if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) - continue; - - if ((long)orig_addr >= sym[i].st_value - && (long)orig_addr < sym[i].st_value + sym[i].st_size) - return disas_strtab + sym[i].st_name; + Elf32_Sym *sym; + struct syminfo *s; + + for (s = syminfos; s; s = s->next) { + sym = s->disas_symtab; + for (i = 0; i < s->disas_num_syms; i++) { + if (sym[i].st_shndx == SHN_UNDEF + || sym[i].st_shndx >= SHN_LORESERVE) + continue; + + if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) + continue; + + if ((long)orig_addr >= sym[i].st_value + && (long)orig_addr < sym[i].st_value + sym[i].st_size) + return s->disas_strtab + sym[i].st_name; + } } return ""; } diff --git a/disas.h b/disas.h index c4a251ff8..5d383faab 100644 --- a/disas.h +++ b/disas.h @@ -9,7 +9,11 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags); const char *lookup_symbol(void *orig_addr); /* Filled in by elfload.c. Simplistic, but will do for now. */ -extern unsigned int disas_num_syms; -extern void *disas_symtab; /* FIXME: includes are a mess --RR */ -extern const char *disas_strtab; +extern struct syminfo { + unsigned int disas_num_syms; + void *disas_symtab; + const char *disas_strtab; + struct syminfo *next; +} *syminfos; + #endif /* _QEMU_DISAS_H */ diff --git a/gdbstub.c b/gdbstub.c index 2491c2cd7..e2c8b2dfa 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -298,11 +298,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ registers[64] = tswapl(env->y); - tmp = (0<<28) | (4<<24) | env->psr \ - | (env->psrs? PSR_S : 0) \ - | (env->psrs? PSR_PS : 0) \ - | (env->psret? PSR_ET : 0) \ - | env->cwp; + tmp = GET_PSR(env); registers[65] = tswapl(tmp); registers[66] = tswapl(env->wim); registers[67] = tswapl(env->tbr); @@ -317,7 +313,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { - uint32_t *registers = (uint32_t *)mem_buf, tmp; + uint32_t *registers = (uint32_t *)mem_buf; int i; /* fill in g0..g7 */ @@ -334,12 +330,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ env->y = tswapl(registers[64]); - tmp = tswapl(registers[65]); - env->psr = tmp & ~PSR_ICC; - env->psrs = (tmp & PSR_S)? 1 : 0; - env->psrps = (tmp & PSR_PS)? 1 : 0; - env->psret = (tmp & PSR_ET)? 1 : 0; - env->cwp = (tmp & PSR_CWP); + PUT_PSR(env, tswapl(registers[65])); env->wim = tswapl(registers[66]); env->tbr = tswapl(registers[67]); env->pc = tswapl(registers[68]); @@ -495,8 +486,10 @@ static void gdb_vm_stopped(void *opaque, int reason) /* disable single step if it was enable */ cpu_single_step(cpu_single_env, 0); - if (reason == EXCP_DEBUG) + if (reason == EXCP_DEBUG) { + tb_flush(cpu_single_env); ret = SIGTRAP; + } else ret = 0; snprintf(buf, sizeof(buf), "S%02x", ret); diff --git a/hw/fdc.c b/hw/fdc.c index d512b1ca9..ee0732848 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -21,6 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +/* + * The controller is used in Sun4m systems in a slightly different + * way. There are changes in DOR register and DMA is not available. + */ #include "vl.h" /********************************************************/ @@ -90,6 +94,16 @@ typedef struct fdrive_t { uint8_t ro; /* Is read-only */ } fdrive_t; +#ifdef TARGET_SPARC +#define DMA_read_memory(a,b,c,d) +#define DMA_write_memory(a,b,c,d) +#define DMA_register_channel(a,b,c) +#define DMA_hold_DREQ(a) +#define DMA_release_DREQ(a) +#define DMA_get_channel_mode(a) (0) +#define DMA_schedule(a) +#endif + static void fd_init (fdrive_t *drv, BlockDriverState *bs) { /* Drive */ @@ -455,6 +469,18 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) } } +static CPUReadMemoryFunc *fdctrl_mem_read[3] = { + fdctrl_read, + fdctrl_read, + fdctrl_read, +}; + +static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { + fdctrl_write, + fdctrl_write, + fdctrl_write, +}; + static void fd_change_cb (void *opaque) { fdrive_t *drv = opaque; @@ -473,7 +499,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, BlockDriverState **fds) { fdctrl_t *fdctrl; -// int io_mem; + int io_mem; int i; FLOPPY_DPRINTF("init controller\n"); @@ -504,11 +530,8 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl_reset(fdctrl, 0); fdctrl->state = FD_CTRL_ACTIVE; if (mem_mapped) { - FLOPPY_ERROR("memory mapped floppy not supported by now !\n"); -#if 0 - io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write); - cpu_register_physical_memory(base, 0x08, io_mem); -#endif + io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl); + cpu_register_physical_memory(io_base, 0x08, io_mem); } else { register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl); register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl); diff --git a/hw/iommu.c b/hw/iommu.c index a9249c4ba..62927acd5 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -117,8 +117,6 @@ typedef struct IOMMUState { uint32_t iostart; } IOMMUState; -static IOMMUState *ps; - static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) { IOMMUState *s = opaque; @@ -187,25 +185,61 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { iommu_mem_writew, }; -uint32_t iommu_translate(uint32_t addr) +uint32_t iommu_translate_local(void *opaque, uint32_t addr) { - uint32_t *iopte = (void *)(ps->regs[1] << 4), pa; + IOMMUState *s = opaque; + uint32_t *iopte = (void *)(s->regs[1] << 4), pa; - iopte += ((addr - ps->iostart) >> PAGE_SHIFT); - cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0); + iopte += ((addr - s->iostart) >> PAGE_SHIFT); + cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4); bswap32s(&pa); pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */ return pa + (addr & PAGE_MASK); } -void iommu_init(uint32_t addr) +static void iommu_save(QEMUFile *f, void *opaque) +{ + IOMMUState *s = opaque; + int i; + + qemu_put_be32s(f, &s->addr); + for (i = 0; i < sizeof(struct iommu_regs); i += 4) + qemu_put_be32s(f, &s->regs[i]); + qemu_put_be32s(f, &s->iostart); +} + +static int iommu_load(QEMUFile *f, void *opaque, int version_id) +{ + IOMMUState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->addr); + for (i = 0; i < sizeof(struct iommu_regs); i += 4) + qemu_put_be32s(f, &s->regs[i]); + qemu_get_be32s(f, &s->iostart); + + return 0; +} + +static void iommu_reset(void *opaque) +{ + IOMMUState *s = opaque; + + memset(s->regs, 0, sizeof(struct iommu_regs)); + s->iostart = 0; +} + +void *iommu_init(uint32_t addr) { IOMMUState *s; int iommu_io_memory; s = qemu_mallocz(sizeof(IOMMUState)); if (!s) - return; + return NULL; s->addr = addr; @@ -213,6 +247,8 @@ void iommu_init(uint32_t addr) cpu_register_physical_memory(addr, sizeof(struct iommu_regs), iommu_io_memory); - ps = s; + register_savevm("iommu", addr, 1, iommu_save, iommu_load, s); + qemu_register_reset(iommu_reset, s); + return s; } diff --git a/hw/lance.c b/hw/lance.c index 25ad8c45b..c594c52e8 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -147,6 +147,7 @@ struct lance_init_block { }; #define LEDMA_REGS 4 +#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) #if 0 /* Structure to describe the current status of DMA registers on the Sparc */ struct sparc_dma_registers { @@ -157,32 +158,28 @@ struct sparc_dma_registers { }; #endif -typedef struct LEDMAState { - uint32_t addr; - uint32_t regs[LEDMA_REGS]; -} LEDMAState; - typedef struct LANCEState { - uint32_t paddr; NetDriverState *nd; uint32_t leptr; uint16_t addr; uint16_t regs[LE_MAXREG]; uint8_t phys[6]; /* mac address */ int irq; - LEDMAState *ledma; + unsigned int rxptr, txptr; + uint32_t ledmaregs[LEDMA_REGS]; } LANCEState; -static unsigned int rxptr, txptr; - static void lance_send(void *opaque); -static void lance_reset(LANCEState *s) +static void lance_reset(void *opaque) { + LANCEState *s = opaque; memcpy(s->phys, s->nd->macaddr, 6); - rxptr = 0; - txptr = 0; + s->rxptr = 0; + s->txptr = 0; + memset(s->regs, 0, LE_MAXREG * 2); s->regs[LE_CSR0] = LE_C0_STOP; + memset(s->ledmaregs, 0, LEDMA_REGS * 4); } static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) @@ -190,7 +187,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) LANCEState *s = opaque; uint32_t saddr; - saddr = addr - s->paddr; + saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: return s->regs[s->addr]; @@ -208,7 +205,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val uint32_t saddr; uint16_t reg; - saddr = addr - s->paddr; + saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: switch(s->addr) { @@ -292,7 +289,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { static int lance_can_receive(void *opaque) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; int i; uint16_t temp; @@ -303,7 +300,7 @@ static int lance_can_receive(void *opaque) ib = (void *) iommu_translate(dmaptr); for (i = 0; i < RX_RING_SIZE; i++) { - cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); temp &= 0xff; if (temp == (LE_R1_OWN)) { #ifdef DEBUG_LANCE @@ -323,7 +320,7 @@ static int lance_can_receive(void *opaque) static void lance_receive(void *opaque, const uint8_t *buf, int size) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; unsigned int i, old_rxptr, j; uint16_t temp; @@ -333,23 +330,23 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) ib = (void *) iommu_translate(dmaptr); - old_rxptr = rxptr; - for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { - cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + old_rxptr = s->rxptr; + for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); if (temp == (LE_R1_OWN)) { - rxptr = (rxptr + 1) & RX_RING_MOD_MASK; + s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; temp = size; bswap16s(&temp); - cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2); + cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp, 2); #if 0 - cpu_physical_memory_write(&ib->rx_buf[i], buf, size); + cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size); #else for (j = 0; j < size; j++) { - cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1); + cpu_physical_memory_write(((uint32_t)&ib->rx_buf[i]) + j, &buf[j], 1); } #endif temp = LE_R1_POK; - cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) pic_set_irq(s->irq, 1); @@ -364,7 +361,7 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) static void lance_send(void *opaque) { LANCEState *s = opaque; - void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]); + uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; unsigned int i, old_txptr, j; uint16_t temp; @@ -375,18 +372,18 @@ static void lance_send(void *opaque) ib = (void *) iommu_translate(dmaptr); - old_txptr = txptr; - for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { - cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + old_txptr = s->txptr; + for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); if (temp == (LE_T1_POK|LE_T1_OWN)) { - cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2); + cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp, 2); bswap16s(&temp); temp = (~temp) + 1; #if 0 - cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp); + cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp); #else for (j = 0; j < temp; j++) { - cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1); + cpu_physical_memory_read((uint32_t)&ib->tx_buf[i] + j, &pkt_buf[j], 1); } #endif @@ -395,8 +392,8 @@ static void lance_send(void *opaque) #endif qemu_send_packet(s->nd, pkt_buf, temp); temp = LE_T1_POK; - cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); - txptr = (txptr + 1) & TX_RING_MOD_MASK; + cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; } } @@ -404,24 +401,20 @@ static void lance_send(void *opaque) static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) { - LEDMAState *s = opaque; + LANCEState *s = opaque; uint32_t saddr; - saddr = (addr - s->addr) >> 2; - if (saddr < LEDMA_REGS) - return s->regs[saddr]; - else - return 0; + saddr = (addr & LEDMA_MAXADDR) >> 2; + return s->ledmaregs[saddr]; } static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { - LEDMAState *s = opaque; + LANCEState *s = opaque; uint32_t saddr; - saddr = (addr - s->addr) >> 2; - if (saddr < LEDMA_REGS) - s->regs[saddr] = val; + saddr = (addr & LEDMA_MAXADDR) >> 2; + s->ledmaregs[saddr] = val; } static CPUReadMemoryFunc *ledma_mem_read[3] = { @@ -436,33 +429,61 @@ static CPUWriteMemoryFunc *ledma_mem_write[3] = { ledma_mem_writel, }; +static void lance_save(QEMUFile *f, void *opaque) +{ + LANCEState *s = opaque; + int i; + + qemu_put_be32s(f, &s->leptr); + qemu_put_be16s(f, &s->addr); + for (i = 0; i < LE_MAXREG; i ++) + qemu_put_be16s(f, &s->regs[i]); + qemu_put_buffer(f, s->phys, 6); + qemu_put_be32s(f, &s->irq); + for (i = 0; i < LEDMA_REGS; i ++) + qemu_put_be32s(f, &s->ledmaregs[i]); +} + +static int lance_load(QEMUFile *f, void *opaque, int version_id) +{ + LANCEState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->leptr); + qemu_get_be16s(f, &s->addr); + for (i = 0; i < LE_MAXREG; i ++) + qemu_get_be16s(f, &s->regs[i]); + qemu_get_buffer(f, s->phys, 6); + qemu_get_be32s(f, &s->irq); + for (i = 0; i < LEDMA_REGS; i ++) + qemu_get_be32s(f, &s->ledmaregs[i]); + return 0; +} + void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) { LANCEState *s; - LEDMAState *led; int lance_io_memory, ledma_io_memory; s = qemu_mallocz(sizeof(LANCEState)); if (!s) return; - s->paddr = leaddr; s->nd = nd; s->irq = irq; lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); cpu_register_physical_memory(leaddr, 8, lance_io_memory); - led = qemu_mallocz(sizeof(LEDMAState)); - if (!led) - return; - - s->ledma = led; - led->addr = ledaddr; - ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led); + ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); lance_reset(s); qemu_add_read_packet(nd, lance_can_receive, lance_receive, s); + register_savevm("lance", leaddr, 1, lance_save, lance_load, s); + qemu_register_reset(lance_reset, s); } diff --git a/hw/m48t08.c b/hw/m48t08.c index 46ec66557..094587953 100644 --- a/hw/m48t08.c +++ b/hw/m48t08.c @@ -32,19 +32,14 @@ #define NVRAM_PRINTF(fmt, args...) do { } while (0) #endif -#define NVRAM_MAX_MEM 0xfff0 +#define NVRAM_MAX_MEM 0x1ff0 +#define NVRAM_MAXADDR 0x1fff struct m48t08_t { - /* Hardware parameters */ - int mem_index; - uint32_t mem_base; - uint16_t size; /* RTC management */ time_t time_offset; time_t stop_time; /* NVRAM storage */ - uint8_t lock; - uint16_t addr; uint8_t *buffer; }; @@ -83,14 +78,13 @@ static void set_time (m48t08_t *NVRAM, struct tm *tm) } /* Direct access to NVRAM */ -void m48t08_write (m48t08_t *NVRAM, uint32_t val) +void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val) { struct tm tm; int tmp; - if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000) - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); - switch (NVRAM->addr) { + addr &= NVRAM_MAXADDR; + switch (addr) { case 0x1FF8: /* control */ NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; @@ -167,25 +161,18 @@ void m48t08_write (m48t08_t *NVRAM, uint32_t val) } break; default: - /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) - break; - if (NVRAM->addr < NVRAM_MAX_MEM || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - NVRAM->buffer[NVRAM->addr] = val & 0xFF; - } + NVRAM->buffer[addr] = val & 0xFF; break; } } -uint32_t m48t08_read (m48t08_t *NVRAM) +uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr) { struct tm tm; - uint32_t retval = 0xFF; + uint8_t retval = 0xFF; - switch (NVRAM->addr) { + addr &= NVRAM_MAXADDR; + switch (addr) { case 0x1FF8: /* control */ goto do_read; @@ -225,65 +212,36 @@ uint32_t m48t08_read (m48t08_t *NVRAM) retval = toBCD(tm.tm_year); break; default: - /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) - break; - if (NVRAM->addr < NVRAM_MAX_MEM || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - do_read: - retval = NVRAM->buffer[NVRAM->addr]; - } + do_read: + retval = NVRAM->buffer[addr]; break; } - if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000) - NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); - return retval; } -void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr) -{ - NVRAM->addr = addr; -} - -void m48t08_toggle_lock (m48t08_t *NVRAM, int lock) -{ - NVRAM->lock ^= 1 << lock; -} - static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) - NVRAM->buffer[addr] = value; + m48t08_write(NVRAM, addr, value); } static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - NVRAM->buffer[addr] = value >> 8; - NVRAM->buffer[addr + 1] = value; - } + m48t08_write(NVRAM, addr, value); + m48t08_write(NVRAM, addr + 1, value >> 8); } static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t08_t *NVRAM = opaque; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - NVRAM->buffer[addr] = value >> 24; - NVRAM->buffer[addr + 1] = value >> 16; - NVRAM->buffer[addr + 2] = value >> 8; - NVRAM->buffer[addr + 3] = value; - } + m48t08_write(NVRAM, addr, value); + m48t08_write(NVRAM, addr + 1, value >> 8); + m48t08_write(NVRAM, addr + 2, value >> 16); + m48t08_write(NVRAM, addr + 3, value >> 24); } static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) @@ -291,10 +249,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) - retval = NVRAM->buffer[addr]; - + retval = m48t08_read(NVRAM, addr); return retval; } @@ -303,12 +258,8 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - retval = NVRAM->buffer[addr] << 8; - retval |= NVRAM->buffer[addr + 1]; - } - + retval = m48t08_read(NVRAM, addr) << 8; + retval |= m48t08_read(NVRAM, addr + 1); return retval; } @@ -317,14 +268,10 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) m48t08_t *NVRAM = opaque; uint32_t retval = 0; - addr -= NVRAM->mem_base; - if (addr < NVRAM_MAX_MEM) { - retval = NVRAM->buffer[addr] << 24; - retval |= NVRAM->buffer[addr + 1] << 16; - retval |= NVRAM->buffer[addr + 2] << 8; - retval |= NVRAM->buffer[addr + 3]; - } - + retval = m48t08_read(NVRAM, addr) << 24; + retval |= m48t08_read(NVRAM, addr + 1) << 16; + retval |= m48t08_read(NVRAM, addr + 2) << 8; + retval |= m48t08_read(NVRAM, addr + 3); return retval; } @@ -340,12 +287,42 @@ static CPUReadMemoryFunc *nvram_read[] = { &nvram_readl, }; +static void nvram_save(QEMUFile *f, void *opaque) +{ + m48t08_t *s = opaque; + + qemu_put_be32s(f, (uint32_t *)&s->time_offset); + qemu_put_be32s(f, (uint32_t *)&s->stop_time); + qemu_put_buffer(f, s->buffer, 0x2000); +} + +static int nvram_load(QEMUFile *f, void *opaque, int version_id) +{ + m48t08_t *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, (uint32_t *)&s->time_offset); + qemu_get_be32s(f, (uint32_t *)&s->stop_time); + qemu_get_buffer(f, s->buffer, 0x2000); + return 0; +} + +static void m48t08_reset(void *opaque) +{ + m48t08_t *s = opaque; + + s->time_offset = 0; + s->stop_time = 0; +} + + /* Initialisation routine */ -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr) +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) { m48t08_t *s; - int i; - unsigned char tmp = 0; + int mem_index; s = qemu_mallocz(sizeof(m48t08_t)); if (!s) @@ -355,25 +332,13 @@ m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr) qemu_free(s); return NULL; } - s->size = size; - s->mem_base = mem_base; - s->addr = 0; if (mem_base != 0) { - s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); - cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); + mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + cpu_register_physical_memory(mem_base, 0x2000, mem_index); } - s->lock = 0; - i = 0x1fd8; - s->buffer[i++] = 0x01; - s->buffer[i++] = 0x80; /* Sun4m OBP */ - memcpy(&s->buffer[i], macaddr, 6); - - /* Calculate checksum */ - for (i = 0x1fd8; i < 0x1fe7; i++) { - tmp ^= s->buffer[i]; - } - s->buffer[0x1fe7] = tmp; + register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s); + qemu_register_reset(m48t08_reset, s); return s; } diff --git a/hw/m48t08.h b/hw/m48t08.h index 9b44bc0d1..985116a09 100644 --- a/hw/m48t08.h +++ b/hw/m48t08.h @@ -3,10 +3,8 @@ typedef struct m48t08_t m48t08_t; -void m48t08_write (m48t08_t *NVRAM, uint32_t val); -uint32_t m48t08_read (m48t08_t *NVRAM); -void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr); -void m48t08_toggle_lock (m48t08_t *NVRAM, int lock); -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr); +void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val); +uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr); +m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size); #endif /* !defined (__M48T08_H__) */ diff --git a/hw/magic-load.c b/hw/magic-load.c index 06a5f743a..713343a75 100644 --- a/hw/magic-load.c +++ b/hw/magic-load.c @@ -1,5 +1,54 @@ #include "vl.h" #include "disas.h" +#include "exec-all.h" + +struct exec +{ + uint32_t a_info; /* Use macros N_MAGIC, etc for access */ + uint32_t a_text; /* length of text, in bytes */ + uint32_t a_data; /* length of data, in bytes */ + uint32_t a_bss; /* length of uninitialized data area, in bytes */ + uint32_t a_syms; /* length of symbol table data in file, in bytes */ + uint32_t a_entry; /* start address */ + uint32_t a_trsize; /* length of relocation info for text, in bytes */ + uint32_t a_drsize; /* length of relocation info for data, in bytes */ +}; + +#ifdef BSWAP_NEEDED +static void bswap_ahdr(struct exec *e) +{ + bswap32s(&e->a_info); + bswap32s(&e->a_text); + bswap32s(&e->a_data); + bswap32s(&e->a_bss); + bswap32s(&e->a_syms); + bswap32s(&e->a_entry); + bswap32s(&e->a_trsize); + bswap32s(&e->a_drsize); +} +#else +#define bswap_ahdr(x) do { } while (0) +#endif + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 +#define _N_HDROFF(x) (1024 - sizeof (struct exec)) +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ + (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) +#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) +#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) + +#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) + +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) + #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB @@ -103,27 +152,27 @@ static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint3 return NULL; } -static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) +static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) { int retval; retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); if (retval < 0) - return -1; + return NULL; retval = read(fd, shdr, sizeof(*shdr)); if (retval < 0) - return -1; + return NULL; bswap_shdr(shdr); if (shdr->sh_type == SHT_STRTAB) return qemu_malloc(shdr->sh_size);; - return 0; + return NULL; } -static int read_program(int fd, struct elf_phdr *phdr, void *dst) +static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry) { int retval; - retval = lseek(fd, 0x4000, SEEK_SET); + retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); if (retval < 0) return -1; return read(fd, dst, phdr->p_filesz); @@ -178,6 +227,7 @@ static void load_symbols(struct elfhdr *ehdr, int fd) { struct elf_shdr symtab, strtab; struct elf_sym *syms; + struct syminfo *s; int nsyms, i; char *str; @@ -196,20 +246,19 @@ static void load_symbols(struct elfhdr *ehdr, int fd) goto error_freesyms; /* Commit */ - if (disas_symtab) - qemu_free(disas_symtab); /* XXX Merge with old symbols? */ - if (disas_strtab) - qemu_free(disas_strtab); - disas_symtab = syms; - disas_num_syms = nsyms; - disas_strtab = str; + s = qemu_mallocz(sizeof(*s)); + s->disas_symtab = syms; + s->disas_num_syms = nsyms; + s->disas_strtab = str; + s->next = syminfos; + syminfos = s; return; error_freesyms: qemu_free(syms); return; } -int load_elf(const char * filename, uint8_t *addr) +int load_elf(const char *filename, uint8_t *addr) { struct elfhdr ehdr; struct elf_phdr phdr; @@ -227,12 +276,13 @@ int load_elf(const char * filename, uint8_t *addr) if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' - || ehdr.e_machine != EM_SPARC) + || (ehdr.e_machine != EM_SPARC + && ehdr.e_machine != EM_SPARC32PLUS)) goto error; if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) goto error; - retval = read_program(fd, &phdr, addr); + retval = read_program(fd, &phdr, addr, ehdr.e_entry); if (retval < 0) goto error; @@ -245,17 +295,45 @@ int load_elf(const char * filename, uint8_t *addr) return -1; } -int load_kernel(const char *filename, uint8_t *addr) +int load_aout(const char *filename, uint8_t *addr) { - int fd, size; + int fd, size, ret; + struct exec e; + uint32_t magic; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; - /* load 32 bit code */ - size = read(fd, addr, 16 * 1024 * 1024); + + size = read(fd, &e, sizeof(e)); if (size < 0) goto fail; + + bswap_ahdr(&e); + + magic = N_MAGIC(e); + switch (magic) { + case ZMAGIC: + case QMAGIC: + case OMAGIC: + lseek(fd, N_TXTOFF(e), SEEK_SET); + size = read(fd, addr, e.a_text + e.a_data); + if (size < 0) + goto fail; + break; + case NMAGIC: + lseek(fd, N_TXTOFF(e), SEEK_SET); + size = read(fd, addr, e.a_text); + if (size < 0) + goto fail; + ret = read(fd, addr + N_DATADDR(e), e.a_data); + if (ret < 0) + goto fail; + size += ret; + break; + default: + goto fail; + } close(fd); return size; fail: @@ -263,64 +341,3 @@ int load_kernel(const char *filename, uint8_t *addr) return -1; } -typedef struct MAGICState { - uint32_t addr; - uint32_t saved_addr; - int magic_state; - char saved_kfn[1024]; -} MAGICState; - -static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr) -{ - int ret; - MAGICState *s = opaque; - - if (s->magic_state == 0) { - ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr); - if (ret < 0) - ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr); - if (ret < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - s->saved_kfn); - } - s->magic_state = 1; /* No more magic */ - tb_flush(); - return bswap32(ret); - } - return 0; -} - -static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -} - - -static CPUReadMemoryFunc *magic_mem_read[3] = { - magic_mem_readl, - magic_mem_readl, - magic_mem_readl, -}; - -static CPUWriteMemoryFunc *magic_mem_write[3] = { - magic_mem_writel, - magic_mem_writel, - magic_mem_writel, -}; - -void magic_init(const char *kfn, int kloadaddr, uint32_t addr) -{ - int magic_io_memory; - MAGICState *s; - - s = qemu_mallocz(sizeof(MAGICState)); - if (!s) - return; - - strcpy(s->saved_kfn, kfn); - s->saved_addr = kloadaddr; - s->magic_state = 0; - s->addr = addr; - magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s); - cpu_register_physical_memory(addr, 4, magic_io_memory); -} - diff --git a/hw/sched.c b/hw/sched.c deleted file mode 100644 index 2ab966de4..000000000 --- a/hw/sched.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * QEMU interrupt controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -//#define DEBUG_IRQ_COUNT - -/* These registers are used for sending/receiving irqs from/to - * different cpu's. - */ -struct sun4m_intreg_percpu { - unsigned int tbt; /* Intrs pending for this cpu, by PIL. */ - /* These next two registers are WRITE-ONLY and are only - * "on bit" sensitive, "off bits" written have NO affect. - */ - unsigned int clear; /* Clear this cpus irqs here. */ - unsigned int set; /* Set this cpus irqs here. */ -}; -/* - * djhr - * Actually the clear and set fields in this struct are misleading.. - * according to the SLAVIO manual (and the same applies for the SEC) - * the clear field clears bits in the mask which will ENABLE that IRQ - * the set field sets bits in the mask to DISABLE the IRQ. - * - * Also the undirected_xx address in the SLAVIO is defined as - * RESERVED and write only.. - * - * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor - * sun4m machines, for MP the layout makes more sense. - */ -struct sun4m_intreg_master { - unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */ - unsigned int irqs; /* Master IRQ bits. */ - - /* Again, like the above, two these registers are WRITE-ONLY. */ - unsigned int clear; /* Clear master IRQ's by setting bits here. */ - unsigned int set; /* Set master IRQ's by setting bits here. */ - - /* This register is both READ and WRITE. */ - unsigned int undirected_target; /* Which cpu gets undirected irqs. */ -}; - -#define SUN4M_INT_ENABLE 0x80000000 -#define SUN4M_INT_E14 0x00000080 -#define SUN4M_INT_E10 0x00080000 - -#define SUN4M_HARD_INT(x) (0x000000001 << (x)) -#define SUN4M_SOFT_INT(x) (0x000010000 << (x)) - -#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ -#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ -#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ -#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ -#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ -#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ -#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ -#define SUN4M_INT_REALTIME 0x00080000 /* system timer */ -#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ -#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ -#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ -#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ -#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ - -#define SUN4M_INT_SBUS(x) (1 << (x+7)) -#define SUN4M_INT_VME(x) (1 << (x)) - -typedef struct SCHEDState { - uint32_t addr, addrg; - uint32_t intreg_pending; - uint32_t intreg_enabled; - uint32_t intregm_pending; - uint32_t intregm_enabled; -} SCHEDState; - -static SCHEDState *ps; - -#ifdef DEBUG_IRQ_COUNT -static uint64_t irq_count[32]; -#endif - -static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - case 0: - return s->intreg_pending; - break; - default: - break; - } - return 0; -} - -static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - case 0: - s->intreg_pending = val; - break; - case 1: // clear - s->intreg_enabled &= ~val; - break; - case 2: // set - s->intreg_enabled |= val; - break; - default: - break; - } -} - -static CPUReadMemoryFunc *intreg_mem_read[3] = { - intreg_mem_readl, - intreg_mem_readl, - intreg_mem_readl, -}; - -static CPUWriteMemoryFunc *intreg_mem_write[3] = { - intreg_mem_writel, - intreg_mem_writel, - intreg_mem_writel, -}; - -static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addrg) >> 2; - switch (saddr) { - case 0: - return s->intregm_pending; - break; - case 1: - return s->intregm_enabled; - break; - default: - break; - } - return 0; -} - -static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SCHEDState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addrg) >> 2; - switch (saddr) { - case 0: - s->intregm_pending = val; - break; - case 1: - s->intregm_enabled = val; - break; - case 2: // clear - s->intregm_enabled &= ~val; - break; - case 3: // set - s->intregm_enabled |= val; - break; - default: - break; - } -} - -static CPUReadMemoryFunc *intregm_mem_read[3] = { - intregm_mem_readl, - intregm_mem_readl, - intregm_mem_readl, -}; - -static CPUWriteMemoryFunc *intregm_mem_write[3] = { - intregm_mem_writel, - intregm_mem_writel, - intregm_mem_writel, -}; - -void pic_info(void) -{ - term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled); - term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled); -} - -void irq_info(void) -{ -#ifndef DEBUG_IRQ_COUNT - term_printf("irq statistic code not compiled.\n"); -#else - int i; - int64_t count; - - term_printf("IRQ statistics:\n"); - for (i = 0; i < 32; i++) { - count = irq_count[i]; - if (count > 0) - term_printf("%2d: %lld\n", i, count); - } -#endif -} - -static const unsigned int intr_to_mask[16] = { - 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -void pic_set_irq(int irq, int level) -{ - if (irq < 16) { - unsigned int mask = intr_to_mask[irq]; - ps->intreg_pending |= 1 << irq; - if (ps->intregm_enabled & mask) { - cpu_single_env->interrupt_index = irq; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); - } - } -#ifdef DEBUG_IRQ_COUNT - if (level == 1) - irq_count[irq]++; -#endif -} - -void sched_init(uint32_t addr, uint32_t addrg) -{ - int intreg_io_memory, intregm_io_memory; - SCHEDState *s; - - s = qemu_mallocz(sizeof(SCHEDState)); - if (!s) - return; - s->addr = addr; - s->addrg = addrg; - - intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s); - cpu_register_physical_memory(addr, 3, intreg_io_memory); - - intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s); - cpu_register_physical_memory(addrg, 5, intregm_io_memory); - - ps = s; -} - diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c new file mode 100644 index 000000000..745467214 --- /dev/null +++ b/hw/slavio_intctl.c @@ -0,0 +1,299 @@ +/* + * QEMU Sparc SLAVIO interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +//#define DEBUG_IRQ_COUNT + +/* + * Registers of interrupt controller in sun4m. + * + * This is the interrupt controller part of chip STP2001 (Slave I/O), also + * produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * There is a system master controller and one for each cpu. + * + */ + +#define MAX_CPUS 16 + +typedef struct SLAVIO_INTCTLState { + uint32_t intreg_pending[MAX_CPUS]; + uint32_t intregm_pending; + uint32_t intregm_disabled; + uint32_t target_cpu; +#ifdef DEBUG_IRQ_COUNT + uint64_t irq_count[32]; +#endif +} SLAVIO_INTCTLState; + +#define INTCTL_MAXADDR 0xf +#define INTCTLM_MAXADDR 0xf + +// per-cpu interrupt controller +static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + int cpu; + + cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; + saddr = (addr & INTCTL_MAXADDR) >> 2; + switch (saddr) { + case 0: + return s->intreg_pending[cpu]; + default: + break; + } + return 0; +} + +static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + int cpu; + + cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; + saddr = (addr & INTCTL_MAXADDR) >> 2; + switch (saddr) { + case 1: // clear pending softints + if (val & 0x4000) + val |= 80000000; + val &= 0xfffe0000; + s->intreg_pending[cpu] &= ~val; + break; + case 2: // set softint + val &= 0xfffe0000; + s->intreg_pending[cpu] |= val; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = { + slavio_intctl_mem_readl, + slavio_intctl_mem_readl, + slavio_intctl_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = { + slavio_intctl_mem_writel, + slavio_intctl_mem_writel, + slavio_intctl_mem_writel, +}; + +// master system interrupt controller +static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + + saddr = (addr & INTCTLM_MAXADDR) >> 2; + switch (saddr) { + case 0: + return s->intregm_pending; + case 1: + return s->intregm_disabled; + case 4: + return s->target_cpu; + default: + break; + } + return 0; +} + +static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t saddr; + + saddr = (addr & INTCTLM_MAXADDR) >> 2; + switch (saddr) { + case 2: // clear (enable) + // Force unused bits + val |= 0x7fb2007f; + s->intregm_disabled &= ~val; + break; + case 3: // set (disable, clear pending) + // Force unused bits + val &= ~0x7fb2007f; + s->intregm_disabled |= val; + s->intregm_pending &= ~val; + break; + case 4: + s->target_cpu = val & (MAX_CPUS - 1); + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = { + slavio_intctlm_mem_readl, + slavio_intctlm_mem_readl, + slavio_intctlm_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = { + slavio_intctlm_mem_writel, + slavio_intctlm_mem_writel, + slavio_intctlm_mem_writel, +}; + +void slavio_pic_info(void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); + } + term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled); +} + +void slavio_irq_info(void *opaque) +{ +#ifndef DEBUG_IRQ_COUNT + term_printf("irq statistic code not compiled.\n"); +#else + SLAVIO_INTCTLState *s = opaque; + int i; + int64_t count; + + term_printf("IRQ statistics:\n"); + for (i = 0; i < 32; i++) { + count = s->irq_count[i]; + if (count > 0) + term_printf("%2d: %lld\n", i, count); + } +#endif +} + +static const uint32_t intbit_to_level[32] = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, +}; + +/* + * "irq" here is the bit number in the system interrupt register to + * separate serial and keyboard interrupts sharing a level. + */ +void slavio_pic_set_irq(void *opaque, int irq, int level) +{ + SLAVIO_INTCTLState *s = opaque; + + if (irq < 32) { + uint32_t mask = 1 << irq; + uint32_t pil = intbit_to_level[irq]; + if (pil > 0) { + if (level) { + s->intregm_pending |= mask; + s->intreg_pending[s->target_cpu] |= 1 << pil; + } + else { + s->intregm_pending &= ~mask; + s->intreg_pending[s->target_cpu] &= ~(1 << pil); + } + if (level && + !(s->intregm_disabled & mask) && + !(s->intregm_disabled & 0x80000000) && + (pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) { +#ifdef DEBUG_IRQ_COUNT + if (level == 1) + s->irq_count[pil]++; +#endif + cpu_single_env->interrupt_index = TT_EXTINT | pil; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } + } + } +} + +static void slavio_intctl_save(QEMUFile *f, void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + qemu_put_be32s(f, &s->intreg_pending[i]); + } + qemu_put_be32s(f, &s->intregm_pending); + qemu_put_be32s(f, &s->intregm_disabled); + qemu_put_be32s(f, &s->target_cpu); +} + +static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + for (i = 0; i < MAX_CPUS; i++) { + qemu_get_be32s(f, &s->intreg_pending[i]); + } + qemu_get_be32s(f, &s->intregm_pending); + qemu_get_be32s(f, &s->intregm_disabled); + qemu_get_be32s(f, &s->target_cpu); + return 0; +} + +static void slavio_intctl_reset(void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + int i; + + for (i = 0; i < MAX_CPUS; i++) { + s->intreg_pending[i] = 0; + } + s->intregm_disabled = 0xffffffff; + s->intregm_pending = 0; + s->target_cpu = 0; +} + +void *slavio_intctl_init(uint32_t addr, uint32_t addrg) +{ + int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; + SLAVIO_INTCTLState *s; + + s = qemu_mallocz(sizeof(SLAVIO_INTCTLState)); + if (!s) + return NULL; + + for (i = 0; i < MAX_CPUS; i++) { + slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); + cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory); + } + + slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); + cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory); + + register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); + qemu_register_reset(slavio_intctl_reset, s); + slavio_intctl_reset(s); + return s; +} + diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c new file mode 100644 index 000000000..348f328f5 --- /dev/null +++ b/hw/slavio_serial.c @@ -0,0 +1,364 @@ +/* + * QEMU Sparc SLAVIO serial port emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG_SERIAL + +/* debug keyboard */ +//#define DEBUG_KBD + +/* debug keyboard : only mouse */ +//#define DEBUG_MOUSE + +/* + * This is the serial port, mouse and keyboard part of chip STP2001 + * (Slave I/O), also produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * The serial ports implement full AMD AM8530 or Zilog Z8530 chips, + * mouse and keyboard ports don't implement all functions and they are + * only asynchronous. There is no DMA. + * + */ + +typedef struct ChannelState { + int irq; + int reg; + int rxint, txint; + uint8_t rx, tx, wregs[16], rregs[16]; + CharDriverState *chr; +} ChannelState; + +struct SerialState { + struct ChannelState chn[2]; +}; + +#define SERIAL_MAXADDR 7 + +static void slavio_serial_update_irq(ChannelState *s) +{ + if ((s->wregs[1] & 1) && // interrupts enabled + (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending + ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && + s->rxint == 1) || // rx ints enabled, pending + ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p + pic_set_irq(s->irq, 1); + } else { + pic_set_irq(s->irq, 0); + } +} + +static void slavio_serial_reset_chn(ChannelState *s) +{ + int i; + + s->reg = 0; + for (i = 0; i < SERIAL_MAXADDR; i++) { + s->rregs[i] = 0; + s->wregs[i] = 0; + } + s->wregs[4] = 4; + s->wregs[9] = 0xc0; + s->wregs[11] = 8; + s->wregs[14] = 0x30; + s->wregs[15] = 0xf8; + s->rregs[0] = 0x44; + s->rregs[1] = 6; + + s->rx = s->tx = 0; + s->rxint = s->txint = 0; +} + +static void slavio_serial_reset(void *opaque) +{ + SerialState *s = opaque; + slavio_serial_reset_chn(&s->chn[0]); + slavio_serial_reset_chn(&s->chn[1]); +} + +static void slavio_serial_mem_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + SerialState *ser = opaque; + ChannelState *s; + uint32_t saddr; + int newreg, channel; + + val &= 0xff; + saddr = (addr & 3) >> 1; + channel = (addr & SERIAL_MAXADDR) >> 2; + s = &ser->chn[channel]; + switch (saddr) { + case 0: + newreg = 0; + switch (s->reg) { + case 0: + newreg = val & 7; + val &= 0x38; + switch (val) { + case 8: + s->reg |= 0x8; + break; + case 0x20: + s->rxint = 0; + break; + case 0x28: + s->txint = 0; + break; + default: + break; + } + break; + case 1 ... 8: + case 10 ... 15: + s->wregs[s->reg] = val; + break; + case 9: + switch (val & 0xc0) { + case 0: + default: + break; + case 0x40: + slavio_serial_reset_chn(&ser->chn[1]); + return; + case 0x80: + slavio_serial_reset_chn(&ser->chn[0]); + return; + case 0xc0: + slavio_serial_reset(ser); + return; + } + break; + default: + break; + } + if (s->reg == 0) + s->reg = newreg; + else + s->reg = 0; + break; + case 1: + if (s->wregs[5] & 8) { // tx enabled + s->tx = val; + if (s->chr) + qemu_chr_write(s->chr, &s->tx, 1); + s->txint = 1; + } + break; + default: + break; + } +} + +static uint32_t slavio_serial_mem_readb(void *opaque, uint32_t addr) +{ + SerialState *ser = opaque; + ChannelState *s; + uint32_t saddr; + uint32_t ret; + int channel; + + saddr = (addr & 3) >> 1; + channel = (addr & SERIAL_MAXADDR) >> 2; + s = &ser->chn[channel]; + switch (saddr) { + case 0: + ret = s->rregs[s->reg]; + s->reg = 0; + return ret; + case 1: + s->rregs[0] &= ~1; + return s->rx; + default: + break; + } + return 0; +} + +static int serial_can_receive(void *opaque) +{ + ChannelState *s = opaque; + if (((s->wregs[3] & 1) == 0) // Rx not enabled + || ((s->rregs[0] & 1) == 1)) // char already available + return 0; + else + return 1; +} + +static void serial_receive_byte(ChannelState *s, int ch) +{ + s->rregs[0] |= 1; + s->rx = ch; + s->rxint = 1; + slavio_serial_update_irq(s); +} + +static void serial_receive_break(ChannelState *s) +{ + s->rregs[0] |= 0x80; + slavio_serial_update_irq(s); +} + +static void serial_receive1(void *opaque, const uint8_t *buf, int size) +{ + ChannelState *s = opaque; + serial_receive_byte(s, buf[0]); +} + +static void serial_event(void *opaque, int event) +{ + ChannelState *s = opaque; + if (event == CHR_EVENT_BREAK) + serial_receive_break(s); +} + +static CPUReadMemoryFunc *slavio_serial_mem_read[3] = { + slavio_serial_mem_readb, + slavio_serial_mem_readb, + slavio_serial_mem_readb, +}; + +static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = { + slavio_serial_mem_writeb, + slavio_serial_mem_writeb, + slavio_serial_mem_writeb, +}; + +static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) +{ + qemu_put_be32s(f, &s->irq); + qemu_put_be32s(f, &s->reg); + qemu_put_be32s(f, &s->rxint); + qemu_put_be32s(f, &s->txint); + qemu_put_8s(f, &s->rx); + qemu_put_8s(f, &s->tx); + qemu_put_buffer(f, s->wregs, 16); + qemu_put_buffer(f, s->rregs, 16); +} + +static void slavio_serial_save(QEMUFile *f, void *opaque) +{ + SerialState *s = opaque; + + slavio_serial_save_chn(f, &s->chn[0]); + slavio_serial_save_chn(f, &s->chn[1]); +} + +static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) +{ + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &s->reg); + qemu_get_be32s(f, &s->rxint); + qemu_get_be32s(f, &s->txint); + qemu_get_8s(f, &s->rx); + qemu_get_8s(f, &s->tx); + qemu_get_buffer(f, s->wregs, 16); + qemu_get_buffer(f, s->rregs, 16); + return 0; +} + +static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) +{ + SerialState *s = opaque; + int ret; + + ret = slavio_serial_load_chn(f, &s->chn[0], version_id); + if (ret != 0) + return ret; + ret = slavio_serial_load_chn(f, &s->chn[1], version_id); + return ret; + +} + +SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2) +{ + int slavio_serial_io_memory; + SerialState *s; + + s = qemu_mallocz(sizeof(SerialState)); + if (!s) + return NULL; + s->chn[0].irq = irq; + s->chn[1].irq = irq; + s->chn[0].chr = chr1; + s->chn[1].chr = chr2; + + slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); + cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); + + if (chr1) { + qemu_chr_add_read_handler(chr1, serial_can_receive, serial_receive1, &s->chn[0]); + qemu_chr_add_event_handler(chr1, serial_event); + } + if (chr2) { + qemu_chr_add_read_handler(chr2, serial_can_receive, serial_receive1, &s->chn[1]); + qemu_chr_add_event_handler(chr2, serial_event); + } + register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s); + qemu_register_reset(slavio_serial_reset, s); + slavio_serial_reset(s); + return s; +} + +static void sunkbd_event(void *opaque, int ch) +{ + ChannelState *s = opaque; + // XXX: PC -> Sun Type 5 translation? + serial_receive_byte(s, ch); +} + +static void sunmouse_event(void *opaque, + int dx, int dy, int dz, int buttons_state) +{ + ChannelState *s = opaque; + int ch; + + // XXX + ch = 0x42; + serial_receive_byte(s, ch); +} + +void slavio_serial_ms_kbd_init(int base, int irq) +{ + int slavio_serial_io_memory; + SerialState *s; + + s = qemu_mallocz(sizeof(SerialState)); + if (!s) + return; + s->chn[0].irq = irq; + s->chn[1].irq = irq; + s->chn[0].chr = NULL; + s->chn[1].chr = NULL; + + slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); + cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); + + qemu_add_kbd_event_handler(sunkbd_event, &s->chn[0]); + qemu_add_mouse_event_handler(sunmouse_event, &s->chn[1]); + qemu_register_reset(slavio_serial_reset, s); + slavio_serial_reset(s); +} diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c new file mode 100644 index 000000000..43f59d275 --- /dev/null +++ b/hw/slavio_timer.c @@ -0,0 +1,289 @@ +/* + * QEMU Sparc SLAVIO timer controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG_TIMER + +/* + * Registers of hardware timer in sun4m. + * + * This is the timer/counter part of chip STP2001 (Slave I/O), also + * produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 + * are zero. Bit 31 is 1 when count has been reached. + * + */ + +typedef struct SLAVIO_TIMERState { + uint32_t limit, count, counthigh; + int64_t count_load_time; + int64_t expire_time; + int64_t stop_time, tick_offset; + QEMUTimer *irq_timer; + int irq; + int reached, stopped; + int mode; // 0 = processor, 1 = user, 2 = system +} SLAVIO_TIMERState; + +#define TIMER_MAXADDR 0x1f +#define CNT_FREQ 2000000 +#define MAX_CPUS 16 + +// Update count, set irq, update expire_time +static void slavio_timer_get_out(SLAVIO_TIMERState *s) +{ + int out; + int64_t diff, ticks, count; + uint32_t limit; + + // There are three clock tick units: CPU ticks, register units + // (nanoseconds), and counter ticks (500 ns). + if (s->mode == 1 && s->stopped) + ticks = s->stop_time; + else + ticks = qemu_get_clock(vm_clock) - s->tick_offset; + + out = (ticks >= s->expire_time); + if (out) + s->reached = 0x80000000; + if (!s->limit) + limit = 0x7fffffff; + else + limit = s->limit; + + // Convert register units to counter ticks + limit = limit >> 9; + + // Convert cpu ticks to counter ticks + diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec); + + // Calculate what the counter should be, convert to register + // units + count = diff % limit; + s->count = count << 9; + s->counthigh = count >> 22; + + // Expire time: CPU ticks left to next interrupt + // Convert remaining counter ticks to CPU ticks + s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); + +#ifdef DEBUG_TIMER + term_printf("timer: irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); +#endif + if (s->mode != 1) + pic_set_irq(s->irq, out); +} + +// timer callback +static void slavio_timer_irq(void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + if (!s->irq_timer) + return; + slavio_timer_get_out(s); + if (s->mode != 1) + qemu_mod_timer(s->irq_timer, s->expire_time); +} + +static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SLAVIO_TIMERState *s = opaque; + uint32_t saddr; + + saddr = (addr & TIMER_MAXADDR) >> 2; + switch (saddr) { + case 0: + // read limit (system counter mode) or read most signifying + // part of counter (user mode) + if (s->mode != 1) { + // clear irq + pic_set_irq(s->irq, 0); + s->count_load_time = qemu_get_clock(vm_clock); + s->reached = 0; + return s->limit; + } + else { + slavio_timer_get_out(s); + return s->counthigh & 0x7fffffff; + } + case 1: + // read counter and reached bit (system mode) or read lsbits + // of counter (user mode) + slavio_timer_get_out(s); + if (s->mode != 1) + return (s->count & 0x7fffffff) | s->reached; + else + return s->count; + case 3: + // read start/stop status + return s->stopped; + case 4: + // read user/system mode + return s->mode & 1; + default: + return 0; + } +} + +static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + SLAVIO_TIMERState *s = opaque; + uint32_t saddr; + + saddr = (addr & TIMER_MAXADDR) >> 2; + switch (saddr) { + case 0: + // set limit, reset counter + s->count_load_time = qemu_get_clock(vm_clock); + // fall through + case 2: + // set limit without resetting counter + if (!val) + s->limit = 0x7fffffff; + else + s->limit = val & 0x7fffffff; + slavio_timer_irq(s); + break; + case 3: + // start/stop user counter + if (s->mode == 1) { + if (val & 1) { + s->stop_time = qemu_get_clock(vm_clock); + s->stopped = 1; + } + else { + if (s->stopped) + s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time; + s->stopped = 0; + } + } + break; + case 4: + // bit 0: user (1) or system (0) counter mode + if (s->mode == 0 || s->mode == 1) + s->mode = val & 1; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_timer_mem_read[3] = { + slavio_timer_mem_readl, + slavio_timer_mem_readl, + slavio_timer_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = { + slavio_timer_mem_writel, + slavio_timer_mem_writel, + slavio_timer_mem_writel, +}; + +static void slavio_timer_save(QEMUFile *f, void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + qemu_put_be32s(f, &s->limit); + qemu_put_be32s(f, &s->count); + qemu_put_be32s(f, &s->counthigh); + qemu_put_be64s(f, &s->count_load_time); + qemu_put_be64s(f, &s->expire_time); + qemu_put_be64s(f, &s->stop_time); + qemu_put_be64s(f, &s->tick_offset); + qemu_put_be32s(f, &s->irq); + qemu_put_be32s(f, &s->reached); + qemu_put_be32s(f, &s->stopped); + qemu_put_be32s(f, &s->mode); +} + +static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) +{ + SLAVIO_TIMERState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->limit); + qemu_get_be32s(f, &s->count); + qemu_get_be32s(f, &s->counthigh); + qemu_get_be64s(f, &s->count_load_time); + qemu_get_be64s(f, &s->expire_time); + qemu_get_be64s(f, &s->stop_time); + qemu_get_be64s(f, &s->tick_offset); + qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &s->reached); + qemu_get_be32s(f, &s->stopped); + qemu_get_be32s(f, &s->mode); + return 0; +} + +static void slavio_timer_reset(void *opaque) +{ + SLAVIO_TIMERState *s = opaque; + + s->limit = 0; + s->count = 0; + s->count_load_time = qemu_get_clock(vm_clock);; + s->stop_time = s->count_load_time; + s->tick_offset = 0; + s->reached = 0; + s->mode &= 2; + s->stopped = 1; + slavio_timer_get_out(s); +} + +static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) +{ + int slavio_timer_io_memory; + SLAVIO_TIMERState *s; + + s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); + if (!s) + return; + s->irq = irq; + s->mode = mode; + s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); + + slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, + slavio_timer_mem_write, s); + cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory); + register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s); + qemu_register_reset(slavio_timer_reset, s); + slavio_timer_reset(s); +} + +void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2) +{ + int i; + + for (i = 0; i < MAX_CPUS; i++) { + slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0); + } + + slavio_timer_init_internal(addr2, irq2, 2); +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 80305e09c..7cc5bd8d9 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -25,29 +25,32 @@ #include "m48t08.h" #define KERNEL_LOAD_ADDR 0x00004000 -#define MMU_CONTEXT_TBL 0x00003000 -#define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400) -#define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800) -#define PROM_ADDR 0xffd04000 +#define PROM_ADDR 0xffd00000 #define PROM_FILENAMEB "proll.bin" #define PROM_FILENAMEE "proll.elf" -#define PROLL_MAGIC_ADDR 0x20000000 -#define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */ +#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ #define PHYS_JJ_IDPROM_OFF 0x1FD8 #define PHYS_JJ_EEPROM_SIZE 0x2000 -#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ +// IRQs are not PIL ones, but master interrupt controller register +// bits +#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ #define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */ -#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */ -#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */ -#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */ -#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */ -#define PHYS_JJ_LE_IRQ 6 -#define PHYS_JJ_CLOCK 0x71D00000 -#define PHYS_JJ_CLOCK_IRQ 10 -#define PHYS_JJ_CLOCK1 0x71D10000 -#define PHYS_JJ_CLOCK1_IRQ 14 -#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */ +#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */ +#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */ +#define PHYS_JJ_LE_IRQ 16 +#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */ +#define PHYS_JJ_CLOCK_IRQ 7 +#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */ +#define PHYS_JJ_CLOCK1_IRQ 19 +#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */ #define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ +#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */ +#define PHYS_JJ_MS_KBD_IRQ 14 +#define PHYS_JJ_SER 0x71100000 /* Serial */ +#define PHYS_JJ_SER_IRQ 15 +#define PHYS_JJ_SCSI_IRQ 18 +#define PHYS_JJ_FDC 0x71400000 /* Floppy */ +#define PHYS_JJ_FLOPPY_IRQ 22 /* TSC handling */ @@ -57,13 +60,73 @@ uint64_t cpu_get_tsc() } void DMA_run() {} -void SB16_run() {} -int serial_can_receive(SerialState *s) { return 0; } -void serial_receive_byte(SerialState *s, int ch) {} -void serial_receive_break(SerialState *s) {} static m48t08_t *nvram; +static void nvram_init(m48t08_t *nvram, uint8_t *macaddr) +{ + unsigned char tmp = 0; + int i, j; + + i = 0x1fd8; + m48t08_write(nvram, i++, 0x01); + m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */ + j = 0; + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i, macaddr[j]); + + /* Calculate checksum */ + for (i = 0x1fd8; i < 0x1fe7; i++) { + tmp ^= m48t08_read(nvram, i); + } + m48t08_write(nvram, 0x1fe7, tmp); +} + +static void *slavio_intctl; + +void pic_info() +{ + slavio_pic_info(slavio_intctl); +} + +void irq_info() +{ + slavio_irq_info(slavio_intctl); +} + +void pic_set_irq(int irq, int level) +{ + slavio_pic_set_irq(slavio_intctl, irq, level); +} + +static void *tcx; + +void vga_update_display() +{ + tcx_update_display(tcx); +} + +void vga_invalidate_display() +{ + tcx_invalidate_display(tcx); +} + +void vga_screen_dump(const char *filename) +{ + tcx_screen_dump(tcx, filename); +} + +static void *iommu; + +uint32_t iommu_translate(uint32_t addr) +{ + return iommu_translate_local(iommu, addr); +} + /* Sun4m hardware initialisation */ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -72,42 +135,50 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; int ret, linux_boot; - unsigned long bios_offset; + unsigned long vram_size = 0x100000, prom_offset; linux_boot = (kernel_filename != NULL); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); - bios_offset = ram_size; - iommu_init(PHYS_JJ_IOMMU); - sched_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); - tcx_init(ds, PHYS_JJ_TCX_FB); + iommu = iommu_init(PHYS_JJ_IOMMU); + slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); + tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size); lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); - nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE, &nd_table[0].macaddr); - timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ); - timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); - magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR, PROLL_MAGIC_ADDR); + nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr); + slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); + slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); + slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]); + fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); - /* We load Proll as the kernel and start it. It will issue a magic - IO to load the real kernel */ - if (linux_boot) { + prom_offset = ram_size + vram_size; + + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + ret = load_elf(buf, phys_ram_base + prom_offset); + if (ret < 0) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_kernel(buf, - phys_ram_base + KERNEL_LOAD_ADDR); + ret = load_image(buf, phys_ram_base + prom_offset); + } + if (ret < 0) { + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); + } + cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, + prom_offset | IO_MEM_ROM); + + if (linux_boot) { + ret = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) + ret = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (ret < 0) + ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (ret < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", - buf); - exit(1); + kernel_filename); + exit(1); } } - /* Setup a MMU entry for entire address space */ - stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1); - stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1); - stl_raw(phys_ram_base + MMU_L1PTP + (0x01 << 2), (MMU_L2PTP >> 4) | 1); // 01.. == 00.. - stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00.. - stl_raw(phys_ram_base + MMU_L1PTP + (0xf0 << 2), (MMU_L2PTP >> 4) | 1); // f0.. == 00.. - /* 3 = U:RWX S:RWX */ - stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2); - stl_raw(phys_ram_base + MMU_L2PTP, ((0x01 << PTE_PPN_SHIFT) >> 4 ) | (3 << PTE_ACCESS_SHIFT) | 2); } diff --git a/hw/tcx.c b/hw/tcx.c index 7f979946f..ccac0bffa 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -25,179 +25,254 @@ #define MAXX 1024 #define MAXY 768 +/* + * Proll uses only small part of display, we need to switch to full + * display when we get linux framebuffer console or X11 running. For + * now it's just slower and awkward. +*/ +#if 1 #define XSZ (8*80) #define YSZ (24*11) #define XOFF (MAXX-XSZ) #define YOFF (MAXY-YSZ) +#else +#define XSZ MAXX +#define YSZ MAXY +#define XOFF 0 +#define YOFF 0 +#endif typedef struct TCXState { uint32_t addr; DisplayState *ds; uint8_t *vram; + unsigned long vram_offset; + uint8_t r[256], g[256], b[256]; } TCXState; -static TCXState *ts; - -void vga_update_display() +static void tcx_draw_line32(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) { - dpy_update(ts->ds, 0, 0, XSZ, YSZ); + int x; + uint8_t val; + + for(x = 0; x < width; x++) { + val = *s++; + *d++ = s1->r[val]; + *d++ = s1->g[val]; + *d++ = s1->b[val]; + d++; + } } -void vga_invalidate_display() {} +static void tcx_draw_line24(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) +{ + int x; + uint8_t val; -static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr) + for(x = 0; x < width; x++) { + val = *s++; + *d++ = s1->r[val]; + *d++ = s1->g[val]; + *d++ = s1->b[val]; + } +} + +static void tcx_draw_line8(TCXState *s1, uint8_t *d, + const uint8_t *s, int width) { - TCXState *s = opaque; - uint32_t saddr; - unsigned int x, y; - - saddr = addr - s->addr - YOFF*MAXX - XOFF; - y = saddr / MAXX; - x = saddr - y * MAXX; - if (x < XSZ && y < YSZ) { - return s->vram[y * XSZ + x]; + int x; + uint8_t val; + + for(x = 0; x < width; x++) { + val = *s++; + /* XXX translate between palettes? */ + *d++ = val; } - return 0; } -static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr) +/* Fixed line length 1024 allows us to do nice tricks not possible on + VGA... */ +void tcx_update_display(void *opaque) { - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = tcx_mem_readb(opaque, addr) << 8; - v |= tcx_mem_readb(opaque, addr + 1); + TCXState *ts = opaque; + uint32_t page; + int y, page_min, page_max, y_start, dd, ds; + uint8_t *d, *s; + void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width); + + if (ts->ds->depth == 0) + return; +#ifdef LD_BYPASS_OK + page = ts->vram_offset + YOFF*MAXX; #else - v = tcx_mem_readb(opaque, addr); - v |= tcx_mem_readb(opaque, addr + 1) << 8; + page = ts->addr + YOFF*MAXX; #endif - return v; + y_start = -1; + page_min = 0x7fffffff; + page_max = -1; + d = ts->ds->data; + s = ts->vram + YOFF*MAXX + XOFF; + dd = ts->ds->linesize; + ds = 1024; + + switch (ts->ds->depth) { + case 32: + f = tcx_draw_line32; + break; + case 24: + f = tcx_draw_line24; + break; + default: + case 8: + f = tcx_draw_line8; + break; + case 0: + return; + } + + for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) { + if (cpu_physical_memory_is_dirty(page)) { + if (y_start < 0) + y_start = y; + if (page < page_min) + page_min = page; + if (page > page_max) + page_max = page; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + f(ts, d, s, XSZ); + d += dd; + s += ds; + } else { + if (y_start >= 0) { + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + XSZ, y - y_start); + y_start = -1; + } + d += dd * 4; + s += ds * 4; + } + } + if (y_start >= 0) { + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + XSZ, y - y_start); + } + /* reset modified pages */ + if (page_max != -1) { + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE); + } } -static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr) +void tcx_invalidate_display(void *opaque) { - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = tcx_mem_readb(opaque, addr) << 24; - v |= tcx_mem_readb(opaque, addr + 1) << 16; - v |= tcx_mem_readb(opaque, addr + 2) << 8; - v |= tcx_mem_readb(opaque, addr + 3); + TCXState *s = opaque; + int i; + + for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) { +#ifdef LD_BYPASS_OK + cpu_physical_memory_set_dirty(s->vram_offset + i); #else - v = tcx_mem_readb(opaque, addr); - v |= tcx_mem_readb(opaque, addr + 1) << 8; - v |= tcx_mem_readb(opaque, addr + 2) << 16; - v |= tcx_mem_readb(opaque, addr + 3) << 24; + cpu_physical_memory_set_dirty(s->addr + i); #endif - return v; + } } -static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void tcx_save(QEMUFile *f, void *opaque) { TCXState *s = opaque; - uint32_t saddr; - unsigned int x, y; - char *sptr; - - saddr = addr - s->addr - YOFF*MAXX - XOFF; - y = saddr / MAXX; - x = saddr - y * MAXX; - if (x < XSZ && y < YSZ) { - sptr = s->ds->data; - if (sptr) { - if (s->ds->depth == 24 || s->ds->depth == 32) { - /* XXX need to do CLUT translation */ - sptr[y * s->ds->linesize + x*4] = val & 0xff; - sptr[y * s->ds->linesize + x*4+1] = val & 0xff; - sptr[y * s->ds->linesize + x*4+2] = val & 0xff; - } - else if (s->ds->depth == 8) { - sptr[y * s->ds->linesize + x] = val & 0xff; - } - } - cpu_physical_memory_set_dirty(addr); - s->vram[y * XSZ + x] = val & 0xff; - } + + qemu_put_be32s(f, (uint32_t *)&s->addr); + qemu_put_be32s(f, (uint32_t *)&s->vram); + qemu_put_buffer(f, s->r, 256); + qemu_put_buffer(f, s->g, 256); + qemu_put_buffer(f, s->b, 256); } -static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static int tcx_load(QEMUFile *f, void *opaque, int version_id) { -#ifdef TARGET_WORDS_BIGENDIAN - tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 1, val & 0xff); -#else - tcx_mem_writeb(opaque, addr, val & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif + TCXState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, (uint32_t *)&s->addr); + qemu_get_be32s(f, (uint32_t *)&s->vram); + qemu_get_buffer(f, s->r, 256); + qemu_get_buffer(f, s->g, 256); + qemu_get_buffer(f, s->b, 256); + return 0; } -static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void tcx_reset(void *opaque) { -#ifdef TARGET_WORDS_BIGENDIAN - tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); - tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 3, val & 0xff); -#else - tcx_mem_writeb(opaque, addr, val & 0xff); - tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); - tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); - tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); + TCXState *s = opaque; + + /* Initialize palette */ + memset(s->r, 0, 256); + memset(s->g, 0, 256); + memset(s->b, 0, 256); + s->r[255] = s->g[255] = s->b[255] = 255; + memset(s->vram, 0, MAXX*MAXY); +#ifdef LD_BYPASS_OK + cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY - 1); #endif } -static CPUReadMemoryFunc *tcx_mem_read[3] = { - tcx_mem_readb, - tcx_mem_readw, - tcx_mem_readl, -}; - -static CPUWriteMemoryFunc *tcx_mem_write[3] = { - tcx_mem_writeb, - tcx_mem_writew, - tcx_mem_writel, -}; - -void tcx_init(DisplayState *ds, uint32_t addr) +void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size) { TCXState *s; - int tcx_io_memory; s = qemu_mallocz(sizeof(TCXState)); if (!s) - return; + return NULL; s->ds = ds; s->addr = addr; - ts = s; - tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s); - cpu_register_physical_memory(addr, 0x100000, - tcx_io_memory); - s->vram = qemu_mallocz(XSZ*YSZ); + s->vram = vram_base; + s->vram_offset = vram_offset; + + cpu_register_physical_memory(addr, vram_size, vram_offset); + + register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); + qemu_register_reset(tcx_reset, s); + tcx_reset(s); dpy_resize(s->ds, XSZ, YSZ); + return s; } -void vga_screen_dump(const char *filename) +void tcx_screen_dump(void *opaque, const char *filename) { - TCXState *s = ts; + TCXState *s = opaque; FILE *f; - uint8_t *d, *d1; - unsigned int v; + uint8_t *d, *d1, v; int y, x; f = fopen(filename, "wb"); if (!f) - return -1; - fprintf(f, "P6\n%d %d\n%d\n", - XSZ, YSZ, 255); - d1 = s->vram; + return; + fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255); + d1 = s->vram + YOFF*MAXX + XOFF; for(y = 0; y < YSZ; y++) { d = d1; for(x = 0; x < XSZ; x++) { v = *d; - fputc((v) & 0xff, f); - fputc((v) & 0xff, f); - fputc((v) & 0xff, f); + fputc(s->r[v], f); + fputc(s->g[v], f); + fputc(s->b[v], f); d++; } - d1 += XSZ; + d1 += MAXX; } fclose(f); return; diff --git a/hw/timer.c b/hw/timer.c deleted file mode 100644 index e393fa36f..000000000 --- a/hw/timer.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * QEMU Sparc timer controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* - * Registers of hardware timer in sun4m. - */ -struct sun4m_timer_percpu { - volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ - volatile unsigned int l14_cur_count; -}; - -struct sun4m_timer_global { - volatile unsigned int l10_timer_limit; - volatile unsigned int l10_cur_count; -}; - -typedef struct TIMERState { - uint32_t addr; - uint32_t timer_regs[2]; - int irq; -} TIMERState; - -static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr) -{ - TIMERState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - default: - return s->timer_regs[saddr]; - break; - } - return 0; -} - -static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - TIMERState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - default: - s->timer_regs[saddr] = val; - break; - } -} - -static CPUReadMemoryFunc *timer_mem_read[3] = { - timer_mem_readl, - timer_mem_readl, - timer_mem_readl, -}; - -static CPUWriteMemoryFunc *timer_mem_write[3] = { - timer_mem_writel, - timer_mem_writel, - timer_mem_writel, -}; - -void timer_init(uint32_t addr, int irq) -{ - int timer_io_memory; - TIMERState *s; - - s = qemu_mallocz(sizeof(TIMERState)); - if (!s) - return; - s->addr = addr; - s->irq = irq; - - timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s); - cpu_register_physical_memory(addr, 2, timer_io_memory); -} diff --git a/linux-user/elfload.c b/linux-user/elfload.c index cfc425697..09c33aa90 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -841,6 +841,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) unsigned int i; struct elf_shdr sechdr, symtab, strtab; char *strings; + struct syminfo *s; lseek(fd, hdr->e_shoff, SEEK_SET); for (i = 0; i < hdr->e_shnum; i++) { @@ -866,24 +867,27 @@ static void load_symbols(struct elfhdr *hdr, int fd) found: /* Now know where the strtab and symtab are. Snarf them. */ - disas_symtab = malloc(symtab.sh_size); - disas_strtab = strings = malloc(strtab.sh_size); - if (!disas_symtab || !disas_strtab) + s = malloc(sizeof(*s)); + s->disas_symtab = malloc(symtab.sh_size); + s->disas_strtab = strings = malloc(strtab.sh_size); + if (!s->disas_symtab || !s->disas_strtab) return; lseek(fd, symtab.sh_offset, SEEK_SET); - if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size) + if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) return; #ifdef BSWAP_NEEDED for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) - bswap_sym(disas_symtab + sizeof(struct elf_sym)*i); + bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); #endif lseek(fd, strtab.sh_offset, SEEK_SET); if (read(fd, strings, strtab.sh_size) != strtab.sh_size) return; - disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->next = syminfos; + syminfos = s; } static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, diff --git a/linux-user/main.c b/linux-user/main.c index 6ab024e0b..3d99dda1a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -497,6 +497,8 @@ void cpu_loop (CPUSPARCState *env) case TT_WIN_UNF: /* window underflow */ restore_window(env); break; + case 0x100: // XXX, why do we get these? + break; default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); diff --git a/linux-user/signal.c b/linux-user/signal.c index 50f2ba10a..49278208c 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1354,13 +1354,14 @@ struct target_rt_signal_frame { __siginfo_fpu_t fpu_state; }; -#define UREG_O0 0 -#define UREG_O6 6 -#define UREG_I0 16 -#define UREG_I1 17 -#define UREG_I2 18 -#define UREG_I6 22 -#define UREG_I7 23 +#define UREG_O0 16 +#define UREG_O6 22 +#define UREG_I0 0 +#define UREG_I1 1 +#define UREG_I2 2 +#define UREG_I6 6 +#define UREG_I7 7 +#define UREG_L0 8 #define UREG_FP UREG_I6 #define UREG_SP UREG_O6 @@ -1385,23 +1386,20 @@ setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) { int err = 0, i; - fprintf(stderr, "2.a %lx psr: %lx regs: %lx\n", si, env->psr, si->si_regs.psr); err |= __put_user(env->psr, &si->si_regs.psr); - fprintf(stderr, "2.a1 pc:%lx\n", si->si_regs.pc); err |= __put_user(env->pc, &si->si_regs.pc); err |= __put_user(env->npc, &si->si_regs.npc); err |= __put_user(env->y, &si->si_regs.y); - fprintf(stderr, "2.b\n"); for (i=0; i < 7; i++) { err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]); } for (i=0; i < 7; i++) { - err |= __put_user(env->regwptr[i+16], &si->si_regs.u_regs[i+8]); + err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); } - fprintf(stderr, "2.c\n"); err |= __put_user(mask, &si->si_mask); return err; } + static int setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ CPUState *env, unsigned long mask) @@ -1434,6 +1432,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, sf = (struct target_signal_frame *) get_sigframe(ka, env, sigframe_size); + //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); #if 0 if (invalid_frame_pointer(sf, sigframe_size)) goto sigill_and_return; @@ -1451,13 +1450,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, } for (i = 0; i < 7; i++) { - err |= __put_user(env->regwptr[i + 8], &sf->ss.locals[i]); + err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]); } for (i = 0; i < 7; i++) { - err |= __put_user(env->regwptr[i + 16], &sf->ss.ins[i]); + err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]); } - //err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], - // sizeof(struct reg_window)); if (err) goto sigsegv; @@ -1486,13 +1483,15 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, /* Flush instruction space. */ //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); - //tb_flush(env); + tb_flush(env); } + //cpu_dump_state(env, stderr, fprintf, 0); return; sigill_and_return: force_sig(TARGET_SIGILL); sigsegv: + //fprintf(stderr, "force_sig\n"); force_sig(TARGET_SIGSEGV); } static inline int @@ -1542,13 +1541,16 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, long do_sigreturn(CPUState *env) { struct target_signal_frame *sf; - unsigned long up_psr, pc, npc; + uint32_t up_psr, pc, npc; target_sigset_t set; + sigset_t host_set; __siginfo_fpu_t *fpu_save; - int err; + int err, i; - sf = (struct new_signal_frame *) env->regwptr[UREG_FP]; - fprintf(stderr, "sigreturn sf: %lx\n", &sf); + sf = (struct target_signal_frame *) env->regwptr[UREG_FP]; + fprintf(stderr, "sigreturn\n"); + fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); + //cpu_dump_state(env, stderr, fprintf, 0); /* 1. Make sure we are not getting garbage from the user */ #if 0 @@ -1567,36 +1569,41 @@ long do_sigreturn(CPUState *env) goto segv_and_exit; /* 2. Restore the state */ - up_psr = env->psr; - //err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs) - //); + err |= __get_user(up_psr, &sf->info.si_regs.psr); + /* User can only change condition codes and FPU enabling in %psr. */ env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */)) | (env->psr & (PSR_ICC /* | PSR_EF */)); - fprintf(stderr, "psr: %lx\n", env->psr); + fprintf(stderr, "psr: %x\n", env->psr); + env->pc = pc-4; + env->npc = pc; + err |= __get_user(env->y, &sf->info.si_regs.y); + for (i=0; i < 7; i++) { + err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); + } + for (i=0; i < 7; i++) { + err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); + } err |= __get_user(fpu_save, &sf->fpu_save); - if (fpu_save) - err |= restore_fpu_state(env, fpu_save); + //if (fpu_save) + // err |= restore_fpu_state(env, fpu_save); /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ err |= __get_user(set.sig[0], &sf->info.si_mask); - //err |= __copy_from_user(&set.sig[1], &sf->extramask, - // (_NSIG_WORDS-1) * sizeof(unsigned int)); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + err |= (__get_user(set.sig[i], &sf->extramask[i - 1])); + } + + target_to_host_sigset_internal(&host_set, &set); + sigprocmask(SIG_SETMASK, &host_set, NULL); if (err) goto segv_and_exit; -#if 0 - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); - current->blocked = set; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); -#endif fprintf(stderr, "returning %lx\n", env->regwptr[0]); return env->regwptr[0]; diff --git a/pc-bios/proll.bin b/pc-bios/proll.bin deleted file mode 100644 index 0489cc245..000000000 Binary files a/pc-bios/proll.bin and /dev/null differ diff --git a/pc-bios/proll.elf b/pc-bios/proll.elf new file mode 100644 index 000000000..e274b0d19 Binary files /dev/null and b/pc-bios/proll.elf differ diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch index b0860e26f..18a157512 100644 --- a/pc-bios/proll.patch +++ b/pc-bios/proll.patch @@ -1,50 +1,2064 @@ -diff -ru proll_18.orig/mrcoffee/main.c proll_18/mrcoffee/main.c ---- proll_18.orig/mrcoffee/main.c 2002-09-13 16:16:59.000000000 +0200 -+++ proll_18/mrcoffee/main.c 2004-09-26 11:52:23.000000000 +0200 -@@ -101,6 +101,7 @@ - le_probe(); - init_net(); +diff -ruN proll_18.orig/Makefile proll-patch4/Makefile +--- proll_18.orig/Makefile 2002-09-13 14:16:59.000000000 +0000 ++++ proll-patch4/Makefile 2004-11-13 15:50:49.000000000 +0000 +@@ -4,6 +4,7 @@ + make -C krups-ser all + make -C espresso all + make -C espresso-ser all ++ make -C qemu all + clean: + make -C mrcoffee clean +@@ -11,3 +12,4 @@ + make -C krups-ser clean + make -C espresso clean + make -C espresso-ser clean ++ make -C qemu clean +diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S +--- proll_18.orig/qemu/head.S 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/qemu/head.S 2004-11-13 15:50:49.000000000 +0000 +@@ -0,0 +1,515 @@ ++/** ++ ** Standalone startup code for Linux PROM emulator. ++ ** Copyright 1999 Pete A. Zaitcev ++ ** This code is licensed under GNU General Public License. ++ **/ ++/* ++ * $Id: proll.patch,v 1.2 2004-12-19 23:18:01 bellard Exp $ ++ */ ++ ++#include ++#include ++#include ++/* #include */ /* Trap entries. Do not use. */ ++#include "phys_jj.h" ++ ++#define C_LABEL(name) name ++#define REGWIN_SZ 0x40 ++ ++#define WRITE_PAUSE nop; nop; nop; /* Have to do this after %wim/%psr chg */ ++ ++ /* 22 is 24-2, (va)>>(SRMMU_PGDIR_SHIFT-PTESIZESHFT) */ ++#define VATOPGDOFF(va) (((va)>>22)&0x3FC) ++#define VATOPMDOFF(va) (((va)>>16)&0xFC) ++ ++#define NOP_INSN 0x01000000 /* Used to patch sparc_save_state */ ++ ++/* Here are some trap goodies */ ++ ++#if 0 ++/* Generic trap entry. */ ++#define TRAP_ENTRY(type, label) \ ++ rd %psr, %l0; b label; rd %wim, %l3; nop; ++#endif ++ ++/* Data/text faults. */ ++#define SRMMU_TFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 1, %l7; ++#define SRMMU_DFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 0, %l7; ++ ++#if 0 ++/* This is for traps we should NEVER get. */ ++#define BAD_TRAP(num) \ ++ rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3; ++ ++/* This is for traps when we want just skip the instruction which caused it */ ++#define SKIP_TRAP(type, name) \ ++ jmpl %l2, %g0; rett %l2 + 4; nop; nop; ++ ++/* Notice that for the system calls we pull a trick. We load up a ++ * different pointer to the system call vector table in %l7, but call ++ * the same generic system call low-level entry point. The trap table ++ * entry sequences are also HyperSparc pipeline friendly ;-) ++ */ ++ ++/* Software trap for Linux system calls. */ ++#define LINUX_SYSCALL_TRAP \ ++ sethi %hi(C_LABEL(sys_call_table)), %l7; \ ++ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ ++ b linux_sparc_syscall; \ ++ rd %psr, %l0; ++ ++/* Software trap for SunOS4.1.x system calls. */ ++#define SUNOS_SYSCALL_TRAP \ ++ rd %psr, %l0; \ ++ sethi %hi(C_LABEL(sunos_sys_table)), %l7; \ ++ b linux_sparc_syscall; \ ++ or %l7, %lo(C_LABEL(sunos_sys_table)), %l7; ++ ++/* Software trap for Slowaris system calls. */ ++#define SOLARIS_SYSCALL_TRAP \ ++ b solaris_syscall; \ ++ rd %psr, %l0; \ ++ nop; \ ++ nop; ++ ++#define INDIRECT_SOLARIS_SYSCALL(x) \ ++ mov x, %g1; \ ++ b solaris_syscall; \ ++ rd %psr, %l0; \ ++ nop; ++ ++#define BREAKPOINT_TRAP \ ++ b breakpoint_trap; \ ++ rd %psr,%l0; \ ++ nop; \ ++ nop; ++ ++/* Software trap for Sparc-netbsd system calls. */ ++#define NETBSD_SYSCALL_TRAP \ ++ sethi %hi(C_LABEL(sys_call_table)), %l7; \ ++ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ ++ b bsd_syscall; \ ++ rd %psr, %l0; ++ ++/* The Get Condition Codes software trap for userland. */ ++#define GETCC_TRAP \ ++ b getcc_trap_handler; mov %psr, %l0; nop; nop; ++ ++/* The Set Condition Codes software trap for userland. */ ++#define SETCC_TRAP \ ++ b setcc_trap_handler; mov %psr, %l0; nop; nop; ++ ++/* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and ++ * gets handled with another macro. ++ */ ++#define TRAP_ENTRY_INTERRUPT(int_level) \ ++ mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3; ++ ++/* NMI's (Non Maskable Interrupts) are special, you can't keep them ++ * from coming in, and basically if you get one, the shows over. ;( ++ * On the sun4c they are usually asynchronous memory errors, on the ++ * the sun4m they could be either due to mem errors or a software ++ * initiated interrupt from the prom/kern on an SMP box saying "I ++ * command you to do CPU tricks, read your mailbox for more info." ++ */ ++#define NMI_TRAP \ ++ rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop; ++ ++#endif ++ ++/* Window overflows/underflows are special and we need to try to be as ++ * efficient as possible here.... ++ */ ++#define WINDOW_SPILL \ ++ rd %psr, %l0; rd %wim, %l3; b spill_window_entry; nop; ++ ++#define WINDOW_FILL \ ++ rd %psr, %l0; rd %wim, %l3; b fill_window_entry; nop; ++ ++#define STUB_TRAP ba stub_trap; nop; nop; nop; ++ ++#define TRAP_ENTRY(a,b) STUB_TRAP ++#define SKIP_TRAP(a,b) STUB_TRAP ++#define SUNOS_SYSCALL_TRAP STUB_TRAP ++#define SOLARIS_SYSCALL_TRAP STUB_TRAP ++#define NETBSD_SYSCALL_TRAP STUB_TRAP ++#define LINUX_SYSCALL_TRAP STUB_TRAP ++#define BREAKPOINT_TRAP STUB_TRAP ++#define NMI_TRAP STUB_TRAP ++#define GETCC_TRAP STUB_TRAP ++#define SETCC_TRAP STUB_TRAP ++#define BAD_TRAP(n) STUB_TRAP ++#define TRAP_ENTRY_INTERRUPT(i) STUB_TRAP ++#define INDIRECT_SOLARIS_SYSCALL(i) STUB_TRAP ++ ++ .section ".text" ++ .globl start, _start ++_start: ++start: ++ .globl spill_window_entry, fill_window_entry ++C_LABEL(trapbase): ++t_zero: b goprol; nop; nop; nop; ++t_tflt: SRMMU_TFAULT /* Inst. Access Exception */ ++t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ ++t_pins: TRAP_ENTRY(0x3, priv_instruction) /* Privileged Instruction */ ++t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ ++t_wovf: WINDOW_SPILL /* Window Overflow */ ++t_wunf: WINDOW_FILL /* Window Underflow */ ++t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ ++t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ ++t_dflt: SRMMU_DFAULT /* Data Miss Exception */ ++t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ ++t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ ++t_badc: BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) ++t_irq1: TRAP_ENTRY_INTERRUPT(1) /* IRQ Software/SBUS Level 1 */ ++t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ ++t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ ++t_irq4: TRAP_ENTRY_INTERRUPT(4) /* IRQ Software Level 4 */ ++t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ ++t_irq6: TRAP_ENTRY_INTERRUPT(6) /* IRQ Software Level 6 */ ++t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ ++t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ ++t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ ++t_irq10:TRAP_ENTRY_INTERRUPT(10) /* IRQ Timer #1 (one we use) */ ++t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ ++t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ ++t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ ++t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ ++t_nmi: NMI_TRAP /* Level 15 (NMI) */ ++t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ ++t_iacce:BAD_TRAP(0x21) /* Instr Access Error */ ++t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23) ++t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ ++t_uflsh:SKIP_TRAP(0x25, unimp_flush) /* Unimplemented FLUSH inst. */ ++t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27) ++t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ ++t_dacce:SRMMU_DFAULT /* Data Access Error */ ++t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ ++t_dserr:BAD_TRAP(0x2b) /* Data Store Error */ ++t_daccm:BAD_TRAP(0x2c) /* Data Access MMU-Miss */ ++t_bad2d: BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) ++ BAD_TRAP(0x30) BAD_TRAP(0x31) BAD_TRAP(0x32) BAD_TRAP(0x33) ++ BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) BAD_TRAP(0x37) ++ BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) ++t_iaccm:BAD_TRAP(0x3c) /* Instr Access MMU-Miss */ ++ BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) ++ BAD_TRAP(0x40) BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) ++ BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46) BAD_TRAP(0x47) ++ BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b) ++ BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) ++ BAD_TRAP(0x50) BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) ++ BAD_TRAP(0x54) BAD_TRAP(0x55) BAD_TRAP(0x56) BAD_TRAP(0x57) ++ BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) BAD_TRAP(0x5b) ++ BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) ++ BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) ++ BAD_TRAP(0x64) BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) ++ BAD_TRAP(0x68) BAD_TRAP(0x69) BAD_TRAP(0x6a) BAD_TRAP(0x6b) ++ BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) BAD_TRAP(0x6f) ++ BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) ++ BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) ++ BAD_TRAP(0x78) BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) ++ BAD_TRAP(0x7c) BAD_TRAP(0x7d) BAD_TRAP(0x7e) BAD_TRAP(0x7f) ++t_sunos:SUNOS_SYSCALL_TRAP /* SunOS System Call */ ++t_sbkpt:BREAKPOINT_TRAP /* Software Breakpoint/KGDB */ ++t_divz: BAD_TRAP(0x82) /* Divide by zero trap */ ++t_flwin:TRAP_ENTRY(0x83, do_flush_windows) /* Flush Windows Trap */ ++t_clwin:BAD_TRAP(0x84) /* Clean Windows Trap */ ++t_rchk: BAD_TRAP(0x85) /* Range Check */ ++t_funal:BAD_TRAP(0x86) /* Fix Unaligned Access Trap */ ++t_iovf: BAD_TRAP(0x87) /* Integer Overflow Trap */ ++t_slowl:SOLARIS_SYSCALL_TRAP /* Slowaris System Call */ ++t_netbs:NETBSD_SYSCALL_TRAP /* Net-B.S. System Call */ ++t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) ++ BAD_TRAP(0x8e) BAD_TRAP(0x8f) ++t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ ++t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) ++ BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) ++ BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) ++t_getcc:GETCC_TRAP /* Get Condition Codes */ ++t_setcc:SETCC_TRAP /* Set Condition Codes */ ++t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3) ++ BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) ++t_slowi:INDIRECT_SOLARIS_SYSCALL(156) ++ BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) ++ BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) ++ BAD_TRAP(0xb0) BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) ++ BAD_TRAP(0xb4) BAD_TRAP(0xb5) BAD_TRAP(0xb6) BAD_TRAP(0xb7) ++ BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) BAD_TRAP(0xbb) ++ BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) ++t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) ++ BAD_TRAP(0xc4) BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) ++ BAD_TRAP(0xc8) BAD_TRAP(0xc9) BAD_TRAP(0xca) BAD_TRAP(0xcb) ++ BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) BAD_TRAP(0xcf) ++ BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) ++t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) ++ BAD_TRAP(0xd8) BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) ++ BAD_TRAP(0xdc) BAD_TRAP(0xdd) BAD_TRAP(0xde) BAD_TRAP(0xdf) ++ BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) BAD_TRAP(0xe3) ++ BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) ++t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) ++ BAD_TRAP(0xec) BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) ++ BAD_TRAP(0xf0) BAD_TRAP(0xf1) BAD_TRAP(0xf2) BAD_TRAP(0xf3) ++ BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) BAD_TRAP(0xf7) ++ BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) ++t_badfc:BAD_TRAP(0xfc) BAD_TRAP(0xfd) ++dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */ ++dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */ ++ ++stub_trap: ++ set (PHYS_JJ_TCX_FB + 0xbf0), %g5 /* 2 cells from side */ ++ set 0x00ffffff, %g4 ++ sta %g4, [%g5] ASI_M_BYPASS ++1: ba 1b; nop ++ ++ .section ".bss" ++ .align 8 ++bss_start: ++ .align 0x1000 ! PAGE_SIZE ++ .globl C_LABEL(bootup_user_stack) ++ .type bootup_user_stack,#object ++ .size bootup_user_stack,0x2000 ++C_LABEL(bootup_user_stack): .skip 0x2000 ++ ++ .section ".text" ++ ++goprol: ++ ! %g1 contains end of memory ++ ! map PROLDATA to PROLBASE+PROLSIZE to end of ram ++ set PROLSIZE+0x1000-PROLDATA+PROLBASE, %g2 ! add 0x1000 for temp tables ++ sub %g1, %g2, %g2 ! start of private memory ++ srl %g2, 0x4, %g7 ! ctx table at s+0x0 ++ add %g2, 0x400, %g3 ! l1 table at s+0x400 ++ srl %g3, 0x4, %g3 ++ or %g3, 0x1, %g3 ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x400, %g2 ! s+0x400 ++ add %g2, 0x800, %g3 ! l2 table for ram (00xxxxxx) at s+0x800 ++ srl %g3, 0x4, %g3 ++ or %g3, 0x1, %g3 ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x500, %g3 ! l2 table for rom (ffxxxxxx) at s+0x900 ++ add %g2, 0x3fc, %g2 ! s+0x7fc ++ srl %g3, 0x4, %g3 ++ or %g3, 0x1, %g3 ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x4, %g2 ! s+0x800 ++ set ((7 << 2) | 2), %g3 ! 7 = U: --- S: RWX (main memory) ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x200, %g3 ! l3 table for rom at s+0xa00 ++ add %g2, 0x1d0, %g2 ! s+0x9d0 ++ srl %g3, 0x4, %g3 ++ or %g3, 0x1, %g3 ++ sta %g3, [%g2] ASI_M_BYPASS ++ add %g2, 0x30, %g2 ! s+0xa00 ++ ++ set PROLBASE, %g3 ++ set 0x1000, %g5 ++ set (PROLDATA-PROLBASE)/0x1000, %g6 ! # of .text pages ++1: srl %g3, 0x4, %g4 ++ or %g4, ((7 << 2) | 2), %g4 ! 4 = U: --X S: --X (rom, execute only) ++ sta %g4, [%g2] ASI_M_BYPASS ++ add %g2, 4, %g2 ++ add %g3, %g5, %g3 ++ deccc %g6 ++ bne 1b ++ nop ++#if 0 ++ set (PROLDATA-PROLRODATA)/0x1000, %g6 ! # of .rodata pages ++1: srl %g3, 0x4, %g4 ++ or %g4, ((0 << 2) | 2), %g4 ! 0 = U: R-- S: R-- (rom, read only) ++ sta %g4, [%g2] ASI_M_BYPASS ++ add %g2, 4, %g2 ++ add %g3, %g5, %g3 ++ deccc %g6 ++ bne 1b ++ nop ++#endif ++ set (PROLBASE+PROLSIZE-PROLDATA)/0x1000, %g6 ! # of .bss pages ++ set 0x1000, %g4 ++ sll %g7, 0x4, %g3 ++ add %g4, %g3, %g3 ++1: srl %g3, 0x4, %g4 ++ or %g4, ((7 << 2) | 2), %g4 ! 5 = U: R-- S: RW- (data area, read/write) ++ sta %g4, [%g2] ASI_M_BYPASS ++ add %g2, 4, %g2 ++ add %g3, %g5, %g3 ++ deccc %g6 ++ bne 1b ++ nop ++ ++ mov %g1, %g3 ++ ++ set AC_M_CTPR, %g2 ++ sta %g7, [%g2] ASI_M_MMUREGS ! set ctx table ptr ++ set 1, %g1 ++ sta %g1, [%g0] ASI_M_MMUREGS ! enable mmu ++ ++ /* ++ * The code which enables traps is a simplified version of ++ * kernel head.S. ++ * ++ * We know number of windows as 8 so we do not calculate them. ++ * The deadwood is here for any case. ++ */ ++ ++ /* Turn on Supervisor, EnableFloating, and all the PIL bits. ++ * Also puts us in register window zero with traps off. ++ */ ++ set (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 ++ wr %g2, 0x0, %psr ++ WRITE_PAUSE ++ ++ /* I want a kernel stack NOW! */ ++ set C_LABEL(bootup_user_stack), %g1 ++ set (0x2000 - REGWIN_SZ), %g2 ++ add %g1, %g2, %sp ++ mov 0, %fp /* And for good luck */ ++ ++ /* Zero out our BSS section. */ ++ set C_LABEL(bss_start) , %o0 ! First address of BSS ++ set C_LABEL(end) , %o1 ! Last address of BSS ++ ba 2f ++ nop ++1: ++ st %g0, [%o0] ++2: ++ subcc %o0, %o1, %g0 ++ bl 1b ++ add %o0, 0x4, %o0 ++ ++ sethi %hi( C_LABEL(ram_size) ), %o0 ++ st %g3, [%o0 + %lo( C_LABEL(ram_size) )] ++ ++ mov 2, %g1 ++ wr %g1, 0x0, %wim ! make window 1 invalid ++ WRITE_PAUSE ++ ++#if 0 ++ wr %g0, 0x0, %wim ++ WRITE_PAUSE ++ save ++ rd %psr, %g3 ++ restore ++ and %g3, PSR_CWP, %g3 ++ add %g3, 0x1, %g3 ++#else ++ or %g0, 8, %g3 ++#endif ++ ++#if 0 ++ sethi %hi( C_LABEL(cputyp) ), %o0 ++ st %g7, [%o0 + %lo( C_LABEL(cputyp) )] ++ ++ sethi %hi( C_LABEL(nwindows) ), %g4 ++ st %g3, [%g4 + %lo( C_LABEL(nwindows) )] ++ ++ sub %g3, 0x1, %g3 ++ sethi %hi( C_LABEL(nwindowsm1) ), %g4 ++ st %g3, [%g4 + %lo( C_LABEL(nwindowsm1) )] ++#endif ++ ++ /* Here we go, start using Linux's trap table... */ ++ set C_LABEL(trapbase), %g3 ++ wr %g3, 0x0, %tbr ++ WRITE_PAUSE ++ ++ /* Finally, turn on traps so that we can call c-code. */ ++ rd %psr, %g3 ++ wr %g3, 0x0, %psr ++ WRITE_PAUSE ++ ++ wr %g3, PSR_ET, %psr ++ WRITE_PAUSE ++ ++ .globl prolmain ++ call C_LABEL(prolmain) ++ nop ++ ++3: ++ b 3b ++ nop ++ ++/* ++ * Memory access trap handler ++ * %l0 program %psr from trap table entry ++ * %l1 program %pc from hardware ++ * %l2 program %npc from hardware ++ * %l3 program %wim from trap table entry ++ * %l4 ++ * %l5 ++ * %l6 ++ * %l7 text flag from trap table entry ++ */ ++ ++ .section ".text" ++ .globl srmmu_fault ++C_LABEL(srmmu_fault): ++ ++ set AC_M_SFAR, %l6 ++ set AC_M_SFSR, %l5 ++ lda [%l6] ASI_M_MMUREGS, %l6 ++ lda [%l5] ASI_M_MMUREGS, %l5 ++ ++ set ignore_fault, %l5 ++ ld [%l5], %l5 ++ subcc %l5, %g0, %g0 /* NULL pointer trap faults always */ ++ be 3f ++ nop ++ subcc %l5, %l6, %g0 ++ be 2f ++ nop ++3: ++ ++ set (PHYS_JJ_TCX_FB + 0xbf0), %g5 /* 2 cells from side */ ++ set 0x00ffffff, %g4 ++ sta %g4, [%g5] ASI_M_BYPASS ++ add %g5, 8, %g5 /* On right side */ ++ sta %g4, [%g5] ASI_M_BYPASS ++1: ba 1b; nop ++ ++2: ++ set C_LABEL(fault_ignored), %l5 ++ mov 1, %l6 ++ st %l6, [%l5] ++ ++ /* ++ * Skip the faulting instruction. ++ * I think it works when next instruction is a branch even. ++ */ ++ or %l2, 0, %l1 ++ add %l2, 4, %l2 ++ ++ wr %l0, 0, %psr ++ WRITE_PAUSE ++ jmp %l1 ++ rett %l2 ++ ++/* ++ * Slow external versions of st_bypass and ld_bypass. ++ * rconsole.c uses inlines. We call these in places which are not speed ++ * critical, to avoid compiler bugs. ++ */ ++ .globl C_LABEL(st_bypass) ++C_LABEL(st_bypass): ++ retl ++ sta %o1, [%o0] ASI_M_BYPASS ++ .globl C_LABEL(ld_bypass) ++C_LABEL(ld_bypass): ++ retl ++ lda [%o0] ASI_M_BYPASS, %o0 ++ .globl C_LABEL(sth_bypass) ++C_LABEL(sth_bypass): ++ retl ++ stha %o1, [%o0] ASI_M_BYPASS ++ .globl C_LABEL(ldh_bypass) ++C_LABEL(ldh_bypass): ++ retl ++ lduha [%o0] ASI_M_BYPASS, %o0 ++ .globl C_LABEL(stb_bypass) ++C_LABEL(stb_bypass): ++ retl ++ stba %o1, [%o0] ASI_M_BYPASS ++ .globl C_LABEL(ldb_bypass) ++C_LABEL(ldb_bypass): ++ retl ++ lduba [%o0] ASI_M_BYPASS, %o0 +diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c +--- proll_18.orig/qemu/main.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/qemu/main.c 2004-11-23 19:05:34.000000000 +0000 +@@ -0,0 +1,178 @@ ++/** ++ ** Proll (PROM replacement) ++ ** Copyright 1999 Pete Zaitcev ++ ** This code is licensed under GNU General Public License. ++ **/ ++#include ++ ++// #include ++#include ++#include "pgtsrmmu.h" ++#include "iommu.h" /* Typical SBus IOMMU for sun4m */ ++#include "phys_jj.h" ++#include "vconsole.h" ++#include "version.h" ++#include /* __P() */ ++#include /* init_net() */ ++#include /* we are a provider for part of this. */ ++#include /* myipaddr */ ++#include ++#include /* our own prototypes */ ++ ++static void init_idprom(void); ++static void makepages_q(struct phym *t, unsigned int highbase); ++ ++struct vconterm dp0; ++struct mem cmem; /* Current memory, virtual */ ++struct mem cio; /* Current I/O space */ ++struct phym pmem; /* Current phys. mem. */ ++struct iommu ciommu; /* Our IOMMU on sun4m */ ++ ++static char *hw_idprom; ++int ignore_fault, fault_ignored, ram_size; ++ ++/* ++ */ ++void prolmain() ++{ ++ //static const char fname[14] = "00000000.PROL"; ++ static struct banks bb; ++ unsigned int hiphybas; ++ const void *romvec; ++ ++ vcon_init(&dp0, PHYS_JJ_TCX_FB); ++ printk("PROLL %s QEMU\n", PROLL_VERSION_STRING); ++ printk("%d MB total\n", ram_size/(1024*1024)); ++ ++ bb.nbanks = 1; ++ bb.bankv[0].start = 0; ++ bb.bankv[0].length = ram_size; ++ ++ hiphybas = ram_size - PROLSIZE; ++ ++ mem_init(&cmem, (char *) &_end, (char *)(PROLBASE+PROLSIZE)); ++ makepages_q(&pmem, hiphybas); ++ init_mmu_swift((unsigned int)pmem.pctp - PROLBASE + hiphybas); ++ ++ mem_init(&cio, (char *)(PROLBASE+PROLSIZE), ++ (char *)(PROLBASE+PROLSIZE+IOMAPSIZE)); ++ ++ iommu_init(&ciommu, hiphybas); ++ ++ /* ++ */ ++ init_idprom(); ++ sched_init(); ++ le_probe(); ++ init_net(); ++ ++#if 0 ++#if 0 /* RARP */ ++ if (rarp() != 0) fatal(); ++ /* printrarp(); */ ++ xtoa(myipaddr, fname, 8); ++ if (load(servaddr, fname) != 0) fatal(); ++#else ++ if (bootp() != 0) fatal(); ++ /* ++ * boot_rec.bp_file cannot be used because system PROM ++ * uses it to locate ourselves. If we load from boot_rec.bp_file, ++ * we will loop reloading PROLL over and over again. ++ * Thus we use traditional PROLL scheme HEXIPADDR.PROL (single L). ++ */ ++ xtoa(myipaddr, fname, 8); ++ if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); ++#endif ++#endif ++ ++ romvec = init_openprom(bb.nbanks, bb.bankv, hiphybas); ++ ++ printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n", ++ PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024, ++ (int)cio.start, (int)cio.curp); ++ //set_timeout(5); while (!chk_timeout()) { } /* P3: let me read */ ++ ++ { ++ void (*entry)(const void *, int, int, int, int) = (void (*)(const void*, int, int, int, int)) LOADBASE; ++ entry(romvec, 0, 0, 0, 0); ++ } ++ ++ mem_fini(&cmem); ++ vcon_fini(&dp0); ++} ++ ++/* ++ * dvma_alloc over iommu_alloc. ++ */ ++void *dvma_alloc(int size, unsigned int *pphys) ++{ ++ return iommu_alloc(&ciommu, size, pphys); ++} ++ ++/* ++ */ ++void udelay(unsigned long usecs) ++{ ++ int i, n; ++ n = usecs*50; ++ for (i = 0; i < n; i++) { } ++} ++ ++static void init_idprom() ++{ ++ char *va_prom; ++ ++ if ((va_prom = map_io(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE)) == NULL) { ++ printk("init_idprom: cannot map eeprom\n"); ++ fatal(); ++ } ++ bcopy(va_prom + PHYS_JJ_IDPROM_OFF, idprom, IDPROM_SIZE); ++ /* ++ * hw_idprom is not used anywhere. ++ * It's just as we hate to leave hanging pointers (I/O page here). ++ */ ++ hw_idprom = va_prom; ++} ++ ++/* ++ * Make CPU page tables. ++ * Returns pointer to context table. ++ * Here we ignore memory allocation errors which "should not happen" ++ * because we cannot print anything anyways if memory initialization fails. ++ */ ++void makepages_q(struct phym *t, unsigned int highbase) ++{ ++ unsigned int *ctp, *l1, pte; ++ int i; ++ unsigned int pa, va; ++ ++ ctp = mem_zalloc(&cmem, NCTX_SWIFT*sizeof(int), NCTX_SWIFT*sizeof(int)); ++ l1 = mem_zalloc(&cmem, 256*sizeof(int), 256*sizeof(int)); ++ ++ pte = SRMMU_ET_PTD | (((unsigned int)l1 - PROLBASE + highbase) >> 4); ++ for (i = 0; i < NCTX_SWIFT; i++) { ++ ctp[i] = pte; ++ } ++ ++ pa = PROLBASE; ++ for (va = PROLBASE; va < PROLDATA; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } ++ pa = highbase + PROLDATA - PROLBASE; ++ for (va = PROLDATA; va < PROLBASE + PROLSIZE; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } ++ ++ /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ ++ pa = 0; ++ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } ++ ++ t->pctp = ctp; ++ t->pl1 = l1; ++ t->pbas = highbase; ++} +diff -ruN proll_18.orig/qemu/Makefile proll-patch4/qemu/Makefile +--- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/qemu/Makefile 2004-11-13 15:50:49.000000000 +0000 +@@ -0,0 +1,119 @@ ++# ++# proll: ++# qemu/Makefile - make PROLL for QEMU ++# $Id: proll.patch,v 1.2 2004-12-19 23:18:01 bellard Exp $ ++# ++# Copyright 1999 Pete Zaitcev ++# This is Free Software is licensed under terms of GNU General Public License. ++# ++ ++CC = gcc ++ ++#CROSS = /usr/local/sparc/bin/sparc-sun-linux- ++CROSS = sparc-unknown-linux-gnu- ++ ++CROSSCC = $(CROSS)gcc ++CROSSLD = $(CROSS)ld ++CROSSNM = $(CROSS)nm ++ ++RM = /bin/rm -f ++ELFTOAOUT = elftoaout ++ ++# ++SRC = ../src ++ ++# Due to remapping algorithm PROLBASE should be algned on PMD. ++# We make PROLBASE a define instead of using _start because we ++# want to shift it to form a PGD entry. A relocatable label will not work. ++# Linux kernel expects us to be at LINUX_OPPROM_BEGVM . ++PROLBASE = 0xffd00000 ++PROLRODATA = 0xffd07000 ++PROLDATA = 0xffd09000 ++PROLSIZE = (240*1024) ++ ++# Linux ++# Fixed %g6 is for arch/sparc/kernel/head.S, it seems ok w/o -ffixed-g6. ++# Kernel uses -fcall-used-g5 -fcall-used-g7, we probably do not need them. ++# __ANSI__ is supposed to be on by default but it is not. ++CFLAGS = -O2 -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -g ++ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g ++# Solaris or Linux/i386 cross compilation ++#CFLAGS = -Iinclude -O ++ ++LDFLAGS = -N -Ttext $(PROLBASE) --section-start .rodata=$(PROLRODATA) -Tdata $(PROLDATA) -Tbss $(PROLDATA) ++ ++ALL = proll.aout ++PROLLEXE = proll.elf ++ ++OBJS = head.o wuf.o wof.o main.o vconsole.o hconsole.o rconsole.o \ ++ printf.o le.o system.o iommu.o \ ++ arp.o netinit.o bootp.o packet.o tftp.o udp.o sched_4m.o openprom.o ++ ++all: $(ALL) ++ ++$(PROLLEXE): $(OBJS) ++ $(CROSSLD) $(LDFLAGS) -o $(PROLLEXE) $(OBJS) ++ ++head.o: head.S $(SRC)/phys_jj.h \ ++ $(SRC)/asi.h $(SRC)/psr.h $(SRC)/crs.h ++ $(CROSSCC) $(ASFLAGS) -DPROLBASE=$(PROLBASE) -o $*.o -c $*.S ++ ++main.o: main.c $(SRC)/asi.h $(SRC)/pgtsrmmu.h $(SRC)/iommu.h \ ++ $(SRC)/phys_jj.h $(SRC)/vconsole.h $(SRC)/version.h $(SRC)/general.h \ ++ $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h ++ $(CROSSCC) $(CFLAGS) -c $*.c ++openprom.o: openprom.c $(SRC)/openprom.h $(SRC)/general.h $(SRC)/romlib.h \ ++ $(SRC)/vconsole.h $(SRC)/system.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $*.c ++ ++system.o: $(SRC)/system.c $(SRC)/vconsole.h $(SRC)/pgtsrmmu.h \ ++ $(SRC)/timer.h $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/asi.h \ ++ $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h $(SRC)/crs.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++iommu.o: $(SRC)/iommu.c $(SRC)/pgtsrmmu.h $(SRC)/phys_jj.h $(SRC)/iommu.h \ ++ $(SRC)/vconsole.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/asi.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++vconsole.o: $(SRC)/vconsole.c $(SRC)/vconsole.h $(SRC)/hconsole.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++hconsole.o: $(SRC)/hconsole.c $(SRC)/hconsole.h $(SRC)/rconsole.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++rconsole.o: $(SRC)/rconsole.c $(SRC)/rconsole.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++printf.o: $(SRC)/printf.c ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++le.o: $(SRC)/le.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/netpriv.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/net.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++ ++arp.o: $(SRC)/arp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++netinit.o: $(SRC)/netinit.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++tftp.o: $(SRC)/tftp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/tftp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++udp.o: $(SRC)/udp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++packet.o: $(SRC)/packet.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++sched_4m.o: $(SRC)/sched_4m.c $(SRC)/system.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++bootp.o: $(SRC)/bootp.c $(SRC)/general.h $(SRC)/net.h \ ++ $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/bootp.h ++ $(CROSSCC) $(CFLAGS) -DNOBPEXT=1 -c $(SRC)/$*.c ++ ++wuf.o: $(SRC)/wuf.S ++ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S ++wof.o: $(SRC)/wof.S ++ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S ++ ++#genlab.o: genlab.c ++# $(CC) -c $*.c ++# ++#genlab: genlab.o ++# $(CC) -o genlab genlab.o ++ ++clean: ++ $(RM) $(OBJS) ++ $(RM) $(PROLLEXE) proll.aout ++ ++proll.aout: $(PROLLEXE) ++ $(ELFTOAOUT) -o proll.aout $(PROLLEXE) +diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c +--- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/qemu/openprom.c 2004-11-23 19:14:05.000000000 +0000 +@@ -0,0 +1,596 @@ ++/* ++ * PROM interface support ++ * Copyright 1996 The Australian National University. ++ * Copyright 1996 Fujitsu Laboratories Limited ++ * Copyright 1999 Pete A. Zaitcev ++ * This software may be distributed under the terms of the Gnu ++ * Public License version 2 or later ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "phys_jj.h" ++ ++struct property { ++ const char *name; ++ const char *value; ++ const int length; ++}; ++ ++struct node { ++ const struct property *properties; ++ /* short */ const int sibling; ++ /* short */ const int child; ++}; ++ ++static int obp_nextnode(int node); ++static int obp_child(int node); ++static int obp_proplen(int node, char *name); ++static int obp_getprop(int node, char *name, char *val); ++static int obp_setprop(int node, char *name, char *val, int len); ++static const char *obp_nextprop(int node, char *name); ++ ++static char obp_idprom[IDPROM_SIZE]; ++static const struct property null_properties = { NULL, NULL, -1 }; ++static const int prop_true = -1; ++ ++static const struct property propv_root[] = { ++ {"name", "SUNW,JavaStation-1", sizeof("SUNW,JavaStation-1") }, ++ {"idprom", obp_idprom, IDPROM_SIZE}, ++ {"banner-name", "JavaStation", sizeof("JavaStation")}, ++ {"compatible", "sun4m", 6}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_iommu_reg[] = { ++ 0x0, 0x10000000, 0x00000300, ++}; ++static const struct property propv_iommu[] = { ++ {"name", "iommu", sizeof("iommu")}, ++ {"reg", (char*)&prop_iommu_reg[0], sizeof(prop_iommu_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_sbus_ranges[] = { ++ 0x0, 0x0, 0x0, 0x30000000, 0x10000000, ++ 0x1, 0x0, 0x0, 0x40000000, 0x10000000, ++ 0x2, 0x0, 0x0, 0x50000000, 0x10000000, ++ 0x3, 0x0, 0x0, 0x60000000, 0x10000000, ++ 0x4, 0x0, 0x0, 0x70000000, 0x10000000, ++}; ++static const struct property propv_sbus[] = { ++ {"name", "sbus", 5}, ++ {"ranges", (char*)&prop_sbus_ranges[0], sizeof(prop_sbus_ranges)}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_tcx_regs[] = { ++ 0x2, 0x00800000, 0x00100000, ++ 0x2, 0x02000000, 0x00000001, ++ 0x2, 0x04000000, 0x00800000, ++ 0x2, 0x06000000, 0x00800000, ++ 0x2, 0x0a000000, 0x00000001, ++ 0x2, 0x0c000000, 0x00000001, ++ 0x2, 0x0e000000, 0x00000001, ++ 0x2, 0x00700000, 0x00001000, ++ 0x2, 0x00200000, 0x00000004, ++ 0x2, 0x00300000, 0x0000081c, ++ 0x2, 0x00000000, 0x00010000, ++ 0x2, 0x00240000, 0x00000004, ++ 0x2, 0x00280000, 0x00000001, ++}; ++ ++#if 1 /* Zaitcev */ ++static const int pixfreq = 0x03dfd240; ++static const int hbporch = 0xa0; ++static const int vfreq = 0x3c; ++#endif ++#if 0 /* Kevin Boone - 70Hz refresh */ ++static const int pixfreq = 0x047868C0; ++static const int hbporch = 0x90; ++static const int vfreq = 0x46; ++#endif ++ ++static const int vbporch = 0x1d; ++static const int vsync = 0x6; ++static const int hsync = 0x88; ++static const int vfporch = 0x3; ++static const int hfporch = 0x18; ++static const int height = 0x300; ++static const int width = 0x400; ++static const int linebytes = 0x400; ++static const int depth = 8; ++static const int tcx_intr[] = { 5, 0 }; ++static const int tcx_interrupts = 5; ++static const struct property propv_sbus_tcx[] = { ++ {"name", "SUNW,tcx", sizeof("SUNW,tcx")}, ++ {"vbporch", (char*)&vbporch, sizeof(int)}, ++ {"hbporch", (char*)&hbporch, sizeof(int)}, ++ {"vsync", (char*)&vsync, sizeof(int)}, ++ {"hsync", (char*)&hsync, sizeof(int)}, ++ {"vfporch", (char*)&vfporch, sizeof(int)}, ++ {"hfporch", (char*)&hfporch, sizeof(int)}, ++ {"pixfreq", (char*)&pixfreq, sizeof(int)}, ++ {"vfreq", (char*)&vfreq, sizeof(int)}, ++ {"height", (char*)&height, sizeof(int)}, ++ {"width", (char*)&width, sizeof(int)}, ++ {"linebytes", (char*)&linebytes, sizeof(int)}, ++ {"depth", (char*)&depth, sizeof(int)}, ++ {"reg", (char*)&prop_tcx_regs[0], sizeof(prop_tcx_regs)}, ++ {"tcx-8-bit", (char*)&prop_true, 0}, ++ {"intr", (char*)&tcx_intr[0], sizeof(tcx_intr)}, ++ {"interrupts", (char*)&tcx_interrupts, sizeof(tcx_interrupts)}, ++ {"device_type", "display", sizeof("display")}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_cs4231_reg[] = { ++ 0x3, 0x0C000000, 0x00000040 ++}; ++static const int cs4231_interrupts = 5; ++static const int cs4231_intr[] = { 5, 0 }; ++ ++static const struct property propv_sbus_cs4231[] = { ++ {"name", "SUNW,CS4231", sizeof("SUNW,CS4231") }, ++ {"intr", (char*)&cs4231_intr[0], sizeof(cs4231_intr) }, ++ {"interrupts", (char*)&cs4231_interrupts, sizeof(cs4231_interrupts) }, ++ {"reg", (char*)&prop_cs4231_reg[0], sizeof(prop_cs4231_reg) }, ++ {"device_type", "serial", sizeof("serial") }, ++ {"alias", "audio", sizeof("audio") }, ++ {NULL, NULL, -1} ++}; ++ ++static const int cpu_nctx = NCTX_SWIFT; ++static const int cpu_cache_line_size = 0x20; ++static const int cpu_cache_nlines = 0x200; ++static const struct property propv_cpu[] = { ++ {"name", "STP1012PGA", sizeof("STP1012PGA") }, ++ {"device_type", "cpu", 4 }, ++ {"mmu-nctx", (char*)&cpu_nctx, sizeof(int)}, ++ {"cache-line-size", (char*)&cpu_cache_line_size, sizeof(int)}, ++ {"cache-nlines", (char*)&cpu_cache_nlines, sizeof(int)}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_obio_ranges[] = { ++ 0x0, 0x0, 0x0, 0x71000000, 0x01000000, ++}; ++static const struct property propv_obio[] = { ++ {"name", "obio", 5 }, ++ {"ranges", (char*)&prop_obio_ranges[0], sizeof(prop_obio_ranges) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_auxio_reg[] = { ++ 0x0, 0x00900000, 0x00000001, ++}; ++static const struct property propv_obio_auxio[] = { ++ {"name", "auxio", sizeof("auxio") }, ++ {"reg", (char*)&prop_auxio_reg[0], sizeof(prop_auxio_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_int_reg[] = { ++ 0x0, 0x00e00000, 0x00000010, ++ 0x0, 0x00e10000, 0x00000010, ++}; ++static const struct property propv_obio_int[] = { ++ {"name", "interrupt", sizeof("interrupt")}, ++ {"reg", (char*)&prop_int_reg[0], sizeof(prop_int_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_cnt_reg[] = { ++ 0x0, 0x00d00000, 0x00000010, ++ 0x0, 0x00d10000, 0x00000010, ++}; ++static const struct property propv_obio_cnt[] = { ++ {"name", "counter", sizeof("counter")}, ++ {"reg", (char*)&prop_cnt_reg[0], sizeof(prop_cnt_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_eeprom_reg[] = { ++ 0x0, 0x00200000, 0x00002000, ++}; ++static const struct property propv_obio_eep[] = { ++ {"name", "eeprom", sizeof("eeprom")}, ++ {"reg", (char*)&prop_eeprom_reg[0], sizeof(prop_eeprom_reg) }, ++ {"model", "mk48t08", sizeof("mk48t08")}, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_su_reg[] = { ++ 0x0, 0x003002f8, 0x00000008, ++}; ++static const struct property propv_obio_su[] = { ++ {"name", "su", sizeof("su")}, ++ {"reg", (char*)&prop_su_reg[0], sizeof(prop_su_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_zs_intr[] = { 0x26, 0x0 }; ++static const int prop_zs_reg[] = { ++ 0x4, 0x00000000, 0x0000000f, ++}; ++static const int prop_zs_slave[] = { 0x1 }; ++static const struct property propv_obio_zs[] = { ++ {"name", "zs", sizeof("zs")}, ++ {"reg", (char*)&prop_zs_reg[0], sizeof(prop_zs_reg) }, ++ {"reg", (char*)&prop_zs_slave[0], sizeof(prop_zs_slave) }, ++ {"device_type", "serial", sizeof("serial") }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_zs1_intr[] = { 0x26, 0x0 }; ++static const int prop_zs1_reg[] = { ++ 0x4, 0x00100000, 0x0000000f, ++}; ++static const int prop_zs1_slave[] = { 0x0 }; ++static const struct property propv_obio_zs1[] = { ++ {"name", "zs", sizeof("zs")}, ++ {"reg", (char*)&prop_zs1_reg[0], sizeof(prop_zs1_reg) }, ++ {"reg", (char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) }, ++ {"device_type", "serial", sizeof("serial") }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_ledma_reg[] = { ++ 0x4, 0x08400010, 0x00000020, ++}; ++static const int prop_ledma_burst = 0x3f; ++static const struct property propv_sbus_ledma[] = { ++ {"name", "ledma", sizeof("ledma")}, ++ {"reg", (char*)&prop_ledma_reg[0], sizeof(prop_ledma_reg) }, ++ {"burst-sizes", (char*)&prop_ledma_burst, sizeof(int) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_le_reg[] = { ++ 0x4, 0x08c00000, 0x00000004, ++}; ++static const int prop_le_busmaster_regval = 0x7; ++static const int prop_le_intr[] = { 0x26, 0x0 }; ++static const struct property propv_sbus_ledma_le[] = { ++ {"name", "le", sizeof("le")}, ++ {"reg", (char*)&prop_le_reg[0], sizeof(prop_le_reg) }, ++ {"busmaster-regval", (char*)&prop_le_busmaster_regval, sizeof(int)}, ++ {"intr", (char*)&prop_le_intr[0], sizeof(prop_le_intr) }, ++ {NULL, NULL, -1} ++}; ++ ++static const struct node nodes[] = { ++ { &null_properties, 1, 0 }, /* 0 = big brother of root */ ++ { propv_root, 0, 2 }, /* 1 "/" */ ++ { propv_iommu, 8, 3 }, /* 2 "/iommu" */ ++ { propv_sbus, 0, 4 }, /* 3 "/iommu/sbus" */ ++ { propv_sbus_tcx, 5, 0 }, /* 4 "/iommu/sbus/SUNW,tcx" */ ++ { propv_sbus_ledma, 7, 6 }, /* 5 "/iommu/sbus/ledma" */ ++ { propv_sbus_ledma_le, 0, 0 }, /* 6 "/iommu/sbus/ledma/le" */ ++ { propv_sbus_cs4231, 0, 0 }, /* 7 "/iommu/sbus/SUNW,CS4231 */ ++ { propv_cpu, 9, 0 }, /* 8 "/STP1012PGA" */ ++ { propv_obio, 0, 10 }, /* 9 "/obio" */ ++ { propv_obio_int, 11, 0 }, /* 10 "/obio/interrupt" */ ++ { propv_obio_cnt, 12, 0 }, /* 11 "/obio/counter" */ ++ { propv_obio_eep, 13, 0 }, /* 12 "/obio/eeprom" */ ++ { propv_obio_su, 14, 0 }, /* 13 "/obio/su" */ ++ { propv_obio_auxio, 0, 0 }, /* 14 "/obio/auxio" */ ++ { propv_obio_zs, 0, 0 }, /* 14 "/obio/zs@0,0" */ ++ { propv_obio_zs1, 0, 0 }, /* 14 "/obio/zs@0,100000" */ ++}; ++ ++static struct linux_mlist_v0 totphys[MAX_BANKS]; ++static struct linux_mlist_v0 totmap[1]; ++static struct linux_mlist_v0 totavail[MAX_BANKS]; ++ ++static struct linux_mlist_v0 *ptphys; ++static struct linux_mlist_v0 *ptmap; ++static struct linux_mlist_v0 *ptavail; ++ ++static const struct linux_nodeops nodeops0 = { ++ obp_nextnode, /* int (*no_nextnode)(int node); */ ++ obp_child, /* int (*no_child)(int node); */ ++ obp_proplen, /* int (*no_proplen)(int node, char *name); */ ++ obp_getprop, /* int (*no_getprop)(int node,char *name,char *val); */ ++ obp_setprop, /* int (*no_setprop)(int node, char *name, ++ char *val, int len); */ ++ obp_nextprop /* char * (*no_nextprop)(int node, char *name); */ ++}; ++ ++static const char arg_nfsroot[] = "console=ttyS0 ip=bootp root=nfs"; ++ ++static const struct linux_arguments_v0 obp_arg = { ++ { "le()", arg_nfsroot, NULL, NULL, NULL, NULL, NULL, NULL }, ++ { "" }, ++ { 'l', 'e' }, 0, 0, 0, NULL, ++ NULL ++}; ++static const struct linux_arguments_v0 * const obp_argp = &obp_arg; ++ ++static const void * const synch_hook = NULL; ++#if 0 ++static const char obp_stdin = PROMDEV_KBD; ++static const char obp_stdout = PROMDEV_SCREEN; ++#else ++static const char obp_stdin = PROMDEV_TTYA; ++static const char obp_stdout = PROMDEV_TTYA; ++#endif ++ ++static int obp_nbgetchar(void); ++static int obp_nbputchar(int ch); ++static void obp_reboot(char *); ++static void obp_abort(void); ++static void obp_halt(void); ++static int obp_devopen(char *str); ++static int obp_devclose(int dev_desc); ++static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf); ++ ++static void doublewalk(unsigned ptab1, unsigned va) ++{ ++unsigned int proc_tablewalk(int ctx, unsigned int va); ++unsigned int mem_tablewalk(unsigned int pa, unsigned int va); ++ ++ proc_tablewalk(0, va); ++ if (ptab1 != 0) mem_tablewalk(ptab1, va); ++} ++ +#ifdef ORIG - #if 0 /* RARP */ - if (rarp() != 0) fatal(); - /* printrarp(); */ -@@ -117,13 +118,20 @@ - xtoa(myipaddr, fname, 8); - if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); ++static const struct linux_romvec romvec0 = { ++ LINUX_OPPROM_MAGIC, /* pv_magic_cookie */ ++ 0, /* pv_romvers - Format selector! */ ++ 77, /* pv_plugin_revision */ ++ 0x10203, /* pv_printrev */ ++ { /* pv_v0mem */ ++ &ptphys, /* v0_totphys */ ++ &ptmap, /* v0_prommap */ ++ &ptavail /* v0_available */ ++ }, ++ &nodeops0, /* struct linux_nodeops *pv_nodeops; */ ++ (void*)doublewalk, /* P3 */ /* char **pv_bootstr; */ ++ { /* struct linux_dev_v0_funcs pv_v0devops; */ ++ &obp_devopen, /* v0_devopen */ ++ &obp_devclose, /* v0_devclose */ ++ &obp_rdblkdev, /* v0_rdblkdev */ ++ NULL, /* v0_wrblkdev */ ++ NULL, /* v0_wrnetdev */ ++ NULL, /* v0_rdnetdev */ ++ NULL, /* v0_rdchardev */ ++ NULL, /* v0_wrchardev */ ++ NULL /* v0_seekdev */ ++ }, ++ &obp_stdin, /* char *pv_stdin */ ++ &obp_stdout, /* char *pv_stdout; */ ++ obp_nbgetchar, /* int (*pv_getchar)(void); */ ++ obp_nbputchar, /* void (*pv_putchar)(int ch); */ ++ obp_nbgetchar, /* int (*pv_nbgetchar)(void); */ ++ obp_nbputchar, /* int (*pv_nbputchar)(int ch); */ ++ NULL, /* void (*pv_putstr)(char *str, int len); */ ++ obp_reboot, /* void (*pv_reboot)(char *bootstr); */ ++ NULL, /* void (*pv_printf)(__const__ char *fmt, ...); */ ++ obp_abort, /* void (*pv_abort)(void); */ ++ NULL, /* __volatile__ int *pv_ticks; */ ++ obp_halt, /* void (*pv_halt)(void); */ ++ (void *)&synch_hook, /* void (**pv_synchook)(void); */ ++ ++#if 0 ++ /* Evaluate a forth string, not different proto for V0 and V2->up. */ ++ union { ++ void (*v0_eval)(int len, char *str); ++ void (*v2_eval)(char *str); ++ } pv_fortheval; ++#endif ++ { 0 }, /* pv_fortheval */ ++ ++ &obp_argp, /* struct linux_arguments_v0 **pv_v0bootargs; */ ++ NULL, /* pv_enaddr */ ++ { /* pv_v2bootargs */ ++ NULL, /* char **bootpath; */ ++ NULL, /* char **bootargs; */ ++ NULL, /* fd_stdin; */ ++ NULL, /* fd_stdout */ ++ }, ++ { /* pv_v2devops */ ++ NULL, /* v2_inst2pkg */ ++ NULL, /* v2_dumb_mem_alloc */ ++ NULL, /* v2_dumb_mem_free */ ++ NULL, /* v2_dumb_mmap */ ++ NULL, /* v2_dumb_munmap */ ++ NULL, /* v2_dev_open */ ++ NULL, /* v2_dev_close */ ++ NULL, /* v2_dev_read */ ++ NULL, /* v2_dev_write */ ++ NULL, /* v2_dev_seek */ ++ NULL, /* v2_wheee2 */ ++ NULL, /* v2_wheee3 */ ++ }, ++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* filler[15] */ ++ NULL, /* pv_setctxt */ ++ NULL, /* v3_cpustart */ ++ NULL, /* v3_cpustop */ ++ NULL, /* v3_cpuidle */ ++ NULL /* v3_cpuresume */ ++}; ++#endif ++ ++static struct linux_romvec romvec0; ++ ++void * ++init_openprom(int bankc, struct bank *bankv, unsigned hiphybas) ++{ ++ int i; ++ ++ /* ++ * Avoid data segment allocations ++ */ ++ ptphys = totphys; ++ ptmap = totmap; ++ ptavail = totavail; ++ /* ++ * Form memory descriptors. ++ */ ++ for (i = 0; i < bankc; i++) { ++ totphys[i].theres_more = &totphys[i+1]; ++ totphys[i].start_adr = (char*) bankv[i].start; ++ totphys[i].num_bytes = bankv[i].length; ++ } ++ totphys[i-1].theres_more = 0; ++ ++ /* ++ * XXX Merged in normal PROM when full banks touch. ++ */ ++ for (i = 0; i < bankc; i++) { ++ unsigned bankbase = bankv[i].start; ++ unsigned banksize = bankv[i].length; ++ if (hiphybas > bankbase && ++ hiphybas < bankbase + banksize) { ++ banksize = hiphybas - bankbase; ++ } ++ totavail[i].theres_more = &totavail[i+1]; ++ totavail[i].start_adr = (char*) bankbase; ++ totavail[i].num_bytes = banksize; ++ } ++ totavail[i-1].theres_more = 0; ++ ++ totmap[0].theres_more = 0; ++ totmap[0].start_adr = (char*) PROLBASE; ++ totmap[0].num_bytes = PROLSIZE; ++ ++ /* ++ * idprom ++ */ ++ bcopy(idprom, obp_idprom, IDPROM_SIZE); ++ ++ // Linux wants a R/W romvec table ++ romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; ++ romvec0.pv_plugin_revision = 77; ++ romvec0.pv_printrev = 0x10203; ++ romvec0.pv_v0mem.v0_totphys = &ptphys; ++ romvec0.pv_v0mem.v0_prommap = &ptmap; ++ romvec0.pv_v0mem.v0_available = &ptavail; ++ romvec0.pv_nodeops = &nodeops0; ++ romvec0.pv_bootstr = (void *)doublewalk; ++ romvec0.pv_stdin = &obp_stdin; ++ romvec0.pv_stdout = &obp_stdout; ++ romvec0.pv_getchar = obp_nbgetchar; ++ romvec0.pv_putchar = obp_nbputchar; ++ romvec0.pv_nbgetchar = obp_nbgetchar; ++ romvec0.pv_nbputchar = obp_nbputchar; ++ romvec0.pv_reboot = obp_reboot; ++ romvec0.pv_abort = obp_abort; ++ romvec0.pv_halt = obp_halt; ++ romvec0.pv_synchook = &synch_hook; ++ romvec0.pv_v0bootargs = &obp_argp; ++ return &romvec0; ++} ++ ++static const struct property *find_property(int node,char *name) ++{ ++ const struct property *prop = &nodes[node].properties[0]; ++ while (prop && prop->name) { ++ if (bcmp(prop->name, name, 128) == 0) return prop; ++ prop++; ++ } ++ return NULL; ++} ++ ++static int obp_nextnode(int node) ++{ ++ return nodes[node].sibling; ++} ++ ++static int obp_child(int node) ++{ ++ return nodes[node].child; ++} ++ ++static int obp_proplen(int node, char *name) ++{ ++ const struct property *prop = find_property(node,name); ++ if (prop) return prop->length; ++ return -1; ++} ++ ++static int obp_getprop(int node, char *name, char *value) ++{ ++ const struct property *prop; ++ ++ prop = find_property(node,name); ++ if (prop) { ++ memcpy(value,prop->value,prop->length); ++ //printk("obp_getprop '%s'= %s\n", name, value); ++ return prop->length; ++ } ++ //printk("obp_getprop: not found\n"); ++ return -1; ++} ++ ++static int obp_setprop(int node, char *name, char *value, int len) ++{ ++ return -1; ++} ++ ++static const char *obp_nextprop(int node,char *name) ++{ ++ const struct property *prop = find_property(node,name); ++ if (prop) return prop[1].name; ++ return NULL; ++} ++ ++#if 0 ++static unsigned char calc_idprom_cksum(struct idprom *idprom) ++{ ++ unsigned char cksum, i, *ptr = (unsigned char *)idprom; ++ ++ for (i = cksum = 0; i <= 0x0E; i++) ++ cksum ^= *ptr++; ++ ++ return cksum; ++} ++#endif ++ ++static int obp_nbgetchar(void) { ++ return -1; ++} ++ ++static int obp_nbputchar(int ch) { ++ extern struct vconterm dp0; ++ char buf = ch; ++ ++ /* We do not use printk() in order to reduce stack depth. */ ++ vcon_write(&dp0, &buf, 1); ++ return 0; ++} ++ ++static void obp_reboot(char *str) { ++ printk("rebooting (%s): not implemented, freezing\n", str); ++ for (;;) {} ++} ++ ++static void obp_abort() { ++ printk("abort, freezing\n"); ++ for (;;) {} ++} ++ ++static void obp_halt() { ++ printk("halt, freezing\n"); ++ for (;;) {} ++} ++ ++static int obp_devopen(char *str) { ++ //printk("open %s\n", str); ++ return 0; ++} ++ ++static int obp_devclose(int dev_desc) { ++ //printk("close %d\n", dev_desc); ++ return 0; ++} ++ ++static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf) { ++ //printk("rdblkdev: fd %d, num_blks %d, blk_st %d, buf 0x%x\n", dev_desc, num_blks, blk_st, buf); ++ //buf[8] = 'L'; ++ return num_blks; ++} +diff -ruN proll_18.orig/src/arp.c proll-patch4/src/arp.c +--- proll_18.orig/src/arp.c 2001-12-24 05:12:31.000000000 +0000 ++++ proll-patch4/src/arp.c 2004-11-13 15:50:49.000000000 +0000 +@@ -45,7 +45,7 @@ + #endif + static struct arp_cache arp_list[ARPNUM]; /* ARP address cache */ + static int next_arp; /* next table entry */ +-static t_ipaddr def_gw = IP_ANY; /* default routing */ ++static t_ipaddr def_gw; /* default routing */ + + + +@@ -144,7 +144,7 @@ + * + * Resolve IP address and return pointer to hardware address. + */ +-unsigned char *ip_resolve(ip) ++const unsigned char *ip_resolve(ip) + t_ipaddr ip; + { + int i; +@@ -230,14 +230,11 @@ + */ + int init_arp() + { +- /* Set name of module for error messages */ +- net_module_name = "arp"; +- + #ifndef NOARP + /* Register ARP packet type and set send buffer pointer */ + if ((arpbuf = (struct arphdr *)reg_type(htons(ETH_P_ARP), arp_recv)) == NULL) + return(FALSE); #endif +- ++ def_gw = IP_ANY; + return(TRUE); + } +diff -ruN proll_18.orig/src/arp.h proll-patch4/src/arp.h +--- proll_18.orig/src/arp.h 1999-03-18 03:39:43.000000000 +0000 ++++ proll-patch4/src/arp.h 2004-11-13 15:50:49.000000000 +0000 +@@ -104,7 +104,7 @@ + extern int init_arp __P((void)); + + /* Resolve IP address and return pointer to hardware address */ +-extern unsigned char *ip_resolve __P((t_ipaddr ip)); ++extern const unsigned char *ip_resolve __P((t_ipaddr ip)); + + /* Add a new antry to the ARP cache */ + extern void addcache __P((unsigned char *ha, t_ipaddr ip)); +diff -ruN proll_18.orig/src/hconsole.c proll-patch4/src/hconsole.c +--- proll_18.orig/src/hconsole.c 2002-07-23 05:52:48.000000000 +0000 ++++ proll-patch4/src/hconsole.c 2004-11-13 15:50:49.000000000 +0000 +@@ -42,7 +42,11 @@ + * No probing sequence or argument passing, hardcode everything. XXX + */ + raster8_cons_a(q, 768, 1024, (char *)a0); ++#if 1 + raster_cons_2(r, q, 768-(24*11)-1, 1024-(8*80)-1, (24*11), (8*80)); ++#else ++ raster_cons_2(r, q, 0, 0, 768, 1024); +#endif + t->r_ = r; + t->r0_ = q; + t->f_ = &f_master; +diff -ruN proll_18.orig/src/lat7_2.bm proll-patch4/src/lat7_2.bm +--- proll_18.orig/src/lat7_2.bm 1999-02-27 05:48:54.000000000 +0000 ++++ proll-patch4/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 +@@ -1,6 +1,6 @@ + #define lat7_2_width 128 + #define lat7_2_height 88 +-static unsigned char lat7_2_bits[] = { ++static unsigned const char lat7_2_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18, + 0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02, +diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch4/src/lat7_2_swapped.bm +--- proll_18.orig/src/lat7_2_swapped.bm 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 +@@ -0,0 +1,121 @@ ++#define lat7_2_width 128 ++#define lat7_2_height 88 ++static unsigned const char lat7_2_bits[] = { ++ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x00, 0x48, ++ 0x48, 0x78, 0x48, 0x5f, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x78, 0x40, ++ 0x70, 0x40, 0x4f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x30, 0x40, 0x40, ++ 0x40, 0x3e, 0x09, 0x0e, 0x0a, 0x09, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, ++ 0x7f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x0e, 0x0a, 0x0e, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, ++ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x44, 0x64, 0x54, 0x4c, 0x54, 0x10, 0x10, ++ 0x10, 0x1f, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x1f, 0x04, 0x04, 0x04, ++ 0x04, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, ++ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0xff, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, ++ 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, ++ 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, ++ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, ++ 0x06, 0x0c, 0x18, 0x30, 0x18, 0x6c, 0x36, 0x18, 0x0c, 0x00, 0x00, 0x60, ++ 0x30, 0x18, 0x0c, 0x18, 0x36, 0x6c, 0x18, 0x30, 0x00, 0x00, 0x7f, 0x36, ++ 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x7e, ++ 0x18, 0x7e, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x78, ++ 0x30, 0x72, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, ++ 0x00, 0x00, 0x00, 0x66, 0x66, 0x22, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x00, 0x00, 0x00, ++ 0x00, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, ++ 0x72, 0x56, 0x6c, 0x18, 0x36, 0x6a, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x24, 0x28, 0x30, 0x4a, 0x44, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, ++ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x18, ++ 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x18, ++ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0x7e, 0x3c, ++ 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, ++ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, ++ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00, ++ 0x00, 0x3c, 0x46, 0x4e, 0x5a, 0x72, 0x62, 0x3c, 0x00, 0x00, 0x00, 0x00, ++ 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, ++ 0x66, 0x06, 0x0c, 0x18, 0x32, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, ++ 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, ++ 0x66, 0x7e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x60, 0x7c, 0x66, ++ 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x7c, 0x66, 0x66, ++ 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x06, 0x0c, 0x18, 0x30, ++ 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, ++ 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, ++ 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, ++ 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x5e, ++ 0x56, 0x5e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x66, ++ 0x7e, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x66, ++ 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, ++ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, ++ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x62, 0x7e, 0x00, ++ 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, 0x00, ++ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, ++ 0x00, 0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, ++ 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, ++ 0x46, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6c, ++ 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, ++ 0x60, 0x60, 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x77, 0x7f, ++ 0x6b, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x76, 0x7e, 0x6e, ++ 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, ++ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, ++ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x6e, 0x3c, 0x02, ++ 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x00, 0x00, ++ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, ++ 0x00, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ++ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, ++ 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, ++ 0x63, 0x6b, 0x6b, 0x7f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3c, ++ 0x18, 0x3c, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, ++ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x0c, 0x18, 0x30, ++ 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, ++ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, ++ 0x00, 0x08, 0x10, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x60, ++ 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, ++ 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, ++ 0x7e, 0x60, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x78, ++ 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x66, 0x66, ++ 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x60, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, ++ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x1c, 0x00, ++ 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, ++ 0x00, 0x00, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x7c, 0x66, 0x00, 0x00, 0x00, ++ 0x00, 0x60, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x76, 0x7f, 0x6b, 0x6b, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, ++ 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, ++ 0x66, 0x66, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x72, 0x60, ++ 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x3c, 0x06, ++ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x78, 0x30, 0x30, 0x36, 0x1c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3a, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x63, 0x6b, 0x6b, 0x6b, 0x36, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x00, ++ 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, ++ 0x18, 0x30, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, ++ 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x0c, ++ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00}; +diff -ruN proll_18.orig/src/le.c proll-patch4/src/le.c +--- proll_18.orig/src/le.c 2002-07-23 05:52:49.000000000 +0000 ++++ proll-patch4/src/le.c 2004-11-13 15:50:49.000000000 +0000 +@@ -185,8 +185,6 @@ + unsigned short rap; /* register address port */ + }; + +-int sparc_lance_debug = 2; +- + /* The Lance uses 24 bit addresses */ + /* On the Sun4c the DVMA will provide the remaining bytes for us */ + /* On the Sun4m we have to instruct the ledma to provide them */ +diff -ruN proll_18.orig/src/netinit.c proll-patch4/src/netinit.c +--- proll_18.orig/src/netinit.c 2002-09-13 21:53:33.000000000 +0000 ++++ proll-patch4/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 +@@ -49,13 +49,20 @@ + unsigned char myhwaddr[ETH_ALEN]; /* my own hardware addr */ + t_ipaddr myipaddr; /* my own IP address */ + t_ipaddr mynetmask; /* my own netmask */ +- char *net_module_name; /* name of init module */ + t_ipaddr servaddr; /* IP of RARP&TFTP server */ + + /* Broadcast hardware address */ +-unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++const unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + ++unsigned int seed; ++ ++/* This is taken from x86 to be used in network kernel. Returns 15 bits. */ ++short int random() ++{ ++ seed = (seed + 23968)*0x015A4E35 >> 1; ++ return seed & 0x7FFF; ++} + + /* + ************************************************************************** +@@ -104,10 +111,17 @@ + */ + void init_net() + { ++ /* Avoid data segment allocations */ ++ seed = 151; ++ + /* Initialize the different network layer modules */ + init_packet(); +- if (!init_arp() || !init_udp()) { +- printf("\nERROR: init_%s\n", net_module_name); ++ if (!init_arp()) { ++ printf("\nERROR: init_arp\n"); ++ fatal(); ++ } ++ if (!init_udp()) { ++ printf("\nERROR: init_udp\n"); + fatal(); + } + } +diff -ruN proll_18.orig/src/netpriv.h proll-patch4/src/netpriv.h +--- proll_18.orig/src/netpriv.h 1999-04-27 05:39:37.000000000 +0000 ++++ proll-patch4/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 +@@ -130,10 +130,9 @@ + * + */ + extern unsigned char myhwaddr[ETH_ALEN]; /* my own hardware address */ +-extern unsigned char bcasthw[ETH_ALEN]; /* broadcast hardware addr */ ++extern const unsigned char bcasthw[ETH_ALEN]; /* broadcast hardware addr */ + extern t_ipaddr myipaddr; /* my own IP address */ + extern t_ipaddr mynetmask; /* netmask for my network */ +-extern char *net_module_name; /* initialized module's name */ + extern t_ipaddr servaddr; /* server IP address */ + + +@@ -150,7 +149,7 @@ + extern unsigned char *reg_type __P((int typeval, int (* receive)())); + + /* Write a packet to the network */ +-extern int write_packet __P((int bufsize, int typeval, unsigned char *addr)); ++extern int write_packet __P((int bufsize, int typeval, const unsigned char *addr)); + + /* Empty read buffer */ + extern void empty_buf __P((void)); +diff -ruN proll_18.orig/src/openprom.h proll-patch4/src/openprom.h +--- proll_18.orig/src/openprom.h 2002-07-14 02:26:30.000000000 +0000 ++++ proll-patch4/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 +@@ -54,20 +54,20 @@ + }; + + struct linux_mem_v0 { +- struct linux_mlist_v0 **v0_totphys; +- struct linux_mlist_v0 **v0_prommap; +- struct linux_mlist_v0 **v0_available; /* What we can use */ ++ struct linux_mlist_v0 * const *v0_totphys; ++ struct linux_mlist_v0 * const *v0_prommap; ++ struct linux_mlist_v0 * const *v0_available; /* What we can use */ + }; + + /* Arguments sent to the kernel from the boot prompt. */ + struct linux_arguments_v0 { +- char *argv[8]; ++ const char *argv[8]; + char args[100]; + char boot_dev[2]; + int boot_dev_ctrl; + int boot_dev_unit; + int dev_partition; +- char *kernel_file_name; ++ const char *kernel_file_name; + void *aieee1; /* XXX */ + }; - romvec = init_openprom(bb.nbanks, bb.bankv, hiphybas); +@@ -91,13 +91,13 @@ + struct linux_mem_v0 pv_v0mem; - printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n", - PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024, - (int)cio.start, (int)cio.curp); + /* Node operations. */ +- struct linux_nodeops *pv_nodeops; ++ const struct linux_nodeops *pv_nodeops; + + char **pv_bootstr; + struct linux_dev_v0_funcs pv_v0devops; + +- char *pv_stdin; +- char *pv_stdout; ++ const char *pv_stdin; ++ const char *pv_stdout; + #define PROMDEV_KBD 0 /* input from keyboard */ + #define PROMDEV_SCREEN 0 /* output to screen */ + #define PROMDEV_TTYA 1 /* in/out to ttya */ +@@ -127,7 +127,7 @@ + void (*v2_eval)(char *str); + } pv_fortheval; + +- struct linux_arguments_v0 **pv_v0bootargs; ++ const struct linux_arguments_v0 * const *pv_v0bootargs; + + /* Get ether address. */ + unsigned int (*pv_enaddr)(int d, char *enaddr); +@@ -175,7 +175,7 @@ + int (*no_proplen)(int node, char *name); + int (*no_getprop)(int node, char *name, char *val); + int (*no_setprop)(int node, char *name, char *val, int len); +- char * (*no_nextprop)(int node, char *name); ++ const char * (*no_nextprop)(int node, char *name); + }; + + /* More fun PROM structures for device probing. */ +diff -ruN proll_18.orig/src/packet.c proll-patch4/src/packet.c +--- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000 ++++ proll-patch4/src/packet.c 2004-11-13 15:50:49.000000000 +0000 +@@ -41,7 +41,7 @@ + int aligner; + } wbuf; + static struct sk_buff *rskb; +-static int nqskb = 0; ++static int nqskb; + + + void init_packet() +@@ -62,6 +62,8 @@ + for (i = 0; i < MAXSKBS; i++) { + skev[i].skb.allocn = i; + } ++ ++ nqskb = 0; + } + + unsigned char *reg_type(int ptype, int (*func)()) +@@ -81,7 +83,7 @@ + return wbuf.s; + } + +-int write_packet(int leng, int type, unsigned char *dst) ++int write_packet(int leng, int type, const unsigned char *dst) + { + struct sk_buff *skb; + unsigned char *s; +diff -ruN proll_18.orig/src/printf.c proll-patch4/src/printf.c +--- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000 ++++ proll-patch4/src/printf.c 2004-11-13 15:50:49.000000000 +0000 +@@ -19,7 +19,7 @@ + static void printn(struct prf_fp *, unsigned long, unsigned int); + static void putchar(char, struct prf_fp *); + +-static char hextab[] = "0123456789ABCDEF"; ++static const char hextab[] = "0123456789ABCDEF"; + + /* + * Scaled down version of C Library printf. +@@ -41,7 +41,7 @@ + void + prf(struct prf_fp *filog, char *fmt, va_list adx) + { +- register c; ++ register int c; + char *s; + + for(;;) { +@@ -60,7 +60,7 @@ + putchar(va_arg(adx,unsigned), filog); + } else if(c == 's') { + s = va_arg(adx,char*); +- while(c = *s++) ++ while((c = *s++)) + putchar(c,filog); + } else if (c == 'l' || c == 'O') { + printn(filog, (long)va_arg(adx,long), c=='l'?10:8); +diff -ruN proll_18.orig/src/rconsole.c proll-patch4/src/rconsole.c +--- proll_18.orig/src/rconsole.c 1999-01-16 07:16:55.000000000 +0000 ++++ proll-patch4/src/rconsole.c 2004-11-13 15:50:49.000000000 +0000 +@@ -28,12 +28,18 @@ + * move to California. Only plain lat7 survived. + * I recreated lat7-1 changes in lat7-2. --zaitcev + */ +#ifdef ORIG - set_timeout(5); while (!chk_timeout()) { } /* P3: let me read */ + #include "lat7_2.bm" /* lat7_1.bm */ +#else -+ printk("loading kernel:"); -+ i = ld_bypass(0x20000000); -+ printk(" done, size %d\n", i); ++#include "lat7_2_swapped.bm" /* lat7_1.bm */ +#endif + #define LAT7_NCHARS 128 + #define LAT7_HEIGHT 11 + #define LAT7_WIDTH 8 - { - void (*entry)(void *, int) = (void (*)(void*, int)) LOADBASE; -diff -ru proll_18.orig/mrcoffee/openprom.c proll_18/mrcoffee/openprom.c ---- proll_18.orig/mrcoffee/openprom.c 2002-09-13 16:17:03.000000000 +0200 -+++ proll_18/mrcoffee/openprom.c 2004-09-21 21:27:16.000000000 +0200 -@@ -144,10 +144,14 @@ - }; ++#ifdef ORIG + static Rf_scan lat7_body[ LAT7_NCHARS*LAT7_HEIGHT ]; ++#endif - static int cpu_nctx = NCTX_SWIFT; -+static int cpu_cache_line_size = 0x20; -+static int cpu_cache_nlines = 0x200; - static struct property propv_cpu[] = { - {"name", "STP1012PGA", sizeof("STP1012PGA") }, - {"device_type", "cpu", 4 }, - {"mmu-nctx", (char*)&cpu_nctx, sizeof(int)}, -+ {"cache-line-size", (char*)&cpu_cache_line_size, sizeof(int)}, -+ {"cache-nlines", (char*)&cpu_cache_nlines, sizeof(int)}, - {NULL, NULL, -1} + #if 1 + /* +@@ -94,6 +100,7 @@ + + #endif + ++#ifdef ORIG + static inline int swapbits(int w0) + { + int w1 = 0; +@@ -105,13 +112,16 @@ + } + return w1; + } ++#endif + + void font_cons_7(struct rfont *p) + { ++#ifdef ORIG + int x; + int col = 0; + int row = 0; + int erow = 0; ++ + for (x = 0; x < LAT7_NCHARS*LAT7_HEIGHT; x++ ) { + lat7_body[ (erow * lat7_2_width/8 + col) * LAT7_HEIGHT + row ] = + swapbits(lat7_2_bits[x]) & 0xFF; +@@ -124,6 +134,9 @@ + } + } + p->body_ = lat7_body; ++#else ++ p->body_ = lat7_2_bits; ++#endif + p->nchars_ = LAT7_NCHARS; + p->width_ = LAT7_WIDTH; + p->height_ = LAT7_HEIGHT; +diff -ruN proll_18.orig/src/rconsole.h proll-patch4/src/rconsole.h +--- proll_18.orig/src/rconsole.h 1999-01-16 05:00:59.000000000 +0000 ++++ proll-patch4/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 +@@ -13,10 +13,10 @@ + */ + + #define RF_MAXWIDTH 16 +-typedef unsigned short Rf_scan; /* __w16 to be used */ ++typedef unsigned char Rf_scan; /* __w16 to be used */ + + struct rfont { +- Rf_scan *body_; ++ const Rf_scan *body_; + int nchars_; /* 128 for ASCII ... 65536 for Unicode */ + int width_; /* [Pixels]. Maximum size is 16. */ + int height_; /* [Pixels == scan lines]. */ +diff -ruN proll_18.orig/src/romlib.h proll-patch4/src/romlib.h +--- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000 ++++ proll-patch4/src/romlib.h 2004-11-13 15:50:49.000000000 +0000 +@@ -73,12 +73,12 @@ + #define memcpy(dst, src, len) bcopy(src, dst, len) + #define memcmp(x1, x2, len) bcmp(x1, x2, len) + #define memset(p, len, zero) bzero(p, len) +-extern void bcopy(void *b1, void *b2, int length); +-extern int bcmp(void *b1, void *b2, int length); ++extern void bcopy(const void *b1, void *b2, int length); ++extern int bcmp(const void *b1, const void *b2, int length); + extern void bzero(void *b, int c); + /* gcc complains about "conflicting types for builtin function strlen". */ + #define strlen(s) ssize(s) +-extern int ssize(char *s); ++extern int ssize(const char *s); + + + /* +diff -ruN proll_18.orig/src/sched_4m.c proll-patch4/src/sched_4m.c +--- proll_18.orig/src/sched_4m.c 1999-04-27 05:48:51.000000000 +0000 ++++ proll-patch4/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 +@@ -108,7 +108,7 @@ + static int set_bolt; /* Tick counter limit */ + static struct handsc hndv[16]; + +-static unsigned int intr_to_mask[16] = { ++static unsigned const int intr_to_mask[16] = { + 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }; +diff -ruN proll_18.orig/src/swap.c proll-patch4/src/swap.c +--- proll_18.orig/src/swap.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch4/src/swap.c 2004-11-13 15:50:49.000000000 +0000 +@@ -0,0 +1,21 @@ ++// Convert the lat7 font so that no conversion is needed at runtime. ++#define ORIG ++#include "rconsole.c" ++ ++#include ++ ++int main() ++{ ++ struct rfont p; ++ int i; ++ ++ font_cons_7(&p); ++ ++ printf(" "); ++ for (i = 0; i < LAT7_NCHARS*LAT7_HEIGHT; i++) { ++ printf("0x%02x, ", p.body_[i]); ++ if ((i % 12) == 11) ++ printf("\n "); ++ } ++ printf("\n"); ++} +diff -ruN proll_18.orig/src/system.c proll-patch4/src/system.c +--- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000 ++++ proll-patch4/src/system.c 2004-11-13 15:50:49.000000000 +0000 +@@ -298,8 +298,8 @@ + } + + /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ +- pa = PAGE_SIZE; +- for (va = PAGE_SIZE; va < LOWMEMSZ; va += PAGE_SIZE) { ++ pa = 0; ++ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { + map_page(l1, va, pa, 0, highbase); + pa += PAGE_SIZE; + } +@@ -518,12 +518,12 @@ + while (len--) *((char *)s)++ = 0; + } + +-void bcopy(void *f, void *t, int len) { ++void bcopy(const void *f, void *t, int len) { + while (len--) *((char *)t)++ = *((char *)f)++; + } + + /* Comparison is 7-bit */ +-int bcmp(void *s1, void *s2, int len) ++int bcmp(const void *s1, const void *s2, int len) + { + int i; + char ch; +@@ -538,8 +538,8 @@ + return 0; + } + +-int strlen(char *s) { +- char *p; ++int strlen(const char *s) { ++ const char *p; + for (p = s; *p != 0; p++) { } + return p - s; + } +@@ -560,14 +560,6 @@ + va_end(x1); + } + +-/* This is taken from x86 to be used in network kernel. Returns 15 bits. */ +-short int random() +-{ +- static unsigned int seed = 151; +- seed = (seed + 23968)*0x015A4E35 >> 1; +- return seed & 0x7FFF; +-} +- + void fatal() + { + printk("fatal."); +diff -ruN proll_18.orig/src/system.h proll-patch4/src/system.h +--- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000 ++++ proll-patch4/src/system.h 2004-11-13 15:50:49.000000000 +0000 +@@ -16,7 +16,7 @@ + #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */ + #define NCTX_SWIFT 0x100 + +-#define MAX_BANKS 3 /* Allocation for all machines */ ++#define MAX_BANKS 8 /* Allocation for all machines */ + + #ifndef __ASSEMBLY__ + struct bank { +diff -ruN proll_18.orig/src/udp.c proll-patch4/src/udp.c +--- proll_18.orig/src/udp.c 2001-12-24 05:12:53.000000000 +0000 ++++ proll-patch4/src/udp.c 2004-11-13 15:50:49.000000000 +0000 +@@ -81,7 +81,7 @@ + int source; + int dest; + { +- register unsigned char *addr; ++ const register unsigned char *addr; + /* Set global variables */ + usource = source; +@@ -299,9 +299,6 @@ + */ + int init_udp() + { +- /* Set module name for error handling */ +- net_module_name = "udp"; +- + /* Register IP packet type and set write buffer pointer */ + if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL) + return(FALSE); diff --git a/qemu-doc.texi b/qemu-doc.texi index 367beb80a..ca5cb09b0 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1099,6 +1099,29 @@ Set the initial VGA graphic mode. The default is 800x600x15. More information is available at @url{http://jocelyn.mayer.free.fr/qemu-ppc/}. +@chapter Sparc System emulator invocation + +Use the executable @file{qemu-system-sparc} to simulate a JavaStation +(sun4m architecture). The emulation is far from complete. + +QEMU emulates the following sun4m peripherials: + +@itemize @minus +@item +IOMMU +@item +TCX Frame buffer +@item +Lance (Am7990) Ethernet +@item +Non Volatile RAM M48T08 +@item +Slave I/O: timers, interrupt controllers, Zilog serial ports +@end itemize + +QEMU uses the Proll, a PROM replacement available at +@url{http://people.redhat.com/zaitcev/linux/}. + @chapter QEMU User space emulator invocation @section Quick Start diff --git a/qemu-tech.texi b/qemu-tech.texi index 4e6f507c7..987b3c3ef 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -126,7 +126,7 @@ maximum performances. @itemize -@item Full PowerPC 32 bit emulation, including priviledged instructions, +@item Full PowerPC 32 bit emulation, including privileged instructions, FPU and MMU. @item Can run most PowerPC Linux binaries. @@ -137,7 +137,8 @@ FPU and MMU. @itemize -@item SPARC V8 user support, except FPU instructions. +@item Somewhat complete SPARC V8 emulation, including privileged +instructions, FPU and MMU. @item Can run some SPARC Linux binaries. diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index adf8df2c9..a66d2e36d 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -10,23 +10,42 @@ /* trap definitions */ #define TT_ILL_INSN 0x02 #define TT_PRIV_INSN 0x03 +#define TT_NFPU_INSN 0x04 #define TT_WIN_OVF 0x05 #define TT_WIN_UNF 0x06 #define TT_FP_EXCP 0x08 #define TT_DIV_ZERO 0x2a #define TT_TRAP 0x80 +#define TT_EXTINT 0x10 #define PSR_NEG (1<<23) #define PSR_ZERO (1<<22) #define PSR_OVF (1<<21) #define PSR_CARRY (1<<20) #define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY) +#define PSR_EF (1<<12) +#define PSR_PIL 0xf00 #define PSR_S (1<<7) #define PSR_PS (1<<6) #define PSR_ET (1<<5) #define PSR_CWP 0x1f /* Fake impl 0, version 4 */ -#define GET_PSR(env) ((0<<28) | (4<<24) | env->psr | (env->psrs? PSR_S : 0) | (env->psrs? PSR_PS : 0) |(env->psret? PSR_ET : 0) | env->cwp) +#define GET_PSR(env) ((0 << 28) | (4 << 24) | env->psr | \ + (env->psref? PSR_EF : 0) | \ + (env->psrpil << 8) | \ + (env->psrs? PSR_S : 0) | \ + (env->psrs? PSR_PS : 0) | \ + (env->psret? PSR_ET : 0) | env->cwp) + +#define PUT_PSR(env, val) do { int _tmp = val; \ + env->psr = _tmp & ~PSR_ICC; \ + env->psref = (_tmp & PSR_EF)? 1 : 0; \ + env->psrpil = (_tmp & PSR_PIL) >> 8; \ + env->psrs = (_tmp & PSR_S)? 1 : 0; \ + env->psrps = (_tmp & PSR_PS)? 1 : 0; \ + env->psret = (_tmp & PSR_ET)? 1 : 0; \ + set_cwp(_tmp & PSR_CWP & (NWINDOWS - 1)); \ + } while (0) /* Trap base register */ #define TBR_BASE_MASK 0xfffff000 @@ -65,6 +84,9 @@ #define FSR_FTT1 (1<<15) #define FSR_FTT0 (1<<14) #define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) +#define FSR_FTT_IEEE_EXCP (1 << 14) +#define FSR_FTT_UNIMPFPOP (3 << 14) +#define FSR_FTT_INVAL_FPR (6 << 14) #define FSR_FCC1 (1<<11) #define FSR_FCC0 (1<<10) @@ -106,6 +128,8 @@ typedef struct CPUSPARCState { int psrs; /* supervisor mode (extracted from PSR) */ int psrps; /* previous supervisor mode */ int psret; /* enable traps */ + int psrpil; /* interrupt level */ + int psref; /* enable fpu */ jmp_buf jmp_env; int user_mode_only; int exception_index; @@ -144,6 +168,8 @@ typedef struct CPUSPARCState { CPUSPARCState *cpu_sparc_init(void); int cpu_sparc_exec(CPUSPARCState *s); int cpu_sparc_close(CPUSPARCState *s); +void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f); +double cpu_put_fp64(uint64_t mant, uint16_t exp); struct siginfo; int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 1b3d9a080..f8edc1715 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -40,6 +40,9 @@ void do_interrupt(int intno, int is_int, int error_code, void raise_exception_err(int exception_index, int error_code); void raise_exception(int tt); void memcpy32(uint32_t *dst, const uint32_t *src); +uint32_t mmu_probe(uint32_t address, int mmulev); +void dump_mmu(void); +void helper_debug(); /* XXX: move that to a generic header */ #if !defined(CONFIG_USER_ONLY) diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h index 2987b68d6..eb1e1e311 100644 --- a/target-sparc/fop_template.h +++ b/target-sparc/fop_template.h @@ -51,18 +51,6 @@ void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void) } /* double floating point registers moves */ -#if 0 -#define CPU_DOUBLE_U_DEF -typedef union { - double d; - struct { - uint32_t lower; - uint32_t upper; - } l; - uint64_t ll; -} CPU_DoubleU; -#endif /* CPU_DOUBLE_U_DEF */ - void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void) { CPU_DoubleU u; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 93ef930fb..76ad643eb 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -19,7 +19,8 @@ */ #include "exec.h" -#define DEBUG_PCALL +//#define DEBUG_PCALL +//#define DEBUG_MMU /* Sparc MMU emulation */ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, @@ -108,80 +109,71 @@ static const int rw_table[2][8] = { { 0, 1, 0, 1, 0, 0, 0, 0 } }; - -/* Perform address translation */ -int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, - int is_user, int is_softmmu) +int get_physical_address (CPUState *env, uint32_t *physical, int *prot, + int *access_index, uint32_t address, int rw, + int is_user) { - int exception = 0; - int access_perms = 0, access_index = 0; - uint8_t *pde_ptr; + int access_perms = 0; + target_phys_addr_t pde_ptr; uint32_t pde, virt_addr; - int error_code = 0, is_dirty, prot, ret = 0; - unsigned long paddr, vaddr, page_offset; - - if (env->user_mode_only) { - /* user mode only emulation */ - ret = -2; - goto do_fault; - } + int error_code = 0, is_dirty; + unsigned long page_offset; virt_addr = address & TARGET_PAGE_MASK; if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ - paddr = address; - page_offset = address & (TARGET_PAGE_SIZE - 1); - prot = PAGE_READ | PAGE_WRITE; - goto do_mapping; + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; + return 0; } /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ - pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); - pde = ldl_raw(pde_ptr); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); /* Ctx pde */ switch (pde & PTE_ENTRYTYPE_MASK) { + default: case 0: /* Invalid */ - error_code = 1; - goto do_fault; - case 2: /* PTE, maybe should not happen? */ + return 1; + case 2: /* L0 PTE, maybe should not happen? */ case 3: /* Reserved */ - error_code = 4; - goto do_fault; - case 1: /* L1 PDE */ - pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4); - pde = ldl_raw(pde_ptr); + return 4; + case 1: /* L0 PDE */ + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); switch (pde & PTE_ENTRYTYPE_MASK) { + default: case 0: /* Invalid */ - error_code = 1; - goto do_fault; + return 1; case 3: /* Reserved */ - error_code = 4; - goto do_fault; - case 1: /* L2 PDE */ - pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - pde = ldl_raw(pde_ptr); + return 4; + case 1: /* L1 PDE */ + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); switch (pde & PTE_ENTRYTYPE_MASK) { + default: case 0: /* Invalid */ - error_code = 1; - goto do_fault; + return 1; case 3: /* Reserved */ - error_code = 4; - goto do_fault; - case 1: /* L3 PDE */ - pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - pde = ldl_raw(pde_ptr); + return 4; + case 1: /* L2 PDE */ + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); switch (pde & PTE_ENTRYTYPE_MASK) { + default: case 0: /* Invalid */ - error_code = 1; - goto do_fault; + return 1; case 1: /* PDE, should not happen */ case 3: /* Reserved */ - error_code = 4; - goto do_fault; + return 4; case 2: /* L3 PTE */ virt_addr = address & TARGET_PAGE_MASK; page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1); @@ -201,40 +193,58 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, /* update page modified and dirty bits */ is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); if (!(pde & PG_ACCESSED_MASK) || is_dirty) { + uint32_t tmppde; pde |= PG_ACCESSED_MASK; if (is_dirty) pde |= PG_MODIFIED_MASK; - stl_raw(pde_ptr, pde); + tmppde = bswap32(pde); + cpu_physical_memory_write(pde_ptr, (uint8_t *)&tmppde, 4); } - /* check access */ - access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); + *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; - error_code = access_table[access_index][access_perms]; + error_code = access_table[*access_index][access_perms]; if (error_code) - goto do_fault; + return error_code; /* the page can be put in the TLB */ - prot = PAGE_READ; + *prot = PAGE_READ; if (pde & PG_MODIFIED_MASK) { /* only set write access if already dirty... otherwise wait for dirty access */ if (rw_table[is_user][access_perms]) - prot |= PAGE_WRITE; + *prot |= PAGE_WRITE; } /* Even if large ptes, we map only one 4KB page in the cache to avoid filling it too fast */ - virt_addr = address & TARGET_PAGE_MASK; - paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset; + *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset; + return 0; +} + +/* Perform address translation */ +int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu) +{ + int exception = 0; + uint32_t virt_addr, paddr; + unsigned long vaddr; + int error_code = 0, prot, ret = 0, access_index; - do_mapping: - vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + if (env->user_mode_only) { + /* user mode only emulation */ + error_code = -2; + goto do_fault_user; + } - ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); - return ret; + error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); + if (error_code == 0) { + virt_addr = address & TARGET_PAGE_MASK; + vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + return ret; + } - do_fault: if (env->mmuregs[3]) /* Fault status register */ env->mmuregs[3] = 1; /* overflow (not read before another fault) */ env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2; @@ -242,7 +252,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault return 0; - + do_fault_user: env->exception_index = exception; env->error_code = error_code; return error_code; @@ -289,13 +299,14 @@ void do_interrupt(int intno, int is_int, int error_code, count, intno, error_code, is_int, env->pc, env->npc, env->regwptr[6]); -#if 0 +#if 1 cpu_dump_state(env, logfile, fprintf, 0); { int i; uint8_t *ptr; + fprintf(logfile, " code="); - ptr = env->pc; + ptr = (uint8_t *)env->pc; for(i = 0; i < 16; i++) { fprintf(logfile, " %02x", ldub(ptr + i)); } @@ -304,12 +315,19 @@ void do_interrupt(int intno, int is_int, int error_code, #endif count++; } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->psret == 0) { + fprintf(logfile, "Trap while interrupts disabled, Error state!\n"); + qemu_system_shutdown_request(); + return; + } #endif env->psret = 0; cwp = (env->cwp - 1) & (NWINDOWS - 1); set_cwp(cwp); - env->regwptr[9] = env->pc; - env->regwptr[10] = env->npc; + env->regwptr[9] = env->pc - 4; // XXX? + env->regwptr[10] = env->pc; env->psrps = env->psrs; env->psrs = 1; env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); @@ -322,3 +340,106 @@ void raise_exception_err(int exception_index, int error_code) { raise_exception(exception_index); } + +uint32_t mmu_probe(uint32_t address, int mmulev) +{ + target_phys_addr_t pde_ptr; + uint32_t pde; + + /* Context base + context number */ + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 2: /* PTE, maybe should not happen? */ + case 3: /* Reserved */ + return 0; + case 1: /* L1 PDE */ + if (mmulev == 3) + return pde; + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L1 PTE */ + return pde; + case 1: /* L2 PDE */ + if (mmulev == 2) + return pde; + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L2 PTE */ + return pde; + case 1: /* L3 PDE */ + if (mmulev == 1) + return pde; + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 1: /* PDE, should not happen */ + case 3: /* Reserved */ + return 0; + case 2: /* L3 PTE */ + return pde; + } + } + } + } + return 0; +} + +void dump_mmu(void) +{ +#ifdef DEBUG_MMU + uint32_t pa, va, va1, va2; + int n, m, o; + target_phys_addr_t pde_ptr; + uint32_t pde; + + printf("MMU dump:\n"); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); + bswap32s(&pde); + printf("Root ptr: 0x%08x, ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); + for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { + pde_ptr = mmu_probe(va, 2); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va); + printf("VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va, pa, pde_ptr); + for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { + pde_ptr = mmu_probe(va1, 1); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va1); + printf(" VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va1, pa, pde_ptr); + for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { + pde_ptr = mmu_probe(va2, 0); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va2); + printf(" VA: 0x%08x, PA: 0x%08x PTE: 0x%08x\n", va2, pa, pde_ptr); + } + } + } + } + } + } + printf("MMU dump ends\n"); +#endif +} diff --git a/target-sparc/op.c b/target-sparc/op.c index 2cf4ed841..f8cf2f893 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -524,13 +524,7 @@ void OPPROTO op_rdpsr(void) void OPPROTO op_wrpsr(void) { - int cwp; - env->psr = T0 & ~PSR_ICC; - env->psrs = (T0 & PSR_S)? 1 : 0; - env->psrps = (T0 & PSR_PS)? 1 : 0; - env->psret = (T0 & PSR_ET)? 1 : 0; - cwp = (T0 & PSR_CWP) & (NWINDOWS - 1); - set_cwp(cwp); + PUT_PSR(env,T0); FORCE_RET(); } @@ -602,10 +596,27 @@ void OPPROTO op_trapcc_T0(void) FORCE_RET(); } -void OPPROTO op_debug(void) +void OPPROTO op_trap_ifnofpu(void) +{ + if (!env->psref) { + env->exception_index = TT_NFPU_INSN; + cpu_loop_exit(); + } + FORCE_RET(); +} + +void OPPROTO op_fpexception_im(void) { - env->exception_index = EXCP_DEBUG; + env->exception_index = TT_FP_EXCP; + env->fsr &= ~FSR_FTT_MASK; + env->fsr |= PARAM1; cpu_loop_exit(); + FORCE_RET(); +} + +void OPPROTO op_debug(void) +{ + helper_debug(); } void OPPROTO op_exit_tb(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 3a6de7cfc..6dead66a8 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -2,6 +2,8 @@ #include #include "exec.h" +//#define DEBUG_MMU + #ifdef USE_INT_TO_FLOAT_HELPERS void do_fitos(void) { @@ -33,6 +35,13 @@ void do_fcmps (void) { if (isnan(FT0) || isnan(FT1)) { T0 = FSR_FCC1 | FSR_FCC0; + env->fsr &= ~(FSR_FCC1 | FSR_FCC0); + env->fsr |= T0; + if (env->fsr & FSR_NVM) { + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } } else if (FT0 < FT1) { T0 = FSR_FCC0; } else if (FT0 > FT1) { @@ -47,6 +56,13 @@ void do_fcmpd (void) { if (isnan(DT0) || isnan(DT1)) { T0 = FSR_FCC1 | FSR_FCC0; + env->fsr &= ~(FSR_FCC1 | FSR_FCC0); + env->fsr |= T0; + if (env->fsr & FSR_NVM) { + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } } else if (DT0 < DT1) { T0 = FSR_FCC0; } else if (DT0 > DT1) { @@ -59,55 +75,131 @@ void do_fcmpd (void) void helper_ld_asi(int asi, int size, int sign) { - switch(asi) { + uint32_t ret; + + switch (asi) { case 3: /* MMU probe */ - T1 = 0; - return; + { + int mmulev; + + mmulev = (T0 >> 8) & 15; + if (mmulev > 4) + ret = 0; + else { + ret = mmu_probe(T0, mmulev); + //bswap32s(&ret); + } +#ifdef DEBUG_MMU + printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); +#endif + } + break; case 4: /* read MMU regs */ { - int temp, reg = (T0 >> 8) & 0xf; + int reg = (T0 >> 8) & 0xf; - temp = env->mmuregs[reg]; + ret = env->mmuregs[reg]; if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/ - env->mmuregs[reg] = 0; - T1 = temp; + env->mmuregs[4] = 0; } - return; + break; case 0x20 ... 0x2f: /* MMU passthrough */ - { - int temp; - - cpu_physical_memory_read(T0, (void *) &temp, size); - bswap32s(&temp); - T1 = temp; - } - return; + cpu_physical_memory_read(T0, (void *) &ret, size); + if (size == 4) + bswap32s(&ret); + else if (size == 2) + bswap16s(&ret); + break; default: - T1 = 0; - return; + ret = 0; + break; } + T1 = ret; } void helper_st_asi(int asi, int size, int sign) { switch(asi) { case 3: /* MMU flush */ - return; + { + int mmulev; + + mmulev = (T0 >> 8) & 15; + switch (mmulev) { + case 0: // flush page + tlb_flush_page(cpu_single_env, T0 & 0xfffff000); + break; + case 1: // flush segment (256k) + case 2: // flush region (16M) + case 3: // flush context (4G) + case 4: // flush entire + tlb_flush(cpu_single_env, 1); + break; + default: + break; + } + dump_mmu(); + return; + } case 4: /* write MMU regs */ { - int reg = (T0 >> 8) & 0xf; + int reg = (T0 >> 8) & 0xf, oldreg; + + oldreg = env->mmuregs[reg]; if (reg == 0) { env->mmuregs[reg] &= ~(MMU_E | MMU_NF); env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); } else env->mmuregs[reg] = T1; + if (oldreg != env->mmuregs[reg]) { +#if 0 + // XXX: Only if MMU mapping change, we may need to flush? + tlb_flush(cpu_single_env, 1); + cpu_loop_exit(); + FORCE_RET(); +#endif + } + dump_mmu(); return; } + case 0x17: /* Block copy, sta access */ + { + // value (T1) = src + // address (T0) = dst + // copy 32 bytes + int src = T1, dst = T0; + uint8_t temp[32]; + + bswap32s(&src); + + cpu_physical_memory_read(src, (void *) &temp, 32); + cpu_physical_memory_write(dst, (void *) &temp, 32); + } + return; + case 0x1f: /* Block fill, stda access */ + { + // value (T1, T2) + // address (T0) = dst + // fill 32 bytes + int i, dst = T0; + uint64_t val; + + val = (((uint64_t)T1) << 32) | T2; + bswap64s(&val); + + for (i = 0; i < 32; i += 8, dst += 8) { + cpu_physical_memory_write(dst, (void *) &val, 8); + } + } + return; case 0x20 ... 0x2f: /* MMU passthrough */ { int temp = T1; - - bswap32s(&temp); + if (size == 4) + bswap32s(&temp); + else if (size == 2) + bswap16s(&temp); + cpu_physical_memory_write(T0, (void *) &temp, size); } return; @@ -116,27 +208,6 @@ void helper_st_asi(int asi, int size, int sign) } } -#if 0 -void do_ldd_raw(uint32_t addr) -{ - T1 = ldl_raw((void *) addr); - T0 = ldl_raw((void *) (addr + 4)); -} - -#if !defined(CONFIG_USER_ONLY) -void do_ldd_user(uint32_t addr) -{ - T1 = ldl_user((void *) addr); - T0 = ldl_user((void *) (addr + 4)); -} -void do_ldd_kernel(uint32_t addr) -{ - T1 = ldl_kernel((void *) addr); - T0 = ldl_kernel((void *) (addr + 4)); -} -#endif -#endif - void helper_rett() { int cwp; @@ -166,3 +237,22 @@ void helper_ldfsr(void) break; } } + +void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f) +{ + int exptemp; + + *pmant = ldexp(frexp(f, &exptemp), 53); + *pexp = exptemp; +} + +double cpu_put_fp64(uint64_t mant, uint16_t exp) +{ + return ldexp((double) mant, exp - 53); +} + +void helper_debug() +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 2ae74f2ce..9c839a004 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -43,12 +43,8 @@ void OPPROTO glue(op_swap, MEMSUFFIX)(void) void OPPROTO glue(op_ldd, MEMSUFFIX)(void) { -#if 1 T1 = glue(ldl, MEMSUFFIX)((void *) T0); T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4)); -#else - glue(do_ldd, MEMSUFFIX)(T0); -#endif } /*** Floating-point store ***/ diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 2440c0d22..2f067958d 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -646,6 +646,7 @@ static void disas_sparc_insn(DisasContext * dc) switch (xop) { case 0x0: case 0x1: /* UNIMPL */ + case 0x5: /*CBN+x */ default: goto illegal_insn; case 0x2: /* BN+x */ @@ -657,16 +658,24 @@ static void disas_sparc_insn(DisasContext * dc) } case 0x6: /* FBN+x */ { +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif target <<= 2; target = sign_extend(target, 22); do_fbranch(dc, target, insn); goto jmp_insn; } case 0x4: /* SETHI */ - gen_movl_imm_T0(target << 10); - gen_movl_T0_reg(rd); - break; - case 0x5: /*CBN+x */ +#define OPTIM +#if defined(OPTIM) + if (rd) { // nop +#endif + gen_movl_imm_T0(target << 10); + gen_movl_T0_reg(rd); +#if defined(OPTIM) + } +#endif break; } break; @@ -691,14 +700,24 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T0(rs1); if (IS_IMM) { rs2 = GET_FIELD(insn, 25, 31); +#if defined(OPTIM) if (rs2 != 0) { - gen_movl_imm_T1(rs2); - gen_op_add_T1_T0(); +#endif + gen_movl_imm_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) } +#endif } else { rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); +#if defined(OPTIM) + if (rs2 != 0) { +#endif + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } +#endif } save_state(dc); cond = GET_FIELD(insn, 3, 6); @@ -707,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc) dc->is_br = 1; goto jmp_insn; } else { + gen_cond(cond); gen_op_trapcc_T0(); } } else if (xop == 0x28) { @@ -741,7 +761,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; #endif - } else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ + } else if (xop == 0x34) { /* FPU Operations */ +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); @@ -770,6 +793,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fsqrtd(); gen_op_store_DT0_fpr(rd); break; + case 0x2b: /* fsqrtq */ + goto nfpu_insn; case 0x41: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -782,6 +807,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_faddd(); gen_op_store_DT0_fpr(rd); break; + case 0x43: /* faddq */ + goto nfpu_insn; case 0x45: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -794,6 +821,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fsubd(); gen_op_store_DT0_fpr(rd); break; + case 0x47: /* fsubq */ + goto nfpu_insn; case 0x49: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -806,6 +835,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fmuld(); gen_op_store_DT0_fpr(rd); break; + case 0x4b: /* fmulq */ + goto nfpu_insn; case 0x4d: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -818,32 +849,16 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fdivd(); gen_op_store_DT0_fpr(rd); break; - case 0x51: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fcmps(); - break; - case 0x52: - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); - gen_op_fcmpd(); - break; - case 0x55: /* fcmpes */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fcmps(); /* XXX */ - break; - case 0x56: /* fcmped */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); - gen_op_fcmpd(); /* XXX */ - break; + case 0x4f: /* fdivq */ + goto nfpu_insn; case 0x69: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); gen_op_fsmuld(); gen_op_store_DT0_fpr(rd); break; + case 0x6e: /* fdmulq */ + goto nfpu_insn; case 0xc4: gen_op_load_fpr_FT1(rs2); gen_op_fitos(); @@ -854,6 +869,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fdtos(); gen_op_store_FT0_fpr(rd); break; + case 0xc7: /* fqtos */ + goto nfpu_insn; case 0xc8: gen_op_load_fpr_FT1(rs2); gen_op_fitod(); @@ -864,6 +881,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fstod(); gen_op_store_DT0_fpr(rd); break; + case 0xcb: /* fqtod */ + goto nfpu_insn; + case 0xcc: /* fitoq */ + goto nfpu_insn; + case 0xcd: /* fstoq */ + goto nfpu_insn; + case 0xce: /* fdtoq */ + goto nfpu_insn; case 0xd1: gen_op_load_fpr_FT1(rs2); gen_op_fstoi(); @@ -874,13 +899,85 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fdtoi(); gen_op_store_FT0_fpr(rd); break; + case 0xd3: /* fqtoi */ + goto nfpu_insn; default: goto illegal_insn; } - } else { + } else if (xop == 0x35) { /* FPU Operations */ +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ + rs2 = GET_FIELD(insn, 27, 31); + xop = GET_FIELD(insn, 18, 26); + switch (xop) { + case 0x51: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fcmps(); + break; + case 0x52: + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpd(); + break; + case 0x53: /* fcmpq */ + goto nfpu_insn; + case 0x55: /* fcmpes */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */ + break; + case 0x56: /* fcmped */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */ + break; + case 0x57: /* fcmpeq */ + goto nfpu_insn; + default: + goto illegal_insn; + } +#if defined(OPTIM) + } else if (xop == 0x2) { + // clr/mov shortcut + + rs1 = GET_FIELD(insn, 13, 17); + if (rs1 == 0) { + // or %g0, x, y -> mov T1, x; mov y, T1 + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); + gen_movl_imm_T1(rs2); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + gen_movl_T1_reg(rd); + } else { + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + // or x, #0, y -> mov T1, x; mov y, T1 + rs2 = GET_FIELDs(insn, 19, 31); + if (rs2 != 0) { + gen_movl_imm_T1(rs2); + gen_op_or_T1_T0(); + } + } else { /* register */ + // or x, %g0, y -> mov T1, x; mov y, T1 + rs2 = GET_FIELD(insn, 27, 31); + if (rs2 != 0) { + gen_movl_reg_T1(rs2); + gen_op_or_T1_T0(); + } + } + gen_movl_T0_reg(rd); + } +#endif + } else if (xop < 0x38) { + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); gen_movl_imm_T1(rs2); } else { /* register */ @@ -901,10 +998,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_logic_T0_cc(); break; case 0x2: - gen_op_or_T1_T0(); - if (xop & 0x10) - gen_op_logic_T0_cc(); - break; + gen_op_or_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; case 0x3: gen_op_xor_T1_T0(); if (xop & 0x10) @@ -964,9 +1061,14 @@ static void disas_sparc_insn(DisasContext * dc) default: goto illegal_insn; } - gen_movl_T0_reg(rd); + gen_movl_T0_reg(rd); } else { switch (xop) { + case 0x20: /* taddcc */ + case 0x21: /* tsubcc */ + case 0x22: /* taddcctv */ + case 0x23: /* tsubcctv */ + goto illegal_insn; case 0x24: /* mulscc */ gen_op_mulscc_T1_T0(); gen_movl_T0_reg(rd); @@ -1021,56 +1123,72 @@ static void disas_sparc_insn(DisasContext * dc) } break; #endif - case 0x38: /* jmpl */ - { - gen_op_add_T1_T0(); - gen_op_movl_npc_T0(); - if (rd != 0) { - gen_op_movl_T0_im((long) (dc->pc)); - gen_movl_T0_reg(rd); - } - dc->pc = dc->npc; - dc->npc = DYNAMIC_PC; - } - goto jmp_insn; -#if !defined(CONFIG_USER_ONLY) - case 0x39: /* rett */ - { - if (!supervisor(dc)) - goto priv_insn; - gen_op_add_T1_T0(); - gen_op_movl_npc_T0(); - gen_op_rett(); -#if 0 - dc->pc = dc->npc; - dc->npc = DYNAMIC_PC; + default: + goto illegal_insn; + } + } + } else { + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); +#if defined(OPTIM) + if (rs2) { #endif - } -#if 0 - goto jmp_insn; + gen_movl_imm_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } #endif - break; + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); +#if defined(OPTIM) + if (rs2) { +#endif + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } #endif - case 0x3b: /* flush */ - gen_op_add_T1_T0(); - gen_op_flush_T0(); - break; - case 0x3c: /* save */ - save_state(dc); - gen_op_add_T1_T0(); - gen_op_save(); - gen_movl_T0_reg(rd); - break; - case 0x3d: /* restore */ - save_state(dc); - gen_op_add_T1_T0(); - gen_op_restore(); - gen_movl_T0_reg(rd); - break; - default: - goto illegal_insn; - } } + switch (xop) { + case 0x38: /* jmpl */ + { + gen_op_movl_npc_T0(); + if (rd != 0) { + gen_op_movl_T0_im((long) (dc->pc)); + gen_movl_T0_reg(rd); + } + dc->pc = dc->npc; + dc->npc = DYNAMIC_PC; + } + goto jmp_insn; +#if !defined(CONFIG_USER_ONLY) + case 0x39: /* rett */ + { + if (!supervisor(dc)) + goto priv_insn; + gen_op_movl_npc_T0(); + gen_op_rett(); + } + break; +#endif + case 0x3b: /* flush */ + gen_op_flush_T0(); + break; + case 0x3c: /* save */ + save_state(dc); + gen_op_save(); + gen_movl_T0_reg(rd); + break; + case 0x3d: /* restore */ + save_state(dc); + gen_op_restore(); + gen_movl_T0_reg(rd); + break; + default: + goto illegal_insn; + } } break; } @@ -1081,14 +1199,24 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); +#if defined(OPTIM) if (rs2 != 0) { +#endif gen_movl_imm_T1(rs2); gen_op_add_T1_T0(); +#if defined(OPTIM) } +#endif } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); +#if defined(OPTIM) + if (rs2 != 0) { +#endif + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } +#endif } if (xop < 4 || (xop > 7 && xop < 0x14) || \ (xop > 0x17 && xop < 0x20)) { @@ -1116,8 +1244,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(ldstub); break; case 0x0f: /* swap register with memory. Also atomically */ + gen_movl_reg_T1(rd); gen_op_ldst(swap); break; +#if !defined(CONFIG_USER_ONLY) case 0x10: /* load word alternate */ if (!supervisor(dc)) goto priv_insn; @@ -1157,11 +1287,18 @@ static void disas_sparc_insn(DisasContext * dc) case 0x1f: /* swap reg with alt. memory. Also atomically */ if (!supervisor(dc)) goto priv_insn; + gen_movl_reg_T1(rd); gen_op_swapa(insn, 1, 4, 0); break; +#endif + default: + goto illegal_insn; } gen_movl_T1_reg(rd); } else if (xop >= 0x20 && xop < 0x24) { +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif switch (xop) { case 0x20: /* load fpreg */ gen_op_ldst(ldf); @@ -1169,11 +1306,14 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x21: /* load fsr */ gen_op_ldfsr(); + gen_op_store_FT0_fpr(rd); break; case 0x23: /* load double fpreg */ gen_op_ldst(lddf); gen_op_store_DT0_fpr(rd); break; + default: + goto illegal_insn; } } else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) { gen_movl_reg_T1(rd); @@ -1192,6 +1332,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T2(rd + 1); gen_op_ldst(std); break; +#if !defined(CONFIG_USER_ONLY) case 0x14: if (!supervisor(dc)) goto priv_insn; @@ -1214,24 +1355,37 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T2(rd + 1); gen_op_stda(insn, 0, 8, 0); break; +#endif + default: + goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif switch (xop) { case 0x24: gen_op_load_fpr_FT0(rd); gen_op_ldst(stf); break; case 0x25: + gen_op_load_fpr_FT0(rd); gen_op_stfsr(); break; case 0x27: gen_op_load_fpr_DT0(rd); gen_op_ldst(stdf); break; + case 0x26: /* stdfq */ + default: + goto illegal_insn; } } else if (xop > 0x33 && xop < 0x38) { /* Co-processor */ + goto illegal_insn; } + else + goto illegal_insn; } } /* default case for non jump instructions */ @@ -1246,17 +1400,24 @@ static void disas_sparc_insn(DisasContext * dc) dc->pc = dc->npc; dc->npc = dc->npc + 4; } - jmp_insn:; + jmp_insn: return; illegal_insn: save_state(dc); gen_op_exception(TT_ILL_INSN); dc->is_br = 1; return; +#if !defined(CONFIG_USER_ONLY) priv_insn: save_state(dc); gen_op_exception(TT_PRIV_INSN); dc->is_br = 1; + return; +#endif + nfpu_insn: + save_state(dc); + gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); + dc->is_br = 1; } static inline int gen_intermediate_code_internal(TranslationBlock * tb, @@ -1271,6 +1432,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, dc->tb = tb; pc_start = tb->pc; dc->pc = pc_start; + last_pc = dc->pc; dc->npc = (target_ulong) tb->cs_base; #if defined(CONFIG_USER_ONLY) dc->mem_idx = 0; @@ -1285,8 +1447,13 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == dc->pc) { - gen_debug(dc, dc->pc); - break; + if (dc->pc != pc_start) + save_state(dc); + gen_op_debug(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; + goto exit_gen_loop; } } } @@ -1310,8 +1477,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, /* if the next PC is different, we abort now */ if (dc->pc != (last_pc + 4)) break; + /* if single step mode, we generate only one instruction and + generate an exception */ + if (env->singlestep_enabled) { + gen_op_jmp_im(dc->pc); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + break; + } } while ((gen_opc_ptr < gen_opc_end) && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + + exit_gen_loop: if (!dc->is_br) { if (dc->pc != DYNAMIC_PC && (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { @@ -1338,7 +1515,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, } #endif } else { - tb->size = dc->npc - pc_start; + tb->size = last_pc + 4 - pc_start; } #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { @@ -1366,14 +1543,10 @@ int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) return gen_intermediate_code_internal(tb, 1, env); } -CPUSPARCState *cpu_sparc_init(void) -{ - CPUSPARCState *env; - - cpu_exec_init(); +extern int ram_size; - if (!(env = malloc(sizeof(CPUSPARCState)))) - return (NULL); +void cpu_reset(CPUSPARCState *env) +{ memset(env, 0, sizeof(*env)); env->cwp = 0; env->wim = 1; @@ -1381,14 +1554,24 @@ CPUSPARCState *cpu_sparc_init(void) #if defined(CONFIG_USER_ONLY) env->user_mode_only = 1; #else - /* Emulate Prom */ env->psrs = 1; - env->pc = 0x4000; + env->pc = 0xffd00000; + env->gregs[1] = ram_size; + env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ env->npc = env->pc + 4; - env->mmuregs[0] = (0x10<<24) | MMU_E; /* Impl 1, ver 0, MMU Enabled */ - env->mmuregs[1] = 0x3000 >> 4; /* MMU Context table */ #endif +} + +CPUSPARCState *cpu_sparc_init(void) +{ + CPUSPARCState *env; + + cpu_exec_init(); + + if (!(env = malloc(sizeof(CPUSPARCState)))) + return (NULL); cpu_single_env = env; + cpu_reset(env); return (env); } @@ -1436,11 +1619,24 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr); } +#if defined(CONFIG_USER_ONLY) target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } +#else +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint32_t phys_addr; + int prot, access_index; + + if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) + return -1; + return phys_addr; +} +#endif + void helper_flush(target_ulong addr) { addr &= ~7; diff --git a/vl.c b/vl.c index 78f968eb1..a2e23a7a6 100644 --- a/vl.c +++ b/vl.c @@ -2214,10 +2214,74 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) #elif defined(TARGET_SPARC) void cpu_save(QEMUFile *f, void *opaque) { + CPUState *env = opaque; + int i; + uint32_t tmp; + + for(i = 1; i < 8; i++) + qemu_put_be32s(f, &env->gregs[i]); + tmp = env->regwptr - env->regbase; + qemu_put_be32s(f, &tmp); + for(i = 1; i < NWINDOWS * 16 + 8; i++) + qemu_put_be32s(f, &env->regbase[i]); + + /* FPU */ + for(i = 0; i < 32; i++) { + uint64_t mant; + uint16_t exp; + cpu_get_fp64(&mant, &exp, env->fpr[i]); + qemu_put_be64(f, mant); + qemu_put_be16(f, exp); + } + qemu_put_be32s(f, &env->pc); + qemu_put_be32s(f, &env->npc); + qemu_put_be32s(f, &env->y); + tmp = GET_PSR(env); + qemu_put_be32s(f, &tmp); + qemu_put_be32s(f, &env->fsr); + qemu_put_be32s(f, &env->cwp); + qemu_put_be32s(f, &env->wim); + qemu_put_be32s(f, &env->tbr); + /* MMU */ + for(i = 0; i < 16; i++) + qemu_put_be32s(f, &env->mmuregs[i]); } int cpu_load(QEMUFile *f, void *opaque, int version_id) { + CPUState *env = opaque; + int i; + uint32_t tmp; + + for(i = 1; i < 8; i++) + qemu_get_be32s(f, &env->gregs[i]); + qemu_get_be32s(f, &tmp); + env->regwptr = env->regbase + tmp; + for(i = 1; i < NWINDOWS * 16 + 8; i++) + qemu_get_be32s(f, &env->regbase[i]); + + /* FPU */ + for(i = 0; i < 32; i++) { + uint64_t mant; + uint16_t exp; + + qemu_get_be64s(f, &mant); + qemu_get_be16s(f, &exp); + env->fpr[i] = cpu_put_fp64(mant, exp); + } + qemu_get_be32s(f, &env->pc); + qemu_get_be32s(f, &env->npc); + qemu_get_be32s(f, &env->y); + qemu_get_be32s(f, &tmp); + PUT_PSR(env, tmp); + qemu_get_be32s(f, &env->fsr); + qemu_get_be32s(f, &env->cwp); + qemu_get_be32s(f, &env->wim); + qemu_get_be32s(f, &env->tbr); + /* MMU */ + for(i = 0; i < 16; i++) + qemu_get_be32s(f, &env->mmuregs[i]); + tlb_flush(env, 1); return 0; } #else @@ -2388,7 +2452,7 @@ void qemu_system_shutdown_request(void) static void main_cpu_reset(void *opaque) { -#ifdef TARGET_I386 +#if defined(TARGET_I386) || defined(TARGET_SPARC) CPUState *env = opaque; cpu_reset(env); #endif diff --git a/vl.h b/vl.h index 3f3acf2ae..942662127 100644 --- a/vl.h +++ b/vl.h @@ -261,7 +261,7 @@ typedef void QEMUTimerCB(void *opaque); Hz. */ extern QEMUClock *rt_clock; -/* Rge virtual clock is only run during the emulation. It is stopped +/* The virtual clock is only run during the emulation. It is stopped when the virtual machine is stopped. Virtual timers use a high precision clock, usually cpu cycles (use ticks_per_sec). */ extern QEMUClock *vm_clock; @@ -672,25 +672,38 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename); +uint32_t iommu_translate(uint32_t addr); /* iommu.c */ -void iommu_init(uint32_t addr); -uint32_t iommu_translate(uint32_t addr); +void *iommu_init(uint32_t addr); +uint32_t iommu_translate_local(void *opaque, uint32_t addr); /* lance.c */ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr); /* tcx.c */ -void tcx_init(DisplayState *ds, uint32_t addr); - -/* sched.c */ -void sched_init(); +void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size); +void tcx_update_display(void *opaque); +void tcx_invalidate_display(void *opaque); +void tcx_screen_dump(void *opaque, const char *filename); + +/* slavio_intctl.c */ +void *slavio_intctl_init(); +void slavio_pic_info(void *opaque); +void slavio_irq_info(void *opaque); +void slavio_pic_set_irq(void *opaque, int irq, int level); /* magic-load.c */ -void magic_init(const char *kfn, int kloadaddr, uint32_t addr); +int load_elf(const char *filename, uint8_t *addr); +int load_aout(const char *filename, uint8_t *addr); + +/* slavio_timer.c */ +void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2); -/* timer.c */ -void timer_init(uint32_t addr, int irq); +/* slavio_serial.c */ +SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2); +void slavio_serial_ms_kbd_init(int base, int irq); /* NVRAM helpers */ #include "hw/m48t59.h" -- cgit v1.2.3 From 808c4954bfe48da4068c540d667ad379b55a5155 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 19 Dec 2004 23:33:47 +0000 Subject: big endian ARM support (Lennert Buytenhek) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1180 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + Changelog | 1 + Makefile.target | 10 +++++++++- configure | 15 +++++++++++---- qemu-binfmt-conf.sh | 1 + 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.cvsignore b/.cvsignore index 42bc1c754..e7ca91532 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,4 +1,5 @@ arm-user +armeb-user config-host.* dyngen i386 diff --git a/Changelog b/Changelog index eada6316e..7e16de638 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,7 @@ version 0.6.2: - 'pidfile' option - .dmg disk image format support (Johannes Schindelin) - keymaps support (initial patch by Johannes Schindelin) + - big endian ARM support (Lennert Buytenhek) version 0.6.1: diff --git a/Makefile.target b/Makefile.target index edf76cffb..933692977 100644 --- a/Makefile.target +++ b/Makefile.target @@ -13,7 +13,15 @@ LIBS= HELPER_CFLAGS=$(CFLAGS) DYNGEN=../dyngen$(EXESUF) # user emulator name -QEMU_USER=qemu-$(TARGET_ARCH) +ifeq ($(TARGET_ARCH),arm) + ifeq ($(TARGET_WORDS_BIGENDIAN),yes) + QEMU_USER=qemu-armeb + else + QEMU_USER=qemu-arm + endif +else + QEMU_USER=qemu-$(TARGET_ARCH) +endif # system emulator name ifdef CONFIG_SOFTMMU ifeq ($(TARGET_ARCH), i386) diff --git a/configure b/configure index bf7e0bf27..8d34921e4 100755 --- a/configure +++ b/configure @@ -27,11 +27,14 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user ppc-softmmu sparc-softmmu" +target_list="i386-user i386 i386-softmmu arm-user armeb-user sparc-user ppc-user ppc-softmmu sparc-softmmu" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" ;; + armv4b) + cpu="armv4b" + ;; armv4l) cpu="armv4l" ;; @@ -205,7 +208,7 @@ fi else # if cross compiling, cannot launch a program, so make a static guess -if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k"; then +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 @@ -383,6 +386,9 @@ if test "$cpu" = "i386" ; then elif test "$cpu" = "amd64" ; then echo "ARCH=amd64" >> $config_mak echo "#define HOST_AMD64 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 @@ -482,6 +488,7 @@ 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" = "ppc" ] && target_bigendian=yes target_softmmu="no" @@ -496,7 +503,7 @@ fi #echo "Creating $config_mak, $config_h and $target_dir/Makefile" mkdir -p $target_dir -if test "$target" = "arm-user" ; then +if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then mkdir -p $target_dir/nwfpe fi if test "$target_user_only" = "no" ; then @@ -519,7 +526,7 @@ 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 -elif test "$target_cpu" = "arm" ; then +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 diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh index e5acc474a..ff09fc4f9 100644 --- a/qemu-binfmt-conf.sh +++ b/qemu-binfmt-conf.sh @@ -25,6 +25,7 @@ if [ $cpu != "i386" ] ; then fi if [ $cpu != "arm" ] ; then echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register + echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "sparc" ] ; then echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register -- cgit v1.2.3 From 42ad6ae97307db3e01e0f83db87a1430e9e9f31b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 22:48:11 +0000 Subject: 'syscall' syscall git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1181 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2407400c1..df3d4d54d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2338,6 +2338,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_idle case TARGET_NR_idle: goto unimplemented; +#endif +#ifdef TARGET_NR_syscall + case TARGET_NR_syscall: + ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); + break; #endif case TARGET_NR_wait4: { -- cgit v1.2.3 From acae4681ae29768c1d5f1641f5a2501c9ace8cf0 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:25:56 +0000 Subject: fixed imul im test - added TEST_VM86 define for x86_64 tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1182 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index a4bfa34de..bc24cb698 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -32,6 +32,7 @@ #define TEST_CMOV 0 #define TEST_FCOMI 0 +#define TEST_VM86 //#define LINUX_VM86_IOPL_FIX //#define TEST_P4_FLAGS @@ -372,7 +373,7 @@ void test_imulw2(int op0, int op1) s1 = op1; res = s0; flags = 0; - asm ("push %4\n\t" + asm volatile ("push %4\n\t" "popf\n\t" "imulw %w2, %w0\n\t" "pushf\n\t" @@ -390,7 +391,7 @@ void test_imull2(int op0, int op1) s1 = op1; res = s0; flags = 0; - asm ("push %4\n\t" + asm volatile ("push %4\n\t" "popf\n\t" "imull %2, %0\n\t" "pushf\n\t" @@ -406,7 +407,7 @@ void test_imull2(int op0, int op1) int res, flags;\ flags = 0;\ res = 0;\ - asm ("push %3\n\t"\ + asm volatile ("push %3\n\t"\ "popf\n\t"\ "imul" size " $" #op0 ", %" size1 "2, %" size1 "0\n\t" \ "pushf\n\t"\ @@ -414,7 +415,7 @@ void test_imull2(int op0, int op1) : "=r" (res), "=g" (flags)\ : "r" (op1), "1" (flags), "0" (res));\ printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",\ - "imul" size, op0, op1, res, flags & CC_MASK);\ + "imul" size " im", op0, op1, res, flags & CC_MASK);\ } @@ -1673,7 +1674,6 @@ static void test_enter(void) TEST_ENTER("w", uint16_t, 31); } - static void *call_end __init_call = NULL; int main(int argc, char **argv) @@ -1697,7 +1697,9 @@ int main(int argc, char **argv) test_lea(); test_segs(); test_code16(); +#ifdef TEST_VM86 test_vm86(); +#endif test_exceptions(); test_self_modifying_code(); test_single_step(); -- cgit v1.2.3 From 574bbf7b0d59f7973cd7a11cb0e370a6d415dcae Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:27:31 +0000 Subject: initial APIC support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1183 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 441 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 hw/apic.c diff --git a/hw/apic.c b/hw/apic.c new file mode 100644 index 000000000..82b858486 --- /dev/null +++ b/hw/apic.c @@ -0,0 +1,441 @@ +/* + * APIC support + * + * Copyright (c) 2004-2005 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "vl.h" + +//#define DEBUG_APIC + +/* APIC Local Vector Table */ +#define APIC_LVT_TIMER 0 +#define APIC_LVT_THERMAL 1 +#define APIC_LVT_PERFORM 2 +#define APIC_LVT_LINT0 3 +#define APIC_LVT_LINT1 4 +#define APIC_LVT_ERROR 5 +#define APIC_LVT_NB 6 + +/* APIC delivery modes */ +#define APIC_DM_FIXED 0 +#define APIC_DM_LOWPRI 1 +#define APIC_DM_SMI 2 +#define APIC_DM_NMI 4 +#define APIC_DM_INIT 5 +#define APIC_DM_SIPI 6 +#define APIC_DM_EXTINT 7 + +#define APIC_TRIGGER_EDGE 0 +#define APIC_TRIGGER_LEVEL 1 + +#define APIC_LVT_TIMER_PERIODIC (1<<17) +#define APIC_LVT_MASKED (1<<16) +#define APIC_LVT_LEVEL_TRIGGER (1<<15) +#define APIC_LVT_REMOTE_IRR (1<<14) +#define APIC_INPUT_POLARITY (1<<13) +#define APIC_SEND_PENDING (1<<12) + +#define ESR_ILLEGAL_ADDRESS (1 << 7) + +#define APIC_SV_ENABLE (1 << 8) + +typedef struct APICState { + CPUState *cpu_env; + uint32_t apicbase; + uint8_t id; + uint8_t tpr; + uint32_t spurious_vec; + uint32_t isr[8]; /* in service register */ + uint32_t tmr[8]; /* trigger mode register */ + uint32_t irr[8]; /* interrupt request register */ + uint32_t lvt[APIC_LVT_NB]; + uint32_t esr; /* error register */ + uint32_t icr[2]; + + uint32_t divide_conf; + int count_shift; + uint32_t initial_count; + int64_t initial_count_load_time, next_time; + QEMUTimer *timer; +} APICState; + +static int apic_io_memory; + +void cpu_set_apic_base(CPUState *env, uint64_t val) +{ + APICState *s = env->apic_state; +#ifdef DEBUG_APIC + printf("cpu_set_apic_base: %016llx\n", val); +#endif + s->apicbase = (val & 0xfffff000) | + (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); + /* if disabled, cannot be enabled again */ + if (!(val & MSR_IA32_APICBASE_ENABLE)) { + s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; + env->cpuid_features &= ~CPUID_APIC; + s->spurious_vec &= ~APIC_SV_ENABLE; + } +} + +uint64_t cpu_get_apic_base(CPUState *env) +{ + APICState *s = env->apic_state; +#ifdef DEBUG_APIC + printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase); +#endif + return s->apicbase; +} + +/* return -1 if no bit is set */ +static int get_highest_priority_int(uint32_t *tab) +{ + int i; + for(i = 0;i < 8; i++) { + if (tab[i] != 0) { + return i * 32 + ffs(tab[i]) - 1; + } + } + return -1; +} + +static inline void set_bit(uint32_t *tab, int index) +{ + int i, mask; + i = index >> 5; + mask = 1 << (index & 0x1f); + tab[i] |= mask; +} + +static inline void reset_bit(uint32_t *tab, int index) +{ + int i, mask; + i = index >> 5; + mask = 1 << (index & 0x1f); + tab[i] &= ~mask; +} + +static int apic_get_ppr(APICState *s) +{ + int tpr, isrv, ppr; + + tpr = (s->tpr >> 4); + isrv = get_highest_priority_int(s->isr); + if (isrv < 0) + isrv = 0; + isrv >>= 4; + if (tpr >= isrv) + ppr = s->tpr; + else + ppr = isrv << 4; + return ppr; +} + +/* signal the CPU if an irq is pending */ +static void apic_update_irq(APICState *s) +{ + int irrv, isrv; + irrv = get_highest_priority_int(s->irr); + if (irrv < 0) + return; + isrv = get_highest_priority_int(s->isr); + /* if the pending irq has less priority, we do not make a new request */ + if (isrv >= 0 && irrv >= isrv) + return; + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); +} + +static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) +{ + set_bit(s->irr, vector_num); + if (trigger_mode) + set_bit(s->tmr, vector_num); + else + reset_bit(s->tmr, vector_num); + apic_update_irq(s); +} + +static void apic_eoi(APICState *s) +{ + int isrv; + isrv = get_highest_priority_int(s->isr); + if (isrv < 0) + return; + reset_bit(s->isr, isrv); + apic_update_irq(s); +} + +int apic_get_interrupt(CPUState *env) +{ + APICState *s = env->apic_state; + int intno; + + /* if the APIC is installed or enabled, we let the 8259 handle the + IRQs */ + if (!s) + return -1; + if (!(s->spurious_vec & APIC_SV_ENABLE)) + return -1; + + /* XXX: spurious IRQ handling */ + intno = get_highest_priority_int(s->irr); + if (intno < 0) + return -1; + reset_bit(s->irr, intno); + set_bit(s->isr, intno); + apic_update_irq(s); + return intno; +} + +static uint32_t apic_get_current_count(APICState *s) +{ + int64_t d; + uint32_t val; + d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> + s->count_shift; + if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { + /* periodic */ + val = s->initial_count - (d % (s->initial_count + 1)); + } else { + if (d >= s->initial_count) + val = 0; + else + val = s->initial_count - d; + } + return val; +} + +static void apic_timer_update(APICState *s, int64_t current_time) +{ + int64_t next_time, d; + + if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { + d = (current_time - s->initial_count_load_time) >> + s->count_shift; + if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { + d = ((d / (s->initial_count + 1)) + 1) * (s->initial_count + 1); + } else { + if (d >= s->initial_count) + goto no_timer; + d = s->initial_count + 1; + } + next_time = s->initial_count_load_time + (d << s->count_shift); + qemu_mod_timer(s->timer, next_time); + s->next_time = next_time; + } else { + no_timer: + qemu_del_timer(s->timer); + } +} + +static void apic_timer(void *opaque) +{ + APICState *s = opaque; + + if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { + apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE); + } + apic_timer_update(s, s->next_time); +} + +static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +} + +static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +} + +static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) +{ + CPUState *env; + APICState *s; + uint32_t val; + int index; + + env = cpu_single_env; + if (!env) + return 0; + s = env->apic_state; + + index = (addr >> 4) & 0xff; + switch(index) { + case 0x02: /* id */ + val = s->id << 24; + break; + case 0x03: /* version */ + val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */ + break; + case 0x08: + val = s->tpr; + break; + case 0x0a: + /* ppr */ + val = apic_get_ppr(s); + break; + case 0x0f: + val = s->spurious_vec; + break; + case 0x10 ... 0x17: + val = s->isr[index & 7]; + break; + case 0x18 ... 0x1f: + val = s->tmr[index & 7]; + break; + case 0x20 ... 0x27: + val = s->irr[index & 7]; + break; + case 0x28: + val = s->esr; + break; + case 0x32 ... 0x37: + val = s->lvt[index - 0x32]; + break; + case 0x30: + case 0x31: + val = s->icr[index & 1]; + break; + case 0x38: + val = s->initial_count; + break; + case 0x39: + val = apic_get_current_count(s); + break; + case 0x3e: + val = s->divide_conf; + break; + default: + s->esr |= ESR_ILLEGAL_ADDRESS; + val = 0; + break; + } +#ifdef DEBUG_APIC + printf("APIC read: %08x = %08x\n", (uint32_t)addr, val); +#endif + return val; +} + +static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + CPUState *env; + APICState *s; + int index; + + env = cpu_single_env; + if (!env) + return; + s = env->apic_state; + +#ifdef DEBUG_APIC + printf("APIC write: %08x = %08x\n", (uint32_t)addr, val); +#endif + + index = (addr >> 4) & 0xff; + switch(index) { + case 0x02: + s->id = (val >> 24); + break; + case 0x08: + s->tpr = val; + break; + case 0x0b: /* EOI */ + apic_eoi(s); + break; + case 0x0f: + s->spurious_vec = val & 0x1ff; + break; + case 0x30: + case 0x31: + s->icr[index & 1] = val; + break; + case 0x32 ... 0x37: + { + int n = index - 0x32; + s->lvt[n] = val; + if (n == APIC_LVT_TIMER) + apic_timer_update(s, qemu_get_clock(vm_clock)); + } + break; + case 0x38: + s->initial_count = val; + s->initial_count_load_time = qemu_get_clock(vm_clock); + apic_timer_update(s, s->initial_count_load_time); + break; + case 0x3e: + { + int v; + s->divide_conf = val & 0xb; + v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); + s->count_shift = (v + 1) & 7; + } + break; + default: + s->esr |= ESR_ILLEGAL_ADDRESS; + break; + } +} + + + +static CPUReadMemoryFunc *apic_mem_read[3] = { + apic_mem_readb, + apic_mem_readw, + apic_mem_readl, +}; + +static CPUWriteMemoryFunc *apic_mem_write[3] = { + apic_mem_writeb, + apic_mem_writew, + apic_mem_writel, +}; + +int apic_init(CPUState *env) +{ + APICState *s; + int i; + + s = malloc(sizeof(APICState)); + if (!s) + return -1; + memset(s, 0, sizeof(*s)); + env->apic_state = s; + s->cpu_env = env; + s->apicbase = 0xfee00000 | + MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE; + for(i = 0; i < APIC_LVT_NB; i++) + s->lvt[i] = 1 << 16; /* mask LVT */ + s->spurious_vec = 0xff; + + if (apic_io_memory == 0) { + /* NOTE: the APIC is directly connected to the CPU - it is not + on the global memory bus. */ + apic_io_memory = cpu_register_io_memory(0, apic_mem_read, + apic_mem_write, NULL); + cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory); + } + s->timer = qemu_new_timer(vm_clock, apic_timer, s); + return 0; +} -- cgit v1.2.3 From 62a46c616811461fd06f6321a966c55d8a30c33a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:28:27 +0000 Subject: suppressed warnings in 64 bit case git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1184 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index ee0732848..fc6b50257 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -95,9 +95,14 @@ typedef struct fdrive_t { } fdrive_t; #ifdef TARGET_SPARC +/* XXX: suppress those hacks */ #define DMA_read_memory(a,b,c,d) #define DMA_write_memory(a,b,c,d) -#define DMA_register_channel(a,b,c) +void DMA_register_channel (int nchan, + DMA_transfer_handler transfer_handler, + void *opaque) +{ +} #define DMA_hold_DREQ(a) #define DMA_release_DREQ(a) #define DMA_get_channel_mode(a) (0) @@ -469,16 +474,27 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) } } +static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg) +{ + return fdctrl_read(opaque, reg); +} + +static void fdctrl_write_mem (void *opaque, + target_phys_addr_t reg, uint32_t value) +{ + fdctrl_write(opaque, reg, value); +} + static CPUReadMemoryFunc *fdctrl_mem_read[3] = { - fdctrl_read, - fdctrl_read, - fdctrl_read, + fdctrl_read_mem, + fdctrl_read_mem, + fdctrl_read_mem, }; static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { - fdctrl_write, - fdctrl_write, - fdctrl_write, + fdctrl_write_mem, + fdctrl_write_mem, + fdctrl_write_mem, }; static void fd_change_cb (void *opaque) -- cgit v1.2.3 From 4f7631cfb540b452a01a0375716b51bcc933ef53 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:28:51 +0000 Subject: initial APIC support (only for x86_64 target now) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1185 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/i8259.c b/hw/i8259.c index 221506b28..8f1821d97 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -197,6 +197,15 @@ int cpu_get_pic_interrupt(CPUState *env) { int irq, irq2, intno; +#ifdef TARGET_X86_64 + intno = apic_get_interrupt(env); + if (intno >= 0) { + /* set irq request if a PIC irq is still pending */ + /* XXX: improve that */ + pic_update_irq(); + return intno; + } +#endif /* read the irq from the PIC */ irq = pic_get_irq(&pics[0]); -- cgit v1.2.3 From 75598f6131dab9b6ba18185c92d3c826854b6ce7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:30:09 +0000 Subject: APIC support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1186 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index 64b6180a3..7b6c8946f 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -527,6 +527,8 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, register_ioport_read(0x92, 1, 1, ioport92_read, NULL); register_ioport_write(0x92, 1, 1, ioport92_write, NULL); + if (pci_enabled) + apic_init(cpu_single_env); pic_init(); pit = pit_init(0x40, 0); -- cgit v1.2.3 From 80a9d03503494feffab254d7d366ab55533f5d09 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:31:27 +0000 Subject: 64 bit target fixes - removed warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1187 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 8 +++++--- linux-user/signal.c | 17 +++++++++++------ linux-user/syscall.c | 5 ++++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 3d99dda1a..aa5923f84 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -181,7 +181,7 @@ static void set_idt(int n, unsigned int dpl) void cpu_loop(CPUX86State *env) { int trapnr; - uint8_t *pc; + target_ulong pc; target_siginfo_t info; for(;;) { @@ -440,6 +440,7 @@ static void restore_window(CPUSPARCState *env) env->wim = new_wim; } +#if 0 static void flush_windows(CPUSPARCState *env) { int offset, cwp1; @@ -459,6 +460,7 @@ static void flush_windows(CPUSPARCState *env) offset++; } } +#endif void cpu_loop (CPUSPARCState *env) { @@ -1067,7 +1069,7 @@ int main(int argc, char **argv) env->eip = regs->eip; /* linux interrupt setup */ - env->idt.base = (void *)idt_table; + env->idt.base = (long)idt_table; env->idt.limit = sizeof(idt_table) - 1; set_idt(0, 0); set_idt(1, 0); @@ -1092,7 +1094,7 @@ int main(int argc, char **argv) set_idt(0x80, 3); /* linux segment setup */ - env->gdt.base = (void *)gdt_table; + env->gdt.base = (long)gdt_table; env->gdt.limit = sizeof(gdt_table) - 1; write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | diff --git a/linux-user/signal.c b/linux-user/signal.c index 49278208c..b2dcaa36a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1272,6 +1272,7 @@ badframe: } #elif defined(TARGET_SPARC) + #define __SUNOS_MAXWIN 31 /* This is what SunOS does, so shall I. */ @@ -1400,6 +1401,7 @@ setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) return err; } +#if 0 static int setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ CPUState *env, unsigned long mask) @@ -1416,6 +1418,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ return err; } +#endif #define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) static void setup_frame(int sig, struct emulated_sigaction *ka, @@ -1483,12 +1486,12 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, /* Flush instruction space. */ //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); - tb_flush(env); + // tb_flush(env); } //cpu_dump_state(env, stderr, fprintf, 0); return; -sigill_and_return: + //sigill_and_return: force_sig(TARGET_SIGILL); sigsegv: //fprintf(stderr, "force_sig\n"); @@ -1544,12 +1547,14 @@ long do_sigreturn(CPUState *env) uint32_t up_psr, pc, npc; target_sigset_t set; sigset_t host_set; - __siginfo_fpu_t *fpu_save; + target_ulong fpu_save; int err, i; sf = (struct target_signal_frame *) env->regwptr[UREG_FP]; +#if 0 fprintf(stderr, "sigreturn\n"); fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); +#endif //cpu_dump_state(env, stderr, fprintf, 0); /* 1. Make sure we are not getting garbage from the user */ @@ -1564,7 +1569,7 @@ long do_sigreturn(CPUState *env) err = __get_user(pc, &sf->info.si_regs.pc); err |= __get_user(npc, &sf->info.si_regs.npc); - fprintf(stderr, "pc: %lx npc %lx\n", pc, npc); + // fprintf(stderr, "pc: %lx npc %lx\n", pc, npc); if ((pc | npc) & 3) goto segv_and_exit; @@ -1585,7 +1590,7 @@ long do_sigreturn(CPUState *env) err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); } - err |= __get_user(fpu_save, &sf->fpu_save); + err |= __get_user(fpu_save, (target_ulong *)&sf->fpu_save); //if (fpu_save) // err |= restore_fpu_state(env, fpu_save); @@ -1604,7 +1609,7 @@ long do_sigreturn(CPUState *env) if (err) goto segv_and_exit; - fprintf(stderr, "returning %lx\n", env->regwptr[0]); + // fprintf(stderr, "returning %lx\n", env->regwptr[0]); return env->regwptr[0]; segv_and_exit: diff --git a/linux-user/syscall.c b/linux-user/syscall.c index df3d4d54d..7901befdd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1326,7 +1326,7 @@ static int write_ldt(CPUX86State *env, if (!ldt_table) return -ENOMEM; memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); - env->ldt.base = ldt_table; + env->ldt.base = (long)ldt_table; env->ldt.limit = 0xffff; } @@ -2502,6 +2502,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, tnamelen = treclen - (2 * sizeof(target_long) + 2); if (tnamelen > 256) tnamelen = 256; + /* XXX: may not be correct */ strncpy(tde->d_name, de->d_name, tnamelen); de = (struct dirent *)((char *)de + reclen); len -= reclen; @@ -3046,7 +3047,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); +#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) unimplemented_nowarn: +#endif ret = -ENOSYS; break; } -- cgit v1.2.3 From 612458f544d4dfe4264217f1bbf6d611037a7b79 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:34:06 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1188 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index e2c8b2dfa..9a491db6d 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -218,13 +218,6 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } #elif defined (TARGET_PPC) -static uint32_t from_le32 (uint32_t *buf) -{ - uint8_t *p = (uint8_t *)buf; - - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -} - static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { uint32_t *registers = (uint32_t *)mem_buf, tmp; @@ -477,6 +470,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) return RS_IDLE; } +extern void tb_flush(CPUState *env); + static void gdb_vm_stopped(void *opaque, int reason) { GDBState *s = opaque; -- cgit v1.2.3 From c27004ec7888096c982bbc9b17016fcfe7903171 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:35:10 +0000 Subject: 64 bit target support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1189 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 130 +++++++++++++++++++++++++++--------------------- cpu-defs.h | 2 + cpu-exec.c | 61 ++++++++++++----------- dis-asm.h | 3 ++ disas.c | 143 ++++++++++++++++++++++++++++++++--------------------- disas.h | 5 +- exec-all.h | 39 +++++++++++---- exec.c | 42 +++++++++------- monitor.c | 2 +- softmmu_header.h | 42 +++++++++------- softmmu_template.h | 28 ++++++----- vl.h | 16 ++++++ 12 files changed, 309 insertions(+), 204 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index e1bdc9133..303fab0c1 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -166,17 +166,17 @@ typedef union { * user : user mode access using soft MMU * kernel : kernel mode access using soft MMU */ -static inline int ldub_raw(void *ptr) +static inline int ldub_p(void *ptr) { return *(uint8_t *)ptr; } -static inline int ldsb_raw(void *ptr) +static inline int ldsb_p(void *ptr) { return *(int8_t *)ptr; } -static inline void stb_raw(void *ptr, int v) +static inline void stb_p(void *ptr, int v) { *(uint8_t *)ptr = v; } @@ -187,7 +187,7 @@ static inline void stb_raw(void *ptr, int v) #if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)) /* conservative code for little endian unaligned accesses */ -static inline int lduw_raw(void *ptr) +static inline int lduw_p(void *ptr) { #ifdef __powerpc__ int val; @@ -199,7 +199,7 @@ static inline int lduw_raw(void *ptr) #endif } -static inline int ldsw_raw(void *ptr) +static inline int ldsw_p(void *ptr) { #ifdef __powerpc__ int val; @@ -211,7 +211,7 @@ static inline int ldsw_raw(void *ptr) #endif } -static inline int ldl_raw(void *ptr) +static inline int ldl_p(void *ptr) { #ifdef __powerpc__ int val; @@ -223,16 +223,16 @@ static inline int ldl_raw(void *ptr) #endif } -static inline uint64_t ldq_raw(void *ptr) +static inline uint64_t ldq_p(void *ptr) { uint8_t *p = ptr; uint32_t v1, v2; - v1 = ldl_raw(p); - v2 = ldl_raw(p + 4); + v1 = ldl_p(p); + v2 = ldl_p(p + 4); return v1 | ((uint64_t)v2 << 32); } -static inline void stw_raw(void *ptr, int v) +static inline void stw_p(void *ptr, int v) { #ifdef __powerpc__ __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); @@ -243,7 +243,7 @@ static inline void stw_raw(void *ptr, int v) #endif } -static inline void stl_raw(void *ptr, int v) +static inline void stl_p(void *ptr, int v) { #ifdef __powerpc__ __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); @@ -256,54 +256,54 @@ static inline void stl_raw(void *ptr, int v) #endif } -static inline void stq_raw(void *ptr, uint64_t v) +static inline void stq_p(void *ptr, uint64_t v) { uint8_t *p = ptr; - stl_raw(p, (uint32_t)v); - stl_raw(p + 4, v >> 32); + stl_p(p, (uint32_t)v); + stl_p(p + 4, v >> 32); } /* float access */ -static inline float ldfl_raw(void *ptr) +static inline float ldfl_p(void *ptr) { union { float f; uint32_t i; } u; - u.i = ldl_raw(ptr); + u.i = ldl_p(ptr); return u.f; } -static inline void stfl_raw(void *ptr, float v) +static inline void stfl_p(void *ptr, float v) { union { float f; uint32_t i; } u; u.f = v; - stl_raw(ptr, u.i); + stl_p(ptr, u.i); } -static inline double ldfq_raw(void *ptr) +static inline double ldfq_p(void *ptr) { CPU_DoubleU u; - u.l.lower = ldl_raw(ptr); - u.l.upper = ldl_raw(ptr + 4); + u.l.lower = ldl_p(ptr); + u.l.upper = ldl_p(ptr + 4); return u.d; } -static inline void stfq_raw(void *ptr, double v) +static inline void stfq_p(void *ptr, double v) { CPU_DoubleU u; u.d = v; - stl_raw(ptr, u.l.lower); - stl_raw(ptr + 4, u.l.upper); + stl_p(ptr, u.l.lower); + stl_p(ptr + 4, u.l.upper); } #elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)) -static inline int lduw_raw(void *ptr) +static inline int lduw_p(void *ptr) { #if defined(__i386__) int val; @@ -318,7 +318,7 @@ static inline int lduw_raw(void *ptr) #endif } -static inline int ldsw_raw(void *ptr) +static inline int ldsw_p(void *ptr) { #if defined(__i386__) int val; @@ -333,7 +333,7 @@ static inline int ldsw_raw(void *ptr) #endif } -static inline int ldl_raw(void *ptr) +static inline int ldl_p(void *ptr) { #if defined(__i386__) || defined(__x86_64__) int val; @@ -348,15 +348,15 @@ static inline int ldl_raw(void *ptr) #endif } -static inline uint64_t ldq_raw(void *ptr) +static inline uint64_t ldq_p(void *ptr) { uint32_t a,b; - a = ldl_raw(ptr); - b = ldl_raw(ptr+4); + a = ldl_p(ptr); + b = ldl_p(ptr+4); return (((uint64_t)a<<32)|b); } -static inline void stw_raw(void *ptr, int v) +static inline void stw_p(void *ptr, int v) { #if defined(__i386__) asm volatile ("xchgb %b0, %h0\n" @@ -370,7 +370,7 @@ static inline void stw_raw(void *ptr, int v) #endif } -static inline void stl_raw(void *ptr, int v) +static inline void stl_p(void *ptr, int v) { #if defined(__i386__) || defined(__x86_64__) asm volatile ("bswap %0\n" @@ -386,105 +386,105 @@ static inline void stl_raw(void *ptr, int v) #endif } -static inline void stq_raw(void *ptr, uint64_t v) +static inline void stq_p(void *ptr, uint64_t v) { - stl_raw(ptr, v >> 32); - stl_raw(ptr + 4, v); + stl_p(ptr, v >> 32); + stl_p(ptr + 4, v); } /* float access */ -static inline float ldfl_raw(void *ptr) +static inline float ldfl_p(void *ptr) { union { float f; uint32_t i; } u; - u.i = ldl_raw(ptr); + u.i = ldl_p(ptr); return u.f; } -static inline void stfl_raw(void *ptr, float v) +static inline void stfl_p(void *ptr, float v) { union { float f; uint32_t i; } u; u.f = v; - stl_raw(ptr, u.i); + stl_p(ptr, u.i); } -static inline double ldfq_raw(void *ptr) +static inline double ldfq_p(void *ptr) { CPU_DoubleU u; - u.l.upper = ldl_raw(ptr); - u.l.lower = ldl_raw(ptr + 4); + u.l.upper = ldl_p(ptr); + u.l.lower = ldl_p(ptr + 4); return u.d; } -static inline void stfq_raw(void *ptr, double v) +static inline void stfq_p(void *ptr, double v) { CPU_DoubleU u; u.d = v; - stl_raw(ptr, u.l.upper); - stl_raw(ptr + 4, u.l.lower); + stl_p(ptr, u.l.upper); + stl_p(ptr + 4, u.l.lower); } #else -static inline int lduw_raw(void *ptr) +static inline int lduw_p(void *ptr) { return *(uint16_t *)ptr; } -static inline int ldsw_raw(void *ptr) +static inline int ldsw_p(void *ptr) { return *(int16_t *)ptr; } -static inline int ldl_raw(void *ptr) +static inline int ldl_p(void *ptr) { return *(uint32_t *)ptr; } -static inline uint64_t ldq_raw(void *ptr) +static inline uint64_t ldq_p(void *ptr) { return *(uint64_t *)ptr; } -static inline void stw_raw(void *ptr, int v) +static inline void stw_p(void *ptr, int v) { *(uint16_t *)ptr = v; } -static inline void stl_raw(void *ptr, int v) +static inline void stl_p(void *ptr, int v) { *(uint32_t *)ptr = v; } -static inline void stq_raw(void *ptr, uint64_t v) +static inline void stq_p(void *ptr, uint64_t v) { *(uint64_t *)ptr = v; } /* float access */ -static inline float ldfl_raw(void *ptr) +static inline float ldfl_p(void *ptr) { return *(float *)ptr; } -static inline double ldfq_raw(void *ptr) +static inline double ldfq_p(void *ptr) { return *(double *)ptr; } -static inline void stfl_raw(void *ptr, float v) +static inline void stfl_p(void *ptr, float v) { *(float *)ptr = v; } -static inline void stfq_raw(void *ptr, double v) +static inline void stfq_p(void *ptr, double v) { *(double *)ptr = v; } @@ -492,6 +492,24 @@ static inline void stfq_raw(void *ptr, double v) /* MMU memory access macros */ +/* NOTE: we use double casts if pointers and target_ulong have + different sizes */ +#define ldub_raw(p) ldub_p((uint8_t *)(long)(p)) +#define ldsb_raw(p) ldsb_p((uint8_t *)(long)(p)) +#define lduw_raw(p) lduw_p((uint8_t *)(long)(p)) +#define ldsw_raw(p) ldsw_p((uint8_t *)(long)(p)) +#define ldl_raw(p) ldl_p((uint8_t *)(long)(p)) +#define ldq_raw(p) ldq_p((uint8_t *)(long)(p)) +#define ldfl_raw(p) ldfl_p((uint8_t *)(long)(p)) +#define ldfq_raw(p) ldfq_p((uint8_t *)(long)(p)) +#define stb_raw(p, v) stb_p((uint8_t *)(long)(p), v) +#define stw_raw(p, v) stw_p((uint8_t *)(long)(p), v) +#define stl_raw(p, v) stl_p((uint8_t *)(long)(p), v) +#define stq_raw(p, v) stq_p((uint8_t *)(long)(p), v) +#define stfl_raw(p, v) stfl_p((uint8_t *)(long)(p), v) +#define stfq_raw(p, v) stfq_p((uint8_t *)(long)(p), v) + + #if defined(CONFIG_USER_ONLY) /* if user mode, no other memory access functions */ diff --git a/cpu-defs.h b/cpu-defs.h index 388d4abdb..042b1e88e 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -49,9 +49,11 @@ #if TARGET_LONG_SIZE == 4 typedef int32_t target_long; typedef uint32_t target_ulong; +#define TARGET_FMT_lx "%08x" #elif TARGET_LONG_SIZE == 8 typedef int64_t target_long; typedef uint64_t target_ulong; +#define TARGET_FMT_lx "%016llx" #else #error TARGET_LONG_SIZE undefined #endif diff --git a/cpu-exec.c b/cpu-exec.c index cc6324ca1..c428b3e38 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -106,15 +106,16 @@ int cpu_exec(CPUState *env1) int code_gen_size, ret, interrupt_request; void (*gen_func)(void); TranslationBlock *tb, **ptb; - uint8_t *tc_ptr, *cs_base, *pc; + target_ulong cs_base, pc; + uint8_t *tc_ptr; unsigned int flags; /* first we save global registers */ + saved_env = env; + env = env1; saved_T0 = T0; saved_T1 = T1; saved_T2 = T2; - saved_env = env; - env = env1; #ifdef __sparc__ /* we also save i7 because longjmp may not restore it */ asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); @@ -285,7 +286,7 @@ int cpu_exec(CPUState *env1) } } #ifdef DEBUG_EXEC - if (loglevel & CPU_LOG_EXEC) { + if ((loglevel & CPU_LOG_EXEC)) { #if defined(TARGET_I386) /* restore flags in standard format */ env->regs[R_EAX] = EAX; @@ -323,19 +324,19 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_ARM) flags = 0; cs_base = 0; - pc = (uint8_t *)env->regs[15]; + pc = env->regs[15]; #elif defined(TARGET_SPARC) flags = 0; - cs_base = (uint8_t *)env->npc; - pc = (uint8_t *) env->pc; + cs_base = env->npc; + pc = env->pc; #elif defined(TARGET_PPC) flags = 0; cs_base = 0; - pc = (uint8_t *)env->nip; + pc = env->nip; #else #error unsupported CPU #endif - tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, + tb = tb_find(&ptb, pc, cs_base, flags); if (!tb) { TranslationBlock **ptb1; @@ -350,7 +351,7 @@ int cpu_exec(CPUState *env1) regs_to_env(); /* XXX: do it just before cpu_gen_code() */ /* find translated block using physical mappings */ - phys_pc = get_phys_addr_code(env, (unsigned long)pc); + 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); @@ -359,13 +360,13 @@ int cpu_exec(CPUState *env1) tb = *ptb1; if (!tb) goto not_found; - if (tb->pc == (unsigned long)pc && + if (tb->pc == pc && tb->page_addr[0] == phys_page1 && - tb->cs_base == (unsigned long)cs_base && + tb->cs_base == cs_base && tb->flags == flags) { /* check next page if needed */ if (tb->page_addr[1] != -1) { - virt_page2 = ((unsigned long)pc & TARGET_PAGE_MASK) + + 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) @@ -378,27 +379,27 @@ int cpu_exec(CPUState *env1) } not_found: /* if no translated code available, then translate it now */ - tb = tb_alloc((unsigned long)pc); + tb = tb_alloc(pc); if (!tb) { /* flush must be done */ tb_flush(env); /* cannot fail at this point */ - tb = tb_alloc((unsigned long)pc); + tb = tb_alloc(pc); /* don't forget to invalidate previous TB info */ - ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; + ptb = &tb_hash[tb_hash_func(pc)]; T0 = 0; } tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; - tb->cs_base = (unsigned long)cs_base; + 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 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK; + virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; phys_page2 = -1; - if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) { + if ((pc & TARGET_PAGE_MASK) != virt_page2) { phys_page2 = get_phys_addr_code(env, virt_page2); } tb_link_phys(tb, phys_pc, phys_page2); @@ -408,7 +409,7 @@ int cpu_exec(CPUState *env1) /* as some TB could have been invalidated because of memory exceptions while generating the code, we must recompute the hash index here */ - ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; + ptb = &tb_hash[tb_hash_func(pc)]; while (*ptb != NULL) ptb = &(*ptb)->hash_next; T0 = 0; @@ -420,24 +421,25 @@ int cpu_exec(CPUState *env1) spin_unlock(&tb_lock); } #ifdef DEBUG_EXEC - if (loglevel & CPU_LOG_EXEC) { - fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", - (long)tb->tc_ptr, (long)tb->pc, - lookup_symbol((void *)tb->pc)); + if ((loglevel & CPU_LOG_EXEC) && (env->hflags & HF_LMA_MASK)) { + fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", + (long)tb->tc_ptr, tb->pc, + lookup_symbol(tb->pc)); } #endif #ifdef __sparc__ T0 = tmp_T0; #endif /* see if we can patch the calling TB. */ - if (T0 != 0 + { + if (T0 != 0 #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 *)(T0 & ~3), T0 & 3, tb); + tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb); #if defined(USE_CODE_COPY) /* propagates the FP use info */ ((TranslationBlock *)(T0 & ~3))->cflags |= @@ -445,6 +447,7 @@ int cpu_exec(CPUState *env1) #endif spin_unlock(&tb_lock); } + } tc_ptr = tb->tc_ptr; env->current_tb = tb; /* execute the generated code */ @@ -631,7 +634,7 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { selector &= 0xffff; cpu_x86_load_seg_cache(env, seg_reg, selector, - (uint8_t *)(selector << 4), 0xffff, 0); + (selector << 4), 0xffff, 0); } else { load_seg(seg_reg, selector); } @@ -645,7 +648,7 @@ void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) saved_env = env; env = s; - helper_fsave(ptr, data32); + helper_fsave((target_ulong)ptr, data32); env = saved_env; } @@ -657,7 +660,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) saved_env = env; env = s; - helper_frstor(ptr, data32); + helper_frstor((target_ulong)ptr, data32); env = saved_env; } diff --git a/dis-asm.h b/dis-asm.h index ebfb2993a..8c4bb5d3e 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -9,6 +9,7 @@ #ifndef DIS_ASM_H #define DIS_ASM_H +#include #include #include #include @@ -20,6 +21,8 @@ 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, diff --git a/disas.c b/disas.c index bfab8c3bb..34b047405 100644 --- a/disas.c +++ b/disas.c @@ -28,23 +28,20 @@ buffer_read_memory (memaddr, myaddr, length, info) return 0; } -#if !defined(CONFIG_USER_ONLY) /* Get LENGTH bytes from info's buffer, at target address memaddr. Transfer them to myaddr. */ static int -target_read_memory (memaddr, myaddr, length, info) - bfd_vma memaddr; - bfd_byte *myaddr; - int length; - struct disassemble_info *info; +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((void *)((long)memaddr + i)); + myaddr[i] = ldub_code(memaddr + i); } return 0; } -#endif /* Print an error message. We can assume that this is in response to an error return from buffer_read_memory. */ @@ -113,75 +110,107 @@ bfd_vma bfd_getb32 (const bfd_byte *addr) /* Disassemble this for me please... (debugging). 'flags' is only used for i386: non zero means 16 bit code */ -void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) +void target_disas(FILE *out, target_ulong code, unsigned long size, int flags) { - uint8_t *pc; + 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); -#if !defined(CONFIG_USER_ONLY) - if (!is_host) { - disasm_info.read_memory_func = target_read_memory; - } + 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) + print_insn = print_insn_arm; +#elif defined(TARGET_SPARC) + print_insn = print_insn_sparc; +#elif defined(TARGET_PPC) + print_insn = print_insn_ppc; +#else + fprintf(out, "Asm output not supported on this arch\n"); + return; #endif + for (pc = code; pc < code + size; pc += count) { +#if TARGET_LONG_BITS == 64 + fprintf(out, "0x%016llx: ", pc); +#else + fprintf(out, "0x%08x: ", pc); +#endif + 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; - if (is_host) { #ifdef WORDS_BIGENDIAN - disasm_info.endian = BFD_ENDIAN_BIG; + disasm_info.endian = BFD_ENDIAN_BIG; #else - disasm_info.endian = BFD_ENDIAN_LITTLE; + disasm_info.endian = BFD_ENDIAN_LITTLE; #endif #if defined(__i386__) - disasm_info.mach = bfd_mach_i386_i386; - print_insn = print_insn_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; + disasm_info.mach = bfd_mach_x86_64; + print_insn = print_insn_i386; #elif defined(__powerpc__) - print_insn = print_insn_ppc; + print_insn = print_insn_ppc; #elif defined(__alpha__) - print_insn = print_insn_alpha; + print_insn = print_insn_alpha; #elif defined(__sparc__) - print_insn = print_insn_sparc; + print_insn = print_insn_sparc; #elif defined(__arm__) - print_insn = print_insn_arm; -#else - fprintf(out, "Asm output not supported on this arch\n"); - return; -#endif - } else { -#ifdef TARGET_WORDS_BIGENDIAN - disasm_info.endian = BFD_ENDIAN_BIG; -#else - disasm_info.endian = BFD_ENDIAN_LITTLE; -#endif -#if defined(TARGET_I386) - if (!flags) - disasm_info.mach = bfd_mach_i386_i386; - else - disasm_info.mach = bfd_mach_i386_i8086; - print_insn = print_insn_i386; -#elif defined(TARGET_ARM) - print_insn = print_insn_arm; -#elif defined(TARGET_SPARC) - print_insn = print_insn_sparc; -#elif defined(TARGET_PPC) - print_insn = print_insn_ppc; + print_insn = print_insn_arm; #else - fprintf(out, "Asm output not supported on this arch\n"); - return; + fprintf(out, "Asm output not supported on this arch\n"); + return; #endif - } - - for (pc = code; pc < (uint8_t *)code + size; pc += count) { - fprintf(out, "0x%08lx: ", (long)pc); + for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) { + fprintf(out, "0x%08lx: ", pc); #ifdef __arm__ /* since data are included in the code, it is better to display code data too */ @@ -189,7 +218,7 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); } #endif - count = print_insn((unsigned long)pc, &disasm_info); + count = print_insn(pc, &disasm_info); fprintf(out, "\n"); if (count < 0) break; @@ -197,7 +226,7 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags) } /* Look up symbol for debugging purpose. Returns "" if unknown. */ -const char *lookup_symbol(void *orig_addr) +const char *lookup_symbol(target_ulong orig_addr) { unsigned int i; /* Hack, because we know this is x86. */ @@ -214,8 +243,8 @@ const char *lookup_symbol(void *orig_addr) if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) continue; - if ((long)orig_addr >= sym[i].st_value - && (long)orig_addr < sym[i].st_value + sym[i].st_size) + if (orig_addr >= sym[i].st_value + && orig_addr < sym[i].st_value + sym[i].st_size) return s->disas_strtab + sym[i].st_name; } } diff --git a/disas.h b/disas.h index 5d383faab..ef80fd700 100644 --- a/disas.h +++ b/disas.h @@ -2,11 +2,12 @@ #define _QEMU_DISAS_H /* Disassemble this for me please... (debugging). */ -void disas(FILE *out, void *code, unsigned long size, int is_host, int flags); +void disas(FILE *out, void *code, unsigned long size); +void target_disas(FILE *out, target_ulong code, unsigned long size, int flags); void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags); /* Look up symbol for debugging purpose. Returns "" if unknown. */ -const char *lookup_symbol(void *orig_addr); +const char *lookup_symbol(target_ulong orig_addr); /* Filled in by elfload.c. Simplistic, but will do for now. */ extern struct syminfo { diff --git a/exec-all.h b/exec-all.h index 8a47f1bb1..a9522b692 100644 --- a/exec-all.h +++ b/exec-all.h @@ -55,8 +55,10 @@ struct TranslationBlock; extern uint16_t gen_opc_buf[OPC_BUF_SIZE]; extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; -extern uint32_t gen_opc_pc[OPC_BUF_SIZE]; -extern uint32_t gen_opc_npc[OPC_BUF_SIZE]; +extern long gen_labels[OPC_BUF_SIZE]; +extern int nb_gen_labels; +extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; +extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; @@ -186,7 +188,7 @@ typedef struct TranslationBlock { struct TranslationBlock *jmp_first; } TranslationBlock; -static inline unsigned int tb_hash_func(unsigned long pc) +static inline unsigned int tb_hash_func(target_ulong pc) { return pc & (CODE_GEN_HASH_SIZE - 1); } @@ -196,7 +198,7 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc) return pc & (CODE_GEN_PHYS_HASH_SIZE - 1); } -TranslationBlock *tb_alloc(unsigned long pc); +TranslationBlock *tb_alloc(target_ulong pc); void tb_flush(CPUState *env); void tb_link(TranslationBlock *tb); void tb_link_phys(TranslationBlock *tb, @@ -329,7 +331,7 @@ do {\ "b " ASM_NAME(__op_jmp) #n "\n"\ "1:\n");\ T0 = (long)(tbparam) + (n);\ - EIP = eip;\ + EIP = (int32_t)eip;\ EXIT_TB();\ } while (0) @@ -341,6 +343,16 @@ do {\ #elif defined(__i386__) && defined(USE_DIRECT_JUMP) /* we patch the jump instruction directly */ +#define GOTO_TB(opname, n)\ +do {\ + asm volatile (".section .data\n"\ + ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\ + ".long 1f\n"\ + ASM_PREVIOUS_SECTION \ + "jmp " ASM_NAME(__op_jmp) #n "\n"\ + "1:\n");\ +} while (0) + #define JUMP_TB(opname, tbparam, n, eip)\ do {\ asm volatile (".section .data\n"\ @@ -350,7 +362,7 @@ do {\ "jmp " ASM_NAME(__op_jmp) #n "\n"\ "1:\n");\ T0 = (long)(tbparam) + (n);\ - EIP = eip;\ + EIP = (int32_t)eip;\ EXIT_TB();\ } while (0) @@ -370,7 +382,7 @@ do {\ goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ label ## n:\ T0 = (long)(tbparam) + (n);\ - EIP = eip;\ + EIP = (int32_t)eip;\ dummy_label ## n:\ EXIT_TB();\ } while (0) @@ -544,7 +556,7 @@ extern int tb_invalidated_flag; #if !defined(CONFIG_USER_ONLY) -void tlb_fill(unsigned long addr, int is_write, int is_user, +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr); #define ACCESS_TYPE 3 @@ -560,6 +572,9 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, #define DATA_SIZE 4 #include "softmmu_header.h" +#define DATA_SIZE 8 +#include "softmmu_header.h" + #undef ACCESS_TYPE #undef MEMSUFFIX #undef env @@ -578,7 +593,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) /* XXX: i386 target specific */ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) { - int is_user, index; + int is_user, index, pd; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); #if defined(TARGET_I386) @@ -592,7 +607,11 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) #endif if (__builtin_expect(env->tlb_read[is_user][index].address != (addr & TARGET_PAGE_MASK), 0)) { - ldub_code((void *)addr); + ldub_code(addr); + } + pd = env->tlb_read[is_user][index].address & ~TARGET_PAGE_MASK; + if (pd > IO_MEM_ROM) { + cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr); } return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; } diff --git a/exec.c b/exec.c index a1553ba10..3057750fe 100644 --- a/exec.c +++ b/exec.c @@ -231,6 +231,10 @@ static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) { VirtPageDesc **lp, *p; + /* XXX: should not truncate for 64 bit addresses */ +#if TARGET_LONG_BITS > 32 + index &= (L1_SIZE - 1); +#endif lp = &l1_virt_map[index >> L2_BITS]; p = *lp; if (!p) { @@ -597,13 +601,13 @@ static void tb_gen_code(CPUState *env, target_ulong phys_pc, phys_page2, virt_page2; int code_gen_size; - phys_pc = get_phys_addr_code(env, (unsigned long)pc); - tb = tb_alloc((unsigned long)pc); + phys_pc = get_phys_addr_code(env, pc); + tb = tb_alloc(pc); if (!tb) { /* flush must be done */ tb_flush(env); /* cannot fail at this point */ - tb = tb_alloc((unsigned long)pc); + tb = tb_alloc(pc); } tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; @@ -614,9 +618,9 @@ static void tb_gen_code(CPUState *env, 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 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK; + virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; phys_page2 = -1; - if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) { + if ((pc & TARGET_PAGE_MASK) != virt_page2) { phys_page2 = get_phys_addr_code(env, virt_page2); } tb_link_phys(tb, phys_pc, phys_page2); @@ -884,7 +888,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, /* Allocate a new translation block. Flush the translation buffer if too many translation blocks or too much generated code. */ -TranslationBlock *tb_alloc(unsigned long pc) +TranslationBlock *tb_alloc(target_ulong pc) { TranslationBlock *tb; @@ -1063,6 +1067,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } +#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) static void breakpoint_invalidate(CPUState *env, target_ulong pc) { target_ulong phys_addr; @@ -1070,6 +1075,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) phys_addr = cpu_get_phys_page_debug(env, pc); tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0); } +#endif /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a breakpoint is reached */ @@ -1872,7 +1878,7 @@ static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 1); #endif - stb_raw((uint8_t *)addr, val); + stb_p((uint8_t *)(long)addr, val); phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } @@ -1884,7 +1890,7 @@ static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 2); #endif - stw_raw((uint8_t *)addr, val); + stw_p((uint8_t *)(long)addr, val); phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } @@ -1896,7 +1902,7 @@ static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) #if !defined(CONFIG_USER_ONLY) tb_invalidate_phys_page_fast(phys_addr, 4); #endif - stl_raw((uint8_t *)addr, val); + stl_p((uint8_t *)(long)addr, val); phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; } @@ -1914,19 +1920,19 @@ static CPUWriteMemoryFunc *code_mem_write[3] = { static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { - stb_raw((uint8_t *)addr, val); + stb_p((uint8_t *)(long)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { - stw_raw((uint8_t *)addr, val); + stw_p((uint8_t *)(long)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { - stl_raw((uint8_t *)addr, val); + stl_p((uint8_t *)(long)addr, val); tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } @@ -2046,17 +2052,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ - val = ldl_raw(buf); + val = ldl_p(buf); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { /* 16 bit read access */ - val = lduw_raw(buf); + val = lduw_p(buf); io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); l = 2; } else { /* 8 bit access */ - val = ldub_raw(buf); + val = ldub_p(buf); io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); l = 1; } @@ -2079,17 +2085,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); - stl_raw(buf, val); + stl_p(buf, val); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { /* 16 bit read access */ val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr); - stw_raw(buf, val); + stw_p(buf, val); l = 2; } else { /* 8 bit access */ val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr); - stb_raw(buf, val); + stb_p(buf, val); l = 1; } } else { diff --git a/monitor.c b/monitor.c index bb2124631..cfb9c4975 100644 --- a/monitor.c +++ b/monitor.c @@ -438,7 +438,7 @@ static void memory_dump(int count, int format, int wsize, } while (len > 0) { - term_printf("0x%08x:", addr); + term_printf(TARGET_FMT_lx ":", addr); l = len; if (l > line_size) l = line_size; diff --git a/softmmu_header.h b/softmmu_header.h index 074d090ba..f709f704a 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -82,13 +82,14 @@ #endif -DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, +DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user); -void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, DATA_TYPE v, int is_user); +void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE v, int is_user); -#if (DATA_SIZE <= 4) && defined(__i386__) && (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) +#if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \ + (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) -static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) +static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) { int res; @@ -131,7 +132,7 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) } #if DATA_SIZE <= 2 -static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr) +static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) { int res; @@ -178,7 +179,7 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr) } #endif -static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) +static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) { asm volatile ("movl %0, %%edx\n" "movl %0, %%eax\n" @@ -232,14 +233,15 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) /* generic load/store macros */ -static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) +static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) { int index; RES_TYPE res; - unsigned long addr, physaddr; + target_ulong addr; + unsigned long physaddr; int is_user; - addr = (unsigned long)ptr; + addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; if (__builtin_expect(env->tlb_read[is_user][index].address != @@ -253,13 +255,14 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(void *ptr) } #if DATA_SIZE <= 2 -static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr) +static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) { int res, index; - unsigned long addr, physaddr; + target_ulong addr; + unsigned long physaddr; int is_user; - addr = (unsigned long)ptr; + addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; if (__builtin_expect(env->tlb_read[is_user][index].address != @@ -275,13 +278,14 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(void *ptr) /* generic store macro */ -static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) +static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) { int index; - unsigned long addr, physaddr; + target_ulong addr; + unsigned long physaddr; int is_user; - addr = (unsigned long)ptr; + addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; if (__builtin_expect(env->tlb_write[is_user][index].address != @@ -296,7 +300,7 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(void *ptr, RES_TYPE v) #endif #if DATA_SIZE == 8 -static inline double glue(ldfq, MEMSUFFIX)(void *ptr) +static inline double glue(ldfq, MEMSUFFIX)(target_ulong ptr) { union { double d; @@ -306,7 +310,7 @@ static inline double glue(ldfq, MEMSUFFIX)(void *ptr) return u.d; } -static inline void glue(stfq, MEMSUFFIX)(void *ptr, double v) +static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, double v) { union { double d; @@ -318,7 +322,7 @@ static inline void glue(stfq, MEMSUFFIX)(void *ptr, double v) #endif /* DATA_SIZE == 8 */ #if DATA_SIZE == 4 -static inline float glue(ldfl, MEMSUFFIX)(void *ptr) +static inline float glue(ldfl, MEMSUFFIX)(target_ulong ptr) { union { float f; @@ -328,7 +332,7 @@ static inline float glue(ldfl, MEMSUFFIX)(void *ptr) return u.f; } -static inline void glue(stfl, MEMSUFFIX)(void *ptr, float v) +static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float v) { union { float f; diff --git a/softmmu_template.h b/softmmu_template.h index f1abee8ac..507672693 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -45,11 +45,11 @@ #define READ_ACCESS_TYPE 0 #endif -static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user, void *retaddr); static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, - unsigned long tlb_addr) + target_ulong tlb_addr) { DATA_TYPE res; int index; @@ -70,12 +70,13 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, } /* handle all cases except unaligned access which span two pages */ -DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, +DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user) { DATA_TYPE res; int index; - unsigned long physaddr, tlb_addr; + target_ulong tlb_addr; + unsigned long physaddr; void *retaddr; /* test if there is match for unaligned or IO access */ @@ -110,13 +111,14 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, } /* handle all unaligned cases */ -static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user, void *retaddr) { DATA_TYPE res, res1, res2; int index, shift; - unsigned long physaddr, tlb_addr, addr1, addr2; + unsigned long physaddr; + target_ulong tlb_addr, addr1, addr2; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: @@ -158,14 +160,14 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, #ifndef SOFTMMU_CODE_ACCESS -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, int is_user, void *retaddr); static inline void glue(io_write, SUFFIX)(unsigned long physaddr, DATA_TYPE val, - unsigned long tlb_addr, + target_ulong tlb_addr, void *retaddr) { int index; @@ -186,11 +188,12 @@ static inline void glue(io_write, SUFFIX)(unsigned long physaddr, #endif /* SHIFT > 2 */ } -void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, +void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, int is_user) { - unsigned long physaddr, tlb_addr; + unsigned long physaddr; + target_ulong tlb_addr; void *retaddr; int index; @@ -223,12 +226,13 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, } /* handles all unaligned cases */ -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, int is_user, void *retaddr) { - unsigned long physaddr, tlb_addr; + unsigned long physaddr; + target_ulong tlb_addr; int index, i; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); diff --git a/vl.h b/vl.h index 942662127..a80d9057b 100644 --- a/vl.h +++ b/vl.h @@ -335,6 +335,18 @@ static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv) *pv = qemu_get_byte(f); } +#if TARGET_LONG_BITS == 64 +#define qemu_put_betl qemu_put_be64 +#define qemu_get_betl qemu_get_be64 +#define qemu_put_betls qemu_put_be64s +#define qemu_get_betls qemu_get_be64s +#else +#define qemu_put_betl qemu_put_be32 +#define qemu_get_betl qemu_get_be32 +#define qemu_put_betls qemu_put_be32s +#define qemu_get_betls qemu_get_be32s +#endif + int64_t qemu_ftell(QEMUFile *f); int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); @@ -628,6 +640,10 @@ uint32_t pic_intack_read(CPUState *env); void pic_info(void); void irq_info(void); +/* APIC */ +int apic_init(CPUState *env); +int apic_get_interrupt(CPUState *env); + /* i8254.c */ #define PIT_FREQ 1193182 -- cgit v1.2.3 From 20f32282379f20e83eeb2f3456ab6cc8431029b8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:36:21 +0000 Subject: initial x86_64 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1190 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/vl.c b/vl.c index a2e23a7a6..c6733ff16 100644 --- a/vl.c +++ b/vl.c @@ -268,6 +268,8 @@ void isa_unassign_ioport(int start, int length) } } +/***********************************************************/ + void pstrcpy(char *buf, int buf_size, const char *str) { int c; @@ -2064,7 +2066,7 @@ int qemu_loadvm(const char *filename) static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) { qemu_put_be32(f, dt->selector); - qemu_put_be32(f, (uint32_t)dt->base); + qemu_put_betl(f, dt->base); qemu_put_be32(f, dt->limit); qemu_put_be32(f, dt->flags); } @@ -2072,7 +2074,7 @@ static void cpu_put_seg(QEMUFile *f, SegmentCache *dt) static void cpu_get_seg(QEMUFile *f, SegmentCache *dt) { dt->selector = qemu_get_be32(f); - dt->base = (uint8_t *)qemu_get_be32(f); + dt->base = qemu_get_betl(f); dt->limit = qemu_get_be32(f); dt->flags = qemu_get_be32(f); } @@ -2084,11 +2086,11 @@ void cpu_save(QEMUFile *f, void *opaque) uint32_t hflags; int i; - for(i = 0; i < 8; i++) - qemu_put_be32s(f, &env->regs[i]); - qemu_put_be32s(f, &env->eip); - qemu_put_be32s(f, &env->eflags); - qemu_put_be32s(f, &env->eflags); + for(i = 0; i < CPU_NB_REGS; i++) + qemu_put_betls(f, &env->regs[i]); + qemu_put_betls(f, &env->eip); + qemu_put_betls(f, &env->eflags); + qemu_put_betl(f, 0); /* XXX: suppress that */ hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ qemu_put_be32s(f, &hflags); @@ -2126,13 +2128,13 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &env->sysenter_esp); qemu_put_be32s(f, &env->sysenter_eip); - qemu_put_be32s(f, &env->cr[0]); - qemu_put_be32s(f, &env->cr[2]); - qemu_put_be32s(f, &env->cr[3]); - qemu_put_be32s(f, &env->cr[4]); + qemu_put_betls(f, &env->cr[0]); + qemu_put_betls(f, &env->cr[2]); + qemu_put_betls(f, &env->cr[3]); + qemu_put_betls(f, &env->cr[4]); for(i = 0; i < 8; i++) - qemu_put_be32s(f, &env->dr[i]); + qemu_put_betls(f, &env->dr[i]); /* MMU */ qemu_put_be32s(f, &env->a20_mask); @@ -2147,11 +2149,11 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) if (version_id != 2) return -EINVAL; - for(i = 0; i < 8; i++) - qemu_get_be32s(f, &env->regs[i]); - qemu_get_be32s(f, &env->eip); - qemu_get_be32s(f, &env->eflags); - qemu_get_be32s(f, &env->eflags); + for(i = 0; i < CPU_NB_REGS; i++) + qemu_get_betls(f, &env->regs[i]); + qemu_get_betls(f, &env->eip); + qemu_get_betls(f, &env->eflags); + qemu_get_betl(f); /* XXX: suppress that */ qemu_get_be32s(f, &hflags); qemu_get_be16s(f, &fpuc); @@ -2185,13 +2187,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &env->sysenter_esp); qemu_get_be32s(f, &env->sysenter_eip); - qemu_get_be32s(f, &env->cr[0]); - qemu_get_be32s(f, &env->cr[2]); - qemu_get_be32s(f, &env->cr[3]); - qemu_get_be32s(f, &env->cr[4]); + qemu_get_betls(f, &env->cr[0]); + qemu_get_betls(f, &env->cr[2]); + qemu_get_betls(f, &env->cr[3]); + qemu_get_betls(f, &env->cr[4]); for(i = 0; i < 8; i++) - qemu_get_be32s(f, &env->dr[i]); + qemu_get_betls(f, &env->dr[i]); /* MMU */ qemu_get_be32s(f, &env->a20_mask); -- cgit v1.2.3 From 0b0babc623d1e6e0fe19a3b05a1f418edb65b371 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:38:40 +0000 Subject: x86_64 target support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1191 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 37 ++++++++++++++++++++++++++----------- configure | 15 ++++++++++----- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/Makefile.target b/Makefile.target index 933692977..b07e4903e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -1,6 +1,10 @@ include config.mak -TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) +TARGET_BASE_ARCH:=$(TARGET_ARCH) +ifeq ($(TARGET_ARCH), x86_64) +TARGET_BASE_ARCH:=i386 +endif +TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH) ifdef CONFIG_USER_ONLY @@ -8,6 +12,7 @@ VPATH+=:$(SRC_PATH)/linux-user DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) endif CFLAGS=-Wall -O2 -g -fno-strict-aliasing +#CFLAGS+=-Werror LDFLAGS=-g LIBS= HELPER_CFLAGS=$(CFLAGS) @@ -52,6 +57,12 @@ endif # ARCH != i386 endif # TARGET_ARCH = i386 +ifeq ($(TARGET_ARCH), x86_64) +ifdef CONFIG_SOFTMMU +PROGS+=$(QEMU_SYSTEM) +endif +endif # TARGET_ARCH = x86_64 + ifeq ($(TARGET_ARCH), ppc) ifeq ($(ARCH), ppc) @@ -64,11 +75,11 @@ PROGS+=$(QEMU_SYSTEM) endif endif # ARCH = i386 -ifeq ($(ARCH), amd64) +ifeq ($(ARCH), x86_64) ifdef CONFIG_SOFTMMU PROGS+=$(QEMU_SYSTEM) endif -endif # ARCH = amd64 +endif # ARCH = x86_64 endif # TARGET_ARCH = ppc @@ -84,11 +95,11 @@ PROGS+=$(QEMU_SYSTEM) endif endif # ARCH = i386 -ifeq ($(ARCH), amd64) +ifeq ($(ARCH), x86_64) ifdef CONFIG_SOFTMMU PROGS+=$(QEMU_SYSTEM) endif -endif # ARCH = amd64 +endif # ARCH = x86_64 endif # TARGET_ARCH = sparc endif # !CONFIG_USER_ONLY @@ -122,9 +133,9 @@ LDFLAGS+=-Wl,-shared endif endif -ifeq ($(ARCH),amd64) +ifeq ($(ARCH),x86_64) OP_CFLAGS=$(CFLAGS) -falign-functions=0 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/amd64.ld +LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld endif ifeq ($(ARCH),ppc) @@ -226,6 +237,10 @@ LIBOBJS+=translate-copy.o endif endif +ifeq ($(TARGET_ARCH), x86_64) +LIBOBJS+=helper.o helper2.o +endif + ifeq ($(TARGET_ARCH), ppc) LIBOBJS+= op_helper.o helper.o endif @@ -239,7 +254,7 @@ LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) USE_I386_DIS=y endif -ifeq ($(findstring amd64, $(TARGET_ARCH) $(ARCH)),amd64) +ifeq ($(findstring x86_64, $(TARGET_ARCH) $(ARCH)),x86_64) USE_I386_DIS=y endif ifdef USE_I386_DIS @@ -297,11 +312,11 @@ audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES) LIBS += $(CONFIG_FMOD_LIB) endif -ifeq ($(TARGET_ARCH), i386) +ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o -VL_OBJS+= cirrus_vga.o mixeng.o +VL_OBJS+= cirrus_vga.o mixeng.o apic.o endif ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) @@ -376,7 +391,7 @@ op.o: op.c helper.o: helper.c $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< -ifeq ($(TARGET_ARCH), i386) +ifeq ($(TARGET_BASE_ARCH), i386) op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h endif diff --git a/configure b/configure index 8d34921e4..9f7ba2b51 100755 --- a/configure +++ b/configure @@ -27,7 +27,7 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386-user i386 i386-softmmu arm-user armeb-user sparc-user ppc-user ppc-softmmu sparc-softmmu" +target_list="i386-user i386 i386-softmmu arm-user armeb-user sparc-user ppc-user ppc-softmmu sparc-softmmu x86_64-softmmu" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" @@ -63,7 +63,7 @@ case "$cpu" in cpu="m68k" ;; x86_64|amd64) - cpu="amd64" + cpu="x86_64" ;; *) cpu="unknown" @@ -383,9 +383,9 @@ echo "EXESUF=$EXESUF" >> $config_mak if test "$cpu" = "i386" ; then echo "ARCH=i386" >> $config_mak echo "#define HOST_I386 1" >> $config_h -elif test "$cpu" = "amd64" ; then - echo "ARCH=amd64" >> $config_mak - echo "#define HOST_AMD64 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 @@ -538,6 +538,11 @@ 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" = "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 else echo "Unsupported target CPU" exit 1 -- cgit v1.2.3 From 995179f1ccb9fbc88b5af70614e5ae22bf43e506 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:39:08 +0000 Subject: gcc 2.x fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1192 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-dmg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block-dmg.c b/block-dmg.c index af8b67b7a..582e3cb2f 100644 --- a/block-dmg.c +++ b/block-dmg.c @@ -109,10 +109,12 @@ dmg_close: /* read offsets */ last_in_offset = last_out_offset = 0; while(lseek(s->fd,0,SEEK_CUR)fd); if(count==0) goto dmg_close; - uint32_t type = read_uint32(s->fd); + type = read_uint32(s->fd); if(type!=0x6d697368 || count<244) lseek(s->fd,count-4,SEEK_CUR); else { -- cgit v1.2.3 From 526ff7de82fe82f83f8de966aee03fa78ff8a36f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:41:14 +0000 Subject: removed warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1193 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/nwfpe/double_cpdo.c | 2 +- target-arm/nwfpe/single_cpdo.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/nwfpe/double_cpdo.c b/target-arm/nwfpe/double_cpdo.c index 0f303ea6f..f1738eac0 100644 --- a/target-arm/nwfpe/double_cpdo.c +++ b/target-arm/nwfpe/double_cpdo.c @@ -38,7 +38,7 @@ float64 float64_pol(float64 rFn,float64 rFm); unsigned int DoubleCPDO(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); - float64 rFm, rFn; + float64 rFm, rFn = 0; unsigned int Fd, Fm, Fn, nRc = 1; //printk("DoubleCPDO(0x%08x)\n",opcode); diff --git a/target-arm/nwfpe/single_cpdo.c b/target-arm/nwfpe/single_cpdo.c index c38cb01e4..58da89b05 100644 --- a/target-arm/nwfpe/single_cpdo.c +++ b/target-arm/nwfpe/single_cpdo.c @@ -38,7 +38,7 @@ float32 float32_pol(float32 rFn,float32 rFm); unsigned int SingleCPDO(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); - float32 rFm, rFn; + float32 rFm, rFn = 0; unsigned int Fd, Fm, Fn, nRc = 1; Fm = getFm(opcode); -- cgit v1.2.3 From b4ff59872759eb491313ae4248732d9a2acc1299 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:43:09 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1194 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index a66d2e36d..6a077c58e 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -29,23 +29,6 @@ #define PSR_PS (1<<6) #define PSR_ET (1<<5) #define PSR_CWP 0x1f -/* Fake impl 0, version 4 */ -#define GET_PSR(env) ((0 << 28) | (4 << 24) | env->psr | \ - (env->psref? PSR_EF : 0) | \ - (env->psrpil << 8) | \ - (env->psrs? PSR_S : 0) | \ - (env->psrs? PSR_PS : 0) | \ - (env->psret? PSR_ET : 0) | env->cwp) - -#define PUT_PSR(env, val) do { int _tmp = val; \ - env->psr = _tmp & ~PSR_ICC; \ - env->psref = (_tmp & PSR_EF)? 1 : 0; \ - env->psrpil = (_tmp & PSR_PIL) >> 8; \ - env->psrs = (_tmp & PSR_S)? 1 : 0; \ - env->psrps = (_tmp & PSR_PS)? 1 : 0; \ - env->psret = (_tmp & PSR_ET)? 1 : 0; \ - set_cwp(_tmp & PSR_CWP & (NWINDOWS - 1)); \ - } while (0) /* Trap base register */ #define TBR_BASE_MASK 0xfffff000 @@ -171,6 +154,28 @@ int cpu_sparc_close(CPUSPARCState *s); void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f); double cpu_put_fp64(uint64_t mant, uint16_t exp); +/* Fake impl 0, version 4 */ +#define GET_PSR(env) ((0 << 28) | (4 << 24) | env->psr | \ + (env->psref? PSR_EF : 0) | \ + (env->psrpil << 8) | \ + (env->psrs? PSR_S : 0) | \ + (env->psrs? PSR_PS : 0) | \ + (env->psret? PSR_ET : 0) | env->cwp) + +#ifndef NO_CPU_IO_DEFS +void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); +#endif + +#define PUT_PSR(env, val) do { int _tmp = val; \ + env->psr = _tmp & ~PSR_ICC; \ + env->psref = (_tmp & PSR_EF)? 1 : 0; \ + env->psrpil = (_tmp & PSR_PIL) >> 8; \ + env->psrs = (_tmp & PSR_S)? 1 : 0; \ + env->psrps = (_tmp & PSR_PS)? 1 : 0; \ + env->psret = (_tmp & PSR_ET)? 1 : 0; \ + cpu_set_cwp(env, _tmp & PSR_CWP & (NWINDOWS - 1)); \ + } while (0) + struct siginfo; int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); -- cgit v1.2.3 From 0fa85d43d47151e71e63754e419340bfcff97e80 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:43:32 +0000 Subject: 64 bit target support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1195 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 10 +++++----- target-ppc/exec.h | 3 +++ target-ppc/helper.c | 6 ++---- target-ppc/op_helper_mem.h | 8 ++++---- target-ppc/op_mem.h | 44 ++++++++++++++++++++++---------------------- target-ppc/translate.c | 10 +++++----- target-sparc/helper.c | 14 +++++++++++--- target-sparc/op_helper.c | 4 ++-- target-sparc/op_mem.h | 28 ++++++++++++++-------------- target-sparc/translate.c | 23 ++++++++++++++++------- 10 files changed, 84 insertions(+), 66 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 56efa41e1..8ec392487 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -29,7 +29,7 @@ /* internal defines */ typedef struct DisasContext { - uint8_t *pc; + target_ulong pc; int is_jmp; struct TranslationBlock *tb; } DisasContext; @@ -762,10 +762,10 @@ static inline int gen_intermediate_code_internal(CPUState *env, DisasContext dc1, *dc = &dc1; uint16_t *gen_opc_end; int j, lj; - uint8_t *pc_start; + target_ulong pc_start; /* generate intermediate code */ - pc_start = (uint8_t *)tb->pc; + pc_start = tb->pc; dc->tb = tb; @@ -784,7 +784,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, while (lj < j) gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = (uint32_t)dc->pc; + gen_opc_pc[lj] = dc->pc; gen_opc_instr_start[lj] = 1; } disas_arm_insn(dc); @@ -811,7 +811,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - disas(logfile, pc_start, dc->pc - pc_start, 0, 0); + target_disas(logfile, pc_start, dc->pc - pc_start, 0); fprintf(logfile, "\n"); if (loglevel & (CPU_LOG_TB_OP)) { fprintf(logfile, "OP:\n"); diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 50c51502c..503cf26c6 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -173,4 +173,7 @@ static inline void regs_to_env(void) { } +int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu); + #endif /* !defined (__PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index de646727a..5d41fcb05 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -29,8 +29,6 @@ /*****************************************************************************/ /* PPC MMU emulation */ -int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, - int is_user, int is_softmmu); /* Perform BAT hit & translation */ static int get_bat (CPUState *env, uint32_t *real, int *prot, @@ -421,7 +419,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; @@ -782,7 +780,7 @@ void do_interrupt (CPUState *env) /* Store exception cause */ /* Get rS/rD and rA from faulting opcode */ env->spr[DSISR] |= - (ldl_code((void *)(env->nip - 4)) & 0x03FF0000) >> 16; + (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; /* data location address has been stored * when the fault has been detected */ diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index f3d5a1675..85ac91163 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -8,14 +8,14 @@ void glue(do_lsw, MEMSUFFIX) (int dst) __func__, T0, T1, dst); } for (; T1 > 3; T1 -= 4, T0 += 4) { - ugpr(dst++) = glue(ldl, MEMSUFFIX)((void *)T0); + ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0); if (dst == 32) dst = 0; } if (T1 > 0) { tmp = 0; for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { - tmp |= glue(ldub, MEMSUFFIX)((void *)T0) << sh; + tmp |= glue(ldub, MEMSUFFIX)(T0) << sh; } ugpr(dst) = tmp; } @@ -30,13 +30,13 @@ void glue(do_stsw, MEMSUFFIX) (int src) __func__, T0, T1, src); } for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(stl, MEMSUFFIX)((void *)T0, ugpr(src++)); + glue(stl, MEMSUFFIX)(T0, ugpr(src++)); if (src == 32) src = 0; } if (T1 > 0) { for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) - glue(stb, MEMSUFFIX)((void *)T0, (ugpr(src) >> sh) & 0xFF); + glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF); } } diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index b5d10cecb..f0f0cd1b3 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -2,26 +2,26 @@ void glue(do_lsw, MEMSUFFIX) (int dst); void glue(do_stsw, MEMSUFFIX) (int src); -static inline uint16_t glue(ld16r, MEMSUFFIX) (void *EA) +static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA) { uint16_t tmp = glue(lduw, MEMSUFFIX)(EA); return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); } -static inline uint32_t glue(ld32r, MEMSUFFIX) (void *EA) +static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) { uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); return ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); } -static inline void glue(st16r, MEMSUFFIX) (void *EA, uint16_t data) +static inline void glue(st16r, MEMSUFFIX) (target_ulong EA, uint16_t data) { uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8); glue(stw, MEMSUFFIX)(EA, tmp); } -static inline void glue(st32r, MEMSUFFIX) (void *EA, uint32_t data) +static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t data) { uint32_t tmp = ((data & 0xFF000000) >> 24) | ((data & 0x00FF0000) >> 8) | ((data & 0x0000FF00) << 8) | ((data & 0x000000FF) << 24); @@ -32,14 +32,14 @@ static inline void glue(st32r, MEMSUFFIX) (void *EA, uint32_t data) #define PPC_LD_OP(name, op) \ PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ { \ - T1 = glue(op, MEMSUFFIX)((void *)T0); \ + T1 = glue(op, MEMSUFFIX)(T0); \ RETURN(); \ } #define PPC_ST_OP(name, op) \ PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ { \ - glue(op, MEMSUFFIX)((void *)T0, T1); \ + glue(op, MEMSUFFIX)(T0, T1); \ RETURN(); \ } @@ -65,7 +65,7 @@ PPC_OP(glue(lmw, MEMSUFFIX)) int dst = PARAM(1); for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ldl, MEMSUFFIX)((void *)T0); + ugpr(dst) = glue(ldl, MEMSUFFIX)(T0); } RETURN(); } @@ -75,7 +75,7 @@ PPC_OP(glue(stmw, MEMSUFFIX)) int src = PARAM(1); for (; src < 32; src++, T0 += 4) { - glue(stl, MEMSUFFIX)((void *)T0, ugpr(src)); + glue(stl, MEMSUFFIX)(T0, ugpr(src)); } RETURN(); } @@ -115,7 +115,7 @@ PPC_OP(glue(stsw, MEMSUFFIX)) #define PPC_STF_OP(name, op) \ PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ { \ - glue(op, MEMSUFFIX)((void *)T0, FT1); \ + glue(op, MEMSUFFIX)(T0, FT1); \ RETURN(); \ } @@ -126,7 +126,7 @@ PPC_STF_OP(fs, stfl); #define PPC_LDF_OP(name, op) \ PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ { \ - FT1 = glue(op, MEMSUFFIX)((void *)T0); \ + FT1 = glue(op, MEMSUFFIX)(T0); \ RETURN(); \ } @@ -139,7 +139,7 @@ PPC_OP(glue(lwarx, MEMSUFFIX)) if (T0 & 0x03) { do_raise_exception(EXCP_ALIGN); } else { - T1 = glue(ldl, MEMSUFFIX)((void *)T0); + T1 = glue(ldl, MEMSUFFIX)(T0); regs->reserve = T0; } RETURN(); @@ -154,7 +154,7 @@ PPC_OP(glue(stwcx, MEMSUFFIX)) if (regs->reserve != T0) { env->crf[0] = xer_ov; } else { - glue(stl, MEMSUFFIX)((void *)T0, T1); + glue(stl, MEMSUFFIX)(T0, T1); env->crf[0] = xer_ov | 0x02; } } @@ -164,27 +164,27 @@ PPC_OP(glue(stwcx, MEMSUFFIX)) PPC_OP(glue(dcbz, MEMSUFFIX)) { - glue(stl, MEMSUFFIX)((void *)(T0 + 0x00), 0); - glue(stl, MEMSUFFIX)((void *)(T0 + 0x04), 0); - glue(stl, MEMSUFFIX)((void *)(T0 + 0x08), 0); - glue(stl, MEMSUFFIX)((void *)(T0 + 0x0C), 0); - glue(stl, MEMSUFFIX)((void *)(T0 + 0x10), 0); - glue(stl, MEMSUFFIX)((void *)(T0 + 0x14), 0); - glue(stl, MEMSUFFIX)((void *)(T0 + 0x18), 0); - glue(stl, MEMSUFFIX)((void *)(T0 + 0x1C), 0); + glue(stl, MEMSUFFIX)(T0 + 0x00, 0); + glue(stl, MEMSUFFIX)(T0 + 0x04, 0); + glue(stl, MEMSUFFIX)(T0 + 0x08, 0); + glue(stl, MEMSUFFIX)(T0 + 0x0C, 0); + glue(stl, MEMSUFFIX)(T0 + 0x10, 0); + glue(stl, MEMSUFFIX)(T0 + 0x14, 0); + glue(stl, MEMSUFFIX)(T0 + 0x18, 0); + glue(stl, MEMSUFFIX)(T0 + 0x1C, 0); RETURN(); } /* External access */ PPC_OP(glue(eciwx, MEMSUFFIX)) { - T1 = glue(ldl, MEMSUFFIX)((void *)T0); + T1 = glue(ldl, MEMSUFFIX)(T0); RETURN(); } PPC_OP(glue(ecowx, MEMSUFFIX)) { - glue(stl, MEMSUFFIX)((void *)T0, T1); + glue(stl, MEMSUFFIX)(T0, T1); RETURN(); } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4647c6e06..3974ecc73 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -131,7 +131,7 @@ static uint8_t spr_access[1024 / 2]; /* internal defines */ typedef struct DisasContext { struct TranslationBlock *tb; - uint32_t nip; + target_ulong nip; uint32_t opcode; uint32_t exception; /* Execution mode */ @@ -3029,7 +3029,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, { DisasContext ctx, *ctxp = &ctx; opc_handler_t **table, *handler; - uint32_t pc_start; + target_ulong pc_start; uint16_t *gen_opc_end; int j, lj = -1; @@ -3069,7 +3069,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.nip, 1 - msr_pr, msr_ir); } #endif - ctx.opcode = ldl_code((void *)ctx.nip); + ctx.opcode = ldl_code(ctx.nip); #if defined PPC_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", @@ -3174,8 +3174,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, cpu_dump_state(env, logfile, fprintf, 0); } if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); - disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + target_disas(logfile, pc_start, ctx.nip - pc_start, 0); fprintf(logfile, "\n"); } if (loglevel & CPU_LOG_TB_OP) { diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 76ad643eb..5fc1da1a8 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -62,7 +62,7 @@ void cpu_unlock(void) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; int ret; @@ -282,6 +282,15 @@ void set_cwp(int new_cwp) env->regwptr = env->regbase + (new_cwp * 16); } +void cpu_set_cwp(CPUState *env1, int new_cwp) +{ + CPUState *saved_env; + saved_env = env; + env = env1; + set_cwp(new_cwp); + env = saved_env; +} + /* * Begin execution of an interruption. is_int is TRUE if coming from * the int instruction. next_eip is the EIP value AFTER the interrupt @@ -318,8 +327,7 @@ void do_interrupt(int intno, int is_int, int error_code, #endif #if !defined(CONFIG_USER_ONLY) if (env->psret == 0) { - fprintf(logfile, "Trap while interrupts disabled, Error state!\n"); - qemu_system_shutdown_request(); + cpu_abort(cpu_single_env, "Trap while interrupts disabled, Error state"); return; } #endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 6dead66a8..850d8c03e 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -108,7 +108,7 @@ void helper_ld_asi(int asi, int size, int sign) if (size == 4) bswap32s(&ret); else if (size == 2) - bswap16s(&ret); + bswap16s((uint16_t *)&ret); break; default: ret = 0; @@ -198,7 +198,7 @@ void helper_st_asi(int asi, int size, int sign) if (size == 4) bswap32s(&temp); else if (size == 2) - bswap16s(&temp); + bswap16s((uint16_t *)&temp); cpu_physical_memory_write(T0, (void *) &temp, size); } diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 9c839a004..995eb27d7 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -2,13 +2,13 @@ #define SPARC_LD_OP(name, qp) \ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ { \ - T1 = glue(qp, MEMSUFFIX)((void *)T0); \ + T1 = glue(qp, MEMSUFFIX)(T0); \ } #define SPARC_ST_OP(name, op) \ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ { \ - glue(op, MEMSUFFIX)((void *)T0, T1); \ + glue(op, MEMSUFFIX)(T0, T1); \ } SPARC_LD_OP(ld, ldl); @@ -24,48 +24,48 @@ SPARC_ST_OP(sth, stw); void OPPROTO glue(op_std, MEMSUFFIX)(void) { - glue(stl, MEMSUFFIX)((void *) T0, T1); - glue(stl, MEMSUFFIX)((void *) (T0 + 4), T2); + glue(stl, MEMSUFFIX)(T0, T1); + glue(stl, MEMSUFFIX)((T0 + 4), T2); } void OPPROTO glue(op_ldstub, MEMSUFFIX)(void) { - T1 = glue(ldub, MEMSUFFIX)((void *) T0); - glue(stb, MEMSUFFIX)((void *) T0, 0xff); /* XXX: Should be Atomically */ + T1 = glue(ldub, MEMSUFFIX)(T0); + glue(stb, MEMSUFFIX)(T0, 0xff); /* XXX: Should be Atomically */ } void OPPROTO glue(op_swap, MEMSUFFIX)(void) { - unsigned int tmp = glue(ldl, MEMSUFFIX)((void *) T0); - glue(stl, MEMSUFFIX)((void *) T0, T1); /* XXX: Should be Atomically */ + unsigned int tmp = glue(ldl, MEMSUFFIX)(T0); + glue(stl, MEMSUFFIX)(T0, T1); /* XXX: Should be Atomically */ T1 = tmp; } void OPPROTO glue(op_ldd, MEMSUFFIX)(void) { - T1 = glue(ldl, MEMSUFFIX)((void *) T0); - T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4)); + T1 = glue(ldl, MEMSUFFIX)(T0); + T0 = glue(ldl, MEMSUFFIX)((T0 + 4)); } /*** Floating-point store ***/ void OPPROTO glue(op_stf, MEMSUFFIX) (void) { - glue(stfl, MEMSUFFIX)((void *) T0, FT0); + glue(stfl, MEMSUFFIX)(T0, FT0); } void OPPROTO glue(op_stdf, MEMSUFFIX) (void) { - glue(stfq, MEMSUFFIX)((void *) T0, DT0); + glue(stfq, MEMSUFFIX)(T0, DT0); } /*** Floating-point load ***/ void OPPROTO glue(op_ldf, MEMSUFFIX) (void) { - FT0 = glue(ldfl, MEMSUFFIX)((void *) T0); + FT0 = glue(ldfl, MEMSUFFIX)(T0); } void OPPROTO glue(op_lddf, MEMSUFFIX) (void) { - DT0 = glue(ldfq, MEMSUFFIX)((void *) T0); + DT0 = glue(ldfq, MEMSUFFIX)(T0); } #undef MEMSUFFIX diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 2f067958d..dc7e6dbf6 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -291,10 +291,7 @@ GEN32(gen_op_store_DT2_fpr, gen_op_store_DT2_fpr_fprf); #if defined(CONFIG_USER_ONLY) #define gen_op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) \ -static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ -{ \ -} +#define OP_LD_TABLE(width) #define supervisor(dc) 0 #else #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() @@ -614,12 +611,14 @@ static void do_fbranch(DisasContext * dc, uint32_t target, uint32_t insn) } } +#if 0 static void gen_debug(DisasContext *s, uint32_t pc) { gen_op_jmp_im(pc); gen_op_debug(); s->is_br = 1; } +#endif #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) @@ -633,7 +632,7 @@ static void disas_sparc_insn(DisasContext * dc) { unsigned int insn, opc, rs1, rs2, rd; - insn = ldl_code((uint8_t *)dc->pc); + insn = ldl_code(dc->pc); opc = GET_FIELD(insn, 0, 1); rd = GET_FIELD(insn, 2, 6); @@ -1290,6 +1289,12 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T1(rd); gen_op_swapa(insn, 1, 4, 0); break; + + /* avoid warnings */ + (void) &gen_op_stfa; + (void) &gen_op_stdfa; + (void) &gen_op_ldfa; + (void) &gen_op_lddfa; #endif default: goto illegal_insn; @@ -1520,8 +1525,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "--------------\n"); - fprintf(logfile, "IN: %s\n", lookup_symbol((uint8_t *)pc_start)); - disas(logfile, (uint8_t *)pc_start, last_pc + 4 - pc_start, 0, 0); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0); fprintf(logfile, "\n"); if (loglevel & CPU_LOG_TB_OP) { fprintf(logfile, "OP:\n"); @@ -1626,6 +1631,10 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } #else +extern int get_physical_address (CPUState *env, uint32_t *physical, int *prot, + int *access_index, uint32_t address, int rw, + int is_user); + target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { uint32_t phys_addr; -- cgit v1.2.3 From c46878786af930f8f06695371ee80ffa8acf98ef Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:44:44 +0000 Subject: labels support in dyngen git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1196 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 2 ++ dyngen-op.h | 9 +++++++++ dyngen.c | 23 ++++++++++++---------- dyngen.h | 4 +--- translate-all.c | 61 +++++++++++++++++++++++++++++++++++++++++++++------------ 5 files changed, 73 insertions(+), 26 deletions(-) create mode 100644 dyngen-op.h diff --git a/dyngen-exec.h b/dyngen-exec.h index 86087ca62..62bcbf33b 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -211,12 +211,14 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ #define EXIT_TB() asm volatile ("ret") +#define GOTO_LABEL_PARAM(n) asm volatile ("jmp __op_gen_label" #n) #endif #ifdef __x86_64__ #define EXIT_TB() asm volatile ("ret") #endif #ifdef __powerpc__ #define EXIT_TB() asm volatile ("blr") +#define GOTO_LABEL_PARAM(n) asm volatile ("b __op_gen_label" #n) #endif #ifdef __s390__ #define EXIT_TB() asm volatile ("br %r14") diff --git a/dyngen-op.h b/dyngen-op.h new file mode 100644 index 000000000..f77a4756f --- /dev/null +++ b/dyngen-op.h @@ -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; +} diff --git a/dyngen.c b/dyngen.c index ad0e83410..1138ca455 100644 --- a/dyngen.c +++ b/dyngen.c @@ -54,7 +54,7 @@ #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) #undef ELF_USES_RELOCA -#elif defined(HOST_AMD64) +#elif defined(HOST_X86_64) #define ELF_CLASS ELFCLASS64 #define ELF_ARCH EM_X86_64 @@ -1307,7 +1307,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, p_start = text + offset; p_end = p_start + size; start_offset = offset; -#if defined(HOST_I386) || defined(HOST_AMD64) +#if defined(HOST_I386) || defined(HOST_X86_64) #ifdef CONFIG_FORMAT_COFF { uint8_t *p; @@ -1482,7 +1482,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, sym_name = get_rel_sym_name(rel); if(!sym_name) continue; - if (strstart(sym_name, "__op_param", &p)) { + 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); @@ -1525,7 +1526,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; if (*sym_name && !strstart(sym_name, "__op_param", NULL) && - !strstart(sym_name, "__op_jmp", NULL)) { + !strstart(sym_name, "__op_jmp", NULL) && + !strstart(sym_name, "__op_gen_label", NULL)) { #if defined(HOST_SPARC) if (sym_name[0] == '.') { fprintf(outfile, @@ -1604,8 +1606,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } #endif - - if (val >= start_offset && val < start_offset + copy_size) { + 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, val - start_offset); } @@ -1642,6 +1643,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (strstart(sym_name, "__op_param", &p)) { snprintf(name, sizeof(name), "param%s", p); + } else if (strstart(sym_name, "__op_gen_label", &p)) { + snprintf(name, sizeof(name), "gen_labels[param%s]", p); } else { snprintf(name, sizeof(name), "(long)(&%s)", sym_name); } @@ -1693,7 +1696,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } -#elif defined(HOST_AMD64) +#elif defined(HOST_X86_64) { char name[256]; int type; @@ -1723,7 +1726,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); break; default: - error("unsupported AMD64 relocation (%d)", type); + error("unsupported X86_64 relocation (%d)", type); } } } @@ -2232,7 +2235,7 @@ int gen_file(FILE *outfile, int out_type) } } 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); @@ -2250,7 +2253,7 @@ int gen_file(FILE *outfile, int out_type) fprintf(outfile, "int dyngen_code(uint8_t *gen_code_buf,\n" " uint16_t *label_offsets, uint16_t *jmp_offsets,\n" -" const uint16_t *opc_buf, const uint32_t *opparam_buf)\n" +" 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" diff --git a/dyngen.h b/dyngen.h index a00ded775..f1ce2484c 100644 --- a/dyngen.h +++ b/dyngen.h @@ -19,6 +19,7 @@ */ int __op_param1, __op_param2, __op_param3; +int __op_gen_label1, __op_gen_label2, __op_gen_label3; int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ @@ -203,6 +204,3 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, } #endif /* __arm__ */ - - - diff --git a/translate-all.c b/translate-all.c index 1fbed4134..f6a7bc2b5 100644 --- a/translate-all.c +++ b/translate-all.c @@ -42,12 +42,15 @@ enum { uint16_t gen_opc_buf[OPC_BUF_SIZE]; uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; -uint32_t gen_opc_pc[OPC_BUF_SIZE]; +long gen_labels[OPC_BUF_SIZE]; +int nb_gen_labels; + +target_ulong gen_opc_pc[OPC_BUF_SIZE]; uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #if defined(TARGET_I386) uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; #elif defined(TARGET_SPARC) -uint32_t gen_opc_npc[OPC_BUF_SIZE]; +target_ulong gen_opc_npc[OPC_BUF_SIZE]; #endif int code_copy_enabled = 1; @@ -65,6 +68,12 @@ static uint8_t op_nb_args[] = { #undef DEF }; +static const unsigned short opc_copy_size[] = { +#define DEF(s, n, copy_size) copy_size, +#include "opc.h" +#undef DEF +}; + void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) { const uint16_t *opc_ptr; @@ -90,6 +99,35 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) #endif +/* compute label info */ +static void dyngen_labels(long *gen_labels, int nb_gen_labels, + uint8_t *gen_code_buf, const uint16_t *opc_buf) +{ + uint8_t *gen_code_ptr; + int c, i; + unsigned long gen_code_addr[OPC_BUF_SIZE]; + + if (nb_gen_labels == 0) + return; + /* compute the address of each op code */ + + gen_code_ptr = gen_code_buf; + i = 0; + for(;;) { + c = opc_buf[i]; + gen_code_addr[i] =(unsigned long)gen_code_ptr; + if (c == INDEX_op_end) + break; + gen_code_ptr += opc_copy_size[c]; + i++; + } + + /* compute the address of each label */ + for(i = 0; i < nb_gen_labels; i++) { + gen_labels[i] = gen_code_addr[gen_labels[i]]; + } +} + /* return non zero if the very first instruction is invalid so that the virtual CPU can trigger an exception. @@ -121,19 +159,21 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, tb->tb_jmp_offset[2] = 0xffff; tb->tb_jmp_offset[3] = 0xffff; #endif + dyngen_labels(gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf); + gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, #ifdef USE_DIRECT_JUMP tb->tb_jmp_offset, #else NULL, #endif - gen_opc_buf, gen_opparam_buf); + gen_opc_buf, gen_opparam_buf, gen_labels); } *gen_code_size_ptr = gen_code_size; #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_OUT_ASM) { fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); - disas(logfile, tb->tc_ptr, *gen_code_size_ptr, 1, 0); + disas(logfile, tb->tc_ptr, *gen_code_size_ptr); fprintf(logfile, "\n"); fflush(logfile); } @@ -141,12 +181,6 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, return 0; } -static const unsigned short opc_copy_size[] = { -#define DEF(s, n, copy_size) copy_size, -#include "opc.h" -#undef DEF -}; - /* The cpu state corresponding to 'searched_pc' is restored. */ int cpu_restore_state(TranslationBlock *tb, @@ -193,11 +227,12 @@ int cpu_restore_state(TranslationBlock *tb, fprintf(logfile, "RESTORE:\n"); for(i=0;i<=j; i++) { if (gen_opc_instr_start[i]) { - fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]); + fprintf(logfile, "0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]); } } - fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%x cs_base=%x\n", - searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base); + fprintf(logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", + searched_pc, j, gen_opc_pc[j] - tb->cs_base, + (uint32_t)tb->cs_base); } #endif env->eip = gen_opc_pc[j] - tb->cs_base; -- cgit v1.2.3 From 14ce26e755135e80f3726d42a5a887723d615291 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:50:08 +0000 Subject: x86_64 target support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1197 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 189 +++- target-i386/exec.h | 81 +- target-i386/helper.c | 963 +++++++++++++++--- target-i386/helper2.c | 528 +++++++--- target-i386/op.c | 552 ++++++++--- target-i386/opreg_template.h | 84 +- target-i386/ops_mem.h | 83 +- target-i386/ops_template.h | 217 ++-- target-i386/ops_template_mem.h | 114 ++- target-i386/translate-copy.c | 18 +- target-i386/translate.c | 2149 +++++++++++++++++++++++++++++----------- 11 files changed, 3678 insertions(+), 1300 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2b189ec8b..883236386 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -20,7 +20,13 @@ #ifndef CPU_I386_H #define CPU_I386_H +#include "config.h" + +#ifdef TARGET_X86_64 +#define TARGET_LONG_BITS 64 +#else #define TARGET_LONG_BITS 32 +#endif /* target supports implicit self modifying code */ #define TARGET_HAS_SMC @@ -63,6 +69,8 @@ #define DESC_G_MASK (1 << 23) #define DESC_B_SHIFT 22 #define DESC_B_MASK (1 << DESC_B_SHIFT) +#define DESC_L_SHIFT 21 /* x86_64 only : 64 bit code segment */ +#define DESC_L_MASK (1 << DESC_L_SHIFT) #define DESC_AVL_MASK (1 << 20) #define DESC_P_MASK (1 << 15) #define DESC_DPL_SHIFT 13 @@ -125,6 +133,8 @@ #define HF_EM_SHIFT 10 #define HF_TS_SHIFT 11 #define HF_IOPL_SHIFT 12 /* must be same as eflags */ +#define HF_LMA_SHIFT 14 /* only used on x86_64: long mode active */ +#define HF_CS64_SHIFT 15 /* only used on x86_64: 64 bit code segment */ #define HF_VM_SHIFT 17 /* must be same as eflags */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) @@ -138,6 +148,8 @@ #define HF_MP_MASK (1 << HF_MP_SHIFT) #define HF_EM_MASK (1 << HF_EM_SHIFT) #define HF_TS_MASK (1 << HF_TS_SHIFT) +#define HF_LMA_MASK (1 << HF_LMA_SHIFT) +#define HF_CS64_MASK (1 << HF_CS64_SHIFT) #define CR0_PE_MASK (1 << 0) #define CR0_MP_MASK (1 << 1) @@ -156,6 +168,9 @@ #define CR4_PSE_MASK (1 << 4) #define CR4_PAE_MASK (1 << 5) #define CR4_PGE_MASK (1 << 7) +#define CR4_PCE_MASK (1 << 8) +#define CR4_OSFXSR_MASK (1 << 9) +#define CR4_OSXMMEXCPT_MASK (1 << 10) #define PG_PRESENT_BIT 0 #define PG_RW_BIT 1 @@ -193,6 +208,44 @@ #define MSR_IA32_SYSENTER_ESP 0x175 #define MSR_IA32_SYSENTER_EIP 0x176 +#define MSR_EFER 0xc0000080 + +#define MSR_EFER_SCE (1 << 0) +#define MSR_EFER_LME (1 << 8) +#define MSR_EFER_LMA (1 << 10) +#define MSR_EFER_NXE (1 << 11) +#define MSR_EFER_FFXSR (1 << 14) + +#define MSR_STAR 0xc0000081 +#define MSR_LSTAR 0xc0000082 +#define MSR_CSTAR 0xc0000083 +#define MSR_FMASK 0xc0000084 +#define MSR_FSBASE 0xc0000100 +#define MSR_GSBASE 0xc0000101 +#define MSR_KERNELGSBASE 0xc0000102 + +/* cpuid_features bits */ +#define CPUID_FP87 (1 << 0) +#define CPUID_VME (1 << 1) +#define CPUID_DE (1 << 2) +#define CPUID_PSE (1 << 3) +#define CPUID_TSC (1 << 4) +#define CPUID_MSR (1 << 5) +#define CPUID_PAE (1 << 6) +#define CPUID_MCE (1 << 7) +#define CPUID_CX8 (1 << 8) +#define CPUID_APIC (1 << 9) +#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ +#define CPUID_MTRR (1 << 12) +#define CPUID_PGE (1 << 13) +#define CPUID_MCA (1 << 14) +#define CPUID_CMOV (1 << 15) +/* ... */ +#define CPUID_MMX (1 << 23) +#define CPUID_FXSR (1 << 24) +#define CPUID_SSE (1 << 25) +#define CPUID_SSE2 (1 << 26) + #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 #define EXCP02_NMI 2 @@ -219,42 +272,52 @@ enum { CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */ CC_OP_MULW, CC_OP_MULL, + CC_OP_MULQ, CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ CC_OP_ADDW, CC_OP_ADDL, + CC_OP_ADDQ, CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ CC_OP_ADCW, CC_OP_ADCL, + CC_OP_ADCQ, CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ CC_OP_SUBW, CC_OP_SUBL, + CC_OP_SUBQ, CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ CC_OP_SBBW, CC_OP_SBBL, + CC_OP_SBBQ, CC_OP_LOGICB, /* modify all flags, CC_DST = res */ CC_OP_LOGICW, CC_OP_LOGICL, + CC_OP_LOGICQ, CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */ CC_OP_INCW, CC_OP_INCL, + CC_OP_INCQ, CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */ CC_OP_DECW, CC_OP_DECL, + CC_OP_DECQ, CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.msb = C */ CC_OP_SHLW, CC_OP_SHLL, + CC_OP_SHLQ, CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ CC_OP_SARW, CC_OP_SARL, + CC_OP_SARQ, CC_OP_NB, }; @@ -271,22 +334,42 @@ typedef double CPU86_LDouble; typedef struct SegmentCache { uint32_t selector; - uint8_t *base; + target_ulong base; uint32_t limit; uint32_t flags; } SegmentCache; +typedef struct { + union { + uint8_t b[16]; + uint16_t w[8]; + uint32_t l[4]; + uint64_t q[2]; + } u; +} XMMReg; + +#ifdef TARGET_X86_64 +#define CPU_NB_REGS 16 +#else +#define CPU_NB_REGS 8 +#endif + typedef struct CPUX86State { +#if TARGET_LONG_BITS > HOST_LONG_BITS + /* temporaries if we cannot store them in host registers */ + target_ulong t0, t1, t2; +#endif + /* standard registers */ - uint32_t regs[8]; - uint32_t eip; - uint32_t eflags; /* eflags register. During CPU emulation, CC + target_ulong regs[CPU_NB_REGS]; + target_ulong eip; + target_ulong eflags; /* eflags register. During CPU emulation, CC flags and DF are set to zero because they are stored elsewhere */ /* emulator internal eflags handling */ - uint32_t cc_src; - uint32_t cc_dst; + target_ulong cc_src; + target_ulong cc_dst; uint32_t cc_op; int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ uint32_t hflags; /* hidden flags, see HF_xxx constants */ @@ -314,10 +397,21 @@ typedef struct CPUX86State { SegmentCache gdt; /* only base and limit are used */ SegmentCache idt; /* only base and limit are used */ + XMMReg xmm_regs[CPU_NB_REGS]; + XMMReg xmm_t0; + /* sysenter registers */ uint32_t sysenter_cs; uint32_t sysenter_esp; uint32_t sysenter_eip; +#ifdef TARGET_X86_64 + target_ulong efer; + target_ulong star; + target_ulong lstar; + target_ulong cstar; + target_ulong fmask; + target_ulong kernelgsbase; +#endif /* temporary data for USE_CODE_COPY mode */ #ifdef USE_CODE_COPY @@ -333,8 +427,8 @@ typedef struct CPUX86State { int exception_is_int; int exception_next_eip; struct TranslationBlock *current_tb; /* currently executing TB */ - uint32_t cr[5]; /* NOTE: cr1 is unused */ - uint32_t dr[8]; /* debug registers */ + target_ulong cr[5]; /* NOTE: cr1 is unused */ + target_ulong dr[8]; /* debug registers */ int interrupt_request; int user_mode_only; /* user mode only simulation */ @@ -346,18 +440,28 @@ typedef struct CPUX86State { context) */ unsigned long mem_write_pc; /* host pc at which the memory was written */ - unsigned long mem_write_vaddr; /* target virtual addr 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_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; /* from this point: preserved by CPU reset */ /* ice debug support */ - uint32_t breakpoints[MAX_BREAKPOINTS]; + target_ulong breakpoints[MAX_BREAKPOINTS]; int nb_breakpoints; int singlestep_enabled; + /* processor features (e.g. for CPUID insn) */ + uint32_t cpuid_vendor1; + uint32_t cpuid_vendor2; + uint32_t cpuid_vendor3; + uint32_t cpuid_version; + uint32_t cpuid_features; + + /* in order to simplify APIC support, we leave this pointer to the + user */ + struct APICState *apic_state; /* user data */ void *opaque; } CPUX86State; @@ -382,7 +486,7 @@ void cpu_set_ferr(CPUX86State *s); cache: it synchronizes the hflags with the segment cache values */ static inline void cpu_x86_load_seg_cache(CPUX86State *env, int seg_reg, unsigned int selector, - uint8_t *base, unsigned int limit, + uint32_t base, unsigned int limit, unsigned int flags) { SegmentCache *sc; @@ -395,27 +499,45 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, sc->flags = flags; /* update the hidden flags */ - new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) - >> (DESC_B_SHIFT - HF_CS32_SHIFT); - new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) - >> (DESC_B_SHIFT - HF_SS32_SHIFT); - if (!(env->cr[0] & CR0_PE_MASK) || - (env->eflags & VM_MASK) || - !(new_hflags & HF_CS32_MASK)) { - /* XXX: try to avoid this test. The problem comes from the - fact that is real mode or vm86 mode we only modify the - 'base' and 'selector' fields of the segment cache to go - faster. A solution may be to force addseg to one in - translate-i386.c. */ - new_hflags |= HF_ADDSEG_MASK; - } else { - new_hflags |= (((unsigned long)env->segs[R_DS].base | - (unsigned long)env->segs[R_ES].base | - (unsigned long)env->segs[R_SS].base) != 0) << - HF_ADDSEG_SHIFT; + { + if (seg_reg == R_CS) { +#ifdef TARGET_X86_64 + if ((env->hflags & HF_LMA_MASK) && (flags & DESC_L_MASK)) { + /* long mode */ + env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK; + env->hflags &= ~(HF_ADDSEG_MASK); + } else +#endif + { + /* legacy / compatibility case */ + new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - HF_CS32_SHIFT); + env->hflags = (env->hflags & ~(HF_CS32_MASK | HF_CS64_MASK)) | + new_hflags; + } + } + new_hflags = (env->segs[R_SS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - HF_SS32_SHIFT); + if (env->hflags & HF_CS64_MASK) { + /* zero base assumed for DS, ES and SS in long mode */ + } else if (!(env->cr[0] & CR0_PE_MASK) || + (env->eflags & VM_MASK) || + !(new_hflags & HF_CS32_MASK)) { + /* XXX: try to avoid this test. The problem comes from the + fact that is real mode or vm86 mode we only modify the + 'base' and 'selector' fields of the segment cache to go + faster. A solution may be to force addseg to one in + translate-i386.c. */ + new_hflags |= HF_ADDSEG_MASK; + } else { + new_hflags |= (((unsigned long)env->segs[R_DS].base | + (unsigned long)env->segs[R_ES].base | + (unsigned long)env->segs[R_SS].base) != 0) << + HF_ADDSEG_SHIFT; + } + env->hflags = (env->hflags & + ~(HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags; } - env->hflags = (env->hflags & - ~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags; } /* wrapper, just in case memory mappings must be changed */ @@ -448,6 +570,9 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state); uint64_t cpu_get_tsc(CPUX86State *env); +void cpu_set_apic_base(CPUX86State *env, uint64_t val); +uint64_t cpu_get_apic_base(CPUX86State *env); + /* will be suppressed */ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); diff --git a/target-i386/exec.h b/target-i386/exec.h index c0c8ca0db..00eee80f9 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -20,14 +20,29 @@ #include "config.h" #include "dyngen-exec.h" +/* XXX: factorize this mess */ +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) +#define HOST_LONG_BITS 64 +#else +#define HOST_LONG_BITS 32 +#endif + +#ifdef TARGET_X86_64 +#define TARGET_LONG_BITS 64 +#else +#define TARGET_LONG_BITS 32 +#endif + /* at least 4 register variables are defined */ register struct CPUX86State *env asm(AREG0); + +/* XXX: use 64 bit regs if HOST_LONG_BITS == 64 */ +#if TARGET_LONG_BITS == 32 + register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); register uint32_t T2 asm(AREG3); -#define A0 T2 - /* if more registers are available, we define some registers too */ #ifdef AREG4 register uint32_t EAX asm(AREG4); @@ -69,6 +84,17 @@ register uint32_t EDI asm(AREG11); #define reg_EDI #endif +#else + +/* no registers can be used */ +#define T0 (env->t0) +#define T1 (env->t1) +#define T2 (env->t2) + +#endif + +#define A0 T2 + extern FILE *logfile; extern int loglevel; @@ -136,26 +162,24 @@ void helper_movl_crN_T0(int reg); void helper_movl_drN_T0(int reg); void helper_invlpg(unsigned int addr); void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); -void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3); +void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, +int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write, int is_user, int is_softmmu); -void tlb_fill(unsigned long addr, int is_write, int is_user, +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw); + target_ulong next_eip, int is_hw); void do_interrupt_user(int intno, int is_int, int error_code, - unsigned int next_eip); + target_ulong next_eip); void raise_interrupt(int intno, int is_int, int error_code, unsigned int next_eip); void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); void __hidden cpu_loop_exit(void); -void helper_fsave(uint8_t *ptr, int data32); -void helper_frstor(uint8_t *ptr, int data32); void OPPROTO op_movl_eflags_T0(void); void OPPROTO op_movl_T0_eflags(void); @@ -163,13 +187,20 @@ void raise_interrupt(int intno, int is_int, int error_code, unsigned int next_eip); void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); -void helper_divl_EAX_T0(uint32_t eip); -void helper_idivl_EAX_T0(uint32_t eip); +void helper_divl_EAX_T0(void); +void helper_idivl_EAX_T0(void); +void helper_mulq_EAX_T0(void); +void helper_imulq_EAX_T0(void); +void helper_imulq_T0_T1(void); +void helper_divq_EAX_T0(void); +void helper_idivq_EAX_T0(void); void helper_cmpxchg8b(void); void helper_cpuid(void); void helper_enter_level(int level, int data32); void helper_sysenter(void); void helper_sysexit(void); +void helper_syscall(void); +void helper_sysret(int dflag); void helper_rdtsc(void); void helper_rdmsr(void); void helper_wrmsr(void); @@ -252,7 +283,7 @@ void check_iol_DX(void); #define stl(p, v) stl_data(p, v) #define stq(p, v) stq_data(p, v) -static inline double ldfq(void *ptr) +static inline double ldfq(target_ulong ptr) { union { double d; @@ -262,7 +293,7 @@ static inline double ldfq(void *ptr) return u.d; } -static inline void stfq(void *ptr, double v) +static inline void stfq(target_ulong ptr, double v) { union { double d; @@ -272,7 +303,7 @@ static inline void stfq(void *ptr, double v) stq(ptr, u.i); } -static inline float ldfl(void *ptr) +static inline float ldfl(target_ulong ptr) { union { float f; @@ -282,7 +313,7 @@ static inline float ldfl(void *ptr) return u.f; } -static inline void stfl(void *ptr, float v) +static inline void stfl(target_ulong ptr, float v) { union { float f; @@ -411,7 +442,7 @@ static inline void fpop(void) } #ifndef USE_X86LDOUBLE -static inline CPU86_LDouble helper_fldt(uint8_t *ptr) +static inline CPU86_LDouble helper_fldt(target_ulong ptr) { CPU86_LDoubleU temp; int upper, e; @@ -451,12 +482,12 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) #ifdef CONFIG_USER_ONLY -static inline CPU86_LDouble helper_fldt(uint8_t *ptr) +static inline CPU86_LDouble helper_fldt(target_ulong ptr) { return *(CPU86_LDouble *)ptr; } -static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) +static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) { *(CPU86_LDouble *)ptr = f; } @@ -465,7 +496,7 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) /* we use memory access macros */ -static inline CPU86_LDouble helper_fldt(uint8_t *ptr) +static inline CPU86_LDouble helper_fldt(target_ulong ptr) { CPU86_LDoubleU temp; @@ -474,7 +505,7 @@ static inline CPU86_LDouble helper_fldt(uint8_t *ptr) return temp.d; } -static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) +static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) { CPU86_LDoubleU temp; @@ -522,10 +553,12 @@ void helper_fscale(void); void helper_fsin(void); void helper_fcos(void); void helper_fxam_ST0(void); -void helper_fstenv(uint8_t *ptr, int data32); -void helper_fldenv(uint8_t *ptr, int data32); -void helper_fsave(uint8_t *ptr, int data32); -void helper_frstor(uint8_t *ptr, int data32); +void helper_fstenv(target_ulong ptr, int data32); +void helper_fldenv(target_ulong ptr, int data32); +void helper_fsave(target_ulong ptr, int data32); +void helper_frstor(target_ulong ptr, int data32); +void helper_fxsave(target_ulong ptr, int data64); +void helper_fxrstor(target_ulong ptr, int data64); void restore_native_fp_state(CPUState *env); void save_native_fp_state(CPUState *env); diff --git a/target-i386/helper.c b/target-i386/helper.c index e6686da72..3ae5b9113 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -119,7 +119,7 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, { SegmentCache *dt; int index; - uint8_t *ptr; + target_ulong ptr; if (selector & 0x4) dt = &env->ldt; @@ -143,9 +143,9 @@ static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) return limit; } -static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) +static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2) { - return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); + return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); } static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) @@ -160,7 +160,7 @@ static inline void load_seg_vm(int seg, int selector) { selector &= 0xffff; cpu_x86_load_seg_cache(env, seg, selector, - (uint8_t *)(selector << 4), 0xffff, 0); + (selector << 4), 0xffff, 0); } static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, @@ -258,13 +258,13 @@ static void switch_tss(int tss_selector, uint32_t next_eip) { int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; - uint8_t *tss_base; + target_ulong tss_base; uint32_t new_regs[8], new_segs[6]; uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap; uint32_t old_eflags, eflags_mask; SegmentCache *dt; int index; - uint8_t *ptr; + target_ulong ptr; type = (e2 >> DESC_TYPE_SHIFT) & 0xf; #ifdef DEBUG_PCALL @@ -345,7 +345,7 @@ static void switch_tss(int tss_selector, /* clear busy bit (it is restartable) */ if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { - uint8_t *ptr; + target_ulong ptr; uint32_t e2; ptr = env->gdt.base + (env->tr.selector & ~7); e2 = ldl_kernel(ptr + 4); @@ -397,7 +397,7 @@ static void switch_tss(int tss_selector, /* set busy bit */ if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { - uint8_t *ptr; + target_ulong ptr; uint32_t e2; ptr = env->gdt.base + (tss_selector & ~7); e2 = ldl_kernel(ptr + 4); @@ -445,11 +445,11 @@ static void switch_tss(int tss_selector, cpu_x86_set_cpl(env, new_segs[R_CS] & 3); /* first just selectors as the rest may trigger exceptions */ for(i = 0; i < 6; i++) - cpu_x86_load_seg_cache(env, i, new_segs[i], NULL, 0, 0); + cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); } env->ldt.selector = new_ldt & ~4; - env->ldt.base = NULL; + env->ldt.base = 0; env->ldt.limit = 0; env->ldt.flags = 0; @@ -573,7 +573,7 @@ static inline unsigned int get_sp_mask(unsigned int e2) #define POPL(ssp, sp, sp_mask, val)\ {\ - val = ldl_kernel((ssp) + (sp & (sp_mask)));\ + val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\ sp += 4;\ } @@ -582,7 +582,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw) { SegmentCache *dt; - uint8_t *ptr, *ssp; + target_ulong ptr, ssp; int type, dpl, selector, ss_dpl, cpl, sp_mask; int has_error_code, new_stack, shift; uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; @@ -703,7 +703,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; /* avoid warning */ sp_mask = 0; /* avoid warning */ - ssp = NULL; /* avoid warning */ + ssp = 0; /* avoid warning */ esp = 0; /* avoid warning */ } @@ -754,10 +754,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (new_stack) { if (env->eflags & VM_MASK) { - cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0, 0); - cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0, 0); - cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0, 0); - cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0, 0); + cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); + cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0); + cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0); + cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0); } ss = (ss & ~3) | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, @@ -780,12 +780,264 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); } +#ifdef TARGET_X86_64 + +#define PUSHQ(sp, val)\ +{\ + sp -= 8;\ + stq_kernel(sp, (val));\ +} + +#define POPQ(sp, val)\ +{\ + val = ldq_kernel(sp);\ + sp += 8;\ +} + +static inline target_ulong get_rsp_from_tss(int level) +{ + int index; + +#if 0 + printf("TR: base=" TARGET_FMT_lx " limit=%x\n", + env->tr.base, env->tr.limit); +#endif + + if (!(env->tr.flags & DESC_P_MASK)) + cpu_abort(env, "invalid tss"); + index = 8 * level + 4; + if ((index + 7) > env->tr.limit) + raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); + return ldq_kernel(env->tr.base + index); +} + +/* 64 bit interrupt */ +static void do_interrupt64(int intno, int is_int, int error_code, + target_ulong next_eip, int is_hw) +{ + SegmentCache *dt; + target_ulong ptr; + int type, dpl, selector, cpl, ist; + int has_error_code, new_stack; + uint32_t e1, e2, e3, ss; + target_ulong old_eip, esp, offset; + + has_error_code = 0; + if (!is_int && !is_hw) { + switch(intno) { + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 17: + has_error_code = 1; + break; + } + } + if (is_int) + old_eip = next_eip; + else + old_eip = env->eip; + + dt = &env->idt; + if (intno * 16 + 15 > dt->limit) + raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + ptr = dt->base + intno * 16; + e1 = ldl_kernel(ptr); + e2 = ldl_kernel(ptr + 4); + e3 = ldl_kernel(ptr + 8); + /* check gate type */ + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; + switch(type) { + case 14: /* 386 interrupt gate */ + case 15: /* 386 trap gate */ + break; + default: + raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + break; + } + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privledge if software int */ + if (is_int && dpl < cpl) + raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + /* check valid bit */ + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); + selector = e1 >> 16; + offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); + ist = e2 & 7; + if ((selector & 0xfffc) == 0) + raise_exception_err(EXCP0D_GPF, 0); + + if (load_segment(&e1, &e2, selector) != 0) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + if (dpl > cpl) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if (!(e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); + if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { + /* to inner priviledge */ + if (ist != 0) + esp = get_rsp_from_tss(ist + 3); + else + esp = get_rsp_from_tss(dpl); + ss = 0; + new_stack = 1; + } else if ((e2 & DESC_C_MASK) || dpl == cpl) { + /* to same priviledge */ + if (env->eflags & VM_MASK) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + new_stack = 0; + esp = ESP & ~0xf; /* align stack */ + dpl = cpl; + } else { + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + new_stack = 0; /* avoid warning */ + esp = 0; /* avoid warning */ + } + + PUSHQ(esp, env->segs[R_SS].selector); + PUSHQ(esp, ESP); + PUSHQ(esp, compute_eflags()); + PUSHQ(esp, env->segs[R_CS].selector); + PUSHQ(esp, old_eip); + if (has_error_code) { + PUSHQ(esp, error_code); + } + + if (new_stack) { + ss = 0 | dpl; + cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); + } + ESP = esp; + + selector = (selector & ~3) | dpl; + cpu_x86_load_seg_cache(env, R_CS, selector, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), + e2); + cpu_x86_set_cpl(env, dpl); + env->eip = offset; + + /* interrupt gate clear IF mask */ + if ((type & 1) == 0) { + env->eflags &= ~IF_MASK; + } + env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); +} + +void helper_syscall(void) +{ + int selector; + + if (!(env->efer & MSR_EFER_SCE)) { + raise_exception_err(EXCP06_ILLOP, 0); + } + selector = (env->star >> 32) & 0xffff; + if (env->hflags & HF_LMA_MASK) { + ECX = env->eip; + env->regs[11] = compute_eflags(); + + cpu_x86_set_cpl(env, 0); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + env->eflags &= ~env->fmask; + if (env->hflags & HF_CS64_MASK) + env->eip = env->lstar; + else + env->eip = env->cstar; + } else { + ECX = (uint32_t)env->eip; + + cpu_x86_set_cpl(env, 0); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); + env->eip = (uint32_t)env->star; + } +} + +void helper_sysret(int dflag) +{ + int cpl, selector; + + cpl = env->hflags & HF_CPL_MASK; + if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + selector = (env->star >> 48) & 0xffff; + if (env->hflags & HF_LMA_MASK) { + if (dflag == 2) { + cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | + DESC_L_MASK); + env->eip = ECX; + } else { + cpu_x86_load_seg_cache(env, R_CS, selector | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + env->eip = (uint32_t)ECX; + } + cpu_x86_load_seg_cache(env, R_SS, selector + 8, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + load_eflags((uint32_t)(env->regs[11]), 0xffffffff); + cpu_x86_set_cpl(env, 3); + } else { + cpu_x86_load_seg_cache(env, R_CS, selector | 3, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + env->eip = (uint32_t)ECX; + cpu_x86_load_seg_cache(env, R_SS, selector + 8, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + env->eflags |= IF_MASK; + cpu_x86_set_cpl(env, 3); + } +} +#endif + /* real mode interrupt */ static void do_interrupt_real(int intno, int is_int, int error_code, unsigned int next_eip) { SegmentCache *dt; - uint8_t *ptr, *ssp; + target_ulong ptr, ssp; int selector; uint32_t offset, esp; uint32_t old_cs, old_eip; @@ -813,16 +1065,16 @@ static void do_interrupt_real(int intno, int is_int, int error_code, ESP = (ESP & ~0xffff) | (esp & 0xffff); env->eip = offset; env->segs[R_CS].selector = selector; - env->segs[R_CS].base = (uint8_t *)(selector << 4); + env->segs[R_CS].base = (selector << 4); env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); } /* fake user mode interrupt */ void do_interrupt_user(int intno, int is_int, int error_code, - unsigned int next_eip) + target_ulong next_eip) { SegmentCache *dt; - uint8_t *ptr; + target_ulong ptr; int dpl, cpl; uint32_t e2; @@ -849,26 +1101,26 @@ void do_interrupt_user(int intno, int is_int, int error_code, * instruction. It is only relevant if is_int is TRUE. */ void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw) + target_ulong next_eip, int is_hw) { #ifdef DEBUG_PCALL if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) { if ((env->cr[0] & CR0_PE_MASK)) { static int count; - fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x pc=%08x SP=%04x:%08x", + fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, count, intno, error_code, is_int, env->hflags & HF_CPL_MASK, env->segs[R_CS].selector, EIP, (int)env->segs[R_CS].base + EIP, env->segs[R_SS].selector, ESP); if (intno == 0x0e) { - fprintf(logfile, " CR2=%08x", env->cr[2]); + fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]); } else { - fprintf(logfile, " EAX=%08x", EAX); + fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX); } fprintf(logfile, "\n"); -#if 0 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); +#if 0 { int i; uint8_t *ptr; @@ -885,7 +1137,14 @@ void do_interrupt(int intno, int is_int, int error_code, } #endif if (env->cr[0] & CR0_PE_MASK) { - do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); +#if TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + do_interrupt64(intno, is_int, error_code, next_eip, is_hw); + } else +#endif + { + do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); + } } else { do_interrupt_real(intno, is_int, error_code, next_eip); } @@ -932,20 +1191,20 @@ void raise_exception(int exception_index) #ifdef BUGGY_GCC_DIV64 /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we call it from another function */ -uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) +uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den) { *q_ptr = num / den; return num % den; } -int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) +int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den) { *q_ptr = num / den; return num % den; } #endif -void helper_divl_EAX_T0(uint32_t eip) +void helper_divl_EAX_T0(void) { unsigned int den, q, r; uint64_t num; @@ -953,20 +1212,19 @@ void helper_divl_EAX_T0(uint32_t eip) num = EAX | ((uint64_t)EDX << 32); den = T0; if (den == 0) { - EIP = eip; raise_exception(EXCP00_DIVZ); } #ifdef BUGGY_GCC_DIV64 - r = div64(&q, num, den); + r = div32(&q, num, den); #else q = (num / den); r = (num % den); #endif - EAX = q; - EDX = r; + EAX = (uint32_t)q; + EDX = (uint32_t)r; } -void helper_idivl_EAX_T0(uint32_t eip) +void helper_idivl_EAX_T0(void) { int den, q, r; int64_t num; @@ -974,17 +1232,16 @@ void helper_idivl_EAX_T0(uint32_t eip) num = EAX | ((uint64_t)EDX << 32); den = T0; if (den == 0) { - EIP = eip; raise_exception(EXCP00_DIVZ); } #ifdef BUGGY_GCC_DIV64 - r = idiv64(&q, num, den); + r = idiv32(&q, num, den); #else q = (num / den); r = (num % den); #endif - EAX = q; - EDX = r; + EAX = (uint32_t)q; + EDX = (uint32_t)r; } void helper_cmpxchg8b(void) @@ -993,9 +1250,9 @@ void helper_cmpxchg8b(void) int eflags; eflags = cc_table[CC_OP].compute_all(); - d = ldq((uint8_t *)A0); + d = ldq(A0); if (d == (((uint64_t)EDX << 32) | EAX)) { - stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); + stq(A0, ((uint64_t)ECX << 32) | EBX); eflags |= CC_Z; } else { EDX = d >> 32; @@ -1005,58 +1262,20 @@ void helper_cmpxchg8b(void) CC_SRC = eflags; } -#define CPUID_FP87 (1 << 0) -#define CPUID_VME (1 << 1) -#define CPUID_DE (1 << 2) -#define CPUID_PSE (1 << 3) -#define CPUID_TSC (1 << 4) -#define CPUID_MSR (1 << 5) -#define CPUID_PAE (1 << 6) -#define CPUID_MCE (1 << 7) -#define CPUID_CX8 (1 << 8) -#define CPUID_APIC (1 << 9) -#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ -#define CPUID_MTRR (1 << 12) -#define CPUID_PGE (1 << 13) -#define CPUID_MCA (1 << 14) -#define CPUID_CMOV (1 << 15) -/* ... */ -#define CPUID_MMX (1 << 23) -#define CPUID_FXSR (1 << 24) -#define CPUID_SSE (1 << 25) -#define CPUID_SSE2 (1 << 26) - void helper_cpuid(void) { - switch(EAX) { + switch((uint32_t)EAX) { case 0: EAX = 2; /* max EAX index supported */ - EBX = 0x756e6547; - ECX = 0x6c65746e; - EDX = 0x49656e69; + EBX = env->cpuid_vendor1; + EDX = env->cpuid_vendor2; + ECX = env->cpuid_vendor3; break; case 1: - { - int family, model, stepping; - /* EAX = 1 info */ -#if 0 - /* pentium 75-200 */ - family = 5; - model = 2; - stepping = 11; -#else - /* pentium pro */ - family = 6; - model = 1; - stepping = 3; -#endif - EAX = (family << 8) | (model << 4) | stepping; - EBX = 0; - ECX = 0; - EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | - CPUID_TSC | CPUID_MSR | CPUID_MCE | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV; - } + EAX = env->cpuid_version; + EBX = 0; + ECX = 0; + EDX = env->cpuid_features; break; default: /* cache info: needed for Pentium Pro compatibility */ @@ -1065,12 +1284,34 @@ void helper_cpuid(void) ECX = 0; EDX = 0; break; +#ifdef TARGET_X86_64 + case 0x80000000: + EAX = 0x80000008; + EBX = env->cpuid_vendor1; + EDX = env->cpuid_vendor2; + ECX = env->cpuid_vendor3; + break; + case 0x80000001: + EAX = env->cpuid_features; + EBX = 0; + ECX = 0; + /* long mode + syscall/sysret features */ + EDX = (env->cpuid_features & 0x0183F3FF) | (1 << 29) | (1 << 11); + break; + case 0x80000008: + /* virtual & phys address size in low 2 bytes. */ + EAX = 0x00003028; + EBX = 0; + ECX = 0; + EDX = 0; + break; +#endif } } void helper_enter_level(int level, int data32) { - uint8_t *ssp; + target_ulong ssp; uint32_t esp_mask, esp, ebp; esp_mask = get_sp_mask(env->segs[R_SS].flags); @@ -1105,20 +1346,26 @@ void helper_lldt_T0(void) int selector; SegmentCache *dt; uint32_t e1, e2; - int index; - uint8_t *ptr; + int index, entry_limit; + target_ulong ptr; selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) { /* XXX: NULL selector case: invalid LDT */ - env->ldt.base = NULL; + env->ldt.base = 0; env->ldt.limit = 0; } else { if (selector & 0x4) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); dt = &env->gdt; index = selector & ~7; - if ((index + 7) > dt->limit) +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) + entry_limit = 15; + else +#endif + entry_limit = 7; + if ((index + entry_limit) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ptr = dt->base + index; e1 = ldl_kernel(ptr); @@ -1127,7 +1374,17 @@ void helper_lldt_T0(void) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - load_seg_cache_raw_dt(&env->ldt, e1, e2); +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint32_t e3; + e3 = ldl_kernel(ptr + 8); + load_seg_cache_raw_dt(&env->ldt, e1, e2); + env->ldt.base |= (target_ulong)e3 << 32; + } else +#endif + { + load_seg_cache_raw_dt(&env->ldt, e1, e2); + } } env->ldt.selector = selector; } @@ -1137,13 +1394,13 @@ void helper_ltr_T0(void) int selector; SegmentCache *dt; uint32_t e1, e2; - int index, type; - uint8_t *ptr; + int index, type, entry_limit; + target_ulong ptr; selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) { - /* NULL selector case: invalid LDT */ - env->tr.base = NULL; + /* NULL selector case: invalid TR */ + env->tr.base = 0; env->tr.limit = 0; env->tr.flags = 0; } else { @@ -1151,7 +1408,13 @@ void helper_ltr_T0(void) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); dt = &env->gdt; index = selector & ~7; - if ((index + 7) > dt->limit) +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) + entry_limit = 15; + else +#endif + entry_limit = 7; + if ((index + entry_limit) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); ptr = dt->base + index; e1 = ldl_kernel(ptr); @@ -1162,7 +1425,17 @@ void helper_ltr_T0(void) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - load_seg_cache_raw_dt(&env->tr, e1, e2); +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint32_t e3; + e3 = ldl_kernel(ptr + 8); + load_seg_cache_raw_dt(&env->tr, e1, e2); + env->tr.base |= (target_ulong)e3 << 32; + } else +#endif + { + load_seg_cache_raw_dt(&env->tr, e1, e2); + } e2 |= DESC_TSS_BUSY_MASK; stl_kernel(ptr + 4, e2); } @@ -1176,14 +1449,14 @@ void load_seg(int seg_reg, int selector) int cpl, dpl, rpl; SegmentCache *dt; int index; - uint8_t *ptr; + target_ulong ptr; selector &= 0xffff; if ((selector & 0xfffc) == 0) { /* null selector case */ if (seg_reg == R_SS) raise_exception_err(EXCP0D_GPF, 0); - cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); + cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); } else { if (selector & 0x4) @@ -1196,7 +1469,7 @@ void load_seg(int seg_reg, int selector) ptr = dt->base + index; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); - + if (!(e2 & DESC_S_MASK)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); rpl = selector & 3; @@ -1247,9 +1520,10 @@ void load_seg(int seg_reg, int selector) /* protected mode jump */ void helper_ljmp_protected_T0_T1(int next_eip) { - int new_cs, new_eip, gate_cs, type; + int new_cs, gate_cs, type; uint32_t e1, e2, cpl, dpl, rpl, limit; - + target_ulong new_eip; + new_cs = T0; new_eip = T1; if ((new_cs & 0xfffc) == 0) @@ -1312,7 +1586,7 @@ void helper_ljmp_protected_T0_T1(int next_eip) if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != (DESC_S_MASK | DESC_CS_MASK))) raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); - if (((e2 & DESC_C_MASK) && (dpl > cpl)) || + if (((e2 & DESC_C_MASK) && (dpl > cpl)) || (!(e2 & DESC_C_MASK) && (dpl != cpl))) raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); if (!(e2 & DESC_P_MASK)) @@ -1336,7 +1610,7 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) { int new_cs, new_eip; uint32_t esp, esp_mask; - uint8_t *ssp; + target_ulong ssp; new_cs = T0; new_eip = T1; @@ -1354,7 +1628,7 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) ESP = (ESP & ~esp_mask) | (esp & esp_mask); env->eip = new_eip; env->segs[R_CS].selector = new_cs; - env->segs[R_CS].base = (uint8_t *)(new_cs << 4); + env->segs[R_CS].base = (new_cs << 4); } /* protected mode call */ @@ -1364,7 +1638,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; uint32_t val, limit, old_sp_mask; - uint8_t *ssp, *old_ssp; + target_ulong ssp, old_ssp; new_cs = T0; new_eip = T1; @@ -1471,7 +1745,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) get_ss_esp_from_tss(&ss, &sp, dpl); #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_PCALL) - fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=%x\n", + fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", ss, sp, param_count, ESP); #endif if ((ss & 0xfffc) == 0) @@ -1555,7 +1829,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) void helper_iret_real(int shift) { uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; - uint8_t *ssp; + target_ulong ssp; int eflags_mask; sp_mask = 0xffff; /* XXXX: use SS segment size ? */ @@ -1595,7 +1869,7 @@ static inline void validate_seg(int seg_reg, int cpl) if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { /* data or non conforming code segment */ if (dpl < cpl) { - cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0); + cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0); } } } @@ -1603,16 +1877,31 @@ static inline void validate_seg(int seg_reg, int cpl) /* protected mode iret */ static inline void helper_ret_protected(int shift, int is_iret, int addend) { - uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask; + uint32_t new_cs, new_eflags, new_ss; uint32_t new_es, new_ds, new_fs, new_gs; uint32_t e1, e2, ss_e1, ss_e2; int cpl, dpl, rpl, eflags_mask, iopl; - uint8_t *ssp; + target_ulong ssp, sp, new_eip, new_esp, sp_mask; - sp_mask = get_sp_mask(env->segs[R_SS].flags); +#ifdef TARGET_X86_64 + if (shift == 2) + sp_mask = -1; + else +#endif + sp_mask = get_sp_mask(env->segs[R_SS].flags); sp = ESP; ssp = env->segs[R_SS].base; new_eflags = 0; /* avoid warning */ +#ifdef TARGET_X86_64 + if (shift == 2) { + POPQ(sp, new_eip); + POPQ(sp, new_cs); + new_cs &= 0xffff; + if (is_iret) { + POPQ(sp, new_eflags); + } + } else +#endif if (shift == 1) { /* 32 bits */ POPL(ssp, sp, sp_mask, new_eip); @@ -1632,7 +1921,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) } #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_PCALL) { - fprintf(logfile, "lret new %04x:%08x s=%d addend=0x%x\n", + fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n", new_cs, new_eip, shift, addend); cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); } @@ -1660,7 +1949,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); sp += addend; - if (rpl == cpl) { + if (rpl == cpl && !(env->hflags & HF_CS64_MASK)) { /* return to same priledge level */ cpu_x86_load_seg_cache(env, R_CS, new_cs, get_seg_base(e1, e2), @@ -1668,6 +1957,13 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) e2); } else { /* return to different priviledge level */ +#ifdef TARGET_X86_64 + if (shift == 2) { + POPQ(sp, new_esp); + POPQ(sp, new_ss); + new_ss &= 0xffff; + } else +#endif if (shift == 1) { /* 32 bits */ POPL(ssp, sp, sp_mask, new_esp); @@ -1680,36 +1976,49 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) } #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_PCALL) { - fprintf(logfile, "new ss:esp=%04x:%08x\n", + fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n", new_ss, new_esp); } #endif - - if ((new_ss & 3) != rpl) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(ss_e2 & DESC_S_MASK) || - (ss_e2 & DESC_CS_MASK) || - !(ss_e2 & DESC_W_MASK)) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; - if (dpl != rpl) - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); - if (!(ss_e2 & DESC_P_MASK)) - raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); + if ((env->hflags & HF_LMA_MASK) && (new_ss & 0xfffc) == 0) { + /* NULL ss is allowed in long mode */ + cpu_x86_load_seg_cache(env, R_SS, new_ss, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + } else { + if ((new_ss & 3) != rpl) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (!(ss_e2 & DESC_S_MASK) || + (ss_e2 & DESC_CS_MASK) || + !(ss_e2 & DESC_W_MASK)) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; + if (dpl != rpl) + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); + if (!(ss_e2 & DESC_P_MASK)) + raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); + cpu_x86_load_seg_cache(env, R_SS, new_ss, + get_seg_base(ss_e1, ss_e2), + get_seg_limit(ss_e1, ss_e2), + ss_e2); + } cpu_x86_load_seg_cache(env, R_CS, new_cs, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); - cpu_x86_load_seg_cache(env, R_SS, new_ss, - get_seg_base(ss_e1, ss_e2), - get_seg_limit(ss_e1, ss_e2), - ss_e2); cpu_x86_set_cpl(env, rpl); sp = new_esp; - sp_mask = get_sp_mask(ss_e2); +#ifdef TARGET_X86_64 + if (shift == 2) + sp_mask = -1; + else +#endif + sp_mask = get_sp_mask(ss_e2); /* validate data segments */ validate_seg(R_ES, cpl); @@ -1765,6 +2074,10 @@ void helper_iret_protected(int shift, int next_eip) /* specific case for TSS */ if (env->eflags & NT_MASK) { +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) + raise_exception_err(EXCP0D_GPF, 0); +#endif tss_selector = lduw_kernel(env->tr.base + 0); if (tss_selector & 4) raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); @@ -1793,12 +2106,12 @@ void helper_sysenter(void) env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, - NULL, 0xffffffff, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, - NULL, 0xffffffff, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK); @@ -1816,12 +2129,12 @@ void helper_sysexit(void) } cpu_x86_set_cpl(env, 3); cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, - NULL, 0xffffffff, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, - NULL, 0xffffffff, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); @@ -1863,22 +2176,67 @@ void helper_rdtsc(void) uint64_t val; val = cpu_get_tsc(env); - EAX = val; - EDX = val >> 32; + EAX = (uint32_t)(val); + EDX = (uint32_t)(val >> 32); +} + +#if defined(CONFIG_USER_ONLY) +void helper_wrmsr(void) +{ } +void helper_rdmsr(void) +{ +} +#else void helper_wrmsr(void) { - switch(ECX) { + uint64_t val; + + val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); + + switch((uint32_t)ECX) { case MSR_IA32_SYSENTER_CS: - env->sysenter_cs = EAX & 0xffff; + env->sysenter_cs = val & 0xffff; break; case MSR_IA32_SYSENTER_ESP: - env->sysenter_esp = EAX; + env->sysenter_esp = val; break; case MSR_IA32_SYSENTER_EIP: - env->sysenter_eip = EAX; + env->sysenter_eip = val; + break; + case MSR_IA32_APICBASE: + cpu_set_apic_base(env, val); + break; +#ifdef TARGET_X86_64 + case MSR_EFER: +#define MSR_EFER_UPDATE_MASK (MSR_EFER_SCE | MSR_EFER_LME | \ + MSR_EFER_NXE | MSR_EFER_FFXSR) + env->efer = (env->efer & ~MSR_EFER_UPDATE_MASK) | + (val & MSR_EFER_UPDATE_MASK); break; + case MSR_STAR: + env->star = val; + break; + case MSR_LSTAR: + env->lstar = val; + break; + case MSR_CSTAR: + env->cstar = val; + break; + case MSR_FMASK: + env->fmask = val; + break; + case MSR_FSBASE: + env->segs[R_FS].base = val; + break; + case MSR_GSBASE: + env->segs[R_GS].base = val; + break; + case MSR_KERNELGSBASE: + env->kernelgsbase = val; + break; +#endif default: /* XXX: exception ? */ break; @@ -1887,24 +2245,55 @@ void helper_wrmsr(void) void helper_rdmsr(void) { - switch(ECX) { + uint64_t val; + switch((uint32_t)ECX) { case MSR_IA32_SYSENTER_CS: - EAX = env->sysenter_cs; - EDX = 0; + val = env->sysenter_cs; break; case MSR_IA32_SYSENTER_ESP: - EAX = env->sysenter_esp; - EDX = 0; + val = env->sysenter_esp; break; case MSR_IA32_SYSENTER_EIP: - EAX = env->sysenter_eip; - EDX = 0; + val = env->sysenter_eip; + break; + case MSR_IA32_APICBASE: + val = cpu_get_apic_base(env); + break; +#ifdef TARGET_X86_64 + case MSR_EFER: + val = env->efer; + break; + case MSR_STAR: + val = env->star; + break; + case MSR_LSTAR: + val = env->lstar; + break; + case MSR_CSTAR: + val = env->cstar; + break; + case MSR_FMASK: + val = env->fmask; + break; + case MSR_FSBASE: + val = env->segs[R_FS].base; + break; + case MSR_GSBASE: + val = env->segs[R_GS].base; break; + case MSR_KERNELGSBASE: + val = env->kernelgsbase; + break; +#endif default: /* XXX: exception ? */ + val = 0; break; } + EAX = (uint32_t)(val); + EDX = (uint32_t)(val >> 32); } +#endif void helper_lsl(void) { @@ -2055,14 +2444,14 @@ void helper_fldt_ST0_A0(void) { int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0); + env->fpregs[new_fpstt] = helper_fldt(A0); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } void helper_fstt_ST0_A0(void) { - helper_fstt(ST0, (uint8_t *)A0); + helper_fstt(ST0, A0); } void fpu_set_exception(int mask) @@ -2102,11 +2491,11 @@ void helper_fbld_ST0_A0(void) val = 0; for(i = 8; i >= 0; i--) { - v = ldub((uint8_t *)A0 + i); + v = ldub(A0 + i); val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); } tmp = val; - if (ldub((uint8_t *)A0 + 9) & 0x80) + if (ldub(A0 + 9) & 0x80) tmp = -tmp; fpush(); ST0 = tmp; @@ -2116,12 +2505,12 @@ void helper_fbst_ST0_A0(void) { CPU86_LDouble tmp; int v; - uint8_t *mem_ref, *mem_end; + target_ulong mem_ref, mem_end; int64_t val; tmp = rint(ST0); val = (int64_t)tmp; - mem_ref = (uint8_t *)A0; + mem_ref = A0; mem_end = mem_ref + 9; if (val < 0) { stb(mem_end, 0x80); @@ -2402,7 +2791,7 @@ void helper_fxam_ST0(void) } } -void helper_fstenv(uint8_t *ptr, int data32) +void helper_fstenv(target_ulong ptr, int data32) { int fpus, fptag, exp, i; uint64_t mant; @@ -2452,7 +2841,7 @@ void helper_fstenv(uint8_t *ptr, int data32) } } -void helper_fldenv(uint8_t *ptr, int data32) +void helper_fldenv(target_ulong ptr, int data32) { int i, fpus, fptag; @@ -2474,7 +2863,7 @@ void helper_fldenv(uint8_t *ptr, int data32) } } -void helper_fsave(uint8_t *ptr, int data32) +void helper_fsave(target_ulong ptr, int data32) { CPU86_LDouble tmp; int i; @@ -2502,7 +2891,7 @@ void helper_fsave(uint8_t *ptr, int data32) env->fptags[7] = 1; } -void helper_frstor(uint8_t *ptr, int data32) +void helper_frstor(target_ulong ptr, int data32) { CPU86_LDouble tmp; int i; @@ -2517,7 +2906,78 @@ void helper_frstor(uint8_t *ptr, int data32) } } -/* XXX: merge with helper_fstt ? */ +void helper_fxsave(target_ulong ptr, int data64) +{ + int fpus, fptag, i, nb_xmm_regs; + CPU86_LDouble tmp; + target_ulong addr; + + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for(i = 0; i < 8; i++) { + fptag |= ((!env->fptags[(env->fpstt + i) & 7]) << i); + } + stw(ptr, env->fpuc); + stw(ptr + 2, fpus); + stw(ptr + 4, fptag); + + addr = ptr + 0x20; + for(i = 0;i < 8; i++) { + tmp = ST(i); + helper_fstt(tmp, addr); + addr += 16; + } + + if (env->cr[4] & CR4_OSFXSR_MASK) { + /* XXX: finish it, endianness */ + stl(ptr + 0x18, 0); /* mxcsr */ + stl(ptr + 0x1c, 0); /* mxcsr_mask */ + nb_xmm_regs = 8 << data64; + addr = ptr + 0xa0; + for(i = 0; i < nb_xmm_regs; i++) { + stq(addr, env->xmm_regs[i].u.q[0]); + stq(addr, env->xmm_regs[i].u.q[1]); + addr += 16; + } + } +} + +void helper_fxrstor(target_ulong ptr, int data64) +{ + int i, fpus, fptag, nb_xmm_regs; + CPU86_LDouble tmp; + target_ulong addr; + + env->fpuc = lduw(ptr); + fpus = lduw(ptr + 2); + fptag = ldub(ptr + 4); + env->fpstt = (fpus >> 11) & 7; + env->fpus = fpus & ~0x3800; + fptag ^= 0xff; + for(i = 0;i < 8; i++) { + env->fptags[(env->fpstt + i) & 7] = ((fptag >> i) & 1); + } + + addr = ptr + 0x20; + for(i = 0;i < 8; i++) { + tmp = helper_fldt(addr); + ST(i) = tmp; + addr += 16; + } + + if (env->cr[4] & CR4_OSFXSR_MASK) { + /* XXX: finish it, endianness */ + //ldl(ptr + 0x18); + //ldl(ptr + 0x1c); + nb_xmm_regs = 8 << data64; + addr = ptr + 0xa0; + for(i = 0; i < nb_xmm_regs; i++) { + env->xmm_regs[i].u.q[0] = ldq(addr); + env->xmm_regs[i].u.q[1] = ldq(addr); + addr += 16; + } + } +} #ifndef USE_X86LDOUBLE @@ -2575,6 +3035,179 @@ CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) } #endif +#ifdef TARGET_X86_64 + +//#define DEBUG_MULDIV + +static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + *plow += a; + /* carry test */ + if (*plow < a) + (*phigh)++; + *phigh += b; +} + +static void neg128(uint64_t *plow, uint64_t *phigh) +{ + *plow = ~ *plow; + *phigh = ~ *phigh; + add128(plow, phigh, 1, 0); +} + +static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + uint32_t a0, a1, b0, b1; + uint64_t v; + + a0 = a; + a1 = a >> 32; + + b0 = b; + b1 = b >> 32; + + v = (uint64_t)a0 * (uint64_t)b0; + *plow = v; + *phigh = 0; + + v = (uint64_t)a0 * (uint64_t)b1; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b0; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b1; + *phigh += v; +#ifdef DEBUG_MULDIV + printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + a, b, *phigh, *plow); +#endif +} + +static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) +{ + int sa, sb; + sa = (a < 0); + if (sa) + a = -a; + sb = (b < 0); + if (sb) + b = -b; + mul64(plow, phigh, a, b); + if (sa ^ sb) { + neg128(plow, phigh); + } +} + +static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) +{ + uint64_t q, r, a1, a0; + int i, qb; + + a0 = *plow; + a1 = *phigh; + if (a1 == 0) { + q = a0 / b; + r = a0 % b; + *plow = q; + *phigh = r; + } else { + /* XXX: use a better algorithm */ + for(i = 0; i < 64; i++) { + if (a1 >= b) { + a1 -= b; + qb = 1; + } else { + qb = 0; + } + a1 = (a1 << 1) | (a0 >> 63); + a0 = (a0 << 1) | qb; + } +#if defined(DEBUG_MULDIV) || 1 + printf("div: 0x%016llx%016llx / 0x%016llx: q=0x%016llx r=0x%016llx\n", + *phigh, *plow, b, a0, a1); +#endif + *plow = a0; + *phigh = a1; + } +} + +static void idiv64(uint64_t *plow, uint64_t *phigh, uint64_t b) +{ + int sa, sb; + sa = ((int64_t)*phigh < 0); + if (sa) + neg128(plow, phigh); + sb = (b < 0); + if (sb) + b = -b; + div64(plow, phigh, b); + if (sa ^ sb) + *plow = - *plow; + if (sb) + *phigh = - *phigh; +} + +void helper_mulq_EAX_T0(void) +{ + uint64_t r0, r1; + + mul64(&r0, &r1, EAX, T0); + EAX = r0; + EDX = r1; + CC_DST = r0; + CC_SRC = r1; +} + +void helper_imulq_EAX_T0(void) +{ + uint64_t r0, r1; + + imul64(&r0, &r1, EAX, T0); + EAX = r0; + EDX = r1; + CC_DST = r0; + CC_SRC = (r1 != (r0 >> 63)); +} + +void helper_imulq_T0_T1(void) +{ + uint64_t r0, r1; + + imul64(&r0, &r1, T0, T1); + T0 = r0; + CC_DST = r0; + CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); +} + +void helper_divq_EAX_T0(void) +{ + uint64_t r0, r1; + if (T0 == 0) { + raise_exception(EXCP00_DIVZ); + } + r0 = EAX; + r1 = EDX; + div64(&r0, &r1, T0); + EAX = r0; + EDX = r1; +} + +void helper_idivq_EAX_T0(void) +{ + uint64_t r0, r1; + if (T0 == 0) { + raise_exception(EXCP00_DIVZ); + } + r0 = EAX; + r1 = EDX; + idiv64(&r0, &r1, T0); + EAX = r0; + EDX = r1; +} + +#endif + #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu @@ -2598,7 +3231,7 @@ CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; int ret; diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 76401d448..34307928a 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -77,6 +77,41 @@ CPUX86State *cpu_x86_init(void) asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); } #endif + { + int family, model, stepping; +#ifdef TARGET_X86_64 + env->cpuid_vendor1 = 0x68747541; /* "Auth" */ + env->cpuid_vendor2 = 0x69746e65; /* "enti" */ + env->cpuid_vendor3 = 0x444d4163; /* "cAMD" */ + family = 6; + model = 2; + stepping = 3; +#else + env->cpuid_vendor1 = 0x756e6547; /* "Genu" */ + env->cpuid_vendor2 = 0x49656e69; /* "ineI" */ + env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */ +#if 0 + /* pentium 75-200 */ + family = 5; + model = 2; + stepping = 11; +#else + /* pentium pro */ + family = 6; + model = 1; + stepping = 3; +#endif +#endif + env->cpuid_version = (family << 8) | (model << 4) | stepping; + env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE | + CPUID_TSC | CPUID_MSR | CPUID_MCE | + CPUID_CX8 | CPUID_PGE | CPUID_CMOV); +#ifdef TARGET_X86_64 + /* currently not enabled for std i386 because not fully tested */ + env->cpuid_features |= CPUID_APIC | CPUID_FXSR | CPUID_PAE | + CPUID_SSE | CPUID_SSE2; +#endif + } cpu_single_env = env; cpu_reset(env); return env; @@ -107,12 +142,12 @@ void cpu_reset(CPUX86State *env) env->tr.limit = 0xffff; env->tr.flags = DESC_P_MASK; - cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0xffff0000, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0); - cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, 0); + cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0); env->eip = 0xfff0; env->regs[R_EDX] = 0x600; /* indicate P6 processor */ @@ -136,36 +171,56 @@ void cpu_x86_close(CPUX86State *env) static const char *cc_op_str[] = { "DYNAMIC", "EFLAGS", + "MULB", "MULW", "MULL", + "MULQ", + "ADDB", "ADDW", "ADDL", + "ADDQ", + "ADCB", "ADCW", "ADCL", + "ADCQ", + "SUBB", "SUBW", "SUBL", + "SUBQ", + "SBBB", "SBBW", "SBBL", + "SBBQ", + "LOGICB", "LOGICW", "LOGICL", + "LOGICQ", + "INCB", "INCW", "INCL", + "INCQ", + "DECB", "DECW", "DECL", + "DECQ", + "SHLB", "SHLW", "SHLL", + "SHLQ", + "SARB", "SARW", "SARL", + "SARQ", }; void cpu_dump_state(CPUState *env, FILE *f, @@ -177,55 +232,147 @@ void cpu_dump_state(CPUState *env, FILE *f, static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" }; eflags = env->eflags; - cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d\n", - env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], - env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], - env->eip, eflags, - eflags & DF_MASK ? 'D' : '-', - eflags & CC_O ? 'O' : '-', - eflags & CC_S ? 'S' : '-', - eflags & CC_Z ? 'Z' : '-', - eflags & CC_A ? 'A' : '-', - eflags & CC_P ? 'P' : '-', - eflags & CC_C ? 'C' : '-', - env->hflags & HF_CPL_MASK, - (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, - (env->a20_mask >> 20) & 1); - for(i = 0; i < 6; i++) { - SegmentCache *sc = &env->segs[i]; - cpu_fprintf(f, "%s =%04x %08x %08x %08x\n", - seg_name[i], - sc->selector, - (int)sc->base, - sc->limit, - sc->flags); +#ifdef TARGET_X86_64 + if (env->hflags & HF_CS64_MASK) { + cpu_fprintf(f, + "RAX=%016llx RBX=%016llx RCX=%016llx RDX=%016llx\n" + "RSI=%016llx RDI=%016llx RBP=%016llx RSP=%016llx\n" + "R8 =%016llx R9 =%016llx R10=%016llx R11=%016llx\n" + "R12=%016llx R13=%016llx R14=%016llx R15=%016llx\n" + "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d\n", + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP], + env->regs[R_ESP], + env->regs[8], + env->regs[9], + env->regs[10], + env->regs[11], + env->regs[12], + env->regs[13], + env->regs[14], + env->regs[15], + env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-', + env->hflags & HF_CPL_MASK, + (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, + (env->a20_mask >> 20) & 1); + } else +#endif + { + cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d\n", + (uint32_t)env->regs[R_EAX], + (uint32_t)env->regs[R_EBX], + (uint32_t)env->regs[R_ECX], + (uint32_t)env->regs[R_EDX], + (uint32_t)env->regs[R_ESI], + (uint32_t)env->regs[R_EDI], + (uint32_t)env->regs[R_EBP], + (uint32_t)env->regs[R_ESP], + (uint32_t)env->eip, eflags, + eflags & DF_MASK ? 'D' : '-', + eflags & CC_O ? 'O' : '-', + eflags & CC_S ? 'S' : '-', + eflags & CC_Z ? 'Z' : '-', + eflags & CC_A ? 'A' : '-', + eflags & CC_P ? 'P' : '-', + eflags & CC_C ? 'C' : '-', + env->hflags & HF_CPL_MASK, + (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, + (env->a20_mask >> 20) & 1); + } + +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + for(i = 0; i < 6; i++) { + SegmentCache *sc = &env->segs[i]; + cpu_fprintf(f, "%s =%04x %016llx %08x %08x\n", + seg_name[i], + sc->selector, + sc->base, + sc->limit, + sc->flags); + } + cpu_fprintf(f, "LDT=%04x %016llx %08x %08x\n", + env->ldt.selector, + env->ldt.base, + env->ldt.limit, + env->ldt.flags); + cpu_fprintf(f, "TR =%04x %016llx %08x %08x\n", + env->tr.selector, + env->tr.base, + env->tr.limit, + env->tr.flags); + cpu_fprintf(f, "GDT= %016llx %08x\n", + env->gdt.base, env->gdt.limit); + cpu_fprintf(f, "IDT= %016llx %08x\n", + env->idt.base, env->idt.limit); + cpu_fprintf(f, "CR0=%08x CR2=%016llx CR3=%016llx CR4=%08x\n", + (uint32_t)env->cr[0], + env->cr[2], + env->cr[3], + (uint32_t)env->cr[4]); + } else +#endif + { + for(i = 0; i < 6; i++) { + SegmentCache *sc = &env->segs[i]; + cpu_fprintf(f, "%s =%04x %08x %08x %08x\n", + seg_name[i], + sc->selector, + (uint32_t)sc->base, + sc->limit, + sc->flags); + } + cpu_fprintf(f, "LDT=%04x %08x %08x %08x\n", + env->ldt.selector, + (uint32_t)env->ldt.base, + env->ldt.limit, + env->ldt.flags); + cpu_fprintf(f, "TR =%04x %08x %08x %08x\n", + env->tr.selector, + (uint32_t)env->tr.base, + env->tr.limit, + env->tr.flags); + cpu_fprintf(f, "GDT= %08x %08x\n", + (uint32_t)env->gdt.base, env->gdt.limit); + cpu_fprintf(f, "IDT= %08x %08x\n", + (uint32_t)env->idt.base, env->idt.limit); + cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", + (uint32_t)env->cr[0], + (uint32_t)env->cr[2], + (uint32_t)env->cr[3], + (uint32_t)env->cr[4]); } - cpu_fprintf(f, "LDT=%04x %08x %08x %08x\n", - env->ldt.selector, - (int)env->ldt.base, - env->ldt.limit, - env->ldt.flags); - cpu_fprintf(f, "TR =%04x %08x %08x %08x\n", - env->tr.selector, - (int)env->tr.base, - env->tr.limit, - env->tr.flags); - cpu_fprintf(f, "GDT= %08x %08x\n", - (int)env->gdt.base, env->gdt.limit); - cpu_fprintf(f, "IDT= %08x %08x\n", - (int)env->idt.base, env->idt.limit); - cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", - env->cr[0], env->cr[2], env->cr[3], env->cr[4]); - if (flags & X86_DUMP_CCOP) { if ((unsigned)env->cc_op < CC_OP_NB) snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]); else snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); - cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", - env->cc_src, env->cc_dst, cc_op_name); +#ifdef TARGET_X86_64 + if (env->hflags & HF_CS64_MASK) { + cpu_fprintf(f, "CCS=%016llx CCD=%016llx CCO=%-8s\n", + env->cc_src, env->cc_dst, + cc_op_name); + } else +#endif + { + cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", + (uint32_t)env->cc_src, (uint32_t)env->cc_dst, + cc_op_name); + } } if (flags & X86_DUMP_FPU) { cpu_fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", @@ -274,6 +421,24 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) { tlb_flush(env, 1); } + +#ifdef TARGET_X86_64 + if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) && + (env->efer & MSR_EFER_LME)) { + /* enter in long mode */ + /* XXX: generate an exception */ + if (!(env->cr[4] & CR4_PAE_MASK)) + return; + env->efer |= MSR_EFER_LMA; + env->hflags |= HF_LMA_MASK; + } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) && + (env->efer & MSR_EFER_LMA)) { + /* exit long mode */ + env->efer &= ~MSR_EFER_LMA; + env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK); + env->eip &= 0xffffffff; + } +#endif env->cr[0] = new_cr0 | CR0_ET_MASK; /* update PE flag in hidden flags */ @@ -286,12 +451,12 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)); } -void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3) +void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3) { env->cr[3] = new_cr3; if (env->cr[0] & CR0_PG_MASK) { #if defined(DEBUG_MMU) - printf("CR3 update: CR3=%08x\n", new_cr3); + printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3); #endif tlb_flush(env, 0); } @@ -300,7 +465,7 @@ void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3) void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) { #if defined(DEBUG_MMU) - printf("CR4 update: CR4=%08x\n", env->cr[4]); + printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]); #endif if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) != (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) { @@ -315,22 +480,51 @@ void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) tlb_flush_page(env, addr); } +static inline uint8_t *get_phys_mem_ptr(target_phys_addr_t addr) +{ + /* XXX: incorrect */ + return phys_ram_base + addr; +} + +/* WARNING: addr must be aligned */ +uint32_t ldl_phys_aligned(target_phys_addr_t addr) +{ + uint8_t *ptr; + uint32_t val; + ptr = get_phys_mem_ptr(addr); + if (!ptr) + val = 0; + else + val = ldl_raw(ptr); + return val; +} + +void stl_phys_aligned(target_phys_addr_t addr, uint32_t val) +{ + uint8_t *ptr; + ptr = get_phys_mem_ptr(addr); + if (!ptr) + return; + stl_raw(ptr, val); +} + /* return value: -1 = cannot handle fault 0 = nothing more to do 1 = generate PF fault 2 = soft MMU activation required for this block */ -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, +int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write, int is_user, int is_softmmu) { - uint8_t *pde_ptr, *pte_ptr; - uint32_t pde, pte, virt_addr, ptep; + uint32_t pdpe_addr, pde_addr, pte_addr; + uint32_t pde, pte, ptep, pdpe; int error_code, is_dirty, prot, page_size, ret; - unsigned long paddr, vaddr, page_offset; + unsigned long paddr, page_offset; + target_ulong vaddr, virt_addr; #if defined(DEBUG_MMU) - printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", + printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", addr, is_write, is_user, env->eip); #endif is_write &= 1; @@ -349,90 +543,166 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, goto do_mapping; } - /* page directory entry */ - pde_ptr = phys_ram_base + - (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask); - pde = ldl_raw(pde_ptr); - if (!(pde & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - if (is_user) { - if (!(pde & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; + + if (env->cr[4] & CR4_PAE_MASK) { + /* XXX: we only use 32 bit physical addresses */ +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint32_t pml4e_addr, pml4e; + int32_t sext; + + /* XXX: handle user + rw rights */ + /* XXX: handle NX flag */ + /* test virtual address sign extension */ + sext = (int64_t)addr >> 47; + if (sext != 0 && sext != -1) { + error_code = 0; + goto do_fault; + } + + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & + env->a20_mask; + pml4e = ldl_phys_aligned(pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (!(pml4e & PG_ACCESSED_MASK)) { + pml4e |= PG_ACCESSED_MASK; + stl_phys_aligned(pml4e_addr, pml4e); + } + + pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & + env->a20_mask; + pdpe = ldl_phys_aligned(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (!(pdpe & PG_ACCESSED_MASK)) { + pdpe |= PG_ACCESSED_MASK; + stl_phys_aligned(pdpe_addr, pdpe); + } + } else +#endif + { + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & + env->a20_mask; + pdpe = ldl_phys_aligned(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } } - is_dirty = is_write && !(pde & PG_DIRTY_MASK); - if (!(pde & PG_ACCESSED_MASK) || is_dirty) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_DIRTY_MASK; - stl_raw(pde_ptr, pde); + + pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & + env->a20_mask; + pde = ldl_phys_aligned(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; } - - pte = pde & ~0x003ff000; /* align to 4MB */ - ptep = pte; - page_size = 4096 * 1024; - virt_addr = addr & ~0x003fffff; - } else { - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - stl_raw(pde_ptr, pde); + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + page_size = 2048 * 1024; + goto handle_big_page; + } else { + /* 4 KB page */ + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl_phys_aligned(pde_addr, pde); + } + pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & + env->a20_mask; + goto handle_4k_page; } - + } else { /* page directory entry */ - pte_ptr = phys_ram_base + - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); - pte = ldl_raw(pte_ptr); - if (!(pte & PG_PRESENT_MASK)) { + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & + env->a20_mask; + pde = ldl_phys_aligned(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; } - /* combine pde and pte user and rw protections */ - ptep = pte & pde; - if (is_user) { - if (!(ptep & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(ptep & PG_RW_MASK)) - goto do_fault_protect; + /* if PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + page_size = 4096 * 1024; + handle_big_page: + if (is_user) { + if (!(pde & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pde & PG_DIRTY_MASK); + if (!(pde & PG_ACCESSED_MASK) || is_dirty) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_DIRTY_MASK; + stl_phys_aligned(pde_addr, pde); + } + + pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ + ptep = pte; + virt_addr = addr & ~(page_size - 1); } else { - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) - goto do_fault_protect; - } - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) - pte |= PG_DIRTY_MASK; - stl_raw(pte_ptr, pte); + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl_phys_aligned(pde_addr, pde); + } + + /* page directory entry */ + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & + env->a20_mask; + handle_4k_page: + pte = ldl_phys_aligned(pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + /* combine pde and pte user and rw protections */ + ptep = pte & pde; + if (is_user) { + if (!(ptep & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) + pte |= PG_DIRTY_MASK; + stl_phys_aligned(pte_addr, pte); + } + page_size = 4096; + virt_addr = addr & ~0xfff; } - page_size = 4096; - virt_addr = addr & ~0xfff; - } - /* the page can be put in the TLB */ - prot = PAGE_READ; - if (pte & PG_DIRTY_MASK) { - /* only set write access if already dirty... otherwise wait - for dirty access */ - if (is_user) { - if (ptep & PG_RW_MASK) - prot |= PAGE_WRITE; - } else { - if (!(env->cr[0] & CR0_WP_MASK) || - (ptep & PG_RW_MASK)) - prot |= PAGE_WRITE; + /* the page can be put in the TLB */ + prot = PAGE_READ; + if (pte & PG_DIRTY_MASK) { + /* only set write access if already dirty... otherwise wait + for dirty access */ + if (is_user) { + if (ptep & PG_RW_MASK) + prot |= PAGE_WRITE; + } else { + if (!(env->cr[0] & CR0_WP_MASK) || + (ptep & PG_RW_MASK)) + prot |= PAGE_WRITE; + } } } - do_mapping: pte = pte & env->a20_mask; diff --git a/target-i386/op.c b/target-i386/op.c index 21d4d8299..1daa551c2 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -22,7 +22,7 @@ #include "exec.h" /* n must be a constant to be efficient */ -static inline int lshift(int x, int n) +static inline target_long lshift(target_long x, int n) { if (n >= 0) return x << n; @@ -80,6 +80,58 @@ static inline int lshift(int x, int n) #undef REG #undef REGNAME +#ifdef TARGET_X86_64 + +#define REG (env->regs[8]) +#define REGNAME _R8 +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG (env->regs[9]) +#define REGNAME _R9 +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG (env->regs[10]) +#define REGNAME _R10 +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG (env->regs[11]) +#define REGNAME _R11 +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG (env->regs[12]) +#define REGNAME _R12 +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG (env->regs[13]) +#define REGNAME _R13 +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG (env->regs[14]) +#define REGNAME _R14 +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG (env->regs[15]) +#define REGNAME _R15 +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#endif + /* operations with flags */ /* update flags with T0 and T1 (add/sub case) */ @@ -170,6 +222,13 @@ void OPPROTO op_bswapl_T0(void) T0 = bswap32(T0); } +#ifdef TARGET_X86_64 +void OPPROTO op_bswapq_T0(void) +{ + T0 = bswap64(T0); +} +#endif + /* multiply/divide */ /* XXX: add eflags optimizations */ @@ -179,7 +238,7 @@ void OPPROTO op_mulb_AL_T0(void) { unsigned int res; res = (uint8_t)EAX * (uint8_t)T0; - EAX = (EAX & 0xffff0000) | res; + EAX = (EAX & ~0xffff) | res; CC_DST = res; CC_SRC = (res & 0xff00); } @@ -188,7 +247,7 @@ void OPPROTO op_imulb_AL_T0(void) { int res; res = (int8_t)EAX * (int8_t)T0; - EAX = (EAX & 0xffff0000) | (res & 0xffff); + EAX = (EAX & ~0xffff) | (res & 0xffff); CC_DST = res; CC_SRC = (res != (int8_t)res); } @@ -197,8 +256,8 @@ void OPPROTO op_mulw_AX_T0(void) { unsigned int res; res = (uint16_t)EAX * (uint16_t)T0; - EAX = (EAX & 0xffff0000) | (res & 0xffff); - EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + EAX = (EAX & ~0xffff) | (res & 0xffff); + EDX = (EDX & ~0xffff) | ((res >> 16) & 0xffff); CC_DST = res; CC_SRC = res >> 16; } @@ -207,8 +266,8 @@ void OPPROTO op_imulw_AX_T0(void) { int res; res = (int16_t)EAX * (int16_t)T0; - EAX = (EAX & 0xffff0000) | (res & 0xffff); - EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + EAX = (EAX & ~0xffff) | (res & 0xffff); + EDX = (EDX & ~0xffff) | ((res >> 16) & 0xffff); CC_DST = res; CC_SRC = (res != (int16_t)res); } @@ -217,10 +276,10 @@ void OPPROTO op_mull_EAX_T0(void) { uint64_t res; res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0); - EAX = res; - EDX = res >> 32; - CC_DST = res; - CC_SRC = res >> 32; + EAX = (uint32_t)res; + EDX = (uint32_t)(res >> 32); + CC_DST = (uint32_t)res; + CC_SRC = (uint32_t)(res >> 32); } void OPPROTO op_imull_EAX_T0(void) @@ -251,6 +310,23 @@ void OPPROTO op_imull_T0_T1(void) CC_SRC = (res != (int32_t)res); } +#ifdef TARGET_X86_64 +void OPPROTO op_mulq_EAX_T0(void) +{ + helper_mulq_EAX_T0(); +} + +void OPPROTO op_imulq_EAX_T0(void) +{ + helper_imulq_EAX_T0(); +} + +void OPPROTO op_imulq_T0_T1(void) +{ + helper_imulq_T0_T1(); +} +#endif + /* division, flags are undefined */ /* XXX: add exceptions for overflow */ @@ -261,12 +337,11 @@ void OPPROTO op_divb_AL_T0(void) num = (EAX & 0xffff); den = (T0 & 0xff); if (den == 0) { - EIP = PARAM1; raise_exception(EXCP00_DIVZ); } q = (num / den) & 0xff; r = (num % den) & 0xff; - EAX = (EAX & 0xffff0000) | (r << 8) | q; + EAX = (EAX & ~0xffff) | (r << 8) | q; } void OPPROTO op_idivb_AL_T0(void) @@ -276,12 +351,11 @@ void OPPROTO op_idivb_AL_T0(void) num = (int16_t)EAX; den = (int8_t)T0; if (den == 0) { - EIP = PARAM1; raise_exception(EXCP00_DIVZ); } q = (num / den) & 0xff; r = (num % den) & 0xff; - EAX = (EAX & 0xffff0000) | (r << 8) | q; + EAX = (EAX & ~0xffff) | (r << 8) | q; } void OPPROTO op_divw_AX_T0(void) @@ -291,13 +365,12 @@ void OPPROTO op_divw_AX_T0(void) num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); den = (T0 & 0xffff); if (den == 0) { - EIP = PARAM1; raise_exception(EXCP00_DIVZ); } q = (num / den) & 0xffff; r = (num % den) & 0xffff; - EAX = (EAX & 0xffff0000) | q; - EDX = (EDX & 0xffff0000) | r; + EAX = (EAX & ~0xffff) | q; + EDX = (EDX & ~0xffff) | r; } void OPPROTO op_idivw_AX_T0(void) @@ -307,30 +380,47 @@ void OPPROTO op_idivw_AX_T0(void) num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); den = (int16_t)T0; if (den == 0) { - EIP = PARAM1; raise_exception(EXCP00_DIVZ); } q = (num / den) & 0xffff; r = (num % den) & 0xffff; - EAX = (EAX & 0xffff0000) | q; - EDX = (EDX & 0xffff0000) | r; + EAX = (EAX & ~0xffff) | q; + EDX = (EDX & ~0xffff) | r; } void OPPROTO op_divl_EAX_T0(void) { - helper_divl_EAX_T0(PARAM1); + helper_divl_EAX_T0(); } void OPPROTO op_idivl_EAX_T0(void) { - helper_idivl_EAX_T0(PARAM1); + helper_idivl_EAX_T0(); } +#ifdef TARGET_X86_64 +void OPPROTO op_divq_EAX_T0(void) +{ + helper_divq_EAX_T0(); +} + +void OPPROTO op_idivq_EAX_T0(void) +{ + helper_idivq_EAX_T0(); +} +#endif + /* constant load & misc op */ +/* XXX: consistent names */ +void OPPROTO op_movl_T0_imu(void) +{ + T0 = (uint32_t)PARAM1; +} + void OPPROTO op_movl_T0_im(void) { - T0 = PARAM1; + T0 = (int32_t)PARAM1; } void OPPROTO op_addl_T0_im(void) @@ -353,9 +443,14 @@ void OPPROTO op_movl_T0_T1(void) T0 = T1; } +void OPPROTO op_movl_T1_imu(void) +{ + T1 = (uint32_t)PARAM1; +} + void OPPROTO op_movl_T1_im(void) { - T1 = PARAM1; + T1 = (int32_t)PARAM1; } void OPPROTO op_addl_T1_im(void) @@ -370,19 +465,95 @@ void OPPROTO op_movl_T1_A0(void) void OPPROTO op_movl_A0_im(void) { - A0 = PARAM1; + A0 = (uint32_t)PARAM1; } void OPPROTO op_addl_A0_im(void) { - A0 += PARAM1; + A0 = (uint32_t)(A0 + PARAM1); +} + +void OPPROTO op_movl_A0_seg(void) +{ + A0 = (uint32_t)*(target_ulong *)((char *)env + PARAM1); +} + +void OPPROTO op_addl_A0_seg(void) +{ + A0 = (uint32_t)(A0 + *(target_ulong *)((char *)env + PARAM1)); } void OPPROTO op_addl_A0_AL(void) { - A0 += (EAX & 0xff); + A0 = (uint32_t)(A0 + (EAX & 0xff)); +} + +#ifdef WORDS_BIGENDIAN +typedef union UREG64 { + struct { uint16_t v3, v2, v1, v0; } w; + struct { uint32_t v1, v0; } l; + uint64_t q; +} UREG64; +#else +typedef union UREG64 { + struct { uint16_t v0, v1, v2, v3; } w; + struct { uint32_t v0, v1; } l; + uint64_t q; +} UREG64; +#endif + +#ifdef TARGET_X86_64 + +#define PARAMQ1 \ +({\ + UREG64 __p;\ + __p.l.v1 = PARAM1;\ + __p.l.v0 = PARAM2;\ + __p.q;\ +}) + +void OPPROTO op_movq_T0_im64(void) +{ + T0 = PARAMQ1; } +void OPPROTO op_movq_A0_im(void) +{ + A0 = (int32_t)PARAM1; +} + +void OPPROTO op_movq_A0_im64(void) +{ + A0 = PARAMQ1; +} + +void OPPROTO op_addq_A0_im(void) +{ + A0 = (A0 + (int32_t)PARAM1); +} + +void OPPROTO op_addq_A0_im64(void) +{ + A0 = (A0 + PARAMQ1); +} + +void OPPROTO op_movq_A0_seg(void) +{ + A0 = *(target_ulong *)((char *)env + PARAM1); +} + +void OPPROTO op_addq_A0_seg(void) +{ + A0 += *(target_ulong *)((char *)env + PARAM1); +} + +void OPPROTO op_addq_A0_AL(void) +{ + A0 = (A0 + (EAX & 0xff)); +} + +#endif + void OPPROTO op_andl_A0_ffff(void) { A0 = A0 & 0xffff; @@ -401,29 +572,29 @@ void OPPROTO op_andl_A0_ffff(void) #include "ops_mem.h" #endif -/* used for bit operations */ +/* indirect jump */ -void OPPROTO op_add_bitw_A0_T1(void) +void OPPROTO op_jmp_T0(void) { - A0 += ((int16_t)T1 >> 4) << 1; + EIP = T0; } -void OPPROTO op_add_bitl_A0_T1(void) +void OPPROTO op_movl_eip_im(void) { - A0 += ((int32_t)T1 >> 5) << 2; + EIP = (uint32_t)PARAM1; } -/* indirect jump */ - -void OPPROTO op_jmp_T0(void) +#ifdef TARGET_X86_64 +void OPPROTO op_movq_eip_im(void) { - EIP = T0; + EIP = (int32_t)PARAM1; } -void OPPROTO op_jmp_im(void) +void OPPROTO op_movq_eip_im64(void) { - EIP = PARAM1; + EIP = PARAMQ1; } +#endif void OPPROTO op_hlt(void) { @@ -505,11 +676,10 @@ void OPPROTO op_sti_vm(void) void OPPROTO op_boundw(void) { int low, high, v; - low = ldsw((uint8_t *)A0); - high = ldsw((uint8_t *)A0 + 2); + low = ldsw(A0); + high = ldsw(A0 + 2); v = (int16_t)T0; if (v < low || v > high) { - EIP = PARAM1; raise_exception(EXCP05_BOUND); } FORCE_RET(); @@ -518,11 +688,10 @@ void OPPROTO op_boundw(void) void OPPROTO op_boundl(void) { int low, high, v; - low = ldl((uint8_t *)A0); - high = ldl((uint8_t *)A0 + 4); + low = ldl(A0); + high = ldl(A0 + 4); v = T0; if (v < low || v > high) { - EIP = PARAM1; raise_exception(EXCP05_BOUND); } FORCE_RET(); @@ -533,11 +702,6 @@ void OPPROTO op_cmpxchg8b(void) helper_cmpxchg8b(); } -void OPPROTO op_jmp(void) -{ - JUMP_TB(op_jmp, PARAM1, 0, PARAM2); -} - void OPPROTO op_movl_T0_0(void) { T0 = 0; @@ -564,6 +728,14 @@ void OPPROTO op_exit_tb(void) #include "ops_template.h" #undef SHIFT +#ifdef TARGET_X86_64 + +#define SHIFT 3 +#include "ops_template.h" +#undef SHIFT + +#endif + /* sign extend */ void OPPROTO op_movsbl_T0_T0(void) @@ -581,6 +753,11 @@ void OPPROTO op_movswl_T0_T0(void) T0 = (int16_t)T0; } +void OPPROTO op_movslq_T0_T0(void) +{ + T0 = (int32_t)T0; +} + void OPPROTO op_movzwl_T0_T0(void) { T0 = (uint16_t)T0; @@ -591,9 +768,16 @@ void OPPROTO op_movswl_EAX_AX(void) EAX = (int16_t)EAX; } +#ifdef TARGET_X86_64 +void OPPROTO op_movslq_RAX_EAX(void) +{ + EAX = (int32_t)EAX; +} +#endif + void OPPROTO op_movsbw_AX_AL(void) { - EAX = (EAX & 0xffff0000) | ((int8_t)EAX & 0xffff); + EAX = (EAX & ~0xffff) | ((int8_t)EAX & 0xffff); } void OPPROTO op_movslq_EDX_EAX(void) @@ -603,14 +787,21 @@ void OPPROTO op_movslq_EDX_EAX(void) void OPPROTO op_movswl_DX_AX(void) { - EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff); + EDX = (EDX & ~0xffff) | (((int16_t)EAX >> 15) & 0xffff); +} + +#ifdef TARGET_X86_64 +void OPPROTO op_movsqo_RDX_RAX(void) +{ + EDX = (int64_t)EAX >> 63; } +#endif /* string ops helpers */ void OPPROTO op_addl_ESI_T0(void) { - ESI += T0; + ESI = (uint32_t)(ESI + T0); } void OPPROTO op_addw_ESI_T0(void) @@ -620,7 +811,7 @@ void OPPROTO op_addw_ESI_T0(void) void OPPROTO op_addl_EDI_T0(void) { - EDI += T0; + EDI = (uint32_t)(EDI + T0); } void OPPROTO op_addw_EDI_T0(void) @@ -630,7 +821,7 @@ void OPPROTO op_addw_EDI_T0(void) void OPPROTO op_decl_ECX(void) { - ECX--; + ECX = (uint32_t)(ECX - 1); } void OPPROTO op_decw_ECX(void) @@ -638,6 +829,23 @@ void OPPROTO op_decw_ECX(void) ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff); } +#ifdef TARGET_X86_64 +void OPPROTO op_addq_ESI_T0(void) +{ + ESI = (ESI + T0); +} + +void OPPROTO op_addq_EDI_T0(void) +{ + EDI = (EDI + T0); +} + +void OPPROTO op_decq_ECX(void) +{ + ECX--; +} +#endif + /* push/pop utils */ void op_addl_A0_SS(void) @@ -647,22 +855,22 @@ void op_addl_A0_SS(void) void op_subl_A0_2(void) { - A0 -= 2; + A0 = (uint32_t)(A0 - 2); } void op_subl_A0_4(void) { - A0 -= 4; + A0 = (uint32_t)(A0 - 4); } void op_addl_ESP_4(void) { - ESP += 4; + ESP = (uint32_t)(ESP + 4); } void op_addl_ESP_2(void) { - ESP += 2; + ESP = (uint32_t)(ESP + 2); } void op_addw_ESP_4(void) @@ -677,7 +885,7 @@ void op_addw_ESP_2(void) void op_addl_ESP_im(void) { - ESP += PARAM1; + ESP = (uint32_t)(ESP + PARAM1); } void op_addw_ESP_im(void) @@ -685,6 +893,23 @@ void op_addw_ESP_im(void) ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff); } +#ifdef TARGET_X86_64 +void op_subq_A0_8(void) +{ + A0 -= 8; +} + +void op_addq_ESP_8(void) +{ + ESP += 8; +} + +void op_addq_ESP_im(void) +{ + ESP += PARAM1; +} +#endif + void OPPROTO op_rdtsc(void) { helper_rdtsc(); @@ -710,6 +935,18 @@ void OPPROTO op_sysexit(void) helper_sysexit(); } +#ifdef TARGET_X86_64 +void OPPROTO op_syscall(void) +{ + helper_syscall(); +} + +void OPPROTO op_sysret(void) +{ + helper_sysret(PARAM1); +} +#endif + void OPPROTO op_rdmsr(void) { helper_rdmsr(); @@ -868,7 +1105,7 @@ void OPPROTO op_movl_seg_T0_vm(void) /* env->segs[] access */ sc = (SegmentCache *)((char *)env + PARAM1); sc->selector = selector; - sc->base = (void *)(selector << 4); + sc->base = (selector << 4); } void OPPROTO op_movl_T0_seg(void) @@ -876,16 +1113,6 @@ void OPPROTO op_movl_T0_seg(void) T0 = env->segs[PARAM1].selector; } -void OPPROTO op_movl_A0_seg(void) -{ - A0 = *(unsigned long *)((char *)env + PARAM1); -} - -void OPPROTO op_addl_A0_seg(void) -{ - A0 += *(unsigned long *)((char *)env + PARAM1); -} - void OPPROTO op_lsl(void) { helper_lsl(); @@ -1006,6 +1233,26 @@ void OPPROTO op_movl_env_T1(void) *(uint32_t *)((char *)env + PARAM1) = T1; } +void OPPROTO op_movtl_T0_env(void) +{ + T0 = *(target_ulong *)((char *)env + PARAM1); +} + +void OPPROTO op_movtl_env_T0(void) +{ + *(target_ulong *)((char *)env + PARAM1) = T0; +} + +void OPPROTO op_movtl_T1_env(void) +{ + T1 = *(target_ulong *)((char *)env + PARAM1); +} + +void OPPROTO op_movtl_env_T1(void) +{ + *(target_ulong *)((char *)env + PARAM1) = T1; +} + void OPPROTO op_clts(void) { env->cr[0] &= ~CR0_TS_MASK; @@ -1014,25 +1261,31 @@ void OPPROTO op_clts(void) /* flags handling */ -/* slow jumps cases : in order to avoid calling a function with a - pointer (which can generate a stack frame on PowerPC), we use - op_setcc to set T0 and then call op_jcc. */ -void OPPROTO op_jcc(void) +void OPPROTO op_goto_tb0(void) { - if (T0) - JUMP_TB(op_jcc, PARAM1, 0, PARAM2); - else - JUMP_TB(op_jcc, PARAM1, 1, PARAM3); - FORCE_RET(); + GOTO_TB(op_goto_tb0, 0); +} + +void OPPROTO op_goto_tb1(void) +{ + GOTO_TB(op_goto_tb1, 1); +} + +void OPPROTO op_jmp_label(void) +{ + GOTO_LABEL_PARAM(1); } -void OPPROTO op_jcc_im(void) +void OPPROTO op_jnz_T0_label(void) { if (T0) - EIP = PARAM1; - else - EIP = PARAM2; - FORCE_RET(); + GOTO_LABEL_PARAM(1); +} + +void OPPROTO op_jz_T0_label(void) +{ + if (!T0) + GOTO_LABEL_PARAM(1); } /* slow set cases (compute x86 flags) */ @@ -1299,6 +1552,28 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl }, [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl }, [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl }, + +#ifdef TARGET_X86_64 + [CC_OP_MULQ] = { compute_all_mulq, compute_c_mull }, + + [CC_OP_ADDQ] = { compute_all_addq, compute_c_addq }, + + [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq }, + + [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq }, + + [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq }, + + [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq }, + + [CC_OP_INCQ] = { compute_all_incq, compute_c_incl }, + + [CC_OP_DECQ] = { compute_all_decq, compute_c_incl }, + + [CC_OP_SHLQ] = { compute_all_shlq, compute_c_shlq }, + + [CC_OP_SARQ] = { compute_all_sarq, compute_c_sarl }, +#endif }; /* floating point support. Some of the code for complicated x87 @@ -1330,20 +1605,20 @@ double qemu_rint(double x) void OPPROTO op_flds_FT0_A0(void) { #ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldl((void *)A0); + FP_CONVERT.i32 = ldl(A0); FT0 = FP_CONVERT.f; #else - FT0 = ldfl((void *)A0); + FT0 = ldfl(A0); #endif } void OPPROTO op_fldl_FT0_A0(void) { #ifdef USE_FP_CONVERT - FP_CONVERT.i64 = ldq((void *)A0); + FP_CONVERT.i64 = ldq(A0); FT0 = FP_CONVERT.d; #else - FT0 = ldfq((void *)A0); + FT0 = ldfq(A0); #endif } @@ -1352,17 +1627,17 @@ void OPPROTO op_fldl_FT0_A0(void) void helper_fild_FT0_A0(void) { - FT0 = (CPU86_LDouble)ldsw((void *)A0); + FT0 = (CPU86_LDouble)ldsw(A0); } void helper_fildl_FT0_A0(void) { - FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + FT0 = (CPU86_LDouble)((int32_t)ldl(A0)); } void helper_fildll_FT0_A0(void) { - FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + FT0 = (CPU86_LDouble)((int64_t)ldq(A0)); } void OPPROTO op_fild_FT0_A0(void) @@ -1385,30 +1660,30 @@ void OPPROTO op_fildll_FT0_A0(void) void OPPROTO op_fild_FT0_A0(void) { #ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldsw((void *)A0); + FP_CONVERT.i32 = ldsw(A0); FT0 = (CPU86_LDouble)FP_CONVERT.i32; #else - FT0 = (CPU86_LDouble)ldsw((void *)A0); + FT0 = (CPU86_LDouble)ldsw(A0); #endif } void OPPROTO op_fildl_FT0_A0(void) { #ifdef USE_FP_CONVERT - FP_CONVERT.i32 = (int32_t) ldl((void *)A0); + FP_CONVERT.i32 = (int32_t) ldl(A0); FT0 = (CPU86_LDouble)FP_CONVERT.i32; #else - FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + FT0 = (CPU86_LDouble)((int32_t)ldl(A0)); #endif } void OPPROTO op_fildll_FT0_A0(void) { #ifdef USE_FP_CONVERT - FP_CONVERT.i64 = (int64_t) ldq((void *)A0); + FP_CONVERT.i64 = (int64_t) ldq(A0); FT0 = (CPU86_LDouble)FP_CONVERT.i64; #else - FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + FT0 = (CPU86_LDouble)((int64_t)ldq(A0)); #endif } #endif @@ -1420,10 +1695,10 @@ void OPPROTO op_flds_ST0_A0(void) int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldl((void *)A0); + FP_CONVERT.i32 = ldl(A0); env->fpregs[new_fpstt] = FP_CONVERT.f; #else - env->fpregs[new_fpstt] = ldfl((void *)A0); + env->fpregs[new_fpstt] = ldfl(A0); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1434,10 +1709,10 @@ void OPPROTO op_fldl_ST0_A0(void) int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT - FP_CONVERT.i64 = ldq((void *)A0); + FP_CONVERT.i64 = ldq(A0); env->fpregs[new_fpstt] = FP_CONVERT.d; #else - env->fpregs[new_fpstt] = ldfq((void *)A0); + env->fpregs[new_fpstt] = ldfq(A0); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1455,7 +1730,7 @@ void helper_fild_ST0_A0(void) { int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw(A0); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } @@ -1464,7 +1739,7 @@ void helper_fildl_ST0_A0(void) { int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl(A0)); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } @@ -1473,7 +1748,7 @@ void helper_fildll_ST0_A0(void) { int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq(A0)); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } @@ -1500,10 +1775,10 @@ void OPPROTO op_fild_ST0_A0(void) int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT - FP_CONVERT.i32 = ldsw((void *)A0); + FP_CONVERT.i32 = ldsw(A0); env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; #else - env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0); + env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw(A0); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1514,10 +1789,10 @@ void OPPROTO op_fildl_ST0_A0(void) int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT - FP_CONVERT.i32 = (int32_t) ldl((void *)A0); + FP_CONVERT.i32 = (int32_t) ldl(A0); env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; #else - env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0)); + env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl(A0)); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1528,10 +1803,10 @@ void OPPROTO op_fildll_ST0_A0(void) int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT - FP_CONVERT.i64 = (int64_t) ldq((void *)A0); + FP_CONVERT.i64 = (int64_t) ldq(A0); env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64; #else - env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0)); + env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq(A0)); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1545,15 +1820,15 @@ void OPPROTO op_fsts_ST0_A0(void) { #ifdef USE_FP_CONVERT FP_CONVERT.f = (float)ST0; - stfl((void *)A0, FP_CONVERT.f); + stfl(A0, FP_CONVERT.f); #else - stfl((void *)A0, (float)ST0); + stfl(A0, (float)ST0); #endif } void OPPROTO op_fstl_ST0_A0(void) { - stfq((void *)A0, (double)ST0); + stfq(A0, (double)ST0); } void OPPROTO op_fstt_ST0_A0(void) @@ -1574,7 +1849,7 @@ void OPPROTO op_fist_ST0_A0(void) val = lrint(d); if (val != (int16_t)val) val = -32768; - stw((void *)A0, val); + stw(A0, val); } void OPPROTO op_fistl_ST0_A0(void) @@ -1588,7 +1863,7 @@ void OPPROTO op_fistl_ST0_A0(void) d = ST0; val = lrint(d); - stl((void *)A0, val); + stl(A0, val); } void OPPROTO op_fistll_ST0_A0(void) @@ -1602,7 +1877,7 @@ void OPPROTO op_fistll_ST0_A0(void) d = ST0; val = llrint(d); - stq((void *)A0, val); + stq(A0, val); } void OPPROTO op_fbld_ST0_A0(void) @@ -1934,25 +2209,25 @@ void OPPROTO op_fnstsw_A0(void) { int fpus; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - stw((void *)A0, fpus); + stw(A0, fpus); } void OPPROTO op_fnstsw_EAX(void) { int fpus; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - EAX = (EAX & 0xffff0000) | fpus; + EAX = (EAX & ~0xffff) | fpus; } void OPPROTO op_fnstcw_A0(void) { - stw((void *)A0, env->fpuc); + stw(A0, env->fpuc); } void OPPROTO op_fldcw_A0(void) { int rnd_type; - env->fpuc = lduw((void *)A0); + env->fpuc = lduw(A0); /* set rounding mode */ switch(env->fpuc & RC_MASK) { default: @@ -2001,22 +2276,22 @@ void OPPROTO op_fninit(void) void OPPROTO op_fnstenv_A0(void) { - helper_fstenv((uint8_t *)A0, PARAM1); + helper_fstenv(A0, PARAM1); } void OPPROTO op_fldenv_A0(void) { - helper_fldenv((uint8_t *)A0, PARAM1); + helper_fldenv(A0, PARAM1); } void OPPROTO op_fnsave_A0(void) { - helper_fsave((uint8_t *)A0, PARAM1); + helper_fsave(A0, PARAM1); } void OPPROTO op_frstor_A0(void) { - helper_frstor((uint8_t *)A0, PARAM1); + helper_frstor(A0, PARAM1); } /* threading support */ @@ -2030,3 +2305,30 @@ void OPPROTO op_unlock(void) cpu_unlock(); } +/* SSE support */ +static inline void memcpy16(void *d, void *s) +{ + ((uint32_t *)d)[0] = ((uint32_t *)s)[0]; + ((uint32_t *)d)[1] = ((uint32_t *)s)[1]; + ((uint32_t *)d)[2] = ((uint32_t *)s)[2]; + ((uint32_t *)d)[3] = ((uint32_t *)s)[3]; +} + +void OPPROTO op_movo(void) +{ + /* XXX: badly generated code */ + XMMReg *d, *s; + d = (XMMReg *)((char *)env + PARAM1); + s = (XMMReg *)((char *)env + PARAM2); + memcpy16(d, s); +} + +void OPPROTO op_fxsave_A0(void) +{ + helper_fxsave(A0, PARAM1); +} + +void OPPROTO op_fxrstor_A0(void) +{ + helper_fxrstor(A0, PARAM1); +} diff --git a/target-i386/opreg_template.h b/target-i386/opreg_template.h index 16a43f2db..648063650 100644 --- a/target-i386/opreg_template.h +++ b/target-i386/opreg_template.h @@ -20,29 +20,56 @@ */ void OPPROTO glue(op_movl_A0,REGNAME)(void) { - A0 = REG; + A0 = (uint32_t)REG; } void OPPROTO glue(op_addl_A0,REGNAME)(void) { - A0 += REG; + A0 = (uint32_t)(A0 + REG); } void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void) { - A0 += REG << 1; + A0 = (uint32_t)(A0 + (REG << 1)); } void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void) { - A0 += REG << 2; + A0 = (uint32_t)(A0 + (REG << 2)); } void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void) { - A0 += REG << 3; + A0 = (uint32_t)(A0 + (REG << 3)); +} + +#ifdef TARGET_X86_64 +void OPPROTO glue(op_movq_A0,REGNAME)(void) +{ + A0 = REG; +} + +void OPPROTO glue(op_addq_A0,REGNAME)(void) +{ + A0 = (A0 + REG); +} + +void OPPROTO glue(glue(op_addq_A0,REGNAME),_s1)(void) +{ + A0 = (A0 + (REG << 1)); +} + +void OPPROTO glue(glue(op_addq_A0,REGNAME),_s2)(void) +{ + A0 = (A0 + (REG << 2)); } +void OPPROTO glue(glue(op_addq_A0,REGNAME),_s3)(void) +{ + A0 = (A0 + (REG << 3)); +} +#endif + void OPPROTO glue(op_movl_T0,REGNAME)(void) { T0 = REG; @@ -65,72 +92,99 @@ void OPPROTO glue(op_movh_T1,REGNAME)(void) void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void) { - REG = T0; + REG = (uint32_t)T0; } void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void) { - REG = T1; + REG = (uint32_t)T1; } void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) +{ + REG = (uint32_t)A0; +} + +#ifdef TARGET_X86_64 +void OPPROTO glue(glue(op_movq,REGNAME),_T0)(void) +{ + REG = T0; +} + +void OPPROTO glue(glue(op_movq,REGNAME),_T1)(void) +{ + REG = T1; +} + +void OPPROTO glue(glue(op_movq,REGNAME),_A0)(void) { REG = A0; } +#endif /* mov T1 to REG if T0 is true */ void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void) { if (T0) - REG = (REG & 0xffff0000) | (T1 & 0xffff); + REG = (REG & ~0xffff) | (T1 & 0xffff); FORCE_RET(); } void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void) +{ + if (T0) + REG = (uint32_t)T1; + FORCE_RET(); +} + +#ifdef TARGET_X86_64 +void OPPROTO glue(glue(op_cmovq,REGNAME),_T1_T0)(void) { if (T0) REG = T1; FORCE_RET(); } +#endif /* NOTE: T0 high order bits are ignored */ void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) { - REG = (REG & 0xffff0000) | (T0 & 0xffff); + REG = (REG & ~0xffff) | (T0 & 0xffff); } /* NOTE: T0 high order bits are ignored */ void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void) { - REG = (REG & 0xffff0000) | (T1 & 0xffff); + REG = (REG & ~0xffff) | (T1 & 0xffff); } /* NOTE: A0 high order bits are ignored */ void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void) { - REG = (REG & 0xffff0000) | (A0 & 0xffff); + REG = (REG & ~0xffff) | (A0 & 0xffff); } /* NOTE: T0 high order bits are ignored */ void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void) { - REG = (REG & 0xffffff00) | (T0 & 0xff); + REG = (REG & ~0xff) | (T0 & 0xff); } /* NOTE: T0 high order bits are ignored */ void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void) { - REG = (REG & 0xffff00ff) | ((T0 & 0xff) << 8); + REG = (REG & ~0xff00) | ((T0 & 0xff) << 8); } /* NOTE: T1 high order bits are ignored */ void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void) { - REG = (REG & 0xffffff00) | (T1 & 0xff); + REG = (REG & ~0xff) | (T1 & 0xff); } /* NOTE: T1 high order bits are ignored */ void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void) { - REG = (REG & 0xffff00ff) | ((T1 & 0xff) << 8); + REG = (REG & ~0xff00) | ((T1 & 0xff) << 8); } + diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h index 6a2ad41ee..284ab71af 100644 --- a/target-i386/ops_mem.h +++ b/target-i386/ops_mem.h @@ -1,83 +1,134 @@ void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void) { - T0 = glue(ldub, MEMSUFFIX)((uint8_t *)A0); + T0 = glue(ldub, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void) { - T0 = glue(ldsb, MEMSUFFIX)((int8_t *)A0); + T0 = glue(ldsb, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void) { - T0 = glue(lduw, MEMSUFFIX)((uint8_t *)A0); + T0 = glue(lduw, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void) { - T0 = glue(ldsw, MEMSUFFIX)((int8_t *)A0); + T0 = glue(ldsw, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void) { - T0 = glue(ldl, MEMSUFFIX)((uint8_t *)A0); + T0 = (uint32_t)glue(ldl, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void) { - T1 = glue(ldub, MEMSUFFIX)((uint8_t *)A0); + T1 = glue(ldub, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void) { - T1 = glue(ldsb, MEMSUFFIX)((int8_t *)A0); + T1 = glue(ldsb, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void) { - T1 = glue(lduw, MEMSUFFIX)((uint8_t *)A0); + T1 = glue(lduw, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void) { - T1 = glue(ldsw, MEMSUFFIX)((int8_t *)A0); + T1 = glue(ldsw, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void) { - T1 = glue(ldl, MEMSUFFIX)((uint8_t *)A0); + T1 = glue(ldl, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void) { - glue(stb, MEMSUFFIX)((uint8_t *)A0, T0); + glue(stb, MEMSUFFIX)(A0, T0); } void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void) { - glue(stw, MEMSUFFIX)((uint8_t *)A0, T0); + glue(stw, MEMSUFFIX)(A0, T0); } void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void) { - glue(stl, MEMSUFFIX)((uint8_t *)A0, T0); + glue(stl, MEMSUFFIX)(A0, T0); } #if 0 void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T1_A0)(void) { - glue(stb, MEMSUFFIX)((uint8_t *)A0, T1); + glue(stb, MEMSUFFIX)(A0, T1); } #endif void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T1_A0)(void) { - glue(stw, MEMSUFFIX)((uint8_t *)A0, T1); + glue(stw, MEMSUFFIX)(A0, T1); } void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T1_A0)(void) { - glue(stl, MEMSUFFIX)((uint8_t *)A0, T1); + glue(stl, MEMSUFFIX)(A0, T1); } +/* SSE support */ +void OPPROTO glue(glue(op_ldo, MEMSUFFIX), _env_A0)(void) +{ + XMMReg *p; + p = (XMMReg *)((char *)env + PARAM1); + /* XXX: host endianness ? */ + p->u.q[0] = glue(ldq, MEMSUFFIX)(A0); + p->u.q[1] = glue(ldq, MEMSUFFIX)(A0 + 8); +} + +void OPPROTO glue(glue(op_sto, MEMSUFFIX), _env_A0)(void) +{ + XMMReg *p; + p = (XMMReg *)((char *)env + PARAM1); + /* XXX: host endianness ? */ + glue(stq, MEMSUFFIX)(A0, p->u.q[0]); + glue(stq, MEMSUFFIX)(A0 + 8, p->u.q[1]); +} + +#ifdef TARGET_X86_64 +void OPPROTO glue(glue(op_ldsl, MEMSUFFIX), _T0_A0)(void) +{ + T0 = (int32_t)glue(ldl, MEMSUFFIX)(A0); +} + +void OPPROTO glue(glue(op_ldsl, MEMSUFFIX), _T1_A0)(void) +{ + T1 = (int32_t)glue(ldl, MEMSUFFIX)(A0); +} + +void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T0_A0)(void) +{ + T0 = glue(ldq, MEMSUFFIX)(A0); +} + +void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T1_A0)(void) +{ + T1 = glue(ldq, MEMSUFFIX)(A0); +} + +void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T0_A0)(void) +{ + glue(stq, MEMSUFFIX)(A0, T0); +} + +void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T1_A0)(void) +{ + glue(stq, MEMSUFFIX)(A0, T1); +} +#endif + #undef MEMSUFFIX diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 2ff1f6664..044968a2c 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -20,7 +20,12 @@ */ #define DATA_BITS (1 << (3 + SHIFT)) #define SHIFT_MASK (DATA_BITS - 1) -#define SIGN_MASK (1 << (DATA_BITS - 1)) +#define SIGN_MASK (((target_ulong)1) << (DATA_BITS - 1)) +#if DATA_BITS <= 32 +#define SHIFT1_MASK 0x1f +#else +#define SHIFT1_MASK 0x3f +#endif #if DATA_BITS == 8 #define SUFFIX b @@ -37,6 +42,11 @@ #define DATA_TYPE uint32_t #define DATA_STYPE int32_t #define DATA_MASK 0xffffffff +#elif DATA_BITS == 64 +#define SUFFIX q +#define DATA_TYPE uint64_t +#define DATA_STYPE int64_t +#define DATA_MASK 0xffffffffffffffff #else #error unhandled operand size #endif @@ -46,7 +56,7 @@ static int glue(compute_all_add, SUFFIX)(void) { int cf, pf, af, zf, sf, of; - int src1, src2; + target_long src1, src2; src1 = CC_SRC; src2 = CC_DST - CC_SRC; cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; @@ -60,7 +70,8 @@ static int glue(compute_all_add, SUFFIX)(void) static int glue(compute_c_add, SUFFIX)(void) { - int src1, cf; + int cf; + target_long src1; src1 = CC_SRC; cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; return cf; @@ -69,7 +80,7 @@ static int glue(compute_c_add, SUFFIX)(void) static int glue(compute_all_adc, SUFFIX)(void) { int cf, pf, af, zf, sf, of; - int src1, src2; + target_long src1, src2; src1 = CC_SRC; src2 = CC_DST - CC_SRC - 1; cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; @@ -83,7 +94,8 @@ static int glue(compute_all_adc, SUFFIX)(void) static int glue(compute_c_adc, SUFFIX)(void) { - int src1, cf; + int cf; + target_long src1; src1 = CC_SRC; cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; return cf; @@ -92,7 +104,7 @@ static int glue(compute_c_adc, SUFFIX)(void) static int glue(compute_all_sub, SUFFIX)(void) { int cf, pf, af, zf, sf, of; - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; @@ -106,7 +118,8 @@ static int glue(compute_all_sub, SUFFIX)(void) static int glue(compute_c_sub, SUFFIX)(void) { - int src1, src2, cf; + int cf; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; @@ -116,7 +129,7 @@ static int glue(compute_c_sub, SUFFIX)(void) static int glue(compute_all_sbb, SUFFIX)(void) { int cf, pf, af, zf, sf, of; - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC + 1; src2 = CC_SRC; cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; @@ -130,7 +143,8 @@ static int glue(compute_all_sbb, SUFFIX)(void) static int glue(compute_c_sbb, SUFFIX)(void) { - int src1, src2, cf; + int cf; + target_long src1, src2; src1 = CC_DST + CC_SRC + 1; src2 = CC_SRC; cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; @@ -157,7 +171,7 @@ static int glue(compute_c_logic, SUFFIX)(void) static int glue(compute_all_inc, SUFFIX)(void) { int cf, pf, af, zf, sf, of; - int src1, src2; + target_long src1, src2; src1 = CC_DST - 1; src2 = 1; cf = CC_SRC; @@ -179,7 +193,7 @@ static int glue(compute_c_inc, SUFFIX)(void) static int glue(compute_all_dec, SUFFIX)(void) { int cf, pf, af, zf, sf, of; - int src1, src2; + target_long src1, src2; src1 = CC_DST + 1; src2 = 1; cf = CC_SRC; @@ -187,7 +201,7 @@ static int glue(compute_all_dec, SUFFIX)(void) af = (CC_DST ^ src1 ^ src2) & 0x10; zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11; + of = ((CC_DST & DATA_MASK) == ((target_ulong)SIGN_MASK - 1)) << 11; return cf | pf | af | zf | sf | of; } @@ -256,71 +270,66 @@ static int glue(compute_all_mul, SUFFIX)(void) void OPPROTO glue(op_jb_sub, SUFFIX)(void) { - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; if ((DATA_TYPE)src1 < (DATA_TYPE)src2) - JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 1, PARAM3); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO glue(op_jz_sub, SUFFIX)(void) { if ((DATA_TYPE)CC_DST == 0) - JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 1, PARAM3); + GOTO_LABEL_PARAM(1); + FORCE_RET(); +} + +void OPPROTO glue(op_jnz_sub, SUFFIX)(void) +{ + if ((DATA_TYPE)CC_DST != 0) + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO glue(op_jbe_sub, SUFFIX)(void) { - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) - JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 1, PARAM3); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO glue(op_js_sub, SUFFIX)(void) { if (CC_DST & SIGN_MASK) - JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 1, PARAM3); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO glue(op_jl_sub, SUFFIX)(void) { - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; if ((DATA_STYPE)src1 < (DATA_STYPE)src2) - JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 1, PARAM3); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO glue(op_jle_sub, SUFFIX)(void) { - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) - JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 0, PARAM2); - else - JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 1, PARAM3); + GOTO_LABEL_PARAM(1); FORCE_RET(); } @@ -330,50 +339,33 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) void OPPROTO glue(op_loopnz, SUFFIX)(void) { - unsigned int tmp; int eflags; eflags = cc_table[CC_OP].compute_all(); - tmp = (ECX - 1) & DATA_MASK; - ECX = (ECX & ~DATA_MASK) | tmp; - if (tmp != 0 && !(eflags & CC_Z)) - EIP = PARAM1; - else - EIP = PARAM2; + if ((DATA_TYPE)ECX != 0 && !(eflags & CC_Z)) + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO glue(op_loopz, SUFFIX)(void) { - unsigned int tmp; int eflags; eflags = cc_table[CC_OP].compute_all(); - tmp = (ECX - 1) & DATA_MASK; - ECX = (ECX & ~DATA_MASK) | tmp; - if (tmp != 0 && (eflags & CC_Z)) - EIP = PARAM1; - else - EIP = PARAM2; + if ((DATA_TYPE)ECX != 0 && (eflags & CC_Z)) + GOTO_LABEL_PARAM(1); FORCE_RET(); } -void OPPROTO glue(op_loop, SUFFIX)(void) +void OPPROTO glue(op_jz_ecx, SUFFIX)(void) { - unsigned int tmp; - tmp = (ECX - 1) & DATA_MASK; - ECX = (ECX & ~DATA_MASK) | tmp; - if (tmp != 0) - EIP = PARAM1; - else - EIP = PARAM2; + if ((DATA_TYPE)ECX == 0) + GOTO_LABEL_PARAM(1); FORCE_RET(); } -void OPPROTO glue(op_jecxz, SUFFIX)(void) +void OPPROTO glue(op_jnz_ecx, SUFFIX)(void) { - if ((DATA_TYPE)ECX == 0) - EIP = PARAM1; - else - EIP = PARAM2; + if ((DATA_TYPE)ECX != 0) + GOTO_LABEL_PARAM(1); FORCE_RET(); } @@ -383,7 +375,7 @@ void OPPROTO glue(op_jecxz, SUFFIX)(void) void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) { - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; @@ -397,7 +389,7 @@ void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) { - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; @@ -411,7 +403,7 @@ void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void) void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) { - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; @@ -420,7 +412,7 @@ void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) { - int src1, src2; + target_long src1, src2; src1 = CC_DST + CC_SRC; src2 = CC_SRC; @@ -432,7 +424,7 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) { int count; - count = T1 & 0x1f; + count = T1 & SHIFT1_MASK; T0 = T0 << count; FORCE_RET(); } @@ -440,7 +432,7 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) { int count; - count = T1 & 0x1f; + count = T1 & SHIFT1_MASK; T0 &= DATA_MASK; T0 = T0 >> count; FORCE_RET(); @@ -448,8 +440,10 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) { - int count, src; - count = T1 & 0x1f; + int count; + target_long src; + + count = T1 & SHIFT1_MASK; src = (DATA_STYPE)T0; T0 = src >> count; FORCE_RET(); @@ -484,7 +478,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) int count; count = T1 & SHIFT_MASK; T1 = T0 >> count; - T0 |= (1 << count); + T0 |= (((target_long)1) << count); } void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) @@ -492,7 +486,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) int count; count = T1 & SHIFT_MASK; T1 = T0 >> count; - T0 &= ~(1 << count); + T0 &= ~(((target_long)1) << count); } void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) @@ -500,12 +494,19 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) int count; count = T1 & SHIFT_MASK; T1 = T0 >> count; - T0 ^= (1 << count); + T0 ^= (((target_long)1) << count); +} + +void OPPROTO glue(glue(op_add_bit, SUFFIX), _A0_T1)(void) +{ + A0 += ((DATA_STYPE)T1 >> (3 + SHIFT)) << SHIFT; } void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) { - int res, count; + int count; + target_long res; + res = T0 & DATA_MASK; if (res != 0) { count = 0; @@ -523,7 +524,9 @@ void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) { - int res, count; + int count; + target_long res; + res = T0 & DATA_MASK; if (res != 0) { count = DATA_BITS - 1; @@ -555,70 +558,8 @@ void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) T0 = DF << SHIFT; } -void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) -{ - if ((DATA_TYPE)CC_DST == 0) - JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 3); - FORCE_RET(); -} - -void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) -{ - if ((DATA_TYPE)CC_DST != 0) - JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 3); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_string_jz_sub, SUFFIX), _im)(void) -{ - if ((DATA_TYPE)CC_DST == 0) { - EIP = PARAM1; - if (env->eflags & TF_MASK) { - raise_exception(EXCP01_SSTP); - } - T0 = 0; - EXIT_TB(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_string_jnz_sub, SUFFIX), _im)(void) -{ - if ((DATA_TYPE)CC_DST != 0) { - EIP = PARAM1; - if (env->eflags & TF_MASK) { - raise_exception(EXCP01_SSTP); - } - T0 = 0; - EXIT_TB(); - } - FORCE_RET(); -} - -#if DATA_BITS >= 16 -void OPPROTO glue(op_jz_ecx, SUFFIX)(void) -{ - if ((DATA_TYPE)ECX == 0) - JUMP_TB(glue(op_jz_ecx, SUFFIX), PARAM1, 1, PARAM2); - FORCE_RET(); -} - -void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void) -{ - if ((DATA_TYPE)ECX == 0) { - EIP = PARAM1; - if (env->eflags & TF_MASK) { - raise_exception(EXCP01_SSTP); - } - T0 = 0; - EXIT_TB(); - } - FORCE_RET(); -} -#endif - /* port I/O */ - +#if DATA_BITS <= 32 void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) { glue(cpu_out, SUFFIX)(env, T0, T1 & DATA_MASK); @@ -648,9 +589,11 @@ void OPPROTO glue(glue(op_check_io, SUFFIX), _DX)(void) { glue(glue(check_io, SUFFIX), _DX)(); } +#endif #undef DATA_BITS #undef SHIFT_MASK +#undef SHIFT1_MASK #undef SIGN_MASK #undef DATA_TYPE #undef DATA_STYPE diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h index ea73c96ca..00454e6d0 100644 --- a/target-i386/ops_template_mem.h +++ b/target-i386/ops_template_mem.h @@ -28,6 +28,8 @@ #define MEM_SUFFIX w_raw #elif DATA_BITS == 32 #define MEM_SUFFIX l_raw +#elif DATA_BITS == 64 +#define MEM_SUFFIX q_raw #endif #elif MEM_WRITE == 1 @@ -38,6 +40,8 @@ #define MEM_SUFFIX w_kernel #elif DATA_BITS == 32 #define MEM_SUFFIX l_kernel +#elif DATA_BITS == 64 +#define MEM_SUFFIX q_kernel #endif #elif MEM_WRITE == 2 @@ -48,6 +52,8 @@ #define MEM_SUFFIX w_user #elif DATA_BITS == 32 #define MEM_SUFFIX l_user +#elif DATA_BITS == 64 +#define MEM_SUFFIX q_user #endif #else @@ -64,14 +70,16 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) { - int count, src; + int count; + target_long src; + count = T1 & SHIFT_MASK; if (count) { src = T0; T0 &= DATA_MASK; T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #else /* gcc 3.2 workaround. This is really a bug in gcc. */ asm volatile("" : : "r" (T0)); @@ -86,14 +94,16 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) { - int count, src; + int count; + target_long src; + count = T1 & SHIFT_MASK; if (count) { src = T0; T0 &= DATA_MASK; T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #else /* gcc 3.2 workaround. This is really a bug in gcc. */ asm volatile("" : : "r" (T0)); @@ -114,7 +124,7 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void) T0 &= DATA_MASK; T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif } FORCE_RET(); @@ -128,7 +138,7 @@ void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) T0 &= DATA_MASK; T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif } FORCE_RET(); @@ -136,10 +146,11 @@ void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) { - int count, res, eflags; - unsigned int src; + int count, eflags; + target_ulong src; + target_long res; - count = T1 & 0x1f; + count = T1 & SHIFT1_MASK; #if DATA_BITS == 16 count = rclw_table[count]; #elif DATA_BITS == 8 @@ -154,7 +165,7 @@ void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) res |= T0 >> (DATA_BITS + 1 - count); T0 = res; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = (eflags & ~(CC_C | CC_O)) | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | @@ -166,10 +177,11 @@ void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) { - int count, res, eflags; - unsigned int src; + int count, eflags; + target_ulong src; + target_long res; - count = T1 & 0x1f; + count = T1 & SHIFT1_MASK; #if DATA_BITS == 16 count = rclw_table[count]; #elif DATA_BITS == 8 @@ -184,7 +196,7 @@ void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) res |= T0 << (DATA_BITS + 1 - count); T0 = res; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = (eflags & ~(CC_C | CC_O)) | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | @@ -196,13 +208,15 @@ void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) { - int count, src; - count = T1 & 0x1f; + int count; + target_long src; + + count = T1 & SHIFT1_MASK; if (count) { src = (DATA_TYPE)T0 << (count - 1); T0 = T0 << count; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = src; CC_DST = T0; @@ -213,14 +227,16 @@ void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) { - int count, src; - count = T1 & 0x1f; + int count; + target_long src; + + count = T1 & SHIFT1_MASK; if (count) { T0 &= DATA_MASK; src = T0 >> (count - 1); T0 = T0 >> count; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = src; CC_DST = T0; @@ -231,14 +247,16 @@ void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void) { - int count, src; - count = T1 & 0x1f; + int count; + target_long src; + + count = T1 & SHIFT1_MASK; if (count) { src = (DATA_STYPE)T0; T0 = src >> count; src = src >> (count - 1); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = src; CC_DST = T0; @@ -262,7 +280,7 @@ void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) res |= T1 << (count - 16); T0 = res >> 16; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -282,7 +300,7 @@ void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) res |= T1 << (count - 16); T0 = res >> 16; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -304,7 +322,7 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) res |= T1 << (32 - count); T0 = res; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -325,7 +343,7 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) res |= T1 << (32 - count); T0 = res; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -335,17 +353,19 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) } #endif -#if DATA_BITS == 32 +#if DATA_BITS >= 32 void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) { - int count, tmp; + int count; + target_long tmp; + count = PARAM1; T0 &= DATA_MASK; T1 &= DATA_MASK; tmp = T0 << (count - 1); T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -353,15 +373,17 @@ void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) { - int count, tmp; - count = ECX & 0x1f; + int count; + target_long tmp; + + count = ECX & SHIFT1_MASK; if (count) { T0 &= DATA_MASK; T1 &= DATA_MASK; tmp = T0 << (count - 1); T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -372,14 +394,16 @@ void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) { - int count, tmp; + int count; + target_long tmp; + count = PARAM1; T0 &= DATA_MASK; T1 &= DATA_MASK; tmp = T0 >> (count - 1); T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -388,15 +412,17 @@ void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) { - int count, tmp; - count = ECX & 0x1f; + int count; + target_long tmp; + + count = ECX & SHIFT1_MASK; if (count) { T0 &= DATA_MASK; T1 &= DATA_MASK; tmp = T0 >> (count - 1); T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = tmp; CC_DST = T0; @@ -414,11 +440,11 @@ void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) cf = cc_table[CC_OP].compute_c(); T0 = T0 + T1 + cf; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = T1; CC_DST = T0; - CC_OP = CC_OP_ADDB + SHIFT + cf * 3; + CC_OP = CC_OP_ADDB + SHIFT + cf * 4; } void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) @@ -427,23 +453,23 @@ void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) cf = cc_table[CC_OP].compute_c(); T0 = T0 - T1 - cf; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = T1; CC_DST = T0; - CC_OP = CC_OP_SUBB + SHIFT + cf * 3; + CC_OP = CC_OP_SUBB + SHIFT + cf * 4; } void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) { - unsigned int src, dst; + target_ulong src, dst; src = T0; dst = EAX - T0; if ((DATA_TYPE)dst == 0) { T0 = T1; #ifdef MEM_WRITE - glue(st, MEM_SUFFIX)((uint8_t *)A0, T0); + glue(st, MEM_SUFFIX)(A0, T0); #endif } else { EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index e6f9198ab..cf8bd5ab3 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -57,7 +57,7 @@ typedef struct DisasContext { int override; /* -1 if no override */ int prefix; int aflag, dflag; - uint8_t *pc; /* pc = eip + cs_base */ + target_ulong pc; /* pc = eip + cs_base */ int is_jmp; /* 1 = means jump (stop translation), 2 means CPU static state change (stop translation) */ /* code output */ @@ -65,7 +65,7 @@ typedef struct DisasContext { uint8_t *gen_code_start; /* current block context */ - uint8_t *cs_base; /* base of CS segment */ + target_ulong cs_base; /* base of CS segment */ int pe; /* protected mode */ int code32; /* 32 bit code segment */ int f_st; /* currently unused */ @@ -277,7 +277,7 @@ static inline uint32_t insn_get(DisasContext *s, int ot) be stopped. */ static int disas_insn(DisasContext *s) { - uint8_t *pc_start, *pc_tmp, *pc_start_insn; + target_ulong pc_start, pc_tmp, pc_start_insn; int b, prefixes, aflag, dflag, next_eip, val; int ot; int modrm, mod, op, rm; @@ -789,6 +789,8 @@ static int disas_insn(DisasContext *s) break; case 0x1e: /* fcomi */ break; + case 0x28: /* ffree sti */ + break; case 0x2a: /* fst sti */ break; case 0x2b: /* fstp sti */ @@ -1176,9 +1178,9 @@ static inline int gen_intermediate_code_internal(CPUState *env, uint8_t *tc_ptr) { DisasContext dc1, *dc = &dc1; - uint8_t *pc_insn, *pc_start, *gen_code_end; + target_ulong pc_insn, pc_start, cs_base; + uint8_t *gen_code_end; int flags, ret; - uint8_t *cs_base; if (env->nb_breakpoints > 0 || env->singlestep_enabled) @@ -1197,8 +1199,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->gen_code_start = gen_code_ptr; /* generate intermediate code */ - pc_start = (uint8_t *)tb->pc; - cs_base = (uint8_t *)tb->cs_base; + pc_start = tb->pc; + cs_base = tb->cs_base; dc->pc = pc_start; dc->cs_base = cs_base; dc->pe = (flags >> HF_PE_SHIFT) & 1; @@ -1249,7 +1251,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, fprintf(logfile, "IN: COPY: %s fpu=%d\n", lookup_symbol(pc_start), tb->cflags & CF_TB_FP_USED ? 1 : 0); - disas(logfile, pc_start, dc->pc - pc_start, 0, !dc->code32); + target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32); fprintf(logfile, "\n"); } #endif diff --git a/target-i386/translate.c b/target-i386/translate.c index eba99052a..a00ce0426 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -39,18 +39,45 @@ static uint32_t *gen_opparam_ptr; #define PREFIX_DATA 0x08 #define PREFIX_ADR 0x10 +#ifdef TARGET_X86_64 +#define X86_64_ONLY(x) x +#define X86_64_DEF(x...) x +#define CODE64(s) ((s)->code64) +#define REX_X(s) ((s)->rex_x) +#define REX_B(s) ((s)->rex_b) +/* XXX: gcc generates push/pop in some opcodes, so we cannot use them */ +#if 1 +#define BUGGY_64(x) NULL +#endif +#else +#define X86_64_ONLY(x) NULL +#define X86_64_DEF(x...) +#define CODE64(s) 0 +#define REX_X(s) 0 +#define REX_B(s) 0 +#endif + +#ifdef TARGET_X86_64 +static int x86_64_hregs; +#endif + typedef struct DisasContext { /* current insn context */ int override; /* -1 if no override */ int prefix; int aflag, dflag; - uint8_t *pc; /* pc = eip + cs_base */ + target_ulong pc; /* pc = eip + cs_base */ int is_jmp; /* 1 = means jump (stop translation), 2 means CPU static state change (stop translation) */ /* current block context */ - uint8_t *cs_base; /* base of CS segment */ + target_ulong cs_base; /* base of CS segment */ int pe; /* protected mode */ int code32; /* 32 bit code segment */ +#ifdef TARGET_X86_64 + int lma; /* long mode active */ + int code64; /* 64 bit code segment */ + int rex_x, rex_b; +#endif int ss32; /* 32 bit stack segment */ int cc_op; /* current CC operation */ int addseg; /* non zero if either DS/ES/SS have a non zero base */ @@ -65,10 +92,13 @@ typedef struct DisasContext { int flags; /* all execution flags */ struct TranslationBlock *tb; int popl_esp_hack; /* for correct popl with esp base handling */ + int rip_offset; /* only used in x86_64, but left for simplicity */ + int cpuid_features; } DisasContext; static void gen_eob(DisasContext *s); -static void gen_jmp(DisasContext *s, unsigned int eip); +static void gen_jmp(DisasContext *s, target_ulong eip); +static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num); /* i386 arith/logic operations */ enum { @@ -121,103 +151,182 @@ enum { OR_EBP, OR_ESI, OR_EDI, - OR_TMP0, /* temporary operand register */ + + OR_TMP0 = 16, /* temporary operand register */ OR_TMP1, OR_A0, /* temporary register used when doing address evaluation */ - OR_ZERO, /* fixed zero register */ - NB_OREGS, }; -static GenOpFunc *gen_op_mov_reg_T0[3][8] = { +#ifdef TARGET_X86_64 + +#define NB_OP_SIZES 4 + +#define DEF_REGS(prefix, suffix) \ + prefix ## EAX ## suffix,\ + prefix ## ECX ## suffix,\ + prefix ## EDX ## suffix,\ + prefix ## EBX ## suffix,\ + prefix ## ESP ## suffix,\ + prefix ## EBP ## suffix,\ + prefix ## ESI ## suffix,\ + prefix ## EDI ## suffix,\ + prefix ## R8 ## suffix,\ + prefix ## R9 ## suffix,\ + prefix ## R10 ## suffix,\ + prefix ## R11 ## suffix,\ + prefix ## R12 ## suffix,\ + prefix ## R13 ## suffix,\ + prefix ## R14 ## suffix,\ + prefix ## R15 ## suffix, + +#define DEF_BREGS(prefixb, prefixh, suffix) \ + \ +static void prefixb ## ESP ## suffix ## _wrapper(void) \ +{ \ + if (x86_64_hregs) \ + prefixb ## ESP ## suffix (); \ + else \ + prefixh ## EAX ## suffix (); \ +} \ + \ +static void prefixb ## EBP ## suffix ## _wrapper(void) \ +{ \ + if (x86_64_hregs) \ + prefixb ## EBP ## suffix (); \ + else \ + prefixh ## ECX ## suffix (); \ +} \ + \ +static void prefixb ## ESI ## suffix ## _wrapper(void) \ +{ \ + if (x86_64_hregs) \ + prefixb ## ESI ## suffix (); \ + else \ + prefixh ## EDX ## suffix (); \ +} \ + \ +static void prefixb ## EDI ## suffix ## _wrapper(void) \ +{ \ + if (x86_64_hregs) \ + prefixb ## EDI ## suffix (); \ + else \ + prefixh ## EBX ## suffix (); \ +} + +DEF_BREGS(gen_op_movb_, gen_op_movh_, _T0) +DEF_BREGS(gen_op_movb_, gen_op_movh_, _T1) +DEF_BREGS(gen_op_movl_T0_, gen_op_movh_T0_, ) +DEF_BREGS(gen_op_movl_T1_, gen_op_movh_T1_, ) + +#else /* !TARGET_X86_64 */ + +#define NB_OP_SIZES 3 + +#define DEF_REGS(prefix, suffix) \ + prefix ## EAX ## suffix,\ + prefix ## ECX ## suffix,\ + prefix ## EDX ## suffix,\ + prefix ## EBX ## suffix,\ + prefix ## ESP ## suffix,\ + prefix ## EBP ## suffix,\ + prefix ## ESI ## suffix,\ + prefix ## EDI ## suffix, + +#endif /* !TARGET_X86_64 */ + +static GenOpFunc *gen_op_mov_reg_T0[NB_OP_SIZES][CPU_NB_REGS] = { [OT_BYTE] = { gen_op_movb_EAX_T0, gen_op_movb_ECX_T0, gen_op_movb_EDX_T0, gen_op_movb_EBX_T0, +#ifdef TARGET_X86_64 + gen_op_movb_ESP_T0_wrapper, + gen_op_movb_EBP_T0_wrapper, + gen_op_movb_ESI_T0_wrapper, + gen_op_movb_EDI_T0_wrapper, + gen_op_movb_R8_T0, + gen_op_movb_R9_T0, + gen_op_movb_R10_T0, + gen_op_movb_R11_T0, + gen_op_movb_R12_T0, + gen_op_movb_R13_T0, + gen_op_movb_R14_T0, + gen_op_movb_R15_T0, +#else gen_op_movh_EAX_T0, gen_op_movh_ECX_T0, gen_op_movh_EDX_T0, gen_op_movh_EBX_T0, +#endif }, [OT_WORD] = { - gen_op_movw_EAX_T0, - gen_op_movw_ECX_T0, - gen_op_movw_EDX_T0, - gen_op_movw_EBX_T0, - gen_op_movw_ESP_T0, - gen_op_movw_EBP_T0, - gen_op_movw_ESI_T0, - gen_op_movw_EDI_T0, + DEF_REGS(gen_op_movw_, _T0) }, [OT_LONG] = { - gen_op_movl_EAX_T0, - gen_op_movl_ECX_T0, - gen_op_movl_EDX_T0, - gen_op_movl_EBX_T0, - gen_op_movl_ESP_T0, - gen_op_movl_EBP_T0, - gen_op_movl_ESI_T0, - gen_op_movl_EDI_T0, + DEF_REGS(gen_op_movl_, _T0) }, +#ifdef TARGET_X86_64 + [OT_QUAD] = { + DEF_REGS(gen_op_movq_, _T0) + }, +#endif }; -static GenOpFunc *gen_op_mov_reg_T1[3][8] = { +static GenOpFunc *gen_op_mov_reg_T1[NB_OP_SIZES][CPU_NB_REGS] = { [OT_BYTE] = { gen_op_movb_EAX_T1, gen_op_movb_ECX_T1, gen_op_movb_EDX_T1, gen_op_movb_EBX_T1, +#ifdef TARGET_X86_64 + gen_op_movb_ESP_T1_wrapper, + gen_op_movb_EBP_T1_wrapper, + gen_op_movb_ESI_T1_wrapper, + gen_op_movb_EDI_T1_wrapper, + gen_op_movb_R8_T1, + gen_op_movb_R9_T1, + gen_op_movb_R10_T1, + gen_op_movb_R11_T1, + gen_op_movb_R12_T1, + gen_op_movb_R13_T1, + gen_op_movb_R14_T1, + gen_op_movb_R15_T1, +#else gen_op_movh_EAX_T1, gen_op_movh_ECX_T1, gen_op_movh_EDX_T1, gen_op_movh_EBX_T1, +#endif }, [OT_WORD] = { - gen_op_movw_EAX_T1, - gen_op_movw_ECX_T1, - gen_op_movw_EDX_T1, - gen_op_movw_EBX_T1, - gen_op_movw_ESP_T1, - gen_op_movw_EBP_T1, - gen_op_movw_ESI_T1, - gen_op_movw_EDI_T1, + DEF_REGS(gen_op_movw_, _T1) }, [OT_LONG] = { - gen_op_movl_EAX_T1, - gen_op_movl_ECX_T1, - gen_op_movl_EDX_T1, - gen_op_movl_EBX_T1, - gen_op_movl_ESP_T1, - gen_op_movl_EBP_T1, - gen_op_movl_ESI_T1, - gen_op_movl_EDI_T1, + DEF_REGS(gen_op_movl_, _T1) + }, +#ifdef TARGET_X86_64 + [OT_QUAD] = { + DEF_REGS(gen_op_movq_, _T1) }, +#endif }; -static GenOpFunc *gen_op_mov_reg_A0[2][8] = { +static GenOpFunc *gen_op_mov_reg_A0[NB_OP_SIZES - 1][CPU_NB_REGS] = { [0] = { - gen_op_movw_EAX_A0, - gen_op_movw_ECX_A0, - gen_op_movw_EDX_A0, - gen_op_movw_EBX_A0, - gen_op_movw_ESP_A0, - gen_op_movw_EBP_A0, - gen_op_movw_ESI_A0, - gen_op_movw_EDI_A0, + DEF_REGS(gen_op_movw_, _A0) }, [1] = { - gen_op_movl_EAX_A0, - gen_op_movl_ECX_A0, - gen_op_movl_EDX_A0, - gen_op_movl_EBX_A0, - gen_op_movl_ESP_A0, - gen_op_movl_EBP_A0, - gen_op_movl_ESI_A0, - gen_op_movl_EDI_A0, + DEF_REGS(gen_op_movl_, _A0) + }, +#ifdef TARGET_X86_64 + [2] = { + DEF_REGS(gen_op_movq_, _A0) }, +#endif }; -static GenOpFunc *gen_op_mov_TN_reg[3][2][8] = +static GenOpFunc *gen_op_mov_TN_reg[NB_OP_SIZES][2][CPU_NB_REGS] = { [OT_BYTE] = { { @@ -225,144 +334,133 @@ static GenOpFunc *gen_op_mov_TN_reg[3][2][8] = gen_op_movl_T0_ECX, gen_op_movl_T0_EDX, gen_op_movl_T0_EBX, +#ifdef TARGET_X86_64 + gen_op_movl_T0_ESP_wrapper, + gen_op_movl_T0_EBP_wrapper, + gen_op_movl_T0_ESI_wrapper, + gen_op_movl_T0_EDI_wrapper, + gen_op_movl_T0_R8, + gen_op_movl_T0_R9, + gen_op_movl_T0_R10, + gen_op_movl_T0_R11, + gen_op_movl_T0_R12, + gen_op_movl_T0_R13, + gen_op_movl_T0_R14, + gen_op_movl_T0_R15, +#else gen_op_movh_T0_EAX, gen_op_movh_T0_ECX, gen_op_movh_T0_EDX, gen_op_movh_T0_EBX, +#endif }, { gen_op_movl_T1_EAX, gen_op_movl_T1_ECX, gen_op_movl_T1_EDX, gen_op_movl_T1_EBX, +#ifdef TARGET_X86_64 + gen_op_movl_T1_ESP_wrapper, + gen_op_movl_T1_EBP_wrapper, + gen_op_movl_T1_ESI_wrapper, + gen_op_movl_T1_EDI_wrapper, + gen_op_movl_T1_R8, + gen_op_movl_T1_R9, + gen_op_movl_T1_R10, + gen_op_movl_T1_R11, + gen_op_movl_T1_R12, + gen_op_movl_T1_R13, + gen_op_movl_T1_R14, + gen_op_movl_T1_R15, +#else gen_op_movh_T1_EAX, gen_op_movh_T1_ECX, gen_op_movh_T1_EDX, gen_op_movh_T1_EBX, +#endif }, }, [OT_WORD] = { { - gen_op_movl_T0_EAX, - gen_op_movl_T0_ECX, - gen_op_movl_T0_EDX, - gen_op_movl_T0_EBX, - gen_op_movl_T0_ESP, - gen_op_movl_T0_EBP, - gen_op_movl_T0_ESI, - gen_op_movl_T0_EDI, + DEF_REGS(gen_op_movl_T0_, ) }, { - gen_op_movl_T1_EAX, - gen_op_movl_T1_ECX, - gen_op_movl_T1_EDX, - gen_op_movl_T1_EBX, - gen_op_movl_T1_ESP, - gen_op_movl_T1_EBP, - gen_op_movl_T1_ESI, - gen_op_movl_T1_EDI, + DEF_REGS(gen_op_movl_T1_, ) }, }, [OT_LONG] = { { - gen_op_movl_T0_EAX, - gen_op_movl_T0_ECX, - gen_op_movl_T0_EDX, - gen_op_movl_T0_EBX, - gen_op_movl_T0_ESP, - gen_op_movl_T0_EBP, - gen_op_movl_T0_ESI, - gen_op_movl_T0_EDI, + DEF_REGS(gen_op_movl_T0_, ) }, { - gen_op_movl_T1_EAX, - gen_op_movl_T1_ECX, - gen_op_movl_T1_EDX, - gen_op_movl_T1_EBX, - gen_op_movl_T1_ESP, - gen_op_movl_T1_EBP, - gen_op_movl_T1_ESI, - gen_op_movl_T1_EDI, + DEF_REGS(gen_op_movl_T1_, ) }, }, +#ifdef TARGET_X86_64 + [OT_QUAD] = { + { + DEF_REGS(gen_op_movl_T0_, ) + }, + { + DEF_REGS(gen_op_movl_T1_, ) + }, + }, +#endif }; -static GenOpFunc *gen_op_movl_A0_reg[8] = { - gen_op_movl_A0_EAX, - gen_op_movl_A0_ECX, - gen_op_movl_A0_EDX, - gen_op_movl_A0_EBX, - gen_op_movl_A0_ESP, - gen_op_movl_A0_EBP, - gen_op_movl_A0_ESI, - gen_op_movl_A0_EDI, +static GenOpFunc *gen_op_movl_A0_reg[CPU_NB_REGS] = { + DEF_REGS(gen_op_movl_A0_, ) }; -static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { +static GenOpFunc *gen_op_addl_A0_reg_sN[4][CPU_NB_REGS] = { [0] = { - gen_op_addl_A0_EAX, - gen_op_addl_A0_ECX, - gen_op_addl_A0_EDX, - gen_op_addl_A0_EBX, - gen_op_addl_A0_ESP, - gen_op_addl_A0_EBP, - gen_op_addl_A0_ESI, - gen_op_addl_A0_EDI, + DEF_REGS(gen_op_addl_A0_, ) }, [1] = { - gen_op_addl_A0_EAX_s1, - gen_op_addl_A0_ECX_s1, - gen_op_addl_A0_EDX_s1, - gen_op_addl_A0_EBX_s1, - gen_op_addl_A0_ESP_s1, - gen_op_addl_A0_EBP_s1, - gen_op_addl_A0_ESI_s1, - gen_op_addl_A0_EDI_s1, + DEF_REGS(gen_op_addl_A0_, _s1) }, [2] = { - gen_op_addl_A0_EAX_s2, - gen_op_addl_A0_ECX_s2, - gen_op_addl_A0_EDX_s2, - gen_op_addl_A0_EBX_s2, - gen_op_addl_A0_ESP_s2, - gen_op_addl_A0_EBP_s2, - gen_op_addl_A0_ESI_s2, - gen_op_addl_A0_EDI_s2, + DEF_REGS(gen_op_addl_A0_, _s2) }, [3] = { - gen_op_addl_A0_EAX_s3, - gen_op_addl_A0_ECX_s3, - gen_op_addl_A0_EDX_s3, - gen_op_addl_A0_EBX_s3, - gen_op_addl_A0_ESP_s3, - gen_op_addl_A0_EBP_s3, - gen_op_addl_A0_ESI_s3, - gen_op_addl_A0_EDI_s3, + DEF_REGS(gen_op_addl_A0_, _s3) }, }; -static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = { +#ifdef TARGET_X86_64 +static GenOpFunc *gen_op_movq_A0_reg[CPU_NB_REGS] = { + DEF_REGS(gen_op_movq_A0_, ) +}; + +static GenOpFunc *gen_op_addq_A0_reg_sN[4][CPU_NB_REGS] = { [0] = { - gen_op_cmovw_EAX_T1_T0, - gen_op_cmovw_ECX_T1_T0, - gen_op_cmovw_EDX_T1_T0, - gen_op_cmovw_EBX_T1_T0, - gen_op_cmovw_ESP_T1_T0, - gen_op_cmovw_EBP_T1_T0, - gen_op_cmovw_ESI_T1_T0, - gen_op_cmovw_EDI_T1_T0, + DEF_REGS(gen_op_addq_A0_, ) }, [1] = { - gen_op_cmovl_EAX_T1_T0, - gen_op_cmovl_ECX_T1_T0, - gen_op_cmovl_EDX_T1_T0, - gen_op_cmovl_EBX_T1_T0, - gen_op_cmovl_ESP_T1_T0, - gen_op_cmovl_EBP_T1_T0, - gen_op_cmovl_ESI_T1_T0, - gen_op_cmovl_EDI_T1_T0, + DEF_REGS(gen_op_addq_A0_, _s1) + }, + [2] = { + DEF_REGS(gen_op_addq_A0_, _s2) + }, + [3] = { + DEF_REGS(gen_op_addq_A0_, _s3) }, }; +#endif + +static GenOpFunc *gen_op_cmov_reg_T1_T0[NB_OP_SIZES - 1][CPU_NB_REGS] = { + [0] = { + DEF_REGS(gen_op_cmovw_, _T1_T0) + }, + [1] = { + DEF_REGS(gen_op_cmovl_, _T1_T0) + }, +#ifdef TARGET_X86_64 + [2] = { + DEF_REGS(gen_op_cmovq_, _T1_T0) + }, +#endif +}; static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { NULL, @@ -387,13 +485,17 @@ static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { {\ gen_op_adcl ## SUFFIX ## _T0_T1_cc,\ gen_op_sbbl ## SUFFIX ## _T0_T1_cc,\ + },\ + {\ + X86_64_ONLY(gen_op_adcq ## SUFFIX ## _T0_T1_cc),\ + X86_64_ONLY(gen_op_sbbq ## SUFFIX ## _T0_T1_cc),\ }, -static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { +static GenOpFunc *gen_op_arithc_T0_T1_cc[4][2] = { DEF_ARITHC( ) }; -static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[9][2] = { +static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3 * 4][2] = { DEF_ARITHC(_raw) #ifndef CONFIG_USER_ONLY DEF_ARITHC(_kernel) @@ -415,14 +517,14 @@ static const int cc_op_arithb[8] = { #define DEF_CMPXCHG(SUFFIX)\ gen_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc,\ gen_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc,\ - gen_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc, - + gen_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc,\ + X86_64_ONLY(gen_op_cmpxchgq ## SUFFIX ## _T0_T1_EAX_cc), -static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { +static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[4] = { DEF_CMPXCHG( ) }; -static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = { +static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3 * 4] = { DEF_CMPXCHG(_raw) #ifndef CONFIG_USER_ONLY DEF_CMPXCHG(_kernel) @@ -460,13 +562,23 @@ static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = { gen_op_shrl ## SUFFIX ## _T0_T1_cc,\ gen_op_shll ## SUFFIX ## _T0_T1_cc,\ gen_op_sarl ## SUFFIX ## _T0_T1_cc,\ + },\ + {\ + X86_64_ONLY(gen_op_rolq ## SUFFIX ## _T0_T1_cc),\ + X86_64_ONLY(gen_op_rorq ## SUFFIX ## _T0_T1_cc),\ + X86_64_ONLY(gen_op_rclq ## SUFFIX ## _T0_T1_cc),\ + X86_64_ONLY(gen_op_rcrq ## SUFFIX ## _T0_T1_cc),\ + X86_64_ONLY(gen_op_shlq ## SUFFIX ## _T0_T1_cc),\ + X86_64_ONLY(gen_op_shrq ## SUFFIX ## _T0_T1_cc),\ + X86_64_ONLY(gen_op_shlq ## SUFFIX ## _T0_T1_cc),\ + X86_64_ONLY(gen_op_sarq ## SUFFIX ## _T0_T1_cc),\ }, -static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { +static GenOpFunc *gen_op_shift_T0_T1_cc[4][8] = { DEF_SHIFT( ) }; -static GenOpFunc *gen_op_shift_mem_T0_T1_cc[9][8] = { +static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3 * 4][8] = { DEF_SHIFT(_raw) #ifndef CONFIG_USER_ONLY DEF_SHIFT(_kernel) @@ -486,18 +598,19 @@ static GenOpFunc *gen_op_shift_mem_T0_T1_cc[9][8] = { {\ gen_op_shldl ## SUFFIX ## _T0_T1_ ## op ## _cc,\ gen_op_shrdl ## SUFFIX ## _T0_T1_ ## op ## _cc,\ + },\ + {\ }, - -static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[3][2] = { +static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[4][2] = { DEF_SHIFTD(, im) }; -static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[3][2] = { +static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[4][2] = { DEF_SHIFTD(, ECX) }; -static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[9][2] = { +static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[3 * 4][2] = { DEF_SHIFTD(_raw, im) #ifndef CONFIG_USER_ONLY DEF_SHIFTD(_kernel, im) @@ -505,7 +618,7 @@ static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[9][2] = { #endif }; -static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[9][2] = { +static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[3 * 4][2] = { DEF_SHIFTD(_raw, ECX) #ifndef CONFIG_USER_ONLY DEF_SHIFTD(_kernel, ECX) @@ -513,7 +626,7 @@ static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[9][2] = { #endif }; -static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { +static GenOpFunc *gen_op_btx_T0_T1_cc[3][4] = { [0] = { gen_op_btw_T0_T1_cc, gen_op_btsw_T0_T1_cc, @@ -526,9 +639,23 @@ static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { gen_op_btrl_T0_T1_cc, gen_op_btcl_T0_T1_cc, }, +#ifdef TARGET_X86_64 + [2] = { + gen_op_btq_T0_T1_cc, + gen_op_btsq_T0_T1_cc, + gen_op_btrq_T0_T1_cc, + gen_op_btcq_T0_T1_cc, + }, +#endif +}; + +static GenOpFunc *gen_op_add_bit_A0_T1[3] = { + gen_op_add_bitw_A0_T1, + gen_op_add_bitl_A0_T1, + X86_64_ONLY(gen_op_add_bitq_A0_T1), }; -static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { +static GenOpFunc *gen_op_bsx_T0_cc[3][2] = { [0] = { gen_op_bsfw_T0_cc, gen_op_bsrw_T0_cc, @@ -537,109 +664,158 @@ static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { gen_op_bsfl_T0_cc, gen_op_bsrl_T0_cc, }, +#ifdef TARGET_X86_64 + [2] = { + gen_op_bsfq_T0_cc, + gen_op_bsrq_T0_cc, + }, +#endif }; -static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = { +static GenOpFunc *gen_op_lds_T0_A0[3 * 4] = { gen_op_ldsb_raw_T0_A0, gen_op_ldsw_raw_T0_A0, + X86_64_ONLY(gen_op_ldsl_raw_T0_A0), NULL, #ifndef CONFIG_USER_ONLY gen_op_ldsb_kernel_T0_A0, gen_op_ldsw_kernel_T0_A0, + X86_64_ONLY(gen_op_ldsl_kernel_T0_A0), NULL, gen_op_ldsb_user_T0_A0, gen_op_ldsw_user_T0_A0, + X86_64_ONLY(gen_op_ldsl_user_T0_A0), NULL, #endif }; -static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = { +static GenOpFunc *gen_op_ldu_T0_A0[3 * 4] = { gen_op_ldub_raw_T0_A0, gen_op_lduw_raw_T0_A0, NULL, + NULL, #ifndef CONFIG_USER_ONLY gen_op_ldub_kernel_T0_A0, gen_op_lduw_kernel_T0_A0, NULL, + NULL, gen_op_ldub_user_T0_A0, gen_op_lduw_user_T0_A0, NULL, + NULL, #endif }; /* sign does not matter, except for lidt/lgdt call (TODO: fix it) */ -static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = { +static GenOpFunc *gen_op_ld_T0_A0[3 * 4] = { gen_op_ldub_raw_T0_A0, gen_op_lduw_raw_T0_A0, gen_op_ldl_raw_T0_A0, + X86_64_ONLY(gen_op_ldq_raw_T0_A0), #ifndef CONFIG_USER_ONLY gen_op_ldub_kernel_T0_A0, gen_op_lduw_kernel_T0_A0, gen_op_ldl_kernel_T0_A0, + X86_64_ONLY(gen_op_ldq_kernel_T0_A0), gen_op_ldub_user_T0_A0, gen_op_lduw_user_T0_A0, gen_op_ldl_user_T0_A0, + X86_64_ONLY(gen_op_ldq_user_T0_A0), #endif }; -static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = { +static GenOpFunc *gen_op_ld_T1_A0[3 * 4] = { gen_op_ldub_raw_T1_A0, gen_op_lduw_raw_T1_A0, gen_op_ldl_raw_T1_A0, + X86_64_ONLY(gen_op_ldq_raw_T1_A0), #ifndef CONFIG_USER_ONLY gen_op_ldub_kernel_T1_A0, gen_op_lduw_kernel_T1_A0, gen_op_ldl_kernel_T1_A0, + X86_64_ONLY(gen_op_ldq_kernel_T1_A0), gen_op_ldub_user_T1_A0, gen_op_lduw_user_T1_A0, gen_op_ldl_user_T1_A0, + X86_64_ONLY(gen_op_ldq_user_T1_A0), #endif }; -static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { +static GenOpFunc *gen_op_st_T0_A0[3 * 4] = { gen_op_stb_raw_T0_A0, gen_op_stw_raw_T0_A0, gen_op_stl_raw_T0_A0, + X86_64_ONLY(gen_op_stq_raw_T0_A0), #ifndef CONFIG_USER_ONLY gen_op_stb_kernel_T0_A0, gen_op_stw_kernel_T0_A0, gen_op_stl_kernel_T0_A0, + X86_64_ONLY(gen_op_stq_kernel_T0_A0), gen_op_stb_user_T0_A0, gen_op_stw_user_T0_A0, gen_op_stl_user_T0_A0, + X86_64_ONLY(gen_op_stq_user_T0_A0), #endif }; -static GenOpFunc *gen_op_st_T1_A0[3 * 3] = { +static GenOpFunc *gen_op_st_T1_A0[3 * 4] = { NULL, gen_op_stw_raw_T1_A0, gen_op_stl_raw_T1_A0, + X86_64_ONLY(gen_op_stq_raw_T1_A0), #ifndef CONFIG_USER_ONLY NULL, gen_op_stw_kernel_T1_A0, gen_op_stl_kernel_T1_A0, + X86_64_ONLY(gen_op_stq_kernel_T1_A0), NULL, gen_op_stw_user_T1_A0, gen_op_stl_user_T1_A0, + X86_64_ONLY(gen_op_stq_user_T1_A0), #endif }; +static inline void gen_jmp_im(target_ulong pc) +{ +#ifdef TARGET_X86_64 + if (pc == (uint32_t)pc) { + gen_op_movl_eip_im(pc); + } else if (pc == (int32_t)pc) { + gen_op_movq_eip_im(pc); + } else { + gen_op_movq_eip_im64(pc >> 32, pc); + } +#else + gen_op_movl_eip_im(pc); +#endif +} + static inline void gen_string_movl_A0_ESI(DisasContext *s) { int override; override = s->override; +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + if (override >= 0) { + gen_op_movq_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addq_A0_reg_sN[0][R_ESI](); + } else { + gen_op_movq_A0_reg[R_ESI](); + } + } else +#endif if (s->aflag) { /* 32 bit address */ if (s->addseg && override < 0) @@ -662,6 +838,11 @@ static inline void gen_string_movl_A0_ESI(DisasContext *s) static inline void gen_string_movl_A0_EDI(DisasContext *s) { +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_movq_A0_reg[R_EDI](); + } else +#endif if (s->aflag) { if (s->addseg) { gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); @@ -676,58 +857,43 @@ static inline void gen_string_movl_A0_EDI(DisasContext *s) } } -static GenOpFunc *gen_op_movl_T0_Dshift[3] = { +static GenOpFunc *gen_op_movl_T0_Dshift[4] = { gen_op_movl_T0_Dshiftb, gen_op_movl_T0_Dshiftw, gen_op_movl_T0_Dshiftl, + X86_64_ONLY(gen_op_movl_T0_Dshiftq), }; -static GenOpFunc2 *gen_op_jz_ecx[2] = { - gen_op_jz_ecxw, - gen_op_jz_ecxl, +static GenOpFunc1 *gen_op_jnz_ecx[3] = { + gen_op_jnz_ecxw, + gen_op_jnz_ecxl, + X86_64_ONLY(gen_op_jnz_ecxq), }; -static GenOpFunc1 *gen_op_jz_ecx_im[2] = { - gen_op_jz_ecxw_im, - gen_op_jz_ecxl_im, +static GenOpFunc1 *gen_op_jz_ecx[3] = { + gen_op_jz_ecxw, + gen_op_jz_ecxl, + X86_64_ONLY(gen_op_jz_ecxq), }; -static GenOpFunc *gen_op_dec_ECX[2] = { +static GenOpFunc *gen_op_dec_ECX[3] = { gen_op_decw_ECX, gen_op_decl_ECX, + X86_64_ONLY(gen_op_decq_ECX), }; -#ifdef USE_DIRECT_JUMP -typedef GenOpFunc GenOpFuncTB2; -#define gen_op_string_jnz_sub(nz, ot, tb) gen_op_string_jnz_sub2[nz][ot]() -#else -typedef GenOpFunc1 GenOpFuncTB2; -#define gen_op_string_jnz_sub(nz, ot, tb) gen_op_string_jnz_sub2[nz][ot](tb) -#endif - -static GenOpFuncTB2 *gen_op_string_jnz_sub2[2][3] = { +static GenOpFunc1 *gen_op_string_jnz_sub[2][4] = { { - gen_op_string_jnz_subb, - gen_op_string_jnz_subw, - gen_op_string_jnz_subl, + gen_op_jnz_subb, + gen_op_jnz_subw, + gen_op_jnz_subl, + X86_64_ONLY(gen_op_jnz_subq), }, { - gen_op_string_jz_subb, - gen_op_string_jz_subw, - gen_op_string_jz_subl, - }, -}; - -static GenOpFunc1 *gen_op_string_jnz_sub_im[2][3] = { - { - gen_op_string_jnz_subb_im, - gen_op_string_jnz_subw_im, - gen_op_string_jnz_subl_im, - }, - { - gen_op_string_jz_subb_im, - gen_op_string_jz_subw_im, - gen_op_string_jz_subl_im, + gen_op_jz_subb, + gen_op_jz_subw, + gen_op_jz_subl, + X86_64_ONLY(gen_op_jz_subq), }, }; @@ -767,12 +933,12 @@ static GenOpFunc *gen_check_io_DX[3] = { gen_op_check_iol_DX, }; -static void gen_check_io(DisasContext *s, int ot, int use_dx, int cur_eip) +static void gen_check_io(DisasContext *s, int ot, int use_dx, target_ulong cur_eip) { if (s->pe && (s->cpl > s->iopl || s->vm86)) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(cur_eip); + gen_jmp_im(cur_eip); if (use_dx) gen_check_io_DX[ot](); else @@ -787,6 +953,12 @@ static inline void gen_movs(DisasContext *s, int ot) gen_string_movl_A0_EDI(s); gen_op_st_T0_A0[ot + s->mem_index](); gen_op_movl_T0_Dshift[ot](); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_ESI_T0(); + gen_op_addq_EDI_T0(); + } else +#endif if (s->aflag) { gen_op_addl_ESI_T0(); gen_op_addl_EDI_T0(); @@ -804,15 +976,19 @@ static inline void gen_update_cc_op(DisasContext *s) } } -static inline void gen_jz_ecx_string(DisasContext *s, unsigned int next_eip) +/* XXX: does not work with gdbstub "ice" single step - not a + serious problem */ +static int gen_jz_ecx_string(DisasContext *s, target_ulong next_eip) { - if (s->jmp_opt) { - gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); - } else { - /* XXX: does not work with gdbstub "ice" single step - not a - serious problem */ - gen_op_jz_ecx_im[s->aflag](next_eip); - } + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + gen_op_jnz_ecx[s->aflag](l1); + gen_set_label(l2); + gen_jmp_tb(s, next_eip, 1); + gen_set_label(l1); + return l2; } static inline void gen_stos(DisasContext *s, int ot) @@ -821,6 +997,11 @@ static inline void gen_stos(DisasContext *s, int ot) gen_string_movl_A0_EDI(s); gen_op_st_T0_A0[ot + s->mem_index](); gen_op_movl_T0_Dshift[ot](); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_EDI_T0(); + } else +#endif if (s->aflag) { gen_op_addl_EDI_T0(); } else { @@ -834,6 +1015,11 @@ static inline void gen_lods(DisasContext *s, int ot) gen_op_ld_T0_A0[ot + s->mem_index](); gen_op_mov_reg_T0[ot][R_EAX](); gen_op_movl_T0_Dshift[ot](); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_ESI_T0(); + } else +#endif if (s->aflag) { gen_op_addl_ESI_T0(); } else { @@ -848,6 +1034,11 @@ static inline void gen_scas(DisasContext *s, int ot) gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_cmpl_T0_T1_cc(); gen_op_movl_T0_Dshift[ot](); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_EDI_T0(); + } else +#endif if (s->aflag) { gen_op_addl_EDI_T0(); } else { @@ -863,6 +1054,12 @@ static inline void gen_cmps(DisasContext *s, int ot) gen_op_ld_T1_A0[ot + s->mem_index](); gen_op_cmpl_T0_T1_cc(); gen_op_movl_T0_Dshift[ot](); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_ESI_T0(); + gen_op_addq_EDI_T0(); + } else +#endif if (s->aflag) { gen_op_addl_ESI_T0(); gen_op_addl_EDI_T0(); @@ -880,6 +1077,11 @@ static inline void gen_ins(DisasContext *s, int ot) gen_op_in_DX_T0[ot](); gen_op_st_T0_A0[ot + s->mem_index](); gen_op_movl_T0_Dshift[ot](); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_EDI_T0(); + } else +#endif if (s->aflag) { gen_op_addl_EDI_T0(); } else { @@ -893,6 +1095,11 @@ static inline void gen_outs(DisasContext *s, int ot) gen_op_ld_T0_A0[ot + s->mem_index](); gen_op_out_DX_T0[ot](); gen_op_movl_T0_Dshift[ot](); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_ESI_T0(); + } else +#endif if (s->aflag) { gen_op_addl_ESI_T0(); } else { @@ -904,36 +1111,35 @@ static inline void gen_outs(DisasContext *s, int ot) instruction */ #define GEN_REPZ(op) \ static inline void gen_repz_ ## op(DisasContext *s, int ot, \ - unsigned int cur_eip, unsigned int next_eip) \ + target_ulong cur_eip, target_ulong next_eip) \ { \ + int l2;\ gen_update_cc_op(s); \ - gen_jz_ecx_string(s, next_eip); \ + l2 = gen_jz_ecx_string(s, next_eip); \ gen_ ## op(s, ot); \ gen_op_dec_ECX[s->aflag](); \ /* a loop would cause two single step exceptions if ECX = 1 \ before rep string_insn */ \ if (!s->jmp_opt) \ - gen_op_jz_ecx_im[s->aflag](next_eip); \ + gen_op_jz_ecx[s->aflag](l2); \ gen_jmp(s, cur_eip); \ } #define GEN_REPZ2(op) \ static inline void gen_repz_ ## op(DisasContext *s, int ot, \ - unsigned int cur_eip, \ - unsigned int next_eip, \ + target_ulong cur_eip, \ + target_ulong next_eip, \ int nz) \ { \ + int l2;\ gen_update_cc_op(s); \ - gen_jz_ecx_string(s, next_eip); \ + l2 = gen_jz_ecx_string(s, next_eip); \ gen_ ## op(s, ot); \ gen_op_dec_ECX[s->aflag](); \ gen_op_set_cc_op(CC_OP_SUBB + ot); \ + gen_op_string_jnz_sub[nz][ot](l2);\ if (!s->jmp_opt) \ - gen_op_string_jnz_sub_im[nz][ot](next_eip); \ - else \ - gen_op_string_jnz_sub(nz, ot, (long)s->tb); \ - if (!s->jmp_opt) \ - gen_op_jz_ecx_im[s->aflag](next_eip); \ + gen_op_jz_ecx[s->aflag](l2); \ gen_jmp(s, cur_eip); \ } @@ -956,7 +1162,7 @@ enum { JCC_LE, }; -static GenOpFunc3 *gen_jcc_sub[3][8] = { +static GenOpFunc1 *gen_jcc_sub[4][8] = { [OT_BYTE] = { NULL, gen_op_jb_subb, @@ -987,20 +1193,37 @@ static GenOpFunc3 *gen_jcc_sub[3][8] = { gen_op_jl_subl, gen_op_jle_subl, }, +#ifdef TARGET_X86_64 + [OT_QUAD] = { + NULL, + BUGGY_64(gen_op_jb_subq), + gen_op_jz_subq, + BUGGY_64(gen_op_jbe_subq), + gen_op_js_subq, + NULL, + BUGGY_64(gen_op_jl_subq), + BUGGY_64(gen_op_jle_subq), + }, +#endif }; -static GenOpFunc2 *gen_op_loop[2][4] = { +static GenOpFunc1 *gen_op_loop[3][4] = { [0] = { gen_op_loopnzw, gen_op_loopzw, - gen_op_loopw, - gen_op_jecxzw, + gen_op_jnz_ecxw, }, [1] = { gen_op_loopnzl, gen_op_loopzl, - gen_op_loopl, - gen_op_jecxzl, + gen_op_jnz_ecxl, + }, +#ifdef TARGET_X86_64 + [2] = { + gen_op_loopnzq, + gen_op_loopzq, + gen_op_jnz_ecxq, }, +#endif }; static GenOpFunc *gen_setcc_slow[8] = { @@ -1014,7 +1237,7 @@ static GenOpFunc *gen_setcc_slow[8] = { gen_op_setle_T0_cc, }; -static GenOpFunc *gen_setcc_sub[3][8] = { +static GenOpFunc *gen_setcc_sub[4][8] = { [OT_BYTE] = { NULL, gen_op_setb_T0_subb, @@ -1045,6 +1268,18 @@ static GenOpFunc *gen_setcc_sub[3][8] = { gen_op_setl_T0_subl, gen_op_setle_T0_subl, }, +#ifdef TARGET_X86_64 + [OT_QUAD] = { + NULL, + gen_op_setb_T0_subq, + gen_op_setz_T0_subq, + gen_op_setbe_T0_subq, + gen_op_sets_T0_subq, + NULL, + gen_op_setl_T0_subq, + gen_op_setle_T0_subq, + }, +#endif }; static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { @@ -1183,8 +1418,9 @@ static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) { + target_long disp; int havesib; - int base, disp; + int base; int index; int scale; int opreg; @@ -1208,16 +1444,20 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ havesib = 1; code = ldub_code(s->pc++); scale = (code >> 6) & 3; - index = (code >> 3) & 7; - base = code & 7; + index = ((code >> 3) & 7) | REX_X(s); + base = (code & 7); } + base |= REX_B(s); switch (mod) { case 0: - if (base == 5) { + if ((base & 7) == 5) { base = -1; - disp = ldl_code(s->pc); + disp = (int32_t)ldl_code(s->pc); s->pc += 4; + if (CODE64(s) && !havesib) { + disp += s->pc + s->rip_offset; + } } else { disp = 0; } @@ -1236,15 +1476,45 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ /* for correct popl handling with esp */ if (base == 4 && s->popl_esp_hack) disp += s->popl_esp_hack; - gen_op_movl_A0_reg[base](); - if (disp != 0) - gen_op_addl_A0_im(disp); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_movq_A0_reg[base](); + if (disp != 0) { + if ((int32_t)disp == disp) + gen_op_addq_A0_im(disp); + else + gen_op_addq_A0_im64(disp >> 32, disp); + } + } else +#endif + { + gen_op_movl_A0_reg[base](); + if (disp != 0) + gen_op_addl_A0_im(disp); + } } else { - gen_op_movl_A0_im(disp); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + if ((int32_t)disp == disp) + gen_op_movq_A0_im(disp); + else + gen_op_movq_A0_im64(disp >> 32, disp); + } else +#endif + { + gen_op_movl_A0_im(disp); + } } /* XXX: index == 4 is always invalid */ if (havesib && (index != 4 || scale != 0)) { - gen_op_addl_A0_reg_sN[scale][index](); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_A0_reg_sN[scale][index](); + } else +#endif + { + gen_op_addl_A0_reg_sN[scale][index](); + } } if (must_add_seg) { if (override < 0) { @@ -1253,7 +1523,14 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ else override = R_DS; } - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base)); + } else +#endif + { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } } } else { switch (mod) { @@ -1336,7 +1613,7 @@ static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_s int mod, rm, opreg, disp; mod = (modrm >> 6) & 3; - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); if (mod == 3) { if (is_store) { if (reg != OR_TMP0) @@ -1383,11 +1660,22 @@ static inline uint32_t insn_get(DisasContext *s, int ot) return ret; } -static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) +static inline int insn_const_size(unsigned int ot) +{ + if (ot <= OT_LONG) + return 1 << ot; + else + return 4; +} + +static inline void gen_jcc(DisasContext *s, int b, + target_ulong val, target_ulong next_eip) { TranslationBlock *tb; int inv, jcc_op; - GenOpFunc3 *func; + GenOpFunc1 *func; + target_ulong tmp; + int l1, l2; inv = b & 1; jcc_op = (b >> 1) & 7; @@ -1398,6 +1686,7 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) case CC_OP_SUBB: case CC_OP_SUBW: case CC_OP_SUBL: + case CC_OP_SUBQ: func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; break; @@ -1405,33 +1694,48 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) case CC_OP_ADDB: case CC_OP_ADDW: case CC_OP_ADDL: + case CC_OP_ADDQ: + case CC_OP_ADCB: case CC_OP_ADCW: case CC_OP_ADCL: + case CC_OP_ADCQ: + case CC_OP_SBBB: case CC_OP_SBBW: case CC_OP_SBBL: + case CC_OP_SBBQ: + case CC_OP_LOGICB: case CC_OP_LOGICW: case CC_OP_LOGICL: + case CC_OP_LOGICQ: + case CC_OP_INCB: case CC_OP_INCW: case CC_OP_INCL: + case CC_OP_INCQ: + case CC_OP_DECB: case CC_OP_DECW: case CC_OP_DECL: + case CC_OP_DECQ: + case CC_OP_SHLB: case CC_OP_SHLW: case CC_OP_SHLL: + case CC_OP_SHLQ: + case CC_OP_SARB: case CC_OP_SARW: case CC_OP_SARL: + case CC_OP_SARQ: switch(jcc_op) { case JCC_Z: - func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op]; break; case JCC_S: - func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op]; break; default: func = NULL; @@ -1448,27 +1752,51 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) if (!func) { gen_setcc_slow[jcc_op](); - func = gen_op_jcc; + func = gen_op_jnz_T0_label; } - tb = s->tb; - if (!inv) { - func((long)tb, val, next_eip); - } else { - func((long)tb, next_eip, val); + if (inv) { + tmp = val; + val = next_eip; + next_eip = tmp; } + tb = s->tb; + + l1 = gen_new_label(); + func(l1); + + gen_op_goto_tb0(); + gen_jmp_im(next_eip); + gen_op_movl_T0_im((long)tb + 0); + gen_op_exit_tb(); + + gen_set_label(l1); + gen_op_goto_tb1(); + gen_jmp_im(val); + gen_op_movl_T0_im((long)tb + 1); + gen_op_exit_tb(); + s->is_jmp = 3; } else { + if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } gen_setcc_slow[jcc_op](); - if (!inv) { - gen_op_jcc_im(val, next_eip); - } else { - gen_op_jcc_im(next_eip, val); + if (inv) { + tmp = val; + val = next_eip; + next_eip = tmp; } + l1 = gen_new_label(); + l2 = gen_new_label(); + gen_op_jnz_T0_label(l1); + gen_jmp_im(next_eip); + gen_op_jmp_label(l2); + gen_set_label(l1); + gen_jmp_im(val); + gen_set_label(l2); gen_eob(s); } } @@ -1485,6 +1813,7 @@ static void gen_setcc(DisasContext *s, int b) case CC_OP_SUBB: case CC_OP_SUBW: case CC_OP_SUBL: + case CC_OP_SUBQ: func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; if (!func) goto slow_jcc; @@ -1494,24 +1823,33 @@ static void gen_setcc(DisasContext *s, int b) case CC_OP_ADDB: case CC_OP_ADDW: case CC_OP_ADDL: + case CC_OP_ADDQ: + case CC_OP_LOGICB: case CC_OP_LOGICW: case CC_OP_LOGICL: + case CC_OP_LOGICQ: + case CC_OP_INCB: case CC_OP_INCW: case CC_OP_INCL: + case CC_OP_INCQ: + case CC_OP_DECB: case CC_OP_DECW: case CC_OP_DECL: + case CC_OP_DECQ: + case CC_OP_SHLB: case CC_OP_SHLW: case CC_OP_SHLL: + case CC_OP_SHLQ: switch(jcc_op) { case JCC_Z: - func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op]; break; case JCC_S: - func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op]; break; default: goto slow_jcc; @@ -1532,13 +1870,13 @@ static void gen_setcc(DisasContext *s, int b) /* move T0 to seg_reg and compute if the CPU state may change. Never call this function with seg_reg == R_CS */ -static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) +static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip) { if (s->pe && !s->vm86) { /* XXX: optimize by finding processor state dynamically */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(cur_eip); + gen_jmp_im(cur_eip); gen_op_movl_seg_T0(seg_reg); /* abort translation because the addseg value may change or because ss32 may change. For R_SS, translation must always @@ -1555,6 +1893,14 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) static inline void gen_stack_update(DisasContext *s, int addend) { +#ifdef TARGET_X86_64 + if (CODE64(s)) { + if (addend == 8) + gen_op_addq_ESP_8(); + else + gen_op_addq_ESP_im(addend); + } else +#endif if (s->ss32) { if (addend == 2) gen_op_addl_ESP_2(); @@ -1575,70 +1921,108 @@ static inline void gen_stack_update(DisasContext *s, int addend) /* generate a push. It depends on ss32, addseg and dflag */ static void gen_push_T0(DisasContext *s) { - gen_op_movl_A0_reg[R_ESP](); - if (!s->dflag) - gen_op_subl_A0_2(); - else - gen_op_subl_A0_4(); - if (s->ss32) { - if (s->addseg) { +#ifdef TARGET_X86_64 + if (CODE64(s)) { + /* XXX: check 16 bit behaviour */ + gen_op_movq_A0_reg[R_ESP](); + gen_op_subq_A0_8(); + gen_op_st_T0_A0[OT_QUAD + s->mem_index](); + gen_op_movq_ESP_A0(); + } else +#endif + { + gen_op_movl_A0_reg[R_ESP](); + if (!s->dflag) + gen_op_subl_A0_2(); + else + gen_op_subl_A0_4(); + if (s->ss32) { + if (s->addseg) { + gen_op_movl_T1_A0(); + gen_op_addl_A0_SS(); + } + } else { + gen_op_andl_A0_ffff(); gen_op_movl_T1_A0(); gen_op_addl_A0_SS(); } - } else { - gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - gen_op_addl_A0_SS(); + gen_op_st_T0_A0[s->dflag + 1 + s->mem_index](); + if (s->ss32 && !s->addseg) + gen_op_movl_ESP_A0(); + else + gen_op_mov_reg_T1[s->ss32 + 1][R_ESP](); } - gen_op_st_T0_A0[s->dflag + 1 + s->mem_index](); - if (s->ss32 && !s->addseg) - gen_op_movl_ESP_A0(); - else - gen_op_mov_reg_T1[s->ss32 + 1][R_ESP](); } /* generate a push. It depends on ss32, addseg and dflag */ /* slower version for T1, only used for call Ev */ static void gen_push_T1(DisasContext *s) { - gen_op_movl_A0_reg[R_ESP](); - if (!s->dflag) - gen_op_subl_A0_2(); - else - gen_op_subl_A0_4(); - if (s->ss32) { - if (s->addseg) { +#ifdef TARGET_X86_64 + if (CODE64(s)) { + /* XXX: check 16 bit behaviour */ + gen_op_movq_A0_reg[R_ESP](); + gen_op_subq_A0_8(); + gen_op_st_T1_A0[OT_QUAD + s->mem_index](); + gen_op_movq_ESP_A0(); + } else +#endif + { + gen_op_movl_A0_reg[R_ESP](); + if (!s->dflag) + gen_op_subl_A0_2(); + else + gen_op_subl_A0_4(); + if (s->ss32) { + if (s->addseg) { + gen_op_addl_A0_SS(); + } + } else { + gen_op_andl_A0_ffff(); gen_op_addl_A0_SS(); } - } else { - gen_op_andl_A0_ffff(); - gen_op_addl_A0_SS(); + gen_op_st_T1_A0[s->dflag + 1 + s->mem_index](); + + if (s->ss32 && !s->addseg) + gen_op_movl_ESP_A0(); + else + gen_stack_update(s, (-2) << s->dflag); } - gen_op_st_T1_A0[s->dflag + 1 + s->mem_index](); - - if (s->ss32 && !s->addseg) - gen_op_movl_ESP_A0(); - else - gen_stack_update(s, (-2) << s->dflag); } /* two step pop is necessary for precise exceptions */ static void gen_pop_T0(DisasContext *s) { - gen_op_movl_A0_reg[R_ESP](); - if (s->ss32) { - if (s->addseg) +#ifdef TARGET_X86_64 + if (CODE64(s)) { + /* XXX: check 16 bit behaviour */ + gen_op_movq_A0_reg[R_ESP](); + gen_op_ld_T0_A0[OT_QUAD + s->mem_index](); + } else +#endif + { + gen_op_movl_A0_reg[R_ESP](); + if (s->ss32) { + if (s->addseg) + gen_op_addl_A0_SS(); + } else { + gen_op_andl_A0_ffff(); gen_op_addl_A0_SS(); - } else { - gen_op_andl_A0_ffff(); - gen_op_addl_A0_SS(); + } + gen_op_ld_T0_A0[s->dflag + 1 + s->mem_index](); } - gen_op_ld_T0_A0[s->dflag + 1 + s->mem_index](); } static void gen_pop_update(DisasContext *s) { - gen_stack_update(s, 2 << s->dflag); +#ifdef TARGET_X86_64 + if (CODE64(s)) { + gen_stack_update(s, 8); + } else +#endif + { + gen_stack_update(s, 2 << s->dflag); + } } static void gen_stack_A0(DisasContext *s) @@ -1718,11 +2102,11 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_mov_reg_T1[ot][R_ESP](); } -static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) +static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(cur_eip); + gen_jmp_im(cur_eip); gen_op_raise_exception(trapno); s->is_jmp = 3; } @@ -1730,20 +2114,20 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) /* an interrupt is different from an exception because of the priviledge checks */ static void gen_interrupt(DisasContext *s, int intno, - unsigned int cur_eip, unsigned int next_eip) + target_ulong cur_eip, target_ulong next_eip) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(cur_eip); + gen_jmp_im(cur_eip); gen_op_raise_interrupt(intno, next_eip); s->is_jmp = 3; } -static void gen_debug(DisasContext *s, unsigned int cur_eip) +static void gen_debug(DisasContext *s, target_ulong cur_eip) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(cur_eip); + gen_jmp_im(cur_eip); gen_op_debug(); s->is_jmp = 3; } @@ -1770,80 +2154,186 @@ static void gen_eob(DisasContext *s) /* generate a jump to eip. No segment change must happen before as a direct call to the next block may occur */ -static void gen_jmp(DisasContext *s, unsigned int eip) +static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num) { TranslationBlock *tb = s->tb; if (s->jmp_opt) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp((long)tb, eip); + if (tb_num) + gen_op_goto_tb1(); + else + gen_op_goto_tb0(); + gen_jmp_im(eip); + gen_op_movl_T0_im((long)tb + tb_num); + gen_op_exit_tb(); s->is_jmp = 3; } else { - gen_op_jmp_im(eip); + gen_jmp_im(eip); gen_eob(s); } } +static void gen_jmp(DisasContext *s, target_ulong eip) +{ + gen_jmp_tb(s, eip, 0); +} + +static void gen_movtl_T0_im(target_ulong val) +{ +#ifdef TARGET_X86_64 + if ((int32_t)val == val) { + gen_op_movl_T0_im(val); + } else { + gen_op_movq_T0_im64(val >> 32, val); + } +#else + gen_op_movl_T0_im(val); +#endif +} + +static GenOpFunc1 *gen_ldo_env_A0[3] = { + gen_op_ldo_raw_env_A0, +#ifndef CONFIG_USER_ONLY + gen_op_ldo_kernel_env_A0, + gen_op_ldo_user_env_A0, +#endif +}; + +static GenOpFunc1 *gen_sto_env_A0[3] = { + gen_op_sto_raw_env_A0, +#ifndef CONFIG_USER_ONLY + gen_op_sto_kernel_env_A0, + gen_op_sto_user_env_A0, +#endif +}; + /* convert one instruction. s->is_jmp is set if the translation must be stopped. Return the next pc value */ -static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) +static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) { int b, prefixes, aflag, dflag; int shift, ot; int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; - unsigned int next_eip; + target_ulong next_eip, tval; + int rex_w, rex_r; s->pc = pc_start; prefixes = 0; aflag = s->code32; dflag = s->code32; s->override = -1; + rex_w = -1; + rex_r = 0; +#ifdef TARGET_X86_64 + s->rex_x = 0; + s->rex_b = 0; + x86_64_hregs = 0; +#endif + s->rip_offset = 0; /* for relative ip address */ next_byte: b = ldub_code(s->pc); s->pc++; /* check prefixes */ - switch (b) { - case 0xf3: - prefixes |= PREFIX_REPZ; - goto next_byte; - case 0xf2: - prefixes |= PREFIX_REPNZ; - goto next_byte; - case 0xf0: - prefixes |= PREFIX_LOCK; - goto next_byte; - case 0x2e: - s->override = R_CS; - goto next_byte; - case 0x36: - s->override = R_SS; - goto next_byte; - case 0x3e: - s->override = R_DS; - goto next_byte; - case 0x26: - s->override = R_ES; - goto next_byte; - case 0x64: - s->override = R_FS; - goto next_byte; - case 0x65: - s->override = R_GS; - goto next_byte; - case 0x66: - prefixes |= PREFIX_DATA; - goto next_byte; - case 0x67: - prefixes |= PREFIX_ADR; - goto next_byte; +#ifdef TARGET_X86_64 + if (CODE64(s)) { + switch (b) { + case 0xf3: + prefixes |= PREFIX_REPZ; + goto next_byte; + case 0xf2: + prefixes |= PREFIX_REPNZ; + goto next_byte; + case 0xf0: + prefixes |= PREFIX_LOCK; + goto next_byte; + case 0x2e: + s->override = R_CS; + goto next_byte; + case 0x36: + s->override = R_SS; + goto next_byte; + case 0x3e: + s->override = R_DS; + goto next_byte; + case 0x26: + s->override = R_ES; + goto next_byte; + case 0x64: + s->override = R_FS; + goto next_byte; + case 0x65: + s->override = R_GS; + goto next_byte; + case 0x66: + prefixes |= PREFIX_DATA; + goto next_byte; + case 0x67: + prefixes |= PREFIX_ADR; + goto next_byte; + case 0x40 ... 0x4f: + /* REX prefix */ + rex_w = (b >> 3) & 1; + rex_r = (b & 0x4) << 1; + s->rex_x = (b & 0x2) << 2; + REX_B(s) = (b & 0x1) << 3; + x86_64_hregs = 1; /* select uniform byte register addressing */ + goto next_byte; + } + if (rex_w == 1) { + /* 0x66 is ignored if rex.w is set */ + dflag = 2; + } else { + if (prefixes & PREFIX_DATA) + dflag ^= 1; + } + if (!(prefixes & PREFIX_ADR)) + aflag = 2; + } else +#endif + { + switch (b) { + case 0xf3: + prefixes |= PREFIX_REPZ; + goto next_byte; + case 0xf2: + prefixes |= PREFIX_REPNZ; + goto next_byte; + case 0xf0: + prefixes |= PREFIX_LOCK; + goto next_byte; + case 0x2e: + s->override = R_CS; + goto next_byte; + case 0x36: + s->override = R_SS; + goto next_byte; + case 0x3e: + s->override = R_DS; + goto next_byte; + case 0x26: + s->override = R_ES; + goto next_byte; + case 0x64: + s->override = R_FS; + goto next_byte; + case 0x65: + s->override = R_GS; + goto next_byte; + case 0x66: + prefixes |= PREFIX_DATA; + goto next_byte; + case 0x67: + prefixes |= PREFIX_ADR; + goto next_byte; + } + if (prefixes & PREFIX_DATA) + dflag ^= 1; + if (prefixes & PREFIX_ADR) + aflag ^= 1; } - if (prefixes & PREFIX_DATA) - dflag ^= 1; - if (prefixes & PREFIX_ADR) - aflag ^= 1; - s->prefix = prefixes; s->aflag = aflag; s->dflag = dflag; @@ -1879,14 +2369,14 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7); + reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); opreg = OR_TMP0; @@ -1907,8 +2397,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 1: /* OP Gv, Ev */ modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; - reg = ((modrm >> 3) & 7); - rm = modrm & 7; + reg = ((modrm >> 3) & 7) | rex_r; + rm = (modrm & 7) | REX_B(s); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[ot + s->mem_index](); @@ -1938,18 +2428,22 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); op = (modrm >> 3) & 7; if (mod != 3) { + if (b == 0x83) + s->rip_offset = 1; + else + s->rip_offset = insn_const_size(ot); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); opreg = OR_TMP0; } else { - opreg = rm + OR_EAX; + opreg = rm; } switch(b) { @@ -1983,13 +2477,15 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); op = (modrm >> 3) & 7; if (mod != 3) { + if (op == 0) + s->rip_offset = insn_const_size(ot); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T0_A0[ot + s->mem_index](); } else { @@ -2036,6 +2532,12 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mull_EAX_T0(); s->cc_op = CC_OP_MULL; break; +#ifdef TARGET_X86_64 + case OT_QUAD: + gen_op_mulq_EAX_T0(); + s->cc_op = CC_OP_MULQ; + break; +#endif } break; case 5: /* imul */ @@ -2053,34 +2555,58 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_imull_EAX_T0(); s->cc_op = CC_OP_MULL; break; +#ifdef TARGET_X86_64 + case OT_QUAD: + gen_op_imulq_EAX_T0(); + s->cc_op = CC_OP_MULQ; + break; +#endif } break; case 6: /* div */ switch(ot) { case OT_BYTE: - gen_op_divb_AL_T0(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); + gen_op_divb_AL_T0(); break; case OT_WORD: - gen_op_divw_AX_T0(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); + gen_op_divw_AX_T0(); break; default: case OT_LONG: - gen_op_divl_EAX_T0(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); + gen_op_divl_EAX_T0(); + break; +#ifdef TARGET_X86_64 + case OT_QUAD: + gen_jmp_im(pc_start - s->cs_base); + gen_op_divq_EAX_T0(); break; +#endif } break; case 7: /* idiv */ switch(ot) { case OT_BYTE: - gen_op_idivb_AL_T0(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); + gen_op_idivb_AL_T0(); break; case OT_WORD: - gen_op_idivw_AX_T0(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); + gen_op_idivw_AX_T0(); break; default: case OT_LONG: - gen_op_idivl_EAX_T0(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); + gen_op_idivl_EAX_T0(); + break; +#ifdef TARGET_X86_64 + case OT_QUAD: + gen_jmp_im(pc_start - s->cs_base); + gen_op_idivq_EAX_T0(); break; +#endif } break; default: @@ -2093,15 +2619,24 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); op = (modrm >> 3) & 7; if (op >= 2 && b == 0xfe) { goto illegal_op; } + if (CODE64(s)) { + if (op >= 2 && op <= 5) { + /* operand size for jumps is 64 bit */ + ot = OT_QUAD; + } else if (op == 6) { + /* default push size is 64 bit */ + ot = dflag ? OT_QUAD : OT_WORD; + } + } if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (op >= 2 && op != 3 && op != 5) @@ -2143,7 +2678,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base); } else { gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); @@ -2164,7 +2699,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_ljmp_protected_T0_T1(s->pc - s->cs_base); } else { gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); @@ -2186,15 +2721,15 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; - rm = modrm & 7; - reg = (modrm >> 3) & 7; + rm = (modrm & 7) | REX_B(s); + reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); - gen_op_mov_TN_reg[ot][1][reg + OR_EAX](); + gen_op_mov_TN_reg[ot][1][reg](); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; @@ -2204,7 +2739,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; val = insn_get(s, ot); gen_op_mov_TN_reg[ot][0][OR_EAX](); @@ -2214,13 +2749,23 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x98: /* CWDE/CBW */ - if (dflag) +#ifdef TARGET_X86_64 + if (dflag == 2) { + gen_op_movslq_RAX_EAX(); + } else +#endif + if (dflag == 1) gen_op_movswl_EAX_AX(); else gen_op_movsbw_AX_AL(); break; case 0x99: /* CDQ/CWD */ - if (dflag) +#ifdef TARGET_X86_64 + if (dflag == 2) { + gen_op_movsqo_RDX_RAX(); + } else +#endif + if (dflag == 1) gen_op_movslq_EDX_EAX(); else gen_op_movswl_DX_AX(); @@ -2228,9 +2773,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x1af: /* imul Gv, Ev */ case 0x69: /* imul Gv, Ev, I */ case 0x6b: - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) + OR_EAX; + reg = ((modrm >> 3) & 7) | rex_r; + if (b == 0x69) + s->rip_offset = insn_const_size(ot); + else if (b == 0x6b) + s->rip_offset = 1; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); if (b == 0x69) { val = insn_get(s, ot); @@ -2242,6 +2791,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_TN_reg[ot][1][reg](); } +#ifdef TARGET_X86_64 + if (ot == OT_QUAD) { + gen_op_imulq_T0_T1(); + } else +#endif if (ot == OT_LONG) { gen_op_imull_T0_T1(); } else { @@ -2255,12 +2809,12 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; if (mod == 3) { - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); gen_op_mov_TN_reg[ot][0][reg](); gen_op_mov_TN_reg[ot][1][rm](); gen_op_addl_T0_T1(); @@ -2282,13 +2836,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; gen_op_mov_TN_reg[ot][1][reg](); if (mod == 3) { - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); gen_op_mov_TN_reg[ot][0][rm](); gen_op_cmpxchg_T0_T1_EAX_cc[ot](); gen_op_mov_reg_T0[ot][rm](); @@ -2314,25 +2868,37 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ - gen_op_mov_TN_reg[OT_LONG][0][b & 7](); + gen_op_mov_TN_reg[OT_LONG][0][(b & 7) | REX_B(s)](); gen_push_T0(s); break; case 0x58 ... 0x5f: /* pop */ - ot = dflag ? OT_LONG : OT_WORD; + if (CODE64(s)) { + ot = dflag ? OT_QUAD : OT_WORD; + } else { + ot = dflag + OT_WORD; + } gen_pop_T0(s); /* NOTE: order is important for pop %sp */ gen_pop_update(s); - gen_op_mov_reg_T0[ot][b & 7](); + gen_op_mov_reg_T0[ot][(b & 7) | REX_B(s)](); break; case 0x60: /* pusha */ + if (CODE64(s)) + goto illegal_op; gen_pusha(s); break; case 0x61: /* popa */ + if (CODE64(s)) + goto illegal_op; gen_popa(s); break; case 0x68: /* push Iv */ case 0x6a: - ot = dflag ? OT_LONG : OT_WORD; + if (CODE64(s)) { + ot = dflag ? OT_QUAD : OT_WORD; + } else { + ot = dflag + OT_WORD; + } if (b == 0x68) val = insn_get(s, ot); else @@ -2341,18 +2907,22 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_push_T0(s); break; case 0x8f: /* pop Ev */ - ot = dflag ? OT_LONG : OT_WORD; + if (CODE64(s)) { + ot = dflag ? OT_QUAD : OT_WORD; + } else { + ot = dflag + OT_WORD; + } modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; gen_pop_T0(s); if (mod == 3) { /* NOTE: order is important for pop %sp */ gen_pop_update(s); - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); gen_op_mov_reg_T0[ot][rm](); } else { /* NOTE: order is important too for MMU exceptions */ - s->popl_esp_hack = 2 << dflag; + s->popl_esp_hack = 1 << ot; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); s->popl_esp_hack = 0; gen_pop_update(s); @@ -2360,6 +2930,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xc8: /* enter */ { + /* XXX: long mode support */ int level; val = lduw_code(s->pc); s->pc += 2; @@ -2369,7 +2940,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xc9: /* leave */ /* XXX: exception not precise (ESP is updated before potential exception) */ - if (s->ss32) { + /* XXX: may be invalid for 16 bit in long mode */ + if (CODE64(s)) { + gen_op_mov_TN_reg[OT_QUAD][0][R_EBP](); + gen_op_mov_reg_T0[OT_QUAD][R_ESP](); + } else if (s->ss32) { gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); gen_op_mov_reg_T0[OT_LONG][R_ESP](); } else { @@ -2377,7 +2952,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_mov_reg_T0[OT_WORD][R_ESP](); } gen_pop_T0(s); - ot = dflag ? OT_LONG : OT_WORD; + if (CODE64(s)) { + ot = dflag ? OT_QUAD : OT_WORD; + } else { + ot = dflag + OT_WORD; + } gen_op_mov_reg_T0[ot][R_EBP](); gen_pop_update(s); break; @@ -2385,6 +2964,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x0e: /* push cs */ case 0x16: /* push ss */ case 0x1e: /* push ds */ + if (CODE64(s)) + goto illegal_op; gen_op_movl_T0_seg(b >> 3); gen_push_T0(s); break; @@ -2396,6 +2977,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x07: /* pop es */ case 0x17: /* pop ss */ case 0x1f: /* pop ds */ + if (CODE64(s)) + goto illegal_op; reg = b >> 3; gen_pop_T0(s); gen_movl_seg_T0(s, reg, pc_start - s->cs_base); @@ -2409,7 +2992,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) s->tf = 0; } if (s->is_jmp) { - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; @@ -2419,7 +3002,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); gen_pop_update(s); if (s->is_jmp) { - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; @@ -2431,38 +3014,40 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; /* generate a generic store */ - gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1); + gen_ldst_modrm(s, modrm, ot, reg, 1); break; case 0xc6: case 0xc7: /* mov Ev, Iv */ if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; - if (mod != 3) + if (mod != 3) { + s->rip_offset = insn_const_size(ot); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + } val = insn_get(s, ot); gen_op_movl_T0_im(val); if (mod != 3) gen_op_st_T0_A0[ot + s->mem_index](); else - gen_op_mov_reg_T0[ot][modrm & 7](); + gen_op_mov_reg_T0[ot][(modrm & 7) | REX_B(s)](); break; case 0x8a: case 0x8b: /* mov Ev, Gv */ if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = OT_WORD + dflag; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_reg_T0[ot][reg](); @@ -2483,7 +3068,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) s->tf = 0; } if (s->is_jmp) { - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; @@ -2494,9 +3079,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (reg >= 6) goto illegal_op; gen_op_movl_T0_seg(reg); - ot = OT_WORD; - if (mod == 3 && dflag) - ot = OT_LONG; + if (mod == 3) + ot = OT_WORD + dflag; + else + ot = OT_WORD; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); break; @@ -2511,9 +3097,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /* ot is the size of source */ ot = (b & 1) + OT_BYTE; modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) + OR_EAX; + reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); if (mod == 3) { gen_op_mov_TN_reg[ot][0][rm](); @@ -2546,12 +3132,12 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x8d: /* lea */ - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; /* we must ensure that no segment is added */ s->override = -1; val = s->addseg; @@ -2565,42 +3151,67 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0xa1: case 0xa2: /* mov Ov, EAX */ case 0xa3: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (s->aflag) - offset_addr = insn_get(s, OT_LONG); - else - offset_addr = insn_get(s, OT_WORD); - gen_op_movl_A0_im(offset_addr); - /* handle override */ { - int override, must_add_seg; - must_add_seg = s->addseg; - if (s->override >= 0) { - override = s->override; - must_add_seg = 1; - } else { - override = R_DS; + target_ulong offset_addr; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag + OT_WORD; +#ifdef TARGET_X86_64 + if (CODE64(s)) { + offset_addr = ldq_code(s->pc); + s->pc += 8; + if (offset_addr == (int32_t)offset_addr) + gen_op_movq_A0_im(offset_addr); + else + gen_op_movq_A0_im64(offset_addr >> 32, offset_addr); + } else +#endif + { + if (s->aflag) { + offset_addr = insn_get(s, OT_LONG); + } else { + offset_addr = insn_get(s, OT_WORD); + } + gen_op_movl_A0_im(offset_addr); + } + /* handle override */ + { + int override, must_add_seg; + must_add_seg = s->addseg; + if (s->override >= 0) { + override = s->override; + must_add_seg = 1; + } else { + override = R_DS; + } + if (must_add_seg) { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } } - if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + if ((b & 2) == 0) { + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_mov_reg_T0[ot][R_EAX](); + } else { + gen_op_mov_TN_reg[ot][0][R_EAX](); + gen_op_st_T0_A0[ot + s->mem_index](); } } - if ((b & 2) == 0) { - gen_op_ld_T0_A0[ot + s->mem_index](); - gen_op_mov_reg_T0[ot][R_EAX](); - } else { - gen_op_mov_TN_reg[ot][0][R_EAX](); - gen_op_st_T0_A0[ot + s->mem_index](); - } break; case 0xd7: /* xlat */ - gen_op_movl_A0_reg[R_EBX](); - gen_op_addl_A0_AL(); - if (s->aflag == 0) - gen_op_andl_A0_ffff(); +#ifdef TARGET_X86_64 + if (CODE64(s)) { + gen_op_movq_A0_reg[R_EBX](); + gen_op_addq_A0_AL(); + } else +#endif + { + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_AL(); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + } /* handle override */ { int override, must_add_seg; @@ -2622,19 +3233,32 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0xb0 ... 0xb7: /* mov R, Ib */ val = insn_get(s, OT_BYTE); gen_op_movl_T0_im(val); - gen_op_mov_reg_T0[OT_BYTE][b & 7](); + gen_op_mov_reg_T0[OT_BYTE][(b & 7) | REX_B(s)](); break; case 0xb8 ... 0xbf: /* mov R, Iv */ - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); - reg = OR_EAX + (b & 7); - gen_op_movl_T0_im(val); - gen_op_mov_reg_T0[ot][reg](); +#ifdef TARGET_X86_64 + if (dflag == 2) { + uint64_t tmp; + /* 64 bit case */ + tmp = ldq_code(s->pc); + s->pc += 8; + reg = (b & 7) | REX_B(s); + gen_movtl_T0_im(tmp); + gen_op_mov_reg_T0[OT_QUAD][reg](); + } else +#endif + { + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + reg = (b & 7) | REX_B(s); + gen_op_movl_T0_im(val); + gen_op_mov_reg_T0[ot][reg](); + } break; case 0x91 ... 0x97: /* xchg R, EAX */ - ot = dflag ? OT_LONG : OT_WORD; - reg = b & 7; + ot = dflag + OT_WORD; + reg = (b & 7) | REX_B(s); rm = R_EAX; goto do_xchg_reg; case 0x86: @@ -2642,12 +3266,12 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; if (mod == 3) { - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); do_xchg_reg: gen_op_mov_TN_reg[ot][0][reg](); gen_op_mov_TN_reg[ot][1][rm](); @@ -2667,9 +3291,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0xc4: /* les Gv */ + if (CODE64(s)) + goto illegal_op; op = R_ES; goto do_lxx; case 0xc5: /* lds Gv */ + if (CODE64(s)) + goto illegal_op; op = R_DS; goto do_lxx; case 0x1b2: /* lss Gv */ @@ -2683,7 +3311,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) do_lxx: ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; @@ -2696,7 +3324,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /* then put the data */ gen_op_mov_reg_T1[ot][reg](); if (s->is_jmp) { - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; @@ -2712,18 +3340,20 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; - rm = modrm & 7; op = (modrm >> 3) & 7; if (mod != 3) { + if (shift == 2) { + s->rip_offset = 1; + } gen_lea_modrm(s, modrm, ®_addr, &offset_addr); opreg = OR_TMP0; } else { - opreg = rm + OR_EAX; + opreg = (modrm & 7) | REX_B(s); } /* simpler op */ @@ -2764,11 +3394,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) op = 1; shift = 0; do_shiftd: - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; - rm = modrm & 7; - reg = (modrm >> 3) & 7; + rm = (modrm & 7) | REX_B(s); + reg = ((modrm >> 3) & 7) | rex_r; if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); @@ -2780,7 +3410,10 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (shift) { val = ldub_code(s->pc++); - val &= 0x1f; + if (ot == OT_QUAD) + val &= 0x3f; + else + val &= 0x1f; if (val) { if (mod == 3) gen_op_shiftd_T0_T1_im_cc[ot][op](val); @@ -2970,7 +3603,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /* check exceptions (FreeBSD FPU probe) */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_fwait(); break; default: @@ -3257,7 +3890,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); @@ -3271,7 +3904,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); @@ -3284,7 +3917,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { @@ -3296,7 +3929,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; if (prefixes & PREFIX_REPNZ) { gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); } else if (prefixes & PREFIX_REPZ) { @@ -3312,7 +3945,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if ((b & 1) == 0) ot = OT_BYTE; else - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; if (prefixes & PREFIX_REPNZ) { gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); } else if (prefixes & PREFIX_REPZ) { @@ -3427,7 +4060,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_lret_protected(s->dflag, val); } else { gen_stack_A0(s); @@ -3465,7 +4098,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_iret_protected(s->dflag, s->pc - s->cs_base); s->cc_op = CC_OP_EFLAGS; } @@ -3473,72 +4106,79 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xe8: /* call im */ { - unsigned int next_eip; - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); + if (dflag) + tval = (int32_t)insn_get(s, OT_LONG); + else + tval = (int16_t)insn_get(s, OT_WORD); next_eip = s->pc - s->cs_base; - val += next_eip; + tval += next_eip; if (s->dflag == 0) - val &= 0xffff; - gen_op_movl_T0_im(next_eip); + tval &= 0xffff; + gen_movtl_T0_im(next_eip); gen_push_T0(s); - gen_jmp(s, val); + gen_jmp(s, tval); } break; case 0x9a: /* lcall im */ { unsigned int selector, offset; - + + if (CODE64(s)) + goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); gen_op_movl_T0_im(selector); - gen_op_movl_T1_im(offset); + gen_op_movl_T1_imu(offset); } goto do_lcall; case 0xe9: /* jmp */ - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); - val += s->pc - s->cs_base; + if (dflag) + tval = (int32_t)insn_get(s, OT_LONG); + else + tval = (int16_t)insn_get(s, OT_WORD); + tval += s->pc - s->cs_base; if (s->dflag == 0) - val = val & 0xffff; - gen_jmp(s, val); + tval &= 0xffff; + gen_jmp(s, tval); break; case 0xea: /* ljmp im */ { unsigned int selector, offset; + if (CODE64(s)) + goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); gen_op_movl_T0_im(selector); - gen_op_movl_T1_im(offset); + gen_op_movl_T1_imu(offset); } goto do_ljmp; case 0xeb: /* jmp Jb */ - val = (int8_t)insn_get(s, OT_BYTE); - val += s->pc - s->cs_base; + tval = (int8_t)insn_get(s, OT_BYTE); + tval += s->pc - s->cs_base; if (s->dflag == 0) - val = val & 0xffff; - gen_jmp(s, val); + tval &= 0xffff; + gen_jmp(s, tval); break; case 0x70 ... 0x7f: /* jcc Jb */ - val = (int8_t)insn_get(s, OT_BYTE); + tval = (int8_t)insn_get(s, OT_BYTE); goto do_jcc; case 0x180 ... 0x18f: /* jcc Jv */ if (dflag) { - val = insn_get(s, OT_LONG); + tval = (int32_t)insn_get(s, OT_LONG); } else { - val = (int16_t)insn_get(s, OT_WORD); + tval = (int16_t)insn_get(s, OT_WORD); } do_jcc: next_eip = s->pc - s->cs_base; - val += next_eip; + tval += next_eip; if (s->dflag == 0) - val &= 0xffff; - gen_jcc(s, b, val, next_eip); + tval &= 0xffff; + gen_jcc(s, b, tval, next_eip); break; case 0x190 ... 0x19f: /* setcc Gv */ @@ -3547,16 +4187,16 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); break; case 0x140 ... 0x14f: /* cmov Gv, Ev */ - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; gen_setcc(s, b); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[ot + s->mem_index](); } else { - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); gen_op_mov_TN_reg[ot][1][rm](); } gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); @@ -3603,11 +4243,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_pop_update(s); s->cc_op = CC_OP_EFLAGS; /* abort translation because TF flag may change */ - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; case 0x9e: /* sahf */ + if (CODE64(s)) + goto illegal_op; gen_op_mov_TN_reg[OT_BYTE][0][R_AH](); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); @@ -3615,6 +4257,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) s->cc_op = CC_OP_EFLAGS; break; case 0x9f: /* lahf */ + if (CODE64(s)) + goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_movl_T0_eflags(); @@ -3648,12 +4292,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* bit operations */ case 0x1ba: /* bt/bts/btr/btc Gv, im */ - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - op = (modrm >> 3) & 7; + op = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); if (mod != 3) { + s->rip_offset = 1; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T0_A0[ot + s->mem_index](); } else { @@ -3687,19 +4332,16 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x1bb: /* btc */ op = 3; do_btx: - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; - rm = modrm & 7; + rm = (modrm & 7) | REX_B(s); gen_op_mov_TN_reg[OT_LONG][1][reg](); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); /* specific case: we need to add a displacement */ - if (ot == OT_WORD) - gen_op_add_bitw_A0_T1(); - else - gen_op_add_bitl_A0_T1(); + gen_op_add_bit_A0_T1[ot - OT_WORD](); gen_op_ld_T0_A0[ot + s->mem_index](); } else { gen_op_mov_TN_reg[ot][0][rm](); @@ -3716,9 +4358,9 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x1bc: /* bsf */ case 0x1bd: /* bsr */ - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); /* NOTE: in order to handle the 0 case, we must load the result. It could be optimized with a generated jump */ @@ -3730,35 +4372,47 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* bcd */ case 0x27: /* daa */ + if (CODE64(s)) + goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_daa(); s->cc_op = CC_OP_EFLAGS; break; case 0x2f: /* das */ + if (CODE64(s)) + goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_das(); s->cc_op = CC_OP_EFLAGS; break; case 0x37: /* aaa */ + if (CODE64(s)) + goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_aaa(); s->cc_op = CC_OP_EFLAGS; break; case 0x3f: /* aas */ + if (CODE64(s)) + goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_aas(); s->cc_op = CC_OP_EFLAGS; break; case 0xd4: /* aam */ + if (CODE64(s)) + goto illegal_op; val = ldub_code(s->pc++); gen_op_aam(val); s->cc_op = CC_OP_LOGICB; break; case 0xd5: /* aad */ + if (CODE64(s)) + goto illegal_op; val = ldub_code(s->pc++); gen_op_aad(val); s->cc_op = CC_OP_LOGICB; @@ -3766,6 +4420,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /************************/ /* misc */ case 0x90: /* nop */ + /* XXX: xchg + rex handling */ /* XXX: correct lock test for all insn */ if (prefixes & PREFIX_LOCK) goto illegal_op; @@ -3777,7 +4432,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_fwait(); } break; @@ -3793,12 +4448,19 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0xce: /* into */ + if (CODE64(s)) + goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_into(s->pc - s->cs_base); break; case 0xf1: /* icebp (undocumented, exits to external debugger) */ +#if 0 gen_debug(s, pc_start - s->cs_base); +#else + /* test ! */ + cpu_set_log(CPU_LOG_TB_IN_ASM | CPU_LOG_PCALL); +#endif break; case 0xfa: /* cli */ if (!s->vm86) { @@ -3826,7 +4488,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK)) gen_op_set_inhibit_irq(); /* give a chance to handle pending irqs */ - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); @@ -3840,6 +4502,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } break; case 0x62: /* bound */ + if (CODE64(s)) + goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); reg = (modrm >> 3) & 7; @@ -3848,18 +4512,30 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; gen_op_mov_TN_reg[ot][0][reg](); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_jmp_im(pc_start - s->cs_base); if (ot == OT_WORD) - gen_op_boundw(pc_start - s->cs_base); + gen_op_boundw(); else - gen_op_boundl(pc_start - s->cs_base); + gen_op_boundl(); break; case 0x1c8 ... 0x1cf: /* bswap reg */ - reg = b & 7; - gen_op_mov_TN_reg[OT_LONG][0][reg](); - gen_op_bswapl_T0(); - gen_op_mov_reg_T0[OT_LONG][reg](); + reg = (b & 7) | REX_B(s); +#ifdef TARGET_X86_64 + if (dflag == 2) { + gen_op_mov_TN_reg[OT_QUAD][0][reg](); + gen_op_bswapq_T0(); + gen_op_mov_reg_T0[OT_QUAD][reg](); + } else +#endif + { + gen_op_mov_TN_reg[OT_LONG][0][reg](); + gen_op_bswapl_T0(); + gen_op_mov_reg_T0[OT_LONG][reg](); + } break; case 0xd6: /* salc */ + if (CODE64(s)) + goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_salc(); @@ -3871,13 +4547,32 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /* FALL THRU */ case 0xe2: /* loop */ case 0xe3: /* jecxz */ - val = (int8_t)insn_get(s, OT_BYTE); - next_eip = s->pc - s->cs_base; - val += next_eip; - if (s->dflag == 0) - val &= 0xffff; - gen_op_loop[s->aflag][b & 3](val, next_eip); - gen_eob(s); + { + int l1, l2; + + tval = (int8_t)insn_get(s, OT_BYTE); + next_eip = s->pc - s->cs_base; + tval += next_eip; + if (s->dflag == 0) + tval &= 0xffff; + + l1 = gen_new_label(); + l2 = gen_new_label(); + b &= 3; + if (b == 3) { + gen_op_jz_ecx[s->aflag](l1); + } else { + gen_op_dec_ECX[s->aflag](); + gen_op_loop[s->aflag][b](l1); + } + + gen_jmp_im(next_eip); + gen_op_jmp_label(l2); + gen_set_label(l1); + gen_jmp_im(tval); + gen_set_label(l2); + gen_eob(s); + } break; case 0x130: /* wrmsr */ case 0x132: /* rdmsr */ @@ -3894,6 +4589,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_rdtsc(); break; case 0x134: /* sysenter */ + if (CODE64(s)) + goto illegal_op; if (!s->pe) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -3901,12 +4598,14 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_sysenter(); gen_eob(s); } break; case 0x135: /* sysexit */ + if (CODE64(s)) + goto illegal_op; if (!s->pe) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -3914,11 +4613,36 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_sysexit(); gen_eob(s); } break; +#ifdef TARGET_X86_64 + case 0x105: /* syscall */ + /* XXX: is it usable in real mode ? */ + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(pc_start - s->cs_base); + gen_op_syscall(); + gen_eob(s); + break; + case 0x107: /* sysret */ + if (!s->pe) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(pc_start - s->cs_base); + gen_op_sysret(s->dflag); + gen_eob(s); + } + break; +#endif case 0x1a2: /* cpuid */ gen_op_cpuid(); break; @@ -3928,7 +4652,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_op_hlt(); s->is_jmp = 3; } @@ -3954,7 +4678,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_lldt_T0(); } break; @@ -3974,7 +4698,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); - gen_op_jmp_im(pc_start - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); gen_op_ltr_T0(); } break; @@ -4010,14 +4734,19 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) else gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); gen_op_st_T0_A0[OT_WORD + s->mem_index](); - gen_op_addl_A0_im(2); +#ifdef TARGET_X86_64 + if (CODE64(s)) + gen_op_addq_A0_im(2); + else +#endif + gen_op_addl_A0_im(2); if (op == 0) - gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); + gen_op_movtl_T0_env(offsetof(CPUX86State,gdt.base)); else - gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); + gen_op_movtl_T0_env(offsetof(CPUX86State,idt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); - gen_op_st_T0_A0[OT_LONG + s->mem_index](); + gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); break; case 2: /* lgdt */ case 3: /* lidt */ @@ -4028,15 +4757,20 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[OT_WORD + s->mem_index](); - gen_op_addl_A0_im(2); - gen_op_ld_T0_A0[OT_LONG + s->mem_index](); +#ifdef TARGET_X86_64 + if (CODE64(s)) + gen_op_addq_A0_im(2); + else +#endif + gen_op_addl_A0_im(2); + gen_op_ld_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); if (!s->dflag) gen_op_andl_T0_im(0xffffff); if (op == 2) { - gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base)); + gen_op_movtl_env_T0(offsetof(CPUX86State,gdt.base)); gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit)); } else { - gen_op_movl_env_T0(offsetof(CPUX86State,idt.base)); + gen_op_movtl_env_T0(offsetof(CPUX86State,idt.base)); gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit)); } } @@ -4051,7 +4785,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_op_lmsw_T0(); - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; @@ -4059,12 +4793,25 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (mod == 3) - goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_invlpg_A0(); - gen_op_jmp_im(s->pc - s->cs_base); - gen_eob(s); + if (mod == 3) { +#ifdef TARGET_X86_64 + if (CODE64(s) && (modrm & 7) == 0) { + /* swapgs */ + gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base)); + gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase)); + gen_op_movtl_env_T1(offsetof(CPUX86State,segs[R_GS].base)); + gen_op_movtl_env_T0(offsetof(CPUX86State,kernelgsbase)); + } else +#endif + { + goto illegal_op; + } + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_invlpg_A0(); + gen_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } } break; default: @@ -4079,30 +4826,87 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) /* nothing to do */ } break; - case 0x63: /* arpl */ - if (!s->pe || s->vm86) - goto illegal_op; - ot = dflag ? OT_LONG : OT_WORD; + case 0x1ae: /* sfence */ modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; - rm = modrm & 7; - if (mod != 3) { + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* fxsave */ + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) + goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_ld_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_TN_reg[ot][0][rm](); + gen_op_fxsave_A0((s->dflag == 2)); + break; + case 1: /* fxrstor */ + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_fxrstor_A0((s->dflag == 2)); + break; + case 5: /* lfence */ + case 6: /* mfence */ + case 7: /* sfence */ + if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE)) + goto illegal_op; + break; + default: + goto illegal_op; } - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_arpl(); - s->cc_op = CC_OP_EFLAGS; - if (mod != 3) { - gen_op_st_T0_A0[ot + s->mem_index](); - } else { - gen_op_mov_reg_T0[ot][rm](); + break; + case 0x63: /* arpl or movslS (x86_64) */ +#ifdef TARGET_X86_64 + if (CODE64(s)) { + int d_ot; + /* d_ot is the size of destination */ + d_ot = dflag + OT_WORD; + + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + mod = (modrm >> 6) & 3; + rm = (modrm & 7) | REX_B(s); + + if (mod == 3) { + gen_op_mov_TN_reg[OT_LONG][0][rm](); + /* sign extend */ + if (d_ot == OT_QUAD) + gen_op_movslq_T0_T0(); + gen_op_mov_reg_T0[d_ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (d_ot == OT_QUAD) { + gen_op_lds_T0_A0[OT_LONG + s->mem_index](); + } else { + gen_op_ld_T0_A0[OT_LONG + s->mem_index](); + } + gen_op_mov_reg_T0[d_ot][reg](); + } + } else +#endif + { + if (!s->pe || s->vm86) + goto illegal_op; + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub_code(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_arpl(); + s->cc_op = CC_OP_EFLAGS; + if (mod != 3) { + gen_op_st_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + gen_op_arpl_update(); } - gen_op_arpl_update(); break; case 0x102: /* lar */ case 0x103: /* lsl */ @@ -4110,7 +4914,7 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; modrm = ldub_code(s->pc++); - reg = (modrm >> 3) & 7; + reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_TN_reg[ot][1][reg](); if (s->cc_op != CC_OP_DYNAMIC) @@ -4148,23 +4952,28 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) modrm = ldub_code(s->pc++); if ((modrm & 0xc0) != 0xc0) goto illegal_op; - rm = modrm & 7; - reg = (modrm >> 3) & 7; + rm = (modrm & 7) | REX_B(s); + reg = ((modrm >> 3) & 7) | rex_r; + if (CODE64(s)) + ot = OT_QUAD; + else + ot = OT_LONG; switch(reg) { case 0: case 2: case 3: case 4: if (b & 2) { - gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_mov_TN_reg[ot][0][rm](); gen_op_movl_crN_T0(reg); - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { - gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); - gen_op_mov_reg_T0[OT_LONG][rm](); + gen_op_movtl_T0_env(offsetof(CPUX86State,cr[reg])); + gen_op_mov_reg_T0[ot][rm](); } break; + /* XXX: add CR8 for x86_64 */ default: goto illegal_op; } @@ -4178,19 +4987,23 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) modrm = ldub_code(s->pc++); if ((modrm & 0xc0) != 0xc0) goto illegal_op; - rm = modrm & 7; - reg = (modrm >> 3) & 7; + rm = (modrm & 7) | REX_B(s); + reg = ((modrm >> 3) & 7) | rex_r; + if (CODE64(s)) + ot = OT_QUAD; + else + ot = OT_LONG; /* XXX: do it dynamically with CR4.DE bit */ - if (reg == 4 || reg == 5) + if (reg == 4 || reg == 5 || reg >= 8) goto illegal_op; if (b & 2) { - gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_mov_TN_reg[ot][0][rm](); gen_op_movl_drN_T0(reg); - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { - gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); - gen_op_mov_reg_T0[OT_LONG][rm](); + gen_op_movtl_T0_env(offsetof(CPUX86State,dr[reg])); + gen_op_mov_reg_T0[ot][rm](); } } break; @@ -4200,10 +5013,69 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) } else { gen_op_clts(); /* abort block because static cpu state changed */ - gen_op_jmp_im(s->pc - s->cs_base); + gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } break; + /* SSE support */ + case 0x16f: + if (prefixes & PREFIX_DATA) { + /* movdqa xmm1, xmm2/mem128 */ + if (!(s->cpuid_features & CPUID_SSE)) + goto illegal_op; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + mod = (modrm >> 6) & 3; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movo(offsetof(CPUX86State,xmm_regs[reg]), + offsetof(CPUX86State,xmm_regs[rm])); + } + } else { + goto illegal_op; + } + break; + case 0x1e7: + if (prefixes & PREFIX_DATA) { + /* movntdq mem128, xmm1 */ + if (!(s->cpuid_features & CPUID_SSE)) + goto illegal_op; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + mod = (modrm >> 6) & 3; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + } else { + goto illegal_op; + } + } else { + goto illegal_op; + } + break; + case 0x17f: + if (prefixes & PREFIX_DATA) { + /* movdqa xmm2/mem128, xmm1 */ + if (!(s->cpuid_features & CPUID_SSE)) + goto illegal_op; + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + mod = (modrm >> 6) & 3; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movo(offsetof(CPUX86State,xmm_regs[rm]), + offsetof(CPUX86State,xmm_regs[reg])); + } + } else { + goto illegal_op; + } + break; default: goto illegal_op; } @@ -4301,26 +5173,51 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_salc] = CC_C, /* needed for correct flag optimisation before string ops */ + [INDEX_op_jnz_ecxw] = CC_OSZAPC, + [INDEX_op_jnz_ecxl] = CC_OSZAPC, [INDEX_op_jz_ecxw] = CC_OSZAPC, [INDEX_op_jz_ecxl] = CC_OSZAPC, - [INDEX_op_jz_ecxw_im] = CC_OSZAPC, - [INDEX_op_jz_ecxl_im] = CC_OSZAPC, + +#ifdef TARGET_X86_64 + [INDEX_op_jb_subq] = CC_C, + [INDEX_op_jz_subq] = CC_Z, + [INDEX_op_jbe_subq] = CC_Z | CC_C, + [INDEX_op_js_subq] = CC_S, + [INDEX_op_jl_subq] = CC_O | CC_S, + [INDEX_op_jle_subq] = CC_O | CC_S | CC_Z, + + [INDEX_op_loopnzq] = CC_Z, + [INDEX_op_loopzq] = CC_Z, + + [INDEX_op_setb_T0_subq] = CC_C, + [INDEX_op_setz_T0_subq] = CC_Z, + [INDEX_op_setbe_T0_subq] = CC_Z | CC_C, + [INDEX_op_sets_T0_subq] = CC_S, + [INDEX_op_setl_T0_subq] = CC_O | CC_S, + [INDEX_op_setle_T0_subq] = CC_O | CC_S | CC_Z, + + [INDEX_op_jnz_ecxq] = CC_OSZAPC, + [INDEX_op_jz_ecxq] = CC_OSZAPC, +#endif #define DEF_READF(SUFFIX)\ [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_C,\ [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_C,\ [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_C,\ + X86_64_DEF([INDEX_op_adcq ## SUFFIX ## _T0_T1_cc] = CC_C,)\ [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_C,\ [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_C,\ [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_C,\ + X86_64_DEF([INDEX_op_sbbq ## SUFFIX ## _T0_T1_cc] = CC_C,)\ \ [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_C,\ [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_C,\ [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_C,\ + X86_64_DEF([INDEX_op_rclq ## SUFFIX ## _T0_T1_cc] = CC_C,)\ [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_C,\ [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_C,\ - [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C, - + [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C,\ + X86_64_DEF([INDEX_op_rcrq ## SUFFIX ## _T0_T1_cc] = CC_C,) DEF_READF( ) DEF_READF(_raw) @@ -4341,14 +5238,17 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_mulb_AL_T0] = CC_OSZAPC, - [INDEX_op_imulb_AL_T0] = CC_OSZAPC, [INDEX_op_mulw_AX_T0] = CC_OSZAPC, - [INDEX_op_imulw_AX_T0] = CC_OSZAPC, [INDEX_op_mull_EAX_T0] = CC_OSZAPC, + X86_64_DEF([INDEX_op_mulq_EAX_T0] = CC_OSZAPC,) + [INDEX_op_imulb_AL_T0] = CC_OSZAPC, + [INDEX_op_imulw_AX_T0] = CC_OSZAPC, [INDEX_op_imull_EAX_T0] = CC_OSZAPC, + X86_64_DEF([INDEX_op_imulq_EAX_T0] = CC_OSZAPC,) [INDEX_op_imulw_T0_T1] = CC_OSZAPC, [INDEX_op_imull_T0_T1] = CC_OSZAPC, - + X86_64_DEF([INDEX_op_imulq_T0_T1] = CC_OSZAPC,) + /* bcd */ [INDEX_op_aam] = CC_OSZAPC, [INDEX_op_aad] = CC_OSZAPC, @@ -4370,21 +5270,28 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, + X86_64_DEF([INDEX_op_btq_T0_T1_cc] = CC_OSZAPC,) [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC, + X86_64_DEF([INDEX_op_btsq_T0_T1_cc] = CC_OSZAPC,) [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC, + X86_64_DEF([INDEX_op_btrq_T0_T1_cc] = CC_OSZAPC,) [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC, [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC, + X86_64_DEF([INDEX_op_btcq_T0_T1_cc] = CC_OSZAPC,) [INDEX_op_bsfw_T0_cc] = CC_OSZAPC, [INDEX_op_bsfl_T0_cc] = CC_OSZAPC, + X86_64_DEF([INDEX_op_bsfq_T0_cc] = CC_OSZAPC,) [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, + X86_64_DEF([INDEX_op_bsrq_T0_cc] = CC_OSZAPC,) [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, + X86_64_DEF([INDEX_op_cmpxchgq_T0_T1_EAX_cc] = CC_OSZAPC,) [INDEX_op_cmpxchg8b] = CC_Z, [INDEX_op_lar] = CC_Z, @@ -4396,49 +5303,63 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_adcq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_sbbq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ \ [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + X86_64_DEF([INDEX_op_rolq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\ [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + X86_64_DEF([INDEX_op_rorq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\ \ [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + X86_64_DEF([INDEX_op_rclq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\ [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\ + X86_64_DEF([INDEX_op_rcrq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\ \ [INDEX_op_shlb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_shlw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_shll ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_shlq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ \ [INDEX_op_shrb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_shrw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_shrl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_shrq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ \ [INDEX_op_sarb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_sarw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ [INDEX_op_sarl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_sarq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\ \ [INDEX_op_shldw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ [INDEX_op_shldl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_shldq ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,)\ [INDEX_op_shldw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ [INDEX_op_shldl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_shldq ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,)\ \ [INDEX_op_shrdw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ [INDEX_op_shrdl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_shrdq ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,)\ [INDEX_op_shrdw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ [INDEX_op_shrdl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_shrdq ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,)\ \ [INDEX_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\ [INDEX_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\ - [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\ + X86_64_DEF([INDEX_op_cmpxchgq ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,) DEF_WRITEF( ) @@ -4462,23 +5383,28 @@ static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1, + X86_64_DEF([INDEX_op_shlq_T0_T1_cc] = INDEX_op_shlq_T0_T1,) [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1, [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1, [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1, + X86_64_DEF([INDEX_op_shrq_T0_T1_cc] = INDEX_op_shrq_T0_T1,) [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1, [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1, [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, + X86_64_DEF([INDEX_op_sarq_T0_T1_cc] = INDEX_op_sarq_T0_T1,) #define DEF_SIMPLER(SUFFIX)\ [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolb ## SUFFIX ## _T0_T1,\ [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolw ## SUFFIX ## _T0_T1,\ [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = INDEX_op_roll ## SUFFIX ## _T0_T1,\ + X86_64_DEF([INDEX_op_rolq ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolq ## SUFFIX ## _T0_T1,)\ \ [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorb ## SUFFIX ## _T0_T1,\ [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorw ## SUFFIX ## _T0_T1,\ - [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorl ## SUFFIX ## _T0_T1, + [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorl ## SUFFIX ## _T0_T1,\ + X86_64_DEF([INDEX_op_rorq ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorq ## SUFFIX ## _T0_T1,) DEF_SIMPLER( ) DEF_SIMPLER(_raw) @@ -4533,15 +5459,15 @@ static inline int gen_intermediate_code_internal(CPUState *env, int search_pc) { DisasContext dc1, *dc = &dc1; - uint8_t *pc_ptr; + target_ulong pc_ptr; uint16_t *gen_opc_end; int flags, j, lj, cflags; - uint8_t *pc_start; - uint8_t *cs_base; + target_ulong pc_start; + target_ulong cs_base; /* generate intermediate code */ - pc_start = (uint8_t *)tb->pc; - cs_base = (uint8_t *)tb->cs_base; + pc_start = tb->pc; + cs_base = tb->cs_base; flags = tb->flags; cflags = tb->cflags; @@ -4563,10 +5489,15 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->mem_index = 0; if (flags & HF_SOFTMMU_MASK) { if (dc->cpl == 3) - dc->mem_index = 6; + dc->mem_index = 2 * 4; else - dc->mem_index = 3; + dc->mem_index = 1 * 4; } + dc->cpuid_features = env->cpuid_features; +#ifdef TARGET_X86_64 + dc->lma = (flags >> HF_LMA_SHIFT) & 1; + dc->code64 = (flags >> HF_CS64_SHIFT) & 1; +#endif dc->flags = flags; dc->jmp_opt = !(dc->tf || env->singlestep_enabled || (flags & HF_INHIBIT_IRQ_MASK) @@ -4583,6 +5514,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; + nb_gen_labels = 0; dc->is_jmp = DISAS_NEXT; pc_ptr = pc_start; @@ -4591,7 +5523,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, for(;;) { if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == (unsigned long)pc_ptr) { + if (env->breakpoints[j] == pc_ptr) { gen_debug(dc, pc_ptr - dc->cs_base); break; } @@ -4604,7 +5536,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, while (lj < j) gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = (uint32_t)pc_ptr; + gen_opc_pc[lj] = pc_ptr; gen_opc_cc_op[lj] = dc->cc_op; gen_opc_instr_start[lj] = 1; } @@ -4620,14 +5552,14 @@ static inline int gen_intermediate_code_internal(CPUState *env, if (dc->tf || dc->singlestep_enabled || (flags & HF_INHIBIT_IRQ_MASK) || (cflags & CF_SINGLE_INSN)) { - gen_op_jmp_im(pc_ptr - dc->cs_base); + gen_jmp_im(pc_ptr - dc->cs_base); gen_eob(dc); break; } /* if too long translation, stop generation too */ if (gen_opc_ptr >= gen_opc_end || (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { - gen_op_jmp_im(pc_ptr - dc->cs_base); + gen_jmp_im(pc_ptr - dc->cs_base); gen_eob(dc); break; } @@ -4646,9 +5578,16 @@ static inline int gen_intermediate_code_internal(CPUState *env, cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); } if (loglevel & CPU_LOG_TB_IN_ASM) { + int disas_flags; fprintf(logfile, "----------------\n"); fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32); +#ifdef TARGET_X86_64 + if (dc->code64) + disas_flags = 2; + else +#endif + disas_flags = !dc->code32; + target_disas(logfile, pc_start, pc_ptr - pc_start, disas_flags); fprintf(logfile, "\n"); if (loglevel & CPU_LOG_TB_OP) { fprintf(logfile, "OP:\n"); -- cgit v1.2.3 From bdfaf503dc395cf77d6b67df5229c5c7a3cb7631 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 3 Jan 2005 23:51:01 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1198 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index 7e16de638..d041fc36a 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,9 @@ version 0.6.2: - .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 + - initial x86_64 target support + - initial APIC support version 0.6.1: -- cgit v1.2.3 From 06c2f5066e298d456e4a6ca24def8a84cc9ed31a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jan 2005 01:06:58 +0000 Subject: syscall insn fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1199 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 2 +- target-i386/helper.c | 8 ++++---- target-i386/op.c | 2 +- target-i386/translate.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 00eee80f9..5529c3552 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -199,7 +199,7 @@ void helper_cpuid(void); void helper_enter_level(int level, int data32); void helper_sysenter(void); void helper_sysexit(void); -void helper_syscall(void); +void helper_syscall(int next_eip_addend); void helper_sysret(int dflag); void helper_rdtsc(void); void helper_rdmsr(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 3ae5b9113..64d6f9e7a 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -934,7 +934,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); } -void helper_syscall(void) +void helper_syscall(int next_eip_addend) { int selector; @@ -943,7 +943,7 @@ void helper_syscall(void) } selector = (env->star >> 32) & 0xffff; if (env->hflags & HF_LMA_MASK) { - ECX = env->eip; + ECX = env->eip + next_eip_addend; env->regs[11] = compute_eflags(); cpu_x86_set_cpl(env, 0); @@ -963,7 +963,7 @@ void helper_syscall(void) else env->eip = env->cstar; } else { - ECX = (uint32_t)env->eip; + ECX = (uint32_t)(env->eip + next_eip_addend); cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, @@ -1119,8 +1119,8 @@ void do_interrupt(int intno, int is_int, int error_code, fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX); } fprintf(logfile, "\n"); - cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); #if 0 + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); { int i; uint8_t *ptr; diff --git a/target-i386/op.c b/target-i386/op.c index 1daa551c2..f81d59b16 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -938,7 +938,7 @@ void OPPROTO op_sysexit(void) #ifdef TARGET_X86_64 void OPPROTO op_syscall(void) { - helper_syscall(); + helper_syscall(PARAM1); } void OPPROTO op_sysret(void) diff --git a/target-i386/translate.c b/target-i386/translate.c index a00ce0426..743aff765 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4626,7 +4626,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); - gen_op_syscall(); + gen_op_syscall(s->pc - pc_start); gen_eob(s); break; case 0x107: /* sysret */ -- cgit v1.2.3 From 02536f8b1f94a701ac3ef8016741fe01cc68cff2 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 6 Jan 2005 20:43:38 +0000 Subject: x86_64 save/restore git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1200 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/vl.c b/vl.c index c6733ff16..7a4762489 100644 --- a/vl.c +++ b/vl.c @@ -2138,6 +2138,20 @@ void cpu_save(QEMUFile *f, void *opaque) /* MMU */ qemu_put_be32s(f, &env->a20_mask); + +#ifdef TARGET_X86_64 + for(i = 0; i < CPU_NB_REGS; i++) { + qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0)); + qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1)); + } + + qemu_put_be64s(f, &env->efer); + qemu_put_be64s(f, &env->star); + qemu_put_be64s(f, &env->lstar); + qemu_put_be64s(f, &env->cstar); + qemu_put_be64s(f, &env->fmask); + qemu_put_be64s(f, &env->kernelgsbase); +#endif } int cpu_load(QEMUFile *f, void *opaque, int version_id) @@ -2198,6 +2212,20 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) /* MMU */ qemu_get_be32s(f, &env->a20_mask); +#ifdef TARGET_X86_64 + for(i = 0; i < CPU_NB_REGS; i++) { + qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0)); + qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1)); + } + + qemu_get_be64s(f, &env->efer); + qemu_get_be64s(f, &env->star); + qemu_get_be64s(f, &env->lstar); + qemu_get_be64s(f, &env->cstar); + qemu_get_be64s(f, &env->fmask); + qemu_get_be64s(f, &env->kernelgsbase); +#endif + /* XXX: compute hflags from scratch, except for CPL and IIF */ env->hflags = hflags; tlb_flush(env, 1); -- cgit v1.2.3 From 826461bb4068bab1c8fef6eb11117a260aa3e2c0 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 6 Jan 2005 20:44:11 +0000 Subject: big endian SSE fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1201 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 883236386..e65fc2e2c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -339,15 +339,40 @@ typedef struct SegmentCache { uint32_t flags; } SegmentCache; -typedef struct { - union { - uint8_t b[16]; - uint16_t w[8]; - uint32_t l[4]; - uint64_t q[2]; - } u; +typedef union { + uint8_t _b[16]; + uint16_t _w[8]; + uint32_t _l[4]; + uint64_t _q[2]; } XMMReg; +typedef union { + uint8_t _b[8]; + uint16_t _w[2]; + uint32_t _l[1]; + uint64_t q; +} MMXReg; + +#ifdef WORDS_BIGENDIAN +#define XMM_B(n) _b[15 - (n)] +#define XMM_W(n) _w[7 - (n)] +#define XMM_L(n) _l[3 - (n)] +#define XMM_Q(n) _q[1 - (n)] + +#define MMX_B(n) _b[7 - (n)] +#define MMX_W(n) _w[3 - (n)] +#define MMX_L(n) _l[1 - (n)] +#else +#define XMM_B(n) _b[n] +#define XMM_W(n) _w[n] +#define XMM_L(n) _l[n] +#define XMM_Q(n) _q[n] + +#define MMX_B(n) _b[n] +#define MMX_W(n) _w[n] +#define MMX_L(n) _l[n] +#endif + #ifdef TARGET_X86_64 #define CPU_NB_REGS 16 #else @@ -425,7 +450,7 @@ typedef struct CPUX86State { int exception_index; int error_code; int exception_is_int; - int exception_next_eip; + target_ulong exception_next_eip; struct TranslationBlock *current_tb; /* currently executing TB */ target_ulong cr[5]; /* NOTE: cr1 is unused */ target_ulong dr[8]; /* debug registers */ -- cgit v1.2.3 From a8ede8ba8be076ae56b7c9ce9b4f2a115589543a Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 6 Jan 2005 20:46:58 +0000 Subject: div64 fix - raise_interrupt() fix - SSE fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1202 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 6 +----- target-i386/helper.c | 21 +++++++++++---------- target-i386/op.c | 7 +++---- target-i386/ops_mem.h | 10 ++++------ target-i386/translate.c | 7 ++++--- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 5529c3552..330343164 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -176,17 +176,13 @@ void do_interrupt(int intno, int is_int, int error_code, void do_interrupt_user(int intno, int is_int, int error_code, target_ulong next_eip); void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip); + int next_eip_addend); void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); void __hidden cpu_loop_exit(void); void OPPROTO op_movl_eflags_T0(void); void OPPROTO op_movl_T0_eflags(void); -void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip); -void raise_exception_err(int exception_index, int error_code); -void raise_exception(int exception_index); void helper_divl_EAX_T0(void); void helper_idivl_EAX_T0(void); void helper_mulq_EAX_T0(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 64d6f9e7a..2567657a7 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1157,12 +1157,12 @@ void do_interrupt(int intno, int is_int, int error_code, * is_int is TRUE. */ void raise_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip) + int next_eip_addend) { env->exception_index = intno; env->error_code = error_code; env->exception_is_int = is_int; - env->exception_next_eip = next_eip; + env->exception_next_eip = env->eip + next_eip_addend; cpu_loop_exit(); } @@ -2929,14 +2929,14 @@ void helper_fxsave(target_ulong ptr, int data64) } if (env->cr[4] & CR4_OSFXSR_MASK) { - /* XXX: finish it, endianness */ + /* XXX: finish it */ stl(ptr + 0x18, 0); /* mxcsr */ stl(ptr + 0x1c, 0); /* mxcsr_mask */ nb_xmm_regs = 8 << data64; addr = ptr + 0xa0; for(i = 0; i < nb_xmm_regs; i++) { - stq(addr, env->xmm_regs[i].u.q[0]); - stq(addr, env->xmm_regs[i].u.q[1]); + stq(addr, env->xmm_regs[i].XMM_Q(0)); + stq(addr + 8, env->xmm_regs[i].XMM_Q(1)); addr += 16; } } @@ -2972,8 +2972,8 @@ void helper_fxrstor(target_ulong ptr, int data64) nb_xmm_regs = 8 << data64; addr = ptr + 0xa0; for(i = 0; i < nb_xmm_regs; i++) { - env->xmm_regs[i].u.q[0] = ldq(addr); - env->xmm_regs[i].u.q[1] = ldq(addr); + env->xmm_regs[i].XMM_Q(0) = ldq(addr); + env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8); addr += 16; } } @@ -3099,6 +3099,7 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) } } +/* XXX: overflow support */ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) { uint64_t q, r, a1, a0; @@ -3114,16 +3115,16 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) } else { /* XXX: use a better algorithm */ for(i = 0; i < 64; i++) { + a1 = (a1 << 1) | (a0 >> 63); if (a1 >= b) { a1 -= b; qb = 1; } else { qb = 0; } - a1 = (a1 << 1) | (a0 >> 63); a0 = (a0 << 1) | qb; } -#if defined(DEBUG_MULDIV) || 1 +#if defined(DEBUG_MULDIV) printf("div: 0x%016llx%016llx / 0x%016llx: q=0x%016llx r=0x%016llx\n", *phigh, *plow, b, a0, a1); #endif @@ -3167,7 +3168,7 @@ void helper_imulq_EAX_T0(void) EAX = r0; EDX = r1; CC_DST = r0; - CC_SRC = (r1 != (r0 >> 63)); + CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); } void helper_imulq_T0_T1(void) diff --git a/target-i386/op.c b/target-i386/op.c index f81d59b16..9ce2a5a2b 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -611,11 +611,10 @@ void OPPROTO op_debug(void) void OPPROTO op_raise_interrupt(void) { - int intno; - unsigned int next_eip; + int intno, next_eip_addend; intno = PARAM1; - next_eip = PARAM2; - raise_interrupt(intno, 1, 0, next_eip); + next_eip_addend = PARAM2; + raise_interrupt(intno, 1, 0, next_eip_addend); } void OPPROTO op_raise_exception(void) diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h index 284ab71af..21c17008b 100644 --- a/target-i386/ops_mem.h +++ b/target-i386/ops_mem.h @@ -85,18 +85,16 @@ void OPPROTO glue(glue(op_ldo, MEMSUFFIX), _env_A0)(void) { XMMReg *p; p = (XMMReg *)((char *)env + PARAM1); - /* XXX: host endianness ? */ - p->u.q[0] = glue(ldq, MEMSUFFIX)(A0); - p->u.q[1] = glue(ldq, MEMSUFFIX)(A0 + 8); + p->XMM_Q(0) = glue(ldq, MEMSUFFIX)(A0); + p->XMM_Q(1) = glue(ldq, MEMSUFFIX)(A0 + 8); } void OPPROTO glue(glue(op_sto, MEMSUFFIX), _env_A0)(void) { XMMReg *p; p = (XMMReg *)((char *)env + PARAM1); - /* XXX: host endianness ? */ - glue(stq, MEMSUFFIX)(A0, p->u.q[0]); - glue(stq, MEMSUFFIX)(A0 + 8, p->u.q[1]); + glue(stq, MEMSUFFIX)(A0, p->XMM_Q(0)); + glue(stq, MEMSUFFIX)(A0 + 8, p->XMM_Q(1)); } #ifdef TARGET_X86_64 diff --git a/target-i386/translate.c b/target-i386/translate.c index 743aff765..686c184f1 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2119,7 +2119,7 @@ static void gen_interrupt(DisasContext *s, int intno, if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(cur_eip); - gen_op_raise_interrupt(intno, next_eip); + gen_op_raise_interrupt(intno, (int)(next_eip - cur_eip)); s->is_jmp = 3; } @@ -4452,7 +4452,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_op_into(s->pc - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); + gen_op_into(s->pc - pc_start); break; case 0xf1: /* icebp (undocumented, exits to external debugger) */ #if 0 @@ -4826,7 +4827,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /* nothing to do */ } break; - case 0x1ae: /* sfence */ + case 0x1ae: modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; -- cgit v1.2.3 From abd2c7dc9c140cee6bd918d7abe05cba6d9d1332 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 6 Jan 2005 20:50:00 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1203 c046a42c-6fe2-441c-8c8c-71466251a162 --- amd64.ld | 171 -------------------------------------------------------------- x86_64.ld | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 171 deletions(-) delete mode 100644 amd64.ld create mode 100644 x86_64.ld diff --git a/amd64.ld b/amd64.ld deleted file mode 100644 index 878dafbe7..000000000 --- a/amd64.ld +++ /dev/null @@ -1,171 +0,0 @@ -/* Default linker script, for normal executables */ -OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") -OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) -SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); -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.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0x90909090 - .plt : { *(.plt) } - .text : - { - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0x90909090 - .fini : - { - KEEP (*(.fini)) - } =0x90909090 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } - /* 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 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(64 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array : { *(.preinit_array) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { *(.init_array) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { *(.fini_array) } - PROVIDE (__fini_array_end = .); - .data : - { - *(.data .data.* .gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } - .dynamic : { *(.dynamic) } - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - /* We don't want to include the .ctor section from - from the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .got : { *(.got.plt) *(.got) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(64 / 8); - } - . = ALIGN(64 / 8); - _end = .; - PROVIDE (end = .); - . = DATA_SEGMENT_END (.); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} diff --git a/x86_64.ld b/x86_64.ld new file mode 100644 index 000000000..878dafbe7 --- /dev/null +++ b/x86_64.ld @@ -0,0 +1,171 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); +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.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } + /* 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 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .got : { *(.got.plt) *(.got) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} -- cgit v1.2.3 From 085339a12b448a64527ce4fdb6e1d43addbb16dc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 Jan 2005 18:54:41 +0000 Subject: MMX/SSE test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1204 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- tests/test-i386.c | 435 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 434 insertions(+), 3 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index c0ee7b2a0..4bd1dc6e3 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ -include ../config-host.mak -CFLAGS=-Wall -O2 -g +CFLAGS=-Wall -O2 -g #-msse2 LDFLAGS= ifeq ($(ARCH),i386) diff --git a/tests/test-i386.c b/tests/test-i386.c index bc24cb698..ea756ec29 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -35,6 +35,7 @@ #define TEST_VM86 //#define LINUX_VM86_IOPL_FIX //#define TEST_P4_FLAGS +//#define TEST_SSE #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) @@ -647,8 +648,8 @@ void test_fbcd(double a) memset((env), 0xaa, sizeof(*(env)));\ for(i=0;i<5;i++)\ asm volatile ("fldl %0" : : "m" (dtab[i]));\ - asm(save " %0\n" : : "m" (*(env)));\ - asm(restore " %0\n": : "m" (*(env)));\ + asm volatile (save " %0\n" : : "m" (*(env)));\ + asm volatile (restore " %0\n": : "m" (*(env)));\ for(i=0;i<5;i++)\ asm volatile ("fstpl %0" : "=m" (rtab[i]));\ for(i=0;i<5;i++)\ @@ -1674,6 +1675,433 @@ static void test_enter(void) TEST_ENTER("w", uint16_t, 31); } +#ifdef TEST_SSE + +typedef int __m64 __attribute__ ((__mode__ (__V2SI__))); +typedef int __m128 __attribute__ ((__mode__(__V4SF__))); + +typedef union { + double d[2]; + float s[4]; + uint32_t l[4]; + uint64_t q[2]; + __m128 dq; +} XMMReg; + +static uint64_t __attribute__((aligned(16))) test_values[4][2] = { + { 0x456723c698694873, 0xdc515cff944a58ec }, + { 0x1f297ccd58bad7ab, 0x41f21efba9e3e146 }, + { 0x007c62c2085427f8, 0x231be9e8cde7438d }, + { 0x0f76255a085427f8, 0xc233e9e8c4c9439a }, +}; + +#define SSE_OP(op)\ +{\ + asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ + printf("%-9s: a=%016llx%016llx b=%016llx%016llx r=%016llx%016llx\n",\ + #op,\ + a.q[1], a.q[0],\ + b.q[1], b.q[0],\ + r.q[1], r.q[0]);\ +} + +#define SSE_OP2(op)\ +{\ + int i;\ + for(i=0;i<2;i++) {\ + a.q[0] = test_values[2*i][0];\ + a.q[1] = test_values[2*i][1];\ + b.q[0] = test_values[2*i+1][0];\ + b.q[1] = test_values[2*i+1][1];\ + SSE_OP(op);\ + }\ +} + +#define MMX_OP2(op)\ +{\ + int i;\ + for(i=0;i<2;i++) {\ + a.q[0] = test_values[2*i][0];\ + b.q[0] = test_values[2*i+1][0];\ + asm volatile (#op " %2, %0" : "=y" (r.q[0]) : "0" (a.q[0]), "y" (b.q[0]));\ + printf("%-9s: a=%016llx b=%016llx r=%016llx\n",\ + #op,\ + a.q[0],\ + b.q[0],\ + r.q[0]);\ + }\ + SSE_OP2(op);\ +} + +#define PSHUF_OP(op, ib)\ +{\ + int i;\ + for(i=0;i<2;i++) {\ + a.q[0] = test_values[2*i][0];\ + a.q[1] = test_values[2*i][1];\ + asm volatile (#op " $" #ib ", %1, %0" : "=x" (r.dq) : "x" (a.dq));\ + printf("%-9s: a=%016llx%016llx ib=%02x r=%016llx%016llx\n",\ + #op,\ + a.q[1], a.q[0],\ + ib,\ + r.q[1], r.q[0]);\ + }\ +} + +#define SHIFT_IM(op, ib)\ +{\ + int i;\ + for(i=0;i<2;i++) {\ + a.q[0] = test_values[2*i][0];\ + a.q[1] = test_values[2*i][1];\ + asm volatile (#op " $" #ib ", %0" : "=x" (r.dq) : "0" (a.dq));\ + printf("%-9s: a=%016llx%016llx ib=%02x r=%016llx%016llx\n",\ + #op,\ + a.q[1], a.q[0],\ + ib,\ + r.q[1], r.q[0]);\ + }\ +} + +#define SHIFT_OP(op, ib)\ +{\ + int i;\ + SHIFT_IM(op, ib);\ + for(i=0;i<2;i++) {\ + a.q[0] = test_values[2*i][0];\ + a.q[1] = test_values[2*i][1];\ + b.q[0] = ib;\ + b.q[1] = 0;\ + asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ + printf("%-9s: a=%016llx%016llx b=%016llx%016llx r=%016llx%016llx\n",\ + #op,\ + a.q[1], a.q[0],\ + b.q[1], b.q[0],\ + r.q[1], r.q[0]);\ + }\ +} + +#define MOVMSK(op)\ +{\ + int i, reg;\ + for(i=0;i<2;i++) {\ + a.q[0] = test_values[2*i][0];\ + a.q[1] = test_values[2*i][1];\ + asm volatile (#op " %1, %0" : "=r" (reg) : "x" (a.dq));\ + printf("%-9s: a=%016llx%016llx r=%08x\n",\ + #op,\ + a.q[1], a.q[0],\ + reg);\ + }\ +} + +#define SSE_OPS(a) \ +SSE_OP(a ## ps);\ +SSE_OP(a ## ss); + +#define SSE_OPD(a) \ +SSE_OP(a ## pd);\ +SSE_OP(a ## sd); + +#define SSE_COMI(op, field)\ +{\ + unsigned int eflags;\ + XMMReg a, b;\ + a.field[0] = a1;\ + b.field[0] = b1;\ + asm volatile (#op " %2, %1\n"\ + "pushf\n"\ + "pop %0\n"\ + : "=m" (eflags)\ + : "x" (a.dq), "x" (b.dq));\ + printf("%-9s: a=%f b=%f cc=%04x\n",\ + #op, a1, b1,\ + eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\ +} + +void test_sse_comi(double a1, double b1) +{ + SSE_COMI(ucomiss, s); + SSE_COMI(ucomisd, d); + SSE_COMI(comiss, s); + SSE_COMI(comisd, d); +} + +#define CVT_OP_XMM(op)\ +{\ + asm volatile (#op " %1, %0" : "=x" (r.dq) : "x" (a.dq));\ + printf("%-9s: a=%016llx%016llx r=%016llx%016llx\n",\ + #op,\ + a.q[1], a.q[0],\ + r.q[1], r.q[0]);\ +} + +#define CVT_OP_XMM2MMX(op)\ +{\ + asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq));\ + printf("%-9s: a=%016llx%016llx r=%016llx\n",\ + #op,\ + a.q[1], a.q[0],\ + r.q[0]);\ +} + +#define CVT_OP_MMX2XMM(op)\ +{\ + asm volatile (#op " %1, %0" : "=x" (r.dq) : "y" (a.q[0]));\ + printf("%-9s: a=%016llx r=%016llx%016llx\n",\ + #op,\ + a.q[0],\ + r.q[1], r.q[0]);\ +} + +#define CVT_OP_REG2XMM(op)\ +{\ + asm volatile (#op " %1, %0" : "=x" (r.dq) : "r" (a.l[0]));\ + printf("%-9s: a=%08x r=%016llx%016llx\n",\ + #op,\ + a.l[0],\ + r.q[1], r.q[0]);\ +} + +#define CVT_OP_XMM2REG(op)\ +{\ + asm volatile (#op " %1, %0" : "=r" (r.l[0]) : "x" (a.dq));\ + printf("%-9s: a=%016llx%016llx r=%08x\n",\ + #op,\ + a.q[1], a.q[0],\ + r.l[0]);\ +} + +void test_sse(void) +{ + XMMReg r, a, b; + + MMX_OP2(punpcklbw); + MMX_OP2(punpcklwd); + MMX_OP2(punpckldq); + MMX_OP2(packsswb); + MMX_OP2(pcmpgtb); + MMX_OP2(pcmpgtw); + MMX_OP2(pcmpgtd); + MMX_OP2(packuswb); + MMX_OP2(punpckhbw); + MMX_OP2(punpckhwd); + MMX_OP2(punpckhdq); + MMX_OP2(packssdw); + MMX_OP2(pcmpeqb); + MMX_OP2(pcmpeqw); + MMX_OP2(pcmpeqd); + + MMX_OP2(paddq); + MMX_OP2(pmullw); + MMX_OP2(psubusb); + MMX_OP2(psubusw); + MMX_OP2(pminub); + MMX_OP2(pand); + MMX_OP2(paddusb); + MMX_OP2(paddusw); + MMX_OP2(pmaxub); + MMX_OP2(pandn); + + MMX_OP2(pmulhuw); + MMX_OP2(pmulhw); + + MMX_OP2(psubsb); + MMX_OP2(psubsw); + MMX_OP2(pminsw); + MMX_OP2(por); + MMX_OP2(paddsb); + MMX_OP2(paddsw); + MMX_OP2(pmaxsw); + MMX_OP2(pxor); + MMX_OP2(pmuludq); + MMX_OP2(pmaddwd); + MMX_OP2(psadbw); + MMX_OP2(psubb); + MMX_OP2(psubw); + MMX_OP2(psubd); + MMX_OP2(psubq); + MMX_OP2(paddb); + MMX_OP2(paddw); + MMX_OP2(paddd); + + MMX_OP2(pavgb); + MMX_OP2(pavgw); + + asm volatile ("pinsrw $1, %1, %0" : "=y" (r.q[0]) : "r" (0x12345678)); + printf("%-9s: r=%016llx\n", "pinsrw", r.q[0]); + + asm volatile ("pinsrw $5, %1, %0" : "=x" (r.dq) : "r" (0x12345678)); + printf("%-9s: r=%016llx%016llx\n", "pinsrw", r.q[1], r.q[0]); + + a.q[0] = test_values[0][0]; + a.q[1] = test_values[0][1]; + asm volatile ("pextrw $1, %1, %0" : "=r" (r.l[0]) : "y" (a.q[0])); + printf("%-9s: r=%08x\n", "pextrw", r.l[0]); + + asm volatile ("pextrw $5, %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); + printf("%-9s: r=%08x\n", "pextrw", r.l[0]); + + asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "y" (a.q[0])); + printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); + + asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); + printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); + + asm volatile ("emms"); + + SSE_OP2(punpcklqdq); + SSE_OP2(punpckhqdq); + SSE_OP2(andps); + SSE_OP2(andpd); + SSE_OP2(andnps); + SSE_OP2(andnpd); + SSE_OP2(orps); + SSE_OP2(orpd); + SSE_OP2(xorps); + SSE_OP2(xorpd); + + SSE_OP2(unpcklps); + SSE_OP2(unpcklpd); + SSE_OP2(unpckhps); + SSE_OP2(unpckhpd); + + PSHUF_OP(shufps, 0x78); + PSHUF_OP(shufpd, 0x02); + + PSHUF_OP(pshufd, 0x78); + PSHUF_OP(pshuflw, 0x78); + PSHUF_OP(pshufhw, 0x78); + + SHIFT_OP(psrlw, 7); + SHIFT_OP(psrlw, 16); + SHIFT_OP(psraw, 7); + SHIFT_OP(psraw, 16); + SHIFT_OP(psllw, 7); + SHIFT_OP(psllw, 16); + + SHIFT_OP(psrld, 7); + SHIFT_OP(psrld, 32); + SHIFT_OP(psrad, 7); + SHIFT_OP(psrad, 32); + SHIFT_OP(pslld, 7); + SHIFT_OP(pslld, 32); + + SHIFT_OP(psrlq, 7); + SHIFT_OP(psrlq, 32); + SHIFT_OP(psllq, 7); + SHIFT_OP(psllq, 32); + + SHIFT_IM(psrldq, 16); + SHIFT_IM(psrldq, 7); + SHIFT_IM(pslldq, 16); + SHIFT_IM(pslldq, 7); + + MOVMSK(movmskps); + MOVMSK(movmskpd); + + /* FPU specific ops */ + + { + uint32_t mxcsr; + asm volatile("stmxcsr %0" : "=m" (mxcsr)); + printf("mxcsr=%08x\n", mxcsr & 0x1f80); + asm volatile("ldmxcsr %0" : : "m" (mxcsr)); + } + + test_sse_comi(2, -1); + test_sse_comi(2, 2); + test_sse_comi(2, 3); + + a.s[0] = 2.7; + a.s[1] = 3.4; + a.s[2] = 4; + a.s[3] = -6.3; + b.s[0] = 45.7; + b.s[1] = 353.4; + b.s[2] = 4; + b.s[3] = 56.3; + SSE_OPS(add); + SSE_OPS(mul); + SSE_OPS(sub); + SSE_OPS(min); + SSE_OPS(div); + SSE_OPS(max); + SSE_OPS(sqrt); + SSE_OPS(cmpeq); + SSE_OPS(cmplt); + SSE_OPS(cmple); + SSE_OPS(cmpunord); + SSE_OPS(cmpneq); + SSE_OPS(cmpnlt); + SSE_OPS(cmpnle); + SSE_OPS(cmpord); + + a.d[0] = 2.7; + a.d[1] = -3.4; + b.d[0] = 45.7; + b.d[1] = -53.4; + SSE_OPD(add); + SSE_OPD(mul); + SSE_OPD(sub); + SSE_OPD(min); + SSE_OPD(div); + SSE_OPD(max); + SSE_OPD(sqrt); + SSE_OPD(cmpeq); + SSE_OPD(cmplt); + SSE_OPD(cmple); + SSE_OPD(cmpunord); + SSE_OPD(cmpneq); + SSE_OPD(cmpnlt); + SSE_OPD(cmpnle); + SSE_OPD(cmpord); + + /* float to float/int */ + a.s[0] = 2.7; + a.s[1] = 3.4; + a.s[2] = 4; + a.s[3] = -6.3; + CVT_OP_XMM(cvtps2pd); + CVT_OP_XMM(cvtss2sd); + CVT_OP_XMM2MMX(cvtps2pi); + CVT_OP_XMM2MMX(cvttps2pi); + CVT_OP_XMM2REG(cvtss2si); + CVT_OP_XMM2REG(cvttss2si); + CVT_OP_XMM(cvtps2dq); + CVT_OP_XMM(cvttps2dq); + + a.d[0] = 2.6; + a.d[1] = -3.4; + CVT_OP_XMM(cvtpd2ps); + CVT_OP_XMM(cvtsd2ss); + CVT_OP_XMM2MMX(cvtpd2pi); + CVT_OP_XMM2MMX(cvttpd2pi); + CVT_OP_XMM2REG(cvtsd2si); + CVT_OP_XMM2REG(cvttsd2si); + CVT_OP_XMM(cvtpd2dq); + CVT_OP_XMM(cvttpd2dq); + + /* int to float */ + a.l[0] = -6; + a.l[1] = 2; + a.l[2] = 100; + a.l[3] = -60000; + CVT_OP_MMX2XMM(cvtpi2ps); + CVT_OP_MMX2XMM(cvtpi2pd); + CVT_OP_REG2XMM(cvtsi2ss); + CVT_OP_REG2XMM(cvtsi2sd); + CVT_OP_XMM(cvtdq2ps); + CVT_OP_XMM(cvtdq2pd); + + /* XXX: test PNI insns */ +#if 0 + SSE_OP2(movshdup); +#endif +} + +#endif + static void *call_end __init_call = NULL; int main(int argc, char **argv) @@ -1704,5 +2132,8 @@ int main(int argc, char **argv) test_self_modifying_code(); test_single_step(); test_enter(); +#ifdef TEST_SSE + test_sse(); +#endif return 0; } -- cgit v1.2.3 From 664e0f195adda3cf01b40d8d1aa79bbc24ad5fab Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 8 Jan 2005 18:58:29 +0000 Subject: MMX/SSE support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1205 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 2 +- linux-user/main.c | 4 +- target-i386/cpu.h | 30 +- target-i386/exec.h | 9 +- target-i386/helper.c | 26 +- target-i386/helper2.c | 30 +- target-i386/op.c | 80 ++- target-i386/ops_mem.h | 16 +- target-i386/ops_sse.h | 1370 +++++++++++++++++++++++++++++++++++++++++++++++ target-i386/translate.c | 888 ++++++++++++++++++++++++++---- vl.c | 117 +++- 12 files changed, 2402 insertions(+), 171 deletions(-) create mode 100644 target-i386/ops_sse.h diff --git a/Changelog b/Changelog index d041fc36a..539e3ec96 100644 --- a/Changelog +++ b/Changelog @@ -11,6 +11,7 @@ version 0.6.2: - added generic 64 bit target support - initial x86_64 target support - initial APIC support + - MMX/SSE/SSE2/PNI support version 0.6.1: diff --git a/Makefile.target b/Makefile.target index b07e4903e..942a105ea 100644 --- a/Makefile.target +++ b/Makefile.target @@ -392,7 +392,7 @@ helper.o: helper.c $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< ifeq ($(TARGET_BASE_ARCH), i386) -op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h +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) diff --git a/linux-user/main.c b/linux-user/main.c index aa5923f84..f2b83b0c2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1052,8 +1052,8 @@ int main(int argc, char **argv) cpu_x86_set_cpl(env, 3); env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; - env->hflags |= HF_PE_MASK; - + env->hflags |= HF_PE_MASK | HF_OSFXSR_MASK; + /* flags setup : we activate the IRQs by default as in user mode */ env->eflags |= IF_MASK; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e65fc2e2c..e494d23f7 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -135,6 +135,7 @@ #define HF_IOPL_SHIFT 12 /* must be same as eflags */ #define HF_LMA_SHIFT 14 /* only used on x86_64: long mode active */ #define HF_CS64_SHIFT 15 /* only used on x86_64: 64 bit code segment */ +#define HF_OSFXSR_SHIFT 16 /* CR4.OSFXSR */ #define HF_VM_SHIFT 17 /* must be same as eflags */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) @@ -150,6 +151,7 @@ #define HF_TS_MASK (1 << HF_TS_SHIFT) #define HF_LMA_MASK (1 << HF_LMA_SHIFT) #define HF_CS64_MASK (1 << HF_CS64_SHIFT) +#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT) #define CR0_PE_MASK (1 << 0) #define CR0_MP_MASK (1 << 1) @@ -340,10 +342,12 @@ typedef struct SegmentCache { } SegmentCache; typedef union { - uint8_t _b[16]; - uint16_t _w[8]; - uint32_t _l[4]; - uint64_t _q[2]; + uint8_t _b[16]; + uint16_t _w[8]; + uint32_t _l[4]; + uint64_t _q[2]; + float _s[4]; + double _d[2]; } XMMReg; typedef union { @@ -357,7 +361,9 @@ typedef union { #define XMM_B(n) _b[15 - (n)] #define XMM_W(n) _w[7 - (n)] #define XMM_L(n) _l[3 - (n)] +#define XMM_S(n) _s[3 - (n)] #define XMM_Q(n) _q[1 - (n)] +#define XMM_D(n) _d[1 - (n)] #define MMX_B(n) _b[7 - (n)] #define MMX_W(n) _w[3 - (n)] @@ -366,12 +372,15 @@ typedef union { #define XMM_B(n) _b[n] #define XMM_W(n) _w[n] #define XMM_L(n) _l[n] +#define XMM_S(n) _s[n] #define XMM_Q(n) _q[n] +#define XMM_D(n) _d[n] #define MMX_B(n) _b[n] #define MMX_W(n) _w[n] #define MMX_L(n) _l[n] #endif +#define MMX_Q(n) q #ifdef TARGET_X86_64 #define CPU_NB_REGS 16 @@ -404,7 +413,14 @@ typedef struct CPUX86State { unsigned int fpus; unsigned int fpuc; uint8_t fptags[8]; /* 0 = valid, 1 = empty */ - CPU86_LDouble fpregs[8]; + union { +#ifdef USE_X86LDOUBLE + CPU86_LDouble d __attribute__((aligned(16))); +#else + CPU86_LDouble d; +#endif + MMXReg mmx; + } fpregs[8]; /* emulator internal variables */ CPU86_LDouble ft0; @@ -421,9 +437,11 @@ typedef struct CPUX86State { SegmentCache tr; SegmentCache gdt; /* only base and limit are used */ SegmentCache idt; /* only base and limit are used */ - + + uint32_t mxcsr; XMMReg xmm_regs[CPU_NB_REGS]; XMMReg xmm_t0; + MMXReg mmx_t0; /* sysenter registers */ uint32_t sysenter_cs; diff --git a/target-i386/exec.h b/target-i386/exec.h index 330343164..1923b95ee 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -131,8 +131,8 @@ extern int loglevel; /* float macros */ #define FT0 (env->ft0) -#define ST0 (env->fpregs[env->fpstt]) -#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) +#define ST0 (env->fpregs[env->fpstt].d) +#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d) #define ST1 ST(1) #ifdef USE_FP_CONVERT @@ -459,7 +459,7 @@ static inline CPU86_LDouble helper_fldt(target_ulong ptr) return temp.d; } -static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) +static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) { CPU86_LDoubleU temp; int e; @@ -557,6 +557,9 @@ void helper_fxsave(target_ulong ptr, int data64); void helper_fxrstor(target_ulong ptr, int data64); void restore_native_fp_state(CPUState *env); void save_native_fp_state(CPUState *env); +float approx_rsqrt(float a); +float approx_rcp(float a); +int fpu_isnan(double a); extern const uint8_t parity_table[256]; extern const uint8_t rclw_table[32]; diff --git a/target-i386/helper.c b/target-i386/helper.c index 2567657a7..9907f8e0b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2444,7 +2444,7 @@ void helper_fldt_ST0_A0(void) { int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = helper_fldt(A0); + env->fpregs[new_fpstt].d = helper_fldt(A0); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } @@ -2804,9 +2804,10 @@ void helper_fstenv(target_ulong ptr, int data32) if (env->fptags[i]) { fptag |= 3; } else { - tmp.d = env->fpregs[i]; + tmp.d = env->fpregs[i].d; exp = EXPD(tmp); mant = MANTD(tmp); + printf("mant=%llx exp=%x\n", mant, exp); if (exp == 0 && mant == 0) { /* zero */ fptag |= 1; @@ -2930,7 +2931,7 @@ void helper_fxsave(target_ulong ptr, int data64) if (env->cr[4] & CR4_OSFXSR_MASK) { /* XXX: finish it */ - stl(ptr + 0x18, 0); /* mxcsr */ + stl(ptr + 0x18, env->mxcsr); /* mxcsr */ stl(ptr + 0x1c, 0); /* mxcsr_mask */ nb_xmm_regs = 8 << data64; addr = ptr + 0xa0; @@ -2967,7 +2968,7 @@ void helper_fxrstor(target_ulong ptr, int data64) if (env->cr[4] & CR4_OSFXSR_MASK) { /* XXX: finish it, endianness */ - //ldl(ptr + 0x18); + env->mxcsr = ldl(ptr + 0x18); //ldl(ptr + 0x1c); nb_xmm_regs = 8 << data64; addr = ptr + 0xa0; @@ -3209,6 +3210,23 @@ void helper_idivq_EAX_T0(void) #endif +/* XXX: do it */ +int fpu_isnan(double a) +{ + return 0; +} + +float approx_rsqrt(float a) +{ + return 1.0 / sqrt(a); +} + +float approx_rcp(float a) +{ + return 1.0 / a; +} + + #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 34307928a..2811cd707 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -158,6 +158,8 @@ void cpu_reset(CPUX86State *env) for(i = 0;i < 8; i++) env->fptags[i] = 1; env->fpuc = 0x37f; + + env->mxcsr = 0x1f80; } void cpu_x86_close(CPUX86State *env) @@ -376,15 +378,15 @@ void cpu_dump_state(CPUState *env, FILE *f, } if (flags & X86_DUMP_FPU) { cpu_fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", - (double)env->fpregs[0], - (double)env->fpregs[1], - (double)env->fpregs[2], - (double)env->fpregs[3]); + (double)env->fpregs[0].d, + (double)env->fpregs[1].d, + (double)env->fpregs[2].d, + (double)env->fpregs[3].d); cpu_fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", - (double)env->fpregs[4], - (double)env->fpregs[5], - (double)env->fpregs[7], - (double)env->fpregs[8]); + (double)env->fpregs[4].d, + (double)env->fpregs[5].d, + (double)env->fpregs[7].d, + (double)env->fpregs[8].d); } } @@ -471,6 +473,14 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) { tlb_flush(env, 1); } + /* SSE handling */ + if (!(env->cpuid_features & CPUID_SSE)) + new_cr4 &= ~CR4_OSFXSR_MASK; + if (new_cr4 & CR4_OSFXSR_MASK) + env->hflags |= HF_OSFXSR_MASK; + else + env->hflags &= ~HF_OSFXSR_MASK; + env->cr[4] = new_cr4; } @@ -800,7 +810,7 @@ void restore_native_fp_state(CPUState *env) fp->fptag = fptag; j = env->fpstt; for(i = 0;i < 8; i++) { - memcpy(&fp->fpregs1[i * 10], &env->fpregs[j], 10); + memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10); j = (j + 1) & 7; } asm volatile ("frstor %0" : "=m" (*fp)); @@ -824,7 +834,7 @@ void save_native_fp_state(CPUState *env) } j = env->fpstt; for(i = 0;i < 8; i++) { - memcpy(&env->fpregs[j], &fp->fpregs1[i * 10], 10); + memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10); j = (j + 1) & 7; } /* we must restore the default rounding state */ diff --git a/target-i386/op.c b/target-i386/op.c index 9ce2a5a2b..10098256d 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -752,11 +752,6 @@ void OPPROTO op_movswl_T0_T0(void) T0 = (int16_t)T0; } -void OPPROTO op_movslq_T0_T0(void) -{ - T0 = (int32_t)T0; -} - void OPPROTO op_movzwl_T0_T0(void) { T0 = (uint16_t)T0; @@ -768,6 +763,11 @@ void OPPROTO op_movswl_EAX_AX(void) } #ifdef TARGET_X86_64 +void OPPROTO op_movslq_T0_T0(void) +{ + T0 = (int32_t)T0; +} + void OPPROTO op_movslq_RAX_EAX(void) { EAX = (int32_t)EAX; @@ -1695,9 +1695,9 @@ void OPPROTO op_flds_ST0_A0(void) new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i32 = ldl(A0); - env->fpregs[new_fpstt] = FP_CONVERT.f; + env->fpregs[new_fpstt].d = FP_CONVERT.f; #else - env->fpregs[new_fpstt] = ldfl(A0); + env->fpregs[new_fpstt].d = ldfl(A0); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1709,9 +1709,9 @@ void OPPROTO op_fldl_ST0_A0(void) new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i64 = ldq(A0); - env->fpregs[new_fpstt] = FP_CONVERT.d; + env->fpregs[new_fpstt].d = FP_CONVERT.d; #else - env->fpregs[new_fpstt] = ldfq(A0); + env->fpregs[new_fpstt].d = ldfq(A0); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1729,7 +1729,7 @@ void helper_fild_ST0_A0(void) { int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw(A0); + env->fpregs[new_fpstt].d = (CPU86_LDouble)ldsw(A0); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } @@ -1738,7 +1738,7 @@ void helper_fildl_ST0_A0(void) { int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl(A0)); + env->fpregs[new_fpstt].d = (CPU86_LDouble)((int32_t)ldl(A0)); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } @@ -1747,7 +1747,7 @@ void helper_fildll_ST0_A0(void) { int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq(A0)); + env->fpregs[new_fpstt].d = (CPU86_LDouble)((int64_t)ldq(A0)); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } @@ -1775,9 +1775,9 @@ void OPPROTO op_fild_ST0_A0(void) new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i32 = ldsw(A0); - env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; + env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i32; #else - env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw(A0); + env->fpregs[new_fpstt].d = (CPU86_LDouble)ldsw(A0); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1789,9 +1789,9 @@ void OPPROTO op_fildl_ST0_A0(void) new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i32 = (int32_t) ldl(A0); - env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32; + env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i32; #else - env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl(A0)); + env->fpregs[new_fpstt].d = (CPU86_LDouble)((int32_t)ldl(A0)); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -1803,9 +1803,9 @@ void OPPROTO op_fildll_ST0_A0(void) new_fpstt = (env->fpstt - 1) & 7; #ifdef USE_FP_CONVERT FP_CONVERT.i64 = (int64_t) ldq(A0); - env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64; + env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i64; #else - env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq(A0)); + env->fpregs[new_fpstt].d = (CPU86_LDouble)((int64_t)ldq(A0)); #endif env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ @@ -2322,6 +2322,29 @@ void OPPROTO op_movo(void) memcpy16(d, s); } +void OPPROTO op_movq(void) +{ + uint64_t *d, *s; + d = (uint64_t *)((char *)env + PARAM1); + s = (uint64_t *)((char *)env + PARAM2); + *d = *s; +} + +void OPPROTO op_movl(void) +{ + uint32_t *d, *s; + d = (uint32_t *)((char *)env + PARAM1); + s = (uint32_t *)((char *)env + PARAM2); + *d = *s; +} + +void OPPROTO op_movq_env_0(void) +{ + uint64_t *d; + d = (uint64_t *)((char *)env + PARAM1); + *d = 0; +} + void OPPROTO op_fxsave_A0(void) { helper_fxsave(A0, PARAM1); @@ -2331,3 +2354,24 @@ void OPPROTO op_fxrstor_A0(void) { helper_fxrstor(A0, PARAM1); } + +/* XXX: optimize by storing fptt and fptags in the static cpu state */ +void OPPROTO op_enter_mmx(void) +{ + env->fpstt = 0; + *(uint32_t *)(env->fptags) = 0; + *(uint32_t *)(env->fptags + 4) = 0; +} + +void OPPROTO op_emms(void) +{ + /* set to empty state */ + *(uint32_t *)(env->fptags) = 0x01010101; + *(uint32_t *)(env->fptags + 4) = 0x01010101; +} + +#define SHIFT 0 +#include "ops_sse.h" + +#define SHIFT 1 +#include "ops_sse.h" diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h index 21c17008b..2e6ccc424 100644 --- a/target-i386/ops_mem.h +++ b/target-i386/ops_mem.h @@ -80,7 +80,21 @@ void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T1_A0)(void) glue(stl, MEMSUFFIX)(A0, T1); } -/* SSE support */ +/* SSE/MMX support */ +void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _env_A0)(void) +{ + uint64_t *p; + p = (uint64_t *)((char *)env + PARAM1); + *p = glue(ldq, MEMSUFFIX)(A0); +} + +void OPPROTO glue(glue(op_stq, MEMSUFFIX), _env_A0)(void) +{ + uint64_t *p; + p = (uint64_t *)((char *)env + PARAM1); + glue(stq, MEMSUFFIX)(A0, *p); +} + void OPPROTO glue(glue(op_ldo, MEMSUFFIX), _env_A0)(void) { XMMReg *p; diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h new file mode 100644 index 000000000..39c90d0c2 --- /dev/null +++ b/target-i386/ops_sse.h @@ -0,0 +1,1370 @@ +/* + * MMX/SSE/SSE2/PNI support + * + * Copyright (c) 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 + */ +#if SHIFT == 0 +#define Reg MMXReg +#define XMM_ONLY(x...) +#define B(n) MMX_B(n) +#define W(n) MMX_W(n) +#define L(n) MMX_L(n) +#define Q(n) q +#define SUFFIX _mmx +#else +#define Reg XMMReg +#define XMM_ONLY(x...) x +#define B(n) XMM_B(n) +#define W(n) XMM_W(n) +#define L(n) XMM_L(n) +#define Q(n) XMM_Q(n) +#define SUFFIX _xmm +#endif + +void OPPROTO glue(op_psrlw, SUFFIX)(void) +{ + Reg *d, *s; + int shift; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + if (s->Q(0) > 15) { + d->Q(0) = 0; +#if SHIFT == 1 + d->Q(1) = 0; +#endif + } else { + shift = s->B(0); + d->W(0) >>= shift; + d->W(1) >>= shift; + d->W(2) >>= shift; + d->W(3) >>= shift; +#if SHIFT == 1 + d->W(4) >>= shift; + d->W(5) >>= shift; + d->W(6) >>= shift; + d->W(7) >>= shift; +#endif + } +} + +void OPPROTO glue(op_psraw, SUFFIX)(void) +{ + Reg *d, *s; + int shift; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + if (s->Q(0) > 15) { + shift = 15; + } else { + shift = s->B(0); + } + d->W(0) = (int16_t)d->W(0) >> shift; + d->W(1) = (int16_t)d->W(1) >> shift; + d->W(2) = (int16_t)d->W(2) >> shift; + d->W(3) = (int16_t)d->W(3) >> shift; +#if SHIFT == 1 + d->W(4) = (int16_t)d->W(4) >> shift; + d->W(5) = (int16_t)d->W(5) >> shift; + d->W(6) = (int16_t)d->W(6) >> shift; + d->W(7) = (int16_t)d->W(7) >> shift; +#endif +} + +void OPPROTO glue(op_psllw, SUFFIX)(void) +{ + Reg *d, *s; + int shift; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + if (s->Q(0) > 15) { + d->Q(0) = 0; +#if SHIFT == 1 + d->Q(1) = 0; +#endif + } else { + shift = s->B(0); + d->W(0) <<= shift; + d->W(1) <<= shift; + d->W(2) <<= shift; + d->W(3) <<= shift; +#if SHIFT == 1 + d->W(4) <<= shift; + d->W(5) <<= shift; + d->W(6) <<= shift; + d->W(7) <<= shift; +#endif + } +} + +void OPPROTO glue(op_psrld, SUFFIX)(void) +{ + Reg *d, *s; + int shift; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + if (s->Q(0) > 31) { + d->Q(0) = 0; +#if SHIFT == 1 + d->Q(1) = 0; +#endif + } else { + shift = s->B(0); + d->L(0) >>= shift; + d->L(1) >>= shift; +#if SHIFT == 1 + d->L(2) >>= shift; + d->L(3) >>= shift; +#endif + } +} + +void OPPROTO glue(op_psrad, SUFFIX)(void) +{ + Reg *d, *s; + int shift; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + if (s->Q(0) > 31) { + shift = 31; + } else { + shift = s->B(0); + } + d->L(0) = (int32_t)d->L(0) >> shift; + d->L(1) = (int32_t)d->L(1) >> shift; +#if SHIFT == 1 + d->L(2) = (int32_t)d->L(2) >> shift; + d->L(3) = (int32_t)d->L(3) >> shift; +#endif +} + +void OPPROTO glue(op_pslld, SUFFIX)(void) +{ + Reg *d, *s; + int shift; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + if (s->Q(0) > 31) { + d->Q(0) = 0; +#if SHIFT == 1 + d->Q(1) = 0; +#endif + } else { + shift = s->B(0); + d->L(0) <<= shift; + d->L(1) <<= shift; +#if SHIFT == 1 + d->L(2) <<= shift; + d->L(3) <<= shift; +#endif + } +} + +void OPPROTO glue(op_psrlq, SUFFIX)(void) +{ + Reg *d, *s; + int shift; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + if (s->Q(0) > 63) { + d->Q(0) = 0; +#if SHIFT == 1 + d->Q(1) = 0; +#endif + } else { + shift = s->B(0); + d->Q(0) >>= shift; +#if SHIFT == 1 + d->Q(1) >>= shift; +#endif + } +} + +void OPPROTO glue(op_psllq, SUFFIX)(void) +{ + Reg *d, *s; + int shift; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + if (s->Q(0) > 63) { + d->Q(0) = 0; +#if SHIFT == 1 + d->Q(1) = 0; +#endif + } else { + shift = s->B(0); + d->Q(0) <<= shift; +#if SHIFT == 1 + d->Q(1) <<= shift; +#endif + } +} + +#if SHIFT == 1 +void OPPROTO glue(op_psrldq, SUFFIX)(void) +{ + Reg *d, *s; + int shift, i; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + shift = s->L(0); + if (shift > 16) + shift = 16; + for(i = 0; i < 16 - shift; i++) + d->B(i) = d->B(i + shift); + for(i = 16 - shift; i < 16; i++) + d->B(i) = 0; + FORCE_RET(); +} + +void OPPROTO glue(op_pslldq, SUFFIX)(void) +{ + Reg *d, *s; + int shift, i; + + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + shift = s->L(0); + if (shift > 16) + shift = 16; + for(i = 15; i >= shift; i--) + d->B(i) = d->B(i - shift); + for(i = 0; i < shift; i++) + d->B(i) = 0; + FORCE_RET(); +} +#endif + +#define SSE_OP_B(name, F)\ +void OPPROTO glue(name, SUFFIX) (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->B(0) = F(d->B(0), s->B(0));\ + d->B(1) = F(d->B(1), s->B(1));\ + d->B(2) = F(d->B(2), s->B(2));\ + d->B(3) = F(d->B(3), s->B(3));\ + d->B(4) = F(d->B(4), s->B(4));\ + d->B(5) = F(d->B(5), s->B(5));\ + d->B(6) = F(d->B(6), s->B(6));\ + d->B(7) = F(d->B(7), s->B(7));\ + XMM_ONLY(\ + d->B(8) = F(d->B(8), s->B(8));\ + d->B(9) = F(d->B(9), s->B(9));\ + d->B(10) = F(d->B(10), s->B(10));\ + d->B(11) = F(d->B(11), s->B(11));\ + d->B(12) = F(d->B(12), s->B(12));\ + d->B(13) = F(d->B(13), s->B(13));\ + d->B(14) = F(d->B(14), s->B(14));\ + d->B(15) = F(d->B(15), s->B(15));\ + )\ +} + +#define SSE_OP_W(name, F)\ +void OPPROTO glue(name, SUFFIX) (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->W(0) = F(d->W(0), s->W(0));\ + d->W(1) = F(d->W(1), s->W(1));\ + d->W(2) = F(d->W(2), s->W(2));\ + d->W(3) = F(d->W(3), s->W(3));\ + XMM_ONLY(\ + d->W(4) = F(d->W(4), s->W(4));\ + d->W(5) = F(d->W(5), s->W(5));\ + d->W(6) = F(d->W(6), s->W(6));\ + d->W(7) = F(d->W(7), s->W(7));\ + )\ +} + +#define SSE_OP_L(name, F)\ +void OPPROTO glue(name, SUFFIX) (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->L(0) = F(d->L(0), s->L(0));\ + d->L(1) = F(d->L(1), s->L(1));\ + XMM_ONLY(\ + d->L(2) = F(d->L(2), s->L(2));\ + d->L(3) = F(d->L(3), s->L(3));\ + )\ +} + +#define SSE_OP_Q(name, F)\ +void OPPROTO glue(name, SUFFIX) (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->Q(0) = F(d->Q(0), s->Q(0));\ + XMM_ONLY(\ + d->Q(1) = F(d->Q(1), s->Q(1));\ + )\ +} + +#if SHIFT == 0 +static inline int satub(int x) +{ + if (x < 0) + return 0; + else if (x > 255) + return 255; + else + return x; +} + +static inline int satuw(int x) +{ + if (x < 0) + return 0; + else if (x > 65535) + return 65535; + else + return x; +} + +static inline int satsb(int x) +{ + if (x < -128) + return -128; + else if (x > 127) + return 127; + else + return x; +} + +static inline int satsw(int x) +{ + if (x < -32768) + return -32768; + else if (x > 32767) + return 32767; + else + return x; +} + +#define FADD(a, b) ((a) + (b)) +#define FADDUB(a, b) satub((a) + (b)) +#define FADDUW(a, b) satuw((a) + (b)) +#define FADDSB(a, b) satsb((int8_t)(a) + (int8_t)(b)) +#define FADDSW(a, b) satsw((int16_t)(a) + (int16_t)(b)) + +#define FSUB(a, b) ((a) - (b)) +#define FSUBUB(a, b) satub((a) - (b)) +#define FSUBUW(a, b) satuw((a) - (b)) +#define FSUBSB(a, b) satsb((int8_t)(a) - (int8_t)(b)) +#define FSUBSW(a, b) satsw((int16_t)(a) - (int16_t)(b)) +#define FMINUB(a, b) ((a) < (b)) ? (a) : (b) +#define FMINSW(a, b) ((int16_t)(a) < (int16_t)(b)) ? (a) : (b) +#define FMAXUB(a, b) ((a) > (b)) ? (a) : (b) +#define FMAXSW(a, b) ((int16_t)(a) > (int16_t)(b)) ? (a) : (b) + +#define FAND(a, b) (a) & (b) +#define FANDN(a, b) ((~(a)) & (b)) +#define FOR(a, b) (a) | (b) +#define FXOR(a, b) (a) ^ (b) + +#define FCMPGTB(a, b) (int8_t)(a) > (int8_t)(b) ? -1 : 0 +#define FCMPGTW(a, b) (int16_t)(a) > (int16_t)(b) ? -1 : 0 +#define FCMPGTL(a, b) (int32_t)(a) > (int32_t)(b) ? -1 : 0 +#define FCMPEQ(a, b) (a) == (b) ? -1 : 0 + +#define FMULLW(a, b) (a) * (b) +#define FMULHUW(a, b) (a) * (b) >> 16 +#define FMULHW(a, b) (int16_t)(a) * (int16_t)(b) >> 16 + +#define FAVG(a, b) ((a) + (b) + 1) >> 1 +#endif + +SSE_OP_B(op_paddb, FADD) +SSE_OP_W(op_paddw, FADD) +SSE_OP_L(op_paddl, FADD) +SSE_OP_Q(op_paddq, FADD) + +SSE_OP_B(op_psubb, FSUB) +SSE_OP_W(op_psubw, FSUB) +SSE_OP_L(op_psubl, FSUB) +SSE_OP_Q(op_psubq, FSUB) + +SSE_OP_B(op_paddusb, FADDUB) +SSE_OP_B(op_paddsb, FADDSB) +SSE_OP_B(op_psubusb, FSUBUB) +SSE_OP_B(op_psubsb, FSUBSB) + +SSE_OP_W(op_paddusw, FADDUW) +SSE_OP_W(op_paddsw, FADDSW) +SSE_OP_W(op_psubusw, FSUBUW) +SSE_OP_W(op_psubsw, FSUBSW) + +SSE_OP_B(op_pminub, FMINUB) +SSE_OP_B(op_pmaxub, FMAXUB) + +SSE_OP_W(op_pminsw, FMINSW) +SSE_OP_W(op_pmaxsw, FMAXSW) + +SSE_OP_Q(op_pand, FAND) +SSE_OP_Q(op_pandn, FANDN) +SSE_OP_Q(op_por, FOR) +SSE_OP_Q(op_pxor, FXOR) + +SSE_OP_B(op_pcmpgtb, FCMPGTB) +SSE_OP_W(op_pcmpgtw, FCMPGTW) +SSE_OP_L(op_pcmpgtl, FCMPGTL) + +SSE_OP_B(op_pcmpeqb, FCMPEQ) +SSE_OP_W(op_pcmpeqw, FCMPEQ) +SSE_OP_L(op_pcmpeql, FCMPEQ) + +SSE_OP_W(op_pmullw, FMULLW) +SSE_OP_W(op_pmulhuw, FMULHUW) +SSE_OP_W(op_pmulhw, FMULHW) + +SSE_OP_B(op_pavgb, FAVG) +SSE_OP_W(op_pavgw, FAVG) + +void OPPROTO glue(op_pmuludq, SUFFIX) (void) +{ + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + d->Q(0) = (uint64_t)s->L(0) * (uint64_t)d->L(0); +#if SHIFT == 1 + d->Q(1) = (uint64_t)s->L(2) * (uint64_t)d->L(2); +#endif +} + +void OPPROTO glue(op_pmaddwd, SUFFIX) (void) +{ + int i; + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + for(i = 0; i < (2 << SHIFT); i++) { + d->L(i) = (int16_t)s->W(2*i) * (int16_t)d->W(2*i) + + (int16_t)s->W(2*i+1) * (int16_t)d->W(2*i+1); + } +} + +#if SHIFT == 0 +static inline int abs1(int a) +{ + if (a < 0) + return -a; + else + return a; +} +#endif +void OPPROTO glue(op_psadbw, SUFFIX) (void) +{ + unsigned int val; + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + val = 0; + val += abs1(d->B(0) - s->B(0)); + val += abs1(d->B(1) - s->B(1)); + val += abs1(d->B(2) - s->B(2)); + val += abs1(d->B(3) - s->B(3)); + val += abs1(d->B(4) - s->B(4)); + val += abs1(d->B(5) - s->B(5)); + val += abs1(d->B(6) - s->B(6)); + val += abs1(d->B(7) - s->B(7)); + d->Q(0) = val; +#if SHIFT == 1 + val = 0; + val += abs1(d->B(8) - s->B(8)); + val += abs1(d->B(9) - s->B(9)); + val += abs1(d->B(10) - s->B(10)); + val += abs1(d->B(11) - s->B(11)); + val += abs1(d->B(12) - s->B(12)); + val += abs1(d->B(13) - s->B(13)); + val += abs1(d->B(14) - s->B(14)); + val += abs1(d->B(15) - s->B(15)); + d->Q(1) = val; +#endif +} + +void OPPROTO glue(op_maskmov, SUFFIX) (void) +{ + int i; + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + for(i = 0; i < (8 << SHIFT); i++) { + if (s->B(i) & 0x80) + stb(A0, d->B(i)); + } +} + +void OPPROTO glue(op_movl_mm_T0, SUFFIX) (void) +{ + Reg *d; + d = (Reg *)((char *)env + PARAM1); + d->L(0) = T0; + d->L(1) = 0; +#if SHIFT == 1 + d->Q(1) = 0; +#endif +} + +void OPPROTO glue(op_movl_T0_mm, SUFFIX) (void) +{ + Reg *s; + s = (Reg *)((char *)env + PARAM1); + T0 = s->L(0); +} + +#if SHIFT == 0 +void OPPROTO glue(op_pshufw, SUFFIX) (void) +{ + Reg r, *d, *s; + int order; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + order = PARAM3; + r.W(0) = s->W(order & 3); + r.W(1) = s->W((order >> 2) & 3); + r.W(2) = s->W((order >> 4) & 3); + r.W(3) = s->W((order >> 6) & 3); + *d = r; +} +#else +void OPPROTO op_shufpd(void) +{ + Reg r, *d, *s; + int order; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + order = PARAM3; + r.Q(0) = s->Q(order & 1); + r.Q(1) = s->Q((order >> 1) & 1); + *d = r; +} + +void OPPROTO glue(op_pshufd, SUFFIX) (void) +{ + Reg r, *d, *s; + int order; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + order = PARAM3; + r.L(0) = s->L(order & 3); + r.L(1) = s->L((order >> 2) & 3); + r.L(2) = s->L((order >> 4) & 3); + r.L(3) = s->L((order >> 6) & 3); + *d = r; +} + +void OPPROTO glue(op_pshuflw, SUFFIX) (void) +{ + Reg r, *d, *s; + int order; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + order = PARAM3; + r.W(0) = s->W(order & 3); + r.W(1) = s->W((order >> 2) & 3); + r.W(2) = s->W((order >> 4) & 3); + r.W(3) = s->W((order >> 6) & 3); + r.Q(1) = s->Q(1); + *d = r; +} + +void OPPROTO glue(op_pshufhw, SUFFIX) (void) +{ + Reg r, *d, *s; + int order; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + order = PARAM3; + r.Q(0) = s->Q(0); + r.W(4) = s->W(4 + (order & 3)); + r.W(5) = s->W(4 + ((order >> 2) & 3)); + r.W(6) = s->W(4 + ((order >> 4) & 3)); + r.W(7) = s->W(4 + ((order >> 6) & 3)); + *d = r; +} +#endif + +#if SHIFT == 1 +/* FPU ops */ +/* XXX: not accurate */ + +#define SSE_OP_S(name, F)\ +void OPPROTO op_ ## name ## ps (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->XMM_S(0) = F(d->XMM_S(0), s->XMM_S(0));\ + d->XMM_S(1) = F(d->XMM_S(1), s->XMM_S(1));\ + d->XMM_S(2) = F(d->XMM_S(2), s->XMM_S(2));\ + d->XMM_S(3) = F(d->XMM_S(3), s->XMM_S(3));\ +}\ +\ +void OPPROTO op_ ## name ## ss (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->XMM_S(0) = F(d->XMM_S(0), s->XMM_S(0));\ +}\ +void OPPROTO op_ ## name ## pd (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->XMM_D(0) = F(d->XMM_D(0), s->XMM_D(0));\ + d->XMM_D(1) = F(d->XMM_D(1), s->XMM_D(1));\ +}\ +\ +void OPPROTO op_ ## name ## sd (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->XMM_D(0) = F(d->XMM_D(0), s->XMM_D(0));\ +} + +#define FPU_ADD(a, b) (a) + (b) +#define FPU_SUB(a, b) (a) - (b) +#define FPU_MUL(a, b) (a) * (b) +#define FPU_DIV(a, b) (a) / (b) +#define FPU_MIN(a, b) (a) < (b) ? (a) : (b) +#define FPU_MAX(a, b) (a) > (b) ? (a) : (b) +#define FPU_SQRT(a, b) sqrt(b) + +SSE_OP_S(add, FPU_ADD) +SSE_OP_S(sub, FPU_SUB) +SSE_OP_S(mul, FPU_MUL) +SSE_OP_S(div, FPU_DIV) +SSE_OP_S(min, FPU_MIN) +SSE_OP_S(max, FPU_MAX) +SSE_OP_S(sqrt, FPU_SQRT) + + +/* float to float conversions */ +void OPPROTO op_cvtps2pd(void) +{ + float s0, s1; + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + s0 = s->XMM_S(0); + s1 = s->XMM_S(1); + d->XMM_D(0) = s0; + d->XMM_D(1) = s1; +} + +void OPPROTO op_cvtpd2ps(void) +{ + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + d->XMM_S(0) = s->XMM_D(0); + d->XMM_S(1) = s->XMM_D(1); + d->Q(1) = 0; +} + +void OPPROTO op_cvtss2sd(void) +{ + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + d->XMM_D(0) = s->XMM_S(0); +} + +void OPPROTO op_cvtsd2ss(void) +{ + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + d->XMM_S(0) = s->XMM_D(0); +} + +/* integer to float */ +void OPPROTO op_cvtdq2ps(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_S(0) = (int32_t)s->XMM_L(0); + d->XMM_S(1) = (int32_t)s->XMM_L(1); + d->XMM_S(2) = (int32_t)s->XMM_L(2); + d->XMM_S(3) = (int32_t)s->XMM_L(3); +} + +void OPPROTO op_cvtdq2pd(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + int32_t l0, l1; + l0 = (int32_t)s->XMM_L(0); + l1 = (int32_t)s->XMM_L(1); + d->XMM_D(0) = l0; + d->XMM_D(1) = l1; +} + +void OPPROTO op_cvtpi2ps(void) +{ + XMMReg *d = (Reg *)((char *)env + PARAM1); + MMXReg *s = (MMXReg *)((char *)env + PARAM2); + d->XMM_S(0) = (int32_t)s->MMX_L(0); + d->XMM_S(1) = (int32_t)s->MMX_L(1); +} + +void OPPROTO op_cvtpi2pd(void) +{ + XMMReg *d = (Reg *)((char *)env + PARAM1); + MMXReg *s = (MMXReg *)((char *)env + PARAM2); + d->XMM_D(0) = (int32_t)s->MMX_L(0); + d->XMM_D(1) = (int32_t)s->MMX_L(1); +} + +void OPPROTO op_cvtsi2ss(void) +{ + XMMReg *d = (Reg *)((char *)env + PARAM1); + d->XMM_S(0) = (int32_t)T0; +} + +void OPPROTO op_cvtsi2sd(void) +{ + XMMReg *d = (Reg *)((char *)env + PARAM1); + d->XMM_D(0) = (int32_t)T0; +} + +#ifdef TARGET_X86_64 +void OPPROTO op_cvtsq2ss(void) +{ + XMMReg *d = (Reg *)((char *)env + PARAM1); + d->XMM_S(0) = (int64_t)T0; +} + +void OPPROTO op_cvtsq2sd(void) +{ + XMMReg *d = (Reg *)((char *)env + PARAM1); + d->XMM_D(0) = (int64_t)T0; +} +#endif + +/* float to integer */ +void OPPROTO op_cvtps2dq(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_L(0) = lrint(s->XMM_S(0)); + d->XMM_L(1) = lrint(s->XMM_S(1)); + d->XMM_L(2) = lrint(s->XMM_S(2)); + d->XMM_L(3) = lrint(s->XMM_S(3)); +} + +void OPPROTO op_cvtpd2dq(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_L(0) = lrint(s->XMM_D(0)); + d->XMM_L(1) = lrint(s->XMM_D(1)); + d->XMM_Q(1) = 0; +} + +void OPPROTO op_cvtps2pi(void) +{ + MMXReg *d = (MMXReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->MMX_L(0) = lrint(s->XMM_S(0)); + d->MMX_L(1) = lrint(s->XMM_S(1)); +} + +void OPPROTO op_cvtpd2pi(void) +{ + MMXReg *d = (MMXReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->MMX_L(0) = lrint(s->XMM_D(0)); + d->MMX_L(1) = lrint(s->XMM_D(1)); +} + +void OPPROTO op_cvtss2si(void) +{ + XMMReg *s = (XMMReg *)((char *)env + PARAM1); + T0 = (int32_t)lrint(s->XMM_S(0)); +} + +void OPPROTO op_cvtsd2si(void) +{ + XMMReg *s = (XMMReg *)((char *)env + PARAM1); + T0 = (int32_t)lrint(s->XMM_D(0)); +} + +#ifdef TARGET_X86_64 +void OPPROTO op_cvtss2sq(void) +{ + XMMReg *s = (XMMReg *)((char *)env + PARAM1); + T0 = llrint(s->XMM_S(0)); +} + +void OPPROTO op_cvtsd2sq(void) +{ + XMMReg *s = (XMMReg *)((char *)env + PARAM1); + T0 = llrint(s->XMM_D(0)); +} +#endif + +/* float to integer truncated */ +void OPPROTO op_cvttps2dq(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_L(0) = (int32_t)s->XMM_S(0); + d->XMM_L(1) = (int32_t)s->XMM_S(1); + d->XMM_L(2) = (int32_t)s->XMM_S(2); + d->XMM_L(3) = (int32_t)s->XMM_S(3); +} + +void OPPROTO op_cvttpd2dq(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_L(0) = (int32_t)s->XMM_D(0); + d->XMM_L(1) = (int32_t)s->XMM_D(1); + d->XMM_Q(1) = 0; +} + +void OPPROTO op_cvttps2pi(void) +{ + MMXReg *d = (MMXReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->MMX_L(0) = (int32_t)(s->XMM_S(0)); + d->MMX_L(1) = (int32_t)(s->XMM_S(1)); +} + +void OPPROTO op_cvttpd2pi(void) +{ + MMXReg *d = (MMXReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->MMX_L(0) = (int32_t)(s->XMM_D(0)); + d->MMX_L(1) = (int32_t)(s->XMM_D(1)); +} + +void OPPROTO op_cvttss2si(void) +{ + XMMReg *s = (XMMReg *)((char *)env + PARAM1); + T0 = (int32_t)(s->XMM_S(0)); +} + +void OPPROTO op_cvttsd2si(void) +{ + XMMReg *s = (XMMReg *)((char *)env + PARAM1); + T0 = (int32_t)(s->XMM_D(0)); +} + +#ifdef TARGET_X86_64 +void OPPROTO op_cvttss2sq(void) +{ + XMMReg *s = (XMMReg *)((char *)env + PARAM1); + T0 = (int64_t)(s->XMM_S(0)); +} + +void OPPROTO op_cvttsd2sq(void) +{ + XMMReg *s = (XMMReg *)((char *)env + PARAM1); + T0 = (int64_t)(s->XMM_D(0)); +} +#endif + +void OPPROTO op_rsqrtps(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_S(0) = approx_rsqrt(s->XMM_S(0)); + d->XMM_S(1) = approx_rsqrt(s->XMM_S(1)); + d->XMM_S(2) = approx_rsqrt(s->XMM_S(2)); + d->XMM_S(3) = approx_rsqrt(s->XMM_S(3)); +} + +void OPPROTO op_rsqrtss(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_S(0) = approx_rsqrt(s->XMM_S(0)); +} + +void OPPROTO op_rcpps(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_S(0) = approx_rcp(s->XMM_S(0)); + d->XMM_S(1) = approx_rcp(s->XMM_S(1)); + d->XMM_S(2) = approx_rcp(s->XMM_S(2)); + d->XMM_S(3) = approx_rcp(s->XMM_S(3)); +} + +void OPPROTO op_rcpss(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_S(0) = approx_rcp(s->XMM_S(0)); +} + +void OPPROTO op_haddps(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + XMMReg r; + r.XMM_S(0) = d->XMM_S(0) + d->XMM_S(1); + r.XMM_S(1) = d->XMM_S(2) + d->XMM_S(3); + r.XMM_S(2) = s->XMM_S(0) + s->XMM_S(1); + r.XMM_S(3) = s->XMM_S(2) + s->XMM_S(3); + *d = r; +} + +void OPPROTO op_haddpd(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + XMMReg r; + r.XMM_D(0) = d->XMM_D(0) + d->XMM_D(1); + r.XMM_D(1) = s->XMM_D(0) + s->XMM_D(1); + *d = r; +} + +void OPPROTO op_hsubps(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + XMMReg r; + r.XMM_S(0) = d->XMM_S(0) - d->XMM_S(1); + r.XMM_S(1) = d->XMM_S(2) - d->XMM_S(3); + r.XMM_S(2) = s->XMM_S(0) - s->XMM_S(1); + r.XMM_S(3) = s->XMM_S(2) - s->XMM_S(3); + *d = r; +} + +void OPPROTO op_hsubpd(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + XMMReg r; + r.XMM_D(0) = d->XMM_D(0) - d->XMM_D(1); + r.XMM_D(1) = s->XMM_D(0) - s->XMM_D(1); + *d = r; +} + +void OPPROTO op_addsubps(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_S(0) = d->XMM_S(0) - s->XMM_S(0); + d->XMM_S(1) = d->XMM_S(1) + s->XMM_S(1); + d->XMM_S(2) = d->XMM_S(2) - s->XMM_S(2); + d->XMM_S(3) = d->XMM_S(3) + s->XMM_S(3); +} + +void OPPROTO op_addsubpd(void) +{ + XMMReg *d = (XMMReg *)((char *)env + PARAM1); + XMMReg *s = (XMMReg *)((char *)env + PARAM2); + d->XMM_D(0) = d->XMM_D(0) - s->XMM_D(0); + d->XMM_D(1) = d->XMM_D(1) + s->XMM_D(1); +} + +/* XXX: unordered */ +#define SSE_OP_CMP(name, F)\ +void OPPROTO op_ ## name ## ps (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->XMM_L(0) = F(d->XMM_S(0), s->XMM_S(0));\ + d->XMM_L(1) = F(d->XMM_S(1), s->XMM_S(1));\ + d->XMM_L(2) = F(d->XMM_S(2), s->XMM_S(2));\ + d->XMM_L(3) = F(d->XMM_S(3), s->XMM_S(3));\ +}\ +\ +void OPPROTO op_ ## name ## ss (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->XMM_L(0) = F(d->XMM_S(0), s->XMM_S(0));\ +}\ +void OPPROTO op_ ## name ## pd (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->XMM_Q(0) = F(d->XMM_D(0), s->XMM_D(0));\ + d->XMM_Q(1) = F(d->XMM_D(1), s->XMM_D(1));\ +}\ +\ +void OPPROTO op_ ## name ## sd (void)\ +{\ + Reg *d, *s;\ + d = (Reg *)((char *)env + PARAM1);\ + s = (Reg *)((char *)env + PARAM2);\ + d->XMM_Q(0) = F(d->XMM_D(0), s->XMM_D(0));\ +} + +#define FPU_CMPEQ(a, b) (a) == (b) ? -1 : 0 +#define FPU_CMPLT(a, b) (a) < (b) ? -1 : 0 +#define FPU_CMPLE(a, b) (a) <= (b) ? -1 : 0 +#define FPU_CMPUNORD(a, b) (fpu_isnan(a) || fpu_isnan(b)) ? - 1 : 0 +#define FPU_CMPNEQ(a, b) (a) == (b) ? 0 : -1 +#define FPU_CMPNLT(a, b) (a) < (b) ? 0 : -1 +#define FPU_CMPNLE(a, b) (a) <= (b) ? 0 : -1 +#define FPU_CMPORD(a, b) (!fpu_isnan(a) && !fpu_isnan(b)) ? - 1 : 0 + +SSE_OP_CMP(cmpeq, FPU_CMPEQ) +SSE_OP_CMP(cmplt, FPU_CMPLT) +SSE_OP_CMP(cmple, FPU_CMPLE) +SSE_OP_CMP(cmpunord, FPU_CMPUNORD) +SSE_OP_CMP(cmpneq, FPU_CMPNEQ) +SSE_OP_CMP(cmpnlt, FPU_CMPNLT) +SSE_OP_CMP(cmpnle, FPU_CMPNLE) +SSE_OP_CMP(cmpord, FPU_CMPORD) + +void OPPROTO op_ucomiss(void) +{ + int eflags; + float s0, s1; + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + s0 = d->XMM_S(0); + s1 = s->XMM_S(0); + if (s0 < s1) + eflags = CC_C; + else if (s0 == s1) + eflags = CC_Z; + else + eflags = 0; + CC_SRC = eflags; + FORCE_RET(); +} + +void OPPROTO op_comiss(void) +{ + int eflags; + float s0, s1; + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + s0 = d->XMM_S(0); + s1 = s->XMM_S(0); + if (s0 < s1) + eflags = CC_C; + else if (s0 == s1) + eflags = CC_Z; + else + eflags = 0; + CC_SRC = eflags; + FORCE_RET(); +} + +void OPPROTO op_ucomisd(void) +{ + int eflags; + double d0, d1; + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + d0 = d->XMM_D(0); + d1 = s->XMM_D(0); + if (d0 < d1) + eflags = CC_C; + else if (d0 == d1) + eflags = CC_Z; + else + eflags = 0; + CC_SRC = eflags; + FORCE_RET(); +} + +void OPPROTO op_comisd(void) +{ + int eflags; + double d0, d1; + Reg *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + d0 = d->XMM_D(0); + d1 = s->XMM_D(0); + if (d0 < d1) + eflags = CC_C; + else if (d0 == d1) + eflags = CC_Z; + else + eflags = 0; + CC_SRC = eflags; + FORCE_RET(); +} + +void OPPROTO op_movmskps(void) +{ + int b0, b1, b2, b3; + Reg *s; + s = (Reg *)((char *)env + PARAM1); + b0 = s->XMM_L(0) >> 31; + b1 = s->XMM_L(1) >> 31; + b2 = s->XMM_L(2) >> 31; + b3 = s->XMM_L(3) >> 31; + T0 = b0 | (b1 << 1) | (b2 << 2) | (b3 << 3); +} + +void OPPROTO op_movmskpd(void) +{ + int b0, b1; + Reg *s; + s = (Reg *)((char *)env + PARAM1); + b0 = s->XMM_L(1) >> 31; + b1 = s->XMM_L(3) >> 31; + T0 = b0 | (b1 << 1); +} + +#endif + +void OPPROTO glue(op_pmovmskb, SUFFIX)(void) +{ + Reg *s; + s = (Reg *)((char *)env + PARAM1); + T0 = 0; + T0 |= (s->XMM_B(0) >> 7); + T0 |= (s->XMM_B(1) >> 6) & 0x02; + T0 |= (s->XMM_B(2) >> 5) & 0x04; + T0 |= (s->XMM_B(3) >> 4) & 0x08; + T0 |= (s->XMM_B(4) >> 3) & 0x10; + T0 |= (s->XMM_B(5) >> 2) & 0x20; + T0 |= (s->XMM_B(6) >> 1) & 0x40; + T0 |= (s->XMM_B(7)) & 0x80; +#if SHIFT == 1 + T0 |= (s->XMM_B(8) << 1) & 0x0100; + T0 |= (s->XMM_B(9) << 2) & 0x0200; + T0 |= (s->XMM_B(10) << 3) & 0x0400; + T0 |= (s->XMM_B(11) << 4) & 0x0800; + T0 |= (s->XMM_B(12) << 5) & 0x1000; + T0 |= (s->XMM_B(13) << 6) & 0x2000; + T0 |= (s->XMM_B(14) << 7) & 0x4000; + T0 |= (s->XMM_B(15) << 8) & 0x8000; +#endif +} + +void OPPROTO glue(op_pinsrw, SUFFIX) (void) +{ + Reg *d = (Reg *)((char *)env + PARAM1); + int pos = PARAM2; + + d->W(pos) = T0; +} + +void OPPROTO glue(op_pextrw, SUFFIX) (void) +{ + Reg *s = (Reg *)((char *)env + PARAM1); + int pos = PARAM2; + + T0 = s->W(pos); +} + +void OPPROTO glue(op_packsswb, SUFFIX) (void) +{ + Reg r, *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + r.B(0) = satsb((int16_t)d->W(0)); + r.B(1) = satsb((int16_t)d->W(1)); + r.B(2) = satsb((int16_t)d->W(2)); + r.B(3) = satsb((int16_t)d->W(3)); +#if SHIFT == 1 + r.B(4) = satsb((int16_t)d->W(4)); + r.B(5) = satsb((int16_t)d->W(5)); + r.B(6) = satsb((int16_t)d->W(6)); + r.B(7) = satsb((int16_t)d->W(7)); +#endif + r.B((4 << SHIFT) + 0) = satsb((int16_t)s->W(0)); + r.B((4 << SHIFT) + 1) = satsb((int16_t)s->W(1)); + r.B((4 << SHIFT) + 2) = satsb((int16_t)s->W(2)); + r.B((4 << SHIFT) + 3) = satsb((int16_t)s->W(3)); +#if SHIFT == 1 + r.B(12) = satsb((int16_t)s->W(4)); + r.B(13) = satsb((int16_t)s->W(5)); + r.B(14) = satsb((int16_t)s->W(6)); + r.B(15) = satsb((int16_t)s->W(7)); +#endif + *d = r; +} + +void OPPROTO glue(op_packuswb, SUFFIX) (void) +{ + Reg r, *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + r.B(0) = satub((int16_t)d->W(0)); + r.B(1) = satub((int16_t)d->W(1)); + r.B(2) = satub((int16_t)d->W(2)); + r.B(3) = satub((int16_t)d->W(3)); +#if SHIFT == 1 + r.B(4) = satub((int16_t)d->W(4)); + r.B(5) = satub((int16_t)d->W(5)); + r.B(6) = satub((int16_t)d->W(6)); + r.B(7) = satub((int16_t)d->W(7)); +#endif + r.B((4 << SHIFT) + 0) = satub((int16_t)s->W(0)); + r.B((4 << SHIFT) + 1) = satub((int16_t)s->W(1)); + r.B((4 << SHIFT) + 2) = satub((int16_t)s->W(2)); + r.B((4 << SHIFT) + 3) = satub((int16_t)s->W(3)); +#if SHIFT == 1 + r.B(12) = satub((int16_t)s->W(4)); + r.B(13) = satub((int16_t)s->W(5)); + r.B(14) = satub((int16_t)s->W(6)); + r.B(15) = satub((int16_t)s->W(7)); +#endif + *d = r; +} + +void OPPROTO glue(op_packssdw, SUFFIX) (void) +{ + Reg r, *d, *s; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + + r.W(0) = satsw(d->L(0)); + r.W(1) = satsw(d->L(1)); +#if SHIFT == 1 + r.W(2) = satsw(d->L(2)); + r.W(3) = satsw(d->L(3)); +#endif + r.W((2 << SHIFT) + 0) = satsw(s->L(0)); + r.W((2 << SHIFT) + 1) = satsw(s->L(1)); +#if SHIFT == 1 + r.W(6) = satsw(s->L(2)); + r.W(7) = satsw(s->L(3)); +#endif + *d = r; +} + +#define UNPCK_OP(base_name, base) \ + \ +void OPPROTO glue(op_punpck ## base_name ## bw, SUFFIX) (void) \ +{ \ + Reg r, *d, *s; \ + d = (Reg *)((char *)env + PARAM1); \ + s = (Reg *)((char *)env + PARAM2); \ + \ + r.B(0) = d->B((base << (SHIFT + 2)) + 0); \ + r.B(1) = s->B((base << (SHIFT + 2)) + 0); \ + r.B(2) = d->B((base << (SHIFT + 2)) + 1); \ + r.B(3) = s->B((base << (SHIFT + 2)) + 1); \ + r.B(4) = d->B((base << (SHIFT + 2)) + 2); \ + r.B(5) = s->B((base << (SHIFT + 2)) + 2); \ + r.B(6) = d->B((base << (SHIFT + 2)) + 3); \ + r.B(7) = s->B((base << (SHIFT + 2)) + 3); \ +XMM_ONLY( \ + r.B(8) = d->B((base << (SHIFT + 2)) + 4); \ + r.B(9) = s->B((base << (SHIFT + 2)) + 4); \ + r.B(10) = d->B((base << (SHIFT + 2)) + 5); \ + r.B(11) = s->B((base << (SHIFT + 2)) + 5); \ + r.B(12) = d->B((base << (SHIFT + 2)) + 6); \ + r.B(13) = s->B((base << (SHIFT + 2)) + 6); \ + r.B(14) = d->B((base << (SHIFT + 2)) + 7); \ + r.B(15) = s->B((base << (SHIFT + 2)) + 7); \ +) \ + *d = r; \ +} \ + \ +void OPPROTO glue(op_punpck ## base_name ## wd, SUFFIX) (void) \ +{ \ + Reg r, *d, *s; \ + d = (Reg *)((char *)env + PARAM1); \ + s = (Reg *)((char *)env + PARAM2); \ + \ + r.W(0) = d->W((base << (SHIFT + 1)) + 0); \ + r.W(1) = s->W((base << (SHIFT + 1)) + 0); \ + r.W(2) = d->W((base << (SHIFT + 1)) + 1); \ + r.W(3) = s->W((base << (SHIFT + 1)) + 1); \ +XMM_ONLY( \ + r.W(4) = d->W((base << (SHIFT + 1)) + 2); \ + r.W(5) = s->W((base << (SHIFT + 1)) + 2); \ + r.W(6) = d->W((base << (SHIFT + 1)) + 3); \ + r.W(7) = s->W((base << (SHIFT + 1)) + 3); \ +) \ + *d = r; \ +} \ + \ +void OPPROTO glue(op_punpck ## base_name ## dq, SUFFIX) (void) \ +{ \ + Reg r, *d, *s; \ + d = (Reg *)((char *)env + PARAM1); \ + s = (Reg *)((char *)env + PARAM2); \ + \ + r.L(0) = d->L((base << SHIFT) + 0); \ + r.L(1) = s->L((base << SHIFT) + 0); \ +XMM_ONLY( \ + r.L(2) = d->L((base << SHIFT) + 1); \ + r.L(3) = s->L((base << SHIFT) + 1); \ +) \ + *d = r; \ +} \ + \ +XMM_ONLY( \ +void OPPROTO glue(op_punpck ## base_name ## qdq, SUFFIX) (void) \ +{ \ + Reg r, *d, *s; \ + d = (Reg *)((char *)env + PARAM1); \ + s = (Reg *)((char *)env + PARAM2); \ + \ + r.Q(0) = d->Q(base); \ + r.Q(1) = s->Q(base); \ + *d = r; \ +} \ +) + +UNPCK_OP(l, 0) +UNPCK_OP(h, 1) + +#undef SHIFT +#undef XMM_ONLY +#undef Reg +#undef B +#undef W +#undef L +#undef Q +#undef SUFFIX diff --git a/target-i386/translate.c b/target-i386/translate.c index 686c184f1..adcdaed5c 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1606,6 +1606,23 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ *offset_ptr = disp; } +/* used for LEA and MOV AX, mem */ +static void gen_add_A0_ds_seg(DisasContext *s) +{ + int override, must_add_seg; + must_add_seg = s->addseg; + override = R_DS; + if (s->override >= 0) { + override = s->override; + must_add_seg = 1; + } else { + override = R_DS; + } + if (must_add_seg) { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } +} + /* generate modrm memory load or store of 'reg'. TMP0 is used if reg != OR_TMP0 */ static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store) @@ -2193,6 +2210,22 @@ static void gen_movtl_T0_im(target_ulong val) #endif } +static GenOpFunc1 *gen_ldq_env_A0[3] = { + gen_op_ldq_raw_env_A0, +#ifndef CONFIG_USER_ONLY + gen_op_ldq_kernel_env_A0, + gen_op_ldq_user_env_A0, +#endif +}; + +static GenOpFunc1 *gen_stq_env_A0[3] = { + gen_op_stq_raw_env_A0, +#ifndef CONFIG_USER_ONLY + gen_op_stq_kernel_env_A0, + gen_op_stq_user_env_A0, +#endif +}; + static GenOpFunc1 *gen_ldo_env_A0[3] = { gen_op_ldo_raw_env_A0, #ifndef CONFIG_USER_ONLY @@ -2209,6 +2242,693 @@ static GenOpFunc1 *gen_sto_env_A0[3] = { #endif }; +#define SSE_SPECIAL ((GenOpFunc2 *)1) + +#define MMX_OP2(x) { gen_op_ ## x ## _mmx, gen_op_ ## x ## _xmm } +#define SSE_FOP(x) { gen_op_ ## x ## ps, gen_op_ ## x ## pd, \ + gen_op_ ## x ## ss, gen_op_ ## x ## sd, } + +static GenOpFunc2 *sse_op_table1[256][4] = { + /* pure SSE operations */ + [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ + [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ + [0x12] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */ + [0x13] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */ + [0x14] = { gen_op_punpckldq_xmm, gen_op_punpcklqdq_xmm }, + [0x15] = { gen_op_punpckhdq_xmm, gen_op_punpckhqdq_xmm }, + [0x16] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd, movshdup */ + [0x17] = { SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd */ + + [0x28] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */ + [0x29] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */ + [0x2a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtpi2ps, cvtpi2pd, cvtsi2ss, cvtsi2sd */ + [0x2b] = { SSE_SPECIAL, SSE_SPECIAL }, /* movntps, movntpd */ + [0x2c] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */ + [0x2d] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */ + [0x2e] = { gen_op_ucomiss, gen_op_ucomisd }, + [0x2f] = { gen_op_comiss, gen_op_comisd }, + [0x50] = { SSE_SPECIAL, SSE_SPECIAL }, /* movmskps, movmskpd */ + [0x51] = SSE_FOP(sqrt), + [0x52] = { gen_op_rsqrtps, NULL, gen_op_rsqrtss, NULL }, + [0x53] = { gen_op_rcpps, NULL, gen_op_rcpss, NULL }, + [0x54] = { gen_op_pand_xmm, gen_op_pand_xmm }, /* andps, andpd */ + [0x55] = { gen_op_pandn_xmm, gen_op_pandn_xmm }, /* andnps, andnpd */ + [0x56] = { gen_op_por_xmm, gen_op_por_xmm }, /* orps, orpd */ + [0x57] = { gen_op_pxor_xmm, gen_op_pxor_xmm }, /* xorps, xorpd */ + [0x58] = SSE_FOP(add), + [0x59] = SSE_FOP(mul), + [0x5a] = { gen_op_cvtps2pd, gen_op_cvtpd2ps, + gen_op_cvtss2sd, gen_op_cvtsd2ss }, + [0x5b] = { gen_op_cvtdq2ps, gen_op_cvtps2dq, gen_op_cvttps2dq }, + [0x5c] = SSE_FOP(sub), + [0x5d] = SSE_FOP(min), + [0x5e] = SSE_FOP(div), + [0x5f] = SSE_FOP(max), + + [0xc2] = SSE_FOP(cmpeq), + [0xc6] = { (GenOpFunc2 *)gen_op_pshufd_xmm, (GenOpFunc2 *)gen_op_shufpd }, + + /* MMX ops and their SSE extensions */ + [0x60] = MMX_OP2(punpcklbw), + [0x61] = MMX_OP2(punpcklwd), + [0x62] = MMX_OP2(punpckldq), + [0x63] = MMX_OP2(packsswb), + [0x64] = MMX_OP2(pcmpgtb), + [0x65] = MMX_OP2(pcmpgtw), + [0x66] = MMX_OP2(pcmpgtl), + [0x67] = MMX_OP2(packuswb), + [0x68] = MMX_OP2(punpckhbw), + [0x69] = MMX_OP2(punpckhwd), + [0x6a] = MMX_OP2(punpckhdq), + [0x6b] = MMX_OP2(packssdw), + [0x6c] = { NULL, gen_op_punpcklqdq_xmm }, + [0x6d] = { NULL, gen_op_punpckhqdq_xmm }, + [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */ + [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */ + [0x70] = { (GenOpFunc2 *)gen_op_pshufw_mmx, + (GenOpFunc2 *)gen_op_pshufd_xmm, + (GenOpFunc2 *)gen_op_pshufhw_xmm, + (GenOpFunc2 *)gen_op_pshuflw_xmm }, + [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */ + [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */ + [0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */ + [0x74] = MMX_OP2(pcmpeqb), + [0x75] = MMX_OP2(pcmpeqw), + [0x76] = MMX_OP2(pcmpeql), + [0x77] = { SSE_SPECIAL }, /* emms */ + [0x7c] = { NULL, gen_op_haddpd, NULL, gen_op_haddps }, + [0x7d] = { NULL, gen_op_hsubpd, NULL, gen_op_hsubps }, + [0x7e] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movd, movd, , movq */ + [0x7f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, movdqu */ + [0xc4] = { SSE_SPECIAL, SSE_SPECIAL }, /* pinsrw */ + [0xc5] = { SSE_SPECIAL, SSE_SPECIAL }, /* pextrw */ + [0xd0] = { NULL, gen_op_addsubpd, NULL, gen_op_addsubps }, + [0xd1] = MMX_OP2(psrlw), + [0xd2] = MMX_OP2(psrld), + [0xd3] = MMX_OP2(psrlq), + [0xd4] = MMX_OP2(paddq), + [0xd5] = MMX_OP2(pmullw), + [0xd6] = { NULL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, + [0xd7] = { SSE_SPECIAL, SSE_SPECIAL }, /* pmovmskb */ + [0xd8] = MMX_OP2(psubusb), + [0xd9] = MMX_OP2(psubusw), + [0xda] = MMX_OP2(pminub), + [0xdb] = MMX_OP2(pand), + [0xdc] = MMX_OP2(paddusb), + [0xdd] = MMX_OP2(paddusw), + [0xde] = MMX_OP2(pmaxub), + [0xdf] = MMX_OP2(pandn), + [0xe0] = MMX_OP2(pavgb), + [0xe1] = MMX_OP2(psraw), + [0xe2] = MMX_OP2(psrad), + [0xe3] = MMX_OP2(pavgw), + [0xe4] = MMX_OP2(pmulhuw), + [0xe5] = MMX_OP2(pmulhw), + [0xe6] = { NULL, gen_op_cvttpd2dq, gen_op_cvtdq2pd, gen_op_cvtpd2dq }, + [0xe7] = { SSE_SPECIAL , SSE_SPECIAL }, /* movntq, movntq */ + [0xe8] = MMX_OP2(psubsb), + [0xe9] = MMX_OP2(psubsw), + [0xea] = MMX_OP2(pminsw), + [0xeb] = MMX_OP2(por), + [0xec] = MMX_OP2(paddsb), + [0xed] = MMX_OP2(paddsw), + [0xee] = MMX_OP2(pmaxsw), + [0xef] = MMX_OP2(pxor), + [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu (PNI) */ + [0xf1] = MMX_OP2(psllw), + [0xf2] = MMX_OP2(pslld), + [0xf3] = MMX_OP2(psllq), + [0xf4] = MMX_OP2(pmuludq), + [0xf5] = MMX_OP2(pmaddwd), + [0xf6] = MMX_OP2(psadbw), + [0xf7] = MMX_OP2(maskmov), + [0xf8] = MMX_OP2(psubb), + [0xf9] = MMX_OP2(psubw), + [0xfa] = MMX_OP2(psubl), + [0xfb] = MMX_OP2(psubq), + [0xfc] = MMX_OP2(paddb), + [0xfd] = MMX_OP2(paddw), + [0xfe] = MMX_OP2(paddl), +}; + +static GenOpFunc2 *sse_op_table2[3 * 8][2] = { + [0 + 2] = MMX_OP2(psrlw), + [0 + 4] = MMX_OP2(psraw), + [0 + 6] = MMX_OP2(psllw), + [8 + 2] = MMX_OP2(psrld), + [8 + 4] = MMX_OP2(psrad), + [8 + 6] = MMX_OP2(pslld), + [16 + 2] = MMX_OP2(psrlq), + [16 + 3] = { NULL, gen_op_psrldq_xmm }, + [16 + 6] = MMX_OP2(psllq), + [16 + 7] = { NULL, gen_op_pslldq_xmm }, +}; + +static GenOpFunc1 *sse_op_table3[4 * 3] = { + gen_op_cvtsi2ss, + gen_op_cvtsi2sd, + X86_64_ONLY(gen_op_cvtsq2ss), + X86_64_ONLY(gen_op_cvtsq2sd), + + gen_op_cvttss2si, + gen_op_cvttsd2si, + X86_64_ONLY(gen_op_cvttss2sq), + X86_64_ONLY(gen_op_cvttsd2sq), + + gen_op_cvtss2si, + gen_op_cvtsd2si, + X86_64_ONLY(gen_op_cvtss2sq), + X86_64_ONLY(gen_op_cvtsd2sq), +}; + +static GenOpFunc2 *sse_op_table4[8][4] = { + SSE_FOP(cmpeq), + SSE_FOP(cmplt), + SSE_FOP(cmple), + SSE_FOP(cmpunord), + SSE_FOP(cmpneq), + SSE_FOP(cmpnlt), + SSE_FOP(cmpnle), + SSE_FOP(cmpord), +}; + +static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) +{ + int b1, op1_offset, op2_offset, is_xmm, val, ot; + int modrm, mod, rm, reg, reg_addr, offset_addr; + GenOpFunc2 *sse_op2; + GenOpFunc3 *sse_op3; + + b &= 0xff; + if (s->prefix & PREFIX_DATA) + b1 = 1; + else if (s->prefix & PREFIX_REPZ) + b1 = 2; + else if (s->prefix & PREFIX_REPNZ) + b1 = 3; + else + b1 = 0; + sse_op2 = sse_op_table1[b][b1]; + if (!sse_op2) + goto illegal_op; + if (b <= 0x5f || b == 0xc6 || b == 0xc2) { + is_xmm = 1; + } else { + if (b1 == 0) { + /* MMX case */ + is_xmm = 0; + } else { + is_xmm = 1; + } + } + /* simple MMX/SSE operation */ + if (s->flags & HF_TS_MASK) { + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + return; + } + if (s->flags & HF_EM_MASK) { + illegal_op: + gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); + return; + } + if (is_xmm && !(s->flags & HF_OSFXSR_MASK)) + goto illegal_op; + if (b == 0x77) { + /* emms */ + gen_op_emms(); + return; + } + /* prepare MMX state (XXX: optimize by storing fptt and fptags in + the static cpu state) */ + if (!is_xmm) { + gen_op_enter_mmx(); + } + + modrm = ldub_code(s->pc++); + reg = ((modrm >> 3) & 7); + if (is_xmm) + reg |= rex_r; + mod = (modrm >> 6) & 3; + if (sse_op2 == SSE_SPECIAL) { + b |= (b1 << 8); + switch(b) { + case 0x0e7: /* movntq */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx)); + break; + case 0x1e7: /* movntdq */ + case 0x02b: /* movntps */ + case 0x12b: /* movntps */ + case 0x2f0: /* lddqu */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + break; + case 0x6e: /* movd mm, ea */ + gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); + gen_op_movl_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + break; + case 0x16e: /* movd xmm, ea */ + gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); + gen_op_movl_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg])); + break; + case 0x6f: /* movq mm, ea */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx)); + } else { + rm = (modrm & 7); + gen_op_movq(offsetof(CPUX86State,fpregs[reg].mmx), + offsetof(CPUX86State,fpregs[rm].mmx)); + } + break; + case 0x010: /* movups */ + case 0x110: /* movupd */ + case 0x028: /* movaps */ + case 0x128: /* movapd */ + case 0x16f: /* movdqa xmm, ea */ + case 0x26f: /* movdqu xmm, ea */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movo(offsetof(CPUX86State,xmm_regs[reg]), + offsetof(CPUX86State,xmm_regs[rm])); + } + break; + case 0x210: /* movss xmm, ea */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[OT_LONG + s->mem_index](); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); + gen_op_movl_T0_0(); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1))); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3))); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)), + offsetof(CPUX86State,xmm_regs[rm].XMM_L(0))); + } + break; + case 0x310: /* movsd xmm, ea */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_op_movl_T0_0(); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3))); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); + } + break; + case 0x012: /* movlps */ + case 0x112: /* movlpd */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + } else { + /* movhlps */ + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1))); + } + break; + case 0x016: /* movhps */ + case 0x116: /* movhpd */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); + } else { + /* movlhps */ + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); + } + break; + case 0x216: /* movshdup */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)), + offsetof(CPUX86State,xmm_regs[rm].XMM_L(1))); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)), + offsetof(CPUX86State,xmm_regs[rm].XMM_L(3))); + } + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)), + offsetof(CPUX86State,xmm_regs[reg].XMM_L(1))); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)), + offsetof(CPUX86State,xmm_regs[reg].XMM_L(3))); + break; + case 0x7e: /* movd ea, mm */ + gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1); + break; + case 0x17e: /* movd ea, xmm */ + gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg])); + gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1); + break; + case 0x27e: /* movq xmm, ea */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); + } + gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); + break; + case 0x7f: /* movq ea, mm */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx)); + } else { + rm = (modrm & 7); + gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx), + offsetof(CPUX86State,fpregs[reg].mmx)); + } + break; + case 0x011: /* movups */ + case 0x111: /* movupd */ + case 0x029: /* movaps */ + case 0x129: /* movapd */ + case 0x17f: /* movdqa ea, xmm */ + case 0x27f: /* movdqu ea, xmm */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movo(offsetof(CPUX86State,xmm_regs[rm]), + offsetof(CPUX86State,xmm_regs[reg])); + } + break; + case 0x211: /* movss ea, xmm */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_movl_T0_env(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); + gen_op_st_T0_A0[OT_LONG + s->mem_index](); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movl(offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)), + offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); + } + break; + case 0x311: /* movsd ea, xmm */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)), + offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + } + break; + case 0x013: /* movlps */ + case 0x113: /* movlpd */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + } else { + goto illegal_op; + } + break; + case 0x017: /* movhps */ + case 0x117: /* movhpd */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); + } else { + goto illegal_op; + } + break; + case 0x71: /* shift mm, im */ + case 0x72: + case 0x73: + case 0x171: /* shift xmm, im */ + case 0x172: + case 0x173: + val = ldub_code(s->pc++); + if (is_xmm) { + gen_op_movl_T0_im(val); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0))); + gen_op_movl_T0_0(); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(1))); + op1_offset = offsetof(CPUX86State,xmm_t0); + } else { + gen_op_movl_T0_im(val); + gen_op_movl_env_T0(offsetof(CPUX86State,mmx_t0.MMX_L(0))); + gen_op_movl_T0_0(); + gen_op_movl_env_T0(offsetof(CPUX86State,mmx_t0.MMX_L(1))); + op1_offset = offsetof(CPUX86State,mmx_t0); + } + sse_op2 = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1]; + if (!sse_op2) + goto illegal_op; + if (is_xmm) { + rm = (modrm & 7) | REX_B(s); + op2_offset = offsetof(CPUX86State,xmm_regs[rm]); + } else { + rm = (modrm & 7); + op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); + } + sse_op2(op2_offset, op1_offset); + break; + case 0x050: /* movmskps */ + gen_op_movmskps(offsetof(CPUX86State,xmm_regs[reg])); + rm = (modrm & 7) | REX_B(s); + gen_op_mov_reg_T0[OT_LONG][rm](); + break; + case 0x150: /* movmskpd */ + gen_op_movmskpd(offsetof(CPUX86State,xmm_regs[reg])); + rm = (modrm & 7) | REX_B(s); + gen_op_mov_reg_T0[OT_LONG][rm](); + break; + case 0x02a: /* cvtpi2ps */ + case 0x12a: /* cvtpi2pd */ + gen_op_enter_mmx(); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + op2_offset = offsetof(CPUX86State,mmx_t0); + gen_ldq_env_A0[s->mem_index >> 2](op2_offset); + } else { + rm = (modrm & 7); + op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); + } + op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + switch(b >> 8) { + case 0x0: + gen_op_cvtpi2ps(op1_offset, op2_offset); + break; + default: + case 0x1: + gen_op_cvtpi2pd(op1_offset, op2_offset); + break; + } + break; + case 0x22a: /* cvtsi2ss */ + case 0x32a: /* cvtsi2sd */ + ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2)](op1_offset); + break; + case 0x02c: /* cvttps2pi */ + case 0x12c: /* cvttpd2pi */ + case 0x02d: /* cvtps2pi */ + case 0x12d: /* cvtpd2pi */ + gen_op_enter_mmx(); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + op2_offset = offsetof(CPUX86State,xmm_t0); + gen_ldo_env_A0[s->mem_index >> 2](op2_offset); + } else { + rm = (modrm & 7) | REX_B(s); + op2_offset = offsetof(CPUX86State,xmm_regs[rm]); + } + op1_offset = offsetof(CPUX86State,fpregs[reg & 7].mmx); + switch(b) { + case 0x02c: + gen_op_cvttps2pi(op1_offset, op2_offset); + break; + case 0x12c: + gen_op_cvttpd2pi(op1_offset, op2_offset); + break; + case 0x02d: + gen_op_cvtps2pi(op1_offset, op2_offset); + break; + case 0x12d: + gen_op_cvtpd2pi(op1_offset, op2_offset); + break; + } + break; + case 0x22c: /* cvttss2si */ + case 0x32c: /* cvttsd2si */ + case 0x22d: /* cvtss2si */ + case 0x32d: /* cvtsd2si */ + ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; + op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 + + (b & 1) * 4](op1_offset); + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 0xc4: /* pinsrw */ + case 0x1c4: + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + val = ldub_code(s->pc++); + if (b1) { + val &= 7; + gen_op_pinsrw_xmm(offsetof(CPUX86State,xmm_regs[reg]), val); + } else { + val &= 3; + gen_op_pinsrw_mmx(offsetof(CPUX86State,fpregs[reg].mmx), val); + } + break; + case 0xc5: /* pextrw */ + case 0x1c5: + if (mod != 3) + goto illegal_op; + val = ldub_code(s->pc++); + if (b1) { + val &= 7; + rm = (modrm & 7) | REX_B(s); + gen_op_pextrw_xmm(offsetof(CPUX86State,xmm_regs[rm]), val); + } else { + val &= 3; + rm = (modrm & 7); + gen_op_pextrw_mmx(offsetof(CPUX86State,fpregs[rm].mmx), val); + } + reg = ((modrm >> 3) & 7) | rex_r; + gen_op_mov_reg_T0[OT_LONG][reg](); + break; + case 0x1d6: /* movq ea, xmm */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)), + offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1))); + } + break; + case 0x2d6: /* movq2dq */ + gen_op_enter_mmx(); + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)), + offsetof(CPUX86State,fpregs[reg & 7].mmx)); + gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1))); + break; + case 0x3d6: /* movdq2q */ + gen_op_enter_mmx(); + rm = (modrm & 7); + gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx), + offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + break; + case 0xd7: /* pmovmskb */ + case 0x1d7: + if (mod != 3) + goto illegal_op; + if (b1) { + rm = (modrm & 7) | REX_B(s); + gen_op_pmovmskb_xmm(offsetof(CPUX86State,xmm_regs[rm])); + } else { + rm = (modrm & 7); + gen_op_pmovmskb_mmx(offsetof(CPUX86State,fpregs[rm].mmx)); + } + reg = ((modrm >> 3) & 7) | rex_r; + gen_op_mov_reg_T0[OT_LONG][reg](); + break; + default: + goto illegal_op; + } + } else { + /* generic MMX or SSE operation */ + if (b == 0xf7) { + /* maskmov : we must prepare A0 */ + if (mod != 3) + goto illegal_op; +#ifdef TARGET_X86_64 + if (CODE64(s)) { + gen_op_movq_A0_reg[R_EDI](); + } else +#endif + { + gen_op_movl_A0_reg[R_EDI](); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + } + gen_add_A0_ds_seg(s); + } + if (is_xmm) { + op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + op2_offset = offsetof(CPUX86State,xmm_t0); + if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f) || + b == 0xc2)) { + /* specific case for SSE single instructions */ + if (b1 == 2) { + /* 32 bit access */ + gen_op_ld_T0_A0[OT_LONG + s->mem_index](); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0))); + } else { + /* 64 bit access */ + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_t0.XMM_D(0))); + } + } else { + gen_ldo_env_A0[s->mem_index >> 2](op2_offset); + } + } else { + rm = (modrm & 7) | REX_B(s); + op2_offset = offsetof(CPUX86State,xmm_regs[rm]); + } + } else { + op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + op2_offset = offsetof(CPUX86State,mmx_t0); + gen_ldq_env_A0[s->mem_index >> 2](op2_offset); + } else { + rm = (modrm & 7); + op2_offset = offsetof(CPUX86State,fpregs[rm].mmx); + } + } + switch(b) { + case 0x70: /* pshufx insn */ + case 0xc6: /* pshufx insn */ + val = ldub_code(s->pc++); + sse_op3 = (GenOpFunc3 *)sse_op2; + sse_op3(op1_offset, op2_offset, val); + break; + case 0xc2: + /* compare insns */ + val = ldub_code(s->pc++); + if (val >= 8) + goto illegal_op; + sse_op2 = sse_op_table4[val][b1]; + sse_op2(op1_offset, op2_offset); + break; + default: + sse_op2(op1_offset, op2_offset); + break; + } + if (b == 0x2e || b == 0x2f) { + s->cc_op = CC_OP_EFLAGS; + } + } +} + + /* convert one instruction. s->is_jmp is set if the translation must be stopped. Return the next pc value */ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) @@ -3176,20 +3896,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } gen_op_movl_A0_im(offset_addr); } - /* handle override */ - { - int override, must_add_seg; - must_add_seg = s->addseg; - if (s->override >= 0) { - override = s->override; - must_add_seg = 1; - } else { - override = R_DS; - } - if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); - } - } + gen_add_A0_ds_seg(s); if ((b & 2) == 0) { gen_op_ld_T0_A0[ot + s->mem_index](); gen_op_mov_reg_T0[ot][R_EAX](); @@ -3212,21 +3919,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->aflag == 0) gen_op_andl_A0_ffff(); } - /* handle override */ - { - int override, must_add_seg; - must_add_seg = s->addseg; - override = R_DS; - if (s->override >= 0) { - override = s->override; - must_add_seg = 1; - } else { - override = R_DS; - } - if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); - } - } + gen_add_A0_ds_seg(s); gen_op_ldu_T0_A0[OT_BYTE + s->mem_index](); gen_op_mov_reg_T0[OT_BYTE][R_EAX](); break; @@ -4827,33 +5520,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /* nothing to do */ } break; - case 0x1ae: - modrm = ldub_code(s->pc++); - mod = (modrm >> 6) & 3; - op = (modrm >> 3) & 7; - switch(op) { - case 0: /* fxsave */ - if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) - goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_fxsave_A0((s->dflag == 2)); - break; - case 1: /* fxrstor */ - if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) - goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_op_fxrstor_A0((s->dflag == 2)); - break; - case 5: /* lfence */ - case 6: /* mfence */ - case 7: /* sfence */ - if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE)) - goto illegal_op; - break; - default: - goto illegal_op; - } - break; case 0x63: /* arpl or movslS (x86_64) */ #ifdef TARGET_X86_64 if (CODE64(s)) { @@ -5018,65 +5684,73 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_eob(s); } break; - /* SSE support */ - case 0x16f: - if (prefixes & PREFIX_DATA) { - /* movdqa xmm1, xmm2/mem128 */ - if (!(s->cpuid_features & CPUID_SSE)) - goto illegal_op; - modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - mod = (modrm >> 6) & 3; - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_movo(offsetof(CPUX86State,xmm_regs[reg]), - offsetof(CPUX86State,xmm_regs[rm])); - } - } else { + /* MMX/SSE/SSE2/PNI support */ + case 0x1c3: /* MOVNTI reg, mem */ + if (!(s->cpuid_features & CPUID_SSE2)) goto illegal_op; - } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + reg = ((modrm >> 3) & 7) | rex_r; + /* generate a generic store */ + gen_ldst_modrm(s, modrm, ot, reg, 1); break; - case 0x1e7: - if (prefixes & PREFIX_DATA) { - /* movntdq mem128, xmm1 */ - if (!(s->cpuid_features & CPUID_SSE)) + case 0x1ae: + modrm = ldub_code(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* fxsave */ + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) goto illegal_op; - modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - mod = (modrm >> 6) & 3; - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); - } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_fxsave_A0((s->dflag == 2)); + break; + case 1: /* fxrstor */ + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_fxrstor_A0((s->dflag == 2)); + break; + case 2: /* ldmxcsr */ + case 3: /* stmxcsr */ + if (s->flags & HF_TS_MASK) { + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + break; } - } else { - goto illegal_op; - } - break; - case 0x17f: - if (prefixes & PREFIX_DATA) { - /* movdqa xmm2/mem128, xmm1 */ - if (!(s->cpuid_features & CPUID_SSE)) + if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK) || + mod == 3) goto illegal_op; - modrm = ldub_code(s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - mod = (modrm >> 6) & 3; - if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (op == 2) { + gen_op_ld_T0_A0[OT_LONG + s->mem_index](); + gen_op_movl_env_T0(offsetof(CPUX86State, mxcsr)); } else { - rm = (modrm & 7) | REX_B(s); - gen_op_movo(offsetof(CPUX86State,xmm_regs[rm]), - offsetof(CPUX86State,xmm_regs[reg])); + gen_op_movl_T0_env(offsetof(CPUX86State, mxcsr)); + gen_op_st_T0_A0[OT_LONG + s->mem_index](); } - } else { + break; + case 5: /* lfence */ + case 6: /* mfence */ + case 7: /* sfence */ + if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE)) + goto illegal_op; + break; + default: goto illegal_op; } break; + case 0x110 ... 0x117: + case 0x128 ... 0x12f: + case 0x150 ... 0x177: + case 0x17c ... 0x17f: + case 0x1c2: + case 0x1c4 ... 0x1c6: + case 0x1d0 ... 0x1fe: + gen_sse(s, b, pc_start, rex_r); + break; default: goto illegal_op; } @@ -5250,6 +5924,12 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_imull_T0_T1] = CC_OSZAPC, X86_64_DEF([INDEX_op_imulq_T0_T1] = CC_OSZAPC,) + /* sse */ + [INDEX_op_ucomiss] = CC_OSZAPC, + [INDEX_op_ucomisd] = CC_OSZAPC, + [INDEX_op_comiss] = CC_OSZAPC, + [INDEX_op_comisd] = CC_OSZAPC, + /* bcd */ [INDEX_op_aam] = CC_OSZAPC, [INDEX_op_aad] = CC_OSZAPC, diff --git a/vl.c b/vl.c index 7a4762489..fe873bac8 100644 --- a/vl.c +++ b/vl.c @@ -2082,15 +2082,14 @@ static void cpu_get_seg(QEMUFile *f, SegmentCache *dt) void cpu_save(QEMUFile *f, void *opaque) { CPUState *env = opaque; - uint16_t fptag, fpus, fpuc; + uint16_t fptag, fpus, fpuc, fpregs_format; uint32_t hflags; int i; - + for(i = 0; i < CPU_NB_REGS; i++) qemu_put_betls(f, &env->regs[i]); qemu_put_betls(f, &env->eip); qemu_put_betls(f, &env->eflags); - qemu_put_betl(f, 0); /* XXX: suppress that */ hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ qemu_put_be32s(f, &hflags); @@ -2098,23 +2097,37 @@ void cpu_save(QEMUFile *f, void *opaque) fpuc = env->fpuc; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; fptag = 0; - for (i=7; i>=0; i--) { - fptag <<= 2; - if (env->fptags[i]) { - fptag |= 3; - } + for(i = 0; i < 8; i++) { + fptag |= ((!env->fptags[i]) << i); } qemu_put_be16s(f, &fpuc); qemu_put_be16s(f, &fpus); qemu_put_be16s(f, &fptag); +#ifdef USE_X86LDOUBLE + fpregs_format = 0; +#else + fpregs_format = 1; +#endif + qemu_put_be16s(f, &fpregs_format); + for(i = 0; i < 8; i++) { uint64_t mant; uint16_t exp; - cpu_get_fp80(&mant, &exp, env->fpregs[i]); +#ifdef USE_X86LDOUBLE + /* we save the real CPU data (in case of MMX usage only 'mant' + contains the MMX register */ + cpu_get_fp80(&mant, &exp, env->fpregs[i].d); qemu_put_be64(f, mant); qemu_put_be16(f, exp); +#else + /* if we use doubles for float emulation, we save the doubles to + avoid losing information in case of MMX usage. It can give + problems if the image is restored on a CPU where long + doubles are used instead. */ + qemu_put_be64(f, env->fpregs[i].xmm.MMX_Q(0)); +#endif } for(i = 0; i < 6; i++) @@ -2139,12 +2152,14 @@ void cpu_save(QEMUFile *f, void *opaque) /* MMU */ qemu_put_be32s(f, &env->a20_mask); -#ifdef TARGET_X86_64 + /* XMM */ + qemu_put_be32s(f, &env->mxcsr); for(i = 0; i < CPU_NB_REGS; i++) { qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0)); qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1)); } +#ifdef TARGET_X86_64 qemu_put_be64s(f, &env->efer); qemu_put_be64s(f, &env->star); qemu_put_be64s(f, &env->lstar); @@ -2154,40 +2169,97 @@ void cpu_save(QEMUFile *f, void *opaque) #endif } +/* XXX: add that in a FPU generic layer */ +union x86_longdouble { + uint64_t mant; + uint16_t exp; +}; + +#define MANTD1(fp) (fp & ((1LL << 52) - 1)) +#define EXPBIAS1 1023 +#define EXPD1(fp) ((fp >> 52) & 0x7FF) +#define SIGND1(fp) ((fp >> 32) & 0x80000000) + +static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) +{ + int e; + /* mantissa */ + p->mant = (MANTD1(temp) << 11) | (1LL << 63); + /* exponent + sign */ + e = EXPD1(temp) - EXPBIAS1 + 16383; + e |= SIGND1(temp) >> 16; + p->exp = e; +} + int cpu_load(QEMUFile *f, void *opaque, int version_id) { CPUState *env = opaque; - int i; + int i, guess_mmx; uint32_t hflags; - uint16_t fpus, fpuc, fptag; + uint16_t fpus, fpuc, fptag, fpregs_format; - if (version_id != 2) + if (version_id != 3) return -EINVAL; for(i = 0; i < CPU_NB_REGS; i++) qemu_get_betls(f, &env->regs[i]); qemu_get_betls(f, &env->eip); qemu_get_betls(f, &env->eflags); - qemu_get_betl(f); /* XXX: suppress that */ qemu_get_be32s(f, &hflags); qemu_get_be16s(f, &fpuc); qemu_get_be16s(f, &fpus); qemu_get_be16s(f, &fptag); - + qemu_get_be16s(f, &fpregs_format); + + /* NOTE: we cannot always restore the FPU state if the image come + from a host with a different 'USE_X86LDOUBLE' define. We guess + if we are in an MMX state to restore correctly in that case. */ + guess_mmx = ((fptag == 0xff) && (fpus & 0x3800) == 0); for(i = 0; i < 8; i++) { uint64_t mant; uint16_t exp; - mant = qemu_get_be64(f); - exp = qemu_get_be16(f); - env->fpregs[i] = cpu_set_fp80(mant, exp); + union x86_longdouble *p; + + switch(fpregs_format) { + case 0: + mant = qemu_get_be64(f); + exp = qemu_get_be16(f); +#ifdef USE_X86LDOUBLE + env->fpregs[i].d = cpu_set_fp80(mant, exp); +#else + /* difficult case */ + if (guess_mmx) + env->fpregs[i].xmm.MMX_Q(0) = mant; + else + env->fpregs[i].d = cpu_set_fp80(mant, exp); +#endif + break; + case 1: + mant = qemu_get_be64(f); +#ifdef USE_X86LDOUBLE + /* difficult case */ + p = (void *)&env->fpregs[i]; + if (guess_mmx) { + p->mant = mant; + p->exp = 0xffff; + } else { + fp64_to_fp80(p, mant); + } +#else + env->fpregs[i].xmm.MMX_Q(0) = mant; +#endif + break; + default: + return -EINVAL; + } } env->fpuc = fpuc; env->fpstt = (fpus >> 11) & 7; env->fpus = fpus & ~0x3800; + fptag ^= 0xff; for(i = 0; i < 8; i++) { - env->fptags[i] = ((fptag & 3) == 3); - fptag >>= 2; + env->fptags[i] = (fptag >> i) & 1; } for(i = 0; i < 6; i++) @@ -2212,12 +2284,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) /* MMU */ qemu_get_be32s(f, &env->a20_mask); -#ifdef TARGET_X86_64 + qemu_get_be32s(f, &env->mxcsr); for(i = 0; i < CPU_NB_REGS; i++) { qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0)); qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1)); } +#ifdef TARGET_X86_64 qemu_get_be64s(f, &env->efer); qemu_get_be64s(f, &env->star); qemu_get_be64s(f, &env->lstar); @@ -3433,7 +3506,7 @@ int main(int argc, char **argv) cpu_single_env = env; register_savevm("timer", 0, 1, timer_save, timer_load, env); - register_savevm("cpu", 0, 2, cpu_save, cpu_load, env); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); register_savevm("ram", 0, 1, ram_save, ram_load, NULL); qemu_register_reset(main_cpu_reset, global_env); -- cgit v1.2.3 From 8636b5d873d6fa5696385da80ddd5f03e1a5de4c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 9 Jan 2005 00:03:14 +0000 Subject: compilation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1206 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/vl.c b/vl.c index fe873bac8..f478f9b23 100644 --- a/vl.c +++ b/vl.c @@ -2113,20 +2113,22 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be16s(f, &fpregs_format); for(i = 0; i < 8; i++) { - uint64_t mant; - uint16_t exp; #ifdef USE_X86LDOUBLE - /* we save the real CPU data (in case of MMX usage only 'mant' - contains the MMX register */ - cpu_get_fp80(&mant, &exp, env->fpregs[i].d); - qemu_put_be64(f, mant); - qemu_put_be16(f, exp); + { + uint64_t mant; + uint16_t exp; + /* we save the real CPU data (in case of MMX usage only 'mant' + contains the MMX register */ + cpu_get_fp80(&mant, &exp, env->fpregs[i].d); + qemu_put_be64(f, mant); + qemu_put_be16(f, exp); + } #else /* if we use doubles for float emulation, we save the doubles to avoid losing information in case of MMX usage. It can give problems if the image is restored on a CPU where long doubles are used instead. */ - qemu_put_be64(f, env->fpregs[i].xmm.MMX_Q(0)); + qemu_put_be64(f, env->fpregs[i].mmx.MMX_Q(0)); #endif } @@ -2169,6 +2171,7 @@ void cpu_save(QEMUFile *f, void *opaque) #endif } +#ifdef USE_X86LDOUBLE /* XXX: add that in a FPU generic layer */ union x86_longdouble { uint64_t mant; @@ -2190,6 +2193,7 @@ static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) e |= SIGND1(temp) >> 16; p->exp = e; } +#endif int cpu_load(QEMUFile *f, void *opaque, int version_id) { @@ -2218,7 +2222,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) for(i = 0; i < 8; i++) { uint64_t mant; uint16_t exp; - union x86_longdouble *p; switch(fpregs_format) { case 0: @@ -2229,7 +2232,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) #else /* difficult case */ if (guess_mmx) - env->fpregs[i].xmm.MMX_Q(0) = mant; + env->fpregs[i].mmx.MMX_Q(0) = mant; else env->fpregs[i].d = cpu_set_fp80(mant, exp); #endif @@ -2237,16 +2240,19 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) case 1: mant = qemu_get_be64(f); #ifdef USE_X86LDOUBLE - /* difficult case */ - p = (void *)&env->fpregs[i]; - if (guess_mmx) { - p->mant = mant; - p->exp = 0xffff; - } else { - fp64_to_fp80(p, mant); + { + union x86_longdouble *p; + /* difficult case */ + p = (void *)&env->fpregs[i]; + if (guess_mmx) { + p->mant = mant; + p->exp = 0xffff; + } else { + fp64_to_fp80(p, mant); + } } #else - env->fpregs[i].xmm.MMX_Q(0) = mant; + env->fpregs[i].mmx.MMX_Q(0) = mant; #endif break; default: -- cgit v1.2.3 From ae063a68dc39f2ee1c87ea2a41c468ba7256acbb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 9 Jan 2005 00:07:04 +0000 Subject: generalized use of GOTO_TB() macro git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1207 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 54 +++++++++++++------------------------------------ target-i386/op.c | 4 ++-- target-i386/translate.c | 14 +++++++++---- 3 files changed, 26 insertions(+), 46 deletions(-) diff --git a/exec-all.h b/exec-all.h index a9522b692..66d4f887d 100644 --- a/exec-all.h +++ b/exec-all.h @@ -322,7 +322,7 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); #if defined(__powerpc__) /* we patch the jump instruction directly */ -#define JUMP_TB(opname, tbparam, n, eip)\ +#define GOTO_TB(opname, tbparam, n)\ do {\ asm volatile (ASM_DATA_SECTION\ ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\ @@ -330,20 +330,12 @@ do {\ ASM_PREVIOUS_SECTION \ "b " ASM_NAME(__op_jmp) #n "\n"\ "1:\n");\ - T0 = (long)(tbparam) + (n);\ - EIP = (int32_t)eip;\ - EXIT_TB();\ -} while (0) - -#define JUMP_TB2(opname, tbparam, n)\ -do {\ - asm volatile ("b " ASM_NAME(__op_jmp) #n "\n");\ } while (0) #elif defined(__i386__) && defined(USE_DIRECT_JUMP) /* we patch the jump instruction directly */ -#define GOTO_TB(opname, n)\ +#define GOTO_TB(opname, tbparam, n)\ do {\ asm volatile (".section .data\n"\ ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\ @@ -353,48 +345,30 @@ do {\ "1:\n");\ } while (0) -#define JUMP_TB(opname, tbparam, n, eip)\ -do {\ - asm volatile (".section .data\n"\ - ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\ - ".long 1f\n"\ - ASM_PREVIOUS_SECTION \ - "jmp " ASM_NAME(__op_jmp) #n "\n"\ - "1:\n");\ - T0 = (long)(tbparam) + (n);\ - EIP = (int32_t)eip;\ - EXIT_TB();\ -} while (0) - -#define JUMP_TB2(opname, tbparam, n)\ -do {\ - asm volatile ("jmp " ASM_NAME(__op_jmp) #n "\n");\ -} while (0) - #else /* jump to next block operations (more portable code, does not need cache flushing, but slower because of indirect jump) */ -#define JUMP_TB(opname, tbparam, n, eip)\ +#define GOTO_TB(opname, tbparam, n)\ do {\ - static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\ + static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ -label ## n:\ - T0 = (long)(tbparam) + (n);\ - EIP = (int32_t)eip;\ -dummy_label ## n:\ - EXIT_TB();\ +label ## n: ;\ +dummy_label ## n: ;\ } while (0) -/* second jump to same destination 'n' */ -#define JUMP_TB2(opname, tbparam, n)\ +#endif + +/* XXX: will be suppressed */ +#define JUMP_TB(opname, tbparam, n, eip)\ do {\ - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\ + GOTO_TB(opname, tbparam, n);\ + T0 = (long)(tbparam) + (n);\ + EIP = (int32_t)eip;\ + EXIT_TB();\ } while (0) -#endif - extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; diff --git a/target-i386/op.c b/target-i386/op.c index 10098256d..ab7501e93 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1262,12 +1262,12 @@ void OPPROTO op_clts(void) void OPPROTO op_goto_tb0(void) { - GOTO_TB(op_goto_tb0, 0); + GOTO_TB(op_goto_tb0, PARAM1, 0); } void OPPROTO op_goto_tb1(void) { - GOTO_TB(op_goto_tb1, 1); + GOTO_TB(op_goto_tb1, PARAM1, 1); } void OPPROTO op_jmp_label(void) diff --git a/target-i386/translate.c b/target-i386/translate.c index adcdaed5c..bd141ffeb 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -61,6 +61,12 @@ static uint32_t *gen_opparam_ptr; static int x86_64_hregs; #endif +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) (long)(x) +#endif + typedef struct DisasContext { /* current insn context */ int override; /* -1 if no override */ @@ -1782,13 +1788,13 @@ static inline void gen_jcc(DisasContext *s, int b, l1 = gen_new_label(); func(l1); - gen_op_goto_tb0(); + gen_op_goto_tb0(TBPARAM(tb)); gen_jmp_im(next_eip); gen_op_movl_T0_im((long)tb + 0); gen_op_exit_tb(); gen_set_label(l1); - gen_op_goto_tb1(); + gen_op_goto_tb1(TBPARAM(tb)); gen_jmp_im(val); gen_op_movl_T0_im((long)tb + 1); gen_op_exit_tb(); @@ -2179,9 +2185,9 @@ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); if (tb_num) - gen_op_goto_tb1(); + gen_op_goto_tb1(TBPARAM(tb)); else - gen_op_goto_tb0(); + gen_op_goto_tb0(TBPARAM(tb)); gen_jmp_im(eip); gen_op_movl_T0_im((long)tb + tb_num); gen_op_exit_tb(); -- cgit v1.2.3 From 9df8aa4abb62ae36404acc46286c3706e05d086f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 9 Jan 2005 00:39:12 +0000 Subject: win32 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1208 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 62bcbf33b..2bf692230 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -209,16 +209,22 @@ extern int __op_param1, __op_param2, __op_param3; extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; +#if defined(_WIN32) +#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 __op_gen_label" #n) +#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n) #endif #ifdef __x86_64__ #define EXIT_TB() asm volatile ("ret") #endif #ifdef __powerpc__ #define EXIT_TB() asm volatile ("blr") -#define GOTO_LABEL_PARAM(n) asm volatile ("b __op_gen_label" #n) +#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n) #endif #ifdef __s390__ #define EXIT_TB() asm volatile ("br %r14") -- cgit v1.2.3 From e995898b0608b46cb0310f60841436169cd0698f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 9 Jan 2005 00:42:09 +0000 Subject: removed trace git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1209 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 9907f8e0b..5255e960d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2807,7 +2807,6 @@ void helper_fstenv(target_ulong ptr, int data32) tmp.d = env->fpregs[i].d; exp = EXPD(tmp); mant = MANTD(tmp); - printf("mant=%llx exp=%x\n", mant, exp); if (exp == 0 && mant == 0) { /* zero */ fptag |= 1; -- cgit v1.2.3 From 5327cf489fcaefd0b64dbd13e6b26e91054a701c Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jan 2005 23:18:50 +0000 Subject: better target_list logic git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1210 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 9f7ba2b51..fa64f6d48 100755 --- a/configure +++ b/configure @@ -27,7 +27,7 @@ ar="ar" make="make" strip="strip" cpu=`uname -m` -target_list="i386-user i386 i386-softmmu arm-user armeb-user sparc-user ppc-user ppc-softmmu sparc-softmmu x86_64-softmmu" +target_list="" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" @@ -80,6 +80,7 @@ oss="no" fmod="no" fmod_lib="" fmod_inc="" +linux="no" # OS specific targetos=`uname -s` @@ -105,6 +106,7 @@ darwin="yes" ;; *) oss="yes" +linux="yes" ;; esac @@ -112,7 +114,6 @@ if [ "$bsd" = "yes" ] ; then if [ ! "$darwin" = "yes" ] ; then make="gmake" fi - target_list="i386-softmmu ppc-softmmu sparc-softmmu" fi # find source path @@ -181,12 +182,21 @@ ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" if test "$mingw32" = "yes" ; then - target_list="i386-softmmu ppc-softmmu sparc-softmmu" + linux="no" EXESUF=".exe" gdbstub="no" oss="no" fi +if test -z "$target_list" ; then +# these targets are portable + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu" +# the following are Linux specific + if [ "$linux" = "yes" ] ; then + target_list="i386-user i386 arm-user armeb-user sparc-user ppc-user $target_list" + fi +fi + if test -z "$cross_prefix" ; then # --- -- cgit v1.2.3 From 8adbc566c9f2924c97a0953682ceb6ab57b78b47 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jan 2005 23:19:18 +0000 Subject: typo git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1211 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/openpic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/openpic.c b/hw/openpic.c index d193cfe6f..ad9db7b36 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -629,7 +629,7 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) break; case 0x10: /* TIBC */ if ((opp->timers[idx].ticc & 0x80000000) != 0 && - (val & 0x800000000) == 0 && + (val & 0x80000000) == 0 && (opp->timers[idx].tibc & 0x80000000) != 0) opp->timers[idx].ticc &= ~0x80000000; opp->timers[idx].tibc = val; -- cgit v1.2.3 From 34444131adc4c88905986b2343b34fb482b9803a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jan 2005 23:19:34 +0000 Subject: windows header fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1212 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/slirp/slirp.h b/slirp/slirp.h index 1bb189d4b..1ff68cb0b 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -20,6 +20,7 @@ typedef uint32_t u_int32_t; typedef uint64_t u_int64_t; typedef char *caddr_t; +# include # include # include # include -- cgit v1.2.3 From 977d5710e6f9628402ea28b70a4ea36eec7fea3e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jan 2005 23:20:04 +0000 Subject: DATA_MASK fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1213 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_template.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 044968a2c..35d5b5412 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -46,7 +46,7 @@ #define SUFFIX q #define DATA_TYPE uint64_t #define DATA_STYPE int64_t -#define DATA_MASK 0xffffffffffffffff +#define DATA_MASK 0xffffffffffffffffULL #else #error unhandled operand size #endif -- cgit v1.2.3 From 7c2e623559a76dbc7e7c8b8497928f3a21dab45f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jan 2005 23:20:21 +0000 Subject: removed debug code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1214 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index bd141ffeb..e548387eb 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5155,12 +5155,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_into(s->pc - pc_start); break; case 0xf1: /* icebp (undocumented, exits to external debugger) */ -#if 0 gen_debug(s, pc_start - s->cs_base); -#else - /* test ! */ - cpu_set_log(CPU_LOG_TB_IN_ASM | CPU_LOG_PCALL); -#endif break; case 0xfa: /* cli */ if (!s->vm86) { -- cgit v1.2.3 From 839fa98885a432aaa4b34a270eda25c7c08522bf Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jan 2005 23:23:48 +0000 Subject: moved ASM_NAME git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1215 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/exec-all.h b/exec-all.h index 66d4f887d..0079b6494 100644 --- a/exec-all.h +++ b/exec-all.h @@ -312,11 +312,9 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); #elif defined(__APPLE__) #define ASM_DATA_SECTION ".data\n" #define ASM_PREVIOUS_SECTION ".text\n" -#define ASM_NAME(x) "_" #x #else #define ASM_DATA_SECTION ".section \".data\"\n" #define ASM_PREVIOUS_SECTION ".previous\n" -#define ASM_NAME(x) stringify(x) #endif #if defined(__powerpc__) -- cgit v1.2.3 From a4682cc20a68c59939552492590559e94b00a984 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Jan 2005 22:33:30 +0000 Subject: fxsr test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1216 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index ea756ec29..b2ef1d8fe 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1872,6 +1872,67 @@ void test_sse_comi(double a1, double b1) r.l[0]);\ } +struct fpxstate { + uint16_t fpuc; + uint16_t fpus; + uint16_t fptag; + uint16_t fop; + uint32_t fpuip; + uint16_t cs_sel; + uint16_t dummy0; + uint32_t fpudp; + uint16_t ds_sel; + uint16_t dummy1; + uint32_t mxcsr; + uint32_t mxcsr_mask; + uint8_t fpregs1[8 * 16]; + uint8_t xmm_regs[8 * 16]; + uint8_t dummy2[224]; +}; + +static struct fpxstate fpx_state __attribute__((aligned(16))); +static struct fpxstate fpx_state2 __attribute__((aligned(16))); + +void test_fxsave(void) +{ + struct fpxstate *fp = &fpx_state; + struct fpxstate *fp2 = &fpx_state2; + int i; + XMMReg a, b; + a.q[0] = test_values[0][0]; + a.q[1] = test_values[0][1]; + b.q[0] = test_values[1][0]; + b.q[1] = test_values[1][1]; + + asm("movdqa %2, %%xmm0\n" + "movdqa %3, %%xmm7\n" + " fld1\n" + " fldpi\n" + " fldln2\n" + " fxsave %0\n" + " fxrstor %0\n" + " fxsave %1\n" + " fninit\n" + : "=m" (*(uint32_t *)fp2), "=m" (*(uint32_t *)fp) + : "m" (a), "m" (b)); + printf("fpuc=%04x\n", fp->fpuc); + printf("fpus=%04x\n", fp->fpus); + printf("fptag=%04x\n", fp->fptag); + for(i = 0; i < 3; i++) { + printf("ST%d: %016llx %04x\n", + i, + *(uint64_t *)&fp->fpregs1[i * 16], + *(uint16_t *)&fp->fpregs1[i * 16 + 8]); + } + printf("mxcsr=%08x\n", fp->mxcsr & 0x1f80); + for(i = 0; i < 8; i++) { + printf("xmm%d: %016llx%016llx\n", + i, + *(uint64_t *)&fp->xmm_regs[i * 16], + *(uint64_t *)&fp->xmm_regs[i * 16 + 8]); + } +} + void test_sse(void) { XMMReg r, a, b; @@ -2098,6 +2159,7 @@ void test_sse(void) #if 0 SSE_OP2(movshdup); #endif + asm volatile ("emms"); } #endif @@ -2134,6 +2196,7 @@ int main(int argc, char **argv) test_enter(); #ifdef TEST_SSE test_sse(); + test_fxsave(); #endif return 0; } -- cgit v1.2.3 From 1bde465e0699bcef41775ace67e0931cabac6bbd Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Jan 2005 22:34:47 +0000 Subject: sse fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1217 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index f2b83b0c2..6b5ed2af6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1052,8 +1052,12 @@ int main(int argc, char **argv) cpu_x86_set_cpl(env, 3); env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; - env->hflags |= HF_PE_MASK | HF_OSFXSR_MASK; - + env->hflags |= HF_PE_MASK; + if (env->cpuid_features & CPUID_SSE) { + env->cr[4] |= CR4_OSFXSR_MASK; + env->hflags |= HF_OSFXSR_MASK; + } + /* flags setup : we activate the IRQs by default as in user mode */ env->eflags |= IF_MASK; -- cgit v1.2.3 From 735a8fd38e86d94f62e732de94e1a137619b9e49 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Jan 2005 22:36:43 +0000 Subject: fixed performance regression git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1218 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e494d23f7..25af117a5 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -564,8 +564,8 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, if (env->hflags & HF_CS64_MASK) { /* zero base assumed for DS, ES and SS in long mode */ } else if (!(env->cr[0] & CR0_PE_MASK) || - (env->eflags & VM_MASK) || - !(new_hflags & HF_CS32_MASK)) { + (env->eflags & VM_MASK) || + !(env->hflags & HF_CS32_MASK)) { /* XXX: try to avoid this test. The problem comes from the fact that is real mode or vm86 mode we only modify the 'base' and 'selector' fields of the segment cache to go @@ -573,9 +573,9 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, translate-i386.c. */ new_hflags |= HF_ADDSEG_MASK; } else { - new_hflags |= (((unsigned long)env->segs[R_DS].base | - (unsigned long)env->segs[R_ES].base | - (unsigned long)env->segs[R_SS].base) != 0) << + new_hflags |= ((env->segs[R_DS].base | + env->segs[R_ES].base | + env->segs[R_SS].base) != 0) << HF_ADDSEG_SHIFT; } env->hflags = (env->hflags & -- cgit v1.2.3 From d3c617219b663c7cbcd443922c3ee070d16ee613 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Jan 2005 22:41:17 +0000 Subject: fxsr fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1219 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 5255e960d..58530dce5 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2915,11 +2915,11 @@ void helper_fxsave(target_ulong ptr, int data64) fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; fptag = 0; for(i = 0; i < 8; i++) { - fptag |= ((!env->fptags[(env->fpstt + i) & 7]) << i); + fptag |= (env->fptags[i] << i); } stw(ptr, env->fpuc); stw(ptr + 2, fpus); - stw(ptr + 4, fptag); + stw(ptr + 4, fptag ^ 0xff); addr = ptr + 0x20; for(i = 0;i < 8; i++) { @@ -2931,7 +2931,7 @@ void helper_fxsave(target_ulong ptr, int data64) if (env->cr[4] & CR4_OSFXSR_MASK) { /* XXX: finish it */ stl(ptr + 0x18, env->mxcsr); /* mxcsr */ - stl(ptr + 0x1c, 0); /* mxcsr_mask */ + stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */ nb_xmm_regs = 8 << data64; addr = ptr + 0xa0; for(i = 0; i < nb_xmm_regs; i++) { @@ -2950,12 +2950,12 @@ void helper_fxrstor(target_ulong ptr, int data64) env->fpuc = lduw(ptr); fpus = lduw(ptr + 2); - fptag = ldub(ptr + 4); + fptag = lduw(ptr + 4); env->fpstt = (fpus >> 11) & 7; env->fpus = fpus & ~0x3800; fptag ^= 0xff; for(i = 0;i < 8; i++) { - env->fptags[(env->fpstt + i) & 7] = ((fptag >> i) & 1); + env->fptags[i] = ((fptag >> i) & 1); } addr = ptr + 0x20; -- cgit v1.2.3 From e5843bc81619d62e95ac714e0d3b403944cfb978 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Jan 2005 22:46:19 +0000 Subject: enable MMX for x86_64 too git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1220 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 2811cd707..2a15ec737 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -108,8 +108,8 @@ CPUX86State *cpu_x86_init(void) CPUID_CX8 | CPUID_PGE | CPUID_CMOV); #ifdef TARGET_X86_64 /* currently not enabled for std i386 because not fully tested */ - env->cpuid_features |= CPUID_APIC | CPUID_FXSR | CPUID_PAE | - CPUID_SSE | CPUID_SSE2; + env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2; + env->cpuid_features |= CPUID_APIC | CPUID_PAE; #endif } cpu_single_env = env; -- cgit v1.2.3 From 6508fe59e07b263a8f9afd0f5f13e6240651f42c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 15 Jan 2005 12:02:56 +0000 Subject: PC parallel port support (Mark Jonckheere) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1221 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 2 +- hw/parallel.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.c | 9 +++ vl.c | 34 ++++++++++ vl.h | 11 ++++ 6 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 hw/parallel.c diff --git a/Changelog b/Changelog index 539e3ec96..c1e5fff7d 100644 --- a/Changelog +++ b/Changelog @@ -12,6 +12,7 @@ version 0.6.2: - initial x86_64 target support - initial APIC support - MMX/SSE/SSE2/PNI support + - PC parallel port support (Mark Jonckheere) version 0.6.1: diff --git a/Makefile.target b/Makefile.target index 942a105ea..6c49acfb2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -316,7 +316,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o -VL_OBJS+= cirrus_vga.o mixeng.o apic.o +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o endif ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) diff --git a/hw/parallel.c b/hw/parallel.c new file mode 100644 index 000000000..1b9fe7cef --- /dev/null +++ b/hw/parallel.c @@ -0,0 +1,188 @@ +/* + * QEMU Parallel PORT emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG_PARALLEL + +/* + * These are the definitions for the Printer Status Register + */ +#define PARA_STS_BUSY 0x80 /* Busy complement */ +#define PARA_STS_ACK 0x40 /* Acknowledge */ +#define PARA_STS_PAPER 0x20 /* Out of paper */ +#define PARA_STS_ONLINE 0x10 /* Online */ +#define PARA_STS_ERROR 0x08 /* Error complement */ + +/* + * These are the definitions for the Printer Control Register + */ +#define PARA_CTR_INTEN 0x10 /* IRQ Enable */ +#define PARA_CTR_SELECT 0x08 /* Select In complement */ +#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */ +#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */ +#define PARA_CTR_STROBE 0x01 /* Strobe complement */ + +struct ParallelState { + uint8_t data; + uint8_t status; /* read only register */ + uint8_t control; + int irq; + int irq_pending; + CharDriverState *chr; +}; + +static void parallel_update_irq(ParallelState *s) +{ + if (s->irq_pending) + pic_set_irq(s->irq, 1); + else + pic_set_irq(s->irq, 0); +} + +static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + ParallelState *s = opaque; + + addr &= 7; +#ifdef DEBUG_PARALLEL + printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val); +#endif + switch(addr) { + case 0: + s->data = val; + parallel_update_irq(s); + break; + case 2: + if ((val & PARA_CTR_INIT) == 0 ) { + s->status = PARA_STS_BUSY; + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_ONLINE; + s->status |= PARA_STS_ERROR; + } + else if (val & PARA_CTR_SELECT) { + if (val & PARA_CTR_STROBE) { + s->status &= ~PARA_STS_BUSY; + if ((s->control & PARA_CTR_STROBE) == 0) + qemu_chr_write(s->chr, &s->data, 1); + } else { + if (s->control & PARA_CTR_INTEN) { + s->irq_pending = 1; + } + } + } + parallel_update_irq(s); + s->control = val; + break; + } +} + +static uint32_t parallel_ioport_read(void *opaque, uint32_t addr) +{ + ParallelState *s = opaque; + uint32_t ret = 0xff; + + addr &= 7; + switch(addr) { + case 0: + ret = s->data; + break; + case 1: + ret = s->status; + s->irq_pending = 0; + if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { + /* XXX Fixme: wait 5 microseconds */ + if (s->status & PARA_STS_ACK) + s->status &= ~PARA_STS_ACK; + else { + /* XXX Fixme: wait 5 microseconds */ + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_BUSY; + } + } + parallel_update_irq(s); + break; + case 2: + ret = s->control; + break; + } +#ifdef DEBUG_PARALLEL + printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret); +#endif + return ret; +} + +static int parallel_can_receive(ParallelState *s) +{ + return 0; +} + +static void parallel_receive_byte(ParallelState *s, int ch) +{ +} + +static void parallel_receive_break(ParallelState *s) +{ +} + +static int parallel_can_receive1(void *opaque) +{ + ParallelState *s = opaque; + return parallel_can_receive(s); +} + +static void parallel_receive1(void *opaque, const uint8_t *buf, int size) +{ + ParallelState *s = opaque; + parallel_receive_byte(s, buf[0]); +} + +static void parallel_event(void *opaque, int event) +{ + ParallelState *s = opaque; +} + +/* If fd is zero, it means that the parallel device uses the console */ +ParallelState *parallel_init(int base, int irq, CharDriverState *chr) +{ + ParallelState *s; + + s = qemu_mallocz(sizeof(ParallelState)); + if (!s) + return NULL; + s->irq = irq; + s->data = 0; + s->status = PARA_STS_BUSY; + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_ONLINE; + s->status |= PARA_STS_ERROR; + s->control = PARA_CTR_SELECT; + s->control |= PARA_CTR_INIT; + + register_ioport_write(base, 8, 1, parallel_ioport_write, s); + register_ioport_read(base, 8, 1, parallel_ioport_read, s); + s->chr = chr; + qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s); + qemu_chr_add_event_handler(chr, parallel_event); + return s; +} diff --git a/hw/pc.c b/hw/pc.c index 7b6c8946f..5deb445a3 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -376,6 +376,9 @@ static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; +static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; +static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; + /* PC hardware initialisation */ void pc_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -538,6 +541,12 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, } } + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { + if (parallel_hds[i]) { + parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); + } + } + if (pci_enabled) { for(i = 0; i < nb_nics; i++) { pci_ne2000_init(pci_bus, &nd_table[i]); diff --git a/vl.c b/vl.c index f478f9b23..468032fb5 100644 --- a/vl.c +++ b/vl.c @@ -136,6 +136,7 @@ int graphic_depth = 15; int full_screen = 0; TextConsole *vga_console; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; +CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; /***********************************************************/ /* x86 ISA bus support */ @@ -2750,6 +2751,7 @@ void help(void) "Debug/Expert options:\n" "-monitor dev redirect the monitor to char device 'dev'\n" "-serial dev redirect the serial port to char device 'dev'\n" + "-parallel dev redirect the parallel port to char device 'dev'\n" "-pidfile file Write PID to 'file'\n" "-S freeze CPU at startup (use 'c' to start execution)\n" "-s wait gdb connection to port %d\n" @@ -2842,6 +2844,7 @@ enum { QEMU_OPTION_std_vga, QEMU_OPTION_monitor, QEMU_OPTION_serial, + QEMU_OPTION_parallel, QEMU_OPTION_loadvm, QEMU_OPTION_full_screen, QEMU_OPTION_pidfile, @@ -2904,6 +2907,7 @@ const QEMUOption qemu_options[] = { { "std-vga", 0, QEMU_OPTION_std_vga }, { "monitor", 1, QEMU_OPTION_monitor }, { "serial", 1, QEMU_OPTION_serial }, + { "parallel", 1, QEMU_OPTION_parallel }, { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, { "full-screen", 0, QEMU_OPTION_full_screen }, { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, @@ -2986,6 +2990,8 @@ int main(int argc, char **argv) char monitor_device[128]; char serial_devices[MAX_SERIAL_PORTS][128]; int serial_device_index; + char parallel_devices[MAX_PARALLEL_PORTS][128]; + int parallel_device_index; const char *loadvm = NULL; #if !defined(CONFIG_SOFTMMU) @@ -3019,6 +3025,11 @@ int main(int argc, char **argv) serial_devices[i][0] = '\0'; serial_device_index = 0; + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc"); + for(i = 1; i < MAX_PARALLEL_PORTS; i++) + parallel_devices[i][0] = '\0'; + parallel_device_index = 0; + nb_tun_fds = 0; net_if_type = -1; nb_nics = 1; @@ -3115,6 +3126,7 @@ int main(int argc, char **argv) case QEMU_OPTION_nographic: pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "stdio"); nographic = 1; break; case QEMU_OPTION_kernel: @@ -3329,6 +3341,15 @@ int main(int argc, char **argv) sizeof(serial_devices[0]), optarg); serial_device_index++; break; + case QEMU_OPTION_parallel: + if (parallel_device_index >= MAX_PARALLEL_PORTS) { + fprintf(stderr, "qemu: too many parallel ports\n"); + exit(1); + } + pstrcpy(parallel_devices[parallel_device_index], + sizeof(parallel_devices[0]), optarg); + parallel_device_index++; + break; case QEMU_OPTION_loadvm: loadvm = optarg; break; @@ -3552,6 +3573,19 @@ int main(int argc, char **argv) } } + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { + if (parallel_devices[i][0] != '\0') { + parallel_hds[i] = qemu_chr_open(parallel_devices[i]); + if (!parallel_hds[i]) { + fprintf(stderr, "qemu: could not open parallel device '%s'\n", + parallel_devices[i]); + exit(1); + } + if (!strcmp(parallel_devices[i], "vc")) + qemu_chr_printf(parallel_hds[i], "parallel%d console\n", i); + } + } + /* setup cpu signal handlers for MMU / self modifying code handling */ #if !defined(CONFIG_SOFTMMU) diff --git a/vl.h b/vl.h index a80d9057b..39ea6550b 100644 --- a/vl.h +++ b/vl.h @@ -224,6 +224,12 @@ void console_select(unsigned int index); extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; +/* parallel ports */ + +#define MAX_PARALLEL_PORTS 3 + +extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; + /* network redirectors support */ #define MAX_NICS 8 @@ -632,6 +638,11 @@ void rtc_set_date(RTCState *s, const struct tm *tm); typedef struct SerialState SerialState; SerialState *serial_init(int base, int irq, CharDriverState *chr); +/* parallel.c */ + +typedef struct ParallelState ParallelState; +ParallelState *parallel_init(int base, int irq, CharDriverState *chr); + /* i8259.c */ void pic_set_irq(int irq, int level); -- cgit v1.2.3 From c82913f742cdb7701aa431efb40ef4036d576d4f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 15 Jan 2005 12:03:28 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1222 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.cvsignore b/.cvsignore index e7ca91532..aff7f55fd 100644 --- a/.cvsignore +++ b/.cvsignore @@ -16,3 +16,4 @@ qemu-img.pod sparc-user qemu-img sparc-softmmu +x86_64-softmmu -- cgit v1.2.3 From bb2d531499960c881facda2b468c359c7df97a75 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 15 Jan 2005 21:50:11 +0000 Subject: -nographic fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1223 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/vl.c b/vl.c index 468032fb5..27c6f3842 100644 --- a/vl.c +++ b/vl.c @@ -3126,7 +3126,6 @@ int main(int argc, char **argv) case QEMU_OPTION_nographic: pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); - pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "stdio"); nographic = 1; break; case QEMU_OPTION_kernel: -- cgit v1.2.3 From d52cf7a64afb766b2b9a88738353bb5ec810b328 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Jan 2005 01:07:28 +0000 Subject: sse fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1224 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_sse.h | 18 ++++++++++++++++-- target-i386/translate.c | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 39c90d0c2..2ba2db3a7 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -528,7 +528,7 @@ void OPPROTO glue(op_maskmov, SUFFIX) (void) s = (Reg *)((char *)env + PARAM2); for(i = 0; i < (8 << SHIFT); i++) { if (s->B(i) & 0x80) - stb(A0, d->B(i)); + stb(A0 + i, d->B(i)); } } @@ -565,6 +565,20 @@ void OPPROTO glue(op_pshufw, SUFFIX) (void) *d = r; } #else +void OPPROTO op_shufps(void) +{ + Reg r, *d, *s; + int order; + d = (Reg *)((char *)env + PARAM1); + s = (Reg *)((char *)env + PARAM2); + order = PARAM3; + r.L(0) = d->L(order & 3); + r.L(1) = d->L((order >> 2) & 3); + r.L(2) = s->L((order >> 4) & 3); + r.L(3) = s->L((order >> 6) & 3); + *d = r; +} + void OPPROTO op_shufpd(void) { Reg r, *d, *s; @@ -572,7 +586,7 @@ void OPPROTO op_shufpd(void) d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); order = PARAM3; - r.Q(0) = s->Q(order & 1); + r.Q(0) = d->Q(order & 1); r.Q(1) = s->Q((order >> 1) & 1); *d = r; } diff --git a/target-i386/translate.c b/target-i386/translate.c index e548387eb..17ce6fa60 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2292,7 +2292,7 @@ static GenOpFunc2 *sse_op_table1[256][4] = { [0x5f] = SSE_FOP(max), [0xc2] = SSE_FOP(cmpeq), - [0xc6] = { (GenOpFunc2 *)gen_op_pshufd_xmm, (GenOpFunc2 *)gen_op_shufpd }, + [0xc6] = { (GenOpFunc2 *)gen_op_shufps, (GenOpFunc2 *)gen_op_shufpd }, /* MMX ops and their SSE extensions */ [0x60] = MMX_OP2(punpcklbw), -- cgit v1.2.3 From 97ed14aead862362210c0367782274afa0f593b9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Jan 2005 01:09:01 +0000 Subject: fix shufps/shufpd tests - added maskmov tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1225 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index b2ef1d8fe..94955c247 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1733,6 +1733,22 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { SSE_OP2(op);\ } +#define SHUF_OP(op, ib)\ +{\ + int i;\ + a.q[0] = test_values[0][0];\ + a.q[1] = test_values[0][1];\ + b.q[0] = test_values[1][0];\ + b.q[1] = test_values[1][1];\ + asm volatile (#op " $" #ib ", %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ + printf("%-9s: a=%016llx%016llx b=%016llx%016llx ib=%02x r=%016llx%016llx\n",\ + #op,\ + a.q[1], a.q[0],\ + b.q[1], b.q[0],\ + ib,\ + r.q[1], r.q[0]);\ +} + #define PSHUF_OP(op, ib)\ {\ int i;\ @@ -2009,6 +2025,32 @@ void test_sse(void) asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); + { + r.q[0] = -1; + r.q[1] = -1; + + a.q[0] = test_values[0][0]; + a.q[1] = test_values[0][1]; + b.q[0] = test_values[1][0]; + b.q[1] = test_values[1][1]; + asm volatile("maskmovq %1, %0" : + : "y" (a.q[0]), "y" (b.q[0]), "D" (&r) + : "memory"); + printf("%-9s: r=%016llx a=%016llx b=%016llx\n", + "maskmov", + r.q[0], + a.q[0], + b.q[0]); + asm volatile("maskmovdqu %1, %0" : + : "x" (a.dq), "x" (b.dq), "D" (&r) + : "memory"); + printf("%-9s: r=%016llx%016llx a=%016llx%016llx b=%016llx%016llx\n", + "maskmov", + r.q[1], r.q[0], + a.q[1], a.q[0], + b.q[1], b.q[0]); + } + asm volatile ("emms"); SSE_OP2(punpcklqdq); @@ -2027,8 +2069,8 @@ void test_sse(void) SSE_OP2(unpckhps); SSE_OP2(unpckhpd); - PSHUF_OP(shufps, 0x78); - PSHUF_OP(shufpd, 0x02); + SHUF_OP(shufps, 0x78); + SHUF_OP(shufpd, 0x02); PSHUF_OP(pshufd, 0x78); PSHUF_OP(pshuflw, 0x78); -- cgit v1.2.3 From ca954f6d90208fa691c04b26ba6227bf717df57f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Jan 2005 23:35:43 +0000 Subject: x86_64 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1226 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 58530dce5..d9c446ff6 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1550,7 +1550,8 @@ void helper_ljmp_protected_T0_T1(int next_eip) if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); limit = get_seg_limit(e1, e2); - if (new_eip > limit) + if (new_eip > limit && + !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, get_seg_base(e1, e2), limit, e2); @@ -1949,7 +1950,8 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); sp += addend; - if (rpl == cpl && !(env->hflags & HF_CS64_MASK)) { + if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || + ((env->hflags & HF_CS64_MASK) && !is_iret))) { /* return to same priledge level */ cpu_x86_load_seg_cache(env, R_CS, new_cs, get_seg_base(e1, e2), -- cgit v1.2.3 From b328f873ab2c952f1e27970969a9315d46ced974 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 Jan 2005 22:03:16 +0000 Subject: gdb M packet parsing fix (Thomas Petazzoni) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1227 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdbstub.c b/gdbstub.c index 9a491db6d..1e95c7c08 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -420,7 +420,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) if (*p == ',') p++; len = strtoul(p, (char **)&p, 16); - if (*p == ',') + if (*p == ':') p++; hextomem(mem_buf, p, len); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) -- cgit v1.2.3 From ada89ce61b21116f6884f758e29167ccba613f39 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 Jan 2005 22:31:41 +0000 Subject: enabled wheel mouse support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1228 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index 730b57337..e38edeeba 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -549,7 +549,6 @@ static void kbd_write_mouse(KBDState *s, int val) break; case AUX_SET_SAMPLE: s->mouse_sample_rate = val; -#if 0 /* detect IMPS/2 or IMEX */ switch(s->mouse_detect_state) { default: @@ -576,7 +575,6 @@ static void kbd_write_mouse(KBDState *s, int val) s->mouse_detect_state = 0; break; } -#endif kbd_queue(s, AUX_ACK, 1); s->mouse_write_cmd = -1; break; -- cgit v1.2.3 From 18a6d284adf2d2aacca902ad683c94389e447b15 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 17 Jan 2005 22:32:23 +0000 Subject: enabled wheel mouse support (initial patch by Volker Ruppert) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1229 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/sdl.c b/sdl.c index b061c8e59..20e45d93f 100644 --- a/sdl.c +++ b/sdl.c @@ -279,9 +279,9 @@ static void sdl_grab_end(void) sdl_update_caption(); } -static void sdl_send_mouse_event(void) +static void sdl_send_mouse_event(int dz) { - int dx, dy, dz, state, buttons; + int dx, dy, state, buttons; state = SDL_GetRelativeMouseState(&dx, &dy); buttons = 0; if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) @@ -290,14 +290,6 @@ static void sdl_send_mouse_event(void) buttons |= MOUSE_EVENT_RBUTTON; if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) buttons |= MOUSE_EVENT_MBUTTON; - /* XXX: test wheel */ - dz = 0; -#ifdef SDL_BUTTON_WHEELUP - if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP)) - dz--; - if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN)) - dz++; -#endif kbd_mouse_event(dx, dy, dz, buttons); } @@ -426,7 +418,7 @@ static void sdl_refresh(DisplayState *ds) break; case SDL_MOUSEMOTION: if (gui_grab) { - sdl_send_mouse_event(); + sdl_send_mouse_event(0); } break; case SDL_MOUSEBUTTONDOWN: @@ -440,7 +432,16 @@ static void sdl_refresh(DisplayState *ds) sdl_grab_start(); } } else { - sdl_send_mouse_event(); + int dz; + dz = 0; +#ifdef SDL_BUTTON_WHEELUP + if (bev->button == SDL_BUTTON_WHEELUP) { + dz = -1; + } else if (bev->button == SDL_BUTTON_WHEELDOWN) { + dz = 1; + } +#endif + sdl_send_mouse_event(dz); } } break; -- cgit v1.2.3 From 83b34f8b5736f7ae523ba573f55f4d9a2455b57f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:26:30 +0000 Subject: more consistent type for size (still a bug in wrapping) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1230 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 2 +- disas.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/disas.c b/disas.c index 34b047405..3a5549d2b 100644 --- a/disas.c +++ b/disas.c @@ -110,7 +110,7 @@ bfd_vma bfd_getb32 (const bfd_byte *addr) /* Disassemble this for me please... (debugging). 'flags' is only used for i386: non zero means 16 bit code */ -void target_disas(FILE *out, target_ulong code, unsigned long size, int flags) +void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) { target_ulong pc; int count; diff --git a/disas.h b/disas.h index ef80fd700..32da4ebcb 100644 --- a/disas.h +++ b/disas.h @@ -3,7 +3,7 @@ /* Disassemble this for me please... (debugging). */ void disas(FILE *out, void *code, unsigned long size); -void target_disas(FILE *out, target_ulong code, unsigned long size, int flags); +void target_disas(FILE *out, target_ulong code, target_ulong size, int flags); void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags); /* Look up symbol for debugging purpose. Returns "" if unknown. */ -- cgit v1.2.3 From bef79c34a293f8f8c27a928ad5b770dd053a4434 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:42:06 +0000 Subject: support for dyngen labels on more hosts git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1231 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 96 ++++++++++++++++++++++------------------------------------------ 1 file changed, 32 insertions(+), 64 deletions(-) diff --git a/dyngen.c b/dyngen.c index 1138ca455..495b9866d 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1185,6 +1185,26 @@ int load_object(const char *filename) #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, sizeof(name), + "(long)(&__dot_%s)", + sym_name + 1); + else +#endif + snprintf(name, name_size, "(long)(&%s)", sym_name); + } +} + #ifdef HOST_ARM int arm_emit_ldr_info(const char *name, unsigned long start_offset, @@ -1244,11 +1264,7 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, if (rel->r_offset == (pc_offset + start_offset)) { sym_name = get_rel_sym_name(rel); /* the compiler leave some unnecessary references to the code */ - if (strstart(sym_name, "__op_param", &p)) { - snprintf(relname, sizeof(relname), "param%s", p); - } else { - snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name); - } + 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); @@ -1641,13 +1657,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; } - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else if (strstart(sym_name, "__op_gen_label", &p)) { - snprintf(name, sizeof(name), "gen_labels[param%s]", p); - } else { - snprintf(name, sizeof(name), "(long)(&%s)", sym_name); - } + 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); @@ -1705,11 +1715,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else { - snprintf(name, sizeof(name), "(long)(&%s)", sym_name); - } + get_reloc_expr(name, sizeof(name), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { @@ -1753,11 +1759,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; } - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else { - snprintf(name, sizeof(name), "(long)(&%s)", sym_name); - } + get_reloc_expr(name, sizeof(name), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { @@ -1842,12 +1844,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; /* dunno how to handle without final_sym_name */ } - if (strstart(sym_name, "__op_param", &p)) { - snprintf(final_sym_name, sizeof(final_sym_name), "param%s", p); - } else { - snprintf(final_sym_name, sizeof(final_sym_name), "(long)(&%s)", sym_name); - } - + get_reloc_expr(final_sym_name, sizeof(final_sym_name), + sym_name); switch(type) { case PPC_RELOC_BR24: fprintf(outfile, "{\n"); @@ -1885,11 +1883,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else { - snprintf(name, sizeof(name), "(long)(&%s)", sym_name); - } + get_reloc_expr(name, sizeof(name), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { @@ -1973,11 +1967,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else { - snprintf(name, sizeof(name), "(long)(&%s)", sym_name); - } + get_reloc_expr(name, sizeof(name), sym_name); type = ELF64_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { @@ -2000,17 +1990,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else { - if (sym_name[0] == '.') - snprintf(name, sizeof(name), - "(long)(&__dot_%s)", - sym_name + 1); - else - snprintf(name, sizeof(name), - "(long)(&%s)", sym_name); - } + get_reloc_expr(name, sizeof(name), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { @@ -2065,11 +2045,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else { - snprintf(name, sizeof(name), "(long)(&%s)", sym_name); - } + get_reloc_expr(name, sizeof(name), sym_name); type = ELF64_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { @@ -2131,11 +2107,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* the compiler leave some unnecessary references to the code */ if (sym_name[0] == '\0') continue; - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else { - snprintf(name, sizeof(name), "(long)(&%s)", sym_name); - } + get_reloc_expr(name, sizeof(name), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = get32((uint32_t *)(text + rel->r_offset)); switch(type) { @@ -2164,11 +2136,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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; - if (strstart(sym_name, "__op_param", &p)) { - snprintf(name, sizeof(name), "param%s", p); - } else { - snprintf(name, sizeof(name), "(long)(&%s)", sym_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; switch(type) { -- cgit v1.2.3 From dc9543dc22cd7a409500caccb1ff3183f53d5966 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:42:59 +0000 Subject: removed warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1232 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/parallel.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/parallel.c b/hw/parallel.c index 1b9fe7cef..a304d7fdf 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -141,10 +141,6 @@ static void parallel_receive_byte(ParallelState *s, int ch) { } -static void parallel_receive_break(ParallelState *s) -{ -} - static int parallel_can_receive1(void *opaque) { ParallelState *s = opaque; @@ -159,7 +155,6 @@ static void parallel_receive1(void *opaque, const uint8_t *buf, int size) static void parallel_event(void *opaque, int event) { - ParallelState *s = opaque; } /* If fd is zero, it means that the parallel device uses the console */ -- cgit v1.2.3 From 79f91c27bad7cf39ff336f1b2ed418942f65bab6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:44:55 +0000 Subject: more fpu functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1233 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/target-i386/exec.h b/target-i386/exec.h index 1923b95ee..404457eba 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -142,6 +142,44 @@ extern int loglevel; #include "cpu.h" #include "exec-all.h" +/* XXX: add a generic FPU library */ + +static inline double float32_to_float64(float a) +{ + return a; +} + +static inline float float64_to_float32(double a) +{ + return a; +} + +#if defined(__powerpc__) +/* better to call an helper on ppc */ +float int32_to_float32(int32_t a); +double int32_to_float64(int32_t a); +#else +static inline float int32_to_float32(int32_t a) +{ + return (float)a; +} + +static inline double int32_to_float64(int32_t a) +{ + return (double)a; +} +#endif + +static inline float int64_to_float32(int64_t a) +{ + return (float)a; +} + +static inline double int64_to_float64(int64_t a) +{ + return (double)a; +} + typedef struct CCTable { int (*compute_all)(void); /* return all the flags */ int (*compute_c)(void); /* return the C flag */ @@ -559,6 +597,7 @@ void restore_native_fp_state(CPUState *env); void save_native_fp_state(CPUState *env); float approx_rsqrt(float a); float approx_rcp(float a); +double helper_sqrt(double a); int fpu_isnan(double a); extern const uint8_t parity_table[256]; -- cgit v1.2.3 From 4d6b6c0aec20e78c966b857c520fe0d242d64b30 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:45:23 +0000 Subject: more fpu functions - x86_64 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1234 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index d9c446ff6..ea2ef5e02 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1454,7 +1454,11 @@ void load_seg(int seg_reg, int selector) selector &= 0xffff; if ((selector & 0xfffc) == 0) { /* null selector case */ - if (seg_reg == R_SS) + if (seg_reg == R_SS +#ifdef TARGET_X86_64 + && !(env->hflags & HF_CS64_MASK) +#endif + ) raise_exception_err(EXCP0D_GPF, 0); cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); } else { @@ -2146,6 +2150,7 @@ void helper_sysexit(void) void helper_movl_crN_T0(int reg) { +#if !defined(CONFIG_USER_ONLY) switch(reg) { case 0: cpu_x86_update_cr0(env, T0); @@ -2156,10 +2161,14 @@ void helper_movl_crN_T0(int reg) case 4: cpu_x86_update_cr4(env, T0); break; + case 8: + cpu_set_apic_tpr(env, T0); + break; default: env->cr[reg] = T0; break; } +#endif } /* XXX: do more */ @@ -3227,6 +3236,25 @@ float approx_rcp(float a) return 1.0 / a; } +/* XXX: find a better solution */ +double helper_sqrt(double a) +{ + return sqrt(a); +} + +/* XXX: move that to another file */ +#if defined(__powerpc__) +/* better to call an helper on ppc */ +float int32_to_float32(int32_t a) +{ + return (float)a; +} + +double int32_to_float64(int32_t a) +{ + return (double)a; +} +#endif #if !defined(CONFIG_USER_ONLY) -- cgit v1.2.3 From 39c61f49f456a0e24f554d372d508ab245fc8edd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:46:09 +0000 Subject: CR8 support - FORCE_RET() fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1235 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-i386/op.c b/target-i386/op.c index ab7501e93..71365b5c2 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1198,6 +1198,13 @@ void OPPROTO op_movl_crN_T0(void) helper_movl_crN_T0(PARAM1); } +void OPPROTO op_movtl_T0_cr8(void) +{ +#if !defined(CONFIG_USER_ONLY) + T0 = cpu_get_apic_tpr(env); +#endif +} + /* DR registers access */ void OPPROTO op_movl_drN_T0(void) { @@ -1279,12 +1286,14 @@ void OPPROTO op_jnz_T0_label(void) { if (T0) GOTO_LABEL_PARAM(1); + FORCE_RET(); } void OPPROTO op_jz_T0_label(void) { if (!T0) GOTO_LABEL_PARAM(1); + FORCE_RET(); } /* slow set cases (compute x86 flags) */ -- cgit v1.2.3 From 0523c6b7c5605e93b1c9960a3a91d08535e9a77e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:46:31 +0000 Subject: FORCE_RET() fixes - fpu fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1236 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_sse.h | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 2ba2db3a7..8472a34d3 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -61,6 +61,7 @@ void OPPROTO glue(op_psrlw, SUFFIX)(void) d->W(7) >>= shift; #endif } + FORCE_RET(); } void OPPROTO glue(op_psraw, SUFFIX)(void) @@ -114,6 +115,7 @@ void OPPROTO glue(op_psllw, SUFFIX)(void) d->W(7) <<= shift; #endif } + FORCE_RET(); } void OPPROTO glue(op_psrld, SUFFIX)(void) @@ -138,6 +140,7 @@ void OPPROTO glue(op_psrld, SUFFIX)(void) d->L(3) >>= shift; #endif } + FORCE_RET(); } void OPPROTO glue(op_psrad, SUFFIX)(void) @@ -183,6 +186,7 @@ void OPPROTO glue(op_pslld, SUFFIX)(void) d->L(3) <<= shift; #endif } + FORCE_RET(); } void OPPROTO glue(op_psrlq, SUFFIX)(void) @@ -205,6 +209,7 @@ void OPPROTO glue(op_psrlq, SUFFIX)(void) d->Q(1) >>= shift; #endif } + FORCE_RET(); } void OPPROTO glue(op_psllq, SUFFIX)(void) @@ -227,6 +232,7 @@ void OPPROTO glue(op_psllq, SUFFIX)(void) d->Q(1) <<= shift; #endif } + FORCE_RET(); } #if SHIFT == 1 @@ -478,6 +484,7 @@ void OPPROTO glue(op_pmaddwd, SUFFIX) (void) d->L(i) = (int16_t)s->W(2*i) * (int16_t)d->W(2*i) + (int16_t)s->W(2*i+1) * (int16_t)d->W(2*i+1); } + FORCE_RET(); } #if SHIFT == 0 @@ -530,6 +537,7 @@ void OPPROTO glue(op_maskmov, SUFFIX) (void) if (s->B(i) & 0x80) stb(A0 + i, d->B(i)); } + FORCE_RET(); } void OPPROTO glue(op_movl_mm_T0, SUFFIX) (void) @@ -682,7 +690,7 @@ void OPPROTO op_ ## name ## sd (void)\ #define FPU_DIV(a, b) (a) / (b) #define FPU_MIN(a, b) (a) < (b) ? (a) : (b) #define FPU_MAX(a, b) (a) > (b) ? (a) : (b) -#define FPU_SQRT(a, b) sqrt(b) +#define FPU_SQRT(a, b) helper_sqrt(b) SSE_OP_S(add, FPU_ADD) SSE_OP_S(sub, FPU_SUB) @@ -702,8 +710,8 @@ void OPPROTO op_cvtps2pd(void) s = (Reg *)((char *)env + PARAM2); s0 = s->XMM_S(0); s1 = s->XMM_S(1); - d->XMM_D(0) = s0; - d->XMM_D(1) = s1; + d->XMM_D(0) = float32_to_float64(s0); + d->XMM_D(1) = float32_to_float64(s1); } void OPPROTO op_cvtpd2ps(void) @@ -711,8 +719,8 @@ void OPPROTO op_cvtpd2ps(void) Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); - d->XMM_S(0) = s->XMM_D(0); - d->XMM_S(1) = s->XMM_D(1); + d->XMM_S(0) = float64_to_float32(s->XMM_D(0)); + d->XMM_S(1) = float64_to_float32(s->XMM_D(1)); d->Q(1) = 0; } @@ -721,7 +729,7 @@ void OPPROTO op_cvtss2sd(void) Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); - d->XMM_D(0) = s->XMM_S(0); + d->XMM_D(0) = float32_to_float64(s->XMM_S(0)); } void OPPROTO op_cvtsd2ss(void) @@ -729,7 +737,7 @@ void OPPROTO op_cvtsd2ss(void) Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); - d->XMM_S(0) = s->XMM_D(0); + d->XMM_S(0) = float64_to_float32(s->XMM_D(0)); } /* integer to float */ @@ -737,10 +745,10 @@ void OPPROTO op_cvtdq2ps(void) { XMMReg *d = (XMMReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->XMM_S(0) = (int32_t)s->XMM_L(0); - d->XMM_S(1) = (int32_t)s->XMM_L(1); - d->XMM_S(2) = (int32_t)s->XMM_L(2); - d->XMM_S(3) = (int32_t)s->XMM_L(3); + d->XMM_S(0) = int32_to_float32(s->XMM_L(0)); + d->XMM_S(1) = int32_to_float32(s->XMM_L(1)); + d->XMM_S(2) = int32_to_float32(s->XMM_L(2)); + d->XMM_S(3) = int32_to_float32(s->XMM_L(3)); } void OPPROTO op_cvtdq2pd(void) @@ -750,49 +758,49 @@ void OPPROTO op_cvtdq2pd(void) int32_t l0, l1; l0 = (int32_t)s->XMM_L(0); l1 = (int32_t)s->XMM_L(1); - d->XMM_D(0) = l0; - d->XMM_D(1) = l1; + d->XMM_D(0) = int32_to_float64(l0); + d->XMM_D(1) = int32_to_float64(l1); } void OPPROTO op_cvtpi2ps(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); MMXReg *s = (MMXReg *)((char *)env + PARAM2); - d->XMM_S(0) = (int32_t)s->MMX_L(0); - d->XMM_S(1) = (int32_t)s->MMX_L(1); + d->XMM_S(0) = int32_to_float32(s->MMX_L(0)); + d->XMM_S(1) = int32_to_float32(s->MMX_L(1)); } void OPPROTO op_cvtpi2pd(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); MMXReg *s = (MMXReg *)((char *)env + PARAM2); - d->XMM_D(0) = (int32_t)s->MMX_L(0); - d->XMM_D(1) = (int32_t)s->MMX_L(1); + d->XMM_D(0) = int32_to_float64(s->MMX_L(0)); + d->XMM_D(1) = int32_to_float64(s->MMX_L(1)); } void OPPROTO op_cvtsi2ss(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_S(0) = (int32_t)T0; + d->XMM_S(0) = int32_to_float32(T0); } void OPPROTO op_cvtsi2sd(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_D(0) = (int32_t)T0; + d->XMM_D(0) = int32_to_float64(T0); } #ifdef TARGET_X86_64 void OPPROTO op_cvtsq2ss(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_S(0) = (int64_t)T0; + d->XMM_S(0) = int64_to_float32(T0); } void OPPROTO op_cvtsq2sd(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_D(0) = (int64_t)T0; + d->XMM_D(0) = int64_to_float64(T0); } #endif -- cgit v1.2.3 From 9230e66e5c711bd077705465d34161d6b1e7fee7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:46:56 +0000 Subject: CR8 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1237 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 12 ++++++++++++ target-i386/cpu.h | 13 ++++--------- target-i386/translate.c | 7 +++++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index 82b858486..486b9bf87 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -100,6 +100,18 @@ uint64_t cpu_get_apic_base(CPUState *env) return s->apicbase; } +void cpu_set_apic_tpr(CPUX86State *env, uint8_t val) +{ + APICState *s = env->apic_state; + s->tpr = (val & 0x0f) << 4; +} + +uint8_t cpu_get_apic_tpr(CPUX86State *env) +{ + APICState *s = env->apic_state; + return s->tpr >> 4; +} + /* return -1 if no bit is set */ static int get_highest_priority_int(uint32_t *tab) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 25af117a5..781be2838 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -509,15 +509,6 @@ typedef struct CPUX86State { void *opaque; } CPUX86State; -#ifndef IN_OP_I386 -void cpu_x86_outb(CPUX86State *env, int addr, int val); -void cpu_x86_outw(CPUX86State *env, int addr, int val); -void cpu_x86_outl(CPUX86State *env, int addr, int val); -int cpu_x86_inb(CPUX86State *env, int addr); -int cpu_x86_inw(CPUX86State *env, int addr); -int cpu_x86_inl(CPUX86State *env, int addr); -#endif - CPUX86State *cpu_x86_init(void); int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); @@ -615,6 +606,10 @@ uint64_t cpu_get_tsc(CPUX86State *env); void cpu_set_apic_base(CPUX86State *env, uint64_t val); uint64_t cpu_get_apic_base(CPUX86State *env); +void cpu_set_apic_tpr(CPUX86State *env, uint8_t val); +#ifndef NO_CPU_IO_DEFS +uint8_t cpu_get_apic_tpr(CPUX86State *env); +#endif /* will be suppressed */ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); diff --git a/target-i386/translate.c b/target-i386/translate.c index 17ce6fa60..f8449e420 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5631,17 +5631,20 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 2: case 3: case 4: + case 8: if (b & 2) { gen_op_mov_TN_reg[ot][0][rm](); gen_op_movl_crN_T0(reg); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { - gen_op_movtl_T0_env(offsetof(CPUX86State,cr[reg])); + if (reg == 8) + gen_op_movtl_T0_cr8(); + else + gen_op_movtl_T0_env(offsetof(CPUX86State,cr[reg])); gen_op_mov_reg_T0[ot][rm](); } break; - /* XXX: add CR8 for x86_64 */ default: goto illegal_op; } -- cgit v1.2.3 From bd3fae3df6233729591b65f7c9f008d4182f6b44 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:48:05 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1238 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 94955c247..9f1c4f003 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1735,7 +1735,6 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { #define SHUF_OP(op, ib)\ {\ - int i;\ a.q[0] = test_values[0][0];\ a.q[1] = test_values[0][1];\ b.q[0] = test_values[1][0];\ -- cgit v1.2.3 From 82e41634cdf063fae727fdb1563479d2209f79ee Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Jan 2005 20:55:36 +0000 Subject: avoid empty op git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1239 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 4 ++-- target-i386/translate.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index 71365b5c2..79545b51a 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1198,12 +1198,12 @@ void OPPROTO op_movl_crN_T0(void) helper_movl_crN_T0(PARAM1); } +#if !defined(CONFIG_USER_ONLY) void OPPROTO op_movtl_T0_cr8(void) { -#if !defined(CONFIG_USER_ONLY) T0 = cpu_get_apic_tpr(env); -#endif } +#endif /* DR registers access */ void OPPROTO op_movl_drN_T0(void) diff --git a/target-i386/translate.c b/target-i386/translate.c index f8449e420..46bf933c9 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5638,9 +5638,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { +#if !defined(CONFIG_USER_ONLY) if (reg == 8) gen_op_movtl_T0_cr8(); else +#endif gen_op_movtl_T0_env(offsetof(CPUX86State,cr[reg])); gen_op_mov_reg_T0[ot][rm](); } -- cgit v1.2.3 From f51589dad53ff431d827f1326b5313b81488e0dc Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 25 Jan 2005 22:35:05 +0000 Subject: Support resolving addresses in PAE mode in cpu_get_phys_page_debug git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1240 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 92 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 2a15ec737..f78786ee6 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -742,33 +742,87 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) #else target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - uint8_t *pde_ptr, *pte_ptr; + uint32_t pde_addr, pte_addr; uint32_t pde, pte, paddr, page_offset, page_size; - if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr; - page_size = 4096; - } else { - /* page directory entry */ - pde_ptr = phys_ram_base + - (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask); - pde = ldl_raw(pde_ptr); - if (!(pde & PG_PRESENT_MASK)) + if (env->cr[4] & CR4_PAE_MASK) { + uint32_t pdpe_addr, pde_addr, pte_addr; + uint32_t pdpe; + + /* XXX: we only use 32 bit physical addresses */ +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint32_t pml4e_addr, pml4e; + int32_t sext; + + /* test virtual address sign extension */ + sext = (int64_t)addr >> 47; + if (sext != 0 && sext != -1) + return -1; + + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & + env->a20_mask; + pml4e = ldl_phys_aligned(pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) + return -1; + + pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & + env->a20_mask; + pdpe = ldl_phys_aligned(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) + return -1; + } else +#endif + { + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & + env->a20_mask; + pdpe = ldl_phys_aligned(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) + return -1; + } + + pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & + env->a20_mask; + pde = ldl_phys_aligned(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { return -1; - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - pte = pde & ~0x003ff000; /* align to 4MB */ - page_size = 4096 * 1024; + } + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + page_size = 2048 * 1024; + pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ + } else { + /* 4 KB page */ + pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & + env->a20_mask; + page_size = 4096; + pte = ldl_phys_aligned(pte_addr); + } + } else { + if (!(env->cr[0] & CR0_PG_MASK)) { + pte = addr; + page_size = 4096; } else { /* page directory entry */ - pte_ptr = phys_ram_base + - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); - pte = ldl_raw(pte_ptr); - if (!(pte & PG_PRESENT_MASK)) + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask; + pde = ldl_phys_aligned(pde_addr); + if (!(pde & PG_PRESENT_MASK)) return -1; - page_size = 4096; + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + pte = pde & ~0x003ff000; /* align to 4MB */ + page_size = 4096 * 1024; + } else { + /* page directory entry */ + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; + pte = ldl_phys_aligned(pte_addr); + if (!(pte & PG_PRESENT_MASK)) + return -1; + page_size = 4096; + } } + pte = pte & env->a20_mask; } - pte = pte & env->a20_mask; + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); paddr = (pte & TARGET_PAGE_MASK) + page_offset; return paddr; -- cgit v1.2.3 From 0b74ed78ef3879af7f32bb31693d9e3e71d4b5dd Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 Jan 2005 19:50:16 +0000 Subject: mode 4 and 5 write fix (Magnus Damn) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1241 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index d3eba4a34..4b92b4090 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -790,7 +790,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s) blt_rop = s->gr[0x32]; #ifdef DEBUG_BITBLT - printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spicth=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", + printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", blt_rop, s->cirrus_blt_mode, s->cirrus_blt_modeext, @@ -1780,11 +1780,12 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, dst = s->vram_ptr + offset; for (x = 0; x < 8; x++) { if (val & 0x80) { - *dst++ = s->cirrus_shadow_gr1; + *dst = s->cirrus_shadow_gr1; } else if (mode == 5) { - *dst++ = s->cirrus_shadow_gr0; + *dst = s->cirrus_shadow_gr0; } val <<= 1; + dst++; } cpu_physical_memory_set_dirty(s->vram_offset + offset); cpu_physical_memory_set_dirty(s->vram_offset + offset + 7); @@ -1802,13 +1803,14 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, dst = s->vram_ptr + offset; for (x = 0; x < 8; x++) { if (val & 0x80) { - *dst++ = s->cirrus_shadow_gr1; - *dst++ = s->gr[0x11]; + *dst = s->cirrus_shadow_gr1; + *(dst + 1) = s->gr[0x11]; } else if (mode == 5) { - *dst++ = s->cirrus_shadow_gr0; - *dst++ = s->gr[0x10]; + *dst = s->cirrus_shadow_gr0; + *(dst + 1) = s->gr[0x10]; } val <<= 1; + dst += 2; } cpu_physical_memory_set_dirty(s->vram_offset + offset); cpu_physical_memory_set_dirty(s->vram_offset + offset + 15); -- cgit v1.2.3 From 9191d4d19f5d535542163f31c82987194e014425 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 Jan 2005 21:30:57 +0000 Subject: Mac OS X fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1242 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 2bf692230..e1a023ee4 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -209,7 +209,7 @@ extern int __op_param1, __op_param2, __op_param3; extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; -#if defined(_WIN32) +#if defined(_WIN32) || defined(__APPLE__) #define ASM_NAME(x) "_" #x #else #define ASM_NAME(x) #x -- cgit v1.2.3 From d79284e07aae8d702c1d3f9d83590480fa06f5d7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 Jan 2005 21:56:26 +0000 Subject: i386 linux 2.6 timer fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1243 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 27c6f3842..107845eb4 100644 --- a/vl.c +++ b/vl.c @@ -922,7 +922,7 @@ static void init_timers(void) sigaction(SIGALRM, &act, NULL); itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 1000; + itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 10 * 1000; setitimer(ITIMER_REAL, &itv, NULL); -- cgit v1.2.3 From e3db7226b411d767b9a3ac8e0d88f5cbd5782349 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 Jan 2005 22:00:47 +0000 Subject: JIT statistics git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1244 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 3 +++ exec.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ monitor.c | 11 +++++++++-- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 303fab0c1..d395c0038 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -742,4 +742,7 @@ static inline void cpu_physical_memory_set_dirty(target_ulong addr) void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end); +void dump_exec_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); + #endif /* CPU_ALL_H */ diff --git a/exec.c b/exec.c index 3057750fe..40bd60a9f 100644 --- a/exec.c +++ b/exec.c @@ -128,6 +128,11 @@ char *logfilename = "/tmp/qemu.log"; FILE *logfile; int loglevel; +/* statistics */ +static int tlb_flush_count; +static int tb_flush_count; +static int tb_phys_invalidate_count; + static void page_init(void) { /* NOTE: we can always suppose that qemu_host_page_size >= @@ -336,6 +341,7 @@ void tb_flush(CPUState *env) code_gen_ptr = code_gen_buffer; /* XXX: flush processor icache at this point if cache flush is expensive */ + tb_flush_count++; } #ifdef DEBUG_TB_CHECK @@ -530,6 +536,7 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad } tb_invalidate(tb); + tb_phys_invalidate_count++; } static inline void set_bits(uint8_t *tab, int start, int len) @@ -1298,6 +1305,7 @@ void tlb_flush(CPUState *env, int flush_global) #if !defined(CONFIG_SOFTMMU) munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); #endif + tlb_flush_count++; } static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) @@ -2137,6 +2145,53 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, return 0; } +void dump_exec_info(FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i, target_code_size, max_target_code_size; + int direct_jmp_count, direct_jmp2_count, cross_page; + TranslationBlock *tb; + + target_code_size = 0; + max_target_code_size = 0; + cross_page = 0; + direct_jmp_count = 0; + direct_jmp2_count = 0; + for(i = 0; i < nb_tbs; i++) { + tb = &tbs[i]; + target_code_size += tb->size; + if (tb->size > max_target_code_size) + max_target_code_size = tb->size; + if (tb->page_addr[1] != -1) + cross_page++; + if (tb->tb_next_offset[0] != 0xffff) { + direct_jmp_count++; + if (tb->tb_next_offset[1] != 0xffff) { + direct_jmp2_count++; + } + } + } + /* XXX: avoid using doubles ? */ + cpu_fprintf(f, "TB count %d\n", nb_tbs); + cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", + nb_tbs ? target_code_size / nb_tbs : 0, + max_target_code_size); + cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n", + nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0, + target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0); + cpu_fprintf(f, "cross page TB count %d (%d%%)\n", + cross_page, + nb_tbs ? (cross_page * 100) / nb_tbs : 0); + cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n", + direct_jmp_count, + nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0, + direct_jmp2_count, + nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0); + cpu_fprintf(f, "TB flush count %d\n", tb_flush_count); + cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); + cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); +} + #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _cmmu diff --git a/monitor.c b/monitor.c index cfb9c4975..ae1ce8792 100644 --- a/monitor.c +++ b/monitor.c @@ -220,14 +220,19 @@ static void do_info_block(void) static void do_info_registers(void) { #ifdef TARGET_I386 - cpu_dump_state(cpu_single_env, stdout, monitor_fprintf, + cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); #else - cpu_dump_state(cpu_single_env, stdout, monitor_fprintf, + cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, 0); #endif } +static void do_info_jit(void) +{ + dump_exec_info(NULL, monitor_fprintf); +} + static void do_info_history (void) { int i; @@ -893,6 +898,8 @@ static term_cmd_t info_cmds[] = { { "mem", "", mem_info, "", "show the active virtual memory mappings", }, #endif + { "jit", "", do_info_jit, + "", "show dynamic compiler info", }, { NULL, NULL, }, }; -- cgit v1.2.3 From f34c9d6f10bd4d1c8abcf258e76fec739674a105 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 27 Jan 2005 22:32:51 +0000 Subject: mouse reset fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1245 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/pckbd.c b/hw/pckbd.c index e38edeeba..be559eb4f 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -539,6 +539,7 @@ static void kbd_write_mouse(KBDState *s, int val) s->mouse_sample_rate = 100; s->mouse_resolution = 2; s->mouse_status = 0; + s->mouse_type = 0; kbd_queue(s, AUX_ACK, 1); kbd_queue(s, 0xaa, 1); kbd_queue(s, s->mouse_type, 1); -- cgit v1.2.3 From 5416376efe7d33adae215ba0e18d220dd9b3c839 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 27 Jan 2005 23:58:13 +0000 Subject: ram dirty flag update fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1246 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 40bd60a9f..0dd14f9e2 100644 --- a/exec.c +++ b/exec.c @@ -2083,7 +2083,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); /* set dirty bit */ - phys_ram_dirty[page >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 1; } } else { if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && -- cgit v1.2.3 From 662f3c86ecf03979feae8ffdba415ff23cffabdc Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 28 Jan 2005 00:00:27 +0000 Subject: ram dirty flag handling fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1247 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/tcx.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/hw/tcx.c b/hw/tcx.c index ccac0bffa..6b55fc96a 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -104,11 +104,7 @@ void tcx_update_display(void *opaque) if (ts->ds->depth == 0) return; -#ifdef LD_BYPASS_OK page = ts->vram_offset + YOFF*MAXX; -#else - page = ts->addr + YOFF*MAXX; -#endif y_start = -1; page_min = 0x7fffffff; page_max = -1; @@ -131,7 +127,7 @@ void tcx_update_display(void *opaque) case 0: return; } - + for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) { if (cpu_physical_memory_is_dirty(page)) { if (y_start < 0) @@ -180,11 +176,7 @@ void tcx_invalidate_display(void *opaque) int i; for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) { -#ifdef LD_BYPASS_OK cpu_physical_memory_set_dirty(s->vram_offset + i); -#else - cpu_physical_memory_set_dirty(s->addr + i); -#endif } } @@ -224,9 +216,7 @@ static void tcx_reset(void *opaque) memset(s->b, 0, 256); s->r[255] = s->g[255] = s->b[255] = 255; memset(s->vram, 0, MAXX*MAXY); -#ifdef LD_BYPASS_OK - cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY - 1); -#endif + cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY); } void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, -- cgit v1.2.3 From bb05683b1271517b5f78aff1890e37f0d27b4d2d Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 28 Jan 2005 00:01:00 +0000 Subject: flush TLBs at cpu reset git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1248 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index dc7e6dbf6..7673bf2dd 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1553,6 +1553,7 @@ extern int ram_size; void cpu_reset(CPUSPARCState *env) { memset(env, 0, sizeof(*env)); + tlb_flush(env, 1); env->cwp = 0; env->wim = 1; env->regwptr = env->regbase + (env->cwp * 16); -- cgit v1.2.3 From 8df1cd076cc14d1d4fc456c6d7d1ceb257781942 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 28 Jan 2005 22:37:22 +0000 Subject: physical memory access functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1249 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 3 ++ exec.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/helper2.c | 87 ++++++++++++++++------------------------- target-ppc/helper.c | 6 +-- 4 files changed, 144 insertions(+), 57 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index d395c0038..1361cf1be 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -725,6 +725,9 @@ static inline void cpu_physical_memory_write(target_phys_addr_t addr, { cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1); } +uint32_t ldl_phys(target_phys_addr_t addr); +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val); +void stl_phys(target_phys_addr_t addr, uint32_t val); int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write); diff --git a/exec.c b/exec.c index 0dd14f9e2..48cbe8574 100644 --- a/exec.c +++ b/exec.c @@ -2032,6 +2032,21 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, addr += l; } } + +/* never used */ +uint32_t ldl_phys(target_phys_addr_t addr) +{ + return 0; +} + +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) +{ +} + +void stl_phys(target_phys_addr_t addr, uint32_t val) +{ +} + #else void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) @@ -2118,6 +2133,96 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, addr += l; } } + +/* warning: addr must be aligned */ +uint32_t ldl_phys(target_phys_addr_t addr) +{ + int io_index; + uint8_t *ptr; + uint32_t val; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + } else { + /* RAM case */ + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + val = ldl_p(ptr); + } + return val; +} + +/* warning: addr must be aligned. The ram page is not masked as dirty + and the code inside is not invalidated. It is useful if the dirty + bits are used to track modified PTEs */ +void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != 0) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + } else { + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + stl_p(ptr, val); + } +} + +/* warning: addr must be aligned */ +/* XXX: optimize code invalidation test */ +void stl_phys(target_phys_addr_t addr, uint32_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != 0) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* RAM case */ + ptr = phys_ram_base + addr1; + stl_p(ptr, val); + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 1; + } +} + #endif /* virtual memory access for debug */ diff --git a/target-i386/helper2.c b/target-i386/helper2.c index f78786ee6..9ecf05d93 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -490,34 +490,26 @@ void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) tlb_flush_page(env, addr); } -static inline uint8_t *get_phys_mem_ptr(target_phys_addr_t addr) -{ - /* XXX: incorrect */ - return phys_ram_base + addr; -} +#if defined(CONFIG_USER_ONLY) -/* WARNING: addr must be aligned */ -uint32_t ldl_phys_aligned(target_phys_addr_t addr) +int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, + int is_write, int is_user, int is_softmmu) { - uint8_t *ptr; - uint32_t val; - ptr = get_phys_mem_ptr(addr); - if (!ptr) - val = 0; - else - val = ldl_raw(ptr); - return val; + /* user mode only emulation */ + is_write &= 1; + env->cr[2] = addr; + env->error_code = (is_write << PG_ERROR_W_BIT); + env->error_code |= PG_ERROR_U_MASK; + return 1; } -void stl_phys_aligned(target_phys_addr_t addr, uint32_t val) +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - uint8_t *ptr; - ptr = get_phys_mem_ptr(addr); - if (!ptr) - return; - stl_raw(ptr, val); + return addr; } +#else + /* return value: -1 = cannot handle fault 0 = nothing more to do @@ -539,12 +531,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, #endif is_write &= 1; - if (env->user_mode_only) { - /* user mode only emulation */ - error_code = 0; - goto do_fault; - } - if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr; virt_addr = addr & TARGET_PAGE_MASK; @@ -553,7 +539,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, goto do_mapping; } - if (env->cr[4] & CR4_PAE_MASK) { /* XXX: we only use 32 bit physical addresses */ #ifdef TARGET_X86_64 @@ -572,33 +557,33 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; - pml4e = ldl_phys_aligned(pml4e_addr); + pml4e = ldl_phys(pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; } if (!(pml4e & PG_ACCESSED_MASK)) { pml4e |= PG_ACCESSED_MASK; - stl_phys_aligned(pml4e_addr, pml4e); + stl_phys_notdirty(pml4e_addr, pml4e); } pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; - pdpe = ldl_phys_aligned(pdpe_addr); + pdpe = ldl_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; } if (!(pdpe & PG_ACCESSED_MASK)) { pdpe |= PG_ACCESSED_MASK; - stl_phys_aligned(pdpe_addr, pdpe); + stl_phys_notdirty(pdpe_addr, pdpe); } } else #endif { pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & env->a20_mask; - pdpe = ldl_phys_aligned(pdpe_addr); + pdpe = ldl_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; @@ -607,7 +592,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask; - pde = ldl_phys_aligned(pde_addr); + pde = ldl_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; @@ -620,7 +605,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, /* 4 KB page */ if (!(pde & PG_ACCESSED_MASK)) { pde |= PG_ACCESSED_MASK; - stl_phys_aligned(pde_addr, pde); + stl_phys_notdirty(pde_addr, pde); } pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask; @@ -630,7 +615,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, /* page directory entry */ pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask; - pde = ldl_phys_aligned(pde_addr); + pde = ldl_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; @@ -654,7 +639,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, pde |= PG_ACCESSED_MASK; if (is_dirty) pde |= PG_DIRTY_MASK; - stl_phys_aligned(pde_addr, pde); + stl_phys_notdirty(pde_addr, pde); } pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ @@ -663,14 +648,14 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, } else { if (!(pde & PG_ACCESSED_MASK)) { pde |= PG_ACCESSED_MASK; - stl_phys_aligned(pde_addr, pde); + stl_phys_notdirty(pde_addr, pde); } /* page directory entry */ pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; handle_4k_page: - pte = ldl_phys_aligned(pte_addr); + pte = ldl_phys(pte_addr); if (!(pte & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; @@ -692,7 +677,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, pte |= PG_ACCESSED_MASK; if (is_dirty) pte |= PG_DIRTY_MASK; - stl_phys_aligned(pte_addr, pte); + stl_phys_notdirty(pte_addr, pte); } page_size = 4096; virt_addr = addr & ~0xfff; @@ -734,12 +719,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, return 1; } -#if defined(CONFIG_USER_ONLY) -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - return addr; -} -#else target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { uint32_t pde_addr, pte_addr; @@ -762,13 +741,13 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; - pml4e = ldl_phys_aligned(pml4e_addr); + pml4e = ldl_phys(pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) return -1; pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; - pdpe = ldl_phys_aligned(pdpe_addr); + pdpe = ldl_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) return -1; } else @@ -776,14 +755,14 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & env->a20_mask; - pdpe = ldl_phys_aligned(pdpe_addr); + pdpe = ldl_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) return -1; } pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask; - pde = ldl_phys_aligned(pde_addr); + pde = ldl_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) { return -1; } @@ -796,7 +775,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask; page_size = 4096; - pte = ldl_phys_aligned(pte_addr); + pte = ldl_phys(pte_addr); } } else { if (!(env->cr[0] & CR0_PG_MASK)) { @@ -805,7 +784,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } else { /* page directory entry */ pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask; - pde = ldl_phys_aligned(pde_addr); + pde = ldl_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) return -1; if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { @@ -814,7 +793,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } else { /* page directory entry */ pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; - pte = ldl_phys_aligned(pte_addr); + pte = ldl_phys(pte_addr); if (!(pte & PG_PRESENT_MASK)) return -1; page_size = 4096; @@ -827,7 +806,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) paddr = (pte & TARGET_PAGE_MASK) + page_offset; return paddr; } -#endif +#endif /* !CONFIG_USER_ONLY */ #if defined(USE_CODE_COPY) struct fpstate { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 5d41fcb05..f3db55fe4 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -129,8 +129,8 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, int ret = -1; /* No entry found */ for (i = 0; i < 8; i++) { - pte0 = ldl_raw(phys_ram_base + base + (i * 8)); - pte1 = ldl_raw(phys_ram_base + base + (i * 8) + 4); + pte0 = ldl_phys(base + (i * 8)); + pte1 = ldl_phys(base + (i * 8) + 4); #if defined (DEBUG_MMU) if (loglevel > 0) { fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " @@ -220,7 +220,7 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, } } if (store) { - stl_raw(phys_ram_base + base + (good * 8) + 4, keep); + stl_phys_notdirty(base + (good * 8) + 4, keep); } } -- cgit v1.2.3 From 49be80301540be4445b2dc58d050a063988c85b4 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 28 Jan 2005 22:40:22 +0000 Subject: endianness fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1250 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/helper.c | 32 +++++++++++--------------------- target-sparc/op_helper.c | 15 +++++++-------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 5fc1da1a8..f4111b3f6 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -129,8 +129,7 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); /* Ctx pde */ switch (pde & PTE_ENTRYTYPE_MASK) { @@ -142,8 +141,7 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, return 4; case 1: /* L0 PDE */ pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -153,8 +151,7 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, return 4; case 1: /* L1 PDE */ pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -164,8 +161,7 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, return 4; case 1: /* L2 PDE */ pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -193,12 +189,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, /* update page modified and dirty bits */ is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); if (!(pde & PG_ACCESSED_MASK) || is_dirty) { - uint32_t tmppde; pde |= PG_ACCESSED_MASK; if (is_dirty) pde |= PG_MODIFIED_MASK; - tmppde = bswap32(pde); - cpu_physical_memory_write(pde_ptr, (uint8_t *)&tmppde, 4); + stl_phys_notdirty(pde_ptr, pde); } /* check access */ *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); @@ -356,8 +350,8 @@ uint32_t mmu_probe(uint32_t address, int mmulev) /* Context base + context number */ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); + switch (pde & PTE_ENTRYTYPE_MASK) { default: case 0: /* Invalid */ @@ -368,8 +362,7 @@ uint32_t mmu_probe(uint32_t address, int mmulev) if (mmulev == 3) return pde; pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -382,8 +375,7 @@ uint32_t mmu_probe(uint32_t address, int mmulev) if (mmulev == 2) return pde; pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -396,8 +388,7 @@ uint32_t mmu_probe(uint32_t address, int mmulev) if (mmulev == 1) return pde; pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); switch (pde & PTE_ENTRYTYPE_MASK) { default: @@ -424,8 +415,7 @@ void dump_mmu(void) printf("MMU dump:\n"); pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); - cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4); - bswap32s(&pde); + pde = ldl_phys(pde_ptr); printf("Root ptr: 0x%08x, ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { pde_ptr = mmu_probe(va, 2); diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 850d8c03e..fecb80dcd 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -106,9 +106,9 @@ void helper_ld_asi(int asi, int size, int sign) case 0x20 ... 0x2f: /* MMU passthrough */ cpu_physical_memory_read(T0, (void *) &ret, size); if (size == 4) - bswap32s(&ret); - else if (size == 2) - bswap16s((uint16_t *)&ret); + tswap32s(&ret); + else if (size == 2) + tswap16s((uint16_t *)&ret); break; default: ret = 0; @@ -170,7 +170,7 @@ void helper_st_asi(int asi, int size, int sign) int src = T1, dst = T0; uint8_t temp[32]; - bswap32s(&src); + tswap32s(&src); cpu_physical_memory_read(src, (void *) &temp, 32); cpu_physical_memory_write(dst, (void *) &temp, 32); @@ -185,7 +185,7 @@ void helper_st_asi(int asi, int size, int sign) uint64_t val; val = (((uint64_t)T1) << 32) | T2; - bswap64s(&val); + tswap64s(&val); for (i = 0; i < 32; i += 8, dst += 8) { cpu_physical_memory_write(dst, (void *) &val, 8); @@ -196,10 +196,9 @@ void helper_st_asi(int asi, int size, int sign) { int temp = T1; if (size == 4) - bswap32s(&temp); + tswap32s(&temp); else if (size == 2) - bswap16s((uint16_t *)&temp); - + tswap16s((uint16_t *)&temp); cpu_physical_memory_write(T0, (void *) &temp, size); } return; -- cgit v1.2.3 From af7bf89b1f525bb684f48ed0e847ad2d2d11c5e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Jan 2005 22:39:04 +0000 Subject: initial sparc64 support - sparc fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1251 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 36 ++++++---- target-sparc/exec.h | 18 +++-- target-sparc/helper.c | 41 +++++++----- target-sparc/op.c | 167 ++++++++++++++++++++++++----------------------- target-sparc/op_helper.c | 13 +++- target-sparc/op_mem.h | 2 +- target-sparc/translate.c | 160 +++++++++++++++++++++++++++++---------------- 7 files changed, 260 insertions(+), 177 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 6a077c58e..7f8b9060a 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -1,7 +1,17 @@ #ifndef CPU_SPARC_H #define CPU_SPARC_H +#include "config.h" + +#if !defined(TARGET_SPARC64) #define TARGET_LONG_BITS 32 +#define TARGET_FPREGS 32 +#define TARGET_FPREG_T float +#else +#define TARGET_LONG_BITS 64 +#define TARGET_FPREGS 64 +#define TARGET_FPREG_T double +#endif #include "cpu-defs.h" @@ -95,15 +105,14 @@ #define NWINDOWS 32 typedef struct CPUSPARCState { - uint32_t gregs[8]; /* general registers */ - uint32_t *regwptr; /* pointer to current register window */ - float fpr[32]; /* floating point registers */ - uint32_t pc; /* program counter */ - uint32_t npc; /* next program counter */ - uint32_t y; /* multiply/divide register */ + target_ulong gregs[8]; /* general registers */ + target_ulong *regwptr; /* pointer to current register window */ + TARGET_FPREG_T fpr[TARGET_FPREGS]; /* floating point registers */ + target_ulong pc; /* program counter */ + target_ulong npc; /* next program counter */ + target_ulong y; /* multiply/divide register */ uint32_t psr; /* processor state register */ uint32_t fsr; /* FPU state register */ - uint32_t T2; uint32_t cwp; /* index of current register window (extracted from PSR) */ uint32_t wim; /* window invalid mask */ @@ -118,11 +127,11 @@ typedef struct CPUSPARCState { int exception_index; int interrupt_index; int interrupt_request; - uint32_t exception_next_pc; + target_ulong exception_next_pc; struct TranslationBlock *current_tb; void *opaque; /* NOTE: we allow 8 more registers to handle wrapping */ - uint32_t regbase[NWINDOWS * 16 + 8]; + target_ulong regbase[NWINDOWS * 16 + 8]; /* in order to avoid passing too many arguments to the memory write helpers, we store some rarely used information in the CPU @@ -140,9 +149,12 @@ typedef struct CPUSPARCState { /* temporary float registers */ float ft0, ft1, ft2; double dt0, dt1, dt2; +#if defined(TARGET_SPARC64) + target_ulong t0, t1, t2; +#endif /* ice debug support */ - uint32_t breakpoints[MAX_BREAKPOINTS]; + target_ulong breakpoints[MAX_BREAKPOINTS]; int nb_breakpoints; int singlestep_enabled; /* XXX: should use CPU single step mode instead */ @@ -155,7 +167,7 @@ void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f); double cpu_put_fp64(uint64_t mant, uint16_t exp); /* Fake impl 0, version 4 */ -#define GET_PSR(env) ((0 << 28) | (4 << 24) | env->psr | \ +#define GET_PSR(env) ((0 << 28) | (4 << 24) | (env->psr & PSR_ICC) | \ (env->psref? PSR_EF : 0) | \ (env->psrpil << 8) | \ (env->psrs? PSR_S : 0) | \ @@ -167,7 +179,7 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); #endif #define PUT_PSR(env, val) do { int _tmp = val; \ - env->psr = _tmp & ~PSR_ICC; \ + env->psr = _tmp & PSR_ICC; \ env->psref = (_tmp & PSR_EF)? 1 : 0; \ env->psrpil = (_tmp & PSR_PIL) >> 8; \ env->psrs = (_tmp & PSR_S)? 1 : 0; \ diff --git a/target-sparc/exec.h b/target-sparc/exec.h index f8edc1715..1fa7d87dc 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -3,9 +3,15 @@ #include "dyngen-exec.h" register struct CPUSPARCState *env asm(AREG0); +#ifdef TARGET_SPARC64 +#define T0 (env->t0) +#define T1 (env->t1) +#define T2 (env->t2) +#else register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); register uint32_t T2 asm(AREG3); +#endif #define FT0 (env->ft0) #define FT1 (env->ft1) #define FT2 (env->ft2) @@ -32,17 +38,19 @@ void do_fsqrts(void); void do_fsqrtd(void); void do_fcmps(void); void do_fcmpd(void); -void do_ldd_kernel(uint32_t addr); -void do_ldd_user(uint32_t addr); -void do_ldd_raw(uint32_t addr); +void do_ldd_kernel(target_ulong addr); +void do_ldd_user(target_ulong addr); +void do_ldd_raw(target_ulong addr); void do_interrupt(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw); void raise_exception_err(int exception_index, int error_code); void raise_exception(int tt); -void memcpy32(uint32_t *dst, const uint32_t *src); -uint32_t mmu_probe(uint32_t address, int mmulev); +void memcpy32(target_ulong *dst, const target_ulong *src); +target_ulong mmu_probe(target_ulong address, int mmulev); void dump_mmu(void); void helper_debug(); +void do_wrpsr(); +void do_rdpsr(); /* XXX: move that to a generic header */ #if !defined(CONFIG_USER_ONLY) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index f4111b3f6..60096bf3a 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -23,7 +23,7 @@ //#define DEBUG_MMU /* Sparc MMU emulation */ -int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, +int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); /* thread support */ @@ -109,13 +109,14 @@ static const int rw_table[2][8] = { { 0, 1, 0, 1, 0, 0, 0, 0 } }; -int get_physical_address (CPUState *env, uint32_t *physical, int *prot, - int *access_index, uint32_t address, int rw, +int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, + int *access_index, target_ulong address, int rw, int is_user) { int access_perms = 0; target_phys_addr_t pde_ptr; - uint32_t pde, virt_addr; + uint32_t pde; + target_ulong virt_addr; int error_code = 0, is_dirty; unsigned long page_offset; @@ -217,11 +218,12 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, } /* Perform address translation */ -int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, +int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { int exception = 0; - uint32_t virt_addr, paddr; + target_ulong virt_addr; + target_phys_addr_t paddr; unsigned long vaddr; int error_code = 0, prot, ret = 0, access_index; @@ -252,7 +254,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, return error_code; } -void memcpy32(uint32_t *dst, const uint32_t *src) +void memcpy32(target_ulong *dst, const target_ulong *src) { dst[0] = src[0]; dst[1] = src[1]; @@ -328,8 +330,13 @@ void do_interrupt(int intno, int is_int, int error_code, env->psret = 0; cwp = (env->cwp - 1) & (NWINDOWS - 1); set_cwp(cwp); - env->regwptr[9] = env->pc - 4; // XXX? - env->regwptr[10] = env->pc; + if (intno & 0x80) { + env->regwptr[9] = env->pc; + env->regwptr[10] = env->npc; + } else { + env->regwptr[9] = env->pc - 4; // XXX? + env->regwptr[10] = env->pc; + } env->psrps = env->psrs; env->psrs = 1; env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); @@ -343,7 +350,7 @@ void raise_exception_err(int exception_index, int error_code) raise_exception(exception_index); } -uint32_t mmu_probe(uint32_t address, int mmulev) +target_ulong mmu_probe(target_ulong address, int mmulev) { target_phys_addr_t pde_ptr; uint32_t pde; @@ -408,30 +415,30 @@ uint32_t mmu_probe(uint32_t address, int mmulev) void dump_mmu(void) { #ifdef DEBUG_MMU - uint32_t pa, va, va1, va2; - int n, m, o; - target_phys_addr_t pde_ptr; + target_ulong va, va1, va2; + unsigned int n, m, o; + target_phys_addr_t pde_ptr, pa; uint32_t pde; printf("MMU dump:\n"); pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); pde = ldl_phys(pde_ptr); - printf("Root ptr: 0x%08x, ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); + printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { pde_ptr = mmu_probe(va, 2); if (pde_ptr) { pa = cpu_get_phys_page_debug(env, va); - printf("VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va, pa, pde_ptr); + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr); for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { pde_ptr = mmu_probe(va1, 1); if (pde_ptr) { pa = cpu_get_phys_page_debug(env, va1); - printf(" VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va1, pa, pde_ptr); + printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr); for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { pde_ptr = mmu_probe(va2, 0); if (pde_ptr) { pa = cpu_get_phys_page_debug(env, va2); - printf(" VA: 0x%08x, PA: 0x%08x PTE: 0x%08x\n", va2, pa, pde_ptr); + printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr); } } } diff --git a/target-sparc/op.c b/target-sparc/op.c index f8cf2f893..d1d48d2a7 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -217,7 +217,7 @@ #define EIP (env->pc) -#define FLAG_SET(x) (env->psr&x)?1:0 +#define FLAG_SET(x) ((env->psr&x)?1:0) #define FFLAG_SET(x) ((env->fsr&x)?1:0) void OPPROTO op_movl_T0_0(void) @@ -225,11 +225,6 @@ void OPPROTO op_movl_T0_0(void) T0 = 0; } -void OPPROTO op_movl_T0_1(void) -{ - T0 = 1; -} - void OPPROTO op_movl_T0_im(void) { T0 = PARAM1; @@ -245,40 +240,51 @@ void OPPROTO op_movl_T2_im(void) T2 = PARAM1; } -void OPPROTO op_addl_T1_im(void) +void OPPROTO op_add_T1_T0(void) { - T1 += PARAM1; + T0 += T1; } -void OPPROTO op_addl_T1_T2(void) +void OPPROTO op_add_T1_T0_cc(void) { - T1 += T2; -} + target_ulong src1; -void OPPROTO op_subl_T1_T2(void) -{ - T1 -= T2; + src1 = T0; + T0 += T1; + env->psr = 0; + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (T0 < src1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + /* V9 xcc */ + FORCE_RET(); } -void OPPROTO op_add_T1_T0(void) +void OPPROTO op_addx_T1_T0(void) { - T0 += T1; + T0 += T1 + FLAG_SET(PSR_CARRY); } -void OPPROTO op_add_T1_T0_cc(void) +void OPPROTO op_addx_T1_T0_cc(void) { - unsigned int src1; + target_ulong src1; + src1 = T0; - T0 += T1; + T0 += T1 + FLAG_SET(PSR_CARRY); env->psr = 0; if (!T0) env->psr |= PSR_ZERO; - if ((int) T0 < 0) + if ((int32_t) T0 < 0) env->psr |= PSR_NEG; if (T0 < src1) env->psr |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) env->psr |= PSR_OVF; + /* V9 xcc */ FORCE_RET(); } @@ -289,19 +295,44 @@ void OPPROTO op_sub_T1_T0(void) void OPPROTO op_sub_T1_T0_cc(void) { - unsigned int src1; + target_ulong src1; src1 = T0; T0 -= T1; env->psr = 0; if (!T0) env->psr |= PSR_ZERO; - if ((int) T0 < 0) + if ((int32_t) T0 < 0) env->psr |= PSR_NEG; if (src1 < T1) env->psr |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) env->psr |= PSR_OVF; + /* V9 xcc */ + FORCE_RET(); +} + +void OPPROTO op_subx_T1_T0(void) +{ + T0 -= T1 + FLAG_SET(PSR_CARRY); +} + +void OPPROTO op_subx_T1_T0_cc(void) +{ + target_ulong src1; + + src1 = T0; + T0 -= T1 + FLAG_SET(PSR_CARRY); + env->psr = 0; + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (src1 < T1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + /* V9 xcc */ FORCE_RET(); } @@ -335,15 +366,10 @@ void OPPROTO op_xnor_T1_T0(void) T0 ^= ~T1; } -void OPPROTO op_addx_T1_T0(void) -{ - T0 += T1 + ((env->psr & PSR_CARRY) ? 1 : 0); -} - void OPPROTO op_umul_T1_T0(void) { uint64_t res; - res = (uint64_t) T0 *(uint64_t) T1; + res = (uint64_t) T0 * (uint64_t) T1; T0 = res & 0xffffffff; env->y = res >> 32; } @@ -358,7 +384,9 @@ void OPPROTO op_smul_T1_T0(void) void OPPROTO op_mulscc_T1_T0(void) { - unsigned int b1, N, V, b2, src1; + unsigned int b1, N, V, b2; + target_ulong src1; + N = FLAG_SET(PSR_NEG); V = FLAG_SET(PSR_OVF); b1 = N ^ V; @@ -372,7 +400,7 @@ void OPPROTO op_mulscc_T1_T0(void) env->psr = 0; if (!T0) env->psr |= PSR_ZERO; - if ((int) T0 < 0) + if ((int32_t) T0 < 0) env->psr |= PSR_NEG; if (T0 < src1) env->psr |= PSR_CARRY; @@ -405,11 +433,11 @@ void OPPROTO op_sdiv_T1_T0(void) int64_t x0; int32_t x1; - x0 = T0 | ((uint64_t) (env->y) << 32); + x0 = T0 | ((int64_t) (env->y) << 32); x1 = T1; x0 = x0 / x1; if ((int32_t) x0 != x0) { - T0 = x0 >> 63; + T0 = x0 < 0? 0x80000000: 0x7fffffff; T1 = 1; } else { T0 = x0; @@ -423,39 +451,22 @@ void OPPROTO op_div_cc(void) env->psr = 0; if (!T0) env->psr |= PSR_ZERO; - if ((int) T0 < 0) + if ((int32_t) T0 < 0) env->psr |= PSR_NEG; if (T1) env->psr |= PSR_OVF; + /* V9 xcc */ FORCE_RET(); } -void OPPROTO op_subx_T1_T0(void) -{ - T0 -= T1 + ((env->psr & PSR_CARRY) ? 1 : 0); -} - void OPPROTO op_logic_T0_cc(void) { env->psr = 0; if (!T0) env->psr |= PSR_ZERO; - if ((int) T0 < 0) - env->psr |= PSR_NEG; - FORCE_RET(); -} - -void OPPROTO op_set_flags(void) -{ - env->psr = 0; - if (!T0) - env->psr |= PSR_ZERO; - if ((unsigned int) T0 < (unsigned int) T1) - env->psr |= PSR_CARRY; - if ((int) T0 < (int) T1) - env->psr |= PSR_OVF; - if ((int) T0 < 0) + if ((int32_t) T0 < 0) env->psr |= PSR_NEG; + /* V9 xcc */ FORCE_RET(); } @@ -519,12 +530,12 @@ void OPPROTO op_wrwim(void) void OPPROTO op_rdpsr(void) { - T0 = GET_PSR(env); + do_rdpsr(); } void OPPROTO op_wrpsr(void) { - PUT_PSR(env,T0); + do_wrpsr(); FORCE_RET(); } @@ -555,7 +566,7 @@ void raise_exception(int tt) handling ? */ void OPPROTO op_save(void) { - int cwp; + uint32_t cwp; cwp = (env->cwp - 1) & (NWINDOWS - 1); if (env->wim & (1 << cwp)) { raise_exception(TT_WIN_OVF); @@ -566,7 +577,7 @@ void OPPROTO op_save(void) void OPPROTO op_restore(void) { - int cwp; + uint32_t cwp; cwp = (env->cwp + 1) & (NWINDOWS - 1); if (env->wim & (1 << cwp)) { raise_exception(TT_WIN_UNF); @@ -626,84 +637,84 @@ void OPPROTO op_exit_tb(void) void OPPROTO op_eval_be(void) { - T2 = (env->psr & PSR_ZERO); + T2 = FLAG_SET(PSR_ZERO); } void OPPROTO op_eval_ble(void) { - unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); + target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); T2 = Z | (N ^ V); } void OPPROTO op_eval_bl(void) { - unsigned int N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); + target_ulong N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); T2 = N ^ V; } void OPPROTO op_eval_bleu(void) { - unsigned int Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY); + target_ulong Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY); T2 = C | Z; } void OPPROTO op_eval_bcs(void) { - T2 = (env->psr & PSR_CARRY); + T2 = FLAG_SET(PSR_CARRY); } void OPPROTO op_eval_bvs(void) { - T2 = (env->psr & PSR_OVF); + T2 = FLAG_SET(PSR_OVF); } void OPPROTO op_eval_bneg(void) { - T2 = (env->psr & PSR_NEG); + T2 = FLAG_SET(PSR_NEG); } void OPPROTO op_eval_bne(void) { - T2 = !(env->psr & PSR_ZERO); + T2 = !FLAG_SET(PSR_ZERO); } void OPPROTO op_eval_bg(void) { - unsigned int Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); + target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); T2 = !(Z | (N ^ V)); } void OPPROTO op_eval_bge(void) { - unsigned int N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); + target_ulong N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); T2 = !(N ^ V); } void OPPROTO op_eval_bgu(void) { - unsigned int Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY); + target_ulong Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY); T2 = !(C | Z); } void OPPROTO op_eval_bcc(void) { - T2 = !(env->psr & PSR_CARRY); + T2 = !FLAG_SET(PSR_CARRY); } void OPPROTO op_eval_bpos(void) { - T2 = !(env->psr & PSR_NEG); + T2 = !FLAG_SET(PSR_NEG); } void OPPROTO op_eval_bvc(void) { - T2 = !(env->psr & PSR_OVF); + T2 = !FLAG_SET(PSR_OVF); } /* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */ @@ -792,16 +803,6 @@ void OPPROTO op_eval_fbo(void) T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); } -void OPPROTO op_movl_T2_0(void) -{ - T2 = 0; -} - -void OPPROTO op_movl_T2_1(void) -{ - T2 = 1; -} - void OPPROTO op_jmp_im(void) { env->pc = PARAM1; @@ -845,10 +846,10 @@ void OPPROTO op_branch_a(void) { if (T2) { env->npc = PARAM2; /* XXX: optimize */ - JUMP_TB(op_generic_branch_a, PARAM1, 0, PARAM3); + JUMP_TB(op_branch_a, PARAM1, 0, PARAM3); } else { env->npc = PARAM3 + 8; /* XXX: optimize */ - JUMP_TB(op_generic_branch_a, PARAM1, 1, PARAM3 + 4); + JUMP_TB(op_branch_a, PARAM1, 1, PARAM3 + 4); } FORCE_RET(); } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index fecb80dcd..2529cca72 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -209,7 +209,8 @@ void helper_st_asi(int asi, int size, int sign) void helper_rett() { - int cwp; + unsigned int cwp; + env->psret = 1; cwp = (env->cwp + 1) & (NWINDOWS - 1); if (env->wim & (1 << cwp)) { @@ -255,3 +256,13 @@ void helper_debug() env->exception_index = EXCP_DEBUG; cpu_loop_exit(); } + +void do_wrpsr() +{ + PUT_PSR(env, T0); +} + +void do_rdpsr() +{ + T0 = GET_PSR(env); +} diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 995eb27d7..9f6ecefd8 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -36,7 +36,7 @@ void OPPROTO glue(op_ldstub, MEMSUFFIX)(void) void OPPROTO glue(op_swap, MEMSUFFIX)(void) { - unsigned int tmp = glue(ldl, MEMSUFFIX)(T0); + target_ulong tmp = glue(ldl, MEMSUFFIX)(T0); glue(stl, MEMSUFFIX)(T0, T1); /* XXX: Should be Atomically */ T1 = tmp; } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 7673bf2dd..0baf8036e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -423,16 +423,13 @@ static inline void save_npc(DisasContext * dc) static inline void save_state(DisasContext * dc) { - gen_op_jmp_im((uint32_t)dc->pc); + gen_op_jmp_im(dc->pc); save_npc(dc); } static void gen_cond(int cond) { switch (cond) { - case 0x0: - gen_op_movl_T2_0(); - break; case 0x1: gen_op_eval_be(); break; @@ -454,9 +451,6 @@ static void gen_cond(int cond) case 0x7: gen_op_eval_bvs(); break; - case 0x8: - gen_op_movl_T2_1(); - break; case 0x9: gen_op_eval_bne(); break; @@ -485,9 +479,6 @@ static void gen_cond(int cond) static void gen_fcond(int cond) { switch (cond) { - case 0x0: - gen_op_movl_T2_0(); - break; case 0x1: gen_op_eval_fbne(); break; @@ -509,9 +500,6 @@ static void gen_fcond(int cond) case 0x7: gen_op_eval_fbu(); break; - case 0x8: - gen_op_movl_T2_1(); - break; case 0x9: gen_op_eval_fbe(); break; @@ -537,10 +525,11 @@ static void gen_fcond(int cond) } } -static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) +static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); - target += (uint32_t) dc->pc; + target_ulong target = dc->pc + offset; + if (cond == 0x0) { /* unconditional not taken */ if (a) { @@ -574,10 +563,11 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn) } } -static void do_fbranch(DisasContext * dc, uint32_t target, uint32_t insn) +static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); - target += (uint32_t) dc->pc; + target_ulong target = dc->pc + offset; + if (cond == 0x0) { /* unconditional not taken */ if (a) { @@ -611,15 +601,6 @@ static void do_fbranch(DisasContext * dc, uint32_t target, uint32_t insn) } } -#if 0 -static void gen_debug(DisasContext *s, uint32_t pc) -{ - gen_op_jmp_im(pc); - gen_op_debug(); - s->is_br = 1; -} -#endif - #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) static int sign_extend(int x, int len) @@ -640,12 +621,13 @@ static void disas_sparc_insn(DisasContext * dc) case 0: /* branches/sethi */ { unsigned int xop = GET_FIELD(insn, 7, 9); - int target; + int32_t target; target = GET_FIELD(insn, 10, 31); switch (xop) { - case 0x0: - case 0x1: /* UNIMPL */ - case 0x5: /*CBN+x */ + case 0x0: /* UNIMPL */ + case 0x1: /* V9 BPcc */ + case 0x3: /* V9 BPr */ + case 0x5: /* V9 FBPcc */ default: goto illegal_insn; case 0x2: /* BN+x */ @@ -679,13 +661,14 @@ static void disas_sparc_insn(DisasContext * dc) } break; } + break; case 1: /*CALL*/ { - unsigned int target = GET_FIELDs(insn, 2, 31) << 2; + target_long target = GET_FIELDs(insn, 2, 31) << 2; - gen_op_movl_T0_im((long) (dc->pc)); + gen_op_movl_T0_im(dc->pc); gen_movl_T0_reg(15); - target = dc->pc + target; + target += dc->pc; dc->pc = dc->npc; dc->npc = target; } @@ -719,12 +702,13 @@ static void disas_sparc_insn(DisasContext * dc) #endif } save_state(dc); + /* V9 icc/xcc */ cond = GET_FIELD(insn, 3, 6); if (cond == 0x8) { gen_op_trap_T0(); dc->is_br = 1; goto jmp_insn; - } else { + } else if (cond != 0) { gen_cond(cond); gen_op_trapcc_T0(); } @@ -735,9 +719,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_rdy(); gen_movl_T0_reg(rd); break; - case 15: /* stbar */ + case 15: /* stbar / V9 membar */ break; /* no effect? */ default: + case 0x2: /* V9 rdccr */ + case 0x3: /* V9 rdasi */ + case 0x4: /* V9 rdtick */ + case 0x5: /* V9 rdpc */ + case 0x6: /* V9 rdfprs */ goto illegal_insn; } #if !defined(CONFIG_USER_ONLY) @@ -901,6 +890,19 @@ static void disas_sparc_insn(DisasContext * dc) case 0xd3: /* fqtoi */ goto nfpu_insn; default: + case 0x2: /* V9 fmovd */ + case 0x6: /* V9 fnegd */ + case 0xa: /* V9 fabsd */ + case 0x81: /* V9 fstox */ + case 0x82: /* V9 fdtox */ + case 0x84: /* V9 fxtos */ + case 0x88: /* V9 fxtod */ + + case 0x3: /* V9 fmovq */ + case 0x7: /* V9 fnegq */ + case 0xb: /* V9 fabsq */ + case 0x83: /* V9 fqtox */ + case 0x8c: /* V9 fxtoq */ goto illegal_insn; } } else if (xop == 0x35) { /* FPU Operations */ @@ -910,6 +912,10 @@ static void disas_sparc_insn(DisasContext * dc) rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); + /* V9 fmovscc: x5, cond = x >> 1 */ + /* V9 fmovdcc: x6, cond = x >> 1 */ + + /* V9 fmovqcc: x7, cond = x >> 1 */ switch (xop) { case 0x51: gen_op_load_fpr_FT0(rs1); @@ -1028,9 +1034,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_logic_T0_cc(); break; case 0x8: - gen_op_addx_T1_T0(); if (xop & 0x10) - gen_op_set_flags(); + gen_op_addx_T1_T0_cc(); + else + gen_op_addx_T1_T0(); break; case 0xa: gen_op_umul_T1_T0(); @@ -1043,9 +1050,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_logic_T0_cc(); break; case 0xc: - gen_op_subx_T1_T0(); if (xop & 0x10) - gen_op_set_flags(); + gen_op_subx_T1_T0_cc(); + else + gen_op_subx_T1_T0(); break; case 0xe: gen_op_udiv_T1_T0(); @@ -1058,6 +1066,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_div_cc(); break; default: + case 0x9: /* V9 mulx */ + case 0xd: /* V9 udivx */ goto illegal_insn; } gen_movl_T0_reg(rd); @@ -1072,15 +1082,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_mulscc_T1_T0(); gen_movl_T0_reg(rd); break; - case 0x25: /* SLL */ + case 0x25: /* sll, V9 sllx */ gen_op_sll(); gen_movl_T0_reg(rd); break; - case 0x26: + case 0x26: /* srl, V9 srlx */ gen_op_srl(); gen_movl_T0_reg(rd); break; - case 0x27: + case 0x27: /* sra, V9 srax */ gen_op_sra(); gen_movl_T0_reg(rd); break; @@ -1092,12 +1102,16 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_wry(); break; default: + case 0x2: /* V9 wrccr */ + case 0x3: /* V9 wrasi */ + case 0x6: /* V9 wrfprs */ + case 0xf: /* V9 sir */ goto illegal_insn; } } break; #if !defined(CONFIG_USER_ONLY) - case 0x31: + case 0x31: /* wrpsr, V9 saved, restored */ { if (!supervisor(dc)) goto priv_insn; @@ -1105,7 +1119,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_wrpsr(); } break; - case 0x32: + case 0x32: /* wrwim, V9 wrpr */ { if (!supervisor(dc)) goto priv_insn; @@ -1123,6 +1137,12 @@ static void disas_sparc_insn(DisasContext * dc) break; #endif default: + case 0x2a: /* V9 rdpr */ + case 0x2b: /* V9 flushw */ + case 0x2c: /* V9 movcc */ + case 0x2d: /* V9 sdivx */ + case 0x2e: /* V9 popc */ + case 0x2f: /* V9 movr */ goto illegal_insn; } } @@ -1155,7 +1175,7 @@ static void disas_sparc_insn(DisasContext * dc) { gen_op_movl_npc_T0(); if (rd != 0) { - gen_op_movl_T0_im((long) (dc->pc)); + gen_op_movl_T0_im(dc->pc); gen_movl_T0_reg(rd); } dc->pc = dc->npc; @@ -1163,7 +1183,7 @@ static void disas_sparc_insn(DisasContext * dc) } goto jmp_insn; #if !defined(CONFIG_USER_ONLY) - case 0x39: /* rett */ + case 0x39: /* rett, V9 return */ { if (!supervisor(dc)) goto priv_insn; @@ -1186,11 +1206,13 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; default: + case 0x3e: /* V9 done/retry */ goto illegal_insn; } } break; } + break; case 3: /* load/store instructions */ { unsigned int xop = GET_FIELD(insn, 7, 12); @@ -1297,6 +1319,16 @@ static void disas_sparc_insn(DisasContext * dc) (void) &gen_op_lddfa; #endif default: + case 0x08: /* V9 ldsw */ + case 0x0b: /* V9 ldx */ + case 0x18: /* V9 ldswa */ + case 0x1b: /* V9 ldxa */ + case 0x2d: /* V9 prefetch */ + case 0x30: /* V9 ldfa */ + case 0x33: /* V9 lddfa */ + case 0x3d: /* V9 prefetcha */ + + case 0x32: /* V9 ldqfa */ goto illegal_insn; } gen_movl_T1_reg(rd); @@ -1313,6 +1345,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldfsr(); gen_op_store_FT0_fpr(rd); break; + case 0x22: /* load quad fpreg */ + goto nfpu_insn; case 0x23: /* load double fpreg */ gen_op_ldst(lddf); gen_op_store_DT0_fpr(rd); @@ -1362,6 +1396,8 @@ static void disas_sparc_insn(DisasContext * dc) break; #endif default: + case 0x0e: /* V9 stx */ + case 0x1e: /* V9 stxa */ goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { @@ -1373,16 +1409,23 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_FT0(rd); gen_op_ldst(stf); break; - case 0x25: + case 0x25: /* stfsr, V9 stxfsr */ gen_op_load_fpr_FT0(rd); gen_op_stfsr(); break; + case 0x26: /* stdfq */ + goto nfpu_insn; case 0x27: gen_op_load_fpr_DT0(rd); gen_op_ldst(stdf); break; - case 0x26: /* stdfq */ default: + case 0x34: /* V9 stfa */ + case 0x37: /* V9 stdfa */ + case 0x3c: /* V9 casa */ + case 0x3e: /* V9 casxa */ + + case 0x36: /* V9 stqfa */ goto illegal_insn; } } else if (xop > 0x33 && xop < 0x38) { @@ -1392,6 +1435,7 @@ static void disas_sparc_insn(DisasContext * dc) else goto illegal_insn; } + break; } /* default case for non jump instructions */ if (dc->npc == DYNAMIC_PC) { @@ -1589,22 +1633,22 @@ void cpu_dump_state(CPUState *env, FILE *f, { int i, x; - cpu_fprintf(f, "pc: 0x%08x npc: 0x%08x\n", (int) env->pc, (int) env->npc); + cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, env->npc); cpu_fprintf(f, "General Registers:\n"); for (i = 0; i < 4; i++) - cpu_fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); cpu_fprintf(f, "\n"); for (; i < 8; i++) - cpu_fprintf(f, "%%g%c: 0x%08x\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); cpu_fprintf(f, "\nCurrent Register Window:\n"); for (x = 0; x < 3; x++) { for (i = 0; i < 4; i++) - cpu_fprintf(f, "%%%c%d: 0x%08x\t", + cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, env->regwptr[i + x * 8]); cpu_fprintf(f, "\n"); for (; i < 8; i++) - cpu_fprintf(f, "%%%c%d: 0x%08x\t", + cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, env->regwptr[i + x * 8]); cpu_fprintf(f, "\n"); @@ -1626,19 +1670,19 @@ void cpu_dump_state(CPUState *env, FILE *f, } #if defined(CONFIG_USER_ONLY) -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } #else -extern int get_physical_address (CPUState *env, uint32_t *physical, int *prot, - int *access_index, uint32_t address, int rw, +extern int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, + int *access_index, target_ulong address, int rw, int is_user); -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - uint32_t phys_addr; + target_phys_addr_t phys_addr; int prot, access_index; if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) -- cgit v1.2.3 From 3a5c3138520104e9ed453867a50f4303e574c5ec Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Jan 2005 22:39:56 +0000 Subject: 64 bit fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1252 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 348f328f5..3dfac0af5 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -97,7 +97,7 @@ static void slavio_serial_reset(void *opaque) slavio_serial_reset_chn(&s->chn[1]); } -static void slavio_serial_mem_writeb(void *opaque, uint32_t addr, uint32_t val) +static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { SerialState *ser = opaque; ChannelState *s; @@ -170,7 +170,7 @@ static void slavio_serial_mem_writeb(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t slavio_serial_mem_readb(void *opaque, uint32_t addr) +static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) { SerialState *ser = opaque; ChannelState *s; -- cgit v1.2.3 From c1135f6152bcb7ea64c36c6330cab20cc8f587e2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Jan 2005 22:41:54 +0000 Subject: removed debug code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1253 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index c428b3e38..df1642851 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -421,7 +421,7 @@ int cpu_exec(CPUState *env1) spin_unlock(&tb_lock); } #ifdef DEBUG_EXEC - if ((loglevel & CPU_LOG_EXEC) && (env->hflags & HF_LMA_MASK)) { + 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)); -- cgit v1.2.3 From 64b3ab24391c47869a09d082ee073e9832718fc2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Jan 2005 22:43:42 +0000 Subject: sparc64 support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1254 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 18 ++++++++++++++---- configure | 10 ++++++++-- thunk.c | 2 +- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Makefile.target b/Makefile.target index 6c49acfb2..0efc9d1c9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -4,6 +4,9 @@ TARGET_BASE_ARCH:=$(TARGET_ARCH) ifeq ($(TARGET_ARCH), x86_64) TARGET_BASE_ARCH:=i386 endif +ifeq ($(TARGET_ARCH), sparc64) +TARGET_BASE_ARCH:=sparc +endif TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH) @@ -102,6 +105,13 @@ endif endif # ARCH = x86_64 endif # TARGET_ARCH = sparc + +ifeq ($(TARGET_ARCH), sparc64) +ifdef CONFIG_SOFTMMU +PROGS+=$(QEMU_SYSTEM) +endif +endif # TARGET_ARCH = sparc64 + endif # !CONFIG_USER_ONLY ifdef CONFIG_STATIC @@ -245,7 +255,7 @@ ifeq ($(TARGET_ARCH), ppc) LIBOBJS+= op_helper.o helper.o endif -ifeq ($(TARGET_ARCH), sparc) +ifeq ($(TARGET_BASE_ARCH), sparc) LIBOBJS+= op_helper.o helper.o endif @@ -266,7 +276,7 @@ endif ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc) LIBOBJS+=ppc-dis.o endif -ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc) +ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc) LIBOBJS+=sparc-dis.o endif ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm) @@ -323,7 +333,7 @@ VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o endif -ifeq ($(TARGET_ARCH), sparc) +ifeq ($(TARGET_BASE_ARCH), sparc) VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o endif ifdef CONFIG_GDBSTUB @@ -399,7 +409,7 @@ ifeq ($(TARGET_ARCH), arm) op.o: op.c op_template.h endif -ifeq ($(TARGET_ARCH), sparc) +ifeq ($(TARGET_BASE_ARCH), sparc) op.o: op.c op_template.h op_mem.h endif diff --git a/configure b/configure index fa64f6d48..5149eb0a3 100755 --- a/configure +++ b/configure @@ -190,10 +190,10 @@ fi if test -z "$target_list" ; then # these targets are portable - target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu sparc64-softmmu" # the following are Linux specific if [ "$linux" = "yes" ] ; then - target_list="i386-user i386 arm-user armeb-user sparc-user ppc-user $target_list" + target_list="i386-user i386 arm-user armeb-user sparc-user ppc-user sparc64-user $target_list" fi fi @@ -500,6 +500,7 @@ 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_softmmu="no" if expr $target : '.*-softmmu' > /dev/null ; then @@ -544,6 +545,11 @@ 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 diff --git a/thunk.c b/thunk.c index 2dbc378cd..bc9bd2881 100644 --- a/thunk.c +++ b/thunk.c @@ -153,7 +153,7 @@ const argtype *thunk_convert(void *dst, const void *src, } break; #else -#error unsupported conversion +#warning unsupported conversion #endif case TYPE_ARRAY: { -- cgit v1.2.3 From 4fa5d7722db71a4bd6f01e607cf01c758c150dd1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Jan 2005 22:57:54 +0000 Subject: fixed sparc cpu load/save git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1255 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 74 ++++++++++++++++++++++++++++++++++---------------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/vl.c b/vl.c index 107845eb4..21c77758d 100644 --- a/vl.c +++ b/vl.c @@ -2328,28 +2328,27 @@ void cpu_save(QEMUFile *f, void *opaque) int i; uint32_t tmp; - for(i = 1; i < 8; i++) - qemu_put_be32s(f, &env->gregs[i]); - tmp = env->regwptr - env->regbase; - qemu_put_be32s(f, &tmp); - for(i = 1; i < NWINDOWS * 16 + 8; i++) - qemu_put_be32s(f, &env->regbase[i]); + for(i = 0; i < 8; i++) + qemu_put_betls(f, &env->gregs[i]); + for(i = 0; i < NWINDOWS * 16; i++) + qemu_put_betls(f, &env->regbase[i]); /* FPU */ - for(i = 0; i < 32; i++) { - uint64_t mant; - uint16_t exp; - cpu_get_fp64(&mant, &exp, env->fpr[i]); - qemu_put_be64(f, mant); - qemu_put_be16(f, exp); - } - qemu_put_be32s(f, &env->pc); - qemu_put_be32s(f, &env->npc); - qemu_put_be32s(f, &env->y); + for(i = 0; i < TARGET_FPREGS; i++) { + union { + TARGET_FPREG_T f; + target_ulong i; + } u; + u.f = env->fpr[i]; + qemu_put_betl(f, u.i); + } + + qemu_put_betls(f, &env->pc); + qemu_put_betls(f, &env->npc); + qemu_put_betls(f, &env->y); tmp = GET_PSR(env); - qemu_put_be32s(f, &tmp); + qemu_put_be32(f, tmp); qemu_put_be32s(f, &env->fsr); - qemu_put_be32s(f, &env->cwp); qemu_put_be32s(f, &env->wim); qemu_put_be32s(f, &env->tbr); /* MMU */ @@ -2363,34 +2362,35 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) int i; uint32_t tmp; - for(i = 1; i < 8; i++) - qemu_get_be32s(f, &env->gregs[i]); - qemu_get_be32s(f, &tmp); - env->regwptr = env->regbase + tmp; - for(i = 1; i < NWINDOWS * 16 + 8; i++) - qemu_get_be32s(f, &env->regbase[i]); + for(i = 0; i < 8; i++) + qemu_get_betls(f, &env->gregs[i]); + for(i = 0; i < NWINDOWS * 16; i++) + qemu_get_betls(f, &env->regbase[i]); /* FPU */ - for(i = 0; i < 32; i++) { - uint64_t mant; - uint16_t exp; - - qemu_get_be64s(f, &mant); - qemu_get_be16s(f, &exp); - env->fpr[i] = cpu_put_fp64(mant, exp); - } - qemu_get_be32s(f, &env->pc); - qemu_get_be32s(f, &env->npc); - qemu_get_be32s(f, &env->y); - qemu_get_be32s(f, &tmp); + for(i = 0; i < TARGET_FPREGS; i++) { + union { + TARGET_FPREG_T f; + target_ulong i; + } u; + u.i = qemu_get_betl(f); + env->fpr[i] = u.f; + } + + qemu_get_betls(f, &env->pc); + qemu_get_betls(f, &env->npc); + qemu_get_betls(f, &env->y); + tmp = qemu_get_be32(f); + env->cwp = 0; /* needed to ensure that the wrapping registers are + correctly updated */ PUT_PSR(env, tmp); qemu_get_be32s(f, &env->fsr); - qemu_get_be32s(f, &env->cwp); qemu_get_be32s(f, &env->wim); qemu_get_be32s(f, &env->tbr); /* MMU */ for(i = 0; i < 16; i++) qemu_get_be32s(f, &env->mmuregs[i]); + tlb_flush(env, 1); return 0; } -- cgit v1.2.3 From a315a14547b07377eb30a517ffcd2344a819266d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Jan 2005 22:59:18 +0000 Subject: initial sparc64 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1256 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 23 ++++ linux-user/signal.c | 29 ++-- linux-user/sparc64/syscall.h | 10 ++ linux-user/sparc64/syscall_nr.h | 286 ++++++++++++++++++++++++++++++++++++++++ linux-user/sparc64/termbits.h | 279 +++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 55 +++++++- 6 files changed, 664 insertions(+), 18 deletions(-) create mode 100644 linux-user/sparc64/syscall.h create mode 100644 linux-user/sparc64/syscall_nr.h create mode 100644 linux-user/sparc64/termbits.h diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 09c33aa90..684e70eeb 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -94,11 +94,33 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif #ifdef TARGET_SPARC +#ifdef TARGET_SPARC64 #define ELF_START_MMAP 0x80000000 #define elf_check_arch(x) ( (x) == EM_SPARC ) +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARC + +/*XXX*/ +#define ELF_PLAT_INIT(_r) + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->tstate = 0; + regs->pc = infop->entry; + regs->npc = regs->pc + 4; + regs->y = 0; + regs->u_regs[14] = infop->start_stack - 16 * 4; +} + +#else +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SPARC ) + #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_SPARC @@ -115,6 +137,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->u_regs[14] = infop->start_stack - 16 * 4; } +#endif #endif #ifdef TARGET_PPC diff --git a/linux-user/signal.c b/linux-user/signal.c index b2dcaa36a..d3ca2bfef 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -131,7 +131,7 @@ static void host_to_target_sigset_internal(target_sigset_t *d, d->sig[0] = target_sigmask; d->sig[1] = sigmask >> 32; #else -#error host_to_target_sigset +#warning host_to_target_sigset #endif } @@ -165,7 +165,7 @@ void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) #elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32); #else -#error target_to_host_sigset +#warning target_to_host_sigset #endif /* TARGET_LONG_BITS */ } @@ -1391,10 +1391,10 @@ setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) err |= __put_user(env->pc, &si->si_regs.pc); err |= __put_user(env->npc, &si->si_regs.npc); err |= __put_user(env->y, &si->si_regs.y); - for (i=0; i < 7; i++) { + for (i=0; i < 8; i++) { err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]); } - for (i=0; i < 7; i++) { + for (i=0; i < 8; i++) { err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); } err |= __put_user(mask, &si->si_mask); @@ -1452,10 +1452,10 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, err |= __put_user(set->sig[i + 1], &sf->extramask[i]); } - for (i = 0; i < 7; i++) { + for (i = 0; i < 8; i++) { err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]); } - for (i = 0; i < 7; i++) { + for (i = 0; i < 8; i++) { err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]); } if (err) @@ -1488,7 +1488,6 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); // tb_flush(env); } - //cpu_dump_state(env, stderr, fprintf, 0); return; //sigill_and_return: @@ -1569,7 +1568,6 @@ long do_sigreturn(CPUState *env) err = __get_user(pc, &sf->info.si_regs.pc); err |= __get_user(npc, &sf->info.si_regs.npc); - // fprintf(stderr, "pc: %lx npc %lx\n", pc, npc); if ((pc | npc) & 3) goto segv_and_exit; @@ -1577,16 +1575,16 @@ long do_sigreturn(CPUState *env) err |= __get_user(up_psr, &sf->info.si_regs.psr); /* User can only change condition codes and FPU enabling in %psr. */ - env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */)) - | (env->psr & (PSR_ICC /* | PSR_EF */)); - fprintf(stderr, "psr: %x\n", env->psr); - env->pc = pc-4; - env->npc = pc; + env->psr = (up_psr & (PSR_ICC /* | PSR_EF */)) + | (env->psr & ~(PSR_ICC /* | PSR_EF */)); + + env->pc = pc; + env->npc = npc; err |= __get_user(env->y, &sf->info.si_regs.y); - for (i=0; i < 7; i++) { + for (i=0; i < 8; i++) { err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); } - for (i=0; i < 7; i++) { + for (i=0; i < 8; i++) { err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); } @@ -1609,7 +1607,6 @@ long do_sigreturn(CPUState *env) if (err) goto segv_and_exit; - // fprintf(stderr, "returning %lx\n", env->regwptr[0]); return env->regwptr[0]; segv_and_exit: diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h new file mode 100644 index 000000000..c361558b6 --- /dev/null +++ b/linux-user/sparc64/syscall.h @@ -0,0 +1,10 @@ +struct target_pt_regs { + target_ulong u_regs[16]; + target_ulong tstate; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong fprs; +}; + +#define UNAME_MACHINE "sun4u" diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h new file mode 100644 index 000000000..9274c85fc --- /dev/null +++ b/linux-user/sparc64/syscall_nr.h @@ -0,0 +1,286 @@ +#define TARGET_NR_restart_syscall 0 /* Linux Specific */ +#define TARGET_NR_exit 1 /* Common */ +#define TARGET_NR_fork 2 /* Common */ +#define TARGET_NR_read 3 /* Common */ +#define TARGET_NR_write 4 /* Common */ +#define TARGET_NR_open 5 /* Common */ +#define TARGET_NR_close 6 /* Common */ +#define TARGET_NR_wait4 7 /* Common */ +#define TARGET_NR_creat 8 /* Common */ +#define TARGET_NR_link 9 /* Common */ +#define TARGET_NR_unlink 10 /* Common */ +#define TARGET_NR_execv 11 /* SunOS Specific */ +#define TARGET_NR_chdir 12 /* Common */ +#define TARGET_NR_chown 13 /* Common */ +#define TARGET_NR_mknod 14 /* Common */ +#define TARGET_NR_chmod 15 /* Common */ +#define TARGET_NR_lchown 16 /* Common */ +#define TARGET_NR_brk 17 /* Common */ +#define TARGET_NR_perfctr 18 /* Performance counter operations */ +#define TARGET_NR_lseek 19 /* Common */ +#define TARGET_NR_getpid 20 /* Common */ +#define TARGET_NR_capget 21 /* Linux Specific */ +#define TARGET_NR_capset 22 /* Linux Specific */ +#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */ +#define TARGET_NR_getuid 24 /* Common */ +/* #define TARGET_NR_time alias 25 ENOSYS under SunOS */ +#define TARGET_NR_ptrace 26 /* Common */ +#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */ +#define TARGET_NR_sigaltstack 28 /* Common */ +#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */ +#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */ +/* #define TARGET_NR_lchown32 31 Linux sparc32 specific */ +/* #define TARGET_NR_fchown32 32 Linux sparc32 specific */ +#define TARGET_NR_access 33 /* Common */ +#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */ +/* #define TARGET_NR_chown32 35 Linux sparc32 specific */ +#define TARGET_NR_sync 36 /* Common */ +#define TARGET_NR_kill 37 /* Common */ +#define TARGET_NR_stat 38 /* Common */ +#define TARGET_NR_sendfile 39 /* Linux Specific */ +#define TARGET_NR_lstat 40 /* Common */ +#define TARGET_NR_dup 41 /* Common */ +#define TARGET_NR_pipe 42 /* Common */ +#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */ +/* #define TARGET_NR_getuid32 44 Linux sparc32 specific */ +#define TARGET_NR_umount2 45 /* Linux Specific */ +#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */ +#define TARGET_NR_getgid 47 /* Common */ +#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */ +#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */ +#define TARGET_NR_getegid 50 /* SunOS calls getgid() */ +#define TARGET_NR_acct 51 /* Common */ +#define TARGET_NR_memory_ordering 52 /* Linux Specific */ +/* #define TARGET_NR_getgid32 53 Linux sparc32 specific */ +#define TARGET_NR_ioctl 54 /* Common */ +#define TARGET_NR_reboot 55 /* Common */ +/* #define TARGET_NR_mmap2 56 Linux sparc32 Specific */ +#define TARGET_NR_symlink 57 /* Common */ +#define TARGET_NR_readlink 58 /* Common */ +#define TARGET_NR_execve 59 /* Common */ +#define TARGET_NR_umask 60 /* Common */ +#define TARGET_NR_chroot 61 /* Common */ +#define TARGET_NR_fstat 62 /* Common */ +/* #define TARGET_NR_fstat64 63 Linux sparc32 Specific */ +#define TARGET_NR_getpagesize 64 /* Common */ +#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */ +#define TARGET_NR_vfork 66 /* Common */ +#define TARGET_NR_pread64 67 /* Linux Specific */ +#define TARGET_NR_pwrite64 68 /* Linux Specific */ +/* #define TARGET_NR_geteuid32 69 Linux sparc32, sbrk under SunOS */ +/* #define TARGET_NR_getegid32 70 Linux sparc32, sstk under SunOS */ +#define TARGET_NR_mmap 71 /* Common */ +/* #define TARGET_NR_setreuid32 72 Linux sparc32, vadvise under SunOS */ +#define TARGET_NR_munmap 73 /* Common */ +#define TARGET_NR_mprotect 74 /* Common */ +#define TARGET_NR_madvise 75 /* Common */ +#define TARGET_NR_vhangup 76 /* Common */ +/* #define TARGET_NR_truncate64 77 Linux sparc32 Specific */ +#define TARGET_NR_mincore 78 /* Common */ +#define TARGET_NR_getgroups 79 /* Common */ +#define TARGET_NR_setgroups 80 /* Common */ +#define TARGET_NR_getpgrp 81 /* Common */ +/* #define TARGET_NR_setgroups32 82 Linux sparc32, setpgrp under SunOS */ +#define TARGET_NR_setitimer 83 /* Common */ +/* #define TARGET_NR_ftruncate64 84 Linux sparc32 Specific */ +#define TARGET_NR_swapon 85 /* Common */ +#define TARGET_NR_getitimer 86 /* Common */ +/* #define TARGET_NR_setuid32 87 Linux sparc32, gethostname under SunOS */ +#define TARGET_NR_sethostname 88 /* Common */ +/* #define TARGET_NR_setgid32 89 Linux sparc32, getdtablesize under SunOS */ +#define TARGET_NR_dup2 90 /* Common */ +/* #define TARGET_NR_setfsuid32 91 Linux sparc32, getdopt under SunOS */ +#define TARGET_NR_fcntl 92 /* Common */ +#define TARGET_NR_select 93 /* Common */ +/* #define TARGET_NR_setfsgid32 94 Linux sparc32, setdopt under SunOS */ +#define TARGET_NR_fsync 95 /* Common */ +#define TARGET_NR_setpriority 96 /* Common */ +#define TARGET_NR_socket 97 /* Common */ +#define TARGET_NR_connect 98 /* Common */ +#define TARGET_NR_accept 99 /* Common */ +#define TARGET_NR_getpriority 100 /* Common */ +#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */ +#define TARGET_NR_rt_sigaction 102 /* Linux Specific */ +#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */ +#define TARGET_NR_rt_sigpending 104 /* Linux Specific */ +#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */ +#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */ +#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */ +#define TARGET_NR_setresuid 108 /* Linux Specific, sigvec under SunOS */ +#define TARGET_NR_getresuid 109 /* Linux Specific, sigblock under SunOS */ +#define TARGET_NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */ +#define TARGET_NR_getresgid 111 /* Linux Specific, sigpause under SunOS */ +/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */ +#define TARGET_NR_recvmsg 113 /* Common */ +#define TARGET_NR_sendmsg 114 /* Common */ +/* #define TARGET_NR_getgroups32 115 Linux sparc32, vtrace under SunOS */ +#define TARGET_NR_gettimeofday 116 /* Common */ +#define TARGET_NR_getrusage 117 /* Common */ +#define TARGET_NR_getsockopt 118 /* Common */ +#define TARGET_NR_getcwd 119 /* Linux Specific */ +#define TARGET_NR_readv 120 /* Common */ +#define TARGET_NR_writev 121 /* Common */ +#define TARGET_NR_settimeofday 122 /* Common */ +#define TARGET_NR_fchown 123 /* Common */ +#define TARGET_NR_fchmod 124 /* Common */ +#define TARGET_NR_recvfrom 125 /* Common */ +#define TARGET_NR_setreuid 126 /* Common */ +#define TARGET_NR_setregid 127 /* Common */ +#define TARGET_NR_rename 128 /* Common */ +#define TARGET_NR_truncate 129 /* Common */ +#define TARGET_NR_ftruncate 130 /* Common */ +#define TARGET_NR_flock 131 /* Common */ +/* #define TARGET_NR_lstat64 132 Linux sparc32 Specific */ +#define TARGET_NR_sendto 133 /* Common */ +#define TARGET_NR_shutdown 134 /* Common */ +#define TARGET_NR_socketpair 135 /* Common */ +#define TARGET_NR_mkdir 136 /* Common */ +#define TARGET_NR_rmdir 137 /* Common */ +#define TARGET_NR_utimes 138 /* SunOS Specific */ +/* #define TARGET_NR_stat64 139 Linux sparc32 Specific */ +#define TARGET_NR_sendfile64 140 /* adjtime under SunOS */ +#define TARGET_NR_getpeername 141 /* Common */ +#define TARGET_NR_futex 142 /* gethostid under SunOS */ +#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */ +#define TARGET_NR_getrlimit 144 /* Common */ +#define TARGET_NR_setrlimit 145 /* Common */ +#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */ +#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */ +#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */ +#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */ +#define TARGET_NR_getsockname 150 /* Common */ +/* #define TARGET_NR_getmsg 151 SunOS Specific */ +/* #define TARGET_NR_putmsg 152 SunOS Specific */ +#define TARGET_NR_poll 153 /* Common */ +#define TARGET_NR_getdents64 154 /* Linux specific */ +/* #define TARGET_NR_fcntl64 155 Linux sparc32 Specific */ +/* #define TARGET_NR_getdirentries 156 SunOS Specific */ +#define TARGET_NR_statfs 157 /* Common */ +#define TARGET_NR_fstatfs 158 /* Common */ +#define TARGET_NR_umount 159 /* Common */ +#define TARGET_NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS */ +#define TARGET_NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS */ +#define TARGET_NR_getdomainname 162 /* SunOS Specific */ +#define TARGET_NR_setdomainname 163 /* Common */ +#define TARGET_NR_utrap_install 164 /* SYSV ABI/v9 required */ +#define TARGET_NR_quotactl 165 /* Common */ +#define TARGET_NR_set_tid_address 166 /* Linux specific, exportfs under SunOS */ +#define TARGET_NR_mount 167 /* Common */ +#define TARGET_NR_ustat 168 /* Common */ +#define TARGET_NR_setxattr 169 /* SunOS: semsys */ +#define TARGET_NR_lsetxattr 170 /* SunOS: msgsys */ +#define TARGET_NR_fsetxattr 171 /* SunOS: shmsys */ +#define TARGET_NR_getxattr 172 /* SunOS: auditsys */ +#define TARGET_NR_lgetxattr 173 /* SunOS: rfssys */ +#define TARGET_NR_getdents 174 /* Common */ +#define TARGET_NR_setsid 175 /* Common */ +#define TARGET_NR_fchdir 176 /* Common */ +#define TARGET_NR_fgetxattr 177 /* SunOS: fchroot */ +#define TARGET_NR_listxattr 178 /* SunOS: vpixsys */ +#define TARGET_NR_llistxattr 179 /* SunOS: aioread */ +#define TARGET_NR_flistxattr 180 /* SunOS: aiowrite */ +#define TARGET_NR_removexattr 181 /* SunOS: aiowait */ +#define TARGET_NR_lremovexattr 182 /* SunOS: aiocancel */ +#define TARGET_NR_sigpending 183 /* Common */ +#define TARGET_NR_query_module 184 /* Linux Specific */ +#define TARGET_NR_setpgid 185 /* Common */ +#define TARGET_NR_fremovexattr 186 /* SunOS: pathconf */ +#define TARGET_NR_tkill 187 /* SunOS: fpathconf */ +#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */ +#define TARGET_NR_uname 189 /* Linux Specific */ +#define TARGET_NR_init_module 190 /* Linux Specific */ +#define TARGET_NR_personality 191 /* Linux Specific */ +#define TARGET_NR_remap_file_pages 192 /* Linux Specific */ +#define TARGET_NR_epoll_create 193 /* Linux Specific */ +#define TARGET_NR_epoll_ctl 194 /* Linux Specific */ +#define TARGET_NR_epoll_wait 195 /* Linux Specific */ +/* #define TARGET_NR_ulimit 196 Linux Specific */ +#define TARGET_NR_getppid 197 /* Linux Specific */ +#define TARGET_NR_sigaction 198 /* Linux Specific */ +#define TARGET_NR_sgetmask 199 /* Linux Specific */ +#define TARGET_NR_ssetmask 200 /* Linux Specific */ +#define TARGET_NR_sigsuspend 201 /* Linux Specific */ +#define TARGET_NR_oldlstat 202 /* Linux Specific */ +#define TARGET_NR_uselib 203 /* Linux Specific */ +#define TARGET_NR_readdir 204 /* Linux Specific */ +#define TARGET_NR_readahead 205 /* Linux Specific */ +#define TARGET_NR_socketcall 206 /* Linux Specific */ +#define TARGET_NR_syslog 207 /* Linux Specific */ +#define TARGET_NR_lookup_dcookie 208 /* Linux Specific */ +#define TARGET_NR_fadvise64 209 /* Linux Specific */ +#define TARGET_NR_fadvise64_64 210 /* Linux Specific */ +#define TARGET_NR_tgkill 211 /* Linux Specific */ +#define TARGET_NR_waitpid 212 /* Linux Specific */ +#define TARGET_NR_swapoff 213 /* Linux Specific */ +#define TARGET_NR_sysinfo 214 /* Linux Specific */ +#define TARGET_NR_ipc 215 /* Linux Specific */ +#define TARGET_NR_sigreturn 216 /* Linux Specific */ +#define TARGET_NR_clone 217 /* Linux Specific */ +/* #define TARGET_NR_modify_ldt 218 Linux Specific - i386 specific, unused */ +#define TARGET_NR_adjtimex 219 /* Linux Specific */ +#define TARGET_NR_sigprocmask 220 /* Linux Specific */ +#define TARGET_NR_create_module 221 /* Linux Specific */ +#define TARGET_NR_delete_module 222 /* Linux Specific */ +#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */ +#define TARGET_NR_getpgid 224 /* Linux Specific */ +#define TARGET_NR_bdflush 225 /* Linux Specific */ +#define TARGET_NR_sysfs 226 /* Linux Specific */ +#define TARGET_NR_afs_syscall 227 /* Linux Specific */ +#define TARGET_NR_setfsuid 228 /* Linux Specific */ +#define TARGET_NR_setfsgid 229 /* Linux Specific */ +#define TARGET_NR__newselect 230 /* Linux Specific */ +#ifdef __KERNEL__ +#define TARGET_NR_time 231 /* Linux sparc32 */ +#endif +/* #define TARGET_NR_oldstat 232 Linux Specific */ +#define TARGET_NR_stime 233 /* Linux Specific */ +#define TARGET_NR_statfs64 234 /* Linux Specific */ +#define TARGET_NR_fstatfs64 235 /* Linux Specific */ +#define TARGET_NR__llseek 236 /* Linux Specific */ +#define TARGET_NR_mlock 237 +#define TARGET_NR_munlock 238 +#define TARGET_NR_mlockall 239 +#define TARGET_NR_munlockall 240 +#define TARGET_NR_sched_setparam 241 +#define TARGET_NR_sched_getparam 242 +#define TARGET_NR_sched_setscheduler 243 +#define TARGET_NR_sched_getscheduler 244 +#define TARGET_NR_sched_yield 245 +#define TARGET_NR_sched_get_priority_max 246 +#define TARGET_NR_sched_get_priority_min 247 +#define TARGET_NR_sched_rr_get_interval 248 +#define TARGET_NR_nanosleep 249 +#define TARGET_NR_mremap 250 +#define TARGET_NR__sysctl 251 +#define TARGET_NR_getsid 252 +#define TARGET_NR_fdatasync 253 +#define TARGET_NR_nfsservctl 254 +#define TARGET_NR_aplib 255 +#define TARGET_NR_clock_settime 256 +#define TARGET_NR_clock_gettime 257 +#define TARGET_NR_clock_getres 258 +#define TARGET_NR_clock_nanosleep 259 +#define TARGET_NR_sched_getaffinity 260 +#define TARGET_NR_sched_setaffinity 261 +#define TARGET_NR_timer_settime 262 +#define TARGET_NR_timer_gettime 263 +#define TARGET_NR_timer_getoverrun 264 +#define TARGET_NR_timer_delete 265 +#define TARGET_NR_timer_create 266 +/* #define TARGET_NR_vserver 267 Reserved for VSERVER */ +#define TARGET_NR_io_setup 268 +#define TARGET_NR_io_destroy 269 +#define TARGET_NR_io_submit 270 +#define TARGET_NR_io_cancel 271 +#define TARGET_NR_io_getevents 272 +#define TARGET_NR_mq_open 273 +#define TARGET_NR_mq_unlink 274 +#define TARGET_NR_mq_timedsend 275 +#define TARGET_NR_mq_timedreceive 276 +#define TARGET_NR_mq_notify 277 +#define TARGET_NR_mq_getsetattr 278 +#define TARGET_NR_waitid 279 +/*#define TARGET_NR_sys_setaltroot 280 available (was setaltroot) */ +#define TARGET_NR_add_key 281 +#define TARGET_NR_request_key 282 +#define TARGET_NR_keyctl 283 diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h new file mode 100644 index 000000000..cad45b292 --- /dev/null +++ b/linux-user/sparc64/termbits.h @@ -0,0 +1,279 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VEOL 5 +#define TARGET_VEOL2 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 + +#define TARGET_VSUSP 10 +#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */ +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 + +/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is + * shared with eof/eol + */ +#define TARGET_VMIN TARGET_VEOF +#define TARGET_VTIME TARGET_VEOL + +/* c_iflag bits */ +#define TARGET_IGNBRK 0x00000001 +#define TARGET_BRKINT 0x00000002 +#define TARGET_IGNPAR 0x00000004 +#define TARGET_PARMRK 0x00000008 +#define TARGET_INPCK 0x00000010 +#define TARGET_ISTRIP 0x00000020 +#define TARGET_INLCR 0x00000040 +#define TARGET_IGNCR 0x00000080 +#define TARGET_ICRNL 0x00000100 +#define TARGET_IUCLC 0x00000200 +#define TARGET_IXON 0x00000400 +#define TARGET_IXANY 0x00000800 +#define TARGET_IXOFF 0x00001000 +#define TARGET_IMAXBEL 0x00002000 + +/* c_oflag bits */ +#define TARGET_OPOST 0x00000001 +#define TARGET_OLCUC 0x00000002 +#define TARGET_ONLCR 0x00000004 +#define TARGET_OCRNL 0x00000008 +#define TARGET_ONOCR 0x00000010 +#define TARGET_ONLRET 0x00000020 +#define TARGET_OFILL 0x00000040 +#define TARGET_OFDEL 0x00000080 +#define TARGET_NLDLY 0x00000100 +#define TARGET_NL0 0x00000000 +#define TARGET_NL1 0x00000100 +#define TARGET_CRDLY 0x00000600 +#define TARGET_CR0 0x00000000 +#define TARGET_CR1 0x00000200 +#define TARGET_CR2 0x00000400 +#define TARGET_CR3 0x00000600 +#define TARGET_TABDLY 0x00001800 +#define TARGET_TAB0 0x00000000 +#define TARGET_TAB1 0x00000800 +#define TARGET_TAB2 0x00001000 +#define TARGET_TAB3 0x00001800 +#define TARGET_XTABS 0x00001800 +#define TARGET_BSDLY 0x00002000 +#define TARGET_BS0 0x00000000 +#define TARGET_BS1 0x00002000 +#define TARGET_VTDLY 0x00004000 +#define TARGET_VT0 0x00000000 +#define TARGET_VT1 0x00004000 +#define TARGET_FFDLY 0x00008000 +#define TARGET_FF0 0x00000000 +#define TARGET_FF1 0x00008000 +#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */ +#define TARGET_WRAP 0x00020000 /* SUNOS specific */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0x0000100f +#define TARGET_B0 0x00000000 /* hang up */ +#define TARGET_B50 0x00000001 +#define TARGET_B75 0x00000002 +#define TARGET_B110 0x00000003 +#define TARGET_B134 0x00000004 +#define TARGET_B150 0x00000005 +#define TARGET_B200 0x00000006 +#define TARGET_B300 0x00000007 +#define TARGET_B600 0x00000008 +#define TARGET_B1200 0x00000009 +#define TARGET_B1800 0x0000000a +#define TARGET_B2400 0x0000000b +#define TARGET_B4800 0x0000000c +#define TARGET_B9600 0x0000000d +#define TARGET_B19200 0x0000000e +#define TARGET_B38400 0x0000000f +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0x00000030 +#define TARGET_CS5 0x00000000 +#define TARGET_CS6 0x00000010 +#define TARGET_CS7 0x00000020 +#define TARGET_CS8 0x00000030 +#define TARGET_CSTOPB 0x00000040 +#define TARGET_CREAD 0x00000080 +#define TARGET_PARENB 0x00000100 +#define TARGET_PARODD 0x00000200 +#define TARGET_HUPCL 0x00000400 +#define TARGET_CLOCAL 0x00000800 +#define TARGET_CBAUDEX 0x00001000 +/* We'll never see these speeds with the Zilogs, but for completeness... */ +#define TARGET_B57600 0x00001001 +#define TARGET_B115200 0x00001002 +#define TARGET_B230400 0x00001003 +#define TARGET_B460800 0x00001004 +/* This is what we can do with the Zilogs. */ +#define TARGET_B76800 0x00001005 +/* This is what we can do with the SAB82532. */ +#define TARGET_B153600 0x00001006 +#define TARGET_B307200 0x00001007 +#define TARGET_B614400 0x00001008 +#define TARGET_B921600 0x00001009 +/* And these are the rest... */ +#define TARGET_B500000 0x0000100a +#define TARGET_B576000 0x0000100b +#define TARGET_B1000000 0x0000100c +#define TARGET_B1152000 0x0000100d +#define TARGET_B1500000 0x0000100e +#define TARGET_B2000000 0x0000100f +/* These have totally bogus values and nobody uses them + so far. Later on we'd have to use say 0x10000x and + adjust CBAUD constant and drivers accordingly. +#define B2500000 0x00001010 +#define B3000000 0x00001011 +#define B3500000 0x00001012 +#define B4000000 0x00001013 */ +#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 0x80000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000001 +#define TARGET_ICANON 0x00000002 +#define TARGET_XCASE 0x00000004 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000010 +#define TARGET_ECHOK 0x00000020 +#define TARGET_ECHONL 0x00000040 +#define TARGET_NOFLSH 0x00000080 +#define TARGET_TOSTOP 0x00000100 +#define TARGET_ECHOCTL 0x00000200 +#define TARGET_ECHOPRT 0x00000400 +#define TARGET_ECHOKE 0x00000800 +#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */ +#define TARGET_FLUSHO 0x00002000 +#define TARGET_PENDIN 0x00004000 +#define TARGET_IEXTEN 0x00008000 + +/* ioctls */ + +/* Big T */ +#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio) +#define TARGET_TCSBRK TARGET_IO('T', 5) +#define TARGET_TCXONC TARGET_IO('T', 6) +#define TARGET_TCFLSH TARGET_IO('T', 7) +#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios) + +/* Note that all the ioctls that are not available in Linux have a + * double underscore on the front to: a) avoid some programs to + * thing we support some ioctls under Linux (autoconfiguration stuff) + */ +/* Little t */ +#define TARGET_TIOCGETD TARGET_IOR('t', 0, int) +#define TARGET_TIOCSETD TARGET_IOW('t', 1, int) +//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */ +//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */ +//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */ +//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */ +//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */ +//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */ +#define TARGET_TIOCEXCL TARGET_IO('t', 13) +#define TARGET_TIOCNXCL TARGET_IO('t', 14) +//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */ +//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */ +//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */ +//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */ +//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */ +//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */ +//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */ +#define TARGET_TIOCCONS TARGET_IO('t', 36) +//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */ +//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */ +#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int) +#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int) +//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) +//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */ +#define TARGET_TIOCMGET TARGET_IOR('t', 106, int) +#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) +#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) +#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) +#define TARGET_TIOCSTART TARGET_IO('t', 110) +#define TARGET_TIOCSTOP TARGET_IO('t', 111) +#define TARGET_TIOCPKT TARGET_IOW('t', 112, int) +#define TARGET_TIOCNOTTY TARGET_IO('t', 113) +#define TARGET_TIOCSTI TARGET_IOW('t', 114, char) +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) +//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */ +//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */ +/* 118 is the non-posix setpgrp tty ioctl */ +/* 119 is the non-posix getpgrp tty ioctl */ +//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */ +//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */ +#define TARGET_TIOCCBRK TARGET_IO('t', 122) +#define TARGET_TIOCSBRK TARGET_IO('t', 123) +//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */ +//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */ +//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */ +//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */ +//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */ +//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int) +#define TARGET_TIOCSCTTY TARGET_IO('t', 132) +#define TARGET_TIOCGSID TARGET_IOR('t', 133, int) +/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ +#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */ +#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */ + +/* Little f */ +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD + +/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it + * someday. This is completely bogus, I know... + */ +//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */ +//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */ + +/* Linux specific, no SunOS equivalent. */ +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TCSBRKP 0x5425 +#define TARGET_TIOCTTYGSTRUCT 0x5426 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x545C /* Wait input */ +#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */ + diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7901befdd..9c7992e0b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1674,6 +1674,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_chdir: ret = get_errno(chdir((const char *)arg1)); break; +#ifdef TARGET_NR_time case TARGET_NR_time: { int *time_ptr = (int *)arg1; @@ -1682,6 +1683,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, tswap32s(time_ptr); } break; +#endif case TARGET_NR_mknod: ret = get_errno(mknod((const char *)arg1, arg2, arg3)); break; @@ -2168,6 +2170,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, arg6)); #endif break; +#ifdef TARGET_NR_mmap2 case TARGET_NR_mmap2: #if defined(TARGET_SPARC) #define MMAP_SHIFT 12 @@ -2179,6 +2182,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, arg5, arg6 << MMAP_SHIFT)); break; +#endif case TARGET_NR_munmap: ret = get_errno(target_munmap(arg1, arg2)); break; @@ -2471,7 +2475,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_getdents: #if TARGET_LONG_SIZE != 4 -#error not supported +#warning not supported #elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8 { struct target_dirent *target_dirp = (void *)arg2; @@ -2746,16 +2750,25 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; } #endif +#ifdef TARGET_NR_truncate64 case TARGET_NR_truncate64: goto unimplemented; +#endif +#ifdef TARGET_NR_ftruncate64 case TARGET_NR_ftruncate64: goto unimplemented; +#endif +#ifdef TARGET_NR_stat64 case TARGET_NR_stat64: ret = get_errno(stat(path((const char *)arg1), &st)); goto do_stat64; +#endif +#ifdef TARGET_NR_lstat64 case TARGET_NR_lstat64: ret = get_errno(lstat(path((const char *)arg1), &st)); goto do_stat64; +#endif +#ifdef TARGET_NR_fstat64 case TARGET_NR_fstat64: { ret = get_errno(fstat(arg1, &st)); @@ -2783,7 +2796,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; - +#endif #ifdef USE_UID16 case TARGET_NR_lchown: ret = get_errno(lchown((const char *)arg1, low2highuid(arg2), low2highgid(arg3))); @@ -2894,37 +2907,60 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #endif /* USE_UID16 */ +#ifdef TARGET_NR_lchown32 case TARGET_NR_lchown32: ret = get_errno(lchown((const char *)arg1, arg2, arg3)); break; +#endif +#ifdef TARGET_NR_getuid32 case TARGET_NR_getuid32: ret = get_errno(getuid()); break; +#endif +#ifdef TARGET_NR_getgid32 case TARGET_NR_getgid32: ret = get_errno(getgid()); break; +#endif +#ifdef TARGET_NR_geteuid32 case TARGET_NR_geteuid32: ret = get_errno(geteuid()); break; +#endif +#ifdef TARGET_NR_getegid32 case TARGET_NR_getegid32: ret = get_errno(getegid()); break; +#endif +#ifdef TARGET_NR_setreuid32 case TARGET_NR_setreuid32: ret = get_errno(setreuid(arg1, arg2)); break; +#endif +#ifdef TARGET_NR_setregid32 case TARGET_NR_setregid32: ret = get_errno(setregid(arg1, arg2)); break; +#endif +#ifdef TARGET_NR_getgroups32 case TARGET_NR_getgroups32: goto unimplemented; +#endif +#ifdef TARGET_NR_setgroups32 case TARGET_NR_setgroups32: goto unimplemented; +#endif +#ifdef TARGET_NR_fchown32 case TARGET_NR_fchown32: ret = get_errno(fchown(arg1, arg2, arg3)); break; +#endif +#ifdef TARGET_NR_setresuid32 case TARGET_NR_setresuid32: ret = get_errno(setresuid(arg1, arg2, arg3)); break; +#endif +#ifdef TARGET_NR_getresuid32 case TARGET_NR_getresuid32: { int ruid, euid, suid; @@ -2936,9 +2972,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#endif +#ifdef TARGET_NR_setresgid32 case TARGET_NR_setresgid32: ret = get_errno(setresgid(arg1, arg2, arg3)); break; +#endif +#ifdef TARGET_NR_getresgid32 case TARGET_NR_getresgid32: { int rgid, egid, sgid; @@ -2950,21 +2990,32 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#endif +#ifdef TARGET_NR_chown32 case TARGET_NR_chown32: ret = get_errno(chown((const char *)arg1, arg2, arg3)); break; +#endif +#ifdef TARGET_NR_setuid32 case TARGET_NR_setuid32: ret = get_errno(setuid(arg1)); break; +#endif +#ifdef TARGET_NR_setgid32 case TARGET_NR_setgid32: ret = get_errno(setgid(arg1)); break; +#endif +#ifdef TARGET_NR_setfsuid32 case TARGET_NR_setfsuid32: ret = get_errno(setfsuid(arg1)); break; +#endif +#ifdef TARGET_NR_setfsgid32 case TARGET_NR_setfsgid32: ret = get_errno(setfsgid(arg1)); break; +#endif case TARGET_NR_pivot_root: goto unimplemented; -- cgit v1.2.3 From dfe86665b8d61659f2c24f7365f75fe89f4705ac Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Jan 2005 23:04:39 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1257 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cvsignore b/.cvsignore index aff7f55fd..50debc4d4 100644 --- a/.cvsignore +++ b/.cvsignore @@ -17,3 +17,5 @@ sparc-user qemu-img sparc-softmmu x86_64-softmmu +sparc64-user +sparc64-softmmu -- cgit v1.2.3 From 99c475abf16b10923baac09682a9d801ae421ac6 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 31 Jan 2005 20:45:13 +0000 Subject: armv5te support (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1258 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 + cpu-exec.c | 7 +- linux-user/arm/syscall.h | 4 +- linux-user/syscall.c | 28 +- target-arm/cpu.h | 3 + target-arm/exec.h | 4 +- target-arm/op.c | 144 +++++++++ target-arm/op_template.h | 9 +- target-arm/translate.c | 740 +++++++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 909 insertions(+), 32 deletions(-) diff --git a/Changelog b/Changelog index c1e5fff7d..2d1c06727 100644 --- a/Changelog +++ b/Changelog @@ -13,6 +13,8 @@ version 0.6.2: - initial APIC support - MMX/SSE/SSE2/PNI support - PC parallel port support (Mark Jonckheere) + - initial SPARC64 support (Blue Swirl) + - armv5te user mode support (Paul Brook) version 0.6.1: diff --git a/cpu-exec.c b/cpu-exec.c index df1642851..fe4bd906e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -160,7 +160,8 @@ int cpu_exec(CPUState *env1) env->CF = (psr >> 29) & 1; env->NZF = (psr & 0xc0000000) ^ 0x40000000; env->VF = (psr << 3) & 0x80000000; - env->cpsr = psr & ~0xf0000000; + env->QF = (psr >> 27) & 1; + env->cpsr = psr & ~CACHED_CPSR_BITS; } #elif defined(TARGET_SPARC) #elif defined(TARGET_PPC) @@ -303,7 +304,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_ARM) env->cpsr = compute_cpsr(); cpu_dump_state(env, logfile, fprintf, 0); - env->cpsr &= ~0xf0000000; + env->cpsr &= ~CACHED_CPSR_BITS; #elif defined(TARGET_SPARC) cpu_dump_state (env, logfile, fprintf, 0); #elif defined(TARGET_PPC) @@ -322,7 +323,7 @@ int cpu_exec(CPUState *env1) cs_base = env->segs[R_CS].base; pc = cs_base + env->eip; #elif defined(TARGET_ARM) - flags = 0; + flags = env->thumb; cs_base = 0; pc = env->regs[15]; #elif defined(TARGET_SPARC) diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index 645036174..f74d76528 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -30,7 +30,7 @@ struct target_pt_regs { #define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) #if defined(TARGET_WORDS_BIGENDIAN) -#define UNAME_MACHINE "armv4b" +#define UNAME_MACHINE "armv5teb" #else -#define UNAME_MACHINE "armv4l" +#define UNAME_MACHINE "armv5tel" #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9c7992e0b..bb609dec8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2944,11 +2944,35 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_getgroups32 case TARGET_NR_getgroups32: - goto unimplemented; + { + int gidsetsize = arg1; + uint32_t *target_grouplist = (void *)arg2; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + ret = get_errno(getgroups(gidsetsize, grouplist)); + if (!is_error(ret)) { + for(i = 0;i < gidsetsize; i++) + put_user(grouplist[i], &target_grouplist[i]); + } + } + break; #endif #ifdef TARGET_NR_setgroups32 case TARGET_NR_setgroups32: - goto unimplemented; + { + int gidsetsize = arg1; + uint32_t *target_grouplist = (void *)arg2; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + for(i = 0;i < gidsetsize; i++) + get_user(grouplist[i], &target_grouplist[i]); + ret = get_errno(setgroups(gidsetsize, grouplist)); + } + break; #endif #ifdef TARGET_NR_fchown32 case TARGET_NR_fchown32: diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7d34766b7..d75451281 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -35,6 +35,9 @@ typedef struct CPUARMState { uint32_t CF; /* 0 or 1 */ uint32_t VF; /* V is the bit 31. All other bits are undefined */ uint32_t NZF; /* N is bit 31. Z is computed from NZF */ + uint32_t QF; /* 0 or 1 */ + + int thumb; /* 0 = arm mode, 1 = thumb mode */ /* exception/interrupt handling */ jmp_buf jmp_env; diff --git a/target-arm/exec.h b/target-arm/exec.h index 14e2072e6..373b63dbe 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -31,12 +31,14 @@ void cpu_lock(void); void cpu_unlock(void); void cpu_loop_exit(void); +/* Implemented CPSR bits. */ +#define CACHED_CPSR_BITS 0xf8000000 static inline int compute_cpsr(void) { int ZF; ZF = (env->NZF == 0); return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); + (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27); } static inline void env_to_regs(void) diff --git a/target-arm/op.c b/target-arm/op.c index 6596de76f..dc1c7341e 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -81,8 +81,15 @@ #define REGNAME r15 #define REG (env->regs[15]) +#define SET_REG(x) REG = x & ~(uint32_t)1 #include "op_template.h" +void OPPROTO op_bx_T0(void) +{ + env->regs[15] = T0 & ~(uint32_t)1; + env->thumb = (T0 & 1) != 0; +} + void OPPROTO op_movl_T0_0(void) { T0 = 0; @@ -382,6 +389,14 @@ void OPPROTO op_imull_T0_T1(void) T0 = res; } +/* 48 bit signed mul, top 32 bits */ +void OPPROTO op_imulw_T0_T1(void) +{ + uint64_t res; + res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); + T0 = res >> 16; +} + void OPPROTO op_addq_T0_T1(void) { uint64_t res; @@ -391,6 +406,15 @@ void OPPROTO op_addq_T0_T1(void) T0 = res; } +void OPPROTO op_addq_lo_T0_T1(void) +{ + uint64_t res; + res = ((uint64_t)T1 << 32) | T0; + res += (uint64_t)(env->regs[PARAM1]); + T1 = res >> 32; + T0 = res; +} + void OPPROTO op_logicq_cc(void) { env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); @@ -694,6 +718,126 @@ void OPPROTO op_rorl_T1_T0_cc(void) FORCE_RET(); } +/* misc */ +void OPPROTO op_clz_T0(void) +{ + int count; + for (count = 32; T0 > 0; count--) + T0 = T0 >> 1; + T0 = count; + FORCE_RET(); +} + +void OPPROTO op_sarl_T0_im(void) +{ + T0 = (int32_t)T0 >> PARAM1; +} + +/* 16->32 Sign extend */ +void OPPROTO op_sxl_T0(void) +{ + T0 = (int16_t)T0; +} + +void OPPROTO op_sxl_T1(void) +{ + T1 = (int16_t)T1; +} + +#define SIGNBIT (uint32_t)0x80000000 +/* saturating arithmetic */ +void OPPROTO op_addl_T0_T1_setq(void) +{ + uint32_t res; + + res = T0 + T1; + if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) + env->QF = 1; + + T0 = res; + FORCE_RET(); +} + +void OPPROTO op_addl_T0_T1_saturate(void) +{ + uint32_t res; + + res = T0 + T1; + if (((res ^ T0) & SIGNBIT) && !((T0 ^ T1) & SIGNBIT)) { + env->QF = 1; + if (T0 & SIGNBIT) + T0 = 0x80000000; + else + T0 = 0x7fffffff; + } + else + T0 = res; + + FORCE_RET(); +} + +void OPPROTO op_subl_T0_T1_saturate(void) +{ + uint32_t res; + + res = T0 - T1; + if (((res ^ T0) & SIGNBIT) && ((T0 ^ T1) & SIGNBIT)) { + env->QF = 1; + if (T0 & SIGNBIT) + T0 = 0x8000000; + else + T0 = 0x7fffffff; + } + else + T0 = res; + + FORCE_RET(); +} + +/* thumb shift by immediate */ +void OPPROTO op_shll_T0_im_thumb(void) +{ + int shift; + shift = PARAM1; + if (shift != 0) { + env->CF = (T1 >> (32 - shift)) & 1; + T0 = T0 << shift; + } + env->NZF = T0; + FORCE_RET(); +} + +void OPPROTO op_shrl_T0_im_thumb(void) +{ + int shift; + + shift = PARAM1; + if (shift == 0) { + env->CF = 0; + T0 = 0; + } else { + env->CF = (T0 >> (shift - 1)) & 1; + T0 = T0 >> shift; + } + FORCE_RET(); +} + +void OPPROTO op_sarl_T0_im_thumb(void) +{ + int shift; + + shift = PARAM1; + if (shift == 0) { + T0 = ((int32_t)T0) >> 31; + env->CF = T0 & 1; + } else { + env->CF = (T0 >> (shift - 1)) & 1; + T0 = ((int32_t)T0) >> shift; + } + env->NZF = T0; + FORCE_RET(); +} + /* exceptions */ void OPPROTO op_swi(void) diff --git a/target-arm/op_template.h b/target-arm/op_template.h index 00e9d51fe..fb2add15d 100644 --- a/target-arm/op_template.h +++ b/target-arm/op_template.h @@ -19,6 +19,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef SET_REG +#define SET_REG(x) REG = x +#endif + void OPPROTO glue(op_movl_T0_, REGNAME)(void) { T0 = REG; @@ -36,13 +40,14 @@ void OPPROTO glue(op_movl_T2_, REGNAME)(void) void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) { - REG = T0; + SET_REG (T0); } void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) { - REG = T1; + SET_REG (T1); } #undef REG #undef REGNAME +#undef SET_REG diff --git a/target-arm/translate.c b/target-arm/translate.c index 8ec392487..e2c5b8fc0 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -245,6 +245,18 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] = { gen_op_movl_T2_im, }; +static GenOpFunc1 *gen_shift_T0_im_thumb[3] = { + gen_op_shll_T0_im_thumb, + gen_op_shrl_T0_im_thumb, + gen_op_sarl_T0_im_thumb, +}; + +static inline void gen_bx(DisasContext *s) +{ + s->is_jmp = DISAS_UPDATE; + gen_op_bx_T0(); +} + static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) { int val; @@ -350,17 +362,166 @@ static void disas_arm_insn(DisasContext *s) s->pc += 4; cond = insn >> 28; - if (cond == 0xf) + if (cond == 0xf){ + if ((insn & 0x0d70f000) == 0x0550f000) + return; /* PLD */ + else if ((insn & 0x0e000000) == 0x0a000000) { + /* branch link and change to thumb (blx ) */ + int32_t offset; + + val = (uint32_t)s->pc; + gen_op_movl_T0_im(val); + gen_movl_reg_T0(s, 14); + /* Sign-extend the 24-bit offset */ + offset = (((int32_t)insn) << 8) >> 8; + /* offset * 4 + bit24 * 2 + (thumb bit) */ + val += (offset << 2) | ((insn >> 23) & 2) | 1; + /* pipeline offset */ + val += 4; + gen_op_movl_T0_im(val); + gen_bx(s); + return; + } goto illegal_op; + } if (cond != 0xe) { /* if not always execute, we generate a conditional jump to next instruction */ gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); s->is_jmp = DISAS_JUMP_NEXT; } - if (((insn & 0x0e000000) == 0 && - (insn & 0x00000090) != 0x90) || - ((insn & 0x0e000000) == (1 << 25))) { + if ((insn & 0x0f900000) == 0x03000000) { + if ((insn & 0x0ff0f000) != 0x0360f000) + goto illegal_op; + /* CPSR = immediate */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) + val = (val >> shift) | (val << (32 - shift)); + gen_op_movl_T0_im(val); + if (insn & (1 << 19)) + gen_op_movl_psr_T0(); + } else if ((insn & 0x0f900000) == 0x01000000 + && (insn & 0x00000090) != 0x00000090) { + /* miscellaneous instructions */ + op1 = (insn >> 21) & 3; + sh = (insn >> 4) & 0xf; + rm = insn & 0xf; + switch (sh) { + case 0x0: /* move program status register */ + if (op1 & 2) { + /* SPSR not accessible in user mode */ + goto illegal_op; + } + if (op1 & 1) { + /* CPSR = reg */ + gen_movl_T0_reg(s, rm); + if (insn & (1 << 19)) + gen_op_movl_psr_T0(); + } else { + /* reg = CPSR */ + rd = (insn >> 12) & 0xf; + gen_op_movl_T0_psr(); + gen_movl_reg_T0(s, rd); + } + case 0x1: + if (op1 == 1) { + /* branch/exchange thumb (bx). */ + gen_movl_T0_reg(s, rm); + gen_bx(s); + } else if (op1 == 3) { + /* clz */ + rd = (insn >> 12) & 0xf; + gen_movl_T0_reg(s, rm); + gen_op_clz_T0(); + gen_movl_reg_T0(s, rd); + } else { + goto illegal_op; + } + break; + case 0x3: + if (op1 != 1) + goto illegal_op; + + /* branch link/exchange thumb (blx) */ + val = (uint32_t)s->pc; + gen_op_movl_T0_im(val); + gen_movl_reg_T0(s, 14); + gen_movl_T0_reg(s, rm); + gen_bx(s); + break; + case 0x5: /* saturating add/subtract */ + rd = (insn >> 12) & 0xf; + rn = (insn >> 16) & 0xf; + gen_movl_T0_reg(s, rn); + if (op1 & 2) { + gen_movl_T1_reg(s, rn); + if (op1 & 1) + gen_op_subl_T0_T1_saturate(); + else + gen_op_addl_T0_T1_saturate(); + } + gen_movl_T1_reg(s, rm); + if (op1 & 1) + gen_op_subl_T0_T1_saturate(); + else + gen_op_addl_T0_T1_saturate(); + gen_movl_reg_T0(s, rn); + break; + case 0x8: /* signed multiply */ + case 0xa: + case 0xc: + case 0xe: + rs = (insn >> 8) & 0xf; + rn = (insn >> 12) & 0xf; + rd = (insn >> 16) & 0xf; + if (op1 == 1) { + /* (32 * 16) >> 16 */ + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rs); + if (sh & 4) + gen_op_sarl_T1_im(16); + else + gen_op_sxl_T1(); + gen_op_imulw_T0_T1(); + if ((sh & 2) == 0) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + } else { + /* 16 * 16 */ + gen_movl_T0_reg(s, rm); + if (sh & 2) + gen_op_sarl_T0_im(16); + else + gen_op_sxl_T0(); + gen_movl_T1_reg(s, rs); + if (sh & 4) + gen_op_sarl_T1_im(16); + else + gen_op_sxl_T1(); + if (op1 == 2) { + gen_op_imull_T0_T1(); + gen_op_addq_T0_T1(rn, rd); + gen_movl_reg_T0(s, rn); + gen_movl_reg_T1(s, rd); + } else { + gen_op_mul_T0_T1(); + if (op1 == 0) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + } + } + break; + default: + goto illegal_op; + } + } else if (((insn & 0x0e000000) == 0 && + (insn & 0x00000090) != 0x90) || + ((insn & 0x0e000000) == (1 << 25))) { int set_cc, logic_cc, shiftop; op1 = (insn >> 21) & 0xf; @@ -519,6 +680,7 @@ static void disas_arm_insn(DisasContext *s) switch(op1) { case 0x0: case 0x1: + /* multiplies, extra load/stores */ sh = (insn >> 5) & 3; if (sh == 0) { if (op1 == 0x0) { @@ -526,7 +688,7 @@ static void disas_arm_insn(DisasContext *s) rn = (insn >> 12) & 0xf; rs = (insn >> 8) & 0xf; rm = (insn) & 0xf; - if (!(insn & (1 << 23))) { + if (((insn >> 22) & 3) == 0) { /* 32 bit mul */ gen_movl_T0_reg(s, rs); gen_movl_T1_reg(s, rm); @@ -546,30 +708,39 @@ static void disas_arm_insn(DisasContext *s) gen_op_imull_T0_T1(); else gen_op_mull_T0_T1(); - if (insn & (1 << 21)) + if (insn & (1 << 21)) /* mult accumulate */ gen_op_addq_T0_T1(rn, rd); + if (!(insn & (1 << 23))) { /* double accumulate */ + gen_op_addq_lo_T0_T1(rn); + gen_op_addq_lo_T0_T1(rd); + } if (insn & (1 << 20)) gen_op_logicq_cc(); gen_movl_reg_T0(s, rn); gen_movl_reg_T1(s, rd); } } else { - /* SWP instruction */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; - rm = (insn) & 0xf; - - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rn); - if (insn & (1 << 22)) { - gen_op_swpb_T0_T1(); + if (insn & (1 << 23)) { + /* load/store exclusive */ + goto illegal_op; } else { - gen_op_swpl_T0_T1(); + /* SWP instruction */ + rm = (insn) & 0xf; + + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if (insn & (1 << 22)) { + gen_op_swpb_T0_T1(); + } else { + gen_op_swpl_T0_T1(); + } + gen_movl_reg_T0(s, rd); } - gen_movl_reg_T0(s, rd); } } else { - /* load/store half word */ + /* Misc load/store */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; gen_movl_T1_reg(s, rn); @@ -590,6 +761,27 @@ static void disas_arm_insn(DisasContext *s) break; } gen_movl_reg_T0(s, rd); + } else if (sh & 2) { + /* doubleword */ + if (sh & 1) { + /* store */ + gen_movl_T0_reg(s, rd); + gen_op_stl_T0_T1(); + gen_op_addl_T1_im(4); + gen_movl_T0_reg(s, rd + 1); + gen_op_stl_T0_T1(); + if ((insn & (1 << 24)) || (insn & (1 << 20))) + gen_op_addl_T1_im(-4); + } else { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd); + gen_op_addl_T1_im(4); + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd + 1); + if ((insn & (1 << 24)) || (insn & (1 << 20))) + gen_op_addl_T1_im(-4); + } } else { /* store */ gen_movl_T0_reg(s, rd); @@ -619,7 +811,10 @@ static void disas_arm_insn(DisasContext *s) gen_op_ldub_T0_T1(); else gen_op_ldl_T0_T1(); - gen_movl_reg_T0(s, rd); + if (rd == 15) + gen_bx(s); + else + gen_movl_reg_T0(s, rd); } else { /* store */ gen_movl_T0_reg(s, rd); @@ -676,7 +871,10 @@ static void disas_arm_insn(DisasContext *s) if (insn & (1 << 20)) { /* load */ gen_op_ldl_T0_T1(); - gen_movl_reg_T0(s, i); + if (i == 15) + gen_bx(s); + else + gen_movl_reg_T0(s, i); } else { /* store */ if (i == 15) { @@ -720,15 +918,15 @@ static void disas_arm_insn(DisasContext *s) case 0xa: case 0xb: { - int offset; + int32_t offset; /* branch (and link) */ - val = (int)s->pc; + val = (int32_t)s->pc; if (insn & (1 << 24)) { gen_op_movl_T0_im(val); gen_op_movl_reg_TN[0][14](); } - offset = (((int)insn << 8) >> 8); + offset = (((int32_t)insn << 8) >> 8); val += (offset << 2) + 4; gen_op_jmp((long)s->tb, val); s->is_jmp = DISAS_TB_JUMP; @@ -752,6 +950,500 @@ static void disas_arm_insn(DisasContext *s) } } +static void disas_thumb_insn(DisasContext *s) +{ + uint32_t val, insn, op, rm, rn, rd, shift, cond; + int32_t offset; + int i; + + insn = lduw(s->pc); + s->pc += 2; + + switch (insn >> 12) { + case 0: case 1: + rd = insn & 7; + op = (insn >> 11) & 3; + if (op == 3) { + /* add/subtract */ + rn = (insn >> 3) & 7; + gen_movl_T0_reg(s, rn); + if (insn & (1 << 10)) { + /* immediate */ + gen_op_movl_T1_im((insn >> 6) & 7); + } else { + /* reg */ + rm = (insn >> 6) & 7; + gen_movl_T1_reg(s, rm); + } + if (insn & (1 << 9)) + gen_op_addl_T0_T1_cc(); + else + gen_op_addl_T0_T1_cc(); + gen_movl_reg_T0(s, rd); + } else { + /* shift immediate */ + rm = (insn >> 3) & 7; + shift = (insn >> 6) & 0x1f; + gen_movl_T0_reg(s, rm); + gen_shift_T0_im_thumb[op](shift); + gen_movl_reg_T0(s, rd); + } + break; + case 2: case 3: + /* arithmetic large immediate */ + op = (insn >> 11) & 3; + rd = (insn >> 8) & 0x7; + if (op == 0) { + gen_op_movl_T0_im(insn & 0xff); + } else { + gen_movl_T0_reg(s, rd); + gen_op_movl_T1_im(insn & 0xff); + } + switch (op) { + case 0: /* mov */ + gen_op_logic_T0_cc(); + break; + case 1: /* cmp */ + gen_op_subl_T0_T1_cc(); + break; + case 2: /* add */ + gen_op_addl_T0_T1_cc(); + break; + case 3: /* sub */ + gen_op_subl_T0_T1_cc(); + break; + } + if (op != 1) + gen_movl_reg_T0(s, rd); + break; + case 4: + if (insn & (1 << 11)) { + rd = (insn >> 8) & 7; + /* load pc-relative */ + val = (insn & 0xff) * 4; + gen_op_movl_T1_im(val); + gen_movl_T2_reg(s, 15); + gen_op_addl_T1_T2(); + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + } + if (insn & (1 << 10)) { + /* data processing extended or blx */ + rd = (insn & 7) | ((insn >> 4) & 8); + rm = (insn >> 3) & 0xf; + op = (insn >> 8) & 3; + switch (op) { + case 0: /* add */ + gen_movl_T0_reg(s, rd); + gen_movl_T1_reg(s, rm); + gen_op_addl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 1: /* cmp */ + gen_movl_T0_reg(s, rd); + gen_movl_T1_reg(s, rm); + gen_op_subl_T0_T1_cc(); + break; + case 2: /* mov/cpy */ + gen_movl_T0_reg(s, rm); + gen_movl_reg_T0(s, rd); + break; + case 3:/* branch [and link] exchange thumb register */ + if (insn & (1 << 7)) { + val = (uint32_t)s->pc | 1; + gen_op_movl_T1_im(val); + gen_movl_reg_T1(s, 14); + } + gen_movl_T0_reg(s, rm); + gen_bx(s); + break; + } + break; + } + + /* data processing register */ + rd = insn & 7; + rm = (insn >> 3) & 7; + op = (insn >> 6) & 0xf; + if (op == 2 || op == 3 || op == 4 || op == 7) { + /* the shift/rotate ops want the operands backwards */ + val = rm; + rm = rd; + rd = val; + val = 1; + } else { + val = 0; + } + + if (op == 9) /* neg */ + gen_op_movl_T0_im(0); + else if (op != 0xf) /* mvn doesn't read its first operand */ + gen_movl_T0_reg(s, rd); + + gen_movl_T1_reg(s, rm); + switch (insn >> 6) { + case 0x0: /* and */ + gen_op_andl_T0_T1(); + gen_op_logic_T0_cc(); + break; + case 0x1: /* eor */ + gen_op_xorl_T0_T1(); + gen_op_logic_T0_cc(); + break; + case 0x2: /* lsl */ + gen_op_shll_T1_T0_cc(); + break; + case 0x3: /* lsr */ + gen_op_shrl_T1_T0_cc(); + break; + case 0x4: /* asr */ + gen_op_sarl_T1_T0_cc(); + break; + case 0x5: /* adc */ + gen_op_adcl_T0_T1_cc(); + break; + case 0x6: /* sbc */ + gen_op_sbcl_T0_T1_cc(); + break; + case 0x7: /* ror */ + gen_op_rorl_T1_T0_cc(); + break; + case 0x8: /* tst */ + gen_op_andl_T0_T1(); + gen_op_logic_T0_cc(); + rd = 16; + case 0x9: /* neg */ + gen_op_rsbl_T0_T1_cc(); + break; + case 0xa: /* cmp */ + gen_op_subl_T0_T1_cc(); + rd = 16; + break; + case 0xb: /* cmn */ + gen_op_addl_T0_T1_cc(); + rd = 16; + break; + case 0xc: /* orr */ + gen_op_orl_T0_T1(); + gen_op_logic_T0_cc(); + break; + case 0xd: /* mul */ + gen_op_mull_T0_T1(); + gen_op_logic_T0_cc(); + break; + case 0xe: /* bic */ + gen_op_bicl_T0_T1(); + gen_op_logic_T0_cc(); + break; + case 0xf: /* mvn */ + gen_op_notl_T1(); + gen_op_logic_T1_cc(); + val = 1; + break; + } + if (rd != 16) { + if (val) + gen_movl_reg_T1(s, rd); + else + gen_movl_reg_T0(s, rd); + } + break; + + case 5: + /* load/store register offset. */ + rd = insn & 7; + rn = (insn >> 3) & 7; + rm = (insn >> 6) & 7; + op = (insn >> 9) & 7; + gen_movl_T1_reg(s, rn); + gen_movl_T2_reg(s, rm); + gen_op_addl_T1_T2(); + + if (op < 3) /* store */ + gen_movl_T0_reg(s, rd); + + switch (op) { + case 0: /* str */ + gen_op_stl_T0_T1(); + break; + case 1: /* strh */ + gen_op_stw_T0_T1(); + break; + case 2: /* strb */ + gen_op_stb_T0_T1(); + break; + case 3: /* ldrsb */ + gen_op_ldsb_T0_T1(); + break; + case 4: /* ldr */ + gen_op_ldl_T0_T1(); + break; + case 5: /* ldrh */ + gen_op_ldsw_T0_T1(); + break; + case 6: /* ldrb */ + gen_op_ldub_T0_T1(); + break; + case 7: /* ldrsh */ + gen_op_ldsw_T0_T1(); + break; + } + if (op >= 3) /* load */ + gen_movl_reg_T0(s, rd); + break; + + case 6: + /* load/store word immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + gen_movl_T1_reg(s, rn); + val = (insn >> 4) & 0x7c; + gen_op_movl_T2_im(val); + gen_op_addl_T1_T2(); + + if (insn & (1 << 11)) { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd); + } else { + /* store */ + gen_movl_T0_reg(s, rd); + gen_op_stl_T0_T1(); + } + break; + + case 7: + /* load/store byte immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + gen_movl_T1_reg(s, rn); + val = (insn >> 6) & 0x1f; + gen_op_movl_T2_im(val); + gen_op_addl_T1_T2(); + + if (insn & (1 << 11)) { + /* load */ + gen_op_ldub_T0_T1(); + gen_movl_reg_T0(s, rd); + } else { + /* store */ + gen_movl_T0_reg(s, rd); + gen_op_stb_T0_T1(); + } + break; + + case 8: + /* load/store halfword immediate offset */ + rd = insn & 7; + rn = (insn >> 3) & 7; + gen_movl_T1_reg(s, rn); + val = (insn >> 5) & 0x3e; + gen_op_movl_T2_im(val); + gen_op_addl_T1_T2(); + + if (insn & (1 << 11)) { + /* load */ + gen_op_lduw_T0_T1(); + gen_movl_reg_T0(s, rd); + } else { + /* store */ + gen_movl_T0_reg(s, rd); + gen_op_stw_T0_T1(); + } + break; + + case 9: + /* load/store from stack */ + rd = (insn >> 8) & 7; + gen_movl_T1_reg(s, 13); + val = (insn & 0xff) * 4; + gen_op_movl_T2_im(val); + gen_op_addl_T1_T2(); + + if (insn & (1 << 11)) { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, rd); + } else { + /* store */ + gen_movl_T0_reg(s, rd); + gen_op_stl_T0_T1(); + } + break; + + case 10: + /* add to high reg */ + rd = (insn >> 8) & 7; + if (insn & (1 << 11)) + rm = 13; /* sp */ + else + rm = 15; /* pc */ + gen_movl_T0_reg(s, rm); + val = (insn & 0xff) * 4; + gen_op_movl_T1_im(val); + gen_op_addl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + + case 11: + /* misc */ + op = (insn >> 8) & 0xf; + switch (op) { + case 0: + /* adjust stack pointer */ + gen_movl_T1_reg(s, 13); + val = (insn & 0x7f) * 4; + if (insn & (1 << 7)) + val = -(int32_t)val; + gen_op_movl_T2_im(val); + gen_op_addl_T1_T2(); + gen_movl_reg_T1(s, 13); + break; + + case 4: case 5: case 0xc: case 0xd: + /* push/pop */ + gen_movl_T1_reg(s, 13); + if (insn & (1 << 11)) + val = 4; + else + val = -4; + gen_op_movl_T2_im(val); + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) { + if (insn & (1 << 11)) { + /* pop */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, i); + } else { + /* push */ + gen_movl_T0_reg(s, i); + gen_op_stl_T0_T1(); + } + /* move to the next address */ + gen_op_addl_T1_T2(); + } + } + if (insn & (1 << 8)) { + if (insn & (1 << 11)) { + /* pop pc */ + gen_op_ldl_T0_T1(); + /* don't set the pc until the rest of the instruction + has completed */ + } else { + /* push lr */ + gen_movl_T0_reg(s, 14); + gen_op_stl_T0_T1(); + } + gen_op_addl_T1_T2(); + } + + /* write back the new stack pointer */ + gen_movl_reg_T1(s, 13); + /* set the new PC value */ + if ((insn & 0x0900) == 0x0900) + gen_bx(s); + break; + + default: + goto undef; + } + break; + + case 12: + /* load/store multiple */ + rn = (insn >> 8) & 0x7; + gen_movl_T1_reg(s, rn); + gen_op_movl_T2_im(4); + val = 0; + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) { + /* advance to the next address */ + if (val) + gen_op_addl_T1_T2(); + else + val = 1; + if (insn & (1 << 11)) { + /* load */ + gen_op_ldl_T0_T1(); + gen_movl_reg_T0(s, i); + } else { + /* store */ + gen_movl_T0_reg(s, i); + gen_op_stl_T0_T1(); + } + } + } + break; + + case 13: + /* conditional branch or swi */ + cond = (insn >> 8) & 0xf; + if (cond == 0xe) + goto undef; + + if (cond == 0xf) { + /* swi */ + gen_op_movl_T0_im((long)s->pc | 1); + /* Don't set r15. */ + gen_op_movl_reg_TN[0][15](); + gen_op_swi(); + s->is_jmp = DISAS_JUMP; + break; + } + /* generate a conditional jump to next instruction */ + gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); + s->is_jmp = DISAS_JUMP_NEXT; + gen_movl_T1_reg(s, 15); + + /* jump to the offset */ + val = (uint32_t)s->pc; + offset = ((int32_t)insn << 24) >> 24; + val += (offset << 1) + 2; + gen_op_jmp((long)s->tb, val); + s->is_jmp = DISAS_TB_JUMP; + break; + + case 14: + /* unconditional branch */ + if (insn & (1 << 11)) + goto undef; /* Second half of a blx */ + val = (uint32_t)s->pc; + offset = ((int32_t)insn << 21) >> 21; + val += (offset << 1) + 2; + gen_op_jmp((long)s->tb, val); + s->is_jmp = DISAS_TB_JUMP; + break; + + case 15: + /* branch and link [and switch to arm] */ + offset = ((int32_t)insn << 21) >> 10; + insn = lduw(s->pc); + offset |= insn & 0x7ff; + + val = (uint32_t)s->pc + 2; + gen_op_movl_T1_im(val | 1); + gen_movl_reg_T1(s, 14); + + val += offset; + if (insn & (1 << 11)) { + /* bl */ + gen_op_jmp((long)s->tb, val); + s->is_jmp = DISAS_TB_JUMP; + } else { + /* blx */ + gen_op_movl_T0_im(val); + gen_bx(s); + } + } + return; +undef: + gen_op_movl_T0_im((long)s->pc - 4); + gen_op_movl_reg_TN[0][15](); + gen_op_undef_insn(); + s->is_jmp = DISAS_JUMP; +} + /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ @@ -787,7 +1479,10 @@ static inline int gen_intermediate_code_internal(CPUState *env, gen_opc_pc[lj] = dc->pc; gen_opc_instr_start[lj] = 1; } - disas_arm_insn(dc); + if (env->thumb) + disas_thumb_insn(dc); + else + disas_arm_insn(dc); } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); switch(dc->is_jmp) { @@ -797,6 +1492,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, break; default: case DISAS_JUMP: + case DISAS_UPDATE: /* indicate that the hash table must be used to find the next TB */ gen_op_movl_T0_0(); gen_op_exit_tb(); -- cgit v1.2.3 From 1ef386870812993f6819e8ac6554d20ba532b383 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 31 Jan 2005 23:31:02 +0000 Subject: x86_64 call Ev fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1259 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 5 +++++ target-i386/translate.c | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/target-i386/op.c b/target-i386/op.c index 79545b51a..933595da6 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -517,6 +517,11 @@ void OPPROTO op_movq_T0_im64(void) T0 = PARAMQ1; } +void OPPROTO op_movq_T1_im64(void) +{ + T1 = PARAMQ1; +} + void OPPROTO op_movq_A0_im(void) { A0 = (int32_t)PARAM1; diff --git a/target-i386/translate.c b/target-i386/translate.c index 46bf933c9..482642aa9 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2216,6 +2216,19 @@ static void gen_movtl_T0_im(target_ulong val) #endif } +static void gen_movtl_T1_im(target_ulong val) +{ +#ifdef TARGET_X86_64 + if ((int32_t)val == val) { + gen_op_movl_T1_im(val); + } else { + gen_op_movq_T1_im64(val >> 32, val); + } +#else + gen_op_movl_T1_im(val); +#endif +} + static GenOpFunc1 *gen_ldq_env_A0[3] = { gen_op_ldq_raw_env_A0, #ifndef CONFIG_USER_ONLY @@ -3391,7 +3404,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->dflag == 0) gen_op_andl_T0_ffff(); next_eip = s->pc - s->cs_base; - gen_op_movl_T1_im(next_eip); + gen_movtl_T1_im(next_eip); gen_push_T1(s); gen_op_jmp_T0(); gen_eob(s); -- cgit v1.2.3 From fa15e030bfd9dfa00530ed1a0d5d9d315a5a591a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 31 Jan 2005 23:32:31 +0000 Subject: 64 bit disas fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1260 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/disas.c b/disas.c index 3a5549d2b..8bba62446 100644 --- a/disas.c +++ b/disas.c @@ -148,11 +148,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #endif for (pc = code; pc < code + size; pc += count) { -#if TARGET_LONG_BITS == 64 - fprintf(out, "0x%016llx: ", pc); -#else - fprintf(out, "0x%08x: ", pc); -#endif + fprintf(out, "0x" TARGET_FMT_lx ": ", pc); count = print_insn(pc, &disasm_info); #if 0 { @@ -301,10 +297,12 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) disasm_info.endian = BFD_ENDIAN_LITTLE; #endif #if defined(TARGET_I386) - if (!flags) - disasm_info.mach = bfd_mach_i386_i386; - else + 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; @@ -318,7 +316,7 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) #endif for(i = 0; i < nb_insn; i++) { - term_printf("0x%08lx: ", (unsigned long)pc); + term_printf("0x" TARGET_FMT_lx ": ", pc); count = print_insn(pc, &disasm_info); term_printf("\n"); if (count < 0) -- cgit v1.2.3 From 90f11f95fe41c1b0ec3c70f11f93efeec8a34611 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Feb 2005 20:25:03 +0000 Subject: pusha, popa and enter fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1261 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 482642aa9..a3005d8d5 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2074,7 +2074,7 @@ static void gen_pusha(DisasContext *s) gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index](); gen_op_addl_A0_im(2 << s->dflag); } - gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); + gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); } /* NOTE: wrap around in 16 bit not fully handled */ @@ -2096,7 +2096,7 @@ static void gen_popa(DisasContext *s) } gen_op_addl_A0_im(2 << s->dflag); } - gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); + gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); } static void gen_enter(DisasContext *s, int esp_addend, int level) @@ -2122,7 +2122,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) } gen_op_mov_reg_T1[ot][R_EBP](); gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); - gen_op_mov_reg_T1[ot][R_ESP](); + gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); } static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) -- cgit v1.2.3 From 6bae70713cb2f87be60ef4f83105c2c928d8612e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 2 Feb 2005 20:40:17 +0000 Subject: sparc fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1262 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 745467214..352ae1f0f 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -113,7 +113,7 @@ static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) saddr = (addr & INTCTLM_MAXADDR) >> 2; switch (saddr) { case 0: - return s->intregm_pending; + return s->intregm_pending & 0x7fffffff; case 1: return s->intregm_disabled; case 4: @@ -132,12 +132,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin saddr = (addr & INTCTLM_MAXADDR) >> 2; switch (saddr) { case 2: // clear (enable) - // Force unused bits - val |= 0x7fb2007f; + // Force clear unused bits + val &= ~0x7fb2007f; s->intregm_disabled &= ~val; break; case 3: // set (disable, clear pending) - // Force unused bits + // Force clear unused bits val &= ~0x7fb2007f; s->intregm_disabled |= val; s->intregm_pending &= ~val; @@ -269,7 +269,7 @@ static void slavio_intctl_reset(void *opaque) for (i = 0; i < MAX_CPUS; i++) { s->intreg_pending[i] = 0; } - s->intregm_disabled = 0xffffffff; + s->intregm_disabled = ~0xffb2007f; s->intregm_pending = 0; s->target_cpu = 0; } -- cgit v1.2.3 From 9f0777ed8812ac98b32ab55bbf87056ba913f8b6 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 2 Feb 2005 20:42:01 +0000 Subject: ARM SMC workaround git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1263 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index fe4bd906e..bbd0c2d7b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -731,7 +731,10 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, int is_write, sigset_t *old_set, void *puc) { - /* XXX: do more */ + /* XXX: locking issue */ + if (is_write && page_unprotect(address, pc, puc)) { + return 1; + } return 0; } #elif defined(TARGET_SPARC) -- cgit v1.2.3 From 78573df6b28bf1419aeb98a8951bde30a0030fba Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 2 Feb 2005 20:43:01 +0000 Subject: SBCS fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1264 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/op.c b/target-arm/op.c index dc1c7341e..813c285b5 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -190,10 +190,10 @@ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ src1 = T0; \ if (!env->CF) { \ T0 = T0 - T1 - 1; \ - env->CF = src1 >= T1; \ + env->CF = src1 > T1; \ } else { \ T0 = T0 - T1; \ - env->CF = src1 > T1; \ + env->CF = src1 >= T1; \ } \ env->VF = (src1 ^ T1) & (src1 ^ T0); \ env->NZF = T0; \ -- cgit v1.2.3 From 832ed0fa340cedb948a63abd472c7ba4bfd911c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Feb 2005 12:35:16 +0000 Subject: ARM FPU endianness fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1265 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 1361cf1be..86430791d 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -114,18 +114,19 @@ static inline void tswap64s(uint64_t *s) #define tswapls(s) tswap64s((uint64_t *)(s)) #endif -/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ +/* NOTE: arm FPA is horrible as double 32 bit words are stored in big + endian ! */ typedef union { double d; -#if !defined(WORDS_BIGENDIAN) && !defined(__arm__) +#if defined(WORDS_BIGENDIAN) || (defined(__arm__) && !defined(__VFP_FP__)) struct { - uint32_t lower; uint32_t upper; + uint32_t lower; } l; #else struct { - uint32_t upper; uint32_t lower; + uint32_t upper; } l; #endif uint64_t ll; -- cgit v1.2.3 From e88de09993cf37702c1f20f5299471aa123295e6 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Feb 2005 12:35:39 +0000 Subject: ARM FPA get_user/put_user fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1266 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 2331c419d..c176a58aa 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -1,5 +1,5 @@ -#ifndef GEMU_H -#define GEMU_H +#ifndef QEMU_H +#define QEMU_H #include "thunk.h" @@ -52,8 +52,6 @@ struct vm86_saved_state { #ifdef TARGET_ARM /* FPU emulator */ #include "nwfpe/fpa11.h" -#undef put_user -#undef get_user #endif /* NOTE: we force a big alignment so that the stack stored after is @@ -238,4 +236,4 @@ static inline unsigned long clear_user(void *dst, unsigned long size) return size; } -#endif +#endif /* QEMU_H */ -- cgit v1.2.3 From 7ff4d2180b27b3356379ca66738da10ad8b2f73a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Feb 2005 12:42:35 +0000 Subject: CF generator for constant operands git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1267 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 5 +++++ target-arm/translate.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target-arm/op.c b/target-arm/op.c index 813c285b5..561883457 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -105,6 +105,11 @@ void OPPROTO op_movl_T1_im(void) T1 = PARAM1; } +void OPPROTO op_mov_CF_T1(void) +{ + env->CF = ((uint32_t)T1) >> 31; +} + void OPPROTO op_movl_T2_im(void) { T2 = PARAM1; diff --git a/target-arm/translate.c b/target-arm/translate.c index e2c5b8fc0..722324213 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -536,7 +536,8 @@ static void disas_arm_insn(DisasContext *s) if (shift) val = (val >> shift) | (val << (32 - shift)); gen_op_movl_T1_im(val); - /* XXX: is CF modified ? */ + if (logic_cc && shift) + gen_op_mov_CF_T1(); } else { /* register */ rm = (insn) & 0xf; -- cgit v1.2.3 From a8d3431ae931aa44ee6228ffecf6277714389de7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Feb 2005 12:43:57 +0000 Subject: endianness fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1268 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/nwfpe/double_cpdo.c | 8 ++++++++ target-arm/nwfpe/fpa11.h | 9 +++++++-- target-arm/nwfpe/fpa11_cpdt.c | 10 ++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/target-arm/nwfpe/double_cpdo.c b/target-arm/nwfpe/double_cpdo.c index f1738eac0..c44d3fc58 100644 --- a/target-arm/nwfpe/double_cpdo.c +++ b/target-arm/nwfpe/double_cpdo.c @@ -150,7 +150,11 @@ unsigned int DoubleCPDO(const unsigned int opcode) case MNF_CODE: { unsigned int *p = (unsigned int*)&rFm; +#ifdef WORDS_BIGENDIAN + p[0] ^= 0x80000000; +#else p[1] ^= 0x80000000; +#endif fpa11->fpreg[Fd].fDouble = rFm; } break; @@ -158,7 +162,11 @@ unsigned int DoubleCPDO(const unsigned int opcode) case ABS_CODE: { unsigned int *p = (unsigned int*)&rFm; +#ifdef WORDS_BIGENDIAN + p[0] &= 0x7fffffff; +#else p[1] &= 0x7fffffff; +#endif fpa11->fpreg[Fd].fDouble = rFm; } break; diff --git a/target-arm/nwfpe/fpa11.h b/target-arm/nwfpe/fpa11.h index 95ad11936..389c02986 100644 --- a/target-arm/nwfpe/fpa11.h +++ b/target-arm/nwfpe/fpa11.h @@ -22,6 +22,10 @@ #ifndef __FPA11_H__ #define __FPA11_H__ +#include +#include +#include + #define GET_FPA11() (qemufpa) /* @@ -87,8 +91,6 @@ extern void resetFPA11(void); extern void SetRoundingMode(const unsigned int); extern void SetRoundingPrecision(const unsigned int); -#define get_user(x,y) ((x)=*(y)) -#define put_user(x,y) (*(y)=(x)) static inline unsigned int readRegister(unsigned int reg) { return (user_registers[(reg)]); @@ -128,4 +130,7 @@ unsigned int ZF; unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs); +/* included only for get_user/put_user macros */ +#include "qemu.h" + #endif diff --git a/target-arm/nwfpe/fpa11_cpdt.c b/target-arm/nwfpe/fpa11_cpdt.c index 283e34673..c1d561554 100644 --- a/target-arm/nwfpe/fpa11_cpdt.c +++ b/target-arm/nwfpe/fpa11_cpdt.c @@ -43,8 +43,13 @@ void loadDouble(const unsigned int Fn,const unsigned int *pMem) unsigned int *p; p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; fpa11->fType[Fn] = typeDouble; +#ifdef WORDS_BIGENDIAN + get_user(p[0], &pMem[0]); /* sign & exponent */ + get_user(p[1], &pMem[1]); +#else get_user(p[0], &pMem[1]); get_user(p[1], &pMem[0]); /* sign & exponent */ +#endif } static inline @@ -133,8 +138,13 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fDouble; } +#ifdef WORDS_BIGENDIAN + put_user(p[0], &pMem[0]); /* msw */ + put_user(p[1], &pMem[1]); /* lsw */ +#else put_user(p[1], &pMem[0]); /* msw */ put_user(p[0], &pMem[1]); /* lsw */ +#endif } static inline -- cgit v1.2.3 From 4955a2cd1600344081e0b618d96c3b29942f76ef Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Feb 2005 14:09:05 +0000 Subject: test and set fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1269 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/exec-all.h b/exec-all.h index 0079b6494..b1f488cd0 100644 --- a/exec-all.h +++ b/exec-all.h @@ -392,28 +392,26 @@ static inline int testandset (int *p) #ifdef __i386__ static inline int testandset (int *p) { - char ret; - long int readval; + long int readval = 0; - __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" - : "=q" (ret), "=m" (*p), "=a" (readval) - : "r" (1), "m" (*p), "a" (0) - : "memory"); - return ret; + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" + : "+m" (*p), "+a" (readval) + : "r" (1) + : "cc"); + return readval; } #endif #ifdef __x86_64__ static inline int testandset (int *p) { - char ret; - int readval; + long int readval = 0; - __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" - : "=q" (ret), "=m" (*p), "=a" (readval) - : "r" (1), "m" (*p), "a" (0) - : "memory"); - return ret; + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" + : "+m" (*p), "+a" (readval) + : "r" (1) + : "cc"); + return readval; } #endif @@ -484,7 +482,7 @@ static inline int testandset (int *p) : "=r" (ret) : "m" (p) : "cc","memory"); - return ret == 0; + return ret; } #endif -- cgit v1.2.3 From b8a9e8f1336492798107a8704c22c4e8053c3dd7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Feb 2005 23:10:07 +0000 Subject: initial user mmu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1270 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/cpu.h | 9 +++++++-- target-arm/exec.h | 3 +++ target-arm/translate.c | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index d75451281..c0994c0c6 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -24,8 +24,10 @@ #include "cpu-defs.h" -#define EXCP_UDEF 1 /* undefined instruction */ -#define EXCP_SWI 2 /* software interrupt */ +#define EXCP_UDEF 1 /* undefined instruction */ +#define EXCP_SWI 2 /* software interrupt */ +#define EXCP_PREFETCH_ABORT 3 +#define EXCP_DATA_ABORT 4 typedef struct CPUARMState { uint32_t regs[16]; @@ -39,6 +41,9 @@ typedef struct CPUARMState { int thumb; /* 0 = arm mode, 1 = thumb mode */ + /* coprocessor 15 (MMU) status */ + uint32_t cp15_6; + /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; diff --git a/target-arm/exec.h b/target-arm/exec.h index 373b63dbe..e17302e0b 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -48,3 +48,6 @@ static inline void env_to_regs(void) static inline void regs_to_env(void) { } + +int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu); diff --git a/target-arm/translate.c b/target-arm/translate.c index 722324213..2eb325e8e 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -424,6 +424,7 @@ static void disas_arm_insn(DisasContext *s) gen_op_movl_T0_psr(); gen_movl_reg_T0(s, rd); } + break; case 0x1: if (op1 == 1) { /* branch/exchange thumb (bx). */ @@ -1576,3 +1577,23 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } + +#if defined(CONFIG_USER_ONLY) + +int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + env->cp15_6 = address; + if (rw == 2) { + env->exception_index = EXCP_PREFETCH_ABORT; + } else { + env->exception_index = EXCP_DATA_ABORT; + } + return 1; +} + +#else + +#error not implemented + +#endif -- cgit v1.2.3 From 9d89330183ceb170df926bbc395deb12e136e0f7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Feb 2005 23:10:53 +0000 Subject: clean up - comments git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1271 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 1 - target-sparc/exec.h | 7 ++++--- target-sparc/helper.c | 49 +++++++++++++++++++++--------------------------- target-sparc/op.c | 6 ------ target-sparc/op_helper.c | 6 ++++++ 5 files changed, 31 insertions(+), 38 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 7f8b9060a..a4b6c730f 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -127,7 +127,6 @@ typedef struct CPUSPARCState { int exception_index; int interrupt_index; int interrupt_request; - target_ulong exception_next_pc; struct TranslationBlock *current_tb; void *opaque; /* NOTE: we allow 8 more registers to handle wrapping */ diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 1fa7d87dc..f905bdfe1 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -41,9 +41,7 @@ void do_fcmpd(void); void do_ldd_kernel(target_ulong addr); void do_ldd_user(target_ulong addr); void do_ldd_raw(target_ulong addr); -void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw); -void raise_exception_err(int exception_index, int error_code); +void do_interrupt(int intno, int error_code); void raise_exception(int tt); void memcpy32(target_ulong *dst, const target_ulong *src); target_ulong mmu_probe(target_ulong address, int mmulev); @@ -129,4 +127,7 @@ static inline void regs_to_env(void) { } +int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu); + #endif diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 60096bf3a..b23be7cee 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -23,8 +23,6 @@ //#define DEBUG_MMU /* Sparc MMU emulation */ -int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu); /* thread support */ @@ -40,7 +38,18 @@ void cpu_unlock(void) spin_unlock(&global_cpu_lock); } -#if !defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) + +int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + env->mmuregs[4] = address; + env->exception_index = 0; /* XXX: must be incorrect */ + env->error_code = -2; /* XXX: is it really used ! */ + return 1; +} + +#else #define MMUSUFFIX _mmu #define GETPC() (__builtin_return_address(0)) @@ -86,11 +95,10 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) cpu_restore_state(tb, env, pc, NULL); } } - raise_exception_err(ret, env->error_code); + raise_exception(ret); } env = saved_env; } -#endif static const int access_table[8][8] = { { 0, 0, 0, 0, 2, 0, 3, 3 }, @@ -227,12 +235,6 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, unsigned long vaddr; int error_code = 0, prot, ret = 0, access_index; - if (env->user_mode_only) { - /* user mode only emulation */ - error_code = -2; - goto do_fault_user; - } - error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); if (error_code == 0) { virt_addr = address & TARGET_PAGE_MASK; @@ -248,11 +250,11 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault return 0; - do_fault_user: env->exception_index = exception; env->error_code = error_code; return error_code; } +#endif void memcpy32(target_ulong *dst, const target_ulong *src) { @@ -287,23 +289,17 @@ void cpu_set_cwp(CPUState *env1, int new_cwp) env = saved_env; } -/* - * Begin execution of an interruption. is_int is TRUE if coming from - * the int instruction. next_eip is the EIP value AFTER the interrupt - * instruction. It is only relevant if is_int is TRUE. - */ -void do_interrupt(int intno, int is_int, int error_code, - unsigned int next_eip, int is_hw) +void do_interrupt(int intno, int error_code) { int cwp; #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_INT) { static int count; - fprintf(logfile, "%6d: v=%02x e=%04x i=%d pc=%08x npc=%08x SP=%08x\n", - count, intno, error_code, is_int, - env->pc, - env->npc, env->regwptr[6]); + fprintf(logfile, "%6d: v=%02x e=%04x pc=%08x npc=%08x SP=%08x\n", + count, intno, error_code, + env->pc, + env->npc, env->regwptr[6]); #if 1 cpu_dump_state(env, logfile, fprintf, 0); { @@ -334,6 +330,8 @@ void do_interrupt(int intno, int is_int, int error_code, env->regwptr[9] = env->pc; env->regwptr[10] = env->npc; } else { + /* XXX: this code is clearly incorrect - npc should have the + incorrect value */ env->regwptr[9] = env->pc - 4; // XXX? env->regwptr[10] = env->pc; } @@ -345,11 +343,6 @@ void do_interrupt(int intno, int is_int, int error_code, env->exception_index = 0; } -void raise_exception_err(int exception_index, int error_code) -{ - raise_exception(exception_index); -} - target_ulong mmu_probe(target_ulong address, int mmulev) { target_phys_addr_t pde_ptr; diff --git a/target-sparc/op.c b/target-sparc/op.c index d1d48d2a7..dd8295e55 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -556,12 +556,6 @@ void OPPROTO op_rett(void) FORCE_RET(); } -void raise_exception(int tt) -{ - env->exception_index = tt; - cpu_loop_exit(); -} - /* XXX: use another pointer for %iN registers to avoid slow wrapping handling ? */ void OPPROTO op_save(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 2529cca72..9699d02f7 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -4,6 +4,12 @@ //#define DEBUG_MMU +void raise_exception(int tt) +{ + env->exception_index = tt; + cpu_loop_exit(); +} + #ifdef USE_INT_TO_FLOAT_HELPERS void do_fitos(void) { -- cgit v1.2.3 From 68016c627beb3df8ce69225b64ed6433efcc967d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Feb 2005 23:12:27 +0000 Subject: SIGSEGV signals for ARM and SPARC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1272 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++------- linux-user/main.c | 11 ++++++++++ 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index bbd0c2d7b..ff548af7a 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -205,9 +205,7 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_SPARC) do_interrupt(env->exception_index, - 0, - env->error_code, - env->exception_next_pc, 0); + env->error_code); #endif } env->exception_index = -1; @@ -263,7 +261,7 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_SPARC) if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(env->interrupt_index, 0, 0, 0, 0); + do_interrupt(env->interrupt_index, 0); env->interrupt_request &= ~CPU_INTERRUPT_HARD; } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); @@ -731,22 +729,72 @@ 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; } - return 0; + /* 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(address, pc, puc)) { return 1; } - return 0; + /* 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, @@ -756,10 +804,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, TranslationBlock *tb; int ret; -#if 1 if (cpu_single_env) env = cpu_single_env; /* XXX: find a correct solution for multithread */ -#endif #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); diff --git a/linux-user/main.c b/linux-user/main.c index 6b5ed2af6..f406f615d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -368,6 +368,17 @@ void cpu_loop(CPUARMState *env) case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; + case EXCP_PREFETCH_ABORT: + case EXCP_DATA_ABORT: + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->cp15_6; + queue_signal(info.si_signo, &info); + } + break; default: error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", -- cgit v1.2.3 From 18fba28c95d0f504d745e8e25c61f06e13601d10 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 8 Feb 2005 21:24:36 +0000 Subject: ppc fixes - gcc 3.4 compile fix (initial patch by Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1273 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 17 ----------------- target-ppc/helper.c | 13 +++++++++---- target-ppc/op.c | 19 ++----------------- target-ppc/op_helper.c | 2 +- target-ppc/translate.c | 35 ++++++++++++++++++++++------------- 5 files changed, 34 insertions(+), 52 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3198c9b97..123cb3f91 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -26,23 +26,6 @@ //#define USE_OPEN_FIRMWARE -/*** Sign extend constants ***/ -/* 8 to 32 bits */ -static inline int32_t s_ext8 (uint8_t value) -{ - int8_t *tmp = &value; - - return *tmp; -} - -/* 16 to 32 bits */ -static inline int32_t s_ext16 (uint16_t value) -{ - int16_t *tmp = &value; - - return *tmp; -} - #include "config.h" #include diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f3db55fe4..21e89008f 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -655,16 +655,21 @@ void _store_msr (CPUState *env, uint32_t value) msr_dr = (value >> MSR_DR) & 0x01; msr_ri = (value >> MSR_RI) & 0x01; msr_le = (value >> MSR_LE) & 0x01; + /* XXX: should enter PM state if msr_pow has been set */ } +#if defined (CONFIG_USER_ONLY) void do_interrupt (CPUState *env) { -#if defined (CONFIG_USER_ONLY) - env->exception_index |= 0x100; + env->exception_index = -1; +} #else +void do_interrupt (CPUState *env) +{ uint32_t msr; - int excp = env->exception_index; + int excp; + excp = env->exception_index; msr = _load_msr(env); #if defined (DEBUG_EXCEPTIONS) if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) @@ -905,7 +910,7 @@ void do_interrupt (CPUState *env) tmp_T0 = 0; #else T0 = 0; -#endif #endif env->exception_index = -1; } +#endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/op.c b/target-ppc/op.c index b360bb6e1..c6c0989ce 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -140,21 +140,6 @@ PPC_OP(set_Rc0) { uint32_t tmp; - if (Ts0 < 0) { - tmp = 0x08; - } else if (Ts0 > 0) { - tmp = 0x04; - } else { - tmp = 0x02; - } - env->crf[0] = tmp; - RETURN(); -} - -PPC_OP(set_Rc0_ov) -{ - uint32_t tmp; - if (Ts0 < 0) { tmp = 0x08; } else if (Ts0 > 0) { @@ -1062,14 +1047,14 @@ PPC_OP(eqv) /* extend sign byte */ PPC_OP(extsb) { - Ts0 = s_ext8(Ts0); + Ts0 = (int8_t)(Ts0); RETURN(); } /* extend sign half word */ PPC_OP(extsh) { - Ts0 = s_ext16(Ts0); + Ts0 = (int16_t)(Ts0); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 073ca37e1..433f6b128 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -377,7 +377,7 @@ void do_fnabs (void) void do_check_reservation (void) { - if ((env->reserve & ~(ICACHE_LINE_SIZE - 1)) == T0) + if ((env->reserve & ~0x03) == T0) env->reserve = -1; } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3974ecc73..4de116f18 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -179,6 +179,11 @@ static void gen_##name (DisasContext *ctx) typedef struct opcode_t { unsigned char opc1, opc2, opc3; +#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */ + unsigned char pad[5]; +#else + unsigned char pad[1]; +#endif opc_handler_t handler; } opcode_t; @@ -192,7 +197,7 @@ static inline uint32_t name (uint32_t opcode) \ #define EXTRACT_SHELPER(name, shift, nb) \ static inline int32_t name (uint32_t opcode) \ { \ - return s_ext16((opcode >> (shift)) & ((1 << (nb)) - 1)); \ + return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \ } /* Opcode part 1 */ @@ -285,10 +290,11 @@ static inline uint32_t MASK (uint32_t start, uint32_t end) #endif #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ -OPCODES_SECTION static opcode_t opc_##name = { \ +OPCODES_SECTION opcode_t opc_##name = { \ .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ + .pad = { 0, }, \ .handler = { \ .inval = invl, \ .type = _typ, \ @@ -297,10 +303,11 @@ OPCODES_SECTION static opcode_t opc_##name = { \ } #define GEN_OPCODE_MARK(name) \ -OPCODES_SECTION static opcode_t opc_##name = { \ +OPCODES_SECTION opcode_t opc_##name = { \ .opc1 = 0xFF, \ .opc2 = 0xFF, \ .opc3 = 0xFF, \ + .pad = { 0, }, \ .handler = { \ .inval = 0x00000000, \ .type = 0x00, \ @@ -361,7 +368,7 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0_ov(); \ + gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ } @@ -380,7 +387,7 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_##name(); \ if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0_ov(); \ + gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ } @@ -1558,7 +1565,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_op_dec_ctr(); switch(type) { case BCOND_IM: - li = s_ext16(BD(ctx->opcode)); + li = (int32_t)((int16_t)(BD(ctx->opcode))); if (AA(ctx->opcode) == 0) { target = ctx->nip + li - 4; } else { @@ -2160,11 +2167,6 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) case DECR: gen_op_store_decr(); break; -#if 0 - case HID0: - gen_op_store_hid0(); - break; -#endif default: gen_op_store_spr(sprn); break; @@ -2894,7 +2896,7 @@ static ppc_def_t ppc_defs[] = static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr) { - opcode_t *opc; + opcode_t *opc, *start, *end; int i, flags; fill_new_table(ppc_opcodes, 0x40); @@ -2906,7 +2908,14 @@ static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr) } } - for (opc = &opc_start + 1; opc != &opc_end; opc++) { + if (&opc_start < &opc_end) { + start = &opc_start; + end = &opc_end; + } else { + start = &opc_end; + end = &opc_start; + } + for (opc = start + 1; opc != end; opc++) { if ((opc->handler.type & flags) != 0) if (register_insn(ppc_opcodes, opc) < 0) { printf("*** ERROR initializing PPC instruction " -- cgit v1.2.3 From f8407028b40d7f17309dc3d470eba080451fa0a2 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Feb 2005 00:01:34 +0000 Subject: spelling fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1274 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/openpic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/openpic.c b/hw/openpic.c index ad9db7b36..e6bca3270 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -345,7 +345,7 @@ static void openpic_reset (openpic_t *opp) int i; opp->glbc = 0x80000000; - /* Initialise controler registers */ + /* Initialise controller registers */ opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; opp->veni = VENI; opp->spve = 0x000000FF; -- cgit v1.2.3 From d7ce296f57740c076279fd6a0282bea255ec0842 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Feb 2005 00:07:08 +0000 Subject: power down support + date fix (Thayne Harbaugh) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1275 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cuda.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/cuda.c b/hw/cuda.c index c05cdeb5f..b19686280 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -87,6 +87,9 @@ #define CUDA_TIMER_FREQ (4700000 / 6) #define CUDA_ADB_POLL_FREQ 50 +/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */ +#define RTC_OFFSET 2082844800 + typedef struct CUDATimer { unsigned int latch; uint16_t counter_value; /* counter value at load time */ @@ -503,7 +506,7 @@ static void cuda_receive_packet(CUDAState *s, break; case CUDA_GET_TIME: /* XXX: add time support ? */ - ti = time(NULL); + ti = time(NULL) + RTC_OFFSET; obuf[0] = CUDA_PACKET; obuf[1] = 0; obuf[2] = 0; @@ -522,6 +525,12 @@ static void cuda_receive_packet(CUDAState *s, obuf[1] = 0; cuda_send_packet_to_host(s, obuf, 2); break; + case CUDA_POWERDOWN: + obuf[0] = CUDA_PACKET; + obuf[1] = 0; + cuda_send_packet_to_host(s, obuf, 2); + qemu_system_shutdown_request(); + break; default: break; } -- cgit v1.2.3 From 7c3fc84d86764fddd8dbc5408409eb5b2b4dc96e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 21:46:47 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1276 c046a42c-6fe2-441c-8c8c-71466251a162 --- LICENSE | 26 ++++++ README | 58 ------------- qemu-doc.texi | 272 +++++++++++++++++++++++++++++++++------------------------- 3 files changed, 179 insertions(+), 177 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..b403f41bd --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +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) The QEMU Accelerator Module is a proprietary product. It is + available without charge. Commercial use of the QEMU Accelerator + Module is allowed. + + Redistribution of the QEMU Accelerator Module: any person or + organisation wishing to distribute it, for example on a CD or as a + binary or source package, must have an explicit authorization from + the author. + + The QEMU Accelerator Module is available without any express or + implied warranty. In no event will the author be held liable for + any damages arising from the use of this software. + +4) QEMU is a trademark of Fabrice Bellard. + + +Fabrice Bellard. \ No newline at end of file diff --git a/README b/README index 030306717..1a39500b7 100644 --- a/README +++ b/README @@ -1,61 +1,3 @@ -The QEMU x86 emulator ---------------------- - -INSTALLATION ------------- - -Type - - ./configure - make - -to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various -supported target CPUs). - -Type - - make install - -to install QEMU in /usr/local - -Tested tool versions --------------------- - -In order to compile QEMU succesfully, it is very important that you -have the right tools. The most important one is gcc. I cannot guaranty -that QEMU works if you do not use a tested gcc version. Look at -'configure' and 'Makefile' if you want to make a different gcc -version work. - -host gcc binutils glibc linux distribution ----------------------------------------------------------------------- -x86 2.95.2 2.13.2 2.1.3 2.4.18 - 3.2 2.13.2 2.1.3 2.4.18 - 2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3 - 3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9 - -PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq - 3.2 - -Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0 - -Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0 - -ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0 - -[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available - for gcc version >= 3.3. -[2] Linux >= 2.4.20 is necessary for precise exception support - (untested). -[3] 2.4.9-ac10-rmk2-np1-cerf2 - -[4] gcc 2.95.x generates invalid code when using too many register -variables. You must use gcc 3.x on PowerPC. - -Documentation -------------- - Read the documentation in qemu-doc.html. - Fabrice Bellard. \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index ca5cb09b0..9c25728b6 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -34,8 +34,12 @@ to ease cross-compilation and cross-debugging. @end itemize -As QEMU requires no host kernel driver to run, it is very safe and -easy to use. +QEMU can run without an host kernel driver and yet gives acceptable +performance. On an x86 host, if you want the highest performance for +the x86 target, the @emph{QEMU Accelerator Module} (KQEMU) allows QEMU +to reach near native performances. KQEMU is currently only supported +for an x86 Linux 2.4 or 2.6 host system, but more host OSes will be +supported in the future. For system emulation, the following hardware targets are supported: @itemize @@ -52,14 +56,8 @@ If you want to compile QEMU yourself, see @ref{compilation}. @section Linux -Download the binary distribution (@file{qemu-XXX-i386.tar.gz}) in -@file{/tmp} and untar it as root from @file{/}: - -@example -su -cd / -tar zxvf /tmp/qemu-XXX-i386.tar.gz -@end example +If a precompiled package is available for your distribution - you just +have to install it. Otherwise, see @ref{compilation}. @section Windows @@ -77,33 +75,8 @@ Download the experimental binary installer at @c man begin DESCRIPTION -The QEMU System emulator simulates a complete PC. - -In order to meet specific user needs, two versions of QEMU are -available: - -@enumerate - -@item -@code{qemu-fast} uses the host Memory Management Unit (MMU) to -simulate the x86 MMU. It is @emph{fast} but has limitations because -the whole 4 GB address space cannot be used and some memory mapped -peripherials cannot be emulated accurately yet. Therefore, a specific -guest Linux kernel can be used (@xref{linux_compile}) as guest -OS. - -Moreover there is no separation between the host and target address -spaces, so it offers no security (the target OS can modify the -@code{qemu-fast} code by writing at the right addresses). - -@item -@code{qemu} uses a software MMU. It is about @emph{two times slower} -but gives a more accurate emulation and a complete separation between -the host and target address spaces. - -@end enumerate - -QEMU emulates the following PC peripherials: +The QEMU System emulator simulates the +following PC peripherials: @itemize @minus @item @@ -369,6 +342,12 @@ Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= translation mode (@var{t}=none, lba or auto). Usually QEMU can guess all thoses parameters. This option is useful for old MS-DOS disk images. + +@item -no-kqemu +Disable the usage of the QEMU Accelerator module (KQEMU). QEMU will work as +usual but will be slower. This option can be useful to determine if +emulation problems are coming from KQEMU. + @item -isa Simulate an ISA-only system (default is PCI system). @item -std-vga @@ -444,6 +423,25 @@ Fabrice Bellard @end ignore +@section QEMU Accelerator Module + +The QEMU Accelerator Module (KQEMU) is an optional part of QEMU currently only +available for Linux 2.4 or 2.6 x86 hosts. It enables QEMU to run x86 +code much faster. Provided it is installed on your PC (see +@ref{kqemu_install}), QEMU will automatically use it. + +WARNING: as with any alpha stage kernel driver, KQEMU may cause +arbitrary data loss on your PC, so you'd better backup your sensitive +data before using it. + +When using KQEMU, QEMU will create a big hidden file containing the +RAM of the virtual machine. For best performance, it is important that +this file is kept in RAM and not on the hard disk. QEMU uses the +@file{/dev/shm} directory to create this file because @code{tmpfs} is +usually mounted on it (check with the shell command +@code{df}). Otherwise @file{/tmp} is used as fallback. You can use the +@var{QEMU_TMPDIR} shell variable to set a new directory for the QEMU +RAM file. @section QEMU Monitor @@ -824,12 +822,6 @@ NOTES: A 2.5.74 kernel is also included in the archive. Just replace the bzImage in qemu.sh to try it. -@item -qemu-fast creates a temporary file in @var{$QEMU_TMPDIR} (@file{/tmp} is the -default) containing all the simulated PC memory. If possible, try to use -a temporary directory using the tmpfs filesystem to avoid too many -unnecessary disk accesses. - @item In order to exit cleanly from qemu, you can do a @emph{shutdown} inside qemu. qemu will automatically exit when the Linux shutdown is done. @@ -848,80 +840,6 @@ Lawton for the plex86 Project (@url{www.plex86.org}). @end enumerate -@node linux_compile -@section Linux Kernel Compilation - -You can use any linux kernel with QEMU. However, if you want to use -@code{qemu-fast} to get maximum performances, you must use a modified -guest kernel. If you are using a 2.6 guest kernel, you can use -directly the patch @file{linux-2.6-qemu-fast.patch} made by Rusty -Russel available in the QEMU source archive. Otherwise, you can make the -following changes @emph{by hand} to the Linux kernel: - -@enumerate -@item -The kernel must be mapped at 0x90000000 (the default is -0xc0000000). You must modify only two lines in the kernel source: - -In @file{include/asm/page.h}, replace -@example -#define __PAGE_OFFSET (0xc0000000) -@end example -by -@example -#define __PAGE_OFFSET (0x90000000) -@end example - -And in @file{arch/i386/vmlinux.lds}, replace -@example - . = 0xc0000000 + 0x100000; -@end example -by -@example - . = 0x90000000 + 0x100000; -@end example - -@item -If you want to enable SMP (Symmetric Multi-Processing) support, you -must make the following change in @file{include/asm/fixmap.h}. Replace -@example -#define FIXADDR_TOP (0xffffX000UL) -@end example -by -@example -#define FIXADDR_TOP (0xa7ffX000UL) -@end example -(X is 'e' or 'f' depending on the kernel version). Although you can -use an SMP kernel with QEMU, it only supports one CPU. - -@item -If you are not using a 2.6 kernel as host kernel but if you use a target -2.6 kernel, you must also ensure that the 'HZ' define is set to 100 -(1000 is the default) as QEMU cannot currently emulate timers at -frequencies greater than 100 Hz on host Linux systems < 2.6. In -@file{include/asm/param.h}, replace: - -@example -# define HZ 1000 /* Internal kernel timer frequency */ -@end example -by -@example -# define HZ 100 /* Internal kernel timer frequency */ -@end example - -@end enumerate - -The file config-2.x.x gives the configuration of the example kernels. - -Just type -@example -make bzImage -@end example - -As you would do to make a real kernel. Then you can use with QEMU -exactly the same kernel as you would boot on your PC (in -@file{arch/i386/boot/bzImage}). - @node gdb_usage @section GDB usage @@ -976,6 +894,12 @@ When using a 2.6 guest Linux kernel, you should add the option kernels make very strict real time clock checks by default that QEMU cannot simulate exactly. +When using a 2.6 guest Linux kernel, verify that the 4G/4G patch is +not activated because QEMU is slower with this patch. The QEMU +Accelerator Module is also much slower in this case. Earlier Fedora +Core 3 Linux kernel (< 2.6.9-1.724_FC3) were known to incorporte this +patch by default. Newer kernels don't have it. + @subsection Windows If you have a slow host, using Windows 95 is better as it gives the @@ -1226,9 +1150,119 @@ Act as if the host page size was 'pagesize' bytes @node compilation @chapter Compilation from the sources -@section Linux/BSD +@section Linux/Unix + +@subsection Compilation + +First you must decompress the sources: +@example +cd /tmp +tar zxvf qemu-x.y.z.tar.gz +cd qemu-x.y.z +@end example + +Then you configure QEMU and build it (usually no options are needed): +@example +./configure +make +@end example + +Then type as root user: +@example +make install +@end example +to install QEMU in @file{/usr/local}. + +@node kqemu_install +@subsection QEMU Accelerator Installation + +If you use x86 Linux, the compilation of the QEMU Accelerator Kernel +Module (KQEMU) is automatically activated provided you have the +necessary kernel headers. If nonetheless the compilation fails, you +can disable its compilation with the @option{--disable-kqemu} option. + +If you are using a 2.6 host kernel, then all the necessary kernel +headers should be already installed. If you are using a 2.4 kernel, +then you should verify that properly configured kernel sources are +installed and compiled. On a Redhat 9 distribution for example, the +following must be done: +@example +1) Install the kernel-source-xxx package +2) cd /usr/src/linux-xxx +3) make distclean +4) Copy /boot/config-vvv in .config (use uname -r to know your configuration name 'vvv') +5) Edit the Makefile to change the EXTRAVERSION line to match your + current configuration name: + EXTRAVERSION = -custom +to + EXTRAVERSION = -8 # This is an example, it can be -8smp too +5) make menuconfig # Just save the configuration +6) make dep bzImage +@end example -Read the @file{README} which gives the related information. +The installation of KQEMU is not fully automatic because it is highly +distribution dependent. When launching +@example +make install +@end example + +KQEMU is installed in /lib/modules/@var{kernel_version}/misc. The +device @file{/dev/kqemu} is created with read/write access rights for +everyone. If you fear security issues, you can restrict the access +rights of @file{/dev/kqemu}. + +If you want that KQEMU is installed automatically at boot time, you can add + +@example +# Load the KQEMU kernel module +/sbin/modprobe kqemu +@end example + +in @file{/etc/rc.d/rc.local}. + +If your distribution uses udev (like Fedora), the @file{/dev/kqemu} is +not created automatically (yet) at every reboot. You can add the +following in @file{/etc/rc.d/rc.local}: + +@example +# Create the KQEMU device +mknod /dev/kqemu c 254 0 +chmod 666 /dev/kqemu +@end example + +@subsection Tested tool versions + +In order to compile QEMU succesfully, it is very important that you +have the right tools. The most important one is gcc. I cannot guaranty +that QEMU works if you do not use a tested gcc version. Look at +'configure' and 'Makefile' if you want to make a different gcc +version work. + +@example +host gcc binutils glibc linux distribution +---------------------------------------------------------------------- +x86 3.2 2.13.2 2.1.3 2.4.18 + 2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3 + 3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9 + +PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq + 3.2 + +Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0 + +Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0 + +ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0 + +[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available + for gcc version >= 3.3. +[2] Linux >= 2.4.20 is necessary for precise exception support + (untested). +[3] 2.4.9-ac10-rmk2-np1-cerf2 + +[4] gcc 2.95.x generates invalid code when using too many register +variables. You must use gcc 3.x on PowerPC. +@end example @section Windows -- cgit v1.2.3 From e3086fbf8f3e8242f7b5040a7a080e051bb9c2b3 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 21:48:51 +0000 Subject: kqemu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1277 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 9 +++++++++ Makefile.target | 8 ++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3cf7e504c..bc978167c 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,9 @@ all: dyngen$(EXESUF) $(TOOLS) $(DOCS) for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ done +ifdef CONFIG_KQEMU + $(MAKE) -C kqemu +endif qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) @@ -32,6 +35,9 @@ clean: for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ done +ifdef CONFIG_KQEMU + $(MAKE) -C kqemu clean +endif distclean: clean rm -f config-host.mak config-host.h @@ -63,6 +69,9 @@ endif for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ done +ifdef CONFIG_KQEMU + cd kqemu ; ./install.sh +endif # various test targets test speed test2: all diff --git a/Makefile.target b/Makefile.target index 0efc9d1c9..5ed2b9254 100644 --- a/Makefile.target +++ b/Makefile.target @@ -237,8 +237,8 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a # cpu emulator library -LIBOBJS=exec.o translate-all.o cpu-exec.o\ - translate.o op.o +LIBOBJS=exec.o kqemu.o translate-all.o cpu-exec.o\ + translate.o op.o ifeq ($(TARGET_ARCH), i386) LIBOBJS+=helper.o helper2.o @@ -363,6 +363,10 @@ ifndef CONFIG_WIN32 VL_LIBS=-lutil endif endif +ifdef TARGET_GPROF +vl.o: CFLAGS+=-p +VL_LDFLAGS+=-p +endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS) -- cgit v1.2.3 From c9ec1fe474ee9085b7eaad2326ee1c688f0c2d19 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 21:55:30 +0000 Subject: kqemu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1278 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 5149eb0a3..4b93737ef 100755 --- a/configure +++ b/configure @@ -81,6 +81,8 @@ fmod="no" fmod_lib="" fmod_inc="" linux="no" +kqemu="no" +kernel_path="" # OS specific targetos=`uname -s` @@ -107,6 +109,9 @@ darwin="yes" *) oss="yes" linux="yes" +if [ "$cpu" = "i386" ] ; then + kqemu="yes" +fi ;; esac @@ -169,6 +174,10 @@ for opt do ;; --enable-adlib) adlib="yes" ;; + --disable-kqemu) kqemu="no" + ;; + --kernel-path=*) kernel_path=${opt#--kernel-path=} + ;; esac done @@ -193,7 +202,7 @@ if test -z "$target_list" ; then target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu sparc64-softmmu" # the following are Linux specific if [ "$linux" = "yes" ] ; then - target_list="i386-user i386 arm-user armeb-user sparc-user ppc-user sparc64-user $target_list" + target_list="i386-user arm-user armeb-user sparc-user ppc-user sparc64-user $target_list" fi fi @@ -300,6 +309,10 @@ echo " --interp-prefix=PREFIX where to find shared libraries, etc." echo " use %M for cpu name [$interp_prefix]" echo " --target-list=LIST set target list [$target_list]" echo "" +echo "kqemu kernel acceleration support:" +echo " --disable-kqemu disable kqemu build" +echo " --kernel-path=PATH set the kernel path (configure probes it)" +echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]" echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" @@ -333,6 +346,40 @@ docdir="$prefix/share/doc/qemu" bindir="$prefix/bin" fi +# kernel module support +if test $kqemu = "yes" ; then +# find the kernel path +if test -z "$kernel_path" ; then +kernel_version=`uname -r` +kernel_path="/lib/modules/$kernel_version/build" +if test '!' -d "$kernel_path/include" ; then + kernel_path="/usr/src/linux" + if test '!' -d "$kernel_path/include" ; then + echo "Could not find kernel includes in /lib/modules or /usr/src/linux - cannot build the kqemu module" + kqemu="no" + fi +fi +fi + +if test $kqemu = "yes" ; then + +# test that the kernel config is present +if test '!' -f "$kernel_path/Makefile" ; then + echo "No .config file present in $kernel_path - kqemu cannot be built" + kqemu="no" +fi + +# find build system (2.6 or legacy) +kbuild26="yes" +if grep -q "PATCHLEVEL = 4" $kernel_path/Makefile ; then +kbuild26="no" +fi + +fi # kqemu + +fi # kqemu + + echo "Install prefix $prefix" echo "BIOS directory $datadir" echo "binary directory $bindir" @@ -357,6 +404,17 @@ if test $fmod = "yes"; then echo -n " (lib='$fmod_lib' include='$fmod_inc')" fi echo "" +if test $kqemu = "yes" ; then +echo "" +echo "KQEMU module configuration:" +echo "kernel sources $kernel_path" +echo -n "kbuild type " +if test $kbuild26 = "yes"; then +echo "2.6" +else +echo "2.4" +fi +fi if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support" @@ -481,6 +539,13 @@ echo -n "#define QEMU_VERSION \"" >> $config_h head $source_path/VERSION >> $config_h echo "\"" >> $config_h +if test $kqemu = "yes" ; then + echo "CONFIG_KQEMU=yes" >> $config_mak + echo "KERNEL_PATH=$kernel_path" >> $config_mak + if test $kbuild26 = "yes" ; then + echo "CONFIG_KBUILD26=yes" >> $config_mak + fi +fi echo "SRC_PATH=$source_path" >> $config_mak echo "TARGET_DIRS=$target_list" >> $config_mak -- cgit v1.2.3 From 49b470eb96a06cbaf01fa8f16b799d9a44b3a642 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 21:59:25 +0000 Subject: shared pages memory allocation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1279 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ osdep.h | 3 +++ 2 files changed, 84 insertions(+) diff --git a/osdep.c b/osdep.c index 087a5c218..bb2c0d1f0 100644 --- a/osdep.c +++ b/osdep.c @@ -273,6 +273,8 @@ void *get_mmap_addr(unsigned long size) #else +#include + int qemu_write(int fd, const void *buf, size_t n) { int ret; @@ -298,6 +300,85 @@ void *qemu_malloc(size_t size) return malloc(size); } +#if defined(USE_KQEMU) + +#include +#include + +void *qemu_vmalloc(size_t size) +{ + static int phys_ram_fd = -1; + static int phys_ram_size = 0; + const char *tmpdir; + char phys_ram_file[1024]; + void *ptr; + + if (phys_ram_fd < 0) { + tmpdir = getenv("QEMU_TMPDIR"); + if (!tmpdir) + tmpdir = "/dev/shm"; + snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", + tmpdir); + if (mkstemp(phys_ram_file) < 0) { + fprintf(stderr, + "warning: could not create temporary file in '%s'.\n" + "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n" + "Using '/tmp' as fallback.\n", + tmpdir); + snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", + "/tmp"); + if (mkstemp(phys_ram_file) < 0) { + fprintf(stderr, "Could not create temporary memory file '%s'\n", + phys_ram_file); + exit(1); + } + } + phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); + if (phys_ram_fd < 0) { + fprintf(stderr, "Could not open temporary memory file '%s'\n", + phys_ram_file); + exit(1); + } + unlink(phys_ram_file); + } + size = (size + 4095) & ~4095; + ftruncate(phys_ram_fd, phys_ram_size + size); + ptr = mmap(NULL, + size, + PROT_WRITE | PROT_READ, MAP_SHARED, + phys_ram_fd, phys_ram_size); + if (ptr == MAP_FAILED) { + fprintf(stderr, "Could not map physical memory\n"); + exit(1); + } + phys_ram_size += size; + return ptr; +} + +void qemu_vfree(void *ptr) +{ + /* may be useful some day, but currently we do not need to free */ +} + +#else + +/* alloc shared memory pages */ +void *qemu_vmalloc(size_t size) +{ +#ifdef _BSD + return valloc(size); +#else + return memalign(4096, size); +#endif +} + +void qemu_vfree(void *ptr) +{ + free(ptr); +} + +#endif + #endif void *qemu_mallocz(size_t size) diff --git a/osdep.h b/osdep.h index f1d18202b..f818ce03a 100644 --- a/osdep.h +++ b/osdep.h @@ -12,6 +12,9 @@ void *qemu_mallocz(size_t size); void qemu_free(void *ptr); char *qemu_strdup(const char *str); +void *qemu_vmalloc(size_t size); +void qemu_vfree(void *ptr); + void *get_mmap_addr(unsigned long size); /* specific kludges for OS compatibility (should be moved elsewhere) */ -- cgit v1.2.3 From d993e0260bf7a200df348a2fb0c5a6efa885987d Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 22:00:06 +0000 Subject: -no-kqemu option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1280 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 19 +++++++++++++------ vl.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/vl.c b/vl.c index 21c77758d..89efe67ca 100644 --- a/vl.c +++ b/vl.c @@ -2760,6 +2760,9 @@ void help(void) "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n" " translation (t=none or lba) (usually qemu can guess them)\n" "-L path set the directory for the BIOS and VGA BIOS\n" +#ifdef USE_KQEMU + "-no-kqemu disable KQEMU kernel module usage\n" +#endif #ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n" #endif @@ -2848,6 +2851,7 @@ enum { QEMU_OPTION_loadvm, QEMU_OPTION_full_screen, QEMU_OPTION_pidfile, + QEMU_OPTION_no_kqemu, }; typedef struct QEMUOption { @@ -2898,6 +2902,9 @@ const QEMUOption qemu_options[] = { { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, { "L", HAS_ARG, QEMU_OPTION_L }, { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, +#ifdef USE_KQEMU + { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, +#endif #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, { "g", 1, QEMU_OPTION_g }, @@ -3358,6 +3365,11 @@ int main(int argc, char **argv) case QEMU_OPTION_pidfile: create_pidfile(optarg); break; +#ifdef USE_KQEMU + case QEMU_OPTION_no_kqemu: + kqemu_allowed = 0; + break; +#endif } } } @@ -3433,12 +3445,7 @@ int main(int argc, char **argv) phys_ram_size = ram_size + vga_ram_size + bios_size; #ifdef CONFIG_SOFTMMU -#ifdef _BSD - /* mallocs are always aligned on BSD. valloc is better for correctness */ - phys_ram_base = valloc(phys_ram_size); -#else - phys_ram_base = memalign(TARGET_PAGE_SIZE, phys_ram_size); -#endif + phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { fprintf(stderr, "Could not allocate physical memory\n"); exit(1); diff --git a/vl.h b/vl.h index 39ea6550b..3fd7ce9ad 100644 --- a/vl.h +++ b/vl.h @@ -124,6 +124,7 @@ extern int graphic_width; extern int graphic_height; extern int graphic_depth; extern const char *keyboard_layout; +extern int kqemu_allowed; /* XXX: make it dynamic */ #if defined (TARGET_PPC) -- cgit v1.2.3 From 0a962c0276f668a5c06948b83a8def0b8d596985 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 22:00:27 +0000 Subject: dirty flag changes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1281 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 17 ++++++++++++++--- exec.c | 44 +++++++++++++++++++++++++++++++------------- hw/tcx.c | 8 +++++--- hw/vga.c | 11 +++++++---- 4 files changed, 57 insertions(+), 23 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 86430791d..afc9ae1a4 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -109,9 +109,11 @@ static inline void tswap64s(uint64_t *s) #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 @@ -733,18 +735,27 @@ void stl_phys(target_phys_addr_t addr, uint32_t val); int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write); +#define VGA_DIRTY_FLAG 0x01 + /* read dirty bit (return 0 or 1) */ static inline int cpu_physical_memory_is_dirty(target_ulong addr) { - return phys_ram_dirty[addr >> TARGET_PAGE_BITS]; + return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff; +} + +static inline int cpu_physical_memory_get_dirty(target_ulong addr, + int dirty_flags) +{ + return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags; } static inline void cpu_physical_memory_set_dirty(target_ulong addr) { - phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff; } -void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end); +void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end, + int dirty_flags); void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); diff --git a/exec.c b/exec.c index 48cbe8574..8fe166bb0 100644 --- a/exec.c +++ b/exec.c @@ -110,7 +110,7 @@ unsigned long qemu_host_page_mask; /* XXX: for system emulation, it could just be an array */ static PageDesc *l1_map[L1_SIZE]; -static PhysPageDesc *l1_phys_map[L1_SIZE]; +PhysPageDesc **l1_phys_map; #if !defined(CONFIG_USER_ONLY) static VirtPageDesc *l1_virt_map[L1_SIZE]; @@ -176,6 +176,8 @@ static void page_init(void) #if !defined(CONFIG_USER_ONLY) virt_valid_tag = 1; #endif + l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *)); + memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *)); } static inline PageDesc *page_find_alloc(unsigned int index) @@ -211,7 +213,7 @@ static inline PhysPageDesc *phys_page_find_alloc(unsigned int index) p = *lp; if (!p) { /* allocate if not found */ - p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE); + p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE); memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE); *lp = p; } @@ -1304,6 +1306,11 @@ void tlb_flush(CPUState *env, int flush_global) #if !defined(CONFIG_SOFTMMU) munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); +#endif +#ifdef USE_KQEMU + if (env->kqemu_enabled) { + kqemu_flush(env, flush_global); + } #endif tlb_flush_count++; } @@ -1362,6 +1369,11 @@ void tlb_flush_page(CPUState *env, target_ulong addr) if (addr < MMAP_AREA_END) munmap((void *)addr, TARGET_PAGE_SIZE); #endif +#ifdef USE_KQEMU + if (env->kqemu_enabled) { + kqemu_flush_page(env, addr); + } +#endif } static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr) @@ -1426,11 +1438,13 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, } } -void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end) +void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end, + int dirty_flags) { CPUState *env; unsigned long length, start1; - int i; + int i, mask, len; + uint8_t *p; start &= TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); @@ -1438,7 +1452,11 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end) length = end - start; if (length == 0) return; - memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS); + mask = ~dirty_flags; + p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); + len = length >> TARGET_PAGE_BITS; + for(i = 0; i < len; i++) + p[i] &= mask; env = cpu_single_env; /* we modify the TLB cache so that the dirty bit will be set again @@ -1497,7 +1515,7 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) CPUState *env = cpu_single_env; int i; - phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff; addr &= TARGET_PAGE_MASK; i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); @@ -1669,7 +1687,7 @@ int page_unprotect(unsigned long addr, unsigned long pc, void *puc) cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n", (unsigned long)addr, vp->prot); /* set the dirty bit */ - phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff; /* flush the code inside */ tb_invalidate_phys_page(vp->phys_addr, pc, puc); return 1; @@ -1887,7 +1905,7 @@ static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) tb_invalidate_phys_page_fast(phys_addr, 1); #endif stb_p((uint8_t *)(long)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; } static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -1899,7 +1917,7 @@ static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) tb_invalidate_phys_page_fast(phys_addr, 2); #endif stw_p((uint8_t *)(long)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; } static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -1911,7 +1929,7 @@ static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) tb_invalidate_phys_page_fast(phys_addr, 4); #endif stl_p((uint8_t *)(long)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; } static CPUReadMemoryFunc *code_mem_read[3] = { @@ -1959,7 +1977,7 @@ static void io_mem_init(void) io_mem_nb = 5; /* alloc dirty bits array */ - phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS); + phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); } /* mem_read and mem_write are arrays of functions containing the @@ -2098,7 +2116,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; } } else { if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && @@ -2219,7 +2237,7 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 1; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; } } diff --git a/hw/tcx.c b/hw/tcx.c index 6b55fc96a..6c4df7c89 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -129,7 +129,7 @@ void tcx_update_display(void *opaque) } for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) { - if (cpu_physical_memory_is_dirty(page)) { + if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { if (y_start < 0) y_start = y; if (page < page_min) @@ -166,7 +166,8 @@ void tcx_update_display(void *opaque) } /* reset modified pages */ if (page_max != -1) { - cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE); + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, + VGA_DIRTY_FLAG); } } @@ -216,7 +217,8 @@ static void tcx_reset(void *opaque) memset(s->b, 0, 256); s->r[255] = s->g[255] = s->b[255] = 255; memset(s->vram, 0, MAXX*MAXY); - cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY); + cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY, + VGA_DIRTY_FLAG); } void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, diff --git a/hw/vga.c b/hw/vga.c index db9e74f19..af463a120 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1454,11 +1454,13 @@ static void vga_draw_graphic(VGAState *s, int full_update) } page0 = s->vram_offset + (addr & TARGET_PAGE_MASK); page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK); - update = full_update | cpu_physical_memory_is_dirty(page0) | - cpu_physical_memory_is_dirty(page1); + update = full_update | + cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) | + cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG); if ((page1 - page0) > TARGET_PAGE_SIZE) { /* if wide line, can use another page */ - update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE); + update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, + VGA_DIRTY_FLAG); } /* explicit invalidation for the hardware cursor */ update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; @@ -1501,7 +1503,8 @@ static void vga_draw_graphic(VGAState *s, int full_update) } /* reset modified pages */ if (page_max != -1) { - cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE); + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, + VGA_DIRTY_FLAG); } memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4); } -- cgit v1.2.3 From 92a31b1fff09bed823865262d4b3c8e7b246c812 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 22:00:52 +0000 Subject: 64 bit support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1282 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 36 ++++++------ monitor.c | 152 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 132 insertions(+), 56 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 684e70eeb..80b964de3 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -306,14 +306,14 @@ extern unsigned long x86_stack_size; static int load_aout_interp(void * exptr, int interp_fd); #ifdef BSWAP_NEEDED -static void bswap_ehdr(Elf32_Ehdr *ehdr) +static void bswap_ehdr(struct elfhdr *ehdr) { bswap16s(&ehdr->e_type); /* Object file type */ bswap16s(&ehdr->e_machine); /* Architecture */ bswap32s(&ehdr->e_version); /* Object file version */ - bswap32s(&ehdr->e_entry); /* Entry point virtual address */ - bswap32s(&ehdr->e_phoff); /* Program header table file offset */ - bswap32s(&ehdr->e_shoff); /* Section header table file offset */ + bswaptls(&ehdr->e_entry); /* Entry point virtual address */ + bswaptls(&ehdr->e_phoff); /* Program header table file offset */ + bswaptls(&ehdr->e_shoff); /* Section header table file offset */ bswap32s(&ehdr->e_flags); /* Processor-specific flags */ bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ @@ -323,30 +323,30 @@ static void bswap_ehdr(Elf32_Ehdr *ehdr) bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ } -static void bswap_phdr(Elf32_Phdr *phdr) +static void bswap_phdr(struct elf_phdr *phdr) { bswap32s(&phdr->p_type); /* Segment type */ - bswap32s(&phdr->p_offset); /* Segment file offset */ - bswap32s(&phdr->p_vaddr); /* Segment virtual address */ - bswap32s(&phdr->p_paddr); /* Segment physical address */ - bswap32s(&phdr->p_filesz); /* Segment size in file */ - bswap32s(&phdr->p_memsz); /* Segment size in memory */ + bswaptls(&phdr->p_offset); /* Segment file offset */ + bswaptls(&phdr->p_vaddr); /* Segment virtual address */ + bswaptls(&phdr->p_paddr); /* Segment physical address */ + bswaptls(&phdr->p_filesz); /* Segment size in file */ + bswaptls(&phdr->p_memsz); /* Segment size in memory */ bswap32s(&phdr->p_flags); /* Segment flags */ - bswap32s(&phdr->p_align); /* Segment alignment */ + bswaptls(&phdr->p_align); /* Segment alignment */ } -static void bswap_shdr(Elf32_Shdr *shdr) +static void bswap_shdr(struct elf_shdr *shdr) { bswap32s(&shdr->sh_name); bswap32s(&shdr->sh_type); - bswap32s(&shdr->sh_flags); - bswap32s(&shdr->sh_addr); - bswap32s(&shdr->sh_offset); - bswap32s(&shdr->sh_size); + bswaptls(&shdr->sh_flags); + bswaptls(&shdr->sh_addr); + bswaptls(&shdr->sh_offset); + bswaptls(&shdr->sh_size); bswap32s(&shdr->sh_link); bswap32s(&shdr->sh_info); - bswap32s(&shdr->sh_addralign); - bswap32s(&shdr->sh_entsize); + bswaptls(&shdr->sh_addralign); + bswaptls(&shdr->sh_entsize); } static void bswap_sym(Elf32_Sym *sym) diff --git a/monitor.c b/monitor.c index ae1ce8792..b9de0295c 100644 --- a/monitor.c +++ b/monitor.c @@ -38,7 +38,8 @@ * 'F' filename * 'B' block device name * 's' string (accept optional quote) - * 'i' integer + * 'i' 32 bit integer + * 'l' target long (32 or 64 bit) * '/' optional gdb-like print format (like "/10x") * * '?' optional type (for 'F', 's' and 'i') @@ -463,7 +464,7 @@ static void memory_dump(int count, int format, int wsize, v = lduw_raw(buf + i); break; case 4: - v = ldl_raw(buf + i); + v = (uint32_t)ldl_raw(buf + i); break; case 8: v = ldq_raw(buf + i); @@ -495,18 +496,31 @@ static void memory_dump(int count, int format, int wsize, } } -static void do_memory_dump(int count, int format, int size, int addr) +#if TARGET_LONG_BITS == 64 +#define GET_TLONG(h, l) (((uint64_t)(h) << 32) | (l)) +#else +#define GET_TLONG(h, l) (l) +#endif + +static void do_memory_dump(int count, int format, int size, + uint32_t addrh, uint32_t addrl) { + target_long addr = GET_TLONG(addrh, addrl); memory_dump(count, format, size, addr, 0); } -static void do_physical_memory_dump(int count, int format, int size, int addr) +static void do_physical_memory_dump(int count, int format, int size, + uint32_t addrh, uint32_t addrl) + { + target_long addr = GET_TLONG(addrh, addrl); memory_dump(count, format, size, addr, 1); } -static void do_print(int count, int format, int size, int val) +static void do_print(int count, int format, int size, unsigned int valh, unsigned int vall) { + target_long val = GET_TLONG(valh, vall); +#if TARGET_LONG_BITS == 32 switch(format) { case 'o': term_printf("%#o", val); @@ -525,6 +539,26 @@ static void do_print(int count, int format, int size, int val) term_printc(val); break; } +#else + switch(format) { + case 'o': + term_printf("%#llo", val); + break; + case 'x': + term_printf("%#llx", val); + break; + case 'u': + term_printf("%llu", val); + break; + default: + case 'd': + term_printf("%lld", val); + break; + case 'c': + term_printc(val); + break; + } +#endif term_printf("\n"); } @@ -859,11 +893,11 @@ static term_cmd_t term_cmds[] = { { "gdbserver", "i?", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, #endif - { "x", "/i", do_memory_dump, + { "x", "/l", do_memory_dump, "/fmt addr", "virtual memory dump starting at 'addr'", }, - { "xp", "/i", do_physical_memory_dump, + { "xp", "/l", do_physical_memory_dump, "/fmt addr", "physical memory dump starting at 'addr'", }, - { "p|print", "/i", do_print, + { "p|print", "/l", do_print, "/fmt expr", "print expression value (use $reg for CPU register access)", }, { "i", "/ii.", do_ioport_read, "/fmt addr", "I/O port read" }, @@ -908,21 +942,25 @@ static term_cmd_t info_cmds[] = { static const char *pch; static jmp_buf expr_env; +#define MD_TLONG 0 +#define MD_I32 1 + typedef struct MonitorDef { const char *name; int offset; - int (*get_value)(struct MonitorDef *md, int val); + target_long (*get_value)(struct MonitorDef *md, int val); + int type; } MonitorDef; #if defined(TARGET_I386) -static int monitor_get_pc (struct MonitorDef *md, int val) +static target_long monitor_get_pc (struct MonitorDef *md, int val) { - return cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base; + return cpu_single_env->eip + cpu_single_env->segs[R_CS].base; } #endif #if defined(TARGET_PPC) -static int monitor_get_ccr (struct MonitorDef *md, int val) +static target_long monitor_get_ccr (struct MonitorDef *md, int val) { unsigned int u; int i; @@ -934,7 +972,7 @@ static int monitor_get_ccr (struct MonitorDef *md, int val) return u; } -static int monitor_get_msr (struct MonitorDef *md, int val) +static target_long monitor_get_msr (struct MonitorDef *md, int val) { return (cpu_single_env->msr[MSR_POW] << MSR_POW) | (cpu_single_env->msr[MSR_ILE] << MSR_ILE) | @@ -953,7 +991,7 @@ static int monitor_get_msr (struct MonitorDef *md, int val) (cpu_single_env->msr[MSR_LE] << MSR_LE); } -static int monitor_get_xer (struct MonitorDef *md, int val) +static target_long monitor_get_xer (struct MonitorDef *md, int val) { return (cpu_single_env->xer[XER_SO] << XER_SO) | (cpu_single_env->xer[XER_OV] << XER_OV) | @@ -961,29 +999,29 @@ static int monitor_get_xer (struct MonitorDef *md, int val) (cpu_single_env->xer[XER_BC] << XER_BC); } -static int monitor_get_decr (struct MonitorDef *md, int val) +static target_long monitor_get_decr (struct MonitorDef *md, int val) { return cpu_ppc_load_decr(cpu_single_env); } -static int monitor_get_tbu (struct MonitorDef *md, int val) +static target_long monitor_get_tbu (struct MonitorDef *md, int val) { return cpu_ppc_load_tbu(cpu_single_env); } -static int monitor_get_tbl (struct MonitorDef *md, int val) +static target_long monitor_get_tbl (struct MonitorDef *md, int val) { return cpu_ppc_load_tbl(cpu_single_env); } #endif #if defined(TARGET_SPARC) -static int monitor_get_psr (struct MonitorDef *md, int val) +static target_long monitor_get_psr (struct MonitorDef *md, int val) { return GET_PSR(cpu_single_env); } -static int monitor_get_reg(struct MonitorDef *md, int val) +static target_long monitor_get_reg(struct MonitorDef *md, int val) { return cpu_single_env->regwptr[val]; } @@ -993,9 +1031,9 @@ static MonitorDef monitor_defs[] = { #ifdef TARGET_I386 #define SEG(name, seg) \ - { name, offsetof(CPUState, segs[seg].selector) },\ + { name, offsetof(CPUState, segs[seg].selector), NULL, MD_I32 },\ { name ".base", offsetof(CPUState, segs[seg].base) },\ - { name ".limit", offsetof(CPUState, segs[seg].limit) }, + { name ".limit", offsetof(CPUState, segs[seg].limit), NULL, MD_I32 }, { "eax", offsetof(CPUState, regs[0]) }, { "ecx", offsetof(CPUState, regs[1]) }, @@ -1005,6 +1043,16 @@ static MonitorDef monitor_defs[] = { { "ebp|fp", offsetof(CPUState, regs[5]) }, { "esi", offsetof(CPUState, regs[6]) }, { "edi", offsetof(CPUState, regs[7]) }, +#ifdef TARGET_X86_64 + { "r8", offsetof(CPUState, regs[8]) }, + { "r9", offsetof(CPUState, regs[9]) }, + { "r10", offsetof(CPUState, regs[10]) }, + { "r11", offsetof(CPUState, regs[11]) }, + { "r12", offsetof(CPUState, regs[12]) }, + { "r13", offsetof(CPUState, regs[13]) }, + { "r14", offsetof(CPUState, regs[14]) }, + { "r15", offsetof(CPUState, regs[15]) }, +#endif { "eflags", offsetof(CPUState, eflags) }, { "eip", offsetof(CPUState, eip) }, SEG("cs", R_CS) @@ -1157,15 +1205,28 @@ static void expr_error(const char *fmt) longjmp(expr_env, 1); } -static int get_monitor_def(int *pval, const char *name) +static int get_monitor_def(target_long *pval, const char *name) { MonitorDef *md; + void *ptr; + for(md = monitor_defs; md->name != NULL; md++) { if (compare_cmd(name, md->name)) { if (md->get_value) { *pval = md->get_value(md, md->offset); } else { - *pval = *(uint32_t *)((uint8_t *)cpu_single_env + md->offset); + ptr = (uint8_t *)cpu_single_env + md->offset; + switch(md->type) { + case MD_I32: + *pval = *(int32_t *)ptr; + break; + case MD_TLONG: + *pval = *(target_long *)ptr; + break; + default: + *pval = 0; + break; + } } return 0; } @@ -1182,11 +1243,11 @@ static void next(void) } } -static int expr_sum(void); +static target_long expr_sum(void); -static int expr_unary(void) +static target_long expr_unary(void) { - int n; + target_long n; char *p; switch(*pch) { @@ -1259,10 +1320,11 @@ static int expr_unary(void) } -static int expr_prod(void) +static target_long expr_prod(void) { - int val, val2, op; - + target_long val, val2; + int op; + val = expr_unary(); for(;;) { op = *pch; @@ -1289,9 +1351,10 @@ static int expr_prod(void) return val; } -static int expr_logic(void) +static target_long expr_logic(void) { - int val, val2, op; + target_long val, val2; + int op; val = expr_prod(); for(;;) { @@ -1316,9 +1379,10 @@ static int expr_logic(void) return val; } -static int expr_sum(void) +static target_long expr_sum(void) { - int val, val2, op; + target_long val, val2; + int op; val = expr_logic(); for(;;) { @@ -1335,7 +1399,7 @@ static int expr_sum(void) return val; } -static int get_expr(int *pval, const char **pp) +static int get_expr(target_long *pval, const char **pp) { pch = *pp; if (setjmp(expr_env)) { @@ -1596,8 +1660,9 @@ static void monitor_handle_command(const char *cmdline) } break; case 'i': + case 'l': { - int val; + target_long val; while (isspace(*p)) p++; if (*typestr == '?' || *typestr == '.') { @@ -1630,9 +1695,20 @@ static void monitor_handle_command(const char *cmdline) if (get_expr(&val, &p)) goto fail; add_num: - if (nb_args >= MAX_ARGS) - goto error_args; - args[nb_args++] = (void *)val; + if (c == 'i') { + if (nb_args >= MAX_ARGS) + goto error_args; + args[nb_args++] = (void *)(int)val; + } else { + if ((nb_args + 1) >= MAX_ARGS) + goto error_args; +#if TARGET_LONG_BITS == 64 + args[nb_args++] = (void *)(int)((val >> 32) & 0xffffffff); +#else + args[nb_args++] = (void *)0; +#endif + args[nb_args++] = (void *)(int)(val & 0xffffffff); + } } break; case '-': -- cgit v1.2.3 From 9df217a31741e21eb63a5e3ee8529391ba3762e3 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 22:05:51 +0000 Subject: kqemu support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1283 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 26 ++++ exec-all.h | 22 +++ kqemu.c | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/cpu.h | 35 +++-- target-i386/helper.c | 28 +++- 5 files changed, 527 insertions(+), 11 deletions(-) create mode 100644 kqemu.c diff --git a/cpu-exec.c b/cpu-exec.c index ff548af7a..4adfb81aa 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -209,7 +209,33 @@ int cpu_exec(CPUState *env1) #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(;;) { #ifdef __sparc__ diff --git a/exec-all.h b/exec-all.h index b1f488cd0..3065858f3 100644 --- a/exec-all.h +++ b/exec-all.h @@ -586,3 +586,25 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; } #endif + + +#ifdef USE_KQEMU +extern int kqemu_fd; +extern int kqemu_flushed; + +int kqemu_init(CPUState *env); +int kqemu_cpu_exec(CPUState *env); +void kqemu_flush_page(CPUState *env, target_ulong addr); +void kqemu_flush(CPUState *env, int global); + +static inline int kqemu_is_ok(CPUState *env) +{ + return(env->kqemu_enabled && + (env->hflags & HF_CPL_MASK) == 3 && + (env->eflags & IOPL_MASK) != IOPL_MASK && + (env->cr[0] & CR0_PE_MASK) && + (env->eflags & IF_MASK) && + !(env->eflags & VM_MASK)); +} + +#endif diff --git a/kqemu.c b/kqemu.c new file mode 100644 index 000000000..20aaf6376 --- /dev/null +++ b/kqemu.c @@ -0,0 +1,427 @@ +/* + * KQEMU support + * + * Copyright (c) 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" +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" + +#ifdef USE_KQEMU + +#define DEBUG + +#include +#include +#include +#include "kqemu/kqemu.h" + +#define KQEMU_DEVICE "/dev/kqemu" + +int kqemu_allowed = 1; +int kqemu_fd = -1; +unsigned long *pages_to_flush; +unsigned int nb_pages_to_flush; +extern uint32_t **l1_phys_map; + +#define cpuid(index, eax, ebx, ecx, edx) \ + asm volatile ("cpuid" \ + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \ + : "0" (index)) + +static int is_cpuid_supported(void) +{ + int v0, v1; + asm volatile ("pushf\n" + "popl %0\n" + "movl %0, %1\n" + "xorl $0x00200000, %0\n" + "pushl %0\n" + "popf\n" + "pushf\n" + "popl %0\n" + : "=a" (v0), "=d" (v1) + : + : "cc"); + return (v0 != v1); +} + +static void kqemu_update_cpuid(CPUState *env) +{ + int critical_features_mask, features; + uint32_t eax, ebx, ecx, edx; + + /* the following features are kept identical on the host and + target cpus because they are important for user code. Strictly + speaking, only SSE really matters because the OS must support + it if the user code uses it. */ + critical_features_mask = + CPUID_CMOV | CPUID_CX8 | + CPUID_FXSR | CPUID_MMX | CPUID_SSE | + CPUID_SSE2; + if (!is_cpuid_supported()) { + features = 0; + } else { + cpuid(1, eax, ebx, ecx, edx); + features = edx; + } + env->cpuid_features = (env->cpuid_features & ~critical_features_mask) | + (features & critical_features_mask); + /* XXX: we could update more of the target CPUID state so that the + non accelerated code sees exactly the same CPU features as the + accelerated code */ +} + +int kqemu_init(CPUState *env) +{ + struct kqemu_init init; + int ret, version; + + if (!kqemu_allowed) + return -1; + + kqemu_fd = open(KQEMU_DEVICE, O_RDWR); + if (kqemu_fd < 0) { + fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE); + return -1; + } + version = 0; + ioctl(kqemu_fd, KQEMU_GET_VERSION, &version); + if (version != KQEMU_VERSION) { + fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n", + version, KQEMU_VERSION); + goto fail; + } + + pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * + sizeof(unsigned long)); + if (!pages_to_flush) + goto fail; + + init.ram_base = phys_ram_base; + init.ram_size = phys_ram_size; + init.ram_dirty = phys_ram_dirty; + init.phys_to_ram_map = l1_phys_map; + init.pages_to_flush = pages_to_flush; + ret = ioctl(kqemu_fd, KQEMU_INIT, &init); + if (ret < 0) { + fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret); + fail: + close(kqemu_fd); + kqemu_fd = -1; + return -1; + } + kqemu_update_cpuid(env); + env->kqemu_enabled = 1; + nb_pages_to_flush = 0; + return 0; +} + +void kqemu_flush_page(CPUState *env, target_ulong addr) +{ +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr); + } +#endif + if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH) + nb_pages_to_flush = KQEMU_FLUSH_ALL; + else + pages_to_flush[nb_pages_to_flush++] = addr; +} + +void kqemu_flush(CPUState *env, int global) +{ +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "kqemu_flush:\n"); + } +#endif + nb_pages_to_flush = KQEMU_FLUSH_ALL; +} + +struct fpstate { + uint16_t fpuc; + uint16_t dummy1; + uint16_t fpus; + uint16_t dummy2; + uint16_t fptag; + uint16_t dummy3; + + uint32_t fpip; + uint32_t fpcs; + uint32_t fpoo; + uint32_t fpos; + uint8_t fpregs1[8 * 10]; +}; + +struct fpxstate { + uint16_t fpuc; + uint16_t fpus; + uint16_t fptag; + uint16_t fop; + uint32_t fpuip; + uint16_t cs_sel; + uint16_t dummy0; + uint32_t fpudp; + uint16_t ds_sel; + uint16_t dummy1; + uint32_t mxcsr; + uint32_t mxcsr_mask; + uint8_t fpregs1[8 * 16]; + uint8_t xmm_regs[8 * 16]; + uint8_t dummy2[224]; +}; + +static struct fpxstate fpx1 __attribute__((aligned(16))); + +static void restore_native_fp_frstor(CPUState *env) +{ + int fptag, i, j; + struct fpstate fp1, *fp = &fp1; + + fp->fpuc = env->fpuc; + fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for (i=7; i>=0; i--) { + fptag <<= 2; + if (env->fptags[i]) { + fptag |= 3; + } else { + /* the FPU automatically computes it */ + } + } + fp->fptag = fptag; + j = env->fpstt; + for(i = 0;i < 8; i++) { + memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10); + j = (j + 1) & 7; + } + asm volatile ("frstor %0" : "=m" (*fp)); +} + +static void save_native_fp_fsave(CPUState *env) +{ + int fptag, i, j; + uint16_t fpuc; + struct fpstate fp1, *fp = &fp1; + + asm volatile ("fsave %0" : : "m" (*fp)); + env->fpuc = fp->fpuc; + env->fpstt = (fp->fpus >> 11) & 7; + env->fpus = fp->fpus & ~0x3800; + fptag = fp->fptag; + for(i = 0;i < 8; i++) { + env->fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } + j = env->fpstt; + for(i = 0;i < 8; i++) { + memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10); + j = (j + 1) & 7; + } + /* we must restore the default rounding state */ + fpuc = 0x037f | (env->fpuc & (3 << 10)); + asm volatile("fldcw %0" : : "m" (fpuc)); +} + +static void restore_native_fp_fxrstor(CPUState *env) +{ + struct fpxstate *fp = &fpx1; + int i, j, fptag; + + fp->fpuc = env->fpuc; + fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + fptag = 0; + for(i = 0; i < 8; i++) + fptag |= (env->fptags[i] << i); + fp->fptag = fptag ^ 0xff; + + j = env->fpstt; + for(i = 0;i < 8; i++) { + memcpy(&fp->fpregs1[i * 16], &env->fpregs[j].d, 10); + j = (j + 1) & 7; + } + if (env->cpuid_features & CPUID_SSE) { + fp->mxcsr = env->mxcsr; + /* XXX: check if DAZ is not available */ + fp->mxcsr_mask = 0xffff; + memcpy(fp->xmm_regs, env->xmm_regs, 8 * 16); + } + asm volatile ("fxrstor %0" : "=m" (*fp)); +} + +static void save_native_fp_fxsave(CPUState *env) +{ + struct fpxstate *fp = &fpx1; + int fptag, i, j; + uint16_t fpuc; + + asm volatile ("fxsave %0" : : "m" (*fp)); + env->fpuc = fp->fpuc; + env->fpstt = (fp->fpus >> 11) & 7; + env->fpus = fp->fpus & ~0x3800; + fptag = fp->fptag ^ 0xff; + for(i = 0;i < 8; i++) { + env->fptags[i] = (fptag >> i) & 1; + } + j = env->fpstt; + for(i = 0;i < 8; i++) { + memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 16], 10); + j = (j + 1) & 7; + } + if (env->cpuid_features & CPUID_SSE) { + env->mxcsr = fp->mxcsr; + memcpy(env->xmm_regs, fp->xmm_regs, 8 * 16); + } + + /* we must restore the default rounding state */ + asm volatile ("fninit"); + fpuc = 0x037f | (env->fpuc & (3 << 10)); + asm volatile("fldcw %0" : : "m" (fpuc)); +} + +int kqemu_cpu_exec(CPUState *env) +{ + struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; + int ret; + +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "kqemu: cpu_exec: enter\n"); + cpu_dump_state(env, logfile, fprintf, 0); + } +#endif + memcpy(kenv->regs, env->regs, sizeof(kenv->regs)); + kenv->eip = env->eip; + kenv->eflags = env->eflags; + memcpy(&kenv->segs, &env->segs, sizeof(env->segs)); + memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt)); + memcpy(&kenv->tr, &env->tr, sizeof(env->tr)); + memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt)); + memcpy(&kenv->idt, &env->idt, sizeof(env->idt)); + kenv->cr0 = env->cr[0]; + kenv->cr2 = env->cr[2]; + kenv->cr3 = env->cr[3]; + kenv->cr4 = env->cr[4]; + kenv->a20_mask = env->a20_mask; + if (env->dr[7] & 0xff) { + kenv->dr7 = env->dr[7]; + kenv->dr0 = env->dr[0]; + kenv->dr1 = env->dr[1]; + kenv->dr2 = env->dr[2]; + kenv->dr3 = env->dr[3]; + } else { + kenv->dr7 = 0; + } + kenv->dr6 = env->dr[6]; + kenv->cpl = 3; + kenv->nb_pages_to_flush = nb_pages_to_flush; + nb_pages_to_flush = 0; + + if (!(kenv->cr0 & CR0_TS_MASK)) { + if (env->cpuid_features & CPUID_FXSR) + restore_native_fp_fxrstor(env); + else + restore_native_fp_frstor(env); + } + + ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv); + + if (!(kenv->cr0 & CR0_TS_MASK)) { + if (env->cpuid_features & CPUID_FXSR) + save_native_fp_fxsave(env); + else + save_native_fp_fsave(env); + } + + memcpy(env->regs, kenv->regs, sizeof(env->regs)); + env->eip = kenv->eip; + env->eflags = kenv->eflags; + memcpy(env->segs, kenv->segs, sizeof(env->segs)); +#if 0 + /* no need to restore that */ + memcpy(env->ldt, kenv->ldt, sizeof(env->ldt)); + memcpy(env->tr, kenv->tr, sizeof(env->tr)); + memcpy(env->gdt, kenv->gdt, sizeof(env->gdt)); + memcpy(env->idt, kenv->idt, sizeof(env->idt)); + env->cr[0] = kenv->cr0; + env->cr[3] = kenv->cr3; + env->cr[4] = kenv->cr4; + env->a20_mask = kenv->a20_mask; +#endif + env->cr[2] = kenv->cr2; + env->dr[6] = kenv->dr6; + +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret); + } +#endif + if ((ret & 0xff00) == KQEMU_RET_INT) { + env->exception_index = ret & 0xff; + env->error_code = 0; + env->exception_is_int = 1; + env->exception_next_eip = kenv->next_eip; +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "kqemu: interrupt v=%02x:\n", + env->exception_index); + cpu_dump_state(env, logfile, fprintf, 0); + } +#endif + return 1; + } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) { + env->exception_index = ret & 0xff; + env->error_code = kenv->error_code; + env->exception_is_int = 0; + env->exception_next_eip = 0; +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n", + env->exception_index, env->error_code); + cpu_dump_state(env, logfile, fprintf, 0); + } +#endif + return 1; + } else if (ret == KQEMU_RET_INTR) { + return 0; + } else if (ret == KQEMU_RET_SOFTMMU) { + return 2; + } else { + cpu_dump_state(env, stderr, fprintf, 0); + fprintf(stderr, "Unsupported return value: 0x%x\n", ret); + exit(1); + } + return 0; +} + +#endif diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 781be2838..74c882b86 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -39,6 +39,9 @@ #if defined(__i386__) && !defined(CONFIG_SOFTMMU) #define USE_CODE_COPY #endif +#if defined(__linux__) && defined(CONFIG_SOFTMMU) && defined(__i386__) && !defined(TARGET_X86_64) +#define USE_KQEMU +#endif #define R_EAX 0 #define R_ECX 1 @@ -248,6 +251,14 @@ #define CPUID_SSE (1 << 25) #define CPUID_SSE2 (1 << 26) +#define CPUID_EXT_SS3 (1 << 0) +#define CPUID_EXT_MONITOR (1 << 3) +#define CPUID_EXT_CX16 (1 << 13) + +#define CPUID_EXT2_SYSCALL (1 << 11) +#define CPUID_EXT2_NX (1 << 20) +#define CPUID_EXT2_LM (1 << 29) + #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 #define EXCP02_NMI 2 @@ -408,6 +419,16 @@ typedef struct CPUX86State { int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ uint32_t hflags; /* hidden flags, see HF_xxx constants */ + /* segments */ + SegmentCache segs[6]; /* selector values */ + SegmentCache ldt; + SegmentCache tr; + SegmentCache gdt; /* only base and limit are used */ + SegmentCache idt; /* only base and limit are used */ + + target_ulong cr[5]; /* NOTE: cr1 is unused */ + uint32_t a20_mask; + /* FPU state */ unsigned int fpstt; /* top of stack index */ unsigned int fpus; @@ -431,13 +452,6 @@ typedef struct CPUX86State { int64_t i64; } fp_convert; - /* segments */ - SegmentCache segs[6]; /* selector values */ - SegmentCache ldt; - SegmentCache tr; - SegmentCache gdt; /* only base and limit are used */ - SegmentCache idt; /* only base and limit are used */ - uint32_t mxcsr; XMMReg xmm_regs[CPU_NB_REGS]; XMMReg xmm_t0; @@ -470,13 +484,10 @@ typedef struct CPUX86State { int exception_is_int; target_ulong exception_next_eip; struct TranslationBlock *current_tb; /* currently executing TB */ - target_ulong cr[5]; /* NOTE: cr1 is unused */ target_ulong dr[8]; /* debug registers */ int interrupt_request; int user_mode_only; /* user mode only simulation */ - uint32_t a20_mask; - /* 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 @@ -501,7 +512,11 @@ typedef struct CPUX86State { uint32_t cpuid_vendor3; uint32_t cpuid_version; uint32_t cpuid_features; + uint32_t cpuid_ext_features; +#ifdef USE_KQEMU + int kqemu_enabled; +#endif /* in order to simplify APIC support, we leave this pointer to the user */ struct APICState *apic_state; diff --git a/target-i386/helper.c b/target-i386/helper.c index ea2ef5e02..b727e93d6 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1274,7 +1274,7 @@ void helper_cpuid(void) case 1: EAX = env->cpuid_version; EBX = 0; - ECX = 0; + ECX = env->cpuid_ext_features; EDX = env->cpuid_features; break; default: @@ -1828,6 +1828,12 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) ESP = (ESP & ~sp_mask) | (sp & sp_mask); EIP = offset; } +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + env->exception_index = -1; + cpu_loop_exit(); + } +#endif } /* real and vm86 mode iret */ @@ -2097,11 +2103,25 @@ void helper_iret_protected(int shift, int next_eip) } else { helper_ret_protected(shift, 1, 0); } +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + CC_OP = CC_OP_EFLAGS; + env->exception_index = -1; + cpu_loop_exit(); + } +#endif } void helper_lret_protected(int shift, int addend) { helper_ret_protected(shift, 0, addend); +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + CC_OP = CC_OP_EFLAGS; + env->exception_index = -1; + cpu_loop_exit(); + } +#endif } void helper_sysenter(void) @@ -2146,6 +2166,12 @@ void helper_sysexit(void) DESC_W_MASK | DESC_A_MASK); ESP = ECX; EIP = EDX; +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + env->exception_index = -1; + cpu_loop_exit(); + } +#endif } void helper_movl_crN_T0(int reg) -- cgit v1.2.3 From bf079a1e703f8d58ba7dcd9b0bcd793e66c962f4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Feb 2005 22:06:29 +0000 Subject: enabled MMX, PAE and SEP git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1284 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 9ecf05d93..730af1b52 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -98,7 +98,7 @@ CPUX86State *cpu_x86_init(void) #else /* pentium pro */ family = 6; - model = 1; + model = 3; stepping = 3; #endif #endif @@ -106,14 +106,18 @@ CPUX86State *cpu_x86_init(void) env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV); + env->cpuid_ext_features = 0; + env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP; #ifdef TARGET_X86_64 /* currently not enabled for std i386 because not fully tested */ - env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2; - env->cpuid_features |= CPUID_APIC | CPUID_PAE; + env->cpuid_features |= CPUID_APIC; #endif } cpu_single_env = env; cpu_reset(env); +#ifdef USE_KQEMU + kqemu_init(env); +#endif return env; } @@ -453,6 +457,8 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)); } +/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in + the PDPT */ void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3) { env->cr[3] = new_cr3; -- cgit v1.2.3 From 441c72ba15628e85bda1207cc92b55f77403764b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Feb 2005 14:45:23 +0000 Subject: kqemu is an external project git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1285 c046a42c-6fe2-441c-8c8c-71466251a162 --- LICENSE | 16 +--------------- configure | 7 +++++++ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/LICENSE b/LICENSE index b403f41bd..bfc9a1f42 100644 --- a/LICENSE +++ b/LICENSE @@ -7,20 +7,6 @@ The following points clarify the QEMU licenses: 2) The Linux user mode QEMU emulator is released under the GNU General Public License. -3) The QEMU Accelerator Module is a proprietary product. It is - available without charge. Commercial use of the QEMU Accelerator - Module is allowed. - - Redistribution of the QEMU Accelerator Module: any person or - organisation wishing to distribute it, for example on a CD or as a - binary or source package, must have an explicit authorization from - the author. - - The QEMU Accelerator Module is available without any express or - implied warranty. In no event will the author be held liable for - any damages arising from the use of this software. - -4) QEMU is a trademark of Fabrice Bellard. - +3) QEMU is a trademark of Fabrice Bellard. Fabrice Bellard. \ No newline at end of file diff --git a/configure b/configure index 4b93737ef..21ea62a52 100755 --- a/configure +++ b/configure @@ -347,6 +347,13 @@ bindir="$prefix/bin" fi # kernel module support +if test $kqemu = "yes" ; then + # test if the source code is installed + if test '!' -f "kqemu/Makefile" ; then + kqemu="no" + fi +fi + if test $kqemu = "yes" ; then # find the kernel path if test -z "$kernel_path" ; then -- cgit v1.2.3 From 9117a4ab9178e97e74149aab0dce6a3ce342a123 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Feb 2005 14:50:42 +0000 Subject: disable USE_KQEMU if no source git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1286 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 74c882b86..38f9595af 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -39,7 +39,7 @@ #if defined(__i386__) && !defined(CONFIG_SOFTMMU) #define USE_CODE_COPY #endif -#if defined(__linux__) && defined(CONFIG_SOFTMMU) && defined(__i386__) && !defined(TARGET_X86_64) +#if defined(CONFIG_KQEMU) && defined(__linux__) && defined(CONFIG_SOFTMMU) && defined(__i386__) && !defined(TARGET_X86_64) #define USE_KQEMU #endif -- cgit v1.2.3 From 0443eaf6aeea33b91c0c7bdc54f9c37157edf527 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Feb 2005 15:02:03 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1287 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 9c25728b6..d3287a886 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1161,6 +1161,12 @@ tar zxvf qemu-x.y.z.tar.gz cd qemu-x.y.z @end example +If you want to use the optional QEMU Accelerator Module, then download +it and install it in qemu-x.y.z/: +@example +tar zxvf /tmp/kqemu-x.y.z.tar.gz +@end example + Then you configure QEMU and build it (usually no options are needed): @example ./configure @@ -1226,7 +1232,7 @@ following in @file{/etc/rc.d/rc.local}: @example # Create the KQEMU device -mknod /dev/kqemu c 254 0 +mknod /dev/kqemu c 250 0 chmod 666 /dev/kqemu @end example -- cgit v1.2.3 From 580a5e27c63809abd633290950e387daedddcafa Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Feb 2005 15:16:03 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1288 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index d3287a886..0e8a960c7 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -443,6 +443,10 @@ usually mounted on it (check with the shell command @var{QEMU_TMPDIR} shell variable to set a new directory for the QEMU RAM file. +KQEMU has only been tested with Linux 2.4, Linux 2.6 and Windows 2000 +as guest OSes. If your guest OS do not work with KQEMU, you can +dynamically disable KQEMU with the @option{-no-kqemu} option. + @section QEMU Monitor The QEMU monitor is used to give complex commands to the QEMU -- cgit v1.2.3 From 824d560f0973d8e4c1ce4e614ed070e7c994bf02 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 12 Feb 2005 18:58:00 +0000 Subject: fixed kqemu config git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1289 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++++ target-i386/cpu.h | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 21ea62a52..cc21847c8 100755 --- a/configure +++ b/configure @@ -195,6 +195,7 @@ if test "$mingw32" = "yes" ; then EXESUF=".exe" gdbstub="no" oss="no" + kqemu="no" fi if test -z "$target_list" ; then @@ -609,6 +610,9 @@ 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" ; 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 diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 38f9595af..154d8bfda 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -39,9 +39,6 @@ #if defined(__i386__) && !defined(CONFIG_SOFTMMU) #define USE_CODE_COPY #endif -#if defined(CONFIG_KQEMU) && defined(__linux__) && defined(CONFIG_SOFTMMU) && defined(__i386__) && !defined(TARGET_X86_64) -#define USE_KQEMU -#endif #define R_EAX 0 #define R_ECX 1 -- cgit v1.2.3 From 1a0c3292b58704843ab97e71c9836f653a31090b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Feb 2005 19:02:07 +0000 Subject: sparc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1290 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 4adfb81aa..1edfa19a0 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -204,8 +204,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_PPC) do_interrupt(env); #elif defined(TARGET_SPARC) - do_interrupt(env->exception_index, - env->error_code); + do_interrupt(env->exception_index); #endif } env->exception_index = -1; @@ -287,7 +286,7 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_SPARC) if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(env->interrupt_index, 0); + do_interrupt(env->interrupt_index); env->interrupt_request &= ~CPU_INTERRUPT_HARD; } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); -- cgit v1.2.3 From 878d3096d20c3b77f5aaa25460d470bc7d8da15b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Feb 2005 19:02:42 +0000 Subject: sparc fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1291 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 5 +++-- target-sparc/exec.h | 2 +- target-sparc/helper.c | 42 ++++++++++++++++++++---------------------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index a4b6c730f..f07464deb 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -18,15 +18,17 @@ /*#define EXCP_INTERRUPT 0x100*/ /* trap definitions */ +#define TT_TFAULT 0x01 #define TT_ILL_INSN 0x02 #define TT_PRIV_INSN 0x03 #define TT_NFPU_INSN 0x04 #define TT_WIN_OVF 0x05 #define TT_WIN_UNF 0x06 #define TT_FP_EXCP 0x08 +#define TT_DFAULT 0x09 +#define TT_EXTINT 0x10 #define TT_DIV_ZERO 0x2a #define TT_TRAP 0x80 -#define TT_EXTINT 0x10 #define PSR_NEG (1<<23) #define PSR_ZERO (1<<22) @@ -142,7 +144,6 @@ typedef struct CPUSPARCState { /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; - int error_code; /* MMU regs */ uint32_t mmuregs[16]; /* temporary float registers */ diff --git a/target-sparc/exec.h b/target-sparc/exec.h index f905bdfe1..5e6c06214 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -41,7 +41,7 @@ void do_fcmpd(void); void do_ldd_kernel(target_ulong addr); void do_ldd_user(target_ulong addr); void do_ldd_raw(target_ulong addr); -void do_interrupt(int intno, int error_code); +void do_interrupt(int intno); void raise_exception(int tt); void memcpy32(target_ulong *dst, const target_ulong *src); target_ulong mmu_probe(target_ulong address, int mmulev); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index b23be7cee..671d2f9b6 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -44,8 +44,10 @@ int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { env->mmuregs[4] = address; - env->exception_index = 0; /* XXX: must be incorrect */ - env->error_code = -2; /* XXX: is it really used ! */ + if (rw & 2) + env->exception_index = TT_TFAULT; + else + env->exception_index = TT_DFAULT; return 1; } @@ -95,7 +97,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) cpu_restore_state(tb, env, pc, NULL); } } - raise_exception(ret); + cpu_loop_exit(); } env = saved_env; } @@ -229,7 +231,6 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { - int exception = 0; target_ulong virt_addr; target_phys_addr_t paddr; unsigned long vaddr; @@ -248,11 +249,15 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2; env->mmuregs[4] = address; /* Fault address register */ - if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault - return 0; - env->exception_index = exception; - env->error_code = error_code; - return error_code; + if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { + // No fault + cpu_abort(env, "Unsupported MMU no fault case"); + } + if (rw & 2) + env->exception_index = TT_TFAULT; + else + env->exception_index = TT_DFAULT; + return 1; } #endif @@ -289,15 +294,15 @@ void cpu_set_cwp(CPUState *env1, int new_cwp) env = saved_env; } -void do_interrupt(int intno, int error_code) +void do_interrupt(int intno) { int cwp; #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_INT) { static int count; - fprintf(logfile, "%6d: v=%02x e=%04x pc=%08x npc=%08x SP=%08x\n", - count, intno, error_code, + fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", + count, intno, env->pc, env->npc, env->regwptr[6]); #if 1 @@ -319,22 +324,15 @@ void do_interrupt(int intno, int error_code) #endif #if !defined(CONFIG_USER_ONLY) if (env->psret == 0) { - cpu_abort(cpu_single_env, "Trap while interrupts disabled, Error state"); + cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); return; } #endif env->psret = 0; cwp = (env->cwp - 1) & (NWINDOWS - 1); set_cwp(cwp); - if (intno & 0x80) { - env->regwptr[9] = env->pc; - env->regwptr[10] = env->npc; - } else { - /* XXX: this code is clearly incorrect - npc should have the - incorrect value */ - env->regwptr[9] = env->pc - 4; // XXX? - env->regwptr[10] = env->pc; - } + env->regwptr[9] = env->pc; + env->regwptr[10] = env->npc; env->psrps = env->psrs; env->psrs = 1; env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); -- cgit v1.2.3 From 0bee699e1db8170071902dbbde9c6b932883a897 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Feb 2005 20:11:30 +0000 Subject: fixed jmpl, rett and call git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1292 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 5 +++++ target-sparc/translate.c | 34 +++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index dd8295e55..7fa98f16b 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -812,6 +812,11 @@ void OPPROTO op_movl_npc_T0(void) env->npc = T0; } +void OPPROTO op_mov_pc_npc(void) +{ + env->pc = env->npc; +} + void OPPROTO op_next_insn(void) { env->pc = env->npc; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 0baf8036e..7b5642828 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -427,6 +427,20 @@ static inline void save_state(DisasContext * dc) save_npc(dc); } +static inline void gen_mov_pc_npc(DisasContext * dc) +{ + if (dc->npc == JUMP_PC) { + gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); + gen_op_mov_pc_npc(); + dc->pc = DYNAMIC_PC; + } else if (dc->npc == DYNAMIC_PC) { + gen_op_mov_pc_npc(); + dc->pc = DYNAMIC_PC; + } else { + dc->pc = dc->npc; + } +} + static void gen_cond(int cond) { switch (cond) { @@ -525,6 +539,7 @@ static void gen_fcond(int cond) } } +/* XXX: potentially incorrect if dynamic npc */ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); @@ -533,7 +548,7 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn) if (cond == 0x0) { /* unconditional not taken */ if (a) { - dc->pc = dc->npc + 4; + dc->pc = dc->npc + 4; dc->npc = dc->pc + 4; } else { dc->pc = dc->npc; @@ -563,6 +578,7 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn) } } +/* XXX: potentially incorrect if dynamic npc */ static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); @@ -609,6 +625,7 @@ static int sign_extend(int x, int len) return (x << len) >> len; } +/* before an instruction, dc->pc must be static */ static void disas_sparc_insn(DisasContext * dc) { unsigned int insn, opc, rs1, rs2, rd; @@ -669,7 +686,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movl_T0_im(dc->pc); gen_movl_T0_reg(15); target += dc->pc; - dc->pc = dc->npc; + gen_mov_pc_npc(dc); dc->npc = target; } goto jmp_insn; @@ -1173,12 +1190,12 @@ static void disas_sparc_insn(DisasContext * dc) switch (xop) { case 0x38: /* jmpl */ { - gen_op_movl_npc_T0(); if (rd != 0) { - gen_op_movl_T0_im(dc->pc); - gen_movl_T0_reg(rd); + gen_op_movl_T1_im(dc->pc); + gen_movl_T1_reg(rd); } - dc->pc = dc->npc; + gen_mov_pc_npc(dc); + gen_op_movl_npc_T0(); dc->npc = DYNAMIC_PC; } goto jmp_insn; @@ -1187,10 +1204,12 @@ static void disas_sparc_insn(DisasContext * dc) { if (!supervisor(dc)) goto priv_insn; + gen_mov_pc_npc(dc); gen_op_movl_npc_T0(); + dc->npc = DYNAMIC_PC; gen_op_rett(); } - break; + goto jmp_insn; #endif case 0x3b: /* flush */ gen_op_flush_T0(); @@ -1605,6 +1624,7 @@ void cpu_reset(CPUSPARCState *env) env->user_mode_only = 1; #else env->psrs = 1; + env->psrps = 1; env->pc = 0xffd00000; env->gregs[1] = ram_size; env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ -- cgit v1.2.3 From 61ff6f58e90af68c572b29dccc537359b0ce1a1e Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Feb 2005 22:54:53 +0000 Subject: sparc sigsegv support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1293 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index f406f615d..b3f88dd16 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -476,6 +476,7 @@ static void flush_windows(CPUSPARCState *env) void cpu_loop (CPUSPARCState *env) { int trapnr, ret; + target_siginfo_t info; while (1) { trapnr = cpu_sparc_exec (env); @@ -510,6 +511,17 @@ void cpu_loop (CPUSPARCState *env) case TT_WIN_UNF: /* window underflow */ restore_window(env); break; + case TT_TFAULT: + case TT_DFAULT: + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->mmuregs[4]; + queue_signal(info.si_signo, &info); + } + break; case 0x100: // XXX, why do we get these? break; default: -- cgit v1.2.3 From 7483750d7d5513911bf68e5810aaf6cebc0cf7b5 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Feb 2005 22:55:43 +0000 Subject: sparc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1294 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/helper.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 671d2f9b6..0269d2eec 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -137,6 +137,8 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot return 0; } + *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); + /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); @@ -146,10 +148,10 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot switch (pde & PTE_ENTRYTYPE_MASK) { default: case 0: /* Invalid */ - return 1; + return 1 << 2; case 2: /* L0 PTE, maybe should not happen? */ case 3: /* Reserved */ - return 4; + return 4 << 2; case 1: /* L0 PDE */ pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); @@ -157,9 +159,9 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot switch (pde & PTE_ENTRYTYPE_MASK) { default: case 0: /* Invalid */ - return 1; + return (1 << 8) | (1 << 2); case 3: /* Reserved */ - return 4; + return (1 << 8) | (4 << 2); case 1: /* L1 PDE */ pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); @@ -167,9 +169,9 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot switch (pde & PTE_ENTRYTYPE_MASK) { default: case 0: /* Invalid */ - return 1; + return (2 << 8) | (1 << 2); case 3: /* Reserved */ - return 4; + return (2 << 8) | (4 << 2); case 1: /* L2 PDE */ pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); @@ -177,10 +179,10 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot switch (pde & PTE_ENTRYTYPE_MASK) { default: case 0: /* Invalid */ - return 1; + return (3 << 8) | (1 << 2); case 1: /* PDE, should not happen */ case 3: /* Reserved */ - return 4; + return (3 << 8) | (4 << 2); case 2: /* L3 PTE */ virt_addr = address & TARGET_PAGE_MASK; page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1); @@ -206,7 +208,6 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot stl_phys_notdirty(pde_ptr, pde); } /* check access */ - *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; error_code = access_table[*access_index][access_perms]; if (error_code) @@ -246,18 +247,28 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, if (env->mmuregs[3]) /* Fault status register */ env->mmuregs[3] = 1; /* overflow (not read before another fault) */ - env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2; + env->mmuregs[3] |= (access_index << 5) | error_code | 2; env->mmuregs[4] = address; /* Fault address register */ if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { +#if 0 // No fault - cpu_abort(env, "Unsupported MMU no fault case"); + vaddr = address & TARGET_PAGE_MASK; + paddr = 0xfffff000; + prot = PAGE_READ | PAGE_WRITE; + ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + return ret; +#else + cpu_abort(env, "MMU no fault case no handled"); + return 0; +#endif + } else { + if (rw & 2) + env->exception_index = TT_TFAULT; + else + env->exception_index = TT_DFAULT; + return 1; } - if (rw & 2) - env->exception_index = TT_TFAULT; - else - env->exception_index = TT_DFAULT; - return 1; } #endif -- cgit v1.2.3 From 3988e8977b8267a468377a03cc9afb643615a8fa Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Feb 2005 22:58:51 +0000 Subject: ADB reset support (Joceylin Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1295 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adb.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index 36c4aecd2..2acfe65bf 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -248,13 +248,25 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, return olen; } +static int adb_kbd_reset(ADBDevice *d) +{ + KBDState *s = d->opaque; + + d->handler = 1; + d->devaddr = ADB_KEYBOARD; + memset(s, 0, sizeof(KBDState)); + + return 0; +} + void adb_kbd_init(ADBBusState *bus) { ADBDevice *d; KBDState *s; s = qemu_mallocz(sizeof(KBDState)); - d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, NULL, s); - d->handler = 1; + d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, + adb_kbd_reset, s); + adb_kbd_reset(d); qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); } @@ -374,13 +386,25 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, return olen; } +static int adb_mouse_reset(ADBDevice *d) +{ + MouseState *s = d->opaque; + + d->handler = 2; + d->devaddr = ADB_MOUSE; + memset(s, 0, sizeof(MouseState)); + + return 0; +} + void adb_mouse_init(ADBBusState *bus) { ADBDevice *d; MouseState *s; s = qemu_mallocz(sizeof(MouseState)); - d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, NULL, s); - d->handler = 2; + d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, + adb_mouse_reset, s); + adb_mouse_reset(d); qemu_add_mouse_event_handler(adb_mouse_event, d); } -- cgit v1.2.3 From c4decf377c314c48795ddd3ead1ce3d2ea981ca0 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Feb 2005 22:59:52 +0000 Subject: ppc fixes (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1296 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 1edfa19a0..835ca4247 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -354,7 +354,7 @@ int cpu_exec(CPUState *env1) cs_base = env->npc; pc = env->pc; #elif defined(TARGET_PPC) - flags = 0; + flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_se << MSR_SE); cs_base = 0; pc = env->nip; #else -- cgit v1.2.3 From 3cc6237083cd40247e060c1fcf403a2d9ccbaf92 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Feb 2005 23:06:19 +0000 Subject: ppc fixes (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1297 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 -- target-ppc/helper.c | 16 --------- target-ppc/op.c | 38 ++++++++++---------- target-ppc/op_helper.c | 17 ++++++--- target-ppc/translate.c | 95 +++++++++++++++++++++++++++++++++++++------------- 5 files changed, 101 insertions(+), 67 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 123cb3f91..1776a3577 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -24,8 +24,6 @@ #include "cpu-defs.h" -//#define USE_OPEN_FIRMWARE - #include "config.h" #include diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 21e89008f..a9424dfa7 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -18,10 +18,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec.h" -#if defined (USE_OPEN_FIRMWARE) -#include -#include "of.h" -#endif //#define DEBUG_MMU //#define DEBUG_BATS @@ -688,18 +684,6 @@ void do_interrupt (CPUState *env) } /* Generate informations in save/restore registers */ switch (excp) { - case EXCP_OFCALL: -#if defined (USE_OPEN_FIRMWARE) - env->gpr[3] = OF_client_entry((void *)env->gpr[3]); -#endif - return; - case EXCP_RTASCALL: -#if defined (USE_OPEN_FIRMWARE) - printf("RTAS call !\n"); - env->gpr[3] = RTAS_entry((void *)env->gpr[3]); - printf("RTAS call done\n"); -#endif - return; case EXCP_NONE: /* Do nothing */ #if defined (DEBUG_EXCEPTIONS) diff --git a/target-ppc/op.c b/target-ppc/op.c index c6c0989ce..5accc5506 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -697,9 +697,9 @@ PPC_OP(addzeo) PPC_OP(divw) { if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { - Ts0 = (-1) * (T0 >> 31); + T0 = (int32_t)((-1) * (T0 >> 31)); } else { - Ts0 /= Ts1; + T0 = (Ts0 / Ts1); } RETURN(); } @@ -712,7 +712,7 @@ PPC_OP(divwo) T0 = (-1) * (T0 >> 31); } else { xer_ov = 0; - Ts0 /= Ts1; + T0 = (Ts0 / Ts1); } RETURN(); } @@ -744,7 +744,7 @@ PPC_OP(divwuo) /* multiply high word */ PPC_OP(mulhw) { - Ts0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32; + T0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32; RETURN(); } @@ -758,7 +758,7 @@ PPC_OP(mulhwu) /* multiply low immediate */ PPC_OP(mulli) { - Ts0 *= SPARAM(1); + T0 = (Ts0 * SPARAM(1)); RETURN(); } @@ -779,7 +779,7 @@ PPC_OP(mullwo) } else { xer_ov = 0; } - Ts0 = res; + T0 = (int32_t)res; RETURN(); } @@ -787,7 +787,7 @@ PPC_OP(mullwo) PPC_OP(neg) { if (T0 != 0x80000000) { - Ts0 = -Ts0; + T0 = -Ts0; } RETURN(); } @@ -799,7 +799,7 @@ PPC_OP(nego) xer_so = 1; } else { xer_ov = 0; - Ts0 = -Ts0; + T0 = -Ts0; } RETURN(); } @@ -1047,14 +1047,14 @@ PPC_OP(eqv) /* extend sign byte */ PPC_OP(extsb) { - Ts0 = (int8_t)(Ts0); + T0 = (int32_t)((int8_t)(Ts0)); RETURN(); } /* extend sign half word */ PPC_OP(extsh) { - Ts0 = (int16_t)(Ts0); + T0 = (int32_t)((int16_t)(Ts0)); RETURN(); } @@ -1175,8 +1175,8 @@ PPC_OP(sraw) /* shift right algebraic word immediate */ PPC_OP(srawi) { - Ts1 = Ts0; - Ts0 = Ts0 >> PARAM(1); + T1 = T0; + T0 = (Ts0 >> PARAM(1)); if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) { xer_ca = 1; } else { @@ -1207,7 +1207,7 @@ PPC_OP(fadd) /* fadds - fadds. */ PPC_OP(fadds) { - FTS0 += FTS1; + FT0 = FTS0 + FTS1; RETURN(); } @@ -1221,7 +1221,7 @@ PPC_OP(fsub) /* fsubs - fsubs. */ PPC_OP(fsubs) { - FTS0 -= FTS1; + FT0 = FTS0 - FTS1; RETURN(); } @@ -1235,7 +1235,7 @@ PPC_OP(fmul) /* fmuls - fmuls. */ PPC_OP(fmuls) { - FTS0 *= FTS1; + FT0 = FTS0 * FTS1; RETURN(); } @@ -1249,7 +1249,7 @@ PPC_OP(fdiv) /* fdivs - fdivs. */ PPC_OP(fdivs) { - FTS0 /= FTS1; + FT0 = FTS0 / FTS1; RETURN(); } @@ -1299,7 +1299,7 @@ PPC_OP(fmadd) /* fmadds - fmadds. */ PPC_OP(fmadds) { - FTS0 = (FTS0 * FTS1) + FTS2; + FT0 = (FTS0 * FTS1) + FTS2; RETURN(); } @@ -1313,7 +1313,7 @@ PPC_OP(fmsub) /* fmsubs - fmsubs. */ PPC_OP(fmsubs) { - FTS0 = (FTS0 * FTS1) - FTS2; + FT0 = (FTS0 * FTS1) - FTS2; RETURN(); } @@ -1349,7 +1349,7 @@ PPC_OP(fnmsubs) /* frsp - frsp. */ PPC_OP(frsp) { - FTS0 = FT0; + FT0 = (float)FT0; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 433f6b128..20aba8b6e 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -188,10 +188,17 @@ void do_load_fpscr (void) } u; int i; - u.s.u[0] = 0; - u.s.u[1] = 0; +#ifdef WORDS_BIGENDIAN +#define WORD0 0 +#define WORD1 1 +#else +#define WORD0 1 +#define WORD1 0 +#endif + u.s.u[WORD0] = 0; + u.s.u[WORD1] = 0; for (i = 0; i < 8; i++) - u.s.u[1] |= env->fpscr[i] << (4 * i); + u.s.u[WORD1] |= env->fpscr[i] << (4 * i); FT0 = u.d; } @@ -210,10 +217,10 @@ void do_store_fpscr (uint32_t mask) u.d = FT0; if (mask & 0x80) - env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[1] >> 28) & ~0x9); + env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9); for (i = 1; i < 7; i++) { if (mask & (1 << (7 - i))) - env->fpscr[i] = (u.s.u[1] >> (4 * (7 - i))) & 0xF; + env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF; } /* TODO: update FEX & VX */ /* Set rounding mode */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4de116f18..bb3bbbb54 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -134,12 +134,13 @@ typedef struct DisasContext { target_ulong nip; uint32_t opcode; uint32_t exception; - /* Execution mode */ + /* Routine used to access memory */ + int mem_idx; + /* Translation flags */ #if !defined(CONFIG_USER_ONLY) int supervisor; #endif - /* Routine used to access memory */ - int mem_idx; + int fpu_enabled; } DisasContext; typedef struct opc_handler_t { @@ -330,19 +331,6 @@ GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON) RET_EXCP(ctx, EXCP_HLT, 0); } -/* Special opcode to call open-firmware */ -GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON) -{ - RET_EXCP(ctx, EXCP_OFCALL, 0); -} - -/* Special opcode to call RTAS */ -GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON) -{ - printf("RTAS entry point !\n"); - RET_EXCP(ctx, EXCP_RTASCALL, 0); -} - static opc_handler_t invalid_handler = { .inval = 0xFFFFFFFF, .type = PPC_NONE, @@ -764,6 +752,10 @@ __GEN_LOGICAL2(srw, 0x18, 0x10); #define _GEN_FLOAT_ACB(name, op1, op2) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rC(ctx->opcode)); \ @@ -781,6 +773,10 @@ _GEN_FLOAT_ACB(name##s, 0x3B, op2); #define _GEN_FLOAT_AB(name, op1, op2, inval) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rB(ctx->opcode)); \ @@ -796,6 +792,10 @@ _GEN_FLOAT_AB(name##s, 0x3B, op2, inval); #define _GEN_FLOAT_AC(name, op1, op2, inval) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rC(ctx->opcode)); \ @@ -811,6 +811,10 @@ _GEN_FLOAT_AC(name##s, 0x3B, op2, inval); #define GEN_FLOAT_B(name, op2, op3) \ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rB(ctx->opcode)); \ gen_op_f##name(); \ @@ -822,6 +826,10 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ #define GEN_FLOAT_BS(name, op2) \ GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rB(ctx->opcode)); \ gen_op_f##name(); \ @@ -853,6 +861,10 @@ GEN_FLOAT_BS(sqrt, 0x16); GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_fsqrts(); @@ -883,6 +895,10 @@ GEN_FLOAT_B(rsp, 0x0C, 0x00); /* fcmpo */ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rA(ctx->opcode)); gen_op_load_fpr_FT1(rB(ctx->opcode)); @@ -893,6 +909,10 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) /* fcmpu */ GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rA(ctx->opcode)); gen_op_load_fpr_FT1(rB(ctx->opcode)); @@ -907,6 +927,10 @@ GEN_FLOAT_B(abs, 0x08, 0x08); /* fmr - fmr. */ GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_store_FT0_fpr(rD(ctx->opcode)); @@ -923,6 +947,10 @@ GEN_FLOAT_B(neg, 0x08, 0x01); /* mcrfs */ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } gen_op_load_fpscr_T0(crfS(ctx->opcode)); gen_op_store_T0_crf(crfD(ctx->opcode)); gen_op_clear_fpscr(crfS(ctx->opcode)); @@ -931,6 +959,10 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) /* mffs */ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } gen_op_load_fpscr(); gen_op_store_FT0_fpr(rD(ctx->opcode)); if (Rc(ctx->opcode)) @@ -942,6 +974,10 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) { uint8_t crb; + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } crb = crbD(ctx->opcode) >> 2; gen_op_load_fpscr_T0(crb); gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03))); @@ -955,6 +991,10 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) { uint8_t crb; + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } crb = crbD(ctx->opcode) >> 2; gen_op_load_fpscr_T0(crb); gen_op_ori(1 << (crbD(ctx->opcode) & 0x03)); @@ -966,6 +1006,10 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) /* mtfsf */ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_store_fpscr(FM(ctx->opcode)); if (Rc(ctx->opcode)) @@ -975,6 +1019,10 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) /* mtfsfi */ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode)); if (Rc(ctx->opcode)) gen_op_set_Rc1(); @@ -1525,6 +1573,10 @@ GEN_STFS(fs, 0x14); /* stfiwx */ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) { + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } RET_INVAL(ctx); } @@ -2978,10 +3030,6 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "reservation 0x%08x\n", env->reserve); } -#if !defined(CONFIG_USER_ONLY) && defined (USE_OPENFIRMWARE) -int setup_machine (CPUPPCState *env, uint32_t mid); -#endif - CPUPPCState *cpu_ppc_init(void) { CPUPPCState *env; @@ -2991,14 +3039,10 @@ CPUPPCState *cpu_ppc_init(void) env = qemu_mallocz(sizeof(CPUPPCState)); if (!env) return NULL; -#if !defined(CONFIG_USER_ONLY) && defined (USE_OPEN_FIRMWARE) - setup_machine(env, 0); -#else // env->spr[PVR] = 0; /* Basic PPC */ env->spr[PVR] = 0x00080100; /* G3 CPU */ // env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */ // env->spr[PVR] = 0x00070100; /* IBM 750FX */ -#endif tlb_flush(env, 1); #if defined (DO_SINGLE_STEP) /* Single step trace mode */ @@ -3053,8 +3097,9 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.mem_idx = 0; #else ctx.supervisor = 1 - msr_pr; - ctx.mem_idx = (1 - msr_pr); + ctx.mem_idx = 1 - msr_pr; #endif + ctx.fpu_enabled = msr_fp; #if defined (DO_SINGLE_STEP) /* Single step trace mode */ msr_se = 1; -- cgit v1.2.3 From f512c6fb6ec9a1a19b4ec6592738d4ad029b46af Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Feb 2005 23:06:39 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1298 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO b/TODO index b8e973ce4..8e256226d 100644 --- a/TODO +++ b/TODO @@ -38,7 +38,6 @@ short term: ppc specific: ------------ - TLB invalidate not needed if msr_pr changes -- endianness bugs in do_load_fpscr and do_store_fpscr - SPR_ENCODE() not useful - enable shift optimizations ? -- cgit v1.2.3 From a20b55246958b33cfa1ba1e9847a924d6da2ba38 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Feb 2005 17:24:28 +0000 Subject: suppressed sparc64 targets as they are far from being usable git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1299 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index cc21847c8..b2ba875a3 100755 --- a/configure +++ b/configure @@ -200,10 +200,10 @@ fi if test -z "$target_list" ; then # these targets are portable - target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu sparc64-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu" # the following are Linux specific if [ "$linux" = "yes" ] ; then - target_list="i386-user arm-user armeb-user sparc-user ppc-user sparc64-user $target_list" + target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list" fi fi -- cgit v1.2.3 From 2623cbaf1ac9101934c06f9afece04b4b62550d8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Feb 2005 17:25:31 +0000 Subject: fixed handling of sparc register window exceptions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1300 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 57 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index b3f88dd16..43fa2f27f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -396,7 +396,8 @@ void cpu_loop(CPUARMState *env) //#define DEBUG_WIN -/* WARNING: dealing with register windows _is_ complicated */ +/* WARNING: dealing with register windows _is_ complicated. More info + can be found at http://www.sics.se/~psm/sparcstack.html */ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) { index = (index + cwp * 16) & (16 * NWINDOWS - 1); @@ -407,34 +408,36 @@ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) return index; } -static inline void save_window_offset(CPUSPARCState *env, int offset) +/* save the register window 'cwp1' */ +static inline void save_window_offset(CPUSPARCState *env, int cwp1) { - unsigned int new_wim, i, cwp1; + unsigned int i; uint32_t *sp_ptr; - new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & - ((1LL << NWINDOWS) - 1); - /* save the window */ - cwp1 = (env->cwp + offset) & (NWINDOWS - 1); sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); #if defined(DEBUG_WIN) printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", (int)sp_ptr, cwp1); #endif - for(i = 0; i < 16; i++) - stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]); - env->wim = new_wim; + for(i = 0; i < 16; i++) { + put_user(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); + sp_ptr++; + } } static void save_window(CPUSPARCState *env) { - save_window_offset(env, 2); + unsigned int new_wim; + new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & + ((1LL << NWINDOWS) - 1); + save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1)); + env->wim = new_wim; } static void restore_window(CPUSPARCState *env) { unsigned int new_wim, i, cwp1; - uint32_t *sp_ptr; + uint32_t *sp_ptr, reg; new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & ((1LL << NWINDOWS) - 1); @@ -446,32 +449,34 @@ static void restore_window(CPUSPARCState *env) printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", (int)sp_ptr, cwp1); #endif - for(i = 0; i < 16; i++) - env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i); + for(i = 0; i < 16; i++) { + get_user(reg, sp_ptr); + env->regbase[get_reg_index(env, cwp1, 8 + i)] = reg; + sp_ptr++; + } env->wim = new_wim; } -#if 0 static void flush_windows(CPUSPARCState *env) { int offset, cwp1; -#if defined(DEBUG_WIN) - printf("flush_windows:\n"); -#endif - offset = 2; + + offset = 1; for(;;) { /* if restore would invoke restore_window(), then we can stop */ - cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + cwp1 = (env->cwp + offset) & (NWINDOWS - 1); if (env->wim & (1 << cwp1)) break; -#if defined(DEBUG_WIN) - printf("offset=%d: ", offset); -#endif - save_window_offset(env, offset); + save_window_offset(env, cwp1); offset++; } -} + /* set wim so that restore will reload the registers */ + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + env->wim = 1 << cwp1; +#if defined(DEBUG_WIN) + printf("flush_windows: nb=%d\n", offset - 1); #endif +} void cpu_loop (CPUSPARCState *env) { @@ -500,7 +505,7 @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; case 0x83: /* flush windows */ - // flush_windows(env); + flush_windows(env); /* next instruction */ env->pc = env->npc; env->npc = env->npc + 4; -- cgit v1.2.3 From 1d6e34fd37ce6b67f3d776328ee05d8848ba81c4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Feb 2005 17:26:37 +0000 Subject: sparc Linux works better with NWINDOWS = 8 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1301 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index f07464deb..4170b5733 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -104,7 +104,8 @@ #define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT) #define PG_CACHE_MASK (1 << PG_CACHE_BIT) -#define NWINDOWS 32 +/* 2 <= NWINDOWS <= 32. In QEMU it must also be a power of two. */ +#define NWINDOWS 8 typedef struct CPUSPARCState { target_ulong gregs[8]; /* general registers */ -- cgit v1.2.3 From 6f2f2b2489c89f37ac6db64bc15eefc7c30a9637 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Feb 2005 19:09:44 +0000 Subject: removed all references to KQEMU to comply with the Savannah rules git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1302 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 98 +---------------------------------------------------------- 1 file changed, 1 insertion(+), 97 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 0e8a960c7..02780a9cd 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -35,11 +35,7 @@ to ease cross-compilation and cross-debugging. @end itemize QEMU can run without an host kernel driver and yet gives acceptable -performance. On an x86 host, if you want the highest performance for -the x86 target, the @emph{QEMU Accelerator Module} (KQEMU) allows QEMU -to reach near native performances. KQEMU is currently only supported -for an x86 Linux 2.4 or 2.6 host system, but more host OSes will be -supported in the future. +performance. For system emulation, the following hardware targets are supported: @itemize @@ -343,11 +339,6 @@ translation mode (@var{t}=none, lba or auto). Usually QEMU can guess all thoses parameters. This option is useful for old MS-DOS disk images. -@item -no-kqemu -Disable the usage of the QEMU Accelerator module (KQEMU). QEMU will work as -usual but will be slower. This option can be useful to determine if -emulation problems are coming from KQEMU. - @item -isa Simulate an ISA-only system (default is PCI system). @item -std-vga @@ -423,30 +414,6 @@ Fabrice Bellard @end ignore -@section QEMU Accelerator Module - -The QEMU Accelerator Module (KQEMU) is an optional part of QEMU currently only -available for Linux 2.4 or 2.6 x86 hosts. It enables QEMU to run x86 -code much faster. Provided it is installed on your PC (see -@ref{kqemu_install}), QEMU will automatically use it. - -WARNING: as with any alpha stage kernel driver, KQEMU may cause -arbitrary data loss on your PC, so you'd better backup your sensitive -data before using it. - -When using KQEMU, QEMU will create a big hidden file containing the -RAM of the virtual machine. For best performance, it is important that -this file is kept in RAM and not on the hard disk. QEMU uses the -@file{/dev/shm} directory to create this file because @code{tmpfs} is -usually mounted on it (check with the shell command -@code{df}). Otherwise @file{/tmp} is used as fallback. You can use the -@var{QEMU_TMPDIR} shell variable to set a new directory for the QEMU -RAM file. - -KQEMU has only been tested with Linux 2.4, Linux 2.6 and Windows 2000 -as guest OSes. If your guest OS do not work with KQEMU, you can -dynamically disable KQEMU with the @option{-no-kqemu} option. - @section QEMU Monitor The QEMU monitor is used to give complex commands to the QEMU @@ -1165,12 +1132,6 @@ tar zxvf qemu-x.y.z.tar.gz cd qemu-x.y.z @end example -If you want to use the optional QEMU Accelerator Module, then download -it and install it in qemu-x.y.z/: -@example -tar zxvf /tmp/kqemu-x.y.z.tar.gz -@end example - Then you configure QEMU and build it (usually no options are needed): @example ./configure @@ -1183,63 +1144,6 @@ make install @end example to install QEMU in @file{/usr/local}. -@node kqemu_install -@subsection QEMU Accelerator Installation - -If you use x86 Linux, the compilation of the QEMU Accelerator Kernel -Module (KQEMU) is automatically activated provided you have the -necessary kernel headers. If nonetheless the compilation fails, you -can disable its compilation with the @option{--disable-kqemu} option. - -If you are using a 2.6 host kernel, then all the necessary kernel -headers should be already installed. If you are using a 2.4 kernel, -then you should verify that properly configured kernel sources are -installed and compiled. On a Redhat 9 distribution for example, the -following must be done: -@example -1) Install the kernel-source-xxx package -2) cd /usr/src/linux-xxx -3) make distclean -4) Copy /boot/config-vvv in .config (use uname -r to know your configuration name 'vvv') -5) Edit the Makefile to change the EXTRAVERSION line to match your - current configuration name: - EXTRAVERSION = -custom -to - EXTRAVERSION = -8 # This is an example, it can be -8smp too -5) make menuconfig # Just save the configuration -6) make dep bzImage -@end example - -The installation of KQEMU is not fully automatic because it is highly -distribution dependent. When launching -@example -make install -@end example - -KQEMU is installed in /lib/modules/@var{kernel_version}/misc. The -device @file{/dev/kqemu} is created with read/write access rights for -everyone. If you fear security issues, you can restrict the access -rights of @file{/dev/kqemu}. - -If you want that KQEMU is installed automatically at boot time, you can add - -@example -# Load the KQEMU kernel module -/sbin/modprobe kqemu -@end example - -in @file{/etc/rc.d/rc.local}. - -If your distribution uses udev (like Fedora), the @file{/dev/kqemu} is -not created automatically (yet) at every reboot. You can add the -following in @file{/etc/rc.d/rc.local}: - -@example -# Create the KQEMU device -mknod /dev/kqemu c 250 0 -chmod 666 /dev/kqemu -@end example - @subsection Tested tool versions In order to compile QEMU succesfully, it is very important that you -- cgit v1.2.3 From 91aa5d4975eeb996a2d4263e94479f85df124660 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Feb 2005 19:53:34 +0000 Subject: Mac OS X fix (Jonas Maebe) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1303 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/dyngen.c b/dyngen.c index 495b9866d..5823e0767 100644 --- a/dyngen.c +++ b/dyngen.c @@ -996,11 +996,11 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide) switch(rel->r_type) { - case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset & 0xffff); + 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 = (other_half & 0xffff); + 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 = (other_half & 0xffff); + 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 ); @@ -1146,13 +1146,11 @@ int load_object(const char *filename) /* 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++) { - const char *name; struct nlist *sym_follow, *sym_next = 0; unsigned int j; - name = find_str_by_index(sym->n_un.n_strx); memset(sym, 0, sizeof(*sym)); - if ( sym->n_type & N_STAB ) /* Debug symbols are skipped */ + if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */ continue; memcpy(sym, syment, sizeof(*syment)); @@ -1848,11 +1846,16 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, sym_name); switch(type) { case PPC_RELOC_BR24: - 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", + 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"); + 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", -- cgit v1.2.3 From 194884dd6f1fee4d4c41f74649e98af04ad6f83a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Feb 2005 20:10:36 +0000 Subject: win32 + Mac OS X compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1304 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osdep.c b/osdep.c index bb2c0d1f0..ba6d5f38a 100644 --- a/osdep.c +++ b/osdep.c @@ -273,7 +273,15 @@ void *get_mmap_addr(unsigned long size) #else +#ifdef _BSD +#include +#else #include +#endif +#ifdef _WIN32 +/* XXX: find a solution to have page aligned data */ +#define memalign(align, size) malloc(size) +#endif int qemu_write(int fd, const void *buf, size_t n) { -- cgit v1.2.3 From 0b9dc5e4c3b96a1e41ab7d660ba2ee2a83380e09 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Feb 2005 20:23:59 +0000 Subject: loop insn fix for non x86 hosts git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1305 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 5 +++++ target-i386/ops_template.h | 8 ++------ target-i386/translate.c | 2 ++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index 933595da6..fed0fca93 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1366,6 +1366,11 @@ void OPPROTO op_set_cc_op(void) CC_OP = PARAM1; } +void OPPROTO op_mov_T0_cc(void) +{ + T0 = cc_table[CC_OP].compute_all(); +} + /* XXX: clear VIF/VIP in all ops ? */ void OPPROTO op_movl_eflags_T0(void) diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 35d5b5412..373b77a24 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -339,18 +339,14 @@ void OPPROTO glue(op_jle_sub, SUFFIX)(void) void OPPROTO glue(op_loopnz, SUFFIX)(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if ((DATA_TYPE)ECX != 0 && !(eflags & CC_Z)) + if ((DATA_TYPE)ECX != 0 && !(T0 & CC_Z)) GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO glue(op_loopz, SUFFIX)(void) { - int eflags; - eflags = cc_table[CC_OP].compute_all(); - if ((DATA_TYPE)ECX != 0 && (eflags & CC_Z)) + if ((DATA_TYPE)ECX != 0 && (T0 & CC_Z)) GOTO_LABEL_PARAM(1); FORCE_RET(); } diff --git a/target-i386/translate.c b/target-i386/translate.c index a3005d8d5..093723944 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5271,6 +5271,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_jz_ecx[s->aflag](l1); } else { gen_op_dec_ECX[s->aflag](); + if (b <= 1) + gen_op_mov_T0_cc(); gen_op_loop[s->aflag][b](l1); } -- cgit v1.2.3 From 713c45faf81f9a68ca589ce37d7e1dee6c2127a2 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Feb 2005 19:08:41 +0000 Subject: initrd support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1306 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index 7cc5bd8d9..784379983 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -25,6 +25,7 @@ #include "m48t08.h" #define KERNEL_LOAD_ADDR 0x00004000 +#define INITRD_LOAD_ADDR 0x00800000 #define PROM_ADDR 0xffd00000 #define PROM_FILENAMEB "proll.bin" #define PROM_FILENAMEE "proll.elf" @@ -135,7 +136,8 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; int ret, linux_boot; - unsigned long vram_size = 0x100000, prom_offset; + unsigned int i; + unsigned long vram_size = 0x100000, prom_offset, initrd_size; linux_boot = (kernel_filename != NULL); @@ -180,5 +182,26 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, kernel_filename); exit(1); } + + /* load initrd */ + initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + if (initrd_size > 0) { + for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { + if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) + == 0x48647253) { // HdrS + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); + break; + } + } + } } } -- cgit v1.2.3 From afc7df11480cfbfe45e6c3db2af9d8c670ec69d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Feb 2005 19:08:57 +0000 Subject: PSR.PS fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1307 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 4170b5733..b07e2afcf 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -172,7 +172,7 @@ double cpu_put_fp64(uint64_t mant, uint16_t exp); (env->psref? PSR_EF : 0) | \ (env->psrpil << 8) | \ (env->psrs? PSR_S : 0) | \ - (env->psrs? PSR_PS : 0) | \ + (env->psrps? PSR_PS : 0) | \ (env->psret? PSR_ET : 0) | env->cwp) #ifndef NO_CPU_IO_DEFS -- cgit v1.2.3 From 55754d9ef27178cf0e13aea85062fc4c32e25f83 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Feb 2005 19:14:33 +0000 Subject: MMU fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1308 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/helper.c | 4 ++-- target-sparc/op_helper.c | 50 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 0269d2eec..bf28a3675 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -414,9 +414,9 @@ target_ulong mmu_probe(target_ulong address, int mmulev) return 0; } +#ifdef DEBUG_MMU void dump_mmu(void) { -#ifdef DEBUG_MMU target_ulong va, va1, va2; unsigned int n, m, o; target_phys_addr_t pde_ptr, pa; @@ -448,5 +448,5 @@ void dump_mmu(void) } } printf("MMU dump ends\n"); -#endif } +#endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 9699d02f7..4c65c64d6 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -105,8 +105,11 @@ void helper_ld_asi(int asi, int size, int sign) int reg = (T0 >> 8) & 0xf; ret = env->mmuregs[reg]; - if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/ - env->mmuregs[4] = 0; + if (reg == 3) /* Fault status cleared on read */ + env->mmuregs[reg] = 0; +#ifdef DEBUG_MMU + printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret); +#endif } break; case 0x20 ... 0x2f: /* MMU passthrough */ @@ -131,20 +134,25 @@ void helper_st_asi(int asi, int size, int sign) int mmulev; mmulev = (T0 >> 8) & 15; +#ifdef DEBUG_MMU + printf("mmu flush level %d\n", mmulev); +#endif switch (mmulev) { case 0: // flush page - tlb_flush_page(cpu_single_env, T0 & 0xfffff000); + tlb_flush_page(env, T0 & 0xfffff000); break; case 1: // flush segment (256k) case 2: // flush region (16M) case 3: // flush context (4G) case 4: // flush entire - tlb_flush(cpu_single_env, 1); + tlb_flush(env, 1); break; default: break; } +#ifdef DEBUG_MMU dump_mmu(); +#endif return; } case 4: /* write MMU regs */ @@ -152,20 +160,34 @@ void helper_st_asi(int asi, int size, int sign) int reg = (T0 >> 8) & 0xf, oldreg; oldreg = env->mmuregs[reg]; - if (reg == 0) { + switch(reg) { + case 0: env->mmuregs[reg] &= ~(MMU_E | MMU_NF); env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); - } else + if ((oldreg & MMU_E) != (env->mmuregs[reg] & MMU_E)) + tlb_flush(env, 1); + break; + case 2: env->mmuregs[reg] = T1; - if (oldreg != env->mmuregs[reg]) { -#if 0 - // XXX: Only if MMU mapping change, we may need to flush? - tlb_flush(cpu_single_env, 1); - cpu_loop_exit(); - FORCE_RET(); -#endif - } + if (oldreg != env->mmuregs[reg]) { + /* we flush when the MMU context changes because + QEMU has no MMU context support */ + tlb_flush(env, 1); + } + break; + case 3: + case 4: + break; + default: + env->mmuregs[reg] = T1; + break; + } +#ifdef DEBUG_MMU + if (oldreg != env->mmuregs[reg]) { + printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); + } dump_mmu(); +#endif return; } case 0x17: /* Block copy, sta access */ -- cgit v1.2.3 From b7bcbe9524c05d5134136cce2d5d2a09c09a4f83 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Feb 2005 19:27:29 +0000 Subject: ARM VFP support (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1309 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 4 + cpu-exec.c | 4 +- target-arm/cpu.h | 28 +++ target-arm/exec.h | 32 ++- target-arm/op.c | 255 +++++++++++++++++++++- target-arm/op_helper.c | 229 ++++++++++++++++++++ target-arm/translate.c | 565 ++++++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 1104 insertions(+), 14 deletions(-) create mode 100644 target-arm/op_helper.c diff --git a/Changelog b/Changelog index 2d1c06727..8898eba36 100644 --- a/Changelog +++ b/Changelog @@ -15,6 +15,7 @@ version 0.6.2: - PC parallel port support (Mark Jonckheere) - initial SPARC64 support (Blue Swirl) - armv5te user mode support (Paul Brook) + - ARM VFP support (Paul Brook) version 0.6.1: diff --git a/Makefile.target b/Makefile.target index 5ed2b9254..25f4719a3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -259,6 +259,10 @@ ifeq ($(TARGET_BASE_ARCH), sparc) LIBOBJS+= op_helper.o helper.o endif +ifeq ($(TARGET_BASE_ARCH), arm) +LIBOBJS+= op_helper.o +endif + # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) diff --git a/cpu-exec.c b/cpu-exec.c index 835ca4247..94c35e31b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -346,7 +346,8 @@ int cpu_exec(CPUState *env1) cs_base = env->segs[R_CS].base; pc = cs_base + env->eip; #elif defined(TARGET_ARM) - flags = env->thumb; + flags = env->thumb | (env->vfp.vec_len << 1) + | (env->vfp.vec_stride << 4); cs_base = 0; pc = env->regs[15]; #elif defined(TARGET_SPARC) @@ -619,6 +620,7 @@ int cpu_exec(CPUState *env1) #endif #elif defined(TARGET_ARM) env->cpsr = compute_cpsr(); + /* XXX: Save/restore host fpu exception state?. */ #elif defined(TARGET_SPARC) #elif defined(TARGET_PPC) #else diff --git a/target-arm/cpu.h b/target-arm/cpu.h index c0994c0c6..a5f4f94e5 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -29,6 +29,14 @@ #define EXCP_PREFETCH_ABORT 3 #define EXCP_DATA_ABORT 4 +/* We currently assume float and double are IEEE single and double + precision respectively. + Doing runtime conversions is tricky because VFP registers may contain + integer values (eg. as the result of a FTOSI instruction). + A double precision register load/store must also load/store the + corresponding single precision pair, although it is undefined how + these overlap. */ + typedef struct CPUARMState { uint32_t regs[16]; uint32_t cpsr; @@ -50,6 +58,7 @@ typedef struct CPUARMState { int interrupt_request; struct TranslationBlock *current_tb; int user_mode_only; + uint32_t address; /* in order to avoid passing too many arguments to the memory write helpers, we store some rarely used information in the CPU @@ -58,6 +67,25 @@ typedef struct CPUARMState { written */ unsigned long mem_write_vaddr; /* target virtual addr at which the memory was written */ + /* VFP coprocessor state. */ + struct { + union { + float s[32]; + double d[16]; + } regs; + + /* We store these fpcsr fields separately for convenience. */ + int vec_len; + int vec_stride; + + uint32_t fpscr; + + /* Temporary variables if we don't have spare fp regs. */ + float tmp0s, tmp1s; + double tmp0d, tmp1d; + + } vfp; + /* user data */ void *opaque; } CPUARMState; diff --git a/target-arm/exec.h b/target-arm/exec.h index e17302e0b..64fce7153 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -24,13 +24,16 @@ register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); register uint32_t T2 asm(AREG3); +/* TODO: Put these in FP regs on targets that have such things. */ +/* It is ok for FT0s and FT0d to overlap. Likewise FT1s and FT1d. */ +#define FT0s env->vfp.tmp0s +#define FT1s env->vfp.tmp1s +#define FT0d env->vfp.tmp0d +#define FT1d env->vfp.tmp1d + #include "cpu.h" #include "exec-all.h" -void cpu_lock(void); -void cpu_unlock(void); -void cpu_loop_exit(void); - /* Implemented CPSR bits. */ #define CACHED_CPSR_BITS 0xf8000000 static inline int compute_cpsr(void) @@ -51,3 +54,24 @@ static inline void regs_to_env(void) int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); + +/* In op_helper.c */ + +void cpu_lock(void); +void cpu_unlock(void); +void cpu_loop_exit(void); + +void raise_exception(int); + +void do_vfp_abss(void); +void do_vfp_absd(void); +void do_vfp_negs(void); +void do_vfp_negd(void); +void do_vfp_sqrts(void); +void do_vfp_sqrtd(void); +void do_vfp_cmps(void); +void do_vfp_cmpd(void); +void do_vfp_cmpes(void); +void do_vfp_cmped(void); +void do_vfp_set_fpscr(void); +void do_vfp_get_fpscr(void); diff --git a/target-arm/op.c b/target-arm/op.c index 561883457..6c608f141 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -2,6 +2,7 @@ * ARM micro operations * * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2005 CodeSourcery, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -857,17 +858,259 @@ void OPPROTO op_undef_insn(void) cpu_loop_exit(); } -/* thread support */ +/* VFP support. We follow the convention used for VFP instrunctions: + Single precition routines have a "s" suffix, double precision a + "d" suffix. */ -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; +#define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void) -void cpu_lock(void) +#define VFP_BINOP(name, op) \ +VFP_OP(name, s) \ +{ \ + FT0s = FT0s op FT1s; \ +} \ +VFP_OP(name, d) \ +{ \ + FT0d = FT0d op FT1d; \ +} +VFP_BINOP(add, +) +VFP_BINOP(sub, -) +VFP_BINOP(mul, *) +VFP_BINOP(div, /) +#undef VFP_BINOP + +#define VFP_HELPER(name) \ +VFP_OP(name, s) \ +{ \ + do_vfp_##name##s(); \ +} \ +VFP_OP(name, d) \ +{ \ + do_vfp_##name##d(); \ +} +VFP_HELPER(abs) +VFP_HELPER(sqrt) +VFP_HELPER(cmp) +VFP_HELPER(cmpe) +#undef VFP_HELPER + +/* XXX: Will this do the right thing for NANs. Should invert the signbit + without looking at the rest of the value. */ +VFP_OP(neg, s) +{ + FT0s = -FT0s; +} + +VFP_OP(neg, d) +{ + FT0d = -FT0d; +} + +VFP_OP(F1_ld0, s) +{ + FT1s = 0.0f; +} + +VFP_OP(F1_ld0, d) +{ + FT1d = 0.0; +} + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float s) +{ + union { + uint32_t i; + float s; + } v; + + v.s = s; + return v.i; +} + +/* Integer to float conversion. */ +VFP_OP(uito, s) +{ + FT0s = (float)(uint32_t)vfp_stoi(FT0s); +} + +VFP_OP(uito, d) +{ + FT0d = (double)(uint32_t)vfp_stoi(FT0s); +} + +VFP_OP(sito, s) +{ + FT0s = (float)(int32_t)vfp_stoi(FT0s); +} + +VFP_OP(sito, d) +{ + FT0d = (double)(int32_t)vfp_stoi(FT0s); +} + +/* Float to integer conversion. */ +VFP_OP(toui, s) +{ + FT0s = vfp_itos((uint32_t)FT0s); +} + +VFP_OP(toui, d) +{ + FT0s = vfp_itos((uint32_t)FT0d); +} + +VFP_OP(tosi, s) +{ + FT0s = vfp_itos((int32_t)FT0s); +} + +VFP_OP(tosi, d) +{ + FT0s = vfp_itos((int32_t)FT0d); +} + +/* TODO: Set rounding mode properly. */ +VFP_OP(touiz, s) +{ + FT0s = vfp_itos((uint32_t)FT0s); +} + +VFP_OP(touiz, d) +{ + FT0s = vfp_itos((uint32_t)FT0d); +} + +VFP_OP(tosiz, s) +{ + FT0s = vfp_itos((int32_t)FT0s); +} + +VFP_OP(tosiz, d) { - spin_lock(&global_cpu_lock); + FT0s = vfp_itos((int32_t)FT0d); } -void cpu_unlock(void) +/* floating point conversion */ +VFP_OP(fcvtd, s) { - spin_unlock(&global_cpu_lock); + FT0d = (double)FT0s; } +VFP_OP(fcvts, d) +{ + FT0s = (float)FT0d; +} + +/* Get and Put values from registers. */ +VFP_OP(getreg_F0, d) +{ + FT0d = *(double *)((char *) env + PARAM1); +} + +VFP_OP(getreg_F0, s) +{ + FT0s = *(float *)((char *) env + PARAM1); +} + +VFP_OP(getreg_F1, d) +{ + FT1d = *(double *)((char *) env + PARAM1); +} + +VFP_OP(getreg_F1, s) +{ + FT1s = *(float *)((char *) env + PARAM1); +} + +VFP_OP(setreg_F0, d) +{ + *(double *)((char *) env + PARAM1) = FT0d; +} + +VFP_OP(setreg_F0, s) +{ + *(float *)((char *) env + PARAM1) = FT0s; +} + +VFP_OP(foobar, d) +{ + FT0d = env->vfp.regs.s[3]; +} + +void OPPROTO op_vfp_movl_T0_fpscr(void) +{ + do_vfp_get_fpscr (); +} + +void OPPROTO op_vfp_movl_T0_fpscr_flags(void) +{ + T0 = env->vfp.fpscr & (0xf << 28); +} + +void OPPROTO op_vfp_movl_fpscr_T0(void) +{ + do_vfp_set_fpscr(); +} + +/* Move between FT0s to T0 */ +void OPPROTO op_vfp_mrs(void) +{ + T0 = vfp_stoi(FT0s); +} + +void OPPROTO op_vfp_msr(void) +{ + FT0s = vfp_itos(T0); +} + +/* Move between FT0d and {T0,T1} */ +void OPPROTO op_vfp_mrrd(void) +{ + CPU_DoubleU u; + + u.d = FT0d; + T0 = u.l.lower; + T1 = u.l.upper; +} + +void OPPROTO op_vfp_mdrr(void) +{ + CPU_DoubleU u; + + u.l.lower = T0; + u.l.upper = T1; + FT0d = u.d; +} + +/* Floating point load/store. Address is in T1 */ +void OPPROTO op_vfp_lds(void) +{ + FT0s = ldfl((void *)T1); +} + +void OPPROTO op_vfp_ldd(void) +{ + FT0d = ldfq((void *)T1); +} + +void OPPROTO op_vfp_sts(void) +{ + stfl((void *)T1, FT0s); +} + +void OPPROTO op_vfp_std(void) +{ + stfq((void *)T1, FT0d); +} diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c new file mode 100644 index 000000000..38c97fe68 --- /dev/null +++ b/target-arm/op_helper.c @@ -0,0 +1,229 @@ +/* + * ARM helper routines + * + * Copyright (c) 2005 CodeSourcery, LLC + * + * 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 +#include +#include "exec.h" + +/* If the host doesn't define C99 math intrinsics then use the normal + operators. This may generate excess exceptions, but it's probably + near enough for most things. */ +#ifndef isless +#define isless(x, y) (x < y) +#endif +#ifndef isgreater +#define isgreater(x, y) (x > y) +#endif +#ifndef isunordered +#define isunordered(x, y) (!((x < y) || (x >= y))) +#endif + +void raise_exception(int tt) +{ + env->exception_index = tt; + cpu_loop_exit(); +} + +/* thread support */ + +spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; + +void cpu_lock(void) +{ + spin_lock(&global_cpu_lock); +} + +void cpu_unlock(void) +{ + spin_unlock(&global_cpu_lock); +} + +/* VFP support. */ + +void do_vfp_abss(void) +{ + FT0s = fabsf(FT0s); +} + +void do_vfp_absd(void) +{ + FT0d = fabs(FT0d); +} + +void do_vfp_sqrts(void) +{ + FT0s = sqrtf(FT0s); +} + +void do_vfp_sqrtd(void) +{ + FT0d = sqrt(FT0d); +} + +/* We use an == operator first to generate teh correct floating point + exception. Subsequent comparisons use the exception-safe macros. */ +#define DO_VFP_cmp(p) \ +void do_vfp_cmp##p(void) \ +{ \ + uint32_t flags; \ + if (FT0##p == FT1##p) \ + flags = 0xc; \ + else if (isless (FT0##p, FT1##p)) \ + flags = 0x8; \ + else if (isgreater (FT0##p, FT1##p)) \ + flags = 0x2; \ + else /* unordered */ \ + flags = 0x3; \ + env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ + FORCE_RET(); \ +} +DO_VFP_cmp(s) +DO_VFP_cmp(d) +#undef DO_VFP_cmp + +/* We use a > operator first to get FP exceptions right. */ +#define DO_VFP_cmpe(p) \ +void do_vfp_cmpe##p(void) \ +{ \ + uint32_t flags; \ + if (FT0##p > FT1##p) \ + flags = 0x2; \ + else if (isless (FT0##p, FT1##p)) \ + flags = 0x8; \ + else if (isunordered (FT0##p, FT1##p)) \ + flags = 0x3; \ + else /* equal */ \ + flags = 0xc; \ + env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ + FORCE_RET(); \ +} +DO_VFP_cmpe(s) +DO_VFP_cmpe(d) +#undef DO_VFP_cmpe + +/* Convert host exception flags to vfp form. */ +int vfp_exceptbits_from_host(int host_bits) +{ + int target_bits = 0; + +#ifdef FE_INVALID + if (host_bits & FE_INVALID) + target_bits |= 1; +#endif +#ifdef FE_DIVBYZERO + if (host_bits & FE_DIVBYZERO) + target_bits |= 2; +#endif +#ifdef FE_OVERFLOW + if (host_bits & FE_OVERFLOW) + target_bits |= 4; +#endif +#ifdef FE_UNDERFLOW + if (host_bits & FE_UNDERFLOW) + target_bits |= 8; +#endif +#ifdef FE_INEXACT + if (host_bits & FE_INEXACT) + target_bits |= 0x10; +#endif + /* C doesn't define an inexact exception. */ + return target_bits; +} + +/* Convert vfp exception flags to target form. */ +int vfp_host_exceptbits_to_host(int target_bits) +{ + int host_bits = 0; + +#ifdef FE_INVALID + if (target_bits & 1) + host_bits |= FE_INVALID; +#endif +#ifdef FE_DIVBYZERO + if (target_bits & 2) + host_bits |= FE_DIVBYZERO; +#endif +#ifdef FE_OVERFLOW + if (target_bits & 4) + host_bits |= FE_OVERFLOW; +#endif +#ifdef FE_UNDERFLOW + if (target_bits & 8) + host_bits |= FE_UNDERFLOW; +#endif +#ifdef FE_INEXACT + if (target_bits & 0x10) + host_bits |= FE_INEXACT; +#endif + return host_bits; +} + +void do_vfp_set_fpscr(void) +{ + int i; + uint32_t changed; + + changed = env->vfp.fpscr; + env->vfp.fpscr = (T0 & 0xffc8ffff); + env->vfp.vec_len = (T0 >> 16) & 7; + env->vfp.vec_stride = (T0 >> 20) & 3; + + changed ^= T0; + if (changed & (3 << 22)) { + i = (T0 >> 22) & 3; + switch (i) { + case 0: + i = FE_TONEAREST; + break; + case 1: + i = FE_UPWARD; + break; + case 2: + i = FE_DOWNWARD; + break; + case 3: + i = FE_TOWARDZERO; + break; + } + fesetround (i); + } + + /* Clear host exception flags. */ + feclearexcept(FE_ALL_EXCEPT); + +#ifdef feenableexcept + if (changed & 0x1f00) { + i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f); + feenableexcept (i); + fedisableexcept (FE_ALL_EXCEPT & ~i); + } +#endif + /* XXX: FZ and DN are not implemented. */ +} + +void do_vfp_get_fpscr(void) +{ + int i; + + T0 = (env->vfp.fpscr & 0xffc8ffff) | (env->vfp.vec_len << 16) + | (env->vfp.vec_stride << 20); + i = fetestexcept(FE_ALL_EXCEPT); + T0 |= vfp_exceptbits_from_host(i); +} diff --git a/target-arm/translate.c b/target-arm/translate.c index 2eb325e8e..db38e331b 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2,6 +2,7 @@ * ARM translation * * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2005 CodeSourcery, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -354,7 +355,527 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn) } } -static void disas_arm_insn(DisasContext *s) +#define VFP_OP(name) \ +static inline void gen_vfp_##name(int dp) \ +{ \ + if (dp) \ + gen_op_vfp_##name##d(); \ + else \ + gen_op_vfp_##name##s(); \ +} + +VFP_OP(add) +VFP_OP(sub) +VFP_OP(mul) +VFP_OP(div) +VFP_OP(neg) +VFP_OP(abs) +VFP_OP(sqrt) +VFP_OP(cmp) +VFP_OP(cmpe) +VFP_OP(F1_ld0) +VFP_OP(uito) +VFP_OP(sito) +VFP_OP(toui) +VFP_OP(touiz) +VFP_OP(tosi) +VFP_OP(tosiz) +VFP_OP(ld) +VFP_OP(st) + +#undef VFP_OP + +static inline void gen_mov_F0_vreg(int dp, int reg) +{ + if (dp) + gen_op_vfp_getreg_F0d(offsetof(CPUARMState, vfp.regs.d[reg])); + else + gen_op_vfp_getreg_F0s(offsetof(CPUARMState, vfp.regs.s[reg])); +} + +static inline void gen_mov_F1_vreg(int dp, int reg) +{ + if (dp) + gen_op_vfp_getreg_F1d(offsetof(CPUARMState, vfp.regs.d[reg])); + else + gen_op_vfp_getreg_F1s(offsetof(CPUARMState, vfp.regs.s[reg])); +} + +static inline void gen_mov_vreg_F0(int dp, int reg) +{ + if (dp) + gen_op_vfp_setreg_F0d(offsetof(CPUARMState, vfp.regs.d[reg])); + else + gen_op_vfp_setreg_F0s(offsetof(CPUARMState, vfp.regs.s[reg])); +} + +/* Disassemble a VFP instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask; + int dp, veclen; + + dp = ((insn & 0xf00) == 0xb00); + switch ((insn >> 24) & 0xf) { + case 0xe: + if (insn & (1 << 4)) { + /* single register transfer */ + if ((insn & 0x6f) != 0x00) + return 1; + rd = (insn >> 12) & 0xf; + if (dp) { + if (insn & 0x80) + return 1; + rn = (insn >> 16) & 0xf; + /* Get the existing value even for arm->vfp moves because + we only set half the register. */ + gen_mov_F0_vreg(1, rn); + gen_op_vfp_mrrd(); + if (insn & (1 << 20)) { + /* vfp->arm */ + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rd); + else + gen_movl_reg_T0(s, rd); + } else { + /* arm->vfp */ + if (insn & (1 << 21)) + gen_movl_T1_reg(s, rd); + else + gen_movl_T0_reg(s, rd); + gen_op_vfp_mdrr(); + gen_mov_vreg_F0(dp, rn); + } + } else { + rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); + if (insn & (1 << 20)) { + /* vfp->arm */ + if (insn & (1 << 21)) { + /* system register */ + switch (rn) { + case 0: /* fpsid */ + n = 0x0091A0000; + break; + case 2: /* fpscr */ + if (rd == 15) + gen_op_vfp_movl_T0_fpscr_flags(); + else + gen_op_vfp_movl_T0_fpscr(); + break; + default: + return 1; + } + } else { + gen_mov_F0_vreg(0, rn); + gen_op_vfp_mrs(); + } + if (rd == 15) { + /* This will only set the 4 flag bits */ + gen_op_movl_psr_T0(); + } else + gen_movl_reg_T0(s, rd); + } else { + /* arm->vfp */ + gen_movl_T0_reg(s, rd); + if (insn & (1 << 21)) { + /* system register */ + switch (rn) { + case 0: /* fpsid */ + /* Writes are ignored. */ + break; + case 2: /* fpscr */ + gen_op_vfp_movl_fpscr_T0(); + /* This could change vector settings, so jump to + the next instuction. */ + gen_op_movl_T0_im(s->pc); + gen_movl_reg_T0(s, 15); + s->is_jmp = DISAS_UPDATE; + break; + default: + return 1; + } + } else { + gen_op_vfp_msr(); + gen_mov_vreg_F0(0, rn); + } + } + } + } else { + /* data processing */ + /* The opcode is in bits 23, 21, 20 and 6. */ + op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1); + if (dp) { + if (op == 15) { + /* rn is opcode */ + rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); + } else { + /* rn is register number */ + if (insn & (1 << 7)) + return 1; + rn = (insn >> 16) & 0xf; + } + + if (op == 15 && (rn == 15 || rn > 17)) { + /* Integer or single precision destination. */ + rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1); + } else { + if (insn & (1 << 22)) + return 1; + rd = (insn >> 12) & 0xf; + } + + if (op == 15 && (rn == 16 || rn == 17)) { + /* Integer source. */ + rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); + } else { + if (insn & (1 << 5)) + return 1; + rm = insn & 0xf; + } + } else { + rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); + if (op == 15 && rn == 15) { + /* Double precision destination. */ + if (insn & (1 << 22)) + return 1; + rd = (insn >> 12) & 0xf; + } else + rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1); + rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); + } + + veclen = env->vfp.vec_len; + if (op == 15 && rn > 3) + veclen = 0; + + /* Shut up compiler warnings. */ + delta_m = 0; + delta_d = 0; + bank_mask = 0; + + if (veclen > 0) { + if (dp) + bank_mask = 0xc; + else + bank_mask = 0x18; + + /* Figure out what type of vector operation this is. */ + if ((rd & bank_mask) == 0) { + /* scalar */ + veclen = 0; + } else { + if (dp) + delta_d = (env->vfp.vec_stride >> 1) + 1; + else + delta_d = env->vfp.vec_stride + 1; + + if ((rm & bank_mask) == 0) { + /* mixed scalar/vector */ + delta_m = 0; + } else { + /* vector */ + delta_m = delta_d; + } + } + } + + /* Load the initial operands. */ + if (op == 15) { + switch (rn) { + case 16: + case 17: + /* Integer source */ + gen_mov_F0_vreg(0, rm); + break; + case 8: + case 9: + /* Compare */ + gen_mov_F0_vreg(dp, rd); + gen_mov_F1_vreg(dp, rm); + break; + case 10: + case 11: + /* Compare with zero */ + gen_mov_F0_vreg(dp, rd); + gen_vfp_F1_ld0(dp); + break; + default: + /* One source operand. */ + gen_mov_F0_vreg(dp, rm); + } + } else { + /* Two source operands. */ + gen_mov_F0_vreg(dp, rn); + gen_mov_F1_vreg(dp, rm); + } + + for (;;) { + /* Perform the calculation. */ + switch (op) { + case 0: /* mac: fd + (fn * fm) */ + gen_vfp_mul(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_add(dp); + break; + case 1: /* nmac: fd - (fn * fm) */ + gen_vfp_mul(dp); + gen_vfp_neg(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_add(dp); + break; + case 2: /* msc: -fd + (fn * fm) */ + gen_vfp_mul(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_sub(dp); + break; + case 3: /* nmsc: -fd - (fn * fm) */ + gen_vfp_mul(dp); + gen_mov_F1_vreg(dp, rd); + gen_vfp_add(dp); + gen_vfp_neg(dp); + break; + case 4: /* mul: fn * fm */ + gen_vfp_mul(dp); + break; + case 5: /* nmul: -(fn * fm) */ + gen_vfp_mul(dp); + gen_vfp_neg(dp); + break; + case 6: /* add: fn + fm */ + gen_vfp_add(dp); + break; + case 7: /* sub: fn - fm */ + gen_vfp_sub(dp); + break; + case 8: /* div: fn / fm */ + gen_vfp_div(dp); + break; + case 15: /* extension space */ + switch (rn) { + case 0: /* cpy */ + /* no-op */ + break; + case 1: /* abs */ + gen_vfp_abs(dp); + break; + case 2: /* neg */ + gen_vfp_neg(dp); + break; + case 3: /* sqrt */ + gen_vfp_sqrt(dp); + break; + case 8: /* cmp */ + gen_vfp_cmp(dp); + break; + case 9: /* cmpe */ + gen_vfp_cmpe(dp); + break; + case 10: /* cmpz */ + gen_vfp_cmp(dp); + break; + case 11: /* cmpez */ + gen_vfp_F1_ld0(dp); + gen_vfp_cmpe(dp); + break; + case 15: /* single<->double conversion */ + if (dp) + gen_op_vfp_fcvtsd(); + else + gen_op_vfp_fcvtds(); + break; + case 16: /* fuito */ + gen_vfp_uito(dp); + break; + case 17: /* fsito */ + gen_vfp_sito(dp); + break; + case 24: /* ftoui */ + gen_vfp_toui(dp); + break; + case 25: /* ftouiz */ + gen_vfp_touiz(dp); + break; + case 26: /* ftosi */ + gen_vfp_tosi(dp); + break; + case 27: /* ftosiz */ + gen_vfp_tosiz(dp); + break; + default: /* undefined */ + printf ("rn:%d\n", rn); + return 1; + } + break; + default: /* undefined */ + printf ("op:%d\n", op); + return 1; + } + + /* Write back the result. */ + if (op == 15 && (rn >= 8 && rn <= 11)) + ; /* Comparison, do nothing. */ + else if (op == 15 && rn > 17) + /* Integer result. */ + gen_mov_vreg_F0(0, rd); + else if (op == 15 && rn == 15) + /* conversion */ + gen_mov_vreg_F0(!dp, rd); + else + gen_mov_vreg_F0(dp, rd); + + /* break out of the loop if we have finished */ + if (veclen == 0) + break; + + if (op == 15 && delta_m == 0) { + /* single source one-many */ + while (veclen--) { + rd = ((rd + delta_d) & (bank_mask - 1)) + | (rd & bank_mask); + gen_mov_vreg_F0(dp, rd); + } + break; + } + /* Setup the next operands. */ + veclen--; + rd = ((rd + delta_d) & (bank_mask - 1)) + | (rd & bank_mask); + + if (op == 15) { + /* One source operand. */ + rm = ((rm + delta_m) & (bank_mask - 1)) + | (rm & bank_mask); + gen_mov_F0_vreg(dp, rm); + } else { + /* Two source operands. */ + rn = ((rn + delta_d) & (bank_mask - 1)) + | (rn & bank_mask); + gen_mov_F0_vreg(dp, rn); + if (delta_m) { + rm = ((rm + delta_m) & (bank_mask - 1)) + | (rm & bank_mask); + gen_mov_F1_vreg(dp, rm); + } + } + } + } + break; + case 0xc: + case 0xd: + if (dp && (insn & (1 << 22))) { + /* two-register transfer */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + if (dp) { + if (insn & (1 << 5)) + return 1; + rm = insn & 0xf; + } else + rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); + + if (insn & (1 << 20)) { + /* vfp->arm */ + if (dp) { + gen_mov_F0_vreg(1, rm); + gen_op_vfp_mrrd(); + gen_movl_reg_T0(s, rd); + gen_movl_reg_T1(s, rn); + } else { + gen_mov_F0_vreg(0, rm); + gen_op_vfp_mrs(); + gen_movl_reg_T0(s, rn); + gen_mov_F0_vreg(0, rm + 1); + gen_op_vfp_mrs(); + gen_movl_reg_T0(s, rd); + } + } else { + /* arm->vfp */ + if (dp) { + gen_movl_T0_reg(s, rd); + gen_movl_T1_reg(s, rn); + gen_op_vfp_mdrr(); + gen_mov_vreg_F0(1, rm); + } else { + gen_movl_T0_reg(s, rn); + gen_op_vfp_msr(); + gen_mov_vreg_F0(0, rm); + gen_movl_T0_reg(s, rd); + gen_op_vfp_msr(); + gen_mov_vreg_F0(0, rm + 1); + } + } + } else { + /* Load/store */ + rn = (insn >> 16) & 0xf; + if (dp) + rd = (insn >> 12) & 0xf; + else + rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1); + gen_movl_T1_reg(s, rn); + if ((insn & 0x01200000) == 0x01000000) { + /* Single load/store */ + offset = (insn & 0xff) << 2; + if ((insn & (1 << 23)) == 0) + offset = -offset; + gen_op_addl_T1_im(offset); + if (insn & (1 << 20)) { + gen_vfp_ld(dp); + gen_mov_vreg_F0(dp, rd); + } else { + gen_mov_F0_vreg(dp, rd); + gen_vfp_st(dp); + } + } else { + /* load/store multiple */ + if (dp) + n = (insn >> 1) & 0x7f; + else + n = insn & 0xff; + + if (insn & (1 << 24)) /* pre-decrement */ + gen_op_addl_T1_im(-((insn & 0xff) << 2)); + + if (dp) + offset = 8; + else + offset = 4; + for (i = 0; i < n; i++) { + if (insn & (1 << 20)) { + /* load */ + gen_vfp_ld(dp); + gen_mov_vreg_F0(dp, rd + i); + } else { + /* store */ + gen_mov_F0_vreg(dp, rd + i); + gen_vfp_st(dp); + } + gen_op_addl_T1_im(offset); + } + if (insn & (1 << 21)) { + /* writeback */ + if (insn & (1 << 24)) + offset = -offset * n; + else if (dp && (insn & 1)) + offset = 4; + else + offset = 0; + + if (offset != 0) + gen_op_addl_T1_im(offset); + gen_movl_reg_T1(s, rn); + } + } + } + break; + default: + /* Should never happen. */ + return 1; + } + return 0; +} + +static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; @@ -363,6 +884,7 @@ static void disas_arm_insn(DisasContext *s) cond = insn >> 28; if (cond == 0xf){ + /* Unconditional instructions. */ if ((insn & 0x0d70f000) == 0x0550f000) return; /* PLD */ else if ((insn & 0x0e000000) == 0x0a000000) { @@ -381,6 +903,10 @@ static void disas_arm_insn(DisasContext *s) gen_op_movl_T0_im(val); gen_bx(s); return; + } else if ((insn & 0x0fe00000) == 0x0c400000) { + /* Coprocessor double register transfer. */ + } else if ((insn & 0x0f000010) == 0x0e000010) { + /* Additional coprocessor register transfer. */ } goto illegal_op; } @@ -934,6 +1460,22 @@ static void disas_arm_insn(DisasContext *s) s->is_jmp = DISAS_TB_JUMP; } break; + case 0xc: + case 0xd: + case 0xe: + /* Coprocessor. */ + op1 = (insn >> 8) & 0xf; + switch (op1) { + case 10: + case 11: + if (disas_vfp_insn (env, s, insn)) + goto illegal_op; + break; + default: + /* unknown coprocessor. */ + goto illegal_op; + } + break; case 0xf: /* swi */ gen_op_movl_T0_im((long)s->pc); @@ -1484,7 +2026,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, if (env->thumb) disas_thumb_insn(dc); else - disas_arm_insn(dc); + disas_arm_insn(env, dc); } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); switch(dc->is_jmp) { @@ -1557,6 +2099,11 @@ void cpu_dump_state(CPUState *env, FILE *f, int flags) { int i; + struct { + uint32_t i; + float s; + } s0, s1; + CPU_DoubleU d; for(i=0;i<16;i++) { cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); @@ -1566,11 +2113,23 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, " "); } cpu_fprintf(f, "PSR=%08x %c%c%c%c\n", - env->cpsr, + env->cpsr, env->cpsr & (1 << 31) ? 'N' : '-', env->cpsr & (1 << 30) ? 'Z' : '-', env->cpsr & (1 << 29) ? 'C' : '-', env->cpsr & (1 << 28) ? 'V' : '-'); + + for (i = 0; i < 16; i++) { + s0.s = env->vfp.regs.s[i * 2]; + s1.s = env->vfp.regs.s[i * 2 + 1]; + d.d = env->vfp.regs.d[i]; + cpu_fprintf(f, "s%02d=%08x(%8f) s%02d=%08x(%8f) d%02d=%08x%08x(%8f)\n", + i * 2, (int)s0.i, s0.s, + i * 2 + 1, (int)s0.i, s0.s, + i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower, + d.d); + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr); + } } target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -- cgit v1.2.3 From 6df700c2069e85e5956228318a4e8a39a72763dd Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Feb 2005 19:43:42 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1310 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/TODO b/TODO index 8e256226d..cd3895054 100644 --- a/TODO +++ b/TODO @@ -1,20 +1,16 @@ short term: ---------- - debug option in 'configure' script + disable -fomit-frame-pointer -- Solaris display error with Cirrus VGA - (http://lists.gnu.org/archive/html/qemu-devel/2004-10/msg00390.html). - Precise VGA timings for old games/demos (malc patch) - merge PIC spurious interrupt patch - merge VNC keyboard patch - merge Solaris patch -- merge ARM patches + self modifying code patch (Paul Brook) -- warning for OS/2: must not use 128 MB memory +- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?) - config file (at least for windows/Mac OS X) - commit message if execution of code in IO memory - update doc: PCI infos. - VNC patch + Synaptic patch. - basic VGA optimizations -- test sysenter/sysexit and fxsr for L4 pistachio 686 - physical memory cache (reduce qemu-fast address space size to about 32 MB) - better code fetch (different exception handling + CS.limit support) - do not resize vga if invalid size. @@ -45,10 +41,8 @@ lower priority: -------------- - more friendly BIOS (logo) - int15 ah=86: use better timing -- HDD geometry in CMOS (not used except for very old DOS programs) - suppress shift_mem ops - fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) -- sysenter/sysexit emulation - optimize FPU operations (evaluate x87 stack pointer statically) - add IPC syscalls - use -msoft-float on ARM @@ -62,4 +56,3 @@ lower priority: cases of self modifying code. - use gcc as a backend to generate better code (easy to do by using op-i386.c operations as local inline functions). -- add SSE2/MMX operations -- cgit v1.2.3 From f94daedd27deff2daf97480dde8b1b02af90a0b6 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 21:28:22 +0000 Subject: more explicit message git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1311 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index b2ba875a3..6b83e38fb 100755 --- a/configure +++ b/configure @@ -373,7 +373,7 @@ if test $kqemu = "yes" ; then # test that the kernel config is present if test '!' -f "$kernel_path/Makefile" ; then - echo "No .config file present in $kernel_path - kqemu cannot be built" + echo "No Makefile file present in $kernel_path - kqemu cannot be built" kqemu="no" fi -- cgit v1.2.3 From 157777ef3e5821643ef46470bc0fecfda9d06ece Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 21:28:45 +0000 Subject: Samba 3 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1312 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vl.c b/vl.c index 89efe67ca..5dcf46ed0 100644 --- a/vl.c +++ b/vl.c @@ -1538,6 +1538,9 @@ void net_slirp_smb(const char *exported_dir) } fprintf(f, "[global]\n" + "private dir=%s\n" + "smb ports=0\n" + "socket address=127.0.0.1\n" "pid directory=%s\n" "lock directory=%s\n" "log file=%s/log.smbd\n" @@ -1551,6 +1554,7 @@ void net_slirp_smb(const char *exported_dir) smb_dir, smb_dir, smb_dir, + smb_dir, exported_dir ); fclose(f); -- cgit v1.2.3 From 5b0753e0d8dfca5a33edcd3cc1306bb5d0594005 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 21:37:28 +0000 Subject: initial Cocoa support (Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1313 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 9 +- cocoa.m | 607 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ configure | 11 + vl.c | 9 +- 4 files changed, 634 insertions(+), 2 deletions(-) create mode 100644 cocoa.m diff --git a/Makefile.target b/Makefile.target index 25f4719a3..5c82e38a6 100644 --- a/Makefile.target +++ b/Makefile.target @@ -346,6 +346,10 @@ endif ifdef CONFIG_SDL VL_OBJS+=sdl.o endif +ifdef CONFIG_COCOA +VL_OBJS+=cocoa.o +COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa +endif ifdef CONFIG_SLIRP DEFINES+=-I$(SRC_PATH)/slirp SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \ @@ -373,7 +377,10 @@ VL_LDFLAGS+=-p endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a - $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS) + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) + +cocoa.o: cocoa.m + $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< sdl.o: sdl.c keymaps.c sdl_keysym.h $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< diff --git a/cocoa.m b/cocoa.m new file mode 100644 index 000000000..ade7f61d8 --- /dev/null +++ b/cocoa.m @@ -0,0 +1,607 @@ +/* + * 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 +*/ +#include "vl.h" +#import + +NSWindow *window = NULL; +NSQuickDrawView *qd_view = NULL; + + +int gArgc; +char **gArgv; +DisplayState current_ds; + +/* main defined in qemu/vl.c */ +int qemu_main(int argc, char **argv); + +/* To deal with miniaturization */ +@interface QemuWindow : NSWindow +{ } +@end + + +/* + ------------------------------------------------------ + Qemu Video Driver + ------------------------------------------------------ +*/ + +/* + ------------------------------------------------------ + cocoa_update + ------------------------------------------------------ +*/ +static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) +{ + //printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); + + /* Use QDFlushPortBuffer() to flush content to display */ + RgnHandle dirty = NewRgn (); + RgnHandle temp = NewRgn (); + + SetEmptyRgn (dirty); + + /* Build the region of dirty rectangles */ + MacSetRectRgn (temp, x, y, + x + w, y + h); + MacUnionRgn (dirty, temp, dirty); + + /* Flush the dirty region */ + QDFlushPortBuffer ( [ qd_view qdPort ], dirty ); + DisposeRgn (dirty); + DisposeRgn (temp); +} + +/* + ------------------------------------------------------ + cocoa_resize + ------------------------------------------------------ +*/ +static void cocoa_resize(DisplayState *ds, int w, int h) +{ + const int device_bpp = 32; + static void *screen_pixels; + static int screen_pitch; + NSRect contentRect; + + //printf("resizing to %d %d\n", w, h); + + contentRect = NSMakeRect (0, 0, w, h); + if(window) + { + [window close]; + [window release]; + } + window = [ [ QemuWindow alloc ] initWithContentRect:contentRect + styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask + backing:NSBackingStoreBuffered defer:NO]; + if(!window) + { + fprintf(stderr, "(cocoa) can't create window\n"); + exit(1); + } + + if(qd_view) + [qd_view release]; + + qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ]; + + if(!qd_view) + { + fprintf(stderr, "(cocoa) can't create qd_view\n"); + exit(1); + } + + [ window setAcceptsMouseMovedEvents:YES ]; + [ window setTitle:@"Qemu" ]; + [ window setReleasedWhenClosed:NO ]; + + /* Set screen to black */ + [ window setBackgroundColor: [NSColor blackColor] ]; + + /* set window position */ + [ window center ]; + + [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ]; + [ [ window contentView ] addSubview:qd_view ]; + [ qd_view release ]; + [ window makeKeyAndOrderFront:nil ]; + + /* Careful here, the window seems to have to be onscreen to do that */ + LockPortBits ( [ qd_view qdPort ] ); + screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) ); + screen_pitch = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) ); + UnlockPortBits ( [ qd_view qdPort ] ); + { + int vOffset = [ window frame ].size.height - + [ qd_view frame ].size.height - [ qd_view frame ].origin.y; + + int hOffset = [ qd_view frame ].origin.x; + + screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8); + } + ds->data = screen_pixels; + ds->linesize = screen_pitch; + ds->depth = device_bpp; + ds->width = w; + ds->height = h; + + current_ds = *ds; +} + +/* + ------------------------------------------------------ + keymap conversion + ------------------------------------------------------ +*/ + +static int keymap[] = +{ + 30, //'a' 0x0 + 31, //'s' + 32, //'d' + 33, //'f' + 35, //'h' + 34, //'g' + 44, //'z' + 45, //'x' + 46, //'c' + 47, //'v' + 0, // 0 0x0a + 48, //'b' + 16, //'q' + 17, //'w' + 18, //'e' + 19, //'r' + 21, //'y' 0x10 + 20, //'t' + 2, //'1' + 3, //'2' + 4, //'3' + 5, //'4' + 7, //'6' + 6, //'5' + 0, //'=' + 10, //'9' + 8, //'7' 0x1A + 0, //'-' + 9, //'8' + 11, //'0' + 27, //']' + 24, //'o' + 22, //'u' 0x20 + 26, //'[' + 23, //'i' + 25, //'p' + 28, //'\n' + 38, //'l' + 36, //'j' + 40, //'"' + 37, //'k' + 39, //';' + 15, //'\t' 0x30 + 0, //' ' + 0, //'`' + 14, //'' + 0, //'' 0x34 + 0, //'' + 0, //'' + /* Not completed to finish see http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */ +}; + +static int cocoa_keycode_to_qemu(int keycode) +{ + if(sizeof(keymap) <= keycode) + { + printf("(cocoa) warning unknow keycode 0x%x\n", keycode); + return 0; + } + return keymap[keycode]; +} + +/* + ------------------------------------------------------ + cocoa_refresh + ------------------------------------------------------ +*/ +static void cocoa_refresh(DisplayState *ds) +{ + //printf("cocoa_refresh \n"); + NSDate *distantPast; + NSEvent *event; + NSAutoreleasePool *pool; + int grab = 1; + + pool = [ [ NSAutoreleasePool alloc ] init ]; + distantPast = [ NSDate distantPast ]; + + if (is_active_console(vga_console)) + vga_update_display(); + do { + event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast + inMode: NSDefaultRunLoopMode dequeue:YES ]; + if (event != nil) { + switch ([event type]) { + case NSKeyDown: + if(grab) + { + int keycode = cocoa_keycode_to_qemu([event keyCode]); + + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode & 0x7f); + } + break; + case NSKeyUp: + if(grab) + { + int keycode = cocoa_keycode_to_qemu([event keyCode]); + + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode | 0x80); + } + break; + case NSScrollWheel: + + case NSLeftMouseDown: + case NSLeftMouseUp: + + case NSOtherMouseDown: + case NSRightMouseDown: + + case NSOtherMouseUp: + case NSRightMouseUp: + + case NSMouseMoved: + case NSOtherMouseDragged: + case NSRightMouseDragged: + case NSLeftMouseDragged: + + default: [NSApp sendEvent:event]; + } + } + } while(event != nil); +} + +/* + ------------------------------------------------------ + cocoa_cleanup + ------------------------------------------------------ +*/ + +static void cocoa_cleanup(void) +{ + +} + +/* + ------------------------------------------------------ + cocoa_display_init + ------------------------------------------------------ +*/ + +void cocoa_display_init(DisplayState *ds, int full_screen) +{ + ds->dpy_update = cocoa_update; + ds->dpy_resize = cocoa_resize; + ds->dpy_refresh = cocoa_refresh; + + cocoa_resize(ds, 640, 400); + + atexit(cocoa_cleanup); +} + +/* + ------------------------------------------------------ + Interface with Cocoa + ------------------------------------------------------ +*/ + + +/* + ------------------------------------------------------ + QemuWindow + Some trick from SDL to use miniwindow + ------------------------------------------------------ +*/ +static void QZ_SetPortAlphaOpaque () +{ + /* Assume 32 bit if( bpp == 32 )*/ + if ( 1 ) { + + uint32_t *pixels = (uint32_t*) current_ds.data; + uint32_t rowPixels = current_ds.linesize / 4; + uint32_t i, j; + + for (i = 0; i < current_ds.height; i++) + for (j = 0; j < current_ds.width; j++) { + + pixels[ (i * rowPixels) + j ] |= 0xFF000000; + } + } +} + +@implementation QemuWindow +- (void)miniaturize:(id)sender +{ + + /* make the alpha channel opaque so anim won't have holes in it */ + QZ_SetPortAlphaOpaque (); + + [ super miniaturize:sender ]; + +} +- (void)display +{ + /* + This method fires just before the window deminaturizes from the Dock. + + We'll save the current visible surface, let the window manager redraw any + UI elements, and restore the SDL surface. This way, no expose event + is required, and the deminiaturize works perfectly. + */ + + /* make sure pixels are fully opaque */ + QZ_SetPortAlphaOpaque (); + + /* save current visible SDL surface */ + [ self cacheImageInRect:[ qd_view frame ] ]; + + /* let the window manager redraw controls, border, etc */ + [ super display ]; + + /* restore visible SDL surface */ + [ self restoreCachedImage ]; +} + +@end + + +/* + ------------------------------------------------------ + QemuCocoaGUIController + NSApp's delegate - indeed main object + ------------------------------------------------------ +*/ + +@interface QemuCocoaGUIController : NSObject +{ +} +- (void)applicationDidFinishLaunching: (NSNotification *) note; +- (void)applicationWillTerminate:(NSNotification *)aNotification; + +- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; + +- (void)startEmulationWithArgc:(int)argc argv:(char**)argv; +@end + +@implementation QemuCocoaGUIController +/* Called when the internal event loop has just started running */ +- (void)applicationDidFinishLaunching: (NSNotification *) note +{ + + /* Do whatever we want here : set up a pc list... */ + { + 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",nil] + modalForWindow:window modalDelegate:self + didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; + } + + /* or Launch Qemu, with the global args */ + //[self startEmulationWithArgc:gArgc argv:gArgv]; +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification +{ + printf("Application will terminate\n"); + qemu_system_shutdown_request(); + /* In order to avoid a crash */ + exit(0); +} + +- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo +{ + if(returnCode == NSCancelButton) + { + exit(0); + } + + if(returnCode == NSOKButton) + { + char *bin = "qemu"; + char *img = (char*)[ [ sheet filename ] cString]; + + char **argv = (char**)malloc( sizeof(char*)*3 ); + + asprintf(&argv[0], "%s", bin); + asprintf(&argv[1], "-hda"); + asprintf(&argv[2], "%s", img); + + printf("Using argc %d argv %s -hda %s\n", 3, bin, img); + + [self startEmulationWithArgc:3 argv:(char**)argv]; + } +} + +- (void)startEmulationWithArgc:(int)argc argv:(char**)argv +{ + int status; + /* Launch Qemu */ + printf("starting qemu...\n"); + status = qemu_main (argc, argv); + exit(status); +} +@end + +/* + ------------------------------------------------------ + Application Creation + ------------------------------------------------------ +*/ + +/* Dock Connection */ +typedef struct CPSProcessSerNum +{ + UInt32 lo; + UInt32 hi; +} CPSProcessSerNum; + +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); + +/* Menu Creation */ +static void setApplicationMenu(void) +{ + /* warning: this code is very odd */ + NSMenu *appleMenu; + NSMenuItem *menuItem; + NSString *title; + NSString *appName; + + appName = @"Qemu"; + appleMenu = [[NSMenu alloc] initWithTitle:@""]; + + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Hide " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + + + /* Put menu into the menubar */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:appleMenu]; + [[NSApp mainMenu] addItem:menuItem]; + + /* Tell the application object that this is now the application menu */ + [NSApp setAppleMenu:appleMenu]; + + /* Finally give up our references to the objects */ + [appleMenu release]; + [menuItem release]; +} + +/* Create a window menu */ +static void setupWindowMenu(void) +{ + NSMenu *windowMenu; + NSMenuItem *windowMenuItem; + NSMenuItem *menuItem; + + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + + /* "Minimize" item */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + [windowMenu addItem:menuItem]; + [menuItem release]; + + /* Put menu into the menubar */ + windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; + [windowMenuItem setSubmenu:windowMenu]; + [[NSApp mainMenu] addItem:windowMenuItem]; + + /* Tell the application object that this is now the window menu */ + [NSApp setWindowsMenu:windowMenu]; + + /* Finally give up our references to the objects */ + [windowMenu release]; + [windowMenuItem release]; + +} + +static void CustomApplicationMain (argc, argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + QemuCocoaGUIController *gui_controller; + CPSProcessSerNum PSN; + + [NSApplication sharedApplication]; + + if (!CPSGetCurrentProcess(&PSN)) + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) + if (!CPSSetFrontProcess(&PSN)) + [NSApplication sharedApplication]; + + /* Set up the menubar */ + [NSApp setMainMenu:[[NSMenu alloc] init]]; + setApplicationMenu(); + setupWindowMenu(); + + /* Create SDLMain and make it the app delegate */ + gui_controller = [[QemuCocoaGUIController alloc] init]; + [NSApp setDelegate:gui_controller]; + + /* Start the main event loop */ + [NSApp run]; + + [gui_controller release]; + [pool release]; +} + +/* Real main of qemu-cocoa */ +int main(int argc, char **argv) +{ + gArgc = argc; + gArgv = argv; + + CustomApplicationMain (argc, argv); + + return 0; +} diff --git a/configure b/configure index 6b83e38fb..e7130038d 100755 --- a/configure +++ b/configure @@ -83,6 +83,7 @@ fmod_inc="" linux="no" kqemu="no" kernel_path="" +cocoa="no" # OS specific targetos=`uname -s` @@ -178,6 +179,8 @@ for opt do ;; --kernel-path=*) kernel_path=${opt#--kernel-path=} ;; + --enable-cocoa) cocoa="yes" ; sdl="no" + ;; esac done @@ -403,6 +406,9 @@ echo "host big endian $bigendian" echo "target list $target_list" echo "gprof enabled $gprof" echo "static build $static" +if test "$darwin" = "yes" ; then + echo "Cocoa support $cocoa" +fi echo "SDL support $sdl" echo "SDL static link $sdl_static" echo "mingw32 support $mingw32" @@ -676,6 +682,11 @@ if test "$target_user_only" = "no"; then 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 diff --git a/vl.c b/vl.c index 5dcf46ed0..9efb4f7da 100644 --- a/vl.c +++ b/vl.c @@ -72,6 +72,11 @@ #endif #endif /* CONFIG_SDL */ +#ifdef CONFIG_COCOA +#undef main +#define main qemu_main +#endif /* CONFIG_COCOA */ + #include "disas.h" #include "exec-all.h" @@ -3554,8 +3559,10 @@ int main(int argc, char **argv) if (nographic) { dumb_display_init(ds); } else { -#ifdef CONFIG_SDL +#if defined(CONFIG_SDL) sdl_display_init(ds, full_screen); +#elif defined(CONFIG_COCOA) + cocoa_display_init(ds, full_screen); #else dumb_display_init(ds); #endif -- cgit v1.2.3 From 76472292e4f4db41d518ff09bd68054ee010fe9e Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 21:40:00 +0000 Subject: escape support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1314 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl_keysym.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sdl_keysym.h b/sdl_keysym.h index 07969bcb4..a1485eeca 100644 --- a/sdl_keysym.h +++ b/sdl_keysym.h @@ -270,6 +270,7 @@ static name2keysym_t name2keysym[]={ {"Multi_Key", SDLK_COMPOSE}, {"Num_Lock", SDLK_NUMLOCK}, {"Pause", SDLK_PAUSE}, +{"Escape", SDLK_ESCAPE}, {0,0}, }; -- cgit v1.2.3 From 1289f43ab16f9a012fb3698bcc5c92e61c10cd34 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 21:43:42 +0000 Subject: Windows keys support with keymaps git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1315 c046a42c-6fe2-441c-8c8c-71466251a162 --- keymaps/modifiers | 5 +++-- sdl_keysym.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/keymaps/modifiers b/keymaps/modifiers index 06c43442e..d8b019f04 100644 --- a/keymaps/modifiers +++ b/keymaps/modifiers @@ -8,9 +8,10 @@ Alt_L 0x38 Control_R 0x9d Control_L 0x1d -# Translate Meta, Super and Hyper to Windows keys. +# Translate Super to Windows keys. # This is hardcoded. See documentation for details. +Super_R 0xdb +Super_L 0xdc # Translate Menu to the Windows Application key. -# This one does not work either. Menu 0xdd diff --git a/sdl_keysym.h b/sdl_keysym.h index a1485eeca..9a7414209 100644 --- a/sdl_keysym.h +++ b/sdl_keysym.h @@ -213,6 +213,8 @@ static name2keysym_t name2keysym[]={ {"Meta_R", SDLK_RMETA}, {"Shift_L", SDLK_LSHIFT}, {"Shift_R", SDLK_RSHIFT}, +{"Super_L", SDLK_LSUPER}, +{"Super_R", SDLK_RSUPER}, /* special keys */ {"BackSpace", SDLK_BACKSPACE}, -- cgit v1.2.3 From b6f479d355a5391e0ac939a17e9175473e6516d1 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 21:51:04 +0000 Subject: -append support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1316 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index 784379983..0af062d96 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -25,6 +25,7 @@ #include "m48t08.h" #define KERNEL_LOAD_ADDR 0x00004000 +#define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 #define PROM_ADDR 0xffd00000 #define PROM_FILENAMEB "proll.bin" @@ -64,11 +65,28 @@ void DMA_run() {} static m48t08_t *nvram; -static void nvram_init(m48t08_t *nvram, uint8_t *macaddr) +static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline) { unsigned char tmp = 0; int i, j; + i = 0x40; + if (cmdline) { + uint32_t cmdline_len; + + strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); + m48t08_write(nvram, i++, CMDLINE_ADDR >> 24); + m48t08_write(nvram, i++, (CMDLINE_ADDR >> 16) & 0xff); + m48t08_write(nvram, i++, (CMDLINE_ADDR >> 8) & 0xff); + m48t08_write(nvram, i++, CMDLINE_ADDR & 0xff); + + cmdline_len = strlen(cmdline); + m48t08_write(nvram, i++, cmdline_len >> 24); + m48t08_write(nvram, i++, (cmdline_len >> 16) & 0xff); + m48t08_write(nvram, i++, (cmdline_len >> 8) & 0xff); + m48t08_write(nvram, i++, cmdline_len & 0xff); + } + i = 0x1fd8; m48t08_write(nvram, i++, 0x01); m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */ @@ -149,7 +167,7 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size); lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr); + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline); slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]); -- cgit v1.2.3 From 232ba5ab2edf39c7feb5e12089e0c4fbd69ca7ed Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 22:30:05 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1317 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index 8898eba36..23c6d4842 100644 --- a/Changelog +++ b/Changelog @@ -16,6 +16,8 @@ version 0.6.2: - initial SPARC64 support (Blue Swirl) - armv5te user mode support (Paul Brook) - ARM VFP support (Paul Brook) + - Samba 3 support + - initial Cocoa support (Pierre d'Herbemont) version 0.6.1: -- cgit v1.2.3 From 24b55b96507ef83d38eba1c310d63ecb8525911a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 22:30:41 +0000 Subject: disabled obsolete static SDL warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1318 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index e7130038d..e9978276d 100755 --- a/configure +++ b/configure @@ -431,11 +431,11 @@ fi fi if test $sdl_too_old = "yes"; then -echo "-> Your SDL version is too old - please upgrade to have FFplay/SDL support" -fi -if test "$sdl_static" = "no"; then - echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output" +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" -- cgit v1.2.3 From 5e83e8e3e7976db85fd037bd12629272827bc91b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 22:32:06 +0000 Subject: SUSE fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1319 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index bb609dec8..d69b21e6f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -577,7 +577,9 @@ static long do_setsockopt(int sockfd, int level, int optname, case SO_OOBINLINE: case SO_NO_CHECK: case SO_PRIORITY: +#ifdef SO_BSDCOMPAT case SO_BSDCOMPAT: +#endif case SO_PASSCRED: case SO_TIMESTAMP: case SO_RCVLOWAT: -- cgit v1.2.3 From d785e6be4d85d08ae34f7942da139493be28ec6b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Mar 2005 22:33:42 +0000 Subject: x86_64 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1320 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 1 + target-i386/exec.h | 51 +++++++++++++++++++++++------------------------- target-sparc/translate.c | 4 ++-- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index e1a023ee4..ba061c372 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -221,6 +221,7 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #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") diff --git a/target-i386/exec.h b/target-i386/exec.h index 404457eba..c4e59c423 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -21,77 +21,74 @@ #include "dyngen-exec.h" /* XXX: factorize this mess */ -#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) -#define HOST_LONG_BITS 64 -#else -#define HOST_LONG_BITS 32 -#endif - #ifdef TARGET_X86_64 #define TARGET_LONG_BITS 64 #else #define TARGET_LONG_BITS 32 #endif +#include "cpu-defs.h" + /* at least 4 register variables are defined */ register struct CPUX86State *env asm(AREG0); -/* XXX: use 64 bit regs if HOST_LONG_BITS == 64 */ -#if TARGET_LONG_BITS == 32 +#if TARGET_LONG_BITS > HOST_LONG_BITS + +/* no registers can be used */ +#define T0 (env->t0) +#define T1 (env->t1) +#define T2 (env->t2) -register uint32_t T0 asm(AREG1); -register uint32_t T1 asm(AREG2); -register uint32_t T2 asm(AREG3); +#else + +/* XXX: use unsigned long instead of target_ulong - better code will + be generated for 64 bit CPUs */ +register target_ulong T0 asm(AREG1); +register target_ulong T1 asm(AREG2); +register target_ulong T2 asm(AREG3); /* if more registers are available, we define some registers too */ #ifdef AREG4 -register uint32_t EAX asm(AREG4); +register target_ulong EAX asm(AREG4); #define reg_EAX #endif #ifdef AREG5 -register uint32_t ESP asm(AREG5); +register target_ulong ESP asm(AREG5); #define reg_ESP #endif #ifdef AREG6 -register uint32_t EBP asm(AREG6); +register target_ulong EBP asm(AREG6); #define reg_EBP #endif #ifdef AREG7 -register uint32_t ECX asm(AREG7); +register target_ulong ECX asm(AREG7); #define reg_ECX #endif #ifdef AREG8 -register uint32_t EDX asm(AREG8); +register target_ulong EDX asm(AREG8); #define reg_EDX #endif #ifdef AREG9 -register uint32_t EBX asm(AREG9); +register target_ulong EBX asm(AREG9); #define reg_EBX #endif #ifdef AREG10 -register uint32_t ESI asm(AREG10); +register target_ulong ESI asm(AREG10); #define reg_ESI #endif #ifdef AREG11 -register uint32_t EDI asm(AREG11); +register target_ulong EDI asm(AREG11); #define reg_EDI #endif -#else - -/* no registers can be used */ -#define T0 (env->t0) -#define T1 (env->t1) -#define T2 (env->t2) - -#endif +#endif /* ! (TARGET_LONG_BITS > HOST_LONG_BITS) */ #define A0 T2 diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 7b5642828..9f5c2f5c3 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1690,7 +1690,7 @@ void cpu_dump_state(CPUState *env, FILE *f, } #if defined(CONFIG_USER_ONLY) -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } @@ -1700,7 +1700,7 @@ extern int get_physical_address (CPUState *env, target_phys_addr_t *physical, in int *access_index, target_ulong address, int rw, int is_user); -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { target_phys_addr_t phys_addr; int prot, access_index; -- cgit v1.2.3 From 776f2227f6244003a5bcb20ea77c49427e6af023 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 2 Mar 2005 22:19:12 +0000 Subject: x86_64 test program git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1321 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 13 +- tests/test-i386-muldiv.h | 46 ++-- tests/test-i386-shift.h | 110 ++++++--- tests/test-i386.c | 568 ++++++++++++++++++++++++++++++++++------------- tests/test-i386.h | 99 +++++---- 5 files changed, 588 insertions(+), 248 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 4bd1dc6e3..de533f932 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -6,6 +6,9 @@ LDFLAGS= ifeq ($(ARCH),i386) TESTS=linux-test testthread sha1-i386 test-i386 runcom endif +ifeq ($(ARCH),x86_64) +TESTS=test-x86_64 +endif TESTS+=sha1# test_path #TESTS+=test_path @@ -24,11 +27,15 @@ test_path: test_path.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< ./$@ || { rm $@; exit 1; } -# i386 emulation test (test various opcodes) */ +# i386/x86_64 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c \ - test-i386-code16.S test-i386-vm86.S -lm + $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ \ + test-i386.c test-i386-code16.S test-i386-vm86.S -lm + +test-x86_64: test-i386.c \ + test-i386.h test-i386-shift.h test-i386-muldiv.h + $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ test-i386.c -lm ifeq ($(ARCH),i386) test: test-i386 diff --git a/tests/test-i386-muldiv.h b/tests/test-i386-muldiv.h index 5dba315c2..fd0d99134 100644 --- a/tests/test-i386-muldiv.h +++ b/tests/test-i386-muldiv.h @@ -1,7 +1,7 @@ -void glue(glue(test_, OP), b)(int op0, int op1) +void glue(glue(test_, OP), b)(long op0, long op1) { - int res, s1, s0, flags; + long res, s1, s0, flags; s0 = op0; s1 = op1; res = s0; @@ -10,16 +10,16 @@ void glue(glue(test_, OP), b)(int op0, int op1) "popf\n\t" stringify(OP)"b %b2\n\t" "pushf\n\t" - "popl %1\n\t" + "pop %1\n\t" : "=a" (res), "=g" (flags) : "q" (s1), "0" (res), "1" (flags)); - printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", stringify(OP) "b", s0, s1, res, flags & CC_MASK); } -void glue(glue(test_, OP), w)(int op0h, int op0, int op1) +void glue(glue(test_, OP), w)(long op0h, long op0, long op1) { - int res, s1, flags, resh; + long res, s1, flags, resh; s1 = op1; resh = op0h; res = op0; @@ -28,29 +28,49 @@ void glue(glue(test_, OP), w)(int op0h, int op0, int op1) "popf\n\t" stringify(OP) "w %w3\n\t" "pushf\n\t" - "popl %1\n\t" + "pop %1\n\t" : "=a" (res), "=g" (flags), "=d" (resh) : "q" (s1), "0" (res), "1" (flags), "2" (resh)); - printf("%-10s AH=%08x AL=%08x B=%08x RH=%08x RL=%08x CC=%04x\n", + printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n", stringify(OP) "w", op0h, op0, s1, resh, res, flags & CC_MASK); } -void glue(glue(test_, OP), l)(int op0h, int op0, int op1) +void glue(glue(test_, OP), l)(long op0h, long op0, long op1) { - int res, s1, flags, resh; + long res, s1, flags, resh; s1 = op1; resh = op0h; res = op0; flags = 0; asm ("push %5\n\t" "popf\n\t" - stringify(OP) "l %3\n\t" + stringify(OP) "l %k3\n\t" "pushf\n\t" - "popl %1\n\t" + "pop %1\n\t" : "=a" (res), "=g" (flags), "=d" (resh) : "q" (s1), "0" (res), "1" (flags), "2" (resh)); - printf("%-10s AH=%08x AL=%08x B=%08x RH=%08x RL=%08x CC=%04x\n", + printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n", stringify(OP) "l", op0h, op0, s1, resh, res, flags & CC_MASK); } +#if defined(__x86_64__) +void glue(glue(test_, OP), q)(long op0h, long op0, long op1) +{ + long res, s1, flags, resh; + s1 = op1; + resh = op0h; + res = op0; + flags = 0; + asm ("push %5\n\t" + "popf\n\t" + stringify(OP) "q %3\n\t" + "pushf\n\t" + "pop %1\n\t" + : "=a" (res), "=g" (flags), "=d" (resh) + : "q" (s1), "0" (res), "1" (flags), "2" (resh)); + printf("%-10s AH=" FMTLX " AL=" FMTLX " B=" FMTLX " RH=" FMTLX " RL=" FMTLX " CC=%04lx\n", + stringify(OP) "q", op0h, op0, s1, resh, res, flags & CC_MASK); +} +#endif + #undef OP diff --git a/tests/test-i386-shift.h b/tests/test-i386-shift.h index c3d8793b8..7a98e27a4 100644 --- a/tests/test-i386-shift.h +++ b/tests/test-i386-shift.h @@ -1,5 +1,6 @@ #define exec_op glue(exec_, OP) +#define exec_opq glue(glue(exec_, OP), q) #define exec_opl glue(glue(exec_, OP), l) #define exec_opw glue(glue(exec_, OP), w) #define exec_opb glue(glue(exec_, OP), b) @@ -7,106 +8,141 @@ #ifndef OP_SHIFTD #ifdef OP_NOBYTE -#define EXECSHIFT(size, res, s1, s2, flags) \ +#define EXECSHIFT(size, rsize, res, s1, s2, flags) \ asm ("push %4\n\t"\ "popf\n\t"\ - stringify(OP) size " %" size "2, %" size "0\n\t" \ + stringify(OP) size " %" rsize "2, %" rsize "0\n\t" \ "pushf\n\t"\ - "popl %1\n\t"\ + "pop %1\n\t"\ : "=g" (res), "=g" (flags)\ : "r" (s1), "0" (res), "1" (flags)); #else -#define EXECSHIFT(size, res, s1, s2, flags) \ +#define EXECSHIFT(size, rsize, res, s1, s2, flags) \ asm ("push %4\n\t"\ "popf\n\t"\ - stringify(OP) size " %%cl, %" size "0\n\t" \ + stringify(OP) size " %%cl, %" rsize "0\n\t" \ "pushf\n\t"\ - "popl %1\n\t"\ + "pop %1\n\t"\ : "=q" (res), "=g" (flags)\ : "c" (s1), "0" (res), "1" (flags)); #endif -void exec_opl(int s2, int s0, int s1, int iflags) +#if defined(__x86_64__) +void exec_opq(long s2, long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECSHIFT("", res, s1, s2, flags); + EXECSHIFT("q", "", res, s1, s2, flags); /* overflow is undefined if count != 1 */ if (s1 != 1) flags &= ~CC_O; - printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", + stringify(OP) "q", s0, s1, res, iflags, flags & CC_MASK); +} +#endif + +void exec_opl(long s2, long s0, long s1, long iflags) +{ + long res, flags; + res = s0; + flags = iflags; + EXECSHIFT("l", "k", res, s1, s2, flags); + /* overflow is undefined if count != 1 */ + if (s1 != 1) + flags &= ~CC_O; + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK); } -void exec_opw(int s2, int s0, int s1, int iflags) +void exec_opw(long s2, long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECSHIFT("w", res, s1, s2, flags); + EXECSHIFT("w", "w", res, s1, s2, flags); /* overflow is undefined if count != 1 */ if (s1 != 1) flags &= ~CC_O; - printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK); } #else -#define EXECSHIFT(size, res, s1, s2, flags) \ +#define EXECSHIFT(size, rsize, res, s1, s2, flags) \ asm ("push %4\n\t"\ "popf\n\t"\ - stringify(OP) size " %%cl, %" size "5, %" size "0\n\t" \ + stringify(OP) size " %%cl, %" rsize "5, %" rsize "0\n\t" \ "pushf\n\t"\ - "popl %1\n\t"\ + "pop %1\n\t"\ : "=g" (res), "=g" (flags)\ : "c" (s1), "0" (res), "1" (flags), "r" (s2)); -void exec_opl(int s2, int s0, int s1, int iflags) +#if defined(__x86_64__) +void exec_opq(long s2, long s0, long s1, long iflags) +{ + long res, flags; + res = s0; + flags = iflags; + EXECSHIFT("q", "", res, s1, s2, flags); + /* overflow is undefined if count != 1 */ + if (s1 != 1) + flags &= ~CC_O; + printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", + stringify(OP) "q", s0, s2, s1, res, iflags, flags & CC_MASK); +} +#endif + +void exec_opl(long s2, long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECSHIFT("", res, s1, s2, flags); + EXECSHIFT("l", "k", res, s1, s2, flags); /* overflow is undefined if count != 1 */ if (s1 != 1) flags &= ~CC_O; - printf("%-10s A=%08x B=%08x C=%08x R=%08x CCIN=%04x CC=%04x\n", + printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", stringify(OP) "l", s0, s2, s1, res, iflags, flags & CC_MASK); } -void exec_opw(int s2, int s0, int s1, int iflags) +void exec_opw(long s2, long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECSHIFT("w", res, s1, s2, flags); + EXECSHIFT("w", "w", res, s1, s2, flags); /* overflow is undefined if count != 1 */ if (s1 != 1) flags &= ~CC_O; - printf("%-10s A=%08x B=%08x C=%08x R=%08x CCIN=%04x CC=%04x\n", + printf("%-10s A=" FMTLX " B=" FMTLX " C=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", stringify(OP) "w", s0, s2, s1, res, iflags, flags & CC_MASK); } #endif #ifndef OP_NOBYTE -void exec_opb(int s0, int s1, int iflags) +void exec_opb(long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECSHIFT("b", res, s1, 0, flags); + EXECSHIFT("b", "b", res, s1, 0, flags); /* overflow is undefined if count != 1 */ if (s1 != 1) flags &= ~CC_O; - printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK); } #endif -void exec_op(int s2, int s0, int s1) +void exec_op(long s2, long s0, long s1) { + s2 = i2l(s2); + s0 = i2l(s0); +#if defined(__x86_64__) + exec_opq(s2, s0, s1, 0); +#endif exec_opl(s2, s0, s1, 0); #ifdef OP_SHIFTD if (s1 <= 15) @@ -118,6 +154,9 @@ void exec_op(int s2, int s0, int s1) exec_opb(s0, s1, 0); #endif #ifdef OP_CC +#if defined(__x86_64__) + exec_opq(s2, s0, s1, CC_C); +#endif exec_opl(s2, s0, s1, CC_C); exec_opw(s2, s0, s1, CC_C); exec_opb(s0, s1, CC_C); @@ -126,10 +165,15 @@ void exec_op(int s2, int s0, int s1) void glue(test_, OP)(void) { - int i; - for(i = 0; i < 32; i++) + int i, n; +#if defined(__x86_64__) + n = 64; +#else + n = 32; +#endif + for(i = 0; i < n; i++) exec_op(0x21ad3d34, 0x12345678, i); - for(i = 0; i < 32; i++) + for(i = 0; i < n; i++) exec_op(0x813f3421, 0x82345678, i); } diff --git a/tests/test-i386.c b/tests/test-i386.c index 9f1c4f003..6afb72747 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -28,14 +28,35 @@ #include #include #include -#include -#define TEST_CMOV 0 -#define TEST_FCOMI 0 +#if !defined(__x86_64__) #define TEST_VM86 +#define TEST_SEGS +#endif //#define LINUX_VM86_IOPL_FIX //#define TEST_P4_FLAGS -//#define TEST_SSE +#if defined(__x86_64__) +#define TEST_SSE +#define TEST_CMOV 1 +#define TEST_FCOMI 1 +#else +#define TEST_CMOV 0 +#define TEST_FCOMI 0 +#endif + +#if defined(__x86_64__) +#define FMT64X "%016lx" +#define FMTLX "%016lx" +#define X86_64_ONLY(x) x +#else +#define FMT64X "%016llx" +#define FMTLX "%08lx" +#define X86_64_ONLY(x) +#endif + +#ifdef TEST_VM86 +#include +#endif #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) @@ -49,12 +70,22 @@ #define CC_S 0x0080 #define CC_O 0x0800 -#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) - -static void *call_start __init_call = NULL; +#define __init_call __attribute__ ((unused,__section__ ("initcall"))) #define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) +#if defined(__x86_64__) +static inline long i2l(long v) +{ + return v | ((v ^ 0xabcd) << 32); +} +#else +static inline long i2l(long v) +{ + return v; +} +#endif + #define OP add #include "test-i386.h" @@ -158,12 +189,20 @@ static void *call_start __init_call = NULL; #include "test-i386-shift.h" /* lea test (modrm support) */ +#define TEST_LEAQ(STR)\ +{\ + asm("lea " STR ", %0"\ + : "=r" (res)\ + : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ + printf("lea %s = " FMTLX "\n", STR, res);\ +} + #define TEST_LEA(STR)\ {\ - asm("leal " STR ", %0"\ + asm("lea " STR ", %0"\ : "=r" (res)\ : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ - printf("lea %s = %08x\n", STR, res);\ + printf("lea %s = " FMTLX "\n", STR, res);\ } #define TEST_LEA16(STR)\ @@ -171,19 +210,19 @@ static void *call_start __init_call = NULL; asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\ : "=wq" (res)\ : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ - printf("lea %s = %08x\n", STR, res);\ + printf("lea %s = %08lx\n", STR, res);\ } void test_lea(void) { - int eax, ebx, ecx, edx, esi, edi, res; - eax = 0x0001; - ebx = 0x0002; - ecx = 0x0004; - edx = 0x0008; - esi = 0x0010; - edi = 0x0020; + long eax, ebx, ecx, edx, esi, edi, res; + eax = i2l(0x0001); + ebx = i2l(0x0002); + ecx = i2l(0x0004); + edx = i2l(0x0008); + esi = i2l(0x0010); + edi = i2l(0x0020); TEST_LEA("0x4000"); @@ -239,6 +278,62 @@ void test_lea(void) TEST_LEA("0x4000(%%edx, %%ecx, 4)"); TEST_LEA("0x4000(%%esi, %%ecx, 8)"); +#if defined(__x86_64__) + TEST_LEAQ("0x4000"); + TEST_LEAQ("0x4000(%%rip)"); + + TEST_LEAQ("(%%rax)"); + TEST_LEAQ("(%%rbx)"); + TEST_LEAQ("(%%rcx)"); + TEST_LEAQ("(%%rdx)"); + TEST_LEAQ("(%%rsi)"); + TEST_LEAQ("(%%rdi)"); + + TEST_LEAQ("0x40(%%rax)"); + TEST_LEAQ("0x40(%%rbx)"); + TEST_LEAQ("0x40(%%rcx)"); + TEST_LEAQ("0x40(%%rdx)"); + TEST_LEAQ("0x40(%%rsi)"); + TEST_LEAQ("0x40(%%rdi)"); + + TEST_LEAQ("0x4000(%%rax)"); + TEST_LEAQ("0x4000(%%rbx)"); + TEST_LEAQ("0x4000(%%rcx)"); + TEST_LEAQ("0x4000(%%rdx)"); + TEST_LEAQ("0x4000(%%rsi)"); + TEST_LEAQ("0x4000(%%rdi)"); + + TEST_LEAQ("(%%rax, %%rcx)"); + TEST_LEAQ("(%%rbx, %%rdx)"); + TEST_LEAQ("(%%rcx, %%rcx)"); + TEST_LEAQ("(%%rdx, %%rcx)"); + TEST_LEAQ("(%%rsi, %%rcx)"); + TEST_LEAQ("(%%rdi, %%rcx)"); + + TEST_LEAQ("0x40(%%rax, %%rcx)"); + TEST_LEAQ("0x4000(%%rbx, %%rdx)"); + + TEST_LEAQ("(%%rcx, %%rcx, 2)"); + TEST_LEAQ("(%%rdx, %%rcx, 4)"); + TEST_LEAQ("(%%rsi, %%rcx, 8)"); + + TEST_LEAQ("(,%%rax, 2)"); + TEST_LEAQ("(,%%rbx, 4)"); + TEST_LEAQ("(,%%rcx, 8)"); + + TEST_LEAQ("0x40(,%%rax, 2)"); + TEST_LEAQ("0x40(,%%rbx, 4)"); + TEST_LEAQ("0x40(,%%rcx, 8)"); + + + TEST_LEAQ("-10(%%rcx, %%rcx, 2)"); + TEST_LEAQ("-10(%%rdx, %%rcx, 4)"); + TEST_LEAQ("-10(%%rsi, %%rcx, 8)"); + + TEST_LEAQ("0x4000(%%rcx, %%rcx, 2)"); + TEST_LEAQ("0x4000(%%rdx, %%rcx, 4)"); + TEST_LEAQ("0x4000(%%rsi, %%rcx, 8)"); +#else /* limited 16 bit addressing test */ TEST_LEA16("0x4000"); TEST_LEA16("(%%bx)"); @@ -255,6 +350,7 @@ void test_lea(void) TEST_LEA16("0x40(%%bx,%%di)"); TEST_LEA16("0x4000(%%bx,%%si)"); TEST_LEA16("0x4000(%%bx,%%di)"); +#endif } #define TEST_JCC(JCC, v1, v2)\ @@ -276,18 +372,24 @@ void test_lea(void) : "r" (v1), "r" (v2));\ printf("%-10s %d\n", "set" JCC, res);\ if (TEST_CMOV) {\ - asm("movl $0x12345678, %0\n\t"\ - "cmpl %2, %1\n\t"\ - "cmov" JCC "l %3, %0\n\t"\ + long val = i2l(1);\ + long res = i2l(0x12345678);\ +X86_64_ONLY(\ + asm("cmpl %2, %1\n\t"\ + "cmov" JCC "q %3, %0\n\t"\ : "=r" (res)\ - : "r" (v1), "r" (v2), "m" (1));\ - printf("%-10s R=0x%08x\n", "cmov" JCC "l", res);\ - asm("movl $0x12345678, %0\n\t"\ - "cmpl %2, %1\n\t"\ + : "r" (v1), "r" (v2), "m" (val), "0" (res));\ + printf("%-10s R=" FMTLX "\n", "cmov" JCC "l", res);)\ + asm("cmpl %2, %1\n\t"\ + "cmov" JCC "l %k3, %k0\n\t"\ + : "=r" (res)\ + : "r" (v1), "r" (v2), "m" (val), "0" (res));\ + printf("%-10s R=" FMTLX "\n", "cmov" JCC "l", res);\ + asm("cmpl %2, %1\n\t"\ "cmov" JCC "w %w3, %w0\n\t"\ : "=r" (res)\ - : "r" (v1), "r" (v2), "r" (1));\ - printf("%-10s R=0x%08x\n", "cmov" JCC "w", res);\ + : "r" (v1), "r" (v2), "r" (1), "0" (res));\ + printf("%-10s R=" FMTLX "\n", "cmov" JCC "w", res);\ } \ } @@ -367,9 +469,9 @@ void test_jcc(void) #define OP imul #include "test-i386-muldiv.h" -void test_imulw2(int op0, int op1) +void test_imulw2(long op0, long op1) { - int res, s1, s0, flags; + long res, s1, s0, flags; s0 = op0; s1 = op1; res = s0; @@ -378,45 +480,66 @@ void test_imulw2(int op0, int op1) "popf\n\t" "imulw %w2, %w0\n\t" "pushf\n\t" - "popl %1\n\t" + "pop %1\n\t" : "=q" (res), "=g" (flags) : "q" (s1), "0" (res), "1" (flags)); - printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", "imulw", s0, s1, res, flags & CC_MASK); } -void test_imull2(int op0, int op1) +void test_imull2(long op0, long op1) { - int res, s1, s0, flags; + long res, s1, s0, flags; s0 = op0; s1 = op1; res = s0; flags = 0; asm volatile ("push %4\n\t" "popf\n\t" - "imull %2, %0\n\t" + "imull %k2, %k0\n\t" "pushf\n\t" - "popl %1\n\t" + "pop %1\n\t" : "=q" (res), "=g" (flags) : "q" (s1), "0" (res), "1" (flags)); - printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", "imull", s0, s1, res, flags & CC_MASK); } -#define TEST_IMUL_IM(size, size1, op0, op1)\ +#if defined(__x86_64__) +void test_imulq2(long op0, long op1) +{ + long res, s1, s0, flags; + s0 = op0; + s1 = op1; + res = s0; + flags = 0; + asm volatile ("push %4\n\t" + "popf\n\t" + "imulq %2, %0\n\t" + "pushf\n\t" + "pop %1\n\t" + : "=q" (res), "=g" (flags) + : "q" (s1), "0" (res), "1" (flags)); + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n", + "imulq", s0, s1, res, flags & CC_MASK); +} +#endif + +#define TEST_IMUL_IM(size, rsize, op0, op1)\ {\ - int res, flags;\ + long res, flags, s1;\ flags = 0;\ res = 0;\ + s1 = op1;\ asm volatile ("push %3\n\t"\ "popf\n\t"\ - "imul" size " $" #op0 ", %" size1 "2, %" size1 "0\n\t" \ + "imul" size " $" #op0 ", %" rsize "2, %" rsize "0\n\t" \ "pushf\n\t"\ - "popl %1\n\t"\ + "pop %1\n\t"\ : "=r" (res), "=g" (flags)\ - : "r" (op1), "1" (flags), "0" (res));\ - printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",\ - "imul" size " im", op0, op1, res, flags & CC_MASK);\ + : "r" (s1), "1" (flags), "0" (res));\ + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CC=%04lx\n",\ + "imul" size " im", (long)op0, (long)op1, res, flags & CC_MASK);\ } @@ -476,10 +599,10 @@ void test_mul(void) TEST_IMUL_IM("w", "w", 0x8000, 0x80000000); TEST_IMUL_IM("w", "w", 0x7fff, 0x1000); - TEST_IMUL_IM("l", "", 45, 0x1234); - TEST_IMUL_IM("l", "", -45, 23); - TEST_IMUL_IM("l", "", 0x8000, 0x80000000); - TEST_IMUL_IM("l", "", 0x7fff, 0x1000); + TEST_IMUL_IM("l", "k", 45, 0x1234); + TEST_IMUL_IM("l", "k", -45, 23); + TEST_IMUL_IM("l", "k", 0x8000, 0x80000000); + TEST_IMUL_IM("l", "k", 0x7fff, 0x1000); test_idivb(0x12341678, 0x127e); test_idivb(0x43210123, -5); @@ -508,30 +631,68 @@ void test_mul(void) test_divl(0, -233223, -45); test_divl(0, 0x80000000, -1); test_divl(0x12343, 0x12345678, 0x81234567); + +#if defined(__x86_64__) + test_imulq(0, 0x1234001d1234001d, 45); + test_imulq(0, 23, -45); + test_imulq(0, 0x8000000000000000, 0x8000000000000000); + test_imulq(0, 0x100000000, 0x100000000); + + test_mulq(0, 0x1234001d1234001d, 45); + test_mulq(0, 23, -45); + test_mulq(0, 0x8000000000000000, 0x8000000000000000); + test_mulq(0, 0x100000000, 0x100000000); + + test_imulq2(0x1234001d1234001d, 45); + test_imulq2(23, -45); + test_imulq2(0x8000000000000000, 0x8000000000000000); + test_imulq2(0x100000000, 0x100000000); + + TEST_IMUL_IM("q", "", 45, 0x12341234); + TEST_IMUL_IM("q", "", -45, 23); + TEST_IMUL_IM("q", "", 0x8000, 0x8000000000000000); + TEST_IMUL_IM("q", "", 0x7fff, 0x10000000); + + test_idivq(0, 0x12345678abcdef, 12347); + test_idivq(0, -233223, -45); + test_idivq(0, 0x8000000000000000, -1); + test_idivq(0x12343, 0x12345678, 0x81234567); + + test_divq(0, 0x12345678abcdef, 12347); + test_divq(0, -233223, -45); + test_divq(0, 0x8000000000000000, -1); + test_divq(0x12343, 0x12345678, 0x81234567); +#endif } #define TEST_BSX(op, size, op0)\ {\ - int res, val, resz;\ + long res, val, resz;\ val = op0;\ - asm("xorl %1, %1\n"\ - "movl $0x12345678, %0\n"\ + asm("xor %1, %1\n"\ + "mov $0x12345678, %0\n"\ #op " %" size "2, %" size "0 ; setz %b1" \ : "=r" (res), "=q" (resz)\ : "g" (val));\ - printf("%-10s A=%08x R=%08x %d\n", #op, val, res, resz);\ + printf("%-10s A=" FMTLX " R=" FMTLX " %ld\n", #op, val, res, resz);\ } void test_bsx(void) { TEST_BSX(bsrw, "w", 0); TEST_BSX(bsrw, "w", 0x12340128); - TEST_BSX(bsrl, "", 0); - TEST_BSX(bsrl, "", 0x00340128); TEST_BSX(bsfw, "w", 0); TEST_BSX(bsfw, "w", 0x12340128); - TEST_BSX(bsfl, "", 0); - TEST_BSX(bsfl, "", 0x00340128); + TEST_BSX(bsrl, "k", 0); + TEST_BSX(bsrl, "k", 0x00340128); + TEST_BSX(bsfl, "k", 0); + TEST_BSX(bsfl, "k", 0x00340128); +#if defined(__x86_64__) + TEST_BSX(bsrq, "", 0); + TEST_BSX(bsrq, "", 0x003401281234); + TEST_BSX(bsfq, "", 0); + TEST_BSX(bsfq, "", 0x003401281234); +#endif } /**********************************************/ @@ -570,14 +731,14 @@ void test_fcmp(double a, double b) printf("(%f<=%f)=%d\n", a, b, a >= b); if (TEST_FCOMI) { - unsigned int eflags; + long eflags; /* test f(u)comi instruction */ asm("fcomi %2, %1\n" "pushf\n" "pop %0\n" : "=r" (eflags) : "t" (a), "u" (b)); - printf("fcomi(%f %f)=%08x\n", a, b, eflags & (CC_Z | CC_P | CC_C)); + printf("fcomi(%f %f)=%08lx\n", a, b, eflags & (CC_Z | CC_P | CC_C)); } } @@ -596,8 +757,8 @@ void test_fcvt(double a) la = a; printf("(float)%f = %f\n", a, fa); printf("(long double)%f = %Lf\n", a, la); - printf("a=%016Lx\n", *(long long *)&a); - printf("la=%016Lx %04x\n", *(long long *)&la, + printf("a=" FMT64X "\n", *(uint64_t *)&a); + printf("la=" FMT64X " %04x\n", *(uint64_t *)&la, *(unsigned short *)((char *)(&la) + 8)); /* test all roundings */ @@ -611,7 +772,7 @@ void test_fcvt(double a) asm volatile ("fldcw %0" : : "m" (fpuc)); printf("(short)a = %d\n", wa); printf("(int)a = %d\n", ia); - printf("(int64_t)a = %Ld\n", lla); + printf("(int64_t)a = " FMT64X "\n", lla); printf("rint(a) = %f\n", ra); } } @@ -709,14 +870,14 @@ void test_fenv(void) "fcmov" CC " %2, %0\n"\ : "=t" (res)\ : "0" (a), "u" (b), "g" (eflags));\ - printf("fcmov%s eflags=0x%04x-> %f\n", \ - CC, eflags, res);\ + printf("fcmov%s eflags=0x%04lx-> %f\n", \ + CC, (long)eflags, res);\ } void test_fcmov(void) { double a, b; - int eflags, i; + long eflags, i; a = 1.0; b = 2.0; @@ -762,6 +923,7 @@ void test_floats(void) } /**********************************************/ +#if !defined(__x86_64__) #define TEST_BCD(op, op0, cc_in, cc_mask)\ {\ @@ -772,7 +934,7 @@ void test_floats(void) "popf\n\t"\ #op "\n\t"\ "pushf\n\t"\ - "popl %1\n\t"\ + "pop %1\n\t"\ : "=a" (res), "=g" (flags)\ : "0" (res), "1" (flags));\ printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n",\ @@ -830,42 +992,53 @@ void test_bcd(void) TEST_BCD(aam, 0x12340547, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); } +#endif #define TEST_XCHG(op, size, opconst)\ {\ - int op0, op1;\ - op0 = 0x12345678;\ - op1 = 0xfbca7654;\ + long op0, op1;\ + op0 = i2l(0x12345678);\ + op1 = i2l(0xfbca7654);\ asm(#op " %" size "0, %" size "1" \ : "=q" (op0), opconst (op1) \ : "0" (op0), "1" (op1));\ - printf("%-10s A=%08x B=%08x\n",\ + printf("%-10s A=" FMTLX " B=" FMTLX "\n",\ #op, op0, op1);\ } #define TEST_CMPXCHG(op, size, opconst, eax)\ {\ - int op0, op1;\ - op0 = 0x12345678;\ - op1 = 0xfbca7654;\ + long op0, op1, op2;\ + op0 = i2l(0x12345678);\ + op1 = i2l(0xfbca7654);\ + op2 = i2l(eax);\ asm(#op " %" size "0, %" size "1" \ : "=q" (op0), opconst (op1) \ - : "0" (op0), "1" (op1), "a" (eax));\ - printf("%-10s EAX=%08x A=%08x C=%08x\n",\ - #op, eax, op0, op1);\ + : "0" (op0), "1" (op1), "a" (op2));\ + printf("%-10s EAX=" FMTLX " A=" FMTLX " C=" FMTLX "\n",\ + #op, op2, op0, op1);\ } void test_xchg(void) { - TEST_XCHG(xchgl, "", "=q"); +#if defined(__x86_64__) + TEST_XCHG(xchgq, "", "=q"); +#endif + TEST_XCHG(xchgl, "k", "=q"); TEST_XCHG(xchgw, "w", "=q"); TEST_XCHG(xchgb, "b", "=q"); - TEST_XCHG(xchgl, "", "=m"); +#if defined(__x86_64__) + TEST_XCHG(xchgq, "", "=m"); +#endif + TEST_XCHG(xchgl, "k", "=m"); TEST_XCHG(xchgw, "w", "=m"); TEST_XCHG(xchgb, "b", "=m"); - TEST_XCHG(xaddl, "", "=q"); +#if defined(__x86_64__) + TEST_XCHG(xaddq, "", "=q"); +#endif + TEST_XCHG(xaddl, "k", "=q"); TEST_XCHG(xaddw, "w", "=q"); TEST_XCHG(xaddb, "b", "=q"); @@ -876,29 +1049,44 @@ void test_xchg(void) printf("xaddl same res=%08x\n", res); } - TEST_XCHG(xaddl, "", "=m"); +#if defined(__x86_64__) + TEST_XCHG(xaddq, "", "=m"); +#endif + TEST_XCHG(xaddl, "k", "=m"); TEST_XCHG(xaddw, "w", "=m"); TEST_XCHG(xaddb, "b", "=m"); - TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfbca7654); +#if defined(__x86_64__) + TEST_CMPXCHG(cmpxchgq, "", "=q", 0xfbca7654); +#endif + TEST_CMPXCHG(cmpxchgl, "k", "=q", 0xfbca7654); TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfbca7654); TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfbca7654); - TEST_CMPXCHG(cmpxchgl, "", "=q", 0xfffefdfc); +#if defined(__x86_64__) + TEST_CMPXCHG(cmpxchgq, "", "=q", 0xfffefdfc); +#endif + TEST_CMPXCHG(cmpxchgl, "k", "=q", 0xfffefdfc); TEST_CMPXCHG(cmpxchgw, "w", "=q", 0xfffefdfc); TEST_CMPXCHG(cmpxchgb, "b", "=q", 0xfffefdfc); - TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfbca7654); +#if defined(__x86_64__) + TEST_CMPXCHG(cmpxchgq, "", "=m", 0xfbca7654); +#endif + TEST_CMPXCHG(cmpxchgl, "k", "=m", 0xfbca7654); TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfbca7654); TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfbca7654); - TEST_CMPXCHG(cmpxchgl, "", "=m", 0xfffefdfc); +#if defined(__x86_64__) + TEST_CMPXCHG(cmpxchgq, "", "=m", 0xfffefdfc); +#endif + TEST_CMPXCHG(cmpxchgl, "k", "=m", 0xfffefdfc); TEST_CMPXCHG(cmpxchgw, "w", "=m", 0xfffefdfc); TEST_CMPXCHG(cmpxchgb, "b", "=m", 0xfffefdfc); { uint64_t op0, op1, op2; - int i, eflags; + long i, eflags; for(i = 0; i < 2; i++) { op0 = 0x123456789abcd; @@ -909,15 +1097,16 @@ void test_xchg(void) op2 = 0x6532432432434; asm("cmpxchg8b %1\n" "pushf\n" - "popl %2\n" + "pop %2\n" : "=A" (op0), "=m" (op1), "=g" (eflags) : "0" (op0), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32))); - printf("cmpxchg8b: op0=%016llx op1=%016llx CC=%02x\n", + printf("cmpxchg8b: op0=" FMT64X " op1=" FMT64X " CC=%02lx\n", op0, op1, eflags & CC_Z); } } } +#ifdef TEST_SEGS /**********************************************/ /* segmentation tests */ @@ -931,11 +1120,11 @@ _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) #define modify_ldt_ldt_s user_desc #endif +#define MK_SEL(n) (((n) << 3) | 7) + uint8_t seg_data1[4096]; uint8_t seg_data2[4096]; -#define MK_SEL(n) (((n) << 3) | 7) - #define TEST_LR(op, size, seg, mask)\ {\ int res, res2;\ @@ -1079,6 +1268,7 @@ void test_code16(void) : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc"); printf("func3() = 0x%08x\n", res); } +#endif extern char func_lret32; extern char func_iret32; @@ -1086,66 +1276,77 @@ extern char func_iret32; void test_misc(void) { char table[256]; - int res, i; + long res, i; for(i=0;i<256;i++) table[i] = 256 - i; res = 0x12345678; asm ("xlat" : "=a" (res) : "b" (table), "0" (res)); - printf("xlat: EAX=%08x\n", res); + printf("xlat: EAX=" FMTLX "\n", res); - asm volatile ("pushl %%cs ; call %1" +#if !defined(__x86_64__) + asm volatile ("push %%cs ; call %1" : "=a" (res) : "m" (func_lret32): "memory", "cc"); - printf("func_lret32=%x\n", res); + printf("func_lret32=" FMTLX "\n", res); - asm volatile ("pushfl ; pushl %%cs ; call %1" + asm volatile ("pushf ; push %%cs ; call %1" : "=a" (res) : "m" (func_iret32): "memory", "cc"); - printf("func_iret32=%x\n", res); + printf("func_iret32=" FMTLX "\n", res); +#endif +#if defined(__x86_64__) + /* specific popl test */ + asm volatile ("push $12345432 ; push $0x9abcdef ; pop (%%rsp) ; pop %0" + : "=g" (res)); + printf("popl esp=" FMTLX "\n", res); +#else /* specific popl test */ asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0" : "=g" (res)); - printf("popl esp=%x\n", res); + printf("popl esp=" FMTLX "\n", res); /* specific popw test */ asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popw (%%esp) ; addl $2, %%esp ; popl %0" : "=g" (res)); - printf("popw esp=%x\n", res); + printf("popw esp=" FMTLX "\n", res); +#endif } uint8_t str_buffer[4096]; #define TEST_STRING1(OP, size, DF, REP)\ {\ - int esi, edi, eax, ecx, eflags;\ + long esi, edi, eax, ecx, eflags;\ \ esi = (long)(str_buffer + sizeof(str_buffer) / 2);\ edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\ - eax = 0x12345678;\ + eax = i2l(0x12345678);\ ecx = 17;\ \ - asm volatile ("pushl $0\n\t"\ + asm volatile ("push $0\n\t"\ "popf\n\t"\ DF "\n\t"\ REP #OP size "\n\t"\ "cld\n\t"\ "pushf\n\t"\ - "popl %4\n\t"\ + "pop %4\n\t"\ : "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\ : "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\ - printf("%-10s ESI=%08x EDI=%08x EAX=%08x ECX=%08x EFL=%04x\n",\ + printf("%-10s ESI=" FMTLX " EDI=" FMTLX " EAX=" FMTLX " ECX=" FMTLX " EFL=%04x\n",\ REP #OP size, esi, edi, eax, ecx,\ - eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\ + (int)(eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)));\ } #define TEST_STRING(OP, REP)\ TEST_STRING1(OP, "b", "", REP);\ TEST_STRING1(OP, "w", "", REP);\ TEST_STRING1(OP, "l", "", REP);\ + X86_64_ONLY(TEST_STRING1(OP, "q", "", REP));\ TEST_STRING1(OP, "b", "std", REP);\ TEST_STRING1(OP, "w", "std", REP);\ - TEST_STRING1(OP, "l", "std", REP) + TEST_STRING1(OP, "l", "std", REP);\ + X86_64_ONLY(TEST_STRING1(OP, "q", "std", REP)) void test_string(void) { @@ -1169,6 +1370,7 @@ void test_string(void) TEST_STRING(cmps, "repnz "); } +#ifdef TEST_VM86 /* VM86 test */ static inline void set_bit(uint8_t *a, unsigned int bit) @@ -1299,9 +1501,10 @@ void test_vm86(void) printf("VM86 end\n"); munmap(vm86_mem, 0x110000); } +#endif /* exception tests */ -#ifndef REG_EAX +#if defined(__i386__) && !defined(REG_EAX) #define REG_EAX EAX #define REG_EBX EBX #define REG_ECX ECX @@ -1316,6 +1519,10 @@ void test_vm86(void) #define REG_ERR ERR #endif +#if defined(__x86_64__) +#define REG_EIP REG_RIP +#endif + jmp_buf jmp_env; int v1; int tab[2]; @@ -1330,23 +1537,22 @@ void sig_handler(int sig, siginfo_t *info, void *puc) (unsigned long)info->si_addr); printf("\n"); - printf("trapno=0x%02x err=0x%08x", - uc->uc_mcontext.gregs[REG_TRAPNO], - uc->uc_mcontext.gregs[REG_ERR]); - printf(" EIP=0x%08x", uc->uc_mcontext.gregs[REG_EIP]); + printf("trapno=" FMTLX " err=" FMTLX, + (long)uc->uc_mcontext.gregs[REG_TRAPNO], + (long)uc->uc_mcontext.gregs[REG_ERR]); + printf(" EIP=" FMTLX, (long)uc->uc_mcontext.gregs[REG_EIP]); printf("\n"); longjmp(jmp_env, 1); } void test_exceptions(void) { - struct modify_ldt_ldt_s ldt; struct sigaction act; volatile int val; act.sa_sigaction = sig_handler; sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; + act.sa_flags = SA_SIGINFO | SA_NODEFER; sigaction(SIGFPE, &act, NULL); sigaction(SIGILL, &act, NULL); sigaction(SIGSEGV, &act, NULL); @@ -1361,6 +1567,7 @@ void test_exceptions(void) v1 = 2 / v1; } +#if !defined(__x86_64__) printf("BOUND exception:\n"); if (setjmp(jmp_env) == 0) { /* bound exception */ @@ -1368,7 +1575,9 @@ void test_exceptions(void) tab[1] = 10; asm volatile ("bound %0, %1" : : "r" (11), "m" (tab[0])); } +#endif +#ifdef TEST_SEGS printf("segment exceptions:\n"); if (setjmp(jmp_env) == 0) { /* load an invalid segment */ @@ -1381,21 +1590,25 @@ void test_exceptions(void) asm volatile ("movl %0, %%ss" : : "r" (3)); } - ldt.entry_number = 1; - ldt.base_addr = (unsigned long)&seg_data1; - ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; - ldt.seg_32bit = 1; - ldt.contents = MODIFY_LDT_CONTENTS_DATA; - ldt.read_exec_only = 0; - ldt.limit_in_pages = 1; - ldt.seg_not_present = 1; - ldt.useable = 1; - modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - - if (setjmp(jmp_env) == 0) { - /* segment not present */ - asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); + { + struct modify_ldt_ldt_s ldt; + ldt.entry_number = 1; + ldt.base_addr = (unsigned long)&seg_data1; + ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; + ldt.seg_32bit = 1; + ldt.contents = MODIFY_LDT_CONTENTS_DATA; + ldt.read_exec_only = 0; + ldt.limit_in_pages = 1; + ldt.seg_not_present = 1; + ldt.useable = 1; + modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ + + if (setjmp(jmp_env) == 0) { + /* segment not present */ + asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); + } } +#endif /* test SEGV reporting */ printf("PF exception:\n"); @@ -1459,11 +1672,13 @@ void test_exceptions(void) asm volatile ("cli"); } +#if !defined(__x86_64__) printf("INTO exception:\n"); if (setjmp(jmp_env) == 0) { /* overflow exception */ asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff)); } +#endif printf("OUTB exception:\n"); if (setjmp(jmp_env) == 0) { @@ -1502,11 +1717,12 @@ void test_exceptions(void) printf("val=0x%x\n", val); } +#if !defined(__x86_64__) /* specific precise single step test */ void sig_trap_handler(int sig, siginfo_t *info, void *puc) { struct ucontext *uc = puc; - printf("EIP=0x%08x\n", uc->uc_mcontext.gregs[REG_EIP]); + printf("EIP=" FMTLX "\n", (long)uc->uc_mcontext.gregs[REG_EIP]); } const uint8_t sstep_buf1[4] = { 1, 2, 3, 4}; @@ -1627,12 +1843,21 @@ void test_self_modifying_code(void) printf("smc_code2(%d) = %d\n", i, smc_code2(i)); } } +#endif -int enter_stack[4096]; +long enter_stack[4096]; + +#if defined(__x86_64__) +#define RSP "%%rsp" +#define RBP "%%rbp" +#else +#define RSP "%%esp" +#define RBP "%%ebp" +#endif #define TEST_ENTER(size, stack_type, level)\ {\ - int esp_save, esp_val, ebp_val, ebp_save, i;\ + long esp_save, esp_val, ebp_val, ebp_save, i;\ stack_type *ptr, *stack_end, *stack_ptr;\ memset(enter_stack, 0, sizeof(enter_stack));\ stack_end = stack_ptr = (stack_type *)(enter_stack + 4096);\ @@ -1640,15 +1865,15 @@ int enter_stack[4096]; for(i=1;i<=32;i++)\ *--stack_ptr = i;\ esp_val = (long)stack_ptr;\ - asm("movl %%esp, %[esp_save]\n"\ - "movl %%ebp, %[ebp_save]\n"\ - "movl %[esp_val], %%esp\n"\ - "movl %[ebp_val], %%ebp\n"\ - "enter" size " $12, $" #level "\n"\ - "movl %%esp, %[esp_val]\n"\ - "movl %%ebp, %[ebp_val]\n"\ - "movl %[esp_save], %%esp\n"\ - "movl %[ebp_save], %%ebp\n"\ + asm("mov " RSP ", %[esp_save]\n"\ + "mov " RBP ", %[ebp_save]\n"\ + "mov %[esp_val], " RSP "\n"\ + "mov %[ebp_val], " RBP "\n"\ + "enter" size " $8, $" #level "\n"\ + "mov " RSP ", %[esp_val]\n"\ + "mov " RBP ", %[ebp_val]\n"\ + "mov %[esp_save], " RSP "\n"\ + "mov %[ebp_save], " RBP "\n"\ : [esp_save] "=r" (esp_save),\ [ebp_save] "=r" (ebp_save),\ [esp_val] "=r" (esp_val),\ @@ -1656,18 +1881,25 @@ int enter_stack[4096]; : "[esp_val]" (esp_val),\ "[ebp_val]" (ebp_val));\ printf("level=%d:\n", level);\ - printf("esp_val=0x%08lx\n", esp_val - (long)stack_end);\ - printf("ebp_val=0x%08lx\n", ebp_val - (long)stack_end);\ + printf("esp_val=" FMTLX "\n", esp_val - (long)stack_end);\ + printf("ebp_val=" FMTLX "\n", ebp_val - (long)stack_end);\ for(ptr = (stack_type *)esp_val; ptr < stack_end; ptr++)\ - printf("%08x\n", ptr[0]);\ + printf(FMTLX "\n", (long)ptr[0]);\ } static void test_enter(void) { +#if defined(__x86_64__) + TEST_ENTER("q", uint64_t, 0); + TEST_ENTER("q", uint64_t, 1); + TEST_ENTER("q", uint64_t, 2); + TEST_ENTER("q", uint64_t, 31); +#else TEST_ENTER("l", uint32_t, 0); TEST_ENTER("l", uint32_t, 1); TEST_ENTER("l", uint32_t, 2); TEST_ENTER("l", uint32_t, 31); +#endif TEST_ENTER("w", uint16_t, 0); TEST_ENTER("w", uint16_t, 1); @@ -1698,7 +1930,7 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { #define SSE_OP(op)\ {\ asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ - printf("%-9s: a=%016llx%016llx b=%016llx%016llx r=%016llx%016llx\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ b.q[1], b.q[0],\ @@ -1724,7 +1956,7 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { a.q[0] = test_values[2*i][0];\ b.q[0] = test_values[2*i+1][0];\ asm volatile (#op " %2, %0" : "=y" (r.q[0]) : "0" (a.q[0]), "y" (b.q[0]));\ - printf("%-9s: a=%016llx b=%016llx r=%016llx\n",\ + printf("%-9s: a=" FMT64X " b=" FMT64X " r=" FMT64X "\n",\ #op,\ a.q[0],\ b.q[0],\ @@ -1740,7 +1972,7 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { b.q[0] = test_values[1][0];\ b.q[1] = test_values[1][1];\ asm volatile (#op " $" #ib ", %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ - printf("%-9s: a=%016llx%016llx b=%016llx%016llx ib=%02x r=%016llx%016llx\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ b.q[1], b.q[0],\ @@ -1755,7 +1987,7 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { a.q[0] = test_values[2*i][0];\ a.q[1] = test_values[2*i][1];\ asm volatile (#op " $" #ib ", %1, %0" : "=x" (r.dq) : "x" (a.dq));\ - printf("%-9s: a=%016llx%016llx ib=%02x r=%016llx%016llx\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ ib,\ @@ -1770,7 +2002,7 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { a.q[0] = test_values[2*i][0];\ a.q[1] = test_values[2*i][1];\ asm volatile (#op " $" #ib ", %0" : "=x" (r.dq) : "0" (a.dq));\ - printf("%-9s: a=%016llx%016llx ib=%02x r=%016llx%016llx\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " ib=%02x r=" FMT64X "" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ ib,\ @@ -1788,7 +2020,7 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { b.q[0] = ib;\ b.q[1] = 0;\ asm volatile (#op " %2, %0" : "=x" (r.dq) : "0" (a.dq), "x" (b.dq));\ - printf("%-9s: a=%016llx%016llx b=%016llx%016llx r=%016llx%016llx\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ b.q[1], b.q[0],\ @@ -1803,7 +2035,7 @@ static uint64_t __attribute__((aligned(16))) test_values[4][2] = { a.q[0] = test_values[2*i][0];\ a.q[1] = test_values[2*i][1];\ asm volatile (#op " %1, %0" : "=r" (reg) : "x" (a.dq));\ - printf("%-9s: a=%016llx%016llx r=%08x\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " r=%08x\n",\ #op,\ a.q[1], a.q[0],\ reg);\ @@ -1845,7 +2077,7 @@ void test_sse_comi(double a1, double b1) #define CVT_OP_XMM(op)\ {\ asm volatile (#op " %1, %0" : "=x" (r.dq) : "x" (a.dq));\ - printf("%-9s: a=%016llx%016llx r=%016llx%016llx\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ r.q[1], r.q[0]);\ @@ -1854,7 +2086,7 @@ void test_sse_comi(double a1, double b1) #define CVT_OP_XMM2MMX(op)\ {\ asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq));\ - printf("%-9s: a=%016llx%016llx r=%016llx\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ r.q[0]);\ @@ -1863,7 +2095,7 @@ void test_sse_comi(double a1, double b1) #define CVT_OP_MMX2XMM(op)\ {\ asm volatile (#op " %1, %0" : "=x" (r.dq) : "y" (a.q[0]));\ - printf("%-9s: a=%016llx r=%016llx%016llx\n",\ + printf("%-9s: a=" FMT64X " r=" FMT64X "" FMT64X "\n",\ #op,\ a.q[0],\ r.q[1], r.q[0]);\ @@ -1872,7 +2104,7 @@ void test_sse_comi(double a1, double b1) #define CVT_OP_REG2XMM(op)\ {\ asm volatile (#op " %1, %0" : "=x" (r.dq) : "r" (a.l[0]));\ - printf("%-9s: a=%08x r=%016llx%016llx\n",\ + printf("%-9s: a=%08x r=" FMT64X "" FMT64X "\n",\ #op,\ a.l[0],\ r.q[1], r.q[0]);\ @@ -1881,7 +2113,7 @@ void test_sse_comi(double a1, double b1) #define CVT_OP_XMM2REG(op)\ {\ asm volatile (#op " %1, %0" : "=r" (r.l[0]) : "x" (a.dq));\ - printf("%-9s: a=%016llx%016llx r=%08x\n",\ + printf("%-9s: a=" FMT64X "" FMT64X " r=%08x\n",\ #op,\ a.q[1], a.q[0],\ r.l[0]);\ @@ -1912,7 +2144,7 @@ void test_fxsave(void) { struct fpxstate *fp = &fpx_state; struct fpxstate *fp2 = &fpx_state2; - int i; + int i, nb_xmm; XMMReg a, b; a.q[0] = test_values[0][0]; a.q[1] = test_values[0][1]; @@ -1921,6 +2153,9 @@ void test_fxsave(void) asm("movdqa %2, %%xmm0\n" "movdqa %3, %%xmm7\n" +#if defined(__x86_64__) + "movdqa %2, %%xmm15\n" +#endif " fld1\n" " fldpi\n" " fldln2\n" @@ -1934,14 +2169,19 @@ void test_fxsave(void) printf("fpus=%04x\n", fp->fpus); printf("fptag=%04x\n", fp->fptag); for(i = 0; i < 3; i++) { - printf("ST%d: %016llx %04x\n", + printf("ST%d: " FMT64X " %04x\n", i, *(uint64_t *)&fp->fpregs1[i * 16], *(uint16_t *)&fp->fpregs1[i * 16 + 8]); } printf("mxcsr=%08x\n", fp->mxcsr & 0x1f80); - for(i = 0; i < 8; i++) { - printf("xmm%d: %016llx%016llx\n", +#if defined(__x86_64__) + nb_xmm = 16; +#else + nb_xmm = 8; +#endif + for(i = 0; i < nb_xmm; i++) { + printf("xmm%d: " FMT64X "" FMT64X "\n", i, *(uint64_t *)&fp->xmm_regs[i * 16], *(uint64_t *)&fp->xmm_regs[i * 16 + 8]); @@ -2005,10 +2245,10 @@ void test_sse(void) MMX_OP2(pavgw); asm volatile ("pinsrw $1, %1, %0" : "=y" (r.q[0]) : "r" (0x12345678)); - printf("%-9s: r=%016llx\n", "pinsrw", r.q[0]); + printf("%-9s: r=" FMT64X "\n", "pinsrw", r.q[0]); asm volatile ("pinsrw $5, %1, %0" : "=x" (r.dq) : "r" (0x12345678)); - printf("%-9s: r=%016llx%016llx\n", "pinsrw", r.q[1], r.q[0]); + printf("%-9s: r=" FMT64X "" FMT64X "\n", "pinsrw", r.q[1], r.q[0]); a.q[0] = test_values[0][0]; a.q[1] = test_values[0][1]; @@ -2035,7 +2275,7 @@ void test_sse(void) asm volatile("maskmovq %1, %0" : : "y" (a.q[0]), "y" (b.q[0]), "D" (&r) : "memory"); - printf("%-9s: r=%016llx a=%016llx b=%016llx\n", + printf("%-9s: r=" FMT64X " a=" FMT64X " b=" FMT64X "\n", "maskmov", r.q[0], a.q[0], @@ -2043,7 +2283,7 @@ void test_sse(void) asm volatile("maskmovdqu %1, %0" : : "x" (a.dq), "x" (b.dq), "D" (&r) : "memory"); - printf("%-9s: r=%016llx%016llx a=%016llx%016llx b=%016llx%016llx\n", + printf("%-9s: r=" FMT64X "" FMT64X " a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X "\n", "maskmov", r.q[1], r.q[0], a.q[1], a.q[0], @@ -2205,15 +2445,17 @@ void test_sse(void) #endif -static void *call_end __init_call = NULL; +extern void *__start_initcall; +extern void *__stop_initcall; + int main(int argc, char **argv) { void **ptr; void (*func)(void); - ptr = &call_start + 1; - while (*ptr != NULL) { + ptr = &__start_initcall; + while (ptr != &__stop_initcall) { func = *ptr++; func(); } @@ -2221,19 +2463,25 @@ int main(int argc, char **argv) test_mul(); test_jcc(); test_floats(); +#if !defined(__x86_64__) test_bcd(); +#endif test_xchg(); test_string(); test_misc(); test_lea(); +#ifdef TEST_SEGS test_segs(); test_code16(); +#endif #ifdef TEST_VM86 test_vm86(); #endif test_exceptions(); +#if !defined(__x86_64__) test_self_modifying_code(); test_single_step(); +#endif test_enter(); #ifdef TEST_SSE test_sse(); diff --git a/tests/test-i386.h b/tests/test-i386.h index 7d1812c88..75106b8ce 100644 --- a/tests/test-i386.h +++ b/tests/test-i386.h @@ -1,95 +1,116 @@ #define exec_op glue(exec_, OP) +#define exec_opq glue(glue(exec_, OP), q) #define exec_opl glue(glue(exec_, OP), l) #define exec_opw glue(glue(exec_, OP), w) #define exec_opb glue(glue(exec_, OP), b) -#define EXECOP2(size, res, s1, flags) \ +#define EXECOP2(size, rsize, res, s1, flags) \ asm ("push %4\n\t"\ "popf\n\t"\ - stringify(OP) size " %" size "2, %" size "0\n\t" \ + stringify(OP) size " %" rsize "2, %" rsize "0\n\t" \ "pushf\n\t"\ - "popl %1\n\t"\ + "pop %1\n\t"\ : "=q" (res), "=g" (flags)\ - : "q" (s1), "0" (res), "1" (flags)); + : "q" (s1), "0" (res), "1" (flags)); \ + printf("%-10s A=" FMTLX " B=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", \ + stringify(OP) size, s0, s1, res, iflags, flags & CC_MASK); -#define EXECOP1(size, res, flags) \ +#define EXECOP1(size, rsize, res, flags) \ asm ("push %3\n\t"\ "popf\n\t"\ - stringify(OP) size " %" size "0\n\t" \ + stringify(OP) size " %" rsize "0\n\t" \ "pushf\n\t"\ - "popl %1\n\t"\ + "pop %1\n\t"\ : "=q" (res), "=g" (flags)\ - : "0" (res), "1" (flags)); + : "0" (res), "1" (flags)); \ + printf("%-10s A=" FMTLX " R=" FMTLX " CCIN=%04lx CC=%04lx\n", \ + stringify(OP) size, s0, res, iflags, flags & CC_MASK); #ifdef OP1 -void exec_opl(int s0, int s1, int iflags) +#if defined(__x86_64__) +void exec_opq(long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECOP1("", res, flags); - printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n", - stringify(OP) "l", s0, res, iflags, flags & CC_MASK); + EXECOP1("q", "", res, flags); } +#endif -void exec_opw(int s0, int s1, int iflags) +void exec_opl(long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECOP1("w", res, flags); - printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n", - stringify(OP) "w", s0, res, iflags, flags & CC_MASK); + EXECOP1("l", "k", res, flags); } -void exec_opb(int s0, int s1, int iflags) +void exec_opw(long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECOP1("b", res, flags); - printf("%-10s A=%08x R=%08x CCIN=%04x CC=%04x\n", - stringify(OP) "b", s0, res, iflags, flags & CC_MASK); + EXECOP1("w", "w", res, flags); +} + +void exec_opb(long s0, long s1, long iflags) +{ + long res, flags; + res = s0; + flags = iflags; + EXECOP1("b", "b", res, flags); } #else -void exec_opl(int s0, int s1, int iflags) +#if defined(__x86_64__) +void exec_opq(long s0, long s1, long iflags) +{ + long res, flags; + res = s0; + flags = iflags; + EXECOP2("q", "", res, s1, flags); +} +#endif + +void exec_opl(long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECOP2("", res, s1, flags); - printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", - stringify(OP) "l", s0, s1, res, iflags, flags & CC_MASK); + EXECOP2("l", "k", res, s1, flags); } -void exec_opw(int s0, int s1, int iflags) +void exec_opw(long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECOP2("w", res, s1, flags); - printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", - stringify(OP) "w", s0, s1, res, iflags, flags & CC_MASK); + EXECOP2("w", "w", res, s1, flags); } -void exec_opb(int s0, int s1, int iflags) +void exec_opb(long s0, long s1, long iflags) { - int res, flags; + long res, flags; res = s0; flags = iflags; - EXECOP2("b", res, s1, flags); - printf("%-10s A=%08x B=%08x R=%08x CCIN=%04x CC=%04x\n", - stringify(OP) "b", s0, s1, res, iflags, flags & CC_MASK); + EXECOP2("b", "b", res, s1, flags); } #endif -void exec_op(int s0, int s1) +void exec_op(long s0, long s1) { + s0 = i2l(s0); + s1 = i2l(s1); +#if defined(__x86_64__) + exec_opq(s0, s1, 0); +#endif exec_opl(s0, s1, 0); exec_opw(s0, s1, 0); exec_opb(s0, s1, 0); #ifdef OP_CC +#if defined(__x86_64__) + exec_opq(s0, s1, CC_C); +#endif exec_opl(s0, s1, CC_C); exec_opw(s0, s1, CC_C); exec_opb(s0, s1, CC_C); -- cgit v1.2.3 From da4dbf742d4689313df16c0468f0aeadb6853872 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 2 Mar 2005 22:22:43 +0000 Subject: cocoa tiny fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1322 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 4 +++- vl.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cocoa.m b/cocoa.m index ade7f61d8..38b4760f9 100644 --- a/cocoa.m +++ b/cocoa.m @@ -34,9 +34,11 @@ x simple graphical prompt to demo - better graphical prompt */ -#include "vl.h" + #import +#include "vl.h" + NSWindow *window = NULL; NSQuickDrawView *qd_view = NULL; diff --git a/vl.h b/vl.h index 3fd7ce9ad..c8404e10e 100644 --- a/vl.h +++ b/vl.h @@ -572,6 +572,9 @@ void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, /* sdl.c */ void sdl_display_init(DisplayState *ds, int full_screen); +/* cocoa.m */ +void cocoa_display_init(DisplayState *ds, int full_screen); + /* ide.c */ #define MAX_DISKS 4 -- cgit v1.2.3 From d057099aa813f3a8a7766c2b352d7da90754caf2 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Mar 2005 01:13:19 +0000 Subject: cmov fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1323 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 6afb72747..d4e0c4888 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -379,7 +379,7 @@ X86_64_ONLY(\ "cmov" JCC "q %3, %0\n\t"\ : "=r" (res)\ : "r" (v1), "r" (v2), "m" (val), "0" (res));\ - printf("%-10s R=" FMTLX "\n", "cmov" JCC "l", res);)\ + printf("%-10s R=" FMTLX "\n", "cmov" JCC "q", res);)\ asm("cmpl %2, %1\n\t"\ "cmov" JCC "l %k3, %k0\n\t"\ : "=r" (res)\ -- cgit v1.2.3 From 313132138a91f90f270510a06db549c3fd7466bf Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Mar 2005 01:14:55 +0000 Subject: x86_64 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1324 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 13 +++++++------ target-i386/op.c | 4 ++-- target-i386/ops_template_mem.h | 4 ++-- target-i386/translate.c | 30 ++++++++++++++++++++++-------- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index b727e93d6..53b85d3aa 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1012,7 +1012,8 @@ void helper_sysret(int dflag) DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); - load_eflags((uint32_t)(env->regs[11]), 0xffffffff); + load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | + IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); cpu_x86_set_cpl(env, 3); } else { cpu_x86_load_seg_cache(env, R_CS, selector | 3, @@ -1209,7 +1210,7 @@ void helper_divl_EAX_T0(void) unsigned int den, q, r; uint64_t num; - num = EAX | ((uint64_t)EDX << 32); + num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); den = T0; if (den == 0) { raise_exception(EXCP00_DIVZ); @@ -1229,7 +1230,7 @@ void helper_idivl_EAX_T0(void) int den, q, r; int64_t num; - num = EAX | ((uint64_t)EDX << 32); + num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); den = T0; if (den == 0) { raise_exception(EXCP00_DIVZ); @@ -3003,7 +3004,7 @@ void helper_fxrstor(target_ulong ptr, int data64) } if (env->cr[4] & CR4_OSFXSR_MASK) { - /* XXX: finish it, endianness */ + /* XXX: finish it */ env->mxcsr = ldl(ptr + 0x18); //ldl(ptr + 0x1c); nb_xmm_regs = 8 << data64; @@ -3170,7 +3171,7 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) } } -static void idiv64(uint64_t *plow, uint64_t *phigh, uint64_t b) +static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) { int sa, sb; sa = ((int64_t)*phigh < 0); @@ -3182,7 +3183,7 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, uint64_t b) div64(plow, phigh, b); if (sa ^ sb) *plow = - *plow; - if (sb) + if (sa) *phigh = - *phigh; } diff --git a/target-i386/op.c b/target-i386/op.c index fed0fca93..dd9d7bad1 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -286,8 +286,8 @@ void OPPROTO op_imull_EAX_T0(void) { int64_t res; res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0); - EAX = res; - EDX = res >> 32; + EAX = (uint32_t)(res); + EDX = (uint32_t)(res >> 32); CC_DST = res; CC_SRC = (res != (int32_t)res); } diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h index 00454e6d0..a999e2d44 100644 --- a/target-i386/ops_template_mem.h +++ b/target-i386/ops_template_mem.h @@ -160,7 +160,7 @@ void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) eflags = cc_table[CC_OP].compute_all(); T0 &= DATA_MASK; src = T0; - res = (T0 << count) | ((eflags & CC_C) << (count - 1)); + res = (T0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1)); if (count > 1) res |= T0 >> (DATA_BITS + 1 - count); T0 = res; @@ -191,7 +191,7 @@ void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) eflags = cc_table[CC_OP].compute_all(); T0 &= DATA_MASK; src = T0; - res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); + res = (T0 >> count) | ((target_ulong)(eflags & CC_C) << (DATA_BITS - count)); if (count > 1) res |= T0 << (DATA_BITS + 1 - count); T0 = res; diff --git a/target-i386/translate.c b/target-i386/translate.c index 093723944..ad5acc9c4 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -600,12 +600,14 @@ static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3 * 4][8] = { {\ gen_op_shldw ## SUFFIX ## _T0_T1_ ## op ## _cc,\ gen_op_shrdw ## SUFFIX ## _T0_T1_ ## op ## _cc,\ - },\ + },\ {\ gen_op_shldl ## SUFFIX ## _T0_T1_ ## op ## _cc,\ gen_op_shrdl ## SUFFIX ## _T0_T1_ ## op ## _cc,\ },\ {\ +X86_64_DEF(gen_op_shldq ## SUFFIX ## _T0_T1_ ## op ## _cc,\ + gen_op_shrdq ## SUFFIX ## _T0_T1_ ## op ## _cc,)\ }, static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[4][2] = { @@ -2723,14 +2725,14 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) sse_op2(op2_offset, op1_offset); break; case 0x050: /* movmskps */ - gen_op_movmskps(offsetof(CPUX86State,xmm_regs[reg])); rm = (modrm & 7) | REX_B(s); - gen_op_mov_reg_T0[OT_LONG][rm](); + gen_op_movmskps(offsetof(CPUX86State,xmm_regs[rm])); + gen_op_mov_reg_T0[OT_LONG][reg](); break; case 0x150: /* movmskpd */ - gen_op_movmskpd(offsetof(CPUX86State,xmm_regs[reg])); rm = (modrm & 7) | REX_B(s); - gen_op_mov_reg_T0[OT_LONG][rm](); + gen_op_movmskpd(offsetof(CPUX86State,xmm_regs[rm])); + gen_op_mov_reg_T0[OT_LONG][reg](); break; case 0x02a: /* cvtpi2ps */ case 0x12a: /* cvtpi2pd */ @@ -2795,10 +2797,22 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) case 0x22d: /* cvtss2si */ case 0x32d: /* cvtsd2si */ ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; - op1_offset = offsetof(CPUX86State,xmm_regs[reg]); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if ((b >> 8) & 1) { + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_t0.XMM_Q(0))); + } else { + gen_op_ld_T0_A0[OT_LONG + s->mem_index](); + gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0))); + } + op2_offset = offsetof(CPUX86State,xmm_t0); + } else { + rm = (modrm & 7) | REX_B(s); + op2_offset = offsetof(CPUX86State,xmm_regs[rm]); + } sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 + - (b & 1) * 4](op1_offset); - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + (b & 1) * 4](op2_offset); + gen_op_mov_reg_T0[ot][reg](); break; case 0xc4: /* pinsrw */ case 0x1c4: -- cgit v1.2.3 From b756921ad18c8d293da634ff3b4e950ec8ae3f80 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 09:43:05 +0000 Subject: sparc update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1325 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 02780a9cd..106ecf4cd 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -42,6 +42,7 @@ For system emulation, the following hardware targets are supported: @item PC (x86 processor) @item PREP (PowerPC processor) @item PowerMac (PowerPC processor, in progress) +@item Sun4m (Sparc processor, in progress) @end itemize For user emulation, x86, PowerPC, ARM, and SPARC CPUs are supported. @@ -1017,6 +1018,9 @@ Slave I/O: timers, interrupt controllers, Zilog serial ports QEMU uses the Proll, a PROM replacement available at @url{http://people.redhat.com/zaitcev/linux/}. +A sample Linux kernel and ram disk image are available on the QEMU web +site. + @chapter QEMU User space emulator invocation @section Quick Start -- cgit v1.2.3 From 6f7e9aec5eb5bdfa57a9e458e391b785c283a007 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 09:43:36 +0000 Subject: sparc fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1326 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- TODO | 1 - hw/esp.c | 192 +++++ hw/fdc.c | 37 +- hw/sun4m.c | 110 ++- hw/tcx.c | 129 +++- pc-bios/proll.elf | Bin 133338 -> 41236 bytes pc-bios/proll.patch | 1919 ++++++++++++++++++++++++++++++++-------------- target-sparc/helper.c | 18 +- target-sparc/op_helper.c | 4 +- vl.c | 10 +- vl.h | 5 +- 12 files changed, 1751 insertions(+), 676 deletions(-) create mode 100644 hw/esp.c diff --git a/Makefile.target b/Makefile.target index 5c82e38a6..68563299e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -338,7 +338,7 @@ 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 mixeng.o endif ifeq ($(TARGET_BASE_ARCH), sparc) -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o esp.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/TODO b/TODO index cd3895054..088c26c69 100644 --- a/TODO +++ b/TODO @@ -3,7 +3,6 @@ short term: - debug option in 'configure' script + disable -fomit-frame-pointer - Precise VGA timings for old games/demos (malc patch) - merge PIC spurious interrupt patch -- merge VNC keyboard patch - merge Solaris patch - warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?) - config file (at least for windows/Mac OS X) diff --git a/hw/esp.c b/hw/esp.c new file mode 100644 index 000000000..2456c345f --- /dev/null +++ b/hw/esp.c @@ -0,0 +1,192 @@ +/* + * QEMU ESP emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* debug ESP card */ +#define DEBUG_ESP + +#ifdef DEBUG_ESP +#define DPRINTF(fmt, args...) \ +do { printf("ESP: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +#define ESPDMA_REGS 4 +#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) +#define ESP_MAXREG 0x3f + +typedef struct ESPState { + BlockDriverState **bd; + uint8_t regs[ESP_MAXREG]; + int irq; + uint32_t espdmaregs[ESPDMA_REGS]; +} ESPState; + +static void esp_reset(void *opaque) +{ + ESPState *s = opaque; + memset(s->regs, 0, ESP_MAXREG); + s->regs[0x0e] = 0x4; // Indicate fas100a + memset(s->espdmaregs, 0, ESPDMA_REGS * 4); +} + +static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) +{ + ESPState *s = opaque; + uint32_t saddr; + + saddr = (addr & ESP_MAXREG) >> 2; + switch (saddr) { + default: + break; + } + DPRINTF("esp: read reg[%d]: 0x%2.2x\n", saddr, s->regs[saddr]); + return s->regs[saddr]; +} + +static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + ESPState *s = opaque; + uint32_t saddr; + + saddr = (addr & ESP_MAXREG) >> 2; + DPRINTF("esp: write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->regs[saddr], val); + switch (saddr) { + case 3: + // Command + switch(val & 0x7f) { + case 0: + DPRINTF("esp: NOP (%2.2x)\n", val); + break; + case 2: + DPRINTF("esp: Chip reset (%2.2x)\n", val); + esp_reset(s); + break; + case 3: + DPRINTF("esp: Bus reset (%2.2x)\n", val); + break; + case 0x1a: + DPRINTF("esp: Set ATN (%2.2x)\n", val); + break; + case 0x42: + DPRINTF("esp: Select with ATN (%2.2x)\n", val); + s->regs[4] = 0x1a; // Status: TCNT | TDONE | CMD + s->regs[5] = 0x20; // Intr: Disconnect, nobody there + s->regs[6] = 0x4; // Seq: Cmd done + pic_set_irq(s->irq, 1); + break; + } + break; + case 4 ... 7: + case 9 ... 0xf: + break; + default: + s->regs[saddr] = val; + break; + } +} + +static CPUReadMemoryFunc *esp_mem_read[3] = { + esp_mem_readb, + esp_mem_readb, + esp_mem_readb, +}; + +static CPUWriteMemoryFunc *esp_mem_write[3] = { + esp_mem_writeb, + esp_mem_writeb, + esp_mem_writeb, +}; + +static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) +{ + ESPState *s = opaque; + uint32_t saddr; + + saddr = (addr & ESPDMA_MAXADDR) >> 2; + return s->espdmaregs[saddr]; +} + +static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + ESPState *s = opaque; + uint32_t saddr; + + saddr = (addr & ESPDMA_MAXADDR) >> 2; + s->espdmaregs[saddr] = val; +} + +static CPUReadMemoryFunc *espdma_mem_read[3] = { + espdma_mem_readl, + espdma_mem_readl, + espdma_mem_readl, +}; + +static CPUWriteMemoryFunc *espdma_mem_write[3] = { + espdma_mem_writel, + espdma_mem_writel, + espdma_mem_writel, +}; + +static void esp_save(QEMUFile *f, void *opaque) +{ + ESPState *s = opaque; + +} + +static int esp_load(QEMUFile *f, void *opaque, int version_id) +{ + ESPState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + return 0; +} + +void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr) +{ + ESPState *s; + int esp_io_memory, espdma_io_memory; + + s = qemu_mallocz(sizeof(ESPState)); + if (!s) + return; + + s->bd = bd; + s->irq = irq; + + esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); + cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory); + + espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s); + cpu_register_physical_memory(espdaddr, 16, espdma_io_memory); + + esp_reset(s); + + register_savevm("esp", espaddr, 1, esp_save, esp_load, s); + qemu_register_reset(esp_reset, s); +} + diff --git a/hw/fdc.c b/hw/fdc.c index fc6b50257..3890ace12 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -94,21 +94,6 @@ typedef struct fdrive_t { uint8_t ro; /* Is read-only */ } fdrive_t; -#ifdef TARGET_SPARC -/* XXX: suppress those hacks */ -#define DMA_read_memory(a,b,c,d) -#define DMA_write_memory(a,b,c,d) -void DMA_register_channel (int nchan, - DMA_transfer_handler transfer_handler, - void *opaque) -{ -} -#define DMA_hold_DREQ(a) -#define DMA_release_DREQ(a) -#define DMA_get_channel_mode(a) (0) -#define DMA_schedule(a) -#endif - static void fd_init (fdrive_t *drv, BlockDriverState *bs) { /* Drive */ @@ -423,6 +408,12 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) uint32_t retval; switch (reg & 0x07) { +#ifdef TARGET_SPARC + case 0x00: + // Identify to Linux as S82078B + retval = fdctrl_read_statusB(fdctrl); + break; +#endif case 0x01: retval = fdctrl_read_statusB(fdctrl); break; @@ -577,6 +568,14 @@ static void fdctrl_reset_irq (fdctrl_t *fdctrl) static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) { +#ifdef TARGET_SPARC + // Sparc mutation + if (!fdctrl->dma_en) { + fdctrl->state &= ~FD_CTRL_BUSY; + fdctrl->int_status = status; + return; + } +#endif if (~(fdctrl->state & FD_CTRL_INTR)) { pic_set_irq(fdctrl->irq_lvl, 1); fdctrl->state |= FD_CTRL_INTR; @@ -980,11 +979,11 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, len = dma_len - fdctrl->data_pos; if (len + rel_pos > FD_SECTOR_LEN) len = FD_SECTOR_LEN - rel_pos; - FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x " - "(%d-0x%08x 0x%08x)\n", len, size, fdctrl->data_pos, + FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x " + "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos, fdctrl->data_len, fdctrl->cur_drv, cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv), - fd_sector(cur_drv) * 512, addr); + fd_sector(cur_drv) * 512); if (fdctrl->data_dir != FD_DIR_WRITE || len < FD_SECTOR_LEN || rel_pos != 0) { /* READ & SCAN commands and realign to a sector for WRITE */ @@ -1045,7 +1044,7 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv), - fdctrl->data_pos - size); + fdctrl->data_pos - len); /* XXX: cur_drv->sect >= cur_drv->last_sect should be an error in fact */ if (cur_drv->sect >= cur_drv->last_sect || diff --git a/hw/sun4m.c b/hw/sun4m.c index 0af062d96..b186b23f1 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -36,7 +36,10 @@ // IRQs are not PIL ones, but master interrupt controller register // bits #define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ -#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */ +#define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */ +#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */ +#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ +#define PHYS_JJ_ESP_IRQ 18 #define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */ #define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */ #define PHYS_JJ_LE_IRQ 16 @@ -50,7 +53,6 @@ #define PHYS_JJ_MS_KBD_IRQ 14 #define PHYS_JJ_SER 0x71100000 /* Serial */ #define PHYS_JJ_SER_IRQ 15 -#define PHYS_JJ_SCSI_IRQ 18 #define PHYS_JJ_FDC 0x71400000 /* Floppy */ #define PHYS_JJ_FLOPPY_IRQ 22 @@ -61,32 +63,86 @@ uint64_t cpu_get_tsc() return qemu_get_clock(vm_clock); } -void DMA_run() {} +int DMA_get_channel_mode (int nchan) +{ + return 0; +} +int DMA_read_memory (int nchan, void *buf, int pos, int size) +{ + return 0; +} +int DMA_write_memory (int nchan, void *buf, int pos, int size) +{ + return 0; +} +void DMA_hold_DREQ (int nchan) {} +void DMA_release_DREQ (int nchan) {} +void DMA_schedule(int nchan) {} +void DMA_run (void) {} +void DMA_init (int high_page_enable) {} +void DMA_register_channel (int nchan, + DMA_transfer_handler transfer_handler, + void *opaque) +{ +} + +static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value) +{ + m48t08_write(nvram, addr++, (value >> 8) & 0xff); + m48t08_write(nvram, addr++, value & 0xff); +} + +static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value) +{ + m48t08_write(nvram, addr++, value >> 24); + m48t08_write(nvram, addr++, (value >> 16) & 0xff); + m48t08_write(nvram, addr++, (value >> 8) & 0xff); + m48t08_write(nvram, addr++, value & 0xff); +} + +static void nvram_set_string (m48t08_t *nvram, uint32_t addr, + const unsigned char *str, uint32_t max) +{ + unsigned int i; + + for (i = 0; i < max && str[i] != '\0'; i++) { + m48t08_write(nvram, addr + i, str[i]); + } + m48t08_write(nvram, addr + max - 1, '\0'); +} static m48t08_t *nvram; -static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline) +extern int nographic; + +static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline, + int boot_device, uint32_t RAM_size, + uint32_t kernel_size, + int width, int height, int depth) { unsigned char tmp = 0; int i, j; - i = 0x40; + // Try to match PPC NVRAM + nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); + nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */ + // NVRAM_size, arch not applicable + m48t08_write(nvram, 0x2F, nographic & 0xff); + nvram_set_lword(nvram, 0x30, RAM_size); + m48t08_write(nvram, 0x34, boot_device & 0xff); + nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR); + nvram_set_lword(nvram, 0x3C, kernel_size); if (cmdline) { - uint32_t cmdline_len; - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - m48t08_write(nvram, i++, CMDLINE_ADDR >> 24); - m48t08_write(nvram, i++, (CMDLINE_ADDR >> 16) & 0xff); - m48t08_write(nvram, i++, (CMDLINE_ADDR >> 8) & 0xff); - m48t08_write(nvram, i++, CMDLINE_ADDR & 0xff); - - cmdline_len = strlen(cmdline); - m48t08_write(nvram, i++, cmdline_len >> 24); - m48t08_write(nvram, i++, (cmdline_len >> 16) & 0xff); - m48t08_write(nvram, i++, (cmdline_len >> 8) & 0xff); - m48t08_write(nvram, i++, cmdline_len & 0xff); + nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); + nvram_set_lword(nvram, 0x44, strlen(cmdline)); } + // initrd_image, initrd_size passed differently + nvram_set_word(nvram, 0x54, width); + nvram_set_word(nvram, 0x56, height); + nvram_set_word(nvram, 0x58, depth); + // Sun4m specific use i = 0x1fd8; m48t08_write(nvram, i++, 0x01); m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */ @@ -155,7 +211,7 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, char buf[1024]; int ret, linux_boot; unsigned int i; - unsigned long vram_size = 0x100000, prom_offset, initrd_size; + long vram_size = 0x100000, prom_offset, initrd_size, kernel_size; linux_boot = (kernel_filename != NULL); @@ -164,14 +220,14 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, iommu = iommu_init(PHYS_JJ_IOMMU); slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); - tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size); + tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline); slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]); fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); + esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA); prom_offset = ram_size + vram_size; @@ -189,13 +245,14 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); + kernel_size = 0; if (linux_boot) { - ret = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (ret < 0) - ret = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (ret < 0) - ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (ret < 0) { + kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) + kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) + kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); @@ -222,4 +279,5 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, } } } + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth); } diff --git a/hw/tcx.c b/hw/tcx.c index 6c4df7c89..c0fddf31d 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -1,7 +1,7 @@ /* - * QEMU Sun4m System Emulator + * QEMU TCX Frame buffer * - * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,29 +25,16 @@ #define MAXX 1024 #define MAXY 768 -/* - * Proll uses only small part of display, we need to switch to full - * display when we get linux framebuffer console or X11 running. For - * now it's just slower and awkward. -*/ -#if 1 -#define XSZ (8*80) -#define YSZ (24*11) -#define XOFF (MAXX-XSZ) -#define YOFF (MAXY-YSZ) -#else -#define XSZ MAXX -#define YSZ MAXY -#define XOFF 0 -#define YOFF 0 -#endif +#define TCX_DAC_NREGS 16 typedef struct TCXState { uint32_t addr; DisplayState *ds; uint8_t *vram; unsigned long vram_offset; + uint16_t width, height; uint8_t r[256], g[256], b[256]; + uint8_t dac_index, dac_state; } TCXState; static void tcx_draw_line32(TCXState *s1, uint8_t *d, @@ -58,9 +45,9 @@ static void tcx_draw_line32(TCXState *s1, uint8_t *d, for(x = 0; x < width; x++) { val = *s++; - *d++ = s1->r[val]; - *d++ = s1->g[val]; *d++ = s1->b[val]; + *d++ = s1->g[val]; + *d++ = s1->r[val]; d++; } } @@ -73,9 +60,9 @@ static void tcx_draw_line24(TCXState *s1, uint8_t *d, for(x = 0; x < width; x++) { val = *s++; - *d++ = s1->r[val]; - *d++ = s1->g[val]; *d++ = s1->b[val]; + *d++ = s1->g[val]; + *d++ = s1->r[val]; } } @@ -104,12 +91,12 @@ void tcx_update_display(void *opaque) if (ts->ds->depth == 0) return; - page = ts->vram_offset + YOFF*MAXX; + page = ts->vram_offset; y_start = -1; page_min = 0x7fffffff; page_max = -1; d = ts->ds->data; - s = ts->vram + YOFF*MAXX + XOFF; + s = ts->vram; dd = ts->ds->linesize; ds = 1024; @@ -128,7 +115,7 @@ void tcx_update_display(void *opaque) return; } - for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) { + for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { if (y_start < 0) y_start = y; @@ -136,23 +123,23 @@ void tcx_update_display(void *opaque) page_min = page; if (page > page_max) page_max = page; - f(ts, d, s, XSZ); + f(ts, d, s, ts->width); d += dd; s += ds; - f(ts, d, s, XSZ); + f(ts, d, s, ts->width); d += dd; s += ds; - f(ts, d, s, XSZ); + f(ts, d, s, ts->width); d += dd; s += ds; - f(ts, d, s, XSZ); + f(ts, d, s, ts->width); d += dd; s += ds; } else { if (y_start >= 0) { /* flush to display */ dpy_update(ts->ds, 0, y_start, - XSZ, y - y_start); + ts->width, y - y_start); y_start = -1; } d += dd * 4; @@ -162,7 +149,7 @@ void tcx_update_display(void *opaque) if (y_start >= 0) { /* flush to display */ dpy_update(ts->ds, 0, y_start, - XSZ, y - y_start); + ts->width, y - y_start); } /* reset modified pages */ if (page_max != -1) { @@ -187,9 +174,13 @@ static void tcx_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, (uint32_t *)&s->addr); qemu_put_be32s(f, (uint32_t *)&s->vram); + qemu_put_be16s(f, (uint16_t *)&s->height); + qemu_put_be16s(f, (uint16_t *)&s->width); qemu_put_buffer(f, s->r, 256); qemu_put_buffer(f, s->g, 256); qemu_put_buffer(f, s->b, 256); + qemu_put_8s(f, &s->dac_index); + qemu_put_8s(f, &s->dac_state); } static int tcx_load(QEMUFile *f, void *opaque, int version_id) @@ -201,9 +192,13 @@ static int tcx_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, (uint32_t *)&s->addr); qemu_get_be32s(f, (uint32_t *)&s->vram); + qemu_get_be16s(f, (uint16_t *)&s->height); + qemu_get_be16s(f, (uint16_t *)&s->width); qemu_get_buffer(f, s->r, 256); qemu_get_buffer(f, s->g, 256); qemu_get_buffer(f, s->b, 256); + qemu_get_8s(f, &s->dac_index); + qemu_get_8s(f, &s->dac_state); return 0; } @@ -219,12 +214,66 @@ static void tcx_reset(void *opaque) memset(s->vram, 0, MAXX*MAXY); cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY, VGA_DIRTY_FLAG); + s->dac_index = 0; + s->dac_state = 0; +} + +static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + TCXState *s = opaque; + uint32_t saddr; + + saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2; + switch (saddr) { + case 0: + s->dac_index = val >> 24; + s->dac_state = 0; + break; + case 1: + switch (s->dac_state) { + case 0: + s->r[s->dac_index] = val >> 24; + s->dac_state++; + break; + case 1: + s->g[s->dac_index] = val >> 24; + s->dac_state++; + break; + case 2: + s->b[s->dac_index] = val >> 24; + default: + s->dac_state = 0; + break; + } + break; + default: + break; + } + return; } +static CPUReadMemoryFunc *tcx_dac_read[3] = { + tcx_dac_readl, + tcx_dac_readl, + tcx_dac_readl, +}; + +static CPUWriteMemoryFunc *tcx_dac_write[3] = { + tcx_dac_writel, + tcx_dac_writel, + tcx_dac_writel, +}; + void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, - unsigned long vram_offset, int vram_size) + unsigned long vram_offset, int vram_size, int width, int height) { TCXState *s; + int io_memory; s = qemu_mallocz(sizeof(TCXState)); if (!s) @@ -233,13 +282,17 @@ void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, s->addr = addr; s->vram = vram_base; s->vram_offset = vram_offset; + s->width = width; + s->height = height; - cpu_register_physical_memory(addr, vram_size, vram_offset); + cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset); + io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); + cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory); register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); qemu_register_reset(tcx_reset, s); tcx_reset(s); - dpy_resize(s->ds, XSZ, YSZ); + dpy_resize(s->ds, width, height); return s; } @@ -253,11 +306,11 @@ void tcx_screen_dump(void *opaque, const char *filename) f = fopen(filename, "wb"); if (!f) return; - fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255); - d1 = s->vram + YOFF*MAXX + XOFF; - for(y = 0; y < YSZ; y++) { + fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + d1 = s->vram; + for(y = 0; y < s->height; y++) { d = d1; - for(x = 0; x < XSZ; x++) { + for(x = 0; x < s->width; x++) { v = *d; fputc(s->r[v], f); fputc(s->g[v], f); diff --git a/pc-bios/proll.elf b/pc-bios/proll.elf index e274b0d19..f960c83e6 100644 Binary files a/pc-bios/proll.elf and b/pc-bios/proll.elf differ diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch index 18a157512..5f2e027d4 100644 --- a/pc-bios/proll.patch +++ b/pc-bios/proll.patch @@ -1,6 +1,6 @@ -diff -ruN proll_18.orig/Makefile proll-patch4/Makefile +diff -ruN proll_18.orig/Makefile proll-patch7/Makefile --- proll_18.orig/Makefile 2002-09-13 14:16:59.000000000 +0000 -+++ proll-patch4/Makefile 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/Makefile 2004-11-13 15:50:49.000000000 +0000 @@ -4,6 +4,7 @@ make -C krups-ser all make -C espresso all @@ -14,17 +14,143 @@ diff -ruN proll_18.orig/Makefile proll-patch4/Makefile make -C espresso clean make -C espresso-ser clean + make -C qemu clean -diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S +diff -ruN proll_18.orig/qemu/Makefile proll-patch7/qemu/Makefile +--- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch7/qemu/Makefile 2005-03-02 16:41:50.000000000 +0000 +@@ -0,0 +1,122 @@ ++# ++# proll: ++# qemu/Makefile - make PROLL for QEMU ++# $Id: proll.patch,v 1.3 2005-03-13 09:43:36 bellard Exp $ ++# ++# Copyright 1999 Pete Zaitcev ++# This is Free Software is licensed under terms of GNU General Public License. ++# ++ ++CC = gcc ++ ++#CROSS = /usr/local/sparc/bin/sparc-sun-linux- ++CROSS = sparc-unknown-linux-gnu- ++ ++CROSSCC = $(CROSS)gcc ++CROSSLD = $(CROSS)ld ++CROSSNM = $(CROSS)nm ++ ++RM = /bin/rm -f ++ELFTOAOUT = elftoaout ++ ++# ++SRC = ../src ++ ++# Due to remapping algorithm PROLBASE should be algned on PMD. ++# We make PROLBASE a define instead of using _start because we ++# want to shift it to form a PGD entry. A relocatable label will not work. ++# Linux kernel expects us to be at LINUX_OPPROM_BEGVM . ++PROLBASE = 0xffd00000 ++PROLRODATA = 0xffd07000 ++PROLDATA = 0xffd09000 ++PROLSIZE = 240*1024 ++ ++# Linux ++# Fixed %g6 is for arch/sparc/kernel/head.S, it seems ok w/o -ffixed-g6. ++# Kernel uses -fcall-used-g5 -fcall-used-g7, we probably do not need them. ++# __ANSI__ is supposed to be on by default but it is not. ++CFLAGS = -O2 -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -g -DQEMU ++ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g ++# Solaris or Linux/i386 cross compilation ++#CFLAGS = -Iinclude -O ++ ++LDFLAGS = -N -Ttext $(PROLBASE) --section-start .rodata=$(PROLRODATA) -Tdata $(PROLDATA) -Tbss $(PROLDATA) ++ ++ALL = proll.aout ++PROLLEXE = proll.elf ++ ++OBJS = head.o wuf.o wof.o main.o $(CONSOLE) \ ++ printf.o le.o system_qemu.o iommu.o \ ++ arp.o netinit.o bootp.o packet.o tftp.o udp.o sched_4m.o openprom.o \ ++ vconsole.o hconsole.o rconsole.o vcons_zs.o ++ ++all: $(ALL) ++ ++$(PROLLEXE): $(OBJS) ++ $(CROSSLD) $(LDFLAGS) -o $(PROLLEXE) $(OBJS) ++ ++head.o: head.S $(SRC)/phys_jj.h \ ++ $(SRC)/asi.h $(SRC)/psr.h $(SRC)/crs.h ++ $(CROSSCC) $(ASFLAGS) -DPROLBASE=$(PROLBASE) -o $*.o -c $*.S ++ ++main.o: main.c $(SRC)/asi.h $(SRC)/pgtsrmmu.h $(SRC)/iommu.h \ ++ $(SRC)/phys_jj.h $(SRC)/vconsole.h $(SRC)/version.h $(SRC)/general.h \ ++ $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h ++ $(CROSSCC) $(CFLAGS) -c $*.c ++openprom.o: openprom.c $(SRC)/openprom.h $(SRC)/general.h $(SRC)/romlib.h \ ++ $(SRC)/vconsole.h $(SRC)/system.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $*.c ++ ++system_qemu.o: system_qemu.c $(SRC)/vconsole.h $(SRC)/pgtsrmmu.h \ ++ $(SRC)/timer.h $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/asi.h \ ++ $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h $(SRC)/crs.h ++ $(CROSSCC) $(CFLAGS) -c $*.c ++iommu.o: $(SRC)/iommu.c $(SRC)/pgtsrmmu.h $(SRC)/phys_jj.h $(SRC)/iommu.h \ ++ $(SRC)/vconsole.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/asi.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++vconsole.o: $(SRC)/vconsole.c $(SRC)/vconsole.h $(SRC)/hconsole.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++vcons_zs.o: $(SRC)/vcons_zs.c $(SRC)/vconsole.h $(SRC)/system.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++hconsole.o: $(SRC)/hconsole.c $(SRC)/hconsole.h $(SRC)/rconsole.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++rconsole.o: $(SRC)/rconsole.c $(SRC)/rconsole.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++printf.o: $(SRC)/printf.c ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++le.o: $(SRC)/le.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/netpriv.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/net.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++ ++arp.o: $(SRC)/arp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++netinit.o: $(SRC)/netinit.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++tftp.o: $(SRC)/tftp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/tftp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++udp.o: $(SRC)/udp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++packet.o: $(SRC)/packet.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++sched_4m.o: $(SRC)/sched_4m.c $(SRC)/system.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c ++bootp.o: $(SRC)/bootp.c $(SRC)/general.h $(SRC)/net.h \ ++ $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/bootp.h ++ $(CROSSCC) $(CFLAGS) -DNOBPEXT=1 -c $(SRC)/$*.c ++ ++wuf.o: $(SRC)/wuf.S ++ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S ++wof.o: $(SRC)/wof.S ++ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S ++ ++#genlab.o: genlab.c ++# $(CC) -c $*.c ++# ++#genlab: genlab.o ++# $(CC) -o genlab genlab.o ++ ++clean: ++ $(RM) $(OBJS) ++ $(RM) $(PROLLEXE) proll.aout ++ ++proll.aout: $(PROLLEXE) ++ $(ELFTOAOUT) -o proll.aout $(PROLLEXE) +diff -ruN proll_18.orig/qemu/head.S proll-patch7/qemu/head.S --- proll_18.orig/qemu/head.S 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch4/qemu/head.S 2004-11-13 15:50:49.000000000 +0000 -@@ -0,0 +1,515 @@ ++++ proll-patch7/qemu/head.S 2005-03-02 15:30:47.000000000 +0000 +@@ -0,0 +1,539 @@ +/** + ** Standalone startup code for Linux PROM emulator. + ** Copyright 1999 Pete A. Zaitcev + ** This code is licensed under GNU General Public License. + **/ +/* -+ * $Id: proll.patch,v 1.2 2004-12-19 23:18:01 bellard Exp $ ++ * $Id: proll.patch,v 1.3 2005-03-13 09:43:36 bellard Exp $ + */ + +#include @@ -167,6 +293,31 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S +_start: +start: + .globl spill_window_entry, fill_window_entry ++ ++#define EXPORT_TRAP(trap) \ ++ .globl trap; \ ++ .type trap,function; \ ++ .size trap, 16 ++ ++EXPORT_TRAP(t_zero) ++EXPORT_TRAP(t_wovf) ++EXPORT_TRAP(t_wunf) ++EXPORT_TRAP(t_irq1) ++EXPORT_TRAP(t_irq2) ++EXPORT_TRAP(t_irq3) ++EXPORT_TRAP(t_irq4) ++EXPORT_TRAP(t_irq5) ++EXPORT_TRAP(t_irq6) ++EXPORT_TRAP(t_irq7) ++EXPORT_TRAP(t_irq8) ++EXPORT_TRAP(t_irq9) ++EXPORT_TRAP(t_irq10) ++EXPORT_TRAP(t_irq11) ++EXPORT_TRAP(t_irq12) ++EXPORT_TRAP(t_irq13) ++EXPORT_TRAP(t_irq14) ++EXPORT_TRAP(t_irq15) ++ +C_LABEL(trapbase): +t_zero: b goprol; nop; nop; nop; +t_tflt: SRMMU_TFAULT /* Inst. Access Exception */ @@ -294,6 +445,8 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S + +goprol: + ! %g1 contains end of memory ++ set PHYS_JJ_EEPROM + 0x30, %g1 ++ lda [%g1] ASI_M_BYPASS, %g1 + ! map PROLDATA to PROLBASE+PROLSIZE to end of ram + set PROLSIZE+0x1000-PROLDATA+PROLBASE, %g2 ! add 0x1000 for temp tables + sub %g1, %g2, %g2 ! start of private memory @@ -397,9 +550,6 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S + bl 1b + add %o0, 0x4, %o0 + -+ sethi %hi( C_LABEL(ram_size) ), %o0 -+ st %g3, [%o0 + %lo( C_LABEL(ram_size) )] -+ + mov 2, %g1 + wr %g1, 0x0, %wim ! make window 1 invalid + WRITE_PAUSE @@ -533,10 +683,10 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch4/qemu/head.S +C_LABEL(ldb_bypass): + retl + lduba [%o0] ASI_M_BYPASS, %o0 -diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c +diff -ruN proll_18.orig/qemu/main.c proll-patch7/qemu/main.c --- proll_18.orig/qemu/main.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch4/qemu/main.c 2004-11-23 19:05:34.000000000 +0000 -@@ -0,0 +1,178 @@ ++++ proll-patch7/qemu/main.c 2005-03-02 20:08:23.000000000 +0000 +@@ -0,0 +1,173 @@ +/** + ** Proll (PROM replacement) + ** Copyright 1999 Pete Zaitcev @@ -558,8 +708,11 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c +#include +#include /* our own prototypes */ + ++void *init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, const char *cmdline, char boot_device, int nographic); ++int vcon_zs_init(struct vconterm *t, unsigned int a0); ++int vcon_zs_write(struct vconterm *t, char *data, int leng); ++ +static void init_idprom(void); -+static void makepages_q(struct phym *t, unsigned int highbase); + +struct vconterm dp0; +struct mem cmem; /* Current memory, virtual */ @@ -567,20 +720,48 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c +struct phym pmem; /* Current phys. mem. */ +struct iommu ciommu; /* Our IOMMU on sun4m */ + -+static char *hw_idprom; -+int ignore_fault, fault_ignored, ram_size; ++static struct { ++ const char id[16]; ++ unsigned int version; ++ char pad1[0x1c]; // Pad to 0x30 ++ unsigned int ram_size; ++ char boot_device; ++ unsigned int load_addr, kernel_size; ++ unsigned int cmdline, cmdline_len; ++ char pad2[0x0c]; // Pad to 0x54 ++ unsigned short width, height, depth; ++} *hw_idprom; ++ ++int ignore_fault, fault_ignored; ++void *printk_fn; ++unsigned int q_height, q_width; + +/* + */ +void prolmain() +{ -+ //static const char fname[14] = "00000000.PROL"; ++ static char fname[14]; + static struct banks bb; + unsigned int hiphybas; + const void *romvec; ++ unsigned int ram_size; ++ char nographic; ++ ++ nographic = ldb_bypass(PHYS_JJ_EEPROM + 0x2F); ++ if (!nographic) { ++ q_width = ldh_bypass(PHYS_JJ_EEPROM + 0x54); ++ q_height = ldh_bypass(PHYS_JJ_EEPROM + 0x56); ++ vcon_init(&dp0, PHYS_JJ_TCX_FB); ++ printk_fn = vcon_write; ++ } ++ else { ++ vcon_zs_init(&dp0, 0x71100000); ++ printk_fn = vcon_zs_write; ++ } ++ + -+ vcon_init(&dp0, PHYS_JJ_TCX_FB); + printk("PROLL %s QEMU\n", PROLL_VERSION_STRING); ++ ram_size = ld_bypass(PHYS_JJ_EEPROM + 0x30); + printk("%d MB total\n", ram_size/(1024*1024)); + + bb.nbanks = 1; @@ -590,7 +771,7 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c + hiphybas = ram_size - PROLSIZE; + + mem_init(&cmem, (char *) &_end, (char *)(PROLBASE+PROLSIZE)); -+ makepages_q(&pmem, hiphybas); ++ makepages(&pmem, hiphybas); + init_mmu_swift((unsigned int)pmem.pctp - PROLBASE + hiphybas); + + mem_init(&cio, (char *)(PROLBASE+PROLSIZE), @@ -601,38 +782,46 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c + /* + */ + init_idprom(); ++ printk("NVRAM: id %s version %d\n", hw_idprom->id, hw_idprom->version); ++ if (!nographic) ++ printk("Prom console: TCX %dx%d\n", q_width, q_height); ++ else ++ printk("Prom console: serial\n"); + sched_init(); + le_probe(); + init_net(); + -+#if 0 -+#if 0 /* RARP */ -+ if (rarp() != 0) fatal(); -+ /* printrarp(); */ -+ xtoa(myipaddr, fname, 8); -+ if (load(servaddr, fname) != 0) fatal(); -+#else -+ if (bootp() != 0) fatal(); -+ /* -+ * boot_rec.bp_file cannot be used because system PROM -+ * uses it to locate ourselves. If we load from boot_rec.bp_file, -+ * we will loop reloading PROLL over and over again. -+ * Thus we use traditional PROLL scheme HEXIPADDR.PROL (single L). -+ */ -+ xtoa(myipaddr, fname, 8); -+ if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); -+#endif -+#endif ++ printk("Boot device: %c\n", hw_idprom->boot_device); ++ if (hw_idprom->boot_device == 'n') { ++ if (bootp() != 0) fatal(); ++ /* ++ * boot_rec.bp_file cannot be used because system PROM ++ * uses it to locate ourselves. If we load from boot_rec.bp_file, ++ * we will loop reloading PROLL over and over again. ++ * Thus we use traditional PROLL scheme HEXIPADDR.PROL (single L). ++ */ ++ xtoa(myipaddr, fname, 8); ++ fname[9] = '.'; ++ fname[10] = 'P'; ++ fname[11] = 'R'; ++ fname[12] = 'O'; ++ fname[13] = 'L'; ++ fname[14] = 0; ++ ++ if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); ++ } + -+ romvec = init_openprom(bb.nbanks, bb.bankv, hiphybas); ++ romvec = init_openprom_qemu(bb.nbanks, bb.bankv, hiphybas, ++ (void *)hw_idprom->cmdline, hw_idprom->boot_device, nographic); + + printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n", + PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024, + (int)cio.start, (int)cio.curp); -+ //set_timeout(5); while (!chk_timeout()) { } /* P3: let me read */ + + { -+ void (*entry)(const void *, int, int, int, int) = (void (*)(const void*, int, int, int, int)) LOADBASE; ++ void (*entry)(const void *, int, int, int, int) = (void *) hw_idprom->load_addr; ++ printk("Kernel loaded at 0x%x, size %dK, command line = '%s'\n", ++ *entry, hw_idprom->kernel_size/1024, hw_idprom->cmdline); + entry(romvec, 0, 0, 0, 0); + } + @@ -652,14 +841,12 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c + */ +void udelay(unsigned long usecs) +{ -+ int i, n; -+ n = usecs*50; -+ for (i = 0; i < n; i++) { } ++ // Qemu hardware is perfect and does not need any delays! +} + +static void init_idprom() +{ -+ char *va_prom; ++ void *va_prom; + + if ((va_prom = map_io(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE)) == NULL) { + printk("init_idprom: cannot map eeprom\n"); @@ -673,259 +860,97 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch4/qemu/main.c + hw_idprom = va_prom; +} + +diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c +--- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch7/qemu/openprom.c 2005-03-02 20:09:57.000000000 +0000 +@@ -0,0 +1,646 @@ +/* -+ * Make CPU page tables. -+ * Returns pointer to context table. -+ * Here we ignore memory allocation errors which "should not happen" -+ * because we cannot print anything anyways if memory initialization fails. ++ * PROM interface support ++ * Copyright 1996 The Australian National University. ++ * Copyright 1996 Fujitsu Laboratories Limited ++ * Copyright 1999 Pete A. Zaitcev ++ * This software may be distributed under the terms of the Gnu ++ * Public License version 2 or later + */ -+void makepages_q(struct phym *t, unsigned int highbase) -+{ -+ unsigned int *ctp, *l1, pte; -+ int i; -+ unsigned int pa, va; + -+ ctp = mem_zalloc(&cmem, NCTX_SWIFT*sizeof(int), NCTX_SWIFT*sizeof(int)); -+ l1 = mem_zalloc(&cmem, 256*sizeof(int), 256*sizeof(int)); ++#include ++#include ++#include ++#include ++#include ++#include "phys_jj.h" + -+ pte = SRMMU_ET_PTD | (((unsigned int)l1 - PROLBASE + highbase) >> 4); -+ for (i = 0; i < NCTX_SWIFT; i++) { -+ ctp[i] = pte; -+ } ++//#define DEBUG_OBP + -+ pa = PROLBASE; -+ for (va = PROLBASE; va < PROLDATA; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } -+ pa = highbase + PROLDATA - PROLBASE; -+ for (va = PROLDATA; va < PROLBASE + PROLSIZE; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } ++struct property { ++ const char *name; ++ const char *value; ++ const int length; ++}; + -+ /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ -+ pa = 0; -+ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } ++struct node { ++ const struct property *properties; ++ /* short */ const int sibling; ++ /* short */ const int child; ++}; + -+ t->pctp = ctp; -+ t->pl1 = l1; -+ t->pbas = highbase; -+} -diff -ruN proll_18.orig/qemu/Makefile proll-patch4/qemu/Makefile ---- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch4/qemu/Makefile 2004-11-13 15:50:49.000000000 +0000 -@@ -0,0 +1,119 @@ -+# -+# proll: -+# qemu/Makefile - make PROLL for QEMU -+# $Id: proll.patch,v 1.2 2004-12-19 23:18:01 bellard Exp $ -+# -+# Copyright 1999 Pete Zaitcev -+# This is Free Software is licensed under terms of GNU General Public License. -+# ++static int obp_nextnode(int node); ++static int obp_child(int node); ++static int obp_proplen(int node, char *name); ++static int obp_getprop(int node, char *name, char *val); ++static int obp_setprop(int node, char *name, char *val, int len); ++static const char *obp_nextprop(int node, char *name); + -+CC = gcc ++static char obp_idprom[IDPROM_SIZE]; ++static const struct property null_properties = { NULL, NULL, -1 }; ++static const int prop_true = -1; + -+#CROSS = /usr/local/sparc/bin/sparc-sun-linux- -+CROSS = sparc-unknown-linux-gnu- ++static const struct property propv_root[] = { ++ {"name", "SUNW,JavaStation-1", sizeof("SUNW,JavaStation-1") }, ++ {"idprom", obp_idprom, IDPROM_SIZE}, ++ {"banner-name", "JavaStation", sizeof("JavaStation")}, ++ {"compatible", "sun4m", 6}, ++ {NULL, NULL, -1} ++}; + -+CROSSCC = $(CROSS)gcc -+CROSSLD = $(CROSS)ld -+CROSSNM = $(CROSS)nm ++static const int prop_iommu_reg[] = { ++ 0x0, 0x10000000, 0x00000300, ++}; ++static const struct property propv_iommu[] = { ++ {"name", "iommu", sizeof("iommu")}, ++ {"reg", (char*)&prop_iommu_reg[0], sizeof(prop_iommu_reg) }, ++ {NULL, NULL, -1} ++}; + -+RM = /bin/rm -f -+ELFTOAOUT = elftoaout ++static const int prop_sbus_ranges[] = { ++ 0x0, 0x0, 0x0, 0x30000000, 0x10000000, ++ 0x1, 0x0, 0x0, 0x40000000, 0x10000000, ++ 0x2, 0x0, 0x0, 0x50000000, 0x10000000, ++ 0x3, 0x0, 0x0, 0x60000000, 0x10000000, ++ 0x4, 0x0, 0x0, 0x70000000, 0x10000000, ++}; ++static const struct property propv_sbus[] = { ++ {"name", "sbus", 5}, ++ {"ranges", (char*)&prop_sbus_ranges[0], sizeof(prop_sbus_ranges)}, ++ {"device_type", "hierarchical", sizeof("hierarchical") }, ++ {NULL, NULL, -1} ++}; + -+# -+SRC = ../src -+ -+# Due to remapping algorithm PROLBASE should be algned on PMD. -+# We make PROLBASE a define instead of using _start because we -+# want to shift it to form a PGD entry. A relocatable label will not work. -+# Linux kernel expects us to be at LINUX_OPPROM_BEGVM . -+PROLBASE = 0xffd00000 -+PROLRODATA = 0xffd07000 -+PROLDATA = 0xffd09000 -+PROLSIZE = (240*1024) -+ -+# Linux -+# Fixed %g6 is for arch/sparc/kernel/head.S, it seems ok w/o -ffixed-g6. -+# Kernel uses -fcall-used-g5 -fcall-used-g7, we probably do not need them. -+# __ANSI__ is supposed to be on by default but it is not. -+CFLAGS = -O2 -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -g -+ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g -+# Solaris or Linux/i386 cross compilation -+#CFLAGS = -Iinclude -O -+ -+LDFLAGS = -N -Ttext $(PROLBASE) --section-start .rodata=$(PROLRODATA) -Tdata $(PROLDATA) -Tbss $(PROLDATA) -+ -+ALL = proll.aout -+PROLLEXE = proll.elf -+ -+OBJS = head.o wuf.o wof.o main.o vconsole.o hconsole.o rconsole.o \ -+ printf.o le.o system.o iommu.o \ -+ arp.o netinit.o bootp.o packet.o tftp.o udp.o sched_4m.o openprom.o -+ -+all: $(ALL) -+ -+$(PROLLEXE): $(OBJS) -+ $(CROSSLD) $(LDFLAGS) -o $(PROLLEXE) $(OBJS) -+ -+head.o: head.S $(SRC)/phys_jj.h \ -+ $(SRC)/asi.h $(SRC)/psr.h $(SRC)/crs.h -+ $(CROSSCC) $(ASFLAGS) -DPROLBASE=$(PROLBASE) -o $*.o -c $*.S -+ -+main.o: main.c $(SRC)/asi.h $(SRC)/pgtsrmmu.h $(SRC)/iommu.h \ -+ $(SRC)/phys_jj.h $(SRC)/vconsole.h $(SRC)/version.h $(SRC)/general.h \ -+ $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h -+ $(CROSSCC) $(CFLAGS) -c $*.c -+openprom.o: openprom.c $(SRC)/openprom.h $(SRC)/general.h $(SRC)/romlib.h \ -+ $(SRC)/vconsole.h $(SRC)/system.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $*.c -+ -+system.o: $(SRC)/system.c $(SRC)/vconsole.h $(SRC)/pgtsrmmu.h \ -+ $(SRC)/timer.h $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/asi.h \ -+ $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h $(SRC)/crs.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+iommu.o: $(SRC)/iommu.c $(SRC)/pgtsrmmu.h $(SRC)/phys_jj.h $(SRC)/iommu.h \ -+ $(SRC)/vconsole.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/asi.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+vconsole.o: $(SRC)/vconsole.c $(SRC)/vconsole.h $(SRC)/hconsole.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+hconsole.o: $(SRC)/hconsole.c $(SRC)/hconsole.h $(SRC)/rconsole.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+rconsole.o: $(SRC)/rconsole.c $(SRC)/rconsole.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+printf.o: $(SRC)/printf.c -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+le.o: $(SRC)/le.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/netpriv.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/net.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+ -+arp.o: $(SRC)/arp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+netinit.o: $(SRC)/netinit.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+tftp.o: $(SRC)/tftp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/tftp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+udp.o: $(SRC)/udp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+packet.o: $(SRC)/packet.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+sched_4m.o: $(SRC)/sched_4m.c $(SRC)/system.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+bootp.o: $(SRC)/bootp.c $(SRC)/general.h $(SRC)/net.h \ -+ $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/bootp.h -+ $(CROSSCC) $(CFLAGS) -DNOBPEXT=1 -c $(SRC)/$*.c -+ -+wuf.o: $(SRC)/wuf.S -+ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S -+wof.o: $(SRC)/wof.S -+ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S -+ -+#genlab.o: genlab.c -+# $(CC) -c $*.c -+# -+#genlab: genlab.o -+# $(CC) -o genlab genlab.o -+ -+clean: -+ $(RM) $(OBJS) -+ $(RM) $(PROLLEXE) proll.aout -+ -+proll.aout: $(PROLLEXE) -+ $(ELFTOAOUT) -o proll.aout $(PROLLEXE) -diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c ---- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch4/qemu/openprom.c 2004-11-23 19:14:05.000000000 +0000 -@@ -0,0 +1,596 @@ -+/* -+ * PROM interface support -+ * Copyright 1996 The Australian National University. -+ * Copyright 1996 Fujitsu Laboratories Limited -+ * Copyright 1999 Pete A. Zaitcev -+ * This software may be distributed under the terms of the Gnu -+ * Public License version 2 or later -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "phys_jj.h" -+ -+struct property { -+ const char *name; -+ const char *value; -+ const int length; -+}; -+ -+struct node { -+ const struct property *properties; -+ /* short */ const int sibling; -+ /* short */ const int child; -+}; -+ -+static int obp_nextnode(int node); -+static int obp_child(int node); -+static int obp_proplen(int node, char *name); -+static int obp_getprop(int node, char *name, char *val); -+static int obp_setprop(int node, char *name, char *val, int len); -+static const char *obp_nextprop(int node, char *name); -+ -+static char obp_idprom[IDPROM_SIZE]; -+static const struct property null_properties = { NULL, NULL, -1 }; -+static const int prop_true = -1; -+ -+static const struct property propv_root[] = { -+ {"name", "SUNW,JavaStation-1", sizeof("SUNW,JavaStation-1") }, -+ {"idprom", obp_idprom, IDPROM_SIZE}, -+ {"banner-name", "JavaStation", sizeof("JavaStation")}, -+ {"compatible", "sun4m", 6}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_iommu_reg[] = { -+ 0x0, 0x10000000, 0x00000300, -+}; -+static const struct property propv_iommu[] = { -+ {"name", "iommu", sizeof("iommu")}, -+ {"reg", (char*)&prop_iommu_reg[0], sizeof(prop_iommu_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_sbus_ranges[] = { -+ 0x0, 0x0, 0x0, 0x30000000, 0x10000000, -+ 0x1, 0x0, 0x0, 0x40000000, 0x10000000, -+ 0x2, 0x0, 0x0, 0x50000000, 0x10000000, -+ 0x3, 0x0, 0x0, 0x60000000, 0x10000000, -+ 0x4, 0x0, 0x0, 0x70000000, 0x10000000, -+}; -+static const struct property propv_sbus[] = { -+ {"name", "sbus", 5}, -+ {"ranges", (char*)&prop_sbus_ranges[0], sizeof(prop_sbus_ranges)}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_tcx_regs[] = { -+ 0x2, 0x00800000, 0x00100000, -+ 0x2, 0x02000000, 0x00000001, -+ 0x2, 0x04000000, 0x00800000, -+ 0x2, 0x06000000, 0x00800000, -+ 0x2, 0x0a000000, 0x00000001, -+ 0x2, 0x0c000000, 0x00000001, -+ 0x2, 0x0e000000, 0x00000001, -+ 0x2, 0x00700000, 0x00001000, -+ 0x2, 0x00200000, 0x00000004, -+ 0x2, 0x00300000, 0x0000081c, -+ 0x2, 0x00000000, 0x00010000, -+ 0x2, 0x00240000, 0x00000004, -+ 0x2, 0x00280000, 0x00000001, -+}; ++static const int prop_tcx_regs[] = { ++ 0x2, 0x00800000, 0x00100000, ++ 0x2, 0x02000000, 0x00000001, ++ 0x2, 0x04000000, 0x00800000, ++ 0x2, 0x06000000, 0x00800000, ++ 0x2, 0x0a000000, 0x00000001, ++ 0x2, 0x0c000000, 0x00000001, ++ 0x2, 0x0e000000, 0x00000001, ++ 0x2, 0x00700000, 0x00001000, ++ 0x2, 0x00200000, 0x00000004, ++ 0x2, 0x00300000, 0x0000081c, ++ 0x2, 0x00000000, 0x00010000, ++ 0x2, 0x00240000, 0x00000004, ++ 0x2, 0x00280000, 0x00000001, ++}; + +#if 1 /* Zaitcev */ +static const int pixfreq = 0x03dfd240; @@ -1005,6 +1030,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c +static const struct property propv_obio[] = { + {"name", "obio", 5 }, + {"ranges", (char*)&prop_obio_ranges[0], sizeof(prop_obio_ranges) }, ++ {"device_type", "hierarchical", sizeof("hierarchical") }, + {NULL, NULL, -1} +}; + @@ -1056,29 +1082,35 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c + {NULL, NULL, -1} +}; + -+static const int prop_zs_intr[] = { 0x26, 0x0 }; ++static const int prop_zs_intr[] = { 12, 0x0 }; +static const int prop_zs_reg[] = { -+ 0x4, 0x00000000, 0x0000000f, ++ 0x0, 0x00000000, 0x00000008, +}; -+static const int prop_zs_slave[] = { 0x1 }; ++static const int prop_zs_addr = { 0x70000000 }; ++static const int prop_zs_slave[] = { 1 }; +static const struct property propv_obio_zs[] = { + {"name", "zs", sizeof("zs")}, + {"reg", (char*)&prop_zs_reg[0], sizeof(prop_zs_reg) }, -+ {"reg", (char*)&prop_zs_slave[0], sizeof(prop_zs_slave) }, ++ {"slave", (char*)&prop_zs_slave[0], sizeof(prop_zs_slave) }, + {"device_type", "serial", sizeof("serial") }, ++ {"intr", (char*)&prop_zs_intr[0], sizeof(prop_zs_intr) }, ++ // {"address", (char*)&prop_zs_addr, sizeof(prop_zs_addr) }, + {NULL, NULL, -1} +}; + -+static const int prop_zs1_intr[] = { 0x26, 0x0 }; ++static const int prop_zs1_intr[] = { 12, 0x0 }; +static const int prop_zs1_reg[] = { -+ 0x4, 0x00100000, 0x0000000f, ++ 0x0, 0x00100000, 0x00000008, +}; -+static const int prop_zs1_slave[] = { 0x0 }; ++static const int prop_zs1_addr = { 0x70100000 }; ++static const int prop_zs1_slave[] = { 0 }; +static const struct property propv_obio_zs1[] = { + {"name", "zs", sizeof("zs")}, + {"reg", (char*)&prop_zs1_reg[0], sizeof(prop_zs1_reg) }, -+ {"reg", (char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) }, ++ {"slave", (char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) }, + {"device_type", "serial", sizeof("serial") }, ++ {"intr", (char*)&prop_zs1_intr[0], sizeof(prop_zs1_intr) }, ++ // {"address", (char*)&prop_zs1_addr, sizeof(prop_zs1_addr) }, + {NULL, NULL, -1} +}; + @@ -1106,24 +1138,110 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c + {NULL, NULL, -1} +}; + ++static const int prop_espdma_reg[] = { ++ 0x4, 0x08400000, 0x00000010, ++}; ++// Disabled, not implemented yet ++static const struct property propv_sbus_espdma[] = { ++ {"name", "xxxespdma", sizeof("xxxespdma")}, ++ {"reg", (char*)&prop_espdma_reg[0], sizeof(prop_espdma_reg) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_esp_reg[] = { ++ 0x4, 0x08800000, 0x00000040, ++}; ++static const int prop_esp_intr[] = { 0x24, 0x0 }; ++static const struct property propv_sbus_espdma_esp[] = { ++ {"name", "esp", sizeof("esp")}, ++ {"reg", (char*)&prop_esp_reg[0], sizeof(prop_esp_reg) }, ++ {"intr", (char*)&prop_esp_intr[0], sizeof(prop_esp_intr) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_bpp_reg[] = { ++ 0x4, 0x0c800000, 0x0000001c, ++}; ++static const int prop_bpp_intr[] = { 0x33, 0x0 }; ++static const struct property propv_sbus_bpp[] = { ++ {"name", "SUNW,bpp", sizeof("SUNW,bpp")}, ++ {"reg", (char*)&prop_bpp_reg[0], sizeof(prop_bpp_reg) }, ++ {"intr", (char*)&prop_bpp_intr[0], sizeof(prop_bpp_intr) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_fd_intr[] = { 0x2b, 0x0 }; ++static const int prop_fd_reg[] = { ++ 0x0, 0x00400000, 0x0000000f, ++}; ++static const struct property propv_obio_fd[] = { ++ {"name", "SUNW,fdtwo", sizeof("SUNW,fdtwo")}, ++ {"reg", (char*)&prop_fd_reg[0], sizeof(prop_fd_reg) }, ++ {"device_type", "block", sizeof("block") }, ++ {"intr", (char*)&prop_fd_intr[0], sizeof(prop_fd_intr) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_pw_intr[] = { 0x22, 0x0 }; ++static const int prop_pw_reg[] = { ++ 0x0, 0x00910000, 0x00000001, ++}; ++static const struct property propv_obio_pw[] = { ++ {"name", "power", sizeof("power")}, ++ {"reg", (char*)&prop_pw_reg[0], sizeof(prop_pw_reg) }, ++ {"intr", (char*)&prop_pw_intr[0], sizeof(prop_pw_intr) }, ++ {NULL, NULL, -1} ++}; ++ ++static const int prop_cf_reg[] = { ++ 0x0, 0x00800000, 0x00000001, ++}; ++static const struct property propv_obio_cf[] = { ++ {"name", "slavioconfig", sizeof("slavioconfig")}, ++ {"reg", (char*)&prop_cf_reg[0], sizeof(prop_cf_reg) }, ++ {NULL, NULL, -1} ++}; ++ +static const struct node nodes[] = { + { &null_properties, 1, 0 }, /* 0 = big brother of root */ + { propv_root, 0, 2 }, /* 1 "/" */ -+ { propv_iommu, 8, 3 }, /* 2 "/iommu" */ ++ { propv_iommu, 11, 3 }, /* 2 "/iommu" */ + { propv_sbus, 0, 4 }, /* 3 "/iommu/sbus" */ + { propv_sbus_tcx, 5, 0 }, /* 4 "/iommu/sbus/SUNW,tcx" */ + { propv_sbus_ledma, 7, 6 }, /* 5 "/iommu/sbus/ledma" */ + { propv_sbus_ledma_le, 0, 0 }, /* 6 "/iommu/sbus/ledma/le" */ -+ { propv_sbus_cs4231, 0, 0 }, /* 7 "/iommu/sbus/SUNW,CS4231 */ -+ { propv_cpu, 9, 0 }, /* 8 "/STP1012PGA" */ -+ { propv_obio, 0, 10 }, /* 9 "/obio" */ -+ { propv_obio_int, 11, 0 }, /* 10 "/obio/interrupt" */ -+ { propv_obio_cnt, 12, 0 }, /* 11 "/obio/counter" */ -+ { propv_obio_eep, 13, 0 }, /* 12 "/obio/eeprom" */ ++ { propv_sbus_cs4231, 8, 0 }, /* 7 "/iommu/sbus/SUNW,CS4231 */ ++ { propv_sbus_bpp, 9, 0 }, /* 8 "/iommu/sbus/SUNW,bpp */ ++ { propv_sbus_espdma, 0, 10 }, /* 9 "/iommu/sbus/espdma" */ ++ { propv_sbus_espdma_esp, 0, 0 }, /* 10 "/iommu/sbus/espdma/esp" */ ++ { propv_cpu, 12, 0 }, /* 11 "/STP1012PGA" */ ++ { propv_obio, 0, 13 }, /* 12 "/obio" */ ++ { propv_obio_int, 14, 0 }, /* 13 "/obio/interrupt" */ ++ { propv_obio_cnt, 15, 0 }, /* 14 "/obio/counter" */ ++ { propv_obio_eep, 16, 0 }, /* 15 "/obio/eeprom" */ ++ { propv_obio_auxio, 17, 0 }, /* 16 "/obio/auxio" */ ++ { propv_obio_zs, 18, 0 }, /* 17 "/obio/zs@0,0" */ ++ { propv_obio_zs1, 19, 0 }, /* 18 "/obio/zs@0,100000" */ ++ { propv_obio_fd, 20, 0 }, /* 19 "/obio/SUNW,fdtwo" */ ++ { propv_obio_pw, 21, 0 }, /* 20 "/obio/power" */ ++ { propv_obio_cf, 0, 0 }, /* 21 "/obio/slavioconfig@0,800000" */ ++#if 0 + { propv_obio_su, 14, 0 }, /* 13 "/obio/su" */ -+ { propv_obio_auxio, 0, 0 }, /* 14 "/obio/auxio" */ -+ { propv_obio_zs, 0, 0 }, /* 14 "/obio/zs@0,0" */ -+ { propv_obio_zs1, 0, 0 }, /* 14 "/obio/zs@0,100000" */ ++ { propv_cpu, 18, 0 }, /* 17 "/STP1012PGA" */ ++ { propv_cpu, 19, 0 }, /* 18 "/STP1012PGA" */ ++ ++ { propv_cpu, 20, 0 }, /* 19 "/STP1012PGA" */ ++ { propv_cpu, 21, 0 }, /* 20 "/STP1012PGA" */ ++ { propv_cpu, 22, 0 }, /* 21 "/STP1012PGA" */ ++ { propv_cpu, 23, 0 }, /* 22 "/STP1012PGA" */ ++ { propv_cpu, 24, 0 }, /* 23 "/STP1012PGA" */ ++ { propv_cpu, 25, 0 }, /* 24 "/STP1012PGA" */ ++ { propv_cpu, 26, 0 }, /* 25 "/STP1012PGA" */ ++ { propv_cpu, 27, 0 }, /* 26 "/STP1012PGA" */ ++ { propv_cpu, 28, 0 }, /* 27 "/STP1012PGA" */ ++ { propv_cpu, 29, 0 }, /* 28 "/STP1012PGA" */ ++ { propv_cpu, 30, 0 }, /* 29 "/STP1012PGA" */ ++#endif +}; + +static struct linux_mlist_v0 totphys[MAX_BANKS]; @@ -1144,303 +1262,677 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch4/qemu/openprom.c + obp_nextprop /* char * (*no_nextprop)(int node, char *name); */ +}; + -+static const char arg_nfsroot[] = "console=ttyS0 ip=bootp root=nfs"; -+ -+static const struct linux_arguments_v0 obp_arg = { -+ { "le()", arg_nfsroot, NULL, NULL, NULL, NULL, NULL, NULL }, -+ { "" }, -+ { 'l', 'e' }, 0, 0, 0, NULL, -+ NULL -+}; ++static struct linux_arguments_v0 obp_arg; +static const struct linux_arguments_v0 * const obp_argp = &obp_arg; + -+static const void * const synch_hook = NULL; -+#if 0 -+static const char obp_stdin = PROMDEV_KBD; -+static const char obp_stdout = PROMDEV_SCREEN; -+#else -+static const char obp_stdin = PROMDEV_TTYA; -+static const char obp_stdout = PROMDEV_TTYA; -+#endif ++static void (*synch_hook)(void); ++static char obp_stdin, obp_stdout; ++ ++static int obp_nbgetchar(void); ++static int obp_nbputchar(int ch); ++static void obp_reboot(char *); ++static void obp_abort(void); ++static void obp_halt(void); ++static int obp_devopen(char *str); ++static int obp_devclose(int dev_desc); ++static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf); ++ ++static void doublewalk(unsigned ptab1, unsigned va) ++{ ++unsigned int proc_tablewalk(int ctx, unsigned int va); ++unsigned int mem_tablewalk(unsigned int pa, unsigned int va); ++ ++ proc_tablewalk(0, va); ++ if (ptab1 != 0) mem_tablewalk(ptab1, va); ++} ++ ++static struct linux_romvec romvec0; ++ ++void * ++init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, ++ const char *cmdline, char boot_device, int nographic) ++{ ++ int i; ++ ++ /* ++ * Avoid data segment allocations ++ */ ++ ptphys = totphys; ++ ptmap = totmap; ++ ptavail = totavail; ++ /* ++ * Form memory descriptors. ++ */ ++ for (i = 0; i < bankc; i++) { ++ totphys[i].theres_more = &totphys[i+1]; ++ totphys[i].start_adr = (char*) bankv[i].start; ++ totphys[i].num_bytes = bankv[i].length; ++ } ++ totphys[i-1].theres_more = 0; ++ ++ /* ++ * XXX Merged in normal PROM when full banks touch. ++ */ ++ for (i = 0; i < bankc; i++) { ++ unsigned bankbase = bankv[i].start; ++ unsigned banksize = bankv[i].length; ++ if (hiphybas > bankbase && ++ hiphybas < bankbase + banksize) { ++ banksize = hiphybas - bankbase; ++ } ++ totavail[i].theres_more = &totavail[i+1]; ++ totavail[i].start_adr = (char*) bankbase; ++ totavail[i].num_bytes = banksize; ++ } ++ totavail[i-1].theres_more = 0; ++ ++ totmap[0].theres_more = 0; ++ totmap[0].start_adr = (char*) PROLBASE; ++ totmap[0].num_bytes = PROLSIZE; ++ ++ /* ++ * idprom ++ */ ++ bcopy(idprom, obp_idprom, IDPROM_SIZE); ++ ++ // Linux wants a R/W romvec table ++ romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; ++ romvec0.pv_plugin_revision = 77; ++ romvec0.pv_printrev = 0x10203; ++ romvec0.pv_v0mem.v0_totphys = &ptphys; ++ romvec0.pv_v0mem.v0_prommap = &ptmap; ++ romvec0.pv_v0mem.v0_available = &ptavail; ++ romvec0.pv_nodeops = &nodeops0; ++ romvec0.pv_bootstr = (void *)doublewalk; ++ romvec0.pv_v0devops.v0_devopen = &obp_devopen; ++ romvec0.pv_v0devops.v0_devclose = &obp_devclose; ++ romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev; ++ romvec0.pv_stdin = &obp_stdin; ++ romvec0.pv_stdout = &obp_stdout; ++ romvec0.pv_getchar = obp_nbgetchar; ++ romvec0.pv_putchar = (void (*)(int))obp_nbputchar; ++ romvec0.pv_nbgetchar = obp_nbgetchar; ++ romvec0.pv_nbputchar = obp_nbputchar; ++ romvec0.pv_reboot = obp_reboot; ++ romvec0.pv_abort = obp_abort; ++ romvec0.pv_halt = obp_halt; ++ romvec0.pv_synchook = &synch_hook; ++ romvec0.pv_v0bootargs = &obp_argp; ++ switch(boot_device) { ++ default: ++ case 'a': ++ obp_arg.argv[0] = "fd()"; ++ break; ++ case 'c': ++ obp_arg.argv[0] = "sd()"; ++ break; ++ case 'n': ++ obp_arg.argv[0] = "le()"; ++ break; ++ } ++ obp_arg.argv[1] = cmdline; ++ ++ if (nographic) { ++ obp_stdin = PROMDEV_TTYA; ++ obp_stdout = PROMDEV_TTYA; ++ } else { ++ obp_stdin = PROMDEV_KBD; ++ obp_stdout = PROMDEV_SCREEN; ++ } ++ return &romvec0; ++} ++ ++static const struct property *find_property(int node,char *name) ++{ ++ const struct property *prop = &nodes[node].properties[0]; ++ while (prop && prop->name) { ++ if (bcmp(prop->name, name, 128) == 0) return prop; ++ prop++; ++ } ++ return NULL; ++} ++ ++static int obp_nextnode(int node) ++{ ++#ifdef DEBUG_OBP ++ printk("obp_nextnode(%d) = %d\n", node, nodes[node].sibling); ++#endif ++ return nodes[node].sibling; ++} ++ ++static int obp_child(int node) ++{ ++#ifdef DEBUG_OBP ++ printk("obp_child(%d) = %d\n", node, nodes[node].child); ++#endif ++ return nodes[node].child; ++} ++ ++static int obp_proplen(int node, char *name) ++{ ++ const struct property *prop = find_property(node,name); ++ if (prop) { ++#ifdef DEBUG_OBP ++ printk("obp_proplen(%d, %s) = %d\n", node, name, prop->length); ++#endif ++ return prop->length; ++ } ++#ifdef DEBUG_OBP ++ printk("obp_proplen(%d, %s) (no prop)\n", node, name); ++#endif ++ return -1; ++} ++ ++static int obp_getprop(int node, char *name, char *value) ++{ ++ const struct property *prop; ++ ++ prop = find_property(node,name); ++ if (prop) { ++ memcpy(value,prop->value,prop->length); ++#ifdef DEBUG_OBP ++ printk("obp_getprop(%d, %s) = %s\n", node, name, value); ++#endif ++ return prop->length; ++ } ++#ifdef DEBUG_OBP ++ printk("obp_getprop(%d, %s): not found\n", node, name); ++#endif ++ return -1; ++} ++ ++static int obp_setprop(int node, char *name, char *value, int len) ++{ ++#ifdef DEBUG_OBP ++ printk("obp_setprop(%d, %s) = %s (%d)\n", node, name, value, len); ++#endif ++ return -1; ++} ++ ++static const char *obp_nextprop(int node,char *name) ++{ ++ const struct property *prop = find_property(node,name); ++ if (prop) { ++#ifdef DEBUG_OBP ++ printk("obp_nextprop(%d, %s) = %s\n", node, name, prop[1].name); ++#endif ++ return prop[1].name; ++ } ++#ifdef DEBUG_OBP ++ printk("obp_nextprop(%d, %s): not found\n", node, name); ++#endif ++ return NULL; ++} ++ ++static int obp_nbgetchar(void) { ++ extern struct vconterm dp0; ++ return vcon_getch(&dp0); ++} ++ ++static int obp_nbputchar(int ch) { ++ printk("%c", ch); ++ return 0; ++} ++ ++static void obp_reboot(char *str) { ++ printk("rebooting (%s): not implemented, freezing\n", str); ++ for (;;) {} ++} ++ ++static void obp_abort() { ++ printk("abort, freezing\n"); ++ for (;;) {} ++} ++ ++static void obp_halt() { ++ printk("halt, freezing\n"); ++ for (;;) {} ++} ++ ++static int obp_devopen(char *str) { ++#ifdef DEBUG_OBP ++ printk("open %s\n", str); ++#endif ++ return 0; ++} ++ ++static int obp_devclose(int dev_desc) { ++#ifdef DEBUG_OBP ++ printk("close %d\n", dev_desc); ++#endif ++ return 0; ++} ++ ++static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf) { ++#ifdef DEBUG_OBP ++ printk("rdblkdev: fd %d, num_blks %d, blk_st %d, buf 0x%x\n", dev_desc, num_blks, blk_st, buf); ++#endif ++ //buf[8] = 'L'; ++ return num_blks; ++} +diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch7/qemu/system_qemu.c +--- proll_18.orig/qemu/system_qemu.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch7/qemu/system_qemu.c 2005-03-02 16:10:20.000000000 +0000 +@@ -0,0 +1,416 @@ ++/** ++ ** Proll (PROM replacement) ++ ** system.c: shared miscallenea. ++ ** Copyright 1999 Pete Zaitcev ++ ** This code is licensed under GNU General Public License. ++ **/ ++#include ++#include ++#include ++#ifndef NULL ++#define NULL ((void*)0) ++#endif ++ ++#include "pgtsrmmu.h" ++ ++#include "vconsole.h" ++#include /* Local copy of 2.2 style include */ ++#include /* __P() */ ++#include /* init_net() */ ++#include /* we are a provider for part of this. */ ++#include /* myipaddr */ ++#include ++#include /* our own prototypes */ ++ ++/* ++ * We export this. ++ */ ++char idprom[IDPROM_SIZE]; ++ ++ ++/* ++ * Create an I/O mapping to pa[size]. ++ * Returns va of the mapping or 0 if unsuccessful. ++ */ ++void * ++map_io(unsigned pa, int size) ++{ ++ void *va; ++ unsigned int npages; ++ unsigned int off; ++ unsigned int mva; ++ ++ off = pa & (PAGE_SIZE-1); ++ npages = (off + size + (PAGE_SIZE-1)) / PAGE_SIZE; ++ pa &= ~(PAGE_SIZE-1); ++ ++ va = mem_alloc(&cio, npages*PAGE_SIZE, PAGE_SIZE); ++ if (va == 0) return va; ++ ++ mva = (unsigned int) va; ++ /* printk("map_io: va 0x%x pa 0x%x off 0x%x npages %d\n", va, pa, off, npages); */ /* P3 */ ++ while (npages-- != 0) { ++ map_page(pmem.pl1, mva, pa, 1, pmem.pbas); ++ mva += PAGE_SIZE; ++ pa += PAGE_SIZE; ++ } ++ ++ return (void *)((unsigned int)va + off); ++} ++ ++/* ++ * Tablewalk routine used for testing. ++ * Returns PTP/PTE. ++ */ ++unsigned int ++proc_tablewalk(int ctx, unsigned int va) ++{ ++ unsigned int pa1; ++ ++ __asm__ __volatile__ ("lda [%1] %2, %0" : ++ "=r" (pa1) : ++ "r" (AC_M_CTPR), "i" (ASI_M_MMUREGS)); ++ /* printk(" ctpr %x ctx %x\n", pa1, ctx); */ /* P3 */ ++ pa1 <<= 4; ++ pa1 = ld_bypass(pa1 + (ctx << 2)); ++ if ((pa1 & 0x03) == 0) goto invalid; ++ return mem_tablewalk((pa1 & 0xFFFFFFF0) << 4, va); ++ ++invalid: ++ printk(" invalid %x\n", pa1); ++ return 0; ++} ++ ++/* ++ * Walk the tables in memory, starting at physical address pa. ++ */ ++unsigned int ++mem_tablewalk(unsigned int pa, unsigned int va) ++{ ++ unsigned int pa1; ++ ++ printk("pa %x va %x", pa, va); ++ pa1 = ld_bypass(pa + (((va&0xFF000000)>>24) << 2)); ++ if ((pa1 & 0x03) == 0) goto invalid; ++ printk(" l1 %x", pa1); ++ pa1 <<= 4; pa1 &= 0xFFFFFF00; ++ pa1 = ld_bypass(pa1 + (((va&0x00FC0000)>>18) << 2)); ++ if ((pa1 & 0x03) == 0) goto invalid; ++ printk(" l2 %x", pa1); ++ pa1 <<= 4; pa1 &= 0xFFFFFF00; ++ pa1 = ld_bypass(pa1 + (((va&0x0003F000)>>12) << 2)); ++ if ((pa1 & 0x03) == 0) goto invalid; ++ printk(" l3 %x", pa1); ++ printk(" off %x\n", va&0x00000FFF); ++ return pa1; ++invalid: ++ printk(" invalid %x\n", pa1); ++ return 0; ++} ++ ++/* ++ * Make CPU page tables. ++ * Returns pointer to context table. ++ * Here we ignore memory allocation errors which "should not happen" ++ * because we cannot print anything anyways if memory initialization fails. ++ */ ++void makepages(struct phym *t, unsigned int highbase) ++{ ++ unsigned int *ctp, *l1, pte; ++ int i; ++ unsigned int pa, va; ++ ++ ctp = mem_zalloc(&cmem, NCTX_SWIFT*sizeof(int), NCTX_SWIFT*sizeof(int)); ++ l1 = mem_zalloc(&cmem, 256*sizeof(int), 256*sizeof(int)); ++ ++ pte = SRMMU_ET_PTD | (((unsigned int)l1 - PROLBASE + highbase) >> 4); ++ for (i = 0; i < NCTX_SWIFT; i++) { ++ ctp[i] = pte; ++ } ++ ++ pa = PROLBASE; ++ for (va = PROLBASE; va < PROLDATA; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } ++ pa = highbase + PROLDATA - PROLBASE; ++ for (va = PROLDATA; va < PROLBASE + PROLSIZE; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } ++ ++ /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ ++ pa = 0; ++ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { ++ map_page(l1, va, pa, 0, highbase); ++ pa += PAGE_SIZE; ++ } + -+static int obp_nbgetchar(void); -+static int obp_nbputchar(int ch); -+static void obp_reboot(char *); -+static void obp_abort(void); -+static void obp_halt(void); -+static int obp_devopen(char *str); -+static int obp_devclose(int dev_desc); -+static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf); ++ t->pctp = ctp; ++ t->pl1 = l1; ++ t->pbas = highbase; ++} + -+static void doublewalk(unsigned ptab1, unsigned va) ++/* ++ * Create a memory mapping from va to epa in page table pgd. ++ * highbase is used for v2p translation. ++ */ ++int ++map_page(unsigned int *pgd, unsigned int va, ++ unsigned int epa, int type, unsigned int highbase) +{ -+unsigned int proc_tablewalk(int ctx, unsigned int va); -+unsigned int mem_tablewalk(unsigned int pa, unsigned int va); -+ -+ proc_tablewalk(0, va); -+ if (ptab1 != 0) mem_tablewalk(ptab1, va); -+} ++ unsigned int pte; ++ unsigned int *p; ++ unsigned int pa; ++ ++ pte = pgd[((va)>>SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD-1)]; ++ if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { ++ p = mem_zalloc(&cmem, SRMMU_PTRS_PER_PMD*sizeof(int), ++ SRMMU_PTRS_PER_PMD*sizeof(int)); ++ if (p == 0) goto drop; ++ pte = SRMMU_ET_PTD | ++ (((unsigned int)p - PROLBASE + highbase) >> 4); ++ pgd[((va)>>SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD-1)] = pte; ++ /* barrier() */ ++ } + -+#ifdef ORIG -+static const struct linux_romvec romvec0 = { -+ LINUX_OPPROM_MAGIC, /* pv_magic_cookie */ -+ 0, /* pv_romvers - Format selector! */ -+ 77, /* pv_plugin_revision */ -+ 0x10203, /* pv_printrev */ -+ { /* pv_v0mem */ -+ &ptphys, /* v0_totphys */ -+ &ptmap, /* v0_prommap */ -+ &ptavail /* v0_available */ -+ }, -+ &nodeops0, /* struct linux_nodeops *pv_nodeops; */ -+ (void*)doublewalk, /* P3 */ /* char **pv_bootstr; */ -+ { /* struct linux_dev_v0_funcs pv_v0devops; */ -+ &obp_devopen, /* v0_devopen */ -+ &obp_devclose, /* v0_devclose */ -+ &obp_rdblkdev, /* v0_rdblkdev */ -+ NULL, /* v0_wrblkdev */ -+ NULL, /* v0_wrnetdev */ -+ NULL, /* v0_rdnetdev */ -+ NULL, /* v0_rdchardev */ -+ NULL, /* v0_wrchardev */ -+ NULL /* v0_seekdev */ -+ }, -+ &obp_stdin, /* char *pv_stdin */ -+ &obp_stdout, /* char *pv_stdout; */ -+ obp_nbgetchar, /* int (*pv_getchar)(void); */ -+ obp_nbputchar, /* void (*pv_putchar)(int ch); */ -+ obp_nbgetchar, /* int (*pv_nbgetchar)(void); */ -+ obp_nbputchar, /* int (*pv_nbputchar)(int ch); */ -+ NULL, /* void (*pv_putstr)(char *str, int len); */ -+ obp_reboot, /* void (*pv_reboot)(char *bootstr); */ -+ NULL, /* void (*pv_printf)(__const__ char *fmt, ...); */ -+ obp_abort, /* void (*pv_abort)(void); */ -+ NULL, /* __volatile__ int *pv_ticks; */ -+ obp_halt, /* void (*pv_halt)(void); */ -+ (void *)&synch_hook, /* void (**pv_synchook)(void); */ ++ pa = ((pte & 0xFFFFFFF0) << 4); ++ pa += (((va)>>SRMMU_PMD_SHIFT & (SRMMU_PTRS_PER_PMD-1)) << 2); ++ pte = ld_bypass(pa); ++ if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { ++ p = mem_zalloc(&cmem, SRMMU_PTRS_PER_PTE*sizeof(int), ++ SRMMU_PTRS_PER_PTE*sizeof(int)); ++ if (p == 0) goto drop; ++ pte = SRMMU_ET_PTD | ++ (((unsigned int)p - PROLBASE + highbase) >> 4); ++ st_bypass(pa, pte); ++ } + -+#if 0 -+ /* Evaluate a forth string, not different proto for V0 and V2->up. */ -+ union { -+ void (*v0_eval)(int len, char *str); -+ void (*v2_eval)(char *str); -+ } pv_fortheval; -+#endif -+ { 0 }, /* pv_fortheval */ -+ -+ &obp_argp, /* struct linux_arguments_v0 **pv_v0bootargs; */ -+ NULL, /* pv_enaddr */ -+ { /* pv_v2bootargs */ -+ NULL, /* char **bootpath; */ -+ NULL, /* char **bootargs; */ -+ NULL, /* fd_stdin; */ -+ NULL, /* fd_stdout */ -+ }, -+ { /* pv_v2devops */ -+ NULL, /* v2_inst2pkg */ -+ NULL, /* v2_dumb_mem_alloc */ -+ NULL, /* v2_dumb_mem_free */ -+ NULL, /* v2_dumb_mmap */ -+ NULL, /* v2_dumb_munmap */ -+ NULL, /* v2_dev_open */ -+ NULL, /* v2_dev_close */ -+ NULL, /* v2_dev_read */ -+ NULL, /* v2_dev_write */ -+ NULL, /* v2_dev_seek */ -+ NULL, /* v2_wheee2 */ -+ NULL, /* v2_wheee3 */ -+ }, -+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* filler[15] */ -+ NULL, /* pv_setctxt */ -+ NULL, /* v3_cpustart */ -+ NULL, /* v3_cpustop */ -+ NULL, /* v3_cpuidle */ -+ NULL /* v3_cpuresume */ -+}; -+#endif ++ pa = ((pte & 0xFFFFFFF0) << 4); ++ pa += (((va)>>PAGE_SHIFT & (SRMMU_PTRS_PER_PTE-1)) << 2); ++ ++ pte = SRMMU_ET_PTE | ((epa & PAGE_MASK) >> 4); ++ if (type) { /* I/O */ ++ pte |= SRMMU_REF; ++ /* SRMMU cannot make Supervisor-only, but not exectutable */ ++ pte |= SRMMU_PRIV; ++ } else { /* memory */ ++ pte |= SRMMU_REF|SRMMU_CACHE; ++ pte |= SRMMU_PRIV; /* Supervisor only access */ ++ } ++ st_bypass(pa, pte); ++ return 0; + -+static struct linux_romvec romvec0; ++drop: ++ return -1; ++} + -+void * -+init_openprom(int bankc, struct bank *bankv, unsigned hiphybas) ++/* ++ * Switch page tables. ++ */ ++void ++init_mmu_swift(unsigned int ctp_phy) +{ -+ int i; ++ unsigned int addr; + + /* -+ * Avoid data segment allocations -+ */ -+ ptphys = totphys; -+ ptmap = totmap; -+ ptavail = totavail; -+ /* -+ * Form memory descriptors. ++ * Flush cache + */ -+ for (i = 0; i < bankc; i++) { -+ totphys[i].theres_more = &totphys[i+1]; -+ totphys[i].start_adr = (char*) bankv[i].start; -+ totphys[i].num_bytes = bankv[i].length; ++ for (addr = 0; addr < 0x2000; addr += 0x10) { ++ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : ++ "r" (addr), "i" (ASI_M_DATAC_TAG)); ++ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : ++ "r" (addr<<1), "i" (ASI_M_TXTC_TAG)); + } -+ totphys[i-1].theres_more = 0; + + /* -+ * XXX Merged in normal PROM when full banks touch. ++ * Switch ctx table + */ -+ for (i = 0; i < bankc; i++) { -+ unsigned bankbase = bankv[i].start; -+ unsigned banksize = bankv[i].length; -+ if (hiphybas > bankbase && -+ hiphybas < bankbase + banksize) { -+ banksize = hiphybas - bankbase; -+ } -+ totavail[i].theres_more = &totavail[i+1]; -+ totavail[i].start_adr = (char*) bankbase; -+ totavail[i].num_bytes = banksize; -+ } -+ totavail[i-1].theres_more = 0; -+ -+ totmap[0].theres_more = 0; -+ totmap[0].start_adr = (char*) PROLBASE; -+ totmap[0].num_bytes = PROLSIZE; ++ ctp_phy >>= 4; ++ /* printk("done flushing, switching to %x\n", ctp_phy); */ ++ __asm__ __volatile__ ("sta %0, [%1] %2\n\t" : : ++ "r" (ctp_phy), "r" (AC_M_CTPR), "i" (ASI_M_MMUREGS)); + + /* -+ * idprom ++ * Flush old page table references + */ -+ bcopy(idprom, obp_idprom, IDPROM_SIZE); -+ -+ // Linux wants a R/W romvec table -+ romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; -+ romvec0.pv_plugin_revision = 77; -+ romvec0.pv_printrev = 0x10203; -+ romvec0.pv_v0mem.v0_totphys = &ptphys; -+ romvec0.pv_v0mem.v0_prommap = &ptmap; -+ romvec0.pv_v0mem.v0_available = &ptavail; -+ romvec0.pv_nodeops = &nodeops0; -+ romvec0.pv_bootstr = (void *)doublewalk; -+ romvec0.pv_stdin = &obp_stdin; -+ romvec0.pv_stdout = &obp_stdout; -+ romvec0.pv_getchar = obp_nbgetchar; -+ romvec0.pv_putchar = obp_nbputchar; -+ romvec0.pv_nbgetchar = obp_nbgetchar; -+ romvec0.pv_nbputchar = obp_nbputchar; -+ romvec0.pv_reboot = obp_reboot; -+ romvec0.pv_abort = obp_abort; -+ romvec0.pv_halt = obp_halt; -+ romvec0.pv_synchook = &synch_hook; -+ romvec0.pv_v0bootargs = &obp_argp; -+ return &romvec0; ++ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : ++ "r" (0x400), "i" (ASI_M_FLUSH_PROBE) : "memory"); +} + -+static const struct property *find_property(int node,char *name) -+{ -+ const struct property *prop = &nodes[node].properties[0]; -+ while (prop && prop->name) { -+ if (bcmp(prop->name, name, 128) == 0) return prop; -+ prop++; ++/* ++ * add_timer, del_timer ++ * This should go into sched.c, but we have it split for different archs. ++ */ ++struct timer_list_head { ++ struct timer_list *head, *tail; ++}; ++ ++static struct timer_list_head timers; /* Anonymous heap of timers */ ++ ++void add_timer(struct timer_list *timer) { ++ struct timer_list *p; ++ if (timer->prev != NULL || timer->next != NULL) { ++ printk("bug: kernel timer added twice at 0x%x.\n", ++ __builtin_return_address(0)); ++ return; + } -+ return NULL; ++ if ((p = timers.tail) != NULL) { ++ timer->prev = p; ++ p->next = timer; ++ timers.tail = timer; ++ } else { ++ timers.head = timer; ++ timers.tail = timer; ++ } ++ return; +} + -+static int obp_nextnode(int node) -+{ -+ return nodes[node].sibling; ++int del_timer(struct timer_list *timer) { ++ struct timer_list *p; ++ int ret; ++ ++ if (timers.head == timer) timers.head = timer->next; ++ if (timers.tail == timer) timers.tail = timer->prev; ++ if ((p = timer->prev) != NULL) p->next = timer->next; ++ if ((p = timer->next) != NULL) p->prev = timer->prev; ++ ret = timer->next != 0 || timer->prev != 0; ++ timer->next = NULL; ++ timer->prev = NULL; ++ return ret; +} + -+static int obp_child(int node) -+{ -+ return nodes[node].child; ++void run_timers() { ++ struct timer_list *p; ++ ++ p = timers.head; ++ while (p != NULL) { ++ if (p->expires < jiffies) { ++ del_timer(p); /* XXX make nonstatic member */ ++ (*p->function)(p->data); ++ p = timers.head; ++ } else { ++ p = p->next; ++ } ++ } +} + -+static int obp_proplen(int node, char *name) ++/* ++ * Allocate memory. This is reusable. ++ */ ++void mem_init(struct mem *t, char *begin, char *limit) +{ -+ const struct property *prop = find_property(node,name); -+ if (prop) return prop->length; -+ return -1; ++ t->start = begin; ++ t->uplim = limit; ++ t->curp = begin; +} + -+static int obp_getprop(int node, char *name, char *value) ++void mem_fini(struct mem *t) +{ -+ const struct property *prop; -+ -+ prop = find_property(node,name); -+ if (prop) { -+ memcpy(value,prop->value,prop->length); -+ //printk("obp_getprop '%s'= %s\n", name, value); -+ return prop->length; -+ } -+ //printk("obp_getprop: not found\n"); -+ return -1; ++ t->curp = 0; +} + -+static int obp_setprop(int node, char *name, char *value, int len) ++void *mem_alloc(struct mem *t, int size, int align) +{ -+ return -1; -+} ++ char *p; + -+static const char *obp_nextprop(int node,char *name) -+{ -+ const struct property *prop = find_property(node,name); -+ if (prop) return prop[1].name; -+ return NULL; ++ p = (char *)((((unsigned int)t->curp) + (align-1)) & ~(align-1)); ++ if (p >= t->uplim || p + size > t->uplim) return 0; ++ t->curp = p + size; ++ return p; +} + -+#if 0 -+static unsigned char calc_idprom_cksum(struct idprom *idprom) ++void *mem_zalloc(struct mem *t, int size, int align) +{ -+ unsigned char cksum, i, *ptr = (unsigned char *)idprom; -+ -+ for (i = cksum = 0; i <= 0x0E; i++) -+ cksum ^= *ptr++; ++ char *p; + -+ return cksum; ++ if ((p = mem_alloc(t, size, align)) != 0) bzero(p, size); ++ return p; +} -+#endif + -+static int obp_nbgetchar(void) { -+ return -1; ++/* ++ * Library functions ++ */ ++void bzero(void *s, int len) { ++ while (len--) *((char *)s)++ = 0; +} + -+static int obp_nbputchar(int ch) { -+ extern struct vconterm dp0; -+ char buf = ch; ++void bcopy(const void *f, void *t, int len) { ++ while (len--) *((char *)t)++ = *((char *)f)++; ++} + -+ /* We do not use printk() in order to reduce stack depth. */ -+ vcon_write(&dp0, &buf, 1); ++/* Comparison is 7-bit */ ++int bcmp(const void *s1, const void *s2, int len) ++{ ++ int i; ++ char ch; ++ ++ while (len--) { ++ ch = *((char *)s1)++; ++ if ((i = ch - *((char *)s2)++) != 0) ++ return i; ++ if (ch == 0) ++ return 0; ++ } + return 0; +} + -+static void obp_reboot(char *str) { -+ printk("rebooting (%s): not implemented, freezing\n", str); -+ for (;;) {} ++int strlen(const char *s) { ++ const char *p; ++ for (p = s; *p != 0; p++) { } ++ return p - s; +} + -+static void obp_abort() { -+ printk("abort, freezing\n"); -+ for (;;) {} -+} ++extern void *printk_fn; + -+static void obp_halt() { -+ printk("halt, freezing\n"); -+ for (;;) {} ++void printk(char *fmt, ...) ++{ ++ struct prf_fp { ++ void *xfp; ++ void (*write)(void *, char *, int); ++ } prfa; ++ extern void prf(struct prf_fp *, char *fmt, va_list adx); ++ va_list x1; ++ ++ va_start(x1, fmt); ++ prfa.xfp = &dp0; ++ prfa.write = printk_fn; ++ prf(&prfa, fmt, x1); ++ va_end(x1); +} + -+static int obp_devopen(char *str) { -+ //printk("open %s\n", str); -+ return 0; ++void fatal() ++{ ++ printk("fatal."); ++loop: goto loop; +} + -+static int obp_devclose(int dev_desc) { -+ //printk("close %d\n", dev_desc); -+ return 0; ++/* ++ * Get the highest bit number from the mask. ++ */ ++int highc(int mask, int size) ++{ ++ int m1; ++ ++ m1 = 1 << size; ++ while (size != 0) { ++ size--; ++ m1 >>= 1; ++ if (m1 & mask) break; ++ } ++ return size; +} + -+static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf) { -+ //printk("rdblkdev: fd %d, num_blks %d, blk_st %d, buf 0x%x\n", dev_desc, num_blks, blk_st, buf); -+ //buf[8] = 'L'; -+ return num_blks; ++/* ++ */ ++unsigned int ld_bp_swap(unsigned int ptr) { ++ unsigned int n; ++ n = ld_bypass(ptr); ++ n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); ++ return n; +} -diff -ruN proll_18.orig/src/arp.c proll-patch4/src/arp.c ++ ++void st_bp_swap(unsigned int ptr, unsigned int n) { ++ n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); ++ st_bypass(ptr, n); ++}; +diff -ruN proll_18.orig/src/arp.c proll-patch7/src/arp.c --- proll_18.orig/src/arp.c 2001-12-24 05:12:31.000000000 +0000 -+++ proll-patch4/src/arp.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/arp.c 2004-11-13 15:50:49.000000000 +0000 @@ -45,7 +45,7 @@ #endif static struct arp_cache arp_list[ARPNUM]; /* ARP address cache */ @@ -1475,9 +1967,9 @@ diff -ruN proll_18.orig/src/arp.c proll-patch4/src/arp.c + def_gw = IP_ANY; return(TRUE); } -diff -ruN proll_18.orig/src/arp.h proll-patch4/src/arp.h +diff -ruN proll_18.orig/src/arp.h proll-patch7/src/arp.h --- proll_18.orig/src/arp.h 1999-03-18 03:39:43.000000000 +0000 -+++ proll-patch4/src/arp.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/arp.h 2004-11-13 15:50:49.000000000 +0000 @@ -104,7 +104,7 @@ extern int init_arp __P((void)); @@ -1487,24 +1979,35 @@ diff -ruN proll_18.orig/src/arp.h proll-patch4/src/arp.h /* Add a new antry to the ARP cache */ extern void addcache __P((unsigned char *ha, t_ipaddr ip)); -diff -ruN proll_18.orig/src/hconsole.c proll-patch4/src/hconsole.c +diff -ruN proll_18.orig/src/hconsole.c proll-patch7/src/hconsole.c --- proll_18.orig/src/hconsole.c 2002-07-23 05:52:48.000000000 +0000 -+++ proll-patch4/src/hconsole.c 2004-11-13 15:50:49.000000000 +0000 -@@ -42,7 +42,11 @@ ++++ proll-patch7/src/hconsole.c 2005-03-02 17:03:09.000000000 +0000 +@@ -29,6 +29,10 @@ + struct raster r_master; /* For a case of resize, whole fb */ + struct raster r_0; /* malloc() erzatz */ + ++#ifdef QEMU ++extern unsigned int q_height, q_width; ++#endif ++ + int hcon_init(struct hconsole *t, unsigned int a0) + { + struct raster *q, *r; +@@ -42,7 +46,11 @@ * No probing sequence or argument passing, hardcode everything. XXX */ raster8_cons_a(q, 768, 1024, (char *)a0); -+#if 1 ++#ifndef QEMU raster_cons_2(r, q, 768-(24*11)-1, 1024-(8*80)-1, (24*11), (8*80)); +#else -+ raster_cons_2(r, q, 0, 0, 768, 1024); ++ raster_cons_2(r, q, 0, 0, q_height, q_width); +#endif t->r_ = r; t->r0_ = q; t->f_ = &f_master; -diff -ruN proll_18.orig/src/lat7_2.bm proll-patch4/src/lat7_2.bm +diff -ruN proll_18.orig/src/lat7_2.bm proll-patch7/src/lat7_2.bm --- proll_18.orig/src/lat7_2.bm 1999-02-27 05:48:54.000000000 +0000 -+++ proll-patch4/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 @@ -1,6 +1,6 @@ #define lat7_2_width 128 #define lat7_2_height 88 @@ -1513,9 +2016,9 @@ diff -ruN proll_18.orig/src/lat7_2.bm proll-patch4/src/lat7_2.bm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18, 0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02, -diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch4/src/lat7_2_swapped.bm +diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch7/src/lat7_2_swapped.bm --- proll_18.orig/src/lat7_2_swapped.bm 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch4/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 @@ -0,0 +1,121 @@ +#define lat7_2_width 128 +#define lat7_2_height 88 @@ -1638,9 +2141,9 @@ diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch4/src/lat7_2_swapped.bm + 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; -diff -ruN proll_18.orig/src/le.c proll-patch4/src/le.c +diff -ruN proll_18.orig/src/le.c proll-patch7/src/le.c --- proll_18.orig/src/le.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch4/src/le.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/le.c 2004-11-13 15:50:49.000000000 +0000 @@ -185,8 +185,6 @@ unsigned short rap; /* register address port */ }; @@ -1650,9 +2153,9 @@ diff -ruN proll_18.orig/src/le.c proll-patch4/src/le.c /* The Lance uses 24 bit addresses */ /* On the Sun4c the DVMA will provide the remaining bytes for us */ /* On the Sun4m we have to instruct the ledma to provide them */ -diff -ruN proll_18.orig/src/netinit.c proll-patch4/src/netinit.c +diff -ruN proll_18.orig/src/netinit.c proll-patch7/src/netinit.c --- proll_18.orig/src/netinit.c 2002-09-13 21:53:33.000000000 +0000 -+++ proll-patch4/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 @@ -49,13 +49,20 @@ unsigned char myhwaddr[ETH_ALEN]; /* my own hardware addr */ t_ipaddr myipaddr; /* my own IP address */ @@ -1696,9 +2199,9 @@ diff -ruN proll_18.orig/src/netinit.c proll-patch4/src/netinit.c fatal(); } } -diff -ruN proll_18.orig/src/netpriv.h proll-patch4/src/netpriv.h +diff -ruN proll_18.orig/src/netpriv.h proll-patch7/src/netpriv.h --- proll_18.orig/src/netpriv.h 1999-04-27 05:39:37.000000000 +0000 -+++ proll-patch4/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 @@ -130,10 +130,9 @@ * */ @@ -1720,9 +2223,9 @@ diff -ruN proll_18.orig/src/netpriv.h proll-patch4/src/netpriv.h /* Empty read buffer */ extern void empty_buf __P((void)); -diff -ruN proll_18.orig/src/openprom.h proll-patch4/src/openprom.h +diff -ruN proll_18.orig/src/openprom.h proll-patch7/src/openprom.h --- proll_18.orig/src/openprom.h 2002-07-14 02:26:30.000000000 +0000 -+++ proll-patch4/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 @@ -54,20 +54,20 @@ }; @@ -1784,9 +2287,9 @@ diff -ruN proll_18.orig/src/openprom.h proll-patch4/src/openprom.h }; /* More fun PROM structures for device probing. */ -diff -ruN proll_18.orig/src/packet.c proll-patch4/src/packet.c +diff -ruN proll_18.orig/src/packet.c proll-patch7/src/packet.c --- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000 -+++ proll-patch4/src/packet.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/packet.c 2004-11-13 15:50:49.000000000 +0000 @@ -41,7 +41,7 @@ int aligner; } wbuf; @@ -1814,9 +2317,9 @@ diff -ruN proll_18.orig/src/packet.c proll-patch4/src/packet.c { struct sk_buff *skb; unsigned char *s; -diff -ruN proll_18.orig/src/printf.c proll-patch4/src/printf.c +diff -ruN proll_18.orig/src/printf.c proll-patch7/src/printf.c --- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000 -+++ proll-patch4/src/printf.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/printf.c 2004-11-13 15:50:49.000000000 +0000 @@ -19,7 +19,7 @@ static void printn(struct prf_fp *, unsigned long, unsigned int); static void putchar(char, struct prf_fp *); @@ -1844,9 +2347,9 @@ diff -ruN proll_18.orig/src/printf.c proll-patch4/src/printf.c putchar(c,filog); } else if (c == 'l' || c == 'O') { printn(filog, (long)va_arg(adx,long), c=='l'?10:8); -diff -ruN proll_18.orig/src/rconsole.c proll-patch4/src/rconsole.c +diff -ruN proll_18.orig/src/rconsole.c proll-patch7/src/rconsole.c --- proll_18.orig/src/rconsole.c 1999-01-16 07:16:55.000000000 +0000 -+++ proll-patch4/src/rconsole.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/rconsole.c 2004-11-13 15:50:49.000000000 +0000 @@ -28,12 +28,18 @@ * move to California. Only plain lat7 survived. * I recreated lat7-1 changes in lat7-2. --zaitcev @@ -1901,9 +2404,9 @@ diff -ruN proll_18.orig/src/rconsole.c proll-patch4/src/rconsole.c p->nchars_ = LAT7_NCHARS; p->width_ = LAT7_WIDTH; p->height_ = LAT7_HEIGHT; -diff -ruN proll_18.orig/src/rconsole.h proll-patch4/src/rconsole.h +diff -ruN proll_18.orig/src/rconsole.h proll-patch7/src/rconsole.h --- proll_18.orig/src/rconsole.h 1999-01-16 05:00:59.000000000 +0000 -+++ proll-patch4/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 @@ -13,10 +13,10 @@ */ @@ -1917,9 +2420,9 @@ diff -ruN proll_18.orig/src/rconsole.h proll-patch4/src/rconsole.h int nchars_; /* 128 for ASCII ... 65536 for Unicode */ int width_; /* [Pixels]. Maximum size is 16. */ int height_; /* [Pixels == scan lines]. */ -diff -ruN proll_18.orig/src/romlib.h proll-patch4/src/romlib.h +diff -ruN proll_18.orig/src/romlib.h proll-patch7/src/romlib.h --- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000 -+++ proll-patch4/src/romlib.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/romlib.h 2004-11-13 15:50:49.000000000 +0000 @@ -73,12 +73,12 @@ #define memcpy(dst, src, len) bcopy(src, dst, len) #define memcmp(x1, x2, len) bcmp(x1, x2, len) @@ -1936,9 +2439,9 @@ diff -ruN proll_18.orig/src/romlib.h proll-patch4/src/romlib.h /* -diff -ruN proll_18.orig/src/sched_4m.c proll-patch4/src/sched_4m.c +diff -ruN proll_18.orig/src/sched_4m.c proll-patch7/src/sched_4m.c --- proll_18.orig/src/sched_4m.c 1999-04-27 05:48:51.000000000 +0000 -+++ proll-patch4/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 @@ -108,7 +108,7 @@ static int set_bolt; /* Tick counter limit */ static struct handsc hndv[16]; @@ -1948,9 +2451,9 @@ diff -ruN proll_18.orig/src/sched_4m.c proll-patch4/src/sched_4m.c 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -diff -ruN proll_18.orig/src/swap.c proll-patch4/src/swap.c +diff -ruN proll_18.orig/src/swap.c proll-patch7/src/swap.c --- proll_18.orig/src/swap.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch4/src/swap.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/swap.c 2004-11-13 15:50:49.000000000 +0000 @@ -0,0 +1,21 @@ +// Convert the lat7 font so that no conversion is needed at runtime. +#define ORIG @@ -1973,9 +2476,9 @@ diff -ruN proll_18.orig/src/swap.c proll-patch4/src/swap.c + } + printf("\n"); +} -diff -ruN proll_18.orig/src/system.c proll-patch4/src/system.c +diff -ruN proll_18.orig/src/system.c proll-patch7/src/system.c --- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch4/src/system.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/system.c 2004-11-13 15:50:49.000000000 +0000 @@ -298,8 +298,8 @@ } @@ -2028,9 +2531,9 @@ diff -ruN proll_18.orig/src/system.c proll-patch4/src/system.c void fatal() { printk("fatal."); -diff -ruN proll_18.orig/src/system.h proll-patch4/src/system.h +diff -ruN proll_18.orig/src/system.h proll-patch7/src/system.h --- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000 -+++ proll-patch4/src/system.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/system.h 2004-11-13 15:50:49.000000000 +0000 @@ -16,7 +16,7 @@ #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */ #define NCTX_SWIFT 0x100 @@ -2040,9 +2543,9 @@ diff -ruN proll_18.orig/src/system.h proll-patch4/src/system.h #ifndef __ASSEMBLY__ struct bank { -diff -ruN proll_18.orig/src/udp.c proll-patch4/src/udp.c +diff -ruN proll_18.orig/src/udp.c proll-patch7/src/udp.c --- proll_18.orig/src/udp.c 2001-12-24 05:12:53.000000000 +0000 -+++ proll-patch4/src/udp.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch7/src/udp.c 2004-11-13 15:50:49.000000000 +0000 @@ -81,7 +81,7 @@ int source; int dest; @@ -2062,3 +2565,263 @@ diff -ruN proll_18.orig/src/udp.c proll-patch4/src/udp.c /* Register IP packet type and set write buffer pointer */ if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL) return(FALSE); +diff -ruN proll_18.orig/src/vcons_zs.c proll-patch7/src/vcons_zs.c +--- proll_18.orig/src/vcons_zs.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch7/src/vcons_zs.c 2005-03-02 12:07:41.000000000 +0000 +@@ -0,0 +1,68 @@ ++/** ++ ** Console over 'zs' (Zilog serial port) ++ ** Copyright 1999 Pete Zaitcev ++ ** This code is licensed under GNU General Public License. ++ **/ ++ ++#include "vconsole.h" ++#include ++ ++#define ZS_DATA 0x02 ++ ++int vcon_zs_init(struct vconterm *t, unsigned int a0) ++{ ++ ++ t->impl = (void *) a0; ++ ++ t->vc_x = 0; t->vc_y = 0; ++ t->backp = 0; t->backc = 0; ++ ++ stb_bypass(a0, 3); // reg 3 ++ stb_bypass(a0, 1); // enable rx ++ ++ stb_bypass(a0, 5); // reg 5 ++ stb_bypass(a0, 8); // enable tx ++ ++ return 0; ++} ++ ++int vcon_zs_putch(struct vconterm *t, char c) ++{ ++ unsigned zs_ptr = (unsigned) t->impl; ++ ++ //while ((ldb_bypass(zs_ptr + ZS_LSR) & 0x60) != 0x60) { } ++ stb_bypass(zs_ptr + ZS_DATA, c); ++ return 0; ++} ++ ++int vcon_zs_write(struct vconterm *t, char *data, int leng) ++{ ++ while (leng != 0) { ++ leng--; ++ vcon_zs_putch(t, *data++); ++ } ++ return leng; ++} ++ ++int vcon_zs_read(struct vconterm *t, char *data, int leng) ++{ ++ unsigned zs_ptr = (unsigned) t->impl; ++ ++ while ((ldb_bypass(zs_ptr) & 1) != 1) { } ++ *data = ldb_bypass(zs_ptr + ZS_DATA); ++ return 0; ++} ++ ++int vcon_zs_getch(struct vconterm *t) ++{ ++ unsigned zs_ptr = (unsigned) t->impl; ++ ++ while ((ldb_bypass(zs_ptr) & 1) != 1) { } ++ return ldb_bypass(zs_ptr + ZS_DATA); ++} ++ ++void vcon_zs_fini(struct vconterm *t) ++{ ++ /* violent crash in the end */ ++ ; ++} +diff -ruN proll_18.orig/src/vconsole.c proll-patch7/src/vconsole.c +--- proll_18.orig/src/vconsole.c 1999-11-08 03:10:28.000000000 +0000 ++++ proll-patch7/src/vconsole.c 2005-03-02 14:29:05.000000000 +0000 +@@ -13,6 +13,10 @@ + + struct hconsole hcons0; + ++enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, ++ EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, ++ ESpalette }; ++ + int vcon_init(struct vconterm *t, unsigned int a0) + { + struct hconsole *hconp; +@@ -25,11 +29,49 @@ + + t->vc_x = 0; t->vc_y = 0; + t->backp = 0; t->backc = 0; ++ t->vc_state = ESnormal; + + hcon_clear(hconp, 0, 0, hconp->ydim_, hconp->xdim_); + return 0; + } + ++/* ++ * gotoxy() must verify all boundaries, because the arguments ++ * might also be negative. If the given position is out of ++ * bounds, the cursor is placed at the nearest margin. ++ */ ++static void gotoxy(struct vconterm *vc, int new_x, int new_y) ++{ ++ int max_x, max_y; ++ struct hconsole *hconp = vc->impl; ++ ++ max_x = hcon_qxdim(hconp); ++ max_y = hcon_qydim(hconp); ++ ++ if (new_x < 0) ++ vc->vc_x = 0; ++ else { ++ if (new_x >= max_x) ++ vc->vc_x = max_x - 1; ++ else ++ vc->vc_x = new_x; ++ } ++ ++ if (new_y < 0) ++ vc->vc_y = 0; ++ else if (new_y >= max_y) ++ vc->vc_y = max_y - 1; ++ else ++ vc->vc_y = new_y; ++ ++} ++ ++/* for absolute user moves, when decom is set */ ++static void gotoxay(struct vconterm *t, int new_x, int new_y) ++{ ++ gotoxy(t, new_x, new_y); ++} ++ + int vcon_write(struct vconterm *t, char *data, int leng) + { + int l = leng; +@@ -40,29 +82,84 @@ + if (l <= 0) break; + c = *data++; --l; + +- switch (c) { +- case 0x07: /* Bell */ +- vcon_i_backflush(t); +- break; +- case 0x0A: /* Linefeed */ +- vcon_i_backflush(t); +- vcon_i_cursfeed(t); ++ switch(t->vc_state) { ++ case ESesc: ++ t->vc_state = ESnormal; ++ switch (c) { ++ case '[': ++ t->vc_state = ESsquare; ++ break; ++ case 'M': ++ hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); ++ break; ++ } + break; +- case 0x0D: /* Return */ +- vcon_i_backflush(t); +- t->vc_x = 0; ++ case ESsquare: ++ for(t->vc_npar = 0 ; t->vc_npar < NPAR ; t->vc_npar++) ++ t->vc_par[t->vc_npar] = 0; ++ t->vc_npar = 0; ++ t->vc_state = ESgetpars; ++ case ESgetpars: ++ if (c==';' && t->vc_nparvc_npar++; ++ break; ++ } else if (c>='0' && c<='9') { ++ t->vc_par[t->vc_npar] *= 10; ++ t->vc_par[t->vc_npar] += c-'0'; ++ break; ++ } else t->vc_state=ESgotpars; ++ case ESgotpars: ++ t->vc_state = ESnormal; ++ switch(c) { ++ case 'H': case 'f': ++ if (t->vc_par[0]) t->vc_par[0]--; ++ if (t->vc_par[1]) t->vc_par[1]--; ++ gotoxay(t, t->vc_par[1], t->vc_par[0]); ++ break; ++ case 'M': ++ hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); ++ break; ++ } + break; + default: +- if (t->backp == 0) { +- t->backc = 1; +- t->backp = data-1; +- } else { +- t->backc++; +- } +- if (t->vc_x + t->backc >= hcon_qxdim(hconp)) { ++ t->vc_state = ESnormal; ++ switch (c) { ++ case 0x07: /* Bell */ ++ vcon_i_backflush(t); ++ break; ++ case 0x08: /* BS */ ++ vcon_i_backflush(t); ++ if (t->vc_x > 0) ++ t->vc_x--; ++ break; ++ case 0x0A: /* Linefeed */ + vcon_i_backflush(t); +- t->vc_x = 0; + vcon_i_cursfeed(t); ++ break; ++ case 0x0D: /* Return */ ++ vcon_i_backflush(t); ++ t->vc_x = 0; ++ break; ++ case 24: case 26: ++ vcon_i_backflush(t); ++ t->vc_state = ESnormal; ++ break; ++ case 27: ++ vcon_i_backflush(t); ++ t->vc_state = ESesc; ++ break; ++ default: ++ if (t->backp == 0) { ++ t->backc = 1; ++ t->backp = data-1; ++ } else { ++ t->backc++; ++ } ++ if (t->vc_x + t->backc >= hcon_qxdim(hconp)) { ++ vcon_i_backflush(t); ++ t->vc_x = 0; ++ vcon_i_cursfeed(t); ++ } + } + } + } +diff -ruN proll_18.orig/src/vconsole.h proll-patch7/src/vconsole.h +--- proll_18.orig/src/vconsole.h 1999-11-08 00:58:13.000000000 +0000 ++++ proll-patch7/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 +@@ -6,6 +6,8 @@ + #ifndef VCONSOLE_H + #define VCONSOLE_H + ++#define NPAR 16 ++ + struct vconterm { + void *impl; + +@@ -13,6 +15,8 @@ + int backc; /* Same, count */ + + int vc_x, vc_y; /* XXX Make vcon_xxx() to use cellmap->xpos_ */ ++ int vc_state; ++ unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */ + }; + + int vcon_init(struct vconterm *t, unsigned int a0); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index bf28a3675..e6891ccbb 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -138,6 +138,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot } *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); + *physical = 0xfffff000; /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ @@ -210,7 +211,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot /* check access */ access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; error_code = access_table[*access_index][access_perms]; - if (error_code) + if (error_code && !(env->mmuregs[0] & MMU_NF)) return error_code; /* the page can be put in the TLB */ @@ -225,7 +226,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot /* Even if large ptes, we map only one 4KB page in the cache to avoid filling it too fast */ *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset; - return 0; + return error_code; } /* Perform address translation */ @@ -251,17 +252,14 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->mmuregs[4] = address; /* Fault address register */ if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { -#if 0 - // No fault + // No fault mode: if a mapping is available, just override + // permissions. If no mapping is available, redirect accesses to + // neverland. Fake/overridden mappings will be flushed when + // switching to normal mode. vaddr = address & TARGET_PAGE_MASK; - paddr = 0xfffff000; prot = PAGE_READ | PAGE_WRITE; ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; -#else - cpu_abort(env, "MMU no fault case no handled"); - return 0; -#endif } else { if (rw & 2) env->exception_index = TT_TFAULT; @@ -316,8 +314,8 @@ void do_interrupt(int intno) count, intno, env->pc, env->npc, env->regwptr[6]); -#if 1 cpu_dump_state(env, logfile, fprintf, 0); +#if 0 { int i; uint8_t *ptr; diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 4c65c64d6..9cb3de49a 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -164,7 +164,9 @@ void helper_st_asi(int asi, int size, int sign) case 0: env->mmuregs[reg] &= ~(MMU_E | MMU_NF); env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); - if ((oldreg & MMU_E) != (env->mmuregs[reg] & MMU_E)) + // Mappings generated during no-fault mode or MMU + // disabled mode are invalid in normal mode + if (oldreg != env->mmuregs[reg]) tlb_flush(env, 1); break; case 2: diff --git a/vl.c b/vl.c index 9efb4f7da..a815a50fa 100644 --- a/vl.c +++ b/vl.c @@ -2733,7 +2733,9 @@ void help(void) "-full-screen start in full screen\n" #ifdef TARGET_PPC "-prep Simulate a PREP system (default is PowerMAC)\n" - "-g WxH[xDEPTH] Set the initial VGA graphic mode\n" +#endif +#if defined(TARGET_PPC) || defined(TARGET_SPARC) + "-g WxH[xDEPTH] Set the initial graphical resolution and depth\n" #endif "\n" "Network options:\n" @@ -2916,6 +2918,8 @@ const QEMUOption qemu_options[] = { #endif #ifdef TARGET_PPC { "prep", 0, QEMU_OPTION_prep }, +#endif +#if defined(TARGET_PPC) || defined(TARGET_SPARC) { "g", 1, QEMU_OPTION_g }, #endif { "localtime", 0, QEMU_OPTION_localtime }, @@ -3179,6 +3183,10 @@ int main(int argc, char **argv) case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && +#ifdef TARGET_SPARC + // Network boot + boot_device != 'n' && +#endif boot_device != 'c' && boot_device != 'd') { fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device); exit(1); diff --git a/vl.h b/vl.h index c8404e10e..5091ca14e 100644 --- a/vl.h +++ b/vl.h @@ -714,7 +714,7 @@ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr); /* tcx.c */ void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, - unsigned long vram_offset, int vram_size); + unsigned long vram_offset, int vram_size, int width, int height); void tcx_update_display(void *opaque); void tcx_invalidate_display(void *opaque); void tcx_screen_dump(void *opaque, const char *filename); @@ -736,6 +736,9 @@ void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2); SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2); void slavio_serial_ms_kbd_init(int base, int irq); +/* esp.c */ +void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr); + /* NVRAM helpers */ #include "hw/m48t59.h" -- cgit v1.2.3 From ba68055eab1990ecbcd711d4f82578959e6e499d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 09:49:52 +0000 Subject: ARM host configure tweaks (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1327 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- configure | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.target b/Makefile.target index 68563299e..78e3e7f10 100644 --- a/Makefile.target +++ b/Makefile.target @@ -188,7 +188,7 @@ OP_CFLAGS=$(CFLAGS) endif ifeq ($(ARCH),arm) -OP_CFLAGS=$(CFLAGS) -mno-sched-prolog +OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld endif diff --git a/configure b/configure index e9978276d..70da7add0 100755 --- a/configure +++ b/configure @@ -32,10 +32,10 @@ case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" ;; - armv4b) + armv*b) cpu="armv4b" ;; - armv4l) + armv*l) cpu="armv4l" ;; alpha) -- cgit v1.2.3 From ae200d10628b471ff26c34aa3983205b3ec8c7e7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 09:53:38 +0000 Subject: GOTO_LABEL_PARAM for ARM git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1328 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dyngen-exec.h b/dyngen-exec.h index ba061c372..d8ecc02ff 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -242,6 +242,7 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #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") -- cgit v1.2.3 From 6eea2b1b81a878b471d597f7fac8598240088898 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 09:55:49 +0000 Subject: add missing FORCE_RET (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1329 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 7 +++++++ target-i386/ops_mem.h | 10 ++++++++++ target-sparc/op.c | 1 + 3 files changed, 18 insertions(+) diff --git a/target-i386/op.c b/target-i386/op.c index dd9d7bad1..dc0dceadf 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1842,11 +1842,13 @@ void OPPROTO op_fsts_ST0_A0(void) #else stfl(A0, (float)ST0); #endif + FORCE_RET(); } void OPPROTO op_fstl_ST0_A0(void) { stfq(A0, (double)ST0); + FORCE_RET(); } void OPPROTO op_fstt_ST0_A0(void) @@ -1868,6 +1870,7 @@ void OPPROTO op_fist_ST0_A0(void) if (val != (int16_t)val) val = -32768; stw(A0, val); + FORCE_RET(); } void OPPROTO op_fistl_ST0_A0(void) @@ -1882,6 +1885,7 @@ void OPPROTO op_fistl_ST0_A0(void) d = ST0; val = lrint(d); stl(A0, val); + FORCE_RET(); } void OPPROTO op_fistll_ST0_A0(void) @@ -1896,6 +1900,7 @@ void OPPROTO op_fistll_ST0_A0(void) d = ST0; val = llrint(d); stq(A0, val); + FORCE_RET(); } void OPPROTO op_fbld_ST0_A0(void) @@ -2228,6 +2233,7 @@ void OPPROTO op_fnstsw_A0(void) int fpus; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; stw(A0, fpus); + FORCE_RET(); } void OPPROTO op_fnstsw_EAX(void) @@ -2240,6 +2246,7 @@ void OPPROTO op_fnstsw_EAX(void) void OPPROTO op_fnstcw_A0(void) { stw(A0, env->fpuc); + FORCE_RET(); } void OPPROTO op_fldcw_A0(void) diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h index 2e6ccc424..0002f0dea 100644 --- a/target-i386/ops_mem.h +++ b/target-i386/ops_mem.h @@ -51,33 +51,39 @@ void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void) void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void) { glue(stb, MEMSUFFIX)(A0, T0); + FORCE_RET(); } void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void) { glue(stw, MEMSUFFIX)(A0, T0); + FORCE_RET(); } void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void) { glue(stl, MEMSUFFIX)(A0, T0); + FORCE_RET(); } #if 0 void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T1_A0)(void) { glue(stb, MEMSUFFIX)(A0, T1); + FORCE_RET(); } #endif void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T1_A0)(void) { glue(stw, MEMSUFFIX)(A0, T1); + FORCE_RET(); } void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T1_A0)(void) { glue(stl, MEMSUFFIX)(A0, T1); + FORCE_RET(); } /* SSE/MMX support */ @@ -93,6 +99,7 @@ void OPPROTO glue(glue(op_stq, MEMSUFFIX), _env_A0)(void) uint64_t *p; p = (uint64_t *)((char *)env + PARAM1); glue(stq, MEMSUFFIX)(A0, *p); + FORCE_RET(); } void OPPROTO glue(glue(op_ldo, MEMSUFFIX), _env_A0)(void) @@ -109,6 +116,7 @@ void OPPROTO glue(glue(op_sto, MEMSUFFIX), _env_A0)(void) p = (XMMReg *)((char *)env + PARAM1); glue(stq, MEMSUFFIX)(A0, p->XMM_Q(0)); glue(stq, MEMSUFFIX)(A0 + 8, p->XMM_Q(1)); + FORCE_RET(); } #ifdef TARGET_X86_64 @@ -135,11 +143,13 @@ void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T1_A0)(void) void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T0_A0)(void) { glue(stq, MEMSUFFIX)(A0, T0); + FORCE_RET(); } void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T1_A0)(void) { glue(stq, MEMSUFFIX)(A0, T1); + FORCE_RET(); } #endif diff --git a/target-sparc/op.c b/target-sparc/op.c index 7fa98f16b..281917a7f 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -765,6 +765,7 @@ void OPPROTO op_eval_fbue(void) { // 0 or 3 T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0)); + FORCE_RET(); } void OPPROTO op_eval_fbge(void) -- cgit v1.2.3 From 539827ecf58f16577b957e9c391b85e886db1828 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 16:51:00 +0000 Subject: fpu init fix (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1330 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/ppc_rom.bin | Bin 524288 -> 524288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin index d882dee3e..f88214dd1 100644 Binary files a/pc-bios/ppc_rom.bin and b/pc-bios/ppc_rom.bin differ -- cgit v1.2.3 From 4f716dc681d1bfa78d0863499fc1f2e13f170ede Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 16:53:06 +0000 Subject: avoid redefinition problems git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1331 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-all.c | 7 ++++--- translate-op.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 translate-op.c diff --git a/translate-all.c b/translate-all.c index f6a7bc2b5..fd7cc668c 100644 --- a/translate-all.c +++ b/translate-all.c @@ -30,6 +30,10 @@ #include "exec-all.h" #include "disas.h" +extern int dyngen_code(uint8_t *gen_code_buf, + uint16_t *label_offsets, uint16_t *jmp_offsets, + const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels); + enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, #include "opc.h" @@ -37,9 +41,6 @@ enum { NB_OPS, }; -#include "dyngen.h" -#include "op.h" - uint16_t gen_opc_buf[OPC_BUF_SIZE]; uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; long gen_labels[OPC_BUF_SIZE]; diff --git a/translate-op.c b/translate-op.c new file mode 100644 index 000000000..fddac70c4 --- /dev/null +++ b/translate-op.c @@ -0,0 +1,37 @@ +/* + * Host code generation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include "config.h" + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +#include "dyngen.h" +#include "op.h" + -- cgit v1.2.3 From 158142c2c2df728cfa3b5320c65534921a764f26 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 16:54:06 +0000 Subject: soft float support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1332 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 14 +- configure | 5 + fpu/softfloat-macros.h | 720 ++++++ fpu/softfloat-native.c | 262 +++ fpu/softfloat-native.h | 312 +++ fpu/softfloat-specialize.h | 464 ++++ fpu/softfloat.c | 5185 ++++++++++++++++++++++++++++++++++++++++++++ fpu/softfloat.h | 329 +++ 8 files changed, 7288 insertions(+), 3 deletions(-) create mode 100644 fpu/softfloat-macros.h create mode 100644 fpu/softfloat-native.c create mode 100644 fpu/softfloat-native.h create mode 100644 fpu/softfloat-specialize.h create mode 100644 fpu/softfloat.c create mode 100644 fpu/softfloat.h diff --git a/Makefile.target b/Makefile.target index 78e3e7f10..cabad43be 100644 --- a/Makefile.target +++ b/Makefile.target @@ -229,7 +229,7 @@ ifeq ($(TARGET_ARCH), i386) OBJS+= vm86.o endif ifeq ($(TARGET_ARCH), arm) -OBJS+=nwfpe/softfloat.o nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \ +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 endif @@ -237,8 +237,14 @@ SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a # cpu emulator library -LIBOBJS=exec.o kqemu.o translate-all.o cpu-exec.o\ +LIBOBJS=exec.o kqemu.o translate-op.o translate-all.o cpu-exec.o\ translate.o op.o +ifdef CONFIG_SOFTFLOAT +LIBOBJS+=fpu/softfloat.o +else +LIBOBJS+=fpu/softfloat-native.o +endif +DEFINES+=-I$(SRC_PATH)/fpu ifeq ($(TARGET_ARCH), i386) LIBOBJS+=helper.o helper2.o @@ -399,7 +405,9 @@ libqemu.a: $(LIBOBJS) translate.o: translate.c gen-op.h opc.h cpu.h -translate-all.o: translate-all.c 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 $@ $< diff --git a/configure b/configure index 70da7add0..585d2114c 100755 --- a/configure +++ b/configure @@ -593,6 +593,7 @@ 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 @@ -658,6 +659,10 @@ if test "$target_user_only" = "yes" ; then echo "#define CONFIG_USER_ONLY 1" >> $config_h fi +if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then + echo "CONFIG_SOFTFLOAT=yes" >> $config_mak + echo "#define CONFIG_SOFTFLOAT 1" >> $config_h +fi # sdl defines if test "$target_user_only" = "no"; then diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h new file mode 100644 index 000000000..2c8f18b1c --- /dev/null +++ b/fpu/softfloat-macros.h @@ -0,0 +1,720 @@ + +/*============================================================================ + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +/*---------------------------------------------------------------------------- +| Shifts `a' right by the number of bits given in `count'. If any nonzero +| bits are shifted off, they are ``jammed'' into the least significant bit of +| the result by setting the least significant bit to 1. The value of `count' +| can be arbitrarily large; in particular, if `count' is greater than 32, the +| result will be either 0 or 1, depending on whether `a' is zero or nonzero. +| The result is stored in the location pointed to by `zPtr'. +*----------------------------------------------------------------------------*/ + +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +{ + bits32 z; + + if ( count == 0 ) { + z = a; + } + else if ( count < 32 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; + +} + +/*---------------------------------------------------------------------------- +| Shifts `a' right by the number of bits given in `count'. If any nonzero +| bits are shifted off, they are ``jammed'' into the least significant bit of +| the result by setting the least significant bit to 1. The value of `count' +| can be arbitrarily large; in particular, if `count' is greater than 64, the +| result will be either 0 or 1, depending on whether `a' is zero or nonzero. +| The result is stored in the location pointed to by `zPtr'. +*----------------------------------------------------------------------------*/ + +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) +{ + bits64 z; + + if ( count == 0 ) { + z = a; + } + else if ( count < 64 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 +| _plus_ the number of bits given in `count'. The shifted result is at most +| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The +| bits shifted off form a second 64-bit result as follows: The _last_ bit +| shifted off is the most-significant bit of the extra result, and the other +| 63 bits of the extra result are all zero if and only if _all_but_the_last_ +| bits shifted off were all zero. This extra result is stored in the location +| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. +| (This routine makes more sense if `a0' and `a1' are considered to form +| a fixed-point value with binary point between `a0' and `a1'. This fixed- +| point value is shifted right by the number of bits given in `count', and +| the integer part of the result is returned at the location pointed to by +| `z0Ptr'. The fractional part of the result may be slightly corrupted as +| described above, and is returned at the location pointed to by `z1Ptr'.) +*----------------------------------------------------------------------------*/ + +INLINE void + shift64ExtraRightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else { + z1 = ( ( a0 | a1 ) != 0 ); + } + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' can be arbitrarily large; in particular, if `count' is greater +| than 128, the result will be 0. The result is broken into two 64-bit pieces +| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shift128Right( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ); + z0 = a0>>count; + } + else { + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +| number of bits given in `count'. If any nonzero bits are shifted off, they +| are ``jammed'' into the least significant bit of the result by setting the +| least significant bit to 1. The value of `count' can be arbitrarily large; +| in particular, if `count' is greater than 128, the result will be either +| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or +| nonzero. The result is broken into two 64-bit pieces which are stored at +| the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shift128RightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ) | ( ( a1<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 128 ) { + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 128 ) { + z2 = a0<>( count & 63 ); + } + else { + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); + z1 = 0; + } + } + z0 = 0; + } + z2 |= ( a2 != 0 ); + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the +| number of bits given in `count'. Any bits shifted off are lost. The value +| of `count' must be less than 64. The result is broken into two 64-bit +| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shortShift128Left( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1<>( ( - count ) & 63 ) ); + +} + +/*---------------------------------------------------------------------------- +| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left +| by the number of bits given in `count'. Any bits shifted off are lost. +| The value of `count' must be less than 64. The result is broken into three +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + shortShift192Left( + bits64 a0, + bits64 a1, + bits64 a2, + int16 count, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 negCount; + + z2 = a2<>negCount; + z0 |= a1>>negCount; + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit +| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so +| any carry out is lost. The result is broken into two 64-bit pieces which +| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + add128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z1; + + z1 = a1 + b1; + *z1Ptr = z1; + *z0Ptr = a0 + b0 + ( z1 < a1 ); + +} + +/*---------------------------------------------------------------------------- +| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the +| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +| modulo 2^192, so any carry out is lost. The result is broken into three +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr', +| `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + add192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 carry0, carry1; + + z2 = a2 + b2; + carry1 = ( z2 < a2 ); + z1 = a1 + b1; + carry0 = ( z1 < a1 ); + z0 = a0 + b0; + z1 += carry1; + z0 += ( z1 < carry1 ); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the +| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +| 2^128, so any borrow out (carry out) is lost. The result is broken into two +| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and +| `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + sub128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - ( a1 < b1 ); + +} + +/*---------------------------------------------------------------------------- +| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' +| from the 192-bit value formed by concatenating `a0', `a1', and `a2'. +| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The +| result is broken into three 64-bit pieces which are stored at the locations +| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + sub192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 borrow0, borrow1; + + z2 = a2 - b2; + borrow1 = ( a2 < b2 ); + z1 = a1 - b1; + borrow0 = ( a1 < b1 ); + z0 = a0 - b0; + z0 -= ( z1 < borrow1 ); + z1 -= borrow1; + z0 -= borrow0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken +| into two 64-bit pieces which are stored at the locations pointed to by +| `z0Ptr' and `z1Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits32 aHigh, aLow, bHigh, bLow; + bits64 z0, zMiddleA, zMiddleB, z1; + + aLow = a; + aHigh = a>>32; + bLow = b; + bHigh = b>>32; + z1 = ( (bits64) aLow ) * bLow; + zMiddleA = ( (bits64) aLow ) * bHigh; + zMiddleB = ( (bits64) aHigh ) * bLow; + z0 = ( (bits64) aHigh ) * bHigh; + zMiddleA += zMiddleB; + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); + zMiddleA <<= 32; + z1 += zMiddleA; + z0 += ( z1 < zMiddleA ); + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by +| `b' to obtain a 192-bit product. The product is broken into three 64-bit +| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +| `z2Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + mul128By64To192( + bits64 a0, + bits64 a1, + bits64 b, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2, more1; + + mul64To128( a1, b, &z1, &z2 ); + mul64To128( a0, b, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the +| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit +| product. The product is broken into four 64-bit pieces which are stored at +| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. +*----------------------------------------------------------------------------*/ + +INLINE void + mul128To256( + bits64 a0, + bits64 a1, + bits64 b0, + bits64 b1, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr, + bits64 *z3Ptr + ) +{ + bits64 z0, z1, z2, z3; + bits64 more1, more2; + + mul64To128( a1, b1, &z2, &z3 ); + mul64To128( a1, b0, &z1, &more2 ); + add128( z1, more2, 0, z2, &z1, &z2 ); + mul64To128( a0, b0, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + mul64To128( a0, b1, &more1, &more2 ); + add128( more1, more2, 0, z2, &more1, &z2 ); + add128( z0, z1, 0, more1, &z0, &z1 ); + *z3Ptr = z3; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/*---------------------------------------------------------------------------- +| Returns an approximation to the 64-bit integer quotient obtained by dividing +| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The +| divisor `b' must be at least 2^63. If q is the exact quotient truncated +| toward zero, the approximation returned lies between q and q + 2 inclusive. +| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit +| unsigned integer is returned. +*----------------------------------------------------------------------------*/ + +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) +{ + bits64 b0, b1; + bits64 rem0, rem1, term0, term1; + bits64 z; + + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); + b0 = b>>32; + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; + mul64To128( b, z, &term0, &term1 ); + sub128( a0, a1, term0, term1, &rem0, &rem1 ); + while ( ( (sbits64) rem0 ) < 0 ) { + z -= LIT64( 0x100000000 ); + b1 = b<<32; + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); + } + rem0 = ( rem0<<32 ) | ( rem1>>32 ); + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns an approximation to the square root of the 32-bit significand given +| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of +| `aExp' (the least significant bit) is 1, the integer returned approximates +| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' +| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either +| case, the approximation returned lies strictly within +/-2 of the exact +| value. +*----------------------------------------------------------------------------*/ + +static bits32 estimateSqrt32( int16 aExp, bits32 a ) +{ + static const bits16 sqrtOddAdjustments[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; + static const bits16 sqrtEvenAdjustments[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + int8 index; + bits32 z; + + index = ( a>>27 ) & 15; + if ( aExp & 1 ) { + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; + z = ( ( a / z )<<14 ) + ( z<<15 ); + a >>= 1; + } + else { + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; + z = a / z + z; + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); + } + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns the number of leading 0 bits before the most-significant 1 bit of +| `a'. If `a' is zero, 32 is returned. +*----------------------------------------------------------------------------*/ + +static int8 countLeadingZeros32( bits32 a ) +{ + static const int8 countLeadingZerosHigh[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + int8 shiftCount; + + shiftCount = 0; + if ( a < 0x10000 ) { + shiftCount += 16; + a <<= 16; + } + if ( a < 0x1000000 ) { + shiftCount += 8; + a <<= 8; + } + shiftCount += countLeadingZerosHigh[ a>>24 ]; + return shiftCount; + +} + +/*---------------------------------------------------------------------------- +| Returns the number of leading 0 bits before the most-significant 1 bit of +| `a'. If `a' is zero, 64 is returned. +*----------------------------------------------------------------------------*/ + +static int8 countLeadingZeros64( bits64 a ) +{ + int8 shiftCount; + + shiftCount = 0; + if ( a < ( (bits64) 1 )<<32 ) { + shiftCount += 32; + } + else { + a >>= 32; + } + shiftCount += countLeadingZeros32( a ); + return shiftCount; + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' +| is equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 == b0 ) && ( a1 == b1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +| than or equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, +| returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is +| not equal to the 128-bit value formed by concatenating `b0' and `b1'. +| Otherwise, returns 0. +*----------------------------------------------------------------------------*/ + +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 != b0 ) || ( a1 != b1 ); + +} + diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c new file mode 100644 index 000000000..8259a7c27 --- /dev/null +++ b/fpu/softfloat-native.c @@ -0,0 +1,262 @@ +/* Native implementation of soft float functions. Only a single status + context is supported */ +#include "softfloat.h" +#include + +void set_float_rounding_mode(int val STATUS_PARAM) +{ + STATUS(float_rounding_mode) = val; +#if defined(_BSD) && !defined(__APPLE__) + fpsetround(val); +#elif defined(__arm__) + /* nothing to do */ +#else + fesetround(val); +#endif +} + +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM) +{ + STATUS(floatx80_rounding_precision) = val; +} +#endif + +#if defined(_BSD) +#define lrint(d) ((int32_t)rint(d)) +#define llrint(d) ((int64_t)rint(d)) +#endif + +#if defined(__powerpc__) + +/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ +double qemu_rint(double x) +{ + double y = 4503599627370496.0; + if (fabs(x) >= y) + return x; + if (x < 0) + y = -y; + y = (x + y) - y; + if (y == 0.0) + y = copysign(y, x); + return y; +} + +#define rint qemu_rint +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32(int v STATUS_PARAM) +{ + return (float32)v; +} + +float64 int32_to_float64(int v STATUS_PARAM) +{ + return (float64)v; +} + +#ifdef FLOATX80 +floatx80 int32_to_floatx80(int v STATUS_PARAM) +{ + return (floatx80)v; +} +#endif +float32 int64_to_float32( int64_t v STATUS_PARAM) +{ + return (float32)v; +} +float64 int64_to_float64( int64_t v STATUS_PARAM) +{ + return (float64)v; +} +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t v STATUS_PARAM) +{ + return (floatx80)v; +} +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 a STATUS_PARAM) +{ + return lrintf(a); +} +int float32_to_int32_round_to_zero( float32 a STATUS_PARAM) +{ + return (int)a; +} +int64_t float32_to_int64( float32 a STATUS_PARAM) +{ + return llrintf(a); +} + +int64_t float32_to_int64_round_to_zero( float32 a STATUS_PARAM) +{ + return (int64_t)a; +} + +float64 float32_to_float64( float32 a STATUS_PARAM) +{ + return a; +} +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 a STATUS_PARAM) +{ + return a; +} +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 a STATUS_PARAM) +{ + return rintf(a); +} + +float32 float32_sqrt( float32 a STATUS_PARAM) +{ + return sqrtf(a); +} +char float32_is_signaling_nan( float32 a1) +{ + float32u u; + uint32_t a; + u.f = a1; + a = u.i; + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 a STATUS_PARAM) +{ + return lrint(a); +} +int float64_to_int32_round_to_zero( float64 a STATUS_PARAM) +{ + return (int)a; +} +int64_t float64_to_int64( float64 a STATUS_PARAM) +{ + return llrint(a); +} +int64_t float64_to_int64_round_to_zero( float64 a STATUS_PARAM) +{ + return (int64_t)a; +} +float32 float64_to_float32( float64 a STATUS_PARAM) +{ + return a; +} +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 a STATUS_PARAM) +{ + return a; +} +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 a STATUS_PARAM) +{ + return a; +} +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +float64 float64_round_to_int( float64 a STATUS_PARAM ) +{ +#if defined(__arm__) + switch(STATUS(float_rounding_mode)) { + default: + case float_round_nearest_even: + asm("rndd %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_down: + asm("rnddm %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_up: + asm("rnddp %0, %1" : "=f" (a) : "f"(a)); + break; + case float_round_to_zero: + asm("rnddz %0, %1" : "=f" (a) : "f"(a)); + break; + } +#else + return rint(a); +#endif +} + +float64 float64_sqrt( float64 a STATUS_PARAM) +{ + return sqrt(a); +} +char float64_is_signaling_nan( float64 a1) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 a STATUS_PARAM) +{ + return lrintl(a); +} +int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM) +{ + return (int)a; +} +int64_t floatx80_to_int64( floatx80 a STATUS_PARAM) +{ + return llrintl(a); +} +int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM) +{ + return (int64_t)a; +} +float32 floatx80_to_float32( floatx80 a STATUS_PARAM) +{ + return a; +} +float64 floatx80_to_float64( floatx80 a STATUS_PARAM) +{ + return a; +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM) +{ + return rintl(a); +} +floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM) +{ + return sqrtl(a); +} +char floatx80_is_signaling_nan( floatx80 a1) +{ + floatx80u u; + u.f = a1; + return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 ); +} + +#endif diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h new file mode 100644 index 000000000..709df51bc --- /dev/null +++ b/fpu/softfloat-native.h @@ -0,0 +1,312 @@ +/* Native implementation of soft float functions */ +#include +#if defined(_BSD) && !defined(__APPLE__) +#include +#else +#include +#endif + +typedef float float32; +typedef double float64; +#ifdef FLOATX80 +typedef long double floatx80; +#endif + +typedef union { + float32 f; + uint32_t i; +} float32u; +typedef union { + float64 f; + uint64_t i; +} float64u; +#ifdef FLOATX80 +typedef union { + floatx80 f; + struct { + uint64_t low; + uint16_t high; + } i; +} floatx80u; +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point rounding mode. +*----------------------------------------------------------------------------*/ +#if defined(_BSD) && !defined(__APPLE__) +enum { + float_round_nearest_even = FP_RN, + float_round_down = FE_RM, + float_round_up = FE_RP, + float_round_to_zero = FE_RZ +}; +#elif defined(__arm__) +enum { + float_round_nearest_even = 0, + float_round_down = 1, + float_round_up = 2, + float_round_to_zero = 3 +}; +#else +enum { + float_round_nearest_even = FE_TONEAREST, + float_round_down = FE_DOWNWARD, + float_round_up = FE_UPWARD, + float_round_to_zero = FE_TOWARDZERO +}; +#endif + +typedef struct float_status { + signed char float_rounding_mode; +#ifdef FLOATX80 + signed char floatx80_rounding_precision; +#endif +} float_status; + +void set_float_rounding_mode(int val STATUS_PARAM); +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32( int STATUS_PARAM); +float64 int32_to_float64( int STATUS_PARAM); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( int STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 int32_to_float128( int STATUS_PARAM); +#endif +float32 int64_to_float32( int64_t STATUS_PARAM); +float64 int64_to_float64( int64_t STATUS_PARAM); +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 int64_to_float128( int64_t STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 STATUS_PARAM); +int float32_to_int32_round_to_zero( float32 STATUS_PARAM); +int64_t float32_to_int64( float32 STATUS_PARAM); +int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM); +float64 float32_to_float64( float32 STATUS_PARAM); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 STATUS_PARAM); +#endif +#ifdef FLOAT128 +float128 float32_to_float128( float32 STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 STATUS_PARAM); +INLINE float32 float32_add( float32 a, float32 b STATUS_PARAM) +{ + return a + b; +} +INLINE float32 float32_sub( float32 a, float32 b STATUS_PARAM) +{ + return a - b; +} +INLINE float32 float32_mul( float32 a, float32 b STATUS_PARAM) +{ + return a * b; +} +INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM) +{ + return a / b; +} +float32 float32_rem( float32, float32 STATUS_PARAM); +float32 float32_sqrt( float32 STATUS_PARAM); +INLINE char float32_eq( float32 a, float32 b STATUS_PARAM) +{ + /* XXX: incorrect because it can raise an exception */ + return a == b; +} +INLINE char float32_le( float32 a, float32 b STATUS_PARAM) +{ + return a <= b; +} +INLINE char float32_lt( float32 a, float32 b STATUS_PARAM) +{ + return a < b; +} +INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM) +{ + return a == b; +} +INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM) +{ + return isless(a, b); +} +char float32_is_signaling_nan( float32 ); + +INLINE float32 float32_abs(float32 a) +{ + return fabsf(a); +} + +INLINE float32 float32_chs(float32 a) +{ + return -a; +} + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 STATUS_PARAM ); +int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +int64_t float64_to_int64( float64 STATUS_PARAM ); +int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +float32 float64_to_float32( float64 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +float64 float64_round_to_int( float64 STATUS_PARAM ); +INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM) +{ + return a + b; +} +INLINE float64 float64_sub( float64 a, float64 b STATUS_PARAM) +{ + return a - b; +} +INLINE float64 float64_mul( float64 a, float64 b STATUS_PARAM) +{ + return a * b; +} +INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM) +{ + return a / b; +} +float64 float64_rem( float64, float64 STATUS_PARAM ); +float64 float64_sqrt( float64 STATUS_PARAM ); +INLINE char float64_eq( float64 a, float64 b STATUS_PARAM) +{ + return a == b; +} +INLINE char float64_le( float64 a, float64 b STATUS_PARAM) +{ + return a <= b; +} +INLINE char float64_lt( float64 a, float64 b STATUS_PARAM) +{ + return a < b; +} +INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM) +{ + return a == b; +} +INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM) +{ + return isless(a, b); + +} +char float64_is_signaling_nan( float64 ); + +INLINE float64 float64_abs(float64 a) +{ + return fabs(a); +} + +INLINE float64 float64_chs(float64 a) +{ + return -a; +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 STATUS_PARAM ); +int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64( floatx80 STATUS_PARAM); +int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM); +float32 floatx80_to_float32( floatx80 STATUS_PARAM ); +float64 floatx80_to_float64( floatx80 STATUS_PARAM ); +#ifdef FLOAT128 +float128 floatx80_to_float128( floatx80 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM ); +INLINE floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a + b; +} +INLINE floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a - b; +} +INLINE floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a * b; +} +INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a / b; +} +floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); +INLINE char floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a == b; +} +INLINE char floatx80_le( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a <= b; +} +INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a < b; +} +INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) +{ + return a == b; +} +INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return islessequal(a, b); +} +INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isless(a, b); + +} +char floatx80_is_signaling_nan( floatx80 ); + +INLINE floatx80 floatx80_abs(floatx80 a) +{ + return fabsl(a); +} + +INLINE floatx80 floatx80_chs(floatx80 a) +{ + return -a; +} +#endif diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h new file mode 100644 index 000000000..d430f58a7 --- /dev/null +++ b/fpu/softfloat-specialize.h @@ -0,0 +1,464 @@ + +/*============================================================================ + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +/*---------------------------------------------------------------------------- +| Underflow tininess-detection mode, statically initialized to default value. +| (The declaration in `softfloat.h' must match the `int8' type here.) +*----------------------------------------------------------------------------*/ +int8 float_detect_tininess = float_tininess_after_rounding; + +/*---------------------------------------------------------------------------- +| Raises the exceptions specified by `flags'. Floating-point traps can be +| defined here if desired. It is currently not possible for such a trap +| to substitute a result value. If traps are not implemented, this routine +| should be simply `float_exception_flags |= flags;'. +*----------------------------------------------------------------------------*/ + +void float_raise( int8 flags STATUS_PARAM ) +{ + + STATUS(float_exception_flags) |= flags; + +} + +/*---------------------------------------------------------------------------- +| Internal canonical NaN format. +*----------------------------------------------------------------------------*/ +typedef struct { + flag sign; + bits64 high, low; +} commonNaNT; + +/*---------------------------------------------------------------------------- +| The pattern for a default generated single-precision NaN. +*----------------------------------------------------------------------------*/ +#define float32_default_nan 0xFFC00000 + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is a NaN; +| otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float32_is_nan( float32 a ) +{ + + return ( 0xFF000000 < (bits32) ( a<<1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float32_is_signaling_nan( float32 a ) +{ + + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) +{ + commonNaNT z; + + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); + z.sign = a>>31; + z.low = 0; + z.high = ( (bits64) a )<<41; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the single- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float32 commonNaNToFloat32( commonNaNT a ) +{ + + return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); + +} + +/*---------------------------------------------------------------------------- +| Takes two single-precision floating-point values `a' and `b', one of which +| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float32_is_nan( a ); + aIsSignalingNaN = float32_is_signaling_nan( a ); + bIsNaN = float32_is_nan( b ); + bIsSignalingNaN = float32_is_signaling_nan( b ); + a |= 0x00400000; + b |= 0x00400000; + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + return bIsNaN ? b : a; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN | ! bIsNaN ) return a; + returnLargerSignificand: + if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b; + if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a; + return ( a < b ) ? a : b; + } + else { + return b; + } + +} + +/*---------------------------------------------------------------------------- +| The pattern for a default generated double-precision NaN. +*----------------------------------------------------------------------------*/ +#define float64_default_nan LIT64( 0xFFF8000000000000 ) + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is a NaN; +| otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float64_is_nan( float64 a ) +{ + + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float64_is_signaling_nan( float64 a ) +{ + + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) +{ + commonNaNT z; + + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = a>>63; + z.low = 0; + z.high = a<<12; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the double- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float64 commonNaNToFloat64( commonNaNT a ) +{ + + return + ( ( (bits64) a.sign )<<63 ) + | LIT64( 0x7FF8000000000000 ) + | ( a.high>>12 ); + +} + +/*---------------------------------------------------------------------------- +| Takes two double-precision floating-point values `a' and `b', one of which +| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +| signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float64_is_nan( a ); + aIsSignalingNaN = float64_is_signaling_nan( a ); + bIsNaN = float64_is_nan( b ); + bIsSignalingNaN = float64_is_signaling_nan( b ); + a |= LIT64( 0x0008000000000000 ); + b |= LIT64( 0x0008000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + return bIsNaN ? b : a; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN | ! bIsNaN ) return a; + returnLargerSignificand: + if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b; + if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a; + return ( a < b ) ? a : b; + } + else { + return b; + } + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| The pattern for a default generated extended double-precision NaN. The +| `high' and `low' values hold the most- and least-significant bits, +| respectively. +*----------------------------------------------------------------------------*/ +#define floatx80_default_nan_high 0xFFFF +#define floatx80_default_nan_low LIT64( 0xC000000000000000 ) + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is a +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag floatx80_is_nan( floatx80 a ) +{ + + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is a +| signaling NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag floatx80_is_signaling_nan( floatx80 a ) +{ + bits64 aLow; + + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the +| invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) +{ + commonNaNT z; + + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = a.high>>15; + z.low = 0; + z.high = a.low<<1; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the extended +| double-precision floating-point format. +*----------------------------------------------------------------------------*/ + +static floatx80 commonNaNToFloatx80( commonNaNT a ) +{ + floatx80 z; + + z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + return z; + +} + +/*---------------------------------------------------------------------------- +| Takes two extended double-precision floating-point values `a' and `b', one +| of which is a NaN, and returns the appropriate NaN result. If either `a' or +| `b' is a signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = floatx80_is_nan( a ); + aIsSignalingNaN = floatx80_is_signaling_nan( a ); + bIsNaN = floatx80_is_nan( b ); + bIsSignalingNaN = floatx80_is_signaling_nan( b ); + a.low |= LIT64( 0xC000000000000000 ); + b.low |= LIT64( 0xC000000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + return bIsNaN ? b : a; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN | ! bIsNaN ) return a; + returnLargerSignificand: + if ( a.low < b.low ) return b; + if ( b.low < a.low ) return a; + return ( a.high < b.high ) ? a : b; + } + else { + return b; + } + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| The pattern for a default generated quadruple-precision NaN. The `high' and +| `low' values hold the most- and least-significant bits, respectively. +*----------------------------------------------------------------------------*/ +#define float128_default_nan_high LIT64( 0xFFFF800000000000 ) +#define float128_default_nan_low LIT64( 0x0000000000000000 ) + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is a NaN; +| otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float128_is_nan( float128 a ) +{ + + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is a +| signaling NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +flag float128_is_signaling_nan( float128 a ) +{ + + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM) +{ + commonNaNT z; + + if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); + z.sign = a.high>>63; + shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the quadruple- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float128 commonNaNToFloat128( commonNaNT a ) +{ + float128 z; + + shift128Right( a.high, a.low, 16, &z.high, &z.low ); + z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 ); + return z; + +} + +/*---------------------------------------------------------------------------- +| Takes two quadruple-precision floating-point values `a' and `b', one of +| which is a NaN, and returns the appropriate NaN result. If either `a' or +| `b' is a signaling NaN, the invalid exception is raised. +*----------------------------------------------------------------------------*/ + +static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float128_is_nan( a ); + aIsSignalingNaN = float128_is_signaling_nan( a ); + bIsNaN = float128_is_nan( b ); + bIsSignalingNaN = float128_is_signaling_nan( b ); + a.high |= LIT64( 0x0000800000000000 ); + b.high |= LIT64( 0x0000800000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); + if ( aIsSignalingNaN ) { + if ( bIsSignalingNaN ) goto returnLargerSignificand; + return bIsNaN ? b : a; + } + else if ( aIsNaN ) { + if ( bIsSignalingNaN | ! bIsNaN ) return a; + returnLargerSignificand: + if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b; + if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a; + return ( a.high < b.high ) ? a : b; + } + else { + return b; + } + +} + +#endif + diff --git a/fpu/softfloat.c b/fpu/softfloat.c new file mode 100644 index 000000000..ad57fd9e1 --- /dev/null +++ b/fpu/softfloat.c @@ -0,0 +1,5185 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic +Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +#include "softfloat.h" + +/*---------------------------------------------------------------------------- +| Primitive arithmetic functions, including multi-word arithmetic, and +| division and square root approximations. (Can be specialized to target if +| desired.) +*----------------------------------------------------------------------------*/ +#include "softfloat-macros.h" + +/*---------------------------------------------------------------------------- +| Functions and definitions to determine: (1) whether tininess for underflow +| is detected before or after rounding by default, (2) what (if anything) +| happens when exceptions are raised, (3) how signaling NaNs are distinguished +| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs +| are propagated from function inputs to output. These details are target- +| specific. +*----------------------------------------------------------------------------*/ +#include "softfloat-specialize.h" + +void set_float_rounding_mode(int val STATUS_PARAM) +{ + STATUS(float_rounding_mode) = val; +} + +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM) +{ + STATUS(floatx80_rounding_precision) = val; +} +#endif + +/*---------------------------------------------------------------------------- +| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 +| and 7, and returns the properly rounded 32-bit integer corresponding to the +| input. If `zSign' is 1, the input is negated before being converted to an +| integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input +| is simply rounded to an integer, with the inexact exception raised if the +| input cannot be represented exactly as an integer. However, if the fixed- +| point input is too large, the invalid exception is raised and the largest +| positive or negative integer is returned. +*----------------------------------------------------------------------------*/ + +static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM) +{ + int8 roundingMode; + flag roundNearestEven; + int8 roundIncrement, roundBits; + int32 z; + + roundingMode = STATUS(float_rounding_mode); + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x40; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x7F; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = absZ & 0x7F; + absZ = ( absZ + roundIncrement )>>7; + absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + z = absZ; + if ( zSign ) z = - z; + if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { + float_raise( float_flag_invalid STATUS_VAR); + return zSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and +| `absZ1', with binary point between bits 63 and 64 (between the input words), +| and returns the properly rounded 64-bit integer corresponding to the input. +| If `zSign' is 1, the input is negated before being converted to an integer. +| Ordinarily, the fixed-point input is simply rounded to an integer, with +| the inexact exception raised if the input cannot be represented exactly as +| an integer. However, if the fixed-point input is too large, the invalid +| exception is raised and the largest positive or negative integer is +| returned. +*----------------------------------------------------------------------------*/ + +static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PARAM) +{ + int8 roundingMode; + flag roundNearestEven, increment; + int64 z; + + roundingMode = STATUS(float_rounding_mode); + roundNearestEven = ( roundingMode == float_round_nearest_even ); + increment = ( (sbits64) absZ1 < 0 ); + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + increment = 0; + } + else { + if ( zSign ) { + increment = ( roundingMode == float_round_down ) && absZ1; + } + else { + increment = ( roundingMode == float_round_up ) && absZ1; + } + } + } + if ( increment ) { + ++absZ0; + if ( absZ0 == 0 ) goto overflow; + absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven ); + } + z = absZ0; + if ( zSign ) z = - z; + if ( z && ( ( z < 0 ) ^ zSign ) ) { + overflow: + float_raise( float_flag_invalid STATUS_VAR); + return + zSign ? (sbits64) LIT64( 0x8000000000000000 ) + : LIT64( 0x7FFFFFFFFFFFFFFF ); + } + if ( absZ1 ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the fraction bits of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE bits32 extractFloat32Frac( float32 a ) +{ + + return a & 0x007FFFFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the exponent bits of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE int16 extractFloat32Exp( float32 a ) +{ + + return ( a>>23 ) & 0xFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat32Sign( float32 a ) +{ + + return a>>31; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal single-precision floating-point value represented +| by the denormalized significand `aSig'. The normalized exponent and +| significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( aSig ) - 8; + *zSigPtr = aSig<>7; + zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat32( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Takes an abstract floating-point value having sign `zSign', exponent `zExp', +| and significand `zSig', and returns the proper single-precision floating- +| point value corresponding to the abstract input. This routine is just like +| `roundAndPackFloat32' except that `zSig' does not have to be normalized. +| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true'' +| floating-point exponent. +*----------------------------------------------------------------------------*/ + +static float32 + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_PARAM) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( zSig ) - 1; + return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>52 ) & 0x7FF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the double-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat64Sign( float64 a ) +{ + + return a>>63; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal double-precision floating-point value represented +| by the denormalized significand `aSig'. The normalized exponent and +| significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ) - 11; + *zSigPtr = aSig<>10; + zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat64( zSign, zExp, zSig ); + +} + +/*---------------------------------------------------------------------------- +| Takes an abstract floating-point value having sign `zSign', exponent `zExp', +| and significand `zSig', and returns the proper double-precision floating- +| point value corresponding to the abstract input. This routine is just like +| `roundAndPackFloat64' except that `zSig' does not have to be normalized. +| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true'' +| floating-point exponent. +*----------------------------------------------------------------------------*/ + +static float64 + normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( zSig ) - 1; + return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>15; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal extended double-precision floating-point value +| represented by the denormalized significand `aSig'. The normalized exponent +| and significand are stored at the locations pointed to by `zExpPtr' and +| `zSigPtr', respectively. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ); + *zSigPtr = aSig<>48 ) & 0x7FFF; + +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the quadruple-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat128Sign( float128 a ) +{ + + return a.high>>63; + +} + +/*---------------------------------------------------------------------------- +| Normalizes the subnormal quadruple-precision floating-point value +| represented by the denormalized significand formed by the concatenation of +| `aSig0' and `aSig1'. The normalized exponent is stored at the location +| pointed to by `zExpPtr'. The most significant 49 bits of the normalized +| significand are stored at the location pointed to by `zSig0Ptr', and the +| least significant 64 bits of the normalized significand are stored at the +| location pointed to by `zSig1Ptr'. +*----------------------------------------------------------------------------*/ + +static void + normalizeFloat128Subnormal( + bits64 aSig0, + bits64 aSig1, + int32 *zExpPtr, + bits64 *zSig0Ptr, + bits64 *zSig1Ptr + ) +{ + int8 shiftCount; + + if ( aSig0 == 0 ) { + shiftCount = countLeadingZeros64( aSig1 ) - 15; + if ( shiftCount < 0 ) { + *zSig0Ptr = aSig1>>( - shiftCount ); + *zSig1Ptr = aSig1<<( shiftCount & 63 ); + } + else { + *zSig0Ptr = aSig1<>( - shiftCount ); + if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the 64-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int64 float32_to_int64( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + bits64 aSig64, aSigExtra; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = 0xBE - aExp; + if ( shiftCount < 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { + return LIT64( 0x7FFFFFFFFFFFFFFF ); + } + return (sbits64) LIT64( 0x8000000000000000 ); + } + if ( aExp ) aSig |= 0x00800000; + aSig64 = aSig; + aSig64 <<= 40; + shift64ExtraRightJamming( aSig64, 0, shiftCount, &aSig64, &aSigExtra ); + return roundAndPackInt64( aSign, aSig64, aSigExtra STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the 64-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. If +| `a' is a NaN, the largest positive integer is returned. Otherwise, if the +| conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + bits64 aSig64; + int64 z; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = aExp - 0xBE; + if ( 0 <= shiftCount ) { + if ( a != 0xDF000000 ) { + float_raise( float_flag_invalid STATUS_VAR); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { + return LIT64( 0x7FFFFFFFFFFFFFFF ); + } + } + return (sbits64) LIT64( 0x8000000000000000 ); + } + else if ( aExp <= 0x7E ) { + if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig64 = aSig | 0x00800000; + aSig64 <<= 40; + z = aSig64>>( - shiftCount ); + if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the double-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float32_to_float64( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR )); + return packFloat64( aSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the extended double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float32_to_floatx80( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + aSig |= 0x00800000; + return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the double-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float32_to_float128( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) ); + return packFloat128( aSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the single-precision floating-point value `a' to an integer, and +| returns the result as a single-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_round_to_int( float32 a STATUS_PARAM) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + float32 z; + + aExp = extractFloat32Exp( a ); + if ( 0x96 <= aExp ) { + if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { + return propagateFloat32NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp <= 0x7E ) { + if ( (bits32) ( a<<1 ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat32Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { + return packFloat32( aSign, 0x7F, 0 ); + } + break; + case float_round_down: + return aSign ? 0xBF800000 : 0; + case float_round_up: + return aSign ? 0x80000000 : 0x3F800000; + } + return packFloat32( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x96 - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the single-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 6; + bSig <<= 6; + if ( 0 < expDiff ) { + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x20000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x20000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + zSig = 0x40000000 + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= 0x20000000; + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits32) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the single- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 7; + bSig <<= 7; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat32( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign ^ 1, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x40000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + bSig |= 0x40000000; + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x40000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + aSig |= 0x40000000; + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the single-precision floating-point values `a' +| and `b'. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_add( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return addFloat32Sigs( a, b, aSign STATUS_VAR); + } + else { + return subFloat32Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_sub( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat32Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the single-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_mul( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig; + bits64 zSig64; + bits32 zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x7F; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); + zSig = zSig64; + if ( 0 <= (sbits32) ( zSig<<1 ) ) { + zSig <<= 1; + --zExp; + } + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the single-precision floating-point value `a' +| by the corresponding value `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_div( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return packFloat32( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat32( zSign, 0xFF, 0 ); + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x7D; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = ( ( (bits64) aSig )<<32 ) / bSig; + if ( ( zSig & 0x3F ) == 0 ) { + zSig |= ( (bits64) bSig * zSig != ( (bits64) aSig )<<32 ); + } + return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the single-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_rem( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig, bSig; + bits32 q; + bits64 aSig64, bSig64, q64; + bits32 alternateASig; + sbits32 sigMean; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig |= 0x00800000; + bSig |= 0x00800000; + if ( expDiff < 32 ) { + aSig <<= 8; + bSig <<= 8; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + if ( 0 < expDiff ) { + q = ( ( (bits64) aSig )<<32 ) / bSig; + q >>= 32 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + } + else { + if ( bSig <= aSig ) aSig -= bSig; + aSig64 = ( (bits64) aSig )<<40; + bSig64 = ( (bits64) bSig )<<40; + expDiff -= 64; + while ( 0 < expDiff ) { + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + aSig64 = - ( ( bSig * q64 )<<38 ); + expDiff -= 62; + } + expDiff += 64; + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + q = q64>>( 64 - expDiff ); + bSig <<= 6; + aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits32) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits32) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the single-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float32_sqrt( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig, zSig; + bits64 rem, term; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, 0 STATUS_VAR ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; + aSig = ( aSig | 0x00800000 )<<8; + zSig = estimateSqrt32( aExp, aSig ) + 2; + if ( ( zSig & 0x7F ) <= 5 ) { + if ( zSig < 2 ) { + zSig = 0x7FFFFFFF; + goto roundAndPack; + } + aSig >>= aExp & 1; + term = ( (bits64) zSig ) * zSig; + rem = ( ( (bits64) aSig )<<32 ) - term; + while ( (sbits64) rem < 0 ) { + --zSig; + rem += ( ( (bits64) zSig )<<1 ) | 1; + } + zSig |= ( rem != 0 ); + } + shift32RightJamming( zSig, 1, &zSig ); + roundAndPack: + return roundAndPackFloat32( 0, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float32_eq( float32 a, float32 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float32_le( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float32_lt( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float32_le_quiet( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float64_to_int32( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x42C - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the 32-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. +| If `a' is a NaN, the largest positive integer is returned. Otherwise, if +| the conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( 0x41E < aExp ) { + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FF ) { + if ( aExp || aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x433 - aExp; + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>( - shiftCount ); + if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the single-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float64_to_float32( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + bits32 zSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig, 22, &aSig ); + zSig = aSig; + if ( aExp || zSig ) { + zSig |= 0x40000000; + aExp -= 0x381; + } + return roundAndPackFloat32( aSign, aExp, zSig STATUS_VAR ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the extended double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float64_to_floatx80( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + return + packFloatx80( + aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the double-precision floating-point value +| `a' to the quadruple-precision floating-point format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float64_to_float128( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) ); + return packFloat128( aSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + shift128Right( aSig, 0, 4, &zSig0, &zSig1 ); + return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the double-precision floating-point value `a' to an integer, and +| returns the result as a double-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_round_to_int( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + float64 z; + + aExp = extractFloat64Exp( a ); + if ( 0x433 <= aExp ) { + if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) { + return propagateFloat64NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp < 0x3FF ) { + if ( (bits64) ( a<<1 ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat64Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) { + return packFloat64( aSign, 0x3FF, 0 ); + } + break; + case float_round_down: + return aSign ? LIT64( 0xBFF0000000000000 ) : 0; + case float_round_up: + return + aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 ); + } + return packFloat64( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x433 - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the double-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 9; + bSig <<= 9; + if ( 0 < expDiff ) { + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= LIT64( 0x2000000000000000 ); + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits64) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the double- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 10; + bSig <<= 10; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat64( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign ^ 1, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + bSig |= LIT64( 0x4000000000000000 ); + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + aSig |= LIT64( 0x4000000000000000 ); + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the double-precision floating-point values `a' +| and `b'. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_add( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return addFloat64Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloat64Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_sub( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return subFloat64Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat64Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the double-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_mul( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FF; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + zSig0 |= ( zSig1 != 0 ); + if ( 0 <= (sbits64) ( zSig0<<1 ) ) { + zSig0 <<= 1; + --zExp; + } + return roundAndPackFloat64( zSign, zExp, zSig0 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the double-precision floating-point value `a' +| by the corresponding value `b'. The operation is performed according to +| the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_div( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + bits64 rem0, rem1; + bits64 term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return packFloat64( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat64( zSign, 0x7FF, 0 ); + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FD; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = estimateDiv128To64( aSig, 0, bSig ); + if ( ( zSig & 0x1FF ) <= 2 ) { + mul64To128( bSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig |= ( rem1 != 0 ); + } + return roundAndPackFloat64( zSign, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the double-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_rem( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits64 aSig, bSig; + bits64 q, alternateASig; + sbits64 sigMean; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + aSig = - ( ( bSig>>2 ) * q ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits64) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits64) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the double-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float64_sqrt( float64 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, zExp; + bits64 aSig, zSig, doubleZSig; + bits64 rem0, rem1, term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; + aSig |= LIT64( 0x0010000000000000 ); + zSig = estimateSqrt32( aExp, aSig>>21 ); + aSig <<= 9 - ( aExp & 1 ); + zSig = estimateDiv128To64( aSig, 0, zSig<<32 ) + ( zSig<<30 ); + if ( ( zSig & 0x1FF ) <= 5 ) { + doubleZSig = zSig<<1; + mul64To128( zSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + doubleZSig -= 2; + add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 ); + } + zSig |= ( ( rem0 | rem1 ) != 0 ); + } + return roundAndPackFloat64( 0, zExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to the +| corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_eq( float64 a, float64 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_le( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_lt( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to the +| corresponding value `b', and 0 otherwise. The invalid exception is raised +| if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than or +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_le_quiet( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the 32-bit two's complement integer format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic---which means in particular that the conversion +| is rounded according to the current rounding mode. If `a' is a NaN, the +| largest positive integer is returned. Otherwise, if the conversion +| overflows, the largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 floatx80_to_int32( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + shiftCount = 0x4037 - aExp; + if ( shiftCount <= 0 ) shiftCount = 1; + shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the 32-bit two's complement integer format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic, except that the conversion is always rounded +| toward zero. If `a' is a NaN, the largest positive integer is returned. +| Otherwise, if the conversion overflows, the largest integer with the same +| sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( 0x401E < aExp ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FFF ) { + if ( aExp || aSig ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + shiftCount = 0x403E - aExp; + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>( - shiftCount ); + if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the single-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 floatx80_to_float32( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig, 33, &aSig ); + if ( aExp || aSig ) aExp -= 0x3F81; + return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the double-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 floatx80_to_float64( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig, zSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat64( aSign, 0x7FF, 0 ); + } + shift64RightJamming( aSig, 1, &zSig ); + if ( aExp || aSig ) aExp -= 0x3C01; + return roundAndPackFloat64( aSign, aExp, zSig STATUS_VAR ); + +} + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the extended double-precision floating- +| point value `a' to the quadruple-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 floatx80_to_float128( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig, zSig0, zSig1; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) ); + } + shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 ); + return packFloat128( aSign, aExp, zSig0, zSig1 ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the extended double-precision floating-point value `a' to an integer, +| and returns the result as an extended quadruple-precision floating-point +| value. The operation is performed according to the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + floatx80 z; + + aExp = extractFloatx80Exp( a ); + if ( 0x403E <= aExp ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) { + return propagateFloatx80NaN( a, a STATUS_VAR ); + } + return a; + } + if ( aExp < 0x3FFF ) { + if ( ( aExp == 0 ) + && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) { + return a; + } + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloatx80Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 ) + ) { + return + packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) ); + } + break; + case float_round_down: + return + aSign ? + packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) ) + : packFloatx80( 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloatx80( 1, 0, 0 ) + : packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) ); + } + return packFloatx80( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x403E - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z.low += lastBitMask>>1; + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z.low += roundBitsMask; + } + } + z.low &= ~ roundBitsMask; + if ( z.low == 0 ) { + ++z.high; + z.low = LIT64( 0x8000000000000000 ); + } + if ( z.low != a.low ) STATUS(float_exception_flags) |= float_flag_inexact; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the extended double- +| precision floating-point values `a' and `b'. If `zSign' is 1, the sum is +| negated before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + return a; + } + zSig1 = 0; + zSig0 = aSig + bSig; + if ( aExp == 0 ) { + normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); + goto roundAndPack; + } + zExp = aExp; + goto shiftRight1; + } + zSig0 = aSig + bSig; + if ( (sbits64) zSig0 < 0 ) goto roundAndPack; + shiftRight1: + shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= LIT64( 0x8000000000000000 ); + ++zExp; + roundAndPack: + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the extended +| double-precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + zSig1 = 0; + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloatx80( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + bBigger: + sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + aBigger: + sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + return + normalizeRoundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the extended double-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return addFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the extended double-precision floating- +| point values `a' and `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return subFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloatx80Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the extended double-precision floating- +| point values `a' and `b'. The operation is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig ) == 0 ) goto invalid; + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FFE; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + if ( 0 < (sbits64) zSig0 ) { + shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); + --zExp; + } + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the extended double-precision floating-point +| value `a' by the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + bits64 rem0, rem1, rem2, term0, term1, term2; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + goto invalid; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return packFloatx80( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FFE; + rem1 = 0; + if ( bSig <= aSig ) { + shift128Right( aSig, 0, 1, &aSig, &rem1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig, rem1, bSig ); + mul64To128( bSig, zSig0, &term0, &term1 ); + sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, bSig ); + if ( (bits64) ( zSig1<<1 ) <= 8 ) { + mul64To128( bSig, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); + } + zSig1 |= ( ( rem1 | rem2 ) != 0 ); + } + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), zSign, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the extended double-precision floating-point value +| `a' with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig; + bits64 q, term0, term1, alternateASig0, alternateASig1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b STATUS_VAR ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( (bits64) ( aSig0<<1 ) == 0 ) return a; + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + bSig |= LIT64( 0x8000000000000000 ); + zSign = aSign; + expDiff = aExp - bExp; + aSig1 = 0; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); + expDiff = 0; + } + q = ( bSig <= aSig0 ); + if ( q ) aSig0 -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + mul64To128( bSig, q, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); + while ( le128( term0, term1, aSig0, aSig1 ) ) { + ++q; + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + } + } + else { + term1 = 0; + term0 = bSig; + } + sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); + if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) + || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) + && ( q & 1 ) ) + ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + zSign = ! zSign; + } + return + normalizeRoundAndPackFloatx80( + 80, zSign, bExp + expDiff, aSig0, aSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the extended double-precision floating-point +| value `a'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1, doubleZSig0; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; + zSig0 = estimateSqrt32( aExp, aSig0>>32 ); + shift128Right( aSig0, 0, 2 + ( aExp & 1 ), &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 ); + doubleZSig0 = zSig0<<1; + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + doubleZSig0 -= 2; + add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 ); + if ( ( zSig1 & LIT64( 0x3FFFFFFFFFFFFFFF ) ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( doubleZSig0, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift128Left( 0, zSig1, 1, &term2, &term3 ); + term3 |= 1; + term2 |= doubleZSig0; + add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shortShift128Left( 0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= doubleZSig0; + return + roundAndPackFloatx80( + STATUS(floatx80_rounding_precision), 0, zExp, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| equal to the corresponding value `b', and 0 otherwise. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| less than or equal to the corresponding value `b', and 0 otherwise. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| less than the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is equal +| to the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is less +| than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs +| do not cause an exception. Otherwise, the comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is less +| than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause +| an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the 32-bit two's complement integer format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| positive integer is returned. Otherwise, if the conversion overflows, the +| largest integer with the same sign as `a' is returned. +*----------------------------------------------------------------------------*/ + +int32 float128_to_int32( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0; + if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 ); + aSig0 |= ( aSig1 != 0 ); + shiftCount = 0x4028 - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 ); + return roundAndPackInt32( aSign, aSig0 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the 32-bit two's complement integer format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. If +| `a' is a NaN, the largest positive integer is returned. Otherwise, if the +| conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1, savedASig; + int32 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + aSig0 |= ( aSig1 != 0 ); + if ( 0x401E < aExp ) { + if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0; + goto invalid; + } + else if ( aExp < 0x3FFF ) { + if ( aExp || aSig0 ) STATUS(float_exception_flags) |= float_flag_inexact; + return 0; + } + aSig0 |= LIT64( 0x0001000000000000 ); + shiftCount = 0x402F - aExp; + savedASig = aSig0; + aSig0 >>= shiftCount; + z = aSig0; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig0<>( ( - shiftCount ) & 63 ) ); + if ( (bits64) ( aSig1<>( - shiftCount ); + if ( aSig1 + || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + } + if ( aSign ) z = - z; + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the single-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float32 float128_to_float32( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + bits32 zSig; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat32( aSign, 0xFF, 0 ); + } + aSig0 |= ( aSig1 != 0 ); + shift64RightJamming( aSig0, 18, &aSig0 ); + zSig = aSig0; + if ( aExp || zSig ) { + zSig |= 0x40000000; + aExp -= 0x3F81; + } + return roundAndPackFloat32( aSign, aExp, zSig STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the double-precision floating-point format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +float64 float128_to_float64( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloat64( aSign, 0x7FF, 0 ); + } + shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); + aSig0 |= ( aSig1 != 0 ); + if ( aExp || aSig0 ) { + aSig0 |= LIT64( 0x4000000000000000 ); + aExp -= 0x3C01; + } + return roundAndPackFloat64( aSign, aExp, aSig0 STATUS_VAR ); + +} + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the extended double-precision floating-point format. The +| conversion is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +floatx80 float128_to_floatx80( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) ); + } + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + else { + aSig0 |= LIT64( 0x0001000000000000 ); + } + shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 ); + return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 STATUS_VAR ); + +} + +#endif + +/*---------------------------------------------------------------------------- +| Rounds the quadruple-precision floating-point value `a' to an integer, and +| returns the result as a quadruple-precision floating-point value. The +| operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_round_to_int( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + float128 z; + + aExp = extractFloat128Exp( a ); + if ( 0x402F <= aExp ) { + if ( 0x406F <= aExp ) { + if ( ( aExp == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) + ) { + return propagateFloat128NaN( a, a STATUS_VAR ); + } + return a; + } + lastBitMask = 1; + lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + if ( lastBitMask ) { + add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low ); + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else { + if ( (sbits64) z.low < 0 ) { + ++z.high; + if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; + } + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); + } + } + z.low &= ~ roundBitsMask; + } + else { + if ( aExp < 0x3FFF ) { + if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; + STATUS(float_exception_flags) |= float_flag_inexact; + aSign = extractFloat128Sign( a ); + switch ( STATUS(float_rounding_mode) ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) + && ( extractFloat128Frac0( a ) + | extractFloat128Frac1( a ) ) + ) { + return packFloat128( aSign, 0x3FFF, 0, 0 ); + } + break; + case float_round_down: + return + aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) + : packFloat128( 0, 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloat128( 1, 0, 0, 0 ) + : packFloat128( 0, 0x3FFF, 0, 0 ); + } + return packFloat128( aSign, 0, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x402F - aExp; + roundBitsMask = lastBitMask - 1; + z.low = 0; + z.high = a.high; + roundingMode = STATUS(float_rounding_mode); + if ( roundingMode == float_round_nearest_even ) { + z.high += lastBitMask>>1; + if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { + z.high &= ~ lastBitMask; + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + z.high |= ( a.low != 0 ); + z.high += roundBitsMask; + } + } + z.high &= ~ roundBitsMask; + } + if ( ( z.low != a.low ) || ( z.high != a.high ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the absolute values of the quadruple-precision +| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated +| before being returned. `zSign' is ignored if the result is a NaN. +| The addition is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + int32 expDiff; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + return a; + } + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); + zSig2 = 0; + zSig0 |= LIT64( 0x0002000000000000 ); + zExp = aExp; + goto shiftRight1; + } + aSig0 |= LIT64( 0x0001000000000000 ); + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + --zExp; + if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack; + ++zExp; + shiftRight1: + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + roundAndPack: + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the absolute values of the quadruple- +| precision floating-point values `a' and `b'. If `zSign' is 1, the +| difference is negated before being returned. `zSign' is ignored if the +| result is a NaN. The subtraction is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float128 subFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; + int32 expDiff; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); + shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig0 < aSig0 ) goto aBigger; + if ( aSig0 < bSig0 ) goto bBigger; + if ( bSig1 < aSig1 ) goto aBigger; + if ( aSig1 < bSig1 ) goto bBigger; + return packFloat128( STATUS(float_rounding_mode) == float_round_down, 0, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + bSig0 |= LIT64( 0x4000000000000000 ); + bBigger: + sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); + aSig0 |= LIT64( 0x4000000000000000 ); + aBigger: + sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of adding the quadruple-precision floating-point values +| `a' and `b'. The operation is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_add( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return addFloat128Sigs( a, b, aSign STATUS_VAR ); + } + else { + return subFloat128Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of subtracting the quadruple-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_sub( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return subFloat128Sigs( a, b, aSign STATUS_VAR ); + } + else { + return addFloat128Sigs( a, b, aSign STATUS_VAR ); + } + +} + +/*---------------------------------------------------------------------------- +| Returns the result of multiplying the quadruple-precision floating-point +| values `a' and `b'. The operation is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_mul( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + zExp = aExp + bExp - 0x4000; + aSig0 |= LIT64( 0x0001000000000000 ); + shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); + mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); + add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zSig2 |= ( zSig3 != 0 ); + if ( LIT64( 0x0002000000000000 ) <= zSig0 ) { + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + ++zExp; + } + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the result of dividing the quadruple-precision floating-point value +| `a' by the corresponding value `b'. The operation is performed according to +| the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_div( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + goto invalid; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return packFloat128( zSign, 0, 0, 0 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero STATUS_VAR); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = aExp - bExp + 0x3FFD; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { + shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); + mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); + sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); + } + zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); + if ( ( zSig1 & 0x3FFF ) <= 4 ) { + mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); + sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the remainder of the quadruple-precision floating-point value `a' +| with respect to the corresponding value `b'. The operation is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_rem( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2; + bits64 allZero, alternateASig0, alternateASig1, sigMean1; + sbits64 sigMean0; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b STATUS_VAR ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b STATUS_VAR ); + return a; + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return a; + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + expDiff = aExp - bExp; + if ( expDiff < -1 ) return a; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), + aSig1, + 15 - ( expDiff < 0 ), + &aSig0, + &aSig1 + ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + q = le128( bSig0, bSig1, aSig0, aSig1 ); + if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero ); + shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero ); + sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 ); + expDiff -= 61; + } + if ( -64 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + q >>= - expDiff; + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + expDiff += 52; + if ( expDiff < 0 ) { + shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + } + else { + shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); + } + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); + } + else { + shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 ); + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + } + do { + alternateASig0 = aSig0; + alternateASig1 = aSig1; + ++q; + sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + } while ( 0 <= (sbits64) aSig0 ); + add128( + aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); + if ( ( sigMean0 < 0 ) + || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + } + zSign = ( (sbits64) aSig0 < 0 ); + if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); + return + normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns the square root of the quadruple-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +float128 float128_sqrt( float128 a STATUS_PARAM ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a STATUS_VAR ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid STATUS_VAR); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE; + aSig0 |= LIT64( 0x0001000000000000 ); + zSig0 = estimateSqrt32( aExp, aSig0>>17 ); + shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 ); + doubleZSig0 = zSig0<<1; + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + doubleZSig0 -= 2; + add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 ); + if ( ( zSig1 & 0x1FFF ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( doubleZSig0, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift128Left( 0, zSig1, 1, &term2, &term3 ); + term3 |= 1; + term2 |= doubleZSig0; + add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 14, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 STATUS_VAR ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float128_eq( float128 a, float128 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. The comparison +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float128_le( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float128_lt( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. Otherwise, the comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float128_le_quiet( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point value `a' is less than +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. Otherwise, the comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +flag float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + diff --git a/fpu/softfloat.h b/fpu/softfloat.h new file mode 100644 index 000000000..9aefbf75a --- /dev/null +++ b/fpu/softfloat.h @@ -0,0 +1,329 @@ +/*============================================================================ + +This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic +Package, Release 2b. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ +arithmetic/SoftFloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has +been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES +RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS +AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, +COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE +EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE +INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR +OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) the source code for the derivative work includes prominent notice that +the work is derivative, and (2) the source code includes prominent notice with +these four paragraphs for those parts of this code that are retained. + +=============================================================================*/ + +#ifndef SOFTFLOAT_H +#define SOFTFLOAT_H + +#include +#include "config.h" + +/*---------------------------------------------------------------------------- +| Each of the following `typedef's defines the most convenient type that holds +| integers of at least as many bits as specified. For example, `uint8' should +| be the most convenient type that can hold unsigned integers of as many as +| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most +| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +| to the same as `int'. +*----------------------------------------------------------------------------*/ +typedef char flag; +typedef uint8_t uint8; +typedef int8_t int8; +typedef int uint16; +typedef int int16; +typedef unsigned int uint32; +typedef signed int int32; +typedef uint64_t uint64; +typedef int64_t int64; + +/*---------------------------------------------------------------------------- +| Each of the following `typedef's defines a type that holds integers +| of _exactly_ the number of bits specified. For instance, for most +| implementation of C, `bits16' and `sbits16' should be `typedef'ed to +| `unsigned short int' and `signed short int' (or `short int'), respectively. +*----------------------------------------------------------------------------*/ +typedef uint8_t bits8; +typedef int8_t sbits8; +typedef uint16_t bits16; +typedef int16_t sbits16; +typedef uint32_t bits32; +typedef int32_t sbits32; +typedef uint64_t bits64; +typedef int64_t sbits64; + +#define LIT64( a ) a##LL +#define INLINE static inline + +/*---------------------------------------------------------------------------- +| The macro `FLOATX80' must be defined to enable the extended double-precision +| floating-point format `floatx80'. If this macro is not defined, the +| `floatx80' type will not be defined, and none of the functions that either +| input or output the `floatx80' type will be defined. The same applies to +| the `FLOAT128' macro and the quadruple-precision format `float128'. +*----------------------------------------------------------------------------*/ +#ifdef CONFIG_SOFTFLOAT +/* bit exact soft float support */ +#define FLOATX80 +#define FLOAT128 +#else +/* native float support */ +#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD) +#define FLOATX80 +#endif +#endif /* !CONFIG_SOFTFLOAT */ + +#define STATUS_PARAM , float_status *status +#define STATUS(field) status->field +#define STATUS_VAR , status + +#ifdef CONFIG_SOFTFLOAT +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point types. +*----------------------------------------------------------------------------*/ +typedef uint32_t float32; +typedef uint64_t float64; +#ifdef FLOATX80 +typedef struct { + uint64_t low; + uint16_t high; +} floatx80; +#endif +#ifdef FLOAT128 +typedef struct { +#ifdef WORDS_BIGENDIAN + uint64_t high, low; +#else + uint64_t low, high; +#endif +} float128; +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point underflow tininess-detection mode. +*----------------------------------------------------------------------------*/ +enum { + float_tininess_after_rounding = 0, + float_tininess_before_rounding = 1 +}; + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point rounding mode. +*----------------------------------------------------------------------------*/ +enum { + float_round_nearest_even = 0, + float_round_down = 1, + float_round_up = 2, + float_round_to_zero = 3 +}; + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point exception flags. +*----------------------------------------------------------------------------*/ +enum { + float_flag_invalid = 1, + float_flag_divbyzero = 4, + float_flag_overflow = 8, + float_flag_underflow = 16, + float_flag_inexact = 32 +}; + +typedef struct float_status { + signed char float_detect_tininess; + signed char float_rounding_mode; + signed char float_exception_flags; +#ifdef FLOATX80 + signed char floatx80_rounding_precision; +#endif +} float_status; + +void set_float_rounding_mode(int val STATUS_PARAM); +#ifdef FLOATX80 +void set_floatx80_rounding_precision(int val STATUS_PARAM); +#endif + +/*---------------------------------------------------------------------------- +| Routine to raise any or all of the software IEC/IEEE floating-point +| exception flags. +*----------------------------------------------------------------------------*/ +void float_raise( signed char STATUS_PARAM); + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE integer-to-floating-point conversion routines. +*----------------------------------------------------------------------------*/ +float32 int32_to_float32( int STATUS_PARAM ); +float64 int32_to_float64( int STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( int STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 int32_to_float128( int STATUS_PARAM ); +#endif +float32 int64_to_float32( int64_t STATUS_PARAM ); +float64 int64_to_float64( int64_t STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 int64_to_floatx80( int64_t STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 int64_to_float128( int64_t STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float32_to_int32( float32 STATUS_PARAM ); +int float32_to_int32_round_to_zero( float32 STATUS_PARAM ); +int64_t float32_to_int64( float32 STATUS_PARAM ); +int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM ); +float64 float32_to_float64( float32 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float32_to_float128( float32 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision operations. +*----------------------------------------------------------------------------*/ +float32 float32_round_to_int( float32 STATUS_PARAM ); +float32 float32_add( float32, float32 STATUS_PARAM ); +float32 float32_sub( float32, float32 STATUS_PARAM ); +float32 float32_mul( float32, float32 STATUS_PARAM ); +float32 float32_div( float32, float32 STATUS_PARAM ); +float32 float32_rem( float32, float32 STATUS_PARAM ); +float32 float32_sqrt( float32 STATUS_PARAM ); +char float32_eq( float32, float32 STATUS_PARAM ); +char float32_le( float32, float32 STATUS_PARAM ); +char float32_lt( float32, float32 STATUS_PARAM ); +char float32_eq_signaling( float32, float32 STATUS_PARAM ); +char float32_le_quiet( float32, float32 STATUS_PARAM ); +char float32_lt_quiet( float32, float32 STATUS_PARAM ); +char float32_is_signaling_nan( float32 ); + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float64_to_int32( float64 STATUS_PARAM ); +int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +int64_t float64_to_int64( float64 STATUS_PARAM ); +int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +float32 float64_to_float32( float64 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 STATUS_PARAM ); +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision operations. +*----------------------------------------------------------------------------*/ +float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_add( float64, float64 STATUS_PARAM ); +float64 float64_sub( float64, float64 STATUS_PARAM ); +float64 float64_mul( float64, float64 STATUS_PARAM ); +float64 float64_div( float64, float64 STATUS_PARAM ); +float64 float64_rem( float64, float64 STATUS_PARAM ); +float64 float64_sqrt( float64 STATUS_PARAM ); +char float64_eq( float64, float64 STATUS_PARAM ); +char float64_le( float64, float64 STATUS_PARAM ); +char float64_lt( float64, float64 STATUS_PARAM ); +char float64_eq_signaling( float64, float64 STATUS_PARAM ); +char float64_le_quiet( float64, float64 STATUS_PARAM ); +char float64_lt_quiet( float64, float64 STATUS_PARAM ); +char float64_is_signaling_nan( float64 ); + +#ifdef FLOATX80 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion routines. +*----------------------------------------------------------------------------*/ +int floatx80_to_int32( floatx80 STATUS_PARAM ); +int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64( floatx80 STATUS_PARAM ); +int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM ); +float32 floatx80_to_float32( floatx80 STATUS_PARAM ); +float64 floatx80_to_float64( floatx80 STATUS_PARAM ); +#ifdef FLOAT128 +float128 floatx80_to_float128( floatx80 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision operations. +*----------------------------------------------------------------------------*/ +floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM ); +floatx80 floatx80_add( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sub( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); +floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); +char floatx80_eq( floatx80, floatx80 STATUS_PARAM ); +char floatx80_le( floatx80, floatx80 STATUS_PARAM ); +char floatx80_lt( floatx80, floatx80 STATUS_PARAM ); +char floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); +char floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); +char floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); +char floatx80_is_signaling_nan( floatx80 ); + +#endif + +#ifdef FLOAT128 + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE quadruple-precision conversion routines. +*----------------------------------------------------------------------------*/ +int float128_to_int32( float128 STATUS_PARAM ); +int float128_to_int32_round_to_zero( float128 STATUS_PARAM ); +int64_t float128_to_int64( float128 STATUS_PARAM ); +int64_t float128_to_int64_round_to_zero( float128 STATUS_PARAM ); +float32 float128_to_float32( float128 STATUS_PARAM ); +float64 float128_to_float64( float128 STATUS_PARAM ); +#ifdef FLOATX80 +floatx80 float128_to_floatx80( float128 STATUS_PARAM ); +#endif + +/*---------------------------------------------------------------------------- +| Software IEC/IEEE quadruple-precision operations. +*----------------------------------------------------------------------------*/ +float128 float128_round_to_int( float128 STATUS_PARAM ); +float128 float128_add( float128, float128 STATUS_PARAM ); +float128 float128_sub( float128, float128 STATUS_PARAM ); +float128 float128_mul( float128, float128 STATUS_PARAM ); +float128 float128_div( float128, float128 STATUS_PARAM ); +float128 float128_rem( float128, float128 STATUS_PARAM ); +float128 float128_sqrt( float128 STATUS_PARAM ); +char float128_eq( float128, float128 STATUS_PARAM ); +char float128_le( float128, float128 STATUS_PARAM ); +char float128_lt( float128, float128 STATUS_PARAM ); +char float128_eq_signaling( float128, float128 STATUS_PARAM ); +char float128_le_quiet( float128, float128 STATUS_PARAM ); +char float128_lt_quiet( float128, float128 STATUS_PARAM ); +char float128_is_signaling_nan( float128 ); + +#endif + +#else /* CONFIG_SOFTFLOAT */ + +#include "softfloat-native.h" + +#endif /* !CONFIG_SOFTFLOAT */ + +#endif /* !SOFTFLOAT_H */ -- cgit v1.2.3 From 20495218834824723ef81306c6e1fd27fc3ae560 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 16:55:58 +0000 Subject: use the generic soft float code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1333 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/nwfpe/ARM-gcc.h | 120 -- target-arm/nwfpe/double_cpdo.c | 22 +- target-arm/nwfpe/extended_cpdo.c | 26 +- target-arm/nwfpe/fpa11.c | 25 +- target-arm/nwfpe/fpa11.h | 1 + target-arm/nwfpe/fpa11_cpdo.c | 12 +- target-arm/nwfpe/fpa11_cpdt.c | 12 +- target-arm/nwfpe/fpa11_cprt.c | 30 +- target-arm/nwfpe/fpopcode.c | 16 +- target-arm/nwfpe/milieu.h | 48 - target-arm/nwfpe/single_cpdo.c | 18 +- target-arm/nwfpe/softfloat-macros | 740 ------- target-arm/nwfpe/softfloat-specialize | 366 ---- target-arm/nwfpe/softfloat.c | 3427 --------------------------------- target-arm/nwfpe/softfloat.h | 232 --- 15 files changed, 84 insertions(+), 5011 deletions(-) delete mode 100644 target-arm/nwfpe/ARM-gcc.h delete mode 100644 target-arm/nwfpe/milieu.h delete mode 100644 target-arm/nwfpe/softfloat-macros delete mode 100644 target-arm/nwfpe/softfloat-specialize delete mode 100644 target-arm/nwfpe/softfloat.c delete mode 100644 target-arm/nwfpe/softfloat.h diff --git a/target-arm/nwfpe/ARM-gcc.h b/target-arm/nwfpe/ARM-gcc.h deleted file mode 100644 index e6598470b..000000000 --- a/target-arm/nwfpe/ARM-gcc.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -------------------------------------------------------------------------------- -The macro `BITS64' can be defined to indicate that 64-bit integer types are -supported by the compiler. -------------------------------------------------------------------------------- -*/ -#define BITS64 - -/* -------------------------------------------------------------------------------- -Each of the following `typedef's defines the most convenient type that holds -integers of at least as many bits as specified. For example, `uint8' should -be the most convenient type that can hold unsigned integers of as many as -8 bits. The `flag' type must be able to hold either a 0 or 1. For most -implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed -to the same as `int'. -------------------------------------------------------------------------------- -*/ -typedef char flag; -typedef unsigned char uint8; -typedef signed char int8; -typedef int uint16; -typedef int int16; -typedef unsigned int uint32; -typedef signed int int32; -#ifdef BITS64 -typedef unsigned long long int bits64; -typedef signed long long int sbits64; -#endif - -/* -------------------------------------------------------------------------------- -Each of the following `typedef's defines a type that holds integers -of _exactly_ the number of bits specified. For instance, for most -implementation of C, `bits16' and `sbits16' should be `typedef'ed to -`unsigned short int' and `signed short int' (or `short int'), respectively. -------------------------------------------------------------------------------- -*/ -typedef unsigned char bits8; -typedef signed char sbits8; -typedef unsigned short int bits16; -typedef signed short int sbits16; -typedef unsigned int bits32; -typedef signed int sbits32; -#ifdef BITS64 -typedef unsigned long long int uint64; -typedef signed long long int int64; -#endif - -#ifdef BITS64 -/* -------------------------------------------------------------------------------- -The `LIT64' macro takes as its argument a textual integer literal and if -necessary ``marks'' the literal as having a 64-bit integer type. For -example, the Gnu C Compiler (`gcc') requires that 64-bit literals be -appended with the letters `LL' standing for `long long', which is `gcc's -name for the 64-bit integer type. Some compilers may allow `LIT64' to be -defined as the identity macro: `#define LIT64( a ) a'. -------------------------------------------------------------------------------- -*/ -#define LIT64( a ) a##LL -#endif - -/* -------------------------------------------------------------------------------- -The macro `INLINE' can be used before functions that should be inlined. If -a compiler does not support explicit inlining, this macro should be defined -to be `static'. -------------------------------------------------------------------------------- -*/ -#define INLINE extern __inline__ - - -/* For use as a GCC soft-float library we need some special function names. */ - -#ifdef __LIBFLOAT__ - -/* Some 32-bit ops can be mapped straight across by just changing the name. */ -#define float32_add __addsf3 -#define float32_sub __subsf3 -#define float32_mul __mulsf3 -#define float32_div __divsf3 -#define int32_to_float32 __floatsisf -#define float32_to_int32_round_to_zero __fixsfsi -#define float32_to_uint32_round_to_zero __fixunssfsi - -/* These ones go through the glue code. To avoid namespace pollution - we rename the internal functions too. */ -#define float32_eq ___float32_eq -#define float32_le ___float32_le -#define float32_lt ___float32_lt - -/* All the 64-bit ops have to go through the glue, so we pull the same - trick. */ -#define float64_add ___float64_add -#define float64_sub ___float64_sub -#define float64_mul ___float64_mul -#define float64_div ___float64_div -#define int32_to_float64 ___int32_to_float64 -#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero -#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero -#define float64_to_float32 ___float64_to_float32 -#define float32_to_float64 ___float32_to_float64 -#define float64_eq ___float64_eq -#define float64_le ___float64_le -#define float64_lt ___float64_lt - -#if 0 -#define float64_add __adddf3 -#define float64_sub __subdf3 -#define float64_mul __muldf3 -#define float64_div __divdf3 -#define int32_to_float64 __floatsidf -#define float64_to_int32_round_to_zero __fixdfsi -#define float64_to_uint32_round_to_zero __fixunsdfsi -#define float64_to_float32 __truncdfsf2 -#define float32_to_float64 __extendsfdf2 -#endif - -#endif diff --git a/target-arm/nwfpe/double_cpdo.c b/target-arm/nwfpe/double_cpdo.c index c44d3fc58..944083a43 100644 --- a/target-arm/nwfpe/double_cpdo.c +++ b/target-arm/nwfpe/double_cpdo.c @@ -53,7 +53,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) switch (fpa11->fType[Fm]) { case typeSingle: - rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); break; case typeDouble: @@ -79,7 +79,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) switch (fpa11->fType[Fn]) { case typeSingle: - rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeDouble: @@ -96,30 +96,30 @@ unsigned int DoubleCPDO(const unsigned int opcode) { /* dyadic opcodes */ case ADF_CODE: - fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm, &fpa11->fp_status); break; case MUF_CODE: case FML_CODE: - fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm, &fpa11->fp_status); break; case SUF_CODE: - fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm, &fpa11->fp_status); break; case RSF_CODE: - fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn); + fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn, &fpa11->fp_status); break; case DVF_CODE: case FDV_CODE: - fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm, &fpa11->fp_status); break; case RDF_CODE: case FRD_CODE: - fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn); + fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn, &fpa11->fp_status); break; #if 0 @@ -133,7 +133,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) #endif case RMF_CODE: - fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm); + fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm, &fpa11->fp_status); break; #if 0 @@ -173,11 +173,11 @@ unsigned int DoubleCPDO(const unsigned int opcode) case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); + fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm, &fpa11->fp_status); break; case SQT_CODE: - fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm); + fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm, &fpa11->fp_status); break; #if 0 diff --git a/target-arm/nwfpe/extended_cpdo.c b/target-arm/nwfpe/extended_cpdo.c index 331407596..f5ef62311 100644 --- a/target-arm/nwfpe/extended_cpdo.c +++ b/target-arm/nwfpe/extended_cpdo.c @@ -53,11 +53,11 @@ unsigned int ExtendedCPDO(const unsigned int opcode) switch (fpa11->fType[Fm]) { case typeSingle: - rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); break; case typeDouble: - rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; case typeExtended: @@ -74,11 +74,11 @@ unsigned int ExtendedCPDO(const unsigned int opcode) switch (fpa11->fType[Fn]) { case typeSingle: - rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeDouble: - rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; case typeExtended: @@ -94,30 +94,30 @@ unsigned int ExtendedCPDO(const unsigned int opcode) { /* dyadic opcodes */ case ADF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm, &fpa11->fp_status); break; case MUF_CODE: case FML_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm, &fpa11->fp_status); break; case SUF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm, &fpa11->fp_status); break; case RSF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn); + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn, &fpa11->fp_status); break; case DVF_CODE: case FDV_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm, &fpa11->fp_status); break; case RDF_CODE: case FRD_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn); + fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn, &fpa11->fp_status); break; #if 0 @@ -131,7 +131,7 @@ unsigned int ExtendedCPDO(const unsigned int opcode) #endif case RMF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm); + fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm, &fpa11->fp_status); break; #if 0 @@ -157,11 +157,11 @@ unsigned int ExtendedCPDO(const unsigned int opcode) case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm, &fpa11->fp_status); break; case SQT_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm); + fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm, &fpa11->fp_status); break; #if 0 diff --git a/target-arm/nwfpe/fpa11.c b/target-arm/nwfpe/fpa11.c index 143bcd399..cfbe700c0 100644 --- a/target-arm/nwfpe/fpa11.c +++ b/target-arm/nwfpe/fpa11.c @@ -61,74 +61,79 @@ void resetFPA11(void) void SetRoundingMode(const unsigned int opcode) { -#if MAINTAIN_FPCR + int rounding_mode; FPA11 *fpa11 = GET_FPA11(); + +#if MAINTAIN_FPCR fpa11->fpcr &= ~MASK_ROUNDING_MODE; #endif switch (opcode & MASK_ROUNDING_MODE) { default: case ROUND_TO_NEAREST: - float_rounding_mode = float_round_nearest_even; + rounding_mode = float_round_nearest_even; #if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_NEAREST; #endif break; case ROUND_TO_PLUS_INFINITY: - float_rounding_mode = float_round_up; + rounding_mode = float_round_up; #if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; #endif break; case ROUND_TO_MINUS_INFINITY: - float_rounding_mode = float_round_down; + rounding_mode = float_round_down; #if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; #endif break; case ROUND_TO_ZERO: - float_rounding_mode = float_round_to_zero; + rounding_mode = float_round_to_zero; #if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_ZERO; #endif break; } + set_float_rounding_mode(rounding_mode, &fpa11->fp_status); } void SetRoundingPrecision(const unsigned int opcode) { -#if MAINTAIN_FPCR + int rounding_precision; FPA11 *fpa11 = GET_FPA11(); +#if MAINTAIN_FPCR fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; #endif switch (opcode & MASK_ROUNDING_PRECISION) { case ROUND_SINGLE: - floatx80_rounding_precision = 32; + rounding_precision = 32; #if MAINTAIN_FPCR fpa11->fpcr |= ROUND_SINGLE; #endif break; case ROUND_DOUBLE: - floatx80_rounding_precision = 64; + rounding_precision = 64; #if MAINTAIN_FPCR fpa11->fpcr |= ROUND_DOUBLE; #endif break; case ROUND_EXTENDED: - floatx80_rounding_precision = 80; + rounding_precision = 80; #if MAINTAIN_FPCR fpa11->fpcr |= ROUND_EXTENDED; #endif break; - default: floatx80_rounding_precision = 80; + default: rounding_precision = 80; } + set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status); } /* Emulate the instruction in the opcode. */ diff --git a/target-arm/nwfpe/fpa11.h b/target-arm/nwfpe/fpa11.h index 389c02986..668393cff 100644 --- a/target-arm/nwfpe/fpa11.h +++ b/target-arm/nwfpe/fpa11.h @@ -83,6 +83,7 @@ typedef struct tagFPA11 { so we can use it to detect whether this instance of the emulator needs to be initialised. */ + float_status fp_status; /* QEMU float emulator status */ } FPA11; extern FPA11* qemufpa; diff --git a/target-arm/nwfpe/fpa11_cpdo.c b/target-arm/nwfpe/fpa11_cpdo.c index 343a6b9fd..cc8aa87c6 100644 --- a/target-arm/nwfpe/fpa11_cpdo.c +++ b/target-arm/nwfpe/fpa11_cpdo.c @@ -80,10 +80,10 @@ unsigned int EmulateCPDO(const unsigned int opcode) { if (typeDouble == nType) fpa11->fpreg[Fd].fSingle = - float64_to_float32(fpa11->fpreg[Fd].fDouble); + float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); else fpa11->fpreg[Fd].fSingle = - floatx80_to_float32(fpa11->fpreg[Fd].fExtended); + floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); } break; @@ -91,10 +91,10 @@ unsigned int EmulateCPDO(const unsigned int opcode) { if (typeSingle == nType) fpa11->fpreg[Fd].fDouble = - float32_to_float64(fpa11->fpreg[Fd].fSingle); + float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); else fpa11->fpreg[Fd].fDouble = - floatx80_to_float64(fpa11->fpreg[Fd].fExtended); + floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); } break; @@ -102,10 +102,10 @@ unsigned int EmulateCPDO(const unsigned int opcode) { if (typeSingle == nType) fpa11->fpreg[Fd].fExtended = - float32_to_floatx80(fpa11->fpreg[Fd].fSingle); + float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); else fpa11->fpreg[Fd].fExtended = - float64_to_floatx80(fpa11->fpreg[Fd].fDouble); + float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); } break; } diff --git a/target-arm/nwfpe/fpa11_cpdt.c b/target-arm/nwfpe/fpa11_cpdt.c index c1d561554..3319d88e1 100644 --- a/target-arm/nwfpe/fpa11_cpdt.c +++ b/target-arm/nwfpe/fpa11_cpdt.c @@ -106,11 +106,11 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem) switch (fpa11->fType[Fn]) { case typeDouble: - val = float64_to_float32(fpa11->fpreg[Fn].fDouble); + val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; case typeExtended: - val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); + val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); break; default: val = fpa11->fpreg[Fn].fSingle; @@ -129,11 +129,11 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem) switch (fpa11->fType[Fn]) { case typeSingle: - val = float32_to_float64(fpa11->fpreg[Fn].fSingle); + val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeExtended: - val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); + val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); break; default: val = fpa11->fpreg[Fn].fDouble; @@ -157,11 +157,11 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem) switch (fpa11->fType[Fn]) { case typeSingle: - val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeDouble: - val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; default: val = fpa11->fpreg[Fn].fExtended; diff --git a/target-arm/nwfpe/fpa11_cprt.c b/target-arm/nwfpe/fpa11_cprt.c index 17871c1d7..fe295e1aa 100644 --- a/target-arm/nwfpe/fpa11_cprt.c +++ b/target-arm/nwfpe/fpa11_cprt.c @@ -21,7 +21,6 @@ */ #include "fpa11.h" -#include "milieu.h" #include "softfloat.h" #include "fpopcode.h" #include "fpa11.inl" @@ -89,7 +88,7 @@ unsigned int PerformFLT(const unsigned int opcode) { fpa11->fType[getFn(opcode)] = typeSingle; fpa11->fpreg[getFn(opcode)].fSingle = - int32_to_float32(readRegister(getRd(opcode))); + int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status); } break; @@ -97,7 +96,7 @@ unsigned int PerformFLT(const unsigned int opcode) { fpa11->fType[getFn(opcode)] = typeDouble; fpa11->fpreg[getFn(opcode)].fDouble = - int32_to_float64(readRegister(getRd(opcode))); + int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status); } break; @@ -105,7 +104,7 @@ unsigned int PerformFLT(const unsigned int opcode) { fpa11->fType[getFn(opcode)] = typeExtended; fpa11->fpreg[getFn(opcode)].fExtended = - int32_to_floatx80(readRegister(getRd(opcode))); + int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status); } break; @@ -128,7 +127,7 @@ unsigned int PerformFIX(const unsigned int opcode) case typeSingle: { writeRegister(getRd(opcode), - float32_to_int32(fpa11->fpreg[Fn].fSingle)); + float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status)); } break; @@ -136,14 +135,14 @@ unsigned int PerformFIX(const unsigned int opcode) { //printf("F%d is 0x%llx\n",Fn,fpa11->fpreg[Fn].fDouble); writeRegister(getRd(opcode), - float64_to_int32(fpa11->fpreg[Fn].fDouble)); + float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status)); } break; case typeExtended: { writeRegister(getRd(opcode), - floatx80_to_int32(fpa11->fpreg[Fn].fExtended)); + floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status)); } break; @@ -157,22 +156,23 @@ unsigned int PerformFIX(const unsigned int opcode) static unsigned int __inline__ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) { + FPA11 *fpa11 = GET_FPA11(); unsigned int flags = 0; /* test for less than condition */ - if (floatx80_lt(Fn,Fm)) + if (floatx80_lt(Fn,Fm, &fpa11->fp_status)) { flags |= CC_NEGATIVE; } /* test for equal condition */ - if (floatx80_eq(Fn,Fm)) + if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) { flags |= CC_ZERO; } /* test for greater than or equal condition */ - if (floatx80_lt(Fm,Fn)) + if (floatx80_lt(Fm,Fn, &fpa11->fp_status)) { flags |= CC_CARRY; } @@ -208,14 +208,14 @@ static unsigned int PerformComparison(const unsigned int opcode) //printk("single.\n"); if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) goto unordered; - rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeDouble: //printk("double.\n"); if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) goto unordered; - rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; case typeExtended: @@ -244,14 +244,14 @@ static unsigned int PerformComparison(const unsigned int opcode) //printk("single.\n"); if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) goto unordered; - rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); break; case typeDouble: //printk("double.\n"); if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) goto unordered; - rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; case typeExtended: @@ -283,7 +283,7 @@ static unsigned int PerformComparison(const unsigned int opcode) if (BIT_AC & readFPSR()) flags |= CC_CARRY; - if (e_flag) float_raise(float_flag_invalid); + if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status); writeConditionCodes(flags); return 1; diff --git a/target-arm/nwfpe/fpopcode.c b/target-arm/nwfpe/fpopcode.c index 0886a0bdf..d29e913f4 100644 --- a/target-arm/nwfpe/fpopcode.c +++ b/target-arm/nwfpe/fpopcode.c @@ -27,14 +27,14 @@ //#include "fpmodule.inl" const floatx80 floatx80Constant[] = { - { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ - { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ - { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ - { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ - { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ - { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ - { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ - { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ + { 0x0000000000000000ULL, 0x0000}, /* extended 0.0 */ + { 0x8000000000000000ULL, 0x3fff}, /* extended 1.0 */ + { 0x8000000000000000ULL, 0x4000}, /* extended 2.0 */ + { 0xc000000000000000ULL, 0x4000}, /* extended 3.0 */ + { 0x8000000000000000ULL, 0x4001}, /* extended 4.0 */ + { 0xa000000000000000ULL, 0x4001}, /* extended 5.0 */ + { 0x8000000000000000ULL, 0x3ffe}, /* extended 0.5 */ + { 0xa000000000000000ULL, 0x4002} /* extended 10.0 */ }; const float64 float64Constant[] = { diff --git a/target-arm/nwfpe/milieu.h b/target-arm/nwfpe/milieu.h deleted file mode 100644 index a3892ab2d..000000000 --- a/target-arm/nwfpe/milieu.h +++ /dev/null @@ -1,48 +0,0 @@ - -/* -=============================================================================== - -This C header file is part of the SoftFloat IEC/IEEE Floating-point -Arithmetic Package, Release 2. - -Written by John R. Hauser. This work was made possible in part by the -International Computer Science Institute, located at Suite 600, 1947 Center -Street, Berkeley, California 94704. Funding was partially provided by the -National Science Foundation under grant MIP-9311980. The original version -of this code was written as part of a project to build a fixed-point vector -processor in collaboration with the University of California at Berkeley, -overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ -arithmetic/softfloat.html'. - -THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort -has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT -TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO -PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY -AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - -Derivative works are acceptable, even for commercial purposes, so long as -(1) they include prominent notice that the work is derivative, and (2) they -include prominent notice akin to these three paragraphs for those parts of -this code that are retained. - -=============================================================================== -*/ - -/* -------------------------------------------------------------------------------- -Include common integer types and flags. -------------------------------------------------------------------------------- -*/ -#include "ARM-gcc.h" - -/* -------------------------------------------------------------------------------- -Symbolic Boolean literals. -------------------------------------------------------------------------------- -*/ -enum { - FALSE = 0, - TRUE = 1 -}; - diff --git a/target-arm/nwfpe/single_cpdo.c b/target-arm/nwfpe/single_cpdo.c index 58da89b05..7dd2620f2 100644 --- a/target-arm/nwfpe/single_cpdo.c +++ b/target-arm/nwfpe/single_cpdo.c @@ -76,30 +76,30 @@ unsigned int SingleCPDO(const unsigned int opcode) { /* dyadic opcodes */ case ADF_CODE: - fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm, &fpa11->fp_status); break; case MUF_CODE: case FML_CODE: - fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm, &fpa11->fp_status); break; case SUF_CODE: - fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm, &fpa11->fp_status); break; case RSF_CODE: - fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn); + fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn, &fpa11->fp_status); break; case DVF_CODE: case FDV_CODE: - fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm, &fpa11->fp_status); break; case RDF_CODE: case FRD_CODE: - fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn); + fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn, &fpa11->fp_status); break; #if 0 @@ -113,7 +113,7 @@ unsigned int SingleCPDO(const unsigned int opcode) #endif case RMF_CODE: - fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm); + fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm, &fpa11->fp_status); break; #if 0 @@ -139,11 +139,11 @@ unsigned int SingleCPDO(const unsigned int opcode) case RND_CODE: case URD_CODE: - fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm); + fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm, &fpa11->fp_status); break; case SQT_CODE: - fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm); + fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm, &fpa11->fp_status); break; #if 0 diff --git a/target-arm/nwfpe/softfloat-macros b/target-arm/nwfpe/softfloat-macros deleted file mode 100644 index c245a0ef4..000000000 --- a/target-arm/nwfpe/softfloat-macros +++ /dev/null @@ -1,740 +0,0 @@ - -/* -=============================================================================== - -This C source fragment is part of the SoftFloat IEC/IEEE Floating-point -Arithmetic Package, Release 2. - -Written by John R. Hauser. This work was made possible in part by the -International Computer Science Institute, located at Suite 600, 1947 Center -Street, Berkeley, California 94704. Funding was partially provided by the -National Science Foundation under grant MIP-9311980. The original version -of this code was written as part of a project to build a fixed-point vector -processor in collaboration with the University of California at Berkeley, -overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ -arithmetic/softfloat.html'. - -THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort -has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT -TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO -PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY -AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - -Derivative works are acceptable, even for commercial purposes, so long as -(1) they include prominent notice that the work is derivative, and (2) they -include prominent notice akin to these three paragraphs for those parts of -this code that are retained. - -=============================================================================== -*/ - -/* -------------------------------------------------------------------------------- -Shifts `a' right by the number of bits given in `count'. If any nonzero -bits are shifted off, they are ``jammed'' into the least significant bit of -the result by setting the least significant bit to 1. The value of `count' -can be arbitrarily large; in particular, if `count' is greater than 32, the -result will be either 0 or 1, depending on whether `a' is zero or nonzero. -The result is stored in the location pointed to by `zPtr'. -------------------------------------------------------------------------------- -*/ -INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) -{ - bits32 z; - if ( count == 0 ) { - z = a; - } - else if ( count < 32 ) { - z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); - } - else { - z = ( a != 0 ); - } - *zPtr = z; -} - -/* -------------------------------------------------------------------------------- -Shifts `a' right by the number of bits given in `count'. If any nonzero -bits are shifted off, they are ``jammed'' into the least significant bit of -the result by setting the least significant bit to 1. The value of `count' -can be arbitrarily large; in particular, if `count' is greater than 64, the -result will be either 0 or 1, depending on whether `a' is zero or nonzero. -The result is stored in the location pointed to by `zPtr'. -------------------------------------------------------------------------------- -*/ -INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) -{ - bits64 z; - -// __asm__("@shift64RightJamming -- start"); - if ( count == 0 ) { - z = a; - } - else if ( count < 64 ) { - z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); - } - else { - z = ( a != 0 ); - } -// __asm__("@shift64RightJamming -- end"); - *zPtr = z; -} - -/* -------------------------------------------------------------------------------- -Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 -_plus_ the number of bits given in `count'. The shifted result is at most -64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The -bits shifted off form a second 64-bit result as follows: The _last_ bit -shifted off is the most-significant bit of the extra result, and the other -63 bits of the extra result are all zero if and only if _all_but_the_last_ -bits shifted off were all zero. This extra result is stored in the location -pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. - (This routine makes more sense if `a0' and `a1' are considered to form a -fixed-point value with binary point between `a0' and `a1'. This fixed-point -value is shifted right by the number of bits given in `count', and the -integer part of the result is returned at the location pointed to by -`z0Ptr'. The fractional part of the result may be slightly corrupted as -described above, and is returned at the location pointed to by `z1Ptr'.) -------------------------------------------------------------------------------- -*/ -INLINE void - shift64ExtraRightJamming( - bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) -{ - bits64 z0, z1; - int8 negCount = ( - count ) & 63; - - if ( count == 0 ) { - z1 = a1; - z0 = a0; - } - else if ( count < 64 ) { - z1 = ( a0<>count; - } - else { - if ( count == 64 ) { - z1 = a0 | ( a1 != 0 ); - } - else { - z1 = ( ( a0 | a1 ) != 0 ); - } - z0 = 0; - } - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the -number of bits given in `count'. Any bits shifted off are lost. The value -of `count' can be arbitrarily large; in particular, if `count' is greater -than 128, the result will be 0. The result is broken into two 64-bit pieces -which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - shift128Right( - bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) -{ - bits64 z0, z1; - int8 negCount = ( - count ) & 63; - - if ( count == 0 ) { - z1 = a1; - z0 = a0; - } - else if ( count < 64 ) { - z1 = ( a0<>count ); - z0 = a0>>count; - } - else { - z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; - z0 = 0; - } - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the -number of bits given in `count'. If any nonzero bits are shifted off, they -are ``jammed'' into the least significant bit of the result by setting the -least significant bit to 1. The value of `count' can be arbitrarily large; -in particular, if `count' is greater than 128, the result will be either 0 -or 1, depending on whether the concatenation of `a0' and `a1' is zero or -nonzero. The result is broken into two 64-bit pieces which are stored at -the locations pointed to by `z0Ptr' and `z1Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - shift128RightJamming( - bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) -{ - bits64 z0, z1; - int8 negCount = ( - count ) & 63; - - if ( count == 0 ) { - z1 = a1; - z0 = a0; - } - else if ( count < 64 ) { - z1 = ( a0<>count ) | ( ( a1<>count; - } - else { - if ( count == 64 ) { - z1 = a0 | ( a1 != 0 ); - } - else if ( count < 128 ) { - z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count ); - z0 = a0>>count; - } - else { - if ( count == 64 ) { - z2 = a1; - z1 = a0; - } - else { - a2 |= a1; - if ( count < 128 ) { - z2 = a0<>( count & 63 ); - } - else { - z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); - z1 = 0; - } - } - z0 = 0; - } - z2 |= ( a2 != 0 ); - } - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the -number of bits given in `count'. Any bits shifted off are lost. The value -of `count' must be less than 64. The result is broken into two 64-bit -pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - shortShift128Left( - bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) -{ - - *z1Ptr = a1<>( ( - count ) & 63 ) ); - -} - -/* -------------------------------------------------------------------------------- -Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left -by the number of bits given in `count'. Any bits shifted off are lost. -The value of `count' must be less than 64. The result is broken into three -64-bit pieces which are stored at the locations pointed to by `z0Ptr', -`z1Ptr', and `z2Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - shortShift192Left( - bits64 a0, - bits64 a1, - bits64 a2, - int16 count, - bits64 *z0Ptr, - bits64 *z1Ptr, - bits64 *z2Ptr - ) -{ - bits64 z0, z1, z2; - int8 negCount; - - z2 = a2<>negCount; - z0 |= a1>>negCount; - } - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit -value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so -any carry out is lost. The result is broken into two 64-bit pieces which -are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - add128( - bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) -{ - bits64 z1; - - z1 = a1 + b1; - *z1Ptr = z1; - *z0Ptr = a0 + b0 + ( z1 < a1 ); - -} - -/* -------------------------------------------------------------------------------- -Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the -192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is -modulo 2^192, so any carry out is lost. The result is broken into three -64-bit pieces which are stored at the locations pointed to by `z0Ptr', -`z1Ptr', and `z2Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - add192( - bits64 a0, - bits64 a1, - bits64 a2, - bits64 b0, - bits64 b1, - bits64 b2, - bits64 *z0Ptr, - bits64 *z1Ptr, - bits64 *z2Ptr - ) -{ - bits64 z0, z1, z2; - int8 carry0, carry1; - - z2 = a2 + b2; - carry1 = ( z2 < a2 ); - z1 = a1 + b1; - carry0 = ( z1 < a1 ); - z0 = a0 + b0; - z1 += carry1; - z0 += ( z1 < carry1 ); - z0 += carry0; - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the -128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo -2^128, so any borrow out (carry out) is lost. The result is broken into two -64-bit pieces which are stored at the locations pointed to by `z0Ptr' and -`z1Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - sub128( - bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) -{ - - *z1Ptr = a1 - b1; - *z0Ptr = a0 - b0 - ( a1 < b1 ); - -} - -/* -------------------------------------------------------------------------------- -Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' -from the 192-bit value formed by concatenating `a0', `a1', and `a2'. -Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The -result is broken into three 64-bit pieces which are stored at the locations -pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - sub192( - bits64 a0, - bits64 a1, - bits64 a2, - bits64 b0, - bits64 b1, - bits64 b2, - bits64 *z0Ptr, - bits64 *z1Ptr, - bits64 *z2Ptr - ) -{ - bits64 z0, z1, z2; - int8 borrow0, borrow1; - - z2 = a2 - b2; - borrow1 = ( a2 < b2 ); - z1 = a1 - b1; - borrow0 = ( a1 < b1 ); - z0 = a0 - b0; - z0 -= ( z1 < borrow1 ); - z1 -= borrow1; - z0 -= borrow0; - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Multiplies `a' by `b' to obtain a 128-bit product. The product is broken -into two 64-bit pieces which are stored at the locations pointed to by -`z0Ptr' and `z1Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) -{ - bits32 aHigh, aLow, bHigh, bLow; - bits64 z0, zMiddleA, zMiddleB, z1; - - aLow = a; - aHigh = a>>32; - bLow = b; - bHigh = b>>32; - z1 = ( (bits64) aLow ) * bLow; - zMiddleA = ( (bits64) aLow ) * bHigh; - zMiddleB = ( (bits64) aHigh ) * bLow; - z0 = ( (bits64) aHigh ) * bHigh; - zMiddleA += zMiddleB; - z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); - zMiddleA <<= 32; - z1 += zMiddleA; - z0 += ( z1 < zMiddleA ); - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to -obtain a 192-bit product. The product is broken into three 64-bit pieces -which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and -`z2Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - mul128By64To192( - bits64 a0, - bits64 a1, - bits64 b, - bits64 *z0Ptr, - bits64 *z1Ptr, - bits64 *z2Ptr - ) -{ - bits64 z0, z1, z2, more1; - - mul64To128( a1, b, &z1, &z2 ); - mul64To128( a0, b, &z0, &more1 ); - add128( z0, more1, 0, z1, &z0, &z1 ); - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the -128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit -product. The product is broken into four 64-bit pieces which are stored at -the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. -------------------------------------------------------------------------------- -*/ -INLINE void - mul128To256( - bits64 a0, - bits64 a1, - bits64 b0, - bits64 b1, - bits64 *z0Ptr, - bits64 *z1Ptr, - bits64 *z2Ptr, - bits64 *z3Ptr - ) -{ - bits64 z0, z1, z2, z3; - bits64 more1, more2; - - mul64To128( a1, b1, &z2, &z3 ); - mul64To128( a1, b0, &z1, &more2 ); - add128( z1, more2, 0, z2, &z1, &z2 ); - mul64To128( a0, b0, &z0, &more1 ); - add128( z0, more1, 0, z1, &z0, &z1 ); - mul64To128( a0, b1, &more1, &more2 ); - add128( more1, more2, 0, z2, &more1, &z2 ); - add128( z0, z1, 0, more1, &z0, &z1 ); - *z3Ptr = z3; - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; - -} - -/* -------------------------------------------------------------------------------- -Returns an approximation to the 64-bit integer quotient obtained by dividing -`b' into the 128-bit value formed by concatenating `a0' and `a1'. The -divisor `b' must be at least 2^63. If q is the exact quotient truncated -toward zero, the approximation returned lies between q and q + 2 inclusive. -If the exact quotient q is larger than 64 bits, the maximum positive 64-bit -unsigned integer is returned. -------------------------------------------------------------------------------- -*/ -static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) -{ - bits64 b0, b1; - bits64 rem0, rem1, term0, term1; - bits64 z; - if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); - b0 = b>>32; - z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; - mul64To128( b, z, &term0, &term1 ); - sub128( a0, a1, term0, term1, &rem0, &rem1 ); - while ( ( (sbits64) rem0 ) < 0 ) { - z -= LIT64( 0x100000000 ); - b1 = b<<32; - add128( rem0, rem1, b0, b1, &rem0, &rem1 ); - } - rem0 = ( rem0<<32 ) | ( rem1>>32 ); - z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns an approximation to the square root of the 32-bit significand given -by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of -`aExp' (the least significant bit) is 1, the integer returned approximates -2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' -is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either -case, the approximation returned lies strictly within +/-2 of the exact -value. -------------------------------------------------------------------------------- -*/ -static bits32 estimateSqrt32( int16 aExp, bits32 a ) -{ - static const bits16 sqrtOddAdjustments[] = { - 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, - 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 - }; - static const bits16 sqrtEvenAdjustments[] = { - 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, - 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 - }; - int8 index; - bits32 z; - - index = ( a>>27 ) & 15; - if ( aExp & 1 ) { - z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; - z = ( ( a / z )<<14 ) + ( z<<15 ); - a >>= 1; - } - else { - z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; - z = a / z + z; - z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); - if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); - } - return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the number of leading 0 bits before the most-significant 1 bit -of `a'. If `a' is zero, 32 is returned. -------------------------------------------------------------------------------- -*/ -static int8 countLeadingZeros32( bits32 a ) -{ - static const int8 countLeadingZerosHigh[] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - int8 shiftCount; - - shiftCount = 0; - if ( a < 0x10000 ) { - shiftCount += 16; - a <<= 16; - } - if ( a < 0x1000000 ) { - shiftCount += 8; - a <<= 8; - } - shiftCount += countLeadingZerosHigh[ a>>24 ]; - return shiftCount; - -} - -/* -------------------------------------------------------------------------------- -Returns the number of leading 0 bits before the most-significant 1 bit -of `a'. If `a' is zero, 64 is returned. -------------------------------------------------------------------------------- -*/ -static int8 countLeadingZeros64( bits64 a ) -{ - int8 shiftCount; - - shiftCount = 0; - if ( a < ( (bits64) 1 )<<32 ) { - shiftCount += 32; - } - else { - a >>= 32; - } - shiftCount += countLeadingZeros32( a ); - return shiftCount; - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' -is equal to the 128-bit value formed by concatenating `b0' and `b1'. -Otherwise, returns 0. -------------------------------------------------------------------------------- -*/ -INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) -{ - - return ( a0 == b0 ) && ( a1 == b1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less -than or equal to the 128-bit value formed by concatenating `b0' and `b1'. -Otherwise, returns 0. -------------------------------------------------------------------------------- -*/ -INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) -{ - - return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less -than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, -returns 0. -------------------------------------------------------------------------------- -*/ -INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) -{ - - return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is -not equal to the 128-bit value formed by concatenating `b0' and `b1'. -Otherwise, returns 0. -------------------------------------------------------------------------------- -*/ -INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) -{ - - return ( a0 != b0 ) || ( a1 != b1 ); - -} - diff --git a/target-arm/nwfpe/softfloat-specialize b/target-arm/nwfpe/softfloat-specialize deleted file mode 100644 index a23a8a360..000000000 --- a/target-arm/nwfpe/softfloat-specialize +++ /dev/null @@ -1,366 +0,0 @@ - -/* -=============================================================================== - -This C source fragment is part of the SoftFloat IEC/IEEE Floating-point -Arithmetic Package, Release 2. - -Written by John R. Hauser. This work was made possible in part by the -International Computer Science Institute, located at Suite 600, 1947 Center -Street, Berkeley, California 94704. Funding was partially provided by the -National Science Foundation under grant MIP-9311980. The original version -of this code was written as part of a project to build a fixed-point vector -processor in collaboration with the University of California at Berkeley, -overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ -arithmetic/softfloat.html'. - -THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort -has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT -TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO -PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY -AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - -Derivative works are acceptable, even for commercial purposes, so long as -(1) they include prominent notice that the work is derivative, and (2) they -include prominent notice akin to these three paragraphs for those parts of -this code that are retained. - -=============================================================================== -*/ - -/* -------------------------------------------------------------------------------- -Underflow tininess-detection mode, statically initialized to default value. -(The declaration in `softfloat.h' must match the `int8' type here.) -------------------------------------------------------------------------------- -*/ -int8 float_detect_tininess = float_tininess_after_rounding; - -/* -------------------------------------------------------------------------------- -Raises the exceptions specified by `flags'. Floating-point traps can be -defined here if desired. It is currently not possible for such a trap to -substitute a result value. If traps are not implemented, this routine -should be simply `float_exception_flags |= flags;'. - -ScottB: November 4, 1998 -Moved this function out of softfloat-specialize into fpmodule.c. -This effectively isolates all the changes required for integrating with the -Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying -fpmodule.c to integrate with the NetBSD kernel (I hope!). -------------------------------------------------------------------------------- -*/ -void float_raise( int8 flags ) -{ - float_exception_flags |= flags; -} - -/* -------------------------------------------------------------------------------- -Internal canonical NaN format. -------------------------------------------------------------------------------- -*/ -typedef struct { - flag sign; - bits64 high, low; -} commonNaNT; - -/* -------------------------------------------------------------------------------- -The pattern for a default generated single-precision NaN. -------------------------------------------------------------------------------- -*/ -#define float32_default_nan 0xFFFFFFFF - -/* -------------------------------------------------------------------------------- -Returns 1 if the single-precision floating-point value `a' is a NaN; -otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag float32_is_nan( float32 a ) -{ - - return ( 0xFF000000 < (bits32) ( a<<1 ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the single-precision floating-point value `a' is a signaling -NaN; otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag float32_is_signaling_nan( float32 a ) -{ - - return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the single-precision floating-point NaN -`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid -exception is raised. -------------------------------------------------------------------------------- -*/ -static commonNaNT float32ToCommonNaN( float32 a ) -{ - commonNaNT z; - - if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); - z.sign = a>>31; - z.low = 0; - z.high = ( (bits64) a )<<41; - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the canonical NaN `a' to the single- -precision floating-point format. -------------------------------------------------------------------------------- -*/ -static float32 commonNaNToFloat32( commonNaNT a ) -{ - - return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); - -} - -/* -------------------------------------------------------------------------------- -Takes two single-precision floating-point values `a' and `b', one of which -is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a -signaling NaN, the invalid exception is raised. -------------------------------------------------------------------------------- -*/ -static float32 propagateFloat32NaN( float32 a, float32 b ) -{ - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; - - aIsNaN = float32_is_nan( a ); - aIsSignalingNaN = float32_is_signaling_nan( a ); - bIsNaN = float32_is_nan( b ); - bIsSignalingNaN = float32_is_signaling_nan( b ); - a |= 0x00400000; - b |= 0x00400000; - if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); - if ( aIsNaN ) { - return ( aIsSignalingNaN & bIsNaN ) ? b : a; - } - else { - return b; - } - -} - -/* -------------------------------------------------------------------------------- -The pattern for a default generated double-precision NaN. -------------------------------------------------------------------------------- -*/ -#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF ) - -/* -------------------------------------------------------------------------------- -Returns 1 if the double-precision floating-point value `a' is a NaN; -otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag float64_is_nan( float64 a ) -{ - - return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the double-precision floating-point value `a' is a signaling -NaN; otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag float64_is_signaling_nan( float64 a ) -{ - - return - ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) - && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the double-precision floating-point NaN -`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid -exception is raised. -------------------------------------------------------------------------------- -*/ -static commonNaNT float64ToCommonNaN( float64 a ) -{ - commonNaNT z; - - if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); - z.sign = a>>63; - z.low = 0; - z.high = a<<12; - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the canonical NaN `a' to the double- -precision floating-point format. -------------------------------------------------------------------------------- -*/ -static float64 commonNaNToFloat64( commonNaNT a ) -{ - - return - ( ( (bits64) a.sign )<<63 ) - | LIT64( 0x7FF8000000000000 ) - | ( a.high>>12 ); - -} - -/* -------------------------------------------------------------------------------- -Takes two double-precision floating-point values `a' and `b', one of which -is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a -signaling NaN, the invalid exception is raised. -------------------------------------------------------------------------------- -*/ -static float64 propagateFloat64NaN( float64 a, float64 b ) -{ - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; - - aIsNaN = float64_is_nan( a ); - aIsSignalingNaN = float64_is_signaling_nan( a ); - bIsNaN = float64_is_nan( b ); - bIsSignalingNaN = float64_is_signaling_nan( b ); - a |= LIT64( 0x0008000000000000 ); - b |= LIT64( 0x0008000000000000 ); - if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); - if ( aIsNaN ) { - return ( aIsSignalingNaN & bIsNaN ) ? b : a; - } - else { - return b; - } - -} - -#ifdef FLOATX80 - -/* -------------------------------------------------------------------------------- -The pattern for a default generated extended double-precision NaN. The -`high' and `low' values hold the most- and least-significant bits, -respectively. -------------------------------------------------------------------------------- -*/ -#define floatx80_default_nan_high 0xFFFF -#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) - -/* -------------------------------------------------------------------------------- -Returns 1 if the extended double-precision floating-point value `a' is a -NaN; otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag floatx80_is_nan( floatx80 a ) -{ - - return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the extended double-precision floating-point value `a' is a -signaling NaN; otherwise returns 0. -------------------------------------------------------------------------------- -*/ -flag floatx80_is_signaling_nan( floatx80 a ) -{ - //register int lr; - bits64 aLow; - - //__asm__("mov %0, lr" : : "g" (lr)); - //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr); - aLow = a.low & ~ LIT64( 0x4000000000000000 ); - return - ( ( a.high & 0x7FFF ) == 0x7FFF ) - && (bits64) ( aLow<<1 ) - && ( a.low == aLow ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the extended double-precision floating- -point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the -invalid exception is raised. -------------------------------------------------------------------------------- -*/ -static commonNaNT floatx80ToCommonNaN( floatx80 a ) -{ - commonNaNT z; - - if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); - z.sign = a.high>>15; - z.low = 0; - z.high = a.low<<1; - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the canonical NaN `a' to the extended -double-precision floating-point format. -------------------------------------------------------------------------------- -*/ -static floatx80 commonNaNToFloatx80( commonNaNT a ) -{ - floatx80 z; - - z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); - z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; - return z; - -} - -/* -------------------------------------------------------------------------------- -Takes two extended double-precision floating-point values `a' and `b', one -of which is a NaN, and returns the appropriate NaN result. If either `a' or -`b' is a signaling NaN, the invalid exception is raised. -------------------------------------------------------------------------------- -*/ -static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b ) -{ - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; - - aIsNaN = floatx80_is_nan( a ); - aIsSignalingNaN = floatx80_is_signaling_nan( a ); - bIsNaN = floatx80_is_nan( b ); - bIsSignalingNaN = floatx80_is_signaling_nan( b ); - a.low |= LIT64( 0xC000000000000000 ); - b.low |= LIT64( 0xC000000000000000 ); - if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); - if ( aIsNaN ) { - return ( aIsSignalingNaN & bIsNaN ) ? b : a; - } - else { - return b; - } - -} - -#endif diff --git a/target-arm/nwfpe/softfloat.c b/target-arm/nwfpe/softfloat.c deleted file mode 100644 index 8ffb9a98d..000000000 --- a/target-arm/nwfpe/softfloat.c +++ /dev/null @@ -1,3427 +0,0 @@ -/* -=============================================================================== - -This C source file is part of the SoftFloat IEC/IEEE Floating-point -Arithmetic Package, Release 2. - -Written by John R. Hauser. This work was made possible in part by the -International Computer Science Institute, located at Suite 600, 1947 Center -Street, Berkeley, California 94704. Funding was partially provided by the -National Science Foundation under grant MIP-9311980. The original version -of this code was written as part of a project to build a fixed-point vector -processor in collaboration with the University of California at Berkeley, -overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ -arithmetic/softfloat.html'. - -THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort -has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT -TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO -PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY -AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - -Derivative works are acceptable, even for commercial purposes, so long as -(1) they include prominent notice that the work is derivative, and (2) they -include prominent notice akin to these three paragraphs for those parts of -this code that are retained. - -=============================================================================== -*/ - -#include "fpa11.h" -#include "milieu.h" -#include "softfloat.h" - -/* -------------------------------------------------------------------------------- -Floating-point rounding mode, extended double-precision rounding precision, -and exception flags. -------------------------------------------------------------------------------- -*/ -int8 float_rounding_mode = float_round_nearest_even; -int8 floatx80_rounding_precision = 80; -int8 float_exception_flags; - -/* -------------------------------------------------------------------------------- -Primitive arithmetic functions, including multi-word arithmetic, and -division and square root approximations. (Can be specialized to target if -desired.) -------------------------------------------------------------------------------- -*/ -#include "softfloat-macros" - -/* -------------------------------------------------------------------------------- -Functions and definitions to determine: (1) whether tininess for underflow -is detected before or after rounding by default, (2) what (if anything) -happens when exceptions are raised, (3) how signaling NaNs are distinguished -from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs -are propagated from function inputs to output. These details are target- -specific. -------------------------------------------------------------------------------- -*/ -#include "softfloat-specialize" - -/* -------------------------------------------------------------------------------- -Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 -and 7, and returns the properly rounded 32-bit integer corresponding to the -input. If `zSign' is nonzero, the input is negated before being converted -to an integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point -input is simply rounded to an integer, with the inexact exception raised if -the input cannot be represented exactly as an integer. If the fixed-point -input is too large, however, the invalid exception is raised and the largest -positive or negative integer is returned. -------------------------------------------------------------------------------- -*/ -static int32 roundAndPackInt32( flag zSign, bits64 absZ ) -{ - int8 roundingMode; - flag roundNearestEven; - int8 roundIncrement, roundBits; - int32 z; - - roundingMode = float_rounding_mode; - roundNearestEven = ( roundingMode == float_round_nearest_even ); - roundIncrement = 0x40; - if ( ! roundNearestEven ) { - if ( roundingMode == float_round_to_zero ) { - roundIncrement = 0; - } - else { - roundIncrement = 0x7F; - if ( zSign ) { - if ( roundingMode == float_round_up ) roundIncrement = 0; - } - else { - if ( roundingMode == float_round_down ) roundIncrement = 0; - } - } - } - roundBits = absZ & 0x7F; - absZ = ( absZ + roundIncrement )>>7; - absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); - z = absZ; - if ( zSign ) z = - z; - if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { - float_exception_flags |= float_flag_invalid; - return zSign ? 0x80000000 : 0x7FFFFFFF; - } - if ( roundBits ) float_exception_flags |= float_flag_inexact; - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the fraction bits of the single-precision floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE bits32 extractFloat32Frac( float32 a ) -{ - - return a & 0x007FFFFF; - -} - -/* -------------------------------------------------------------------------------- -Returns the exponent bits of the single-precision floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE int16 extractFloat32Exp( float32 a ) -{ - - return ( a>>23 ) & 0xFF; - -} - -/* -------------------------------------------------------------------------------- -Returns the sign bit of the single-precision floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE flag extractFloat32Sign( float32 a ) -{ - - return a>>31; - -} - -/* -------------------------------------------------------------------------------- -Normalizes the subnormal single-precision floating-point value represented -by the denormalized significand `aSig'. The normalized exponent and -significand are stored at the locations pointed to by `zExpPtr' and -`zSigPtr', respectively. -------------------------------------------------------------------------------- -*/ -static void - normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) -{ - int8 shiftCount; - - shiftCount = countLeadingZeros32( aSig ) - 8; - *zSigPtr = aSig<>7; - zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); - if ( zSig == 0 ) zExp = 0; - return packFloat32( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Takes an abstract floating-point value having sign `zSign', exponent `zExp', -and significand `zSig', and returns the proper single-precision floating- -point value corresponding to the abstract input. This routine is just like -`roundAndPackFloat32' except that `zSig' does not have to be normalized in -any way. In all cases, `zExp' must be 1 less than the ``true'' floating- -point exponent. -------------------------------------------------------------------------------- -*/ -static float32 - normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ) -{ - int8 shiftCount; - - shiftCount = countLeadingZeros32( zSig ) - 1; - return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>52 ) & 0x7FF; - -} - -/* -------------------------------------------------------------------------------- -Returns the sign bit of the double-precision floating-point value `a'. -------------------------------------------------------------------------------- -*/ -INLINE flag extractFloat64Sign( float64 a ) -{ - - return a>>63; - -} - -/* -------------------------------------------------------------------------------- -Normalizes the subnormal double-precision floating-point value represented -by the denormalized significand `aSig'. The normalized exponent and -significand are stored at the locations pointed to by `zExpPtr' and -`zSigPtr', respectively. -------------------------------------------------------------------------------- -*/ -static void - normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) -{ - int8 shiftCount; - - shiftCount = countLeadingZeros64( aSig ) - 11; - *zSigPtr = aSig<>10; - zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); - if ( zSig == 0 ) zExp = 0; - return packFloat64( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Takes an abstract floating-point value having sign `zSign', exponent `zExp', -and significand `zSig', and returns the proper double-precision floating- -point value corresponding to the abstract input. This routine is just like -`roundAndPackFloat64' except that `zSig' does not have to be normalized in -any way. In all cases, `zExp' must be 1 less than the ``true'' floating- -point exponent. -------------------------------------------------------------------------------- -*/ -static float64 - normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig ) -{ - int8 shiftCount; - - shiftCount = countLeadingZeros64( zSig ) - 1; - return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>15; - -} - -/* -------------------------------------------------------------------------------- -Normalizes the subnormal extended double-precision floating-point value -represented by the denormalized significand `aSig'. The normalized exponent -and significand are stored at the locations pointed to by `zExpPtr' and -`zSigPtr', respectively. -------------------------------------------------------------------------------- -*/ -static void - normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) -{ - int8 shiftCount; - - shiftCount = countLeadingZeros64( aSig ); - *zSigPtr = aSig<>( - shiftCount ); - if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { - float_exception_flags |= float_flag_inexact; - } - return aSign ? - z : z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the single-precision floating-point value -`a' to the double-precision floating-point format. The conversion is -performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic. -------------------------------------------------------------------------------- -*/ -float64 float32_to_float64( float32 a ) -{ - flag aSign; - int16 aExp; - bits32 aSig; - - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - aSign = extractFloat32Sign( a ); - if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) ); - return packFloat64( aSign, 0x7FF, 0 ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); - normalizeFloat32Subnormal( aSig, &aExp, &aSig ); - --aExp; - } - return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); - -} - -#ifdef FLOATX80 - -/* -------------------------------------------------------------------------------- -Returns the result of converting the single-precision floating-point value -`a' to the extended double-precision floating-point format. The conversion -is performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic. -------------------------------------------------------------------------------- -*/ -floatx80 float32_to_floatx80( float32 a ) -{ - flag aSign; - int16 aExp; - bits32 aSig; - - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - aSign = extractFloat32Sign( a ); - if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) ); - return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); - normalizeFloat32Subnormal( aSig, &aExp, &aSig ); - } - aSig |= 0x00800000; - return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); - -} - -#endif - -/* -------------------------------------------------------------------------------- -Rounds the single-precision floating-point value `a' to an integer, and -returns the result as a single-precision floating-point value. The -operation is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float32 float32_round_to_int( float32 a ) -{ - flag aSign; - int16 aExp; - bits32 lastBitMask, roundBitsMask; - int8 roundingMode; - float32 z; - - aExp = extractFloat32Exp( a ); - if ( 0x96 <= aExp ) { - if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { - return propagateFloat32NaN( a, a ); - } - return a; - } - if ( aExp <= 0x7E ) { - if ( (bits32) ( a<<1 ) == 0 ) return a; - float_exception_flags |= float_flag_inexact; - aSign = extractFloat32Sign( a ); - switch ( float_rounding_mode ) { - case float_round_nearest_even: - if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { - return packFloat32( aSign, 0x7F, 0 ); - } - break; - case float_round_down: - return aSign ? 0xBF800000 : 0; - case float_round_up: - return aSign ? 0x80000000 : 0x3F800000; - } - return packFloat32( aSign, 0, 0 ); - } - lastBitMask = 1; - lastBitMask <<= 0x96 - aExp; - roundBitsMask = lastBitMask - 1; - z = a; - roundingMode = float_rounding_mode; - if ( roundingMode == float_round_nearest_even ) { - z += lastBitMask>>1; - if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; - } - else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { - z += roundBitsMask; - } - } - z &= ~ roundBitsMask; - if ( z != a ) float_exception_flags |= float_flag_inexact; - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the absolute values of the single-precision -floating-point values `a' and `b'. If `zSign' is true, the sum is negated -before being returned. `zSign' is ignored if the result is a NaN. The -addition is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static float32 addFloat32Sigs( float32 a, float32 b, flag zSign ) -{ - int16 aExp, bExp, zExp; - bits32 aSig, bSig, zSig; - int16 expDiff; - - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - bSig = extractFloat32Frac( b ); - bExp = extractFloat32Exp( b ); - expDiff = aExp - bExp; - aSig <<= 6; - bSig <<= 6; - if ( 0 < expDiff ) { - if ( aExp == 0xFF ) { - if ( aSig ) return propagateFloat32NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig |= 0x20000000; - } - shift32RightJamming( bSig, expDiff, &bSig ); - zExp = aExp; - } - else if ( expDiff < 0 ) { - if ( bExp == 0xFF ) { - if ( bSig ) return propagateFloat32NaN( a, b ); - return packFloat32( zSign, 0xFF, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig |= 0x20000000; - } - shift32RightJamming( aSig, - expDiff, &aSig ); - zExp = bExp; - } - else { - if ( aExp == 0xFF ) { - if ( aSig | bSig ) return propagateFloat32NaN( a, b ); - return a; - } - if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); - zSig = 0x40000000 + aSig + bSig; - zExp = aExp; - goto roundAndPack; - } - aSig |= 0x20000000; - zSig = ( aSig + bSig )<<1; - --zExp; - if ( (sbits32) zSig < 0 ) { - zSig = aSig + bSig; - ++zExp; - } - roundAndPack: - return roundAndPackFloat32( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the absolute values of the single- -precision floating-point values `a' and `b'. If `zSign' is true, the -difference is negated before being returned. `zSign' is ignored if the -result is a NaN. The subtraction is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static float32 subFloat32Sigs( float32 a, float32 b, flag zSign ) -{ - int16 aExp, bExp, zExp; - bits32 aSig, bSig, zSig; - int16 expDiff; - - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - bSig = extractFloat32Frac( b ); - bExp = extractFloat32Exp( b ); - expDiff = aExp - bExp; - aSig <<= 7; - bSig <<= 7; - if ( 0 < expDiff ) goto aExpBigger; - if ( expDiff < 0 ) goto bExpBigger; - if ( aExp == 0xFF ) { - if ( aSig | bSig ) return propagateFloat32NaN( a, b ); - float_raise( float_flag_invalid ); - return float32_default_nan; - } - if ( aExp == 0 ) { - aExp = 1; - bExp = 1; - } - if ( bSig < aSig ) goto aBigger; - if ( aSig < bSig ) goto bBigger; - return packFloat32( float_rounding_mode == float_round_down, 0, 0 ); - bExpBigger: - if ( bExp == 0xFF ) { - if ( bSig ) return propagateFloat32NaN( a, b ); - return packFloat32( zSign ^ 1, 0xFF, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig |= 0x40000000; - } - shift32RightJamming( aSig, - expDiff, &aSig ); - bSig |= 0x40000000; - bBigger: - zSig = bSig - aSig; - zExp = bExp; - zSign ^= 1; - goto normalizeRoundAndPack; - aExpBigger: - if ( aExp == 0xFF ) { - if ( aSig ) return propagateFloat32NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig |= 0x40000000; - } - shift32RightJamming( bSig, expDiff, &bSig ); - aSig |= 0x40000000; - aBigger: - zSig = aSig - bSig; - zExp = aExp; - normalizeRoundAndPack: - --zExp; - return normalizeRoundAndPackFloat32( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the single-precision floating-point values `a' -and `b'. The operation is performed according to the IEC/IEEE Standard for -Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float32 float32_add( float32 a, float32 b ) -{ - flag aSign, bSign; - - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - if ( aSign == bSign ) { - return addFloat32Sigs( a, b, aSign ); - } - else { - return subFloat32Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the single-precision floating-point values -`a' and `b'. The operation is performed according to the IEC/IEEE Standard -for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float32 float32_sub( float32 a, float32 b ) -{ - flag aSign, bSign; - - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - if ( aSign == bSign ) { - return subFloat32Sigs( a, b, aSign ); - } - else { - return addFloat32Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of multiplying the single-precision floating-point values -`a' and `b'. The operation is performed according to the IEC/IEEE Standard -for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float32 float32_mul( float32 a, float32 b ) -{ - flag aSign, bSign, zSign; - int16 aExp, bExp, zExp; - bits32 aSig, bSig; - bits64 zSig64; - bits32 zSig; - - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - aSign = extractFloat32Sign( a ); - bSig = extractFloat32Frac( b ); - bExp = extractFloat32Exp( b ); - bSign = extractFloat32Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0xFF ) { - if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { - return propagateFloat32NaN( a, b ); - } - if ( ( bExp | bSig ) == 0 ) { - float_raise( float_flag_invalid ); - return float32_default_nan; - } - return packFloat32( zSign, 0xFF, 0 ); - } - if ( bExp == 0xFF ) { - if ( bSig ) return propagateFloat32NaN( a, b ); - if ( ( aExp | aSig ) == 0 ) { - float_raise( float_flag_invalid ); - return float32_default_nan; - } - return packFloat32( zSign, 0xFF, 0 ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); - normalizeFloat32Subnormal( aSig, &aExp, &aSig ); - } - if ( bExp == 0 ) { - if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); - normalizeFloat32Subnormal( bSig, &bExp, &bSig ); - } - zExp = aExp + bExp - 0x7F; - aSig = ( aSig | 0x00800000 )<<7; - bSig = ( bSig | 0x00800000 )<<8; - shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); - zSig = zSig64; - if ( 0 <= (sbits32) ( zSig<<1 ) ) { - zSig <<= 1; - --zExp; - } - return roundAndPackFloat32( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of dividing the single-precision floating-point value `a' -by the corresponding value `b'. The operation is performed according to the -IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float32 float32_div( float32 a, float32 b ) -{ - flag aSign, bSign, zSign; - int16 aExp, bExp, zExp; - bits32 aSig, bSig, zSig; - - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - aSign = extractFloat32Sign( a ); - bSig = extractFloat32Frac( b ); - bExp = extractFloat32Exp( b ); - bSign = extractFloat32Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0xFF ) { - if ( aSig ) return propagateFloat32NaN( a, b ); - if ( bExp == 0xFF ) { - if ( bSig ) return propagateFloat32NaN( a, b ); - float_raise( float_flag_invalid ); - return float32_default_nan; - } - return packFloat32( zSign, 0xFF, 0 ); - } - if ( bExp == 0xFF ) { - if ( bSig ) return propagateFloat32NaN( a, b ); - return packFloat32( zSign, 0, 0 ); - } - if ( bExp == 0 ) { - if ( bSig == 0 ) { - if ( ( aExp | aSig ) == 0 ) { - float_raise( float_flag_invalid ); - return float32_default_nan; - } - float_raise( float_flag_divbyzero ); - return packFloat32( zSign, 0xFF, 0 ); - } - normalizeFloat32Subnormal( bSig, &bExp, &bSig ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); - normalizeFloat32Subnormal( aSig, &aExp, &aSig ); - } - zExp = aExp - bExp + 0x7D; - aSig = ( aSig | 0x00800000 )<<7; - bSig = ( bSig | 0x00800000 )<<8; - if ( bSig <= ( aSig + aSig ) ) { - aSig >>= 1; - ++zExp; - } - zSig = ( ( (bits64) aSig )<<32 ) / bSig; - if ( ( zSig & 0x3F ) == 0 ) { - zSig |= ( ( (bits64) bSig ) * zSig != ( (bits64) aSig )<<32 ); - } - return roundAndPackFloat32( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the remainder of the single-precision floating-point value `a' -with respect to the corresponding value `b'. The operation is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float32 float32_rem( float32 a, float32 b ) -{ - flag aSign, bSign, zSign; - int16 aExp, bExp, expDiff; - bits32 aSig, bSig; - bits32 q; - bits64 aSig64, bSig64, q64; - bits32 alternateASig; - sbits32 sigMean; - - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - aSign = extractFloat32Sign( a ); - bSig = extractFloat32Frac( b ); - bExp = extractFloat32Exp( b ); - bSign = extractFloat32Sign( b ); - if ( aExp == 0xFF ) { - if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { - return propagateFloat32NaN( a, b ); - } - float_raise( float_flag_invalid ); - return float32_default_nan; - } - if ( bExp == 0xFF ) { - if ( bSig ) return propagateFloat32NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - if ( bSig == 0 ) { - float_raise( float_flag_invalid ); - return float32_default_nan; - } - normalizeFloat32Subnormal( bSig, &bExp, &bSig ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return a; - normalizeFloat32Subnormal( aSig, &aExp, &aSig ); - } - expDiff = aExp - bExp; - aSig |= 0x00800000; - bSig |= 0x00800000; - if ( expDiff < 32 ) { - aSig <<= 8; - bSig <<= 8; - if ( expDiff < 0 ) { - if ( expDiff < -1 ) return a; - aSig >>= 1; - } - q = ( bSig <= aSig ); - if ( q ) aSig -= bSig; - if ( 0 < expDiff ) { - q = ( ( (bits64) aSig )<<32 ) / bSig; - q >>= 32 - expDiff; - bSig >>= 2; - aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; - } - else { - aSig >>= 2; - bSig >>= 2; - } - } - else { - if ( bSig <= aSig ) aSig -= bSig; - aSig64 = ( (bits64) aSig )<<40; - bSig64 = ( (bits64) bSig )<<40; - expDiff -= 64; - while ( 0 < expDiff ) { - q64 = estimateDiv128To64( aSig64, 0, bSig64 ); - q64 = ( 2 < q64 ) ? q64 - 2 : 0; - aSig64 = - ( ( bSig * q64 )<<38 ); - expDiff -= 62; - } - expDiff += 64; - q64 = estimateDiv128To64( aSig64, 0, bSig64 ); - q64 = ( 2 < q64 ) ? q64 - 2 : 0; - q = q64>>( 64 - expDiff ); - bSig <<= 6; - aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; - } - do { - alternateASig = aSig; - ++q; - aSig -= bSig; - } while ( 0 <= (sbits32) aSig ); - sigMean = aSig + alternateASig; - if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { - aSig = alternateASig; - } - zSign = ( (sbits32) aSig < 0 ); - if ( zSign ) aSig = - aSig; - return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the square root of the single-precision floating-point value `a'. -The operation is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float32 float32_sqrt( float32 a ) -{ - flag aSign; - int16 aExp, zExp; - bits32 aSig, zSig; - bits64 rem, term; - - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - aSign = extractFloat32Sign( a ); - if ( aExp == 0xFF ) { - if ( aSig ) return propagateFloat32NaN( a, 0 ); - if ( ! aSign ) return a; - float_raise( float_flag_invalid ); - return float32_default_nan; - } - if ( aSign ) { - if ( ( aExp | aSig ) == 0 ) return a; - float_raise( float_flag_invalid ); - return float32_default_nan; - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return 0; - normalizeFloat32Subnormal( aSig, &aExp, &aSig ); - } - zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; - aSig = ( aSig | 0x00800000 )<<8; - zSig = estimateSqrt32( aExp, aSig ) + 2; - if ( ( zSig & 0x7F ) <= 5 ) { - if ( zSig < 2 ) { - zSig = 0xFFFFFFFF; - } - else { - aSig >>= aExp & 1; - term = ( (bits64) zSig ) * zSig; - rem = ( ( (bits64) aSig )<<32 ) - term; - while ( (sbits64) rem < 0 ) { - --zSig; - rem += ( ( (bits64) zSig )<<1 ) | 1; - } - zSig |= ( rem != 0 ); - } - } - shift32RightJamming( zSig, 1, &zSig ); - return roundAndPackFloat32( 0, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the single-precision floating-point value `a' is equal to the -corresponding value `b', and 0 otherwise. The comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float32_eq( float32 a, float32 b ) -{ - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the single-precision floating-point value `a' is less than or -equal to the corresponding value `b', and 0 otherwise. The comparison is -performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float32_le( float32 a, float32 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the single-precision floating-point value `a' is less than -the corresponding value `b', and 0 otherwise. The comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float32_lt( float32 a, float32 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the single-precision floating-point value `a' is equal to the -corresponding value `b', and 0 otherwise. The invalid exception is raised -if either operand is a NaN. Otherwise, the comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float32_eq_signaling( float32 a, float32 b ) -{ - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the single-precision floating-point value `a' is less than or -equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not -cause an exception. Otherwise, the comparison is performed according to the -IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float32_le_quiet( float32 a, float32 b ) -{ - flag aSign, bSign; - //int16 aExp, bExp; - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the single-precision floating-point value `a' is less than -the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -exception. Otherwise, the comparison is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float32_lt_quiet( float32 a, float32 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) - || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) - ) { - if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloat32Sign( a ); - bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the double-precision floating-point value -`a' to the 32-bit two's complement integer format. The conversion is -performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic---which means in particular that the conversion is rounded -according to the current rounding mode. If `a' is a NaN, the largest -positive integer is returned. Otherwise, if the conversion overflows, the -largest integer with the same sign as `a' is returned. -------------------------------------------------------------------------------- -*/ -int32 float64_to_int32( float64 a ) -{ - flag aSign; - int16 aExp, shiftCount; - bits64 aSig; - - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - aSign = extractFloat64Sign( a ); - if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; - if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); - shiftCount = 0x42C - aExp; - if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); - return roundAndPackInt32( aSign, aSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the double-precision floating-point value -`a' to the 32-bit two's complement integer format. The conversion is -performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic, except that the conversion is always rounded toward zero. If -`a' is a NaN, the largest positive integer is returned. Otherwise, if the -conversion overflows, the largest integer with the same sign as `a' is -returned. -------------------------------------------------------------------------------- -*/ -int32 float64_to_int32_round_to_zero( float64 a ) -{ - flag aSign; - int16 aExp, shiftCount; - bits64 aSig, savedASig; - int32 z; - - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - aSign = extractFloat64Sign( a ); - shiftCount = 0x433 - aExp; - if ( shiftCount < 21 ) { - if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; - goto invalid; - } - else if ( 52 < shiftCount ) { - if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; - return 0; - } - aSig |= LIT64( 0x0010000000000000 ); - savedASig = aSig; - aSig >>= shiftCount; - z = aSig; - if ( aSign ) z = - z; - if ( ( z < 0 ) ^ aSign ) { - invalid: - float_exception_flags |= float_flag_invalid; - return aSign ? 0x80000000 : 0x7FFFFFFF; - } - if ( ( aSig<>= shiftCount; - z = aSig; - if ( aSign ) z = - z; - if ( ( z < 0 ) ^ aSign ) { - invalid: - float_exception_flags |= float_flag_invalid; - return aSign ? 0x80000000 : 0x7FFFFFFF; - } - if ( ( aSig<>1; - if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; - } - else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { - z += roundBitsMask; - } - } - z &= ~ roundBitsMask; - if ( z != a ) float_exception_flags |= float_flag_inexact; - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the absolute values of the double-precision -floating-point values `a' and `b'. If `zSign' is true, the sum is negated -before being returned. `zSign' is ignored if the result is a NaN. The -addition is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static float64 addFloat64Sigs( float64 a, float64 b, flag zSign ) -{ - int16 aExp, bExp, zExp; - bits64 aSig, bSig, zSig; - int16 expDiff; - - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - bSig = extractFloat64Frac( b ); - bExp = extractFloat64Exp( b ); - expDiff = aExp - bExp; - aSig <<= 9; - bSig <<= 9; - if ( 0 < expDiff ) { - if ( aExp == 0x7FF ) { - if ( aSig ) return propagateFloat64NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig |= LIT64( 0x2000000000000000 ); - } - shift64RightJamming( bSig, expDiff, &bSig ); - zExp = aExp; - } - else if ( expDiff < 0 ) { - if ( bExp == 0x7FF ) { - if ( bSig ) return propagateFloat64NaN( a, b ); - return packFloat64( zSign, 0x7FF, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig |= LIT64( 0x2000000000000000 ); - } - shift64RightJamming( aSig, - expDiff, &aSig ); - zExp = bExp; - } - else { - if ( aExp == 0x7FF ) { - if ( aSig | bSig ) return propagateFloat64NaN( a, b ); - return a; - } - if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); - zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; - zExp = aExp; - goto roundAndPack; - } - aSig |= LIT64( 0x2000000000000000 ); - zSig = ( aSig + bSig )<<1; - --zExp; - if ( (sbits64) zSig < 0 ) { - zSig = aSig + bSig; - ++zExp; - } - roundAndPack: - return roundAndPackFloat64( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the absolute values of the double- -precision floating-point values `a' and `b'. If `zSign' is true, the -difference is negated before being returned. `zSign' is ignored if the -result is a NaN. The subtraction is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static float64 subFloat64Sigs( float64 a, float64 b, flag zSign ) -{ - int16 aExp, bExp, zExp; - bits64 aSig, bSig, zSig; - int16 expDiff; - - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - bSig = extractFloat64Frac( b ); - bExp = extractFloat64Exp( b ); - expDiff = aExp - bExp; - aSig <<= 10; - bSig <<= 10; - if ( 0 < expDiff ) goto aExpBigger; - if ( expDiff < 0 ) goto bExpBigger; - if ( aExp == 0x7FF ) { - if ( aSig | bSig ) return propagateFloat64NaN( a, b ); - float_raise( float_flag_invalid ); - return float64_default_nan; - } - if ( aExp == 0 ) { - aExp = 1; - bExp = 1; - } - if ( bSig < aSig ) goto aBigger; - if ( aSig < bSig ) goto bBigger; - return packFloat64( float_rounding_mode == float_round_down, 0, 0 ); - bExpBigger: - if ( bExp == 0x7FF ) { - if ( bSig ) return propagateFloat64NaN( a, b ); - return packFloat64( zSign ^ 1, 0x7FF, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig |= LIT64( 0x4000000000000000 ); - } - shift64RightJamming( aSig, - expDiff, &aSig ); - bSig |= LIT64( 0x4000000000000000 ); - bBigger: - zSig = bSig - aSig; - zExp = bExp; - zSign ^= 1; - goto normalizeRoundAndPack; - aExpBigger: - if ( aExp == 0x7FF ) { - if ( aSig ) return propagateFloat64NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig |= LIT64( 0x4000000000000000 ); - } - shift64RightJamming( bSig, expDiff, &bSig ); - aSig |= LIT64( 0x4000000000000000 ); - aBigger: - zSig = aSig - bSig; - zExp = aExp; - normalizeRoundAndPack: - --zExp; - return normalizeRoundAndPackFloat64( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the double-precision floating-point values `a' -and `b'. The operation is performed according to the IEC/IEEE Standard for -Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float64 float64_add( float64 a, float64 b ) -{ - flag aSign, bSign; - - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - if ( aSign == bSign ) { - return addFloat64Sigs( a, b, aSign ); - } - else { - return subFloat64Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the double-precision floating-point values -`a' and `b'. The operation is performed according to the IEC/IEEE Standard -for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float64 float64_sub( float64 a, float64 b ) -{ - flag aSign, bSign; - - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - if ( aSign == bSign ) { - return subFloat64Sigs( a, b, aSign ); - } - else { - return addFloat64Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of multiplying the double-precision floating-point values -`a' and `b'. The operation is performed according to the IEC/IEEE Standard -for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float64 float64_mul( float64 a, float64 b ) -{ - flag aSign, bSign, zSign; - int16 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; - - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - aSign = extractFloat64Sign( a ); - bSig = extractFloat64Frac( b ); - bExp = extractFloat64Exp( b ); - bSign = extractFloat64Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FF ) { - if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { - return propagateFloat64NaN( a, b ); - } - if ( ( bExp | bSig ) == 0 ) { - float_raise( float_flag_invalid ); - return float64_default_nan; - } - return packFloat64( zSign, 0x7FF, 0 ); - } - if ( bExp == 0x7FF ) { - if ( bSig ) return propagateFloat64NaN( a, b ); - if ( ( aExp | aSig ) == 0 ) { - float_raise( float_flag_invalid ); - return float64_default_nan; - } - return packFloat64( zSign, 0x7FF, 0 ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); - normalizeFloat64Subnormal( aSig, &aExp, &aSig ); - } - if ( bExp == 0 ) { - if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); - normalizeFloat64Subnormal( bSig, &bExp, &bSig ); - } - zExp = aExp + bExp - 0x3FF; - aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; - bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; - mul64To128( aSig, bSig, &zSig0, &zSig1 ); - zSig0 |= ( zSig1 != 0 ); - if ( 0 <= (sbits64) ( zSig0<<1 ) ) { - zSig0 <<= 1; - --zExp; - } - return roundAndPackFloat64( zSign, zExp, zSig0 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of dividing the double-precision floating-point value `a' -by the corresponding value `b'. The operation is performed according to -the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float64 float64_div( float64 a, float64 b ) -{ - flag aSign, bSign, zSign; - int16 aExp, bExp, zExp; - bits64 aSig, bSig, zSig; - bits64 rem0, rem1; - bits64 term0, term1; - - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - aSign = extractFloat64Sign( a ); - bSig = extractFloat64Frac( b ); - bExp = extractFloat64Exp( b ); - bSign = extractFloat64Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FF ) { - if ( aSig ) return propagateFloat64NaN( a, b ); - if ( bExp == 0x7FF ) { - if ( bSig ) return propagateFloat64NaN( a, b ); - float_raise( float_flag_invalid ); - return float64_default_nan; - } - return packFloat64( zSign, 0x7FF, 0 ); - } - if ( bExp == 0x7FF ) { - if ( bSig ) return propagateFloat64NaN( a, b ); - return packFloat64( zSign, 0, 0 ); - } - if ( bExp == 0 ) { - if ( bSig == 0 ) { - if ( ( aExp | aSig ) == 0 ) { - float_raise( float_flag_invalid ); - return float64_default_nan; - } - float_raise( float_flag_divbyzero ); - return packFloat64( zSign, 0x7FF, 0 ); - } - normalizeFloat64Subnormal( bSig, &bExp, &bSig ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); - normalizeFloat64Subnormal( aSig, &aExp, &aSig ); - } - zExp = aExp - bExp + 0x3FD; - aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; - bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; - if ( bSig <= ( aSig + aSig ) ) { - aSig >>= 1; - ++zExp; - } - zSig = estimateDiv128To64( aSig, 0, bSig ); - if ( ( zSig & 0x1FF ) <= 2 ) { - mul64To128( bSig, zSig, &term0, &term1 ); - sub128( aSig, 0, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { - --zSig; - add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); - } - zSig |= ( rem1 != 0 ); - } - return roundAndPackFloat64( zSign, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the remainder of the double-precision floating-point value `a' -with respect to the corresponding value `b'. The operation is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float64 float64_rem( float64 a, float64 b ) -{ - flag aSign, bSign, zSign; - int16 aExp, bExp, expDiff; - bits64 aSig, bSig; - bits64 q, alternateASig; - sbits64 sigMean; - - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - aSign = extractFloat64Sign( a ); - bSig = extractFloat64Frac( b ); - bExp = extractFloat64Exp( b ); - bSign = extractFloat64Sign( b ); - if ( aExp == 0x7FF ) { - if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { - return propagateFloat64NaN( a, b ); - } - float_raise( float_flag_invalid ); - return float64_default_nan; - } - if ( bExp == 0x7FF ) { - if ( bSig ) return propagateFloat64NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - if ( bSig == 0 ) { - float_raise( float_flag_invalid ); - return float64_default_nan; - } - normalizeFloat64Subnormal( bSig, &bExp, &bSig ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return a; - normalizeFloat64Subnormal( aSig, &aExp, &aSig ); - } - expDiff = aExp - bExp; - aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; - bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; - if ( expDiff < 0 ) { - if ( expDiff < -1 ) return a; - aSig >>= 1; - } - q = ( bSig <= aSig ); - if ( q ) aSig -= bSig; - expDiff -= 64; - while ( 0 < expDiff ) { - q = estimateDiv128To64( aSig, 0, bSig ); - q = ( 2 < q ) ? q - 2 : 0; - aSig = - ( ( bSig>>2 ) * q ); - expDiff -= 62; - } - expDiff += 64; - if ( 0 < expDiff ) { - q = estimateDiv128To64( aSig, 0, bSig ); - q = ( 2 < q ) ? q - 2 : 0; - q >>= 64 - expDiff; - bSig >>= 2; - aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; - } - else { - aSig >>= 2; - bSig >>= 2; - } - do { - alternateASig = aSig; - ++q; - aSig -= bSig; - } while ( 0 <= (sbits64) aSig ); - sigMean = aSig + alternateASig; - if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { - aSig = alternateASig; - } - zSign = ( (sbits64) aSig < 0 ); - if ( zSign ) aSig = - aSig; - return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the square root of the double-precision floating-point value `a'. -The operation is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -float64 float64_sqrt( float64 a ) -{ - flag aSign; - int16 aExp, zExp; - bits64 aSig, zSig; - bits64 rem0, rem1, term0, term1; //, shiftedRem; - //float64 z; - - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - aSign = extractFloat64Sign( a ); - if ( aExp == 0x7FF ) { - if ( aSig ) return propagateFloat64NaN( a, a ); - if ( ! aSign ) return a; - float_raise( float_flag_invalid ); - return float64_default_nan; - } - if ( aSign ) { - if ( ( aExp | aSig ) == 0 ) return a; - float_raise( float_flag_invalid ); - return float64_default_nan; - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return 0; - normalizeFloat64Subnormal( aSig, &aExp, &aSig ); - } - zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; - aSig |= LIT64( 0x0010000000000000 ); - zSig = estimateSqrt32( aExp, aSig>>21 ); - zSig <<= 31; - aSig <<= 9 - ( aExp & 1 ); - zSig = estimateDiv128To64( aSig, 0, zSig ) + zSig + 2; - if ( ( zSig & 0x3FF ) <= 5 ) { - if ( zSig < 2 ) { - zSig = LIT64( 0xFFFFFFFFFFFFFFFF ); - } - else { - aSig <<= 2; - mul64To128( zSig, zSig, &term0, &term1 ); - sub128( aSig, 0, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { - --zSig; - shortShift128Left( 0, zSig, 1, &term0, &term1 ); - term1 |= 1; - add128( rem0, rem1, term0, term1, &rem0, &rem1 ); - } - zSig |= ( ( rem0 | rem1 ) != 0 ); - } - } - shift64RightJamming( zSig, 1, &zSig ); - return roundAndPackFloat64( 0, zExp, zSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the double-precision floating-point value `a' is equal to the -corresponding value `b', and 0 otherwise. The comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float64_eq( float64 a, float64 b ) -{ - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the double-precision floating-point value `a' is less than or -equal to the corresponding value `b', and 0 otherwise. The comparison is -performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float64_le( float64 a, float64 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the double-precision floating-point value `a' is less than -the corresponding value `b', and 0 otherwise. The comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float64_lt( float64 a, float64 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the double-precision floating-point value `a' is equal to the -corresponding value `b', and 0 otherwise. The invalid exception is raised -if either operand is a NaN. Otherwise, the comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float64_eq_signaling( float64 a, float64 b ) -{ - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the double-precision floating-point value `a' is less than or -equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not -cause an exception. Otherwise, the comparison is performed according to the -IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float64_le_quiet( float64 a, float64 b ) -{ - flag aSign, bSign; - //int16 aExp, bExp; - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the double-precision floating-point value `a' is less than -the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an -exception. Otherwise, the comparison is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag float64_lt_quiet( float64 a, float64 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) - || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) - ) { - if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloat64Sign( a ); - bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); - -} - -#ifdef FLOATX80 - -/* -------------------------------------------------------------------------------- -Returns the result of converting the extended double-precision floating- -point value `a' to the 32-bit two's complement integer format. The -conversion is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic---which means in particular that the conversion -is rounded according to the current rounding mode. If `a' is a NaN, the -largest positive integer is returned. Otherwise, if the conversion -overflows, the largest integer with the same sign as `a' is returned. -------------------------------------------------------------------------------- -*/ -int32 floatx80_to_int32( floatx80 a ) -{ - flag aSign; - int32 aExp, shiftCount; - bits64 aSig; - - aSig = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); - aSign = extractFloatx80Sign( a ); - if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; - shiftCount = 0x4037 - aExp; - if ( shiftCount <= 0 ) shiftCount = 1; - shift64RightJamming( aSig, shiftCount, &aSig ); - return roundAndPackInt32( aSign, aSig ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of converting the extended double-precision floating- -point value `a' to the 32-bit two's complement integer format. The -conversion is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic, except that the conversion is always rounded -toward zero. If `a' is a NaN, the largest positive integer is returned. -Otherwise, if the conversion overflows, the largest integer with the same -sign as `a' is returned. -------------------------------------------------------------------------------- -*/ -int32 floatx80_to_int32_round_to_zero( floatx80 a ) -{ - flag aSign; - int32 aExp, shiftCount; - bits64 aSig, savedASig; - int32 z; - - aSig = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); - aSign = extractFloatx80Sign( a ); - shiftCount = 0x403E - aExp; - if ( shiftCount < 32 ) { - if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; - goto invalid; - } - else if ( 63 < shiftCount ) { - if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; - return 0; - } - savedASig = aSig; - aSig >>= shiftCount; - z = aSig; - if ( aSign ) z = - z; - if ( ( z < 0 ) ^ aSign ) { - invalid: - float_exception_flags |= float_flag_invalid; - return aSign ? 0x80000000 : 0x7FFFFFFF; - } - if ( ( aSig<>1; - if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; - } - else if ( roundingMode != float_round_to_zero ) { - if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { - z.low += roundBitsMask; - } - } - z.low &= ~ roundBitsMask; - if ( z.low == 0 ) { - ++z.high; - z.low = LIT64( 0x8000000000000000 ); - } - if ( z.low != a.low ) float_exception_flags |= float_flag_inexact; - return z; - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the absolute values of the extended double- -precision floating-point values `a' and `b'. If `zSign' is true, the sum is -negated before being returned. `zSign' is ignored if the result is a NaN. -The addition is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) -{ - int32 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; - int32 expDiff; - - aSig = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); - bSig = extractFloatx80Frac( b ); - bExp = extractFloatx80Exp( b ); - expDiff = aExp - bExp; - if ( 0 < expDiff ) { - if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); - return a; - } - if ( bExp == 0 ) --expDiff; - shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); - zExp = aExp; - } - else if ( expDiff < 0 ) { - if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); - return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); - } - if ( aExp == 0 ) ++expDiff; - shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); - zExp = bExp; - } - else { - if ( aExp == 0x7FFF ) { - if ( (bits64) ( ( aSig | bSig )<<1 ) ) { - return propagateFloatx80NaN( a, b ); - } - return a; - } - zSig1 = 0; - zSig0 = aSig + bSig; - if ( aExp == 0 ) { - normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); - goto roundAndPack; - } - zExp = aExp; - goto shiftRight1; - } - - zSig0 = aSig + bSig; - - if ( (sbits64) zSig0 < 0 ) goto roundAndPack; - shiftRight1: - shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); - zSig0 |= LIT64( 0x8000000000000000 ); - ++zExp; - roundAndPack: - return - roundAndPackFloatx80( - floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the absolute values of the extended -double-precision floating-point values `a' and `b'. If `zSign' is true, -the difference is negated before being returned. `zSign' is ignored if the -result is a NaN. The subtraction is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) -{ - int32 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; - int32 expDiff; - floatx80 z; - - aSig = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); - bSig = extractFloatx80Frac( b ); - bExp = extractFloatx80Exp( b ); - expDiff = aExp - bExp; - if ( 0 < expDiff ) goto aExpBigger; - if ( expDiff < 0 ) goto bExpBigger; - if ( aExp == 0x7FFF ) { - if ( (bits64) ( ( aSig | bSig )<<1 ) ) { - return propagateFloatx80NaN( a, b ); - } - float_raise( float_flag_invalid ); - z.low = floatx80_default_nan_low; - z.high = floatx80_default_nan_high; - return z; - } - if ( aExp == 0 ) { - aExp = 1; - bExp = 1; - } - zSig1 = 0; - if ( bSig < aSig ) goto aBigger; - if ( aSig < bSig ) goto bBigger; - return packFloatx80( float_rounding_mode == float_round_down, 0, 0 ); - bExpBigger: - if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); - return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); - } - if ( aExp == 0 ) ++expDiff; - shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); - bBigger: - sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); - zExp = bExp; - zSign ^= 1; - goto normalizeRoundAndPack; - aExpBigger: - if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); - return a; - } - if ( bExp == 0 ) --expDiff; - shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); - aBigger: - sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); - zExp = aExp; - normalizeRoundAndPack: - return - normalizeRoundAndPackFloatx80( - floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of adding the extended double-precision floating-point -values `a' and `b'. The operation is performed according to the IEC/IEEE -Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -floatx80 floatx80_add( floatx80 a, floatx80 b ) -{ - flag aSign, bSign; - - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign == bSign ) { - return addFloatx80Sigs( a, b, aSign ); - } - else { - return subFloatx80Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of subtracting the extended double-precision floating- -point values `a' and `b'. The operation is performed according to the -IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -floatx80 floatx80_sub( floatx80 a, floatx80 b ) -{ - flag aSign, bSign; - - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign == bSign ) { - return subFloatx80Sigs( a, b, aSign ); - } - else { - return addFloatx80Sigs( a, b, aSign ); - } - -} - -/* -------------------------------------------------------------------------------- -Returns the result of multiplying the extended double-precision floating- -point values `a' and `b'. The operation is performed according to the -IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -floatx80 floatx80_mul( floatx80 a, floatx80 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; - floatx80 z; - - aSig = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); - aSign = extractFloatx80Sign( a ); - bSig = extractFloatx80Frac( b ); - bExp = extractFloatx80Exp( b ); - bSign = extractFloatx80Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) - || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { - return propagateFloatx80NaN( a, b ); - } - if ( ( bExp | bSig ) == 0 ) goto invalid; - return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); - } - if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); - if ( ( aExp | aSig ) == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = floatx80_default_nan_low; - z.high = floatx80_default_nan_high; - return z; - } - return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); - normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); - } - if ( bExp == 0 ) { - if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); - normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); - } - zExp = aExp + bExp - 0x3FFE; - mul64To128( aSig, bSig, &zSig0, &zSig1 ); - if ( 0 < (sbits64) zSig0 ) { - shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); - --zExp; - } - return - roundAndPackFloatx80( - floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the result of dividing the extended double-precision floating-point -value `a' by the corresponding value `b'. The operation is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -floatx80 floatx80_div( floatx80 a, floatx80 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; - bits64 rem0, rem1, rem2, term0, term1, term2; - floatx80 z; - - aSig = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); - aSign = extractFloatx80Sign( a ); - bSig = extractFloatx80Frac( b ); - bExp = extractFloatx80Exp( b ); - bSign = extractFloatx80Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); - if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); - goto invalid; - } - return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); - } - if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); - return packFloatx80( zSign, 0, 0 ); - } - if ( bExp == 0 ) { - if ( bSig == 0 ) { - if ( ( aExp | aSig ) == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = floatx80_default_nan_low; - z.high = floatx80_default_nan_high; - return z; - } - float_raise( float_flag_divbyzero ); - return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); - } - normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); - normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); - } - zExp = aExp - bExp + 0x3FFE; - rem1 = 0; - if ( bSig <= aSig ) { - shift128Right( aSig, 0, 1, &aSig, &rem1 ); - ++zExp; - } - zSig0 = estimateDiv128To64( aSig, rem1, bSig ); - mul64To128( bSig, zSig0, &term0, &term1 ); - sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { - --zSig0; - add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); - } - zSig1 = estimateDiv128To64( rem1, 0, bSig ); - if ( (bits64) ( zSig1<<1 ) <= 8 ) { - mul64To128( bSig, zSig1, &term1, &term2 ); - sub128( rem1, 0, term1, term2, &rem1, &rem2 ); - while ( (sbits64) rem1 < 0 ) { - --zSig1; - add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); - } - zSig1 |= ( ( rem1 | rem2 ) != 0 ); - } - return - roundAndPackFloatx80( - floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the remainder of the extended double-precision floating-point value -`a' with respect to the corresponding value `b'. The operation is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -floatx80 floatx80_rem( floatx80 a, floatx80 b ) -{ - flag aSign, bSign, zSign; - int32 aExp, bExp, expDiff; - bits64 aSig0, aSig1, bSig; - bits64 q, term0, term1, alternateASig0, alternateASig1; - floatx80 z; - - aSig0 = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); - aSign = extractFloatx80Sign( a ); - bSig = extractFloatx80Frac( b ); - bExp = extractFloatx80Exp( b ); - bSign = extractFloatx80Sign( b ); - if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig0<<1 ) - || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { - return propagateFloatx80NaN( a, b ); - } - goto invalid; - } - if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); - return a; - } - if ( bExp == 0 ) { - if ( bSig == 0 ) { - invalid: - float_raise( float_flag_invalid ); - z.low = floatx80_default_nan_low; - z.high = floatx80_default_nan_high; - return z; - } - normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); - } - if ( aExp == 0 ) { - if ( (bits64) ( aSig0<<1 ) == 0 ) return a; - normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); - } - bSig |= LIT64( 0x8000000000000000 ); - zSign = aSign; - expDiff = aExp - bExp; - aSig1 = 0; - if ( expDiff < 0 ) { - if ( expDiff < -1 ) return a; - shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); - expDiff = 0; - } - q = ( bSig <= aSig0 ); - if ( q ) aSig0 -= bSig; - expDiff -= 64; - while ( 0 < expDiff ) { - q = estimateDiv128To64( aSig0, aSig1, bSig ); - q = ( 2 < q ) ? q - 2 : 0; - mul64To128( bSig, q, &term0, &term1 ); - sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); - shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); - expDiff -= 62; - } - expDiff += 64; - if ( 0 < expDiff ) { - q = estimateDiv128To64( aSig0, aSig1, bSig ); - q = ( 2 < q ) ? q - 2 : 0; - q >>= 64 - expDiff; - mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); - sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); - shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); - while ( le128( term0, term1, aSig0, aSig1 ) ) { - ++q; - sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); - } - } - else { - term1 = 0; - term0 = bSig; - } - sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); - if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) - || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) - && ( q & 1 ) ) - ) { - aSig0 = alternateASig0; - aSig1 = alternateASig1; - zSign = ! zSign; - } - return - normalizeRoundAndPackFloatx80( - 80, zSign, bExp + expDiff, aSig0, aSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns the square root of the extended double-precision floating-point -value `a'. The operation is performed according to the IEC/IEEE Standard -for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -floatx80 floatx80_sqrt( floatx80 a ) -{ - flag aSign; - int32 aExp, zExp; - bits64 aSig0, aSig1, zSig0, zSig1; - bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; - bits64 shiftedRem0, shiftedRem1; - floatx80 z; - - aSig0 = extractFloatx80Frac( a ); - aExp = extractFloatx80Exp( a ); - aSign = extractFloatx80Sign( a ); - if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a ); - if ( ! aSign ) return a; - goto invalid; - } - if ( aSign ) { - if ( ( aExp | aSig0 ) == 0 ) return a; - invalid: - float_raise( float_flag_invalid ); - z.low = floatx80_default_nan_low; - z.high = floatx80_default_nan_high; - return z; - } - if ( aExp == 0 ) { - if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); - normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); - } - zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; - zSig0 = estimateSqrt32( aExp, aSig0>>32 ); - zSig0 <<= 31; - aSig1 = 0; - shift128Right( aSig0, 0, ( aExp & 1 ) + 2, &aSig0, &aSig1 ); - zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; - if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); - shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); - mul64To128( zSig0, zSig0, &term0, &term1 ); - sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { - --zSig0; - shortShift128Left( 0, zSig0, 1, &term0, &term1 ); - term1 |= 1; - add128( rem0, rem1, term0, term1, &rem0, &rem1 ); - } - shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); - zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); - if ( (bits64) ( zSig1<<1 ) <= 10 ) { - if ( zSig1 == 0 ) zSig1 = 1; - mul64To128( zSig0, zSig1, &term1, &term2 ); - shortShift128Left( term1, term2, 1, &term1, &term2 ); - sub128( rem1, 0, term1, term2, &rem1, &rem2 ); - mul64To128( zSig1, zSig1, &term2, &term3 ); - sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); - while ( (sbits64) rem1 < 0 ) { - --zSig1; - shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); - term3 |= 1; - add192( - rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); - } - zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); - } - return - roundAndPackFloatx80( - floatx80_rounding_precision, 0, zExp, zSig0, zSig1 ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the extended double-precision floating-point value `a' is -equal to the corresponding value `b', and 0 otherwise. The comparison is -performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic. -------------------------------------------------------------------------------- -*/ -flag floatx80_eq( floatx80 a, floatx80 b ) -{ - - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) - ) { - if ( floatx80_is_signaling_nan( a ) - || floatx80_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the extended double-precision floating-point value `a' is -less than or equal to the corresponding value `b', and 0 otherwise. The -comparison is performed according to the IEC/IEEE Standard for Binary -Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag floatx80_le( floatx80 a, floatx80 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the extended double-precision floating-point value `a' is -less than the corresponding value `b', and 0 otherwise. The comparison -is performed according to the IEC/IEEE Standard for Binary Floating-point -Arithmetic. -------------------------------------------------------------------------------- -*/ -flag floatx80_lt( floatx80 a, floatx80 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - != 0 ); - } - return - aSign ? lt128( b.high, b.low, a.high, a.low ) - : lt128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the extended double-precision floating-point value `a' is equal -to the corresponding value `b', and 0 otherwise. The invalid exception is -raised if either operand is a NaN. Otherwise, the comparison is performed -according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag floatx80_eq_signaling( floatx80 a, floatx80 b ) -{ - - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) - ) { - float_raise( float_flag_invalid ); - return 0; - } - return - ( a.low == b.low ) - && ( ( a.high == b.high ) - || ( ( a.low == 0 ) - && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) - ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the extended double-precision floating-point value `a' is less -than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs -do not cause an exception. Otherwise, the comparison is performed according -to the IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag floatx80_le_quiet( floatx80 a, floatx80 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) - ) { - if ( floatx80_is_signaling_nan( a ) - || floatx80_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign != bSign ) { - return - aSign - || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - == 0 ); - } - return - aSign ? le128( b.high, b.low, a.high, a.low ) - : le128( a.high, a.low, b.high, b.low ); - -} - -/* -------------------------------------------------------------------------------- -Returns 1 if the extended double-precision floating-point value `a' is less -than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause -an exception. Otherwise, the comparison is performed according to the -IEC/IEEE Standard for Binary Floating-point Arithmetic. -------------------------------------------------------------------------------- -*/ -flag floatx80_lt_quiet( floatx80 a, floatx80 b ) -{ - flag aSign, bSign; - - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) - ) { - if ( floatx80_is_signaling_nan( a ) - || floatx80_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid ); - } - return 0; - } - aSign = extractFloatx80Sign( a ); - bSign = extractFloatx80Sign( b ); - if ( aSign != bSign ) { - return - aSign - && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) - != 0 ); - } - return - aSign ? lt128( b.high, b.low, a.high, a.low ) - : lt128( a.high, a.low, b.high, b.low ); - -} - -#endif - diff --git a/target-arm/nwfpe/softfloat.h b/target-arm/nwfpe/softfloat.h deleted file mode 100644 index 22c2193a4..000000000 --- a/target-arm/nwfpe/softfloat.h +++ /dev/null @@ -1,232 +0,0 @@ - -/* -=============================================================================== - -This C header file is part of the SoftFloat IEC/IEEE Floating-point -Arithmetic Package, Release 2. - -Written by John R. Hauser. This work was made possible in part by the -International Computer Science Institute, located at Suite 600, 1947 Center -Street, Berkeley, California 94704. Funding was partially provided by the -National Science Foundation under grant MIP-9311980. The original version -of this code was written as part of a project to build a fixed-point vector -processor in collaboration with the University of California at Berkeley, -overseen by Profs. Nelson Morgan and John Wawrzynek. More information -is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ -arithmetic/softfloat.html'. - -THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort -has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT -TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO -PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY -AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - -Derivative works are acceptable, even for commercial purposes, so long as -(1) they include prominent notice that the work is derivative, and (2) they -include prominent notice akin to these three paragraphs for those parts of -this code that are retained. - -=============================================================================== -*/ - -#ifndef __SOFTFLOAT_H__ -#define __SOFTFLOAT_H__ - -/* -------------------------------------------------------------------------------- -The macro `FLOATX80' must be defined to enable the extended double-precision -floating-point format `floatx80'. If this macro is not defined, the -`floatx80' type will not be defined, and none of the functions that either -input or output the `floatx80' type will be defined. -------------------------------------------------------------------------------- -*/ -#define FLOATX80 - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE floating-point types. -------------------------------------------------------------------------------- -*/ -typedef unsigned long int float32; -typedef unsigned long long float64; -typedef struct { - unsigned short high; - unsigned long long low; -} floatx80; - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE floating-point underflow tininess-detection mode. -------------------------------------------------------------------------------- -*/ -extern signed char float_detect_tininess; -enum { - float_tininess_after_rounding = 0, - float_tininess_before_rounding = 1 -}; - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE floating-point rounding mode. -------------------------------------------------------------------------------- -*/ -extern signed char float_rounding_mode; -enum { - float_round_nearest_even = 0, - float_round_to_zero = 1, - float_round_down = 2, - float_round_up = 3 -}; - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE floating-point exception flags. -------------------------------------------------------------------------------- -extern signed char float_exception_flags; -enum { - float_flag_inexact = 1, - float_flag_underflow = 2, - float_flag_overflow = 4, - float_flag_divbyzero = 8, - float_flag_invalid = 16 -}; - -ScottB: November 4, 1998 -Changed the enumeration to match the bit order in the FPA11. -*/ - -extern signed char float_exception_flags; -enum { - float_flag_invalid = 1, - float_flag_divbyzero = 2, - float_flag_overflow = 4, - float_flag_underflow = 8, - float_flag_inexact = 16 -}; - -/* -------------------------------------------------------------------------------- -Routine to raise any or all of the software IEC/IEEE floating-point -exception flags. -------------------------------------------------------------------------------- -*/ -void float_raise( signed char ); - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE integer-to-floating-point conversion routines. -------------------------------------------------------------------------------- -*/ -float32 int32_to_float32( signed int ); -float64 int32_to_float64( signed int ); -#ifdef FLOATX80 -floatx80 int32_to_floatx80( signed int ); -#endif - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE single-precision conversion routines. -------------------------------------------------------------------------------- -*/ -signed int float32_to_int32( float32 ); -signed int float32_to_int32_round_to_zero( float32 ); -float64 float32_to_float64( float32 ); -#ifdef FLOATX80 -floatx80 float32_to_floatx80( float32 ); -#endif - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE single-precision operations. -------------------------------------------------------------------------------- -*/ -float32 float32_round_to_int( float32 ); -float32 float32_add( float32, float32 ); -float32 float32_sub( float32, float32 ); -float32 float32_mul( float32, float32 ); -float32 float32_div( float32, float32 ); -float32 float32_rem( float32, float32 ); -float32 float32_sqrt( float32 ); -char float32_eq( float32, float32 ); -char float32_le( float32, float32 ); -char float32_lt( float32, float32 ); -char float32_eq_signaling( float32, float32 ); -char float32_le_quiet( float32, float32 ); -char float32_lt_quiet( float32, float32 ); -char float32_is_signaling_nan( float32 ); - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE double-precision conversion routines. -------------------------------------------------------------------------------- -*/ -signed int float64_to_int32( float64 ); -signed int float64_to_int32_round_to_zero( float64 ); -float32 float64_to_float32( float64 ); -#ifdef FLOATX80 -floatx80 float64_to_floatx80( float64 ); -#endif - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE double-precision operations. -------------------------------------------------------------------------------- -*/ -float64 float64_round_to_int( float64 ); -float64 float64_add( float64, float64 ); -float64 float64_sub( float64, float64 ); -float64 float64_mul( float64, float64 ); -float64 float64_div( float64, float64 ); -float64 float64_rem( float64, float64 ); -float64 float64_sqrt( float64 ); -char float64_eq( float64, float64 ); -char float64_le( float64, float64 ); -char float64_lt( float64, float64 ); -char float64_eq_signaling( float64, float64 ); -char float64_le_quiet( float64, float64 ); -char float64_lt_quiet( float64, float64 ); -char float64_is_signaling_nan( float64 ); - -#ifdef FLOATX80 - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE extended double-precision conversion routines. -------------------------------------------------------------------------------- -*/ -signed int floatx80_to_int32( floatx80 ); -signed int floatx80_to_int32_round_to_zero( floatx80 ); -float32 floatx80_to_float32( floatx80 ); -float64 floatx80_to_float64( floatx80 ); - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE extended double-precision rounding precision. Valid -values are 32, 64, and 80. -------------------------------------------------------------------------------- -*/ -extern signed char floatx80_rounding_precision; - -/* -------------------------------------------------------------------------------- -Software IEC/IEEE extended double-precision operations. -------------------------------------------------------------------------------- -*/ -floatx80 floatx80_round_to_int( floatx80 ); -floatx80 floatx80_add( floatx80, floatx80 ); -floatx80 floatx80_sub( floatx80, floatx80 ); -floatx80 floatx80_mul( floatx80, floatx80 ); -floatx80 floatx80_div( floatx80, floatx80 ); -floatx80 floatx80_rem( floatx80, floatx80 ); -floatx80 floatx80_sqrt( floatx80 ); -char floatx80_eq( floatx80, floatx80 ); -char floatx80_le( floatx80, floatx80 ); -char floatx80_lt( floatx80, floatx80 ); -char floatx80_eq_signaling( floatx80, floatx80 ); -char floatx80_le_quiet( floatx80, floatx80 ); -char floatx80_lt_quiet( floatx80, floatx80 ); -char floatx80_is_signaling_nan( floatx80 ); - -#endif - -#endif -- cgit v1.2.3 From 4c2e770f377a2c38bb26c24e333b747511ddd040 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 16:56:51 +0000 Subject: fpu init fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1334 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 43fa2f27f..126a9193e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1164,7 +1164,7 @@ int main(int argc, char **argv) { int i; for (i = 0; i < 32; i++) { - if (i != 12 && i != 6) + if (i != 12 && i != 6 && i != 13) env->msr[i] = (regs->msr >> i) & 1; } env->nip = regs->nip; -- cgit v1.2.3 From 4ecc31906d7535c4ad88fcc63968bef412dd67ba Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 17:01:22 +0000 Subject: fpu fixes (Jocelyn Mayer) - soft float support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1335 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 12 ++-- target-ppc/exec.h | 10 +--- target-ppc/helper.c | 3 +- target-ppc/op.c | 74 ++----------------------- target-ppc/op_helper.c | 145 +++++++++++++++++++++++++++++++++---------------- target-ppc/translate.c | 95 +++++++++++++++++++++++--------- 6 files changed, 181 insertions(+), 158 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1776a3577..70ee83507 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -27,6 +27,8 @@ #include "config.h" #include +#include "softfloat.h" + /* Instruction types */ enum { PPC_NONE = 0x0000, @@ -94,7 +96,7 @@ typedef struct CPUPPCState { /* general purpose registers */ uint32_t gpr[32]; /* floating point registers */ - double fpr[32]; + float64 fpr[32]; /* segment registers */ uint32_t sdr1; uint32_t sr[16]; @@ -119,9 +121,11 @@ typedef struct CPUPPCState { uint32_t spr[1024]; /* qemu dedicated */ /* temporary float registers */ - double ft0; - double ft1; - double ft2; + float64 ft0; + float64 ft1; + float64 ft2; + float_status fp_status; + int interrupt_request; jmp_buf jmp_env; int exception_index; diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 503cf26c6..ad21c5669 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -32,9 +32,6 @@ register uint32_t T2 asm(AREG3); #define FT0 (env->ft0) #define FT1 (env->ft1) #define FT2 (env->ft2) -#define FTS0 ((float)env->ft0) -#define FTS1 ((float)env->ft1) -#define FTS2 ((float)env->ft2) #if defined (DEBUG_OP) #define RETURN() __asm__ __volatile__("nop"); @@ -137,17 +134,12 @@ void do_fctiw (void); void do_fctiwz (void); void do_fnmadd (void); void do_fnmsub (void); -void do_fnmadds (void); -void do_fnmsubs (void); void do_fsqrt (void); -void do_fsqrts (void); void do_fres (void); -void do_fsqrte (void); +void do_frsqrte (void); void do_fsel (void); void do_fcmpu (void); void do_fcmpo (void); -void do_fabs (void); -void do_fnabs (void); void do_check_reservation (void); void do_icbi (void); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index a9424dfa7..b54b5d205 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -809,6 +809,7 @@ void do_interrupt (CPUState *env) msr |= 0x00010000; goto store_current; case EXCP_NO_FP: + msr &= ~0xFFFF0000; goto store_current; case EXCP_DECR: if (msr_ee == 0) { @@ -854,7 +855,6 @@ void do_interrupt (CPUState *env) return; case EXCP_RFI: /* Restore user-mode state */ - tb_flush(env); #if defined (DEBUG_EXCEPTIONS) if (msr_pr == 1) printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); @@ -887,7 +887,6 @@ void do_interrupt (CPUState *env) env->nip = excp << 8; env->exception_index = EXCP_NONE; /* Invalidate all TLB as we may have changed translation mode */ - tlb_flush(env, 1); /* ensure that no TB jump will be modified as the program flow was changed */ #ifdef __sparc__ diff --git a/target-ppc/op.c b/target-ppc/op.c index 5accc5506..6ae7a523b 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -32,10 +32,6 @@ #define FT1 (env->ft1) #define FT2 (env->ft2) -#define FTS0 ((float)env->ft0) -#define FTS1 ((float)env->ft1) -#define FTS2 ((float)env->ft2) - #define PPC_OP(name) void glue(op_, name)(void) #define REG 0 @@ -1204,13 +1200,6 @@ PPC_OP(fadd) RETURN(); } -/* fadds - fadds. */ -PPC_OP(fadds) -{ - FT0 = FTS0 + FTS1; - RETURN(); -} - /* fsub - fsub. */ PPC_OP(fsub) { @@ -1218,13 +1207,6 @@ PPC_OP(fsub) RETURN(); } -/* fsubs - fsubs. */ -PPC_OP(fsubs) -{ - FT0 = FTS0 - FTS1; - RETURN(); -} - /* fmul - fmul. */ PPC_OP(fmul) { @@ -1232,24 +1214,11 @@ PPC_OP(fmul) RETURN(); } -/* fmuls - fmuls. */ -PPC_OP(fmuls) -{ - FT0 = FTS0 * FTS1; - RETURN(); -} - /* fdiv - fdiv. */ +void do_fdiv (void); PPC_OP(fdiv) { - FT0 /= FT1; - RETURN(); -} - -/* fdivs - fdivs. */ -PPC_OP(fdivs) -{ - FT0 = FTS0 / FTS1; + do_fdiv(); RETURN(); } @@ -1260,13 +1229,6 @@ PPC_OP(fsqrt) RETURN(); } -/* fsqrts - fsqrts. */ -PPC_OP(fsqrts) -{ - do_fsqrts(); - RETURN(); -} - /* fres - fres. */ PPC_OP(fres) { @@ -1277,7 +1239,7 @@ PPC_OP(fres) /* frsqrte - frsqrte. */ PPC_OP(frsqrte) { - do_fsqrte(); + do_frsqrte(); RETURN(); } @@ -1296,13 +1258,6 @@ PPC_OP(fmadd) RETURN(); } -/* fmadds - fmadds. */ -PPC_OP(fmadds) -{ - FT0 = (FTS0 * FTS1) + FTS2; - RETURN(); -} - /* fmsub - fmsub. */ PPC_OP(fmsub) { @@ -1310,13 +1265,6 @@ PPC_OP(fmsub) RETURN(); } -/* fmsubs - fmsubs. */ -PPC_OP(fmsubs) -{ - FT0 = (FTS0 * FTS1) - FTS2; - RETURN(); -} - /* fnmadd - fnmadd. - fnmadds - fnmadds. */ PPC_OP(fnmadd) { @@ -1324,13 +1272,6 @@ PPC_OP(fnmadd) RETURN(); } -/* fnmadds - fnmadds. */ -PPC_OP(fnmadds) -{ - do_fnmadds(); - RETURN(); -} - /* fnmsub - fnmsub. */ PPC_OP(fnmsub) { @@ -1338,13 +1279,6 @@ PPC_OP(fnmsub) RETURN(); } -/* fnmsubs - fnmsubs. */ -PPC_OP(fnmsubs) -{ - do_fnmsubs(); - RETURN(); -} - /*** Floating-Point round & convert ***/ /* frsp - frsp. */ PPC_OP(frsp) @@ -1385,6 +1319,7 @@ PPC_OP(fcmpo) /*** Floating-point move ***/ /* fabs */ +void do_fabs (void); PPC_OP(fabs) { do_fabs(); @@ -1392,6 +1327,7 @@ PPC_OP(fabs) } /* fnabs */ +void do_fnabs (void); PPC_OP(fnabs) { do_fnabs(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 20aba8b6e..102249d41 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -213,7 +213,7 @@ void do_store_fpscr (uint32_t mask) uint32_t u[2]; } s; } u; - int i; + int i, rnd_type; u.d = FT0; if (mask & 0x80) @@ -227,21 +227,23 @@ void do_store_fpscr (uint32_t mask) switch (env->fpscr[0] & 0x3) { case 0: /* Best approximation (round to nearest) */ - fesetround(FE_TONEAREST); + rnd_type = float_round_nearest_even; break; case 1: /* Smaller magnitude (round toward zero) */ - fesetround(FE_TOWARDZERO); + rnd_type = float_round_to_zero; break; case 2: /* Round toward +infinite */ - fesetround(FE_UPWARD); + rnd_type = float_round_up; break; + default: case 3: /* Round toward -infinite */ - fesetround(FE_DOWNWARD); + rnd_type = float_round_down; break; } + set_float_rounding_mode(rnd_type, &env->fp_status); } void do_fctiw (void) @@ -249,16 +251,14 @@ void do_fctiw (void) union { double d; uint64_t i; - } *p = (void *)&FT1; + } p; - if (FT0 > (double)0x7FFFFFFF) - p->i = 0x7FFFFFFFULL << 32; - else if (FT0 < -(double)0x80000000) - p->i = 0x80000000ULL << 32; - else - p->i = 0; - p->i |= (uint32_t)FT0; - FT0 = p->d; + /* XXX: higher bits are not supposed to be significant. + * to make tests easier, return the same as a real PPC 750 (aka G3) + */ + p.i = float64_to_int32(FT0, &env->fp_status); + p.i |= 0xFFF80000ULL << 32; + FT0 = p.d; } void do_fctiwz (void) @@ -266,39 +266,36 @@ void do_fctiwz (void) union { double d; uint64_t i; - } *p = (void *)&FT1; - int cround = fegetround(); - - fesetround(FE_TOWARDZERO); - if (FT0 > (double)0x7FFFFFFF) - p->i = 0x7FFFFFFFULL << 32; - else if (FT0 < -(double)0x80000000) - p->i = 0x80000000ULL << 32; - else - p->i = 0; - p->i |= (uint32_t)FT0; - FT0 = p->d; - fesetround(cround); + } p; + + /* XXX: higher bits are not supposed to be significant. + * to make tests easier, return the same as a real PPC 750 (aka G3) + */ + p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); + p.i |= 0xFFF80000ULL << 32; + FT0 = p.d; } void do_fnmadd (void) { - FT0 = -((FT0 * FT1) + FT2); + FT0 = (FT0 * FT1) + FT2; + if (!isnan(FT0)) + FT0 = -FT0; } void do_fnmsub (void) { - FT0 = -((FT0 * FT1) - FT2); + FT0 = (FT0 * FT1) - FT2; + if (!isnan(FT0)) + FT0 = -FT0; } -void do_fnmadds (void) +void do_fdiv (void) { - FT0 = -((FTS0 * FTS1) + FTS2); -} - -void do_fnmsubs (void) -{ - FT0 = -((FTS0 * FTS1) - FTS2); + if (FT0 == -0.0 && FT1 == -0.0) + FT0 = 0.0 / 0.0; + else + FT0 /= FT1; } void do_fsqrt (void) @@ -306,27 +303,65 @@ void do_fsqrt (void) FT0 = sqrt(FT0); } -void do_fsqrts (void) -{ - FT0 = (float)sqrt((float)FT0); -} - void do_fres (void) { - FT0 = 1.0 / FT0; + union { + double d; + uint64_t i; + } p; + + if (isnormal(FT0)) { + FT0 = (float)(1.0 / FT0); + } else { + p.d = FT0; + if (p.i == 0x8000000000000000ULL) { + p.i = 0xFFF0000000000000ULL; + } else if (p.i == 0x0000000000000000ULL) { + p.i = 0x7FF0000000000000ULL; + } else if (isnan(FT0)) { + p.i = 0x7FF8000000000000ULL; + } else if (FT0 < 0.0) { + p.i = 0x8000000000000000ULL; + } else { + p.i = 0x0000000000000000ULL; + } + FT0 = p.d; + } } -void do_fsqrte (void) +void do_frsqrte (void) { - FT0 = 1.0 / sqrt(FT0); + union { + double d; + uint64_t i; + } p; + + if (isnormal(FT0) && FT0 > 0.0) { + FT0 = (float)(1.0 / sqrt(FT0)); + } else { + p.d = FT0; + if (p.i == 0x8000000000000000ULL) { + p.i = 0xFFF0000000000000ULL; + } else if (p.i == 0x0000000000000000ULL) { + p.i = 0x7FF0000000000000ULL; + } else if (isnan(FT0)) { + if (!(p.i & 0x0008000000000000ULL)) + p.i |= 0x000FFFFFFFFFFFFFULL; + } else if (FT0 < 0) { + p.i = 0x7FF8000000000000ULL; + } else { + p.i = 0x0000000000000000ULL; + } + FT0 = p.d; + } } void do_fsel (void) { if (FT0 >= 0) - FT0 = FT2; - else FT0 = FT1; + else + FT0 = FT2; } void do_fcmpu (void) @@ -371,12 +406,26 @@ void do_fcmpo (void) void do_fabs (void) { - FT0 = fabsl(FT0); + union { + double d; + uint64_t i; + } p; + + p.d = FT0; + p.i &= ~0x8000000000000000ULL; + FT0 = p.d; } void do_fnabs (void) { - FT0 = -fabsl(FT0); + union { + double d; + uint64_t i; + } p; + + p.d = FT0; + p.i |= 0x8000000000000000ULL; + FT0 = p.d; } /* Instruction cache invalidation helper */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index bb3bbbb54..f41bbb845 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -740,6 +740,7 @@ __GEN_LOGICAL2(sraw, 0x18, 0x18); GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); + if (SH(ctx->opcode) != 0) gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31)); if (Rc(ctx->opcode) != 0) gen_op_set_Rc0(); @@ -749,7 +750,7 @@ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) __GEN_LOGICAL2(srw, 0x18, 0x10); /*** Floating-Point arithmetic ***/ -#define _GEN_FLOAT_ACB(name, op1, op2) \ +#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ { \ if (!ctx->fpu_enabled) { \ @@ -760,17 +761,20 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rC(ctx->opcode)); \ gen_op_load_fpr_FT2(rB(ctx->opcode)); \ - gen_op_f##name(); \ + gen_op_f##op(); \ + if (isfloat) { \ + gen_op_frsp(); \ + } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ if (Rc(ctx->opcode)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_ACB(name, op2) \ -_GEN_FLOAT_ACB(name, 0x3F, op2); \ -_GEN_FLOAT_ACB(name##s, 0x3B, op2); +_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \ +_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1); -#define _GEN_FLOAT_AB(name, op1, op2, inval) \ +#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ if (!ctx->fpu_enabled) { \ @@ -780,16 +784,19 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rB(ctx->opcode)); \ - gen_op_f##name(); \ + gen_op_f##op(); \ + if (isfloat) { \ + gen_op_frsp(); \ + } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ if (Rc(ctx->opcode)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_AB(name, op2, inval) \ -_GEN_FLOAT_AB(name, 0x3F, op2, inval); \ -_GEN_FLOAT_AB(name##s, 0x3B, op2, inval); +_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \ +_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1); -#define _GEN_FLOAT_AC(name, op1, op2, inval) \ +#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ if (!ctx->fpu_enabled) { \ @@ -799,14 +806,17 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rC(ctx->opcode)); \ - gen_op_f##name(); \ + gen_op_f##op(); \ + if (isfloat) { \ + gen_op_frsp(); \ + } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ if (Rc(ctx->opcode)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_AC(name, op2, inval) \ -_GEN_FLOAT_AC(name, 0x3F, op2, inval); \ -_GEN_FLOAT_AC(name##s, 0x3B, op2, inval); +_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \ +_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1); #define GEN_FLOAT_B(name, op2, op3) \ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ @@ -823,8 +833,8 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ gen_op_set_Rc1(); \ } -#define GEN_FLOAT_BS(name, op2) \ -GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ +#define GEN_FLOAT_BS(name, op1, op2) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ { \ if (!ctx->fpu_enabled) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ @@ -840,24 +850,24 @@ GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ /* fadd - fadds */ GEN_FLOAT_AB(add, 0x15, 0x000007C0); -/* fdiv */ +/* fdiv - fdivs */ GEN_FLOAT_AB(div, 0x12, 0x000007C0); -/* fmul */ +/* fmul - fmuls */ GEN_FLOAT_AC(mul, 0x19, 0x0000F800); /* fres */ -GEN_FLOAT_BS(res, 0x18); +GEN_FLOAT_BS(res, 0x3B, 0x18); /* frsqrte */ -GEN_FLOAT_BS(rsqrte, 0x1A); +GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A); /* fsel */ -_GEN_FLOAT_ACB(sel, 0x3F, 0x17); -/* fsub */ +_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0); +/* fsub - fsubs */ GEN_FLOAT_AB(sub, 0x14, 0x000007C0); /* Optional: */ /* fsqrt */ -GEN_FLOAT_BS(sqrt, 0x16); +GEN_FLOAT_BS(sqrt, 0x3F, 0x16); GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) { @@ -867,20 +877,21 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) } gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rB(ctx->opcode)); - gen_op_fsqrts(); + gen_op_fsqrt(); + gen_op_frsp(); gen_op_store_FT0_fpr(rD(ctx->opcode)); if (Rc(ctx->opcode)) gen_op_set_Rc1(); } /*** Floating-Point multiply-and-add ***/ -/* fmadd */ +/* fmadd - fmadds */ GEN_FLOAT_ACB(madd, 0x1D); -/* fmsub */ +/* fmsub - fmsubs */ GEN_FLOAT_ACB(msub, 0x1C); -/* fnmadd */ +/* fnmadd - fnmadds */ GEN_FLOAT_ACB(nmadd, 0x1F); -/* fnmsub */ +/* fnmsub - fnmsubs */ GEN_FLOAT_ACB(nmsub, 0x1E); /*** Floating-Point round & convert ***/ @@ -1426,6 +1437,10 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ if (rA(ctx->opcode) == 0) { \ gen_op_set_T0(simm); \ } else { \ @@ -1441,6 +1456,10 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ RET_INVAL(ctx); \ @@ -1457,6 +1476,10 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_LDUXF(width, opc) \ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ if (rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode)) { \ RET_INVAL(ctx); \ @@ -1473,6 +1496,10 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ #define GEN_LDXF(width, opc2, opc3) \ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ } else { \ @@ -1501,6 +1528,10 @@ GEN_LDFS(fs, 0x10); GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ if (rA(ctx->opcode) == 0) { \ gen_op_set_T0(simm); \ } else { \ @@ -1516,6 +1547,10 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ uint32_t simm = SIMM(ctx->opcode); \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ if (rA(ctx->opcode) == 0) { \ RET_INVAL(ctx); \ return; \ @@ -1531,6 +1566,10 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_STUXF(width, opc) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ if (rA(ctx->opcode) == 0) { \ RET_INVAL(ctx); \ return; \ @@ -1546,6 +1585,10 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ #define GEN_STXF(width, opc2, opc3) \ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ + if (!ctx->fpu_enabled) { \ + RET_EXCP(ctx, EXCP_NO_FP, 0); \ + return; \ + } \ if (rA(ctx->opcode) == 0) { \ gen_op_load_gpr_T0(rB(ctx->opcode)); \ } else { \ -- cgit v1.2.3 From 7a0e1f41ceeb658791a1456ffc7f8f9edca7da19 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 17:01:47 +0000 Subject: soft float support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1336 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 11 ----- target-i386/cpu.h | 14 ++++-- target-i386/exec.h | 70 +++++--------------------- target-i386/helper.c | 78 ++++++++++++++--------------- target-i386/op.c | 49 +++--------------- target-i386/ops_sse.h | 126 +++++++++++++++++++++++------------------------ target-sparc/cpu.h | 3 ++ target-sparc/op_helper.c | 18 +++---- vl.c | 1 + 9 files changed, 139 insertions(+), 231 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index d8ecc02ff..9b39f59b5 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -62,17 +62,6 @@ extern int fprintf(FILE *, const char *, ...); extern int printf(const char *, ...); #undef NULL #define NULL 0 -#if defined(_BSD) && !defined(__APPLE__) -#include - -#define FE_TONEAREST FP_RN -#define FE_DOWNWARD FP_RM -#define FE_UPWARD FP_RP -#define FE_TOWARDZERO FP_RZ -#define fesetround(x) fpsetround(x) -#else -#include -#endif #ifdef __i386__ #define AREG0 "ebp" diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 154d8bfda..ce65c3430 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -36,6 +36,8 @@ #include "cpu-defs.h" +#include "softfloat.h" + #if defined(__i386__) && !defined(CONFIG_SOFTMMU) #define USE_CODE_COPY #endif @@ -332,14 +334,14 @@ enum { CC_OP_NB, }; -#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD) +#ifdef FLOATX80 #define USE_X86LDOUBLE #endif #ifdef USE_X86LDOUBLE -typedef long double CPU86_LDouble; +typedef floatx80 CPU86_LDouble; #else -typedef double CPU86_LDouble; +typedef float64 CPU86_LDouble; #endif typedef struct SegmentCache { @@ -354,8 +356,8 @@ typedef union { uint16_t _w[8]; uint32_t _l[4]; uint64_t _q[2]; - float _s[4]; - double _d[2]; + float32 _s[4]; + float64 _d[2]; } XMMReg; typedef union { @@ -441,6 +443,7 @@ typedef struct CPUX86State { } fpregs[8]; /* emulator internal variables */ + float_status fp_status; CPU86_LDouble ft0; union { float f; @@ -449,6 +452,7 @@ typedef struct CPUX86State { int64_t i64; } fp_convert; + float_status sse_status; uint32_t mxcsr; XMMReg xmm_regs[CPU_NB_REGS]; XMMReg xmm_t0; diff --git a/target-i386/exec.h b/target-i386/exec.h index c4e59c423..137774f5a 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -139,44 +139,6 @@ extern int loglevel; #include "cpu.h" #include "exec-all.h" -/* XXX: add a generic FPU library */ - -static inline double float32_to_float64(float a) -{ - return a; -} - -static inline float float64_to_float32(double a) -{ - return a; -} - -#if defined(__powerpc__) -/* better to call an helper on ppc */ -float int32_to_float32(int32_t a); -double int32_to_float64(int32_t a); -#else -static inline float int32_to_float32(int32_t a) -{ - return (float)a; -} - -static inline double int32_to_float64(int32_t a) -{ - return (double)a; -} -#endif - -static inline float int64_to_float32(int64_t a) -{ - return (float)a; -} - -static inline double int64_to_float64(int64_t a) -{ - return (double)a; -} - typedef struct CCTable { int (*compute_all)(void); /* return all the flags */ int (*compute_c)(void); /* return the C flag */ @@ -358,9 +320,11 @@ static inline void stfl(target_ulong ptr, float v) #ifdef USE_X86LDOUBLE /* use long double functions */ -#define lrint lrintl -#define llrint llrintl -#define fabs fabsl +#define floatx_to_int32 floatx80_to_int32 +#define floatx_to_int64 floatx80_to_int64 +#define floatx_abs floatx80_abs +#define floatx_chs floatx80_chs +#define floatx_round_to_int floatx80_round_to_int #define sin sinl #define cos cosl #define sqrt sqrtl @@ -370,17 +334,14 @@ static inline void stfl(target_ulong ptr, float v) #define atan2 atan2l #define floor floorl #define ceil ceill -#define rint rintl -#endif - -#if !defined(_BSD) -extern int lrint(CPU86_LDouble x); -extern int64_t llrint(CPU86_LDouble x); #else -#define lrint(d) ((int)rint(d)) -#define llrint(d) ((int)rint(d)) +#define floatx_to_int32 float64_to_int32 +#define floatx_to_int64 float64_to_int64 +#define floatx_abs float64_abs +#define floatx_chs float64_chs +#define floatx_round_to_int float64_round_to_int #endif -extern CPU86_LDouble fabs(CPU86_LDouble x); + extern CPU86_LDouble sin(CPU86_LDouble x); extern CPU86_LDouble cos(CPU86_LDouble x); extern CPU86_LDouble sqrt(CPU86_LDouble x); @@ -390,7 +351,6 @@ extern CPU86_LDouble tan(CPU86_LDouble x); extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); extern CPU86_LDouble floor(CPU86_LDouble x); extern CPU86_LDouble ceil(CPU86_LDouble x); -extern CPU86_LDouble rint(CPU86_LDouble x); #define RC_MASK 0xc00 #define RC_NEAR 0x000 @@ -400,13 +360,6 @@ extern CPU86_LDouble rint(CPU86_LDouble x); #define MAXTAN 9223372036854775808.0 -#ifdef __arm__ -/* we have no way to do correct rounding - a FPU emulator is needed */ -#define FE_DOWNWARD FE_TONEAREST -#define FE_UPWARD FE_TONEAREST -#define FE_TOWARDZERO FE_TONEAREST -#endif - #ifdef USE_X86LDOUBLE /* only for x86 */ @@ -596,6 +549,7 @@ float approx_rsqrt(float a); float approx_rcp(float a); double helper_sqrt(double a); int fpu_isnan(double a); +void update_fp_status(void); extern const uint8_t parity_table[256]; extern const uint8_t rclw_table[32]; diff --git a/target-i386/helper.c b/target-i386/helper.c index 53b85d3aa..64cb51ab5 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2541,13 +2541,11 @@ void helper_fbld_ST0_A0(void) void helper_fbst_ST0_A0(void) { - CPU86_LDouble tmp; int v; target_ulong mem_ref, mem_end; int64_t val; - tmp = rint(ST0); - val = (int64_t)tmp; + val = floatx_to_int64(ST0, &env->fp_status); mem_ref = A0; mem_end = mem_ref + 9; if (val < 0) { @@ -2740,29 +2738,7 @@ void helper_fsincos(void) void helper_frndint(void) { - CPU86_LDouble a; - - a = ST0; -#ifdef __arm__ - switch(env->fpuc & RC_MASK) { - default: - case RC_NEAR: - asm("rndd %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_DOWN: - asm("rnddm %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_UP: - asm("rnddp %0, %1" : "=f" (a) : "f"(a)); - break; - case RC_CHOP: - asm("rnddz %0, %1" : "=f" (a) : "f"(a)); - break; - } -#else - a = rint(a); -#endif - ST0 = a; + ST0 = floatx_round_to_int(ST0, &env->fp_status); } void helper_fscale(void) @@ -3263,25 +3239,43 @@ float approx_rcp(float a) return 1.0 / a; } -/* XXX: find a better solution */ -double helper_sqrt(double a) +void update_fp_status(void) { - return sqrt(a); -} + int rnd_type; -/* XXX: move that to another file */ -#if defined(__powerpc__) -/* better to call an helper on ppc */ -float int32_to_float32(int32_t a) -{ - return (float)a; -} - -double int32_to_float64(int32_t a) -{ - return (double)a; -} + /* set rounding mode */ + switch(env->fpuc & RC_MASK) { + default: + case RC_NEAR: + rnd_type = float_round_nearest_even; + break; + case RC_DOWN: + rnd_type = float_round_down; + break; + case RC_UP: + rnd_type = float_round_up; + break; + case RC_CHOP: + rnd_type = float_round_to_zero; + break; + } + set_float_rounding_mode(rnd_type, &env->fp_status); +#ifdef FLOATX80 + switch((env->fpuc >> 8) & 3) { + case 0: + rnd_type = 32; + break; + case 2: + rnd_type = 64; + break; + case 3: + default: + rnd_type = 80; + break; + } + set_floatx80_rounding_precision(rnd_type, &env->fp_status); #endif +} #if !defined(CONFIG_USER_ONLY) diff --git a/target-i386/op.c b/target-i386/op.c index dc0dceadf..bbc2b19ae 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1598,26 +1598,6 @@ CCTable cc_table[CC_OP_NB] = { functions comes from the LGPL'ed x86 emulator found in the Willows TWIN windows emulator. */ -#if defined(__powerpc__) -extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble); - -/* correct (but slow) PowerPC rint() (glibc version is incorrect) */ -double qemu_rint(double x) -{ - double y = 4503599627370496.0; - if (fabs(x) >= y) - return x; - if (x < 0) - y = -y; - y = (x + y) - y; - if (y == 0.0) - y = copysign(y, x); - return y; -} - -#define rint qemu_rint -#endif - /* fp load FT0 */ void OPPROTO op_flds_FT0_A0(void) @@ -1866,7 +1846,7 @@ void OPPROTO op_fist_ST0_A0(void) int val; d = ST0; - val = lrint(d); + val = floatx_to_int32(d, &env->fp_status); if (val != (int16_t)val) val = -32768; stw(A0, val); @@ -1883,7 +1863,7 @@ void OPPROTO op_fistl_ST0_A0(void) int val; d = ST0; - val = lrint(d); + val = floatx_to_int32(d, &env->fp_status); stl(A0, val); FORCE_RET(); } @@ -1898,7 +1878,7 @@ void OPPROTO op_fistll_ST0_A0(void) int64_t val; d = ST0; - val = llrint(d); + val = floatx_to_int64(d, &env->fp_status); stq(A0, val); FORCE_RET(); } @@ -2101,12 +2081,12 @@ void OPPROTO op_fdivr_STN_ST0(void) /* misc FPU operations */ void OPPROTO op_fchs_ST0(void) { - ST0 = -ST0; + ST0 = floatx_chs(ST0); } void OPPROTO op_fabs_ST0(void) { - ST0 = fabs(ST0); + ST0 = floatx_abs(ST0); } void OPPROTO op_fxam_ST0(void) @@ -2251,25 +2231,8 @@ void OPPROTO op_fnstcw_A0(void) void OPPROTO op_fldcw_A0(void) { - int rnd_type; env->fpuc = lduw(A0); - /* set rounding mode */ - switch(env->fpuc & RC_MASK) { - default: - case RC_NEAR: - rnd_type = FE_TONEAREST; - break; - case RC_DOWN: - rnd_type = FE_DOWNWARD; - break; - case RC_UP: - rnd_type = FE_UPWARD; - break; - case RC_CHOP: - rnd_type = FE_TOWARDZERO; - break; - } - fesetround(rnd_type); + update_fp_status(); } void OPPROTO op_fclex(void) diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 8472a34d3..be1d68bfb 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -654,10 +654,10 @@ void OPPROTO op_ ## name ## ps (void)\ Reg *d, *s;\ d = (Reg *)((char *)env + PARAM1);\ s = (Reg *)((char *)env + PARAM2);\ - d->XMM_S(0) = F(d->XMM_S(0), s->XMM_S(0));\ - d->XMM_S(1) = F(d->XMM_S(1), s->XMM_S(1));\ - d->XMM_S(2) = F(d->XMM_S(2), s->XMM_S(2));\ - d->XMM_S(3) = F(d->XMM_S(3), s->XMM_S(3));\ + d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0));\ + d->XMM_S(1) = F(32, d->XMM_S(1), s->XMM_S(1));\ + d->XMM_S(2) = F(32, d->XMM_S(2), s->XMM_S(2));\ + d->XMM_S(3) = F(32, d->XMM_S(3), s->XMM_S(3));\ }\ \ void OPPROTO op_ ## name ## ss (void)\ @@ -665,15 +665,15 @@ void OPPROTO op_ ## name ## ss (void)\ Reg *d, *s;\ d = (Reg *)((char *)env + PARAM1);\ s = (Reg *)((char *)env + PARAM2);\ - d->XMM_S(0) = F(d->XMM_S(0), s->XMM_S(0));\ + d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0));\ }\ void OPPROTO op_ ## name ## pd (void)\ {\ Reg *d, *s;\ d = (Reg *)((char *)env + PARAM1);\ s = (Reg *)((char *)env + PARAM2);\ - d->XMM_D(0) = F(d->XMM_D(0), s->XMM_D(0));\ - d->XMM_D(1) = F(d->XMM_D(1), s->XMM_D(1));\ + d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ + d->XMM_D(1) = F(64, d->XMM_D(1), s->XMM_D(1));\ }\ \ void OPPROTO op_ ## name ## sd (void)\ @@ -681,16 +681,16 @@ void OPPROTO op_ ## name ## sd (void)\ Reg *d, *s;\ d = (Reg *)((char *)env + PARAM1);\ s = (Reg *)((char *)env + PARAM2);\ - d->XMM_D(0) = F(d->XMM_D(0), s->XMM_D(0));\ + d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ } -#define FPU_ADD(a, b) (a) + (b) -#define FPU_SUB(a, b) (a) - (b) -#define FPU_MUL(a, b) (a) * (b) -#define FPU_DIV(a, b) (a) / (b) -#define FPU_MIN(a, b) (a) < (b) ? (a) : (b) -#define FPU_MAX(a, b) (a) > (b) ? (a) : (b) -#define FPU_SQRT(a, b) helper_sqrt(b) +#define FPU_ADD(size, a, b) float ## size ## _add(a, b, &env->sse_status) +#define FPU_SUB(size, a, b) float ## size ## _sub(a, b, &env->sse_status) +#define FPU_MUL(size, a, b) float ## size ## _mul(a, b, &env->sse_status) +#define FPU_DIV(size, a, b) float ## size ## _div(a, b, &env->sse_status) +#define FPU_MIN(size, a, b) (a) < (b) ? (a) : (b) +#define FPU_MAX(size, a, b) (a) > (b) ? (a) : (b) +#define FPU_SQRT(size, a, b) float ## size ## _sqrt(b, &env->sse_status) SSE_OP_S(add, FPU_ADD) SSE_OP_S(sub, FPU_SUB) @@ -710,8 +710,8 @@ void OPPROTO op_cvtps2pd(void) s = (Reg *)((char *)env + PARAM2); s0 = s->XMM_S(0); s1 = s->XMM_S(1); - d->XMM_D(0) = float32_to_float64(s0); - d->XMM_D(1) = float32_to_float64(s1); + d->XMM_D(0) = float32_to_float64(s0, &env->sse_status); + d->XMM_D(1) = float32_to_float64(s1, &env->sse_status); } void OPPROTO op_cvtpd2ps(void) @@ -719,8 +719,8 @@ void OPPROTO op_cvtpd2ps(void) Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); - d->XMM_S(0) = float64_to_float32(s->XMM_D(0)); - d->XMM_S(1) = float64_to_float32(s->XMM_D(1)); + d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status); + d->XMM_S(1) = float64_to_float32(s->XMM_D(1), &env->sse_status); d->Q(1) = 0; } @@ -729,7 +729,7 @@ void OPPROTO op_cvtss2sd(void) Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); - d->XMM_D(0) = float32_to_float64(s->XMM_S(0)); + d->XMM_D(0) = float32_to_float64(s->XMM_S(0), &env->sse_status); } void OPPROTO op_cvtsd2ss(void) @@ -737,7 +737,7 @@ void OPPROTO op_cvtsd2ss(void) Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); - d->XMM_S(0) = float64_to_float32(s->XMM_D(0)); + d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status); } /* integer to float */ @@ -745,10 +745,10 @@ void OPPROTO op_cvtdq2ps(void) { XMMReg *d = (XMMReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->XMM_S(0) = int32_to_float32(s->XMM_L(0)); - d->XMM_S(1) = int32_to_float32(s->XMM_L(1)); - d->XMM_S(2) = int32_to_float32(s->XMM_L(2)); - d->XMM_S(3) = int32_to_float32(s->XMM_L(3)); + d->XMM_S(0) = int32_to_float32(s->XMM_L(0), &env->sse_status); + d->XMM_S(1) = int32_to_float32(s->XMM_L(1), &env->sse_status); + d->XMM_S(2) = int32_to_float32(s->XMM_L(2), &env->sse_status); + d->XMM_S(3) = int32_to_float32(s->XMM_L(3), &env->sse_status); } void OPPROTO op_cvtdq2pd(void) @@ -758,49 +758,49 @@ void OPPROTO op_cvtdq2pd(void) int32_t l0, l1; l0 = (int32_t)s->XMM_L(0); l1 = (int32_t)s->XMM_L(1); - d->XMM_D(0) = int32_to_float64(l0); - d->XMM_D(1) = int32_to_float64(l1); + d->XMM_D(0) = int32_to_float64(l0, &env->sse_status); + d->XMM_D(1) = int32_to_float64(l1, &env->sse_status); } void OPPROTO op_cvtpi2ps(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); MMXReg *s = (MMXReg *)((char *)env + PARAM2); - d->XMM_S(0) = int32_to_float32(s->MMX_L(0)); - d->XMM_S(1) = int32_to_float32(s->MMX_L(1)); + d->XMM_S(0) = int32_to_float32(s->MMX_L(0), &env->sse_status); + d->XMM_S(1) = int32_to_float32(s->MMX_L(1), &env->sse_status); } void OPPROTO op_cvtpi2pd(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); MMXReg *s = (MMXReg *)((char *)env + PARAM2); - d->XMM_D(0) = int32_to_float64(s->MMX_L(0)); - d->XMM_D(1) = int32_to_float64(s->MMX_L(1)); + d->XMM_D(0) = int32_to_float64(s->MMX_L(0), &env->sse_status); + d->XMM_D(1) = int32_to_float64(s->MMX_L(1), &env->sse_status); } void OPPROTO op_cvtsi2ss(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_S(0) = int32_to_float32(T0); + d->XMM_S(0) = int32_to_float32(T0, &env->sse_status); } void OPPROTO op_cvtsi2sd(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_D(0) = int32_to_float64(T0); + d->XMM_D(0) = int32_to_float64(T0, &env->sse_status); } #ifdef TARGET_X86_64 void OPPROTO op_cvtsq2ss(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_S(0) = int64_to_float32(T0); + d->XMM_S(0) = int64_to_float32(T0, &env->sse_status); } void OPPROTO op_cvtsq2sd(void) { XMMReg *d = (Reg *)((char *)env + PARAM1); - d->XMM_D(0) = int64_to_float64(T0); + d->XMM_D(0) = int64_to_float64(T0, &env->sse_status); } #endif @@ -809,18 +809,18 @@ void OPPROTO op_cvtps2dq(void) { XMMReg *d = (XMMReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->XMM_L(0) = lrint(s->XMM_S(0)); - d->XMM_L(1) = lrint(s->XMM_S(1)); - d->XMM_L(2) = lrint(s->XMM_S(2)); - d->XMM_L(3) = lrint(s->XMM_S(3)); + d->XMM_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status); + d->XMM_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status); + d->XMM_L(2) = float32_to_int32(s->XMM_S(2), &env->sse_status); + d->XMM_L(3) = float32_to_int32(s->XMM_S(3), &env->sse_status); } void OPPROTO op_cvtpd2dq(void) { XMMReg *d = (XMMReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->XMM_L(0) = lrint(s->XMM_D(0)); - d->XMM_L(1) = lrint(s->XMM_D(1)); + d->XMM_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status); + d->XMM_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status); d->XMM_Q(1) = 0; } @@ -828,41 +828,41 @@ void OPPROTO op_cvtps2pi(void) { MMXReg *d = (MMXReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->MMX_L(0) = lrint(s->XMM_S(0)); - d->MMX_L(1) = lrint(s->XMM_S(1)); + d->MMX_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status); + d->MMX_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status); } void OPPROTO op_cvtpd2pi(void) { MMXReg *d = (MMXReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->MMX_L(0) = lrint(s->XMM_D(0)); - d->MMX_L(1) = lrint(s->XMM_D(1)); + d->MMX_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status); + d->MMX_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status); } void OPPROTO op_cvtss2si(void) { XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = (int32_t)lrint(s->XMM_S(0)); + T0 = float32_to_int32(s->XMM_S(0), &env->sse_status); } void OPPROTO op_cvtsd2si(void) { XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = (int32_t)lrint(s->XMM_D(0)); + T0 = float64_to_int32(s->XMM_D(0), &env->sse_status); } #ifdef TARGET_X86_64 void OPPROTO op_cvtss2sq(void) { XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = llrint(s->XMM_S(0)); + T0 = float32_to_int64(s->XMM_S(0), &env->sse_status); } void OPPROTO op_cvtsd2sq(void) { XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = llrint(s->XMM_D(0)); + T0 = float64_to_int64(s->XMM_D(0), &env->sse_status); } #endif @@ -871,18 +871,18 @@ void OPPROTO op_cvttps2dq(void) { XMMReg *d = (XMMReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->XMM_L(0) = (int32_t)s->XMM_S(0); - d->XMM_L(1) = (int32_t)s->XMM_S(1); - d->XMM_L(2) = (int32_t)s->XMM_S(2); - d->XMM_L(3) = (int32_t)s->XMM_S(3); + d->XMM_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status); + d->XMM_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status); + d->XMM_L(2) = float32_to_int32_round_to_zero(s->XMM_S(2), &env->sse_status); + d->XMM_L(3) = float32_to_int32_round_to_zero(s->XMM_S(3), &env->sse_status); } void OPPROTO op_cvttpd2dq(void) { XMMReg *d = (XMMReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->XMM_L(0) = (int32_t)s->XMM_D(0); - d->XMM_L(1) = (int32_t)s->XMM_D(1); + d->XMM_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status); + d->XMM_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status); d->XMM_Q(1) = 0; } @@ -890,41 +890,41 @@ void OPPROTO op_cvttps2pi(void) { MMXReg *d = (MMXReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->MMX_L(0) = (int32_t)(s->XMM_S(0)); - d->MMX_L(1) = (int32_t)(s->XMM_S(1)); + d->MMX_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status); + d->MMX_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status); } void OPPROTO op_cvttpd2pi(void) { MMXReg *d = (MMXReg *)((char *)env + PARAM1); XMMReg *s = (XMMReg *)((char *)env + PARAM2); - d->MMX_L(0) = (int32_t)(s->XMM_D(0)); - d->MMX_L(1) = (int32_t)(s->XMM_D(1)); + d->MMX_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status); + d->MMX_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status); } void OPPROTO op_cvttss2si(void) { XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = (int32_t)(s->XMM_S(0)); + T0 = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status); } void OPPROTO op_cvttsd2si(void) { XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = (int32_t)(s->XMM_D(0)); + T0 = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status); } #ifdef TARGET_X86_64 void OPPROTO op_cvttss2sq(void) { XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = (int64_t)(s->XMM_S(0)); + T0 = float32_to_int64_round_to_zero(s->XMM_S(0), &env->sse_status); } void OPPROTO op_cvttsd2sq(void) { XMMReg *s = (XMMReg *)((char *)env + PARAM1); - T0 = (int64_t)(s->XMM_D(0)); + T0 = float64_to_int64_round_to_zero(s->XMM_D(0), &env->sse_status); } #endif diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index b07e2afcf..67a6e3e46 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -15,6 +15,8 @@ #include "cpu-defs.h" +#include "softfloat.h" + /*#define EXCP_INTERRUPT 0x100*/ /* trap definitions */ @@ -150,6 +152,7 @@ typedef struct CPUSPARCState { /* temporary float registers */ float ft0, ft1, ft2; double dt0, dt1, dt2; + float_status fp_status; #if defined(TARGET_SPARC64) target_ulong t0, t1, t2; #endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 9cb3de49a..40ab90156 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1,5 +1,3 @@ -#include -#include #include "exec.h" //#define DEBUG_MMU @@ -24,17 +22,17 @@ void do_fitod(void) void do_fabss(void) { - FT0 = fabsf(FT1); + FT0 = float32_abs(FT1); } void do_fsqrts(void) { - FT0 = sqrtf(FT1); + FT0 = float32_sqrt(FT1, &env->fp_status); } void do_fsqrtd(void) { - DT0 = sqrt(DT1); + DT0 = float64_sqrt(DT1, &env->fp_status); } void do_fcmps (void) @@ -252,20 +250,22 @@ void helper_rett() void helper_ldfsr(void) { + int rnd_mode; switch (env->fsr & FSR_RD_MASK) { case FSR_RD_NEAREST: - fesetround(FE_TONEAREST); + rnd_mode = float_round_nearest_even; break; case FSR_RD_ZERO: - fesetround(FE_TOWARDZERO); + rnd_mode = float_round_to_zero; break; case FSR_RD_POS: - fesetround(FE_UPWARD); + rnd_mode = float_round_up; break; case FSR_RD_NEG: - fesetround(FE_DOWNWARD); + rnd_mode = float_round_down; break; } + set_float_rounding_mode(rnd_mode, &env->fp_status); } void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f) diff --git a/vl.c b/vl.c index a815a50fa..9f8b8a6b9 100644 --- a/vl.c +++ b/vl.c @@ -2271,6 +2271,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) } env->fpuc = fpuc; + /* XXX: restore FPU round state */ env->fpstt = (fpus >> 11) & 7; env->fpus = fpus & ~0x3800; fptag ^= 0xff; -- cgit v1.2.3 From 53cd6637924a83481038b2266c59dc1e1ff7bb11 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 18:50:23 +0000 Subject: soft float support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1337 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 42 +++++++------- target-arm/cpu.h | 13 +++-- target-arm/op.c | 85 +++++++++++++++-------------- target-arm/op_helper.c | 145 +++++++++++++++---------------------------------- 4 files changed, 119 insertions(+), 166 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index afc9ae1a4..25f9cea7a 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -119,7 +119,7 @@ static inline void tswap64s(uint64_t *s) /* NOTE: arm FPA is horrible as double 32 bit words are stored in big endian ! */ typedef union { - double d; + float64 d; #if defined(WORDS_BIGENDIAN) || (defined(__arm__) && !defined(__VFP_FP__)) struct { uint32_t upper; @@ -268,27 +268,27 @@ static inline void stq_p(void *ptr, uint64_t v) /* float access */ -static inline float ldfl_p(void *ptr) +static inline float32 ldfl_p(void *ptr) { union { - float f; + float32 f; uint32_t i; } u; u.i = ldl_p(ptr); return u.f; } -static inline void stfl_p(void *ptr, float v) +static inline void stfl_p(void *ptr, float32 v) { union { - float f; + float32 f; uint32_t i; } u; u.f = v; stl_p(ptr, u.i); } -static inline double ldfq_p(void *ptr) +static inline float64 ldfq_p(void *ptr) { CPU_DoubleU u; u.l.lower = ldl_p(ptr); @@ -296,7 +296,7 @@ static inline double ldfq_p(void *ptr) return u.d; } -static inline void stfq_p(void *ptr, double v) +static inline void stfq_p(void *ptr, float64 v) { CPU_DoubleU u; u.d = v; @@ -397,27 +397,27 @@ static inline void stq_p(void *ptr, uint64_t v) /* float access */ -static inline float ldfl_p(void *ptr) +static inline float32 ldfl_p(void *ptr) { union { - float f; + float32 f; uint32_t i; } u; u.i = ldl_p(ptr); return u.f; } -static inline void stfl_p(void *ptr, float v) +static inline void stfl_p(void *ptr, float32 v) { union { - float f; + float32 f; uint32_t i; } u; u.f = v; stl_p(ptr, u.i); } -static inline double ldfq_p(void *ptr) +static inline float64 ldfq_p(void *ptr) { CPU_DoubleU u; u.l.upper = ldl_p(ptr); @@ -425,7 +425,7 @@ static inline double ldfq_p(void *ptr) return u.d; } -static inline void stfq_p(void *ptr, double v) +static inline void stfq_p(void *ptr, float64 v) { CPU_DoubleU u; u.d = v; @@ -472,24 +472,24 @@ static inline void stq_p(void *ptr, uint64_t v) /* float access */ -static inline float ldfl_p(void *ptr) +static inline float32 ldfl_p(void *ptr) { - return *(float *)ptr; + return *(float32 *)ptr; } -static inline double ldfq_p(void *ptr) +static inline float64 ldfq_p(void *ptr) { - return *(double *)ptr; + return *(float64 *)ptr; } -static inline void stfl_p(void *ptr, float v) +static inline void stfl_p(void *ptr, float32 v) { - *(float *)ptr = v; + *(float32 *)ptr = v; } -static inline void stfq_p(void *ptr, double v) +static inline void stfq_p(void *ptr, float64 v) { - *(double *)ptr = v; + *(float64 *)ptr = v; } #endif diff --git a/target-arm/cpu.h b/target-arm/cpu.h index a5f4f94e5..cf11c2f94 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -24,6 +24,8 @@ #include "cpu-defs.h" +#include "softfloat.h" + #define EXCP_UDEF 1 /* undefined instruction */ #define EXCP_SWI 2 /* software interrupt */ #define EXCP_PREFETCH_ABORT 3 @@ -70,8 +72,8 @@ typedef struct CPUARMState { /* VFP coprocessor state. */ struct { union { - float s[32]; - double d[16]; + float32 s[32]; + float64 d[16]; } regs; /* We store these fpcsr fields separately for convenience. */ @@ -81,9 +83,10 @@ typedef struct CPUARMState { uint32_t fpscr; /* Temporary variables if we don't have spare fp regs. */ - float tmp0s, tmp1s; - double tmp0d, tmp1d; - + float32 tmp0s, tmp1s; + float64 tmp0d, tmp1d; + + float_status fp_status; } vfp; /* user data */ diff --git a/target-arm/op.c b/target-arm/op.c index 6c608f141..42ee4f960 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -864,19 +864,19 @@ void OPPROTO op_undef_insn(void) #define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void) -#define VFP_BINOP(name, op) \ +#define VFP_BINOP(name) \ VFP_OP(name, s) \ { \ - FT0s = FT0s op FT1s; \ + FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status); \ } \ VFP_OP(name, d) \ { \ - FT0d = FT0d op FT1d; \ + FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status); \ } -VFP_BINOP(add, +) -VFP_BINOP(sub, -) -VFP_BINOP(mul, *) -VFP_BINOP(div, /) +VFP_BINOP(add) +VFP_BINOP(sub) +VFP_BINOP(mul) +VFP_BINOP(div) #undef VFP_BINOP #define VFP_HELPER(name) \ @@ -898,41 +898,51 @@ VFP_HELPER(cmpe) without looking at the rest of the value. */ VFP_OP(neg, s) { - FT0s = -FT0s; + FT0s = float32_chs(FT0s); } VFP_OP(neg, d) { - FT0d = -FT0d; + FT0d = float64_chs(FT0d); } VFP_OP(F1_ld0, s) { - FT1s = 0.0f; + union { + uint32_t i; + float32 s; + } v; + v.i = 0; + FT1s = v.s; } VFP_OP(F1_ld0, d) { - FT1d = 0.0; + union { + uint64_t i; + float64 d; + } v; + v.i = 0; + FT1d = v.d; } /* Helper routines to perform bitwise copies between float and int. */ -static inline float vfp_itos(uint32_t i) +static inline float32 vfp_itos(uint32_t i) { union { uint32_t i; - float s; + float32 s; } v; v.i = i; return v.s; } -static inline uint32_t vfp_stoi(float s) +static inline uint32_t vfp_stoi(float32 s) { union { uint32_t i; - float s; + float32 s; } v; v.s = s; @@ -942,111 +952,106 @@ static inline uint32_t vfp_stoi(float s) /* Integer to float conversion. */ VFP_OP(uito, s) { - FT0s = (float)(uint32_t)vfp_stoi(FT0s); + FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); } VFP_OP(uito, d) { - FT0d = (double)(uint32_t)vfp_stoi(FT0s); + FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); } VFP_OP(sito, s) { - FT0s = (float)(int32_t)vfp_stoi(FT0s); + FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); } VFP_OP(sito, d) { - FT0d = (double)(int32_t)vfp_stoi(FT0s); + FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); } /* Float to integer conversion. */ VFP_OP(toui, s) { - FT0s = vfp_itos((uint32_t)FT0s); + FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status)); } VFP_OP(toui, d) { - FT0s = vfp_itos((uint32_t)FT0d); + FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status)); } VFP_OP(tosi, s) { - FT0s = vfp_itos((int32_t)FT0s); + FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status)); } VFP_OP(tosi, d) { - FT0s = vfp_itos((int32_t)FT0d); + FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status)); } /* TODO: Set rounding mode properly. */ VFP_OP(touiz, s) { - FT0s = vfp_itos((uint32_t)FT0s); + FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status)); } VFP_OP(touiz, d) { - FT0s = vfp_itos((uint32_t)FT0d); + FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status)); } VFP_OP(tosiz, s) { - FT0s = vfp_itos((int32_t)FT0s); + FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status)); } VFP_OP(tosiz, d) { - FT0s = vfp_itos((int32_t)FT0d); + FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status)); } /* floating point conversion */ VFP_OP(fcvtd, s) { - FT0d = (double)FT0s; + FT0d = float32_to_float64(FT0s, &env->vfp.fp_status); } VFP_OP(fcvts, d) { - FT0s = (float)FT0d; + FT0s = float64_to_float32(FT0d, &env->vfp.fp_status); } /* Get and Put values from registers. */ VFP_OP(getreg_F0, d) { - FT0d = *(double *)((char *) env + PARAM1); + FT0d = *(float64 *)((char *) env + PARAM1); } VFP_OP(getreg_F0, s) { - FT0s = *(float *)((char *) env + PARAM1); + FT0s = *(float32 *)((char *) env + PARAM1); } VFP_OP(getreg_F1, d) { - FT1d = *(double *)((char *) env + PARAM1); + FT1d = *(float64 *)((char *) env + PARAM1); } VFP_OP(getreg_F1, s) { - FT1s = *(float *)((char *) env + PARAM1); + FT1s = *(float32 *)((char *) env + PARAM1); } VFP_OP(setreg_F0, d) { - *(double *)((char *) env + PARAM1) = FT0d; + *(float64 *)((char *) env + PARAM1) = FT0d; } VFP_OP(setreg_F0, s) { - *(float *)((char *) env + PARAM1) = FT0s; -} - -VFP_OP(foobar, d) -{ - FT0d = env->vfp.regs.s[3]; + *(float32 *)((char *) env + PARAM1) = FT0s; } void OPPROTO op_vfp_movl_T0_fpscr(void) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 38c97fe68..a39e44adb 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -17,24 +17,8 @@ * 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 -#include #include "exec.h" -/* If the host doesn't define C99 math intrinsics then use the normal - operators. This may generate excess exceptions, but it's probably - near enough for most things. */ -#ifndef isless -#define isless(x, y) (x < y) -#endif -#ifndef isgreater -#define isgreater(x, y) (x > y) -#endif -#ifndef isunordered -#define isunordered(x, y) (!((x < y) || (x >= y))) -#endif - void raise_exception(int tt) { env->exception_index = tt; @@ -59,119 +43,88 @@ void cpu_unlock(void) void do_vfp_abss(void) { - FT0s = fabsf(FT0s); + FT0s = float32_abs(FT0s); } void do_vfp_absd(void) { - FT0d = fabs(FT0d); + FT0d = float64_abs(FT0d); } void do_vfp_sqrts(void) { - FT0s = sqrtf(FT0s); + FT0s = float32_sqrt(FT0s, &env->vfp.fp_status); } void do_vfp_sqrtd(void) { - FT0d = sqrt(FT0d); + FT0d = float64_sqrt(FT0d, &env->vfp.fp_status); } -/* We use an == operator first to generate teh correct floating point - exception. Subsequent comparisons use the exception-safe macros. */ -#define DO_VFP_cmp(p) \ +/* XXX: check quiet/signaling case */ +#define DO_VFP_cmp(p, size) \ void do_vfp_cmp##p(void) \ { \ uint32_t flags; \ - if (FT0##p == FT1##p) \ - flags = 0xc; \ - else if (isless (FT0##p, FT1##p)) \ - flags = 0x8; \ - else if (isgreater (FT0##p, FT1##p)) \ - flags = 0x2; \ - else /* unordered */ \ - flags = 0x3; \ + switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\ + case 0: flags = 0xc; break;\ + case -1: flags = 0x8; break;\ + case 1: flags = 0x2; break;\ + default: case 2: flags = 0x3; break;\ + }\ env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ FORCE_RET(); \ -} -DO_VFP_cmp(s) -DO_VFP_cmp(d) -#undef DO_VFP_cmp - -/* We use a > operator first to get FP exceptions right. */ -#define DO_VFP_cmpe(p) \ +}\ +\ void do_vfp_cmpe##p(void) \ { \ - uint32_t flags; \ - if (FT0##p > FT1##p) \ - flags = 0x2; \ - else if (isless (FT0##p, FT1##p)) \ - flags = 0x8; \ - else if (isunordered (FT0##p, FT1##p)) \ - flags = 0x3; \ - else /* equal */ \ - flags = 0xc; \ + uint32_t flags; \ + switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\ + case 0: flags = 0xc; break;\ + case -1: flags = 0x8; break;\ + case 1: flags = 0x2; break;\ + default: case 2: flags = 0x3; break;\ + }\ env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ - FORCE_RET(); \ + FORCE_RET(); \ } -DO_VFP_cmpe(s) -DO_VFP_cmpe(d) -#undef DO_VFP_cmpe +DO_VFP_cmp(s, 32) +DO_VFP_cmp(d, 64) +#undef DO_VFP_cmp /* Convert host exception flags to vfp form. */ -int vfp_exceptbits_from_host(int host_bits) +static inline int vfp_exceptbits_from_host(int host_bits) { int target_bits = 0; -#ifdef FE_INVALID - if (host_bits & FE_INVALID) + if (host_bits & float_flag_invalid) target_bits |= 1; -#endif -#ifdef FE_DIVBYZERO - if (host_bits & FE_DIVBYZERO) + if (host_bits & float_flag_divbyzero) target_bits |= 2; -#endif -#ifdef FE_OVERFLOW - if (host_bits & FE_OVERFLOW) + if (host_bits & float_flag_overflow) target_bits |= 4; -#endif -#ifdef FE_UNDERFLOW - if (host_bits & FE_UNDERFLOW) + if (host_bits & float_flag_underflow) target_bits |= 8; -#endif -#ifdef FE_INEXACT - if (host_bits & FE_INEXACT) + if (host_bits & float_flag_inexact) target_bits |= 0x10; -#endif - /* C doesn't define an inexact exception. */ return target_bits; } /* Convert vfp exception flags to target form. */ -int vfp_host_exceptbits_to_host(int target_bits) +static inline int vfp_exceptbits_to_host(int target_bits) { int host_bits = 0; -#ifdef FE_INVALID if (target_bits & 1) - host_bits |= FE_INVALID; -#endif -#ifdef FE_DIVBYZERO + host_bits |= float_flag_invalid; if (target_bits & 2) - host_bits |= FE_DIVBYZERO; -#endif -#ifdef FE_OVERFLOW + host_bits |= float_flag_divbyzero; if (target_bits & 4) - host_bits |= FE_OVERFLOW; -#endif -#ifdef FE_UNDERFLOW + host_bits |= float_flag_overflow; if (target_bits & 8) - host_bits |= FE_UNDERFLOW; -#endif -#ifdef FE_INEXACT + host_bits |= float_flag_underflow; if (target_bits & 0x10) - host_bits |= FE_INEXACT; -#endif + host_bits |= float_flag_inexact; return host_bits; } @@ -190,31 +143,23 @@ void do_vfp_set_fpscr(void) i = (T0 >> 22) & 3; switch (i) { case 0: - i = FE_TONEAREST; + i = float_round_nearest_even; break; case 1: - i = FE_UPWARD; + i = float_round_up; break; case 2: - i = FE_DOWNWARD; + i = float_round_down; break; case 3: - i = FE_TOWARDZERO; + i = float_round_to_zero; break; } - fesetround (i); + set_float_rounding_mode(i, &env->vfp.fp_status); } - /* Clear host exception flags. */ - feclearexcept(FE_ALL_EXCEPT); - -#ifdef feenableexcept - if (changed & 0x1f00) { - i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f); - feenableexcept (i); - fedisableexcept (FE_ALL_EXCEPT & ~i); - } -#endif + i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f); + set_float_exception_flags(i, &env->vfp.fp_status); /* XXX: FZ and DN are not implemented. */ } @@ -224,6 +169,6 @@ void do_vfp_get_fpscr(void) T0 = (env->vfp.fpscr & 0xffc8ffff) | (env->vfp.vec_len << 16) | (env->vfp.vec_stride << 20); - i = fetestexcept(FE_ALL_EXCEPT); + i = get_float_exception_flags(&env->vfp.fp_status); T0 |= vfp_exceptbits_from_host(i); } -- cgit v1.2.3 From 1d6bda356153c82e100680d9f2165e32c8fb1330 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Mar 2005 18:52:29 +0000 Subject: added abs, chs and compare functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1338 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fpu/softfloat.h | 69 +++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index ad57fd9e1..5e846200a 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -54,6 +54,11 @@ void set_float_rounding_mode(int val STATUS_PARAM) STATUS(float_rounding_mode) = val; } +void set_float_exception_flags(int val STATUS_PARAM) +{ + STATUS(float_exception_flags) = val; +} + #ifdef FLOATX80 void set_floatx80_rounding_precision(int val STATUS_PARAM) { @@ -5183,3 +5188,133 @@ flag float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) #endif +/* misc functions */ +float32 uint32_to_float32( unsigned int a STATUS_PARAM ) +{ + return int64_to_float32(a STATUS_VAR); +} + +float64 uint32_to_float64( unsigned int a STATUS_PARAM ) +{ + return int64_to_float64(a STATUS_VAR); +} + +unsigned int float32_to_uint32( float32 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float32_to_int64(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float32_to_int64_round_to_zero(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float64_to_uint32( float64 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float64_to_int64(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float64_to_int64_round_to_zero(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffffffff) { + res = 0xffffffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + +#define COMPARE(s, nan_exp) \ +INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \ + int is_quiet STATUS_PARAM ) \ +{ \ + flag aSign, bSign; \ + \ + if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \ + extractFloat ## s ## Frac( a ) ) || \ + ( ( extractFloat ## s ## Exp( b ) == nan_exp ) && \ + extractFloat ## s ## Frac( b ) )) { \ + if (!is_quiet || \ + float ## s ## _is_signaling_nan( a ) || \ + float ## s ## _is_signaling_nan( b ) ) { \ + float_raise( float_flag_invalid STATUS_VAR); \ + } \ + return float_relation_unordered; \ + } \ + aSign = extractFloat ## s ## Sign( a ); \ + bSign = extractFloat ## s ## Sign( b ); \ + if ( aSign != bSign ) { \ + if ( (bits ## s) ( ( a | b )<<1 ) == 0 ) { \ + /* zero case */ \ + return float_relation_equal; \ + } else { \ + return 1 - (2 * aSign); \ + } \ + } else { \ + if (a == b) { \ + return float_relation_equal; \ + } else { \ + return 1 - 2 * (aSign ^ ( a < b )); \ + } \ + } \ +} \ + \ +char float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \ +{ \ + return float ## s ## _compare_internal(a, b, 0 STATUS_VAR); \ +} \ + \ +char float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ +{ \ + return float ## s ## _compare_internal(a, b, 1 STATUS_VAR); \ +} + +COMPARE(32, 0xff) +COMPARE(64, 0x7ff) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 9aefbf75a..666d6a017 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -93,6 +93,16 @@ typedef int64_t sbits64; #define STATUS(field) status->field #define STATUS_VAR , status +/*---------------------------------------------------------------------------- +| Software IEC/IEEE floating-point ordering relations +*----------------------------------------------------------------------------*/ +enum { + float_relation_less = -1, + float_relation_equal = 0, + float_relation_greater = 1, + float_relation_unordered = 2 +}; + #ifdef CONFIG_SOFTFLOAT /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point types. @@ -154,6 +164,11 @@ typedef struct float_status { } float_status; void set_float_rounding_mode(int val STATUS_PARAM); +void set_float_exception_flags(int val STATUS_PARAM); +INLINE int get_float_exception_flags(float_status *status) +{ + return STATUS(float_exception_flags); +} #ifdef FLOATX80 void set_floatx80_rounding_precision(int val STATUS_PARAM); #endif @@ -169,6 +184,8 @@ void float_raise( signed char STATUS_PARAM); *----------------------------------------------------------------------------*/ float32 int32_to_float32( int STATUS_PARAM ); float64 int32_to_float64( int STATUS_PARAM ); +float32 uint32_to_float32( unsigned int STATUS_PARAM ); +float64 uint32_to_float64( unsigned int STATUS_PARAM ); #ifdef FLOATX80 floatx80 int32_to_floatx80( int STATUS_PARAM ); #endif @@ -189,6 +206,8 @@ float128 int64_to_float128( int64_t STATUS_PARAM ); *----------------------------------------------------------------------------*/ int float32_to_int32( float32 STATUS_PARAM ); int float32_to_int32_round_to_zero( float32 STATUS_PARAM ); +unsigned int float32_to_uint32( float32 STATUS_PARAM ); +unsigned int float32_to_uint32_round_to_zero( float32 STATUS_PARAM ); int64_t float32_to_int64( float32 STATUS_PARAM ); int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM ); float64 float32_to_float64( float32 STATUS_PARAM ); @@ -215,13 +234,27 @@ char float32_lt( float32, float32 STATUS_PARAM ); char float32_eq_signaling( float32, float32 STATUS_PARAM ); char float32_le_quiet( float32, float32 STATUS_PARAM ); char float32_lt_quiet( float32, float32 STATUS_PARAM ); +char float32_compare( float32, float32 STATUS_PARAM ); +char float32_compare_quiet( float32, float32 STATUS_PARAM ); char float32_is_signaling_nan( float32 ); +INLINE float32 float32_abs(float32 a) +{ + return a & 0x7fffffff; +} + +INLINE float32 float32_chs(float32 a) +{ + return a ^ 0x80000000; +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ int float64_to_int32( float64 STATUS_PARAM ); int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +unsigned int float64_to_uint32( float64 STATUS_PARAM ); +unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); int64_t float64_to_int64( float64 STATUS_PARAM ); int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); float32 float64_to_float32( float64 STATUS_PARAM ); @@ -248,8 +281,20 @@ char float64_lt( float64, float64 STATUS_PARAM ); char float64_eq_signaling( float64, float64 STATUS_PARAM ); char float64_le_quiet( float64, float64 STATUS_PARAM ); char float64_lt_quiet( float64, float64 STATUS_PARAM ); +char float64_compare( float64, float64 STATUS_PARAM ); +char float64_compare_quiet( float64, float64 STATUS_PARAM ); char float64_is_signaling_nan( float64 ); +INLINE float64 float64_abs(float64 a) +{ + return a & 0x7fffffffffffffffLL; +} + +INLINE float64 float64_chs(float64 a) +{ + return a ^ 0x8000000000000000LL; +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -283,6 +328,18 @@ char floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); char floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); char floatx80_is_signaling_nan( floatx80 ); +INLINE floatx80 floatx80_abs(floatx80 a) +{ + a.high &= 0x7fff; + return a; +} + +INLINE floatx80 floatx80_chs(floatx80 a) +{ + a.high ^= 0x8000; + return a; +} + #endif #ifdef FLOAT128 @@ -318,6 +375,18 @@ char float128_le_quiet( float128, float128 STATUS_PARAM ); char float128_lt_quiet( float128, float128 STATUS_PARAM ); char float128_is_signaling_nan( float128 ); +INLINE float128 float128_abs(float128 a) +{ + a.high &= 0x7fffffffffffffffLL; + return a; +} + +INLINE float128 float128_chs(float128 a) +{ + a.high ^= 0x8000000000000000LL; + return a; +} + #endif #else /* CONFIG_SOFTFLOAT */ -- cgit v1.2.3 From b109f9f867a793b66217d43ede10c7a47242e270 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Mar 2005 10:33:58 +0000 Subject: more native FPU comparison functions - native FPU remainder git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1339 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ fpu/softfloat-native.h | 28 +++++++++++++--- 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 8259a7c27..89c0842af 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -120,10 +120,39 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) return rintf(a); } +float32 float32_rem( float32 a, float32 b STATUS_PARAM) +{ + return remainderf(a, b); +} + float32 float32_sqrt( float32 a STATUS_PARAM) { return sqrtf(a); } +char float32_compare( float32 a, float32 b STATUS_PARAM ) +{ + if (a < b) { + return -1; + } else if (a == b) { + return 0; + } else if (a > b) { + return 1; + } else { + return 2; + } +} +char float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return -1; + } else if (a == b) { + return 0; + } else if (isgreater(a, b)) { + return 1; + } else { + return 2; + } +} char float32_is_signaling_nan( float32 a1) { float32u u; @@ -195,10 +224,39 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) #endif } +float64 float64_rem( float64 a, float64 b STATUS_PARAM) +{ + return remainder(a, b); +} + float64 float64_sqrt( float64 a STATUS_PARAM) { return sqrt(a); } +char float64_compare( float64 a, float64 b STATUS_PARAM ) +{ + if (a < b) { + return -1; + } else if (a == b) { + return 0; + } else if (a > b) { + return 1; + } else { + return 2; + } +} +char float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return -1; + } else if (a == b) { + return 0; + } else if (isgreater(a, b)) { + return 1; + } else { + return 2; + } +} char float64_is_signaling_nan( float64 a1) { float64u u; @@ -248,10 +306,38 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM) { return rintl(a); } +floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM) +{ + return remainderl(a, b); +} floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM) { return sqrtl(a); } +char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if (a < b) { + return -1; + } else if (a == b) { + return 0; + } else if (a > b) { + return 1; + } else { + return 2; + } +} +char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if (isless(a, b)) { + return -1; + } else if (a == b) { + return 0; + } else if (isgreater(a, b)) { + return 1; + } else { + return 2; + } +} char floatx80_is_signaling_nan( floatx80 a1) { floatx80u u; diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 709df51bc..9017ea582 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -127,7 +127,6 @@ float32 float32_rem( float32, float32 STATUS_PARAM); float32 float32_sqrt( float32 STATUS_PARAM); INLINE char float32_eq( float32 a, float32 b STATUS_PARAM) { - /* XXX: incorrect because it can raise an exception */ return a == b; } INLINE char float32_le( float32 a, float32 b STATUS_PARAM) @@ -140,7 +139,7 @@ INLINE char float32_lt( float32 a, float32 b STATUS_PARAM) } INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM) { - return a == b; + return a <= b && a >= b; } INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM) { @@ -150,6 +149,13 @@ INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM) { return isless(a, b); } +INLINE char float32_unordered( float32 a, float32 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +char float32_compare( float32, float32 STATUS_PARAM ); +char float32_compare_quiet( float32, float32 STATUS_PARAM ); char float32_is_signaling_nan( float32 ); INLINE float32 float32_abs(float32 a) @@ -213,7 +219,7 @@ INLINE char float64_lt( float64 a, float64 b STATUS_PARAM) } INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM) { - return a == b; + return a <= b && a >= b; } INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM) { @@ -224,6 +230,13 @@ INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM) return isless(a, b); } +INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +char float64_compare( float64, float64 STATUS_PARAM ); +char float64_compare_quiet( float64, float64 STATUS_PARAM ); char float64_is_signaling_nan( float64 ); INLINE float64 float64_abs(float64 a) @@ -287,7 +300,7 @@ INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) } INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) { - return a == b; + return a <= b && a >= b; } INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM) { @@ -298,6 +311,13 @@ INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) return isless(a, b); } +INLINE char floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isunordered(a, b); + +} +char floatx80_compare( floatx80, floatx80 STATUS_PARAM ); +char floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); char floatx80_is_signaling_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) -- cgit v1.2.3 From b7a100da9c90f987d1279fba403bbc856f369196 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Mar 2005 10:34:22 +0000 Subject: removed extern inline (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1340 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/nwfpe/fpa11.inl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-arm/nwfpe/fpa11.inl b/target-arm/nwfpe/fpa11.inl index 1c45cba2d..7183ec96a 100644 --- a/target-arm/nwfpe/fpa11.inl +++ b/target-arm/nwfpe/fpa11.inl @@ -22,13 +22,13 @@ #include "fpa11.h" /* Read and write floating point status register */ -extern __inline__ unsigned int readFPSR(void) +static inline unsigned int readFPSR(void) { FPA11 *fpa11 = GET_FPA11(); return(fpa11->fpsr); } -extern __inline__ void writeFPSR(FPSR reg) +static inline void writeFPSR(FPSR reg) { FPA11 *fpa11 = GET_FPA11(); /* the sysid byte in the status register is readonly */ @@ -36,14 +36,14 @@ extern __inline__ void writeFPSR(FPSR reg) } /* Read and write floating point control register */ -extern __inline__ FPCR readFPCR(void) +static inline FPCR readFPCR(void) { FPA11 *fpa11 = GET_FPA11(); /* clear SB, AB and DA bits before returning FPCR */ return(fpa11->fpcr & ~MASK_RFC); } -extern __inline__ void writeFPCR(FPCR reg) +static inline void writeFPCR(FPCR reg) { FPA11 *fpa11 = GET_FPA11(); fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ -- cgit v1.2.3 From 8422b1133739343c1b35d0bba30c3209649e43e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Mar 2005 10:39:24 +0000 Subject: NaN support in FPU comparisons git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1341 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 6 ++- target-i386/helper.c | 6 --- target-i386/op.c | 94 +++++++++++++++++++++++++++++++++------------- target-i386/ops_sse.h | 102 ++++++++++++++++++++++++++++++++++---------------- 4 files changed, 141 insertions(+), 67 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 137774f5a..e4b6251a2 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -325,6 +325,8 @@ static inline void stfl(target_ulong ptr, float v) #define floatx_abs floatx80_abs #define floatx_chs floatx80_chs #define floatx_round_to_int floatx80_round_to_int +#define floatx_compare floatx80_compare +#define floatx_compare_quiet floatx80_compare_quiet #define sin sinl #define cos cosl #define sqrt sqrtl @@ -340,6 +342,8 @@ static inline void stfl(target_ulong ptr, float v) #define floatx_abs float64_abs #define floatx_chs float64_chs #define floatx_round_to_int float64_round_to_int +#define floatx_compare float64_compare +#define floatx_compare_quiet float64_compare_quiet #endif extern CPU86_LDouble sin(CPU86_LDouble x); @@ -547,8 +551,6 @@ void restore_native_fp_state(CPUState *env); void save_native_fp_state(CPUState *env); float approx_rsqrt(float a); float approx_rcp(float a); -double helper_sqrt(double a); -int fpu_isnan(double a); void update_fp_status(void); extern const uint8_t parity_table[256]; diff --git a/target-i386/helper.c b/target-i386/helper.c index 64cb51ab5..a15ec5a6a 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3223,12 +3223,6 @@ void helper_idivq_EAX_T0(void) #endif -/* XXX: do it */ -int fpu_isnan(double a) -{ - return 0; -} - float approx_rsqrt(float a) { return 1.0 / sqrt(a); diff --git a/target-i386/op.c b/target-i386/op.c index bbc2b19ae..c157b120b 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1952,52 +1952,94 @@ void OPPROTO op_fxchg_ST0_STN(void) /* FPU operations */ -/* XXX: handle nans */ void OPPROTO op_fcom_ST0_FT0(void) { - env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ - if (ST0 < FT0) - env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ - else if (ST0 == FT0) - env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ + int cc; + switch(floatx_compare(ST0, FT0, &env->fp_status)) { + case -1: + cc = 0x0100; + break; + case 0: + cc = 0x4000; + break; + case 1: + cc = 0x0000; + break; + case 2: + default: + cc = 0x4500; + break; + } + env->fpus = (env->fpus & ~0x4500) | cc; FORCE_RET(); } -/* XXX: handle nans */ void OPPROTO op_fucom_ST0_FT0(void) { - env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ - if (ST0 < FT0) - env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ - else if (ST0 == FT0) - env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ + int cc; + switch(floatx_compare_quiet(ST0, FT0, &env->fp_status)) { + case -1: + cc = 0x0100; + break; + case 0: + cc = 0x4000; + break; + case 1: + cc = 0x0000; + break; + case 2: + default: + cc = 0x4500; + break; + } + env->fpus = (env->fpus & ~0x4500) | cc; FORCE_RET(); } -/* XXX: handle nans */ void OPPROTO op_fcomi_ST0_FT0(void) { - int eflags; + int eflags, cc; + switch(floatx_compare(ST0, FT0, &env->fp_status)) { + case -1: + cc = CC_C; + break; + case 0: + cc = CC_Z; + break; + case 1: + cc = 0; + break; + case 2: + default: + cc = CC_Z | CC_P | CC_C; + break; + } eflags = cc_table[CC_OP].compute_all(); - eflags &= ~(CC_Z | CC_P | CC_C); - if (ST0 < FT0) - eflags |= CC_C; - else if (ST0 == FT0) - eflags |= CC_Z; + eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | cc; CC_SRC = eflags; FORCE_RET(); } -/* XXX: handle nans */ void OPPROTO op_fucomi_ST0_FT0(void) { - int eflags; + int eflags, cc; + switch(floatx_compare_quiet(ST0, FT0, &env->fp_status)) { + case -1: + cc = CC_C; + break; + case 0: + cc = CC_Z; + break; + case 1: + cc = 0; + break; + case 2: + default: + cc = CC_Z | CC_P | CC_C; + break; + } eflags = cc_table[CC_OP].compute_all(); - eflags &= ~(CC_Z | CC_P | CC_C); - if (ST0 < FT0) - eflags |= CC_C; - else if (ST0 == FT0) - eflags |= CC_Z; + eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | cc; CC_SRC = eflags; FORCE_RET(); } diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index be1d68bfb..f982594a8 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -704,7 +704,7 @@ SSE_OP_S(sqrt, FPU_SQRT) /* float to float conversions */ void OPPROTO op_cvtps2pd(void) { - float s0, s1; + float32 s0, s1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); @@ -1031,10 +1031,10 @@ void OPPROTO op_ ## name ## ps (void)\ Reg *d, *s;\ d = (Reg *)((char *)env + PARAM1);\ s = (Reg *)((char *)env + PARAM2);\ - d->XMM_L(0) = F(d->XMM_S(0), s->XMM_S(0));\ - d->XMM_L(1) = F(d->XMM_S(1), s->XMM_S(1));\ - d->XMM_L(2) = F(d->XMM_S(2), s->XMM_S(2));\ - d->XMM_L(3) = F(d->XMM_S(3), s->XMM_S(3));\ + d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\ + d->XMM_L(1) = F(32, d->XMM_S(1), s->XMM_S(1));\ + d->XMM_L(2) = F(32, d->XMM_S(2), s->XMM_S(2));\ + d->XMM_L(3) = F(32, d->XMM_S(3), s->XMM_S(3));\ }\ \ void OPPROTO op_ ## name ## ss (void)\ @@ -1042,15 +1042,15 @@ void OPPROTO op_ ## name ## ss (void)\ Reg *d, *s;\ d = (Reg *)((char *)env + PARAM1);\ s = (Reg *)((char *)env + PARAM2);\ - d->XMM_L(0) = F(d->XMM_S(0), s->XMM_S(0));\ + d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\ }\ void OPPROTO op_ ## name ## pd (void)\ {\ Reg *d, *s;\ d = (Reg *)((char *)env + PARAM1);\ s = (Reg *)((char *)env + PARAM2);\ - d->XMM_Q(0) = F(d->XMM_D(0), s->XMM_D(0));\ - d->XMM_Q(1) = F(d->XMM_D(1), s->XMM_D(1));\ + d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ + d->XMM_Q(1) = F(64, d->XMM_D(1), s->XMM_D(1));\ }\ \ void OPPROTO op_ ## name ## sd (void)\ @@ -1058,17 +1058,17 @@ void OPPROTO op_ ## name ## sd (void)\ Reg *d, *s;\ d = (Reg *)((char *)env + PARAM1);\ s = (Reg *)((char *)env + PARAM2);\ - d->XMM_Q(0) = F(d->XMM_D(0), s->XMM_D(0));\ + d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\ } -#define FPU_CMPEQ(a, b) (a) == (b) ? -1 : 0 -#define FPU_CMPLT(a, b) (a) < (b) ? -1 : 0 -#define FPU_CMPLE(a, b) (a) <= (b) ? -1 : 0 -#define FPU_CMPUNORD(a, b) (fpu_isnan(a) || fpu_isnan(b)) ? - 1 : 0 -#define FPU_CMPNEQ(a, b) (a) == (b) ? 0 : -1 -#define FPU_CMPNLT(a, b) (a) < (b) ? 0 : -1 -#define FPU_CMPNLE(a, b) (a) <= (b) ? 0 : -1 -#define FPU_CMPORD(a, b) (!fpu_isnan(a) && !fpu_isnan(b)) ? - 1 : 0 +#define FPU_CMPEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? -1 : 0 +#define FPU_CMPLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0 +#define FPU_CMPLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? -1 : 0 +#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? - 1 : 0 +#define FPU_CMPNEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? 0 : -1 +#define FPU_CMPNLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1 +#define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1 +#define FPU_CMPORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? 0 : -1 SSE_OP_CMP(cmpeq, FPU_CMPEQ) SSE_OP_CMP(cmplt, FPU_CMPLT) @@ -1082,19 +1082,28 @@ SSE_OP_CMP(cmpord, FPU_CMPORD) void OPPROTO op_ucomiss(void) { int eflags; - float s0, s1; + float32 s0, s1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); s0 = d->XMM_S(0); s1 = s->XMM_S(0); - if (s0 < s1) + switch(float32_compare_quiet(s0, s1, &env->sse_status)) { + case -1: eflags = CC_C; - else if (s0 == s1) + break; + case 0: eflags = CC_Z; - else + break; + case 1: eflags = 0; + break; + case 2: + default: + eflags = CC_Z | CC_P | CC_C; + break; + } CC_SRC = eflags; FORCE_RET(); } @@ -1102,19 +1111,28 @@ void OPPROTO op_ucomiss(void) void OPPROTO op_comiss(void) { int eflags; - float s0, s1; + float32 s0, s1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); s0 = d->XMM_S(0); s1 = s->XMM_S(0); - if (s0 < s1) + switch(float32_compare(s0, s1, &env->sse_status)) { + case -1: eflags = CC_C; - else if (s0 == s1) + break; + case 0: eflags = CC_Z; - else + break; + case 1: eflags = 0; + break; + case 2: + default: + eflags = CC_Z | CC_P | CC_C; + break; + } CC_SRC = eflags; FORCE_RET(); } @@ -1122,19 +1140,28 @@ void OPPROTO op_comiss(void) void OPPROTO op_ucomisd(void) { int eflags; - double d0, d1; + float64 d0, d1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); d0 = d->XMM_D(0); d1 = s->XMM_D(0); - if (d0 < d1) + switch(float64_compare_quiet(d0, d1, &env->sse_status)) { + case -1: eflags = CC_C; - else if (d0 == d1) + break; + case 0: eflags = CC_Z; - else + break; + case 1: eflags = 0; + break; + case 2: + default: + eflags = CC_Z | CC_P | CC_C; + break; + } CC_SRC = eflags; FORCE_RET(); } @@ -1142,19 +1169,28 @@ void OPPROTO op_ucomisd(void) void OPPROTO op_comisd(void) { int eflags; - double d0, d1; + float64 d0, d1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); s = (Reg *)((char *)env + PARAM2); d0 = d->XMM_D(0); d1 = s->XMM_D(0); - if (d0 < d1) + switch(float64_compare(d0, d1, &env->sse_status)) { + case -1: eflags = CC_C; - else if (d0 == d1) + break; + case 0: eflags = CC_Z; - else + break; + case 1: eflags = 0; + break; + case 2: + default: + eflags = CC_Z | CC_P | CC_C; + break; + } CC_SRC = eflags; FORCE_RET(); } -- cgit v1.2.3 From 86bd2ca58a99c5dec1372809236640bcc8ede2cd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Mar 2005 10:40:15 +0000 Subject: NaN tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1342 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 182 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 124 insertions(+), 58 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index d4e0c4888..5e6e6c624 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -40,6 +40,7 @@ #define TEST_CMOV 1 #define TEST_FCOMI 1 #else +//#define TEST_SSE #define TEST_CMOV 0 #define TEST_FCOMI 0 #endif @@ -697,6 +698,14 @@ void test_bsx(void) /**********************************************/ +union float64u { + double d; + uint64_t l; +}; + +union float64u q_nan = { .l = 0xFFF8000000000000 }; +union float64u s_nan = { .l = 0xFFF0000000000000 }; + void test_fops(double a, double b) { printf("a=%f b=%f a+b=%f\n", a, b, a + b); @@ -718,28 +727,68 @@ void test_fops(double a, double b) } +void fpu_clear_exceptions(void) +{ + struct __attribute__((packed)) { + uint16_t fpuc; + uint16_t dummy1; + uint16_t fpus; + uint16_t dummy2; + uint16_t fptag; + uint16_t dummy3; + uint32_t ignored[4]; + long double fpregs[8]; + } float_env32; + + asm volatile ("fnstenv %0\n" : : "m" (float_env32)); + float_env32.fpus &= ~0x7f; + asm volatile ("fldenv %0\n" : : "m" (float_env32)); +} + +/* XXX: display exception bits when supported */ +#define FPUS_EMASK 0x0000 +//#define FPUS_EMASK 0x007f + void test_fcmp(double a, double b) { - printf("(%f<%f)=%d\n", - a, b, a < b); - printf("(%f<=%f)=%d\n", - a, b, a <= b); - printf("(%f==%f)=%d\n", - a, b, a == b); - printf("(%f>%f)=%d\n", - a, b, a > b); - printf("(%f<=%f)=%d\n", - a, b, a >= b); + long eflags, fpus; + + fpu_clear_exceptions(); + asm("fcom %2\n" + "fstsw %%ax\n" + : "=a" (fpus) + : "t" (a), "u" (b)); + printf("fcom(%f %f)=%04lx \n", + a, b, fpus & (0x4500 | FPUS_EMASK)); + fpu_clear_exceptions(); + asm("fucom %2\n" + "fstsw %%ax\n" + : "=a" (fpus) + : "t" (a), "u" (b)); + printf("fucom(%f %f)=%04lx\n", + a, b, fpus & (0x4500 | FPUS_EMASK)); if (TEST_FCOMI) { - long eflags; /* test f(u)comi instruction */ - asm("fcomi %2, %1\n" + fpu_clear_exceptions(); + asm("fcomi %3, %2\n" + "fstsw %%ax\n" "pushf\n" "pop %0\n" - : "=r" (eflags) + : "=r" (eflags), "=a" (fpus) : "t" (a), "u" (b)); - printf("fcomi(%f %f)=%08lx\n", a, b, eflags & (CC_Z | CC_P | CC_C)); + printf("fcomi(%f %f)=%04lx %02lx\n", + a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); + fpu_clear_exceptions(); + asm("fucomi %3, %2\n" + "fstsw %%ax\n" + "pushf\n" + "pop %0\n" + : "=r" (eflags), "=a" (fpus) + : "t" (a), "u" (b)); + printf("fucomi(%f %f)=%04lx %02lx\n", + a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); } + fpu_clear_exceptions(); } void test_fcvt(double a) @@ -907,6 +956,8 @@ void test_floats(void) test_fcmp(2, -1); test_fcmp(2, 2); test_fcmp(2, 3); + test_fcmp(2, q_nan.d); + test_fcmp(q_nan.d, -1); test_fcvt(0.5); test_fcvt(-0.5); test_fcvt(1.0/7.0); @@ -2191,6 +2242,7 @@ void test_fxsave(void) void test_sse(void) { XMMReg r, a, b; + int i; MMX_OP2(punpcklbw); MMX_OP2(punpcklwd); @@ -2354,51 +2406,65 @@ void test_sse(void) test_sse_comi(2, -1); test_sse_comi(2, 2); test_sse_comi(2, 3); + test_sse_comi(2, q_nan.d); + test_sse_comi(q_nan.d, -1); + + for(i = 0; i < 2; i++) { + a.s[0] = 2.7; + a.s[1] = 3.4; + a.s[2] = 4; + a.s[3] = -6.3; + b.s[0] = 45.7; + b.s[1] = 353.4; + b.s[2] = 4; + b.s[3] = 56.3; + if (i == 1) { + a.s[0] = q_nan.d; + b.s[3] = q_nan.d; + } + + SSE_OPS(add); + SSE_OPS(mul); + SSE_OPS(sub); + SSE_OPS(min); + SSE_OPS(div); + SSE_OPS(max); + SSE_OPS(sqrt); + SSE_OPS(cmpeq); + SSE_OPS(cmplt); + SSE_OPS(cmple); + SSE_OPS(cmpunord); + SSE_OPS(cmpneq); + SSE_OPS(cmpnlt); + SSE_OPS(cmpnle); + SSE_OPS(cmpord); + + + a.d[0] = 2.7; + a.d[1] = -3.4; + b.d[0] = 45.7; + b.d[1] = -53.4; + if (i == 1) { + a.d[0] = q_nan.d; + b.d[1] = q_nan.d; + } + SSE_OPD(add); + SSE_OPD(mul); + SSE_OPD(sub); + SSE_OPD(min); + SSE_OPD(div); + SSE_OPD(max); + SSE_OPD(sqrt); + SSE_OPD(cmpeq); + SSE_OPD(cmplt); + SSE_OPD(cmple); + SSE_OPD(cmpunord); + SSE_OPD(cmpneq); + SSE_OPD(cmpnlt); + SSE_OPD(cmpnle); + SSE_OPD(cmpord); + } - a.s[0] = 2.7; - a.s[1] = 3.4; - a.s[2] = 4; - a.s[3] = -6.3; - b.s[0] = 45.7; - b.s[1] = 353.4; - b.s[2] = 4; - b.s[3] = 56.3; - SSE_OPS(add); - SSE_OPS(mul); - SSE_OPS(sub); - SSE_OPS(min); - SSE_OPS(div); - SSE_OPS(max); - SSE_OPS(sqrt); - SSE_OPS(cmpeq); - SSE_OPS(cmplt); - SSE_OPS(cmple); - SSE_OPS(cmpunord); - SSE_OPS(cmpneq); - SSE_OPS(cmpnlt); - SSE_OPS(cmpnle); - SSE_OPS(cmpord); - - a.d[0] = 2.7; - a.d[1] = -3.4; - b.d[0] = 45.7; - b.d[1] = -53.4; - SSE_OPD(add); - SSE_OPD(mul); - SSE_OPD(sub); - SSE_OPD(min); - SSE_OPD(div); - SSE_OPD(max); - SSE_OPD(sqrt); - SSE_OPD(cmpeq); - SSE_OPD(cmplt); - SSE_OPD(cmple); - SSE_OPD(cmpunord); - SSE_OPD(cmpneq); - SSE_OPD(cmpnlt); - SSE_OPD(cmpnle); - SSE_OPD(cmpord); - /* float to float/int */ a.s[0] = 2.7; a.s[1] = 3.4; -- cgit v1.2.3 From c3278b7bf0be16b06f51aa82ffbf4807e608e7b1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Mar 2005 12:43:29 +0000 Subject: sparc exception fix (we go up to the shell prompt) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1343 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 1 + target-sparc/helper.c | 2 +- target-sparc/translate.c | 2 ++ translate-all.c | 21 ++++++++++++++++++--- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/exec-all.h b/exec-all.h index 3065858f3..1ecb41c55 100644 --- a/exec-all.h +++ b/exec-all.h @@ -61,6 +61,7 @@ extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +extern target_ulong gen_opc_jump_pc[2]; typedef void (GenOpFunc)(void); typedef void (GenOpFunc1)(long); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index e6891ccbb..82a3a4ec9 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -94,7 +94,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) if (tb) { /* the PC is inside the translated code. It means that we have a virtual CPU fault */ - cpu_restore_state(tb, env, pc, NULL); + cpu_restore_state(tb, env, pc, (void *)T2); } } cpu_loop_exit(); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 9f5c2f5c3..543ed927b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1582,6 +1582,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, page_dump(logfile); } #endif + gen_opc_jump_pc[0] = dc->jump_pc[0]; + gen_opc_jump_pc[1] = dc->jump_pc[1]; } else { tb->size = last_pc + 4 - pc_start; } diff --git a/translate-all.c b/translate-all.c index fd7cc668c..e4f7c9c19 100644 --- a/translate-all.c +++ b/translate-all.c @@ -52,6 +52,7 @@ uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; #elif defined(TARGET_SPARC) target_ulong gen_opc_npc[OPC_BUF_SIZE]; +target_ulong gen_opc_jump_pc[2]; #endif int code_copy_enabled = 1; @@ -244,9 +245,23 @@ int cpu_restore_state(TranslationBlock *tb, #elif defined(TARGET_ARM) env->regs[15] = gen_opc_pc[j]; #elif defined(TARGET_SPARC) - /* XXX: restore npc too */ - env->pc = gen_opc_pc[j]; - env->npc = gen_opc_npc[j]; + { + target_ulong npc; + env->pc = gen_opc_pc[j]; + npc = gen_opc_npc[j]; + if (npc == 1) { + /* dynamic NPC: already stored */ + } else if (npc == 2) { + target_ulong t2 = (target_ulong)puc; + /* jump PC: use T2 and the jump targets of the translation */ + if (t2) + env->npc = gen_opc_jump_pc[0]; + else + env->npc = gen_opc_jump_pc[1]; + } else { + env->npc = npc; + } + } #elif defined(TARGET_PPC) { int type; -- cgit v1.2.3 From 2f275b8f9ff82864d389b5cfff1e3b65a7b78923 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 20:31:50 +0000 Subject: SCSI support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1344 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 224 insertions(+), 18 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 2456c345f..e04539a2a 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -24,7 +24,7 @@ #include "vl.h" /* debug ESP card */ -#define DEBUG_ESP +//#define DEBUG_ESP #ifdef DEBUG_ESP #define DPRINTF(fmt, args...) \ @@ -39,16 +39,178 @@ do { printf("ESP: " fmt , ##args); } while (0) typedef struct ESPState { BlockDriverState **bd; - uint8_t regs[ESP_MAXREG]; + uint8_t rregs[ESP_MAXREG]; + uint8_t wregs[ESP_MAXREG]; int irq; uint32_t espdmaregs[ESPDMA_REGS]; + uint32_t ti_size; + int ti_dir; + uint8_t ti_buf[65536]; } ESPState; +#define STAT_DO 0x00 +#define STAT_DI 0x01 +#define STAT_CD 0x02 +#define STAT_ST 0x03 +#define STAT_MI 0x06 +#define STAT_MO 0x07 + +#define STAT_TC 0x10 +#define STAT_IN 0x80 + +#define INTR_FC 0x08 +#define INTR_BS 0x10 +#define INTR_DC 0x20 + +#define SEQ_0 0x0 +#define SEQ_CD 0x4 + +static void handle_satn(ESPState *s) +{ + uint8_t buf[32]; + uint32_t dmaptr, dmalen; + unsigned int i; + int64_t nb_sectors; + int target; + + dmaptr = iommu_translate(s->espdmaregs[1]); + dmalen = s->wregs[0] | (s->wregs[1] << 8); + DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen); + DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); + cpu_physical_memory_read(dmaptr, buf, dmalen); + for (i = 0; i < dmalen; i++) { + DPRINTF("Command %2.2x\n", buf[i]); + } + s->ti_dir = 0; + s->ti_size = 0; + target = s->wregs[4] & 7; + + if (target > 4 || !s->bd[target]) { // No such drive + s->rregs[4] = STAT_IN; + s->rregs[5] = INTR_DC; + s->rregs[6] = SEQ_0; + s->espdmaregs[0] |= 1; + pic_set_irq(s->irq, 1); + return; + } + switch (buf[1]) { + case 0x0: + DPRINTF("Test Unit Ready (len %d)\n", buf[5]); + break; + case 0x12: + DPRINTF("Inquiry (len %d)\n", buf[5]); + memset(s->ti_buf, 0, 36); + if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { + s->ti_buf[0] = 5; + memcpy(&s->ti_buf[16], "QEMU CDROM ", 16); + } else { + s->ti_buf[0] = 0; + memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16); + } + memcpy(&s->ti_buf[8], "QEMU ", 8); + s->ti_buf[2] = 1; + s->ti_buf[3] = 2; + s->ti_dir = 1; + s->ti_size = 36; + break; + case 0x1a: + DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]); + break; + case 0x25: + DPRINTF("Read Capacity (len %d)\n", buf[5]); + memset(s->ti_buf, 0, 8); + bdrv_get_geometry(s->bd[target], &nb_sectors); + s->ti_buf[0] = (nb_sectors >> 24) & 0xff; + s->ti_buf[1] = (nb_sectors >> 16) & 0xff; + s->ti_buf[2] = (nb_sectors >> 8) & 0xff; + s->ti_buf[3] = nb_sectors & 0xff; + s->ti_buf[4] = 0; + s->ti_buf[5] = 0; + s->ti_buf[6] = 2; + s->ti_buf[7] = 0; + s->ti_dir = 1; + s->ti_size = 8; + break; + case 0x28: + { + int64_t offset, len; + + offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; + len = (buf[8] << 8) | buf[9]; + DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); + bdrv_read(s->bd[target], offset, s->ti_buf, len); + s->ti_dir = 1; + s->ti_size = len * 512; + break; + } + case 0x2a: + { + int64_t offset, len; + + offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; + len = (buf[8] << 8) | buf[9]; + DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); + bdrv_write(s->bd[target], offset, s->ti_buf, len); + s->ti_dir = 0; + s->ti_size = len * 512; + break; + } + default: + DPRINTF("Unknown command (%2.2x)\n", buf[1]); + break; + } + s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; + s->rregs[5] = INTR_BS | INTR_FC; + s->rregs[6] = SEQ_CD; + s->espdmaregs[0] |= 1; + pic_set_irq(s->irq, 1); +} + +static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) +{ + uint32_t dmaptr, dmalen; + + dmaptr = iommu_translate(s->espdmaregs[1]); + dmalen = s->wregs[0] | (s->wregs[1] << 8); + DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); + cpu_physical_memory_write(dmaptr, buf, len); + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; + s->rregs[5] = INTR_BS | INTR_FC; + s->rregs[6] = SEQ_CD; + s->espdmaregs[0] |= 1; + pic_set_irq(s->irq, 1); + +} +static const uint8_t okbuf[] = {0, 0}; + +static void handle_ti(ESPState *s) +{ + uint32_t dmaptr, dmalen; + unsigned int i; + + dmaptr = iommu_translate(s->espdmaregs[1]); + dmalen = s->wregs[0] | (s->wregs[1] << 8); + DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen); + DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); + for (i = 0; i < s->ti_size; i++) { + dmaptr = iommu_translate(s->espdmaregs[1] + i); + if (s->ti_dir) + cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); + else + cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); + } + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; + s->rregs[5] = INTR_BS; + s->rregs[6] = 0; + s->espdmaregs[0] |= 1; + pic_set_irq(s->irq, 1); +} + static void esp_reset(void *opaque) { ESPState *s = opaque; - memset(s->regs, 0, ESP_MAXREG); - s->regs[0x0e] = 0x4; // Indicate fas100a + memset(s->rregs, 0, ESP_MAXREG); + s->rregs[0x0e] = 0x4; // Indicate fas100a memset(s->espdmaregs, 0, ESPDMA_REGS * 4); } @@ -62,8 +224,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) default: break; } - DPRINTF("esp: read reg[%d]: 0x%2.2x\n", saddr, s->regs[saddr]); - return s->regs[saddr]; + DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); + return s->rregs[saddr]; } static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -72,30 +234,51 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) uint32_t saddr; saddr = (addr & ESP_MAXREG) >> 2; - DPRINTF("esp: write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->regs[saddr], val); + DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); switch (saddr) { case 3: // Command switch(val & 0x7f) { case 0: - DPRINTF("esp: NOP (%2.2x)\n", val); + DPRINTF("NOP (%2.2x)\n", val); + break; + case 1: + DPRINTF("Flush FIFO (%2.2x)\n", val); + s->rregs[6] = 0; + s->rregs[5] = INTR_FC; break; case 2: - DPRINTF("esp: Chip reset (%2.2x)\n", val); + DPRINTF("Chip reset (%2.2x)\n", val); esp_reset(s); break; case 3: - DPRINTF("esp: Bus reset (%2.2x)\n", val); + DPRINTF("Bus reset (%2.2x)\n", val); + break; + case 0x10: + handle_ti(s); + break; + case 0x11: + DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); + dma_write(s, okbuf, 2); + break; + case 0x12: + DPRINTF("Message Accepted (%2.2x)\n", val); + dma_write(s, okbuf, 2); + s->rregs[5] = INTR_DC; + s->rregs[6] = 0; break; case 0x1a: - DPRINTF("esp: Set ATN (%2.2x)\n", val); + DPRINTF("Set ATN (%2.2x)\n", val); break; case 0x42: - DPRINTF("esp: Select with ATN (%2.2x)\n", val); - s->regs[4] = 0x1a; // Status: TCNT | TDONE | CMD - s->regs[5] = 0x20; // Intr: Disconnect, nobody there - s->regs[6] = 0x4; // Seq: Cmd done - pic_set_irq(s->irq, 1); + handle_satn(s); + break; + case 0x43: + DPRINTF("Set ATN & stop (%2.2x)\n", val); + handle_satn(s); + break; + default: + DPRINTF("Unhandled command (%2.2x)\n", val); break; } break; @@ -103,9 +286,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) case 9 ... 0xf: break; default: - s->regs[saddr] = val; break; } + s->wregs[saddr] = val; } static CPUReadMemoryFunc *esp_mem_read[3] = { @@ -126,6 +309,7 @@ static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) uint32_t saddr; saddr = (addr & ESPDMA_MAXADDR) >> 2; + DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]); return s->espdmaregs[saddr]; } @@ -135,6 +319,15 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va uint32_t saddr; saddr = (addr & ESPDMA_MAXADDR) >> 2; + DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val); + switch (saddr) { + case 0: + if (!(val & 0x10)) + pic_set_irq(s->irq, 0); + break; + default: + break; + } s->espdmaregs[saddr] = val; } @@ -153,16 +346,29 @@ static CPUWriteMemoryFunc *espdma_mem_write[3] = { static void esp_save(QEMUFile *f, void *opaque) { ESPState *s = opaque; - + unsigned int i; + + qemu_put_buffer(f, s->rregs, ESP_MAXREG); + qemu_put_buffer(f, s->wregs, ESP_MAXREG); + qemu_put_be32s(f, &s->irq); + for (i = 0; i < ESPDMA_REGS; i++) + qemu_put_be32s(f, &s->espdmaregs[i]); } static int esp_load(QEMUFile *f, void *opaque, int version_id) { ESPState *s = opaque; + unsigned int i; if (version_id != 1) return -EINVAL; + qemu_get_buffer(f, s->rregs, ESP_MAXREG); + qemu_get_buffer(f, s->wregs, ESP_MAXREG); + qemu_get_be32s(f, &s->irq); + for (i = 0; i < ESPDMA_REGS; i++) + qemu_get_be32s(f, &s->espdmaregs[i]); + return 0; } -- cgit v1.2.3 From d827220bbf2b4d56af6161753e9f88db400f6b63 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 20:32:23 +0000 Subject: use standard TCX display size for sparc git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1345 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 9f8b8a6b9..46a36adf5 100644 --- a/vl.c +++ b/vl.c @@ -1,7 +1,7 @@ /* * QEMU System Emulator * - * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -135,8 +135,13 @@ int pci_enabled = 1; int prep_enabled = 0; int rtc_utc = 1; int cirrus_vga_enabled = 1; +#ifdef TARGET_SPARC +int graphic_width = 1024; +int graphic_height = 768; +#else int graphic_width = 800; int graphic_height = 600; +#endif int graphic_depth = 15; int full_screen = 0; TextConsole *vga_console; -- cgit v1.2.3 From 8be1f5c889fa39571f9dad766497b7bdd56e9d6d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 20:42:35 +0000 Subject: keyboard support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1346 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 166 insertions(+), 25 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 3dfac0af5..4b02d29f6 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -1,7 +1,7 @@ /* * QEMU Sparc SLAVIO serial port emulation * - * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,13 +22,13 @@ * THE SOFTWARE. */ #include "vl.h" - +/* debug serial */ //#define DEBUG_SERIAL /* debug keyboard */ //#define DEBUG_KBD -/* debug keyboard : only mouse */ +/* debug mouse */ //#define DEBUG_MOUSE /* @@ -42,11 +42,49 @@ * */ +#ifdef DEBUG_SERIAL +#define SER_DPRINTF(fmt, args...) \ +do { printf("SER: " fmt , ##args); } while (0) +#else +#define SER_DPRINTF(fmt, args...) +#endif +#ifdef DEBUG_KBD +#define KBD_DPRINTF(fmt, args...) \ +do { printf("KBD: " fmt , ##args); } while (0) +#else +#define KBD_DPRINTF(fmt, args...) +#endif +#ifdef DEBUG_MOUSE +#define MS_DPRINTF(fmt, args...) \ +do { printf("SER: " fmt , ##args); } while (0) +#else +#define MS_DPRINTF(fmt, args...) +#endif + +typedef enum { + chn_a, chn_b, +} chn_id_t; + +typedef enum { + ser, kbd, mouse, +} chn_type_t; + +#define KBD_QUEUE_SIZE 256 + +typedef struct { + uint8_t data[KBD_QUEUE_SIZE]; + int rptr, wptr, count; +} KBDQueue; + typedef struct ChannelState { int irq; int reg; int rxint, txint; + chn_id_t chn; // this channel, A (base+4) or B (base+0) + chn_type_t type; + struct ChannelState *otherchn; uint8_t rx, tx, wregs[16], rregs[16]; + KBDQueue queue; CharDriverState *chr; } ChannelState; @@ -56,6 +94,45 @@ struct SerialState { #define SERIAL_MAXADDR 7 +static void handle_kbd_command(ChannelState *s, int val); +static int serial_can_receive(void *opaque); +static void serial_receive_byte(ChannelState *s, int ch); + +static void put_queue(void *opaque, int b) +{ + ChannelState *s = opaque; + KBDQueue *q = &s->queue; + + KBD_DPRINTF("put: 0x%02x\n", b); + if (q->count >= KBD_QUEUE_SIZE) + return; + q->data[q->wptr] = b; + if (++q->wptr == KBD_QUEUE_SIZE) + q->wptr = 0; + q->count++; + serial_receive_byte(s, 0); +} + +static uint32_t get_queue(void *opaque) +{ + ChannelState *s = opaque; + KBDQueue *q = &s->queue; + int val; + + if (q->count == 0) { + return 0; + } else { + val = q->data[q->rptr]; + if (++q->rptr == KBD_QUEUE_SIZE) + q->rptr = 0; + q->count--; + } + KBD_DPRINTF("get 0x%02x\n", val); + if (q->count > 0) + serial_receive_byte(s, 0); + return val; +} + static void slavio_serial_update_irq(ChannelState *s) { if ((s->wregs[1] & 1) && // interrupts enabled @@ -110,6 +187,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint s = &ser->chn[channel]; switch (saddr) { case 0: + SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff); newreg = 0; switch (s->reg) { case 0: @@ -158,11 +236,23 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint s->reg = 0; break; case 1: + SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val); if (s->wregs[5] & 8) { // tx enabled s->tx = val; if (s->chr) qemu_chr_write(s->chr, &s->tx, 1); + else if (s->type == kbd) { + handle_kbd_command(s, val); + } s->txint = 1; + s->rregs[0] |= 4; + // Interrupts reported only on channel A + if (s->chn == 0) + s->rregs[3] |= 0x10; + else { + s->otherchn->rregs[3] |= 2; + } + slavio_serial_update_irq(s); } break; default: @@ -183,12 +273,18 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) s = &ser->chn[channel]; switch (saddr) { case 0: + SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]); ret = s->rregs[s->reg]; s->reg = 0; return ret; case 1: + SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', s->rx); s->rregs[0] &= ~1; - return s->rx; + if (s->type == kbd) + ret = get_queue(s); + else + ret = s->rx; + return ret; default: break; } @@ -208,6 +304,12 @@ static int serial_can_receive(void *opaque) static void serial_receive_byte(ChannelState *s, int ch) { s->rregs[0] |= 1; + // Interrupts reported only on channel A + if (s->chn == 0) + s->rregs[3] |= 0x20; + else { + s->otherchn->rregs[3] |= 4; + } s->rx = ch; s->rxint = 1; slavio_serial_update_irq(s); @@ -295,39 +397,73 @@ static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2) { - int slavio_serial_io_memory; + int slavio_serial_io_memory, i; SerialState *s; s = qemu_mallocz(sizeof(SerialState)); if (!s) return NULL; - s->chn[0].irq = irq; - s->chn[1].irq = irq; - s->chn[0].chr = chr1; - s->chn[1].chr = chr2; slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); - if (chr1) { - qemu_chr_add_read_handler(chr1, serial_can_receive, serial_receive1, &s->chn[0]); - qemu_chr_add_event_handler(chr1, serial_event); - } - if (chr2) { - qemu_chr_add_read_handler(chr2, serial_can_receive, serial_receive1, &s->chn[1]); - qemu_chr_add_event_handler(chr2, serial_event); + s->chn[0].chr = chr1; + s->chn[1].chr = chr2; + + for (i = 0; i < 2; i++) { + s->chn[i].irq = irq; + s->chn[i].chn = 1 - i; + s->chn[i].type = ser; + if (s->chn[i].chr) { + qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]); + qemu_chr_add_event_handler(s->chn[i].chr, serial_event); + } } + s->chn[0].otherchn = &s->chn[1]; + s->chn[1].otherchn = &s->chn[0]; register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s); qemu_register_reset(slavio_serial_reset, s); slavio_serial_reset(s); return s; } +static const uint8_t keycodes[128] = { + 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12, + 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112, + 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0, + 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66, + 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67, +}; + static void sunkbd_event(void *opaque, int ch) { ChannelState *s = opaque; - // XXX: PC -> Sun Type 5 translation? - serial_receive_byte(s, ch); + int release = ch & 0x80; + + ch = keycodes[ch & 0x7f]; + KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press"); + put_queue(s, ch | release); +} + +static void handle_kbd_command(ChannelState *s, int val) +{ + KBD_DPRINTF("Command %d\n", val); + switch (val) { + case 1: // Reset, return type code + put_queue(s, 0xff); + put_queue(s, 0xff); + put_queue(s, 5); // Type 5 + break; + case 7: // Query layout + put_queue(s, 0xfe); + put_queue(s, 0x20); // XXX, layout? + break; + default: + break; + } } static void sunmouse_event(void *opaque, @@ -343,22 +479,27 @@ static void sunmouse_event(void *opaque, void slavio_serial_ms_kbd_init(int base, int irq) { - int slavio_serial_io_memory; + int slavio_serial_io_memory, i; SerialState *s; s = qemu_mallocz(sizeof(SerialState)); if (!s) return; - s->chn[0].irq = irq; - s->chn[1].irq = irq; - s->chn[0].chr = NULL; - s->chn[1].chr = NULL; + for (i = 0; i < 2; i++) { + s->chn[i].irq = irq; + s->chn[i].chn = 1 - i; + s->chn[i].chr = NULL; + } + s->chn[0].otherchn = &s->chn[1]; + s->chn[1].otherchn = &s->chn[0]; + s->chn[0].type = mouse; + s->chn[1].type = kbd; slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); - qemu_add_kbd_event_handler(sunkbd_event, &s->chn[0]); - qemu_add_mouse_event_handler(sunmouse_event, &s->chn[1]); + qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0]); + qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); qemu_register_reset(slavio_serial_reset, s); slavio_serial_reset(s); } -- cgit v1.2.3 From b81b3b10aa6fa9f0be8162b3403e321e4768b977 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 20:43:37 +0000 Subject: swap serial ports (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1347 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index b186b23f1..b911ba234 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -1,7 +1,7 @@ /* * QEMU Sun4m System Emulator * - * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -225,7 +225,9 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); - slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]); + // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device + // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device + slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA); -- cgit v1.2.3 From ed91024191c04f4adc6e1493f780b21332ab983e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 20:44:48 +0000 Subject: defaut case (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1348 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 40ab90156..143cc1644 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -255,6 +255,7 @@ void helper_ldfsr(void) case FSR_RD_NEAREST: rnd_mode = float_round_nearest_even; break; + default: case FSR_RD_ZERO: rnd_mode = float_round_to_zero; break; -- cgit v1.2.3 From c44644bb966bd0cf7e09d94b043814ea0740fe8f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 20:45:26 +0000 Subject: update (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1349 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/proll.elf | Bin 41236 -> 137898 bytes pc-bios/proll.patch | 201 ++++++++++++++++++++++++++++------------------------ 2 files changed, 110 insertions(+), 91 deletions(-) diff --git a/pc-bios/proll.elf b/pc-bios/proll.elf index f960c83e6..ac93c4be9 100644 Binary files a/pc-bios/proll.elf and b/pc-bios/proll.elf differ diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch index 5f2e027d4..e72e0e45e 100644 --- a/pc-bios/proll.patch +++ b/pc-bios/proll.patch @@ -1,6 +1,6 @@ -diff -ruN proll_18.orig/Makefile proll-patch7/Makefile +diff -ruN proll_18.orig/Makefile proll-patch8/Makefile --- proll_18.orig/Makefile 2002-09-13 14:16:59.000000000 +0000 -+++ proll-patch7/Makefile 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/Makefile 2004-11-13 15:50:49.000000000 +0000 @@ -4,6 +4,7 @@ make -C krups-ser all make -C espresso all @@ -14,14 +14,14 @@ diff -ruN proll_18.orig/Makefile proll-patch7/Makefile make -C espresso clean make -C espresso-ser clean + make -C qemu clean -diff -ruN proll_18.orig/qemu/Makefile proll-patch7/qemu/Makefile +diff -ruN proll_18.orig/qemu/Makefile proll-patch8/qemu/Makefile --- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch7/qemu/Makefile 2005-03-02 16:41:50.000000000 +0000 ++++ proll-patch8/qemu/Makefile 2005-03-02 16:41:50.000000000 +0000 @@ -0,0 +1,122 @@ +# +# proll: +# qemu/Makefile - make PROLL for QEMU -+# $Id: proll.patch,v 1.3 2005-03-13 09:43:36 bellard Exp $ ++# $Id: proll.patch,v 1.4 2005-04-06 20:45:26 bellard Exp $ +# +# Copyright 1999 Pete Zaitcev +# This is Free Software is licensed under terms of GNU General Public License. @@ -140,9 +140,9 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch7/qemu/Makefile + +proll.aout: $(PROLLEXE) + $(ELFTOAOUT) -o proll.aout $(PROLLEXE) -diff -ruN proll_18.orig/qemu/head.S proll-patch7/qemu/head.S +diff -ruN proll_18.orig/qemu/head.S proll-patch8/qemu/head.S --- proll_18.orig/qemu/head.S 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch7/qemu/head.S 2005-03-02 15:30:47.000000000 +0000 ++++ proll-patch8/qemu/head.S 2005-03-02 15:30:47.000000000 +0000 @@ -0,0 +1,539 @@ +/** + ** Standalone startup code for Linux PROM emulator. @@ -150,7 +150,7 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch7/qemu/head.S + ** This code is licensed under GNU General Public License. + **/ +/* -+ * $Id: proll.patch,v 1.3 2005-03-13 09:43:36 bellard Exp $ ++ * $Id: proll.patch,v 1.4 2005-04-06 20:45:26 bellard Exp $ + */ + +#include @@ -683,9 +683,9 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch7/qemu/head.S +C_LABEL(ldb_bypass): + retl + lduba [%o0] ASI_M_BYPASS, %o0 -diff -ruN proll_18.orig/qemu/main.c proll-patch7/qemu/main.c +diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c --- proll_18.orig/qemu/main.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch7/qemu/main.c 2005-03-02 20:08:23.000000000 +0000 ++++ proll-patch8/qemu/main.c 2005-04-03 11:58:46.000000000 +0000 @@ -0,0 +1,173 @@ +/** + ** Proll (PROM replacement) @@ -755,7 +755,7 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch7/qemu/main.c + printk_fn = vcon_write; + } + else { -+ vcon_zs_init(&dp0, 0x71100000); ++ vcon_zs_init(&dp0, 0x71100004); + printk_fn = vcon_zs_write; + } + @@ -860,10 +860,10 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch7/qemu/main.c + hw_idprom = va_prom; +} + -diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c +diff -ruN proll_18.orig/qemu/openprom.c proll-patch8/qemu/openprom.c --- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch7/qemu/openprom.c 2005-03-02 20:09:57.000000000 +0000 -@@ -0,0 +1,646 @@ ++++ proll-patch8/qemu/openprom.c 2005-04-06 16:53:31.000000000 +0000 +@@ -0,0 +1,665 @@ +/* + * PROM interface support + * Copyright 1996 The Australian National University. @@ -1082,27 +1082,27 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c + {NULL, NULL, -1} +}; + -+static const int prop_zs_intr[] = { 12, 0x0 }; ++static const int prop_zs_intr[] = { 0x2c, 0x0 }; +static const int prop_zs_reg[] = { + 0x0, 0x00000000, 0x00000008, +}; -+static const int prop_zs_addr = { 0x70000000 }; +static const int prop_zs_slave[] = { 1 }; ++static void *prop_zs_addr; +static const struct property propv_obio_zs[] = { + {"name", "zs", sizeof("zs")}, + {"reg", (char*)&prop_zs_reg[0], sizeof(prop_zs_reg) }, + {"slave", (char*)&prop_zs_slave[0], sizeof(prop_zs_slave) }, + {"device_type", "serial", sizeof("serial") }, + {"intr", (char*)&prop_zs_intr[0], sizeof(prop_zs_intr) }, -+ // {"address", (char*)&prop_zs_addr, sizeof(prop_zs_addr) }, ++ {"address", (char*)&prop_zs_addr, sizeof(prop_zs_addr) }, + {NULL, NULL, -1} +}; + -+static const int prop_zs1_intr[] = { 12, 0x0 }; ++static const int prop_zs1_intr[] = { 0x2c, 0x0 }; +static const int prop_zs1_reg[] = { + 0x0, 0x00100000, 0x00000008, +}; -+static const int prop_zs1_addr = { 0x70100000 }; ++static void *prop_zs1_addr; +static const int prop_zs1_slave[] = { 0 }; +static const struct property propv_obio_zs1[] = { + {"name", "zs", sizeof("zs")}, @@ -1110,7 +1110,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c + {"slave", (char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) }, + {"device_type", "serial", sizeof("serial") }, + {"intr", (char*)&prop_zs1_intr[0], sizeof(prop_zs1_intr) }, -+ // {"address", (char*)&prop_zs1_addr, sizeof(prop_zs1_addr) }, ++ {"address", (char*)&prop_zs1_addr, sizeof(prop_zs1_addr) }, + {NULL, NULL, -1} +}; + @@ -1141,9 +1141,9 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c +static const int prop_espdma_reg[] = { + 0x4, 0x08400000, 0x00000010, +}; -+// Disabled, not implemented yet ++ +static const struct property propv_sbus_espdma[] = { -+ {"name", "xxxespdma", sizeof("xxxespdma")}, ++ {"name", "espdma", sizeof("espdma")}, + {"reg", (char*)&prop_espdma_reg[0], sizeof(prop_espdma_reg) }, + {NULL, NULL, -1} +}; @@ -1202,6 +1202,20 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c + {NULL, NULL, -1} +}; + ++static const struct property propv_options[] = { ++ {"name", "options", sizeof("options")}, ++ {"screen-#columns", "80", sizeof("80")}, ++ {"screen-#rows", "25", sizeof("25")}, ++ {"tpe-link-test?", "true", sizeof("true")}, ++ {"ttya-mode", "9600,8,n,1,-", sizeof("9600,8,n,1,-")}, ++ {"ttya-ignore-cd", "true", sizeof("true")}, ++ {"ttya-rts-dtr-off", "false", sizeof("false")}, ++ {"ttyb-mode", "9600,8,n,1,-", sizeof("9600,8,n,1,-")}, ++ {"ttyb-ignore-cd", "true", sizeof("true")}, ++ {"ttyb-rts-dtr-off", "false", sizeof("false")}, ++ {NULL, NULL, -1} ++}; ++ +static const struct node nodes[] = { + { &null_properties, 1, 0 }, /* 0 = big brother of root */ + { propv_root, 0, 2 }, /* 1 "/" */ @@ -1215,33 +1229,18 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c + { propv_sbus_espdma, 0, 10 }, /* 9 "/iommu/sbus/espdma" */ + { propv_sbus_espdma_esp, 0, 0 }, /* 10 "/iommu/sbus/espdma/esp" */ + { propv_cpu, 12, 0 }, /* 11 "/STP1012PGA" */ -+ { propv_obio, 0, 13 }, /* 12 "/obio" */ ++ { propv_obio, 22, 13 }, /* 12 "/obio" */ + { propv_obio_int, 14, 0 }, /* 13 "/obio/interrupt" */ + { propv_obio_cnt, 15, 0 }, /* 14 "/obio/counter" */ + { propv_obio_eep, 16, 0 }, /* 15 "/obio/eeprom" */ + { propv_obio_auxio, 17, 0 }, /* 16 "/obio/auxio" */ -+ { propv_obio_zs, 18, 0 }, /* 17 "/obio/zs@0,0" */ -+ { propv_obio_zs1, 19, 0 }, /* 18 "/obio/zs@0,100000" */ ++ { propv_obio_zs1, 18, 0 }, /* 17 "/obio/zs@0,100000" ++ Must be before zs@0,0! */ ++ { propv_obio_zs, 19, 0 }, /* 18 "/obio/zs@0,0" */ + { propv_obio_fd, 20, 0 }, /* 19 "/obio/SUNW,fdtwo" */ + { propv_obio_pw, 21, 0 }, /* 20 "/obio/power" */ + { propv_obio_cf, 0, 0 }, /* 21 "/obio/slavioconfig@0,800000" */ -+#if 0 -+ { propv_obio_su, 14, 0 }, /* 13 "/obio/su" */ -+ { propv_cpu, 18, 0 }, /* 17 "/STP1012PGA" */ -+ { propv_cpu, 19, 0 }, /* 18 "/STP1012PGA" */ -+ -+ { propv_cpu, 20, 0 }, /* 19 "/STP1012PGA" */ -+ { propv_cpu, 21, 0 }, /* 20 "/STP1012PGA" */ -+ { propv_cpu, 22, 0 }, /* 21 "/STP1012PGA" */ -+ { propv_cpu, 23, 0 }, /* 22 "/STP1012PGA" */ -+ { propv_cpu, 24, 0 }, /* 23 "/STP1012PGA" */ -+ { propv_cpu, 25, 0 }, /* 24 "/STP1012PGA" */ -+ { propv_cpu, 26, 0 }, /* 25 "/STP1012PGA" */ -+ { propv_cpu, 27, 0 }, /* 26 "/STP1012PGA" */ -+ { propv_cpu, 28, 0 }, /* 27 "/STP1012PGA" */ -+ { propv_cpu, 29, 0 }, /* 28 "/STP1012PGA" */ -+ { propv_cpu, 30, 0 }, /* 29 "/STP1012PGA" */ -+#endif ++ { propv_options, 0, 0 }, /* 22 "/options" */ +}; + +static struct linux_mlist_v0 totphys[MAX_BANKS]; @@ -1379,6 +1378,8 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c + obp_stdin = PROMDEV_KBD; + obp_stdout = PROMDEV_SCREEN; + } ++ prop_zs_addr = map_io(0x71000000, 8); ++ prop_zs1_addr = map_io(0x71100000, 8); + return &romvec0; +} + @@ -1427,6 +1428,14 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c +{ + const struct property *prop; + ++ if (!name) { ++ // NULL name means get first property ++#ifdef DEBUG_OBP ++ printk("obp_getprop(%d, %x (NULL)) = %s\n", node, name, ++ nodes[node].properties[0].name); ++#endif ++ return (int)nodes[node].properties[0].name; ++ } + prop = find_property(node,name); + if (prop) { + memcpy(value,prop->value,prop->length); @@ -1451,8 +1460,18 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c + +static const char *obp_nextprop(int node,char *name) +{ -+ const struct property *prop = find_property(node,name); -+ if (prop) { ++ const struct property *prop; ++ ++ if (!name || *name == '\0') { ++ // NULL name means get first property ++#ifdef DEBUG_OBP ++ printk("obp_nextprop(%d, NULL) = %s\n", node, ++ nodes[node].properties[0].name); ++#endif ++ return nodes[node].properties[0].name; ++ } ++ prop = find_property(node,name); ++ if (prop && prop[1].name) { +#ifdef DEBUG_OBP + printk("obp_nextprop(%d, %s) = %s\n", node, name, prop[1].name); +#endif @@ -1461,7 +1480,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c +#ifdef DEBUG_OBP + printk("obp_nextprop(%d, %s): not found\n", node, name); +#endif -+ return NULL; ++ return (const char *)-1; +} + +static int obp_nbgetchar(void) { @@ -1510,9 +1529,9 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch7/qemu/openprom.c + //buf[8] = 'L'; + return num_blks; +} -diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch7/qemu/system_qemu.c +diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch8/qemu/system_qemu.c --- proll_18.orig/qemu/system_qemu.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch7/qemu/system_qemu.c 2005-03-02 16:10:20.000000000 +0000 ++++ proll-patch8/qemu/system_qemu.c 2005-03-02 16:10:20.000000000 +0000 @@ -0,0 +1,416 @@ +/** + ** Proll (PROM replacement) @@ -1930,9 +1949,9 @@ diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch7/qemu/system_qemu.c + n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); + st_bypass(ptr, n); +}; -diff -ruN proll_18.orig/src/arp.c proll-patch7/src/arp.c +diff -ruN proll_18.orig/src/arp.c proll-patch8/src/arp.c --- proll_18.orig/src/arp.c 2001-12-24 05:12:31.000000000 +0000 -+++ proll-patch7/src/arp.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/arp.c 2004-11-13 15:50:49.000000000 +0000 @@ -45,7 +45,7 @@ #endif static struct arp_cache arp_list[ARPNUM]; /* ARP address cache */ @@ -1967,9 +1986,9 @@ diff -ruN proll_18.orig/src/arp.c proll-patch7/src/arp.c + def_gw = IP_ANY; return(TRUE); } -diff -ruN proll_18.orig/src/arp.h proll-patch7/src/arp.h +diff -ruN proll_18.orig/src/arp.h proll-patch8/src/arp.h --- proll_18.orig/src/arp.h 1999-03-18 03:39:43.000000000 +0000 -+++ proll-patch7/src/arp.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/arp.h 2004-11-13 15:50:49.000000000 +0000 @@ -104,7 +104,7 @@ extern int init_arp __P((void)); @@ -1979,9 +1998,9 @@ diff -ruN proll_18.orig/src/arp.h proll-patch7/src/arp.h /* Add a new antry to the ARP cache */ extern void addcache __P((unsigned char *ha, t_ipaddr ip)); -diff -ruN proll_18.orig/src/hconsole.c proll-patch7/src/hconsole.c +diff -ruN proll_18.orig/src/hconsole.c proll-patch8/src/hconsole.c --- proll_18.orig/src/hconsole.c 2002-07-23 05:52:48.000000000 +0000 -+++ proll-patch7/src/hconsole.c 2005-03-02 17:03:09.000000000 +0000 ++++ proll-patch8/src/hconsole.c 2005-03-02 17:03:09.000000000 +0000 @@ -29,6 +29,10 @@ struct raster r_master; /* For a case of resize, whole fb */ struct raster r_0; /* malloc() erzatz */ @@ -2005,9 +2024,9 @@ diff -ruN proll_18.orig/src/hconsole.c proll-patch7/src/hconsole.c t->r_ = r; t->r0_ = q; t->f_ = &f_master; -diff -ruN proll_18.orig/src/lat7_2.bm proll-patch7/src/lat7_2.bm +diff -ruN proll_18.orig/src/lat7_2.bm proll-patch8/src/lat7_2.bm --- proll_18.orig/src/lat7_2.bm 1999-02-27 05:48:54.000000000 +0000 -+++ proll-patch7/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 @@ -1,6 +1,6 @@ #define lat7_2_width 128 #define lat7_2_height 88 @@ -2016,9 +2035,9 @@ diff -ruN proll_18.orig/src/lat7_2.bm proll-patch7/src/lat7_2.bm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18, 0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02, -diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch7/src/lat7_2_swapped.bm +diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch8/src/lat7_2_swapped.bm --- proll_18.orig/src/lat7_2_swapped.bm 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch7/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 @@ -0,0 +1,121 @@ +#define lat7_2_width 128 +#define lat7_2_height 88 @@ -2141,9 +2160,9 @@ diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch7/src/lat7_2_swapped.bm + 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; -diff -ruN proll_18.orig/src/le.c proll-patch7/src/le.c +diff -ruN proll_18.orig/src/le.c proll-patch8/src/le.c --- proll_18.orig/src/le.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch7/src/le.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/le.c 2004-11-13 15:50:49.000000000 +0000 @@ -185,8 +185,6 @@ unsigned short rap; /* register address port */ }; @@ -2153,9 +2172,9 @@ diff -ruN proll_18.orig/src/le.c proll-patch7/src/le.c /* The Lance uses 24 bit addresses */ /* On the Sun4c the DVMA will provide the remaining bytes for us */ /* On the Sun4m we have to instruct the ledma to provide them */ -diff -ruN proll_18.orig/src/netinit.c proll-patch7/src/netinit.c +diff -ruN proll_18.orig/src/netinit.c proll-patch8/src/netinit.c --- proll_18.orig/src/netinit.c 2002-09-13 21:53:33.000000000 +0000 -+++ proll-patch7/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 @@ -49,13 +49,20 @@ unsigned char myhwaddr[ETH_ALEN]; /* my own hardware addr */ t_ipaddr myipaddr; /* my own IP address */ @@ -2199,9 +2218,9 @@ diff -ruN proll_18.orig/src/netinit.c proll-patch7/src/netinit.c fatal(); } } -diff -ruN proll_18.orig/src/netpriv.h proll-patch7/src/netpriv.h +diff -ruN proll_18.orig/src/netpriv.h proll-patch8/src/netpriv.h --- proll_18.orig/src/netpriv.h 1999-04-27 05:39:37.000000000 +0000 -+++ proll-patch7/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 @@ -130,10 +130,9 @@ * */ @@ -2223,9 +2242,9 @@ diff -ruN proll_18.orig/src/netpriv.h proll-patch7/src/netpriv.h /* Empty read buffer */ extern void empty_buf __P((void)); -diff -ruN proll_18.orig/src/openprom.h proll-patch7/src/openprom.h +diff -ruN proll_18.orig/src/openprom.h proll-patch8/src/openprom.h --- proll_18.orig/src/openprom.h 2002-07-14 02:26:30.000000000 +0000 -+++ proll-patch7/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 @@ -54,20 +54,20 @@ }; @@ -2287,9 +2306,9 @@ diff -ruN proll_18.orig/src/openprom.h proll-patch7/src/openprom.h }; /* More fun PROM structures for device probing. */ -diff -ruN proll_18.orig/src/packet.c proll-patch7/src/packet.c +diff -ruN proll_18.orig/src/packet.c proll-patch8/src/packet.c --- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000 -+++ proll-patch7/src/packet.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/packet.c 2004-11-13 15:50:49.000000000 +0000 @@ -41,7 +41,7 @@ int aligner; } wbuf; @@ -2317,9 +2336,9 @@ diff -ruN proll_18.orig/src/packet.c proll-patch7/src/packet.c { struct sk_buff *skb; unsigned char *s; -diff -ruN proll_18.orig/src/printf.c proll-patch7/src/printf.c +diff -ruN proll_18.orig/src/printf.c proll-patch8/src/printf.c --- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000 -+++ proll-patch7/src/printf.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/printf.c 2004-11-13 15:50:49.000000000 +0000 @@ -19,7 +19,7 @@ static void printn(struct prf_fp *, unsigned long, unsigned int); static void putchar(char, struct prf_fp *); @@ -2347,9 +2366,9 @@ diff -ruN proll_18.orig/src/printf.c proll-patch7/src/printf.c putchar(c,filog); } else if (c == 'l' || c == 'O') { printn(filog, (long)va_arg(adx,long), c=='l'?10:8); -diff -ruN proll_18.orig/src/rconsole.c proll-patch7/src/rconsole.c +diff -ruN proll_18.orig/src/rconsole.c proll-patch8/src/rconsole.c --- proll_18.orig/src/rconsole.c 1999-01-16 07:16:55.000000000 +0000 -+++ proll-patch7/src/rconsole.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/rconsole.c 2004-11-13 15:50:49.000000000 +0000 @@ -28,12 +28,18 @@ * move to California. Only plain lat7 survived. * I recreated lat7-1 changes in lat7-2. --zaitcev @@ -2404,9 +2423,9 @@ diff -ruN proll_18.orig/src/rconsole.c proll-patch7/src/rconsole.c p->nchars_ = LAT7_NCHARS; p->width_ = LAT7_WIDTH; p->height_ = LAT7_HEIGHT; -diff -ruN proll_18.orig/src/rconsole.h proll-patch7/src/rconsole.h +diff -ruN proll_18.orig/src/rconsole.h proll-patch8/src/rconsole.h --- proll_18.orig/src/rconsole.h 1999-01-16 05:00:59.000000000 +0000 -+++ proll-patch7/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 @@ -13,10 +13,10 @@ */ @@ -2420,9 +2439,9 @@ diff -ruN proll_18.orig/src/rconsole.h proll-patch7/src/rconsole.h int nchars_; /* 128 for ASCII ... 65536 for Unicode */ int width_; /* [Pixels]. Maximum size is 16. */ int height_; /* [Pixels == scan lines]. */ -diff -ruN proll_18.orig/src/romlib.h proll-patch7/src/romlib.h +diff -ruN proll_18.orig/src/romlib.h proll-patch8/src/romlib.h --- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000 -+++ proll-patch7/src/romlib.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/romlib.h 2004-11-13 15:50:49.000000000 +0000 @@ -73,12 +73,12 @@ #define memcpy(dst, src, len) bcopy(src, dst, len) #define memcmp(x1, x2, len) bcmp(x1, x2, len) @@ -2439,9 +2458,9 @@ diff -ruN proll_18.orig/src/romlib.h proll-patch7/src/romlib.h /* -diff -ruN proll_18.orig/src/sched_4m.c proll-patch7/src/sched_4m.c +diff -ruN proll_18.orig/src/sched_4m.c proll-patch8/src/sched_4m.c --- proll_18.orig/src/sched_4m.c 1999-04-27 05:48:51.000000000 +0000 -+++ proll-patch7/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 @@ -108,7 +108,7 @@ static int set_bolt; /* Tick counter limit */ static struct handsc hndv[16]; @@ -2451,9 +2470,9 @@ diff -ruN proll_18.orig/src/sched_4m.c proll-patch7/src/sched_4m.c 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -diff -ruN proll_18.orig/src/swap.c proll-patch7/src/swap.c +diff -ruN proll_18.orig/src/swap.c proll-patch8/src/swap.c --- proll_18.orig/src/swap.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch7/src/swap.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/swap.c 2004-11-13 15:50:49.000000000 +0000 @@ -0,0 +1,21 @@ +// Convert the lat7 font so that no conversion is needed at runtime. +#define ORIG @@ -2476,9 +2495,9 @@ diff -ruN proll_18.orig/src/swap.c proll-patch7/src/swap.c + } + printf("\n"); +} -diff -ruN proll_18.orig/src/system.c proll-patch7/src/system.c +diff -ruN proll_18.orig/src/system.c proll-patch8/src/system.c --- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch7/src/system.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/system.c 2004-11-13 15:50:49.000000000 +0000 @@ -298,8 +298,8 @@ } @@ -2531,9 +2550,9 @@ diff -ruN proll_18.orig/src/system.c proll-patch7/src/system.c void fatal() { printk("fatal."); -diff -ruN proll_18.orig/src/system.h proll-patch7/src/system.h +diff -ruN proll_18.orig/src/system.h proll-patch8/src/system.h --- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000 -+++ proll-patch7/src/system.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/system.h 2004-11-13 15:50:49.000000000 +0000 @@ -16,7 +16,7 @@ #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */ #define NCTX_SWIFT 0x100 @@ -2543,9 +2562,9 @@ diff -ruN proll_18.orig/src/system.h proll-patch7/src/system.h #ifndef __ASSEMBLY__ struct bank { -diff -ruN proll_18.orig/src/udp.c proll-patch7/src/udp.c +diff -ruN proll_18.orig/src/udp.c proll-patch8/src/udp.c --- proll_18.orig/src/udp.c 2001-12-24 05:12:53.000000000 +0000 -+++ proll-patch7/src/udp.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch8/src/udp.c 2004-11-13 15:50:49.000000000 +0000 @@ -81,7 +81,7 @@ int source; int dest; @@ -2565,9 +2584,9 @@ diff -ruN proll_18.orig/src/udp.c proll-patch7/src/udp.c /* Register IP packet type and set write buffer pointer */ if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL) return(FALSE); -diff -ruN proll_18.orig/src/vcons_zs.c proll-patch7/src/vcons_zs.c +diff -ruN proll_18.orig/src/vcons_zs.c proll-patch8/src/vcons_zs.c --- proll_18.orig/src/vcons_zs.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch7/src/vcons_zs.c 2005-03-02 12:07:41.000000000 +0000 ++++ proll-patch8/src/vcons_zs.c 2005-03-20 10:25:39.000000000 +0000 @@ -0,0 +1,68 @@ +/** + ** Console over 'zs' (Zilog serial port) @@ -2637,9 +2656,9 @@ diff -ruN proll_18.orig/src/vcons_zs.c proll-patch7/src/vcons_zs.c + /* violent crash in the end */ + ; +} -diff -ruN proll_18.orig/src/vconsole.c proll-patch7/src/vconsole.c +diff -ruN proll_18.orig/src/vconsole.c proll-patch8/src/vconsole.c --- proll_18.orig/src/vconsole.c 1999-11-08 03:10:28.000000000 +0000 -+++ proll-patch7/src/vconsole.c 2005-03-02 14:29:05.000000000 +0000 ++++ proll-patch8/src/vconsole.c 2005-03-02 14:29:05.000000000 +0000 @@ -13,6 +13,10 @@ struct hconsole hcons0; @@ -2804,9 +2823,9 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch7/src/vconsole.c } } } -diff -ruN proll_18.orig/src/vconsole.h proll-patch7/src/vconsole.h +diff -ruN proll_18.orig/src/vconsole.h proll-patch8/src/vconsole.h --- proll_18.orig/src/vconsole.h 1999-11-08 00:58:13.000000000 +0000 -+++ proll-patch7/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 ++++ proll-patch8/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 @@ -6,6 +6,8 @@ #ifndef VCONSOLE_H #define VCONSOLE_H -- cgit v1.2.3 From 66321a11a4ef45942b3bee7377a36bb94831365a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 20:47:48 +0000 Subject: sparc update (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1350 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 17 +++++-- hw/iommu.c | 97 ++++++++++---------------------------- hw/lance.c | 134 +++++++++++++++++++++++------------------------------ hw/slavio_intctl.c | 60 +++++++++++++++++++----- hw/slavio_timer.c | 14 ++++-- 5 files changed, 153 insertions(+), 169 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 94c35e31b..432e6020d 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1,7 +1,7 @@ /* * i386 emulator main execution loop * - * Copyright (c) 2003 Fabrice Bellard + * 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 @@ -285,9 +285,18 @@ int cpu_exec(CPUState *env1) } } #elif defined(TARGET_SPARC) - if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(env->interrupt_index); - env->interrupt_request &= ~CPU_INTERRUPT_HARD; + 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; + } } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; diff --git a/hw/iommu.c b/hw/iommu.c index 62927acd5..d0b16ea88 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -1,7 +1,7 @@ /* * QEMU SPARC iommu emulation * - * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,30 +26,14 @@ /* debug iommu */ //#define DEBUG_IOMMU -/* The IOMMU registers occupy three pages in IO space. */ -struct iommu_regs { - /* First page */ - volatile unsigned long control; /* IOMMU control */ - volatile unsigned long base; /* Physical base of iopte page table */ - volatile unsigned long _unused1[3]; - volatile unsigned long tlbflush; /* write only */ - volatile unsigned long pageflush; /* write only */ - volatile unsigned long _unused2[1017]; - /* Second page */ - volatile unsigned long afsr; /* Async-fault status register */ - volatile unsigned long afar; /* Async-fault physical address */ - volatile unsigned long _unused3[2]; - volatile unsigned long sbuscfg0; /* SBUS configuration registers, per-slot */ - volatile unsigned long sbuscfg1; - volatile unsigned long sbuscfg2; - volatile unsigned long sbuscfg3; - volatile unsigned long mfsr; /* Memory-fault status register */ - volatile unsigned long mfar; /* Memory-fault physical address */ - volatile unsigned long _unused4[1014]; - /* Third page */ - volatile unsigned long mid; /* IOMMU module-id */ -}; +#ifdef DEBUG_IOMMU +#define DPRINTF(fmt, args...) \ +do { printf("IOMMU: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif +#define IOMMU_NREGS (3*4096) #define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ #define IOMMU_CTRL_VERS 0x0f000000 /* Version */ #define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ @@ -63,43 +47,6 @@ struct iommu_regs { #define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */ #define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */ -#define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */ -#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after transaction */ -#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than 12.8 us. */ -#define IOMMU_AFSR_BE 0x10000000 /* Write access received error acknowledge */ -#define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */ -#define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */ -#define IOMMU_AFSR_RESV 0x00f00000 /* Reserver, forced to 0x8 by hardware */ -#define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */ -#define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */ -#define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */ - -#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */ -#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ -#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ -#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses - produced by this device as pure - physical. */ - -#define IOMMU_MFSR_ERR 0x80000000 /* One or more of PERR1 or PERR0 */ -#define IOMMU_MFSR_S 0x01000000 /* Sparc was in supervisor mode */ -#define IOMMU_MFSR_CPU 0x00800000 /* CPU transaction caused parity error */ -#define IOMMU_MFSR_ME 0x00080000 /* Multiple parity errors occurred */ -#define IOMMU_MFSR_PERR 0x00006000 /* high bit indicates parity error occurred - on the even word of the access, low bit - indicated odd word caused the parity error */ -#define IOMMU_MFSR_BM 0x00001000 /* Error occurred while in boot mode */ -#define IOMMU_MFSR_C 0x00000800 /* Address causing error was marked cacheable */ -#define IOMMU_MFSR_RTYP 0x000000f0 /* Memory request transaction type */ - -#define IOMMU_MID_SBAE 0x001f0000 /* SBus arbitration enable */ -#define IOMMU_MID_SE 0x00100000 /* Enables SCSI/ETHERNET arbitration */ -#define IOMMU_MID_SB3 0x00080000 /* Enable SBUS device 3 arbitration */ -#define IOMMU_MID_SB2 0x00040000 /* Enable SBUS device 2 arbitration */ -#define IOMMU_MID_SB1 0x00020000 /* Enable SBUS device 1 arbitration */ -#define IOMMU_MID_SB0 0x00010000 /* Enable SBUS device 0 arbitration */ -#define IOMMU_MID_MID 0x0000000f /* Module-id, hardcoded to 0x8 */ - /* The format of an iopte in the page tables */ #define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ #define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ @@ -113,7 +60,7 @@ struct iommu_regs { typedef struct IOMMUState { uint32_t addr; - uint32_t regs[sizeof(struct iommu_regs)]; + uint32_t regs[IOMMU_NREGS]; uint32_t iostart; } IOMMUState; @@ -125,6 +72,7 @@ static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) saddr = (addr - s->addr) >> 2; switch (saddr) { default: + DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]); return s->regs[saddr]; break; } @@ -137,6 +85,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val uint32_t saddr; saddr = (addr - s->addr) >> 2; + DPRINTF("write reg[%d] = %x\n", saddr, val); switch (saddr) { case 0: switch (val & IOMMU_CTRL_RNGE) { @@ -166,6 +115,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val s->iostart = 0x80000000; break; } + DPRINTF("iostart = %x\n", s->iostart); /* Fall through */ default: s->regs[saddr] = val; @@ -188,13 +138,17 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { uint32_t iommu_translate_local(void *opaque, uint32_t addr) { IOMMUState *s = opaque; - uint32_t *iopte = (void *)(s->regs[1] << 4), pa; + uint32_t iopte, pa, tmppte; - iopte += ((addr - s->iostart) >> PAGE_SHIFT); - cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4); + iopte = s->regs[1] << 4; + addr &= ~s->iostart; + iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; + cpu_physical_memory_read(iopte, (void *) &pa, 4); bswap32s(&pa); - pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */ - return pa + (addr & PAGE_MASK); + tmppte = pa; + pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); + DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte); + return pa; } static void iommu_save(QEMUFile *f, void *opaque) @@ -203,7 +157,7 @@ static void iommu_save(QEMUFile *f, void *opaque) int i; qemu_put_be32s(f, &s->addr); - for (i = 0; i < sizeof(struct iommu_regs); i += 4) + for (i = 0; i < IOMMU_NREGS; i++) qemu_put_be32s(f, &s->regs[i]); qemu_put_be32s(f, &s->iostart); } @@ -217,7 +171,7 @@ static int iommu_load(QEMUFile *f, void *opaque, int version_id) return -EINVAL; qemu_get_be32s(f, &s->addr); - for (i = 0; i < sizeof(struct iommu_regs); i += 4) + for (i = 0; i < IOMMU_NREGS; i++) qemu_put_be32s(f, &s->regs[i]); qemu_get_be32s(f, &s->iostart); @@ -228,7 +182,7 @@ static void iommu_reset(void *opaque) { IOMMUState *s = opaque; - memset(s->regs, 0, sizeof(struct iommu_regs)); + memset(s->regs, 0, IOMMU_NREGS * 4); s->iostart = 0; } @@ -244,8 +198,7 @@ void *iommu_init(uint32_t addr) s->addr = addr; iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); - cpu_register_physical_memory(addr, sizeof(struct iommu_regs), - iommu_io_memory); + cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); register_savevm("iommu", addr, 1, iommu_save, iommu_load, s); qemu_register_reset(iommu_reset, s); diff --git a/hw/lance.c b/hw/lance.c index c594c52e8..3a8a7d0b2 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -1,7 +1,7 @@ /* * QEMU Lance emulation * - * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,20 +26,24 @@ /* debug LANCE card */ //#define DEBUG_LANCE +#ifdef DEBUG_LANCE +#define DPRINTF(fmt, args...) \ +do { printf("LANCE: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + #ifndef LANCE_LOG_TX_BUFFERS #define LANCE_LOG_TX_BUFFERS 4 #define LANCE_LOG_RX_BUFFERS 4 #endif -#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ - - #define LE_CSR0 0 #define LE_CSR1 1 #define LE_CSR2 2 #define LE_CSR3 3 -#define LE_MAXREG (LE_CSR3 + 1) +#define LE_NREGS (LE_CSR3 + 1) +#define LE_MAXREG LE_CSR3 #define LE_RDP 0 #define LE_RAP 1 @@ -148,21 +152,12 @@ struct lance_init_block { #define LEDMA_REGS 4 #define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) -#if 0 -/* Structure to describe the current status of DMA registers on the Sparc */ -struct sparc_dma_registers { - uint32_t cond_reg; /* DMA condition register */ - uint32_t st_addr; /* Start address of this transfer */ - uint32_t cnt; /* How many bytes to transfer */ - uint32_t dma_test; /* DMA test register */ -}; -#endif typedef struct LANCEState { NetDriverState *nd; uint32_t leptr; uint16_t addr; - uint16_t regs[LE_MAXREG]; + uint16_t regs[LE_NREGS]; uint8_t phys[6]; /* mac address */ int irq; unsigned int rxptr, txptr; @@ -177,7 +172,7 @@ static void lance_reset(void *opaque) memcpy(s->phys, s->nd->macaddr, 6); s->rxptr = 0; s->txptr = 0; - memset(s->regs, 0, LE_MAXREG * 2); + memset(s->regs, 0, LE_NREGS * 2); s->regs[LE_CSR0] = LE_C0_STOP; memset(s->ledmaregs, 0, LEDMA_REGS * 4); } @@ -190,10 +185,13 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: + DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]); return s->regs[s->addr]; case LE_RAP: + DPRINTF("read areg = %4.4x\n", s->addr); return s->addr; default: + DPRINTF("read unknown(%d)\n", saddr>>1); break; } return 0; @@ -208,6 +206,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: + DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val); switch(s->addr) { case LE_CSR0: if (val & LE_C0_STOP) { @@ -242,12 +241,6 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val } s->regs[LE_CSR0] = reg; - - // trigger bits - //if (val & LE_C0_TDMD) - - if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) - pic_set_irq(s->irq, 1); break; case LE_CSR1: s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); @@ -263,10 +256,12 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val } break; case LE_RAP: - if (val < LE_MAXREG) + DPRINTF("write areg = %4.4x\n", val); + if (val < LE_NREGS) s->addr = val; break; default: + DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val); break; } lance_send(s); @@ -292,7 +287,7 @@ static int lance_can_receive(void *opaque) uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; int i; - uint16_t temp; + uint8_t temp8; if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) return 0; @@ -300,18 +295,13 @@ static int lance_can_receive(void *opaque) ib = (void *) iommu_translate(dmaptr); for (i = 0; i < RX_RING_SIZE; i++) { - cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); - temp &= 0xff; - if (temp == (LE_R1_OWN)) { -#ifdef DEBUG_LANCE - fprintf(stderr, "lance: can receive %d\n", RX_BUFF_SIZE); -#endif + cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); + if (temp8 == (LE_R1_OWN)) { + DPRINTF("can receive %d\n", RX_BUFF_SIZE); return RX_BUFF_SIZE; } } -#ifdef DEBUG_LANCE - fprintf(stderr, "lance: cannot receive\n"); -#endif + DPRINTF("cannot receive\n"); return 0; } @@ -322,9 +312,11 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) LANCEState *s = opaque; uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; - unsigned int i, old_rxptr, j; - uint16_t temp; + unsigned int i, old_rxptr; + uint16_t temp16; + uint8_t temp8; + DPRINTF("receive size %d\n", size); if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) return; @@ -332,27 +324,19 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) old_rxptr = s->rxptr; for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); - if (temp == (LE_R1_OWN)) { + cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); + if (temp8 == (LE_R1_OWN)) { s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; - temp = size; - bswap16s(&temp); - cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp, 2); -#if 0 + temp16 = size + 4; + bswap16s(&temp16); + cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2); cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size); -#else - for (j = 0; j < size; j++) { - cpu_physical_memory_write(((uint32_t)&ib->rx_buf[i]) + j, &buf[j], 1); - } -#endif - temp = LE_R1_POK; - cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1); + temp8 = LE_R1_POK; + cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; - if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) + if (s->regs[LE_CSR0] & LE_C0_INEA) pic_set_irq(s->irq, 1); -#ifdef DEBUG_LANCE - fprintf(stderr, "lance: got packet, len %d\n", size); -#endif + DPRINTF("got packet, len %d\n", size); return; } } @@ -363,40 +347,36 @@ static void lance_send(void *opaque) LANCEState *s = opaque; uint32_t dmaptr = s->leptr + s->ledmaregs[3]; struct lance_init_block *ib; - unsigned int i, old_txptr, j; - uint16_t temp; + unsigned int i, old_txptr; + uint16_t temp16; + uint8_t temp8; char pkt_buf[PKT_BUF_SZ]; + DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]); if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) return; ib = (void *) iommu_translate(dmaptr); + DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring); old_txptr = s->txptr; for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); - if (temp == (LE_T1_POK|LE_T1_OWN)) { - cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp, 2); - bswap16s(&temp); - temp = (~temp) + 1; -#if 0 - cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp); -#else - for (j = 0; j < temp; j++) { - cpu_physical_memory_read((uint32_t)&ib->tx_buf[i] + j, &pkt_buf[j], 1); - } -#endif - -#ifdef DEBUG_LANCE - fprintf(stderr, "lance: sending packet, len %d\n", temp); -#endif - qemu_send_packet(s->nd, pkt_buf, temp); - temp = LE_T1_POK; - cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1); + cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); + if (temp8 == (LE_T1_POK|LE_T1_OWN)) { + cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2); + bswap16s(&temp16); + temp16 = (~temp16) + 1; + cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16); + DPRINTF("sending packet, len %d\n", temp16); + qemu_send_packet(s->nd, pkt_buf, temp16); + temp8 = LE_T1_POK; + cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; } } + if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) + pic_set_irq(s->irq, 1); } static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) @@ -436,7 +416,7 @@ static void lance_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->leptr); qemu_put_be16s(f, &s->addr); - for (i = 0; i < LE_MAXREG; i ++) + for (i = 0; i < LE_NREGS; i ++) qemu_put_be16s(f, &s->regs[i]); qemu_put_buffer(f, s->phys, 6); qemu_put_be32s(f, &s->irq); @@ -454,7 +434,7 @@ static int lance_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->leptr); qemu_get_be16s(f, &s->addr); - for (i = 0; i < LE_MAXREG; i ++) + for (i = 0; i < LE_NREGS; i ++) qemu_get_be16s(f, &s->regs[i]); qemu_get_buffer(f, s->phys, 6); qemu_get_be32s(f, &s->irq); @@ -476,7 +456,7 @@ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) s->irq = irq; lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); - cpu_register_physical_memory(leaddr, 8, lance_io_memory); + cpu_register_physical_memory(leaddr, 4, lance_io_memory); ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 352ae1f0f..9c8ddd0d0 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -1,7 +1,7 @@ /* * QEMU Sparc SLAVIO interrupt controller emulation * - * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,14 @@ */ #include "vl.h" //#define DEBUG_IRQ_COUNT +//#define DEBUG_IRQ + +#ifdef DEBUG_IRQ +#define DPRINTF(fmt, args...) \ +do { printf("IRQ: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif /* * Registers of interrupt controller in sun4m. @@ -49,6 +57,7 @@ typedef struct SLAVIO_INTCTLState { #define INTCTL_MAXADDR 0xf #define INTCTLM_MAXADDR 0xf +static void slavio_check_interrupts(void *opaque); // per-cpu interrupt controller static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) @@ -82,10 +91,12 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint val |= 80000000; val &= 0xfffe0000; s->intreg_pending[cpu] &= ~val; + DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); break; case 2: // set softint val &= 0xfffe0000; s->intreg_pending[cpu] |= val; + DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); break; default: break; @@ -135,15 +146,19 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin // Force clear unused bits val &= ~0x7fb2007f; s->intregm_disabled &= ~val; + DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); + slavio_check_interrupts(s); break; case 3: // set (disable, clear pending) // Force clear unused bits val &= ~0x7fb2007f; s->intregm_disabled |= val; s->intregm_pending &= ~val; + DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); break; case 4: s->target_cpu = val & (MAX_CPUS - 1); + DPRINTF("Set master irq cpu %d\n", s->target_cpu); break; default: break; @@ -196,6 +211,36 @@ static const uint32_t intbit_to_level[32] = { 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, }; +static void slavio_check_interrupts(void *opaque) +{ + SLAVIO_INTCTLState *s = opaque; + uint32_t pending = s->intregm_pending; + unsigned int i, max = 0; + + pending &= ~s->intregm_disabled; + + if (pending && !(s->intregm_disabled & 0x80000000)) { + for (i = 0; i < 32; i++) { + if (pending & (1 << i)) { + if (max < intbit_to_level[i]) + max = intbit_to_level[i]; + } + } + if (cpu_single_env->interrupt_index == 0) { + DPRINTF("Triggered pil %d\n", max); +#ifdef DEBUG_IRQ_COUNT + s->irq_count[max]++; +#endif + cpu_single_env->interrupt_index = TT_EXTINT | max; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } + else + DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, cpu_single_env->interrupt_index); + } + else + DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled); +} + /* * "irq" here is the bit number in the system interrupt register to * separate serial and keyboard interrupts sharing a level. @@ -204,6 +249,7 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) { SLAVIO_INTCTLState *s = opaque; + DPRINTF("Set irq %d level %d\n", irq, level); if (irq < 32) { uint32_t mask = 1 << irq; uint32_t pil = intbit_to_level[irq]; @@ -216,19 +262,9 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) s->intregm_pending &= ~mask; s->intreg_pending[s->target_cpu] &= ~(1 << pil); } - if (level && - !(s->intregm_disabled & mask) && - !(s->intregm_disabled & 0x80000000) && - (pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) { -#ifdef DEBUG_IRQ_COUNT - if (level == 1) - s->irq_count[pil]++; -#endif - cpu_single_env->interrupt_index = TT_EXTINT | pil; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); - } } } + slavio_check_interrupts(s); } static void slavio_intctl_save(QEMUFile *f, void *opaque) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 43f59d275..47d538529 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -1,7 +1,7 @@ /* * QEMU Sparc SLAVIO timer controller emulation * - * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,13 @@ //#define DEBUG_TIMER +#ifdef DEBUG_TIMER +#define DPRINTF(fmt, args...) \ +do { printf("TIMER: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + /* * Registers of hardware timer in sun4m. * @@ -90,9 +97,8 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) // Convert remaining counter ticks to CPU ticks s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); -#ifdef DEBUG_TIMER - term_printf("timer: irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); -#endif + DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); + if (s->mode != 1) pic_set_irq(s->irq, out); } -- cgit v1.2.3 From 39d2243955012581607e8430a6fb33b34f3b09ac Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 23:00:25 +0000 Subject: PCI irq in sync with new Bochs BIOS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1351 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci.c b/hw/pci.c index 2fed66f0a..6035c890a 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -494,7 +494,7 @@ PIIX3State *piix3_state; static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) { int slot_addend; - slot_addend = (pci_dev->devfn >> 3); + slot_addend = (pci_dev->devfn >> 3) - 1; return (irq_num + slot_addend) & 3; } -- cgit v1.2.3 From 7e6c3f34bf800da6a8db461a6099047905c34f3a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 23:01:24 +0000 Subject: new bochs BIOS - 16 bit APM support (initial patch by Struan Bartlett) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1352 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 211 +++++++++++++++--------------------------------------- 2 files changed, 57 insertions(+), 154 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index fe9816e0a..f3e40c240 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 785076964..7ba84d7c1 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,162 +1,65 @@ Index: rombios.c =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v -retrieving revision 1.110 -diff -u -w -r1.110 rombios.c ---- rombios.c 31 May 2004 13:11:27 -0000 1.110 -+++ rombios.c 7 Oct 2004 21:23:50 -0000 -@@ -137,6 +137,7 @@ - #define DEBUG_INT16 0 - #define DEBUG_INT1A 0 - #define DEBUG_INT74 0 -+#define DEBUG_APM 0 - - #define BX_CPU 3 - #define BX_USE_PS2_MOUSE 1 -@@ -145,6 +146,7 @@ - #define BX_SUPPORT_FLOPPY 1 - #define BX_FLOPPY_ON_CNT 37 // 2 seconds - #define BX_PCIBIOS 1 -+#define BX_APM 1 - - #define BX_USE_ATADRV 1 - #define BX_ELTORITO_BOOT 1 -@@ -230,17 +232,6 @@ - out dx,ax - MEND - --MACRO HALT2 -- ;; the HALT macro is called with the line number of the HALT call. -- ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex -- ;; to print a BX_PANIC message. This will normally halt the simulation -- ;; with a message such as "BIOS panic at rombios.c, line 4091". -- ;; However, users can choose to make panics non-fatal and continue. -- mov dx,#PANIC_PORT2 -- mov ax,#?1 -- out dx,ax --MEND -- - MACRO JMP_AP - db 0xea - dw ?2 -@@ -1543,15 +1534,12 @@ - } - - if (action & BIOS_PRINTF_HALT) { -- // freeze in a busy loop. If I do a HLT instruction, then in versions -- // 1.3.pre1 and earlier, it will panic without ever updating the VGA -- // display, so the panic message will not be visible. By waiting -- // forever, you are certain to see the panic message on screen. -- // After a few more versions have passed, we can turn this back into -- // a halt or something. -- // do {} while (1); -+ // freeze in a busy loop. - ASM_START -- HALT2(__LINE__) -+ cli -+ halt2_loop: -+ hlt -+ jmp halt2_loop - ASM_END - } - } -@@ -5412,8 +5400,8 @@ - case 0x03: SET_BL( 0x06 ); break; - } - -- DI = 0xefc7; -- ES = 0xf000; -+ DI = read_word(0x00, 0x1e*4); // INT vector 0x1E -+ ES = read_word(0x00, 0x1e*4+2); - goto int13_success; - break; - -@@ -6984,8 +6972,8 @@ - } - - /* set es & di to point to 11 byte diskette param table in ROM */ -- DI = 0xefc7; -- ES = 0xf000; -+ DI = read_word(0x00, 0x1e*4); // INT vector 0x1E -+ ES = read_word(0x00, 0x1e*4+2); - CLEAR_CF(); // success - /* disk status not changed upon success */ - return; -@@ -7880,7 +7868,7 @@ - mov al, #0x02 - out #0x0a, al ;; clear DMA-1 channel 2 mask bit - -- SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table) -+ SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2) - SET_INT_VECTOR(0x40, #0xF000, #int13_diskette) - SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6 - -@@ -8344,6 +8332,19 @@ - pop ax - iret - -+ -+;-------------------- -+#if BX_APM -+use32 386 -+#define APM_PROT32 -+#include "apmbios.S" -+use16 386 +retrieving revision 1.130 +diff -u -w -r1.130 rombios.c +--- rombios.c 13 Feb 2005 08:47:30 -0000 1.130 ++++ rombios.c 6 Apr 2005 22:38:16 -0000 +@@ -8570,7 +8570,10 @@ + use32 386 + #define APM_PROT32 + #include "apmbios.S" + -+#define APM_REAL + use16 386 ++#define APM_PROT16 +#include "apmbios.S" -+ -+#endif -+ - ;-------------------- - #if BX_PCIBIOS - use32 386 -@@ -9515,6 +9516,26 @@ - pop ds - iret -+diskette_param_table2: -+;; New diskette parameter table adding 3 parameters from IBM -+;; Since no provisions are made for multiple drive types, most -+;; values in this table are ignored. I set parameters for 1.44M -+;; floppy here -+db 0xAF -+db 0x02 ;; head load time 0000001, DMA used -+db 0x25 -+db 0x02 -+db 18 -+db 0x1B -+db 0xFF -+db 0x6C -+db 0xF6 -+db 0x0F -+db 0x08 -+db 79 ;; maximum track -+db 0 ;; data transfer rate -+db 4 ;; drive type in cmos + #define APM_REAL + #include "apmbios.S" +Index: apmbios.S +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/apmbios.S,v +retrieving revision 1.1 +diff -u -w -r1.1 apmbios.S +--- apmbios.S 20 Jun 2004 18:27:09 -0000 1.1 ++++ apmbios.S 6 Apr 2005 22:38:16 -0000 +@@ -1,6 +1,9 @@ + // APM BIOS support for the Bochs BIOS + // Copyright (C) 2004 Fabrice Bellard + // ++// 16-bit interface activation ++// Copyright (C) 2005 Struan Bartlett ++// + // 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 +@@ -111,13 +114,28 @@ + mov bl, #0x4d // 'M' + // bit 0 : 16 bit interface supported + // bit 1 : 32 bit interface supported +- mov cx, #0x2 ++ mov cx, #0x3 + jmp APMSYM(ok) + + ;----------------- + ; APM real mode interface connect + APMSYM(01): + cmp al, #0x01 ++ jne APMSYM(02) ++ jmp APMSYM(ok) ++ ++;----------------- ++; APM 16 bit protected mode interface connect ++APMSYM(02): ++ cmp al, #0x02 ++ jne APMSYM(03) + - .org 0xf045 ; INT 10 Functions 0-Fh Entry Point - HALT(__LINE__) - iret -@@ -9560,6 +9581,10 @@ - .org 0xf859 ; INT 15h System Services Entry Point - int15_handler: - pushf -+#if BX_APM -+ cmp ah, #0x53 -+ je apm_call -+#endif - push ds - push es - pushad -@@ -9570,6 +9595,10 @@ - popf - //JMPL(iret_modify_cf) - jmp iret_modify_cf -+#if BX_APM -+apm_call: -+ jmp _apmreal_entry -+#endif ++ mov bx, #_apm16_entry ++ ++ mov ax, #0xf000 // 16 bit code segment base ++ mov si, #0xfff0 // 16 bit code segment size ++ mov cx, #0xf000 // data segment address ++ mov di, #0xfff0 // data segment length + jne APMSYM(03) + jmp APMSYM(ok) - ;; Protected mode IDT descriptor - ;; -- cgit v1.2.3 From c194feda5fbe7a9e4e4cc66eba84874ceba46453 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 23:03:38 +0000 Subject: IDE irq fix (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1353 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index cf3a5f32f..f7c9b4503 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -207,7 +207,7 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, } ide0_mem_index = pmac_ide_init(&bs_table[0], openpic, 0x13); - ide1_mem_index = pmac_ide_init(&bs_table[2], openpic, 0x13); + ide1_mem_index = pmac_ide_init(&bs_table[2], openpic, 0x14); /* cuda also initialize ADB */ cuda_mem_index = cuda_init(openpic, 0x19); -- cgit v1.2.3 From 85d8be6bf2c6823f9d386794defa790618c08986 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 6 Apr 2005 23:06:54 +0000 Subject: Open Hack'Ware version 0.4.1 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1354 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/ppc_rom.bin | Bin 524288 -> 524288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin index f88214dd1..3755ff01e 100644 Binary files a/pc-bios/ppc_rom.bin and b/pc-bios/ppc_rom.bin differ -- cgit v1.2.3 From 8e96005d86cba6b2ce177f489463eda602d99238 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Apr 2005 19:42:46 +0000 Subject: VFP register ordering (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1355 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/cpu.h | 11 ++++------- target-arm/translate.c | 31 ++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index cf11c2f94..134617513 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -35,9 +35,9 @@ precision respectively. Doing runtime conversions is tricky because VFP registers may contain integer values (eg. as the result of a FTOSI instruction). - A double precision register load/store must also load/store the - corresponding single precision pair, although it is undefined how - these overlap. */ + s<2n> maps to the least significant half of d + s<2n+1> maps to the most significant half of d + */ typedef struct CPUARMState { uint32_t regs[16]; @@ -71,10 +71,7 @@ typedef struct CPUARMState { memory was written */ /* VFP coprocessor state. */ struct { - union { - float32 s[32]; - float64 d[16]; - } regs; + float64 regs[16]; /* We store these fpcsr fields separately for convenience. */ int vec_len; diff --git a/target-arm/translate.c b/target-arm/translate.c index db38e331b..39c28e754 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -385,28 +385,41 @@ VFP_OP(st) #undef VFP_OP +static inline long +vfp_reg_offset (int dp, int reg) +{ + if (dp) + return offsetof(CPUARMState, vfp.regs[reg]); + else if (reg & 1) { + return offsetof(CPUARMState, vfp.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.upper); + } else { + return offsetof(CPUARMState, vfp.regs[reg >> 1]) + + offsetof(CPU_DoubleU, l.lower); + } +} static inline void gen_mov_F0_vreg(int dp, int reg) { if (dp) - gen_op_vfp_getreg_F0d(offsetof(CPUARMState, vfp.regs.d[reg])); + gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg)); else - gen_op_vfp_getreg_F0s(offsetof(CPUARMState, vfp.regs.s[reg])); + gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg)); } static inline void gen_mov_F1_vreg(int dp, int reg) { if (dp) - gen_op_vfp_getreg_F1d(offsetof(CPUARMState, vfp.regs.d[reg])); + gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg)); else - gen_op_vfp_getreg_F1s(offsetof(CPUARMState, vfp.regs.s[reg])); + gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg)); } static inline void gen_mov_vreg_F0(int dp, int reg) { if (dp) - gen_op_vfp_setreg_F0d(offsetof(CPUARMState, vfp.regs.d[reg])); + gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg)); else - gen_op_vfp_setreg_F0s(offsetof(CPUARMState, vfp.regs.s[reg])); + gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); } /* Disassemble a VFP instruction. Returns nonzero if an error occured @@ -2120,9 +2133,9 @@ void cpu_dump_state(CPUState *env, FILE *f, env->cpsr & (1 << 28) ? 'V' : '-'); for (i = 0; i < 16; i++) { - s0.s = env->vfp.regs.s[i * 2]; - s1.s = env->vfp.regs.s[i * 2 + 1]; - d.d = env->vfp.regs.d[i]; + d.d = env->vfp.regs[i]; + s0.i = d.l.lower; + s1.i = d.l.upper; cpu_fprintf(f, "s%02d=%08x(%8f) s%02d=%08x(%8f) d%02d=%08x%08x(%8f)\n", i * 2, (int)s0.i, s0.s, i * 2 + 1, (int)s0.i, s0.s, -- cgit v1.2.3 From 9d60cac01fa5f0c36d49ae8df3ad040d13606700 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Apr 2005 19:55:52 +0000 Subject: ARM double ordering fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1356 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index 25f9cea7a..448f2c5ba 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -120,7 +120,8 @@ static inline void tswap64s(uint64_t *s) endian ! */ typedef union { float64 d; -#if defined(WORDS_BIGENDIAN) || (defined(__arm__) && !defined(__VFP_FP__)) +#if defined(WORDS_BIGENDIAN) \ + || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) struct { uint32_t upper; uint32_t lower; -- cgit v1.2.3 From b7e2c11dbd16257ec511b4aaa9c765eeda926563 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Apr 2005 20:33:08 +0000 Subject: helper_lret_protected fix for kqemu (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1357 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index a15ec5a6a..b358c2ecf 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2118,7 +2118,6 @@ void helper_lret_protected(int shift, int addend) helper_ret_protected(shift, 0, addend); #ifdef USE_KQEMU if (kqemu_is_ok(env)) { - CC_OP = CC_OP_EFLAGS; env->exception_index = -1; cpu_loop_exit(); } -- cgit v1.2.3 From 5a246934eb737c242e28995641c9ebf80477b0b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Apr 2005 20:35:06 +0000 Subject: open the dialog box if an image was not selected from command-line (Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1358 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cocoa.m b/cocoa.m index 38b4760f9..fba6c2160 100644 --- a/cocoa.m +++ b/cocoa.m @@ -416,8 +416,11 @@ static void QZ_SetPortAlphaOpaque () /* Called when the internal event loop has just started running */ - (void)applicationDidFinishLaunching: (NSNotification *) note { - - /* Do whatever we want here : set up a pc list... */ + + /* 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]; @@ -431,9 +434,11 @@ static void QZ_SetPortAlphaOpaque () modalForWindow:window modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; } - - /* or Launch Qemu, with the global args */ - //[self startEmulationWithArgc:gArgc argv:gArgv]; + else + { + /* or Launch Qemu, with the global args */ + [self startEmulationWithArgc:gArgc argv:gArgv]; + } } - (void)applicationWillTerminate:(NSNotification *)aNotification -- cgit v1.2.3 From 7a674b136337ac195b2a983f4a6b81f1c50c715e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Apr 2005 20:36:50 +0000 Subject: accept more disk image extensions (David Still) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1359 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocoa.m b/cocoa.m index fba6c2160..d41517b08 100644 --- a/cocoa.m +++ b/cocoa.m @@ -430,7 +430,7 @@ static void QZ_SetPortAlphaOpaque () [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",nil] + [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]; } -- cgit v1.2.3 From b8076a748d52db5f5258c29fe342b8593a0b9914 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Apr 2005 22:20:31 +0000 Subject: ia64 host support (David Mosberger) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1360 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 6 ++ cpu-exec.c | 43 ++++++++++ disas.c | 9 ++- dyngen-exec.h | 14 ++-- dyngen.c | 206 ++++++++++++++++++++++++++++++++++++++++++++---- dyngen.h | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++ exec-all.h | 11 +++ exec.c | 2 +- ia64.ld | 211 +++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/mmap.c | 6 +- linux-user/signal.c | 57 +++++++------- qemu-img.c | 8 +- vl.c | 9 +++ 13 files changed, 738 insertions(+), 64 deletions(-) create mode 100644 ia64.ld diff --git a/Makefile.target b/Makefile.target index cabad43be..16f649637 100644 --- a/Makefile.target +++ b/Makefile.target @@ -184,7 +184,9 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld endif ifeq ($(ARCH),ia64) +CFLAGS += -mno-sdata OP_CFLAGS=$(CFLAGS) +LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld endif ifeq ($(ARCH),arm) @@ -382,6 +384,10 @@ vl.o: CFLAGS+=-p VL_LDFLAGS+=-p endif +ifeq ($(ARCH),ia64) +VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld +endif + $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) diff --git a/cpu-exec.c b/cpu-exec.c index 432e6020d..59f127747 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -573,6 +573,15 @@ int cpu_exec(CPUState *env1) ); } } +#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 @@ -1118,6 +1127,40 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, &uc->uc_sigmask, puc); } +#elif defined(__ia64) + +#ifndef __ISR_VALID + /* This ought to be in ... */ +# define __ISR_VALID 1 +# define si_flags _sifields._sigfault._si_pad0 +#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_flags & __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); +} + #else #error host CPU specific signal handler needed diff --git a/disas.c b/disas.c index 8bba62446..7005716c1 100644 --- a/disas.c +++ b/disas.c @@ -143,7 +143,8 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #elif defined(TARGET_PPC) print_insn = print_insn_ppc; #else - fprintf(out, "Asm output not supported on this arch\n"); + fprintf(out, "0x" TARGET_FMT_lx + ": Asm output not supported on this arch\n", code); return; #endif @@ -202,7 +203,8 @@ void disas(FILE *out, void *code, unsigned long size) #elif defined(__arm__) print_insn = print_insn_arm; #else - fprintf(out, "Asm output not supported on this arch\n"); + 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) { @@ -311,7 +313,8 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) #elif defined(TARGET_PPC) print_insn = print_insn_ppc; #else - term_printf("Asm output not supported on this arch\n"); + term_printf("0x" TARGET_FMT_lx + ": Asm output not supported on this arch\n", pc); return; #endif diff --git a/dyngen-exec.h b/dyngen-exec.h index 9b39f59b5..902728013 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -29,7 +29,7 @@ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; /* XXX may be done for all 64 bits targets ? */ -#if defined (__x86_64__) +#if defined (__x86_64__) || defined(__ia64) typedef unsigned long uint64_t; #else typedef unsigned long long uint64_t; @@ -38,7 +38,7 @@ typedef unsigned long long uint64_t; typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; -#if defined (__x86_64__) +#if defined (__x86_64__) || defined(__ia64) typedef signed long int64_t; #else typedef signed long long int64_t; @@ -148,10 +148,10 @@ extern int printf(const char *, ...); #define AREG4 "%d5" #endif #ifdef __ia64__ -#define AREG0 "r27" -#define AREG1 "r24" -#define AREG2 "r25" -#define AREG3 "r26" +#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 */ @@ -224,6 +224,8 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #endif #ifdef __ia64__ #define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;") +#define GOTO_LABEL_PARAM(n) asm volatile ("br.sptk.many " \ + ASM_NAME(__op_gen_label) #n) #endif #ifdef __sparc__ #define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \ diff --git a/dyngen.c b/dyngen.c index 5823e0767..45284954b 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1203,6 +1203,48 @@ void get_reloc_expr(char *name, int name_size, const char *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, @@ -1392,7 +1434,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* 08 00 84 00 */ if (get32((uint32_t *)p) != 0x00840008) error("br.ret.sptk.many b0;; expected at the end of %s", name); - copy_size = p - p_start; + copy_size = p_end - p_start; } #elif defined(HOST_SPARC) { @@ -1529,7 +1571,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } 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); @@ -1550,9 +1596,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; } #endif -#ifdef __APPLE__ +#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 @@ -1964,25 +2019,78 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_IA64) { + unsigned long sym_idx; + long code_offset; char name[256]; int type; - int addend; + long addend; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { - sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; - get_reloc_expr(name, sizeof(name), sym_name); - type = ELF64_R_TYPE(rel->r_info); - addend = rel->r_addend; - switch(type) { - case R_IA64_LTOFF22: - error("must implemnt R_IA64_LTOFF22 relocation"); - case R_IA64_PCREL21B: - error("must implemnt R_IA64_PCREL21B relocation"); - default: - error("unsupported ia64 relocation (%d)", type); - } - } + 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); + 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, rel->r_offset - start_offset); + continue; + } + get_reloc_expr(name, sizeof(name), sym_name); + type = ELF64_R_TYPE(rel->r_info); + addend = rel->r_addend; + code_offset = rel->r_offset - start_offset; + 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) { @@ -2236,6 +2344,63 @@ fprintf(outfile, " LDREntry *arm_ldr_ptr = arm_ldr_table;\n" " uint32_t *arm_data_ptr = arm_data_table;\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" @@ -2298,6 +2463,13 @@ fprintf(outfile, " }\n" " the_end:\n" ); +#ifdef HOST_IA64 + fprintf(outfile, + " 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"); +#endif /* generate some code patching */ #ifdef HOST_ARM diff --git a/dyngen.h b/dyngen.h index f1ce2484c..e0e1f4a13 100644 --- a/dyngen.h +++ b/dyngen.h @@ -43,6 +43,11 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) #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 @@ -204,3 +209,218 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, } #endif /* __arm__ */ + +#ifdef __ia64 + + +/* Patch instruction with "val" where "mask" has 1 bits. */ +static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val) +{ + uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16); +# define insn_mask ((1UL << 41) - 1) + unsigned long shift; + + b0 = b[0]; b1 = b[1]; + shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */ + if (shift >= 64) { + m1 = mask << (shift - 64); + v1 = val << (shift - 64); + } else { + m0 = mask << shift; m1 = mask >> (64 - shift); + v0 = val << shift; v1 = val >> (64 - shift); + b[0] = (b0 & ~m0) | (v0 & m0); + } + b[1] = (b1 & ~m1) | (v1 & m1); +} + +static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val) +{ + ia64_patch(insn_addr, + 0x011ffffe000UL, + ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ + | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); +} + +static inline void ia64_imm64 (void *insn, uint64_t val) +{ + /* Ignore the slot number of the relocation; GCC and Intel + toolchains differed for some time on whether IMM64 relocs are + against slot 1 (Intel) or slot 2 (GCC). */ + uint64_t insn_addr = (uint64_t) insn & ~3UL; + + ia64_patch(insn_addr + 2, + 0x01fffefe000UL, + ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ + | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ + | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */) + ); + ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); +} + +static inline void ia64_imm60b (void *insn, uint64_t val) +{ + /* Ignore the slot number of the relocation; GCC and Intel + toolchains differed for some time on whether IMM64 relocs are + against slot 1 (Intel) or slot 2 (GCC). */ + uint64_t insn_addr = (uint64_t) insn & ~3UL; + + if (val + ((uint64_t) 1 << 59) >= (1UL << 60)) + fprintf(stderr, "%s: value %ld out of IMM60 range\n", + __FUNCTION__, (int64_t) val); + ia64_patch_imm60(insn_addr + 2, val); +} + +static inline void ia64_imm22 (void *insn, uint64_t val) +{ + if (val + (1 << 21) >= (1 << 22)) + fprintf(stderr, "%s: value %li out of IMM22 range\n", + __FUNCTION__, (int64_t)val); + ia64_patch((uint64_t) insn, 0x01fffcfe000UL, + ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ + | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); +} + +/* Like ia64_imm22(), but also clear bits 20-21. For addl, this has + the effect of turning "addl rX=imm22,rY" into "addl + rX=imm22,r0". */ +static inline void ia64_imm22_r0 (void *insn, uint64_t val) +{ + if (val + (1 << 21) >= (1 << 22)) + fprintf(stderr, "%s: value %li out of IMM22 range\n", + __FUNCTION__, (int64_t)val); + ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20), + ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ + | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ + | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ + | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); +} + +static inline void ia64_imm21b (void *insn, uint64_t val) +{ + if (val + (1 << 20) >= (1 << 21)) + fprintf(stderr, "%s: value %li out of IMM21b range\n", + __FUNCTION__, (int64_t)val); + ia64_patch((uint64_t) insn, 0x11ffffe000UL, + ( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */ + | ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); +} + +static inline void ia64_nop_b (void *insn) +{ + ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37); +} + +static inline void ia64_ldxmov(void *insn, uint64_t val) +{ + if (val + (1 << 21) < (1 << 22)) + ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37); +} + +static inline int ia64_patch_ltoff(void *insn, uint64_t val, + int relaxable) +{ + if (relaxable && (val + (1 << 21) < (1 << 22))) { + ia64_imm22_r0(insn, val); + return 0; + } + return 1; +} + +struct ia64_fixup { + struct ia64_fixup *next; + void *addr; /* address that needs to be patched */ + long value; +}; + +#define IA64_PLT(insn, plt_index) \ +do { \ + struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ + fixup->next = plt_fixes; \ + plt_fixes = fixup; \ + fixup->addr = (insn); \ + fixup->value = (plt_index); \ + plt_offset[(plt_index)] = 1; \ +} while (0) + +#define IA64_LTOFF(insn, val, relaxable) \ +do { \ + if (ia64_patch_ltoff(insn, val, relaxable)) { \ + struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ + fixup->next = ltoff_fixes; \ + ltoff_fixes = fixup; \ + fixup->addr = (insn); \ + fixup->value = (val); \ + } \ +} while (0) + +static inline void ia64_apply_fixes (uint8_t **gen_code_pp, + struct ia64_fixup *ltoff_fixes, + uint64_t gp, + struct ia64_fixup *plt_fixes, + int num_plts, + unsigned long *plt_target, + unsigned int *plt_offset) +{ + static const uint8_t plt_bundle[] = { + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */ + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, + + 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 + }; + uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start, *vp; + struct ia64_fixup *fixup; + unsigned int offset = 0; + struct fdesc { + long ip; + long gp; + } *fdesc; + int i; + + if (plt_fixes) { + plt_start = gen_code_ptr; + + for (i = 0; i < num_plts; ++i) { + if (plt_offset[i]) { + plt_offset[i] = offset; + offset += sizeof(plt_bundle); + + fdesc = (struct fdesc *) plt_target[i]; + memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle)); + ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp); + ia64_imm60b(gen_code_ptr + 0x12, + (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4); + gen_code_ptr += sizeof(plt_bundle); + } + } + + for (fixup = plt_fixes; fixup; fixup = fixup->next) + ia64_imm21b(fixup->addr, + ((long) plt_start + plt_offset[fixup->value] + - ((long) fixup->addr & ~0xf)) >> 4); + } + + got_start = gen_code_ptr; + + /* First, create the GOT: */ + for (fixup = ltoff_fixes; fixup; fixup = fixup->next) { + /* first check if we already have this value in the GOT: */ + for (vp = got_start; vp < gen_code_ptr; ++vp) + if (*(uint64_t *) vp == fixup->value) + break; + if (vp == gen_code_ptr) { + /* Nope, we need to put the value in the GOT: */ + *(uint64_t *) vp = fixup->value; + gen_code_ptr += 8; + } + ia64_imm22(fixup->addr, (long) vp - gp); + } + *gen_code_pp = gen_code_ptr; +} + +#endif diff --git a/exec-all.h b/exec-all.h index 1ecb41c55..263d4c2b0 100644 --- a/exec-all.h +++ b/exec-all.h @@ -126,6 +126,8 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, #if defined(__alpha__) #define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024) +#elif defined(__ia64) +#define CODE_GEN_BUFFER_SIZE (4 * 1024 * 1024) /* range of addl */ #elif defined(__powerpc__) #define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024) #else @@ -487,6 +489,15 @@ static inline int testandset (int *p) } #endif +#ifdef __ia64 +#include + +static inline int testandset (int *p) +{ + return __sync_lock_test_and_set (p, 1); +} +#endif + typedef int spinlock_t; #define SPIN_LOCK_UNLOCKED 0 diff --git a/exec.c b/exec.c index 8fe166bb0..264775e1e 100644 --- a/exec.c +++ b/exec.c @@ -58,7 +58,7 @@ int nb_tbs; /* any access to the tbs or the page table must use this lock */ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; -uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; +uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32))); uint8_t *code_gen_ptr; int phys_ram_size; diff --git a/ia64.ld b/ia64.ld new file mode 100644 index 000000000..8d2ede2d3 --- /dev/null +++ b/ia64.ld @@ -0,0 +1,211 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf64-ia64-little", "elf64-ia64-little", + "elf64-ia64-little") +OUTPUT_ARCH(ia64) +ENTRY(_start) +SEARCH_DIR("/usr/ia64-linux/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x60000000); . = 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.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .rela.IA_64.pltoff : { *(.rela.IA_64.pltoff) } + .init : + { + KEEP (*(.init)) + } =0x00300000010070000002000001000400 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x00300000010070000002000001000400 + .fini : + { + KEEP (*(.fini)) + } =0x00300000010070000002000001000400 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .opd : { *(.opd) } + .IA_64.unwind_info : { *(.IA_64.unwind_info* .gnu.linkonce.ia64unwi.*) } + .IA_64.unwind : { *(.IA_64.unwind* .gnu.linkonce.ia64unw.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x10000) + (. & (0x10000 - 1)); + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .dynamic : { *(.dynamic) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + /* Ensure __gp is outside the range of any normal data. We need to + do this to avoid the linker optimizing the code in op.o and getting + it out of sync with the relocs that we read when processing that + file. A better solution might be to ensure that the dynamically + generated code and static qemu code share a single gp-value. */ + __gp = . + 0x200000; + .got : { *(.got.plt) *(.got) } + .IA_64.pltoff : { *(.IA_64.pltoff) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss : + { + . += 0x400000; /* ensure .bss stuff is out of reach of gp */ + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 81233035d..a404ef3b0 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -152,7 +152,8 @@ long target_mmap(unsigned long start, unsigned long len, int prot, int flags, int fd, unsigned long offset) { unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; -#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ + defined(__ia64) static unsigned long last_start = 0x40000000; #endif @@ -191,7 +192,8 @@ long target_mmap(unsigned long start, unsigned long len, int prot, host_start = start & qemu_host_page_mask; if (!(flags & MAP_FIXED)) { -#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ + defined(__ia64) /* tell the kenel to search at the same place as i386 */ if (host_start == 0) { host_start = last_start; diff --git a/linux-user/signal.c b/linux-user/signal.c index d3ca2bfef..7a904ad00 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -26,13 +26,6 @@ #include #include -#ifdef __ia64__ -#undef uc_mcontext -#undef uc_sigmask -#undef uc_stack -#undef uc_link -#endif - #include "qemu.h" //#define DEBUG_SIGNAL @@ -557,11 +550,11 @@ typedef struct target_sigaltstack { } target_stack_t; struct target_ucontext { - target_ulong uc_flags; - target_ulong uc_link; - target_stack_t uc_stack; - struct target_sigcontext uc_mcontext; - target_sigset_t uc_sigmask; /* mask last for extensibility */ + target_ulong tuc_flags; + target_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ }; struct sigframe @@ -743,16 +736,18 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, goto give_sigsegv; /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(/*current->sas_ss_sp*/ 0, &frame->uc.uc_stack.ss_sp); + err |= __put_user(0, &frame->uc.tuc_flags); + err |= __put_user(0, &frame->uc.tuc_link); + err |= __put_user(/*current->sas_ss_sp*/ 0, + &frame->uc.tuc_stack.ss_sp); err |= __put_user(/* sas_ss_flags(regs->esp) */ 0, - &frame->uc.uc_stack.ss_flags); - err |= __put_user(/* current->sas_ss_size */ 0, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, + &frame->uc.tuc_stack.ss_flags); + err |= __put_user(/* current->sas_ss_size */ 0, + &frame->uc.tuc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { - if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i])) + if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) goto give_sigsegv; } @@ -880,14 +875,14 @@ long do_rt_sigreturn(CPUX86State *env) if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; #endif - target_to_host_sigset(&set, &frame->uc.uc_sigmask); + target_to_host_sigset(&set, &frame->uc.tuc_sigmask); sigprocmask(SIG_SETMASK, &set, NULL); - if (restore_sigcontext(env, &frame->uc.uc_mcontext, &eax)) + if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) goto badframe; #if 0 - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + if (__copy_from_user(&st, &frame->uc.tuc_stack, sizeof(st))) goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ @@ -933,11 +928,11 @@ typedef struct target_sigaltstack { } target_stack_t; struct target_ucontext { - target_ulong uc_flags; - target_ulong uc_link; - target_stack_t uc_stack; - struct target_sigcontext uc_mcontext; - target_sigset_t uc_sigmask; /* mask last for extensibility */ + target_ulong tuc_flags; + target_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ }; struct sigframe @@ -1135,10 +1130,10 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, /* Clear all the bits of the ucontext we don't use. */ err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); - err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ + err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ env, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { - if (__put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i])) + if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) return; } @@ -1253,10 +1248,10 @@ long do_rt_sigreturn(CPUState *env) if (verify_area(VERIFY_READ, frame, sizeof (*frame))) goto badframe; #endif - target_to_host_sigset(&host_set, &frame->uc.uc_sigmask); + target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); sigprocmask(SIG_SETMASK, &host_set, NULL); - if (restore_sigcontext(env, &frame->uc.uc_mcontext)) + if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) goto badframe; #if 0 diff --git a/qemu-img.c b/qemu-img.c index 132428cf6..31f877606 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -165,7 +165,7 @@ static void get_human_readable_size(char *buf, int buf_size, int64_t size) int i; if (size <= 999) { - snprintf(buf, buf_size, "%lld", size); + snprintf(buf, buf_size, "%lld", (long long) size); } else { base = 1024; for(i = 0; i < NB_SUFFIXES; i++) { @@ -176,7 +176,7 @@ static void get_human_readable_size(char *buf, int buf_size, int64_t size) break; } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { snprintf(buf, buf_size, "%lld%c", - (size + (base >> 1)) / base, + (long long) ((size + (base >> 1)) / base), suffixes[i]); break; } @@ -369,7 +369,7 @@ static int img_create(int argc, char **argv) printf(", backing_file=%s", base_filename); } - printf(", size=%lld kB\n", size / 1024); + printf(", size=%lld kB\n", (long long) (size / 1024)); ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted); if (ret < 0) { if (ret == -ENOTSUP) { @@ -666,7 +666,7 @@ static int img_info(int argc, char **argv) "virtual size: %s (%lld bytes)\n" "disk size: %s\n", filename, fmt_name, size_buf, - total_sectors * 512, + (long long) (total_sectors * 512), dsize_buf); if (bdrv_is_encrypted(bs)) printf("encrypted: yes\n"); diff --git a/vl.c b/vl.c index 46a36adf5..40c0c0afd 100644 --- a/vl.c +++ b/vl.c @@ -519,6 +519,15 @@ int64_t cpu_get_real_ticks(void) return val; } +#elif defined(__ia64) + +int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); + return val; +} + #else #error unsupported CPU #endif -- cgit v1.2.3 From 2b03a7a5bc4b23d912e0d8d23c8486ac8eec8a1d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Apr 2005 14:39:05 +0000 Subject: renamed set_bit to cow_set_bit (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1361 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-cow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block-cow.c b/block-cow.c index 81bd334cc..15270dfd3 100644 --- a/block-cow.c +++ b/block-cow.c @@ -124,7 +124,7 @@ static int cow_open(BlockDriverState *bs, const char *filename) return -1; } -static inline void set_bit(uint8_t *bitmap, int64_t bitnum) +static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum) { bitmap[bitnum / 8] |= (1 << (bitnum%8)); } @@ -198,7 +198,7 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num, if (ret != nb_sectors * 512) return -1; for (i = 0; i < nb_sectors; i++) - set_bit(s->cow_bitmap, sector_num + i); + cow_set_bit(s->cow_bitmap, sector_num + i); return 0; } -- cgit v1.2.3 From d39c0b990a243fba280eb4222daf685491431a5b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Apr 2005 14:40:58 +0000 Subject: fixed MMU bug on code page boundary git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1362 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 543ed927b..f93c3b1ca 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1395,24 +1395,24 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; gen_op_sta(insn, 0, 4, 0); - break; + break; case 0x15: if (!supervisor(dc)) goto priv_insn; gen_op_stba(insn, 0, 1, 0); - break; + break; case 0x16: if (!supervisor(dc)) goto priv_insn; gen_op_stha(insn, 0, 2, 0); - break; + break; case 0x17: if (!supervisor(dc)) goto priv_insn; flush_T2(dc); gen_movl_reg_T2(rd + 1); gen_op_stda(insn, 0, 8, 0); - break; + break; #endif default: case 0x0e: /* V9 stx */ @@ -1545,6 +1545,10 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, /* if the next PC is different, we abort now */ if (dc->pc != (last_pc + 4)) break; + /* if we reach a page boundary, we stop generation so that the + PC of a TT_TFAULT exception is always in the right page */ + if ((dc->pc & (TARGET_PAGE_SIZE - 1)) == 0) + break; /* if single step mode, we generate only one instruction and generate an exception */ if (env->singlestep_enabled) { -- cgit v1.2.3 From 40545f84cfcbe4b73cca040b3043a1c2de935762 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Apr 2005 14:51:41 +0000 Subject: packet fix for for netware 3.11 (initial patch by Mark Jonckheere) - security bug fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1363 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 79d3026c0..e1b656e1b 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -246,7 +246,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) { NE2000State *s = opaque; - int offset, page; + int offset, page, index; addr &= 0xf; #ifdef DEBUG_NE2000 @@ -264,10 +264,18 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) ne2000_update_irq(s); } if (val & E8390_TRANS) { - qemu_send_packet(s->nd, s->mem + (s->tpsr << 8), s->tcnt); + index = (s->tpsr << 8); + /* XXX: next 2 lines are a hack to make netware 3.11 work */ + if (index >= NE2000_PMEM_END) + index -= NE2000_PMEM_SIZE; + /* fail safe: check range on the transmitted length */ + if (index + s->tcnt <= NE2000_PMEM_END) { + qemu_send_packet(s->nd, s->mem + index, s->tcnt); + } /* signal end of transfert */ s->tsr = ENTSR_PTX; s->isr |= ENISR_TX; + s->cmd &= ~E8390_TRANS; ne2000_update_irq(s); } } -- cgit v1.2.3 From e3a4e4b64302b7bd38f206421113312b427d35c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 17 Apr 2005 17:56:18 +0000 Subject: destination write mask support, fixed banked memory access, read-only access for bus type in SR 0x17 (Volker Ruppert) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1364 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 8 ++++---- hw/cirrus_vga_rop2.h | 37 ++++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 4b92b4090..13450f0fc 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -800,7 +800,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_blt_srcpitch, s->cirrus_blt_dstaddr, s->cirrus_blt_srcaddr, - s->sr[0x2f]); + s->gr[0x2f]); #endif switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { @@ -1042,10 +1042,10 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index) else offset <<= 12; - if (s->vram_size <= offset) + if (s->real_vram_size <= offset) limit = 0; else - limit = s->vram_size - offset; + limit = s->real_vram_size - offset; if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) { if (limit > 0x8000) { @@ -1213,7 +1213,7 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) #endif break; case 0x17: // Configuration Readback and Extended Control - s->sr[reg_index] = reg_value; + s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7); cirrus_update_memory_access(s); break; default: diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h index 5521870c8..a326f97b7 100644 --- a/hw/cirrus_vga_rop2.h +++ b/hw/cirrus_vga_rop2.h @@ -47,6 +47,7 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) int x, y, pattern_y, pattern_pitch, pattern_x; unsigned int col; const uint8_t *src1; + int skipleft = (s->gr[0x2f] & 0x07) * (DEPTH / 8); #if DEPTH == 8 pattern_pitch = 8; @@ -56,11 +57,11 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) pattern_pitch = 32; #endif pattern_y = s->cirrus_blt_srcaddr & 7; - pattern_x = 0; + pattern_x = skipleft; for(y = 0; y < bltheight; y++) { - d = dst; + d = dst + skipleft; src1 = src + pattern_y * pattern_pitch; - for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) { #if DEPTH == 8 col = src1[pattern_x]; pattern_x = (pattern_x + 1) & 7; @@ -99,7 +100,8 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) unsigned int col; unsigned bitmask; unsigned index; - int srcskipleft = 0; + int srcskipleft = s->gr[0x2f] & 0x07; + int dstskipleft = srcskipleft * (DEPTH / 8); if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { bits_xor = 0xff; @@ -112,8 +114,8 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) for(y = 0; y < bltheight; y++) { bitmask = 0x80 >> srcskipleft; bits = *src++ ^ bits_xor; - d = dst; - for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + d = dst + dstskipleft; + for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) { if ((bitmask & 0xff) == 0) { bitmask = 0x80; bits = *src++ ^ bits_xor; @@ -142,15 +144,16 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) unsigned bits; unsigned int col; unsigned bitmask; - int srcskipleft = 0; + int srcskipleft = s->gr[0x2f] & 0x07; + int dstskipleft = srcskipleft * (DEPTH / 8); colors[0] = s->cirrus_blt_bgcol; colors[1] = s->cirrus_blt_fgcol; for(y = 0; y < bltheight; y++) { bitmask = 0x80 >> srcskipleft; bits = *src++; - d = dst; - for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + d = dst + dstskipleft; + for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) { if ((bitmask & 0xff) == 0) { bitmask = 0x80; bits = *src++; @@ -175,6 +178,8 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) int x, y, bitpos, pattern_y; unsigned int bits, bits_xor; unsigned int col; + int srcskipleft = s->gr[0x2f] & 0x07; + int dstskipleft = srcskipleft * (DEPTH / 8); if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { bits_xor = 0xff; @@ -187,9 +192,9 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) for(y = 0; y < bltheight; y++) { bits = src[pattern_y] ^ bits_xor; - bitpos = 7; - d = dst; - for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + bitpos = 7 - srcskipleft; + d = dst + dstskipleft; + for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) { if ((bits >> bitpos) & 1) { PUTPIXEL(); } @@ -213,6 +218,8 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) int x, y, bitpos, pattern_y; unsigned int bits; unsigned int col; + int srcskipleft = s->gr[0x2f] & 0x07; + int dstskipleft = srcskipleft * (DEPTH / 8); colors[0] = s->cirrus_blt_bgcol; colors[1] = s->cirrus_blt_fgcol; @@ -220,9 +227,9 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) for(y = 0; y < bltheight; y++) { bits = src[pattern_y]; - bitpos = 7; - d = dst; - for (x = 0; x < bltwidth; x += (DEPTH / 8)) { + bitpos = 7 - srcskipleft; + d = dst + dstskipleft; + for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) { col = colors[(bits >> bitpos) & 1]; PUTPIXEL(); d += (DEPTH / 8); -- cgit v1.2.3 From 74ffc7729e3a1e1e328ba053a15cb5b7a5a605d1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 17 Apr 2005 18:32:14 +0000 Subject: removed unused stuff git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1365 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/exec-all.h b/exec-all.h index 263d4c2b0..4579da9f6 100644 --- a/exec-all.h +++ b/exec-all.h @@ -601,9 +601,6 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) #ifdef USE_KQEMU -extern int kqemu_fd; -extern int kqemu_flushed; - int kqemu_init(CPUState *env); int kqemu_cpu_exec(CPUState *env); void kqemu_flush_page(CPUState *env, target_ulong addr); -- cgit v1.2.3 From 6e4255f6a65091fbe7d17bfda546e2aa1b72f9a6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 17 Apr 2005 18:33:47 +0000 Subject: windows support for kqemu (Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1366 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ osdep.c | 25 +++++++++++++++++++------ 2 files changed, 74 insertions(+), 12 deletions(-) diff --git a/kqemu.c b/kqemu.c index 20aaf6376..1e0e86b51 100644 --- a/kqemu.c +++ b/kqemu.c @@ -20,9 +20,11 @@ #include "config.h" #ifdef _WIN32 #include +#include #else #include #include +#include #endif #include #include @@ -41,13 +43,25 @@ #include #include -#include #include "kqemu/kqemu.h" +#ifdef _WIN32 +#define KQEMU_DEVICE "\\\\.\\kqemu" +#else #define KQEMU_DEVICE "/dev/kqemu" +#endif + +#ifdef _WIN32 +#define KQEMU_INVALID_FD INVALID_HANDLE_VALUE +HANDLE kqemu_fd = KQEMU_INVALID_FD; +#define kqemu_closefd(x) CloseHandle(x) +#else +#define KQEMU_INVALID_FD -1 +int kqemu_fd = KQEMU_INVALID_FD; +#define kqemu_closefd(x) close(x) +#endif int kqemu_allowed = 1; -int kqemu_fd = -1; unsigned long *pages_to_flush; unsigned int nb_pages_to_flush; extern uint32_t **l1_phys_map; @@ -104,17 +118,32 @@ int kqemu_init(CPUState *env) { struct kqemu_init init; int ret, version; +#ifdef _WIN32 + DWORD temp; +#endif if (!kqemu_allowed) return -1; +#ifdef _WIN32 + kqemu_fd = CreateFile(KQEMU_DEVICE, GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL); +#else kqemu_fd = open(KQEMU_DEVICE, O_RDWR); - if (kqemu_fd < 0) { +#endif + if (kqemu_fd == KQEMU_INVALID_FD) { fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE); return -1; } version = 0; +#ifdef _WIN32 + DeviceIoControl(kqemu_fd, KQEMU_GET_VERSION, NULL, 0, + &version, sizeof(version), &temp, NULL); +#else ioctl(kqemu_fd, KQEMU_GET_VERSION, &version); +#endif if (version != KQEMU_VERSION) { fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n", version, KQEMU_VERSION); @@ -131,12 +160,17 @@ int kqemu_init(CPUState *env) init.ram_dirty = phys_ram_dirty; init.phys_to_ram_map = l1_phys_map; init.pages_to_flush = pages_to_flush; +#ifdef _WIN32 + ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init), + NULL, 0, &temp, NULL) == TRUE ? 0 : -1; +#else ret = ioctl(kqemu_fd, KQEMU_INIT, &init); +#endif if (ret < 0) { fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret); fail: - close(kqemu_fd); - kqemu_fd = -1; + kqemu_closefd(kqemu_fd); + kqemu_fd = KQEMU_INVALID_FD; return -1; } kqemu_update_cpuid(env); @@ -313,6 +347,9 @@ int kqemu_cpu_exec(CPUState *env) { struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; int ret; +#ifdef _WIN32 + DWORD temp; +#endif #ifdef DEBUG if (loglevel & CPU_LOG_INT) { @@ -354,8 +391,20 @@ int kqemu_cpu_exec(CPUState *env) restore_native_fp_frstor(env); } +#ifdef _WIN32 + DeviceIoControl(kqemu_fd, KQEMU_EXEC, + kenv, sizeof(struct kqemu_cpu_state), + kenv, sizeof(struct kqemu_cpu_state), + &temp, NULL); + ret = kenv->retval; +#else +#if KQEMU_VERSION >= 0x010100 + ioctl(kqemu_fd, KQEMU_EXEC, kenv); + ret = kenv->retval; +#else ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv); - +#endif +#endif if (!(kenv->cr0 & CR0_TS_MASK)) { if (env->cpuid_features & CPUID_FXSR) save_native_fp_fxsave(env); diff --git a/osdep.c b/osdep.c index ba6d5f38a..eef1ecbec 100644 --- a/osdep.c +++ b/osdep.c @@ -273,15 +273,13 @@ void *get_mmap_addr(unsigned long size) #else -#ifdef _BSD +#ifdef _WIN32 +#include +#elif defined(_BSD) #include #else #include #endif -#ifdef _WIN32 -/* XXX: find a solution to have page aligned data */ -#define memalign(align, size) malloc(size) -#endif int qemu_write(int fd, const void *buf, size_t n) { @@ -308,7 +306,22 @@ void *qemu_malloc(size_t size) return malloc(size); } -#if defined(USE_KQEMU) +#if defined(_WIN32) + +void *qemu_vmalloc(size_t size) +{ + /* FIXME: this is not exactly optimal solution since VirtualAlloc + has 64Kb granularity, but at least it guarantees us that the + memory is page aligned. */ + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); +} + +void qemu_vfree(void *ptr) +{ + VirtualFree(ptr, 0, MEM_RELEASE); +} + +#elif defined(USE_KQEMU) #include #include -- cgit v1.2.3 From 1fddef4b1ba3bf14d36472475019a4a6acd4d976 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 17 Apr 2005 19:16:13 +0000 Subject: gdb support for user mode (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1367 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 + exec.c | 12 ++-- gdbstub.c | 152 ++++++++++++++++++++++++++++++++++++++++++++----- gdbstub.h | 11 ++++ linux-user/main.c | 69 +++++++++++++++++++++- linux-user/qemu.h | 1 + linux-user/signal.c | 6 ++ target-arm/cpu.h | 7 +++ target-arm/op.c | 6 ++ target-arm/translate.c | 14 ++++- target-i386/cpu.h | 2 + target-ppc/cpu.h | 2 + target-sparc/cpu.h | 2 + vl.h | 7 +-- 14 files changed, 265 insertions(+), 29 deletions(-) create mode 100644 gdbstub.h diff --git a/Makefile.target b/Makefile.target index 16f649637..789848e53 100644 --- a/Makefile.target +++ b/Makefile.target @@ -298,6 +298,9 @@ endif ifeq ($(ARCH),ia64) OBJS += ia64-syscall.o endif +ifdef CONFIG_GDBSTUB +OBJS+=gdbstub.o +endif all: $(PROGS) diff --git a/exec.c b/exec.c index 264775e1e..f92304376 100644 --- a/exec.c +++ b/exec.c @@ -1076,7 +1076,7 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) +#if defined(TARGET_HAS_ICE) static void breakpoint_invalidate(CPUState *env, target_ulong pc) { target_ulong phys_addr; @@ -1090,7 +1090,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) { -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) +#if defined(TARGET_HAS_ICE) int i; for(i = 0; i < env->nb_breakpoints; i++) { @@ -1112,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) /* remove a breakpoint */ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) { -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) +#if defined(TARGET_HAS_ICE) int i; for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) @@ -1120,9 +1120,9 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) } return -1; found: - memmove(&env->breakpoints[i], &env->breakpoints[i + 1], - (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); env->nb_breakpoints--; + if (i < env->nb_breakpoints) + env->breakpoints[i] = env->breakpoints[env->nb_breakpoints]; breakpoint_invalidate(env, pc); return 0; @@ -1135,7 +1135,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc) CPU loop after each instruction */ void cpu_single_step(CPUState *env, int enabled) { -#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) +#if defined(TARGET_HAS_ICE) if (env->singlestep_enabled != enabled) { env->singlestep_enabled = enabled; /* must flush all the translated code to avoid inconsistancies */ diff --git a/gdbstub.c b/gdbstub.c index 1e95c7c08..5dc93c457 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -17,7 +17,18 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef CONFIG_USER_ONLY +#include +#include +#include +#include +#include +#include + +#include "qemu.h" +#else #include "vl.h" +#endif #include #include @@ -31,9 +42,10 @@ enum RSState { RS_GETLINE, RS_CHKSUM1, RS_CHKSUM2, + RS_CONTINUE }; - -static int gdbserver_fd; +/* XXX: This is not thread safe. Do we care? */ +static int gdbserver_fd = -1; typedef struct GDBState { enum RSState state; @@ -43,6 +55,11 @@ typedef struct GDBState { int line_csum; } GDBState; +#ifdef CONFIG_USER_ONLY +/* XXX: remove this hack. */ +static GDBState gdbserver_state; +#endif + static int get_char(GDBState *s) { uint8_t ch; @@ -330,8 +347,47 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->npc = tswapl(registers[69]); env->fsr = tswapl(registers[70]); } -#else +#elif defined (TARGET_ARM) +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + /* 16 core integer registers (4 bytes each). */ + for (i = 0; i < 16; i++) + { + *(uint32_t *)ptr = tswapl(env->regs[i]); + ptr += 4; + } + /* 8 FPA registers (12 bytes each), FPS (4 bytes). + Not yet implemented. */ + memset (ptr, 0, 8 * 12 + 4); + ptr += 8 * 12 + 4; + /* CPSR (4 bytes). */ + *(uint32_t *)ptr = tswapl (env->cpsr); + ptr += 4; + + return ptr - mem_buf; +} +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + /* Core integer registers. */ + for (i = 0; i < 16; i++) + { + env->regs[i] = tswapl(*(uint32_t *)ptr); + ptr += 4; + } + /* Ignore FPA regs and scr. */ + ptr += 8 * 12 + 4; + env->cpsr = tswapl(*(uint32_t *)ptr); +} +#else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { return 0; @@ -343,10 +399,8 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) #endif -/* port = 0 means default port */ -static int gdb_handle_packet(GDBState *s, const char *line_buf) +static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) { - CPUState *env = cpu_single_env; const char *p; int ch, reg_size, type; char buf[4096]; @@ -361,6 +415,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) ch = *p++; switch(ch) { case '?': + /* TODO: Make this return the correct value for user-mode. */ snprintf(buf, sizeof(buf), "S%02x", SIGTRAP); put_packet(s, buf); break; @@ -376,8 +431,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) env->npc = addr + 4; #endif } - vm_start(); - break; + return RS_CONTINUE; case 's': if (*p != '\0') { addr = strtoul(p, (char **)&p, 16); @@ -391,8 +445,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) #endif } cpu_single_step(env, 1); - vm_start(); - break; + return RS_CONTINUE; case 'g': reg_size = cpu_gdb_read_registers(env, mem_buf); memtohex(buf, mem_buf, reg_size); @@ -472,6 +525,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) extern void tb_flush(CPUState *env); +#ifndef CONFIG_USER_ONLY static void gdb_vm_stopped(void *opaque, int reason) { GDBState *s = opaque; @@ -490,17 +544,20 @@ static void gdb_vm_stopped(void *opaque, int reason) snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(s, buf); } +#endif -static void gdb_read_byte(GDBState *s, int ch) +static void gdb_read_byte(GDBState *s, CPUState *env, int ch) { int i, csum; char reply[1]; +#ifndef CONFIG_USER_ONLY if (vm_running) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ vm_stop(EXCP_INTERRUPT); } else { +#endif switch(s->state) { case RS_IDLE: if (ch == '$') { @@ -535,13 +592,67 @@ static void gdb_read_byte(GDBState *s, int ch) } else { reply[0] = '+'; put_buffer(s, reply, 1); - s->state = gdb_handle_packet(s, s->line_buf); + s->state = gdb_handle_packet(s, env, s->line_buf); } break; + case RS_CONTINUE: +#ifndef CONFIG_USER_ONLY + vm_start(); + s->state = RS_IDLE; +#endif + break; } +#ifndef CONFIG_USER_ONLY } +#endif } +#ifdef CONFIG_USER_ONLY +int +gdb_handlesig (CPUState *env, int sig) +{ + GDBState *s; + char buf[256]; + int n; + + if (gdbserver_fd < 0) + return sig; + + s = &gdbserver_state; + + /* disable single step if it was enabled */ + cpu_single_step(env, 0); + tb_flush(env); + + if (sig != 0) + { + snprintf(buf, sizeof(buf), "S%02x", sig); + put_packet(s, buf); + } + + /* TODO: How do we terminate this loop? */ + sig = 0; + s->state = RS_IDLE; + while (s->state != RS_CONTINUE) + { + n = read (s->fd, buf, 256); + if (n > 0) + { + int i; + + for (i = 0; i < n; i++) + gdb_read_byte (s, env, buf[i]); + } + else if (n == 0 || errno != EAGAIN) + { + /* XXX: Connection closed. Should probably wait for annother + connection before continuing. */ + return sig; + } + } + return sig; +} +#else static int gdb_can_read(void *opaque) { return 256; @@ -559,10 +670,12 @@ static void gdb_read(void *opaque, const uint8_t *buf, int size) vm_start(); } else { for(i = 0; i < size; i++) - gdb_read_byte(s, buf[i]); + gdb_read_byte(s, cpu_single_env, buf[i]); } } +#endif + static void gdb_accept(void *opaque, const uint8_t *buf, int size) { GDBState *s; @@ -585,15 +698,21 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) val = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); +#ifdef CONFIG_USER_ONLY + s = &gdbserver_state; + memset (s, 0, sizeof (GDBState)); +#else s = qemu_mallocz(sizeof(GDBState)); if (!s) { close(fd); return; } +#endif s->fd = fd; fcntl(fd, F_SETFL, O_NONBLOCK); +#ifndef CONFIG_USER_ONLY /* stop the VM */ vm_stop(EXCP_INTERRUPT); @@ -601,6 +720,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); /* when the VM is stopped, the following callback is called */ qemu_add_vm_stop_handler(gdb_vm_stopped, s); +#endif } static int gdbserver_open(int port) @@ -631,7 +751,9 @@ static int gdbserver_open(int port) perror("listen"); return -1; } +#ifndef CONFIG_USER_ONLY fcntl(fd, F_SETFL, O_NONBLOCK); +#endif return fd; } @@ -641,6 +763,10 @@ int gdbserver_start(int port) if (gdbserver_fd < 0) return -1; /* accept connections */ +#ifdef CONFIG_USER_ONLY + gdb_accept (NULL, NULL, 0); +#else qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); +#endif return 0; } diff --git a/gdbstub.h b/gdbstub.h new file mode 100644 index 000000000..63b88dadc --- /dev/null +++ b/gdbstub.h @@ -0,0 +1,11 @@ +#ifndef GDBSTUB_H +#define GDBSTUB_H + +#define DEFAULT_GDBSTUB_PORT 1234 + +#ifdef CONFIG_USER_ONLY +int gdb_handlesig (CPUState *, int); +#endif +int gdbserver_start(int); + +#endif diff --git a/linux-user/main.c b/linux-user/main.c index 126a9193e..0dcffb186 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -278,6 +278,20 @@ void cpu_loop(CPUX86State *env) case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; default: pc = env->segs[R_CS].base + env->eip; fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", @@ -379,6 +393,20 @@ void cpu_loop(CPUARMState *env) queue_signal(info.si_signo, &info); } break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; default: error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", @@ -529,6 +557,20 @@ void cpu_loop (CPUSPARCState *env) break; case 0x100: // XXX, why do we get these? break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); @@ -911,8 +953,20 @@ void cpu_loop(CPUPPCState *env) case EXCP_INTERRUPT: /* Don't know why this should ever happen... */ break; - case EXCP_DEBUG: - break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; default: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); @@ -930,10 +984,11 @@ void cpu_loop(CPUPPCState *env) void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" - "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n" + "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" "-h print this help\n" + "-g wait gdb connection to port %d\n" "-L path set the elf interpreter prefix (default=%s)\n" "-s size set the stack size in bytes (default=%ld)\n" "\n" @@ -944,6 +999,7 @@ void usage(void) "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n", TARGET_ARCH, + DEFAULT_GDBSTUB_PORT, interp_prefix, x86_stack_size, DEBUG_LOGFILE); @@ -967,6 +1023,7 @@ int main(int argc, char **argv) CPUState *env; int optind; const char *r; + int use_gdbstub = 0; if (argc <= 1) usage(); @@ -1020,6 +1077,8 @@ int main(int argc, char **argv) fprintf(stderr, "page size must be a power of two\n"); exit(1); } + } else if (!strcmp(r, "g")) { + use_gdbstub = 1; } else #ifdef USE_CODE_COPY if (!strcmp(r, "no-code-copy")) { @@ -1176,6 +1235,10 @@ int main(int argc, char **argv) #error unsupported target CPU #endif + if (use_gdbstub) { + gdbserver_start (DEFAULT_GDBSTUB_PORT); + gdb_handlesig(env, 0); + } cpu_loop(env); /* never exits */ return 0; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index c176a58aa..2a815eb81 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -9,6 +9,7 @@ #include "cpu.h" #include "syscall.h" +#include "gdbstub.h" /* This struct is used to hold certain information about the image. * Basically, it replicates in user space what would be certain diff --git a/linux-user/signal.c b/linux-user/signal.c index 7a904ad00..a7c06c9fb 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1675,6 +1675,12 @@ void process_pending_signals(void *cpu_env) k->first = q->next; if (!k->first) k->pending = 0; + + sig = gdb_handlesig (cpu_env, sig); + if (!sig) { + fprintf (stderr, "Lost signal\n"); + abort(); + } handler = k->sa._sa_handler; if (handler == TARGET_SIG_DFL) { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 134617513..ef7469d0c 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -26,6 +26,8 @@ #include "softfloat.h" +#define TARGET_HAS_ICE 1 + #define EXCP_UDEF 1 /* undefined instruction */ #define EXCP_SWI 2 /* software interrupt */ #define EXCP_PREFETCH_ABORT 3 @@ -62,6 +64,11 @@ typedef struct CPUARMState { int user_mode_only; uint32_t address; + /* ICE debug support. */ + target_ulong breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; + int singlestep_enabled; + /* in order to avoid passing too many arguments to the memory write helpers, we store some rarely used information in the CPU context) */ diff --git a/target-arm/op.c b/target-arm/op.c index 42ee4f960..f4cbb6e66 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -858,6 +858,12 @@ void OPPROTO op_undef_insn(void) cpu_loop_exit(); } +void OPPROTO op_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + /* VFP support. We follow the convention used for VFP instrunctions: Single precition routines have a "s" suffix, double precision a "d" suffix. */ diff --git a/target-arm/translate.c b/target-arm/translate.c index 39c28e754..280b68c4c 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2026,6 +2026,17 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->pc = pc_start; lj = -1; do { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == dc->pc) { + gen_op_movl_T0_im((long)dc->pc); + gen_op_movl_reg_TN[0][15](); + gen_op_debug(); + dc->is_jmp = DISAS_JUMP; + break; + } + } + } if (search_pc) { j = gen_opc_ptr - gen_opc_buf; if (lj < j) { @@ -2040,7 +2051,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, disas_thumb_insn(dc); else disas_arm_insn(env, dc); - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + !env->singlestep_enabled && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); switch(dc->is_jmp) { case DISAS_JUMP_NEXT: diff --git a/target-i386/cpu.h b/target-i386/cpu.h index ce65c3430..d0157ce8d 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -34,6 +34,8 @@ close to the modifying instruction */ #define TARGET_HAS_PRECISE_SMC +#define TARGET_HAS_ICE 1 + #include "cpu-defs.h" #include "softfloat.h" diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 70ee83507..12f7c1720 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -29,6 +29,8 @@ #include "softfloat.h" +#define TARGET_HAS_ICE 1 + /* Instruction types */ enum { PPC_NONE = 0x0000, diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 67a6e3e46..b556e23e4 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -17,6 +17,8 @@ #include "softfloat.h" +#define TARGET_HAS_ICE 1 + /*#define EXCP_INTERRUPT 0x100*/ /* trap definitions */ diff --git a/vl.h b/vl.h index 5091ca14e..0fe94ac6e 100644 --- a/vl.h +++ b/vl.h @@ -71,6 +71,7 @@ static inline char *realpath(const char *path, char *resolved_path) #else #include "cpu.h" +#include "gdbstub.h" #endif /* !defined(QEMU_TOOL) */ @@ -829,10 +830,4 @@ const char *readline_get_history(unsigned int index); void readline_start(const char *prompt, int is_password, ReadLineFunc *readline_func, void *opaque); -/* gdbstub.c */ - -#define DEFAULT_GDBSTUB_PORT 1234 - -int gdbserver_start(int port); - #endif /* VL_H */ -- cgit v1.2.3 From cc6f538bf6768cec1383c72e864f547ad9f04e30 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 17 Apr 2005 19:49:02 +0000 Subject: verr and verw eflags opt fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1368 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index ad5acc9c4..e6a7f6a7b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6012,6 +6012,8 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_cmpxchg8b] = CC_Z, [INDEX_op_lar] = CC_Z, [INDEX_op_lsl] = CC_Z, + [INDEX_op_verr] = CC_Z, + [INDEX_op_verw] = CC_Z, [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, -- cgit v1.2.3 From 5516d670f69dafc77c936a02ff9916a9fba9fcd0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 17 Apr 2005 19:50:21 +0000 Subject: make lsl, lar verr and verw exception safe git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1369 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 78 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index b358c2ecf..2c852090a 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2335,13 +2335,13 @@ void helper_rdmsr(void) void helper_lsl(void) { unsigned int selector, limit; - uint32_t e1, e2; + uint32_t e1, e2, eflags; int rpl, dpl, cpl, type; - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + eflags = cc_table[CC_OP].compute_all(); selector = T0 & 0xffff; if (load_segment(&e1, &e2, selector) != 0) - return; + goto fail; rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; @@ -2350,7 +2350,7 @@ void helper_lsl(void) /* conforming */ } else { if (dpl < cpl || dpl < rpl) - return; + goto fail; } } else { type = (e2 >> DESC_TYPE_SHIFT) & 0xf; @@ -2362,28 +2362,31 @@ void helper_lsl(void) case 11: break; default: - return; + goto fail; } - if (dpl < cpl || dpl < rpl) + if (dpl < cpl || dpl < rpl) { + fail: + CC_SRC = eflags & ~CC_Z; return; + } } limit = get_seg_limit(e1, e2); T1 = limit; - CC_SRC |= CC_Z; + CC_SRC = eflags | CC_Z; } void helper_lar(void) { unsigned int selector; - uint32_t e1, e2; + uint32_t e1, e2, eflags; int rpl, dpl, cpl, type; - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + eflags = cc_table[CC_OP].compute_all(); selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) - return; + goto fail; if (load_segment(&e1, &e2, selector) != 0) - return; + goto fail; rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; @@ -2392,7 +2395,7 @@ void helper_lar(void) /* conforming */ } else { if (dpl < cpl || dpl < rpl) - return; + goto fail; } } else { type = (e2 >> DESC_TYPE_SHIFT) & 0xf; @@ -2407,72 +2410,81 @@ void helper_lar(void) case 12: break; default: - return; + goto fail; } - if (dpl < cpl || dpl < rpl) + if (dpl < cpl || dpl < rpl) { + fail: + CC_SRC = eflags & ~CC_Z; return; + } } T1 = e2 & 0x00f0ff00; - CC_SRC |= CC_Z; + CC_SRC = eflags | CC_Z; } void helper_verr(void) { unsigned int selector; - uint32_t e1, e2; + uint32_t e1, e2, eflags; int rpl, dpl, cpl; - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + eflags = cc_table[CC_OP].compute_all(); selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) - return; + goto fail; if (load_segment(&e1, &e2, selector) != 0) - return; + goto fail; if (!(e2 & DESC_S_MASK)) - return; + goto fail; rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; if (e2 & DESC_CS_MASK) { if (!(e2 & DESC_R_MASK)) - return; + goto fail; if (!(e2 & DESC_C_MASK)) { if (dpl < cpl || dpl < rpl) - return; + goto fail; } } else { - if (dpl < cpl || dpl < rpl) + if (dpl < cpl || dpl < rpl) { + fail: + CC_SRC = eflags & ~CC_Z; return; + } } - CC_SRC |= CC_Z; + CC_SRC = eflags | CC_Z; } void helper_verw(void) { unsigned int selector; - uint32_t e1, e2; + uint32_t e1, e2, eflags; int rpl, dpl, cpl; - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; + eflags = cc_table[CC_OP].compute_all(); selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) - return; + goto fail; if (load_segment(&e1, &e2, selector) != 0) - return; + goto fail; if (!(e2 & DESC_S_MASK)) - return; + goto fail; rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; if (e2 & DESC_CS_MASK) { - return; + goto fail; } else { if (dpl < cpl || dpl < rpl) + goto fail; + if (!(e2 & DESC_W_MASK)) { + fail: + CC_SRC = eflags & ~CC_Z; return; - if (!(e2 & DESC_W_MASK)) - return; + } } - CC_SRC |= CC_Z; + CC_SRC = eflags | CC_Z; } /* FPU helpers */ -- cgit v1.2.3 From 07f4ddbf7ead5e01316b3579f7d7a11ac1f9489d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 17:44:28 +0000 Subject: kqemu build fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1370 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++++ configure | 26 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index bc978167c..6fc4d9aa3 100644 --- a/Makefile +++ b/Makefile @@ -18,8 +18,12 @@ all: dyngen$(EXESUF) $(TOOLS) $(DOCS) $(MAKE) -C $$d $@ || exit 1 ; \ done ifdef CONFIG_KQEMU +ifdef CONFIG_WIN32 + $(MAKE) -C kqemu -f Makefile.winnt +else $(MAKE) -C kqemu endif +endif qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) diff --git a/configure b/configure index 585d2114c..7ef930067 100755 --- a/configure +++ b/configure @@ -94,6 +94,9 @@ mingw32="yes" FreeBSD) bsd="yes" oss="yes" +if [ "$cpu" = "i386" ] ; then + kqemu="yes" +fi ;; NetBSD) bsd="yes" @@ -110,7 +113,7 @@ darwin="yes" *) oss="yes" linux="yes" -if [ "$cpu" = "i386" ] ; then +if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" fi ;; @@ -198,7 +201,9 @@ if test "$mingw32" = "yes" ; then EXESUF=".exe" gdbstub="no" oss="no" - kqemu="no" + if [ "$cpu" = "i386" ] ; then + kqemu="yes" + fi fi if test -z "$target_list" ; then @@ -350,7 +355,7 @@ docdir="$prefix/share/doc/qemu" bindir="$prefix/bin" fi -# kernel module support +# kqemu support if test $kqemu = "yes" ; then # test if the source code is installed if test '!' -f "kqemu/Makefile" ; then @@ -358,7 +363,8 @@ if test $kqemu = "yes" ; then fi fi -if test $kqemu = "yes" ; then +# Linux specific kqemu configuration +if test $kqemu = "yes" -a $linux = "yes" ; then # find the kernel path if test -z "$kernel_path" ; then kernel_version=`uname -r` @@ -388,7 +394,7 @@ fi fi # kqemu -fi # kqemu +fi # kqemu and linux echo "Install prefix $prefix" @@ -418,9 +424,10 @@ if test $fmod = "yes"; then echo -n " (lib='$fmod_lib' include='$fmod_inc')" fi echo "" -if test $kqemu = "yes" ; then +echo "kqemu support $kqemu" +if test $kqemu = "yes" -a $linux = "yes" ; then echo "" -echo "KQEMU module configuration:" +echo "KQEMU Linux module configuration:" echo "kernel sources $kernel_path" echo -n "kbuild type " if test $kbuild26 = "yes"; then @@ -617,7 +624,7 @@ 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" ; then + 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 @@ -642,6 +649,9 @@ elif test "$target_cpu" = "x86_64" ; then 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 else echo "Unsupported target CPU" exit 1 -- cgit v1.2.3 From c28e951fc797115eb7c79d31519215f5d79efea2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 17:45:43 +0000 Subject: x86_64 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1371 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 9 deletions(-) diff --git a/kqemu.c b/kqemu.c index 1e0e86b51..f882c8b2f 100644 --- a/kqemu.c +++ b/kqemu.c @@ -45,6 +45,11 @@ #include #include "kqemu/kqemu.h" +/* compatibility stuff */ +#ifndef KQEMU_RET_SYSCALL +#define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */ +#endif + #ifdef _WIN32 #define KQEMU_DEVICE "\\\\.\\kqemu" #else @@ -71,6 +76,12 @@ extern uint32_t **l1_phys_map; : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \ : "0" (index)) +#ifdef __x86_64__ +static int is_cpuid_supported(void) +{ + return 1; +} +#else static int is_cpuid_supported(void) { int v0, v1; @@ -87,6 +98,7 @@ static int is_cpuid_supported(void) : "cc"); return (v0 != v1); } +#endif static void kqemu_update_cpuid(CPUState *env) { @@ -231,8 +243,8 @@ struct fpxstate { uint32_t mxcsr; uint32_t mxcsr_mask; uint8_t fpregs1[8 * 16]; - uint8_t xmm_regs[8 * 16]; - uint8_t dummy2[224]; + uint8_t xmm_regs[16 * 16]; + uint8_t dummy2[96]; }; static struct fpxstate fpx1 __attribute__((aligned(16))); @@ -308,7 +320,7 @@ static void restore_native_fp_fxrstor(CPUState *env) fp->mxcsr = env->mxcsr; /* XXX: check if DAZ is not available */ fp->mxcsr_mask = 0xffff; - memcpy(fp->xmm_regs, env->xmm_regs, 8 * 16); + memcpy(fp->xmm_regs, env->xmm_regs, CPU_NB_REGS * 16); } asm volatile ("fxrstor %0" : "=m" (*fp)); } @@ -334,7 +346,7 @@ static void save_native_fp_fxsave(CPUState *env) } if (env->cpuid_features & CPUID_SSE) { env->mxcsr = fp->mxcsr; - memcpy(env->xmm_regs, fp->xmm_regs, 8 * 16); + memcpy(env->xmm_regs, fp->xmm_regs, CPU_NB_REGS * 16); } /* we must restore the default rounding state */ @@ -343,6 +355,55 @@ static void save_native_fp_fxsave(CPUState *env) asm volatile("fldcw %0" : : "m" (fpuc)); } +static int do_syscall(CPUState *env, + struct kqemu_cpu_state *kenv) +{ + int selector; + + selector = (env->star >> 32) & 0xffff; +#ifdef __x86_64__ + if (env->hflags & HF_LMA_MASK) { + env->regs[R_ECX] = kenv->next_eip; + env->regs[11] = env->eflags; + + cpu_x86_set_cpl(env, 0); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + env->eflags &= ~env->fmask; + if (env->hflags & HF_CS64_MASK) + env->eip = env->lstar; + else + env->eip = env->cstar; + } else +#endif + { + env->regs[R_ECX] = (uint32_t)kenv->next_eip; + + cpu_x86_set_cpl(env, 0); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); + env->eip = (uint32_t)env->star; + } + return 2; +} + int kqemu_cpu_exec(CPUState *env) { struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; @@ -370,6 +431,9 @@ int kqemu_cpu_exec(CPUState *env) kenv->cr3 = env->cr[3]; kenv->cr4 = env->cr[4]; kenv->a20_mask = env->a20_mask; +#ifdef __x86_64__ + kenv->efer = env->efer; +#endif if (env->dr[7] & 0xff) { kenv->dr7 = env->dr[7]; kenv->dr0 = env->dr[0]; @@ -435,17 +499,21 @@ int kqemu_cpu_exec(CPUState *env) fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret); } #endif + if (ret == KQEMU_RET_SYSCALL) { + /* syscall instruction */ + return do_syscall(env, kenv); + } else if ((ret & 0xff00) == KQEMU_RET_INT) { env->exception_index = ret & 0xff; env->error_code = 0; env->exception_is_int = 1; env->exception_next_eip = kenv->next_eip; #ifdef DEBUG - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "kqemu: interrupt v=%02x:\n", - env->exception_index); - cpu_dump_state(env, logfile, fprintf, 0); - } + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "kqemu: interrupt v=%02x:\n", + env->exception_index); + cpu_dump_state(env, logfile, fprintf, 0); + } #endif return 1; } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) { -- cgit v1.2.3 From 8d9bfc2b48b74962a9ee698edff9b0d9a0671c36 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 17:46:55 +0000 Subject: enable EFER usage in i386 emulation - more cpuid bits git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1372 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index d0157ce8d..354951110 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -258,6 +258,7 @@ #define CPUID_EXT2_SYSCALL (1 << 11) #define CPUID_EXT2_NX (1 << 20) +#define CPUID_EXT2_FFXSR (1 << 25) #define CPUID_EXT2_LM (1 << 29) #define EXCP00_DIVZ 0 @@ -464,9 +465,9 @@ typedef struct CPUX86State { uint32_t sysenter_cs; uint32_t sysenter_esp; uint32_t sysenter_eip; + uint64_t efer; + uint64_t star; #ifdef TARGET_X86_64 - target_ulong efer; - target_ulong star; target_ulong lstar; target_ulong cstar; target_ulong fmask; @@ -510,13 +511,17 @@ typedef struct CPUX86State { int singlestep_enabled; /* processor features (e.g. for CPUID insn) */ + uint32_t cpuid_level; uint32_t cpuid_vendor1; uint32_t cpuid_vendor2; uint32_t cpuid_vendor3; uint32_t cpuid_version; uint32_t cpuid_features; uint32_t cpuid_ext_features; - + uint32_t cpuid_xlevel; + uint32_t cpuid_model[12]; + uint32_t cpuid_ext2_features; + #ifdef USE_KQEMU int kqemu_enabled; #endif -- cgit v1.2.3 From f419b32104ef9da81b52143cc10e90f235c2441a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 17:48:47 +0000 Subject: sysret fix - better cpuid support - lcall support for x86_64 - efer access in i386 emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1373 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 149 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 110 insertions(+), 39 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 2c852090a..ee3f670b5 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -933,6 +933,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, } env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); } +#endif void helper_syscall(int next_eip_addend) { @@ -942,6 +943,7 @@ void helper_syscall(int next_eip_addend) raise_exception_err(EXCP06_ILLOP, 0); } selector = (env->star >> 32) & 0xffff; +#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { ECX = env->eip + next_eip_addend; env->regs[11] = compute_eflags(); @@ -962,7 +964,9 @@ void helper_syscall(int next_eip_addend) env->eip = env->lstar; else env->eip = env->cstar; - } else { + } else +#endif + { ECX = (uint32_t)(env->eip + next_eip_addend); cpu_x86_set_cpl(env, 0); @@ -985,11 +989,15 @@ void helper_sysret(int dflag) { int cpl, selector; + if (!(env->efer & MSR_EFER_SCE)) { + raise_exception_err(EXCP06_ILLOP, 0); + } cpl = env->hflags & HF_CPL_MASK; if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { raise_exception_err(EXCP0D_GPF, 0); } selector = (env->star >> 48) & 0xffff; +#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { if (dflag == 2) { cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, @@ -1015,7 +1023,9 @@ void helper_sysret(int dflag) load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); cpu_x86_set_cpl(env, 3); - } else { + } else +#endif + { cpu_x86_load_seg_cache(env, R_CS, selector | 3, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | @@ -1030,8 +1040,15 @@ void helper_sysret(int dflag) env->eflags |= IF_MASK; cpu_x86_set_cpl(env, 3); } -} +#ifdef USE_KQEMU + if (kqemu_is_ok(env)) { + if (env->hflags & HF_LMA_MASK) + CC_OP = CC_OP_EFLAGS; + env->exception_index = -1; + cpu_loop_exit(); + } #endif +} /* real mode interrupt */ static void do_interrupt_real(int intno, int is_int, int error_code, @@ -1265,9 +1282,21 @@ void helper_cmpxchg8b(void) void helper_cpuid(void) { - switch((uint32_t)EAX) { + uint32_t index; + index = (uint32_t)EAX; + + /* test if maximum index reached */ + if (index & 0x80000000) { + if (index > env->cpuid_xlevel) + index = env->cpuid_level; + } else { + if (index > env->cpuid_level) + index = env->cpuid_level; + } + + switch(index) { case 0: - EAX = 2; /* max EAX index supported */ + EAX = env->cpuid_level; EBX = env->cpuid_vendor1; EDX = env->cpuid_vendor2; ECX = env->cpuid_vendor3; @@ -1278,16 +1307,15 @@ void helper_cpuid(void) ECX = env->cpuid_ext_features; EDX = env->cpuid_features; break; - default: + case 2: /* cache info: needed for Pentium Pro compatibility */ EAX = 0x410601; EBX = 0; ECX = 0; EDX = 0; break; -#ifdef TARGET_X86_64 case 0x80000000: - EAX = 0x80000008; + EAX = env->cpuid_xlevel; EBX = env->cpuid_vendor1; EDX = env->cpuid_vendor2; ECX = env->cpuid_vendor3; @@ -1296,8 +1324,15 @@ void helper_cpuid(void) EAX = env->cpuid_features; EBX = 0; ECX = 0; - /* long mode + syscall/sysret features */ - EDX = (env->cpuid_features & 0x0183F3FF) | (1 << 29) | (1 << 11); + EDX = env->cpuid_ext2_features; + break; + case 0x80000002: + case 0x80000003: + case 0x80000004: + EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0]; + EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1]; + ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2]; + EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3]; break; case 0x80000008: /* virtual & phys address size in low 2 bytes. */ @@ -1306,7 +1341,13 @@ void helper_cpuid(void) ECX = 0; EDX = 0; break; -#endif + default: + /* reserved values: zero */ + EAX = 0; + EBX = 0; + ECX = 0; + EDX = 0; + break; } } @@ -1523,11 +1564,11 @@ void load_seg(int seg_reg, int selector) } /* protected mode jump */ -void helper_ljmp_protected_T0_T1(int next_eip) +void helper_ljmp_protected_T0_T1(int next_eip_addend) { int new_cs, gate_cs, type; uint32_t e1, e2, cpl, dpl, rpl, limit; - target_ulong new_eip; + target_ulong new_eip, next_eip; new_cs = T0; new_eip = T1; @@ -1573,6 +1614,7 @@ void helper_ljmp_protected_T0_T1(int next_eip) case 5: /* task gate */ if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + next_eip = env->eip + next_eip_addend; switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); break; case 4: /* 286 call gate */ @@ -1638,16 +1680,17 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) } /* protected mode call */ -void helper_lcall_protected_T0_T1(int shift, int next_eip) +void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) { int new_cs, new_eip, new_stack, i; uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; uint32_t val, limit, old_sp_mask; - target_ulong ssp, old_ssp; + target_ulong ssp, old_ssp, next_eip; new_cs = T0; new_eip = T1; + next_eip = env->eip + next_eip_addend; #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_PCALL) { fprintf(logfile, "lcall %04x:%08x s=%d\n", @@ -1684,25 +1727,43 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - sp = ESP; - sp_mask = get_sp_mask(env->segs[R_SS].flags); - ssp = env->segs[R_SS].base; - if (shift) { - PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); - PUSHL(ssp, sp, sp_mask, next_eip); - } else { - PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); - PUSHW(ssp, sp, sp_mask, next_eip); +#ifdef TARGET_X86_64 + /* XXX: check 16/32 bit cases in long mode */ + if (shift == 2) { + target_ulong rsp; + /* 64 bit case */ + rsp = ESP; + PUSHQ(rsp, env->segs[R_CS].selector); + PUSHQ(rsp, next_eip); + /* from this point, not restartable */ + ESP = rsp; + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), + get_seg_limit(e1, e2), e2); + EIP = new_eip; + } else +#endif + { + sp = ESP; + sp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + if (shift) { + PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHL(ssp, sp, sp_mask, next_eip); + } else { + PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); + PUSHW(ssp, sp, sp_mask, next_eip); + } + + limit = get_seg_limit(e1, e2); + if (new_eip > limit) + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); + /* from this point, not restartable */ + ESP = (ESP & ~sp_mask) | (sp & sp_mask); + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, + get_seg_base(e1, e2), limit, e2); + EIP = new_eip; } - - limit = get_seg_limit(e1, e2); - if (new_eip > limit) - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); - /* from this point, not restartable */ - ESP = (ESP & ~sp_mask) | (sp & sp_mask); - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), limit, e2); - EIP = new_eip; } else { /* check gate type */ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; @@ -2245,16 +2306,26 @@ void helper_wrmsr(void) case MSR_IA32_APICBASE: cpu_set_apic_base(env, val); break; -#ifdef TARGET_X86_64 case MSR_EFER: -#define MSR_EFER_UPDATE_MASK (MSR_EFER_SCE | MSR_EFER_LME | \ - MSR_EFER_NXE | MSR_EFER_FFXSR) - env->efer = (env->efer & ~MSR_EFER_UPDATE_MASK) | - (val & MSR_EFER_UPDATE_MASK); + { + uint64_t update_mask; + update_mask = 0; + if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) + update_mask |= MSR_EFER_SCE; + if (env->cpuid_ext2_features & CPUID_EXT2_LM) + update_mask |= MSR_EFER_LME; + if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) + update_mask |= MSR_EFER_FFXSR; + if (env->cpuid_ext2_features & CPUID_EXT2_NX) + update_mask |= MSR_EFER_NXE; + env->efer = (env->efer & ~update_mask) | + (val & update_mask); + } break; case MSR_STAR: env->star = val; break; +#ifdef TARGET_X86_64 case MSR_LSTAR: env->lstar = val; break; @@ -2296,13 +2367,13 @@ void helper_rdmsr(void) case MSR_IA32_APICBASE: val = cpu_get_apic_base(env); break; -#ifdef TARGET_X86_64 case MSR_EFER: val = env->efer; break; case MSR_STAR: val = env->star; break; +#ifdef TARGET_X86_64 case MSR_LSTAR: val = env->lstar; break; -- cgit v1.2.3 From a6f379881e1acae7708ef647f4b9c921ed054ae8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 17:50:32 +0000 Subject: return model id in cpuid for x86_64 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1374 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 730af1b52..24cbcfc4e 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -102,15 +102,32 @@ CPUX86State *cpu_x86_init(void) stepping = 3; #endif #endif + env->cpuid_level = 2; env->cpuid_version = (family << 8) | (model << 4) | stepping; env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV); env->cpuid_ext_features = 0; env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP; + env->cpuid_xlevel = 0; + { + const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION; + int c, len, i; + len = strlen(model_id); + for(i = 0; i < 48; i++) { + if (i >= len) + c = '\0'; + else + c = model_id[i]; + env->cpuid_model[i >> 2] |= c << (8 * (i & 3)); + } + } #ifdef TARGET_X86_64 /* currently not enabled for std i386 because not fully tested */ env->cpuid_features |= CPUID_APIC; + env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF); + env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL; + env->cpuid_xlevel = 0x80000008; #endif } cpu_single_env = env; -- cgit v1.2.3 From aba9d61e34b9d43b856fd758d70f38e99e026cab Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 17:53:12 +0000 Subject: lcall and ljmp fixes in 64 bit mode - sysret fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1375 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index e6a7f6a7b..c4584a012 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2231,6 +2231,16 @@ static void gen_movtl_T1_im(target_ulong val) #endif } +static void gen_add_A0_im(DisasContext *s, int val) +{ +#ifdef TARGET_X86_64 + if (CODE64(s)) + gen_op_addq_A0_im(val); + else +#endif + gen_op_addl_A0_im(val); +} + static GenOpFunc1 *gen_ldq_env_A0[3] = { gen_op_ldq_raw_env_A0, #ifndef CONFIG_USER_ONLY @@ -3382,9 +3392,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; } if (CODE64(s)) { - if (op >= 2 && op <= 5) { + if (op == 2 || op == 4) { /* operand size for jumps is 64 bit */ ot = OT_QUAD; + } else if (op == 3 || op == 5) { + /* for call calls, the operand is 16 or 32 bit, even + in long mode */ + ot = dflag ? OT_LONG : OT_WORD; } else if (op == 6) { /* default push size is 64 bit */ ot = dflag ? OT_QUAD : OT_WORD; @@ -3425,14 +3439,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 3: /* lcall Ev */ gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); do_lcall: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base); + gen_op_lcall_protected_T0_T1(dflag, s->pc - pc_start); } else { gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); } @@ -3446,14 +3460,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 5: /* ljmp Ev */ gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); do_ljmp: if (s->pe && !s->vm86) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_ljmp_protected_T0_T1(s->pc - s->cs_base); + gen_op_ljmp_protected_T0_T1(s->pc - pc_start); } else { gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); gen_op_movl_T0_T1(); @@ -4043,7 +4057,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[ot + s->mem_index](); - gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ gen_op_ldu_T0_A0[OT_WORD + s->mem_index](); gen_movl_seg_T0(s, op, pc_start - s->cs_base); @@ -5182,7 +5196,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_into(s->pc - pc_start); break; case 0xf1: /* icebp (undocumented, exits to external debugger) */ +#if 1 gen_debug(s, pc_start - s->cs_base); +#else + /* start debug */ + tb_flush(cpu_single_env); + cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM); +#endif break; case 0xfa: /* cli */ if (!s->vm86) { @@ -5363,6 +5383,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } gen_jmp_im(pc_start - s->cs_base); gen_op_sysret(s->dflag); + /* condition codes are modified only in long mode */ + if (s->lma) + s->cc_op = CC_OP_EFLAGS; gen_eob(s); } break; @@ -5458,12 +5481,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) else gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); gen_op_st_T0_A0[OT_WORD + s->mem_index](); -#ifdef TARGET_X86_64 - if (CODE64(s)) - gen_op_addq_A0_im(2); - else -#endif - gen_op_addl_A0_im(2); + gen_add_A0_im(s, 2); if (op == 0) gen_op_movtl_T0_env(offsetof(CPUX86State,gdt.base)); else @@ -5481,12 +5499,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } else { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[OT_WORD + s->mem_index](); -#ifdef TARGET_X86_64 - if (CODE64(s)) - gen_op_addq_A0_im(2); - else -#endif - gen_op_addl_A0_im(2); + gen_add_A0_im(s, 2); gen_op_ld_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); if (!s->dflag) gen_op_andl_T0_im(0xffffff); -- cgit v1.2.3 From e06e5259c3226f1e2408eb8bb940ee4fe5697f4c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 17:54:59 +0000 Subject: lretq, lcall and ljmp tests in 64 bit mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1376 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386-code16.S | 18 ------------- tests/test-i386.c | 68 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/tests/test-i386-code16.S b/tests/test-i386-code16.S index 78ecc1f77..e400e73fd 100644 --- a/tests/test-i386-code16.S +++ b/tests/test-i386-code16.S @@ -77,21 +77,3 @@ myfunc2: code16_end: - - -/* other 32 bits tests */ - .code32 - - .globl func_lret32 -func_lret32: - movl $0x87654321, %eax - lret - - .globl func_iret32 -func_iret32: - movl $0xabcd4321, %eax - iret - - - - \ No newline at end of file diff --git a/tests/test-i386.c b/tests/test-i386.c index 5e6e6c624..310a93aeb 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1321,8 +1321,25 @@ void test_code16(void) } #endif -extern char func_lret32; -extern char func_iret32; +#if defined(__x86_64__) +asm(".globl func_lret\n" + "func_lret:\n" + "movl $0x87654641, %eax\n" + "lretq\n"); +#else +asm(".globl func_lret\n" + "func_lret:\n" + "movl $0x87654321, %eax\n" + "lret\n" + + ".globl func_iret\n" + "func_iret:\n" + "movl $0xabcd4321, %eax\n" + "iret\n"); +#endif + +extern char func_lret; +extern char func_iret; void test_misc(void) { @@ -1334,16 +1351,53 @@ void test_misc(void) asm ("xlat" : "=a" (res) : "b" (table), "0" (res)); printf("xlat: EAX=" FMTLX "\n", res); -#if !defined(__x86_64__) +#if defined(__x86_64__) + { + static struct __attribute__((packed)) { + uint32_t offset; + uint16_t seg; + } desc; + long cs_sel; + + asm volatile ("mov %%cs, %0" : "=r" (cs_sel)); + + asm volatile ("push %1\n" + "call func_lret\n" + : "=a" (res) + : "r" (cs_sel) : "memory", "cc"); + printf("func_lret=" FMTLX "\n", res); + + /* NOTE: we assume that &func_lret < 4GB */ + desc.offset = (long)&func_lret; + desc.seg = cs_sel; + + asm volatile ("xor %%rax, %%rax\n" + "rex64 lcall %1\n" + : "=a" (res) + : "m" (desc) + : "memory", "cc"); + printf("func_lret2=" FMTLX "\n", res); + + asm volatile ("push %2\n" + "mov $ 1f, %%rax\n" + "push %%rax\n" + "ljmp %1\n" + "1:\n" + : "=a" (res) + : "m" (desc), "b" (cs_sel) + : "memory", "cc"); + printf("func_lret3=" FMTLX "\n", res); + } +#else asm volatile ("push %%cs ; call %1" : "=a" (res) - : "m" (func_lret32): "memory", "cc"); - printf("func_lret32=" FMTLX "\n", res); + : "m" (func_lret): "memory", "cc"); + printf("func_lret=" FMTLX "\n", res); asm volatile ("pushf ; push %%cs ; call %1" : "=a" (res) - : "m" (func_iret32): "memory", "cc"); - printf("func_iret32=" FMTLX "\n", res); + : "m" (func_iret): "memory", "cc"); + printf("func_iret=" FMTLX "\n", res); #endif #if defined(__x86_64__) -- cgit v1.2.3 From e1a2849c90dd0710dd2893ce1ac1ea30aec150a2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:01:57 +0000 Subject: ARM syscall fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1377 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 0dcffb186..4d1f8ce88 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -373,7 +373,7 @@ void cpu_loop(CPUARMState *env) env->regs[2], env->regs[3], env->regs[4], - 0); + env->regs[5]); } else { goto error; } -- cgit v1.2.3 From c7d344af8fb308975f941de1640b917e1b085a81 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:05:46 +0000 Subject: - remove the ugly "stop" pseudo-opcode. - fix fsqrt instruction (there's no fsqrt.). - floating point load and store are not integer instructions. - wrong opcode for dcba instructions. (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1378 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f41bbb845..6cfbcc2b2 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -325,12 +325,6 @@ GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE) RET_INVAL(ctx); } -/* Special opcode to stop emulation */ -GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON) -{ - RET_EXCP(ctx, EXCP_HLT, 0); -} - static opc_handler_t invalid_handler = { .inval = 0xFFFFFFFF, .type = PPC_NONE, @@ -867,7 +861,19 @@ _GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0); GEN_FLOAT_AB(sub, 0x14, 0x000007C0); /* Optional: */ /* fsqrt */ -GEN_FLOAT_BS(sqrt, 0x3F, 0x16); +GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) +{ + if (!ctx->fpu_enabled) { + RET_EXCP(ctx, EXCP_NO_FP, 0); + return; + } + gen_op_reset_scrfx(); + gen_op_load_fpr_FT0(rB(ctx->opcode)); + gen_op_fsqrt(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + if (Rc(ctx->opcode)) + gen_op_set_Rc1(); +} GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) { @@ -1434,7 +1440,7 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) /*** Floating-point load ***/ #define GEN_LDF(width, opc) \ -GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (!ctx->fpu_enabled) { \ @@ -1453,7 +1459,7 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ } #define GEN_LDUF(width, opc) \ -GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (!ctx->fpu_enabled) { \ @@ -1474,7 +1480,7 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ } #define GEN_LDUXF(width, opc) \ -GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ +GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ if (!ctx->fpu_enabled) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ @@ -1494,7 +1500,7 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ } #define GEN_LDXF(width, opc2, opc3) \ -GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ +GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ { \ if (!ctx->fpu_enabled) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ @@ -1525,7 +1531,7 @@ GEN_LDFS(fs, 0x10); /*** Floating-point store ***/ #define GEN_STF(width, opc) \ -GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (!ctx->fpu_enabled) { \ @@ -1544,7 +1550,7 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ } #define GEN_STUF(width, opc) \ -GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ uint32_t simm = SIMM(ctx->opcode); \ if (!ctx->fpu_enabled) { \ @@ -1564,7 +1570,7 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ } #define GEN_STUXF(width, opc) \ -GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ +GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ if (!ctx->fpu_enabled) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ @@ -1583,7 +1589,7 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ } #define GEN_STXF(width, opc2, opc3) \ -GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ +GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ { \ if (!ctx->fpu_enabled) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ @@ -2370,7 +2376,7 @@ GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) /* Optional: */ /* dcba */ -GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT) +GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT) { } -- cgit v1.2.3 From 111bfab3b5c6a47a7182e095647e6a5e0e17feb8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:16:07 +0000 Subject: This patch adds little-endian mode support to PPC emulation. This is needed by OS/2 and Windows NT and some programs like VirtualPC. This patch has been tested using OS/2 bootloader (thanks to Tero Kaarlela). (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1379 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 3 +- disas.c | 2 + target-ppc/op_helper_mem.h | 49 ++++++++++++ target-ppc/op_mem.h | 180 +++++++++++++++++++++++++++++++++++++++++++++ target-ppc/translate.c | 124 ++++++++++++++++++++++++------- 5 files changed, 331 insertions(+), 27 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 59f127747..c83db7d64 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -364,7 +364,8 @@ int cpu_exec(CPUState *env1) cs_base = env->npc; pc = env->pc; #elif defined(TARGET_PPC) - flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_se << MSR_SE); + flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | + (msr_se << MSR_SE) | (msr_le << MSR_LE); cs_base = 0; pc = env->nip; #else diff --git a/disas.c b/disas.c index 7005716c1..8754713a8 100644 --- a/disas.c +++ b/disas.c @@ -141,6 +141,8 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #elif defined(TARGET_SPARC) print_insn = print_insn_sparc; #elif defined(TARGET_PPC) + if (cpu_single_env->msr[MSR_LE]) + disasm_info.endian = BFD_ENDIAN_LITTLE; print_insn = print_insn_ppc; #else fprintf(out, "0x" TARGET_FMT_lx diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index 85ac91163..fa7f07676 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -40,4 +40,53 @@ void glue(do_stsw, MEMSUFFIX) (int src) } } +void glue(do_lsw_le, MEMSUFFIX) (int dst) +{ + uint32_t tmp; + int sh; + + if (loglevel > 0) { + fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", + __func__, T0, T1, dst); + } + for (; T1 > 3; T1 -= 4, T0 += 4) { + tmp = glue(ldl, MEMSUFFIX)(T0); + ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | + ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); + if (dst == 32) + dst = 0; + } + if (T1 > 0) { + tmp = 0; + for (sh = 0; T1 > 0; T1--, T0++, sh += 8) { + tmp |= glue(ldub, MEMSUFFIX)(T0) << sh; + } + ugpr(dst) = tmp; + } +} + +void glue(do_stsw_le, MEMSUFFIX) (int src) +{ + uint32_t tmp; + int sh; + + if (loglevel > 0) { + fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", + __func__, T0, T1, src); + } + for (; T1 > 3; T1 -= 4, T0 += 4) { + tmp = ((ugpr(src++) & 0xFF000000) >> 24); + tmp |= ((ugpr(src++) & 0x00FF0000) >> 8); + tmp |= ((ugpr(src++) & 0x0000FF00) << 8); + tmp |= ((ugpr(src++) & 0x000000FF) << 24); + glue(stl, MEMSUFFIX)(T0, tmp); + if (src == 32) + src = 0; + } + if (T1 > 0) { + for (sh = 0; T1 > 0; T1--, T0++, sh += 8) + glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF); + } +} + #undef MEMSUFFIX diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index f0f0cd1b3..9b3f721e5 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -8,6 +8,12 @@ static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA) return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); } +static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA) +{ + int16_t tmp = glue(lduw, MEMSUFFIX)(EA); + return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); +} + static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) { uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); @@ -48,17 +54,29 @@ PPC_LD_OP(ha, ldsw); PPC_LD_OP(hz, lduw); PPC_LD_OP(wz, ldl); +PPC_LD_OP(ha_le, ld16rs); +PPC_LD_OP(hz_le, ld16r); +PPC_LD_OP(wz_le, ld32r); + /*** Integer store ***/ PPC_ST_OP(b, stb); PPC_ST_OP(h, stw); PPC_ST_OP(w, stl); +PPC_ST_OP(h_le, st16r); +PPC_ST_OP(w_le, st32r); + /*** Integer load and store with byte reverse ***/ PPC_LD_OP(hbr, ld16r); PPC_LD_OP(wbr, ld32r); PPC_ST_OP(hbr, st16r); PPC_ST_OP(wbr, st32r); +PPC_LD_OP(hbr_le, lduw); +PPC_LD_OP(wbr_le, ldl); +PPC_ST_OP(hbr_le, stw); +PPC_ST_OP(wbr_le, stl); + /*** Integer load and store multiple ***/ PPC_OP(glue(lmw, MEMSUFFIX)) { @@ -80,6 +98,26 @@ PPC_OP(glue(stmw, MEMSUFFIX)) RETURN(); } +PPC_OP(glue(lmw_le, MEMSUFFIX)) +{ + int dst = PARAM(1); + + for (; dst < 32; dst++, T0 += 4) { + ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0); + } + RETURN(); +} + +PPC_OP(glue(stmw_le, MEMSUFFIX)) +{ + int src = PARAM(1); + + for (; src < 32; src++, T0 += 4) { + glue(st32r, MEMSUFFIX)(T0, ugpr(src)); + } + RETURN(); +} + /*** Integer load and store strings ***/ PPC_OP(glue(lswi, MEMSUFFIX)) { @@ -87,6 +125,13 @@ PPC_OP(glue(lswi, MEMSUFFIX)) RETURN(); } +void glue(do_lsw_le, MEMSUFFIX) (int dst); +PPC_OP(glue(lswi_le, MEMSUFFIX)) +{ + glue(do_lsw_le, MEMSUFFIX)(PARAM(1)); + RETURN(); +} + /* PPC32 specification says we must generate an exception if * rA is in the range of registers to be loaded. * In an other hand, IBM says this is valid, but rA won't be loaded. @@ -105,12 +150,32 @@ PPC_OP(glue(lswx, MEMSUFFIX)) RETURN(); } +PPC_OP(glue(lswx_le, MEMSUFFIX)) +{ + if (T1 > 0) { + if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) || + (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) { + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + } else { + glue(do_lsw_le, MEMSUFFIX)(PARAM(1)); + } + } + RETURN(); +} + PPC_OP(glue(stsw, MEMSUFFIX)) { glue(do_stsw, MEMSUFFIX)(PARAM(1)); RETURN(); } +void glue(do_stsw_le, MEMSUFFIX) (int src); +PPC_OP(glue(stsw_le, MEMSUFFIX)) +{ + glue(do_stsw_le, MEMSUFFIX)(PARAM(1)); + RETURN(); +} + /*** Floating-point store ***/ #define PPC_STF_OP(name, op) \ PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ @@ -122,6 +187,43 @@ PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ PPC_STF_OP(fd, stfq); PPC_STF_OP(fs, stfl); +static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) +{ + union { + double d; + uint64_t u; + } u; + + u.d = d; + u.u = ((u.u & 0xFF00000000000000ULL) >> 56) | + ((u.u & 0x00FF000000000000ULL) >> 40) | + ((u.u & 0x0000FF0000000000ULL) >> 24) | + ((u.u & 0x000000FF00000000ULL) >> 8) | + ((u.u & 0x00000000FF000000ULL) << 8) | + ((u.u & 0x0000000000FF0000ULL) << 24) | + ((u.u & 0x000000000000FF00ULL) << 40) | + ((u.u & 0x00000000000000FFULL) << 56); + glue(stfq, MEMSUFFIX)(EA, u.d); +} + +static inline void glue(stflr, MEMSUFFIX) (target_ulong EA, float f) +{ + union { + float f; + uint32_t u; + } u; + + u.f = f; + u.u = ((u.u & 0xFF000000UL) >> 24) | + ((u.u & 0x00FF0000ULL) >> 8) | + ((u.u & 0x0000FF00UL) << 8) | + ((u.u & 0x000000FFULL) << 24); + glue(stfl, MEMSUFFIX)(EA, u.f); +} + +PPC_STF_OP(fd_le, stfqr); +PPC_STF_OP(fs_le, stflr); + /*** Floating-point load ***/ #define PPC_LDF_OP(name, op) \ PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ @@ -133,6 +235,45 @@ PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ PPC_LDF_OP(fd, ldfq); PPC_LDF_OP(fs, ldfl); +static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) +{ + union { + double d; + uint64_t u; + } u; + + u.d = glue(ldfq, MEMSUFFIX)(EA); + u.u = ((u.u & 0xFF00000000000000ULL) >> 56) | + ((u.u & 0x00FF000000000000ULL) >> 40) | + ((u.u & 0x0000FF0000000000ULL) >> 24) | + ((u.u & 0x000000FF00000000ULL) >> 8) | + ((u.u & 0x00000000FF000000ULL) << 8) | + ((u.u & 0x0000000000FF0000ULL) << 24) | + ((u.u & 0x000000000000FF00ULL) << 40) | + ((u.u & 0x00000000000000FFULL) << 56); + + return u.d; +} + +static inline float glue(ldflr, MEMSUFFIX) (target_ulong EA) +{ + union { + float f; + uint32_t u; + } u; + + u.f = glue(ldfl, MEMSUFFIX)(EA); + u.u = ((u.u & 0xFF000000UL) >> 24) | + ((u.u & 0x00FF0000ULL) >> 8) | + ((u.u & 0x0000FF00UL) << 8) | + ((u.u & 0x000000FFULL) << 24); + + return u.f; +} + +PPC_LDF_OP(fd_le, ldfqr); +PPC_LDF_OP(fs_le, ldflr); + /* Load and set reservation */ PPC_OP(glue(lwarx, MEMSUFFIX)) { @@ -145,6 +286,17 @@ PPC_OP(glue(lwarx, MEMSUFFIX)) RETURN(); } +PPC_OP(glue(lwarx_le, MEMSUFFIX)) +{ + if (T0 & 0x03) { + do_raise_exception(EXCP_ALIGN); + } else { + T1 = glue(ld32r, MEMSUFFIX)(T0); + regs->reserve = T0; + } + RETURN(); +} + /* Store with reservation */ PPC_OP(glue(stwcx, MEMSUFFIX)) { @@ -162,6 +314,22 @@ PPC_OP(glue(stwcx, MEMSUFFIX)) RETURN(); } +PPC_OP(glue(stwcx_le, MEMSUFFIX)) +{ + if (T0 & 0x03) { + do_raise_exception(EXCP_ALIGN); + } else { + if (regs->reserve != T0) { + env->crf[0] = xer_ov; + } else { + glue(st32r, MEMSUFFIX)(T0, T1); + env->crf[0] = xer_ov | 0x02; + } + } + regs->reserve = 0; + RETURN(); +} + PPC_OP(glue(dcbz, MEMSUFFIX)) { glue(stl, MEMSUFFIX)(T0 + 0x00, 0); @@ -188,4 +356,16 @@ PPC_OP(glue(ecowx, MEMSUFFIX)) RETURN(); } +PPC_OP(glue(eciwx_le, MEMSUFFIX)) +{ + T1 = glue(ld32r, MEMSUFFIX)(T0); + RETURN(); +} + +PPC_OP(glue(ecowx_le, MEMSUFFIX)) +{ + glue(st32r, MEMSUFFIX)(T0, T1); + RETURN(); +} + #undef MEMSUFFIX diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6cfbcc2b2..7d2e62b95 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1046,22 +1046,41 @@ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) } /*** Integer load ***/ +#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) -#define op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) -#define OP_ST_TABLE(width) +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_l##width[] = { \ + &gen_op_l##width##_raw, \ + &gen_op_l##width##_le_raw, \ +}; +#define OP_ST_TABLE(width) \ +static GenOpFunc *gen_op_st##width[] = { \ + &gen_op_st##width##_raw, \ + &gen_op_st##width##_le_raw, \ +}; +/* Byte access routine are endian safe */ +#define gen_op_stb_le_raw gen_op_stb_raw +#define gen_op_lbz_le_raw gen_op_lbz_raw #else -#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_user, \ + &gen_op_l##width##_le_user, \ &gen_op_l##width##_kernel, \ -} + &gen_op_l##width##_le_kernel, \ +}; #define OP_ST_TABLE(width) \ static GenOpFunc *gen_op_st##width[] = { \ &gen_op_st##width##_user, \ + &gen_op_st##width##_le_user, \ &gen_op_st##width##_kernel, \ -} + &gen_op_st##width##_le_kernel, \ +}; +/* Byte access routine are endian safe */ +#define gen_op_stb_le_user gen_op_stb_user +#define gen_op_lbz_le_user gen_op_lbz_user +#define gen_op_stb_le_kernel gen_op_stb_kernel +#define gen_op_lbz_le_kernel gen_op_lbz_kernel #endif #define GEN_LD(width, opc) \ @@ -1232,17 +1251,28 @@ OP_ST_TABLE(wbr); GEN_STX(wbr, 0x16, 0x14); /*** Integer load and store multiple ***/ +#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg) #if defined(CONFIG_USER_ONLY) -#define op_ldstm(name, reg) gen_op_##name##_raw(reg) +static GenOpFunc1 *gen_op_lmw[] = { + &gen_op_lmw_raw, + &gen_op_lmw_le_raw, +}; +static GenOpFunc1 *gen_op_stmw[] = { + &gen_op_stmw_raw, + &gen_op_stmw_le_raw, +}; #else -#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg) static GenOpFunc1 *gen_op_lmw[] = { &gen_op_lmw_user, + &gen_op_lmw_le_user, &gen_op_lmw_kernel, + &gen_op_lmw_le_kernel, }; static GenOpFunc1 *gen_op_stmw[] = { &gen_op_stmw_user, + &gen_op_stmw_le_user, &gen_op_stmw_kernel, + &gen_op_stmw_le_kernel, }; #endif @@ -1277,23 +1307,39 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) } /*** Integer load and store strings ***/ -#if defined(CONFIG_USER_ONLY) -#define op_ldsts(name, start) gen_op_##name##_raw(start) -#define op_ldstsx(name, rd, ra, rb) gen_op_##name##_raw(rd, ra, rb) -#else #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start) #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb) +#if defined(CONFIG_USER_ONLY) +static GenOpFunc1 *gen_op_lswi[] = { + &gen_op_lswi_raw, + &gen_op_lswi_le_raw, +}; +static GenOpFunc3 *gen_op_lswx[] = { + &gen_op_lswx_raw, + &gen_op_lswx_le_raw, +}; +static GenOpFunc1 *gen_op_stsw[] = { + &gen_op_stsw_raw, + &gen_op_stsw_le_raw, +}; +#else static GenOpFunc1 *gen_op_lswi[] = { &gen_op_lswi_user, + &gen_op_lswi_le_user, &gen_op_lswi_kernel, + &gen_op_lswi_le_kernel, }; static GenOpFunc3 *gen_op_lswx[] = { &gen_op_lswx_user, + &gen_op_lswx_le_user, &gen_op_lswx_kernel, + &gen_op_lswx_le_kernel, }; static GenOpFunc1 *gen_op_stsw[] = { &gen_op_stsw_user, + &gen_op_stsw_le_user, &gen_op_stsw_kernel, + &gen_op_stsw_le_kernel, }; #endif @@ -1389,23 +1435,33 @@ GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM) { } -/* lwarx */ +#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])() +#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) -#define op_lwarx() gen_op_lwarx_raw() -#define op_stwcx() gen_op_stwcx_raw() +static GenOpFunc *gen_op_lwarx[] = { + &gen_op_lwarx_raw, + &gen_op_lwarx_le_raw, +}; +static GenOpFunc *gen_op_stwcx[] = { + &gen_op_stwcx_raw, + &gen_op_stwcx_le_raw, +}; #else -#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])() static GenOpFunc *gen_op_lwarx[] = { &gen_op_lwarx_user, + &gen_op_lwarx_le_user, &gen_op_lwarx_kernel, + &gen_op_lwarx_le_kernel, }; -#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])() static GenOpFunc *gen_op_stwcx[] = { &gen_op_stwcx_user, + &gen_op_stwcx_le_user, &gen_op_stwcx_kernel, + &gen_op_stwcx_le_kernel, }; #endif +/* lwarx */ GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES) { if (rA(ctx->opcode) == 0) { @@ -2498,23 +2554,33 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) /*** External control ***/ /* Optional: */ -/* eciwx */ -#if defined(CONFIG_USER_ONLY) -#define op_eciwx() gen_op_eciwx_raw() -#define op_ecowx() gen_op_ecowx_raw() -#else #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])() #define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])() +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_eciwx[] = { + &gen_op_eciwx_raw, + &gen_op_eciwx_le_raw, +}; +static GenOpFunc *gen_op_ecowx[] = { + &gen_op_ecowx_raw, + &gen_op_ecowx_le_raw, +}; +#else static GenOpFunc *gen_op_eciwx[] = { &gen_op_eciwx_user, + &gen_op_eciwx_le_user, &gen_op_eciwx_kernel, + &gen_op_eciwx_le_kernel, }; static GenOpFunc *gen_op_ecowx[] = { &gen_op_ecowx_user, + &gen_op_ecowx_le_user, &gen_op_ecowx_kernel, + &gen_op_ecowx_le_kernel, }; #endif +/* eciwx */ GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN) { /* Should check EAR[E] & alignment ! */ @@ -3143,10 +3209,10 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.tb = tb; ctx.exception = EXCP_NONE; #if defined(CONFIG_USER_ONLY) - ctx.mem_idx = 0; + ctx.mem_idx = msr_le; #else ctx.supervisor = 1 - msr_pr; - ctx.mem_idx = 1 - msr_pr; + ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le; #endif ctx.fpu_enabled = msr_fp; #if defined (DO_SINGLE_STEP) @@ -3173,11 +3239,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } #endif ctx.opcode = ldl_code(ctx.nip); + if (msr_le) { + ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) | + ((ctx.opcode & 0x00FF0000) >> 8) | + ((ctx.opcode & 0x0000FF00) << 8) | + ((ctx.opcode & 0x000000FF) << 24); + } #if defined PPC_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", + fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n", ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode)); + opc3(ctx.opcode), msr_le ? "little" : "big"); } #endif ctx.nip += 4; -- cgit v1.2.3 From dccfafc4e1325dbf90d8ee7b2bc56e6e02eaf4b5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:16:54 +0000 Subject: This patch fixes two bugs in cuda emulation: - the CUDA timer is always triggered twice, with current code - SET_TIME command is supposed to send back a 7 bytes packet (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1380 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cuda.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/cuda.c b/hw/cuda.c index b19686280..7eea0421c 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -178,16 +178,19 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) /* current counter value */ d = muldiv64(current_time - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); - if (d <= s->counter_value) { + if (d < s->counter_value) { next_time = s->counter_value + 1; - } else { - base = ((d - s->counter_value) / s->latch); + } else + { + base = ((d - s->counter_value + 1) / s->latch); base = (base * s->latch) + s->counter_value; next_time = base + s->latch; } +#if 0 #ifdef DEBUG_CUDA printf("latch=%d counter=%lld delta_next=%lld\n", s->latch, d, next_time - d); +#endif #endif next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + s->load_time; @@ -505,6 +508,7 @@ static void cuda_receive_packet(CUDAState *s, cuda_send_packet_to_host(s, obuf, 2); break; case CUDA_GET_TIME: + case CUDA_SET_TIME: /* XXX: add time support ? */ ti = time(NULL) + RTC_OFFSET; obuf[0] = CUDA_PACKET; @@ -516,7 +520,6 @@ static void cuda_receive_packet(CUDAState *s, obuf[6] = ti; cuda_send_packet_to_host(s, obuf, 7); break; - case CUDA_SET_TIME: case CUDA_FILE_SERVER_FLAG: case CUDA_SET_DEVICE_LIST: case CUDA_SET_AUTO_RATE: -- cgit v1.2.3 From da9b266bb8491fd41badfff8ae1772007602dcca Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:18:54 +0000 Subject: PREP machines have two IO mappings. This patch adds support for non-contiguous IO map, which is used by OS/2. It also adds the missing legacy IO ports for the PREP PCI bridge and changes CPU PVR from 74x/75x to 604 to make OS/2 happy. (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1381 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 10 +++++ hw/ppc_prep.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 125 insertions(+), 10 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 6035c890a..cb7131a6a 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -694,6 +694,16 @@ PCIBus *pci_prep_init(void) s = pci_register_bus(); s->set_irq = prep_set_irq; + register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); + register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); + + register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); + register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); + register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); + register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); + register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); + register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); + PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, PPC_PCIIO_write, s); cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index c93b72fae..06951e542 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -249,6 +249,7 @@ typedef struct sysctrl_t { uint8_t state; uint8_t syscontrol; uint8_t fake_io[2]; + int contiguous_map; } sysctrl_t; enum { @@ -328,10 +329,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) break; case 0x0850: /* I/O map type register */ - if (!(val & 0x01)) { - printf("No support for non-continuous I/O map mode\n"); - abort(); - } + sysctrl->contiguous_map = val & 0x01; break; default: printf("ERROR: unaffected IO port write: %04lx => %02x\n", @@ -375,6 +373,9 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) /* Motorola base module extended feature register */ retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */ break; + case 0x0814: + /* L2 invalidate: don't care */ + break; case 0x0818: /* Keylock */ retval = 0x00; @@ -391,7 +392,7 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) break; case 0x0850: /* I/O map type register */ - retval = 0x01; + retval = sysctrl->contiguous_map; break; default: printf("ERROR: unaffected IO port: %04lx read\n", (long)addr); @@ -402,6 +403,108 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) return retval; } +static inline target_phys_addr_t prep_IO_address (sysctrl_t *sysctrl, + target_phys_addr_t addr) +{ + if (sysctrl->contiguous_map == 0) { + /* 64 KB contiguous space for IOs */ + addr &= 0xFFFF; + } else { + /* 8 MB non-contiguous space for IOs */ + addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7); + } + + return addr; +} + +static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + sysctrl_t *sysctrl = opaque; + + addr = prep_IO_address(sysctrl, addr); + cpu_outb(NULL, addr, value); +} + +static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr) +{ + sysctrl_t *sysctrl = opaque; + uint32_t ret; + + addr = prep_IO_address(sysctrl, addr); + ret = cpu_inb(NULL, addr); + + return ret; +} + +static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + sysctrl_t *sysctrl = opaque; + + addr = prep_IO_address(sysctrl, addr); +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif + PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value); + cpu_outw(NULL, addr, value); +} + +static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr) +{ + sysctrl_t *sysctrl = opaque; + uint32_t ret; + + addr = prep_IO_address(sysctrl, addr); + ret = cpu_inw(NULL, addr); +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap16(ret); +#endif + PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret); + + return ret; +} + +static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + sysctrl_t *sysctrl = opaque; + + addr = prep_IO_address(sysctrl, addr); +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif + PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value); + cpu_outl(NULL, addr, value); +} + +static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr) +{ + sysctrl_t *sysctrl = opaque; + uint32_t ret; + + addr = prep_IO_address(sysctrl, addr); + ret = cpu_inl(NULL, addr); +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap32(ret); +#endif + PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret); + + return ret; +} + +CPUWriteMemoryFunc *PPC_prep_io_write[] = { + &PPC_prep_io_writeb, + &PPC_prep_io_writew, + &PPC_prep_io_writel, +}; + +CPUReadMemoryFunc *PPC_prep_io_read[] = { + &PPC_prep_io_readb, + &PPC_prep_io_readw, + &PPC_prep_io_readl, +}; + extern CPUPPCState *global_env; #define NVRAM_SIZE 0x2000 @@ -472,16 +575,18 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, initrd_size = 0; } - /* Register CPU as a 74x/75x */ - cpu_ppc_register(cpu_single_env, 0x00080000); + /* Register CPU as a 604 */ + cpu_ppc_register(cpu_single_env, 0x00040000); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); isa_mem_base = 0xc0000000; pci_bus = pci_prep_init(); - /* Register 64 KB of ISA IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); - cpu_register_physical_memory(0x80000000, 0x00010000, PPC_io_memory); + // pci_bus = i440fx_init(); + /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ + PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read, + PPC_prep_io_write, sysctrl); + cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); /* init basic PC hardware */ vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, -- cgit v1.2.3 From 89344d5ad7751010874300ff2b25953edcd6d3cb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:21:13 +0000 Subject: arm vfp fcmp and fcmpe instructions fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1382 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index a39e44adb..a0cddb654 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -67,7 +67,7 @@ void do_vfp_cmp##p(void) \ { \ uint32_t flags; \ switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\ - case 0: flags = 0xc; break;\ + case 0: flags = 0x6; break;\ case -1: flags = 0x8; break;\ case 1: flags = 0x2; break;\ default: case 2: flags = 0x3; break;\ @@ -80,7 +80,7 @@ void do_vfp_cmpe##p(void) \ { \ uint32_t flags; \ switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\ - case 0: flags = 0xc; break;\ + case 0: flags = 0x6; break;\ case -1: flags = 0x8; break;\ case 1: flags = 0x2; break;\ default: case 2: flags = 0x3; break;\ -- cgit v1.2.3 From a4f81979e8c82ea8fb9f3c96692b9c58c8e88e5a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:25:41 +0000 Subject: ARM "Angel" semihosting syscalls (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1383 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- linux-user/arm-semi.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++ linux-user/arm/syscall.h | 5 ++ linux-user/main.c | 7 ++ linux-user/qemu.h | 6 ++ linux-user/syscall.c | 2 +- 6 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 linux-user/arm-semi.c diff --git a/Makefile.target b/Makefile.target index 789848e53..5375cb32b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -233,7 +233,7 @@ 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 + nwfpe/double_cpdo.o nwfpe/extended_cpdo.o arm-semi.o endif SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c new file mode 100644 index 000000000..f37b65c47 --- /dev/null +++ b/linux-user/arm-semi.c @@ -0,0 +1,193 @@ +/* + * Arm "Angel" semihosting syscalls + * + * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024) + +#define SYS_OPEN 0x01 +#define SYS_CLOSE 0x02 +#define SYS_WRITEC 0x03 +#define SYS_WRITE0 0x04 +#define SYS_WRITE 0x05 +#define SYS_READ 0x06 +#define SYS_READC 0x07 +#define SYS_ISTTY 0x09 +#define SYS_SEEK 0x0a +#define SYS_FLEN 0x0c +#define SYS_TMPNAM 0x0d +#define SYS_REMOVE 0x0e +#define SYS_RENAME 0x0f +#define SYS_CLOCK 0x10 +#define SYS_TIME 0x11 +#define SYS_SYSTEM 0x12 +#define SYS_ERRNO 0x13 +#define SYS_GET_CMDLINE 0x15 +#define SYS_HEAPINFO 0x16 +#define SYS_EXIT 0x18 + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +int open_modeflags[12] = { + O_RDONLY, + O_RDONLY | O_BINARY, + O_RDWR, + O_RDWR | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_APPEND, + O_WRONLY | O_CREAT | O_APPEND | O_BINARY, + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY +}; + +static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code) +{ + if (code == (uint32_t)-1) + ts->swi_errno = errno; + return code; +} + +#define ARG(x) tswap32(args[x]) +uint32_t do_arm_semihosting(CPUState *env) +{ + uint32_t *args; + char * s; + int nr; + uint32_t ret; + TaskState *ts = env->opaque; + + nr = env->regs[0]; + args = (uint32_t *)env->regs[1]; + switch (nr) { + case SYS_OPEN: + s = (char *)ARG(0); + if (ARG(1) >= 12) + return (uint32_t)-1; + if (strcmp(s, ":tt") == 0) { + if (ARG(1) < 4) + return STDIN_FILENO; + else + return STDOUT_FILENO; + } + return set_swi_errno(ts, open(s, open_modeflags[ARG(1)])); + case SYS_CLOSE: + return set_swi_errno(ts, close(ARG(0))); + case SYS_WRITEC: + /* Write to debug console. stderr is near enough. */ + return write(STDERR_FILENO, args, 1); + case SYS_WRITE0: + s = (char *)args; + return write(STDERR_FILENO, s, strlen(s)); + case SYS_WRITE: + ret = set_swi_errno(ts, write(ARG(0), (void *)ARG(1), ARG(2))); + if (ret == (uint32_t)-1) + return -1; + return ARG(2) - ret; + case SYS_READ: + ret = set_swi_errno(ts, read(ARG(0), (void *)ARG(1), ARG(2))); + if (ret == (uint32_t)-1) + return -1; + return ARG(2) - ret; + case SYS_READC: + /* XXX: Read from debug cosole. Not implemented. */ + return 0; + case SYS_ISTTY: + return isatty(ARG(0)); + case SYS_SEEK: + return set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); + case SYS_FLEN: + { + struct stat buf; + ret = set_swi_errno(ts, fstat(ARG(0), &buf)); + if (ret == (uint32_t)-1) + return -1; + return buf.st_size; + } + case SYS_TMPNAM: + /* XXX: Not implemented. */ + return -1; + case SYS_REMOVE: + return set_swi_errno(ts, remove((char *)ARG(0))); + case SYS_RENAME: + return set_swi_errno(ts, rename((char *)ARG(0), (char *)ARG(2))); + case SYS_CLOCK: + return clock() / (CLOCKS_PER_SEC / 100); + case SYS_TIME: + return set_swi_errno(ts, time(NULL)); + case SYS_SYSTEM: + return set_swi_errno(ts, system((char *)ARG(0))); + case SYS_ERRNO: + return ts->swi_errno; + case SYS_GET_CMDLINE: + /* XXX: Not implemented. */ + s = (char *)ARG(0); + *s = 0; + return -1; + case SYS_HEAPINFO: + { + uint32_t *ptr; + uint32_t limit; + + /* Some C llibraries assume the heap immediately follows .bss, so + allocate it using sbrk. */ + if (!ts->heap_limit) { + long ret; + + ts->heap_base = do_brk(NULL); + limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE; + /* Try a big heap, and reduce the size if that fails. */ + for (;;) { + ret = do_brk((char *)limit); + if (ret != -1) + break; + limit = (ts->heap_base >> 1) + (limit >> 1); + } + ts->heap_limit = limit; + } + + ptr = (uint32_t *)tswap32(ARG(0)); + ptr[0] = tswap32(ts->heap_base); + ptr[1] = tswap32(ts->heap_limit); + ptr[2] = tswap32(ts->stack_base); + ptr[3] = tswap32(0); /* Stack limit. */ + return 0; + } + case SYS_EXIT: + exit(0); + default: + fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); + } +} + diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index f74d76528..daf4b34af 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -29,8 +29,13 @@ struct target_pt_regs { #define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) +#define ARM_NR_semihosting 0x123456 +#define ARM_NR_thumb_semihosting 0xAB + #if defined(TARGET_WORDS_BIGENDIAN) #define UNAME_MACHINE "armv5teb" #else #define UNAME_MACHINE "armv5tel" #endif + +uint32_t do_arm_semihosting(CPUState *); diff --git a/linux-user/main.c b/linux-user/main.c index 4d1f8ce88..bcdf8441b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -363,6 +363,9 @@ void cpu_loop(CPUARMState *env) n = insn & 0xffffff; if (n == ARM_NR_cacheflush) { arm_cache_flush(env->regs[0], env->regs[1]); + } else if (n == ARM_NR_semihosting + || n == ARM_NR_thumb_semihosting) { + env->regs[0] = do_arm_semihosting (env); } else if (n >= ARM_SYSCALL_BASE) { /* linux syscall */ n -= ARM_SYSCALL_BASE; @@ -1207,6 +1210,10 @@ int main(int argc, char **argv) env->regs[i] = regs->uregs[i]; } env->cpsr = regs->uregs[16]; + ts->stack_base = info->start_stack; + ts->heap_base = info->brk; + /* This will be filled in on the first SYS_HEAPINFO call. */ + ts->heap_limit = 0; } #elif defined(TARGET_SPARC) { diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 2a815eb81..f385a1c92 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -62,6 +62,11 @@ typedef struct TaskState { #ifdef TARGET_ARM /* FPA state */ FPA11 fpa; + /* Extra fields for semihosted binaries. */ + uint32_t stack_base; + uint32_t heap_base; + uint32_t heap_limit; + int swi_errno; #endif #ifdef TARGET_I386 struct target_vm86plus_struct *target_v86; @@ -80,6 +85,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); void target_set_brk(char *new_brk); +long do_brk(char *new_brk); void syscall_init(void); long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d69b21e6f..b00ce90cb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -264,7 +264,7 @@ void target_set_brk(char *new_brk) target_original_brk = new_brk; } -static long do_brk(char *new_brk) +long do_brk(char *new_brk) { char *brk_page; long mapped_addr; -- cgit v1.2.3 From 8aaca4c0b45c85f4108312232c9a7c4bdd641e8e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:27:52 +0000 Subject: ARM singlestep support (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1384 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 65 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 280b68c4c..03a26fef5 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -33,6 +33,7 @@ typedef struct DisasContext { target_ulong pc; int is_jmp; struct TranslationBlock *tb; + int singlestep_enabled; } DisasContext; #define DISAS_JUMP_NEXT 4 @@ -888,6 +889,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) return 0; } +static inline void gen_jmp (DisasContext *s, uint32_t dest) +{ + if (__builtin_expect(s->singlestep_enabled, 0)) { + /* An indirect jump so that we still trigger the debug exception. */ + gen_op_movl_T0_im(dest); + gen_bx(s); + } else { + gen_op_jmp((long)s->tb, dest); + s->is_jmp = DISAS_TB_JUMP; + } +} + static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; @@ -1469,8 +1482,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } offset = (((int32_t)insn << 8) >> 8); val += (offset << 2) + 4; - gen_op_jmp((long)s->tb, val); - s->is_jmp = DISAS_TB_JUMP; + gen_jmp(s, val); } break; case 0xc: @@ -1957,8 +1969,7 @@ static void disas_thumb_insn(DisasContext *s) val = (uint32_t)s->pc; offset = ((int32_t)insn << 24) >> 24; val += (offset << 1) + 2; - gen_op_jmp((long)s->tb, val); - s->is_jmp = DISAS_TB_JUMP; + gen_jmp(s, val); break; case 14: @@ -1968,8 +1979,7 @@ static void disas_thumb_insn(DisasContext *s) val = (uint32_t)s->pc; offset = ((int32_t)insn << 21) >> 21; val += (offset << 1) + 2; - gen_op_jmp((long)s->tb, val); - s->is_jmp = DISAS_TB_JUMP; + gen_jmp(s, val); break; case 15: @@ -1985,8 +1995,7 @@ static void disas_thumb_insn(DisasContext *s) val += offset; if (insn & (1 << 11)) { /* bl */ - gen_op_jmp((long)s->tb, val); - s->is_jmp = DISAS_TB_JUMP; + gen_jmp(s, val); } else { /* blx */ gen_op_movl_T0_im(val); @@ -2024,6 +2033,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; + dc->singlestep_enabled = env->singlestep_enabled; lj = -1; do { if (env->nb_breakpoints > 0) { @@ -2054,21 +2064,30 @@ static inline int gen_intermediate_code_internal(CPUState *env, } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); - switch(dc->is_jmp) { - case DISAS_JUMP_NEXT: - case DISAS_NEXT: - gen_op_jmp((long)dc->tb, (long)dc->pc); - break; - default: - case DISAS_JUMP: - case DISAS_UPDATE: - /* indicate that the hash table must be used to find the next TB */ - gen_op_movl_T0_0(); - gen_op_exit_tb(); - break; - case DISAS_TB_JUMP: - /* nothing more to generate */ - break; + if (__builtin_expect(env->singlestep_enabled, 0)) { + /* Make sure the pc is updated, and raise a debug exception. */ + if (dc->is_jmp == DISAS_NEXT || dc->is_jmp == DISAS_JUMP_NEXT) { + gen_op_movl_T0_im((long)dc->pc); + gen_op_movl_reg_TN[0][15](); + } + gen_op_debug(); + } else { + switch(dc->is_jmp) { + case DISAS_JUMP_NEXT: + case DISAS_NEXT: + gen_op_jmp((long)dc->tb, (long)dc->pc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + /* indicate that the hash table must be used to find the next TB */ + gen_op_movl_T0_0(); + gen_op_exit_tb(); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + } } *gen_opc_ptr = INDEX_op_end; -- cgit v1.2.3 From c326e0afec0f1034851d55fbbb005f87b345a10b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:30:28 +0000 Subject: cygwin host support (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1385 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index 7ef930067..f01b00bd2 100755 --- a/configure +++ b/configure @@ -88,6 +88,10 @@ cocoa="no" # OS specific targetos=`uname -s` case $targetos in +CYGWIN*) +mingw32="yes" +CFLAGS="-O2 -mno-cygwin" +;; MINGW32*) mingw32="yes" ;; -- cgit v1.2.3 From 08e489025b49bb0d9e3781643772e35c445a21b2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:43:45 +0000 Subject: removed obsolete S3 VGA code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1386 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 63 +-------------------------------------------------------------- 1 file changed, 1 insertion(+), 62 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index af463a120..2c425ffe9 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -28,12 +28,8 @@ //#define DEBUG_VGA_MEM //#define DEBUG_VGA_REG -//#define DEBUG_S3 //#define DEBUG_BOCHS_VBE -/* S3 VGA is deprecated - another graphic card will be emulated */ -//#define CONFIG_S3VGA - /* force some bits to zero */ const uint8_t sr_mask[8] = { (uint8_t)~0xfc, @@ -224,11 +220,6 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) val = s->cr[s->cr_index]; #ifdef DEBUG_VGA_REG printf("vga: read CR%x = 0x%02x\n", s->cr_index, val); -#endif -#ifdef DEBUG_S3 - if (s->cr_index >= 0x20) - printf("S3: CR read index=0x%x val=0x%x\n", - s->cr_index, val); #endif break; case 0x3ba: @@ -359,43 +350,10 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0x12: /* veritcal display end */ s->cr[s->cr_index] = val; break; - -#ifdef CONFIG_S3VGA - /* S3 registers */ - case 0x2d: - case 0x2e: - case 0x2f: - case 0x30: - /* chip ID, cannot write */ - break; - case 0x31: - /* update start address */ - { - int v; - s->cr[s->cr_index] = val; - v = (val >> 4) & 3; - s->cr[0x69] = (s->cr[69] & ~0x03) | v; - } - break; - case 0x51: - /* update start address */ - { - int v; - s->cr[s->cr_index] = val; - v = val & 3; - s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2); - } - break; -#endif default: s->cr[s->cr_index] = val; break; } -#ifdef DEBUG_S3 - if (s->cr_index >= 0x20) - printf("S3: CR write index=0x%x val=0x%x\n", - s->cr_index, val); -#endif break; case 0x3ba: case 0x3da: @@ -954,22 +912,10 @@ static void vga_get_offsets(VGAState *s, { /* compute line_offset in bytes */ line_offset = s->cr[0x13]; -#ifdef CONFIG_S3VGA - { - uinr32_t v; - v = (s->cr[0x51] >> 4) & 3; /* S3 extension */ - if (v == 0) - v = (s->cr[0x43] >> 2) & 1; /* S3 extension */ - line_offset |= (v << 8); - } -#endif line_offset <<= 3; - + /* starting address */ start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); -#ifdef CONFIG_S3VGA - start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */ -#endif } *pline_offset = line_offset; *pstart_addr = start_addr; @@ -1597,13 +1543,6 @@ void vga_invalidate_display(void) static void vga_reset(VGAState *s) { memset(s, 0, sizeof(VGAState)); -#ifdef CONFIG_S3VGA - /* chip ID for 8c968 */ - s->cr[0x2d] = 0x88; - s->cr[0x2e] = 0xb0; - s->cr[0x2f] = 0x01; /* XXX: check revision code */ - s->cr[0x30] = 0xe1; -#endif s->graphic_mode = -1; /* force full update */ } -- cgit v1.2.3 From 74c161bd17d2cf8d9649d0f69033c10ab46df177 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 18:46:03 +0000 Subject: Fix dumping of arm registers (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1387 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 03a26fef5..315595e89 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2172,8 +2172,8 @@ void cpu_dump_state(CPUState *env, FILE *f, i * 2 + 1, (int)s0.i, s0.s, i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower, d.d); - cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr); } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr); } target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -- cgit v1.2.3 From 6bae7ed8b900bc0f1fb1df0f70ceed5e8cca0ca1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Apr 2005 20:44:25 +0000 Subject: informative message about low memory on /dev/shm git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1388 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osdep.c b/osdep.c index eef1ecbec..f2a69d9a7 100644 --- a/osdep.c +++ b/osdep.c @@ -323,6 +323,7 @@ void qemu_vfree(void *ptr) #elif defined(USE_KQEMU) +#include #include #include @@ -333,11 +334,37 @@ void *qemu_vmalloc(size_t size) const char *tmpdir; char phys_ram_file[1024]; void *ptr; + struct statfs stfs; if (phys_ram_fd < 0) { tmpdir = getenv("QEMU_TMPDIR"); if (!tmpdir) tmpdir = "/dev/shm"; + if (statfs(tmpdir, &stfs) == 0) { + int64_t free_space; + int ram_mb; + + extern int ram_size; + free_space = (int64_t)stfs.f_bavail * stfs.f_bsize; + if ((ram_size + 8192 * 1024) >= free_space) { + ram_mb = (ram_size / (1024 * 1024)); + fprintf(stderr, + "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n", + tmpdir, ram_mb); + if (strcmp(tmpdir, "/dev/shm") == 0) { + fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n" + "umount /dev/shm\n" + "mount -t tmpfs -o size=%dm none /dev/shm\n", + ram_mb + 16); + } else { + fprintf(stderr, + "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n" + "QEMU_TMPDIR environment variable to set another directory where the QEMU\n" + "temporary RAM file will be opened.\n"); + } + exit(1); + } + } snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", tmpdir); if (mkstemp(phys_ram_file) < 0) { -- cgit v1.2.3 From 41625033686b7cb8bf8966c7d0907ec208d6a028 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Apr 2005 10:07:11 +0000 Subject: removed RS_CONTINUE 'state' git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1389 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 5dc93c457..eb3062708 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -42,17 +42,19 @@ enum RSState { RS_GETLINE, RS_CHKSUM1, RS_CHKSUM2, - RS_CONTINUE }; /* XXX: This is not thread safe. Do we care? */ static int gdbserver_fd = -1; typedef struct GDBState { - enum RSState state; + enum RSState state; /* parsing state */ int fd; char line_buf[4096]; int line_buf_index; int line_csum; +#ifdef CONFIG_USER_ONLY + int running_state; +#endif } GDBState; #ifdef CONFIG_USER_ONLY @@ -431,7 +433,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) env->npc = addr + 4; #endif } - return RS_CONTINUE; +#ifdef CONFIG_USER_ONLY + s->running_state = 1; +#else + vm_start(); +#endif + return RS_IDLE; case 's': if (*p != '\0') { addr = strtoul(p, (char **)&p, 16); @@ -445,7 +452,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #endif } cpu_single_step(env, 1); - return RS_CONTINUE; +#ifdef CONFIG_USER_ONLY + s->running_state = 1; +#else + vm_start(); +#endif + return RS_IDLE; case 'g': reg_size = cpu_gdb_read_registers(env, mem_buf); memtohex(buf, mem_buf, reg_size); @@ -556,8 +568,9 @@ static void gdb_read_byte(GDBState *s, CPUState *env, int ch) /* when the CPU is running, we cannot do anything except stop it when receiving a char */ vm_stop(EXCP_INTERRUPT); - } else { + } else #endif + { switch(s->state) { case RS_IDLE: if (ch == '$') { @@ -595,16 +608,8 @@ static void gdb_read_byte(GDBState *s, CPUState *env, int ch) s->state = gdb_handle_packet(s, env, s->line_buf); } break; - case RS_CONTINUE: -#ifndef CONFIG_USER_ONLY - vm_start(); - s->state = RS_IDLE; -#endif - break; } -#ifndef CONFIG_USER_ONLY } -#endif } #ifdef CONFIG_USER_ONLY @@ -630,11 +635,10 @@ gdb_handlesig (CPUState *env, int sig) put_packet(s, buf); } - /* TODO: How do we terminate this loop? */ sig = 0; s->state = RS_IDLE; - while (s->state != RS_CONTINUE) - { + s->running_state = 0; + while (s->running_state == 0) { n = read (s->fd, buf, 256); if (n > 0) { @@ -649,7 +653,7 @@ gdb_handlesig (CPUState *env, int sig) connection before continuing. */ return sig; } - } + } return sig; } #else -- cgit v1.2.3 From b3180cdc0195c14d8f01971010b920ef98b35bc3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Apr 2005 10:08:19 +0000 Subject: MMU fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1390 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 82a3a4ec9..9fd5f214b 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -142,7 +142,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); pde = ldl_phys(pde_ptr); /* Ctx pde */ @@ -356,7 +356,7 @@ target_ulong mmu_probe(target_ulong address, int mmulev) uint32_t pde; /* Context base + context number */ - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); pde = ldl_phys(pde_ptr); switch (pde & PTE_ENTRYTYPE_MASK) { @@ -421,7 +421,7 @@ void dump_mmu(void) uint32_t pde; printf("MMU dump:\n"); - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); pde = ldl_phys(pde_ptr); printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { -- cgit v1.2.3 From dff293e751c7670dfc7a8fcc9175446c311f3ed9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Apr 2005 18:01:56 +0000 Subject: qemu code is not ready to handle these registers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1391 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 902728013..2dc948bf4 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -74,8 +74,8 @@ extern int printf(const char *, ...); #define AREG1 "rbx" #define AREG2 "r12" #define AREG3 "r13" -#define AREG4 "r14" -#define AREG5 "r15" +//#define AREG4 "r14" +//#define AREG5 "r15" #endif #ifdef __powerpc__ #define AREG0 "r27" -- cgit v1.2.3 From e04f40b5aaded924d4f751d54762ffb6e6ab2e0f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Apr 2005 18:02:38 +0000 Subject: compatibility fix with kqemu-x86_64 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1392 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec.c b/exec.c index f92304376..08914aecd 100644 --- a/exec.c +++ b/exec.c @@ -80,7 +80,7 @@ typedef struct PageDesc { typedef struct PhysPageDesc { /* offset in host memory of the page + io_index in the low 12 bits */ - unsigned long phys_offset; + uint32_t phys_offset; } PhysPageDesc; typedef struct VirtPageDesc { -- cgit v1.2.3 From c45b3c0e1b5125d1588c988dca2174bf3cfa5287 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Apr 2005 18:03:37 +0000 Subject: efer is present even in legacy mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1393 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kqemu.c b/kqemu.c index f882c8b2f..4d152502e 100644 --- a/kqemu.c +++ b/kqemu.c @@ -431,7 +431,7 @@ int kqemu_cpu_exec(CPUState *env) kenv->cr3 = env->cr[3]; kenv->cr4 = env->cr[4]; kenv->a20_mask = env->a20_mask; -#ifdef __x86_64__ +#if KQEMU_VERSION >= 0x010100 kenv->efer = env->efer; #endif if (env->dr[7] & 0xff) { @@ -530,6 +530,11 @@ int kqemu_cpu_exec(CPUState *env) #endif return 1; } else if (ret == KQEMU_RET_INTR) { +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + cpu_dump_state(env, logfile, fprintf, 0); + } +#endif return 0; } else if (ret == KQEMU_RET_SOFTMMU) { return 2; -- cgit v1.2.3 From b359d4e7e44d643d25e3ead1dba31e6559f4eb72 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Apr 2005 18:04:33 +0000 Subject: fixed zero ss selector case in x86_64 emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1394 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index ee3f670b5..0d2cd74bc 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1494,11 +1494,12 @@ void load_seg(int seg_reg, int selector) target_ulong ptr; selector &= 0xffff; + cpl = env->hflags & HF_CPL_MASK; if ((selector & 0xfffc) == 0) { /* null selector case */ if (seg_reg == R_SS #ifdef TARGET_X86_64 - && !(env->hflags & HF_CS64_MASK) + && (!(env->hflags & HF_CS64_MASK) || cpl == 3) #endif ) raise_exception_err(EXCP0D_GPF, 0); @@ -1520,7 +1521,6 @@ void load_seg(int seg_reg, int selector) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; if (seg_reg == R_SS) { /* must be writable segment */ if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) @@ -2054,13 +2054,20 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) new_ss, new_esp); } #endif - if ((env->hflags & HF_LMA_MASK) && (new_ss & 0xfffc) == 0) { - /* NULL ss is allowed in long mode */ - cpu_x86_load_seg_cache(env, R_SS, new_ss, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | - DESC_W_MASK | DESC_A_MASK); + if ((new_ss & 0xfffc) == 0) { +#ifdef TARGET_X86_64 + /* NULL ss is allowed in long mode if cpl != 3*/ + if ((env->hflags & HF_LMA_MASK) && rpl != 3) { + cpu_x86_load_seg_cache(env, R_SS, new_ss, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + } else +#endif + { + raise_exception_err(EXCP0D_GPF, 0); + } } else { if ((new_ss & 3) != rpl) raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); -- cgit v1.2.3 From fc9f715de8bc5aaed89ada800c1ead43c19f5784 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 19:33:35 +0000 Subject: i386-user compile fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1395 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cpu-exec.c b/cpu-exec.c index c83db7d64..d414e3343 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -322,14 +322,30 @@ int cpu_exec(CPUState *env1) if ((loglevel & CPU_LOG_EXEC)) { #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); -- cgit v1.2.3 From e362b55a321c00bde7a164811dac71120ca8f871 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:34:26 +0000 Subject: fixed clean target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1396 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 5375cb32b..dbceeb7f4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -459,7 +459,7 @@ mixeng.o: mixeng.c mixeng.h mixeng_template.h $(CC) $(DEFINES) -c -o $@ $< clean: - rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o + rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o install: all ifneq ($(PROGS),) -- cgit v1.2.3 From 1026f1336b1121ff3215fcef703cbcfe63a488fd Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:34:45 +0000 Subject: win32 conf fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1397 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/configure b/configure index f01b00bd2..3e26b8071 100755 --- a/configure +++ b/configure @@ -566,9 +566,11 @@ echo "\"" >> $config_h if test $kqemu = "yes" ; then echo "CONFIG_KQEMU=yes" >> $config_mak - echo "KERNEL_PATH=$kernel_path" >> $config_mak - if test $kbuild26 = "yes" ; then - echo "CONFIG_KBUILD26=yes" >> $config_mak + if test $linux = "yes" ; then + echo "KERNEL_PATH=$kernel_path" >> $config_mak + if test $kbuild26 = "yes" ; then + echo "CONFIG_KBUILD26=yes" >> $config_mak + fi fi fi echo "SRC_PATH=$source_path" >> $config_mak -- cgit v1.2.3 From 430116a1d8acbc0ac843517b57f70b75fe56d9ae Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:35:05 +0000 Subject: debug fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1398 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/sdlaudio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index d6e13d03c..978686a07 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -217,7 +217,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len) static void sdl_hw_fini (HWVoice *hw) { ldebug ("sdl_hw_fini %d fixed=%d\n", - glob_sdl.initialized, audio_conf.fixed_format); + glob_sdl.initialized, audio_state.fixed_format); sdl_close (&glob_sdl); } @@ -229,7 +229,7 @@ static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) int shift; ldebug ("sdl_hw_init %d freq=%d fixed=%d\n", - s->initialized, freq, audio_conf.fixed_format); + s->initialized, freq, audio_state.fixed_format); if (nchannels != 2) { dolog ("Bogus channel count %d\n", nchannels); -- cgit v1.2.3 From e50e6a20192616b93d94be316556deb001e4f477 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:36:11 +0000 Subject: better arm conditionnal execution implementation (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1399 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 37 ++++++++++++++++++++---------------- target-arm/translate.c | 51 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/target-arm/op.c b/target-arm/op.c index f4cbb6e66..08afa2f7c 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -251,104 +251,109 @@ void OPPROTO op_logic_T1_cc(void) void OPPROTO op_test_eq(void) { if (env->NZF == 0) - JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1);; FORCE_RET(); } void OPPROTO op_test_ne(void) { if (env->NZF != 0) - JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1);; FORCE_RET(); } void OPPROTO op_test_cs(void) { if (env->CF != 0) - JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_cc(void) { if (env->CF == 0) - JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_mi(void) { if ((env->NZF & 0x80000000) != 0) - JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_pl(void) { if ((env->NZF & 0x80000000) == 0) - JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_vs(void) { if ((env->VF & 0x80000000) != 0) - JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_vc(void) { if ((env->VF & 0x80000000) == 0) - JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_hi(void) { if (env->CF != 0 && env->NZF != 0) - JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_ls(void) { if (env->CF == 0 || env->NZF == 0) - JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_ge(void) { if (((env->VF ^ env->NZF) & 0x80000000) == 0) - JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_lt(void) { if (((env->VF ^ env->NZF) & 0x80000000) != 0) - JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_gt(void) { if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) - JUMP_TB(op_test_gt, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } void OPPROTO op_test_le(void) { if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) - JUMP_TB(op_test_le, PARAM1, 0, PARAM2); + GOTO_LABEL_PARAM(1); FORCE_RET(); } -void OPPROTO op_jmp(void) +void OPPROTO op_jmp0(void) { - JUMP_TB(op_jmp, PARAM1, 1, PARAM2); + JUMP_TB(op_jmp0, PARAM1, 0, PARAM2); +} + +void OPPROTO op_jmp1(void) +{ + JUMP_TB(op_jmp1, PARAM1, 1, PARAM2); } void OPPROTO op_exit_tb(void) diff --git a/target-arm/translate.c b/target-arm/translate.c index 315595e89..c9005c4b8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -32,6 +32,10 @@ typedef struct DisasContext { target_ulong pc; int is_jmp; + /* Nonzero if this instruction has been conditionally skipped. */ + int condjmp; + /* The label that will be jumped to when the instruction is skipped. */ + int condlabel; struct TranslationBlock *tb; int singlestep_enabled; } DisasContext; @@ -53,7 +57,7 @@ enum { #include "gen-op.h" -static GenOpFunc2 *gen_test_cc[14] = { +static GenOpFunc1 *gen_test_cc[14] = { gen_op_test_eq, gen_op_test_ne, gen_op_test_cs, @@ -896,7 +900,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) gen_op_movl_T0_im(dest); gen_bx(s); } else { - gen_op_jmp((long)s->tb, dest); + gen_op_jmp0((long)s->tb, dest); s->is_jmp = DISAS_TB_JUMP; } } @@ -939,8 +943,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (cond != 0xe) { /* if not always execute, we generate a conditional jump to next instruction */ - gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); - s->is_jmp = DISAS_JUMP_NEXT; + s->condlabel = gen_new_label(); + gen_test_cc[cond ^ 1](s->condlabel); + s->condjmp = 1; + //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); + //s->is_jmp = DISAS_JUMP_NEXT; } if ((insn & 0x0f900000) == 0x03000000) { if ((insn & 0x0ff0f000) != 0x0360f000) @@ -1961,8 +1968,11 @@ static void disas_thumb_insn(DisasContext *s) break; } /* generate a conditional jump to next instruction */ - gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); - s->is_jmp = DISAS_JUMP_NEXT; + s->condlabel = gen_new_label(); + gen_test_cc[cond ^ 1](s->condlabel); + s->condjmp = 1; + //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); + //s->is_jmp = DISAS_JUMP_NEXT; gen_movl_T1_reg(s, 15); /* jump to the offset */ @@ -2034,6 +2044,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; dc->singlestep_enabled = env->singlestep_enabled; + dc->condjmp = 0; + nb_gen_labels = 0; lj = -1; do { if (env->nb_breakpoints > 0) { @@ -2057,25 +2069,41 @@ static inline int gen_intermediate_code_internal(CPUState *env, gen_opc_pc[lj] = dc->pc; gen_opc_instr_start[lj] = 1; } + if (env->thumb) disas_thumb_insn(dc); else disas_arm_insn(env, dc); + + if (dc->condjmp && !dc->is_jmp) { + gen_set_label(dc->condlabel); + dc->condjmp = 0; + } + /* Translation stops when a conditional branch is enoutered. + * Otherwise the subsequent code could get translated several times. + */ } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + /* It this stage dc->condjmp will only be set when the skipped + * instruction was a conditional branch, and teh PC has already been + * written. */ if (__builtin_expect(env->singlestep_enabled, 0)) { /* Make sure the pc is updated, and raise a debug exception. */ - if (dc->is_jmp == DISAS_NEXT || dc->is_jmp == DISAS_JUMP_NEXT) { + if (dc->condjmp) { + gen_op_debug(); + gen_set_label(dc->condlabel); + } + if (dc->condjmp || !dc->is_jmp) { gen_op_movl_T0_im((long)dc->pc); gen_op_movl_reg_TN[0][15](); + dc->condjmp = 0; } gen_op_debug(); } else { switch(dc->is_jmp) { - case DISAS_JUMP_NEXT: case DISAS_NEXT: - gen_op_jmp((long)dc->tb, (long)dc->pc); + gen_op_jmp1((long)dc->tb, (long)dc->pc); break; default: case DISAS_JUMP: @@ -2088,6 +2116,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, /* nothing more to generate */ break; } + if (dc->condjmp) { + gen_set_label(dc->condlabel); + gen_op_jmp1((long)dc->tb, (long)dc->pc); + dc->condjmp = 0; + } } *gen_opc_ptr = INDEX_op_end; -- cgit v1.2.3 From 43fb823b5f89c6d716e2cbce603c6fb1ca6c0b2f Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:38:17 +0000 Subject: removed switches in op.c (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1400 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 90 +++++++++++++-------------------------------------- target-i386/ops_sse.h | 82 ++++++++-------------------------------------- 2 files changed, 36 insertions(+), 136 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index c157b120b..2af4e8eb3 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1952,94 +1952,48 @@ void OPPROTO op_fxchg_ST0_STN(void) /* FPU operations */ +const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500}; + void OPPROTO op_fcom_ST0_FT0(void) { - int cc; - switch(floatx_compare(ST0, FT0, &env->fp_status)) { - case -1: - cc = 0x0100; - break; - case 0: - cc = 0x4000; - break; - case 1: - cc = 0x0000; - break; - case 2: - default: - cc = 0x4500; - break; - } - env->fpus = (env->fpus & ~0x4500) | cc; + int ret; + + ret = floatx_compare(ST0, FT0, &env->fp_status); + env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1]; FORCE_RET(); } void OPPROTO op_fucom_ST0_FT0(void) { - int cc; - switch(floatx_compare_quiet(ST0, FT0, &env->fp_status)) { - case -1: - cc = 0x0100; - break; - case 0: - cc = 0x4000; - break; - case 1: - cc = 0x0000; - break; - case 2: - default: - cc = 0x4500; - break; - } - env->fpus = (env->fpus & ~0x4500) | cc; + int ret; + + ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); + env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1]; FORCE_RET(); } +const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; + void OPPROTO op_fcomi_ST0_FT0(void) { - int eflags, cc; - switch(floatx_compare(ST0, FT0, &env->fp_status)) { - case -1: - cc = CC_C; - break; - case 0: - cc = CC_Z; - break; - case 1: - cc = 0; - break; - case 2: - default: - cc = CC_Z | CC_P | CC_C; - break; - } + int eflags; + int ret; + + ret = floatx_compare(ST0, FT0, &env->fp_status); eflags = cc_table[CC_OP].compute_all(); - eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | cc; + eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; CC_SRC = eflags; FORCE_RET(); } void OPPROTO op_fucomi_ST0_FT0(void) { - int eflags, cc; - switch(floatx_compare_quiet(ST0, FT0, &env->fp_status)) { - case -1: - cc = CC_C; - break; - case 0: - cc = CC_Z; - break; - case 1: - cc = 0; - break; - case 2: - default: - cc = CC_Z | CC_P | CC_C; - break; - } + int eflags; + int ret; + + ret = floatx_compare_quiet(ST0, FT0, &env->fp_status); eflags = cc_table[CC_OP].compute_all(); - eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | cc; + eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1]; CC_SRC = eflags; FORCE_RET(); } diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index f982594a8..cdc380120 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -1079,9 +1079,11 @@ SSE_OP_CMP(cmpnlt, FPU_CMPNLT) SSE_OP_CMP(cmpnle, FPU_CMPNLE) SSE_OP_CMP(cmpord, FPU_CMPORD) +const int comis_eflags[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; + void OPPROTO op_ucomiss(void) { - int eflags; + int ret; float32 s0, s1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); @@ -1089,28 +1091,14 @@ void OPPROTO op_ucomiss(void) s0 = d->XMM_S(0); s1 = s->XMM_S(0); - switch(float32_compare_quiet(s0, s1, &env->sse_status)) { - case -1: - eflags = CC_C; - break; - case 0: - eflags = CC_Z; - break; - case 1: - eflags = 0; - break; - case 2: - default: - eflags = CC_Z | CC_P | CC_C; - break; - } - CC_SRC = eflags; + ret = float32_compare_quiet(s0, s1, &env->sse_status); + CC_SRC = comis_eflags[ret + 1]; FORCE_RET(); } void OPPROTO op_comiss(void) { - int eflags; + int ret; float32 s0, s1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); @@ -1118,28 +1106,14 @@ void OPPROTO op_comiss(void) s0 = d->XMM_S(0); s1 = s->XMM_S(0); - switch(float32_compare(s0, s1, &env->sse_status)) { - case -1: - eflags = CC_C; - break; - case 0: - eflags = CC_Z; - break; - case 1: - eflags = 0; - break; - case 2: - default: - eflags = CC_Z | CC_P | CC_C; - break; - } - CC_SRC = eflags; + ret = float32_compare(s0, s1, &env->sse_status); + CC_SRC = comis_eflags[ret + 1]; FORCE_RET(); } void OPPROTO op_ucomisd(void) { - int eflags; + int ret; float64 d0, d1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); @@ -1147,28 +1121,14 @@ void OPPROTO op_ucomisd(void) d0 = d->XMM_D(0); d1 = s->XMM_D(0); - switch(float64_compare_quiet(d0, d1, &env->sse_status)) { - case -1: - eflags = CC_C; - break; - case 0: - eflags = CC_Z; - break; - case 1: - eflags = 0; - break; - case 2: - default: - eflags = CC_Z | CC_P | CC_C; - break; - } - CC_SRC = eflags; + ret = float64_compare_quiet(d0, d1, &env->sse_status); + CC_SRC = comis_eflags[ret + 1]; FORCE_RET(); } void OPPROTO op_comisd(void) { - int eflags; + int ret; float64 d0, d1; Reg *d, *s; d = (Reg *)((char *)env + PARAM1); @@ -1176,22 +1136,8 @@ void OPPROTO op_comisd(void) d0 = d->XMM_D(0); d1 = s->XMM_D(0); - switch(float64_compare(d0, d1, &env->sse_status)) { - case -1: - eflags = CC_C; - break; - case 0: - eflags = CC_Z; - break; - case 1: - eflags = 0; - break; - case 2: - default: - eflags = CC_Z | CC_P | CC_C; - break; - } - CC_SRC = eflags; + ret = float64_compare(d0, d1, &env->sse_status); + CC_SRC = comis_eflags[ret + 1]; FORCE_RET(); } -- cgit v1.2.3 From e90096763d74b1126cf502c2d710d64df5ecbb63 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:42:36 +0000 Subject: report user mode gdb exit codes (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1401 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 16 ++++++++++++++++ gdbstub.h | 1 + linux-user/syscall.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/gdbstub.c b/gdbstub.c index eb3062708..527d2e926 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -656,6 +656,22 @@ gdb_handlesig (CPUState *env, int sig) } return sig; } + +/* Tell the remote gdb that the process has exited. */ +void gdb_exit(CPUState *env, int code) +{ + GDBState *s; + char buf[4]; + + if (gdbserver_fd < 0) + return; + + s = &gdbserver_state; + + snprintf(buf, sizeof(buf), "W%02x", code); + put_packet(s, buf); +} + #else static int gdb_can_read(void *opaque) { diff --git a/gdbstub.h b/gdbstub.h index 63b88dadc..7b42596f1 100644 --- a/gdbstub.h +++ b/gdbstub.h @@ -5,6 +5,7 @@ #ifdef CONFIG_USER_ONLY int gdb_handlesig (CPUState *, int); +void gdb_exit(CPUState *, int); #endif int gdbserver_start(int); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b00ce90cb..0a4f07e31 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1603,6 +1603,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef HAVE_GPROF _mcleanup(); #endif + gdb_exit(cpu_env, arg1); /* XXX: should free thread stack and CPU env */ _exit(arg1); ret = 0; /* avoid warning */ @@ -2409,6 +2410,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef __NR_exit_group /* new thread calls */ case TARGET_NR_exit_group: + gdb_exit(cpu_env, arg1); ret = get_errno(exit_group(arg1)); break; #endif -- cgit v1.2.3 From d0b3e73525f17fcffff7219c6bcc2b214cff7374 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:44:10 +0000 Subject: SYS_SEEK fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1402 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm-semi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c index f37b65c47..ea014f6bc 100644 --- a/linux-user/arm-semi.c +++ b/linux-user/arm-semi.c @@ -124,7 +124,10 @@ uint32_t do_arm_semihosting(CPUState *env) case SYS_ISTTY: return isatty(ARG(0)); case SYS_SEEK: - return set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); + ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); + if (ret == (uint32_t)-1) + return -1; + return 0; case SYS_FLEN: { struct stat buf; -- cgit v1.2.3 From e4afee9716d20cbc7d1875a66411f85c8c640286 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:46:24 +0000 Subject: cosmetics git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1403 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 3e26b8071..05e8a5999 100755 --- a/configure +++ b/configure @@ -158,8 +158,6 @@ for opt do ;; --extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}" ;; - --extra-libs=*) extralibs=${opt#--extra-libs=} - ;; --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` ;; --target-list=*) target_list=${opt#--target-list=} @@ -420,7 +418,9 @@ if test "$darwin" = "yes" ; then echo "Cocoa support $cocoa" fi echo "SDL support $sdl" -echo "SDL static link $sdl_static" +if test "$sdl" != "no" ; then + echo "SDL static link $sdl_static" +fi echo "mingw32 support $mingw32" echo "Adlib support $adlib" echo -n "FMOD support $fmod" -- cgit v1.2.3 From ad81218e40e27d79e1021c248cf16ca269d963df Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 20:49:17 +0000 Subject: depth=24 write mask fix (Volker Ruppert) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1404 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 2 +- hw/cirrus_vga_rop2.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 13450f0fc..934cde990 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -31,7 +31,7 @@ /* * TODO: - * - add support for WRITEMASK (GR2F) + * - destination write mask support not complete (bits 5..7) * - optimize linear mappings * - optimize bitblt functions */ diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h index a326f97b7..2f61740e5 100644 --- a/hw/cirrus_vga_rop2.h +++ b/hw/cirrus_vga_rop2.h @@ -47,7 +47,11 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) int x, y, pattern_y, pattern_pitch, pattern_x; unsigned int col; const uint8_t *src1; +#if DEPTH == 24 + int skipleft = s->gr[0x2f] & 0x1f; +#else int skipleft = (s->gr[0x2f] & 0x07) * (DEPTH / 8); +#endif #if DEPTH == 8 pattern_pitch = 8; @@ -100,8 +104,13 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) unsigned int col; unsigned bitmask; unsigned index; +#if DEPTH == 24 + int dstskipleft = s->gr[0x2f] & 0x1f; + int srcskipleft = dstskipleft / 3; +#else int srcskipleft = s->gr[0x2f] & 0x07; int dstskipleft = srcskipleft * (DEPTH / 8); +#endif if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { bits_xor = 0xff; @@ -178,8 +187,13 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) int x, y, bitpos, pattern_y; unsigned int bits, bits_xor; unsigned int col; +#if DEPTH == 24 + int dstskipleft = s->gr[0x2f] & 0x1f; + int srcskipleft = dstskipleft / 3; +#else int srcskipleft = s->gr[0x2f] & 0x07; int dstskipleft = srcskipleft * (DEPTH / 8); +#endif if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { bits_xor = 0xff; -- cgit v1.2.3 From 6d82d04a498a7c8a74a04f6b59c623eb3c2d69b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 21:02:48 +0000 Subject: proll update: IDE HDD/CD support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1405 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/proll.elf | Bin 137898 -> 152807 bytes pc-bios/proll.patch | 889 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 792 insertions(+), 97 deletions(-) diff --git a/pc-bios/proll.elf b/pc-bios/proll.elf index ac93c4be9..f6198f4d6 100644 Binary files a/pc-bios/proll.elf and b/pc-bios/proll.elf differ diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch index e72e0e45e..fb215a0c6 100644 --- a/pc-bios/proll.patch +++ b/pc-bios/proll.patch @@ -1,6 +1,6 @@ -diff -ruN proll_18.orig/Makefile proll-patch8/Makefile +diff -ruN proll_18.orig/Makefile proll-patch10/Makefile --- proll_18.orig/Makefile 2002-09-13 14:16:59.000000000 +0000 -+++ proll-patch8/Makefile 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/Makefile 2004-11-13 15:50:49.000000000 +0000 @@ -4,6 +4,7 @@ make -C krups-ser all make -C espresso all @@ -14,14 +14,14 @@ diff -ruN proll_18.orig/Makefile proll-patch8/Makefile make -C espresso clean make -C espresso-ser clean + make -C qemu clean -diff -ruN proll_18.orig/qemu/Makefile proll-patch8/qemu/Makefile +diff -ruN proll_18.orig/qemu/Makefile proll-patch10/qemu/Makefile --- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch8/qemu/Makefile 2005-03-02 16:41:50.000000000 +0000 -@@ -0,0 +1,122 @@ ++++ proll-patch10/qemu/Makefile 2005-04-12 14:42:23.000000000 +0000 +@@ -0,0 +1,123 @@ +# +# proll: +# qemu/Makefile - make PROLL for QEMU -+# $Id: proll.patch,v 1.4 2005-04-06 20:45:26 bellard Exp $ ++# $Id: proll.patch,v 1.5 2005-04-26 21:02:48 bellard Exp $ +# +# Copyright 1999 Pete Zaitcev +# This is Free Software is licensed under terms of GNU General Public License. @@ -47,8 +47,8 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch8/qemu/Makefile +# want to shift it to form a PGD entry. A relocatable label will not work. +# Linux kernel expects us to be at LINUX_OPPROM_BEGVM . +PROLBASE = 0xffd00000 -+PROLRODATA = 0xffd07000 -+PROLDATA = 0xffd09000 ++PROLRODATA = 0xffd08000 ++PROLDATA = 0xffd0b000 +PROLSIZE = 240*1024 + +# Linux @@ -68,7 +68,7 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch8/qemu/Makefile +OBJS = head.o wuf.o wof.o main.o $(CONSOLE) \ + printf.o le.o system_qemu.o iommu.o \ + arp.o netinit.o bootp.o packet.o tftp.o udp.o sched_4m.o openprom.o \ -+ vconsole.o hconsole.o rconsole.o vcons_zs.o ++ vconsole.o hconsole.o rconsole.o vcons_zs.o esp.o + +all: $(ALL) + @@ -106,7 +106,8 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch8/qemu/Makefile + $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c +le.o: $(SRC)/le.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/netpriv.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/net.h $(SRC)/phys_jj.h + $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+ ++esp.o: $(SRC)/esp.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/phys_jj.h ++ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c +arp.o: $(SRC)/arp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h + $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c +netinit.o: $(SRC)/netinit.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h @@ -140,9 +141,9 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch8/qemu/Makefile + +proll.aout: $(PROLLEXE) + $(ELFTOAOUT) -o proll.aout $(PROLLEXE) -diff -ruN proll_18.orig/qemu/head.S proll-patch8/qemu/head.S +diff -ruN proll_18.orig/qemu/head.S proll-patch10/qemu/head.S --- proll_18.orig/qemu/head.S 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch8/qemu/head.S 2005-03-02 15:30:47.000000000 +0000 ++++ proll-patch10/qemu/head.S 2005-03-02 15:30:47.000000000 +0000 @@ -0,0 +1,539 @@ +/** + ** Standalone startup code for Linux PROM emulator. @@ -150,7 +151,7 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch8/qemu/head.S + ** This code is licensed under GNU General Public License. + **/ +/* -+ * $Id: proll.patch,v 1.4 2005-04-06 20:45:26 bellard Exp $ ++ * $Id: proll.patch,v 1.5 2005-04-26 21:02:48 bellard Exp $ + */ + +#include @@ -683,10 +684,10 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch8/qemu/head.S +C_LABEL(ldb_bypass): + retl + lduba [%o0] ASI_M_BYPASS, %o0 -diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c +diff -ruN proll_18.orig/qemu/main.c proll-patch10/qemu/main.c --- proll_18.orig/qemu/main.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch8/qemu/main.c 2005-04-03 11:58:46.000000000 +0000 -@@ -0,0 +1,173 @@ ++++ proll-patch10/qemu/main.c 2005-04-16 18:03:23.000000000 +0000 +@@ -0,0 +1,185 @@ +/** + ** Proll (PROM replacement) + ** Copyright 1999 Pete Zaitcev @@ -711,7 +712,9 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c +void *init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, const char *cmdline, char boot_device, int nographic); +int vcon_zs_init(struct vconterm *t, unsigned int a0); +int vcon_zs_write(struct vconterm *t, char *data, int leng); -+ ++int vcon_zs_getch(struct vconterm *t); ++void esp_probe(); ++int esp_boot(int unit); +static void init_idprom(void); + +struct vconterm dp0; @@ -733,7 +736,7 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c +} *hw_idprom; + +int ignore_fault, fault_ignored; -+void *printk_fn; ++void *printk_fn, *getch_fn; +unsigned int q_height, q_width; + +/* @@ -745,7 +748,7 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c + unsigned int hiphybas; + const void *romvec; + unsigned int ram_size; -+ char nographic; ++ char nographic, bootdev; + + nographic = ldb_bypass(PHYS_JJ_EEPROM + 0x2F); + if (!nographic) { @@ -753,10 +756,12 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c + q_height = ldh_bypass(PHYS_JJ_EEPROM + 0x56); + vcon_init(&dp0, PHYS_JJ_TCX_FB); + printk_fn = vcon_write; ++ getch_fn = vcon_getch; + } + else { + vcon_zs_init(&dp0, 0x71100004); + printk_fn = vcon_zs_write; ++ getch_fn = vcon_zs_getch; + } + + @@ -790,9 +795,13 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c + sched_init(); + le_probe(); + init_net(); ++ esp_probe(); + -+ printk("Boot device: %c\n", hw_idprom->boot_device); -+ if (hw_idprom->boot_device == 'n') { ++ bootdev = hw_idprom->boot_device; ++ printk("Boot device: %c\n", bootdev); ++ if (hw_idprom->kernel_size > 0) { ++ printk("Kernel already loaded\n"); ++ } else if (bootdev == 'n') { + if (bootp() != 0) fatal(); + /* + * boot_rec.bp_file cannot be used because system PROM @@ -809,6 +818,10 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c + fname[14] = 0; + + if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); ++ } else if (bootdev == 'c') { ++ if (esp_boot(0) != 0) fatal(); ++ } else if (bootdev == 'd') { ++ if (esp_boot(2) != 0) fatal(); + } + + romvec = init_openprom_qemu(bb.nbanks, bb.bankv, hiphybas, @@ -860,10 +873,10 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch8/qemu/main.c + hw_idprom = va_prom; +} + -diff -ruN proll_18.orig/qemu/openprom.c proll-patch8/qemu/openprom.c +diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c --- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch8/qemu/openprom.c 2005-04-06 16:53:31.000000000 +0000 -@@ -0,0 +1,665 @@ ++++ proll-patch10/qemu/openprom.c 2005-04-16 17:30:19.000000000 +0000 +@@ -0,0 +1,741 @@ +/* + * PROM interface support + * Copyright 1996 The Australian National University. @@ -882,6 +895,8 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch8/qemu/openprom.c + +//#define DEBUG_OBP + ++#define PAGE_SIZE 4096 ++ +struct property { + const char *name; + const char *value; @@ -1275,6 +1290,8 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch8/qemu/openprom.c +static int obp_devopen(char *str); +static int obp_devclose(int dev_desc); +static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf); ++static char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size); ++static void obp_dumb_munmap(char *va, unsigned int size); + +static void doublewalk(unsigned ptab1, unsigned va) +{ @@ -1353,20 +1370,34 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch8/qemu/openprom.c + romvec0.pv_nbgetchar = obp_nbgetchar; + romvec0.pv_nbputchar = obp_nbputchar; + romvec0.pv_reboot = obp_reboot; ++ romvec0.pv_printf = (void (*)(const char *fmt, ...))printk; + romvec0.pv_abort = obp_abort; + romvec0.pv_halt = obp_halt; + romvec0.pv_synchook = &synch_hook; + romvec0.pv_v0bootargs = &obp_argp; ++ romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap; ++ romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap; ++ obp_arg.boot_dev_ctrl = 0; ++ obp_arg.boot_dev_unit = '0'; + switch(boot_device) { + default: + case 'a': + obp_arg.argv[0] = "fd()"; ++ obp_arg.boot_dev[0] = 'f'; ++ obp_arg.boot_dev[1] = 'd'; + break; ++ case 'd': ++ obp_arg.boot_dev_unit = '2'; ++ // Fall through + case 'c': + obp_arg.argv[0] = "sd()"; ++ obp_arg.boot_dev[0] = 's'; ++ obp_arg.boot_dev[1] = 'd'; + break; + case 'n': + obp_arg.argv[0] = "le()"; ++ obp_arg.boot_dev[0] = 'l'; ++ obp_arg.boot_dev[1] = 'e'; + break; + } + obp_arg.argv[1] = cmdline; @@ -1483,9 +1514,11 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch8/qemu/openprom.c + return (const char *)-1; +} + ++extern int (*getch_fn)(struct vconterm *v); ++ +static int obp_nbgetchar(void) { + extern struct vconterm dp0; -+ return vcon_getch(&dp0); ++ return getch_fn(&dp0); +} + +static int obp_nbputchar(int ch) { @@ -1507,32 +1540,88 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch8/qemu/openprom.c + printk("halt, freezing\n"); + for (;;) {} +} -+ ++#define isnum(c) ((c >= '0') && (c < '9')) ++#define ctoi(c) (c - '0') +static int obp_devopen(char *str) { +#ifdef DEBUG_OBP -+ printk("open %s\n", str); ++ printk("obp_devopen(%s)\n", str); +#endif ++ if (str[0] == 's' && str[1] == 'd' && str[4] == ',') { ++ unsigned int target; ++ ++ if (str[5] < 7) ++ target = str[5]; ++ else if (isnum(str[6]) && isnum(str[5])) { ++ target = (ctoi(str[5]) * 10 + ctoi(str[6])) & 7; ++ } ++ else { ++ target = ctoi(str[5]) & 7; ++ } ++ return 's' + target; ++ } + return 0; +} + +static int obp_devclose(int dev_desc) { +#ifdef DEBUG_OBP -+ printk("close %d\n", dev_desc); ++ printk("obp_devclose %d\n", dev_desc); +#endif + return 0; +} + -+static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf) { ++extern void *esp_read(int unit, int offset, short len); ++ ++static int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf) ++{ ++ unsigned int i; ++ void *src; ++ +#ifdef DEBUG_OBP -+ printk("rdblkdev: fd %d, num_blks %d, blk_st %d, buf 0x%x\n", dev_desc, num_blks, blk_st, buf); ++ printk("obp_rdblkdev: fd %d, num_blks %d, offset %d, buf 0x%x\n", dev_desc, num_blks, offset, buf); +#endif -+ //buf[8] = 'L'; -+ return num_blks; ++ if (dev_desc >= 's' && dev_desc < 'v') { ++ for(i = 0; i < num_blks; i++) { ++ src = esp_read(dev_desc - 's', offset + i, 1); ++ memcpy(&buf[i << 9], src, 512); ++ } ++ return num_blks; ++ } ++ return -1; +} -diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch8/qemu/system_qemu.c ++ ++static char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size) ++{ ++ unsigned int npages; ++ unsigned int off; ++ unsigned int mva; ++ ++#ifdef DEBUG_OBP ++ printk("obp_dumb_mmap: virta %x, which_io %d, paddr %x, sz %d\n", va, which_io, pa, size); ++#endif ++ off = pa & (PAGE_SIZE-1); ++ npages = (off + size + (PAGE_SIZE-1)) / PAGE_SIZE; ++ pa &= ~(PAGE_SIZE-1); ++ ++ mva = (unsigned int) va; ++ while (npages-- != 0) { ++ map_page(pmem.pl1, mva, pa, 1, pmem.pbas); ++ mva += PAGE_SIZE; ++ pa += PAGE_SIZE; ++ } ++ return va; ++} ++ ++static void obp_dumb_munmap(char *va, unsigned int size) ++{ ++#ifdef DEBUG_OBP ++ printk("obp_dumb_munmap: virta %x, sz %d\n", va, size); ++#endif ++ ++} +diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch10/qemu/system_qemu.c --- proll_18.orig/qemu/system_qemu.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch8/qemu/system_qemu.c 2005-03-02 16:10:20.000000000 +0000 -@@ -0,0 +1,416 @@ ++++ proll-patch10/qemu/system_qemu.c 2005-04-16 06:16:20.000000000 +0000 +@@ -0,0 +1,430 @@ +/** + ** Proll (PROM replacement) + ** system.c: shared miscallenea. @@ -1859,19 +1948,30 @@ diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch8/qemu/system_qemu.c +{ + char *p; + -+ if ((p = mem_alloc(t, size, align)) != 0) bzero(p, size); ++ if ((p = mem_alloc(t, size, align)) != 0) memset(p, 0, size); + return p; +} + +/* + * Library functions + */ -+void bzero(void *s, int len) { -+ while (len--) *((char *)s)++ = 0; ++void *memset(void *s, int c, size_t len) ++{ ++ void *p = s; ++ ++ while (len--) { ++ *(char *)s = c; ++ s++; ++ } ++ return p; +} + +void bcopy(const void *f, void *t, int len) { -+ while (len--) *((char *)t)++ = *((char *)f)++; ++ while (len--) { ++ *(char *)t = *(char *)f; ++ f++; ++ t++; ++ } +} + +/* Comparison is 7-bit */ @@ -1881,8 +1981,11 @@ diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch8/qemu/system_qemu.c + char ch; + + while (len--) { -+ ch = *((char *)s1)++; -+ if ((i = ch - *((char *)s2)++) != 0) ++ ch = *(char *)s1; ++ i = ch - *(char *)s2; ++ s1++; ++ s2++; ++ if (i != 0) + return i; + if (ch == 0) + return 0; @@ -1949,9 +2052,9 @@ diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch8/qemu/system_qemu.c + n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); + st_bypass(ptr, n); +}; -diff -ruN proll_18.orig/src/arp.c proll-patch8/src/arp.c +diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c --- proll_18.orig/src/arp.c 2001-12-24 05:12:31.000000000 +0000 -+++ proll-patch8/src/arp.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/arp.c 2004-11-13 15:50:49.000000000 +0000 @@ -45,7 +45,7 @@ #endif static struct arp_cache arp_list[ARPNUM]; /* ARP address cache */ @@ -1986,9 +2089,9 @@ diff -ruN proll_18.orig/src/arp.c proll-patch8/src/arp.c + def_gw = IP_ANY; return(TRUE); } -diff -ruN proll_18.orig/src/arp.h proll-patch8/src/arp.h +diff -ruN proll_18.orig/src/arp.h proll-patch10/src/arp.h --- proll_18.orig/src/arp.h 1999-03-18 03:39:43.000000000 +0000 -+++ proll-patch8/src/arp.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/arp.h 2004-11-13 15:50:49.000000000 +0000 @@ -104,7 +104,7 @@ extern int init_arp __P((void)); @@ -1998,9 +2101,265 @@ diff -ruN proll_18.orig/src/arp.h proll-patch8/src/arp.h /* Add a new antry to the ARP cache */ extern void addcache __P((unsigned char *ha, t_ipaddr ip)); -diff -ruN proll_18.orig/src/hconsole.c proll-patch8/src/hconsole.c +diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c +--- proll_18.orig/src/esp.c 1970-01-01 00:00:00.000000000 +0000 ++++ proll-patch10/src/esp.c 2005-04-16 06:24:23.000000000 +0000 +@@ -0,0 +1,252 @@ ++#include /* == */ ++#include /* __P for netpriv.h */ ++#include /* dmaga */ ++#include ++ ++#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */ ++#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ ++#define PHYS_JJ_ESP_IRQ 4 ++#define BUFSIZE 4096 ++/* ++ * XXX Crude ++ */ ++struct esp_dma { ++ struct sparc_dma_registers *regs; ++ enum dvma_rev revision; ++}; ++ ++struct esp_regs { ++ unsigned int regs[16]; ++}; ++ ++struct esp_private { ++ int active; /* initialized */ ++ int inst; /* iface number */ ++ ++ volatile struct esp_regs *ll; ++ __u32 buffer_dvma; ++ unsigned int irq; /* device IRQ number */ ++ int interrupt; ++ ++ struct esp_dma *espdma; /* If set this points to espdma */ ++ ++ unsigned char *buffer; ++}; ++ ++static void esp_interrupt(void *dev_id) ++{ ++ struct esp_private *lp = (struct esp_private *)dev_id; ++ ++ lp->interrupt = 1; ++ /* Acknowledge all the interrupt sources ASAP */ ++ ++ lp->interrupt = 0; ++} ++ ++static int esp_open (void *dev) ++{ ++ struct esp_private *lp = (struct esp_private *)dev; ++ int status = 0; ++ ++ if (request_irq(lp->irq, &esp_interrupt, (void *)dev)) { ++ printk ("Esp: Can't get irq %d\n", lp->irq); ++ return -1; ++ } ++ ++ /* On the 4m, setup the espdma to provide the upper bits for buffers */ ++ if (lp->espdma) ++ lp->espdma->regs->dma_test = ((__u32) lp->buffer_dvma) & 0xff000000; ++ ++ return status; ++} ++ ++static int esp_close (void *dev) ++{ ++ struct esp_private *lp = (struct esp_private *)dev; ++ ++ free_irq (lp->irq, (void *) dev); ++ return 0; ++} ++ ++static int ++esp_init(struct esp_private *esp, struct esp_dma *espdma, int irq) ++{ ++ volatile struct esp_regs *ll; ++ ++ /* Get the IO region */ ++ ll = map_io(PHYS_JJ_ESP, sizeof (struct esp_regs)); ++ if (ll == 0) return -1; ++ ++ esp->buffer = dvma_alloc(BUFSIZE, &esp->buffer_dvma); ++ esp->ll = ll; ++ esp->espdma = espdma; ++ esp->irq = irq; ++ ++ // Chip reset ++ stb_bypass((int)ll + 3*2, 2); ++ return 0; ++} ++ ++static int espdma_init(struct esp_dma *espdma) ++{ ++ void *p; ++ ++ /* Hardcode everything for MrCoffee. */ ++ if ((p = map_io(PHYS_JJ_ESPDMA, 0x10)) == 0) { ++ printk("espdma_init: cannot map registers\n"); ++ return -1; ++ } ++ espdma->regs = p; ++ ++ printk("dma1: "); ++ ++ switch((espdma->regs->cond_reg)&DMA_DEVICE_ID) { ++ case DMA_VERS0: ++ espdma->revision=dvmarev0; ++ printk("Revision 0 "); ++ break; ++ case DMA_ESCV1: ++ espdma->revision=dvmaesc1; ++ printk("ESC Revision 1 "); ++ break; ++ case DMA_VERS1: ++ espdma->revision=dvmarev1; ++ printk("Revision 1 "); ++ break; ++ case DMA_VERS2: ++ espdma->revision=dvmarev2; ++ printk("Revision 2 "); ++ break; ++ case DMA_VERHME: ++ espdma->revision=dvmahme; ++ printk("HME DVMA gate array "); ++ break; ++ case DMA_VERSPLUS: ++ espdma->revision=dvmarevplus; ++ printk("Revision 1 PLUS "); ++ break; ++ default: ++ printk("unknown dma version %x", ++ (espdma->regs->cond_reg)&DMA_DEVICE_ID); ++ /* espdma->allocated = 1; */ ++ break; ++ } ++ printk("\n"); ++ return 0; ++} ++ ++static struct esp_dma espdma0; ++static struct esp_private esp; ++/* ++ * Find all the esp cards on the system and initialize them ++ */ ++void esp_probe () ++{ ++ if (espdma_init(&espdma0) != 0) { ++ return; ++ } ++ ++ if (esp_init(&esp, &espdma0, PHYS_JJ_ESP_IRQ) != 0) { ++ printk("esp_probe: esp0 init failed\n"); ++ return; ++ } ++ return; ++} ++ ++void *esp_read(int unit, int offset, short len) ++{ ++ // Set SCSI target ++ stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7); ++ // Set DMA address ++ st_bypass(PHYS_JJ_ESPDMA + 4, esp.buffer_dvma); ++ // Set DMA length ++ stb_bypass(PHYS_JJ_ESP + 0*4, 10); ++ stb_bypass(PHYS_JJ_ESP + 1*4, 0); ++ // Set DMA direction ++ st_bypass(PHYS_JJ_ESPDMA + 0, 0x000); ++ // Setup command = Read(10) ++ esp.buffer[0] = 0x80; ++ esp.buffer[1] = 0x28; ++ esp.buffer[2] = 0x00; ++ esp.buffer[3] = (offset >> 24) & 0xff; ++ esp.buffer[4] = (offset >> 16) & 0xff; ++ esp.buffer[5] = (offset >> 8) & 0xff; ++ esp.buffer[6] = offset & 0xff; ++ esp.buffer[7] = 0x00; ++ esp.buffer[8] = (len >> 8) & 0xff; ++ esp.buffer[9] = len & 0xff; ++ // Set ATN, issue command ++ stb_bypass(PHYS_JJ_ESP + 3*4, 0x42); ++ ++ // Set DMA length = 512 * read length ++ stb_bypass(PHYS_JJ_ESP + 0*4, 0); ++ stb_bypass(PHYS_JJ_ESP + 1*4, (len << 1) & 0xff); ++ // Set DMA direction ++ st_bypass(PHYS_JJ_ESPDMA + 0, 0x100); ++ // Transfer ++ stb_bypass(PHYS_JJ_ESP + 3*4, 0x10); ++ return esp.buffer; ++} ++ ++// Sparc boot sequence can be found in SILO docs, ++// first-isofs/README.SILO_ISOFS ++int esp_boot(int unit) ++{ ++ struct sun_disklabel { ++ unsigned char info[128]; /* Informative text string */ ++ unsigned char spare0[14]; ++ struct sun_info { ++ unsigned char spare1; ++ unsigned char id; ++ unsigned char spare2; ++ unsigned char flags; ++ } infos[8]; ++ unsigned char spare[246]; /* Boot information etc. */ ++ short rspeed; /* Disk rotational speed */ ++ short pcylcount; /* Physical cylinder count */ ++ short sparecyl; /* extra sects per cylinder */ ++ unsigned char spare2[4]; /* More magic... */ ++ short ilfact; /* Interleave factor */ ++ short ncyl; /* Data cylinder count */ ++ short nacyl; /* Alt. cylinder count */ ++ short ntrks; /* Tracks per cylinder */ ++ short nsect; /* Sectors per track */ ++ unsigned char spare3[4]; /* Even more magic... */ ++ struct sun_partition { ++ int start_cylinder; ++ int num_sectors; ++ } partitions[8]; ++ short magic; /* Magic number */ ++ short csum; /* Label xor'd checksum */ ++ } *label; ++ unsigned int i, offset; ++ void *src, *dst; ++ ++ printk("Loading partition table from target %d:\n", unit); ++ // Chip reset ++ stb_bypass(PHYS_JJ_ESP + 3*4, 2); ++ ++ esp_open(&esp); ++ ++ label = esp_read(unit, 0, 1); ++ printk("CHS: %d/%d/%d, partitions:\n", label->ncyl, label->ntrks, label->nsect); ++ for (i = 0; i < 8; i++) { ++ printk("%c: %d + %d\n", 'a' + i, label->partitions[i].start_cylinder, ++ label->partitions[i].num_sectors); ++ } ++ offset = label->partitions[4].start_cylinder * label->ntrks * label->nsect + 1; ++ printk("booting sd(0,%d,0):d (offset %d)\n", unit, offset); ++ // Skip a.out header (0x20) ++ dst = (void *)0x4000; ++ src = esp_read(unit, offset, 1); ++ src = (void *)((unsigned int) src + 0x20); ++ memcpy(dst, src, 512 - 0x20); ++ dst = (void *)0x4000 + 512 - 0x20; ++ for (i = 1; i < 7680/512; i++) { ++ src = esp_read(unit, offset + i, 1); ++ memcpy(dst, src, 512); ++ dst += 512; ++ } ++ esp_close(&esp); ++ return 0; ++} +diff -ruN proll_18.orig/src/hconsole.c proll-patch10/src/hconsole.c --- proll_18.orig/src/hconsole.c 2002-07-23 05:52:48.000000000 +0000 -+++ proll-patch8/src/hconsole.c 2005-03-02 17:03:09.000000000 +0000 ++++ proll-patch10/src/hconsole.c 2005-03-02 17:03:09.000000000 +0000 @@ -29,6 +29,10 @@ struct raster r_master; /* For a case of resize, whole fb */ struct raster r_0; /* malloc() erzatz */ @@ -2024,9 +2383,69 @@ diff -ruN proll_18.orig/src/hconsole.c proll-patch8/src/hconsole.c t->r_ = r; t->r0_ = q; t->f_ = &f_master; -diff -ruN proll_18.orig/src/lat7_2.bm proll-patch8/src/lat7_2.bm +diff -ruN proll_18.orig/src/hme.c proll-patch10/src/hme.c +--- proll_18.orig/src/hme.c 2002-07-23 05:52:52.000000000 +0000 ++++ proll-patch10/src/hme.c 2005-04-16 06:16:20.000000000 +0000 +@@ -655,10 +655,10 @@ + unsigned int flags, + unsigned int addr) + { +- __asm__ __volatile__(" +- stwa %3, [%0] %2 +- stwa %4, [%1] %2 +-" : /* no outputs */ ++ __asm__ __volatile__( ++ "stwa %3, [%0] %2\n\t" ++ "stwa %4, [%1] %2\n\t" ++ : /* no outputs */ + : "r" (&rp->rx_addr), "r" (&rp->rx_flags), + "i" (ASI_PL), "r" (addr), "r" (flags)); + } +@@ -667,10 +667,10 @@ + unsigned int flags, + unsigned int addr) + { +- __asm__ __volatile__(" +- stwa %3, [%0] %2 +- stwa %4, [%1] %2 +-" : /* no outputs */ ++ __asm__ __volatile__( ++ "stwa %3, [%0] %2\n\t" ++ "stwa %4, [%1] %2\n\t" ++ : /* no outputs */ + : "r" (&tp->tx_addr), "r" (&tp->tx_flags), + "i" (ASI_PL), "r" (addr), "r" (flags)); + } +@@ -2404,7 +2404,7 @@ + TXD(("[%d]", elem)); + this = &txbase[elem]; + #ifdef __sparc_v9__ +- __asm__ __volatile__("lduwa [%1] %2, %0" ++ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" + : "=r" (flags) + : "r" (&this->tx_flags), "i" (ASI_PL)); + #else +@@ -2447,7 +2447,7 @@ + RXD(("RX<")); + this = &rxbase[elem]; + #ifdef __sparc_v9__ +- __asm__ __volatile__("lduwa [%1] %2, %0" ++ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" + : "=r" (flags) + : "r" (&this->rx_flags), "i" (ASI_PL)); + #else +@@ -2530,7 +2530,7 @@ + elem = NEXT_RX(elem); + this = &rxbase[elem]; + #ifdef __sparc_v9__ +- __asm__ __volatile__("lduwa [%1] %2, %0" ++ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" + : "=r" (flags) + : "r" (&this->rx_flags), "i" (ASI_PL)); + #else +diff -ruN proll_18.orig/src/lat7_2.bm proll-patch10/src/lat7_2.bm --- proll_18.orig/src/lat7_2.bm 1999-02-27 05:48:54.000000000 +0000 -+++ proll-patch8/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 @@ -1,6 +1,6 @@ #define lat7_2_width 128 #define lat7_2_height 88 @@ -2035,9 +2454,9 @@ diff -ruN proll_18.orig/src/lat7_2.bm proll-patch8/src/lat7_2.bm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18, 0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02, -diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch8/src/lat7_2_swapped.bm +diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch10/src/lat7_2_swapped.bm --- proll_18.orig/src/lat7_2_swapped.bm 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch8/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 @@ -0,0 +1,121 @@ +#define lat7_2_width 128 +#define lat7_2_height 88 @@ -2160,9 +2579,9 @@ diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch8/src/lat7_2_swapped.bm + 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; -diff -ruN proll_18.orig/src/le.c proll-patch8/src/le.c +diff -ruN proll_18.orig/src/le.c proll-patch10/src/le.c --- proll_18.orig/src/le.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch8/src/le.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/le.c 2005-04-16 06:16:20.000000000 +0000 @@ -185,8 +185,6 @@ unsigned short rap; /* register address port */ }; @@ -2172,9 +2591,18 @@ diff -ruN proll_18.orig/src/le.c proll-patch8/src/le.c /* The Lance uses 24 bit addresses */ /* On the Sun4c the DVMA will provide the remaining bytes for us */ /* On the Sun4m we have to instruct the ledma to provide them */ -diff -ruN proll_18.orig/src/netinit.c proll-patch8/src/netinit.c +@@ -771,7 +769,7 @@ + /* Clear the slack of the packet, do I need this? */ + /* For a firewall its a good idea - AC */ + if (len != skblen) +- bzero((char *) &ib->tx_buf [entry][skblen], len - skblen); ++ memset((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); + + /* Now, give the packet to the lance */ + ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); +diff -ruN proll_18.orig/src/netinit.c proll-patch10/src/netinit.c --- proll_18.orig/src/netinit.c 2002-09-13 21:53:33.000000000 +0000 -+++ proll-patch8/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 @@ -49,13 +49,20 @@ unsigned char myhwaddr[ETH_ALEN]; /* my own hardware addr */ t_ipaddr myipaddr; /* my own IP address */ @@ -2218,9 +2646,9 @@ diff -ruN proll_18.orig/src/netinit.c proll-patch8/src/netinit.c fatal(); } } -diff -ruN proll_18.orig/src/netpriv.h proll-patch8/src/netpriv.h +diff -ruN proll_18.orig/src/netpriv.h proll-patch10/src/netpriv.h --- proll_18.orig/src/netpriv.h 1999-04-27 05:39:37.000000000 +0000 -+++ proll-patch8/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 @@ -130,10 +130,9 @@ * */ @@ -2242,9 +2670,9 @@ diff -ruN proll_18.orig/src/netpriv.h proll-patch8/src/netpriv.h /* Empty read buffer */ extern void empty_buf __P((void)); -diff -ruN proll_18.orig/src/openprom.h proll-patch8/src/openprom.h +diff -ruN proll_18.orig/src/openprom.h proll-patch10/src/openprom.h --- proll_18.orig/src/openprom.h 2002-07-14 02:26:30.000000000 +0000 -+++ proll-patch8/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 @@ -54,20 +54,20 @@ }; @@ -2306,9 +2734,9 @@ diff -ruN proll_18.orig/src/openprom.h proll-patch8/src/openprom.h }; /* More fun PROM structures for device probing. */ -diff -ruN proll_18.orig/src/packet.c proll-patch8/src/packet.c +diff -ruN proll_18.orig/src/packet.c proll-patch10/src/packet.c --- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000 -+++ proll-patch8/src/packet.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/packet.c 2004-11-13 15:50:49.000000000 +0000 @@ -41,7 +41,7 @@ int aligner; } wbuf; @@ -2336,9 +2764,9 @@ diff -ruN proll_18.orig/src/packet.c proll-patch8/src/packet.c { struct sk_buff *skb; unsigned char *s; -diff -ruN proll_18.orig/src/printf.c proll-patch8/src/printf.c +diff -ruN proll_18.orig/src/printf.c proll-patch10/src/printf.c --- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000 -+++ proll-patch8/src/printf.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/printf.c 2004-11-13 15:50:49.000000000 +0000 @@ -19,7 +19,7 @@ static void printn(struct prf_fp *, unsigned long, unsigned int); static void putchar(char, struct prf_fp *); @@ -2366,9 +2794,9 @@ diff -ruN proll_18.orig/src/printf.c proll-patch8/src/printf.c putchar(c,filog); } else if (c == 'l' || c == 'O') { printn(filog, (long)va_arg(adx,long), c=='l'?10:8); -diff -ruN proll_18.orig/src/rconsole.c proll-patch8/src/rconsole.c +diff -ruN proll_18.orig/src/rconsole.c proll-patch10/src/rconsole.c --- proll_18.orig/src/rconsole.c 1999-01-16 07:16:55.000000000 +0000 -+++ proll-patch8/src/rconsole.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/rconsole.c 2005-04-16 06:16:20.000000000 +0000 @@ -28,12 +28,18 @@ * move to California. Only plain lat7 survived. * I recreated lat7-1 changes in lat7-2. --zaitcev @@ -2388,6 +2816,37 @@ diff -ruN proll_18.orig/src/rconsole.c proll-patch8/src/rconsole.c #if 1 /* +@@ -46,18 +52,18 @@ + #endif + + static __inline__ void stfb_w(void *ptr, unsigned int data) { +- __asm__ __volatile__ ("sta %0, [%1] %2" : : ++ __asm__ __volatile__ ("sta %0, [%1] %2\n\t" : : + "r" (data), "r" (ptr), "i" (ASI_M_BYPASS)); + } + + static __inline__ void stfb_b(void *ptr, unsigned int data) { +- __asm__ __volatile__ ("stba %0, [%1] %2" : : ++ __asm__ __volatile__ ("stba %0, [%1] %2\n\t" : : + "r" (data), "r" (ptr), "i" (ASI_M_BYPASS)); + } + + static __inline__ unsigned int ldfb_w(void *ptr) { + unsigned int data; +- __asm__ __volatile__ ("lda [%1] %2, %0" : ++ __asm__ __volatile__ ("lda [%1] %2, %0\n\t" : + "=r" (data) : + "r" (ptr), "i" (ASI_M_BYPASS)); + return data; +@@ -65,7 +71,7 @@ + + static __inline__ unsigned int ldfb_b(void *ptr) { + unsigned int data; +- __asm__ __volatile__ ("lduba [%1] %2, %0" : ++ __asm__ __volatile__ ("lduba [%1] %2, %0\n\t" : + "=r" (data) : + "r" (ptr), "i" (ASI_M_BYPASS)); + return data; @@ -94,6 +100,7 @@ #endif @@ -2423,9 +2882,9 @@ diff -ruN proll_18.orig/src/rconsole.c proll-patch8/src/rconsole.c p->nchars_ = LAT7_NCHARS; p->width_ = LAT7_WIDTH; p->height_ = LAT7_HEIGHT; -diff -ruN proll_18.orig/src/rconsole.h proll-patch8/src/rconsole.h +diff -ruN proll_18.orig/src/rconsole.h proll-patch10/src/rconsole.h --- proll_18.orig/src/rconsole.h 1999-01-16 05:00:59.000000000 +0000 -+++ proll-patch8/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 @@ -13,10 +13,10 @@ */ @@ -2439,18 +2898,21 @@ diff -ruN proll_18.orig/src/rconsole.h proll-patch8/src/rconsole.h int nchars_; /* 128 for ASCII ... 65536 for Unicode */ int width_; /* [Pixels]. Maximum size is 16. */ int height_; /* [Pixels == scan lines]. */ -diff -ruN proll_18.orig/src/romlib.h proll-patch8/src/romlib.h +diff -ruN proll_18.orig/src/romlib.h proll-patch10/src/romlib.h --- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000 -+++ proll-patch8/src/romlib.h 2004-11-13 15:50:49.000000000 +0000 -@@ -73,12 +73,12 @@ ++++ proll-patch10/src/romlib.h 2005-04-16 20:32:49.000000000 +0000 +@@ -72,13 +72,13 @@ + */ #define memcpy(dst, src, len) bcopy(src, dst, len) #define memcmp(x1, x2, len) bcmp(x1, x2, len) - #define memset(p, len, zero) bzero(p, len) +-#define memset(p, len, zero) bzero(p, len) -extern void bcopy(void *b1, void *b2, int length); -extern int bcmp(void *b1, void *b2, int length); +-extern void bzero(void *b, int c); +extern void bcopy(const void *b1, void *b2, int length); +extern int bcmp(const void *b1, const void *b2, int length); - extern void bzero(void *b, int c); ++typedef unsigned int size_t; ++extern void *memset(void *p, int c, size_t len); /* gcc complains about "conflicting types for builtin function strlen". */ #define strlen(s) ssize(s) -extern int ssize(char *s); @@ -2458,9 +2920,9 @@ diff -ruN proll_18.orig/src/romlib.h proll-patch8/src/romlib.h /* -diff -ruN proll_18.orig/src/sched_4m.c proll-patch8/src/sched_4m.c +diff -ruN proll_18.orig/src/sched_4m.c proll-patch10/src/sched_4m.c --- proll_18.orig/src/sched_4m.c 1999-04-27 05:48:51.000000000 +0000 -+++ proll-patch8/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 @@ -108,7 +108,7 @@ static int set_bolt; /* Tick counter limit */ static struct handsc hndv[16]; @@ -2470,9 +2932,9 @@ diff -ruN proll_18.orig/src/sched_4m.c proll-patch8/src/sched_4m.c 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -diff -ruN proll_18.orig/src/swap.c proll-patch8/src/swap.c +diff -ruN proll_18.orig/src/swap.c proll-patch10/src/swap.c --- proll_18.orig/src/swap.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch8/src/swap.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/swap.c 2004-11-13 15:50:49.000000000 +0000 @@ -0,0 +1,21 @@ +// Convert the lat7 font so that no conversion is needed at runtime. +#define ORIG @@ -2495,9 +2957,9 @@ diff -ruN proll_18.orig/src/swap.c proll-patch8/src/swap.c + } + printf("\n"); +} -diff -ruN proll_18.orig/src/system.c proll-patch8/src/system.c +diff -ruN proll_18.orig/src/system.c proll-patch10/src/system.c --- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch8/src/system.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/system.c 2005-04-16 06:16:20.000000000 +0000 @@ -298,8 +298,8 @@ } @@ -2509,13 +2971,39 @@ diff -ruN proll_18.orig/src/system.c proll-patch8/src/system.c map_page(l1, va, pa, 0, highbase); pa += PAGE_SIZE; } -@@ -518,12 +518,12 @@ - while (len--) *((char *)s)++ = 0; +@@ -507,30 +507,44 @@ + { + char *p; + +- if ((p = mem_alloc(t, size, align)) != 0) bzero(p, size); ++ if ((p = mem_alloc(t, size, align)) != 0) memset(p, 0, size); + return p; + } + + /* + * Library functions + */ +-void bzero(void *s, int len) { +- while (len--) *((char *)s)++ = 0; ++void *memset(void *s, int c, size_t len) ++{ ++ void *p = s; ++ ++ while (len--) { ++ *(char *)s = c; ++ s++; ++ } ++ return p; } -void bcopy(void *f, void *t, int len) { +- while (len--) *((char *)t)++ = *((char *)f)++; +void bcopy(const void *f, void *t, int len) { - while (len--) *((char *)t)++ = *((char *)f)++; ++ while (len--) { ++ *(char *)t = *(char *)f; ++ f++; ++ t++; ++ } } /* Comparison is 7-bit */ @@ -2524,7 +3012,19 @@ diff -ruN proll_18.orig/src/system.c proll-patch8/src/system.c { int i; char ch; -@@ -538,8 +538,8 @@ + + while (len--) { +- ch = *((char *)s1)++; +- if ((i = ch - *((char *)s2)++) != 0) ++ ch = *(char *)s1; ++ i = ch - *(char *)s2; ++ s1++; ++ s2++; ++ if (i != 0) + return i; + if (ch == 0) + return 0; +@@ -538,8 +552,8 @@ return 0; } @@ -2535,7 +3035,7 @@ diff -ruN proll_18.orig/src/system.c proll-patch8/src/system.c for (p = s; *p != 0; p++) { } return p - s; } -@@ -560,14 +560,6 @@ +@@ -560,14 +574,6 @@ va_end(x1); } @@ -2550,9 +3050,9 @@ diff -ruN proll_18.orig/src/system.c proll-patch8/src/system.c void fatal() { printk("fatal."); -diff -ruN proll_18.orig/src/system.h proll-patch8/src/system.h +diff -ruN proll_18.orig/src/system.h proll-patch10/src/system.h --- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000 -+++ proll-patch8/src/system.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/system.h 2005-04-16 06:16:20.000000000 +0000 @@ -16,7 +16,7 @@ #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */ #define NCTX_SWIFT 0x100 @@ -2562,9 +3062,118 @@ diff -ruN proll_18.orig/src/system.h proll-patch8/src/system.h #ifndef __ASSEMBLY__ struct bank { -diff -ruN proll_18.orig/src/udp.c proll-patch8/src/udp.c +@@ -164,10 +164,10 @@ + + extern __inline__ void setipl(unsigned long __orig_psr) + { +- __asm__ __volatile__(" +- wr %0, 0x0, %%psr +- nop; nop; nop +-" : /* no outputs */ ++ __asm__ __volatile__( ++ "wr %0, 0x0, %%psr\n\t" ++ "nop; nop; nop\n\t" ++ : /* no outputs */ + : "r" (__orig_psr) + : "memory", "cc"); + } +@@ -176,13 +176,13 @@ + { + unsigned long tmp; + +- __asm__ __volatile__(" +- rd %%psr, %0 +- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ +- or %0, %1, %0 +- wr %0, 0x0, %%psr +- nop; nop; nop +-" : "=r" (tmp) ++ __asm__ __volatile__( ++ "rd %%psr, %0\n\t" ++ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ ++ "or %0, %1, %0\n\t" ++ "wr %0, 0x0, %%psr\n\t" ++ "nop; nop; nop\n\t" ++ : "=r" (tmp) + : "i" (PSR_PIL) + : "memory"); + } +@@ -191,13 +191,13 @@ + { + unsigned long tmp; + +- __asm__ __volatile__(" +- rd %%psr, %0 +- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ +- andn %0, %1, %0 +- wr %0, 0x0, %%psr +- nop; nop; nop +-" : "=r" (tmp) ++ __asm__ __volatile__( ++ "rd %%psr, %0\n\t" ++ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ ++ "andn %0, %1, %0\n\t" ++ "wr %0, 0x0, %%psr\n\t" ++ "nop; nop; nop\n\t" ++ : "=r" (tmp) + : "i" (PSR_PIL) + : "memory"); + } +@@ -214,18 +214,18 @@ + { + unsigned long retval; + +- __asm__ __volatile__(" +- rd %%psr, %0 +- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ +- and %0, %2, %%g1 +- and %1, %2, %%g2 +- xorcc %%g1, %%g2, %%g0 +- be 1f +- nop +- wr %0, %2, %%psr +- nop; nop; nop; +-1: +-" : "=r" (retval) ++ __asm__ __volatile__( ++ "rd %%psr, %0\n\t" ++ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ ++ "and %0, %2, %%g1\n\t" ++ "and %1, %2, %%g2\n\t" ++ "xorcc %%g1, %%g2, %%g0\n\t" ++ "be 1f\n\t" ++ "nop\n\t" ++ "wr %0, %2, %%psr\n\t" ++ "nop; nop; nop;\n\t" ++ "1:\n\t" ++ : "=r" (retval) + : "r" (__new_psr), "i" (PSR_PIL) + : "g1", "g2", "memory", "cc"); + +@@ -236,13 +236,13 @@ + { + unsigned long retval; + +- __asm__ __volatile__(" +- rd %%psr, %0 +- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ +- or %0, %1, %%g1 +- wr %%g1, 0x0, %%psr +- nop; nop; nop +-" : "=r" (retval) ++ __asm__ __volatile__( ++ "rd %%psr, %0\n\t" ++ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ ++ "or %0, %1, %%g1\n\t" ++ "wr %%g1, 0x0, %%psr\n\t" ++ "nop; nop; nop\n\t" ++ : "=r" (retval) + : "i" (PSR_PIL) + : "g1", "memory"); + +diff -ruN proll_18.orig/src/udp.c proll-patch10/src/udp.c --- proll_18.orig/src/udp.c 2001-12-24 05:12:53.000000000 +0000 -+++ proll-patch8/src/udp.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch10/src/udp.c 2004-11-13 15:50:49.000000000 +0000 @@ -81,7 +81,7 @@ int source; int dest; @@ -2584,9 +3193,9 @@ diff -ruN proll_18.orig/src/udp.c proll-patch8/src/udp.c /* Register IP packet type and set write buffer pointer */ if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL) return(FALSE); -diff -ruN proll_18.orig/src/vcons_zs.c proll-patch8/src/vcons_zs.c +diff -ruN proll_18.orig/src/vcons_zs.c proll-patch10/src/vcons_zs.c --- proll_18.orig/src/vcons_zs.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch8/src/vcons_zs.c 2005-03-20 10:25:39.000000000 +0000 ++++ proll-patch10/src/vcons_zs.c 2005-04-10 07:01:03.000000000 +0000 @@ -0,0 +1,68 @@ +/** + ** Console over 'zs' (Zilog serial port) @@ -2648,7 +3257,7 @@ diff -ruN proll_18.orig/src/vcons_zs.c proll-patch8/src/vcons_zs.c + unsigned zs_ptr = (unsigned) t->impl; + + while ((ldb_bypass(zs_ptr) & 1) != 1) { } -+ return ldb_bypass(zs_ptr + ZS_DATA); ++ return ldb_bypass(zs_ptr + ZS_DATA) & 0xff; +} + +void vcon_zs_fini(struct vconterm *t) @@ -2656,10 +3265,17 @@ diff -ruN proll_18.orig/src/vcons_zs.c proll-patch8/src/vcons_zs.c + /* violent crash in the end */ + ; +} -diff -ruN proll_18.orig/src/vconsole.c proll-patch8/src/vconsole.c +diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c --- proll_18.orig/src/vconsole.c 1999-11-08 03:10:28.000000000 +0000 -+++ proll-patch8/src/vconsole.c 2005-03-02 14:29:05.000000000 +0000 -@@ -13,6 +13,10 @@ ++++ proll-patch10/src/vconsole.c 2005-04-17 19:23:21.000000000 +0000 +@@ -7,12 +7,17 @@ + #include "vconsole.h" + + #include "hconsole.h" ++#include + + static void vcon_i_cursfeed(struct vconterm *t); + static void vcon_i_backflush(struct vconterm *t); struct hconsole hcons0; @@ -2670,7 +3286,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch8/src/vconsole.c int vcon_init(struct vconterm *t, unsigned int a0) { struct hconsole *hconp; -@@ -25,11 +29,49 @@ +@@ -25,11 +30,49 @@ t->vc_x = 0; t->vc_y = 0; t->backp = 0; t->backc = 0; @@ -2720,7 +3336,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch8/src/vconsole.c int vcon_write(struct vconterm *t, char *data, int leng) { int l = leng; -@@ -40,29 +82,84 @@ +@@ -40,29 +83,99 @@ if (l <= 0) break; c = *data++; --l; @@ -2741,6 +3357,9 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch8/src/vconsole.c + case 'M': + hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); + break; ++ default: ++ printk("Unhandled escape code '%c'\n", c); ++ break; + } break; - case 0x0D: /* Return */ @@ -2768,9 +3387,21 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch8/src/vconsole.c + if (t->vc_par[1]) t->vc_par[1]--; + gotoxay(t, t->vc_par[1], t->vc_par[0]); + break; ++ case 'J': ++ if (t->vc_par[0] == 0) { ++ //erase from cursor to end of display ++ hcon_clear(hconp, t->vc_y, t->vc_x, hconp->ydim_, hconp->xdim_); ++ } ++ break; + case 'M': + hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); + break; ++ case 'm': ++ break; ++ default: ++ printk("Unhandled escape code '%c', par[%d, %d, %d, %d, %d]\n", ++ c, t->vc_par[0], t->vc_par[1], t->vc_par[2], t->vc_par[3], t->vc_par[4]); ++ break; + } break; default: @@ -2823,9 +3454,73 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch8/src/vconsole.c } } } -diff -ruN proll_18.orig/src/vconsole.h proll-patch8/src/vconsole.h +@@ -100,9 +213,62 @@ + return 0; + } + ++static const unsigned char sunkbd_keycode[128] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 8, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, ++ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '\\', 13, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ ' ', ++}; ++ ++static const unsigned char sunkbd_keycode_shifted[128] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0, 8, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, ++ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '|', 13, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ ' ', ++}; ++ ++static int shiftstate; ++ + int vcon_getch(struct vconterm *t) + { +- return -1; ++ int ch; ++ ++ while ((ldb_bypass(0x71000004) & 1) != 1) { } ++ do { ++ ch = ldb_bypass(0x71000006) & 0xff; ++ if (ch == 99) ++ shiftstate |= 1; ++ else if (ch == 110) ++ shiftstate |= 2; ++ else if (ch == 227) ++ shiftstate &= ~1; ++ else if (ch == 238) ++ shiftstate &= ~2; ++ //printk("getch: %d\n", ch); ++ } ++ while ((ch & 0x80) == 0 || ch == 238 || ch == 227); // Wait for key release ++ //printk("getch rel: %d\n", ch); ++ ch &= 0x7f; ++ if (shiftstate) ++ ch = sunkbd_keycode_shifted[ch]; ++ else ++ ch = sunkbd_keycode[ch]; ++ //printk("getch xlate: %d\n", ch); ++ return ch; + } + + void vcon_fini(struct vconterm *t) +diff -ruN proll_18.orig/src/vconsole.h proll-patch10/src/vconsole.h --- proll_18.orig/src/vconsole.h 1999-11-08 00:58:13.000000000 +0000 -+++ proll-patch8/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 ++++ proll-patch10/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 @@ -6,6 +6,8 @@ #ifndef VCONSOLE_H #define VCONSOLE_H -- cgit v1.2.3 From ff1afc72f2dc508c176d0ed2bfee69545ea3b8ef Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 21:08:00 +0000 Subject: VMDK4 write support - fixed packing of VMDK4Header (Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1406 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vmdk.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/block-vmdk.c b/block-vmdk.c index 1cc498853..f80bf07b7 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -2,6 +2,7 @@ * 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 @@ -24,9 +25,6 @@ #include "vl.h" #include "block_int.h" -/* XXX: this code is untested */ -/* XXX: add write support */ - #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') @@ -56,14 +54,16 @@ typedef struct { int64_t grain_offset; char filler[1]; char check_bytes[4]; -} VMDK4Header; +} __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; @@ -96,9 +96,13 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) uint32_t magic; int l1_size; - fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) - return -1; + 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); @@ -111,7 +115,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) 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) * 512; + 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; @@ -126,7 +131,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) 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) * 512; + 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; } @@ -143,14 +149,26 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) 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; - /* XXX: currently only read only */ - bs->read_only = 1; return 0; fail: + qemu_free(s->l1_backup_table); qemu_free(s->l1_table); qemu_free(s->l2_cache); close(fd); @@ -158,12 +176,12 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) } static uint64_t get_cluster_offset(BlockDriverState *bs, - uint64_t offset) + 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; + uint32_t min_count, *l2_table, tmp; uint64_t cluster_offset; l1_index = (offset >> 9) / s->l1_entry_sectors; @@ -172,7 +190,6 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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 */ @@ -204,6 +221,26 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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; } @@ -215,7 +252,7 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, int index_in_cluster, n; uint64_t cluster_offset; - cluster_offset = get_cluster_offset(bs, sector_num << 9); + 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) @@ -232,7 +269,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, uint64_t cluster_offset; while (nb_sectors > 0) { - cluster_offset = get_cluster_offset(bs, sector_num << 9); + 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) @@ -255,7 +292,27 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, static int vmdk_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - return -1; + 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 void vmdk_close(BlockDriverState *bs) -- cgit v1.2.3 From 905f20b1519369a7b987347c6b01afe2c1b00350 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 21:09:55 +0000 Subject: fixed gdb error reporting (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1407 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 527d2e926..22c38e5e3 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -489,7 +489,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) p++; hextomem(mem_buf, p, len); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0) - put_packet(s, "ENN"); + put_packet(s, "E14"); else put_packet(s, "OK"); break; @@ -507,7 +507,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) put_packet(s, "OK"); } else { breakpoint_error: - put_packet(s, "ENN"); + put_packet(s, "E22"); } break; case 'z': -- cgit v1.2.3 From c99280bc29781fef0c620ed386f75f8ed8094ddf Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 21:25:15 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1408 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b1d7abc0d..bcaffe19b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.2 \ No newline at end of file +0.7.0 \ No newline at end of file -- cgit v1.2.3 From a8753c3466dcf5c08f51313a402eb09be5af7e30 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 21:34:00 +0000 Subject: Bochs disk image support (Alex Beregszaszi) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1409 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 8 +- Makefile | 2 +- Makefile.target | 2 +- block-bochs.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ block.c | 1 + vl.h | 1 + 6 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 block-bochs.c diff --git a/Changelog b/Changelog index 23c6d4842..26c3efacd 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -version 0.6.2: +version 0.7.0: - better BIOS translation and HDD geometry auto-detection - user mode networking bug fix @@ -9,15 +9,19 @@ version 0.6.2: - keymaps support (initial patch by Johannes Schindelin) - big endian ARM support (Lennert Buytenhek) - added generic 64 bit target support - - initial x86_64 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 version 0.6.1: diff --git a/Makefile b/Makefile index 6fc4d9aa3..10b5235cc 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ else endif endif -qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c +qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c diff --git a/Makefile.target b/Makefile.target index dbceeb7f4..991fcb9c5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -314,7 +314,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o -VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o SOUND_HW = sb16.o AUDIODRV = audio.o noaudio.o wavaudio.o diff --git a/block-bochs.c b/block-bochs.c new file mode 100644 index 000000000..62317aff3 --- /dev/null +++ b/block-bochs.c @@ -0,0 +1,224 @@ +/* + * Block driver for the various disk image formats used by Bochs + * Currently only for "growing" type in read-only mode + * + * Copyright (c) 2005 Alex Beregszaszi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "block_int.h" + +/**************************************************************/ + +#define HEADER_MAGIC "Bochs Virtual HD Image" +#define HEADER_VERSION 0x00010000 +#define HEADER_SIZE 512 + +#define REDOLOG_TYPE "Redolog" +#define GROWING_TYPE "Growing" + +// not allocated: 0xffffffff + +// always little-endian +struct bochs_header { + char magic[32]; // "Bochs Virtual HD Image" + char type[16]; // "Redolog" + char subtype[16]; // "Undoable" / "Volatile" / "Growing" + uint32_t version; + uint32_t header; // size of header + + union { + struct { + uint32_t catalog; // num of entries + uint32_t bitmap; // bitmap size + uint32_t extent; // extent size + uint64_t disk; // disk size + char padding[HEADER_SIZE - 64 - 8 - 20]; + } redolog; + char padding[HEADER_SIZE - 64 - 8]; + } extra; +}; + +typedef struct BDRVBochsState { + int fd; + + uint32_t *catalog_bitmap; + int catalog_size; + + int data_offset; + + int bitmap_blocks; + int extent_blocks; + int extent_size; +} BDRVBochsState; + +static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + const struct bochs_header *bochs = (const void *)buf; + + if (buf_size < HEADER_SIZE) + return 0; + + if (!strcmp(bochs->magic, HEADER_MAGIC) && + !strcmp(bochs->type, REDOLOG_TYPE) && + !strcmp(bochs->subtype, GROWING_TYPE) && + (le32_to_cpu(bochs->version) == HEADER_VERSION)) + return 100; + + return 0; +} + +static int bochs_open(BlockDriverState *bs, const char *filename) +{ + BDRVBochsState *s = bs->opaque; + int fd, i; + struct bochs_header bochs; + + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) + return -1; + } + + bs->read_only = 1; // no write support yet + + s->fd = fd; + + if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) { + goto fail; + } + + if (strcmp(bochs.magic, HEADER_MAGIC) || + strcmp(bochs.type, REDOLOG_TYPE) || + strcmp(bochs.subtype, GROWING_TYPE) || + (le32_to_cpu(bochs.version) != HEADER_VERSION)) { + goto fail; + } + + bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512; + + lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET); + + s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog); + s->catalog_bitmap = qemu_malloc(s->catalog_size * 4); + if (!s->catalog_bitmap) + goto fail; + if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) != + s->catalog_size * 4) + goto fail; + for (i = 0; i < s->catalog_size; i++) + le32_to_cpus(&s->catalog_bitmap[i]); + + s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4); + + s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512; + s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512; + + s->extent_size = le32_to_cpu(bochs.extra.redolog.extent); + + return 0; + fail: + close(fd); + return -1; +} + +static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) +{ + BDRVBochsState *s = bs->opaque; + int64_t offset = sector_num * 512; + int64_t extent_index, extent_offset, bitmap_offset, block_offset; + char bitmap_entry; + + // seek to sector + extent_index = offset / s->extent_size; + extent_offset = (offset % s->extent_size) / 512; + + if (s->catalog_bitmap[extent_index] == 0xffffffff) + { +// fprintf(stderr, "page not allocated [%x - %x:%x]\n", +// sector_num, extent_index, extent_offset); + return -1; // not allocated + } + + bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] * + (s->extent_blocks + s->bitmap_blocks)); + block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset)); + +// fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n", +// sector_num, extent_index, extent_offset, +// le32_to_cpu(s->catalog_bitmap[extent_index]), +// bitmap_offset, block_offset); + + // read in bitmap for current extent + lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET); + + read(s->fd, &bitmap_entry, 1); + + if (!((bitmap_entry >> (extent_offset % 8)) & 1)) + { +// fprintf(stderr, "sector (%x) in bitmap not allocated\n", +// sector_num); + return -1; // not allocated + } + + lseek(s->fd, block_offset, SEEK_SET); + + return 0; +} + +static int bochs_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVBochsState *s = bs->opaque; + int ret; + + while (nb_sectors > 0) { + if (!seek_to_sector(bs, sector_num)) + { + ret = read(s->fd, buf, 512); + if (ret != 512) + return -1; + } + else + memset(buf, 0, 512); + nb_sectors--; + sector_num++; + buf += 512; + } + return 0; +} + +static void bochs_close(BlockDriverState *bs) +{ + BDRVBochsState *s = bs->opaque; + qemu_free(s->catalog_bitmap); + close(s->fd); +} + +BlockDriver bdrv_bochs = { + "bochs", + sizeof(BDRVBochsState), + bochs_probe, + bochs_open, + bochs_read, + NULL, + bochs_close, +}; diff --git a/block.c b/block.c index a4433a898..7af6379a3 100644 --- a/block.c +++ b/block.c @@ -608,4 +608,5 @@ void bdrv_init(void) bdrv_register(&bdrv_vmdk); bdrv_register(&bdrv_cloop); bdrv_register(&bdrv_dmg); + bdrv_register(&bdrv_bochs); } diff --git a/vl.h b/vl.h index 0fe94ac6e..4ad4330f3 100644 --- a/vl.h +++ b/vl.h @@ -382,6 +382,7 @@ extern BlockDriver bdrv_qcow; extern BlockDriver bdrv_vmdk; extern BlockDriver bdrv_cloop; extern BlockDriver bdrv_dmg; +extern BlockDriver bdrv_bochs; void bdrv_init(void); BlockDriver *bdrv_find_format(const char *format_name); -- cgit v1.2.3 From 11650e363894d90f82ce29bc97c4a104fcb89459 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 21:39:25 +0000 Subject: clean target update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1410 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index de533f932..78a215bb1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -88,4 +88,5 @@ test2: done clean: - rm -f *~ *.o test-i386.out test-i386.ref qruncom $(TESTS) + rm -f *~ *.o test-i386.out test-i386.ref \ + test-x86_64.log test-x86_64.ref qruncom $(TESTS) -- cgit v1.2.3 From c747cd1fa26d1ed0cc009302fb9c75a8f03651e2 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 21:47:02 +0000 Subject: raw CDROM access for windows (Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1411 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/block.c b/block.c index 7af6379a3..e9061424d 100644 --- a/block.c +++ b/block.c @@ -533,6 +533,12 @@ static int raw_open(BlockDriverState *bs, const char *filename) bs->read_only = 1; } size = lseek(fd, 0, SEEK_END); +#ifdef _WIN32 + /* On Windows hosts it can happen that we're unable to get file size + for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ + if (size == -1) + size = LONG_LONG_MAX; +#endif bs->total_sectors = size / 512; s->fd = fd; return 0; -- cgit v1.2.3 From 7674e7bf08c0be8e6872f8602e2d875b3efb6903 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 26 Apr 2005 21:59:26 +0000 Subject: BSD cdrom device access fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1412 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index e9061424d..cbe07a9d8 100644 --- a/block.c +++ b/block.c @@ -24,6 +24,14 @@ #include "vl.h" #include "block_int.h" +#ifdef _BSD +#include +#include +#include +#include +#include +#endif + static BlockDriverState *bdrv_first; static BlockDriver *first_drv; @@ -88,18 +96,33 @@ static void get_tmp_filename(char *filename, int size) } #endif +/* XXX: force raw format if block or character device ? It would + simplify the BSD case */ static BlockDriver *find_image_format(const char *filename) { int fd, ret, score, score_max; BlockDriver *drv1, *drv; - uint8_t buf[1024]; + uint8_t *buf; + size_t bufsize = 1024; fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) return NULL; - ret = read(fd, buf, sizeof(buf)); +#ifdef DIOCGSECTORSIZE + { + unsigned int sectorsize = 512; + if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && + sectorsize > bufsize) + bufsize = sectorsize; + } +#endif + buf = malloc(bufsize); + if (!buf) + return NULL; + ret = read(fd, buf, bufsize); if (ret < 0) { close(fd); + free(buf); return NULL; } close(fd); @@ -113,6 +136,7 @@ static BlockDriver *find_image_format(const char *filename) drv = drv1; } } + free(buf); return drv; } @@ -532,7 +556,19 @@ static int raw_open(BlockDriverState *bs, const char *filename) return -1; bs->read_only = 1; } - size = lseek(fd, 0, SEEK_END); +#ifdef _BSD + { + struct stat sb; + if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { +#ifdef DIOCGMEDIASIZE + if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) +#endif + size = lseek(fd, 0LL, SEEK_END); + } else +#endif + { + size = lseek(fd, 0, SEEK_END); + } #ifdef _WIN32 /* On Windows hosts it can happen that we're unable to get file size for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ -- cgit v1.2.3 From e5484d339114117920753c4045bed75510215862 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Apr 2005 19:55:01 +0000 Subject: BSD fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1413 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/block.c b/block.c index cbe07a9d8..ce1c388b9 100644 --- a/block.c +++ b/block.c @@ -548,6 +548,9 @@ static int raw_open(BlockDriverState *bs, const char *filename) BDRVRawState *s = bs->opaque; int fd; int64_t size; +#ifdef _BSD + struct stat sb; +#endif fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); if (fd < 0) { @@ -557,13 +560,11 @@ static int raw_open(BlockDriverState *bs, const char *filename) bs->read_only = 1; } #ifdef _BSD - { - struct stat sb; - if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { + if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { #ifdef DIOCGMEDIASIZE - if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) + if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) #endif - size = lseek(fd, 0LL, SEEK_END); + size = lseek(fd, 0LL, SEEK_END); } else #endif { -- cgit v1.2.3 From b48a8bb6b17e7e53527b8acfefdc034ec09717fe Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Apr 2005 19:55:58 +0000 Subject: win32 fix (Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1414 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dyngen.c b/dyngen.c index 45284954b..d95d6a452 100644 --- a/dyngen.c +++ b/dyngen.c @@ -635,6 +635,8 @@ static char *get_rel_sym_name(EXE_RELOC *rel) 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; } @@ -1698,6 +1700,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = get_rel_sym_name(rel); + if (!sym_name) + continue; if (strstart(sym_name, "__op_jmp", &p)) { int n; n = strtol(p, NULL, 10); -- cgit v1.2.3 From 192c7bd92722d0d4a55cc9ed59b642e0aaf0d5c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Apr 2005 20:11:21 +0000 Subject: ARM Thumb syscalls (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1415 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/syscall.h | 1 + linux-user/main.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index daf4b34af..1d508f0a3 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -26,6 +26,7 @@ struct target_pt_regs { #define ARM_ORIG_r0 uregs[17] #define ARM_SYSCALL_BASE 0x900000 +#define ARM_THUMB_SYSCALL 0 #define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) diff --git a/linux-user/main.c b/linux-user/main.c index bcdf8441b..d0f662c07 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -359,16 +359,27 @@ void cpu_loop(CPUARMState *env) case EXCP_SWI: { /* system call */ - insn = ldl((void *)(env->regs[15] - 4)); - n = insn & 0xffffff; + if (env->thumb) { + insn = lduw((void *)(env->regs[15] - 2)); + n = insn & 0xff; + } else { + insn = ldl((void *)(env->regs[15] - 4)); + n = insn & 0xffffff; + } + if (n == ARM_NR_cacheflush) { arm_cache_flush(env->regs[0], env->regs[1]); } else if (n == ARM_NR_semihosting || n == ARM_NR_thumb_semihosting) { env->regs[0] = do_arm_semihosting (env); - } else if (n >= ARM_SYSCALL_BASE) { + } else if (n >= ARM_SYSCALL_BASE + || (env->thumb && n == ARM_THUMB_SYSCALL)) { /* linux syscall */ - n -= ARM_SYSCALL_BASE; + if (env->thumb) { + n = env->regs[7]; + } else { + n -= ARM_SYSCALL_BASE; + } env->regs[0] = do_syscall(env, n, env->regs[0], -- cgit v1.2.3 From c2d551ff5acc0e236fe7fd8dfb1ce290d9ff4d99 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Apr 2005 20:15:00 +0000 Subject: ARM thumb disassembly (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1416 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm-dis.c | 5 +++++ disas.c | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/arm-dis.c b/arm-dis.c index a84d91b48..1e027efc7 100644 --- a/arm-dis.c +++ b/arm-dis.c @@ -1556,6 +1556,11 @@ print_insn_arm (pc, info) } is_thumb = force_thumb; + if (pc & 1) + { + is_thumb = 1; + pc &= ~(bfd_vma) 1; + } #if 0 if (!is_thumb && info->symbols != NULL) diff --git a/disas.c b/disas.c index 8754713a8..ded2c6d72 100644 --- a/disas.c +++ b/disas.c @@ -108,8 +108,20 @@ bfd_vma bfd_getb32 (const bfd_byte *addr) return (bfd_vma) v; } -/* Disassemble this for me please... (debugging). 'flags' is only used - for i386: non zero means 16 bit code */ +#ifdef TARGET_ARM +static int +print_insn_thumb1(bfd_vma pc, disassemble_info *info) +{ + return print_insn_arm(pc | 1, info); +} +#endif + +/* Disassemble this for me please... (debugging). 'flags' has teh following + values: + i386 - nonzero means 16 bit code + arm - nonzero means thumb code + other targets - unused + */ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) { target_ulong pc; @@ -137,7 +149,10 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) disasm_info.mach = bfd_mach_i386_i386; print_insn = print_insn_i386; #elif defined(TARGET_ARM) - print_insn = print_insn_arm; + if (flags) + print_insn = print_insn_thumb1; + else + print_insn = print_insn_arm; #elif defined(TARGET_SPARC) print_insn = print_insn_sparc; #elif defined(TARGET_PPC) -- cgit v1.2.3 From 6a0f9e82c5bf457b958fe7918f8ff0080035f35e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Apr 2005 20:17:58 +0000 Subject: Virtual PC read-only disk image support (Alex Beregszaszi) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1417 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile | 2 +- Makefile.target | 4 +- block-vpc.c | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ block.c | 1 + vl.h | 1 + 6 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 block-vpc.c diff --git a/Changelog b/Changelog index 26c3efacd..c257d6157 100644 --- a/Changelog +++ b/Changelog @@ -22,6 +22,7 @@ version 0.7.0: - 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: diff --git a/Makefile b/Makefile index 10b5235cc..7f4770c6c 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ else endif endif -qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c +qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c diff --git a/Makefile.target b/Makefile.target index 991fcb9c5..1e6ff277e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -313,8 +313,8 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o -VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o +VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o SOUND_HW = sb16.o AUDIODRV = audio.o noaudio.o wavaudio.o diff --git a/block-vpc.c b/block-vpc.c new file mode 100644 index 000000000..88ad575bf --- /dev/null +++ b/block-vpc.c @@ -0,0 +1,243 @@ +/* + * 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 (!strncmp(buf, "conectix", 8)) + return 100; + + return 0; +} + +static int vpc_open(BlockDriverState *bs, const char *filename) +{ + BDRVVPCState *s = bs->opaque; + int fd, i; + struct vpc_subheader header; + + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) + return -1; + } + + bs->read_only = 1; // no write support yet + + s->fd = fd; + + if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE) + goto fail; + + if (strncmp(header.magic, "conectix", 8)) + goto fail; + lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET); + + if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE) + goto fail; + + if (strncmp(header.magic, "cxsparse", 8)) + goto fail; + + bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) * + be32_to_cpu(header.type.sparse.pageentry_size)) / 512; + + lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET); + + s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries); + s->pagetable = qemu_malloc(s->pagetable_entries * 4); + if (!s->pagetable) + goto fail; + if (read(s->fd, s->pagetable, s->pagetable_entries * 4) != + s->pagetable_entries * 4) + goto fail; + for (i = 0; i < s->pagetable_entries; i++) + be32_to_cpus(&s->pagetable[i]); + + s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size); +#ifdef CACHE + s->pageentry_u8 = qemu_malloc(512); + if (!s->pageentry_u8) + goto fail; + s->pageentry_u32 = s->pageentry_u8; + s->pageentry_u16 = s->pageentry_u8; + s->last_pagetable = -1; +#endif + + return 0; + fail: + close(fd); + return -1; +} + +static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) +{ + BDRVVPCState *s = bs->opaque; + uint64_t offset = sector_num * 512; + uint64_t bitmap_offset, block_offset; + uint32_t pagetable_index, pageentry_index; + + pagetable_index = offset / s->pageentry_size; + pageentry_index = (offset % s->pageentry_size) / 512; + + if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff) + return -1; // not allocated + + bitmap_offset = 512 * s->pagetable[pagetable_index]; + block_offset = bitmap_offset + 512 + (512 * pageentry_index); + +// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n", +// sector_num, pagetable_index, pageentry_index, +// bitmap_offset, block_offset); + +// disabled by reason +#if 0 +#ifdef CACHE + if (bitmap_offset != s->last_bitmap) + { + lseek(s->fd, bitmap_offset, SEEK_SET); + + s->last_bitmap = bitmap_offset; + + // Scary! Bitmap is stored as big endian 32bit entries, + // while we used to look it up byte by byte + read(s->fd, s->pageentry_u8, 512); + for (i = 0; i < 128; i++) + be32_to_cpus(&s->pageentry_u32[i]); + } + + if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1) + return -1; +#else + lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET); + + read(s->fd, &bitmap_entry, 1); + + if ((bitmap_entry >> (pageentry_index % 8)) & 1) + return -1; // not allocated +#endif +#endif + lseek(s->fd, block_offset, SEEK_SET); + + return 0; +} + +static int vpc_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVVPCState *s = bs->opaque; + int ret; + + while (nb_sectors > 0) { + if (!seek_to_sector(bs, sector_num)) + { + ret = read(s->fd, buf, 512); + if (ret != 512) + return -1; + } + else + memset(buf, 0, 512); + nb_sectors--; + sector_num++; + buf += 512; + } + return 0; +} + +static void vpc_close(BlockDriverState *bs) +{ + BDRVVPCState *s = bs->opaque; + qemu_free(s->pagetable); +#ifdef CACHE + qemu_free(s->pageentry_u8); +#endif + close(s->fd); +} + +BlockDriver bdrv_vpc = { + "vpc", + sizeof(BDRVVPCState), + vpc_probe, + vpc_open, + vpc_read, + NULL, + vpc_close, +}; diff --git a/block.c b/block.c index ce1c388b9..8baa3b87e 100644 --- a/block.c +++ b/block.c @@ -652,4 +652,5 @@ void bdrv_init(void) bdrv_register(&bdrv_cloop); bdrv_register(&bdrv_dmg); bdrv_register(&bdrv_bochs); + bdrv_register(&bdrv_vpc); } diff --git a/vl.h b/vl.h index 4ad4330f3..8d29506ef 100644 --- a/vl.h +++ b/vl.h @@ -383,6 +383,7 @@ extern BlockDriver bdrv_vmdk; extern BlockDriver bdrv_cloop; extern BlockDriver bdrv_dmg; extern BlockDriver bdrv_bochs; +extern BlockDriver bdrv_vpc; void bdrv_init(void); BlockDriver *bdrv_find_format(const char *format_name); -- cgit v1.2.3 From 5899f386ba9474d0bb0c055f9276d8923845cbd3 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Apr 2005 20:25:20 +0000 Subject: ARM thumb fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1418 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 3 +- target-arm/translate.c | 86 +++++++++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/target-arm/op.c b/target-arm/op.c index 08afa2f7c..0a3811ed2 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -824,12 +824,13 @@ void OPPROTO op_shrl_T0_im_thumb(void) shift = PARAM1; if (shift == 0) { - env->CF = 0; + env->CF = ((uint32_t)shift) >> 31; T0 = 0; } else { env->CF = (T0 >> (shift - 1)) & 1; T0 = T0 >> shift; } + env->NZF = T0; FORCE_RET(); } diff --git a/target-arm/translate.c b/target-arm/translate.c index c9005c4b8..29657416f 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -38,6 +38,7 @@ typedef struct DisasContext { int condlabel; struct TranslationBlock *tb; int singlestep_enabled; + int thumb; } DisasContext; #define DISAS_JUMP_NEXT 4 @@ -268,8 +269,11 @@ static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) int val; if (reg == 15) { - /* normaly, since we updated PC, we need only to add 4 */ - val = (long)s->pc + 4; + /* normaly, since we updated PC, we need only to add one insn */ + if (s->thumb) + val = (long)s->pc + 2; + else + val = (long)s->pc + 4; gen_op_movl_TN_im[t](val); } else { gen_op_movl_TN_reg[t][reg](); @@ -897,6 +901,8 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) { if (__builtin_expect(s->singlestep_enabled, 0)) { /* An indirect jump so that we still trigger the debug exception. */ + if (s->thumb) + dest |= 1; gen_op_movl_T0_im(dest); gen_bx(s); } else { @@ -1552,7 +1558,7 @@ static void disas_thumb_insn(DisasContext *s) gen_movl_T1_reg(s, rm); } if (insn & (1 << 9)) - gen_op_addl_T0_T1_cc(); + gen_op_subl_T0_T1_cc(); else gen_op_addl_T0_T1_cc(); gen_movl_reg_T0(s, rd); @@ -1595,11 +1601,10 @@ static void disas_thumb_insn(DisasContext *s) case 4: if (insn & (1 << 11)) { rd = (insn >> 8) & 7; - /* load pc-relative */ - val = (insn & 0xff) * 4; + /* load pc-relative. Bit 1 of PC is ignored. */ + val = s->pc + 2 + ((insn & 0xff) * 4); + val &= ~(uint32_t)2; gen_op_movl_T1_im(val); - gen_movl_T2_reg(s, 15); - gen_op_addl_T1_T2(); gen_op_ldl_T0_T1(); gen_movl_reg_T0(s, rd); break; @@ -1658,7 +1663,7 @@ static void disas_thumb_insn(DisasContext *s) gen_movl_T0_reg(s, rd); gen_movl_T1_reg(s, rm); - switch (insn >> 6) { + switch (op) { case 0x0: /* and */ gen_op_andl_T0_T1(); gen_op_logic_T0_cc(); @@ -1689,8 +1694,9 @@ static void disas_thumb_insn(DisasContext *s) gen_op_andl_T0_T1(); gen_op_logic_T0_cc(); rd = 16; + break; case 0x9: /* neg */ - gen_op_rsbl_T0_T1_cc(); + gen_op_subl_T0_T1_cc(); break; case 0xa: /* cmp */ gen_op_subl_T0_T1_cc(); @@ -1716,11 +1722,12 @@ static void disas_thumb_insn(DisasContext *s) gen_op_notl_T1(); gen_op_logic_T1_cc(); val = 1; + rm = rd; break; } if (rd != 16) { if (val) - gen_movl_reg_T1(s, rd); + gen_movl_reg_T1(s, rm); else gen_movl_reg_T0(s, rd); } @@ -1756,7 +1763,7 @@ static void disas_thumb_insn(DisasContext *s) gen_op_ldl_T0_T1(); break; case 5: /* ldrh */ - gen_op_ldsw_T0_T1(); + gen_op_lduw_T0_T1(); break; case 6: /* ldrb */ gen_op_ldub_T0_T1(); @@ -1851,11 +1858,13 @@ static void disas_thumb_insn(DisasContext *s) case 10: /* add to high reg */ rd = (insn >> 8) & 7; - if (insn & (1 << 11)) - rm = 13; /* sp */ - else - rm = 15; /* pc */ - gen_movl_T0_reg(s, rm); + if (insn & (1 << 11)) { + /* SP */ + gen_movl_T0_reg(s, 13); + } else { + /* PC. bit 1 is ignored. */ + gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2); + } val = (insn & 0xff) * 4; gen_op_movl_T1_im(val); gen_op_addl_T0_T1(); @@ -1880,11 +1889,19 @@ static void disas_thumb_insn(DisasContext *s) case 4: case 5: case 0xc: case 0xd: /* push/pop */ gen_movl_T1_reg(s, 13); - if (insn & (1 << 11)) - val = 4; + if (insn & (1 << 8)) + offset = 4; else - val = -4; - gen_op_movl_T2_im(val); + offset = 0; + for (i = 0; i < 8; i++) { + if (insn & (1 << i)) + offset += 4; + } + if ((insn & (1 << 11)) == 0) { + gen_op_movl_T2_im(-offset); + gen_op_addl_T1_T2(); + } + gen_op_movl_T2_im(4); for (i = 0; i < 8; i++) { if (insn & (1 << i)) { if (insn & (1 << 11)) { @@ -1896,7 +1913,7 @@ static void disas_thumb_insn(DisasContext *s) gen_movl_T0_reg(s, i); gen_op_stl_T0_T1(); } - /* move to the next address */ + /* advance to the next address. */ gen_op_addl_T1_T2(); } } @@ -1913,7 +1930,10 @@ static void disas_thumb_insn(DisasContext *s) } gen_op_addl_T1_T2(); } - + if ((insn & (1 << 11)) == 0) { + gen_op_movl_T2_im(-offset); + gen_op_addl_T1_T2(); + } /* write back the new stack pointer */ gen_movl_reg_T1(s, 13); /* set the new PC value */ @@ -1931,14 +1951,8 @@ static void disas_thumb_insn(DisasContext *s) rn = (insn >> 8) & 0x7; gen_movl_T1_reg(s, rn); gen_op_movl_T2_im(4); - val = 0; for (i = 0; i < 8; i++) { if (insn & (1 << i)) { - /* advance to the next address */ - if (val) - gen_op_addl_T1_T2(); - else - val = 1; if (insn & (1 << 11)) { /* load */ gen_op_ldl_T0_T1(); @@ -1948,8 +1962,12 @@ static void disas_thumb_insn(DisasContext *s) gen_movl_T0_reg(s, i); gen_op_stl_T0_T1(); } + /* advance to the next address */ + gen_op_addl_T1_T2(); } } + /* Base register writeback. */ + gen_movl_reg_T1(s, rn); break; case 13: @@ -1976,9 +1994,9 @@ static void disas_thumb_insn(DisasContext *s) gen_movl_T1_reg(s, 15); /* jump to the offset */ - val = (uint32_t)s->pc; + val = (uint32_t)s->pc + 2; offset = ((int32_t)insn << 24) >> 24; - val += (offset << 1) + 2; + val += offset << 1; gen_jmp(s, val); break; @@ -2002,19 +2020,20 @@ static void disas_thumb_insn(DisasContext *s) gen_op_movl_T1_im(val | 1); gen_movl_reg_T1(s, 14); - val += offset; + val += offset << 1; if (insn & (1 << 11)) { /* bl */ gen_jmp(s, val); } else { /* blx */ + val &= ~(uint32_t)2; gen_op_movl_T0_im(val); gen_bx(s); } } return; undef: - gen_op_movl_T0_im((long)s->pc - 4); + gen_op_movl_T0_im((long)s->pc - 2); gen_op_movl_reg_TN[0][15](); gen_op_undef_insn(); s->is_jmp = DISAS_JUMP; @@ -2045,6 +2064,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->pc = pc_start; dc->singlestep_enabled = env->singlestep_enabled; dc->condjmp = 0; + dc->thumb = env->thumb; nb_gen_labels = 0; lj = -1; do { @@ -2128,7 +2148,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, dc->pc - pc_start, 0); + target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb); fprintf(logfile, "\n"); if (loglevel & (CPU_LOG_TB_OP)) { fprintf(logfile, "OP:\n"); -- cgit v1.2.3 From 43095f3198919e64f8ace4bda12bd45d71795dd2 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Apr 2005 20:49:23 +0000 Subject: tarbin fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1419 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7f4770c6c..2a4f32990 100644 --- a/Makefile +++ b/Makefile @@ -108,9 +108,10 @@ tar: # generate a binary distribution tarbin: ( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \ - $(bindir)/qemu $(bindir)/qemu-fast \ + $(bindir)/qemu \ $(bindir)/qemu-system-ppc \ $(bindir)/qemu-system-sparc \ + $(bindir)/qemu-system-x86_64 \ $(bindir)/qemu-i386 \ $(bindir)/qemu-arm \ $(bindir)/qemu-sparc \ -- cgit v1.2.3 From 98ff7d30f2dd8ebf9c8ecb8a579bd24c17a15440 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 28 Apr 2005 19:26:35 +0000 Subject: BMDMA interrupt fix (aka Solaris x86 IDE bug fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1421 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index 3997a06e2..d2220ba0b 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -499,7 +499,10 @@ static inline void ide_abort_command(IDEState *s) static inline void ide_set_irq(IDEState *s) { + BMDMAState *bm = s->bmdma; if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { + if (bm) + bm->status |= BM_STATUS_INT; #ifdef TARGET_PPC if (s->openpic) openpic_set_irq(s->openpic, s->irq, 1); -- cgit v1.2.3 From a343df1659d59fa20b8fa642f5eb92c5aad2eab9 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 28 Apr 2005 19:45:10 +0000 Subject: ne2000 reset fix - start/stop registers read access (aka OS/2 Warp V4 fix) (lukewarm) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1422 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index e1b656e1b..db6133607 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -61,6 +61,9 @@ #define EN1_CURPAG 0x17 #define EN1_MULT 0x18 +#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */ +#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */ + /* Register accessed at EN_CMD, the 8390 base addr. */ #define E8390_STOP 0x01 /* Stop and reset the chip */ #define E8390_START 0x02 /* Start the chip, clear reset */ @@ -150,7 +153,7 @@ static void ne2000_reset(NE2000State *s) static void ne2000_update_irq(NE2000State *s) { int isr; - isr = s->isr & s->imr; + isr = (s->isr & s->imr) & 0x7f; #if defined(DEBUG_NE2000) printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n", s->irq, isr ? 1 : 0, s->isr, s->imr); @@ -255,7 +258,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (addr == E8390_CMD) { /* control register */ s->cmd = val; - if (val & E8390_START) { + if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */ s->isr &= ~ENISR_RESET; /* test specific case: zero length transfert */ if ((val & (E8390_RREAD | E8390_RWRITE)) && @@ -376,6 +379,12 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) case EN0_RSR: ret = s->rsr; break; + case EN2_STARTPG: + ret = s->start >> 8; + break; + case EN2_STOPPG: + ret = s->stop >> 8; + break; default: ret = 0x00; break; -- cgit v1.2.3 From d37282add1de687bc596dac20b4f58f5394547e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 28 Apr 2005 20:41:53 +0000 Subject: added --enable-adlib in help git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1423 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 05e8a5999..6deafb237 100755 --- a/configure +++ b/configure @@ -331,6 +331,7 @@ echo " --cc=CC use C compiler CC [$cc]" echo " --make=MAKE use specified make [$make]" echo " --static enable static build [$static]" echo " --enable-mingw32 enable Win32 cross compilation with mingw32" +echo " --enable-adlib enable Adlib emulation" echo " --enable-fmod enable FMOD audio output driver" echo " --fmod-lib path to FMOD library" echo " --fmod-inc path to FMOD includes" -- cgit v1.2.3 From 7c35359cbf4eaa1d808a1ebb3647fe65fcc9dc60 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 28 Apr 2005 20:49:23 +0000 Subject: raw dmg support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1424 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-dmg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block-dmg.c b/block-dmg.c index 582e3cb2f..5df723543 100644 --- a/block-dmg.c +++ b/block-dmg.c @@ -91,7 +91,9 @@ static int dmg_open(BlockDriverState *bs, const char *filename) if(lseek(s->fd,-0x1d8,SEEK_END)<0) { dmg_close: close(s->fd); - return -1; + /* open raw instead */ + bs->drv=&bdrv_raw; + return bs->drv->bdrv_open(bs,filename); } info_begin=read_off(s->fd); if(info_begin==0) -- cgit v1.2.3 From 712e78744e3a0332825a80298f38225b30dec88c Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 28 Apr 2005 21:09:32 +0000 Subject: probing fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1425 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-cow.c | 3 ++- block-qcow.c | 21 ++++++++++++++++----- block-vpc.c | 3 +-- block.c | 42 +++++++++++++++++++++++------------------- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/block-cow.c b/block-cow.c index 15270dfd3..eeeab7068 100644 --- a/block-cow.c +++ b/block-cow.c @@ -54,7 +54,8 @@ 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 (be32_to_cpu(cow_header->magic) == COW_MAGIC && + 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 diff --git a/block-qcow.c b/block-qcow.c index a473298a8..ca05be88b 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -80,8 +80,9 @@ 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 (be32_to_cpu(cow_header->magic) == QCOW_MAGIC && + + if (buf_size >= sizeof(QCowHeader) && + be32_to_cpu(cow_header->magic) == QCOW_MAGIC && be32_to_cpu(cow_header->version) == QCOW_VERSION) return 100; else @@ -551,9 +552,19 @@ static int qcow_create(const char *filename, int64_t total_size, header_size = sizeof(header); backing_filename_len = 0; if (backing_file) { - realpath(backing_file, backing_filename); - if (stat(backing_filename, &st) != 0) { - return -1; + const char *p; + /* XXX: this is a hack: we do not attempt to check for URL + like syntax */ + p = strchr(backing_file, ':'); + if (p && (p - backing_file) >= 2) { + /* URL like but exclude "c:" like filenames */ + pstrcpy(backing_filename, sizeof(backing_filename), + backing_file); + } else { + realpath(backing_file, backing_filename); + if (stat(backing_filename, &st) != 0) { + return -1; + } } header.mtime = cpu_to_be32(st.st_mtime); header.backing_file_offset = cpu_to_be64(header_size); diff --git a/block-vpc.c b/block-vpc.c index 88ad575bf..e4c51bab2 100644 --- a/block-vpc.c +++ b/block-vpc.c @@ -81,9 +81,8 @@ typedef struct BDRVVPCState { static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename) { - if (!strncmp(buf, "conectix", 8)) + if (buf_size >= 8 && !strncmp(buf, "conectix", 8)) return 100; - return 0; } diff --git a/block.c b/block.c index 8baa3b87e..18eaf4604 100644 --- a/block.c +++ b/block.c @@ -106,26 +106,29 @@ static BlockDriver *find_image_format(const char *filename) size_t bufsize = 1024; fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) - return NULL; + if (fd < 0) { + buf = NULL; + ret = 0; + } else { #ifdef DIOCGSECTORSIZE - { - unsigned int sectorsize = 512; - if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && - sectorsize > bufsize) - bufsize = sectorsize; - } + { + unsigned int sectorsize = 512; + if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && + sectorsize > bufsize) + bufsize = sectorsize; + } #endif - buf = malloc(bufsize); - if (!buf) - return NULL; - ret = read(fd, buf, bufsize); - if (ret < 0) { + buf = qemu_malloc(bufsize); + if (!buf) + return NULL; + ret = read(fd, buf, bufsize); + if (ret < 0) { + close(fd); + qemu_free(buf); + return NULL; + } close(fd); - free(buf); - return NULL; } - close(fd); drv = NULL; score_max = 0; @@ -136,7 +139,7 @@ static BlockDriver *find_image_format(const char *filename) drv = drv1; } } - free(buf); + qemu_free(buf); return drv; } @@ -154,7 +157,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, bs->read_only = 0; bs->is_temporary = 0; bs->encrypted = 0; - + if (snapshot) { BlockDriverState *bs1; int64_t total_size; @@ -183,7 +186,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, filename = tmp_filename; bs->is_temporary = 1; } - + pstrcpy(bs->filename, sizeof(bs->filename), filename); if (!drv) { drv = find_image_format(filename); @@ -653,4 +656,5 @@ void bdrv_init(void) bdrv_register(&bdrv_dmg); bdrv_register(&bdrv_bochs); bdrv_register(&bdrv_vpc); + bdrv_register(&bdrv_vvfat); } -- cgit v1.2.3 From de167e416fa3d6e4bbdcac90973954c6bfae3070 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 28 Apr 2005 21:15:08 +0000 Subject: Virtual VFAT support (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1426 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 + Makefile | 2 +- Makefile.target | 2 +- block-vvfat.c | 1742 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-img.c | 7 +- vl.h | 1 + 6 files changed, 1753 insertions(+), 5 deletions(-) create mode 100644 block-vvfat.c diff --git a/Changelog b/Changelog index c257d6157..761a91d47 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +version 0.7.1: + + - read-only Virtual FAT support (Johannes Schindelin) + version 0.7.0: - better BIOS translation and HDD geometry auto-detection diff --git a/Makefile b/Makefile index 2a4f32990..11b38d15f 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ else endif endif -qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c +qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c diff --git a/Makefile.target b/Makefile.target index 1e6ff277e..434af9b36 100644 --- a/Makefile.target +++ b/Makefile.target @@ -314,7 +314,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o -VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o SOUND_HW = sb16.o AUDIODRV = audio.o noaudio.o wavaudio.o diff --git a/block-vvfat.c b/block-vvfat.c new file mode 100644 index 000000000..7bce91e41 --- /dev/null +++ b/block-vvfat.c @@ -0,0 +1,1742 @@ +/* + * QEMU Block driver for virtual VFAT (shadows a local directory) + * + * 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 +#include +#include +#include "vl.h" +#include "block_int.h" + +// TODO: new file +// TODO: delete file +// TODO: make root directory larger +// TODO: make directory clusters connected, so they are reserved anyway... add a member which tells how many clusters are reserved after a directory +// TODO: introduce another member in mapping_t which says where the directory resides in s->directory (for mkdir and rmdir) +// in _read and _write, before treating direntries or file contents, get_mapping to know what it is. +// TODO: mkdir +// TODO: rmdir + +// TODO: when commit_data'ing a direntry and is_consistent, commit_remove +// TODO: reset MODE_MODIFIED when commit_remove'ing + +#define DEBUG + +/* 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; +} + +/* make sure that memory is reserved at pointer[index*item_size] */ +static inline void* array_get(array_t* array,unsigned 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 0; + array->size=new_size; + array->next=index+1; + } + return array->pointer+index*array->item_size; +} + +static inline void* array_get_next(array_t* array) { + unsigned int next=array->next; + void* result=array_get(array,next); + array->next=next+1; + 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_tonext-1,index,1)) + return -1; + array->next--; + return 0; +} + +/* 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 zero; + 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; /* 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, + * offset is the offset in the file in clusters of this slice */ + off_t begin,end,offset; + char* filename; + + /* as s->directory is growable, no pointer may be used here */ + unsigned int dir_index; + enum { MODE_NORMAL,MODE_UNDEFINED,MODE_MODIFIED,MODE_DELETED,MODE_DIRECTORY } mode; +} mapping_t; + +/* this structure is used to hold sectors which need to be written, but it's + * not known yet where to write them. */ + +typedef struct commit_t { + uint32_t cluster_num; + uint8_t* buf; +} commit_t; + +/* write support exists for fat, direntry and file contents */ +typedef enum { + WRITE_UNDEFINED,WRITE_FAT,WRITE_DIRENTRY,WRITE_DATA +} write_action_t; + +/* here begins the real VVFAT driver */ + +typedef struct BDRVVVFATState { + 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; + unsigned int sectors_for_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 */ + unsigned int first_file_mapping; /* index of the first mapping which is not a directory, but a file */ + uint32_t max_fat_value; + + int current_fd; + char current_fd_is_writable; /* =0 if read only, !=0 if read/writable */ + mapping_t* current_mapping; + unsigned char* cluster; + unsigned int current_cluster; + + /* write support */ + array_t commit; + /* for each file, the file contents, the direntry, and the fat entries are + * written, but not necessarily in that order */ + write_action_t action[3]; +} BDRVVVFATState; + + +static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + if (strstart(filename, "fat:", NULL) || + strstart(filename, "fatrw:", NULL)) + return 100; + return 0; +} + +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; + partition->fs_type=(s->fat_type==16?0x6:0xb); /* FAT16/FAT32 */ + partition->end_head=0xf; + 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(0x3f); + partition->end_sector_long=cpu_to_le32(s->sector_count); + + real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa; +} + +/* 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;idirectory)); + entry->attributes=0xf; + entry->reserved[0]=0; + entry->begin=0; + entry->name[0]=(number_of_entries-i)|(i==0?0x40:0); + } + for(i=0;idirectory),s->directory.next-1-(i/26)); + entry->name[offset]=buffer[i]; + } + return array_get(&(s->directory),s->directory.next-number_of_entries); +} + +/* fat functions */ + +static inline uint8_t fat_chksum(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==12) { + assert(0); /* TODO */ + } else if(s->fat_type==16) { + uint16_t* entry=array_get(&(s->fat),cluster); + *entry=cpu_to_le16(value&0xffff); + } else { + uint32_t* entry=array_get(&(s->fat),cluster); + *entry=cpu_to_le32(value); + } +} + +static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster) +{ + //fprintf(stderr,"want to get fat for cluster %d\n",cluster); + if(s->fat_type==12) { + const uint8_t* x=s->fat.pointer+cluster*3/2; + return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; + } else if(s->fat_type==16) { + uint16_t* entry=array_get(&(s->fat),cluster); + return le16_to_cpu(*entry); + } else { + uint32_t* entry=array_get(&(s->fat),cluster); + return le32_to_cpu(*entry); + } +} + +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) +{ + int i; + + array_init(&(s->fat),(s->fat_type==32?4:2)); + array_get(&(s->fat),s->sectors_per_fat*0x200/s->fat.item_size-1); + memset(s->fat.pointer,0,s->fat.size); + fat_set(s,0,0x7ffffff8); + + for(i=1;isectors_for_directory/s->sectors_per_cluster-1;i++) + fat_set(s,i,i+1); + fat_set(s,i,0x7fffffff); + + 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=0xfffffff; break; + default: s->max_fat_value=0; /* error... */ + } + +} + +static inline int long2unix_name(unsigned char* dest,int dest_size,direntry_t* direntry_short) { + int i=-1,j; + int chksum=fat_chksum(direntry_short); + while(1) { + char* buf=(char*)(direntry_short+i); + if((buf[0]&0x3f)!=-i || direntry_short[i].reserved[1]!=chksum || + direntry_short[i].attributes!=0xf) { + if(i<-1) + return -3; + /* take short name */ + for(j=7;j>0 && direntry_short->name[j]==' ';j--); + if(j+1>dest_size) + return -1; + strncpy(dest,direntry_short->name,j+1); + dest+=j+1; dest_size-=j+1; + for(j=2;j>=0 && direntry_short->extension[j]==' ';j--); + if(j>=0) { + if(j+2>dest_size) + return -1; + dest[0]='.'; + strncpy(dest+1,direntry_short->extension,j+1); + } + return 0; + } + for(j=0;j<13;j++) { + dest_size--; + if(dest_size<0) + return -2; + dest[0]=buf[2*j+((j<5)?1:(j<11)?4:6)]; + if(dest[0]==0 && (buf[0]&0x40)!=0) + return 0; + dest++; + } + /* last entry, but no trailing \0? */ + if(buf[0]&0x40) + return -3; + i--; + } +} + +static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int directory_start,const char* filename,int is_dot) +{ + int i,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; + } + + for(i=1;i<8 && filename[i] && filename[i]!='.';i++); + + entry_long=create_long_filename(s,filename); + + entry=array_get_next(&(s->directory)); + memset(entry->name,0x20,11); + strncpy(entry->name,filename,i); + + if(filename[i]) { + int len=strlen(filename); + for(i=len;i>0 && filename[i-1]!='.';i--); + if(i>0) + memcpy(entry->extension,filename+i,(len-i>3?3:len-i)); + } + + /* upcase & remove unwanted characters */ + for(i=10;i>=0;i--) { + if(i==10 || i==7) for(;i>1 && 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(;entry1attributes&0xf) && !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_longattributes==0xf) { + entry_long->reserved[1]=chksum; + entry_long++; + } + } + + return entry; +} + +static int read_directory(BDRVVVFATState* s,const char* dirname, + int first_cluster_of_parent) +{ + + DIR* dir=opendir(dirname); + struct dirent* entry; + struct stat st; + unsigned int start_of_directory=s->directory.next; + /* mappings before first_file_mapping are directories */ + unsigned int first_directory_mapping=s->first_file_mapping; + unsigned int first_cluster=(start_of_directory/0x10/s->sectors_per_cluster); + int i; + + if(!dir) + return -1; + + while((entry=readdir(dir))) { + unsigned int length=strlen(dirname)+2+strlen(entry->d_name); + char* buffer; + direntry_t* direntry; + int is_dot=!strcmp(entry->d_name,"."); + int is_dotdot=!strcmp(entry->d_name,".."); + + if(start_of_directory==1 && (is_dotdot || is_dot)) + continue; + + buffer=(char*)malloc(length); + snprintf(buffer,length,"%s/%s",dirname,entry->d_name); + + if(stat(buffer,&st)<0) { + free(buffer); + continue; + } + + /* create directory entry for this file */ + //fprintf(stderr,"create direntry at %d (cluster %d) for %s\n",s->directory.next,s->directory.next/0x10/s->sectors_per_cluster,entry->d_name); + direntry=create_short_filename(s,start_of_directory,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) + direntry->begin=cpu_to_le16(first_cluster_of_parent); + else if(is_dot) + direntry->begin=cpu_to_le16(first_cluster); + else + direntry->begin=cpu_to_le16(0); /* do that later */ + direntry->size=cpu_to_le32(st.st_size); + + /* create mapping for this file */ + if(!is_dot && !is_dotdot) { + if(S_ISDIR(st.st_mode)) + s->current_mapping=(mapping_t*)array_insert(&(s->mapping),s->first_file_mapping++,1); + else + s->current_mapping=(mapping_t*)array_get_next(&(s->mapping)); + s->current_mapping->begin=0; + s->current_mapping->end=st.st_size; + s->current_mapping->offset=0; + s->current_mapping->filename=buffer; + s->current_mapping->dir_index=s->directory.next-1; + s->current_mapping->mode=(S_ISDIR(st.st_mode)?MODE_DIRECTORY:MODE_UNDEFINED); + } + } + 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)); + } + + /* reserve next cluster also (for new files) */ + for(i=0;i<0x10*s->sectors_per_cluster;i++) { + direntry_t* direntry=array_get_next(&(s->directory)); + memset(direntry,0,sizeof(direntry_t)); + } + + /* was it the first directory? */ + if(start_of_directory==1) { + mapping_t* mapping=array_insert(&(s->mapping),0,1); + mapping->filename=strdup(dirname); + mapping->mode=MODE_DIRECTORY; + mapping->begin=0; + mapping->end=1; + mapping->offset=0; + mapping->dir_index=0xffffffff; + s->sectors_of_root_directory=s->directory.next/0x10; + } + + /* recurse directories */ + { + int i; + + //fprintf(stderr,"iterating subdirectories of %s (first cluster %d): %d to %d\n",dirname,first_cluster,first_directory_mapping,last_directory_mapping); + for(i=first_directory_mapping;ifirst_file_mapping;i++) { + mapping_t* mapping=array_get(&(s->mapping),i); + direntry_t* direntry=array_get(&(s->directory),mapping->dir_index); + /* the directory to be read can add more subdirectories */ + int last_dir_mapping=s->first_file_mapping; + + assert(mapping->mode==MODE_DIRECTORY); + /* first, tell the mapping where the directory will start */ + mapping->begin=s->directory.next/0x10/s->sectors_per_cluster; + if(i>0) { + mapping[-1].end=mapping->begin; + assert(mapping[-1].beginbegin); + } + /* then tell the direntry */ + direntry->begin=cpu_to_le16(mapping->begin); + //fprintf(stderr,"read directory %s (begin %d)\n",mapping->filename,(int)mapping->begin); + /* then read it */ + if(read_directory(s,mapping->filename,first_cluster)) + return -1; + + if(last_dir_mapping!=s->first_file_mapping) { + int diff=s->first_file_mapping-last_dir_mapping; + assert(diff>0); + + if(last_dir_mapping!=i+1) { + int count=last_dir_mapping-i-1; + int to=s->first_file_mapping-count; + + assert(count>0); + assert(to>i+1); + array_roll(&(s->mapping),to,i+1,count); + /* could have changed due to realloc */ + mapping=array_get(&(s->mapping),i); + mapping->end=mapping[1].begin; + } + i+=diff; + } + } + } + + return 0; +} + +static int init_directory(BDRVVVFATState* s,const char* dirname) +{ + bootsector_t* bootsector=(bootsector_t*)&(s->first_sectors[(s->first_sectors_number-1)*0x200]); + unsigned int i; + unsigned int cluster; + + memset(&(s->first_sectors[0]),0,0x40*0x200); + + /* TODO: if FAT32, this is probably wrong */ + s->sectors_per_fat=0xfc; + s->sectors_per_cluster=0x10; + s->cluster_size=s->sectors_per_cluster*0x200; + s->cluster=malloc(s->cluster_size); + + array_init(&(s->mapping),sizeof(mapping_t)); + array_init(&(s->directory),sizeof(direntry_t)); + array_init(&(s->commit),sizeof(commit_t)); + + /* add volume label */ + { + direntry_t* entry=array_get_next(&(s->directory)); + entry->attributes=0x28; /* archive | volume label */ + snprintf(entry->name,11,"QEMU VVFAT"); + } + + if(read_directory(s,dirname,0)) + return -1; + + /* make sure that the number of directory entries is multiple of 0x200/0x20 (to fit the last sector exactly) */ + s->sectors_for_directory=s->directory.next/0x10; + + s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2+s->sectors_for_directory; + s->cluster_count=(s->sector_count-s->faked_sectors)/s->sectors_per_cluster; + + /* Now build FAT, and write back information into directory */ + init_fat(s); + + cluster=s->sectors_for_directory/s->sectors_per_cluster; + assert(s->sectors_for_directory%s->sectors_per_cluster==0); + + /* set the end of the last read directory */ + if(s->first_file_mapping>0) { + mapping_t* mapping=array_get(&(s->mapping),s->first_file_mapping-1); + mapping->end=cluster; + } + + for(i=1;imapping.next;i++) { + mapping_t* mapping=array_get(&(s->mapping),i); + direntry_t* direntry=array_get(&(s->directory),mapping->dir_index); + if(mapping->mode==MODE_DIRECTORY) { + /* directory */ + int i; +#ifdef DEBUG + fprintf(stderr,"assert: %s %d < %d\n",mapping->filename,(int)mapping->begin,(int)mapping->end); +#endif + assert(mapping->beginend); + for(i=mapping->begin;iend-1;i++) + fat_set(s,i,i+1); + fat_set(s,i,0x7fffffff); + } else { + /* as the space is virtual, we can be sloppy about it */ + unsigned int end_cluster=cluster+mapping->end/s->cluster_size; + + if(end_cluster>=s->cluster_count) { + fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type); + return -1; + } + mapping->begin=cluster; + mapping->mode=MODE_NORMAL; + mapping->offset=0; + direntry->size=cpu_to_le32(mapping->end); + if(direntry->size==0) { + direntry->begin=0; + mapping->end=cluster; + continue; + } + + direntry->begin=cpu_to_le16(cluster); + mapping->end=end_cluster+1; + for(;clustercurrent_mapping=0; + + 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->zero=0; + bootsector->media_type=(s->first_sectors_number==1?0xf0:0xf8); /* media descriptor */ + bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); + bootsector->sectors_per_track=cpu_to_le16(0x3f); + bootsector->number_of_heads=cpu_to_le16(0x10); + bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f); + /* TODO: if FAT32, adjust */ + bootsector->total_sectors=cpu_to_le32(s->sector_count); + + /* TODO: if FAT32, this is wrong */ + bootsector->u.fat16.drive_number=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; +} + +static int vvfat_open(BlockDriverState *bs, const char* dirname) +{ + BDRVVVFATState *s = bs->opaque; + int i; + + /* TODO: automatically determine which FAT type */ + s->fat_type=16; + s->sector_count=0xec04f; + + s->current_cluster=0xffffffff; + s->first_file_mapping=0; + + /* TODO: if simulating a floppy, this is 1, because there is no partition table */ + s->first_sectors_number=0x40; + + if (strstart(dirname, "fat:", &dirname)) { + /* read only is the default for safety */ + bs->read_only = 1; + } else if (strstart(dirname, "fatrw:", &dirname)) { + /* development only for now */ + bs->read_only = 0; + } else { + return -1; + } + if(init_directory(s,dirname)) + return -1; + + if(s->first_sectors_number==0x40) + init_mbr(s); + + /* TODO: this could be wrong for FAT32 */ + bs->cyls=1023; bs->heads=15; bs->secs=63; + bs->total_sectors=bs->cyls*bs->heads*bs->secs; + + /* write support */ + for(i=0;i<3;i++) + s->action[i]=WRITE_UNDEFINED; + return 0; +} + +static inline void vvfat_close_current_file(BDRVVVFATState *s) +{ + if(s->current_mapping) { + s->current_mapping = 0; + close(s->current_fd); + } +} + +/* 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; + //fprintf(stderr,"find_aux: cluster_num=%d, index1=%d,index2=%d\n",cluster_num,index1,index2); + while(1) { + mapping_t* mapping; + index3=(index1+index2)/2; + mapping=array_get(&(s->mapping),index3); + //fprintf(stderr,"index3: %d = (%d+%d)/2, end: %d\n",index3,index1,index2,(int)mapping->end); + if(mapping->end>cluster_num) { + assert(index2!=index3 || index2==0); + if(index2==index3) + return index2; + index2=index3; + } else { + if(index1==index3) + return index2; + index1=index3; + } + assert(index1<=index2); + } +} + +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; + return mapping; +} + +static int open_file(BDRVVVFATState* s,mapping_t* mapping,int flags) +{ + if(!mapping) + return -1; + assert(flags==O_RDONLY || flags==O_RDWR); + if(!s->current_mapping || + strcmp(s->current_mapping->filename,mapping->filename) || + (flags==O_RDWR && !s->current_fd_is_writable)) { + /* open file */ + int fd = open(mapping->filename, flags | O_BINARY | O_LARGEFILE); + if(fd<0) + return -1; + vvfat_close_current_file(s); + s->current_fd = fd; + s->current_fd_is_writable = (flags==O_RDWR?-1:0); + 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; + 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); + if(open_file(s,mapping,O_RDONLY)) + return -2; + } + + offset=s->cluster_size*(cluster_num-s->current_mapping->begin+s->current_mapping->offset); + if(lseek(s->current_fd, offset, SEEK_SET)!=offset) + return -3; + 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; +} + +static int vvfat_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVVVFATState *s = bs->opaque; + int i; + + // fprintf(stderr,"vvfat_read: sector %d+%d\n",(int)sector_num,nb_sectors); + + for(i=0;ifaked_sectors) { + if(sector_numfirst_sectors_number) + memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200); + else if(sector_num-s->first_sectors_numbersectors_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_fatsectors_per_fat) + memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200); + else if(sector_num-s->first_sectors_number-s->sectors_per_fat*2sectors_for_directory) + memcpy(buf+i*0x200,&(s->directory.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat*2)*0x200]),0x200); + } else { + uint32_t sector=sector_num-s->first_sectors_number-s->sectors_per_fat*2, + sector_offset_in_cluster=(sector%s->sectors_per_cluster), + cluster_num=sector/s->sectors_per_cluster; + if(read_cluster(s, cluster_num) != 0) { + //fprintf(stderr,"failed to read cluster %d\n",(int)cluster_num); + // 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; +} + +static void print_direntry(direntry_t* direntry) +{ + if(!direntry) + return; + if(direntry->attributes==0xf) { + unsigned char* c=(unsigned char*)direntry; + int i; + for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2) + fputc(c[i],stderr); + for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2) + fputc(c[i],stderr); + for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2) + fputc(c[i],stderr); + fputc('\n',stderr); + } else { + int i; + for(i=0;i<11;i++) + fputc(direntry->name[i],stderr); + fprintf(stderr,"attributes=0x%02x begin=%d size=%d\n", + direntry->attributes, + direntry->begin,direntry->size); + } +} + +static void print_changed_sector(BlockDriverState *bs,int64_t sector_num,const uint8_t *buf) +{ + BDRVVVFATState *s = bs->opaque; + + if(sector_numfirst_sectors_number) + return; + if(sector_numfirst_sectors_number+s->sectors_per_fat*2) { + int first=((sector_num-s->first_sectors_number)%s->sectors_per_fat); + int first_fat_entry=first*0x200/2; + int i; + + fprintf(stderr, "fat:\n"); + for(i=0;i<0x200;i+=2) { + uint16_t* f=array_get(&(s->fat),first_fat_entry+i/2); + if(memcmp(buf+i,f,2)) + fprintf(stderr,"%d(%d->%d) ",first_fat_entry+i/2,*f,*(uint16_t*)(buf+i)); + } + fprintf(stderr, "\n"); + } else if(sector_numfaked_sectors) { + direntry_t* d=(direntry_t*)buf; + int i; + fprintf(stderr, "directory:\n"); + for(i=0;i<0x200/sizeof(direntry_t);i++) { + direntry_t* d_old=(direntry_t*)(s->directory.pointer+0x200*(sector_num-s->first_sectors_number-s->sectors_per_fat*2)+i*sizeof(direntry_t)); + if(memcmp(d+i,d_old,sizeof(direntry_t))) { + fprintf(stderr, "old: "); print_direntry(d_old); + fprintf(stderr, "new: "); print_direntry(d+i); + fprintf(stderr, "\n"); + } + } + } else { + int sec=(sector_num-s->first_sectors_number-2*s->sectors_per_fat); + fprintf(stderr, "\tcluster: %d(+%d sectors)\n",sec/s->sectors_per_cluster,sec%s->sectors_per_cluster); + } +} + +char direntry_is_free(const direntry_t* direntry) +{ + return direntry->name[0]==0 || direntry->name[0]==0xe5; +} + +/* TODO: use this everywhere */ +static inline uint32_t begin_of_direntry(direntry_t* direntry) +{ + return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16); +} + +int consistency_check1(BDRVVVFATState *s) { + /* check all mappings */ + int i; + for(i=0;imapping.next;i++) { + mapping_t* mapping=array_get(&(s->mapping),i); + int j; + for(j=mapping->begin;jend-1;j++) + assert(fat_get(s,j)==j+1); + assert(fat_get(s,j)==(0x7fffffff&s->max_fat_value)); + } + return 0; +} + +int consistency_check2(BDRVVVFATState *s) { + /* check fat entries: consecutive fat entries should be mapped in one mapping */ + int i; + /* TODO: i=0 (mappings for direntries have to be sorted) */ + for(i=s->sectors_for_directory/s->sectors_per_cluster;ifat.next-1;i++) { + uint32_t j=fat_get(s,i); + if(j!=i+1 && j!=0 && !fat_eof(s,j)) { + mapping_t* mapping=find_mapping_for_cluster(s,i+1); + assert(mapping->begin==i+1); + } + } + return 0; +} + +int consistency_check3(BDRVVVFATState *s) { + /* check that for each file there is exactly one mapping per cluster */ + int i,count_non_next=0; + for(i=0;imapping.next;i++) { + mapping_t* mapping=array_get(&(s->mapping),i); + /* TODO: when directories are correctly adapted, add them here */ + assert(mapping->beginend); + if(mapping->mode==MODE_NORMAL) { + int j,count=0,count_next=0; + for(j=0;jmapping.next;j++) { + mapping_t* other=array_get(&(s->mapping),j); + if(mapping->beginend&&mapping->end>other->begin) + count++; + if(mapping->end==other->begin) + count_next++; + } + assert(count==1); /* no overlapping mappings */ + assert(count_next==1 || count_next==0); /* every mapping except the last one has a successor */ + if(!count_next) + count_non_next++; + } + } + assert(count_non_next==1); /* only one last mapping */ + return 0; +} + +static inline commit_t* commit_get_next(BDRVVVFATState* s) +{ + commit_t* commit=array_get_next(&(s->commit)); + if((commit->buf=malloc(s->cluster_size))==0) { + /* out of memory */ + s->commit.next--; + return 0; + } + return commit; +} + +int commit_remove(BDRVVVFATState* s,commit_t* commit) +{ + int index=commit-(commit_t*)s->commit.pointer; + free(commit->buf); + if(array_roll(&(s->commit),s->commit.next-1,index,1)) + return -1; + s->commit.next--; + return 0; +} + +/* TODO: the plan for write support: + * + * it seems that the direntries are written first, then the data is committed + * to the free sectors, then fat 1 is updated, then fat2. + * + * Plan: when sectors are written, do the following: + * + * - if they are in a directory, check if the entry has changed. if yes, + * look what has changed (different strategies for name, begin & size). + * + * if it is new (old entry is only 0's or has E5 at the start), create it, + * and also create mapping, but in a special mode "undefined" (TODO), + * because we cannot know which clusters belong to it yet. + * + * if it is zeroed, or has E5 at the start, look if has just moved. If yes, + * copy the entry to the new position. If no, delete the file. + * + * - if they are in data, and the cluster is undefined, add it to the commit + * list. if the cluster is defined (find_mapping), then write it into the + * corresponding file. + * + * If it is the last cluster (TODO: add a function + * fat_get(s,cluster); ), make sure not to write a complete cluster_size. + * + * If the data is in current_cluster, update s->cluster. + * + * - if they are in fat 1, update mappings, look in the commit list + * (assertions!) and if the cluster is now known (or changed from undefined + * state to defined state, like when begin or size changed in a direntry), + * write it. + * + * - if they are in fat 2, make sure they match with current fat. + * + */ + +void mapping_modify_from_direntry(BDRVVVFATState* s,mapping_t* mapping,direntry_t* direntry) +{ + int begin=le16_to_cpu(direntry->begin), + end=begin+le32_to_cpu(direntry->size)/s->cluster_size+1, + i; + mapping->mode = MODE_MODIFIED; + /* TODO: what if begin==0 (size==0)? */ + mapping->begin = begin; + /* TODO: why not just mapping->end = begin+1 ? */ + for(i=begin+1;iend = i; +} + +mapping_t* find_mapping_for_direntry(BDRVVVFATState* s,direntry_t* direntry) +{ + int i; + int dir_index=direntry-((direntry_t*)s->directory.pointer); + + /* TODO: support allocation for new clusters for directories (new/larger directory */ + assert(dir_index<0x200/0x20*s->sectors_for_directory); + + for(i=0;imapping.next;i++) { + mapping_t* mapping=array_get(&(s->mapping),i); + if(mapping->dir_index==dir_index && mapping->offset==0 && + mapping->mode!=MODE_UNDEFINED) + return mapping; + } + return 0; +} + +static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) +{ + return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)/s->sectors_per_cluster; +} + +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; +} + +static commit_t* get_commit_for_cluster(BDRVVVFATState* s,uint32_t cluster_num) +{ + int i; + for(i=0;icommit.next;i++) { + commit_t* commit=array_get(&(s->commit),i); + if(commit->cluster_num==cluster_num) + return commit; + } + return 0; +} + +static inline commit_t* create_or_get_commit_for_sector(BDRVVVFATState* s,off_t sector_num) +{ + int i; + commit_t* commit; + uint32_t cluster_num=sector2cluster(s,sector_num); + + for(i=0;icommit.next;i++) { + commit=array_get(&(s->commit),i); + if(commit->cluster_num==cluster_num) + return commit; + } + + commit=commit_get_next(s); + commit->cluster_num=cluster_num; + /* we can ignore read errors here */ + read_cluster(s,cluster_num); + memcpy(commit->buf,s->cluster,s->cluster_size); + return commit; +} + +static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping) +{ + if(mapping->mode==MODE_UNDEFINED) + return 0; + if(mapping->dir_index>=0x200/0x20*s->sectors_for_directory) + return 0; + return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index); +} + +static void print_mappings(BDRVVVFATState* s) +{ + int i; + fprintf(stderr,"mapping:\n"); + for(i=0;imapping.next;i++) { + mapping_t* m=array_get(&(s->mapping),i); + direntry_t* d=get_direntry_for_mapping(s,m); + fprintf(stderr,"%02d %d-%d (%d) %s (dir: %d)",i,(int)m->begin,(int)m->end,(int)m->offset,m->filename,m->dir_index); + print_direntry(d); + fprintf(stderr,"\n"); + } + fprintf(stderr,"mappings end.\n"); +} + +/* TODO: statify all functions */ + +/* This function is only meant for file contents. + * It will return an error if used for other sectors. */ +static int write_cluster(BDRVVVFATState* s,uint32_t cluster_num,const uint8_t* buf) +{ + /* sector_offset is the sector_num relative to the first cluster */ + mapping_t* mapping=find_mapping_for_cluster(s,cluster_num); + direntry_t* direntry; + int next_cluster,write_size,last_cluster; + off_t offset; + + /* if this cluster is free, return error */ + next_cluster=fat_get(s,cluster_num); + if(next_cluster<2) + return -1; + + /* TODO: MODE_DIRECTORY */ + if(!mapping || mapping->mode==MODE_UNDEFINED || mapping->mode==MODE_DIRECTORY) + return -1; + direntry=get_direntry_for_mapping(s,mapping); + if(!direntry) + return -2; + + /* get size to write */ + last_cluster=fat_eof(s,next_cluster); + write_size=!last_cluster?s->cluster_size: + (le32_to_cpu(direntry->size)%s->cluster_size); + if(write_size<=0) + return 0; + //fprintf(stderr,"next_cluster: %d (%d), write_size: %d, %d, %d\n",next_cluster,s->max_fat_value-8,write_size,direntry->size,s->cluster_size); + + if(open_file(s,mapping,O_RDWR)) + return -4; + + offset=(cluster_num-mapping->begin+mapping->offset)*s->cluster_size; + if(lseek(s->current_fd,offset,SEEK_SET)!=offset) + return -3; + if(write(s->current_fd,buf,write_size)!=write_size) { + lseek(s->current_fd,0,SEEK_END); + vvfat_close_current_file(s); + return -2; + } + + /* seek to end of file, so it doesn't get truncated */ + if(!last_cluster) + lseek(s->current_fd,0,SEEK_END); + else { + ftruncate(s->current_fd,le32_to_cpu(direntry->size)); + vvfat_close_current_file(s); + } + + /* update s->cluster if necessary */ + if(cluster_num==s->current_cluster && s->cluster!=buf) + memcpy(s->cluster,buf,s->cluster_size); + + return 0; +} + +/* this function returns !=0 on error */ +int mapping_is_consistent(BDRVVVFATState* s,mapping_t* mapping) +{ + direntry_t* direntry=get_direntry_for_mapping(s,mapping); + uint32_t cluster_count=0; + int commit_count=0; /* number of commits for this file (we also write incomplete files; think "append") */ + //fprintf(stderr,"check direntry for %s\n",mapping->filename); + while(mapping) { + int i; + assert(mapping->beginend); + for(i=mapping->begin;iend-1;i++) { + if(i<=0 || fat_get(s,i)!=i+1) { + /*fprintf(stderr,"the fat mapping of %d is not %d, but %d\n", + i,i+1,fat_get(s,i));*/ + return -1; + } + if(get_commit_for_cluster(s,i)) + commit_count++; + } + if(get_commit_for_cluster(s,i)) + commit_count++; + + cluster_count+=mapping->end-mapping->begin; + + i=fat_get(s,mapping->end-1); + if(fat_eof(s,i)) + break; + + mapping=find_mapping_for_cluster(s,i); + if(!mapping) { + //fprintf(stderr,"No mapping found for %d\n",i); + print_mappings(s); + return -2; + } + } + + if(cluster_count!=(le32_to_cpu(direntry->size)+s->cluster_size-1)/s->cluster_size) { + //fprintf(stderr,"cluster_count is %d, but size is %d\n",cluster_count,le32_to_cpu(direntry->size)); + return -3; + } + + if(commit_count==0) + return -4; + + //fprintf(stderr,"okay\n"); + return 0; +} + +/* TODO: remember what comes third, and what's first in this OS: + * FAT, direntry or data. + * If the last written sector is either last in cluster or sector_num+nb_sectors-1, + * - commit every cluster for this file if mapping_is_consistent()==0 + * - if the last written sector is first_action, and last_action=third_action, clear commit + */ + +static int commit_cluster_aux(BDRVVVFATState* s,commit_t* commit) +{ + int result=write_cluster(s,commit->cluster_num,commit->buf); + return result; +} + + +static int commit_cluster(BDRVVVFATState* s,uint32_t cluster_num) +{ + commit_t* commit; + + /* commit the sectors of this cluster */ + commit=get_commit_for_cluster(s,cluster_num); + if(commit) + return commit_cluster_aux(s,commit); + return 0; +} + +/* this function checks the consistency for the direntry which belongs to + * the mapping. if everything is found consistent, the data is committed. + * this returns 0 if no error occurred (even if inconsistencies were found) */ +static inline int commit_data_if_consistent(BDRVVVFATState* s,mapping_t* mapping,write_action_t action) +{ + direntry_t* direntry; + + if(!mapping) + return 0; + + //fprintf(stderr,"7\n"); +#define d(x) fprintf(stderr,#x "\n") + direntry=get_direntry_for_mapping(s,mapping); + + //d(8); + + assert(action==WRITE_FAT || action==WRITE_DIRENTRY || action==WRITE_DATA); + + //d(9); + //fprintf(stderr,"mapping: 0x%x s=0x%x\n",(uint32_t)mapping,(uint32_t)s); + /*fprintf(stderr,"commit? file=%s, action=%s\n", + mapping->filename,action==WRITE_FAT?"fat":action==WRITE_DIRENTRY?"direntry":"data");*/ + + //d(10); + if(s->action[2]==WRITE_UNDEFINED) { + int i; + for(i=2;i>0 && s->action[i-1]==WRITE_UNDEFINED;i--); + if(i>0 && action!=s->action[i-1]) + s->action[i]=action; + assert(i<2 || s->action[0]!=s->action[2]); + } + //d(11); + + if(mapping_is_consistent(s,mapping)==0) { + uint32_t cluster_num=begin_of_direntry(direntry); + off_t remaining_bytes=le32_to_cpu(direntry->size); + //fprintf(stderr,"the data for %s was found consistent\n",mapping->filename); + while(remaining_bytes>0) { + commit_t* commit=get_commit_for_cluster(s,cluster_num); + if(!commit) + continue; + + //fprintf(stderr,"commit_cluster %d (%d), remaining: %d\n",cluster_num,s->max_fat_value-15,(int)remaining_bytes); + assert(cluster_num>1); + assert(cluster_nummax_fat_value-15); + if(commit_cluster(s,cluster_num)) { + fprintf(stderr,"error committing cluster %d\n",cluster_num); + return -1; + } + cluster_num=fat_get(s,cluster_num); + remaining_bytes-=s->cluster_size; + /* TODO: if(action==s->action[2]) { + commit_t* commit=get_commit_for_cluster(s,cluster_num); + commit_remove(s,commit); + } */ + } + } + //print_mappings(s); + //fprintf(stderr,"finish vvfat_write\n"); + return 0; +} + +static int vvfat_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BDRVVVFATState *s = bs->opaque; + int i; + + /* fprintf(stderr,"vvfat_write %d+%d (%s)\n",(int)sector_num,nb_sectors, + (sector_num>=s->faked_sectors?"data": + (sector_num>=s->first_sectors_number+2*s->sectors_per_fat?"directory": + (sector_num>=s->first_sectors_number+s->sectors_per_fat?"fat 2": + (sector_num>=s->first_sectors_number?"fat 1":"boot sector"))))); */ + + for(i=0;ifirst_sectors_number) { + /* change the bootsector or partition table? no! */ + return -1; + } else if(sector_numfirst_sectors_number+s->sectors_per_fat) { + /* FAT 1 */ + int fat_entries_per_cluster=s->cluster_size*8/s->fat_type; + int first_cluster=(sector_num-s->first_sectors_number)*fat_entries_per_cluster,i; + mapping_t* mapping=0; + + /* write back */ + memcpy(s->fat.pointer+0x200*(sector_num-s->first_sectors_number), + buf,0x200); + + /* for each changed FAT entry, */ + for(i=0;isectors_for_directory/s->sectors_per_cluster) + continue; + + new_value=fat_get(s,first_cluster+i); + + /* check the current fat entry */ + if(new_value<2 || (new_value>=s->max_fat_value-0xf && !fat_eof(s,new_value))) { + /* free, reserved or bad cluster */ + mapping=find_mapping_for_cluster(s,first_cluster+i); + //assert(!mapping || mapping->mode==MODE_DELETED); + if(mapping && mapping->mode==MODE_DELETED && + first_cluster+i+1==mapping->end) + array_remove(&(s->mapping),mapping-(mapping_t*)s->mapping.pointer); + mapping=0; + continue; + } + + /* get the mapping for the current entry */ + if(!mapping || mapping->begin>new_value || mapping->end<=new_value) { + mapping=find_mapping_for_cluster(s,first_cluster+i); + } + + print_mappings(s); + fprintf(stderr,"fat_get(%d)=%d\n",first_cluster+i,new_value); + /* TODO: what if there's no mapping? this is valid. */ + /* TODO: refactor the rest of this clause so it can be called when the direntry changes, too */ + assert(mapping); + + if(new_value>1 && new_valuemax_fat_value-0xf) { + /* the cluster new_value points to is valid */ + + if(first_cluster+i+1==new_value) { + /* consecutive cluster */ + if(mapping->end<=new_value) + mapping->end=new_value+1; + } else { + mapping_t* next_mapping; + + /* the current mapping ends here */ + mapping->end=first_cluster+i+1; + + /* the next mapping */ + next_mapping=find_mapping_for_cluster(s,new_value); + if(next_mapping) { + assert(mapping!=next_mapping); + /* assert next mapping's filename is the same */ + assert(next_mapping->filename==mapping->filename); + assert(next_mapping->dir_index==mapping->dir_index); + /* assert next mapping is MODIFIED or UNDEFINED */ + assert(next_mapping->mode==MODE_MODIFIED || next_mapping->mode==MODE_UNDEFINED); + } else { + int index=find_mapping_for_cluster_aux(s,new_value,0,s->mapping.next); + next_mapping=array_insert(&(s->mapping),index,1); + next_mapping->filename=mapping->filename; + next_mapping->dir_index=mapping->dir_index; + next_mapping->mode=MODE_MODIFIED; + next_mapping->begin=0; + } + /* adjust offset of next mapping */ + next_mapping->offset=mapping->offset+mapping->end-mapping->begin; + /* set begin and possible end */ + if(next_mapping->begin!=new_value) { + next_mapping->begin=new_value; + next_mapping->end=new_value+1; + } + if(commit_data_if_consistent(s,mapping,WRITE_FAT)) + return -4; + mapping=0; + } + } else if(fat_eof(s,new_value)) { + /* the last cluster of the file */ + mapping->end=first_cluster+i+1; + if(commit_data_if_consistent(s,mapping,WRITE_FAT)) + return -4; + mapping=0; + } + } + } else if(sector_numfirst_sectors_number+2*s->sectors_per_fat) { + /* FAT 2: check if it is the same as FAT 1 */ + if(memcmp(array_get(&(s->fat),sector_num-s->first_sectors_number),buf,0x200)) + return -1; /* mismatch */ + } else if(sector_numfaked_sectors) { + /* direntry */ + /* - if they are in a directory, check if the entry has changed. + * if yes, look what has changed (different strategies for name, + * begin & size). + * + * if it is new (old entry is only 0's or has E5 at the start), + * create it, and also create mapping, but in a special mode + * "undefined", because we cannot know which clusters belong + * to it yet. + * + * if it is zeroed, or has E5 at the start, look if has just + * moved. If yes, copy the entry to the new position. If no, + * delete the file. + */ + mapping_t* dir_mapping=find_mapping_for_cluster(s,sector2cluster(s,sector_num)); + direntry_t *original=array_get(&(s->directory),sector_num-s->first_sectors_number-2*s->sectors_per_fat); + direntry_t *new_=(direntry_t*)buf; + int first_dir_index=(sector_num-s->first_sectors_number-2*s->sectors_per_fat)*0x200/0x20; + int j; + +#if 0 + fprintf(stderr,"direntry: consistency check\n"); + + if(s->commit.next==0) { + consistency_check1(s); + consistency_check2(s); + consistency_check3(s); + } +#endif + + assert(sizeof(direntry_t)==0x20); + + for(j=0;j<0x200/0x20;j++) { + //fprintf(stderr,"compare direntry %d: 0x%x,0x%x\n",j,(uint32_t)original+j,(uint32_t)new_+j); + if(memcmp(original+j,new_+j,sizeof(direntry_t))) { + //fprintf(stderr,"different\n"); + /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */ + if(direntry_is_free(original+j)) { + mapping_t* mapping; + char buffer[4096]; + int fd,i; + + if(new_[j].attributes==0xf) + continue; /* long entry */ + + print_mappings(s); + //fprintf(stderr,"sector: %d cluster: %d\n",(int)sector_num,(int)sector2cluster(s,sector_num)); + + /* construct absolute path */ + strncpy(buffer,dir_mapping->filename,4096); + i=strlen(buffer); + if(i+2>=4096) + return -1; + buffer[i]='/'; + if(long2unix_name(buffer+i+1,4096-i-1,new_+j)) + return -2; + + /* new file/directory */ + if(new_[j].attributes&0x10) { +#ifdef _WIN32 +#define SEVENFIVEFIVE +#else +#define SEVENFIVEFIVE ,0755 +#endif + if(mkdir(buffer SEVENFIVEFIVE)) + return -3; + /* TODO: map direntry.begin as directory, together with new array_t direntries */ + assert(0); + } else { + fd=open(buffer,O_CREAT|O_EXCL,0644); + if(!fd) + return -3; + close(fd); + } + + /* create mapping */ + i=find_mapping_for_cluster_aux(s,begin_of_direntry(new_+j),0,s->mapping.next); + mapping=array_insert(&(s->mapping),i,1); + mapping->filename=strdup(buffer); + mapping->offset=0; + /* back pointer to direntry */ + mapping->dir_index=first_dir_index+j; + /* set mode to modified */ + mapping->mode=MODE_MODIFIED; + /* set begin to direntry.begin */ + mapping->begin=begin_of_direntry(new_+j); + /* set end to begin+1 */ + mapping->end=mapping->begin+1; + /* commit file contents */ + if(commit_data_if_consistent(s,mapping,WRITE_DIRENTRY)) { + fprintf(stderr,"error committing file contents for new file %s!\n",buffer); + return -4; + } + } else if(direntry_is_free(new_+j)) { + assert(0); + /* TODO: delete file */ + /* TODO: write direntry */ + /* TODO: modify mapping: set mode=deleted */ + } else { + /* modified file */ + mapping_t* mapping=0; + /* if direntry.begin has changed, + * set mode to modified, + * adapt begin, + * adapt end */ + /* TODO: handle rename */ + assert(!memcmp(new_[j].name,original[j].name,11)); + //fprintf(stderr,"1\n"); + if(new_[j].begin!=original[j].begin || new_[j].size/s->cluster_size!=original[j].size/s->cluster_size) { + //fprintf(stderr,"2\n"); + mapping = find_mapping_for_direntry(s,original+j); + //fprintf(stderr,"3\n"); + if(!mapping) /* this should never happen! */ + return -2; + mapping_modify_from_direntry(s,mapping,new_+j); + //fprintf(stderr,"4\n"); + if(commit_data_if_consistent(s,mapping,WRITE_DIRENTRY)) { + fprintf(stderr,"big error\n"); + return -4; + } + } + /* TODO: handle modified times and other attributes */ + + //fprintf(stderr,"5: mapping=0x%x, s=0x%x, s->mapping.pointer=0x%x\n",(uint32_t)mapping,(uint32_t)s,(uint32_t)s->mapping.pointer); + //fprintf(stderr,"6\n"); + } + } + } + /* write back direntries */ + memcpy(original,new_,0x200); + } else { + /* data */ + off_t sector=sector_num-s->first_sectors_number-2*s->sectors_per_fat; + off_t cluster=sector/s->sectors_per_cluster; + mapping_t* mapping=find_mapping_for_cluster(s,cluster); + if(mapping && mapping->mode==MODE_DELETED) + return -3; /* this is an error: no writes to these clusters before committed */ + { + /* as of yet, undefined: put into commits */ + commit_t* commit=create_or_get_commit_for_sector(s,sector_num); + + if(!commit) + return -1; /* out of memory */ + memcpy(commit->buf+0x200*sector_offset_in_cluster(s,sector_num),buf,0x200); + + //fprintf(stderr,"mapping: 0x%x\n",(uint32_t)mapping); + if(commit_data_if_consistent(s,mapping,WRITE_DATA)) + return -4; + } + } + } + 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) + free(s->cluster); +} + +BlockDriver bdrv_vvfat = { + "vvfat", + sizeof(BDRVVVFATState), + vvfat_probe, + vvfat_open, + vvfat_read, + vvfat_write, + vvfat_close, +}; + + diff --git a/qemu-img.c b/qemu-img.c index 31f877606..9fb988757 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -658,9 +658,10 @@ static int img_info(int argc, char **argv) get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); allocated_size = get_allocated_file_size(filename); if (allocated_size < 0) - error("Could not get file size '%s'", filename); - get_human_readable_size(dsize_buf, sizeof(dsize_buf), - allocated_size); + sprintf(dsize_buf, "unavailable"); + else + get_human_readable_size(dsize_buf, sizeof(dsize_buf), + allocated_size); printf("image: %s\n" "file format: %s\n" "virtual size: %s (%lld bytes)\n" diff --git a/vl.h b/vl.h index 8d29506ef..12bebe6b0 100644 --- a/vl.h +++ b/vl.h @@ -384,6 +384,7 @@ extern BlockDriver bdrv_cloop; extern BlockDriver bdrv_dmg; extern BlockDriver bdrv_bochs; extern BlockDriver bdrv_vpc; +extern BlockDriver bdrv_vvfat; void bdrv_init(void); BlockDriver *bdrv_find_format(const char *format_name); -- cgit v1.2.3 From b671f9ed2de4c45995843a85a7f3adc90071a47e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 30 Apr 2005 15:08:33 +0000 Subject: typos git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1427 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 10 +++++----- qemu-tech.texi | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 106ecf4cd..2693db7b5 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -22,7 +22,7 @@ QEMU has two operating modes: @item Full system emulation. In this mode, QEMU emulates a full system (for -example a PC), including a processor and various peripherials. It can +example a PC), including a processor and various peripherals. It can be used to launch different Operating Systems without rebooting the PC or to debug system code. @@ -73,7 +73,7 @@ Download the experimental binary installer at @c man begin DESCRIPTION The QEMU System emulator simulates the -following PC peripherials: +following PC peripherals: @itemize @minus @item @@ -930,7 +930,7 @@ problem. Use the executable @file{qemu-system-ppc} to simulate a complete PREP or PowerMac PowerPC system. -QEMU emulates the following PowerMac peripherials: +QEMU emulates the following PowerMac peripherals: @itemize @minus @item @@ -947,7 +947,7 @@ Non Volatile RAM VIA-CUDA with ADB keyboard and mouse. @end itemize -QEMU emulates the following PREP peripherials: +QEMU emulates the following PREP peripherals: @itemize @minus @item @@ -1000,7 +1000,7 @@ More information is available at Use the executable @file{qemu-system-sparc} to simulate a JavaStation (sun4m architecture). The emulation is far from complete. -QEMU emulates the following sun4m peripherials: +QEMU emulates the following sun4m peripherals: @itemize @minus @item diff --git a/qemu-tech.texi b/qemu-tech.texi index 987b3c3ef..c86094b7c 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -22,7 +22,7 @@ QEMU has two operating modes: @item Full system emulation. In this mode, QEMU emulates a full system -(usually a PC), including a processor and various peripherials. It can +(usually a PC), including a processor and various peripherals. It can be used to launch an different Operating System without rebooting the PC or to debug system code. -- cgit v1.2.3 From a09db21f711237d01375b64e6a4da676e88d4f37 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 30 Apr 2005 16:10:35 +0000 Subject: Windows 2000 install disk full hack (original idea from Vladimir N. Oleynik) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1428 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ hw/ide.c | 26 +++++++++++++++++++++++++- vl.c | 17 +++++++++++++++-- vl.h | 1 + 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index 761a91d47..bea8f8b3e 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,8 @@ version 0.7.1: - read-only Virtual FAT support (Johannes Schindelin) + - Windows 2000 install disk full hack (original idea from Vladimir + N. Oleynik) version 0.7.0: diff --git a/hw/ide.c b/hw/ide.c index d2220ba0b..49039e7eb 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -332,6 +332,7 @@ typedef struct IDEState { uint8_t *data_ptr; uint8_t *data_end; uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; + QEMUTimer *sector_write_timer; /* only used for win2k instal hack */ } IDEState; #define BM_STATUS_DMAING 0x01 @@ -645,6 +646,12 @@ static void ide_sector_read_dma(IDEState *s) ide_dma_start(s, ide_read_dma_cb); } +static void ide_sector_write_timer_cb(void *opaque) +{ + IDEState *s = opaque; + ide_set_irq(s); +} + static void ide_sector_write(IDEState *s) { int64_t sector_num; @@ -670,7 +677,22 @@ static void ide_sector_write(IDEState *s) ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); } ide_set_sector(s, sector_num + n); - ide_set_irq(s); + +#ifdef TARGET_I386 + if (win2k_install_hack) { + /* It seems there is a bug in the Windows 2000 installer HDD + IDE driver which fills the disk with empty logs when the + IDE write IRQ comes too early. This hack tries to correct + that at the expense of slower write performances. Use this + option _only_ to install Windows 2000. You must disable it + for normal use. */ + qemu_mod_timer(s->sector_write_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); + } else +#endif + { + ide_set_irq(s); + } } static int ide_write_dma_cb(IDEState *s, @@ -1939,6 +1961,8 @@ static void ide_init2(IDEState *ide_state, int irq, } s->drive_serial = drive_serial++; s->irq = irq; + s->sector_write_timer = qemu_new_timer(vm_clock, + ide_sector_write_timer_cb, s); ide_reset(s); } } diff --git a/vl.c b/vl.c index 40c0c0afd..5c62e7315 100644 --- a/vl.c +++ b/vl.c @@ -147,6 +147,9 @@ int full_screen = 0; TextConsole *vga_console; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; +#ifdef TARGET_I386 +int win2k_install_hack = 0; +#endif /***********************************************************/ /* x86 ISA bus support */ @@ -933,7 +936,7 @@ static void init_timers(void) /* timer signal */ sigfillset(&act.sa_mask); - act.sa_flags = 0; + act.sa_flags = 0; #if defined (TARGET_I386) && defined(USE_CODE_COPY) act.sa_flags |= SA_ONSTACK; #endif @@ -2746,6 +2749,9 @@ void help(void) "-enable-audio enable audio support\n" "-localtime set the real time clock to local time [default=utc]\n" "-full-screen start in full screen\n" +#ifdef TARGET_I386 + "-win2k-hack use it when installing Windows 2000 to avoid a disk full bug\n" +#endif #ifdef TARGET_PPC "-prep Simulate a PREP system (default is PowerMAC)\n" #endif @@ -2878,6 +2884,7 @@ enum { QEMU_OPTION_full_screen, QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, + QEMU_OPTION_win2k_hack, }; typedef struct QEMUOption { @@ -2946,7 +2953,8 @@ const QEMUOption qemu_options[] = { { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, { "full-screen", 0, QEMU_OPTION_full_screen }, { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, - + { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, + /* temporary options */ { "pci", 0, QEMU_OPTION_pci }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, @@ -3397,6 +3405,11 @@ int main(int argc, char **argv) case QEMU_OPTION_pidfile: create_pidfile(optarg); break; +#ifdef TARGET_I386 + case QEMU_OPTION_win2k_hack: + win2k_install_hack = 1; + break; +#endif #ifdef USE_KQEMU case QEMU_OPTION_no_kqemu: kqemu_allowed = 0; diff --git a/vl.h b/vl.h index 12bebe6b0..21d4bf8e1 100644 --- a/vl.h +++ b/vl.h @@ -126,6 +126,7 @@ extern int graphic_height; extern int graphic_depth; extern const char *keyboard_layout; extern int kqemu_allowed; +extern int win2k_install_hack; /* XXX: make it dynamic */ #if defined (TARGET_PPC) -- cgit v1.2.3 From 2d5262f9919448f2199e6086a8af83cf4bfcdda1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 12 May 2005 18:46:11 +0000 Subject: dcbz fix (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1429 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 7d2e62b95..cf47f2b3f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2400,6 +2400,8 @@ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE) #define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() static GenOpFunc *gen_op_dcbz[] = { &gen_op_dcbz_user, + &gen_op_dcbz_user, + &gen_op_dcbz_kernel, &gen_op_dcbz_kernel, }; #endif -- cgit v1.2.3 From 04d81be884925127e2ebee994e4a89ce44eab06e Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 13 May 2005 22:42:37 +0000 Subject: open fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1430 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm-semi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c index ea014f6bc..6950daaa6 100644 --- a/linux-user/arm-semi.c +++ b/linux-user/arm-semi.c @@ -99,7 +99,7 @@ uint32_t do_arm_semihosting(CPUState *env) else return STDOUT_FILENO; } - return set_swi_errno(ts, open(s, open_modeflags[ARG(1)])); + return set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); case SYS_CLOSE: return set_swi_errno(ts, close(ARG(0))); case SYS_WRITEC: -- cgit v1.2.3 From ff8263a951c5ce22bef919c792d20e5cbf5066b3 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 13 May 2005 22:45:23 +0000 Subject: ARM saturating arithmetic fixes (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1431 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 17 +++++++++++++++++ target-arm/translate.c | 15 +++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/target-arm/op.c b/target-arm/op.c index 0a3811ed2..8a82def79 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -805,6 +805,23 @@ void OPPROTO op_subl_T0_T1_saturate(void) FORCE_RET(); } +void OPPROTO op_double_T1_saturate(void) +{ + int32_t val; + + val = T1; + if (val >= 0x40000000) { + T1 = 0x7fffffff; + env->QF = 1; + } else if (val <= (int32_t)0xc0000000) { + T1 = 0x80000000; + env->QF = 1; + } else { + T1 = val << 1; + } + FORCE_RET(); +} + /* thumb shift by immediate */ void OPPROTO op_shll_T0_im_thumb(void) { diff --git a/target-arm/translate.c b/target-arm/translate.c index 29657416f..2a62c5628 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1019,20 +1019,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0x5: /* saturating add/subtract */ rd = (insn >> 12) & 0xf; rn = (insn >> 16) & 0xf; - gen_movl_T0_reg(s, rn); - if (op1 & 2) { - gen_movl_T1_reg(s, rn); - if (op1 & 1) - gen_op_subl_T0_T1_saturate(); - else - gen_op_addl_T0_T1_saturate(); - } - gen_movl_T1_reg(s, rm); + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if (op1 & 2) + gen_op_double_T1_saturate(); if (op1 & 1) gen_op_subl_T0_T1_saturate(); else gen_op_addl_T0_T1_saturate(); - gen_movl_reg_T0(s, rn); + gen_movl_reg_T0(s, rd); break; case 0x8: /* signed multiply */ case 0xa: -- cgit v1.2.3 From bc380d1719ddcd70841784b2fb0a3b3c0ba935fa Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 13 May 2005 22:50:47 +0000 Subject: ARM VFP dump fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1432 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 2a62c5628..adbd56124 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2191,7 +2191,7 @@ void cpu_dump_state(CPUState *env, FILE *f, int flags) { int i; - struct { + union { uint32_t i; float s; } s0, s1; -- cgit v1.2.3 From 72cc6cfeef616f443761365c294a86057950f9bd Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 13 May 2005 23:08:13 +0000 Subject: handle the case where several PCI irqs share the same PIC irq git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1433 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index cb7131a6a..6283684ec 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -498,6 +498,27 @@ static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) return (irq_num + slot_addend) & 3; } +static inline int get_pci_irq_level(int irq_num) +{ + int pic_level; +#if (PCI_IRQ_WORDS == 2) + pic_level = ((pci_irq_levels[irq_num][0] | + pci_irq_levels[irq_num][1]) != 0); +#else + { + int i; + pic_level = 0; + for(i = 0; i < PCI_IRQ_WORDS; i++) { + if (pci_irq_levels[irq_num][i]) { + pic_level = 1; + break; + } + } + } +#endif + return pic_level; +} + static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level) { int irq_index, shift, pic_irq, pic_level; @@ -510,26 +531,20 @@ static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level) *p = (*p & ~(1 << shift)) | (level << shift); /* now we change the pic irq level according to the piix irq mappings */ + /* XXX: optimize */ pic_irq = piix3_state->dev.config[0x60 + irq_num]; if (pic_irq < 16) { /* the pic level is the logical OR of all the PCI irqs mapped to it */ pic_level = 0; -#if (PCI_IRQ_WORDS == 2) - pic_level = ((pci_irq_levels[irq_num][0] | - pci_irq_levels[irq_num][1]) != 0); -#else - { - int i; - pic_level = 0; - for(i = 0; i < PCI_IRQ_WORDS; i++) { - if (pci_irq_levels[irq_num][i]) { - pic_level = 1; - break; - } - } - } -#endif + if (pic_irq == piix3_state->dev.config[0x60]) + pic_level |= get_pci_irq_level(0); + if (pic_irq == piix3_state->dev.config[0x61]) + pic_level |= get_pci_irq_level(1); + if (pic_irq == piix3_state->dev.config[0x62]) + pic_level |= get_pci_irq_level(2); + if (pic_irq == piix3_state->dev.config[0x63]) + pic_level |= get_pci_irq_level(3); pic_set_irq(pic_irq, pic_level); } } -- cgit v1.2.3 From e4cf1adc806f24d26756fa828e0d7b515a06752d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Jun 2005 20:15:57 +0000 Subject: added sum command git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1434 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/monitor.c b/monitor.c index b9de0295c..285508e06 100644 --- a/monitor.c +++ b/monitor.c @@ -562,6 +562,22 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne term_printf("\n"); } +static void do_sum(uint32_t start, uint32_t size) +{ + uint32_t addr; + uint8_t buf[1]; + uint16_t sum; + + sum = 0; + for(addr = start; addr < (start + size); addr++) { + cpu_physical_memory_rw(addr, buf, 1, 0); + /* BSD sum algorithm ('sum' Unix command) */ + sum = (sum >> 1) | (sum << 15); + sum += buf[0]; + } + term_printf("%05d\n", sum); +} + typedef struct { int keycode; const char *name; @@ -906,6 +922,8 @@ static term_cmd_t term_cmds[] = { "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, { "system_reset", "", do_system_reset, "", "reset the system" }, + { "sum", "ii", do_sum, + "addr size", "compute the checksum of a memory region" }, { NULL, NULL, }, }; -- cgit v1.2.3 From 43ef9eb267fc0daade111c35ae945dc95427e3ef Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Jun 2005 20:34:16 +0000 Subject: use fprintf_func callback to print code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1435 c046a42c-6fe2-441c-8c8c-71466251a162 --- ppc-dis.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/ppc-dis.c b/ppc-dis.c index fcced1785..0da1be99e 100644 --- a/ppc-dis.c +++ b/ppc-dis.c @@ -3067,7 +3067,9 @@ const struct powerpc_macro powerpc_macros[] = { const int powerpc_num_macros = sizeof (powerpc_macros) / sizeof (powerpc_macros[0]); -static int print_insn_powerpc(FILE *, uint32_t insn, unsigned memaddr, int dialect); +static int +print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr, + int dialect); /* Print a big endian PowerPC instruction. For convenience, also disassemble instructions supported by the Motorola PowerPC 601. */ @@ -3083,14 +3085,14 @@ int print_insn_ppc (bfd_vma pc, disassemble_info *info) opc = bfd_getb32(buf); else opc = bfd_getl32(buf); - return print_insn_powerpc (info->stream, opc, pc, + return print_insn_powerpc (info, opc, pc, PPC | B32 | M601); } /* Print a PowerPC or POWER instruction. */ static int -print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr, +print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr, int dialect) { const struct powerpc_opcode *opcode; @@ -3136,9 +3138,9 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr, continue; /* The instruction is valid. */ - fprintf(out, "%s", opcode->name); + (*info->fprintf_func)(info->stream, "%s", opcode->name); if (opcode->operands[0] != 0) - fprintf(out, "\t"); + (*info->fprintf_func)(info->stream, "\t"); /* Now extract and print the operands. */ need_comma = 0; @@ -3175,26 +3177,26 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr, if (need_comma) { - fprintf(out, ","); + (*info->fprintf_func)(info->stream, ","); need_comma = 0; } /* Print the operand as directed by the flags. */ if ((operand->flags & PPC_OPERAND_GPR) != 0) - fprintf(out, "r%d", value); + (*info->fprintf_func)(info->stream, "r%d", value); else if ((operand->flags & PPC_OPERAND_FPR) != 0) - fprintf(out, "f%d", value); + (*info->fprintf_func)(info->stream, "f%d", value); else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) - fprintf(out, "%08X", memaddr + value); + (*info->fprintf_func)(info->stream, "%08X", memaddr + value); else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) - fprintf(out, "%08X", value & 0xffffffff); + (*info->fprintf_func)(info->stream, "%08X", value & 0xffffffff); else if ((operand->flags & PPC_OPERAND_CR) == 0 || (dialect & PPC_OPCODE_PPC) == 0) - fprintf(out, "%d", value); + (*info->fprintf_func)(info->stream, "%d", value); else { if (operand->bits == 3) - fprintf(out, "cr%d", value); + (*info->fprintf_func)(info->stream, "cr%d", value); else { static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; @@ -3203,20 +3205,20 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr, cr = value >> 2; if (cr != 0) - fprintf(out, "4*cr%d", cr); + (*info->fprintf_func)(info->stream, "4*cr%d", cr); cc = value & 3; if (cc != 0) { if (cr != 0) - fprintf(out, "+"); - fprintf(out, "%s", cbnames[cc]); + (*info->fprintf_func)(info->stream, "+"); + (*info->fprintf_func)(info->stream, "%s", cbnames[cc]); } } } if (need_paren) { - fprintf(out, ")"); + (*info->fprintf_func)(info->stream, ")"); need_paren = 0; } @@ -3224,7 +3226,7 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr, need_comma = 1; else { - fprintf(out, "("); + (*info->fprintf_func)(info->stream, "("); need_paren = 1; } } @@ -3234,7 +3236,7 @@ print_insn_powerpc (FILE *out, uint32_t insn, unsigned memaddr, } /* We could not find a match. */ - fprintf(out, ".long 0x%x", insn); + (*info->fprintf_func)(info->stream, ".long 0x%x", insn); return 4; } -- cgit v1.2.3 From 6d506e6dc2994030427e185bf44f0020c37ac086 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Jun 2005 22:16:41 +0000 Subject: added temporary osi_call callback git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1436 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 12f7c1720..7df0c6269 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -159,6 +159,9 @@ typedef struct CPUPPCState { /* Power management */ int power_mode; + /* temporary hack to handle OSI calls (only used if non NULL) */ + int (*osi_call)(struct CPUPPCState *env); + /* user data */ void *opaque; } CPUPPCState; -- cgit v1.2.3 From d094807b9bfe39401e82dce6b7e97a70eb5931be Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Jun 2005 22:17:59 +0000 Subject: MMU fix - temporary osi_call support - xec_bc mask fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1437 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 71 ++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b54b5d205..52aad9532 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -22,6 +22,8 @@ //#define DEBUG_MMU //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS +/* accurate but slower TLB flush in exceptions */ +//#define ACCURATE_TLB_FLUSH /*****************************************************************************/ /* PPC MMU emulation */ @@ -128,7 +130,7 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, pte0 = ldl_phys(base + (i * 8)); pte1 = ldl_phys(base + (i * 8) + 4); #if defined (DEBUG_MMU) - if (loglevel > 0) { + if (loglevel > 0) { fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, pte0 >> 31, h, (pte0 >> 6) & 1, va); @@ -175,17 +177,17 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, if (loglevel > 0) fprintf(logfile, "PTE access granted !\n"); #endif - good = i; - keep = pte1; - ret = 0; + good = i; + keep = pte1; + ret = 0; } else { /* Access right violation */ - ret = -2; + ret = -2; #if defined (DEBUG_MMU) if (loglevel > 0) fprintf(logfile, "PTE access rejected\n"); #endif - } + } *prot = access; } } @@ -194,7 +196,7 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, if (good != -1) { *RPN = keep & 0xFFFFF000; #if defined (DEBUG_MMU) - if (loglevel > 0) { + if (loglevel > 0) { fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", *RPN, *prot, ret); } @@ -205,7 +207,7 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, keep |= 0x00000100; store = 1; } - if (!(keep & 0x00000080)) { + if (!(keep & 0x00000080)) { if (rw && ret == 0) { /* Change flag */ keep |= 0x00000080; @@ -251,7 +253,7 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; if ((sr & 0x80000000) == 0) { #if defined (DEBUG_MMU) - if (loglevel > 0) + if (loglevel > 0) fprintf(logfile, "pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000); #endif @@ -604,7 +606,7 @@ void _store_xer (CPUState *env, uint32_t value) xer_so = (value >> XER_SO) & 0x01; xer_ov = (value >> XER_OV) & 0x01; xer_ca = (value >> XER_CA) & 0x01; - xer_bc = (value >> XER_BC) & 0x1f; + xer_bc = (value >> XER_BC) & 0x3f; } uint32_t _load_msr (CPUState *env) @@ -628,12 +630,12 @@ uint32_t _load_msr (CPUState *env) void _store_msr (CPUState *env, uint32_t value) { -#if 0 // TRY +#ifdef ACCURATE_TLB_FLUSH if (((value >> MSR_IR) & 0x01) != msr_ir || ((value >> MSR_DR) & 0x01) != msr_dr) { /* Flush all tlb when changing translation mode or privilege level */ - tlb_flush(env, 1); + tlb_flush(env, 1); } #endif msr_pow = (value >> MSR_POW) & 0x03; @@ -660,6 +662,13 @@ void do_interrupt (CPUState *env) env->exception_index = -1; } #else +static void dump_syscall(CPUState *env) +{ + fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x r5=0x%08x r6=0x%08x nip=0x%08x\n", + env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->nip); +} + void do_interrupt (CPUState *env) { uint32_t msr; @@ -707,11 +716,11 @@ void do_interrupt (CPUState *env) */ msr &= ~0xFFFF0000; env->spr[DSISR] = 0; - if (env->error_code & EXCP_DSI_TRANSLATE) + if ((env->error_code & 0x0f) == EXCP_DSI_TRANSLATE) env->spr[DSISR] |= 0x40000000; - else if (env->error_code & EXCP_DSI_PROT) + else if ((env->error_code & 0x0f) == EXCP_DSI_PROT) env->spr[DSISR] |= 0x08000000; - else if (env->error_code & EXCP_DSI_NOTSUP) { + else if ((env->error_code & 0x0f) == EXCP_DSI_NOTSUP) { env->spr[DSISR] |= 0x80000000; if (env->error_code & EXCP_DSI_DIRECT) env->spr[DSISR] |= 0x04000000; @@ -819,28 +828,15 @@ void do_interrupt (CPUState *env) } goto store_next; case EXCP_SYSCALL: + /* NOTE: this is a temporary hack to support graphics OSI + calls from the MOL driver */ + if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && + env->osi_call) { + if (env->osi_call(env) != 0) + return; + } if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", - env->gpr[0], env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6]); - if (env->gpr[0] == 4 && env->gpr[3] == 1) { - int len, addr, i; - uint8_t c; - - fprintf(logfile, "write: "); - addr = env->gpr[4]; - len = env->gpr[5]; - if (len > 64) - len = 64; - for(i = 0; i < len; i++) { - c = 0; - cpu_memory_rw_debug(env, addr + i, &c, 1, 0); - if (c < 32 || c > 126) - c = '.'; - fprintf(logfile, "%c", c); - } - fprintf(logfile, "\n"); - } + dump_syscall(env); } goto store_next; case EXCP_TRACE: @@ -887,6 +883,9 @@ void do_interrupt (CPUState *env) env->nip = excp << 8; env->exception_index = EXCP_NONE; /* Invalidate all TLB as we may have changed translation mode */ +#ifdef ACCURATE_TLB_FLUSH + tlb_flush(env, 1); +#endif /* ensure that no TB jump will be modified as the program flow was changed */ #ifdef __sparc__ -- cgit v1.2.3 From 899343378961f6639376d95822cbceb7c0b64dbe Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Jun 2005 22:19:02 +0000 Subject: bctr and blr must ignore the two lsb git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1438 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 6ae7a523b..8c8021e1a 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -446,7 +446,7 @@ PPC_OP(b) PPC_OP(b_T1) { - regs->nip = T1; + regs->nip = T1 & ~3; } PPC_OP(btest) -- cgit v1.2.3 From 30aec8768fcfe30ff87892e254eec3b9d42cd0dc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Jun 2005 22:19:19 +0000 Subject: xec_bc mask fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1439 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 102249d41..3f5fb0bbc 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -103,7 +103,7 @@ void do_store_xer (void) xer_so = (T0 >> XER_SO) & 0x01; xer_ov = (T0 >> XER_OV) & 0x01; xer_ca = (T0 >> XER_CA) & 0x01; - xer_bc = (T0 >> XER_BC) & 0x1f; + xer_bc = (T0 >> XER_BC) & 0x3f; } void do_load_msr (void) -- cgit v1.2.3 From 71be0fc3eb3f8ac523e1b1b2ae138a5c9a613dee Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Jun 2005 22:19:46 +0000 Subject: removed dynamic test of traces git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1440 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper_mem.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index fa7f07676..6fc120242 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -3,10 +3,10 @@ void glue(do_lsw, MEMSUFFIX) (int dst) uint32_t tmp; int sh; - if (loglevel > 0) { - fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", - __func__, T0, T1, dst); - } +#if 0 + fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", + __func__, T0, T1, dst); +#endif for (; T1 > 3; T1 -= 4, T0 += 4) { ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0); if (dst == 32) @@ -25,10 +25,10 @@ void glue(do_stsw, MEMSUFFIX) (int src) { int sh; - if (loglevel > 0) { - fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", - __func__, T0, T1, src); - } +#if 0 + fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", + __func__, T0, T1, src); +#endif for (; T1 > 3; T1 -= 4, T0 += 4) { glue(stl, MEMSUFFIX)(T0, ugpr(src++)); if (src == 32) @@ -45,10 +45,10 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst) uint32_t tmp; int sh; - if (loglevel > 0) { +#if 0 fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", __func__, T0, T1, dst); - } +#endif for (; T1 > 3; T1 -= 4, T0 += 4) { tmp = glue(ldl, MEMSUFFIX)(T0); ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | @@ -70,10 +70,10 @@ void glue(do_stsw_le, MEMSUFFIX) (int src) uint32_t tmp; int sh; - if (loglevel > 0) { +#if 0 fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", __func__, T0, T1, src); - } +#endif for (; T1 > 3; T1 -= 4, T0 += 4) { tmp = ((ugpr(src++) & 0xFF000000) >> 24); tmp |= ((ugpr(src++) & 0x00FF0000) >> 8); -- cgit v1.2.3 From 8dd4983c4e0c4e4f2ed87060a770ba99e03f3b9e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Jun 2005 22:22:27 +0000 Subject: fixed lsw[ix] / stsw[ix] potential exception bug - mtcrf workaround for Mac OS X 10.4 - use direct jump at page boundary git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1441 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index cf47f2b3f..2a828ed29 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1370,6 +1370,8 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) gen_op_load_gpr_T0(ra); } gen_op_set_T1(nb); + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip((ctx)->nip - 4); op_ldsts(lswi, start); } @@ -1388,6 +1390,8 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) gen_op_add(); } gen_op_load_xer_bc(); + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip((ctx)->nip - 4); op_ldstsx(lswx, rD(ctx->opcode), ra, rb); } @@ -1404,6 +1408,8 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) if (nb == 0) nb = 32; gen_op_set_T1(nb); + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip((ctx)->nip - 4); op_ldsts(stsw, rS(ctx->opcode)); } @@ -1421,6 +1427,8 @@ GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) gen_op_add(); } gen_op_load_xer_bc(); + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip((ctx)->nip - 4); op_ldsts(stsw, rS(ctx->opcode)); } @@ -2123,7 +2131,8 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) } /* mtcrf */ -GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC) +/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */ +GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) { gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_cr(CRM(ctx->opcode)); @@ -3312,10 +3321,14 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.exception != EXCP_TRAP)) { RET_EXCP(ctxp, EXCP_TRACE, 0); } + if (ctx.exception != EXCP_NONE) + break; /* if we reach a page boundary, stop generation */ if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { - RET_EXCP(ctxp, EXCP_BRANCH, 0); - } + gen_op_b((long)ctx.tb, ctx.nip); + ctx.exception = EXCP_BRANCH; + break; + } } if (ctx.exception == EXCP_NONE) { gen_op_b((unsigned long)ctx.tb, ctx.nip); -- cgit v1.2.3 From 7c48011b451f1a80cc98d99b796d41c97c96bcd1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 14:38:00 +0000 Subject: added back loglevel test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1442 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper_mem.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index 6fc120242..fb90691f2 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -4,8 +4,10 @@ void glue(do_lsw, MEMSUFFIX) (int dst) int sh; #if 0 - fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", - __func__, T0, T1, dst); + if (loglevel > 0) { + fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", + __func__, T0, T1, dst); + } #endif for (; T1 > 3; T1 -= 4, T0 += 4) { ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0); @@ -26,8 +28,10 @@ void glue(do_stsw, MEMSUFFIX) (int src) int sh; #if 0 - fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", - __func__, T0, T1, src); + if (loglevel > 0) { + fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", + __func__, T0, T1, src); + } #endif for (; T1 > 3; T1 -= 4, T0 += 4) { glue(stl, MEMSUFFIX)(T0, ugpr(src++)); @@ -46,8 +50,10 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst) int sh; #if 0 + if (loglevel > 0) { fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", __func__, T0, T1, dst); + } #endif for (; T1 > 3; T1 -= 4, T0 += 4) { tmp = glue(ldl, MEMSUFFIX)(T0); @@ -71,8 +77,10 @@ void glue(do_stsw_le, MEMSUFFIX) (int src) int sh; #if 0 + if (loglevel > 0) { fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", __func__, T0, T1, src); + } #endif for (; T1 > 3; T1 -= 4, T0 += 4) { tmp = ((ugpr(src++) & 0xFF000000) >> 24); -- cgit v1.2.3 From 2d6187930509063b3103c76d200ced50639acdb6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 14:39:02 +0000 Subject: simplified end of page handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1443 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2a828ed29..b2006df53 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3321,14 +3321,9 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.exception != EXCP_TRAP)) { RET_EXCP(ctxp, EXCP_TRACE, 0); } - if (ctx.exception != EXCP_NONE) - break; /* if we reach a page boundary, stop generation */ - if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { - gen_op_b((long)ctx.tb, ctx.nip); - ctx.exception = EXCP_BRANCH; + if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) break; - } } if (ctx.exception == EXCP_NONE) { gen_op_b((unsigned long)ctx.tb, ctx.nip); -- cgit v1.2.3 From cc1daa40f188ec3ea6c37db546887488a419e900 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 14:49:17 +0000 Subject: added -M machine option - permit to put CDROM on hdb on PPC to handle the case where a single IDE controller is present git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1444 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 35 deletions(-) diff --git a/vl.c b/vl.c index 5c62e7315..c922e9864 100644 --- a/vl.c +++ b/vl.c @@ -2493,6 +2493,33 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) return 0; } +/***********************************************************/ +/* machine registration */ + +QEMUMachine *first_machine = NULL; + +int qemu_register_machine(QEMUMachine *m) +{ + QEMUMachine **pm; + pm = &first_machine; + while (*pm != NULL) + pm = &(*pm)->next; + m->next = NULL; + *pm = m; + return 0; +} + +QEMUMachine *find_machine(const char *name) +{ + QEMUMachine *m; + + for(m = first_machine; m != NULL; m = m->next) { + if (!strcmp(m->name, name)) + return m; + } + return NULL; +} + /***********************************************************/ /* main execution loop */ @@ -2735,6 +2762,7 @@ void help(void) "'disk_image' is a raw hard image image for IDE hard disk 0\n" "\n" "Standard options:\n" + "-M machine select emulated machine (-M ? for list)\n" "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" @@ -2752,9 +2780,6 @@ void help(void) #ifdef TARGET_I386 "-win2k-hack use it when installing Windows 2000 to avoid a disk full bug\n" #endif -#ifdef TARGET_PPC - "-prep Simulate a PREP system (default is PowerMAC)\n" -#endif #if defined(TARGET_PPC) || defined(TARGET_SPARC) "-g WxH[xDEPTH] Set the initial graphical resolution and depth\n" #endif @@ -2835,6 +2860,7 @@ void help(void) enum { QEMU_OPTION_h, + QEMU_OPTION_M, QEMU_OPTION_fda, QEMU_OPTION_fdb, QEMU_OPTION_hda, @@ -2896,6 +2922,7 @@ typedef struct QEMUOption { const QEMUOption qemu_options[] = { { "h", 0, QEMU_OPTION_h }, + { "M", HAS_ARG, QEMU_OPTION_M }, { "fda", HAS_ARG, QEMU_OPTION_fda }, { "fdb", HAS_ARG, QEMU_OPTION_fdb }, { "hda", HAS_ARG, QEMU_OPTION_hda }, @@ -3007,6 +3034,20 @@ static void read_passwords(void) } } +/* XXX: currently we cannot use simultaneously different CPUs */ +void register_machines(void) +{ +#if defined(TARGET_I386) + qemu_register_machine(&pc_machine); +#elif defined(TARGET_PPC) + qemu_register_machine(&heathrow_machine); + qemu_register_machine(&core99_machine); + qemu_register_machine(&prep_machine); +#elif defined(TARGET_SPARC) + qemu_register_machine(&sun4m_machine); +#endif +} + #define NET_IF_TUN 0 #define NET_IF_USER 1 #define NET_IF_DUMMY 2 @@ -3016,7 +3057,7 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB int use_gdbstub, gdbstub_port; #endif - int i, has_cdrom; + int i, cdrom_index; int snapshot, linux_boot; CPUState *env; const char *initrd_filename; @@ -3036,11 +3077,14 @@ int main(int argc, char **argv) char parallel_devices[MAX_PARALLEL_PORTS][128]; int parallel_device_index; const char *loadvm = NULL; - + QEMUMachine *machine; + #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); #endif + register_machines(); + machine = first_machine; initrd_filename = NULL; for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; @@ -3058,7 +3102,11 @@ int main(int argc, char **argv) nographic = 0; kernel_filename = NULL; kernel_cmdline = ""; - has_cdrom = 1; +#ifdef TARGET_PPC + cdrom_index = 1; +#else + cdrom_index = 2; +#endif cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); @@ -3118,14 +3166,33 @@ int main(int argc, char **argv) } switch(popt->index) { + case QEMU_OPTION_M: + machine = find_machine(optarg); + if (!machine) { + QEMUMachine *m; + printf("Supported machines are:\n"); + for(m = first_machine; m != NULL; m = m->next) { + printf("%-10s %s%s\n", + m->name, m->desc, + m == first_machine ? " (default)" : ""); + } + exit(1); + } + break; case QEMU_OPTION_initrd: initrd_filename = optarg; break; case QEMU_OPTION_hda: - hd_filename[0] = optarg; - break; case QEMU_OPTION_hdb: - hd_filename[1] = optarg; + case QEMU_OPTION_hdc: + case QEMU_OPTION_hdd: + { + int hd_index; + hd_index = popt->index - QEMU_OPTION_hda; + hd_filename[hd_index] = optarg; + if (hd_index == cdrom_index) + cdrom_index = -1; + } break; case QEMU_OPTION_snapshot: snapshot = 1; @@ -3192,16 +3259,10 @@ int main(int argc, char **argv) } } break; - case QEMU_OPTION_hdc: - hd_filename[2] = optarg; - has_cdrom = 0; - break; - case QEMU_OPTION_hdd: - hd_filename[3] = optarg; - break; case QEMU_OPTION_cdrom: - hd_filename[2] = optarg; - has_cdrom = 1; + if (cdrom_index >= 0) { + hd_filename[cdrom_index] = optarg; + } break; case QEMU_OPTION_boot: boot_device = optarg[0]; @@ -3421,7 +3482,9 @@ int main(int argc, char **argv) linux_boot = (kernel_filename != NULL); - if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0' && + if (!linux_boot && + hd_filename[0] == '\0' && + (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') help(); @@ -3531,9 +3594,9 @@ int main(int argc, char **argv) /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); - if (has_cdrom) { - bs_table[2] = bdrv_new("cdrom"); - bdrv_set_type_hint(bs_table[2], BDRV_TYPE_CDROM); + if (cdrom_index >= 0) { + bs_table[cdrom_index] = bdrv_new("cdrom"); + bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); } /* open the virtual block devices */ @@ -3684,19 +3747,9 @@ int main(int argc, char **argv) #endif init_timers(); -#if defined(TARGET_I386) - pc_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, initrd_filename); -#elif defined(TARGET_PPC) - ppc_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, initrd_filename); -#elif defined(TARGET_SPARC) - sun4m_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, initrd_filename); -#endif + machine->init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); -- cgit v1.2.3 From 54fa5af54622a9bd2d4e6988a6e402f60bde3653 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 14:50:39 +0000 Subject: more generic IRQ support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1445 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 6 ++++++ hw/openpic.c | 3 ++- vl.h | 64 ++++++++++++++++++++++++++++++++++++------------------------ 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/hw/i8259.c b/hw/i8259.c index 8f1821d97..9bfaaed1b 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -179,6 +179,12 @@ void pic_set_irq(int irq, int level) pic_update_irq(); } +/* this function should be used to have the controller context */ +void pic_set_irq_new(void *opaque, int irq, int level) +{ + pic_set_irq(irq, level); +} + /* acknowledge interrupt 'irq' */ static inline void pic_intack(PicState *s, int irq) { diff --git a/hw/openpic.c b/hw/openpic.c index e6bca3270..08fb9bd12 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -320,8 +320,9 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) } } -void openpic_set_irq(openpic_t *opp, int n_IRQ, int level) +void openpic_set_irq(void *opaque, int n_IRQ, int level) { + openpic_t *opp = opaque; IRQ_src_t *src; src = &opp->src[n_IRQ]; diff --git a/vl.h b/vl.h index 21d4bf8e1..3b2ccda93 100644 --- a/vl.h +++ b/vl.h @@ -443,6 +443,24 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf); #ifndef QEMU_TOOL + +typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, + int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename); + +typedef struct QEMUMachine { + const char *name; + const char *desc; + QEMUMachineInitFunc *init; + struct QEMUMachine *next; +} QEMUMachine; + +int qemu_register_machine(QEMUMachine *m); + +typedef void SetIRQFunc(void *opaque, int irq_num, int level); + /* ISA bus */ extern target_phys_addr_t isa_mem_base; @@ -527,16 +545,21 @@ void pci_bios_init(void); void pci_info(void); /* temporary: will be moved in platform specific file */ +void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque); PCIBus *pci_prep_init(void); -struct openpic_t; -void pci_pmac_set_openpic(PCIBus *bus, struct openpic_t *openpic); +PCIBus *pci_grackle_init(uint32_t base); PCIBus *pci_pmac_init(void); /* openpic.c */ typedef struct openpic_t openpic_t; -void openpic_set_irq (openpic_t *opp, int n_IRQ, int level); +void openpic_set_irq(void *opaque, int n_IRQ, int level); openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus); +/* heathrow_pic.c */ +typedef struct HeathrowPICS HeathrowPICS; +void heathrow_pic_set_irq(void *opaque, int num, int level); +HeathrowPICS *heathrow_pic_init(int *pmem_index); + /* vga.c */ #define VGA_RAM_SIZE (4096 * 1024) @@ -587,10 +610,11 @@ extern BlockDriverState *bs_table[MAX_DISKS]; void isa_ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1); -void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table); +void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, + int secondary_ide_enabled); void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table); int pmac_ide_init (BlockDriverState **hd_table, - openpic_t *openpic, int irq); + SetIRQFunc *set_irq, void *irq_opaque, int irq); /* sb16.c */ void SB16_init (void); @@ -655,6 +679,7 @@ ParallelState *parallel_init(int base, int irq, CharDriverState *chr); /* i8259.c */ void pic_set_irq(int irq, int level); +void pic_set_irq_new(void *opaque, int irq, int level); void pic_init(void); uint32_t pic_intack_read(CPUState *env); void pic_info(void); @@ -676,24 +701,13 @@ int pit_get_gate(PITState *pit, int channel); int pit_get_out(PITState *pit, int channel, int64_t current_time); /* pc.c */ -void pc_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename); +extern QEMUMachine pc_machine; /* ppc.c */ -void ppc_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename); -void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename); -void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename); +extern QEMUMachine prep_machine; +extern QEMUMachine core99_machine; +extern QEMUMachine heathrow_machine; + #ifdef TARGET_PPC ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); #endif @@ -702,12 +716,10 @@ void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); extern CPUWriteMemoryFunc *PPC_io_write[]; extern CPUReadMemoryFunc *PPC_io_read[]; extern int prep_enabled; +void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ -void sun4m_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename); +extern QEMUMachine sun4m_machine; uint32_t iommu_translate(uint32_t addr); /* iommu.c */ @@ -809,7 +821,7 @@ void adb_mouse_init(ADBBusState *bus); /* cuda.c */ extern ADBBusState adb_bus; -int cuda_init(openpic_t *openpic, int irq); +int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); #endif /* defined(QEMU_TOOL) */ -- cgit v1.2.3 From b5ff2d6e2d67a14b01872d852d879a69a83242cd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 14:51:11 +0000 Subject: PC machine support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1446 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 5deb445a3..dac125c09 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -380,10 +380,10 @@ static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; /* PC hardware initialisation */ -void pc_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) +static void pc_init1(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) { char buf[1024]; int ret, linux_boot, initrd_size, i, nb_nics1; @@ -595,3 +595,9 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, pci_bios_init(); } } + +QEMUMachine pc_machine = { + "pc", + "Standard PC", + pc_init1, +}; -- cgit v1.2.3 From 938828a263bc3708b8aead8bdc54cbc3526d5c59 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 14:54:40 +0000 Subject: use new machine API git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1447 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 5f992290e..2146739a9 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -440,23 +440,4 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, NVRAM_set_word(nvram, 0xFC, crc); return 0; - } - -/*****************************************************************************/ -void ppc_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - if (prep_enabled) { - ppc_prep_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, - snapshot, kernel_filename, kernel_cmdline, - initrd_filename); - } else { - ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, - snapshot, kernel_filename, kernel_cmdline, - initrd_filename); - } - /* Special port to get debug messages from Open-Firmware */ - register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); } -- cgit v1.2.3 From 0aa6a4a2500627d8824a536d4ea45176de273761 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 15:11:17 +0000 Subject: added Heathrow PowerMAC machine - added UniN memory fake controller for Mac99 - added temporary frame buffer OSI calls to keep Mac OS X happy git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1448 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 297 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 246 insertions(+), 51 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index f7c9b4503..af5799507 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -34,9 +34,10 @@ static int dbdma_mem_index; static int cuda_mem_index; -static int ide0_mem_index; -static int ide1_mem_index; -static int openpic_mem_index; +static int ide0_mem_index = -1; +static int ide1_mem_index = -1; +static int openpic_mem_index = -1; +static int heathrow_pic_mem_index = -1; /* DBDMA: currently no op - should suffice right now */ @@ -84,11 +85,20 @@ static CPUReadMemoryFunc *dbdma_read[] = { static void macio_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { + if (heathrow_pic_mem_index >= 0) { + cpu_register_physical_memory(addr + 0x00000, 0x1000, + heathrow_pic_mem_index); + } cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index); cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index); - cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index); - cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); - cpu_register_physical_memory(addr + 0x40000, 0x40000, openpic_mem_index); + if (ide0_mem_index >= 0) + cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index); + if (ide1_mem_index >= 0) + cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); + if (openpic_mem_index >= 0) { + cpu_register_physical_memory(addr + 0x40000, 0x40000, + openpic_mem_index); + } } static void macio_init(PCIBus *bus) @@ -116,20 +126,112 @@ static void macio_init(PCIBus *bus) PCI_ADDRESS_SPACE_MEM, macio_map); } -/* PowerPC PREP hardware initialisation */ -void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) +/* UniN device */ +static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ +} + +static uint32_t unin_readl (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static CPUWriteMemoryFunc *unin_write[] = { + &unin_writel, + &unin_writel, + &unin_writel, +}; + +static CPUReadMemoryFunc *unin_read[] = { + &unin_readl, + &unin_readl, + &unin_readl, +}; + +/* temporary frame buffer OSI calls for the video.x driver. The right + solution is to modify the driver to use VGA PCI I/Os */ +static int vga_osi_call(CPUState *env) +{ + static int vga_vbl_enabled; + int linesize; + + // printf("osi_call R5=%d\n", env->gpr[5]); + + /* same handler as PearPC, coming from the original MOL video + driver. */ + switch(env->gpr[5]) { + case 4: + break; + case 28: /* set_vmode */ + if (env->gpr[6] != 1 || env->gpr[7] != 0) + env->gpr[3] = 1; + else + env->gpr[3] = 0; + break; + case 29: /* get_vmode_info */ + if (env->gpr[6] != 0) { + if (env->gpr[6] != 1 || env->gpr[7] != 0) { + env->gpr[3] = 1; + break; + } + } + env->gpr[3] = 0; + env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */ + env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */ + env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */ + env->gpr[7] = 85 << 16; /* refresh rate */ + env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */ + linesize = ((graphic_depth + 7) >> 3) * graphic_width; + linesize = (linesize + 3) & ~3; + env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */ + break; + case 31: /* set_video power */ + env->gpr[3] = 0; + break; + case 39: /* video_ctrl */ + if (env->gpr[6] == 0 || env->gpr[6] == 1) + vga_vbl_enabled = env->gpr[6]; + env->gpr[3] = 0; + break; + case 47: + break; + case 59: /* set_color */ + /* R6 = index, R7 = RGB */ + env->gpr[3] = 0; + break; + case 64: /* get color */ + /* R6 = index */ + env->gpr[3] = 0; + break; + case 116: /* set hwcursor */ + /* R6 = x, R7 = y, R8 = visible, R9 = data */ + break; + default: + fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]); + break; + } + return 1; /* osi_call handled */ +} + +/* PowerPC CHRP hardware initialisation */ +static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + int is_heathrow) { char buf[1024]; - openpic_t *openpic; + SetIRQFunc *set_irq; + void *pic; m48t59_t *nvram; - int PPC_io_memory; + int PPC_io_memory, unin_memory; int ret, linux_boot, i; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; PCIBus *pci_bus; + const char *arch_name; linux_boot = (kernel_filename != NULL); @@ -180,49 +282,101 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, } /* Register CPU as a 74x/75x */ cpu_ppc_register(cpu_single_env, 0x00080000); - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); - - isa_mem_base = 0x80000000; - pci_bus = pci_pmac_init(); - - /* Register 8 MB of ISA IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); - cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory); - - /* init basic PC hardware */ - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); - openpic = openpic_init(NULL, &openpic_mem_index, 1); - pci_pmac_set_openpic(pci_bus, openpic); - - /* XXX: suppress that */ - pic_init(); - - /* XXX: use Mac Serial port */ - serial_init(0x3f8, 4, serial_hds[0]); - - for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(pci_bus, &nd_table[i]); + /* Set time-base frequency to 10 Mhz */ + cpu_ppc_tb_init(cpu_single_env, 10UL * 1000UL * 1000UL); + + cpu_single_env->osi_call = vga_osi_call; + + if (is_heathrow) { + isa_mem_base = 0x80000000; + pci_bus = pci_grackle_init(0xfec00000); + + /* Register 2 MB of ISA IO space */ + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); + cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory); + + /* init basic PC hardware */ + vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + pic = heathrow_pic_init(&heathrow_pic_mem_index); + set_irq = heathrow_pic_set_irq; + pci_set_pic(pci_bus, set_irq, pic); + + /* XXX: suppress that */ + pic_init(); + + /* XXX: use Mac Serial port */ + serial_init(0x3f8, 4, serial_hds[0]); + + for(i = 0; i < nb_nics; i++) { + pci_ne2000_init(pci_bus, &nd_table[i]); + } + + pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); + + /* cuda also initialize ADB */ + cuda_mem_index = cuda_init(set_irq, pic, 0x12); + + adb_kbd_init(&adb_bus); + adb_mouse_init(&adb_bus); + + macio_init(pci_bus); + + nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); + + arch_name = "HEATHROW"; + } else { + isa_mem_base = 0x80000000; + pci_bus = pci_pmac_init(); + + /* Register 8 MB of ISA IO space */ + PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); + cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory); + + /* UniN init */ + unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); + cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); + + /* init basic PC hardware */ + vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + pic = openpic_init(NULL, &openpic_mem_index, 1); + set_irq = openpic_set_irq; + pci_set_pic(pci_bus, set_irq, pic); + + /* XXX: suppress that */ + pic_init(); + + /* XXX: use Mac Serial port */ + serial_init(0x3f8, 4, serial_hds[0]); + + for(i = 0; i < nb_nics; i++) { + pci_ne2000_init(pci_bus, &nd_table[i]); + } + +#if 1 + ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13); + ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14); +#else + pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); +#endif + /* cuda also initialize ADB */ + cuda_mem_index = cuda_init(set_irq, pic, 0x19); + + adb_kbd_init(&adb_bus); + adb_mouse_init(&adb_bus); + + macio_init(pci_bus); + + nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); + + arch_name = "MAC99"; } - - ide0_mem_index = pmac_ide_init(&bs_table[0], openpic, 0x13); - ide1_mem_index = pmac_ide_init(&bs_table[2], openpic, 0x14); - - /* cuda also initialize ADB */ - cuda_mem_index = cuda_init(openpic, 0x19); - - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); - - macio_init(pci_bus); - - nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) graphic_depth = 15; - PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "CHRP", ram_size, boot_device, + PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device, kernel_base, kernel_size, kernel_cmdline, initrd_base, initrd_size, @@ -230,4 +384,45 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, 0, graphic_width, graphic_height, graphic_depth); /* No PCI init: the BIOS will do it */ + + /* Special port to get debug messages from Open-Firmware */ + register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); +} + +static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + ppc_chrp_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 0); } + +static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + ppc_chrp_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 1); +} + +QEMUMachine core99_machine = { + "core99", + "Core99 based PowerMAC", + ppc_core99_init, +}; + +QEMUMachine heathrow_machine = { + "heathrow", + "Heathrow based PowerMAC", + ppc_heathrow_init, +}; -- cgit v1.2.3 From 5457c8ceebafae8d3ff929d22bb32d1edb2250dd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 15:15:26 +0000 Subject: added CMD646 PCI IDE controller support - better IRQ handling - added IDE flush cache command - added work around for Darwin/PPC to select IDE drive git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1449 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 235 ++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 165 insertions(+), 70 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 49039e7eb..93e01924c 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -296,8 +296,9 @@ typedef struct IDEState { int cylinders, heads, sectors; int64_t nb_sectors; int mult_sectors; + SetIRQFunc *set_irq; + void *irq_opaque; int irq; - openpic_t *openpic; PCIDevice *pci_dev; struct BMDMAState *bmdma; int drive_serial; @@ -342,6 +343,18 @@ typedef struct IDEState { #define BM_CMD_START 0x01 #define BM_CMD_READ 0x08 +#define IDE_TYPE_PIIX3 0 +#define IDE_TYPE_CMD646 1 + +/* CMD646 specific */ +#define MRDMODE 0x71 +#define MRDMODE_INTR_CH0 0x04 +#define MRDMODE_INTR_CH1 0x08 +#define MRDMODE_BLK_CH0 0x10 +#define MRDMODE_BLK_CH1 0x20 +#define UDIDETCR0 0x73 +#define UDIDETCR1 0x7B + typedef int IDEDMAFunc(IDEState *s, target_phys_addr_t phys_addr, int transfer_size1); @@ -350,6 +363,8 @@ typedef struct BMDMAState { uint8_t cmd; uint8_t status; uint32_t addr; + + struct PCIIDEState *pci_dev; /* current transfer state */ IDEState *ide_if; IDEDMAFunc *dma_cb; @@ -359,6 +374,7 @@ typedef struct PCIIDEState { PCIDevice dev; IDEState ide_if[4]; BMDMAState bmdma[2]; + int type; /* see IDE_TYPE_xxx */ } PCIIDEState; static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb); @@ -502,17 +518,10 @@ static inline void ide_set_irq(IDEState *s) { BMDMAState *bm = s->bmdma; if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { - if (bm) + if (bm) { bm->status |= BM_STATUS_INT; -#ifdef TARGET_PPC - if (s->openpic) - openpic_set_irq(s->openpic, s->irq, 1); - else -#endif - if (s->irq == 16) - pci_set_irq(s->pci_dev, 0, 1); - else - pic_set_irq(s->irq, 1); + } + s->set_irq(s->irq_opaque, s->irq, 1); } } @@ -814,7 +823,8 @@ static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, case 2352: /* sync bytes */ buf[0] = 0x00; - memset(buf + 1, 0xff, 11); + memset(buf + 1, 0xff, 10); + buf[11] = 0x00; buf += 12; /* MSF */ lba_to_msf(buf, lba); @@ -942,6 +952,9 @@ static int ide_atapi_cmd_read_dma_cb(IDEState *s, transfer_size = transfer_size1; while (transfer_size > 0) { +#ifdef DEBUG_IDE_ATAPI + printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr); +#endif if (s->packet_transfer_size <= 0) break; len = s->cd_sector_size - s->io_buffer_index; @@ -1019,9 +1032,8 @@ static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) *q++ = 0; /* reserved */ if (msf) { *q++ = 0; /* reserved */ - *q++ = 0; /* minute */ - *q++ = 2; /* second */ - *q++ = 0; /* frame */ + lba_to_msf(q, 0); + q += 3; } else { /* sector 0 */ cpu_to_ube32(q, 0); @@ -1476,6 +1488,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) unit = (val >> 4) & 1; s = ide_if + unit; ide_if->cur_drive = s; +#ifdef TARGET_PPC + /* XXX: currently a workaround for Darwin/PPC. Need to check + the IDE spec to see if it is correct */ + ide_set_signature(s); +#endif break; default: case 7: @@ -1596,6 +1613,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case WIN_STANDBYNOW1: case WIN_IDLEIMMEDIATE: + case WIN_FLUSH_CACHE: s->status = READY_STAT; ide_set_irq(s); break; @@ -1697,15 +1715,7 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = 0; else ret = s->status; -#ifdef TARGET_PPC - if (s->openpic) - openpic_set_irq(s->openpic, s->irq, 0); - else -#endif - if (s->irq == 16) - pci_set_irq(s->pci_dev, 0, 0); - else - pic_set_irq(s->irq, 0); + s->set_irq(s->irq_opaque, s->irq, 0); break; } #ifdef DEBUG_IDE @@ -1898,8 +1908,9 @@ static int guess_disk_lchs(IDEState *s, return -1; } -static void ide_init2(IDEState *ide_state, int irq, - BlockDriverState *hd0, BlockDriverState *hd1) +static void ide_init2(IDEState *ide_state, + BlockDriverState *hd0, BlockDriverState *hd1, + SetIRQFunc *set_irq, void *irq_opaque, int irq) { IDEState *s; static int drive_serial = 1; @@ -1960,6 +1971,8 @@ static void ide_init2(IDEState *ide_state, int irq, } } s->drive_serial = drive_serial++; + s->set_irq = set_irq; + s->irq_opaque = irq_opaque; s->irq = irq; s->sector_write_timer = qemu_new_timer(vm_clock, ide_sector_write_timer_cb, s); @@ -1995,13 +2008,15 @@ void isa_ide_init(int iobase, int iobase2, int irq, if (!ide_state) return; - ide_init2(ide_state, irq, hd0, hd1); + ide_init2(ide_state, hd0, hd1, pic_set_irq_new, NULL, irq); ide_init_ioport(ide_state, iobase, iobase2); } /***********************************************************/ /* PCI IDE definitions */ +static void cmd646_update_irq(PCIIDEState *d); + static void ide_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { @@ -2082,17 +2097,6 @@ static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb) } } -static uint32_t bmdma_cmd_readb(void *opaque, uint32_t addr) -{ - BMDMAState *bm = opaque; - uint32_t val; - val = bm->cmd; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif - return val; -} - static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) { BMDMAState *bm = opaque; @@ -2112,24 +2116,77 @@ static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t bmdma_status_readb(void *opaque, uint32_t addr) +static uint32_t bmdma_readb(void *opaque, uint32_t addr) { BMDMAState *bm = opaque; + PCIIDEState *pci_dev; uint32_t val; - val = bm->status; + + switch(addr & 3) { + case 0: + val = bm->cmd; + break; + case 1: + pci_dev = bm->pci_dev; + if (pci_dev->type == IDE_TYPE_CMD646) { + val = pci_dev->dev.config[MRDMODE]; + } else { + val = 0xff; + } + break; + case 2: + val = bm->status; + break; + case 3: + pci_dev = bm->pci_dev; + if (pci_dev->type == IDE_TYPE_CMD646) { + if (bm == &pci_dev->bmdma[0]) + val = pci_dev->dev.config[UDIDETCR0]; + else + val = pci_dev->dev.config[UDIDETCR1]; + } else { + val = 0xff; + } + break; + default: + val = 0xff; + break; + } #ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); + printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val); #endif return val; } -static void bmdma_status_writeb(void *opaque, uint32_t addr, uint32_t val) +static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val) { BMDMAState *bm = opaque; + PCIIDEState *pci_dev; #ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); + printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val); #endif - bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); + switch(addr & 3) { + case 1: + pci_dev = bm->pci_dev; + if (pci_dev->type == IDE_TYPE_CMD646) { + pci_dev->dev.config[MRDMODE] = + (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30); + cmd646_update_irq(pci_dev); + } + break; + case 2: + bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); + break; + case 3: + pci_dev = bm->pci_dev; + if (pci_dev->type == IDE_TYPE_CMD646) { + if (bm == &pci_dev->bmdma[0]) + pci_dev->dev.config[UDIDETCR0] = val; + else + pci_dev->dev.config[UDIDETCR1] = val; + } + break; + } } static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr) @@ -2162,12 +2219,12 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, BMDMAState *bm = &d->bmdma[i]; d->ide_if[2 * i].bmdma = bm; d->ide_if[2 * i + 1].bmdma = bm; - + bm->pci_dev = (PCIIDEState *)pci_dev; + register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); - register_ioport_read(addr, 1, 1, bmdma_cmd_readb, bm); - register_ioport_write(addr + 2, 1, 1, bmdma_status_writeb, bm); - register_ioport_read(addr + 2, 1, 1, bmdma_status_readb, bm); + register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); + register_ioport_read(addr, 4, 1, bmdma_readb, bm); register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); @@ -2175,29 +2232,62 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, } } -/* hd_table must contain 4 block drivers */ -void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table) +/* XXX: call it also when the MRDMODE is changed from the PCI config + registers */ +static void cmd646_update_irq(PCIIDEState *d) +{ + int pci_level; + pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) && + !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) || + ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) && + !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1)); + pci_set_irq((PCIDevice *)d, 0, pci_level); +} + +/* the PCI irq level is the logical OR of the two channels */ +static void cmd646_set_irq(void *opaque, int channel, int level) +{ + PCIIDEState *d = opaque; + int irq_mask; + + irq_mask = MRDMODE_INTR_CH0 << channel; + if (level) + d->dev.config[MRDMODE] |= irq_mask; + else + d->dev.config[MRDMODE] &= ~irq_mask; + cmd646_update_irq(d); +} + +/* CMD646 PCI IDE controller */ +void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, + int secondary_ide_enabled) { PCIIDEState *d; uint8_t *pci_conf; int i; - d = (PCIIDEState *)pci_register_device(bus, "IDE", sizeof(PCIIDEState), + d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE", + sizeof(PCIIDEState), -1, NULL, NULL); + d->type = IDE_TYPE_CMD646; pci_conf = d->dev.config; - pci_conf[0x00] = 0x86; // Intel - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x00; // fake - pci_conf[0x03] = 0x01; // fake + pci_conf[0x00] = 0x95; // CMD646 + pci_conf[0x01] = 0x10; + pci_conf[0x02] = 0x46; + pci_conf[0x03] = 0x06; + + pci_conf[0x08] = 0x07; // IDE controller revision + pci_conf[0x09] = 0x8f; + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage - pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic - - pci_conf[0x2c] = 0x86; // subsys vendor - pci_conf[0x2d] = 0x80; // subsys vendor - pci_conf[0x2e] = 0x00; // fake - pci_conf[0x2f] = 0x01; // fake + pci_conf[0x0e] = 0x00; // header_type + + if (secondary_ide_enabled) { + /* XXX: if not enabled, really disable the seconday IDE controller */ + pci_conf[0x51] = 0x80; /* enable IDE1 */ + } pci_register_io_region((PCIDevice *)d, 0, 0x8, PCI_ADDRESS_SPACE_IO, ide_map); @@ -2211,11 +2301,13 @@ void pci_ide_init(PCIBus *bus, BlockDriverState **hd_table) PCI_ADDRESS_SPACE_IO, bmdma_map); pci_conf[0x3d] = 0x01; // interrupt on pin 1 - + for(i = 0; i < 4; i++) d->ide_if[i].pci_dev = (PCIDevice *)d; - ide_init2(&d->ide_if[0], 16, hd_table[0], hd_table[1]); - ide_init2(&d->ide_if[2], 16, hd_table[2], hd_table[3]); + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], + cmd646_set_irq, d, 0); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], + cmd646_set_irq, d, 1); } /* hd_table must contain 4 block drivers */ @@ -2230,6 +2322,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) sizeof(PCIIDEState), ((PCIDevice *)piix3_state)->devfn + 1, NULL, NULL); + d->type = IDE_TYPE_PIIX3; + pci_conf = d->dev.config; pci_conf[0x00] = 0x86; // Intel pci_conf[0x01] = 0x80; @@ -2242,8 +2336,10 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) pci_register_io_region((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, bmdma_map); - ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]); - ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]); + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], + pic_set_irq_new, NULL, 14); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], + pic_set_irq_new, NULL, 15); ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); ide_init_ioport(&d->ide_if[2], 0x170, 0x376); } @@ -2361,15 +2457,14 @@ static CPUReadMemoryFunc *pmac_ide_read[] = { /* PowerMac uses memory mapped registers, not I/O. Return the memory I/O index to access the ide. */ int pmac_ide_init (BlockDriverState **hd_table, - openpic_t *openpic, int irq) + SetIRQFunc *set_irq, void *irq_opaque, int irq) { IDEState *ide_if; int pmac_ide_memory; ide_if = qemu_mallocz(sizeof(IDEState) * 2); - ide_init2(&ide_if[0], irq, hd_table[0], hd_table[1]); - ide_if[0].openpic = openpic; - ide_if[1].openpic = openpic; + ide_init2(&ide_if[0], hd_table[0], hd_table[1], + set_irq, irq_opaque, irq); pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, pmac_ide_write, &ide_if[0]); -- cgit v1.2.3 From 384d887691a3b936e2703e2d9c01a1dc5294b8d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 15:16:50 +0000 Subject: correct PCI ID for PREP PCI host bridge - added Grackle PCI host bridge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1450 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 165 ++++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 61 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 6283684ec..a5ecbf1be 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -45,7 +45,9 @@ struct PCIBus { int devfn_min; void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level); uint32_t config_reg; /* XXX: suppress */ - openpic_t *openpic; /* XXX: suppress */ + /* low level pic */ + SetIRQFunc *low_set_irq; + void *irq_opaque; PCIDevice *devices[256]; }; @@ -723,25 +725,25 @@ PCIBus *pci_prep_init(void) PPC_PCIIO_write, s); cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); - d = pci_register_device(s, "PREP PCI Bridge", sizeof(PCIDevice), 0, - NULL, NULL); - - /* XXX: put correct IDs */ - d->config[0x00] = 0x11; // vendor_id + /* PCI host bridge */ + d = pci_register_device(s, "PREP Host Bridge - Motorola Raven", + sizeof(PCIDevice), 0, NULL, NULL); + d->config[0x00] = 0x57; // vendor_id : Motorola d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x04; // class_sub = pci2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x01; // header_type + d->config[0x02] = 0x01; // device_id : Raven + d->config[0x03] = 0x48; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer + return s; } -/* pmac pci init */ - -#if 0 /* Grackle PCI host */ static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, uint32_t val) @@ -846,7 +848,93 @@ static CPUReadMemoryFunc *pci_grackle_read[] = { &pci_grackle_readw, &pci_grackle_readl, }; + +void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque) +{ + bus->low_set_irq = set_irq; + bus->irq_opaque = irq_opaque; +} + +/* XXX: we do not simulate the hardware - we rely on the BIOS to + set correctly for irq line field */ +static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level) +{ + PCIBus *s = d->bus; + s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_grackle_init(uint32_t base) +{ + PCIBus *s; + PCIDevice *d; + int pci_mem_config, pci_mem_data; + + s = pci_register_bus(); + s->set_irq = pci_set_irq_simple; + + pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, + pci_grackle_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, + pci_grackle_write, s); + cpu_register_physical_memory(base, 0x1000, pci_mem_config); + cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); + d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice), + 0, NULL, NULL); + d->config[0x00] = 0x57; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x02; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x09] = 0x01; + d->config[0x0a] = 0x00; // class_sub = host + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x00; // header_type + + d->config[0x18] = 0x00; // primary_bus + d->config[0x19] = 0x01; // secondary_bus + d->config[0x1a] = 0x00; // subordinate_bus + d->config[0x1c] = 0x00; + d->config[0x1d] = 0x00; + + d->config[0x20] = 0x00; // memory_base + d->config[0x21] = 0x00; + d->config[0x22] = 0x01; // memory_limit + d->config[0x23] = 0x00; + + d->config[0x24] = 0x00; // prefetchable_memory_base + d->config[0x25] = 0x00; + d->config[0x26] = 0x00; // prefetchable_memory_limit + d->config[0x27] = 0x00; + +#if 0 + /* PCI2PCI bridge same values as PearPC - check this */ + d->config[0x00] = 0x11; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x26; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x02; // revision + d->config[0x0a] = 0x04; // class_sub = pci2pci + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x01; // header_type + + d->config[0x18] = 0x0; // primary_bus + d->config[0x19] = 0x1; // secondary_bus + d->config[0x1a] = 0x1; // subordinate_bus + d->config[0x1c] = 0x10; // io_base + d->config[0x1d] = 0x20; // io_limit + + d->config[0x20] = 0x80; // memory_base + d->config[0x21] = 0x80; + d->config[0x22] = 0x90; // memory_limit + d->config[0x23] = 0x80; + + d->config[0x24] = 0x00; // prefetchable_memory_base + d->config[0x25] = 0x84; + d->config[0x26] = 0x00; // prefetchable_memory_limit + d->config[0x27] = 0x85; #endif + return s; +} /* Uninorth PCI host (for all Mac99 and newer machines */ static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, @@ -1088,23 +1176,6 @@ static CPUReadMemoryFunc *pci_unin_read[] = { }; #endif -static void pmac_set_irq(PCIDevice *d, int irq_num, int level) -{ - openpic_t *openpic; - /* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ - openpic = d->bus->openpic; -#ifdef TARGET_PPC - if (openpic) - openpic_set_irq(openpic, d->config[PCI_INTERRUPT_LINE], level); -#endif -} - -void pci_pmac_set_openpic(PCIBus *bus, openpic_t *openpic) -{ - bus->openpic = openpic; -} - PCIBus *pci_pmac_init(void) { PCIBus *s; @@ -1114,7 +1185,7 @@ PCIBus *pci_pmac_init(void) /* Use values found on a real PowerMac */ /* Uninorth main bus */ s = pci_register_bus(); - s->set_irq = pmac_set_irq; + s->set_irq = pci_set_irq_simple; pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, pci_unin_main_config_write, s); @@ -1217,34 +1288,6 @@ PCIBus *pci_pmac_init(void) d->config[0x0E] = 0x00; // header_type d->config[0x34] = 0x00; // capabilities_pointer #endif - -#if 0 // Grackle ? - /* same values as PearPC - check this */ - d->config[0x00] = 0x11; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x04; // class_sub = pci2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x01; // header_type - - d->config[0x18] = 0x0; // primary_bus - d->config[0x19] = 0x1; // secondary_bus - d->config[0x1a] = 0x1; // subordinate_bus - d->config[0x1c] = 0x10; // io_base - d->config[0x1d] = 0x20; // io_limit - - d->config[0x20] = 0x80; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x90; // memory_limit - d->config[0x23] = 0x80; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x84; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x85; -#endif return s; } -- cgit v1.2.3 From c0e564d53b8de4ec390ad632e9a6b9d401fe9ad8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 15:17:28 +0000 Subject: use new machine API git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1451 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 17 +++++++++++++---- hw/sun4m.c | 14 ++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 06951e542..849635f6c 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -510,10 +510,10 @@ extern CPUPPCState *global_env; #define NVRAM_SIZE 0x2000 /* PowerPC PREP hardware initialisation */ -void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) +static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) { char buf[1024]; m48t59_t *nvram; @@ -650,4 +650,13 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* XXX: need an option to load a NVRAM image */ 0, graphic_width, graphic_height, graphic_depth); + + /* Special port to get debug messages from Open-Firmware */ + register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); } + +QEMUMachine prep_machine = { + "prep", + "PowerPC PREP platform", + ppc_prep_init, +}; diff --git a/hw/sun4m.c b/hw/sun4m.c index b911ba234..397ade4cb 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -203,10 +203,10 @@ uint32_t iommu_translate(uint32_t addr) } /* Sun4m hardware initialisation */ -void sun4m_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) +static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) { char buf[1024]; int ret, linux_boot; @@ -283,3 +283,9 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device, } nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth); } + +QEMUMachine sun4m_machine = { + "sun4m", + "Sun4m platform", + sun4m_init, +}; -- cgit v1.2.3 From e68b9b2b10ee8874b80595d8c2d08819999543d8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 15:21:57 +0000 Subject: added Heathrow PIC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1452 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/heathrow_pic.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 hw/heathrow_pic.c diff --git a/Makefile.target b/Makefile.target index 434af9b36..de7d7ebe4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -346,7 +346,7 @@ endif ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o -VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o +VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o endif ifeq ($(TARGET_BASE_ARCH), sparc) VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o esp.o diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c new file mode 100644 index 000000000..d65da9a9f --- /dev/null +++ b/hw/heathrow_pic.c @@ -0,0 +1,168 @@ +/* + * Heathrow PIC support (standard PowerMac PIC) + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG + +typedef struct HeathrowPIC { + uint32_t events; + uint32_t mask; + uint32_t levels; + uint32_t level_triggered; +} HeathrowPIC; + +struct HeathrowPICS { + HeathrowPIC pics[2]; +}; + +static inline int check_irq(HeathrowPIC *pic) +{ + return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask; +} + +/* update the CPU irq state */ +static void heathrow_pic_update(HeathrowPICS *s) +{ + if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) { + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } +} + +static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + HeathrowPICS *s = opaque; + HeathrowPIC *pic; + unsigned int n; + + value = bswap32(value); +#ifdef DEBUG + printf("pic_writel: %08x: %08x\n", + addr, value); +#endif + n = ((addr & 0xfff) - 0x10) >> 4; + if (n >= 2) + return; + pic = &s->pics[n]; + switch(addr & 0xf) { + case 0x04: + pic->mask = value; + heathrow_pic_update(s); + break; + case 0x08: + /* do not reset level triggered IRQs */ + value &= ~pic->level_triggered; + pic->events &= ~value; + heathrow_pic_update(s); + break; + default: + break; + } +} + +static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) +{ + HeathrowPICS *s = opaque; + HeathrowPIC *pic; + unsigned int n; + uint32_t value; + + n = ((addr & 0xfff) - 0x10) >> 4; + if (n >= 2) { + value = 0; + } else { + pic = &s->pics[n]; + switch(addr & 0xf) { + case 0x0: + value = pic->events; + break; + case 0x4: + value = pic->mask; + break; + case 0xc: + value = pic->levels; + break; + default: + value = 0; + break; + } + } +#ifdef DEBUG + printf("pic_readl: %08x: %08x\n", + addr, value); +#endif + value = bswap32(value); + return value; +} + +static CPUWriteMemoryFunc *pic_write[] = { + &pic_writel, + &pic_writel, + &pic_writel, +}; + +static CPUReadMemoryFunc *pic_read[] = { + &pic_readl, + &pic_readl, + &pic_readl, +}; + + +void heathrow_pic_set_irq(void *opaque, int num, int level) +{ + HeathrowPICS *s = opaque; + HeathrowPIC *pic; + unsigned int irq_bit; + +#if defined(DEBUG) + { + static int last_level[64]; + if (last_level[num] != level) { + printf("set_irq: num=0x%02x level=%d\n", num, level); + last_level[num] = level; + } + } +#endif + pic = &s->pics[1 - (num >> 5)]; + irq_bit = 1 << (num & 0x1f); + if (level) { + pic->events |= irq_bit & ~pic->level_triggered; + pic->levels |= irq_bit; + } else { + pic->levels &= ~irq_bit; + } + heathrow_pic_update(s); +} + +HeathrowPICS *heathrow_pic_init(int *pmem_index) +{ + HeathrowPICS *s; + + s = qemu_mallocz(sizeof(HeathrowPICS)); + s->pics[0].level_triggered = 0; + s->pics[1].level_triggered = 0x1ff00000; + *pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s); + return s; +} -- cgit v1.2.3 From cadae95f334026f5089295bdd6fa8f890e0c31a7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 15:24:23 +0000 Subject: IER behavior change - better IRQ handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1453 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cuda.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/hw/cuda.c b/hw/cuda.c index 7eea0421c..5ef2637e0 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -120,8 +120,9 @@ typedef struct CUDAState { int data_in_index; int data_out_index; + SetIRQFunc *set_irq; int irq; - openpic_t *openpic; + void *irq_opaque; uint8_t autopoll; uint8_t data_in[128]; uint8_t data_out[16]; @@ -140,9 +141,9 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti, static void cuda_update_irq(CUDAState *s) { if (s->ifr & s->ier & (SR_INT | T1_INT)) { - openpic_set_irq(s->openpic, s->irq, 1); + s->set_irq(s->irq_opaque, s->irq, 1); } else { - openpic_set_irq(s->openpic, s->irq, 0); + s->set_irq(s->irq_opaque, s->irq, 0); } } @@ -356,6 +357,7 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) cuda_update_irq(s); break; case 14: +#if 0 if (val & IER_SET) { /* set bits */ s->ier |= val & 0x7f; @@ -363,6 +365,10 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) /* reset bits */ s->ier &= ~val; } +#else + /* XXX: please explain me why the SPEC is not correct ! */ + s->ier = val; +#endif cuda_update_irq(s); break; default: @@ -545,7 +551,7 @@ static void cuda_receive_packet_from_host(CUDAState *s, #ifdef DEBUG_CUDA_PACKET { int i; - printf("cuda_receive_packet_to_host:\n"); + printf("cuda_receive_packet_from_host:\n"); for(i = 0; i < len; i++) printf(" %02x", data[i]); printf("\n"); @@ -605,19 +611,21 @@ static CPUReadMemoryFunc *cuda_read[] = { &cuda_readl, }; -int cuda_init(openpic_t *openpic, int irq) +int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq) { CUDAState *s = &cuda_state; int cuda_mem_index; - s->openpic = openpic; + s->set_irq = set_irq; + s->irq_opaque = irq_opaque; s->irq = irq; s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); s->timers[0].latch = 0x10000; set_counter(s, &s->timers[0], 0xffff); s->timers[1].latch = 0x10000; - s->ier = T1_INT | SR_INT; + // s->ier = T1_INT | SR_INT; + s->ier = 0; set_counter(s, &s->timers[1], 0xffff); s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s); -- cgit v1.2.3 From 6e20a45f53c1b6edb37ec81d59d3a9764d924b02 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 15:56:02 +0000 Subject: comma separated list of targets in --target-list (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1454 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index 6deafb237..ed4c4f745 100755 --- a/configure +++ b/configure @@ -215,6 +215,8 @@ if test -z "$target_list" ; then if [ "$linux" = "yes" ] ; then target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list" fi +else + target_list=$(echo "$target_list" | sed -e 's/,/ /g') fi if test -z "$cross_prefix" ; then -- cgit v1.2.3 From a84eaf0c9be70e25f319a47835cd60ba4e8d9c72 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 15:57:04 +0000 Subject: add missing definitions in the ppc linker script (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1455 c046a42c-6fe2-441c-8c8c-71466251a162 --- ppc.ld | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ppc.ld b/ppc.ld index d95b93cce..d0a0dcb9e 100644 --- a/ppc.ld +++ b/ppc.ld @@ -53,6 +53,16 @@ SECTIONS _etext = .; PROVIDE (etext = .); .fini : { *(.fini) } =0x47ff041f + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); .rodata : { *(.rodata) *(.gnu.linkonce.r*) } .rodata1 : { *(.rodata1) } .reginfo : { *(.reginfo) } -- cgit v1.2.3 From 3f1a88f450fecaf5955642cac074ca4b3a4c2aef Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 16:48:41 +0000 Subject: added help on -nics git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1456 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 2693db7b5..3551b330f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -203,6 +203,10 @@ Set TUN/TAP network init script [default=/etc/qemu-ifup]. This script is launched to configure the host network interface (usually tun0) corresponding to the virtual NE2000 card. +@item -nics n + +Simulate @var{n} network cards (the default is 1). + @item -macaddr addr Set the mac address of the first interface (the format is -- cgit v1.2.3 From b685369795f028535862cb3caddaf219c655db2a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 17:10:39 +0000 Subject: added HOST_LONG_BITS in configure git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1457 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 7 +++++++ cpu-defs.h | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/configure b/configure index ed4c4f745..9e4bfe03d 100755 --- a/configure +++ b/configure @@ -246,6 +246,12 @@ 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 <> $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 diff --git a/cpu-defs.h b/cpu-defs.h index 042b1e88e..c58d27139 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -29,12 +29,6 @@ #error TARGET_LONG_BITS must be defined before including this header #endif -#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) -#define HOST_LONG_BITS 64 -#else -#define HOST_LONG_BITS 32 -#endif - #ifndef TARGET_PHYS_ADDR_BITS #if TARGET_LONG_BITS >= HOST_LONG_BITS #define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS -- cgit v1.2.3 From 101c59356292c30ed5c8f7138c7680b4dc3d4811 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 5 Jun 2005 17:11:42 +0000 Subject: 64 bit fixes (initial patch by Gwenole Beauchesne) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1458 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/bootp.c | 2 +- slirp/bootp.h | 6 +++--- slirp/ip_icmp.h | 4 ++-- slirp/libslirp.h | 8 ++++++++ slirp/slirp_config.h | 3 +-- slirp/udp.c | 18 ++++++++++++------ slirp/udp.h | 1 + 7 files changed, 28 insertions(+), 14 deletions(-) diff --git a/slirp/bootp.c b/slirp/bootp.c index 56caf707e..9f0652fd6 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -238,7 +238,7 @@ static void bootp_reply(struct bootp_t *bp) void bootp_input(struct mbuf *m) { - struct bootp_t *bp = (struct bootp_t *)m->m_data; + struct bootp_t *bp = mtod(m, struct bootp_t *); if (bp->bp_op == BOOTP_REQUEST) { bootp_reply(bp); diff --git a/slirp/bootp.h b/slirp/bootp.h index d3b2baa04..e48f53f37 100644 --- a/slirp/bootp.h +++ b/slirp/bootp.h @@ -97,9 +97,9 @@ struct bootp_t { uint8_t bp_htype; uint8_t bp_hlen; uint8_t bp_hops; - unsigned long bp_xid; - unsigned short bp_secs; - unsigned short unused; + uint32_t bp_xid; + uint16_t bp_secs; + uint16_t unused; struct in_addr bp_ciaddr; struct in_addr bp_yiaddr; struct in_addr bp_siaddr; diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h index 7ddaaf8f3..8c9b5a1ba 100644 --- a/slirp/ip_icmp.h +++ b/slirp/ip_icmp.h @@ -83,8 +83,8 @@ struct icmp { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; - u_long id_mask; - char id_data[1]; + uint32_t id_mask; + char id_data[1]; } icmp_dun; #define icmp_otime icmp_dun.id_ts.its_otime #define icmp_rtime icmp_dun.id_ts.its_rtime diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 6a54eb14f..cff159e79 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -9,6 +9,10 @@ int inet_aton(const char *cp, struct in_addr *ia); #include #endif +#ifdef __cplusplus +extern "C" { +#endif + void slirp_init(void); void slirp_select_fill(int *pnfds, @@ -29,4 +33,8 @@ int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, extern const char *tftp_prefix; +#ifdef __cplusplus +} +#endif + #endif diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h index 856c31567..a0795ef6b 100644 --- a/slirp/slirp_config.h +++ b/slirp/slirp_config.h @@ -149,8 +149,7 @@ #define SIZEOF_INT 4 /* Define to sizeof(char *) */ -/* XXX: patch it */ -#define SIZEOF_CHAR_P 4 +#define SIZEOF_CHAR_P (HOST_LONG_BITS / 8) /* Define if you have random() */ #undef HAVE_RANDOM diff --git a/slirp/udp.c b/slirp/udp.c index aefa0b749..079c54353 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -420,10 +420,16 @@ struct talk_request { #endif struct cu_header { - char dest[8]; - short family; - u_short port; - u_long addr; + uint16_t d_family; // destination family + uint16_t d_port; // destination port + uint32_t d_addr; // destination address + uint16_t s_family; // source family + uint16_t s_port; // source port + uint32_t s_addr; // source address + uint32_t seqn; // sequence number + uint16_t message; // message + uint16_t data_type; // data type + uint16_t pkt_len; // packet length } *cu_head; switch(so->so_emu) { @@ -610,8 +616,8 @@ struct cu_header { if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) return; cu_head = mtod(m, struct cu_header *); - cu_head->port = addr.sin_port; - cu_head->addr = (u_long) our_addr.s_addr; + cu_head->s_port = addr.sin_port; + cu_head->s_addr = our_addr.s_addr; } return; diff --git a/slirp/udp.h b/slirp/udp.h index 195b1bfff..24c11bbf7 100644 --- a/slirp/udp.h +++ b/slirp/udp.h @@ -94,6 +94,7 @@ struct udpstat { extern struct udpstat udpstat; extern struct socket udb; +struct mbuf; void udp_init _P((void)); void udp_input _P((register struct mbuf *, int)); -- cgit v1.2.3 From c98baaac2fb3ff80412f7968694ec41c800aea22 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 13:31:24 +0000 Subject: correct __builtin_expect definition - increased code gen buffer size for x86 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1459 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exec-all.h b/exec-all.h index 4579da9f6..183df1faa 100644 --- a/exec-all.h +++ b/exec-all.h @@ -28,7 +28,7 @@ #define tostring(s) #s #endif -#if GCC_MAJOR < 3 +#if __GNUC__ < 3 #define __builtin_expect(x, n) (x) #endif @@ -131,7 +131,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, #elif defined(__powerpc__) #define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024) #else -#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024) +#define CODE_GEN_BUFFER_SIZE (16 * 1024 * 1024) #endif //#define CODE_GEN_BUFFER_SIZE (128 * 1024) -- cgit v1.2.3 From 97ccc689e614918a3b21ef58ce77ce297ace27fa Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 13:32:17 +0000 Subject: Configure check for graphical output (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1460 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/configure b/configure index 9e4bfe03d..9332aa10c 100755 --- a/configure +++ b/configure @@ -84,6 +84,7 @@ linux="no" kqemu="no" kernel_path="" cocoa="no" +check_gfx="yes" # OS specific targetos=`uname -s` @@ -186,6 +187,8 @@ for opt do ;; --enable-cocoa) cocoa="yes" ; sdl="no" ;; + --disable-gfx-check) check_gfx="no" + ;; esac done @@ -613,6 +616,14 @@ if expr $target : '.*-user' > /dev/null ; then target_user_only="yes" fi +if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ + -a "$sdl" = "no" -a "$cocoa" = "no" ; then + echo "ERROR: QEMU requires SDL or Cocoa for graphical output" + echo "To build QEMU with graphical output configure with --disable-gfx-check" + echo "Note that this will disable all output from the virtual graphics card." + exit 1; +fi + #echo "Creating $config_mak, $config_h and $target_dir/Makefile" mkdir -p $target_dir -- cgit v1.2.3 From 8979b2277d92d0acd0fd3be523a7515f86f79bec Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 14:02:54 +0000 Subject: VMDK disk image creation (Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1461 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + block-vmdk.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index bea8f8b3e..b6a142376 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,7 @@ 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) version 0.7.0: diff --git a/block-vmdk.c b/block-vmdk.c index f80bf07b7..3bbd1494f 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -315,6 +315,109 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, 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; @@ -331,6 +434,6 @@ BlockDriver bdrv_vmdk = { vmdk_read, vmdk_write, vmdk_close, - NULL, /* no create yet */ + vmdk_create, vmdk_is_allocated, }; -- cgit v1.2.3 From 3475187dd814be9b27c4632b59c1e3c76d966d63 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 14:31:34 +0000 Subject: sparc64 marge (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1462 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 9 +- cpu-exec.c | 34 +- disas.c | 3 + gdbstub.c | 47 +- hw/elf_ops.h | 218 +++++++ hw/magic-load.c | 282 +++------ hw/slavio_intctl.c | 6 +- hw/slavio_misc.c | 240 ++++++++ hw/sun4m.c | 10 + hw/sun4u.c | 254 ++++++++ linux-user/main.c | 4 + monitor.c | 7 + qemu-doc.texi | 47 +- qemu-tech.texi | 27 +- target-sparc/cpu.h | 94 ++- target-sparc/exec.h | 32 +- target-sparc/fbranch_template.h | 89 +++ target-sparc/fop_template.h | 28 - target-sparc/helper.c | 189 +++++- target-sparc/op.c | 826 ++++++++++++++++++++++---- target-sparc/op_helper.c | 432 +++++++++++++- target-sparc/op_mem.h | 59 +- target-sparc/translate.c | 1253 +++++++++++++++++++++++++++++++++------ vl.c | 35 +- vl.h | 14 + 26 files changed, 3627 insertions(+), 613 deletions(-) create mode 100644 hw/elf_ops.h create mode 100644 hw/slavio_misc.c create mode 100644 hw/sun4u.c create mode 100644 target-sparc/fbranch_template.h diff --git a/Changelog b/Changelog index b6a142376..9a41b98a8 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ version 0.7.1: - Windows 2000 install disk full hack (original idea from Vladimir N. Oleynik) - VMDK disk image creation (Filip Navara) + - SPARC64 progress (Blue Swirl) version 0.7.0: diff --git a/Makefile.target b/Makefile.target index de7d7ebe4..9cff36746 100644 --- a/Makefile.target +++ b/Makefile.target @@ -349,7 +349,11 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o endif ifeq ($(TARGET_BASE_ARCH), sparc) -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o esp.o +ifeq ($(TARGET_ARCH), sparc64) +VL_OBJS+= sun4u.o m48t08.o magic-load.o slavio_serial.o +else +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o +endif endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o @@ -442,7 +446,8 @@ op.o: op.c op_template.h endif ifeq ($(TARGET_BASE_ARCH), sparc) -op.o: op.c op_template.h op_mem.h +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_ARCH), ppc) diff --git a/cpu-exec.c b/cpu-exec.c index d414e3343..8c5557739 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -47,6 +47,9 @@ void cpu_loop_exit(void) longjmp(env->jmp_env, 1); } #endif +#ifndef TARGET_SPARC +#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 @@ -74,8 +77,12 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) int cpu_exec(CPUState *env1) { - int saved_T0, saved_T1, saved_T2; + 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 @@ -100,6 +107,11 @@ int cpu_exec(CPUState *env1) #ifdef reg_EDI int saved_EDI; #endif +#elif defined(TARGET_SPARC) +#if defined(reg_REGWPTR) + uint32_t *saved_regwptr; +#endif +#endif #ifdef __sparc__ int saved_i7, tmp_T0; #endif @@ -115,7 +127,9 @@ int cpu_exec(CPUState *env1) env = env1; saved_T0 = T0; saved_T1 = T1; +#if defined(reg_T2) saved_T2 = T2; +#endif #ifdef __sparc__ /* we also save i7 because longjmp may not restore it */ asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); @@ -164,6 +178,9 @@ int cpu_exec(CPUState *env1) env->cpsr = psr & ~CACHED_CPSR_BITS; } #elif defined(TARGET_SPARC) +#if defined(reg_REGWPTR) + saved_regwptr = REGWPTR; +#endif #elif defined(TARGET_PPC) #else #error unsupported target CPU @@ -354,7 +371,9 @@ int cpu_exec(CPUState *env1) cpu_dump_state(env, logfile, fprintf, 0); env->cpsr &= ~CACHED_CPSR_BITS; #elif defined(TARGET_SPARC) - cpu_dump_state (env, logfile, fprintf, 0); + 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); #else @@ -376,7 +395,11 @@ int cpu_exec(CPUState *env1) cs_base = 0; pc = env->regs[15]; #elif defined(TARGET_SPARC) - flags = 0; +#ifdef TARGET_SPARC64 + flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); +#else + flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); +#endif cs_base = env->npc; pc = env->pc; #elif defined(TARGET_PPC) @@ -657,6 +680,9 @@ int cpu_exec(CPUState *env1) env->cpsr = compute_cpsr(); /* XXX: Save/restore host fpu exception state?. */ #elif defined(TARGET_SPARC) +#if defined(reg_REGWPTR) + REGWPTR = saved_regwptr; +#endif #elif defined(TARGET_PPC) #else #error unsupported target CPU @@ -666,7 +692,9 @@ int cpu_exec(CPUState *env1) #endif T0 = saved_T0; T1 = saved_T1; +#if defined(reg_T2) T2 = saved_T2; +#endif env = saved_env; return ret; } diff --git a/disas.c b/disas.c index ded2c6d72..c54e5d91c 100644 --- a/disas.c +++ b/disas.c @@ -155,6 +155,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) print_insn = print_insn_arm; #elif defined(TARGET_SPARC) print_insn = print_insn_sparc; +#ifdef TARGET_SPARC64 + disasm_info.mach = bfd_mach_sparc_v9b; +#endif #elif defined(TARGET_PPC) if (cpu_single_env->msr[MSR_LE]) disasm_info.endian = BFD_ENDIAN_LITTLE; diff --git a/gdbstub.c b/gdbstub.c index 22c38e5e3..5586df29f 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1,7 +1,7 @@ /* * gdb server stub * - * Copyright (c) 2003 Fabrice Bellard + * 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 @@ -293,7 +293,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) #elif defined (TARGET_SPARC) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { - uint32_t *registers = (uint32_t *)mem_buf, tmp; + target_ulong *registers = (target_ulong *)mem_buf; int i; /* fill in g0..g7 */ @@ -308,10 +308,15 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) for (i = 0; i < 32; i++) { registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i])); } +#ifndef TARGET_SPARC64 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ registers[64] = tswapl(env->y); - tmp = GET_PSR(env); - registers[65] = tswapl(tmp); + { + target_ulong tmp; + + tmp = GET_PSR(env); + registers[65] = tswapl(tmp); + } registers[66] = tswapl(env->wim); registers[67] = tswapl(env->tbr); registers[68] = tswapl(env->pc); @@ -319,13 +324,24 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) registers[70] = tswapl(env->fsr); registers[71] = 0; /* csr */ registers[72] = 0; - - return 73 * 4; + return 73 * sizeof(target_ulong); +#else + for (i = 0; i < 32; i += 2) { + registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i])); + } + registers[81] = tswapl(env->pc); + registers[82] = tswapl(env->npc); + registers[83] = tswapl(env->tstate[env->tl]); + registers[84] = tswapl(env->fsr); + registers[85] = tswapl(env->fprs); + registers[86] = tswapl(env->y); + return 87 * sizeof(target_ulong); +#endif } static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { - uint32_t *registers = (uint32_t *)mem_buf; + target_ulong *registers = (target_ulong *)mem_buf; int i; /* fill in g0..g7 */ @@ -334,12 +350,13 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* fill in register window */ for(i = 0; i < 24; i++) { - env->regwptr[i] = tswapl(registers[i]); + env->regwptr[i] = tswapl(registers[i + 8]); } /* fill in fprs */ for (i = 0; i < 32; i++) { *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]); } +#ifndef TARGET_SPARC64 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ env->y = tswapl(registers[64]); PUT_PSR(env, tswapl(registers[65])); @@ -348,6 +365,20 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->pc = tswapl(registers[68]); env->npc = tswapl(registers[69]); env->fsr = tswapl(registers[70]); +#else + for (i = 0; i < 32; i += 2) { + uint64_t tmp; + tmp = tswapl(registers[i/2 + 64]) << 32; + tmp |= tswapl(registers[i/2 + 64 + 1]); + *((uint64_t *)&env->fpr[i]) = tmp; + } + env->pc = tswapl(registers[81]); + env->npc = tswapl(registers[82]); + env->tstate[env->tl] = tswapl(registers[83]); + env->fsr = tswapl(registers[84]); + env->fprs = tswapl(registers[85]); + env->y = tswapl(registers[86]); +#endif } #elif defined (TARGET_ARM) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) diff --git a/hw/elf_ops.h b/hw/elf_ops.h new file mode 100644 index 000000000..1f3232d47 --- /dev/null +++ b/hw/elf_ops.h @@ -0,0 +1,218 @@ +#ifdef BSWAP_NEEDED +static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr) +{ + bswap16s(&ehdr->e_type); /* Object file type */ + bswap16s(&ehdr->e_machine); /* Architecture */ + bswap32s(&ehdr->e_version); /* Object file version */ + bswapSZs(&ehdr->e_entry); /* Entry point virtual address */ + bswapSZs(&ehdr->e_phoff); /* Program header table file offset */ + bswapSZs(&ehdr->e_shoff); /* Section header table file offset */ + bswap32s(&ehdr->e_flags); /* Processor-specific flags */ + bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ + bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ +} + +static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr) +{ + bswap32s(&phdr->p_type); /* Segment type */ + bswapSZs(&phdr->p_offset); /* Segment file offset */ + bswapSZs(&phdr->p_vaddr); /* Segment virtual address */ + bswapSZs(&phdr->p_paddr); /* Segment physical address */ + bswapSZs(&phdr->p_filesz); /* Segment size in file */ + bswapSZs(&phdr->p_memsz); /* Segment size in memory */ + bswap32s(&phdr->p_flags); /* Segment flags */ + bswapSZs(&phdr->p_align); /* Segment alignment */ +} + +static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr) +{ + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswapSZs(&shdr->sh_flags); + bswapSZs(&shdr->sh_addr); + bswapSZs(&shdr->sh_offset); + bswapSZs(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswapSZs(&shdr->sh_addralign); + bswapSZs(&shdr->sh_entsize); +} + +static void glue(bswap_sym, SZ)(struct elf_sym *sym) +{ + bswap32s(&sym->st_name); + bswapSZs(&sym->st_value); + bswapSZs(&sym->st_size); + bswap16s(&sym->st_shndx); +} +#endif + +static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, elf_word type) +{ + int i, retval; + + retval = lseek(fd, ehdr->e_phoff, SEEK_SET); + if (retval < 0) + return -1; + + for (i = 0; i < ehdr->e_phnum; i++) { + retval = read(fd, phdr, sizeof(*phdr)); + if (retval < 0) + return -1; + glue(bswap_phdr, SZ)(phdr); + if (phdr->p_type == type) + return 0; + } + return -1; +} + +static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type) +{ + int i, retval; + + retval = lseek(fd, ehdr->e_shoff, SEEK_SET); + if (retval < 0) + return NULL; + + for (i = 0; i < ehdr->e_shnum; i++) { + retval = read(fd, shdr, sizeof(*shdr)); + if (retval < 0) + return NULL; + glue(bswap_shdr, SZ)(shdr); + if (shdr->sh_type == type) + return qemu_malloc(shdr->sh_size); + } + return NULL; +} + +static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) +{ + int retval; + + retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); + if (retval < 0) + return NULL; + + retval = read(fd, shdr, sizeof(*shdr)); + if (retval < 0) + return NULL; + glue(bswap_shdr, SZ)(shdr); + if (shdr->sh_type == SHT_STRTAB) + return qemu_malloc(shdr->sh_size);; + return NULL; +} + +static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst, elf_word entry) +{ + int retval; + retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); + if (retval < 0) + return -1; + return read(fd, dst, phdr->p_filesz); +} + +static int glue(read_section, SZ)(int fd, struct elf_shdr *s, void *dst) +{ + int retval; + + retval = lseek(fd, s->sh_offset, SEEK_SET); + if (retval < 0) + return -1; + retval = read(fd, dst, s->sh_size); + if (retval < 0) + return -1; + return 0; +} + +static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type) +{ + void *dst; + + dst = glue(find_shdr, SZ)(ehdr, fd, shdr, type); + if (!dst) + goto error; + + if (glue(read_section, SZ)(fd, shdr, dst)) + goto error; + return dst; + error: + qemu_free(dst); + return NULL; +} + +static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) +{ + void *dst; + + dst = glue(find_strtab, SZ)(ehdr, fd, shdr, symtab); + if (!dst) + goto error; + + if (glue(read_section, SZ)(fd, shdr, dst)) + goto error; + return dst; + error: + qemu_free(dst); + return NULL; +} + +static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd) +{ + struct elf_shdr symtab, strtab; + struct elf_sym *syms; +#if (SZ == 64) + struct elf32_sym *syms32; +#endif + struct syminfo *s; + int nsyms, i; + char *str; + + /* Symbol table */ + syms = glue(process_section, SZ)(ehdr, fd, &symtab, SHT_SYMTAB); + if (!syms) + return; + + nsyms = symtab.sh_size / sizeof(struct elf_sym); +#if (SZ == 64) + syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym)); +#endif + for (i = 0; i < nsyms; i++) { + glue(bswap_sym, SZ)(&syms[i]); +#if (SZ == 64) + syms32[i].st_name = syms[i].st_name; + syms32[i].st_info = syms[i].st_info; + syms32[i].st_other = syms[i].st_other; + syms32[i].st_shndx = syms[i].st_shndx; + syms32[i].st_value = syms[i].st_value & 0xffffffff; + syms32[i].st_size = syms[i].st_size & 0xffffffff; +#endif + } + /* String table */ + str = glue(process_strtab, SZ)(ehdr, fd, &strtab, &symtab); + if (!str) + goto error_freesyms; + + /* Commit */ + s = qemu_mallocz(sizeof(*s)); +#if (SZ == 64) + s->disas_symtab = syms32; + qemu_free(syms); +#else + s->disas_symtab = syms; +#endif + s->disas_num_syms = nsyms; + s->disas_strtab = str; + s->next = syminfos; + syminfos = s; + return; + error_freesyms: +#if (SZ == 64) + qemu_free(syms32); +#endif + qemu_free(syms); + return; +} diff --git a/hw/magic-load.c b/hw/magic-load.c index 713343a75..63942c647 100644 --- a/hw/magic-load.c +++ b/hw/magic-load.c @@ -56,213 +56,49 @@ static void bswap_ahdr(struct exec *e) #include "elf.h" -#ifdef BSWAP_NEEDED -static void bswap_ehdr(Elf32_Ehdr *ehdr) -{ - bswap16s(&ehdr->e_type); /* Object file type */ - bswap16s(&ehdr->e_machine); /* Architecture */ - bswap32s(&ehdr->e_version); /* Object file version */ - bswap32s(&ehdr->e_entry); /* Entry point virtual address */ - bswap32s(&ehdr->e_phoff); /* Program header table file offset */ - bswap32s(&ehdr->e_shoff); /* Section header table file offset */ - bswap32s(&ehdr->e_flags); /* Processor-specific flags */ - bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ - bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ - bswap16s(&ehdr->e_phnum); /* Program header table entry count */ - bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ - bswap16s(&ehdr->e_shnum); /* Section header table entry count */ - bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ -} - -static void bswap_phdr(Elf32_Phdr *phdr) -{ - bswap32s(&phdr->p_type); /* Segment type */ - bswap32s(&phdr->p_offset); /* Segment file offset */ - bswap32s(&phdr->p_vaddr); /* Segment virtual address */ - bswap32s(&phdr->p_paddr); /* Segment physical address */ - bswap32s(&phdr->p_filesz); /* Segment size in file */ - bswap32s(&phdr->p_memsz); /* Segment size in memory */ - bswap32s(&phdr->p_flags); /* Segment flags */ - bswap32s(&phdr->p_align); /* Segment alignment */ -} - -static void bswap_shdr(Elf32_Shdr *shdr) -{ - bswap32s(&shdr->sh_name); - bswap32s(&shdr->sh_type); - bswap32s(&shdr->sh_flags); - bswap32s(&shdr->sh_addr); - bswap32s(&shdr->sh_offset); - bswap32s(&shdr->sh_size); - bswap32s(&shdr->sh_link); - bswap32s(&shdr->sh_info); - bswap32s(&shdr->sh_addralign); - bswap32s(&shdr->sh_entsize); -} - -static void bswap_sym(Elf32_Sym *sym) -{ - bswap32s(&sym->st_name); - bswap32s(&sym->st_value); - bswap32s(&sym->st_size); - bswap16s(&sym->st_shndx); -} -#else -#define bswap_ehdr(e) do { } while (0) -#define bswap_phdr(e) do { } while (0) -#define bswap_shdr(e) do { } while (0) -#define bswap_sym(e) do { } while (0) +#ifndef BSWAP_NEEDED +#define bswap_ehdr32(e) do { } while (0) +#define bswap_phdr32(e) do { } while (0) +#define bswap_shdr32(e) do { } while (0) +#define bswap_sym32(e) do { } while (0) +#ifdef TARGET_SPARC64 +#define bswap_ehdr64(e) do { } while (0) +#define bswap_phdr64(e) do { } while (0) +#define bswap_shdr64(e) do { } while (0) +#define bswap_sym64(e) do { } while (0) +#endif #endif -static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type) -{ - int i, retval; - - retval = lseek(fd, ehdr->e_phoff, SEEK_SET); - if (retval < 0) - return -1; - - for (i = 0; i < ehdr->e_phnum; i++) { - retval = read(fd, phdr, sizeof(*phdr)); - if (retval < 0) - return -1; - bswap_phdr(phdr); - if (phdr->p_type == type) - return 0; - } - return -1; -} - -static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type) -{ - int i, retval; - - retval = lseek(fd, ehdr->e_shoff, SEEK_SET); - if (retval < 0) - return NULL; - - for (i = 0; i < ehdr->e_shnum; i++) { - retval = read(fd, shdr, sizeof(*shdr)); - if (retval < 0) - return NULL; - bswap_shdr(shdr); - if (shdr->sh_type == type) - return qemu_malloc(shdr->sh_size); - } - return NULL; -} - -static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) -{ - int retval; - - retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); - if (retval < 0) - return NULL; - - retval = read(fd, shdr, sizeof(*shdr)); - if (retval < 0) - return NULL; - bswap_shdr(shdr); - if (shdr->sh_type == SHT_STRTAB) - return qemu_malloc(shdr->sh_size);; - return NULL; -} - -static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry) -{ - int retval; - retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); - if (retval < 0) - return -1; - return read(fd, dst, phdr->p_filesz); -} - -static int read_section(int fd, struct elf_shdr *s, void *dst) -{ - int retval; - - retval = lseek(fd, s->sh_offset, SEEK_SET); - if (retval < 0) - return -1; - retval = read(fd, dst, s->sh_size); - if (retval < 0) - return -1; - return 0; -} - -static void *process_section(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type) -{ - void *dst; - - dst = find_shdr(ehdr, fd, shdr, type); - if (!dst) - goto error; - - if (read_section(fd, shdr, dst)) - goto error; - return dst; - error: - qemu_free(dst); - return NULL; -} - -static void *process_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) -{ - void *dst; - - dst = find_strtab(ehdr, fd, shdr, symtab); - if (!dst) - goto error; - - if (read_section(fd, shdr, dst)) - goto error; - return dst; - error: - qemu_free(dst); - return NULL; -} - -static void load_symbols(struct elfhdr *ehdr, int fd) -{ - struct elf_shdr symtab, strtab; - struct elf_sym *syms; - struct syminfo *s; - int nsyms, i; - char *str; - - /* Symbol table */ - syms = process_section(ehdr, fd, &symtab, SHT_SYMTAB); - if (!syms) - return; - - nsyms = symtab.sh_size / sizeof(struct elf_sym); - for (i = 0; i < nsyms; i++) - bswap_sym(&syms[i]); - - /* String table */ - str = process_strtab(ehdr, fd, &strtab, &symtab); - if (!str) - goto error_freesyms; - - /* Commit */ - s = qemu_mallocz(sizeof(*s)); - s->disas_symtab = syms; - s->disas_num_syms = nsyms; - s->disas_strtab = str; - s->next = syminfos; - syminfos = s; - return; - error_freesyms: - qemu_free(syms); - return; -} +#define SZ 32 +#define elf_word uint32_t +#define bswapSZs bswap32s +#include "elf_ops.h" + +#ifdef TARGET_SPARC64 +#undef elfhdr +#undef elf_phdr +#undef elf_shdr +#undef elf_sym +#undef elf_note +#undef elf_word +#undef bswapSZs +#undef SZ +#define elfhdr elf64_hdr +#define elf_phdr elf64_phdr +#define elf_note elf64_note +#define elf_shdr elf64_shdr +#define elf_sym elf64_sym +#define elf_word uint64_t +#define bswapSZs bswap64s +#define SZ 64 +#include "elf_ops.h" +#endif int load_elf(const char *filename, uint8_t *addr) { - struct elfhdr ehdr; - struct elf_phdr phdr; + struct elf32_hdr ehdr; int retval, fd; + Elf32_Half machine; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) @@ -272,21 +108,43 @@ int load_elf(const char *filename, uint8_t *addr) if (retval < 0) goto error; - bswap_ehdr(&ehdr); - if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' - || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' - || (ehdr.e_machine != EM_SPARC - && ehdr.e_machine != EM_SPARC32PLUS)) + || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F') goto error; + machine = tswap16(ehdr.e_machine); + if (machine == EM_SPARC || machine == EM_SPARC32PLUS) { + struct elf32_phdr phdr; - if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) - goto error; - retval = read_program(fd, &phdr, addr, ehdr.e_entry); - if (retval < 0) - goto error; + bswap_ehdr32(&ehdr); - load_symbols(&ehdr, fd); + if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD)) + goto error; + retval = read_program32(fd, &phdr, addr, ehdr.e_entry); + if (retval < 0) + goto error; + load_symbols32(&ehdr, fd); + } +#ifdef TARGET_SPARC64 + else if (machine == EM_SPARCV9) { + struct elf64_hdr ehdr64; + struct elf64_phdr phdr; + + lseek(fd, 0, SEEK_SET); + + retval = read(fd, &ehdr64, sizeof(ehdr64)); + if (retval < 0) + goto error; + + bswap_ehdr64(&ehdr64); + + if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD)) + goto error; + retval = read_program64(fd, &phdr, addr, ehdr64.e_entry); + if (retval < 0) + goto error; + load_symbols64(&ehdr64, fd); + } +#endif close(fd); return retval; diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 9c8ddd0d0..8a5db5c3c 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -144,14 +144,14 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin switch (saddr) { case 2: // clear (enable) // Force clear unused bits - val &= ~0x7fb2007f; + val &= ~0x4fb2007f; s->intregm_disabled &= ~val; DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); slavio_check_interrupts(s); break; case 3: // set (disable, clear pending) // Force clear unused bits - val &= ~0x7fb2007f; + val &= ~0x4fb2007f; s->intregm_disabled |= val; s->intregm_pending &= ~val; DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); @@ -208,7 +208,7 @@ void slavio_irq_info(void *opaque) static const uint32_t intbit_to_level[32] = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, - 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }; static void slavio_check_interrupts(void *opaque) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c new file mode 100644 index 000000000..597a0cb12 --- /dev/null +++ b/hw/slavio_misc.c @@ -0,0 +1,240 @@ +/* + * QEMU Sparc SLAVIO aux io port emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +/* debug misc */ +//#define DEBUG_MISC + +/* + * This is the auxio port, chip control and system control part of + * chip STP2001 (Slave I/O), also produced as NCR89C105. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt + * + * This also includes the PMC CPU idle controller. + */ + +#ifdef DEBUG_MISC +#define MISC_DPRINTF(fmt, args...) \ +do { printf("MISC: " fmt , ##args); } while (0) +#else +#define MISC_DPRINTF(fmt, args...) +#endif + +typedef struct MiscState { + int irq; + uint8_t config; + uint8_t aux1, aux2; + uint8_t diag, mctrl; +} MiscState; + +#define MISC_MAXADDR 1 + +static void slavio_misc_update_irq(void *opaque) +{ + MiscState *s = opaque; + + if ((s->aux2 & 0x4) && (s->config & 0x8)) { + pic_set_irq(s->irq, 1); + } else { + pic_set_irq(s->irq, 0); + } +} + +static void slavio_misc_reset(void *opaque) +{ + MiscState *s = opaque; + + // Diagnostic register not cleared in reset + s->config = s->aux1 = s->aux2 = s->mctrl = 0; +} + +void slavio_set_power_fail(void *opaque, int power_failing) +{ + MiscState *s = opaque; + + MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config); + if (power_failing && (s->config & 0x8)) { + s->aux2 |= 0x4; + } else { + s->aux2 &= ~0x4; + } + slavio_misc_update_irq(s); +} + +static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + MiscState *s = opaque; + + switch (addr & 0xfff0000) { + case 0x1800000: + MISC_DPRINTF("Write config %2.2x\n", val & 0xff); + s->config = val & 0xff; + slavio_misc_update_irq(s); + break; + case 0x1900000: + MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); + s->aux1 = val & 0xff; + break; + case 0x1910000: + val &= 0x3; + MISC_DPRINTF("Write aux2 %2.2x\n", val); + val |= s->aux2 & 0x4; + if (val & 0x2) // Clear Power Fail int + val &= 0x1; + s->aux2 = val; + if (val & 1) + qemu_system_shutdown_request(); + slavio_misc_update_irq(s); + break; + case 0x1a00000: + MISC_DPRINTF("Write diag %2.2x\n", val & 0xff); + s->diag = val & 0xff; + break; + case 0x1b00000: + MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); + s->mctrl = val & 0xff; + break; + case 0x1f00000: + MISC_DPRINTF("Write system control %2.2x\n", val & 0xff); + if (val & 1) + qemu_system_reset_request(); + break; + case 0xa000000: + MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); +#if 0 + // XXX: halting CPU does not work + raise_exception(EXCP_HLT); + cpu_loop_exit(); +#endif + break; + } +} + +static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr) +{ + MiscState *s = opaque; + uint32_t ret = 0; + + switch (addr & 0xfff0000) { + case 0x1800000: + ret = s->config; + MISC_DPRINTF("Read config %2.2x\n", ret); + break; + case 0x1900000: + ret = s->aux1; + MISC_DPRINTF("Read aux1 %2.2x\n", ret); + break; + case 0x1910000: + ret = s->aux2; + MISC_DPRINTF("Read aux2 %2.2x\n", ret); + break; + case 0x1a00000: + ret = s->diag; + MISC_DPRINTF("Read diag %2.2x\n", ret); + break; + case 0x1b00000: + ret = s->mctrl; + MISC_DPRINTF("Read modem control %2.2x\n", ret); + break; + case 0x1f00000: + MISC_DPRINTF("Read system control %2.2x\n", ret); + break; + case 0xa000000: + MISC_DPRINTF("Read power management %2.2x\n", ret); + break; + } + return ret; +} + +static CPUReadMemoryFunc *slavio_misc_mem_read[3] = { + slavio_misc_mem_readb, + slavio_misc_mem_readb, + slavio_misc_mem_readb, +}; + +static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = { + slavio_misc_mem_writeb, + slavio_misc_mem_writeb, + slavio_misc_mem_writeb, +}; + +static void slavio_misc_save(QEMUFile *f, void *opaque) +{ + MiscState *s = opaque; + + qemu_put_be32s(f, &s->irq); + qemu_put_8s(f, &s->config); + qemu_put_8s(f, &s->aux1); + qemu_put_8s(f, &s->aux2); + qemu_put_8s(f, &s->diag); + qemu_put_8s(f, &s->mctrl); +} + +static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) +{ + MiscState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->irq); + qemu_get_8s(f, &s->config); + qemu_get_8s(f, &s->aux1); + qemu_get_8s(f, &s->aux2); + qemu_get_8s(f, &s->diag); + qemu_get_8s(f, &s->mctrl); + return 0; +} + +void *slavio_misc_init(uint32_t base, int irq) +{ + int slavio_misc_io_memory; + MiscState *s; + + s = qemu_mallocz(sizeof(MiscState)); + if (!s) + return NULL; + + slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s); + // Slavio control + cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory); + // AUX 1 + cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory); + // AUX 2 + cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory); + // Diagnostics + cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory); + // Modem control + cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory); + // System control + cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory); + // Power management + cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory); + + s->irq = irq; + + register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s); + qemu_register_reset(slavio_misc_reset, s); + slavio_misc_reset(s); + return s; +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 397ade4cb..56b9069e5 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -37,6 +37,7 @@ // bits #define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ #define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */ +#define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */ #define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */ #define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ #define PHYS_JJ_ESP_IRQ 18 @@ -55,6 +56,7 @@ #define PHYS_JJ_SER_IRQ 15 #define PHYS_JJ_FDC 0x71400000 /* Floppy */ #define PHYS_JJ_FLOPPY_IRQ 22 +#define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */ /* TSC handling */ @@ -202,6 +204,13 @@ uint32_t iommu_translate(uint32_t addr) return iommu_translate_local(iommu, addr); } +static void *slavio_misc; + +void qemu_system_powerdown(void) +{ + slavio_set_power_fail(slavio_misc, 1); +} + /* Sun4m hardware initialisation */ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -230,6 +239,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA); + slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); prom_offset = ram_size + vram_size; diff --git a/hw/sun4u.c b/hw/sun4u.c new file mode 100644 index 000000000..af1546421 --- /dev/null +++ b/hw/sun4u.c @@ -0,0 +1,254 @@ +/* + * QEMU Sun4u System Emulator + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "m48t08.h" + +#define KERNEL_LOAD_ADDR 0x00004000 +#define CMDLINE_ADDR 0x007ff000 +#define INITRD_LOAD_ADDR 0x00800000 +#define PROM_ADDR 0xffd00000 +#define PROM_FILENAMEB "proll-sparc64.bin" +#define PROM_FILENAMEE "proll-sparc64.elf" +#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ +#define PHYS_JJ_IDPROM_OFF 0x1FD8 +#define PHYS_JJ_EEPROM_SIZE 0x2000 +// IRQs are not PIL ones, but master interrupt controller register +// bits +#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */ +#define PHYS_JJ_MS_KBD_IRQ 14 +#define PHYS_JJ_SER 0x71100000 /* Serial */ +#define PHYS_JJ_SER_IRQ 15 + +/* TSC handling */ + +uint64_t cpu_get_tsc() +{ + return qemu_get_clock(vm_clock); +} + +int DMA_get_channel_mode (int nchan) +{ + return 0; +} +int DMA_read_memory (int nchan, void *buf, int pos, int size) +{ + return 0; +} +int DMA_write_memory (int nchan, void *buf, int pos, int size) +{ + return 0; +} +void DMA_hold_DREQ (int nchan) {} +void DMA_release_DREQ (int nchan) {} +void DMA_schedule(int nchan) {} +void DMA_run (void) {} +void DMA_init (int high_page_enable) {} +void DMA_register_channel (int nchan, + DMA_transfer_handler transfer_handler, + void *opaque) +{ +} + +static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value) +{ + m48t08_write(nvram, addr++, (value >> 8) & 0xff); + m48t08_write(nvram, addr++, value & 0xff); +} + +static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value) +{ + m48t08_write(nvram, addr++, value >> 24); + m48t08_write(nvram, addr++, (value >> 16) & 0xff); + m48t08_write(nvram, addr++, (value >> 8) & 0xff); + m48t08_write(nvram, addr++, value & 0xff); +} + +static void nvram_set_string (m48t08_t *nvram, uint32_t addr, + const unsigned char *str, uint32_t max) +{ + unsigned int i; + + for (i = 0; i < max && str[i] != '\0'; i++) { + m48t08_write(nvram, addr + i, str[i]); + } + m48t08_write(nvram, addr + max - 1, '\0'); +} + +static m48t08_t *nvram; + +extern int nographic; + +static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline, + int boot_device, uint32_t RAM_size, + uint32_t kernel_size, + int width, int height, int depth) +{ + unsigned char tmp = 0; + int i, j; + + // Try to match PPC NVRAM + nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); + nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */ + // NVRAM_size, arch not applicable + m48t08_write(nvram, 0x2F, nographic & 0xff); + nvram_set_lword(nvram, 0x30, RAM_size); + m48t08_write(nvram, 0x34, boot_device & 0xff); + nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR); + nvram_set_lword(nvram, 0x3C, kernel_size); + if (cmdline) { + strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); + nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); + nvram_set_lword(nvram, 0x44, strlen(cmdline)); + } + // initrd_image, initrd_size passed differently + nvram_set_word(nvram, 0x54, width); + nvram_set_word(nvram, 0x56, height); + nvram_set_word(nvram, 0x58, depth); + + // Sun4m specific use + i = 0x1fd8; + m48t08_write(nvram, i++, 0x01); + m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */ + j = 0; + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i++, macaddr[j++]); + m48t08_write(nvram, i, macaddr[j]); + + /* Calculate checksum */ + for (i = 0x1fd8; i < 0x1fe7; i++) { + tmp ^= m48t08_read(nvram, i); + } + m48t08_write(nvram, 0x1fe7, tmp); +} + +void pic_info() +{ +} + +void irq_info() +{ +} + +void pic_set_irq(int irq, int level) +{ +} + +void vga_update_display() +{ +} + +void vga_invalidate_display() +{ +} + +void vga_screen_dump(const char *filename) +{ +} + +void qemu_system_powerdown(void) +{ +} + +/* Sun4u hardware initialisation */ +static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + char buf[1024]; + int ret, linux_boot; + unsigned int i; + long vram_size = 0x100000, prom_offset, initrd_size, kernel_size; + + linux_boot = (kernel_filename != NULL); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, 0); + + nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); + // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device + // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device + slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); + + prom_offset = ram_size + vram_size; + + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + ret = load_elf(buf, phys_ram_base + prom_offset); + if (ret < 0) { + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); + ret = load_image(buf, phys_ram_base + prom_offset); + } + if (ret < 0) { + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); + } + cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, + prom_offset | IO_MEM_ROM); + + kernel_size = 0; + if (linux_boot) { + kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) + kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) + kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + if (initrd_size > 0) { + for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { + if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) + == 0x48647253) { // HdrS + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); + break; + } + } + } + } + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth); +} + +QEMUMachine sun4u_machine = { + "sun4u", + "Sun4u platform", + sun4u_init, +}; diff --git a/linux-user/main.c b/linux-user/main.c index d0f662c07..5601a23e6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -552,6 +552,7 @@ void cpu_loop (CPUSPARCState *env) env->pc = env->npc; env->npc = env->npc + 4; break; +#ifndef TARGET_SPARC64 case TT_WIN_OVF: /* window overflow */ save_window(env); break; @@ -569,6 +570,9 @@ void cpu_loop (CPUSPARCState *env) queue_signal(info.si_signo, &info); } break; +#else + // XXX +#endif case 0x100: // XXX, why do we get these? break; case EXCP_DEBUG: diff --git a/monitor.c b/monitor.c index 285508e06..d0b011004 100644 --- a/monitor.c +++ b/monitor.c @@ -767,6 +767,11 @@ static void do_system_reset(void) qemu_system_reset_request(); } +static void do_system_powerdown(void) +{ + qemu_system_powerdown_request(); +} + #if defined(TARGET_I386) static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask) { @@ -922,6 +927,8 @@ static term_cmd_t term_cmds[] = { "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, { "system_reset", "", do_system_reset, "", "reset the system" }, + { "system_powerdown", "", do_system_powerdown, + "", "send system power down event" }, { "sum", "ii", do_sum, "addr size", "compute the checksum of a memory region" }, { NULL, NULL, }, diff --git a/qemu-doc.texi b/qemu-doc.texi index 3551b330f..211b6687a 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -42,10 +42,11 @@ For system emulation, the following hardware targets are supported: @item PC (x86 processor) @item PREP (PowerPC processor) @item PowerMac (PowerPC processor, in progress) -@item Sun4m (Sparc processor, in progress) +@item Sun4m (32-bit Sparc processor) +@item Sun4u (64-bit Sparc processor, in progress) @end itemize -For user emulation, x86, PowerPC, ARM, and SPARC CPUs are supported. +For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported. @chapter Installation @@ -999,15 +1000,15 @@ Set the initial VGA graphic mode. The default is 800x600x15. More information is available at @url{http://jocelyn.mayer.free.fr/qemu-ppc/}. -@chapter Sparc System emulator invocation +@chapter Sparc32 System emulator invocation Use the executable @file{qemu-system-sparc} to simulate a JavaStation -(sun4m architecture). The emulation is far from complete. +(sun4m architecture). The emulation is somewhat complete. QEMU emulates the following sun4m peripherals: @itemize @minus -@item +@item IOMMU @item TCX Frame buffer @@ -1016,14 +1017,42 @@ Lance (Am7990) Ethernet @item Non Volatile RAM M48T08 @item -Slave I/O: timers, interrupt controllers, Zilog serial ports +Slave I/O: timers, interrupt controllers, Zilog serial ports, keyboard +and power/reset logic +@item +ESP SCSI controller with hard disk and CD-ROM support +@item +Floppy drive @end itemize +The number of peripherals is fixed in the architecture. + QEMU uses the Proll, a PROM replacement available at -@url{http://people.redhat.com/zaitcev/linux/}. +@url{http://people.redhat.com/zaitcev/linux/}. The required +QEMU-specific patches are included with the sources. + +A sample Linux 2.6 series kernel and ram disk image are available on +the QEMU web site. Please note that currently neither Linux 2.4 +series, NetBSD, nor OpenBSD kernels work. + +@c man begin OPTIONS + +The following options are specific to the Sparc emulation: + +@table @option + +@item -g WxH + +Set the initial TCX graphic mode. The default is 1024x768. + +@end table + +@c man end + +@chapter Sparc64 System emulator invocation -A sample Linux kernel and ram disk image are available on the QEMU web -site. +Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine. +The emulator is not usable for anything yet. @chapter QEMU User space emulator invocation diff --git a/qemu-tech.texi b/qemu-tech.texi index c86094b7c..379cbad55 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -138,9 +138,32 @@ FPU and MMU. @itemize @item Somewhat complete SPARC V8 emulation, including privileged -instructions, FPU and MMU. +instructions, FPU and MMU. SPARC V9 emulation includes most privileged +instructions, FPU and I/D MMU, but misses VIS instructions. -@item Can run some SPARC Linux binaries. +@item Can run some 32-bit SPARC Linux binaries. + +@end itemize + +Current QEMU limitations: + +@itemize + +@item Tagged add/subtract instructions are not supported, but they are +probably not used. + +@item IPC syscalls are missing. + +@item 128-bit floating point operations are not supported, though none of the +real CPUs implement them either. FCMPE[SD] are not correctly +implemented. Floating point exception support is untested. + +@item Alignment is not enforced at all. + +@item Atomic instructions are not correctly implemented. + +@item Sparc64 emulators are not usable for anything yet. +Address space is limited to first 4 gigabytes. @end itemize diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index b556e23e4..2eb900dfe 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -6,12 +6,11 @@ #if !defined(TARGET_SPARC64) #define TARGET_LONG_BITS 32 #define TARGET_FPREGS 32 -#define TARGET_FPREG_T float #else #define TARGET_LONG_BITS 64 #define TARGET_FPREGS 64 -#define TARGET_FPREG_T double #endif +#define TARGET_FPREG_T float #include "cpu-defs.h" @@ -22,6 +21,7 @@ /*#define EXCP_INTERRUPT 0x100*/ /* trap definitions */ +#ifndef TARGET_SPARC64 #define TT_TFAULT 0x01 #define TT_ILL_INSN 0x02 #define TT_PRIV_INSN 0x03 @@ -33,6 +33,21 @@ #define TT_EXTINT 0x10 #define TT_DIV_ZERO 0x2a #define TT_TRAP 0x80 +#else +#define TT_TFAULT 0x08 +#define TT_ILL_INSN 0x10 +#define TT_PRIV_INSN 0x11 +#define TT_NFPU_INSN 0x20 +#define TT_FP_EXCP 0x21 +#define TT_CLRWIN 0x24 +#define TT_DIV_ZERO 0x28 +#define TT_DFAULT 0x30 +#define TT_EXTINT 0x40 +#define TT_SPILL 0x80 +#define TT_FILL 0xc0 +#define TT_WOTHER 0x10 +#define TT_TRAP 0x100 +#endif #define PSR_NEG (1<<23) #define PSR_ZERO (1<<22) @@ -49,6 +64,13 @@ /* Trap base register */ #define TBR_BASE_MASK 0xfffff000 +#if defined(TARGET_SPARC64) +#define PS_PEF (1<<4) +#define PS_AM (1<<3) +#define PS_PRIV (1<<2) +#define PS_IE (1<<1) +#endif + /* Fcc */ #define FSR_RD1 (1<<31) #define FSR_RD0 (1<<30) @@ -119,15 +141,15 @@ typedef struct CPUSPARCState { target_ulong npc; /* next program counter */ target_ulong y; /* multiply/divide register */ uint32_t psr; /* processor state register */ - uint32_t fsr; /* FPU state register */ + target_ulong fsr; /* FPU state register */ uint32_t cwp; /* index of current register window (extracted from PSR) */ uint32_t wim; /* window invalid mask */ - uint32_t tbr; /* trap base register */ + target_ulong tbr; /* trap base register */ int psrs; /* supervisor mode (extracted from PSR) */ int psrps; /* previous supervisor mode */ int psret; /* enable traps */ - int psrpil; /* interrupt level */ + uint32_t psrpil; /* interrupt level */ int psref; /* enable fpu */ jmp_buf jmp_env; int user_mode_only; @@ -150,13 +172,43 @@ typedef struct CPUSPARCState { CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; /* MMU regs */ +#if defined(TARGET_SPARC64) + uint64_t lsu; +#define DMMU_E 0x8 +#define IMMU_E 0x4 + uint64_t immuregs[16]; + uint64_t dmmuregs[16]; + uint64_t itlb_tag[64]; + uint64_t itlb_tte[64]; + uint64_t dtlb_tag[64]; + uint64_t dtlb_tte[64]; +#else uint32_t mmuregs[16]; +#endif /* temporary float registers */ - float ft0, ft1, ft2; - double dt0, dt1, dt2; + float ft0, ft1; + double dt0, dt1; float_status fp_status; #if defined(TARGET_SPARC64) - target_ulong t0, t1, t2; +#define MAXTL 4 + uint64_t t0, t1, t2; + uint64_t tpc[MAXTL]; + uint64_t tnpc[MAXTL]; + uint64_t tstate[MAXTL]; + uint32_t tt[MAXTL]; + uint32_t xcc; /* Extended integer condition codes */ + uint32_t asi; + uint32_t pstate; + uint32_t tl; + uint32_t cansave, canrestore, otherwin, wstate, cleanwin; + target_ulong agregs[8]; /* alternate general registers */ + target_ulong igregs[8]; /* interrupt general registers */ + target_ulong mgregs[8]; /* mmu general registers */ + uint64_t version; + uint64_t fprs; +#endif +#if !defined(TARGET_SPARC64) && !defined(reg_T2) + target_ulong t2; #endif /* ice debug support */ @@ -165,6 +217,24 @@ typedef struct CPUSPARCState { int singlestep_enabled; /* XXX: should use CPU single step mode instead */ } CPUSPARCState; +#if defined(TARGET_SPARC64) +#define GET_FSR32(env) (env->fsr & 0xcfc1ffff) +#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ + env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL); \ + } while (0) +#define GET_FSR64(env) (env->fsr & 0x3fcfc1ffffULL) +#define PUT_FSR64(env, val) do { uint64_t _tmp = val; \ + env->fsr = _tmp & 0x3fcfc1c3ffULL; \ + } while (0) +// Manuf 0x17, version 0x11, mask 0 (UltraSparc-II) +#define GET_VER(env) ((0x17ULL << 48) | (0x11ULL << 32) | \ + (0 << 24) | (MAXTL << 8) | (NWINDOWS - 1)) +#else +#define GET_FSR32(env) (env->fsr) +#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ + env->fsr = _tmp & 0xcfc1ffff; \ + } while (0) +#endif CPUSPARCState *cpu_sparc_init(void); int cpu_sparc_exec(CPUSPARCState *s); @@ -194,6 +264,14 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); cpu_set_cwp(env, _tmp & PSR_CWP & (NWINDOWS - 1)); \ } while (0) +#ifdef TARGET_SPARC64 +#define GET_CCR(env) ((env->xcc << 4) | (env->psr & PSR_ICC)) +#define PUT_CCR(env, val) do { int _tmp = val; \ + env->xcc = _tmp >> 4; \ + env->psr = (_tmp & 0xf) << 20; \ + } while (0) +#endif + struct siginfo; int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 5e6c06214..cbfcb14d2 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -1,23 +1,41 @@ #ifndef EXEC_SPARC_H #define EXEC_SPARC_H 1 #include "dyngen-exec.h" +#include "config.h" register struct CPUSPARCState *env asm(AREG0); #ifdef TARGET_SPARC64 #define T0 (env->t0) #define T1 (env->t1) #define T2 (env->t2) +#define REGWPTR env->regwptr #else register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); + +#undef REG_REGWPTR // Broken +#ifdef REG_REGWPTR +register uint32_t *REGWPTR asm(AREG3); +#define reg_REGWPTR + +#ifdef AREG4 +register uint32_t T2 asm(AREG4); +#define reg_T2 +#else +#define T2 (env->t2) +#endif + +#else +#define REGWPTR env->regwptr register uint32_t T2 asm(AREG3); +#define reg_T2 +#endif #endif + #define FT0 (env->ft0) #define FT1 (env->ft1) -#define FT2 (env->ft2) #define DT0 (env->dt0) #define DT1 (env->dt1) -#define DT2 (env->dt2) #include "cpu.h" #include "exec-all.h" @@ -38,6 +56,16 @@ void do_fsqrts(void); void do_fsqrtd(void); void do_fcmps(void); void do_fcmpd(void); +#ifdef TARGET_SPARC64 +void do_fabsd(void); +void do_fcmps_fcc1(void); +void do_fcmpd_fcc1(void); +void do_fcmps_fcc2(void); +void do_fcmpd_fcc2(void); +void do_fcmps_fcc3(void); +void do_fcmpd_fcc3(void); +void do_popc(); +#endif void do_ldd_kernel(target_ulong addr); void do_ldd_user(target_ulong addr); void do_ldd_raw(target_ulong addr); diff --git a/target-sparc/fbranch_template.h b/target-sparc/fbranch_template.h new file mode 100644 index 000000000..e6bf9a269 --- /dev/null +++ b/target-sparc/fbranch_template.h @@ -0,0 +1,89 @@ +/* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */ + +void OPPROTO glue(op_eval_fbne, FCC)(void) +{ +// !0 + T2 = FFLAG_SET(FSR_FCC0) | FFLAG_SET(FSR_FCC1); /* L or G or U */ +} + +void OPPROTO glue(op_eval_fblg, FCC)(void) +{ +// 1 or 2 + T2 = FFLAG_SET(FSR_FCC0) ^ FFLAG_SET(FSR_FCC1); +} + +void OPPROTO glue(op_eval_fbul, FCC)(void) +{ +// 1 or 3 + T2 = FFLAG_SET(FSR_FCC0); +} + +void OPPROTO glue(op_eval_fbl, FCC)(void) +{ +// 1 + T2 = FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); +} + +void OPPROTO glue(op_eval_fbug, FCC)(void) +{ +// 2 or 3 + T2 = FFLAG_SET(FSR_FCC1); +} + +void OPPROTO glue(op_eval_fbg, FCC)(void) +{ +// 2 + T2 = !FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); +} + +void OPPROTO glue(op_eval_fbu, FCC)(void) +{ +// 3 + T2 = FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); +} + +void OPPROTO glue(op_eval_fbe, FCC)(void) +{ +// 0 + T2 = !FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); +} + +void OPPROTO glue(op_eval_fbue, FCC)(void) +{ +// 0 or 3 + T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0)); + FORCE_RET(); +} + +void OPPROTO glue(op_eval_fbge, FCC)(void) +{ +// 0 or 2 + T2 = !FFLAG_SET(FSR_FCC0); +} + +void OPPROTO glue(op_eval_fbuge, FCC)(void) +{ +// !1 + T2 = !(FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1)); +} + +void OPPROTO glue(op_eval_fble, FCC)(void) +{ +// 0 or 1 + T2 = !FFLAG_SET(FSR_FCC1); +} + +void OPPROTO glue(op_eval_fbule, FCC)(void) +{ +// !2 + T2 = !(!FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); +} + +void OPPROTO glue(op_eval_fbo, FCC)(void) +{ +// !3 + T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); +} + +#undef FCC +#undef FFLAG_SET diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h index eb1e1e311..74988f7df 100644 --- a/target-sparc/fop_template.h +++ b/target-sparc/fop_template.h @@ -40,16 +40,6 @@ void OPPROTO glue(op_store_FT1_fpr_fpr, REGNAME)(void) REG = FT1; } -void OPPROTO glue(op_load_fpr_FT2_fpr, REGNAME)(void) -{ - FT2 = REG; -} - -void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void) -{ - REG = FT2; -} - /* double floating point registers moves */ void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void) { @@ -87,23 +77,5 @@ void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void) *p = u.l.upper; } -void OPPROTO glue(op_load_fpr_DT2_fpr, REGNAME)(void) -{ - CPU_DoubleU u; - uint32_t *p = (uint32_t *)® - u.l.lower = *(p +1); - u.l.upper = *p; - DT2 = u.d; -} - -void OPPROTO glue(op_store_DT2_fpr_fpr, REGNAME)(void) -{ - CPU_DoubleU u; - uint32_t *p = (uint32_t *)® - u.d = DT2; - *(p +1) = u.l.lower; - *p = u.l.upper; -} - #undef REG #undef REGNAME diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 9fd5f214b..a281e8d63 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -43,7 +43,6 @@ void cpu_unlock(void) int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { - env->mmuregs[4] = address; if (rw & 2) env->exception_index = TT_TFAULT; else @@ -102,6 +101,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) env = saved_env; } +#ifndef TARGET_SPARC64 static const int access_table[8][8] = { { 0, 0, 0, 0, 2, 0, 3, 3 }, { 0, 0, 0, 0, 2, 0, 0, 0 }, @@ -268,6 +268,136 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 1; } } +#else +static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot, + int *access_index, target_ulong address, int rw, + int is_user) +{ + target_ulong mask; + unsigned int i; + + if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ + *physical = address & 0xffffffff; + *prot = PAGE_READ | PAGE_WRITE; + return 0; + } + + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { + switch (env->dtlb_tte[i] >> 60) { + default: + case 0x4: // 8k + mask = 0xffffffffffffe000ULL; + break; + case 0x5: // 64k + mask = 0xffffffffffff0000ULL; + break; + case 0x6: // 512k + mask = 0xfffffffffff80000ULL; + break; + case 0x7: // 4M + mask = 0xffffffffffc00000ULL; + break; + } + // ctx match, vaddr match? + if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) && + (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) { + // access ok? + if (((env->dtlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) || + (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { + env->exception_index = TT_DFAULT; + return 1; + } + *physical = env->dtlb_tte[i] & 0xffffe000; + *prot = PAGE_READ; + if (env->dtlb_tte[i] & 0x2) + *prot |= PAGE_WRITE; + return 0; + } + } + } + env->exception_index = TT_DFAULT; + return 1; +} + +static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot, + int *access_index, target_ulong address, int rw, + int is_user) +{ + target_ulong mask; + unsigned int i; + + if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */ + *physical = address & 0xffffffff; + *prot = PAGE_READ; + return 0; + } + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { + switch (env->itlb_tte[i] >> 60) { + default: + case 0x4: // 8k + mask = 0xffffffffffffe000ULL; + break; + case 0x5: // 64k + mask = 0xffffffffffff0000ULL; + break; + case 0x6: // 512k + mask = 0xfffffffffff80000ULL; + break; + case 0x7: // 4M + mask = 0xffffffffffc00000ULL; + break; + } + // ctx match, vaddr match? + if (env->immuregs[1] == (env->itlb_tag[i] & 0x1fff) && + (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) { + // access ok? + if ((env->itlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) { + env->exception_index = TT_TFAULT; + return 1; + } + *physical = env->itlb_tte[i] & 0xffffe000; + *prot = PAGE_READ; + return 0; + } + } + } + env->exception_index = TT_TFAULT; + return 1; +} + +int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot, + int *access_index, target_ulong address, int rw, + int is_user) +{ + if (rw == 2) + return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user); + else + return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user); +} + +/* Perform address translation */ +int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + target_ulong virt_addr; + target_phys_addr_t paddr; + unsigned long vaddr; + int error_code = 0, prot, ret = 0, access_index; + + error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); + if (error_code == 0) { + virt_addr = address & TARGET_PAGE_MASK; + vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + return ret; + } + // XXX + return 1; +} + +#endif #endif void memcpy32(target_ulong *dst, const target_ulong *src) @@ -292,17 +422,73 @@ void set_cwp(int new_cwp) if (new_cwp == (NWINDOWS - 1)) memcpy32(env->regbase + NWINDOWS * 16, env->regbase); env->regwptr = env->regbase + (new_cwp * 16); + REGWPTR = env->regwptr; } void cpu_set_cwp(CPUState *env1, int new_cwp) { CPUState *saved_env; +#ifdef reg_REGWPTR + target_ulong *saved_regwptr; +#endif + saved_env = env; +#ifdef reg_REGWPTR + saved_regwptr = REGWPTR; +#endif env = env1; set_cwp(new_cwp); env = saved_env; +#ifdef reg_REGWPTR + REGWPTR = saved_regwptr; +#endif } +#ifdef TARGET_SPARC64 +void do_interrupt(int intno) +{ +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_INT) { + static int count; + fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", + count, intno, + env->pc, + env->npc, env->regwptr[6]); + cpu_dump_state(env, logfile, fprintf, 0); +#if 0 + { + int i; + uint8_t *ptr; + + fprintf(logfile, " code="); + ptr = (uint8_t *)env->pc; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->pstate & PS_IE) { + cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); + return; + } +#endif + env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | + ((env->pstate & 0xfff) << 8) | (env->cwp & 0xff); + env->tpc[env->tl] = env->pc; + env->tnpc[env->tl] = env->npc; + env->tt[env->tl] = intno; + env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4); + env->tl++; + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = 0; +} +#else void do_interrupt(int intno) { int cwp; @@ -448,3 +634,4 @@ void dump_mmu(void) printf("MMU dump ends\n"); } #endif +#endif diff --git a/target-sparc/op.c b/target-sparc/op.c index 281917a7f..86c45c709 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -46,76 +46,76 @@ #define REG (env->gregs[7]) #include "op_template.h" #define REGNAME i0 -#define REG (env->regwptr[16]) +#define REG (REGWPTR[16]) #include "op_template.h" #define REGNAME i1 -#define REG (env->regwptr[17]) +#define REG (REGWPTR[17]) #include "op_template.h" #define REGNAME i2 -#define REG (env->regwptr[18]) +#define REG (REGWPTR[18]) #include "op_template.h" #define REGNAME i3 -#define REG (env->regwptr[19]) +#define REG (REGWPTR[19]) #include "op_template.h" #define REGNAME i4 -#define REG (env->regwptr[20]) +#define REG (REGWPTR[20]) #include "op_template.h" #define REGNAME i5 -#define REG (env->regwptr[21]) +#define REG (REGWPTR[21]) #include "op_template.h" #define REGNAME i6 -#define REG (env->regwptr[22]) +#define REG (REGWPTR[22]) #include "op_template.h" #define REGNAME i7 -#define REG (env->regwptr[23]) +#define REG (REGWPTR[23]) #include "op_template.h" #define REGNAME l0 -#define REG (env->regwptr[8]) +#define REG (REGWPTR[8]) #include "op_template.h" #define REGNAME l1 -#define REG (env->regwptr[9]) +#define REG (REGWPTR[9]) #include "op_template.h" #define REGNAME l2 -#define REG (env->regwptr[10]) +#define REG (REGWPTR[10]) #include "op_template.h" #define REGNAME l3 -#define REG (env->regwptr[11]) +#define REG (REGWPTR[11]) #include "op_template.h" #define REGNAME l4 -#define REG (env->regwptr[12]) +#define REG (REGWPTR[12]) #include "op_template.h" #define REGNAME l5 -#define REG (env->regwptr[13]) +#define REG (REGWPTR[13]) #include "op_template.h" #define REGNAME l6 -#define REG (env->regwptr[14]) +#define REG (REGWPTR[14]) #include "op_template.h" #define REGNAME l7 -#define REG (env->regwptr[15]) +#define REG (REGWPTR[15]) #include "op_template.h" #define REGNAME o0 -#define REG (env->regwptr[0]) +#define REG (REGWPTR[0]) #include "op_template.h" #define REGNAME o1 -#define REG (env->regwptr[1]) +#define REG (REGWPTR[1]) #include "op_template.h" #define REGNAME o2 -#define REG (env->regwptr[2]) +#define REG (REGWPTR[2]) #include "op_template.h" #define REGNAME o3 -#define REG (env->regwptr[3]) +#define REG (REGWPTR[3]) #include "op_template.h" #define REGNAME o4 -#define REG (env->regwptr[4]) +#define REG (REGWPTR[4]) #include "op_template.h" #define REGNAME o5 -#define REG (env->regwptr[5]) +#define REG (REGWPTR[5]) #include "op_template.h" #define REGNAME o6 -#define REG (env->regwptr[6]) +#define REG (REGWPTR[6]) #include "op_template.h" #define REGNAME o7 -#define REG (env->regwptr[7]) +#define REG (REGWPTR[7]) #include "op_template.h" #define REGNAME f0 @@ -215,10 +215,106 @@ #define REG (env->fpr[31]) #include "fop_template.h" +#ifdef TARGET_SPARC64 +#define REGNAME f32 +#define REG (env->fpr[32]) +#include "fop_template.h" +#define REGNAME f34 +#define REG (env->fpr[34]) +#include "fop_template.h" +#define REGNAME f36 +#define REG (env->fpr[36]) +#include "fop_template.h" +#define REGNAME f38 +#define REG (env->fpr[38]) +#include "fop_template.h" +#define REGNAME f40 +#define REG (env->fpr[40]) +#include "fop_template.h" +#define REGNAME f42 +#define REG (env->fpr[42]) +#include "fop_template.h" +#define REGNAME f44 +#define REG (env->fpr[44]) +#include "fop_template.h" +#define REGNAME f46 +#define REG (env->fpr[46]) +#include "fop_template.h" +#define REGNAME f48 +#define REG (env->fpr[47]) +#include "fop_template.h" +#define REGNAME f50 +#define REG (env->fpr[50]) +#include "fop_template.h" +#define REGNAME f52 +#define REG (env->fpr[52]) +#include "fop_template.h" +#define REGNAME f54 +#define REG (env->fpr[54]) +#include "fop_template.h" +#define REGNAME f56 +#define REG (env->fpr[56]) +#include "fop_template.h" +#define REGNAME f58 +#define REG (env->fpr[58]) +#include "fop_template.h" +#define REGNAME f60 +#define REG (env->fpr[60]) +#include "fop_template.h" +#define REGNAME f62 +#define REG (env->fpr[62]) +#include "fop_template.h" +#endif + +#ifdef TARGET_SPARC64 +#undef JUMP_TB +#define JUMP_TB(opname, tbparam, n, eip) \ + do { \ + GOTO_TB(opname, tbparam, n); \ + T0 = (long)(tbparam) + (n); \ + env->pc = (eip) & 0xffffffff; \ + EXIT_TB(); \ + } while (0) + +#ifdef WORDS_BIGENDIAN +typedef union UREG64 { + struct { uint16_t v3, v2, v1, v0; } w; + struct { uint32_t v1, v0; } l; + uint64_t q; +} UREG64; +#else +typedef union UREG64 { + struct { uint16_t v0, v1, v2, v3; } w; + struct { uint32_t v0, v1; } l; + uint64_t q; +} UREG64; +#endif + +#define PARAMQ1 \ +({\ + UREG64 __p;\ + __p.l.v1 = PARAM1;\ + __p.l.v0 = PARAM2;\ + __p.q;\ +}) + +void OPPROTO op_movq_T0_im64(void) +{ + T0 = PARAMQ1; +} + +void OPPROTO op_movq_T1_im64(void) +{ + T1 = PARAMQ1; +} + +#define XFLAG_SET(x) ((env->xcc&x)?1:0) + +#else #define EIP (env->pc) +#endif #define FLAG_SET(x) ((env->psr&x)?1:0) -#define FFLAG_SET(x) ((env->fsr&x)?1:0) void OPPROTO op_movl_T0_0(void) { @@ -227,17 +323,52 @@ void OPPROTO op_movl_T0_0(void) void OPPROTO op_movl_T0_im(void) { - T0 = PARAM1; + T0 = (uint32_t)PARAM1; } void OPPROTO op_movl_T1_im(void) { - T1 = PARAM1; + T1 = (uint32_t)PARAM1; } void OPPROTO op_movl_T2_im(void) { - T2 = PARAM1; + T2 = (uint32_t)PARAM1; +} + +void OPPROTO op_movl_T0_sim(void) +{ + T0 = (int32_t)PARAM1; +} + +void OPPROTO op_movl_T1_sim(void) +{ + T1 = (int32_t)PARAM1; +} + +void OPPROTO op_movl_T2_sim(void) +{ + T2 = (int32_t)PARAM1; +} + +void OPPROTO op_movl_T0_env(void) +{ + T0 = *(uint32_t *)((char *)env + PARAM1); +} + +void OPPROTO op_movl_env_T0(void) +{ + *(uint32_t *)((char *)env + PARAM1) = T0; +} + +void OPPROTO op_movtl_T0_env(void) +{ + T0 = *(target_ulong *)((char *)env + PARAM1); +} + +void OPPROTO op_movtl_env_T0(void) +{ + *(target_ulong *)((char *)env + PARAM1) = T0; } void OPPROTO op_add_T1_T0(void) @@ -252,6 +383,27 @@ void OPPROTO op_add_T1_T0_cc(void) src1 = T0; T0 += T1; env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (T0 < src1) + env->xcc |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) + env->xcc |= PSR_OVF; +#else if (!T0) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) @@ -260,7 +412,7 @@ void OPPROTO op_add_T1_T0_cc(void) env->psr |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) env->psr |= PSR_OVF; - /* V9 xcc */ +#endif FORCE_RET(); } @@ -276,6 +428,27 @@ void OPPROTO op_addx_T1_T0_cc(void) src1 = T0; T0 += T1 + FLAG_SET(PSR_CARRY); env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (T0 < src1) + env->xcc |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) + env->xcc |= PSR_OVF; +#else if (!T0) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) @@ -284,7 +457,7 @@ void OPPROTO op_addx_T1_T0_cc(void) env->psr |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) env->psr |= PSR_OVF; - /* V9 xcc */ +#endif FORCE_RET(); } @@ -300,6 +473,27 @@ void OPPROTO op_sub_T1_T0_cc(void) src1 = T0; T0 -= T1; env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (T0 < src1) + env->xcc |= PSR_CARRY; + if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) + env->xcc |= PSR_OVF; +#else if (!T0) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) @@ -308,7 +502,7 @@ void OPPROTO op_sub_T1_T0_cc(void) env->psr |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) env->psr |= PSR_OVF; - /* V9 xcc */ +#endif FORCE_RET(); } @@ -324,6 +518,27 @@ void OPPROTO op_subx_T1_T0_cc(void) src1 = T0; T0 -= T1 + FLAG_SET(PSR_CARRY); env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (T0 < src1) + env->xcc |= PSR_CARRY; + if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) + env->xcc |= PSR_OVF; +#else if (!T0) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) @@ -332,7 +547,7 @@ void OPPROTO op_subx_T1_T0_cc(void) env->psr |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) env->psr |= PSR_OVF; - /* V9 xcc */ +#endif FORCE_RET(); } @@ -449,24 +664,73 @@ void OPPROTO op_sdiv_T1_T0(void) void OPPROTO op_div_cc(void) { env->psr = 0; +#ifdef TARGET_SPARC64 + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (T1) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; +#else if (!T0) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; if (T1) env->psr |= PSR_OVF; - /* V9 xcc */ +#endif FORCE_RET(); } +#ifdef TARGET_SPARC64 +void OPPROTO op_mulx_T1_T0(void) +{ + T0 *= T1; + FORCE_RET(); +} + +void OPPROTO op_udivx_T1_T0(void) +{ + T0 /= T1; + FORCE_RET(); +} + +void OPPROTO op_sdivx_T1_T0(void) +{ + if (T0 == INT64_MIN && T1 == -1) + T0 = INT64_MIN; + else + T0 /= (target_long) T1; + FORCE_RET(); +} +#endif + void OPPROTO op_logic_T0_cc(void) { env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; +#else if (!T0) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - /* V9 xcc */ +#endif FORCE_RET(); } @@ -475,6 +739,27 @@ void OPPROTO op_sll(void) T0 <<= T1; } +#ifdef TARGET_SPARC64 +void OPPROTO op_srl(void) +{ + T0 = (T0 & 0xffffffff) >> T1; +} + +void OPPROTO op_srlx(void) +{ + T0 >>= T1; +} + +void OPPROTO op_sra(void) +{ + T0 = ((int32_t) (T0 & 0xffffffff)) >> T1; +} + +void OPPROTO op_srax(void) +{ + T0 = ((int64_t) T0) >> T1; +} +#else void OPPROTO op_srl(void) { T0 >>= T1; @@ -484,6 +769,7 @@ void OPPROTO op_sra(void) { T0 = ((int32_t) T0) >> T1; } +#endif /* Load and store */ #define MEMSUFFIX _raw @@ -498,62 +784,137 @@ void OPPROTO op_sra(void) void OPPROTO op_ldfsr(void) { - env->fsr = *((uint32_t *) &FT0); + PUT_FSR32(env, *((uint32_t *) &FT0)); helper_ldfsr(); } void OPPROTO op_stfsr(void) { - *((uint32_t *) &FT0) = env->fsr; + *((uint32_t *) &FT0) = GET_FSR32(env); } -void OPPROTO op_wry(void) +#ifndef TARGET_SPARC64 +void OPPROTO op_rdpsr(void) { - env->y = T0; + do_rdpsr(); } -void OPPROTO op_rdy(void) +void OPPROTO op_wrpsr(void) { - T0 = env->y; + do_wrpsr(); + FORCE_RET(); } -void OPPROTO op_rdwim(void) +void OPPROTO op_rett(void) { - T0 = env->wim; + helper_rett(); + FORCE_RET(); } -void OPPROTO op_wrwim(void) +/* XXX: use another pointer for %iN registers to avoid slow wrapping + handling ? */ +void OPPROTO op_save(void) { - env->wim = T0; + uint32_t cwp; + cwp = (env->cwp - 1) & (NWINDOWS - 1); + if (env->wim & (1 << cwp)) { + raise_exception(TT_WIN_OVF); + } + set_cwp(cwp); FORCE_RET(); } -void OPPROTO op_rdpsr(void) +void OPPROTO op_restore(void) { - do_rdpsr(); + uint32_t cwp; + cwp = (env->cwp + 1) & (NWINDOWS - 1); + if (env->wim & (1 << cwp)) { + raise_exception(TT_WIN_UNF); + } + set_cwp(cwp); + FORCE_RET(); +} +#else +void OPPROTO op_rdccr(void) +{ + T0 = GET_CCR(env); } -void OPPROTO op_wrpsr(void) +void OPPROTO op_wrccr(void) { - do_wrpsr(); - FORCE_RET(); + PUT_CCR(env, T0); } -void OPPROTO op_rdtbr(void) +void OPPROTO op_rdtick(void) { - T0 = env->tbr; + T0 = 0; // XXX read cycle counter and bit 31 } -void OPPROTO op_wrtbr(void) +void OPPROTO op_wrtick(void) { - env->tbr = T0; - FORCE_RET(); + // XXX write cycle counter and bit 31 } -void OPPROTO op_rett(void) +void OPPROTO op_rdtpc(void) { - helper_rett(); - FORCE_RET(); + T0 = env->tpc[env->tl]; +} + +void OPPROTO op_wrtpc(void) +{ + env->tpc[env->tl] = T0; +} + +void OPPROTO op_rdtnpc(void) +{ + T0 = env->tnpc[env->tl]; +} + +void OPPROTO op_wrtnpc(void) +{ + env->tnpc[env->tl] = T0; +} + +void OPPROTO op_rdtstate(void) +{ + T0 = env->tstate[env->tl]; +} + +void OPPROTO op_wrtstate(void) +{ + env->tstate[env->tl] = T0; +} + +void OPPROTO op_rdtt(void) +{ + T0 = env->tt[env->tl]; +} + +void OPPROTO op_wrtt(void) +{ + env->tt[env->tl] = T0; +} + +void OPPROTO op_rdpstate(void) +{ + T0 = env->pstate; +} + +void OPPROTO op_wrpstate(void) +{ + env->pstate = T0 & 0x1f; +} + +// CWP handling is reversed in V9, but we still use the V8 register +// order. +void OPPROTO op_rdcwp(void) +{ + T0 = NWINDOWS - 1 - env->cwp; +} + +void OPPROTO op_wrcwp(void) +{ + env->cwp = NWINDOWS - 1 - T0; } /* XXX: use another pointer for %iN registers to avoid slow wrapping @@ -562,10 +923,20 @@ void OPPROTO op_save(void) { uint32_t cwp; cwp = (env->cwp - 1) & (NWINDOWS - 1); - if (env->wim & (1 << cwp)) { - raise_exception(TT_WIN_OVF); + if (env->cansave == 0) { + raise_exception(TT_SPILL | (env->otherwin != 0 ? + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); + } else { + if (env->cleanwin - env->canrestore == 0) { + // XXX Clean windows without trap + raise_exception(TT_CLRWIN); + } else { + env->cansave--; + env->canrestore++; + set_cwp(cwp); + } } - set_cwp(cwp); FORCE_RET(); } @@ -573,12 +944,18 @@ void OPPROTO op_restore(void) { uint32_t cwp; cwp = (env->cwp + 1) & (NWINDOWS - 1); - if (env->wim & (1 << cwp)) { - raise_exception(TT_WIN_UNF); + if (env->canrestore == 0) { + raise_exception(TT_FILL | (env->otherwin != 0 ? + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); + } else { + env->cansave++; + env->canrestore--; + set_cwp(cwp); } - set_cwp(cwp); FORCE_RET(); } +#endif void OPPROTO op_exception(void) { @@ -629,6 +1006,11 @@ void OPPROTO op_exit_tb(void) EXIT_TB(); } +void OPPROTO op_eval_ba(void) +{ + T2 = 1; +} + void OPPROTO op_eval_be(void) { T2 = FLAG_SET(PSR_ZERO); @@ -665,6 +1047,11 @@ void OPPROTO op_eval_bvs(void) T2 = FLAG_SET(PSR_OVF); } +void OPPROTO op_eval_bn(void) +{ + T2 = 0; +} + void OPPROTO op_eval_bneg(void) { T2 = FLAG_SET(PSR_NEG); @@ -711,101 +1098,156 @@ void OPPROTO op_eval_bvc(void) T2 = !FLAG_SET(PSR_OVF); } -/* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */ +#ifdef TARGET_SPARC64 +void OPPROTO op_eval_xbe(void) +{ + T2 = XFLAG_SET(PSR_ZERO); +} -void OPPROTO op_eval_fbne(void) +void OPPROTO op_eval_xble(void) { -// !0 - T2 = (env->fsr & (FSR_FCC1 | FSR_FCC0)); /* L or G or U */ + target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); + + T2 = Z | (N ^ V); } -void OPPROTO op_eval_fblg(void) +void OPPROTO op_eval_xbl(void) { -// 1 or 2 - T2 = FFLAG_SET(FSR_FCC0) ^ FFLAG_SET(FSR_FCC1); + target_ulong N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); + + T2 = N ^ V; } -void OPPROTO op_eval_fbul(void) +void OPPROTO op_eval_xbleu(void) { -// 1 or 3 - T2 = FFLAG_SET(FSR_FCC0); + target_ulong Z = XFLAG_SET(PSR_ZERO), C = XFLAG_SET(PSR_CARRY); + + T2 = C | Z; } -void OPPROTO op_eval_fbl(void) +void OPPROTO op_eval_xbcs(void) { -// 1 - T2 = FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); + T2 = XFLAG_SET(PSR_CARRY); } -void OPPROTO op_eval_fbug(void) +void OPPROTO op_eval_xbvs(void) { -// 2 or 3 - T2 = FFLAG_SET(FSR_FCC1); + T2 = XFLAG_SET(PSR_OVF); } -void OPPROTO op_eval_fbg(void) +void OPPROTO op_eval_xbneg(void) { -// 2 - T2 = !FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); + T2 = XFLAG_SET(PSR_NEG); } -void OPPROTO op_eval_fbu(void) +void OPPROTO op_eval_xbne(void) { -// 3 - T2 = FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1); + T2 = !XFLAG_SET(PSR_ZERO); } -void OPPROTO op_eval_fbe(void) +void OPPROTO op_eval_xbg(void) { -// 0 - T2 = !FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1); + target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); + + T2 = !(Z | (N ^ V)); } -void OPPROTO op_eval_fbue(void) +void OPPROTO op_eval_xbge(void) { -// 0 or 3 - T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0)); - FORCE_RET(); + target_ulong N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); + + T2 = !(N ^ V); +} + +void OPPROTO op_eval_xbgu(void) +{ + target_ulong Z = XFLAG_SET(PSR_ZERO), C = XFLAG_SET(PSR_CARRY); + + T2 = !(C | Z); +} + +void OPPROTO op_eval_xbcc(void) +{ + T2 = !XFLAG_SET(PSR_CARRY); +} + +void OPPROTO op_eval_xbpos(void) +{ + T2 = !XFLAG_SET(PSR_NEG); +} + +void OPPROTO op_eval_xbvc(void) +{ + T2 = !XFLAG_SET(PSR_OVF); +} +#endif + +#define FCC +#define FFLAG_SET(x) (env->fsr & x? 1: 0) +#include "fbranch_template.h" + +#ifdef TARGET_SPARC64 +#define FCC _fcc1 +#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 32))? 1: 0) +#include "fbranch_template.h" +#define FCC _fcc2 +#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 34))? 1: 0) +#include "fbranch_template.h" +#define FCC _fcc3 +#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 36))? 1: 0) +#include "fbranch_template.h" +#endif + +#ifdef TARGET_SPARC64 +void OPPROTO op_eval_brz(void) +{ + T2 = T0; } -void OPPROTO op_eval_fbge(void) +void OPPROTO op_eval_brnz(void) { -// 0 or 2 - T2 = !FFLAG_SET(FSR_FCC0); + T2 = !T0; } -void OPPROTO op_eval_fbuge(void) +void OPPROTO op_eval_brlz(void) { -// !1 - T2 = !(FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1)); + T2 = ((int64_t)T0 < 0); } -void OPPROTO op_eval_fble(void) +void OPPROTO op_eval_brlez(void) { -// 0 or 1 - T2 = !FFLAG_SET(FSR_FCC1); + T2 = ((int64_t)T0 <= 0); } -void OPPROTO op_eval_fbule(void) +void OPPROTO op_eval_brgz(void) { -// !2 - T2 = !(!FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); + T2 = ((int64_t)T0 > 0); } -void OPPROTO op_eval_fbo(void) +void OPPROTO op_eval_brgez(void) { -// !3 - T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1)); + T2 = ((int64_t)T0 >= 0); } +void OPPROTO op_jmp_im64(void) +{ + env->pc = PARAMQ1; +} + +void OPPROTO op_movq_npc_im64(void) +{ + env->npc = PARAMQ1; +} +#endif + void OPPROTO op_jmp_im(void) { - env->pc = PARAM1; + env->pc = (uint32_t)PARAM1; } void OPPROTO op_movl_npc_im(void) { - env->npc = PARAM1; + env->npc = (uint32_t)PARAM1; } void OPPROTO op_movl_npc_T0(void) @@ -826,17 +1268,17 @@ void OPPROTO op_next_insn(void) void OPPROTO op_branch(void) { - env->npc = PARAM3; /* XXX: optimize */ + env->npc = (uint32_t)PARAM3; /* XXX: optimize */ JUMP_TB(op_branch, PARAM1, 0, PARAM2); } void OPPROTO op_branch2(void) { if (T2) { - env->npc = PARAM2 + 4; + env->npc = (uint32_t)PARAM2 + 4; JUMP_TB(op_branch2, PARAM1, 0, PARAM2); } else { - env->npc = PARAM3 + 4; + env->npc = (uint32_t)PARAM3 + 4; JUMP_TB(op_branch2, PARAM1, 1, PARAM3); } FORCE_RET(); @@ -845,10 +1287,10 @@ void OPPROTO op_branch2(void) void OPPROTO op_branch_a(void) { if (T2) { - env->npc = PARAM2; /* XXX: optimize */ + env->npc = (uint32_t)PARAM2; /* XXX: optimize */ JUMP_TB(op_branch_a, PARAM1, 0, PARAM3); } else { - env->npc = PARAM3 + 8; /* XXX: optimize */ + env->npc = (uint32_t)PARAM3 + 8; /* XXX: optimize */ JUMP_TB(op_branch_a, PARAM1, 1, PARAM3 + 4); } FORCE_RET(); @@ -857,9 +1299,9 @@ void OPPROTO op_branch_a(void) void OPPROTO op_generic_branch(void) { if (T2) { - env->npc = PARAM1; + env->npc = (uint32_t)PARAM1; } else { - env->npc = PARAM2; + env->npc = (uint32_t)PARAM2; } FORCE_RET(); } @@ -879,6 +1321,18 @@ void OPPROTO op_fabss(void) do_fabss(); } +#ifdef TARGET_SPARC64 +void OPPROTO op_fnegd(void) +{ + DT0 = -DT1; +} + +void OPPROTO op_fabsd(void) +{ + do_fabsd(); +} +#endif + void OPPROTO op_fsqrts(void) { do_fsqrts(); @@ -944,6 +1398,38 @@ void OPPROTO op_fcmpd(void) do_fcmpd(); } +#ifdef TARGET_SPARC64 +void OPPROTO op_fcmps_fcc1(void) +{ + do_fcmps_fcc1(); +} + +void OPPROTO op_fcmpd_fcc1(void) +{ + do_fcmpd_fcc1(); +} + +void OPPROTO op_fcmps_fcc2(void) +{ + do_fcmps_fcc2(); +} + +void OPPROTO op_fcmpd_fcc2(void) +{ + do_fcmpd_fcc2(); +} + +void OPPROTO op_fcmps_fcc3(void) +{ + do_fcmps_fcc3(); +} + +void OPPROTO op_fcmpd_fcc3(void) +{ + do_fcmpd_fcc3(); +} +#endif + #ifdef USE_INT_TO_FLOAT_HELPERS void OPPROTO op_fitos(void) { @@ -964,6 +1450,18 @@ void OPPROTO op_fitod(void) { DT0 = (double) *((int32_t *)&FT1); } + +#ifdef TARGET_SPARC64 +void OPPROTO op_fxtos(void) +{ + FT0 = (float) *((int64_t *)&DT1); +} + +void OPPROTO op_fxtod(void) +{ + DT0 = (double) *((int64_t *)&DT1); +} +#endif #endif void OPPROTO op_fdtos(void) @@ -986,6 +1484,102 @@ void OPPROTO op_fdtoi(void) *((int32_t *)&FT0) = (int32_t) DT1; } +#ifdef TARGET_SPARC64 +void OPPROTO op_fstox(void) +{ + *((int64_t *)&DT0) = (int64_t) FT1; +} + +void OPPROTO op_fdtox(void) +{ + *((int64_t *)&DT0) = (int64_t) DT1; +} + +void OPPROTO op_fmovs_cc(void) +{ + if (T2) + FT0 = FT1; +} + +void OPPROTO op_fmovd_cc(void) +{ + if (T2) + DT0 = DT1; +} + +void OPPROTO op_mov_cc(void) +{ + if (T2) + T0 = T1; +} + +void OPPROTO op_flushw(void) +{ + if (env->cansave != NWINDOWS - 2) { + raise_exception(TT_SPILL | (env->otherwin != 0 ? + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); + } +} + +void OPPROTO op_saved(void) +{ + env->cansave++; + if (env->otherwin == 0) + env->canrestore--; +} + +void OPPROTO op_restored(void) +{ + env->canrestore++; + if (env->cleanwin < NWINDOWS - 1) + env->cleanwin++; + if (env->otherwin == 0) + env->cansave--; + else + env->otherwin--; +} + +void OPPROTO op_popc(void) +{ + do_popc(); +} + +void OPPROTO op_done(void) +{ + env->pc = env->tnpc[env->tl]; + env->npc = env->tnpc[env->tl] + 4; + env->pstate = env->tstate[env->tl]; + env->tl--; +} + +void OPPROTO op_retry(void) +{ + env->pc = env->tpc[env->tl]; + env->npc = env->tnpc[env->tl]; + env->pstate = env->tstate[env->tl]; + env->tl--; +} + +void OPPROTO op_sir(void) +{ + // XXX + +} + +void OPPROTO op_ld_asi_reg() +{ + T0 += PARAM1; + helper_ld_asi(env->asi, PARAM2, PARAM3); +} + +void OPPROTO op_st_asi_reg() +{ + T0 += PARAM1; + helper_st_asi(env->asi, PARAM2, PARAM3); +} +#endif + void OPPROTO op_ld_asi() { helper_ld_asi(PARAM1, PARAM2, PARAM3); diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 143cc1644..ac307a79b 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -25,6 +25,13 @@ void do_fabss(void) FT0 = float32_abs(FT1); } +#ifdef TARGET_SPARC64 +void do_fabsd(void) +{ + DT0 = float64_abs(DT1); +} +#endif + void do_fsqrts(void) { FT0 = float32_sqrt(FT1, &env->fp_status); @@ -35,48 +42,185 @@ void do_fsqrtd(void) DT0 = float64_sqrt(DT1, &env->fp_status); } +#define FS 0 void do_fcmps (void) { + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); if (isnan(FT0) || isnan(FT1)) { - T0 = FSR_FCC1 | FSR_FCC0; - env->fsr &= ~(FSR_FCC1 | FSR_FCC0); - env->fsr |= T0; + T0 = (FSR_FCC1 | FSR_FCC0) << FS; if (env->fsr & FSR_NVM) { + env->fsr |= T0; raise_exception(TT_FP_EXCP); } else { env->fsr |= FSR_NVA; } } else if (FT0 < FT1) { - T0 = FSR_FCC0; + T0 = FSR_FCC0 << FS; } else if (FT0 > FT1) { - T0 = FSR_FCC1; + T0 = FSR_FCC1 << FS; } else { T0 = 0; } - env->fsr = T0; + env->fsr |= T0; } void do_fcmpd (void) { + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(DT0) || isnan(DT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (DT0 < DT1) { + T0 = FSR_FCC0 << FS; + } else if (DT0 > DT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +#ifdef TARGET_SPARC64 +#undef FS +#define FS 22 +void do_fcmps_fcc1 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(FT0) || isnan(FT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (FT0 < FT1) { + T0 = FSR_FCC0 << FS; + } else if (FT0 > FT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +void do_fcmpd_fcc1 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(DT0) || isnan(DT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (DT0 < DT1) { + T0 = FSR_FCC0 << FS; + } else if (DT0 > DT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +#undef FS +#define FS 24 +void do_fcmps_fcc2 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(FT0) || isnan(FT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (FT0 < FT1) { + T0 = FSR_FCC0 << FS; + } else if (FT0 > FT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +void do_fcmpd_fcc2 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); if (isnan(DT0) || isnan(DT1)) { - T0 = FSR_FCC1 | FSR_FCC0; - env->fsr &= ~(FSR_FCC1 | FSR_FCC0); - env->fsr |= T0; + T0 = (FSR_FCC1 | FSR_FCC0) << FS; if (env->fsr & FSR_NVM) { + env->fsr |= T0; raise_exception(TT_FP_EXCP); } else { env->fsr |= FSR_NVA; } } else if (DT0 < DT1) { - T0 = FSR_FCC0; + T0 = FSR_FCC0 << FS; } else if (DT0 > DT1) { - T0 = FSR_FCC1; + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} + +#undef FS +#define FS 26 +void do_fcmps_fcc3 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(FT0) || isnan(FT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (FT0 < FT1) { + T0 = FSR_FCC0 << FS; + } else if (FT0 > FT1) { + T0 = FSR_FCC1 << FS; } else { T0 = 0; } - env->fsr = T0; + env->fsr |= T0; } +void do_fcmpd_fcc3 (void) +{ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); + if (isnan(DT0) || isnan(DT1)) { + T0 = (FSR_FCC1 | FSR_FCC0) << FS; + if (env->fsr & FSR_NVM) { + env->fsr |= T0; + raise_exception(TT_FP_EXCP); + } else { + env->fsr |= FSR_NVA; + } + } else if (DT0 < DT1) { + T0 = FSR_FCC0 << FS; + } else if (DT0 > DT1) { + T0 = FSR_FCC1 << FS; + } else { + T0 = 0; + } + env->fsr |= T0; +} +#undef FS +#endif + +#ifndef TARGET_SPARC64 void helper_ld_asi(int asi, int size, int sign) { uint32_t ret; @@ -235,6 +379,255 @@ void helper_st_asi(int asi, int size, int sign) } } +#else + +void helper_ld_asi(int asi, int size, int sign) +{ + uint64_t ret; + + if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) + raise_exception(TT_PRIV_INSN); + + switch (asi) { + case 0x14: // Bypass + case 0x15: // Bypass, non-cacheable + { + cpu_physical_memory_read(T0, (void *) &ret, size); + if (size == 8) + tswap64s(&ret); + if (size == 4) + tswap32s((uint32_t *)&ret); + else if (size == 2) + tswap16s((uint16_t *)&ret); + break; + } + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE + // XXX + break; + case 0x45: // LSU + ret = env->lsu; + break; + case 0x50: // I-MMU regs + { + int reg = (T0 >> 3) & 0xf; + + ret = env->immuregs[reg]; + break; + } + case 0x51: // I-MMU 8k TSB pointer + case 0x52: // I-MMU 64k TSB pointer + case 0x55: // I-MMU data access + case 0x56: // I-MMU tag read + break; + case 0x58: // D-MMU regs + { + int reg = (T0 >> 3) & 0xf; + + ret = env->dmmuregs[reg]; + break; + } + case 0x59: // D-MMU 8k TSB pointer + case 0x5a: // D-MMU 64k TSB pointer + case 0x5b: // D-MMU data pointer + case 0x5d: // D-MMU data access + case 0x5e: // D-MMU tag read + break; + case 0x54: // I-MMU data in, WO + case 0x57: // I-MMU demap, WO + case 0x5c: // D-MMU data in, WO + case 0x5f: // D-MMU demap, WO + default: + ret = 0; + break; + } + T1 = ret; +} + +void helper_st_asi(int asi, int size, int sign) +{ + if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) + raise_exception(TT_PRIV_INSN); + + switch(asi) { + case 0x14: // Bypass + case 0x15: // Bypass, non-cacheable + { + target_ulong temp = T1; + if (size == 8) + tswap64s(&temp); + else if (size == 4) + tswap32s((uint32_t *)&temp); + else if (size == 2) + tswap16s((uint16_t *)&temp); + cpu_physical_memory_write(T0, (void *) &temp, size); + } + return; + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE + // XXX + return; + case 0x45: // LSU + { + uint64_t oldreg; + + oldreg = env->lsu; + env->lsu = T1 & (DMMU_E | IMMU_E); + // Mappings generated during D/I MMU disabled mode are + // invalid in normal mode + if (oldreg != env->lsu) + tlb_flush(env, 1); + return; + } + case 0x50: // I-MMU regs + { + int reg = (T0 >> 3) & 0xf; + uint64_t oldreg; + + oldreg = env->immuregs[reg]; + switch(reg) { + case 0: // RO + case 4: + return; + case 1: // Not in I-MMU + case 2: + case 7: + case 8: + return; + case 3: // SFSR + if ((T1 & 1) == 0) + T1 = 0; // Clear SFSR + break; + case 5: // TSB access + case 6: // Tag access + default: + break; + } + env->immuregs[reg] = T1; +#ifdef DEBUG_MMU + if (oldreg != env->immuregs[reg]) { + printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->immuregs[reg]); + } + dump_mmu(); +#endif + return; + } + case 0x54: // I-MMU data in + { + unsigned int i; + + // Try finding an invalid entry + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) { + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } + } + // Try finding an unlocked entry + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x40) == 0) { + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } + } + // error state? + return; + } + case 0x55: // I-MMU data access + { + unsigned int i = (T0 >> 3) & 0x3f; + + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } + case 0x57: // I-MMU demap + return; + case 0x58: // D-MMU regs + { + int reg = (T0 >> 3) & 0xf; + uint64_t oldreg; + + oldreg = env->dmmuregs[reg]; + switch(reg) { + case 0: // RO + case 4: + return; + case 3: // SFSR + if ((T1 & 1) == 0) { + T1 = 0; // Clear SFSR, Fault address + env->dmmuregs[4] = 0; + } + env->dmmuregs[reg] = T1; + break; + case 1: // Primary context + case 2: // Secondary context + case 5: // TSB access + case 6: // Tag access + case 7: // Virtual Watchpoint + case 8: // Physical Watchpoint + default: + break; + } + env->dmmuregs[reg] = T1; +#ifdef DEBUG_MMU + if (oldreg != env->dmmuregs[reg]) { + printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->dmmuregs[reg]); + } + dump_mmu(); +#endif + return; + } + case 0x5c: // D-MMU data in + { + unsigned int i; + + // Try finding an invalid entry + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) { + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } + } + // Try finding an unlocked entry + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x40) == 0) { + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } + } + // error state? + return; + } + case 0x5d: // D-MMU data access + { + unsigned int i = (T0 >> 3) & 0x3f; + + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } + case 0x5f: // D-MMU demap + return; + case 0x51: // I-MMU 8k TSB pointer, RO + case 0x52: // I-MMU 64k TSB pointer, RO + case 0x56: // I-MMU tag read, RO + case 0x59: // D-MMU 8k TSB pointer, RO + case 0x5a: // D-MMU 64k TSB pointer, RO + case 0x5b: // D-MMU data pointer, RO + case 0x5e: // D-MMU tag read, RO + default: + return; + } +} + +#endif + +#ifndef TARGET_SPARC64 void helper_rett() { unsigned int cwp; @@ -247,6 +640,7 @@ void helper_rett() set_cwp(cwp); env->psrs = env->psrps; } +#endif void helper_ldfsr(void) { @@ -288,6 +682,7 @@ void helper_debug() cpu_loop_exit(); } +#ifndef TARGET_SPARC64 void do_wrpsr() { PUT_PSR(env, T0); @@ -297,3 +692,16 @@ void do_rdpsr() { T0 = GET_PSR(env); } + +#else + +void do_popc() +{ + T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL); + T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL); + T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL); + T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL); + T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL); + T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL); +} +#endif diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 9f6ecefd8..2407c15d8 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -2,9 +2,15 @@ #define SPARC_LD_OP(name, qp) \ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ { \ - T1 = glue(qp, MEMSUFFIX)(T0); \ + T1 = (target_ulong)glue(qp, MEMSUFFIX)(T0); \ } +#define SPARC_LD_OP_S(name, qp) \ + void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ + { \ + T1 = (target_long)glue(qp, MEMSUFFIX)(T0); \ + } + #define SPARC_ST_OP(name, op) \ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ { \ @@ -14,8 +20,8 @@ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ SPARC_LD_OP(ld, ldl); SPARC_LD_OP(ldub, ldub); SPARC_LD_OP(lduh, lduw); -SPARC_LD_OP(ldsb, ldsb); -SPARC_LD_OP(ldsh, ldsw); +SPARC_LD_OP_S(ldsb, ldsb); +SPARC_LD_OP_S(ldsh, ldsw); /*** Integer store ***/ SPARC_ST_OP(st, stl); @@ -68,4 +74,51 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (void) { DT0 = glue(ldfq, MEMSUFFIX)(T0); } + +#ifdef TARGET_SPARC64 +/* XXX: Should be Atomically */ +/* XXX: There are no cas[x] instructions, only cas[x]a */ +void OPPROTO glue(op_cas, MEMSUFFIX)(void) +{ + uint32_t tmp; + + tmp = glue(ldl, MEMSUFFIX)(T0); + T2 &= 0xffffffffULL; + if (tmp == (T1 & 0xffffffffULL)) { + glue(stl, MEMSUFFIX)(T0, T2); + } + T2 = tmp; +} + +void OPPROTO glue(op_casx, MEMSUFFIX)(void) +{ + uint64_t tmp; + + // XXX + tmp = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32; + tmp |= glue(ldl, MEMSUFFIX)(T0); + if (tmp == T1) { + glue(stq, MEMSUFFIX)(T0, T2); + } + T2 = tmp; +} + +void OPPROTO glue(op_ldsw, MEMSUFFIX)(void) +{ + T1 = (int64_t)glue(ldl, MEMSUFFIX)(T0); +} + +void OPPROTO glue(op_ldx, MEMSUFFIX)(void) +{ + // XXX + T1 = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32; + T1 |= glue(ldl, MEMSUFFIX)(T0); +} + +void OPPROTO glue(op_stx, MEMSUFFIX)(void) +{ + glue(stl, MEMSUFFIX)(T0, T1 >> 32); + glue(stl, MEMSUFFIX)(T0, T1 & 0xffffffff); +} +#endif #undef MEMSUFFIX diff --git a/target-sparc/translate.c b/target-sparc/translate.c index f93c3b1ca..e1c02725f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2,7 +2,7 @@ SPARC translation Copyright (C) 2003 Thomas M. Ogrisegg - Copyright (C) 2003 Fabrice Bellard + 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 @@ -22,12 +22,12 @@ /* TODO-list: + Rest of V9 instructions, VIS instructions NPC/PC static optimisations (use JUMP_TB when possible) - FPU-Instructions - Privileged instructions - Coprocessor-Instructions Optimize synthetic instructions - Optional alignment and privileged instruction check + Optional alignment check + 128-bit float + Tagged add/sub */ #include @@ -69,9 +69,29 @@ enum { #include "gen-op.h" +// This function uses non-native bit order #define GET_FIELD(X, FROM, TO) \ ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) +// This function uses the order in the manuals, i.e. bit 0 is 2^0 +#define GET_FIELD_SP(X, FROM, TO) \ + GET_FIELD(X, 31 - (TO), 31 - (FROM)) + +#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) +#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), 32 - ((b) - (a) + 1)) + +#ifdef TARGET_SPARC64 +#define DFPREG(r) (((r & 1) << 6) | (r & 0x1e)) +#else +#define DFPREG(r) (r) +#endif + +static int sign_extend(int x, int len) +{ + len = 32 - len; + return (x << len) >> len; +} + #define IS_IMM (insn & (1<<13)) static void disas_sparc_insn(DisasContext * dc); @@ -258,6 +278,34 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] = { gen_op_movl_T2_im }; +// Sign extending version +static GenOpFunc1 * const gen_op_movl_TN_sim[3] = { + gen_op_movl_T0_sim, + gen_op_movl_T1_sim, + gen_op_movl_T2_sim +}; + +#ifdef TARGET_SPARC64 +#define GEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [64] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +NAME ## 32, 0, NAME ## 34, 0, NAME ## 36, 0, NAME ## 38, 0, \ +NAME ## 40, 0, NAME ## 42, 0, NAME ## 44, 0, NAME ## 46, 0, \ +NAME ## 48, 0, NAME ## 50, 0, NAME ## 52, 0, NAME ## 54, 0, \ +NAME ## 56, 0, NAME ## 58, 0, NAME ## 60, 0, NAME ## 62, 0, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} +#else #define GEN32(func, NAME) \ static GenOpFunc *NAME ## _table [32] = { \ NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ @@ -273,22 +321,77 @@ static inline void func(int n) \ { \ NAME ## _table[n](); \ } +#endif /* floating point registers moves */ GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fprf); GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fprf); -GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fprf); GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fprf); GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fprf); -GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fprf); GEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fprf); GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); -GEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fprf); GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); -GEN32(gen_op_store_DT2_fpr, gen_op_store_DT2_fpr_fprf); +#ifdef TARGET_SPARC64 +// 'a' versions allowed to user depending on asi +#if defined(CONFIG_USER_ONLY) +#define supervisor(dc) 0 +#define gen_op_ldst(name) gen_op_##name##_raw() +#define OP_LD_TABLE(width) \ + static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ + { \ + int asi, offset; \ + \ + if (IS_IMM) { \ + offset = GET_FIELD(insn, 25, 31); \ + if (is_ld) \ + gen_op_ld_asi_reg(offset, size, sign); \ + else \ + gen_op_st_asi_reg(offset, size, sign); \ + return; \ + } \ + asi = GET_FIELD(insn, 19, 26); \ + switch (asi) { \ + case 0x80: /* Primary address space */ \ + gen_op_##width##_raw(); \ + break; \ + default: \ + break; \ + } \ + } + +#else +#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() +#define OP_LD_TABLE(width) \ + static GenOpFunc *gen_op_##width[] = { \ + &gen_op_##width##_user, \ + &gen_op_##width##_kernel, \ + }; \ + \ + static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ + { \ + int asi, offset; \ + \ + if (IS_IMM) { \ + offset = GET_FIELD(insn, 25, 31); \ + if (is_ld) \ + gen_op_ld_asi_reg(offset, size, sign); \ + else \ + gen_op_st_asi_reg(offset, size, sign); \ + return; \ + } \ + asi = GET_FIELD(insn, 19, 26); \ + if (is_ld) \ + gen_op_ld_asi(asi, size, sign); \ + else \ + gen_op_st_asi(asi, size, sign); \ + } + +#define supervisor(dc) (dc->mem_idx == 1) +#endif +#else #if defined(CONFIG_USER_ONLY) #define gen_op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -330,6 +433,7 @@ static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ #define supervisor(dc) (dc->mem_idx == 1) #endif +#endif OP_LD_TABLE(ld); OP_LD_TABLE(st); @@ -348,21 +452,44 @@ OP_LD_TABLE(stdf); OP_LD_TABLE(ldf); OP_LD_TABLE(lddf); -static inline void gen_movl_imm_TN(int reg, int imm) +#ifdef TARGET_SPARC64 +OP_LD_TABLE(ldsw); +OP_LD_TABLE(ldx); +OP_LD_TABLE(stx); +OP_LD_TABLE(cas); +OP_LD_TABLE(casx); +#endif + +static inline void gen_movl_imm_TN(int reg, uint32_t imm) { gen_op_movl_TN_im[reg] (imm); } -static inline void gen_movl_imm_T1(int val) +static inline void gen_movl_imm_T1(uint32_t val) { gen_movl_imm_TN(1, val); } -static inline void gen_movl_imm_T0(int val) +static inline void gen_movl_imm_T0(uint32_t val) { gen_movl_imm_TN(0, val); } +static inline void gen_movl_simm_TN(int reg, int32_t imm) +{ + gen_op_movl_TN_sim[reg](imm); +} + +static inline void gen_movl_simm_T1(int32_t val) +{ + gen_movl_simm_TN(1, val); +} + +static inline void gen_movl_simm_T0(int32_t val) +{ + gen_movl_simm_TN(0, val); +} + static inline void gen_movl_reg_TN(int reg, int t) { if (reg) @@ -411,19 +538,45 @@ static inline void flush_T2(DisasContext * dc) } } +static inline void gen_jmp_im(target_ulong pc) +{ +#ifdef TARGET_SPARC64 + if (pc == (uint32_t)pc) { + gen_op_jmp_im(pc); + } else { + gen_op_jmp_im64(pc >> 32, pc); + } +#else + gen_op_jmp_im(pc); +#endif +} + +static inline void gen_movl_npc_im(target_ulong npc) +{ +#ifdef TARGET_SPARC64 + if (npc == (uint32_t)npc) { + gen_op_movl_npc_im(npc); + } else { + gen_op_movq_npc_im64(npc >> 32, npc); + } +#else + gen_op_movl_npc_im(npc); +#endif +} + static inline void save_npc(DisasContext * dc) { if (dc->npc == JUMP_PC) { gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); dc->npc = DYNAMIC_PC; } else if (dc->npc != DYNAMIC_PC) { - gen_op_movl_npc_im(dc->npc); + gen_movl_npc_im(dc->npc); } } static inline void save_state(DisasContext * dc) { - gen_op_jmp_im(dc->pc); + gen_jmp_im(dc->pc); save_npc(dc); } @@ -441,110 +594,159 @@ static inline void gen_mov_pc_npc(DisasContext * dc) } } -static void gen_cond(int cond) -{ - switch (cond) { - case 0x1: - gen_op_eval_be(); - break; - case 0x2: - gen_op_eval_ble(); - break; - case 0x3: - gen_op_eval_bl(); - break; - case 0x4: - gen_op_eval_bleu(); - break; - case 0x5: - gen_op_eval_bcs(); - break; - case 0x6: - gen_op_eval_bneg(); - break; - case 0x7: - gen_op_eval_bvs(); - break; - case 0x9: - gen_op_eval_bne(); - break; - case 0xa: - gen_op_eval_bg(); - break; - case 0xb: - gen_op_eval_bge(); - break; - case 0xc: - gen_op_eval_bgu(); - break; - case 0xd: - gen_op_eval_bcc(); - break; - case 0xe: - gen_op_eval_bpos(); - break; - default: - case 0xf: - gen_op_eval_bvc(); - break; - } -} +static GenOpFunc * const gen_cond[2][16] = { + { + gen_op_eval_ba, + gen_op_eval_be, + gen_op_eval_ble, + gen_op_eval_bl, + gen_op_eval_bleu, + gen_op_eval_bcs, + gen_op_eval_bneg, + gen_op_eval_bvs, + gen_op_eval_bn, + gen_op_eval_bne, + gen_op_eval_bg, + gen_op_eval_bge, + gen_op_eval_bgu, + gen_op_eval_bcc, + gen_op_eval_bpos, + gen_op_eval_bvc, + }, + { +#ifdef TARGET_SPARC64 + gen_op_eval_ba, + gen_op_eval_xbe, + gen_op_eval_xble, + gen_op_eval_xbl, + gen_op_eval_xbleu, + gen_op_eval_xbcs, + gen_op_eval_xbneg, + gen_op_eval_xbvs, + gen_op_eval_bn, + gen_op_eval_xbne, + gen_op_eval_xbg, + gen_op_eval_xbge, + gen_op_eval_xbgu, + gen_op_eval_xbcc, + gen_op_eval_xbpos, + gen_op_eval_xbvc, +#endif + }, +}; + +static GenOpFunc * const gen_fcond[4][16] = { + { + gen_op_eval_ba, + gen_op_eval_fbne, + gen_op_eval_fblg, + gen_op_eval_fbul, + gen_op_eval_fbl, + gen_op_eval_fbug, + gen_op_eval_fbg, + gen_op_eval_fbu, + gen_op_eval_bn, + gen_op_eval_fbe, + gen_op_eval_fbue, + gen_op_eval_fbge, + gen_op_eval_fbuge, + gen_op_eval_fble, + gen_op_eval_fbule, + gen_op_eval_fbo, + }, +#ifdef TARGET_SPARC64 + { + gen_op_eval_ba, + gen_op_eval_fbne_fcc1, + gen_op_eval_fblg_fcc1, + gen_op_eval_fbul_fcc1, + gen_op_eval_fbl_fcc1, + gen_op_eval_fbug_fcc1, + gen_op_eval_fbg_fcc1, + gen_op_eval_fbu_fcc1, + gen_op_eval_bn, + gen_op_eval_fbe_fcc1, + gen_op_eval_fbue_fcc1, + gen_op_eval_fbge_fcc1, + gen_op_eval_fbuge_fcc1, + gen_op_eval_fble_fcc1, + gen_op_eval_fbule_fcc1, + gen_op_eval_fbo_fcc1, + }, + { + gen_op_eval_ba, + gen_op_eval_fbne_fcc2, + gen_op_eval_fblg_fcc2, + gen_op_eval_fbul_fcc2, + gen_op_eval_fbl_fcc2, + gen_op_eval_fbug_fcc2, + gen_op_eval_fbg_fcc2, + gen_op_eval_fbu_fcc2, + gen_op_eval_bn, + gen_op_eval_fbe_fcc2, + gen_op_eval_fbue_fcc2, + gen_op_eval_fbge_fcc2, + gen_op_eval_fbuge_fcc2, + gen_op_eval_fble_fcc2, + gen_op_eval_fbule_fcc2, + gen_op_eval_fbo_fcc2, + }, + { + gen_op_eval_ba, + gen_op_eval_fbne_fcc3, + gen_op_eval_fblg_fcc3, + gen_op_eval_fbul_fcc3, + gen_op_eval_fbl_fcc3, + gen_op_eval_fbug_fcc3, + gen_op_eval_fbg_fcc3, + gen_op_eval_fbu_fcc3, + gen_op_eval_bn, + gen_op_eval_fbe_fcc3, + gen_op_eval_fbue_fcc3, + gen_op_eval_fbge_fcc3, + gen_op_eval_fbuge_fcc3, + gen_op_eval_fble_fcc3, + gen_op_eval_fbule_fcc3, + gen_op_eval_fbo_fcc3, + }, +#else + {}, {}, {}, +#endif +}; -static void gen_fcond(int cond) +#ifdef TARGET_SPARC64 +static void gen_cond_reg(int cond) { switch (cond) { case 0x1: - gen_op_eval_fbne(); + gen_op_eval_brz(); break; case 0x2: - gen_op_eval_fblg(); + gen_op_eval_brlez(); break; case 0x3: - gen_op_eval_fbul(); - break; - case 0x4: - gen_op_eval_fbl(); + gen_op_eval_brlz(); break; case 0x5: - gen_op_eval_fbug(); + gen_op_eval_brnz(); break; case 0x6: - gen_op_eval_fbg(); - break; - case 0x7: - gen_op_eval_fbu(); - break; - case 0x9: - gen_op_eval_fbe(); - break; - case 0xa: - gen_op_eval_fbue(); - break; - case 0xb: - gen_op_eval_fbge(); - break; - case 0xc: - gen_op_eval_fbuge(); - break; - case 0xd: - gen_op_eval_fble(); - break; - case 0xe: - gen_op_eval_fbule(); + gen_op_eval_brgz(); break; default: - case 0xf: - gen_op_eval_fbo(); + case 0x7: + gen_op_eval_brgez(); break; } } +#endif /* XXX: potentially incorrect if dynamic npc */ -static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn) +static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; - + if (cond == 0x0) { /* unconditional not taken */ if (a) { @@ -565,7 +767,7 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn) } } else { flush_T2(dc); - gen_cond(cond); + gen_cond[cc][cond](); if (a) { gen_op_branch_a((long)dc->tb, target, dc->npc); dc->is_br = 1; @@ -579,7 +781,7 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn) } /* XXX: potentially incorrect if dynamic npc */ -static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn) +static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -604,7 +806,7 @@ static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn) } } else { flush_T2(dc); - gen_fcond(cond); + gen_fcond[cc][cond](); if (a) { gen_op_branch_a((long)dc->tb, target, dc->npc); dc->is_br = 1; @@ -617,14 +819,41 @@ static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn) } } -#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) - -static int sign_extend(int x, int len) +#ifdef TARGET_SPARC64 +/* XXX: potentially incorrect if dynamic npc */ +static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn) { - len = 32 - len; - return (x << len) >> len; + unsigned int cond = GET_FIELD_SP(insn, 25, 27), a = (insn & (1 << 29)); + target_ulong target = dc->pc + offset; + + flush_T2(dc); + gen_cond_reg(cond); + if (a) { + gen_op_branch_a((long)dc->tb, target, dc->npc); + dc->is_br = 1; + } else { + dc->pc = dc->npc; + dc->jump_pc[0] = target; + dc->jump_pc[1] = dc->npc + 4; + dc->npc = JUMP_PC; + } } +static GenOpFunc * const gen_fcmps[4] = { + gen_op_fcmps, + gen_op_fcmps_fcc1, + gen_op_fcmps_fcc2, + gen_op_fcmps_fcc3, +}; + +static GenOpFunc * const gen_fcmpd[4] = { + gen_op_fcmpd, + gen_op_fcmpd_fcc1, + gen_op_fcmpd_fcc2, + gen_op_fcmpd_fcc3, +}; +#endif + /* before an instruction, dc->pc must be static */ static void disas_sparc_insn(DisasContext * dc) { @@ -639,19 +868,54 @@ static void disas_sparc_insn(DisasContext * dc) { unsigned int xop = GET_FIELD(insn, 7, 9); int32_t target; - target = GET_FIELD(insn, 10, 31); switch (xop) { - case 0x0: /* UNIMPL */ +#ifdef TARGET_SPARC64 case 0x1: /* V9 BPcc */ + { + int cc; + + target = GET_FIELD_SP(insn, 0, 18); + target <<= 2; + target = sign_extend(target, 18); + cc = GET_FIELD_SP(insn, 20, 21); + if (cc == 0) + do_branch(dc, target, insn, 0); + else if (cc == 2) + do_branch(dc, target, insn, 1); + else + goto illegal_insn; + goto jmp_insn; + } case 0x3: /* V9 BPr */ + { + target = GET_FIELD_SP(insn, 0, 13) | + (GET_FIELD_SP(insn, 20, 21) >> 7); + target <<= 2; + target = sign_extend(target, 16); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_T0_reg(rs1); + do_branch_reg(dc, target, insn); + goto jmp_insn; + } case 0x5: /* V9 FBPcc */ - default: - goto illegal_insn; + { + int cc = GET_FIELD_SP(insn, 20, 21); +#if !defined(CONFIG_USER_ONLY) + gen_op_trap_ifnofpu(); +#endif + target = GET_FIELD_SP(insn, 0, 18); + target <<= 2; + target = sign_extend(target, 19); + do_fbranch(dc, target, insn, cc); + goto jmp_insn; + } +#endif case 0x2: /* BN+x */ { + target = GET_FIELD(insn, 10, 31); target <<= 2; target = sign_extend(target, 22); - do_branch(dc, target, insn); + do_branch(dc, target, insn, 0); goto jmp_insn; } case 0x6: /* FBN+x */ @@ -659,9 +923,10 @@ static void disas_sparc_insn(DisasContext * dc) #if !defined(CONFIG_USER_ONLY) gen_op_trap_ifnofpu(); #endif + target = GET_FIELD(insn, 10, 31); target <<= 2; target = sign_extend(target, 22); - do_fbranch(dc, target, insn); + do_fbranch(dc, target, insn, 0); goto jmp_insn; } case 0x4: /* SETHI */ @@ -669,12 +934,16 @@ static void disas_sparc_insn(DisasContext * dc) #if defined(OPTIM) if (rd) { // nop #endif - gen_movl_imm_T0(target << 10); + uint32_t value = GET_FIELD(insn, 10, 31); + gen_movl_imm_T0(value << 10); gen_movl_T0_reg(rd); #if defined(OPTIM) } #endif break; + case 0x0: /* UNIMPL */ + default: + goto illegal_insn; } break; } @@ -695,6 +964,7 @@ static void disas_sparc_insn(DisasContext * dc) unsigned int xop = GET_FIELD(insn, 7, 12); if (xop == 0x3a) { /* generate trap */ int cond; + rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); if (IS_IMM) { @@ -702,7 +972,7 @@ static void disas_sparc_insn(DisasContext * dc) #if defined(OPTIM) if (rs2 != 0) { #endif - gen_movl_imm_T1(rs2); + gen_movl_simm_T1(rs2); gen_op_add_T1_T0(); #if defined(OPTIM) } @@ -719,51 +989,141 @@ static void disas_sparc_insn(DisasContext * dc) #endif } save_state(dc); - /* V9 icc/xcc */ cond = GET_FIELD(insn, 3, 6); if (cond == 0x8) { gen_op_trap_T0(); dc->is_br = 1; goto jmp_insn; } else if (cond != 0) { - gen_cond(cond); +#ifdef TARGET_SPARC64 + /* V9 icc/xcc */ + int cc = GET_FIELD_SP(insn, 11, 12); + if (cc == 0) + gen_cond[0][cond](); + else if (cc == 2) + gen_cond[1][cond](); + else + goto illegal_insn; +#else + gen_cond[0][cond](); +#endif gen_op_trapcc_T0(); } } else if (xop == 0x28) { rs1 = GET_FIELD(insn, 13, 17); switch(rs1) { case 0: /* rdy */ - gen_op_rdy(); + gen_op_movtl_T0_env(offsetof(CPUSPARCState, y)); gen_movl_T0_reg(rd); break; case 15: /* stbar / V9 membar */ break; /* no effect? */ - default: +#ifdef TARGET_SPARC64 case 0x2: /* V9 rdccr */ + gen_op_rdccr(); + gen_movl_T0_reg(rd); + break; case 0x3: /* V9 rdasi */ + gen_op_movl_T0_env(offsetof(CPUSPARCState, asi)); + gen_movl_T0_reg(rd); + break; case 0x4: /* V9 rdtick */ + gen_op_rdtick(); + gen_movl_T0_reg(rd); + break; case 0x5: /* V9 rdpc */ + gen_op_movl_T0_im(dc->pc); + gen_movl_T0_reg(rd); + break; case 0x6: /* V9 rdfprs */ + gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs)); + gen_movl_T0_reg(rd); + break; +#endif + default: goto illegal_insn; } #if !defined(CONFIG_USER_ONLY) - } else if (xop == 0x29) { +#ifndef TARGET_SPARC64 + } else if (xop == 0x29) { /* rdpsr / V9 unimp */ if (!supervisor(dc)) goto priv_insn; gen_op_rdpsr(); gen_movl_T0_reg(rd); break; - } else if (xop == 0x2a) { +#endif + } else if (xop == 0x2a) { /* rdwim / V9 rdpr */ if (!supervisor(dc)) goto priv_insn; - gen_op_rdwim(); +#ifdef TARGET_SPARC64 + rs1 = GET_FIELD(insn, 13, 17); + switch (rs1) { + case 0: // tpc + gen_op_rdtpc(); + break; + case 1: // tnpc + gen_op_rdtnpc(); + break; + case 2: // tstate + gen_op_rdtstate(); + break; + case 3: // tt + gen_op_rdtt(); + break; + case 4: // tick + gen_op_rdtick(); + break; + case 5: // tba + gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); + break; + case 6: // pstate + gen_op_rdpstate(); + break; + case 7: // tl + gen_op_movl_T0_env(offsetof(CPUSPARCState, tl)); + break; + case 8: // pil + gen_op_movl_T0_env(offsetof(CPUSPARCState, psrpil)); + break; + case 9: // cwp + gen_op_rdcwp(); + break; + case 10: // cansave + gen_op_movl_T0_env(offsetof(CPUSPARCState, cansave)); + break; + case 11: // canrestore + gen_op_movl_T0_env(offsetof(CPUSPARCState, canrestore)); + break; + case 12: // cleanwin + gen_op_movl_T0_env(offsetof(CPUSPARCState, cleanwin)); + break; + case 13: // otherwin + gen_op_movl_T0_env(offsetof(CPUSPARCState, otherwin)); + break; + case 14: // wstate + gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate)); + break; + case 31: // ver + gen_op_movtl_T0_env(offsetof(CPUSPARCState, version)); + break; + case 15: // fq + default: + goto illegal_insn; + } +#else + gen_op_movl_T0_env(offsetof(CPUSPARCState, wim)); +#endif gen_movl_T0_reg(rd); break; - } else if (xop == 0x2b) { + } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ +#ifdef TARGET_SPARC64 + gen_op_flushw(); +#else if (!supervisor(dc)) goto priv_insn; - gen_op_rdtbr(); + gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); gen_movl_T0_reg(rd); +#endif break; #endif } else if (xop == 0x34) { /* FPU Operations */ @@ -794,9 +1154,9 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x2a: /* fsqrtd */ - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fsqrtd(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x2b: /* fsqrtq */ goto nfpu_insn; @@ -807,10 +1167,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x42: - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_faddd(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x43: /* faddq */ goto nfpu_insn; @@ -821,10 +1181,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x46: - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fsubd(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x47: /* fsubq */ goto nfpu_insn; @@ -835,8 +1195,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x4a: - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmuld(); gen_op_store_DT0_fpr(rd); break; @@ -849,10 +1209,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x4e: - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fdivd(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x4f: /* fdivq */ goto nfpu_insn; @@ -860,7 +1220,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); gen_op_fsmuld(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x6e: /* fdmulq */ goto nfpu_insn; @@ -870,7 +1230,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0xc6: - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fdtos(); gen_op_store_FT0_fpr(rd); break; @@ -879,12 +1239,12 @@ static void disas_sparc_insn(DisasContext * dc) case 0xc8: gen_op_load_fpr_FT1(rs2); gen_op_fitod(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0xc9: gen_op_load_fpr_FT1(rs2); gen_op_fstod(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0xcb: /* fqtod */ goto nfpu_insn; @@ -906,55 +1266,248 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0xd3: /* fqtoi */ goto nfpu_insn; - default: +#ifdef TARGET_SPARC64 case 0x2: /* V9 fmovd */ + gen_op_load_fpr_DT0(DFPREG(rs2)); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; case 0x6: /* V9 fnegd */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fnegd(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; case 0xa: /* V9 fabsd */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fabsd(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; case 0x81: /* V9 fstox */ + gen_op_load_fpr_FT1(rs2); + gen_op_fstox(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; case 0x82: /* V9 fdtox */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fdtox(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; case 0x84: /* V9 fxtos */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fxtos(); + gen_op_store_FT0_fpr(rd); + break; case 0x88: /* V9 fxtod */ - + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fxtod(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; case 0x3: /* V9 fmovq */ case 0x7: /* V9 fnegq */ case 0xb: /* V9 fabsq */ case 0x83: /* V9 fqtox */ case 0x8c: /* V9 fxtoq */ + goto nfpu_insn; +#endif + default: goto illegal_insn; } } else if (xop == 0x35) { /* FPU Operations */ +#ifdef TARGET_SPARC64 + int cond; +#endif #if !defined(CONFIG_USER_ONLY) gen_op_trap_ifnofpu(); #endif rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); - /* V9 fmovscc: x5, cond = x >> 1 */ - /* V9 fmovdcc: x6, cond = x >> 1 */ - - /* V9 fmovqcc: x7, cond = x >> 1 */ +#ifdef TARGET_SPARC64 + if ((xop & 0x11f) == 0x005) { // V9 fmovsr + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + flush_T2(dc); + gen_cond_reg(cond); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + gen_cond_reg(cond); + gen_op_fmovs_cc(); + gen_op_store_DT0_fpr(rd); + break; + } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr + goto nfpu_insn; + } +#endif switch (xop) { - case 0x51: +#ifdef TARGET_SPARC64 + case 0x001: /* V9 fmovscc %fcc0 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_fcond[0][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x002: /* V9 fmovdcc %fcc0 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_fcond[0][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x003: /* V9 fmovqcc %fcc0 */ + goto nfpu_insn; + case 0x041: /* V9 fmovscc %fcc1 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_fcond[1][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x042: /* V9 fmovdcc %fcc1 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_fcond[1][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x043: /* V9 fmovqcc %fcc1 */ + goto nfpu_insn; + case 0x081: /* V9 fmovscc %fcc2 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_fcond[2][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x082: /* V9 fmovdcc %fcc2 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_fcond[2][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x083: /* V9 fmovqcc %fcc2 */ + goto nfpu_insn; + case 0x0c1: /* V9 fmovscc %fcc3 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_fcond[3][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x0c2: /* V9 fmovdcc %fcc3 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_fcond[3][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x0c3: /* V9 fmovqcc %fcc3 */ + goto nfpu_insn; + case 0x101: /* V9 fmovscc %icc */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_cond[0][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x102: /* V9 fmovdcc %icc */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_cond[0][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x103: /* V9 fmovqcc %icc */ + goto nfpu_insn; + case 0x181: /* V9 fmovscc %xcc */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_cond[1][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x182: /* V9 fmovdcc %xcc */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_cond[1][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x183: /* V9 fmovqcc %xcc */ + goto nfpu_insn; +#endif + case 0x51: /* V9 %fcc */ gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); +#ifdef TARGET_SPARC64 + gen_fcmps[rd & 3](); +#else gen_op_fcmps(); +#endif break; - case 0x52: - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + case 0x52: /* V9 %fcc */ + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); +#ifdef TARGET_SPARC64 + gen_fcmpd[rd & 3](); +#else gen_op_fcmpd(); +#endif break; case 0x53: /* fcmpq */ goto nfpu_insn; - case 0x55: /* fcmpes */ + case 0x55: /* fcmpes, V9 %fcc */ gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); +#ifdef TARGET_SPARC64 + gen_fcmps[rd & 3](); +#else gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */ +#endif break; - case 0x56: /* fcmped */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + case 0x56: /* fcmped, V9 %fcc */ + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); +#ifdef TARGET_SPARC64 + gen_fcmpd[rd & 3](); +#else gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */ +#endif break; case 0x57: /* fcmpeq */ goto nfpu_insn; @@ -970,7 +1523,7 @@ static void disas_sparc_insn(DisasContext * dc) // or %g0, x, y -> mov T1, x; mov y, T1 if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); - gen_movl_imm_T1(rs2); + gen_movl_simm_T1(rs2); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); @@ -982,7 +1535,7 @@ static void disas_sparc_insn(DisasContext * dc) // or x, #0, y -> mov T1, x; mov y, T1 rs2 = GET_FIELDs(insn, 19, 31); if (rs2 != 0) { - gen_movl_imm_T1(rs2); + gen_movl_simm_T1(rs2); gen_op_or_T1_T0(); } } else { /* register */ @@ -1001,7 +1554,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); - gen_movl_imm_T1(rs2); + gen_movl_simm_T1(rs2); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); @@ -1083,13 +1636,21 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_div_cc(); break; default: - case 0x9: /* V9 mulx */ - case 0xd: /* V9 udivx */ goto illegal_insn; } gen_movl_T0_reg(rd); } else { switch (xop) { +#ifdef TARGET_SPARC64 + case 0x9: /* V9 mulx */ + gen_op_mulx_T1_T0(); + gen_movl_T0_reg(rd); + break; + case 0xd: /* V9 udivx */ + gen_op_udivx_T1_T0(); + gen_movl_T0_reg(rd); + break; +#endif case 0x20: /* taddcc */ case 0x21: /* tsubcc */ case 0x22: /* taddcctv */ @@ -1099,30 +1660,67 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_mulscc_T1_T0(); gen_movl_T0_reg(rd); break; - case 0x25: /* sll, V9 sllx */ - gen_op_sll(); + case 0x25: /* sll, V9 sllx ( == sll) */ + gen_op_sll(); gen_movl_T0_reg(rd); break; case 0x26: /* srl, V9 srlx */ - gen_op_srl(); +#ifdef TARGET_SPARC64 + if (insn & (1 << 12)) + gen_op_srlx(); + else + gen_op_srl(); +#else + gen_op_srl(); +#endif gen_movl_T0_reg(rd); break; case 0x27: /* sra, V9 srax */ - gen_op_sra(); +#ifdef TARGET_SPARC64 + if (insn & (1 << 12)) + gen_op_srax(); + else + gen_op_sra(); +#else + gen_op_sra(); +#endif gen_movl_T0_reg(rd); break; case 0x30: { - gen_op_xor_T1_T0(); switch(rd) { - case 0: - gen_op_wry(); + case 0: /* wry */ + gen_op_xor_T1_T0(); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, y)); break; - default: +#ifdef TARGET_SPARC64 case 0x2: /* V9 wrccr */ + gen_op_wrccr(); + break; case 0x3: /* V9 wrasi */ + gen_op_movl_env_T0(offsetof(CPUSPARCState, asi)); + break; case 0x6: /* V9 wrfprs */ - case 0xf: /* V9 sir */ + gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs)); + break; + case 0xf: /* V9 sir, nop if user */ +#if !defined(CONFIG_USER_ONLY) + if (supervisor(dc)) + gen_op_sir(); +#endif + break; +#endif + case 0x10: /* Performance Control */ + case 0x11: /* Performance Instrumentation Counter */ + case 0x12: /* Dispatch Control */ + case 0x13: /* Graphics Status */ + case 0x14: /* Softint set */ + case 0x15: /* Softint clear */ + case 0x16: /* Softint write */ + case 0x17: /* Tick compare */ + case 0x18: /* System tick */ + case 0x19: /* System tick compare */ + default: goto illegal_insn; } } @@ -1132,8 +1730,21 @@ static void disas_sparc_insn(DisasContext * dc) { if (!supervisor(dc)) goto priv_insn; +#ifdef TARGET_SPARC64 + switch (rd) { + case 0: + gen_op_saved(); + break; + case 1: + gen_op_restored(); + break; + default: + goto illegal_insn; + } +#else gen_op_xor_T1_T0(); gen_op_wrpsr(); +#endif } break; case 0x32: /* wrwim, V9 wrpr */ @@ -1141,28 +1752,179 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; gen_op_xor_T1_T0(); - gen_op_wrwim(); +#ifdef TARGET_SPARC64 + switch (rd) { + case 0: // tpc + gen_op_wrtpc(); + break; + case 1: // tnpc + gen_op_wrtnpc(); + break; + case 2: // tstate + gen_op_wrtstate(); + break; + case 3: // tt + gen_op_wrtt(); + break; + case 4: // tick + gen_op_wrtick(); + break; + case 5: // tba + gen_op_movl_env_T0(offsetof(CPUSPARCState, tbr)); + break; + case 6: // pstate + gen_op_wrpstate(); + break; + case 7: // tl + gen_op_movl_env_T0(offsetof(CPUSPARCState, tl)); + break; + case 8: // pil + gen_op_movl_env_T0(offsetof(CPUSPARCState, psrpil)); + break; + case 9: // cwp + gen_op_wrcwp(); + break; + case 10: // cansave + gen_op_movl_env_T0(offsetof(CPUSPARCState, cansave)); + break; + case 11: // canrestore + gen_op_movl_env_T0(offsetof(CPUSPARCState, canrestore)); + break; + case 12: // cleanwin + gen_op_movl_env_T0(offsetof(CPUSPARCState, cleanwin)); + break; + case 13: // otherwin + gen_op_movl_env_T0(offsetof(CPUSPARCState, otherwin)); + break; + case 14: // wstate + gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate)); + break; + default: + goto illegal_insn; + } +#else + gen_op_movl_env_T0(offsetof(CPUSPARCState, wim)); +#endif } break; - case 0x33: +#ifndef TARGET_SPARC64 + case 0x33: /* wrtbr, V9 unimp */ { if (!supervisor(dc)) goto priv_insn; gen_op_xor_T1_T0(); - gen_op_wrtbr(); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); } break; #endif - default: - case 0x2a: /* V9 rdpr */ - case 0x2b: /* V9 flushw */ +#endif +#ifdef TARGET_SPARC64 case 0x2c: /* V9 movcc */ + { + int cc = GET_FIELD_SP(insn, 11, 12); + int cond = GET_FIELD_SP(insn, 14, 17); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELD_SPs(insn, 0, 10); + gen_movl_simm_T1(rs2); + } + else { + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_T1(rs2); + } + gen_movl_reg_T0(rd); + flush_T2(dc); + if (insn & (1 << 18)) { + if (cc == 0) + gen_cond[0][cond](); + else if (cc == 2) + gen_cond[1][cond](); + else + goto illegal_insn; + } else { + gen_fcond[cc][cond](); + } + gen_op_mov_cc(); + gen_movl_T0_reg(rd); + break; + } case 0x2d: /* V9 sdivx */ + gen_op_sdivx_T1_T0(); + gen_movl_T0_reg(rd); + break; case 0x2e: /* V9 popc */ + { + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELD_SPs(insn, 0, 12); + gen_movl_simm_T1(rs2); + // XXX optimize: popc(constant) + } + else { + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_T1(rs2); + } + gen_op_popc(); + gen_movl_T0_reg(rd); + } case 0x2f: /* V9 movr */ + { + int cond = GET_FIELD_SP(insn, 10, 12); + rs1 = GET_FIELD(insn, 13, 17); + flush_T2(dc); + gen_movl_reg_T0(rs1); + gen_cond_reg(cond); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELD_SPs(insn, 0, 10); + gen_movl_simm_T1(rs2); + } + else { + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_T1(rs2); + } + gen_movl_reg_T0(rd); + gen_op_mov_cc(); + gen_movl_T0_reg(rd); + break; + } + case 0x36: /* UltraSparc shutdown, VIS */ + { + // XXX + } +#endif + default: goto illegal_insn; } } +#ifdef TARGET_SPARC64 + } else if (xop == 0x39) { /* V9 return */ + gen_op_restore(); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); +#if defined(OPTIM) + if (rs2) { +#endif + gen_movl_simm_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } +#endif + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); +#if defined(OPTIM) + if (rs2) { +#endif + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); +#if defined(OPTIM) + } +#endif + } + gen_mov_pc_npc(dc); + gen_op_movl_npc_T0(); + dc->npc = DYNAMIC_PC; + goto jmp_insn; +#endif } else { rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); @@ -1171,7 +1933,7 @@ static void disas_sparc_insn(DisasContext * dc) #if defined(OPTIM) if (rs2) { #endif - gen_movl_imm_T1(rs2); + gen_movl_simm_T1(rs2); gen_op_add_T1_T0(); #if defined(OPTIM) } @@ -1199,7 +1961,7 @@ static void disas_sparc_insn(DisasContext * dc) dc->npc = DYNAMIC_PC; } goto jmp_insn; -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) case 0x39: /* rett, V9 return */ { if (!supervisor(dc)) @@ -1224,8 +1986,27 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_restore(); gen_movl_T0_reg(rd); break; - default: +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) case 0x3e: /* V9 done/retry */ + { + switch (rd) { + case 0: + if (!supervisor(dc)) + goto priv_insn; + gen_op_done(); + break; + case 1: + if (!supervisor(dc)) + goto priv_insn; + gen_op_retry(); + break; + default: + goto illegal_insn; + } + } + break; +#endif + default: goto illegal_insn; } } @@ -1242,7 +2023,7 @@ static void disas_sparc_insn(DisasContext * dc) #if defined(OPTIM) if (rs2 != 0) { #endif - gen_movl_imm_T1(rs2); + gen_movl_simm_T1(rs2); gen_op_add_T1_T0(); #if defined(OPTIM) } @@ -1258,8 +2039,9 @@ static void disas_sparc_insn(DisasContext * dc) } #endif } - if (xop < 4 || (xop > 7 && xop < 0x14) || \ - (xop > 0x17 && xop < 0x20)) { + if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || \ + (xop > 0x17 && xop < 0x1d ) || \ + (xop > 0x2c && xop < 0x33) || xop == 0x1f) { switch (xop) { case 0x0: /* load word */ gen_op_ldst(ld); @@ -1287,72 +2069,115 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T1(rd); gen_op_ldst(swap); break; -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) case 0x10: /* load word alternate */ +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_lda(insn, 1, 4, 0); break; case 0x11: /* load unsigned byte alternate */ +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_lduba(insn, 1, 1, 0); break; case 0x12: /* load unsigned halfword alternate */ +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_lduha(insn, 1, 2, 0); break; case 0x13: /* load double word alternate */ +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_ldda(insn, 1, 8, 0); gen_movl_T0_reg(rd + 1); break; case 0x19: /* load signed byte alternate */ +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_ldsba(insn, 1, 1, 1); break; case 0x1a: /* load signed halfword alternate */ +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_ldsha(insn, 1, 2 ,1); break; case 0x1d: /* ldstuba -- XXX: should be atomically */ +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_ldstuba(insn, 1, 1, 0); break; case 0x1f: /* swap reg with alt. memory. Also atomically */ +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_movl_reg_T1(rd); gen_op_swapa(insn, 1, 4, 0); break; - + +#ifndef TARGET_SPARC64 /* avoid warnings */ (void) &gen_op_stfa; (void) &gen_op_stdfa; (void) &gen_op_ldfa; (void) &gen_op_lddfa; +#else +#if !defined(CONFIG_USER_ONLY) + (void) &gen_op_cas; + (void) &gen_op_casx; #endif - default: +#endif +#endif +#ifdef TARGET_SPARC64 case 0x08: /* V9 ldsw */ + gen_op_ldst(ldsw); + break; case 0x0b: /* V9 ldx */ + gen_op_ldst(ldx); + break; case 0x18: /* V9 ldswa */ + gen_op_ldswa(insn, 1, 4, 1); + break; case 0x1b: /* V9 ldxa */ - case 0x2d: /* V9 prefetch */ + gen_op_ldxa(insn, 1, 8, 0); + break; + case 0x2d: /* V9 prefetch, no effect */ + goto skip_move; case 0x30: /* V9 ldfa */ + gen_op_ldfa(insn, 1, 8, 0); // XXX + break; case 0x33: /* V9 lddfa */ - case 0x3d: /* V9 prefetcha */ + gen_op_lddfa(insn, 1, 8, 0); // XXX + break; + case 0x3d: /* V9 prefetcha, no effect */ + goto skip_move; case 0x32: /* V9 ldqfa */ + goto nfpu_insn; +#endif + default: goto illegal_insn; } gen_movl_T1_reg(rd); +#ifdef TARGET_SPARC64 + skip_move: ; +#endif } else if (xop >= 0x20 && xop < 0x24) { -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) gen_op_trap_ifnofpu(); #endif switch (xop) { @@ -1368,12 +2193,13 @@ static void disas_sparc_insn(DisasContext * dc) goto nfpu_insn; case 0x23: /* load double fpreg */ gen_op_ldst(lddf); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; default: goto illegal_insn; } - } else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) { + } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \ + xop == 0xe || xop == 0x1e) { gen_movl_reg_T1(rd); switch (xop) { case 0x4: @@ -1390,33 +2216,47 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T2(rd + 1); gen_op_ldst(std); break; -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) case 0x14: +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_sta(insn, 0, 4, 0); break; case 0x15: +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_stba(insn, 0, 1, 0); break; case 0x16: +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif gen_op_stha(insn, 0, 2, 0); break; case 0x17: +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; +#endif flush_T2(dc); gen_movl_reg_T2(rd + 1); gen_op_stda(insn, 0, 8, 0); break; #endif - default: +#ifdef TARGET_SPARC64 case 0x0e: /* V9 stx */ + gen_op_ldst(stx); + break; case 0x1e: /* V9 stxa */ + gen_op_stxa(insn, 0, 8, 0); // XXX + break; +#endif + default: goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { @@ -1430,26 +2270,41 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x25: /* stfsr, V9 stxfsr */ gen_op_load_fpr_FT0(rd); + // XXX gen_op_stfsr(); break; case 0x26: /* stdfq */ goto nfpu_insn; case 0x27: - gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT0(DFPREG(rd)); gen_op_ldst(stdf); break; default: + goto illegal_insn; + } + } else if (xop > 0x33 && xop < 0x3f) { +#ifdef TARGET_SPARC64 + switch (xop) { case 0x34: /* V9 stfa */ + gen_op_stfa(insn, 0, 0, 0); // XXX + break; case 0x37: /* V9 stdfa */ + gen_op_stdfa(insn, 0, 0, 0); // XXX + break; case 0x3c: /* V9 casa */ + gen_op_casa(insn, 0, 4, 0); // XXX + break; case 0x3e: /* V9 casxa */ - + gen_op_casxa(insn, 0, 8, 0); // XXX + break; case 0x36: /* V9 stqfa */ + goto nfpu_insn; + default: goto illegal_insn; } - } else if (xop > 0x33 && xop < 0x38) { - /* Co-processor */ +#else goto illegal_insn; +#endif } else goto illegal_insn; @@ -1540,6 +2395,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, } last_pc = dc->pc; disas_sparc_insn(dc); + if (dc->is_br) break; /* if the next PC is different, we abort now */ @@ -1552,7 +2408,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, /* if single step mode, we generate only one instruction and generate an exception */ if (env->singlestep_enabled) { - gen_op_jmp_im(dc->pc); + gen_jmp_im(dc->pc); gen_op_movl_T0_0(); gen_op_exit_tb(); break; @@ -1568,7 +2424,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, gen_op_branch((long)tb, dc->pc, dc->npc); } else { if (dc->pc != DYNAMIC_PC) - gen_op_jmp_im(dc->pc); + gen_jmp_im(dc->pc); save_npc(dc); gen_op_movl_T0_0(); gen_op_exit_tb(); @@ -1633,8 +2489,13 @@ void cpu_reset(CPUSPARCState *env) env->psrps = 1; env->pc = 0xffd00000; env->gregs[1] = ram_size; - env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ env->npc = env->pc + 4; +#ifdef TARGET_SPARC64 + env->pstate = PS_AM | PS_PRIV; // XXX: Force AM + env->version = GET_VER(env); +#else + env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ +#endif #endif } @@ -1692,7 +2553,7 @@ void cpu_dump_state(CPUState *env, FILE *f, GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), env->psrs?'S':'-', env->psrps?'P':'-', env->psret?'E':'-', env->wim); - cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr); + cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env)); } #if defined(CONFIG_USER_ONLY) diff --git a/vl.c b/vl.c index c922e9864..178c13a6d 100644 --- a/vl.c +++ b/vl.c @@ -2375,12 +2375,14 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_betls(f, &env->y); tmp = GET_PSR(env); qemu_put_be32(f, tmp); - qemu_put_be32s(f, &env->fsr); + qemu_put_betls(f, &env->fsr); + qemu_put_betls(f, &env->tbr); +#ifndef TARGET_SPARC64 qemu_put_be32s(f, &env->wim); - qemu_put_be32s(f, &env->tbr); /* MMU */ for(i = 0; i < 16; i++) qemu_put_be32s(f, &env->mmuregs[i]); +#endif } int cpu_load(QEMUFile *f, void *opaque, int version_id) @@ -2411,13 +2413,14 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) env->cwp = 0; /* needed to ensure that the wrapping registers are correctly updated */ PUT_PSR(env, tmp); - qemu_get_be32s(f, &env->fsr); + qemu_get_betls(f, &env->fsr); + qemu_get_betls(f, &env->tbr); +#ifndef TARGET_SPARC64 qemu_get_be32s(f, &env->wim); - qemu_get_be32s(f, &env->tbr); /* MMU */ for(i = 0; i < 16; i++) qemu_get_be32s(f, &env->mmuregs[i]); - +#endif tlb_flush(env, 1); return 0; } @@ -2577,6 +2580,7 @@ typedef struct QEMUResetEntry { static QEMUResetEntry *first_reset_entry; static int reset_requested; static int shutdown_requested; +static int powerdown_requested; void qemu_register_reset(QEMUResetHandler *func, void *opaque) { @@ -2614,6 +2618,12 @@ void qemu_system_shutdown_request(void) cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } +void qemu_system_powerdown_request(void) +{ + powerdown_requested = 1; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); +} + static void main_cpu_reset(void *opaque) { #if defined(TARGET_I386) || defined(TARGET_SPARC) @@ -2728,20 +2738,25 @@ int main_loop(void) if (vm_running) { ret = cpu_exec(env); if (shutdown_requested) { - ret = EXCP_INTERRUPT; + ret = EXCP_INTERRUPT; break; } if (reset_requested) { reset_requested = 0; qemu_system_reset(); - ret = EXCP_INTERRUPT; + ret = EXCP_INTERRUPT; + } + if (powerdown_requested) { + powerdown_requested = 0; + qemu_system_powerdown(); + ret = EXCP_INTERRUPT; } if (ret == EXCP_DEBUG) { vm_stop(EXCP_DEBUG); } /* if hlt instruction, we wait until the next IRQ */ /* XXX: use timeout computed from timers */ - if (ret == EXCP_HLT) + if (ret == EXCP_HLT) timeout = 10; else timeout = 0; @@ -3044,8 +3059,12 @@ void register_machines(void) qemu_register_machine(&core99_machine); qemu_register_machine(&prep_machine); #elif defined(TARGET_SPARC) +#ifdef TARGET_SPARC64 + qemu_register_machine(&sun4u_machine); +#else qemu_register_machine(&sun4m_machine); #endif +#endif } #define NET_IF_TUN 0 diff --git a/vl.h b/vl.h index 3b2ccda93..81fd06a01 100644 --- a/vl.h +++ b/vl.h @@ -110,6 +110,13 @@ typedef void QEMUResetHandler(void *opaque); void qemu_register_reset(QEMUResetHandler *func, void *opaque); void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); +void qemu_system_powerdown_request(void); +#if !defined(TARGET_SPARC) +// Please implement a power failure function to signal the OS +#define qemu_system_powerdown() do{}while(0) +#else +void qemu_system_powerdown(void); +#endif void main_loop_wait(int timeout); @@ -753,9 +760,16 @@ void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2); SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2); void slavio_serial_ms_kbd_init(int base, int irq); +/* slavio_misc.c */ +void *slavio_misc_init(uint32_t base, int irq); +void slavio_set_power_fail(void *opaque, int power_failing); + /* esp.c */ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr); +/* sun4u.c */ +extern QEMUMachine sun4u_machine; + /* NVRAM helpers */ #include "hw/m48t59.h" -- cgit v1.2.3 From 6643d27ea00f3580fb0120219bd510f00b64bca5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 14:45:34 +0000 Subject: MIPS disas support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1463 c046a42c-6fe2-441c-8c8c-71466251a162 --- mips-dis.c | 4000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4000 insertions(+) create mode 100644 mips-dis.c diff --git a/mips-dis.c b/mips-dis.c new file mode 100644 index 000000000..6d7037cc6 --- /dev/null +++ b/mips-dis.c @@ -0,0 +1,4000 @@ +/* Print mips instructions for GDB, the GNU debugger, or for objdump. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp). + +This file is part of GDB, GAS, and the GNU binutils. + +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" + +/* mips.h. Mips opcode list for GDB, the GNU debugger. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Contributed by Ralph Campbell and OSF + Commented and modified by Ian Lance Taylor, Cygnus Support + +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 +1, 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. */ + +/* mips.h. Mips opcode list for GDB, the GNU debugger. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Contributed by Ralph Campbell and OSF + Commented and modified by Ian Lance Taylor, Cygnus Support + +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 +1, 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. */ + +/* These are bit masks and shift counts to use to access the various + fields of an instruction. To retrieve the X field of an + instruction, use the expression + (i >> OP_SH_X) & OP_MASK_X + To set the same field (to j), use + i = (i &~ (OP_MASK_X << OP_SH_X)) | (j << OP_SH_X) + + Make sure you use fields that are appropriate for the instruction, + of course. + + The 'i' format uses OP, RS, RT and IMMEDIATE. + + The 'j' format uses OP and TARGET. + + The 'r' format uses OP, RS, RT, RD, SHAMT and FUNCT. + + The 'b' format uses OP, RS, RT and DELTA. + + The floating point 'i' format uses OP, RS, RT and IMMEDIATE. + + The floating point 'r' format uses OP, FMT, FT, FS, FD and FUNCT. + + A breakpoint instruction uses OP, CODE and SPEC (10 bits of the + breakpoint instruction are not defined; Kane says the breakpoint + code field in BREAK is 20 bits; yet MIPS assemblers and debuggers + only use ten bits). An optional two-operand form of break/sdbbp + allows the lower ten bits to be set too, and MIPS32 and later + architectures allow 20 bits to be set with a signal operand + (using CODE20). + + The syscall instruction uses CODE20. + + The general coprocessor instructions use COPZ. */ + +#define OP_MASK_OP 0x3f +#define OP_SH_OP 26 +#define OP_MASK_RS 0x1f +#define OP_SH_RS 21 +#define OP_MASK_FR 0x1f +#define OP_SH_FR 21 +#define OP_MASK_FMT 0x1f +#define OP_SH_FMT 21 +#define OP_MASK_BCC 0x7 +#define OP_SH_BCC 18 +#define OP_MASK_CODE 0x3ff +#define OP_SH_CODE 16 +#define OP_MASK_CODE2 0x3ff +#define OP_SH_CODE2 6 +#define OP_MASK_RT 0x1f +#define OP_SH_RT 16 +#define OP_MASK_FT 0x1f +#define OP_SH_FT 16 +#define OP_MASK_CACHE 0x1f +#define OP_SH_CACHE 16 +#define OP_MASK_RD 0x1f +#define OP_SH_RD 11 +#define OP_MASK_FS 0x1f +#define OP_SH_FS 11 +#define OP_MASK_PREFX 0x1f +#define OP_SH_PREFX 11 +#define OP_MASK_CCC 0x7 +#define OP_SH_CCC 8 +#define OP_MASK_CODE20 0xfffff /* 20 bit syscall/breakpoint code. */ +#define OP_SH_CODE20 6 +#define OP_MASK_SHAMT 0x1f +#define OP_SH_SHAMT 6 +#define OP_MASK_FD 0x1f +#define OP_SH_FD 6 +#define OP_MASK_TARGET 0x3ffffff +#define OP_SH_TARGET 0 +#define OP_MASK_COPZ 0x1ffffff +#define OP_SH_COPZ 0 +#define OP_MASK_IMMEDIATE 0xffff +#define OP_SH_IMMEDIATE 0 +#define OP_MASK_DELTA 0xffff +#define OP_SH_DELTA 0 +#define OP_MASK_FUNCT 0x3f +#define OP_SH_FUNCT 0 +#define OP_MASK_SPEC 0x3f +#define OP_SH_SPEC 0 +#define OP_SH_LOCC 8 /* FP condition code. */ +#define OP_SH_HICC 18 /* FP condition code. */ +#define OP_MASK_CC 0x7 +#define OP_SH_COP1NORM 25 /* Normal COP1 encoding. */ +#define OP_MASK_COP1NORM 0x1 /* a single bit. */ +#define OP_SH_COP1SPEC 21 /* COP1 encodings. */ +#define OP_MASK_COP1SPEC 0xf +#define OP_MASK_COP1SCLR 0x4 +#define OP_MASK_COP1CMP 0x3 +#define OP_SH_COP1CMP 4 +#define OP_SH_FORMAT 21 /* FP short format field. */ +#define OP_MASK_FORMAT 0x7 +#define OP_SH_TRUE 16 +#define OP_MASK_TRUE 0x1 +#define OP_SH_GE 17 +#define OP_MASK_GE 0x01 +#define OP_SH_UNSIGNED 16 +#define OP_MASK_UNSIGNED 0x1 +#define OP_SH_HINT 16 +#define OP_MASK_HINT 0x1f +#define OP_SH_MMI 0 /* Multimedia (parallel) op. */ +#define OP_MASK_MMI 0x3f +#define OP_SH_MMISUB 6 +#define OP_MASK_MMISUB 0x1f +#define OP_MASK_PERFREG 0x1f /* Performance monitoring. */ +#define OP_SH_PERFREG 1 +#define OP_SH_SEL 0 /* Coprocessor select field. */ +#define OP_MASK_SEL 0x7 /* The sel field of mfcZ and mtcZ. */ +#define OP_SH_CODE19 6 /* 19 bit wait code. */ +#define OP_MASK_CODE19 0x7ffff +#define OP_SH_ALN 21 +#define OP_MASK_ALN 0x7 +#define OP_SH_VSEL 21 +#define OP_MASK_VSEL 0x1f +#define OP_MASK_VECBYTE 0x7 /* Selector field is really 4 bits, + but 0x8-0xf don't select bytes. */ +#define OP_SH_VECBYTE 22 +#define OP_MASK_VECALIGN 0x7 /* Vector byte-align (alni.ob) op. */ +#define OP_SH_VECALIGN 21 +#define OP_MASK_INSMSB 0x1f /* "ins" MSB. */ +#define OP_SH_INSMSB 11 +#define OP_MASK_EXTMSBD 0x1f /* "ext" MSBD. */ +#define OP_SH_EXTMSBD 11 + +#define OP_OP_COP0 0x10 +#define OP_OP_COP1 0x11 +#define OP_OP_COP2 0x12 +#define OP_OP_COP3 0x13 +#define OP_OP_LWC1 0x31 +#define OP_OP_LWC2 0x32 +#define OP_OP_LWC3 0x33 /* a.k.a. pref */ +#define OP_OP_LDC1 0x35 +#define OP_OP_LDC2 0x36 +#define OP_OP_LDC3 0x37 /* a.k.a. ld */ +#define OP_OP_SWC1 0x39 +#define OP_OP_SWC2 0x3a +#define OP_OP_SWC3 0x3b +#define OP_OP_SDC1 0x3d +#define OP_OP_SDC2 0x3e +#define OP_OP_SDC3 0x3f /* a.k.a. sd */ + +/* Values in the 'VSEL' field. */ +#define MDMX_FMTSEL_IMM_QH 0x1d +#define MDMX_FMTSEL_IMM_OB 0x1e +#define MDMX_FMTSEL_VEC_QH 0x15 +#define MDMX_FMTSEL_VEC_OB 0x16 + +/* This structure holds information for a particular instruction. */ + +struct mips_opcode +{ + /* The name of the instruction. */ + const char *name; + /* A string describing the arguments for this instruction. */ + const char *args; + /* The basic opcode for the instruction. When assembling, this + opcode is modified by the arguments to produce the actual opcode + that is used. If pinfo is INSN_MACRO, then this is 0. */ + unsigned long match; + /* If pinfo is not INSN_MACRO, then this is a bit mask for the + relevant portions of the opcode when disassembling. If the + actual opcode anded with the match field equals the opcode field, + then we have found the correct instruction. If pinfo is + INSN_MACRO, then this field is the macro identifier. */ + unsigned long mask; + /* For a macro, this is INSN_MACRO. Otherwise, it is a collection + of bits describing the instruction, notably any relevant hazard + information. */ + unsigned long pinfo; + /* A collection of bits describing the instruction sets of which this + instruction or macro is a member. */ + unsigned long membership; +}; + +/* These are the characters which may appear in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + Each of these characters corresponds to a mask field defined above. + + "<" 5 bit shift amount (OP_*_SHAMT) + ">" shift amount between 32 and 63, stored after subtracting 32 (OP_*_SHAMT) + "a" 26 bit target address (OP_*_TARGET) + "b" 5 bit base register (OP_*_RS) + "c" 10 bit breakpoint code (OP_*_CODE) + "d" 5 bit destination register specifier (OP_*_RD) + "h" 5 bit prefx hint (OP_*_PREFX) + "i" 16 bit unsigned immediate (OP_*_IMMEDIATE) + "j" 16 bit signed immediate (OP_*_DELTA) + "k" 5 bit cache opcode in target register position (OP_*_CACHE) + Also used for immediate operands in vr5400 vector insns. + "o" 16 bit signed offset (OP_*_DELTA) + "p" 16 bit PC relative branch target address (OP_*_DELTA) + "q" 10 bit extra breakpoint code (OP_*_CODE2) + "r" 5 bit same register used as both source and target (OP_*_RS) + "s" 5 bit source register specifier (OP_*_RS) + "t" 5 bit target register (OP_*_RT) + "u" 16 bit upper 16 bits of address (OP_*_IMMEDIATE) + "v" 5 bit same register used as both source and destination (OP_*_RS) + "w" 5 bit same register used as both target and destination (OP_*_RT) + "U" 5 bit same destination register in both OP_*_RD and OP_*_RT + (used by clo and clz) + "C" 25 bit coprocessor function code (OP_*_COPZ) + "B" 20 bit syscall/breakpoint function code (OP_*_CODE20) + "J" 19 bit wait function code (OP_*_CODE19) + "x" accept and ignore register name + "z" must be zero register + "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD) + "+A" 5 bit ins/ext position, which becomes LSB (OP_*_SHAMT). + Enforces: 0 <= pos < 32. + "+B" 5 bit ins size, which becomes MSB (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + "+C" 5 bit ext size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 0 < (pos+size) <= 32. + (Also used by "dext" w/ different limits, but limits for + that are checked by the M_DEXT macro.) + "+E" 5 bit dins/dext position, which becomes LSB-32 (OP_*_SHAMT). + Enforces: 32 <= pos < 64. + "+F" 5 bit "dinsm" size, which becomes MSB-32 (OP_*_INSMSB). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + "+H" 5 bit "dextu" size, which becomes MSBD (OP_*_EXTMSBD). + Requires that "+A" or "+E" occur first to set position. + Enforces: 32 < (pos+size) <= 64. + + Floating point instructions: + "D" 5 bit destination register (OP_*_FD) + "M" 3 bit compare condition code (OP_*_CCC) (only used for mips4 and up) + "N" 3 bit branch condition code (OP_*_BCC) (only used for mips4 and up) + "S" 5 bit fs source 1 register (OP_*_FS) + "T" 5 bit ft source 2 register (OP_*_FT) + "R" 5 bit fr source 3 register (OP_*_FR) + "V" 5 bit same register used as floating source and destination (OP_*_FS) + "W" 5 bit same register used as floating target and destination (OP_*_FT) + + Coprocessor instructions: + "E" 5 bit target register (OP_*_RT) + "G" 5 bit destination register (OP_*_RD) + "H" 3 bit sel field for (d)mtc* and (d)mfc* (OP_*_SEL) + "P" 5 bit performance-monitor register (OP_*_PERFREG) + "e" 5 bit vector register byte specifier (OP_*_VECBYTE) + "%" 3 bit immediate vr5400 vector alignment operand (OP_*_VECALIGN) + see also "k" above + "+D" Combined destination register ("G") and sel ("H") for CP0 ops, + for pretty-printing in disassembly only. + + Macro instructions: + "A" General 32 bit expression + "I" 32 bit immediate (value placed in imm_expr). + "+I" 32 bit immediate (value placed in imm2_expr). + "F" 64 bit floating point constant in .rdata + "L" 64 bit floating point constant in .lit8 + "f" 32 bit floating point constant + "l" 32 bit floating point constant in .lit4 + + MDMX instruction operands (note that while these use the FP register + fields, they accept both $fN and $vN names for the registers): + "O" MDMX alignment offset (OP_*_ALN) + "Q" MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT) + "X" MDMX destination register (OP_*_FD) + "Y" MDMX source register (OP_*_FS) + "Z" MDMX source register (OP_*_FT) + + Other: + "()" parens surrounding optional value + "," separates operands + "[]" brackets around index for vector-op scalar operand specifier (vr5400) + "+" Start of extension sequence. + + Characters used so far, for quick reference when adding more: + "%[]<>(),+" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefhijklopqrstuvwxz" + + Extension character sequences used so far ("+" followed by the + following), for quick reference when adding more: + "ABCDEFGHI" +*/ + +/* These are the bits which may be set in the pinfo field of an + instructions, if it is not equal to INSN_MACRO. */ + +/* Modifies the general purpose register in OP_*_RD. */ +#define INSN_WRITE_GPR_D 0x00000001 +/* Modifies the general purpose register in OP_*_RT. */ +#define INSN_WRITE_GPR_T 0x00000002 +/* Modifies general purpose register 31. */ +#define INSN_WRITE_GPR_31 0x00000004 +/* Modifies the floating point register in OP_*_FD. */ +#define INSN_WRITE_FPR_D 0x00000008 +/* Modifies the floating point register in OP_*_FS. */ +#define INSN_WRITE_FPR_S 0x00000010 +/* Modifies the floating point register in OP_*_FT. */ +#define INSN_WRITE_FPR_T 0x00000020 +/* Reads the general purpose register in OP_*_RS. */ +#define INSN_READ_GPR_S 0x00000040 +/* Reads the general purpose register in OP_*_RT. */ +#define INSN_READ_GPR_T 0x00000080 +/* Reads the floating point register in OP_*_FS. */ +#define INSN_READ_FPR_S 0x00000100 +/* Reads the floating point register in OP_*_FT. */ +#define INSN_READ_FPR_T 0x00000200 +/* Reads the floating point register in OP_*_FR. */ +#define INSN_READ_FPR_R 0x00000400 +/* Modifies coprocessor condition code. */ +#define INSN_WRITE_COND_CODE 0x00000800 +/* Reads coprocessor condition code. */ +#define INSN_READ_COND_CODE 0x00001000 +/* TLB operation. */ +#define INSN_TLB 0x00002000 +/* Reads coprocessor register other than floating point register. */ +#define INSN_COP 0x00004000 +/* Instruction loads value from memory, requiring delay. */ +#define INSN_LOAD_MEMORY_DELAY 0x00008000 +/* Instruction loads value from coprocessor, requiring delay. */ +#define INSN_LOAD_COPROC_DELAY 0x00010000 +/* Instruction has unconditional branch delay slot. */ +#define INSN_UNCOND_BRANCH_DELAY 0x00020000 +/* Instruction has conditional branch delay slot. */ +#define INSN_COND_BRANCH_DELAY 0x00040000 +/* Conditional branch likely: if branch not taken, insn nullified. */ +#define INSN_COND_BRANCH_LIKELY 0x00080000 +/* Moves to coprocessor register, requiring delay. */ +#define INSN_COPROC_MOVE_DELAY 0x00100000 +/* Loads coprocessor register from memory, requiring delay. */ +#define INSN_COPROC_MEMORY_DELAY 0x00200000 +/* Reads the HI register. */ +#define INSN_READ_HI 0x00400000 +/* Reads the LO register. */ +#define INSN_READ_LO 0x00800000 +/* Modifies the HI register. */ +#define INSN_WRITE_HI 0x01000000 +/* Modifies the LO register. */ +#define INSN_WRITE_LO 0x02000000 +/* Takes a trap (easier to keep out of delay slot). */ +#define INSN_TRAP 0x04000000 +/* Instruction stores value into memory. */ +#define INSN_STORE_MEMORY 0x08000000 +/* Instruction uses single precision floating point. */ +#define FP_S 0x10000000 +/* Instruction uses double precision floating point. */ +#define FP_D 0x20000000 +/* Instruction is part of the tx39's integer multiply family. */ +#define INSN_MULT 0x40000000 +/* Instruction synchronize shared memory. */ +#define INSN_SYNC 0x80000000 +/* Instruction reads MDMX accumulator. XXX FIXME: No bits left! */ +#define INSN_READ_MDMX_ACC 0 +/* Instruction writes MDMX accumulator. XXX FIXME: No bits left! */ +#define INSN_WRITE_MDMX_ACC 0 + +/* Instruction is actually a macro. It should be ignored by the + disassembler, and requires special treatment by the assembler. */ +#define INSN_MACRO 0xffffffff + +/* Masks used to mark instructions to indicate which MIPS ISA level + they were introduced in. ISAs, as defined below, are logical + ORs of these bits, indicating that they support the instructions + defined at the given level. */ + +#define INSN_ISA_MASK 0x00000fff +#define INSN_ISA1 0x00000001 +#define INSN_ISA2 0x00000002 +#define INSN_ISA3 0x00000004 +#define INSN_ISA4 0x00000008 +#define INSN_ISA5 0x00000010 +#define INSN_ISA32 0x00000020 +#define INSN_ISA64 0x00000040 +#define INSN_ISA32R2 0x00000080 +#define INSN_ISA64R2 0x00000100 + +/* Masks used for MIPS-defined ASEs. */ +#define INSN_ASE_MASK 0x0000f000 + +/* MIPS 16 ASE */ +#define INSN_MIPS16 0x00002000 +/* MIPS-3D ASE */ +#define INSN_MIPS3D 0x00004000 +/* MDMX ASE */ +#define INSN_MDMX 0x00008000 + +/* Chip specific instructions. These are bitmasks. */ + +/* MIPS R4650 instruction. */ +#define INSN_4650 0x00010000 +/* LSI R4010 instruction. */ +#define INSN_4010 0x00020000 +/* NEC VR4100 instruction. */ +#define INSN_4100 0x00040000 +/* Toshiba R3900 instruction. */ +#define INSN_3900 0x00080000 +/* MIPS R10000 instruction. */ +#define INSN_10000 0x00100000 +/* Broadcom SB-1 instruction. */ +#define INSN_SB1 0x00200000 +/* NEC VR4111/VR4181 instruction. */ +#define INSN_4111 0x00400000 +/* NEC VR4120 instruction. */ +#define INSN_4120 0x00800000 +/* NEC VR5400 instruction. */ +#define INSN_5400 0x01000000 +/* NEC VR5500 instruction. */ +#define INSN_5500 0x02000000 + +/* MIPS ISA defines, use instead of hardcoding ISA level. */ + +#define ISA_UNKNOWN 0 /* Gas internal use. */ +#define ISA_MIPS1 (INSN_ISA1) +#define ISA_MIPS2 (ISA_MIPS1 | INSN_ISA2) +#define ISA_MIPS3 (ISA_MIPS2 | INSN_ISA3) +#define ISA_MIPS4 (ISA_MIPS3 | INSN_ISA4) +#define ISA_MIPS5 (ISA_MIPS4 | INSN_ISA5) + +#define ISA_MIPS32 (ISA_MIPS2 | INSN_ISA32) +#define ISA_MIPS64 (ISA_MIPS5 | INSN_ISA32 | INSN_ISA64) + +#define ISA_MIPS32R2 (ISA_MIPS32 | INSN_ISA32R2) +#define ISA_MIPS64R2 (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2) + + +/* CPU defines, use instead of hardcoding processor number. Keep this + in sync with bfd/archures.c in order for machine selection to work. */ +#define CPU_UNKNOWN 0 /* Gas internal use. */ +#define CPU_R3000 3000 +#define CPU_R3900 3900 +#define CPU_R4000 4000 +#define CPU_R4010 4010 +#define CPU_VR4100 4100 +#define CPU_R4111 4111 +#define CPU_VR4120 4120 +#define CPU_R4300 4300 +#define CPU_R4400 4400 +#define CPU_R4600 4600 +#define CPU_R4650 4650 +#define CPU_R5000 5000 +#define CPU_VR5400 5400 +#define CPU_VR5500 5500 +#define CPU_R6000 6000 +#define CPU_RM7000 7000 +#define CPU_R8000 8000 +#define CPU_R10000 10000 +#define CPU_R12000 12000 +#define CPU_MIPS16 16 +#define CPU_MIPS32 32 +#define CPU_MIPS32R2 33 +#define CPU_MIPS5 5 +#define CPU_MIPS64 64 +#define CPU_MIPS64R2 65 +#define CPU_SB1 12310201 /* octal 'SB', 01. */ + +/* Test for membership in an ISA including chip specific ISAs. INSN + is pointer to an element of the opcode table; ISA is the specified + ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to + test, or zero if no CPU specific ISA test is desired. */ + +#define OPCODE_IS_MEMBER(insn, isa, cpu) \ + (((insn)->membership & isa) != 0 \ + || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0) \ + || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0) \ + || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0) \ + || ((cpu == CPU_R10000 || cpu == CPU_R12000) \ + && ((insn)->membership & INSN_10000) != 0) \ + || (cpu == CPU_SB1 && ((insn)->membership & INSN_SB1) != 0) \ + || (cpu == CPU_R4111 && ((insn)->membership & INSN_4111) != 0) \ + || (cpu == CPU_VR4120 && ((insn)->membership & INSN_4120) != 0) \ + || (cpu == CPU_VR5400 && ((insn)->membership & INSN_5400) != 0) \ + || (cpu == CPU_VR5500 && ((insn)->membership & INSN_5500) != 0) \ + || 0) /* Please keep this term for easier source merging. */ + +/* This is a list of macro expanded instructions. + + _I appended means immediate + _A appended means address + _AB appended means address with base register + _D appended means 64 bit floating point constant + _S appended means 32 bit floating point constant. */ + +enum +{ + M_ABS, + M_ADD_I, + M_ADDU_I, + M_AND_I, + M_BEQ, + M_BEQ_I, + M_BEQL_I, + M_BGE, + M_BGEL, + M_BGE_I, + M_BGEL_I, + M_BGEU, + M_BGEUL, + M_BGEU_I, + M_BGEUL_I, + M_BGT, + M_BGTL, + M_BGT_I, + M_BGTL_I, + M_BGTU, + M_BGTUL, + M_BGTU_I, + M_BGTUL_I, + M_BLE, + M_BLEL, + M_BLE_I, + M_BLEL_I, + M_BLEU, + M_BLEUL, + M_BLEU_I, + M_BLEUL_I, + M_BLT, + M_BLTL, + M_BLT_I, + M_BLTL_I, + M_BLTU, + M_BLTUL, + M_BLTU_I, + M_BLTUL_I, + M_BNE, + M_BNE_I, + M_BNEL_I, + M_DABS, + M_DADD_I, + M_DADDU_I, + M_DDIV_3, + M_DDIV_3I, + M_DDIVU_3, + M_DDIVU_3I, + M_DEXT, + M_DINS, + M_DIV_3, + M_DIV_3I, + M_DIVU_3, + M_DIVU_3I, + M_DLA_AB, + M_DLCA_AB, + M_DLI, + M_DMUL, + M_DMUL_I, + M_DMULO, + M_DMULO_I, + M_DMULOU, + M_DMULOU_I, + M_DREM_3, + M_DREM_3I, + M_DREMU_3, + M_DREMU_3I, + M_DSUB_I, + M_DSUBU_I, + M_DSUBU_I_2, + M_J_A, + M_JAL_1, + M_JAL_2, + M_JAL_A, + M_L_DOB, + M_L_DAB, + M_LA_AB, + M_LB_A, + M_LB_AB, + M_LBU_A, + M_LBU_AB, + M_LCA_AB, + M_LD_A, + M_LD_OB, + M_LD_AB, + M_LDC1_AB, + M_LDC2_AB, + M_LDC3_AB, + M_LDL_AB, + M_LDR_AB, + M_LH_A, + M_LH_AB, + M_LHU_A, + M_LHU_AB, + M_LI, + M_LI_D, + M_LI_DD, + M_LI_S, + M_LI_SS, + M_LL_AB, + M_LLD_AB, + M_LS_A, + M_LW_A, + M_LW_AB, + M_LWC0_A, + M_LWC0_AB, + M_LWC1_A, + M_LWC1_AB, + M_LWC2_A, + M_LWC2_AB, + M_LWC3_A, + M_LWC3_AB, + M_LWL_A, + M_LWL_AB, + M_LWR_A, + M_LWR_AB, + M_LWU_AB, + M_MOVE, + M_MUL, + M_MUL_I, + M_MULO, + M_MULO_I, + M_MULOU, + M_MULOU_I, + M_NOR_I, + M_OR_I, + M_REM_3, + M_REM_3I, + M_REMU_3, + M_REMU_3I, + M_DROL, + M_ROL, + M_DROL_I, + M_ROL_I, + M_DROR, + M_ROR, + M_DROR_I, + M_ROR_I, + M_S_DA, + M_S_DOB, + M_S_DAB, + M_S_S, + M_SC_AB, + M_SCD_AB, + M_SD_A, + M_SD_OB, + M_SD_AB, + M_SDC1_AB, + M_SDC2_AB, + M_SDC3_AB, + M_SDL_AB, + M_SDR_AB, + M_SEQ, + M_SEQ_I, + M_SGE, + M_SGE_I, + M_SGEU, + M_SGEU_I, + M_SGT, + M_SGT_I, + M_SGTU, + M_SGTU_I, + M_SLE, + M_SLE_I, + M_SLEU, + M_SLEU_I, + M_SLT_I, + M_SLTU_I, + M_SNE, + M_SNE_I, + M_SB_A, + M_SB_AB, + M_SH_A, + M_SH_AB, + M_SW_A, + M_SW_AB, + M_SWC0_A, + M_SWC0_AB, + M_SWC1_A, + M_SWC1_AB, + M_SWC2_A, + M_SWC2_AB, + M_SWC3_A, + M_SWC3_AB, + M_SWL_A, + M_SWL_AB, + M_SWR_A, + M_SWR_AB, + M_SUB_I, + M_SUBU_I, + M_SUBU_I_2, + M_TEQ_I, + M_TGE_I, + M_TGEU_I, + M_TLT_I, + M_TLTU_I, + M_TNE_I, + M_TRUNCWD, + M_TRUNCWS, + M_ULD, + M_ULD_A, + M_ULH, + M_ULH_A, + M_ULHU, + M_ULHU_A, + M_ULW, + M_ULW_A, + M_USH, + M_USH_A, + M_USW, + M_USW_A, + M_USD, + M_USD_A, + M_XOR_I, + M_COP0, + M_COP1, + M_COP2, + M_COP3, + M_NUM_MACROS +}; + + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +extern const struct mips_opcode mips_builtin_opcodes[]; +extern const int bfd_mips_num_builtin_opcodes; +extern struct mips_opcode *mips_opcodes; +extern int bfd_mips_num_opcodes; +#define NUMOPCODES bfd_mips_num_opcodes + + +/* The rest of this file adds definitions for the mips16 TinyRISC + processor. */ + +/* These are the bitmasks and shift counts used for the different + fields in the instruction formats. Other than OP, no masks are + provided for the fixed portions of an instruction, since they are + not needed. + + The I format uses IMM11. + + The RI format uses RX and IMM8. + + The RR format uses RX, and RY. + + The RRI format uses RX, RY, and IMM5. + + The RRR format uses RX, RY, and RZ. + + The RRI_A format uses RX, RY, and IMM4. + + The SHIFT format uses RX, RY, and SHAMT. + + The I8 format uses IMM8. + + The I8_MOVR32 format uses RY and REGR32. + + The IR_MOV32R format uses REG32R and MOV32Z. + + The I64 format uses IMM8. + + The RI64 format uses RY and IMM5. + */ + +#define MIPS16OP_MASK_OP 0x1f +#define MIPS16OP_SH_OP 11 +#define MIPS16OP_MASK_IMM11 0x7ff +#define MIPS16OP_SH_IMM11 0 +#define MIPS16OP_MASK_RX 0x7 +#define MIPS16OP_SH_RX 8 +#define MIPS16OP_MASK_IMM8 0xff +#define MIPS16OP_SH_IMM8 0 +#define MIPS16OP_MASK_RY 0x7 +#define MIPS16OP_SH_RY 5 +#define MIPS16OP_MASK_IMM5 0x1f +#define MIPS16OP_SH_IMM5 0 +#define MIPS16OP_MASK_RZ 0x7 +#define MIPS16OP_SH_RZ 2 +#define MIPS16OP_MASK_IMM4 0xf +#define MIPS16OP_SH_IMM4 0 +#define MIPS16OP_MASK_REGR32 0x1f +#define MIPS16OP_SH_REGR32 0 +#define MIPS16OP_MASK_REG32R 0x1f +#define MIPS16OP_SH_REG32R 3 +#define MIPS16OP_EXTRACT_REG32R(i) ((((i) >> 5) & 7) | ((i) & 0x18)) +#define MIPS16OP_MASK_MOVE32Z 0x7 +#define MIPS16OP_SH_MOVE32Z 0 +#define MIPS16OP_MASK_IMM6 0x3f +#define MIPS16OP_SH_IMM6 5 + +/* These are the characters which may appears in the args field of an + instruction. They appear in the order in which the fields appear + when the instruction is used. Commas and parentheses in the args + string are ignored when assembling, and written into the output + when disassembling. + + "y" 3 bit register (MIPS16OP_*_RY) + "x" 3 bit register (MIPS16OP_*_RX) + "z" 3 bit register (MIPS16OP_*_RZ) + "Z" 3 bit register (MIPS16OP_*_MOVE32Z) + "v" 3 bit same register as source and destination (MIPS16OP_*_RX) + "w" 3 bit same register as source and destination (MIPS16OP_*_RY) + "0" zero register ($0) + "S" stack pointer ($sp or $29) + "P" program counter + "R" return address register ($ra or $31) + "X" 5 bit MIPS register (MIPS16OP_*_REGR32) + "Y" 5 bit MIPS register (MIPS16OP_*_REG32R) + "6" 6 bit unsigned break code (MIPS16OP_*_IMM6) + "a" 26 bit jump address + "e" 11 bit extension value + "l" register list for entry instruction + "L" register list for exit instruction + + The remaining codes may be extended. Except as otherwise noted, + the full extended operand is a 16 bit signed value. + "<" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 5 bit unsigned) + ">" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 5 bit unsigned) + "[" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 6 bit unsigned) + "]" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 6 bit unsigned) + "4" 4 bit signed immediate * 0 (MIPS16OP_*_IMM4) (full 15 bit signed) + "5" 5 bit unsigned immediate * 0 (MIPS16OP_*_IMM5) + "H" 5 bit unsigned immediate * 2 (MIPS16OP_*_IMM5) + "W" 5 bit unsigned immediate * 4 (MIPS16OP_*_IMM5) + "D" 5 bit unsigned immediate * 8 (MIPS16OP_*_IMM5) + "j" 5 bit signed immediate * 0 (MIPS16OP_*_IMM5) + "8" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) + "V" 8 bit unsigned immediate * 4 (MIPS16OP_*_IMM8) + "C" 8 bit unsigned immediate * 8 (MIPS16OP_*_IMM8) + "U" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned) + "k" 8 bit signed immediate * 0 (MIPS16OP_*_IMM8) + "K" 8 bit signed immediate * 8 (MIPS16OP_*_IMM8) + "p" 8 bit conditional branch address (MIPS16OP_*_IMM8) + "q" 11 bit branch address (MIPS16OP_*_IMM11) + "A" 8 bit PC relative address * 4 (MIPS16OP_*_IMM8) + "B" 5 bit PC relative address * 8 (MIPS16OP_*_IMM5) + "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5) + */ + +/* For the mips16, we use the same opcode table format and a few of + the same flags. However, most of the flags are different. */ + +/* Modifies the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_WRITE_X 0x00000001 +/* Modifies the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_WRITE_Y 0x00000002 +/* Modifies the register in MIPS16OP_*_RZ. */ +#define MIPS16_INSN_WRITE_Z 0x00000004 +/* Modifies the T ($24) register. */ +#define MIPS16_INSN_WRITE_T 0x00000008 +/* Modifies the SP ($29) register. */ +#define MIPS16_INSN_WRITE_SP 0x00000010 +/* Modifies the RA ($31) register. */ +#define MIPS16_INSN_WRITE_31 0x00000020 +/* Modifies the general purpose register in MIPS16OP_*_REG32R. */ +#define MIPS16_INSN_WRITE_GPR_Y 0x00000040 +/* Reads the register in MIPS16OP_*_RX. */ +#define MIPS16_INSN_READ_X 0x00000080 +/* Reads the register in MIPS16OP_*_RY. */ +#define MIPS16_INSN_READ_Y 0x00000100 +/* Reads the register in MIPS16OP_*_MOVE32Z. */ +#define MIPS16_INSN_READ_Z 0x00000200 +/* Reads the T ($24) register. */ +#define MIPS16_INSN_READ_T 0x00000400 +/* Reads the SP ($29) register. */ +#define MIPS16_INSN_READ_SP 0x00000800 +/* Reads the RA ($31) register. */ +#define MIPS16_INSN_READ_31 0x00001000 +/* Reads the program counter. */ +#define MIPS16_INSN_READ_PC 0x00002000 +/* Reads the general purpose register in MIPS16OP_*_REGR32. */ +#define MIPS16_INSN_READ_GPR_X 0x00004000 +/* Is a branch insn. */ +#define MIPS16_INSN_BRANCH 0x00010000 + +/* The following flags have the same value for the mips16 opcode + table: + INSN_UNCOND_BRANCH_DELAY + INSN_COND_BRANCH_DELAY + INSN_COND_BRANCH_LIKELY (never used) + INSN_READ_HI + INSN_READ_LO + INSN_WRITE_HI + INSN_WRITE_LO + INSN_TRAP + INSN_ISA3 + */ + +extern const struct mips_opcode mips16_opcodes[]; +extern const int bfd_mips16_num_opcodes; + +/* Short hand so the lines aren't too long. */ + +#define LDD INSN_LOAD_MEMORY_DELAY +#define LCD INSN_LOAD_COPROC_DELAY +#define UBD INSN_UNCOND_BRANCH_DELAY +#define CBD INSN_COND_BRANCH_DELAY +#define COD INSN_COPROC_MOVE_DELAY +#define CLD INSN_COPROC_MEMORY_DELAY +#define CBL INSN_COND_BRANCH_LIKELY +#define TRAP INSN_TRAP +#define SM INSN_STORE_MEMORY + +#define WR_d INSN_WRITE_GPR_D +#define WR_t INSN_WRITE_GPR_T +#define WR_31 INSN_WRITE_GPR_31 +#define WR_D INSN_WRITE_FPR_D +#define WR_T INSN_WRITE_FPR_T +#define WR_S INSN_WRITE_FPR_S +#define RD_s INSN_READ_GPR_S +#define RD_b INSN_READ_GPR_S +#define RD_t INSN_READ_GPR_T +#define RD_S INSN_READ_FPR_S +#define RD_T INSN_READ_FPR_T +#define RD_R INSN_READ_FPR_R +#define WR_CC INSN_WRITE_COND_CODE +#define RD_CC INSN_READ_COND_CODE +#define RD_C0 INSN_COP +#define RD_C1 INSN_COP +#define RD_C2 INSN_COP +#define RD_C3 INSN_COP +#define WR_C0 INSN_COP +#define WR_C1 INSN_COP +#define WR_C2 INSN_COP +#define WR_C3 INSN_COP + +#define WR_HI INSN_WRITE_HI +#define RD_HI INSN_READ_HI +#define MOD_HI WR_HI|RD_HI + +#define WR_LO INSN_WRITE_LO +#define RD_LO INSN_READ_LO +#define MOD_LO WR_LO|RD_LO + +#define WR_HILO WR_HI|WR_LO +#define RD_HILO RD_HI|RD_LO +#define MOD_HILO WR_HILO|RD_HILO + +#define IS_M INSN_MULT + +#define WR_MACC INSN_WRITE_MDMX_ACC +#define RD_MACC INSN_READ_MDMX_ACC + +#define I1 INSN_ISA1 +#define I2 INSN_ISA2 +#define I3 INSN_ISA3 +#define I4 INSN_ISA4 +#define I5 INSN_ISA5 +#define I32 INSN_ISA32 +#define I64 INSN_ISA64 +#define I33 INSN_ISA32R2 +#define I65 INSN_ISA64R2 + +/* MIPS64 MIPS-3D ASE support. */ +#define I16 INSN_MIPS16 + +/* MIPS64 MIPS-3D ASE support. */ +#define M3D INSN_MIPS3D + +/* MIPS64 MDMX ASE support. */ +#define MX INSN_MDMX + +#define P3 INSN_4650 +#define L1 INSN_4010 +#define V1 (INSN_4100 | INSN_4111 | INSN_4120) +#define T3 INSN_3900 +#define M1 INSN_10000 +#define SB1 INSN_SB1 +#define N411 INSN_4111 +#define N412 INSN_4120 +#define N5 (INSN_5400 | INSN_5500) +#define N54 INSN_5400 +#define N55 INSN_5500 + +#define G1 (T3 \ + ) + +#define G2 (T3 \ + ) + +#define G3 (I4 \ + ) + +/* The order of overloaded instructions matters. Label arguments and + register arguments look the same. Instructions that can have either + for arguments must apear in the correct order in this table for the + assembler to pick the right one. In other words, entries with + immediate operands must apear after the same instruction with + registers. + + Because of the lookup algorithm used, entries with the same opcode + name must be contiguous. + + Many instructions are short hand for other instructions (i.e., The + jal instruction is short for jalr ). */ + +const struct mips_opcode mips_builtin_opcodes[] = +{ +/* These instructions appear first so that the disassembler will find + them first. The assemblers uses a hash table based on the + instruction name anyhow. */ +/* name, args, match, mask, pinfo, membership */ +{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, I4|I32|G3 }, +{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, I4 }, +{"nop", "", 0x00000000, 0xffffffff, 0, I1 }, /* sll */ +{"ssnop", "", 0x00000040, 0xffffffff, 0, I32|N55 }, /* sll */ +{"ehb", "", 0x000000c0, 0xffffffff, 0, I33 }, /* sll */ +{"li", "t,j", 0x24000000, 0xffe00000, WR_t, I1 }, /* addiu */ +{"li", "t,i", 0x34000000, 0xffe00000, WR_t, I1 }, /* ori */ +{"li", "t,I", 0, (int) M_LI, INSN_MACRO, I1 }, +{"move", "d,s", 0, (int) M_MOVE, INSN_MACRO, I1 }, +{"move", "d,s", 0x0000002d, 0xfc1f07ff, WR_d|RD_s, I3 },/* daddu */ +{"move", "d,s", 0x00000021, 0xfc1f07ff, WR_d|RD_s, I1 },/* addu */ +{"move", "d,s", 0x00000025, 0xfc1f07ff, WR_d|RD_s, I1 },/* or */ +{"b", "p", 0x10000000, 0xffff0000, UBD, I1 },/* beq 0,0 */ +{"b", "p", 0x04010000, 0xffff0000, UBD, I1 },/* bgez 0 */ +{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, I1 },/* bgezal 0*/ + +{"abs", "d,v", 0, (int) M_ABS, INSN_MACRO, I1 }, +{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_D|RD_S|FP_S, I1 }, +{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_D|RD_S|FP_D, I1 }, +{"abs.ps", "D,V", 0x46c00005, 0xffff003f, WR_D|RD_S|FP_D, I5 }, +{"add", "d,v,t", 0x00000020, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"add", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, I1 }, +{"add.s", "D,V,T", 0x46000000, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 }, +{"add.d", "D,V,T", 0x46200000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 }, +{"add.ob", "X,Y,Q", 0x7800000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"add.ob", "D,S,T", 0x4ac0000b, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"add.ob", "D,S,T[e]", 0x4800000b, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"add.ob", "D,S,k", 0x4bc0000b, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"add.ps", "D,V,T", 0x46c00000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"add.qh", "X,Y,Q", 0x7820000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"adda.ob", "Y,Q", 0x78000037, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"adda.qh", "Y,Q", 0x78200037, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"addi", "t,r,j", 0x20000000, 0xfc000000, WR_t|RD_s, I1 }, +{"addiu", "t,r,j", 0x24000000, 0xfc000000, WR_t|RD_s, I1 }, +{"addl.ob", "Y,Q", 0x78000437, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"addl.qh", "Y,Q", 0x78200437, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"addr.ps", "D,S,T", 0x46c00018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D }, +{"addu", "d,v,t", 0x00000021, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"addu", "t,r,I", 0, (int) M_ADDU_I, INSN_MACRO, I1 }, +{"alni.ob", "X,Y,Z,O", 0x78000018, 0xff00003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"alni.ob", "D,S,T,%", 0x48000018, 0xff00003f, WR_D|RD_S|RD_T, N54 }, +{"alni.qh", "X,Y,Z,O", 0x7800001a, 0xff00003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"alnv.ps", "D,V,T,s", 0x4c00001e, 0xfc00003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"alnv.ob", "X,Y,Z,s", 0x78000019, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, MX|SB1 }, +{"alnv.qh", "X,Y,Z,s", 0x7800001b, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, MX }, +{"and", "d,v,t", 0x00000024, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"and", "t,r,I", 0, (int) M_AND_I, INSN_MACRO, I1 }, +{"and.ob", "X,Y,Q", 0x7800000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"and.ob", "D,S,T", 0x4ac0000c, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"and.ob", "D,S,T[e]", 0x4800000c, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"and.ob", "D,S,k", 0x4bc0000c, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"and.qh", "X,Y,Q", 0x7820000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"andi", "t,r,i", 0x30000000, 0xfc000000, WR_t|RD_s, I1 }, +/* b is at the top of the table. */ +/* bal is at the top of the table. */ +{"bc0f", "p", 0x41000000, 0xffff0000, CBD|RD_CC, I1 }, +{"bc0fl", "p", 0x41020000, 0xffff0000, CBL|RD_CC, I2|T3 }, +{"bc0t", "p", 0x41010000, 0xffff0000, CBD|RD_CC, I1 }, +{"bc0tl", "p", 0x41030000, 0xffff0000, CBL|RD_CC, I2|T3 }, +{"bc1any2f", "N,p", 0x45200000, 0xffe30000, CBD|RD_CC|FP_S, M3D }, +{"bc1any2t", "N,p", 0x45210000, 0xffe30000, CBD|RD_CC|FP_S, M3D }, +{"bc1any4f", "N,p", 0x45400000, 0xffe30000, CBD|RD_CC|FP_S, M3D }, +{"bc1any4t", "N,p", 0x45410000, 0xffe30000, CBD|RD_CC|FP_S, M3D }, +{"bc1f", "p", 0x45000000, 0xffff0000, CBD|RD_CC|FP_S, I1 }, +{"bc1f", "N,p", 0x45000000, 0xffe30000, CBD|RD_CC|FP_S, I4|I32 }, +{"bc1fl", "p", 0x45020000, 0xffff0000, CBL|RD_CC|FP_S, I2|T3 }, +{"bc1fl", "N,p", 0x45020000, 0xffe30000, CBL|RD_CC|FP_S, I4|I32 }, +{"bc1t", "p", 0x45010000, 0xffff0000, CBD|RD_CC|FP_S, I1 }, +{"bc1t", "N,p", 0x45010000, 0xffe30000, CBD|RD_CC|FP_S, I4|I32 }, +{"bc1tl", "p", 0x45030000, 0xffff0000, CBL|RD_CC|FP_S, I2|T3 }, +{"bc1tl", "N,p", 0x45030000, 0xffe30000, CBL|RD_CC|FP_S, I4|I32 }, +/* bc2* are at the bottom of the table. */ +{"bc3f", "p", 0x4d000000, 0xffff0000, CBD|RD_CC, I1 }, +{"bc3fl", "p", 0x4d020000, 0xffff0000, CBL|RD_CC, I2|T3 }, +{"bc3t", "p", 0x4d010000, 0xffff0000, CBD|RD_CC, I1 }, +{"bc3tl", "p", 0x4d030000, 0xffff0000, CBL|RD_CC, I2|T3 }, +{"beqz", "s,p", 0x10000000, 0xfc1f0000, CBD|RD_s, I1 }, +{"beqzl", "s,p", 0x50000000, 0xfc1f0000, CBL|RD_s, I2|T3 }, +{"beq", "s,t,p", 0x10000000, 0xfc000000, CBD|RD_s|RD_t, I1 }, +{"beq", "s,I,p", 0, (int) M_BEQ_I, INSN_MACRO, I1 }, +{"beql", "s,t,p", 0x50000000, 0xfc000000, CBL|RD_s|RD_t, I2|T3 }, +{"beql", "s,I,p", 0, (int) M_BEQL_I, INSN_MACRO, I2|T3 }, +{"bge", "s,t,p", 0, (int) M_BGE, INSN_MACRO, I1 }, +{"bge", "s,I,p", 0, (int) M_BGE_I, INSN_MACRO, I1 }, +{"bgel", "s,t,p", 0, (int) M_BGEL, INSN_MACRO, I2|T3 }, +{"bgel", "s,I,p", 0, (int) M_BGEL_I, INSN_MACRO, I2|T3 }, +{"bgeu", "s,t,p", 0, (int) M_BGEU, INSN_MACRO, I1 }, +{"bgeu", "s,I,p", 0, (int) M_BGEU_I, INSN_MACRO, I1 }, +{"bgeul", "s,t,p", 0, (int) M_BGEUL, INSN_MACRO, I2|T3 }, +{"bgeul", "s,I,p", 0, (int) M_BGEUL_I, INSN_MACRO, I2|T3 }, +{"bgez", "s,p", 0x04010000, 0xfc1f0000, CBD|RD_s, I1 }, +{"bgezl", "s,p", 0x04030000, 0xfc1f0000, CBL|RD_s, I2|T3 }, +{"bgezal", "s,p", 0x04110000, 0xfc1f0000, CBD|RD_s|WR_31, I1 }, +{"bgezall", "s,p", 0x04130000, 0xfc1f0000, CBL|RD_s|WR_31, I2|T3 }, +{"bgt", "s,t,p", 0, (int) M_BGT, INSN_MACRO, I1 }, +{"bgt", "s,I,p", 0, (int) M_BGT_I, INSN_MACRO, I1 }, +{"bgtl", "s,t,p", 0, (int) M_BGTL, INSN_MACRO, I2|T3 }, +{"bgtl", "s,I,p", 0, (int) M_BGTL_I, INSN_MACRO, I2|T3 }, +{"bgtu", "s,t,p", 0, (int) M_BGTU, INSN_MACRO, I1 }, +{"bgtu", "s,I,p", 0, (int) M_BGTU_I, INSN_MACRO, I1 }, +{"bgtul", "s,t,p", 0, (int) M_BGTUL, INSN_MACRO, I2|T3 }, +{"bgtul", "s,I,p", 0, (int) M_BGTUL_I, INSN_MACRO, I2|T3 }, +{"bgtz", "s,p", 0x1c000000, 0xfc1f0000, CBD|RD_s, I1 }, +{"bgtzl", "s,p", 0x5c000000, 0xfc1f0000, CBL|RD_s, I2|T3 }, +{"ble", "s,t,p", 0, (int) M_BLE, INSN_MACRO, I1 }, +{"ble", "s,I,p", 0, (int) M_BLE_I, INSN_MACRO, I1 }, +{"blel", "s,t,p", 0, (int) M_BLEL, INSN_MACRO, I2|T3 }, +{"blel", "s,I,p", 0, (int) M_BLEL_I, INSN_MACRO, I2|T3 }, +{"bleu", "s,t,p", 0, (int) M_BLEU, INSN_MACRO, I1 }, +{"bleu", "s,I,p", 0, (int) M_BLEU_I, INSN_MACRO, I1 }, +{"bleul", "s,t,p", 0, (int) M_BLEUL, INSN_MACRO, I2|T3 }, +{"bleul", "s,I,p", 0, (int) M_BLEUL_I, INSN_MACRO, I2|T3 }, +{"blez", "s,p", 0x18000000, 0xfc1f0000, CBD|RD_s, I1 }, +{"blezl", "s,p", 0x58000000, 0xfc1f0000, CBL|RD_s, I2|T3 }, +{"blt", "s,t,p", 0, (int) M_BLT, INSN_MACRO, I1 }, +{"blt", "s,I,p", 0, (int) M_BLT_I, INSN_MACRO, I1 }, +{"bltl", "s,t,p", 0, (int) M_BLTL, INSN_MACRO, I2|T3 }, +{"bltl", "s,I,p", 0, (int) M_BLTL_I, INSN_MACRO, I2|T3 }, +{"bltu", "s,t,p", 0, (int) M_BLTU, INSN_MACRO, I1 }, +{"bltu", "s,I,p", 0, (int) M_BLTU_I, INSN_MACRO, I1 }, +{"bltul", "s,t,p", 0, (int) M_BLTUL, INSN_MACRO, I2|T3 }, +{"bltul", "s,I,p", 0, (int) M_BLTUL_I, INSN_MACRO, I2|T3 }, +{"bltz", "s,p", 0x04000000, 0xfc1f0000, CBD|RD_s, I1 }, +{"bltzl", "s,p", 0x04020000, 0xfc1f0000, CBL|RD_s, I2|T3 }, +{"bltzal", "s,p", 0x04100000, 0xfc1f0000, CBD|RD_s|WR_31, I1 }, +{"bltzall", "s,p", 0x04120000, 0xfc1f0000, CBL|RD_s|WR_31, I2|T3 }, +{"bnez", "s,p", 0x14000000, 0xfc1f0000, CBD|RD_s, I1 }, +{"bnezl", "s,p", 0x54000000, 0xfc1f0000, CBL|RD_s, I2|T3 }, +{"bne", "s,t,p", 0x14000000, 0xfc000000, CBD|RD_s|RD_t, I1 }, +{"bne", "s,I,p", 0, (int) M_BNE_I, INSN_MACRO, I1 }, +{"bnel", "s,t,p", 0x54000000, 0xfc000000, CBL|RD_s|RD_t, I2|T3 }, +{"bnel", "s,I,p", 0, (int) M_BNEL_I, INSN_MACRO, I2|T3 }, +{"break", "", 0x0000000d, 0xffffffff, TRAP, I1 }, +{"break", "c", 0x0000000d, 0xfc00ffff, TRAP, I1 }, +{"break", "c,q", 0x0000000d, 0xfc00003f, TRAP, I1 }, +{"c.f.d", "S,T", 0x46200030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.f.d", "M,S,T", 0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.f.s", "S,T", 0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.f.s", "M,S,T", 0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.f.ps", "S,T", 0x46c00030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.f.ps", "M,S,T", 0x46c00030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.un.d", "S,T", 0x46200031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.un.d", "M,S,T", 0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.un.s", "S,T", 0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.un.s", "M,S,T", 0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.un.ps", "S,T", 0x46c00031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.un.ps", "M,S,T", 0x46c00031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.eq.d", "S,T", 0x46200032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.eq.d", "M,S,T", 0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.eq.s", "S,T", 0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.eq.s", "M,S,T", 0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.eq.ob", "Y,Q", 0x78000001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 }, +{"c.eq.ob", "S,T", 0x4ac00001, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.eq.ob", "S,T[e]", 0x48000001, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.eq.ob", "S,k", 0x4bc00001, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.eq.ps", "S,T", 0x46c00032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.eq.ps", "M,S,T", 0x46c00032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.eq.qh", "Y,Q", 0x78200001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX }, +{"c.ueq.d", "S,T", 0x46200033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.ueq.d", "M,S,T", 0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.ueq.s", "S,T", 0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.ueq.s", "M,S,T", 0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.ueq.ps","S,T", 0x46c00033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ueq.ps","M,S,T", 0x46c00033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.olt.d", "S,T", 0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.olt.d", "M,S,T", 0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.olt.s", "S,T", 0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.olt.s", "M,S,T", 0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.olt.ps","S,T", 0x46c00034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.olt.ps","M,S,T", 0x46c00034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ult.d", "S,T", 0x46200035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.ult.d", "M,S,T", 0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.ult.s", "S,T", 0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.ult.s", "M,S,T", 0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.ult.ps","S,T", 0x46c00035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ult.ps","M,S,T", 0x46c00035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ole.d", "S,T", 0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.ole.d", "M,S,T", 0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.ole.s", "S,T", 0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.ole.s", "M,S,T", 0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.ole.ps","S,T", 0x46c00036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ole.ps","M,S,T", 0x46c00036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ule.d", "S,T", 0x46200037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.ule.d", "M,S,T", 0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.ule.s", "S,T", 0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.ule.s", "M,S,T", 0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.ule.ps","S,T", 0x46c00037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ule.ps","M,S,T", 0x46c00037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.sf.d", "S,T", 0x46200038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.sf.d", "M,S,T", 0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.sf.s", "S,T", 0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.sf.s", "M,S,T", 0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.sf.ps", "S,T", 0x46c00038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.sf.ps", "M,S,T", 0x46c00038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ngle.d","S,T", 0x46200039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.ngle.d","M,S,T", 0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.ngle.s","S,T", 0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.ngle.s","M,S,T", 0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.ngle.ps","S,T", 0x46c00039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ngle.ps","M,S,T", 0x46c00039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.seq.d", "S,T", 0x4620003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.seq.d", "M,S,T", 0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.seq.s", "S,T", 0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.seq.s", "M,S,T", 0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.seq.ps","S,T", 0x46c0003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.seq.ps","M,S,T", 0x46c0003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ngl.d", "S,T", 0x4620003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.ngl.d", "M,S,T", 0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.ngl.s", "S,T", 0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.ngl.s", "M,S,T", 0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.ngl.ps","S,T", 0x46c0003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ngl.ps","M,S,T", 0x46c0003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.lt.d", "S,T", 0x4620003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.lt.d", "M,S,T", 0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.lt.s", "S,T", 0x4600003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.lt.s", "M,S,T", 0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.lt.ob", "Y,Q", 0x78000004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 }, +{"c.lt.ob", "S,T", 0x4ac00004, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.lt.ob", "S,T[e]", 0x48000004, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.lt.ob", "S,k", 0x4bc00004, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.lt.ps", "S,T", 0x46c0003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.lt.ps", "M,S,T", 0x46c0003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.lt.qh", "Y,Q", 0x78200004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX }, +{"c.nge.d", "S,T", 0x4620003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.nge.d", "M,S,T", 0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.nge.s", "S,T", 0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.nge.s", "M,S,T", 0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.nge.ps","S,T", 0x46c0003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.nge.ps","M,S,T", 0x46c0003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.le.d", "S,T", 0x4620003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.le.d", "M,S,T", 0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.le.s", "S,T", 0x4600003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.le.s", "M,S,T", 0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.le.ob", "Y,Q", 0x78000005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 }, +{"c.le.ob", "S,T", 0x4ac00005, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.le.ob", "S,T[e]", 0x48000005, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.le.ob", "S,k", 0x4bc00005, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"c.le.ps", "S,T", 0x46c0003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.le.ps", "M,S,T", 0x46c0003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.le.qh", "Y,Q", 0x78200005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX }, +{"c.ngt.d", "S,T", 0x4620003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, +{"c.ngt.d", "M,S,T", 0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, +{"c.ngt.s", "S,T", 0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, +{"c.ngt.s", "M,S,T", 0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, +{"c.ngt.ps","S,T", 0x46c0003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"c.ngt.ps","M,S,T", 0x46c0003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, +{"cabs.eq.d", "M,S,T", 0x46200072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.eq.ps", "M,S,T", 0x46c00072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.eq.s", "M,S,T", 0x46000072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.f.d", "M,S,T", 0x46200070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.f.ps", "M,S,T", 0x46c00070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.f.s", "M,S,T", 0x46000070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.le.d", "M,S,T", 0x4620007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.le.ps", "M,S,T", 0x46c0007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.le.s", "M,S,T", 0x4600007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.lt.d", "M,S,T", 0x4620007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.lt.ps", "M,S,T", 0x46c0007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.lt.s", "M,S,T", 0x4600007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.nge.d", "M,S,T", 0x4620007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.nge.ps","M,S,T", 0x46c0007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.nge.s", "M,S,T", 0x4600007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.ngl.d", "M,S,T", 0x4620007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ngl.ps","M,S,T", 0x46c0007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ngl.s", "M,S,T", 0x4600007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.ngle.d","M,S,T", 0x46200079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ngle.s","M,S,T", 0x46000079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.ngt.d", "M,S,T", 0x4620007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ngt.ps","M,S,T", 0x46c0007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ngt.s", "M,S,T", 0x4600007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.ole.d", "M,S,T", 0x46200076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ole.ps","M,S,T", 0x46c00076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ole.s", "M,S,T", 0x46000076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.olt.d", "M,S,T", 0x46200074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.olt.ps","M,S,T", 0x46c00074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.olt.s", "M,S,T", 0x46000074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.seq.d", "M,S,T", 0x4620007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.seq.ps","M,S,T", 0x46c0007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.seq.s", "M,S,T", 0x4600007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.sf.d", "M,S,T", 0x46200078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.sf.ps", "M,S,T", 0x46c00078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.sf.s", "M,S,T", 0x46000078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.ueq.d", "M,S,T", 0x46200073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ueq.ps","M,S,T", 0x46c00073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ueq.s", "M,S,T", 0x46000073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.ule.d", "M,S,T", 0x46200077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ule.ps","M,S,T", 0x46c00077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ule.s", "M,S,T", 0x46000077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.ult.d", "M,S,T", 0x46200075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ult.ps","M,S,T", 0x46c00075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.ult.s", "M,S,T", 0x46000075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cabs.un.d", "M,S,T", 0x46200071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.un.ps", "M,S,T", 0x46c00071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, +{"cabs.un.s", "M,S,T", 0x46000071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, +{"cache", "k,o(b)", 0xbc000000, 0xfc000000, RD_b, I3|I32|T3}, +{"ceil.l.d", "D,S", 0x4620000a, 0xffff003f, WR_D|RD_S|FP_D, I3 }, +{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S, I3 }, +{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_D, I2 }, +{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, I2 }, +{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, I1 }, +{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, I1 }, +{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, I1 }, +/* cfc2 is at the bottom of the table. */ +{"cfc3", "t,G", 0x4c400000, 0xffe007ff, LCD|WR_t|RD_C3, I1 }, +{"clo", "U,s", 0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, I32|N55 }, +{"clz", "U,s", 0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, I32|N55 }, +{"ctc0", "t,G", 0x40c00000, 0xffe007ff, COD|RD_t|WR_CC, I1 }, +{"ctc1", "t,G", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, I1 }, +{"ctc1", "t,S", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, I1 }, +/* ctc2 is at the bottom of the table. */ +{"ctc3", "t,G", 0x4cc00000, 0xffe007ff, COD|RD_t|WR_CC, I1 }, +{"cvt.d.l", "D,S", 0x46a00021, 0xffff003f, WR_D|RD_S|FP_D, I3 }, +{"cvt.d.s", "D,S", 0x46000021, 0xffff003f, WR_D|RD_S|FP_D|FP_S, I1 }, +{"cvt.d.w", "D,S", 0x46800021, 0xffff003f, WR_D|RD_S|FP_D, I1 }, +{"cvt.l.d", "D,S", 0x46200025, 0xffff003f, WR_D|RD_S|FP_D, I3 }, +{"cvt.l.s", "D,S", 0x46000025, 0xffff003f, WR_D|RD_S|FP_S, I3 }, +{"cvt.s.l", "D,S", 0x46a00020, 0xffff003f, WR_D|RD_S|FP_S, I3 }, +{"cvt.s.d", "D,S", 0x46200020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I1 }, +{"cvt.s.w", "D,S", 0x46800020, 0xffff003f, WR_D|RD_S|FP_S, I1 }, +{"cvt.s.pl","D,S", 0x46c00028, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I5 }, +{"cvt.s.pu","D,S", 0x46c00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I5 }, +{"cvt.w.d", "D,S", 0x46200024, 0xffff003f, WR_D|RD_S|FP_D, I1 }, +{"cvt.w.s", "D,S", 0x46000024, 0xffff003f, WR_D|RD_S|FP_S, I1 }, +{"cvt.ps.pw", "D,S", 0x46800026, 0xffff003f, WR_D|RD_S|FP_S|FP_D, M3D }, +{"cvt.ps.s","D,V,T", 0x46000026, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"cvt.pw.ps", "D,S", 0x46c00024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, M3D }, +{"dabs", "d,v", 0, (int) M_DABS, INSN_MACRO, I3 }, +{"dadd", "d,v,t", 0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t, I3 }, +{"dadd", "t,r,I", 0, (int) M_DADD_I, INSN_MACRO, I3 }, +{"daddi", "t,r,j", 0x60000000, 0xfc000000, WR_t|RD_s, I3 }, +{"daddiu", "t,r,j", 0x64000000, 0xfc000000, WR_t|RD_s, I3 }, +{"daddu", "d,v,t", 0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t, I3 }, +{"daddu", "t,r,I", 0, (int) M_DADDU_I, INSN_MACRO, I3 }, +{"dbreak", "", 0x7000003f, 0xffffffff, 0, N5 }, +{"dclo", "U,s", 0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, I64|N55 }, +{"dclz", "U,s", 0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, I64|N55 }, +/* dctr and dctw are used on the r5000. */ +{"dctr", "o(b)", 0xbc050000, 0xfc1f0000, RD_b, I3 }, +{"dctw", "o(b)", 0xbc090000, 0xfc1f0000, RD_b, I3 }, +{"deret", "", 0x4200001f, 0xffffffff, 0, I32|G2 }, +{"dext", "t,r,I,+I", 0, (int) M_DEXT, INSN_MACRO, I65 }, +{"dext", "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s, I65 }, +{"dextm", "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s, I65 }, +{"dextu", "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s, I65 }, +/* For ddiv, see the comments about div. */ +{"ddiv", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, +{"ddiv", "d,v,t", 0, (int) M_DDIV_3, INSN_MACRO, I3 }, +{"ddiv", "d,v,I", 0, (int) M_DDIV_3I, INSN_MACRO, I3 }, +/* For ddivu, see the comments about div. */ +{"ddivu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, +{"ddivu", "d,v,t", 0, (int) M_DDIVU_3, INSN_MACRO, I3 }, +{"ddivu", "d,v,I", 0, (int) M_DDIVU_3I, INSN_MACRO, I3 }, +{"di", "", 0x41606000, 0xffffffff, WR_t|WR_C0, I33 }, +{"di", "t", 0x41606000, 0xffe0ffff, WR_t|WR_C0, I33 }, +{"dins", "t,r,I,+I", 0, (int) M_DINS, INSN_MACRO, I65 }, +{"dins", "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s, I65 }, +{"dinsm", "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s, I65 }, +{"dinsu", "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s, I65 }, +/* The MIPS assembler treats the div opcode with two operands as + though the first operand appeared twice (the first operand is both + a source and a destination). To get the div machine instruction, + you must use an explicit destination of $0. */ +{"div", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 }, +{"div", "z,t", 0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO, I1 }, +{"div", "d,v,t", 0, (int) M_DIV_3, INSN_MACRO, I1 }, +{"div", "d,v,I", 0, (int) M_DIV_3I, INSN_MACRO, I1 }, +{"div.d", "D,V,T", 0x46200003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 }, +{"div.s", "D,V,T", 0x46000003, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 }, +{"div.ps", "D,V,T", 0x46c00003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, SB1 }, +/* For divu, see the comments about div. */ +{"divu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 }, +{"divu", "z,t", 0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO, I1 }, +{"divu", "d,v,t", 0, (int) M_DIVU_3, INSN_MACRO, I1 }, +{"divu", "d,v,I", 0, (int) M_DIVU_3I, INSN_MACRO, I1 }, +{"dla", "t,A(b)", 0, (int) M_DLA_AB, INSN_MACRO, I3 }, +{"dlca", "t,A(b)", 0, (int) M_DLCA_AB, INSN_MACRO, I3 }, +{"dli", "t,j", 0x24000000, 0xffe00000, WR_t, I3 }, /* addiu */ +{"dli", "t,i", 0x34000000, 0xffe00000, WR_t, I3 }, /* ori */ +{"dli", "t,I", 0, (int) M_DLI, INSN_MACRO, I3 }, +{"dmacc", "d,s,t", 0x00000029, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, +{"dmacchi", "d,s,t", 0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, +{"dmacchis", "d,s,t", 0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, +{"dmacchiu", "d,s,t", 0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, +{"dmacchius", "d,s,t", 0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, +{"dmaccs", "d,s,t", 0x00000429, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, +{"dmaccu", "d,s,t", 0x00000069, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, +{"dmaccus", "d,s,t", 0x00000469, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, +{"dmadd16", "s,t", 0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO, N411 }, +{"dmfc0", "t,G", 0x40200000, 0xffe007ff, LCD|WR_t|RD_C0, I3 }, +{"dmfc0", "t,+D", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, I64 }, +{"dmfc0", "t,G,H", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, I64 }, +{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, I3 }, +{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I64 }, +{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I64 }, +{"dmfc1", "t,S", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I3 }, +{"dmfc1", "t,G", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I3 }, +{"dmtc1", "t,S", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I3 }, +{"dmtc1", "t,G", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I3 }, +/* dmfc2 is at the bottom of the table. */ +/* dmtc2 is at the bottom of the table. */ +{"dmfc3", "t,G", 0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, I3 }, +{"dmfc3", "t,G,H", 0x4c200000, 0xffe007f8, LCD|WR_t|RD_C3, I64 }, +{"dmtc3", "t,G", 0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, I3 }, +{"dmtc3", "t,G,H", 0x4ca00000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, I64 }, +{"dmul", "d,v,t", 0, (int) M_DMUL, INSN_MACRO, I3 }, +{"dmul", "d,v,I", 0, (int) M_DMUL_I, INSN_MACRO, I3 }, +{"dmulo", "d,v,t", 0, (int) M_DMULO, INSN_MACRO, I3 }, +{"dmulo", "d,v,I", 0, (int) M_DMULO_I, INSN_MACRO, I3 }, +{"dmulou", "d,v,t", 0, (int) M_DMULOU, INSN_MACRO, I3 }, +{"dmulou", "d,v,I", 0, (int) M_DMULOU_I, INSN_MACRO, I3 }, +{"dmult", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, +{"dmultu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, +{"dneg", "d,w", 0x0000002e, 0xffe007ff, WR_d|RD_t, I3 }, /* dsub 0 */ +{"dnegu", "d,w", 0x0000002f, 0xffe007ff, WR_d|RD_t, I3 }, /* dsubu 0*/ +{"drem", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, +{"drem", "d,v,t", 3, (int) M_DREM_3, INSN_MACRO, I3 }, +{"drem", "d,v,I", 3, (int) M_DREM_3I, INSN_MACRO, I3 }, +{"dremu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, +{"dremu", "d,v,t", 3, (int) M_DREMU_3, INSN_MACRO, I3 }, +{"dremu", "d,v,I", 3, (int) M_DREMU_3I, INSN_MACRO, I3 }, +{"dret", "", 0x7000003e, 0xffffffff, 0, N5 }, +{"drol", "d,v,t", 0, (int) M_DROL, INSN_MACRO, I3 }, +{"drol", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, I3 }, +{"dror", "d,v,t", 0, (int) M_DROR, INSN_MACRO, I3 }, +{"dror", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, I3 }, +{"dror", "d,w,<", 0x0020003a, 0xffe0003f, WR_d|RD_t, N5|I65 }, +{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, N5|I65 }, +{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, N5|I65 }, +{"drotl", "d,v,t", 0, (int) M_DROL, INSN_MACRO, I65 }, +{"drotl", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, I65 }, +{"drotr", "d,v,t", 0, (int) M_DROR, INSN_MACRO, I65 }, +{"drotr", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, I65 }, +{"drotrv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, I65 }, +{"drotr32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, I65 }, +{"dsbh", "d,w", 0x7c0000a4, 0xffe007ff, WR_d|RD_t, I65 }, +{"dshd", "d,w", 0x7c000164, 0xffe007ff, WR_d|RD_t, I65 }, +{"dsllv", "d,t,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, +{"dsll32", "d,w,<", 0x0000003c, 0xffe0003f, WR_d|RD_t, I3 }, +{"dsll", "d,w,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsllv */ +{"dsll", "d,w,>", 0x0000003c, 0xffe0003f, WR_d|RD_t, I3 }, /* dsll32 */ +{"dsll", "d,w,<", 0x00000038, 0xffe0003f, WR_d|RD_t, I3 }, +{"dsrav", "d,t,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, +{"dsra32", "d,w,<", 0x0000003f, 0xffe0003f, WR_d|RD_t, I3 }, +{"dsra", "d,w,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsrav */ +{"dsra", "d,w,>", 0x0000003f, 0xffe0003f, WR_d|RD_t, I3 }, /* dsra32 */ +{"dsra", "d,w,<", 0x0000003b, 0xffe0003f, WR_d|RD_t, I3 }, +{"dsrlv", "d,t,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, +{"dsrl32", "d,w,<", 0x0000003e, 0xffe0003f, WR_d|RD_t, I3 }, +{"dsrl", "d,w,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsrlv */ +{"dsrl", "d,w,>", 0x0000003e, 0xffe0003f, WR_d|RD_t, I3 }, /* dsrl32 */ +{"dsrl", "d,w,<", 0x0000003a, 0xffe0003f, WR_d|RD_t, I3 }, +{"dsub", "d,v,t", 0x0000002e, 0xfc0007ff, WR_d|RD_s|RD_t, I3 }, +{"dsub", "d,v,I", 0, (int) M_DSUB_I, INSN_MACRO, I3 }, +{"dsubu", "d,v,t", 0x0000002f, 0xfc0007ff, WR_d|RD_s|RD_t, I3 }, +{"dsubu", "d,v,I", 0, (int) M_DSUBU_I, INSN_MACRO, I3 }, +{"ei", "", 0x41606020, 0xffffffff, WR_t|WR_C0, I33 }, +{"ei", "t", 0x41606020, 0xffe0ffff, WR_t|WR_C0, I33 }, +{"eret", "", 0x42000018, 0xffffffff, 0, I3|I32 }, +{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, I33 }, +{"floor.l.d", "D,S", 0x4620000b, 0xffff003f, WR_D|RD_S|FP_D, I3 }, +{"floor.l.s", "D,S", 0x4600000b, 0xffff003f, WR_D|RD_S|FP_S, I3 }, +{"floor.w.d", "D,S", 0x4620000f, 0xffff003f, WR_D|RD_S|FP_D, I2 }, +{"floor.w.s", "D,S", 0x4600000f, 0xffff003f, WR_D|RD_S|FP_S, I2 }, +{"flushi", "", 0xbc010000, 0xffffffff, 0, L1 }, +{"flushd", "", 0xbc020000, 0xffffffff, 0, L1 }, +{"flushid", "", 0xbc030000, 0xffffffff, 0, L1 }, +{"hibernate","", 0x42000023, 0xffffffff, 0, V1 }, +{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, I33 }, +{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, I1 }, +{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, I33 }, +{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, I1 }, /* jr */ +/* SVR4 PIC code requires special handling for j, so it must be a + macro. */ +{"j", "a", 0, (int) M_J_A, INSN_MACRO, I1 }, +/* This form of j is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"j", "a", 0x08000000, 0xfc000000, UBD, I1 }, +{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, I1 }, +{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, I1 }, +{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, I33 }, +{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, I33 }, +/* SVR4 PIC code requires special handling for jal, so it must be a + macro. */ +{"jal", "d,s", 0, (int) M_JAL_2, INSN_MACRO, I1 }, +{"jal", "s", 0, (int) M_JAL_1, INSN_MACRO, I1 }, +{"jal", "a", 0, (int) M_JAL_A, INSN_MACRO, I1 }, +/* This form of jal is used by the disassembler and internally by the + assembler, but will never match user input (because the line above + will match first). */ +{"jal", "a", 0x0c000000, 0xfc000000, UBD|WR_31, I1 }, +{"jalx", "a", 0x74000000, 0xfc000000, UBD|WR_31, I16 }, +{"la", "t,A(b)", 0, (int) M_LA_AB, INSN_MACRO, I1 }, +{"lb", "t,o(b)", 0x80000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, +{"lb", "t,A(b)", 0, (int) M_LB_AB, INSN_MACRO, I1 }, +{"lbu", "t,o(b)", 0x90000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, +{"lbu", "t,A(b)", 0, (int) M_LBU_AB, INSN_MACRO, I1 }, +{"lca", "t,A(b)", 0, (int) M_LCA_AB, INSN_MACRO, I1 }, +{"ld", "t,o(b)", 0xdc000000, 0xfc000000, WR_t|RD_b, I3 }, +{"ld", "t,o(b)", 0, (int) M_LD_OB, INSN_MACRO, I1 }, +{"ld", "t,A(b)", 0, (int) M_LD_AB, INSN_MACRO, I1 }, +{"ldc1", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 }, +{"ldc1", "E,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 }, +{"ldc1", "T,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, I2 }, +{"ldc1", "E,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, I2 }, +{"l.d", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 }, /* ldc1 */ +{"l.d", "T,o(b)", 0, (int) M_L_DOB, INSN_MACRO, I1 }, +{"l.d", "T,A(b)", 0, (int) M_L_DAB, INSN_MACRO, I1 }, +{"ldc2", "E,o(b)", 0xd8000000, 0xfc000000, CLD|RD_b|WR_CC, I2 }, +{"ldc2", "E,A(b)", 0, (int) M_LDC2_AB, INSN_MACRO, I2 }, +{"ldc3", "E,o(b)", 0xdc000000, 0xfc000000, CLD|RD_b|WR_CC, I2 }, +{"ldc3", "E,A(b)", 0, (int) M_LDC3_AB, INSN_MACRO, I2 }, +{"ldl", "t,o(b)", 0x68000000, 0xfc000000, LDD|WR_t|RD_b, I3 }, +{"ldl", "t,A(b)", 0, (int) M_LDL_AB, INSN_MACRO, I3 }, +{"ldr", "t,o(b)", 0x6c000000, 0xfc000000, LDD|WR_t|RD_b, I3 }, +{"ldr", "t,A(b)", 0, (int) M_LDR_AB, INSN_MACRO, I3 }, +{"ldxc1", "D,t(b)", 0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I4 }, +{"lh", "t,o(b)", 0x84000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, +{"lh", "t,A(b)", 0, (int) M_LH_AB, INSN_MACRO, I1 }, +{"lhu", "t,o(b)", 0x94000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, +{"lhu", "t,A(b)", 0, (int) M_LHU_AB, INSN_MACRO, I1 }, +/* li is at the start of the table. */ +{"li.d", "t,F", 0, (int) M_LI_D, INSN_MACRO, I1 }, +{"li.d", "T,L", 0, (int) M_LI_DD, INSN_MACRO, I1 }, +{"li.s", "t,f", 0, (int) M_LI_S, INSN_MACRO, I1 }, +{"li.s", "T,l", 0, (int) M_LI_SS, INSN_MACRO, I1 }, +{"ll", "t,o(b)", 0xc0000000, 0xfc000000, LDD|RD_b|WR_t, I2 }, +{"ll", "t,A(b)", 0, (int) M_LL_AB, INSN_MACRO, I2 }, +{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, I3 }, +{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, I3 }, +{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, I1 }, +{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I5|N55 }, +{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, +{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, I1 }, +{"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, CLD|RD_b|WR_CC, I1 }, +{"lwc0", "E,A(b)", 0, (int) M_LWC0_AB, INSN_MACRO, I1 }, +{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 }, +{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 }, +{"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 }, +{"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 }, +{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 }, /* lwc1 */ +{"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 }, +{"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, CLD|RD_b|WR_CC, I1 }, +{"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, I1 }, +{"lwc3", "E,o(b)", 0xcc000000, 0xfc000000, CLD|RD_b|WR_CC, I1 }, +{"lwc3", "E,A(b)", 0, (int) M_LWC3_AB, INSN_MACRO, I1 }, +{"lwl", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, +{"lwl", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, I1 }, +{"lcache", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, I2 }, /* same */ +{"lcache", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, I2 }, /* as lwl */ +{"lwr", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, +{"lwr", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, I1 }, +{"flush", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, I2 }, /* same */ +{"flush", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, I2 }, /* as lwr */ +{"lwu", "t,o(b)", 0x9c000000, 0xfc000000, LDD|RD_b|WR_t, I3 }, +{"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, I3 }, +{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I4 }, +{"macc", "d,s,t", 0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, +{"macc", "d,s,t", 0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"maccs", "d,s,t", 0x00000428, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, +{"macchi", "d,s,t", 0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, +{"macchi", "d,s,t", 0x00000358, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"macchis", "d,s,t", 0x00000628, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, +{"macchiu", "d,s,t", 0x00000268, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, +{"macchiu", "d,s,t", 0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"macchius","d,s,t", 0x00000668, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, +{"maccu", "d,s,t", 0x00000068, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, +{"maccu", "d,s,t", 0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"maccus", "d,s,t", 0x00000468, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, +{"mad", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, P3 }, +{"madu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, P3 }, +{"madd.d", "D,R,S,T", 0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 }, +{"madd.s", "D,R,S,T", 0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 }, +{"madd.ps", "D,R,S,T", 0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 }, +{"madd", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55}, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, G1 }, +{"madd", "d,s,t", 0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 }, +{"maddu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55}, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, G1 }, +{"maddu", "d,s,t", 0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 }, +{"madd16", "s,t", 0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO, N411 }, +{"max.ob", "X,Y,Q", 0x78000007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"max.ob", "D,S,T", 0x4ac00007, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"max.ob", "D,S,T[e]", 0x48000007, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"max.ob", "D,S,k", 0x4bc00007, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"max.qh", "X,Y,Q", 0x78200007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"mfpc", "t,P", 0x4000c801, 0xffe0ffc1, LCD|WR_t|RD_C0, M1|N5 }, +{"mfps", "t,P", 0x4000c800, 0xffe0ffc1, LCD|WR_t|RD_C0, M1|N5 }, +{"mfc0", "t,G", 0x40000000, 0xffe007ff, LCD|WR_t|RD_C0, I1 }, +{"mfc0", "t,+D", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, I32 }, +{"mfc0", "t,G,H", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, I32 }, +{"mfc1", "t,S", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I1 }, +{"mfc1", "t,G", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I1 }, +{"mfhc1", "t,S", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I33 }, +{"mfhc1", "t,G", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I33 }, +/* mfc2 is at the bottom of the table. */ +/* mfhc2 is at the bottom of the table. */ +{"mfc3", "t,G", 0x4c000000, 0xffe007ff, LCD|WR_t|RD_C3, I1 }, +{"mfc3", "t,G,H", 0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, I32 }, +{"mfdr", "t,G", 0x7000003d, 0xffe007ff, LCD|WR_t|RD_C0, N5 }, +{"mfhi", "d", 0x00000010, 0xffff07ff, WR_d|RD_HI, I1 }, +{"mflo", "d", 0x00000012, 0xffff07ff, WR_d|RD_LO, I1 }, +{"min.ob", "X,Y,Q", 0x78000006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"min.ob", "D,S,T", 0x4ac00006, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"min.ob", "D,S,T[e]", 0x48000006, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"min.ob", "D,S,k", 0x4bc00006, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"min.qh", "X,Y,Q", 0x78200006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"mov.d", "D,S", 0x46200006, 0xffff003f, WR_D|RD_S|FP_D, I1 }, +{"mov.s", "D,S", 0x46000006, 0xffff003f, WR_D|RD_S|FP_S, I1 }, +{"mov.ps", "D,S", 0x46c00006, 0xffff003f, WR_D|RD_S|FP_D, I5 }, +{"movf", "d,s,N", 0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_D|FP_S, I4|I32}, +{"movf.d", "D,S,N", 0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I4|I32 }, +{"movf.l", "D,S,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 }, +{"movf.l", "X,Y,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 }, +{"movf.s", "D,S,N", 0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, I4|I32 }, +{"movf.ps", "D,S,N", 0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I5 }, +{"movn", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, I4|I32 }, +{"ffc", "d,v", 0x0000000b, 0xfc1f07ff, WR_d|RD_s, L1 }, +{"movn.d", "D,S,t", 0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I4|I32 }, +{"movn.l", "D,S,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 }, +{"movn.l", "X,Y,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 }, +{"movn.s", "D,S,t", 0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, I4|I32 }, +{"movn.ps", "D,S,t", 0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I5 }, +{"movt", "d,s,N", 0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC, I4|I32 }, +{"movt.d", "D,S,N", 0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I4|I32 }, +{"movt.l", "D,S,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 }, +{"movt.l", "X,Y,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 }, +{"movt.s", "D,S,N", 0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, I4|I32 }, +{"movt.ps", "D,S,N", 0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I5 }, +{"movz", "d,v,t", 0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, I4|I32 }, +{"ffs", "d,v", 0x0000000a, 0xfc1f07ff, WR_d|RD_s, L1 }, +{"movz.d", "D,S,t", 0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I4|I32 }, +{"movz.l", "D,S,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 }, +{"movz.l", "X,Y,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 }, +{"movz.s", "D,S,t", 0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, I4|I32 }, +{"movz.ps", "D,S,t", 0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I5 }, +{"msac", "d,s,t", 0x000001d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"msacu", "d,s,t", 0x000001d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"msachi", "d,s,t", 0x000003d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"msachiu", "d,s,t", 0x000003d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +/* move is at the top of the table. */ +{"msgn.qh", "X,Y,Q", 0x78200000, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"msub.d", "D,R,S,T", 0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 }, +{"msub.s", "D,R,S,T", 0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 }, +{"msub.ps", "D,R,S,T", 0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 }, +{"msub", "s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 }, +{"msub", "s,t", 0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55 }, +{"msubu", "s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 }, +{"msubu", "s,t", 0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55 }, +{"mtpc", "t,P", 0x4080c801, 0xffe0ffc1, COD|RD_t|WR_C0, M1|N5 }, +{"mtps", "t,P", 0x4080c800, 0xffe0ffc1, COD|RD_t|WR_C0, M1|N5 }, +{"mtc0", "t,G", 0x40800000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, I1 }, +{"mtc0", "t,+D", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I32 }, +{"mtc0", "t,G,H", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I32 }, +{"mtc1", "t,S", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I1 }, +{"mtc1", "t,G", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I1 }, +{"mthc1", "t,S", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I33 }, +{"mthc1", "t,G", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I33 }, +/* mtc2 is at the bottom of the table. */ +/* mthc2 is at the bottom of the table. */ +{"mtc3", "t,G", 0x4c800000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, I1 }, +{"mtc3", "t,G,H", 0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, I32 }, +{"mtdr", "t,G", 0x7080003d, 0xffe007ff, COD|RD_t|WR_C0, N5 }, +{"mthi", "s", 0x00000011, 0xfc1fffff, RD_s|WR_HI, I1 }, +{"mtlo", "s", 0x00000013, 0xfc1fffff, RD_s|WR_LO, I1 }, +{"mul.d", "D,V,T", 0x46200002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 }, +{"mul.s", "D,V,T", 0x46000002, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 }, +{"mul.ob", "X,Y,Q", 0x78000030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"mul.ob", "D,S,T", 0x4ac00030, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"mul.ob", "D,S,T[e]", 0x48000030, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"mul.ob", "D,S,k", 0x4bc00030, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"mul.ps", "D,V,T", 0x46c00002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"mul.qh", "X,Y,Q", 0x78200030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"mul", "d,v,t", 0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, I32|P3|N55}, +{"mul", "d,s,t", 0x00000058, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N54 }, +{"mul", "d,v,t", 0, (int) M_MUL, INSN_MACRO, I1 }, +{"mul", "d,v,I", 0, (int) M_MUL_I, INSN_MACRO, I1 }, +{"mula.ob", "Y,Q", 0x78000033, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"mula.ob", "S,T", 0x4ac00033, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"mula.ob", "S,T[e]", 0x48000033, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, +{"mula.ob", "S,k", 0x4bc00033, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"mula.qh", "Y,Q", 0x78200033, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"mulhi", "d,s,t", 0x00000258, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"mulhiu", "d,s,t", 0x00000259, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"mull.ob", "Y,Q", 0x78000433, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"mull.ob", "S,T", 0x4ac00433, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"mull.ob", "S,T[e]", 0x48000433, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, +{"mull.ob", "S,k", 0x4bc00433, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"mull.qh", "Y,Q", 0x78200433, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"mulo", "d,v,t", 0, (int) M_MULO, INSN_MACRO, I1 }, +{"mulo", "d,v,I", 0, (int) M_MULO_I, INSN_MACRO, I1 }, +{"mulou", "d,v,t", 0, (int) M_MULOU, INSN_MACRO, I1 }, +{"mulou", "d,v,I", 0, (int) M_MULOU_I, INSN_MACRO, I1 }, +{"mulr.ps", "D,S,T", 0x46c0001a, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D }, +{"muls", "d,s,t", 0x000000d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"mulsu", "d,s,t", 0x000000d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"mulshi", "d,s,t", 0x000002d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"mulshiu", "d,s,t", 0x000002d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"muls.ob", "Y,Q", 0x78000032, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"muls.ob", "S,T", 0x4ac00032, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"muls.ob", "S,T[e]", 0x48000032, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, +{"muls.ob", "S,k", 0x4bc00032, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"muls.qh", "Y,Q", 0x78200032, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"mulsl.ob", "Y,Q", 0x78000432, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"mulsl.ob", "S,T", 0x4ac00432, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"mulsl.ob", "S,T[e]", 0x48000432, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, +{"mulsl.ob", "S,k", 0x4bc00432, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, +{"mulsl.qh", "Y,Q", 0x78200432, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"mult", "s,t", 0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1 }, +{"mult", "d,s,t", 0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 }, +{"multu", "s,t", 0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1 }, +{"multu", "d,s,t", 0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 }, +{"mulu", "d,s,t", 0x00000059, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +{"neg", "d,w", 0x00000022, 0xffe007ff, WR_d|RD_t, I1 }, /* sub 0 */ +{"negu", "d,w", 0x00000023, 0xffe007ff, WR_d|RD_t, I1 }, /* subu 0 */ +{"neg.d", "D,V", 0x46200007, 0xffff003f, WR_D|RD_S|FP_D, I1 }, +{"neg.s", "D,V", 0x46000007, 0xffff003f, WR_D|RD_S|FP_S, I1 }, +{"neg.ps", "D,V", 0x46c00007, 0xffff003f, WR_D|RD_S|FP_D, I5 }, +{"nmadd.d", "D,R,S,T", 0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 }, +{"nmadd.s", "D,R,S,T", 0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 }, +{"nmadd.ps","D,R,S,T", 0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 }, +{"nmsub.d", "D,R,S,T", 0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 }, +{"nmsub.s", "D,R,S,T", 0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 }, +{"nmsub.ps","D,R,S,T", 0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 }, +/* nop is at the start of the table. */ +{"nor", "d,v,t", 0x00000027, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"nor", "t,r,I", 0, (int) M_NOR_I, INSN_MACRO, I1 }, +{"nor.ob", "X,Y,Q", 0x7800000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"nor.ob", "D,S,T", 0x4ac0000f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"nor.ob", "D,S,T[e]", 0x4800000f, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"nor.ob", "D,S,k", 0x4bc0000f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"nor.qh", "X,Y,Q", 0x7820000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"not", "d,v", 0x00000027, 0xfc1f07ff, WR_d|RD_s|RD_t, I1 },/*nor d,s,0*/ +{"or", "d,v,t", 0x00000025, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"or", "t,r,I", 0, (int) M_OR_I, INSN_MACRO, I1 }, +{"or.ob", "X,Y,Q", 0x7800000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"or.ob", "D,S,T", 0x4ac0000e, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"or.ob", "D,S,T[e]", 0x4800000e, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"or.ob", "D,S,k", 0x4bc0000e, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"or.qh", "X,Y,Q", 0x7820000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"ori", "t,r,i", 0x34000000, 0xfc000000, WR_t|RD_s, I1 }, +{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, SB1 }, +{"pabsdiffc.ob", "Y,Q", 0x78000035, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, SB1 }, +{"pavg.ob", "X,Y,Q", 0x78000008, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, SB1 }, +{"pickf.ob", "X,Y,Q", 0x78000002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"pickf.ob", "D,S,T", 0x4ac00002, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"pickf.ob", "D,S,k", 0x4bc00002, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"pickf.qh", "X,Y,Q", 0x78200002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"pickt.ob", "X,Y,Q", 0x78000003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"pickt.ob", "D,S,T", 0x4ac00003, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"pickt.ob", "D,S,k", 0x4bc00003, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"pickt.qh", "X,Y,Q", 0x78200003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"pll.ps", "D,V,T", 0x46c0002c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"plu.ps", "D,V,T", 0x46c0002d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, + /* pref and prefx are at the start of the table. */ +{"pul.ps", "D,V,T", 0x46c0002e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"puu.ps", "D,V,T", 0x46c0002f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"rach.ob", "X", 0x7a00003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 }, +{"rach.ob", "D", 0x4a00003f, 0xfffff83f, WR_D, N54 }, +{"rach.qh", "X", 0x7a20003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX }, +{"racl.ob", "X", 0x7800003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 }, +{"racl.ob", "D", 0x4800003f, 0xfffff83f, WR_D, N54 }, +{"racl.qh", "X", 0x7820003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX }, +{"racm.ob", "X", 0x7900003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 }, +{"racm.ob", "D", 0x4900003f, 0xfffff83f, WR_D, N54 }, +{"racm.qh", "X", 0x7920003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX }, +{"recip.d", "D,S", 0x46200015, 0xffff003f, WR_D|RD_S|FP_D, I4 }, +{"recip.ps","D,S", 0x46c00015, 0xffff003f, WR_D|RD_S|FP_D, SB1 }, +{"recip.s", "D,S", 0x46000015, 0xffff003f, WR_D|RD_S|FP_S, I4 }, +{"recip1.d", "D,S", 0x4620001d, 0xffff003f, WR_D|RD_S|FP_D, M3D }, +{"recip1.ps", "D,S", 0x46c0001d, 0xffff003f, WR_D|RD_S|FP_S, M3D }, +{"recip1.s", "D,S", 0x4600001d, 0xffff003f, WR_D|RD_S|FP_S, M3D }, +{"recip2.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D }, +{"recip2.ps", "D,S,T", 0x46c0001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D }, +{"recip2.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D }, +{"rem", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 }, +{"rem", "d,v,t", 0, (int) M_REM_3, INSN_MACRO, I1 }, +{"rem", "d,v,I", 0, (int) M_REM_3I, INSN_MACRO, I1 }, +{"remu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 }, +{"remu", "d,v,t", 0, (int) M_REMU_3, INSN_MACRO, I1 }, +{"remu", "d,v,I", 0, (int) M_REMU_3I, INSN_MACRO, I1 }, +{"rdhwr", "t,K", 0x7c00003b, 0xffe007ff, WR_t, I33 }, +{"rdpgpr", "d,w", 0x41400000, 0xffe007ff, WR_d, I33 }, +{"rfe", "", 0x42000010, 0xffffffff, 0, I1|T3 }, +{"rnas.qh", "X,Q", 0x78200025, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, +{"rnau.ob", "X,Q", 0x78000021, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 }, +{"rnau.qh", "X,Q", 0x78200021, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, +{"rnes.qh", "X,Q", 0x78200026, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, +{"rneu.ob", "X,Q", 0x78000022, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 }, +{"rneu.qh", "X,Q", 0x78200022, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, +{"rol", "d,v,t", 0, (int) M_ROL, INSN_MACRO, I1 }, +{"rol", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, I1 }, +{"ror", "d,v,t", 0, (int) M_ROR, INSN_MACRO, I1 }, +{"ror", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, I1 }, +{"ror", "d,w,<", 0x00200002, 0xffe0003f, WR_d|RD_t, N5|I33 }, +{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, N5|I33 }, +{"rotl", "d,v,t", 0, (int) M_ROL, INSN_MACRO, I33 }, +{"rotl", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, I33 }, +{"rotr", "d,v,t", 0, (int) M_ROR, INSN_MACRO, I33 }, +{"rotr", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, I33 }, +{"rotrv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, I33 }, +{"round.l.d", "D,S", 0x46200008, 0xffff003f, WR_D|RD_S|FP_D, I3 }, +{"round.l.s", "D,S", 0x46000008, 0xffff003f, WR_D|RD_S|FP_S, I3 }, +{"round.w.d", "D,S", 0x4620000c, 0xffff003f, WR_D|RD_S|FP_D, I2 }, +{"round.w.s", "D,S", 0x4600000c, 0xffff003f, WR_D|RD_S|FP_S, I2 }, +{"rsqrt.d", "D,S", 0x46200016, 0xffff003f, WR_D|RD_S|FP_D, I4 }, +{"rsqrt.ps","D,S", 0x46c00016, 0xffff003f, WR_D|RD_S|FP_D, SB1 }, +{"rsqrt.s", "D,S", 0x46000016, 0xffff003f, WR_D|RD_S|FP_S, I4 }, +{"rsqrt1.d", "D,S", 0x4620001e, 0xffff003f, WR_D|RD_S|FP_D, M3D }, +{"rsqrt1.ps", "D,S", 0x46c0001e, 0xffff003f, WR_D|RD_S|FP_S, M3D }, +{"rsqrt1.s", "D,S", 0x4600001e, 0xffff003f, WR_D|RD_S|FP_S, M3D }, +{"rsqrt2.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D }, +{"rsqrt2.ps", "D,S,T", 0x46c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D }, +{"rsqrt2.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D }, +{"rzs.qh", "X,Q", 0x78200024, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, +{"rzu.ob", "X,Q", 0x78000020, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 }, +{"rzu.ob", "D,k", 0x4bc00020, 0xffe0f83f, WR_D|RD_S|RD_T, N54 }, +{"rzu.qh", "X,Q", 0x78200020, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, +{"sb", "t,o(b)", 0xa0000000, 0xfc000000, SM|RD_t|RD_b, I1 }, +{"sb", "t,A(b)", 0, (int) M_SB_AB, INSN_MACRO, I1 }, +{"sc", "t,o(b)", 0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, I2 }, +{"sc", "t,A(b)", 0, (int) M_SC_AB, INSN_MACRO, I2 }, +{"scd", "t,o(b)", 0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, I3 }, +{"scd", "t,A(b)", 0, (int) M_SCD_AB, INSN_MACRO, I3 }, +{"sd", "t,o(b)", 0xfc000000, 0xfc000000, SM|RD_t|RD_b, I3 }, +{"sd", "t,o(b)", 0, (int) M_SD_OB, INSN_MACRO, I1 }, +{"sd", "t,A(b)", 0, (int) M_SD_AB, INSN_MACRO, I1 }, +{"sdbbp", "", 0x0000000e, 0xffffffff, TRAP, G2 }, +{"sdbbp", "c", 0x0000000e, 0xfc00ffff, TRAP, G2 }, +{"sdbbp", "c,q", 0x0000000e, 0xfc00003f, TRAP, G2 }, +{"sdbbp", "", 0x7000003f, 0xffffffff, TRAP, I32 }, +{"sdbbp", "B", 0x7000003f, 0xfc00003f, TRAP, I32 }, +{"sdc1", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 }, +{"sdc1", "E,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 }, +{"sdc1", "T,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, I2 }, +{"sdc1", "E,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, I2 }, +{"sdc2", "E,o(b)", 0xf8000000, 0xfc000000, SM|RD_C2|RD_b, I2 }, +{"sdc2", "E,A(b)", 0, (int) M_SDC2_AB, INSN_MACRO, I2 }, +{"sdc3", "E,o(b)", 0xfc000000, 0xfc000000, SM|RD_C3|RD_b, I2 }, +{"sdc3", "E,A(b)", 0, (int) M_SDC3_AB, INSN_MACRO, I2 }, +{"s.d", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 }, +{"s.d", "T,o(b)", 0, (int) M_S_DOB, INSN_MACRO, I1 }, +{"s.d", "T,A(b)", 0, (int) M_S_DAB, INSN_MACRO, I1 }, +{"sdl", "t,o(b)", 0xb0000000, 0xfc000000, SM|RD_t|RD_b, I3 }, +{"sdl", "t,A(b)", 0, (int) M_SDL_AB, INSN_MACRO, I3 }, +{"sdr", "t,o(b)", 0xb4000000, 0xfc000000, SM|RD_t|RD_b, I3 }, +{"sdr", "t,A(b)", 0, (int) M_SDR_AB, INSN_MACRO, I3 }, +{"sdxc1", "S,t(b)", 0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I4 }, +{"seb", "d,w", 0x7c000420, 0xffe007ff, WR_d|RD_t, I33 }, +{"seh", "d,w", 0x7c000620, 0xffe007ff, WR_d|RD_t, I33 }, +{"selsl", "d,v,t", 0x00000005, 0xfc0007ff, WR_d|RD_s|RD_t, L1 }, +{"selsr", "d,v,t", 0x00000001, 0xfc0007ff, WR_d|RD_s|RD_t, L1 }, +{"seq", "d,v,t", 0, (int) M_SEQ, INSN_MACRO, I1 }, +{"seq", "d,v,I", 0, (int) M_SEQ_I, INSN_MACRO, I1 }, +{"sge", "d,v,t", 0, (int) M_SGE, INSN_MACRO, I1 }, +{"sge", "d,v,I", 0, (int) M_SGE_I, INSN_MACRO, I1 }, +{"sgeu", "d,v,t", 0, (int) M_SGEU, INSN_MACRO, I1 }, +{"sgeu", "d,v,I", 0, (int) M_SGEU_I, INSN_MACRO, I1 }, +{"sgt", "d,v,t", 0, (int) M_SGT, INSN_MACRO, I1 }, +{"sgt", "d,v,I", 0, (int) M_SGT_I, INSN_MACRO, I1 }, +{"sgtu", "d,v,t", 0, (int) M_SGTU, INSN_MACRO, I1 }, +{"sgtu", "d,v,I", 0, (int) M_SGTU_I, INSN_MACRO, I1 }, +{"sh", "t,o(b)", 0xa4000000, 0xfc000000, SM|RD_t|RD_b, I1 }, +{"sh", "t,A(b)", 0, (int) M_SH_AB, INSN_MACRO, I1 }, +{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"sle", "d,v,t", 0, (int) M_SLE, INSN_MACRO, I1 }, +{"sle", "d,v,I", 0, (int) M_SLE_I, INSN_MACRO, I1 }, +{"sleu", "d,v,t", 0, (int) M_SLEU, INSN_MACRO, I1 }, +{"sleu", "d,v,I", 0, (int) M_SLEU_I, INSN_MACRO, I1 }, +{"sllv", "d,t,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, +{"sll", "d,w,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* sllv */ +{"sll", "d,w,<", 0x00000000, 0xffe0003f, WR_d|RD_t, I1 }, +{"sll.ob", "X,Y,Q", 0x78000010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"sll.ob", "D,S,T[e]", 0x48000010, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"sll.ob", "D,S,k", 0x4bc00010, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"sll.qh", "X,Y,Q", 0x78200010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"slt", "d,v,t", 0x0000002a, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"slt", "d,v,I", 0, (int) M_SLT_I, INSN_MACRO, I1 }, +{"slti", "t,r,j", 0x28000000, 0xfc000000, WR_t|RD_s, I1 }, +{"sltiu", "t,r,j", 0x2c000000, 0xfc000000, WR_t|RD_s, I1 }, +{"sltu", "d,v,t", 0x0000002b, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"sltu", "d,v,I", 0, (int) M_SLTU_I, INSN_MACRO, I1 }, +{"sne", "d,v,t", 0, (int) M_SNE, INSN_MACRO, I1 }, +{"sne", "d,v,I", 0, (int) M_SNE_I, INSN_MACRO, I1 }, +{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_D|RD_S|FP_D, I2 }, +{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_D|RD_S|FP_S, I2 }, +{"sqrt.ps", "D,S", 0x46c00004, 0xffff003f, WR_D|RD_S|FP_D, SB1 }, +{"srav", "d,t,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, +{"sra", "d,w,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* srav */ +{"sra", "d,w,<", 0x00000003, 0xffe0003f, WR_d|RD_t, I1 }, +{"sra.qh", "X,Y,Q", 0x78200013, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"srlv", "d,t,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, +{"srl", "d,w,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* srlv */ +{"srl", "d,w,<", 0x00000002, 0xffe0003f, WR_d|RD_t, I1 }, +{"srl.ob", "X,Y,Q", 0x78000012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"srl.ob", "D,S,T[e]", 0x48000012, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"srl.ob", "D,S,k", 0x4bc00012, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"srl.qh", "X,Y,Q", 0x78200012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +/* ssnop is at the start of the table. */ +{"standby", "", 0x42000021, 0xffffffff, 0, V1 }, +{"sub", "d,v,t", 0x00000022, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"sub", "d,v,I", 0, (int) M_SUB_I, INSN_MACRO, I1 }, +{"sub.d", "D,V,T", 0x46200001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 }, +{"sub.s", "D,V,T", 0x46000001, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 }, +{"sub.ob", "X,Y,Q", 0x7800000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"sub.ob", "D,S,T", 0x4ac0000a, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"sub.ob", "D,S,T[e]", 0x4800000a, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"sub.ob", "D,S,k", 0x4bc0000a, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"sub.ps", "D,V,T", 0x46c00001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"sub.qh", "X,Y,Q", 0x7820000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"suba.ob", "Y,Q", 0x78000036, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"suba.qh", "Y,Q", 0x78200036, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"subl.ob", "Y,Q", 0x78000436, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"subl.qh", "Y,Q", 0x78200436, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"subu", "d,v,t", 0x00000023, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"subu", "d,v,I", 0, (int) M_SUBU_I, INSN_MACRO, I1 }, +{"suspend", "", 0x42000022, 0xffffffff, 0, V1 }, +{"suxc1", "S,t(b)", 0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I5|N55 }, +{"sw", "t,o(b)", 0xac000000, 0xfc000000, SM|RD_t|RD_b, I1 }, +{"sw", "t,A(b)", 0, (int) M_SW_AB, INSN_MACRO, I1 }, +{"swc0", "E,o(b)", 0xe0000000, 0xfc000000, SM|RD_C0|RD_b, I1 }, +{"swc0", "E,A(b)", 0, (int) M_SWC0_AB, INSN_MACRO, I1 }, +{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 }, +{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 }, +{"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 }, +{"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 }, +{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 }, /* swc1 */ +{"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 }, +{"swc2", "E,o(b)", 0xe8000000, 0xfc000000, SM|RD_C2|RD_b, I1 }, +{"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, I1 }, +{"swc3", "E,o(b)", 0xec000000, 0xfc000000, SM|RD_C3|RD_b, I1 }, +{"swc3", "E,A(b)", 0, (int) M_SWC3_AB, INSN_MACRO, I1 }, +{"swl", "t,o(b)", 0xa8000000, 0xfc000000, SM|RD_t|RD_b, I1 }, +{"swl", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, I1 }, +{"scache", "t,o(b)", 0xa8000000, 0xfc000000, RD_t|RD_b, I2 }, /* same */ +{"scache", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, I2 }, /* as swl */ +{"swr", "t,o(b)", 0xb8000000, 0xfc000000, SM|RD_t|RD_b, I1 }, +{"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, I1 }, +{"invalidate", "t,o(b)",0xb8000000, 0xfc000000, RD_t|RD_b, I2 }, /* same */ +{"invalidate", "t,A(b)",0, (int) M_SWR_AB, INSN_MACRO, I2 }, /* as swr */ +{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I4 }, +{"sync", "", 0x0000000f, 0xffffffff, INSN_SYNC, I2|G1 }, +{"sync.p", "", 0x0000040f, 0xffffffff, INSN_SYNC, I2 }, +{"sync.l", "", 0x0000000f, 0xffffffff, INSN_SYNC, I2 }, +{"synci", "o(b)", 0x041f0000, 0xfc1f0000, SM|RD_b, I33 }, +{"syscall", "", 0x0000000c, 0xffffffff, TRAP, I1 }, +{"syscall", "B", 0x0000000c, 0xfc00003f, TRAP, I1 }, +{"teqi", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, I2 }, +{"teq", "s,t", 0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, +{"teq", "s,t,q", 0x00000034, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, +{"teq", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* teqi */ +{"teq", "s,I", 0, (int) M_TEQ_I, INSN_MACRO, I2 }, +{"tgei", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, I2 }, +{"tge", "s,t", 0x00000030, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, +{"tge", "s,t,q", 0x00000030, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, +{"tge", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tgei */ +{"tge", "s,I", 0, (int) M_TGE_I, INSN_MACRO, I2 }, +{"tgeiu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, I2 }, +{"tgeu", "s,t", 0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, +{"tgeu", "s,t,q", 0x00000031, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, +{"tgeu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tgeiu */ +{"tgeu", "s,I", 0, (int) M_TGEU_I, INSN_MACRO, I2 }, +{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, I1 }, +{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, I1 }, +{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, I1 }, +{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, I1 }, +{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, I2 }, +{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, +{"tlt", "s,t,q", 0x00000032, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, +{"tlt", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tlti */ +{"tlt", "s,I", 0, (int) M_TLT_I, INSN_MACRO, I2 }, +{"tltiu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, I2 }, +{"tltu", "s,t", 0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, +{"tltu", "s,t,q", 0x00000033, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, +{"tltu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tltiu */ +{"tltu", "s,I", 0, (int) M_TLTU_I, INSN_MACRO, I2 }, +{"tnei", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, I2 }, +{"tne", "s,t", 0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, +{"tne", "s,t,q", 0x00000036, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, +{"tne", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tnei */ +{"tne", "s,I", 0, (int) M_TNE_I, INSN_MACRO, I2 }, +{"trunc.l.d", "D,S", 0x46200009, 0xffff003f, WR_D|RD_S|FP_D, I3 }, +{"trunc.l.s", "D,S", 0x46000009, 0xffff003f, WR_D|RD_S|FP_S, I3 }, +{"trunc.w.d", "D,S", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_D, I2 }, +{"trunc.w.d", "D,S,x", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_D, I2 }, +{"trunc.w.d", "D,S,t", 0, (int) M_TRUNCWD, INSN_MACRO, I1 }, +{"trunc.w.s", "D,S", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, I2 }, +{"trunc.w.s", "D,S,x", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, I2 }, +{"trunc.w.s", "D,S,t", 0, (int) M_TRUNCWS, INSN_MACRO, I1 }, +{"uld", "t,o(b)", 0, (int) M_ULD, INSN_MACRO, I3 }, +{"uld", "t,A(b)", 0, (int) M_ULD_A, INSN_MACRO, I3 }, +{"ulh", "t,o(b)", 0, (int) M_ULH, INSN_MACRO, I1 }, +{"ulh", "t,A(b)", 0, (int) M_ULH_A, INSN_MACRO, I1 }, +{"ulhu", "t,o(b)", 0, (int) M_ULHU, INSN_MACRO, I1 }, +{"ulhu", "t,A(b)", 0, (int) M_ULHU_A, INSN_MACRO, I1 }, +{"ulw", "t,o(b)", 0, (int) M_ULW, INSN_MACRO, I1 }, +{"ulw", "t,A(b)", 0, (int) M_ULW_A, INSN_MACRO, I1 }, +{"usd", "t,o(b)", 0, (int) M_USD, INSN_MACRO, I3 }, +{"usd", "t,A(b)", 0, (int) M_USD_A, INSN_MACRO, I3 }, +{"ush", "t,o(b)", 0, (int) M_USH, INSN_MACRO, I1 }, +{"ush", "t,A(b)", 0, (int) M_USH_A, INSN_MACRO, I1 }, +{"usw", "t,o(b)", 0, (int) M_USW, INSN_MACRO, I1 }, +{"usw", "t,A(b)", 0, (int) M_USW_A, INSN_MACRO, I1 }, +{"wach.ob", "Y", 0x7a00003e, 0xffff07ff, WR_MACC|RD_S|FP_D, MX|SB1 }, +{"wach.ob", "S", 0x4a00003e, 0xffff07ff, RD_S, N54 }, +{"wach.qh", "Y", 0x7a20003e, 0xffff07ff, WR_MACC|RD_S|FP_D, MX }, +{"wacl.ob", "Y,Z", 0x7800003e, 0xffe007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, +{"wacl.ob", "S,T", 0x4800003e, 0xffe007ff, RD_S|RD_T, N54 }, +{"wacl.qh", "Y,Z", 0x7820003e, 0xffe007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, +{"wait", "", 0x42000020, 0xffffffff, TRAP, I3|I32 }, +{"wait", "J", 0x42000020, 0xfe00003f, TRAP, I32|N55 }, +{"waiti", "", 0x42000020, 0xffffffff, TRAP, L1 }, +{"wb", "o(b)", 0xbc040000, 0xfc1f0000, SM|RD_b, L1 }, +{"wrpgpr", "d,w", 0x41c00000, 0xffe007ff, RD_t, I33 }, +{"wsbh", "d,w", 0x7c0000a0, 0xffe007ff, WR_d|RD_t, I33 }, +{"xor", "d,v,t", 0x00000026, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, +{"xor", "t,r,I", 0, (int) M_XOR_I, INSN_MACRO, I1 }, +{"xor.ob", "X,Y,Q", 0x7800000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, +{"xor.ob", "D,S,T", 0x4ac0000d, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"xor.ob", "D,S,T[e]", 0x4800000d, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, +{"xor.ob", "D,S,k", 0x4bc0000d, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, +{"xor.qh", "X,Y,Q", 0x7820000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"xori", "t,r,i", 0x38000000, 0xfc000000, WR_t|RD_s, I1 }, + +/* Coprocessor 2 move/branch operations overlap with VR5400 .ob format + instructions so they are here for the latters to take precedence. */ +{"bc2f", "p", 0x49000000, 0xffff0000, CBD|RD_CC, I1 }, +{"bc2fl", "p", 0x49020000, 0xffff0000, CBL|RD_CC, I2|T3 }, +{"bc2t", "p", 0x49010000, 0xffff0000, CBD|RD_CC, I1 }, +{"bc2tl", "p", 0x49030000, 0xffff0000, CBL|RD_CC, I2|T3 }, +{"cfc2", "t,G", 0x48400000, 0xffe007ff, LCD|WR_t|RD_C2, I1 }, +{"ctc2", "t,G", 0x48c00000, 0xffe007ff, COD|RD_t|WR_CC, I1 }, +{"dmfc2", "t,G", 0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, I3 }, +{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, I64 }, +{"dmtc2", "t,G", 0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, I3 }, +{"dmtc2", "t,G,H", 0x48a00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, I64 }, +{"mfc2", "t,G", 0x48000000, 0xffe007ff, LCD|WR_t|RD_C2, I1 }, +{"mfc2", "t,G,H", 0x48000000, 0xffe007f8, LCD|WR_t|RD_C2, I32 }, +{"mfhc2", "t,i", 0x48600000, 0xffe00000, LCD|WR_t|RD_C2, I33 }, +{"mtc2", "t,G", 0x48800000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, I1 }, +{"mtc2", "t,G,H", 0x48800000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, I32 }, +{"mthc2", "t,i", 0x48e00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, I33 }, + +/* No hazard protection on coprocessor instructions--they shouldn't + change the state of the processor and if they do it's up to the + user to put in nops as necessary. These are at the end so that the + disassembler recognizes more specific versions first. */ +{"c0", "C", 0x42000000, 0xfe000000, 0, I1 }, +{"c1", "C", 0x46000000, 0xfe000000, 0, I1 }, +{"c2", "C", 0x4a000000, 0xfe000000, 0, I1 }, +{"c3", "C", 0x4e000000, 0xfe000000, 0, I1 }, +{"cop0", "C", 0, (int) M_COP0, INSN_MACRO, I1 }, +{"cop1", "C", 0, (int) M_COP1, INSN_MACRO, I1 }, +{"cop2", "C", 0, (int) M_COP2, INSN_MACRO, I1 }, +{"cop3", "C", 0, (int) M_COP3, INSN_MACRO, I1 }, + + /* Conflicts with the 4650's "mul" instruction. Nobody's using the + 4010 any more, so move this insn out of the way. If the object + format gave us more info, we could do this right. */ +{"addciu", "t,r,j", 0x70000000, 0xfc000000, WR_t|RD_s, L1 }, +}; + +#define MIPS_NUM_OPCODES \ + ((sizeof mips_builtin_opcodes) / (sizeof (mips_builtin_opcodes[0]))) +const int bfd_mips_num_builtin_opcodes = MIPS_NUM_OPCODES; + +/* const removed from the following to allow for dynamic extensions to the + * built-in instruction set. */ +struct mips_opcode *mips_opcodes = + (struct mips_opcode *) mips_builtin_opcodes; +int bfd_mips_num_opcodes = MIPS_NUM_OPCODES; +#undef MIPS_NUM_OPCODES + +typedef int bfd_boolean; +#define TRUE (1) +#define FALSE (0) + +/* Mips instructions are at maximum this many bytes long. */ +#define INSNLEN 4 + +static void set_default_mips_dis_options + PARAMS ((struct disassemble_info *)); +static void parse_mips_dis_option + PARAMS ((const char *, unsigned int)); +static void parse_mips_dis_options + PARAMS ((const char *)); +static int _print_insn_mips + PARAMS ((bfd_vma, struct disassemble_info *, enum bfd_endian)); +static int print_insn_mips + PARAMS ((bfd_vma, unsigned long int, struct disassemble_info *)); +static void print_insn_args + PARAMS ((const char *, unsigned long, bfd_vma, struct disassemble_info *)); +#if 0 +static int print_insn_mips16 + PARAMS ((bfd_vma, struct disassemble_info *)); +#endif +#if 0 +static int is_newabi + PARAMS ((Elf32_Ehdr *)); +#endif +#if 0 +static void print_mips16_insn_arg + PARAMS ((int, const struct mips_opcode *, int, bfd_boolean, int, bfd_vma, + struct disassemble_info *)); +#endif + +/* FIXME: These should be shared with gdb somehow. */ + +struct mips_cp0sel_name { + unsigned int cp0reg; + unsigned int sel; + const char * const name; +}; + +/* The mips16 register names. */ +static const char * const mips16_reg_names[] = { + "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3" +}; + +static const char * const mips_gpr_names_numeric[32] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_gpr_names_oldabi[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static const char * const mips_gpr_names_newabi[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static const char * const mips_fpr_names_numeric[32] = { + "$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" +}; + +static const char * const mips_fpr_names_32[32] = { + "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f", + "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f", + "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f", + "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f" +}; + +static const char * const mips_fpr_names_n32[32] = { + "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3", + "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", + "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9", + "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13" +}; + +static const char * const mips_fpr_names_64[32] = { + "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3", + "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", + "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11", + "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" +}; + +static const char * const mips_cp0_names_numeric[32] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_cp0_names_mips3264[32] = { + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "$7", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", + "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = { + { 16, 1, "c0_config1" }, + { 16, 2, "c0_config2" }, + { 16, 3, "c0_config3" }, + { 18, 1, "c0_watchlo,1" }, + { 18, 2, "c0_watchlo,2" }, + { 18, 3, "c0_watchlo,3" }, + { 18, 4, "c0_watchlo,4" }, + { 18, 5, "c0_watchlo,5" }, + { 18, 6, "c0_watchlo,6" }, + { 18, 7, "c0_watchlo,7" }, + { 19, 1, "c0_watchhi,1" }, + { 19, 2, "c0_watchhi,2" }, + { 19, 3, "c0_watchhi,3" }, + { 19, 4, "c0_watchhi,4" }, + { 19, 5, "c0_watchhi,5" }, + { 19, 6, "c0_watchhi,6" }, + { 19, 7, "c0_watchhi,7" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 27, 1, "c0_cacheerr,1" }, + { 27, 2, "c0_cacheerr,2" }, + { 27, 3, "c0_cacheerr,3" }, + { 28, 1, "c0_datalo" }, + { 29, 1, "c0_datahi" } +}; + +static const char * const mips_cp0_names_mips3264r2[32] = { + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr", + "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = { + { 4, 1, "c0_contextconfig" }, + { 5, 1, "c0_pagegrain" }, + { 12, 1, "c0_intctl" }, + { 12, 2, "c0_srsctl" }, + { 12, 3, "c0_srsmap" }, + { 15, 1, "c0_ebase" }, + { 16, 1, "c0_config1" }, + { 16, 2, "c0_config2" }, + { 16, 3, "c0_config3" }, + { 18, 1, "c0_watchlo,1" }, + { 18, 2, "c0_watchlo,2" }, + { 18, 3, "c0_watchlo,3" }, + { 18, 4, "c0_watchlo,4" }, + { 18, 5, "c0_watchlo,5" }, + { 18, 6, "c0_watchlo,6" }, + { 18, 7, "c0_watchlo,7" }, + { 19, 1, "c0_watchhi,1" }, + { 19, 2, "c0_watchhi,2" }, + { 19, 3, "c0_watchhi,3" }, + { 19, 4, "c0_watchhi,4" }, + { 19, 5, "c0_watchhi,5" }, + { 19, 6, "c0_watchhi,6" }, + { 19, 7, "c0_watchhi,7" }, + { 23, 1, "c0_tracecontrol" }, + { 23, 2, "c0_tracecontrol2" }, + { 23, 3, "c0_usertracedata" }, + { 23, 4, "c0_tracebpc" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 27, 1, "c0_cacheerr,1" }, + { 27, 2, "c0_cacheerr,2" }, + { 27, 3, "c0_cacheerr,3" }, + { 28, 1, "c0_datalo" }, + { 28, 2, "c0_taglo1" }, + { 28, 3, "c0_datalo1" }, + { 28, 4, "c0_taglo2" }, + { 28, 5, "c0_datalo2" }, + { 28, 6, "c0_taglo3" }, + { 28, 7, "c0_datalo3" }, + { 29, 1, "c0_datahi" }, + { 29, 2, "c0_taghi1" }, + { 29, 3, "c0_datahi1" }, + { 29, 4, "c0_taghi2" }, + { 29, 5, "c0_datahi2" }, + { 29, 6, "c0_taghi3" }, + { 29, 7, "c0_datahi3" }, +}; + +/* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods. */ +static const char * const mips_cp0_names_sb1[32] = { + "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", + "c0_context", "c0_pagemask", "c0_wired", "$7", + "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", + "c0_status", "c0_cause", "c0_epc", "c0_prid", + "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi", + "c0_xcontext", "$21", "$22", "c0_debug", + "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr_i", + "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave", +}; + +static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = { + { 16, 1, "c0_config1" }, + { 18, 1, "c0_watchlo,1" }, + { 19, 1, "c0_watchhi,1" }, + { 22, 0, "c0_perftrace" }, + { 23, 3, "c0_edebug" }, + { 25, 1, "c0_perfcnt,1" }, + { 25, 2, "c0_perfcnt,2" }, + { 25, 3, "c0_perfcnt,3" }, + { 25, 4, "c0_perfcnt,4" }, + { 25, 5, "c0_perfcnt,5" }, + { 25, 6, "c0_perfcnt,6" }, + { 25, 7, "c0_perfcnt,7" }, + { 26, 1, "c0_buserr_pa" }, + { 27, 1, "c0_cacheerr_d" }, + { 27, 3, "c0_cacheerr_d_pa" }, + { 28, 1, "c0_datalo_i" }, + { 28, 2, "c0_taglo_d" }, + { 28, 3, "c0_datalo_d" }, + { 29, 1, "c0_datahi_i" }, + { 29, 2, "c0_taghi_d" }, + { 29, 3, "c0_datahi_d" }, +}; + +static const char * const mips_hwr_names_numeric[32] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_hwr_names_mips3264r2[32] = { + "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres", + "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +struct mips_abi_choice { + const char *name; + const char * const *gpr_names; + const char * const *fpr_names; +}; + +struct mips_abi_choice mips_abi_choices[] = { + { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric }, + { "32", mips_gpr_names_oldabi, mips_fpr_names_32 }, + { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 }, + { "64", mips_gpr_names_newabi, mips_fpr_names_64 }, +}; + +struct mips_arch_choice { + const char *name; + int bfd_mach_valid; + unsigned long bfd_mach; + int processor; + int isa; + const char * const *cp0_names; + const struct mips_cp0sel_name *cp0sel_names; + unsigned int cp0sel_names_len; + const char * const *hwr_names; +}; + +#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_mips4111 4111 +#define bfd_mach_mips4120 4120 +#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_mips5400 5400 +#define bfd_mach_mips5500 5500 +#define bfd_mach_mips6000 6000 +#define bfd_mach_mips7000 7000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips10000 10000 +#define bfd_mach_mips12000 12000 +#define bfd_mach_mips16 16 +#define bfd_mach_mips5 5 +#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ +#define bfd_mach_mipsisa32 32 +#define bfd_mach_mipsisa32r2 33 +#define bfd_mach_mipsisa64 64 +#define bfd_mach_mipsisa64r2 65 + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +const struct mips_arch_choice mips_arch_choices[] = { + { "numeric", 0, 0, 0, 0, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + + { "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + { "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, + + /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs. + Note that MIPS-3D and MDMX are not applicable to MIPS32. (See + _MIPS32 Architecture For Programmers Volume I: Introduction to the + MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95), + page 1. */ + { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32, + ISA_MIPS32 | INSN_MIPS16, + mips_cp0_names_mips3264, + mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), + mips_hwr_names_numeric }, + + { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2, + ISA_MIPS32R2 | INSN_MIPS16, + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_hwr_names_mips3264r2 }, + + /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */ + { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64, + ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX, + mips_cp0_names_mips3264, + mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), + mips_hwr_names_numeric }, + + { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2, + ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX, + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_hwr_names_mips3264r2 }, + + { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1, + ISA_MIPS64 | INSN_MIPS3D | INSN_SB1, + mips_cp0_names_sb1, + mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1), + mips_hwr_names_numeric }, + + /* This entry, mips16, is here only for ISA/processor selection; do + not print its name. */ + { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16, + mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, +}; + +/* ISA and processor type to disassemble for, and register names to use. + set_default_mips_dis_options and parse_mips_dis_options fill in these + values. */ +static int mips_processor; +static int mips_isa; +static const char * const *mips_gpr_names; +static const char * const *mips_fpr_names; +static const char * const *mips_cp0_names; +static const struct mips_cp0sel_name *mips_cp0sel_names; +static int mips_cp0sel_names_len; +static const char * const *mips_hwr_names; + +static const struct mips_abi_choice *choose_abi_by_name + PARAMS ((const char *, unsigned int)); +static const struct mips_arch_choice *choose_arch_by_name + PARAMS ((const char *, unsigned int)); +static const struct mips_arch_choice *choose_arch_by_number + PARAMS ((unsigned long)); +static const struct mips_cp0sel_name *lookup_mips_cp0sel_name + PARAMS ((const struct mips_cp0sel_name *, unsigned int, unsigned int, + unsigned int)); + +static const struct mips_abi_choice * +choose_abi_by_name (name, namelen) + const char *name; + unsigned int namelen; +{ + const struct mips_abi_choice *c; + unsigned int i; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++) + { + if (strncmp (mips_abi_choices[i].name, name, namelen) == 0 + && strlen (mips_abi_choices[i].name) == namelen) + c = &mips_abi_choices[i]; + } + return c; +} + +static const struct mips_arch_choice * +choose_arch_by_name (name, namelen) + const char *name; + unsigned int namelen; +{ + const struct mips_arch_choice *c = NULL; + unsigned int i; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) + { + if (strncmp (mips_arch_choices[i].name, name, namelen) == 0 + && strlen (mips_arch_choices[i].name) == namelen) + c = &mips_arch_choices[i]; + } + return c; +} + +static const struct mips_arch_choice * +choose_arch_by_number (mach) + unsigned long mach; +{ + static unsigned long hint_bfd_mach; + static const struct mips_arch_choice *hint_arch_choice; + const struct mips_arch_choice *c; + unsigned int i; + + /* We optimize this because even if the user specifies no + flags, this will be done for every instruction! */ + if (hint_bfd_mach == mach + && hint_arch_choice != NULL + && hint_arch_choice->bfd_mach == hint_bfd_mach) + return hint_arch_choice; + + for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) + { + if (mips_arch_choices[i].bfd_mach_valid + && mips_arch_choices[i].bfd_mach == mach) + { + c = &mips_arch_choices[i]; + hint_bfd_mach = mach; + hint_arch_choice = c; + } + } + return c; +} + +void +set_default_mips_dis_options (info) + struct disassemble_info *info; +{ + const struct mips_arch_choice *chosen_arch; + + /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names, + and numeric FPR, CP0 register, and HWR names. */ + mips_isa = ISA_MIPS3; + mips_processor = CPU_R3000; + mips_gpr_names = mips_gpr_names_oldabi; + mips_fpr_names = mips_fpr_names_numeric; + mips_cp0_names = mips_cp0_names_numeric; + mips_cp0sel_names = NULL; + mips_cp0sel_names_len = 0; + mips_hwr_names = mips_hwr_names_numeric; + + /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */ +#if 0 + if (info->flavour == bfd_target_elf_flavour && info->section != NULL) + { + Elf_Internal_Ehdr *header; + + header = elf_elfheader (info->section->owner); + if (is_newabi (header)) + mips_gpr_names = mips_gpr_names_newabi; + } +#endif + + /* Set ISA, architecture, and cp0 register names as best we can. */ +#if ! SYMTAB_AVAILABLE && 0 + /* This is running out on a target machine, not in a host tool. + FIXME: Where does mips_target_info come from? */ + target_processor = mips_target_info.processor; + mips_isa = mips_target_info.isa; +#else + chosen_arch = choose_arch_by_number (info->mach); + if (chosen_arch != NULL) + { + mips_processor = chosen_arch->processor; + mips_isa = chosen_arch->isa; + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + mips_hwr_names = chosen_arch->hwr_names; + } +#endif +} + +void +parse_mips_dis_option (option, len) + const char *option; + unsigned int len; +{ + unsigned int i, optionlen, vallen; + const char *val; + const struct mips_abi_choice *chosen_abi; + const struct mips_arch_choice *chosen_arch; + + /* Look for the = that delimits the end of the option name. */ + for (i = 0; i < len; i++) + { + if (option[i] == '=') + break; + } + if (i == 0) /* Invalid option: no name before '='. */ + return; + if (i == len) /* Invalid option: no '='. */ + return; + if (i == (len - 1)) /* Invalid option: no value after '='. */ + return; + + optionlen = i; + val = option + (optionlen + 1); + vallen = len - (optionlen + 1); + + if (strncmp("gpr-names", option, optionlen) == 0 + && strlen("gpr-names") == optionlen) + { + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + mips_gpr_names = chosen_abi->gpr_names; + return; + } + + if (strncmp("fpr-names", option, optionlen) == 0 + && strlen("fpr-names") == optionlen) + { + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + mips_fpr_names = chosen_abi->fpr_names; + return; + } + + if (strncmp("cp0-names", option, optionlen) == 0 + && strlen("cp0-names") == optionlen) + { + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + { + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + } + return; + } + + if (strncmp("hwr-names", option, optionlen) == 0 + && strlen("hwr-names") == optionlen) + { + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + mips_hwr_names = chosen_arch->hwr_names; + return; + } + + if (strncmp("reg-names", option, optionlen) == 0 + && strlen("reg-names") == optionlen) + { + /* We check both ABI and ARCH here unconditionally, so + that "numeric" will do the desirable thing: select + numeric register names for all registers. Other than + that, a given name probably won't match both. */ + chosen_abi = choose_abi_by_name (val, vallen); + if (chosen_abi != NULL) + { + mips_gpr_names = chosen_abi->gpr_names; + mips_fpr_names = chosen_abi->fpr_names; + } + chosen_arch = choose_arch_by_name (val, vallen); + if (chosen_arch != NULL) + { + mips_cp0_names = chosen_arch->cp0_names; + mips_cp0sel_names = chosen_arch->cp0sel_names; + mips_cp0sel_names_len = chosen_arch->cp0sel_names_len; + mips_hwr_names = chosen_arch->hwr_names; + } + return; + } + + /* Invalid option. */ +} + +void +parse_mips_dis_options (options) + const char *options; +{ + const char *option_end; + + if (options == NULL) + return; + + while (*options != '\0') + { + /* Skip empty options. */ + if (*options == ',') + { + options++; + continue; + } + + /* We know that *options is neither NUL or a comma. */ + option_end = options + 1; + while (*option_end != ',' && *option_end != '\0') + option_end++; + + parse_mips_dis_option (options, option_end - options); + + /* Go on to the next one. If option_end points to a comma, it + will be skipped above. */ + options = option_end; + } +} + +static const struct mips_cp0sel_name * +lookup_mips_cp0sel_name(names, len, cp0reg, sel) + const struct mips_cp0sel_name *names; + unsigned int len, cp0reg, sel; +{ + unsigned int i; + + for (i = 0; i < len; i++) + if (names[i].cp0reg == cp0reg && names[i].sel == sel) + return &names[i]; + return NULL; +} + +/* Print insn arguments for 32/64-bit code. */ + +static void +print_insn_args (d, l, pc, info) + const char *d; + register unsigned long int l; + bfd_vma pc; + struct disassemble_info *info; +{ + int op, delta; + unsigned int lsb, msb, msbd; + + lsb = 0; + + for (; *d != '\0'; d++) + { + switch (*d) + { + case ',': + case '(': + case ')': + case '[': + case ']': + (*info->fprintf_func) (info->stream, "%c", *d); + break; + + case '+': + /* Extension character; switch for second char. */ + d++; + switch (*d) + { + case '\0': + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, incomplete extension sequence (+)")); + return; + + case 'A': + lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT; + (*info->fprintf_func) (info->stream, "0x%x", lsb); + break; + + case 'B': + msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB; + (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); + break; + + case 'C': + case 'H': + msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; + (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); + break; + + case 'D': + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RD) & OP_MASK_RD; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mtcN (et al.), to be + printed textually if known. If not known, print both + CP0 register name and sel numerically since CP0 register + with sel 0 may have a name unrelated to register being + printed. */ + n = lookup_mips_cp0sel_name(mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + (*info->fprintf_func) (info->stream, "%s", n->name); + else + (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel); + break; + } + + case 'E': + lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32; + (*info->fprintf_func) (info->stream, "0x%x", lsb); + break; + + case 'F': + msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32; + (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); + break; + + case 'G': + msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32; + (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); + break; + + default: + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, undefined extension sequence (+%c)"), + *d); + return; + } + break; + + case 's': + case 'b': + case 'r': + case 'v': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]); + break; + + case 't': + case 'w': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + break; + + case 'i': + case 'u': + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE); + break; + + case 'j': /* Same as i, but sign-extended. */ + case 'o': + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + (*info->fprintf_func) (info->stream, "%d", + delta); + break; + + case 'h': + (*info->fprintf_func) (info->stream, "0x%x", + (unsigned int) ((l >> OP_SH_PREFX) + & OP_MASK_PREFX)); + break; + + case 'k': + (*info->fprintf_func) (info->stream, "0x%x", + (unsigned int) ((l >> OP_SH_CACHE) + & OP_MASK_CACHE)); + break; + + case 'a': + info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff) + | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)); + (*info->print_address_func) (info->target, info); + break; + + case 'p': + /* Sign extend the displacement. */ + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) + delta |= ~0xffff; + info->target = (delta << 2) + pc + INSNLEN; + (*info->print_address_func) (info->target, info); + break; + + case 'd': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'U': + { + /* First check for both rd and rt being equal. */ + unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD; + if (reg == ((l >> OP_SH_RT) & OP_MASK_RT)) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[reg]); + else + { + /* If one is zero use the other. */ + if (reg == 0) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0) + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[reg]); + else /* Bogus, result depends on processor. */ + (*info->fprintf_func) (info->stream, "%s or %s", + mips_gpr_names[reg], + mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); + } + } + break; + + case 'z': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); + break; + + case '<': + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); + break; + + case 'c': + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_CODE) & OP_MASK_CODE); + break; + + case 'q': + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_CODE2) & OP_MASK_CODE2); + break; + + case 'C': + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_COPZ) & OP_MASK_COPZ); + break; + + case 'B': + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_CODE20) & OP_MASK_CODE20); + break; + + case 'J': + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_CODE19) & OP_MASK_CODE19); + break; + + case 'S': + case 'V': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]); + break; + + case 'T': + case 'W': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]); + break; + + case 'D': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]); + break; + + case 'R': + (*info->fprintf_func) (info->stream, "%s", + mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]); + break; + + case 'E': + /* Coprocessor register for lwcN instructions, et al. + + Note that there is no load/store cp0 instructions, and + that FPU (cp1) instructions disassemble this field using + 'T' format. Therefore, until we gain understanding of + cp2 register names, we can simply print the register + numbers. */ + (*info->fprintf_func) (info->stream, "$%d", + (l >> OP_SH_RT) & OP_MASK_RT); + break; + + case 'G': + /* Coprocessor register for mtcN instructions, et al. Note + that FPU (cp1) instructions disassemble this field using + 'S' format. Therefore, we only need to worry about cp0, + cp2, and cp3. */ + op = (l >> OP_SH_OP) & OP_MASK_OP; + if (op == OP_OP_COP0) + (*info->fprintf_func) (info->stream, "%s", + mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]); + else + (*info->fprintf_func) (info->stream, "$%d", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + + case 'K': + (*info->fprintf_func) (info->stream, "%s", + mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]); + break; + + case 'N': + (*info->fprintf_func) (info->stream, "$fcc%d", + (l >> OP_SH_BCC) & OP_MASK_BCC); + break; + + case 'M': + (*info->fprintf_func) (info->stream, "$fcc%d", + (l >> OP_SH_CCC) & OP_MASK_CCC); + break; + + case 'P': + (*info->fprintf_func) (info->stream, "%d", + (l >> OP_SH_PERFREG) & OP_MASK_PERFREG); + break; + + case 'e': + (*info->fprintf_func) (info->stream, "%d", + (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE); + break; + + case '%': + (*info->fprintf_func) (info->stream, "%d", + (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN); + break; + + case 'H': + (*info->fprintf_func) (info->stream, "%d", + (l >> OP_SH_SEL) & OP_MASK_SEL); + break; + + case 'O': + (*info->fprintf_func) (info->stream, "%d", + (l >> OP_SH_ALN) & OP_MASK_ALN); + break; + + case 'Q': + { + unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL; + if ((vsel & 0x10) == 0) + { + int fmt; + vsel &= 0x0f; + for (fmt = 0; fmt < 3; fmt++, vsel >>= 1) + if ((vsel & 1) == 0) + break; + (*info->fprintf_func) (info->stream, "$v%d[%d]", + (l >> OP_SH_FT) & OP_MASK_FT, + vsel >> 1); + } + else if ((vsel & 0x08) == 0) + { + (*info->fprintf_func) (info->stream, "$v%d", + (l >> OP_SH_FT) & OP_MASK_FT); + } + else + { + (*info->fprintf_func) (info->stream, "0x%x", + (l >> OP_SH_FT) & OP_MASK_FT); + } + } + break; + + case 'X': + (*info->fprintf_func) (info->stream, "$v%d", + (l >> OP_SH_FD) & OP_MASK_FD); + break; + + case 'Y': + (*info->fprintf_func) (info->stream, "$v%d", + (l >> OP_SH_FS) & OP_MASK_FS); + break; + + case 'Z': + (*info->fprintf_func) (info->stream, "$v%d", + (l >> OP_SH_FT) & OP_MASK_FT); + break; + + default: + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, + _("# internal error, undefined modifier(%c)"), + *d); + return; + } + } +} + +/* Check if the object uses NewABI conventions. */ +#if 0 +static int +is_newabi (header) + Elf_Internal_Ehdr *header; +{ + /* There are no old-style ABIs which use 64-bit ELF. */ + if (header->e_ident[EI_CLASS] == ELFCLASS64) + return 1; + + /* If a 32-bit ELF file, n32 is a new-style ABI. */ + if ((header->e_flags & EF_MIPS_ABI2) != 0) + return 1; + + return 0; +} +#endif + +/* Print the mips instruction at address MEMADDR in debugged memory, + on using INFO. Returns length of the instruction, in bytes, which is + always INSNLEN. BIGENDIAN must be 1 if this is big-endian code, 0 if + this is little-endian code. */ + +static int +print_insn_mips (memaddr, word, info) + bfd_vma memaddr; + unsigned long int word; + struct disassemble_info *info; +{ + register const struct mips_opcode *op; + static bfd_boolean init = 0; + static const struct mips_opcode *mips_hash[OP_MASK_OP + 1]; + + /* Build a hash table to shorten the search time. */ + if (! init) + { + unsigned int i; + + for (i = 0; i <= OP_MASK_OP; i++) + { + for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++) + { + if (op->pinfo == INSN_MACRO) + continue; + if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) + { + mips_hash[i] = op; + break; + } + } + } + + init = 1; + } + + info->bytes_per_chunk = INSNLEN; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP]; + if (op != NULL) + { + for (; op < &mips_opcodes[NUMOPCODES]; op++) + { + if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match) + { + register const char *d; + + /* We always allow to disassemble the jalx instruction. */ + if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor) + && strcmp (op->name, "jalx")) + continue; + + /* Figure out instruction type and branch delay information. */ + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) + { + if ((info->insn_type & INSN_WRITE_GPR_31) != 0) + info->insn_type = dis_jsr; + else + info->insn_type = dis_branch; + info->branch_delay_insns = 1; + } + else if ((op->pinfo & (INSN_COND_BRANCH_DELAY + | INSN_COND_BRANCH_LIKELY)) != 0) + { + if ((info->insn_type & INSN_WRITE_GPR_31) != 0) + info->insn_type = dis_condjsr; + else + info->insn_type = dis_condbranch; + info->branch_delay_insns = 1; + } + else if ((op->pinfo & (INSN_STORE_MEMORY + | INSN_LOAD_MEMORY_DELAY)) != 0) + info->insn_type = dis_dref; + + (*info->fprintf_func) (info->stream, "%s", op->name); + + d = op->args; + if (d != NULL && *d != '\0') + { + (*info->fprintf_func) (info->stream, "\t"); + print_insn_args (d, word, memaddr, info); + } + + return INSNLEN; + } + } + } + + /* Handle undefined instructions. */ + info->insn_type = dis_noninsn; + (*info->fprintf_func) (info->stream, "0x%x", word); + return INSNLEN; +} + +/* In an environment where we do not know the symbol type of the + instruction we are forced to assume that the low order bit of the + instructions' address may mark it as a mips16 instruction. If we + are single stepping, or the pc is within the disassembled function, + this works. Otherwise, we need a clue. Sometimes. */ + +#include "cpu.h" + +static int +_print_insn_mips (memaddr, info, endianness) + bfd_vma memaddr; + struct disassemble_info *info; + enum bfd_endian endianness; +{ + bfd_byte buffer[INSNLEN]; + int status; + + set_default_mips_dis_options (info); + parse_mips_dis_options (info->disassembler_options); + +#if 0 +#if 1 + /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */ + /* Only a few tools will work this way. */ + if (memaddr & 0x01) + return print_insn_mips16 (memaddr, info); +#endif + +#if SYMTAB_AVAILABLE + if (info->mach == bfd_mach_mips16 + || (info->flavour == bfd_target_elf_flavour + && info->symbols != NULL + && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other + == STO_MIPS16))) + return print_insn_mips16 (memaddr, info); +#endif +#endif + + status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info); + if (status == 0) + { + unsigned long insn; + + if (endianness == BFD_ENDIAN_BIG) + insn = (unsigned long) bfd_getb32 (buffer); + else + insn = (unsigned long) bfd_getl32 (buffer); + + return print_insn_mips (memaddr, insn, info); + } + else + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } +} + +int +print_insn_big_mips (memaddr, info) + bfd_vma memaddr; + struct disassemble_info *info; +{ + return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG); +} + +int +print_insn_little_mips (memaddr, info) + bfd_vma memaddr; + struct disassemble_info *info; +{ + return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE); +} + +/* Disassemble mips16 instructions. */ +#if 0 +static int +print_insn_mips16 (memaddr, info) + bfd_vma memaddr; + struct disassemble_info *info; +{ + int status; + bfd_byte buffer[2]; + int length; + int insn; + bfd_boolean use_extend; + int extend = 0; + const struct mips_opcode *op, *opend; + + info->bytes_per_chunk = 2; + info->display_endian = info->endian; + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->target = 0; + info->target2 = 0; + + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + length = 2; + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + /* Handle the extend opcode specially. */ + use_extend = FALSE; + if ((insn & 0xf800) == 0xf000) + { + use_extend = TRUE; + extend = insn & 0x7ff; + + memaddr += 2; + + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + if (status != 0) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_BIG) + insn = bfd_getb16 (buffer); + else + insn = bfd_getl16 (buffer); + + /* Check for an extend opcode followed by an extend opcode. */ + if ((insn & 0xf800) == 0xf000) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + info->insn_type = dis_noninsn; + return length; + } + + length += 2; + } + + /* FIXME: Should probably use a hash table on the major opcode here. */ + + opend = mips16_opcodes + bfd_mips16_num_opcodes; + for (op = mips16_opcodes; op < opend; op++) + { + if (op->pinfo != INSN_MACRO && (insn & op->mask) == op->match) + { + const char *s; + + if (strchr (op->args, 'a') != NULL) + { + if (use_extend) + { + (*info->fprintf_func) (info->stream, "extend 0x%x", + (unsigned int) extend); + info->insn_type = dis_noninsn; + return length - 2; + } + + use_extend = FALSE; + + memaddr += 2; + + status = (*info->read_memory_func) (memaddr, buffer, 2, + info); + if (status == 0) + { + use_extend = TRUE; + if (info->endian == BFD_ENDIAN_BIG) + extend = bfd_getb16 (buffer); + else + extend = bfd_getl16 (buffer); + length += 2; + } + } + + (*info->fprintf_func) (info->stream, "%s", op->name); + if (op->args[0] != '\0') + (*info->fprintf_func) (info->stream, "\t"); + + for (s = op->args; *s != '\0'; s++) + { + if (*s == ',' + && s[1] == 'w' + && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX) + == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY))) + { + /* Skip the register and the comma. */ + ++s; + continue; + } + if (*s == ',' + && s[1] == 'v' + && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ) + == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX))) + { + /* Skip the register and the comma. */ + ++s; + continue; + } + print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr, + info); + } + + if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) + { + info->branch_delay_insns = 1; + if (info->insn_type != dis_jsr) + info->insn_type = dis_branch; + } + + return length; + } + } + + if (use_extend) + (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000); + (*info->fprintf_func) (info->stream, "0x%x", insn); + info->insn_type = dis_noninsn; + + return length; +} + +/* Disassemble an operand for a mips16 instruction. */ + +static void +print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) + char type; + const struct mips_opcode *op; + int l; + bfd_boolean use_extend; + int extend; + bfd_vma memaddr; + struct disassemble_info *info; +{ + switch (type) + { + case ',': + case '(': + case ')': + (*info->fprintf_func) (info->stream, "%c", type); + break; + + case 'y': + case 'w': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names[((l >> MIPS16OP_SH_RY) + & MIPS16OP_MASK_RY)]); + break; + + case 'x': + case 'v': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names[((l >> MIPS16OP_SH_RX) + & MIPS16OP_MASK_RX)]); + break; + + case 'z': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names[((l >> MIPS16OP_SH_RZ) + & MIPS16OP_MASK_RZ)]); + break; + + case 'Z': + (*info->fprintf_func) (info->stream, "%s", + mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z) + & MIPS16OP_MASK_MOVE32Z)]); + break; + + case '0': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); + break; + + case 'S': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]); + break; + + case 'P': + (*info->fprintf_func) (info->stream, "$pc"); + break; + + case 'R': + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]); + break; + + case 'X': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[((l >> MIPS16OP_SH_REGR32) + & MIPS16OP_MASK_REGR32)]); + break; + + case 'Y': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]); + break; + + case '<': + case '>': + case '[': + case ']': + case '4': + case '5': + case 'H': + case 'W': + case 'D': + case 'j': + case '6': + case '8': + case 'V': + case 'C': + case 'U': + case 'k': + case 'K': + case 'p': + case 'q': + case 'A': + case 'B': + case 'E': + { + int immed, nbits, shift, signedp, extbits, pcrel, extu, branch; + + shift = 0; + signedp = 0; + extbits = 16; + pcrel = 0; + extu = 0; + branch = 0; + switch (type) + { + case '<': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 5; + extu = 1; + break; + case '>': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 5; + extu = 1; + break; + case '[': + nbits = 3; + immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ; + extbits = 6; + extu = 1; + break; + case ']': + nbits = 3; + immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX; + extbits = 6; + extu = 1; + break; + case '4': + nbits = 4; + immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4; + signedp = 1; + extbits = 15; + break; + case '5': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 1; + break; + case 'H': + nbits = 5; + shift = 1; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 2; + break; + case 'W': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + if ((op->pinfo & MIPS16_INSN_READ_PC) == 0 + && (op->pinfo & MIPS16_INSN_READ_SP) == 0) + { + info->insn_type = dis_dref; + info->data_size = 4; + } + break; + case 'D': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'j': + nbits = 5; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + signedp = 1; + break; + case '6': + nbits = 6; + immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + break; + case '8': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + break; + case 'V': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + /* FIXME: This might be lw, or it might be addiu to $sp or + $pc. We assume it's load. */ + info->insn_type = dis_dref; + info->data_size = 4; + break; + case 'C': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'U': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + extu = 1; + break; + case 'k': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'K': + nbits = 8; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + break; + case 'p': + nbits = 8; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + signedp = 1; + pcrel = 1; + branch = 1; + info->insn_type = dis_condbranch; + break; + case 'q': + nbits = 11; + immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11; + signedp = 1; + pcrel = 1; + branch = 1; + info->insn_type = dis_branch; + break; + case 'A': + nbits = 8; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8; + pcrel = 1; + /* FIXME: This can be lw or la. We assume it is lw. */ + info->insn_type = dis_dref; + info->data_size = 4; + break; + case 'B': + nbits = 5; + shift = 3; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + info->insn_type = dis_dref; + info->data_size = 8; + break; + case 'E': + nbits = 5; + shift = 2; + immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5; + pcrel = 1; + break; + default: + abort (); + } + + if (! use_extend) + { + if (signedp && immed >= (1 << (nbits - 1))) + immed -= 1 << nbits; + immed <<= shift; + if ((type == '<' || type == '>' || type == '[' || type == ']') + && immed == 0) + immed = 8; + } + else + { + if (extbits == 16) + immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0); + else if (extbits == 15) + immed |= ((extend & 0xf) << 11) | (extend & 0x7f0); + else + immed = ((extend >> 6) & 0x1f) | (extend & 0x20); + immed &= (1 << extbits) - 1; + if (! extu && immed >= (1 << (extbits - 1))) + immed -= 1 << extbits; + } + + if (! pcrel) + (*info->fprintf_func) (info->stream, "%d", immed); + else + { + bfd_vma baseaddr; + + if (branch) + { + immed *= 2; + baseaddr = memaddr + 2; + } + else if (use_extend) + baseaddr = memaddr - 2; + else + { + int status; + bfd_byte buffer[2]; + + baseaddr = memaddr; + + /* If this instruction is in the delay slot of a jr + instruction, the base address is the address of the + jr instruction. If it is in the delay slot of jalr + instruction, the base address is the address of the + jalr instruction. This test is unreliable: we have + no way of knowing whether the previous word is + instruction or data. */ + status = (*info->read_memory_func) (memaddr - 4, buffer, 2, + info); + if (status == 0 + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0xf800) == 0x1800)) + baseaddr = memaddr - 4; + else + { + status = (*info->read_memory_func) (memaddr - 2, buffer, + 2, info); + if (status == 0 + && (((info->endian == BFD_ENDIAN_BIG + ? bfd_getb16 (buffer) + : bfd_getl16 (buffer)) + & 0xf81f) == 0xe800)) + baseaddr = memaddr - 2; + } + } + info->target = (baseaddr & ~((1 << shift) - 1)) + immed; + (*info->print_address_func) (info->target, info); + } + } + break; + + case 'a': + if (! use_extend) + extend = 0; + l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); + info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l; + (*info->print_address_func) (info->target, info); + info->insn_type = dis_jsr; + info->branch_delay_insns = 1; + break; + + case 'l': + case 'L': + { + int need_comma, amask, smask; + + need_comma = 0; + + l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6; + + amask = (l >> 3) & 7; + + if (amask > 0 && amask < 5) + { + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]); + if (amask > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[amask + 3]); + need_comma = 1; + } + + smask = (l >> 1) & 3; + if (smask == 3) + { + (*info->fprintf_func) (info->stream, "%s??", + need_comma ? "," : ""); + need_comma = 1; + } + else if (smask > 0) + { + (*info->fprintf_func) (info->stream, "%s%s", + need_comma ? "," : "", + mips_gpr_names[16]); + if (smask > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[smask + 15]); + need_comma = 1; + } + + if (l & 1) + { + (*info->fprintf_func) (info->stream, "%s%s", + need_comma ? "," : "", + mips_gpr_names[31]); + need_comma = 1; + } + + if (amask == 5 || amask == 6) + { + (*info->fprintf_func) (info->stream, "%s$f0", + need_comma ? "," : ""); + if (amask == 6) + (*info->fprintf_func) (info->stream, "-$f1"); + } + } + break; + + default: + /* xgettext:c-format */ + (*info->fprintf_func) + (info->stream, + _("# internal disassembler error, unrecognised modifier (%c)"), + type); + abort (); + } +} +#endif + +void +print_mips_disassembler_options (stream) + FILE *stream; +{ + unsigned int i; + + fprintf (stream, _("\n\ +The following MIPS specific disassembler options are supported for use\n\ +with the -M switch (multiple options should be separated by commas):\n")); + + fprintf (stream, _("\n\ + gpr-names=ABI Print GPR names according to specified ABI.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + fpr-names=ABI Print FPR names according to specified ABI.\n\ + Default: numeric.\n")); + + fprintf (stream, _("\n\ + cp0-names=ARCH Print CP0 register names according to\n\ + specified architecture.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + hwr-names=ARCH Print HWR names according to specified \n\ + architecture.\n\ + Default: based on binary being disassembled.\n")); + + fprintf (stream, _("\n\ + reg-names=ABI Print GPR and FPR names according to\n\ + specified ABI.\n")); + + fprintf (stream, _("\n\ + reg-names=ARCH Print CP0 register and HWR names according to\n\ + specified architecture.\n")); + + fprintf (stream, _("\n\ + For the options above, the following values are supported for \"ABI\":\n\ + ")); + for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++) + fprintf (stream, " %s", mips_abi_choices[i].name); + fprintf (stream, _("\n")); + + fprintf (stream, _("\n\ + For the options above, The following values are supported for \"ARCH\":\n\ + ")); + for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++) + if (*mips_arch_choices[i].name != '\0') + fprintf (stream, " %s", mips_arch_choices[i].name); + fprintf (stream, _("\n")); + + fprintf (stream, _("\n")); +} -- cgit v1.2.3 From 6af0bf9c7c3ab9ddbf74a3bf34e067761eb43c3d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 14:58:51 +0000 Subject: MIPS target (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1464 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 22 +- cpu-all.h | 7 + cpu-exec.c | 74 +++ dis-asm.h | 2 + disas.c | 26 + elf.h | 18 + exec-all.h | 2 + hw/mips_r4k.c | 309 +++++++++ softmmu_header.h | 4 + target-mips/cpu.h | 415 ++++++++++++ target-mips/exec.h | 183 ++++++ target-mips/helper.c | 461 +++++++++++++ target-mips/mips-defs.h | 58 ++ target-mips/op.c | 641 ++++++++++++++++++ target-mips/op_helper.c | 634 ++++++++++++++++++ target-mips/op_helper_mem.c | 143 ++++ target-mips/op_mem.c | 113 ++++ target-mips/op_template.c | 65 ++ target-mips/translate.c | 1505 +++++++++++++++++++++++++++++++++++++++++++ translate-all.c | 2 + vl.c | 13 + vl.h | 5 + 22 files changed, 4701 insertions(+), 1 deletion(-) create mode 100644 hw/mips_r4k.c create mode 100644 target-mips/cpu.h create mode 100644 target-mips/exec.h create mode 100644 target-mips/helper.c create mode 100644 target-mips/mips-defs.h create mode 100644 target-mips/op.c create mode 100644 target-mips/op_helper.c create mode 100644 target-mips/op_helper_mem.c create mode 100644 target-mips/op_mem.c create mode 100644 target-mips/op_template.c create mode 100644 target-mips/translate.c diff --git a/Makefile.target b/Makefile.target index 9cff36746..ade079f85 100644 --- a/Makefile.target +++ b/Makefile.target @@ -72,6 +72,10 @@ ifeq ($(ARCH), ppc) PROGS+=$(QEMU_SYSTEM) endif +endif # TARGET_ARCH = ppc + +ifeq ($(TARGET_ARCH), mips) + ifeq ($(ARCH), i386) ifdef CONFIG_SOFTMMU PROGS+=$(QEMU_SYSTEM) @@ -84,7 +88,7 @@ PROGS+=$(QEMU_SYSTEM) endif endif # ARCH = x86_64 -endif # TARGET_ARCH = ppc +endif # TARGET_ARCH = mips ifeq ($(TARGET_ARCH), sparc) @@ -263,6 +267,10 @@ ifeq ($(TARGET_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 @@ -288,6 +296,9 @@ endif ifeq ($(findstring ppc, $(TARGET_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 @@ -348,6 +359,10 @@ VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o endif +ifeq ($(TARGET_ARCH), mips) +VL_OBJS+= mips.o mips_r4k.o dma.o vga.o serial.o #ide.o ne2000.o pckbd.o +VL_OBJS+= #i8259.o i8254.o fdc.o m48t59.o +endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) VL_OBJS+= sun4u.o m48t08.o magic-load.o slavio_serial.o @@ -455,6 +470,11 @@ op.o: op.c op_template.h op_mem.h op_helper.o: op_helper_mem.h endif +ifeq ($(TARGET_ARCH), mips) +op.o: op.c op_template.c op_mem.c +op_helper.o: op_helper_mem.c +endif + mixeng.o: mixeng.c mixeng.h mixeng_template.h %.o: %.c diff --git a/cpu-all.h b/cpu-all.h index 448f2c5ba..d50f5a2c6 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -617,6 +617,13 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size); #define cpu_gen_code cpu_ppc_gen_code #define cpu_signal_handler cpu_ppc_signal_handler +#elif defined(TARGET_MIPS) +#define CPUState CPUMIPSState +#define cpu_init cpu_mips_init +#define cpu_exec cpu_mips_exec +#define cpu_gen_code cpu_mips_gen_code +#define cpu_signal_handler cpu_mips_signal_handler + #else #error unsupported target CPU diff --git a/cpu-exec.c b/cpu-exec.c index 8c5557739..20cb0df62 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -182,6 +182,7 @@ int cpu_exec(CPUState *env1) saved_regwptr = REGWPTR; #endif #elif defined(TARGET_PPC) +#elif defined(TARGET_MIPS) #else #error unsupported target CPU #endif @@ -220,6 +221,8 @@ int cpu_exec(CPUState *env1) 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); #endif @@ -301,6 +304,19 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_TIMER; } } +#elif defined(TARGET_MIPS) + if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->CP0_Status & (1 << CP0St_IE)) && + (env->CP0_Cause & 0x0000FC00) && + !(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; + } #elif defined(TARGET_SPARC) if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->psret != 0)) { @@ -376,6 +392,8 @@ int cpu_exec(CPUState *env1) cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_PPC) cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_MIPS) + cpu_dump_state(env, logfile, fprintf, 0); #else #error unsupported target CPU #endif @@ -407,6 +425,10 @@ int cpu_exec(CPUState *env1) (msr_se << MSR_SE) | (msr_le << MSR_LE); cs_base = 0; pc = env->nip; +#elif defined(TARGET_MIPS) + flags = env->hflags & MIPS_HFLAGS_TMASK; + cs_base = NULL; + pc = env->PC; #else #error unsupported CPU #endif @@ -684,6 +706,7 @@ int cpu_exec(CPUState *env1) REGWPTR = saved_regwptr; #endif #elif defined(TARGET_PPC) +#elif defined(TARGET_MIPS) #else #error unsupported target CPU #endif @@ -935,6 +958,57 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* 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(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; +} + #else #error unsupported target CPU #endif diff --git a/dis-asm.h b/dis-asm.h index 8c4bb5d3e..4be6a352d 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -404,6 +404,8 @@ extern int generic_symbol_at_address bfd_vma bfd_getl32 (const bfd_byte *addr); bfd_vma bfd_getb32 (const bfd_byte *addr); +bfd_vma bfd_getl16 (const bfd_byte *addr); +bfd_vma bfd_getb16 (const bfd_byte *addr); typedef enum bfd_boolean {false, true} boolean; #endif /* ! defined (DIS_ASM_H) */ diff --git a/disas.c b/disas.c index c54e5d91c..f713040da 100644 --- a/disas.c +++ b/disas.c @@ -108,6 +108,24 @@ bfd_vma bfd_getb32 (const bfd_byte *addr) 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) @@ -162,6 +180,8 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) if (cpu_single_env->msr[MSR_LE]) disasm_info.endian = BFD_ENDIAN_LITTLE; print_insn = print_insn_ppc; +#elif defined(TARGET_MIPS) + print_insn = print_insn_big_mips; #else fprintf(out, "0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", code); @@ -222,6 +242,10 @@ void disas(FILE *out, void *code, unsigned long size) print_insn = print_insn_sparc; #elif defined(__arm__) print_insn = print_insn_arm; +#elif defined(__MIPSEB__) + print_insn = print_insn_big_mips; +#elif defined(__MIPSEL__) + print_insn = print_insn_little_mips; #else fprintf(out, "0x%lx: Asm output not supported on this arch\n", (long) code); @@ -332,6 +356,8 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) print_insn = print_insn_sparc; #elif defined(TARGET_PPC) print_insn = print_insn_ppc; +#elif defined(TARGET_MIPS) + print_insn = print_insn_big_mips; #else term_printf("0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", pc); diff --git a/elf.h b/elf.h index b5dca4b11..0dc82e7ca 100644 --- a/elf.h +++ b/elf.h @@ -31,11 +31,29 @@ typedef int64_t Elf64_Sxword; #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff #define PT_MIPS_REGINFO 0x70000000 +#define PT_MIPS_OPTIONS 0x70000001 /* Flags in the e_flags field of the header */ +/* MIPS architecture level. */ +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */ + +/* The ABI of a file. */ +#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */ +#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */ + #define EF_MIPS_NOREORDER 0x00000001 #define EF_MIPS_PIC 0x00000002 #define EF_MIPS_CPIC 0x00000004 +#define EF_MIPS_ABI2 0x00000020 +#define EF_MIPS_OPTIONS_FIRST 0x00000080 +#define EF_MIPS_32BITMODE 0x00000100 +#define EF_MIPS_ABI 0x0000f000 #define EF_MIPS_ARCH 0xf0000000 /* These constants define the different elf file types */ diff --git a/exec-all.h b/exec-all.h index 183df1faa..b7c0ad860 100644 --- a/exec-all.h +++ b/exec-all.h @@ -582,6 +582,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) is_user = ((env->hflags & HF_CPL_MASK) == 3); #elif defined (TARGET_PPC) is_user = msr_pr; +#elif defined (TARGET_MIPS) + is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); #elif defined (TARGET_SPARC) is_user = (env->psrs == 0); #else diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c new file mode 100644 index 000000000..1b6a80167 --- /dev/null +++ b/hw/mips_r4k.c @@ -0,0 +1,309 @@ +#include "vl.h" + +#define DEBUG_IRQ_COUNT + +#define BIOS_FILENAME "mips_bios.bin" +//#define BIOS_FILENAME "system.bin" +#define KERNEL_LOAD_ADDR 0x80010000 +#define INITRD_LOAD_ADDR 0x80800000 + +/* MIPS R4K IRQ controler */ +#if defined(DEBUG_IRQ_COUNT) +static uint64_t irq_count[16]; +#endif + +extern FILE *logfile; + +void mips_set_irq (int n_IRQ, int level) +{ + uint32_t mask; + + if (n_IRQ < 0 || n_IRQ >= 8) + return; + mask = 0x100 << n_IRQ; + if (level != 0) { +#if 1 + if (logfile) { + fprintf(logfile, "%s n %d l %d mask %08x %08x\n", + __func__, n_IRQ, level, mask, cpu_single_env->CP0_Status); + } +#endif + cpu_single_env->CP0_Cause |= mask; + if ((cpu_single_env->CP0_Status & 0x00000001) && + (cpu_single_env->CP0_Status & mask)) { +#if defined(DEBUG_IRQ_COUNT) + irq_count[n_IRQ]++; +#endif +#if 1 + if (logfile) + fprintf(logfile, "%s raise IRQ\n", __func__); +#endif + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + } + } else { + cpu_single_env->CP0_Cause &= ~mask; + } +} + +void pic_set_irq (int n_IRQ, int level) +{ + mips_set_irq(n_IRQ + 2, level); +} + +void pic_info (void) +{ + term_printf("IRQ asserted: %02x mask: %02x\n", + (cpu_single_env->CP0_Cause >> 8) & 0xFF, + (cpu_single_env->CP0_Status >> 8) & 0xFF); +} + +void irq_info (void) +{ +#if !defined(DEBUG_IRQ_COUNT) + term_printf("irq statistic code not compiled.\n"); +#else + int i; + int64_t count; + + term_printf("IRQ statistics:\n"); + for (i = 0; i < 8; i++) { + count = irq_count[i]; + if (count > 0) + term_printf("%2d: %lld\n", i, count); + } +#endif +} + +void cpu_mips_irqctrl_init (void) +{ +} + +/* MIPS R4K timer */ +uint32_t cpu_mips_get_random (CPUState *env) +{ + uint64_t now = qemu_get_clock(vm_clock); + + return (uint32_t)now & 0x0000000F; +} + +uint32_t cpu_mips_get_count (CPUState *env) +{ + return env->CP0_Count + + (uint32_t)muldiv64(qemu_get_clock(vm_clock), + 100 * 1000 * 1000, ticks_per_sec); +} + +static void cpu_mips_update_count (CPUState *env, uint32_t count, + uint32_t compare) +{ + uint64_t now, next; + uint32_t tmp; + + tmp = count; + if (count == compare) + tmp++; + now = qemu_get_clock(vm_clock); + next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); + if (next == now) + next++; +#if 1 + if (logfile) { + fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n", + __func__, now, count, compare, next - now); + } +#endif + /* Store new count and compare registers */ + env->CP0_Compare = compare; + env->CP0_Count = + count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec); + /* Adjust timer */ + qemu_mod_timer(env->timer, next); +} + +void cpu_mips_store_count (CPUState *env, uint32_t value) +{ + cpu_mips_update_count(env, value, env->CP0_Compare); +} + +void cpu_mips_store_compare (CPUState *env, uint32_t value) +{ + cpu_mips_update_count(env, cpu_mips_get_count(env), value); + pic_set_irq(5, 0); +} + +static void mips_timer_cb (void *opaque) +{ + CPUState *env; + + env = opaque; +#if 1 + if (logfile) { + fprintf(logfile, "%s\n", __func__); + } +#endif + cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); + pic_set_irq(5, 1); +} + +void cpu_mips_clock_init (CPUState *env) +{ + env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); + env->CP0_Compare = 0; + cpu_mips_update_count(env, 1, 0); +} + +static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + if (logfile) + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); + cpu_outb(NULL, addr & 0xffff, value); +} + +static uint32_t io_readb (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret = cpu_inb(NULL, addr & 0xffff); + if (logfile) + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); + return ret; +} + +static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + if (logfile) + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif + cpu_outw(NULL, addr & 0xffff, value); +} + +static uint32_t io_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret = cpu_inw(NULL, addr & 0xffff); +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap16(ret); +#endif + if (logfile) + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); + return ret; +} + +static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + if (logfile) + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif + cpu_outl(NULL, addr & 0xffff, value); +} + +static uint32_t io_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret = cpu_inl(NULL, addr & 0xffff); + +#ifdef TARGET_WORDS_BIGENDIAN + ret = bswap32(ret); +#endif + if (logfile) + fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); + return ret; +} + +CPUWriteMemoryFunc *io_write[] = { + &io_writeb, + &io_writew, + &io_writel, +}; + +CPUReadMemoryFunc *io_read[] = { + &io_readb, + &io_readw, + &io_readl, +}; + +void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + char buf[1024]; + target_ulong kernel_base, kernel_size, initrd_base, initrd_size; + unsigned long bios_offset; + int io_memory; + int linux_boot; + int ret; + + printf("%s: start\n", __func__); + linux_boot = (kernel_filename != NULL); + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + bios_offset = ram_size + vga_ram_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE); + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret != BIOS_SIZE) { + fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf); + exit(1); + } + cpu_register_physical_memory((uint32_t)(0x1fc00000), + BIOS_SIZE, bios_offset | IO_MEM_ROM); +#if 0 + memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE); + cpu_single_env->PC = 0x80010004; +#else + cpu_single_env->PC = 0xBFC00004; +#endif + if (linux_boot) { + kernel_base = KERNEL_LOAD_ADDR; + /* now we can load the kernel */ + kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + /* load initrd */ + if (initrd_filename) { + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_base); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + cpu_single_env->PC = KERNEL_LOAD_ADDR; + } else { + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; + } + /* XXX: should not be ! */ + printf("%s: init VGA\n", __func__); + vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + + + /* Init internal devices */ + cpu_mips_clock_init(cpu_single_env); + cpu_mips_irqctrl_init(); + + isa_mem_base = 0x78000000; + /* Register 64 KB of ISA IO space at random address */ + io_memory = cpu_register_io_memory(0, io_read, io_write, NULL); + cpu_register_physical_memory(0x70000000, 0x00010000, io_memory); + serial_init(0x3f8, 4, serial_hds[0]); + printf("%s: done\n", __func__); +} + +QEMUMachine mips_machine = { + "mips", + "mips r4k platform", + mips_r4k_init, +}; diff --git a/softmmu_header.h b/softmmu_header.h index f709f704a..0798cf572 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -55,6 +55,8 @@ #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) #elif defined (TARGET_PPC) #define CPU_MEM_INDEX (msr_pr) +#elif defined (TARGET_MIPS) +#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) #elif defined (TARGET_SPARC) #define CPU_MEM_INDEX ((env->psrs) == 0) #endif @@ -66,6 +68,8 @@ #define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) #elif defined (TARGET_PPC) #define CPU_MEM_INDEX (msr_pr) +#elif defined (TARGET_MIPS) +#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) #elif defined (TARGET_SPARC) #define CPU_MEM_INDEX ((env->psrs) == 0) #endif diff --git a/target-mips/cpu.h b/target-mips/cpu.h new file mode 100644 index 000000000..8f5150874 --- /dev/null +++ b/target-mips/cpu.h @@ -0,0 +1,415 @@ +#if !defined (__MIPS_CPU_H__) +#define __MIPS_CPU_H__ + +#include "mips-defs.h" +#include "cpu-defs.h" +#include "config.h" +#include "softfloat.h" + +typedef union fpr_t fpr_t; +union fpr_t { + double d; + float f; + uint32_t u[2]; +}; + +#if defined(MIPS_USES_R4K_TLB) +typedef struct tlb_t tlb_t; +struct tlb_t { + target_ulong VPN; + target_ulong end; + uint8_t ASID; + uint8_t G; + uint8_t C[2]; + uint8_t V[2]; + uint8_t D[2]; + target_ulong PFN[2]; +}; +#endif + +typedef struct CPUMIPSState CPUMIPSState; +struct CPUMIPSState { + /* General integer registers */ + target_ulong gpr[32]; + /* Special registers */ + target_ulong PC; + uint32_t HI, LO; + uint32_t DCR; /* ? */ +#if defined(MIPS_USES_FPU) + /* Floating point registers */ + fpr_t fpr[16]; + /* Floating point special purpose registers */ + uint32_t fcr0; + uint32_t fcr25; + uint32_t fcr26; + uint32_t fcr28; + uint32_t fcsr; +#endif +#if defined(MIPS_USES_R4K_TLB) + tlb_t tlb[16]; +#endif + uint32_t CP0_index; + uint32_t CP0_random; + uint32_t CP0_EntryLo0; + uint32_t CP0_EntryLo1; + uint32_t CP0_Context; + uint32_t CP0_PageMask; + uint32_t CP0_Wired; + uint32_t CP0_BadVAddr; + uint32_t CP0_Count; + uint32_t CP0_EntryHi; + uint32_t CP0_Compare; + uint32_t CP0_Status; +#define CP0St_CU3 31 +#define CP0St_CU2 30 +#define CP0St_CU1 29 +#define CP0St_CU0 28 +#define CP0St_RP 27 +#define CP0St_RE 25 +#define CP0St_BEV 22 +#define CP0St_TS 21 +#define CP0St_SR 20 +#define CP0St_NMI 19 +#define CP0St_IM 8 +#define CP0St_UM 4 +#define CP0St_ERL 2 +#define CP0St_EXL 1 +#define CP0St_IE 0 + uint32_t CP0_Cause; +#define CP0Ca_IV 23 + uint32_t CP0_EPC; + uint32_t CP0_PRid; + uint32_t CP0_Config0; +#define CP0C0_M 31 +#define CP0C0_K23 28 +#define CP0C0_KU 25 +#define CP0C0_MDU 20 +#define CP0C0_MM 17 +#define CP0C0_BM 16 +#define CP0C0_BE 15 +#define CP0C0_AT 13 +#define CP0C0_AR 10 +#define CP0C0_MT 7 +#define CP0C0_K0 0 + uint32_t CP0_Config1; +#define CP0C1_MMU 25 +#define CP0C1_IS 22 +#define CP0C1_IL 19 +#define CP0C1_IA 16 +#define CP0C1_DS 13 +#define CP0C1_DL 10 +#define CP0C1_DA 7 +#define CP0C1_PC 4 +#define CP0C1_WR 3 +#define CP0C1_CA 2 +#define CP0C1_EP 1 +#define CP0C1_FP 0 + uint32_t CP0_LLAddr; + uint32_t CP0_WatchLo; + uint32_t CP0_WatchHi; + uint32_t CP0_Debug; +#define CPDB_DBD 31 +#define CP0DB_DM 30 +#define CP0DB_LSNM 28 +#define CP0DB_Doze 27 +#define CP0DB_Halt 26 +#define CP0DB_CNT 25 +#define CP0DB_IBEP 24 +#define CP0DB_DBEP 21 +#define CP0DB_IEXI 20 +#define CP0DB_VER 15 +#define CP0DB_DEC 10 +#define CP0DB_SSt 8 +#define CP0DB_DINT 5 +#define CP0DB_DIB 4 +#define CP0DB_DDBS 3 +#define CP0DB_DDBL 2 +#define CP0DB_DBp 1 +#define CP0DB_DSS 0 + uint32_t CP0_DEPC; + uint32_t CP0_TagLo; + uint32_t CP0_DataLo; + uint32_t CP0_ErrorEPC; + uint32_t CP0_DESAVE; + /* Qemu */ +#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU) + double ft0, ft1, ft2; +#endif + struct QEMUTimer *timer; /* Internal timer */ + int interrupt_request; + jmp_buf jmp_env; + int exception_index; + int error_code; + int user_mode_only; /* user mode only simulation */ + uint32_t hflags; /* CPU State */ + /* TMASK defines different execution modes */ +#define MIPS_HFLAGS_TMASK 0x00FF +#define MIPS_HFLAG_MODE 0x001F /* execution modes */ +#define MIPS_HFLAG_UM 0x0001 /* user mode */ +#define MIPS_HFLAG_ERL 0x0002 /* Error mode */ +#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */ +#define MIPS_HFLAG_DM 0x0008 /* Debug mode */ +#define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ +#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ +#define MIPS_HFLAG_DS 0x0080 /* In / out of delay slot */ + /* Those flags keep the branch state if the translation is interrupted + * between the branch instruction and the delay slot + */ +#define MIPS_HFLAG_BMASK 0x0F00 +#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */ +#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */ +#define MIPS_HFLAG_BL 0x0400 /* Likely branch */ +#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */ + target_ulong btarget; /* Jump / branch target */ + int bcond; /* Branch condition (if needed) */ + 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) */ + target_ulong mem_write_pc; /* host pc at which the memory was + written */ + unsigned long mem_write_vaddr; /* target virtual addr at which the + memory was written */ + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + /* ice debug support */ + target_ulong breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; + int singlestep_enabled; /* XXX: should use CPU single step mode instead */ + /* user data */ + void *opaque; +}; + +#include "cpu-all.h" + +/* Memory access type : + * may be needed for precise access rights control and precise exceptions. + */ +enum { + /* 1 bit to define user level / supervisor access */ + ACCESS_USER = 0x00, + ACCESS_SUPER = 0x01, + /* 1 bit to indicate direction */ + ACCESS_STORE = 0x02, + /* Type of instruction that generated the access */ + ACCESS_CODE = 0x10, /* Code fetch access */ + ACCESS_INT = 0x20, /* Integer load/store access */ + ACCESS_FLOAT = 0x30, /* floating point load/store access */ +}; + +/* Exceptions */ +enum { + EXCP_NONE = -1, + EXCP_RESET = 0, + EXCP_SRESET, + EXCP_DSS, + EXCP_DINT, + EXCP_NMI, + EXCP_MCHECK, + EXCP_EXT_INTERRUPT, + EXCP_DFWATCH, + EXCP_DIB, /* 8 */ + EXCP_IWATCH, + EXCP_AdEL, + EXCP_AdES, + EXCP_TLBF, + EXCP_IBE, + EXCP_DBp, + EXCP_SYSCALL, + EXCP_BREAK, + EXCP_CpU, /* 16 */ + EXCP_RI, + EXCP_OVERFLOW, + EXCP_TRAP, + EXCP_DDBS, + EXCP_DWATCH, + EXCP_LAE, /* 22 */ + EXCP_SAE, + EXCP_LTLBL, + EXCP_TLBL, + EXCP_TLBS, + EXCP_DBE, + EXCP_DDBL, + EXCP_MTCP0 = 0x104, /* mtmsr instruction: */ + /* may change privilege level */ + EXCP_BRANCH = 0x108, /* branch instruction */ + EXCP_ERET = 0x10C, /* return from interrupt */ + EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */ + EXCP_FLUSH = 0x109, +}; + +/* MIPS opcodes */ +#define EXT_SPECIAL 0x100 +#define EXT_SPECIAL2 0x200 +#define EXT_REGIMM 0x300 +#define EXT_CP0 0x400 +#define EXT_CP1 0x500 +#define EXT_CP2 0x600 +#define EXT_CP3 0x700 + +enum { + /* indirect opcode tables */ + OPC_SPECIAL = 0x00, + OPC_BREGIMM = 0x01, + OPC_CP0 = 0x10, + OPC_CP1 = 0x11, + OPC_CP2 = 0x12, + OPC_CP3 = 0x13, + OPC_SPECIAL2 = 0x1C, + /* arithmetic with immediate */ + OPC_ADDI = 0x08, + OPC_ADDIU = 0x09, + OPC_SLTI = 0x0A, + OPC_SLTIU = 0x0B, + OPC_ANDI = 0x0C, + OPC_ORI = 0x0D, + OPC_XORI = 0x0E, + OPC_LUI = 0x0F, + /* Jump and branches */ + OPC_J = 0x02, + OPC_JAL = 0x03, + OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */ + OPC_BEQL = 0x14, + OPC_BNE = 0x05, + OPC_BNEL = 0x15, + OPC_BLEZ = 0x06, + OPC_BLEZL = 0x16, + OPC_BGTZ = 0x07, + OPC_BGTZL = 0x17, + OPC_JALX = 0x1D, /* MIPS 16 only */ + /* Load and stores */ + OPC_LB = 0x20, + OPC_LH = 0x21, + OPC_LWL = 0x22, + OPC_LW = 0x23, + OPC_LBU = 0x24, + OPC_LHU = 0x25, + OPC_LWR = 0x26, + OPC_SB = 0x28, + OPC_SH = 0x29, + OPC_SWL = 0x2A, + OPC_SW = 0x2B, + OPC_SWR = 0x2E, + OPC_LL = 0x30, + OPC_SC = 0x38, + /* Floating point load/store */ + OPC_LWC1 = 0x31, + OPC_LWC2 = 0x32, + OPC_LDC1 = 0x35, + OPC_LDC2 = 0x36, + OPC_SWC1 = 0x39, + OPC_SWC2 = 0x3A, + OPC_SDC1 = 0x3D, + OPC_SDC2 = 0x3E, + /* Cache and prefetch */ + OPC_CACHE = 0x2F, + OPC_PREF = 0x33, +}; + +/* MIPS special opcodes */ +enum { + /* Shifts */ + OPC_SLL = 0x00 | EXT_SPECIAL, + /* NOP is SLL r0, r0, 0 */ + /* SSNOP is SLL r0, r0, 1 */ + OPC_SRL = 0x02 | EXT_SPECIAL, + OPC_SRA = 0x03 | EXT_SPECIAL, + OPC_SLLV = 0x04 | EXT_SPECIAL, + OPC_SRLV = 0x06 | EXT_SPECIAL, + OPC_SRAV = 0x07 | EXT_SPECIAL, + /* Multiplication / division */ + OPC_MULT = 0x18 | EXT_SPECIAL, + OPC_MULTU = 0x19 | EXT_SPECIAL, + OPC_DIV = 0x1A | EXT_SPECIAL, + OPC_DIVU = 0x1B | EXT_SPECIAL, + /* 2 registers arithmetic / logic */ + OPC_ADD = 0x20 | EXT_SPECIAL, + OPC_ADDU = 0x21 | EXT_SPECIAL, + OPC_SUB = 0x22 | EXT_SPECIAL, + OPC_SUBU = 0x23 | EXT_SPECIAL, + OPC_AND = 0x24 | EXT_SPECIAL, + OPC_OR = 0x25 | EXT_SPECIAL, + OPC_XOR = 0x26 | EXT_SPECIAL, + OPC_NOR = 0x27 | EXT_SPECIAL, + OPC_SLT = 0x2A | EXT_SPECIAL, + OPC_SLTU = 0x2B | EXT_SPECIAL, + /* Jumps */ + OPC_JR = 0x08 | EXT_SPECIAL, + OPC_JALR = 0x09 | EXT_SPECIAL, + /* Traps */ + OPC_TGE = 0x30 | EXT_SPECIAL, + OPC_TGEU = 0x31 | EXT_SPECIAL, + OPC_TLT = 0x32 | EXT_SPECIAL, + OPC_TLTU = 0x33 | EXT_SPECIAL, + OPC_TEQ = 0x34 | EXT_SPECIAL, + OPC_TNE = 0x36 | EXT_SPECIAL, + /* HI / LO registers load & stores */ + OPC_MFHI = 0x10 | EXT_SPECIAL, + OPC_MTHI = 0x11 | EXT_SPECIAL, + OPC_MFLO = 0x12 | EXT_SPECIAL, + OPC_MTLO = 0x13 | EXT_SPECIAL, + /* Conditional moves */ + OPC_MOVZ = 0x0A | EXT_SPECIAL, + OPC_MOVN = 0x0B | EXT_SPECIAL, + + OPC_MOVCI = 0x01 | EXT_SPECIAL, + + /* Special */ + OPC_PMON = 0x05 | EXT_SPECIAL, + OPC_SYSCALL = 0x0C | EXT_SPECIAL, + OPC_BREAK = 0x0D | EXT_SPECIAL, + OPC_SYNC = 0x0F | EXT_SPECIAL, +}; + +enum { + /* Mutiply & xxx operations */ + OPC_MADD = 0x00 | EXT_SPECIAL2, + OPC_MADDU = 0x01 | EXT_SPECIAL2, + OPC_MUL = 0x02 | EXT_SPECIAL2, + OPC_MSUB = 0x04 | EXT_SPECIAL2, + OPC_MSUBU = 0x05 | EXT_SPECIAL2, + /* Misc */ + OPC_CLZ = 0x20 | EXT_SPECIAL2, + OPC_CLO = 0x21 | EXT_SPECIAL2, + /* Special */ + OPC_SDBBP = 0x3F | EXT_SPECIAL2, +}; + +/* Branch REGIMM */ +enum { + OPC_BLTZ = 0x00 | EXT_REGIMM, + OPC_BLTZL = 0x02 | EXT_REGIMM, + OPC_BGEZ = 0x01 | EXT_REGIMM, + OPC_BGEZL = 0x03 | EXT_REGIMM, + OPC_BLTZAL = 0x10 | EXT_REGIMM, + OPC_BLTZALL = 0x12 | EXT_REGIMM, + OPC_BGEZAL = 0x11 | EXT_REGIMM, + OPC_BGEZALL = 0x13 | EXT_REGIMM, + OPC_TGEI = 0x08 | EXT_REGIMM, + OPC_TGEIU = 0x09 | EXT_REGIMM, + OPC_TLTI = 0x0A | EXT_REGIMM, + OPC_TLTIU = 0x0B | EXT_REGIMM, + OPC_TEQI = 0x0C | EXT_REGIMM, + OPC_TNEI = 0x0E | EXT_REGIMM, +}; + +enum { + /* Coprocessor 0 (MMU) */ + OPC_MFC0 = 0x00 | EXT_CP0, + OPC_MTC0 = 0x04 | EXT_CP0, + OPC_TLBR = 0x01 | EXT_CP0, + OPC_TLBWI = 0x02 | EXT_CP0, + OPC_TLBWR = 0x06 | EXT_CP0, + OPC_TLBP = 0x08 | EXT_CP0, + OPC_ERET = 0x18 | EXT_CP0, + OPC_DERET = 0x1F | EXT_CP0, + OPC_WAIT = 0x20 | EXT_CP0, +}; + +int cpu_mips_exec(CPUMIPSState *s); +CPUMIPSState *cpu_mips_init(void); +uint32_t cpu_mips_get_clock (void); + +#endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-mips/exec.h b/target-mips/exec.h new file mode 100644 index 000000000..258a96b84 --- /dev/null +++ b/target-mips/exec.h @@ -0,0 +1,183 @@ +#if !defined(__QEMU_MIPS_EXEC_H__) +#define __QEMU_MIPS_EXEC_H__ + +#define DEBUG_OP + +#include "mips-defs.h" +#include "dyngen-exec.h" + +register struct CPUMIPSState *env asm(AREG0); + +#if defined (USE_64BITS_REGS) +typedef int64_t host_int_t; +typedef uint64_t host_uint_t; +#else +typedef int32_t host_int_t; +typedef uint32_t host_uint_t; +#endif + +register host_uint_t T0 asm(AREG1); +register host_uint_t T1 asm(AREG2); +register host_uint_t T2 asm(AREG3); +register host_int_t Ts0 asm(AREG1); +register host_int_t Ts1 asm(AREG2); +register host_int_t Ts2 asm(AREG3); + +#define PARAM(n) ((uint32_t)PARAM##n) +#define SPARAM(n) ((int32_t)PARAM##n) + +#if defined (USE_HOST_FLOAT_REGS) +register double FT0 asm(FREG0); +register double FT1 asm(FREG1); +register double FT2 asm(FREG2); +register float FTS0 asm(FREG0); +register float FTS1 asm(FREG1); +register float FTS2 asm(FREG2); +#else +#define FT0 (env->ft0.d) +#define FT1 (env->ft1.d) +#define FT2 (env->ft2.d) +#define FTS0 (env->ft0.f) +#define FTS1 (env->ft1.f) +#define FTS2 (env->ft2.f) +#endif + +#if defined (DEBUG_OP) +#define RETURN() __asm__ __volatile__("nop"); +#else +#define RETURN() __asm__ __volatile__(""); +#endif + +#include "cpu.h" +#include "exec-all.h" + +#if !defined(CONFIG_USER_ONLY) + +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel + +#define ACCESS_TYPE 0 +#define MEMSUFFIX _kernel +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ACCESS_TYPE 1 +#define MEMSUFFIX _user +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE 2 +#define MEMSUFFIX _data +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ldub(p) ldub_data(p) +#define ldsb(p) ldsb_data(p) +#define lduw(p) lduw_data(p) +#define ldsw(p) ldsw_data(p) +#define ldl(p) ldl_data(p) +#define ldq(p) ldq_data(p) + +#define stb(p, v) stb_data(p, v) +#define stw(p, v) stw_data(p, v) +#define stl(p, v) stl_data(p, v) +#define stq(p, v) stq_data(p, v) + +#endif /* !defined(CONFIG_USER_ONLY) */ + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +#if (HOST_LONG_BITS == 32) +void do_mult (void); +void do_multu (void); +void do_madd (void); +void do_maddu (void); +void do_msub (void); +void do_msubu (void); +#endif +__attribute__ (( regparm(2) )) +void do_mfc0(int reg, int sel); +__attribute__ (( regparm(2) )) +void do_mtc0(int reg, int sel); +void do_tlbwi (void); +void do_tlbwr (void); +void do_tlbp (void); +void do_tlbr (void); +void do_lwl_raw (void); +void do_lwr_raw (void); +void do_swl_raw (void); +void do_swr_raw (void); +#if !defined(CONFIG_USER_ONLY) +void do_lwl_user (void); +void do_lwl_kernel (void); +void do_lwr_user (void); +void do_lwr_kernel (void); +void do_swl_user (void); +void do_swl_kernel (void); +void do_swr_user (void); +void do_swr_kernel (void); +#endif +__attribute__ (( regparm(1) )) +void do_pmon (int function); + +int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu); +void do_interrupt (CPUState *env); + +void cpu_loop_exit(void); +__attribute__ (( regparm(2) )) +void do_raise_exception_err (uint32_t exception, int error_code); +__attribute__ (( regparm(1) )) +void do_raise_exception (uint32_t exception); + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags); +void cpu_mips_irqctrl_init (void); +uint32_t cpu_mips_get_random (CPUState *env); +uint32_t cpu_mips_get_count (CPUState *env); +void cpu_mips_store_count (CPUState *env, uint32_t value); +void cpu_mips_store_compare (CPUState *env, uint32_t value); +void cpu_mips_clock_init (CPUState *env); + +#endif /* !defined(__QEMU_MIPS_EXEC_H__) */ diff --git a/target-mips/helper.c b/target-mips/helper.c new file mode 100644 index 000000000..05661bb97 --- /dev/null +++ b/target-mips/helper.c @@ -0,0 +1,461 @@ +/* + * MIPS emulation helpers for qemu. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "exec.h" + +/* MIPS32 4K MMU emulation */ +#if MIPS_USES_4K_TLB +static int map_address (CPUState *env, target_ulong *physical, int *prot, + target_ulong address, int rw, int access_type) +{ + tlb_t *tlb; + target_ulong tag; + uint8_t ASID; + int i, n; + int ret; + + ret = -2; + tag = (address & 0xFFFFE000); + ASID = env->CP0_EntryHi & 0x000000FF; + for (i = 0; i < 16; i++) { + tlb = &env->tlb[i]; + /* Check ASID, virtual page number & size */ + if ((tlb->G == 1 || tlb->ASID == ASID) && + tlb->VPN == tag && address < tlb->end) { + /* TLB match */ + n = (address >> 12) & 1; + /* Check access rights */ + if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) { + *physical = tlb->PFN[n] | (address & 0xFFF); + *prot = PROT_READ; + if (tlb->D[n]) + *prot |= PROT_WRITE; + return 0; + } else if (!(tlb->V[n] & 2)) { + return -3; + } else { + return -4; + } + } + } + + return ret; +} +#endif + +int get_physical_address (CPUState *env, target_ulong *physical, int *prot, + target_ulong address, int rw, int access_type) +{ + int user_mode; + int ret; + + /* User mode can only access useg */ + user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0; +#if 0 + if (logfile) { + fprintf(logfile, "user mode %d h %08x\n", + user_mode, env->hflags); + } +#endif + if (user_mode && address > 0x7FFFFFFFUL) + return -1; + ret = 0; + if (address < 0x80000000UL) { + if (user_mode || !(env->hflags & MIPS_HFLAG_ERL)) { +#if MIPS_USES_4K_TLB + ret = map_address(env, physical, prot, address, rw); +#else + *physical = address + 0x40000000UL; + *prot = PAGE_READ | PAGE_WRITE; +#endif + } else { + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; + } + } else if (address < 0xA0000000UL) { + /* kseg0 */ + /* XXX: check supervisor mode */ + *physical = address - 0x80000000UL; + *prot = PAGE_READ | PAGE_WRITE; + } else if (address < 0xC0000000UL) { + /* kseg1 */ + /* XXX: check supervisor mode */ + *physical = address - 0xA0000000UL; + *prot = PAGE_READ | PAGE_WRITE; + } else if (address < 0xE0000000UL) { + /* kseg2 */ +#if MIPS_USES_4K_TLB + ret = map_address(env, physical, prot, address, rw); +#else + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; +#endif + } else { + /* kseg3 */ + /* XXX: check supervisor mode */ + /* XXX: debug segment is not emulated */ +#if MIPS_USES_4K_TLB + ret = map_address(env, physical, prot, address, rw); +#else + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; +#endif + } +#if 0 + if (logfile) { + fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw, + access_type, *physical, *prot, ret); + } +#endif + + return ret; +} + +#if defined(CONFIG_USER_ONLY) +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} +#else +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + target_ulong phys_addr; + int prot; + + if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) + return -1; + return phys_addr; +} +#endif + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + unsigned long pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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, NULL); + } + } + do_raise_exception_err(env->exception_index, env->error_code); + } + env = saved_env; +} + +void cpu_mips_init_mmu (CPUState *env) +{ +} + +#endif /* !defined(CONFIG_USER_ONLY) */ + +int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + target_ulong physical; + int prot; + int exception = 0, error_code = 0; + int access_type; + int ret = 0; + + if (logfile) { + cpu_dump_state(env, logfile, fprintf, 0); + fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n", + __func__, env->PC, address, rw, is_user, is_softmmu); + } + /* data access */ + /* XXX: put correct access by using cpu_restore_state() + correctly */ + access_type = ACCESS_INT; + if (env->user_mode_only) { + /* user mode only emulation */ + ret = -2; + goto do_fault; + } + ret = get_physical_address(env, &physical, &prot, + address, rw, access_type); + if (logfile) { + fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n", + __func__, address, ret, physical, prot); + } + if (ret == 0) { + ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot, + is_user, is_softmmu); + } else if (ret < 0) { + do_fault: + switch (ret) { + default: + case -1: + /* Reference to kernel address from user mode or supervisor mode */ + /* Reference to supervisor address from user mode */ + if (rw) + exception = EXCP_AdES; + else + exception = EXCP_AdEL; + break; + case -2: + /* No TLB match for a mapped address */ + if (rw) + exception = EXCP_TLBS; + else + exception = EXCP_TLBL; + error_code = 1; + break; + case -3: + /* TLB match with no valid bit */ + if (rw) + exception = EXCP_TLBS; + else + exception = EXCP_TLBL; + error_code = 0; + break; + case -4: + /* TLB match but 'D' bit is cleared */ + exception = EXCP_LTLBL; + break; + + } + if (ret == -2) { + exception = EXCP_AdEL; + } + /* Raise exception */ + env->CP0_BadVAddr = address; + env->CP0_Context = + (env->CP0_Context & 0x00000FFF) | (address & 0xFFFFF000); + env->CP0_EntryHi = + (env->CP0_EntryHi & 0x00000FFF) | (address & 0xFFFFF000); + env->exception_index = exception; + env->error_code = error_code; + ret = 1; + } + + return ret; +} + +void do_interrupt (CPUState *env) +{ + target_ulong pc, offset; + int cause = -1; + + if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { + fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n", + __func__, env->PC, env->CP0_EPC, cause, env->exception_index); + } + if (env->exception_index == EXCP_EXT_INTERRUPT && + (env->hflags & MIPS_HFLAG_DM)) + env->exception_index = EXCP_DINT; + offset = 0x180; + switch (env->exception_index) { + case EXCP_DSS: + env->CP0_Debug |= 1 << CP0DB_DSS; + /* Debug single step cannot be raised inside a delay slot and + * resume will always occur on the next instruction + * (but we assume the pc has always been updated during + * code translation). + */ + env->CP0_DEPC = env->PC; + goto enter_debug_mode; + case EXCP_DINT: + env->CP0_Debug |= 1 << CP0DB_DINT; + goto set_DEPC; + case EXCP_DIB: + env->CP0_Debug |= 1 << CP0DB_DIB; + goto set_DEPC; + case EXCP_DBp: + env->CP0_Debug |= 1 << CP0DB_DBp; + goto set_DEPC; + case EXCP_DDBS: + env->CP0_Debug |= 1 << CP0DB_DDBS; + goto set_DEPC; + case EXCP_DDBL: + env->CP0_Debug |= 1 << CP0DB_DDBL; + goto set_DEPC; + set_DEPC: + if (env->hflags & MIPS_HFLAG_DS) { + /* If the exception was raised from a delay slot, + * come back to the jump + */ + env->CP0_DEPC = env->PC - 4; + } else { + env->CP0_DEPC = env->PC; + } + enter_debug_mode: + env->hflags |= MIPS_HFLAG_DM; + /* EJTAG probe trap enable is not implemented... */ + pc = 0xBFC00480; + break; + case EXCP_RESET: +#if defined (MIPS_USES_R4K_TLB) + env->CP0_random = MIPS_TLB_NB - 1; +#endif + env->CP0_Wired = 0; + env->CP0_Config0 = MIPS_CONFIG0; +#if defined (MIPS_CONFIG1) + env->CP0_Config1 = MIPS_CONFIG1; +#endif +#if defined (MIPS_CONFIG2) + env->CP0_Config2 = MIPS_CONFIG2; +#endif +#if defined (MIPS_CONFIG3) + env->CP0_Config3 = MIPS_CONFIG3; +#endif + env->CP0_WatchLo = 0; + env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV); + goto set_error_EPC; + case EXCP_SRESET: + env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) | + (1 << CP0St_SR); + env->CP0_WatchLo = 0; + goto set_error_EPC; + case EXCP_NMI: + env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) | + (1 << CP0St_NMI); + set_error_EPC: + env->hflags = MIPS_HFLAG_ERL; + if (env->hflags & MIPS_HFLAG_DS) { + /* If the exception was raised from a delay slot, + * come back to the jump + */ + env->CP0_ErrorEPC = env->PC - 4; + } else { + env->CP0_ErrorEPC = env->PC; + } + pc = 0xBFC00000; + break; + case EXCP_MCHECK: + cause = 24; + goto set_EPC; + case EXCP_EXT_INTERRUPT: + cause = 0; + if (env->CP0_Cause & (1 << CP0Ca_IV)) + offset = 0x200; + goto set_EPC; + case EXCP_DWATCH: + cause = 23; + /* XXX: TODO: manage defered watch exceptions */ + goto set_EPC; + case EXCP_AdEL: + case EXCP_AdES: + cause = 4; + goto set_EPC; + case EXCP_TLBL: + case EXCP_TLBF: + cause = 2; + if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) + offset = 0x000; + goto set_EPC; + case EXCP_IBE: + cause = 6; + goto set_EPC; + case EXCP_DBE: + cause = 7; + goto set_EPC; + case EXCP_SYSCALL: + cause = 8; + goto set_EPC; + case EXCP_BREAK: + cause = 9; + goto set_EPC; + case EXCP_RI: + cause = 10; + goto set_EPC; + case EXCP_CpU: + cause = 11; + /* XXX: fill in the faulty unit number */ + goto set_EPC; + case EXCP_OVERFLOW: + cause = 12; + goto set_EPC; + case EXCP_TRAP: + cause = 13; + goto set_EPC; + case EXCP_LTLBL: + cause = 1; + goto set_EPC; + case EXCP_TLBS: + cause = 3; + set_EPC: + if (env->CP0_Status & (1 << CP0St_BEV)) { + pc = 0xBFC00200; + } else { + pc = 0x80000000; + } + env->hflags |= MIPS_HFLAG_EXL; + pc += offset; + env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); + if (env->hflags & MIPS_HFLAG_DS) { + /* If the exception was raised from a delay slot, + * come back to the jump + */ + env->CP0_EPC = env->PC - 4; + env->CP0_Cause |= 0x80000000; + } else { + env->CP0_EPC = env->PC; + env->CP0_Cause &= ~0x80000000; + } + break; + default: + if (logfile) { + fprintf(logfile, "Invalid MIPS exception %d. Exiting\n", + env->exception_index); + } + printf("Invalid MIPS exception %d. Exiting\n", env->exception_index); + exit(1); + } + env->PC = pc; + if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { + fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n" + " S %08x C %08x A %08x D %08x\n", + __func__, env->PC, env->CP0_EPC, cause, env->exception_index, + env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, + env->CP0_DEPC); + } + env->exception_index = EXCP_NONE; +} diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h new file mode 100644 index 000000000..6d28e9cd0 --- /dev/null +++ b/target-mips/mips-defs.h @@ -0,0 +1,58 @@ +#if !defined (__QEMU_MIPS_DEFS_H__) +#define __QEMU_MIPS_DEFS_H__ + +/* If we want to use 64 bits host regs... */ +//#define USE_64BITS_REGS +/* If we want to use host float regs... */ +//#define USE_HOST_FLOAT_REGS + +enum { + MIPS_R4Kc = 0x00018000, + MIPS_R4Kp = 0x00018300, +}; + +/* Emulate MIPS R4Kc for now */ +#define MIPS_CPU MIPS_R4Kc + +#if (MIPS_CPU == MIPS_R4Kc) +/* 32 bits target */ +#define TARGET_LONG_BITS 32 +/* real pages are variable size... */ +#define TARGET_PAGE_BITS 12 +/* Uses MIPS R4Kx ehancements to MIPS32 architecture */ +#define MIPS_USES_R4K_EXT +/* Uses MIPS R4Kc TLB model */ +#define MIPS_USES_R4K_TLB +#define MIPS_TLB_NB 16 +/* Have config1, runs in big-endian mode, uses TLB */ +#define MIPS_CONFIG0 \ +((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \ + (1 << CP0C0_BE) | (0x001 << CP0C0_MT) | (0x010 << CP0C0_K0)) +/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache, + * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, + * no performance counters, watch registers present, no code compression, + * EJTAG present, no FPU + */ +#define MIPS_CONFIG1 \ +((15 << CP0C1_MMU) | \ + (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \ + (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \ + (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \ + (1 << CP0C1_EP) | (0 << CP0C1_FP)) +#elif defined (MIPS_CPU == MIPS_R4Kp) +/* 32 bits target */ +#define TARGET_LONG_BITS 32 +/* real pages are variable size... */ +#define TARGET_PAGE_BITS 12 +/* Uses MIPS R4Kx ehancements to MIPS32 architecture */ +#define MIPS_USES_R4K_EXT +/* Uses MIPS R4Km FPM MMU model */ +#define MIPS_USES_R4K_FPM +#else +#error "MIPS CPU not defined" +/* Remainder for other flags */ +//#define TARGET_MIPS64 +//define MIPS_USES_FPU +#endif + +#endif /* !defined (__QEMU_MIPS_DEFS_H__) */ diff --git a/target-mips/op.c b/target-mips/op.c new file mode 100644 index 000000000..6d94be631 --- /dev/null +++ b/target-mips/op.c @@ -0,0 +1,641 @@ +/* + * MIPS emulation micro-operations for qemu. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * 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" + +#define REG 1 +#include "op_template.c" +#undef REG +#define REG 2 +#include "op_template.c" +#undef REG +#define REG 3 +#include "op_template.c" +#undef REG +#define REG 4 +#include "op_template.c" +#undef REG +#define REG 5 +#include "op_template.c" +#undef REG +#define REG 6 +#include "op_template.c" +#undef REG +#define REG 7 +#include "op_template.c" +#undef REG +#define REG 8 +#include "op_template.c" +#undef REG +#define REG 9 +#include "op_template.c" +#undef REG +#define REG 10 +#include "op_template.c" +#undef REG +#define REG 11 +#include "op_template.c" +#undef REG +#define REG 12 +#include "op_template.c" +#undef REG +#define REG 13 +#include "op_template.c" +#undef REG +#define REG 14 +#include "op_template.c" +#undef REG +#define REG 15 +#include "op_template.c" +#undef REG +#define REG 16 +#include "op_template.c" +#undef REG +#define REG 17 +#include "op_template.c" +#undef REG +#define REG 18 +#include "op_template.c" +#undef REG +#define REG 19 +#include "op_template.c" +#undef REG +#define REG 20 +#include "op_template.c" +#undef REG +#define REG 21 +#include "op_template.c" +#undef REG +#define REG 22 +#include "op_template.c" +#undef REG +#define REG 23 +#include "op_template.c" +#undef REG +#define REG 24 +#include "op_template.c" +#undef REG +#define REG 25 +#include "op_template.c" +#undef REG +#define REG 26 +#include "op_template.c" +#undef REG +#define REG 27 +#include "op_template.c" +#undef REG +#define REG 28 +#include "op_template.c" +#undef REG +#define REG 29 +#include "op_template.c" +#undef REG +#define REG 30 +#include "op_template.c" +#undef REG +#define REG 31 +#include "op_template.c" +#undef REG + +#define TN T0 +#include "op_template.c" +#undef TN +#define TN T1 +#include "op_template.c" +#undef TN +#define TN T2 +#include "op_template.c" +#undef TN + +void op_dup_T0 (void) +{ + T2 = T0; + RETURN(); +} + +void op_load_HI (void) +{ + T0 = env->HI; + RETURN(); +} + +void op_store_HI (void) +{ + env->HI = T0; + RETURN(); +} + +void op_load_LO (void) +{ + T0 = env->LO; + RETURN(); +} + +void op_store_LO (void) +{ + env->LO = T0; + RETURN(); +} + +/* Load and store */ +#define MEMSUFFIX _raw +#include "op_mem.c" +#undef MEMSUFFIX +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_mem.c" +#undef MEMSUFFIX + +#define MEMSUFFIX _kernel +#include "op_mem.c" +#undef MEMSUFFIX +#endif + +/* Arithmetic */ +void op_add (void) +{ + T0 += T1; + RETURN(); +} + +void op_addo (void) +{ + target_ulong tmp; + + tmp = T0; + T0 += T1; + if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) { + CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); + } + RETURN(); +} + +void op_sub (void) +{ + T0 -= T1; + RETURN(); +} + +void op_subo (void) +{ + target_ulong tmp; + + tmp = T0; + T0 = (int32_t)T0 - (int32_t)T1; + if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) { + CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); + } + RETURN(); +} + +void op_mul (void) +{ + T0 = (int32_t)T0 * (int32_t)T1; + RETURN(); +} + +void op_div (void) +{ + if (T1 != 0) { + env->LO = (int32_t)T0 / (int32_t)T1; + env->HI = (int32_t)T0 % (int32_t)T1; + } + RETURN(); +} + +void op_divu (void) +{ + if (T1 != 0) { + env->LO = T0 / T1; + env->HI = T0 % T1; + } + RETURN(); +} + +/* Logical */ +void op_and (void) +{ + T0 &= T1; + RETURN(); +} + +void op_nor (void) +{ + T0 = ~(T0 | T1); + RETURN(); +} + +void op_or (void) +{ + T0 |= T1; + RETURN(); +} + +void op_xor (void) +{ + T0 ^= T1; + RETURN(); +} + +void op_sll (void) +{ + T0 = T0 << T1; + RETURN(); +} + +void op_sra (void) +{ + T0 = (int32_t)T0 >> T1; + RETURN(); +} + +void op_srl (void) +{ + T0 = T0 >> T1; + RETURN(); +} + +void op_sllv (void) +{ + T0 = T1 << (T0 & 0x1F); + RETURN(); +} + +void op_srav (void) +{ + T0 = (int32_t)T1 >> (T0 & 0x1F); + RETURN(); +} + +void op_srlv (void) +{ + T0 = T1 >> (T0 & 0x1F); + RETURN(); +} + +void op_clo (void) +{ + int n; + + if (T0 == (target_ulong)-1) { + T0 = 32; + } else { + for (n = 0; n < 32; n++) { + if (!(T0 & (1 << 31))) + break; + T0 = T0 << 1; + } + T0 = n; + } + RETURN(); +} + +void op_clz (void) +{ + int n; + + if (T0 == 0) { + T0 = 32; + } else { + for (n = 0; n < 32; n++) { + if (T0 & (1 << 31)) + break; + T0 = T0 << 1; + } + T0 = n; + } + RETURN(); +} + +/* 64 bits arithmetic */ +#if (HOST_LONG_BITS == 64) +static inline uint64_t get_HILO (void) +{ + return ((uint64_t)env->HI << 32) | (uint64_t)env->LO; +} + +static inline void set_HILO (uint64_t HILO) +{ + env->LO = HILO & 0xFFFFFFFF; + env->HI = HILO >> 32; +} + +void op_mult (void) +{ + set_HILO((int64_t)T0 * (int64_t)T1); + RETURN(); +} + +void op_multu (void) +{ + set_HILO((uint64_t)T0 * (uint64_t)T1); + RETURN(); +} + +void op_madd (void) +{ + int64_t tmp; + + tmp = ((int64_t)T0 * (int64_t)T1); + set_HILO((int64_t)get_HILO() + tmp); + RETURN(); +} + +void op_maddu (void) +{ + uint64_t tmp; + + tmp = ((uint64_t)T0 * (uint64_t)T1); + set_HILO(get_HILO() + tmp); + RETURN(); +} + +void op_msub (void) +{ + int64_t tmp; + + tmp = ((int64_t)T0 * (int64_t)T1); + set_HILO((int64_t)get_HILO() - tmp); + RETURN(); +} + +void op_msubu (void) +{ + uint64_t tmp; + + tmp = ((uint64_t)T0 * (uint64_t)T1); + set_HILO(get_HILO() - tmp); + RETURN(); +} +#else +void op_mult (void) +{ + CALL_FROM_TB0(do_mult); + RETURN(); +} + +void op_multu (void) +{ + CALL_FROM_TB0(do_multu); + RETURN(); +} + +void op_madd (void) +{ + CALL_FROM_TB0(do_madd); + RETURN(); +} + +void op_maddu (void) +{ + CALL_FROM_TB0(do_maddu); + RETURN(); +} + +void op_msub (void) +{ + CALL_FROM_TB0(do_msub); + RETURN(); +} + +void op_msubu (void) +{ + CALL_FROM_TB0(do_msubu); + RETURN(); +} +#endif + +/* Conditional moves */ +void op_movn (void) +{ + if (T1 != 0) + env->gpr[PARAM1] = T0; + RETURN(); +} + +void op_movz (void) +{ + if (T1 == 0) + env->gpr[PARAM1] = T0; + RETURN(); +} + +/* Tests */ +#define OP_COND(name, cond) \ +void glue(op_, name) (void) \ +{ \ + if (cond) { \ + T0 = 1; \ + } else { \ + T0 = 0; \ + } \ + RETURN(); \ +} + +OP_COND(eq, T0 == T1); +OP_COND(ne, T0 != T1); +OP_COND(ge, (int32_t)T0 >= (int32_t)T1); +OP_COND(geu, T0 >= T1); +OP_COND(lt, (int32_t)T0 < (int32_t)T1); +OP_COND(ltu, T0 < T1); +OP_COND(gez, (int32_t)T0 >= 0); +OP_COND(gtz, (int32_t)T0 > 0); +OP_COND(lez, (int32_t)T0 <= 0); +OP_COND(ltz, (int32_t)T0 < 0); + +/* Branchs */ +//#undef USE_DIRECT_JUMP +#define EIP env->PC + +/* Branch to register */ +void op_save_breg_target (void) +{ + env->btarget = T2; +} + +void op_restore_breg_target (void) +{ + T2 = env->btarget; +} + +void op_breg (void) +{ + env->PC = T2; + RETURN(); +} + +/* Unconditional branch */ +void op_branch (void) +{ + JUMP_TB(branch, PARAM1, 0, PARAM2); + RETURN(); +} + +void op_save_btarget (void) +{ + env->btarget = PARAM1; + RETURN(); +} + +/* Conditional branch */ +void op_set_bcond (void) +{ + T2 = T0; + RETURN(); +} + +void op_save_bcond (void) +{ + env->bcond = T2; + RETURN(); +} + +void op_restore_bcond (void) +{ + T2 = env->bcond; + RETURN(); +} + +void op_bcond (void) +{ + if (T2) { + JUMP_TB(bcond, PARAM1, 0, PARAM2); + } else { + JUMP_TB(bcond, PARAM1, 1, PARAM3); + } + RETURN(); +} + +/* Likely branch (used to skip the delay slot) */ +void op_blikely (void) +{ + /* If the test is false, skip the delay slot */ + if (T2 == 0) { + env->hflags = PARAM3; + JUMP_TB(blikely, PARAM1, 1, PARAM2); + } + RETURN(); +} + +/* CP0 functions */ +void op_mfc0 (void) +{ + CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2); + RETURN(); +} + +void op_mtc0 (void) +{ + CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2); + RETURN(); +} + +#if defined(MIPS_USES_R4K_TLB) +void op_tlbwi (void) +{ + CALL_FROM_TB0(do_tlbwi); + RETURN(); +} + +void op_tlbwr (void) +{ + CALL_FROM_TB0(do_tlbwr); + RETURN(); +} + +void op_tlbp (void) +{ + CALL_FROM_TB0(do_tlbp); + RETURN(); +} + +void op_tlbr (void) +{ + CALL_FROM_TB0(do_tlbr); + RETURN(); +} +#endif + +/* Specials */ +void op_pmon (void) +{ + CALL_FROM_TB1(do_pmon, PARAM1); +} + +void op_trap (void) +{ + if (T0) { + CALL_FROM_TB1(do_raise_exception, EXCP_TRAP); + } + RETURN(); +} + +void op_set_lladdr (void) +{ + env->CP0_LLAddr = T2; +} + +void debug_eret (void); +void op_eret (void) +{ + CALL_FROM_TB0(debug_eret); + if (env->hflags & MIPS_HFLAG_ERL) + env->PC = env->CP0_ErrorEPC; + else + env->PC = env->CP0_EPC; + env->CP0_LLAddr = 1; +} + +void op_deret (void) +{ + CALL_FROM_TB0(debug_eret); + env->PC = env->CP0_DEPC; +} + +void op_save_state (void) +{ + env->hflags = PARAM1; + RETURN(); +} + +void op_save_pc (void) +{ + env->PC = PARAM1; + RETURN(); +} + +void op_raise_exception (void) +{ + CALL_FROM_TB1(do_raise_exception, PARAM1); + RETURN(); +} + +void op_raise_exception_err (void) +{ + CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2); + RETURN(); +} + +void op_exit_tb (void) +{ + EXIT_TB(); +} + diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c new file mode 100644 index 000000000..dc1040786 --- /dev/null +++ b/target-mips/op_helper.c @@ -0,0 +1,634 @@ +/* + * MIPS emulation helpers for qemu. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * 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 +#include "exec.h" + +#define MIPS_DEBUG_DISAS + +/*****************************************************************************/ +/* Exceptions processing helpers */ +void cpu_loop_exit(void) +{ + longjmp(env->jmp_env, 1); +} + +__attribute__ (( regparm(2) )) +void do_raise_exception_err (uint32_t exception, int error_code) +{ +#if 1 + if (logfile && exception < 0x100) + fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code); +#endif + env->exception_index = exception; + env->error_code = error_code; + T0 = 0; + cpu_loop_exit(); +} + +__attribute__ (( regparm(1) )) +void do_raise_exception (uint32_t exception) +{ + do_raise_exception_err(exception, 0); +} + +#define MEMSUFFIX _raw +#include "op_helper_mem.c" +#undef MEMSUFFIX +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_helper_mem.c" +#undef MEMSUFFIX +#define MEMSUFFIX _kernel +#include "op_helper_mem.c" +#undef MEMSUFFIX +#endif + +/* 64 bits arithmetic for 32 bits hosts */ +#if (HOST_LONG_BITS == 32) +static inline uint64_t get_HILO (void) +{ + return ((uint64_t)env->HI << 32) | (uint64_t)env->LO; +} + +static inline void set_HILO (uint64_t HILO) +{ + env->LO = HILO & 0xFFFFFFFF; + env->HI = HILO >> 32; +} + +void do_mult (void) +{ + set_HILO((int64_t)T0 * (int64_t)T1); +} + +void do_multu (void) +{ + set_HILO((uint64_t)T0 * (uint64_t)T1); +} + +void do_madd (void) +{ + int64_t tmp; + + tmp = ((int64_t)T0 * (int64_t)T1); + set_HILO((int64_t)get_HILO() + tmp); +} + +void do_maddu (void) +{ + uint64_t tmp; + + tmp = ((uint64_t)T0 * (uint64_t)T1); + set_HILO(get_HILO() + tmp); +} + +void do_msub (void) +{ + int64_t tmp; + + tmp = ((int64_t)T0 * (int64_t)T1); + set_HILO((int64_t)get_HILO() - tmp); +} + +void do_msubu (void) +{ + uint64_t tmp; + + tmp = ((uint64_t)T0 * (uint64_t)T1); + set_HILO(get_HILO() - tmp); +} +#endif + +/* CP0 helpers */ +__attribute__ (( regparm(2) )) +void do_mfc0 (int reg, int sel) +{ + const unsigned char *rn; + + if (sel != 0 && reg != 16 && reg != 28) { + rn = "invalid"; + goto print; + } + switch (reg) { + case 0: + T0 = env->CP0_index; + rn = "Index"; + break; + case 1: + T0 = cpu_mips_get_random(env); + rn = "Random"; + break; + case 2: + T0 = env->CP0_EntryLo0; + rn = "EntryLo0"; + break; + case 3: + T0 = env->CP0_EntryLo1; + rn = "EntryLo1"; + break; + case 4: + T0 = env->CP0_Context; + rn = "Context"; + break; + case 5: + T0 = env->CP0_PageMask; + rn = "PageMask"; + break; + case 6: + T0 = env->CP0_Wired; + rn = "Wired"; + break; + case 8: + T0 = env->CP0_BadVAddr; + rn = "BadVaddr"; + break; + case 9: + T0 = cpu_mips_get_count(env); + rn = "Count"; + break; + case 10: + T0 = env->CP0_EntryHi; + rn = "EntryHi"; + break; + case 11: + T0 = env->CP0_Compare; + rn = "Compare"; + break; + case 12: + T0 = env->CP0_Status; + if (env->hflags & MIPS_HFLAG_UM) + T0 |= CP0St_UM; + if (env->hflags & MIPS_HFLAG_ERL) + T0 |= CP0St_ERL; + if (env->hflags & MIPS_HFLAG_EXL) + T0 |= CP0St_EXL; + rn = "Status"; + break; + case 13: + T0 = env->CP0_Cause; + rn = "Cause"; + break; + case 14: + T0 = env->CP0_EPC; + rn = "EPC"; + break; + case 15: + T0 = env->CP0_PRid; + rn = "PRid"; + break; + case 16: + switch (sel) { + case 0: + T0 = env->CP0_Config0; + rn = "Config"; + break; + case 1: + T0 = env->CP0_Config1; + rn = "Config1"; + break; + default: + rn = "Unknown config register"; + break; + } + break; + case 17: + T0 = env->CP0_LLAddr >> 4; + rn = "LLAddr"; + break; + case 18: + T0 = env->CP0_WatchLo; + rn = "WatchLo"; + break; + case 19: + T0 = env->CP0_WatchHi; + rn = "WatchHi"; + break; + case 23: + T0 = env->CP0_Debug; + if (env->hflags & MIPS_HFLAG_DM) + T0 |= 1 << CP0DB_DM; + rn = "Debug"; + break; + case 24: + T0 = env->CP0_DEPC; + rn = "DEPC"; + break; + case 28: + switch (sel) { + case 0: + T0 = env->CP0_TagLo; + rn = "TagLo"; + break; + case 1: + T0 = env->CP0_DataLo; + rn = "DataLo"; + break; + default: + rn = "unknown sel"; + break; + } + break; + case 30: + T0 = env->CP0_ErrorEPC; + rn = "ErrorEPC"; + break; + case 31: + T0 = env->CP0_DESAVE; + rn = "DESAVE"; + break; + default: + rn = "unknown"; + break; + } + print: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n", + env->PC, rn, T0, reg, sel); + } +#endif + return; +} + +__attribute__ (( regparm(2) )) +void do_mtc0 (int reg, int sel) +{ + const unsigned char *rn; + uint32_t val, old, mask; + int i, raise; + + if (sel != 0 && reg != 16 && reg != 28) { + val = -1; + old = -1; + rn = "invalid"; + goto print; + } + switch (reg) { + case 0: + val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F); + old = env->CP0_index; + env->CP0_index = val; + rn = "Index"; + break; + case 2: + val = T0 & 0x03FFFFFFF; + old = env->CP0_EntryLo0; + env->CP0_EntryLo0 = val; + rn = "EntryLo0"; + break; + case 3: + val = T0 & 0x03FFFFFFF; + old = env->CP0_EntryLo1; + env->CP0_EntryLo1 = val; + rn = "EntryLo1"; + break; + case 4: + val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0); + old = env->CP0_Context; + env->CP0_Context = val; + rn = "Context"; + break; + case 5: + val = T0 & 0x01FFE000; + old = env->CP0_PageMask; + env->CP0_PageMask = val; + rn = "PageMask"; + break; + case 6: + val = T0 & 0x0000000F; + old = env->CP0_Wired; + env->CP0_Wired = val; + rn = "Wired"; + break; + case 9: + val = T0; + old = cpu_mips_get_count(env); + cpu_mips_store_count(env, val); + rn = "Count"; + break; + case 10: + val = T0 & 0xFFFFF0FF; + old = env->CP0_EntryHi; + env->CP0_EntryHi = val; + rn = "EntryHi"; + break; + case 11: + val = T0; + old = env->CP0_Compare; + cpu_mips_store_compare(env, val); + rn = "Compare"; + break; + case 12: + val = T0 & 0xFA78FF01; + if (T0 & (1 << CP0St_UM)) + env->hflags |= MIPS_HFLAG_UM; + else + env->hflags &= ~MIPS_HFLAG_UM; + if (T0 & (1 << CP0St_ERL)) + env->hflags |= MIPS_HFLAG_ERL; + else + env->hflags &= ~MIPS_HFLAG_ERL; + if (T0 & (1 << CP0St_EXL)) + env->hflags |= MIPS_HFLAG_EXL; + else + env->hflags &= ~MIPS_HFLAG_EXL; + old = env->CP0_Status; + env->CP0_Status = val; + /* If we unmasked an asserted IRQ, raise it */ + mask = 0x0000FC00; + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n", + old, val, env->CP0_Cause, old & mask, val & mask, + env->CP0_Cause & mask); + } +#if 1 + if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) && + !(env->hflags & MIPS_HFLAG_EXL) && + !(env->hflags & MIPS_HFLAG_ERL) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Cause & mask)) { + if (logfile) + fprintf(logfile, "Raise pending IRQs\n"); + env->interrupt_request |= CPU_INTERRUPT_HARD; + do_raise_exception(EXCP_EXT_INTERRUPT); + } else if (!(val & 0x00000001) && (old & 0x00000001)) { + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + } +#endif + rn = "Status"; + break; + case 13: + val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300); + old = env->CP0_Cause; + env->CP0_Cause = val; +#if 0 + /* Check if we ever asserted a software IRQ */ + for (i = 0; i < 2; i++) { + mask = 0x100 << i; + if ((val & mask) & !(old & mask)) + mips_set_irq(i); + } +#endif + rn = "Cause"; + break; + case 14: + val = T0; + old = env->CP0_EPC; + env->CP0_EPC = val; + rn = "EPC"; + break; + case 16: + switch (sel) { + case 0: +#if defined(MIPS_USES_R4K_TLB) + val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001); +#else + val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001); +#endif + old = env->CP0_Config0; + env->CP0_Config0 = val; + rn = "Config0"; + break; + default: + val = -1; + old = -1; + rn = "bad config selector"; + break; + } + break; + case 18: + val = T0; + old = env->CP0_WatchLo; + env->CP0_WatchLo = val; + rn = "WatchLo"; + break; + case 19: + val = T0 & 0x40FF0FF8; + old = env->CP0_WatchHi; + env->CP0_WatchHi = val; + rn = "WatchHi"; + break; + case 23: + val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120); + if (T0 & (1 << CP0DB_DM)) + env->hflags |= MIPS_HFLAG_DM; + else + env->hflags &= ~MIPS_HFLAG_DM; + old = env->CP0_Debug; + env->CP0_Debug = val; + rn = "Debug"; + break; + case 24: + val = T0; + old = env->CP0_DEPC; + env->CP0_DEPC = val; + rn = "DEPC"; + break; + case 28: + switch (sel) { + case 0: + val = T0 & 0xFFFFFCF6; + old = env->CP0_TagLo; + env->CP0_TagLo = val; + rn = "TagLo"; + break; + default: + val = -1; + old = -1; + rn = "invalid sel"; + break; + } + break; + case 30: + val = T0; + old = env->CP0_ErrorEPC; + env->CP0_ErrorEPC = val; + rn = "EPC"; + break; + case 31: + val = T0; + old = env->CP0_DESAVE; + env->CP0_DESAVE = val; + rn = "DESAVE"; + break; + default: + val = -1; + old = -1; + rn = "unknown"; + break; + } + print: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n", + env->PC, rn, T0, val, reg, sel, old); + } +#endif + return; +} + +/* TLB management */ +#if defined(MIPS_USES_R4K_TLB) +__attribute__ (( regparm(1) )) +static void invalidate_tb (int idx) +{ + tlb_t *tlb; + target_ulong addr, end; + + tlb = &env->tlb[idx]; + if (tlb->V[0]) { + addr = tlb->PFN[0]; + end = addr + (tlb->end - tlb->VPN); + tb_invalidate_page_range(addr, end); + } + if (tlb->V[1]) { + addr = tlb->PFN[1]; + end = addr + (tlb->end - tlb->VPN); + tb_invalidate_page_range(addr, end); + } +} + +__attribute__ (( regparm(1) )) +static void fill_tb (int idx) +{ + tlb_t *tlb; + int size; + + /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ + tlb = &env->tlb[idx]; + tlb->VPN = env->CP0_EntryHi & 0xFFFFE000; + tlb->ASID = env->CP0_EntryHi & 0x000000FF; + size = env->CP0_PageMask >> 13; + size = 4 * (size + 1); + tlb->end = tlb->VPN + (1 << (8 + size)); + tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; + tlb->V[0] = env->CP0_EntryLo0 & 2; + tlb->D[0] = env->CP0_EntryLo0 & 4; + tlb->C[0] = (env->CP0_EntryLo0 >> 3) & 0x7; + tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12; + tlb->V[1] = env->CP0_EntryLo1 & 2; + tlb->D[1] = env->CP0_EntryLo1 & 4; + tlb->C[1] = (env->CP0_EntryLo1 >> 3) & 0x7; + tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; +} + +void do_tlbwi (void) +{ + invalidate_tb(env->CP0_index & 0xF); + fill_tb(env->CP0_index & 0xF); +} + +void do_tlbwr (void) +{ + int r = cpu_mips_get_random(env); + + invalidate_tb(r); + fill_tb(r); +} + +void do_tlbp (void) +{ + tlb_t *tlb; + target_ulong tag; + uint8_t ASID; + int i; + + tag = (env->CP0_EntryHi & 0xFFFFE000); + ASID = env->CP0_EntryHi & 0x000000FF; + for (i = 0; i < 16; i++) { + tlb = &env->tlb[i]; + /* Check ASID, virtual page number & size */ + if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { + /* TLB match */ + env->CP0_index = i; + break; + } + } + if (i == 16) { + env->CP0_index |= 0x80000000; + } +} + +void do_tlbr (void) +{ + tlb_t *tlb; + int size; + + tlb = &env->tlb[env->CP0_index & 0xF]; + env->CP0_EntryHi = tlb->VPN | tlb->ASID; + size = (tlb->end - tlb->VPN) >> 12; + env->CP0_PageMask = (size - 1) << 13; + env->CP0_EntryLo0 = tlb->V[0] | tlb->D[0] | (tlb->C[0] << 3) | + (tlb->PFN[0] >> 6); + env->CP0_EntryLo1 = tlb->V[1] | tlb->D[1] | (tlb->C[1] << 3) | + (tlb->PFN[1] >> 6); +} +#endif + +__attribute__ (( regparm(1) )) +void op_dump_ldst (const unsigned char *func) +{ + if (loglevel) + fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1); +} + +void dump_sc (void) +{ + if (loglevel) { + fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__, + T1, T0, env->CP0_LLAddr); + } +} + +void debug_eret (void) +{ + if (loglevel) { + fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n", + env->PC, env->CP0_EPC, env->CP0_ErrorEPC, + env->hflags & MIPS_HFLAG_ERL ? 1 : 0); + } +} + +__attribute__ (( regparm(1) )) +void do_pmon (int function) +{ + function /= 2; + switch (function) { + case 2: /* TODO: char inbyte(int waitflag); */ + if (env->gpr[4] == 0) + env->gpr[2] = -1; + /* Fall through */ + case 11: /* TODO: char inbyte (void); */ + env->gpr[2] = -1; + break; + case 3: + case 12: + printf("%c", env->gpr[4] & 0xFF); + break; + case 17: + break; + case 158: + { + unsigned char *fmt = (void *)env->gpr[4]; + printf("%s", fmt); + } + break; + } +} diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c new file mode 100644 index 000000000..69793b0b9 --- /dev/null +++ b/target-mips/op_helper_mem.c @@ -0,0 +1,143 @@ +void glue(do_lwl, MEMSUFFIX) (void) +{ +#if defined (DEBUG_OP) + target_ulong sav = T0; +#endif + uint32_t tmp; + + tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + /* XXX: this is valid only in big-endian mode + * should be reverted for little-endian... + */ + switch (T0 & 3) { + case 0: + T0 = tmp; + break; + case 1: + T0 = (tmp << 8) | (T1 & 0x000000FF); + break; + case 2: + T0 = (tmp << 16) | (T1 & 0x0000FFFF); + break; + case 3: + T0 = (tmp << 24) | (T1 & 0x00FFFFFF); + break; + } +#if defined (DEBUG_OP) + if (logfile) { + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + __func__, sav, tmp, T1, T0); + } +#endif + RETURN(); +} + +void glue(do_lwr, MEMSUFFIX) (void) +{ +#if defined (DEBUG_OP) + target_ulong sav = T0; +#endif + uint32_t tmp; + + tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + /* XXX: this is valid only in big-endian mode + * should be reverted for little-endian... + */ + switch (T0 & 3) { + case 0: + T0 = (tmp >> 24) | (T1 & 0xFFFFFF00); + break; + case 1: + T0 = (tmp >> 16) | (T1 & 0xFFFF0000); + break; + case 2: + T0 = (tmp >> 8) | (T1 & 0xFF000000); + break; + case 3: + T0 = tmp; + break; + } +#if defined (DEBUG_OP) + if (logfile) { + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + __func__, sav, tmp, T1, T0); + } +#endif + RETURN(); +} + +void glue(do_swl, MEMSUFFIX) (void) +{ +#if defined (DEBUG_OP) + target_ulong sav; +#endif + uint32_t tmp; + + tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); +#if defined (DEBUG_OP) + sav = tmp; +#endif + /* XXX: this is valid only in big-endian mode + * should be reverted for little-endian... + */ + switch (T0 & 3) { + case 0: + tmp = T1; + break; + case 1: + tmp = (tmp & 0xFF000000) | (T1 >> 8); + break; + case 2: + tmp = (tmp & 0xFFFF0000) | (T1 >> 16); + break; + case 3: + tmp = (tmp & 0xFFFFFF00) | (T1 >> 24); + break; + } + glue(stl, MEMSUFFIX)(T0 & ~3, tmp); +#if defined (DEBUG_OP) + if (logfile) { + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + __func__, T0, sav, T1, tmp); + } +#endif + RETURN(); +} + +void glue(do_swr, MEMSUFFIX) (void) +{ +#if defined (DEBUG_OP) + target_ulong sav; +#endif + uint32_t tmp; + + tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); +#if defined (DEBUG_OP) + sav = tmp; +#endif + /* XXX: this is valid only in big-endian mode + * should be reverted for little-endian... + */ + switch (T0 & 3) { + case 0: + tmp = (tmp & 0x00FFFFFF) | (T1 << 24); + break; + case 1: + tmp = (tmp & 0x0000FFFF) | (T1 << 16); + break; + case 2: + tmp = (tmp & 0x000000FF) | (T1 << 8); + break; + case 3: + tmp = T1; + break; + } + glue(stl, MEMSUFFIX)(T0 & ~3, tmp); +#if defined (DEBUG_OP) + if (logfile) { + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + __func__, T0, sav, T1, tmp); + } +#endif + RETURN(); +} diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c new file mode 100644 index 000000000..bbb322db4 --- /dev/null +++ b/target-mips/op_mem.c @@ -0,0 +1,113 @@ +/* + * MIPS emulation memory micro-operations for qemu. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * 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 + */ + +/* Standard loads and stores */ +void glue(op_lb, MEMSUFFIX) (void) +{ + T0 = glue(ldsb, MEMSUFFIX)(T0); + RETURN(); +} + +void glue(op_lbu, MEMSUFFIX) (void) +{ + T0 = glue(ldub, MEMSUFFIX)(T0); + RETURN(); +} + +void glue(op_sb, MEMSUFFIX) (void) +{ + glue(stb, MEMSUFFIX)(T0, T1); + RETURN(); +} + +void glue(op_lh, MEMSUFFIX) (void) +{ + T0 = glue(ldsw, MEMSUFFIX)(T0); + RETURN(); +} + +void glue(op_lhu, MEMSUFFIX) (void) +{ + T0 = glue(lduw, MEMSUFFIX)(T0); + RETURN(); +} + +void glue(op_sh, MEMSUFFIX) (void) +{ + glue(stw, MEMSUFFIX)(T0, T1); + RETURN(); +} + +void glue(op_lw, MEMSUFFIX) (void) +{ + T0 = glue(ldl, MEMSUFFIX)(T0); + RETURN(); +} + +void glue(op_sw, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)(T0, T1); + RETURN(); +} + +/* "half" load and stores */ +void glue(op_lwl, MEMSUFFIX) (void) +{ + CALL_FROM_TB0(glue(do_lwl, MEMSUFFIX)); + RETURN(); +} + +void glue(op_lwr, MEMSUFFIX) (void) +{ + CALL_FROM_TB0(glue(do_lwr, MEMSUFFIX)); + RETURN(); +} + +void glue(op_swl, MEMSUFFIX) (void) +{ + CALL_FROM_TB0(glue(do_swl, MEMSUFFIX)); + RETURN(); +} + +void glue(op_swr, MEMSUFFIX) (void) +{ + CALL_FROM_TB0(glue(do_swr, MEMSUFFIX)); + RETURN(); +} + +void glue(op_ll, MEMSUFFIX) (void) +{ + T1 = T0; + T0 = glue(ldl, MEMSUFFIX)(T0); + env->CP0_LLAddr = T1; + RETURN(); +} + +void glue(op_sc, MEMSUFFIX) (void) +{ + CALL_FROM_TB0(dump_sc); + if (T0 == env->CP0_LLAddr) { + glue(stl, MEMSUFFIX)(T0, T1); + T0 = 1; + } else { + T0 = 0; + } + RETURN(); +} diff --git a/target-mips/op_template.c b/target-mips/op_template.c new file mode 100644 index 000000000..9314c95e2 --- /dev/null +++ b/target-mips/op_template.c @@ -0,0 +1,65 @@ +/* + * MIPS emulation micro-operations templates for reg load & store for qemu. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * 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(REG) +void glue(op_load_gpr_T0_gpr, REG) (void) +{ + T0 = env->gpr[REG]; + RETURN(); +} + +void glue(op_store_T0_gpr_gpr, REG) (void) +{ + env->gpr[REG] = T0; + RETURN(); +} + +void glue(op_load_gpr_T1_gpr, REG) (void) +{ + T1 = env->gpr[REG]; + RETURN(); +} + +void glue(op_store_T1_gpr_gpr, REG) (void) +{ + env->gpr[REG] = T1; + RETURN(); +} + +void glue(op_load_gpr_T2_gpr, REG) (void) +{ + T2 = env->gpr[REG]; + RETURN(); +} +#endif + +#if defined (TN) +void glue(op_set_, TN) (void) +{ + TN = PARAM1; + RETURN(); +} + +void glue (op_reset_, TN) (void) +{ + TN = 0; + RETURN(); +} +#endif diff --git a/target-mips/translate.c b/target-mips/translate.c new file mode 100644 index 000000000..87e123ade --- /dev/null +++ b/target-mips/translate.c @@ -0,0 +1,1505 @@ +/* + * MIPS32 emulation for qemu: main translation routines. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * 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 +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +#define MIPS_DEBUG_DISAS +//#define MIPS_SINGLE_STEP + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; + +#include "gen-op.h" + +const unsigned char *regnames[] = + { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; + +/* Warning: no function for r0 register (hard wired to zero) */ +#define GEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = { \ +NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} + +/* General purpose registers moves */ +GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); +GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr); +GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); + +GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); +GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); + +typedef struct DisasContext { + struct TranslationBlock *tb; + target_ulong pc, saved_pc; + uint32_t opcode; + /* Routine used to access memory */ + int mem_idx; + uint32_t hflags, saved_hflags; + uint32_t CP0_Status; + int bstate; + target_ulong btarget; +} DisasContext; + +enum { + BS_NONE = 0, /* We go out of the TB without reaching a branch or an + * exception condition + */ + BS_STOP = 1, /* We want to stop translation for any reason */ + BS_BRANCH = 2, /* We reached a branch condition */ + BS_EXCP = 3, /* We reached an exception condition */ +}; + +#if defined MIPS_DEBUG_DISAS +#define MIPS_DEBUG(fmt, args...) \ +do { \ + if (loglevel & CPU_LOG_TB_IN_ASM) { \ + fprintf(logfile, "%08x: %08x " fmt "\n", \ + ctx->pc, ctx->opcode , ##args); \ + } \ +} while (0) +#else +#define MIPS_DEBUG(fmt, args...) do { } while(0) +#endif + +#define MIPS_INVAL(op) \ +do { \ + MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \ + ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \ +} while (0) + +#define GEN_LOAD_REG_TN(Tn, Rn) \ +do { \ + if (Rn == 0) { \ + glue(gen_op_reset_, Tn)(); \ + } else { \ + glue(gen_op_load_gpr_, Tn)(Rn); \ + } \ +} while (0) + +#define GEN_LOAD_IMM_TN(Tn, Imm) \ +do { \ + if (Imm == 0) { \ + glue(gen_op_reset_, Tn)(); \ + } else { \ + glue(gen_op_set_, Tn)(Imm); \ + } \ +} while (0) + +#define GEN_STORE_TN_REG(Rn, Tn) \ +do { \ + if (Rn != 0) { \ + glue(glue(gen_op_store_, Tn),_gpr)(Rn); \ + } \ +} while (0) + +static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) +{ +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "hflags %08x saved %08x\n", + ctx->hflags, ctx->saved_hflags); + } +#endif + if (do_save_pc && ctx->pc != ctx->saved_pc) { + gen_op_save_pc(ctx->pc); + ctx->saved_pc = ctx->pc; + } + if (ctx->hflags != ctx->saved_hflags) { + gen_op_save_state(ctx->hflags); + ctx->saved_hflags = ctx->hflags; + if (ctx->hflags & MIPS_HFLAG_BR) { + gen_op_save_breg_target(); + } else if (ctx->hflags & MIPS_HFLAG_B) { + gen_op_save_btarget(ctx->btarget); + } else if (ctx->hflags & MIPS_HFLAG_BMASK) { + gen_op_save_bcond(); + gen_op_save_btarget(ctx->btarget); + } + } +} + +static inline void generate_exception (DisasContext *ctx, int excp) +{ +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "%s: raise exception %d\n", __func__, excp); +#endif + save_cpu_state(ctx, 1); + gen_op_raise_exception(excp); + ctx->bstate = BS_EXCP; +} + +#if defined(CONFIG_USER_ONLY) +#define op_ldst(name) gen_op_##name##_raw() +#define OP_LD_TABLE(width) +#define OP_ST_TABLE(width) +#else +#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_l##width[] = { \ + &gen_op_l##width##_user, \ + &gen_op_l##width##_kernel, \ +} +#define OP_ST_TABLE(width) \ +static GenOpFunc *gen_op_s##width[] = { \ + &gen_op_s##width##_user, \ + &gen_op_s##width##_kernel, \ +} +#endif + +#ifdef TARGET_MIPS64 +OP_LD_TABLE(d); +OP_LD_TABLE(dl); +OP_LD_TABLE(dr); +OP_ST_TABLE(d); +OP_ST_TABLE(dl); +OP_ST_TABLE(dr); +#endif +OP_LD_TABLE(w); +OP_LD_TABLE(wl); +OP_LD_TABLE(wr); +OP_ST_TABLE(w); +OP_ST_TABLE(wl); +OP_ST_TABLE(wr); +OP_LD_TABLE(h); +OP_LD_TABLE(hu); +OP_ST_TABLE(h); +OP_LD_TABLE(b); +OP_LD_TABLE(bu); +OP_ST_TABLE(b); +OP_LD_TABLE(l); +OP_ST_TABLE(c); + +/* Load and store */ +static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, + int base, int16_t offset) +{ + const unsigned char *opn = "unk"; + + if (base == 0) { + GEN_LOAD_IMM_TN(T0, offset); + } else if (offset == 0) { + gen_op_load_gpr_T0(base); + } else { + gen_op_load_gpr_T0(base); + gen_op_set_T1(offset); + gen_op_add(); + } + /* Don't do NOP if destination is zero: we must perform the actual + * memory access + */ + switch (opc) { +#if defined(TARGET_MIPS64) + case OPC_LD: +#if defined (MIPS_HAS_UNALIGNED_LS) + case OPC_ULD: +#endif + op_ldst(ld); + GEN_STORE_TN_REG(rt, T0); + opn = "ld"; + break; + case OPC_SD: +#if defined (MIPS_HAS_UNALIGNED_LS) + case OPC_USD: +#endif + GEN_LOAD_REG_TN(T1, rt); + op_ldst(sd); + opn = "sd"; + break; + case OPC_LDL: + op_ldst(ldl); + GEN_STORE_TN_REG(rt, T0); + opn = "ldl"; + break; + case OPC_SDL: + GEN_LOAD_REG_TN(T1, rt); + op_ldst(sdl); + opn = "sdl"; + break; + case OPC_LDR: + op_ldst(ldr); + GEN_STORE_TN_REG(rt, T0); + opn = "ldr"; + break; + case OPC_SDR: + GEN_LOAD_REG_TN(T1, rt); + op_ldst(sdr); + opn = "sdr"; + break; +#endif + case OPC_LW: +#if defined (MIPS_HAS_UNALIGNED_LS) + case OPC_ULW: +#endif + op_ldst(lw); + GEN_STORE_TN_REG(rt, T0); + opn = "lw"; + break; + case OPC_SW: +#if defined (MIPS_HAS_UNALIGNED_LS) + case OPC_USW: +#endif + GEN_LOAD_REG_TN(T1, rt); + op_ldst(sw); + opn = "sw"; + break; + case OPC_LH: +#if defined (MIPS_HAS_UNALIGNED_LS) + case OPC_ULH: +#endif + op_ldst(lh); + GEN_STORE_TN_REG(rt, T0); + opn = "lh"; + break; + case OPC_SH: +#if defined (MIPS_HAS_UNALIGNED_LS) + case OPC_USH: +#endif + GEN_LOAD_REG_TN(T1, rt); + op_ldst(sh); + opn = "sh"; + break; + case OPC_LHU: +#if defined (MIPS_HAS_UNALIGNED_LS) + case OPC_ULHU: +#endif + op_ldst(lhu); + GEN_STORE_TN_REG(rt, T0); + opn = "lhu"; + break; + case OPC_LB: + op_ldst(lb); + GEN_STORE_TN_REG(rt, T0); + opn = "lb"; + break; + case OPC_SB: + GEN_LOAD_REG_TN(T1, rt); + op_ldst(sb); + opn = "sb"; + break; + case OPC_LBU: + op_ldst(lbu); + GEN_STORE_TN_REG(rt, T0); + opn = "lbu"; + break; + case OPC_LWL: + op_ldst(lwl); + GEN_STORE_TN_REG(rt, T0); + opn = "lwl"; + break; + case OPC_SWL: + GEN_LOAD_REG_TN(T1, rt); + op_ldst(swl); + opn = "swr"; + break; + case OPC_LWR: + op_ldst(lwr); + GEN_STORE_TN_REG(rt, T0); + opn = "lwr"; + break; + case OPC_SWR: + GEN_LOAD_REG_TN(T1, rt); + op_ldst(swr); + opn = "swr"; + break; + case OPC_LL: + op_ldst(ll); + GEN_STORE_TN_REG(rt, T0); + opn = "ll"; + break; + case OPC_SC: + GEN_LOAD_REG_TN(T1, rt); + op_ldst(sc); + GEN_STORE_TN_REG(rt, T0); + opn = "sc"; + break; + default: + MIPS_INVAL("load/store"); + generate_exception(ctx, EXCP_RI); + return; + } + MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); +} + +/* Arithmetic with immediate operand */ +static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, + int rs, int16_t imm) +{ + uint32_t uimm; + const unsigned char *opn = "unk"; + + if (rt == 0 && opc != OPC_ADDI) { + /* if no destination, treat it as a NOP + * For addi, we must generate the overflow exception when needed. + */ + MIPS_DEBUG("NOP"); + return; + } + if (opc == OPC_ADDI || opc == OPC_ADDIU || + opc == OPC_SLTI || opc == OPC_SLTIU) + uimm = (int32_t)imm; /* Sign extent to 32 bits */ + else + uimm = (uint16_t)imm; + if (opc != OPC_LUI) { + GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_IMM_TN(T1, uimm); + } else { + uimm = uimm << 16; + GEN_LOAD_IMM_TN(T0, uimm); + } + switch (opc) { + case OPC_ADDI: + save_cpu_state(ctx, 1); + gen_op_addo(); + opn = "addi"; + break; + case OPC_ADDIU: + gen_op_add(); + opn = "addiu"; + break; + case OPC_SLTI: + gen_op_lt(); + opn = "slti"; + break; + case OPC_SLTIU: + gen_op_ltu(); + opn = "sltiu"; + break; + case OPC_ANDI: + gen_op_and(); + opn = "andi"; + break; + case OPC_ORI: + gen_op_or(); + opn = "ori"; + break; + case OPC_XORI: + gen_op_xor(); + opn = "xori"; + break; + case OPC_LUI: + opn = "lui"; + break; + case OPC_SLL: + gen_op_sll(); + opn = "sll"; + break; + case OPC_SRA: + gen_op_sra(); + opn = "sra"; + break; + case OPC_SRL: + gen_op_srl(); + opn = "srl"; + break; + default: + MIPS_INVAL("imm arith"); + generate_exception(ctx, EXCP_RI); + return; + } + GEN_STORE_TN_REG(rt, T0); + MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm); +} + +/* Arithmetic */ +static void gen_arith (DisasContext *ctx, uint16_t opc, + int rd, int rs, int rt) +{ + const unsigned char *opn = "unk"; + + if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) { + /* if no destination, treat it as a NOP + * For add & sub, we must generate the overflow exception when needed. + */ + MIPS_DEBUG("NOP"); + return; + } + GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_TN(T1, rt); + switch (opc) { + case OPC_ADD: + save_cpu_state(ctx, 1); + gen_op_addo(); + opn = "add"; + break; + case OPC_ADDU: + gen_op_add(); + opn = "addu"; + break; + case OPC_SUB: + save_cpu_state(ctx, 1); + gen_op_subo(); + opn = "sub"; + break; + case OPC_SUBU: + gen_op_sub(); + opn = "subu"; + break; + case OPC_SLT: + gen_op_lt(); + opn = "slt"; + break; + case OPC_SLTU: + gen_op_ltu(); + opn = "sltu"; + break; + case OPC_AND: + gen_op_and(); + opn = "and"; + break; + case OPC_NOR: + gen_op_nor(); + opn = "nor"; + break; + case OPC_OR: + gen_op_or(); + opn = "or"; + break; + case OPC_XOR: + gen_op_xor(); + opn = "xor"; + break; + case OPC_MUL: + gen_op_mul(); + opn = "mul"; + break; + case OPC_MOVN: + gen_op_movn(rd); + opn = "movn"; + goto print; + case OPC_MOVZ: + gen_op_movz(rd); + opn = "movz"; + goto print; + case OPC_SLLV: + gen_op_sllv(); + opn = "sllv"; + break; + case OPC_SRAV: + gen_op_srav(); + opn = "srav"; + break; + case OPC_SRLV: + gen_op_srlv(); + opn = "srlv"; + break; + default: + MIPS_INVAL("arith"); + generate_exception(ctx, EXCP_RI); + return; + } + GEN_STORE_TN_REG(rd, T0); + print: + MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); +} + +/* Arithmetic on HI/LO registers */ +static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg) +{ + const unsigned char *opn = "unk"; + + if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { + /* Treat as a NOP */ + MIPS_DEBUG("NOP"); + return; + } + switch (opc) { + case OPC_MFHI: + gen_op_load_HI(); + GEN_STORE_TN_REG(reg, T0); + opn = "mfhi"; + break; + case OPC_MFLO: + gen_op_load_LO(); + GEN_STORE_TN_REG(reg, T0); + opn = "mflo"; + break; + case OPC_MTHI: + GEN_LOAD_REG_TN(T0, reg); + gen_op_store_HI(); + opn = "mthi"; + break; + case OPC_MTLO: + GEN_LOAD_REG_TN(T0, reg); + gen_op_store_LO(); + opn = "mtlo"; + break; + default: + MIPS_INVAL("HILO"); + generate_exception(ctx, EXCP_RI); + return; + } + MIPS_DEBUG("%s %s", opn, regnames[reg]); +} + +static void gen_muldiv (DisasContext *ctx, uint16_t opc, + int rs, int rt) +{ + const unsigned char *opn = "unk"; + + GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_TN(T1, rt); + switch (opc) { + case OPC_DIV: + gen_op_div(); + opn = "div"; + break; + case OPC_DIVU: + gen_op_divu(); + opn = "divu"; + break; + case OPC_MULT: + gen_op_mult(); + opn = "mult"; + break; + case OPC_MULTU: + gen_op_multu(); + opn = "multu"; + break; + case OPC_MADD: + gen_op_madd(); + opn = "madd"; + break; + case OPC_MADDU: + gen_op_maddu(); + opn = "maddu"; + break; + case OPC_MSUB: + gen_op_msub(); + opn = "msub"; + break; + case OPC_MSUBU: + gen_op_msubu(); + opn = "msubu"; + break; + default: + MIPS_INVAL("mul/div"); + generate_exception(ctx, EXCP_RI); + return; + } + MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]); +} + +static void gen_cl (DisasContext *ctx, uint16_t opc, + int rd, int rs) +{ + const unsigned char *opn = "unk"; + if (rd == 0) { + /* Treat as a NOP */ + MIPS_DEBUG("NOP"); + return; + } + GEN_LOAD_REG_TN(T0, rs); + switch (opc) { + case OPC_CLO: + /* CLO */ + gen_op_clo(); + opn = "clo"; + break; + case OPC_CLZ: + /* CLZ */ + gen_op_clz(); + opn = "clz"; + break; + default: + MIPS_INVAL("CLx"); + generate_exception(ctx, EXCP_RI); + return; + } + gen_op_store_T0_gpr(rd); + MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); +} + +/* Traps */ +static void gen_trap (DisasContext *ctx, uint16_t opc, + int rs, int rt, int16_t imm) +{ + int cond; + + cond = 0; + /* Load needed operands */ + switch (opc) { + case OPC_TEQ: + case OPC_TGE: + case OPC_TGEU: + case OPC_TLT: + case OPC_TLTU: + case OPC_TNE: + /* Compare two registers */ + if (rs != rt) { + GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_TN(T1, rt); + cond = 1; + } + case OPC_TEQI: + case OPC_TGEI: + case OPC_TGEIU: + case OPC_TLTI: + case OPC_TLTIU: + case OPC_TNEI: + /* Compare register to immediate */ + if (rs != 0 || imm != 0) { + GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_IMM_TN(T1, (int32_t)imm); + cond = 1; + } + break; + } + if (cond == 0) { + switch (opc) { + case OPC_TEQ: /* rs == rs */ + case OPC_TEQI: /* r0 == 0 */ + case OPC_TGE: /* rs >= rs */ + case OPC_TGEI: /* r0 >= 0 */ + case OPC_TGEU: /* rs >= rs unsigned */ + case OPC_TGEIU: /* r0 >= 0 unsigned */ + /* Always trap */ + gen_op_set_T0(1); + break; + case OPC_TLT: /* rs < rs */ + case OPC_TLTI: /* r0 < 0 */ + case OPC_TLTU: /* rs < rs unsigned */ + case OPC_TLTIU: /* r0 < 0 unsigned */ + case OPC_TNE: /* rs != rs */ + case OPC_TNEI: /* r0 != 0 */ + /* Never trap: treat as NOP */ + return; + default: + MIPS_INVAL("TRAP"); + generate_exception(ctx, EXCP_RI); + return; + } + } else { + switch (opc) { + case OPC_TEQ: + case OPC_TEQI: + gen_op_eq(); + break; + case OPC_TGE: + case OPC_TGEI: + gen_op_ge(); + break; + case OPC_TGEU: + case OPC_TGEIU: + gen_op_geu(); + break; + case OPC_TLT: + case OPC_TLTI: + gen_op_lt(); + break; + case OPC_TLTU: + case OPC_TLTIU: + gen_op_ltu(); + break; + case OPC_TNE: + case OPC_TNEI: + gen_op_ne(); + break; + default: + MIPS_INVAL("TRAP"); + generate_exception(ctx, EXCP_RI); + return; + } + } + save_cpu_state(ctx, 1); + gen_op_trap(); + ctx->bstate = BS_STOP; +} + +/* Branches (before delay slot) */ +static void gen_compute_branch (DisasContext *ctx, uint16_t opc, + int rs, int rt, int32_t offset) +{ + target_ulong btarget; + int blink, bcond; + + btarget = -1; + blink = 0; + bcond = 0; + /* Load needed operands */ + switch (opc) { + case OPC_BEQ: + case OPC_BEQL: + case OPC_BNE: + case OPC_BNEL: + /* Compare two registers */ + if (rs != rt) { + GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_TN(T1, rt); + bcond = 1; + } + btarget = ctx->pc + 4 + offset; + break; + case OPC_BGEZ: + case OPC_BGEZAL: + case OPC_BGEZALL: + case OPC_BGEZL: + case OPC_BGTZ: + case OPC_BGTZL: + case OPC_BLEZ: + case OPC_BLEZL: + case OPC_BLTZ: + case OPC_BLTZAL: + case OPC_BLTZALL: + case OPC_BLTZL: + /* Compare to zero */ + if (rs != 0) { + gen_op_load_gpr_T0(rs); + bcond = 1; + } + btarget = ctx->pc + 4 + offset; + break; + case OPC_J: + case OPC_JAL: + /* Jump to immediate */ + btarget = ((ctx->pc + 4) & 0xFF000000) | offset; + break; + case OPC_JR: + case OPC_JALR: + /* Jump to register */ + if (offset != 0) { + /* Only hint = 0 is valid */ + generate_exception(ctx, EXCP_RI); + return; + } + GEN_LOAD_REG_TN(T2, rs); + break; + default: + MIPS_INVAL("branch/jump"); + generate_exception(ctx, EXCP_RI); + return; + } + if (bcond == 0) { + /* No condition to be computed */ + switch (opc) { + case OPC_BEQ: /* rx == rx */ + case OPC_BEQL: /* rx == rx likely */ + case OPC_BGEZ: /* 0 >= 0 */ + case OPC_BGEZL: /* 0 >= 0 likely */ + case OPC_BLEZ: /* 0 <= 0 */ + case OPC_BLEZL: /* 0 <= 0 likely */ + /* Always take */ + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + MIPS_DEBUG("balways"); + break; + case OPC_BGEZAL: /* 0 >= 0 */ + case OPC_BGEZALL: /* 0 >= 0 likely */ + /* Always take and link */ + blink = 31; + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + MIPS_DEBUG("balways and link"); + break; + case OPC_BNE: /* rx != rx */ + case OPC_BGTZ: /* 0 > 0 */ + case OPC_BLTZ: /* 0 < 0 */ + case OPC_BLTZAL: /* 0 < 0 */ + /* Treated as NOP */ + MIPS_DEBUG("bnever (NOP)"); + return; + case OPC_BNEL: /* rx != rx likely */ + case OPC_BGTZL: /* 0 > 0 likely */ + case OPC_BLTZALL: /* 0 < 0 likely */ + case OPC_BLTZL: /* 0 < 0 likely */ + /* Skip the instruction in the delay slot */ + MIPS_DEBUG("bnever and skip"); + gen_op_branch((long)ctx->tb, ctx->pc + 4); + return; + case OPC_J: + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + MIPS_DEBUG("j %08x", btarget); + break; + case OPC_JAL: + blink = 31; + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + MIPS_DEBUG("jal %08x", btarget); + break; + case OPC_JR: + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR; + MIPS_DEBUG("jr %s", regnames[rs]); + break; + case OPC_JALR: + blink = rt; + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR; + MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); + break; + default: + MIPS_INVAL("branch/jump"); + generate_exception(ctx, EXCP_RI); + return; + } + } else { + switch (opc) { + case OPC_BEQ: + gen_op_eq(); + MIPS_DEBUG("beq %s, %s, %08x", + regnames[rs], regnames[rt], btarget); + goto not_likely; + case OPC_BEQL: + gen_op_eq(); + MIPS_DEBUG("beql %s, %s, %08x", + regnames[rs], regnames[rt], btarget); + goto likely; + case OPC_BNE: + gen_op_ne(); + MIPS_DEBUG("bne %s, %s, %08x", + regnames[rs], regnames[rt], btarget); + goto not_likely; + case OPC_BNEL: + gen_op_ne(); + MIPS_DEBUG("bnel %s, %s, %08x", + regnames[rs], regnames[rt], btarget); + goto likely; + case OPC_BGEZ: + gen_op_gez(); + MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget); + goto not_likely; + case OPC_BGEZL: + gen_op_gez(); + MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget); + goto likely; + case OPC_BGEZAL: + gen_op_gez(); + MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget); + blink = 31; + goto not_likely; + case OPC_BGEZALL: + gen_op_gez(); + blink = 31; + MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget); + goto likely; + case OPC_BGTZ: + gen_op_gtz(); + MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget); + goto not_likely; + case OPC_BGTZL: + gen_op_gtz(); + MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget); + goto likely; + case OPC_BLEZ: + gen_op_lez(); + MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget); + goto not_likely; + case OPC_BLEZL: + gen_op_lez(); + MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget); + goto likely; + case OPC_BLTZ: + gen_op_ltz(); + MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget); + goto not_likely; + case OPC_BLTZL: + gen_op_ltz(); + MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget); + goto likely; + case OPC_BLTZAL: + gen_op_ltz(); + blink = 31; + MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); + not_likely: + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BC; + break; + case OPC_BLTZALL: + gen_op_ltz(); + blink = 31; + MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); + likely: + ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BL; + break; + } + gen_op_set_bcond(); + } + MIPS_DEBUG("enter ds: link %d cond %02x target %08x", + blink, ctx->hflags, btarget); + ctx->btarget = btarget; + if (blink > 0) { + gen_op_set_T0(ctx->pc + 8); + gen_op_store_T0_gpr(blink); + } + return; +} + +/* CP0 (MMU and control) */ +static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) +{ + const unsigned char *opn = "unk"; + + if (!(ctx->CP0_Status & (1 << CP0St_CU0))) { + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "CP0 is not usable\n"); + } + gen_op_raise_exception_err(EXCP_CpU, 0); + return; + } + switch (opc) { + case OPC_MFC0: + if (rt == 0) { + /* Treat as NOP */ + return; + } + gen_op_mfc0(rd, ctx->opcode & 0x7); + gen_op_store_T0_gpr(rt); + opn = "mfc0"; + break; + case OPC_MTC0: + /* If we get an exception, we want to restart at next instruction */ + ctx->pc += 4; + save_cpu_state(ctx, 1); + ctx->pc -= 4; + GEN_LOAD_REG_TN(T0, rt); + gen_op_mtc0(rd, ctx->opcode & 0x7); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + opn = "mtc0"; + break; +#if defined(MIPS_USES_R4K_TLB) + case OPC_TLBWI: + gen_op_tlbwi(); + opn = "tlbwi"; + break; + case OPC_TLBWR: + gen_op_tlbwr(); + opn = "tlbwr"; + break; + case OPC_TLBP: + gen_op_tlbp(); + opn = "tlbp"; + break; + case OPC_TLBR: + gen_op_tlbr(); + opn = "tlbr"; + break; +#endif + case OPC_ERET: + opn = "eret"; + save_cpu_state(ctx, 0); + gen_op_eret(); + ctx->bstate = BS_EXCP; + break; + case OPC_DERET: + opn = "deret"; + if (!(ctx->hflags & MIPS_HFLAG_DM)) { + generate_exception(ctx, EXCP_RI); + } else { + save_cpu_state(ctx, 0); + gen_op_deret(); + ctx->bstate = BS_EXCP; + } + break; + /* XXX: TODO: WAIT */ + default: + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n", + ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, + ((ctx->opcode >> 16) & 0x1F)); + } + generate_exception(ctx, EXCP_RI); + return; + } + MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); +} + +/* Coprocessor 1 (FPU) */ + +/* ISA extensions */ +/* MIPS16 extension to MIPS32 */ +/* SmartMIPS extension to MIPS32 */ + +#ifdef TARGET_MIPS64 +static void gen_arith64 (DisasContext *ctx, uint16_t opc) +{ + if (func == 0x02 && rd == 0) { + /* NOP */ + return; + } + if (rs == 0 || rt == 0) { + gen_op_reset_T0(); + gen_op_save64(); + } else { + gen_op_load_gpr_T0(rs); + gen_op_load_gpr_T1(rt); + gen_op_save64(); + if (func & 0x01) + gen_op_mul64u(); + else + gen_op_mul64s(); + } + if (func & 0x02) + gen_op_add64(); + else + gen_op_sub64(); +} + +/* Coprocessor 3 (FPU) */ + +/* MDMX extension to MIPS64 */ +/* MIPS-3D extension to MIPS64 */ + +#endif + +static void decode_opc (DisasContext *ctx) +{ + int32_t offset; + int rs, rt, rd, sa; + uint16_t op, op1; + int16_t imm; + + if ((ctx->hflags & MIPS_HFLAG_DS) && + (ctx->hflags & MIPS_HFLAG_BL)) { + /* Handle blikely not taken case */ + MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); + gen_op_blikely((long)ctx->tb, ctx->pc + 4, + ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); + } + op = ctx->opcode >> 26; + rs = ((ctx->opcode >> 21) & 0x1F); + rt = ((ctx->opcode >> 16) & 0x1F); + rd = ((ctx->opcode >> 11) & 0x1F); + sa = ((ctx->opcode >> 6) & 0x1F); + imm = (int16_t)ctx->opcode; + switch (op) { + case 0x00: /* Special opcode */ + op1 = ctx->opcode & 0x3F; + switch (op1) { + case 0x00: /* Arithmetic with immediate */ + case 0x02 ... 0x03: + gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa); + break; + case 0x04: /* Arithmetic */ + case 0x06 ... 0x07: + case 0x0A ... 0x0B: + case 0x20 ... 0x27: + case 0x2A ... 0x2B: + gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt); + break; + case 0x18 ... 0x1B: /* MULT / DIV */ + gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt); + break; + case 0x08 ... 0x09: /* Jumps */ + gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa); + return; + case 0x30 ... 0x34: /* Traps */ + case 0x36: + gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1); + break; + case 0x10: /* Move from HI/LO */ + case 0x12: + gen_HILO(ctx, op1 | EXT_SPECIAL, rd); + break; + case 0x11: + case 0x13: /* Move to HI/LO */ + gen_HILO(ctx, op1 | EXT_SPECIAL, rs); + break; + case 0x0C: /* SYSCALL */ + generate_exception(ctx, EXCP_SYSCALL); + break; + case 0x0D: /* BREAK */ + generate_exception(ctx, EXCP_BREAK); + break; + case 0x0F: /* SYNC */ + /* Treat as a noop */ + break; + case 0x05: /* Pmon entry point */ + gen_op_pmon((ctx->opcode >> 6) & 0x1F); + break; +#if defined (MIPS_HAS_MOVCI) + case 0x01: /* MOVCI */ +#endif +#if defined (TARGET_MIPS64) + case 0x14: /* MIPS64 specific opcodes */ + case 0x16: + case 0x17: + case 0x1C ... 0x1F: + case 0x2C ... 0x2F: + case 0x37: + case 0x39 ... 0x3B: + case 0x3E ... 0x3F: +#endif + default: /* Invalid */ + MIPS_INVAL("special"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case 0x1C: /* Special2 opcode */ + op1 = ctx->opcode & 0x3F; + switch (op1) { +#if defined (MIPS_USES_R4K_EXT) + /* Those instructions are not part of MIPS32 core */ + case 0x00 ... 0x01: /* Multiply and add/sub */ + case 0x04 ... 0x05: + gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt); + break; + case 0x02: /* MUL */ + gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt); + break; + case 0x20 ... 0x21: /* CLO / CLZ */ + gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs); + break; +#endif + case 0x3F: /* SDBBP */ + /* XXX: not clear which exception should be raised + * when in debug mode... + */ + if (!(ctx->hflags & MIPS_HFLAG_DM)) { + generate_exception(ctx, EXCP_DBp); + } else { + generate_exception(ctx, EXCP_DBp); + } + /* Treat as a noop */ + break; + default: /* Invalid */ + MIPS_INVAL("special2"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case 0x01: /* B REGIMM opcode */ + op1 = ((ctx->opcode >> 16) & 0x1F); + switch (op1) { + case 0x00 ... 0x03: /* REGIMM branches */ + case 0x10 ... 0x13: + gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2); + return; + case 0x08 ... 0x0C: /* Traps */ + case 0x0E: + gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm); + break; + default: /* Invalid */ + MIPS_INVAL("REGIMM"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case 0x10: /* CP0 opcode */ + op1 = ((ctx->opcode >> 21) & 0x1F); + switch (op1) { + case 0x00: + case 0x04: + gen_cp0(ctx, op1 | EXT_CP0, rt, rd); + break; + default: + gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd); + break; + } + break; + case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */ + gen_arith_imm(ctx, op, rt, rs, imm); + break; + case 0x02 ... 0x03: /* Jump */ + offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2; + gen_compute_branch(ctx, op, rs, rt, offset); + return; + case 0x04 ... 0x07: /* Branch */ + case 0x14 ... 0x17: + gen_compute_branch(ctx, op, rs, rt, imm << 2); + return; + case 0x20 ... 0x26: /* Load and stores */ + case 0x28 ... 0x2E: + case 0x30: + case 0x38: + gen_ldst(ctx, op, rt, rs, imm); + break; + case 0x2F: /* Cache operation */ + /* Treat as a noop */ + break; + case 0x33: /* Prefetch */ + /* Treat as a noop */ + break; + case 0x3F: /* HACK */ + break; +#if defined(MIPS_USES_FPU) + case 0x31 ... 0x32: /* Floating point load/store */ + case 0x35 ... 0x36: + case 0x3A ... 0x3B: + case 0x3D ... 0x3E: + /* Not implemented */ + /* XXX: not correct */ +#endif + case 0x11: /* CP1 opcode */ + /* Not implemented */ + /* XXX: not correct */ + case 0x12: /* CP2 opcode */ + /* Not implemented */ + /* XXX: not correct */ + case 0x13: /* CP3 opcode */ + /* Not implemented */ + /* XXX: not correct */ +#if defined (TARGET_MIPS64) + case 0x18 ... 0x1B: + case 0x27: + case 0x34: + case 0x37: + /* MIPS64 opcodes */ +#endif +#if defined (MIPS_HAS_JALX) + case 0x1D: + /* JALX: not implemented */ +#endif + case 0x1E: + /* ASE specific */ +#if defined (MIPS_HAS_LSC) + case 0x31: /* LWC1 */ + case 0x32: /* LWC2 */ + case 0x35: /* SDC1 */ + case 0x36: /* SDC2 */ +#endif + default: /* Invalid */ + MIPS_INVAL(""); + generate_exception(ctx, EXCP_RI); + break; + } + if (ctx->hflags & MIPS_HFLAG_DS) { + int hflags = ctx->hflags; + /* Branches completion */ + ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS); + ctx->bstate = BS_BRANCH; + save_cpu_state(ctx, 0); + switch (hflags & MIPS_HFLAG_BMASK) { + case MIPS_HFLAG_B: + /* unconditional branch */ + MIPS_DEBUG("unconditional branch"); + gen_op_branch((long)ctx->tb, ctx->btarget); + break; + case MIPS_HFLAG_BL: + /* blikely taken case */ + MIPS_DEBUG("blikely branch taken"); + gen_op_branch((long)ctx->tb, ctx->btarget); + break; + case MIPS_HFLAG_BC: + /* Conditional branch */ + MIPS_DEBUG("conditional branch"); + gen_op_bcond((long)ctx->tb, ctx->btarget, ctx->pc + 4); + break; + case MIPS_HFLAG_BR: + /* unconditional branch to register */ + MIPS_DEBUG("branch to register"); + gen_op_breg(); + break; + default: + MIPS_DEBUG("unknown branch"); + break; + } + } +} + +int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, + int search_pc) +{ + DisasContext ctx, *ctxp = &ctx; + target_ulong pc_start; + uint16_t *gen_opc_end; + int j, lj = -1; + + pc_start = tb->pc; + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + ctx.pc = pc_start; + ctx.tb = tb; + ctx.bstate = BS_NONE; + /* Restore delay slot state */ + ctx.hflags = env->hflags; + ctx.saved_hflags = ctx.hflags; + if (ctx.hflags & MIPS_HFLAG_BR) { + gen_op_restore_breg_target(); + } else if (ctx.hflags & MIPS_HFLAG_B) { + ctx.btarget = env->btarget; + } else if (ctx.hflags & MIPS_HFLAG_BMASK) { + /* If we are in the delay slot of a conditional branch, + * restore the branch condition from env->bcond to T2 + */ + ctx.btarget = env->btarget; + gen_op_restore_bcond(); + } +#if defined(CONFIG_USER_ONLY) + ctx.mem_idx = 0; +#else + ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1; +#endif + ctx.CP0_Status = env->CP0_Status; +#ifdef DEBUG_DISAS + if (loglevel & CPU_LOG_TB_CPU) { + fprintf(logfile, "------------------------------------------------\n"); + cpu_dump_state(env, logfile, fprintf, 0); + } +#endif +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "\ntb %p super %d cond %04x %04x\n", + tb, ctx.mem_idx, ctx.hflags, env->hflags); +#endif + while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + save_cpu_state(ctxp, 1); + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + gen_opc_pc[lj] = ctx.pc; + gen_opc_instr_start[lj] = 1; + } + } + ctx.opcode = ldl_code(ctx.pc); + decode_opc(&ctx); + ctx.pc += 4; + if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) + break; +#if defined (MIPS_SINGLE_STEP) + break; +#endif + } + if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { + save_cpu_state(ctxp, 0); + gen_op_branch((long)ctx.tb, ctx.pc); + } + gen_op_reset_T0(); + /* Generate the return instruction */ + gen_op_exit_tb(); + *gen_opc_ptr = INDEX_op_end; + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + tb->size = 0; + } else { + tb->size = ctx.pc - pc_start; + } +#ifdef DEBUG_DISAS +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "\n"); +#endif + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + target_disas(logfile, pc_start, ctx.pc - pc_start, 0); + fprintf(logfile, "\n"); + } + if (loglevel & CPU_LOG_TB_OP) { + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } + if (loglevel & CPU_LOG_TB_CPU) { + fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags); + } +#endif + + return 0; +} + +int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 1); +} + +void cpu_dump_state (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; + + cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n", + env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); + for (i = 0; i < 32; i++) { + if ((i & 3) == 0) + cpu_fprintf(f, "GPR%02d:", i); + cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]); + if ((i & 3) == 3) + cpu_fprintf(f, "\n"); + } + cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n", + env->CP0_Status, env->CP0_Cause, env->CP0_EPC); + cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n", + env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); +} + +CPUMIPSState *cpu_mips_init (void) +{ + CPUMIPSState *env; + + cpu_exec_init(); + env = qemu_mallocz(sizeof(CPUMIPSState)); + if (!env) + return NULL; + tlb_flush(env, 1); + /* Minimal init */ + env->PC = 0xBFC00000; +#if defined (MIPS_USES_R4K_TLB) + env->CP0_random = MIPS_TLB_NB - 1; +#endif + env->CP0_Wired = 0; + env->CP0_Config0 = MIPS_CONFIG0; +#if defined (MIPS_CONFIG1) + env->CP0_Config1 = MIPS_CONFIG1; +#endif +#if defined (MIPS_CONFIG2) + env->CP0_Config2 = MIPS_CONFIG2; +#endif +#if defined (MIPS_CONFIG3) + env->CP0_Config3 = MIPS_CONFIG3; +#endif + env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV); + env->CP0_WatchLo = 0; + env->hflags = MIPS_HFLAG_ERL; + /* Count register increments in debug mode, EJTAG version 1 */ + env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); + env->CP0_PRid = MIPS_CPU; + env->exception_index = EXCP_NONE; + + cpu_single_env = env; + + return env; +} diff --git a/translate-all.c b/translate-all.c index e4f7c9c19..cac91c535 100644 --- a/translate-all.c +++ b/translate-all.c @@ -300,6 +300,8 @@ int cpu_restore_state(TranslationBlock *tb, } env->access_type = type; } +#elif defined(TARGET_MIPS) + env->PC = gen_opc_pc[j]; #endif return 0; } diff --git a/vl.c b/vl.c index 178c13a6d..86e61c360 100644 --- a/vl.c +++ b/vl.c @@ -2348,6 +2348,17 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) { return 0; } + +#elif defined(TARGET_MIPS) +void cpu_save(QEMUFile *f, void *opaque) +{ +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} + #elif defined(TARGET_SPARC) void cpu_save(QEMUFile *f, void *opaque) { @@ -3058,6 +3069,8 @@ void register_machines(void) qemu_register_machine(&heathrow_machine); qemu_register_machine(&core99_machine); qemu_register_machine(&prep_machine); +#elif defined(TARGET_MIPS) + qemu_register_machine(&mips_machine); #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 qemu_register_machine(&sun4u_machine); diff --git a/vl.h b/vl.h index 81fd06a01..64e9777a4 100644 --- a/vl.h +++ b/vl.h @@ -138,6 +138,8 @@ extern int win2k_install_hack; /* XXX: make it dynamic */ #if defined (TARGET_PPC) #define BIOS_SIZE (512 * 1024) +#elif defined(TARGET_MIPS) +#define BIOS_SIZE (128 * 1024) #else #define BIOS_SIZE ((256 + 64) * 1024) #endif @@ -715,6 +717,9 @@ extern QEMUMachine prep_machine; extern QEMUMachine core99_machine; extern QEMUMachine heathrow_machine; +/* mips_r4k.c */ +extern QEMUMachine mips_machine; + #ifdef TARGET_PPC ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); #endif -- cgit v1.2.3 From 9fb63ac281f4472242f040b59d428aba35237530 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:07:44 +0000 Subject: MIPS_USES_R4K_TLB typo git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1465 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 05661bb97..aaee8f919 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -17,11 +17,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #include "exec.h" /* MIPS32 4K MMU emulation */ -#if MIPS_USES_4K_TLB +#ifdef MIPS_USES_R4K_TLB static int map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) { @@ -44,9 +43,9 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, /* Check access rights */ if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) { *physical = tlb->PFN[n] | (address & 0xFFF); - *prot = PROT_READ; + *prot = PAGE_READ; if (tlb->D[n]) - *prot |= PROT_WRITE; + *prot |= PAGE_WRITE; return 0; } else if (!(tlb->V[n] & 2)) { return -3; @@ -78,9 +77,9 @@ int get_physical_address (CPUState *env, target_ulong *physical, int *prot, return -1; ret = 0; if (address < 0x80000000UL) { - if (user_mode || !(env->hflags & MIPS_HFLAG_ERL)) { -#if MIPS_USES_4K_TLB - ret = map_address(env, physical, prot, address, rw); + if (!(env->hflags & MIPS_HFLAG_ERL)) { +#ifdef MIPS_USES_R4K_TLB + ret = map_address(env, physical, prot, address, rw, access_type); #else *physical = address + 0x40000000UL; *prot = PAGE_READ | PAGE_WRITE; @@ -101,8 +100,8 @@ int get_physical_address (CPUState *env, target_ulong *physical, int *prot, *prot = PAGE_READ | PAGE_WRITE; } else if (address < 0xE0000000UL) { /* kseg2 */ -#if MIPS_USES_4K_TLB - ret = map_address(env, physical, prot, address, rw); +#ifdef MIPS_USES_R4K_TLB + ret = map_address(env, physical, prot, address, rw, access_type); #else *physical = address; *prot = PAGE_READ | PAGE_WRITE; @@ -111,8 +110,8 @@ int get_physical_address (CPUState *env, target_ulong *physical, int *prot, /* kseg3 */ /* XXX: check supervisor mode */ /* XXX: debug segment is not emulated */ -#if MIPS_USES_4K_TLB - ret = map_address(env, physical, prot, address, rw); +#ifdef MIPS_USES_R4K_TLB + ret = map_address(env, physical, prot, address, rw, access_type); #else *physical = address; *prot = PAGE_READ | PAGE_WRITE; @@ -332,7 +331,7 @@ void do_interrupt (CPUState *env) pc = 0xBFC00480; break; case EXCP_RESET: -#if defined (MIPS_USES_R4K_TLB) +#ifdef MIPS_USES_R4K_TLB env->CP0_random = MIPS_TLB_NB - 1; #endif env->CP0_Wired = 0; -- cgit v1.2.3 From bc9ed47b123a0a8d3aa32d5bd3f8c682afcd6bd0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:10:44 +0000 Subject: fixed jump mask (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1466 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 87e123ade..cb1791f09 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -798,7 +798,7 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, case OPC_J: case OPC_JAL: /* Jump to immediate */ - btarget = ((ctx->pc + 4) & 0xFF000000) | offset; + btarget = ((ctx->pc + 4) & 0xF0000000) | offset; break; case OPC_JR: case OPC_JALR: -- cgit v1.2.3 From de12d6369bec323e9198c85b9cd60e52812442ba Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:11:25 +0000 Subject: kernel load fix (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1467 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 1b6a80167..528ff2b8d 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -257,8 +257,9 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, if (linux_boot) { kernel_base = KERNEL_LOAD_ADDR; /* now we can load the kernel */ - kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); - if (kernel_size < 0) { + kernel_size = load_image(kernel_filename, + phys_ram_base + (kernel_base - 0x80000000)); + if (kernel_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); @@ -268,7 +269,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, initrd_base = INITRD_LOAD_ADDR; initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base); - if (initrd_size < 0) { + if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); -- cgit v1.2.3 From dfae6487c048d9888820737f1546bac438030a31 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:12:18 +0000 Subject: remove nonsense exception code (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1468 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index aaee8f919..1a15246a9 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -261,9 +261,6 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, break; } - if (ret == -2) { - exception = EXCP_AdEL; - } /* Raise exception */ env->CP0_BadVAddr = address; env->CP0_Context = -- cgit v1.2.3 From 899abcf5131ee7e433935a599ca3d22e51bf18ac Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:13:42 +0000 Subject: fixed random register (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1469 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 528ff2b8d..27f636530 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -78,14 +78,14 @@ void cpu_mips_irqctrl_init (void) { } -/* MIPS R4K timer */ uint32_t cpu_mips_get_random (CPUState *env) { - uint64_t now = qemu_get_clock(vm_clock); + uint32_t now = qemu_get_clock(vm_clock); - return (uint32_t)now & 0x0000000F; + return now % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired; } +/* MIPS R4K timer */ uint32_t cpu_mips_get_count (CPUState *env) { return env->CP0_Count + -- cgit v1.2.3 From ae022501f2a17f522b33db2af54ab42d7f456ce8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:16:15 +0000 Subject: soft irq are just irqs (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1470 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- target-mips/op_helper.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 20cb0df62..c7cd60788 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -307,7 +307,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Cause & 0x0000FC00) && + (env->CP0_Cause & 0x0000FF00) && !(env->hflags & MIPS_HFLAG_EXL) && !(env->hflags & MIPS_HFLAG_ERL) && !(env->hflags & MIPS_HFLAG_DM)) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index dc1040786..854abea0c 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -352,7 +352,7 @@ void do_mtc0 (int reg, int sel) old = env->CP0_Status; env->CP0_Status = val; /* If we unmasked an asserted IRQ, raise it */ - mask = 0x0000FC00; + mask = 0x0000FF00; if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n", old, val, env->CP0_Cause, old & mask, val & mask, -- cgit v1.2.3 From 9d1d106a3d95ada648703e871975897c1cf05383 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:20:06 +0000 Subject: unaligned load fix (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1471 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index cb1791f09..386bf74b3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -329,6 +329,7 @@ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, opn = "lbu"; break; case OPC_LWL: + GEN_LOAD_REG_TN(T1, rt); op_ldst(lwl); GEN_STORE_TN_REG(rt, T0); opn = "lwl"; @@ -339,6 +340,7 @@ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, opn = "swr"; break; case OPC_LWR: + GEN_LOAD_REG_TN(T1, rt); op_ldst(lwr); GEN_STORE_TN_REG(rt, T0); opn = "lwr"; -- cgit v1.2.3 From 0699b548399936ed24b110e3e1f82cc80adbdfd9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:20:29 +0000 Subject: init cleanup (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1472 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 27f636530..1deda1488 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -285,22 +285,19 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, initrd_base = 0; initrd_size = 0; } - /* XXX: should not be ! */ - printf("%s: init VGA\n", __func__); - vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); - /* Init internal devices */ cpu_mips_clock_init(cpu_single_env); cpu_mips_irqctrl_init(); - isa_mem_base = 0x78000000; - /* Register 64 KB of ISA IO space at random address */ + /* Register 64 KB of ISA IO space at 0x14000000 */ io_memory = cpu_register_io_memory(0, io_read, io_write, NULL); - cpu_register_physical_memory(0x70000000, 0x00010000, io_memory); + cpu_register_physical_memory(0x14000000, 0x00010000, io_memory); + isa_mem_base = 0x10000000; + serial_init(0x3f8, 4, serial_hds[0]); - printf("%s: done\n", __func__); + vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); } QEMUMachine mips_machine = { -- cgit v1.2.3 From 90b37806ba1a09b77dc6245ac34dabbceba555df Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:22:34 +0000 Subject: fixed C0 status codes (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1473 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 854abea0c..bdfe7d057 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -174,11 +174,11 @@ void do_mfc0 (int reg, int sel) case 12: T0 = env->CP0_Status; if (env->hflags & MIPS_HFLAG_UM) - T0 |= CP0St_UM; + T0 |= (1 << CP0St_UM); if (env->hflags & MIPS_HFLAG_ERL) - T0 |= CP0St_ERL; + T0 |= (1 << CP0St_ERL); if (env->hflags & MIPS_HFLAG_EXL) - T0 |= CP0St_EXL; + T0 |= (1 << CP0St_EXL); rn = "Status"; break; case 13: -- cgit v1.2.3 From 51e11d9e6c8deea88ba2d24c8a04102c787cdd19 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:23:21 +0000 Subject: fixed eret insn (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1474 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 6d94be631..df76e8e71 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -597,10 +597,13 @@ void debug_eret (void); void op_eret (void) { CALL_FROM_TB0(debug_eret); - if (env->hflags & MIPS_HFLAG_ERL) + if (env->hflags & MIPS_HFLAG_ERL) { env->PC = env->CP0_ErrorEPC; - else + env->hflags &= ~MIPS_HFLAG_ERL; + } else { env->PC = env->CP0_EPC; + env->hflags &= ~MIPS_HFLAG_EXL; + } env->CP0_LLAddr = 1; } -- cgit v1.2.3 From 9827e95c78ff34051533211624d0177e744a92d7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:26:04 +0000 Subject: added NE2000 (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1475 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/mips_r4k.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index ade079f85..9bc08731b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -360,7 +360,7 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o endif ifeq ($(TARGET_ARCH), mips) -VL_OBJS+= mips.o mips_r4k.o dma.o vga.o serial.o #ide.o ne2000.o pckbd.o +VL_OBJS+= mips.o mips_r4k.o dma.o vga.o serial.o ne2000.o #ide.o pckbd.o VL_OBJS+= #i8259.o i8254.o fdc.o m48t59.o endif ifeq ($(TARGET_BASE_ARCH), sparc) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 1deda1488..44f1ba4fc 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -298,6 +298,8 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, serial_init(0x3f8, 4, serial_hds[0]); vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); + + isa_ne2000_init(0x300, 9, &nd_table[0]); } QEMUMachine mips_machine = { -- cgit v1.2.3 From bc2c390907757c4d172279e81395b8818338abec Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:27:11 +0000 Subject: fixed priviledgees for CP0 use (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1476 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 386bf74b3..d781fccfb 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -971,7 +971,10 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) { const unsigned char *opn = "unk"; - if (!(ctx->CP0_Status & (1 << CP0St_CU0))) { + if (!(ctx->CP0_Status & (1 << CP0St_CU0)) && + !(ctx->hflags & MIPS_HFLAG_UM) && + !(ctx->hflags & MIPS_HFLAG_ERL) && + !(ctx->hflags & MIPS_HFLAG_EXL)) { if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "CP0 is not usable\n"); } -- cgit v1.2.3 From 568b600d858a7bcb94ed4520a13ad1629750e03f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:28:16 +0000 Subject: report C0 status correctly (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1477 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index d781fccfb..f5529c1b3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1454,6 +1454,7 @@ void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { + uint32_t c0_status; int i; cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n", @@ -1465,8 +1466,17 @@ void cpu_dump_state (CPUState *env, FILE *f, if ((i & 3) == 3) cpu_fprintf(f, "\n"); } + + c0_status = env->CP0_Status; + if (env->hflags & MIPS_HFLAG_UM) + c0_status |= (1 << CP0St_UM); + if (env->hflags & MIPS_HFLAG_ERL) + c0_status |= (1 << CP0St_ERL); + if (env->hflags & MIPS_HFLAG_EXL) + c0_status |= (1 << CP0St_EXL); + cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n", - env->CP0_Status, env->CP0_Cause, env->CP0_EPC); + c0_status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n", env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); } -- cgit v1.2.3 From e1d9a50836b162d493afc9cb90610d8224a47c7e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:29:46 +0000 Subject: use mask in C0_status (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1478 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index bdfe7d057..9da31849c 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -363,7 +363,7 @@ void do_mtc0 (int reg, int sel) !(env->hflags & MIPS_HFLAG_EXL) && !(env->hflags & MIPS_HFLAG_ERL) && !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Cause & mask)) { + (env->CP0_Status & env->CP0_Cause & mask)) { if (logfile) fprintf(logfile, "Raise pending IRQs\n"); env->interrupt_request |= CPU_INTERRUPT_HARD; -- cgit v1.2.3 From 7a962d3087d24fa0ea377cbde39ab97f81457ff6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:31:15 +0000 Subject: use MIPS_TLB_NB constant (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1479 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 2 +- target-mips/op_helper.c | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 1a15246a9..238149614 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -33,7 +33,7 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, ret = -2; tag = (address & 0xFFFFE000); ASID = env->CP0_EntryHi & 0x000000FF; - for (i = 0; i < 16; i++) { + for (i = 0; i < MIPS_TLB_NB; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9da31849c..399200865 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -531,8 +531,10 @@ static void fill_tb (int idx) void do_tlbwi (void) { - invalidate_tb(env->CP0_index & 0xF); - fill_tb(env->CP0_index & 0xF); + /* Wildly undefined effects for CP0_index containing a too high value and + MIPS_TLB_NB not being a power of two. But so does real silicon. */ + invalidate_tb(env->CP0_index & (MIPS_TLB_NB - 1)); + fill_tb(env->CP0_index & (MIPS_TLB_NB - 1)); } void do_tlbwr (void) @@ -552,7 +554,7 @@ void do_tlbp (void) tag = (env->CP0_EntryHi & 0xFFFFE000); ASID = env->CP0_EntryHi & 0x000000FF; - for (i = 0; i < 16; i++) { + for (i = 0; i < MIPS_TLB_NB; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { @@ -561,7 +563,7 @@ void do_tlbp (void) break; } } - if (i == 16) { + if (i == MIPS_TLB_NB) { env->CP0_index |= 0x80000000; } } @@ -571,7 +573,7 @@ void do_tlbr (void) tlb_t *tlb; int size; - tlb = &env->tlb[env->CP0_index & 0xF]; + tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; env->CP0_EntryHi = tlb->VPN | tlb->ASID; size = (tlb->end - tlb->VPN) >> 12; env->CP0_PageMask = (size - 1) << 13; -- cgit v1.2.3 From 8549850891b3e0714cdb01aecf3e08a746c1b361 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:34:05 +0000 Subject: fixed c0_context in tlb exception (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1480 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 238149614..aa97e8229 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -263,10 +263,10 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, } /* Raise exception */ env->CP0_BadVAddr = address; - env->CP0_Context = - (env->CP0_Context & 0x00000FFF) | (address & 0xFFFFF000); + env->CP0_Context = (env->CP0_Context & 0xff800000) | + ((address >> 8) & 0x007ffff0); env->CP0_EntryHi = - (env->CP0_EntryHi & 0x00000FFF) | (address & 0xFFFFF000); + (env->CP0_EntryHi & 0x000000FF) | (address & 0xFFFFF000); env->exception_index = exception; env->error_code = error_code; ret = 1; -- cgit v1.2.3 From 0d8aca8c670b3203fa478443969c6a65166aadcc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:35:03 +0000 Subject: TLB reload exception vector (Ralf Baechle) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1481 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-mips/helper.c b/target-mips/helper.c index aa97e8229..96e3100da 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -417,6 +417,9 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBS: cause = 3; + if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) + offset = 0x000; + goto set_EPC; set_EPC: if (env->CP0_Status & (1 << CP0St_BEV)) { pc = 0xBFC00200; -- cgit v1.2.3 From d325856010ca97e4962aaf3150c5ee7c0d5340bb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:37:12 +0000 Subject: MIPS support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1482 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 9332aa10c..76b4bfe38 100755 --- a/configure +++ b/configure @@ -213,7 +213,7 @@ fi if test -z "$target_list" ; then # these targets are portable - target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu" # the following are Linux specific if [ "$linux" = "yes" ] ; then target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list" @@ -607,6 +607,7 @@ target_bigendian="no" [ "$target_cpu" = "sparc" ] && target_bigendian=yes [ "$target_cpu" = "sparc64" ] && target_bigendian=yes [ "$target_cpu" = "ppc" ] && target_bigendian=yes +[ "$target_cpu" = "mips" ] && target_bigendian=yes target_softmmu="no" if expr $target : '.*-softmmu' > /dev/null ; then target_softmmu="yes" @@ -679,6 +680,10 @@ elif test "$target_cpu" = "x86_64" ; then if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" ; then echo "#define USE_KQEMU 1" >> $config_h fi +elif test "$target_cpu" = "mips" ; then + echo "TARGET_ARCH=mips" >> $config_mak + echo "#define TARGET_ARCH \"mips\"" >> $config_h + echo "#define TARGET_MIPS 1" >> $config_h else echo "Unsupported target CPU" exit 1 -- cgit v1.2.3 From 1b351e52918c8eceb2b3dc7a9c5e0b7b342ccd18 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:39:04 +0000 Subject: moved CALL_FROM_TBx definitions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1483 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/target-mips/op.c b/target-mips/op.c index df76e8e71..32f7e4fc9 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -21,6 +21,30 @@ #include "config.h" #include "exec.h" +#ifndef CALL_FROM_TB0 +#define CALL_FROM_TB0(func) func(); +#endif +#ifndef CALL_FROM_TB1 +#define CALL_FROM_TB1(func, arg0) func(arg0); +#endif +#ifndef CALL_FROM_TB1_CONST16 +#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0); +#endif +#ifndef CALL_FROM_TB2 +#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1); +#endif +#ifndef CALL_FROM_TB2_CONST16 +#define CALL_FROM_TB2_CONST16(func, arg0, arg1) \ +CALL_FROM_TB2(func, arg0, arg1); +#endif +#ifndef CALL_FROM_TB3 +#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2); +#endif +#ifndef CALL_FROM_TB4 +#define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \ + func(arg0, arg1, arg2, arg3); +#endif + #define REG 1 #include "op_template.c" #undef REG -- cgit v1.2.3 From b195775fef3c221ff04e3091005e16c5745bf3c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 15:39:14 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1484 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index 9a41b98a8..a55f32855 100644 --- a/Changelog +++ b/Changelog @@ -5,6 +5,8 @@ version 0.7.1: N. Oleynik) - VMDK disk image creation (Filip Navara) - SPARC64 progress (Blue Swirl) + - initial MIPS support (Jocelyn mayer) + - MIPS improvements (Ralf Baechle) version 0.7.0: -- cgit v1.2.3 From bf82d81801536e79aefd1d0de3ab676b7ad23a34 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 18:07:26 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1485 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.cvsignore b/.cvsignore index 50debc4d4..ca88a6662 100644 --- a/.cvsignore +++ b/.cvsignore @@ -19,3 +19,4 @@ sparc-softmmu x86_64-softmmu sparc64-user sparc64-softmmu +mips-softmmu -- cgit v1.2.3 From 73133662c6db9e58d02716d9517b3947c853de68 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 18:11:03 +0000 Subject: i8259 PIC support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1486 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 69 ++++++----------------------------------------------------- 1 file changed, 7 insertions(+), 62 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 44f1ba4fc..9ce4a5ac9 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -1,77 +1,21 @@ #include "vl.h" -#define DEBUG_IRQ_COUNT - #define BIOS_FILENAME "mips_bios.bin" //#define BIOS_FILENAME "system.bin" #define KERNEL_LOAD_ADDR 0x80010000 #define INITRD_LOAD_ADDR 0x80800000 -/* MIPS R4K IRQ controler */ -#if defined(DEBUG_IRQ_COUNT) -static uint64_t irq_count[16]; -#endif - extern FILE *logfile; -void mips_set_irq (int n_IRQ, int level) +static void pic_irq_request(void *opaque, int level) { - uint32_t mask; - - if (n_IRQ < 0 || n_IRQ >= 8) - return; - mask = 0x100 << n_IRQ; - if (level != 0) { -#if 1 - if (logfile) { - fprintf(logfile, "%s n %d l %d mask %08x %08x\n", - __func__, n_IRQ, level, mask, cpu_single_env->CP0_Status); - } -#endif - cpu_single_env->CP0_Cause |= mask; - if ((cpu_single_env->CP0_Status & 0x00000001) && - (cpu_single_env->CP0_Status & mask)) { -#if defined(DEBUG_IRQ_COUNT) - irq_count[n_IRQ]++; -#endif -#if 1 - if (logfile) - fprintf(logfile, "%s raise IRQ\n", __func__); -#endif - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); - } + if (level) { + cpu_single_env->CP0_Cause |= 0x00000400; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); } else { - cpu_single_env->CP0_Cause &= ~mask; - } -} - -void pic_set_irq (int n_IRQ, int level) -{ - mips_set_irq(n_IRQ + 2, level); -} - -void pic_info (void) -{ - term_printf("IRQ asserted: %02x mask: %02x\n", - (cpu_single_env->CP0_Cause >> 8) & 0xFF, - (cpu_single_env->CP0_Status >> 8) & 0xFF); -} - -void irq_info (void) -{ -#if !defined(DEBUG_IRQ_COUNT) - term_printf("irq statistic code not compiled.\n"); -#else - int i; - int64_t count; - - term_printf("IRQ statistics:\n"); - for (i = 0; i < 8; i++) { - count = irq_count[i]; - if (count > 0) - term_printf("%2d: %lld\n", i, count); + cpu_single_env->CP0_Cause &= ~0x00000400; + cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); } -#endif } void cpu_mips_irqctrl_init (void) @@ -295,6 +239,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x14000000, 0x00010000, io_memory); isa_mem_base = 0x10000000; + isa_pic = pic_init(pic_irq_request, cpu_single_env); serial_init(0x3f8, 4, serial_hds[0]); vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); -- cgit v1.2.3 From 3de388f676e936097f99fb58e8a58c5461eb696e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 18:11:44 +0000 Subject: more generic i8259 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1487 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/i8259.c | 145 ++++++++++++++++++++++++++++++++------------------------ hw/ide.c | 6 +-- hw/pc.c | 29 +++++++++++- hw/ppc_chrp.c | 9 +++- hw/ppc_prep.c | 15 ++++-- vl.c | 1 + vl.h | 9 +++- 8 files changed, 141 insertions(+), 77 deletions(-) diff --git a/Makefile.target b/Makefile.target index 9bc08731b..c2fed5342 100644 --- a/Makefile.target +++ b/Makefile.target @@ -360,8 +360,8 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o endif ifeq ($(TARGET_ARCH), mips) -VL_OBJS+= mips.o mips_r4k.o dma.o vga.o serial.o ne2000.o #ide.o pckbd.o -VL_OBJS+= #i8259.o i8254.o fdc.o m48t59.o +VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8259.o +#VL_OBJS+= #ide.o pckbd.o i8254.o fdc.o m48t59.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) diff --git a/hw/i8259.c b/hw/i8259.c index 9bfaaed1b..1be40c909 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -46,10 +46,16 @@ typedef struct PicState { uint8_t init4; /* true if 4 byte init */ uint8_t elcr; /* PIIX edge/trigger selection*/ uint8_t elcr_mask; + PicState2 *pics_state; } PicState; -/* 0 is master pic, 1 is slave pic */ -static PicState pics[2]; +struct PicState2 { + /* 0 is master pic, 1 is slave pic */ + /* XXX: better separation between the two pics */ + PicState pics[2]; + IRQRequestFunc *irq_request; + void *irq_request_opaque; +}; #if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT) static int irq_level[16]; @@ -110,7 +116,7 @@ static int pic_get_irq(PicState *s) master, the IRQ coming from the slave is not taken into account for the priority computation. */ mask = s->isr; - if (s->special_fully_nested_mode && s == &pics[0]) + if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) mask &= ~(1 << 2); cur_priority = get_priority(s, mask); if (priority < cur_priority) { @@ -123,32 +129,34 @@ static int pic_get_irq(PicState *s) /* raise irq to CPU if necessary. must be called every time the active irq may change */ -static void pic_update_irq(void) +/* XXX: should not export it, but it is needed for an APIC kludge */ +void pic_update_irq(PicState2 *s) { int irq2, irq; /* first look at slave pic */ - irq2 = pic_get_irq(&pics[1]); + irq2 = pic_get_irq(&s->pics[1]); if (irq2 >= 0) { /* if irq request by slave pic, signal master PIC */ - pic_set_irq1(&pics[0], 2, 1); - pic_set_irq1(&pics[0], 2, 0); + pic_set_irq1(&s->pics[0], 2, 1); + pic_set_irq1(&s->pics[0], 2, 0); } /* look at requested irq */ - irq = pic_get_irq(&pics[0]); + irq = pic_get_irq(&s->pics[0]); if (irq >= 0) { #if defined(DEBUG_PIC) { int i; for(i = 0; i < 2; i++) { printf("pic%d: imr=%x irr=%x padd=%d\n", - i, pics[i].imr, pics[i].irr, pics[i].priority_add); + i, s->pics[i].imr, s->pics[i].irr, + s->pics[i].priority_add); } } printf("pic: cpu_interrupt\n"); #endif - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + s->irq_request(s->irq_request_opaque, 1); } } @@ -156,8 +164,10 @@ static void pic_update_irq(void) int64_t irq_time[16]; #endif -void pic_set_irq(int irq, int level) +void pic_set_irq_new(void *opaque, int irq, int level) { + PicState2 *s = opaque; + #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq]) { #if defined(DEBUG_PIC) @@ -175,14 +185,14 @@ void pic_set_irq(int irq, int level) irq_time[irq] = qemu_get_clock(vm_clock); } #endif - pic_set_irq1(&pics[irq >> 3], irq & 7, level); - pic_update_irq(); + pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); + pic_update_irq(s); } -/* this function should be used to have the controller context */ -void pic_set_irq_new(void *opaque, int irq, int level) +/* obsolete function */ +void pic_set_irq(int irq, int level) { - pic_set_irq(irq, level); + pic_set_irq_new(isa_pic, irq, level); } /* acknowledge interrupt 'irq' */ @@ -199,43 +209,32 @@ static inline void pic_intack(PicState *s, int irq) s->irr &= ~(1 << irq); } -int cpu_get_pic_interrupt(CPUState *env) +int pic_read_irq(PicState2 *s) { int irq, irq2, intno; -#ifdef TARGET_X86_64 - intno = apic_get_interrupt(env); - if (intno >= 0) { - /* set irq request if a PIC irq is still pending */ - /* XXX: improve that */ - pic_update_irq(); - return intno; - } -#endif - /* read the irq from the PIC */ - - irq = pic_get_irq(&pics[0]); + irq = pic_get_irq(&s->pics[0]); if (irq >= 0) { - pic_intack(&pics[0], irq); + pic_intack(&s->pics[0], irq); if (irq == 2) { - irq2 = pic_get_irq(&pics[1]); + irq2 = pic_get_irq(&s->pics[1]); if (irq2 >= 0) { - pic_intack(&pics[1], irq2); + pic_intack(&s->pics[1], irq2); } else { /* spurious IRQ on slave controller */ irq2 = 7; } - intno = pics[1].irq_base + irq2; + intno = s->pics[1].irq_base + irq2; irq = irq2 + 8; } else { - intno = pics[0].irq_base + irq; + intno = s->pics[0].irq_base + irq; } } else { /* spurious IRQ on host controller */ irq = 7; - intno = pics[0].irq_base + irq; + intno = s->pics[0].irq_base + irq; } - pic_update_irq(); + pic_update_irq(s); #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", @@ -251,11 +250,22 @@ int cpu_get_pic_interrupt(CPUState *env) static void pic_reset(void *opaque) { PicState *s = opaque; - int tmp; - tmp = s->elcr_mask; - memset(s, 0, sizeof(PicState)); - s->elcr_mask = tmp; + s->last_irr = 0; + s->irr = 0; + s->imr = 0; + s->isr = 0; + s->priority_add = 0; + s->irq_base = 0; + s->read_reg_select = 0; + s->poll = 0; + s->special_mask = 0; + s->init_state = 0; + s->auto_eoi = 0; + s->rotate_on_auto_eoi = 0; + s->special_fully_nested_mode = 0; + s->init4 = 0; + s->elcr = 0; } static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) @@ -272,8 +282,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* init */ pic_reset(s); /* deassert a pending interrupt */ - cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); - + s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0); s->init_state = 1; s->init4 = val & 1; if (val & 0x02) @@ -302,23 +311,23 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->isr &= ~(1 << irq); if (cmd == 5) s->priority_add = (irq + 1) & 7; - pic_update_irq(); + pic_update_irq(s->pics_state); } break; case 3: irq = val & 7; s->isr &= ~(1 << irq); - pic_update_irq(); + pic_update_irq(s->pics_state); break; case 6: s->priority_add = (val + 1) & 7; - pic_update_irq(); + pic_update_irq(s->pics_state); break; case 7: irq = val & 7; s->isr &= ~(1 << irq); s->priority_add = (irq + 1) & 7; - pic_update_irq(); + pic_update_irq(s->pics_state); break; default: /* no operation */ @@ -330,7 +339,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0: /* normal mode */ s->imr = val; - pic_update_irq(); + pic_update_irq(s->pics_state); break; case 1: s->irq_base = val & 0xf8; @@ -359,16 +368,16 @@ static uint32_t pic_poll_read (PicState *s, uint32_t addr1) ret = pic_get_irq(s); if (ret >= 0) { if (addr1 >> 7) { - pics[0].isr &= ~(1 << 2); - pics[0].irr &= ~(1 << 2); + s->pics_state->pics[0].isr &= ~(1 << 2); + s->pics_state->pics[0].irr &= ~(1 << 2); } s->irr &= ~(1 << ret); s->isr &= ~(1 << ret); if (addr1 >> 7 || ret != 2) - pic_update_irq(); + pic_update_irq(s->pics_state); } else { ret = 0x07; - pic_update_irq(); + pic_update_irq(s->pics_state); } return ret; @@ -402,15 +411,16 @@ static uint32_t pic_ioport_read(void *opaque, uint32_t addr1) } /* memory mapped interrupt status */ -uint32_t pic_intack_read(CPUState *env) +/* XXX: may be the same than pic_read_irq() */ +uint32_t pic_intack_read(PicState2 *s) { int ret; - ret = pic_poll_read(&pics[0], 0x00); + ret = pic_poll_read(&s->pics[0], 0x00); if (ret == 2) - ret = pic_poll_read(&pics[1], 0x80) + 8; + ret = pic_poll_read(&s->pics[1], 0x80) + 8; /* Prepare for ISR read */ - pics[0].read_reg_select = 1; + s->pics[0].read_reg_select = 1; return ret; } @@ -490,9 +500,12 @@ void pic_info(void) { int i; PicState *s; + + if (!isa_pic) + return; for(i=0;i<2;i++) { - s = &pics[i]; + s = &isa_pic->pics[i]; term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", i, s->irr, s->imr, s->isr, s->priority_add, s->irq_base, s->read_reg_select, s->elcr, @@ -517,11 +530,19 @@ void irq_info(void) #endif } -void pic_init(void) +PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque) { - pic_init1(0x20, 0x4d0, &pics[0]); - pic_init1(0xa0, 0x4d1, &pics[1]); - pics[0].elcr_mask = 0xf8; - pics[1].elcr_mask = 0xde; + PicState2 *s; + s = qemu_mallocz(sizeof(PicState2)); + if (!s) + return NULL; + pic_init1(0x20, 0x4d0, &s->pics[0]); + pic_init1(0xa0, 0x4d1, &s->pics[1]); + s->pics[0].elcr_mask = 0xf8; + s->pics[1].elcr_mask = 0xde; + s->irq_request = irq_request; + s->irq_request_opaque = irq_request_opaque; + s->pics[0].pics_state = s; + s->pics[1].pics_state = s; + return s; } - diff --git a/hw/ide.c b/hw/ide.c index 93e01924c..31670a160 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2008,7 +2008,7 @@ void isa_ide_init(int iobase, int iobase2, int irq, if (!ide_state) return; - ide_init2(ide_state, hd0, hd1, pic_set_irq_new, NULL, irq); + ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq); ide_init_ioport(ide_state, iobase, iobase2); } @@ -2337,9 +2337,9 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) PCI_ADDRESS_SPACE_IO, bmdma_map); ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], - pic_set_irq_new, NULL, 14); + pic_set_irq_new, isa_pic, 14); ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], - pic_set_irq_new, NULL, 15); + pic_set_irq_new, isa_pic, 15); ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); ide_init_ioport(&d->ide_if[2], 0x170, 0x376); } diff --git a/hw/pc.c b/hw/pc.c index dac125c09..696c9192c 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -65,6 +65,33 @@ uint64_t cpu_get_tsc(CPUX86State *env) return qemu_get_clock(vm_clock); } +/* IRQ handling */ +int cpu_get_pic_interrupt(CPUState *env) +{ + int intno; + +#ifdef TARGET_X86_64 + intno = apic_get_interrupt(env); + if (intno >= 0) { + /* set irq request if a PIC irq is still pending */ + /* XXX: improve that */ + pic_update_irq(isa_pic); + return intno; + } +#endif + /* read the irq from the PIC */ + intno = pic_read_irq(isa_pic); + return intno; +} + +static void pic_irq_request(void *opaque, int level) +{ + if (level) + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); +} + /* PC cmos mappings */ #define REG_EQUIPMENT_BYTE 0x14 @@ -532,7 +559,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled) apic_init(cpu_single_env); - pic_init(); + isa_pic = pic_init(pic_irq_request, cpu_single_env); pit = pit_init(0x40, 0); for(i = 0; i < MAX_SERIAL_PORTS; i++) { diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index af5799507..cd0283c5b 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -213,6 +213,11 @@ static int vga_osi_call(CPUState *env) return 1; /* osi_call handled */ } +/* XXX: suppress that */ +static void pic_irq_request(void *opaque, int level) +{ +} + /* PowerPC CHRP hardware initialisation */ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, @@ -303,7 +308,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ - pic_init(); + pic_init(pic_irq_request, NULL); /* XXX: use Mac Serial port */ serial_init(0x3f8, 4, serial_hds[0]); @@ -345,7 +350,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ - pic_init(); + pic_init(pic_irq_request, NULL); /* XXX: use Mac Serial port */ serial_init(0x3f8, 4, serial_hds[0]); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 849635f6c..b287c6f91 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -96,6 +96,14 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) return 0; } +static void pic_irq_request(void *opaque, int level) +{ + if (level) + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); +} + /* PCI intack register */ /* Read-only register (?) */ static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value) @@ -108,7 +116,7 @@ static inline uint32_t _PPC_intack_read (target_phys_addr_t addr) uint32_t retval = 0; if (addr == 0xBFFFFFF0) - retval = pic_intack_read(NULL); + retval = pic_intack_read(isa_pic); // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); return retval; @@ -505,8 +513,6 @@ CPUReadMemoryFunc *PPC_prep_io_read[] = { &PPC_prep_io_readl, }; -extern CPUPPCState *global_env; - #define NVRAM_SIZE 0x2000 /* PowerPC PREP hardware initialisation */ @@ -593,8 +599,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, vga_ram_size); rtc_init(0x70, 8); // openpic = openpic_init(0x00000000, 0xF0000000, 1); - // pic_init(openpic); - pic_init(); + isa_pic = pic_init(pic_irq_request, cpu_single_env); // pit = pit_init(0x40, 0); serial_init(0x3f8, 4, serial_hds[0]); diff --git a/vl.c b/vl.c index 86e61c360..13b07c842 100644 --- a/vl.c +++ b/vl.c @@ -155,6 +155,7 @@ int win2k_install_hack = 0; /* x86 ISA bus support */ target_phys_addr_t isa_mem_base = 0; +PicState2 *isa_pic; uint32_t default_ioport_readb(void *opaque, uint32_t address) { diff --git a/vl.h b/vl.h index 64e9777a4..6f6aba75b 100644 --- a/vl.h +++ b/vl.h @@ -469,6 +469,7 @@ typedef struct QEMUMachine { int qemu_register_machine(QEMUMachine *m); typedef void SetIRQFunc(void *opaque, int irq_num, int level); +typedef void IRQRequestFunc(void *opaque, int level); /* ISA bus */ @@ -687,10 +688,14 @@ ParallelState *parallel_init(int base, int irq, CharDriverState *chr); /* i8259.c */ +typedef struct PicState2 PicState2; +extern PicState2 *isa_pic; void pic_set_irq(int irq, int level); void pic_set_irq_new(void *opaque, int irq, int level); -void pic_init(void); -uint32_t pic_intack_read(CPUState *env); +PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque); +int pic_read_irq(PicState2 *s); +void pic_update_irq(PicState2 *s); +uint32_t pic_intack_read(PicState2 *s); void pic_info(void); void irq_info(void); -- cgit v1.2.3 From 2f636b458f6c5e40f8ab2615ae1e8a1cde7e86b8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 20:12:37 +0000 Subject: Cirrus fix (Magnus Damm) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1488 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga_rop2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h index 2f61740e5..da11d0f5e 100644 --- a/hw/cirrus_vga_rop2.h +++ b/hw/cirrus_vga_rop2.h @@ -61,8 +61,8 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) pattern_pitch = 32; #endif pattern_y = s->cirrus_blt_srcaddr & 7; - pattern_x = skipleft; for(y = 0; y < bltheight; y++) { + pattern_x = skipleft; d = dst + skipleft; src1 = src + pattern_y * pattern_pitch; for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) { -- cgit v1.2.3 From 3fc6c082e3aad85addf25d36740030982963c0c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 20:59:34 +0000 Subject: preliminary patch to support more PowerPC CPUs (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1489 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + gdbstub.c | 8 +- hw/ppc_chrp.c | 22 +- hw/ppc_prep.c | 10 +- linux-user/main.c | 23 +- target-ppc/cpu.h | 990 ++++++++++++++++----- target-ppc/exec.h | 24 +- target-ppc/helper.c | 407 ++++++++- target-ppc/op.c | 74 +- target-ppc/op_helper.c | 277 +----- target-ppc/op_template.h | 6 +- target-ppc/translate.c | 1010 +++------------------ target-ppc/translate_init.c | 2069 +++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 3454 insertions(+), 1467 deletions(-) create mode 100644 target-ppc/translate_init.c diff --git a/Makefile.target b/Makefile.target index c2fed5342..59ce7eb49 100644 --- a/Makefile.target +++ b/Makefile.target @@ -468,6 +468,7 @@ endif ifeq ($(TARGET_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) diff --git a/gdbstub.c b/gdbstub.c index 5586df29f..cbae3208c 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -253,14 +253,14 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) } /* nip, msr, ccr, lnk, ctr, xer, mq */ registers[96] = tswapl(env->nip); - registers[97] = tswapl(_load_msr(env)); + registers[97] = tswapl(do_load_msr(env)); tmp = 0; for (i = 0; i < 8; i++) tmp |= env->crf[i] << (32 - ((i + 1) * 4)); registers[98] = tswapl(tmp); registers[99] = tswapl(env->lr); registers[100] = tswapl(env->ctr); - registers[101] = tswapl(_load_xer(env)); + registers[101] = tswapl(do_load_xer(env)); registers[102] = 0; return 103 * 4; @@ -282,13 +282,13 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* nip, msr, ccr, lnk, ctr, xer, mq */ env->nip = tswapl(registers[96]); - _store_msr(env, tswapl(registers[97])); + do_store_msr(env, tswapl(registers[97])); registers[98] = tswapl(registers[98]); for (i = 0; i < 8; i++) env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; env->lr = tswapl(registers[99]); env->ctr = tswapl(registers[100]); - _store_xer(env, tswapl(registers[101])); + do_store_xer(env, tswapl(registers[101])); } #elif defined (TARGET_SPARC) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index cd0283c5b..4437911bd 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -235,6 +235,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, int ret, linux_boot, i; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; + ppc_def_t *def; PCIBus *pci_bus; const char *arch_name; @@ -286,7 +287,26 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, initrd_size = 0; } /* Register CPU as a 74x/75x */ - cpu_ppc_register(cpu_single_env, 0x00080000); + /* XXX: CPU model (or PVR) should be provided on command line */ + // ppc_find_by_name("750gx", &def); // Linux boot OK + // ppc_find_by_name("750fx", &def); // Linux boot OK + /* Linux does not boot on 750cxe (and probably other 750cx based) + * because it assumes it has 8 IBAT & DBAT pairs as it only have 4. + */ + // ppc_find_by_name("750cxe", &def); + // ppc_find_by_name("750p", &def); + // ppc_find_by_name("740p", &def); + ppc_find_by_name("750", &def); + // ppc_find_by_name("740", &def); + // ppc_find_by_name("G3", &def); + // ppc_find_by_name("604r", &def); + // ppc_find_by_name("604e", &def); + // ppc_find_by_name("604", &def); + if (def == NULL) { + cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n"); + } + cpu_ppc_register(cpu_single_env, def); + /* Set time-base frequency to 10 Mhz */ cpu_ppc_tb_init(cpu_single_env, 10UL * 1000UL * 1000UL); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index b287c6f91..141fa1eee 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -527,6 +527,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, int ret, linux_boot, i, nb_nics1; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; + ppc_def_t *def; PCIBus *pci_bus; sysctrl = qemu_mallocz(sizeof(sysctrl_t)); @@ -582,7 +583,14 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, } /* Register CPU as a 604 */ - cpu_ppc_register(cpu_single_env, 0x00040000); + /* XXX: CPU model (or PVR) should be provided on command line */ + // ppc_find_by_name("604r", &def); + // ppc_find_by_name("604e", &def); + ppc_find_by_name("604", &def); + if (def == NULL) { + cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n"); + } + cpu_ppc_register(cpu_single_env, def); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); diff --git a/linux-user/main.c b/linux-user/main.c index 5601a23e6..d8fd0e408 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -700,10 +700,11 @@ void cpu_loop(CPUPPCState *env) info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); case EXCP_DSI: - fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]); + fprintf(stderr, "Invalid data memory access: 0x%08x\n", + env->spr[SPR_DAR]); if (loglevel) { fprintf(logfile, "Invalid data memory access: 0x%08x\n", - env->spr[DAR]); + env->spr[SPR_DAR]); } switch (env->error_code & 0xF) { case EXCP_DSI_TRANSLATE: @@ -1243,7 +1244,25 @@ int main(int argc, char **argv) } #elif defined(TARGET_PPC) { + ppc_def_t *def; int i; + + /* Choose and initialise CPU */ + /* XXX: CPU model (or PVR) should be provided on command line */ + // ppc_find_by_name("750gx", &def); + // ppc_find_by_name("750fx", &def); + // ppc_find_by_name("750p", &def); + ppc_find_by_name("750", &def); + // ppc_find_by_name("G3", &def); + // ppc_find_by_name("604r", &def); + // ppc_find_by_name("604e", &def); + // ppc_find_by_name("604", &def); + if (def == NULL) { + cpu_abort(cpu_single_env, + "Unable to find PowerPC CPU definition\n"); + } + cpu_ppc_register(cpu_single_env, def); + for (i = 0; i < 32; i++) { if (i != 12 && i != 6 && i != 13) env->msr[i] = (regs->msr >> i) & 1; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7df0c6269..a7b4051e1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1,7 +1,7 @@ /* - * PPC emulation cpu definitions for qemu. + * PowerPC emulation cpu definitions for qemu. * - * Copyright (c) 2003 Jocelyn Mayer + * Copyright (c) 2003-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,64 +20,403 @@ #if !defined (__CPU_PPC_H__) #define __CPU_PPC_H__ +#include "config.h" + #define TARGET_LONG_BITS 32 #include "cpu-defs.h" -#include "config.h" #include #include "softfloat.h" #define TARGET_HAS_ICE 1 +/*****************************************************************************/ +/* PVR definitions for most known PowerPC */ +enum { + /* PowerPC 401 cores */ + CPU_PPC_401A1 = 0x00210000, + CPU_PPC_401B2 = 0x00220000, + CPU_PPC_401C2 = 0x00230000, + CPU_PPC_401D2 = 0x00240000, + CPU_PPC_401E2 = 0x00250000, + CPU_PPC_401F2 = 0x00260000, + CPU_PPC_401G2 = 0x00270000, + CPU_PPC_IOP480 = 0x40100000, + /* PowerPC 403 cores */ + CPU_PPC_403GA = 0x00200000, + CPU_PPC_403GB = 0x00200100, + CPU_PPC_403GC = 0x00200200, + CPU_PPC_403GCX = 0x00201400, + /* PowerPC 405 cores */ + CPU_PPC_405 = 0x40110000, + CPU_PPC_405EP = 0x51210000, + CPU_PPC_405GPR = 0x50910000, + CPU_PPC_405D2 = 0x20010000, + CPU_PPC_405D4 = 0x41810000, + CPU_PPC_NPE405H = 0x41410000, + CPU_PPC_NPE405L = 0x41610000, +#if 0 + CPU_PPC_STB02 = xxx, +#endif + CPU_PPC_STB03 = 0x40310000, +#if 0 + CPU_PPC_STB04 = xxx, +#endif + CPU_PPC_STB25 = 0x51510000, +#if 0 + CPU_PPC_STB130 = xxx, +#endif + /* PowerPC 440 cores */ + CPU_PPC_440EP = 0x42220000, + CPU_PPC_440GP = 0x40120400, + CPU_PPC_440GX = 0x51B20000, + /* PowerPC MPC 8xx cores */ + CPU_PPC_8540 = 0x80200000, + CPU_PPC_8xx = 0x00500000, + CPU_PPC_8240 = 0x00810100, + CPU_PPC_8245 = 0x00811014, + /* PowerPC 6xx cores */ + CPU_PPC_601 = 0x00010000, + CPU_PPC_602 = 0x00050000, + CPU_PPC_603 = 0x00030000, + CPU_PPC_603E = 0x00060000, + CPU_PPC_603EV = 0x00070000, + CPU_PPC_603R = 0x00071000, + CPU_PPC_G2 = 0x80810000, + CPU_PPC_G2LE = 0x80820000, + CPU_PPC_604 = 0x00040000, + CPU_PPC_604E = 0x00090000, + CPU_PPC_604R = 0x000a0000, + /* PowerPC 74x/75x cores (aka G3) */ + CPU_PPC_74x = 0x00080000, + CPU_PPC_755 = 0x00083000, + CPU_PPC_74xP = 0x10080000, + CPU_PPC_750CXE22 = 0x00082202, + CPU_PPC_750CXE24 = 0x00082214, + CPU_PPC_750CXE24b = 0x00083214, + CPU_PPC_750CXE31 = 0x00083211, + CPU_PPC_750CXE31b = 0x00083311, +#define CPU_PPC_750CXE CPU_PPC_750CXE31b + CPU_PPC_750FX = 0x70000000, + CPU_PPC_750GX = 0x70020000, + /* PowerPC 74xx cores (aka G4) */ + CPU_PPC_7400 = 0x000C0000, + CPU_PPC_7410 = 0x800C0000, + CPU_PPC_7441 = 0x80000200, + CPU_PPC_7450 = 0x80000000, + CPU_PPC_7451 = 0x80000203, + CPU_PPC_7455 = 0x80010000, + CPU_PPC_7457 = 0x80020000, + CPU_PPC_7457A = 0x80030000, + /* 64 bits PowerPC */ + CPU_PPC_620 = 0x00140000, + CPU_PPC_630 = 0x00400000, + CPU_PPC_631 = 0x00410000, + CPU_PPC_POWER4 = 0x00350000, + CPU_PPC_POWER4P = 0x00380000, + CPU_PPC_POWER5 = 0x003A0000, + CPU_PPC_POWER5P = 0x003B0000, + CPU_PPC_970 = 0x00390000, + CPU_PPC_970FX = 0x003C0000, + CPU_PPC_RS64 = 0x00330000, + CPU_PPC_RS64II = 0x00340000, + CPU_PPC_RS64III = 0x00360000, + CPU_PPC_RS64IV = 0x00370000, + /* Original POWER */ + /* XXX: should be POWER (RIOS), RSC3308, RSC4608, + * POWER2 (RIOS2) & RSC2 (P2SC) here + */ +#if 0 + CPU_POWER = xxx, +#endif +#if 0 + CPU_POWER2 = xxx, +#endif +}; + +/* System version register (used on MPC 8xx) */ +enum { + PPC_SVR_8540 = 0x80300000, + PPC_SVR_8541E = 0x807A0000, + PPC_SVR_8555E = 0x80790000, + PPC_SVR_8560 = 0x80700000, +}; + +/*****************************************************************************/ /* Instruction types */ enum { - PPC_NONE = 0x0000, - PPC_INTEGER = 0x0001, /* CPU has integer operations instructions */ - PPC_FLOAT = 0x0002, /* CPU has floating point operations instructions */ - PPC_FLOW = 0x0004, /* CPU has flow control instructions */ - PPC_MEM = 0x0008, /* CPU has virtual memory instructions */ - PPC_RES = 0x0010, /* CPU has ld/st with reservation instructions */ - PPC_CACHE = 0x0020, /* CPU has cache control instructions */ - PPC_MISC = 0x0040, /* CPU has spr/msr access instructions */ - PPC_EXTERN = 0x0080, /* CPU has external control instructions */ - PPC_SEGMENT = 0x0100, /* CPU has memory segment instructions */ - PPC_CACHE_OPT= 0x0200, - PPC_FLOAT_OPT= 0x0400, - PPC_MEM_OPT = 0x0800, + PPC_NONE = 0x00000000, + /* integer operations instructions */ + /* flow control instructions */ + /* virtual memory instructions */ + /* ld/st with reservation instructions */ + /* cache control instructions */ + /* spr/msr access instructions */ + PPC_INSNS_BASE = 0x00000001, +#define PPC_INTEGER PPC_INSNS_BASE +#define PPC_FLOW PPC_INSNS_BASE +#define PPC_MEM PPC_INSNS_BASE +#define PPC_RES PPC_INSNS_BASE +#define PPC_CACHE PPC_INSNS_BASE +#define PPC_MISC PPC_INSNS_BASE + /* floating point operations instructions */ + PPC_FLOAT = 0x00000002, + /* more floating point operations instructions */ + PPC_FLOAT_EXT = 0x00000004, + /* external control instructions */ + PPC_EXTERN = 0x00000008, + /* segment register access instructions */ + PPC_SEGMENT = 0x00000010, + /* Optional cache control instructions */ + PPC_CACHE_OPT = 0x00000020, + /* Optional floating point op instructions */ + PPC_FLOAT_OPT = 0x00000040, + /* Optional memory control instructions */ + PPC_MEM_TLBIA = 0x00000080, + PPC_MEM_TLBIE = 0x00000100, + PPC_MEM_TLBSYNC = 0x00000200, + /* eieio & sync */ + PPC_MEM_SYNC = 0x00000400, + /* PowerPC 6xx TLB management instructions */ + PPC_6xx_TLB = 0x00000800, + /* Altivec support */ + PPC_ALTIVEC = 0x00001000, + /* Time base support */ + PPC_TB = 0x00002000, + /* Embedded PowerPC dedicated instructions */ + PPC_4xx_COMMON = 0x00004000, + /* PowerPC 40x exception model */ + PPC_40x_EXCP = 0x00008000, + /* PowerPC 40x specific instructions */ + PPC_40x_SPEC = 0x00010000, + /* PowerPC 405 Mac instructions */ + PPC_405_MAC = 0x00020000, + /* PowerPC 440 specific instructions */ + PPC_440_SPEC = 0x00040000, + /* Specific extensions */ + /* Power-to-PowerPC bridge (601) */ + PPC_POWER_BR = 0x00080000, + /* PowerPC 602 specific */ + PPC_602_SPEC = 0x00100000, + /* Deprecated instructions */ + /* Original POWER instruction set */ + PPC_POWER = 0x00200000, + /* POWER2 instruction set extension */ + PPC_POWER2 = 0x00400000, + /* Power RTC support */ + PPC_POWER_RTC = 0x00800000, + /* 64 bits PowerPC instructions */ + /* 64 bits PowerPC instruction set */ + PPC_64B = 0x01000000, + /* 64 bits hypervisor extensions */ + PPC_64H = 0x02000000, + /* 64 bits PowerPC "bridge" features */ + PPC_64_BRIDGE = 0x04000000, }; -#define PPC_COMMON (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ - PPC_RES | PPC_CACHE | PPC_MISC | PPC_SEGMENT) -/* PPC 604 */ -#define PPC_604 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ - PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT \ - PPC_MEM_OPT) -/* PPC 740/745/750/755 (aka G3) has external access instructions */ -#define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ - PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT) +/* CPU run-time flags (MMU and exception model) */ +enum { + /* MMU model */ +#define PPC_FLAGS_MMU_MASK (0x0000000F) + /* Standard 32 bits PowerPC MMU */ + PPC_FLAGS_MMU_32B = 0x00000000, + /* Standard 64 bits PowerPC MMU */ + PPC_FLAGS_MMU_64B = 0x00000001, + /* PowerPC 601 MMU */ + PPC_FLAGS_MMU_601 = 0x00000002, + /* PowerPC 6xx MMU with software TLB */ + PPC_FLAGS_MMU_SOFT_6xx = 0x00000003, + /* PowerPC 4xx MMU with software TLB */ + PPC_FLAGS_MMU_SOFT_4xx = 0x00000004, + /* PowerPC 403 MMU */ + PPC_FLAGS_MMU_403 = 0x00000005, + /* Exception model */ +#define PPC_FLAGS_EXCP_MASK (0x000000F0) + /* Standard PowerPC exception model */ + PPC_FLAGS_EXCP_STD = 0x00000000, + /* PowerPC 40x exception model */ + PPC_FLAGS_EXCP_40x = 0x00000010, + /* PowerPC 601 exception model */ + PPC_FLAGS_EXCP_601 = 0x00000020, + /* PowerPC 602 exception model */ + PPC_FLAGS_EXCP_602 = 0x00000030, + /* PowerPC 603 exception model */ + PPC_FLAGS_EXCP_603 = 0x00000040, + /* PowerPC 604 exception model */ + PPC_FLAGS_EXCP_604 = 0x00000050, + /* PowerPC 7x0 exception model */ + PPC_FLAGS_EXCP_7x0 = 0x00000060, + /* PowerPC 7x5 exception model */ + PPC_FLAGS_EXCP_7x5 = 0x00000070, + /* PowerPC 74xx exception model */ + PPC_FLAGS_EXCP_74xx = 0x00000080, + /* PowerPC 970 exception model */ + PPC_FLAGS_EXCP_970 = 0x00000090, +}; + +#define PPC_MMU(env) (env->flags & PPC_FLAGS_MMU_MASK) +#define PPC_EXCP(env) (env->flags & PPC_FLAGS_EXCP_MASK) + +/*****************************************************************************/ +/* Supported instruction set definitions */ +/* This generates an empty opcode table... */ +#define PPC_INSNS_TODO (PPC_NONE) +#define PPC_FLAGS_TODO (0x00000000) + +/* PowerPC 40x instruction set */ +#define PPC_INSNS_4xx (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_4xx_COMMON) +/* PowerPC 401 */ +#define PPC_INSNS_401 (PPC_INSNS_TODO) +#define PPC_FLAGS_401 (PPC_FLAGS_TODO) +/* PowerPC 403 */ +#define PPC_INSNS_403 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_MEM_TLBIA | \ + PPC_40x_EXCP | PPC_40x_SPEC) +#define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x) +/* PowerPC 405 */ +#define PPC_INSNS_405 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_CACHE_OPT | \ + PPC_MEM_TLBIA | PPC_TB | PPC_40x_SPEC | PPC_40x_EXCP | \ + PPC_405_MAC) +#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x) +/* PowerPC 440 */ +#define PPC_INSNS_440 (PPC_INSNS_4xx | PPC_CACHE_OPT | PPC_405_MAC | \ + PPC_440_SPEC) +#define PPC_FLAGS_440 (PPC_FLAGS_TODO) +/* Non-embedded PowerPC */ +#define PPC_INSNS_COMMON (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \ + PPC_SEGMENT | PPC_MEM_TLBIE) +/* PowerPC 601 */ +#define PPC_INSNS_601 (PPC_INSNS_COMMON | PPC_EXTERN | PPC_POWER_BR) +#define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601) +/* PowerPC 602 */ +#define PPC_INSNS_602 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ + PPC_MEM_TLBSYNC | PPC_TB) +#define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602) +/* PowerPC 603 */ +#define PPC_INSNS_603 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ + PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB) +#define PPC_FLAGS_603 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603) +/* PowerPC G2 */ +#define PPC_INSNS_G2 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ + PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB) +#define PPC_FLAGS_G2 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603) +/* PowerPC 604 */ +#define PPC_INSNS_604 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ + PPC_MEM_TLBSYNC | PPC_TB) +#define PPC_FLAGS_604 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_604) +/* PowerPC 740/750 (aka G3) */ +#define PPC_INSNS_7x0 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ + PPC_MEM_TLBSYNC | PPC_TB) +#define PPC_FLAGS_7x0 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_7x0) +/* PowerPC 745/755 */ +#define PPC_INSNS_7x5 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ + PPC_MEM_TLBSYNC | PPC_TB | PPC_6xx_TLB) +#define PPC_FLAGS_7x5 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_7x5) +/* PowerPC 74xx (aka G4) */ +#define PPC_INSNS_74xx (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_ALTIVEC | \ + PPC_MEM_TLBSYNC | PPC_TB) +#define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx) + +/* Default PowerPC will be 604/970 */ +#define PPC_INSNS_PPC32 PPC_INSNS_604 +#define PPC_FLAGS_PPC32 PPC_FLAGS_604 +#if 0 +#define PPC_INSNS_PPC64 PPC_INSNS_970 +#define PPC_FLAGS_PPC64 PPC_FLAGS_970 +#endif +#define PPC_INSNS_DEFAULT PPC_INSNS_604 +#define PPC_FLAGS_DEFAULT PPC_FLAGS_604 +typedef struct ppc_def_t ppc_def_t; +/*****************************************************************************/ +/* Types used to describe some PowerPC registers */ +typedef struct CPUPPCState CPUPPCState; +typedef struct opc_handler_t opc_handler_t; typedef struct ppc_tb_t ppc_tb_t; +typedef struct ppc_spr_t ppc_spr_t; +typedef struct ppc_dcr_t ppc_dcr_t; +typedef struct ppc_avr_t ppc_avr_t; + +/* SPR access micro-ops generations callbacks */ +struct ppc_spr_t { + void (*uea_read)(void *opaque, int spr_num); + void (*uea_write)(void *opaque, int spr_num); + void (*oea_read)(void *opaque, int spr_num); + void (*oea_write)(void *opaque, int spr_num); + const unsigned char *name; +}; + +/* Altivec registers (128 bits) */ +struct ppc_avr_t { + uint32_t u[4]; +}; -/* Supervisor mode registers */ -/* Machine state register */ -#define MSR_POW 18 -#define MSR_ILE 16 -#define MSR_EE 15 -#define MSR_PR 14 -#define MSR_FP 13 -#define MSR_ME 12 -#define MSR_FE0 11 -#define MSR_SE 10 -#define MSR_BE 9 -#define MSR_FE1 8 -#define MSR_IP 6 -#define MSR_IR 5 -#define MSR_DR 4 -#define MSR_RI 1 -#define MSR_LE 0 +/* Software TLB cache */ +typedef struct ppc_tlb_t ppc_tlb_t; +struct ppc_tlb_t { + /* Physical page number */ + target_phys_addr_t RPN; + /* Virtual page number */ + target_ulong VPN; + /* Page size */ + target_ulong size; + /* Protection bits */ + int prot; + int is_user; + uint32_t private; + uint32_t flags; +}; + +/*****************************************************************************/ +/* Machine state register bits definition */ +#define MSR_SF 63 /* Sixty-four-bit mode */ +#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */ +#define MSR_HV 60 /* hypervisor state */ +#define MSR_VR 25 /* altivec available */ +#define MSR_AP 23 /* Access privilege state on 602 */ +#define MSR_SA 22 /* Supervisor access mode on 602 */ +#define MSR_KEY 19 /* key bit on 603e */ +#define MSR_POW 18 /* Power management */ +#define MSR_WE 18 /* Wait state enable on embedded PowerPC */ +#define MSR_TGPR 17 /* TGPR usage on 602/603 */ +#define MSR_TLB 17 /* TLB on ? */ +#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC */ +#define MSR_ILE 16 /* Interrupt little-endian mode */ +#define MSR_EE 15 /* External interrupt enable */ +#define MSR_PR 14 /* Problem state */ +#define MSR_FP 13 /* Floating point available */ +#define MSR_ME 12 /* Machine check interrupt enable */ +#define MSR_FE0 11 /* Floating point exception mode 0 */ +#define MSR_SE 10 /* Single-step trace enable */ +#define MSR_DWE 10 /* Debug wait enable on 405 */ +#define MSR_BE 9 /* Branch trace enable */ +#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC */ +#define MSR_FE1 8 /* Floating point exception mode 1 */ +#define MSR_AL 7 /* AL bit on POWER */ +#define MSR_IP 6 /* Interrupt prefix */ +#define MSR_IR 5 /* Instruction relocate */ +#define MSR_IS 5 /* Instruction address space on embedded PowerPC */ +#define MSR_DR 4 /* Data relocate */ +#define MSR_DS 4 /* Data address space on embedded PowerPC */ +#define MSR_PE 3 /* Protection enable on 403 */ +#define MSR_EP 3 /* Exception prefix on 601 */ +#define MSR_PX 2 /* Protection exclusive on 403 */ +#define MSR_PMM 2 /* Performance monitor mark on POWER */ +#define MSR_RI 1 /* Recoverable interrupt */ +#define MSR_LE 0 /* Little-endian mode */ +#define msr_sf env->msr[MSR_SF] +#define msr_isf env->msr[MSR_ISF] +#define msr_hv env->msr[MSR_HV] +#define msr_vr env->msr[MSR_VR] +#define msr_ap env->msr[MSR_AP] +#define msr_sa env->msr[MSR_SA] +#define msr_key env->msr[MSR_KEY] #define msr_pow env->msr[MSR_POW] +#define msr_we env->msr[MSR_WE] +#define msr_tgpr env->msr[MSR_TGPR] +#define msr_tlb env->msr[MSR_TLB] +#define msr_ce env->msr[MSR_CE] #define msr_ile env->msr[MSR_ILE] #define msr_ee env->msr[MSR_EE] #define msr_pr env->msr[MSR_PR] @@ -85,58 +424,72 @@ typedef struct ppc_tb_t ppc_tb_t; #define msr_me env->msr[MSR_ME] #define msr_fe0 env->msr[MSR_FE0] #define msr_se env->msr[MSR_SE] +#define msr_dwe env->msr[MSR_DWE] #define msr_be env->msr[MSR_BE] +#define msr_de env->msr[MSR_DE] #define msr_fe1 env->msr[MSR_FE1] +#define msr_al env->msr[MSR_AL] #define msr_ip env->msr[MSR_IP] #define msr_ir env->msr[MSR_IR] +#define msr_is env->msr[MSR_IS] #define msr_dr env->msr[MSR_DR] +#define msr_ds env->msr[MSR_DS] +#define msr_pe env->msr[MSR_PE] +#define msr_ep env->msr[MSR_EP] +#define msr_px env->msr[MSR_PX] +#define msr_pmm env->msr[MSR_PMM] #define msr_ri env->msr[MSR_RI] #define msr_le env->msr[MSR_LE] -/* Segment registers */ -typedef struct CPUPPCState { +/*****************************************************************************/ +/* The whole PowerPC CPU context */ +struct CPUPPCState { + /* First are the most commonly used resources + * during translated code execution + */ +#if TARGET_LONG_BITS > HOST_LONG_BITS + /* temporary fixed-point registers + * used to emulate 64 bits target on 32 bits hosts + */ + target_ulong t0, t1, t2; +#endif /* general purpose registers */ - uint32_t gpr[32]; - /* floating point registers */ - float64 fpr[32]; - /* segment registers */ - uint32_t sdr1; - uint32_t sr[16]; + target_ulong gpr[32]; + /* LR */ + target_ulong lr; + /* CTR */ + target_ulong ctr; + /* condition register */ + uint8_t crf[8]; /* XER */ - uint8_t xer[4]; + /* XXX: We use only 5 fields, but we want to keep the structure aligned */ + uint8_t xer[8]; /* Reservation address */ - uint32_t reserve; + target_ulong reserve; + + /* Those ones are used in supervisor mode only */ /* machine state register */ - uint8_t msr[32]; - /* condition register */ - uint8_t crf[8]; - /* floating point status and control register */ - uint8_t fpscr[8]; - uint32_t nip; - /* special purpose registers */ - uint32_t lr; - uint32_t ctr; - /* BATs */ - uint32_t DBAT[2][8]; - uint32_t IBAT[2][8]; - /* all others */ - uint32_t spr[1024]; - /* qemu dedicated */ + uint8_t msr[64]; + /* temporary general purpose registers */ + target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */ + + /* Floating point execution context */ /* temporary float registers */ float64 ft0; float64 ft1; float64 ft2; float_status fp_status; + /* floating point registers */ + float64 fpr[32]; + /* floating point status and control register */ + uint8_t fpscr[8]; - int interrupt_request; - jmp_buf jmp_env; - int exception_index; - int error_code; + /* soft mmu support */ + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; int access_type; /* when a memory exception occurs, the access type is stored here */ - int user_mode_only; /* user mode only simulation */ - 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) */ @@ -144,17 +497,71 @@ typedef struct CPUPPCState { written */ unsigned long mem_write_vaddr; /* target virtual addr at which the memory was written */ - /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ - CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; - /* ice debug support */ - uint32_t breakpoints[MAX_BREAKPOINTS]; - int nb_breakpoints; - int singlestep_enabled; /* XXX: should use CPU single step mode instead */ + /* MMU context */ + /* Address space register */ + target_ulong asr; + /* segment registers */ + target_ulong sdr1; + target_ulong sr[16]; + /* BATs */ + int nb_BATs; + target_ulong DBAT[2][8]; + target_ulong IBAT[2][8]; + /* Other registers */ + /* Special purpose registers */ + target_ulong spr[1024]; + /* Altivec registers */ + ppc_avr_t avr[32]; + uint32_t vscr; + + /* Internal devices resources */ /* Time base and decrementer */ ppc_tb_t *tb_env; + /* Device control registers */ + int (*dcr_read)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong *val); + int (*dcr_write)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong val); + ppc_dcr_t *dcr_env; + + /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */ + int nb_tlb; + int nb_ways, last_way; + ppc_tlb_t tlb[128]; + /* Callbacks for specific checks on some implementations */ + int (*tlb_check_more)(CPUPPCState *env, struct ppc_tlb_t *tlb, int *prot, + target_ulong vaddr, int rw, int acc_type, + int is_user); + /* 403 dedicated access protection registers */ + target_ulong pb[4]; + + /* Those resources are used during exception processing */ + /* CPU model definition */ + uint64_t msr_mask; + uint32_t flags; + + int exception_index; + int error_code; + int interrupt_request; + + /* Those resources are used only during code translation */ + /* Next instruction pointer */ + target_ulong nip; + /* SPR translation callbacks */ + ppc_spr_t spr_cb[1024]; + /* opcode handlers */ + opc_handler_t *opcodes[0x40]; + + /* Those resources are used only in Qemu core */ + jmp_buf jmp_env; + int user_mode_only; /* user mode only simulation */ + struct TranslationBlock *current_tb; /* currently executing TB */ + uint32_t hflags; + + /* ice debug support */ + target_ulong breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; + int singlestep_enabled; /* XXX: should use CPU single step mode instead */ /* Power management */ int power_mode; @@ -164,8 +571,9 @@ typedef struct CPUPPCState { /* user data */ void *opaque; -} CPUPPCState; +}; +/*****************************************************************************/ CPUPPCState *cpu_ppc_init(void); int cpu_ppc_exec(CPUPPCState *s); void cpu_ppc_close(CPUPPCState *s); @@ -181,12 +589,38 @@ void cpu_loop_exit(void); void dump_stack (CPUPPCState *env); -uint32_t _load_xer (CPUPPCState *env); -void _store_xer (CPUPPCState *env, uint32_t value); -uint32_t _load_msr (CPUPPCState *env); -void _store_msr (CPUPPCState *env, uint32_t value); +target_ulong do_load_ibatu (CPUPPCState *env, int nr); +target_ulong do_load_ibatl (CPUPPCState *env, int nr); +void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value); +void do_store_ibatl (CPUPPCState *env, int nr, target_ulong value); +target_ulong do_load_dbatu (CPUPPCState *env, int nr); +target_ulong do_load_dbatl (CPUPPCState *env, int nr); +void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value); +void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value); + +target_ulong do_load_nip (CPUPPCState *env); +void do_store_nip (CPUPPCState *env, target_ulong value); +target_ulong do_load_sdr1 (CPUPPCState *env); +void do_store_sdr1 (CPUPPCState *env, target_ulong value); +target_ulong do_load_asr (CPUPPCState *env); +void do_store_asr (CPUPPCState *env, target_ulong value); +target_ulong do_load_sr (CPUPPCState *env, int srnum); +void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); +uint32_t do_load_cr (CPUPPCState *env); +void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask); +uint32_t do_load_xer (CPUPPCState *env); +void do_store_xer (CPUPPCState *env, uint32_t value); +target_ulong do_load_msr (CPUPPCState *env); +void do_store_msr (CPUPPCState *env, target_ulong value); +float64 do_load_fpscr (CPUPPCState *env); +void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask); + +void do_compute_hflags (CPUPPCState *env); -int cpu_ppc_register (CPUPPCState *env, uint32_t pvr); +int ppc_find_by_name (const unsigned char *name, ppc_def_t **def); +int ppc_find_by_pvr (uint32_t apvr, ppc_def_t **def); +void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def); /* Time-base and decrementer management */ #ifndef NO_CPU_IO_DEFS @@ -201,132 +635,276 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" +/*****************************************************************************/ +/* Registers definitions */ #define ugpr(n) (env->gpr[n]) -#define fprd(n) (env->fpr[n]) -#define fprs(n) ((float)env->fpr[n]) -#define fpru(n) ((uint32_t)env->fpr[n]) -#define fpri(n) ((int32_t)env->fpr[n]) - -#define SPR_ENCODE(sprn) \ -(((sprn) >> 5) | (((sprn) & 0x1F) << 5)) -/* User mode SPR */ -#define spr(n) env->spr[n] #define XER_SO 31 #define XER_OV 30 #define XER_CA 29 +#define XER_CMP 8 #define XER_BC 0 -#define xer_so env->xer[3] -#define xer_ov env->xer[2] -#define xer_ca env->xer[1] +#define xer_so env->xer[4] +#define xer_ov env->xer[6] +#define xer_ca env->xer[2] +#define xer_cmp env->xer[1] #define xer_bc env->xer[0] -#define MQ SPR_ENCODE(0) -#define XER SPR_ENCODE(1) -#define RTCUR SPR_ENCODE(4) -#define RTCLR SPR_ENCODE(5) -#define LR SPR_ENCODE(8) -#define CTR SPR_ENCODE(9) -/* VEA mode SPR */ -#define V_TBL SPR_ENCODE(268) -#define V_TBU SPR_ENCODE(269) -/* supervisor mode SPR */ -#define DSISR SPR_ENCODE(18) -#define DAR SPR_ENCODE(19) -#define RTCUW SPR_ENCODE(20) -#define RTCLW SPR_ENCODE(21) -#define DECR SPR_ENCODE(22) -#define SDR1 SPR_ENCODE(25) -#define SRR0 SPR_ENCODE(26) -#define SRR1 SPR_ENCODE(27) -#define SPRG0 SPR_ENCODE(272) -#define SPRG1 SPR_ENCODE(273) -#define SPRG2 SPR_ENCODE(274) -#define SPRG3 SPR_ENCODE(275) -#define SPRG4 SPR_ENCODE(276) -#define SPRG5 SPR_ENCODE(277) -#define SPRG6 SPR_ENCODE(278) -#define SPRG7 SPR_ENCODE(279) -#define ASR SPR_ENCODE(280) -#define EAR SPR_ENCODE(282) -#define O_TBL SPR_ENCODE(284) -#define O_TBU SPR_ENCODE(285) -#define PVR SPR_ENCODE(287) -#define IBAT0U SPR_ENCODE(528) -#define IBAT0L SPR_ENCODE(529) -#define IBAT1U SPR_ENCODE(530) -#define IBAT1L SPR_ENCODE(531) -#define IBAT2U SPR_ENCODE(532) -#define IBAT2L SPR_ENCODE(533) -#define IBAT3U SPR_ENCODE(534) -#define IBAT3L SPR_ENCODE(535) -#define DBAT0U SPR_ENCODE(536) -#define DBAT0L SPR_ENCODE(537) -#define DBAT1U SPR_ENCODE(538) -#define DBAT1L SPR_ENCODE(539) -#define DBAT2U SPR_ENCODE(540) -#define DBAT2L SPR_ENCODE(541) -#define DBAT3U SPR_ENCODE(542) -#define DBAT3L SPR_ENCODE(543) -#define IBAT4U SPR_ENCODE(560) -#define IBAT4L SPR_ENCODE(561) -#define IBAT5U SPR_ENCODE(562) -#define IBAT5L SPR_ENCODE(563) -#define IBAT6U SPR_ENCODE(564) -#define IBAT6L SPR_ENCODE(565) -#define IBAT7U SPR_ENCODE(566) -#define IBAT7L SPR_ENCODE(567) -#define DBAT4U SPR_ENCODE(568) -#define DBAT4L SPR_ENCODE(569) -#define DBAT5U SPR_ENCODE(570) -#define DBAT5L SPR_ENCODE(571) -#define DBAT6U SPR_ENCODE(572) -#define DBAT6L SPR_ENCODE(573) -#define DBAT7U SPR_ENCODE(574) -#define DBAT7L SPR_ENCODE(575) -#define UMMCR0 SPR_ENCODE(936) -#define UPMC1 SPR_ENCODE(937) -#define UPMC2 SPR_ENCODE(938) -#define USIA SPR_ENCODE(939) -#define UMMCR1 SPR_ENCODE(940) -#define UPMC3 SPR_ENCODE(941) -#define UPMC4 SPR_ENCODE(942) -#define MMCR0 SPR_ENCODE(952) -#define PMC1 SPR_ENCODE(953) -#define PMC2 SPR_ENCODE(954) -#define SIA SPR_ENCODE(955) -#define MMCR1 SPR_ENCODE(956) -#define PMC3 SPR_ENCODE(957) -#define PMC4 SPR_ENCODE(958) -#define SDA SPR_ENCODE(959) -#define DMISS SPR_ENCODE(976) -#define DCMP SPR_ENCODE(977) -#define DHASH1 SPR_ENCODE(978) -#define DHASH2 SPR_ENCODE(979) -#define IMISS SPR_ENCODE(980) -#define ICMP SPR_ENCODE(981) -#define RPA SPR_ENCODE(982) -#define TCR SPR_ENCODE(984) -#define IBR SPR_ENCODE(986) -#define ESASRR SPR_ENCODE(987) -#define SEBR SPR_ENCODE(990) -#define SER SPR_ENCODE(991) -#define HID0 SPR_ENCODE(1008) -#define HID1 SPR_ENCODE(1009) -#define IABR SPR_ENCODE(1010) -#define HID2 SPR_ENCODE(1011) -#define DABR SPR_ENCODE(1013) -#define L2PM SPR_ENCODE(1016) -#define L2CR SPR_ENCODE(1017) -#define ICTC SPR_ENCODE(1019) -#define THRM1 SPR_ENCODE(1020) -#define THRM2 SPR_ENCODE(1021) -#define THRM3 SPR_ENCODE(1022) -#define SP SPR_ENCODE(1021) -#define SPR_LP SPR_ENCODE(1022) -#define DABR_MASK 0xFFFFFFF8 -#define FPECR SPR_ENCODE(1022) -#define PIR SPR_ENCODE(1023) +/* SPR definitions */ +#define SPR_MQ (0x000) +#define SPR_XER (0x001) +#define SPR_601_VRTCU (0x004) +#define SPR_601_VRTCL (0x005) +#define SPR_601_UDECR (0x006) +#define SPR_LR (0x008) +#define SPR_CTR (0x009) +#define SPR_DSISR (0x012) +#define SPR_DAR (0x013) +#define SPR_601_RTCU (0x014) +#define SPR_601_RTCL (0x015) +#define SPR_DECR (0x016) +#define SPR_SDR1 (0x019) +#define SPR_SRR0 (0x01A) +#define SPR_SRR1 (0x01B) +#define SPR_440_PID (0x030) +#define SPR_440_DECAR (0x036) +#define SPR_CSRR0 (0x03A) +#define SPR_CSRR1 (0x03B) +#define SPR_440_DEAR (0x03D) +#define SPR_440_ESR (0x03E) +#define SPR_440_IVPR (0x03F) +#define SPR_8xx_EIE (0x050) +#define SPR_8xx_EID (0x051) +#define SPR_8xx_NRE (0x052) +#define SPR_58x_CMPA (0x090) +#define SPR_58x_CMPB (0x091) +#define SPR_58x_CMPC (0x092) +#define SPR_58x_CMPD (0x093) +#define SPR_58x_ICR (0x094) +#define SPR_58x_DER (0x094) +#define SPR_58x_COUNTA (0x096) +#define SPR_58x_COUNTB (0x097) +#define SPR_58x_CMPE (0x098) +#define SPR_58x_CMPF (0x099) +#define SPR_58x_CMPG (0x09A) +#define SPR_58x_CMPH (0x09B) +#define SPR_58x_LCTRL1 (0x09C) +#define SPR_58x_LCTRL2 (0x09D) +#define SPR_58x_ICTRL (0x09E) +#define SPR_58x_BAR (0x09F) +#define SPR_VRSAVE (0x100) +#define SPR_USPRG0 (0x100) +#define SPR_USPRG4 (0x104) +#define SPR_USPRG5 (0x105) +#define SPR_USPRG6 (0x106) +#define SPR_USPRG7 (0x107) +#define SPR_VTBL (0x10C) +#define SPR_VTBU (0x10D) +#define SPR_SPRG0 (0x110) +#define SPR_SPRG1 (0x111) +#define SPR_SPRG2 (0x112) +#define SPR_SPRG3 (0x113) +#define SPR_SPRG4 (0x114) +#define SPR_SCOMC (0x114) +#define SPR_SPRG5 (0x115) +#define SPR_SCOMD (0x115) +#define SPR_SPRG6 (0x116) +#define SPR_SPRG7 (0x117) +#define SPR_ASR (0x118) +#define SPR_EAR (0x11A) +#define SPR_TBL (0x11C) +#define SPR_TBU (0x11D) +#define SPR_SVR (0x11E) +#define SPR_440_PIR (0x11E) +#define SPR_PVR (0x11F) +#define SPR_HSPRG0 (0x130) +#define SPR_440_DBSR (0x130) +#define SPR_HSPRG1 (0x131) +#define SPR_440_DBCR0 (0x134) +#define SPR_IBCR (0x135) +#define SPR_440_DBCR1 (0x135) +#define SPR_DBCR (0x136) +#define SPR_HDEC (0x136) +#define SPR_440_DBCR2 (0x136) +#define SPR_HIOR (0x137) +#define SPR_MBAR (0x137) +#define SPR_RMOR (0x138) +#define SPR_440_IAC1 (0x138) +#define SPR_HRMOR (0x139) +#define SPR_440_IAC2 (0x139) +#define SPR_HSSR0 (0x13A) +#define SPR_440_IAC3 (0x13A) +#define SPR_HSSR1 (0x13B) +#define SPR_440_IAC4 (0x13B) +#define SPR_LPCR (0x13C) +#define SPR_440_DAC1 (0x13C) +#define SPR_LPIDR (0x13D) +#define SPR_DABR2 (0x13D) +#define SPR_440_DAC2 (0x13D) +#define SPR_440_DVC1 (0x13E) +#define SPR_440_DVC2 (0x13F) +#define SPR_440_TSR (0x150) +#define SPR_440_TCR (0x154) +#define SPR_440_IVOR0 (0x190) +#define SPR_440_IVOR1 (0x191) +#define SPR_440_IVOR2 (0x192) +#define SPR_440_IVOR3 (0x193) +#define SPR_440_IVOR4 (0x194) +#define SPR_440_IVOR5 (0x195) +#define SPR_440_IVOR6 (0x196) +#define SPR_440_IVOR7 (0x197) +#define SPR_440_IVOR8 (0x198) +#define SPR_440_IVOR9 (0x199) +#define SPR_440_IVOR10 (0x19A) +#define SPR_440_IVOR11 (0x19B) +#define SPR_440_IVOR12 (0x19C) +#define SPR_440_IVOR13 (0x19D) +#define SPR_440_IVOR14 (0x19E) +#define SPR_440_IVOR15 (0x19F) +#define SPR_IBAT0U (0x210) +#define SPR_IBAT0L (0x211) +#define SPR_IBAT1U (0x212) +#define SPR_IBAT1L (0x213) +#define SPR_IBAT2U (0x214) +#define SPR_IBAT2L (0x215) +#define SPR_IBAT3U (0x216) +#define SPR_IBAT3L (0x217) +#define SPR_DBAT0U (0x218) +#define SPR_DBAT0L (0x219) +#define SPR_DBAT1U (0x21A) +#define SPR_DBAT1L (0x21B) +#define SPR_DBAT2U (0x21C) +#define SPR_DBAT2L (0x21D) +#define SPR_DBAT3U (0x21E) +#define SPR_DBAT3L (0x21F) +#define SPR_IBAT4U (0x230) +#define SPR_IBAT4L (0x231) +#define SPR_IBAT5U (0x232) +#define SPR_IBAT5L (0x233) +#define SPR_IBAT6U (0x234) +#define SPR_IBAT6L (0x235) +#define SPR_IBAT7U (0x236) +#define SPR_IBAT7L (0x237) +#define SPR_DBAT4U (0x238) +#define SPR_DBAT4L (0x239) +#define SPR_DBAT5U (0x23A) +#define SPR_DBAT5L (0x23B) +#define SPR_DBAT6U (0x23C) +#define SPR_DBAT6L (0x23D) +#define SPR_DBAT7U (0x23E) +#define SPR_DBAT7L (0x23F) +#define SPR_440_INV0 (0x370) +#define SPR_440_INV1 (0x371) +#define SPR_440_INV2 (0x372) +#define SPR_440_INV3 (0x373) +#define SPR_440_IVT0 (0x374) +#define SPR_440_IVT1 (0x375) +#define SPR_440_IVT2 (0x376) +#define SPR_440_IVT3 (0x377) +#define SPR_440_DNV0 (0x390) +#define SPR_440_DNV1 (0x391) +#define SPR_440_DNV2 (0x392) +#define SPR_440_DNV3 (0x393) +#define SPR_440_DVT0 (0x394) +#define SPR_440_DVT1 (0x395) +#define SPR_440_DVT2 (0x396) +#define SPR_440_DVT3 (0x397) +#define SPR_440_DVLIM (0x398) +#define SPR_440_IVLIM (0x399) +#define SPR_440_RSTCFG (0x39B) +#define SPR_440_DCBTRL (0x39C) +#define SPR_440_DCBTRH (0x39D) +#define SPR_440_ICBTRL (0x39E) +#define SPR_440_ICBTRH (0x39F) +#define SPR_UMMCR0 (0x3A8) +#define SPR_UPMC1 (0x3A9) +#define SPR_UPMC2 (0x3AA) +#define SPR_USIA (0x3AB) +#define SPR_UMMCR1 (0x3AC) +#define SPR_UPMC3 (0x3AD) +#define SPR_UPMC4 (0x3AE) +#define SPR_USDA (0x3AF) +#define SPR_40x_ZPR (0x3B0) +#define SPR_40x_PID (0x3B1) +#define SPR_440_MMUCR (0x3B2) +#define SPR_4xx_CCR0 (0x3B3) +#define SPR_405_IAC3 (0x3B4) +#define SPR_405_IAC4 (0x3B5) +#define SPR_405_DVC1 (0x3B6) +#define SPR_405_DVC2 (0x3B7) +#define SPR_MMCR0 (0x3B8) +#define SPR_PMC1 (0x3B9) +#define SPR_40x_SGR (0x3B9) +#define SPR_PMC2 (0x3BA) +#define SPR_40x_DCWR (0x3BA) +#define SPR_SIA (0x3BB) +#define SPR_405_SLER (0x3BB) +#define SPR_MMCR1 (0x3BC) +#define SPR_405_SU0R (0x3BC) +#define SPR_PMC3 (0x3BD) +#define SPR_405_DBCR1 (0x3BD) +#define SPR_PMC4 (0x3BE) +#define SPR_SDA (0x3BF) +#define SPR_403_VTBL (0x3CC) +#define SPR_403_VTBU (0x3CD) +#define SPR_DMISS (0x3D0) +#define SPR_DCMP (0x3D1) +#define SPR_DHASH1 (0x3D2) +#define SPR_DHASH2 (0x3D3) +#define SPR_4xx_ICDBDR (0x3D3) +#define SPR_IMISS (0x3D4) +#define SPR_40x_ESR (0x3D4) +#define SPR_ICMP (0x3D5) +#define SPR_40x_DEAR (0x3D5) +#define SPR_RPA (0x3D6) +#define SPR_40x_EVPR (0x3D6) +#define SPR_403_CDBCR (0x3D7) +#define SPR_TCR (0x3D8) +#define SPR_40x_TSR (0x3D8) +#define SPR_IBR (0x3DA) +#define SPR_40x_TCR (0x3DA) +#define SPR_ESASR (0x3DB) +#define SPR_40x_PIT (0x3DB) +#define SPR_403_TBL (0x3DC) +#define SPR_403_TBU (0x3DD) +#define SPR_SEBR (0x3DE) +#define SPR_40x_SRR2 (0x3DE) +#define SPR_SER (0x3DF) +#define SPR_40x_SRR3 (0x3DF) +#define SPR_HID0 (0x3F0) +#define SPR_40x_DBSR (0x3F0) +#define SPR_HID1 (0x3F1) +#define SPR_IABR (0x3F2) +#define SPR_40x_DBCR0 (0x3F2) +#define SPR_601_HID2 (0x3F2) +#define SPR_HID2 (0x3F3) +#define SPR_440_DBDR (0x3F3) +#define SPR_40x_IAC1 (0x3F4) +#define SPR_DABR (0x3F5) +#define DABR_MASK (~(target_ulong)0x7) +#define SPR_40x_IAC2 (0x3F5) +#define SPR_601_HID5 (0x3F5) +#define SPR_40x_DAC1 (0x3F6) +#define SPR_40x_DAC2 (0x3F7) +#define SPR_L2PM (0x3F8) +#define SPR_750_HID2 (0x3F8) +#define SPR_L2CR (0x3F9) +#define SPR_IABR2 (0x3FA) +#define SPR_40x_DCCR (0x3FA) +#define SPR_ICTC (0x3FB) +#define SPR_40x_ICCR (0x3FB) +#define SPR_THRM1 (0x3FC) +#define SPR_403_PBL1 (0x3FC) +#define SPR_SP (0x3FD) +#define SPR_THRM2 (0x3FD) +#define SPR_403_PBU1 (0x3FD) +#define SPR_LT (0x3FE) +#define SPR_THRM3 (0x3FE) +#define SPR_FPECR (0x3FE) +#define SPR_403_PBL2 (0x3FE) +#define SPR_PIR (0x3FF) +#define SPR_403_PBU2 (0x3FF) +#define SPR_601_HID15 (0x3FF) /* Memory access type : * may be needed for precise access rights control and precise exceptions. @@ -348,7 +926,7 @@ enum { /* Exceptions */ enum { EXCP_NONE = -1, - /* PPC hardware exceptions : exception vector / 0x100 */ + /* PowerPC hardware exceptions : exception vector / 0x100 */ EXCP_RESET = 0x01, /* System reset */ EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */ EXCP_DSI = 0x03, /* Impossible memory access */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index ad21c5669..e559d5c8c 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -1,7 +1,7 @@ /* - * PPC emulation definitions for qemu. + * PowerPC emulation definitions for qemu. * - * Copyright (c) 2003 Jocelyn Mayer + * Copyright (c) 2003-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -119,15 +119,6 @@ static inline uint32_t rotl (uint32_t i, int n) void do_raise_exception_err (uint32_t exception, int error_code); void do_raise_exception (uint32_t exception); -void do_load_cr (void); -void do_store_cr (uint32_t mask); -void do_load_xer (void); -void do_store_xer (void); -void do_load_msr (void); -void do_store_msr (void); -void do_load_fpscr (void); -void do_store_fpscr (uint32_t mask); - void do_sraw(void); void do_fctiw (void); @@ -143,20 +134,9 @@ void do_fcmpo (void); void do_check_reservation (void); void do_icbi (void); -void do_store_sr (uint32_t srnum); -void do_store_ibat (int ul, int nr); -void do_store_dbat (int ul, int nr); void do_tlbia (void); void do_tlbie (void); -void dump_state (void); -void dump_rfi (void); -void dump_store_sr (int srnum); -void dump_store_ibat (int ul, int nr); -void dump_store_dbat (int ul, int nr); -void dump_store_tb (int ul); -void dump_update_tb(uint32_t param); - static inline void env_to_regs(void) { } diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 52aad9532..6ddc0f47f 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1,7 +1,7 @@ /* - * PPC emulation helpers for qemu. + * PowerPC emulation helpers for qemu. * - * Copyright (c) 2003 Jocelyn Mayer + * Copyright (c) 2003-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,7 +26,7 @@ //#define ACCURATE_TLB_FLUSH /*****************************************************************************/ -/* PPC MMU emulation */ +/* PowerPC MMU emulation */ /* Perform BAT hit & translation */ static int get_bat (CPUState *env, uint32_t *real, int *prot, @@ -580,7 +580,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, if (rw) error_code |= EXCP_DSI_STORE; /* Store fault address */ - env->spr[DAR] = address; + env->spr[SPR_DAR] = address; } #if 0 printf("%s: set exception to %d %02x\n", @@ -593,25 +593,239 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, return ret; } -uint32_t _load_xer (CPUState *env) +/*****************************************************************************/ +/* BATs management */ +#if !defined(FLUSH_ALL_TLBS) +static inline void do_invalidate_BAT (CPUPPCState *env, + target_ulong BATu, target_ulong mask) +{ + target_ulong base, end, page; + base = BATu & ~0x0001FFFF; + end = base + mask + 0x00020000; +#if defined (DEBUG_BATS) + if (loglevel != 0) + fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", base, end, mask); +#endif + for (page = base; page != end; page += TARGET_PAGE_SIZE) + tlb_flush_page(env, page); +#if defined (DEBUG_BATS) + if (loglevel != 0) + fprintf(logfile, "Flush done\n"); +#endif +} +#endif + +static inline void dump_store_bat (CPUPPCState *env, char ID, int ul, int nr, + target_ulong value) +{ +#if defined (DEBUG_BATS) + if (loglevel != 0) { + fprintf(logfile, "Set %cBAT%d%c to 0x%08lx (0x%08lx)\n", + ID, nr, ul == 0 ? 'u' : 'l', (unsigned long)value, + (unsigned long)env->nip); + } +#endif +} + +target_ulong do_load_ibatu (CPUPPCState *env, int nr) +{ + return env->IBAT[0][nr]; +} + +target_ulong do_load_ibatl (CPUPPCState *env, int nr) +{ + return env->IBAT[1][nr]; +} + +void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value) +{ + target_ulong mask; + + dump_store_bat(env, 'I', 0, nr, value); + if (env->IBAT[0][nr] != value) { + mask = (value << 15) & 0x0FFE0000UL; +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#endif + /* When storing valid upper BAT, mask BEPI and BRPN + * and invalidate all TLBs covered by this BAT + */ + mask = (value << 15) & 0x0FFE0000UL; + env->IBAT[0][nr] = (value & 0x00001FFFUL) | + (value & ~0x0001FFFFUL & ~mask); + env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) | + (env->IBAT[1][nr] & ~0x0001FFFF & ~mask); +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#endif +#if defined(FLUSH_ALL_TLBS) + tlb_flush(env, 1); +#endif + } +} + +void do_store_ibatl (CPUPPCState *env, int nr, target_ulong value) +{ + dump_store_bat(env, 'I', 1, nr, value); + env->IBAT[1][nr] = value; +} + +target_ulong do_load_dbatu (CPUPPCState *env, int nr) +{ + return env->DBAT[0][nr]; +} + +target_ulong do_load_dbatl (CPUPPCState *env, int nr) +{ + return env->DBAT[1][nr]; +} + +void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value) +{ + target_ulong mask; + + dump_store_bat(env, 'D', 0, nr, value); + if (env->DBAT[0][nr] != value) { + /* When storing valid upper BAT, mask BEPI and BRPN + * and invalidate all TLBs covered by this BAT + */ + mask = (value << 15) & 0x0FFE0000UL; +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->DBAT[0][nr], mask); +#endif + mask = (value << 15) & 0x0FFE0000UL; + env->DBAT[0][nr] = (value & 0x00001FFFUL) | + (value & ~0x0001FFFFUL & ~mask); + env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) | + (env->DBAT[1][nr] & ~0x0001FFFF & ~mask); +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->DBAT[0][nr], mask); +#else + tlb_flush(env, 1); +#endif + } +} + +void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) +{ + dump_store_bat(env, 'D', 1, nr, value); + env->DBAT[1][nr] = value; +} + +static inline void invalidate_all_tlbs (CPUPPCState *env) +{ + /* XXX: this needs to be completed for sotware driven TLB support */ + tlb_flush(env, 1); +} + +/*****************************************************************************/ +/* Special registers manipulation */ +target_ulong do_load_nip (CPUPPCState *env) +{ + return env->nip; +} + +void do_store_nip (CPUPPCState *env, target_ulong value) +{ + env->nip = value; +} + +target_ulong do_load_sdr1 (CPUPPCState *env) +{ + return env->sdr1; +} + +void do_store_sdr1 (CPUPPCState *env, target_ulong value) +{ +#if defined (DEBUG_MMU) + if (loglevel != 0) { + fprintf(logfile, "%s: 0x%08lx\n", __func__, (unsigned long)value); + } +#endif + if (env->sdr1 != value) { + env->sdr1 = value; + invalidate_all_tlbs(env); + } +} + +target_ulong do_load_sr (CPUPPCState *env, int srnum) +{ + return env->sr[srnum]; +} + +void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) +{ +#if defined (DEBUG_MMU) + if (loglevel != 0) { + fprintf(logfile, "%s: reg=%d 0x%08lx %08lx\n", + __func__, srnum, (unsigned long)value, env->sr[srnum]); + } +#endif + if (env->sr[srnum] != value) { + env->sr[srnum] = value; +#if !defined(FLUSH_ALL_TLBS) && 0 + { + target_ulong page, end; + /* Invalidate 256 MB of virtual memory */ + page = (16 << 20) * srnum; + end = page + (16 << 20); + for (; page != end; page += TARGET_PAGE_SIZE) + tlb_flush_page(env, page); + } +#else + invalidate_all_tlbs(env); +#endif + } +} + +uint32_t do_load_cr (CPUPPCState *env) +{ + return (env->crf[0] << 28) | + (env->crf[1] << 24) | + (env->crf[2] << 20) | + (env->crf[3] << 16) | + (env->crf[4] << 12) | + (env->crf[5] << 8) | + (env->crf[6] << 4) | + (env->crf[7] << 0); +} + +void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask) +{ + int i, sh; + + for (i = 0, sh = 7; i < 8; i++, sh --) { + if (mask & (1 << sh)) + env->crf[i] = (value >> (sh * 4)) & 0xFUL; + } +} + +uint32_t do_load_xer (CPUPPCState *env) { return (xer_so << XER_SO) | (xer_ov << XER_OV) | (xer_ca << XER_CA) | - (xer_bc << XER_BC); + (xer_bc << XER_BC) | + (xer_cmp << XER_CMP); } -void _store_xer (CPUState *env, uint32_t value) +void do_store_xer (CPUPPCState *env, uint32_t value) { xer_so = (value >> XER_SO) & 0x01; xer_ov = (value >> XER_OV) & 0x01; xer_ca = (value >> XER_CA) & 0x01; - xer_bc = (value >> XER_BC) & 0x3f; + xer_cmp = (value >> XER_CMP) & 0xFF; + xer_bc = (value >> XER_BC) & 0x3F; } -uint32_t _load_msr (CPUState *env) +target_ulong do_load_msr (CPUPPCState *env) { - return (msr_pow << MSR_POW) | + return (msr_vr << MSR_VR) | + (msr_ap << MSR_AP) | + (msr_sa << MSR_SA) | + (msr_key << MSR_KEY) | + (msr_pow << MSR_POW) | + (msr_tlb << MSR_TLB) | (msr_ile << MSR_ILE) | (msr_ee << MSR_EE) | (msr_pr << MSR_PR) | @@ -621,41 +835,141 @@ uint32_t _load_msr (CPUState *env) (msr_se << MSR_SE) | (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | + (msr_al << MSR_AL) | (msr_ip << MSR_IP) | (msr_ir << MSR_IR) | (msr_dr << MSR_DR) | + (msr_pe << MSR_PE) | + (msr_px << MSR_PX) | (msr_ri << MSR_RI) | (msr_le << MSR_LE); } -void _store_msr (CPUState *env, uint32_t value) +void do_compute_hflags (CPUPPCState *env) { -#ifdef ACCURATE_TLB_FLUSH - if (((value >> MSR_IR) & 0x01) != msr_ir || - ((value >> MSR_DR) & 0x01) != msr_dr) + /* Compute current hflags */ + env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) | + (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) | + (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | + (msr_se << MSR_SE) | (msr_be << MSR_BE); +} + +void do_store_msr (CPUPPCState *env, target_ulong value) { - /* Flush all tlb when changing translation mode or privilege level */ + value &= env->msr_mask; + if (((value >> MSR_IR) & 1) != msr_ir || + ((value >> MSR_DR) & 1) != msr_dr) { + /* Flush all tlb when changing translation mode + * When using software driven TLB, we may also need to reload + * all defined TLBs + */ tlb_flush(env, 1); + env->interrupt_request |= CPU_INTERRUPT_EXITTB; } +#if 0 + if (loglevel != 0) { + fprintf(logfile, "%s: T0 %08lx\n", __func__, value); + } +#endif + msr_vr = (value >> MSR_VR) & 1; + msr_ap = (value >> MSR_AP) & 1; + msr_sa = (value >> MSR_SA) & 1; + msr_key = (value >> MSR_KEY) & 1; + msr_pow = (value >> MSR_POW) & 1; + msr_tlb = (value >> MSR_TLB) & 1; + msr_ile = (value >> MSR_ILE) & 1; + msr_ee = (value >> MSR_EE) & 1; + msr_pr = (value >> MSR_PR) & 1; + msr_fp = (value >> MSR_FP) & 1; + msr_me = (value >> MSR_ME) & 1; + msr_fe0 = (value >> MSR_FE0) & 1; + msr_se = (value >> MSR_SE) & 1; + msr_be = (value >> MSR_BE) & 1; + msr_fe1 = (value >> MSR_FE1) & 1; + msr_al = (value >> MSR_AL) & 1; + msr_ip = (value >> MSR_IP) & 1; + msr_ir = (value >> MSR_IR) & 1; + msr_dr = (value >> MSR_DR) & 1; + msr_pe = (value >> MSR_PE) & 1; + msr_px = (value >> MSR_PX) & 1; + msr_ri = (value >> MSR_RI) & 1; + msr_le = (value >> MSR_LE) & 1; + do_compute_hflags(env); +} + +float64 do_load_fpscr (CPUPPCState *env) +{ + /* The 32 MSB of the target fpr are undefined. + * They'll be zero... + */ + union { + float64 d; + struct { + uint32_t u[2]; + } s; + } u; + int i; + +#ifdef WORDS_BIGENDIAN +#define WORD0 0 +#define WORD1 1 +#else +#define WORD0 1 +#define WORD1 0 #endif - msr_pow = (value >> MSR_POW) & 0x03; - msr_ile = (value >> MSR_ILE) & 0x01; - msr_ee = (value >> MSR_EE) & 0x01; - msr_pr = (value >> MSR_PR) & 0x01; - msr_fp = (value >> MSR_FP) & 0x01; - msr_me = (value >> MSR_ME) & 0x01; - msr_fe0 = (value >> MSR_FE0) & 0x01; - msr_se = (value >> MSR_SE) & 0x01; - msr_be = (value >> MSR_BE) & 0x01; - msr_fe1 = (value >> MSR_FE1) & 0x01; - msr_ip = (value >> MSR_IP) & 0x01; - msr_ir = (value >> MSR_IR) & 0x01; - msr_dr = (value >> MSR_DR) & 0x01; - msr_ri = (value >> MSR_RI) & 0x01; - msr_le = (value >> MSR_LE) & 0x01; - /* XXX: should enter PM state if msr_pow has been set */ + u.s.u[WORD0] = 0; + u.s.u[WORD1] = 0; + for (i = 0; i < 8; i++) + u.s.u[WORD1] |= env->fpscr[i] << (4 * i); + return u.d; } +void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask) +{ + /* + * We use only the 32 LSB of the incoming fpr + */ + union { + double d; + struct { + uint32_t u[2]; + } s; + } u; + int i, rnd_type; + + u.d = f; + if (mask & 0x80) + env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9); + for (i = 1; i < 7; i++) { + if (mask & (1 << (7 - i))) + env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF; + } + /* TODO: update FEX & VX */ + /* Set rounding mode */ + switch (env->fpscr[0] & 0x3) { + case 0: + /* Best approximation (round to nearest) */ + rnd_type = float_round_nearest_even; + break; + case 1: + /* Smaller magnitude (round toward zero) */ + rnd_type = float_round_to_zero; + break; + case 2: + /* Round toward +infinite */ + rnd_type = float_round_up; + break; + default: + case 3: + /* Round toward -infinite */ + rnd_type = float_round_down; + break; + } + set_float_rounding_mode(rnd_type, &env->fp_status); +} + +/*****************************************************************************/ +/* Exception processing */ #if defined (CONFIG_USER_ONLY) void do_interrupt (CPUState *env) { @@ -675,7 +989,7 @@ void do_interrupt (CPUState *env) int excp; excp = env->exception_index; - msr = _load_msr(env); + msr = do_load_msr(env); #if defined (DEBUG_EXCEPTIONS) if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { @@ -715,29 +1029,29 @@ void do_interrupt (CPUState *env) * when the fault has been detected */ msr &= ~0xFFFF0000; - env->spr[DSISR] = 0; + env->spr[SPR_DSISR] = 0; if ((env->error_code & 0x0f) == EXCP_DSI_TRANSLATE) - env->spr[DSISR] |= 0x40000000; + env->spr[SPR_DSISR] |= 0x40000000; else if ((env->error_code & 0x0f) == EXCP_DSI_PROT) - env->spr[DSISR] |= 0x08000000; + env->spr[SPR_DSISR] |= 0x08000000; else if ((env->error_code & 0x0f) == EXCP_DSI_NOTSUP) { - env->spr[DSISR] |= 0x80000000; + env->spr[SPR_DSISR] |= 0x80000000; if (env->error_code & EXCP_DSI_DIRECT) - env->spr[DSISR] |= 0x04000000; + env->spr[SPR_DSISR] |= 0x04000000; } if (env->error_code & EXCP_DSI_STORE) - env->spr[DSISR] |= 0x02000000; + env->spr[SPR_DSISR] |= 0x02000000; if ((env->error_code & 0xF) == EXCP_DSI_DABR) - env->spr[DSISR] |= 0x00400000; + env->spr[SPR_DSISR] |= 0x00400000; if (env->error_code & EXCP_DSI_ECXW) - env->spr[DSISR] |= 0x00100000; + env->spr[SPR_DSISR] |= 0x00100000; #if defined (DEBUG_EXCEPTIONS) if (loglevel) { fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", - env->spr[DSISR], env->spr[DAR]); + env->spr[SPR_DSISR], env->spr[SPR_DAR]); } else { printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", - env->spr[DSISR], env->spr[DAR], env->nip); + env->spr[SPR_DSISR], env->spr[SPR_DAR], env->nip); } #endif goto store_next; @@ -777,7 +1091,7 @@ void do_interrupt (CPUState *env) case EXCP_ALIGN: /* Store exception cause */ /* Get rS/rD and rA from faulting opcode */ - env->spr[DSISR] |= + env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; /* data location address has been stored * when the fault has been detected @@ -858,14 +1172,14 @@ void do_interrupt (CPUState *env) return; store_current: /* SRR0 is set to current instruction */ - env->spr[SRR0] = (uint32_t)env->nip - 4; + env->spr[SPR_SRR0] = (uint32_t)env->nip - 4; break; store_next: /* SRR0 is set to next instruction */ - env->spr[SRR0] = (uint32_t)env->nip; + env->spr[SPR_SRR0] = (uint32_t)env->nip; break; } - env->spr[SRR1] = msr; + env->spr[SPR_SRR1] = msr; /* reload MSR with correct bits */ msr_pow = 0; msr_ee = 0; @@ -879,6 +1193,7 @@ void do_interrupt (CPUState *env) msr_dr = 0; msr_ri = 0; msr_le = msr_ile; + do_compute_hflags(env); /* Jump to handler */ env->nip = excp << 8; env->exception_index = EXCP_NONE; diff --git a/target-ppc/op.c b/target-ppc/op.c index 8c8021e1a..38ed13aa1 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1,7 +1,7 @@ /* - * PPC emulation micro-operations for qemu. + * PowerPC emulation micro-operations for qemu. * - * Copyright (c) 2003 Jocelyn Mayer + * Copyright (c) 2003-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -130,7 +130,7 @@ #define REG 31 #include "op_template.h" -/* PPC state maintenance operations */ +/* PowerPC state maintenance operations */ /* set_Rc0 */ PPC_OP(set_Rc0) { @@ -223,7 +223,7 @@ PPC_OP(load_srin) PPC_OP(store_srin) { - do_store_sr(T1 >> 28); + do_store_sr(env, ((uint32_t)T1 >> 28), T0); RETURN(); } @@ -235,7 +235,7 @@ PPC_OP(load_sdr1) PPC_OP(store_sdr1) { - regs->sdr1 = T0; + do_store_sdr1(env, T0); RETURN(); } @@ -247,13 +247,13 @@ PPC_OP(exit_tb) /* Load/store special registers */ PPC_OP(load_cr) { - do_load_cr(); + T0 = do_load_cr(env); RETURN(); } PPC_OP(store_cr) { - do_store_cr(PARAM(1)); + do_store_cr(env, T0, PARAM(1)); RETURN(); } @@ -279,25 +279,25 @@ PPC_OP(load_xer_bc) PPC_OP(load_xer) { - do_load_xer(); + T0 = do_load_xer(env); RETURN(); } PPC_OP(store_xer) { - do_store_xer(); + do_store_xer(env, T0); RETURN(); } PPC_OP(load_msr) { - do_load_msr(); + T0 = do_load_msr(env); RETURN(); } PPC_OP(store_msr) { - do_store_msr(); + do_store_msr(env, T0); RETURN(); } @@ -378,9 +378,20 @@ PPC_OP(load_ibat) T0 = regs->IBAT[PARAM(1)][PARAM(2)]; } -PPC_OP(store_ibat) +void op_store_ibatu (void) { - do_store_ibat(PARAM(1), PARAM(2)); + do_store_ibatu(env, PARAM1, T0); + RETURN(); +} + +void op_store_ibatl (void) +{ +#if 1 + env->IBAT[1][PARAM1] = T0; +#else + do_store_ibatl(env, PARAM1, T0); +#endif + RETURN(); } PPC_OP(load_dbat) @@ -388,21 +399,32 @@ PPC_OP(load_dbat) T0 = regs->DBAT[PARAM(1)][PARAM(2)]; } -PPC_OP(store_dbat) +void op_store_dbatu (void) +{ + do_store_dbatu(env, PARAM1, T0); + RETURN(); +} + +void op_store_dbatl (void) { - do_store_dbat(PARAM(1), PARAM(2)); +#if 1 + env->DBAT[1][PARAM1] = T0; +#else + do_store_dbatl(env, PARAM1, T0); +#endif + RETURN(); } /* FPSCR */ PPC_OP(load_fpscr) { - do_load_fpscr(); + FT0 = do_load_fpscr(env); RETURN(); } PPC_OP(store_fpscr) { - do_store_fpscr(PARAM(1)); + do_store_fpscr(env, FT0, PARAM1); RETURN(); } @@ -1362,17 +1384,13 @@ PPC_OP(check_reservation) /* Return from interrupt */ PPC_OP(rfi) { - regs->nip = regs->spr[SRR0] & ~0x00000003; + regs->nip = regs->spr[SPR_SRR0] & ~0x00000003; #if 1 // TRY - T0 = regs->spr[SRR1] & ~0xFFF00000; + T0 = regs->spr[SPR_SRR1] & ~0xFFF00000; #else - T0 = regs->spr[SRR1] & ~0xFFFF0000; -#endif - do_store_msr(); -#if defined (DEBUG_OP) - dump_rfi(); + T0 = regs->spr[SPR_SRR1] & ~0xFFFF0000; #endif - // do_tlbia(); + do_store_msr(env, T0); do_raise_exception(EXCP_RFI); RETURN(); } @@ -1420,3 +1438,9 @@ PPC_OP(tlbie) do_tlbie(); RETURN(); } + +void op_store_pir (void) +{ + env->spr[SPR_PIR] = T0 & 0x0000000FUL; + RETURN(); +} diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 3f5fb0bbc..670e27894 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1,7 +1,7 @@ /* - * PPC emulation helpers for qemu. + * PowerPC emulation helpers for qemu. * - * Copyright (c) 2003 Jocelyn Mayer + * Copyright (c) 2003-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -67,91 +67,6 @@ void do_raise_exception (uint32_t exception) /*****************************************************************************/ /* Helpers for "fat" micro operations */ -/* Special registers load and store */ -void do_load_cr (void) -{ - T0 = (env->crf[0] << 28) | - (env->crf[1] << 24) | - (env->crf[2] << 20) | - (env->crf[3] << 16) | - (env->crf[4] << 12) | - (env->crf[5] << 8) | - (env->crf[6] << 4) | - (env->crf[7] << 0); -} - -void do_store_cr (uint32_t mask) -{ - int i, sh; - - for (i = 0, sh = 7; i < 8; i++, sh --) { - if (mask & (1 << sh)) - env->crf[i] = (T0 >> (sh * 4)) & 0xF; - } -} - -void do_load_xer (void) -{ - T0 = (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC); -} - -void do_store_xer (void) -{ - xer_so = (T0 >> XER_SO) & 0x01; - xer_ov = (T0 >> XER_OV) & 0x01; - xer_ca = (T0 >> XER_CA) & 0x01; - xer_bc = (T0 >> XER_BC) & 0x3f; -} - -void do_load_msr (void) -{ - T0 = (msr_pow << MSR_POW) | - (msr_ile << MSR_ILE) | - (msr_ee << MSR_EE) | - (msr_pr << MSR_PR) | - (msr_fp << MSR_FP) | - (msr_me << MSR_ME) | - (msr_fe0 << MSR_FE0) | - (msr_se << MSR_SE) | - (msr_be << MSR_BE) | - (msr_fe1 << MSR_FE1) | - (msr_ip << MSR_IP) | - (msr_ir << MSR_IR) | - (msr_dr << MSR_DR) | - (msr_ri << MSR_RI) | - (msr_le << MSR_LE); -} - -void do_store_msr (void) -{ -#if 1 // TRY - if (((T0 >> MSR_IR) & 0x01) != msr_ir || - ((T0 >> MSR_DR) & 0x01) != msr_dr || - ((T0 >> MSR_PR) & 0x01) != msr_pr) - { - do_tlbia(); - } -#endif - msr_pow = (T0 >> MSR_POW) & 0x03; - msr_ile = (T0 >> MSR_ILE) & 0x01; - msr_ee = (T0 >> MSR_EE) & 0x01; - msr_pr = (T0 >> MSR_PR) & 0x01; - msr_fp = (T0 >> MSR_FP) & 0x01; - msr_me = (T0 >> MSR_ME) & 0x01; - msr_fe0 = (T0 >> MSR_FE0) & 0x01; - msr_se = (T0 >> MSR_SE) & 0x01; - msr_be = (T0 >> MSR_BE) & 0x01; - msr_fe1 = (T0 >> MSR_FE1) & 0x01; - msr_ip = (T0 >> MSR_IP) & 0x01; - msr_ir = (T0 >> MSR_IR) & 0x01; - msr_dr = (T0 >> MSR_DR) & 0x01; - msr_ri = (T0 >> MSR_RI) & 0x01; - msr_le = (T0 >> MSR_LE) & 0x01; -} - /* shift right arithmetic helper */ void do_sraw (void) { @@ -175,77 +90,6 @@ void do_sraw (void) } /* Floating point operations helpers */ -void do_load_fpscr (void) -{ - /* The 32 MSB of the target fpr are undefined. - * They'll be zero... - */ - union { - double d; - struct { - uint32_t u[2]; - } s; - } u; - int i; - -#ifdef WORDS_BIGENDIAN -#define WORD0 0 -#define WORD1 1 -#else -#define WORD0 1 -#define WORD1 0 -#endif - u.s.u[WORD0] = 0; - u.s.u[WORD1] = 0; - for (i = 0; i < 8; i++) - u.s.u[WORD1] |= env->fpscr[i] << (4 * i); - FT0 = u.d; -} - -void do_store_fpscr (uint32_t mask) -{ - /* - * We use only the 32 LSB of the incoming fpr - */ - union { - double d; - struct { - uint32_t u[2]; - } s; - } u; - int i, rnd_type; - - u.d = FT0; - if (mask & 0x80) - env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9); - for (i = 1; i < 7; i++) { - if (mask & (1 << (7 - i))) - env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF; - } - /* TODO: update FEX & VX */ - /* Set rounding mode */ - switch (env->fpscr[0] & 0x3) { - case 0: - /* Best approximation (round to nearest) */ - rnd_type = float_round_nearest_even; - break; - case 1: - /* Smaller magnitude (round toward zero) */ - rnd_type = float_round_to_zero; - break; - case 2: - /* Round toward +infinite */ - rnd_type = float_round_up; - break; - default: - case 3: - /* Round toward -infinite */ - rnd_type = float_round_down; - break; - } - set_float_rounding_mode(rnd_type, &env->fp_status); -} - void do_fctiw (void) { union { @@ -254,7 +98,7 @@ void do_fctiw (void) } p; /* XXX: higher bits are not supposed to be significant. - * to make tests easier, return the same as a real PPC 750 (aka G3) + * to make tests easier, return the same as a real PowerPC 750 (aka G3) */ p.i = float64_to_int32(FT0, &env->fp_status); p.i |= 0xFFF80000ULL << 32; @@ -269,7 +113,7 @@ void do_fctiwz (void) } p; /* XXX: higher bits are not supposed to be significant. - * to make tests easier, return the same as a real PPC 750 (aka G3) + * to make tests easier, return the same as a real PowerPC 750 (aka G3) */ p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); p.i |= 0xFFF80000ULL << 32; @@ -455,116 +299,3 @@ void do_tlbie (void) tlb_flush_page(env, T0); } -void do_store_sr (uint32_t srnum) -{ -#if defined (DEBUG_OP) - dump_store_sr(srnum); -#endif -#if 0 // TRY - { - uint32_t base, page; - - base = srnum << 28; - for (page = base; page != base + 0x100000000; page += 0x1000) - tlb_flush_page(env, page); - } -#else - tlb_flush(env, 1); -#endif - env->sr[srnum] = T0; -} - -/* For BATs, we may not invalidate any TLBs if the change is only on - * protection bits for user mode. - */ -void do_store_ibat (int ul, int nr) -{ -#if defined (DEBUG_OP) - dump_store_ibat(ul, nr); -#endif -#if 0 // TRY - { - uint32_t base, length, page; - - base = env->IBAT[0][nr]; - length = (((base >> 2) & 0x000007FF) + 1) << 17; - base &= 0xFFFC0000; - for (page = base; page != base + length; page += 0x1000) - tlb_flush_page(env, page); - } -#else - tlb_flush(env, 1); -#endif - env->IBAT[ul][nr] = T0; -} - -void do_store_dbat (int ul, int nr) -{ -#if defined (DEBUG_OP) - dump_store_dbat(ul, nr); -#endif -#if 0 // TRY - { - uint32_t base, length, page; - base = env->DBAT[0][nr]; - length = (((base >> 2) & 0x000007FF) + 1) << 17; - base &= 0xFFFC0000; - for (page = base; page != base + length; page += 0x1000) - tlb_flush_page(env, page); - } -#else - tlb_flush(env, 1); -#endif - env->DBAT[ul][nr] = T0; -} - -/*****************************************************************************/ -/* Special helpers for debug */ -void dump_state (void) -{ - // cpu_dump_state(env, stdout, fprintf, 0); -} - -void dump_rfi (void) -{ -#if 0 - printf("Return from interrupt => 0x%08x\n", env->nip); - // cpu_dump_state(env, stdout, fprintf, 0); -#endif -} - -void dump_store_sr (int srnum) -{ -#if 0 - printf("%s: reg=%d 0x%08x\n", __func__, srnum, T0); -#endif -} - -static void _dump_store_bat (char ID, int ul, int nr) -{ - printf("Set %cBAT%d%c to 0x%08x (0x%08x)\n", - ID, nr, ul == 0 ? 'u' : 'l', T0, env->nip); -} - -void dump_store_ibat (int ul, int nr) -{ - _dump_store_bat('I', ul, nr); -} - -void dump_store_dbat (int ul, int nr) -{ - _dump_store_bat('D', ul, nr); -} - -void dump_store_tb (int ul) -{ - printf("Set TB%c to 0x%08x\n", ul == 0 ? 'L' : 'U', T0); -} - -void dump_update_tb(uint32_t param) -{ -#if 0 - printf("Update TB: 0x%08x + %d => 0x%08x\n", T1, param, T0); -#endif -} - diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 338b7aa23..1be640d6d 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -1,7 +1,7 @@ /* - * PPC emulation micro-operations for qemu. + * PowerPC emulation micro-operations for qemu. * - * Copyright (c) 2003 Jocelyn Mayer + * Copyright (c) 2003-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -175,7 +175,7 @@ void OPPROTO glue(op_load_sr, REG)(void) void OPPROTO glue(op_store_sr, REG)(void) { - do_store_sr(REG); + do_store_sr(env, REG, T0); RETURN(); } #endif diff --git a/target-ppc/translate.c b/target-ppc/translate.c index b2006df53..52a28def1 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1,7 +1,7 @@ /* - * PPC emulation for qemu: main translation routines. + * PowerPC emulation for qemu: main translation routines. * - * Copyright (c) 2003 Jocelyn Mayer + * Copyright (c) 2003-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -141,16 +141,17 @@ typedef struct DisasContext { int supervisor; #endif int fpu_enabled; + ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ } DisasContext; -typedef struct opc_handler_t { +struct opc_handler_t { /* invalid bits */ uint32_t inval; /* instruction type */ uint32_t type; /* handler */ void (*handler)(DisasContext *ctx); -} opc_handler_t; +}; #define RET_EXCP(ctx, excp, error) \ do { \ @@ -173,6 +174,11 @@ RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) #define RET_MTMSR(ctx) \ RET_EXCP((ctx), EXCP_MTMSR, 0) +static inline void RET_STOP (DisasContext *ctx) +{ + RET_EXCP(ctx, EXCP_MTMSR, 0); +} + #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ static void gen_##name (DisasContext *ctx); \ GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \ @@ -186,6 +192,7 @@ typedef struct opcode_t { unsigned char pad[1]; #endif opc_handler_t handler; + const unsigned char *oname; } opcode_t; /*** Instruction decoding ***/ @@ -226,7 +233,13 @@ EXTRACT_HELPER(crbD, 21, 5); EXTRACT_HELPER(crbA, 16, 5); EXTRACT_HELPER(crbB, 11, 5); /* SPR / TBL */ -EXTRACT_HELPER(SPR, 11, 10); +EXTRACT_HELPER(_SPR, 11, 10); +static inline uint32_t SPR (uint32_t opcode) +{ + uint32_t sprn = _SPR(opcode); + + return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5); +} /*** Get constants ***/ EXTRACT_HELPER(IMM, 12, 8); /* 16 bits signed immediate value */ @@ -282,12 +295,17 @@ static inline uint32_t MASK (uint32_t start, uint32_t end) return ret; } +#if HOST_LONG_BITS == 64 +#define OPC_ALIGN 8 +#else +#define OPC_ALIGN 4 +#endif #if defined(__APPLE__) #define OPCODES_SECTION \ - __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (8) )) + __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) )) #else #define OPCODES_SECTION \ - __attribute__ ((section(".opcodes"), unused, aligned (8) )) + __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) )) #endif #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ @@ -301,6 +319,7 @@ OPCODES_SECTION opcode_t opc_##name = { \ .type = _typ, \ .handler = &gen_##name, \ }, \ + .oname = stringify(name), \ } #define GEN_OPCODE_MARK(name) \ @@ -314,6 +333,7 @@ OPCODES_SECTION opcode_t opc_##name = { \ .type = 0x00, \ .handler = NULL, \ }, \ + .oname = stringify(name), \ } /* Start opcode list */ @@ -1344,7 +1364,7 @@ static GenOpFunc1 *gen_op_stsw[] = { #endif /* lswi */ -/* PPC32 specification says we must generate an exception if +/* PowerPC32 specification says we must generate an exception if * rA is in the range of registers to be loaded. * In an other hand, IBM says this is valid, but rA won't be loaded. * For now, I'll follow the spec... @@ -1965,169 +1985,54 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) #endif } +#if 0 +#define SPR_NOACCESS ((void *)(-1)) +#else +static void spr_noaccess (void *opaque, int sprn) +{ + sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5); + printf("ERROR: try to access SPR %d !\n", sprn); +} +#define SPR_NOACCESS (&spr_noaccess) +#endif + /* mfspr */ -GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) +static inline void gen_op_mfspr (DisasContext *ctx) { + void (*read_cb)(void *opaque, int sprn); uint32_t sprn = SPR(ctx->opcode); -#if defined(CONFIG_USER_ONLY) - switch (check_spr_access(sprn, 0, 0)) -#else - switch (check_spr_access(sprn, 0, ctx->supervisor)) +#if !defined(CONFIG_USER_ONLY) + if (ctx->supervisor) + read_cb = ctx->spr_cb[sprn].oea_read; + else #endif - { - case -1: - RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); - return; - case 0: + read_cb = ctx->spr_cb[sprn].uea_read; + if (read_cb != NULL) { + if (read_cb != SPR_NOACCESS) { + (*read_cb)(ctx, sprn); + gen_op_store_T0_gpr(rD(ctx->opcode)); + } else { + /* Privilege exception */ + printf("Trying to read priviledged spr %d %03x\n", sprn, sprn); RET_PRIVREG(ctx); - return; - default: - break; } - switch (sprn) { - case XER: - gen_op_load_xer(); - break; - case LR: - gen_op_load_lr(); - break; - case CTR: - gen_op_load_ctr(); - break; - case IBAT0U: - gen_op_load_ibat(0, 0); - break; - case IBAT1U: - gen_op_load_ibat(0, 1); - break; - case IBAT2U: - gen_op_load_ibat(0, 2); - break; - case IBAT3U: - gen_op_load_ibat(0, 3); - break; - case IBAT4U: - gen_op_load_ibat(0, 4); - break; - case IBAT5U: - gen_op_load_ibat(0, 5); - break; - case IBAT6U: - gen_op_load_ibat(0, 6); - break; - case IBAT7U: - gen_op_load_ibat(0, 7); - break; - case IBAT0L: - gen_op_load_ibat(1, 0); - break; - case IBAT1L: - gen_op_load_ibat(1, 1); - break; - case IBAT2L: - gen_op_load_ibat(1, 2); - break; - case IBAT3L: - gen_op_load_ibat(1, 3); - break; - case IBAT4L: - gen_op_load_ibat(1, 4); - break; - case IBAT5L: - gen_op_load_ibat(1, 5); - break; - case IBAT6L: - gen_op_load_ibat(1, 6); - break; - case IBAT7L: - gen_op_load_ibat(1, 7); - break; - case DBAT0U: - gen_op_load_dbat(0, 0); - break; - case DBAT1U: - gen_op_load_dbat(0, 1); - break; - case DBAT2U: - gen_op_load_dbat(0, 2); - break; - case DBAT3U: - gen_op_load_dbat(0, 3); - break; - case DBAT4U: - gen_op_load_dbat(0, 4); - break; - case DBAT5U: - gen_op_load_dbat(0, 5); - break; - case DBAT6U: - gen_op_load_dbat(0, 6); - break; - case DBAT7U: - gen_op_load_dbat(0, 7); - break; - case DBAT0L: - gen_op_load_dbat(1, 0); - break; - case DBAT1L: - gen_op_load_dbat(1, 1); - break; - case DBAT2L: - gen_op_load_dbat(1, 2); - break; - case DBAT3L: - gen_op_load_dbat(1, 3); - break; - case DBAT4L: - gen_op_load_dbat(1, 4); - break; - case DBAT5L: - gen_op_load_dbat(1, 5); - break; - case DBAT6L: - gen_op_load_dbat(1, 6); - break; - case DBAT7L: - gen_op_load_dbat(1, 7); - break; - case SDR1: - gen_op_load_sdr1(); - break; - case V_TBL: - gen_op_load_tbl(); - break; - case V_TBU: - gen_op_load_tbu(); - break; - case DECR: - gen_op_load_decr(); - break; - default: - gen_op_load_spr(sprn); - break; + } else { + /* Not defined */ + printf("Trying to read invalid spr %d %03x\n", sprn, sprn); + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); } - gen_op_store_T0_gpr(rD(ctx->opcode)); } -/* mftb */ -GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) +GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) { - uint32_t sprn = SPR(ctx->opcode); - - /* We need to update the time base before reading it */ - switch (sprn) { - case V_TBL: - gen_op_load_tbl(); - break; - case V_TBU: - gen_op_load_tbu(); - break; - default: - RET_INVAL(ctx); - return; + gen_op_mfspr(ctx); } - gen_op_store_T0_gpr(rD(ctx->opcode)); + +/* mftb */ +GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB) +{ + gen_op_mfspr(ctx); } /* mtcrf */ @@ -2158,184 +2063,28 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) /* mtspr */ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) { + void (*write_cb)(void *opaque, int sprn); uint32_t sprn = SPR(ctx->opcode); -#if 0 - if (loglevel > 0) { - fprintf(logfile, "MTSPR %d src=%d (%d)\n", SPR_ENCODE(sprn), - rS(ctx->opcode), sprn); - } -#endif -#if defined(CONFIG_USER_ONLY) - switch (check_spr_access(sprn, 1, 0)) -#else - switch (check_spr_access(sprn, 1, ctx->supervisor)) +#if !defined(CONFIG_USER_ONLY) + if (ctx->supervisor) + write_cb = ctx->spr_cb[sprn].oea_write; + else #endif - { - case -1: - RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); - break; - case 0: + write_cb = ctx->spr_cb[sprn].uea_write; + if (write_cb != NULL) { + if (write_cb != SPR_NOACCESS) { + gen_op_load_gpr_T0(rS(ctx->opcode)); + (*write_cb)(ctx, sprn); + } else { + /* Privilege exception */ + printf("Trying to write priviledged spr %d %03x\n", sprn, sprn); RET_PRIVREG(ctx); - break; - default: - break; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - switch (sprn) { - case XER: - gen_op_store_xer(); - break; - case LR: - gen_op_store_lr(); - break; - case CTR: - gen_op_store_ctr(); - break; - case IBAT0U: - gen_op_store_ibat(0, 0); - RET_MTMSR(ctx); - break; - case IBAT1U: - gen_op_store_ibat(0, 1); - RET_MTMSR(ctx); - break; - case IBAT2U: - gen_op_store_ibat(0, 2); - RET_MTMSR(ctx); - break; - case IBAT3U: - gen_op_store_ibat(0, 3); - RET_MTMSR(ctx); - break; - case IBAT4U: - gen_op_store_ibat(0, 4); - RET_MTMSR(ctx); - break; - case IBAT5U: - gen_op_store_ibat(0, 5); - RET_MTMSR(ctx); - break; - case IBAT6U: - gen_op_store_ibat(0, 6); - RET_MTMSR(ctx); - break; - case IBAT7U: - gen_op_store_ibat(0, 7); - RET_MTMSR(ctx); - break; - case IBAT0L: - gen_op_store_ibat(1, 0); - RET_MTMSR(ctx); - break; - case IBAT1L: - gen_op_store_ibat(1, 1); - RET_MTMSR(ctx); - break; - case IBAT2L: - gen_op_store_ibat(1, 2); - RET_MTMSR(ctx); - break; - case IBAT3L: - gen_op_store_ibat(1, 3); - RET_MTMSR(ctx); - break; - case IBAT4L: - gen_op_store_ibat(1, 4); - RET_MTMSR(ctx); - break; - case IBAT5L: - gen_op_store_ibat(1, 5); - RET_MTMSR(ctx); - break; - case IBAT6L: - gen_op_store_ibat(1, 6); - RET_MTMSR(ctx); - break; - case IBAT7L: - gen_op_store_ibat(1, 7); - RET_MTMSR(ctx); - break; - case DBAT0U: - gen_op_store_dbat(0, 0); - RET_MTMSR(ctx); - break; - case DBAT1U: - gen_op_store_dbat(0, 1); - RET_MTMSR(ctx); - break; - case DBAT2U: - gen_op_store_dbat(0, 2); - RET_MTMSR(ctx); - break; - case DBAT3U: - gen_op_store_dbat(0, 3); - RET_MTMSR(ctx); - break; - case DBAT4U: - gen_op_store_dbat(0, 4); - RET_MTMSR(ctx); - break; - case DBAT5U: - gen_op_store_dbat(0, 5); - RET_MTMSR(ctx); - break; - case DBAT6U: - gen_op_store_dbat(0, 6); - RET_MTMSR(ctx); - break; - case DBAT7U: - gen_op_store_dbat(0, 7); - RET_MTMSR(ctx); - break; - case DBAT0L: - gen_op_store_dbat(1, 0); - RET_MTMSR(ctx); - break; - case DBAT1L: - gen_op_store_dbat(1, 1); - RET_MTMSR(ctx); - break; - case DBAT2L: - gen_op_store_dbat(1, 2); - RET_MTMSR(ctx); - break; - case DBAT3L: - gen_op_store_dbat(1, 3); - RET_MTMSR(ctx); - break; - case DBAT4L: - gen_op_store_dbat(1, 4); - RET_MTMSR(ctx); - break; - case DBAT5L: - gen_op_store_dbat(1, 5); - RET_MTMSR(ctx); - break; - case DBAT6L: - gen_op_store_dbat(1, 6); - RET_MTMSR(ctx); - break; - case DBAT7L: - gen_op_store_dbat(1, 7); - RET_MTMSR(ctx); - break; - case SDR1: - gen_op_store_sdr1(); - RET_MTMSR(ctx); - break; - case O_TBL: - gen_op_store_tbl(); - break; - case O_TBU: - gen_op_store_tbu(); - break; - case DECR: - gen_op_store_decr(); - break; - default: - gen_op_store_spr(sprn); - break; + } else { + /* Not defined */ + printf("Trying to write invalid spr %d %03x\n", sprn, sprn); + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); } } @@ -2514,7 +2263,7 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) /*** Lookaside buffer management ***/ /* Optional & supervisor only: */ /* tlbia */ -GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) +GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -2624,510 +2373,41 @@ GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) /* End opcode list */ GEN_OPCODE_MARK(end); -/*****************************************************************************/ -#include -#include - -int fflush (FILE *stream); - -/* Main ppc opcodes table: - * at init, all opcodes are invalids - */ -static opc_handler_t *ppc_opcodes[0x40]; - -/* Opcode types */ -enum { - PPC_DIRECT = 0, /* Opcode routine */ - PPC_INDIRECT = 1, /* Indirect opcode table */ -}; - -static inline int is_indirect_opcode (void *handler) -{ - return ((unsigned long)handler & 0x03) == PPC_INDIRECT; -} - -static inline opc_handler_t **ind_table(void *handler) -{ - return (opc_handler_t **)((unsigned long)handler & ~3); -} - -/* Instruction table creation */ -/* Opcodes tables creation */ -static void fill_new_table (opc_handler_t **table, int len) -{ - int i; - - for (i = 0; i < len; i++) - table[i] = &invalid_handler; -} - -static int create_new_table (opc_handler_t **table, unsigned char idx) -{ - opc_handler_t **tmp; - - tmp = malloc(0x20 * sizeof(opc_handler_t)); - if (tmp == NULL) - return -1; - fill_new_table(tmp, 0x20); - table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT); - - return 0; -} - -static int insert_in_table (opc_handler_t **table, unsigned char idx, - opc_handler_t *handler) -{ - if (table[idx] != &invalid_handler) - return -1; - table[idx] = handler; - - return 0; -} - -static int register_direct_insn (opc_handler_t **ppc_opcodes, - unsigned char idx, opc_handler_t *handler) -{ - if (insert_in_table(ppc_opcodes, idx, handler) < 0) { - printf("*** ERROR: opcode %02x already assigned in main " - "opcode table\n", idx); - return -1; - } - - return 0; -} - -static int register_ind_in_table (opc_handler_t **table, - unsigned char idx1, unsigned char idx2, - opc_handler_t *handler) -{ - if (table[idx1] == &invalid_handler) { - if (create_new_table(table, idx1) < 0) { - printf("*** ERROR: unable to create indirect table " - "idx=%02x\n", idx1); - return -1; - } - } else { - if (!is_indirect_opcode(table[idx1])) { - printf("*** ERROR: idx %02x already assigned to a direct " - "opcode\n", idx1); - return -1; - } - } - if (handler != NULL && - insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { - printf("*** ERROR: opcode %02x already assigned in " - "opcode table %02x\n", idx2, idx1); - return -1; - } - - return 0; -} - -static int register_ind_insn (opc_handler_t **ppc_opcodes, - unsigned char idx1, unsigned char idx2, - opc_handler_t *handler) -{ - int ret; - - ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler); - - return ret; -} - -static int register_dblind_insn (opc_handler_t **ppc_opcodes, - unsigned char idx1, unsigned char idx2, - unsigned char idx3, opc_handler_t *handler) -{ - if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { - printf("*** ERROR: unable to join indirect table idx " - "[%02x-%02x]\n", idx1, idx2); - return -1; - } - if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, - handler) < 0) { - printf("*** ERROR: unable to insert opcode " - "[%02x-%02x-%02x]\n", idx1, idx2, idx3); - return -1; - } - - return 0; -} - -static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn) -{ - if (insn->opc2 != 0xFF) { - if (insn->opc3 != 0xFF) { - if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, - insn->opc3, &insn->handler) < 0) - return -1; - } else { - if (register_ind_insn(ppc_opcodes, insn->opc1, - insn->opc2, &insn->handler) < 0) - return -1; - } - } else { - if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) - return -1; - } - - return 0; -} - -static int test_opcode_table (opc_handler_t **table, int len) -{ - int i, count, tmp; - - for (i = 0, count = 0; i < len; i++) { - /* Consistency fixup */ - if (table[i] == NULL) - table[i] = &invalid_handler; - if (table[i] != &invalid_handler) { - if (is_indirect_opcode(table[i])) { - tmp = test_opcode_table(ind_table(table[i]), 0x20); - if (tmp == 0) { - free(table[i]); - table[i] = &invalid_handler; - } else { - count++; - } - } else { - count++; - } - } - } - - return count; -} - -static void fix_opcode_tables (opc_handler_t **ppc_opcodes) -{ - if (test_opcode_table(ppc_opcodes, 0x40) == 0) - printf("*** WARNING: no opcode defined !\n"); -} - -#define SPR_RIGHTS(rw, priv) (1 << ((2 * (priv)) + (rw))) -#define SPR_UR SPR_RIGHTS(0, 0) -#define SPR_UW SPR_RIGHTS(1, 0) -#define SPR_SR SPR_RIGHTS(0, 1) -#define SPR_SW SPR_RIGHTS(1, 1) - -#define spr_set_rights(spr, rights) \ -do { \ - spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \ -} while (0) - -static void init_spr_rights (uint32_t pvr) -{ - /* XER (SPR 1) */ - spr_set_rights(XER, SPR_UR | SPR_UW | SPR_SR | SPR_SW); - /* LR (SPR 8) */ - spr_set_rights(LR, SPR_UR | SPR_UW | SPR_SR | SPR_SW); - /* CTR (SPR 9) */ - spr_set_rights(CTR, SPR_UR | SPR_UW | SPR_SR | SPR_SW); - /* TBL (SPR 268) */ - spr_set_rights(V_TBL, SPR_UR | SPR_SR); - /* TBU (SPR 269) */ - spr_set_rights(V_TBU, SPR_UR | SPR_SR); - /* DSISR (SPR 18) */ - spr_set_rights(DSISR, SPR_SR | SPR_SW); - /* DAR (SPR 19) */ - spr_set_rights(DAR, SPR_SR | SPR_SW); - /* DEC (SPR 22) */ - spr_set_rights(DECR, SPR_SR | SPR_SW); - /* SDR1 (SPR 25) */ - spr_set_rights(SDR1, SPR_SR | SPR_SW); - /* SRR0 (SPR 26) */ - spr_set_rights(SRR0, SPR_SR | SPR_SW); - /* SRR1 (SPR 27) */ - spr_set_rights(SRR1, SPR_SR | SPR_SW); - /* SPRG0 (SPR 272) */ - spr_set_rights(SPRG0, SPR_SR | SPR_SW); - /* SPRG1 (SPR 273) */ - spr_set_rights(SPRG1, SPR_SR | SPR_SW); - /* SPRG2 (SPR 274) */ - spr_set_rights(SPRG2, SPR_SR | SPR_SW); - /* SPRG3 (SPR 275) */ - spr_set_rights(SPRG3, SPR_SR | SPR_SW); - /* ASR (SPR 280) */ - spr_set_rights(ASR, SPR_SR | SPR_SW); - /* EAR (SPR 282) */ - spr_set_rights(EAR, SPR_SR | SPR_SW); - /* TBL (SPR 284) */ - spr_set_rights(O_TBL, SPR_SW); - /* TBU (SPR 285) */ - spr_set_rights(O_TBU, SPR_SW); - /* PVR (SPR 287) */ - spr_set_rights(PVR, SPR_SR); - /* IBAT0U (SPR 528) */ - spr_set_rights(IBAT0U, SPR_SR | SPR_SW); - /* IBAT0L (SPR 529) */ - spr_set_rights(IBAT0L, SPR_SR | SPR_SW); - /* IBAT1U (SPR 530) */ - spr_set_rights(IBAT1U, SPR_SR | SPR_SW); - /* IBAT1L (SPR 531) */ - spr_set_rights(IBAT1L, SPR_SR | SPR_SW); - /* IBAT2U (SPR 532) */ - spr_set_rights(IBAT2U, SPR_SR | SPR_SW); - /* IBAT2L (SPR 533) */ - spr_set_rights(IBAT2L, SPR_SR | SPR_SW); - /* IBAT3U (SPR 534) */ - spr_set_rights(IBAT3U, SPR_SR | SPR_SW); - /* IBAT3L (SPR 535) */ - spr_set_rights(IBAT3L, SPR_SR | SPR_SW); - /* DBAT0U (SPR 536) */ - spr_set_rights(DBAT0U, SPR_SR | SPR_SW); - /* DBAT0L (SPR 537) */ - spr_set_rights(DBAT0L, SPR_SR | SPR_SW); - /* DBAT1U (SPR 538) */ - spr_set_rights(DBAT1U, SPR_SR | SPR_SW); - /* DBAT1L (SPR 539) */ - spr_set_rights(DBAT1L, SPR_SR | SPR_SW); - /* DBAT2U (SPR 540) */ - spr_set_rights(DBAT2U, SPR_SR | SPR_SW); - /* DBAT2L (SPR 541) */ - spr_set_rights(DBAT2L, SPR_SR | SPR_SW); - /* DBAT3U (SPR 542) */ - spr_set_rights(DBAT3U, SPR_SR | SPR_SW); - /* DBAT3L (SPR 543) */ - spr_set_rights(DBAT3L, SPR_SR | SPR_SW); - /* FPECR (SPR 1022) */ - spr_set_rights(FPECR, SPR_SR | SPR_SW); - /* Special registers for PPC 604 */ - if ((pvr & 0xFFFF0000) == 0x00040000) { - /* IABR */ - spr_set_rights(IABR , SPR_SR | SPR_SW); - /* DABR (SPR 1013) */ - spr_set_rights(DABR, SPR_SR | SPR_SW); - /* HID0 */ - spr_set_rights(HID0, SPR_SR | SPR_SW); - /* PIR */ - spr_set_rights(PIR, SPR_SR | SPR_SW); - /* PMC1 */ - spr_set_rights(PMC1, SPR_SR | SPR_SW); - /* PMC2 */ - spr_set_rights(PMC2, SPR_SR | SPR_SW); - /* MMCR0 */ - spr_set_rights(MMCR0, SPR_SR | SPR_SW); - /* SIA */ - spr_set_rights(SIA, SPR_SR | SPR_SW); - /* SDA */ - spr_set_rights(SDA, SPR_SR | SPR_SW); - } - /* Special registers for MPC740/745/750/755 (aka G3) & IBM 750 */ - if ((pvr & 0xFFFF0000) == 0x00080000 || - (pvr & 0xFFFF0000) == 0x70000000) { - /* HID0 */ - spr_set_rights(HID0, SPR_SR | SPR_SW); - /* HID1 */ - spr_set_rights(HID1, SPR_SR | SPR_SW); - /* IABR */ - spr_set_rights(IABR, SPR_SR | SPR_SW); - /* ICTC */ - spr_set_rights(ICTC, SPR_SR | SPR_SW); - /* L2CR */ - spr_set_rights(L2CR, SPR_SR | SPR_SW); - /* MMCR0 */ - spr_set_rights(MMCR0, SPR_SR | SPR_SW); - /* MMCR1 */ - spr_set_rights(MMCR1, SPR_SR | SPR_SW); - /* PMC1 */ - spr_set_rights(PMC1, SPR_SR | SPR_SW); - /* PMC2 */ - spr_set_rights(PMC2, SPR_SR | SPR_SW); - /* PMC3 */ - spr_set_rights(PMC3, SPR_SR | SPR_SW); - /* PMC4 */ - spr_set_rights(PMC4, SPR_SR | SPR_SW); - /* SIA */ - spr_set_rights(SIA, SPR_SR | SPR_SW); - /* SDA */ - spr_set_rights(SDA, SPR_SR | SPR_SW); - /* THRM1 */ - spr_set_rights(THRM1, SPR_SR | SPR_SW); - /* THRM2 */ - spr_set_rights(THRM2, SPR_SR | SPR_SW); - /* THRM3 */ - spr_set_rights(THRM3, SPR_SR | SPR_SW); - /* UMMCR0 */ - spr_set_rights(UMMCR0, SPR_UR | SPR_UW); - /* UMMCR1 */ - spr_set_rights(UMMCR1, SPR_UR | SPR_UW); - /* UPMC1 */ - spr_set_rights(UPMC1, SPR_UR | SPR_UW); - /* UPMC2 */ - spr_set_rights(UPMC2, SPR_UR | SPR_UW); - /* UPMC3 */ - spr_set_rights(UPMC3, SPR_UR | SPR_UW); - /* UPMC4 */ - spr_set_rights(UPMC4, SPR_UR | SPR_UW); - /* USIA */ - spr_set_rights(USIA, SPR_UR | SPR_UW); - } - /* MPC755 has special registers */ - if (pvr == 0x00083100) { - /* SPRG4 */ - spr_set_rights(SPRG4, SPR_SR | SPR_SW); - /* SPRG5 */ - spr_set_rights(SPRG5, SPR_SR | SPR_SW); - /* SPRG6 */ - spr_set_rights(SPRG6, SPR_SR | SPR_SW); - /* SPRG7 */ - spr_set_rights(SPRG7, SPR_SR | SPR_SW); - /* IBAT4U */ - spr_set_rights(IBAT4U, SPR_SR | SPR_SW); - /* IBAT4L */ - spr_set_rights(IBAT4L, SPR_SR | SPR_SW); - /* IBAT5U */ - spr_set_rights(IBAT5U, SPR_SR | SPR_SW); - /* IBAT5L */ - spr_set_rights(IBAT5L, SPR_SR | SPR_SW); - /* IBAT6U */ - spr_set_rights(IBAT6U, SPR_SR | SPR_SW); - /* IBAT6L */ - spr_set_rights(IBAT6L, SPR_SR | SPR_SW); - /* IBAT7U */ - spr_set_rights(IBAT7U, SPR_SR | SPR_SW); - /* IBAT7L */ - spr_set_rights(IBAT7L, SPR_SR | SPR_SW); - /* DBAT4U */ - spr_set_rights(DBAT4U, SPR_SR | SPR_SW); - /* DBAT4L */ - spr_set_rights(DBAT4L, SPR_SR | SPR_SW); - /* DBAT5U */ - spr_set_rights(DBAT5U, SPR_SR | SPR_SW); - /* DBAT5L */ - spr_set_rights(DBAT5L, SPR_SR | SPR_SW); - /* DBAT6U */ - spr_set_rights(DBAT6U, SPR_SR | SPR_SW); - /* DBAT6L */ - spr_set_rights(DBAT6L, SPR_SR | SPR_SW); - /* DBAT7U */ - spr_set_rights(DBAT7U, SPR_SR | SPR_SW); - /* DBAT7L */ - spr_set_rights(DBAT7L, SPR_SR | SPR_SW); - /* DMISS */ - spr_set_rights(DMISS, SPR_SR | SPR_SW); - /* DCMP */ - spr_set_rights(DCMP, SPR_SR | SPR_SW); - /* DHASH1 */ - spr_set_rights(DHASH1, SPR_SR | SPR_SW); - /* DHASH2 */ - spr_set_rights(DHASH2, SPR_SR | SPR_SW); - /* IMISS */ - spr_set_rights(IMISS, SPR_SR | SPR_SW); - /* ICMP */ - spr_set_rights(ICMP, SPR_SR | SPR_SW); - /* RPA */ - spr_set_rights(RPA, SPR_SR | SPR_SW); - /* HID2 */ - spr_set_rights(HID2, SPR_SR | SPR_SW); - /* L2PM */ - spr_set_rights(L2PM, SPR_SR | SPR_SW); - } -} - -/*****************************************************************************/ -/* PPC "main stream" common instructions (no optional ones) */ - -typedef struct ppc_proc_t { - int flags; - void *specific; -} ppc_proc_t; - -typedef struct ppc_def_t { - unsigned long pvr; - unsigned long pvr_mask; - ppc_proc_t *proc; -} ppc_def_t; - -static ppc_proc_t ppc_proc_common = { - .flags = PPC_COMMON, - .specific = NULL, -}; - -static ppc_proc_t ppc_proc_G3 = { - .flags = PPC_750, - .specific = NULL, -}; - -static ppc_def_t ppc_defs[] = -{ - /* MPC740/745/750/755 (G3) */ - { - .pvr = 0x00080000, - .pvr_mask = 0xFFFF0000, - .proc = &ppc_proc_G3, - }, - /* IBM 750FX (G3 embedded) */ - { - .pvr = 0x70000000, - .pvr_mask = 0xFFFF0000, - .proc = &ppc_proc_G3, - }, - /* Fallback (generic PPC) */ - { - .pvr = 0x00000000, - .pvr_mask = 0x00000000, - .proc = &ppc_proc_common, - }, -}; - -static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr) -{ - opcode_t *opc, *start, *end; - int i, flags; - - fill_new_table(ppc_opcodes, 0x40); - for (i = 0; ; i++) { - if ((ppc_defs[i].pvr & ppc_defs[i].pvr_mask) == - (pvr & ppc_defs[i].pvr_mask)) { - flags = ppc_defs[i].proc->flags; - break; - } - } - - if (&opc_start < &opc_end) { - start = &opc_start; - end = &opc_end; - } else { - start = &opc_end; - end = &opc_start; - } - for (opc = start + 1; opc != end; opc++) { - if ((opc->handler.type & flags) != 0) - if (register_insn(ppc_opcodes, opc) < 0) { - printf("*** ERROR initializing PPC instruction " - "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, - opc->opc3); - return -1; - } - } - fix_opcode_tables(ppc_opcodes); - - return 0; -} - +#include "translate_init.c" /*****************************************************************************/ -/* Misc PPC helpers */ - +/* Misc PowerPC helpers */ void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { +#if defined(TARGET_PPC64) || 1 +#define FILL "" +#define REGX "%016llx" +#define RGPL 4 +#define RFPL 4 +#else +#define FILL " " +#define REGX "%08llx" +#define RGPL 8 +#define RFPL 4 +#endif + int i; - cpu_fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x " - "MSR=0x%08x\n", env->nip, env->lr, env->ctr, - _load_xer(env), _load_msr(env)); + cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n", + env->nip, env->lr, env->ctr); + cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x DECR %08x\n", + do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env), + cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env)); for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - cpu_fprintf(f, "GPR%02d:", i); - cpu_fprintf(f, " %08x", env->gpr[i]); - if ((i & 7) == 7) + if ((i & (RGPL - 1)) == 0) + cpu_fprintf(f, "GPR%02d", i); + cpu_fprintf(f, " " REGX, env->gpr[i]); + if ((i & (RGPL - 1)) == (RGPL - 1)) cpu_fprintf(f, "\n"); } - cpu_fprintf(f, "CR: 0x"); + cpu_fprintf(f, "CR "); for (i = 0; i < 8; i++) cpu_fprintf(f, "%01x", env->crf[i]); cpu_fprintf(f, " ["); @@ -3141,65 +2421,22 @@ void cpu_dump_state(CPUState *env, FILE *f, a = 'E'; cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } - cpu_fprintf(f, " ] "); - cpu_fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env), - cpu_ppc_load_tbl(env)); - for (i = 0; i < 16; i++) { - if ((i & 3) == 0) - cpu_fprintf(f, "FPR%02d:", i); + cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve); + for (i = 0; i < 32; i++) { + if ((i & (RFPL - 1)) == 0) + cpu_fprintf(f, "FPR%02d", i); cpu_fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i])); - if ((i & 3) == 3) + if ((i & (RFPL - 1)) == (RFPL - 1)) cpu_fprintf(f, "\n"); } - cpu_fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n", - env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env)); - cpu_fprintf(f, "reservation 0x%08x\n", env->reserve); -} - -CPUPPCState *cpu_ppc_init(void) -{ - CPUPPCState *env; - - cpu_exec_init(); - - env = qemu_mallocz(sizeof(CPUPPCState)); - if (!env) - return NULL; -// env->spr[PVR] = 0; /* Basic PPC */ - env->spr[PVR] = 0x00080100; /* G3 CPU */ -// env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */ -// env->spr[PVR] = 0x00070100; /* IBM 750FX */ - tlb_flush(env, 1); -#if defined (DO_SINGLE_STEP) - /* Single step trace mode */ - msr_se = 1; -#endif - msr_fp = 1; /* Allow floating point exceptions */ - msr_me = 1; /* Allow machine check exceptions */ -#if defined(CONFIG_USER_ONLY) - msr_pr = 1; - cpu_ppc_register(env, 0x00080000); -#else - env->nip = 0xFFFFFFFC; -#endif - cpu_single_env = env; - return env; -} - -int cpu_ppc_register (CPUPPCState *env, uint32_t pvr) -{ - env->spr[PVR] = pvr; - if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) - return -1; - init_spr_rights(env->spr[PVR]); + cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL + "SDR1 " REGX "\n", + env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1); - return 0; -} - -void cpu_ppc_close(CPUPPCState *env) -{ - /* Should also remove all opcode tables... */ - free(env); +#undef REGX +#undef RGPL +#undef RFPL +#undef FILL } /*****************************************************************************/ @@ -3219,6 +2456,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.nip = pc_start; ctx.tb = tb; ctx.exception = EXCP_NONE; + ctx.spr_cb = env->spr_cb; #if defined(CONFIG_USER_ONLY) ctx.mem_idx = msr_le; #else @@ -3226,7 +2464,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le; #endif ctx.fpu_enabled = msr_fp; -#if defined (DO_SINGLE_STEP) +#if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; #endif @@ -3264,7 +2502,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } #endif ctx.nip += 4; - table = ppc_opcodes; + table = env->opcodes; handler = table[opc1(ctx.opcode)]; if (is_indirect_opcode(handler)) { table = ind_table(handler); @@ -3322,9 +2560,13 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, RET_EXCP(ctxp, EXCP_TRACE, 0); } /* if we reach a page boundary, stop generation */ - if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) + if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { break; } +#if defined (DO_SINGLE_STEP) + break; +#endif + } if (ctx.exception == EXCP_NONE) { gen_op_b((unsigned long)ctx.tb, ctx.nip); } else if (ctx.exception != EXCP_BRANCH) { diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c new file mode 100644 index 000000000..624527d5f --- /dev/null +++ b/target-ppc/translate_init.c @@ -0,0 +1,2069 @@ +/* + * PowerPC CPU initialization for qemu. + * + * Copyright (c) 2003-2005 Jocelyn Mayer + * + * 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 + */ + +/* A lot of PowerPC definition have been included here. + * Most of them are not usable for now but have been kept + * inside "#if defined(TODO) ... #endif" statements to make tests easier. + */ + +//#define PPC_DUMP_CPU +//#define PPC_DEBUG_SPR + +struct ppc_def_t { + const unsigned char *name; + uint32_t pvr; + uint32_t pvr_mask; + uint32_t insns_flags; + uint32_t flags; + uint64_t msr_mask; +}; + +/* Generic callbacks: + * do nothing but store/retrieve spr value + */ +static void spr_read_generic (void *opaque, int sprn) +{ + gen_op_load_spr(sprn); +} + +static void spr_write_generic (void *opaque, int sprn) +{ + gen_op_store_spr(sprn); +} + +/* SPR common to all PPC */ +/* XER */ +static void spr_read_xer (void *opaque, int sprn) +{ + gen_op_load_xer(); +} + +static void spr_write_xer (void *opaque, int sprn) +{ + gen_op_store_xer(); +} + +/* LR */ +static void spr_read_lr (void *opaque, int sprn) +{ + gen_op_load_lr(); +} + +static void spr_write_lr (void *opaque, int sprn) +{ + gen_op_store_lr(); +} + +/* CTR */ +static void spr_read_ctr (void *opaque, int sprn) +{ + gen_op_load_ctr(); +} + +static void spr_write_ctr (void *opaque, int sprn) +{ + gen_op_store_ctr(); +} + +/* User read access to SPR */ +/* USPRx */ +/* UMMCRx */ +/* UPMCx */ +/* USIA */ +/* UDECR */ +static void spr_read_ureg (void *opaque, int sprn) +{ + gen_op_load_spr(sprn + 0x10); +} + +/* SPR common to all non-embedded PPC (ie not 4xx) */ +/* DECR */ +static void spr_read_decr (void *opaque, int sprn) +{ + gen_op_load_decr(); +} + +static void spr_write_decr (void *opaque, int sprn) +{ + gen_op_store_decr(); +} + +/* SPR common to all non-embedded PPC, except 601 */ +/* Time base */ +static void spr_read_tbl (void *opaque, int sprn) +{ + gen_op_load_tbl(); +} + +static void spr_write_tbl (void *opaque, int sprn) +{ + gen_op_store_tbl(); +} + +static void spr_read_tbu (void *opaque, int sprn) +{ + gen_op_load_tbu(); +} + +static void spr_write_tbu (void *opaque, int sprn) +{ + gen_op_store_tbu(); +} + +/* IBAT0U...IBAT0U */ +/* IBAT0L...IBAT7L */ +static void spr_read_ibat (void *opaque, int sprn) +{ + gen_op_load_ibat(sprn & 1, (sprn - SPR_IBAT0U) / 2); +} + +static void spr_read_ibat_h (void *opaque, int sprn) +{ + gen_op_load_ibat(sprn & 1, (sprn - SPR_IBAT4U) / 2); +} + +static void spr_write_ibatu (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_ibatu((sprn - SPR_IBAT0U) / 2); + RET_STOP(ctx); +} + +static void spr_write_ibatu_h (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_ibatu((sprn - SPR_IBAT4U) / 2); + RET_STOP(ctx); +} + +static void spr_write_ibatl (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_ibatl((sprn - SPR_IBAT0L) / 2); + RET_STOP(ctx); +} + +static void spr_write_ibatl_h (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_ibatl((sprn - SPR_IBAT4L) / 2); + RET_STOP(ctx); +} + +/* DBAT0U...DBAT7U */ +/* DBAT0L...DBAT7L */ +static void spr_read_dbat (void *opaque, int sprn) +{ + gen_op_load_dbat(sprn & 1, (sprn - SPR_DBAT0U) / 2); +} + +static void spr_read_dbat_h (void *opaque, int sprn) +{ + gen_op_load_dbat(sprn & 1, (sprn - SPR_DBAT4U) / 2); +} + +static void spr_write_dbatu (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_dbatu((sprn - SPR_DBAT0U) / 2); + RET_STOP(ctx); +} + +static void spr_write_dbatu_h (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_dbatu((sprn - SPR_DBAT4U) / 2); + RET_STOP(ctx); +} + +static void spr_write_dbatl (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_dbatl((sprn - SPR_DBAT0L) / 2); + RET_STOP(ctx); +} + +static void spr_write_dbatl_h (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_dbatl((sprn - SPR_DBAT4L) / 2); + RET_STOP(ctx); +} + +/* SDR1 */ +static void spr_read_sdr1 (void *opaque, int sprn) +{ + gen_op_load_sdr1(); +} + +static void spr_write_sdr1 (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_sdr1(); + RET_STOP(ctx); +} + +static void spr_write_pir (void *opaque, int sprn) +{ + gen_op_store_pir(); +} + +static inline void spr_register (CPUPPCState *env, int num, + const unsigned char *name, + void (*uea_read)(void *opaque, int sprn), + void (*uea_write)(void *opaque, int sprn), + void (*oea_read)(void *opaque, int sprn), + void (*oea_write)(void *opaque, int sprn), + target_ulong initial_value) +{ + ppc_spr_t *spr; + + spr = &env->spr_cb[num]; + if (spr->name != NULL ||env-> spr[num] != 0x00000000 || + spr->uea_read != NULL || spr->uea_write != NULL || + spr->oea_read != NULL || spr->oea_write != NULL) { + printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num); + exit(1); + } +#if defined(PPC_DEBUG_SPR) + printf("*** register spr %d (%03x) %s val %08llx\n", num, num, name, + (unsigned long long)initial_value); +#endif + spr->name = name; + spr->uea_read = uea_read; + spr->uea_write = uea_write; + spr->oea_read = oea_read; + spr->oea_write = oea_write; + env->spr[num] = initial_value; +} + +/* Generic PowerPC SPRs */ +static void gen_spr_generic (CPUPPCState *env) +{ + /* Integer processing */ + spr_register(env, SPR_XER, "XER", + &spr_read_xer, &spr_write_xer, + &spr_read_xer, &spr_write_xer, + 0x00000000); + /* Branch contol */ + spr_register(env, SPR_LR, "LR", + &spr_read_lr, &spr_write_lr, + &spr_read_lr, &spr_write_lr, + 0x00000000); + spr_register(env, SPR_CTR, "CTR", + &spr_read_ctr, &spr_write_ctr, + &spr_read_ctr, &spr_write_ctr, + 0x00000000); + /* Interrupt processing */ + spr_register(env, SPR_SRR0, "SRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SRR1, "SRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Processor control */ + spr_register(env, SPR_SPRG0, "SPRG0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG1, "SPRG1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG2, "SPRG2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG3, "SPRG3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR common to all non-embedded PowerPC, including 601 */ +static void gen_spr_ne_601 (CPUPPCState *env) +{ + /* Exception processing */ + spr_register(env, SPR_DSISR, "DSISR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_DAR, "DAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Timer */ + spr_register(env, SPR_DECR, "DECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_decr, &spr_write_decr, + 0x00000000); + /* Memory management */ + spr_register(env, SPR_SDR1, "SDR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_sdr1, &spr_write_sdr1, + 0x00000000); +} + +/* BATs 0-3 */ +static void gen_low_BATs (CPUPPCState *env) +{ + spr_register(env, SPR_IBAT0U, "IBAT0U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatu, + 0x00000000); + spr_register(env, SPR_IBAT0L, "IBAT0L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatl, + 0x00000000); + spr_register(env, SPR_IBAT1U, "IBAT1U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatu, + 0x00000000); + spr_register(env, SPR_IBAT1L, "IBAT1L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatl, + 0x00000000); + spr_register(env, SPR_IBAT2U, "IBAT2U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatu, + 0x00000000); + spr_register(env, SPR_IBAT2L, "IBAT2L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatl, + 0x00000000); + spr_register(env, SPR_IBAT3U, "IBAT3U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatu, + 0x00000000); + spr_register(env, SPR_IBAT3L, "IBAT3L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat, &spr_write_ibatl, + 0x00000000); + spr_register(env, SPR_DBAT0U, "DBAT0U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatu, + 0x00000000); + spr_register(env, SPR_DBAT0L, "DBAT0L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatl, + 0x00000000); + spr_register(env, SPR_DBAT1U, "DBAT1U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatu, + 0x00000000); + spr_register(env, SPR_DBAT1L, "DBAT1L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatl, + 0x00000000); + spr_register(env, SPR_DBAT2U, "DBAT2U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatu, + 0x00000000); + spr_register(env, SPR_DBAT2L, "DBAT2L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatl, + 0x00000000); + spr_register(env, SPR_DBAT3U, "DBAT3U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatu, + 0x00000000); + spr_register(env, SPR_DBAT3L, "DBAT3L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat, &spr_write_dbatl, + 0x00000000); + env->nb_BATs = 4; +} + +/* BATs 4-7 */ +static void gen_high_BATs (CPUPPCState *env) +{ + spr_register(env, SPR_IBAT4U, "IBAT4U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatu_h, + 0x00000000); + spr_register(env, SPR_IBAT4L, "IBAT4L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatl_h, + 0x00000000); + spr_register(env, SPR_IBAT5U, "IBAT5U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatu_h, + 0x00000000); + spr_register(env, SPR_IBAT5L, "IBAT5L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatl_h, + 0x00000000); + spr_register(env, SPR_IBAT6U, "IBAT6U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatu_h, + 0x00000000); + spr_register(env, SPR_IBAT6L, "IBAT6L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatl_h, + 0x00000000); + spr_register(env, SPR_IBAT7U, "IBAT7U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatu_h, + 0x00000000); + spr_register(env, SPR_IBAT7L, "IBAT7L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_ibat_h, &spr_write_ibatl_h, + 0x00000000); + spr_register(env, SPR_DBAT4U, "DBAT4U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatu_h, + 0x00000000); + spr_register(env, SPR_DBAT4L, "DBAT4L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatl_h, + 0x00000000); + spr_register(env, SPR_DBAT5U, "DBAT5U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatu_h, + 0x00000000); + spr_register(env, SPR_DBAT5L, "DBAT5L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatl_h, + 0x00000000); + spr_register(env, SPR_DBAT6U, "DBAT6U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatu_h, + 0x00000000); + spr_register(env, SPR_DBAT6L, "DBAT6L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatl_h, + 0x00000000); + spr_register(env, SPR_DBAT7U, "DBAT7U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatu_h, + 0x00000000); + spr_register(env, SPR_DBAT7L, "DBAT7L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_dbat_h, &spr_write_dbatl_h, + 0x00000000); + env->nb_BATs = 8; +} + +/* Generic PowerPC time base */ +static void gen_tbl (CPUPPCState *env) +{ + spr_register(env, SPR_VTBL, "TBL", + &spr_read_tbl, SPR_NOACCESS, + &spr_read_tbl, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_TBL, "TBL", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_tbl, + 0x00000000); + spr_register(env, SPR_VTBU, "TBU", + &spr_read_tbu, SPR_NOACCESS, + &spr_read_tbu, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_TBU, "TBU", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_tbu, + 0x00000000); +} + +/* SPR common to all 7xx PowerPC implementations */ +static void gen_spr_7xx (CPUPPCState *env) +{ + /* Breakpoints */ + /* XXX : not implemented */ + spr_register(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Cache management */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTC, "ICTC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Performance monitors */ + /* XXX : not implemented */ + spr_register(env, SPR_MMCR0, "MMCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MMCR1, "MMCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC1, "PMC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC2, "PMC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC3, "PMC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC4, "PMC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_SIA, "SIA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_UMMCR0, "UMMCR0", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_UMMCR1, "UMMCR1", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_UPMC1, "UPMC1", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_UPMC2, "UPMC2", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_UPMC3, "UPMC3", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_UPMC4, "UPMC4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_USIA, "USIA", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Thermal management */ + /* XXX : not implemented */ + spr_register(env, SPR_THRM1, "THRM1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_THRM2, "THRM2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_THRM3, "THRM3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 604 implementation */ +static void gen_spr_604 (CPUPPCState *env) +{ + /* Processor identification */ + spr_register(env, SPR_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* Breakpoints */ + /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Performance counters */ + /* XXX : not implemented */ + spr_register(env, SPR_MMCR0, "MMCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MMCR1, "MMCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC1, "PMC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC2, "PMC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC3, "PMC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC4, "PMC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_SIA, "SIA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_SDA, "SDA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +// XXX: TODO (64 bits PPC sprs) +/* + * ASR => SPR 280 (64 bits) + * FPECR => SPR 1022 (?) + * VRSAVE => SPR 256 (Altivec) + * SCOMC => SPR 276 (64 bits ?) + * SCOMD => SPR 277 (64 bits ?) + * HSPRG0 => SPR 304 (hypervisor) + * HSPRG1 => SPR 305 (hypervisor) + * HDEC => SPR 310 (hypervisor) + * HIOR => SPR 311 (hypervisor) + * RMOR => SPR 312 (970) + * HRMOR => SPR 313 (hypervisor) + * HSRR0 => SPR 314 (hypervisor) + * HSRR1 => SPR 315 (hypervisor) + * LPCR => SPR 316 (970) + * LPIDR => SPR 317 (970) + * ... and more (thermal management, performance counters, ...) + */ + +static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) +{ + /* Default MMU definitions */ + env->nb_BATs = -1; + env->nb_tlb = 0; + env->nb_ways = 0; + /* XXX: missing: + * 32 bits PPC: + * - MPC5xx(x) + * - MPC8xx(x) + * - RCPU (MPC5xx) + */ + spr_register(env, SPR_PVR, "PVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + def->pvr); + switch (def->pvr & def->pvr_mask) { + case CPU_PPC_604: /* PPC 604 */ + case CPU_PPC_604E: /* PPC 604e */ + case CPU_PPC_604R: /* PPC 604r */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_604(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_74x: /* PPC 740 / 750 */ + case CPU_PPC_74xP: /* PPC 740P / 750P */ + case CPU_PPC_750CXE: /* IBM PPC 750cxe */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_7xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_750FX: /* IBM PPC 750 FX */ + case CPU_PPC_750GX: /* IBM PPC 750 GX */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ + gen_high_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_7xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + default: + gen_spr_generic(env); + break; + } + if (env->nb_BATs == -1) + env->nb_BATs = 4; +} + +#if defined(PPC_DUMP_CPU) +static void dump_sprs (CPUPPCState *env) +{ + ppc_spr_t *spr; + uint32_t pvr = env->spr[SPR_PVR]; + uint32_t sr, sw, ur, uw; + int i, j, n; + + printf("* SPRs for PVR=%08x\n", pvr); + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + n = (i << 5) | j; + spr = &env->spr_cb[n]; + sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS; + sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS; + uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS; + ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS; + if (sw || sr || uw || ur) { + printf("%4d (%03x) %8s s%c%c u%c%c\n", + (i << 5) | j, (i << 5) | j, spr->name, + sw ? 'w' : '-', sr ? 'r' : '-', + uw ? 'w' : '-', ur ? 'r' : '-'); + } + } + } + fflush(stdout); + fflush(stderr); +} +#endif + +/*****************************************************************************/ +#include +#include + +int fflush (FILE *stream); + +/* Opcode types */ +enum { + PPC_DIRECT = 0, /* Opcode routine */ + PPC_INDIRECT = 1, /* Indirect opcode table */ +}; + +static inline int is_indirect_opcode (void *handler) +{ + return ((unsigned long)handler & 0x03) == PPC_INDIRECT; +} + +static inline opc_handler_t **ind_table(void *handler) +{ + return (opc_handler_t **)((unsigned long)handler & ~3); +} + +/* Instruction table creation */ +/* Opcodes tables creation */ +static void fill_new_table (opc_handler_t **table, int len) +{ + int i; + + for (i = 0; i < len; i++) + table[i] = &invalid_handler; +} + +static int create_new_table (opc_handler_t **table, unsigned char idx) +{ + opc_handler_t **tmp; + + tmp = malloc(0x20 * sizeof(opc_handler_t)); + if (tmp == NULL) + return -1; + fill_new_table(tmp, 0x20); + table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT); + + return 0; +} + +static int insert_in_table (opc_handler_t **table, unsigned char idx, + opc_handler_t *handler) +{ + if (table[idx] != &invalid_handler) + return -1; + table[idx] = handler; + + return 0; +} + +static int register_direct_insn (opc_handler_t **ppc_opcodes, + unsigned char idx, opc_handler_t *handler) +{ + if (insert_in_table(ppc_opcodes, idx, handler) < 0) { + printf("*** ERROR: opcode %02x already assigned in main " + "opcode table\n", idx); + return -1; + } + + return 0; +} + +static int register_ind_in_table (opc_handler_t **table, + unsigned char idx1, unsigned char idx2, + opc_handler_t *handler) +{ + if (table[idx1] == &invalid_handler) { + if (create_new_table(table, idx1) < 0) { + printf("*** ERROR: unable to create indirect table " + "idx=%02x\n", idx1); + return -1; + } + } else { + if (!is_indirect_opcode(table[idx1])) { + printf("*** ERROR: idx %02x already assigned to a direct " + "opcode\n", idx1); + return -1; + } + } + if (handler != NULL && + insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { + printf("*** ERROR: opcode %02x already assigned in " + "opcode table %02x\n", idx2, idx1); + return -1; + } + + return 0; +} + +static int register_ind_insn (opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, + opc_handler_t *handler) +{ + int ret; + + ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler); + + return ret; +} + +static int register_dblind_insn (opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, + unsigned char idx3, opc_handler_t *handler) +{ + if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { + printf("*** ERROR: unable to join indirect table idx " + "[%02x-%02x]\n", idx1, idx2); + return -1; + } + if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, + handler) < 0) { + printf("*** ERROR: unable to insert opcode " + "[%02x-%02x-%02x]\n", idx1, idx2, idx3); + return -1; + } + + return 0; +} + +static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn) +{ + if (insn->opc2 != 0xFF) { + if (insn->opc3 != 0xFF) { + if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, + insn->opc3, &insn->handler) < 0) + return -1; + } else { + if (register_ind_insn(ppc_opcodes, insn->opc1, + insn->opc2, &insn->handler) < 0) + return -1; + } + } else { + if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) + return -1; + } + + return 0; +} + +static int test_opcode_table (opc_handler_t **table, int len) +{ + int i, count, tmp; + + for (i = 0, count = 0; i < len; i++) { + /* Consistency fixup */ + if (table[i] == NULL) + table[i] = &invalid_handler; + if (table[i] != &invalid_handler) { + if (is_indirect_opcode(table[i])) { + tmp = test_opcode_table(ind_table(table[i]), 0x20); + if (tmp == 0) { + free(table[i]); + table[i] = &invalid_handler; + } else { + count++; + } + } else { + count++; + } + } + } + + return count; +} + +static void fix_opcode_tables (opc_handler_t **ppc_opcodes) +{ + if (test_opcode_table(ppc_opcodes, 0x40) == 0) + printf("*** WARNING: no opcode defined !\n"); +} + +/*****************************************************************************/ +static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) +{ + opcode_t *opc, *start, *end; + + fill_new_table(env->opcodes, 0x40); +#if defined(PPC_DUMP_CPU) + printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name); +#endif + if (&opc_start < &opc_end) { + start = &opc_start; + end = &opc_end; + } else { + start = &opc_end; + end = &opc_start; + } + for (opc = start + 1; opc != end; opc++) { + if ((opc->handler.type & def->insns_flags) != 0) { + if (register_insn(env->opcodes, opc) < 0) { + printf("*** ERROR initializing PPC instruction " + "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + opc->opc3); + return -1; + } +#if defined(PPC_DUMP_CPU) + if (opc1 != 0x00) { + if (opc->opc3 == 0xFF) { + if (opc->opc2 == 0xFF) { + printf(" %02x -- -- (%2d ----) : %s\n", + opc->opc1, opc->opc1, opc->oname); + } else { + printf(" %02x %02x -- (%2d %4d) : %s\n", + opc->opc1, opc->opc2, opc->opc1, opc->opc2, + opc->oname); + } + } else { + printf(" %02x %02x %02x (%2d %4d) : %s\n", + opc->opc1, opc->opc2, opc->opc3, + opc->opc1, (opc->opc3 << 5) | opc->opc2, + opc->oname); + } + } +#endif + } + } + fix_opcode_tables(env->opcodes); + fflush(stdout); + fflush(stderr); + + return 0; +} + +int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) +{ + env->msr_mask = def->msr_mask; + env->flags = def->flags; + if (create_ppc_opcodes(env, def) < 0) { + printf("Error creating opcodes table\n"); + fflush(stdout); + fflush(stderr); + return -1; + } + init_ppc_proc(env, def); +#if defined(PPC_DUMP_CPU) + dump_sprs(env); +#endif + fflush(stdout); + fflush(stderr); + + return 0; +} + +CPUPPCState *cpu_ppc_init(void) +{ + CPUPPCState *env; + + cpu_exec_init(); + + env = qemu_mallocz(sizeof(CPUPPCState)); + if (!env) + return NULL; + tlb_flush(env, 1); +#if defined (DO_SINGLE_STEP) && 0 + /* Single step trace mode */ + msr_se = 1; + msr_be = 1; +#endif + msr_fp = 1; /* Allow floating point exceptions */ + msr_me = 1; /* Allow machine check exceptions */ +#if defined(CONFIG_USER_ONLY) + msr_pr = 1; +#else + env->nip = 0xFFFFFFFC; +#endif + do_compute_hflags(env); + env->reserve = -1; + cpu_single_env = env; + return env; +} + +void cpu_ppc_close(CPUPPCState *env) +{ + /* Should also remove all opcode tables... */ + free(env); +} + +/*****************************************************************************/ +/* PowerPC CPU definitions */ +static ppc_def_t ppc_defs[] = +{ + /* Embedded PPC */ +#if defined (TODO) + /* PPC 401 */ + { + .name = "401", + .pvr = CPU_PPC_401, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* IOP480 (401 microcontroler) */ + { + .name = "iop480", + .pvr = CPU_PPC_IOP480, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* PPC 403 GA */ + { + .name = "403ga", + .pvr = CPU_PPC_403GA, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, +#endif +#if defined (TODO) + /* PPC 403 GB */ + { + .name = "403gb", + .pvr = CPU_PPC_403GB, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, +#endif +#if defined (TODO) + /* PPC 403 GC */ + { + .name = "403gc", + .pvr = CPU_PPC_403GC, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, +#endif +#if defined (TODO) + /* PPC 403 GCX */ + { + .name = "403gcx", + .pvr = CPU_PPC_403GCX, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, +#endif +#if defined (TODO) + /* PPC 405 CR */ + { + .name = "405cr", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* PPC 405 GP */ + { + .name = "405gp", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* PPC 405 EP */ + { + .name = "405ep", + .pvr = CPU_PPC_405EP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* PPC 405 GPR */ + { + .name = "405gpr", + .pvr = CPU_PPC_405GPR, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* PPC 405 D2 */ + { + .name = "405d2", + .pvr = CPU_PPC_405D2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* PPC 405 D4 */ + { + .name = "405d4", + .pvr = CPU_PPC_405D4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* Npe405 H */ + { + .name = "Npe405H", + .pvr = CPU_PPC_NPE405H, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* Npe405 L */ + { + .name = "Npe405L", + .pvr = CPU_PPC_NPE405L, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* STB03xx */ + { + .name = "STB03", + .pvr = CPU_PPC_STB03, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* STB04xx */ + { + .name = "STB04", + .pvr = CPU_PPC_STB04, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* STB25xx */ + { + .name = "STB25", + .pvr = CPU_PPC_STB25, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* PPC 440 EP */ + { + .name = "440ep", + .pvr = CPU_PPC_440EP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, +#endif +#if defined (TODO) + /* PPC 440 GP */ + { + .name = "440gp", + .pvr = CPU_PPC_440GP, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, +#endif +#if defined (TODO) + /* PPC 440 GX */ + { + .name = "440gx", + .pvr = CPU_PPC_440GX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, +#endif + + /* 32 bits "classic" powerpc */ +#if defined (TODO) + /* PPC 601 */ + { + .name = "601", + .pvr = CPU_PPC_601, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_601, + .flags = PPC_FLAGS_601, + .msr_mask = 0x000000000000FD70, + }, +#endif +#if defined (TODO) + /* PPC 602 */ + { + .name = "602", + .pvr = CPU_PPC_602, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_602, + .flags = PPC_FLAGS_602, + .msr_mask = 0x0000000000C7FF73, + }, +#endif +#if defined (TODO) + /* PPC 603 */ + { + .name = "603", + .pvr = CPU_PPC_603, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, +#endif +#if defined (TODO) + /* PPC 603e */ + { + .name = "603e", + .pvr = CPU_PPC_603E, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + { + .name = "Stretch", + .pvr = CPU_PPC_603E, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, +#endif +#if defined (TODO) + /* PPC 603ev */ + { + .name = "603ev", + .pvr = CPU_PPC_603EV, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, +#endif +#if defined (TODO) + /* PPC 603r */ + { + .name = "603r", + .pvr = CPU_PPC_603R, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + { + .name = "Goldeneye", + .pvr = CPU_PPC_603R, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, +#endif +#if defined (TODO) + /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ + { + .name = "G2", + .pvr = CPU_PPC_G2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { /* Same as G2, with LE mode support */ + .name = "G2le", + .pvr = CPU_PPC_G2LE, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, +#endif + /* PPC 604 */ + { + .name = "604", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* PPC 604e */ + { + .name = "604e", + .pvr = CPU_PPC_604E, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* PPC 604r */ + { + .name = "604r", + .pvr = CPU_PPC_604R, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* generic G3 */ + { + .name = "G3", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* MPC740 (G3) */ + { + .name = "740", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Arthur", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#endif +#if defined (TODO) + /* MPC745 (G3) */ + { + .name = "745", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Goldfinger", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, +#endif + /* MPC750 (G3) */ + { + .name = "750", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* MPC755 (G3) */ + { + .name = "755", + .pvr = CPU_PPC_755, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, +#endif +#if defined (TODO) + /* MPC740P (G3) */ + { + .name = "740p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Conan/Doyle", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#endif +#if defined (TODO) + /* MPC745P (G3) */ + { + .name = "745p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, +#endif + /* MPC750P (G3) */ + { + .name = "750p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* MPC755P (G3) */ + { + .name = "755p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, +#endif + /* IBM 750CXe (G3 embedded) */ + { + .name = "750cxe", + .pvr = CPU_PPC_750CXE, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* IBM 750FX (G3 embedded) */ + { + .name = "750fx", + .pvr = CPU_PPC_750FX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* IBM 750GX (G3 embedded) */ + { + .name = "750gx", + .pvr = CPU_PPC_750GX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* generic G4 */ + { + .name = "G4", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif +#if defined (TODO) + /* PPC 7400 (G4) */ + { + .name = "7400", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Max", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif +#if defined (TODO) + /* PPC 7410 (G4) */ + { + .name = "7410", + .pvr = CPU_PPC_7410, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Nitro", + .pvr = CPU_PPC_7410, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif + /* XXX: 7441 */ + /* XXX: 7445 */ + /* XXX: 7447 */ + /* XXX: 7447A */ +#if defined (TODO) + /* PPC 7450 (G4) */ + { + .name = "7450", + .pvr = CPU_PPC_7450, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Vger", + .pvr = CPU_PPC_7450, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif + /* XXX: 7451 */ +#if defined (TODO) + /* PPC 7455 (G4) */ + { + .name = "7455", + .pvr = CPU_PPC_7455, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 6", + .pvr = CPU_PPC_7455, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif +#if defined (TODO) + /* PPC 7457 (G4) */ + { + .name = "7457", + .pvr = CPU_PPC_7457, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 7", + .pvr = CPU_PPC_7457, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif +#if defined (TODO) + /* PPC 7457A (G4) */ + { + .name = "7457A", + .pvr = CPU_PPC_7457A, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 7 PM", + .pvr = CPU_PPC_7457A, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif + /* 64 bits PPC */ +#if defined (TODO) + /* PPC 620 */ + { + .name = "620", + .pvr = CPU_PPC_620, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_620, + .flags = PPC_FLAGS_620, + .msr_mask = 0x800000000005FF73, + }, +#endif +#if defined (TODO) + /* PPC 630 (POWER3) */ + { + .name = "630", + .pvr = CPU_PPC_630, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_630, + .flags = PPC_FLAGS_630, + .msr_mask = xxx, + } + { + .name = "POWER3", + .pvr = CPU_PPC_630, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_630, + .flags = PPC_FLAGS_630, + .msr_mask = xxx, + } +#endif +#if defined (TODO) + /* PPC 631 (Power 3+)*/ + { + .name = "631", + .pvr = CPU_PPC_631, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_631, + .flags = PPC_FLAGS_631, + .msr_mask = xxx, + }, + { + .name = "POWER3+", + .pvr = CPU_PPC_631, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_631, + .flags = PPC_FLAGS_631, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER4 */ + { + .name = "POWER4", + .pvr = CPU_PPC_POWER4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER4, + .flags = PPC_FLAGS_POWER4, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER4p */ + { + .name = "POWER4+", + .pvr = CPU_PPC_POWER4P, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER4, + .flags = PPC_FLAGS_POWER4, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER5 */ + { + .name = "POWER5", + .pvr = CPU_PPC_POWER5, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER5, + .flags = PPC_FLAGS_POWER5, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER5+ */ + { + .name = "POWER5+", + .pvr = CPU_PPC_POWER5P, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER5, + .flags = PPC_FLAGS_POWER5, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* PPC 970 */ + { + .name = "970", + .pvr = CPU_PPC_970, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_970, + .flags = PPC_FLAGS_970, + .msr_mask = 0x900000000204FF36, + }, +#endif +#if defined (TODO) + /* PPC 970FX (G5) */ + { + .name = "970fx", + .pvr = CPU_PPC_970FX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_970FX, + .flags = PPC_FLAGS_970FX, + .msr_mask = 0x800000000204FF36, + }, +#endif +#if defined (TODO) + /* RS64 (Apache/A35) */ + /* This one seems to support the whole POWER2 instruction set + * and the PowerPC 64 one. + */ + { + .name = "RS64", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "Apache", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "A35", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-II (NorthStar/A50) */ + { + .name = "RS64-II", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "NortStar", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "A50", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-III (Pulsar) */ + { + .name = "RS64-III", + .pvr = CPU_PPC_RS64III, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "Pulsar", + .pvr = CPU_PPC_RS64III, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-IV (IceStar/IStar/SStar) */ + { + .name = "RS64-IV", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "IceStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "IStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "SStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif + /* POWER */ +#if defined (TODO) + /* Original POWER */ + { + .name = "POWER", + .pvr = CPU_POWER, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER, + .flags = PPC_FLAGS_POWER, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER2 */ + { + .name = "POWER2", + .pvr = CPU_POWER2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER, + .flags = PPC_FLAGS_POWER, + .msr_mask = xxx, + }, +#endif + /* Generic PowerPCs */ +#if defined (TODO) + { + .name = "ppc64", + .pvr = CPU_PPC_970, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_PPC64, + .flags = PPC_FLAGS_PPC64, + .msr_mask = 0xA00000000204FF36, + }, +#endif + { + .name = "ppc32", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_PPC32, + .flags = PPC_FLAGS_PPC32, + .msr_mask = 0x000000000005FF77, + }, + /* Fallback */ + { + .name = "ppc", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_PPC32, + .flags = PPC_FLAGS_PPC32, + .msr_mask = 0x000000000005FF77, + }, +}; + +int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) +{ + int i, ret; + + ret = -1; + *def = NULL; + for (i = 0; strcmp(ppc_defs[i].name, "ppc") != 0; i++) { + if (strcasecmp(name, ppc_defs[i].name) == 0) { + *def = &ppc_defs[i]; + ret = 0; + break; + } + } + + return ret; +} + +int ppc_find_by_pvr (uint32_t pvr, ppc_def_t **def) +{ + int i, ret; + + ret = -1; + *def = NULL; + for (i = 0; ppc_defs[i].name != NULL; i++) { + if ((pvr & ppc_defs[i].pvr_mask) == + (ppc_defs[i].pvr & ppc_defs[i].pvr_mask)) { + *def = &ppc_defs[i]; + ret = 0; + break; + } + } + + return ret; +} + +void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i; + + for (i = 0; ; i++) { + (*cpu_fprintf)(f, "PowerPC '%s' PVR %08x mask %08x\n", + ppc_defs[i].name, + ppc_defs[i].pvr, ppc_defs[i].pvr_mask); + if (strcmp(ppc_defs[i].name, "ppc") == 0) + break; + } +} -- cgit v1.2.3 From fa296b0fb4ceb0a2535bce201a76f1c00ca21468 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 22:04:06 +0000 Subject: PIC fix - changed back TB frequency to 100 MHz git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1490 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 4437911bd..515806fbb 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -307,8 +307,8 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, } cpu_ppc_register(cpu_single_env, def); - /* Set time-base frequency to 10 Mhz */ - cpu_ppc_tb_init(cpu_single_env, 10UL * 1000UL * 1000UL); + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); cpu_single_env->osi_call = vga_osi_call; @@ -328,7 +328,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ - pic_init(pic_irq_request, NULL); + isa_pic = pic_init(pic_irq_request, NULL); /* XXX: use Mac Serial port */ serial_init(0x3f8, 4, serial_hds[0]); @@ -370,7 +370,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ - pic_init(pic_irq_request, NULL); + isa_pic = pic_init(pic_irq_request, NULL); /* XXX: use Mac Serial port */ serial_init(0x3f8, 4, serial_hds[0]); -- cgit v1.2.3 From f68c781c2d08fec54ae460749b76b422c2a1921f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 22:07:19 +0000 Subject: simplified git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1491 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 68 --------------------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/Makefile.target b/Makefile.target index 59ce7eb49..74b5da830 100644 --- a/Makefile.target +++ b/Makefile.target @@ -44,78 +44,10 @@ endif ifdef CONFIG_USER_ONLY PROGS=$(QEMU_USER) else -ifeq ($(TARGET_ARCH), i386) - -ifeq ($(ARCH), i386) PROGS+=$(QEMU_SYSTEM) ifndef CONFIG_SOFTMMU CONFIG_STATIC=y endif -else -# the system emulator using soft mmu is portable -ifdef CONFIG_SOFTMMU -PROGS+=$(QEMU_SYSTEM) -endif -endif # ARCH != i386 - -endif # TARGET_ARCH = i386 - -ifeq ($(TARGET_ARCH), x86_64) -ifdef CONFIG_SOFTMMU -PROGS+=$(QEMU_SYSTEM) -endif -endif # TARGET_ARCH = x86_64 - -ifeq ($(TARGET_ARCH), ppc) - -ifeq ($(ARCH), ppc) -PROGS+=$(QEMU_SYSTEM) -endif - -endif # TARGET_ARCH = ppc - -ifeq ($(TARGET_ARCH), mips) - -ifeq ($(ARCH), i386) -ifdef CONFIG_SOFTMMU -PROGS+=$(QEMU_SYSTEM) -endif -endif # ARCH = i386 - -ifeq ($(ARCH), x86_64) -ifdef CONFIG_SOFTMMU -PROGS+=$(QEMU_SYSTEM) -endif -endif # ARCH = x86_64 - -endif # TARGET_ARCH = mips - -ifeq ($(TARGET_ARCH), sparc) - -ifeq ($(ARCH), ppc) -PROGS+=$(QEMU_SYSTEM) -endif - -ifeq ($(ARCH), i386) -ifdef CONFIG_SOFTMMU -PROGS+=$(QEMU_SYSTEM) -endif -endif # ARCH = i386 - -ifeq ($(ARCH), x86_64) -ifdef CONFIG_SOFTMMU -PROGS+=$(QEMU_SYSTEM) -endif -endif # ARCH = x86_64 - -endif # TARGET_ARCH = sparc - -ifeq ($(TARGET_ARCH), sparc64) -ifdef CONFIG_SOFTMMU -PROGS+=$(QEMU_SYSTEM) -endif -endif # TARGET_ARCH = sparc64 - endif # !CONFIG_USER_ONLY ifdef CONFIG_STATIC -- cgit v1.2.3 From 2be0071f22f5719eb5e2800f070547227ba37e5a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 2 Jul 2005 22:09:27 +0000 Subject: simplified PowerPC exception handling (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1492 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 6 +- linux-user/main.c | 45 +---- target-ppc/cpu.h | 116 ++++++------ target-ppc/helper.c | 502 ++++++++++++++++++++++++++++++++++++++----------- target-ppc/op.c | 20 +- target-ppc/op_helper.c | 6 - target-ppc/translate.c | 11 +- 7 files changed, 482 insertions(+), 224 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index c58d27139..83d1748e2 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -68,9 +68,9 @@ typedef uint64_t target_phys_addr_t; #define HOST_LONG_SIZE (HOST_LONG_BITS / 8) -#define EXCP_INTERRUPT 256 /* async interruption */ -#define EXCP_HLT 257 /* hlt instruction reached */ -#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ +#define EXCP_INTERRUPT 0x10000 /* async interruption */ +#define EXCP_HLT 0x10001 /* hlt instruction reached */ +#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ #define MAX_BREAKPOINTS 32 diff --git a/linux-user/main.c b/linux-user/main.c index d8fd0e408..856147f04 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -706,28 +706,22 @@ void cpu_loop(CPUPPCState *env) fprintf(logfile, "Invalid data memory access: 0x%08x\n", env->spr[SPR_DAR]); } - switch (env->error_code & 0xF) { - case EXCP_DSI_TRANSLATE: + switch (env->error_code & 0xFF000000) { + case 0x40000000: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; break; - case EXCP_DSI_NOTSUP: - case EXCP_DSI_EXTERNAL: + case 0x04000000: info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLADR; break; - case EXCP_DSI_PROT: + case 0x08000000: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_ACCERR; break; - case EXCP_DSI_DABR: - info.si_signo = TARGET_SIGTRAP; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - break; default: /* Let's send a regular segfault... */ fprintf(stderr, "Invalid segfault errno (%02x)\n", @@ -748,19 +742,14 @@ void cpu_loop(CPUPPCState *env) fprintf(stderr, "Invalid instruction fetch\n"); if (loglevel) fprintf(logfile, "Invalid instruction fetch\n"); - switch (env->error_code) { - case EXCP_ISI_TRANSLATE: + switch (env->error_code & 0xFF000000) { + case 0x40000000: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; break; - case EXCP_ISI_GUARD: - info.si_signo = TARGET_SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLADR; - break; - case EXCP_ISI_NOEXEC: - case EXCP_ISI_PROT: + case 0x10000000: + case 0x08000000: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_ACCERR; @@ -930,18 +919,6 @@ void cpu_loop(CPUPPCState *env) if (loglevel) fprintf(logfile, "Decrementer exception\n"); abort(); - case EXCP_RESA: /* Implementation specific */ - /* Should not happen ! */ - fprintf(stderr, "RESA exception should never happen !\n"); - if (loglevel) - fprintf(logfile, "RESA exception should never happen !\n"); - abort(); - case EXCP_RESB: /* Implementation specific */ - /* Should not happen ! */ - fprintf(stderr, "RESB exception should never happen !\n"); - if (loglevel) - fprintf(logfile, "RESB exception should never happen !\n"); - abort(); case EXCP_TRACE: /* Do nothing: we use this to trace execution */ break; @@ -963,12 +940,6 @@ void cpu_loop(CPUPPCState *env) case EXCP_BRANCH: /* We stopped because of a jump... */ break; - case EXCP_RFI: - /* Should not occur: we always are in user mode */ - fprintf(stderr, "Return from interrupt ?\n"); - if (loglevel) - fprintf(logfile, "Return from interrupt ?\n"); - abort(); case EXCP_INTERRUPT: /* Don't know why this should ever happen... */ break; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index a7b4051e1..7fc79434a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -924,62 +924,72 @@ enum { /*****************************************************************************/ /* Exceptions */ -enum { - EXCP_NONE = -1, - /* PowerPC hardware exceptions : exception vector / 0x100 */ - EXCP_RESET = 0x01, /* System reset */ - EXCP_MACHINE_CHECK = 0x02, /* Machine check exception */ - EXCP_DSI = 0x03, /* Impossible memory access */ - EXCP_ISI = 0x04, /* Impossible instruction fetch */ - EXCP_EXTERNAL = 0x05, /* External interruption */ - EXCP_ALIGN = 0x06, /* Alignment exception */ - EXCP_PROGRAM = 0x07, /* Program exception */ - EXCP_NO_FP = 0x08, /* No floating point */ - EXCP_DECR = 0x09, /* Decrementer exception */ - EXCP_RESA = 0x0A, /* Implementation specific */ - EXCP_RESB = 0x0B, /* Implementation specific */ - EXCP_SYSCALL = 0x0C, /* System call */ - EXCP_TRACE = 0x0D, /* Trace exception (optional) */ - EXCP_FP_ASSIST = 0x0E, /* Floating-point assist (optional) */ - /* MPC740/745/750 & IBM 750 */ - EXCP_PERF = 0x0F, /* Performance monitor */ - EXCP_IABR = 0x13, /* Instruction address breakpoint */ - EXCP_SMI = 0x14, /* System management interrupt */ - EXCP_THRM = 0x15, /* Thermal management interrupt */ - /* MPC755 */ - EXCP_TLBMISS = 0x10, /* Instruction TLB miss */ - EXCP_TLBMISS_DL = 0x11, /* Data TLB miss for load */ - EXCP_TLBMISS_DS = 0x12, /* Data TLB miss for store */ - EXCP_PPC_MAX = 0x16, - /* Qemu exception */ - EXCP_OFCALL = 0x20, /* Call open-firmware emulator */ - EXCP_RTASCALL = 0x21, /* Call RTAS emulator */ - /* Special cases where we want to stop translation */ - EXCP_MTMSR = 0x104, /* mtmsr instruction: */ +#define EXCP_NONE -1 +/* PowerPC hardware exceptions : exception vectors defined in PowerPC book 3 */ +#define EXCP_RESET 0x0100 /* System reset */ +#define EXCP_MACHINE_CHECK 0x0200 /* Machine check exception */ +#define EXCP_DSI 0x0300 /* Data storage exception */ +#define EXCP_DSEG 0x0380 /* Data segment exception */ +#define EXCP_ISI 0x0400 /* Instruction storage exception */ +#define EXCP_ISEG 0x0480 /* Instruction segment exception */ +#define EXCP_EXTERNAL 0x0500 /* External interruption */ +#define EXCP_ALIGN 0x0600 /* Alignment exception */ +#define EXCP_PROGRAM 0x0700 /* Program exception */ +#define EXCP_NO_FP 0x0800 /* Floating point unavailable exception */ +#define EXCP_DECR 0x0900 /* Decrementer exception */ +#define EXCP_HDECR 0x0980 /* Hypervisor decrementer exception */ +#define EXCP_SYSCALL 0x0C00 /* System call */ +#define EXCP_TRACE 0x0D00 /* Trace exception */ +#define EXCP_PERF 0x0F00 /* Performance monitor exception */ +/* Exceptions defined in PowerPC 32 bits programming environment manual */ +#define EXCP_FP_ASSIST 0x0E00 /* Floating-point assist */ +/* Implementation specific exceptions */ +/* 40x exceptions */ +#define EXCP_40x_PIT 0x1000 /* Programmable interval timer interrupt */ +#define EXCP_40x_FIT 0x1010 /* Fixed interval timer interrupt */ +#define EXCP_40x_WATCHDOG 0x1020 /* Watchdog timer exception */ +#define EXCP_40x_DTLBMISS 0x1100 /* Data TLB miss exception */ +#define EXCP_40x_ITLBMISS 0x1200 /* Instruction TLB miss exception */ +#define EXCP_40x_DEBUG 0x2000 /* Debug exception */ +/* 405 specific exceptions */ +#define EXCP_405_APU 0x0F20 /* APU unavailable exception */ +/* TLB assist exceptions (602/603) */ +#define EXCP_I_TLBMISS 0x1000 /* Instruction TLB miss */ +#define EXCP_DL_TLBMISS 0x1100 /* Data load TLB miss */ +#define EXCP_DS_TLBMISS 0x1200 /* Data store TLB miss */ +/* Breakpoint exceptions (602/603/604/620/740/745/750/755...) */ +#define EXCP_IABR 0x1300 /* Instruction address breakpoint */ +#define EXCP_SMI 0x1400 /* System management interrupt */ +/* Altivec related exceptions */ +#define EXCP_VPU 0x0F20 /* VPU unavailable exception */ +/* 601 specific exceptions */ +#define EXCP_601_IO 0x0600 /* IO error exception */ +#define EXCP_601_RUNM 0x2000 /* Run mode exception */ +/* 602 specific exceptions */ +#define EXCP_602_WATCHDOG 0x1500 /* Watchdog exception */ +#define EXCP_602_EMUL 0x1600 /* Emulation trap exception */ +/* G2 specific exceptions */ +#define EXCP_G2_CRIT 0x0A00 /* Critical interrupt */ +/* MPC740/745/750 & IBM 750 specific exceptions */ +#define EXCP_THRM 0x1700 /* Thermal management interrupt */ +/* 74xx specific exceptions */ +#define EXCP_74xx_VPUA 0x1600 /* VPU assist exception */ +/* 970FX specific exceptions */ +#define EXCP_970_SOFTP 0x1500 /* Soft patch exception */ +#define EXCP_970_MAINT 0x1600 /* Maintenance exception */ +#define EXCP_970_THRM 0x1800 /* Thermal exception */ +#define EXCP_970_VPUA 0x1700 /* VPU assist exception */ +/* End of exception vectors area */ +#define EXCP_PPC_MAX 0x4000 +/* Qemu exceptions: special cases we want to stop translation */ +#define EXCP_MTMSR 0x11000 /* mtmsr instruction: */ /* may change privilege level */ - EXCP_BRANCH = 0x108, /* branch instruction */ - EXCP_RFI = 0x10C, /* return from interrupt */ - EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */ -}; +#define EXCP_BRANCH 0x11001 /* branch instruction */ +#define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */ +#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ */ + /* Error codes */ enum { - /* Exception subtypes for EXCP_DSI */ - EXCP_DSI_TRANSLATE = 0x01, /* Data address can't be translated */ - EXCP_DSI_NOTSUP = 0x02, /* Access type not supported */ - EXCP_DSI_PROT = 0x03, /* Memory protection violation */ - EXCP_DSI_EXTERNAL = 0x04, /* External access disabled */ - EXCP_DSI_DABR = 0x05, /* Data address breakpoint */ - /* flags for EXCP_DSI */ - EXCP_DSI_DIRECT = 0x10, - EXCP_DSI_STORE = 0x20, - EXCP_DSI_ECXW = 0x40, - /* Exception subtypes for EXCP_ISI */ - EXCP_ISI_TRANSLATE = 0x01, /* Code address can't be translated */ - EXCP_ISI_NOEXEC = 0x02, /* Try to fetch from a data segment */ - EXCP_ISI_GUARD = 0x03, /* Fetch from guarded memory */ - EXCP_ISI_PROT = 0x04, /* Memory protection violation */ - EXCP_ISI_DIRECT = 0x05, /* Trying to fetch from * - * a direct store segment */ /* Exception subtypes for EXCP_ALIGN */ EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 6ddc0f47f..fbecb76d0 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -22,8 +22,6 @@ //#define DEBUG_MMU //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS -/* accurate but slower TLB flush in exceptions */ -//#define ACCURATE_TLB_FLUSH /*****************************************************************************/ /* PowerPC MMU emulation */ @@ -524,20 +522,25 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, switch (ret) { case -1: /* No matches in page tables */ - error_code = EXCP_ISI_TRANSLATE; + error_code = 0x40000000; break; case -2: /* Access rights violation */ - error_code = EXCP_ISI_PROT; + error_code = 0x08000000; break; case -3: /* No execute protection violation */ - error_code = EXCP_ISI_NOEXEC; + error_code = 0x10000000; break; case -4: /* Direct store exception */ /* No code fetch is allowed in direct-store areas */ - error_code = EXCP_ISI_DIRECT; + error_code = 0x10000000; + break; + case -5: + /* No match in segment table */ + exception = EXCP_ISEG; + error_code = 0; break; } } else { @@ -545,11 +548,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, switch (ret) { case -1: /* No matches in page tables */ - error_code = EXCP_DSI_TRANSLATE; + error_code = 0x40000000; break; case -2: /* Access rights violation */ - error_code = EXCP_DSI_PROT; + error_code = 0x08000000; break; case -4: /* Direct store exception */ @@ -561,14 +564,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, break; case ACCESS_RES: /* lwarx, ldarx or srwcx. */ - exception = EXCP_DSI; - error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT; + error_code = 0x04000000; break; case ACCESS_EXT: /* eciwx or ecowx */ - exception = EXCP_DSI; - error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | - EXCP_DSI_ECXW; + error_code = 0x04100000; break; default: printf("DSI: invalid exception (%d)\n", ret); @@ -576,11 +576,17 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, error_code = EXCP_INVAL | EXCP_INVAL_INVAL; break; } + case -5: + /* No match in segment table */ + exception = EXCP_DSEG; + error_code = 0; + break; } if (rw) - error_code |= EXCP_DSI_STORE; + error_code |= 0x02000000; /* Store fault address */ env->spr[SPR_DAR] = address; + env->spr[SPR_DSISR] = error_code; } #if 0 printf("%s: set exception to %d %02x\n", @@ -985,119 +991,107 @@ static void dump_syscall(CPUState *env) void do_interrupt (CPUState *env) { - uint32_t msr; + target_ulong msr, *srr_0, *srr_1, tmp; int excp; excp = env->exception_index; msr = do_load_msr(env); + /* The default is to use SRR0 & SRR1 to save the exception context */ + srr_0 = &env->spr[SPR_SRR0]; + srr_1 = &env->spr[SPR_SRR1]; #if defined (DEBUG_EXCEPTIONS) - if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) - { - if (loglevel > 0) { - fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", - env->nip, excp << 8, env->error_code); + if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { + if (loglevel != 0) { + fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n", + (unsigned long)env->nip, excp, env->error_code); + cpu_dump_state(env, logfile, fprintf, 0); } - if (loglevel > 0) - cpu_dump_state(env, logfile, fprintf, 0); } #endif if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", - env->nip, excp << 8, env->error_code); + fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n", + (unsigned long)env->nip, excp, env->error_code); } + msr_pow = 0; /* Generate informations in save/restore registers */ switch (excp) { - case EXCP_NONE: - /* Do nothing */ -#if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_NONE\n", __func__); -#endif - return; - case EXCP_RESET: - if (msr_ip) - excp += 0xFFC00; + /* Generic PowerPC exceptions */ + case EXCP_RESET: /* 0x0100 */ + if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) { + if (msr_ip) + excp += 0xFFC00; + excp |= 0xFFC00000; + } else { + srr_0 = &env->spr[SPR_40x_SRR2]; + srr_1 = &env->spr[SPR_40x_SRR3]; + } goto store_next; - case EXCP_MACHINE_CHECK: + case EXCP_MACHINE_CHECK: /* 0x0200 */ if (msr_me == 0) { cpu_abort(env, "Machine check exception while not allowed\n"); } + if (PPC_EXCP(env) == PPC_FLAGS_EXCP_40x) { + srr_0 = &env->spr[SPR_40x_SRR2]; + srr_1 = &env->spr[SPR_40x_SRR3]; + } msr_me = 0; break; - case EXCP_DSI: + case EXCP_DSI: /* 0x0300 */ /* Store exception cause */ /* data location address has been stored * when the fault has been detected - */ + */ msr &= ~0xFFFF0000; - env->spr[SPR_DSISR] = 0; - if ((env->error_code & 0x0f) == EXCP_DSI_TRANSLATE) - env->spr[SPR_DSISR] |= 0x40000000; - else if ((env->error_code & 0x0f) == EXCP_DSI_PROT) - env->spr[SPR_DSISR] |= 0x08000000; - else if ((env->error_code & 0x0f) == EXCP_DSI_NOTSUP) { - env->spr[SPR_DSISR] |= 0x80000000; - if (env->error_code & EXCP_DSI_DIRECT) - env->spr[SPR_DSISR] |= 0x04000000; - } - if (env->error_code & EXCP_DSI_STORE) - env->spr[SPR_DSISR] |= 0x02000000; - if ((env->error_code & 0xF) == EXCP_DSI_DABR) - env->spr[SPR_DSISR] |= 0x00400000; - if (env->error_code & EXCP_DSI_ECXW) - env->spr[SPR_DSISR] |= 0x00100000; #if defined (DEBUG_EXCEPTIONS) if (loglevel) { fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } else { - printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", - env->spr[SPR_DSISR], env->spr[SPR_DAR], env->nip); + printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n", + env->spr[SPR_DSISR], env->spr[SPR_DAR]); } #endif goto store_next; - case EXCP_ISI: + case EXCP_ISI: /* 0x0400 */ /* Store exception cause */ msr &= ~0xFFFF0000; - if (env->error_code == EXCP_ISI_TRANSLATE) - msr |= 0x40000000; - else if (env->error_code == EXCP_ISI_NOEXEC || - env->error_code == EXCP_ISI_GUARD || - env->error_code == EXCP_ISI_DIRECT) - msr |= 0x10000000; - else - msr |= 0x08000000; + msr |= env->error_code; #if defined (DEBUG_EXCEPTIONS) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", msr, env->nip); - } else { - printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n", - msr, env->nip, env->spr[V_TBL]); } #endif goto store_next; - case EXCP_EXTERNAL: + case EXCP_EXTERNAL: /* 0x0500 */ if (msr_ee == 0) { #if defined (DEBUG_EXCEPTIONS) if (loglevel > 0) { fprintf(logfile, "Skipping hardware interrupt\n"); - } + } #endif /* Requeue it */ - do_raise_exception(EXCP_EXTERNAL); + env->interrupt_request |= CPU_INTERRUPT_HARD; return; - } + } goto store_next; - case EXCP_ALIGN: - /* Store exception cause */ - /* Get rS/rD and rA from faulting opcode */ - env->spr[SPR_DSISR] |= - (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; - /* data location address has been stored - * when the fault has been detected - */ + case EXCP_ALIGN: /* 0x0600 */ + if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) { + /* Store exception cause */ + /* Get rS/rD and rA from faulting opcode */ + env->spr[SPR_DSISR] |= + (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; + /* data location address has been stored + * when the fault has been detected + */ + } else { + /* IO error exception on PowerPC 601 */ + /* XXX: TODO */ + cpu_abort(env, + "601 IO error exception is not implemented yet !\n"); + } goto store_current; - case EXCP_PROGRAM: + case EXCP_PROGRAM: /* 0x0700 */ msr &= ~0xFFFF0000; switch (env->error_code & ~0xF) { case EXCP_FP: @@ -1131,17 +1125,19 @@ void do_interrupt (CPUState *env) } msr |= 0x00010000; goto store_current; - case EXCP_NO_FP: + case EXCP_NO_FP: /* 0x0800 */ msr &= ~0xFFFF0000; goto store_current; case EXCP_DECR: if (msr_ee == 0) { +#if 1 /* Requeue it */ - do_raise_exception(EXCP_DECR); + env->interrupt_request |= CPU_INTERRUPT_TIMER; +#endif return; } goto store_next; - case EXCP_SYSCALL: + case EXCP_SYSCALL: /* 0x0C00 */ /* NOTE: this is a temporary hack to support graphics OSI calls from the MOL driver */ if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && @@ -1153,35 +1149,332 @@ void do_interrupt (CPUState *env) dump_syscall(env); } goto store_next; - case EXCP_TRACE: + case EXCP_TRACE: /* 0x0D00 */ + /* XXX: TODO */ + cpu_abort(env, "Trace exception is not implemented yet !\n"); + goto store_next; + case EXCP_PERF: /* 0x0F00 */ + /* XXX: TODO */ + cpu_abort(env, + "Performance counter exception is not implemented yet !\n"); + goto store_next; + /* 32 bits PowerPC specific exceptions */ + case EXCP_FP_ASSIST: /* 0x0E00 */ + /* XXX: TODO */ + cpu_abort(env, "Floating point assist exception " + "is not implemented yet !\n"); + goto store_next; + /* 64 bits PowerPC exceptions */ + case EXCP_DSEG: /* 0x0380 */ + /* XXX: TODO */ + cpu_abort(env, "Data segment exception is not implemented yet !\n"); goto store_next; - case EXCP_FP_ASSIST: + case EXCP_ISEG: /* 0x0480 */ + /* XXX: TODO */ + cpu_abort(env, + "Instruction segment exception is not implemented yet !\n"); goto store_next; - case EXCP_MTMSR: - /* Nothing to do */ + case EXCP_HDECR: /* 0x0980 */ + if (msr_ee == 0) { +#if 1 + /* Requeue it */ + env->interrupt_request |= CPU_INTERRUPT_TIMER; +#endif return; - case EXCP_BRANCH: - /* Nothing to do */ + } + cpu_abort(env, + "Hypervisor decrementer exception is not implemented yet !\n"); + goto store_next; + /* Implementation specific exceptions */ + case 0x0A00: + if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) { + /* Critical interrupt on G2 */ + /* XXX: TODO */ + cpu_abort(env, "G2 critical interrupt is not implemented yet !\n"); + goto store_next; + } else { + cpu_abort(env, "Invalid exception 0x0A00 !\n"); + } return; - case EXCP_RFI: - /* Restore user-mode state */ -#if defined (DEBUG_EXCEPTIONS) - if (msr_pr == 1) - printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); + case 0x0F20: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + /* APU unavailable on 405 */ + /* XXX: TODO */ + cpu_abort(env, + "APU unavailable exception is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_74xx: + /* Altivec unavailable */ + /* XXX: TODO */ + cpu_abort(env, "Altivec unavailable exception " + "is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x0F20 !\n"); + break; + } + return; + case 0x1000: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + /* PIT on 4xx */ + /* XXX: TODO */ + cpu_abort(env, "40x PIT exception is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_602: + case PPC_FLAGS_EXCP_603: + /* ITLBMISS on 602/603 */ + msr &= ~0xF00F0000; + msr_tgpr = 1; + goto store_gprs; + default: + cpu_abort(env, "Invalid exception 0x1000 !\n"); + break; + } + return; + case 0x1010: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + /* FIT on 4xx */ + cpu_abort(env, "40x FIT exception is not implemented yet !\n"); + /* XXX: TODO */ + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1010 !\n"); + break; + } + return; + case 0x1020: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + /* Watchdog on 4xx */ + /* XXX: TODO */ + cpu_abort(env, + "40x watchdog exception is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1020 !\n"); + break; + } + return; + case 0x1100: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + /* DTLBMISS on 4xx */ + /* XXX: TODO */ + cpu_abort(env, + "40x DTLBMISS exception is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_602: + case PPC_FLAGS_EXCP_603: + /* DLTLBMISS on 602/603 */ + msr &= ~0xF00F0000; + msr_tgpr = 1; + goto store_gprs; + default: + cpu_abort(env, "Invalid exception 0x1100 !\n"); + break; + } + return; + case 0x1200: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + /* ITLBMISS on 4xx */ + /* XXX: TODO */ + cpu_abort(env, + "40x ITLBMISS exception is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_602: + case PPC_FLAGS_EXCP_603: + /* DSTLBMISS on 602/603 */ + msr &= ~0xF00F0000; + msr_tgpr = 1; + store_gprs: +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "6xx %sTLB miss: IM %08x DM %08x IC %08x " + "DC %08x H1 %08x H2 %08x %08x\n", + excp == 0x1000 ? "I" : excp == 0x1100 ? "DL" : "DS", + env->spr[SPR_IMISS], env->spr[SPR_DMISS], + env->spr[SPR_ICMP], env->spr[SPR_DCMP], + env->spr[SPR_DHASH1], env->spr[SPR_DHASH2], + env->error_code); + } #endif + /* Swap temporary saved registers with GPRs */ + tmp = env->gpr[0]; + env->gpr[0] = env->tgpr[0]; + env->tgpr[0] = tmp; + tmp = env->gpr[1]; + env->gpr[1] = env->tgpr[1]; + env->tgpr[1] = tmp; + tmp = env->gpr[2]; + env->gpr[2] = env->tgpr[2]; + env->tgpr[2] = tmp; + tmp = env->gpr[3]; + env->gpr[3] = env->tgpr[3]; + env->tgpr[3] = tmp; + msr |= env->crf[0] << 28; + msr |= env->error_code; /* key, D/I, S/L bits */ + /* Set way using a LRU mechanism */ + msr |= (env->last_way ^ 1) << 17; + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1200 !\n"); + break; + } + return; + case 0x1300: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_601: + case PPC_FLAGS_EXCP_602: + case PPC_FLAGS_EXCP_603: + case PPC_FLAGS_EXCP_604: + case PPC_FLAGS_EXCP_7x0: + case PPC_FLAGS_EXCP_7x5: + /* IABR on 6xx/7xx */ + /* XXX: TODO */ + cpu_abort(env, "IABR exception is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1300 !\n"); + break; + } + return; + case 0x1400: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_601: + case PPC_FLAGS_EXCP_602: + case PPC_FLAGS_EXCP_603: + case PPC_FLAGS_EXCP_604: + case PPC_FLAGS_EXCP_7x0: + case PPC_FLAGS_EXCP_7x5: + /* SMI on 6xx/7xx */ + /* XXX: TODO */ + cpu_abort(env, "SMI exception is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1400 !\n"); + break; + } + return; + case 0x1500: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_602: + /* Watchdog on 602 */ + cpu_abort(env, + "602 watchdog exception is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_970: + /* Soft patch exception on 970 */ + /* XXX: TODO */ + cpu_abort(env, + "970 soft-patch exception is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_74xx: + /* VPU assist on 74xx */ + /* XXX: TODO */ + cpu_abort(env, "VPU assist exception is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1500 !\n"); + break; + } + return; + case 0x1600: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_602: + /* Emulation trap on 602 */ + /* XXX: TODO */ + cpu_abort(env, "602 emulation trap exception " + "is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_970: + /* Maintenance exception on 970 */ + /* XXX: TODO */ + cpu_abort(env, + "970 maintenance exception is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1600 !\n"); + break; + } + return; + case 0x1700: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_7x0: + case PPC_FLAGS_EXCP_7x5: + /* Thermal management interrupt on G3 */ + /* XXX: TODO */ + cpu_abort(env, "G3 thermal management exception " + "is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_970: + /* VPU assist on 970 */ + /* XXX: TODO */ + cpu_abort(env, + "970 VPU assist exception is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1700 !\n"); + break; + } + return; + case 0x1800: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_970: + /* Thermal exception on 970 */ + /* XXX: TODO */ + cpu_abort(env, "970 thermal management exception " + "is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1800 !\n"); + break; + } + return; + case 0x2000: + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + /* DEBUG on 4xx */ + /* XXX: TODO */ + cpu_abort(env, "40x debug exception is not implemented yet !\n"); + goto store_next; + case PPC_FLAGS_EXCP_601: + /* Run mode exception on 601 */ + /* XXX: TODO */ + cpu_abort(env, + "601 run mode exception is not implemented yet !\n"); + goto store_next; + default: + cpu_abort(env, "Invalid exception 0x1800 !\n"); + break; + } + return; + /* Other exceptions */ + /* Qemu internal exceptions: + * we should never come here with those values: abort execution + */ + default: + cpu_abort(env, "Invalid exception: code %d (%04x)\n", excp, excp); return; store_current: - /* SRR0 is set to current instruction */ - env->spr[SPR_SRR0] = (uint32_t)env->nip - 4; + /* save current instruction location */ + *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL; break; store_next: - /* SRR0 is set to next instruction */ - env->spr[SPR_SRR0] = (uint32_t)env->nip; + /* save next instruction location */ + *srr_0 = env->nip & 0xFFFFFFFFULL; break; } - env->spr[SPR_SRR1] = msr; + /* Save msr */ + *srr_1 = msr; + /* If we disactivated any translation, flush TLBs */ + if (msr_ir || msr_dr) { + tlb_flush(env, 1); + } /* reload MSR with correct bits */ - msr_pow = 0; msr_ee = 0; msr_pr = 0; msr_fp = 0; @@ -1193,14 +1486,11 @@ void do_interrupt (CPUState *env) msr_dr = 0; msr_ri = 0; msr_le = msr_ile; + msr_sf = msr_isf; do_compute_hflags(env); /* Jump to handler */ - env->nip = excp << 8; + env->nip = excp; env->exception_index = EXCP_NONE; - /* Invalidate all TLB as we may have changed translation mode */ -#ifdef ACCURATE_TLB_FLUSH - tlb_flush(env, 1); -#endif /* ensure that no TB jump will be modified as the program flow was changed */ #ifdef __sparc__ @@ -1208,6 +1498,6 @@ void do_interrupt (CPUState *env) #else T0 = 0; #endif - env->exception_index = -1; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/op.c b/target-ppc/op.c index 38ed13aa1..c7953662b 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -204,16 +204,6 @@ PPC_OP(update_nip) env->nip = PARAM(1); } -PPC_OP(debug) -{ - env->nip = PARAM(1); -#if defined (DEBUG_OP) - dump_state(); -#endif - do_raise_exception(EXCP_DEBUG); - RETURN(); -} - /* Segment registers load and store with immediate index */ PPC_OP(load_srin) { @@ -1384,14 +1374,10 @@ PPC_OP(check_reservation) /* Return from interrupt */ PPC_OP(rfi) { - regs->nip = regs->spr[SPR_SRR0] & ~0x00000003; -#if 1 // TRY - T0 = regs->spr[SPR_SRR1] & ~0xFFF00000; -#else - T0 = regs->spr[SPR_SRR1] & ~0xFFFF0000; -#endif + env->nip = env->spr[SPR_SRR0] & ~0x00000003; + T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL; do_store_msr(env, T0); - do_raise_exception(EXCP_RFI); + env->interrupt_request |= CPU_INTERRUPT_EXITTB; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 670e27894..e57fbe461 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -42,12 +42,6 @@ void do_raise_exception_err (uint32_t exception, int error_code) printf("Raise exception %3x code : %d\n", exception, error_code); #endif switch (exception) { - case EXCP_EXTERNAL: - case EXCP_DECR: - printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n"); - if (msr_ee == 0) - return; - break; case EXCP_PROGRAM: if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) return; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 52a28def1..70f88637d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -179,6 +179,12 @@ static inline void RET_STOP (DisasContext *ctx) RET_EXCP(ctx, EXCP_MTMSR, 0); } +static inline void RET_CHG_FLOW (DisasContext *ctx) +{ + gen_op_raise_exception_err(EXCP_MTMSR, 0); + ctx->exception = EXCP_MTMSR; +} + #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ static void gen_##name (DisasContext *ctx); \ GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \ @@ -1895,7 +1901,7 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) return; } gen_op_rfi(); - RET_EXCP(ctx, EXCP_RFI, 0); + RET_CHG_FLOW(ctx); #endif } @@ -2555,7 +2561,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, (msr_se && (ctx.nip < 0x100 || ctx.nip > 0xF00 || (ctx.nip & 0xFC) != 0x04) && - ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI && + ctx.exception != EXCP_SYSCALL && + ctx.exception != EXCP_SYSCALL_USER && ctx.exception != EXCP_TRAP)) { RET_EXCP(ctxp, EXCP_TRACE, 0); } -- cgit v1.2.3 From fb3444b86cd84c8c0750d1df189aa76beec8e1d8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 13:57:11 +0000 Subject: endian register support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1493 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 141fa1eee..6b2bfd27b 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -258,6 +258,7 @@ typedef struct sysctrl_t { uint8_t syscontrol; uint8_t fake_io[2]; int contiguous_map; + int endian; } sysctrl_t; enum { @@ -297,8 +298,9 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) } /* Check LE mode */ if (val & 0x02) { - printf("Little Endian mode isn't supported (yet ?)\n"); - abort(); + sysctrl->endian = 1; + } else { + sysctrl->endian = 0; } break; case 0x0800: @@ -549,7 +551,6 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, } cpu_register_physical_memory((uint32_t)(-BIOS_SIZE), BIOS_SIZE, bios_offset | IO_MEM_ROM); - cpu_single_env->nip = 0xfffffffc; if (linux_boot) { kernel_base = KERNEL_LOAD_ADDR; @@ -604,7 +605,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* init basic PC hardware */ vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + vga_ram_size, 0, 0); rtc_init(0x70, 8); // openpic = openpic_init(0x00000000, 0xF0000000, 1); isa_pic = pic_init(pic_irq_request, cpu_single_env); -- cgit v1.2.3 From d5295253b0d2baf190180b08c2a531021af91c99 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 14:00:51 +0000 Subject: VGA bios support for PowerPC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1494 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 ++- hw/mips_r4k.c | 2 +- hw/pc.c | 2 +- hw/ppc_chrp.c | 51 ++++++++++++++++++++++++++++++++++++++------------- hw/vga.c | 21 ++++++++++++++++++--- hw/vga_int.h | 2 ++ pc-bios/video.x | Bin 0 -> 12192 bytes vl.h | 5 +++-- 8 files changed, 65 insertions(+), 21 deletions(-) create mode 100644 pc-bios/video.x diff --git a/Makefile b/Makefile index 11b38d15f..74b1a94eb 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,7 @@ install: all mkdir -p "$(datadir)" install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/vgabios-cirrus.bin \ - pc-bios/ppc_rom.bin \ + pc-bios/ppc_rom.bin pc-bios/video.x \ pc-bios/proll.elf \ pc-bios/linux_boot.bin "$(datadir)" mkdir -p "$(docdir)" @@ -121,6 +121,7 @@ tarbin: $(datadir)/vgabios.bin \ $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ + $(datadir)/video.x \ $(datadir)/proll.elf \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 9ce4a5ac9..ca135ac39 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -242,7 +242,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, isa_pic = pic_init(pic_irq_request, cpu_single_env); serial_init(0x3f8, 4, serial_hds[0]); vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + vga_ram_size, 0, 0); isa_ne2000_init(0x300, 9, &nd_table[0]); } diff --git a/hw/pc.c b/hw/pc.c index 696c9192c..29037db7b 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -547,7 +547,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } } else { vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + vga_ram_size, 0, 0); } rtc_state = rtc_init(0x70, 8); diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 515806fbb..5d20333d7 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -24,6 +24,7 @@ #include "vl.h" #define BIOS_FILENAME "ppc_rom.bin" +#define VGABIOS_FILENAME "video.x" #define NVRAM_SIZE 0x2000 #define KERNEL_LOAD_ADDR 0x01000000 @@ -232,12 +233,13 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, void *pic; m48t59_t *nvram; int PPC_io_memory, unin_memory; - int ret, linux_boot, i; - unsigned long bios_offset; + int linux_boot, i; + unsigned long bios_offset, vga_bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; ppc_def_t *def; PCIBus *pci_bus; const char *arch_name; + int vga_bios_size, bios_size; linux_boot = (kernel_filename != NULL); @@ -247,15 +249,36 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, /* allocate and load BIOS */ bios_offset = ram_size + vga_ram_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - ret = load_image(buf, phys_ram_base + bios_offset); - if (ret != BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf); + bios_size = load_image(buf, phys_ram_base + bios_offset); + if (bios_size < 0 || bios_size > BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf); exit(1); } - cpu_register_physical_memory((uint32_t)(-BIOS_SIZE), - BIOS_SIZE, bios_offset | IO_MEM_ROM); - cpu_single_env->nip = 0xfffffffc; - + bios_size = (bios_size + 0xfff) & ~0xfff; + cpu_register_physical_memory((uint32_t)(-bios_size), + bios_size, bios_offset | IO_MEM_ROM); + + /* allocate and load VGA BIOS */ + vga_bios_offset = bios_offset + bios_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); + vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8); + if (vga_bios_size < 0) { + /* if no bios is present, we can still work */ + fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf); + vga_bios_size = 0; + } else { + /* set a specific header (XXX: find real Apple format for NDRV + drivers) */ + phys_ram_base[vga_bios_offset] = 'N'; + phys_ram_base[vga_bios_offset + 1] = 'D'; + phys_ram_base[vga_bios_offset + 2] = 'R'; + phys_ram_base[vga_bios_offset + 3] = 'V'; + cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4), + vga_bios_size); + vga_bios_size += 8; + } + vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff; + if (linux_boot) { kernel_base = KERNEL_LOAD_ADDR; /* now we can load the kernel */ @@ -321,8 +344,9 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory); /* init basic PC hardware */ - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + vga_initialize(pci_bus, ds, phys_ram_base + ram_size, + ram_size, vga_ram_size, + vga_bios_offset, vga_bios_size); pic = heathrow_pic_init(&heathrow_pic_mem_index); set_irq = heathrow_pic_set_irq; pci_set_pic(pci_bus, set_irq, pic); @@ -363,8 +387,9 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); /* init basic PC hardware */ - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + vga_initialize(pci_bus, ds, phys_ram_base + ram_size, + ram_size, vga_ram_size, + vga_bios_offset, vga_bios_size); pic = openpic_init(NULL, &openpic_mem_index, 1); set_irq = openpic_set_irq; pci_set_pic(pci_bus, set_irq, pic); diff --git a/hw/vga.c b/hw/vga.c index 2c425ffe9..49e5b211f 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1654,8 +1654,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { VGAState *s = vga_state; - - cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); + if (region_num == PCI_ROM_SLOT) { + cpu_register_physical_memory(addr, s->bios_size, s->bios_offset); + } else { + cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); + } } void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, @@ -1701,7 +1704,8 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size) + unsigned long vga_ram_offset, int vga_ram_size, + unsigned long vga_bios_offset, int vga_bios_size) { VGAState *s; @@ -1776,6 +1780,17 @@ int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, /* XXX: vga_ram_size must be a power of two */ pci_register_io_region(d, 0, vga_ram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); + if (vga_bios_size != 0) { + unsigned int bios_total_size; + s->bios_offset = vga_bios_offset; + s->bios_size = vga_bios_size; + /* must be a power of two */ + bios_total_size = 1; + while (bios_total_size < vga_bios_size) + bios_total_size <<= 1; + pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size, + PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); + } } else { #ifdef CONFIG_BOCHS_VBE /* XXX: use optimized standard vga accesses */ diff --git a/hw/vga_int.h b/hw/vga_int.h index 2e7fb30ef..621268de4 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -78,6 +78,8 @@ uint8_t *vram_ptr; \ unsigned long vram_offset; \ unsigned int vram_size; \ + unsigned long bios_offset; \ + unsigned int bios_size; \ uint32_t latch; \ uint8_t sr_index; \ uint8_t sr[256]; \ diff --git a/pc-bios/video.x b/pc-bios/video.x new file mode 100644 index 000000000..761aa0c9d Binary files /dev/null and b/pc-bios/video.x differ diff --git a/vl.h b/vl.h index 6f6aba75b..85d0cf473 100644 --- a/vl.h +++ b/vl.h @@ -137,7 +137,7 @@ extern int win2k_install_hack; /* XXX: make it dynamic */ #if defined (TARGET_PPC) -#define BIOS_SIZE (512 * 1024) +#define BIOS_SIZE ((512 + 32) * 1024) #elif defined(TARGET_MIPS) #define BIOS_SIZE (128 * 1024) #else @@ -596,7 +596,8 @@ static inline void dpy_resize(DisplayState *s, int w, int h) } int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size); + unsigned long vga_ram_offset, int vga_ram_size, + unsigned long vga_bios_offset, int vga_bios_size); void vga_update_display(void); void vga_invalidate_display(void); void vga_screen_dump(const char *filename); -- cgit v1.2.3 From 0289b2c1df2a6e8347541bde30533898ac1d5553 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 16:00:32 +0000 Subject: changed machine names git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1495 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 5d20333d7..eb9482eae 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -466,13 +466,13 @@ static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device, } QEMUMachine core99_machine = { - "core99", - "Core99 based PowerMAC", + "mac99", + "Mac99 based PowerMAC", ppc_core99_init, }; QEMUMachine heathrow_machine = { - "heathrow", + "g3bw", "Heathrow based PowerMAC", ppc_heathrow_init, }; -- cgit v1.2.3 From 4157a662124c733ef94cb3b7fa3c849fdfb28c8e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 16:00:49 +0000 Subject: allow variable bios size git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1496 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 6b2bfd27b..148a08af5 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -526,7 +526,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, char buf[1024]; m48t59_t *nvram; int PPC_io_memory; - int ret, linux_boot, i, nb_nics1; + int linux_boot, i, nb_nics1, bios_size; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; ppc_def_t *def; @@ -544,13 +544,14 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, /* allocate and load BIOS */ bios_offset = ram_size + vga_ram_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - ret = load_image(buf, phys_ram_base + bios_offset); - if (ret != BIOS_SIZE) { + bios_size = load_image(buf, phys_ram_base + bios_offset); + if (bios_size < 0 || bios_size > BIOS_SIZE) { fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf); exit(1); } - cpu_register_physical_memory((uint32_t)(-BIOS_SIZE), - BIOS_SIZE, bios_offset | IO_MEM_ROM); + bios_size = (bios_size + 0xfff) & ~0xfff; + cpu_register_physical_memory((uint32_t)(-bios_size), + bios_size, bios_offset | IO_MEM_ROM); if (linux_boot) { kernel_base = KERNEL_LOAD_ADDR; -- cgit v1.2.3 From 97067eb5bcf603e709fbf0304c80810a470eb4b4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 16:25:26 +0000 Subject: temporary version with better Darwin/Mac OS X support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1497 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/ohw.diff | 1685 +++++++++++++++++++++++++++++++++++++++++++++++++++ pc-bios/ppc_rom.bin | Bin 524288 -> 524288 bytes 2 files changed, 1685 insertions(+) create mode 100644 pc-bios/ohw.diff diff --git a/pc-bios/ohw.diff b/pc-bios/ohw.diff new file mode 100644 index 000000000..86fb1c2e1 --- /dev/null +++ b/pc-bios/ohw.diff @@ -0,0 +1,1685 @@ +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bios.h OpenHackWare-release-0.4/src/bios.h +--- OpenHackWare-release-0.4.org/src/bios.h 2005-04-06 23:20:22.000000000 +0200 ++++ OpenHackWare-release-0.4/src/bios.h 2005-07-03 16:17:41.000000000 +0200 +@@ -64,6 +64,7 @@ + ARCH_CHRP, + ARCH_MAC99, + ARCH_POP, ++ ARCH_HEATHROW, + }; + + /* Hardware definition(s) */ +@@ -183,12 +184,12 @@ + part_t *bd_probe (int boot_device); + bloc_device_t *bd_get (int device); + void bd_put (bloc_device_t *bd); +-void bd_set_boot_part (bloc_device_t *bd, part_t *partition); ++void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum); + part_t **_bd_parts (bloc_device_t *bd); + + void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1, + uint32_t io_base2, uint32_t io_base3, +- void *OF_private); ++ void *OF_private0, void *OF_private1); + void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1, + void *OF_private); + +@@ -399,17 +400,23 @@ + uint16_t min_grant, uint16_t max_latency); + void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses); + void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn, +- uint32_t *regions, uint32_t *sizes); ++ uint32_t *regions, uint32_t *sizes, ++ int irq_line); + void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size, + void *private_data); ++void OF_finalize_pci_ide (void *dev, ++ uint32_t io_base0, uint32_t io_base1, ++ uint32_t io_base2, uint32_t io_base3); + int OF_register_bus (const unsigned char *name, uint32_t address, + const unsigned char *type); + int OF_register_serial (const unsigned char *bus, const unsigned char *name, + uint32_t io_base, int irq); + int OF_register_stdio (const unsigned char *dev_in, + const unsigned char *dev_out); +-void OF_vga_register (const unsigned char *name, uint32_t address, +- int width, int height, int depth); ++void OF_vga_register (const unsigned char *name, unused uint32_t address, ++ int width, int height, int depth, ++ unsigned long vga_bios_addr, ++ unsigned long vga_bios_size); + void *OF_blockdev_register (void *parent, void *private, + const unsigned char *type, + const unsigned char *name, int devnum, +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bloc.c OpenHackWare-release-0.4/src/bloc.c +--- OpenHackWare-release-0.4.org/src/bloc.c 2005-04-06 23:21:00.000000000 +0200 ++++ OpenHackWare-release-0.4/src/bloc.c 2005-07-03 16:17:41.000000000 +0200 +@@ -55,6 +55,7 @@ + /* Partitions */ + part_t *parts, *bparts; + part_t *boot_part; ++ int bpartnum; + /* Chain */ + bloc_device_t *next; + }; +@@ -223,10 +224,12 @@ + } + + /* XXX: to be suppressed */ +-void bd_set_boot_part (bloc_device_t *bd, part_t *partition) ++void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum) + { ++ dprintf("%s: part %p (%p) %d\n", __func__, partition, bd->boot_part, partnum); + if (bd->boot_part == NULL) { + bd->boot_part = partition; ++ bd->bpartnum = partnum; + } + } + +@@ -240,6 +243,13 @@ + return &bd->bparts; + } + ++void bd_set_boot_device (bloc_device_t *bd) ++{ ++#if defined (USE_OPENFIRMWARE) ++ OF_blockdev_set_boot_device(bd->OF_private, bd->bpartnum, "\\\\ofwboot"); ++#endif ++} ++ + part_t *bd_probe (int boot_device) + { + char devices[] = { /*'a', 'b',*/ 'c', 'd', 'e', 'f', 'm', '\0', }; +@@ -272,9 +282,7 @@ + tmp = part_probe(bd, force_raw); + if (boot_device == bd->device) { + boot_part = tmp; +-#if defined (USE_OPENFIRMWARE) +- OF_blockdev_set_boot_device(bd->OF_private, 2, "\\\\ofwboot"); +-#endif ++ bd_set_boot_device(bd); + } + } + +@@ -717,34 +725,29 @@ + /* IDE PCI access for pc */ + static uint8_t ide_pci_port_read (bloc_device_t *bd, int port) + { +- eieio(); +- +- return *(uint8_t *)(bd->io_base + port); ++ uint8_t value; ++ value = inb(bd->io_base + port); ++ return value; + } + + static void ide_pci_port_write (bloc_device_t *bd, int port, uint8_t value) + { +- *(uint8_t *)(bd->io_base + port) = value; +- eieio(); ++ outb(bd->io_base + port, value); + } + + static uint32_t ide_pci_data_readl (bloc_device_t *bd) + { +- eieio(); +- +- return *((uint32_t *)bd->io_base); ++ return inl(bd->io_base); + } + + static void ide_pci_data_writel (bloc_device_t *bd, uint32_t val) + { +- *(uint32_t *)(bd->io_base) = val; +- eieio(); ++ outl(bd->io_base, val); + } + + static void ide_pci_control_write (bloc_device_t *bd, uint32_t val) + { +- *((uint8_t *)bd->tmp) = val; +- eieio(); ++ outb(bd->tmp + 2, val); + } + + static ide_ops_t ide_pci_pc_ops = { +@@ -761,7 +764,7 @@ + + void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1, + uint32_t io_base2, uint32_t io_base3, +- unused void *OF_private) ++ void *OF_private0, void *OF_private1) + { + if (ide_pci_ops == NULL) { + ide_pci_ops = malloc(sizeof(ide_ops_t)); +@@ -770,19 +773,19 @@ + memcpy(ide_pci_ops, &ide_pci_pc_ops, sizeof(ide_ops_t)); + } + if ((io_base0 != 0 || io_base1 != 0) && +- ide_pci_ops->base[0] == 0 && ide_pci_ops->base[1] == 0) { ++ ide_pci_ops->base[0] == 0 && ide_pci_ops->base[2] == 0) { + ide_pci_ops->base[0] = io_base0; +- ide_pci_ops->base[1] = io_base1; ++ ide_pci_ops->base[2] = io_base1; + #ifdef USE_OPENFIRMWARE +- ide_pci_ops->OF_private[0] = OF_private; ++ ide_pci_ops->OF_private[0] = OF_private0; + #endif + } + if ((io_base2 != 0 || io_base3 != 0) && +- ide_pci_ops->base[2] == 0 && ide_pci_ops->base[3] == 0) { +- ide_pci_ops->base[2] = io_base2; ++ ide_pci_ops->base[1] == 0 && ide_pci_ops->base[3] == 0) { ++ ide_pci_ops->base[1] = io_base2; + ide_pci_ops->base[3] = io_base3; + #ifdef USE_OPENFIRMWARE +- ide_pci_ops->OF_private[1] = OF_private; ++ ide_pci_ops->OF_private[1] = OF_private1; + #endif + } + } +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/apple.c OpenHackWare-release-0.4/src/libpart/apple.c +--- OpenHackWare-release-0.4.org/src/libpart/apple.c 2005-03-31 09:23:33.000000000 +0200 ++++ OpenHackWare-release-0.4/src/libpart/apple.c 2005-07-03 16:17:41.000000000 +0200 +@@ -199,14 +199,18 @@ + if (len == 0) { + /* Place holder. Skip it */ + DPRINTF("%s placeholder part\t%d\n", __func__, i); ++ part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; ++ part_register(bd, part, name, i); + } else if (strncmp("Apple_Void", type, 32) == 0) { + /* Void partition. Skip it */ + DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type); ++ part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; ++ part_register(bd, part, name, i); + } else if (strncmp("Apple_Free", type, 32) == 0) { + /* Free space. Skip it */ + DPRINTF("%s Free part (%d)\n", __func__, i); + part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; +- part_register(bd, part, name); ++ part_register(bd, part, name, i); + } else if (strncmp("Apple_partition_map", type, 32) == 0 || + strncmp("Apple_Partition_Map", type, 32) == 0 + #if 0 // Is this really used or is it just a mistake ? +@@ -226,7 +230,7 @@ + */ + } + part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; +- part_register(bd, part, name); ++ part_register(bd, part, name, i); + } else if (strncmp("Apple_Driver", type, 32) == 0 || + strncmp("Apple_Driver43", type, 32) == 0 || + strncmp("Apple_Driver43_CD", type, 32) == 0 || +@@ -236,8 +240,12 @@ + strncmp("Apple_Driver_IOKit", type, 32) == 0) { + /* Drivers. don't care for now */ + DPRINTF("%s Drivers part\t%d [%s]\n", __func__, i, type); ++ part->flags = PART_TYPE_APPLE | PART_FLAG_DRIVER; ++ part_register(bd, part, name, i); + } else if (strncmp("Apple_Patches", type, 32) == 0) { + /* Patches: don't care for now */ ++ part->flags = PART_TYPE_APPLE | PART_FLAG_PATCH; ++ part_register(bd, part, name, i); + DPRINTF("%s Patches part\t%d [%s]\n", __func__, i, type); + } else if (strncmp("Apple_HFS", type, 32) == 0 || + strncmp("Apple_MFS", type, 32) == 0 || +@@ -256,9 +264,8 @@ + count = partmap->bloc_cnt * HFS_BLOCSIZE; + if (partmap->boot_size == 0 || partmap->boot_load == 0) { + printf("Not a bootable partition %d %d (%p %p)\n", +- partmap->boot_size, partmap->boot_load,boot_part, part); +- if (boot_part == NULL) +- boot_part = part; ++ partmap->boot_size, partmap->boot_load, ++ boot_part, part); + part->flags = PART_TYPE_APPLE | PART_FLAG_FS; + } else { + part->boot_start.bloc = partmap->boot_start; +@@ -278,8 +285,8 @@ + boot_part = part; + part->flags = PART_TYPE_APPLE | PART_FLAG_FS | PART_FLAG_BOOT; + } +- printf("Partition: %d %s st %0x size %0x", +- i, name, partmap->start_bloc, partmap->bloc_cnt); ++ printf("Partition: %d '%s' '%s' st %0x size %0x", ++ i, name, type, partmap->start_bloc, partmap->bloc_cnt); + #ifndef DEBUG + printf("\n"); + #endif +@@ -290,11 +297,13 @@ + part->boot_load, part->boot_entry); + DPRINTF(" load %0x entry %0x %0x\n", + partmap->boot_load2, partmap->boot_entry2, HFS_BLOCSIZE); +- part_register(bd, part, name); ++ part_register(bd, part, name, i); + } else { + memcpy(tmp, type, 32); + tmp[32] = '\0'; + ERROR("Unknown partition type [%s]\n", tmp); ++ part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY; ++ part_register(bd, part, name, i); + } + } + error: +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/core.c OpenHackWare-release-0.4/src/libpart/core.c +--- OpenHackWare-release-0.4.org/src/libpart/core.c 2005-03-31 09:23:33.000000000 +0200 ++++ OpenHackWare-release-0.4/src/libpart/core.c 2005-07-03 16:17:41.000000000 +0200 +@@ -126,7 +126,7 @@ + } + + int part_register (bloc_device_t *bd, part_t *partition, +- const unsigned char *name) ++ const unsigned char *name, int partnum) + { + part_t **cur; + +@@ -134,6 +134,7 @@ + partition->bd = bd; + partition->next = NULL; + partition->name = strdup(name); ++ partition->partnum = partnum; + for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) + continue; + *cur = partition; +@@ -141,29 +142,15 @@ + return 0; + } + +-static inline int set_boot_part (bloc_device_t *bd, int partnum) +-{ +- part_t *cur; +- +- cur = part_get(bd, partnum); +- if (cur == NULL) +- return -1; +- bd_set_boot_part(bd, cur); +- +- return 0; +-} +- + part_t *part_get (bloc_device_t *bd, int partnum) + { + part_t **listp, *cur; +- int i; + + listp = _bd_parts(bd); +- cur = *listp; +- for (i = 0; i != partnum; i++) { +- if (cur == NULL) ++ ++ for (cur = *listp; cur != NULL; cur = cur->next) { ++ if (cur->partnum == partnum) + break; +- cur = cur->next; + } + + return cur; +@@ -192,17 +179,20 @@ + part_set_blocsize(bd, part, 512); + part->bd = bd; + part->flags = PART_TYPE_RAW | PART_FLAG_BOOT; +- part_register(bd, part, "Raw"); ++ part_register(bd, part, "Raw", 0); + + return part; + } + ++bloc_device_t *part_get_bd (part_t *part) ++{ ++ return part->bd; ++} ++ + part_t *part_probe (bloc_device_t *bd, int set_raw) + { +- part_t *part0, *boot_part, **cur; ++ part_t *part0 = NULL, *boot_part, **cur; + +- /* Register the 0 partition: raw partition containing the whole disk */ +- part0 = part_get_raw(bd); + /* Try to find a valid boot partition */ + boot_part = Apple_probe_partitions(bd); + if (boot_part == NULL) { +@@ -210,10 +200,13 @@ + if (boot_part == NULL && arch == ARCH_PREP) + boot_part = PREP_find_partition(bd); + if (boot_part == NULL && set_raw != 0) { +- boot_part = part0; +- set_boot_part(bd, 0); ++ dprintf("Use bloc device as raw partition\n"); + } + } ++ if (_bd_parts(bd) == NULL) { ++ /* Register the 0 partition: raw partition containing the whole disk */ ++ part0 = part_get_raw(bd); ++ } + /* Probe filesystem on each found partition */ + for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) { + const unsigned char *map, *type; +@@ -248,23 +241,28 @@ + type = "unknown"; + break; + } +- DPRINTF("Probe filesystem on %s %s partition '%s' %s\n", ++ dprintf("Probe filesystem on %s %s partition '%s' %s %p\n", + type, map, (*cur)->name, +- ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : ""); ++ ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : "", *cur); + if (((*cur)->flags) & PART_FLAG_FS) { + if (((*cur)->flags) & PART_FLAG_BOOT) + (*cur)->fs = fs_probe(*cur, 1); + else + (*cur)->fs = fs_probe(*cur, 0); ++ } else if (((*cur)->flags) & PART_TYPE_RAW) { ++ (*cur)->fs = fs_probe(*cur, 2); + } else { + (*cur)->fs = fs_probe(*cur, 2); + } +- if (((*cur)->flags) & PART_FLAG_BOOT) { +- bd_set_boot_part(bd, *cur); + fs_get_bootfile((*cur)->fs); ++ if (((*cur)->flags) & PART_FLAG_BOOT) { ++ dprintf("Partition is bootable (%d)\n", (*cur)->partnum); ++ bd_set_boot_part(bd, *cur, (*cur)->partnum); ++ if (boot_part == NULL) ++ boot_part = *cur; + } + } +- DPRINTF("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs, ++ dprintf("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs, + part_fs(boot_part), part0); + + return boot_part; +@@ -279,6 +277,7 @@ + part->boot_size.offset = 0; + part->boot_load = 0; + part->boot_entry = 0; ++ part->flags |= PART_FLAG_BOOT; + + return 0; + } +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/isofs.c OpenHackWare-release-0.4/src/libpart/isofs.c +--- OpenHackWare-release-0.4.org/src/libpart/isofs.c 2005-03-31 09:23:33.000000000 +0200 ++++ OpenHackWare-release-0.4/src/libpart/isofs.c 2005-07-03 16:17:41.000000000 +0200 +@@ -242,7 +242,7 @@ + part->boot_start.bloc, part->boot_size.bloc, + part->boot_load, part->boot_entry); + part->flags = PART_TYPE_ISO9660 | PART_FLAG_BOOT; +- part_register(bd, part, name); ++ part_register(bd, part, name, i + 1); + fs_raw_set_bootfile(part, part->boot_start.bloc, + part->boot_start.offset, + part->boot_size.bloc, +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/libpart.h OpenHackWare-release-0.4/src/libpart/libpart.h +--- OpenHackWare-release-0.4.org/src/libpart/libpart.h 2005-03-31 09:23:33.000000000 +0200 ++++ OpenHackWare-release-0.4/src/libpart/libpart.h 2005-07-03 16:17:41.000000000 +0200 +@@ -30,6 +30,7 @@ + + struct part_t { + bloc_device_t *bd; ++ int partnum; + uint32_t start; /* Partition first bloc */ + uint32_t size; /* Partition size, in blocs */ + uint32_t spb; +@@ -54,7 +55,7 @@ + }; + + int part_register (bloc_device_t *bd, part_t *partition, +- const unsigned char *name); ++ const unsigned char *name, int partnum); + void part_set_blocsize (bloc_device_t *bd, part_t *part, uint32_t blocsize); + void part_private_set (part_t *part, void *private); + void *part_private_get (part_t *part); +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/prep.c OpenHackWare-release-0.4/src/libpart/prep.c +--- OpenHackWare-release-0.4.org/src/libpart/prep.c 2005-03-31 09:23:33.000000000 +0200 ++++ OpenHackWare-release-0.4/src/libpart/prep.c 2005-07-03 16:17:41.000000000 +0200 +@@ -164,7 +164,7 @@ + part->boot_load = 0; + part->boot_entry = boot_offset - part->bloc_size; + part->flags = PART_TYPE_PREP | PART_FLAG_BOOT; +- part_register(bd, part, "PREP boot"); ++ part_register(bd, part, "PREP boot", i); + fs_raw_set_bootfile(part, part->boot_start.bloc, + part->boot_start.offset, + part->boot_size.bloc, +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/main.c OpenHackWare-release-0.4/src/main.c +--- OpenHackWare-release-0.4.org/src/main.c 2005-03-31 09:23:33.000000000 +0200 ++++ OpenHackWare-release-0.4/src/main.c 2005-06-07 23:48:39.000000000 +0200 +@@ -364,20 +364,24 @@ + void *load_base, *load_entry, *last_alloc, *load_end; + uint32_t memsize, boot_image_size, cmdline_size, ramdisk_size; + uint32_t boot_base, boot_nb; +- int boot_device; ++ int boot_device, i; ++ static const uint32_t isa_base_tab[3] = { ++ 0x80000000, /* PREP */ ++ 0xFE000000, /* Grackle (Heathrow) */ ++ 0xF2000000, /* UniNorth (Mac99) */ ++ }; + + /* Retrieve NVRAM configuration */ +- nvram_retry: ++ for(i = 0; i < 3; i++) { ++ isa_io_base = isa_base_tab[i]; + nvram = NVRAM_get_config(&memsize, &boot_device, + &boot_image, &boot_image_size, + &cmdline, &cmdline_size, + &ramdisk, &ramdisk_size); +- if (nvram == NULL) { +- /* Retry with another isa_io_base */ +- if (isa_io_base == 0x80000000) { +- isa_io_base = 0xF2000000; +- goto nvram_retry; ++ if (nvram) ++ break; + } ++ if (i == 3) { + ERROR("Unable to load configuration from NVRAM. Aborting...\n"); + return -1; + } +@@ -402,7 +406,7 @@ + cpu_name = CPU_get_name(pvr); + OF_register_cpu(cpu_name, 0, pvr, + 200 * 1000 * 1000, 200 * 1000 * 1000, +- 100 * 1000 * 1000, 10 * 1000 * 1000, ++ 100 * 1000 * 1000, 100 * 1000 * 1000, + 0x0092); + } + OF_register_memory(memsize, 512 * 1024 /* TOFIX */); +@@ -433,9 +437,12 @@ + vga_puts(copyright); + vga_puts("\n"); + ++#if 0 + /* QEMU is quite incoherent: d is cdrom, not second drive */ ++ /* XXX: should probe CD-ROM position */ + if (boot_device == 'd') + boot_device = 'e'; ++#endif + /* Open boot device */ + boot_part = bd_probe(boot_device); + if (boot_device == 'm') { +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/nvram.c OpenHackWare-release-0.4/src/nvram.c +--- OpenHackWare-release-0.4.org/src/nvram.c 2005-03-31 09:23:33.000000000 +0200 ++++ OpenHackWare-release-0.4/src/nvram.c 2005-06-04 23:44:03.000000000 +0200 +@@ -334,6 +334,7 @@ + ret = NVRAM_chrp_format(nvram); + break; + case ARCH_MAC99: ++ case ARCH_HEATHROW: /* XXX: may be incorrect */ + ret = NVRAM_mac99_format(nvram); + break; + case ARCH_POP: +@@ -409,13 +410,12 @@ + arch = ARCH_MAC99; + } else if (strcmp(sign, "POP") == 0) { + arch = ARCH_POP; ++ } else if (strcmp(sign, "HEATHROW") == 0) { ++ arch = ARCH_HEATHROW; + } else { + ERROR("Unknown PPC architecture: '%s'\n", sign); + return NULL; + } +- /* HACK */ +- if (arch == ARCH_CHRP) +- arch = ARCH_MAC99; + lword = NVRAM_get_lword(nvram, 0x30); + *RAM_size = lword; + byte = NVRAM_get_byte(nvram, 0x34); +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/of.c OpenHackWare-release-0.4/src/of.c +--- OpenHackWare-release-0.4.org/src/of.c 2005-04-06 23:17:26.000000000 +0200 ++++ OpenHackWare-release-0.4/src/of.c 2005-07-03 17:46:25.000000000 +0200 +@@ -489,7 +489,7 @@ + ERROR("%s can't alloc new node '%s' name\n", __func__, name); + return NULL; + } +- new->prop_address = OF_prop_int_new(env, new, "address", address); ++ new->prop_address = OF_prop_int_new(env, new, "unit-address", address); + if (new->prop_address == NULL) { + free(new->prop_name->value); + free(new->prop_name); +@@ -1421,15 +1421,12 @@ + __attribute__ (( section (".OpenFirmware") )) + int OF_init (void) + { +- const unsigned char compat_str[] = + #if 0 + "PowerMac3,1\0MacRISC\0Power Macintosh\0"; + "PowerMac1,2\0MacRISC\0Power Macintosh\0"; + "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0"; + "AAPL,PowerMac3,0\0MacRISC\0Power Macintosh\0"; + "AAPL,Gossamer\0MacRISC\0Power Macintosh\0"; +-#else +- "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0"; + #endif + OF_env_t *OF_env; + OF_node_t *als, *opt, *chs, *pks; +@@ -1455,15 +1452,21 @@ + return -1; + } + OF_prop_string_new(OF_env, OF_node_root, "device_type", "bootrom"); +-#if 0 +- OF_prop_string_new(OF_env, OF_node_root, +- "model", "PPC Open Hack'Ware " BIOS_VERSION); +-#else ++ if (arch == ARCH_HEATHROW) { ++ const unsigned char compat_str[] = ++ "PowerMac1,1\0MacRISC\0Power Macintosh"; ++ OF_property_new(OF_env, OF_node_root, "compatible", ++ compat_str, sizeof(compat_str)); + OF_prop_string_new(OF_env, OF_node_root, +- "model", compat_str); +-#endif ++ "model", "Power Macintosh"); ++ } else { ++ const unsigned char compat_str[] = ++ "PowerMac3,1\0MacRISC\0Power Macintosh"; + OF_property_new(OF_env, OF_node_root, "compatible", + compat_str, sizeof(compat_str)); ++ OF_prop_string_new(OF_env, OF_node_root, ++ "model", "PowerMac3,1"); ++ } + #if 0 + OF_prop_string_new(OF_env, OF_node_root, "copyright", copyright); + #else +@@ -1561,14 +1564,15 @@ + range.size = 0x00800000; + OF_property_new(OF_env, rom, "ranges", &range, sizeof(OF_range_t)); + OF_prop_int_new(OF_env, rom, "#address-cells", 1); ++ + /* "/rom/boot-rom@fff00000" node */ +- brom = OF_node_new(OF_env, OF_node_root, "boot-rom", 0xfff00000); ++ brom = OF_node_new(OF_env, rom, "boot-rom", 0xfff00000); + if (brom == NULL) { + ERROR("Cannot create 'boot-rom'\n"); + return -1; + } + regs.address = 0xFFF00000; +- regs.size = 0x00010000; ++ regs.size = 0x00100000; + OF_property_new(OF_env, brom, "reg", ®s, sizeof(OF_regprop_t)); + OF_prop_string_new(OF_env, brom, "write-characteristic", "flash"); + OF_prop_string_new(OF_env, brom, "BootROM-build-date", +@@ -1577,7 +1581,7 @@ + OF_prop_string_new(OF_env, brom, "copyright", copyright); + OF_prop_string_new(OF_env, brom, "model", BIOS_str); + OF_prop_int_new(OF_env, brom, "result", 0); +-#if 0 ++#if 1 + { + /* Hack taken 'as-is' from PearPC */ + unsigned char info[] = { +@@ -1596,7 +1600,9 @@ + OF_node_put(OF_env, brom); + OF_node_put(OF_env, rom); + } ++#if 0 + /* From here, hardcoded hacks to get a Mac-like machine */ ++ /* XXX: Core99 does not seem to like this NVRAM tree */ + /* "/nvram@fff04000" node */ + { + OF_regprop_t regs; +@@ -1617,6 +1623,7 @@ + OF_prop_int_new(OF_env, chs, "nvram", OF_pack_handle(OF_env, nvr)); + OF_node_put(OF_env, nvr); + } ++#endif + /* "/pseudo-hid" : hid emulation as Apple does */ + { + OF_node_t *hid; +@@ -1663,7 +1670,27 @@ + } + OF_node_put(OF_env, hid); + } ++ if (arch == ARCH_MAC99) { ++ OF_node_t *unin; ++ OF_regprop_t regs; + ++ unin = OF_node_new(OF_env, OF_node_root, ++ "uni-n", 0xf8000000); ++ if (unin == NULL) { ++ ERROR("Cannot create 'uni-n'\n"); ++ return -1; ++ } ++ OF_prop_string_new(OF_env, unin, "device-type", "memory-controller"); ++ OF_prop_string_new(OF_env, unin, "model", "AAPL,UniNorth"); ++ OF_prop_string_new(OF_env, unin, "compatible", "uni-north"); ++ regs.address = 0xf8000000; ++ regs.size = 0x01000000; ++ OF_property_new(OF_env, unin, "reg", ®s, sizeof(regs)); ++ OF_prop_int_new(OF_env, unin, "#address-cells", 1); ++ OF_prop_int_new(OF_env, unin, "#size-cells", 1); ++ OF_prop_int_new(OF_env, unin, "device-rev", 3); ++ OF_node_put(OF_env, unin); ++ } + + #if 1 /* This is mandatory for claim to work + * but I don't know where it should really be (in cpu ?) +@@ -1693,7 +1720,9 @@ + + /* "/options/boot-args" node */ + { +- const unsigned char *args = "-v rootdev cdrom"; ++ // const unsigned char *args = "-v rootdev cdrom"; ++ //const unsigned char *args = "-v io=0xffffffff"; ++ const unsigned char *args = "-v"; + /* Ask MacOS X to print debug messages */ + // OF_prop_string_new(OF_env, chs, "machargs", args); + // OF_prop_string_new(OF_env, opt, "boot-command", args); +@@ -2021,9 +2050,9 @@ + if (dev->acells != 0) + OF_prop_int_new(OF_env, node, "#address-cells", dev->acells); + if (dev->scells != 0) +- OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->acells); ++ OF_prop_int_new(OF_env, node, "#size-cells", dev->scells); + if (dev->icells != 0) +- OF_prop_int_new(OF_env, node, "#size-cells", dev->acells); ++ OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->icells); + dprintf("Done %p %p\n", parent, node); + + return node; +@@ -2040,8 +2069,9 @@ + OF_env_t *OF_env; + pci_range_t ranges[3]; + OF_regprop_t regs[1]; +- OF_node_t *pci_host; ++ OF_node_t *pci_host, *als; + int nranges; ++ unsigned char buffer[OF_NAMELEN_MAX]; + + OF_env = OF_env_main; + dprintf("register PCI host '%s' '%s' '%s' '%s'\n", +@@ -2052,6 +2082,17 @@ + ERROR("Cannot create pci host\n"); + return NULL; + } ++ ++ als = OF_node_get(OF_env, "aliases"); ++ if (als == NULL) { ++ ERROR("Cannot get 'aliases'\n"); ++ return NULL; ++ } ++ sprintf(buffer, "/%s", dev->name); ++ OF_prop_string_set(OF_env, als, "pci", buffer); ++ OF_node_put(OF_env, als); ++ ++ + regs[0].address = cfg_base; + regs[0].size = cfg_len; + OF_property_new(OF_env, pci_host, "reg", regs, sizeof(OF_regprop_t)); +@@ -2136,6 +2177,11 @@ + return pci_dev; + } + ++/* XXX: suppress that, used for interrupt map init */ ++OF_node_t *pci_host_node; ++uint32_t pci_host_interrupt_map[7 * 32]; ++int pci_host_interrupt_map_len = 0; ++ + void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses) + { + OF_env_t *OF_env; +@@ -2145,10 +2191,12 @@ + regs[0].address = first_bus; + regs[0].size = nb_busses; + OF_property_new(OF_env, dev, "bus-range", regs, sizeof(OF_regprop_t)); ++ pci_host_node = dev; + } + + void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn, +- uint32_t *regions, uint32_t *sizes) ++ uint32_t *regions, uint32_t *sizes, ++ int irq_line) + { + OF_env_t *OF_env; + pci_reg_prop_t pregs[6], rregs[6]; +@@ -2156,6 +2204,7 @@ + int i, j, k; + + OF_env = OF_env_main; ++ /* XXX: only useful for VGA card in fact */ + if (regions[0] != 0x00000000) + OF_prop_int_set(OF_env, dev, "address", regions[0] & ~0x0000000F); + for (i = 0, j = 0, k = 0; i < 6; i++) { +@@ -2222,7 +2271,22 @@ + } else { + OF_property_new(OF_env, dev, "assigned-addresses", NULL, 0); + } +-#if 0 ++ if (irq_line >= 0) { ++ int i; ++ OF_prop_int_new(OF_env, dev, "interrupts", 1); ++ i = pci_host_interrupt_map_len; ++ pci_host_interrupt_map[i++] = (devfn << 8) & 0xf800; ++ pci_host_interrupt_map[i++] = 0; ++ pci_host_interrupt_map[i++] = 0; ++ pci_host_interrupt_map[i++] = 0; ++ pci_host_interrupt_map[i++] = 0; /* pic handle will be patched later */ ++ pci_host_interrupt_map[i++] = irq_line; ++ if (arch != ARCH_HEATHROW) { ++ pci_host_interrupt_map[i++] = 1; ++ } ++ pci_host_interrupt_map_len = i; ++ } ++#if 1 + { + OF_prop_t *prop_name = ((OF_node_t *)dev)->prop_name; + +@@ -2390,6 +2454,54 @@ + return 0; + } + ++static void keylargo_ata(OF_node_t *mio, uint32_t base_address, ++ uint32_t base, int irq1, int irq2, ++ uint16_t pic_phandle) ++{ ++ OF_env_t *OF_env = OF_env_main; ++ OF_node_t *ata; ++ OF_regprop_t regs[2]; ++ ++ ata = OF_node_new(OF_env, mio, "ata-4", base); ++ if (ata == NULL) { ++ ERROR("Cannot create 'ata-4'\n"); ++ return; ++ } ++ OF_prop_string_new(OF_env, ata, "device_type", "ata"); ++#if 1 ++ OF_prop_string_new(OF_env, ata, "compatible", "key2largo-ata"); ++ OF_prop_string_new(OF_env, ata, "model", "ata-4"); ++ OF_prop_string_new(OF_env, ata, "cable-type", "80-conductor"); ++#else ++ OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); ++ OF_prop_string_new(OF_env, ata, "model", "ata-4"); ++#endif ++ OF_prop_int_new(OF_env, ata, "#address-cells", 1); ++ OF_prop_int_new(OF_env, ata, "#size-cells", 0); ++ regs[0].address = base; ++ regs[0].size = 0x00001000; ++#if 0 // HACK: Don't set up DMA registers ++ regs[1].address = 0x00008A00; ++ regs[1].size = 0x00001000; ++ OF_property_new(OF_env, ata, "reg", ++ regs, 2 * sizeof(OF_regprop_t)); ++#else ++ OF_property_new(OF_env, ata, "reg", ++ regs, sizeof(OF_regprop_t)); ++#endif ++ OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle); ++ regs[0].address = irq1; ++ regs[0].size = 0x00000001; ++ regs[1].address = irq2; ++ regs[1].size = 0x00000000; ++ OF_property_new(OF_env, ata, "interrupts", ++ regs, 2 * sizeof(OF_regprop_t)); ++ if (base == 0x1f000) ++ ide_pci_pmac_register(base_address + base, 0x00000000, ata); ++ else ++ ide_pci_pmac_register(0x00000000, base_address + base, ata); ++} ++ + void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size, + void *private_data) + { +@@ -2398,6 +2510,8 @@ + pci_reg_prop_t pregs[2]; + OF_node_t *mio, *chs, *als; + uint16_t pic_phandle; ++ int rec_len; ++ OF_prop_t *mio_reg; + + OF_DPRINTF("mac-io: %p\n", dev); + OF_env = OF_env_main; +@@ -2416,10 +2530,14 @@ + mio = dev; + mio->private_data = private_data; + pregs[0].addr.hi = 0x00000000; +- pregs[0].addr.mid = 0x82013810; ++ pregs[0].addr.mid = 0x00000000; + pregs[0].addr.lo = 0x00000000; + pregs[0].size_hi = base_address; + pregs[0].size_lo = size; ++ mio_reg = OF_property_get(OF_env, mio, "reg"); ++ if (mio_reg && mio_reg->vlen >= 5 * 4) { ++ pregs[0].addr.mid = ((pci_reg_prop_t *)mio_reg->value)->addr.hi; ++ } + OF_property_new(OF_env, mio, "ranges", + &pregs, sizeof(pci_reg_prop_t)); + #if 0 +@@ -2431,8 +2549,49 @@ + OF_property_new(OF_env, mio, "assigned-addresses", + &pregs, sizeof(pci_reg_prop_t)); + #endif +- /* OpenPIC */ ++ ++ switch(arch) { ++ default: ++ case ARCH_MAC99: ++ OF_prop_int_new(OF_env, mio, "#interrupt-cells", 2); ++ OF_prop_string_new(OF_env, mio, "model", "AAPL,Keylargo"); ++ OF_prop_string_new(OF_env, mio, "compatible", "Keylargo"); ++ break; ++ case ARCH_HEATHROW: ++ OF_prop_int_new(OF_env, mio, "#interrupt-cells", 1); ++ OF_prop_string_new(OF_env, mio, "model", "AAPL,343S1211"); + { ++ const char str[] = "paddington\0heathrow"; ++ OF_property_new(OF_env, mio, "compatible", str, sizeof(str)); ++ } ++ break; ++ } ++ ++ if (arch == ARCH_HEATHROW) { ++ /* Heathrow PIC */ ++ OF_regprop_t regs; ++ OF_node_t *mpic; ++ const char compat_str[] = "heathrow\0mac-risc"; ++ ++ mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x10); ++ if (mpic == NULL) { ++ ERROR("Cannot create 'mpic'\n"); ++ goto out; ++ } ++ OF_prop_string_new(OF_env, mpic, "device_type", "interrupt-controller"); ++ OF_property_new(OF_env, mpic, "compatible", compat_str, sizeof(compat_str)); ++ OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 1); ++ regs.address = 0x10; ++ regs.size = 0x20; ++ OF_property_new(OF_env, mpic, "reg", ++ ®s, sizeof(regs)); ++ OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0); ++ pic_phandle = OF_pack_handle(OF_env, mpic); ++ OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle); ++ OF_node_put(OF_env, mpic); ++ rec_len = 6; ++ } else { ++ /* OpenPIC */ + OF_regprop_t regs[4]; + OF_node_t *mpic; + mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x40000); +@@ -2455,8 +2614,37 @@ + pic_phandle = OF_pack_handle(OF_env, mpic); + OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle); + OF_node_put(OF_env, mpic); ++ rec_len = 7; + } +-#if 1 ++ ++ /* patch pci host table */ ++ /* XXX: do it after the PCI init */ ++ { ++ int i; ++ uint32_t tab[4]; ++ ++ for(i = 0; i < pci_host_interrupt_map_len; i += rec_len) ++ pci_host_interrupt_map[i + 4] = pic_phandle; ++#if 0 ++ dprintf("interrupt-map:\n"); ++ for(i = 0; i < pci_host_interrupt_map_len; i++) { ++ dprintf(" %08x", pci_host_interrupt_map[i]); ++ if ((i % rec_len) == (rec_len - 1)) ++ dprintf("\n"); ++ } ++ dprintf("\n"); ++#endif ++ OF_property_new(OF_env, pci_host_node, "interrupt-map", ++ pci_host_interrupt_map, ++ pci_host_interrupt_map_len * sizeof(uint32_t)); ++ tab[0] = 0xf800; ++ tab[1] = 0; ++ tab[2] = 0; ++ tab[3] = 0; ++ OF_property_new(OF_env, pci_host_node, "interrupt-map-mask", ++ tab, 4 * sizeof(uint32_t)); ++ } ++#if 0 + /* escc is usefull to get MacOS X debug messages */ + { + OF_regprop_t regs[8]; +@@ -2645,85 +2833,12 @@ + OF_node_put(OF_env, scc); + } + #endif +- /* IDE controller */ +- { +- OF_node_t *ata; +- OF_regprop_t regs[2]; +- ata = OF_node_new(OF_env, mio, "ata-4", 0x1f000); +- if (ata == NULL) { +- ERROR("Cannot create 'ata-4'\n"); +- goto out; +- } +- OF_prop_string_new(OF_env, ata, "device_type", "ata"); +-#if 1 +- OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata"); +- OF_prop_string_new(OF_env, ata, "model", "ata-4"); +-#else +- OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); +- OF_prop_string_new(OF_env, ata, "model", "ata-4"); +-#endif +- OF_prop_int_new(OF_env, ata, "#address-cells", 1); +- OF_prop_int_new(OF_env, ata, "#size-cells", 0); +- regs[0].address = 0x0001F000; +- regs[0].size = 0x00001000; +-#if 0 // HACK: Don't set up DMA registers +- regs[1].address = 0x00008A00; +- regs[1].size = 0x00001000; +- OF_property_new(OF_env, ata, "reg", +- regs, 2 * sizeof(OF_regprop_t)); +-#else +- OF_property_new(OF_env, ata, "reg", +- regs, sizeof(OF_regprop_t)); +-#endif +- OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle); +- regs[0].address = 0x00000013; +- regs[0].size = 0x00000001; +- regs[1].address = 0x0000000B; +- regs[1].size = 0x00000000; +- OF_property_new(OF_env, ata, "interrupts", +- regs, 2 * sizeof(OF_regprop_t)); +- ide_pci_pmac_register(base_address + 0x1f000, 0x00000000, ata); +- +- } +- { +- OF_node_t *ata; +- OF_regprop_t regs[2]; +- ata = OF_node_new(OF_env, mio, "ata-4", 0x20000); +- if (ata == NULL) { +- ERROR("Cannot create 'ata-4'\n"); +- goto out; +- } +- OF_prop_string_new(OF_env, ata, "device_type", "ata"); +-#if 1 +- OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata"); +- OF_prop_string_new(OF_env, ata, "model", "ata-4"); +-#else +- OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); +- OF_prop_string_new(OF_env, ata, "model", "ata-4"); +-#endif +- OF_prop_int_new(OF_env, ata, "#address-cells", 1); +- OF_prop_int_new(OF_env, ata, "#size-cells", 0); +- regs[0].address = 0x00020000; +- regs[0].size = 0x00001000; +-#if 0 // HACK: Don't set up DMA registers +- regs[1].address = 0x00008A00; +- regs[1].size = 0x00001000; +- OF_property_new(OF_env, ata, "reg", +- regs, 2 * sizeof(OF_regprop_t)); +-#else +- OF_property_new(OF_env, ata, "reg", +- regs, sizeof(OF_regprop_t)); +-#endif +- OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle); +- regs[0].address = 0x00000014; +- regs[0].size = 0x00000001; +- regs[1].address = 0x0000000B; +- regs[1].size = 0x00000000; +- OF_property_new(OF_env, ata, "interrupts", +- regs, 2 * sizeof(OF_regprop_t)); +- ide_pci_pmac_register(0x00000000, base_address + 0x20000, ata); +- ++ /* Keylargo IDE controller: need some work (DMA problem ?) */ ++ if (arch == ARCH_MAC99) { ++ keylargo_ata(mio, base_address, 0x1f000, 0x13, 0xb, pic_phandle); ++ keylargo_ata(mio, base_address, 0x20000, 0x14, 0xb, pic_phandle); + } ++#if 0 + /* Timer */ + { + OF_node_t *tmr; +@@ -2746,10 +2861,11 @@ + regs, sizeof(OF_regprop_t)); + OF_node_put(OF_env, tmr); + } ++#endif + /* VIA-PMU */ + { + /* Controls adb, RTC and power-mgt (forget it !) */ +- OF_node_t *via, *adb, *rtc; ++ OF_node_t *via, *adb; + OF_regprop_t regs[1]; + #if 0 // THIS IS A HACK AND IS COMPLETELY ABSURD ! + // (but needed has Qemu doesn't emulate via-pmu). +@@ -2773,14 +2889,21 @@ + regs[0].size = 0x00002000; + OF_property_new(OF_env, via, "reg", regs, sizeof(OF_regprop_t)); + OF_prop_int_new(OF_env, via, "interrupt-parent", pic_phandle); ++ if (arch == ARCH_HEATHROW) { ++ OF_prop_int_new(OF_env, via, "interrupts", 0x12); ++ } else { + regs[0].address = 0x00000019; + regs[0].size = 0x00000001; + OF_property_new(OF_env, via, "interrupts", + regs, sizeof(OF_regprop_t)); ++ } ++ /* force usage of OF bus speeds */ ++ OF_prop_int_new(OF_env, via, "BusSpeedCorrect", 1); + #if 0 + OF_prop_int_new(OF_env, via, "pmu-version", 0x00D0740C); + #endif +-#if 1 ++ { ++ OF_node_t *kbd, *mouse; + /* ADB pseudo-device */ + adb = OF_node_new(OF_env, via, "adb", OF_ADDRESS_NONE); + if (adb == NULL) { +@@ -2797,9 +2920,26 @@ + OF_prop_int_new(OF_env, adb, "#size-cells", 0); + OF_pack_get_path(OF_env, tmp, 512, adb); + OF_prop_string_new(OF_env, als, "adb", tmp); +- /* XXX: add "keyboard@2" and "mouse@3" */ +- OF_node_put(OF_env, adb); +-#endif ++ ++ kbd = OF_node_new(OF_env, adb, "keyboard", 2); ++ if (kbd == NULL) { ++ ERROR("Cannot create 'kbd'\n"); ++ goto out; ++ } ++ OF_prop_string_new(OF_env, kbd, "device_type", "keyboard"); ++ OF_prop_int_new(OF_env, kbd, "reg", 2); ++ ++ mouse = OF_node_new(OF_env, adb, "mouse", 3); ++ if (mouse == NULL) { ++ ERROR("Cannot create 'mouse'\n"); ++ goto out; ++ } ++ OF_prop_string_new(OF_env, mouse, "device_type", "mouse"); ++ OF_prop_int_new(OF_env, mouse, "reg", 3); ++ OF_prop_int_new(OF_env, mouse, "#buttons", 3); ++ } ++ { ++ OF_node_t *rtc; + + rtc = OF_node_new(OF_env, via, "rtc", OF_ADDRESS_NONE); + if (rtc == NULL) { +@@ -2813,14 +2953,55 @@ + OF_prop_string_new(OF_env, rtc, "compatible", "rtc"); + #endif + OF_node_put(OF_env, rtc); +- OF_node_put(OF_env, via); + } ++ // OF_node_put(OF_env, via); ++ } ++ { ++ OF_node_t *pmgt; ++ pmgt = OF_node_new(OF_env, mio, "power-mgt", OF_ADDRESS_NONE); ++ OF_prop_string_new(OF_env, pmgt, "device_type", "power-mgt"); ++ OF_prop_string_new(OF_env, pmgt, "compatible", "cuda"); ++ OF_prop_string_new(OF_env, pmgt, "mgt-kind", "min-consumption-pwm-led"); ++ OF_node_put(OF_env, pmgt); ++ } ++ + out: + // OF_node_put(OF_env, mio); + OF_node_put(OF_env, chs); + OF_node_put(OF_env, als); + } + ++void OF_finalize_pci_ide (void *dev, ++ uint32_t io_base0, uint32_t io_base1, ++ uint32_t io_base2, uint32_t io_base3) ++{ ++ OF_env_t *OF_env = OF_env_main; ++ OF_node_t *pci_ata = dev; ++ OF_node_t *ata, *atas[2]; ++ int i; ++ ++ OF_prop_int_new(OF_env, pci_ata, "#address-cells", 1); ++ OF_prop_int_new(OF_env, pci_ata, "#size-cells", 0); ++ ++ /* XXX: Darwin handles only one device */ ++ for(i = 0; i < 1; i++) { ++ ata = OF_node_new(OF_env, pci_ata, "ata-4", i); ++ if (ata == NULL) { ++ ERROR("Cannot create 'ata-4'\n"); ++ return; ++ } ++ OF_prop_string_new(OF_env, ata, "device_type", "ata"); ++ OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata"); ++ OF_prop_string_new(OF_env, ata, "model", "ata-4"); ++ OF_prop_int_new(OF_env, ata, "#address-cells", 1); ++ OF_prop_int_new(OF_env, ata, "#size-cells", 0); ++ OF_prop_int_new(OF_env, ata, "reg", i); ++ atas[i] = ata; ++ } ++ ide_pci_pc_register(io_base0, io_base1, io_base2, io_base3, ++ atas[0], atas[1]); ++} ++ + /*****************************************************************************/ + /* Fake package */ + static void OF_method_fake (OF_env_t *OF_env) +@@ -2862,11 +3043,11 @@ + /* As we get a 1:1 mapping, do nothing */ + ihandle = popd(OF_env); + args = (void *)popd(OF_env); +- address = popd(OF_env); +- virt = popd(OF_env); +- size = popd(OF_env); + popd(OF_env); +- OF_DPRINTF("Translate address %0x %0x %0x %0x\n", ihandle, address, ++ size = popd(OF_env); ++ virt = popd(OF_env); ++ address = popd(OF_env); ++ dprintf("map %0x %0x %0x %0x\n", ihandle, address, + virt, size); + pushd(OF_env, 0); + } +@@ -3270,7 +3451,7 @@ + OF_prop_string_new(OF_env, dsk, "device_type", "block"); + OF_prop_string_new(OF_env, dsk, "category", type); + OF_prop_int_new(OF_env, dsk, "device_id", devnum); +- OF_prop_int_new(OF_env, dsk, "reg", 0); ++ OF_prop_int_new(OF_env, dsk, "reg", devnum); + OF_method_new(OF_env, dsk, "open", &OF_blockdev_open); + OF_method_new(OF_env, dsk, "seek", &OF_blockdev_seek); + OF_method_new(OF_env, dsk, "read", &OF_blockdev_read); +@@ -3432,7 +3613,8 @@ + } + + void OF_vga_register (const unsigned char *name, unused uint32_t address, +- int width, int height, int depth) ++ int width, int height, int depth, ++ unsigned long vga_bios_addr, unsigned long vga_bios_size) + { + OF_env_t *OF_env; + unsigned char tmp[OF_NAMELEN_MAX]; +@@ -3504,6 +3686,18 @@ + OF_prop_string_new(OF_env, als, "display", tmp); + OF_node_put(OF_env, als); + /* XXX: may also need read-rectangle */ ++ ++ if (vga_bios_size >= 8) { ++ const uint8_t *p; ++ int size; ++ /* check the QEMU VGA BIOS header */ ++ p = (const uint8_t *)vga_bios_addr; ++ if (p[0] == 'N' && p[1] == 'D' && p[2] == 'R' && p[3] == 'V') { ++ size = *(uint32_t *)(p + 4); ++ OF_property_new(OF_env, disp, "driver,AAPL,MacOS,PowerPC", ++ p + 8, size); ++ } ++ } + out: + OF_node_put(OF_env, disp); + } +@@ -4451,7 +4645,10 @@ + break; + case 0x233441d3: /* MacOS X 10.2 and OpenDarwin 1.41 */ + /* Create "memory-map" pseudo device */ +- popd(OF_env); ++ { ++ OF_node_t *map; ++ uint32_t phandle; ++ + /* Find "/packages" */ + chs = OF_pack_find_by_name(OF_env, OF_node_root, "/chosen"); + if (chs == NULL) { +@@ -4459,10 +4656,6 @@ + ERROR("Cannot get '/chosen'\n"); + break; + } +- { +-#if 1 +- OF_node_t *map; +- uint32_t phandle; + map = OF_node_new(OF_env, chs, "memory-map", OF_ADDRESS_NONE); + if (map == NULL) { + pushd(OF_env, -1); +@@ -4473,11 +4666,8 @@ + OF_node_put(OF_env, map); + OF_node_put(OF_env, chs); + pushd(OF_env, phandle); +- } +-#else +- pushd(OF_env, 0); +-#endif + pushd(OF_env, 0); ++ } + break; + case 0x32a2d18e: /* MacOS X 10.2 and OpenDarwin 6.02 */ + /* Return screen ihandle */ +@@ -4540,9 +4730,10 @@ + case 0x4ad41f2d: + /* Yaboot: wait 10 ms: sure ! */ + break; ++ + default: + /* ERROR */ +- printf("Script:\n%s\n", FString); ++ printf("Script: len=%d\n%s\n", (int)strlen(FString), FString); + printf("Call %0x NOT IMPLEMENTED !\n", crc); + bug(); + break; +diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/pci.c OpenHackWare-release-0.4/src/pci.c +--- OpenHackWare-release-0.4.org/src/pci.c 2005-03-31 09:23:33.000000000 +0200 ++++ OpenHackWare-release-0.4/src/pci.c 2005-07-03 15:52:16.000000000 +0200 +@@ -99,8 +99,8 @@ + uint16_t min_grant; + uint16_t max_latency; + uint8_t irq_line; +- uint32_t regions[6]; +- uint32_t sizes[6]; ++ uint32_t regions[7]; /* the region 6 is the PCI ROM */ ++ uint32_t sizes[7]; + pci_device_t *next; + }; + +@@ -158,6 +158,7 @@ + + /* IRQ numbers assigned to PCI IRQs */ + static uint8_t prep_pci_irqs[4] = { 9, 11, 9, 11 }; ++static uint8_t heathrow_pci_irqs[4] = { 0x15, 0x16, 0x17, 0x18 }; + static uint8_t pmac_pci_irqs[4] = { 8, 9, 10, 11 }; + + /* PREP PCI host */ +@@ -399,6 +400,79 @@ + &uninorth_config_readl, &uninorth_config_writel, + }; + ++/* Grackle PCI host */ ++ ++static uint32_t grackle_cfg_address (pci_bridge_t *bridge, ++ uint8_t bus, uint8_t devfn, ++ uint8_t offset) ++{ ++ uint32_t addr; ++ addr = 0x80000000 | (bus << 16) | (devfn << 8) | (offset & 0xfc); ++ stswap32((uint32_t *)bridge->cfg_addr, addr); ++ return bridge->cfg_data + (offset & 3); ++} ++ ++static uint8_t grackle_config_readb (pci_bridge_t *bridge, ++ uint8_t bus, uint8_t devfn, ++ uint8_t offset) ++{ ++ uint32_t addr; ++ addr = grackle_cfg_address(bridge, bus, devfn, offset); ++ return *((uint8_t *)addr); ++} ++ ++static void grackle_config_writeb (pci_bridge_t *bridge, ++ uint8_t bus, uint8_t devfn, ++ uint8_t offset, uint8_t val) ++{ ++ uint32_t addr; ++ addr = grackle_cfg_address(bridge, bus, devfn, offset); ++ *((uint8_t *)addr) = val; ++} ++ ++static uint16_t grackle_config_readw (pci_bridge_t *bridge, ++ uint8_t bus, uint8_t devfn, ++ uint8_t offset) ++{ ++ uint32_t addr; ++ addr = grackle_cfg_address(bridge, bus, devfn, offset); ++ return ldswap16((uint16_t *)addr); ++} ++ ++static void grackle_config_writew (pci_bridge_t *bridge, ++ uint8_t bus, uint8_t devfn, ++ uint8_t offset, uint16_t val) ++{ ++ uint32_t addr; ++ addr = grackle_cfg_address(bridge, bus, devfn, offset); ++ stswap16((uint16_t *)addr, val); ++} ++ ++static uint32_t grackle_config_readl (pci_bridge_t *bridge, ++ uint8_t bus, uint8_t devfn, ++ uint8_t offset) ++{ ++ uint32_t addr; ++ addr = grackle_cfg_address(bridge, bus, devfn, offset); ++ return ldswap32((uint32_t *)addr); ++} ++ ++static void grackle_config_writel (pci_bridge_t *bridge, ++ uint8_t bus, uint8_t devfn, ++ uint8_t offset, uint32_t val) ++{ ++ uint32_t addr; ++ ++ addr = grackle_cfg_address(bridge, bus, devfn, offset); ++ stswap32((uint32_t *)addr, val); ++} ++ ++static pci_ops_t grackle_pci_ops = { ++ &grackle_config_readb, &grackle_config_writeb, ++ &grackle_config_readw, &grackle_config_writew, ++ &grackle_config_readl, &grackle_config_writel, ++}; ++ + static inline uint8_t pci_config_readb (pci_bridge_t *bridge, + uint8_t bus, uint8_t devfn, + uint8_t offset) +@@ -466,12 +540,22 @@ + }, + }; + ++static int ide_config_cb2 (pci_device_t *device) ++{ ++ OF_finalize_pci_ide(device->common.OF_private, ++ device->regions[0] & ~0x0000000F, ++ device->regions[1] & ~0x0000000F, ++ device->regions[2] & ~0x0000000F, ++ device->regions[3] & ~0x0000000F); ++ return 0; ++} ++ + static pci_dev_t ide_devices[] = { + { +- 0x8086, 0x0100, +- NULL, "Qemu IDE", "Qemu IDE", "ide", ++ 0x1095, 0x0646, /* CMD646 IDE controller */ ++ "pci-ide", "pci-ata", NULL, NULL, + 0, 0, 0, +- NULL, NULL, ++ ide_config_cb2, NULL, + }, + { + 0xFFFF, 0xFFFF, +@@ -481,7 +565,9 @@ + }, + }; + +-static int ide_config_cb (pci_device_t *device) ++#if 0 ++/* should base it on PCI ID, not on arch */ ++static int ide_config_cb (unused pci_device_t *device) + { + printf("Register IDE controller\n"); + switch (arch) { +@@ -491,14 +577,8 @@ + device->common.OF_private); + break; + default: +- ide_pci_pc_register(device->regions[0] & ~0x0000000F, +- device->regions[1] & ~0x0000000F, +- device->regions[2] & ~0x0000000F, +- device->regions[3] & ~0x0000000F, +- device->common.OF_private); + break; + } +- + return 0; + } + +@@ -512,16 +592,12 @@ + device->common.OF_private); + break; + default: +- ide_pci_pc_register(device->regions[0] & ~0x0000000F, +- device->regions[1] & ~0x0000000F, +- device->regions[2] & ~0x0000000F, +- device->regions[3] & ~0x0000000F, +- device->common.OF_private); + break; + } + + return 0; + } ++#endif + + static pci_subclass_t mass_subclass[] = { + { +@@ -530,7 +606,7 @@ + }, + { + 0x01, "IDE controller", "ide", ide_devices, NULL, +- &ide_config_cb, NULL, ++ NULL, NULL, + }, + { + 0x02, "Floppy disk controller", NULL, NULL, NULL, +@@ -546,7 +622,7 @@ + }, + { + 0x05, "ATA controller", "ata", NULL, NULL, +- &ata_config_cb, NULL, ++ NULL, NULL, + }, + { + 0x80, "misc mass-storage controller", NULL, NULL, NULL, +@@ -646,7 +722,9 @@ + /* VGA 640x480x16 */ + OF_vga_register(device->common.device->name, + device->regions[0] & ~0x0000000F, +- vga_width, vga_height, vga_depth); ++ vga_width, vga_height, vga_depth, ++ device->regions[6] & ~0x0000000F, ++ device->sizes[6]); + } + vga_console_register(); + +@@ -750,6 +828,13 @@ + NULL, &PREP_pci_ops, + }; + ++pci_dev_t grackle_fake_bridge = { ++ 0xFFFF, 0xFFFF, ++ "pci", "pci-bridge", "DEC,21154", "DEC,21154.pci-bridge", ++ -1, -1, -1, ++ NULL, &grackle_pci_ops, ++}; ++ + static pci_dev_t hbrg_devices[] = { + { + 0x106B, 0x0020, NULL, +@@ -758,8 +843,8 @@ + NULL, &uninorth_agp_fake_bridge, + }, + { +- 0x106B, 0x001F, +- NULL, "pci", "AAPL,UniNorth", "uni-north", ++ 0x106B, 0x001F, NULL, ++ "pci", "AAPL,UniNorth", "uni-north", + 3, 2, 1, + NULL, &uninorth_fake_bridge, + }, +@@ -770,10 +855,10 @@ + NULL, &uninorth_fake_bridge, + }, + { +- 0x1011, 0x0026, NULL, +- "pci-bridge", NULL, NULL, ++ 0x1057, 0x0002, "pci", ++ "pci", "MOT,MPC106", "grackle", + 3, 2, 1, +- NULL, &PREP_pci_ops, ++ NULL, &grackle_fake_bridge, + }, + { + 0x1057, 0x4801, NULL, +@@ -1446,8 +1531,10 @@ + /* Apple Mac-io controller */ + { + 0x106B, 0x0022, +- "mac-io", "mac-io", "AAPL,Keylargo", "Keylargo", +- 1, 1, 2, ++ /* model, compatible and #interrupt-cells fields are filled in ++ of.c */ ++ "mac-io", "mac-io", NULL, NULL, ++ 1, 1, 0, + &macio_config_cb, NULL, + }, + { +@@ -1599,7 +1686,7 @@ + uint8_t min_grant, uint8_t max_latency, + int irq_line) + { +- uint32_t cmd; ++ uint32_t cmd, addr; + int i; + + device->min_grant = min_grant; +@@ -1611,22 +1698,28 @@ + printf("MAP PCI device %d:%d to IRQ %d\n", + device->bus, device->devfn, irq_line); + } +- for (i = 0; i < 6; i++) { ++ for (i = 0; i < 7; i++) { + if ((device->regions[i] & ~0xF) != 0x00000000 && + (device->regions[i] & ~0xF) != 0xFFFFFFF0) { + printf("Map PCI device %d:%d %d to %0x %0x (%s)\n", + device->bus, device->devfn, i, + device->regions[i], device->sizes[i], +- device->regions[i] & 0x00000001 ? "I/O" : "memory"); ++ (device->regions[i] & 0x00000001) && i != 6 ? "I/O" : ++ "memory"); ++ if (i != 6) { + cmd = pci_config_readl(bridge, device->bus, device->devfn, 0x04); + if (device->regions[i] & 0x00000001) + cmd |= 0x00000001; + else + cmd |= 0x00000002; + pci_config_writel(bridge, device->bus, device->devfn, 0x04, cmd); ++ } ++ if (i == 6) ++ addr = 0x30; /* PCI ROM */ ++ else ++ addr = 0x10 + (i * sizeof(uint32_t)); + pci_config_writel(bridge, device->bus, device->devfn, +- 0x10 + (i * sizeof(uint32_t)), +- device->regions[i]); ++ addr, device->regions[i]); + } + } + } +@@ -1900,7 +1993,7 @@ + goto out; + } + ret = (pci_u_t *)newd; +- max_areas = 6; ++ max_areas = 7; + /* register PCI device in OF tree */ + if (bridge->dev.common.type == PCI_FAKE_BRIDGE) { + newd->common.OF_private = +@@ -1927,6 +2020,9 @@ + /* Handle 64 bits memory mapping */ + continue; + } ++ if (i == 6) ++ addr = 0x30; /* PCI ROM */ ++ else + addr = 0x10 + (i * sizeof(uint32_t)); + /* Get region size + * Note: we assume it's always a power of 2 +@@ -1935,7 +2031,7 @@ + smask = pci_config_readl(bridge, bus, devfn, addr); + if (smask == 0x00000000 || smask == 0xFFFFFFFF) + continue; +- if (smask & 0x00000001) { ++ if ((smask & 0x00000001) != 0 && i != 6) { + /* I/O space */ + base = io_base; + /* Align to a minimum of 256 bytes (arbitrary) */ +@@ -1947,6 +2043,8 @@ + /* Align to a minimum of 64 kB (arbitrary) */ + min_align = 1 << 16; + amask = 0x0000000F; ++ if (i == 6) ++ smask |= 1; /* PCI ROM enable */ + } + omask = smask & amask; + smask &= ~amask; +@@ -1980,7 +2078,10 @@ + if (irq_pin > 0) { + /* assign the IRQ */ + irq_pin = ((devfn >> 3) + irq_pin - 1) & 3; +- if (arch == ARCH_PREP) { ++ /* XXX: should base it on the PCI bridge type, not the arch */ ++ switch(arch) { ++ case ARCH_PREP: ++ { + int elcr_port, val; + irq_line = prep_pci_irqs[irq_pin]; + /* set the IRQ to level-sensitive */ +@@ -1988,14 +2089,22 @@ + val = inb(elcr_port); + val |= 1 << (irq_line & 7); + outb(elcr_port, val); +- } else { ++ } ++ break; ++ case ARCH_MAC99: + irq_line = pmac_pci_irqs[irq_pin]; ++ break; ++ case ARCH_HEATHROW: ++ irq_line = heathrow_pci_irqs[irq_pin]; ++ break; ++ default: ++ break; + } + } + update_device: + pci_update_device(bridge, newd, min_grant, max_latency, irq_line); + OF_finalize_pci_device(newd->common.OF_private, bus, devfn, +- newd->regions, newd->sizes); ++ newd->regions, newd->sizes, irq_line); + /* Call special inits if needed */ + if (dev->config_cb != NULL) + (*dev->config_cb)(newd); +@@ -2049,6 +2158,32 @@ + case ARCH_CHRP: + /* TODO */ + break; ++ case ARCH_HEATHROW: ++ dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp); ++ if (dev == NULL) ++ return -1; ++ fake_host = pci_add_host(hostp, dev, ++ (0x06 << 24) | (0x00 << 16) | (0xFF << 8)); ++ if (fake_host == NULL) ++ return -1; ++ fake_host->dev.common.type = PCI_FAKE_HOST; ++ dev = &grackle_fake_bridge; ++ if (dev == NULL) ++ goto free_fake_host; ++ fake_bridge = pci_add_bridge(fake_host, 0, 0, dev, ++ (0x06 << 24) | (0x04 << 16) | (0xFF << 8), ++ cfg_base, cfg_len, ++ cfg_base + 0x7ec00000, ++ cfg_base + 0x7ee00000, ++ mem_base, mem_len, ++ io_base, io_len, ++ rbase, rlen, ++ 0, ++ &grackle_pci_ops); ++ if (fake_bridge == NULL) ++ goto free_fake_host; ++ fake_bridge->dev.common.type = PCI_FAKE_BRIDGE; ++ break; + case ARCH_MAC99: + dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp); + if (dev == NULL) +@@ -2167,6 +2302,30 @@ + case ARCH_CHRP: + /* TODO */ + break; ++ case ARCH_HEATHROW: ++ cfg_base = 0x80000000; ++ cfg_len = 0x7f000000; ++ mem_base = 0x80000000; ++ mem_len = 0x01000000; ++ io_base = 0xfe000000; ++ io_len = 0x00800000; ++#if 1 ++ rbase = 0xfd000000; ++ rlen = 0x01000000; ++#else ++ rbase = 0x00000000; ++ rlen = 0x01000000; ++#endif ++ if (pci_check_host(&pci_main, cfg_base, cfg_len, ++ mem_base, mem_len, io_base, io_len, rbase, rlen, ++ 0x1057, 0x0002) == 0) { ++ isa_io_base = io_base; ++ busnum++; ++ } ++ for (curh = pci_main; curh->next != NULL; curh = curh->next) ++ continue; ++ pci_check_devices(curh); ++ break; + case ARCH_MAC99: + /* We are supposed to have 3 host bridges: + * - the uninorth AGP bridge at 0xF0000000 diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin index 3755ff01e..8ba25bc37 100644 Binary files a/pc-bios/ppc_rom.bin and b/pc-bios/ppc_rom.bin differ -- cgit v1.2.3 From e0727e17f389267b03b0cabcb6d094295819054c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 16:44:10 +0000 Subject: removed bogus include git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1498 c046a42c-6fe2-441c-8c8c-71466251a162 --- mips-dis.c | 2 -- ppc-dis.c | 1 - 2 files changed, 3 deletions(-) diff --git a/mips-dis.c b/mips-dis.c index 6d7037cc6..fbc64c77c 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -3315,8 +3315,6 @@ print_insn_mips (memaddr, word, info) are single stepping, or the pc is within the disassembled function, this works. Otherwise, we need a clue. Sometimes. */ -#include "cpu.h" - static int _print_insn_mips (memaddr, info, endianness) bfd_vma memaddr; diff --git a/ppc-dis.c b/ppc-dis.c index 0da1be99e..803b9f554 100644 --- a/ppc-dis.c +++ b/ppc-dis.c @@ -3073,7 +3073,6 @@ print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr, /* Print a big endian PowerPC instruction. For convenience, also disassemble instructions supported by the Motorola PowerPC 601. */ -#include "cpu.h" int print_insn_ppc (bfd_vma pc, disassemble_info *info) { -- cgit v1.2.3 From 33d084399ca64f8b0c7c97de473eafc77b0e8a36 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 16:45:42 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1499 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + pc-bios/README | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index a55f32855..dcd252c14 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,7 @@ version 0.7.1: - SPARC64 progress (Blue Swirl) - initial MIPS support (Jocelyn mayer) - MIPS improvements (Ralf Baechle) + - 64 bit fixes in user networking (initial patch by Gwenole Beauchesne) version 0.7.0: diff --git a/pc-bios/README b/pc-bios/README index a10a9f0df..5e61a28fc 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -5,9 +5,13 @@ project (http://www.nongnu.org/vgabios/). - The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is - available at http://site.voila.fr/jmayer/OpenHackWare/index.htm. + available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm. - Proll is a GPL'd boot PROM for Sparc JavaStations (http://people.redhat.com/zaitcev/linux/). Applying proll.patch allows circumventing some bugs and enables faster kernel load through a hack. + +- video.x is a PowerMac NDRV compatible driver for a VGA frame + buffer. It comes from the Mac-on-Linux project + (http://www.maconlinux.org/). -- cgit v1.2.3 From 51a36cb2cb38bee2834de8add532cb66e4e6b884 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 17:08:43 +0000 Subject: win32 compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1500 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/udp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slirp/udp.c b/slirp/udp.c index 079c54353..be51af679 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -425,7 +425,7 @@ struct cu_header { uint32_t d_addr; // destination address uint16_t s_family; // source family uint16_t s_port; // source port - uint32_t s_addr; // source address + uint32_t so_addr; // source address uint32_t seqn; // sequence number uint16_t message; // message uint16_t data_type; // data type @@ -617,7 +617,7 @@ struct cu_header { return; cu_head = mtod(m, struct cu_header *); cu_head->s_port = addr.sin_port; - cu_head->s_addr = our_addr.s_addr; + cu_head->so_addr = our_addr.s_addr; } return; -- cgit v1.2.3 From 9d0a8e6f8fa8a877b932c99ef8b458669a73c59a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 17:34:05 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1501 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 211b6687a..439c0b057 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -39,11 +39,13 @@ performance. For system emulation, the following hardware targets are supported: @itemize -@item PC (x86 processor) +@item PC (x86 or x86_64 processor) @item PREP (PowerPC processor) -@item PowerMac (PowerPC processor, in progress) +@item G3 BW PowerMac (PowerPC processor) +@item Mac99 PowerMac (PowerPC processor, in progress) @item Sun4m (32-bit Sparc processor) @item Sun4u (64-bit Sparc processor, in progress) +@item Malta board (32-bit MIPS processor, in progress) @end itemize For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported. @@ -193,6 +195,11 @@ Start in full screen. Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. +@item -win2k-hack +Use it when installing Windows 2000 to avoid a disk full bug. After +Windows 2000 is installed, you no longer need this option (this option +slows down the IDE transfers). + @end table Network options: @@ -897,16 +904,13 @@ idle. You can install the utility from @url{http://www.user.cityline.ru/~maxamn/amnhltm.zip} to solve this problem. Note that no such tool is needed for NT, 2000 or XP. -@subsubsection Windows 2000 disk full problems - -Currently (release 0.6.0) QEMU has a bug which gives a @code{disk -full} error during installation of some releases of Windows 2000. The -workaround is to stop QEMU as soon as you notice that your disk image -size is growing too fast (monitor it with @code{ls -ls}). Then -relaunch QEMU to continue the installation. If you still experience -the problem, relaunch QEMU again. +@subsubsection Windows 2000 disk full problem -Future QEMU releases are likely to correct this bug. +Windows 2000 has a bug which gives a disk full problem during its +installation. When installing it, use the @option{-win2k-hack} QEMU +option to enable a specific workaround. After Windows 2000 is +installed, you no longer need this option (this option slows down the +IDE transfers). @subsubsection Windows XP security problems @@ -1054,6 +1058,11 @@ Set the initial TCX graphic mode. The default is 1024x768. Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine. The emulator is not usable for anything yet. +@chapter MIPS System emulator invocation + +Use the executable @file{qemu-system-mips} to simulate a MIPS machine. +The emulator begins to launch a Linux kernel. + @chapter QEMU User space emulator invocation @section Quick Start -- cgit v1.2.3 From d24b15a8d8f59c79d9183e8d884867a64cb003bb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 21:28:00 +0000 Subject: no need to dump CCOP git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1502 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index d0b011004..4e6f6faba 100644 --- a/monitor.c +++ b/monitor.c @@ -222,7 +222,7 @@ static void do_info_registers(void) { #ifdef TARGET_I386 cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, - X86_DUMP_FPU | X86_DUMP_CCOP); + X86_DUMP_FPU); #else cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, 0); -- cgit v1.2.3 From 2157fa0682e3b2a1cb0b4864e6f4b86f88b1fae2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Jul 2005 21:29:17 +0000 Subject: better fpu state dump git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1503 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 60 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 24cbcfc4e..d571458f7 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -250,7 +250,7 @@ void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { - int eflags, i; + int eflags, i, nb; char cc_op_name[32]; static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" }; @@ -398,16 +398,54 @@ void cpu_dump_state(CPUState *env, FILE *f, } } if (flags & X86_DUMP_FPU) { - cpu_fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", - (double)env->fpregs[0].d, - (double)env->fpregs[1].d, - (double)env->fpregs[2].d, - (double)env->fpregs[3].d); - cpu_fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", - (double)env->fpregs[4].d, - (double)env->fpregs[5].d, - (double)env->fpregs[7].d, - (double)env->fpregs[8].d); + int fptag; + fptag = 0; + for(i = 0; i < 8; i++) { + fptag |= ((!env->fptags[i]) << i); + } + cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n", + env->fpuc, + (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11, + env->fpstt, + fptag, + env->mxcsr); + for(i=0;i<8;i++) { +#if defined(USE_X86LDOUBLE) + union { + long double d; + struct { + uint64_t lower; + uint16_t upper; + } l; + } tmp; + tmp.d = env->fpregs[i].d; + cpu_fprintf(f, "FPR%d=%016llx %04x", + i, tmp.l.lower, tmp.l.upper); +#else + cpu_fprintf(f, "FPR%d=%016llx", + i, env->fpregs[i].mmx.q); +#endif + if ((i & 1) == 1) + cpu_fprintf(f, "\n"); + else + cpu_fprintf(f, " "); + } + if (env->hflags & HF_CS64_MASK) + nb = 16; + else + nb = 8; + for(i=0;ixmm_regs[i].XMM_L(3), + env->xmm_regs[i].XMM_L(2), + env->xmm_regs[i].XMM_L(1), + env->xmm_regs[i].XMM_L(0)); + if ((i & 1) == 1) + cpu_fprintf(f, "\n"); + else + cpu_fprintf(f, " "); + } } } -- cgit v1.2.3 From fdabc366bd922d3029b42864ecf268103d8ca8e6 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 4 Jul 2005 22:17:05 +0000 Subject: correct split between helper.c and op_helper.c - moved some uops to op_helper.c (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1504 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 9 + target-ppc/exec.h | 4 + target-ppc/helper.c | 103 ++---------- target-ppc/op.c | 267 +++++++----------------------- target-ppc/op_helper.c | 435 +++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 455 insertions(+), 363 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7fc79434a..8dd9cc12d 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -32,6 +32,15 @@ #define TARGET_HAS_ICE 1 +/* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC + * have different cache line sizes + */ +#define ICACHE_LINE_SIZE 32 +#define DCACHE_LINE_SIZE 32 + +/* XXX: put this in a common place */ +#define likely(x) __builtin_expect(!!(x), 1) + /*****************************************************************************/ /* PVR definitions for most known PowerPC */ enum { diff --git a/target-ppc/exec.h b/target-ppc/exec.h index e559d5c8c..9e8988001 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -20,8 +20,12 @@ #if !defined (__PPC_H__) #define __PPC_H__ +#include "config.h" + #include "dyngen-exec.h" +#define TARGET_LONG_BITS 32 + register struct CPUPPCState *env asm(AREG0); register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index fbecb76d0..c9693c8b1 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -17,11 +17,21 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "exec.h" +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" //#define DEBUG_MMU //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS +//#define FLUSH_ALL_TLBS /*****************************************************************************/ /* PowerPC MMU emulation */ @@ -394,92 +404,6 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } #endif -#if !defined(CONFIG_USER_ONLY) - -#define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) -{ - TranslationBlock *tb; - CPUState *saved_env; - unsigned long pc; - int ret; - - /* XXX: hack to restore env in all cases, even if not called from - generated code */ - saved_env = env; - env = cpu_single_env; -#if 0 - { - unsigned long tlb_addrr, tlb_addrw; - int index; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_addrr = env->tlb_read[is_user][index].address; - tlb_addrw = env->tlb_write[is_user][index].address; - if (loglevel) { - fprintf(logfile, - "%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " - "(0x%08lx 0x%08lx)\n", __func__, env, - &env->tlb_read[is_user][index], index, addr, - tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, - tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); - } - } -#endif - ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); - if (ret) { - if (retaddr) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - 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, NULL); - } - } - do_raise_exception_err(env->exception_index, env->error_code); - } -#if 0 - { - unsigned long tlb_addrr, tlb_addrw; - int index; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_addrr = env->tlb_read[is_user][index].address; - tlb_addrw = env->tlb_write[is_user][index].address; - printf("%s 2 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx " - "(0x%08lx 0x%08lx)\n", __func__, env, - &env->tlb_read[is_user][index], index, addr, - tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK, - tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); - } -#endif - env = saved_env; -} - -void cpu_ppc_init_mmu(CPUState *env) -{ - /* Nothing to do: all translation are disabled */ -} -#endif - /* Perform address translation */ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, int is_user, int is_softmmu) @@ -576,13 +500,14 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, error_code = EXCP_INVAL | EXCP_INVAL_INVAL; break; } + break; case -5: /* No match in segment table */ exception = EXCP_DSEG; error_code = 0; break; } - if (rw) + if (exception == EXCP_DSI && rw == 1) error_code |= 0x02000000; /* Store fault address */ env->spr[SPR_DAR] = address; @@ -1491,12 +1416,14 @@ void do_interrupt (CPUState *env) /* Jump to handler */ env->nip = excp; env->exception_index = EXCP_NONE; +#if 0 /* ensure that no TB jump will be modified as the program flow was changed */ #ifdef __sparc__ tmp_T0 = 0; #else T0 = 0; +#endif #endif env->interrupt_request |= CPU_INTERRUPT_EXITTB; } diff --git a/target-ppc/op.c b/target-ppc/op.c index c7953662b..0e37119da 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -548,16 +548,10 @@ PPC_OP(add) RETURN(); } -PPC_OP(addo) +void do_addo (void); +void op_addo (void) { - T2 = T0; - T0 += T1; - if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } + do_addo(); RETURN(); } @@ -574,53 +568,24 @@ PPC_OP(addc) RETURN(); } -PPC_OP(addco) +void do_addco (void); +void op_addco (void) { - T2 = T0; - T0 += T1; - if (T0 < T2) { - xer_ca = 1; - } else { - xer_ca = 0; - } - if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } + do_addco(); RETURN(); } /* add extended */ -/* candidate for helper (too long) */ -PPC_OP(adde) +void do_adde (void); +void op_adde (void) { - T2 = T0; - T0 += T1 + xer_ca; - if (T0 < T2 || (xer_ca == 1 && T0 == T2)) { - xer_ca = 1; - } else { - xer_ca = 0; - } - RETURN(); + do_adde(); } +void do_addeo (void); PPC_OP(addeo) { - T2 = T0; - T0 += T1 + xer_ca; - if (T0 < T2 || (xer_ca == 1 && T0 == T2)) { - xer_ca = 1; - } else { - xer_ca = 0; - } - if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } + do_addeo(); RETURN(); } @@ -654,18 +619,10 @@ PPC_OP(addme) RETURN(); } -PPC_OP(addmeo) +void do_addmeo (void); +void op_addmeo (void) { - T1 = T0; - T0 += xer_ca + (-1); - if (T1 & (T1 ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } - if (T1 != 0) - xer_ca = 1; + do_addmeo(); RETURN(); } @@ -682,26 +639,14 @@ PPC_OP(addze) RETURN(); } -PPC_OP(addzeo) +void do_addzeo (void); +void op_addzeo (void) { - T1 = T0; - T0 += xer_ca; - if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } - if (T0 < T1) { - xer_ca = 1; - } else { - xer_ca = 0; - } + do_addzeo(); RETURN(); } /* divide word */ -/* candidate for helper (too long) */ PPC_OP(divw) { if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { @@ -712,16 +657,10 @@ PPC_OP(divw) RETURN(); } -PPC_OP(divwo) +void do_divwo (void); +void op_divwo (void) { - if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { - xer_so = 1; - xer_ov = 1; - T0 = (-1) * (T0 >> 31); - } else { - xer_ov = 0; - T0 = (Ts0 / Ts1); - } + do_divwo(); RETURN(); } @@ -736,16 +675,10 @@ PPC_OP(divwu) RETURN(); } -PPC_OP(divwuo) +void do_divwuo (void); +void op_divwuo (void) { - if (T1 == 0) { - xer_so = 1; - xer_ov = 1; - T0 = 0; - } else { - xer_ov = 0; - T0 /= T1; - } + do_divwuo(); RETURN(); } @@ -777,17 +710,10 @@ PPC_OP(mullw) RETURN(); } -PPC_OP(mullwo) +void do_mullwo (void); +void op_mullwo (void) { - int64_t res = (int64_t)Ts0 * (int64_t)Ts1; - - if ((int32_t)res != res) { - xer_ov = 1; - xer_so = 1; - } else { - xer_ov = 0; - } - T0 = (int32_t)res; + do_mullwo(); RETURN(); } @@ -800,15 +726,10 @@ PPC_OP(neg) RETURN(); } -PPC_OP(nego) +void do_nego (void); +void op_nego (void) { - if (T0 == 0x80000000) { - xer_ov = 1; - xer_so = 1; - } else { - xer_ov = 0; - T0 = -Ts0; - } + do_nego(); RETURN(); } @@ -819,16 +740,10 @@ PPC_OP(subf) RETURN(); } -PPC_OP(subfo) +void do_subfo (void); +void op_subfo (void) { - T2 = T0; - T0 = T1 - T0; - if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } + do_subfo(); RETURN(); } @@ -844,52 +759,25 @@ PPC_OP(subfc) RETURN(); } -PPC_OP(subfco) +void do_subfco (void); +void op_subfco (void) { - T2 = T0; - T0 = T1 - T0; - if (T0 <= T1) { - xer_ca = 1; - } else { - xer_ca = 0; - } - if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } + do_subfco(); RETURN(); } /* substract from extended */ -/* candidate for helper (too long) */ -PPC_OP(subfe) +void do_subfe (void); +void op_subfe (void) { - T0 = T1 + ~T0 + xer_ca; - if (T0 < T1 || (xer_ca == 1 && T0 == T1)) { - xer_ca = 1; - } else { - xer_ca = 0; - } + do_subfe(); RETURN(); } +void do_subfeo (void); PPC_OP(subfeo) { - T2 = T0; - T0 = T1 + ~T0 + xer_ca; - if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } - if (T0 < T1 || (xer_ca == 1 && T0 == T1)) { - xer_ca = 1; - } else { - xer_ca = 0; - } + do_subfeo(); RETURN(); } @@ -915,18 +803,10 @@ PPC_OP(subfme) RETURN(); } -PPC_OP(subfmeo) +void do_subfmeo (void); +void op_subfmeo (void) { - T1 = T0; - T0 = ~T0 + xer_ca - 1; - if (~T1 & (~T1 ^ T0) & (1 << 31)) { - xer_so = 1; - xer_ov = 1; - } else { - xer_ov = 0; - } - if (T1 != -1) - xer_ca = 1; + do_subfmeo(); RETURN(); } @@ -943,21 +823,10 @@ PPC_OP(subfze) RETURN(); } -PPC_OP(subfzeo) +void do_subfzeo (void); +void op_subfzeo (void) { - T1 = T0; - T0 = ~T0 + xer_ca; - if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) { - xer_ov = 1; - xer_so = 1; - } else { - xer_ov = 0; - } - if (T0 < ~T1) { - xer_ca = 1; - } else { - xer_ca = 0; - } + do_subfzeo(); RETURN(); } @@ -1174,7 +1043,7 @@ PPC_OP(slw) } /* shift right algebraic word */ -PPC_OP(sraw) +void op_sraw (void) { do_sraw(); RETURN(); @@ -1227,10 +1096,9 @@ PPC_OP(fmul) } /* fdiv - fdiv. */ -void do_fdiv (void); PPC_OP(fdiv) { - do_fdiv(); + FT0 = float64_div(FT0, FT1, &env->fp_status); RETURN(); } @@ -1331,25 +1199,24 @@ PPC_OP(fcmpo) /*** Floating-point move ***/ /* fabs */ -void do_fabs (void); PPC_OP(fabs) { - do_fabs(); + FT0 = float64_abs(FT0); RETURN(); } /* fnabs */ -void do_fnabs (void); PPC_OP(fnabs) { - do_fnabs(); + FT0 = float64_abs(FT0); + FT0 = float64_chs(FT0); RETURN(); } /* fneg */ PPC_OP(fneg) { - FT0 = -FT0; + FT0 = float64_chs(FT0); RETURN(); } @@ -1367,40 +1234,30 @@ PPC_OP(fneg) /* Special op to check and maybe clear reservation */ PPC_OP(check_reservation) { - do_check_reservation(); + if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003)) + env->reserve = -1; RETURN(); } /* Return from interrupt */ -PPC_OP(rfi) +void do_rfi (void); +void op_rfi (void) { - env->nip = env->spr[SPR_SRR0] & ~0x00000003; - T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL; - do_store_msr(env, T0); - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + do_rfi(); RETURN(); } /* Trap word */ -PPC_OP(tw) +void do_tw (uint32_t cmp, int flags); +void op_tw (void) { - if ((Ts0 < Ts1 && (PARAM(1) & 0x10)) || - (Ts0 > Ts1 && (PARAM(1) & 0x08)) || - (Ts0 == Ts1 && (PARAM(1) & 0x04)) || - (T0 < T1 && (PARAM(1) & 0x02)) || - (T0 > T1 && (PARAM(1) & 0x01))) - do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); + do_tw(T1, PARAM(1)); RETURN(); } -PPC_OP(twi) +void op_twi (void) { - if ((Ts0 < SPARAM(1) && (PARAM(2) & 0x10)) || - (Ts0 > SPARAM(1) && (PARAM(2) & 0x08)) || - (Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) || - (T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) || - (T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01))) - do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); + do_tw(PARAM(1), PARAM(2)); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index e57fbe461..06fa6d4fa 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -29,6 +29,14 @@ #include "op_helper_mem.h" #endif +//#define DEBUG_OP +//#define DEBUG_EXCEPTIONS +//#define FLUSH_ALL_TLBS + +#define Ts0 (long)((target_long)T0) +#define Ts1 (long)((target_long)T1) +#define Ts2 (long)((target_long)T2) + /*****************************************************************************/ /* Exceptions processing helpers */ void cpu_loop_exit(void) @@ -60,29 +68,260 @@ void do_raise_exception (uint32_t exception) } /*****************************************************************************/ -/* Helpers for "fat" micro operations */ +/* Fixed point operations helpers */ +void do_addo (void) +{ + T2 = T0; + T0 += T1; + if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } +} + +void do_addco (void) +{ + T2 = T0; + T0 += T1; + if (likely(T0 >= T2)) { + xer_ca = 0; + } else { + xer_ca = 1; + } + if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } +} + +void do_adde (void) +{ + T2 = T0; + T0 += T1 + xer_ca; + if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) { + xer_ca = 0; + } else { + xer_ca = 1; + } +} + +void do_addeo (void) +{ + T2 = T0; + T0 += T1 + xer_ca; + if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) { + xer_ca = 0; + } else { + xer_ca = 1; + } + if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } +} + +void do_addmeo (void) +{ + T1 = T0; + T0 += xer_ca + (-1); + if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } + if (likely(T1 != 0)) + xer_ca = 1; +} + +void do_addzeo (void) +{ + T1 = T0; + T0 += xer_ca; + if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } + if (likely(T0 >= T1)) { + xer_ca = 0; + } else { + xer_ca = 1; + } +} + +void do_divwo (void) +{ + if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) { + xer_ov = 0; + T0 = (Ts0 / Ts1); + } else { + xer_so = 1; + xer_ov = 1; + T0 = (-1) * ((uint32_t)T0 >> 31); + } +} + +void do_divwuo (void) +{ + if (likely((uint32_t)T1 != 0)) { + xer_ov = 0; + T0 = (uint32_t)T0 / (uint32_t)T1; + } else { + xer_so = 1; + xer_ov = 1; + T0 = 0; + } +} + +void do_mullwo (void) +{ + int64_t res = (int64_t)Ts0 * (int64_t)Ts1; + + if (likely((int32_t)res == res)) { + xer_ov = 0; + } else { + xer_ov = 1; + xer_so = 1; + } + T0 = (int32_t)res; +} + +void do_nego (void) +{ + if (likely(T0 != INT32_MIN)) { + xer_ov = 0; + T0 = -Ts0; + } else { + xer_ov = 1; + xer_so = 1; + } +} + +void do_subfo (void) +{ + T2 = T0; + T0 = T1 - T0; + if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } + RETURN(); +} + +void do_subfco (void) +{ + T2 = T0; + T0 = T1 - T0; + if (likely(T0 > T1)) { + xer_ca = 0; + } else { + xer_ca = 1; + } + if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } +} + +void do_subfe (void) +{ + T0 = T1 + ~T0 + xer_ca; + if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) { + xer_ca = 0; + } else { + xer_ca = 1; + } +} + +void do_subfeo (void) +{ + T2 = T0; + T0 = T1 + ~T0 + xer_ca; + if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } + if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) { + xer_ca = 0; + } else { + xer_ca = 1; + } +} + +void do_subfmeo (void) +{ + T1 = T0; + T0 = ~T0 + xer_ca - 1; + if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } + if (likely(T1 != -1)) + xer_ca = 1; +} + +void do_subfzeo (void) +{ + T1 = T0; + T0 = ~T0 + xer_ca; + if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) { + xer_ov = 0; + } else { + xer_ov = 1; + xer_so = 1; + } + if (likely(T0 >= ~T1)) { + xer_ca = 0; + } else { + xer_ca = 1; + } +} + /* shift right arithmetic helper */ void do_sraw (void) { int32_t ret; + if (likely(!(T1 & 0x20UL))) { + if (likely(T1 != 0)) { + ret = (int32_t)T0 >> (T1 & 0x1fUL); + if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) { xer_ca = 0; - if (T1 & 0x20) { - ret = (-1) * (T0 >> 31); - if (ret < 0 && (T0 & ~0x80000000) != 0) + } else { xer_ca = 1; -#if 1 // TRY - } else if (T1 == 0) { + } + } else { ret = T0; -#endif + xer_ca = 0; + } + } else { + ret = (-1) * ((uint32_t)T0 >> 31); + if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) { + xer_ca = 0; } else { - ret = (int32_t)T0 >> (T1 & 0x1f); - if (ret < 0 && ((int32_t)T0 & ((1 << T1) - 1)) != 0) xer_ca = 1; } + } T0 = ret; } +/*****************************************************************************/ /* Floating point operations helpers */ void do_fctiw (void) { @@ -116,29 +355,23 @@ void do_fctiwz (void) void do_fnmadd (void) { - FT0 = (FT0 * FT1) + FT2; - if (!isnan(FT0)) - FT0 = -FT0; + FT0 = float64_mul(FT0, FT1, &env->fp_status); + FT0 = float64_add(FT0, FT2, &env->fp_status); + if (likely(!isnan(FT0))) + FT0 = float64_chs(FT0); } void do_fnmsub (void) { - FT0 = (FT0 * FT1) - FT2; - if (!isnan(FT0)) - FT0 = -FT0; -} - -void do_fdiv (void) -{ - if (FT0 == -0.0 && FT1 == -0.0) - FT0 = 0.0 / 0.0; - else - FT0 /= FT1; + FT0 = float64_mul(FT0, FT1, &env->fp_status); + FT0 = float64_sub(FT0, FT2, &env->fp_status); + if (likely(!isnan(FT0))) + FT0 = float64_chs(FT0); } void do_fsqrt (void) { - FT0 = sqrt(FT0); + FT0 = float64_sqrt(FT0, &env->fp_status); } void do_fres (void) @@ -148,7 +381,7 @@ void do_fres (void) uint64_t i; } p; - if (isnormal(FT0)) { + if (likely(isnormal(FT0))) { FT0 = (float)(1.0 / FT0); } else { p.d = FT0; @@ -174,8 +407,9 @@ void do_frsqrte (void) uint64_t i; } p; - if (isnormal(FT0) && FT0 > 0.0) { - FT0 = (float)(1.0 / sqrt(FT0)); + if (likely(isnormal(FT0) && FT0 > 0.0)) { + FT0 = float64_sqrt(FT0, &env->fp_status); + FT0 = float32_div(1.0, FT0, &env->fp_status); } else { p.d = FT0; if (p.i == 0x8000000000000000ULL) { @@ -204,16 +438,18 @@ void do_fsel (void) void do_fcmpu (void) { - if (isnan(FT0) || isnan(FT1)) { - T0 = 0x01; + if (likely(!isnan(FT0) && !isnan(FT1))) { + if (float64_lt(FT0, FT1, &env->fp_status)) { + T0 = 0x08UL; + } else if (!float64_le(FT0, FT1, &env->fp_status)) { + T0 = 0x04UL; + } else { + T0 = 0x02UL; + } + } else { + T0 = 0x01UL; env->fpscr[4] |= 0x1; env->fpscr[6] |= 0x1; - } else if (FT0 < FT1) { - T0 = 0x08; - } else if (FT0 > FT1) { - T0 = 0x04; - } else { - T0 = 0x02; } env->fpscr[3] = T0; } @@ -221,8 +457,16 @@ void do_fcmpu (void) void do_fcmpo (void) { env->fpscr[4] &= ~0x1; - if (isnan(FT0) || isnan(FT1)) { - T0 = 0x01; + if (likely(!isnan(FT0) && !isnan(FT1))) { + if (float64_lt(FT0, FT1, &env->fp_status)) { + T0 = 0x08UL; + } else if (!float64_le(FT0, FT1, &env->fp_status)) { + T0 = 0x04UL; + } else { + T0 = 0x02UL; + } + } else { + T0 = 0x01UL; env->fpscr[4] |= 0x1; /* I don't know how to test "quiet" nan... */ if (0 /* || ! quiet_nan(...) */) { @@ -232,56 +476,51 @@ void do_fcmpo (void) } else { env->fpscr[4] |= 0x8; } - } else if (FT0 < FT1) { - T0 = 0x08; - } else if (FT0 > FT1) { - T0 = 0x04; - } else { - T0 = 0x02; } env->fpscr[3] = T0; } -void do_fabs (void) +void do_rfi (void) { - union { - double d; - uint64_t i; - } p; - - p.d = FT0; - p.i &= ~0x8000000000000000ULL; - FT0 = p.d; + env->nip = env->spr[SPR_SRR0] & ~0x00000003; + T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL; + do_store_msr(env, T0); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request |= CPU_INTERRUPT_EXITTB; } -void do_fnabs (void) +void do_tw (uint32_t cmp, int flags) { - union { - double d; - uint64_t i; - } p; - - p.d = FT0; - p.i |= 0x8000000000000000ULL; - FT0 = p.d; + if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) || + (Ts0 > (int32_t)cmp && (flags & 0x08)) || + (Ts0 == (int32_t)cmp && (flags & 0x04)) || + (T0 < cmp && (flags & 0x02)) || + (T0 > cmp && (flags & 0x01))))) + do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); } /* Instruction cache invalidation helper */ -#define ICACHE_LINE_SIZE 32 - -void do_check_reservation (void) -{ - if ((env->reserve & ~0x03) == T0) - env->reserve = -1; -} - void do_icbi (void) { - /* Invalidate one cache line */ + uint32_t tmp; + /* Invalidate one cache line : + * PowerPC specification says this is to be treated like a load + * (not a fetch) by the MMU. To be sure it will be so, + * do the load "by hand". + */ +#if defined(TARGET_PPC64) + if (!msr_sf) + T0 &= 0xFFFFFFFFULL; +#endif + tmp = ldl_kernel(T0); T0 &= ~(ICACHE_LINE_SIZE - 1); tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE); } +/*****************************************************************************/ +/* MMU related helpers */ /* TLB invalidation helpers */ void do_tlbia (void) { @@ -290,6 +529,62 @@ void do_tlbia (void) void do_tlbie (void) { +#if !defined(FLUSH_ALL_TLBS) tlb_flush_page(env, T0); +#else + do_tlbia(); +#endif +} + +/*****************************************************************************/ +/* Softmmu support */ +#if !defined (CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + target_phys_addr_t pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (!likely(ret == 0)) { + if (likely(retaddr)) { + /* now we have a real cpu fault */ + pc = (target_phys_addr_t)retaddr; + tb = tb_find_pc(pc); + if (likely(tb)) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc, NULL); +} + } + do_raise_exception_err(env->exception_index, env->error_code); + } + env = saved_env; } +#endif /* !CONFIG_USER_ONLY */ -- cgit v1.2.3 From e37e863f5e492cf60db21233f4008aafd6c5f610 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 4 Jul 2005 22:17:33 +0000 Subject: correct split between helper.c and op_helper.c - cosmetics git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1505 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 168 ------------------------------------------------ target-mips/exec.h | 12 ---- target-mips/helper.c | 58 +++-------------- target-mips/op_helper.c | 69 ++++++++++++++++---- target-mips/translate.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 233 insertions(+), 242 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 8f5150874..8ed09d584 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -240,174 +240,6 @@ enum { EXCP_FLUSH = 0x109, }; -/* MIPS opcodes */ -#define EXT_SPECIAL 0x100 -#define EXT_SPECIAL2 0x200 -#define EXT_REGIMM 0x300 -#define EXT_CP0 0x400 -#define EXT_CP1 0x500 -#define EXT_CP2 0x600 -#define EXT_CP3 0x700 - -enum { - /* indirect opcode tables */ - OPC_SPECIAL = 0x00, - OPC_BREGIMM = 0x01, - OPC_CP0 = 0x10, - OPC_CP1 = 0x11, - OPC_CP2 = 0x12, - OPC_CP3 = 0x13, - OPC_SPECIAL2 = 0x1C, - /* arithmetic with immediate */ - OPC_ADDI = 0x08, - OPC_ADDIU = 0x09, - OPC_SLTI = 0x0A, - OPC_SLTIU = 0x0B, - OPC_ANDI = 0x0C, - OPC_ORI = 0x0D, - OPC_XORI = 0x0E, - OPC_LUI = 0x0F, - /* Jump and branches */ - OPC_J = 0x02, - OPC_JAL = 0x03, - OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */ - OPC_BEQL = 0x14, - OPC_BNE = 0x05, - OPC_BNEL = 0x15, - OPC_BLEZ = 0x06, - OPC_BLEZL = 0x16, - OPC_BGTZ = 0x07, - OPC_BGTZL = 0x17, - OPC_JALX = 0x1D, /* MIPS 16 only */ - /* Load and stores */ - OPC_LB = 0x20, - OPC_LH = 0x21, - OPC_LWL = 0x22, - OPC_LW = 0x23, - OPC_LBU = 0x24, - OPC_LHU = 0x25, - OPC_LWR = 0x26, - OPC_SB = 0x28, - OPC_SH = 0x29, - OPC_SWL = 0x2A, - OPC_SW = 0x2B, - OPC_SWR = 0x2E, - OPC_LL = 0x30, - OPC_SC = 0x38, - /* Floating point load/store */ - OPC_LWC1 = 0x31, - OPC_LWC2 = 0x32, - OPC_LDC1 = 0x35, - OPC_LDC2 = 0x36, - OPC_SWC1 = 0x39, - OPC_SWC2 = 0x3A, - OPC_SDC1 = 0x3D, - OPC_SDC2 = 0x3E, - /* Cache and prefetch */ - OPC_CACHE = 0x2F, - OPC_PREF = 0x33, -}; - -/* MIPS special opcodes */ -enum { - /* Shifts */ - OPC_SLL = 0x00 | EXT_SPECIAL, - /* NOP is SLL r0, r0, 0 */ - /* SSNOP is SLL r0, r0, 1 */ - OPC_SRL = 0x02 | EXT_SPECIAL, - OPC_SRA = 0x03 | EXT_SPECIAL, - OPC_SLLV = 0x04 | EXT_SPECIAL, - OPC_SRLV = 0x06 | EXT_SPECIAL, - OPC_SRAV = 0x07 | EXT_SPECIAL, - /* Multiplication / division */ - OPC_MULT = 0x18 | EXT_SPECIAL, - OPC_MULTU = 0x19 | EXT_SPECIAL, - OPC_DIV = 0x1A | EXT_SPECIAL, - OPC_DIVU = 0x1B | EXT_SPECIAL, - /* 2 registers arithmetic / logic */ - OPC_ADD = 0x20 | EXT_SPECIAL, - OPC_ADDU = 0x21 | EXT_SPECIAL, - OPC_SUB = 0x22 | EXT_SPECIAL, - OPC_SUBU = 0x23 | EXT_SPECIAL, - OPC_AND = 0x24 | EXT_SPECIAL, - OPC_OR = 0x25 | EXT_SPECIAL, - OPC_XOR = 0x26 | EXT_SPECIAL, - OPC_NOR = 0x27 | EXT_SPECIAL, - OPC_SLT = 0x2A | EXT_SPECIAL, - OPC_SLTU = 0x2B | EXT_SPECIAL, - /* Jumps */ - OPC_JR = 0x08 | EXT_SPECIAL, - OPC_JALR = 0x09 | EXT_SPECIAL, - /* Traps */ - OPC_TGE = 0x30 | EXT_SPECIAL, - OPC_TGEU = 0x31 | EXT_SPECIAL, - OPC_TLT = 0x32 | EXT_SPECIAL, - OPC_TLTU = 0x33 | EXT_SPECIAL, - OPC_TEQ = 0x34 | EXT_SPECIAL, - OPC_TNE = 0x36 | EXT_SPECIAL, - /* HI / LO registers load & stores */ - OPC_MFHI = 0x10 | EXT_SPECIAL, - OPC_MTHI = 0x11 | EXT_SPECIAL, - OPC_MFLO = 0x12 | EXT_SPECIAL, - OPC_MTLO = 0x13 | EXT_SPECIAL, - /* Conditional moves */ - OPC_MOVZ = 0x0A | EXT_SPECIAL, - OPC_MOVN = 0x0B | EXT_SPECIAL, - - OPC_MOVCI = 0x01 | EXT_SPECIAL, - - /* Special */ - OPC_PMON = 0x05 | EXT_SPECIAL, - OPC_SYSCALL = 0x0C | EXT_SPECIAL, - OPC_BREAK = 0x0D | EXT_SPECIAL, - OPC_SYNC = 0x0F | EXT_SPECIAL, -}; - -enum { - /* Mutiply & xxx operations */ - OPC_MADD = 0x00 | EXT_SPECIAL2, - OPC_MADDU = 0x01 | EXT_SPECIAL2, - OPC_MUL = 0x02 | EXT_SPECIAL2, - OPC_MSUB = 0x04 | EXT_SPECIAL2, - OPC_MSUBU = 0x05 | EXT_SPECIAL2, - /* Misc */ - OPC_CLZ = 0x20 | EXT_SPECIAL2, - OPC_CLO = 0x21 | EXT_SPECIAL2, - /* Special */ - OPC_SDBBP = 0x3F | EXT_SPECIAL2, -}; - -/* Branch REGIMM */ -enum { - OPC_BLTZ = 0x00 | EXT_REGIMM, - OPC_BLTZL = 0x02 | EXT_REGIMM, - OPC_BGEZ = 0x01 | EXT_REGIMM, - OPC_BGEZL = 0x03 | EXT_REGIMM, - OPC_BLTZAL = 0x10 | EXT_REGIMM, - OPC_BLTZALL = 0x12 | EXT_REGIMM, - OPC_BGEZAL = 0x11 | EXT_REGIMM, - OPC_BGEZALL = 0x13 | EXT_REGIMM, - OPC_TGEI = 0x08 | EXT_REGIMM, - OPC_TGEIU = 0x09 | EXT_REGIMM, - OPC_TLTI = 0x0A | EXT_REGIMM, - OPC_TLTIU = 0x0B | EXT_REGIMM, - OPC_TEQI = 0x0C | EXT_REGIMM, - OPC_TNEI = 0x0E | EXT_REGIMM, -}; - -enum { - /* Coprocessor 0 (MMU) */ - OPC_MFC0 = 0x00 | EXT_CP0, - OPC_MTC0 = 0x04 | EXT_CP0, - OPC_TLBR = 0x01 | EXT_CP0, - OPC_TLBWI = 0x02 | EXT_CP0, - OPC_TLBWR = 0x06 | EXT_CP0, - OPC_TLBP = 0x08 | EXT_CP0, - OPC_ERET = 0x18 | EXT_CP0, - OPC_DERET = 0x1F | EXT_CP0, - OPC_WAIT = 0x20 | EXT_CP0, -}; - int cpu_mips_exec(CPUMIPSState *s); CPUMIPSState *cpu_mips_init(void); uint32_t cpu_mips_get_clock (void); diff --git a/target-mips/exec.h b/target-mips/exec.h index 258a96b84..d7f75efc5 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -19,27 +19,15 @@ typedef uint32_t host_uint_t; register host_uint_t T0 asm(AREG1); register host_uint_t T1 asm(AREG2); register host_uint_t T2 asm(AREG3); -register host_int_t Ts0 asm(AREG1); -register host_int_t Ts1 asm(AREG2); -register host_int_t Ts2 asm(AREG3); - -#define PARAM(n) ((uint32_t)PARAM##n) -#define SPARAM(n) ((int32_t)PARAM##n) #if defined (USE_HOST_FLOAT_REGS) register double FT0 asm(FREG0); register double FT1 asm(FREG1); register double FT2 asm(FREG2); -register float FTS0 asm(FREG0); -register float FTS1 asm(FREG1); -register float FTS2 asm(FREG2); #else #define FT0 (env->ft0.d) #define FT1 (env->ft1.d) #define FT2 (env->ft2.d) -#define FTS0 (env->ft0.f) -#define FTS1 (env->ft1.f) -#define FTS2 (env->ft2.f) #endif #if defined (DEBUG_OP) diff --git a/target-mips/helper.c b/target-mips/helper.c index 96e3100da..8d2617557 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -17,7 +17,16 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "exec.h" +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" /* MIPS32 4K MMU emulation */ #ifdef MIPS_USES_R4K_TLB @@ -142,57 +151,10 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return -1; return phys_addr; } -#endif - -#if !defined(CONFIG_USER_ONLY) - -#define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - -void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) -{ - TranslationBlock *tb; - CPUState *saved_env; - unsigned long pc; - int ret; - - /* XXX: hack to restore env in all cases, even if not called from - generated code */ - saved_env = env; - env = cpu_single_env; - ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1); - if (ret) { - if (retaddr) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - 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, NULL); - } - } - do_raise_exception_err(env->exception_index, env->error_code); - } - env = saved_env; -} void cpu_mips_init_mmu (CPUState *env) { } - #endif /* !defined(CONFIG_USER_ONLY) */ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 399200865..b8397be29 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -29,7 +29,6 @@ void cpu_loop_exit(void) longjmp(env->jmp_env, 1); } -__attribute__ (( regparm(2) )) void do_raise_exception_err (uint32_t exception, int error_code) { #if 1 @@ -42,7 +41,6 @@ void do_raise_exception_err (uint32_t exception, int error_code) cpu_loop_exit(); } -__attribute__ (( regparm(1) )) void do_raise_exception (uint32_t exception) { do_raise_exception_err(exception, 0); @@ -117,7 +115,6 @@ void do_msubu (void) #endif /* CP0 helpers */ -__attribute__ (( regparm(2) )) void do_mfc0 (int reg, int sel) { const unsigned char *rn; @@ -267,12 +264,10 @@ void do_mfc0 (int reg, int sel) return; } -__attribute__ (( regparm(2) )) void do_mtc0 (int reg, int sel) { const unsigned char *rn; uint32_t val, old, mask; - int i, raise; if (sel != 0 && reg != 16 && reg != 28) { val = -1; @@ -379,11 +374,14 @@ void do_mtc0 (int reg, int sel) old = env->CP0_Cause; env->CP0_Cause = val; #if 0 - /* Check if we ever asserted a software IRQ */ - for (i = 0; i < 2; i++) { - mask = 0x100 << i; - if ((val & mask) & !(old & mask)) - mips_set_irq(i); + { + int i; + /* Check if we ever asserted a software IRQ */ + for (i = 0; i < 2; i++) { + mask = 0x100 << i; + if ((val & mask) & !(old & mask)) + mips_set_irq(i); + } } #endif rn = "Cause"; @@ -486,7 +484,6 @@ void do_mtc0 (int reg, int sel) /* TLB management */ #if defined(MIPS_USES_R4K_TLB) -__attribute__ (( regparm(1) )) static void invalidate_tb (int idx) { tlb_t *tlb; @@ -505,7 +502,6 @@ static void invalidate_tb (int idx) } } -__attribute__ (( regparm(1) )) static void fill_tb (int idx) { tlb_t *tlb; @@ -584,7 +580,6 @@ void do_tlbr (void) } #endif -__attribute__ (( regparm(1) )) void op_dump_ldst (const unsigned char *func) { if (loglevel) @@ -608,7 +603,6 @@ void debug_eret (void) } } -__attribute__ (( regparm(1) )) void do_pmon (int function) { function /= 2; @@ -634,3 +628,50 @@ void do_pmon (int function) break; } } + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + unsigned long pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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, NULL); + } + } + do_raise_exception_err(env->exception_index, env->error_code); + } + env = saved_env; +} + +#endif diff --git a/target-mips/translate.c b/target-mips/translate.c index f5529c1b3..705577547 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -43,6 +43,174 @@ static uint32_t *gen_opparam_ptr; #include "gen-op.h" +/* MIPS opcodes */ +#define EXT_SPECIAL 0x100 +#define EXT_SPECIAL2 0x200 +#define EXT_REGIMM 0x300 +#define EXT_CP0 0x400 +#define EXT_CP1 0x500 +#define EXT_CP2 0x600 +#define EXT_CP3 0x700 + +enum { + /* indirect opcode tables */ + OPC_SPECIAL = 0x00, + OPC_BREGIMM = 0x01, + OPC_CP0 = 0x10, + OPC_CP1 = 0x11, + OPC_CP2 = 0x12, + OPC_CP3 = 0x13, + OPC_SPECIAL2 = 0x1C, + /* arithmetic with immediate */ + OPC_ADDI = 0x08, + OPC_ADDIU = 0x09, + OPC_SLTI = 0x0A, + OPC_SLTIU = 0x0B, + OPC_ANDI = 0x0C, + OPC_ORI = 0x0D, + OPC_XORI = 0x0E, + OPC_LUI = 0x0F, + /* Jump and branches */ + OPC_J = 0x02, + OPC_JAL = 0x03, + OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */ + OPC_BEQL = 0x14, + OPC_BNE = 0x05, + OPC_BNEL = 0x15, + OPC_BLEZ = 0x06, + OPC_BLEZL = 0x16, + OPC_BGTZ = 0x07, + OPC_BGTZL = 0x17, + OPC_JALX = 0x1D, /* MIPS 16 only */ + /* Load and stores */ + OPC_LB = 0x20, + OPC_LH = 0x21, + OPC_LWL = 0x22, + OPC_LW = 0x23, + OPC_LBU = 0x24, + OPC_LHU = 0x25, + OPC_LWR = 0x26, + OPC_SB = 0x28, + OPC_SH = 0x29, + OPC_SWL = 0x2A, + OPC_SW = 0x2B, + OPC_SWR = 0x2E, + OPC_LL = 0x30, + OPC_SC = 0x38, + /* Floating point load/store */ + OPC_LWC1 = 0x31, + OPC_LWC2 = 0x32, + OPC_LDC1 = 0x35, + OPC_LDC2 = 0x36, + OPC_SWC1 = 0x39, + OPC_SWC2 = 0x3A, + OPC_SDC1 = 0x3D, + OPC_SDC2 = 0x3E, + /* Cache and prefetch */ + OPC_CACHE = 0x2F, + OPC_PREF = 0x33, +}; + +/* MIPS special opcodes */ +enum { + /* Shifts */ + OPC_SLL = 0x00 | EXT_SPECIAL, + /* NOP is SLL r0, r0, 0 */ + /* SSNOP is SLL r0, r0, 1 */ + OPC_SRL = 0x02 | EXT_SPECIAL, + OPC_SRA = 0x03 | EXT_SPECIAL, + OPC_SLLV = 0x04 | EXT_SPECIAL, + OPC_SRLV = 0x06 | EXT_SPECIAL, + OPC_SRAV = 0x07 | EXT_SPECIAL, + /* Multiplication / division */ + OPC_MULT = 0x18 | EXT_SPECIAL, + OPC_MULTU = 0x19 | EXT_SPECIAL, + OPC_DIV = 0x1A | EXT_SPECIAL, + OPC_DIVU = 0x1B | EXT_SPECIAL, + /* 2 registers arithmetic / logic */ + OPC_ADD = 0x20 | EXT_SPECIAL, + OPC_ADDU = 0x21 | EXT_SPECIAL, + OPC_SUB = 0x22 | EXT_SPECIAL, + OPC_SUBU = 0x23 | EXT_SPECIAL, + OPC_AND = 0x24 | EXT_SPECIAL, + OPC_OR = 0x25 | EXT_SPECIAL, + OPC_XOR = 0x26 | EXT_SPECIAL, + OPC_NOR = 0x27 | EXT_SPECIAL, + OPC_SLT = 0x2A | EXT_SPECIAL, + OPC_SLTU = 0x2B | EXT_SPECIAL, + /* Jumps */ + OPC_JR = 0x08 | EXT_SPECIAL, + OPC_JALR = 0x09 | EXT_SPECIAL, + /* Traps */ + OPC_TGE = 0x30 | EXT_SPECIAL, + OPC_TGEU = 0x31 | EXT_SPECIAL, + OPC_TLT = 0x32 | EXT_SPECIAL, + OPC_TLTU = 0x33 | EXT_SPECIAL, + OPC_TEQ = 0x34 | EXT_SPECIAL, + OPC_TNE = 0x36 | EXT_SPECIAL, + /* HI / LO registers load & stores */ + OPC_MFHI = 0x10 | EXT_SPECIAL, + OPC_MTHI = 0x11 | EXT_SPECIAL, + OPC_MFLO = 0x12 | EXT_SPECIAL, + OPC_MTLO = 0x13 | EXT_SPECIAL, + /* Conditional moves */ + OPC_MOVZ = 0x0A | EXT_SPECIAL, + OPC_MOVN = 0x0B | EXT_SPECIAL, + + OPC_MOVCI = 0x01 | EXT_SPECIAL, + + /* Special */ + OPC_PMON = 0x05 | EXT_SPECIAL, + OPC_SYSCALL = 0x0C | EXT_SPECIAL, + OPC_BREAK = 0x0D | EXT_SPECIAL, + OPC_SYNC = 0x0F | EXT_SPECIAL, +}; + +enum { + /* Mutiply & xxx operations */ + OPC_MADD = 0x00 | EXT_SPECIAL2, + OPC_MADDU = 0x01 | EXT_SPECIAL2, + OPC_MUL = 0x02 | EXT_SPECIAL2, + OPC_MSUB = 0x04 | EXT_SPECIAL2, + OPC_MSUBU = 0x05 | EXT_SPECIAL2, + /* Misc */ + OPC_CLZ = 0x20 | EXT_SPECIAL2, + OPC_CLO = 0x21 | EXT_SPECIAL2, + /* Special */ + OPC_SDBBP = 0x3F | EXT_SPECIAL2, +}; + +/* Branch REGIMM */ +enum { + OPC_BLTZ = 0x00 | EXT_REGIMM, + OPC_BLTZL = 0x02 | EXT_REGIMM, + OPC_BGEZ = 0x01 | EXT_REGIMM, + OPC_BGEZL = 0x03 | EXT_REGIMM, + OPC_BLTZAL = 0x10 | EXT_REGIMM, + OPC_BLTZALL = 0x12 | EXT_REGIMM, + OPC_BGEZAL = 0x11 | EXT_REGIMM, + OPC_BGEZALL = 0x13 | EXT_REGIMM, + OPC_TGEI = 0x08 | EXT_REGIMM, + OPC_TGEIU = 0x09 | EXT_REGIMM, + OPC_TLTI = 0x0A | EXT_REGIMM, + OPC_TLTIU = 0x0B | EXT_REGIMM, + OPC_TEQI = 0x0C | EXT_REGIMM, + OPC_TNEI = 0x0E | EXT_REGIMM, +}; + +enum { + /* Coprocessor 0 (MMU) */ + OPC_MFC0 = 0x00 | EXT_CP0, + OPC_MTC0 = 0x04 | EXT_CP0, + OPC_TLBR = 0x01 | EXT_CP0, + OPC_TLBWI = 0x02 | EXT_CP0, + OPC_TLBWR = 0x06 | EXT_CP0, + OPC_TLBP = 0x08 | EXT_CP0, + OPC_ERET = 0x18 | EXT_CP0, + OPC_DERET = 0x1F | EXT_CP0, + OPC_WAIT = 0x20 | EXT_CP0, +}; + const unsigned char *regnames[] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", -- cgit v1.2.3 From ee5bbe38b1193bb2a8c2a450acb3d4679663fba1 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 4 Jul 2005 22:18:23 +0000 Subject: correct split between helper.c and op_helper.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1506 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 4 +- target-sparc/helper.c | 195 ++++------------------------------------------- target-sparc/op_helper.c | 188 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 201 insertions(+), 186 deletions(-) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index cbfcb14d2..c5b73fee8 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -72,8 +72,8 @@ void do_ldd_raw(target_ulong addr); void do_interrupt(int intno); void raise_exception(int tt); void memcpy32(target_ulong *dst, const target_ulong *src); -target_ulong mmu_probe(target_ulong address, int mmulev); -void dump_mmu(void); +target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev); +void dump_mmu(CPUState *env); void helper_debug(); void do_wrpsr(); void do_rdpsr(); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index a281e8d63..be3d6b985 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -17,7 +17,16 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "exec.h" +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" //#define DEBUG_PCALL //#define DEBUG_MMU @@ -52,55 +61,6 @@ int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, #else -#define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) -{ - TranslationBlock *tb; - int ret; - unsigned long pc; - CPUState *saved_env; - - /* XXX: hack to restore env in all cases, even if not called from - generated code */ - saved_env = env; - env = cpu_single_env; - - ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1); - if (ret) { - if (retaddr) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - 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, (void *)T2); - } - } - cpu_loop_exit(); - } - env = saved_env; -} - #ifndef TARGET_SPARC64 static const int access_table[8][8] = { { 0, 0, 0, 0, 2, 0, 3, 3 }, @@ -412,131 +372,8 @@ void memcpy32(target_ulong *dst, const target_ulong *src) dst[7] = src[7]; } -void set_cwp(int new_cwp) -{ - /* put the modified wrap registers at their proper location */ - if (env->cwp == (NWINDOWS - 1)) - memcpy32(env->regbase, env->regbase + NWINDOWS * 16); - env->cwp = new_cwp; - /* put the wrap registers at their temporary location */ - if (new_cwp == (NWINDOWS - 1)) - memcpy32(env->regbase + NWINDOWS * 16, env->regbase); - env->regwptr = env->regbase + (new_cwp * 16); - REGWPTR = env->regwptr; -} - -void cpu_set_cwp(CPUState *env1, int new_cwp) -{ - CPUState *saved_env; -#ifdef reg_REGWPTR - target_ulong *saved_regwptr; -#endif - - saved_env = env; -#ifdef reg_REGWPTR - saved_regwptr = REGWPTR; -#endif - env = env1; - set_cwp(new_cwp); - env = saved_env; -#ifdef reg_REGWPTR - REGWPTR = saved_regwptr; -#endif -} - -#ifdef TARGET_SPARC64 -void do_interrupt(int intno) -{ -#ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_INT) { - static int count; - fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", - count, intno, - env->pc, - env->npc, env->regwptr[6]); - cpu_dump_state(env, logfile, fprintf, 0); -#if 0 - { - int i; - uint8_t *ptr; - - fprintf(logfile, " code="); - ptr = (uint8_t *)env->pc; - for(i = 0; i < 16; i++) { - fprintf(logfile, " %02x", ldub(ptr + i)); - } - fprintf(logfile, "\n"); - } -#endif - count++; - } -#endif -#if !defined(CONFIG_USER_ONLY) - if (env->pstate & PS_IE) { - cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); - return; - } -#endif - env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | - ((env->pstate & 0xfff) << 8) | (env->cwp & 0xff); - env->tpc[env->tl] = env->pc; - env->tnpc[env->tl] = env->npc; - env->tt[env->tl] = intno; - env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4); - env->tl++; - env->pc = env->tbr; - env->npc = env->pc + 4; - env->exception_index = 0; -} -#else -void do_interrupt(int intno) -{ - int cwp; - -#ifdef DEBUG_PCALL - if (loglevel & CPU_LOG_INT) { - static int count; - fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", - count, intno, - env->pc, - env->npc, env->regwptr[6]); - cpu_dump_state(env, logfile, fprintf, 0); -#if 0 - { - int i; - uint8_t *ptr; - - fprintf(logfile, " code="); - ptr = (uint8_t *)env->pc; - for(i = 0; i < 16; i++) { - fprintf(logfile, " %02x", ldub(ptr + i)); - } - fprintf(logfile, "\n"); - } -#endif - count++; - } -#endif -#if !defined(CONFIG_USER_ONLY) - if (env->psret == 0) { - cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); - return; - } -#endif - env->psret = 0; - cwp = (env->cwp - 1) & (NWINDOWS - 1); - set_cwp(cwp); - env->regwptr[9] = env->pc; - env->regwptr[10] = env->npc; - env->psrps = env->psrs; - env->psrs = 1; - env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); - env->pc = env->tbr; - env->npc = env->pc + 4; - env->exception_index = 0; -} - -target_ulong mmu_probe(target_ulong address, int mmulev) +#if !defined(TARGET_SPARC64) +target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) { target_phys_addr_t pde_ptr; uint32_t pde; @@ -599,7 +436,7 @@ target_ulong mmu_probe(target_ulong address, int mmulev) } #ifdef DEBUG_MMU -void dump_mmu(void) +void dump_mmu(CPUState *env) { target_ulong va, va1, va2; unsigned int n, m, o; @@ -611,17 +448,17 @@ void dump_mmu(void) pde = ldl_phys(pde_ptr); printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { - pde_ptr = mmu_probe(va, 2); + pde_ptr = mmu_probe(env, va, 2); if (pde_ptr) { pa = cpu_get_phys_page_debug(env, va); printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr); for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { - pde_ptr = mmu_probe(va1, 1); + pde_ptr = mmu_probe(env, va1, 1); if (pde_ptr) { pa = cpu_get_phys_page_debug(env, va1); printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr); for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { - pde_ptr = mmu_probe(va2, 0); + pde_ptr = mmu_probe(env, va2, 0); if (pde_ptr) { pa = cpu_get_phys_page_debug(env, va2); printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr); diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index ac307a79b..15ce85337 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -234,7 +234,7 @@ void helper_ld_asi(int asi, int size, int sign) if (mmulev > 4) ret = 0; else { - ret = mmu_probe(T0, mmulev); + ret = mmu_probe(env, T0, mmulev); //bswap32s(&ret); } #ifdef DEBUG_MMU @@ -293,7 +293,7 @@ void helper_st_asi(int asi, int size, int sign) break; } #ifdef DEBUG_MMU - dump_mmu(); + dump_mmu(env); #endif return; } @@ -330,7 +330,7 @@ void helper_st_asi(int asi, int size, int sign) if (oldreg != env->mmuregs[reg]) { printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); } - dump_mmu(); + dump_mmu(env); #endif return; } @@ -508,7 +508,7 @@ void helper_st_asi(int asi, int size, int sign) if (oldreg != env->immuregs[reg]) { printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->immuregs[reg]); } - dump_mmu(); + dump_mmu(env); #endif return; } @@ -576,7 +576,7 @@ void helper_st_asi(int asi, int size, int sign) if (oldreg != env->dmmuregs[reg]) { printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->dmmuregs[reg]); } - dump_mmu(); + dump_mmu(env); #endif return; } @@ -705,3 +705,181 @@ void do_popc() T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL); } #endif + +void set_cwp(int new_cwp) +{ + /* put the modified wrap registers at their proper location */ + if (env->cwp == (NWINDOWS - 1)) + memcpy32(env->regbase, env->regbase + NWINDOWS * 16); + env->cwp = new_cwp; + /* put the wrap registers at their temporary location */ + if (new_cwp == (NWINDOWS - 1)) + memcpy32(env->regbase + NWINDOWS * 16, env->regbase); + env->regwptr = env->regbase + (new_cwp * 16); + REGWPTR = env->regwptr; +} + +void cpu_set_cwp(CPUState *env1, int new_cwp) +{ + CPUState *saved_env; +#ifdef reg_REGWPTR + target_ulong *saved_regwptr; +#endif + + saved_env = env; +#ifdef reg_REGWPTR + saved_regwptr = REGWPTR; +#endif + env = env1; + set_cwp(new_cwp); + env = saved_env; +#ifdef reg_REGWPTR + REGWPTR = saved_regwptr; +#endif +} + +#ifdef TARGET_SPARC64 +void do_interrupt(int intno) +{ +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_INT) { + static int count; + fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", + count, intno, + env->pc, + env->npc, env->regwptr[6]); + cpu_dump_state(env, logfile, fprintf, 0); +#if 0 + { + int i; + uint8_t *ptr; + + fprintf(logfile, " code="); + ptr = (uint8_t *)env->pc; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->pstate & PS_IE) { + cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); + return; + } +#endif + env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | + ((env->pstate & 0xfff) << 8) | (env->cwp & 0xff); + env->tpc[env->tl] = env->pc; + env->tnpc[env->tl] = env->npc; + env->tt[env->tl] = intno; + env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4); + env->tl++; + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = 0; +} +#else +void do_interrupt(int intno) +{ + int cwp; + +#ifdef DEBUG_PCALL + if (loglevel & CPU_LOG_INT) { + static int count; + fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", + count, intno, + env->pc, + env->npc, env->regwptr[6]); + cpu_dump_state(env, logfile, fprintf, 0); +#if 0 + { + int i; + uint8_t *ptr; + + fprintf(logfile, " code="); + ptr = (uint8_t *)env->pc; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } +#endif + count++; + } +#endif +#if !defined(CONFIG_USER_ONLY) + if (env->psret == 0) { + cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); + return; + } +#endif + env->psret = 0; + cwp = (env->cwp - 1) & (NWINDOWS - 1); + set_cwp(cwp); + env->regwptr[9] = env->pc; + env->regwptr[10] = env->npc; + env->psrps = env->psrs; + env->psrs = 1; + env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); + env->pc = env->tbr; + env->npc = env->pc + 4; + env->exception_index = 0; +} +#endif + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + int ret; + unsigned long pc; + CPUState *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + + ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + 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, (void *)T2); + } + } + cpu_loop_exit(); + } + env = saved_env; +} + +#endif -- cgit v1.2.3 From aefce9af41cc282adfdf4996902f10d8c31d3fe5 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Jul 2005 19:07:52 +0000 Subject: compilation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1507 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index d7f75efc5..77fce26d2 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -123,9 +123,7 @@ void do_maddu (void); void do_msub (void); void do_msubu (void); #endif -__attribute__ (( regparm(2) )) void do_mfc0(int reg, int sel); -__attribute__ (( regparm(2) )) void do_mtc0(int reg, int sel); void do_tlbwi (void); void do_tlbwr (void); @@ -145,7 +143,6 @@ void do_swl_kernel (void); void do_swr_user (void); void do_swr_kernel (void); #endif -__attribute__ (( regparm(1) )) void do_pmon (int function); int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, @@ -153,9 +150,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, void do_interrupt (CPUState *env); void cpu_loop_exit(void); -__attribute__ (( regparm(2) )) void do_raise_exception_err (uint32_t exception, int error_code); -__attribute__ (( regparm(1) )) void do_raise_exception (uint32_t exception); void cpu_dump_state(CPUState *env, FILE *f, -- cgit v1.2.3 From 61271e5c2d3eff4cc0c4845be291172c2015b6f1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Jul 2005 21:45:18 +0000 Subject: more precise cuda timers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1508 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cuda.c | 69 +++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/hw/cuda.c b/hw/cuda.c index 5ef2637e0..98a26377d 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -23,6 +23,8 @@ */ #include "vl.h" +/* XXX: implement all timer modes */ + //#define DEBUG_CUDA //#define DEBUG_CUDA_PACKET @@ -41,6 +43,7 @@ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ #define T1_INT 0x40 /* Timer 1 interrupt */ +#define T2_INT 0x20 /* Timer 2 interrupt */ /* Bits in ACR */ #define T1MODE 0xc0 /* Timer 1 mode */ @@ -91,7 +94,8 @@ #define RTC_OFFSET 2082844800 typedef struct CUDATimer { - unsigned int latch; + int index; + uint16_t latch; uint16_t counter_value; /* counter value at load time */ int64_t load_time; int64_t next_irq_time; @@ -154,10 +158,16 @@ static unsigned int get_counter(CUDATimer *s) d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); - if (d <= s->counter_value) { - counter = d; + if (s->index == 0) { + /* the timer goes down from latch to -1 (period of latch + 2) */ + if (d <= (s->counter_value + 1)) { + counter = (s->counter_value - d) & 0xffff; + } else { + counter = (d - (s->counter_value + 1)) % (s->latch + 2); + counter = (s->latch - counter) & 0xffff; + } } else { - counter = s->latch - 1 - ((d - s->counter_value) % s->latch); + counter = (s->counter_value - d) & 0xffff; } return counter; } @@ -175,17 +185,27 @@ static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) { - int64_t d, next_time, base; + int64_t d, next_time; + unsigned int counter; + /* current counter value */ d = muldiv64(current_time - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); - if (d < s->counter_value) { - next_time = s->counter_value + 1; - } else - { - base = ((d - s->counter_value + 1) / s->latch); - base = (base * s->latch) + s->counter_value; - next_time = base + s->latch; + /* the timer goes down from latch to -1 (period of latch + 2) */ + if (d <= (s->counter_value + 1)) { + counter = (s->counter_value - d) & 0xffff; + } else { + counter = (d - (s->counter_value + 1)) % (s->latch + 2); + counter = (s->latch - counter) & 0xffff; + } + + /* Note: we consider the irq is raised on 0 */ + if (counter == 0xffff) { + next_time = d + s->latch + 1; + } else if (counter == 0) { + next_time = d + s->latch + 2; + } else { + next_time = d + counter; } #if 0 #ifdef DEBUG_CUDA @@ -249,17 +269,18 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) break; case 5: val = get_counter(&s->timers[0]) >> 8; - s->ifr &= ~T1_INT; cuda_update_irq(s); break; case 6: val = s->timers[0].latch & 0xff; break; case 7: + /* XXX: check this */ val = (s->timers[0].latch >> 8) & 0xff; break; case 8: val = get_counter(&s->timers[1]) & 0xff; + s->ifr &= ~T2_INT; break; case 9: val = get_counter(&s->timers[1]) >> 8; @@ -317,12 +338,13 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) s->dira = val; break; case 4: - val = val | (get_counter(&s->timers[0]) & 0xff00); - set_counter(s, &s->timers[0], val); + s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; + cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); break; case 5: - val = (val << 8) | (get_counter(&s->timers[0]) & 0xff); - set_counter(s, &s->timers[0], val); + s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); + s->ifr &= ~T1_INT; + set_counter(s, &s->timers[0], s->timers[0].latch); break; case 6: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; @@ -330,15 +352,15 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 7: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); + s->ifr &= ~T1_INT; cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); break; case 8: - val = val | (get_counter(&s->timers[1]) & 0xff00); + s->timers[1].latch = val; set_counter(s, &s->timers[1], val); break; case 9: - val = (val << 8) | (get_counter(&s->timers[1]) & 0xff); - set_counter(s, &s->timers[1], val); + set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch); break; case 10: s->sr = val; @@ -620,10 +642,13 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq) s->irq_opaque = irq_opaque; s->irq = irq; + s->timers[0].index = 0; s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); - s->timers[0].latch = 0x10000; + s->timers[0].latch = 0xffff; set_counter(s, &s->timers[0], 0xffff); - s->timers[1].latch = 0x10000; + + s->timers[1].index = 1; + s->timers[1].latch = 0; // s->ier = T1_INT | SR_INT; s->ier = 0; set_counter(s, &s->timers[1], 0xffff); -- cgit v1.2.3 From a368741bf2508b7ca29d9ade73ec1b0f29ae2286 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Jul 2005 21:46:09 +0000 Subject: suppressed ppc ide hack - fixed read toc for Darwin/PPC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1509 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 31670a160..f5fd028b8 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1118,10 +1118,16 @@ static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf, *q++ = 0; /* min */ *q++ = 0; /* sec */ *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 0; - *q++ = 0; - *q++ = 0; + if (msf) { + *q++ = 0; + lba_to_msf(q, 0); + q += 3; + } else { + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + } len = q - buf; cpu_to_ube16(buf, len - 2); @@ -1488,11 +1494,6 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) unit = (val >> 4) & 1; s = ide_if + unit; ide_if->cur_drive = s; -#ifdef TARGET_PPC - /* XXX: currently a workaround for Darwin/PPC. Need to check - the IDE spec to see if it is correct */ - ide_set_signature(s); -#endif break; default: case 7: -- cgit v1.2.3 From 4e588a4d0e1683488282658c057d4b44976d77d8 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Jul 2005 21:46:29 +0000 Subject: negative decr fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1510 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 2146739a9..c460fec48 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -107,13 +107,16 @@ uint32_t cpu_ppc_load_decr (CPUState *env) { ppc_tb_t *tb_env = env->tb_env; uint32_t decr; + int64_t diff; - decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock), - tb_env->tb_freq, ticks_per_sec); + diff = tb_env->decr_next - qemu_get_clock(vm_clock); + if (diff >= 0) + decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec); + else + decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec); #if defined(DEBUG_TB) printf("%s: 0x%08x\n", __func__, decr); #endif - return decr; } -- cgit v1.2.3 From e5733356241f92e565f0aed731d265c8b1ae3956 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Jul 2005 21:47:27 +0000 Subject: heathrow nvram support - use different device ids for different macios git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1511 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 6 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index eb9482eae..a76fc47dc 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -31,7 +31,7 @@ #define INITRD_LOAD_ADDR 0x01800000 /* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA, - NVRAM (not implemented). */ + NVRAM */ static int dbdma_mem_index; static int cuda_mem_index; @@ -39,6 +39,7 @@ static int ide0_mem_index = -1; static int ide1_mem_index = -1; static int openpic_mem_index = -1; static int heathrow_pic_mem_index = -1; +static int macio_nvram_mem_index = -1; /* DBDMA: currently no op - should suffice right now */ @@ -83,6 +84,53 @@ static CPUReadMemoryFunc *dbdma_read[] = { &dbdma_readl, }; +/* macio style NVRAM device */ +typedef struct MacIONVRAMState { + uint8_t data[0x2000]; +} MacIONVRAMState; + +static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + MacIONVRAMState *s = opaque; + addr = (addr >> 4) & 0x1fff; + s->data[addr] = value; + // printf("macio_nvram_writeb %04x = %02x\n", addr, value); +} + +static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr) +{ + MacIONVRAMState *s = opaque; + uint32_t value; + + addr = (addr >> 4) & 0x1fff; + value = s->data[addr]; + // printf("macio_nvram_readb %04x = %02x\n", addr, value); + return value; +} + +static CPUWriteMemoryFunc *macio_nvram_write[] = { + &macio_nvram_writeb, + &macio_nvram_writeb, + &macio_nvram_writeb, +}; + +static CPUReadMemoryFunc *macio_nvram_read[] = { + &macio_nvram_readb, + &macio_nvram_readb, + &macio_nvram_readb, +}; + +static MacIONVRAMState *macio_nvram_init(void) +{ + MacIONVRAMState *s; + s = qemu_mallocz(sizeof(MacIONVRAMState)); + if (!s) + return NULL; + macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read, + macio_nvram_write, s); + return s; +} + static void macio_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { @@ -100,9 +148,11 @@ static void macio_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr + 0x40000, 0x40000, openpic_mem_index); } + if (macio_nvram_mem_index >= 0) + cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index); } -static void macio_init(PCIBus *bus) +static void macio_init(PCIBus *bus, int device_id) { PCIDevice *d; @@ -112,8 +162,8 @@ static void macio_init(PCIBus *bus) in PearPC */ d->config[0x00] = 0x6b; // vendor_id d->config[0x01] = 0x10; - d->config[0x02] = 0x22; - d->config[0x03] = 0x00; + d->config[0x02] = device_id; + d->config[0x03] = device_id >> 8; d->config[0x0a] = 0x00; // class_sub = pci2pci d->config[0x0b] = 0xff; // class_base = bridge @@ -219,6 +269,28 @@ static void pic_irq_request(void *opaque, int level) { } +static uint8_t nvram_chksum(const uint8_t *buf, int n) +{ + int sum, i; + sum = 0; + for(i = 0; i < n; i++) + sum += buf[i]; + return (sum & 0xff) + (sum >> 8); +} + +/* set a free Mac OS NVRAM partition */ +void pmac_format_nvram_partition(uint8_t *buf, int len) +{ + char partition_name[12] = "wwwwwwwwwwww"; + + buf[0] = 0x7f; /* free partition magic */ + buf[1] = 0; /* checksum */ + buf[2] = len >> 8; + buf[3] = len; + memcpy(buf + 4, partition_name, 12); + buf[1] = nvram_chksum(buf, 16); +} + /* PowerPC CHRP hardware initialisation */ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, @@ -369,7 +441,13 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - macio_init(pci_bus); + { + MacIONVRAMState *nvr; + nvr = macio_nvram_init(); + pmac_format_nvram_partition(nvr->data, 0x2000); + } + + macio_init(pci_bus, 0x0017); nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); @@ -416,7 +494,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - macio_init(pci_bus); + macio_init(pci_bus, 0x0022); nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); -- cgit v1.2.3 From 98352369101d2f3097e7f75d291b0a438c4dbbe4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 7 Jul 2005 22:38:00 +0000 Subject: specific mac-io PCI device_id for paddington/heathrow - fixed atapi requests - reset IDE drives in quiesce - added heathrow nvram OF description git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1512 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/ohw.diff | 330 ++++++++++++++++++++++++++++++++++++++-------------- pc-bios/ppc_rom.bin | Bin 524288 -> 524288 bytes 2 files changed, 244 insertions(+), 86 deletions(-) diff --git a/pc-bios/ohw.diff b/pc-bios/ohw.diff index 86fb1c2e1..4fb542274 100644 --- a/pc-bios/ohw.diff +++ b/pc-bios/ohw.diff @@ -1,6 +1,6 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bios.h OpenHackWare-release-0.4/src/bios.h --- OpenHackWare-release-0.4.org/src/bios.h 2005-04-06 23:20:22.000000000 +0200 -+++ OpenHackWare-release-0.4/src/bios.h 2005-07-03 16:17:41.000000000 +0200 ++++ OpenHackWare-release-0.4/src/bios.h 2005-07-07 01:10:20.000000000 +0200 @@ -64,6 +64,7 @@ ARCH_CHRP, ARCH_MAC99, @@ -9,7 +9,15 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- }; /* Hardware definition(s) */ -@@ -183,12 +184,12 @@ +@@ -174,6 +175,7 @@ + int bd_ioctl (bloc_device_t *bd, int func, void *args); + uint32_t bd_seclen (bloc_device_t *bd); + void bd_close (bloc_device_t *bd); ++void bd_reset_all(void); + uint32_t bd_seclen (bloc_device_t *bd); + uint32_t bd_maxbloc (bloc_device_t *bd); + void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum, +@@ -183,12 +185,12 @@ part_t *bd_probe (int boot_device); bloc_device_t *bd_get (int device); void bd_put (bloc_device_t *bd); @@ -24,7 +32,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1, void *OF_private); -@@ -399,17 +400,23 @@ +@@ -399,17 +401,23 @@ uint16_t min_grant, uint16_t max_latency); void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses); void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn, @@ -53,7 +61,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- const unsigned char *name, int devnum, diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bloc.c OpenHackWare-release-0.4/src/bloc.c --- OpenHackWare-release-0.4.org/src/bloc.c 2005-04-06 23:21:00.000000000 +0200 -+++ OpenHackWare-release-0.4/src/bloc.c 2005-07-03 16:17:41.000000000 +0200 ++++ OpenHackWare-release-0.4/src/bloc.c 2005-07-08 00:28:26.000000000 +0200 @@ -55,6 +55,7 @@ /* Partitions */ part_t *parts, *bparts; @@ -62,7 +70,33 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* Chain */ bloc_device_t *next; }; -@@ -223,10 +224,12 @@ +@@ -66,6 +67,7 @@ + + static int ide_initialize (bloc_device_t *bd, int device); + static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum); ++static int ide_reset (bloc_device_t *bd); + + static int mem_initialize (bloc_device_t *bd, int device); + static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum); +@@ -212,6 +214,17 @@ + { + } + ++void bd_reset_all(void) ++{ ++ bloc_device_t *bd; ++ for (bd = bd_list; bd != NULL; bd = bd->next) { ++ if (bd->init == &ide_initialize) { ++ /* reset IDE drive because Darwin wants all IDE devices to be reset */ ++ ide_reset(bd); ++ } ++ } ++} ++ + uint32_t bd_seclen (bloc_device_t *bd) + { + return bd->seclen; +@@ -223,10 +236,12 @@ } /* XXX: to be suppressed */ @@ -76,7 +110,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- } } -@@ -240,6 +243,13 @@ +@@ -240,6 +255,13 @@ return &bd->bparts; } @@ -90,7 +124,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- part_t *bd_probe (int boot_device) { char devices[] = { /*'a', 'b',*/ 'c', 'd', 'e', 'f', 'm', '\0', }; -@@ -272,9 +282,7 @@ +@@ -272,9 +294,7 @@ tmp = part_probe(bd, force_raw); if (boot_device == bd->device) { boot_part = tmp; @@ -101,7 +135,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- } } -@@ -717,34 +725,29 @@ +@@ -717,34 +737,29 @@ /* IDE PCI access for pc */ static uint8_t ide_pci_port_read (bloc_device_t *bd, int port) { @@ -143,7 +177,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- } static ide_ops_t ide_pci_pc_ops = { -@@ -761,7 +764,7 @@ +@@ -761,7 +776,7 @@ void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1, uint32_t io_base2, uint32_t io_base3, @@ -152,7 +186,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- { if (ide_pci_ops == NULL) { ide_pci_ops = malloc(sizeof(ide_ops_t)); -@@ -770,19 +773,19 @@ +@@ -770,19 +785,19 @@ memcpy(ide_pci_ops, &ide_pci_pc_ops, sizeof(ide_ops_t)); } if ((io_base0 != 0 || io_base1 != 0) && @@ -178,6 +212,78 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- #endif } } +@@ -935,6 +950,8 @@ + } + + static void atapi_pad_req (void *buffer, int len); ++static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer, ++ int maxlen); + static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum); + + static int ide_initialize (bloc_device_t *bd, int device) +@@ -1035,9 +1052,7 @@ + DPRINTF("INQUIRY\n"); + len = spc_inquiry_req(&atapi_buffer, 36); + atapi_pad_req(&atapi_buffer, len); +- ide_port_write(bd, 0x07, 0xA0); +- for (i = 0; i < 3; i++) +- ide_data_writel(bd, ldswap32(&atapi_buffer[i])); ++ atapi_make_req(bd, atapi_buffer, 36); + status = ide_port_read(bd, 0x07); + if (status != 0x48) { + ERROR("ATAPI INQUIRY : status %0x != 0x48\n", status); +@@ -1053,9 +1068,7 @@ + DPRINTF("READ_CAPACITY\n"); + len = mmc_read_capacity_req(&atapi_buffer); + atapi_pad_req(&atapi_buffer, len); +- ide_port_write(bd, 0x07, 0xA0); +- for (i = 0; i < 3; i++) +- ide_data_writel(bd, ldswap32(&atapi_buffer[i])); ++ atapi_make_req(bd, atapi_buffer, 8); + status = ide_port_read(bd, 0x07); + if (status != 0x48) { + ERROR("ATAPI READ_CAPACITY : status %0x != 0x48\n", status); +@@ -1105,6 +1118,22 @@ + memset(p + len, 0, 12 - len); + } + ++static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer, ++ int maxlen) ++{ ++ int i; ++ /* select drive */ ++ if (bd->drv == 0) ++ ide_port_write(bd, 0x06, 0x40); ++ else ++ ide_port_write(bd, 0x06, 0x50); ++ ide_port_write(bd, 0x04, maxlen & 0xff); ++ ide_port_write(bd, 0x05, (maxlen >> 8) & 0xff); ++ ide_port_write(bd, 0x07, 0xA0); ++ for (i = 0; i < 3; i++) ++ ide_data_writel(bd, ldswap32(&buffer[i])); ++} ++ + static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum) + { + uint32_t atapi_buffer[4]; +@@ -1112,16 +1141,9 @@ + uint32_t status, value; + int i, len; + +- /* select drive */ +- if (bd->drv == 0) +- ide_port_write(bd, 0x06, 0x40); +- else +- ide_port_write(bd, 0x06, 0x50); + len = mmc_read12_req(atapi_buffer, secnum, 1); + atapi_pad_req(&atapi_buffer, len); +- ide_port_write(bd, 0x07, 0xA0); +- for (i = 0; i < 3; i++) +- ide_data_writel(bd, ldswap32(&atapi_buffer[i])); ++ atapi_make_req(bd, atapi_buffer, bd->seclen); + status = ide_port_read(bd, 0x07); + if (status != 0x48) { + ERROR("ATAPI READ12 : status %0x != 0x48\n", status); diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/apple.c OpenHackWare-release-0.4/src/libpart/apple.c --- OpenHackWare-release-0.4.org/src/libpart/apple.c 2005-03-31 09:23:33.000000000 +0200 +++ OpenHackWare-release-0.4/src/libpart/apple.c 2005-07-03 16:17:41.000000000 +0200 @@ -527,7 +633,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- byte = NVRAM_get_byte(nvram, 0x34); diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/of.c OpenHackWare-release-0.4/src/of.c --- OpenHackWare-release-0.4.org/src/of.c 2005-04-06 23:17:26.000000000 +0200 -+++ OpenHackWare-release-0.4/src/of.c 2005-07-03 17:46:25.000000000 +0200 ++++ OpenHackWare-release-0.4/src/of.c 2005-07-07 23:30:08.000000000 +0200 @@ -489,7 +489,7 @@ ERROR("%s can't alloc new node '%s' name\n", __func__, name); return NULL; @@ -537,7 +643,41 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- if (new->prop_address == NULL) { free(new->prop_name->value); free(new->prop_name); -@@ -1421,15 +1421,12 @@ +@@ -1017,6 +1017,33 @@ + string, strlen(string) + 1); + } + ++/* convert '\1' char to '\0' */ ++static OF_prop_t *OF_prop_string_new1 (OF_env_t *env, OF_node_t *node, ++ const unsigned char *name, ++ const unsigned char *string) ++{ ++ int len, i; ++ OF_prop_t *ret; ++ unsigned char *str; ++ ++ if (strchr(string, '\1') == NULL) { ++ return OF_prop_string_new(env, node, name, string); ++ } else { ++ len = strlen(string) + 1; ++ str = malloc(len); ++ if (!str) ++ return NULL; ++ memcpy(str, string, len); ++ for(i = 0; i < len; i++) ++ if (str[i] == '\1') ++ str[i] = '\0'; ++ ret = OF_property_new(env, node, name, ++ str, len); ++ free(str); ++ return ret; ++ } ++} ++ + __attribute__ (( section (".OpenFirmware") )) + static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node, + const unsigned char *name, uint32_t value) +@@ -1421,15 +1448,12 @@ __attribute__ (( section (".OpenFirmware") )) int OF_init (void) { @@ -553,7 +693,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- #endif OF_env_t *OF_env; OF_node_t *als, *opt, *chs, *pks; -@@ -1455,15 +1452,21 @@ +@@ -1455,15 +1479,21 @@ return -1; } OF_prop_string_new(OF_env, OF_node_root, "device_type", "bootrom"); @@ -581,7 +721,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- #if 0 OF_prop_string_new(OF_env, OF_node_root, "copyright", copyright); #else -@@ -1561,14 +1564,15 @@ +@@ -1561,14 +1591,15 @@ range.size = 0x00800000; OF_property_new(OF_env, rom, "ranges", &range, sizeof(OF_range_t)); OF_prop_int_new(OF_env, rom, "#address-cells", 1); @@ -599,7 +739,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- OF_property_new(OF_env, brom, "reg", ®s, sizeof(OF_regprop_t)); OF_prop_string_new(OF_env, brom, "write-characteristic", "flash"); OF_prop_string_new(OF_env, brom, "BootROM-build-date", -@@ -1577,7 +1581,7 @@ +@@ -1577,7 +1608,7 @@ OF_prop_string_new(OF_env, brom, "copyright", copyright); OF_prop_string_new(OF_env, brom, "model", BIOS_str); OF_prop_int_new(OF_env, brom, "result", 0); @@ -608,7 +748,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- { /* Hack taken 'as-is' from PearPC */ unsigned char info[] = { -@@ -1596,7 +1600,9 @@ +@@ -1596,7 +1627,9 @@ OF_node_put(OF_env, brom); OF_node_put(OF_env, rom); } @@ -618,7 +758,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* "/nvram@fff04000" node */ { OF_regprop_t regs; -@@ -1617,6 +1623,7 @@ +@@ -1617,6 +1650,7 @@ OF_prop_int_new(OF_env, chs, "nvram", OF_pack_handle(OF_env, nvr)); OF_node_put(OF_env, nvr); } @@ -626,7 +766,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* "/pseudo-hid" : hid emulation as Apple does */ { OF_node_t *hid; -@@ -1663,7 +1670,27 @@ +@@ -1663,7 +1697,27 @@ } OF_node_put(OF_env, hid); } @@ -654,7 +794,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- #if 1 /* This is mandatory for claim to work * but I don't know where it should really be (in cpu ?) -@@ -1693,7 +1720,9 @@ +@@ -1693,7 +1747,9 @@ /* "/options/boot-args" node */ { @@ -665,7 +805,18 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* Ask MacOS X to print debug messages */ // OF_prop_string_new(OF_env, chs, "machargs", args); // OF_prop_string_new(OF_env, opt, "boot-command", args); -@@ -2021,9 +2050,9 @@ +@@ -2013,17 +2069,17 @@ + OF_prop_int_new(OF_env, node, "min-grant", min_grant); + OF_prop_int_new(OF_env, node, "max-latency", max_latency); + if (dev->type != NULL) +- OF_prop_string_new(OF_env, node, "device_type", dev->type); ++ OF_prop_string_new1(OF_env, node, "device_type", dev->type); + if (dev->compat != NULL) +- OF_prop_string_new(OF_env, node, "compatible", dev->compat); ++ OF_prop_string_new1(OF_env, node, "compatible", dev->compat); + if (dev->model != NULL) +- OF_prop_string_new(OF_env, node, "model", dev->model); ++ OF_prop_string_new1(OF_env, node, "model", dev->model); if (dev->acells != 0) OF_prop_int_new(OF_env, node, "#address-cells", dev->acells); if (dev->scells != 0) @@ -677,7 +828,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- dprintf("Done %p %p\n", parent, node); return node; -@@ -2040,8 +2069,9 @@ +@@ -2040,8 +2096,9 @@ OF_env_t *OF_env; pci_range_t ranges[3]; OF_regprop_t regs[1]; @@ -688,7 +839,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- OF_env = OF_env_main; dprintf("register PCI host '%s' '%s' '%s' '%s'\n", -@@ -2052,6 +2082,17 @@ +@@ -2052,6 +2109,17 @@ ERROR("Cannot create pci host\n"); return NULL; } @@ -706,7 +857,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- regs[0].address = cfg_base; regs[0].size = cfg_len; OF_property_new(OF_env, pci_host, "reg", regs, sizeof(OF_regprop_t)); -@@ -2136,6 +2177,11 @@ +@@ -2136,6 +2204,11 @@ return pci_dev; } @@ -718,7 +869,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses) { OF_env_t *OF_env; -@@ -2145,10 +2191,12 @@ +@@ -2145,10 +2218,12 @@ regs[0].address = first_bus; regs[0].size = nb_busses; OF_property_new(OF_env, dev, "bus-range", regs, sizeof(OF_regprop_t)); @@ -732,7 +883,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- { OF_env_t *OF_env; pci_reg_prop_t pregs[6], rregs[6]; -@@ -2156,6 +2204,7 @@ +@@ -2156,6 +2231,7 @@ int i, j, k; OF_env = OF_env_main; @@ -740,7 +891,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- if (regions[0] != 0x00000000) OF_prop_int_set(OF_env, dev, "address", regions[0] & ~0x0000000F); for (i = 0, j = 0, k = 0; i < 6; i++) { -@@ -2222,7 +2271,22 @@ +@@ -2222,7 +2298,22 @@ } else { OF_property_new(OF_env, dev, "assigned-addresses", NULL, 0); } @@ -764,7 +915,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- { OF_prop_t *prop_name = ((OF_node_t *)dev)->prop_name; -@@ -2390,6 +2454,54 @@ +@@ -2390,6 +2481,54 @@ return 0; } @@ -819,7 +970,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size, void *private_data) { -@@ -2398,6 +2510,8 @@ +@@ -2398,6 +2537,8 @@ pci_reg_prop_t pregs[2]; OF_node_t *mio, *chs, *als; uint16_t pic_phandle; @@ -828,7 +979,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- OF_DPRINTF("mac-io: %p\n", dev); OF_env = OF_env_main; -@@ -2416,10 +2530,14 @@ +@@ -2416,10 +2557,14 @@ mio = dev; mio->private_data = private_data; pregs[0].addr.hi = 0x00000000; @@ -844,28 +995,10 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- OF_property_new(OF_env, mio, "ranges", &pregs, sizeof(pci_reg_prop_t)); #if 0 -@@ -2431,8 +2549,49 @@ +@@ -2431,8 +2576,32 @@ OF_property_new(OF_env, mio, "assigned-addresses", &pregs, sizeof(pci_reg_prop_t)); #endif -- /* OpenPIC */ -+ -+ switch(arch) { -+ default: -+ case ARCH_MAC99: -+ OF_prop_int_new(OF_env, mio, "#interrupt-cells", 2); -+ OF_prop_string_new(OF_env, mio, "model", "AAPL,Keylargo"); -+ OF_prop_string_new(OF_env, mio, "compatible", "Keylargo"); -+ break; -+ case ARCH_HEATHROW: -+ OF_prop_int_new(OF_env, mio, "#interrupt-cells", 1); -+ OF_prop_string_new(OF_env, mio, "model", "AAPL,343S1211"); - { -+ const char str[] = "paddington\0heathrow"; -+ OF_property_new(OF_env, mio, "compatible", str, sizeof(str)); -+ } -+ break; -+ } + + if (arch == ARCH_HEATHROW) { + /* Heathrow PIC */ @@ -891,11 +1024,12 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- + OF_node_put(OF_env, mpic); + rec_len = 6; + } else { -+ /* OpenPIC */ + /* OpenPIC */ +- { OF_regprop_t regs[4]; OF_node_t *mpic; mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x40000); -@@ -2455,8 +2614,37 @@ +@@ -2455,8 +2624,37 @@ pic_phandle = OF_pack_handle(OF_env, mpic); OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle); OF_node_put(OF_env, mpic); @@ -934,7 +1068,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* escc is usefull to get MacOS X debug messages */ { OF_regprop_t regs[8]; -@@ -2645,85 +2833,12 @@ +@@ -2645,85 +2843,12 @@ OF_node_put(OF_env, scc); } #endif @@ -1025,7 +1159,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* Timer */ { OF_node_t *tmr; -@@ -2746,10 +2861,11 @@ +@@ -2746,10 +2871,11 @@ regs, sizeof(OF_regprop_t)); OF_node_put(OF_env, tmr); } @@ -1038,7 +1172,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- OF_regprop_t regs[1]; #if 0 // THIS IS A HACK AND IS COMPLETELY ABSURD ! // (but needed has Qemu doesn't emulate via-pmu). -@@ -2773,14 +2889,21 @@ +@@ -2773,14 +2899,21 @@ regs[0].size = 0x00002000; OF_property_new(OF_env, via, "reg", regs, sizeof(OF_regprop_t)); OF_prop_int_new(OF_env, via, "interrupt-parent", pic_phandle); @@ -1061,7 +1195,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* ADB pseudo-device */ adb = OF_node_new(OF_env, via, "adb", OF_ADDRESS_NONE); if (adb == NULL) { -@@ -2797,9 +2920,26 @@ +@@ -2797,9 +2930,26 @@ OF_prop_int_new(OF_env, adb, "#size-cells", 0); OF_pack_get_path(OF_env, tmp, 512, adb); OF_prop_string_new(OF_env, als, "adb", tmp); @@ -1091,7 +1225,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- rtc = OF_node_new(OF_env, via, "rtc", OF_ADDRESS_NONE); if (rtc == NULL) { -@@ -2813,14 +2953,55 @@ +@@ -2813,14 +2963,68 @@ OF_prop_string_new(OF_env, rtc, "compatible", "rtc"); #endif OF_node_put(OF_env, rtc); @@ -1107,6 +1241,19 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- + OF_prop_string_new(OF_env, pmgt, "mgt-kind", "min-consumption-pwm-led"); + OF_node_put(OF_env, pmgt); + } ++ ++ if (arch == ARCH_HEATHROW) { ++ /* NVRAM */ ++ OF_node_t *nvr; ++ OF_regprop_t regs; ++ nvr = OF_node_new(OF_env, mio, "nvram", 0x60000); ++ OF_prop_string_new(OF_env, nvr, "device_type", "nvram"); ++ regs.address = 0x60000; ++ regs.size = 0x00020000; ++ OF_property_new(OF_env, nvr, "reg", ®s, sizeof(regs)); ++ OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000); ++ OF_node_put(OF_env, nvr); ++ } + out: // OF_node_put(OF_env, mio); @@ -1148,7 +1295,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /*****************************************************************************/ /* Fake package */ static void OF_method_fake (OF_env_t *OF_env) -@@ -2862,11 +3043,11 @@ +@@ -2862,11 +3066,11 @@ /* As we get a 1:1 mapping, do nothing */ ihandle = popd(OF_env); args = (void *)popd(OF_env); @@ -1160,11 +1307,11 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- + size = popd(OF_env); + virt = popd(OF_env); + address = popd(OF_env); -+ dprintf("map %0x %0x %0x %0x\n", ihandle, address, ++ OF_DPRINTF("Map %0x %0x %0x %0x\n", ihandle, address, virt, size); pushd(OF_env, 0); } -@@ -3270,7 +3451,7 @@ +@@ -3270,7 +3474,7 @@ OF_prop_string_new(OF_env, dsk, "device_type", "block"); OF_prop_string_new(OF_env, dsk, "category", type); OF_prop_int_new(OF_env, dsk, "device_id", devnum); @@ -1173,7 +1320,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- OF_method_new(OF_env, dsk, "open", &OF_blockdev_open); OF_method_new(OF_env, dsk, "seek", &OF_blockdev_seek); OF_method_new(OF_env, dsk, "read", &OF_blockdev_read); -@@ -3432,7 +3613,8 @@ +@@ -3432,7 +3636,8 @@ } void OF_vga_register (const unsigned char *name, unused uint32_t address, @@ -1183,7 +1330,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- { OF_env_t *OF_env; unsigned char tmp[OF_NAMELEN_MAX]; -@@ -3504,6 +3686,18 @@ +@@ -3504,6 +3709,18 @@ OF_prop_string_new(OF_env, als, "display", tmp); OF_node_put(OF_env, als); /* XXX: may also need read-rectangle */ @@ -1202,7 +1349,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- out: OF_node_put(OF_env, disp); } -@@ -4451,7 +4645,10 @@ +@@ -4451,7 +4668,10 @@ break; case 0x233441d3: /* MacOS X 10.2 and OpenDarwin 1.41 */ /* Create "memory-map" pseudo device */ @@ -1214,7 +1361,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* Find "/packages" */ chs = OF_pack_find_by_name(OF_env, OF_node_root, "/chosen"); if (chs == NULL) { -@@ -4459,10 +4656,6 @@ +@@ -4459,10 +4679,6 @@ ERROR("Cannot get '/chosen'\n"); break; } @@ -1225,7 +1372,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- map = OF_node_new(OF_env, chs, "memory-map", OF_ADDRESS_NONE); if (map == NULL) { pushd(OF_env, -1); -@@ -4473,11 +4666,8 @@ +@@ -4473,11 +4689,8 @@ OF_node_put(OF_env, map); OF_node_put(OF_env, chs); pushd(OF_env, phandle); @@ -1238,7 +1385,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- break; case 0x32a2d18e: /* MacOS X 10.2 and OpenDarwin 6.02 */ /* Return screen ihandle */ -@@ -4540,9 +4730,10 @@ +@@ -4540,9 +4753,10 @@ case 0x4ad41f2d: /* Yaboot: wait 10 ms: sure ! */ break; @@ -1250,9 +1397,17 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- printf("Call %0x NOT IMPLEMENTED !\n", crc); bug(); break; +@@ -4581,6 +4795,7 @@ + { + OF_CHECK_NBARGS(OF_env, 0); + /* Should free all OF resources */ ++ bd_reset_all(); + #if defined (DEBUG_BIOS) + { + uint16_t loglevel = 0x02 | 0x10 | 0x80; diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/pci.c OpenHackWare-release-0.4/src/pci.c --- OpenHackWare-release-0.4.org/src/pci.c 2005-03-31 09:23:33.000000000 +0200 -+++ OpenHackWare-release-0.4/src/pci.c 2005-07-03 15:52:16.000000000 +0200 ++++ OpenHackWare-release-0.4/src/pci.c 2005-07-07 23:27:37.000000000 +0200 @@ -99,8 +99,8 @@ uint16_t min_grant; uint16_t max_latency; @@ -1490,20 +1645,23 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- }, { 0x1057, 0x4801, NULL, -@@ -1446,8 +1531,10 @@ - /* Apple Mac-io controller */ +@@ -1443,7 +1528,14 @@ + } + + static const pci_dev_t misc_pci[] = { +- /* Apple Mac-io controller */ ++ /* Paddington Mac I/O */ ++ { ++ 0x106B, 0x0017, ++ "mac-io", "mac-io", "AAPL,343S1211", "paddington\1heathrow", ++ 1, 1, 1, ++ &macio_config_cb, NULL, ++ }, ++ /* KeyLargo Mac I/O */ { 0x106B, 0x0022, -- "mac-io", "mac-io", "AAPL,Keylargo", "Keylargo", -- 1, 1, 2, -+ /* model, compatible and #interrupt-cells fields are filled in -+ of.c */ -+ "mac-io", "mac-io", NULL, NULL, -+ 1, 1, 0, - &macio_config_cb, NULL, - }, - { -@@ -1599,7 +1686,7 @@ + "mac-io", "mac-io", "AAPL,Keylargo", "Keylargo", +@@ -1599,7 +1691,7 @@ uint8_t min_grant, uint8_t max_latency, int irq_line) { @@ -1512,7 +1670,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- int i; device->min_grant = min_grant; -@@ -1611,22 +1698,28 @@ +@@ -1611,22 +1703,28 @@ printf("MAP PCI device %d:%d to IRQ %d\n", device->bus, device->devfn, irq_line); } @@ -1545,7 +1703,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- } } } -@@ -1900,7 +1993,7 @@ +@@ -1900,7 +1998,7 @@ goto out; } ret = (pci_u_t *)newd; @@ -1554,7 +1712,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* register PCI device in OF tree */ if (bridge->dev.common.type == PCI_FAKE_BRIDGE) { newd->common.OF_private = -@@ -1927,6 +2020,9 @@ +@@ -1927,6 +2025,9 @@ /* Handle 64 bits memory mapping */ continue; } @@ -1564,7 +1722,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- addr = 0x10 + (i * sizeof(uint32_t)); /* Get region size * Note: we assume it's always a power of 2 -@@ -1935,7 +2031,7 @@ +@@ -1935,7 +2036,7 @@ smask = pci_config_readl(bridge, bus, devfn, addr); if (smask == 0x00000000 || smask == 0xFFFFFFFF) continue; @@ -1573,7 +1731,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* I/O space */ base = io_base; /* Align to a minimum of 256 bytes (arbitrary) */ -@@ -1947,6 +2043,8 @@ +@@ -1947,6 +2048,8 @@ /* Align to a minimum of 64 kB (arbitrary) */ min_align = 1 << 16; amask = 0x0000000F; @@ -1582,7 +1740,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- } omask = smask & amask; smask &= ~amask; -@@ -1980,7 +2078,10 @@ +@@ -1980,7 +2083,10 @@ if (irq_pin > 0) { /* assign the IRQ */ irq_pin = ((devfn >> 3) + irq_pin - 1) & 3; @@ -1594,7 +1752,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- int elcr_port, val; irq_line = prep_pci_irqs[irq_pin]; /* set the IRQ to level-sensitive */ -@@ -1988,14 +2089,22 @@ +@@ -1988,14 +2094,22 @@ val = inb(elcr_port); val |= 1 << (irq_line & 7); outb(elcr_port, val); @@ -1619,7 +1777,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- /* Call special inits if needed */ if (dev->config_cb != NULL) (*dev->config_cb)(newd); -@@ -2049,6 +2158,32 @@ +@@ -2049,6 +2163,32 @@ case ARCH_CHRP: /* TODO */ break; @@ -1652,7 +1810,7 @@ diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' -- case ARCH_MAC99: dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp); if (dev == NULL) -@@ -2167,6 +2302,30 @@ +@@ -2167,6 +2307,30 @@ case ARCH_CHRP: /* TODO */ break; diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin index 8ba25bc37..f7cd8a82e 100644 Binary files a/pc-bios/ppc_rom.bin and b/pc-bios/ppc_rom.bin differ -- cgit v1.2.3 From b7c7b18129e137bd24240800d7fac02eee3b1edf Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 14:01:47 +0000 Subject: fixed VIA irq register access git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1513 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cuda.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/cuda.c b/hw/cuda.c index 98a26377d..dec5ffb31 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -298,9 +298,11 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) break; case 13: val = s->ifr; + if (s->ifr & s->ier) + val |= 0x80; break; case 14: - val = s->ier; + val = s->ier | 0x80; break; default: case 15: @@ -379,7 +381,6 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) cuda_update_irq(s); break; case 14: -#if 0 if (val & IER_SET) { /* set bits */ s->ier |= val & 0x7f; @@ -387,10 +388,6 @@ static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) /* reset bits */ s->ier &= ~val; } -#else - /* XXX: please explain me why the SPEC is not correct ! */ - s->ier = val; -#endif cuda_update_irq(s); break; default: -- cgit v1.2.3 From 8346901560d96edf94b803fd3f94db940ad370b3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 14:27:54 +0000 Subject: sparc64 fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1514 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 +- configure | 4 + hw/magic-load.c | 2 +- hw/pci.c | 247 +++++++++++++++++++++++++++++++++++++++ hw/sun4u.c | 293 +++++++++++++++++++++++++++++++++-------------- qemu-doc.texi | 13 +++ qemu-tech.texi | 1 - target-sparc/cpu.h | 21 +++- target-sparc/exec.h | 3 + target-sparc/helper.c | 226 +++++++++++++++++++++++++----------- target-sparc/op.c | 82 ++++++------- target-sparc/op_helper.c | 174 +++++++++++++++++++++++++--- target-sparc/op_mem.h | 16 +-- target-sparc/translate.c | 249 ++++++++++++++++++++++++++++++++-------- vl.h | 1 + 15 files changed, 1053 insertions(+), 284 deletions(-) diff --git a/Makefile.target b/Makefile.target index 74b5da830..c5a515272 100644 --- a/Makefile.target +++ b/Makefile.target @@ -297,7 +297,10 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8259.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -VL_OBJS+= sun4u.o m48t08.o magic-load.o slavio_serial.o +VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o +VL_OBJS+= cirrus_vga.o parallel.o +VL_OBJS+= magic-load.o else VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o endif diff --git a/configure b/configure index 76b4bfe38..c18a9d115 100755 --- a/configure +++ b/configure @@ -153,6 +153,8 @@ for opt do ;; --cc=*) cc=`echo $opt | cut -d '=' -f 2` ;; + --host-cc=*) host_cc=`echo $opt | cut -d '=' -f 2` + ;; --make=*) make=`echo $opt | cut -d '=' -f 2` ;; --extra-cflags=*) CFLAGS="${opt#--extra-cflags=}" @@ -339,6 +341,7 @@ echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]" echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" echo " --cc=CC use C compiler CC [$cc]" +echo " --host-cc=CC use C compiler CC [$cc] for dyngen etc." echo " --make=MAKE use specified make [$make]" echo " --static enable static build [$static]" echo " --enable-mingw32 enable Win32 cross compilation with mingw32" @@ -420,6 +423,7 @@ echo "ELF interp prefix $interp_prefix" fi echo "Source path $source_path" echo "C compiler $cc" +echo "Host C compiler $host_cc" echo "make $make" echo "host CPU $cpu" echo "host big endian $bigendian" diff --git a/hw/magic-load.c b/hw/magic-load.c index 63942c647..d5c098fb4 100644 --- a/hw/magic-load.c +++ b/hw/magic-load.c @@ -139,7 +139,7 @@ int load_elf(const char *filename, uint8_t *addr) if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD)) goto error; - retval = read_program64(fd, &phdr, addr, ehdr64.e_entry); + retval = read_program64(fd, &phdr, phys_ram_base + ehdr64.e_entry, ehdr64.e_entry); if (retval < 0) goto error; load_symbols64(&ehdr64, fd); diff --git a/hw/pci.c b/hw/pci.c index a5ecbf1be..efca2cd53 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1291,6 +1291,253 @@ PCIBus *pci_pmac_init(void) return s; } +/* Ultrasparc APB PCI host */ +static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBus *s = opaque; + int i; + + for (i = 11; i < 32; i++) { + if ((val & (1 << i)) != 0) + break; + } + s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); +} + +static uint32_t pci_apb_config_readl (void *opaque, + target_phys_addr_t addr) +{ + PCIBus *s = opaque; + uint32_t val; + int devfn; + + devfn = (s->config_reg >> 8) & 0xFF; + val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); + return val; +} + +static CPUWriteMemoryFunc *pci_apb_config_write[] = { + &pci_apb_config_writel, + &pci_apb_config_writel, + &pci_apb_config_writel, +}; + +static CPUReadMemoryFunc *pci_apb_config_read[] = { + &pci_apb_config_readl, + &pci_apb_config_readl, + &pci_apb_config_readl, +}; + +static void apb_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + //PCIBus *s = opaque; + + switch (addr & 0x3f) { + case 0x00: // Control/Status + case 0x10: // AFSR + case 0x18: // AFAR + case 0x20: // Diagnostic + case 0x28: // Target address space + // XXX + default: + break; + } +} + +static uint32_t apb_config_readl (void *opaque, + target_phys_addr_t addr) +{ + //PCIBus *s = opaque; + uint32_t val; + + switch (addr & 0x3f) { + case 0x00: // Control/Status + case 0x10: // AFSR + case 0x18: // AFAR + case 0x20: // Diagnostic + case 0x28: // Target address space + // XXX + default: + val = 0; + break; + } + return val; +} + +static CPUWriteMemoryFunc *apb_config_write[] = { + &apb_config_writel, + &apb_config_writel, + &apb_config_writel, +}; + +static CPUReadMemoryFunc *apb_config_read[] = { + &apb_config_readl, + &apb_config_readl, + &apb_config_readl, +}; + +static void pci_apb_writeb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBus *s = opaque; + + pci_data_write(s, addr & 7, val, 1); +} + +static void pci_apb_writew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBus *s = opaque; + + pci_data_write(s, addr & 7, val, 2); +} + +static void pci_apb_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + PCIBus *s = opaque; + + pci_data_write(s, addr & 7, val, 4); +} + +static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr) +{ + PCIBus *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr & 7, 1); + return val; +} + +static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr) +{ + PCIBus *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr & 7, 2); + return val; +} + +static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr) +{ + PCIBus *s = opaque; + uint32_t val; + + val = pci_data_read(s, addr, 4); + return val; +} + +static CPUWriteMemoryFunc *pci_apb_write[] = { + &pci_apb_writeb, + &pci_apb_writew, + &pci_apb_writel, +}; + +static CPUReadMemoryFunc *pci_apb_read[] = { + &pci_apb_readb, + &pci_apb_readw, + &pci_apb_readl, +}; + +static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outb(NULL, addr & 0xffff, val); +} + +static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outw(NULL, addr & 0xffff, val); +} + +static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outl(NULL, addr & 0xffff, val); +} + +static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inb(NULL, addr & 0xffff); + return val; +} + +static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inw(NULL, addr & 0xffff); + return val; +} + +static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inl(NULL, addr & 0xffff); + return val; +} + +static CPUWriteMemoryFunc *pci_apb_iowrite[] = { + &pci_apb_iowriteb, + &pci_apb_iowritew, + &pci_apb_iowritel, +}; + +static CPUReadMemoryFunc *pci_apb_ioread[] = { + &pci_apb_ioreadb, + &pci_apb_ioreadw, + &pci_apb_ioreadl, +}; + +PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base) +{ + PCIBus *s; + PCIDevice *d; + int pci_mem_config, pci_mem_data, apb_config, pci_ioport; + + /* Ultrasparc APB main bus */ + s = pci_register_bus(); + s->set_irq = pci_set_irq_simple; + + pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, + pci_apb_config_write, s); + apb_config = cpu_register_io_memory(0, apb_config_read, + apb_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_apb_read, + pci_apb_write, s); + pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, + pci_apb_iowrite, s); + + cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); + cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); + cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); + cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom + + d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice), + -1, NULL, NULL); + d->config[0x00] = 0x8e; // vendor_id : Sun + d->config[0x01] = 0x10; + d->config[0x02] = 0x00; // device_id + d->config[0x03] = 0xa0; + d->config[0x04] = 0x06; // command = bus master, pci mem + d->config[0x05] = 0x00; + d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error + d->config[0x07] = 0x03; // status = medium devsel + d->config[0x08] = 0x00; // revision + d->config[0x09] = 0x00; // programming i/f + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + return s; +} + /***********************************************************/ /* generic PCI irq support */ diff --git a/hw/sun4u.c b/hw/sun4u.c index af1546421..9c8945393 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -22,23 +22,18 @@ * THE SOFTWARE. */ #include "vl.h" -#include "m48t08.h" +#include "m48t59.h" -#define KERNEL_LOAD_ADDR 0x00004000 -#define CMDLINE_ADDR 0x007ff000 -#define INITRD_LOAD_ADDR 0x00800000 -#define PROM_ADDR 0xffd00000 +#define KERNEL_LOAD_ADDR 0x00404000 +#define CMDLINE_ADDR 0x003ff000 +#define INITRD_LOAD_ADDR 0x00300000 +#define PROM_ADDR 0x1fff0000000ULL +#define APB_SPECIAL_BASE 0x1fe00000000ULL +#define APB_MEM_BASE 0x1ff00000000ULL +#define VGA_BASE (APB_MEM_BASE + 0x400000ULL) #define PROM_FILENAMEB "proll-sparc64.bin" #define PROM_FILENAMEE "proll-sparc64.elf" -#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ -#define PHYS_JJ_IDPROM_OFF 0x1FD8 -#define PHYS_JJ_EEPROM_SIZE 0x2000 -// IRQs are not PIL ones, but master interrupt controller register -// bits -#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */ -#define PHYS_JJ_MS_KBD_IRQ 14 -#define PHYS_JJ_SER 0x71100000 /* Serial */ -#define PHYS_JJ_SER_IRQ 15 +#define NVRAM_SIZE 0x2000 /* TSC handling */ @@ -70,79 +65,170 @@ void DMA_register_channel (int nchan, { } -static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value) +/* NVRAM helpers */ +void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) { - m48t08_write(nvram, addr++, (value >> 8) & 0xff); - m48t08_write(nvram, addr++, value & 0xff); + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value); } -static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value) +uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) { - m48t08_write(nvram, addr++, value >> 24); - m48t08_write(nvram, addr++, (value >> 16) & 0xff); - m48t08_write(nvram, addr++, (value >> 8) & 0xff); - m48t08_write(nvram, addr++, value & 0xff); + m48t59_set_addr(nvram, addr); + return m48t59_read(nvram); } -static void nvram_set_string (m48t08_t *nvram, uint32_t addr, +void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) +{ + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value >> 8); + m48t59_set_addr(nvram, addr + 1); + m48t59_write(nvram, value & 0xFF); +} + +uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) +{ + uint16_t tmp; + + m48t59_set_addr(nvram, addr); + tmp = m48t59_read(nvram) << 8; + m48t59_set_addr(nvram, addr + 1); + tmp |= m48t59_read(nvram); + + return tmp; +} + +void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) +{ + m48t59_set_addr(nvram, addr); + m48t59_write(nvram, value >> 24); + m48t59_set_addr(nvram, addr + 1); + m48t59_write(nvram, (value >> 16) & 0xFF); + m48t59_set_addr(nvram, addr + 2); + m48t59_write(nvram, (value >> 8) & 0xFF); + m48t59_set_addr(nvram, addr + 3); + m48t59_write(nvram, value & 0xFF); +} + +uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) +{ + uint32_t tmp; + + m48t59_set_addr(nvram, addr); + tmp = m48t59_read(nvram) << 24; + m48t59_set_addr(nvram, addr + 1); + tmp |= m48t59_read(nvram) << 16; + m48t59_set_addr(nvram, addr + 2); + tmp |= m48t59_read(nvram) << 8; + m48t59_set_addr(nvram, addr + 3); + tmp |= m48t59_read(nvram); + + return tmp; +} + +void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, const unsigned char *str, uint32_t max) { - unsigned int i; + int i; for (i = 0; i < max && str[i] != '\0'; i++) { - m48t08_write(nvram, addr + i, str[i]); + m48t59_set_addr(nvram, addr + i); + m48t59_write(nvram, str[i]); } - m48t08_write(nvram, addr + max - 1, '\0'); + m48t59_set_addr(nvram, addr + max - 1); + m48t59_write(nvram, '\0'); } -static m48t08_t *nvram; +int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) +{ + int i; + + memset(dst, 0, max); + for (i = 0; i < max; i++) { + dst[i] = NVRAM_get_byte(nvram, addr + i); + if (dst[i] == '\0') + break; + } + + return i; +} + +static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) +{ + uint16_t tmp; + uint16_t pd, pd1, pd2; + + tmp = prev >> 8; + pd = prev ^ value; + pd1 = pd & 0x000F; + pd2 = ((pd >> 4) & 0x000F) ^ pd1; + tmp ^= (pd1 << 3) | (pd1 << 8); + tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); + + return tmp; +} + +uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) +{ + uint32_t i; + uint16_t crc = 0xFFFF; + int odd; + + odd = count & 1; + count &= ~1; + for (i = 0; i != count; i++) { + crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); + } + if (odd) { + crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); + } + + return crc; +} extern int nographic; -static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline, - int boot_device, uint32_t RAM_size, - uint32_t kernel_size, - int width, int height, int depth) -{ - unsigned char tmp = 0; - int i, j; - - // Try to match PPC NVRAM - nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); - nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */ - // NVRAM_size, arch not applicable - m48t08_write(nvram, 0x2F, nographic & 0xff); - nvram_set_lword(nvram, 0x30, RAM_size); - m48t08_write(nvram, 0x34, boot_device & 0xff); - nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR); - nvram_set_lword(nvram, 0x3C, kernel_size); +int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, + const unsigned char *arch, + uint32_t RAM_size, int boot_device, + uint32_t kernel_image, uint32_t kernel_size, + const char *cmdline, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image, + int width, int height, int depth) +{ + uint16_t crc; + + /* Set parameters for Open Hack'Ware BIOS */ + NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); + NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ + NVRAM_set_word(nvram, 0x14, NVRAM_size); + NVRAM_set_string(nvram, 0x20, arch, 16); + NVRAM_set_byte(nvram, 0x2f, nographic & 0xff); + NVRAM_set_lword(nvram, 0x30, RAM_size); + NVRAM_set_byte(nvram, 0x34, boot_device); + NVRAM_set_lword(nvram, 0x38, kernel_image); + NVRAM_set_lword(nvram, 0x3C, kernel_size); if (cmdline) { - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); - nvram_set_lword(nvram, 0x44, strlen(cmdline)); + /* XXX: put the cmdline in NVRAM too ? */ + strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); + NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR); + NVRAM_set_lword(nvram, 0x44, strlen(cmdline)); + } else { + NVRAM_set_lword(nvram, 0x40, 0); + NVRAM_set_lword(nvram, 0x44, 0); } - // initrd_image, initrd_size passed differently - nvram_set_word(nvram, 0x54, width); - nvram_set_word(nvram, 0x56, height); - nvram_set_word(nvram, 0x58, depth); - - // Sun4m specific use - i = 0x1fd8; - m48t08_write(nvram, i++, 0x01); - m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */ - j = 0; - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i, macaddr[j]); - - /* Calculate checksum */ - for (i = 0x1fd8; i < 0x1fe7; i++) { - tmp ^= m48t08_read(nvram, i); - } - m48t08_write(nvram, 0x1fe7, tmp); + NVRAM_set_lword(nvram, 0x48, initrd_image); + NVRAM_set_lword(nvram, 0x4C, initrd_size); + NVRAM_set_lword(nvram, 0x50, NVRAM_image); + + NVRAM_set_word(nvram, 0x54, width); + NVRAM_set_word(nvram, 0x56, height); + NVRAM_set_word(nvram, 0x58, depth); + crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); + NVRAM_set_word(nvram, 0xFC, crc); + + return 0; } void pic_info() @@ -157,21 +243,25 @@ void pic_set_irq(int irq, int level) { } -void vga_update_display() +void pic_set_irq_new(void *opaque, int irq, int level) { } -void vga_invalidate_display() +void qemu_system_powerdown(void) { } -void vga_screen_dump(const char *filename) -{ -} +static const int ide_iobase[2] = { 0x1f0, 0x170 }; +static const int ide_iobase2[2] = { 0x3f6, 0x376 }; +static const int ide_irq[2] = { 14, 15 }; -void qemu_system_powerdown(void) -{ -} +static const int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; +static const int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; + +static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; +static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; + +static fdctrl_t *floppy_controller; /* Sun4u hardware initialisation */ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, @@ -180,21 +270,18 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; + m48t59_t *nvram; int ret, linux_boot; unsigned int i; - long vram_size = 0x100000, prom_offset, initrd_size, kernel_size; + long prom_offset, initrd_size, kernel_size; + PCIBus *pci_bus; linux_boot = (kernel_filename != NULL); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); - nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); - // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device - // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device - slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); - - prom_offset = ram_size + vram_size; + prom_offset = ram_size + vga_ram_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); ret = load_elf(buf, phys_ram_base + prom_offset); @@ -211,6 +298,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, prom_offset | IO_MEM_ROM); kernel_size = 0; + initrd_size = 0; if (linux_boot) { kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) @@ -224,7 +312,6 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } /* load initrd */ - initrd_size = 0; if (initrd_filename) { initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); if (initrd_size < 0) { @@ -244,7 +331,41 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } } } - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth); + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE); + isa_mem_base = VGA_BASE; + vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size, 0, 0); + cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size); + //pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); + + for(i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + serial_init(serial_io[i], serial_irq[i], serial_hds[i]); + } + } + + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { + if (parallel_hds[i]) { + parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); + } + } + + for(i = 0; i < nb_nics; i++) { + pci_ne2000_init(pci_bus, &nd_table[i]); + } + + pci_cmd646_ide_init(pci_bus, bs_table, 1); + kbd_init(); + floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); + nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE); + sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device, + KERNEL_LOAD_ADDR, kernel_size, + kernel_cmdline, + INITRD_LOAD_ADDR, initrd_size, + /* XXX: need an option to load a NVRAM image */ + 0, + graphic_width, graphic_height, graphic_depth); + } QEMUMachine sun4u_machine = { diff --git a/qemu-doc.texi b/qemu-doc.texi index 439c0b057..17072a728 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1058,6 +1058,19 @@ Set the initial TCX graphic mode. The default is 1024x768. Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine. The emulator is not usable for anything yet. +QEMU emulates the following sun4u peripherals: + +@itemize @minus +@item +UltraSparc IIi APB PCI Bridge +@item +PCI VGA compatible card with VESA Bochs Extensions +@item +Non Volatile RAM M48T59 +@item +PC-compatible serial ports +@end itemize + @chapter MIPS System emulator invocation Use the executable @file{qemu-system-mips} to simulate a MIPS machine. diff --git a/qemu-tech.texi b/qemu-tech.texi index 379cbad55..95d1787e3 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -163,7 +163,6 @@ implemented. Floating point exception support is untested. @item Atomic instructions are not correctly implemented. @item Sparc64 emulators are not usable for anything yet. -Address space is limited to first 4 gigabytes. @end itemize diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 2eb900dfe..999d5d7e6 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -6,9 +6,11 @@ #if !defined(TARGET_SPARC64) #define TARGET_LONG_BITS 32 #define TARGET_FPREGS 32 +#define TARGET_PAGE_BITS 12 /* 4k */ #else #define TARGET_LONG_BITS 64 #define TARGET_FPREGS 64 +#define TARGET_PAGE_BITS 12 /* XXX */ #endif #define TARGET_FPREG_T float @@ -35,6 +37,7 @@ #define TT_TRAP 0x80 #else #define TT_TFAULT 0x08 +#define TT_TMISS 0x09 #define TT_ILL_INSN 0x10 #define TT_PRIV_INSN 0x11 #define TT_NFPU_INSN 0x20 @@ -42,6 +45,9 @@ #define TT_CLRWIN 0x24 #define TT_DIV_ZERO 0x28 #define TT_DFAULT 0x30 +#define TT_DMISS 0x31 +#define TT_DPROT 0x32 +#define TT_PRIV_ACT 0x37 #define TT_EXTINT 0x40 #define TT_SPILL 0x80 #define TT_FILL 0xc0 @@ -65,10 +71,14 @@ #define TBR_BASE_MASK 0xfffff000 #if defined(TARGET_SPARC64) +#define PS_IG (1<<11) +#define PS_MG (1<<10) +#define PS_RED (1<<5) #define PS_PEF (1<<4) #define PS_AM (1<<3) #define PS_PRIV (1<<2) #define PS_IE (1<<1) +#define PS_AG (1<<0) #endif /* Fcc */ @@ -166,7 +176,7 @@ typedef struct CPUSPARCState { context) */ unsigned long mem_write_pc; /* host pc at which the memory was written */ - unsigned long mem_write_vaddr; /* target virtual addr at which the + target_ulong mem_write_vaddr; /* target virtual addr at which the memory was written */ /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; @@ -201,11 +211,13 @@ typedef struct CPUSPARCState { uint32_t pstate; uint32_t tl; uint32_t cansave, canrestore, otherwin, wstate, cleanwin; - target_ulong agregs[8]; /* alternate general registers */ - target_ulong igregs[8]; /* interrupt general registers */ - target_ulong mgregs[8]; /* mmu general registers */ + uint64_t agregs[8]; /* alternate general registers */ + uint64_t bgregs[8]; /* backup for normal global registers */ + uint64_t igregs[8]; /* interrupt general registers */ + uint64_t mgregs[8]; /* mmu general registers */ uint64_t version; uint64_t fprs; + uint64_t tick_cmpr, stick_cmpr; #endif #if !defined(TARGET_SPARC64) && !defined(reg_T2) target_ulong t2; @@ -275,7 +287,6 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); struct siginfo; int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); -#define TARGET_PAGE_BITS 12 /* 4k */ #include "cpu-all.h" #endif diff --git a/target-sparc/exec.h b/target-sparc/exec.h index c5b73fee8..942b81189 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -65,6 +65,9 @@ void do_fcmpd_fcc2(void); void do_fcmps_fcc3(void); void do_fcmpd_fcc3(void); void do_popc(); +void do_wrpstate(); +void do_done(); +void do_retry(); #endif void do_ldd_kernel(target_ulong addr); void do_ldd_user(target_ulong addr); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index be3d6b985..78a033bc5 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -1,7 +1,7 @@ /* * sparc helpers * - * Copyright (c) 2003 Fabrice Bellard + * 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 @@ -28,7 +28,6 @@ #include "cpu.h" #include "exec-all.h" -//#define DEBUG_PCALL //#define DEBUG_MMU /* Sparc MMU emulation */ @@ -62,6 +61,9 @@ int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, #else #ifndef TARGET_SPARC64 +/* + * Sparc V8 Reference MMU (SRMMU) + */ static const int access_table[8][8] = { { 0, 0, 0, 0, 2, 0, 3, 3 }, { 0, 0, 0, 0, 2, 0, 0, 0 }, @@ -229,6 +231,9 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, } } #else +/* + * UltraSparc IIi I/DMMUs + */ static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot, int *access_index, target_ulong address, int rw, int is_user) @@ -237,46 +242,55 @@ static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical unsigned int i; if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ - *physical = address & 0xffffffff; + *physical = address; *prot = PAGE_READ | PAGE_WRITE; return 0; } for (i = 0; i < 64; i++) { - if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { - switch (env->dtlb_tte[i] >> 60) { - default: - case 0x4: // 8k - mask = 0xffffffffffffe000ULL; - break; - case 0x5: // 64k - mask = 0xffffffffffff0000ULL; - break; - case 0x6: // 512k - mask = 0xfffffffffff80000ULL; - break; - case 0x7: // 4M - mask = 0xffffffffffc00000ULL; - break; - } - // ctx match, vaddr match? - if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) && - (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) { - // access ok? - if (((env->dtlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) || - (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { - env->exception_index = TT_DFAULT; - return 1; - } - *physical = env->dtlb_tte[i] & 0xffffe000; - *prot = PAGE_READ; - if (env->dtlb_tte[i] & 0x2) - *prot |= PAGE_WRITE; - return 0; + switch ((env->dtlb_tte[i] >> 61) & 3) { + default: + case 0x0: // 8k + mask = 0xffffffffffffe000ULL; + break; + case 0x1: // 64k + mask = 0xffffffffffff0000ULL; + break; + case 0x2: // 512k + mask = 0xfffffffffff80000ULL; + break; + case 0x3: // 4M + mask = 0xffffffffffc00000ULL; + break; + } + // ctx match, vaddr match? + if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) && + (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) { + // valid, access ok? + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 || + ((env->dtlb_tte[i] & 0x4) && is_user) || + (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { + if (env->dmmuregs[3]) /* Fault status register */ + env->dmmuregs[3] = 2; /* overflow (not read before another fault) */ + env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1; + env->dmmuregs[4] = address; /* Fault address register */ + env->exception_index = TT_DFAULT; +#ifdef DEBUG_MMU + printf("DFAULT at 0x%llx\n", address); +#endif + return 1; } + *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); + *prot = PAGE_READ; + if (env->dtlb_tte[i] & 0x2) + *prot |= PAGE_WRITE; + return 0; } } - env->exception_index = TT_DFAULT; +#ifdef DEBUG_MMU + printf("DMISS at 0x%llx\n", address); +#endif + env->exception_index = TT_DMISS; return 1; } @@ -288,42 +302,51 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical unsigned int i; if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */ - *physical = address & 0xffffffff; + *physical = address; *prot = PAGE_READ; return 0; } + for (i = 0; i < 64; i++) { - if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { - switch (env->itlb_tte[i] >> 60) { - default: - case 0x4: // 8k - mask = 0xffffffffffffe000ULL; - break; - case 0x5: // 64k - mask = 0xffffffffffff0000ULL; - break; - case 0x6: // 512k - mask = 0xfffffffffff80000ULL; - break; - case 0x7: // 4M - mask = 0xffffffffffc00000ULL; + switch ((env->itlb_tte[i] >> 61) & 3) { + default: + case 0x0: // 8k + mask = 0xffffffffffffe000ULL; + break; + case 0x1: // 64k + mask = 0xffffffffffff0000ULL; + break; + case 0x2: // 512k + mask = 0xfffffffffff80000ULL; + break; + case 0x3: // 4M + mask = 0xffffffffffc00000ULL; break; + } + // ctx match, vaddr match? + if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) && + (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) { + // valid, access ok? + if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 || + ((env->itlb_tte[i] & 0x4) && is_user)) { + if (env->immuregs[3]) /* Fault status register */ + env->immuregs[3] = 2; /* overflow (not read before another fault) */ + env->immuregs[3] |= (is_user << 3) | 1; + env->exception_index = TT_TFAULT; +#ifdef DEBUG_MMU + printf("TFAULT at 0x%llx\n", address); +#endif + return 1; } - // ctx match, vaddr match? - if (env->immuregs[1] == (env->itlb_tag[i] & 0x1fff) && - (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) { - // access ok? - if ((env->itlb_tte[i] & 0x4) && !(env->pstate & PS_PRIV)) { - env->exception_index = TT_TFAULT; - return 1; - } - *physical = env->itlb_tte[i] & 0xffffe000; - *prot = PAGE_READ; - return 0; - } + *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); + *prot = PAGE_READ; + return 0; } } - env->exception_index = TT_TFAULT; +#ifdef DEBUG_MMU + printf("TMISS at 0x%llx\n", address); +#endif + env->exception_index = TT_TMISS; return 1; } @@ -341,15 +364,17 @@ int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot, int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { - target_ulong virt_addr; + target_ulong virt_addr, vaddr; target_phys_addr_t paddr; - unsigned long vaddr; int error_code = 0, prot, ret = 0, access_index; error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); if (error_code == 0) { virt_addr = address & TARGET_PAGE_MASK; vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); +#ifdef DEBUG_MMU + printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr); +#endif ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; } @@ -471,4 +496,77 @@ void dump_mmu(CPUState *env) printf("MMU dump ends\n"); } #endif +#else +#ifdef DEBUG_MMU +void dump_mmu(CPUState *env) +{ + unsigned int i; + const char *mask; + + printf("MMU contexts: Primary: %lld, Secondary: %lld\n", env->dmmuregs[1], env->dmmuregs[2]); + if ((env->lsu & DMMU_E) == 0) { + printf("DMMU disabled\n"); + } else { + printf("DMMU dump:\n"); + for (i = 0; i < 64; i++) { + switch ((env->dtlb_tte[i] >> 61) & 3) { + default: + case 0x0: + mask = " 8k"; + break; + case 0x1: + mask = " 64k"; + break; + case 0x2: + mask = "512k"; + break; + case 0x3: + mask = " 4M"; + break; + } + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %lld\n", + env->dtlb_tag[i] & ~0x1fffULL, + env->dtlb_tte[i] & 0x1ffffffe000ULL, + mask, + env->dtlb_tte[i] & 0x4? "priv": "user", + env->dtlb_tte[i] & 0x2? "RW": "RO", + env->dtlb_tte[i] & 0x40? "locked": "unlocked", + env->dtlb_tag[i] & 0x1fffULL); + } + } + } + if ((env->lsu & IMMU_E) == 0) { + printf("IMMU disabled\n"); + } else { + printf("IMMU dump:\n"); + for (i = 0; i < 64; i++) { + switch ((env->itlb_tte[i] >> 61) & 3) { + default: + case 0x0: + mask = " 8k"; + break; + case 0x1: + mask = " 64k"; + break; + case 0x2: + mask = "512k"; + break; + case 0x3: + mask = " 4M"; + break; + } + if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %lld\n", + env->itlb_tag[i] & ~0x1fffULL, + env->itlb_tte[i] & 0x1ffffffe000ULL, + mask, + env->itlb_tte[i] & 0x4? "priv": "user", + env->itlb_tte[i] & 0x40? "locked": "unlocked", + env->itlb_tag[i] & 0x1fffULL); + } + } + } +} +#endif #endif diff --git a/target-sparc/op.c b/target-sparc/op.c index 86c45c709..f8b491a7f 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -267,15 +267,6 @@ #endif #ifdef TARGET_SPARC64 -#undef JUMP_TB -#define JUMP_TB(opname, tbparam, n, eip) \ - do { \ - GOTO_TB(opname, tbparam, n); \ - T0 = (long)(tbparam) + (n); \ - env->pc = (eip) & 0xffffffff; \ - EXIT_TB(); \ - } while (0) - #ifdef WORDS_BIGENDIAN typedef union UREG64 { struct { uint16_t v3, v2, v1, v0; } w; @@ -388,7 +379,7 @@ void OPPROTO op_add_T1_T0_cc(void) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) @@ -433,7 +424,7 @@ void OPPROTO op_addx_T1_T0_cc(void) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) @@ -478,7 +469,7 @@ void OPPROTO op_sub_T1_T0_cc(void) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) @@ -523,7 +514,7 @@ void OPPROTO op_subx_T1_T0_cc(void) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) @@ -585,7 +576,11 @@ void OPPROTO op_umul_T1_T0(void) { uint64_t res; res = (uint64_t) T0 * (uint64_t) T1; +#ifdef TARGET_SPARC64 + T0 = res; +#else T0 = res & 0xffffffff; +#endif env->y = res >> 32; } @@ -593,7 +588,11 @@ void OPPROTO op_smul_T1_T0(void) { uint64_t res; res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1); +#ifdef TARGET_SPARC64 + T0 = res; +#else T0 = res & 0xffffffff; +#endif env->y = res >> 32; } @@ -902,7 +901,7 @@ void OPPROTO op_rdpstate(void) void OPPROTO op_wrpstate(void) { - env->pstate = T0 & 0x1f; + do_wrpstate(); } // CWP handling is reversed in V9, but we still use the V8 register @@ -1201,12 +1200,12 @@ void OPPROTO op_eval_xbvc(void) #ifdef TARGET_SPARC64 void OPPROTO op_eval_brz(void) { - T2 = T0; + T2 = (T0 == 0); } void OPPROTO op_eval_brnz(void) { - T2 = !T0; + T2 = (T0 != 0); } void OPPROTO op_eval_brlz(void) @@ -1266,43 +1265,32 @@ void OPPROTO op_next_insn(void) env->npc = env->npc + 4; } -void OPPROTO op_branch(void) +void OPPROTO op_goto_tb0(void) { - env->npc = (uint32_t)PARAM3; /* XXX: optimize */ - JUMP_TB(op_branch, PARAM1, 0, PARAM2); + GOTO_TB(op_goto_tb0, PARAM1, 0); } -void OPPROTO op_branch2(void) +void OPPROTO op_goto_tb1(void) { - if (T2) { - env->npc = (uint32_t)PARAM2 + 4; - JUMP_TB(op_branch2, PARAM1, 0, PARAM2); - } else { - env->npc = (uint32_t)PARAM3 + 4; - JUMP_TB(op_branch2, PARAM1, 1, PARAM3); - } - FORCE_RET(); + GOTO_TB(op_goto_tb1, PARAM1, 1); } -void OPPROTO op_branch_a(void) +void OPPROTO op_jmp_label(void) { - if (T2) { - env->npc = (uint32_t)PARAM2; /* XXX: optimize */ - JUMP_TB(op_branch_a, PARAM1, 0, PARAM3); - } else { - env->npc = (uint32_t)PARAM3 + 8; /* XXX: optimize */ - JUMP_TB(op_branch_a, PARAM1, 1, PARAM3 + 4); - } + GOTO_LABEL_PARAM(1); +} + +void OPPROTO op_jnz_T2_label(void) +{ + if (T2) + GOTO_LABEL_PARAM(1); FORCE_RET(); } -void OPPROTO op_generic_branch(void) +void OPPROTO op_jz_T2_label(void) { - if (T2) { - env->npc = (uint32_t)PARAM1; - } else { - env->npc = (uint32_t)PARAM2; - } + if (!T2) + GOTO_LABEL_PARAM(1); FORCE_RET(); } @@ -1547,18 +1535,12 @@ void OPPROTO op_popc(void) void OPPROTO op_done(void) { - env->pc = env->tnpc[env->tl]; - env->npc = env->tnpc[env->tl] + 4; - env->pstate = env->tstate[env->tl]; - env->tl--; + do_done(); } void OPPROTO op_retry(void) { - env->pc = env->tpc[env->tl]; - env->npc = env->tnpc[env->tl]; - env->pstate = env->tstate[env->tl]; - env->tl--; + do_retry(); } void OPPROTO op_sir(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 15ce85337..468bbb6b4 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1,5 +1,6 @@ #include "exec.h" +//#define DEBUG_PCALL //#define DEBUG_MMU void raise_exception(int tt) @@ -223,7 +224,7 @@ void do_fcmpd_fcc3 (void) #ifndef TARGET_SPARC64 void helper_ld_asi(int asi, int size, int sign) { - uint32_t ret; + uint32_t ret = 0; switch (asi) { case 3: /* MMU probe */ @@ -299,7 +300,8 @@ void helper_st_asi(int asi, int size, int sign) } case 4: /* write MMU regs */ { - int reg = (T0 >> 8) & 0xf, oldreg; + int reg = (T0 >> 8) & 0xf; + uint32_t oldreg; oldreg = env->mmuregs[reg]; switch(reg) { @@ -339,7 +341,7 @@ void helper_st_asi(int asi, int size, int sign) // value (T1) = src // address (T0) = dst // copy 32 bytes - int src = T1, dst = T0; + uint32_t src = T1, dst = T0; uint8_t temp[32]; tswap32s(&src); @@ -353,7 +355,8 @@ void helper_st_asi(int asi, int size, int sign) // value (T1, T2) // address (T0) = dst // fill 32 bytes - int i, dst = T0; + int i; + uint32_t dst = T0; uint64_t val; val = (((uint64_t)T1) << 32) | T2; @@ -366,7 +369,7 @@ void helper_st_asi(int asi, int size, int sign) return; case 0x20 ... 0x2f: /* MMU passthrough */ { - int temp = T1; + uint32_t temp = T1; if (size == 4) tswap32s(&temp); else if (size == 2) @@ -383,10 +386,10 @@ void helper_st_asi(int asi, int size, int sign) void helper_ld_asi(int asi, int size, int sign) { - uint64_t ret; + uint64_t ret = 0; if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) - raise_exception(TT_PRIV_INSN); + raise_exception(TT_PRIV_ACT); switch (asi) { case 0x14: // Bypass @@ -401,8 +404,23 @@ void helper_ld_asi(int asi, int size, int sign) tswap16s((uint16_t *)&ret); break; } + case 0x04: // Nucleus + case 0x0c: // Nucleus Little Endian (LE) + case 0x10: // As if user primary + case 0x11: // As if user secondary + case 0x18: // As if user primary LE + case 0x19: // As if user secondary LE case 0x1c: // Bypass LE case 0x1d: // Bypass, non-cacheable LE + case 0x24: // Nucleus quad LDD 128 bit atomic + case 0x2c: // Nucleus quad LDD 128 bit atomic + case 0x4a: // UPA config + case 0x82: // Primary no-fault + case 0x83: // Secondary no-fault + case 0x88: // Primary LE + case 0x89: // Secondary LE + case 0x8a: // Primary no-fault LE + case 0x8b: // Secondary no-fault LE // XXX break; case 0x45: // LSU @@ -418,8 +436,22 @@ void helper_ld_asi(int asi, int size, int sign) case 0x51: // I-MMU 8k TSB pointer case 0x52: // I-MMU 64k TSB pointer case 0x55: // I-MMU data access - case 0x56: // I-MMU tag read + // XXX break; + case 0x56: // I-MMU tag read + { + unsigned int i; + + for (i = 0; i < 64; i++) { + // Valid, ctx match, vaddr match + if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && + env->itlb_tag[i] == T0) { + ret = env->itlb_tag[i]; + break; + } + } + break; + } case 0x58: // D-MMU regs { int reg = (T0 >> 3) & 0xf; @@ -427,16 +459,34 @@ void helper_ld_asi(int asi, int size, int sign) ret = env->dmmuregs[reg]; break; } + case 0x5e: // D-MMU tag read + { + unsigned int i; + + for (i = 0; i < 64; i++) { + // Valid, ctx match, vaddr match + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && + env->dtlb_tag[i] == T0) { + ret = env->dtlb_tag[i]; + break; + } + } + break; + } case 0x59: // D-MMU 8k TSB pointer case 0x5a: // D-MMU 64k TSB pointer case 0x5b: // D-MMU data pointer case 0x5d: // D-MMU data access - case 0x5e: // D-MMU tag read + case 0x48: // Interrupt dispatch, RO + case 0x49: // Interrupt data receive + case 0x7f: // Incoming interrupt vector, RO + // XXX break; case 0x54: // I-MMU data in, WO case 0x57: // I-MMU demap, WO case 0x5c: // D-MMU data in, WO case 0x5f: // D-MMU demap, WO + case 0x77: // Interrupt vector, WO default: ret = 0; break; @@ -447,7 +497,7 @@ void helper_ld_asi(int asi, int size, int sign) void helper_st_asi(int asi, int size, int sign) { if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) - raise_exception(TT_PRIV_INSN); + raise_exception(TT_PRIV_ACT); switch(asi) { case 0x14: // Bypass @@ -463,8 +513,19 @@ void helper_st_asi(int asi, int size, int sign) cpu_physical_memory_write(T0, (void *) &temp, size); } return; + case 0x04: // Nucleus + case 0x0c: // Nucleus Little Endian (LE) + case 0x10: // As if user primary + case 0x11: // As if user secondary + case 0x18: // As if user primary LE + case 0x19: // As if user secondary LE case 0x1c: // Bypass LE case 0x1d: // Bypass, non-cacheable LE + case 0x24: // Nucleus quad LDD 128 bit atomic + case 0x2c: // Nucleus quad LDD 128 bit atomic + case 0x4a: // UPA config + case 0x88: // Primary LE + case 0x89: // Secondary LE // XXX return; case 0x45: // LSU @@ -475,8 +536,13 @@ void helper_st_asi(int asi, int size, int sign) env->lsu = T1 & (DMMU_E | IMMU_E); // Mappings generated during D/I MMU disabled mode are // invalid in normal mode - if (oldreg != env->lsu) + if (oldreg != env->lsu) { +#ifdef DEBUG_MMU + printf("LSU change: 0x%llx -> 0x%llx\n", oldreg, env->lsu); + dump_mmu(env); +#endif tlb_flush(env, 1); + } return; } case 0x50: // I-MMU regs @@ -506,7 +572,7 @@ void helper_st_asi(int asi, int size, int sign) env->immuregs[reg] = T1; #ifdef DEBUG_MMU if (oldreg != env->immuregs[reg]) { - printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->immuregs[reg]); + printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->immuregs[reg]); } dump_mmu(env); #endif @@ -544,6 +610,7 @@ void helper_st_asi(int asi, int size, int sign) return; } case 0x57: // I-MMU demap + // XXX return; case 0x58: // D-MMU regs { @@ -574,7 +641,7 @@ void helper_st_asi(int asi, int size, int sign) env->dmmuregs[reg] = T1; #ifdef DEBUG_MMU if (oldreg != env->dmmuregs[reg]) { - printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->dmmuregs[reg]); + printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->dmmuregs[reg]); } dump_mmu(env); #endif @@ -612,6 +679,8 @@ void helper_st_asi(int asi, int size, int sign) return; } case 0x5f: // D-MMU demap + case 0x49: // Interrupt data receive + // XXX return; case 0x51: // I-MMU 8k TSB pointer, RO case 0x52: // I-MMU 64k TSB pointer, RO @@ -620,6 +689,12 @@ void helper_st_asi(int asi, int size, int sign) case 0x5a: // D-MMU 64k TSB pointer, RO case 0x5b: // D-MMU data pointer, RO case 0x5e: // D-MMU tag read, RO + case 0x48: // Interrupt dispatch, RO + case 0x7f: // Incoming interrupt vector, RO + case 0x82: // Primary no-fault, RO + case 0x83: // Secondary no-fault, RO + case 0x8a: // Primary no-fault LE, RO + case 0x8b: // Secondary no-fault LE, RO default: return; } @@ -704,6 +779,61 @@ void do_popc() T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL); T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL); } + +static inline uint64_t *get_gregset(uint64_t pstate) +{ + switch (pstate) { + default: + case 0: + return env->bgregs; + case PS_AG: + return env->agregs; + case PS_MG: + return env->mgregs; + case PS_IG: + return env->igregs; + } +} + +void do_wrpstate() +{ + uint64_t new_pstate, pstate_regs, new_pstate_regs; + uint64_t *src, *dst; + + new_pstate = T0 & 0xf3f; + pstate_regs = env->pstate & 0xc01; + new_pstate_regs = new_pstate & 0xc01; + if (new_pstate_regs != pstate_regs) { + // Switch global register bank + src = get_gregset(new_pstate_regs); + dst = get_gregset(pstate_regs); + memcpy32(dst, env->gregs); + memcpy32(env->gregs, src); + } + env->pstate = new_pstate; +} + +void do_done(void) +{ + env->tl--; + env->pc = env->tnpc[env->tl]; + env->npc = env->tnpc[env->tl] + 4; + PUT_CCR(env, env->tstate[env->tl] >> 32); + env->asi = (env->tstate[env->tl] >> 24) & 0xff; + env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; + set_cwp(env->tstate[env->tl] & 0xff); +} + +void do_retry(void) +{ + env->tl--; + env->pc = env->tpc[env->tl]; + env->npc = env->tnpc[env->tl]; + PUT_CCR(env, env->tstate[env->tl] >> 32); + env->asi = (env->tstate[env->tl] >> 24) & 0xff; + env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; + set_cwp(env->tstate[env->tl] & 0xff); +} #endif void set_cwp(int new_cwp) @@ -744,7 +874,7 @@ void do_interrupt(int intno) #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_INT) { static int count; - fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", + fprintf(logfile, "%6d: v=%04x pc=%016llx npc=%016llx SP=%016llx\n", count, intno, env->pc, env->npc, env->regwptr[6]); @@ -766,8 +896,8 @@ void do_interrupt(int intno) } #endif #if !defined(CONFIG_USER_ONLY) - if (env->pstate & PS_IE) { - cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); + if (env->tl == MAXTL) { + cpu_abort(cpu_single_env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); return; } #endif @@ -776,8 +906,16 @@ void do_interrupt(int intno) env->tpc[env->tl] = env->pc; env->tnpc[env->tl] = env->npc; env->tt[env->tl] = intno; - env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4); - env->tl++; + env->pstate = PS_PEF | PS_PRIV | PS_AG; + env->tbr &= ~0x7fffULL; + env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); + if (env->tl < MAXTL - 1) { + env->tl++; + } else { + env->pstate |= PS_RED; + if (env->tl != MAXTL) + env->tl++; + } env->pc = env->tbr; env->npc = env->pc + 4; env->exception_index = 0; diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 2407c15d8..f5dbd2605 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -105,20 +105,10 @@ void OPPROTO glue(op_casx, MEMSUFFIX)(void) void OPPROTO glue(op_ldsw, MEMSUFFIX)(void) { - T1 = (int64_t)glue(ldl, MEMSUFFIX)(T0); + T1 = (int64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff); } -void OPPROTO glue(op_ldx, MEMSUFFIX)(void) -{ - // XXX - T1 = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32; - T1 |= glue(ldl, MEMSUFFIX)(T0); -} - -void OPPROTO glue(op_stx, MEMSUFFIX)(void) -{ - glue(stl, MEMSUFFIX)(T0, T1 >> 32); - glue(stl, MEMSUFFIX)(T0, T1 & 0xffffffff); -} +SPARC_LD_OP(ldx, ldq); +SPARC_ST_OP(stx, stq); #endif #undef MEMSUFFIX diff --git a/target-sparc/translate.c b/target-sparc/translate.c index e1c02725f..c2ba2e35c 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -86,6 +86,12 @@ enum { #define DFPREG(r) (r) #endif +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) (long)(x) +#endif + static int sign_extend(int x, int len) { len = 32 - len; @@ -462,7 +468,7 @@ OP_LD_TABLE(casx); static inline void gen_movl_imm_TN(int reg, uint32_t imm) { - gen_op_movl_TN_im[reg] (imm); + gen_op_movl_TN_im[reg](imm); } static inline void gen_movl_imm_T1(uint32_t val) @@ -529,15 +535,6 @@ static inline void gen_movl_T1_reg(int reg) gen_movl_TN_reg(reg, 1); } -/* call this function before using T2 as it may have been set for a jump */ -static inline void flush_T2(DisasContext * dc) -{ - if (dc->npc == JUMP_PC) { - gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); - dc->npc = DYNAMIC_PC; - } -} - static inline void gen_jmp_im(target_ulong pc) { #ifdef TARGET_SPARC64 @@ -564,10 +561,88 @@ static inline void gen_movl_npc_im(target_ulong npc) #endif } +static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2) +{ + int l1; + + l1 = gen_new_label(); + + gen_op_jz_T2_label(l1); + + gen_op_goto_tb0(TBPARAM(tb)); + gen_jmp_im(pc1); + gen_movl_npc_im(pc1 + 4); + gen_op_movl_T0_im((long)tb + 0); + gen_op_exit_tb(); + + gen_set_label(l1); + gen_op_goto_tb1(TBPARAM(tb)); + gen_jmp_im(pc2); + gen_movl_npc_im(pc2 + 4); + gen_op_movl_T0_im((long)tb + 1); + gen_op_exit_tb(); +} + +static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2) +{ + int l1; + + l1 = gen_new_label(); + + gen_op_jz_T2_label(l1); + + gen_op_goto_tb0(TBPARAM(tb)); + gen_jmp_im(pc2); + gen_movl_npc_im(pc1); + gen_op_movl_T0_im((long)tb + 0); + gen_op_exit_tb(); + + gen_set_label(l1); + gen_op_goto_tb1(TBPARAM(tb)); + gen_jmp_im(pc2 + 4); + gen_movl_npc_im(pc2 + 8); + gen_op_movl_T0_im((long)tb + 1); + gen_op_exit_tb(); +} + +static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc) +{ + gen_op_goto_tb0(TBPARAM(tb)); + gen_jmp_im(pc); + gen_movl_npc_im(npc); + gen_op_movl_T0_im((long)tb + 0); + gen_op_exit_tb(); +} + +static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2) +{ + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + gen_op_jz_T2_label(l1); + + gen_movl_npc_im(npc1); + gen_op_jmp_label(l2); + + gen_set_label(l1); + gen_movl_npc_im(npc2); + gen_set_label(l2); +} + +/* call this function before using T2 as it may have been set for a jump */ +static inline void flush_T2(DisasContext * dc) +{ + if (dc->npc == JUMP_PC) { + gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); + dc->npc = DYNAMIC_PC; + } +} + static inline void save_npc(DisasContext * dc) { if (dc->npc == JUMP_PC) { - gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); + gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); dc->npc = DYNAMIC_PC; } else if (dc->npc != DYNAMIC_PC) { gen_movl_npc_im(dc->npc); @@ -583,7 +658,7 @@ static inline void save_state(DisasContext * dc) static inline void gen_mov_pc_npc(DisasContext * dc) { if (dc->npc == JUMP_PC) { - gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); + gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); gen_op_mov_pc_npc(); dc->pc = DYNAMIC_PC; } else if (dc->npc == DYNAMIC_PC) { @@ -769,7 +844,7 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) flush_T2(dc); gen_cond[cc][cond](); if (a) { - gen_op_branch_a((long)dc->tb, target, dc->npc); + gen_branch_a(dc, (long)dc->tb, target, dc->npc); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -808,7 +883,7 @@ static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) flush_T2(dc); gen_fcond[cc][cond](); if (a) { - gen_op_branch_a((long)dc->tb, target, dc->npc); + gen_branch_a(dc, (long)dc->tb, target, dc->npc); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -829,7 +904,7 @@ static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn) flush_T2(dc); gen_cond_reg(cond); if (a) { - gen_op_branch_a((long)dc->tb, target, dc->npc); + gen_branch_a(dc, (long)dc->tb, target, dc->npc); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -893,7 +968,7 @@ static void disas_sparc_insn(DisasContext * dc) target <<= 2; target = sign_extend(target, 16); rs1 = GET_FIELD(insn, 13, 17); - gen_movl_T0_reg(rs1); + gen_movl_reg_T0(rs1); do_branch_reg(dc, target, insn); goto jmp_insn; } @@ -952,7 +1027,15 @@ static void disas_sparc_insn(DisasContext * dc) /*CALL*/ { target_long target = GET_FIELDs(insn, 2, 31) << 2; +#ifdef TARGET_SPARC64 + if (dc->pc == (uint32_t)dc->pc) { + gen_op_movl_T0_im(dc->pc); + } else { + gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); + } +#else gen_op_movl_T0_im(dc->pc); +#endif gen_movl_T0_reg(15); target += dc->pc; gen_mov_pc_npc(dc); @@ -1039,6 +1122,25 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs)); gen_movl_T0_reg(rd); break; + case 0x17: /* Tick compare */ + gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr)); + gen_movl_T0_reg(rd); + break; + case 0x18: /* System tick */ + gen_op_rdtick(); // XXX + gen_movl_T0_reg(rd); + break; + case 0x19: /* System tick compare */ + gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr)); + gen_movl_T0_reg(rd); + break; + case 0x10: /* Performance Control */ + case 0x11: /* Performance Instrumentation Counter */ + case 0x12: /* Dispatch Control */ + case 0x13: /* Graphics Status */ + case 0x14: /* Softint set, WO */ + case 0x15: /* Softint clear, WO */ + case 0x16: /* Softint write */ #endif default: goto illegal_insn; @@ -1548,6 +1650,50 @@ static void disas_sparc_insn(DisasContext * dc) } gen_movl_T0_reg(rd); } +#endif +#ifdef TARGET_SPARC64 + } else if (xop == 0x25) { /* sll, V9 sllx ( == sll) */ + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 20, 31); + gen_movl_simm_T1(rs2); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + gen_op_sll(); + gen_movl_T0_reg(rd); + } else if (xop == 0x26) { /* srl, V9 srlx */ + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 20, 31); + gen_movl_simm_T1(rs2); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + if (insn & (1 << 12)) + gen_op_srlx(); + else + gen_op_srl(); + gen_movl_T0_reg(rd); + } else if (xop == 0x27) { /* sra, V9 srax */ + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 20, 31); + gen_movl_simm_T1(rs2); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + if (insn & (1 << 12)) + gen_op_srax(); + else + gen_op_sra(); + gen_movl_T0_reg(rd); #endif } else if (xop < 0x38) { rs1 = GET_FIELD(insn, 13, 17); @@ -1660,32 +1806,20 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_mulscc_T1_T0(); gen_movl_T0_reg(rd); break; - case 0x25: /* sll, V9 sllx ( == sll) */ +#ifndef TARGET_SPARC64 + case 0x25: /* sll */ gen_op_sll(); gen_movl_T0_reg(rd); break; - case 0x26: /* srl, V9 srlx */ -#ifdef TARGET_SPARC64 - if (insn & (1 << 12)) - gen_op_srlx(); - else - gen_op_srl(); -#else + case 0x26: /* srl */ gen_op_srl(); -#endif gen_movl_T0_reg(rd); break; - case 0x27: /* sra, V9 srax */ -#ifdef TARGET_SPARC64 - if (insn & (1 << 12)) - gen_op_srax(); - else - gen_op_sra(); -#else + case 0x27: /* sra */ gen_op_sra(); -#endif gen_movl_T0_reg(rd); break; +#endif case 0x30: { switch(rd) { @@ -1709,7 +1843,28 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_sir(); #endif break; + case 0x17: /* Tick compare */ +#if !defined(CONFIG_USER_ONLY) + if (!supervisor(dc)) + goto illegal_insn; +#endif + gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); + break; + case 0x18: /* System tick */ +#if !defined(CONFIG_USER_ONLY) + if (!supervisor(dc)) + goto illegal_insn; +#endif + gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); + break; + case 0x19: /* System tick compare */ +#if !defined(CONFIG_USER_ONLY) + if (!supervisor(dc)) + goto illegal_insn; #endif + gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); + break; + case 0x10: /* Performance Control */ case 0x11: /* Performance Instrumentation Counter */ case 0x12: /* Dispatch Control */ @@ -1717,9 +1872,7 @@ static void disas_sparc_insn(DisasContext * dc) case 0x14: /* Softint set */ case 0x15: /* Softint clear */ case 0x16: /* Softint write */ - case 0x17: /* Tick compare */ - case 0x18: /* System tick */ - case 0x19: /* System tick compare */ +#endif default: goto illegal_insn; } @@ -1770,7 +1923,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_wrtick(); break; case 5: // tba - gen_op_movl_env_T0(offsetof(CPUSPARCState, tbr)); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); break; case 6: // pstate gen_op_wrpstate(); @@ -1896,7 +2049,6 @@ static void disas_sparc_insn(DisasContext * dc) } #ifdef TARGET_SPARC64 } else if (xop == 0x39) { /* V9 return */ - gen_op_restore(); rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ @@ -1920,6 +2072,7 @@ static void disas_sparc_insn(DisasContext * dc) } #endif } + gen_op_restore(); gen_mov_pc_npc(dc); gen_op_movl_npc_T0(); dc->npc = DYNAMIC_PC; @@ -1993,13 +2146,17 @@ static void disas_sparc_insn(DisasContext * dc) case 0: if (!supervisor(dc)) goto priv_insn; + dc->npc = DYNAMIC_PC; + dc->pc = DYNAMIC_PC; gen_op_done(); - break; + goto jmp_insn; case 1: if (!supervisor(dc)) goto priv_insn; + dc->npc = DYNAMIC_PC; + dc->pc = DYNAMIC_PC; gen_op_retry(); - break; + goto jmp_insn; default: goto illegal_insn; } @@ -2317,7 +2474,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_next_insn(); } else if (dc->npc == JUMP_PC) { /* we can do a static jump */ - gen_op_branch2((long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]); + gen_branch2(dc, (long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -2365,6 +2522,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; + nb_gen_labels = 0; do { if (env->nb_breakpoints > 0) { @@ -2421,7 +2579,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, if (dc->pc != DYNAMIC_PC && (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { /* static PC and NPC: we can use direct chaining */ - gen_op_branch((long)tb, dc->pc, dc->npc); + gen_branch(dc, (long)tb, dc->pc, dc->npc); } else { if (dc->pc != DYNAMIC_PC) gen_jmp_im(dc->pc); @@ -2487,15 +2645,16 @@ void cpu_reset(CPUSPARCState *env) #else env->psrs = 1; env->psrps = 1; - env->pc = 0xffd00000; env->gregs[1] = ram_size; - env->npc = env->pc + 4; #ifdef TARGET_SPARC64 - env->pstate = PS_AM | PS_PRIV; // XXX: Force AM + env->pstate = PS_PRIV; env->version = GET_VER(env); + env->pc = 0x1fff0000000ULL; #else env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ + env->pc = 0xffd00000; #endif + env->npc = env->pc + 4; #endif } diff --git a/vl.h b/vl.h index 85d0cf473..f9fe6a34f 100644 --- a/vl.h +++ b/vl.h @@ -559,6 +559,7 @@ void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque); PCIBus *pci_prep_init(void); PCIBus *pci_grackle_init(uint32_t base); PCIBus *pci_pmac_init(void); +PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base); /* openpic.c */ typedef struct openpic_t openpic_t; -- cgit v1.2.3 From 667f38b167caebb38a16aef6df56db0dcb34d684 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 14:46:27 +0000 Subject: [f]truncate64 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1515 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0a4f07e31..5a6d3821f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2756,11 +2756,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_truncate64 case TARGET_NR_truncate64: - goto unimplemented; + ret = get_errno(truncate64((const char *)arg1, arg2)); + break; #endif #ifdef TARGET_NR_ftruncate64 case TARGET_NR_ftruncate64: - goto unimplemented; + ret = get_errno(ftruncate64(arg1, arg2)); + break; #endif #ifdef TARGET_NR_stat64 case TARGET_NR_stat64: -- cgit v1.2.3 From 2efbe911d3ea518f5d4648954379f9d5aa02e806 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 15:10:20 +0000 Subject: more set/getsockopt values git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1516 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 7 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5a6d3821f..e51f51353 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -547,7 +547,21 @@ static long do_setsockopt(int sockfd, int level, int optname, break; case SOL_IP: switch(optname) { + case IP_TOS: + case IP_TTL: case IP_HDRINCL: + case IP_ROUTER_ALERT: + case IP_RECVOPTS: + case IP_RETOPTS: + case IP_PKTINFO: + case IP_MTU_DISCOVER: + case IP_RECVERR: + case IP_RECVTOS: +#ifdef IP_FREEBIND + case IP_FREEBIND: +#endif + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: val = 0; if (optlen >= sizeof(uint32_t)) { if (get_user(val, (uint32_t *)optval)) @@ -619,6 +633,45 @@ static long do_getsockopt(int sockfd, int level, int optname, /* These don't just return a single integer */ goto unimplemented; default: + goto int_case; + } + break; + case SOL_TCP: + /* TCP options all take an 'int' value. */ + int_case: + if (get_user(len, optlen)) + return -EFAULT; + if (len < 0) + return -EINVAL; + lv = sizeof(int); + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); + if (ret < 0) + return ret; + val = tswap32(val); + if (len > lv) + len = lv; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + if (put_user(len, optlen)) + return -EFAULT; + break; + case SOL_IP: + switch(optname) { + case IP_TOS: + case IP_TTL: + case IP_HDRINCL: + case IP_ROUTER_ALERT: + case IP_RECVOPTS: + case IP_RETOPTS: + case IP_PKTINFO: + case IP_MTU_DISCOVER: + case IP_RECVERR: + case IP_RECVTOS: +#ifdef IP_FREEBIND + case IP_FREEBIND: +#endif + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: if (get_user(len, optlen)) return -EFAULT; if (len < 0) @@ -627,14 +680,25 @@ static long do_getsockopt(int sockfd, int level, int optname, ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); if (ret < 0) return ret; - val = tswap32(val); - if (len > lv) - len = lv; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - if (put_user(len, optlen)) - return -EFAULT; + if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { + unsigned char ucval = val; + len = 1; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval,&ucval,1)) + return -EFAULT; + } else { + val = tswap32(val); + if (len > sizeof(int)) + len = sizeof(int); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + } break; + default: + goto unimplemented; } break; default: -- cgit v1.2.3 From 8f091a59605092994c4b52c20b7173c514411e38 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 17:41:26 +0000 Subject: x86_64 fixes (initial patch by Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1517 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 10 ++++ target-i386/exec.h | 5 +- target-i386/helper.c | 54 +++++++++++++++++++++- target-i386/helper2.c | 9 +++- target-i386/op.c | 12 +++++ target-i386/translate.c | 120 ++++++++++++++++++++++++++++++++++-------------- 6 files changed, 171 insertions(+), 39 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 354951110..f8373a102 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -214,6 +214,12 @@ #define MSR_IA32_SYSENTER_ESP 0x175 #define MSR_IA32_SYSENTER_EIP 0x176 +#define MSR_MCG_CAP 0x179 +#define MSR_MCG_STATUS 0x17a +#define MSR_MCG_CTL 0x17b + +#define MSR_PAT 0x277 + #define MSR_EFER 0xc0000080 #define MSR_EFER_SCE (1 << 0) @@ -246,6 +252,8 @@ #define CPUID_PGE (1 << 13) #define CPUID_MCA (1 << 14) #define CPUID_CMOV (1 << 15) +#define CPUID_PAT (1 << 16) +#define CPUID_CLFLUSH (1 << 19) /* ... */ #define CPUID_MMX (1 << 23) #define CPUID_FXSR (1 << 24) @@ -474,6 +482,8 @@ typedef struct CPUX86State { target_ulong kernelgsbase; #endif + uint64_t pat; + /* temporary data for USE_CODE_COPY mode */ #ifdef USE_CODE_COPY uint32_t tmp0; diff --git a/target-i386/exec.h b/target-i386/exec.h index e4b6251a2..a3bbea999 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -157,11 +157,11 @@ void helper_lldt_T0(void); void helper_ltr_T0(void); void helper_movl_crN_T0(int reg); void helper_movl_drN_T0(int reg); -void helper_invlpg(unsigned int addr); +void helper_invlpg(target_ulong addr); void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); +void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr); int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write, int is_user, int is_softmmu); void tlb_fill(target_ulong addr, int is_write, int is_user, @@ -190,6 +190,7 @@ void helper_idivq_EAX_T0(void); void helper_cmpxchg8b(void); void helper_cpuid(void); void helper_enter_level(int level, int data32); +void helper_enter64_level(int level, int data64); void helper_sysenter(void); void helper_sysexit(void); void helper_syscall(int next_eip_addend); diff --git a/target-i386/helper.c b/target-i386/helper.c index 0d2cd74bc..2d241a143 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1334,6 +1334,20 @@ void helper_cpuid(void) ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2]; EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3]; break; + case 0x80000005: + /* cache info (L1 cache) */ + EAX = 0x01ff01ff; + EBX = 0x01ff01ff; + ECX = 0x40020140; + EDX = 0x40020140; + break; + case 0x80000006: + /* cache info (L2 cache) */ + EAX = 0; + EBX = 0x42004200; + ECX = 0x02008140; + EDX = 0; + break; case 0x80000008: /* virtual & phys address size in low 2 bytes. */ EAX = 0x00003028; @@ -1383,6 +1397,37 @@ void helper_enter_level(int level, int data32) } } +#ifdef TARGET_X86_64 +void helper_enter64_level(int level, int data64) +{ + target_ulong esp, ebp; + ebp = EBP; + esp = ESP; + + if (data64) { + /* 64 bit */ + esp -= 8; + while (--level) { + esp -= 8; + ebp -= 8; + stq(esp, ldq(ebp)); + } + esp -= 8; + stq(esp, T1); + } else { + /* 16 bit */ + esp -= 2; + while (--level) { + esp -= 2; + ebp -= 2; + stw(esp, lduw(ebp)); + } + esp -= 2; + stw(esp, T1); + } +} +#endif + void helper_lldt_T0(void) { int selector; @@ -1963,6 +2008,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) #endif sp_mask = get_sp_mask(env->segs[R_SS].flags); sp = ESP; + /* XXX: ssp is zero in 64 bit ? */ ssp = env->segs[R_SS].base; new_eflags = 0; /* avoid warning */ #ifdef TARGET_X86_64 @@ -2271,7 +2317,7 @@ void helper_movl_drN_T0(int reg) env->dr[reg] = T0; } -void helper_invlpg(unsigned int addr) +void helper_invlpg(target_ulong addr) { cpu_x86_flush_tlb(env, addr); } @@ -2332,6 +2378,9 @@ void helper_wrmsr(void) case MSR_STAR: env->star = val; break; + case MSR_PAT: + env->pat = val; + break; #ifdef TARGET_X86_64 case MSR_LSTAR: env->lstar = val; @@ -2380,6 +2429,9 @@ void helper_rdmsr(void) case MSR_STAR: val = env->star; break; + case MSR_PAT: + val = env->pat; + break; #ifdef TARGET_X86_64 case MSR_LSTAR: val = env->lstar; diff --git a/target-i386/helper2.c b/target-i386/helper2.c index d571458f7..60335909a 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -106,7 +106,9 @@ CPUX86State *cpu_x86_init(void) env->cpuid_version = (family << 8) | (model << 4) | stepping; env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_MCE | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV); + CPUID_CX8 | CPUID_PGE | CPUID_CMOV | + CPUID_PAT); + env->pat = 0x0007040600070406ULL; env->cpuid_ext_features = 0; env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP; env->cpuid_xlevel = 0; @@ -128,6 +130,9 @@ CPUX86State *cpu_x86_init(void) env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF); env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL; env->cpuid_xlevel = 0x80000008; + + /* these features are needed for Win64 and aren't fully implemented */ + env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA; #endif } cpu_single_env = env; @@ -546,7 +551,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) } /* XXX: also flush 4MB pages */ -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) +void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr) { tlb_flush_page(env, addr); } diff --git a/target-i386/op.c b/target-i386/op.c index 2af4e8eb3..3574576ab 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -898,6 +898,11 @@ void op_addw_ESP_im(void) } #ifdef TARGET_X86_64 +void op_subq_A0_2(void) +{ + A0 -= 2; +} + void op_subq_A0_8(void) { A0 -= 8; @@ -929,6 +934,13 @@ void OPPROTO op_enter_level(void) helper_enter_level(PARAM1, PARAM2); } +#ifdef TARGET_X86_64 +void OPPROTO op_enter64_level(void) +{ + helper_enter64_level(PARAM1, PARAM2); +} +#endif + void OPPROTO op_sysenter(void) { helper_sysenter(); diff --git a/target-i386/translate.c b/target-i386/translate.c index c4584a012..619522a63 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1627,7 +1627,14 @@ static void gen_add_A0_ds_seg(DisasContext *s) override = R_DS; } if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); +#ifdef TARGET_X86_64 + if (CODE64(s)) { + gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base)); + } else +#endif + { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } } } @@ -1948,10 +1955,14 @@ static void gen_push_T0(DisasContext *s) { #ifdef TARGET_X86_64 if (CODE64(s)) { - /* XXX: check 16 bit behaviour */ gen_op_movq_A0_reg[R_ESP](); - gen_op_subq_A0_8(); - gen_op_st_T0_A0[OT_QUAD + s->mem_index](); + if (s->dflag) { + gen_op_subq_A0_8(); + gen_op_st_T0_A0[OT_QUAD + s->mem_index](); + } else { + gen_op_subq_A0_2(); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + } gen_op_movq_ESP_A0(); } else #endif @@ -1985,10 +1996,14 @@ static void gen_push_T1(DisasContext *s) { #ifdef TARGET_X86_64 if (CODE64(s)) { - /* XXX: check 16 bit behaviour */ gen_op_movq_A0_reg[R_ESP](); - gen_op_subq_A0_8(); - gen_op_st_T1_A0[OT_QUAD + s->mem_index](); + if (s->dflag) { + gen_op_subq_A0_8(); + gen_op_st_T1_A0[OT_QUAD + s->mem_index](); + } else { + gen_op_subq_A0_2(); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + } gen_op_movq_ESP_A0(); } else #endif @@ -2020,9 +2035,8 @@ static void gen_pop_T0(DisasContext *s) { #ifdef TARGET_X86_64 if (CODE64(s)) { - /* XXX: check 16 bit behaviour */ gen_op_movq_A0_reg[R_ESP](); - gen_op_ld_T0_A0[OT_QUAD + s->mem_index](); + gen_op_ld_T0_A0[(s->dflag ? OT_QUAD : OT_WORD) + s->mem_index](); } else #endif { @@ -2041,7 +2055,7 @@ static void gen_pop_T0(DisasContext *s) static void gen_pop_update(DisasContext *s) { #ifdef TARGET_X86_64 - if (CODE64(s)) { + if (CODE64(s) && s->dflag) { gen_stack_update(s, 8); } else #endif @@ -2105,26 +2119,48 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) { int ot, opsize; - ot = s->dflag + OT_WORD; level &= 0x1f; - opsize = 2 << s->dflag; - - gen_op_movl_A0_ESP(); - gen_op_addl_A0_im(-opsize); - if (!s->ss32) - gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); - /* push bp */ - gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_st_T0_A0[ot + s->mem_index](); - if (level) { - gen_op_enter_level(level, s->dflag); +#ifdef TARGET_X86_64 + if (CODE64(s)) { + ot = s->dflag ? OT_QUAD : OT_WORD; + opsize = 1 << ot; + + gen_op_movl_A0_ESP(); + gen_op_addq_A0_im(-opsize); + gen_op_movl_T1_A0(); + + /* push bp */ + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_st_T0_A0[ot + s->mem_index](); + if (level) { + gen_op_enter64_level(level, (ot == OT_QUAD)); + } + gen_op_mov_reg_T1[ot][R_EBP](); + gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); + gen_op_mov_reg_T1[OT_QUAD][R_ESP](); + } else +#endif + { + ot = s->dflag + OT_WORD; + opsize = 2 << s->dflag; + + gen_op_movl_A0_ESP(); + gen_op_addl_A0_im(-opsize); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + /* push bp */ + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_st_T0_A0[ot + s->mem_index](); + if (level) { + gen_op_enter_level(level, s->dflag); + } + gen_op_mov_reg_T1[ot][R_EBP](); + gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); + gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); } - gen_op_mov_reg_T1[ot][R_EBP](); - gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); - gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); } static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) @@ -2901,7 +2937,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) if (mod != 3) goto illegal_op; #ifdef TARGET_X86_64 - if (CODE64(s)) { + if (s->aflag == 2) { gen_op_movq_A0_reg[R_EDI](); } else #endif @@ -3697,7 +3733,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0xc8: /* enter */ { - /* XXX: long mode support */ int level; val = lduw_code(s->pc); s->pc += 2; @@ -3707,7 +3742,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0xc9: /* leave */ /* XXX: exception not precise (ESP is updated before potential exception) */ - /* XXX: may be invalid for 16 bit in long mode */ if (CODE64(s)) { gen_op_mov_TN_reg[OT_QUAD][0][R_EBP](); gen_op_mov_reg_T0[OT_QUAD][R_ESP](); @@ -3926,7 +3960,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) else ot = dflag + OT_WORD; #ifdef TARGET_X86_64 - if (CODE64(s)) { + if (s->aflag == 2) { offset_addr = ldq_code(s->pc); s->pc += 8; if (offset_addr == (int32_t)offset_addr) @@ -3955,7 +3989,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0xd7: /* xlat */ #ifdef TARGET_X86_64 - if (CODE64(s)) { + if (s->aflag == 2) { gen_op_movq_A0_reg[R_EBX](); gen_op_addq_A0_AL(); } else @@ -4779,6 +4813,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) val = ldsw_code(s->pc); s->pc += 2; gen_pop_T0(s); + if (CODE64(s) && s->dflag) + s->dflag = 2; gen_stack_update(s, val + (2 << s->dflag)); if (s->dflag == 0) gen_op_andl_T0_ffff(); @@ -5782,14 +5818,30 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 5: /* lfence */ case 6: /* mfence */ - case 7: /* sfence */ if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE)) goto illegal_op; break; + case 7: /* sfence / clflush */ + if ((modrm & 0xc7) == 0xc0) { + /* sfence */ + if (!(s->cpuid_features & CPUID_SSE)) + goto illegal_op; + } else { + /* clflush */ + if (!(s->cpuid_features & CPUID_CLFLUSH)) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + } + break; default: goto illegal_op; } break; + case 0x10d: /* prefetch */ + modrm = ldub_code(s->pc++); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* ignore for now */ + break; case 0x110 ... 0x117: case 0x128 ... 0x12f: case 0x150 ... 0x177: -- cgit v1.2.3 From e5d80f94c574592a293dfbd6ab5cda674373b514 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 17:43:14 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1518 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.texi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qemu-img.texi b/qemu-img.texi index 3afd32085..ac7923ffd 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -44,8 +44,7 @@ User Mode Linux Copy On Write image format. Used to be the only growable image format in QEMU. It is supported only for compatibility with previous versions. It does not work on win32. @item vmdk -VMware 3 and 4 compatible image format. Currently only supported as -read-only. +VMware 3 and 4 compatible image format. @item cloop Linux Compressed Loop image, useful only to reuse directly compressed CD-ROM images present for example in the Knoppix CD-ROMs. -- cgit v1.2.3 From 1ff5c1a68e2784722b66ecc40e30908e87e28a3b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 17:54:50 +0000 Subject: prevent window resizing git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1519 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sdl.c b/sdl.c index 20e45d93f..d43da8831 100644 --- a/sdl.c +++ b/sdl.c @@ -53,7 +53,6 @@ static void sdl_resize(DisplayState *ds, int w, int h) // printf("resizing to %d %d\n", w, h); flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; - flags |= SDL_RESIZABLE; if (gui_fullscreen) flags |= SDL_FULLSCREEN; screen = SDL_SetVideoMode(w, h, 0, flags); -- cgit v1.2.3 From d592d3033d7bc41db6159e9387591a216e3c46e0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 19:05:37 +0000 Subject: IOAPIC support (initial patch by Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1520 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 545 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/i8259.c | 13 ++ hw/pc.c | 12 +- vl.h | 6 + 4 files changed, 547 insertions(+), 29 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index 486b9bf87..8b33cab37 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -20,6 +20,7 @@ #include "vl.h" //#define DEBUG_APIC +//#define DEBUG_IOAPIC /* APIC Local Vector Table */ #define APIC_LVT_TIMER 0 @@ -39,6 +40,10 @@ #define APIC_DM_SIPI 6 #define APIC_DM_EXTINT 7 +/* APIC destination mode */ +#define APIC_DESTMODE_FLAT 0xf +#define APIC_DESTMODE_CLUSTER 1 + #define APIC_TRIGGER_EDGE 0 #define APIC_TRIGGER_LEVEL 1 @@ -49,6 +54,8 @@ #define APIC_INPUT_POLARITY (1<<13) #define APIC_SEND_PENDING (1<<12) +#define IOAPIC_NUM_PINS 0x18 + #define ESR_ILLEGAL_ADDRESS (1 << 7) #define APIC_SV_ENABLE (1 << 8) @@ -57,8 +64,11 @@ typedef struct APICState { CPUState *cpu_env; uint32_t apicbase; uint8_t id; + uint8_t arb_id; uint8_t tpr; uint32_t spurious_vec; + uint8_t log_dest; + uint8_t dest_mode; uint32_t isr[8]; /* in service register */ uint32_t tmr[8]; /* trigger mode register */ uint32_t irr[8]; /* interrupt request register */ @@ -71,9 +81,65 @@ typedef struct APICState { uint32_t initial_count; int64_t initial_count_load_time, next_time; QEMUTimer *timer; + + struct APICState *next_apic; } APICState; +struct IOAPICState { + uint8_t id; + uint8_t ioregsel; + + uint32_t irr; + uint64_t ioredtbl[IOAPIC_NUM_PINS]; +}; + static int apic_io_memory; +static APICState *first_local_apic = NULL; +static int last_apic_id = 0; +static IOAPICState *ioapic_state; + +static void apic_init_ipi(APICState *s); +static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); +static void apic_update_irq(APICState *s); + +static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, + uint8_t vector_num, uint8_t polarity, + uint8_t trigger_mode) +{ + APICState *apic_iter; + + switch (delivery_mode) { + case APIC_DM_LOWPRI: + case APIC_DM_FIXED: + /* XXX: arbitration */ + break; + + case APIC_DM_SMI: + case APIC_DM_NMI: + break; + + case APIC_DM_INIT: + /* normal INIT IPI sent to processors */ + for (apic_iter = first_local_apic; apic_iter != NULL; + apic_iter = apic_iter->next_apic) { + apic_init_ipi(apic_iter); + } + return; + + case APIC_DM_EXTINT: + /* XXX: implement */ + break; + + default: + return; + } + + for (apic_iter = first_local_apic; apic_iter != NULL; + apic_iter = apic_iter->next_apic) { + if (deliver_bitmask & (1 << apic_iter->id)) + apic_set_irq(apic_iter, vector_num, trigger_mode); + } +} void cpu_set_apic_base(CPUState *env, uint64_t val) { @@ -104,6 +170,7 @@ void cpu_set_apic_tpr(CPUX86State *env, uint8_t val) { APICState *s = env->apic_state; s->tpr = (val & 0x0f) << 4; + apic_update_irq(s); } uint8_t cpu_get_apic_tpr(CPUX86State *env) @@ -112,16 +179,24 @@ uint8_t cpu_get_apic_tpr(CPUX86State *env) return s->tpr >> 4; } -/* return -1 if no bit is set */ -static int get_highest_priority_int(uint32_t *tab) +int fls_bit(int value) { - int i; - for(i = 0;i < 8; i++) { - if (tab[i] != 0) { - return i * 32 + ffs(tab[i]) - 1; - } - } - return -1; + unsigned int ret = 0; + +#ifdef HOST_I386 + __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value)); + return ret; +#else + if (value > 0xffff) + value >>= 16, ret = 16; + if (value > 0xff) + value >>= 8, ret += 8; + if (value > 0xf) + value >>= 4, ret += 4; + if (value > 0x3) + value >>= 2, ret += 2; + return ret + (value >> 1); +#endif } static inline void set_bit(uint32_t *tab, int index) @@ -140,6 +215,18 @@ static inline void reset_bit(uint32_t *tab, int index) tab[i] &= ~mask; } +/* return -1 if no bit is set */ +static int get_highest_priority_int(uint32_t *tab) +{ + int i; + for(i = 7; i >= 0; i--) { + if (tab[i] != 0) { + return i * 32 + fls_bit(tab[i]); + } + } + return -1; +} + static int apic_get_ppr(APICState *s) { int tpr, isrv, ppr; @@ -156,16 +243,23 @@ static int apic_get_ppr(APICState *s) return ppr; } +static int apic_get_arb_pri(APICState *s) +{ + /* XXX: arbitration */ + return 0; +} + /* signal the CPU if an irq is pending */ static void apic_update_irq(APICState *s) { - int irrv, isrv; + int irrv, ppr; + if (!(s->spurious_vec & APIC_SV_ENABLE)) + return; irrv = get_highest_priority_int(s->irr); if (irrv < 0) return; - isrv = get_highest_priority_int(s->isr); - /* if the pending irq has less priority, we do not make a new request */ - if (isrv >= 0 && irrv >= isrv) + ppr = apic_get_ppr(s); + if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) return; cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); } @@ -187,9 +281,116 @@ static void apic_eoi(APICState *s) if (isrv < 0) return; reset_bit(s->isr, isrv); + /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to + set the remote IRR bit for level triggered interrupts. */ apic_update_irq(s); } +static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode) +{ + uint32_t mask = 0; + APICState *apic_iter; + + if (dest_mode == 0) { + if (dest == 0xff) + mask = 0xff; + else + mask = 1 << dest; + } else { + /* XXX: cluster mode */ + for (apic_iter = first_local_apic; apic_iter != NULL; + apic_iter = apic_iter->next_apic) { + if (dest & apic_iter->log_dest) + mask |= (1 << apic_iter->id); + } + } + + return mask; +} + + +static void apic_init_ipi(APICState *s) +{ + int i; + + for(i = 0; i < APIC_LVT_NB; i++) + s->lvt[i] = 1 << 16; /* mask LVT */ + s->tpr = 0; + s->spurious_vec = 0xff; + s->log_dest = 0; + s->dest_mode = 0; + memset(s->isr, 0, sizeof(s->isr)); + memset(s->tmr, 0, sizeof(s->tmr)); + memset(s->irr, 0, sizeof(s->irr)); + memset(s->lvt, 0, sizeof(s->lvt)); + s->esr = 0; + memset(s->icr, 0, sizeof(s->icr)); + s->divide_conf = 0; + s->count_shift = 0; + s->initial_count = 0; + s->initial_count_load_time = 0; + s->next_time = 0; +} + +static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, + uint8_t delivery_mode, uint8_t vector_num, + uint8_t polarity, uint8_t trigger_mode) +{ + uint32_t deliver_bitmask = 0; + int dest_shorthand = (s->icr[0] >> 18) & 3; + APICState *apic_iter; + + switch (delivery_mode) { + case APIC_DM_LOWPRI: + /* XXX: serch for focus processor, arbitration */ + dest = s->id; + + case APIC_DM_INIT: + { + int trig_mode = (s->icr[0] >> 15) & 1; + int level = (s->icr[0] >> 14) & 1; + if (level == 0 && trig_mode == 1) { + for (apic_iter = first_local_apic; apic_iter != NULL; + apic_iter = apic_iter->next_apic) { + if (deliver_bitmask & (1 << apic_iter->id)) { + apic_iter->arb_id = apic_iter->id; + } + } + return; + } + } + break; + + case APIC_DM_SIPI: + for (apic_iter = first_local_apic; apic_iter != NULL; + apic_iter = apic_iter->next_apic) { + if (deliver_bitmask & (1 << apic_iter->id)) { + /* XXX: SMP support */ + /* apic_startup(apic_iter); */ + } + } + return; + } + + switch (dest_shorthand) { + case 0: + deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode); + break; + case 1: + deliver_bitmask = (1 << s->id); + break; + case 2: + deliver_bitmask = 0xffffffff; + break; + case 3: + deliver_bitmask = 0xffffffff & ~(1 << s->id); + break; + } + + apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity, + trigger_mode); +} + int apic_get_interrupt(CPUState *env) { APICState *s = env->apic_state; @@ -207,6 +408,8 @@ int apic_get_interrupt(CPUState *env) if (intno < 0) return -1; reset_bit(s->irr, intno); + if (s->tpr && intno <= s->tpr) + return s->spurious_vec & 0xff; set_bit(s->isr, intno); apic_update_irq(s); return intno; @@ -220,7 +423,7 @@ static uint32_t apic_get_current_count(APICState *s) s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { /* periodic */ - val = s->initial_count - (d % (s->initial_count + 1)); + val = s->initial_count - (d % ((uint64_t)s->initial_count + 1)); } else { if (d >= s->initial_count) val = 0; @@ -238,11 +441,11 @@ static void apic_timer_update(APICState *s, int64_t current_time) d = (current_time - s->initial_count_load_time) >> s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { - d = ((d / (s->initial_count + 1)) + 1) * (s->initial_count + 1); + d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1); } else { if (d >= s->initial_count) goto no_timer; - d = s->initial_count + 1; + d = (uint64_t)s->initial_count + 1; } next_time = s->initial_count_load_time + (d << s->count_shift); qemu_mod_timer(s->timer, next_time); @@ -304,10 +507,19 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) case 0x08: val = s->tpr; break; + case 0x09: + val = apic_get_arb_pri(s); + break; case 0x0a: /* ppr */ val = apic_get_ppr(s); break; + case 0x0d: + val = s->log_dest << 24; + break; + case 0x0e: + val = s->dest_mode << 28; + break; case 0x0f: val = s->spurious_vec; break; @@ -372,16 +584,29 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 0x08: s->tpr = val; + apic_update_irq(s); break; case 0x0b: /* EOI */ apic_eoi(s); break; + case 0x0d: + s->log_dest = val >> 24; + break; + case 0x0e: + s->dest_mode = val >> 28; + break; case 0x0f: s->spurious_vec = val & 0x1ff; + apic_update_irq(s); break; case 0x30: + s->icr[0] = val; + apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1, + (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff), + (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1); + break; case 0x31: - s->icr[index & 1] = val; + s->icr[1] = val; break; case 0x32 ... 0x37: { @@ -410,7 +635,76 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) } } +static void apic_save(QEMUFile *f, void *opaque) +{ + APICState *s = opaque; + int i; + + qemu_put_be32s(f, &s->apicbase); + qemu_put_8s(f, &s->id); + qemu_put_8s(f, &s->arb_id); + qemu_put_8s(f, &s->tpr); + qemu_put_be32s(f, &s->spurious_vec); + qemu_put_8s(f, &s->log_dest); + qemu_put_8s(f, &s->dest_mode); + for (i = 0; i < 8; i++) { + qemu_put_be32s(f, &s->isr[i]); + qemu_put_be32s(f, &s->tmr[i]); + qemu_put_be32s(f, &s->irr[i]); + } + for (i = 0; i < APIC_LVT_NB; i++) { + qemu_put_be32s(f, &s->lvt[i]); + } + qemu_put_be32s(f, &s->esr); + qemu_put_be32s(f, &s->icr[0]); + qemu_put_be32s(f, &s->icr[1]); + qemu_put_be32s(f, &s->divide_conf); + qemu_put_be32s(f, &s->count_shift); + qemu_put_be32s(f, &s->initial_count); + qemu_put_be64s(f, &s->initial_count_load_time); + qemu_put_be64s(f, &s->next_time); +} + +static int apic_load(QEMUFile *f, void *opaque, int version_id) +{ + APICState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + /* XXX: what if the base changes? (registered memory regions) */ + qemu_get_be32s(f, &s->apicbase); + qemu_get_8s(f, &s->id); + qemu_get_8s(f, &s->arb_id); + qemu_get_8s(f, &s->tpr); + qemu_get_be32s(f, &s->spurious_vec); + qemu_get_8s(f, &s->log_dest); + qemu_get_8s(f, &s->dest_mode); + for (i = 0; i < 8; i++) { + qemu_get_be32s(f, &s->isr[i]); + qemu_get_be32s(f, &s->tmr[i]); + qemu_get_be32s(f, &s->irr[i]); + } + for (i = 0; i < APIC_LVT_NB; i++) { + qemu_get_be32s(f, &s->lvt[i]); + } + qemu_get_be32s(f, &s->esr); + qemu_get_be32s(f, &s->icr[0]); + qemu_get_be32s(f, &s->icr[1]); + qemu_get_be32s(f, &s->divide_conf); + qemu_get_be32s(f, &s->count_shift); + qemu_get_be32s(f, &s->initial_count); + qemu_get_be64s(f, &s->initial_count_load_time); + qemu_get_be64s(f, &s->next_time); + return 0; +} +static void apic_reset(void *opaque) +{ + APICState *s = opaque; + apic_init_ipi(s); +} static CPUReadMemoryFunc *apic_mem_read[3] = { apic_mem_readb, @@ -427,27 +721,228 @@ static CPUWriteMemoryFunc *apic_mem_write[3] = { int apic_init(CPUState *env) { APICState *s; - int i; - s = malloc(sizeof(APICState)); + s = qemu_mallocz(sizeof(APICState)); if (!s) return -1; - memset(s, 0, sizeof(*s)); env->apic_state = s; + apic_init_ipi(s); + s->id = last_apic_id++; s->cpu_env = env; s->apicbase = 0xfee00000 | - MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE; - for(i = 0; i < APIC_LVT_NB; i++) - s->lvt[i] = 1 << 16; /* mask LVT */ - s->spurious_vec = 0xff; + (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; + /* XXX: mapping more APICs at the same memory location */ if (apic_io_memory == 0) { /* NOTE: the APIC is directly connected to the CPU - it is not on the global memory bus. */ apic_io_memory = cpu_register_io_memory(0, apic_mem_read, apic_mem_write, NULL); - cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory); + cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, + apic_io_memory); } s->timer = qemu_new_timer(vm_clock, apic_timer, s); + + register_savevm("apic", 0, 1, apic_save, apic_load, s); + qemu_register_reset(apic_reset, s); + + s->next_apic = first_local_apic; + first_local_apic = s; + + return 0; +} + +static void ioapic_service(IOAPICState *s) +{ + uint8_t vector; + uint32_t mask; + uint64_t entry; + uint8_t dest; + uint8_t dest_mode; + + for (vector = 0; vector < IOAPIC_NUM_PINS; vector++) { + mask = 1 << vector; + if (s->irr & mask) { + entry = s->ioredtbl[vector]; + if (!(entry & APIC_LVT_MASKED)) { + if (!((entry >> 15) & 1)) + s->irr &= ~mask; + dest = entry >> 56; + dest_mode = (entry >> 11) & 1; + apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode), + (entry >> 8) & 7, entry & 0xff, + (entry >> 13) & 1, (entry >> 15) & 1); + } + } + } +} + +void ioapic_set_irq(void *opaque, int vector, int level) +{ + IOAPICState *s = opaque; + + if (vector >= 0 && vector < IOAPIC_NUM_PINS) { + uint32_t mask = 1 << vector; + uint64_t entry = s->ioredtbl[vector]; + + if ((entry >> 15) & 1) { + /* level triggered */ + if (level) { + s->irr |= mask; + ioapic_service(s); + } else { + s->irr &= ~mask; + } + } else { + /* edge triggered */ + if (level) { + s->irr |= mask; + ioapic_service(s); + } + } + } +} + +static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr) +{ + IOAPICState *s = opaque; + int index; + uint32_t val = 0; + + addr &= 0xff; + if (addr == 0x00) { + val = s->ioregsel; + } else if (addr == 0x10) { + switch (s->ioregsel) { + case 0x00: + val = s->id << 24; + break; + case 0x01: + val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */ + break; + case 0x02: + val = 0; + break; + default: + index = (s->ioregsel - 0x10) >> 1; + if (index >= 0 && index < IOAPIC_NUM_PINS) { + if (s->ioregsel & 1) + val = s->ioredtbl[index] >> 32; + else + val = s->ioredtbl[index] & 0xffffffff; + } + } +#ifdef DEBUG_IOAPIC + printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val); +#endif + } + return val; +} + +static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + IOAPICState *s = opaque; + int index; + + addr &= 0xff; + if (addr == 0x00) { + s->ioregsel = val; + return; + } else if (addr == 0x10) { +#ifdef DEBUG_IOAPIC + printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val); +#endif + switch (s->ioregsel) { + case 0x00: + s->id = (val >> 24) & 0xff; + return; + case 0x01: + case 0x02: + return; + default: + index = (s->ioregsel - 0x10) >> 1; + if (index >= 0 && index < IOAPIC_NUM_PINS) { + if (s->ioregsel & 1) { + s->ioredtbl[index] &= 0xffffffff; + s->ioredtbl[index] |= (uint64_t)val << 32; + } else { + s->ioredtbl[index] &= ~0xffffffffULL; + s->ioredtbl[index] |= val; + } + ioapic_service(s); + } + } + } +} + +static void ioapic_save(QEMUFile *f, void *opaque) +{ + IOAPICState *s = opaque; + int i; + + qemu_put_8s(f, &s->id); + qemu_put_8s(f, &s->ioregsel); + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + qemu_put_be64s(f, &s->ioredtbl[i]); + } +} + +static int ioapic_load(QEMUFile *f, void *opaque, int version_id) +{ + IOAPICState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_8s(f, &s->id); + qemu_get_8s(f, &s->ioregsel); + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + qemu_get_be64s(f, &s->ioredtbl[i]); + } return 0; } + +static void ioapic_reset(void *opaque) +{ + IOAPICState *s = opaque; + int i; + + memset(s, 0, sizeof(*s)); + for(i = 0; i < IOAPIC_NUM_PINS; i++) + s->ioredtbl[i] = 1 << 16; /* mask LVT */ +} + +static CPUReadMemoryFunc *ioapic_mem_read[3] = { + ioapic_mem_readl, + ioapic_mem_readl, + ioapic_mem_readl, +}; + +static CPUWriteMemoryFunc *ioapic_mem_write[3] = { + ioapic_mem_writel, + ioapic_mem_writel, + ioapic_mem_writel, +}; + +IOAPICState *ioapic_init(void) +{ + IOAPICState *s; + int io_memory; + + s = malloc(sizeof(IOAPICState)); + if (!s) + return NULL; + ioapic_state = s; + ioapic_reset(s); + s->id = last_apic_id++; + + io_memory = cpu_register_io_memory(0, ioapic_mem_read, + ioapic_mem_write, s); + cpu_register_physical_memory(0xfec00000, 0x1000, io_memory); + + register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s); + qemu_register_reset(ioapic_reset, s); + + return s; +} diff --git a/hw/i8259.c b/hw/i8259.c index 1be40c909..00d5068ea 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -55,6 +55,9 @@ struct PicState2 { PicState pics[2]; IRQRequestFunc *irq_request; void *irq_request_opaque; + /* IOAPIC callback support */ + SetIRQFunc *alt_irq_func; + void *alt_irq_opaque; }; #if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT) @@ -186,6 +189,9 @@ void pic_set_irq_new(void *opaque, int irq, int level) } #endif pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); + /* used for IOAPIC irqs */ + if (s->alt_irq_func) + s->alt_irq_func(s->alt_irq_opaque, irq, level); pic_update_irq(s); } @@ -546,3 +552,10 @@ PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque) s->pics[1].pics_state = s; return s; } + +void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, + void *alt_irq_opaque) +{ + s->alt_irq_func = alt_irq_func; + s->alt_irq_opaque = alt_irq_opaque; +} diff --git a/hw/pc.c b/hw/pc.c index 29037db7b..f0ae1b964 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -41,6 +41,7 @@ int dummy_refresh_clock; static fdctrl_t *floppy_controller; static RTCState *rtc_state; static PITState *pit; +static IOAPICState *ioapic; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -70,7 +71,6 @@ int cpu_get_pic_interrupt(CPUState *env) { int intno; -#ifdef TARGET_X86_64 intno = apic_get_interrupt(env); if (intno >= 0) { /* set irq request if a PIC irq is still pending */ @@ -78,7 +78,6 @@ int cpu_get_pic_interrupt(CPUState *env) pic_update_irq(isa_pic); return intno; } -#endif /* read the irq from the PIC */ intno = pic_read_irq(isa_pic); return intno; @@ -417,7 +416,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, unsigned long bios_offset, vga_bios_offset; int bios_size, isa_bios_size; PCIBus *pci_bus; - + linux_boot = (kernel_filename != NULL); /* allocate RAM */ @@ -557,10 +556,15 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, register_ioport_read(0x92, 1, 1, ioport92_read, NULL); register_ioport_write(0x92, 1, 1, ioport92_write, NULL); - if (pci_enabled) + if (pci_enabled) { apic_init(cpu_single_env); + ioapic = ioapic_init(); + } isa_pic = pic_init(pic_irq_request, cpu_single_env); pit = pit_init(0x40, 0); + if (pci_enabled) { + pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); + } for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { diff --git a/vl.h b/vl.h index f9fe6a34f..e0bc8b855 100644 --- a/vl.h +++ b/vl.h @@ -695,6 +695,8 @@ extern PicState2 *isa_pic; void pic_set_irq(int irq, int level); void pic_set_irq_new(void *opaque, int irq, int level); PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque); +void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, + void *alt_irq_opaque); int pic_read_irq(PicState2 *s); void pic_update_irq(PicState2 *s); uint32_t pic_intack_read(PicState2 *s); @@ -702,8 +704,12 @@ void pic_info(void); void irq_info(void); /* APIC */ +typedef struct IOAPICState IOAPICState; + int apic_init(CPUState *env); int apic_get_interrupt(CPUState *env); +IOAPICState *ioapic_init(void); +void ioapic_set_irq(void *opaque, int vector, int level); /* i8254.c */ -- cgit v1.2.3 From 45bbbb466cf4a6280076ea5a51f67ef5bedee345 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 20:21:38 +0000 Subject: added overflow exceptions in divisions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1521 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 44 +++++++++++++++++++++++++++++++------------- target-i386/op.c | 21 ++++++++++++++++----- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 2d241a143..c83dbf219 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1209,13 +1209,13 @@ void raise_exception(int exception_index) #ifdef BUGGY_GCC_DIV64 /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we call it from another function */ -uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den) +uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den) { *q_ptr = num / den; return num % den; } -int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den) +int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den) { *q_ptr = num / den; return num % den; @@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den) void helper_divl_EAX_T0(void) { - unsigned int den, q, r; - uint64_t num; + unsigned int den, r; + uint64_t num, q; num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); den = T0; @@ -1238,14 +1238,16 @@ void helper_divl_EAX_T0(void) q = (num / den); r = (num % den); #endif + if (q > 0xffffffff) + raise_exception(EXCP00_DIVZ); EAX = (uint32_t)q; EDX = (uint32_t)r; } void helper_idivl_EAX_T0(void) { - int den, q, r; - int64_t num; + int den, r; + int64_t num, q; num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); den = T0; @@ -1258,6 +1260,8 @@ void helper_idivl_EAX_T0(void) q = (num / den); r = (num % den); #endif + if (q != (int32_t)q) + raise_exception(EXCP00_DIVZ); EAX = (uint32_t)q; EDX = (uint32_t)r; } @@ -3254,8 +3258,8 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) } } -/* XXX: overflow support */ -static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) +/* return TRUE if overflow */ +static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) { uint64_t q, r, a1, a0; int i, qb; @@ -3268,6 +3272,8 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) *plow = q; *phigh = r; } else { + if (a1 >= b) + return 1; /* XXX: use a better algorithm */ for(i = 0; i < 64; i++) { a1 = (a1 << 1) | (a0 >> 63); @@ -3286,9 +3292,11 @@ static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) *plow = a0; *phigh = a1; } + return 0; } -static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) +/* return TRUE if overflow */ +static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) { int sa, sb; sa = ((int64_t)*phigh < 0); @@ -3297,11 +3305,19 @@ static void idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) sb = (b < 0); if (sb) b = -b; - div64(plow, phigh, b); - if (sa ^ sb) + if (div64(plow, phigh, b) != 0) + return 1; + if (sa ^ sb) { + if (*plow > (1ULL << 63)) + return 1; *plow = - *plow; + } else { + if (*plow >= (1ULL << 63)) + return 1; + } if (sa) *phigh = - *phigh; + return 0; } void helper_mulq_EAX_T0(void) @@ -3344,7 +3360,8 @@ void helper_divq_EAX_T0(void) } r0 = EAX; r1 = EDX; - div64(&r0, &r1, T0); + if (div64(&r0, &r1, T0)) + raise_exception(EXCP00_DIVZ); EAX = r0; EDX = r1; } @@ -3357,7 +3374,8 @@ void helper_idivq_EAX_T0(void) } r0 = EAX; r1 = EDX; - idiv64(&r0, &r1, T0); + if (idiv64(&r0, &r1, T0)) + raise_exception(EXCP00_DIVZ); EAX = r0; EDX = r1; } diff --git a/target-i386/op.c b/target-i386/op.c index 3574576ab..142b66263 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void) #endif /* division, flags are undefined */ -/* XXX: add exceptions for overflow */ void OPPROTO op_divb_AL_T0(void) { @@ -339,7 +338,10 @@ void OPPROTO op_divb_AL_T0(void) if (den == 0) { raise_exception(EXCP00_DIVZ); } - q = (num / den) & 0xff; + q = (num / den); + if (q > 0xff) + raise_exception(EXCP00_DIVZ); + q &= 0xff; r = (num % den) & 0xff; EAX = (EAX & ~0xffff) | (r << 8) | q; } @@ -353,7 +355,10 @@ void OPPROTO op_idivb_AL_T0(void) if (den == 0) { raise_exception(EXCP00_DIVZ); } - q = (num / den) & 0xff; + q = (num / den); + if (q != (int8_t)q) + raise_exception(EXCP00_DIVZ); + q &= 0xff; r = (num % den) & 0xff; EAX = (EAX & ~0xffff) | (r << 8) | q; } @@ -367,7 +372,10 @@ void OPPROTO op_divw_AX_T0(void) if (den == 0) { raise_exception(EXCP00_DIVZ); } - q = (num / den) & 0xffff; + q = (num / den); + if (q > 0xffff) + raise_exception(EXCP00_DIVZ); + q &= 0xffff; r = (num % den) & 0xffff; EAX = (EAX & ~0xffff) | q; EDX = (EDX & ~0xffff) | r; @@ -382,7 +390,10 @@ void OPPROTO op_idivw_AX_T0(void) if (den == 0) { raise_exception(EXCP00_DIVZ); } - q = (num / den) & 0xffff; + q = (num / den); + if (q != (int16_t)q) + raise_exception(EXCP00_DIVZ); + q &= 0xffff; r = (num % den) & 0xffff; EAX = (EAX & ~0xffff) | q; EDX = (EDX & ~0xffff) | r; -- cgit v1.2.3 From b1fc0348b1ddc935fca98bddc7ee1c8c64e91f0b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 21:43:15 +0000 Subject: EXTINT delivery mode support for I/O APIC (Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1522 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index 8b33cab37..581aa7b67 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -96,7 +96,6 @@ struct IOAPICState { static int apic_io_memory; static APICState *first_local_apic = NULL; static int last_apic_id = 0; -static IOAPICState *ioapic_state; static void apic_init_ipi(APICState *s); static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); @@ -127,7 +126,7 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, return; case APIC_DM_EXTINT: - /* XXX: implement */ + /* handled in I/O APIC code */ break; default: @@ -754,24 +753,34 @@ int apic_init(CPUState *env) static void ioapic_service(IOAPICState *s) { + uint8_t i; + uint8_t trig_mode; uint8_t vector; + uint8_t delivery_mode; uint32_t mask; uint64_t entry; uint8_t dest; uint8_t dest_mode; + uint8_t polarity; - for (vector = 0; vector < IOAPIC_NUM_PINS; vector++) { - mask = 1 << vector; + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + mask = 1 << i; if (s->irr & mask) { - entry = s->ioredtbl[vector]; + entry = s->ioredtbl[i]; if (!(entry & APIC_LVT_MASKED)) { - if (!((entry >> 15) & 1)) - s->irr &= ~mask; + trig_mode = ((entry >> 15) & 1); dest = entry >> 56; dest_mode = (entry >> 11) & 1; + delivery_mode = (entry >> 8) & 7; + polarity = (entry >> 13) & 1; + if (trig_mode == APIC_TRIGGER_EDGE) + s->irr &= ~mask; + if (delivery_mode == APIC_DM_EXTINT) + vector = pic_read_irq(isa_pic); + else + vector = entry & 0xff; apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode), - (entry >> 8) & 7, entry & 0xff, - (entry >> 13) & 1, (entry >> 15) & 1); + delivery_mode, vector, polarity, trig_mode); } } } @@ -930,10 +939,9 @@ IOAPICState *ioapic_init(void) IOAPICState *s; int io_memory; - s = malloc(sizeof(IOAPICState)); + s = qemu_mallocz(sizeof(IOAPICState)); if (!s) return NULL; - ioapic_state = s; ioapic_reset(s); s->id = last_apic_id++; -- cgit v1.2.3 From a2458627f9d29675ef29d2a3c8c6a3df99bedfb1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Jul 2005 22:39:53 +0000 Subject: ppc64 target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1523 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 11 +++++++---- configure | 6 ++++++ dis-asm.h | 18 ++++++++++++++++++ disas.c | 10 ++++++++++ ppc-dis.c | 9 +++++++-- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/Makefile.target b/Makefile.target index c5a515272..9a6b4d724 100644 --- a/Makefile.target +++ b/Makefile.target @@ -4,6 +4,9 @@ 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 @@ -195,7 +198,7 @@ ifeq ($(TARGET_ARCH), x86_64) LIBOBJS+=helper.o helper2.o endif -ifeq ($(TARGET_ARCH), ppc) +ifeq ($(TARGET_BASE_ARCH), ppc) LIBOBJS+= op_helper.o helper.o endif @@ -225,7 +228,7 @@ endif ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha) LIBOBJS+=alpha-dis.o endif -ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc) +ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc) LIBOBJS+=ppc-dis.o endif ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips) @@ -286,7 +289,7 @@ VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o endif -ifeq ($(TARGET_ARCH), ppc) +ifeq ($(TARGET_BASE_ARCH), ppc) VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o @@ -400,7 +403,7 @@ 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_ARCH), ppc) +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 diff --git a/configure b/configure index c18a9d115..b45408afb 100755 --- a/configure +++ b/configure @@ -611,6 +611,7 @@ target_bigendian="no" [ "$target_cpu" = "sparc" ] && target_bigendian=yes [ "$target_cpu" = "sparc64" ] && target_bigendian=yes [ "$target_cpu" = "ppc" ] && target_bigendian=yes +[ "$target_cpu" = "ppc64" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes target_softmmu="no" if expr $target : '.*-softmmu' > /dev/null ; then @@ -676,6 +677,11 @@ 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 diff --git a/dis-asm.h b/dis-asm.h index 4be6a352d..880baf19e 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -126,6 +126,24 @@ enum bfd_architecture #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 */ diff --git a/disas.c b/disas.c index f713040da..aea8cfee4 100644 --- a/disas.c +++ b/disas.c @@ -179,6 +179,11 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #elif defined(TARGET_PPC) if (cpu_single_env->msr[MSR_LE]) disasm_info.endian = BFD_ENDIAN_LITTLE; +#ifdef TARGET_PPC64 + disasm_info.mach = bfd_mach_ppc64; +#else + disasm_info.mach = bfd_mach_ppc; +#endif print_insn = print_insn_ppc; #elif defined(TARGET_MIPS) print_insn = print_insn_big_mips; @@ -355,6 +360,11 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) #elif defined(TARGET_SPARC) print_insn = print_insn_sparc; #elif defined(TARGET_PPC) +#ifdef TARGET_PPC64 + disasm_info.mach = bfd_mach_ppc64; +#else + disasm_info.mach = bfd_mach_ppc; +#endif print_insn = print_insn_ppc; #elif defined(TARGET_MIPS) print_insn = print_insn_big_mips; diff --git a/ppc-dis.c b/ppc-dis.c index 803b9f554..f6fad8861 100644 --- a/ppc-dis.c +++ b/ppc-dis.c @@ -3084,8 +3084,13 @@ int print_insn_ppc (bfd_vma pc, disassemble_info *info) opc = bfd_getb32(buf); else opc = bfd_getl32(buf); - return print_insn_powerpc (info, opc, pc, - PPC | B32 | M601); + if (info->mach == bfd_mach_ppc64) { + return print_insn_powerpc (info, opc, pc, + PPC | B64); + } else { + return print_insn_powerpc (info, opc, pc, + PPC | B32 | M601); + } } /* Print a PowerPC or POWER instruction. */ -- cgit v1.2.3 From 9529397248a1330cf442e79e4d4bbe912fa7f6e6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 09:05:18 +0000 Subject: open OSS audio device as write only (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1524 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/ossaudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index ee897c9dd..5246ebb78 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -127,7 +127,7 @@ static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd) int fmt, freq, nchannels; const char *dspname = conf.dspname; - fd = open (dspname, O_RDWR | O_NONBLOCK); + fd = open (dspname, O_WRONLY | O_NONBLOCK); if (-1 == fd) { dolog ("Could not initialize audio hardware. Failed to open `%s':\n" "Reason:%s\n", -- cgit v1.2.3 From 90f18422d9d54237cbec19461321a9de1011ad8c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 10:17:31 +0000 Subject: 64 bit virtual addressing fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1525 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 26 deletions(-) diff --git a/exec.c b/exec.c index 08914aecd..178c237fb 100644 --- a/exec.c +++ b/exec.c @@ -83,6 +83,8 @@ typedef struct PhysPageDesc { uint32_t phys_offset; } PhysPageDesc; +/* Note: the VirtPage handling is absolete and will be suppressed + ASAP */ typedef struct VirtPageDesc { /* physical address of code page. It is valid only if 'valid_tag' matches 'virt_valid_tag' */ @@ -113,7 +115,13 @@ static PageDesc *l1_map[L1_SIZE]; PhysPageDesc **l1_phys_map; #if !defined(CONFIG_USER_ONLY) +#if TARGET_LONG_BITS > 32 +#define VIRT_L_BITS 9 +#define VIRT_L_SIZE (1 << VIRT_L_BITS) +static void *l1_virt_map[VIRT_L_SIZE]; +#else static VirtPageDesc *l1_virt_map[L1_SIZE]; +#endif static unsigned int virt_valid_tag; #endif @@ -234,51 +242,113 @@ static inline PhysPageDesc *phys_page_find(unsigned int index) static void tlb_protect_code(CPUState *env, target_ulong addr); static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr); -static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) +static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc) { - VirtPageDesc **lp, *p; - - /* XXX: should not truncate for 64 bit addresses */ #if TARGET_LONG_BITS > 32 - index &= (L1_SIZE - 1); -#endif + void **p, **lp; + + p = l1_virt_map; + lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); + p = *lp; + if (!p) { + if (!alloc) + return NULL; + p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); + *lp = p; + } + lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); + p = *lp; + if (!p) { + if (!alloc) + return NULL; + p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); + *lp = p; + } + lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); + p = *lp; + if (!p) { + if (!alloc) + return NULL; + p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); + *lp = p; + } + lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); + p = *lp; + if (!p) { + if (!alloc) + return NULL; + p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); + *lp = p; + } + lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); + p = *lp; + if (!p) { + if (!alloc) + return NULL; + p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE); + *lp = p; + } + return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1)); +#else + VirtPageDesc *p, **lp; + lp = &l1_virt_map[index >> L2_BITS]; p = *lp; if (!p) { /* allocate if not found */ - p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE); - memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE); + if (!alloc) + return NULL; + p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE); *lp = p; } return p + (index & (L2_SIZE - 1)); +#endif } -static inline VirtPageDesc *virt_page_find(unsigned int index) +static inline VirtPageDesc *virt_page_find(target_ulong index) { - VirtPageDesc *p; + return virt_page_find_alloc(index, 0); +} - p = l1_virt_map[index >> L2_BITS]; - if (!p) - return 0; - return p + (index & (L2_SIZE - 1)); +#if TARGET_LONG_BITS > 32 +static void virt_page_flush_internal(void **p, int level) +{ + int i; + if (level == 0) { + VirtPageDesc *q = (VirtPageDesc *)p; + for(i = 0; i < VIRT_L_SIZE; i++) + q[i].valid_tag = 0; + } else { + level--; + for(i = 0; i < VIRT_L_SIZE; i++) { + if (p[i]) + virt_page_flush_internal(p[i], level); + } + } } +#endif static void virt_page_flush(void) { - int i, j; - VirtPageDesc *p; - virt_valid_tag++; if (virt_valid_tag == 0) { virt_valid_tag = 1; - for(i = 0; i < L1_SIZE; i++) { - p = l1_virt_map[i]; - if (p) { - for(j = 0; j < L2_SIZE; j++) - p[j].valid_tag = 0; +#if TARGET_LONG_BITS > 32 + virt_page_flush_internal(l1_virt_map, 5); +#else + { + int i, j; + VirtPageDesc *p; + for(i = 0; i < L1_SIZE; i++) { + p = l1_virt_map[i]; + if (p) { + for(j = 0; j < L2_SIZE; j++) + p[j].valid_tag = 0; + } } } +#endif } } #else @@ -945,7 +1015,7 @@ void tb_link(TranslationBlock *tb) /* save the code memory mappings (needed to invalidate the code) */ addr = tb->pc & TARGET_PAGE_MASK; - vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); + vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); #ifdef DEBUG_TLB_CHECK if (vp->valid_tag == virt_valid_tag && vp->phys_addr != tb->page_addr[0]) { @@ -963,7 +1033,7 @@ void tb_link(TranslationBlock *tb) if (tb->page_addr[1] != -1) { addr += TARGET_PAGE_SIZE; - vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); + vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); #ifdef DEBUG_TLB_CHECK if (vp->valid_tag == virt_valid_tag && vp->phys_addr != tb->page_addr[1]) { @@ -1572,7 +1642,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); } - index = (vaddr >> 12) & (CPU_TLB_SIZE - 1); + index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); addend -= vaddr; if (prot & PAGE_READ) { env->tlb_read[is_user][index].address = address; @@ -1635,7 +1705,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, original mapping */ VirtPageDesc *vp; - vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS); + vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1); vp->phys_addr = pd; vp->prot = prot; vp->valid_tag = virt_valid_tag; -- cgit v1.2.3 From 108c49b8a20a535219037b522019d9b57051e8e8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 12:55:09 +0000 Subject: allow more than 32 bit of physical memory git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1526 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 61 +++++++++++++++++++++++++++++++++++++----------------- softmmu_template.h | 20 +++++++++--------- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/exec.c b/exec.c index 178c237fb..26abb0f1a 100644 --- a/exec.c +++ b/exec.c @@ -51,6 +51,15 @@ #define MMAP_AREA_START 0x00000000 #define MMAP_AREA_END 0xa8000000 +#if defined(TARGET_SPARC64) +#define TARGET_PHYS_ADDR_SPACE_BITS 41 +#elif defined(TARGET_PPC64) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#else +/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */ +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#endif + TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; @@ -184,8 +193,8 @@ static void page_init(void) #if !defined(CONFIG_USER_ONLY) virt_valid_tag = 1; #endif - l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *)); - memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *)); + l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *)); + memset(l1_phys_map, 0, L1_SIZE * sizeof(void *)); } static inline PageDesc *page_find_alloc(unsigned int index) @@ -213,29 +222,43 @@ static inline PageDesc *page_find(unsigned int index) return p + (index & (L2_SIZE - 1)); } -static inline PhysPageDesc *phys_page_find_alloc(unsigned int index) +static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc) { - PhysPageDesc **lp, *p; + void **lp, **p; - lp = &l1_phys_map[index >> L2_BITS]; + p = (void **)l1_phys_map; +#if TARGET_PHYS_ADDR_SPACE_BITS > 32 + +#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS) +#error unsupported TARGET_PHYS_ADDR_SPACE_BITS +#endif + lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1)); p = *lp; if (!p) { /* allocate if not found */ + if (!alloc) + return NULL; + p = qemu_vmalloc(sizeof(void *) * L1_SIZE); + memset(p, 0, sizeof(void *) * L1_SIZE); + *lp = p; + } +#endif + lp = p + ((index >> L2_BITS) & (L1_SIZE - 1)); + p = *lp; + if (!p) { + /* allocate if not found */ + if (!alloc) + return NULL; p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE); memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE); *lp = p; } - return p + (index & (L2_SIZE - 1)); + return ((PhysPageDesc *)p) + (index & (L2_SIZE - 1)); } -static inline PhysPageDesc *phys_page_find(unsigned int index) +static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) { - PhysPageDesc *p; - - p = l1_phys_map[index >> L2_BITS]; - if (!p) - return 0; - return p + (index & (L2_SIZE - 1)); + return phys_page_find_alloc(index, 0); } #if !defined(CONFIG_USER_ONLY) @@ -1400,7 +1423,7 @@ void tlb_flush_page(CPUState *env, target_ulong addr) TranslationBlock *tb; #if defined(DEBUG_TLB) - printf("tlb_flush_page: 0x%08x\n", addr); + printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr); #endif /* must reset current TB so that interrupts cannot modify the links while we are modifying them */ @@ -1567,7 +1590,7 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end, } static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, - unsigned long start) + unsigned long start) { unsigned long addr; if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) { @@ -1606,7 +1629,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, TranslationBlock *first_tb; unsigned int index; target_ulong address; - unsigned long addend; + target_phys_addr_t addend; int ret; p = phys_page_find(paddr >> TARGET_PAGE_BITS); @@ -1623,7 +1646,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, } } #if defined(DEBUG_TLB) - printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n", + printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n", vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd); #endif @@ -1929,13 +1952,13 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long size, unsigned long phys_offset) { - unsigned long addr, end_addr; + target_phys_addr_t addr, end_addr; PhysPageDesc *p; size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; end_addr = start_addr + size; for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { - p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS); + p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); p->phys_offset = phys_offset; if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) phys_offset += TARGET_PAGE_SIZE; diff --git a/softmmu_template.h b/softmmu_template.h index 507672693..558bb8be8 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -48,7 +48,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user, void *retaddr); -static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, +static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, target_ulong tlb_addr) { DATA_TYPE res; @@ -76,7 +76,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE res; int index; target_ulong tlb_addr; - unsigned long physaddr; + target_phys_addr_t physaddr; void *retaddr; /* test if there is match for unaligned or IO access */ @@ -99,7 +99,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, is_user, retaddr); } else { /* unaligned access in the same page */ - res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr); } } else { /* the page is not in the TLB : fill it */ @@ -117,7 +117,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, { DATA_TYPE res, res1, res2; int index, shift; - unsigned long physaddr; + target_phys_addr_t physaddr; target_ulong tlb_addr, addr1, addr2; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); @@ -148,7 +148,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, res = (DATA_TYPE)res; } else { /* unaligned/aligned access in the same page */ - res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); + res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr); } } else { /* the page is not in the TLB : fill it */ @@ -165,7 +165,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user, void *retaddr); -static inline void glue(io_write, SUFFIX)(unsigned long physaddr, +static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, DATA_TYPE val, target_ulong tlb_addr, void *retaddr) @@ -192,7 +192,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, int is_user) { - unsigned long physaddr; + target_phys_addr_t physaddr; target_ulong tlb_addr; void *retaddr; int index; @@ -215,7 +215,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, is_user, retaddr); } else { /* aligned/unaligned access in the same page */ - glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val); + glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val); } } else { /* the page is not in the TLB : fill it */ @@ -231,7 +231,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user, void *retaddr) { - unsigned long physaddr; + target_phys_addr_t physaddr; target_ulong tlb_addr; int index, i; @@ -259,7 +259,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, } } else { /* aligned/unaligned access in the same page */ - glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val); + glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val); } } else { /* the page is not in the TLB : fill it */ -- cgit v1.2.3 From 09d459a1db9b19d1ff66e98620f1ea16aba379de Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 14:14:53 +0000 Subject: temporary work around for 16 bit code in kqemu git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1527 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exec-all.h b/exec-all.h index b7c0ad860..5e809b0b7 100644 --- a/exec-all.h +++ b/exec-all.h @@ -615,7 +615,8 @@ static inline int kqemu_is_ok(CPUState *env) (env->eflags & IOPL_MASK) != IOPL_MASK && (env->cr[0] & CR0_PE_MASK) && (env->eflags & IF_MASK) && - !(env->eflags & VM_MASK)); + !(env->eflags & VM_MASK) && + (env->ldt.limit == 0 || env->ldt.limit == 0x27)); } #endif -- cgit v1.2.3 From 57e4c06ed749e14c7c183996883dee27c23a0ade Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 14:33:17 +0000 Subject: fscale fix (bug noticed by Kuwanger, fix by malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1528 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 1 + target-i386/helper.c | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index a3bbea999..b1145017d 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -337,6 +337,7 @@ static inline void stfl(target_ulong ptr, float v) #define atan2 atan2l #define floor floorl #define ceil ceill +#define ldexp ldexpl #else #define floatx_to_int32 float64_to_int32 #define floatx_to_int64 float64_to_int64 diff --git a/target-i386/helper.c b/target-i386/helper.c index c83dbf219..01b663f38 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2888,11 +2888,7 @@ void helper_frndint(void) void helper_fscale(void) { - CPU86_LDouble fpsrcop, fptemp; - - fpsrcop = 2.0; - fptemp = pow(fpsrcop,ST1); - ST0 *= fptemp; + ST0 = ldexp (ST0, (int)(ST1)); } void helper_fsin(void) -- cgit v1.2.3 From db6e6ed77ec38506ffe842c8d419aebbb074f967 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 14:56:40 +0000 Subject: do not export fls_bit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1529 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/apic.c b/hw/apic.c index 581aa7b67..a66e03296 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -178,7 +178,7 @@ uint8_t cpu_get_apic_tpr(CPUX86State *env) return s->tpr >> 4; } -int fls_bit(int value) +static int fls_bit(int value) { unsigned int ret = 0; -- cgit v1.2.3 From 90cb94935228cc064f99fe98e70a8ea5deefb689 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 15:11:38 +0000 Subject: s390 bits git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1530 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 17 +++++++++++++++++ dyngen-exec.h | 1 + vl.c | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/cpu-exec.c b/cpu-exec.c index c7cd60788..e7f4322ef 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1280,6 +1280,23 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) &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 diff --git a/dyngen-exec.h b/dyngen-exec.h index 2dc948bf4..946347d6c 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -218,6 +218,7 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #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") diff --git a/vl.c b/vl.c index 13b07c842..c3894b801 100644 --- a/vl.c +++ b/vl.c @@ -532,6 +532,15 @@ int64_t cpu_get_real_ticks(void) return val; } +#elif defined(__s390__) + +int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); + return val; +} + #else #error unsupported CPU #endif -- cgit v1.2.3 From 0f4c64157fb50cb86535d62779ca1b05f323f77a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 18:10:56 +0000 Subject: kqemu info git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1531 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/monitor.c b/monitor.c index 4e6f6faba..297c0a42d 100644 --- a/monitor.c +++ b/monitor.c @@ -885,6 +885,20 @@ static void mem_info(void) } #endif +static void do_info_kqemu(void) +{ +#ifdef USE_KQEMU + int val; + val = 0; + if (cpu_single_env) + val = cpu_single_env->kqemu_enabled; + term_printf("kqemu is %s\n", val ? "enabled" : "disabled"); +#else + term_printf("kqemu support is not compiled\n"); +#endif +} + + static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -959,6 +973,8 @@ static term_cmd_t info_cmds[] = { #endif { "jit", "", do_info_jit, "", "show dynamic compiler info", }, + { "kqemu", "", do_info_kqemu, + "", "show kqemu information", }, { NULL, NULL, }, }; -- cgit v1.2.3 From 5cedb46460fab4a391b702ff679f27eacca342cf Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 18:14:03 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1532 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + VERSION | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.cvsignore b/.cvsignore index ca88a6662..6d6858b65 100644 --- a/.cvsignore +++ b/.cvsignore @@ -6,6 +6,7 @@ i386 i386-softmmu i386-user ppc-softmmu +ppc64-softmmu ppc-user qemu-doc.html qemu-tech.html diff --git a/VERSION b/VERSION index bcaffe19b..7deb86fee 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.0 \ No newline at end of file +0.7.1 \ No newline at end of file -- cgit v1.2.3 From 93856aac7b554dfb4622ec31c986bb0ff0be3570 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 18:44:35 +0000 Subject: update tarbin target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1533 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 74b1a94eb..87360906d 100644 --- a/Makefile +++ b/Makefile @@ -112,6 +112,7 @@ tarbin: $(bindir)/qemu-system-ppc \ $(bindir)/qemu-system-sparc \ $(bindir)/qemu-system-x86_64 \ + $(bindir)/qemu-system-mips \ $(bindir)/qemu-i386 \ $(bindir)/qemu-arm \ $(bindir)/qemu-sparc \ -- cgit v1.2.3 From f5a8510c7cac37c83acd5faf88c537551e6c21f9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Jul 2005 18:44:56 +0000 Subject: copyright git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1534 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- qemu-img.c | 2 +- vl.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 856147f04..622d06edf 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -973,7 +973,7 @@ void cpu_loop(CPUPPCState *env) void usage(void) { - printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n" "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" diff --git a/qemu-img.c b/qemu-img.c index 9fb988757..3a18c9325 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -127,7 +127,7 @@ static void format_print(void *opaque, const char *name) void help(void) { - printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004 Fabrice Bellard\n" + printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2005 Fabrice Bellard\n" "usage: qemu-img command [command options]\n" "QEMU disk image utility\n" "\n" diff --git a/vl.c b/vl.c index c3894b801..354968d61 100644 --- a/vl.c +++ b/vl.c @@ -2792,7 +2792,7 @@ int main_loop(void) void help(void) { - printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" + printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" "\n" "'disk_image' is a raw hard image image for IDE hard disk 0\n" -- cgit v1.2.3 From e99f9060555b67518fe6a3d8303d162b0c4f93a3 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 28 Jul 2005 21:45:38 +0000 Subject: FreeBSD fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1536 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index b45408afb..19a0ec900 100755 --- a/configure +++ b/configure @@ -99,7 +99,7 @@ mingw32="yes" FreeBSD) bsd="yes" oss="yes" -if [ "$cpu" = "i386" ] ; then +if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" fi ;; -- cgit v1.2.3 From 6cc721cf4214a088538318083b27ed67a5159f3e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 28 Jul 2005 22:27:28 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1537 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 17072a728..526bd4b73 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -113,6 +113,7 @@ qemu linux.img Linux should boot and give you a prompt. +@node sec_invocation @section Invocation @example @@ -254,7 +255,7 @@ Then @file{dir} can be accessed in @file{\\smbserver\qemu}. Note that a SAMBA server must be installed on the host OS in @file{/usr/sbin/smbd}. QEMU was tested succesfully with smbd version -2.2.7a from the Red Hat 9. +2.2.7a from the Red Hat 9 and version 3.0.10-1.fc3 from Fedora Core 3. @item -redir [tcp|udp]:host-port:[guest-host]:guest-port @@ -912,6 +913,23 @@ option to enable a specific workaround. After Windows 2000 is installed, you no longer need this option (this option slows down the IDE transfers). +@subsubsection Windows 2000 shutdown + +Windows 2000 cannot automatically shutdown in QEMU although Windows 98 +can. It comes from the fact that Windows 2000 does not automatically +use the APM driver provided by the BIOS. + +In order to correct that, do the following (thanks to Struan +Bartlett): go to the Control Panel => Add/Remove Hardware & Next => +Add/Troubleshoot a device => Add a new device & Next => No, select the +hardware from a list & Next => NT Apm/Legacy Support & Next => Next +(again) a few times. Now the driver is installed and Windows 2000 now +correctly instructs QEMU to shutdown at the appropriate moment. + +@subsubsection Share a directory between Unix and Windows + +See @ref{sec_invocation} about the help of the option @option{-smb}. + @subsubsection Windows XP security problems Some releases of Windows XP install correctly but give a security -- cgit v1.2.3 From 92510b8cf5a18e1671633fddb53599fb02936302 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 6 Aug 2005 09:14:32 +0000 Subject: ide PCI ident fix, aka FreeBSD/amd64 bug fix (Jung-uk Kim) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1538 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ide.c b/hw/ide.c index f5fd028b8..28ed5abbe 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2330,6 +2330,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) pci_conf[0x01] = 0x80; pci_conf[0x02] = 0x10; pci_conf[0x03] = 0x70; + pci_conf[0x09] = 0x80; // legacy ATA mode pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage pci_conf[0x0e] = 0x00; // header_type -- cgit v1.2.3 From 1f3358c87d50a6f10aea4d22a38fbe421f5e3873 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 15 Aug 2005 16:33:12 +0000 Subject: CLFLUSH cpuid fix (aka Linux 2.6 hang on x86_64) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1539 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 01b663f38..fd0443046 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1307,7 +1307,7 @@ void helper_cpuid(void) break; case 1: EAX = env->cpuid_version; - EBX = 0; + EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ ECX = env->cpuid_ext_features; EDX = env->cpuid_features; break; -- cgit v1.2.3 From bc3fc8dac089f5fa06ea78d9c433a3567efd240a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 15 Aug 2005 16:33:56 +0000 Subject: 16/32 stack operations fix on x86_64 (aka win2000 startup bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1540 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/op.c b/target-i386/op.c index 142b66263..637004579 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -865,7 +865,7 @@ void OPPROTO op_decq_ECX(void) void op_addl_A0_SS(void) { - A0 += (long)env->segs[R_SS].base; + A0 = (uint32_t)(A0 + env->segs[R_SS].base); } void op_subl_A0_2(void) -- cgit v1.2.3 From 6688bc6d04d1249643eb1494794aa649194c9fbb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:23:39 +0000 Subject: cscope rule git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1541 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 87360906d..332058642 100644 --- a/Makefile +++ b/Makefile @@ -84,6 +84,11 @@ test speed test2: all TAGS: etags *.[ch] tests/*.[ch] +cscope: + rm -f ./cscope.* + find . -name "*.[ch]" -print > ./cscope.files + cscope -b + # documentation %.html: %.texi texi2html -monolithic -number $< -- cgit v1.2.3 From ff7b8f5b0f05e632561624c69f9a3557d633c2ae Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:24:05 +0000 Subject: ram_addr_t type for ram offsets git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1542 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpu-defs.h b/cpu-defs.h index 83d1748e2..912133ee6 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -66,6 +66,9 @@ typedef uint64_t target_phys_addr_t; #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 */ -- cgit v1.2.3 From 04c504cc4fb6b600e597bc6a869d478d3b7d3db4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:24:50 +0000 Subject: use ram_addr_t git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1543 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index d50f5a2c6..4f1f7726a 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -708,7 +708,6 @@ extern uint8_t *phys_ram_dirty; #define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */ #define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ #define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) -#define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */ #define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); @@ -743,27 +742,29 @@ void stl_phys(target_phys_addr_t addr, uint32_t val); int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write); -#define VGA_DIRTY_FLAG 0x01 +#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(target_ulong addr) +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(target_ulong addr, +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(target_ulong addr) +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(target_ulong start, target_ulong end, +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, ...)); -- cgit v1.2.3 From 3a7d929e62d82f48b4b93f8691007ae8d9daec57 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:26:42 +0000 Subject: merge self modifying code handling in dirty ram page mecanism git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1544 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 238 ++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 118 insertions(+), 120 deletions(-) diff --git a/exec.c b/exec.c index 26abb0f1a..c75c23eb0 100644 --- a/exec.c +++ b/exec.c @@ -262,8 +262,10 @@ static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) } #if !defined(CONFIG_USER_ONLY) -static void tlb_protect_code(CPUState *env, target_ulong addr); -static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr); +static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, + target_ulong vaddr); +static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, + target_ulong vaddr); static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc) { @@ -945,7 +947,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, TranslationBlock *last_first_tb; tb->page_addr[n] = page_addr; - p = page_find(page_addr >> TARGET_PAGE_BITS); + p = page_find_alloc(page_addr >> TARGET_PAGE_BITS); tb->page_next[n] = p->first_tb; last_first_tb = p->first_tb; p->first_tb = (TranslationBlock *)((long)tb | n); @@ -981,7 +983,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, target_ulong virt_addr; virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS); - tlb_protect_code(cpu_single_env, virt_addr); + tlb_protect_code(cpu_single_env, page_addr, virt_addr); } #endif @@ -1473,50 +1475,44 @@ static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr) { if (addr == (tlb_entry->address & (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && - (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE && - (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) { - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE; + (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; } } /* update the TLBs so that writes to code in the virtual page 'addr' can be detected */ -static void tlb_protect_code(CPUState *env, target_ulong addr) +static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, + target_ulong vaddr) { int i; - addr &= TARGET_PAGE_MASK; - i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_protect_code1(&env->tlb_write[0][i], addr); - tlb_protect_code1(&env->tlb_write[1][i], addr); + vaddr &= TARGET_PAGE_MASK; + i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + tlb_protect_code1(&env->tlb_write[0][i], vaddr); + tlb_protect_code1(&env->tlb_write[1][i], vaddr); + + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG; +#ifdef USE_KQEMU + if (env->kqemu_enabled) { + kqemu_set_notdirty(env, ram_addr); + } +#endif + #if !defined(CONFIG_SOFTMMU) /* NOTE: as we generated the code for this page, it is already at least readable */ - if (addr < MMAP_AREA_END) - mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ); + if (vaddr < MMAP_AREA_END) + mprotect((void *)vaddr, TARGET_PAGE_SIZE, PROT_READ); #endif } -static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, - unsigned long phys_addr) -{ - if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE && - ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) { - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; - } -} - /* update the TLB so that writes in physical page 'phys_addr' are no longer - tested self modifying code */ -static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr) + tested for self modifying code */ +static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, + target_ulong vaddr) { - int i; - - phys_addr &= TARGET_PAGE_MASK; - phys_addr += (long)phys_ram_base; - i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr); - tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG; } static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, @@ -1531,7 +1527,7 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, } } -void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end, +void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, int dirty_flags) { CPUState *env; @@ -1552,6 +1548,12 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end, p[i] &= mask; env = cpu_single_env; +#ifdef USE_KQEMU + if (env->kqemu_enabled) { + for(i = 0; i < len; i++) + kqemu_set_notdirty(env, (unsigned long)i << TARGET_PAGE_BITS); + } +#endif /* we modify the TLB cache so that the dirty bit will be set again when accessing the range */ start1 = start + (unsigned long)phys_ram_base; @@ -1589,6 +1591,29 @@ void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end, #endif } +static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) +{ + ram_addr_t ram_addr; + + if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + ram_addr = (tlb_entry->address & TARGET_PAGE_MASK) + + tlb_entry->addend - (unsigned long)phys_ram_base; + if (!cpu_physical_memory_is_dirty(ram_addr)) { + tlb_entry->address |= IO_MEM_NOTDIRTY; + } + } +} + +/* update the TLB according to the current state of the dirty bits */ +void cpu_tlb_update_dirty(CPUState *env) +{ + int i; + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_update_dirty(&env->tlb_write[0][i]); + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_update_dirty(&env->tlb_write[1][i]); +} + static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, unsigned long start) { @@ -1626,28 +1651,20 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, { PhysPageDesc *p; unsigned long pd; - TranslationBlock *first_tb; unsigned int index; target_ulong address; target_phys_addr_t addend; int ret; p = phys_page_find(paddr >> TARGET_PAGE_BITS); - first_tb = NULL; if (!p) { pd = IO_MEM_UNASSIGNED; } else { - PageDesc *p1; pd = p->phys_offset; - if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) { - /* NOTE: we also allocate the page at this stage */ - p1 = page_find_alloc(pd >> TARGET_PAGE_BITS); - first_tb = p1->first_tb; - } } #if defined(DEBUG_TLB) - printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n", - vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd); + printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n", + vaddr, paddr, prot, is_user, is_softmmu, pd); #endif ret = 0; @@ -1679,18 +1696,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, /* ROM: access is ignored (same as unassigned) */ env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM; env->tlb_write[is_user][index].addend = addend; - } else - /* XXX: the PowerPC code seems not ready to handle - self modifying code with DCBI */ -#if defined(TARGET_HAS_SMC) || 1 - if (first_tb) { - /* if code is present, we use a specific memory - handler. It works only for physical memory access */ - env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE; - env->tlb_write[is_user][index].addend = addend; - } else -#endif - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd)) { env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY; env->tlb_write[is_user][index].addend = addend; @@ -1986,75 +1992,66 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = { unassigned_mem_writeb, }; -/* self modifying code support in soft mmu mode : writing to a page - containing code comes to these functions */ - -static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { - unsigned long phys_addr; - - phys_addr = addr - (unsigned long)phys_ram_base; + unsigned long ram_addr; + int dirty_flags; + ram_addr = addr - (unsigned long)phys_ram_base; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(phys_addr, 1); + tb_invalidate_phys_page_fast(ram_addr, 1); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; #endif + } stb_p((uint8_t *)(long)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; + /* we set the page as dirty only if the code has been flushed */ + if (dirty_flags & CODE_DIRTY_FLAG) + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { - unsigned long phys_addr; - - phys_addr = addr - (unsigned long)phys_ram_base; + unsigned long ram_addr; + int dirty_flags; + ram_addr = addr - (unsigned long)phys_ram_base; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(phys_addr, 2); + tb_invalidate_phys_page_fast(ram_addr, 2); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; #endif + } stw_p((uint8_t *)(long)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; + /* we set the page as dirty only if the code has been flushed */ + if (dirty_flags & CODE_DIRTY_FLAG) + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { - unsigned long phys_addr; - - phys_addr = addr - (unsigned long)phys_ram_base; + unsigned long ram_addr; + int dirty_flags; + ram_addr = addr - (unsigned long)phys_ram_base; + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; + if (!(dirty_flags & CODE_DIRTY_FLAG)) { #if !defined(CONFIG_USER_ONLY) - tb_invalidate_phys_page_fast(phys_addr, 4); + tb_invalidate_phys_page_fast(ram_addr, 4); + dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS]; #endif + } stl_p((uint8_t *)(long)addr, val); - phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; + /* we set the page as dirty only if the code has been flushed */ + if (dirty_flags & CODE_DIRTY_FLAG) + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } -static CPUReadMemoryFunc *code_mem_read[3] = { +static CPUReadMemoryFunc *error_mem_read[3] = { NULL, /* never used */ NULL, /* never used */ NULL, /* never used */ }; -static CPUWriteMemoryFunc *code_mem_write[3] = { - code_mem_writeb, - code_mem_writew, - code_mem_writel, -}; - -static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - stb_p((uint8_t *)(long)addr, val); - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); -} - -static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - stw_p((uint8_t *)(long)addr, val); - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); -} - -static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - stl_p((uint8_t *)(long)addr, val); - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); -} - static CPUWriteMemoryFunc *notdirty_mem_write[3] = { notdirty_mem_writeb, notdirty_mem_writew, @@ -2063,14 +2060,14 @@ static CPUWriteMemoryFunc *notdirty_mem_write[3] = { static void io_mem_init(void) { - cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL); cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL); - cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL); - cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL); + cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL); io_mem_nb = 5; /* alloc dirty bits array */ phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); + memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); } /* mem_read and mem_write are arrays of functions containing the @@ -2182,7 +2179,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } if (is_write) { - if ((pd & ~TARGET_PAGE_MASK) != 0) { + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit read access */ @@ -2206,14 +2203,15 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, /* RAM case */ ptr = phys_ram_base + addr1; memcpy(ptr, buf, l); - /* invalidate code */ - tb_invalidate_phys_page_range(addr1, addr1 + l, 0); - /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + l, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; + } } } else { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && - (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { @@ -2261,8 +2259,7 @@ uint32_t ldl_phys(target_phys_addr_t addr) pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && - (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); @@ -2292,7 +2289,7 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) != 0) { + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); } else { @@ -2303,7 +2300,6 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) } /* warning: addr must be aligned */ -/* XXX: optimize code invalidation test */ void stl_phys(target_phys_addr_t addr, uint32_t val) { int io_index; @@ -2318,7 +2314,7 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) != 0) { + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); } else { @@ -2327,10 +2323,12 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) /* RAM case */ ptr = phys_ram_base + addr1; stl_p(ptr, val); - /* invalidate code */ - tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); - /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; + if (!cpu_physical_memory_is_dirty(addr1)) { + /* invalidate code */ + tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); + /* set dirty bit */ + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; + } } } -- cgit v1.2.3 From aa0629734011106231e02fca3c19e9e0e24c02be Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:30:12 +0000 Subject: kqemu fixes - new API support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1545 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/kqemu.c b/kqemu.c index 4d152502e..9a0f05b17 100644 --- a/kqemu.c +++ b/kqemu.c @@ -40,6 +40,7 @@ #ifdef USE_KQEMU #define DEBUG +//#define PROFILE #include #include @@ -49,6 +50,10 @@ #ifndef KQEMU_RET_SYSCALL #define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */ #endif +#ifndef KQEMU_MAX_RAM_PAGES_TO_UPDATE +#define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512 +#define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1) +#endif #ifdef _WIN32 #define KQEMU_DEVICE "\\\\.\\kqemu" @@ -69,6 +74,8 @@ int kqemu_fd = KQEMU_INVALID_FD; int kqemu_allowed = 1; unsigned long *pages_to_flush; unsigned int nb_pages_to_flush; +unsigned long *ram_pages_to_update; +unsigned int nb_ram_pages_to_update; extern uint32_t **l1_phys_map; #define cpuid(index, eax, ebx, ecx, edx) \ @@ -167,11 +174,19 @@ int kqemu_init(CPUState *env) if (!pages_to_flush) goto fail; + ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE * + sizeof(unsigned long)); + if (!ram_pages_to_update) + goto fail; + init.ram_base = phys_ram_base; init.ram_size = phys_ram_size; init.ram_dirty = phys_ram_dirty; init.phys_to_ram_map = l1_phys_map; init.pages_to_flush = pages_to_flush; +#if KQEMU_VERSION >= 0x010200 + init.ram_pages_to_update = ram_pages_to_update; +#endif #ifdef _WIN32 ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init), NULL, 0, &temp, NULL) == TRUE ? 0 : -1; @@ -188,6 +203,7 @@ int kqemu_init(CPUState *env) kqemu_update_cpuid(env); env->kqemu_enabled = 1; nb_pages_to_flush = 0; + nb_ram_pages_to_update = 0; return 0; } @@ -214,6 +230,19 @@ void kqemu_flush(CPUState *env, int global) nb_pages_to_flush = KQEMU_FLUSH_ALL; } +void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr) +{ +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", ram_addr); + } +#endif + if (nb_ram_pages_to_update >= KQEMU_MAX_RAM_PAGES_TO_UPDATE) + nb_ram_pages_to_update = KQEMU_RAM_PAGES_UPDATE_ALL; + else + ram_pages_to_update[nb_ram_pages_to_update++] = ram_addr; +} + struct fpstate { uint16_t fpuc; uint16_t dummy1; @@ -404,6 +433,103 @@ static int do_syscall(CPUState *env, return 2; } +#ifdef PROFILE + +#define PC_REC_SIZE 1 +#define PC_REC_HASH_BITS 16 +#define PC_REC_HASH_SIZE (1 << PC_REC_HASH_BITS) + +typedef struct PCRecord { + unsigned long pc; + int64_t count; + struct PCRecord *next; +} PCRecord; + +PCRecord *pc_rec_hash[PC_REC_HASH_SIZE]; +int nb_pc_records; + +void kqemu_record_pc(unsigned long pc) +{ + unsigned long h; + PCRecord **pr, *r; + + h = pc / PC_REC_SIZE; + h = h ^ (h >> PC_REC_HASH_BITS); + h &= (PC_REC_HASH_SIZE - 1); + pr = &pc_rec_hash[h]; + for(;;) { + r = *pr; + if (r == NULL) + break; + if (r->pc == pc) { + r->count++; + return; + } + pr = &r->next; + } + r = malloc(sizeof(PCRecord)); + r->count = 1; + r->pc = pc; + r->next = NULL; + *pr = r; + nb_pc_records++; +} + +int pc_rec_cmp(const void *p1, const void *p2) +{ + PCRecord *r1 = *(PCRecord **)p1; + PCRecord *r2 = *(PCRecord **)p2; + if (r1->count < r2->count) + return 1; + else if (r1->count == r2->count) + return 0; + else + return -1; +} + +void kqemu_record_dump(void) +{ + PCRecord **pr, *r; + int i, h; + FILE *f; + int64_t total, sum; + + pr = malloc(sizeof(PCRecord *) * nb_pc_records); + i = 0; + total = 0; + for(h = 0; h < PC_REC_HASH_SIZE; h++) { + for(r = pc_rec_hash[h]; r != NULL; r = r->next) { + pr[i++] = r; + total += r->count; + } + } + qsort(pr, nb_pc_records, sizeof(PCRecord *), pc_rec_cmp); + + f = fopen("/tmp/kqemu.stats", "w"); + if (!f) { + perror("/tmp/kqemu.stats"); + exit(1); + } + fprintf(f, "total: %lld\n", total); + sum = 0; + for(i = 0; i < nb_pc_records; i++) { + r = pr[i]; + sum += r->count; + fprintf(f, "%08lx: %lld %0.2f%% %0.2f%%\n", + r->pc, + r->count, + (double)r->count / (double)total * 100.0, + (double)sum / (double)total * 100.0); + } + fclose(f); + free(pr); +} +#else +void kqemu_record_dump(void) +{ +} +#endif + int kqemu_cpu_exec(CPUState *env) { struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; @@ -447,6 +573,11 @@ int kqemu_cpu_exec(CPUState *env) kenv->cpl = 3; kenv->nb_pages_to_flush = nb_pages_to_flush; nb_pages_to_flush = 0; +#if KQEMU_VERSION >= 0x010200 + kenv->user_only = 1; + kenv->nb_ram_pages_to_update = nb_ram_pages_to_update; +#endif + nb_ram_pages_to_update = 0; if (!(kenv->cr0 & CR0_TS_MASK)) { if (env->cpuid_features & CPUID_FXSR) @@ -494,6 +625,49 @@ int kqemu_cpu_exec(CPUState *env) env->cr[2] = kenv->cr2; env->dr[6] = kenv->dr6; +#if KQEMU_VERSION >= 0x010200 + if (kenv->nb_ram_pages_to_update > 0) { + cpu_tlb_update_dirty(env); + } +#endif + + /* restore the hidden flags */ + { + unsigned int new_hflags; +#ifdef TARGET_X86_64 + if ((env->hflags & HF_LMA_MASK) && + (env->segs[R_CS].flags & DESC_L_MASK)) { + /* long mode */ + new_hflags = HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK; + } else +#endif + { + /* legacy / compatibility case */ + new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - HF_CS32_SHIFT); + new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) + >> (DESC_B_SHIFT - HF_SS32_SHIFT); + if (!(env->cr[0] & CR0_PE_MASK) || + (env->eflags & VM_MASK) || + !(env->hflags & HF_CS32_MASK)) { + /* XXX: try to avoid this test. The problem comes from the + fact that is real mode or vm86 mode we only modify the + 'base' and 'selector' fields of the segment cache to go + faster. A solution may be to force addseg to one in + translate-i386.c. */ + new_hflags |= HF_ADDSEG_MASK; + } else { + new_hflags |= ((env->segs[R_DS].base | + env->segs[R_ES].base | + env->segs[R_SS].base) != 0) << + HF_ADDSEG_SHIFT; + } + } + env->hflags = (env->hflags & + ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) | + new_hflags; + } + #ifdef DEBUG if (loglevel & CPU_LOG_INT) { fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret); @@ -537,6 +711,14 @@ int kqemu_cpu_exec(CPUState *env) #endif return 0; } else if (ret == KQEMU_RET_SOFTMMU) { +#ifdef PROFILE + kqemu_record_pc(env->eip + env->segs[R_CS].base); +#endif +#ifdef DEBUG + if (loglevel & CPU_LOG_INT) { + cpu_dump_state(env, logfile, fprintf, 0); + } +#endif return 2; } else { cpu_dump_state(env, stderr, fprintf, 0); -- cgit v1.2.3 From 5e6ad6f90eaab923b2d949882751075c5e3291e0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:30:40 +0000 Subject: kqemu profiling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1546 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 3 +++ vl.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/monitor.c b/monitor.c index 297c0a42d..1ff9bde6e 100644 --- a/monitor.c +++ b/monitor.c @@ -251,6 +251,9 @@ static void do_info_history (void) static void do_quit(void) { +#ifdef USE_KQEMU + kqemu_record_dump(); +#endif exit(0); } diff --git a/vl.h b/vl.h index e0bc8b855..31d05b6b5 100644 --- a/vl.h +++ b/vl.h @@ -878,4 +878,6 @@ const char *readline_get_history(unsigned int index); void readline_start(const char *prompt, int is_password, ReadLineFunc *readline_func, void *opaque); +void kqemu_record_dump(void); + #endif /* VL_H */ -- cgit v1.2.3 From 81eea5ebb65a987cb376934e86b29c7713ac67f5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:30:54 +0000 Subject: comment git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1547 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sb16.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sb16.c b/hw/sb16.c index 33026febb..bca5795ea 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -540,7 +540,7 @@ static void command (SB16State *s, uint8_t cmd) return; warn: - dolog ("warning: command %#x,%d is not trully understood yet\n", + dolog ("warning: command %#x,%d is not truly understood yet\n", cmd, s->needed_bytes); s->cmd = cmd; return; -- cgit v1.2.3 From 2c8e03018571246e9c332a68ad7c89d2949155ab Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:32:43 +0000 Subject: RSP update fix for x86_64 in iret git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1548 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index fd0443046..c41cbb727 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2012,7 +2012,6 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) #endif sp_mask = get_sp_mask(env->segs[R_SS].flags); sp = ESP; - /* XXX: ssp is zero in 64 bit ? */ ssp = env->segs[R_SS].base; new_eflags = 0; /* avoid warning */ #ifdef TARGET_X86_64 @@ -2145,7 +2144,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) cpu_x86_set_cpl(env, rpl); sp = new_esp; #ifdef TARGET_X86_64 - if (shift == 2) + if (env->hflags & HF_CS64_MASK) sp_mask = -1; else #endif -- cgit v1.2.3 From 4b7df22f91dd314bd99f9f8f163600587434341f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:37:35 +0000 Subject: added kqemu_set_notdirty() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1549 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/exec-all.h b/exec-all.h index 5e809b0b7..0f7921465 100644 --- a/exec-all.h +++ b/exec-all.h @@ -572,7 +572,6 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) /* NOTE: this function can trigger an exception */ /* NOTE2: the returned address is not exactly the physical address: it is the offset relative to phys_ram_base */ -/* XXX: i386 target specific */ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) { int is_user, index, pd; @@ -607,6 +606,7 @@ int kqemu_init(CPUState *env); int kqemu_cpu_exec(CPUState *env); void kqemu_flush_page(CPUState *env, target_ulong addr); void kqemu_flush(CPUState *env, int global); +void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr); static inline int kqemu_is_ok(CPUState *env) { @@ -615,8 +615,11 @@ static inline int kqemu_is_ok(CPUState *env) (env->eflags & IOPL_MASK) != IOPL_MASK && (env->cr[0] & CR0_PE_MASK) && (env->eflags & IF_MASK) && - !(env->eflags & VM_MASK) && - (env->ldt.limit == 0 || env->ldt.limit == 0x27)); + !(env->eflags & VM_MASK) +#if 1 + && (env->ldt.limit == 0 || env->ldt.limit == 0x27) +#endif + ); } #endif -- cgit v1.2.3 From c96a29cdef7659ae7c4a816206915896a8f69e39 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:40:49 +0000 Subject: Fix MIPS counter / compare interrupt (Ralf Baechle git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1550 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index ca135ac39..bb7742f8d 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -72,7 +72,8 @@ void cpu_mips_store_count (CPUState *env, uint32_t value) void cpu_mips_store_compare (CPUState *env, uint32_t value) { cpu_mips_update_count(env, cpu_mips_get_count(env), value); - pic_set_irq(5, 0); + cpu_single_env->CP0_Cause &= ~0x00008000; + cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); } static void mips_timer_cb (void *opaque) @@ -86,7 +87,8 @@ static void mips_timer_cb (void *opaque) } #endif cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); - pic_set_irq(5, 1); + cpu_single_env->CP0_Cause |= 0x00008000; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); } void cpu_mips_clock_init (CPUState *env) -- cgit v1.2.3 From 697584ab24c8aa4f9b8162a12993523bb2450af0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:41:56 +0000 Subject: Add i8259 PIT to MIPS (Ralf Baechle git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1551 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++-- hw/mips_r4k.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index 9a6b4d724..ea0f5c8fd 100644 --- a/Makefile.target +++ b/Makefile.target @@ -295,8 +295,8 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o endif ifeq ($(TARGET_ARCH), mips) -VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8259.o -#VL_OBJS+= #ide.o pckbd.o i8254.o fdc.o m48t59.o +VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.o +#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index bb7742f8d..bf3376d4f 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -7,6 +7,8 @@ extern FILE *logfile; +static PITState *pit; + static void pic_irq_request(void *opaque, int level) { if (level) { @@ -242,6 +244,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, isa_mem_base = 0x10000000; isa_pic = pic_init(pic_irq_request, cpu_single_env); + pit = pit_init(0x40, 0); serial_init(0x3f8, 4, serial_hds[0]); vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0, 0); -- cgit v1.2.3 From 7ebab6991081f9fabc207b778f0ae154190caca1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:43:38 +0000 Subject: Fix interrupt masking (Ralf Baechle git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1552 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index e7f4322ef..bdfc86550 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -307,7 +307,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Cause & 0x0000FF00) && + (env->CP0_Status & env->CP0_Cause & 0x0000FF00) && !(env->hflags & MIPS_HFLAG_EXL) && !(env->hflags & MIPS_HFLAG_ERL) && !(env->hflags & MIPS_HFLAG_DM)) { -- cgit v1.2.3 From 89353a790bbc336cd1a5029e2d3c9df6a82845af Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 09:50:09 +0000 Subject: Byte swapping bug in arm semihosting (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1553 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm-semi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c index 6950daaa6..472361a47 100644 --- a/linux-user/arm-semi.c +++ b/linux-user/arm-semi.c @@ -178,7 +178,7 @@ uint32_t do_arm_semihosting(CPUState *env) ts->heap_limit = limit; } - ptr = (uint32_t *)tswap32(ARG(0)); + ptr = (uint32_t *)ARG(0); ptr[0] = tswap32(ts->heap_base); ptr[1] = tswap32(ts->heap_limit); ptr[2] = tswap32(ts->stack_base); -- cgit v1.2.3 From 0bccf03d6f6d0c9ecb4534d1d5b7bb49350bd84e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 10:12:28 +0000 Subject: fix AUX vector entries (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1554 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 80b964de3..7b102c6cb 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -186,19 +186,17 @@ do { \ * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. */ -#define DLINFO_ARCH_ITEMS 3 +#define DLINFO_ARCH_ITEMS 5 #define ARCH_DLINFO \ do { \ - sp -= DLINFO_ARCH_ITEMS * 2; \ - NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \ - NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \ - NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \ + NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ /* \ * Now handle glibc compatibility. \ */ \ - sp -= 2*2; \ - NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ - NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ } while (0) static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) @@ -643,24 +641,24 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, if ((unsigned long)csp & 15UL) sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); -#define NEW_AUX_ENT(nr, id, val) \ - put_user (id, sp + (nr * 2)); \ - put_user (val, sp + (nr * 2 + 1)) - sp -= 2; - NEW_AUX_ENT (0, AT_NULL, 0); - - sp -= DLINFO_ITEMS*2; - NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); - NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum)); - NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); - NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr)); - NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0); - NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid()); - NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid()); - NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid()); - NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid()); +#define NEW_AUX_ENT(id, val) \ + sp -= 2; \ + put_user (id, sp); \ + put_user (val, sp + 1) + NEW_AUX_ENT (AT_NULL, 0); + + /* There must be exactly DLINFO_ITEMS entries here. */ + NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); + NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum)); + NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); + NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr)); + NEW_AUX_ENT(AT_FLAGS, (target_ulong)0); + NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT(AT_UID, (target_ulong) getuid()); + NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid()); + NEW_AUX_ENT(AT_GID, (target_ulong) getgid()); + NEW_AUX_ENT(AT_EGID, (target_ulong) getegid()); #ifdef ARCH_DLINFO /* * ARCH_DLINFO must come last so platform specific code can enforce -- cgit v1.2.3 From 1e8a7cfd11385ee43ce28cca6b52f5834a4fff4a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 10:14:28 +0000 Subject: Show thumb state in cpu dump (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1555 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index adbd56124..c3e8fe826 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2204,12 +2204,13 @@ void cpu_dump_state(CPUState *env, FILE *f, else cpu_fprintf(f, " "); } - cpu_fprintf(f, "PSR=%08x %c%c%c%c\n", + cpu_fprintf(f, "PSR=%08x %c%c%c%c %c\n", env->cpsr, env->cpsr & (1 << 31) ? 'N' : '-', env->cpsr & (1 << 30) ? 'Z' : '-', env->cpsr & (1 << 29) ? 'C' : '-', - env->cpsr & (1 << 28) ? 'V' : '-'); + env->cpsr & (1 << 28) ? 'V' : '-', + env->thumb ? 'T' : 'A'); for (i = 0; i < 16; i++) { d.d = env->vfp.regs[i]; -- cgit v1.2.3 From ecada8a2dddff7b0382e35b9ffe5643ed895a7f4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 10:28:44 +0000 Subject: CR4.TSD flag support (Matt Schulkind) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1556 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 5 ++++- target-i386/translate.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index c41cbb727..424dc5284 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2328,7 +2328,10 @@ void helper_invlpg(target_ulong addr) void helper_rdtsc(void) { uint64_t val; - + + if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { + raise_exception(EXCP0D_GPF); + } val = cpu_get_tsc(env); EAX = (uint32_t)(val); EDX = (uint32_t)(val >> 32); diff --git a/target-i386/translate.c b/target-i386/translate.c index 619522a63..0f6b0eb7c 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4909,7 +4909,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_movl_T1_imu(offset); } goto do_lcall; - case 0xe9: /* jmp */ + case 0xe9: /* jmp im */ if (dflag) tval = (int32_t)insn_get(s, OT_LONG); else @@ -5366,6 +5366,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } break; case 0x131: /* rdtsc */ + gen_jmp_im(pc_start - s->cs_base); gen_op_rdtsc(); break; case 0x134: /* sysenter */ -- cgit v1.2.3 From 75913b727e2702b7ee3099c0388502778554f681 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 15:19:36 +0000 Subject: compilation fix for gcc3.4 on win32 (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1557 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/exec-all.h b/exec-all.h index 0f7921465..33780660f 100644 --- a/exec-all.h +++ b/exec-all.h @@ -320,13 +320,16 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); #define ASM_PREVIOUS_SECTION ".previous\n" #endif +#define ASM_OP_LABEL_NAME(n, opname) \ + ASM_NAME(__op_label) #n "." ASM_NAME(opname) + #if defined(__powerpc__) /* we patch the jump instruction directly */ #define GOTO_TB(opname, tbparam, n)\ do {\ asm volatile (ASM_DATA_SECTION\ - ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\ + ASM_OP_LABEL_NAME(n, opname) ":\n"\ ".long 1f\n"\ ASM_PREVIOUS_SECTION \ "b " ASM_NAME(__op_jmp) #n "\n"\ @@ -339,7 +342,7 @@ do {\ #define GOTO_TB(opname, tbparam, n)\ do {\ asm volatile (".section .data\n"\ - ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\ + ASM_OP_LABEL_NAME(n, opname) ":\n"\ ".long 1f\n"\ ASM_PREVIOUS_SECTION \ "jmp " ASM_NAME(__op_jmp) #n "\n"\ @@ -353,7 +356,8 @@ do {\ #define GOTO_TB(opname, tbparam, n)\ do {\ static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\ - static void __attribute__((unused)) *__op_label ## n = &&label ## n;\ + static void __attribute__((unused)) *__op_label ## n \ + __asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\ goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ label ## n: ;\ dummy_label ## n: ;\ -- cgit v1.2.3 From 3f20e1ddf2770016f8c8fa15971e0d0ebdd1c731 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 17:30:26 +0000 Subject: TSS error code push fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1558 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 424dc5284..c7fea9553 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -622,9 +622,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); if (has_error_code) { - int mask; + int mask, type; /* push the error code */ - shift = (env->segs[R_CS].flags >> DESC_B_SHIFT) & 1; + type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; + shift = type >> 3; if (env->segs[R_SS].flags & DESC_B_MASK) mask = 0xffffffff; else -- cgit v1.2.3 From f23db1692be35affcd4dc00a9c44caebb8831d4f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 19:12:28 +0000 Subject: dirty ram page handling fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1559 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/exec.c b/exec.c index c75c23eb0..3466c9df7 100644 --- a/exec.c +++ b/exec.c @@ -1492,12 +1492,12 @@ static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, tlb_protect_code1(&env->tlb_write[0][i], vaddr); tlb_protect_code1(&env->tlb_write[1][i], vaddr); - phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG; #ifdef USE_KQEMU if (env->kqemu_enabled) { kqemu_set_notdirty(env, ram_addr); } #endif + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG; #if !defined(CONFIG_SOFTMMU) /* NOTE: as we generated the code for this page, it is already at @@ -1541,19 +1541,23 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, length = end - start; if (length == 0) return; - mask = ~dirty_flags; - p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); len = length >> TARGET_PAGE_BITS; - for(i = 0; i < len; i++) - p[i] &= mask; - env = cpu_single_env; #ifdef USE_KQEMU if (env->kqemu_enabled) { - for(i = 0; i < len; i++) - kqemu_set_notdirty(env, (unsigned long)i << TARGET_PAGE_BITS); + ram_addr_t addr; + addr = start; + for(i = 0; i < len; i++) { + kqemu_set_notdirty(env, addr); + addr += TARGET_PAGE_SIZE; + } } #endif + mask = ~dirty_flags; + p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); + for(i = 0; i < len; i++) + p[i] &= mask; + /* we modify the TLB cache so that the dirty bit will be set again when accessing the range */ start1 = start + (unsigned long)phys_ram_base; @@ -1633,8 +1637,6 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) CPUState *env = cpu_single_env; int i; - phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff; - addr &= TARGET_PAGE_MASK; i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_set_dirty1(&env->tlb_write[0][i], addr); @@ -2005,8 +2007,11 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t #endif } stb_p((uint8_t *)(long)addr, val); - /* we set the page as dirty only if the code has been flushed */ - if (dirty_flags & CODE_DIRTY_FLAG) + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } @@ -2023,8 +2028,11 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t #endif } stw_p((uint8_t *)(long)addr, val); - /* we set the page as dirty only if the code has been flushed */ - if (dirty_flags & CODE_DIRTY_FLAG) + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } @@ -2041,8 +2049,11 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t #endif } stl_p((uint8_t *)(long)addr, val); - /* we set the page as dirty only if the code has been flushed */ - if (dirty_flags & CODE_DIRTY_FLAG) + dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; + /* we remove the notdirty callback only if the code has been + flushed */ + if (dirty_flags == 0xff) tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); } @@ -2207,7 +2218,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); } } } else { @@ -2327,7 +2339,8 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + (0xff & ~CODE_DIRTY_FLAG); } } } -- cgit v1.2.3 From fc8dc06020f91d29754b5982bca22097ff60ce19 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 21 Aug 2005 19:15:23 +0000 Subject: kqemu_set_notdirty() opt git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1560 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kqemu.c b/kqemu.c index 9a0f05b17..5b750edd2 100644 --- a/kqemu.c +++ b/kqemu.c @@ -237,6 +237,9 @@ void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr) fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", ram_addr); } #endif + /* we only track transitions to dirty state */ + if (phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] != 0xff) + return; if (nb_ram_pages_to_update >= KQEMU_MAX_RAM_PAGES_TO_UPDATE) nb_ram_pages_to_update = KQEMU_RAM_PAGES_UPDATE_ALL; else -- cgit v1.2.3 From df5f8956993449b735b5d917242a12222a4c58a1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 3 Sep 2005 10:45:09 +0000 Subject: improved user net performances git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1561 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp/slirp.c b/slirp/slirp.c index 3b840a82d..404cce8f7 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -350,7 +350,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) * See if anything has timed out */ if (link_up) { - if (time_fasttimo && ((curtime - time_fasttimo) >= 199)) { + if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) { tcp_fasttimo(); time_fasttimo = 0; } -- cgit v1.2.3 From a7c15abbb1fea0cf41b739e37b0229304fbc3c2d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 3 Sep 2005 10:45:39 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1562 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Changelog b/Changelog index dcd252c14..3ba685bc2 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,10 @@ +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) @@ -8,6 +15,7 @@ version 0.7.1: - 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: -- cgit v1.2.3 From 1c213d197626942201052f19be2b5f83370a6b36 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 3 Sep 2005 10:49:04 +0000 Subject: comments git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1563 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exec.c b/exec.c index 3466c9df7..11a3a6499 100644 --- a/exec.c +++ b/exec.c @@ -2193,17 +2193,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { - /* 32 bit read access */ + /* 32 bit write access */ val = ldl_p(buf); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); l = 4; } else if (l >= 2 && ((addr & 1) == 0)) { - /* 16 bit read access */ + /* 16 bit write access */ val = lduw_p(buf); io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); l = 2; } else { - /* 8 bit access */ + /* 8 bit write access */ val = ldub_p(buf); io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); l = 1; @@ -2237,7 +2237,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, stw_p(buf, val); l = 2; } else { - /* 8 bit access */ + /* 8 bit read access */ val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr); stb_p(buf, val); l = 1; -- cgit v1.2.3 From aa0bc6b68c98d4b8122a846c962a1bac1c329ca4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 3 Sep 2005 15:28:58 +0000 Subject: avoid losing chars in serial console git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1564 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/vl.c b/vl.c index 354968d61..9819916a1 100644 --- a/vl.c +++ b/vl.c @@ -1138,7 +1138,11 @@ CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) #define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ +#define TERM_FIFO_MAX_SIZE 1 + static int term_got_escape, client_index; +static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; +int term_fifo_size; void term_print_help(void) { @@ -1207,19 +1211,37 @@ static void stdio_received_byte(int ch) chr = stdio_clients[client_index]; s = chr->opaque; - buf[0] = ch; - /* XXX: should queue the char if the device is not - ready */ - if (s->fd_can_read(s->fd_opaque) > 0) + if (s->fd_can_read(s->fd_opaque) > 0) { + buf[0] = ch; s->fd_read(s->fd_opaque, buf, 1); + } else if (term_fifo_size == 0) { + term_fifo[term_fifo_size++] = ch; + } } } } static int stdio_can_read(void *opaque) { - /* XXX: not strictly correct */ - return 1; + CharDriverState *chr; + FDCharDriver *s; + + if (client_index < stdio_nb_clients) { + chr = stdio_clients[client_index]; + s = chr->opaque; + /* try to flush the queue if needed */ + if (term_fifo_size != 0 && s->fd_can_read(s->fd_opaque) > 0) { + s->fd_read(s->fd_opaque, term_fifo, 1); + term_fifo_size = 0; + } + /* see if we can absorb more chars */ + if (term_fifo_size == 0) + return 1; + else + return 0; + } else { + return 1; + } } static void stdio_read(void *opaque, const uint8_t *buf, int size) -- cgit v1.2.3 From ca0d1734b44a67ca0077c3f5714d901f7489559d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 3 Sep 2005 16:25:14 +0000 Subject: SYSENTER fix for x86_64 CPUs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1565 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kqemu.c b/kqemu.c index 5b750edd2..94792c09f 100644 --- a/kqemu.c +++ b/kqemu.c @@ -119,13 +119,19 @@ static void kqemu_update_cpuid(CPUState *env) critical_features_mask = CPUID_CMOV | CPUID_CX8 | CPUID_FXSR | CPUID_MMX | CPUID_SSE | - CPUID_SSE2; + CPUID_SSE2 | CPUID_SEP; if (!is_cpuid_supported()) { features = 0; } else { cpuid(1, eax, ebx, ecx, edx); features = edx; } +#ifdef __x86_64__ + /* NOTE: on x86_64 CPUs, SYSENTER is not supported in + compatibility mode, so in order to have the best performances + it is better not to use it */ + features &= ~CPUID_SEP; +#endif env->cpuid_features = (env->cpuid_features & ~critical_features_mask) | (features & critical_features_mask); /* XXX: we could update more of the target CPUID state so that the -- cgit v1.2.3 From a332e112b73d641ca603066e46bb5b05d6c054fc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 3 Sep 2005 17:55:47 +0000 Subject: kqemu_cpu_interrupt support for win32 (Filip Navara) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1566 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 1 + kqemu.c | 22 +++++++++++++++++----- vl.c | 3 +++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/exec-all.h b/exec-all.h index 33780660f..045648c06 100644 --- a/exec-all.h +++ b/exec-all.h @@ -611,6 +611,7 @@ int kqemu_cpu_exec(CPUState *env); void kqemu_flush_page(CPUState *env, target_ulong addr); void kqemu_flush(CPUState *env, int global); void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr); +void kqemu_cpu_interrupt(CPUState *env); static inline int kqemu_is_ok(CPUState *env) { diff --git a/kqemu.c b/kqemu.c index 94792c09f..70cfe2879 100644 --- a/kqemu.c +++ b/kqemu.c @@ -596,11 +596,14 @@ int kqemu_cpu_exec(CPUState *env) } #ifdef _WIN32 - DeviceIoControl(kqemu_fd, KQEMU_EXEC, - kenv, sizeof(struct kqemu_cpu_state), - kenv, sizeof(struct kqemu_cpu_state), - &temp, NULL); - ret = kenv->retval; + if (DeviceIoControl(kqemu_fd, KQEMU_EXEC, + kenv, sizeof(struct kqemu_cpu_state), + kenv, sizeof(struct kqemu_cpu_state), + &temp, NULL)) { + ret = kenv->retval; + } else { + ret = -1; + } #else #if KQEMU_VERSION >= 0x010100 ioctl(kqemu_fd, KQEMU_EXEC, kenv); @@ -737,4 +740,13 @@ int kqemu_cpu_exec(CPUState *env) return 0; } +void kqemu_cpu_interrupt(CPUState *env) +{ +#if defined(_WIN32) && KQEMU_VERSION >= 0x010101 + /* cancelling the I/O request causes KQEMU to finish executing the + current block and successfully returning. */ + CancelIo(kqemu_fd); +#endif +} + #endif diff --git a/vl.c b/vl.c index 9819916a1..ea46bdc9c 100644 --- a/vl.c +++ b/vl.c @@ -875,6 +875,9 @@ static void host_alarm_handler(int host_signum) qemu_get_clock(rt_clock))) { /* stop the cpu because a timer occured */ cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); +#ifdef USE_KQEMU + kqemu_cpu_interrupt(global_env); +#endif } } -- cgit v1.2.3 From 8289336c9867f227c2ae7f037904e83480a476c6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 3 Sep 2005 21:33:43 +0000 Subject: kqemu_enabled test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1567 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index ea46bdc9c..e7cd9668f 100644 --- a/vl.c +++ b/vl.c @@ -876,7 +876,9 @@ static void host_alarm_handler(int host_signum) /* stop the cpu because a timer occured */ cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); #ifdef USE_KQEMU - kqemu_cpu_interrupt(global_env); + if (global_env->kqemu_enabled) { + kqemu_cpu_interrupt(global_env); + } #endif } } -- cgit v1.2.3 From 7fa98e2a7a61bbd221235f2e0ee933431e268166 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Sep 2005 16:35:31 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1568 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7deb86fee..d5cc44d1d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1 \ No newline at end of file +0.7.2 \ No newline at end of file -- cgit v1.2.3 From de7581500691999629a35a9752c6a830ce520ca6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Sep 2005 16:54:47 +0000 Subject: disabled LDT test (kqemu 0.7.2 no longer needs it) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1569 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/exec-all.h b/exec-all.h index 045648c06..5db83d368 100644 --- a/exec-all.h +++ b/exec-all.h @@ -620,11 +620,7 @@ static inline int kqemu_is_ok(CPUState *env) (env->eflags & IOPL_MASK) != IOPL_MASK && (env->cr[0] & CR0_PE_MASK) && (env->eflags & IF_MASK) && - !(env->eflags & VM_MASK) -#if 1 - && (env->ldt.limit == 0 || env->ldt.limit == 0x27) -#endif - ); + !(env->eflags & VM_MASK)); } #endif -- cgit v1.2.3 From c0b24a1dd67495dec07fb4740face382f471f9c4 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Sep 2005 19:26:14 +0000 Subject: div64 fix (aka ssh bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1570 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index c7fea9553..e2f6fba2e 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3261,7 +3261,7 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) { uint64_t q, r, a1, a0; - int i, qb; + int i, qb, ab; a0 = *plow; a1 = *phigh; @@ -3275,8 +3275,9 @@ static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) return 1; /* XXX: use a better algorithm */ for(i = 0; i < 64; i++) { + ab = a1 >> 63; a1 = (a1 << 1) | (a0 >> 63); - if (a1 >= b) { + if (ab || a1 >= b) { a1 -= b; qb = 1; } else { -- cgit v1.2.3 From 1983a3956ce8c37a32de09976c65187bf3d4478b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 15:45:19 +0000 Subject: ASI printing (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1571 c046a42c-6fe2-441c-8c8c-71466251a162 --- sparc-dis.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/sparc-dis.c b/sparc-dis.c index 956597c79..597dc8a70 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -2102,7 +2102,55 @@ lookup_value (table, value) /* Handle ASI's. */ -static arg asi_table[] = +static const arg asi_table_v8[] = +{ + { 0x00, "#ASI_M_RES00" }, + { 0x01, "#ASI_M_UNA01" }, + { 0x02, "#ASI_M_MXCC" }, + { 0x03, "#ASI_M_FLUSH_PROBE" }, + { 0x04, "#ASI_M_MMUREGS" }, + { 0x05, "#ASI_M_TLBDIAG" }, + { 0x06, "#ASI_M_DIAGS" }, + { 0x07, "#ASI_M_IODIAG" }, + { 0x08, "#ASI_M_USERTXT" }, + { 0x09, "#ASI_M_KERNELTXT" }, + { 0x0A, "#ASI_M_USERDATA" }, + { 0x0B, "#ASI_M_KERNELDATA" }, + { 0x0C, "#ASI_M_TXTC_TAG" }, + { 0x0D, "#ASI_M_TXTC_DATA" }, + { 0x0E, "#ASI_M_DATAC_TAG" }, + { 0x0F, "#ASI_M_DATAC_DATA" }, + { 0x10, "#ASI_M_FLUSH_PAGE" }, + { 0x11, "#ASI_M_FLUSH_SEG" }, + { 0x12, "#ASI_M_FLUSH_REGION" }, + { 0x13, "#ASI_M_FLUSH_CTX" }, + { 0x14, "#ASI_M_FLUSH_USER" }, + { 0x17, "#ASI_M_BCOPY" }, + { 0x18, "#ASI_M_IFLUSH_PAGE" }, + { 0x19, "#ASI_M_IFLUSH_SEG" }, + { 0x1A, "#ASI_M_IFLUSH_REGION" }, + { 0x1B, "#ASI_M_IFLUSH_CTX" }, + { 0x1C, "#ASI_M_IFLUSH_USER" }, + { 0x1F, "#ASI_M_BFILL" }, + { 0x20, "#ASI_M_BYPASS" }, + { 0x29, "#ASI_M_FBMEM" }, + { 0x2A, "#ASI_M_VMEUS" }, + { 0x2B, "#ASI_M_VMEPS" }, + { 0x2C, "#ASI_M_VMEUT" }, + { 0x2D, "#ASI_M_VMEPT" }, + { 0x2E, "#ASI_M_SBUS" }, + { 0x2F, "#ASI_M_CTL" }, + { 0x31, "#ASI_M_FLUSH_IWHOLE" }, + { 0x36, "#ASI_M_IC_FLCLEAR" }, + { 0x37, "#ASI_M_DC_FLCLEAR" }, + { 0x39, "#ASI_M_DCDR" }, + { 0x40, "#ASI_M_VIKING_TMP1" }, + { 0x41, "#ASI_M_VIKING_TMP2" }, + { 0x4c, "#ASI_M_ACTION" }, + { 0, 0 } +}; + +static const arg asi_table_v9[] = { /* These are in the v9 architecture manual. */ /* The shorter versions appear first, they're here because Sun's as has them. @@ -2142,22 +2190,18 @@ static arg asi_table[] = { 0, 0 } }; -/* Return the value for ASI NAME, or -1 if not found. */ +/* Return the name for ASI value VALUE or NULL if not found. */ -int -sparc_encode_asi (name) - const char *name; +static const char * +sparc_decode_asi_v9 (int value) { - return lookup_name (asi_table, name); + return lookup_value (asi_table_v9, value); } -/* Return the name for ASI value VALUE or NULL if not found. */ - -const char * -sparc_decode_asi (value) - int value; +static const char * +sparc_decode_asi_v8 (int value) { - return lookup_value (asi_table, value); + return lookup_value (asi_table_v8, value); } /* Handle membar masks. */ @@ -2841,7 +2885,12 @@ print_insn_sparc (memaddr, info) case 'A': { - const char *name = sparc_decode_asi (X_ASI (insn)); + const char *name; + + if (info->mach == bfd_mach_sparc_v9) + name = sparc_decode_asi_v9 (X_ASI (insn)); + else + name = sparc_decode_asi_v8 (X_ASI (insn)); if (name) (*info->fprintf_func) (stream, "%s", name); -- cgit v1.2.3 From 48b2c193533ed12c6b1e4754862a397d2d196085 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 16:08:23 +0000 Subject: sparc fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1572 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdbstub.c b/gdbstub.c index cbae3208c..96b3ae6d0 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -297,7 +297,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) int i; /* fill in g0..g7 */ - for(i = 0; i < 7; i++) { + for(i = 0; i < 8; i++) { registers[i] = tswapl(env->gregs[i]); } /* fill in register window */ -- cgit v1.2.3 From 819385c58b319d9f80d676cefaed0610118f03ac Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 16:58:32 +0000 Subject: suppressed m48t08 RTC - simplified m48t59 RTC api git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1573 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +- hw/m48t08.c | 356 -------------------------------------------------------- hw/m48t08.h | 10 -- hw/m48t59.c | 188 +++++++++++++++--------------- hw/m48t59.h | 10 +- hw/ppc.c | 50 +++----- hw/ppc_chrp.c | 4 +- hw/ppc_prep.c | 2 +- hw/sun4m.c | 53 +++++---- hw/sun4u.c | 50 +++----- 10 files changed, 166 insertions(+), 560 deletions(-) delete mode 100644 hw/m48t08.c delete mode 100644 hw/m48t08.h diff --git a/Makefile.target b/Makefile.target index ea0f5c8fd..1ca4e3a4c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -305,7 +305,8 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o VL_OBJS+= cirrus_vga.o parallel.o VL_OBJS+= magic-load.o else -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o magic-load.o slavio_intctl.o +VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o endif endif ifdef CONFIG_GDBSTUB diff --git a/hw/m48t08.c b/hw/m48t08.c deleted file mode 100644 index 094587953..000000000 --- a/hw/m48t08.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * QEMU M48T08 NVRAM emulation for Sparc platform - * - * Copyright (c) 2003-2004 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -#include "m48t08.h" - -//#define DEBUG_NVRAM - -#if defined(DEBUG_NVRAM) -#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) -#else -#define NVRAM_PRINTF(fmt, args...) do { } while (0) -#endif - -#define NVRAM_MAX_MEM 0x1ff0 -#define NVRAM_MAXADDR 0x1fff - -struct m48t08_t { - /* RTC management */ - time_t time_offset; - time_t stop_time; - /* NVRAM storage */ - uint8_t *buffer; -}; - -/* Fake timer functions */ -/* Generic helpers for BCD */ -static inline uint8_t toBCD (uint8_t value) -{ - return (((value / 10) % 10) << 4) | (value % 10); -} - -static inline uint8_t fromBCD (uint8_t BCD) -{ - return ((BCD >> 4) * 10) + (BCD & 0x0F); -} - -/* RTC management helpers */ -static void get_time (m48t08_t *NVRAM, struct tm *tm) -{ - time_t t; - - t = time(NULL) + NVRAM->time_offset; -#ifdef _WIN32 - memcpy(tm,localtime(&t),sizeof(*tm)); -#else - localtime_r (&t, tm) ; -#endif -} - -static void set_time (m48t08_t *NVRAM, struct tm *tm) -{ - time_t now, new_time; - - new_time = mktime(tm); - now = time(NULL); - NVRAM->time_offset = new_time - now; -} - -/* Direct access to NVRAM */ -void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val) -{ - struct tm tm; - int tmp; - - addr &= NVRAM_MAXADDR; - switch (addr) { - case 0x1FF8: - /* control */ - NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; - break; - case 0x1FF9: - /* seconds (BCD) */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_time(NVRAM, &tm); - tm.tm_sec = tmp; - set_time(NVRAM, &tm); - } - if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) { - if (val & 0x80) { - NVRAM->stop_time = time(NULL); - } else { - NVRAM->time_offset += NVRAM->stop_time - time(NULL); - NVRAM->stop_time = 0; - } - } - NVRAM->buffer[0x1FF9] = val & 0x80; - break; - case 0x1FFA: - /* minutes (BCD) */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_time(NVRAM, &tm); - tm.tm_min = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFB: - /* hours (BCD) */ - tmp = fromBCD(val & 0x3F); - if (tmp >= 0 && tmp <= 23) { - get_time(NVRAM, &tm); - tm.tm_hour = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFC: - /* day of the week / century */ - tmp = fromBCD(val & 0x07); - get_time(NVRAM, &tm); - tm.tm_wday = tmp; - set_time(NVRAM, &tm); - NVRAM->buffer[0x1FFC] = val & 0x40; - break; - case 0x1FFD: - /* date */ - tmp = fromBCD(val & 0x1F); - if (tmp != 0) { - get_time(NVRAM, &tm); - tm.tm_mday = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFE: - /* month */ - tmp = fromBCD(val & 0x1F); - if (tmp >= 1 && tmp <= 12) { - get_time(NVRAM, &tm); - tm.tm_mon = tmp - 1; - set_time(NVRAM, &tm); - } - break; - case 0x1FFF: - /* year */ - tmp = fromBCD(val); - if (tmp >= 0 && tmp <= 99) { - get_time(NVRAM, &tm); - tm.tm_year = fromBCD(val); - set_time(NVRAM, &tm); - } - break; - default: - NVRAM->buffer[addr] = val & 0xFF; - break; - } -} - -uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr) -{ - struct tm tm; - uint8_t retval = 0xFF; - - addr &= NVRAM_MAXADDR; - switch (addr) { - case 0x1FF8: - /* control */ - goto do_read; - case 0x1FF9: - /* seconds (BCD) */ - get_time(NVRAM, &tm); - retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec); - break; - case 0x1FFA: - /* minutes (BCD) */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_min); - break; - case 0x1FFB: - /* hours (BCD) */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_hour); - break; - case 0x1FFC: - /* day of the week / century */ - get_time(NVRAM, &tm); - retval = NVRAM->buffer[0x1FFC] | tm.tm_wday; - break; - case 0x1FFD: - /* date */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_mday); - break; - case 0x1FFE: - /* month */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_mon + 1); - break; - case 0x1FFF: - /* year */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_year); - break; - default: - do_read: - retval = NVRAM->buffer[addr]; - break; - } - return retval; -} - -static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - m48t08_t *NVRAM = opaque; - - m48t08_write(NVRAM, addr, value); -} - -static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - m48t08_t *NVRAM = opaque; - - m48t08_write(NVRAM, addr, value); - m48t08_write(NVRAM, addr + 1, value >> 8); -} - -static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - m48t08_t *NVRAM = opaque; - - m48t08_write(NVRAM, addr, value); - m48t08_write(NVRAM, addr + 1, value >> 8); - m48t08_write(NVRAM, addr + 2, value >> 16); - m48t08_write(NVRAM, addr + 3, value >> 24); -} - -static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) -{ - m48t08_t *NVRAM = opaque; - uint32_t retval = 0; - - retval = m48t08_read(NVRAM, addr); - return retval; -} - -static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) -{ - m48t08_t *NVRAM = opaque; - uint32_t retval = 0; - - retval = m48t08_read(NVRAM, addr) << 8; - retval |= m48t08_read(NVRAM, addr + 1); - return retval; -} - -static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) -{ - m48t08_t *NVRAM = opaque; - uint32_t retval = 0; - - retval = m48t08_read(NVRAM, addr) << 24; - retval |= m48t08_read(NVRAM, addr + 1) << 16; - retval |= m48t08_read(NVRAM, addr + 2) << 8; - retval |= m48t08_read(NVRAM, addr + 3); - return retval; -} - -static CPUWriteMemoryFunc *nvram_write[] = { - &nvram_writeb, - &nvram_writew, - &nvram_writel, -}; - -static CPUReadMemoryFunc *nvram_read[] = { - &nvram_readb, - &nvram_readw, - &nvram_readl, -}; - -static void nvram_save(QEMUFile *f, void *opaque) -{ - m48t08_t *s = opaque; - - qemu_put_be32s(f, (uint32_t *)&s->time_offset); - qemu_put_be32s(f, (uint32_t *)&s->stop_time); - qemu_put_buffer(f, s->buffer, 0x2000); -} - -static int nvram_load(QEMUFile *f, void *opaque, int version_id) -{ - m48t08_t *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, (uint32_t *)&s->time_offset); - qemu_get_be32s(f, (uint32_t *)&s->stop_time); - qemu_get_buffer(f, s->buffer, 0x2000); - return 0; -} - -static void m48t08_reset(void *opaque) -{ - m48t08_t *s = opaque; - - s->time_offset = 0; - s->stop_time = 0; -} - - -/* Initialisation routine */ -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size) -{ - m48t08_t *s; - int mem_index; - - s = qemu_mallocz(sizeof(m48t08_t)); - if (!s) - return NULL; - s->buffer = qemu_mallocz(size); - if (!s->buffer) { - qemu_free(s); - return NULL; - } - if (mem_base != 0) { - mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); - cpu_register_physical_memory(mem_base, 0x2000, mem_index); - } - - register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s); - qemu_register_reset(m48t08_reset, s); - return s; -} - -#if 0 -struct idprom -{ - unsigned char id_format; /* Format identifier (always 0x01) */ - unsigned char id_machtype; /* Machine type */ - unsigned char id_ethaddr[6]; /* Hardware ethernet address */ - long id_date; /* Date of manufacture */ - unsigned int id_sernum:24; /* Unique serial number */ - unsigned char id_cksum; /* Checksum - xor of the data bytes */ - unsigned char reserved[16]; -}; -#endif diff --git a/hw/m48t08.h b/hw/m48t08.h deleted file mode 100644 index 985116a09..000000000 --- a/hw/m48t08.h +++ /dev/null @@ -1,10 +0,0 @@ -#if !defined (__M48T08_H__) -#define __M48T08_H__ - -typedef struct m48t08_t m48t08_t; - -void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val); -uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr); -m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size); - -#endif /* !defined (__M48T08_H__) */ diff --git a/hw/m48t59.c b/hw/m48t59.c index 5ab58160a..81e64e441 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -1,7 +1,7 @@ /* - * QEMU M48T59 NVRAM emulation for PPC PREP platform + * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms * - * Copyright (c) 2003-2004 Jocelyn Mayer + * Copyright (c) 2003-2005 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,7 +32,14 @@ #define NVRAM_PRINTF(fmt, args...) do { } while (0) #endif +/* + * The M48T08 and M48T59 chips are very similar. The newer '59 has + * alarm and a watchdog timer and related control registers. In the + * PPC platform there is also a nvram lock function. + */ struct m48t59_t { + /* Model parameters */ + int type; // 8 = m48t08, 59 = m48t59 /* Hardware parameters */ int IRQ; int mem_index; @@ -188,14 +195,17 @@ static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) } /* Direct access to NVRAM */ -void m48t59_write (m48t59_t *NVRAM, uint32_t val) +void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) { struct tm tm; int tmp; - if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000) - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); - switch (NVRAM->addr) { + if (addr > 0x1FF8 && addr < 0x2000) + NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); + if (NVRAM->type == 8 && + (addr >= 0x1ff0 && addr <= 0x1ff7)) + goto do_write; + switch (addr) { case 0x1FF0: /* flags register : read-only */ break; @@ -204,52 +214,52 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val) break; case 0x1FF2: /* alarm seconds */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_sec = tmp; - NVRAM->buffer[0x1FF2] = val; - set_alarm(NVRAM, &tm); - } + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_alarm(NVRAM, &tm); + tm.tm_sec = tmp; + NVRAM->buffer[0x1FF2] = val; + set_alarm(NVRAM, &tm); + } break; case 0x1FF3: /* alarm minutes */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_min = tmp; - NVRAM->buffer[0x1FF3] = val; - set_alarm(NVRAM, &tm); - } + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_alarm(NVRAM, &tm); + tm.tm_min = tmp; + NVRAM->buffer[0x1FF3] = val; + set_alarm(NVRAM, &tm); + } break; case 0x1FF4: /* alarm hours */ - tmp = fromBCD(val & 0x3F); - if (tmp >= 0 && tmp <= 23) { - get_alarm(NVRAM, &tm); - tm.tm_hour = tmp; - NVRAM->buffer[0x1FF4] = val; - set_alarm(NVRAM, &tm); - } + tmp = fromBCD(val & 0x3F); + if (tmp >= 0 && tmp <= 23) { + get_alarm(NVRAM, &tm); + tm.tm_hour = tmp; + NVRAM->buffer[0x1FF4] = val; + set_alarm(NVRAM, &tm); + } break; case 0x1FF5: /* alarm date */ - tmp = fromBCD(val & 0x1F); - if (tmp != 0) { - get_alarm(NVRAM, &tm); - tm.tm_mday = tmp; - NVRAM->buffer[0x1FF5] = val; - set_alarm(NVRAM, &tm); - } + tmp = fromBCD(val & 0x1F); + if (tmp != 0) { + get_alarm(NVRAM, &tm); + tm.tm_mday = tmp; + NVRAM->buffer[0x1FF5] = val; + set_alarm(NVRAM, &tm); + } break; case 0x1FF6: /* interrupts */ - NVRAM->buffer[0x1FF6] = val; + NVRAM->buffer[0x1FF6] = val; break; case 0x1FF7: /* watchdog */ - NVRAM->buffer[0x1FF7] = val; - set_up_watchdog(NVRAM, val); + NVRAM->buffer[0x1FF7] = val; + set_up_watchdog(NVRAM, val); break; case 0x1FF8: /* control */ @@ -328,24 +338,27 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val) break; default: /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) + if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) + if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) break; - if (NVRAM->addr < 0x1FF0 || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - NVRAM->buffer[NVRAM->addr] = val & 0xFF; + do_write: + if (addr < NVRAM->size) { + NVRAM->buffer[addr] = val & 0xFF; } break; } } -uint32_t m48t59_read (m48t59_t *NVRAM) +uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) { struct tm tm; uint32_t retval = 0xFF; - switch (NVRAM->addr) { + if (NVRAM->type == 8 && + (addr >= 0x1ff0 && addr <= 0x1ff7)) + goto do_read; + switch (addr) { case 0x1FF0: /* flags register */ goto do_read; @@ -412,19 +425,18 @@ uint32_t m48t59_read (m48t59_t *NVRAM) break; default: /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) + if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) + if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) break; - if (NVRAM->addr < 0x1FF0 || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - do_read: - retval = NVRAM->buffer[NVRAM->addr]; + do_read: + if (addr < NVRAM->size) { + retval = NVRAM->buffer[addr]; } break; } - if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000) - NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); + if (addr > 0x1FF9 && addr < 0x2000) + NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval); return retval; } @@ -456,7 +468,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) NVRAM->addr |= val << 8; break; case 3: - m48t59_write(NVRAM, val); + m48t59_write(NVRAM, val, NVRAM->addr); NVRAM->addr = 0x0000; break; default: @@ -472,7 +484,7 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) addr -= NVRAM->io_base; switch (addr) { case 3: - retval = m48t59_read(NVRAM); + retval = m48t59_read(NVRAM, NVRAM->addr); break; default: retval = -1; @@ -488,8 +500,7 @@ static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) m48t59_t *NVRAM = opaque; addr -= NVRAM->mem_base; - if (addr < 0x1FF0) - NVRAM->buffer[addr] = value; + m48t59_write(NVRAM, addr, value & 0xff); } static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) @@ -497,10 +508,8 @@ static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) m48t59_t *NVRAM = opaque; addr -= NVRAM->mem_base; - if (addr < 0x1FF0) { - NVRAM->buffer[addr] = value >> 8; - NVRAM->buffer[addr + 1] = value; - } + m48t59_write(NVRAM, addr, (value >> 8) & 0xff); + m48t59_write(NVRAM, addr + 1, value & 0xff); } static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) @@ -508,53 +517,43 @@ static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) m48t59_t *NVRAM = opaque; addr -= NVRAM->mem_base; - if (addr < 0x1FF0) { - NVRAM->buffer[addr] = value >> 24; - NVRAM->buffer[addr + 1] = value >> 16; - NVRAM->buffer[addr + 2] = value >> 8; - NVRAM->buffer[addr + 3] = value; - } + m48t59_write(NVRAM, addr, (value >> 24) & 0xff); + m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff); + m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff); + m48t59_write(NVRAM, addr + 3, value & 0xff); } static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) { m48t59_t *NVRAM = opaque; - uint32_t retval = 0; + uint32_t retval; addr -= NVRAM->mem_base; - if (addr < 0x1FF0) - retval = NVRAM->buffer[addr]; - + retval = m48t59_read(NVRAM, addr); return retval; } static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) { m48t59_t *NVRAM = opaque; - uint32_t retval = 0; + uint32_t retval; addr -= NVRAM->mem_base; - if (addr < 0x1FF0) { - retval = NVRAM->buffer[addr] << 8; - retval |= NVRAM->buffer[addr + 1]; - } - + retval = m48t59_read(NVRAM, addr) << 8; + retval |= m48t59_read(NVRAM, addr + 1); return retval; } static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) { m48t59_t *NVRAM = opaque; - uint32_t retval = 0; - - addr -= NVRAM->mem_base; - if (addr < 0x1FF0) { - retval = NVRAM->buffer[addr] << 24; - retval |= NVRAM->buffer[addr + 1] << 16; - retval |= NVRAM->buffer[addr + 2] << 8; - retval |= NVRAM->buffer[addr + 3]; - } + uint32_t retval; + addr -= NVRAM->mem_base; + retval = m48t59_read(NVRAM, addr) << 24; + retval |= m48t59_read(NVRAM, addr + 1) << 16; + retval |= m48t59_read(NVRAM, addr + 2) << 8; + retval |= m48t59_read(NVRAM, addr + 3); return retval; } @@ -569,9 +568,11 @@ static CPUReadMemoryFunc *nvram_read[] = { &nvram_readw, &nvram_readl, }; + /* Initialisation routine */ -m48t59_t *m48t59_init (int IRQ, uint32_t mem_base, - uint32_t io_base, uint16_t size) +m48t59_t *m48t59_init (int IRQ, target_ulong mem_base, + uint32_t io_base, uint16_t size, + int type) { m48t59_t *s; @@ -588,14 +589,19 @@ m48t59_t *m48t59_init (int IRQ, uint32_t mem_base, s->mem_base = mem_base; s->io_base = io_base; s->addr = 0; - register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); - register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); + s->type = type; + if (io_base != 0) { + register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); + register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); + } if (mem_base != 0) { s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); } - s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); - s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); + if (type == 59) { + s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); + s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); + } s->lock = 0; return s; diff --git a/hw/m48t59.h b/hw/m48t59.h index 03d8ea3b9..af22dc112 100644 --- a/hw/m48t59.h +++ b/hw/m48t59.h @@ -3,11 +3,11 @@ typedef struct m48t59_t m48t59_t; -void m48t59_write (m48t59_t *NVRAM, uint32_t val); -uint32_t m48t59_read (m48t59_t *NVRAM); -void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr); +void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val); +uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr); void m48t59_toggle_lock (m48t59_t *NVRAM, int lock); -m48t59_t *m48t59_init (int IRQ, uint32_t io_base, - uint32_t mem_base, uint16_t size); +m48t59_t *m48t59_init (int IRQ, target_ulong mem_base, + uint32_t io_base, uint16_t size, + int type); #endif /* !defined (__M48T59_H__) */ diff --git a/hw/ppc.c b/hw/ppc.c index c460fec48..3743ad786 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -283,61 +283,45 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) /* NVRAM helpers */ void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) { - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value); + m48t59_write(nvram, addr, value); } uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) { - m48t59_set_addr(nvram, addr); - return m48t59_read(nvram); + return m48t59_read(nvram, addr); } void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) { - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value >> 8); - m48t59_set_addr(nvram, addr + 1); - m48t59_write(nvram, value & 0xFF); + m48t59_write(nvram, addr, value >> 8); + m48t59_write(nvram, addr + 1, value & 0xFF); } uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) { uint16_t tmp; - m48t59_set_addr(nvram, addr); - tmp = m48t59_read(nvram) << 8; - m48t59_set_addr(nvram, addr + 1); - tmp |= m48t59_read(nvram); - + tmp = m48t59_read(nvram, addr) << 8; + tmp |= m48t59_read(nvram, addr + 1); return tmp; } void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) { - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value >> 24); - m48t59_set_addr(nvram, addr + 1); - m48t59_write(nvram, (value >> 16) & 0xFF); - m48t59_set_addr(nvram, addr + 2); - m48t59_write(nvram, (value >> 8) & 0xFF); - m48t59_set_addr(nvram, addr + 3); - m48t59_write(nvram, value & 0xFF); + m48t59_write(nvram, addr, value >> 24); + m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF); + m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF); + m48t59_write(nvram, addr + 3, value & 0xFF); } uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) { uint32_t tmp; - m48t59_set_addr(nvram, addr); - tmp = m48t59_read(nvram) << 24; - m48t59_set_addr(nvram, addr + 1); - tmp |= m48t59_read(nvram) << 16; - m48t59_set_addr(nvram, addr + 2); - tmp |= m48t59_read(nvram) << 8; - m48t59_set_addr(nvram, addr + 3); - tmp |= m48t59_read(nvram); - + tmp = m48t59_read(nvram, addr) << 24; + tmp |= m48t59_read(nvram, addr + 1) << 16; + tmp |= m48t59_read(nvram, addr + 2) << 8; + tmp |= m48t59_read(nvram, addr + 3); return tmp; } @@ -347,11 +331,9 @@ void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, int i; for (i = 0; i < max && str[i] != '\0'; i++) { - m48t59_set_addr(nvram, addr + i); - m48t59_write(nvram, str[i]); + m48t59_write(nvram, addr + i, str[i]); } - m48t59_set_addr(nvram, addr + max - 1); - m48t59_write(nvram, '\0'); + m48t59_write(nvram, addr + max - 1, '\0'); } int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index a76fc47dc..46e903168 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -449,7 +449,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, macio_init(pci_bus, 0x0017); - nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); + nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59); arch_name = "HEATHROW"; } else { @@ -496,7 +496,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, macio_init(pci_bus, 0x0022); - nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE); + nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59); arch_name = "MAC99"; } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 148a08af5..017457df2 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -652,7 +652,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); #endif - nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE); + nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); if (nvram == NULL) return; sysctrl->nvram = nvram; diff --git a/hw/sun4m.c b/hw/sun4m.c index 56b9069e5..7174c23cb 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ #include "vl.h" -#include "m48t08.h" #define KERNEL_LOAD_ADDR 0x00004000 #define CMDLINE_ADDR 0x007ff000 @@ -88,36 +87,36 @@ void DMA_register_channel (int nchan, { } -static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value) +static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) { - m48t08_write(nvram, addr++, (value >> 8) & 0xff); - m48t08_write(nvram, addr++, value & 0xff); + m48t59_write(nvram, addr++, (value >> 8) & 0xff); + m48t59_write(nvram, addr++, value & 0xff); } -static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value) +static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) { - m48t08_write(nvram, addr++, value >> 24); - m48t08_write(nvram, addr++, (value >> 16) & 0xff); - m48t08_write(nvram, addr++, (value >> 8) & 0xff); - m48t08_write(nvram, addr++, value & 0xff); + m48t59_write(nvram, addr++, value >> 24); + m48t59_write(nvram, addr++, (value >> 16) & 0xff); + m48t59_write(nvram, addr++, (value >> 8) & 0xff); + m48t59_write(nvram, addr++, value & 0xff); } -static void nvram_set_string (m48t08_t *nvram, uint32_t addr, +static void nvram_set_string (m48t59_t *nvram, uint32_t addr, const unsigned char *str, uint32_t max) { unsigned int i; for (i = 0; i < max && str[i] != '\0'; i++) { - m48t08_write(nvram, addr + i, str[i]); + m48t59_write(nvram, addr + i, str[i]); } - m48t08_write(nvram, addr + max - 1, '\0'); + m48t59_write(nvram, addr + max - 1, '\0'); } -static m48t08_t *nvram; +static m48t59_t *nvram; extern int nographic; -static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline, +static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, int boot_device, uint32_t RAM_size, uint32_t kernel_size, int width, int height, int depth) @@ -129,9 +128,9 @@ static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline, nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */ // NVRAM_size, arch not applicable - m48t08_write(nvram, 0x2F, nographic & 0xff); + m48t59_write(nvram, 0x2F, nographic & 0xff); nvram_set_lword(nvram, 0x30, RAM_size); - m48t08_write(nvram, 0x34, boot_device & 0xff); + m48t59_write(nvram, 0x34, boot_device & 0xff); nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR); nvram_set_lword(nvram, 0x3C, kernel_size); if (cmdline) { @@ -146,21 +145,21 @@ static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline, // Sun4m specific use i = 0x1fd8; - m48t08_write(nvram, i++, 0x01); - m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */ + m48t59_write(nvram, i++, 0x01); + m48t59_write(nvram, i++, 0x80); /* Sun4m OBP */ j = 0; - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i++, macaddr[j++]); - m48t08_write(nvram, i, macaddr[j]); + m48t59_write(nvram, i++, macaddr[j++]); + m48t59_write(nvram, i++, macaddr[j++]); + m48t59_write(nvram, i++, macaddr[j++]); + m48t59_write(nvram, i++, macaddr[j++]); + m48t59_write(nvram, i++, macaddr[j++]); + m48t59_write(nvram, i, macaddr[j]); /* Calculate checksum */ for (i = 0x1fd8; i < 0x1fe7; i++) { - tmp ^= m48t08_read(nvram, i); + tmp ^= m48t59_read(nvram, i); } - m48t08_write(nvram, 0x1fe7, tmp); + m48t59_write(nvram, 0x1fe7, tmp); } static void *slavio_intctl; @@ -231,7 +230,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); - nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE); + nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8); slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device diff --git a/hw/sun4u.c b/hw/sun4u.c index 9c8945393..40d70a9ca 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -68,60 +68,46 @@ void DMA_register_channel (int nchan, /* NVRAM helpers */ void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) { - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value); + m48t59_write(nvram, addr, value); } uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) { - m48t59_set_addr(nvram, addr); - return m48t59_read(nvram); + return m48t59_read(nvram, addr); } void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) { - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value >> 8); - m48t59_set_addr(nvram, addr + 1); - m48t59_write(nvram, value & 0xFF); + m48t59_write(nvram, addr, value >> 8); + m48t59_write(nvram, addr + 1, value & 0xFF); } uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) { uint16_t tmp; - m48t59_set_addr(nvram, addr); - tmp = m48t59_read(nvram) << 8; - m48t59_set_addr(nvram, addr + 1); - tmp |= m48t59_read(nvram); + tmp = m48t59_read(nvram, addr) << 8; + tmp |= m48t59_read(nvram, addr + 1); return tmp; } void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) { - m48t59_set_addr(nvram, addr); - m48t59_write(nvram, value >> 24); - m48t59_set_addr(nvram, addr + 1); - m48t59_write(nvram, (value >> 16) & 0xFF); - m48t59_set_addr(nvram, addr + 2); - m48t59_write(nvram, (value >> 8) & 0xFF); - m48t59_set_addr(nvram, addr + 3); - m48t59_write(nvram, value & 0xFF); + m48t59_write(nvram, addr, value >> 24); + m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF); + m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF); + m48t59_write(nvram, addr + 3, value & 0xFF); } uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) { uint32_t tmp; - m48t59_set_addr(nvram, addr); - tmp = m48t59_read(nvram) << 24; - m48t59_set_addr(nvram, addr + 1); - tmp |= m48t59_read(nvram) << 16; - m48t59_set_addr(nvram, addr + 2); - tmp |= m48t59_read(nvram) << 8; - m48t59_set_addr(nvram, addr + 3); - tmp |= m48t59_read(nvram); + tmp = m48t59_read(nvram, addr) << 24; + tmp |= m48t59_read(nvram, addr + 1) << 16; + tmp |= m48t59_read(nvram, addr + 2) << 8; + tmp |= m48t59_read(nvram, addr + 3); return tmp; } @@ -132,11 +118,9 @@ void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, int i; for (i = 0; i < max && str[i] != '\0'; i++) { - m48t59_set_addr(nvram, addr + i); - m48t59_write(nvram, str[i]); + m48t59_write(nvram, addr + i, str[i]); } - m48t59_set_addr(nvram, addr + max - 1); - m48t59_write(nvram, '\0'); + m48t59_write(nvram, addr + max - 1, '\0'); } int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) @@ -357,7 +341,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, pci_cmd646_ide_init(pci_bus, bs_table, 1); kbd_init(); floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); - nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE); + nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device, KERNEL_LOAD_ADDR, kernel_size, kernel_cmdline, -- cgit v1.2.3 From 7b936c0c42933b8b6bc308e71a6e20904f512eb4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 17:05:13 +0000 Subject: sparc64 fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1574 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/monitor.c b/monitor.c index 1ff9bde6e..0153e8d8b 100644 --- a/monitor.c +++ b/monitor.c @@ -1060,10 +1060,12 @@ static target_long monitor_get_tbl (struct MonitorDef *md, int val) #endif #if defined(TARGET_SPARC) +#ifndef TARGET_SPARC64 static target_long monitor_get_psr (struct MonitorDef *md, int val) { return GET_PSR(cpu_single_env); } +#endif static target_long monitor_get_reg(struct MonitorDef *md, int val) { @@ -1202,8 +1204,10 @@ static MonitorDef monitor_defs[] = { { "pc", offsetof(CPUState, pc) }, { "npc", offsetof(CPUState, npc) }, { "y", offsetof(CPUState, y) }, +#ifndef TARGET_SPARC64 { "psr", 0, &monitor_get_psr, }, { "wim", offsetof(CPUState, wim) }, +#endif { "tbr", offsetof(CPUState, tbr) }, { "fsr", offsetof(CPUState, fsr) }, { "f0", offsetof(CPUState, fpr[0]) }, @@ -1238,6 +1242,32 @@ static MonitorDef monitor_defs[] = { { "f29", offsetof(CPUState, fpr[29]) }, { "f30", offsetof(CPUState, fpr[30]) }, { "f31", offsetof(CPUState, fpr[31]) }, +#ifdef TARGET_SPARC64 + { "f32", offsetof(CPUState, fpr[32]) }, + { "f34", offsetof(CPUState, fpr[34]) }, + { "f36", offsetof(CPUState, fpr[36]) }, + { "f38", offsetof(CPUState, fpr[38]) }, + { "f40", offsetof(CPUState, fpr[40]) }, + { "f42", offsetof(CPUState, fpr[42]) }, + { "f44", offsetof(CPUState, fpr[44]) }, + { "f46", offsetof(CPUState, fpr[46]) }, + { "f48", offsetof(CPUState, fpr[48]) }, + { "f50", offsetof(CPUState, fpr[50]) }, + { "f52", offsetof(CPUState, fpr[52]) }, + { "f54", offsetof(CPUState, fpr[54]) }, + { "f56", offsetof(CPUState, fpr[56]) }, + { "f58", offsetof(CPUState, fpr[58]) }, + { "f60", offsetof(CPUState, fpr[60]) }, + { "f62", offsetof(CPUState, fpr[62]) }, + { "asi", offsetof(CPUState, asi) }, + { "pstate", offsetof(CPUState, pstate) }, + { "cansave", offsetof(CPUState, cansave) }, + { "canrestore", offsetof(CPUState, canrestore) }, + { "otherwin", offsetof(CPUState, otherwin) }, + { "wstate", offsetof(CPUState, wstate) }, + { "cleanwin", offsetof(CPUState, cleanwin) }, + { "fprs", offsetof(CPUState, fprs) }, +#endif #endif { NULL }, }; -- cgit v1.2.3 From f69a86955e028f963ae31257bd6cb25be705a6cd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 17:05:44 +0000 Subject: slavio_serial fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1575 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 4b02d29f6..de45cc5de 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -195,7 +195,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint val &= 0x38; switch (val) { case 8: - s->reg |= 0x8; + newreg |= 0x8; break; case 0x20: s->rxint = 0; @@ -245,7 +245,8 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint handle_kbd_command(s, val); } s->txint = 1; - s->rregs[0] |= 4; + s->rregs[0] |= 4; // Tx buffer empty + s->rregs[1] |= 1; // All sent // Interrupts reported only on channel A if (s->chn == 0) s->rregs[3] |= 0x10; @@ -278,12 +279,12 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) s->reg = 0; return ret; case 1: - SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', s->rx); s->rregs[0] &= ~1; if (s->type == kbd) ret = get_queue(s); else ret = s->rx; + SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret); return ret; default: break; @@ -453,7 +454,6 @@ static void handle_kbd_command(ChannelState *s, int val) KBD_DPRINTF("Command %d\n", val); switch (val) { case 1: // Reset, return type code - put_queue(s, 0xff); put_queue(s, 0xff); put_queue(s, 5); // Type 5 break; -- cgit v1.2.3 From aea3ce4c8dc2231711e648c4199279fb9b7f25b4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 17:06:11 +0000 Subject: restore regwptr (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1576 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 942b81189..5f48ba8e6 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -152,6 +152,10 @@ void do_rdpsr(); static inline void env_to_regs(void) { +#if defined(reg_REGWPTR) + REGWPTR = env->regbase + (env->cwp * 16); + env->regwptr = REGWPTR; +#endif } static inline void regs_to_env(void) -- cgit v1.2.3 From 4f6200f03b32d1cb166c2b85c97e857109dd8f9d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 17:24:05 +0000 Subject: ESP PIO mode, 2k CDROM sector size (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1577 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 143 insertions(+), 39 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index e04539a2a..6890bd144 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -36,6 +36,9 @@ do { printf("ESP: " fmt , ##args); } while (0) #define ESPDMA_REGS 4 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) #define ESP_MAXREG 0x3f +#define TI_BUFSZ 65536 +#define DMA_VER 0xa0000000 +#define DMA_LOADED 0x04000000 typedef struct ESPState { BlockDriverState **bd; @@ -44,8 +47,10 @@ typedef struct ESPState { int irq; uint32_t espdmaregs[ESPDMA_REGS]; uint32_t ti_size; + uint32_t ti_rptr, ti_wptr; int ti_dir; - uint8_t ti_buf[65536]; + uint8_t ti_buf[TI_BUFSZ]; + int dma; } ESPState; #define STAT_DO 0x00 @@ -73,17 +78,25 @@ static void handle_satn(ESPState *s) int64_t nb_sectors; int target; - dmaptr = iommu_translate(s->espdmaregs[1]); dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen); - DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); - cpu_physical_memory_read(dmaptr, buf, dmalen); + target = s->wregs[4] & 7; + DPRINTF("Select with ATN len %d target %d\n", dmalen, target); + if (s->dma) { + dmaptr = iommu_translate(s->espdmaregs[1]); + DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); + cpu_physical_memory_read(dmaptr, buf, dmalen); + } else { + buf[0] = 0; + memcpy(&buf[1], s->ti_buf, dmalen); + dmalen++; + } for (i = 0; i < dmalen; i++) { DPRINTF("Command %2.2x\n", buf[i]); } s->ti_dir = 0; s->ti_size = 0; - target = s->wregs[4] & 7; + s->ti_rptr = 0; + s->ti_wptr = 0; if (target > 4 || !s->bd[target]) { // No such drive s->rregs[4] = STAT_IN; @@ -126,7 +139,10 @@ static void handle_satn(ESPState *s) s->ti_buf[3] = nb_sectors & 0xff; s->ti_buf[4] = 0; s->ti_buf[5] = 0; - s->ti_buf[6] = 2; + if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) + s->ti_buf[6] = 8; // sector size 2048 + else + s->ti_buf[6] = 2; // sector size 512 s->ti_buf[7] = 0; s->ti_dir = 1; s->ti_size = 8; @@ -135,28 +151,42 @@ static void handle_satn(ESPState *s) { int64_t offset, len; - offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; - len = (buf[8] << 8) | buf[9]; + if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { + offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; + len = ((buf[8] << 8) | buf[9]) * 4; + s->ti_size = len * 2048; + } else { + offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; + len = (buf[8] << 8) | buf[9]; + s->ti_size = len * 512; + } DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); bdrv_read(s->bd[target], offset, s->ti_buf, len); + // XXX error handling s->ti_dir = 1; - s->ti_size = len * 512; break; } case 0x2a: { int64_t offset, len; - offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; - len = (buf[8] << 8) | buf[9]; + if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { + offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; + len = ((buf[8] << 8) | buf[9]) * 4; + s->ti_size = len * 2048; + } else { + offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; + len = (buf[8] << 8) | buf[9]; + s->ti_size = len * 512; + } DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); bdrv_write(s->bd[target], offset, s->ti_buf, len); + // XXX error handling s->ti_dir = 0; - s->ti_size = len * 512; break; } default: - DPRINTF("Unknown command (%2.2x)\n", buf[1]); + DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); break; } s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; @@ -170,17 +200,26 @@ static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) { uint32_t dmaptr, dmalen; - dmaptr = iommu_translate(s->espdmaregs[1]); dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); - cpu_physical_memory_write(dmaptr, buf, len); - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS | INTR_FC; - s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= 1; + DPRINTF("Transfer status len %d\n", dmalen); + if (s->dma) { + dmaptr = iommu_translate(s->espdmaregs[1]); + DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); + cpu_physical_memory_write(dmaptr, buf, len); + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; + s->rregs[5] = INTR_BS | INTR_FC; + s->rregs[6] = SEQ_CD; + s->espdmaregs[0] |= 1; + } else { + memcpy(s->ti_buf, buf, len); + s->ti_size = dmalen; + s->ti_rptr = 0; + s->ti_wptr = 0; + } pic_set_irq(s->irq, 1); } + static const uint8_t okbuf[] = {0, 0}; static void handle_ti(ESPState *s) @@ -188,21 +227,27 @@ static void handle_ti(ESPState *s) uint32_t dmaptr, dmalen; unsigned int i; - dmaptr = iommu_translate(s->espdmaregs[1]); dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen); - DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); - for (i = 0; i < s->ti_size; i++) { - dmaptr = iommu_translate(s->espdmaregs[1] + i); - if (s->ti_dir) - cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); - else - cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); - } - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS; - s->rregs[6] = 0; - s->espdmaregs[0] |= 1; + DPRINTF("Transfer Information len %d\n", dmalen); + if (s->dma) { + dmaptr = iommu_translate(s->espdmaregs[1]); + DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); + for (i = 0; i < s->ti_size; i++) { + dmaptr = iommu_translate(s->espdmaregs[1] + i); + if (s->ti_dir) + cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); + else + cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); + } + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; + s->rregs[5] = INTR_BS; + s->rregs[6] = 0; + s->espdmaregs[0] |= 1; + } else { + s->ti_size = dmalen; + s->ti_rptr = 0; + s->ti_wptr = 0; + } pic_set_irq(s->irq, 1); } @@ -221,10 +266,23 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) saddr = (addr & ESP_MAXREG) >> 2; switch (saddr) { + case 2: + // FIFO + if (s->ti_size > 0) { + s->ti_size--; + s->rregs[saddr] = s->ti_buf[s->ti_rptr++]; + pic_set_irq(s->irq, 1); + } + if (s->ti_size == 0) { + s->ti_rptr = 0; + s->ti_wptr = 0; + } + break; default: break; } DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); + return s->rregs[saddr]; } @@ -236,8 +294,23 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) saddr = (addr & ESP_MAXREG) >> 2; DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); switch (saddr) { + case 0: + case 1: + s->rregs[saddr] = val; + break; + case 2: + // FIFO + s->ti_size++; + s->ti_buf[s->ti_wptr++] = val & 0xff; + break; case 3: + s->rregs[saddr] = val; // Command + if (val & 0x80) { + s->dma = 1; + } else { + s->dma = 0; + } switch(val & 0x7f) { case 0: DPRINTF("NOP (%2.2x)\n", val); @@ -278,13 +351,20 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) handle_satn(s); break; default: - DPRINTF("Unhandled command (%2.2x)\n", val); + DPRINTF("Unhandled ESP command (%2.2x)\n", val); break; } break; case 4 ... 7: - case 9 ... 0xf: break; + case 8: + s->rregs[saddr] = val; + break; + case 9 ... 10: + break; + case 11 ... 15: + s->rregs[saddr] = val; + break; default: break; } @@ -309,7 +389,8 @@ static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) uint32_t saddr; saddr = (addr & ESPDMA_MAXADDR) >> 2; - DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]); + DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]); + return s->espdmaregs[saddr]; } @@ -319,12 +400,23 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va uint32_t saddr; saddr = (addr & ESPDMA_MAXADDR) >> 2; - DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val); + DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val); switch (saddr) { case 0: if (!(val & 0x10)) pic_set_irq(s->irq, 0); + if (val & 0x80) { + esp_reset(s); + } else if (val & 0x40) { + val &= ~0x40; + } else if (val == 0) + val = 0x40; + val &= 0x0fffffff; + val |= DMA_VER; break; + case 1: + s->espdmaregs[0] = DMA_LOADED; + break; default: break; } @@ -353,6 +445,12 @@ static void esp_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->irq); for (i = 0; i < ESPDMA_REGS; i++) qemu_put_be32s(f, &s->espdmaregs[i]); + qemu_put_be32s(f, &s->ti_size); + qemu_put_be32s(f, &s->ti_rptr); + qemu_put_be32s(f, &s->ti_wptr); + qemu_put_be32s(f, &s->ti_dir); + qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); + qemu_put_be32s(f, &s->dma); } static int esp_load(QEMUFile *f, void *opaque, int version_id) @@ -368,6 +466,12 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->irq); for (i = 0; i < ESPDMA_REGS; i++) qemu_get_be32s(f, &s->espdmaregs[i]); + qemu_get_be32s(f, &s->ti_size); + qemu_get_be32s(f, &s->ti_rptr); + qemu_get_be32s(f, &s->ti_wptr); + qemu_get_be32s(f, &s->ti_dir); + qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); + qemu_get_be32s(f, &s->dma); return 0; } -- cgit v1.2.3 From 4e3b1ea1b87237827905292fdb59917ccd252f5c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 17:24:19 +0000 Subject: sparc merge (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1578 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/slavio_misc.c | 11 ++++++++--- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/hw/iommu.c b/hw/iommu.c index d0b16ea88..6defe61ca 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -33,9 +33,11 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define DPRINTF(fmt, args...) #endif -#define IOMMU_NREGS (3*4096) +#define IOMMU_NREGS (3*4096/4) +#define IOMMU_CTRL (0x0000 >> 2) #define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ #define IOMMU_CTRL_VERS 0x0f000000 /* Version */ +#define IOMMU_VERSION 0x04000000 #define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ #define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */ #define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */ @@ -46,6 +48,32 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */ #define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */ #define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */ +#define IOMMU_CTRL_MASK 0x0000001d + +#define IOMMU_BASE (0x0004 >> 2) +#define IOMMU_BASE_MASK 0x07fffc00 + +#define IOMMU_TLBFLUSH (0x0014 >> 2) +#define IOMMU_TLBFLUSH_MASK 0xffffffff + +#define IOMMU_PGFLUSH (0x0018 >> 2) +#define IOMMU_PGFLUSH_MASK 0xffffffff + +#define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */ +#define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */ +#define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */ +#define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configration per-slot */ +#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */ +#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ +#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ +#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses + produced by this device as pure + physical. */ +#define IOMMU_SBCFG_MASK 0x00010003 + +#define IOMMU_ARBEN (0x2000 >> 2) /* SBUS arbitration enable */ +#define IOMMU_ARBEN_MASK 0x001f0000 +#define IOMMU_MID 0x00000008 /* The format of an iopte in the page tables */ #define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ @@ -87,7 +115,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val saddr = (addr - s->addr) >> 2; DPRINTF("write reg[%d] = %x\n", saddr, val); switch (saddr) { - case 0: + case IOMMU_CTRL: switch (val & IOMMU_CTRL_RNGE) { case IOMMU_RNGE_16MB: s->iostart = 0xff000000; @@ -116,7 +144,30 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val break; } DPRINTF("iostart = %x\n", s->iostart); - /* Fall through */ + s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION); + break; + case IOMMU_BASE: + s->regs[saddr] = val & IOMMU_BASE_MASK; + break; + case IOMMU_TLBFLUSH: + DPRINTF("tlb flush %x\n", val); + s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK; + break; + case IOMMU_PGFLUSH: + DPRINTF("page flush %x\n", val); + s->regs[saddr] = val & IOMMU_PGFLUSH_MASK; + break; + case IOMMU_SBCFG0: + case IOMMU_SBCFG1: + case IOMMU_SBCFG2: + case IOMMU_SBCFG3: + s->regs[saddr] = val & IOMMU_SBCFG_MASK; + break; + case IOMMU_ARBEN: + // XXX implement SBus probing: fault when reading unmapped + // addresses, fault cause and address stored to MMU/IOMMU + s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID; + break; default: s->regs[saddr] = val; break; @@ -184,6 +235,7 @@ static void iommu_reset(void *opaque) memset(s->regs, 0, IOMMU_NREGS * 4); s->iostart = 0; + s->regs[0] = IOMMU_VERSION; } void *iommu_init(uint32_t addr) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 597a0cb12..1b681be48 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -44,7 +44,7 @@ typedef struct MiscState { int irq; uint8_t config; uint8_t aux1, aux2; - uint8_t diag, mctrl; + uint8_t diag, mctrl, sysctrl; } MiscState; #define MISC_MAXADDR 1 @@ -64,7 +64,7 @@ static void slavio_misc_reset(void *opaque) { MiscState *s = opaque; - // Diagnostic register not cleared in reset + // Diagnostic and system control registers not cleared in reset s->config = s->aux1 = s->aux2 = s->mctrl = 0; } @@ -116,8 +116,10 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32 break; case 0x1f00000: MISC_DPRINTF("Write system control %2.2x\n", val & 0xff); - if (val & 1) + if (val & 1) { + s->sysctrl = 0x2; qemu_system_reset_request(); + } break; case 0xa000000: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); @@ -158,6 +160,7 @@ static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr) break; case 0x1f00000: MISC_DPRINTF("Read system control %2.2x\n", ret); + ret = s->sysctrl; break; case 0xa000000: MISC_DPRINTF("Read power management %2.2x\n", ret); @@ -188,6 +191,7 @@ static void slavio_misc_save(QEMUFile *f, void *opaque) qemu_put_8s(f, &s->aux2); qemu_put_8s(f, &s->diag); qemu_put_8s(f, &s->mctrl); + qemu_put_8s(f, &s->sysctrl); } static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) @@ -203,6 +207,7 @@ static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->aux2); qemu_get_8s(f, &s->diag); qemu_get_8s(f, &s->mctrl); + qemu_get_8s(f, &s->sysctrl); return 0; } -- cgit v1.2.3 From bb3911a609084dc1c0c72fc25884ef712066bec9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 17:28:50 +0000 Subject: Sparc64 add/sub flag bugs fixed (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1579 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index f8b491a7f..67de62f4c 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -379,7 +379,7 @@ void OPPROTO op_add_T1_T0_cc(void) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) @@ -424,7 +424,7 @@ void OPPROTO op_addx_T1_T0_cc(void) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) @@ -480,7 +480,7 @@ void OPPROTO op_sub_T1_T0_cc(void) env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) env->xcc |= PSR_NEG; - if (T0 < src1) + if (src1 < T1) env->xcc |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) env->xcc |= PSR_OVF; @@ -525,7 +525,7 @@ void OPPROTO op_subx_T1_T0_cc(void) env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) env->xcc |= PSR_NEG; - if (T0 < src1) + if (src1 < T1) env->xcc |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) env->xcc |= PSR_OVF; -- cgit v1.2.3 From a9049a07bbeabe118c97d40e638958a946436b6f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 18:16:26 +0000 Subject: moved common softmmu code to common header (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1580 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_exec.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ target-arm/exec.h | 1 + target-i386/exec.h | 65 +-------------------------------------------------- target-mips/exec.h | 66 +--------------------------------------------------- target-ppc/exec.h | 67 +---------------------------------------------------- target-sparc/exec.h | 66 +--------------------------------------------------- 6 files changed, 70 insertions(+), 260 deletions(-) create mode 100644 softmmu_exec.h diff --git a/softmmu_exec.h b/softmmu_exec.h new file mode 100644 index 000000000..3b789eeb7 --- /dev/null +++ b/softmmu_exec.h @@ -0,0 +1,65 @@ +/* Common softmmu definitions and inline routines. */ + +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel + +#define ACCESS_TYPE 0 +#define MEMSUFFIX _kernel +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ACCESS_TYPE 1 +#define MEMSUFFIX _user +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE 2 +#define MEMSUFFIX _data +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#define ldub(p) ldub_data(p) +#define ldsb(p) ldsb_data(p) +#define lduw(p) lduw_data(p) +#define ldsw(p) ldsw_data(p) +#define ldl(p) ldl_data(p) +#define ldq(p) ldq_data(p) + +#define stb(p, v) stb_data(p, v) +#define stw(p, v) stw_data(p, v) +#define stl(p, v) stl_data(p, v) +#define stq(p, v) stq_data(p, v) diff --git a/target-arm/exec.h b/target-arm/exec.h index 64fce7153..e4ea93f95 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -75,3 +75,4 @@ void do_vfp_cmpes(void); void do_vfp_cmped(void); void do_vfp_set_fpscr(void); void do_vfp_get_fpscr(void); + diff --git a/target-i386/exec.h b/target-i386/exec.h index b1145017d..61ba3cd6d 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -210,72 +210,9 @@ void check_iob_DX(void); void check_iow_DX(void); void check_iol_DX(void); -/* XXX: move that to a generic header */ #if !defined(CONFIG_USER_ONLY) -#define ldul_user ldl_user -#define ldul_kernel ldl_kernel - -#define ACCESS_TYPE 0 -#define MEMSUFFIX _kernel -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ACCESS_TYPE 1 -#define MEMSUFFIX _user -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -/* these access are slower, they must be as rare as possible */ -#define ACCESS_TYPE 2 -#define MEMSUFFIX _data -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ldub(p) ldub_data(p) -#define ldsb(p) ldsb_data(p) -#define lduw(p) lduw_data(p) -#define ldsw(p) ldsw_data(p) -#define ldl(p) ldl_data(p) -#define ldq(p) ldq_data(p) - -#define stb(p, v) stb_data(p, v) -#define stw(p, v) stw_data(p, v) -#define stl(p, v) stl_data(p, v) -#define stq(p, v) stq_data(p, v) +#include "softmmu_exec.h" static inline double ldfq(target_ulong ptr) { diff --git a/target-mips/exec.h b/target-mips/exec.h index 77fce26d2..b3e423493 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -40,71 +40,7 @@ register double FT2 asm(FREG2); #include "exec-all.h" #if !defined(CONFIG_USER_ONLY) - -#define ldul_user ldl_user -#define ldul_kernel ldl_kernel - -#define ACCESS_TYPE 0 -#define MEMSUFFIX _kernel -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ACCESS_TYPE 1 -#define MEMSUFFIX _user -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -/* these access are slower, they must be as rare as possible */ -#define ACCESS_TYPE 2 -#define MEMSUFFIX _data -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ldub(p) ldub_data(p) -#define ldsb(p) ldsb_data(p) -#define lduw(p) lduw_data(p) -#define ldsw(p) ldsw_data(p) -#define ldl(p) ldl_data(p) -#define ldq(p) ldq_data(p) - -#define stb(p, v) stb_data(p, v) -#define stw(p, v) stw_data(p, v) -#define stl(p, v) stl_data(p, v) -#define stq(p, v) stq_data(p, v) - +#include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ static inline void env_to_regs(void) diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 9e8988001..3ef0968bc 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -51,73 +51,8 @@ static inline uint32_t rotl (uint32_t i, int n) return ((i << n) | (i >> (32 - n))); } -/* XXX: move that to a generic header */ #if !defined(CONFIG_USER_ONLY) - -#define ldul_user ldl_user -#define ldul_kernel ldl_kernel - -#define ACCESS_TYPE 0 -#define MEMSUFFIX _kernel -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ACCESS_TYPE 1 -#define MEMSUFFIX _user -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -/* these access are slower, they must be as rare as possible */ -#define ACCESS_TYPE 2 -#define MEMSUFFIX _data -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ldub(p) ldub_data(p) -#define ldsb(p) ldsb_data(p) -#define lduw(p) lduw_data(p) -#define ldsw(p) ldsw_data(p) -#define ldl(p) ldl_data(p) -#define ldq(p) ldq_data(p) - -#define stb(p, v) stb_data(p, v) -#define stw(p, v) stw_data(p, v) -#define stl(p, v) stl_data(p, v) -#define stq(p, v) stq_data(p, v) - +#include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ void do_raise_exception_err (uint32_t exception, int error_code); diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 5f48ba8e6..1b67ef4bf 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -83,71 +83,7 @@ void do_rdpsr(); /* XXX: move that to a generic header */ #if !defined(CONFIG_USER_ONLY) - -#define ldul_user ldl_user -#define ldul_kernel ldl_kernel - -#define ACCESS_TYPE 0 -#define MEMSUFFIX _kernel -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ACCESS_TYPE 1 -#define MEMSUFFIX _user -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -/* these access are slower, they must be as rare as possible */ -#define ACCESS_TYPE 2 -#define MEMSUFFIX _data -#define DATA_SIZE 1 -#include "softmmu_header.h" - -#define DATA_SIZE 2 -#include "softmmu_header.h" - -#define DATA_SIZE 4 -#include "softmmu_header.h" - -#define DATA_SIZE 8 -#include "softmmu_header.h" -#undef ACCESS_TYPE -#undef MEMSUFFIX - -#define ldub(p) ldub_data(p) -#define ldsb(p) ldsb_data(p) -#define lduw(p) lduw_data(p) -#define ldsw(p) ldsw_data(p) -#define ldl(p) ldl_data(p) -#define ldq(p) ldq_data(p) - -#define stb(p, v) stb_data(p, v) -#define stw(p, v) stw_data(p, v) -#define stl(p, v) stl_data(p, v) -#define stq(p, v) stq_data(p, v) - +#include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ static inline void env_to_regs(void) -- cgit v1.2.3 From b3ecf620de718d9cc56b00d145dbd569db2c4a62 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 18:21:23 +0000 Subject: Thumb symbol lookup (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1581 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/disas.c b/disas.c index aea8cfee4..f8d8b9ead 100644 --- a/disas.c +++ b/disas.c @@ -279,6 +279,7 @@ const char *lookup_symbol(target_ulong orig_addr) /* 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; @@ -290,8 +291,13 @@ const char *lookup_symbol(target_ulong orig_addr) if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) continue; - if (orig_addr >= sym[i].st_value - && orig_addr < sym[i].st_value + sym[i].st_size) + 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; } } -- cgit v1.2.3 From 87f48e6a1afbaf14bed8a5c253c874ec4f15edfb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 18:24:49 +0000 Subject: fixed/full keyboard input - full mouse support - support for qemu console (Mike Kronenberg) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1582 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 448 +++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 373 insertions(+), 75 deletions(-) diff --git a/cocoa.m b/cocoa.m index d41517b08..895e96f98 100644 --- a/cocoa.m +++ b/cocoa.m @@ -47,6 +47,9 @@ 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); @@ -171,63 +174,175 @@ static void cocoa_resize(DisplayState *ds, int w, int h) ------------------------------------------------------ */ -static int keymap[] = +int keymap[] = { - 30, //'a' 0x0 - 31, //'s' - 32, //'d' - 33, //'f' - 35, //'h' - 34, //'g' - 44, //'z' - 45, //'x' - 46, //'c' - 47, //'v' - 0, // 0 0x0a - 48, //'b' - 16, //'q' - 17, //'w' - 18, //'e' - 19, //'r' - 21, //'y' 0x10 - 20, //'t' - 2, //'1' - 3, //'2' - 4, //'3' - 5, //'4' - 7, //'6' - 6, //'5' - 0, //'=' - 10, //'9' - 8, //'7' 0x1A - 0, //'-' - 9, //'8' - 11, //'0' - 27, //']' - 24, //'o' - 22, //'u' 0x20 - 26, //'[' - 23, //'i' - 25, //'p' - 28, //'\n' - 38, //'l' - 36, //'j' - 40, //'"' - 37, //'k' - 39, //';' - 15, //'\t' 0x30 - 0, //' ' - 0, //'`' - 14, //'' - 0, //'' 0x34 - 0, //'' - 0, //'' - /* Not completed to finish see http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */ +// 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 +*/ }; -static int cocoa_keycode_to_qemu(int keycode) +int cocoa_keycode_to_qemu(int keycode) { - if(sizeof(keymap) <= keycode) + if((sizeof(keymap)/sizeof(int)) <= keycode) { printf("(cocoa) warning unknow keycode 0x%x\n", keycode); return 0; @@ -246,7 +361,6 @@ static void cocoa_refresh(DisplayState *ds) NSDate *distantPast; NSEvent *event; NSAutoreleasePool *pool; - int grab = 1; pool = [ [ NSAutoreleasePool alloc ] init ]; distantPast = [ NSDate distantPast ]; @@ -258,41 +372,225 @@ static void cocoa_refresh(DisplayState *ds) inMode: NSDefaultRunLoopMode dequeue:YES ]; if (event != nil) { switch ([event type]) { - case NSKeyDown: - if(grab) + case NSFlagsChanged: { int keycode = cocoa_keycode_to_qemu([event keyCode]); + modifiers_state[keycode] = (modifiers_state[keycode] == 0) ? 1 : 0; + + if ( modifiers_state[keycode] ) { /* Keydown */ + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode & 0x7f); + } else { /* Keyup */ + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode | 0x80); + } - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode & 0x7f); + /* emulate caps lock and num lock keyup */ + if ((keycode == 58) || (keycode == 69)) + { + modifiers_state[keycode] = 0; + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode | 0x80); + } + + /* 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); + if (is_active_console(vga_console)) { + /* tell the vga console to redisplay itself */ + vga_invalidate_display(); + break; + } + } + } else { + /* handle standard key events */ + if (is_active_console(vga_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 { + switch([event keyCode]) { + case 123: + kbd_put_keysym(QEMU_KEY_LEFT); + break; + case 124: + kbd_put_keysym(QEMU_KEY_RIGHT); + break; + case 125: + kbd_put_keysym(QEMU_KEY_DOWN); + break; + case 126: + kbd_put_keysym(QEMU_KEY_UP); + break; + default: + kbd_put_keysym([[event characters] characterAtIndex:0]); + break; + } + } + } + } + break; + case NSKeyUp: - if(grab) { - int keycode = cocoa_keycode_to_qemu([event keyCode]); - - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); + int keycode = cocoa_keycode_to_qemu([event keyCode]); + if (is_active_console(vga_console)) { + if (keycode & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key + } } break; - case NSScrollWheel: - + + 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: - - case NSOtherMouseDown: + 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: - - case NSOtherMouseUp: + 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: - - case NSMouseMoved: + if (grab) { + kbd_mouse_event(0, 0, 0, 0); + } else { + [NSApp sendEvent: event]; + } + break; + case NSOtherMouseDragged: - case NSRightMouseDragged: - case NSLeftMouseDragged: + 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]; } -- cgit v1.2.3 From 3b0d4f61c917c4612b561d75b33a11f4da00738b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 18:30:10 +0000 Subject: OS X: support for the built in CD-ROM drive (Mike Kronenberg) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1583 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 18eaf4604..077c27855 100644 --- a/block.c +++ b/block.c @@ -32,9 +32,79 @@ #include #endif +#ifdef CONFIG_COCOA +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#endif + static BlockDriverState *bdrv_first; static BlockDriver *first_drv; +#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 + void bdrv_register(BlockDriver *bdrv) { bdrv->next = first_drv; @@ -117,6 +187,12 @@ static BlockDriver *find_image_format(const char *filename) sectorsize > bufsize) bufsize = sectorsize; } +#endif +#ifdef CONFIG_COCOA + u_int32_t blockSize = 512; + if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { + bufsize = blockSize; + } #endif buf = qemu_malloc(bufsize); if (!buf) @@ -145,6 +221,32 @@ static BlockDriver *find_image_format(const char *filename) int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) { +#ifdef CONFIG_COCOA + if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) { + 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 return bdrv_open2(bs, filename, snapshot, NULL); } @@ -567,7 +669,11 @@ static int raw_open(BlockDriverState *bs, const char *filename) #ifdef DIOCGMEDIASIZE if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) #endif - size = lseek(fd, 0LL, SEEK_END); +#ifdef CONFIG_COCOA + size = LONG_LONG_MAX; +#else + size = lseek(fd, 0LL, SEEK_END); +#endif } else #endif { -- cgit v1.2.3 From 1d14ffa97eacd3cb722271eaf6f093038396eac4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 18:58:22 +0000 Subject: merged 15a_aqemu.patch audio patch (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1584 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 + Makefile.target | 43 +- audio/alsaaudio.c | 926 +++++++++++++++++++++++ audio/audio.c | 1856 +++++++++++++++++++++++++++++++++-------------- audio/audio.h | 90 ++- audio/audio_int.h | 310 +++++--- audio/audio_template.h | 401 ++++++++++ audio/coreaudio.c | 513 +++++++++++++ audio/dsound_template.h | 298 ++++++++ audio/dsoundaudio.c | 1082 +++++++++++++++++++++++++++ audio/fmodaudio.c | 526 ++++++++++---- audio/mixeng.c | 231 +++--- audio/mixeng.h | 26 +- audio/mixeng_template.h | 136 +++- audio/noaudio.c | 164 +++-- audio/ossaudio.c | 588 ++++++++++----- audio/rate_template.h | 111 +++ audio/sdlaudio.c | 327 ++++++--- audio/sys-queue.h | 241 ++++++ audio/wavaudio.c | 160 ++-- configure | 74 +- hw/adlib.c | 285 ++++---- hw/es1370.c | 1007 +++++++++++++++++++++++++ hw/pc.c | 6 +- hw/sb16.c | 266 +++++-- qemu-doc.texi | 19 +- vl.c | 109 ++- vl.h | 4 + 28 files changed, 8179 insertions(+), 1627 deletions(-) create mode 100644 audio/alsaaudio.c create mode 100644 audio/audio_template.h create mode 100644 audio/coreaudio.c create mode 100644 audio/dsound_template.h create mode 100644 audio/dsoundaudio.c create mode 100644 audio/rate_template.h create mode 100644 audio/sys-queue.h create mode 100644 hw/es1370.c diff --git a/Changelog b/Changelog index 3ba685bc2..ea7806544 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,10 @@ +version 0.7.3: + + - Mac OS X cocoa improvements (Mike Kronenberg) + - DirectSound driver (malc) + - new audio options: '-soundhw' and 'audio-help' (malc) + - ES1370 PCI audio device (malc) + version 0.7.2: - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit) diff --git a/Makefile.target b/Makefile.target index 1ca4e3a4c..b1773f4dd 100644 --- a/Makefile.target +++ b/Makefile.target @@ -262,7 +262,7 @@ endif VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o -SOUND_HW = sb16.o +SOUND_HW = sb16.o es1370.o AUDIODRV = audio.o noaudio.o wavaudio.o ifdef CONFIG_SDL AUDIODRV += sdlaudio.o @@ -270,29 +270,38 @@ endif ifdef CONFIG_OSS AUDIODRV += ossaudio.o endif - -pc.o: DEFINES := -DUSE_SB16 $(DEFINES) - -ifdef CONFIG_ADLIB -SOUND_HW += fmopl.o adlib.o +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: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES) LIBS += $(CONFIG_FMOD_LIB) endif +ifdef CONFIG_ADLIB +SOUND_HW += fmopl.o adlib.o +endif ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o +DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o +DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.o @@ -317,7 +326,10 @@ VL_OBJS+=sdl.o endif ifdef CONFIG_COCOA VL_OBJS+=cocoa.o -COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa +COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit +ifdef CONFIG_COREAUDIO +COCOA_LIBS+=-framework CoreAudio +endif endif ifdef CONFIG_SLIRP DEFINES+=-I$(SRC_PATH)/slirp @@ -349,6 +361,10 @@ ifeq ($(ARCH),ia64) VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.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) @@ -364,6 +380,9 @@ sdlaudio.o: sdlaudio.c depend: $(SRCS) $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend +vldepend: $(VL_OBJS:.o=.c) + $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend + # libqemu libqemu.a: $(LIBOBJS) @@ -415,8 +434,6 @@ op.o: op.c op_template.c op_mem.c op_helper.o: op_helper_mem.c endif -mixeng.o: mixeng.c mixeng.h mixeng_template.h - %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< @@ -434,3 +451,9 @@ endif ifneq ($(wildcard .depend),) include .depend endif + +ifeq (0, 1) +audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \ +fmodaudio.o alsaaudio.o mixeng.o: \ +CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare +endif diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c new file mode 100644 index 000000000..133690576 --- /dev/null +++ b/audio/alsaaudio.c @@ -0,0 +1,926 @@ +/* + * QEMU ALSA audio driver + * + * Copyright (c) 2005 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include "vl.h" + +#define AUDIO_CAP "alsa" +#include "audio_int.h" + +typedef struct ALSAVoiceOut { + HWVoiceOut hw; + void *pcm_buf; + snd_pcm_t *handle; + int can_pause; + int was_enabled; +} ALSAVoiceOut; + +typedef struct ALSAVoiceIn { + HWVoiceIn hw; + snd_pcm_t *handle; + void *pcm_buf; + int can_pause; +} ALSAVoiceIn; + +static struct { + int size_in_usec_in; + int size_in_usec_out; + const char *pcm_name_in; + const char *pcm_name_out; + unsigned int buffer_size_in; + unsigned int period_size_in; + unsigned int buffer_size_out; + unsigned int period_size_out; + unsigned int threshold; + + int buffer_size_in_overriden; + int period_size_in_overriden; + + int buffer_size_out_overriden; + int period_size_out_overriden; +} conf = { +#ifdef HIGH_LATENCY + .size_in_usec_in = 1, + .size_in_usec_out = 1, +#endif + .pcm_name_out = "hw:0,0", + .pcm_name_in = "hw:0,0", +#ifdef HIGH_LATENCY + .buffer_size_in = 400000, + .period_size_in = 400000 / 4, + .buffer_size_out = 400000, + .period_size_out = 400000 / 4, +#else +#define DEFAULT_BUFFER_SIZE 1024 +#define DEFAULT_PERIOD_SIZE 256 + .buffer_size_in = DEFAULT_BUFFER_SIZE, + .period_size_in = DEFAULT_PERIOD_SIZE, + .buffer_size_out = DEFAULT_BUFFER_SIZE, + .period_size_out = DEFAULT_PERIOD_SIZE, + .buffer_size_in_overriden = 0, + .buffer_size_out_overriden = 0, + .period_size_in_overriden = 0, + .period_size_out_overriden = 0, +#endif + .threshold = 0 +}; + +struct alsa_params_req { + int freq; + audfmt_e fmt; + int nchannels; + unsigned int buffer_size; + unsigned int period_size; +}; + +struct alsa_params_obt { + int freq; + audfmt_e fmt; + int nchannels; + int can_pause; + snd_pcm_uframes_t buffer_size; +}; + +static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err)); +} + +static void GCC_FMT_ATTR (3, 4) alsa_logerr2 ( + int err, + const char *typ, + const char *fmt, + ... + ) +{ + va_list ap; + + AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err)); +} + +static void alsa_anal_close (snd_pcm_t **handlep) +{ + int err = snd_pcm_close (*handlep); + if (err) { + alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep); + } + *handlep = NULL; +} + +static int alsa_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} + +static int aud_to_alsafmt (audfmt_e fmt) +{ + switch (fmt) { + case AUD_FMT_S8: + return SND_PCM_FORMAT_S8; + + case AUD_FMT_U8: + return SND_PCM_FORMAT_U8; + + case AUD_FMT_S16: + return SND_PCM_FORMAT_S16_LE; + + case AUD_FMT_U16: + return SND_PCM_FORMAT_U16_LE; + + default: + dolog ("Internal logic error: Bad audio format %d\n", fmt); +#ifdef DEBUG_AUDIO + abort (); +#endif + return SND_PCM_FORMAT_U8; + } +} + +static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness) +{ + switch (alsafmt) { + case SND_PCM_FORMAT_S8: + *endianness = 0; + *fmt = AUD_FMT_S8; + break; + + case SND_PCM_FORMAT_U8: + *endianness = 0; + *fmt = AUD_FMT_U8; + break; + + case SND_PCM_FORMAT_S16_LE: + *endianness = 0; + *fmt = AUD_FMT_S16; + break; + + case SND_PCM_FORMAT_U16_LE: + *endianness = 0; + *fmt = AUD_FMT_U16; + break; + + case SND_PCM_FORMAT_S16_BE: + *endianness = 1; + *fmt = AUD_FMT_S16; + break; + + case SND_PCM_FORMAT_U16_BE: + *endianness = 1; + *fmt = AUD_FMT_U16; + break; + + default: + dolog ("Unrecognized audio format %d\n", alsafmt); + return -1; + } + + return 0; +} + +#ifdef DEBUG_MISMATCHES +static void alsa_dump_info (struct alsa_params_req *req, + struct alsa_params_obt *obt) +{ + dolog ("parameter | requested value | obtained value\n"); + dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); + dolog ("channels | %10d | %10d\n", + req->nchannels, obt->nchannels); + dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); + dolog ("============================================\n"); + dolog ("requested: buffer size %d period size %d\n", + req->buffer_size, req->period_size); + dolog ("obtained: buffer size %ld\n", obt->buffer_size); +} +#endif + +static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) +{ + int err; + snd_pcm_sw_params_t *sw_params; + + snd_pcm_sw_params_alloca (&sw_params); + + err = snd_pcm_sw_params_current (handle, sw_params); + if (err < 0) { + dolog ("Can not fully initialize DAC\n"); + alsa_logerr (err, "Failed to get current software parameters\n"); + return; + } + + err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold); + if (err < 0) { + dolog ("Can not fully initialize DAC\n"); + alsa_logerr (err, "Failed to set software threshold to %ld\n", + threshold); + return; + } + + err = snd_pcm_sw_params (handle, sw_params); + if (err < 0) { + dolog ("Can not fully initialize DAC\n"); + alsa_logerr (err, "Failed to set software parameters\n"); + return; + } +} + +static int alsa_open (int in, struct alsa_params_req *req, + struct alsa_params_obt *obt, snd_pcm_t **handlep) +{ + snd_pcm_t *handle; + snd_pcm_hw_params_t *hw_params; + int err, freq, nchannels; + const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out; + unsigned int period_size, buffer_size; + snd_pcm_uframes_t obt_buffer_size; + const char *typ = in ? "ADC" : "DAC"; + + freq = req->freq; + period_size = req->period_size; + buffer_size = req->buffer_size; + nchannels = req->nchannels; + + snd_pcm_hw_params_alloca (&hw_params); + + err = snd_pcm_open ( + &handle, + pcm_name, + in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK + ); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name); + return -1; + } + + err = snd_pcm_hw_params_any (handle, hw_params); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n"); + goto err; + } + + err = snd_pcm_hw_params_set_access ( + handle, + hw_params, + SND_PCM_ACCESS_RW_INTERLEAVED + ); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to set access type\n"); + goto err; + } + + err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt); + goto err; + } + + err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq); + goto err; + } + + err = snd_pcm_hw_params_set_channels_near ( + handle, + hw_params, + &nchannels + ); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to set number of channels %d\n", + req->nchannels); + goto err; + } + + if (nchannels != 1 && nchannels != 2) { + alsa_logerr2 (err, typ, + "Can not handle obtained number of channels %d\n", + nchannels); + goto err; + } + + if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) { + if (!buffer_size) { + buffer_size = DEFAULT_BUFFER_SIZE; + period_size= DEFAULT_PERIOD_SIZE; + } + } + + if (buffer_size) { + if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) { + if (period_size) { + err = snd_pcm_hw_params_set_period_time_near ( + handle, + hw_params, + &period_size, + 0); + if (err < 0) { + alsa_logerr2 (err, typ, + "Failed to set period time %d\n", + req->period_size); + goto err; + } + } + + err = snd_pcm_hw_params_set_buffer_time_near ( + handle, + hw_params, + &buffer_size, + 0); + + if (err < 0) { + alsa_logerr2 (err, typ, + "Failed to set buffer time %d\n", + req->buffer_size); + goto err; + } + } + else { + int dir; + snd_pcm_uframes_t minval; + + if (period_size) { + minval = period_size; + dir = 0; + + err = snd_pcm_hw_params_get_period_size_min ( + hw_params, + &minval, + &dir + ); + if (err < 0) { + alsa_logerr ( + err, + "Can not get minmal period size for %s\n", + typ + ); + } + else { + if (period_size < minval) { + if ((in && conf.period_size_in_overriden) + || (!in && conf.period_size_out_overriden)) { + dolog ("%s period size(%d) is less " + "than minmal period size(%ld)\n", + typ, + period_size, + minval); + } + period_size = minval; + } + } + + err = snd_pcm_hw_params_set_period_size ( + handle, + hw_params, + period_size, + 0 + ); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to set period size %d\n", + req->period_size); + goto err; + } + } + + minval = buffer_size; + err = snd_pcm_hw_params_get_buffer_size_min ( + hw_params, + &minval + ); + if (err < 0) { + alsa_logerr (err, "Can not get minmal buffer size for %s\n", + typ); + } + else { + if (buffer_size < minval) { + if ((in && conf.buffer_size_in_overriden) + || (!in && conf.buffer_size_out_overriden)) { + dolog ( + "%s buffer size(%d) is less " + "than minimal buffer size(%ld)\n", + typ, + buffer_size, + minval + ); + } + buffer_size = minval; + } + } + + err = snd_pcm_hw_params_set_buffer_size ( + handle, + hw_params, + buffer_size + ); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to set buffer size %d\n", + req->buffer_size); + goto err; + } + } + } + else { + dolog ("warning: buffer size is not set\n"); + } + + err = snd_pcm_hw_params (handle, hw_params); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to apply audio parameters\n"); + goto err; + } + + err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size); + if (err < 0) { + alsa_logerr2 (err, typ, "Failed to get buffer size\n"); + goto err; + } + + err = snd_pcm_prepare (handle); + if (err < 0) { + alsa_logerr2 (err, typ, "Can not prepare handle %p\n", handle); + goto err; + } + + obt->can_pause = snd_pcm_hw_params_can_pause (hw_params); + if (obt->can_pause < 0) { + alsa_logerr (err, "Can not get pause capability for %s\n", typ); + obt->can_pause = 0; + } + + if (!in && conf.threshold) { + snd_pcm_uframes_t threshold; + int bytes_per_sec; + + bytes_per_sec = freq + << (nchannels == 2) + << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16); + + threshold = (conf.threshold * bytes_per_sec) / 1000; + alsa_set_threshold (handle, threshold); + } + + obt->fmt = req->fmt; + obt->nchannels = nchannels; + obt->freq = freq; + obt->buffer_size = snd_pcm_frames_to_bytes (handle, obt_buffer_size); + *handlep = handle; + + if (obt->fmt != req->fmt || + obt->nchannels != req->nchannels || + obt->freq != req->freq) { +#ifdef DEBUG_MISMATCHES + dolog ("Audio paramters mismatch for %s\n", typ); + alsa_dump_info (req, obt); +#endif + } + +#ifdef DEBUG + alsa_dump_info (req, obt); +#endif + return 0; + + err: + alsa_anal_close (&handle); + return -1; +} + +static int alsa_recover (snd_pcm_t *handle) +{ + int err = snd_pcm_prepare (handle); + if (err < 0) { + alsa_logerr (err, "Failed to prepare handle %p\n", handle); + return -1; + } + return 0; +} + +static int alsa_run_out (HWVoiceOut *hw) +{ + ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; + int rpos, live, decr; + int samples; + uint8_t *dst; + st_sample_t *src; + snd_pcm_sframes_t avail; + + live = audio_pcm_hw_get_live_out (hw); + if (!live) { + return 0; + } + + avail = snd_pcm_avail_update (alsa->handle); + if (avail < 0) { + if (avail == -EPIPE) { + if (!alsa_recover (alsa->handle)) { + avail = snd_pcm_avail_update (alsa->handle); + if (avail >= 0) { + goto ok; + } + } + } + + alsa_logerr (avail, "Can not get amount free space\n"); + return 0; + } + + ok: + decr = audio_MIN (live, avail); + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int convert_samples = audio_MIN (samples, left_till_end_samples); + snd_pcm_sframes_t written; + + src = hw->mix_buf + rpos; + dst = advance (alsa->pcm_buf, rpos << hw->info.shift); + + hw->clip (dst, src, convert_samples); + + again: + written = snd_pcm_writei (alsa->handle, dst, convert_samples); + + if (written < 0) { + switch (written) { + case -EPIPE: + if (!alsa_recover (alsa->handle)) { + goto again; + } + dolog ( + "Failed to write %d frames to %p, handle %p not prepared\n", + convert_samples, + dst, + alsa->handle + ); + goto exit; + + case -EAGAIN: + goto again; + + default: + alsa_logerr (written, "Failed to write %d frames to %p\n", + convert_samples, dst); + goto exit; + } + } + + mixeng_clear (src, written); + rpos = (rpos + written) % hw->samples; + samples -= written; + } + + exit: + hw->rpos = rpos; + return decr; +} + +static void alsa_fini_out (HWVoiceOut *hw) +{ + ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; + + ldebug ("alsa_fini\n"); + alsa_anal_close (&alsa->handle); + + if (alsa->pcm_buf) { + qemu_free (alsa->pcm_buf); + alsa->pcm_buf = NULL; + } +} + +static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +{ + ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; + struct alsa_params_req req; + struct alsa_params_obt obt; + audfmt_e effective_fmt; + int endianness; + int err; + snd_pcm_t *handle; + + req.fmt = aud_to_alsafmt (fmt); + req.freq = freq; + req.nchannels = nchannels; + req.period_size = conf.period_size_out; + req.buffer_size = conf.buffer_size_out; + + if (alsa_open (0, &req, &obt, &handle)) { + return -1; + } + + err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness); + if (err) { + alsa_anal_close (&handle); + return -1; + } + + audio_pcm_init_info ( + &hw->info, + obt.freq, + obt.nchannels, + effective_fmt, + audio_need_to_swap_endian (endianness) + ); + alsa->can_pause = obt.can_pause; + hw->bufsize = obt.buffer_size; + + alsa->pcm_buf = qemu_mallocz (hw->bufsize); + if (!alsa->pcm_buf) { + alsa_anal_close (&handle); + return -1; + } + + alsa->handle = handle; + alsa->was_enabled = 0; + return 0; +} + +static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...) +{ + int err; + ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; + + switch (cmd) { + case VOICE_ENABLE: + ldebug ("enabling voice\n"); + audio_pcm_info_clear_buf (&hw->info, alsa->pcm_buf, hw->samples); + if (alsa->can_pause) { + /* Why this was_enabled madness is needed at all?? */ + if (alsa->was_enabled) { + err = snd_pcm_pause (alsa->handle, 0); + if (err < 0) { + alsa_logerr (err, "Failed to resume playing\n"); + /* not fatal really */ + } + } + else { + alsa->was_enabled = 1; + } + } + break; + + case VOICE_DISABLE: + ldebug ("disabling voice\n"); + if (alsa->can_pause) { + err = snd_pcm_pause (alsa->handle, 1); + if (err < 0) { + alsa_logerr (err, "Failed to stop playing\n"); + /* not fatal really */ + } + } + break; + } + return 0; +} + +static int alsa_init_in (HWVoiceIn *hw, + int freq, int nchannels, audfmt_e fmt) +{ + ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; + struct alsa_params_req req; + struct alsa_params_obt obt; + int endianness; + int err; + audfmt_e effective_fmt; + snd_pcm_t *handle; + + req.fmt = aud_to_alsafmt (fmt); + req.freq = freq; + req.nchannels = nchannels; + req.period_size = conf.period_size_in; + req.buffer_size = conf.buffer_size_in; + + if (alsa_open (1, &req, &obt, &handle)) { + return -1; + } + + err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness); + if (err) { + alsa_anal_close (&handle); + return -1; + } + + audio_pcm_init_info ( + &hw->info, + obt.freq, + obt.nchannels, + effective_fmt, + audio_need_to_swap_endian (endianness) + ); + alsa->can_pause = obt.can_pause; + hw->bufsize = obt.buffer_size; + alsa->pcm_buf = qemu_mallocz (hw->bufsize); + if (!alsa->pcm_buf) { + alsa_anal_close (&handle); + return -1; + } + + alsa->handle = handle; + return 0; +} + +static void alsa_fini_in (HWVoiceIn *hw) +{ + ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; + + alsa_anal_close (&alsa->handle); + + if (alsa->pcm_buf) { + qemu_free (alsa->pcm_buf); + alsa->pcm_buf = NULL; + } +} + +static int alsa_run_in (HWVoiceIn *hw) +{ + ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; + int hwshift = hw->info.shift; + int i; + int live = audio_pcm_hw_get_live_in (hw); + int dead = hw->samples - live; + struct { + int add; + int len; + } bufs[2] = { + { hw->wpos, 0 }, + { 0, 0 } + }; + + snd_pcm_uframes_t read_samples = 0; + + if (!dead) { + return 0; + } + + if (hw->wpos + dead > hw->samples) { + bufs[0].len = (hw->samples - hw->wpos); + bufs[1].len = (dead - (hw->samples - hw->wpos)); + } + else { + bufs[0].len = dead; + } + + + for (i = 0; i < 2; ++i) { + void *src; + st_sample_t *dst; + snd_pcm_sframes_t nread; + snd_pcm_uframes_t len; + + len = bufs[i].len; + + src = advance (alsa->pcm_buf, bufs[i].add << hwshift); + dst = hw->conv_buf + bufs[i].add; + + while (len) { + nread = snd_pcm_readi (alsa->handle, src, len); + + if (nread < 0) { + switch (nread) { + case -EPIPE: + if (!alsa_recover (alsa->handle)) { + continue; + } + dolog ( + "Failed to read %ld frames from %p, " + "handle %p not prepared\n", + len, + src, + alsa->handle + ); + goto exit; + + case -EAGAIN: + continue; + + default: + alsa_logerr ( + nread, + "Failed to read %ld frames from %p\n", + len, + src + ); + goto exit; + } + } + + hw->conv (dst, src, nread, &nominal_volume); + + src = advance (src, nread << hwshift); + dst += nread; + + read_samples += nread; + len -= nread; + } + } + + exit: + hw->wpos = (hw->wpos + read_samples) % hw->samples; + return read_samples; +} + +static int alsa_read (SWVoiceIn *sw, void *buf, int size) +{ + return audio_pcm_sw_read (sw, buf, size); +} + +static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + +static void *alsa_audio_init (void) +{ + return &conf; +} + +static void alsa_audio_fini (void *opaque) +{ + (void) opaque; +} + +static struct audio_option alsa_options[] = { + {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out, + "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0}, + {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out, + "DAC period size", &conf.period_size_out_overriden, 0}, + {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out, + "DAC buffer size", &conf.buffer_size_out_overriden, 0}, + + {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in, + "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0}, + {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in, + "ADC period size", &conf.period_size_in_overriden, 0}, + {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in, + "ADC buffer size", &conf.buffer_size_in_overriden, 0}, + + {"THRESHOLD", AUD_OPT_INT, &conf.threshold, + "(undocumented)", NULL, 0}, + + {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out, + "DAC device name (for instance dmix)", NULL, 0}, + + {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in, + "ADC device name", NULL, 0}, + {NULL, 0, NULL, NULL, NULL, 0} +}; + +static struct audio_pcm_ops alsa_pcm_ops = { + alsa_init_out, + alsa_fini_out, + alsa_run_out, + alsa_write, + alsa_ctl_out, + + alsa_init_in, + alsa_fini_in, + alsa_run_in, + alsa_read, + alsa_ctl_in +}; + +struct audio_driver alsa_audio_driver = { + INIT_FIELD (name = ) "alsa", + INIT_FIELD (descr = ) "ALSA http://www.alsa-project.org", + INIT_FIELD (options = ) alsa_options, + INIT_FIELD (init = ) alsa_audio_init, + INIT_FIELD (fini = ) alsa_audio_fini, + INIT_FIELD (pcm_ops = ) &alsa_pcm_ops, + INIT_FIELD (can_be_default = ) 1, + INIT_FIELD (max_voices_out = ) INT_MAX, + INIT_FIELD (max_voices_in = ) INT_MAX, + INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut), + INIT_FIELD (voice_size_in = ) sizeof (ALSAVoiceIn) +}; diff --git a/audio/audio.c b/audio/audio.c index 0c0c8dd86..1a3925d4e 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1,8 +1,8 @@ /* * QEMU Audio subsystem - * - * Copyright (c) 2003-2004 Vassili Karpov (malc) - * + * + * Copyright (c) 2003-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -21,34 +21,78 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include #include "vl.h" -#define USE_WAV_AUDIO +#define AUDIO_CAP "audio" +#include "audio_int.h" -#include "audio/audio_int.h" +static void audio_pcm_hw_fini_in (HWVoiceIn *hw); +static void audio_pcm_hw_fini_out (HWVoiceOut *hw); -#define dolog(...) AUD_log ("audio", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif +static LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; +static LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; -#define QC_AUDIO_DRV "QEMU_AUDIO_DRV" -#define QC_VOICES "QEMU_VOICES" -#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT" -#define QC_FIXED_FREQ "QEMU_FIXED_FREQ" +/* #define DEBUG_PLIVE */ +/* #define DEBUG_LIVE */ +/* #define DEBUG_OUT */ -static HWVoice *hw_voices; +static struct audio_driver *drvtab[] = { +#ifdef CONFIG_OSS + &oss_audio_driver, +#endif +#ifdef CONFIG_ALSA + &alsa_audio_driver, +#endif +#ifdef CONFIG_COREAUDIO + &coreaudio_audio_driver, +#endif +#ifdef CONFIG_DSOUND + &dsound_audio_driver, +#endif +#ifdef CONFIG_FMOD + &fmod_audio_driver, +#endif +#ifdef CONFIG_SDL + &sdl_audio_driver, +#endif + &no_audio_driver, + &wav_audio_driver +}; AudioState audio_state = { + /* Out */ + 1, /* use fixed settings */ + 44100, /* fixed frequency */ + 2, /* fixed channels */ + AUD_FMT_S16, /* fixed format */ + 1, /* number of hw voices */ + 1, /* greedy */ + + /* In */ 1, /* use fixed settings */ 44100, /* fixed frequency */ 2, /* fixed channels */ AUD_FMT_S16, /* fixed format */ 1, /* number of hw voices */ - -1 /* voice size */ + 1, /* greedy */ + + NULL, /* driver opaque */ + NULL, /* driver */ + + NULL, /* timer handle */ + { 0 }, /* period */ + 0 /* plive */ +}; + +volume_t nominal_volume = { + 0, +#ifdef FLOAT_MIXENG + 1.0, + 1.0 +#else + UINT_MAX, + UINT_MAX +#endif }; /* http://www.df.lth.se/~john_e/gems/gem002d.html */ @@ -68,275 +112,361 @@ inline uint32_t lsbindex (uint32_t u) return popcount ((u&-u)-1); } -int audio_get_conf_int (const char *key, int defval) +#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED +#error No its not +#else +int audio_bug (const char *funcname, int cond) { - int val = defval; - char *strval; - - strval = getenv (key); - if (strval) { - val = atoi (strval); + if (cond) { + static int shown; + + AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname); + if (!shown) { + shown = 1; + AUD_log (NULL, "Save all your work and restart without audio\n"); + AUD_log (NULL, "Please send bug report to malc@pulsesoft.com\n"); + AUD_log (NULL, "I am sorry\n"); + } + AUD_log (NULL, "Context:\n"); + +#if defined AUDIO_BREAKPOINT_ON_BUG +# if defined HOST_I386 +# if defined __GNUC__ + __asm__ ("int3"); +# elif defined _MSC_VER + _asm _emit 0xcc; +# else + abort (); +# endif +# else + abort (); +# endif +#endif } - return val; + return cond; } +#endif -const char *audio_get_conf_str (const char *key, const char *defval) +static char *audio_alloc_prefix (const char *s) { - const char *val = getenv (key); - if (!val) - return defval; - else - return val; -} + const char qemu_prefix[] = "QEMU_"; + size_t len; + char *r; -void AUD_log (const char *cap, const char *fmt, ...) -{ - va_list ap; - fprintf (stderr, "%s: ", cap); - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); -} + if (!s) { + return NULL; + } -/* - * Soft Voice - */ -void pcm_sw_free_resources (SWVoice *sw) -{ - if (sw->buf) qemu_free (sw->buf); - if (sw->rate) st_rate_stop (sw->rate); - sw->buf = NULL; - sw->rate = NULL; -} + len = strlen (s); + r = qemu_malloc (len + sizeof (qemu_prefix)); -int pcm_sw_alloc_resources (SWVoice *sw) -{ - sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t)); - if (!sw->buf) - return -1; + if (r) { + size_t i; + char *u = r + sizeof (qemu_prefix) - 1; - sw->rate = st_rate_start (sw->freq, sw->hw->freq); - if (!sw->rate) { - qemu_free (sw->buf); - sw->buf = NULL; - return -1; + strcpy (r, qemu_prefix); + strcat (r, s); + + for (i = 0; i < len; ++i) { + u[i] = toupper (u[i]); + } } - return 0; + return r; } -void pcm_sw_fini (SWVoice *sw) +const char *audio_audfmt_to_string (audfmt_e fmt) { - pcm_sw_free_resources (sw); -} + switch (fmt) { + case AUD_FMT_U8: + return "U8"; -int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, - int nchannels, audfmt_e fmt) -{ - int bits = 8, sign = 0; + case AUD_FMT_U16: + return "U16"; - switch (fmt) { case AUD_FMT_S8: - sign = 1; - case AUD_FMT_U8: - break; + return "S8"; case AUD_FMT_S16: - sign = 1; - case AUD_FMT_U16: - bits = 16; - break; + return "S16"; } - sw->hw = hw; - sw->freq = freq; - sw->fmt = fmt; - sw->nchannels = nchannels; - sw->shift = (nchannels == 2) + (bits == 16); - sw->align = (1 << sw->shift) - 1; - sw->left = 0; - sw->pos = 0; - sw->wpos = 0; - sw->live = 0; - sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq; - sw->bytes_per_second = sw->freq << sw->shift; - sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16]; - - pcm_sw_free_resources (sw); - return pcm_sw_alloc_resources (sw); -} - -/* Hard voice */ -void pcm_hw_free_resources (HWVoice *hw) -{ - if (hw->mix_buf) - qemu_free (hw->mix_buf); - hw->mix_buf = NULL; + dolog ("Bogus audfmt %d returning S16\n", fmt); + return "S16"; } -int pcm_hw_alloc_resources (HWVoice *hw) +audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp) { - hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); - if (!hw->mix_buf) - return -1; - return 0; + if (!strcasecmp (s, "u8")) { + *defaultp = 0; + return AUD_FMT_U8; + } + else if (!strcasecmp (s, "u16")) { + *defaultp = 0; + return AUD_FMT_U16; + } + else if (!strcasecmp (s, "s8")) { + *defaultp = 0; + return AUD_FMT_S8; + } + else if (!strcasecmp (s, "s16")) { + *defaultp = 0; + return AUD_FMT_S16; + } + else { + dolog ("Bogus audio format `%s' using %s\n", + s, audio_audfmt_to_string (defval)); + *defaultp = 1; + return defval; + } } -void pcm_hw_fini (HWVoice *hw) +static audfmt_e audio_get_conf_fmt (const char *envname, + audfmt_e defval, + int *defaultp) { - if (hw->active) { - ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt); - pcm_hw_free_resources (hw); - hw->pcm_ops->fini (hw); - memset (hw, 0, audio_state.drv->voice_size); + const char *var = getenv (envname); + if (!var) { + *defaultp = 1; + return defval; } + return audio_string_to_audfmt (var, defval, defaultp); } -void pcm_hw_gc (HWVoice *hw) +static int audio_get_conf_int (const char *key, int defval, int *defaultp) { - if (hw->nb_voices) - return; + int val; + char *strval; - pcm_hw_fini (hw); + strval = getenv (key); + if (strval) { + *defaultp = 0; + val = atoi (strval); + return val; + } + else { + *defaultp = 1; + return defval; + } } -int pcm_hw_get_live (HWVoice *hw) +static const char *audio_get_conf_str (const char *key, + const char *defval, + int *defaultp) { - int i, alive = 0, live = hw->samples; - - for (i = 0; i < hw->nb_voices; i++) { - if (hw->pvoice[i]->live) { - live = audio_MIN (hw->pvoice[i]->live, live); - alive += 1; - } + const char *val = getenv (key); + if (!val) { + *defaultp = 1; + return defval; + } + else { + *defaultp = 0; + return val; } - - if (alive) - return live; - else - return -1; } -int pcm_hw_get_live2 (HWVoice *hw, int *nb_active) +void AUD_log (const char *cap, const char *fmt, ...) { - int i, alive = 0, live = hw->samples; - - *nb_active = 0; - for (i = 0; i < hw->nb_voices; i++) { - if (hw->pvoice[i]->live) { - if (hw->pvoice[i]->live < live) { - *nb_active = hw->pvoice[i]->active != 0; - live = hw->pvoice[i]->live; - } - alive += 1; - } + va_list ap; + if (cap) { + fprintf (stderr, "%s: ", cap); } - - if (alive) - return live; - else - return -1; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); } -void pcm_hw_dec_live (HWVoice *hw, int decr) +void AUD_vlog (const char *cap, const char *fmt, va_list ap) { - int i; - - for (i = 0; i < hw->nb_voices; i++) { - if (hw->pvoice[i]->live) { - hw->pvoice[i]->live -= decr; - } + if (cap) { + fprintf (stderr, "%s: ", cap); } + vfprintf (stderr, fmt, ap); } -void pcm_hw_clear (HWVoice *hw, void *buf, int len) +static void audio_print_options (const char *prefix, + struct audio_option *opt) { - if (!len) + char *uprefix; + + if (!prefix) { + dolog ("No prefix specified\n"); + return; + } + + if (!opt) { + dolog ("No options\n"); return; + } - switch (hw->fmt) { - case AUD_FMT_S16: - case AUD_FMT_S8: - memset (buf, len << hw->shift, 0x00); - break; + uprefix = audio_alloc_prefix (prefix); - case AUD_FMT_U8: - memset (buf, len << hw->shift, 0x80); - break; + for (; opt->name; opt++) { + const char *state = "default"; + printf (" %s_%s: ", uprefix, opt->name); - case AUD_FMT_U16: - { - unsigned int i; - uint16_t *p = buf; - int shift = hw->nchannels - 1; + if (opt->overridenp && *opt->overridenp) { + state = "current"; + } - for (i = 0; i < len << shift; i++) { - p[i] = INT16_MAX; + switch (opt->tag) { + case AUD_OPT_BOOL: + { + int *intp = opt->valp; + printf ("boolean, %s = %d\n", state, *intp ? 1 : 0); + } + break; + + case AUD_OPT_INT: + { + int *intp = opt->valp; + printf ("integer, %s = %d\n", state, *intp); + } + break; + + case AUD_OPT_FMT: + { + audfmt_e *fmtp = opt->valp; + printf ( + "format, %s = %s, (one of: U8 S8 U16 S16)\n", + state, + audio_audfmt_to_string (*fmtp) + ); + } + break; + + case AUD_OPT_STR: + { + const char **strp = opt->valp; + printf ("string, %s = %s\n", + state, + *strp ? *strp : "(not set)"); } + break; + + default: + printf ("???\n"); + dolog ("Bad value tag for option %s_%s %d\n", + uprefix, opt->name, opt->tag); + break; } - break; + printf (" %s\n", opt->descr); } + + qemu_free (uprefix); } -int pcm_hw_write (SWVoice *sw, void *buf, int size) +static void audio_process_options (const char *prefix, + struct audio_option *opt) { - int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck; - int ret = 0, pos = 0; - if (!sw) - return size; + char *optname; + const char qemu_prefix[] = "QEMU_"; + size_t preflen; - hwsamples = sw->hw->samples; - samples = size >> sw->shift; + if (audio_bug (AUDIO_FUNC, !prefix)) { + dolog ("prefix = NULL\n"); + return; + } - if (!sw->live) { - sw->wpos = sw->hw->rpos; + if (audio_bug (AUDIO_FUNC, !opt)) { + dolog ("opt = NULL\n"); + return; } - wpos = sw->wpos; - live = sw->live; - dead = hwsamples - live; - swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio; - swlim = audio_MIN (swlim, samples); - ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n", - size, live, dead, swlim, wpos); - if (swlim) - sw->conv (sw->buf, buf, swlim); + preflen = strlen (prefix); - while (swlim) { - dead = hwsamples - live; - left = hwsamples - wpos; - blck = audio_MIN (dead, left); - if (!blck) { - /* dolog ("swlim=%d\n", swlim); */ + for (; opt->name; opt++) { + size_t len, i; + int def; + + if (!opt->valp) { + dolog ("Option value pointer for `%s' is not set\n", + opt->name); + continue; + } + + len = strlen (opt->name); + optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1); + if (!optname) { + dolog ("Can not allocate memory for option name `%s'\n", + opt->name); + continue; + } + + strcpy (optname, qemu_prefix); + for (i = 0; i <= preflen; ++i) { + optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]); + } + strcat (optname, "_"); + strcat (optname, opt->name); + + def = 1; + switch (opt->tag) { + case AUD_OPT_BOOL: + case AUD_OPT_INT: + { + int *intp = opt->valp; + *intp = audio_get_conf_int (optname, *intp, &def); + } + break; + + case AUD_OPT_FMT: + { + audfmt_e *fmtp = opt->valp; + *fmtp = audio_get_conf_fmt (optname, *fmtp, &def); + } + break; + + case AUD_OPT_STR: + { + const char **strp = opt->valp; + *strp = audio_get_conf_str (optname, *strp, &def); + } + break; + + default: + dolog ("Bad value tag for option `%s' - %d\n", + optname, opt->tag); break; } - isamp = swlim; - osamp = blck; - st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp); - ret += isamp; - swlim -= isamp; - pos += isamp; - live += osamp; - wpos = (wpos + osamp) % hwsamples; - } - sw->wpos = wpos; - sw->live = live; - return ret << sw->shift; + if (!opt->overridenp) { + opt->overridenp = &opt->overriden; + } + *opt->overridenp = !def; + qemu_free (optname); + } } -int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +static int audio_pcm_info_eq (struct audio_pcm_info *info, int freq, + int nchannels, audfmt_e fmt) { - int sign = 0, bits = 8; + int bits = 8, sign = 0; - pcm_hw_fini (hw); - ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt); - if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) { - memset (hw, 0, audio_state.drv->voice_size); - return -1; + switch (fmt) { + case AUD_FMT_S8: + sign = 1; + case AUD_FMT_U8: + break; + + case AUD_FMT_S16: + sign = 1; + case AUD_FMT_U16: + bits = 16; + break; } + return info->freq == freq + && info->nchannels == nchannels + && info->sign == sign + && info->bits == bits; +} - switch (hw->fmt) { +void audio_pcm_init_info (struct audio_pcm_info *info, int freq, + int nchannels, audfmt_e fmt, int swap_endian) +{ + int bits = 8, sign = 0; + + switch (fmt) { case AUD_FMT_S8: sign = 1; case AUD_FMT_U8: @@ -349,425 +479,595 @@ int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) break; } - hw->nb_voices = 0; - hw->active = 1; - hw->shift = (hw->nchannels == 2) + (bits == 16); - hw->bytes_per_second = hw->freq << hw->shift; - hw->align = (1 << hw->shift) - 1; - hw->samples = hw->bufsize >> hw->shift; - hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16]; - if (pcm_hw_alloc_resources (hw)) { - pcm_hw_fini (hw); - return -1; - } - return 0; + info->freq = freq; + info->bits = bits; + info->sign = sign; + info->nchannels = nchannels; + info->shift = (nchannels == 2) + (bits == 16); + info->align = (1 << info->shift) - 1; + info->bytes_per_second = info->freq << info->shift; + info->swap_endian = swap_endian; } -static int dist (void *hw) +void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) { - if (hw) { - return (((uint8_t *) hw - (uint8_t *) hw_voices) - / audio_state.drv->voice_size) + 1; + if (!len) { + return; + } + + if (info->sign) { + memset (buf, len << info->shift, 0x00); } else { - return 0; + if (info->bits == 8) { + memset (buf, len << info->shift, 0x80); + } + else { + int i; + uint16_t *p = buf; + int shift = info->nchannels - 1; + short s = INT16_MAX; + + if (info->swap_endian) { + s = bswap16 (s); + } + + for (i = 0; i < len << shift; i++) { + p[i] = s; + } + } } } -#define ADVANCE(hw) \ - ((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices) - -HWVoice *pcm_hw_find_any (HWVoice *hw) +/* + * Hard voice (capture) + */ +static void audio_pcm_hw_free_resources_in (HWVoiceIn *hw) { - int i = dist (hw); - for (; i < audio_state.nb_hw_voices; i++) { - hw = ADVANCE (hw); - return hw; + if (hw->conv_buf) { + qemu_free (hw->conv_buf); } - return NULL; + hw->conv_buf = NULL; } -HWVoice *pcm_hw_find_any_active (HWVoice *hw) +static int audio_pcm_hw_alloc_resources_in (HWVoiceIn *hw) { - int i = dist (hw); - for (; i < audio_state.nb_hw_voices; i++) { - hw = ADVANCE (hw); - if (hw->active) - return hw; + hw->conv_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); + if (!hw->conv_buf) { + return -1; } - return NULL; + return 0; } -HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw) +static int audio_pcm_hw_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) { - int i = dist (hw); - for (; i < audio_state.nb_hw_voices; i++) { - hw = ADVANCE (hw); - if (hw->active && hw->enabled) - return hw; + audio_pcm_hw_fini_in (hw); + + if (hw->pcm_ops->init_in (hw, freq, nchannels, fmt)) { + memset (hw, 0, audio_state.drv->voice_size_in); + return -1; } - return NULL; + LIST_INIT (&hw->sw_head); + hw->active = 1; + hw->samples = hw->bufsize >> hw->info.shift; + hw->conv = + mixeng_conv + [nchannels == 2] + [hw->info.sign] + [hw->info.swap_endian] + [hw->info.bits == 16]; + if (audio_pcm_hw_alloc_resources_in (hw)) { + audio_pcm_hw_free_resources_in (hw); + return -1; + } + return 0; } -HWVoice *pcm_hw_find_any_passive (HWVoice *hw) +static uint64_t audio_pcm_hw_find_min_in (HWVoiceIn *hw) { - int i = dist (hw); - for (; i < audio_state.nb_hw_voices; i++) { - hw = ADVANCE (hw); - if (!hw->active) - return hw; + SWVoiceIn *sw; + int m = hw->total_samples_captured; + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (sw->active) { + m = audio_MIN (m, sw->total_hw_samples_acquired); + } } - return NULL; + return m; } -HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq, - int nchannels, audfmt_e fmt) +int audio_pcm_hw_get_live_in (HWVoiceIn *hw) { - while ((hw = pcm_hw_find_any_active (hw))) { - if (hw->freq == freq && - hw->nchannels == nchannels && - hw->fmt == fmt) - return hw; + int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw); + if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + dolog ("live=%d hw->samples=%d\n", live, hw->samples); + return 0; } - return NULL; + return live; } -HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt) +/* + * Soft voice (capture) + */ +static void audio_pcm_sw_free_resources_in (SWVoiceIn *sw) { - HWVoice *hw; - - if (audio_state.fixed_format) { - freq = audio_state.fixed_freq; - nchannels = audio_state.fixed_channels; - fmt = audio_state.fixed_fmt; + if (sw->conv_buf) { + qemu_free (sw->conv_buf); } - hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt); - - if (hw) - return hw; - - hw = pcm_hw_find_any_passive (NULL); - if (hw) { - hw->pcm_ops = audio_state.drv->pcm_ops; - if (!hw->pcm_ops) - return NULL; - - if (pcm_hw_init (hw, freq, nchannels, fmt)) { - pcm_hw_gc (hw); - return NULL; - } - else - return hw; + if (sw->rate) { + st_rate_stop (sw->rate); } - return pcm_hw_find_any (NULL); + sw->conv_buf = NULL; + sw->rate = NULL; } -int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw) +static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw) { - SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw)); - if (!pvoice) + int samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; + sw->conv_buf = qemu_mallocz (samples * sizeof (st_sample_t)); + if (!sw->conv_buf) { return -1; + } - memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw)); - qemu_free (hw->pvoice); - hw->pvoice = pvoice; - hw->pvoice[hw->nb_voices++] = sw; + sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq); + if (!sw->rate) { + qemu_free (sw->conv_buf); + sw->conv_buf = NULL; + return -1; + } return 0; } -int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw) +static int audio_pcm_sw_init_in (SWVoiceIn *sw, HWVoiceIn *hw, const char *name, + int freq, int nchannels, audfmt_e fmt) { - int i, j; - if (hw->nb_voices > 1) { - SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw)); + audio_pcm_init_info (&sw->info, freq, nchannels, fmt, + /* None of the cards emulated by QEMU are big-endian + hence following shortcut */ + audio_need_to_swap_endian (0)); + sw->hw = hw; + sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq; - if (!pvoice) { - dolog ("Can not maintain consistent state (not enough memory)\n"); - return -1; - } + sw->clip = + mixeng_clip + [nchannels == 2] + [sw->info.sign] + [sw->info.swap_endian] + [sw->info.bits == 16]; - for (i = 0, j = 0; i < hw->nb_voices; i++) { - if (j >= hw->nb_voices - 1) { - dolog ("Can not maintain consistent state " - "(invariant violated)\n"); - return -1; - } - if (hw->pvoice[i] != sw) - pvoice[j++] = hw->pvoice[i]; - } - qemu_free (hw->pvoice); - hw->pvoice = pvoice; - hw->nb_voices -= 1; + sw->name = qemu_strdup (name); + audio_pcm_sw_free_resources_in (sw); + return audio_pcm_sw_alloc_resources_in (sw); +} + +static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw) +{ + HWVoiceIn *hw = sw->hw; + int live = hw->total_samples_captured - sw->total_hw_samples_acquired; + int rpos; + + if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + dolog ("live=%d hw->samples=%d\n", live, hw->samples); + return 0; + } + + rpos = hw->wpos - live; + if (rpos >= 0) { + return rpos; } else { - qemu_free (hw->pvoice); - hw->pvoice = NULL; - hw->nb_voices = 0; + return hw->samples + rpos; } - return 0; } -SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt) +int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) { - SWVoice *sw; - HWVoice *hw; + HWVoiceIn *hw = sw->hw; + int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0; + st_sample_t *src, *dst = sw->conv_buf; + + rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples; + + live = hw->total_samples_captured - sw->total_hw_samples_acquired; + if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + dolog ("live_in=%d hw->samples=%d\n", live, hw->samples); + return 0; + } + + samples = size >> sw->info.shift; + if (!live) { + return 0; + } - sw = qemu_mallocz (sizeof (*sw)); - if (!sw) - goto err1; + swlim = (live * sw->ratio) >> 32; + swlim = audio_MIN (swlim, samples); - hw = pcm_hw_add (freq, nchannels, fmt); - if (!hw) - goto err2; + while (swlim) { + src = hw->conv_buf + rpos; + isamp = hw->wpos - rpos; + /* XXX: <= ? */ + if (isamp <= 0) { + isamp = hw->samples - rpos; + } - if (pcm_hw_add_sw (hw, sw)) - goto err3; + if (!isamp) { + break; + } + osamp = swlim; - if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) - goto err4; + if (audio_bug (AUDIO_FUNC, osamp < 0)) { + dolog ("osamp=%d\n", osamp); + } - return sw; + st_rate_flow (sw->rate, src, dst, &isamp, &osamp); + swlim -= osamp; + rpos = (rpos + isamp) % hw->samples; + dst += osamp; + ret += osamp; + total += isamp; + } -err4: - pcm_hw_del_sw (hw, sw); -err3: - pcm_hw_gc (hw); -err2: - qemu_free (sw); -err1: - return NULL; + sw->clip (buf, sw->conv_buf, ret); + sw->total_hw_samples_acquired += total; + return ret << sw->info.shift; } -SWVoice *AUD_open (SWVoice *sw, const char *name, - int freq, int nchannels, audfmt_e fmt) +/* + * Hard voice (playback) + */ +static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) { - if (!audio_state.drv) { - return NULL; + SWVoiceOut *sw; + int m = INT_MAX; + int nb_live = 0; + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (sw->active || !sw->empty) { + m = audio_MIN (m, sw->total_hw_samples_mixed); + nb_live += 1; + } } - if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) { - return sw; + *nb_livep = nb_live; + return m; +} + +static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw) +{ + if (hw->mix_buf) { + qemu_free (hw->mix_buf); } - if (sw) { - ldebug ("Different format %s %d %d %d\n", - name, - sw->freq == freq, - sw->nchannels == nchannels, - sw->fmt == fmt); + hw->mix_buf = NULL; +} + +static int audio_pcm_hw_alloc_resources_out (HWVoiceOut *hw) +{ + hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); + if (!hw->mix_buf) { + return -1; } - if (nchannels != 1 && nchannels != 2) { - dolog ("Bogus channel count %d for voice %s\n", nchannels, name); - return NULL; + return 0; +} + +static int audio_pcm_hw_init_out (HWVoiceOut *hw, int freq, + int nchannels, audfmt_e fmt) +{ + audio_pcm_hw_fini_out (hw); + if (hw->pcm_ops->init_out (hw, freq, nchannels, fmt)) { + memset (hw, 0, audio_state.drv->voice_size_out); + return -1; } - if (!audio_state.fixed_format && sw) { - pcm_sw_fini (sw); - pcm_hw_del_sw (sw->hw, sw); - pcm_hw_gc (sw->hw); - if (sw->name) { - qemu_free (sw->name); - sw->name = NULL; - } - qemu_free (sw); - sw = NULL; + LIST_INIT (&hw->sw_head); + hw->active = 1; + hw->samples = hw->bufsize >> hw->info.shift; + hw->clip = + mixeng_clip + [nchannels == 2] + [hw->info.sign] + [hw->info.swap_endian] + [hw->info.bits == 16]; + if (audio_pcm_hw_alloc_resources_out (hw)) { + audio_pcm_hw_fini_out (hw); + return -1; } + return 0; +} - if (sw) { - HWVoice *hw = sw->hw; - if (!hw) { - dolog ("Internal logic error voice %s has no hardware store\n", - name); - return sw; - } +int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live) +{ + int smin; - if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) { - pcm_sw_fini (sw); - pcm_hw_del_sw (hw, sw); - pcm_hw_gc (hw); - if (sw->name) { - qemu_free (sw->name); - sw->name = NULL; - } - qemu_free (sw); - return NULL; - } + smin = audio_pcm_hw_find_min_out (hw, nb_live); + + if (!*nb_live) { + return 0; } else { - sw = pcm_create_voice_pair (freq, nchannels, fmt); - if (!sw) { - dolog ("Failed to create voice %s\n", name); - return NULL; + int live = smin; + + if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + dolog ("live=%d hw->samples=%d\n", live, hw->samples); + return 0; } + return live; } +} + +int audio_pcm_hw_get_live_out (HWVoiceOut *hw) +{ + int nb_live; + int live; - if (sw->name) { - qemu_free (sw->name); - sw->name = NULL; + live = audio_pcm_hw_get_live_out2 (hw, &nb_live); + if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + dolog ("live=%d hw->samples=%d\n", live, hw->samples); + return 0; } - sw->name = qemu_strdup (name); - return sw; + return live; } -void AUD_close (SWVoice *sw) +/* + * Soft voice (playback) + */ +static void audio_pcm_sw_free_resources_out (SWVoiceOut *sw) { - if (!sw) - return; + if (sw->buf) { + qemu_free (sw->buf); + } - pcm_sw_fini (sw); - pcm_hw_del_sw (sw->hw, sw); - pcm_hw_gc (sw->hw); - if (sw->name) { - qemu_free (sw->name); - sw->name = NULL; + if (sw->rate) { + st_rate_stop (sw->rate); } - qemu_free (sw); + + sw->buf = NULL; + sw->rate = NULL; } -int AUD_write (SWVoice *sw, void *buf, int size) +static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw) { - int bytes; + sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t)); + if (!sw->buf) { + return -1; + } - if (!sw->hw->enabled) - dolog ("Writing to disabled voice %s\n", sw->name); - bytes = sw->hw->pcm_ops->write (sw, buf, size); - return bytes; + sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq); + if (!sw->rate) { + qemu_free (sw->buf); + sw->buf = NULL; + return -1; + } + return 0; } -void AUD_run (void) +static int audio_pcm_sw_init_out (SWVoiceOut *sw, HWVoiceOut *hw, + const char *name, int freq, + int nchannels, audfmt_e fmt) { - HWVoice *hw = NULL; - - while ((hw = pcm_hw_find_any_active_enabled (hw))) { - int i; - if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) { - hw->enabled = 0; - hw->pcm_ops->ctl (hw, VOICE_DISABLE); - for (i = 0; i < hw->nb_voices; i++) { - hw->pvoice[i]->live = 0; - /* hw->pvoice[i]->old_ticks = 0; */ - } - continue; - } + audio_pcm_init_info (&sw->info, freq, nchannels, fmt, + /* None of the cards emulated by QEMU are big-endian + hence following shortcut */ + audio_need_to_swap_endian (0)); + sw->hw = hw; + sw->empty = 1; + sw->active = 0; + sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq; + sw->total_hw_samples_mixed = 0; + + sw->conv = + mixeng_conv + [nchannels == 2] + [sw->info.sign] + [sw->info.swap_endian] + [sw->info.bits == 16]; + sw->name = qemu_strdup (name); - hw->pcm_ops->run (hw); - assert (hw->rpos < hw->samples); - for (i = 0; i < hw->nb_voices; i++) { - SWVoice *sw = hw->pvoice[i]; - if (!sw->active && !sw->live && sw->old_ticks) { - int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks; - if (delta > audio_state.ticks_threshold) { - ldebug ("resetting old_ticks for %s\n", sw->name); - sw->old_ticks = 0; - } - } - } - } + audio_pcm_sw_free_resources_out (sw); + return audio_pcm_sw_alloc_resources_out (sw); } -int AUD_get_free (SWVoice *sw) +int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) { - int free; + int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck; + int ret = 0, pos = 0, total = 0; - if (!sw) - return 4096; + if (!sw) { + return size; + } - free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio - / INT_MAX; + hwsamples = sw->hw->samples; - free &= ~sw->hw->align; - if (!free) return 0; + live = sw->total_hw_samples_mixed; + if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){ + dolog ("live=%d hw->samples=%d\n", live, hwsamples); + return 0; + } - return free; -} + if (live == hwsamples) { + return 0; + } -int AUD_get_buffer_size (SWVoice *sw) -{ - return sw->hw->bufsize; -} + wpos = (sw->hw->rpos + live) % hwsamples; + samples = size >> sw->info.shift; -void AUD_adjust (SWVoice *sw, int bytes) -{ - if (!sw) - return; - sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second; + dead = hwsamples - live; + swlim = ((int64_t) dead << 32) / sw->ratio; + swlim = audio_MIN (swlim, samples); + if (swlim) { + sw->conv (sw->buf, buf, swlim, &sw->vol); + } + + while (swlim) { + dead = hwsamples - live; + left = hwsamples - wpos; + blck = audio_MIN (dead, left); + if (!blck) { + break; + } + isamp = swlim; + osamp = blck; + st_rate_flow_mix ( + sw->rate, + sw->buf + pos, + sw->hw->mix_buf + wpos, + &isamp, + &osamp + ); + ret += isamp; + swlim -= isamp; + pos += isamp; + live += osamp; + wpos = (wpos + osamp) % hwsamples; + total += osamp; + } + + sw->total_hw_samples_mixed += total; + sw->empty = sw->total_hw_samples_mixed == 0; + +#ifdef DEBUG_OUT + dolog ( + "%s: write size %d ret %d total sw %d, hw %d\n", + sw->name, + size >> sw->info.shift, + ret, + sw->total_hw_samples_mixed, + sw->hw->total_samples_played + ); +#endif + + return ret << sw->info.shift; } -void AUD_reset (SWVoice *sw) +#ifdef DEBUG_AUDIO +static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info) { - sw->active = 0; - sw->old_ticks = 0; + dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n", + cap, info->bits, info->sign, info->freq, info->nchannels); } +#endif -int AUD_calc_elapsed (SWVoice *sw) +#define DAC +#include "audio_template.h" +#undef DAC +#include "audio_template.h" + +int AUD_write (SWVoiceOut *sw, void *buf, int size) { - int64_t now, delta, bytes; - int dead, swlim; + int bytes; - if (!sw) - return 0; + if (!sw) { + /* XXX: Consider options */ + return size; + } - now = qemu_get_clock (vm_clock); - delta = now - sw->old_ticks; - bytes = (delta * sw->bytes_per_second) / ticks_per_sec; - if (delta < 0) { - dolog ("whoops delta(<0)=%lld\n", delta); + if (!sw->hw->enabled) { + dolog ("Writing to disabled voice %s\n", sw->name); return 0; } - dead = sw->hw->samples - sw->live; - swlim = ((dead * (int64_t) INT_MAX) / sw->ratio); + bytes = sw->hw->pcm_ops->write (sw, buf, size); + return bytes; +} + +int AUD_read (SWVoiceIn *sw, void *buf, int size) +{ + int bytes; - if (bytes > swlim) { - return swlim; + if (!sw) { + /* XXX: Consider options */ + return size; } - else { - return bytes; + + if (!sw->hw->enabled) { + dolog ("Reading from disabled voice %s\n", sw->name); + return 0; } + + bytes = sw->hw->pcm_ops->read (sw, buf, size); + return bytes; } -void AUD_enable (SWVoice *sw, int on) +int AUD_get_buffer_size_out (SWVoiceOut *sw) { - int i; - HWVoice *hw; + return sw->hw->bufsize; +} + +void AUD_set_active_out (SWVoiceOut *sw, int on) +{ + HWVoiceOut *hw; - if (!sw) + if (!sw) { return; + } hw = sw->hw; - if (on) { - if (!sw->live) - sw->wpos = sw->hw->rpos; - if (!sw->old_ticks) { - sw->old_ticks = qemu_get_clock (vm_clock); + if (sw->active != on) { + SWVoiceOut *temp_sw; + + if (on) { + int total; + + hw->pending_disable = 0; + if (!hw->enabled) { + hw->enabled = 1; + hw->pcm_ops->ctl_out (hw, VOICE_ENABLE); + } + + if (sw->empty) { + total = 0; + } + } + else { + if (hw->enabled) { + int nb_active = 0; + + for (temp_sw = hw->sw_head.lh_first; temp_sw; + temp_sw = temp_sw->entries.le_next) { + nb_active += temp_sw->active != 0; + } + + hw->pending_disable = nb_active == 1; + } } + sw->active = on; + } +} + +void AUD_set_active_in (SWVoiceIn *sw, int on) +{ + HWVoiceIn *hw; + + if (!sw) { + return; } + hw = sw->hw; if (sw->active != on) { + SWVoiceIn *temp_sw; + if (on) { - hw->pending_disable = 0; if (!hw->enabled) { hw->enabled = 1; - for (i = 0; i < hw->nb_voices; i++) { - ldebug ("resetting voice\n"); - sw = hw->pvoice[i]; - sw->old_ticks = qemu_get_clock (vm_clock); - } - hw->pcm_ops->ctl (hw, VOICE_ENABLE); + hw->pcm_ops->ctl_in (hw, VOICE_ENABLE); } + sw->total_hw_samples_acquired = hw->total_samples_captured; } else { - if (hw->enabled && !hw->pending_disable) { + if (hw->enabled) { int nb_active = 0; - for (i = 0; i < hw->nb_voices; i++) { - nb_active += hw->pvoice[i]->active != 0; + + for (temp_sw = hw->sw_head.lh_first; temp_sw; + temp_sw = temp_sw->entries.le_next) { + nb_active += temp_sw->active != 0; } if (nb_active == 1) { - hw->pending_disable = 1; + hw->enabled = 0; + hw->pcm_ops->ctl_in (hw, VOICE_DISABLE); } } } @@ -775,118 +1075,547 @@ void AUD_enable (SWVoice *sw, int on) } } -static struct audio_output_driver *drvtab[] = { -#ifdef CONFIG_OSS - &oss_output_driver, +static int audio_get_avail (SWVoiceIn *sw) +{ + int live; + + if (!sw) { + return 0; + } + + live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; + if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { + dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); + return 0; + } + + ldebug ( + "%s: get_avail live %d ret %lld\n", + sw->name, + live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift + ); + + return (((int64_t) live << 32) / sw->ratio) << sw->info.shift; +} + +static int audio_get_free (SWVoiceOut *sw) +{ + int live, dead; + + if (!sw) { + return 0; + } + + live = sw->total_hw_samples_mixed; + + if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { + dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); + } + + dead = sw->hw->samples - live; + +#ifdef DEBUG_OUT + dolog ("%s: get_free live %d dead %d ret %lld\n", + sw->name, + live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); #endif -#ifdef CONFIG_FMOD - &fmod_output_driver, + + return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; +} + +static void audio_run_out (void) +{ + HWVoiceOut *hw = NULL; + SWVoiceOut *sw; + + while ((hw = audio_pcm_hw_find_any_active_enabled_out (hw))) { + int played; + int live, free, nb_live; + + live = audio_pcm_hw_get_live_out2 (hw, &nb_live); + if (!nb_live) { + live = 0; + } + if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { + dolog ("live=%d hw->samples=%d\n", live, hw->samples); + } + + if (hw->pending_disable && !nb_live) { +#ifdef DEBUG_OUT + dolog ("Disabling voice\n"); #endif -#ifdef CONFIG_SDL - &sdl_output_driver, + hw->enabled = 0; + hw->pending_disable = 0; + hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); + continue; + } + + if (!live) { + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (sw->active) { + free = audio_get_free (sw); + if (free > 0) { + sw->callback.fn (sw->callback.opaque, free); + } + } + } + continue; + } + + played = hw->pcm_ops->run_out (hw); + if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { + dolog ("hw->rpos=%d hw->samples=%d played=%d\n", + hw->rpos, hw->samples, played); + hw->rpos = 0; + } + +#ifdef DEBUG_OUT + dolog ("played = %d total %d\n", played, hw->total_samples_played); #endif - &no_output_driver, -#ifdef USE_WAV_AUDIO - &wav_output_driver, + + if (played) { + hw->ts_helper += played; + } + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + again: + if (!sw->active && sw->empty) { + continue; + } + + if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) { + dolog ("played=%d sw->total_hw_samples_mixed=%d\n", + played, sw->total_hw_samples_mixed); + played = sw->total_hw_samples_mixed; + } + + sw->total_hw_samples_mixed -= played; + + if (!sw->total_hw_samples_mixed) { + sw->empty = 1; + + if (!sw->active && !sw->callback.fn) { + SWVoiceOut *temp = sw->entries.le_next; + +#ifdef DEBUG_PLIVE + dolog ("Finishing with old voice\n"); #endif + AUD_close_out (sw); + sw = temp; + if (sw) { + goto again; + } + else { + break; + } + } + } + + if (sw->active) { + free = audio_get_free (sw); + if (free > 0) { + sw->callback.fn (sw->callback.opaque, free); + } + } + } + } +} + +static void audio_run_in (void) +{ + HWVoiceIn *hw = NULL; + + while ((hw = audio_pcm_hw_find_any_active_enabled_in (hw))) { + SWVoiceIn *sw; + int captured, min; + + captured = hw->pcm_ops->run_in (hw); + + min = audio_pcm_hw_find_min_in (hw); + hw->total_samples_captured += captured - min; + hw->ts_helper += captured; + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + sw->total_hw_samples_acquired -= min; + + if (sw->active) { + int avail; + + avail = audio_get_avail (sw); + if (avail > 0) { + sw->callback.fn (sw->callback.opaque, avail); + } + } + } + } +} + +static struct audio_option audio_options[] = { + /* DAC */ + {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out, + "Use fixed settings for host DAC", NULL, 0}, + + {"DAC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out, + "Frequency for fixed host DAC", NULL, 0}, + + {"DAC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out, + "Format for fixed host DAC", NULL, 0}, + + {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_out, + "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0}, + + {"DAC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out, + "Number of voices for DAC", NULL, 0}, + + /* ADC */ + {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out, + "Use fixed settings for host ADC", NULL, 0}, + + {"ADC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out, + "Frequency for fixed ADC", NULL, 0}, + + {"ADC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out, + "Format for fixed ADC", NULL, 0}, + + {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_in, + "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0}, + + {"ADC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out, + "Number of voices for ADC", NULL, 0}, + + /* Misc */ + {"TIMER_PERIOD", AUD_OPT_INT, &audio_state.period.usec, + "Timer period in microseconds (0 - try lowest possible)", NULL, 0}, + + {"PLIVE", AUD_OPT_BOOL, &audio_state.plive, + "(undocumented)", NULL, 0}, + + {NULL, 0, NULL, NULL, NULL, 0} }; -static int voice_init (struct audio_output_driver *drv) +void AUD_help (void) +{ + size_t i; + + audio_process_options ("AUDIO", audio_options); + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { + struct audio_driver *d = drvtab[i]; + if (d->options) { + audio_process_options (d->name, d->options); + } + } + + printf ("Audio options:\n"); + audio_print_options ("AUDIO", audio_options); + printf ("\n"); + + printf ("Available drivers:\n"); + + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { + struct audio_driver *d = drvtab[i]; + + printf ("Name: %s\n", d->name); + printf ("Description: %s\n", d->descr); + + switch (d->max_voices_out) { + case 0: + printf ("Does not support DAC\n"); + break; + case 1: + printf ("One DAC voice\n"); + break; + case INT_MAX: + printf ("Theoretically supports many DAC voices\n"); + break; + default: + printf ("Theoretically supports upto %d DAC voices\n", + d->max_voices_out); + break; + } + + switch (d->max_voices_in) { + case 0: + printf ("Does not support ADC\n"); + break; + case 1: + printf ("One ADC voice\n"); + break; + case INT_MAX: + printf ("Theoretically supports many ADC voices\n"); + break; + default: + printf ("Theoretically supports upto %d ADC voices\n", + d->max_voices_in); + break; + } + + if (d->options) { + printf ("Options:\n"); + audio_print_options (d->name, d->options); + } + else { + printf ("No options\n"); + } + printf ("\n"); + } + + printf ( + "Options are settable through environment variables.\n" + "Example:\n" +#ifdef _WIN32 + " set QEMU_AUDIO_DRV=wav\n" + " set QEMU_WAV_PATH=c:/tune.wav\n" +#else + " export QEMU_AUDIO_DRV=wav\n" + " export QEMU_WAV_PATH=$HOME/tune.wav\n" + "(for csh replace export with setenv in the above)\n" +#endif + " qemu ...\n\n" + ); +} + +void audio_timer (void *opaque) +{ + AudioState *s = opaque; + + audio_run_out (); + audio_run_in (); + + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks); +} + +static int audio_driver_init (struct audio_driver *drv) { + if (drv->options) { + audio_process_options (drv->name, drv->options); + } audio_state.opaque = drv->init (); + if (audio_state.opaque) { - if (audio_state.nb_hw_voices > drv->max_voices) { - dolog ("`%s' does not support %d multiple hardware channels\n" - "Resetting to %d\n", - drv->name, audio_state.nb_hw_voices, drv->max_voices); - audio_state.nb_hw_voices = drv->max_voices; + int i; + HWVoiceOut *hwo; + HWVoiceIn *hwi; + + if (audio_state.nb_hw_voices_out > drv->max_voices_out) { + if (!drv->max_voices_out) { + dolog ("`%s' does not support DAC\n", drv->name); + } + else { + dolog ( + "`%s' does not support %d multiple DAC voicess\n" + "Resetting to %d\n", + drv->name, + audio_state.nb_hw_voices_out, + drv->max_voices_out + ); + } + audio_state.nb_hw_voices_out = drv->max_voices_out; } - hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size); - if (hw_voices) { - audio_state.drv = drv; - return 1; + + LIST_INIT (&hw_head_out); + hwo = qemu_mallocz (audio_state.nb_hw_voices_out * drv->voice_size_out); + if (!hwo) { + dolog ( + "Not enough memory for %d `%s' DAC voices (each %d bytes)\n", + audio_state.nb_hw_voices_out, + drv->name, + drv->voice_size_out + ); + drv->fini (audio_state.opaque); + return -1; } - else { - dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n", - audio_state.nb_hw_voices, drv->name, drv->voice_size); + + for (i = 0; i < audio_state.nb_hw_voices_out; ++i) { + LIST_INSERT_HEAD (&hw_head_out, hwo, entries); + hwo = advance (hwo, drv->voice_size_out); + } + + if (!drv->voice_size_in && drv->max_voices_in) { + ldebug ("warning: No ADC voice size defined for `%s'\n", + drv->name); + drv->max_voices_in = 0; + } + + if (!drv->voice_size_out && drv->max_voices_out) { + ldebug ("warning: No DAC voice size defined for `%s'\n", + drv->name); + } + + if (drv->voice_size_in && !drv->max_voices_in) { + ldebug ("warning: ADC voice size is %d for ADC less driver `%s'\n", + drv->voice_size_out, drv->name); + } + + if (drv->voice_size_out && !drv->max_voices_out) { + ldebug ("warning: DAC voice size is %d for DAC less driver `%s'\n", + drv->voice_size_in, drv->name); + } + + if (audio_state.nb_hw_voices_in > drv->max_voices_in) { + if (!drv->max_voices_in) { + ldebug ("`%s' does not support ADC\n", drv->name); + } + else { + dolog ( + "`%s' does not support %d multiple ADC voices\n" + "Resetting to %d\n", + drv->name, + audio_state.nb_hw_voices_in, + drv->max_voices_in + ); + } + audio_state.nb_hw_voices_in = drv->max_voices_in; + } + + LIST_INIT (&hw_head_in); + hwi = qemu_mallocz (audio_state.nb_hw_voices_in * drv->voice_size_in); + if (!hwi) { + dolog ( + "Not enough memory for %d `%s' ADC voices (each %d bytes)\n", + audio_state.nb_hw_voices_in, + drv->name, + drv->voice_size_in + ); + qemu_free (hwo); drv->fini (audio_state.opaque); - return 0; + return -1; + } + + for (i = 0; i < audio_state.nb_hw_voices_in; ++i) { + LIST_INSERT_HEAD (&hw_head_in, hwi, entries); + hwi = advance (hwi, drv->voice_size_in); } + + audio_state.drv = drv; + return 0; } else { - dolog ("Could not init `%s' audio\n", drv->name); - return 0; + dolog ("Could not init `%s' audio driver\n", drv->name); + return -1; } } static void audio_vm_stop_handler (void *opaque, int reason) { - HWVoice *hw = NULL; + HWVoiceOut *hwo = NULL; + HWVoiceIn *hwi = NULL; + int op = reason ? VOICE_ENABLE : VOICE_DISABLE; + + (void) opaque; + while ((hwo = audio_pcm_hw_find_any_out (hwo))) { + if (!hwo->pcm_ops) { + continue; + } + + if (hwo->enabled != reason) { + hwo->pcm_ops->ctl_out (hwo, op); + } + } - while ((hw = pcm_hw_find_any (hw))) { - if (!hw->pcm_ops) + while ((hwi = audio_pcm_hw_find_any_in (hwi))) { + if (!hwi->pcm_ops) { continue; + } - hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE); + if (hwi->enabled != reason) { + hwi->pcm_ops->ctl_in (hwi, op); + } } } static void audio_atexit (void) { - HWVoice *hw = NULL; + HWVoiceOut *hwo = NULL; + HWVoiceIn *hwi = NULL; + + while ((hwo = audio_pcm_hw_find_any_out (hwo))) { + if (!hwo->pcm_ops) { + continue; + } + + if (hwo->enabled) { + hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); + } + hwo->pcm_ops->fini_out (hwo); + } - while ((hw = pcm_hw_find_any (hw))) { - if (!hw->pcm_ops) + while ((hwi = audio_pcm_hw_find_any_in (hwi))) { + if (!hwi->pcm_ops) { continue; + } - hw->pcm_ops->ctl (hw, VOICE_DISABLE); - hw->pcm_ops->fini (hw); + if (hwi->enabled) { + hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE); + } + hwi->pcm_ops->fini_in (hwi); } audio_state.drv->fini (audio_state.opaque); } static void audio_save (QEMUFile *f, void *opaque) { + (void) f; + (void) opaque; } static int audio_load (QEMUFile *f, void *opaque, int version_id) { - if (version_id != 1) + (void) f; + (void) opaque; + + if (version_id != 1) { return -EINVAL; + } return 0; } void AUD_init (void) { - int i; + size_t i; int done = 0; const char *drvname; + AudioState *s = &audio_state; + + audio_process_options ("AUDIO", audio_options); + + if (s->nb_hw_voices_out <= 0) { + dolog ("Bogus number of DAC voices %d\n", + s->nb_hw_voices_out); + s->nb_hw_voices_out = 1; + } + + if (s->nb_hw_voices_in <= 0) { + dolog ("Bogus number of ADC voices %d\n", + s->nb_hw_voices_in); + s->nb_hw_voices_in = 1; + } - audio_state.fixed_format = - !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format); - audio_state.fixed_freq = - audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq); - audio_state.nb_hw_voices = - audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices); + { + int def; + drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def); + } - if (audio_state.nb_hw_voices <= 0) { - dolog ("Bogus number of voices %d, resetting to 1\n", - audio_state.nb_hw_voices); + s->ts = qemu_new_timer (vm_clock, audio_timer, s); + if (!s->ts) { + dolog ("Can not create audio timer\n"); + return; } - drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL); if (drvname) { int found = 0; + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { if (!strcmp (drvname, drvtab[i]->name)) { - done = voice_init (drvtab[i]); + done = !audio_driver_init (drvtab[i]); found = 1; break; } } + if (!found) { dolog ("Unknown audio driver `%s'\n", drvname); + dolog ("Run with -audio-help to list available drivers\n"); } } @@ -895,17 +1624,32 @@ void AUD_init (void) if (!done) { for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { - if (drvtab[i]->can_be_default) - done = voice_init (drvtab[i]); + if (drvtab[i]->can_be_default) { + done = !audio_driver_init (drvtab[i]); + } } } - audio_state.ticks_threshold = ticks_per_sec / 50; - audio_state.freq_threshold = 100; - register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); if (!done) { - dolog ("Can not initialize audio subsystem\n"); - voice_init (&no_output_driver); + if (audio_driver_init (&no_audio_driver)) { + dolog ("Can not initialize audio subsystem\n"); + } + else { + dolog ("warning: using timer based audio emulation\n"); + } } + + if (s->period.usec <= 0) { + if (s->period.usec < 0) { + dolog ("warning: timer period is negative - %d treating as zero\n", + s->period.usec); + } + s->period.ticks = 1; + } + else { + s->period.ticks = (ticks_per_sec * s->period.usec) / 1000000; + } + + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks); } diff --git a/audio/audio.h b/audio/audio.h index 7520383a4..6dd2fd22e 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -1,8 +1,8 @@ /* * QEMU Audio subsystem header - * - * Copyright (c) 2003-2004 Vassili Karpov (malc) - * + * + * Copyright (c) 2003-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -24,7 +24,7 @@ #ifndef QEMU_AUDIO_H #define QEMU_AUDIO_H -#include "mixeng.h" +typedef void (*audio_callback_fn_t) (void *opaque, int avail); typedef enum { AUD_FMT_U8, @@ -33,22 +33,60 @@ typedef enum { AUD_FMT_S16 } audfmt_e; -typedef struct SWVoice SWVoice; +typedef struct SWVoiceOut SWVoiceOut; +typedef struct SWVoiceIn SWVoiceIn; + +typedef struct QEMUAudioTimeStamp { + uint64_t old_ts; +} QEMUAudioTimeStamp; + +void AUD_vlog (const char *cap, const char *fmt, va_list ap); +void AUD_log (const char *cap, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__ ((__format__ (__printf__, 2, 3))) +#endif + ; -SWVoice * AUD_open (SWVoice *sw, const char *name, int freq, - int nchannels, audfmt_e fmt); -void AUD_init (void); -void AUD_log (const char *cap, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 2, 3)));; -void AUD_close (SWVoice *sw); -int AUD_write (SWVoice *sw, void *pcm_buf, int size); -void AUD_adjust (SWVoice *sw, int leftover); -void AUD_reset (SWVoice *sw); -int AUD_get_free (SWVoice *sw); -int AUD_get_buffer_size (SWVoice *sw); -void AUD_run (void); -void AUD_enable (SWVoice *sw, int on); -int AUD_calc_elapsed (SWVoice *sw); +void AUD_init (void); +void AUD_help (void); + +SWVoiceOut *AUD_open_out ( + SWVoiceOut *sw, + const char *name, + void *callback_opaque, + audio_callback_fn_t callback_fn, + int freq, + int nchannels, + audfmt_e fmt + ); +void AUD_close_out (SWVoiceOut *sw); +int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size); +int AUD_get_buffer_size_out (SWVoiceOut *sw); +void AUD_set_active_out (SWVoiceOut *sw, int on); +int AUD_is_active_out (SWVoiceOut *sw); +void AUD_init_time_stamp_out (SWVoiceOut *sw, + QEMUAudioTimeStamp *ts); +uint64_t AUD_time_stamp_get_elapsed_usec_out (SWVoiceOut *sw, + QEMUAudioTimeStamp *ts); + +SWVoiceIn *AUD_open_in ( + SWVoiceIn *sw, + const char *name, + void *callback_opaque, + audio_callback_fn_t callback_fn, + int freq, + int nchannels, + audfmt_e fmt + ); +void AUD_close_in (SWVoiceIn *sw); +int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size); +void AUD_adjust_in (SWVoiceIn *sw, int leftover); +void AUD_set_active_in (SWVoiceIn *sw, int on); +int AUD_is_active_in (SWVoiceIn *sw); +void AUD_init_time_stamp_in (SWVoiceIn *sw, + QEMUAudioTimeStamp *ts); +uint64_t AUD_time_stamp_get_elapsed_usec_in (SWVoiceIn *sw, + QEMUAudioTimeStamp *ts); static inline void *advance (void *p, int incr) { @@ -59,7 +97,21 @@ static inline void *advance (void *p, int incr) uint32_t popcount (uint32_t u); inline uint32_t lsbindex (uint32_t u); +#ifdef __GNUC__ +#define audio_MIN(a, b) ( __extension__ ({ \ + __typeof (a) ta = a; \ + __typeof (b) tb = b; \ + ((ta)>(tb)?(tb):(ta)); \ +})) + +#define audio_MAX(a, b) ( __extension__ ({ \ + __typeof (a) ta = a; \ + __typeof (b) tb = b; \ + ((ta)<(tb)?(tb):(ta)); \ +})) +#else #define audio_MIN(a, b) ((a)>(b)?(b):(a)) #define audio_MAX(a, b) ((a)<(b)?(b):(a)) +#endif #endif /* audio.h */ diff --git a/audio/audio_int.h b/audio/audio_int.h index 0be2a6166..9d288292a 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -1,8 +1,8 @@ /* * QEMU Audio subsystem header - * - * Copyright (c) 2003-2004 Vassili Karpov (malc) - * + * + * Copyright (c) 2003-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -24,140 +24,266 @@ #ifndef QEMU_AUDIO_INT_H #define QEMU_AUDIO_INT_H -#include "vl.h" +#include "sys-queue.h" + +#ifdef CONFIG_COREAUDIO +#define FLOAT_MIXENG +/* #define RECIPROCAL */ +#endif +#include "mixeng.h" + +int audio_bug (const char *funcname, int cond); + +struct audio_pcm_ops; + +typedef enum { + AUD_OPT_INT, + AUD_OPT_FMT, + AUD_OPT_STR, + AUD_OPT_BOOL +} audio_option_tag_e; + +struct audio_option { + const char *name; + audio_option_tag_e tag; + void *valp; + const char *descr; + int *overridenp; + int overriden; +}; + +struct audio_callback { + void *opaque; + audio_callback_fn_t fn; +}; -struct pcm_ops; +struct audio_pcm_info { + int bits; + int sign; + int freq; + int nchannels; + int align; + int shift; + int bytes_per_second; + int swap_endian; +}; -typedef struct HWVoice { +typedef struct HWVoiceOut { int active; int enabled; int pending_disable; int valid; - int freq; + struct audio_pcm_info info; f_sample *clip; - audfmt_e fmt; - int nchannels; - - int align; - int shift; int rpos; int bufsize; + uint64_t ts_helper; - int bytes_per_second; st_sample_t *mix_buf; int samples; - int64_t old_ticks; - int nb_voices; - struct SWVoice **pvoice; - struct pcm_ops *pcm_ops; -} HWVoice; + LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; + struct audio_pcm_ops *pcm_ops; + LIST_ENTRY (HWVoiceOut) entries; +} HWVoiceOut; -extern struct pcm_ops no_pcm_ops; -extern struct audio_output_driver no_output_driver; +typedef struct HWVoiceIn { + int enabled; + int active; + struct audio_pcm_info info; + + t_sample *conv; -extern struct pcm_ops oss_pcm_ops; -extern struct audio_output_driver oss_output_driver; + int wpos; + int bufsize; + int total_samples_captured; + uint64_t ts_helper; -extern struct pcm_ops sdl_pcm_ops; -extern struct audio_output_driver sdl_output_driver; + st_sample_t *conv_buf; -extern struct pcm_ops wav_pcm_ops; -extern struct audio_output_driver wav_output_driver; + int samples; + LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; + struct audio_pcm_ops *pcm_ops; + LIST_ENTRY (HWVoiceIn) entries; +} HWVoiceIn; -extern struct pcm_ops fmod_pcm_ops; -extern struct audio_output_driver fmod_output_driver; +extern struct audio_driver no_audio_driver; +extern struct audio_driver oss_audio_driver; +extern struct audio_driver sdl_audio_driver; +extern struct audio_driver wav_audio_driver; +extern struct audio_driver fmod_audio_driver; +extern struct audio_driver alsa_audio_driver; +extern struct audio_driver coreaudio_audio_driver; +extern struct audio_driver dsound_audio_driver; +extern volume_t nominal_volume; -struct audio_output_driver { +struct audio_driver { const char *name; + const char *descr; + struct audio_option *options; void *(*init) (void); void (*fini) (void *); - struct pcm_ops *pcm_ops; + struct audio_pcm_ops *pcm_ops; int can_be_default; - int max_voices; - int voice_size; + int max_voices_out; + int max_voices_in; + int voice_size_out; + int voice_size_in; }; typedef struct AudioState { - int fixed_format; - int fixed_freq; - int fixed_channels; - int fixed_fmt; - int nb_hw_voices; - int64_t ticks_threshold; - int freq_threshold; + int fixed_settings_out; + int fixed_freq_out; + int fixed_channels_out; + int fixed_fmt_out; + int nb_hw_voices_out; + int greedy_out; + + int fixed_settings_in; + int fixed_freq_in; + int fixed_channels_in; + int fixed_fmt_in; + int nb_hw_voices_in; + int greedy_in; + void *opaque; - struct audio_output_driver *drv; -} AudioState; -extern AudioState audio_state; + struct audio_driver *drv; -struct SWVoice { - int freq; - audfmt_e fmt; - int nchannels; + QEMUTimer *ts; + union { + int usec; + int64_t ticks; + } period; - int shift; - int align; + int plive; +} AudioState; +extern AudioState audio_state; +struct SWVoiceOut { + struct audio_pcm_info info; t_sample *conv; - - int left; - int pos; - int bytes_per_second; int64_t ratio; st_sample_t *buf; void *rate; + int total_hw_samples_mixed; + int active; + int empty; + HWVoiceOut *hw; + char *name; + volume_t vol; + struct audio_callback callback; + LIST_ENTRY (SWVoiceOut) entries; +}; - int wpos; - int live; +struct SWVoiceIn { int active; - int64_t old_ticks; - HWVoice *hw; + struct audio_pcm_info info; + int64_t ratio; + void *rate; + int total_hw_samples_acquired; + st_sample_t *conv_buf; + f_sample *clip; + HWVoiceIn *hw; char *name; + volume_t vol; + struct audio_callback callback; + LIST_ENTRY (SWVoiceIn) entries; }; -struct pcm_ops { - int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt); - void (*fini) (HWVoice *hw); - void (*run) (HWVoice *hw); - int (*write) (SWVoice *sw, void *buf, int size); - int (*ctl) (HWVoice *hw, int cmd, ...); +struct audio_pcm_ops { + int (*init_out)(HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt); + void (*fini_out)(HWVoiceOut *hw); + int (*run_out) (HWVoiceOut *hw); + int (*write) (SWVoiceOut *sw, void *buf, int size); + int (*ctl_out) (HWVoiceOut *hw, int cmd, ...); + + int (*init_in) (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt); + void (*fini_in) (HWVoiceIn *hw); + int (*run_in) (HWVoiceIn *hw); + int (*read) (SWVoiceIn *sw, void *buf, int size); + int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); }; -void pcm_sw_free_resources (SWVoice *sw); -int pcm_sw_alloc_resources (SWVoice *sw); -void pcm_sw_fini (SWVoice *sw); -int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, - int nchannels, audfmt_e fmt); - -void pcm_hw_clear (HWVoice *hw, void *buf, int len); -HWVoice * pcm_hw_find_any (HWVoice *hw); -HWVoice * pcm_hw_find_any_active (HWVoice *hw); -HWVoice * pcm_hw_find_any_passive (HWVoice *hw); -HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq, - int nchannels, audfmt_e fmt); -HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt); -int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw); -int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw); -SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt); - -void pcm_hw_free_resources (HWVoice *hw); -int pcm_hw_alloc_resources (HWVoice *hw); -void pcm_hw_fini (HWVoice *hw); -void pcm_hw_gc (HWVoice *hw); -int pcm_hw_get_live (HWVoice *hw); -int pcm_hw_get_live2 (HWVoice *hw, int *nb_active); -void pcm_hw_dec_live (HWVoice *hw, int decr); -int pcm_hw_write (SWVoice *sw, void *buf, int len); - -int audio_get_conf_int (const char *key, int defval); -const char *audio_get_conf_str (const char *key, const char *defval); - -struct audio_output_driver; +void audio_pcm_init_info (struct audio_pcm_info *info, int freq, + int nchannels, audfmt_e fmt, int swap_endian); +void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); + +int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len); +int audio_pcm_hw_get_live_in (HWVoiceIn *hw); + +int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len); +int audio_pcm_hw_get_live_out (HWVoiceOut *hw); +int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live); #define VOICE_ENABLE 1 #define VOICE_DISABLE 2 +static inline int audio_ring_dist (int dst, int src, int len) +{ + return (dst >= src) ? (dst - src) : (len - src + dst); +} + +static inline int audio_need_to_swap_endian (int endianness) +{ +#ifdef WORDS_BIGENDIAN + return endianness != 1; +#else + return endianness != 0; +#endif +} + +#if defined __GNUC__ +#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2))) +#define INIT_FIELD(f) . f +#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (printf, n, m))) +#else +#define GCC_ATTR /**/ +#define INIT_FIELD(f) /**/ +#define GCC_FMT_ATTR(n, m) +#endif + +static void GCC_ATTR dolog (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); +} + +#ifdef DEBUG +static void GCC_ATTR ldebug (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); +} +#else +#if defined NDEBUG && defined __GNUC__ +#define ldebug(...) +#elif defined NDEBUG && defined _MSC_VER +#define ldebug __noop +#else +static void GCC_ATTR ldebug (const char *fmt, ...) +{ + (void) fmt; +} +#endif +#endif + +#undef GCC_ATTR + +#define AUDIO_STRINGIFY_(n) #n +#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n) + +#if defined _MSC_VER || defined __GNUC__ +#define AUDIO_FUNC __FUNCTION__ +#else +#define AUDIO_FUNC __FILE__ ":" AUDIO_STRINGIFY (__LINE__) +#endif + #endif /* audio_int.h */ diff --git a/audio/audio_template.h b/audio/audio_template.h new file mode 100644 index 000000000..25ea72fd4 --- /dev/null +++ b/audio/audio_template.h @@ -0,0 +1,401 @@ +/* + * QEMU Audio subsystem header + * + * Copyright (c) 2005 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifdef DAC +#define TYPE out +#define HW glue (HWVoice, Out) +#define SW glue (SWVoice, Out) +#else +#define TYPE in +#define HW glue (HWVoice, In) +#define SW glue (SWVoice, In) +#endif + +static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) +{ + glue (audio_pcm_sw_free_resources_, TYPE) (sw); + if (sw->name) { + qemu_free (sw->name); + sw->name = NULL; + } +} + +static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw) +{ + LIST_INSERT_HEAD (&hw->sw_head, sw, entries); +} + +static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) +{ + LIST_REMOVE (sw, entries); +} + +static void glue (audio_pcm_hw_fini_, TYPE) (HW *hw) +{ + if (hw->active) { + glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); + glue (hw->pcm_ops->fini_, TYPE) (hw); + memset (hw, 0, glue (audio_state.drv->voice_size_, TYPE)); + } +} + +static void glue (audio_pcm_hw_gc_, TYPE) (HW *hw) +{ + if (!hw->sw_head.lh_first) { + glue (audio_pcm_hw_fini_, TYPE) (hw); + } +} + +static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw) +{ + return hw ? hw->entries.le_next : glue (hw_head_, TYPE).lh_first; +} + +static HW *glue (audio_pcm_hw_find_any_active_, TYPE) (HW *hw) +{ + while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { + if (hw->active) { + return hw; + } + } + return NULL; +} + +static HW *glue (audio_pcm_hw_find_any_active_enabled_, TYPE) (HW *hw) +{ + while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { + if (hw->active && hw->enabled) { + return hw; + } + } + return NULL; +} + +static HW *glue (audio_pcm_hw_find_any_passive_, TYPE) (HW *hw) +{ + while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { + if (!hw->active) { + return hw; + } + } + return NULL; +} + +static HW *glue (audio_pcm_hw_find_specific_, TYPE) ( + HW *hw, + int freq, + int nchannels, + audfmt_e fmt + ) +{ + while ((hw = glue (audio_pcm_hw_find_any_active_, TYPE) (hw))) { + if (audio_pcm_info_eq (&hw->info, freq, nchannels, fmt)) { + return hw; + } + } + return NULL; +} + +static HW *glue (audio_pcm_hw_add_new_, TYPE) ( + int freq, + int nchannels, + audfmt_e fmt + ) +{ + HW *hw; + + hw = glue (audio_pcm_hw_find_any_passive_, TYPE) (NULL); + if (hw) { + hw->pcm_ops = audio_state.drv->pcm_ops; + if (!hw->pcm_ops) { + return NULL; + } + + if (glue (audio_pcm_hw_init_, TYPE) (hw, freq, nchannels, fmt)) { + glue (audio_pcm_hw_gc_, TYPE) (hw); + return NULL; + } + else { + return hw; + } + } + + return NULL; +} + +static HW *glue (audio_pcm_hw_add_, TYPE) ( + int freq, + int nchannels, + audfmt_e fmt + ) +{ + HW *hw; + + if (glue (audio_state.greedy_, TYPE)) { + hw = glue (audio_pcm_hw_add_new_, TYPE) (freq, nchannels, fmt); + if (hw) { + return hw; + } + } + + hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, freq, nchannels, fmt); + if (hw) { + return hw; + } + + hw = glue (audio_pcm_hw_add_new_, TYPE) (freq, nchannels, fmt); + if (hw) { + return hw; + } + + return glue (audio_pcm_hw_find_any_active_, TYPE) (NULL); +} + +static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( + const char *name, + int freq, + int nchannels, + audfmt_e fmt + ) +{ + SW *sw; + HW *hw; + int hw_freq = freq; + int hw_nchannels = nchannels; + int hw_fmt = fmt; + + if (glue (audio_state.fixed_settings_, TYPE)) { + hw_freq = glue (audio_state.fixed_freq_, TYPE); + hw_nchannels = glue (audio_state.fixed_channels_, TYPE); + hw_fmt = glue (audio_state.fixed_fmt_, TYPE); + } + + sw = qemu_mallocz (sizeof (*sw)); + if (!sw) { + goto err1; + } + + hw = glue (audio_pcm_hw_add_, TYPE) (hw_freq, hw_nchannels, hw_fmt); + if (!hw) { + goto err2; + } + + glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); + + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, freq, nchannels, fmt)) { + goto err3; + } + + return sw; + +err3: + glue (audio_pcm_hw_del_sw_, TYPE) (sw); + glue (audio_pcm_hw_gc_, TYPE) (hw); +err2: + qemu_free (sw); +err1: + return NULL; +} + +void glue (AUD_close_, TYPE) (SW *sw) +{ + if (sw) { + glue (audio_pcm_sw_fini_, TYPE) (sw); + glue (audio_pcm_hw_del_sw_, TYPE) (sw); + glue (audio_pcm_hw_gc_, TYPE) (sw->hw); + qemu_free (sw); + } +} + +SW *glue (AUD_open_, TYPE) ( + SW *sw, + const char *name, + void *callback_opaque , + audio_callback_fn_t callback_fn, + int freq, + int nchannels, + audfmt_e fmt + ) +{ +#ifdef DAC + int live = 0; + SW *old_sw = NULL; +#endif + + if (!callback_fn) { + dolog ("No callback specifed for voice `%s'\n", name); + goto fail; + } + + if (nchannels != 1 && nchannels != 2) { + dolog ("Bogus channel count %d for voice `%s'\n", nchannels, name); + goto fail; + } + + if (!audio_state.drv) { + dolog ("No audio driver defined\n"); + goto fail; + } + + if (sw && audio_pcm_info_eq (&sw->info, freq, nchannels, fmt)) { + return sw; + } + +#ifdef DAC + if (audio_state.plive && sw && (!sw->active && !sw->empty)) { + live = sw->total_hw_samples_mixed; + +#ifdef DEBUG_PLIVE + dolog ("Replacing voice %s with %d live samples\n", sw->name, live); + dolog ("Old %s freq %d, bits %d, channels %d\n", + sw->name, sw->info.freq, sw->info.bits, sw->info.nchannels); + dolog ("New %s freq %d, bits %d, channels %d\n", + name, freq, (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, + nchannels); +#endif + + if (live) { + old_sw = sw; + old_sw->callback.fn = NULL; + sw = NULL; + } + } +#endif + + if (!glue (audio_state.fixed_settings_, TYPE) && sw) { + glue (AUD_close_, TYPE) (sw); + sw = NULL; + } + + if (sw) { + HW *hw = sw->hw; + + if (!hw) { + dolog ("Internal logic error voice %s has no hardware store\n", + name); + goto fail; + } + + if (glue (audio_pcm_sw_init_, TYPE) ( + sw, + hw, + name, + freq, + nchannels, + fmt + )) { + goto fail; + } + } + else { + sw = glue (audio_pcm_create_voice_pair_, TYPE) ( + name, + freq, + nchannels, + fmt); + if (!sw) { + dolog ("Failed to create voice %s\n", name); + goto fail; + } + } + + if (sw) { + sw->vol = nominal_volume; + sw->callback.fn = callback_fn; + sw->callback.opaque = callback_opaque; + +#ifdef DAC + if (live) { + int mixed = + (live << old_sw->info.shift) + * old_sw->info.bytes_per_second + / sw->info.bytes_per_second; + +#ifdef DEBUG_PLIVE + dolog ("Silence will be mixed %d\n", mixed); +#endif + sw->total_hw_samples_mixed += mixed; + } +#endif + +#ifdef DEBUG_AUDIO + dolog ("%s\n", name); + audio_pcm_print_info ("hw", &sw->hw->info); + audio_pcm_print_info ("sw", &sw->info); +#endif + } + + return sw; + + fail: + glue (AUD_close_, TYPE) (sw); + return NULL; +} + +int glue (AUD_is_active_, TYPE) (SW *sw) +{ + return sw ? sw->active : 0; +} + +void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) +{ + if (!sw) { + return; + } + + ts->old_ts = sw->hw->ts_helper; +} + +uint64_t glue (AUD_time_stamp_get_elapsed_usec_, TYPE) ( + SW *sw, + QEMUAudioTimeStamp *ts + ) +{ + uint64_t delta, cur_ts, old_ts; + + if (!sw) { + return 0; + } + + cur_ts = sw->hw->ts_helper; + old_ts = ts->old_ts; + /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */ + + if (cur_ts >= old_ts) { + delta = cur_ts - old_ts; + } + else { + delta = UINT64_MAX - old_ts + cur_ts; + } + + if (!delta) { + return 0; + } + + return (delta * sw->hw->info.freq) / 1000000; +} + +#undef TYPE +#undef HW +#undef SW diff --git a/audio/coreaudio.c b/audio/coreaudio.c new file mode 100644 index 000000000..eee12386c --- /dev/null +++ b/audio/coreaudio.c @@ -0,0 +1,513 @@ +/* + * QEMU OS X CoreAudio audio driver + * + * Copyright (c) 2005 Mike Kronenberg + * + * 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 +#include /* strerror */ +#include /* pthread_X */ + +#include "vl.h" + +#define AUDIO_CAP "coreaudio" +#include "audio_int.h" + +#define DEVICE_BUFFER_FRAMES (512) + +struct { + int buffer_frames; +} conf = { + .buffer_frames = 512 +}; + +typedef struct coreaudioVoiceOut { + HWVoiceOut hw; + pthread_mutex_t mutex; + AudioDeviceID outputDeviceID; + UInt32 audioDevicePropertyBufferSize; + AudioStreamBasicDescription outputStreamBasicDescription; + int isPlaying; + int live; + int decr; + int rpos; +} coreaudioVoiceOut; + +static void coreaudio_logstatus (OSStatus status) +{ + char *str = "BUG"; + + switch(status) { + case kAudioHardwareNoError: + str = "kAudioHardwareNoError"; + break; + + case kAudioHardwareNotRunningError: + str = "kAudioHardwareNotRunningError"; + break; + + case kAudioHardwareUnspecifiedError: + str = "kAudioHardwareUnspecifiedError"; + break; + + case kAudioHardwareUnknownPropertyError: + str = "kAudioHardwareUnknownPropertyError"; + break; + + case kAudioHardwareBadPropertySizeError: + str = "kAudioHardwareBadPropertySizeError"; + break; + + case kAudioHardwareIllegalOperationError: + str = "kAudioHardwareIllegalOperationError"; + break; + + case kAudioHardwareBadDeviceError: + str = "kAudioHardwareBadDeviceError"; + break; + + case kAudioHardwareBadStreamError: + str = "kAudioHardwareBadStreamError"; + break; + + case kAudioHardwareUnsupportedOperationError: + str = "kAudioHardwareUnsupportedOperationError"; + break; + + case kAudioDeviceUnsupportedFormatError: + str = "kAudioDeviceUnsupportedFormatError"; + break; + + case kAudioDevicePermissionsError: + str = "kAudioDevicePermissionsError"; + break; + + default: + AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status); + return; + } + + AUD_log (AUDIO_CAP, "Reason: %s\n", str); +} + +static void GCC_FMT_ATTR (2, 3) coreaudio_logerr ( + OSStatus status, + const char *fmt, + ... + ) +{ + va_list ap; + + va_start (ap, fmt); + AUD_log (AUDIO_CAP, fmt, ap); + va_end (ap); + + coreaudio_logstatus (status); +} + +static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 ( + OSStatus status, + const char *typ, + const char *fmt, + ... + ) +{ + va_list ap; + + AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + coreaudio_logstatus (status); +} + +static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name) +{ + int err; + + err = pthread_mutex_lock (&core->mutex); + if (err) { + dolog ("Can not lock voice for %s\nReason: %s\n", + fn_name, strerror (err)); + return -1; + } + return 0; +} + +static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name) +{ + int err; + + err = pthread_mutex_unlock (&core->mutex); + if (err) { + dolog ("Can not unlock voice for %s\nReason: %s\n", + fn_name, strerror (err)); + return -1; + } + return 0; +} + +static int coreaudio_run_out (HWVoiceOut *hw) +{ + int live, decr; + coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; + + if (coreaudio_lock (core, "coreaudio_run_out")) { + return 0; + } + + live = audio_pcm_hw_get_live_out (hw); + + if (core->decr > live) { + ldebug ("core->decr %d live %d core->live %d\n", + core->decr, + live, + core->live); + } + + decr = audio_MIN (core->decr, live); + core->decr -= decr; + + core->live = live - decr; + hw->rpos = core->rpos; + + coreaudio_unlock (core, "coreaudio_run_out"); + return decr; +} + +/* callback to feed audiooutput buffer */ +static OSStatus audioDeviceIOProc( + AudioDeviceID inDevice, + const AudioTimeStamp* inNow, + const AudioBufferList* inInputData, + const AudioTimeStamp* inInputTime, + AudioBufferList* outOutputData, + const AudioTimeStamp* inOutputTime, + void* hwptr) +{ + unsigned int frame, frameCount; + float *out = outOutputData->mBuffers[0].mData; + HWVoiceOut *hw = hwptr; + coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr; + int rpos, live; + st_sample_t *src; +#ifndef FLOAT_MIXENG +#ifdef RECIPROCAL + const float scale = 1.f / UINT_MAX; +#else + const float scale = UINT_MAX; +#endif +#endif + + if (coreaudio_lock (core, "audioDeviceIOProc")) { + inInputTime = 0; + return 0; + } + + frameCount = conf.buffer_frames; + live = core->live; + + /* if there are not enough samples, set signal and return */ + if (live < frameCount) { + inInputTime = 0; + coreaudio_unlock (core, "audioDeviceIOProc(empty)"); + return 0; + } + + rpos = core->rpos; + src = hw->mix_buf + rpos; + + /* fill buffer */ + for (frame = 0; frame < frameCount; frame++) { +#ifdef FLOAT_MIXENG + *out++ = src[frame].l; /* left channel */ + *out++ = src[frame].r; /* right channel */ +#else +#ifdef RECIPROCAL + *out++ = src[frame].l * scale; /* left channel */ + *out++ = src[frame].r * scale; /* right channel */ +#else + *out++ = src[frame].l / scale; /* left channel */ + *out++ = src[frame].r / scale; /* right channel */ +#endif +#endif + } + + /* cleanup */ + mixeng_clear (src, frameCount); + rpos = (rpos + frameCount) % hw->samples; + core->decr = frameCount; + core->rpos = rpos; + + coreaudio_unlock (core, "audioDeviceIOProc"); + return 0; +} + +static int coreaudio_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} + +static int coreaudio_init_out (HWVoiceOut *hw, int freq, + int nchannels, audfmt_e fmt) +{ + OSStatus status; + coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; + UInt32 propertySize; + int err; + int bits = 8; + int endianess = 0; + const char *typ = "DAC"; + + /* create mutex */ + err = pthread_mutex_init(&core->mutex, NULL); + if (err) { + dolog("Can not create mutex\nReason: %s\n", strerror (err)); + return -1; + } + + if (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) { + bits = 16; + endianess = 1; + } + + audio_pcm_init_info ( + &hw->info, + freq, + nchannels, + fmt, + /* Following is irrelevant actually since we do not use + mixengs clipping routines */ + audio_need_to_swap_endian (endianess) + ); + hw->bufsize = 4 * conf.buffer_frames * nchannels * bits; + + /* open default output device */ + propertySize = sizeof(core->outputDeviceID); + status = AudioHardwareGetProperty( + kAudioHardwarePropertyDefaultOutputDevice, + &propertySize, + &core->outputDeviceID); + if (status != kAudioHardwareNoError) { + coreaudio_logerr2 (status, typ, + "Can not get default output Device\n"); + return -1; + } + if (core->outputDeviceID == kAudioDeviceUnknown) { + dolog ("Can not initialize %s - Unknown Audiodevice\n", typ); + return -1; + } + + /* set Buffersize to conf.buffer_frames frames */ + propertySize = sizeof(core->audioDevicePropertyBufferSize); + core->audioDevicePropertyBufferSize = + conf.buffer_frames * sizeof(float) * 2; + status = AudioDeviceSetProperty( + core->outputDeviceID, + NULL, + 0, + false, + kAudioDevicePropertyBufferSize, + propertySize, + &core->audioDevicePropertyBufferSize); + if (status != kAudioHardwareNoError) { + coreaudio_logerr2 (status, typ, + "Can not set device buffer size %d\n", + kAudioDevicePropertyBufferSize); + return -1; + } + + /* get Buffersize */ + propertySize = sizeof(core->audioDevicePropertyBufferSize); + status = AudioDeviceGetProperty( + core->outputDeviceID, + 0, + false, + kAudioDevicePropertyBufferSize, + &propertySize, + &core->audioDevicePropertyBufferSize); + if (status != kAudioHardwareNoError) { + coreaudio_logerr2 (status, typ, "Can not get device buffer size\n"); + return -1; + } + + /* get StreamFormat */ + propertySize = sizeof(core->outputStreamBasicDescription); + status = AudioDeviceGetProperty( + core->outputDeviceID, + 0, + false, + kAudioDevicePropertyStreamFormat, + &propertySize, + &core->outputStreamBasicDescription); + if (status != kAudioHardwareNoError) { + coreaudio_logerr2 (status, typ, + "Can not get Device Stream properties\n"); + core->outputDeviceID = kAudioDeviceUnknown; + return -1; + } + + /* set Samplerate */ + core->outputStreamBasicDescription.mSampleRate = (Float64)freq; + propertySize = sizeof(core->outputStreamBasicDescription); + status = AudioDeviceSetProperty( + core->outputDeviceID, + 0, + 0, + 0, + kAudioDevicePropertyStreamFormat, + propertySize, + &core->outputStreamBasicDescription); + if (status != kAudioHardwareNoError) { + coreaudio_logerr2 (status, typ, "Can not set samplerate %d\n", freq); + core->outputDeviceID = kAudioDeviceUnknown; + return -1; + } + + /* set Callback */ + status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw); + if (status != kAudioHardwareNoError) { + coreaudio_logerr2 (status, typ, "Can not set IOProc\n"); + core->outputDeviceID = kAudioDeviceUnknown; + return -1; + } + + /* start Playback */ + if (!core->isPlaying) { + status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); + if (status != kAudioHardwareNoError) { + coreaudio_logerr2 (status, typ, "Can not start playback\n"); + AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); + core->outputDeviceID = kAudioDeviceUnknown; + return -1; + } + core->isPlaying = 1; + } + + return 0; +} + +static void coreaudio_fini_out (HWVoiceOut *hw) +{ + OSStatus status; + int err; + coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; + + /* stop playback */ + if (core->isPlaying) { + status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); + if (status != kAudioHardwareNoError) { + coreaudio_logerr (status, "Can not stop playback\n"); + } + core->isPlaying = 0; + } + + /* remove callback */ + status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); + if (status != kAudioHardwareNoError) { + coreaudio_logerr (status, "Can not remove IOProc\n"); + } + core->outputDeviceID = kAudioDeviceUnknown; + + /* destroy mutex */ + err = pthread_mutex_destroy(&core->mutex); + if (err) { + dolog("Can not destroy mutex\nReason: %s\n", strerror (err)); + } +} + +static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) +{ + OSStatus status; + coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; + + switch (cmd) { + case VOICE_ENABLE: + /* start playback */ + if (!core->isPlaying) { + status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); + if (status != kAudioHardwareNoError) { + coreaudio_logerr (status, "Can not unpause playback\n"); + } + core->isPlaying = 1; + } + break; + + case VOICE_DISABLE: + /* stop playback */ + if (core->isPlaying) { + status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); + if (status != kAudioHardwareNoError) { + coreaudio_logerr (status, "Can not pause playback\n"); + } + core->isPlaying = 0; + } + break; + } + return 0; +} + +static void *coreaudio_audio_init (void) +{ + return &coreaudio_audio_init; +} + +static void coreaudio_audio_fini (void *opaque) +{ + (void) opaque; +} + +static struct audio_option coreaudio_options[] = { + {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames, + "Size of the buffer in frames", NULL, 0}, + {NULL, 0, NULL, NULL, NULL, 0} +}; + +static struct audio_pcm_ops coreaudio_pcm_ops = { + coreaudio_init_out, + coreaudio_fini_out, + coreaudio_run_out, + coreaudio_write, + coreaudio_ctl_out, + + NULL, + NULL, + NULL, + NULL, + NULL +}; + +struct audio_driver coreaudio_audio_driver = { + INIT_FIELD (name = ) "coreaudio", + INIT_FIELD (descr = ) + "CoreAudio http://developer.apple.com/audio/coreaudio.html", + INIT_FIELD (options = ) coreaudio_options, + INIT_FIELD (init = ) coreaudio_audio_init, + INIT_FIELD (fini = ) coreaudio_audio_fini, + INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops, + INIT_FIELD (can_be_default = ) 1, + INIT_FIELD (max_voices_out = ) 1, + INIT_FIELD (max_voices_in = ) 0, + INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut), + INIT_FIELD (voice_size_in = ) 0 +}; diff --git a/audio/dsound_template.h b/audio/dsound_template.h new file mode 100644 index 000000000..a04806eae --- /dev/null +++ b/audio/dsound_template.h @@ -0,0 +1,298 @@ +/* + * QEMU DirectSound audio driver header + * + * Copyright (c) 2005 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifdef DSBTYPE_IN +#define NAME "capture buffer" +#define TYPE in +#define IFACE IDirectSoundCaptureBuffer +#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER +#define FIELD dsound_capture_buffer +#else +#define NAME "playback buffer" +#define TYPE out +#define IFACE IDirectSoundBuffer +#define BUFPTR LPDIRECTSOUNDBUFFER +#define FIELD dsound_buffer +#endif + +static int glue (dsound_unlock_, TYPE) ( + BUFPTR buf, + LPVOID p1, + LPVOID p2, + DWORD blen1, + DWORD blen2 + ) +{ + HRESULT hr; + + hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not unlock " NAME "\n"); + return -1; + } + + return 0; +} + +static int glue (dsound_lock_, TYPE) ( + BUFPTR buf, + struct audio_pcm_info *info, + DWORD pos, + DWORD len, + LPVOID *p1p, + LPVOID *p2p, + DWORD *blen1p, + DWORD *blen2p, + int entire + ) +{ + HRESULT hr; + int i; + LPVOID p1 = NULL, p2 = NULL; + DWORD blen1 = 0, blen2 = 0; + + for (i = 0; i < conf.lock_retries; ++i) { + hr = glue (IFACE, _Lock) ( + buf, + pos, + len, + &p1, + &blen1, + &p2, + &blen2, + (entire +#ifdef DSBTYPE_IN + ? DSCBLOCK_ENTIREBUFFER +#else + ? DSBLOCK_ENTIREBUFFER +#endif + : 0) + ); + + if (FAILED (hr)) { +#ifndef DSBTYPE_IN + if (hr == DSERR_BUFFERLOST) { + if (glue (dsound_restore_, TYPE) (buf)) { + dsound_logerr (hr, "Can not lock " NAME "\n"); + goto fail; + } + continue; + } +#endif + dsound_logerr (hr, "Can not lock " NAME "\n"); + goto fail; + } + + break; + } + + if (i == conf.lock_retries) { + dolog ("%d attempts to lock " NAME " failed\n", i); + goto fail; + } + + if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { + dolog ("DirectSound returned misaligned buffer %ld %ld\n", + blen1, blen2); + glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); + goto fail; + } + + if (!p1 && blen1) { + dolog ("warning: !p1 && blen1=%ld\n", blen1); + blen1 = 0; + } + + if (!p2 && blen2) { + dolog ("warning: !p2 && blen2=%ld\n", blen2); + blen2 = 0; + } + + *p1p = p1; + *p2p = p2; + *blen1p = blen1; + *blen2p = blen2; + return 0; + + fail: + *p1p = NULL - 1; + *p2p = NULL - 1; + *blen1p = -1; + *blen2p = -1; + return -1; +} + +#ifdef DSBTYPE_IN +static void dsound_fini_in (HWVoiceIn *hw) +#else +static void dsound_fini_out (HWVoiceOut *hw) +#endif +{ + HRESULT hr; +#ifdef DSBTYPE_IN + DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; +#else + DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; +#endif + + if (ds->FIELD) { + hr = glue (IFACE, _Stop) (ds->FIELD); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not stop " NAME "\n"); + } + + hr = glue (IFACE, _Release) (ds->FIELD); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not release " NAME "\n"); + } + ds->FIELD = NULL; + } +} + +#ifdef DSBTYPE_IN +static int dsound_init_in ( + HWVoiceIn *hw, + int freq, + int nchannels, + audfmt_e fmt + ) +#else +static int dsound_init_out ( + HWVoiceOut *hw, + int freq, + int nchannels, + audfmt_e fmt + ) +#endif +{ + int err; + HRESULT hr; + dsound *s = &glob_dsound; + WAVEFORMATEX wfx; + struct full_fmt full_fmt; +#ifdef DSBTYPE_IN + const char *typ = "ADC"; + DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; + DSCBUFFERDESC bd; + DSCBCAPS bc; +#else + const char *typ = "DAC"; + DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; + DSBUFFERDESC bd; + DSBCAPS bc; +#endif + + full_fmt.freq = freq; + full_fmt.nchannels = nchannels; + full_fmt.fmt = fmt; + err = waveformat_from_full_fmt (&wfx, &full_fmt); + if (err) { + return -1; + } + + memset (&bd, 0, sizeof (bd)); + bd.dwSize = sizeof (bd); + bd.lpwfxFormat = &wfx; +#ifdef DSBTYPE_IN + bd.dwBufferBytes = conf.bufsize_in; + hr = IDirectSoundCapture_CreateCaptureBuffer ( + s->dsound_capture, + &bd, + &ds->dsound_capture_buffer, + NULL + ); +#else + bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + bd.dwBufferBytes = conf.bufsize_out; + hr = IDirectSound_CreateSoundBuffer ( + s->dsound, + &bd, + &ds->dsound_buffer, + NULL + ); +#endif + + if (FAILED (hr)) { + dsound_logerr2 (hr, typ, "Can not create " NAME "\n"); + return -1; + } + + hr = glue (IFACE, _GetFormat) ( + ds->FIELD, + &wfx, + sizeof (wfx), + NULL + ); + if (FAILED (hr)) { + dsound_logerr2 (hr, typ, "Can not get " NAME " format\n"); + goto fail0; + } + +#ifdef DEBUG_DSOUND + dolog (NAME "\n"); + print_wave_format (&wfx); +#endif + + memset (&bc, 0, sizeof (bc)); + bc.dwSize = sizeof (bc); + + hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); + if (FAILED (hr)) { + dsound_logerr2 (hr, typ, "Can not get " NAME " format\n"); + goto fail0; + } + + err = waveformat_to_full_fmt (&wfx, &full_fmt); + if (err) { + goto fail0; + } + + ds->first_time = 1; + hw->bufsize = bc.dwBufferBytes; + audio_pcm_init_info ( + &hw->info, + full_fmt.freq, + full_fmt.nchannels, + full_fmt.fmt, + audio_need_to_swap_endian (0) + ); + +#ifdef DEBUG_DSOUND + dolog ("caps %ld, desc %ld\n", + bc.dwBufferBytes, bd.dwBufferBytes); + + dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", + hw->bufsize, full_fmt.freq, full_fmt.nchannels, full_fmt.fmt); +#endif + return 0; + + fail0: + glue (dsound_fini_, TYPE) (hw); + return -1; +} + +#undef NAME +#undef TYPE +#undef IFACE +#undef BUFPTR +#undef FIELD diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c new file mode 100644 index 000000000..64b84174d --- /dev/null +++ b/audio/dsoundaudio.c @@ -0,0 +1,1082 @@ +/* + * QEMU DirectSound audio driver + * + * Copyright (c) 2005 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation + */ + +#include "vl.h" + +#define AUDIO_CAP "dsound" +#include "audio_int.h" + +#include +#include +#include + +/* #define DEBUG_DSOUND */ + +struct full_fmt { + int freq; + int nchannels; + audfmt_e fmt; +}; + +static struct { + int lock_retries; + int restore_retries; + int getstatus_retries; + int set_primary; + int bufsize_in; + int bufsize_out; + struct full_fmt full_fmt; + int latency_millis; +} conf = { + 1, + 1, + 1, + 0, + 16384, + 16384, + { + 44100, + 2, + AUD_FMT_S16 + }, + 10 +}; + +typedef struct { + LPDIRECTSOUND dsound; + LPDIRECTSOUNDCAPTURE dsound_capture; + LPDIRECTSOUNDBUFFER dsound_primary_buffer; + struct full_fmt fmt; +} dsound; + +static dsound glob_dsound; + +typedef struct { + HWVoiceOut hw; + LPDIRECTSOUNDBUFFER dsound_buffer; + DWORD old_pos; + int first_time; +#ifdef DEBUG_DSOUND + DWORD old_ppos; + DWORD played; + DWORD mixed; +#endif +} DSoundVoiceOut; + +typedef struct { + HWVoiceIn hw; + int first_time; + LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer; +} DSoundVoiceIn; + +static void dsound_log_hresult (HRESULT hr) +{ + const char *str = "BUG"; + + switch (hr) { + case DS_OK: + str = "The method succeeded"; + break; +#ifdef DS_NO_VIRTUALIZATION + case DS_NO_VIRTUALIZATION: + str = "The buffer was created, but another 3D algorithm was substituted"; + break; +#endif +#ifdef DS_INCOMPLETE + case DS_INCOMPLETE: + str = "The method succeeded, but not all the optional effects were obtained"; + break; +#endif +#ifdef DSERR_ACCESSDENIED + case DSERR_ACCESSDENIED: + str = "The request failed because access was denied"; + break; +#endif +#ifdef DSERR_ALLOCATED + case DSERR_ALLOCATED: + str = "The request failed because resources, such as a priority level, were already in use by another caller"; + break; +#endif +#ifdef DSERR_ALREADYINITIALIZED + case DSERR_ALREADYINITIALIZED: + str = "The object is already initialized"; + break; +#endif +#ifdef DSERR_BADFORMAT + case DSERR_BADFORMAT: + str = "The specified wave format is not supported"; + break; +#endif +#ifdef DSERR_BADSENDBUFFERGUID + case DSERR_BADSENDBUFFERGUID: + str = "The GUID specified in an audiopath file does not match a valid mix-in buffer"; + break; +#endif +#ifdef DSERR_BUFFERLOST + case DSERR_BUFFERLOST: + str = "The buffer memory has been lost and must be restored"; + break; +#endif +#ifdef DSERR_BUFFERTOOSMALL + case DSERR_BUFFERTOOSMALL: + str = "The buffer size is not great enough to enable effects processing"; + break; +#endif +#ifdef DSERR_CONTROLUNAVAIL + case DSERR_CONTROLUNAVAIL: + str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC"; + break; +#endif +#ifdef DSERR_DS8_REQUIRED + case DSERR_DS8_REQUIRED: + str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface"; + break; +#endif +#ifdef DSERR_FXUNAVAILABLE + case DSERR_FXUNAVAILABLE: + str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software"; + break; +#endif +#ifdef DSERR_GENERIC + case DSERR_GENERIC : + str = "An undetermined error occurred inside the DirectSound subsystem"; + break; +#endif +#ifdef DSERR_INVALIDCALL + case DSERR_INVALIDCALL: + str = "This function is not valid for the current state of this object"; + break; +#endif +#ifdef DSERR_INVALIDPARAM + case DSERR_INVALIDPARAM: + str = "An invalid parameter was passed to the returning function"; + break; +#endif +#ifdef DSERR_NOAGGREGATION + case DSERR_NOAGGREGATION: + str = "The object does not support aggregation"; + break; +#endif +#ifdef DSERR_NODRIVER + case DSERR_NODRIVER: + str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID"; + break; +#endif +#ifdef DSERR_NOINTERFACE + case DSERR_NOINTERFACE: + str = "The requested COM interface is not available"; + break; +#endif +#ifdef DSERR_OBJECTNOTFOUND + case DSERR_OBJECTNOTFOUND: + str = "The requested object was not found"; + break; +#endif +#ifdef DSERR_OTHERAPPHASPRIO + case DSERR_OTHERAPPHASPRIO: + str = "Another application has a higher priority level, preventing this call from succeeding"; + break; +#endif +#ifdef DSERR_OUTOFMEMORY + case DSERR_OUTOFMEMORY: + str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request"; + break; +#endif +#ifdef DSERR_PRIOLEVELNEEDED + case DSERR_PRIOLEVELNEEDED: + str = "A cooperative level of DSSCL_PRIORITY or higher is required"; + break; +#endif +#ifdef DSERR_SENDLOOP + case DSERR_SENDLOOP: + str = "A circular loop of send effects was detected"; + break; +#endif +#ifdef DSERR_UNINITIALIZED + case DSERR_UNINITIALIZED: + str = "The Initialize method has not been called or has not been called successfully before other methods were called"; + break; +#endif +#ifdef DSERR_UNSUPPORTED + case DSERR_UNSUPPORTED: + str = "The function called is not supported at this time"; + break; +#endif + default: + AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr); + return; + } + + AUD_log (AUDIO_CAP, "Reason: %s\n", str); +} + +static void GCC_FMT_ATTR (2, 3) dsound_logerr ( + HRESULT hr, + const char *fmt, + ... + ) +{ + va_list ap; + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + dsound_log_hresult (hr); +} + +static void GCC_FMT_ATTR (3, 4) dsound_logerr2 ( + HRESULT hr, + const char *typ, + const char *fmt, + ... + ) +{ + va_list ap; + + AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + dsound_log_hresult (hr); +} + +static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis) +{ + return (millis * info->bytes_per_second) / 1000; +} + +#ifdef DEBUG_DSOUND +static void print_wave_format (WAVEFORMATEX *wfx) +{ + dolog ("tag = %d\n", wfx->wFormatTag); + dolog ("nChannels = %d\n", wfx->nChannels); + dolog ("nSamplesPerSec = %ld\n", wfx->nSamplesPerSec); + dolog ("nAvgBytesPerSec = %ld\n", wfx->nAvgBytesPerSec); + dolog ("nBlockAlign = %d\n", wfx->nBlockAlign); + dolog ("wBitsPerSample = %d\n", wfx->wBitsPerSample); + dolog ("cbSize = %d\n", wfx->cbSize); +} +#endif + +static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb) +{ + HRESULT hr; + int i; + + for (i = 0; i < conf.restore_retries; ++i) { + hr = IDirectSoundBuffer_Restore (dsb); + + switch (hr) { + case DS_OK: + return 0; + + case DSERR_BUFFERLOST: + continue; + + default: + dsound_logerr (hr, "Can not restore playback buffer\n"); + return -1; + } + } + + dolog ("%d attempts to restore playback buffer failed\n", i); + return -1; +} + +static int waveformat_from_full_fmt (WAVEFORMATEX *wfx, + struct full_fmt *full_fmt) +{ + memset (wfx, 0, sizeof (*wfx)); + + wfx->wFormatTag = WAVE_FORMAT_PCM; + wfx->nChannels = full_fmt->nchannels; + wfx->nSamplesPerSec = full_fmt->freq; + wfx->nAvgBytesPerSec = full_fmt->freq << (full_fmt->nchannels == 2); + wfx->nBlockAlign = 1 << (full_fmt->nchannels == 2); + wfx->cbSize = 0; + + switch (full_fmt->fmt) { + case AUD_FMT_S8: + wfx->wBitsPerSample = 8; + break; + + case AUD_FMT_U8: + wfx->wBitsPerSample = 8; + break; + + case AUD_FMT_S16: + wfx->wBitsPerSample = 16; + wfx->nAvgBytesPerSec <<= 1; + wfx->nBlockAlign <<= 1; + break; + + case AUD_FMT_U16: + wfx->wBitsPerSample = 16; + wfx->nAvgBytesPerSec <<= 1; + wfx->nBlockAlign <<= 1; + break; + + default: + dolog ("Internal logic error: Bad audio format %d\n", + full_fmt->freq); + return -1; + } + + return 0; +} + +static int waveformat_to_full_fmt (WAVEFORMATEX *wfx, + struct full_fmt *full_fmt) +{ + if (wfx->wFormatTag != WAVE_FORMAT_PCM) { + dolog ("Invalid wave format, tag is not PCM, but %d\n", + wfx->wFormatTag); + return -1; + } + + if (!wfx->nSamplesPerSec) { + dolog ("Invalid wave format, frequency is zero\n"); + return -1; + } + full_fmt->freq = wfx->nSamplesPerSec; + + switch (wfx->nChannels) { + case 1: + full_fmt->nchannels = 1; + break; + + case 2: + full_fmt->nchannels = 2; + break; + + default: + dolog ( + "Invalid wave format, number of channels is not 1 or 2, but %d\n", + wfx->nChannels + ); + return -1; + } + + switch (wfx->wBitsPerSample) { + case 8: + full_fmt->fmt = AUD_FMT_U8; + break; + + case 16: + full_fmt->fmt = AUD_FMT_S16; + break; + + default: + dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n", + wfx->wBitsPerSample); + return -1; + } + + return 0; +} + +#include "dsound_template.h" +#define DSBTYPE_IN +#include "dsound_template.h" +#undef DSBTYPE_IN + +static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp) +{ + HRESULT hr; + int i; + + for (i = 0; i < conf.getstatus_retries; ++i) { + hr = IDirectSoundBuffer_GetStatus (dsb, statusp); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not get playback buffer status\n"); + return -1; + } + + if (*statusp & DSERR_BUFFERLOST) { + if (dsound_restore_out (dsb)) { + return -1; + } + continue; + } + break; + } + + return 0; +} + +static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb, + DWORD *statusp) +{ + HRESULT hr; + + hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not get capture buffer status\n"); + return -1; + } + + return 0; +} + +static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len) +{ + int src_len1 = dst_len; + int src_len2 = 0; + int pos = hw->rpos + dst_len; + st_sample_t *src1 = hw->mix_buf + hw->rpos; + st_sample_t *src2 = NULL; + + if (pos > hw->samples) { + src_len1 = hw->samples - hw->rpos; + src2 = hw->mix_buf; + src_len2 = dst_len - src_len1; + pos = src_len2; + } + + if (src_len1) { + hw->clip (dst, src1, src_len1); + mixeng_clear (src1, src_len1); + } + + if (src_len2) { + dst = advance (dst, src_len1 << hw->info.shift); + hw->clip (dst, src2, src_len2); + mixeng_clear (src2, src_len2); + } + + hw->rpos = pos % hw->samples; +} + +static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb) +{ + int err; + LPVOID p1, p2; + DWORD blen1, blen2, len1, len2; + + err = dsound_lock_out ( + dsb, + &hw->info, + 0, + hw->samples << hw->info.shift, + &p1, &p2, + &blen1, &blen2, + 1 + ); + if (err) { + return; + } + + len1 = blen1 >> hw->info.shift; + len2 = blen2 >> hw->info.shift; + +#ifdef DEBUG_DSOUND + dolog ("clear %p,%ld,%ld %p,%ld,%ld\n", + p1, blen1, len1, + p2, blen2, len2); +#endif + + if (p1 && len1) { + audio_pcm_info_clear_buf (&hw->info, p1, len1); + } + + if (p2 && len2) { + audio_pcm_info_clear_buf (&hw->info, p2, len2); + } + + dsound_unlock_out (dsb, p1, p2, blen1, blen2); +} + +static void dsound_close (dsound *s) +{ + HRESULT hr; + + if (s->dsound_primary_buffer) { + hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not release primary buffer\n"); + } + s->dsound_primary_buffer = NULL; + } +} + +static int dsound_open (dsound *s) +{ + int err; + HRESULT hr; + WAVEFORMATEX wfx; + DSBUFFERDESC dsbd; + HWND hwnd; + + hwnd = GetForegroundWindow (); + hr = IDirectSound_SetCooperativeLevel ( + s->dsound, + hwnd, + DSSCL_PRIORITY + ); + + if (FAILED (hr)) { + dsound_logerr (hr, "Can not set cooperative level for window %p\n", + hwnd); + return -1; + } + + if (!conf.set_primary) { + return 0; + } + + err = waveformat_from_full_fmt (&wfx, &conf.full_fmt); + if (err) { + return -1; + } + + memset (&dsbd, 0, sizeof (dsbd)); + dsbd.dwSize = sizeof (dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + + hr = IDirectSound_CreateSoundBuffer ( + s->dsound, + &dsbd, + &s->dsound_primary_buffer, + NULL + ); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not create primary playback buffer\n"); + return -1; + } + + hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not set primary playback buffer format\n"); + } + + hr = IDirectSoundBuffer_GetFormat ( + s->dsound_primary_buffer, + &wfx, + sizeof (wfx), + NULL + ); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not get primary playback buffer format\n"); + goto fail0; + } + +#ifdef DEBUG_DSOUND + dolog ("Primary\n"); + print_wave_format (&wfx); +#endif + + err = waveformat_to_full_fmt (&wfx, &s->fmt); + if (err) { + goto fail0; + } + + return 0; + + fail0: + dsound_close (s); + return -1; +} + +static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) +{ + HRESULT hr; + DWORD status; + DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; + LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; + + if (!dsb) { + dolog ("Attempt to control voice without a buffer\n"); + return 0; + } + + switch (cmd) { + case VOICE_ENABLE: + if (dsound_get_status_out (dsb, &status)) { + return -1; + } + + if (status & DSBSTATUS_PLAYING) { + dolog ("warning: voice is already playing\n"); + return 0; + } + + dsound_clear_sample (hw, dsb); + + hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not start playing buffer\n"); + return -1; + } + break; + + case VOICE_DISABLE: + if (dsound_get_status_out (dsb, &status)) { + return -1; + } + + if (status & DSBSTATUS_PLAYING) { + hr = IDirectSoundBuffer_Stop (dsb); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not stop playing buffer\n"); + return -1; + } + } + else { + dolog ("warning: voice is not playing\n"); + } + break; + } + return 0; +} + +static int dsound_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} + +static int dsound_run_out (HWVoiceOut *hw) +{ + int err; + HRESULT hr; + DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; + LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; + int live, len, hwshift; + DWORD blen1, blen2; + DWORD len1, len2; + DWORD decr; + DWORD wpos, ppos, old_pos; + LPVOID p1, p2; + + if (!dsb) { + dolog ("Attempt to run empty with playback buffer\n"); + return 0; + } + + hwshift = hw->info.shift; + + live = audio_pcm_hw_get_live_out (hw); + + hr = IDirectSoundBuffer_GetCurrentPosition ( + dsb, + &ppos, + ds->first_time ? &wpos : NULL + ); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not get playback buffer position\n"); + return 0; + } + + len = live << hwshift; + + if (ds->first_time) { + if (conf.latency_millis) { + DWORD cur_blat = audio_ring_dist (wpos, ppos, hw->bufsize); + + ds->first_time = 0; + old_pos = wpos; + old_pos += + millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat; + old_pos %= hw->bufsize; + old_pos &= ~hw->info.align; + } + else { + old_pos = wpos; + } +#ifdef DEBUG_DSOUND + ds->played = 0; + ds->mixed = 0; +#endif + } + else { + if (ds->old_pos == ppos) { +#ifdef DEBUG_DSOUND + dolog ("old_pos == ppos\n"); +#endif + return 0; + } + +#ifdef DEBUG_DSOUND + ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize); +#endif + old_pos = ds->old_pos; + } + + if ((old_pos < ppos) && ((old_pos + len) > ppos)) { + len = ppos - old_pos; + } + else { + if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->bufsize))) { + len = hw->bufsize - old_pos + ppos; + } + } + + if (audio_bug (AUDIO_FUNC, len < 0 || len > hw->bufsize)) { + dolog ("len=%d hw->bufsize=%d old_pos=%ld ppos=%ld\n", + len, hw->bufsize, old_pos, ppos); + return 0; + } + + len &= ~hw->info.align; + if (!len) { + return 0; + } + +#ifdef DEBUG_DSOUND + ds->old_ppos = ppos; +#endif + err = dsound_lock_out ( + dsb, + &hw->info, + old_pos, + len, + &p1, &p2, + &blen1, &blen2, + 0 + ); + if (err) { + return 0; + } + + len1 = blen1 >> hwshift; + len2 = blen2 >> hwshift; + decr = len1 + len2; + + if (p1 && len1) { + dsound_write_sample (hw, p1, len1); + } + + if (p2 && len2) { + dsound_write_sample (hw, p2, len2); + } + + dsound_unlock_out (dsb, p1, p2, blen1, blen2); + ds->old_pos = (old_pos + (decr << hwshift)) % hw->bufsize; + +#ifdef DEBUG_DSOUND + ds->mixed += decr << hwshift; + + dolog ("played %lu mixed %lu diff %ld sec %f\n", + ds->played, + ds->mixed, + ds->mixed - ds->played, + abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second); +#endif + return decr; +} + +static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) +{ + HRESULT hr; + DWORD status; + DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; + LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer; + + if (!dscb) { + dolog ("Attempt to control capture voice without a buffer\n"); + return -1; + } + + switch (cmd) { + case VOICE_ENABLE: + if (dsound_get_status_in (dscb, &status)) { + return -1; + } + + if (status & DSCBSTATUS_CAPTURING) { + dolog ("warning: voice is already capturing\n"); + return 0; + } + + /* clear ?? */ + + hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not start capturing\n"); + return -1; + } + break; + + case VOICE_DISABLE: + if (dsound_get_status_in (dscb, &status)) { + return -1; + } + + if (status & DSCBSTATUS_CAPTURING) { + hr = IDirectSoundCaptureBuffer_Stop (dscb); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not stop capturing\n"); + return -1; + } + } + else { + dolog ("warning: voice is not capturing\n"); + } + break; + } + return 0; +} + +static int dsound_read (SWVoiceIn *sw, void *buf, int len) +{ + return audio_pcm_sw_read (sw, buf, len); +} + +static int dsound_run_in (HWVoiceIn *hw) +{ + int err; + HRESULT hr; + DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; + LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer; + int live, len, dead; + DWORD blen1, blen2; + DWORD len1, len2; + DWORD decr; + DWORD cpos, rpos; + LPVOID p1, p2; + int hwshift; + + if (!dscb) { + dolog ("Attempt to run without capture buffer\n"); + return 0; + } + + hwshift = hw->info.shift; + + live = audio_pcm_hw_get_live_in (hw); + dead = hw->samples - live; + if (!dead) { + return 0; + } + + hr = IDirectSoundCaptureBuffer_GetCurrentPosition ( + dscb, + &cpos, + ds->first_time ? &rpos : NULL + ); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not get capture buffer position\n"); + return 0; + } + + if (ds->first_time) { + ds->first_time = 0; + if (rpos & hw->info.align) { + ldebug ("warning: misaligned capture read position %ld(%d)\n", + rpos, hw->info.align); + } + hw->wpos = rpos >> hwshift; + } + + if (cpos & hw->info.align) { + ldebug ("warning: misaligned capture position %ld(%d)\n", + cpos, hw->info.align); + } + cpos >>= hwshift; + + len = audio_ring_dist (cpos, hw->wpos, hw->samples); + if (!len) { + return 0; + } + len = audio_MIN (len, dead); + + err = dsound_lock_in ( + dscb, + &hw->info, + hw->wpos << hwshift, + len << hwshift, + &p1, + &p2, + &blen1, + &blen2, + 0 + ); + if (err) { + return 0; + } + + len1 = blen1 >> hwshift; + len2 = blen2 >> hwshift; + decr = len1 + len2; + + if (p1 && len1) { + hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume); + } + + if (p2 && len2) { + hw->conv (hw->conv_buf, p2, len2, &nominal_volume); + } + + dsound_unlock_in (dscb, p1, p2, blen1, blen2); + hw->wpos = (hw->wpos + decr) % hw->samples; + return decr; +} + +static void dsound_audio_fini (void *opaque) +{ + HRESULT hr; + dsound *s = opaque; + + if (!s->dsound) { + return; + } + + hr = IDirectSound_Release (s->dsound); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not release DirectSound\n"); + } + s->dsound = NULL; + + if (!s->dsound_capture) { + return; + } + + hr = IDirectSoundCapture_Release (s->dsound_capture); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not release DirectSoundCapture\n"); + } + s->dsound_capture = NULL; +} + +static void *dsound_audio_init (void) +{ + int err; + HRESULT hr; + dsound *s = &glob_dsound; + + hr = CoInitialize (NULL); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not initialize COM\n"); + return NULL; + } + + hr = CoCreateInstance ( + &CLSID_DirectSound, + NULL, + CLSCTX_ALL, + &IID_IDirectSound, + (void **) &s->dsound + ); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not create DirectSound instance\n"); + return NULL; + } + + hr = IDirectSound_Initialize (s->dsound, NULL); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not initialize DirectSound\n"); + return NULL; + } + + hr = CoCreateInstance ( + &CLSID_DirectSoundCapture, + NULL, + CLSCTX_ALL, + &IID_IDirectSoundCapture, + (void **) &s->dsound_capture + ); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not create DirectSoundCapture instance\n"); + } + else { + hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not initialize DirectSoundCapture\n"); + + hr = IDirectSoundCapture_Release (s->dsound_capture); + if (FAILED (hr)) { + dsound_logerr (hr, "Can not release DirectSoundCapture\n"); + } + s->dsound_capture = NULL; + } + } + + err = dsound_open (s); + if (err) { + dsound_audio_fini (s); + return NULL; + } + + return s; +} + +static struct audio_option dsound_options[] = { + {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries, + "Number of times to attempt locking the buffer", NULL, 0}, + {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries, + "Number of times to attempt restoring the buffer", NULL, 0}, + {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries, + "Number of times to attempt getting status of the buffer", NULL, 0}, + {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary, + "Set the parameters of primary buffer", NULL, 0}, + {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis, + "(undocumented)", NULL, 0}, + {"PRIMARY_FREQ", AUD_OPT_INT, &conf.full_fmt.freq, + "Primary buffer frequency", NULL, 0}, + {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.full_fmt.nchannels, + "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0}, + {"PRIMARY_FMT", AUD_OPT_FMT, &conf.full_fmt.fmt, + "Primary buffer format", NULL, 0}, + {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out, + "(undocumented)", NULL, 0}, + {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in, + "(undocumented)", NULL, 0}, + {NULL, 0, NULL, NULL, NULL, 0} +}; + +static struct audio_pcm_ops dsound_pcm_ops = { + dsound_init_out, + dsound_fini_out, + dsound_run_out, + dsound_write, + dsound_ctl_out, + + dsound_init_in, + dsound_fini_in, + dsound_run_in, + dsound_read, + dsound_ctl_in +}; + +struct audio_driver dsound_audio_driver = { + INIT_FIELD (name = ) "dsound", + INIT_FIELD (descr = ) + "DirectSound http://wikipedia.org/wiki/DirectSound", + INIT_FIELD (options = ) dsound_options, + INIT_FIELD (init = ) dsound_audio_init, + INIT_FIELD (fini = ) dsound_audio_fini, + INIT_FIELD (pcm_ops = ) &dsound_pcm_ops, + INIT_FIELD (can_be_default = ) 1, + INIT_FIELD (max_voices_out = ) INT_MAX, + INIT_FIELD (max_voices_in = ) 1, + INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut), + INIT_FIELD (voice_size_in = ) sizeof (DSoundVoiceIn) +}; diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index 7b79026a8..36b8d47c4 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -1,8 +1,8 @@ /* - * QEMU FMOD audio output driver - * - * Copyright (c) 2004 Vassili Karpov (malc) - * + * QEMU FMOD audio driver + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -25,53 +25,77 @@ #include #include "vl.h" -#include "audio/audio_int.h" +#define AUDIO_CAP "fmod" +#include "audio_int.h" -typedef struct FMODVoice { - HWVoice hw; +typedef struct FMODVoiceOut { + HWVoiceOut hw; unsigned int old_pos; FSOUND_SAMPLE *fmod_sample; int channel; -} FMODVoice; - -#define dolog(...) AUD_log ("fmod", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif +} FMODVoiceOut; -#define QC_FMOD_DRV "QEMU_FMOD_DRV" -#define QC_FMOD_FREQ "QEMU_FMOD_FREQ" -#define QC_FMOD_SAMPLES "QEMU_FMOD_SAMPLES" -#define QC_FMOD_CHANNELS "QEMU_FMOD_CHANNELS" -#define QC_FMOD_BUFSIZE "QEMU_FMOD_BUFSIZE" -#define QC_FMOD_THRESHOLD "QEMU_FMOD_THRESHOLD" +typedef struct FMODVoiceIn { + HWVoiceIn hw; + FSOUND_SAMPLE *fmod_sample; +} FMODVoiceIn; static struct { + const char *drvname; int nb_samples; int freq; int nb_channels; int bufsize; int threshold; + int broken_adc; } conf = { - 2048, + NULL, + 2048 * 2, 44100, - 1, + 2, + 0, 0, - 128 + 0 }; -#define errstr() FMOD_ErrorString (FSOUND_GetError ()) +static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + AUD_log (AUDIO_CAP, "Reason: %s\n", + FMOD_ErrorString (FSOUND_GetError ())); +} + +static void GCC_FMT_ATTR (2, 3) fmod_logerr2 ( + const char *typ, + const char *fmt, + ... + ) +{ + va_list ap; + + AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + AUD_log (AUDIO_CAP, "Reason: %s\n", + FMOD_ErrorString (FSOUND_GetError ())); +} -static int fmod_hw_write (SWVoice *sw, void *buf, int len) +static int fmod_write (SWVoiceOut *sw, void *buf, int len) { - return pcm_hw_write (sw, buf, len); + return audio_pcm_sw_write (sw, buf, len); } -static void fmod_clear_sample (FMODVoice *fmd) +static void fmod_clear_sample (FMODVoiceOut *fmd) { - HWVoice *hw = &fmd->hw; + HWVoiceOut *hw = &fmd->hw; int status; void *p1 = 0, *p2 = 0; unsigned int len1 = 0, len2 = 0; @@ -79,7 +103,7 @@ static void fmod_clear_sample (FMODVoice *fmd) status = FSOUND_Sample_Lock ( fmd->fmod_sample, 0, - hw->samples << hw->shift, + hw->samples << hw->info.shift, &p1, &p2, &len1, @@ -87,78 +111,88 @@ static void fmod_clear_sample (FMODVoice *fmd) ); if (!status) { - dolog ("Failed to lock sample\nReason: %s\n", errstr ()); + fmod_logerr ("Failed to lock sample\n"); return; } - if ((len1 & hw->align) || (len2 & hw->align)) { - dolog ("Locking sample returned unaligned length %d, %d\n", - len1, len2); + if ((len1 & hw->info.align) || (len2 & hw->info.align)) { + dolog ("Lock returned misaligned length %d, %d, alignment %d\n", + len1, len2, hw->info.align + 1); goto fail; } - if (len1 + len2 != hw->samples << hw->shift) { - dolog ("Locking sample returned incomplete length %d, %d\n", - len1 + len2, hw->samples << hw->shift); + if ((len1 + len2) - (hw->samples << hw->info.shift)) { + dolog ("Lock returned incomplete length %d, %d\n", + len1 + len2, hw->samples << hw->info.shift); goto fail; } - pcm_hw_clear (hw, p1, hw->samples); + + audio_pcm_info_clear_buf (&hw->info, p1, hw->samples); fail: status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2); if (!status) { - dolog ("Failed to unlock sample\nReason: %s\n", errstr ()); + fmod_logerr ("Failed to unlock sample\n"); } } -static int fmod_write_sample (HWVoice *hw, uint8_t *dst, st_sample_t *src, - int src_size, int src_pos, int dst_len) +static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len) { - int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len; - st_sample_t *src1 = src + src_pos, *src2 = 0; - - if (src_pos + dst_len > src_size) { - src_len1 = src_size - src_pos; - src2 = src; + int src_len1 = dst_len; + int src_len2 = 0; + int pos = hw->rpos + dst_len; + st_sample_t *src1 = hw->mix_buf + hw->rpos; + st_sample_t *src2 = NULL; + + if (pos > hw->samples) { + src_len1 = hw->samples - hw->rpos; + src2 = hw->mix_buf; src_len2 = dst_len - src_len1; pos = src_len2; } if (src_len1) { hw->clip (dst, src1, src_len1); - memset (src1, 0, src_len1 * sizeof (st_sample_t)); - advance (dst, src_len1); + mixeng_clear (src1, src_len1); } if (src_len2) { + dst = advance (dst, src_len1 << hw->info.shift); hw->clip (dst, src2, src_len2); - memset (src2, 0, src_len2 * sizeof (st_sample_t)); + mixeng_clear (src2, src_len2); } - return pos; + + hw->rpos = pos % hw->samples; } -static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2, +static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2, unsigned int blen1, unsigned int blen2) { - int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2); + int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2); if (!status) { - dolog ("Failed to unlock sample\nReason: %s\n", errstr ()); + fmod_logerr ("Failed to unlock sample\n"); return -1; } return 0; } -static int fmod_lock_sample (FMODVoice *fmd, int pos, int len, - void **p1, void **p2, - unsigned int *blen1, unsigned int *blen2) +static int fmod_lock_sample ( + FSOUND_SAMPLE *sample, + struct audio_pcm_info *info, + int pos, + int len, + void **p1, + void **p2, + unsigned int *blen1, + unsigned int *blen2 + ) { - HWVoice *hw = &fmd->hw; int status; status = FSOUND_Sample_Lock ( - fmd->fmod_sample, - pos << hw->shift, - len << hw->shift, + sample, + pos << info->shift, + len << info->shift, p1, p2, blen1, @@ -166,89 +200,117 @@ static int fmod_lock_sample (FMODVoice *fmd, int pos, int len, ); if (!status) { - dolog ("Failed to lock sample\nReason: %s\n", errstr ()); + fmod_logerr ("Failed to lock sample\n"); return -1; } - if ((*blen1 & hw->align) || (*blen2 & hw->align)) { - dolog ("Locking sample returned unaligned length %d, %d\n", - *blen1, *blen2); - fmod_unlock_sample (fmd, *p1, *p2, *blen1, *blen2); + if ((*blen1 & info->align) || (*blen2 & info->align)) { + dolog ("Lock returned misaligned length %d, %d, alignment %d\n", + *blen1, *blen2, info->align + 1); + + fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2); + + *p1 = NULL - 1; + *p2 = NULL - 1; + *blen1 = ~0U; + *blen2 = ~0U; return -1; } + + if (!*p1 && *blen1) { + dolog ("warning: !p1 && blen1=%d\n", *blen1); + *blen1 = 0; + } + + if (!p2 && *blen2) { + dolog ("warning: !p2 && blen2=%d\n", *blen2); + *blen2 = 0; + } + return 0; } -static void fmod_hw_run (HWVoice *hw) +static int fmod_run_out (HWVoiceOut *hw) { - FMODVoice *fmd = (FMODVoice *) hw; - int rpos, live, decr; + FMODVoiceOut *fmd = (FMODVoiceOut *) hw; + int live, decr; void *p1 = 0, *p2 = 0; unsigned int blen1 = 0, blen2 = 0; unsigned int len1 = 0, len2 = 0; - int nb_active; + int nb_live; - live = pcm_hw_get_live2 (hw, &nb_active); - if (live <= 0) { - return; + live = audio_pcm_hw_get_live_out2 (hw, &nb_live); + if (!live) { + return 0; } if (!hw->pending_disable - && nb_active - && conf.threshold - && live <= conf.threshold) { - ldebug ("live=%d nb_active=%d\n", live, nb_active); - return; + && nb_live + && (conf.threshold && live <= conf.threshold)) { + ldebug ("live=%d nb_live=%d\n", live, nb_live); + return 0; } decr = live; -#if 1 if (fmd->channel >= 0) { - int pos2 = (fmd->old_pos + decr) % hw->samples; - int pos = FSOUND_GetCurrentPosition (fmd->channel); + int len = decr; + int old_pos = fmd->old_pos; + int ppos = FSOUND_GetCurrentPosition (fmd->channel); - if (fmd->old_pos < pos && pos2 >= pos) { - decr = pos - fmd->old_pos - (pos2 == pos) - 1; + if (ppos == old_pos || !ppos) { + return 0; } - else if (fmd->old_pos > pos && pos2 >= pos && pos2 < fmd->old_pos) { - decr = (hw->samples - fmd->old_pos) + pos - (pos2 == pos) - 1; + + if ((old_pos < ppos) && ((old_pos + len) > ppos)) { + len = ppos - old_pos; + } + else { + if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) { + len = hw->samples - old_pos + ppos; + } + } + decr = len; + + if (audio_bug (AUDIO_FUNC, decr < 0)) { + dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n", + decr, live, ppos, old_pos, len); + return 0; } -/* ldebug ("pos=%d pos2=%d old=%d live=%d decr=%d\n", */ -/* pos, pos2, fmd->old_pos, live, decr); */ } -#endif - if (decr <= 0) { - return; + + if (!decr) { + return 0; } - if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) { - return; + if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info, + fmd->old_pos, decr, + &p1, &p2, + &blen1, &blen2)) { + return 0; } - len1 = blen1 >> hw->shift; - len2 = blen2 >> hw->shift; + len1 = blen1 >> hw->info.shift; + len2 = blen2 >> hw->info.shift; ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2); decr = len1 + len2; - rpos = hw->rpos; - if (len1) { - rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1); + if (p1 && len1) { + fmod_write_sample (hw, p1, len1); } - if (len2) { - rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2); + if (p2 && len2) { + fmod_write_sample (hw, p2, len2); } - fmod_unlock_sample (fmd, p1, p2, blen1, blen2); + fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2); - pcm_hw_dec_live (hw, decr); - hw->rpos = rpos % hw->samples; fmd->old_pos = (fmd->old_pos + decr) % hw->samples; + return decr; } -static int AUD_to_fmodfmt (audfmt_e fmt, int stereo) +static int aud_to_fmodfmt (audfmt_e fmt, int stereo) { int mode = FSOUND_LOOP_NORMAL; @@ -270,16 +332,19 @@ static int AUD_to_fmodfmt (audfmt_e fmt, int stereo) break; default: - dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt); - exit (EXIT_FAILURE); + dolog ("Internal logic error: Bad audio format %d\n", fmt); +#ifdef DEBUG_FMOD + abort (); +#endif + mode |= FSOUND_8BITS; } mode |= stereo ? FSOUND_STEREO : FSOUND_MONO; return mode; } -static void fmod_hw_fini (HWVoice *hw) +static void fmod_fini_out (HWVoiceOut *hw) { - FMODVoice *fmd = (FMODVoice *) hw; + FMODVoiceOut *fmd = (FMODVoiceOut *) hw; if (fmd->fmod_sample) { FSOUND_Sample_Free (fmd->fmod_sample); @@ -291,12 +356,12 @@ static void fmod_hw_fini (HWVoice *hw) } } -static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +static int fmod_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) { int bits16, mode, channel; - FMODVoice *fmd = (FMODVoice *) hw; + FMODVoiceOut *fmd = (FMODVoiceOut *) hw; - mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0); + mode = aud_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0); fmd->fmod_sample = FSOUND_Sample_Alloc ( FSOUND_FREE, /* index */ conf.nb_samples, /* length */ @@ -308,52 +373,145 @@ static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) ); if (!fmd->fmod_sample) { - dolog ("Failed to allocate FMOD sample\nReason: %s\n", errstr ()); + fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n"); return -1; } channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1); if (channel < 0) { - dolog ("Failed to start playing sound\nReason: %s\n", errstr ()); + fmod_logerr2 ("DAC", "Failed to start playing sound\n"); FSOUND_Sample_Free (fmd->fmod_sample); return -1; } fmd->channel = channel; - hw->freq = freq; - hw->fmt = fmt; - hw->nchannels = nchannels; - bits16 = fmt == AUD_FMT_U16 || fmt == AUD_FMT_S16; + /* FMOD always operates on little endian frames? */ + audio_pcm_init_info (&hw->info, freq, nchannels, fmt, + audio_need_to_swap_endian (0)); + bits16 = (mode & FSOUND_16BITS) != 0; hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16; return 0; } -static int fmod_hw_ctl (HWVoice *hw, int cmd, ...) +static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...) { int status; - FMODVoice *fmd = (FMODVoice *) hw; + FMODVoiceOut *fmd = (FMODVoiceOut *) hw; switch (cmd) { case VOICE_ENABLE: fmod_clear_sample (fmd); status = FSOUND_SetPaused (fmd->channel, 0); if (!status) { - dolog ("Failed to resume channel %d\nReason: %s\n", - fmd->channel, errstr ()); + fmod_logerr ("Failed to resume channel %d\n", fmd->channel); } break; case VOICE_DISABLE: status = FSOUND_SetPaused (fmd->channel, 1); if (!status) { - dolog ("Failed to pause channel %d\nReason: %s\n", - fmd->channel, errstr ()); + fmod_logerr ("Failed to pause channel %d\n", fmd->channel); } break; } return 0; } +static int fmod_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) +{ + int bits16, mode; + FMODVoiceIn *fmd = (FMODVoiceIn *) hw; + + if (conf.broken_adc) { + return -1; + } + + mode = aud_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0); + fmd->fmod_sample = FSOUND_Sample_Alloc ( + FSOUND_FREE, /* index */ + conf.nb_samples, /* length */ + mode, /* mode */ + freq, /* freq */ + 255, /* volume */ + 128, /* pan */ + 255 /* priority */ + ); + + if (!fmd->fmod_sample) { + fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n"); + return -1; + } + + /* FMOD always operates on little endian frames? */ + audio_pcm_init_info (&hw->info, freq, nchannels, fmt, + audio_need_to_swap_endian (0)); + bits16 = (mode & FSOUND_16BITS) != 0; + hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16; + return 0; +} + +static void fmod_fini_in (HWVoiceIn *hw) +{ + FMODVoiceIn *fmd = (FMODVoiceIn *) hw; + + if (fmd->fmod_sample) { + FSOUND_Record_Stop (); + FSOUND_Sample_Free (fmd->fmod_sample); + fmd->fmod_sample = 0; + } +} + +static int fmod_run_in (HWVoiceIn *hw) +{ + FMODVoiceIn *fmd = (FMODVoiceIn *) hw; + int hwshift = hw->info.shift; + int live, dead, new_pos, len; + unsigned int blen1 = 0, blen2 = 0; + unsigned int len1, len2; + unsigned int decr; + void *p1, *p2; + + live = audio_pcm_hw_get_live_in (hw); + dead = hw->samples - live; + if (!dead) { + return 0; + } + + new_pos = FSOUND_Record_GetPosition (); + if (new_pos < 0) { + fmod_logerr ("Can not get recording position\n"); + return 0; + } + + len = audio_ring_dist (new_pos, hw->wpos, hw->samples); + if (!len) { + return 0; + } + len = audio_MIN (len, dead); + + if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info, + hw->wpos, len, + &p1, &p2, + &blen1, &blen2)) { + return 0; + } + + len1 = blen1 >> hwshift; + len2 = blen2 >> hwshift; + decr = len1 + len2; + + if (p1 && blen1) { + hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume); + } + if (p2 && len2) { + hw->conv (hw->conv_buf, p2, len2, &nominal_volume); + } + + fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2); + hw->wpos = (hw->wpos + decr) % hw->samples; + return decr; +} + static struct { const char *name; int type; @@ -378,16 +536,16 @@ static struct { {"ps2", FSOUND_OUTPUT_PS2}, {"gcube", FSOUND_OUTPUT_GC}, #endif - {"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME} + {"none-realtime", FSOUND_OUTPUT_NOSOUND_NONREALTIME} }; static void *fmod_audio_init (void) { - int i; + size_t i; double ver; int status; int output_type = -1; - const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL); + const char *drv = conf.drvname; ver = FSOUND_GetVersion (); if (ver < FMOD_VERSION) { @@ -395,6 +553,14 @@ static void *fmod_audio_init (void) return NULL; } +#ifdef __linux__ + if (ver < 3.75) { + dolog ("FMOD before 3.75 has bug preventing ADC from working\n" + "ADC will be disabled.\n"); + conf.broken_adc = 1; + } +#endif + if (drv) { int found = 0; for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { @@ -405,65 +571,115 @@ static void *fmod_audio_init (void) } } if (!found) { - dolog ("Unknown FMOD output driver `%s'\n", drv); + dolog ("Unknown FMOD driver `%s'\n", drv); + dolog ("Valid drivers:\n"); + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { + dolog (" %s\n", drvtab[i].name); + } } } if (output_type != -1) { status = FSOUND_SetOutput (output_type); if (!status) { - dolog ("FSOUND_SetOutput(%d) failed\nReason: %s\n", - output_type, errstr ()); + fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type); return NULL; } } - conf.freq = audio_get_conf_int (QC_FMOD_FREQ, conf.freq); - conf.nb_samples = audio_get_conf_int (QC_FMOD_SAMPLES, conf.nb_samples); - conf.nb_channels = - audio_get_conf_int (QC_FMOD_CHANNELS, - (audio_state.nb_hw_voices > 1 - ? audio_state.nb_hw_voices - : conf.nb_channels)); - conf.bufsize = audio_get_conf_int (QC_FMOD_BUFSIZE, conf.bufsize); - conf.threshold = audio_get_conf_int (QC_FMOD_THRESHOLD, conf.threshold); - if (conf.bufsize) { status = FSOUND_SetBufferSize (conf.bufsize); if (!status) { - dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n", - conf.bufsize, errstr ()); + fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize); } } status = FSOUND_Init (conf.freq, conf.nb_channels, 0); if (!status) { - dolog ("FSOUND_Init failed\nReason: %s\n", errstr ()); + fmod_logerr ("FSOUND_Init failed\n"); return NULL; } return &conf; } +static int fmod_read (SWVoiceIn *sw, void *buf, int size) +{ + return audio_pcm_sw_read (sw, buf, size); +} + +static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...) +{ + int status; + FMODVoiceIn *fmd = (FMODVoiceIn *) hw; + + switch (cmd) { + case VOICE_ENABLE: + status = FSOUND_Record_StartSample (fmd->fmod_sample, 1); + if (!status) { + fmod_logerr ("Failed to start recording\n"); + } + break; + + case VOICE_DISABLE: + status = FSOUND_Record_Stop (); + if (!status) { + fmod_logerr ("Failed to stop recording\n"); + } + break; + } + return 0; +} + static void fmod_audio_fini (void *opaque) { + (void) opaque; FSOUND_Close (); } -struct pcm_ops fmod_pcm_ops = { - fmod_hw_init, - fmod_hw_fini, - fmod_hw_run, - fmod_hw_write, - fmod_hw_ctl +static struct audio_option fmod_options[] = { + {"DRV", AUD_OPT_STR, &conf.drvname, + "FMOD driver", NULL, 0}, + {"FREQ", AUD_OPT_INT, &conf.freq, + "Default frequency", NULL, 0}, + {"SAMPLES", AUD_OPT_INT, &conf.nb_samples, + "Buffer size in samples", NULL, 0}, + {"CHANNELS", AUD_OPT_INT, &conf.nb_channels, + "Number of default channels (1 - mono, 2 - stereo)", NULL, 0}, + {"BUFSIZE", AUD_OPT_INT, &conf.bufsize, + "(undocumented)", NULL, 0}, +#if 0 + {"THRESHOLD", AUD_OPT_INT, &conf.threshold, + "(undocumented)"}, +#endif + + {NULL, 0, NULL, NULL, NULL, 0} +}; + +static struct audio_pcm_ops fmod_pcm_ops = { + fmod_init_out, + fmod_fini_out, + fmod_run_out, + fmod_write, + fmod_ctl_out, + + fmod_init_in, + fmod_fini_in, + fmod_run_in, + fmod_read, + fmod_ctl_in }; -struct audio_output_driver fmod_output_driver = { - "fmod", - fmod_audio_init, - fmod_audio_fini, - &fmod_pcm_ops, - 1, - INT_MAX, - sizeof (FMODVoice) +struct audio_driver fmod_audio_driver = { + INIT_FIELD (name = ) "fmod", + INIT_FIELD (descr = ) "FMOD 3.xx http://www.fmod.org", + INIT_FIELD (options = ) fmod_options, + INIT_FIELD (init = ) fmod_audio_init, + INIT_FIELD (fini = ) fmod_audio_fini, + INIT_FIELD (pcm_ops = ) &fmod_pcm_ops, + INIT_FIELD (can_be_default = ) 1, + INIT_FIELD (max_voices_out = ) INT_MAX, + INIT_FIELD (max_voices_in = ) INT_MAX, + INIT_FIELD (voice_size_out = ) sizeof (FMODVoiceOut), + INIT_FIELD (voice_size_in = ) sizeof (FMODVoiceIn) }; diff --git a/audio/mixeng.c b/audio/mixeng.c index b0bb412c6..d43c5e59d 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -1,7 +1,7 @@ /* * QEMU Mixing engine * - * Copyright (c) 2004 Vassili Karpov (malc) + * Copyright (c) 2004-2005 Vassili Karpov (malc) * Copyright (c) 1998 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -23,87 +23,174 @@ * THE SOFTWARE. */ #include "vl.h" -//#define DEBUG_FP -#include "audio/mixeng.h" +#define AUDIO_CAP "mixeng" +#include "audio_int.h" + +#define NOVOL + +/* 8 bit */ +#define ENDIAN_CONVERSION natural +#define ENDIAN_CONVERT(v) (v) + +/* Signed 8 bit */ #define IN_T int8_t -#define IN_MIN CHAR_MIN -#define IN_MAX CHAR_MAX +#define IN_MIN SCHAR_MIN +#define IN_MAX SCHAR_MAX #define SIGNED +#define SHIFT 8 #include "mixeng_template.h" #undef SIGNED #undef IN_MAX #undef IN_MIN #undef IN_T +#undef SHIFT +/* Unsigned 8 bit */ #define IN_T uint8_t #define IN_MIN 0 #define IN_MAX UCHAR_MAX +#define SHIFT 8 #include "mixeng_template.h" #undef IN_MAX #undef IN_MIN #undef IN_T +#undef SHIFT + +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +/* Signed 16 bit */ #define IN_T int16_t #define IN_MIN SHRT_MIN #define IN_MAX SHRT_MAX #define SIGNED +#define SHIFT 16 +#define ENDIAN_CONVERSION natural +#define ENDIAN_CONVERT(v) (v) #include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#define ENDIAN_CONVERSION swap +#define ENDIAN_CONVERT(v) bswap16 (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION #undef SIGNED #undef IN_MAX #undef IN_MIN #undef IN_T +#undef SHIFT #define IN_T uint16_t #define IN_MIN 0 #define IN_MAX USHRT_MAX +#define SHIFT 16 +#define ENDIAN_CONVERSION natural +#define ENDIAN_CONVERT(v) (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#define ENDIAN_CONVERSION swap +#define ENDIAN_CONVERT(v) bswap16 (v) #include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION #undef IN_MAX #undef IN_MIN #undef IN_T +#undef SHIFT -t_sample *mixeng_conv[2][2][2] = { +t_sample *mixeng_conv[2][2][2][2] = { { { - conv_uint8_t_to_mono, - conv_uint16_t_to_mono + { + conv_natural_uint8_t_to_mono, + conv_natural_uint16_t_to_mono + }, + { + conv_natural_uint8_t_to_mono, + conv_swap_uint16_t_to_mono + } }, { - conv_int8_t_to_mono, - conv_int16_t_to_mono + { + conv_natural_int8_t_to_mono, + conv_natural_int16_t_to_mono + }, + { + conv_natural_int8_t_to_mono, + conv_swap_int16_t_to_mono + } } }, { { - conv_uint8_t_to_stereo, - conv_uint16_t_to_stereo + { + conv_natural_uint8_t_to_stereo, + conv_natural_uint16_t_to_stereo + }, + { + conv_natural_uint8_t_to_stereo, + conv_swap_uint16_t_to_stereo + } }, { - conv_int8_t_to_stereo, - conv_int16_t_to_stereo + { + conv_natural_int8_t_to_stereo, + conv_natural_int16_t_to_stereo + }, + { + conv_natural_int8_t_to_stereo, + conv_swap_int16_t_to_stereo + } } } }; -f_sample *mixeng_clip[2][2][2] = { +f_sample *mixeng_clip[2][2][2][2] = { { { - clip_uint8_t_from_mono, - clip_uint16_t_from_mono + { + clip_natural_uint8_t_from_mono, + clip_natural_uint16_t_from_mono + }, + { + clip_natural_uint8_t_from_mono, + clip_swap_uint16_t_from_mono + } }, { - clip_int8_t_from_mono, - clip_int16_t_from_mono + { + clip_natural_int8_t_from_mono, + clip_natural_int16_t_from_mono + }, + { + clip_natural_int8_t_from_mono, + clip_swap_int16_t_from_mono + } } }, { { - clip_uint8_t_from_stereo, - clip_uint16_t_from_stereo + { + clip_natural_uint8_t_from_stereo, + clip_natural_uint16_t_from_stereo + }, + { + clip_natural_uint8_t_from_stereo, + clip_swap_uint16_t_from_stereo + } }, { - clip_int8_t_from_stereo, - clip_int16_t_from_stereo + { + clip_natural_int8_t_from_stereo, + clip_natural_int16_t_from_stereo + }, + { + clip_natural_int8_t_from_stereo, + clip_swap_int16_t_from_stereo + } } } }; @@ -116,9 +203,9 @@ f_sample *mixeng_clip[2][2][2] = { * Contributors with a more efficient algorithm.] * * This source code is freely redistributable and may be used for - * any purpose. This copyright notice must be maintained. - * Lance Norskog And Sundry Contributors are not responsible for - * the consequences of using this software. + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. */ /* @@ -156,21 +243,13 @@ void *st_rate_start (int inrate, int outrate) rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff)); if (!rate) { - exit (EXIT_FAILURE); - } - - if (inrate == outrate) { - // exit (EXIT_FAILURE); - } - - if (inrate >= 65535 || outrate >= 65535) { - // exit (EXIT_FAILURE); + return NULL; } rate->opos = 0; /* increment */ - rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate; + rate->opos_inc = ((uint64_t) inrate << 32) / outrate; rate->ipos = 0; rate->ilast.l = 0; @@ -178,78 +257,20 @@ void *st_rate_start (int inrate, int outrate) return rate; } -/* - * Processed signed long samples from ibuf to obuf. - * Return number of samples processed. - */ -void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, - int *isamp, int *osamp) -{ - rate_t rate = (rate_t) opaque; - st_sample_t *istart, *iend; - st_sample_t *ostart, *oend; - st_sample_t ilast, icur, out; - int64_t t; - - ilast = rate->ilast; - - istart = ibuf; - iend = ibuf + *isamp; +#define NAME st_rate_flow_mix +#define OP(a, b) a += b +#include "rate_template.h" - ostart = obuf; - oend = obuf + *osamp; - - if (rate->opos_inc == 1ULL << 32) { - int i, n = *isamp > *osamp ? *osamp : *isamp; - for (i = 0; i < n; i++) { - obuf[i].l += ibuf[i].r; - obuf[i].r += ibuf[i].r; - } - *isamp = n; - *osamp = n; - return; - } - - while (obuf < oend) { - - /* Safety catch to make sure we have input samples. */ - if (ibuf >= iend) - break; - - /* read as many input samples so that ipos > opos */ - - while (rate->ipos <= (rate->opos >> 32)) { - ilast = *ibuf++; - rate->ipos++; - /* See if we finished the input buffer yet */ - if (ibuf >= iend) goto the_end; - } - - icur = *ibuf; - - /* interpolate */ - t = rate->opos & 0xffffffff; - out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX; - out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX; - - /* output sample & increment position */ -#if 0 - *obuf++ = out; -#else - obuf->l += out.l; - obuf->r += out.r; - obuf += 1; -#endif - rate->opos += rate->opos_inc; - } - -the_end: - *isamp = ibuf - istart; - *osamp = obuf - ostart; - rate->ilast = ilast; -} +#define NAME st_rate_flow +#define OP(a, b) a = b +#include "rate_template.h" void st_rate_stop (void *opaque) { qemu_free (opaque); } + +void mixeng_clear (st_sample_t *buf, int len) +{ + memset (buf, 0, len * sizeof (st_sample_t)); +} diff --git a/audio/mixeng.h b/audio/mixeng.h index 699435ea2..9e3bac174 100644 --- a/audio/mixeng.h +++ b/audio/mixeng.h @@ -1,8 +1,8 @@ /* * QEMU Mixing engine header - * - * Copyright (c) 2004 Vassili Karpov (malc) - * + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -24,16 +24,28 @@ #ifndef QEMU_MIXENG_H #define QEMU_MIXENG_H -typedef void (t_sample) (void *dst, const void *src, int samples); -typedef void (f_sample) (void *dst, const void *src, int samples); +#ifdef FLOAT_MIXENG +typedef float real_t; +typedef struct { int mute; real_t r; real_t l; } volume_t; +typedef struct { real_t l; real_t r; } st_sample_t; +#else +typedef struct { int mute; int64_t r; int64_t l; } volume_t; typedef struct { int64_t l; int64_t r; } st_sample_t; +#endif + +typedef void (t_sample) (st_sample_t *dst, const void *src, + int samples, volume_t *vol); +typedef void (f_sample) (void *dst, const st_sample_t *src, int samples); -extern t_sample *mixeng_conv[2][2][2]; -extern f_sample *mixeng_clip[2][2][2]; +extern t_sample *mixeng_conv[2][2][2][2]; +extern f_sample *mixeng_clip[2][2][2][2]; void *st_rate_start (int inrate, int outrate); void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, int *isamp, int *osamp); +void st_rate_flow_mix (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, + int *isamp, int *osamp); void st_rate_stop (void *opaque); +void mixeng_clear (st_sample_t *buf, int len); #endif /* mixeng.h */ diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h index f3b3f654f..d726441e2 100644 --- a/audio/mixeng_template.h +++ b/audio/mixeng_template.h @@ -1,8 +1,8 @@ /* * QEMU Mixing engine - * - * Copyright (c) 2004 Vassili Karpov (malc) - * + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -27,85 +27,151 @@ * dec++'ified by Dscho */ +#ifndef SIGNED +#define HALF (IN_MAX >> 1) +#endif + +#ifdef NOVOL +#define VOL(a, b) a +#else +#ifdef FLOAT_MIXENG +#define VOL(a, b) ((a) * (b)) +#else +#define VOL(a, b) ((a) * (b)) >> 32 +#endif +#endif + +#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T)) + +#ifdef FLOAT_MIXENG +static real_t inline glue (conv_, ET) (IN_T v) +{ + IN_T nv = ENDIAN_CONVERT (v); + +#ifdef RECIPROCAL +#ifdef SIGNED + return nv * (1.f / (real_t) (IN_MAX - IN_MIN)); +#else + return (nv - HALF) * (1.f / (real_t) IN_MAX); +#endif +#else /* !RECIPROCAL */ #ifdef SIGNED -#define HALFT IN_MAX -#define HALF IN_MAX + return nv / (real_t) (IN_MAX - IN_MIN); #else -#define HALFT ((IN_MAX)>>1) -#define HALF HALFT + return (nv - HALF) / (real_t) IN_MAX; #endif +#endif +} -static int64_t inline glue(conv_,IN_T) (IN_T v) +static IN_T inline glue (clip_, ET) (real_t v) { + if (v >= 0.5) { + return IN_MAX; + } + else if (v < -0.5) { + return IN_MIN; + } + +#ifdef SIGNED + return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN))); +#else + return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF)); +#endif +} + +#else /* !FLOAT_MIXENG */ + +static inline int64_t glue (conv_, ET) (IN_T v) +{ + IN_T nv = ENDIAN_CONVERT (v); #ifdef SIGNED - return (INT_MAX*(int64_t)v)/HALF; + return ((int64_t) nv) << (32 - SHIFT); #else - return (INT_MAX*((int64_t)v-HALFT))/HALF; + return ((int64_t) nv - HALF) << (32 - SHIFT); #endif } -static IN_T inline glue(clip_,IN_T) (int64_t v) +static inline IN_T glue (clip_, ET) (int64_t v) { - if (v >= INT_MAX) + if (v >= 0x7f000000) { return IN_MAX; - else if (v < -INT_MAX) + } + else if (v < -2147483648LL) { return IN_MIN; + } #ifdef SIGNED - return (IN_T) (v*HALF/INT_MAX); + return ENDIAN_CONVERT ((IN_T) (v >> (32 - SHIFT))); #else - return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX; + return ENDIAN_CONVERT ((IN_T) ((v >> (32 - SHIFT)) + HALF)); #endif } +#endif -static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src, - int samples) +static void glue (glue (conv_, ET), _to_stereo) + (st_sample_t *dst, const void *src, int samples, volume_t *vol) { - st_sample_t *out = (st_sample_t *) dst; + st_sample_t *out = dst; IN_T *in = (IN_T *) src; +#ifndef NOVOL + if (vol->mute) { + mixeng_clear (dst, samples); + return; + } +#else + (void) vol; +#endif while (samples--) { - out->l = glue(conv_,IN_T) (*in++); - out->r = glue(conv_,IN_T) (*in++); + out->l = VOL (glue (conv_, ET) (*in++), vol->l); + out->r = VOL (glue (conv_, ET) (*in++), vol->r); out += 1; } } -static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src, - int samples) +static void glue (glue (conv_, ET), _to_mono) + (st_sample_t *dst, const void *src, int samples, volume_t *vol) { - st_sample_t *out = (st_sample_t *) dst; + st_sample_t *out = dst; IN_T *in = (IN_T *) src; +#ifndef NOVOL + if (vol->mute) { + mixeng_clear (dst, samples); + return; + } +#else + (void) vol; +#endif while (samples--) { - out->l = glue(conv_,IN_T) (in[0]); + out->l = VOL (glue (conv_, ET) (in[0]), vol->l); out->r = out->l; out += 1; in += 1; } } -static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src, - int samples) +static void glue (glue (clip_, ET), _from_stereo) + (void *dst, const st_sample_t *src, int samples) { - st_sample_t *in = (st_sample_t *) src; + const st_sample_t *in = src; IN_T *out = (IN_T *) dst; while (samples--) { - *out++ = glue(clip_,IN_T) (in->l); - *out++ = glue(clip_,IN_T) (in->r); + *out++ = glue (clip_, ET) (in->l); + *out++ = glue (clip_, ET) (in->r); in += 1; } } -static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src, - int samples) +static void glue (glue (clip_, ET), _from_mono) + (void *dst, const st_sample_t *src, int samples) { - st_sample_t *in = (st_sample_t *) src; + const st_sample_t *in = src; IN_T *out = (IN_T *) dst; while (samples--) { - *out++ = glue(clip_,IN_T) (in->l + in->r); + *out++ = glue (clip_, ET) (in->l + in->r); in += 1; } } +#undef ET #undef HALF -#undef HALFT - +#undef VOL diff --git a/audio/noaudio.c b/audio/noaudio.c index a192885a7..e7936cc7b 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -1,8 +1,8 @@ /* - * QEMU NULL audio output driver - * - * Copyright (c) 2004 Vassili Karpov (malc) - * + * QEMU Timer based audio emulation + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -23,77 +23,110 @@ */ #include "vl.h" -#include "audio/audio_int.h" +#define AUDIO_CAP "noaudio" +#include "audio_int.h" -typedef struct NoVoice { - HWVoice hw; +typedef struct NoVoiceOut { + HWVoiceOut hw; int64_t old_ticks; -} NoVoice; +} NoVoiceOut; -#define dolog(...) AUD_log ("noaudio", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif +typedef struct NoVoiceIn { + HWVoiceIn hw; + int64_t old_ticks; +} NoVoiceIn; -static void no_hw_run (HWVoice *hw) +static int no_run_out (HWVoiceOut *hw) { - NoVoice *no = (NoVoice *) hw; - int rpos, live, decr, samples; - st_sample_t *src; + NoVoiceOut *no = (NoVoiceOut *) hw; + int live, decr, samples; int64_t now = qemu_get_clock (vm_clock); int64_t ticks = now - no->old_ticks; - int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; + int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - if (bytes > INT_MAX) - samples = INT_MAX >> hw->shift; - else - samples = bytes >> hw->shift; + if (bytes > INT_MAX) { + samples = INT_MAX >> hw->info.shift; + } + else { + samples = bytes >> hw->info.shift; + } - live = pcm_hw_get_live (hw); - if (live <= 0) - return; + live = audio_pcm_hw_get_live_out (&no->hw); + if (!live) { + return 0; + } no->old_ticks = now; decr = audio_MIN (live, samples); - samples = decr; - rpos = hw->rpos; - while (samples) { - int left_till_end_samples = hw->samples - rpos; - int convert_samples = audio_MIN (samples, left_till_end_samples); + hw->rpos = (hw->rpos + decr) % hw->samples; + return decr; +} - src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); - memset (src, 0, convert_samples * sizeof (st_sample_t)); +static int no_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} - rpos = (rpos + convert_samples) % hw->samples; - samples -= convert_samples; - } +static int no_init_out (HWVoiceOut *hw, int freq, + int nchannels, audfmt_e fmt) +{ + audio_pcm_init_info (&hw->info, freq, nchannels, fmt, 0); + hw->bufsize = 4096; + return 0; +} - pcm_hw_dec_live (hw, decr); - hw->rpos = rpos; +static void no_fini_out (HWVoiceOut *hw) +{ + (void) hw; } -static int no_hw_write (SWVoice *sw, void *buf, int len) +static int no_ctl_out (HWVoiceOut *hw, int cmd, ...) { - return pcm_hw_write (sw, buf, len); + (void) hw; + (void) cmd; + return 0; } -static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +static int no_init_in (HWVoiceIn *hw, int freq, + int nchannels, audfmt_e fmt) { - hw->freq = freq; - hw->nchannels = nchannels; - hw->fmt = fmt; + audio_pcm_init_info (&hw->info, freq, nchannels, fmt, 0); hw->bufsize = 4096; return 0; } -static void no_hw_fini (HWVoice *hw) +static void no_fini_in (HWVoiceIn *hw) { (void) hw; } -static int no_hw_ctl (HWVoice *hw, int cmd, ...) +static int no_run_in (HWVoiceIn *hw) +{ + NoVoiceIn *no = (NoVoiceIn *) hw; + int64_t now = qemu_get_clock (vm_clock); + int64_t ticks = now - no->old_ticks; + int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; + int live = audio_pcm_hw_get_live_in (hw); + int dead = hw->samples - live; + int samples; + + bytes = audio_MIN (bytes, INT_MAX); + samples = bytes >> hw->info.shift; + samples = audio_MIN (samples, dead); + + return samples; +} + +static int no_read (SWVoiceIn *sw, void *buf, int size) +{ + int samples = size >> sw->info.shift; + int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; + int to_clear = audio_MIN (samples, total); + audio_pcm_info_clear_buf (&sw->info, buf, to_clear); + return to_clear; +} + +static int no_ctl_in (HWVoiceIn *hw, int cmd, ...) { (void) hw; (void) cmd; @@ -107,22 +140,33 @@ static void *no_audio_init (void) static void no_audio_fini (void *opaque) { + (void) opaque; } -struct pcm_ops no_pcm_ops = { - no_hw_init, - no_hw_fini, - no_hw_run, - no_hw_write, - no_hw_ctl +static struct audio_pcm_ops no_pcm_ops = { + no_init_out, + no_fini_out, + no_run_out, + no_write, + no_ctl_out, + + no_init_in, + no_fini_in, + no_run_in, + no_read, + no_ctl_in }; -struct audio_output_driver no_output_driver = { - "none", - no_audio_init, - no_audio_fini, - &no_pcm_ops, - 1, - 1, - sizeof (NoVoice) +struct audio_driver no_audio_driver = { + INIT_FIELD (name = ) "none", + INIT_FIELD (descr = ) "Timer based audio emulation", + INIT_FIELD (options = ) NULL, + INIT_FIELD (init = ) no_audio_init, + INIT_FIELD (fini = ) no_audio_fini, + INIT_FIELD (pcm_ops = ) &no_pcm_ops, + INIT_FIELD (can_be_default = ) 1, + INIT_FIELD (max_voices_out = ) INT_MAX, + INIT_FIELD (max_voices_in = ) INT_MAX, + INIT_FIELD (voice_size_out = ) sizeof (NoVoiceOut), + INIT_FIELD (voice_size_in = ) sizeof (NoVoiceIn) }; diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 5246ebb78..ff1a03494 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -1,8 +1,8 @@ /* - * QEMU OSS audio output driver - * - * Copyright (c) 2003-2004 Vassili Karpov (malc) - * + * QEMU OSS audio driver + * + * Copyright (c) 2003-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -25,45 +25,42 @@ #include #include #include -#include #include "vl.h" -#include "audio/audio_int.h" +#define AUDIO_CAP "oss" +#include "audio_int.h" -typedef struct OSSVoice { - HWVoice hw; +typedef struct OSSVoiceOut { + HWVoiceOut hw; void *pcm_buf; int fd; int nfrags; int fragsize; int mmapped; int old_optr; -} OSSVoice; - -#define dolog(...) AUD_log ("oss", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif +} OSSVoiceOut; -#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" -#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" -#define QC_OSS_MMAP "QEMU_OSS_MMAP" -#define QC_OSS_DEV "QEMU_OSS_DEV" - -#define errstr() strerror (errno) +typedef struct OSSVoiceIn { + HWVoiceIn hw; + void *pcm_buf; + int fd; + int nfrags; + int fragsize; + int old_optr; +} OSSVoiceIn; static struct { int try_mmap; int nfrags; int fragsize; - const char *dspname; + const char *devpath_out; + const char *devpath_in; } conf = { .try_mmap = 0, .nfrags = 4, .fragsize = 4096, - .dspname = "/dev/dsp" + .devpath_out = "/dev/dsp", + .devpath_in = "/dev/dsp" }; struct oss_params { @@ -74,65 +71,141 @@ struct oss_params { int fragsize; }; -static int oss_hw_write (SWVoice *sw, void *buf, int len) +static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...) { - return pcm_hw_write (sw, buf, len); + va_list ap; + + AUD_vlog (AUDIO_CAP, fmt, ap); + + va_start (ap, fmt); + AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); + va_end (ap); } -static int AUD_to_ossfmt (audfmt_e fmt) +static void GCC_FMT_ATTR (3, 4) oss_logerr2 ( + int err, + const char *typ, + const char *fmt, + ... + ) +{ + va_list ap; + + AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); +} + +static void oss_anal_close (int *fdp) +{ + int err = close (*fdp); + if (err) { + oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp); + } + *fdp = -1; +} + +static int oss_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} + +static int aud_to_ossfmt (audfmt_e fmt) { switch (fmt) { - case AUD_FMT_S8: return AFMT_S8; - case AUD_FMT_U8: return AFMT_U8; - case AUD_FMT_S16: return AFMT_S16_LE; - case AUD_FMT_U16: return AFMT_U16_LE; + case AUD_FMT_S8: + return AFMT_S8; + + case AUD_FMT_U8: + return AFMT_U8; + + case AUD_FMT_S16: + return AFMT_S16_LE; + + case AUD_FMT_U16: + return AFMT_U16_LE; + default: - dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt); - exit (EXIT_FAILURE); + dolog ("Internal logic error: Bad audio format %d\n", fmt); +#ifdef DEBUG_AUDIO + abort (); +#endif + return AFMT_U8; } } -static int oss_to_audfmt (int fmt) +static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness) { - switch (fmt) { - case AFMT_S8: return AUD_FMT_S8; - case AFMT_U8: return AUD_FMT_U8; - case AFMT_S16_LE: return AUD_FMT_S16; - case AFMT_U16_LE: return AUD_FMT_U16; + switch (ossfmt) { + case AFMT_S8: + *endianness =0; + *fmt = AUD_FMT_S8; + break; + + case AFMT_U8: + *endianness = 0; + *fmt = AUD_FMT_U8; + break; + + case AFMT_S16_LE: + *endianness = 0; + *fmt = AUD_FMT_S16; + break; + + case AFMT_U16_LE: + *endianness = 0; + *fmt = AUD_FMT_U16; + break; + + case AFMT_S16_BE: + *endianness = 1; + *fmt = AUD_FMT_S16; + break; + + case AFMT_U16_BE: + *endianness = 1; + *fmt = AUD_FMT_U16; + break; + default: - dolog ("Internal logic error: Unrecognized OSS audio format %d\n" - "Aborting\n", - fmt); - exit (EXIT_FAILURE); + dolog ("Unrecognized audio format %d\n", ossfmt); + return -1; } + + return 0; } -#ifdef DEBUG_PCM -static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt) +#ifdef DEBUG_MISMATCHES +static void oss_dump_info (struct oss_params *req, struct oss_params *obt) { dolog ("parameter | requested value | obtained value\n"); dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); - dolog ("channels | %10d | %10d\n", req->nchannels, obt->nchannels); + dolog ("channels | %10d | %10d\n", + req->nchannels, obt->nchannels); dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); - dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize); + dolog ("fragsize | %10d | %10d\n", + req->fragsize, obt->fragsize); } #endif -static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd) +static int oss_open (int in, struct oss_params *req, + struct oss_params *obt, int *pfd) { int fd; int mmmmssss; audio_buf_info abinfo; int fmt, freq, nchannels; - const char *dspname = conf.dspname; + const char *dspname = in ? conf.devpath_in : conf.devpath_out; + const char *typ = in ? "ADC" : "DAC"; - fd = open (dspname, O_WRONLY | O_NONBLOCK); + fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK); if (-1 == fd) { - dolog ("Could not initialize audio hardware. Failed to open `%s':\n" - "Reason:%s\n", - dspname, - errstr ()); + oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname); return -1; } @@ -141,52 +214,35 @@ static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd) fmt = req->fmt; if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { - dolog ("Could not initialize audio hardware\n" - "Failed to set sample size\n" - "Reason: %s\n", - errstr ()); + oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt); goto err; } if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) { - dolog ("Could not initialize audio hardware\n" - "Failed to set number of channels\n" - "Reason: %s\n", - errstr ()); + oss_logerr2 (errno, typ, "Failed to set number of channels %d\n", + req->nchannels); goto err; } if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) { - dolog ("Could not initialize audio hardware\n" - "Failed to set frequency\n" - "Reason: %s\n", - errstr ()); + oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq); goto err; } if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) { - dolog ("Could not initialize audio hardware\n" - "Failed to set non-blocking mode\n" - "Reason: %s\n", - errstr ()); + oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n"); goto err; } mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize); if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { - dolog ("Could not initialize audio hardware\n" - "Failed to set buffer length (%d, %d)\n" - "Reason:%s\n", - conf.nfrags, conf.fragsize, - errstr ()); + oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n", + req->nfrags, req->fragsize); goto err; } - if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) { - dolog ("Could not initialize audio hardware\n" - "Failed to get buffer length\n" - "Reason:%s\n", - errstr ()); + if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) { + oss_logerr2 (errno, typ, "Failed to get buffer length\n"); goto err; } @@ -202,25 +258,25 @@ static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd) (req->freq != obt->freq) || (req->fragsize != obt->fragsize) || (req->nfrags != obt->nfrags)) { -#ifdef DEBUG_PCM +#ifdef DEBUG_MISMATCHES dolog ("Audio parameters mismatch\n"); - oss_dump_pcm_info (req, obt); + oss_dump_info (req, obt); #endif } -#ifdef DEBUG_PCM - oss_dump_pcm_info (req, obt); +#ifdef DEBUG + oss_dump_info (req, obt); #endif return 0; -err: - close (fd); + err: + oss_anal_close (&fd); return -1; } -static void oss_hw_run (HWVoice *hw) +static int oss_run_out (HWVoiceOut *hw) { - OSSVoice *oss = (OSSVoice *) hw; + OSSVoiceOut *oss = (OSSVoiceOut *) hw; int err, rpos, live, decr; int samples; uint8_t *dst; @@ -228,23 +284,25 @@ static void oss_hw_run (HWVoice *hw) struct audio_buf_info abinfo; struct count_info cntinfo; - live = pcm_hw_get_live (hw); - if (live <= 0) - return; + live = audio_pcm_hw_get_live_out (hw); + if (!live) { + return 0; + } if (oss->mmapped) { int bytes; err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); if (err < 0) { - dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ()); - return; + oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); + return 0; } if (cntinfo.ptr == oss->old_optr) { - if (abs (hw->samples - live) < 64) - dolog ("overrun\n"); - return; + if (abs (hw->samples - live) < 64) { + dolog ("warning: overrun\n"); + } + return 0; } if (cntinfo.ptr > oss->old_optr) { @@ -254,18 +312,25 @@ static void oss_hw_run (HWVoice *hw) bytes = hw->bufsize + cntinfo.ptr - oss->old_optr; } - decr = audio_MIN (bytes >> hw->shift, live); + decr = audio_MIN (bytes >> hw->info.shift, live); } else { err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo); if (err < 0) { - dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ()); - return; + oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); + return 0; + } + + if (abinfo.bytes < 0 || abinfo.bytes > hw->bufsize) { + ldebug ("warning: invalid available size, size=%d bufsize=%d\n", + abinfo.bytes, hw->bufsize); + return 0; } - decr = audio_MIN (abinfo.bytes >> hw->shift, live); - if (decr <= 0) - return; + decr = audio_MIN (abinfo.bytes >> hw->info.shift, live); + if (!decr) { + return 0; + } } samples = decr; @@ -274,33 +339,41 @@ static void oss_hw_run (HWVoice *hw) int left_till_end_samples = hw->samples - rpos; int convert_samples = audio_MIN (samples, left_till_end_samples); - src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); - dst = advance (oss->pcm_buf, rpos << hw->shift); + src = hw->mix_buf + rpos; + dst = advance (oss->pcm_buf, rpos << hw->info.shift); hw->clip (dst, src, convert_samples); if (!oss->mmapped) { int written; - written = write (oss->fd, dst, convert_samples << hw->shift); + written = write (oss->fd, dst, convert_samples << hw->info.shift); /* XXX: follow errno recommendations ? */ if (written == -1) { - dolog ("Failed to write audio\nReason: %s\n", errstr ()); + oss_logerr ( + errno, + "Failed to write %d bytes of audio data from %p\n", + convert_samples << hw->info.shift, + dst + ); continue; } - if (written != convert_samples << hw->shift) { - int wsamples = written >> hw->shift; - int wbytes = wsamples << hw->shift; + if (written != convert_samples << hw->info.shift) { + int wsamples = written >> hw->info.shift; + int wbytes = wsamples << hw->info.shift; if (wbytes != written) { - dolog ("Unaligned write %d, %d\n", wbytes, written); + dolog ("warning: misaligned write %d (requested %d), " + "alignment %d\n", + wbytes, written, hw->info.align + 1); } - memset (src, 0, wbytes); - decr -= samples; + mixeng_clear (src, wsamples); + decr -= wsamples; rpos = (rpos + wsamples) % hw->samples; break; } } - memset (src, 0, convert_samples * sizeof (st_sample_t)); + + mixeng_clear (src, convert_samples); rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; @@ -309,28 +382,24 @@ static void oss_hw_run (HWVoice *hw) oss->old_optr = cntinfo.ptr; } - pcm_hw_dec_live (hw, decr); hw->rpos = rpos; + return decr; } -static void oss_hw_fini (HWVoice *hw) +static void oss_fini_out (HWVoiceOut *hw) { int err; - OSSVoice *oss = (OSSVoice *) hw; + OSSVoiceOut *oss = (OSSVoiceOut *) hw; - ldebug ("oss_hw_fini\n"); - err = close (oss->fd); - if (err) { - dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ()); - } - oss->fd = -1; + ldebug ("oss_fini\n"); + oss_anal_close (&oss->fd); if (oss->pcm_buf) { if (oss->mmapped) { err = munmap (oss->pcm_buf, hw->bufsize); if (err) { - dolog ("Failed to unmap OSS buffer\nReason: %s\n", - errstr ()); + oss_logerr (errno, "Failed to unmap buffer %p, size %d\n", + oss->pcm_buf, hw->bufsize); } } else { @@ -340,25 +409,38 @@ static void oss_hw_fini (HWVoice *hw) } } -static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) { - OSSVoice *oss = (OSSVoice *) hw; + OSSVoiceOut *oss = (OSSVoiceOut *) hw; struct oss_params req, obt; + int endianness; + int err; + int fd; + audfmt_e effective_fmt; - assert (!oss->fd); - req.fmt = AUD_to_ossfmt (fmt); + req.fmt = aud_to_ossfmt (fmt); req.freq = freq; req.nchannels = nchannels; req.fragsize = conf.fragsize; req.nfrags = conf.nfrags; - if (oss_open (&req, &obt, &oss->fd)) + if (oss_open (0, &req, &obt, &fd)) { return -1; + } - hw->freq = obt.freq; - hw->fmt = oss_to_audfmt (obt.fmt); - hw->nchannels = obt.nchannels; + err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); + if (err) { + oss_anal_close (&fd); + return -1; + } + audio_pcm_init_info ( + &hw->info, + obt.freq, + obt.nchannels, + effective_fmt, + audio_need_to_swap_endian (endianness) + ); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; hw->bufsize = obt.nfrags * obt.fragsize; @@ -366,22 +448,23 @@ static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) oss->mmapped = 0; if (conf.try_mmap) { oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE, - MAP_SHARED, oss->fd, 0); + MAP_SHARED, fd, 0); if (oss->pcm_buf == MAP_FAILED) { - dolog ("Failed to mmap OSS device\nReason: %s\n", - errstr ()); + oss_logerr (errno, "Failed to map %d bytes of DAC\n", + hw->bufsize); } else { int err; int trig = 0; - if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n", - errstr ()); + if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); } else { trig = PCM_ENABLE_OUTPUT; - if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" - "Reason: %s\n", errstr ()); + if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { + oss_logerr ( + errno, + "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" + ); } else { oss->mmapped = 1; @@ -391,8 +474,8 @@ static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) if (!oss->mmapped) { err = munmap (oss->pcm_buf, hw->bufsize); if (err) { - dolog ("Failed to unmap OSS device\nReason: %s\n", - errstr ()); + oss_logerr (errno, "Failed to unmap buffer %p size %d\n", + oss->pcm_buf, hw->bufsize); } } } @@ -401,31 +484,34 @@ static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) if (!oss->mmapped) { oss->pcm_buf = qemu_mallocz (hw->bufsize); if (!oss->pcm_buf) { - close (oss->fd); - oss->fd = -1; + oss_anal_close (&fd); return -1; } } + oss->fd = fd; return 0; } -static int oss_hw_ctl (HWVoice *hw, int cmd, ...) +static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) { int trig; - OSSVoice *oss = (OSSVoice *) hw; + OSSVoiceOut *oss = (OSSVoiceOut *) hw; - if (!oss->mmapped) + if (!oss->mmapped) { return 0; + } switch (cmd) { case VOICE_ENABLE: ldebug ("enabling voice\n"); - pcm_hw_clear (hw, oss->pcm_buf, hw->samples); + audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples); trig = PCM_ENABLE_OUTPUT; if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" - "Reason: %s\n", errstr ()); + oss_logerr ( + errno, + "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" + ); return -1; } break; @@ -434,8 +520,7 @@ static int oss_hw_ctl (HWVoice *hw, int cmd, ...) ldebug ("disabling voice\n"); trig = 0; if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n", - errstr ()); + oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); return -1; } break; @@ -443,33 +528,194 @@ static int oss_hw_ctl (HWVoice *hw, int cmd, ...) return 0; } +static int oss_init_in (HWVoiceIn *hw, + int freq, int nchannels, audfmt_e fmt) +{ + OSSVoiceIn *oss = (OSSVoiceIn *) hw; + struct oss_params req, obt; + int endianness; + int err; + int fd; + audfmt_e effective_fmt; + + req.fmt = aud_to_ossfmt (fmt); + req.freq = freq; + req.nchannels = nchannels; + req.fragsize = conf.fragsize; + req.nfrags = conf.nfrags; + if (oss_open (1, &req, &obt, &fd)) { + return -1; + } + + err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); + if (err) { + oss_anal_close (&fd); + return -1; + } + + audio_pcm_init_info ( + &hw->info, + obt.freq, + obt.nchannels, + effective_fmt, + audio_need_to_swap_endian (endianness) + ); + oss->nfrags = obt.nfrags; + oss->fragsize = obt.fragsize; + hw->bufsize = obt.nfrags * obt.fragsize; + oss->pcm_buf = qemu_mallocz (hw->bufsize); + if (!oss->pcm_buf) { + oss_anal_close (&fd); + return -1; + } + + oss->fd = fd; + return 0; +} + +static void oss_fini_in (HWVoiceIn *hw) +{ + OSSVoiceIn *oss = (OSSVoiceIn *) hw; + + oss_anal_close (&oss->fd); + + if (oss->pcm_buf) { + qemu_free (oss->pcm_buf); + oss->pcm_buf = NULL; + } +} + +static int oss_run_in (HWVoiceIn *hw) +{ + OSSVoiceIn *oss = (OSSVoiceIn *) hw; + int hwshift = hw->info.shift; + int i; + int live = audio_pcm_hw_get_live_in (hw); + int dead = hw->samples - live; + size_t read_samples = 0; + struct { + int add; + int len; + } bufs[2] = { + { hw->wpos, 0 }, + { 0, 0 } + }; + + if (!dead) { + return 0; + } + + if (hw->wpos + dead > hw->samples) { + bufs[0].len = (hw->samples - hw->wpos) << hwshift; + bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift; + } + else { + bufs[0].len = dead << hwshift; + } + + + for (i = 0; i < 2; ++i) { + ssize_t nread; + + if (bufs[i].len) { + void *p = advance (oss->pcm_buf, bufs[i].add << hwshift); + nread = read (oss->fd, p, bufs[i].len); + + if (nread > 0) { + if (nread & hw->info.align) { + dolog ("warning: misaligned read %d (requested %d), " + "alignment %d\n", nread, bufs[i].add << hwshift, + hw->info.align + 1); + } + read_samples += nread >> hwshift; + hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift, + &nominal_volume); + } + + if (bufs[i].len - nread) { + if (nread == -1) { + switch (errno) { + case EINTR: + case EAGAIN: + break; + default: + oss_logerr ( + errno, + "Failed to read %d bytes of audio (to %p)\n", + bufs[i].len, p + ); + break; + } + } + break; + } + } + } + + hw->wpos = (hw->wpos + read_samples) % hw->samples; + return read_samples; +} + +static int oss_read (SWVoiceIn *sw, void *buf, int size) +{ + return audio_pcm_sw_read (sw, buf, size); +} + +static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) +{ + (void) hw; + (void) cmd; + return 0; +} + static void *oss_audio_init (void) { - conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize); - conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags); - conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap); - conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname); return &conf; } static void oss_audio_fini (void *opaque) { + (void) opaque; } -struct pcm_ops oss_pcm_ops = { - oss_hw_init, - oss_hw_fini, - oss_hw_run, - oss_hw_write, - oss_hw_ctl +static struct audio_option oss_options[] = { + {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize, + "Fragment size in bytes", NULL, 0}, + {"NFRAGS", AUD_OPT_INT, &conf.nfrags, + "Number of fragments", NULL, 0}, + {"MMAP", AUD_OPT_BOOL, &conf.try_mmap, + "Try using memory mapped access", NULL, 0}, + {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out, + "Path to DAC device", NULL, 0}, + {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in, + "Path to ADC device", NULL, 0}, + {NULL, 0, NULL, NULL, NULL, 0} +}; + +static struct audio_pcm_ops oss_pcm_ops = { + oss_init_out, + oss_fini_out, + oss_run_out, + oss_write, + oss_ctl_out, + + oss_init_in, + oss_fini_in, + oss_run_in, + oss_read, + oss_ctl_in }; -struct audio_output_driver oss_output_driver = { - "oss", - oss_audio_init, - oss_audio_fini, - &oss_pcm_ops, - 1, - INT_MAX, - sizeof (OSSVoice) +struct audio_driver oss_audio_driver = { + INIT_FIELD (name = ) "oss", + INIT_FIELD (descr = ) "OSS http://www.opensound.com", + INIT_FIELD (options = ) oss_options, + INIT_FIELD (init = ) oss_audio_init, + INIT_FIELD (fini = ) oss_audio_fini, + INIT_FIELD (pcm_ops = ) &oss_pcm_ops, + INIT_FIELD (can_be_default = ) 1, + INIT_FIELD (max_voices_out = ) INT_MAX, + INIT_FIELD (max_voices_in = ) INT_MAX, + INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut), + INIT_FIELD (voice_size_in = ) sizeof (OSSVoiceIn) }; diff --git a/audio/rate_template.h b/audio/rate_template.h new file mode 100644 index 000000000..5cc95c829 --- /dev/null +++ b/audio/rate_template.h @@ -0,0 +1,111 @@ +/* + * QEMU Mixing engine + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * Copyright (c) 1998 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, + int *isamp, int *osamp) +{ + rate_t rate = (rate_t) opaque; + st_sample_t *istart, *iend; + st_sample_t *ostart, *oend; + st_sample_t ilast, icur, out; +#ifdef FLOAT_MIXENG + real_t t; +#else + int64_t t; +#endif + + ilast = rate->ilast; + + istart = ibuf; + iend = ibuf + *isamp; + + ostart = obuf; + oend = obuf + *osamp; + + if (rate->opos_inc == (1ULL + UINT_MAX)) { + int i, n = *isamp > *osamp ? *osamp : *isamp; + for (i = 0; i < n; i++) { + OP (obuf[i].l, ibuf[i].r); + OP (obuf[i].r, ibuf[i].r); + } + *isamp = n; + *osamp = n; + return; + } + + while (obuf < oend) { + + /* Safety catch to make sure we have input samples. */ + if (ibuf >= iend) { + break; + } + + /* read as many input samples so that ipos > opos */ + + while (rate->ipos <= (rate->opos >> 32)) { + ilast = *ibuf++; + rate->ipos++; + /* See if we finished the input buffer yet */ + if (ibuf >= iend) { + goto the_end; + } + } + + icur = *ibuf; + + /* interpolate */ +#ifdef FLOAT_MIXENG +#ifdef RECIPROCAL + t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX); +#else + t = (rate->opos & UINT_MAX) / (real_t) UINT_MAX; +#endif + out.l = (ilast.l * (1.0 - t)) + icur.l * t; + out.r = (ilast.r * (1.0 - t)) + icur.r * t; +#else + t = rate->opos & 0xffffffff; + out.l = (ilast.l * ((int64_t) UINT_MAX - t) + icur.l * t) >> 32; + out.r = (ilast.r * ((int64_t) UINT_MAX - t) + icur.r * t) >> 32; +#endif + + /* output sample & increment position */ + OP (obuf->l, out.l); + OP (obuf->r, out.r); + obuf += 1; + rate->opos += rate->opos_inc; + } + +the_end: + *isamp = ibuf - istart; + *osamp = obuf - ostart; + rate->ilast = ilast; +} + +#undef NAME +#undef OP diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 978686a07..673e2a112 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -1,8 +1,8 @@ /* - * QEMU SDL audio output driver - * - * Copyright (c) 2004 Vassili Karpov (malc) - * + * QEMU SDL audio driver + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -25,22 +25,15 @@ #include #include "vl.h" -#include "audio/audio_int.h" - -typedef struct SDLVoice { - HWVoice hw; -} SDLVoice; - -#define dolog(...) AUD_log ("sdl", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif +#define AUDIO_CAP "sdl" +#include "audio_int.h" -#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES" - -#define errstr() SDL_GetError () +typedef struct SDLVoiceOut { + HWVoiceOut hw; + int live; + int rpos; + int decr; +} SDLVoiceOut; static struct { int nb_samples; @@ -56,91 +49,129 @@ struct SDLAudioState { } glob_sdl; typedef struct SDLAudioState SDLAudioState; -static void sdl_hw_run (HWVoice *hw) +static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...) { - (void) hw; + va_list ap; + + va_start (ap, fmt); + AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); + + AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ()); } -static int sdl_lock (SDLAudioState *s) +static int sdl_lock (SDLAudioState *s, const char *forfn) { if (SDL_LockMutex (s->mutex)) { - dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ()); + sdl_logerr ("SDL_LockMutex for %s failed\n", forfn); return -1; } return 0; } -static int sdl_unlock (SDLAudioState *s) +static int sdl_unlock (SDLAudioState *s, const char *forfn) { if (SDL_UnlockMutex (s->mutex)) { - dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ()); + sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn); return -1; } return 0; } -static int sdl_post (SDLAudioState *s) +static int sdl_post (SDLAudioState *s, const char *forfn) { if (SDL_SemPost (s->sem)) { - dolog ("SDL_SemPost failed\nReason: %s\n", errstr ()); + sdl_logerr ("SDL_SemPost for %s failed\n", forfn); return -1; } return 0; } -static int sdl_wait (SDLAudioState *s) +static int sdl_wait (SDLAudioState *s, const char *forfn) { if (SDL_SemWait (s->sem)) { - dolog ("SDL_SemWait failed\nReason: %s\n", errstr ()); + sdl_logerr ("SDL_SemWait for %s failed\n", forfn); return -1; } return 0; } -static int sdl_unlock_and_post (SDLAudioState *s) +static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn) { - if (sdl_unlock (s)) + if (sdl_unlock (s, forfn)) { return -1; + } - return sdl_post (s); -} - -static int sdl_hw_write (SWVoice *sw, void *buf, int len) -{ - int ret; - SDLAudioState *s = &glob_sdl; - sdl_lock (s); - ret = pcm_hw_write (sw, buf, len); - sdl_unlock_and_post (s); - return ret; + return sdl_post (s, forfn); } -static int AUD_to_sdlfmt (audfmt_e fmt, int *shift) +static int aud_to_sdlfmt (audfmt_e fmt, int *shift) { - *shift = 0; switch (fmt) { - case AUD_FMT_S8: return AUDIO_S8; - case AUD_FMT_U8: return AUDIO_U8; - case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB; - case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB; + case AUD_FMT_S8: + *shift = 0; + return AUDIO_S8; + + case AUD_FMT_U8: + *shift = 0; + return AUDIO_U8; + + case AUD_FMT_S16: + *shift = 1; + return AUDIO_S16LSB; + + case AUD_FMT_U16: + *shift = 1; + return AUDIO_U16LSB; + default: - dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt); - exit (EXIT_FAILURE); + dolog ("Internal logic error: Bad audio format %d\n", fmt); +#ifdef DEBUG_AUDIO + abort (); +#endif + return AUDIO_U8; } } -static int sdl_to_audfmt (int fmt) +static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess) { - switch (fmt) { - case AUDIO_S8: return AUD_FMT_S8; - case AUDIO_U8: return AUD_FMT_U8; - case AUDIO_S16LSB: return AUD_FMT_S16; - case AUDIO_U16LSB: return AUD_FMT_U16; + switch (sdlfmt) { + case AUDIO_S8: + *endianess = 0; + *fmt = AUD_FMT_S8; + break; + + case AUDIO_U8: + *endianess = 0; + *fmt = AUD_FMT_U8; + break; + + case AUDIO_S16LSB: + *endianess = 0; + *fmt = AUD_FMT_S16; + break; + + case AUDIO_U16LSB: + *endianess = 0; + *fmt = AUD_FMT_U16; + break; + + case AUDIO_S16MSB: + *endianess = 1; + *fmt = AUD_FMT_S16; + break; + + case AUDIO_U16MSB: + *endianess = 1; + *fmt = AUD_FMT_U16; + break; + default: - dolog ("Internal logic error: Unrecognized SDL audio format %d\n" - "Aborting\n", fmt); - exit (EXIT_FAILURE); + dolog ("Unrecognized SDL audio format %d\n", sdlfmt); + return -1; } + + return 0; } static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) @@ -149,7 +180,7 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) status = SDL_OpenAudio (req, obt); if (status) { - dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ()); + sdl_logerr ("SDL_OpenAudio failed\n"); } return status; } @@ -157,9 +188,9 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) static void sdl_close (SDLAudioState *s) { if (s->initialized) { - sdl_lock (s); + sdl_lock (s, "sdl_close"); s->exit = 1; - sdl_unlock_and_post (s); + sdl_unlock_and_post (s, "sdl_close"); SDL_PauseAudio (1); SDL_CloseAudio (); s->initialized = 0; @@ -168,31 +199,40 @@ static void sdl_close (SDLAudioState *s) static void sdl_callback (void *opaque, Uint8 *buf, int len) { - SDLVoice *sdl = opaque; + SDLVoiceOut *sdl = opaque; SDLAudioState *s = &glob_sdl; - HWVoice *hw = &sdl->hw; - int samples = len >> hw->shift; + HWVoiceOut *hw = &sdl->hw; + int samples = len >> hw->info.shift; if (s->exit) { return; } while (samples) { - int to_mix, live, decr; + int to_mix, decr; /* dolog ("in callback samples=%d\n", samples); */ - sdl_wait (s); + sdl_wait (s, "sdl_callback"); if (s->exit) { return; } - sdl_lock (s); - live = pcm_hw_get_live (hw); - if (live <= 0) + if (sdl_lock (s, "sdl_callback")) { + return; + } + + if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) { + dolog ("sdl->live=%d hw->samples=%d\n", + sdl->live, hw->samples); + return; + } + + if (!sdl->live) { goto again; + } /* dolog ("in callback live=%d\n", live); */ - to_mix = audio_MIN (samples, live); + to_mix = audio_MIN (samples, sdl->live); decr = to_mix; while (to_mix) { int chunk = audio_MIN (to_mix, hw->samples - hw->rpos); @@ -200,44 +240,86 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len) /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ hw->clip (buf, src, chunk); - memset (src, 0, chunk * sizeof (st_sample_t)); - hw->rpos = (hw->rpos + chunk) % hw->samples; + mixeng_clear (src, chunk); + sdl->rpos = (sdl->rpos + chunk) % hw->samples; to_mix -= chunk; - buf += chunk << hw->shift; + buf += chunk << hw->info.shift; } samples -= decr; - pcm_hw_dec_live (hw, decr); + sdl->live -= decr; + sdl->decr += decr; again: - sdl_unlock (s); + if (sdl_unlock (s, "sdl_callback")) { + return; + } } /* dolog ("done len=%d\n", len); */ } -static void sdl_hw_fini (HWVoice *hw) +static int sdl_write_out (SWVoiceOut *sw, void *buf, int len) { - ldebug ("sdl_hw_fini %d fixed=%d\n", - glob_sdl.initialized, audio_state.fixed_format); + return audio_pcm_sw_write (sw, buf, len); +} + +static int sdl_run_out (HWVoiceOut *hw) +{ + int decr, live; + SDLVoiceOut *sdl = (SDLVoiceOut *) hw; + SDLAudioState *s = &glob_sdl; + + if (sdl_lock (s, "sdl_callback")) { + return 0; + } + + live = audio_pcm_hw_get_live_out (hw); + + if (sdl->decr > live) { + ldebug ("sdl->decr %d live %d sdl->live %d\n", + sdl->decr, + live, + sdl->live); + } + + decr = audio_MIN (sdl->decr, live); + sdl->decr -= decr; + + sdl->live = live - decr; + hw->rpos = sdl->rpos; + + if (sdl->live > 0) { + sdl_unlock_and_post (s, "sdl_callback"); + } + else { + sdl_unlock (s, "sdl_callback"); + } + return decr; +} + +static void sdl_fini_out (HWVoiceOut *hw) +{ + (void) hw; + sdl_close (&glob_sdl); } -static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +static int sdl_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) { - SDLVoice *sdl = (SDLVoice *) hw; + SDLVoiceOut *sdl = (SDLVoiceOut *) hw; SDLAudioState *s = &glob_sdl; SDL_AudioSpec req, obt; int shift; - - ldebug ("sdl_hw_init %d freq=%d fixed=%d\n", - s->initialized, freq, audio_state.fixed_format); + int endianess; + int err; + audfmt_e effective_fmt; if (nchannels != 2) { - dolog ("Bogus channel count %d\n", nchannels); + dolog ("Can not init DAC. Bogus channel count %d\n", nchannels); return -1; } req.freq = freq; - req.format = AUD_to_sdlfmt (fmt, &shift); + req.format = aud_to_sdlfmt (fmt, &shift); req.channels = nchannels; req.samples = conf.nb_samples; shift <<= nchannels == 2; @@ -245,12 +327,23 @@ static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) req.callback = sdl_callback; req.userdata = sdl; - if (sdl_open (&req, &obt)) + if (sdl_open (&req, &obt)) { + return -1; + } + + err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess); + if (err) { + sdl_close (s); return -1; + } - hw->freq = obt.freq; - hw->fmt = sdl_to_audfmt (obt.format); - hw->nchannels = obt.channels; + audio_pcm_init_info ( + &hw->info, + obt.freq, + obt.channels, + effective_fmt, + audio_need_to_swap_endian (endianess) + ); hw->bufsize = obt.samples << shift; s->initialized = 1; @@ -259,7 +352,7 @@ static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) return 0; } -static int sdl_hw_ctl (HWVoice *hw, int cmd, ...) +static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...) { (void) hw; @@ -278,24 +371,22 @@ static int sdl_hw_ctl (HWVoice *hw, int cmd, ...) static void *sdl_audio_init (void) { SDLAudioState *s = &glob_sdl; - conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples); if (SDL_InitSubSystem (SDL_INIT_AUDIO)) { - dolog ("SDL failed to initialize audio subsystem\nReason: %s\n", - errstr ()); + sdl_logerr ("SDL failed to initialize audio subsystem\n"); return NULL; } s->mutex = SDL_CreateMutex (); if (!s->mutex) { - dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ()); + sdl_logerr ("Failed to create SDL mutex\n"); SDL_QuitSubSystem (SDL_INIT_AUDIO); return NULL; } s->sem = SDL_CreateSemaphore (0); if (!s->sem) { - dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ()); + sdl_logerr ("Failed to create SDL semaphore\n"); SDL_DestroyMutex (s->mutex); SDL_QuitSubSystem (SDL_INIT_AUDIO); return NULL; @@ -313,20 +404,36 @@ static void sdl_audio_fini (void *opaque) SDL_QuitSubSystem (SDL_INIT_AUDIO); } -struct pcm_ops sdl_pcm_ops = { - sdl_hw_init, - sdl_hw_fini, - sdl_hw_run, - sdl_hw_write, - sdl_hw_ctl +static struct audio_option sdl_options[] = { + {"SAMPLES", AUD_OPT_INT, &conf.nb_samples, + "Size of SDL buffer in samples", NULL, 0}, + {NULL, 0, NULL, NULL, NULL, 0} +}; + +static struct audio_pcm_ops sdl_pcm_ops = { + sdl_init_out, + sdl_fini_out, + sdl_run_out, + sdl_write_out, + sdl_ctl_out, + + NULL, + NULL, + NULL, + NULL, + NULL }; -struct audio_output_driver sdl_output_driver = { - "sdl", - sdl_audio_init, - sdl_audio_fini, - &sdl_pcm_ops, - 1, - 1, - sizeof (SDLVoice) +struct audio_driver sdl_audio_driver = { + INIT_FIELD (name = ) "sdl", + INIT_FIELD (descr = ) "SDL http://www.libsdl.org", + INIT_FIELD (options = ) sdl_options, + INIT_FIELD (init = ) sdl_audio_init, + INIT_FIELD (fini = ) sdl_audio_fini, + INIT_FIELD (pcm_ops = ) &sdl_pcm_ops, + INIT_FIELD (can_be_default = ) 1, + INIT_FIELD (max_voices_out = ) 1, + INIT_FIELD (max_voices_in = ) 0, + INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut), + INIT_FIELD (voice_size_in = ) 0 }; diff --git a/audio/sys-queue.h b/audio/sys-queue.h new file mode 100644 index 000000000..5b6e2a0a2 --- /dev/null +++ b/audio/sys-queue.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)queue.h 8.3 (Berkeley) 12/13/93 + */ + +#ifndef _SYS_QUEUE_H +#define _SYS_QUEUE_H 1 + +/* + * This file defines three types of data structures: lists, tail queues, + * and circular queues. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list after + * an existing element or at the head of the list. A list may only be + * traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A tail queue may only be traversed in the forward direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define LIST_INIT(head) { \ + (head)->lh_first = NULL; \ +} + +#define LIST_INSERT_AFTER(listelm, elm, field) { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} + +#define LIST_INSERT_HEAD(head, elm, field) { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} + +#define LIST_REMOVE(elm, field) { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} + +#define TAILQ_INSERT_HEAD(head, elm, field) { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} + +#define TAILQ_INSERT_TAIL(head, elm, field) { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} + +#define TAILQ_REMOVE(head, elm, field) { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} + +#define CIRCLEQ_REMOVE(head, elm, field) { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} +#endif /* sys/queue.h */ diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 5680161c7..e9bd87872 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -1,8 +1,8 @@ /* - * QEMU WAV audio output driver - * - * Copyright (c) 2004 Vassili Karpov (malc) - * + * QEMU WAV audio driver + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -23,22 +23,16 @@ */ #include "vl.h" -#include "audio/audio_int.h" +#define AUDIO_CAP "wav" +#include "audio_int.h" -typedef struct WAVVoice { - HWVoice hw; +typedef struct WAVVoiceOut { + HWVoiceOut hw; QEMUFile *f; int64_t old_ticks; void *pcm_buf; int total_samples; -} WAVVoice; - -#define dolog(...) AUD_log ("wav", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif +} WAVVoiceOut; static struct { const char *wav_path; @@ -46,24 +40,27 @@ static struct { .wav_path = "qemu.wav" }; -static void wav_hw_run (HWVoice *hw) +static int wav_run_out (HWVoiceOut *hw) { - WAVVoice *wav = (WAVVoice *) hw; + WAVVoiceOut *wav = (WAVVoiceOut *) hw; int rpos, live, decr, samples; uint8_t *dst; st_sample_t *src; int64_t now = qemu_get_clock (vm_clock); int64_t ticks = now - wav->old_ticks; - int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; + int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - if (bytes > INT_MAX) - samples = INT_MAX >> hw->shift; - else - samples = bytes >> hw->shift; + if (bytes > INT_MAX) { + samples = INT_MAX >> hw->info.shift; + } + else { + samples = bytes >> hw->info.shift; + } - live = pcm_hw_get_live (hw); - if (live <= 0) - return; + live = audio_pcm_hw_get_live_out (hw); + if (!live) { + return 0; + } wav->old_ticks = now; decr = audio_MIN (live, samples); @@ -73,25 +70,25 @@ static void wav_hw_run (HWVoice *hw) int left_till_end_samples = hw->samples - rpos; int convert_samples = audio_MIN (samples, left_till_end_samples); - src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); - dst = advance (wav->pcm_buf, rpos << hw->shift); + src = hw->mix_buf + rpos; + dst = advance (wav->pcm_buf, rpos << hw->info.shift); hw->clip (dst, src, convert_samples); - qemu_put_buffer (wav->f, dst, convert_samples << hw->shift); - memset (src, 0, convert_samples * sizeof (st_sample_t)); + qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift); + mixeng_clear (src, convert_samples); rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; wav->total_samples += convert_samples; } - pcm_hw_dec_live (hw, decr); hw->rpos = rpos; + return decr; } -static int wav_hw_write (SWVoice *sw, void *buf, int len) +static int wav_write_out (SWVoiceOut *sw, void *buf, int len) { - return pcm_hw_write (sw, buf, len); + return audio_pcm_sw_write (sw, buf, len); } /* VICE code: Store number as little endian. */ @@ -104,10 +101,10 @@ static void le_store (uint8_t *buf, uint32_t val, int len) } } -static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) +static int wav_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) { - WAVVoice *wav = (WAVVoice *) hw; - int bits16 = 0, stereo = audio_state.fixed_channels == 2; + WAVVoiceOut *wav = (WAVVoiceOut *) hw; + int bits16; uint8_t hdr[] = { 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, @@ -115,34 +112,50 @@ static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 }; - switch (audio_state.fixed_fmt) { + freq = audio_state.fixed_freq_out; + fmt = audio_state.fixed_fmt_out; + nchannels = audio_state.fixed_channels_out; + + switch (fmt) { case AUD_FMT_S8: case AUD_FMT_U8: + bits16 = 0; break; case AUD_FMT_S16: case AUD_FMT_U16: bits16 = 1; break; + + default: + dolog ("Internal logic error bad format %d\n", fmt); + return -1; } hdr[34] = bits16 ? 0x10 : 0x08; - hw->freq = 44100; - hw->nchannels = stereo ? 2 : 1; - hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; + audio_pcm_init_info ( + &hw->info, + freq, + nchannels, + bits16 ? AUD_FMT_S16 : AUD_FMT_U8, + audio_need_to_swap_endian (0) + ); hw->bufsize = 4096; wav->pcm_buf = qemu_mallocz (hw->bufsize); - if (!wav->pcm_buf) + if (!wav->pcm_buf) { + dolog ("Can not initialize WAV buffer of %d bytes\n", + hw->bufsize); return -1; + } - le_store (hdr + 22, hw->nchannels, 2); - le_store (hdr + 24, hw->freq, 4); - le_store (hdr + 28, hw->freq << (bits16 + stereo), 4); - le_store (hdr + 32, 1 << (bits16 + stereo), 2); + le_store (hdr + 22, hw->info.nchannels, 2); + le_store (hdr + 24, hw->info.freq, 4); + le_store (hdr + 28, hw->info.freq << (bits16 + (nchannels == 2)), 4); + le_store (hdr + 32, 1 << (bits16 + (nchannels == 2)), 2); wav->f = fopen (conf.wav_path, "wb"); if (!wav->f) { - dolog ("failed to open wave file `%s'\nReason: %s\n", + dolog ("Failed to open wave file `%s'\nReason: %s\n", conf.wav_path, strerror (errno)); qemu_free (wav->pcm_buf); wav->pcm_buf = NULL; @@ -153,17 +166,18 @@ static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) return 0; } -static void wav_hw_fini (HWVoice *hw) +static void wav_fini_out (HWVoiceOut *hw) { - WAVVoice *wav = (WAVVoice *) hw; - int stereo = hw->nchannels == 2; + WAVVoiceOut *wav = (WAVVoiceOut *) hw; + int stereo = hw->info.nchannels == 2; uint8_t rlen[4]; uint8_t dlen[4]; uint32_t rifflen = (wav->total_samples << stereo) + 36; uint32_t datalen = wav->total_samples << stereo; - if (!wav->f || !hw->active) + if (!wav->f || !hw->active) { return; + } le_store (rlen, rifflen, 4); le_store (dlen, datalen, 4); @@ -181,7 +195,7 @@ static void wav_hw_fini (HWVoice *hw) wav->pcm_buf = NULL; } -static int wav_hw_ctl (HWVoice *hw, int cmd, ...) +static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...) { (void) hw; (void) cmd; @@ -195,23 +209,41 @@ static void *wav_audio_init (void) static void wav_audio_fini (void *opaque) { + (void) opaque; ldebug ("wav_fini"); } -struct pcm_ops wav_pcm_ops = { - wav_hw_init, - wav_hw_fini, - wav_hw_run, - wav_hw_write, - wav_hw_ctl +struct audio_option wav_options[] = { + {"PATH", AUD_OPT_STR, &conf.wav_path, + "Path to wave file", NULL, 0}, + {NULL, 0, NULL, NULL, NULL, 0} +}; + +struct audio_pcm_ops wav_pcm_ops = { + wav_init_out, + wav_fini_out, + wav_run_out, + wav_write_out, + wav_ctl_out, + + NULL, + NULL, + NULL, + NULL, + NULL }; -struct audio_output_driver wav_output_driver = { - "wav", - wav_audio_init, - wav_audio_fini, - &wav_pcm_ops, - 1, - 1, - sizeof (WAVVoice) +struct audio_driver wav_audio_driver = { + INIT_FIELD (name = ) "wav", + INIT_FIELD (descr = ) + "WAV renderer http://wikipedia.org/wiki/WAV", + INIT_FIELD (options = ) wav_options, + INIT_FIELD (init = ) wav_audio_init, + INIT_FIELD (fini = ) wav_audio_fini, + INIT_FIELD (pcm_ops = ) &wav_pcm_ops, + INIT_FIELD (can_be_default = ) 0, + INIT_FIELD (max_voices_out = ) 1, + INIT_FIELD (max_voices_in = ) 0, + INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut), + INIT_FIELD (voice_size_in = ) 0 }; diff --git a/configure b/configure index 19a0ec900..98ef82b6e 100755 --- a/configure +++ b/configure @@ -77,6 +77,9 @@ gdbstub="yes" slirp="yes" adlib="no" oss="no" +dsound="no" +coreaudio="no" +alsa="no" fmod="no" fmod_lib="" fmod_inc="" @@ -115,7 +118,7 @@ Darwin) bsd="yes" darwin="yes" ;; -*) +*) oss="yes" linux="yes" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then @@ -131,7 +134,7 @@ if [ "$bsd" = "yes" ] ; then fi # find source path -# XXX: we assume an absolute path is given when launching configure, +# XXX: we assume an absolute path is given when launching configure, # except in './configure' case. source_path=${0%configure} source_path=${source_path%/} @@ -171,6 +174,12 @@ for opt do ;; --disable-sdl) sdl="no" ;; + --enable-coreaudio) coreaudio="yes" + ;; + --enable-alsa) alsa="yes" + ;; + --enable-dsound) dsound="yes" + ;; --enable-fmod) fmod="yes" ;; --fmod-lib=*) fmod_lib=${opt#--fmod-lib=} @@ -178,17 +187,17 @@ for opt do --fmod-inc=*) fmod_inc=${opt#--fmod-inc=} ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" - ;; + ;; --disable-slirp) slirp="no" - ;; + ;; --enable-adlib) adlib="yes" - ;; + ;; --disable-kqemu) kqemu="no" - ;; + ;; --kernel-path=*) kernel_path=${opt#--kernel-path=} - ;; - --enable-cocoa) cocoa="yes" ; sdl="no" - ;; + ;; + --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" + ;; --disable-gfx-check) check_gfx="no" ;; esac @@ -231,8 +240,8 @@ if test -z "$cross_prefix" ; then cat > $TMPC << EOF #include int main(int argc, char ** argv){ - volatile uint32_t i=0x01234567; - return (*((uint8_t*)(&i))) == 0x67; + volatile uint32_t i=0x01234567; + return (*((uint8_t*)(&i))) == 0x67; } EOF @@ -346,7 +355,10 @@ echo " --make=MAKE use specified make [$make]" echo " --static enable static build [$static]" echo " --enable-mingw32 enable Win32 cross compilation with mingw32" echo " --enable-adlib enable Adlib emulation" -echo " --enable-fmod enable FMOD audio output driver" +echo " --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 " --fmod-lib path to FMOD library" echo " --fmod-inc path to FMOD includes" echo "" @@ -375,20 +387,20 @@ fi # kqemu support if test $kqemu = "yes" ; then # test if the source code is installed - if test '!' -f "kqemu/Makefile" ; then + if test '!' -f "kqemu/Makefile" ; then kqemu="no" fi fi - + # Linux specific kqemu configuration if test $kqemu = "yes" -a $linux = "yes" ; then # find the kernel path if test -z "$kernel_path" ; then kernel_version=`uname -r` kernel_path="/lib/modules/$kernel_version/build" -if test '!' -d "$kernel_path/include" ; then +if test '!' -d "$kernel_path/include" ; then kernel_path="/usr/src/linux" - if test '!' -d "$kernel_path/include" ; then + if test '!' -d "$kernel_path/include" ; then echo "Could not find kernel includes in /lib/modules or /usr/src/linux - cannot build the kqemu module" kqemu="no" fi @@ -401,7 +413,7 @@ if test $kqemu = "yes" ; then if test '!' -f "$kernel_path/Makefile" ; then echo "No Makefile file present in $kernel_path - kqemu cannot be built" kqemu="no" -fi +fi # find build system (2.6 or legacy) kbuild26="yes" @@ -439,8 +451,18 @@ if test "$sdl" != "no" ; then fi echo "mingw32 support $mingw32" echo "Adlib support $adlib" +echo "CoreAudio support $coreaudio" +echo "ALSA support $alsa" +echo "DSound support $dsound" echo -n "FMOD support $fmod" -if test $fmod = "yes"; then +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 echo -n " (lib='$fmod_lib' include='$fmod_inc')" fi echo "" @@ -568,6 +590,18 @@ 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 @@ -600,7 +634,7 @@ if [ "$bsd" = "yes" ] ; then echo "#define _BSD 1" >> $config_h fi -for target in $target_list; do +for target in $target_list; do target_dir="$target" config_mak=$target_dir/config.mak @@ -623,7 +657,7 @@ if expr $target : '.*-user' > /dev/null ; then fi if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ - -a "$sdl" = "no" -a "$cocoa" = "no" ; then + -a "$sdl" = "no" -a "$cocoa" = "no" ; then echo "ERROR: QEMU requires SDL or Cocoa for graphical output" echo "To build QEMU with graphical output configure with --disable-gfx-check" echo "Note that this will disable all output from the virtual graphics card." diff --git a/hw/adlib.c b/hw/adlib.c index 939a7ed03..70de4ffab 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -1,8 +1,8 @@ /* - * QEMU Adlib emulation - * - * Copyright (c) 2004 Vassili Karpov (malc) - * + * QEMU Proxy for OPL2/3 emulation by MAME team + * + * Copyright (c) 2004-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -21,8 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include "vl.h" +#define ADLIB_KILL_TIMERS 1 + #define dolog(...) AUD_log ("adlib", __VA_ARGS__) #ifdef DEBUG #define ldebug(...) dolog (__VA_ARGS__) @@ -30,23 +33,15 @@ #define ldebug(...) #endif -#ifdef USE_YMF262 -#define HAS_YMF262 1 +#ifdef HAS_YMF262 #include "ymf262.h" -void YMF262UpdateOneQEMU(int which, INT16 *dst, int length); +void YMF262UpdateOneQEMU (int which, INT16 *dst, int length); #define SHIFT 2 #else #include "fmopl.h" #define SHIFT 1 #endif -#ifdef _WIN32 -#include -#define small_delay() Sleep (1) -#else -#define small_delay() usleep (1) -#endif - #define IO_READ_PROTO(name) \ uint32_t name (void *opaque, uint32_t nport) #define IO_WRITE_PROTO(name) \ @@ -58,35 +53,70 @@ static struct { } conf = {0x220, 44100}; typedef struct { + int ticking[2]; int enabled; int active; - int cparam; - int64_t ticks; int bufpos; +#ifdef DEBUG + int64_t exp[2]; +#endif int16_t *mixbuf; - double interval; - QEMUTimer *ts, *opl_ts; - SWVoice *voice; - int left, pos, samples, bytes_per_second, old_free; - int refcount; -#ifndef USE_YMF262 + uint64_t dexp[2]; + SWVoiceOut *voice; + int left, pos, samples; + QEMUAudioTimeStamp ats; +#ifndef HAS_YMF262 FM_OPL *opl; #endif } AdlibState; static AdlibState adlib; +static void adlib_stop_opl_timer (AdlibState *s, size_t n) +{ +#ifdef HAS_YMF262 + YMF262TimerOver (0, n); +#else + OPLTimerOver (s->opl, n); +#endif + s->ticking[n] = 0; +} + +static void adlib_kill_timers (AdlibState *s) +{ + size_t i; + + for (i = 0; i < 2; ++i) { + if (s->ticking[i]) { + uint64_t delta; + + delta = AUD_time_stamp_get_elapsed_usec_out (s->voice, &s->ats); + ldebug ( + "delta = %f dexp = %f expired => %d\n", + delta / 1000000.0, + s->dexp[i] / 1000000.0, + delta >= s->dexp[i] + ); + if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) { + adlib_stop_opl_timer (s, i); + AUD_init_time_stamp_out (s->voice, &s->ats); + } + } + } +} + static IO_WRITE_PROTO(adlib_write) { AdlibState *s = opaque; int a = nport & 3; int status; - s->ticks = qemu_get_clock (vm_clock); s->active = 1; - AUD_enable (s->voice, 1); + AUD_set_active_out (s->voice, 1); -#ifdef USE_YMF262 + adlib_kill_timers (s); + +#ifdef HAS_YMF262 status = YMF262Write (0, a, val); #else status = OPLWrite (s->opl, a, val); @@ -99,8 +129,9 @@ static IO_READ_PROTO(adlib_read) uint8_t data; int a = nport & 3; -#ifdef USE_YMF262 - (void) s; + adlib_kill_timers (s); + +#ifdef HAS_YMF262 data = YMF262Read (0, a); #else data = OPLRead (s->opl, a); @@ -108,119 +139,115 @@ static IO_READ_PROTO(adlib_read) return data; } -static void OPL_timer (void *opaque) +static void timer_handler (int c, double interval_Sec) { - AdlibState *s = opaque; -#ifdef USE_YMF262 - YMF262TimerOver (s->cparam >> 1, s->cparam & 1); -#else - OPLTimerOver (s->opl, s->cparam); + AdlibState *s = &adlib; + unsigned n = c & 1; +#ifdef DEBUG + double interval; #endif - qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval); -} -static void YMF262TimerHandler (int c, double interval_Sec) -{ - AdlibState *s = &adlib; if (interval_Sec == 0.0) { - qemu_del_timer (s->opl_ts); + s->ticking[n] = 0; return; } - s->cparam = c; - s->interval = ticks_per_sec * interval_Sec; - qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval); - small_delay (); + + s->ticking[n] = 1; +#ifdef DEBUG + interval = ticks_per_sec * interval_Sec; + exp = qemu_get_clock (vm_clock) + interval; + s->exp[n] = exp; +#endif + + s->dexp[n] = interval_Sec * 1000000.0; + AUD_init_time_stamp_out (s->voice, &s->ats); } static int write_audio (AdlibState *s, int samples) { int net = 0; - int ss = samples; + int pos = s->pos; + while (samples) { - int nbytes = samples << SHIFT; - int wbytes = AUD_write (s->voice, - s->mixbuf + (s->pos << (SHIFT - 1)), - nbytes); - int wsampl = wbytes >> SHIFT; - samples -= wsampl; - s->pos = (s->pos + wsampl) % s->samples; - net += wsampl; - if (!wbytes) + int nbytes, wbytes, wsampl; + + nbytes = samples << SHIFT; + wbytes = AUD_write ( + s->voice, + s->mixbuf + (pos << (SHIFT - 1)), + nbytes + ); + + if (wbytes) { + wsampl = wbytes >> SHIFT; + + samples -= wsampl; + pos = (pos + wsampl) % s->samples; + + net += wsampl; + } + else { break; + } } - if (net > ss) { - dolog ("WARNING: net > ss\n"); - } + return net; } -static void timer (void *opaque) +static void adlib_callback (void *opaque, int free) { AdlibState *s = opaque; - int elapsed, samples, net = 0; - - if (s->refcount) - dolog ("refcount=%d\n", s->refcount); + int samples, net = 0, to_play, written; - s->refcount += 1; - if (!(s->active && s->enabled)) - goto reset; - - AUD_run (); - - while (s->left) { - int written = write_audio (s, s->left); - net += written; - if (!written) - goto reset2; - s->left -= written; + samples = free >> SHIFT; + if (!(s->active && s->enabled) || !samples) { + return; } - s->pos = 0; - - elapsed = AUD_calc_elapsed (s->voice); - if (!elapsed) - goto reset2; - /* elapsed = AUD_get_free (s->voice); */ - samples = elapsed >> SHIFT; - if (!samples) - goto reset2; + to_play = audio_MIN (s->left, samples); + while (to_play) { + written = write_audio (s, to_play); + + if (written) { + s->left -= written; + samples -= written; + to_play -= written; + s->pos = (s->pos + written) % s->samples; + } + else { + return; + } + } samples = audio_MIN (samples, s->samples - s->pos); - if (s->left) - dolog ("left=%d samples=%d elapsed=%d free=%d\n", - s->left, samples, elapsed, AUD_get_free (s->voice)); - - if (!samples) - goto reset2; + if (!samples) { + return; + } -#ifdef USE_YMF262 +#ifdef HAS_YMF262 YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples); #else YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples); #endif while (samples) { - int written = write_audio (s, samples); - net += written; - if (!written) - break; - samples -= written; + written = write_audio (s, samples); + + if (written) { + net += written; + samples -= written; + s->pos = (s->pos + written) % s->samples; + } + else { + s->left = samples; + return; + } } - if (!samples) - s->pos = 0; - s->left = samples; - -reset2: - AUD_adjust (s->voice, net << SHIFT); -reset: - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + ticks_per_sec / 1024); - s->refcount -= 1; } static void Adlib_fini (AdlibState *s) { -#ifdef USE_YMF262 +#ifdef HAS_YMF262 YMF262Shutdown (); #else if (s->opl) { @@ -229,15 +256,9 @@ static void Adlib_fini (AdlibState *s) } #endif - if (s->opl_ts) - qemu_free_timer (s->opl_ts); - - if (s->ts) - qemu_free_timer (s->ts); - -#define maybe_free(p) if (p) qemu_free (p) - maybe_free (s->mixbuf); -#undef maybe_free + if (s->mixbuf) { + qemu_free (s->mixbuf); + } s->active = 0; s->enabled = 0; @@ -247,15 +268,13 @@ void Adlib_init (void) { AdlibState *s = &adlib; - memset (s, 0, sizeof (*s)); - -#ifdef USE_YMF262 +#ifdef HAS_YMF262 if (YMF262Init (1, 14318180, conf.freq)) { dolog ("YMF262Init %d failed\n", conf.freq); return; } else { - YMF262SetTimerHandler (0, YMF262TimerHandler, 0); + YMF262SetTimerHandler (0, timer_handler, 0); s->enabled = 1; } #else @@ -265,33 +284,26 @@ void Adlib_init (void) return; } else { - OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0); + OPLSetTimerHandler (s->opl, timer_handler, 0); s->enabled = 1; } #endif - s->opl_ts = qemu_new_timer (vm_clock, OPL_timer, s); - if (!s->opl_ts) { - dolog ("Can not get timer for adlib emulation\n"); - Adlib_fini (s); - return; - } - - s->ts = qemu_new_timer (vm_clock, timer, s); - if (!s->opl_ts) { - dolog ("Can not get timer for adlib emulation\n"); - Adlib_fini (s); - return; - } - - s->voice = AUD_open (s->voice, "adlib", conf.freq, SHIFT, AUD_FMT_S16); + s->voice = AUD_open_out ( + s->voice, + "adlib", + s, + adlib_callback, + conf.freq, + SHIFT, + AUD_FMT_S16 + ); if (!s->voice) { Adlib_fini (s); return; } - s->bytes_per_second = conf.freq << SHIFT; - s->samples = AUD_get_buffer_size (s->voice) >> SHIFT; + s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT; s->mixbuf = qemu_mallocz (s->samples << SHIFT); if (!s->mixbuf) { @@ -300,6 +312,7 @@ void Adlib_init (void) Adlib_fini (s); return; } + register_ioport_read (0x388, 4, 1, adlib_read, s); register_ioport_write (0x388, 4, 1, adlib_write, s); @@ -308,6 +321,4 @@ void Adlib_init (void) register_ioport_read (conf.port + 8, 2, 1, adlib_read, s); register_ioport_write (conf.port + 8, 2, 1, adlib_write, s); - - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); } diff --git a/hw/es1370.c b/hw/es1370.c new file mode 100644 index 000000000..0191f5fdf --- /dev/null +++ b/hw/es1370.c @@ -0,0 +1,1007 @@ +/* + * QEMU ES1370 emulation + * + * Copyright (c) 2005 Vassili Karpov (malc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* #define DEBUG_ES1370 */ +/* #define VERBOSE_ES1370 */ +#define SILENT_ES1370 + +#include "vl.h" + +/* Missing stuff: + SCTRL_P[12](END|ST)INC + SCTRL_P1SCTRLD + SCTRL_P2DACSEN + CTRL_DAC_SYNC + MIDI + non looped mode + surely more +*/ + +/* + Following macros and samplerate array were copied verbatim from + Linux kernel 2.4.30: drivers/sound/es1370.c + + Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch) +*/ + +/* Start blatant GPL violation */ + +#define ES1370_REG_CONTROL 0x00 +#define ES1370_REG_STATUS 0x04 +#define ES1370_REG_UART_DATA 0x08 +#define ES1370_REG_UART_STATUS 0x09 +#define ES1370_REG_UART_CONTROL 0x09 +#define ES1370_REG_UART_TEST 0x0a +#define ES1370_REG_MEMPAGE 0x0c +#define ES1370_REG_CODEC 0x10 +#define ES1370_REG_SERIAL_CONTROL 0x20 +#define ES1370_REG_DAC1_SCOUNT 0x24 +#define ES1370_REG_DAC2_SCOUNT 0x28 +#define ES1370_REG_ADC_SCOUNT 0x2c + +#define ES1370_REG_DAC1_FRAMEADR 0xc30 +#define ES1370_REG_DAC1_FRAMECNT 0xc34 +#define ES1370_REG_DAC2_FRAMEADR 0xc38 +#define ES1370_REG_DAC2_FRAMECNT 0xc3c +#define ES1370_REG_ADC_FRAMEADR 0xd30 +#define ES1370_REG_ADC_FRAMECNT 0xd34 +#define ES1370_REG_PHANTOM_FRAMEADR 0xd38 +#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c + +static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 }; + +#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2) +#define DAC2_DIVTOSR(x) (1411200/((x)+2)) + +#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */ +#define CTRL_XCTL1 0x40000000 /* electret mic bias */ +#define CTRL_OPEN 0x20000000 /* no function, can be read and written */ +#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */ +#define CTRL_SH_PCLKDIV 16 +#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */ +#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */ +#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */ +#define CTRL_SH_WTSRSEL 12 +#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */ +#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */ +#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */ +#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */ +#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */ +#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */ +#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */ +#define CTRL_ADC_EN 0x00000010 /* enable ADC */ +#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */ +#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */ +#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */ +#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */ + +#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */ +#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */ +#define STAT_CBUSY 0x00000200 /* 1 = codec busy */ +#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */ +#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */ +#define STAT_SH_VC 5 +#define STAT_MCCB 0x00000010 /* CCB int pending */ +#define STAT_UART 0x00000008 /* UART int pending */ +#define STAT_DAC1 0x00000004 /* DAC1 int pending */ +#define STAT_DAC2 0x00000002 /* DAC2 int pending */ +#define STAT_ADC 0x00000001 /* ADC int pending */ + +#define USTAT_RXINT 0x80 /* UART rx int pending */ +#define USTAT_TXINT 0x04 /* UART tx int pending */ +#define USTAT_TXRDY 0x02 /* UART tx ready */ +#define USTAT_RXRDY 0x01 /* UART rx ready */ + +#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */ +#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */ +#define UCTRL_ENA_TXINT 0x20 /* enable TX int */ +#define UCTRL_CNTRL 0x03 /* control field */ +#define UCTRL_CNTRL_SWR 0x03 /* software reset command */ + +#define SCTRL_P2ENDINC 0x00380000 /* */ +#define SCTRL_SH_P2ENDINC 19 +#define SCTRL_P2STINC 0x00070000 /* */ +#define SCTRL_SH_P2STINC 16 +#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */ +#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */ +#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */ +#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */ +#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */ +#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */ +#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */ +#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */ +#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */ +#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */ +#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */ +#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */ +#define SCTRL_R1FMT 0x00000030 /* format mask */ +#define SCTRL_SH_R1FMT 4 +#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */ +#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */ +#define SCTRL_P2FMT 0x0000000c /* format mask */ +#define SCTRL_SH_P2FMT 2 +#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */ +#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */ +#define SCTRL_P1FMT 0x00000003 /* format mask */ +#define SCTRL_SH_P1FMT 0 + +/* End blatant GPL violation */ + +#define NB_CHANNELS 3 +#define DAC1_CHANNEL 0 +#define DAC2_CHANNEL 1 +#define ADC_CHANNEL 2 + +#define IO_READ_PROTO(n) \ +static uint32_t n (void *opaque, uint32_t addr) +#define IO_WRITE_PROTO(n) \ +static void n (void *opaque, uint32_t addr, uint32_t val) + +static void es1370_dac1_callback (void *opaque, int free); +static void es1370_dac2_callback (void *opaque, int free); +static void es1370_adc_callback (void *opaque, int avail); + +#ifdef DEBUG_ES1370 + +#define ldebug(...) AUD_log ("es1370", __VA_ARGS__) + +static void print_ctl (uint32_t val) +{ + char buf[1024]; + + buf[0] = '\0'; +#define a(n) if (val & CTRL_##n) strcat (buf, " "#n) + a (ADC_STOP); + a (XCTL1); + a (OPEN); + a (MSFMTSEL); + a (M_SBB); + a (DAC_SYNC); + a (CCB_INTRM); + a (M_CB); + a (XCTL0); + a (BREQ); + a (DAC1_EN); + a (DAC2_EN); + a (ADC_EN); + a (UART_EN); + a (JYSTK_EN); + a (CDC_EN); + a (SERR_DIS); +#undef a + AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n", + (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV, + DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), + dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], + buf); +} + +static void print_sctl (uint32_t val) +{ + static const char *fmt_names[] = {"8M", "8S", "16M", "16S"}; + char buf[1024]; + + buf[0] = '\0'; + +#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n) +#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n) + b (R1LOOPSEL); + b (P2LOOPSEL); + b (P1LOOPSEL); + a (P2PAUSE); + a (P1PAUSE); + a (R1INTEN); + a (P2INTEN); + a (P1INTEN); + a (P1SCTRLD); + a (P2DACSEN); + if (buf[0]) { + strcat (buf, "\n "); + } + else { + buf[0] = ' '; + buf[1] = '\0'; + } +#undef b +#undef a + AUD_log ("es1370", + "%s" + "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n", + buf, + (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC, + (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC, + fmt_names [(val >> SCTRL_SH_R1FMT) & 3], + fmt_names [(val >> SCTRL_SH_P2FMT) & 3], + fmt_names [(val >> SCTRL_SH_P1FMT) & 3] + ); +} +#else +#define ldebug(...) +#define print_ctl(...) +#define print_sctl(...) +#endif + +#ifdef VERBOSE_ES1370 +#define dolog(...) AUD_log ("es1370", __VA_ARGS__) +#else +#define dolog(...) +#endif + +#ifndef SILENT_ES1370 +#define lwarn(...) AUD_log ("es1370: warning:", __VA_ARGS__) +#else +#define lwarn(...) +#endif + +struct chan { + uint32_t shift; + uint32_t leftover; + uint32_t scount; + uint32_t frame_addr; + uint32_t frame_cnt; +}; + +typedef struct ES1370State { + PCIDevice *pci_dev; + + struct chan chan[NB_CHANNELS]; + SWVoiceOut *dac_voice[2]; + SWVoiceIn *adc_voice; + + uint32_t ctl; + uint32_t status; + uint32_t mempage; + uint32_t codec; + uint32_t sctl; +} ES1370State; + +typedef struct PCIES1370State { + PCIDevice dev; + ES1370State es1370; +} PCIES1370State; + +struct chan_bits { + uint32_t ctl_en; + uint32_t stat_int; + uint32_t sctl_pause; + uint32_t sctl_inten; + uint32_t sctl_fmt; + uint32_t sctl_sh_fmt; + uint32_t sctl_loopsel; + void (*calc_freq) (ES1370State *s, uint32_t ctl, + uint32_t *old_freq, uint32_t *new_freq); +}; + +static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl, + uint32_t *old_freq, uint32_t *new_freq); +static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl, + uint32_t *old_freq, + uint32_t *new_freq); + +static const struct chan_bits es1370_chan_bits[] = { + {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN, + SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL, + es1370_dac1_calc_freq}, + + {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN, + SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL, + es1370_dac2_and_adc_calc_freq}, + + {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN, + SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL, + es1370_dac2_and_adc_calc_freq} +}; + +static void es1370_update_status (ES1370State *s, uint32_t new_status) +{ + uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC); + + if (level) { + s->status = new_status | STAT_INTR; + } + else { + s->status = new_status & ~STAT_INTR; + } + pci_set_irq (s->pci_dev, 0, !!level); +} + +static void es1370_reset (ES1370State *s) +{ + size_t i; + + s->ctl = 1; + s->status = 0x60; + s->mempage = 0; + s->codec = 0; + s->sctl = 0; + + for (i = 0; i < NB_CHANNELS; ++i) { + struct chan *d = &s->chan[i]; + d->scount = 0; + d->leftover = 0; + if (i == ADC_CHANNEL) { + AUD_close_in (s->adc_voice); + s->adc_voice = NULL; + } + else { + AUD_close_out (s->dac_voice[i]); + s->dac_voice[i] = NULL; + } + } + pci_set_irq (s->pci_dev, 0, 0); +} + +static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl) +{ + uint32_t new_status = s->status; + + if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) { + new_status &= ~STAT_DAC1; + } + + if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) { + new_status &= ~STAT_DAC2; + } + + if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) { + new_status &= ~STAT_ADC; + } + + if (new_status != s->status) { + es1370_update_status (s, new_status); + } +} + +static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl, + uint32_t *old_freq, uint32_t *new_freq) + +{ + *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; + *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; +} + +static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl, + uint32_t *old_freq, + uint32_t *new_freq) + +{ + uint32_t old_pclkdiv, new_pclkdiv; + + new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV; + old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV; + *new_freq = DAC2_DIVTOSR (new_pclkdiv); + *old_freq = DAC2_DIVTOSR (old_pclkdiv); +} + +static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) +{ + size_t i; + uint32_t old_freq, new_freq, old_fmt, new_fmt; + + for (i = 0; i < NB_CHANNELS; ++i) { + struct chan *d = &s->chan[i]; + const struct chan_bits *b = &es1370_chan_bits[i]; + + new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt; + old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt; + + b->calc_freq (s, ctl, &old_freq, &new_freq); + + if ((old_fmt != new_fmt) || (old_freq != new_freq)) { + d->shift = (new_fmt & 1) + (new_fmt >> 1); + ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n", + i, + new_freq, + 1 << (new_fmt & 1), + (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8, + d->shift); + if (new_freq) { + if (i == ADC_CHANNEL) { + s->adc_voice = + AUD_open_in ( + s->adc_voice, + "es1370.adc", + s, + es1370_adc_callback, + new_freq, + 1 << (new_fmt & 1), + (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8 + ); + } + else { + s->dac_voice[i] = + AUD_open_out ( + s->dac_voice[i], + i ? "es1370.dac2" : "es1370.dac1", + s, + i ? es1370_dac2_callback : es1370_dac1_callback, + new_freq, + 1 << (new_fmt & 1), + (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8 + ); + } + } + } + + if (((ctl ^ s->ctl) & b->ctl_en) + || ((sctl ^ s->sctl) & b->sctl_pause)) { + int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause); + + if (i == ADC_CHANNEL) { + AUD_set_active_in (s->adc_voice, on); + } + else { + AUD_set_active_out (s->dac_voice[i], on); + } + } + } + + s->ctl = ctl; + s->sctl = sctl; +} + +static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr) +{ + addr &= 0xff; + if (addr >= 0x30 && addr <= 0x3f) + addr |= s->mempage << 8; + return addr; +} + +IO_WRITE_PROTO (es1370_writeb) +{ + ES1370State *s = opaque; + addr = es1370_fixup (s, addr); + uint32_t shift, mask; + + switch (addr) { + case ES1370_REG_CONTROL: + case ES1370_REG_CONTROL + 1: + case ES1370_REG_CONTROL + 2: + case ES1370_REG_CONTROL + 3: + shift = (addr - ES1370_REG_CONTROL) << 3; + mask = 0xff << shift; + val = (s->ctl & ~mask) | ((val & 0xff) << shift); + es1370_update_voices (s, val, s->sctl); + print_ctl (val); + break; + case ES1370_REG_MEMPAGE: + s->mempage = val; + break; + case ES1370_REG_SERIAL_CONTROL: + case ES1370_REG_SERIAL_CONTROL + 1: + case ES1370_REG_SERIAL_CONTROL + 2: + case ES1370_REG_SERIAL_CONTROL + 3: + shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3; + mask = 0xff << shift; + val = (s->sctl & ~mask) | ((val & 0xff) << shift); + es1370_maybe_lower_irq (s, val); + es1370_update_voices (s, s->ctl, val); + print_sctl (val); + break; + default: + lwarn ("writeb %#x <- %#x\n", addr, val); + break; + } +} + +IO_WRITE_PROTO (es1370_writew) +{ + ES1370State *s = opaque; + addr = es1370_fixup (s, addr); + uint32_t shift, mask; + struct chan *d = &s->chan[0]; + + switch (addr) { + case ES1370_REG_CODEC: + dolog ("ignored codec write address %#x, data %#x\n", + (val >> 8) & 0xff, val & 0xff); + s->codec = val; + break; + + case ES1370_REG_CONTROL: + case ES1370_REG_CONTROL + 2: + shift = (addr != ES1370_REG_CONTROL) << 4; + mask = 0xffff << shift; + val = (s->ctl & ~mask) | ((val & 0xffff) << shift); + es1370_update_voices (s, val, s->sctl); + print_ctl (val); + break; + + case ES1370_REG_ADC_SCOUNT: + d++; + case ES1370_REG_DAC2_SCOUNT: + d++; + case ES1370_REG_DAC1_SCOUNT: + d->scount = (d->scount & ~0xffff) | (val & 0xffff); + break; + + default: + lwarn ("writew %#x <- %#x\n", addr, val); + break; + } +} + +IO_WRITE_PROTO (es1370_writel) +{ + ES1370State *s = opaque; + struct chan *d = &s->chan[0]; + + addr = es1370_fixup (s, addr); + + switch (addr) { + case ES1370_REG_CONTROL: + es1370_update_voices (s, val, s->sctl); + print_ctl (val); + break; + + case ES1370_REG_MEMPAGE: + s->mempage = val & 0xf; + break; + + case ES1370_REG_SERIAL_CONTROL: + es1370_maybe_lower_irq (s, val); + es1370_update_voices (s, s->ctl, val); + print_sctl (val); + break; + + case ES1370_REG_ADC_SCOUNT: + d++; + case ES1370_REG_DAC2_SCOUNT: + d++; + case ES1370_REG_DAC1_SCOUNT: + d->scount = (val & 0xffff) | (d->scount & ~0xffff); + ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n", + d - &s->chan[0], val >> 16, (val & 0xffff)); + break; + + case ES1370_REG_ADC_FRAMEADR: + d++; + case ES1370_REG_DAC2_FRAMEADR: + d++; + case ES1370_REG_DAC1_FRAMEADR: + d->frame_addr = val; + ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val); + break; + + case ES1370_REG_ADC_FRAMECNT: + d++; + case ES1370_REG_DAC2_FRAMECNT: + d++; + case ES1370_REG_DAC1_FRAMECNT: + d->frame_cnt = val; + d->leftover = 0; + ldebug ("chan %d frame count %d, buffer size %d\n", + d - &s->chan[0], val >> 16, val & 0xffff); + break; + + default: + lwarn ("writel %#x <- %#x\n", addr, val); + break; + } +} + +IO_READ_PROTO (es1370_readb) +{ + ES1370State *s = opaque; + uint32_t val; + + addr = es1370_fixup (s, addr); + + switch (addr) { + case 0x1b: /* Legacy */ + lwarn ("Attempt to read from legacy register\n"); + val = 5; + break; + case ES1370_REG_MEMPAGE: + val = s->mempage; + break; + case ES1370_REG_CONTROL + 0: + case ES1370_REG_CONTROL + 1: + case ES1370_REG_CONTROL + 2: + case ES1370_REG_CONTROL + 3: + val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3); + break; + case ES1370_REG_STATUS + 0: + case ES1370_REG_STATUS + 1: + case ES1370_REG_STATUS + 2: + case ES1370_REG_STATUS + 3: + val = s->status >> ((addr - ES1370_REG_STATUS) << 3); + break; + default: + val = ~0; + lwarn ("readb %#x -> %#x\n", addr, val); + break; + } + return val; +} + +IO_READ_PROTO (es1370_readw) +{ + ES1370State *s = opaque; + struct chan *d = &s->chan[0]; + uint32_t val; + + addr = es1370_fixup (s, addr); + + switch (addr) { + case ES1370_REG_ADC_SCOUNT + 2: + d++; + case ES1370_REG_DAC2_SCOUNT + 2: + d++; + case ES1370_REG_DAC1_SCOUNT + 2: + val = d->scount >> 16; + break; + + default: + val = ~0; + lwarn ("readw %#x -> %#x\n", addr, val); + break; + } + + return val; +} + +IO_READ_PROTO (es1370_readl) +{ + ES1370State *s = opaque; + uint32_t val; + struct chan *d = &s->chan[0]; + + addr = es1370_fixup (s, addr); + + switch (addr) { + case ES1370_REG_CONTROL: + val = s->ctl; + break; + case ES1370_REG_STATUS: + val = s->status; + break; + case ES1370_REG_MEMPAGE: + val = s->mempage; + break; + case ES1370_REG_CODEC: + val = s->codec; + break; + case ES1370_REG_SERIAL_CONTROL: + val = s->sctl; + break; + + case ES1370_REG_ADC_SCOUNT: + d++; + case ES1370_REG_DAC2_SCOUNT: + d++; + case ES1370_REG_DAC1_SCOUNT: + val = d->scount; +#ifdef DEBUG_ES1370 + { + uint32_t curr_count = d->scount >> 16; + uint32_t count = d->scount & 0xffff; + + curr_count <<= d->shift; + count <<= d->shift; + dolog ("read scount curr %d, total %d\n", curr_count, count); + } +#endif + break; + + case ES1370_REG_ADC_FRAMECNT: + d++; + case ES1370_REG_DAC2_FRAMECNT: + d++; + case ES1370_REG_DAC1_FRAMECNT: + val = d->frame_cnt; +#ifdef DEBUG_ES1370 + { + uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2; + uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2; + if (curr > size) + dolog ("read framecnt curr %d, size %d %d\n", curr, size, + curr > size); + } +#endif + break; + + case ES1370_REG_ADC_FRAMEADR: + d++; + case ES1370_REG_DAC2_FRAMEADR: + d++; + case ES1370_REG_DAC1_FRAMEADR: + val = d->frame_addr; + break; + + default: + val = ~0U; + lwarn ("readl %#x -> %#x\n", addr, val); + break; + } + return val; +} + + +static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, + int max, int *irq) +{ + uint8_t tmpbuf[4096]; + uint32_t addr = d->frame_addr; + int sc = d->scount & 0xffff; + int csc = d->scount >> 16; + int csc_bytes = (csc + 1) << d->shift; + int cnt = d->frame_cnt >> 16; + int size = d->frame_cnt & 0xffff; + int left = ((size - cnt + 1) << 2) + d->leftover; + int transfered = 0; + int temp = audio_MIN (max, audio_MIN (left, csc_bytes)); + int index = d - &s->chan[0]; + + addr += (cnt << 2) + d->leftover; + + if (index == ADC_CHANNEL) { + while (temp) { + int acquired, to_copy; + + to_copy = audio_MIN (temp, sizeof (tmpbuf)); + acquired = AUD_read (s->adc_voice, tmpbuf, to_copy); + if (!acquired) + break; + + cpu_physical_memory_write (addr, tmpbuf, acquired); + + temp -= acquired; + addr += acquired; + transfered += acquired; + } + } + else { + SWVoiceOut *voice = s->dac_voice[index]; + + while (temp) { + int copied, to_copy; + + to_copy = audio_MIN (temp, sizeof (tmpbuf)); + cpu_physical_memory_read (addr, tmpbuf, to_copy); + copied = AUD_write (voice, tmpbuf, to_copy); + if (!copied) + break; + temp -= copied; + addr += copied; + transfered += copied; + } + } + + if (csc_bytes == transfered) { + *irq = 1; + d->scount = sc | (sc << 16); + ldebug ("sc = %d, rate = %f\n", + (sc + 1) << d->shift, + (sc + 1) / (double) 44100); + } + else { + *irq = 0; + d->scount = sc | (((csc_bytes - transfered - 1) >> d->shift) << 16); + } + + cnt += (transfered + d->leftover) >> 2; + + if (s->sctl & loop_sel) { + /* Bah, how stupid is that having a 0 represent true value? + i just spent few hours on this shit */ + lwarn ("whoops non looping mode\n"); + } + else { + d->frame_cnt = size; + + if (cnt <= d->frame_cnt) + d->frame_cnt |= cnt << 16; + } + + d->leftover = (transfered + d->leftover) & 3; +} + +static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail) +{ + uint32_t new_status = s->status; + int max_bytes, irq; + struct chan *d = &s->chan[chan]; + const struct chan_bits *b = &es1370_chan_bits[chan]; + + if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) { + return; + } + + max_bytes = free_or_avail; + max_bytes &= ~((1 << d->shift) - 1); + if (!max_bytes) { + return; + } + + es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq); + + if (irq) { + if (s->sctl & b->sctl_inten) { + new_status |= b->stat_int; + } + } + + if (new_status != s->status) { + es1370_update_status (s, new_status); + } +} + +static void es1370_dac1_callback (void *opaque, int free) +{ + ES1370State *s = opaque; + + es1370_run_channel (s, DAC1_CHANNEL, free); +} + +static void es1370_dac2_callback (void *opaque, int free) +{ + ES1370State *s = opaque; + + es1370_run_channel (s, DAC2_CHANNEL, free); +} + +static void es1370_adc_callback (void *opaque, int avail) +{ + ES1370State *s = opaque; + + es1370_run_channel (s, ADC_CHANNEL, avail); +} + +static void es1370_map (PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIES1370State *d = (PCIES1370State *) pci_dev; + ES1370State *s = &d->es1370; + + register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s); + register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s); + register_ioport_write (addr, 0x40, 4, es1370_writel, s); + + register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s); + register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s); + register_ioport_read (addr, 0x40, 4, es1370_readl, s); +} + +static void es1370_save (QEMUFile *f, void *opaque) +{ + ES1370State *s = opaque; + size_t i; + + for (i = 0; i < NB_CHANNELS; ++i) { + struct chan *d = &s->chan[i]; + qemu_put_be32s (f, &d->shift); + qemu_put_be32s (f, &d->leftover); + qemu_put_be32s (f, &d->scount); + qemu_put_be32s (f, &d->frame_addr); + qemu_put_be32s (f, &d->frame_cnt); + } + qemu_put_be32s (f, &s->ctl); + qemu_put_be32s (f, &s->status); + qemu_put_be32s (f, &s->mempage); + qemu_put_be32s (f, &s->codec); + qemu_put_be32s (f, &s->sctl); +} + +static int es1370_load (QEMUFile *f, void *opaque, int version_id) +{ + uint32_t ctl, sctl; + ES1370State *s = opaque; + size_t i; + + if (version_id != 1) + return -EINVAL; + + for (i = 0; i < NB_CHANNELS; ++i) { + struct chan *d = &s->chan[i]; + qemu_get_be32s (f, &d->shift); + qemu_get_be32s (f, &d->leftover); + qemu_get_be32s (f, &d->scount); + qemu_get_be32s (f, &d->frame_addr); + qemu_get_be32s (f, &d->frame_cnt); + if (i == ADC_CHANNEL) { + if (s->adc_voice) { + AUD_close_in (s->adc_voice); + s->adc_voice = NULL; + } + } + else { + if (s->dac_voice[i]) { + AUD_close_out (s->dac_voice[i]); + s->dac_voice[i] = NULL; + } + } + } + + qemu_get_be32s (f, &ctl); + qemu_get_be32s (f, &s->status); + qemu_get_be32s (f, &s->mempage); + qemu_get_be32s (f, &s->codec); + qemu_get_be32s (f, &sctl); + + s->ctl = 0; + s->sctl = 0; + es1370_update_voices (s, ctl, sctl); + return 0; +} + +static void es1370_on_reset (void *opaque) +{ + ES1370State *s = opaque; + es1370_reset (s); +} + +int es1370_init (PCIBus *bus) +{ + PCIES1370State *d; + ES1370State *s; + uint8_t *c; + + d = (PCIES1370State *) pci_register_device (bus, "ES1370", + sizeof (PCIES1370State), + -1, NULL, NULL); + + if (!d) { + fprintf (stderr, "Failed to register PCI device for ES1370\n"); + return -1; + } + + c = d->dev.config; + c[0x00] = 0x74; + c[0x01] = 0x12; + c[0x02] = 0x00; + c[0x03] = 0x50; + c[0x07] = 2 << 1; + c[0x0a] = 0x01; + c[0x0b] = 0x04; + +#if 1 + c[0x2c] = 0x42; + c[0x2d] = 0x49; + c[0x2e] = 0x4c; + c[0x2f] = 0x4c; +#else + c[0x2c] = 0x74; + c[0x2d] = 0x12; + c[0x2e] = 0x71; + c[0x2f] = 0x13; + c[0x34] = 0xdc; + c[0x3c] = 10; + c[0xdc] = 0x00; +#endif + + c[0x3d] = 1; + c[0x3e] = 0x0c; + c[0x3f] = 0x80; + + s = &d->es1370; + s->pci_dev = &d->dev; + + pci_register_io_region (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map); + register_savevm ("es1370", 0, 1, es1370_save, es1370_load, s); + qemu_register_reset (es1370_on_reset, s); + es1370_reset (s); + return 0; +} diff --git a/hw/pc.c b/hw/pc.c index f0ae1b964..ad3d5e032 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -602,18 +602,18 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (audio_enabled) { AUD_init(); -#ifdef USE_SB16 if (sb16_enabled) SB16_init (); -#endif #ifdef CONFIG_ADLIB if (adlib_enabled) Adlib_init (); #endif -#ifdef USE_GUS +#ifdef CONFIG_GUS if (gus_enabled) GUS_init (); #endif + if (pci_enabled && es1370_enabled) + es1370_init (pci_bus); } floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); diff --git a/hw/sb16.c b/hw/sb16.c index bca5795ea..e79d19278 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -1,8 +1,8 @@ /* * QEMU Soundblaster 16 emulation - * - * Copyright (c) 2003-2004 Vassili Karpov (malc) - * + * + * Copyright (c) 2003-2005 Vassili Karpov (malc) + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -99,9 +99,10 @@ typedef struct SB16State { int dma_running; int bytes_per_second; int align; - SWVoice *voice; + int audio_free; + SWVoiceOut *voice; - QEMUTimer *ts, *aux_ts; + QEMUTimer *aux_ts; /* mixer state */ int mixer_nreg; uint8_t mixer_regs[256]; @@ -110,6 +111,8 @@ typedef struct SB16State { /* XXX: suppress that and use a context */ static struct SB16State dsp; +static void SB_audio_callback (void *opaque, int free); + static int magic_of_irq (int irq) { switch (irq) { @@ -174,11 +177,11 @@ static void control (SB16State *s, int hold) if (hold) { DMA_hold_DREQ (dma); - AUD_enable (s->voice, 1); + AUD_set_active_out (s->voice, 1); } else { DMA_release_DREQ (dma); - AUD_enable (s->voice, 0); + AUD_set_active_out (s->voice, 0); } } @@ -207,8 +210,9 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->freq = (1000000 + (tmp / 2)) / tmp; } - if (dma_len != -1) + if (dma_len != -1) { s->block_size = dma_len << s->fmt_stereo; + } else { /* This is apparently the only way to make both Act1/PL and SecondReality/FC work @@ -227,17 +231,28 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->dma_auto = (mask & DMA8_AUTO) != 0; s->align = (1 << s->fmt_stereo) - 1; - if (s->block_size & s->align) - dolog ("warning: unaligned buffer\n"); + if (s->block_size & s->align) { + dolog ("warning: misaligned block size %d, alignment %d\n", + s->block_size, s->align + 1); + } ldebug ("freq %d, stereo %d, sign %d, bits %d, " "dma %d, auto %d, fifo %d, high %d\n", s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, s->block_size, s->dma_auto, s->fifo, s->highspeed); - if (s->freq) - s->voice = AUD_open (s->voice, "sb16", s->freq, - 1 << s->fmt_stereo, s->fmt); + if (s->freq) { + s->audio_free = 0; + s->voice = AUD_open_out ( + s->voice, + "sb16", + s, + SB_audio_callback, + s->freq, + 1 << s->fmt_stereo, + s->fmt + ); + } control (s, 1); speaker (s, 1); @@ -309,12 +324,23 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16); s->highspeed = 0; s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1; - if (s->block_size & s->align) - dolog ("warning: unaligned buffer\n"); + if (s->block_size & s->align) { + dolog ("warning: misaligned block size %d, alignment %d\n", + s->block_size, s->align + 1); + } - if (s->freq) - s->voice = AUD_open (s->voice, "sb16", s->freq, - 1 << s->fmt_stereo, s->fmt); + if (s->freq) { + s->audio_free = 0; + s->voice = AUD_open_out ( + s->voice, + "sb16", + s, + SB_audio_callback, + s->freq, + 1 << s->fmt_stereo, + s->fmt + ); + } control (s, 1); speaker (s, 1); @@ -323,14 +349,16 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) static inline void dsp_out_data (SB16State *s, uint8_t val) { ldebug ("outdata %#x\n", val); - if (s->out_data_len < sizeof (s->out_data)) + if (s->out_data_len < sizeof (s->out_data)) { s->out_data[s->out_data_len++] = val; + } } static inline uint8_t dsp_get_data (SB16State *s) { - if (s->in_index) + if (s->in_index) { return s->in2_data[--s->in_index]; + } else { dolog ("buffer underflow\n"); return 0; @@ -356,6 +384,8 @@ static void command (SB16State *s, uint8_t cmd) s->needed_bytes = 3; } else { + s->needed_bytes = 0; + switch (cmd) { case 0x03: dsp_out_data (s, 0x10); /* s->csp_param); */ @@ -403,7 +433,7 @@ static void command (SB16State *s, uint8_t cmd) goto warn; case 0x35: - dolog ("MIDI command(0x35) not implemented\n"); + dolog ("0x35 - MIDI command not implemented\n"); break; case 0x40: @@ -435,6 +465,38 @@ static void command (SB16State *s, uint8_t cmd) s->needed_bytes = 2; break; + case 0x74: + s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */ + dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"); + break; + + case 0x75: /* DMA DAC, 4-bit ADPCM Reference */ + s->needed_bytes = 2; + dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"); + break; + + case 0x76: /* DMA DAC, 2.6-bit ADPCM */ + s->needed_bytes = 2; + dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"); + break; + + case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */ + s->needed_bytes = 2; + dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"); + break; + + case 0x7d: + dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"); + dolog ("not implemented\n"); + break; + + case 0x7f: + dolog ( + "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n" + ); + dolog ("not implemented\n"); + break; + case 0x80: s->needed_bytes = 2; break; @@ -476,9 +538,9 @@ static void command (SB16State *s, uint8_t cmd) s->dma_auto = 0; break; - case 0xe0: + case 0xe0: /* DSP identification */ s->needed_bytes = 1; - goto warn; + break; case 0xe1: dsp_out_data (s, s->ver & 0xff); @@ -503,7 +565,7 @@ static void command (SB16State *s, uint8_t cmd) case 0xe7: dolog ("Attempt to probe for ESS (0xe7)?\n"); - return; + break; case 0xe8: /* read test reg */ dsp_out_data (s, s->test_reg); @@ -529,21 +591,29 @@ static void command (SB16State *s, uint8_t cmd) goto warn; default: - dolog ("unrecognized command %#x\n", cmd); - return; + dolog ("Unrecognized command %#x\n", cmd); + break; } } - s->cmd = cmd; - if (!s->needed_bytes) + if (!s->needed_bytes) { ldebug ("\n"); + } + + exit: + if (!s->needed_bytes) { + s->cmd = -1; + } + else { + s->cmd = cmd; + } return; warn: dolog ("warning: command %#x,%d is not truly understood yet\n", cmd, s->needed_bytes); - s->cmd = cmd; - return; + goto exit; + } static uint16_t dsp_get_lohi (SB16State *s) @@ -607,8 +677,9 @@ static void complete (SB16State *s) s->csp_reg83[s->csp_reg83r % 4] = d0; s->csp_reg83r += 1; } - else + else { s->csp_regs[d1] = d0; + } break; case 0x0f: @@ -622,8 +693,9 @@ static void complete (SB16State *s) dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]); s->csp_reg83w += 1; } - else + else { dsp_out_data (s, s->csp_regs[d0]); + } break; case 0x10: @@ -641,8 +713,9 @@ static void complete (SB16State *s) break; case 0x42: /* FT2 sets output freq with this, go figure */ +#if 0 dolog ("cmd 0x42 might not do what it think it should\n"); - +#endif case 0x41: s->freq = dsp_get_hilo (s); ldebug ("set freq %d\n", s->freq); @@ -653,6 +726,13 @@ static void complete (SB16State *s) ldebug ("set dma block len %d\n", s->block_size); break; + case 0x74: + case 0x75: + case 0x76: + case 0x77: + /* ADPCM stuff, ignore */ + break; + case 0x80: { int freq, samples, bytes; @@ -662,10 +742,17 @@ static void complete (SB16State *s) samples = dsp_get_lohi (s) + 1; bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); ticks = (bytes * ticks_per_sec) / freq; - if (ticks < ticks_per_sec / 1024) + if (ticks < ticks_per_sec / 1024) { pic_set_irq (s->irq, 1); - else - qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + ticks); + } + else { + if (s->aux_ts) { + qemu_mod_timer ( + s->aux_ts, + qemu_get_clock (vm_clock) + ticks + ); + } + } ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks); } break; @@ -674,7 +761,7 @@ static void complete (SB16State *s) d0 = dsp_get_data (s); s->out_data_len = 0; ldebug ("E0 data = %#x\n", d0); - dsp_out_data(s, ~d0); + dsp_out_data (s, ~d0); break; case 0xe2: @@ -737,6 +824,7 @@ static void reset (SB16State *s) s->nzero = 0; s->highspeed = 0; s->v2x6 = 0; + s->cmd = -1; dsp_out_data(s, 0xaa); speaker (s, 0); @@ -761,8 +849,9 @@ static IO_WRITE_PROTO (dsp_write) pic_set_irq (s->irq, 0); control (s, 0); } - else + else { reset (s); + } } s->v2x6 = 0; break; @@ -845,7 +934,10 @@ static IO_READ_PROTO (dsp_read) s->last_read_byte = retval; } else { - dolog ("empty output buffer\n"); + if (s->cmd != -1) { + dolog ("empty output buffer for command %#x\n", + s->cmd); + } retval = s->last_read_byte; /* goto error; */ } @@ -882,13 +974,14 @@ static IO_READ_PROTO (dsp_read) goto error; } - if (!ack) + if (!ack) { ldebug ("read %#x -> %#x\n", nport, retval); + } return retval; error: - dolog ("WARNING dsp_read %#x error\n", nport); + dolog ("warning: dsp_read %#x error\n", nport); return 0xff; } @@ -933,8 +1026,9 @@ static IO_WRITE_PROTO(mixer_write_datab) SB16State *s = opaque; ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); - if (s->mixer_nreg > sizeof (s->mixer_regs)) + if (s->mixer_nreg > sizeof (s->mixer_regs)) { return; + } switch (s->mixer_nreg) { case 0x00: @@ -945,8 +1039,9 @@ static IO_WRITE_PROTO(mixer_write_datab) { int irq = irq_of_magic (val); ldebug ("setting irq to %d (val=%#x)\n", irq, val); - if (irq > 0) + if (irq > 0) { s->irq = irq; + } } break; @@ -956,8 +1051,12 @@ static IO_WRITE_PROTO(mixer_write_datab) dma = lsbindex (val & 0xf); hdma = lsbindex (val & 0xf0); - dolog ("attempt to set DMA register 8bit %d, 16bit %d (val=%#x)\n", - dma, hdma, val); + if (dma != s->dma || hdma != s->hdma) { + dolog ( + "attempt to change DMA " + "8bit %d(%d), 16bit %d(%d) (val=%#x)\n", + dma, s->dma, hdma, s->hdma, val); + } #if 0 s->dma = dma; s->hdma = hdma; @@ -971,8 +1070,9 @@ static IO_WRITE_PROTO(mixer_write_datab) return; default: - if (s->mixer_nreg >= 0x80) - dolog ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val); + if (s->mixer_nreg >= 0x80) { + ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val); + } break; } @@ -989,10 +1089,14 @@ static IO_READ_PROTO(mixer_read) { SB16State *s = opaque; #ifndef DEBUG_SB16_MOST - if (s->mixer_nreg != 0x82) -#endif + if (s->mixer_nreg != 0x82) { + ldebug ("mixer_read[%#x] -> %#x\n", + s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); + } +#else ldebug ("mixer_read[%#x] -> %#x\n", s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); +#endif return s->mixer_regs[s->mixer_nreg]; } @@ -1010,8 +1114,9 @@ static int write_audio (SB16State *s, int nchan, int dma_pos, int to_copy, copied; to_copy = audio_MIN (temp, left); - if (to_copy > sizeof(tmpbuf)) + if (to_copy > sizeof(tmpbuf)) { to_copy = sizeof(tmpbuf); + } copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); copied = AUD_write (s->voice, tmpbuf, copied); @@ -1020,8 +1125,9 @@ static int write_audio (SB16State *s, int nchan, int dma_pos, dma_pos = (dma_pos + copied) % dma_len; net += copied; - if (!copied) + if (!copied) { break; + } } return net; @@ -1030,27 +1136,28 @@ static int write_audio (SB16State *s, int nchan, int dma_pos, static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) { SB16State *s = opaque; - int free, rfree, till, copy, written, elapsed; + int till, copy, written, free; if (s->left_till_irq < 0) { s->left_till_irq = s->block_size; } - elapsed = AUD_calc_elapsed (s->voice); - free = elapsed;/* AUD_get_free (s->voice); */ - rfree = free; - free = audio_MIN (free, elapsed) & ~s->align; - - if ((free <= 0) || !dma_len) { - return dma_pos; + if (s->voice) { + free = s->audio_free & ~s->align; + if ((free <= 0) || !dma_len) { + return dma_pos; + } + } + else { + free = dma_len; } copy = free; till = s->left_till_irq; #ifdef DEBUG_SB16_MOST - dolog ("pos:%06d free:%d,%d till:%d len:%d\n", - dma_pos, free, AUD_get_free (s->voice), till, dma_len); + dolog ("pos:%06d %d till:%d len:%d\n", + dma_pos, free, till, dma_len); #endif if (till <= copy) { @@ -1082,15 +1189,13 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) s->left_till_irq = s->block_size + s->left_till_irq; } - AUD_adjust (s->voice, written); return dma_pos; } -void SB_timer (void *opaque) +static void SB_audio_callback (void *opaque, int free) { SB16State *s = opaque; - AUD_run (); - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); + s->audio_free = free; } static void SB_save (QEMUFile *f, void *opaque) @@ -1150,8 +1255,9 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) { SB16State *s = opaque; - if (version_id != 1) + if (version_id != 1) { return -EINVAL; + } qemu_get_be32s (f, &s->irq); qemu_get_be32s (f, &s->dma); @@ -1202,14 +1308,23 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) qemu_get_buffer (f, s->mixer_regs, 256); if (s->voice) { - AUD_close (s->voice); + AUD_close_out (s->voice); s->voice = NULL; } if (s->dma_running) { - if (s->freq) - s->voice = AUD_open (s->voice, "sb16", s->freq, - 1 << s->fmt_stereo, s->fmt); + if (s->freq) { + s->audio_free = 0; + s->voice = AUD_open_out ( + s->voice, + "sb16", + s, + SB_audio_callback, + s->freq, + 1 << s->fmt_stereo, + s->fmt + ); + } control (s, 1); speaker (s, s->speaker); @@ -1224,10 +1339,7 @@ void SB16_init (void) static const uint8_t dsp_write_ports[] = {0x6, 0xc}; static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; - s->ts = qemu_new_timer (vm_clock, SB_timer, s); - if (!s->ts) - return; - + s->cmd = -1; s->irq = conf.irq; s->dma = conf.dma; s->hdma = conf.hdma; @@ -1243,8 +1355,9 @@ void SB16_init (void) reset_mixer (s); s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s); - if (!s->aux_ts) - return; + if (!s->aux_ts) { + dolog ("Can not create auxiliary timer\n"); + } for (i = 0; i < LENOFA (dsp_write_ports); i++) { register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s); @@ -1263,6 +1376,5 @@ void SB16_init (void) DMA_register_channel (s->dma, SB_read_DMA, s); s->can_write = 1; - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); register_savevm ("sb16", 0, 1, SB_save, SB_load, s); } diff --git a/qemu-doc.texi b/qemu-doc.texi index 526bd4b73..51875d774 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -181,8 +181,23 @@ The default is @code{en-us}. @item -enable-audio -The SB16 emulation is disabled by default as it may give problems with -Windows. You can enable it manually with this option. +Will enable audio and all the sound hardware QEMU was built with. + +@item -audio-help + +Will show the audio subsystem help: list of drivers, tunable +parameters. + +@item -soundhw card1,card2,... + +Enable audio and selected sound hardware. Use ? to print all +available sound hardware. + +@example +qemu -soundhw sb16,adlib hda +qemu -soundhw es1370 hda +qemu -soundhw ? +@end example @item -localtime Set the real time clock to local time (the default is to UTC diff --git a/vl.c b/vl.c index e7cd9668f..1ca0c347a 100644 --- a/vl.c +++ b/vl.c @@ -127,10 +127,13 @@ int nb_nics; NetDriverState nd_table[MAX_NICS]; QEMUTimer *gui_timer; int vm_running; +#ifdef HAS_AUDIO int audio_enabled = 0; -int sb16_enabled = 1; -int adlib_enabled = 1; -int gus_enabled = 1; +int sb16_enabled = 0; +int adlib_enabled = 0; +int gus_enabled = 0; +int es1370_enabled = 0; +#endif int pci_enabled = 1; int prep_enabled = 0; int rtc_utc = 1; @@ -930,7 +933,7 @@ static void init_timers(void) #ifdef _WIN32 { int count=0; - timerID = timeSetEvent(10, // interval (ms) + timerID = timeSetEvent(1, // interval (ms) 0, // resolution host_alarm_handler, // function (DWORD)&count, // user parameter @@ -2837,7 +2840,12 @@ void help(void) #ifndef _WIN32 "-k language use keyboard layout (for example \"fr\" for French)\n" #endif +#ifdef HAS_AUDIO "-enable-audio enable audio support\n" + "-audio-help print list of audio drivers and their options\n" + "-soundhw c1,... comma separated list of sound card names\n" + " use -soundhw ? to get the list of supported sound cards\n" +#endif "-localtime set the real time clock to local time [default=utc]\n" "-full-screen start in full screen\n" #ifdef TARGET_I386 @@ -2935,7 +2943,11 @@ enum { QEMU_OPTION_snapshot, QEMU_OPTION_m, QEMU_OPTION_nographic, +#ifdef HAS_AUDIO QEMU_OPTION_enable_audio, + QEMU_OPTION_audio_help, + QEMU_OPTION_soundhw, +#endif QEMU_OPTION_nics, QEMU_OPTION_macaddr, @@ -2998,7 +3010,11 @@ const QEMUOption qemu_options[] = { { "m", HAS_ARG, QEMU_OPTION_m }, { "nographic", 0, QEMU_OPTION_nographic }, { "k", HAS_ARG, QEMU_OPTION_k }, +#ifdef HAS_AUDIO { "enable-audio", 0, QEMU_OPTION_enable_audio }, + { "audio-help", 0, QEMU_OPTION_audio_help }, + { "soundhw", HAS_ARG, QEMU_OPTION_soundhw }, +#endif { "nics", HAS_ARG, QEMU_OPTION_nics}, { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, @@ -3117,6 +3133,78 @@ void register_machines(void) #endif } +#ifdef HAS_AUDIO +static void select_soundhw (const char *optarg) +{ + if (*optarg == '?') { + show_valid_cards: + printf ("Valid sound card names (comma separated):\n"); + printf ("sb16 Creative Sound Blaster 16\n"); +#ifdef CONFIG_ADLIB +#ifdef HAS_YMF262 + printf ("adlib Ymaha YMF262 (OPL3)\n"); +#else + printf ("adlib Ymaha YM3812 (OPL2)\n"); +#endif +#endif +#ifdef CONFIG_GUS + printf ("gus Gravis Ultrasound GF1\n"); +#endif + printf ("es1370 ENSONIQ AudioPCI ES1370\n"); + exit (*optarg != '?'); + } + else { + struct { + char *name; + int *enabledp; + } soundhw_tab[] = { + { "sb16", &sb16_enabled }, +#ifdef CONFIG_ADLIB + { "adlib", &adlib_enabled }, +#endif +#ifdef CONFIG_GUS + { "gus", &gus_enabled }, +#endif + { "es1370", &es1370_enabled }, + }; + size_t tablen, l, i; + const char *p; + char *e; + int bad_card = 0; + + p = optarg; + tablen = sizeof (soundhw_tab) / sizeof (soundhw_tab[0]); + + while (*p) { + e = strchr (p, ','); + l = !e ? strlen (p) : (size_t) (e - p); + for (i = 0; i < tablen; ++i) { + if (!strncmp (soundhw_tab[i].name, p, l)) { + audio_enabled = 1; + *soundhw_tab[i].enabledp = 1; + break; + } + } + if (i == tablen) { + if (l > 80) { + fprintf (stderr, + "Unknown sound card name (too big to show)\n"); + } + else { + fprintf (stderr, "Unknown sound card name `%.*s'\n", + (int) l, p); + } + bad_card = 1; + } + p += l + (e != NULL); + } + + if (bad_card) + goto show_valid_cards; + } +} +#endif + #define NET_IF_TUN 0 #define NET_IF_USER 1 #define NET_IF_DUMMY 2 @@ -3401,9 +3489,22 @@ int main(int argc, char **argv) case QEMU_OPTION_dummy_net: net_if_type = NET_IF_DUMMY; break; +#ifdef HAS_AUDIO case QEMU_OPTION_enable_audio: audio_enabled = 1; + sb16_enabled = 1; + adlib_enabled = 1; + gus_enabled = 1; + es1370_enabled = 1; break; + case QEMU_OPTION_audio_help: + AUD_help (); + exit (0); + break; + case QEMU_OPTION_soundhw: + select_soundhw (optarg); + break; +#endif case QEMU_OPTION_h: help(); break; diff --git a/vl.h b/vl.h index 31d05b6b5..543d57972 100644 --- a/vl.h +++ b/vl.h @@ -124,6 +124,7 @@ extern int audio_enabled; extern int sb16_enabled; extern int adlib_enabled; extern int gus_enabled; +extern int es1370_enabled; extern int ram_size; extern int bios_size; extern int rtc_utc; @@ -628,6 +629,9 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table); int pmac_ide_init (BlockDriverState **hd_table, SetIRQFunc *set_irq, void *irq_opaque, int irq); +/* es1370.c */ +int es1370_init (PCIBus *bus); + /* sb16.c */ void SB16_init (void); -- cgit v1.2.3 From 6f5f11a5bc1183f00847695d543a327af4e6c87c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 19:12:29 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1585 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index ea7806544..26f266e1a 100644 --- a/Changelog +++ b/Changelog @@ -1,8 +1,9 @@ version 0.7.3: - Mac OS X cocoa improvements (Mike Kronenberg) + - Mac OS X CoreAudio driver (Mike Kronenberg) - DirectSound driver (malc) - - new audio options: '-soundhw' and 'audio-help' (malc) + - new audio options: '-soundhw' and '-audio-help' (malc) - ES1370 PCI audio device (malc) version 0.7.2: -- cgit v1.2.3 From 05f3fb8de34098a1ff08c30e8a3d575c6f6f2cae Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 19:34:15 +0000 Subject: endianness fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1586 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/iommu.c b/hw/iommu.c index 6defe61ca..e7d96c81c 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -194,8 +194,7 @@ uint32_t iommu_translate_local(void *opaque, uint32_t addr) iopte = s->regs[1] << 4; addr &= ~s->iostart; iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; - cpu_physical_memory_read(iopte, (void *) &pa, 4); - bswap32s(&pa); + pa = ldl_phys(iopte); tmppte = pa; pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte); -- cgit v1.2.3 From aab33094073678d459ccaac5c60ea7533e8d1d8e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 20:48:42 +0000 Subject: more physical memory access functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1587 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 6 ++++++ exec.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index 4f1f7726a..be42bc9eb 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -735,9 +735,15 @@ static inline void cpu_physical_memory_write(target_phys_addr_t addr, { 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); int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write); diff --git a/exec.c b/exec.c index 11a3a6499..95fbe12ce 100644 --- a/exec.c +++ b/exec.c @@ -2284,6 +2284,30 @@ uint32_t ldl_phys(target_phys_addr_t addr) return val; } +/* XXX: optimize */ +uint32_t ldub_phys(target_phys_addr_t addr) +{ + uint8_t val; + cpu_physical_memory_read(addr, &val, 1); + return val; +} + +/* XXX: optimize */ +uint32_t lduw_phys(target_phys_addr_t addr) +{ + uint16_t val; + cpu_physical_memory_read(addr, (uint8_t *)&val, 2); + return tswap16(val); +} + +/* XXX: optimize */ +uint64_t ldq_phys(target_phys_addr_t addr) +{ + uint64_t val; + cpu_physical_memory_read(addr, (uint8_t *)&val, 8); + return tswap64(val); +} + /* warning: addr must be aligned. The ram page is not masked as dirty and the code inside is not invalidated. It is useful if the dirty bits are used to track modified PTEs */ @@ -2345,6 +2369,27 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) } } +/* XXX: optimize */ +void stb_phys(target_phys_addr_t addr, uint32_t val) +{ + uint8_t v = val; + cpu_physical_memory_write(addr, &v, 1); +} + +/* XXX: optimize */ +void stw_phys(target_phys_addr_t addr, uint32_t val) +{ + uint16_t v = tswap16(val); + cpu_physical_memory_write(addr, (const uint8_t *)&v, 2); +} + +/* XXX: optimize */ +void stq_phys(target_phys_addr_t addr, uint64_t val) +{ + val = tswap64(val); + cpu_physical_memory_write(addr, (const uint8_t *)&val, 8); +} + #endif /* virtual memory access for debug */ -- cgit v1.2.3 From 02aab46a362acd041006776e322a85a7753e4c14 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 20:49:44 +0000 Subject: endianness fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1588 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 80 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 468bbb6b4..e931f9a32 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -256,11 +256,18 @@ void helper_ld_asi(int asi, int size, int sign) } break; case 0x20 ... 0x2f: /* MMU passthrough */ - cpu_physical_memory_read(T0, (void *) &ret, size); - if (size == 4) - tswap32s(&ret); - else if (size == 2) - tswap16s((uint16_t *)&ret); + switch(size) { + case 1: + ret = ldub_phys(T0); + break; + case 2: + ret = lduw_phys(T0 & ~1); + break; + default: + case 4: + ret = ldl_phys(T0 & ~3); + break; + } break; default: ret = 0; @@ -369,12 +376,18 @@ void helper_st_asi(int asi, int size, int sign) return; case 0x20 ... 0x2f: /* MMU passthrough */ { - uint32_t temp = T1; - if (size == 4) - tswap32s(&temp); - else if (size == 2) - tswap16s((uint16_t *)&temp); - cpu_physical_memory_write(T0, (void *) &temp, size); + switch(size) { + case 1: + stb_phys(T0, T1); + break; + case 2: + stw_phys(T0 & ~1, T1); + break; + case 4: + default: + stl_phys(T0 & ~3, T1); + break; + } } return; default: @@ -395,13 +408,21 @@ void helper_ld_asi(int asi, int size, int sign) case 0x14: // Bypass case 0x15: // Bypass, non-cacheable { - cpu_physical_memory_read(T0, (void *) &ret, size); - if (size == 8) - tswap64s(&ret); - if (size == 4) - tswap32s((uint32_t *)&ret); - else if (size == 2) - tswap16s((uint16_t *)&ret); + switch(size) { + case 1: + ret = ldub_phys(T0); + break; + case 2: + ret = lduw_phys(T0 & ~1); + break; + case 4: + ret = ldl_phys(T0 & ~3); + break; + default: + case 8: + ret = ldq_phys(T0 & ~7); + break; + } break; } case 0x04: // Nucleus @@ -503,14 +524,21 @@ void helper_st_asi(int asi, int size, int sign) case 0x14: // Bypass case 0x15: // Bypass, non-cacheable { - target_ulong temp = T1; - if (size == 8) - tswap64s(&temp); - else if (size == 4) - tswap32s((uint32_t *)&temp); - else if (size == 2) - tswap16s((uint16_t *)&temp); - cpu_physical_memory_write(T0, (void *) &temp, size); + switch(size) { + case 1: + stb_phys(T0, T1); + break; + case 2: + stw_phys(T0 & ~1, T1); + break; + case 4: + stl_phys(T0 & ~3, T1); + break; + case 8: + default: + stq_phys(T0 & ~7, T1); + break; + } } return; case 0x04: // Nucleus -- cgit v1.2.3 From bd6ea3c8f32b3f1127026ecdd813b87baf649483 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 20:53:51 +0000 Subject: vmdk endianness fix (Benoit Poulot-Cazajous) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1589 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vmdk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block-vmdk.c b/block-vmdk.c index 3bbd1494f..fc87be353 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -123,8 +123,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename) if (read(fd, &header, sizeof(header)) != sizeof(header)) goto fail; - bs->total_sectors = le32_to_cpu(header.capacity); - s->cluster_sectors = le32_to_cpu(header.granularity); + 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) -- cgit v1.2.3 From afce2927aac2a668edcaa4ef6d025b87cd8e0cd5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 20:58:30 +0000 Subject: Arm AT_HWCAP AUXV entry (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1590 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 7b102c6cb..2ae1e5324 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -91,6 +91,28 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 +#define DLINFO_ARCH_ITEMS 1 +enum +{ + ARM_HWCAP_ARM_SWP = 1 << 0, + ARM_HWCAP_ARM_HALF = 1 << 1, + ARM_HWCAP_ARM_THUMB = 1 << 2, + ARM_HWCAP_ARM_26BIT = 1 << 3, + ARM_HWCAP_ARM_FAST_MULT = 1 << 4, + ARM_HWCAP_ARM_FPA = 1 << 5, + ARM_HWCAP_ARM_VFP = 1 << 6, + ARM_HWCAP_ARM_EDSP = 1 << 7, +}; + +#define ARM_HWCAPS (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ + | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ + | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP) + +#define ARCH_DLINFO \ +do { \ + NEW_AUX_ENT(AT_HWCAP, ARM_HWCAPS); \ +} while (0) + #endif #ifdef TARGET_SPARC -- cgit v1.2.3 From 74c33bed31839bbff861877194a5a39f8000c284 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 21:01:05 +0000 Subject: User-mode gdbserver port number (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1591 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 622d06edf..468cb9b89 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -978,7 +978,7 @@ void usage(void) "Linux CPU emulator (compiled for %s emulation)\n" "\n" "-h print this help\n" - "-g wait gdb connection to port %d\n" + "-g port wait gdb connection to port\n" "-L path set the elf interpreter prefix (default=%s)\n" "-s size set the stack size in bytes (default=%ld)\n" "\n" @@ -989,7 +989,6 @@ void usage(void) "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n", TARGET_ARCH, - DEFAULT_GDBSTUB_PORT, interp_prefix, x86_stack_size, DEBUG_LOGFILE); @@ -1013,7 +1012,7 @@ int main(int argc, char **argv) CPUState *env; int optind; const char *r; - int use_gdbstub = 0; + int gdbstub_port = 0; if (argc <= 1) usage(); @@ -1068,7 +1067,7 @@ int main(int argc, char **argv) exit(1); } } else if (!strcmp(r, "g")) { - use_gdbstub = 1; + gdbstub_port = atoi(argv[optind++]); } else #ifdef USE_CODE_COPY if (!strcmp(r, "no-code-copy")) { @@ -1247,8 +1246,8 @@ int main(int argc, char **argv) #error unsupported target CPU #endif - if (use_gdbstub) { - gdbserver_start (DEFAULT_GDBSTUB_PORT); + if (gdbstub_port) { + gdbserver_start (gdbstub_port); gdb_handlesig(env, 0); } cpu_loop(env); -- cgit v1.2.3 From 24741ef3de1de0e5dca6ebf621d405f2ac0919af Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 21:23:39 +0000 Subject: avoid using physical accesses in user emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1592 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 14 --- target-ppc/helper.c | 38 ++++++-- target-sparc/helper.c | 235 +++++++++++++++++++++++------------------------ target-sparc/op_helper.c | 11 ++- 4 files changed, 156 insertions(+), 142 deletions(-) diff --git a/exec.c b/exec.c index 95fbe12ce..a6f973eda 100644 --- a/exec.c +++ b/exec.c @@ -2152,20 +2152,6 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } -/* never used */ -uint32_t ldl_phys(target_phys_addr_t addr) -{ - return 0; -} - -void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) -{ -} - -void stl_phys(target_phys_addr_t addr, uint32_t val) -{ -} - #else void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c9693c8b1..66c26041c 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -36,6 +36,32 @@ /*****************************************************************************/ /* PowerPC MMU emulation */ +#if defined(CONFIG_USER_ONLY) +int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu) +{ + int exception, error_code; + + if (rw == 2) { + exception = EXCP_ISI; + error_code = 0; + } else { + exception = EXCP_DSI; + error_code = 0; + if (rw) + error_code |= 0x02000000; + env->spr[SPR_DAR] = address; + env->spr[SPR_DSISR] = error_code; + } + env->exception_index = exception; + env->error_code = error_code; + return 1; +} +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} +#else /* Perform BAT hit & translation */ static int get_bat (CPUState *env, uint32_t *real, int *prot, uint32_t virtual, int rw, int type) @@ -355,8 +381,8 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, return ret; } -int get_physical_address (CPUState *env, uint32_t *physical, int *prot, - uint32_t address, int rw, int access_type) +static int get_physical_address (CPUState *env, uint32_t *physical, int *prot, + uint32_t address, int rw, int access_type) { int ret; #if 0 @@ -387,12 +413,6 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, return ret; } -#if defined(CONFIG_USER_ONLY) -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - return addr; -} -#else target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { uint32_t phys_addr; @@ -402,7 +422,6 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return -1; return phys_addr; } -#endif /* Perform address translation */ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, @@ -523,6 +542,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, } return ret; } +#endif /*****************************************************************************/ /* BATs management */ diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 78a033bc5..ad1ae5bbb 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -230,7 +230,107 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 1; } } -#else + +target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) +{ + target_phys_addr_t pde_ptr; + uint32_t pde; + + /* Context base + context number */ + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 2: /* PTE, maybe should not happen? */ + case 3: /* Reserved */ + return 0; + case 1: /* L1 PDE */ + if (mmulev == 3) + return pde; + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L1 PTE */ + return pde; + case 1: /* L2 PDE */ + if (mmulev == 2) + return pde; + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L2 PTE */ + return pde; + case 1: /* L3 PDE */ + if (mmulev == 1) + return pde; + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + pde = ldl_phys(pde_ptr); + + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 1: /* PDE, should not happen */ + case 3: /* Reserved */ + return 0; + case 2: /* L3 PTE */ + return pde; + } + } + } + } + return 0; +} + +#ifdef DEBUG_MMU +void dump_mmu(CPUState *env) +{ + target_ulong va, va1, va2; + unsigned int n, m, o; + target_phys_addr_t pde_ptr, pa; + uint32_t pde; + + printf("MMU dump:\n"); + pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); + pde = ldl_phys(pde_ptr); + printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); + for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { + pde_ptr = mmu_probe(env, va, 2); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va); + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr); + for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { + pde_ptr = mmu_probe(env, va1, 1); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va1); + printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr); + for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { + pde_ptr = mmu_probe(env, va2, 0); + if (pde_ptr) { + pa = cpu_get_phys_page_debug(env, va2); + printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr); + } + } + } + } + } + } + printf("MMU dump ends\n"); +} +#endif /* DEBUG_MMU */ + +#else /* !TARGET_SPARC64 */ /* * UltraSparc IIi I/DMMUs */ @@ -382,121 +482,6 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 1; } -#endif -#endif - -void memcpy32(target_ulong *dst, const target_ulong *src) -{ - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = src[3]; - dst[4] = src[4]; - dst[5] = src[5]; - dst[6] = src[6]; - dst[7] = src[7]; -} - -#if !defined(TARGET_SPARC64) -target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) -{ - target_phys_addr_t pde_ptr; - uint32_t pde; - - /* Context base + context number */ - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 2: /* PTE, maybe should not happen? */ - case 3: /* Reserved */ - return 0; - case 1: /* L1 PDE */ - if (mmulev == 3) - return pde; - pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 3: /* Reserved */ - return 0; - case 2: /* L1 PTE */ - return pde; - case 1: /* L2 PDE */ - if (mmulev == 2) - return pde; - pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 3: /* Reserved */ - return 0; - case 2: /* L2 PTE */ - return pde; - case 1: /* L3 PDE */ - if (mmulev == 1) - return pde; - pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); - pde = ldl_phys(pde_ptr); - - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 1: /* PDE, should not happen */ - case 3: /* Reserved */ - return 0; - case 2: /* L3 PTE */ - return pde; - } - } - } - } - return 0; -} - -#ifdef DEBUG_MMU -void dump_mmu(CPUState *env) -{ - target_ulong va, va1, va2; - unsigned int n, m, o; - target_phys_addr_t pde_ptr, pa; - uint32_t pde; - - printf("MMU dump:\n"); - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); - pde = ldl_phys(pde_ptr); - printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); - for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { - pde_ptr = mmu_probe(env, va, 2); - if (pde_ptr) { - pa = cpu_get_phys_page_debug(env, va); - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr); - for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { - pde_ptr = mmu_probe(env, va1, 1); - if (pde_ptr) { - pa = cpu_get_phys_page_debug(env, va1); - printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr); - for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { - pde_ptr = mmu_probe(env, va2, 0); - if (pde_ptr) { - pa = cpu_get_phys_page_debug(env, va2); - printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr); - } - } - } - } - } - } - printf("MMU dump ends\n"); -} -#endif -#else #ifdef DEBUG_MMU void dump_mmu(CPUState *env) { @@ -568,5 +553,19 @@ void dump_mmu(CPUState *env) } } } -#endif -#endif +#endif /* DEBUG_MMU */ + +#endif /* TARGET_SPARC64 */ +#endif /* !CONFIG_USER_ONLY */ + +void memcpy32(target_ulong *dst, const target_ulong *src) +{ + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index e931f9a32..695bc21e0 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -221,6 +221,15 @@ void do_fcmpd_fcc3 (void) #undef FS #endif +#if defined(CONFIG_USER_ONLY) +void helper_ld_asi(int asi, int size, int sign) +{ +} + +void helper_st_asi(int asi, int size, int sign) +{ +} +#else #ifndef TARGET_SPARC64 void helper_ld_asi(int asi, int size, int sign) { @@ -727,8 +736,8 @@ void helper_st_asi(int asi, int size, int sign) return; } } - #endif +#endif /* !CONFIG_USER_ONLY */ #ifndef TARGET_SPARC64 void helper_rett() -- cgit v1.2.3 From d5d11eac6c853d10a9d97a279f1c69e0f0d66397 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 21:38:50 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1593 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 26f266e1a..56efe3cc8 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,7 @@ version 0.7.3: - 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) -- cgit v1.2.3 From c53be3347484b0f73deebcfa2e5faf538d6fa7c0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 21:39:19 +0000 Subject: suppressed JUMP_TB (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1594 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 9 --------- target-arm/op.c | 8 ++++---- target-arm/translate.c | 25 ++++++++++++++++++++++--- target-mips/op.c | 38 +++++++++++++------------------------- target-mips/translate.c | 47 ++++++++++++++++++++++++++++++++++++++++------- target-ppc/op.c | 18 ++++++++++-------- target-ppc/translate.c | 31 +++++++++++++++++++++++++++---- 7 files changed, 116 insertions(+), 60 deletions(-) diff --git a/exec-all.h b/exec-all.h index 5db83d368..380300698 100644 --- a/exec-all.h +++ b/exec-all.h @@ -365,15 +365,6 @@ dummy_label ## n: ;\ #endif -/* XXX: will be suppressed */ -#define JUMP_TB(opname, tbparam, n, eip)\ -do {\ - GOTO_TB(opname, tbparam, n);\ - T0 = (long)(tbparam) + (n);\ - EIP = (int32_t)eip;\ - EXIT_TB();\ -} while (0) - extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; diff --git a/target-arm/op.c b/target-arm/op.c index 8a82def79..1d30b1bda 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -346,14 +346,14 @@ void OPPROTO op_test_le(void) FORCE_RET(); } -void OPPROTO op_jmp0(void) +void OPPROTO op_goto_tb0(void) { - JUMP_TB(op_jmp0, PARAM1, 0, PARAM2); + GOTO_TB(op_goto_tb0, PARAM1, 0); } -void OPPROTO op_jmp1(void) +void OPPROTO op_goto_tb1(void) { - JUMP_TB(op_jmp1, PARAM1, 1, PARAM2); + GOTO_TB(op_goto_tb1, PARAM1, 1); } void OPPROTO op_exit_tb(void) diff --git a/target-arm/translate.c b/target-arm/translate.c index c3e8fe826..f954de3f7 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -43,6 +43,12 @@ typedef struct DisasContext { #define DISAS_JUMP_NEXT 4 +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) (long)(x) +#endif + /* XXX: move that elsewhere */ static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; @@ -897,6 +903,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) return 0; } +static inline void gen_jmp_tb(long tb, int n, uint32_t dest) +{ + if (n == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_op_movl_T0_im(dest); + gen_op_movl_r15_T0(); + gen_op_movl_T0_im(tb + n); + gen_op_exit_tb(); +} + static inline void gen_jmp (DisasContext *s, uint32_t dest) { if (__builtin_expect(s->singlestep_enabled, 0)) { @@ -906,7 +924,8 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) gen_op_movl_T0_im(dest); gen_bx(s); } else { - gen_op_jmp0((long)s->tb, dest); + long tb = (long)s->tb; + gen_jmp_tb(tb, 0, dest); s->is_jmp = DISAS_TB_JUMP; } } @@ -2118,7 +2137,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, } else { switch(dc->is_jmp) { case DISAS_NEXT: - gen_op_jmp1((long)dc->tb, (long)dc->pc); + gen_jmp_tb((long)dc->tb, 1, dc->pc); break; default: case DISAS_JUMP: @@ -2133,7 +2152,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, } if (dc->condjmp) { gen_set_label(dc->condlabel); - gen_op_jmp1((long)dc->tb, (long)dc->pc); + gen_jmp_tb((long)dc->tb, 1, dc->pc); dc->condjmp = 0; } } diff --git a/target-mips/op.c b/target-mips/op.c index 32f7e4fc9..029ce5d00 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -487,7 +487,16 @@ OP_COND(ltz, (int32_t)T0 < 0); /* Branchs */ //#undef USE_DIRECT_JUMP -#define EIP env->PC + +void OPPROTO op_goto_tb0(void) +{ + GOTO_TB(op_goto_tb0, PARAM1, 0); +} + +void OPPROTO op_goto_tb1(void) +{ + GOTO_TB(op_goto_tb1, PARAM1, 1); +} /* Branch to register */ void op_save_breg_target (void) @@ -506,13 +515,6 @@ void op_breg (void) RETURN(); } -/* Unconditional branch */ -void op_branch (void) -{ - JUMP_TB(branch, PARAM1, 0, PARAM2); - RETURN(); -} - void op_save_btarget (void) { env->btarget = PARAM1; @@ -538,24 +540,10 @@ void op_restore_bcond (void) RETURN(); } -void op_bcond (void) -{ - if (T2) { - JUMP_TB(bcond, PARAM1, 0, PARAM2); - } else { - JUMP_TB(bcond, PARAM1, 1, PARAM3); - } - RETURN(); -} - -/* Likely branch (used to skip the delay slot) */ -void op_blikely (void) +void op_jnz_T2 (void) { - /* If the test is false, skip the delay slot */ - if (T2 == 0) { - env->hflags = PARAM3; - JUMP_TB(blikely, PARAM1, 1, PARAM2); - } + if (T2) + GOTO_LABEL_PARAM(1); RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index 705577547..5e54dd84b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -31,6 +31,12 @@ #define MIPS_DEBUG_DISAS //#define MIPS_SINGLE_STEP +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) (long)(x) +#endif + enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, #include "opc.h" @@ -922,6 +928,17 @@ static void gen_trap (DisasContext *ctx, uint16_t opc, ctx->bstate = BS_STOP; } +static inline void gen_jmp_tb(long tb, int n, uint32_t dest) +{ + if (n == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_op_save_pc(dest); + gen_op_set_T0(tb + n); + gen_op_exit_tb(); +} + /* Branches (before delay slot) */ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, int rs, int rt, int32_t offset) @@ -1018,7 +1035,7 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, case OPC_BLTZL: /* 0 < 0 likely */ /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever and skip"); - gen_op_branch((long)ctx->tb, ctx->pc + 4); + gen_jmp_tb((long)ctx->tb, 0, ctx->pc + 4); return; case OPC_J: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; @@ -1255,6 +1272,15 @@ static void gen_arith64 (DisasContext *ctx, uint16_t opc) #endif +static void gen_blikely(DisasContext *ctx) +{ + int l1; + l1 = gen_new_label(); + gen_op_jnz_T2(l1); + gen_op_save_state(ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); + gen_jmp_tb((long)ctx->tb, 1, ctx->pc + 4); +} + static void decode_opc (DisasContext *ctx) { int32_t offset; @@ -1266,8 +1292,7 @@ static void decode_opc (DisasContext *ctx) (ctx->hflags & MIPS_HFLAG_BL)) { /* Handle blikely not taken case */ MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); - gen_op_blikely((long)ctx->tb, ctx->pc + 4, - ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); + gen_blikely(ctx); } op = ctx->opcode >> 26; rs = ((ctx->opcode >> 21) & 0x1F); @@ -1477,17 +1502,24 @@ static void decode_opc (DisasContext *ctx) case MIPS_HFLAG_B: /* unconditional branch */ MIPS_DEBUG("unconditional branch"); - gen_op_branch((long)ctx->tb, ctx->btarget); + gen_jmp_tb((long)ctx->tb, 0, ctx->btarget); break; case MIPS_HFLAG_BL: /* blikely taken case */ MIPS_DEBUG("blikely branch taken"); - gen_op_branch((long)ctx->tb, ctx->btarget); + gen_jmp_tb((long)ctx->tb, 0, ctx->btarget); break; case MIPS_HFLAG_BC: /* Conditional branch */ MIPS_DEBUG("conditional branch"); - gen_op_bcond((long)ctx->tb, ctx->btarget, ctx->pc + 4); + { + int l1; + l1 = gen_new_label(); + gen_op_jnz_T2(l1); + gen_jmp_tb((long)ctx->tb, 0, ctx->btarget); + gen_set_label(l1); + gen_jmp_tb((long)ctx->tb, 1, ctx->pc + 4); + } break; case MIPS_HFLAG_BR: /* unconditional branch to register */ @@ -1513,6 +1545,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; + nb_gen_labels = 0; ctx.pc = pc_start; ctx.tb = tb; ctx.bstate = BS_NONE; @@ -1570,7 +1603,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { save_cpu_state(ctxp, 0); - gen_op_branch((long)ctx.tb, ctx.pc); + gen_jmp_tb((long)ctx.tb, 0, ctx.pc); } gen_op_reset_T0(); /* Generate the return instruction */ diff --git a/target-ppc/op.c b/target-ppc/op.c index 0e37119da..4b0af5587 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -451,9 +451,14 @@ PPC_OP(setlr) regs->lr = PARAM1; } -PPC_OP(b) +PPC_OP(goto_tb0) { - JUMP_TB(b1, PARAM1, 0, PARAM2); + GOTO_TB(op_goto_tb0, PARAM1, 0); +} + +PPC_OP(goto_tb1) +{ + GOTO_TB(op_goto_tb1, PARAM1, 1); } PPC_OP(b_T1) @@ -461,13 +466,10 @@ PPC_OP(b_T1) regs->nip = T1 & ~3; } -PPC_OP(btest) +PPC_OP(jz_T0) { - if (T0) { - JUMP_TB(btest, PARAM1, 0, PARAM2); - } else { - JUMP_TB(btest, PARAM1, 1, PARAM3); - } + if (!T0) + GOTO_LABEL_PARAM(1); RETURN(); } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 70f88637d..c04c0ef99 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -30,6 +30,12 @@ //#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) (long)(x) +#endif + enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, #include "opc.h" @@ -1721,6 +1727,18 @@ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) /*** Branch ***/ +static inline void gen_jmp_tb(long tb, int n, uint32_t dest) +{ + if (n == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_op_set_T1(dest); + gen_op_b_T1(); + gen_op_set_T0(tb + n); + gen_op_exit_tb(); +} + /* b ba bl bla */ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { @@ -1736,7 +1754,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) if (LK(ctx->opcode)) { gen_op_setlr(ctx->nip); } - gen_op_b((long)ctx->tb, target); + gen_jmp_tb((long)ctx->tb, 0, target); ctx->exception = EXCP_BRANCH; } @@ -1787,7 +1805,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) case 4: case 6: if (type == BCOND_IM) { - gen_op_b((long)ctx->tb, target); + gen_jmp_tb((long)ctx->tb, 0, target); } else { gen_op_b_T1(); } @@ -1827,7 +1845,11 @@ static inline void gen_bcond(DisasContext *ctx, int type) } } if (type == BCOND_IM) { - gen_op_btest((long)ctx->tb, target, ctx->nip); + int l1 = gen_new_label(); + gen_op_jz_T0(l1); + gen_jmp_tb((long)ctx->tb, 0, target); + gen_set_label(l1); + gen_jmp_tb((long)ctx->tb, 1, ctx->nip); } else { gen_op_btest_T1(ctx->nip); } @@ -2459,6 +2481,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; + nb_gen_labels = 0; ctx.nip = pc_start; ctx.tb = tb; ctx.exception = EXCP_NONE; @@ -2575,7 +2598,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #endif } if (ctx.exception == EXCP_NONE) { - gen_op_b((unsigned long)ctx.tb, ctx.nip); + gen_jmp_tb((long)ctx.tb, 0, ctx.nip); } else if (ctx.exception != EXCP_BRANCH) { gen_op_set_T0(0); } -- cgit v1.2.3 From 9903da21e34d84a01ab6dfc30a01f619e6ef5415 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Oct 2005 23:19:10 +0000 Subject: SDL full screen patch for Windows (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1595 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sdl.c b/sdl.c index d43da8831..9c7afd907 100644 --- a/sdl.c +++ b/sdl.c @@ -55,11 +55,22 @@ static void sdl_resize(DisplayState *ds, int w, int h) flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; if (gui_fullscreen) flags |= SDL_FULLSCREEN; + + again: screen = SDL_SetVideoMode(w, h, 0, flags); if (!screen) { fprintf(stderr, "Could not open SDL display\n"); exit(1); } + if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) { + flags &= ~SDL_HWSURFACE; + goto again; + } + + if (!screen->pixels) { + fprintf(stderr, "Could not open SDL display\n"); + exit(1); + } ds->data = screen->pixels; ds->linesize = screen->pitch; ds->depth = screen->format->BitsPerPixel; -- cgit v1.2.3 From 1aff381f59b508a422f6fe03965fbc3728d3c45a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 2 Nov 2005 22:30:45 +0000 Subject: gcc4 warning (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1596 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/configure b/configure index 98ef82b6e..ee3b7f33e 100755 --- a/configure +++ b/configure @@ -88,6 +88,7 @@ kqemu="no" kernel_path="" cocoa="no" check_gfx="yes" +check_gcc="yes" # OS specific targetos=`uname -s` @@ -200,6 +201,8 @@ for opt do ;; --disable-gfx-check) check_gfx="no" ;; + --disable-gcc-check) check_gcc="no" + ;; esac done @@ -277,6 +280,23 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu have_gcc3_options="yes" fi +# Check for gcc4 +if test "$check_gcc" = "yes" ; then + cat > $TMPC <= 4 +#error gcc4 +#endif +int main(){return 0;} +EOF + if ! $cc -o $TMPO $TMPC 2>/dev/null ; then + echo "ERROR: \"$cc\" looks like gcc 4.x" + 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 + ########################################## # SDL probe -- cgit v1.2.3 From bb36d4708bc93874af95db54da2a9cee0d30a84d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Nov 2005 14:22:28 +0000 Subject: initial USB support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1597 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 2 +- hw/pc.c | 22 ++ hw/usb-uhci.c | 672 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb.c | 694 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb.h | 139 ++++++++++++ usb-linux.c | 309 +++++++++++++++++++++++++ vl.c | 6 + vl.h | 3 + 9 files changed, 1847 insertions(+), 1 deletion(-) create mode 100644 hw/usb-uhci.c create mode 100644 hw/usb.c create mode 100644 hw/usb.h create mode 100644 usb-linux.c diff --git a/Changelog b/Changelog index 56efe3cc8..6aff1395d 100644 --- a/Changelog +++ b/Changelog @@ -6,6 +6,7 @@ version 0.7.3: - ALSA audio driver (malc) - new audio options: '-soundhw' and '-audio-help' (malc) - ES1370 PCI audio device (malc) + - Initial USB support version 0.7.2: diff --git a/Makefile.target b/Makefile.target index b1773f4dd..56b7036a5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -294,7 +294,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o -VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o usb.o usb-uhci.o usb-linux.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff --git a/hw/pc.c b/hw/pc.c index ad3d5e032..cd28998e1 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -620,6 +620,28 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, cmos_init(ram_size, boot_device, bs_table); + if (pci_enabled && usb_enabled) { + USBPort *usb_root_ports[2]; + USBDevice *usb_hub; + usb_uhci_init(pci_bus, usb_root_ports); +#if 0 + { + USBPort *usb_hub1_ports[4]; + USBPort *usb_hub2_ports[2]; + /* test: we simulate a USB hub */ + usb_hub = usb_hub_init(usb_hub1_ports, 4); + usb_attach(usb_root_ports[0], usb_hub); + + /* test: we simulate a USB hub */ + usb_hub = usb_hub_init(usb_hub2_ports, 2); + usb_attach(usb_hub1_ports[0], usb_hub); + } +#endif + /* simulated hub with the host USB devices connected to it */ + usb_hub = usb_host_hub_init(); + usb_attach(usb_root_ports[0], usb_hub); + } + /* must be done after all PCI devices are instanciated */ /* XXX: should be done in the Bochs BIOS */ if (pci_enabled) { diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c new file mode 100644 index 000000000..42417feda --- /dev/null +++ b/hw/usb-uhci.c @@ -0,0 +1,672 @@ +/* + * USB UHCI controller emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG +//#define DEBUG_PACKET + +#define UHCI_CMD_GRESET (1 << 2) +#define UHCI_CMD_HCRESET (1 << 1) +#define UHCI_CMD_RS (1 << 0) + +#define UHCI_STS_HCHALTED (1 << 5) +#define UHCI_STS_HCPERR (1 << 4) +#define UHCI_STS_HSERR (1 << 3) +#define UHCI_STS_RD (1 << 2) +#define UHCI_STS_USBERR (1 << 1) +#define UHCI_STS_USBINT (1 << 0) + +#define TD_CTRL_SPD (1 << 29) +#define TD_CTRL_ERROR_SHIFT 27 +#define TD_CTRL_IOS (1 << 25) +#define TD_CTRL_IOC (1 << 24) +#define TD_CTRL_ACTIVE (1 << 23) +#define TD_CTRL_STALL (1 << 22) +#define TD_CTRL_BABBLE (1 << 20) +#define TD_CTRL_NAK (1 << 19) +#define TD_CTRL_TIMEOUT (1 << 18) + +#define UHCI_PORT_RESET (1 << 9) +#define UHCI_PORT_LSDA (1 << 8) +#define UHCI_PORT_ENC (1 << 3) +#define UHCI_PORT_EN (1 << 2) +#define UHCI_PORT_CSC (1 << 1) +#define UHCI_PORT_CCS (1 << 0) + +#define FRAME_TIMER_FREQ 1000 + +#define FRAME_MAX_LOOPS 100 + +#define NB_PORTS 2 + +typedef struct UHCIPort { + USBPort port; + uint16_t ctrl; + USBDevice *dev; /* connected device */ +} UHCIPort; + +typedef struct UHCIState { + PCIDevice dev; + uint16_t cmd; /* cmd register */ + uint16_t status; + uint16_t intr; /* interrupt enable register */ + uint16_t frnum; /* frame number */ + uint32_t fl_base_addr; /* frame list base address */ + uint8_t sof_timing; + uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ + QEMUTimer *frame_timer; + UHCIPort ports[NB_PORTS]; +} UHCIState; + +typedef struct UHCI_TD { + uint32_t link; + uint32_t ctrl; /* see TD_CTRL_xxx */ + uint32_t token; + uint32_t buffer; +} UHCI_TD; + +typedef struct UHCI_QH { + uint32_t link; + uint32_t el_link; +} UHCI_QH; + +static void uhci_attach(USBPort *port1, USBDevice *dev); + +static void uhci_update_irq(UHCIState *s) +{ + int level; + if (((s->status2 & 1) && (s->intr & (1 << 2))) || + ((s->status2 & 2) && (s->intr & (1 << 3))) || + ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) || + ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) || + (s->status & UHCI_STS_HSERR) || + (s->status & UHCI_STS_HCPERR)) { + level = 1; + } else { + level = 0; + } + pci_set_irq(&s->dev, 0, level); +} + +static void uhci_reset(UHCIState *s) +{ + uint8_t *pci_conf; + int i; + UHCIPort *port; + + pci_conf = s->dev.config; + + pci_conf[0x6a] = 0x01; /* usb clock */ + pci_conf[0x6b] = 0x00; + s->cmd = 0; + s->status = 0; + s->status2 = 0; + s->intr = 0; + s->fl_base_addr = 0; + s->sof_timing = 64; + for(i = 0; i < NB_PORTS; i++) { + port = &s->ports[i]; + port->ctrl = 0x0080; + if (port->dev) + uhci_attach(&port->port, port->dev); + } +} + +static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + UHCIState *s = opaque; + + addr &= 0x1f; + switch(addr) { + case 0x0c: + s->sof_timing = val; + break; + } +} + +static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) +{ + UHCIState *s = opaque; + uint32_t val; + + addr &= 0x1f; + switch(addr) { + case 0x0c: + val = s->sof_timing; + default: + val = 0xff; + break; + } + return val; +} + +static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +{ + UHCIState *s = opaque; + + addr &= 0x1f; +#ifdef DEBUG + printf("uhci writew port=0x%04x val=0x%04x\n", addr, val); +#endif + switch(addr) { + case 0x00: + if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { + /* start frame processing */ + qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock)); + } + if (val & UHCI_CMD_GRESET) { + UHCIPort *port; + USBDevice *dev; + int i; + + /* send reset on the USB bus */ + for(i = 0; i < NB_PORTS; i++) { + port = &s->ports[i]; + dev = port->dev; + if (dev) { + dev->handle_packet(dev, + USB_MSG_RESET, 0, 0, NULL, 0); + } + } + uhci_reset(s); + return; + } + if (val & UHCI_CMD_GRESET) { + uhci_reset(s); + return; + } + s->cmd = val; + break; + case 0x02: + s->status &= ~val; + /* XXX: the chip spec is not coherent, so we add a hidden + register to distinguish between IOC and SPD */ + if (val & UHCI_STS_USBINT) + s->status2 = 0; + uhci_update_irq(s); + break; + case 0x04: + s->intr = val; + uhci_update_irq(s); + break; + case 0x06: + if (s->status & UHCI_STS_HCHALTED) + s->frnum = val & 0x7ff; + break; + case 0x10 ... 0x1f: + { + UHCIPort *port; + USBDevice *dev; + int n; + + n = (addr >> 1) & 7; + if (n >= NB_PORTS) + return; + port = &s->ports[n]; + dev = port->dev; + if (dev) { + /* port reset */ + if ( (val & UHCI_PORT_RESET) && + !(port->ctrl & UHCI_PORT_RESET) ) { + dev->handle_packet(dev, + USB_MSG_RESET, 0, 0, NULL, 0); + } + } + port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb); + /* some bits are reset when a '1' is written to them */ + port->ctrl &= ~(val & 0x000a); + } + break; + } +} + +static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) +{ + UHCIState *s = opaque; + uint32_t val; + + addr &= 0x1f; + switch(addr) { + case 0x00: + val = s->cmd; + break; + case 0x02: + val = s->status; + break; + case 0x04: + val = s->intr; + break; + case 0x06: + val = s->frnum; + break; + case 0x10 ... 0x1f: + { + UHCIPort *port; + int n; + n = (addr >> 1) & 7; + if (n >= NB_PORTS) + goto read_default; + port = &s->ports[n]; + val = port->ctrl; + } + break; + default: + read_default: + val = 0xff7f; /* disabled port */ + break; + } +#ifdef DEBUG + printf("uhci readw port=0x%04x val=0x%04x\n", addr, val); +#endif + return val; +} + +static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +{ + UHCIState *s = opaque; + + addr &= 0x1f; +#ifdef DEBUG + printf("uhci writel port=0x%04x val=0x%08x\n", addr, val); +#endif + switch(addr) { + case 0x08: + s->fl_base_addr = val & ~0xfff; + break; + } +} + +static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr) +{ + UHCIState *s = opaque; + uint32_t val; + + addr &= 0x1f; + switch(addr) { + case 0x08: + val = s->fl_base_addr; + break; + default: + val = 0xffffffff; + break; + } + return val; +} + +static void uhci_attach(USBPort *port1, USBDevice *dev) +{ + UHCIState *s = port1->opaque; + UHCIPort *port = &s->ports[port1->index]; + + if (dev) { + if (port->dev) { + usb_attach(port1, NULL); + } + /* set connect status */ + if (!(port->ctrl & UHCI_PORT_CCS)) { + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + } + /* update speed */ + if (dev->speed == USB_SPEED_LOW) + port->ctrl |= UHCI_PORT_LSDA; + else + port->ctrl &= ~UHCI_PORT_LSDA; + port->dev = dev; + /* send the attach message */ + dev->handle_packet(dev, + USB_MSG_ATTACH, 0, 0, NULL, 0); + } else { + /* set connect status */ + if (!(port->ctrl & UHCI_PORT_CCS)) { + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + } + /* disable port */ + if (port->ctrl & UHCI_PORT_EN) { + port->ctrl &= ~UHCI_PORT_EN; + port->ctrl |= UHCI_PORT_ENC; + } + dev = port->dev; + if (dev) { + /* send the detach message */ + dev->handle_packet(dev, + USB_MSG_DETACH, 0, 0, NULL, 0); + } + port->dev = NULL; + } +} + +static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + UHCIPort *port; + USBDevice *dev; + int i, ret; + +#ifdef DEBUG_PACKET + { + const char *pidstr; + switch(pid) { + case USB_TOKEN_SETUP: pidstr = "SETUP"; break; + case USB_TOKEN_IN: pidstr = "IN"; break; + case USB_TOKEN_OUT: pidstr = "OUT"; break; + default: pidstr = "?"; break; + } + printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n", + s->frnum, pidstr, devaddr, devep, len); + if (pid != USB_TOKEN_IN) { + printf(" data_out="); + for(i = 0; i < len; i++) { + printf(" %02x", data[i]); + } + printf("\n"); + } + } +#endif + for(i = 0; i < NB_PORTS; i++) { + port = &s->ports[i]; + dev = port->dev; + if (dev && (port->ctrl & UHCI_PORT_EN)) { + ret = dev->handle_packet(dev, pid, + devaddr, devep, + data, len); + if (ret != USB_RET_NODEV) { +#ifdef DEBUG_PACKET + { + printf(" ret=%d ", ret); + if (pid == USB_TOKEN_IN && ret > 0) { + printf("data_in="); + for(i = 0; i < ret; i++) { + printf(" %02x", data[i]); + } + } + printf("\n"); + } +#endif + return ret; + } + } + } + return USB_RET_NODEV; +} + +/* return -1 if fatal error (frame must be stopped) + 0 if TD successful + 1 if TD unsuccessful or inactive +*/ +static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) +{ + uint8_t pid; + uint8_t buf[1280]; + int len, max_len, err, ret; + + if (td->ctrl & TD_CTRL_IOC) { + *int_mask |= 0x01; + } + + if (!(td->ctrl & TD_CTRL_ACTIVE)) + return 1; + + /* TD is active */ + max_len = ((td->token >> 21) + 1) & 0x7ff; + pid = td->token & 0xff; + switch(pid) { + case USB_TOKEN_OUT: + case USB_TOKEN_SETUP: + cpu_physical_memory_read(td->buffer, buf, max_len); + ret = uhci_broadcast_packet(s, pid, + (td->token >> 8) & 0x7f, + (td->token >> 15) & 0xf, + buf, max_len); + len = max_len; + break; + case USB_TOKEN_IN: + ret = uhci_broadcast_packet(s, pid, + (td->token >> 8) & 0x7f, + (td->token >> 15) & 0xf, + buf, max_len); + if (ret >= 0) { + len = ret; + if (len > max_len) { + len = max_len; + ret = USB_RET_BABBLE; + } + if (len > 0) { + /* write the data back */ + cpu_physical_memory_write(td->buffer, buf, len); + } + } else { + len = 0; + } + break; + default: + /* invalid pid : frame interrupted */ + s->status |= UHCI_STS_HCPERR; + uhci_update_irq(s); + return -1; + } + if (td->ctrl & TD_CTRL_IOS) + td->ctrl &= ~TD_CTRL_ACTIVE; + if (ret >= 0) { + td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); + td->ctrl &= ~TD_CTRL_ACTIVE; + if (pid == USB_TOKEN_IN && + (td->ctrl & TD_CTRL_SPD) && + len < max_len) { + *int_mask |= 0x02; + /* short packet: do not update QH */ + return 1; + } else { + /* success */ + return 0; + } + } else { + switch(ret) { + default: + case USB_RET_NODEV: + do_timeout: + td->ctrl |= TD_CTRL_TIMEOUT; + err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3; + if (err != 0) { + err--; + if (err == 0) { + td->ctrl &= ~TD_CTRL_ACTIVE; + s->status |= UHCI_STS_USBERR; + uhci_update_irq(s); + } + } + td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | + (err << TD_CTRL_ERROR_SHIFT); + return 1; + case USB_RET_NAK: + td->ctrl |= TD_CTRL_NAK; + if (pid == USB_TOKEN_SETUP) + goto do_timeout; + return 1; + case USB_RET_STALL: + td->ctrl |= TD_CTRL_STALL; + td->ctrl &= ~TD_CTRL_ACTIVE; + return 1; + case USB_RET_BABBLE: + td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; + td->ctrl &= ~TD_CTRL_ACTIVE; + /* frame interrupted */ + return -1; + } + } +} + +static void uhci_frame_timer(void *opaque) +{ + UHCIState *s = opaque; + int64_t expire_time; + uint32_t frame_addr, link, old_td_ctrl, val; + int int_mask, cnt, ret; + UHCI_TD td; + UHCI_QH qh; + + if (!(s->cmd & UHCI_CMD_RS)) { + qemu_del_timer(s->frame_timer); + return; + } + frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); + cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); + le32_to_cpus(&link); + int_mask = 0; + cnt = FRAME_MAX_LOOPS; + while ((link & 1) == 0) { + if (--cnt == 0) + break; + /* valid frame */ + if (link & 2) { + /* QH */ + cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); + le32_to_cpus(&qh.link); + le32_to_cpus(&qh.el_link); + depth_first: + if (qh.el_link & 1) { + /* no element : go to next entry */ + link = qh.link; + } else if (qh.el_link & 2) { + /* QH */ + link = qh.el_link; + } else { + /* TD */ + if (--cnt == 0) + break; + cpu_physical_memory_read(qh.el_link & ~0xf, + (uint8_t *)&td, sizeof(td)); + le32_to_cpus(&td.link); + le32_to_cpus(&td.ctrl); + le32_to_cpus(&td.token); + le32_to_cpus(&td.buffer); + old_td_ctrl = td.ctrl; + ret = uhci_handle_td(s, &td, &int_mask); + /* update the status bits of the TD */ + if (old_td_ctrl != td.ctrl) { + val = cpu_to_le32(td.ctrl); + cpu_physical_memory_write((qh.el_link & ~0xf) + 4, + (const uint8_t *)&val, + sizeof(val)); + } + if (ret < 0) + break; /* interrupted frame */ + if (ret == 0) { + /* update qh element link */ + qh.el_link = td.link; + val = cpu_to_le32(qh.el_link); + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, + sizeof(val)); + if (qh.el_link & 4) { + /* depth first */ + goto depth_first; + } + } + /* go to next entry */ + link = qh.link; + } + } else { + /* TD */ + cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td)); + le32_to_cpus(&td.link); + le32_to_cpus(&td.ctrl); + le32_to_cpus(&td.token); + le32_to_cpus(&td.buffer); + old_td_ctrl = td.ctrl; + ret = uhci_handle_td(s, &td, &int_mask); + /* update the status bits of the TD */ + if (old_td_ctrl != td.ctrl) { + val = cpu_to_le32(td.ctrl); + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, + sizeof(val)); + } + if (ret < 0) + break; /* interrupted frame */ + link = td.link; + } + } + s->frnum = (s->frnum + 1) & 0x7ff; + if (int_mask) { + s->status2 |= int_mask; + s->status |= UHCI_STS_USBINT; + uhci_update_irq(s); + } + /* prepare the timer for the next frame */ + expire_time = qemu_get_clock(vm_clock) + + (ticks_per_sec / FRAME_TIMER_FREQ); + qemu_mod_timer(s->frame_timer, expire_time); +} + +static void uhci_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + UHCIState *s = (UHCIState *)pci_dev; + + register_ioport_write(addr, 32, 2, uhci_ioport_writew, s); + register_ioport_read(addr, 32, 2, uhci_ioport_readw, s); + register_ioport_write(addr, 32, 4, uhci_ioport_writel, s); + register_ioport_read(addr, 32, 4, uhci_ioport_readl, s); + register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s); + register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); +} + +void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) +{ + UHCIState *s; + uint8_t *pci_conf; + UHCIPort *port; + int i; + + s = (UHCIState *)pci_register_device(bus, + "USB-UHCI", sizeof(UHCIState), + -1, + NULL, NULL); + pci_conf = s->dev.config; + pci_conf[0x00] = 0x86; + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x20; + pci_conf[0x03] = 0x70; + pci_conf[0x08] = 0x01; // revision number + pci_conf[0x09] = 0x00; + pci_conf[0x0a] = 0x03; + pci_conf[0x0b] = 0x0c; + pci_conf[0x0e] = 0x00; // header_type + pci_conf[0x3d] = 1; // interrupt pin 0 + + for(i = 0; i < NB_PORTS; i++) { + port = &s->ports[i]; + port->port.opaque = s; + port->port.index = i; + port->port.attach = uhci_attach; + usb_ports[i] = &port->port; + } + s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); + + uhci_reset(s); + + pci_register_io_region(&s->dev, 0, 0x20, + PCI_ADDRESS_SPACE_IO, uhci_map); +} diff --git a/hw/usb.c b/hw/usb.c new file mode 100644 index 000000000..cfbdb15d1 --- /dev/null +++ b/hw/usb.c @@ -0,0 +1,694 @@ +/* + * QEMU USB emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +void usb_attach(USBPort *port, USBDevice *dev) +{ + port->attach(port, dev); +} + +/**********************/ +/* generic USB device helpers (you are not forced to use them when + writing your USB device driver, but they help handling the + protocol) +*/ + +#define SETUP_STATE_IDLE 0 +#define SETUP_STATE_DATA 1 +#define SETUP_STATE_ACK 2 + +int usb_generic_handle_packet(USBDevice *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + int l, ret = 0; + + switch(pid) { + case USB_MSG_ATTACH: + s->state = USB_STATE_ATTACHED; + break; + case USB_MSG_DETACH: + s->state = USB_STATE_NOTATTACHED; + break; + case USB_MSG_RESET: + s->remote_wakeup = 0; + s->addr = 0; + s->state = USB_STATE_DEFAULT; + s->handle_reset(s); + break; + case USB_TOKEN_SETUP: + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + return USB_RET_NODEV; + if (len != 8) + goto fail; + memcpy(s->setup_buf, data, 8); + s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; + s->setup_index = 0; + if (s->setup_buf[0] & USB_DIR_IN) { + ret = s->handle_control(s, + (s->setup_buf[0] << 8) | s->setup_buf[1], + (s->setup_buf[3] << 8) | s->setup_buf[2], + (s->setup_buf[5] << 8) | s->setup_buf[4], + s->setup_len, + s->data_buf); + if (ret < 0) + return ret; + if (ret < s->setup_len) + s->setup_len = ret; + s->setup_state = SETUP_STATE_DATA; + } else { + if (s->setup_len == 0) + s->setup_state = SETUP_STATE_ACK; + else + s->setup_state = SETUP_STATE_DATA; + } + break; + case USB_TOKEN_IN: + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + return USB_RET_NODEV; + switch(devep) { + case 0: + switch(s->setup_state) { + case SETUP_STATE_ACK: + s->setup_state = SETUP_STATE_IDLE; + if (!(s->setup_buf[0] & USB_DIR_IN)) { + ret = s->handle_control(s, + (s->setup_buf[0] << 8) | s->setup_buf[1], + (s->setup_buf[3] << 8) | s->setup_buf[2], + (s->setup_buf[5] << 8) | s->setup_buf[4], + s->setup_len, + s->data_buf); + if (ret > 0) + ret = 0; + } else { + goto fail; + } + break; + case SETUP_STATE_DATA: + if (s->setup_buf[0] & USB_DIR_IN) { + l = s->setup_len - s->setup_index; + if (l > len) + l = len; + memcpy(data, s->data_buf + s->setup_index, l); + s->setup_index += l; + if (s->setup_index >= s->setup_len) + s->setup_state = SETUP_STATE_ACK; + ret = l; + } else { + s->setup_state = SETUP_STATE_IDLE; + goto fail; + } + break; + default: + goto fail; + } + break; + default: + ret = s->handle_data(s, pid, devep, data, len); + break; + } + break; + case USB_TOKEN_OUT: + if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + return USB_RET_NODEV; + switch(devep) { + case 0: + switch(s->setup_state) { + case SETUP_STATE_ACK: + s->setup_state = SETUP_STATE_IDLE; + if (s->setup_buf[0] & USB_DIR_IN) { + /* transfer OK */ + } else { + goto fail; + } + break; + case SETUP_STATE_DATA: + if (!(s->setup_buf[0] & USB_DIR_IN)) { + l = s->setup_len - s->setup_index; + if (l > len) + l = len; + memcpy(s->data_buf + s->setup_index, data, l); + s->setup_index += l; + if (s->setup_index >= s->setup_len) + s->setup_state = SETUP_STATE_ACK; + ret = l; + } else { + s->setup_state = SETUP_STATE_IDLE; + goto fail; + } + break; + default: + goto fail; + } + break; + default: + ret = s->handle_data(s, pid, devep, data, len); + break; + } + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +/* XXX: fix overflow */ +int set_usb_string(uint8_t *buf, const char *str) +{ + int len, i; + uint8_t *q; + + q = buf; + len = strlen(str); + *q++ = 2 * len + 1; + *q++ = 3; + for(i = 0; i < len; i++) { + *q++ = str[i]; + *q++ = 0; + } + return q - buf; +} + +/**********************/ +/* USB hub emulation */ + +//#define DEBUG + +#define MAX_PORTS 8 + +#define DS_IDLE 0 +#define DS_CONTROL_IN 1 +#define DS_CONTROL_OUT 2 + +typedef struct USBHubPort { + USBPort port; + USBDevice *dev; + uint16_t wPortStatus; + uint16_t wPortChange; +} USBHubPort; + +typedef struct USBHubState { + USBDevice dev; + int nb_ports; + USBHubPort ports[MAX_PORTS]; +} USBHubState; + +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) + +#define PORT_STAT_CONNECTION 0x0001 +#define PORT_STAT_ENABLE 0x0002 +#define PORT_STAT_SUSPEND 0x0004 +#define PORT_STAT_OVERCURRENT 0x0008 +#define PORT_STAT_RESET 0x0010 +#define PORT_STAT_POWER 0x0100 +#define PORT_STAT_LOW_SPEED 0x0200 +#define PORT_STAT_HIGH_SPEED 0x0400 +#define PORT_STAT_TEST 0x0800 +#define PORT_STAT_INDICATOR 0x1000 + +#define PORT_STAT_C_CONNECTION 0x0001 +#define PORT_STAT_C_ENABLE 0x0002 +#define PORT_STAT_C_SUSPEND 0x0004 +#define PORT_STAT_C_OVERCURRENT 0x0008 +#define PORT_STAT_C_RESET 0x0010 + +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVERCURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOWSPEED 9 +#define PORT_HIGHSPEED 10 +#define PORT_C_CONNECTION 16 +#define PORT_C_ENABLE 17 +#define PORT_C_SUSPEND 18 +#define PORT_C_OVERCURRENT 19 +#define PORT_C_RESET 20 +#define PORT_TEST 21 +#define PORT_INDICATOR 22 + +/* same as Linux kernel root hubs */ + +static const uint8_t qemu_hub_dev_descriptor[] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ + + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* __u16 idVendor; */ + 0x00, 0x00, /* __u16 idProduct; */ + 0x01, 0x01, /* __u16 bcdDevice */ + + 0x03, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* XXX: patch interrupt size */ +static const uint8_t qemu_hub_config_descriptor[] = { + + /* one configuration */ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* __u16 wTotalLength; */ + 0x01, /* __u8 bNumInterfaces; (1) */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0xc0, /* __u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* __u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_hub_hub_descriptor[] = +{ + 0x09, /* __u8 bLength; */ + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ + 0x00, /* __u8 bNbrPorts; (patched later) */ + 0x0a, /* __u16 wHubCharacteristics; */ + 0x00, /* (per-port OC, no power switching) */ + 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* __u8 bHubContrCurrent; 0 mA */ + 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ +}; + +static void usb_hub_attach(USBPort *port1, USBDevice *dev) +{ + USBHubState *s = port1->opaque; + USBHubPort *port = &s->ports[port1->index]; + + if (dev) { + if (port->dev) + usb_attach(port1, NULL); + + port->wPortStatus |= PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (dev->speed == USB_SPEED_LOW) + port->wPortStatus |= PORT_STAT_LOW_SPEED; + else + port->wPortStatus &= ~PORT_STAT_LOW_SPEED; + port->dev = dev; + } else { + dev = port->dev; + if (dev) { + port->wPortStatus &= ~PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (port->wPortStatus & PORT_STAT_ENABLE) { + port->wPortStatus &= ~PORT_STAT_ENABLE; + port->wPortChange |= PORT_STAT_C_ENABLE; + } + port->dev = NULL; + } + } +} + +static void usb_hub_handle_reset(USBDevice *dev) +{ + /* XXX: do it */ +} + +static int usb_hub_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBHubState *s = (USBHubState *)dev; + int ret; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_hub_dev_descriptor, + sizeof(qemu_hub_dev_descriptor)); + ret = sizeof(qemu_hub_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_hub_config_descriptor, + sizeof(qemu_hub_config_descriptor)); + ret = sizeof(qemu_hub_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "314159"); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "QEMU USB Hub"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "QEMU " QEMU_VERSION); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* usb specific requests */ + case GetHubStatus: + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + ret = 4; + break; + case GetPortStatus: + { + unsigned int n = index - 1; + USBHubPort *port; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + data[0] = port->wPortStatus; + data[1] = port->wPortStatus >> 8; + data[2] = port->wPortChange; + data[3] = port->wPortChange >> 8; + ret = 4; + } + break; + case SetHubFeature: + case ClearHubFeature: + if (value == 0 || value == 1) { + } else { + goto fail; + } + ret = 0; + break; + case SetPortFeature: + { + unsigned int n = index - 1; + USBHubPort *port; + USBDevice *dev; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + dev = port->dev; + switch(value) { + case PORT_SUSPEND: + port->wPortStatus |= PORT_STAT_SUSPEND; + break; + case PORT_RESET: + if (dev) { + dev->handle_packet(dev, + USB_MSG_RESET, 0, 0, NULL, 0); + port->wPortChange |= PORT_STAT_C_RESET; + /* set enable bit */ + port->wPortChange |= PORT_STAT_C_ENABLE; + port->wPortStatus |= PORT_STAT_ENABLE; + } + break; + case PORT_POWER: + break; + default: + goto fail; + } + ret = 0; + } + break; + case ClearPortFeature: + { + unsigned int n = index - 1; + USBHubPort *port; + USBDevice *dev; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + dev = port->dev; + switch(value) { + case PORT_ENABLE: + port->wPortStatus &= ~PORT_STAT_ENABLE; + break; + case PORT_C_ENABLE: + port->wPortChange &= ~PORT_STAT_C_ENABLE; + break; + case PORT_SUSPEND: + port->wPortStatus &= ~PORT_STAT_SUSPEND; + break; + case PORT_C_SUSPEND: + port->wPortChange &= ~PORT_STAT_C_SUSPEND; + break; + case PORT_C_CONNECTION: + port->wPortChange &= ~PORT_STAT_C_CONNECTION; + break; + case PORT_C_OVERCURRENT: + port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; + break; + case PORT_C_RESET: + port->wPortChange &= ~PORT_STAT_C_RESET; + break; + default: + goto fail; + } + ret = 0; + } + break; + case GetHubDescriptor: + memcpy(data, qemu_hub_hub_descriptor, + sizeof(qemu_hub_hub_descriptor)); + data[2] = s->nb_ports; + ret = sizeof(qemu_hub_hub_descriptor); + break; + default: + fail: + ret = USB_RET_STALL; + } + return ret; +} + +static int usb_hub_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + USBHubState *s = (USBHubState *)dev; + int ret; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + USBHubPort *port; + unsigned int status; + int i, n; + n = (s->nb_ports + 1 + 7) / 8; + if (n > len) + return USB_RET_BABBLE; + status = 0; + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + if (port->wPortChange) + status |= (1 << (i + 1)); + } + if (status != 0) { + for(i = 0; i < n; i++) { + data[i] = status >> (8 * i); + } + ret = n; + } else { + ret = 0; + } + } else { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_hub_broadcast_packet(USBHubState *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + USBHubPort *port; + USBDevice *dev; + int i, ret; + + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + dev = port->dev; + if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { + ret = dev->handle_packet(dev, pid, + devaddr, devep, + data, len); + if (ret != USB_RET_NODEV) { + return ret; + } + } + } + return USB_RET_NODEV; +} + +static int usb_hub_handle_packet(USBDevice *dev, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + USBHubState *s = (USBHubState *)dev; + +#if defined(DEBUG) && 0 + printf("usb_hub: pid=0x%x\n", pid); +#endif + if (dev->state == USB_STATE_DEFAULT && + dev->addr != 0 && + devaddr != dev->addr && + (pid == USB_TOKEN_SETUP || + pid == USB_TOKEN_OUT || + pid == USB_TOKEN_IN)) { + /* broadcast the packet to the devices */ + return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); + } + return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); +} + +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) +{ + USBHubState *s; + USBHubPort *port; + int i; + + if (nb_ports > MAX_PORTS) + return NULL; + s = qemu_mallocz(sizeof(USBHubState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_hub_handle_packet; + + /* generic USB device init */ + s->dev.handle_reset = usb_hub_handle_reset; + s->dev.handle_control = usb_hub_handle_control; + s->dev.handle_data = usb_hub_handle_data; + + s->nb_ports = nb_ports; + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + port->wPortStatus = PORT_STAT_POWER; + port->wPortChange = 0; + port->port.attach = usb_hub_attach; + port->port.opaque = s; + port->port.index = i; + usb_ports[i] = &port->port; + } + return (USBDevice *)s; +} diff --git a/hw/usb.h b/hw/usb.h new file mode 100644 index 000000000..1bfce3b51 --- /dev/null +++ b/hw/usb.h @@ -0,0 +1,139 @@ +/* + * QEMU USB API + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define USB_TOKEN_SETUP 0x2d +#define USB_TOKEN_IN 0x69 /* device -> host */ +#define USB_TOKEN_OUT 0xe1 /* host -> device */ + +/* specific usb messages, also sent in the 'pid' parameter */ +#define USB_MSG_ATTACH 0x100 +#define USB_MSG_DETACH 0x101 +#define USB_MSG_RESET 0x102 + +#define USB_RET_NODEV (-1) +#define USB_RET_NAK (-2) +#define USB_RET_STALL (-3) +#define USB_RET_BABBLE (-4) + +#define USB_SPEED_LOW 0 +#define USB_SPEED_FULL 1 +#define USB_SPEED_HIGH 2 + +#define USB_STATE_NOTATTACHED 0 +#define USB_STATE_ATTACHED 1 +//#define USB_STATE_POWERED 2 +#define USB_STATE_DEFAULT 3 +//#define USB_STATE_ADDRESS 4 +//#define USB_STATE_CONFIGURED 5 +#define USB_STATE_SUSPENDED 6 + +#define USB_DIR_OUT 0 +#define USB_DIR_IN 0x80 + +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) +#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_DEVICE_SELF_POWERED 0 +#define USB_DEVICE_REMOTE_WAKEUP 1 + +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 + +typedef struct USBPort USBPort; +typedef struct USBDevice USBDevice; + +/* definition of a USB device */ +struct USBDevice { + void *opaque; + int (*handle_packet)(USBDevice *dev, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len); + int speed; + + /* The following fields are used by the generic USB device + layer. They are here just to avoid creating a new structure for + them. */ + void (*handle_reset)(USBDevice *dev); + int (*handle_control)(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data); + int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, + uint8_t *data, int len); + uint8_t addr; + + int state; + uint8_t setup_buf[8]; + uint8_t data_buf[1024]; + int remote_wakeup; + int setup_state; + int setup_len; + int setup_index; +}; + +/* USB port on which a device can be connected */ +struct USBPort { + void (*attach)(USBPort *port, USBDevice *dev); + void *opaque; + int index; /* internal port index, may be used with the opaque */ +}; + +void usb_attach(USBPort *port, USBDevice *dev); +int usb_generic_handle_packet(USBDevice *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len); +int set_usb_string(uint8_t *buf, const char *str); + +/* usb hub */ +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports); + +/* usb-uhci.c */ +void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); + +/* usb-linux.c */ +USBDevice *usb_host_hub_init(void); diff --git a/usb-linux.c b/usb-linux.c new file mode 100644 index 000000000..87f3d120b --- /dev/null +++ b/usb-linux.c @@ -0,0 +1,309 @@ +/* + * Linux host USB redirector + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#if defined(__linux__) +#include +#include +#include +#include + +/* We redefine it to avoid version problems */ +struct usb_ctrltransfer { + uint8_t bRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + uint32_t timeout; + void *data; +}; + +//#define DEBUG + +#define MAX_DEVICES 8 + +#define USBDEVFS_PATH "/proc/bus/usb" + +typedef struct USBHostDevice { + USBDevice dev; + int fd; +} USBHostDevice; + +typedef struct USBHostHubState { + USBDevice *hub_dev; + USBPort *hub_ports[MAX_DEVICES]; + USBDevice *hub_devices[MAX_DEVICES]; +} USBHostHubState; + +static void usb_host_handle_reset(USBDevice *dev) +{ +#if 0 + USBHostDevice *s = (USBHostDevice *)dev; + /* USBDEVFS_RESET, but not the first time as it has already be + done by the host OS */ + ioctl(s->fd, USBDEVFS_RESET); +#endif +} + +static int usb_host_handle_control(USBDevice *dev, + int request, + int value, + int index, + int length, + uint8_t *data) +{ + USBHostDevice *s = (USBHostDevice *)dev; + struct usb_ctrltransfer ct; + int ret; + + if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) { + /* specific SET_ADDRESS support */ + dev->addr = value; + return 0; + } else { + ct.bRequestType = request >> 8; + ct.bRequest = request; + ct.wValue = value; + ct.wIndex = index; + ct.wLength = length; + ct.timeout = 50; + ct.data = data; + ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct); + if (ret < 0) { + switch(errno) { + case ETIMEDOUT: + return USB_RET_NAK; + default: + return USB_RET_STALL; + } + } else { + return ret; + } + } +} + +static int usb_host_handle_data(USBDevice *dev, int pid, + uint8_t devep, + uint8_t *data, int len) +{ + USBHostDevice *s = (USBHostDevice *)dev; + struct usbdevfs_bulktransfer bt; + int ret; + + /* XXX: optimize and handle all data types by looking at the + config descriptor */ + if (pid == USB_TOKEN_IN) + devep |= 0x80; + bt.ep = devep; + bt.len = len; + bt.timeout = 50; + bt.data = data; + ret = ioctl(s->fd, USBDEVFS_BULK, &bt); + if (ret < 0) { + switch(errno) { + case ETIMEDOUT: + return USB_RET_NAK; + case EPIPE: + default: +#ifdef DEBUG + printf("handle_data: errno=%d\n", errno); +#endif + return USB_RET_STALL; + } + } else { + return ret; + } +} + +static int usb_host_handle_packet(USBDevice *dev, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); +} + +/* XXX: exclude high speed devices or implement EHCI */ +static void scan_host_device(USBHostHubState *s, const char *filename) +{ + int fd, interface, ret, i; + USBHostDevice *dev; + struct usbdevfs_connectinfo ci; + uint8_t descr[1024]; + int descr_len, dev_descr_len, config_descr_len, nb_interfaces; + +#ifdef DEBUG + printf("scanning %s\n", filename); +#endif + fd = open(filename, O_RDWR); + if (fd < 0) { + perror(filename); + return; + } + + /* read the config description */ + descr_len = read(fd, descr, sizeof(descr)); + if (descr_len <= 0) { + perror("read descr"); + goto fail; + } + + i = 0; + dev_descr_len = descr[0]; + if (dev_descr_len > descr_len) + goto fail; + i += dev_descr_len; + config_descr_len = descr[i]; + if (i + config_descr_len > descr_len) + goto fail; + nb_interfaces = descr[i + 4]; + if (nb_interfaces != 1) { + /* NOTE: currently we grab only one interface */ + goto fail; + } + /* XXX: only grab if all interfaces are free */ + interface = 0; + ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface); + if (ret < 0) { + if (errno == EBUSY) { +#ifdef DEBUG + printf("%s already grabbed\n", filename); +#endif + } else { + perror("USBDEVFS_CLAIMINTERFACE"); + } + fail: + close(fd); + return; + } + + ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); + if (ret < 0) { + perror("USBDEVFS_CONNECTINFO"); + goto fail; + } + +#ifdef DEBUG + printf("%s grabbed\n", filename); +#endif + + /* find a free slot */ + for(i = 0; i < MAX_DEVICES; i++) { + if (!s->hub_devices[i]) + break; + } + if (i == MAX_DEVICES) { +#ifdef DEBUG + printf("too many host devices\n"); + goto fail; +#endif + } + + dev = qemu_mallocz(sizeof(USBHostDevice)); + if (!dev) + goto fail; + dev->fd = fd; + if (ci.slow) + dev->dev.speed = USB_SPEED_LOW; + else + dev->dev.speed = USB_SPEED_HIGH; + dev->dev.handle_packet = usb_host_handle_packet; + + dev->dev.handle_reset = usb_host_handle_reset; + dev->dev.handle_control = usb_host_handle_control; + dev->dev.handle_data = usb_host_handle_data; + + s->hub_devices[i] = (USBDevice *)dev; + + /* activate device on hub */ + usb_attach(s->hub_ports[i], s->hub_devices[i]); +} + +static void scan_host_devices(USBHostHubState *s, const char *bus_path) +{ + DIR *d; + struct dirent *de; + char buf[1024]; + + d = opendir(bus_path); + if (!d) + return; + for(;;) { + de = readdir(d); + if (!de) + break; + if (de->d_name[0] != '.') { + snprintf(buf, sizeof(buf), "%s/%s", bus_path, de->d_name); + scan_host_device(s, buf); + } + } + closedir(d); +} + +static void scan_host_buses(USBHostHubState *s) +{ + DIR *d; + struct dirent *de; + char buf[1024]; + + d = opendir(USBDEVFS_PATH); + if (!d) + return; + for(;;) { + de = readdir(d); + if (!de) + break; + if (isdigit(de->d_name[0])) { + snprintf(buf, sizeof(buf), "%s/%s", USBDEVFS_PATH, de->d_name); + scan_host_devices(s, buf); + } + } + closedir(d); +} + +/* virtual hub containing the USB devices of the host */ +USBDevice *usb_host_hub_init(void) +{ + USBHostHubState *s; + s = qemu_mallocz(sizeof(USBHostHubState)); + if (!s) + return NULL; + s->hub_dev = usb_hub_init(s->hub_ports, MAX_DEVICES); + if (!s->hub_dev) { + free(s); + return NULL; + } + scan_host_buses(s); + return s->hub_dev; +} + +#else + +/* XXX: modify configure to compile the right host driver */ +USBDevice *usb_host_hub_init(void) +{ + return NULL; +} + +#endif diff --git a/vl.c b/vl.c index 1ca0c347a..d551a4e55 100644 --- a/vl.c +++ b/vl.c @@ -153,6 +153,7 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; #ifdef TARGET_I386 int win2k_install_hack = 0; #endif +int usb_enabled = 0; /***********************************************************/ /* x86 ISA bus support */ @@ -2986,6 +2987,7 @@ enum { QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, QEMU_OPTION_win2k_hack, + QEMU_OPTION_usb, }; typedef struct QEMUOption { @@ -3060,6 +3062,7 @@ const QEMUOption qemu_options[] = { { "full-screen", 0, QEMU_OPTION_full_screen }, { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, + { "usb", 0, QEMU_OPTION_usb }, /* temporary options */ { "pci", 0, QEMU_OPTION_pci }, @@ -3646,6 +3649,9 @@ int main(int argc, char **argv) kqemu_allowed = 0; break; #endif + case QEMU_OPTION_usb: + usb_enabled = 1; + break; } } } diff --git a/vl.h b/vl.h index 543d57972..e1a2ec3f1 100644 --- a/vl.h +++ b/vl.h @@ -135,6 +135,7 @@ extern int graphic_depth; extern const char *keyboard_layout; extern int kqemu_allowed; extern int win2k_install_hack; +extern int usb_enabled; /* XXX: make it dynamic */ #if defined (TARGET_PPC) @@ -859,6 +860,8 @@ void adb_mouse_init(ADBBusState *bus); extern ADBBusState adb_bus; int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); +#include "hw/usb.h" + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From 92414fdca00c1746b950a45f4bc76796239d18aa Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Nov 2005 16:55:48 +0000 Subject: cosmetics git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1598 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb.c | 101 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/hw/usb.c b/hw/usb.c index cfbdb15d1..0728db29f 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -199,10 +199,6 @@ int set_usb_string(uint8_t *buf, const char *str) #define MAX_PORTS 8 -#define DS_IDLE 0 -#define DS_CONTROL_IN 1 -#define DS_CONTROL_OUT 2 - typedef struct USBHubPort { USBPort port; USBDevice *dev; @@ -260,41 +256,41 @@ typedef struct USBHubState { /* same as Linux kernel root hubs */ static const uint8_t qemu_hub_dev_descriptor[] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ - - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* __u16 idVendor; */ - 0x00, 0x00, /* __u16 idProduct; */ - 0x01, 0x01, /* __u16 bcdDevice */ - - 0x03, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x01, /* u16 bcdUSB; v1.1 */ + + 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* u16 idVendor; */ + 0x00, 0x00, /* u16 idProduct; */ + 0x01, 0x01, /* u16 bcdDevice */ + + 0x03, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x01, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ }; /* XXX: patch interrupt size */ static const uint8_t qemu_hub_config_descriptor[] = { /* one configuration */ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __u16 wTotalLength; */ - 0x01, /* __u8 bNumInterfaces; (1) */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0xc0, /* __u8 bmAttributes; + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xc0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ + 0x00, /* u8 MaxPower; */ /* USB 1.1: * USB 2.0, single TT organization (mandatory): @@ -308,36 +304,36 @@ static const uint8_t qemu_hub_config_descriptor[] = { */ /* one interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* __u8 if_iInterface; */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* u8 if_bInterfaceSubClass; */ + 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* u8 if_iInterface; */ /* one endpoint (status change endpoint) */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; static const uint8_t qemu_hub_hub_descriptor[] = { - 0x09, /* __u8 bLength; */ - 0x29, /* __u8 bDescriptorType; Hub-descriptor */ - 0x00, /* __u8 bNbrPorts; (patched later) */ - 0x0a, /* __u16 wHubCharacteristics; */ + 0x09, /* u8 bLength; */ + 0x29, /* u8 bDescriptorType; Hub-descriptor */ + 0x00, /* u8 bNbrPorts; (patched later) */ + 0x0a, /* u16 wHubCharacteristics; */ 0x00, /* (per-port OC, no power switching) */ - 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ - 0x00, /* __u8 bHubContrCurrent; 0 mA */ - 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ - 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ + 0x01, /* u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* u8 bHubContrCurrent; 0 mA */ + 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */ }; static void usb_hub_attach(USBPort *port1, USBDevice *dev) @@ -571,6 +567,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, default: fail: ret = USB_RET_STALL; + break; } return ret; } -- cgit v1.2.3 From 59ae540c3dbd1ab3fb004e85eaf3aa4f3520a308 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Nov 2005 16:57:08 +0000 Subject: added virtual USB mouse support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1599 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +- hw/pc.c | 21 ++-- hw/usb-hid.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb.h | 10 ++ 4 files changed, 373 insertions(+), 8 deletions(-) create mode 100644 hw/usb-hid.c diff --git a/Makefile.target b/Makefile.target index 56b7036a5..cefad7403 100644 --- a/Makefile.target +++ b/Makefile.target @@ -294,7 +294,8 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o -VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o usb.o usb-uhci.o usb-linux.o +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o +VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff --git a/hw/pc.c b/hw/pc.c index cd28998e1..90a0e48fa 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -622,24 +622,31 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled && usb_enabled) { USBPort *usb_root_ports[2]; - USBDevice *usb_hub; + USBDevice *usb_dev; usb_uhci_init(pci_bus, usb_root_ports); #if 0 { USBPort *usb_hub1_ports[4]; USBPort *usb_hub2_ports[2]; /* test: we simulate a USB hub */ - usb_hub = usb_hub_init(usb_hub1_ports, 4); - usb_attach(usb_root_ports[0], usb_hub); + usb_dev = usb_hub_init(usb_hub1_ports, 4); + usb_attach(usb_root_ports[0], usb_dev); /* test: we simulate a USB hub */ - usb_hub = usb_hub_init(usb_hub2_ports, 2); - usb_attach(usb_hub1_ports[0], usb_hub); + usb_dev = usb_hub_init(usb_hub2_ports, 2); + usb_attach(usb_hub1_ports[0], usb_dev); } #endif +#if 0 + /* USB mouse */ + usb_dev = usb_mouse_init(); + usb_attach(usb_root_ports[0], usb_dev); +#endif +#if 1 /* simulated hub with the host USB devices connected to it */ - usb_hub = usb_host_hub_init(); - usb_attach(usb_root_ports[0], usb_hub); + usb_dev = usb_host_hub_init(); + usb_attach(usb_root_ports[0], usb_dev); +#endif } /* must be done after all PCI devices are instanciated */ diff --git a/hw/usb-hid.c b/hw/usb-hid.c new file mode 100644 index 000000000..6f9ee827d --- /dev/null +++ b/hw/usb-hid.c @@ -0,0 +1,347 @@ +/* + * QEMU USB HID devices + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* HID interface requests */ +#define GET_REPORT 0xa101 +#define GET_IDLE 0xa102 +#define GET_PROTOCOL 0xa103 +#define SET_IDLE 0x210a +#define SET_PROTOCOL 0x210b + +typedef struct USBMouseState { + USBDevice dev; + int dx, dy, dz, buttons_state; +} USBMouseState; + +/* mostly the same values as the Bochs USB Mouse device */ +static const uint8_t qemu_mouse_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + 0x27, 0x06, /* u16 idVendor; */ + 0x01, 0x00, /* u16 idProduct; */ + 0x00, 0x00, /* u16 bcdDevice */ + + 0x03, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x01, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_mouse_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 50, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; */ + 0x01, /* u8 if_bInterfaceSubClass; */ + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x05, /* u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + + /* HID descriptor */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 50, 0, /* u16 len */ +}; + +static const uint8_t qemu_mouse_hid_report_descriptor[] = { + 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, + 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, + 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, + 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, + 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, + 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, + 0xC0, 0xC0, +}; + +static void usb_mouse_event(void *opaque, + int dx1, int dy1, int dz1, int buttons_state) +{ + USBMouseState *s = opaque; + + s->dx += dx1; + s->dy += dy1; + s->dz += dz1; + s->buttons_state = buttons_state; +} + +static inline int int_clamp(int val, int vmin, int vmax) +{ + if (val < vmin) + return vmin; + else if (val > vmax) + return vmax; + else + return val; +} + +static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) +{ + int dx, dy, dz, b, l; + + dx = int_clamp(s->dx, -128, 127); + dy = int_clamp(s->dy, -128, 127); + dz = int_clamp(s->dz, -128, 127); + + s->dx -= dx; + s->dy -= dy; + s->dz -= dz; + + b = 0; + if (s->buttons_state & MOUSE_EVENT_LBUTTON) + b |= 0x01; + if (s->buttons_state & MOUSE_EVENT_RBUTTON) + b |= 0x02; + if (s->buttons_state & MOUSE_EVENT_MBUTTON) + b |= 0x04; + + buf[0] = b; + buf[1] = dx; + buf[2] = dy; + l = 3; + if (len >= 4) { + buf[3] = dz; + l = 4; + } + return l; +} + +static void usb_mouse_handle_reset(USBDevice *dev) +{ + USBMouseState *s = (USBMouseState *)dev; + + s->dx = 0; + s->dy = 0; + s->dz = 0; + s->buttons_state = 0; +} + +static int usb_mouse_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBMouseState *s = (USBMouseState *)dev; + int ret; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_mouse_dev_descriptor, + sizeof(qemu_mouse_dev_descriptor)); + ret = sizeof(qemu_mouse_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_mouse_config_descriptor, + sizeof(qemu_mouse_config_descriptor)); + ret = sizeof(qemu_mouse_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "QEMU USB Mouse"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "QEMU " QEMU_VERSION); + break; + case 4: + ret = set_usb_string(data, "HID Mouse"); + break; + case 5: + ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* hid specific requests */ + case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case 0x22: + memcpy(data, qemu_mouse_hid_report_descriptor, + sizeof(qemu_mouse_hid_report_descriptor)); + ret = sizeof(qemu_mouse_hid_report_descriptor); + break; + default: + goto fail; + } + break; + case GET_REPORT: + ret = usb_mouse_poll(s, data, length); + break; + case SET_IDLE: + ret = 0; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_mouse_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + USBMouseState *s = (USBMouseState *)dev; + int ret; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + ret = usb_mouse_poll(s, data, len); + } else { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +USBDevice *usb_mouse_init(void) +{ + USBMouseState *s; + + s = qemu_mallocz(sizeof(USBMouseState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_mouse_handle_reset; + s->dev.handle_control = usb_mouse_handle_control; + s->dev.handle_data = usb_mouse_handle_data; + + qemu_add_mouse_event_handler(usb_mouse_event, s); + + return (USBDevice *)s; +} diff --git a/hw/usb.h b/hw/usb.h index 1bfce3b51..7a5c8ad26 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -64,6 +64,13 @@ #define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) #define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8) +#define InterfaceRequest \ + ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) +#define InterfaceOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) +#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) +#define EndpointOutRequest \ + ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8) #define USB_REQ_GET_STATUS 0x00 #define USB_REQ_CLEAR_FEATURE 0x01 @@ -137,3 +144,6 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); /* usb-linux.c */ USBDevice *usb_host_hub_init(void); + +/* usb-hid.c */ +USBDevice *usb_mouse_init(void); -- cgit v1.2.3 From f04308e45274d0e74546870ea7b02aaef07b077e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Nov 2005 17:22:48 +0000 Subject: same PCI parameters as PIIX3 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1600 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 42417feda..4dd0c6381 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -106,7 +106,7 @@ static void uhci_update_irq(UHCIState *s) } else { level = 0; } - pci_set_irq(&s->dev, 0, level); + pci_set_irq(&s->dev, 3, level); } static void uhci_reset(UHCIState *s) @@ -642,7 +642,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) s = (UHCIState *)pci_register_device(bus, "USB-UHCI", sizeof(UHCIState), - -1, + ((PCIDevice *)piix3_state)->devfn + 2, NULL, NULL); pci_conf = s->dev.config; pci_conf[0x00] = 0x86; @@ -654,7 +654,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) pci_conf[0x0a] = 0x03; pci_conf[0x0b] = 0x0c; pci_conf[0x0e] = 0x00; // header_type - pci_conf[0x3d] = 1; // interrupt pin 0 + pci_conf[0x3d] = 4; // interrupt pin 3 for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; -- cgit v1.2.3 From c0fe3827ea18f7d29550f2ff2495cec2fe7a3d94 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Nov 2005 18:55:28 +0000 Subject: audio merge (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1601 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- audio/alsaaudio.c | 86 ++++---- audio/audio.c | 550 ++++++++++++++++++++++++++---------------------- audio/audio.h | 78 ++++--- audio/audio_int.h | 107 ++++------ audio/audio_template.h | 251 ++++++++++++---------- audio/coreaudio.c | 52 +++-- audio/dsound_template.h | 66 +++--- audio/dsoundaudio.c | 126 ++++++----- audio/fmodaudio.c | 26 ++- audio/mixeng.c | 7 +- audio/noaudio.c | 14 +- audio/ossaudio.c | 108 ++++++---- audio/rate_template.h | 2 +- audio/sdlaudio.c | 26 ++- audio/wavaudio.c | 57 ++--- hw/adlib.c | 40 ++-- hw/es1370.c | 49 +++-- hw/pc.c | 22 +- hw/sb16.c | 78 +++++-- qemu-doc.texi | 11 +- vl.c | 11 +- vl.h | 8 +- 23 files changed, 981 insertions(+), 798 deletions(-) diff --git a/Makefile.target b/Makefile.target index cefad7403..a22b2e080 100644 --- a/Makefile.target +++ b/Makefile.target @@ -453,8 +453,8 @@ ifneq ($(wildcard .depend),) include .depend endif -ifeq (0, 1) +ifeq (1, 0) audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \ -fmodaudio.o alsaaudio.o mixeng.o: \ +fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \ CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare endif diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 133690576..65a0a0d2e 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -98,7 +98,7 @@ struct alsa_params_obt { audfmt_e fmt; int nchannels; int can_pause; - snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t samples; }; static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...) @@ -121,7 +121,7 @@ static void GCC_FMT_ATTR (3, 4) alsa_logerr2 ( { va_list ap; - AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); va_start (ap, fmt); AUD_vlog (AUDIO_CAP, fmt, ap); @@ -209,7 +209,7 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness) return 0; } -#ifdef DEBUG_MISMATCHES +#if defined DEBUG_MISMATCHES || defined DEBUG static void alsa_dump_info (struct alsa_params_req *req, struct alsa_params_obt *obt) { @@ -221,7 +221,7 @@ static void alsa_dump_info (struct alsa_params_req *req, dolog ("============================================\n"); dolog ("requested: buffer size %d period size %d\n", req->buffer_size, req->period_size); - dolog ("obtained: buffer size %ld\n", obt->buffer_size); + dolog ("obtained: samples %ld\n", obt->samples); } #endif @@ -234,14 +234,14 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) err = snd_pcm_sw_params_current (handle, sw_params); if (err < 0) { - dolog ("Can not fully initialize DAC\n"); + dolog ("Could not fully initialize DAC\n"); alsa_logerr (err, "Failed to get current software parameters\n"); return; } err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold); if (err < 0) { - dolog ("Can not fully initialize DAC\n"); + dolog ("Could not fully initialize DAC\n"); alsa_logerr (err, "Failed to set software threshold to %ld\n", threshold); return; @@ -249,7 +249,7 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) err = snd_pcm_sw_params (handle, sw_params); if (err < 0) { - dolog ("Can not fully initialize DAC\n"); + dolog ("Could not fully initialize DAC\n"); alsa_logerr (err, "Failed to set software parameters\n"); return; } @@ -344,7 +344,8 @@ static int alsa_open (int in, struct alsa_params_req *req, handle, hw_params, &period_size, - 0); + 0 + ); if (err < 0) { alsa_logerr2 (err, typ, "Failed to set period time %d\n", @@ -357,7 +358,8 @@ static int alsa_open (int in, struct alsa_params_req *req, handle, hw_params, &buffer_size, - 0); + 0 + ); if (err < 0) { alsa_logerr2 (err, typ, @@ -382,7 +384,7 @@ static int alsa_open (int in, struct alsa_params_req *req, if (err < 0) { alsa_logerr ( err, - "Can not get minmal period size for %s\n", + "Could not get minmal period size for %s\n", typ ); } @@ -419,7 +421,7 @@ static int alsa_open (int in, struct alsa_params_req *req, &minval ); if (err < 0) { - alsa_logerr (err, "Can not get minmal buffer size for %s\n", + alsa_logerr (err, "Could not get minmal buffer size for %s\n", typ); } else { @@ -451,7 +453,7 @@ static int alsa_open (int in, struct alsa_params_req *req, } } else { - dolog ("warning: buffer size is not set\n"); + dolog ("warning: Buffer size is not set\n"); } err = snd_pcm_hw_params (handle, hw_params); @@ -468,13 +470,13 @@ static int alsa_open (int in, struct alsa_params_req *req, err = snd_pcm_prepare (handle); if (err < 0) { - alsa_logerr2 (err, typ, "Can not prepare handle %p\n", handle); + alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle); goto err; } obt->can_pause = snd_pcm_hw_params_can_pause (hw_params); if (obt->can_pause < 0) { - alsa_logerr (err, "Can not get pause capability for %s\n", typ); + alsa_logerr (err, "Could not get pause capability for %s\n", typ); obt->can_pause = 0; } @@ -493,17 +495,17 @@ static int alsa_open (int in, struct alsa_params_req *req, obt->fmt = req->fmt; obt->nchannels = nchannels; obt->freq = freq; - obt->buffer_size = snd_pcm_frames_to_bytes (handle, obt_buffer_size); + obt->samples = obt_buffer_size; *handlep = handle; +#if defined DEBUG_MISMATCHES || defined DEBUG if (obt->fmt != req->fmt || obt->nchannels != req->nchannels || obt->freq != req->freq) { -#ifdef DEBUG_MISMATCHES dolog ("Audio paramters mismatch for %s\n", typ); alsa_dump_info (req, obt); -#endif } +#endif #ifdef DEBUG alsa_dump_info (req, obt); @@ -550,7 +552,7 @@ static int alsa_run_out (HWVoiceOut *hw) } } - alsa_logerr (avail, "Can not get amount free space\n"); + alsa_logerr (avail, "Could not get amount free space\n"); return 0; } @@ -618,7 +620,7 @@ static void alsa_fini_out (HWVoiceOut *hw) } } -static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as) { ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; struct alsa_params_req req; @@ -627,10 +629,11 @@ static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) int endianness; int err; snd_pcm_t *handle; + audsettings_t obt_as; - req.fmt = aud_to_alsafmt (fmt); - req.freq = freq; - req.nchannels = nchannels; + req.fmt = aud_to_alsafmt (as->fmt); + req.freq = as->freq; + req.nchannels = as->nchannels; req.period_size = conf.period_size_out; req.buffer_size = conf.buffer_size_out; @@ -644,18 +647,22 @@ static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.nchannels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.nchannels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianness) ); alsa->can_pause = obt.can_pause; - hw->bufsize = obt.buffer_size; + hw->samples = obt.samples; - alsa->pcm_buf = qemu_mallocz (hw->bufsize); + alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift); if (!alsa->pcm_buf) { + dolog ("Could not allocate DAC buffer (%d bytes)\n", + hw->samples << hw->info.shift); alsa_anal_close (&handle); return -1; } @@ -703,8 +710,7 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...) return 0; } -static int alsa_init_in (HWVoiceIn *hw, - int freq, int nchannels, audfmt_e fmt) +static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) { ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; struct alsa_params_req req; @@ -713,10 +719,11 @@ static int alsa_init_in (HWVoiceIn *hw, int err; audfmt_e effective_fmt; snd_pcm_t *handle; + audsettings_t obt_as; - req.fmt = aud_to_alsafmt (fmt); - req.freq = freq; - req.nchannels = nchannels; + req.fmt = aud_to_alsafmt (as->fmt); + req.freq = as->freq; + req.nchannels = as->nchannels; req.period_size = conf.period_size_in; req.buffer_size = conf.buffer_size_in; @@ -730,17 +737,22 @@ static int alsa_init_in (HWVoiceIn *hw, return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.nchannels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.nchannels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianness) ); alsa->can_pause = obt.can_pause; - hw->bufsize = obt.buffer_size; - alsa->pcm_buf = qemu_mallocz (hw->bufsize); + hw->samples = obt.samples; + + alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!alsa->pcm_buf) { + dolog ("Could not allocate ADC buffer (%d bytes)\n", + hw->samples << hw->info.shift); alsa_anal_close (&handle); return -1; } diff --git a/audio/audio.c b/audio/audio.c index 1a3925d4e..961654b00 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -26,16 +26,12 @@ #define AUDIO_CAP "audio" #include "audio_int.h" -static void audio_pcm_hw_fini_in (HWVoiceIn *hw); -static void audio_pcm_hw_fini_out (HWVoiceOut *hw); - -static LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; -static LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; - /* #define DEBUG_PLIVE */ /* #define DEBUG_LIVE */ /* #define DEBUG_OUT */ +#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" + static struct audio_driver *drvtab[] = { #ifdef CONFIG_OSS &oss_audio_driver, @@ -59,31 +55,50 @@ static struct audio_driver *drvtab[] = { &wav_audio_driver }; -AudioState audio_state = { - /* Out */ - 1, /* use fixed settings */ - 44100, /* fixed frequency */ - 2, /* fixed channels */ - AUD_FMT_S16, /* fixed format */ - 1, /* number of hw voices */ - 1, /* greedy */ - - /* In */ - 1, /* use fixed settings */ - 44100, /* fixed frequency */ - 2, /* fixed channels */ - AUD_FMT_S16, /* fixed format */ - 1, /* number of hw voices */ - 1, /* greedy */ - - NULL, /* driver opaque */ - NULL, /* driver */ - - NULL, /* timer handle */ +struct fixed_settings { + int enabled; + int nb_voices; + int greedy; + audsettings_t settings; +}; + +static struct { + struct fixed_settings fixed_out; + struct fixed_settings fixed_in; + union { + int hz; + int64_t ticks; + } period; + int plive; +} conf = { + { /* DAC fixed settings */ + 1, /* enabled */ + 1, /* nb_voices */ + 1, /* greedy */ + { + 44100, /* freq */ + 2, /* nchannels */ + AUD_FMT_S16 /* fmt */ + } + }, + + { /* ADC fixed settings */ + 1, /* enabled */ + 1, /* nb_voices */ + 1, /* greedy */ + { + 44100, /* freq */ + 2, /* nchannels */ + AUD_FMT_S16 /* fmt */ + } + }, + { 0 }, /* period */ 0 /* plive */ }; +static AudioState glob_audio_state; + volume_t nominal_volume = { 0, #ifdef FLOAT_MIXENG @@ -148,6 +163,26 @@ int audio_bug (const char *funcname, int cond) } #endif +void *audio_calloc (const char *funcname, int nmemb, size_t size) +{ + int cond; + size_t len; + + len = nmemb * size; + cond = !nmemb || !size; + cond |= nmemb < 0; + cond |= len < size; + + if (audio_bug ("audio_calloc", cond)) { + AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n", + funcname); + AUD_log (NULL, "nmemb=%d size=%d (len=%d)\n", nmemb, size, len); + return NULL; + } + + return qemu_mallocz (len); +} + static char *audio_alloc_prefix (const char *s) { const char qemu_prefix[] = "QEMU_"; @@ -386,14 +421,19 @@ static void audio_process_options (const char *prefix, } len = strlen (opt->name); + /* len of opt->name + len of prefix + size of qemu_prefix + * (includes trailing zero) + zero + underscore (on behalf of + * sizeof) */ optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1); if (!optname) { - dolog ("Can not allocate memory for option name `%s'\n", + dolog ("Could not allocate memory for option name `%s'\n", opt->name); continue; } strcpy (optname, qemu_prefix); + + /* copy while upper-casing, including trailing zero */ for (i = 0; i <= preflen; ++i) { optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]); } @@ -438,12 +478,60 @@ static void audio_process_options (const char *prefix, } } -static int audio_pcm_info_eq (struct audio_pcm_info *info, int freq, - int nchannels, audfmt_e fmt) +static void audio_print_settings (audsettings_t *as) +{ + dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels); + + switch (as->fmt) { + case AUD_FMT_S8: + AUD_log (NULL, "S8"); + break; + case AUD_FMT_U8: + AUD_log (NULL, "U8"); + break; + case AUD_FMT_S16: + AUD_log (NULL, "S16"); + break; + case AUD_FMT_U16: + AUD_log (NULL, "U16"); + break; + default: + AUD_log (NULL, "invalid(%d)", as->fmt); + break; + } + AUD_log (NULL, "\n"); +} + +static int audio_validate_settigs (audsettings_t *as) +{ + int invalid; + + invalid = as->nchannels != 1 && as->nchannels != 2; + + switch (as->fmt) { + case AUD_FMT_S8: + case AUD_FMT_U8: + case AUD_FMT_S16: + case AUD_FMT_U16: + break; + default: + invalid = 1; + break; + } + + invalid |= as->freq <= 0; + + if (invalid) { + return -1; + } + return 0; +} + +static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) { int bits = 8, sign = 0; - switch (fmt) { + switch (as->fmt) { case AUD_FMT_S8: sign = 1; case AUD_FMT_U8: @@ -455,18 +543,21 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, int freq, bits = 16; break; } - return info->freq == freq - && info->nchannels == nchannels + return info->freq == as->freq + && info->nchannels == as->nchannels && info->sign == sign && info->bits == bits; } -void audio_pcm_init_info (struct audio_pcm_info *info, int freq, - int nchannels, audfmt_e fmt, int swap_endian) +void audio_pcm_init_info ( + struct audio_pcm_info *info, + audsettings_t *as, + int swap_endian + ) { int bits = 8, sign = 0; - switch (fmt) { + switch (as->fmt) { case AUD_FMT_S8: sign = 1; case AUD_FMT_U8: @@ -479,11 +570,11 @@ void audio_pcm_init_info (struct audio_pcm_info *info, int freq, break; } - info->freq = freq; + info->freq = as->freq; info->bits = bits; info->sign = sign; - info->nchannels = nchannels; - info->shift = (nchannels == 2) + (bits == 16); + info->nchannels = as->nchannels; + info->shift = (as->nchannels == 2) + (bits == 16); info->align = (1 << info->shift) - 1; info->bytes_per_second = info->freq << info->shift; info->swap_endian = swap_endian; @@ -532,38 +623,16 @@ static void audio_pcm_hw_free_resources_in (HWVoiceIn *hw) static int audio_pcm_hw_alloc_resources_in (HWVoiceIn *hw) { - hw->conv_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); + hw->conv_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); if (!hw->conv_buf) { + dolog ("Could not allocate ADC conversion buffer (%d bytes)\n", + hw->samples * sizeof (st_sample_t)); return -1; } return 0; } -static int audio_pcm_hw_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) -{ - audio_pcm_hw_fini_in (hw); - - if (hw->pcm_ops->init_in (hw, freq, nchannels, fmt)) { - memset (hw, 0, audio_state.drv->voice_size_in); - return -1; - } - LIST_INIT (&hw->sw_head); - hw->active = 1; - hw->samples = hw->bufsize >> hw->info.shift; - hw->conv = - mixeng_conv - [nchannels == 2] - [hw->info.sign] - [hw->info.swap_endian] - [hw->info.bits == 16]; - if (audio_pcm_hw_alloc_resources_in (hw)) { - audio_pcm_hw_free_resources_in (hw); - return -1; - } - return 0; -} - -static uint64_t audio_pcm_hw_find_min_in (HWVoiceIn *hw) +static int audio_pcm_hw_find_min_in (HWVoiceIn *hw) { SWVoiceIn *sw; int m = hw->total_samples_captured; @@ -606,8 +675,10 @@ static void audio_pcm_sw_free_resources_in (SWVoiceIn *sw) static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw) { int samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; - sw->conv_buf = qemu_mallocz (samples * sizeof (st_sample_t)); + sw->conv_buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t)); if (!sw->conv_buf) { + dolog ("Could not allocate buffer for `%s' (%d bytes)\n", + SW_NAME (sw), samples * sizeof (st_sample_t)); return -1; } @@ -620,19 +691,22 @@ static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw) return 0; } -static int audio_pcm_sw_init_in (SWVoiceIn *sw, HWVoiceIn *hw, const char *name, - int freq, int nchannels, audfmt_e fmt) +static int audio_pcm_sw_init_in ( + SWVoiceIn *sw, + HWVoiceIn *hw, + const char *name, + audsettings_t *as + ) { - audio_pcm_init_info (&sw->info, freq, nchannels, fmt, - /* None of the cards emulated by QEMU are big-endian - hence following shortcut */ - audio_need_to_swap_endian (0)); + /* None of the cards emulated by QEMU are big-endian + hence following shortcut */ + audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0)); sw->hw = hw; sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq; sw->clip = mixeng_clip - [nchannels == 2] + [sw->info.nchannels == 2] [sw->info.sign] [sw->info.swap_endian] [sw->info.bits == 16]; @@ -699,6 +773,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) if (audio_bug (AUDIO_FUNC, osamp < 0)) { dolog ("osamp=%d\n", osamp); + return 0; } st_rate_flow (sw->rate, src, dst, &isamp, &osamp); @@ -717,23 +792,6 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) /* * Hard voice (playback) */ -static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) -{ - SWVoiceOut *sw; - int m = INT_MAX; - int nb_live = 0; - - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - if (sw->active || !sw->empty) { - m = audio_MIN (m, sw->total_hw_samples_mixed); - nb_live += 1; - } - } - - *nb_livep = nb_live; - return m; -} - static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw) { if (hw->mix_buf) { @@ -745,37 +803,31 @@ static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw) static int audio_pcm_hw_alloc_resources_out (HWVoiceOut *hw) { - hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); + hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); if (!hw->mix_buf) { + dolog ("Could not allocate DAC mixing buffer (%d bytes)\n", + hw->samples * sizeof (st_sample_t)); return -1; } return 0; } -static int audio_pcm_hw_init_out (HWVoiceOut *hw, int freq, - int nchannels, audfmt_e fmt) +static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) { - audio_pcm_hw_fini_out (hw); - if (hw->pcm_ops->init_out (hw, freq, nchannels, fmt)) { - memset (hw, 0, audio_state.drv->voice_size_out); - return -1; - } + SWVoiceOut *sw; + int m = INT_MAX; + int nb_live = 0; - LIST_INIT (&hw->sw_head); - hw->active = 1; - hw->samples = hw->bufsize >> hw->info.shift; - hw->clip = - mixeng_clip - [nchannels == 2] - [hw->info.sign] - [hw->info.swap_endian] - [hw->info.bits == 16]; - if (audio_pcm_hw_alloc_resources_out (hw)) { - audio_pcm_hw_fini_out (hw); - return -1; + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (sw->active || !sw->empty) { + m = audio_MIN (m, sw->total_hw_samples_mixed); + nb_live += 1; + } } - return 0; + + *nb_livep = nb_live; + return m; } int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live) @@ -830,8 +882,10 @@ static void audio_pcm_sw_free_resources_out (SWVoiceOut *sw) static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw) { - sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t)); + sw->buf = audio_calloc (AUDIO_FUNC, sw->hw->samples, sizeof (st_sample_t)); if (!sw->buf) { + dolog ("Could not allocate buffer for `%s' (%d bytes)\n", + SW_NAME (sw), sw->hw->samples * sizeof (st_sample_t)); return -1; } @@ -844,14 +898,16 @@ static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw) return 0; } -static int audio_pcm_sw_init_out (SWVoiceOut *sw, HWVoiceOut *hw, - const char *name, int freq, - int nchannels, audfmt_e fmt) +static int audio_pcm_sw_init_out ( + SWVoiceOut *sw, + HWVoiceOut *hw, + const char *name, + audsettings_t *as + ) { - audio_pcm_init_info (&sw->info, freq, nchannels, fmt, - /* None of the cards emulated by QEMU are big-endian - hence following shortcut */ - audio_need_to_swap_endian (0)); + /* None of the cards emulated by QEMU are big-endian + hence following shortcut */ + audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0)); sw->hw = hw; sw->empty = 1; sw->active = 0; @@ -860,7 +916,7 @@ static int audio_pcm_sw_init_out (SWVoiceOut *sw, HWVoiceOut *hw, sw->conv = mixeng_conv - [nchannels == 2] + [sw->info.nchannels == 2] [sw->info.sign] [sw->info.swap_endian] [sw->info.bits == 16]; @@ -930,12 +986,11 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) #ifdef DEBUG_OUT dolog ( - "%s: write size %d ret %d total sw %d, hw %d\n", - sw->name, + "%s: write size %d ret %d total sw %d\n", + SW_NAME (sw), size >> sw->info.shift, ret, - sw->total_hw_samples_mixed, - sw->hw->total_samples_played + sw->total_hw_samples_mixed ); #endif @@ -965,7 +1020,7 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size) } if (!sw->hw->enabled) { - dolog ("Writing to disabled voice %s\n", sw->name); + dolog ("Writing to disabled voice %s\n", SW_NAME (sw)); return 0; } @@ -983,7 +1038,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size) } if (!sw->hw->enabled) { - dolog ("Reading from disabled voice %s\n", sw->name); + dolog ("Reading from disabled voice %s\n", SW_NAME (sw)); return 0; } @@ -993,7 +1048,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size) int AUD_get_buffer_size_out (SWVoiceOut *sw) { - return sw->hw->bufsize; + return sw->hw->samples << sw->hw->info.shift; } void AUD_set_active_out (SWVoiceOut *sw, int on) @@ -1091,7 +1146,7 @@ static int audio_get_avail (SWVoiceIn *sw) ldebug ( "%s: get_avail live %d ret %lld\n", - sw->name, + SW_NAME (sw), live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift ); @@ -1110,34 +1165,37 @@ static int audio_get_free (SWVoiceOut *sw) if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); + return 0; } dead = sw->hw->samples - live; #ifdef DEBUG_OUT dolog ("%s: get_free live %d dead %d ret %lld\n", - sw->name, + SW_NAME (sw), live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); #endif return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; } -static void audio_run_out (void) +static void audio_run_out (AudioState *s) { HWVoiceOut *hw = NULL; SWVoiceOut *sw; - while ((hw = audio_pcm_hw_find_any_active_enabled_out (hw))) { + while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) { int played; - int live, free, nb_live; + int live, free, nb_live, cleanup_required; live = audio_pcm_hw_get_live_out2 (hw, &nb_live); if (!nb_live) { live = 0; } + if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { dolog ("live=%d hw->samples=%d\n", live, hw->samples); + continue; } if (hw->pending_disable && !nb_live) { @@ -1170,15 +1228,15 @@ static void audio_run_out (void) } #ifdef DEBUG_OUT - dolog ("played = %d total %d\n", played, hw->total_samples_played); + dolog ("played=%d\n", played); #endif if (played) { hw->ts_helper += played; } + cleanup_required = 0; for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - again: if (!sw->active && sw->empty) { continue; } @@ -1193,22 +1251,7 @@ static void audio_run_out (void) if (!sw->total_hw_samples_mixed) { sw->empty = 1; - - if (!sw->active && !sw->callback.fn) { - SWVoiceOut *temp = sw->entries.le_next; - -#ifdef DEBUG_PLIVE - dolog ("Finishing with old voice\n"); -#endif - AUD_close_out (sw); - sw = temp; - if (sw) { - goto again; - } - else { - break; - } - } + cleanup_required |= !sw->active && !sw->callback.fn; } if (sw->active) { @@ -1218,14 +1261,27 @@ static void audio_run_out (void) } } } + + if (cleanup_required) { + restart: + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (!sw->active && !sw->callback.fn) { +#ifdef DEBUG_PLIVE + dolog ("Finishing with old voice\n"); +#endif + audio_close_out (s, sw); + goto restart; /* play it safe */ + } + } + } } } -static void audio_run_in (void) +static void audio_run_in (AudioState *s) { HWVoiceIn *hw = NULL; - while ((hw = audio_pcm_hw_find_any_active_enabled_in (hw))) { + while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) { SWVoiceIn *sw; int captured, min; @@ -1252,42 +1308,42 @@ static void audio_run_in (void) static struct audio_option audio_options[] = { /* DAC */ - {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out, + {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled, "Use fixed settings for host DAC", NULL, 0}, - {"DAC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out, + {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq, "Frequency for fixed host DAC", NULL, 0}, - {"DAC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out, + {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt, "Format for fixed host DAC", NULL, 0}, - {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_out, + {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels, "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0}, - {"DAC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out, + {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices, "Number of voices for DAC", NULL, 0}, /* ADC */ - {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out, + {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled, "Use fixed settings for host ADC", NULL, 0}, - {"ADC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out, - "Frequency for fixed ADC", NULL, 0}, + {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq, + "Frequency for fixed host ADC", NULL, 0}, - {"ADC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out, - "Format for fixed ADC", NULL, 0}, + {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt, + "Format for fixed host ADC", NULL, 0}, - {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_in, + {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels, "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0}, - {"ADC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out, + {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices, "Number of voices for ADC", NULL, 0}, /* Misc */ - {"TIMER_PERIOD", AUD_OPT_INT, &audio_state.period.usec, - "Timer period in microseconds (0 - try lowest possible)", NULL, 0}, + {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz, + "Timer period in HZ (0 - use lowest possible)", NULL, 0}, - {"PLIVE", AUD_OPT_BOOL, &audio_state.plive, + {"PLIVE", AUD_OPT_BOOL, &conf.plive, "(undocumented)", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} @@ -1378,25 +1434,21 @@ void audio_timer (void *opaque) { AudioState *s = opaque; - audio_run_out (); - audio_run_in (); + audio_run_out (s); + audio_run_in (s); - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); } -static int audio_driver_init (struct audio_driver *drv) +static int audio_driver_init (AudioState *s, struct audio_driver *drv) { if (drv->options) { audio_process_options (drv->name, drv->options); } - audio_state.opaque = drv->init (); + s->drv_opaque = drv->init (); - if (audio_state.opaque) { - int i; - HWVoiceOut *hwo; - HWVoiceIn *hwi; - - if (audio_state.nb_hw_voices_out > drv->max_voices_out) { + if (s->drv_opaque) { + if (s->nb_hw_voices_out > drv->max_voices_out) { if (!drv->max_voices_out) { dolog ("`%s' does not support DAC\n", drv->name); } @@ -1405,30 +1457,13 @@ static int audio_driver_init (struct audio_driver *drv) "`%s' does not support %d multiple DAC voicess\n" "Resetting to %d\n", drv->name, - audio_state.nb_hw_voices_out, + s->nb_hw_voices_out, drv->max_voices_out ); } - audio_state.nb_hw_voices_out = drv->max_voices_out; - } - - LIST_INIT (&hw_head_out); - hwo = qemu_mallocz (audio_state.nb_hw_voices_out * drv->voice_size_out); - if (!hwo) { - dolog ( - "Not enough memory for %d `%s' DAC voices (each %d bytes)\n", - audio_state.nb_hw_voices_out, - drv->name, - drv->voice_size_out - ); - drv->fini (audio_state.opaque); - return -1; + s->nb_hw_voices_out = drv->max_voices_out; } - for (i = 0; i < audio_state.nb_hw_voices_out; ++i) { - LIST_INSERT_HEAD (&hw_head_out, hwo, entries); - hwo = advance (hwo, drv->voice_size_out); - } if (!drv->voice_size_in && drv->max_voices_in) { ldebug ("warning: No ADC voice size defined for `%s'\n", @@ -1442,16 +1477,16 @@ static int audio_driver_init (struct audio_driver *drv) } if (drv->voice_size_in && !drv->max_voices_in) { - ldebug ("warning: ADC voice size is %d for ADC less driver `%s'\n", - drv->voice_size_out, drv->name); + ldebug ("warning: `%s' ADC voice size %d, zero voices \n", + drv->name, drv->voice_size_out); } if (drv->voice_size_out && !drv->max_voices_out) { - ldebug ("warning: DAC voice size is %d for DAC less driver `%s'\n", - drv->voice_size_in, drv->name); + ldebug ("warning: `%s' DAC voice size %d, zero voices \n", + drv->name, drv->voice_size_in); } - if (audio_state.nb_hw_voices_in > drv->max_voices_in) { + if (s->nb_hw_voices_in > drv->max_voices_in) { if (!drv->max_voices_in) { ldebug ("`%s' does not support ADC\n", drv->name); } @@ -1460,33 +1495,16 @@ static int audio_driver_init (struct audio_driver *drv) "`%s' does not support %d multiple ADC voices\n" "Resetting to %d\n", drv->name, - audio_state.nb_hw_voices_in, + s->nb_hw_voices_in, drv->max_voices_in ); } - audio_state.nb_hw_voices_in = drv->max_voices_in; + s->nb_hw_voices_in = drv->max_voices_in; } - LIST_INIT (&hw_head_in); - hwi = qemu_mallocz (audio_state.nb_hw_voices_in * drv->voice_size_in); - if (!hwi) { - dolog ( - "Not enough memory for %d `%s' ADC voices (each %d bytes)\n", - audio_state.nb_hw_voices_in, - drv->name, - drv->voice_size_in - ); - qemu_free (hwo); - drv->fini (audio_state.opaque); - return -1; - } - - for (i = 0; i < audio_state.nb_hw_voices_in; ++i) { - LIST_INSERT_HEAD (&hw_head_in, hwi, entries); - hwi = advance (hwi, drv->voice_size_in); - } - - audio_state.drv = drv; + LIST_INIT (&s->hw_head_out); + LIST_INIT (&s->hw_head_in); + s->drv = drv; return 0; } else { @@ -1497,12 +1515,12 @@ static int audio_driver_init (struct audio_driver *drv) static void audio_vm_stop_handler (void *opaque, int reason) { + AudioState *s = opaque; HWVoiceOut *hwo = NULL; HWVoiceIn *hwi = NULL; int op = reason ? VOICE_ENABLE : VOICE_DISABLE; - (void) opaque; - while ((hwo = audio_pcm_hw_find_any_out (hwo))) { + while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) { if (!hwo->pcm_ops) { continue; } @@ -1512,7 +1530,7 @@ static void audio_vm_stop_handler (void *opaque, int reason) } } - while ((hwi = audio_pcm_hw_find_any_in (hwi))) { + while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) { if (!hwi->pcm_ops) { continue; } @@ -1525,10 +1543,11 @@ static void audio_vm_stop_handler (void *opaque, int reason) static void audio_atexit (void) { + AudioState *s = &glob_audio_state; HWVoiceOut *hwo = NULL; HWVoiceIn *hwi = NULL; - while ((hwo = audio_pcm_hw_find_any_out (hwo))) { + while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) { if (!hwo->pcm_ops) { continue; } @@ -1539,7 +1558,7 @@ static void audio_atexit (void) hwo->pcm_ops->fini_out (hwo); } - while ((hwi = audio_pcm_hw_find_any_in (hwi))) { + while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) { if (!hwi->pcm_ops) { continue; } @@ -1549,7 +1568,10 @@ static void audio_atexit (void) } hwi->pcm_ops->fini_in (hwi); } - audio_state.drv->fini (audio_state.opaque); + + if (s->drv) { + s->drv->fini (s->drv_opaque); + } } static void audio_save (QEMUFile *f, void *opaque) @@ -1570,15 +1592,33 @@ static int audio_load (QEMUFile *f, void *opaque, int version_id) return 0; } -void AUD_init (void) +void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card) +{ + card->audio = s; + card->name = qemu_strdup (name); + memset (&card->entries, 0, sizeof (card->entries)); + LIST_INSERT_HEAD (&s->card_head, card, entries); +} + +void AUD_remove_card (QEMUSoundCard *card) +{ + LIST_REMOVE (card, entries); + card->audio = NULL; + qemu_free (card->name); +} + +AudioState *AUD_init (void) { size_t i; int done = 0; const char *drvname; - AudioState *s = &audio_state; + AudioState *s = &glob_audio_state; audio_process_options ("AUDIO", audio_options); + s->nb_hw_voices_out = conf.fixed_out.nb_voices; + s->nb_hw_voices_in = conf.fixed_in.nb_voices; + if (s->nb_hw_voices_out <= 0) { dolog ("Bogus number of DAC voices %d\n", s->nb_hw_voices_out); @@ -1598,8 +1638,8 @@ void AUD_init (void) s->ts = qemu_new_timer (vm_clock, audio_timer, s); if (!s->ts) { - dolog ("Can not create audio timer\n"); - return; + dolog ("Could not create audio timer\n"); + return NULL; } if (drvname) { @@ -1607,7 +1647,7 @@ void AUD_init (void) for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { if (!strcmp (drvname, drvtab[i]->name)) { - done = !audio_driver_init (drvtab[i]); + done = !audio_driver_init (s, drvtab[i]); found = 1; break; } @@ -1619,37 +1659,47 @@ void AUD_init (void) } } - qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); - atexit (audio_atexit); - if (!done) { for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { if (drvtab[i]->can_be_default) { - done = !audio_driver_init (drvtab[i]); + done = !audio_driver_init (s, drvtab[i]); } } } - register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); if (!done) { - if (audio_driver_init (&no_audio_driver)) { - dolog ("Can not initialize audio subsystem\n"); + done = !audio_driver_init (s, &no_audio_driver); + if (!done) { + dolog ("Could not initialize audio subsystem\n"); } else { - dolog ("warning: using timer based audio emulation\n"); + dolog ("warning: Using timer based audio emulation\n"); } } - if (s->period.usec <= 0) { - if (s->period.usec < 0) { - dolog ("warning: timer period is negative - %d treating as zero\n", - s->period.usec); + if (done) { + if (conf.period.hz <= 0) { + if (conf.period.hz < 0) { + dolog ("warning: Timer period is negative - %d " + "treating as zero\n", + conf.period.hz); + } + conf.period.ticks = 1; } - s->period.ticks = 1; + else { + conf.period.ticks = ticks_per_sec / conf.period.hz; + } + + qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); } else { - s->period.ticks = (ticks_per_sec * s->period.usec) / 1000000; + qemu_del_timer (s->ts); + return NULL; } - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks); + LIST_INIT (&s->card_head); + register_savevm ("audio", 0, 1, audio_save, audio_load, s); + atexit (audio_atexit); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); + return s; } diff --git a/audio/audio.h b/audio/audio.h index 6dd2fd22e..682d0e000 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -24,18 +24,33 @@ #ifndef QEMU_AUDIO_H #define QEMU_AUDIO_H +#include "sys-queue.h" + typedef void (*audio_callback_fn_t) (void *opaque, int avail); typedef enum { - AUD_FMT_U8, - AUD_FMT_S8, - AUD_FMT_U16, - AUD_FMT_S16 + AUD_FMT_U8, + AUD_FMT_S8, + AUD_FMT_U16, + AUD_FMT_S16 } audfmt_e; +typedef struct { + int freq; + int nchannels; + audfmt_e fmt; +} audsettings_t; + +typedef struct AudioState AudioState; typedef struct SWVoiceOut SWVoiceOut; typedef struct SWVoiceIn SWVoiceIn; +typedef struct QEMUSoundCard { + AudioState *audio; + char *name; + LIST_ENTRY (QEMUSoundCard) entries; +} QEMUSoundCard; + typedef struct QEMUAudioTimeStamp { uint64_t old_ts; } QEMUAudioTimeStamp; @@ -47,46 +62,45 @@ void AUD_log (const char *cap, const char *fmt, ...) #endif ; -void AUD_init (void); +AudioState *AUD_init (void); void AUD_help (void); +void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card); +void AUD_remove_card (QEMUSoundCard *card); -SWVoiceOut *AUD_open_out ( +SWVoiceOut *AUD_open_out ( + QEMUSoundCard *card, SWVoiceOut *sw, const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - int freq, - int nchannels, - audfmt_e fmt + audsettings_t *settings ); -void AUD_close_out (SWVoiceOut *sw); -int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size); -int AUD_get_buffer_size_out (SWVoiceOut *sw); -void AUD_set_active_out (SWVoiceOut *sw, int on); -int AUD_is_active_out (SWVoiceOut *sw); -void AUD_init_time_stamp_out (SWVoiceOut *sw, - QEMUAudioTimeStamp *ts); -uint64_t AUD_time_stamp_get_elapsed_usec_out (SWVoiceOut *sw, - QEMUAudioTimeStamp *ts); - -SWVoiceIn *AUD_open_in ( + +void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw); +int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size); +int AUD_get_buffer_size_out (SWVoiceOut *sw); +void AUD_set_active_out (SWVoiceOut *sw, int on); +int AUD_is_active_out (SWVoiceOut *sw); + +void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); +uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); + +SWVoiceIn *AUD_open_in ( + QEMUSoundCard *card, SWVoiceIn *sw, const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - int freq, - int nchannels, - audfmt_e fmt + audsettings_t *settings ); -void AUD_close_in (SWVoiceIn *sw); -int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size); -void AUD_adjust_in (SWVoiceIn *sw, int leftover); -void AUD_set_active_in (SWVoiceIn *sw, int on); -int AUD_is_active_in (SWVoiceIn *sw); -void AUD_init_time_stamp_in (SWVoiceIn *sw, - QEMUAudioTimeStamp *ts); -uint64_t AUD_time_stamp_get_elapsed_usec_in (SWVoiceIn *sw, - QEMUAudioTimeStamp *ts); + +void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw); +int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size); +void AUD_set_active_in (SWVoiceIn *sw, int on); +int AUD_is_active_in (SWVoiceIn *sw); + +void AUD_init_time_stamp_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts); +uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts); static inline void *advance (void *p, int incr) { diff --git a/audio/audio_int.h b/audio/audio_int.h index 9d288292a..6d4c32b06 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -24,16 +24,12 @@ #ifndef QEMU_AUDIO_INT_H #define QEMU_AUDIO_INT_H -#include "sys-queue.h" - #ifdef CONFIG_COREAUDIO #define FLOAT_MIXENG /* #define RECIPROCAL */ #endif #include "mixeng.h" -int audio_bug (const char *funcname, int cond); - struct audio_pcm_ops; typedef enum { @@ -69,7 +65,6 @@ struct audio_pcm_info { }; typedef struct HWVoiceOut { - int active; int enabled; int pending_disable; int valid; @@ -78,7 +73,6 @@ typedef struct HWVoiceOut { f_sample *clip; int rpos; - int bufsize; uint64_t ts_helper; st_sample_t *mix_buf; @@ -91,13 +85,11 @@ typedef struct HWVoiceOut { typedef struct HWVoiceIn { int enabled; - int active; struct audio_pcm_info info; t_sample *conv; int wpos; - int bufsize; int total_samples_captured; uint64_t ts_helper; @@ -109,58 +101,6 @@ typedef struct HWVoiceIn { LIST_ENTRY (HWVoiceIn) entries; } HWVoiceIn; -extern struct audio_driver no_audio_driver; -extern struct audio_driver oss_audio_driver; -extern struct audio_driver sdl_audio_driver; -extern struct audio_driver wav_audio_driver; -extern struct audio_driver fmod_audio_driver; -extern struct audio_driver alsa_audio_driver; -extern struct audio_driver coreaudio_audio_driver; -extern struct audio_driver dsound_audio_driver; -extern volume_t nominal_volume; - -struct audio_driver { - const char *name; - const char *descr; - struct audio_option *options; - void *(*init) (void); - void (*fini) (void *); - struct audio_pcm_ops *pcm_ops; - int can_be_default; - int max_voices_out; - int max_voices_in; - int voice_size_out; - int voice_size_in; -}; - -typedef struct AudioState { - int fixed_settings_out; - int fixed_freq_out; - int fixed_channels_out; - int fixed_fmt_out; - int nb_hw_voices_out; - int greedy_out; - - int fixed_settings_in; - int fixed_freq_in; - int fixed_channels_in; - int fixed_fmt_in; - int nb_hw_voices_in; - int greedy_in; - - void *opaque; - struct audio_driver *drv; - - QEMUTimer *ts; - union { - int usec; - int64_t ticks; - } period; - - int plive; -} AudioState; -extern AudioState audio_state; - struct SWVoiceOut { struct audio_pcm_info info; t_sample *conv; @@ -192,22 +132,58 @@ struct SWVoiceIn { LIST_ENTRY (SWVoiceIn) entries; }; +struct audio_driver { + const char *name; + const char *descr; + struct audio_option *options; + void *(*init) (void); + void (*fini) (void *); + struct audio_pcm_ops *pcm_ops; + int can_be_default; + int max_voices_out; + int max_voices_in; + int voice_size_out; + int voice_size_in; +}; + struct audio_pcm_ops { - int (*init_out)(HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt); + int (*init_out)(HWVoiceOut *hw, audsettings_t *as); void (*fini_out)(HWVoiceOut *hw); int (*run_out) (HWVoiceOut *hw); int (*write) (SWVoiceOut *sw, void *buf, int size); int (*ctl_out) (HWVoiceOut *hw, int cmd, ...); - int (*init_in) (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt); + int (*init_in) (HWVoiceIn *hw, audsettings_t *as); void (*fini_in) (HWVoiceIn *hw); int (*run_in) (HWVoiceIn *hw); int (*read) (SWVoiceIn *sw, void *buf, int size); int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); }; -void audio_pcm_init_info (struct audio_pcm_info *info, int freq, - int nchannels, audfmt_e fmt, int swap_endian); +struct AudioState { + struct audio_driver *drv; + void *drv_opaque; + + QEMUTimer *ts; + LIST_HEAD (card_head, QEMUSoundCard) card_head; + LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; + LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; + int nb_hw_voices_out; + int nb_hw_voices_in; +}; + +extern struct audio_driver no_audio_driver; +extern struct audio_driver oss_audio_driver; +extern struct audio_driver sdl_audio_driver; +extern struct audio_driver wav_audio_driver; +extern struct audio_driver fmod_audio_driver; +extern struct audio_driver alsa_audio_driver; +extern struct audio_driver coreaudio_audio_driver; +extern struct audio_driver dsound_audio_driver; +extern volume_t nominal_volume; + +void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as, + int swap_endian); void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len); @@ -217,6 +193,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len); int audio_pcm_hw_get_live_out (HWVoiceOut *hw); int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live); +int audio_bug (const char *funcname, int cond); +void *audio_calloc (const char *funcname, int nmemb, size_t size); + #define VOICE_ENABLE 1 #define VOICE_DISABLE 2 diff --git a/audio/audio_template.h b/audio/audio_template.h index 25ea72fd4..d985c2eef 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -32,6 +32,43 @@ #define SW glue (SWVoice, In) #endif +static int glue (audio_pcm_hw_init_, TYPE) ( + HW *hw, + audsettings_t *as + ) +{ + glue (audio_pcm_hw_free_resources_, TYPE) (hw); + + if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { + return -1; + } + + if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { + dolog ("hw->samples=%d\n", hw->samples); + return -1; + } + + LIST_INIT (&hw->sw_head); +#ifdef DAC + hw->clip = + mixeng_clip +#else + hw->conv = + mixeng_conv +#endif + [hw->info.nchannels == 2] + [hw->info.sign] + [hw->info.swap_endian] + [hw->info.bits == 16]; + + if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { + glue (hw->pcm_ops->fini_, TYPE) (hw); + return -1; + } + + return 0; +} + static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) { glue (audio_pcm_sw_free_resources_, TYPE) (sw); @@ -51,89 +88,86 @@ static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) LIST_REMOVE (sw, entries); } -static void glue (audio_pcm_hw_fini_, TYPE) (HW *hw) +static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp) { - if (hw->active) { - glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); - glue (hw->pcm_ops->fini_, TYPE) (hw); - memset (hw, 0, glue (audio_state.drv->voice_size_, TYPE)); - } -} + HW *hw = *hwp; -static void glue (audio_pcm_hw_gc_, TYPE) (HW *hw) -{ if (!hw->sw_head.lh_first) { - glue (audio_pcm_hw_fini_, TYPE) (hw); + LIST_REMOVE (hw, entries); + glue (s->nb_hw_voices_, TYPE) += 1; + glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); + glue (hw->pcm_ops->fini_, TYPE) (hw); + qemu_free (hw); + *hwp = NULL; } } -static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw) +static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw) { - return hw ? hw->entries.le_next : glue (hw_head_, TYPE).lh_first; + return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first; } -static HW *glue (audio_pcm_hw_find_any_active_, TYPE) (HW *hw) +static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw) { - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { - if (hw->active) { + while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) { + if (hw->enabled) { return hw; } } return NULL; } -static HW *glue (audio_pcm_hw_find_any_active_enabled_, TYPE) (HW *hw) +static HW *glue (audio_pcm_hw_find_any_passive_, TYPE) (AudioState *s) { - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { - if (hw->active && hw->enabled) { - return hw; + if (glue (s->nb_hw_voices_, TYPE)) { + struct audio_driver *drv = s->drv; + + if (audio_bug (AUDIO_FUNC, !drv)) { + dolog ("No host audio driver\n"); + return NULL; } - } - return NULL; -} -static HW *glue (audio_pcm_hw_find_any_passive_, TYPE) (HW *hw) -{ - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { - if (!hw->active) { - return hw; + HW *hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE)); + if (!hw) { + dolog ("Can not allocate voice `%s' size %d\n", + drv->name, glue (drv->voice_size_, TYPE)); } + + LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); + glue (s->nb_hw_voices_, TYPE) -= 1; + return hw; } + return NULL; } static HW *glue (audio_pcm_hw_find_specific_, TYPE) ( + AudioState *s, HW *hw, - int freq, - int nchannels, - audfmt_e fmt + audsettings_t *as ) { - while ((hw = glue (audio_pcm_hw_find_any_active_, TYPE) (hw))) { - if (audio_pcm_info_eq (&hw->info, freq, nchannels, fmt)) { + while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) { + if (audio_pcm_info_eq (&hw->info, as)) { return hw; } } return NULL; } -static HW *glue (audio_pcm_hw_add_new_, TYPE) ( - int freq, - int nchannels, - audfmt_e fmt - ) +static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) { HW *hw; - hw = glue (audio_pcm_hw_find_any_passive_, TYPE) (NULL); + hw = glue (audio_pcm_hw_find_any_passive_, TYPE) (s); if (hw) { - hw->pcm_ops = audio_state.drv->pcm_ops; + hw->pcm_ops = s->drv->pcm_ops; if (!hw->pcm_ops) { return NULL; } - if (glue (audio_pcm_hw_init_, TYPE) (hw, freq, nchannels, fmt)) { - glue (audio_pcm_hw_gc_, TYPE) (hw); + if (glue (audio_pcm_hw_init_, TYPE) (hw, as)) { + glue (audio_pcm_hw_gc_, TYPE) (s, &hw); return NULL; } else { @@ -144,66 +178,62 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) ( return NULL; } -static HW *glue (audio_pcm_hw_add_, TYPE) ( - int freq, - int nchannels, - audfmt_e fmt - ) +static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as) { HW *hw; - if (glue (audio_state.greedy_, TYPE)) { - hw = glue (audio_pcm_hw_add_new_, TYPE) (freq, nchannels, fmt); + if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) { + hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); if (hw) { return hw; } } - hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, freq, nchannels, fmt); + hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as); if (hw) { return hw; } - hw = glue (audio_pcm_hw_add_new_, TYPE) (freq, nchannels, fmt); + hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); if (hw) { return hw; } - return glue (audio_pcm_hw_find_any_active_, TYPE) (NULL); + return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL); } static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( - const char *name, - int freq, - int nchannels, - audfmt_e fmt + AudioState *s, + const char *sw_name, + audsettings_t *as ) { SW *sw; HW *hw; - int hw_freq = freq; - int hw_nchannels = nchannels; - int hw_fmt = fmt; + audsettings_t hw_as; - if (glue (audio_state.fixed_settings_, TYPE)) { - hw_freq = glue (audio_state.fixed_freq_, TYPE); - hw_nchannels = glue (audio_state.fixed_channels_, TYPE); - hw_fmt = glue (audio_state.fixed_fmt_, TYPE); + if (glue (conf.fixed_, TYPE).enabled) { + hw_as = glue (conf.fixed_, TYPE).settings; + } + else { + hw_as = *as; } - sw = qemu_mallocz (sizeof (*sw)); + sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); if (!sw) { + dolog ("Could not allocate soft voice `%s' (%d bytes)\n", + sw_name ? sw_name : "unknown", sizeof (*sw)); goto err1; } - hw = glue (audio_pcm_hw_add_, TYPE) (hw_freq, hw_nchannels, hw_fmt); + hw = glue (audio_pcm_hw_add_, TYPE) (s, &hw_as); if (!hw) { goto err2; } glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, freq, nchannels, fmt)) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) { goto err3; } @@ -211,67 +241,86 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( err3: glue (audio_pcm_hw_del_sw_, TYPE) (sw); - glue (audio_pcm_hw_gc_, TYPE) (hw); + glue (audio_pcm_hw_gc_, TYPE) (s, &hw); err2: qemu_free (sw); err1: return NULL; } -void glue (AUD_close_, TYPE) (SW *sw) +static void glue (audio_close_, TYPE) (AudioState *s, SW *sw) +{ + glue (audio_pcm_sw_fini_, TYPE) (sw); + glue (audio_pcm_hw_del_sw_, TYPE) (sw); + glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw); + qemu_free (sw); +} +void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw) { if (sw) { - glue (audio_pcm_sw_fini_, TYPE) (sw); - glue (audio_pcm_hw_del_sw_, TYPE) (sw); - glue (audio_pcm_hw_gc_, TYPE) (sw->hw); - qemu_free (sw); + if (audio_bug (AUDIO_FUNC, !card || !card->audio)) { + dolog ("card=%p card->audio=%p\n", + card, card ? card->audio : NULL); + return; + } + + glue (audio_close_, TYPE) (card->audio, sw); } } SW *glue (AUD_open_, TYPE) ( + QEMUSoundCard *card, SW *sw, const char *name, void *callback_opaque , audio_callback_fn_t callback_fn, - int freq, - int nchannels, - audfmt_e fmt + audsettings_t *as ) { + AudioState *s; #ifdef DAC int live = 0; SW *old_sw = NULL; #endif - if (!callback_fn) { - dolog ("No callback specifed for voice `%s'\n", name); + ldebug ("open %s, freq %d, nchannels %d, fmt %d\n", + name, as->freq, as->nchannels, as->fmt); + + if (audio_bug (AUDIO_FUNC, + !card || !card->audio || !name || !callback_fn || !as)) { + dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n", + card, card ? card->audio : NULL, name, callback_fn, as); goto fail; } - if (nchannels != 1 && nchannels != 2) { - dolog ("Bogus channel count %d for voice `%s'\n", nchannels, name); + s = card->audio; + + if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) { + audio_print_settings (as); goto fail; } - if (!audio_state.drv) { - dolog ("No audio driver defined\n"); + if (audio_bug (AUDIO_FUNC, !s->drv)) { + dolog ("Can not open `%s' (no host audio driver)\n", name); goto fail; } - if (sw && audio_pcm_info_eq (&sw->info, freq, nchannels, fmt)) { + if (sw && audio_pcm_info_eq (&sw->info, as)) { return sw; } #ifdef DAC - if (audio_state.plive && sw && (!sw->active && !sw->empty)) { + if (conf.plive && sw && (!sw->active && !sw->empty)) { live = sw->total_hw_samples_mixed; #ifdef DEBUG_PLIVE - dolog ("Replacing voice %s with %d live samples\n", sw->name, live); + dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live); dolog ("Old %s freq %d, bits %d, channels %d\n", - sw->name, sw->info.freq, sw->info.bits, sw->info.nchannels); + SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); dolog ("New %s freq %d, bits %d, channels %d\n", - name, freq, (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, + name, + freq, + (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, nchannels); #endif @@ -283,8 +332,8 @@ SW *glue (AUD_open_, TYPE) ( } #endif - if (!glue (audio_state.fixed_settings_, TYPE) && sw) { - glue (AUD_close_, TYPE) (sw); + if (!glue (conf.fixed_, TYPE).enabled && sw) { + glue (AUD_close_, TYPE) (card, sw); sw = NULL; } @@ -292,30 +341,19 @@ SW *glue (AUD_open_, TYPE) ( HW *hw = sw->hw; if (!hw) { - dolog ("Internal logic error voice %s has no hardware store\n", - name); + dolog ("Internal logic error voice `%s' has no hardware store\n", + SW_NAME (sw)); goto fail; } - if (glue (audio_pcm_sw_init_, TYPE) ( - sw, - hw, - name, - freq, - nchannels, - fmt - )) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) { goto fail; } } else { - sw = glue (audio_pcm_create_voice_pair_, TYPE) ( - name, - freq, - nchannels, - fmt); + sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as); if (!sw) { - dolog ("Failed to create voice %s\n", name); + dolog ("Failed to create voice `%s'\n", name); goto fail; } } @@ -349,7 +387,7 @@ SW *glue (AUD_open_, TYPE) ( return sw; fail: - glue (AUD_close_, TYPE) (sw); + glue (AUD_close_, TYPE) (card, sw); return NULL; } @@ -367,10 +405,7 @@ void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) ts->old_ts = sw->hw->ts_helper; } -uint64_t glue (AUD_time_stamp_get_elapsed_usec_, TYPE) ( - SW *sw, - QEMUAudioTimeStamp *ts - ) +uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) { uint64_t delta, cur_ts, old_ts; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index eee12386c..855193868 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -31,8 +31,6 @@ #define AUDIO_CAP "coreaudio" #include "audio_int.h" -#define DEVICE_BUFFER_FRAMES (512) - struct { int buffer_frames; } conf = { @@ -132,7 +130,7 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 ( { va_list ap; - AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); va_start (ap, fmt); AUD_vlog (AUDIO_CAP, fmt, ap); @@ -147,7 +145,7 @@ static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name) err = pthread_mutex_lock (&core->mutex); if (err) { - dolog ("Can not lock voice for %s\nReason: %s\n", + dolog ("Could not lock voice for %s\nReason: %s\n", fn_name, strerror (err)); return -1; } @@ -160,7 +158,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name) err = pthread_mutex_unlock (&core->mutex); if (err) { - dolog ("Can not unlock voice for %s\nReason: %s\n", + dolog ("Could not unlock voice for %s\nReason: %s\n", fn_name, strerror (err)); return -1; } @@ -268,8 +266,7 @@ static int coreaudio_write (SWVoiceOut *sw, void *buf, int len) return audio_pcm_sw_write (sw, buf, len); } -static int coreaudio_init_out (HWVoiceOut *hw, int freq, - int nchannels, audfmt_e fmt) +static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) { OSStatus status; coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; @@ -282,25 +279,22 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, /* create mutex */ err = pthread_mutex_init(&core->mutex, NULL); if (err) { - dolog("Can not create mutex\nReason: %s\n", strerror (err)); + dolog("Could not create mutex\nReason: %s\n", strerror (err)); return -1; } - if (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) { + if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { bits = 16; endianess = 1; } audio_pcm_init_info ( &hw->info, - freq, - nchannels, - fmt, + as, /* Following is irrelevant actually since we do not use mixengs clipping routines */ audio_need_to_swap_endian (endianess) ); - hw->bufsize = 4 * conf.buffer_frames * nchannels * bits; /* open default output device */ propertySize = sizeof(core->outputDeviceID); @@ -310,18 +304,18 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, &core->outputDeviceID); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, - "Can not get default output Device\n"); + "Could not get default output Device\n"); return -1; } if (core->outputDeviceID == kAudioDeviceUnknown) { - dolog ("Can not initialize %s - Unknown Audiodevice\n", typ); + dolog ("Could not initialize %s - Unknown Audiodevice\n", typ); return -1; } /* set Buffersize to conf.buffer_frames frames */ propertySize = sizeof(core->audioDevicePropertyBufferSize); core->audioDevicePropertyBufferSize = - conf.buffer_frames * sizeof(float) * 2; + conf.buffer_frames * sizeof(float) << (as->nchannels == 2); status = AudioDeviceSetProperty( core->outputDeviceID, NULL, @@ -332,7 +326,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, &core->audioDevicePropertyBufferSize); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, - "Can not set device buffer size %d\n", + "Could not set device buffer size %d\n", kAudioDevicePropertyBufferSize); return -1; } @@ -347,9 +341,11 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, &propertySize, &core->audioDevicePropertyBufferSize); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Can not get device buffer size\n"); + coreaudio_logerr2 (status, typ, "Could not get device buffer size\n"); return -1; } + hw->samples = (core->audioDevicePropertyBufferSize / sizeof (float)) + >> (as->nchannels == 2); /* get StreamFormat */ propertySize = sizeof(core->outputStreamBasicDescription); @@ -362,13 +358,13 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, &core->outputStreamBasicDescription); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, - "Can not get Device Stream properties\n"); + "Could not get Device Stream properties\n"); core->outputDeviceID = kAudioDeviceUnknown; return -1; } /* set Samplerate */ - core->outputStreamBasicDescription.mSampleRate = (Float64)freq; + core->outputStreamBasicDescription.mSampleRate = (Float64)as->freq; propertySize = sizeof(core->outputStreamBasicDescription); status = AudioDeviceSetProperty( core->outputDeviceID, @@ -379,7 +375,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, propertySize, &core->outputStreamBasicDescription); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Can not set samplerate %d\n", freq); + coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", freq); core->outputDeviceID = kAudioDeviceUnknown; return -1; } @@ -387,7 +383,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, /* set Callback */ status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Can not set IOProc\n"); + coreaudio_logerr2 (status, typ, "Could not set IOProc\n"); core->outputDeviceID = kAudioDeviceUnknown; return -1; } @@ -396,7 +392,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, int freq, if (!core->isPlaying) { status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Can not start playback\n"); + coreaudio_logerr2 (status, typ, "Could not start playback\n"); AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); core->outputDeviceID = kAudioDeviceUnknown; return -1; @@ -417,7 +413,7 @@ static void coreaudio_fini_out (HWVoiceOut *hw) if (core->isPlaying) { status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Can not stop playback\n"); + coreaudio_logerr (status, "Could not stop playback\n"); } core->isPlaying = 0; } @@ -425,14 +421,14 @@ static void coreaudio_fini_out (HWVoiceOut *hw) /* remove callback */ status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Can not remove IOProc\n"); + coreaudio_logerr (status, "Could not remove IOProc\n"); } core->outputDeviceID = kAudioDeviceUnknown; /* destroy mutex */ err = pthread_mutex_destroy(&core->mutex); if (err) { - dolog("Can not destroy mutex\nReason: %s\n", strerror (err)); + dolog("Could not destroy mutex\nReason: %s\n", strerror (err)); } } @@ -447,7 +443,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) if (!core->isPlaying) { status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Can not unpause playback\n"); + coreaudio_logerr (status, "Could not unpause playback\n"); } core->isPlaying = 1; } @@ -458,7 +454,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) if (core->isPlaying) { status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Can not pause playback\n"); + coreaudio_logerr (status, "Could not pause playback\n"); } core->isPlaying = 0; } diff --git a/audio/dsound_template.h b/audio/dsound_template.h index a04806eae..38ba5b9ca 100644 --- a/audio/dsound_template.h +++ b/audio/dsound_template.h @@ -47,7 +47,7 @@ static int glue (dsound_unlock_, TYPE) ( hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); if (FAILED (hr)) { - dsound_logerr (hr, "Can not unlock " NAME "\n"); + dsound_logerr (hr, "Could not unlock " NAME "\n"); return -1; } @@ -93,13 +93,13 @@ static int glue (dsound_lock_, TYPE) ( #ifndef DSBTYPE_IN if (hr == DSERR_BUFFERLOST) { if (glue (dsound_restore_, TYPE) (buf)) { - dsound_logerr (hr, "Can not lock " NAME "\n"); + dsound_logerr (hr, "Could not lock " NAME "\n"); goto fail; } continue; } #endif - dsound_logerr (hr, "Can not lock " NAME "\n"); + dsound_logerr (hr, "Could not lock " NAME "\n"); goto fail; } @@ -158,38 +158,28 @@ static void dsound_fini_out (HWVoiceOut *hw) if (ds->FIELD) { hr = glue (IFACE, _Stop) (ds->FIELD); if (FAILED (hr)) { - dsound_logerr (hr, "Can not stop " NAME "\n"); + dsound_logerr (hr, "Could not stop " NAME "\n"); } hr = glue (IFACE, _Release) (ds->FIELD); if (FAILED (hr)) { - dsound_logerr (hr, "Can not release " NAME "\n"); + dsound_logerr (hr, "Could not release " NAME "\n"); } ds->FIELD = NULL; } } #ifdef DSBTYPE_IN -static int dsound_init_in ( - HWVoiceIn *hw, - int freq, - int nchannels, - audfmt_e fmt - ) +static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as) #else -static int dsound_init_out ( - HWVoiceOut *hw, - int freq, - int nchannels, - audfmt_e fmt - ) +static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as) #endif { int err; HRESULT hr; dsound *s = &glob_dsound; WAVEFORMATEX wfx; - struct full_fmt full_fmt; + audsettings_t obt_as; #ifdef DSBTYPE_IN const char *typ = "ADC"; DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; @@ -202,10 +192,7 @@ static int dsound_init_out ( DSBCAPS bc; #endif - full_fmt.freq = freq; - full_fmt.nchannels = nchannels; - full_fmt.fmt = fmt; - err = waveformat_from_full_fmt (&wfx, &full_fmt); + err = waveformat_from_audio_settings (&wfx, as); if (err) { return -1; } @@ -233,18 +220,13 @@ static int dsound_init_out ( #endif if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Can not create " NAME "\n"); + dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); return -1; } - hr = glue (IFACE, _GetFormat) ( - ds->FIELD, - &wfx, - sizeof (wfx), - NULL - ); + hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Can not get " NAME " format\n"); + dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); goto fail0; } @@ -258,31 +240,33 @@ static int dsound_init_out ( hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Can not get " NAME " format\n"); + dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); goto fail0; } - err = waveformat_to_full_fmt (&wfx, &full_fmt); + err = waveformat_to_audio_settings (&wfx, &obt_as); if (err) { goto fail0; } ds->first_time = 1; - hw->bufsize = bc.dwBufferBytes; - audio_pcm_init_info ( - &hw->info, - full_fmt.freq, - full_fmt.nchannels, - full_fmt.fmt, - audio_need_to_swap_endian (0) - ); + + audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0)); + + if (bc.dwBufferBytes & hw->info.align) { + dolog ( + "GetCaps returned misaligned buffer size %ld, alignment %d\n", + bc.dwBufferBytes, hw->info.align + 1 + ); + } + hw->samples = bc.dwBufferBytes >> hw->info.shift; #ifdef DEBUG_DSOUND dolog ("caps %ld, desc %ld\n", bc.dwBufferBytes, bd.dwBufferBytes); dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", - hw->bufsize, full_fmt.freq, full_fmt.nchannels, full_fmt.fmt); + hw->bufsize, settings.freq, settings.nchannels, settings.fmt); #endif return 0; diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index 64b84174d..63c5a5057 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -37,12 +37,6 @@ /* #define DEBUG_DSOUND */ -struct full_fmt { - int freq; - int nchannels; - audfmt_e fmt; -}; - static struct { int lock_retries; int restore_retries; @@ -50,7 +44,7 @@ static struct { int set_primary; int bufsize_in; int bufsize_out; - struct full_fmt full_fmt; + audsettings_t settings; int latency_millis; } conf = { 1, @@ -71,7 +65,7 @@ typedef struct { LPDIRECTSOUND dsound; LPDIRECTSOUNDCAPTURE dsound_capture; LPDIRECTSOUNDBUFFER dsound_primary_buffer; - struct full_fmt fmt; + audsettings_t settings; } dsound; static dsound glob_dsound; @@ -259,7 +253,7 @@ static void GCC_FMT_ATTR (3, 4) dsound_logerr2 ( { va_list ap; - AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); va_start (ap, fmt); AUD_vlog (AUDIO_CAP, fmt, ap); va_end (ap); @@ -301,7 +295,7 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb) continue; default: - dsound_logerr (hr, "Can not restore playback buffer\n"); + dsound_logerr (hr, "Could not restore playback buffer\n"); return -1; } } @@ -310,19 +304,18 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb) return -1; } -static int waveformat_from_full_fmt (WAVEFORMATEX *wfx, - struct full_fmt *full_fmt) +static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as) { memset (wfx, 0, sizeof (*wfx)); wfx->wFormatTag = WAVE_FORMAT_PCM; - wfx->nChannels = full_fmt->nchannels; - wfx->nSamplesPerSec = full_fmt->freq; - wfx->nAvgBytesPerSec = full_fmt->freq << (full_fmt->nchannels == 2); - wfx->nBlockAlign = 1 << (full_fmt->nchannels == 2); + wfx->nChannels = as->nchannels; + wfx->nSamplesPerSec = as->freq; + wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2); + wfx->nBlockAlign = 1 << (as->nchannels == 2); wfx->cbSize = 0; - switch (full_fmt->fmt) { + switch (as->fmt) { case AUD_FMT_S8: wfx->wBitsPerSample = 8; break; @@ -344,16 +337,14 @@ static int waveformat_from_full_fmt (WAVEFORMATEX *wfx, break; default: - dolog ("Internal logic error: Bad audio format %d\n", - full_fmt->freq); + dolog ("Internal logic error: Bad audio format %d\n", as->freq); return -1; } return 0; } -static int waveformat_to_full_fmt (WAVEFORMATEX *wfx, - struct full_fmt *full_fmt) +static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as) { if (wfx->wFormatTag != WAVE_FORMAT_PCM) { dolog ("Invalid wave format, tag is not PCM, but %d\n", @@ -365,15 +356,15 @@ static int waveformat_to_full_fmt (WAVEFORMATEX *wfx, dolog ("Invalid wave format, frequency is zero\n"); return -1; } - full_fmt->freq = wfx->nSamplesPerSec; + as->freq = wfx->nSamplesPerSec; switch (wfx->nChannels) { case 1: - full_fmt->nchannels = 1; + as->nchannels = 1; break; case 2: - full_fmt->nchannels = 2; + as->nchannels = 2; break; default: @@ -386,11 +377,11 @@ static int waveformat_to_full_fmt (WAVEFORMATEX *wfx, switch (wfx->wBitsPerSample) { case 8: - full_fmt->fmt = AUD_FMT_U8; + as->fmt = AUD_FMT_U8; break; case 16: - full_fmt->fmt = AUD_FMT_S16; + as->fmt = AUD_FMT_S16; break; default: @@ -415,7 +406,7 @@ static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp) for (i = 0; i < conf.getstatus_retries; ++i) { hr = IDirectSoundBuffer_GetStatus (dsb, statusp); if (FAILED (hr)) { - dsound_logerr (hr, "Can not get playback buffer status\n"); + dsound_logerr (hr, "Could not get playback buffer status\n"); return -1; } @@ -438,7 +429,7 @@ static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb, hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp); if (FAILED (hr)) { - dsound_logerr (hr, "Can not get capture buffer status\n"); + dsound_logerr (hr, "Could not get capture buffer status\n"); return -1; } @@ -520,7 +511,7 @@ static void dsound_close (dsound *s) if (s->dsound_primary_buffer) { hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer); if (FAILED (hr)) { - dsound_logerr (hr, "Can not release primary buffer\n"); + dsound_logerr (hr, "Could not release primary buffer\n"); } s->dsound_primary_buffer = NULL; } @@ -542,7 +533,7 @@ static int dsound_open (dsound *s) ); if (FAILED (hr)) { - dsound_logerr (hr, "Can not set cooperative level for window %p\n", + dsound_logerr (hr, "Could not set cooperative level for window %p\n", hwnd); return -1; } @@ -551,7 +542,7 @@ static int dsound_open (dsound *s) return 0; } - err = waveformat_from_full_fmt (&wfx, &conf.full_fmt); + err = waveformat_from_audio_settings (&wfx, &conf.settings); if (err) { return -1; } @@ -569,13 +560,13 @@ static int dsound_open (dsound *s) NULL ); if (FAILED (hr)) { - dsound_logerr (hr, "Can not create primary playback buffer\n"); + dsound_logerr (hr, "Could not create primary playback buffer\n"); return -1; } hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx); if (FAILED (hr)) { - dsound_logerr (hr, "Can not set primary playback buffer format\n"); + dsound_logerr (hr, "Could not set primary playback buffer format\n"); } hr = IDirectSoundBuffer_GetFormat ( @@ -585,7 +576,7 @@ static int dsound_open (dsound *s) NULL ); if (FAILED (hr)) { - dsound_logerr (hr, "Can not get primary playback buffer format\n"); + dsound_logerr (hr, "Could not get primary playback buffer format\n"); goto fail0; } @@ -594,7 +585,7 @@ static int dsound_open (dsound *s) print_wave_format (&wfx); #endif - err = waveformat_to_full_fmt (&wfx, &s->fmt); + err = waveformat_to_audio_settings (&wfx, &s->settings); if (err) { goto fail0; } @@ -625,7 +616,7 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) } if (status & DSBSTATUS_PLAYING) { - dolog ("warning: voice is already playing\n"); + dolog ("warning: Voice is already playing\n"); return 0; } @@ -633,7 +624,7 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING); if (FAILED (hr)) { - dsound_logerr (hr, "Can not start playing buffer\n"); + dsound_logerr (hr, "Could not start playing buffer\n"); return -1; } break; @@ -646,12 +637,12 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) if (status & DSBSTATUS_PLAYING) { hr = IDirectSoundBuffer_Stop (dsb); if (FAILED (hr)) { - dsound_logerr (hr, "Can not stop playing buffer\n"); + dsound_logerr (hr, "Could not stop playing buffer\n"); return -1; } } else { - dolog ("warning: voice is not playing\n"); + dolog ("warning: Voice is not playing\n"); } break; } @@ -675,6 +666,7 @@ static int dsound_run_out (HWVoiceOut *hw) DWORD decr; DWORD wpos, ppos, old_pos; LPVOID p1, p2; + int bufsize; if (!dsb) { dolog ("Attempt to run empty with playback buffer\n"); @@ -682,6 +674,7 @@ static int dsound_run_out (HWVoiceOut *hw) } hwshift = hw->info.shift; + bufsize = hw->samples << hwshift; live = audio_pcm_hw_get_live_out (hw); @@ -691,7 +684,7 @@ static int dsound_run_out (HWVoiceOut *hw) ds->first_time ? &wpos : NULL ); if (FAILED (hr)) { - dsound_logerr (hr, "Can not get playback buffer position\n"); + dsound_logerr (hr, "Could not get playback buffer position\n"); return 0; } @@ -699,13 +692,14 @@ static int dsound_run_out (HWVoiceOut *hw) if (ds->first_time) { if (conf.latency_millis) { - DWORD cur_blat = audio_ring_dist (wpos, ppos, hw->bufsize); + DWORD cur_blat; + cur_blat = audio_ring_dist (wpos, ppos, bufsize); ds->first_time = 0; old_pos = wpos; old_pos += millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat; - old_pos %= hw->bufsize; + old_pos %= bufsize; old_pos &= ~hw->info.align; } else { @@ -734,14 +728,14 @@ static int dsound_run_out (HWVoiceOut *hw) len = ppos - old_pos; } else { - if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->bufsize))) { - len = hw->bufsize - old_pos + ppos; + if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) { + len = bufsize - old_pos + ppos; } } - if (audio_bug (AUDIO_FUNC, len < 0 || len > hw->bufsize)) { - dolog ("len=%d hw->bufsize=%d old_pos=%ld ppos=%ld\n", - len, hw->bufsize, old_pos, ppos); + if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) { + dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n", + len, bufsize, old_pos, ppos); return 0; } @@ -779,7 +773,7 @@ static int dsound_run_out (HWVoiceOut *hw) } dsound_unlock_out (dsb, p1, p2, blen1, blen2); - ds->old_pos = (old_pos + (decr << hwshift)) % hw->bufsize; + ds->old_pos = (old_pos + (decr << hwshift)) % bufsize; #ifdef DEBUG_DSOUND ds->mixed += decr << hwshift; @@ -812,7 +806,7 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) } if (status & DSCBSTATUS_CAPTURING) { - dolog ("warning: voice is already capturing\n"); + dolog ("warning: Voice is already capturing\n"); return 0; } @@ -820,7 +814,7 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING); if (FAILED (hr)) { - dsound_logerr (hr, "Can not start capturing\n"); + dsound_logerr (hr, "Could not start capturing\n"); return -1; } break; @@ -833,12 +827,12 @@ static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) if (status & DSCBSTATUS_CAPTURING) { hr = IDirectSoundCaptureBuffer_Stop (dscb); if (FAILED (hr)) { - dsound_logerr (hr, "Can not stop capturing\n"); + dsound_logerr (hr, "Could not stop capturing\n"); return -1; } } else { - dolog ("warning: voice is not capturing\n"); + dolog ("warning: Voice is not capturing\n"); } break; } @@ -883,21 +877,21 @@ static int dsound_run_in (HWVoiceIn *hw) ds->first_time ? &rpos : NULL ); if (FAILED (hr)) { - dsound_logerr (hr, "Can not get capture buffer position\n"); + dsound_logerr (hr, "Could not get capture buffer position\n"); return 0; } if (ds->first_time) { ds->first_time = 0; if (rpos & hw->info.align) { - ldebug ("warning: misaligned capture read position %ld(%d)\n", + ldebug ("warning: Misaligned capture read position %ld(%d)\n", rpos, hw->info.align); } hw->wpos = rpos >> hwshift; } if (cpos & hw->info.align) { - ldebug ("warning: misaligned capture position %ld(%d)\n", + ldebug ("warning: Misaligned capture position %ld(%d)\n", cpos, hw->info.align); } cpos >>= hwshift; @@ -951,7 +945,7 @@ static void dsound_audio_fini (void *opaque) hr = IDirectSound_Release (s->dsound); if (FAILED (hr)) { - dsound_logerr (hr, "Can not release DirectSound\n"); + dsound_logerr (hr, "Could not release DirectSound\n"); } s->dsound = NULL; @@ -961,7 +955,7 @@ static void dsound_audio_fini (void *opaque) hr = IDirectSoundCapture_Release (s->dsound_capture); if (FAILED (hr)) { - dsound_logerr (hr, "Can not release DirectSoundCapture\n"); + dsound_logerr (hr, "Could not release DirectSoundCapture\n"); } s->dsound_capture = NULL; } @@ -974,7 +968,7 @@ static void *dsound_audio_init (void) hr = CoInitialize (NULL); if (FAILED (hr)) { - dsound_logerr (hr, "Can not initialize COM\n"); + dsound_logerr (hr, "Could not initialize COM\n"); return NULL; } @@ -986,13 +980,13 @@ static void *dsound_audio_init (void) (void **) &s->dsound ); if (FAILED (hr)) { - dsound_logerr (hr, "Can not create DirectSound instance\n"); + dsound_logerr (hr, "Could not create DirectSound instance\n"); return NULL; } hr = IDirectSound_Initialize (s->dsound, NULL); if (FAILED (hr)) { - dsound_logerr (hr, "Can not initialize DirectSound\n"); + dsound_logerr (hr, "Could not initialize DirectSound\n"); return NULL; } @@ -1004,16 +998,16 @@ static void *dsound_audio_init (void) (void **) &s->dsound_capture ); if (FAILED (hr)) { - dsound_logerr (hr, "Can not create DirectSoundCapture instance\n"); + dsound_logerr (hr, "Could not create DirectSoundCapture instance\n"); } else { hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL); if (FAILED (hr)) { - dsound_logerr (hr, "Can not initialize DirectSoundCapture\n"); + dsound_logerr (hr, "Could not initialize DirectSoundCapture\n"); hr = IDirectSoundCapture_Release (s->dsound_capture); if (FAILED (hr)) { - dsound_logerr (hr, "Can not release DirectSoundCapture\n"); + dsound_logerr (hr, "Could not release DirectSoundCapture\n"); } s->dsound_capture = NULL; } @@ -1039,11 +1033,11 @@ static struct audio_option dsound_options[] = { "Set the parameters of primary buffer", NULL, 0}, {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis, "(undocumented)", NULL, 0}, - {"PRIMARY_FREQ", AUD_OPT_INT, &conf.full_fmt.freq, + {"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq, "Primary buffer frequency", NULL, 0}, - {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.full_fmt.nchannels, + {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels, "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0}, - {"PRIMARY_FMT", AUD_OPT_FMT, &conf.full_fmt.fmt, + {"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt, "Primary buffer format", NULL, 0}, {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out, "(undocumented)", NULL, 0}, diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index 36b8d47c4..072d8a830 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -78,7 +78,7 @@ static void GCC_FMT_ATTR (2, 3) fmod_logerr2 ( { va_list ap; - AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); va_start (ap, fmt); AUD_vlog (AUDIO_CAP, fmt, ap); @@ -356,17 +356,17 @@ static void fmod_fini_out (HWVoiceOut *hw) } } -static int fmod_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as) { int bits16, mode, channel; FMODVoiceOut *fmd = (FMODVoiceOut *) hw; - mode = aud_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0); + mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); fmd->fmod_sample = FSOUND_Sample_Alloc ( FSOUND_FREE, /* index */ conf.nb_samples, /* length */ mode, /* mode */ - freq, /* freq */ + as->freq, /* freq */ 255, /* volume */ 128, /* pan */ 255 /* priority */ @@ -386,10 +386,9 @@ static int fmod_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) fmd->channel = channel; /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, freq, nchannels, fmt, - audio_need_to_swap_endian (0)); + audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); bits16 = (mode & FSOUND_16BITS) != 0; - hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16; + hw->samples = conf.nb_samples; return 0; } @@ -417,7 +416,7 @@ static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...) return 0; } -static int fmod_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) +static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as) { int bits16, mode; FMODVoiceIn *fmd = (FMODVoiceIn *) hw; @@ -426,12 +425,12 @@ static int fmod_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) return -1; } - mode = aud_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0); + mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); fmd->fmod_sample = FSOUND_Sample_Alloc ( FSOUND_FREE, /* index */ conf.nb_samples, /* length */ mode, /* mode */ - freq, /* freq */ + as->freq, /* freq */ 255, /* volume */ 128, /* pan */ 255 /* priority */ @@ -443,10 +442,9 @@ static int fmod_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt) } /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, freq, nchannels, fmt, - audio_need_to_swap_endian (0)); + audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); bits16 = (mode & FSOUND_16BITS) != 0; - hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16; + hw->samples = conf.nb_samples; return 0; } @@ -479,7 +477,7 @@ static int fmod_run_in (HWVoiceIn *hw) new_pos = FSOUND_Record_GetPosition (); if (new_pos < 0) { - fmod_logerr ("Can not get recording position\n"); + fmod_logerr ("Could not get recording position\n"); return 0; } diff --git a/audio/mixeng.c b/audio/mixeng.c index d43c5e59d..14e37ae16 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -228,21 +228,22 @@ f_sample *mixeng_clip[2][2][2][2] = { */ /* Private data */ -typedef struct ratestuff { +struct rate { uint64_t opos; uint64_t opos_inc; uint32_t ipos; /* position in the input stream (integer) */ st_sample_t ilast; /* last sample in the input stream */ -} *rate_t; +}; /* * Prepare processing. */ void *st_rate_start (int inrate, int outrate) { - rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff)); + struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate)); if (!rate) { + dolog ("Could not allocate resampler (%d bytes)\n", sizeof (*rate)); return NULL; } diff --git a/audio/noaudio.c b/audio/noaudio.c index e7936cc7b..aa3581168 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -67,11 +67,10 @@ static int no_write (SWVoiceOut *sw, void *buf, int len) return audio_pcm_sw_write (sw, buf, len); } -static int no_init_out (HWVoiceOut *hw, int freq, - int nchannels, audfmt_e fmt) +static int no_init_out (HWVoiceOut *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, freq, nchannels, fmt, 0); - hw->bufsize = 4096; + audio_pcm_init_info (&hw->info, as, 0); + hw->samples = 1024; return 0; } @@ -87,11 +86,10 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...) return 0; } -static int no_init_in (HWVoiceIn *hw, int freq, - int nchannels, audfmt_e fmt) +static int no_init_in (HWVoiceIn *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, freq, nchannels, fmt, 0); - hw->bufsize = 4096; + audio_pcm_init_info (&hw->info, as, 0); + hw->samples = 1024; return 0; } diff --git a/audio/ossaudio.c b/audio/ossaudio.c index ff1a03494..507274249 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -91,7 +91,7 @@ static void GCC_FMT_ATTR (3, 4) oss_logerr2 ( { va_list ap; - AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ); + AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); va_start (ap, fmt); AUD_vlog (AUDIO_CAP, fmt, ap); @@ -179,7 +179,7 @@ static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness) return 0; } -#ifdef DEBUG_MISMATCHES +#if defined DEBUG_MISMATCHES || defined DEBUG static void oss_dump_info (struct oss_params *req, struct oss_params *obt) { dolog ("parameter | requested value | obtained value\n"); @@ -253,16 +253,16 @@ static int oss_open (int in, struct oss_params *req, obt->fragsize = abinfo.fragsize; *pfd = fd; +#ifdef DEBUG_MISMATCHES if ((req->fmt != obt->fmt) || (req->nchannels != obt->nchannels) || (req->freq != obt->freq) || (req->fragsize != obt->fragsize) || (req->nfrags != obt->nfrags)) { -#ifdef DEBUG_MISMATCHES dolog ("Audio parameters mismatch\n"); oss_dump_info (req, obt); -#endif } +#endif #ifdef DEBUG oss_dump_info (req, obt); @@ -283,12 +283,15 @@ static int oss_run_out (HWVoiceOut *hw) st_sample_t *src; struct audio_buf_info abinfo; struct count_info cntinfo; + int bufsize; live = audio_pcm_hw_get_live_out (hw); if (!live) { return 0; } + bufsize = hw->samples << hw->info.shift; + if (oss->mmapped) { int bytes; @@ -300,7 +303,7 @@ static int oss_run_out (HWVoiceOut *hw) if (cntinfo.ptr == oss->old_optr) { if (abs (hw->samples - live) < 64) { - dolog ("warning: overrun\n"); + dolog ("warning: Overrun\n"); } return 0; } @@ -309,7 +312,7 @@ static int oss_run_out (HWVoiceOut *hw) bytes = cntinfo.ptr - oss->old_optr; } else { - bytes = hw->bufsize + cntinfo.ptr - oss->old_optr; + bytes = bufsize + cntinfo.ptr - oss->old_optr; } decr = audio_MIN (bytes >> hw->info.shift, live); @@ -321,9 +324,9 @@ static int oss_run_out (HWVoiceOut *hw) return 0; } - if (abinfo.bytes < 0 || abinfo.bytes > hw->bufsize) { - ldebug ("warning: invalid available size, size=%d bufsize=%d\n", - abinfo.bytes, hw->bufsize); + if (abinfo.bytes < 0 || abinfo.bytes > bufsize) { + ldebug ("warning: Invalid available size, size=%d bufsize=%d\n", + abinfo.bytes, bufsize); return 0; } @@ -362,7 +365,7 @@ static int oss_run_out (HWVoiceOut *hw) int wsamples = written >> hw->info.shift; int wbytes = wsamples << hw->info.shift; if (wbytes != written) { - dolog ("warning: misaligned write %d (requested %d), " + dolog ("warning: Misaligned write %d (requested %d), " "alignment %d\n", wbytes, written, hw->info.align + 1); } @@ -396,10 +399,10 @@ static void oss_fini_out (HWVoiceOut *hw) if (oss->pcm_buf) { if (oss->mmapped) { - err = munmap (oss->pcm_buf, hw->bufsize); + err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); if (err) { oss_logerr (errno, "Failed to unmap buffer %p, size %d\n", - oss->pcm_buf, hw->bufsize); + oss->pcm_buf, hw->samples << hw->info.shift); } } else { @@ -409,7 +412,7 @@ static void oss_fini_out (HWVoiceOut *hw) } } -static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int oss_init_out (HWVoiceOut *hw, audsettings_t *as) { OSSVoiceOut *oss = (OSSVoiceOut *) hw; struct oss_params req, obt; @@ -417,10 +420,11 @@ static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) int err; int fd; audfmt_e effective_fmt; + audsettings_t obt_as; - req.fmt = aud_to_ossfmt (fmt); - req.freq = freq; - req.nchannels = nchannels; + req.fmt = aud_to_ossfmt (as->fmt); + req.freq = as->freq; + req.nchannels = as->nchannels; req.fragsize = conf.fragsize; req.nfrags = conf.nfrags; @@ -434,24 +438,38 @@ static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.nchannels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.nchannels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianness) ); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; - hw->bufsize = obt.nfrags * obt.fragsize; + + if (obt.nfrags * obt.fragsize & hw->info.align) { + dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", + obt.nfrags * obt.fragsize, hw->info.align + 1); + } + + hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; oss->mmapped = 0; if (conf.try_mmap) { - oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); + oss->pcm_buf = mmap ( + 0, + hw->samples << hw->info.shift, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0 + ); if (oss->pcm_buf == MAP_FAILED) { oss_logerr (errno, "Failed to map %d bytes of DAC\n", - hw->bufsize); + hw->samples << hw->info.shift); } else { int err; int trig = 0; @@ -472,18 +490,24 @@ static int oss_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) } if (!oss->mmapped) { - err = munmap (oss->pcm_buf, hw->bufsize); + err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); if (err) { oss_logerr (errno, "Failed to unmap buffer %p size %d\n", - oss->pcm_buf, hw->bufsize); + oss->pcm_buf, hw->samples << hw->info.shift); } } } } if (!oss->mmapped) { - oss->pcm_buf = qemu_mallocz (hw->bufsize); + oss->pcm_buf = audio_calloc ( + AUDIO_FUNC, + hw->samples, + 1 << hw->info.shift + ); if (!oss->pcm_buf) { + dolog ("Could not allocate DAC buffer (%d bytes)\n", + hw->samples << hw->info.shift); oss_anal_close (&fd); return -1; } @@ -528,8 +552,7 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) return 0; } -static int oss_init_in (HWVoiceIn *hw, - int freq, int nchannels, audfmt_e fmt) +static int oss_init_in (HWVoiceIn *hw, audsettings_t *as) { OSSVoiceIn *oss = (OSSVoiceIn *) hw; struct oss_params req, obt; @@ -537,10 +560,11 @@ static int oss_init_in (HWVoiceIn *hw, int err; int fd; audfmt_e effective_fmt; + audsettings_t obt_as; - req.fmt = aud_to_ossfmt (fmt); - req.freq = freq; - req.nchannels = nchannels; + req.fmt = aud_to_ossfmt (as->fmt); + req.freq = as->freq; + req.nchannels = as->nchannels; req.fragsize = conf.fragsize; req.nfrags = conf.nfrags; if (oss_open (1, &req, &obt, &fd)) { @@ -553,18 +577,28 @@ static int oss_init_in (HWVoiceIn *hw, return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.nchannels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.nchannels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianness) ); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; - hw->bufsize = obt.nfrags * obt.fragsize; - oss->pcm_buf = qemu_mallocz (hw->bufsize); + + if (obt.nfrags * obt.fragsize & hw->info.align) { + dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", + obt.nfrags * obt.fragsize, hw->info.align + 1); + } + + hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; + oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!oss->pcm_buf) { + dolog ("Could not allocate ADC buffer (%d bytes)\n", + hw->samples << hw->info.shift); oss_anal_close (&fd); return -1; } @@ -623,7 +657,7 @@ static int oss_run_in (HWVoiceIn *hw) if (nread > 0) { if (nread & hw->info.align) { - dolog ("warning: misaligned read %d (requested %d), " + dolog ("warning: Misaligned read %d (requested %d), " "alignment %d\n", nread, bufs[i].add << hwshift, hw->info.align + 1); } diff --git a/audio/rate_template.h b/audio/rate_template.h index 5cc95c829..3e0e77c94 100644 --- a/audio/rate_template.h +++ b/audio/rate_template.h @@ -30,7 +30,7 @@ void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, int *isamp, int *osamp) { - rate_t rate = (rate_t) opaque; + struct rate *rate = opaque; st_sample_t *istart, *iend; st_sample_t *ostart, *oend; st_sample_t ilast, icur, out; diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 673e2a112..713c7849d 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -303,7 +303,7 @@ static void sdl_fini_out (HWVoiceOut *hw) sdl_close (&glob_sdl); } -static int sdl_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as) { SDLVoiceOut *sdl = (SDLVoiceOut *) hw; SDLAudioState *s = &glob_sdl; @@ -312,18 +312,14 @@ static int sdl_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) int endianess; int err; audfmt_e effective_fmt; + audsettings_t obt_as; - if (nchannels != 2) { - dolog ("Can not init DAC. Bogus channel count %d\n", nchannels); - return -1; - } + shift <<= as->nchannels == 2; - req.freq = freq; - req.format = aud_to_sdlfmt (fmt, &shift); - req.channels = nchannels; + req.freq = as->freq; + req.format = aud_to_sdlfmt (as->fmt, &shift); + req.channels = as->nchannels; req.samples = conf.nb_samples; - shift <<= nchannels == 2; - req.callback = sdl_callback; req.userdata = sdl; @@ -337,14 +333,16 @@ static int sdl_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) return -1; } + obt_as.freq = obt.freq; + obt_as.nchannels = obt.channels; + obt_as.fmt = effective_fmt; + audio_pcm_init_info ( &hw->info, - obt.freq, - obt.channels, - effective_fmt, + &obt_as, audio_need_to_swap_endian (endianess) ); - hw->bufsize = obt.samples << shift; + hw->samples = obt.samples; s->initialized = 1; s->exit = 0; diff --git a/audio/wavaudio.c b/audio/wavaudio.c index e9bd87872..4cc9ca7f8 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -35,9 +35,15 @@ typedef struct WAVVoiceOut { } WAVVoiceOut; static struct { + audsettings_t settings; const char *wav_path; } conf = { - .wav_path = "qemu.wav" + { + 44100, + 2, + AUD_FMT_S16 + }, + "qemu.wav" }; static int wav_run_out (HWVoiceOut *hw) @@ -101,22 +107,22 @@ static void le_store (uint8_t *buf, uint32_t val, int len) } } -static int wav_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) +static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) { WAVVoiceOut *wav = (WAVVoiceOut *) hw; - int bits16; + int bits16 = 0, stereo = 0; uint8_t hdr[] = { 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 }; + audsettings_t wav_as = conf.settings; - freq = audio_state.fixed_freq_out; - fmt = audio_state.fixed_fmt_out; - nchannels = audio_state.fixed_channels_out; + (void) as; - switch (fmt) { + stereo = wav_as.nchannels == 2; + switch (wav_as.fmt) { case AUD_FMT_S8: case AUD_FMT_U8: bits16 = 0; @@ -126,32 +132,24 @@ static int wav_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt) case AUD_FMT_U16: bits16 = 1; break; - - default: - dolog ("Internal logic error bad format %d\n", fmt); - return -1; } hdr[34] = bits16 ? 0x10 : 0x08; - audio_pcm_init_info ( - &hw->info, - freq, - nchannels, - bits16 ? AUD_FMT_S16 : AUD_FMT_U8, - audio_need_to_swap_endian (0) - ); - hw->bufsize = 4096; - wav->pcm_buf = qemu_mallocz (hw->bufsize); + + audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0)); + + hw->samples = 1024; + wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!wav->pcm_buf) { - dolog ("Can not initialize WAV buffer of %d bytes\n", - hw->bufsize); + dolog ("Could not allocate buffer (%d bytes)\n", + hw->samples << hw->info.shift); return -1; } le_store (hdr + 22, hw->info.nchannels, 2); le_store (hdr + 24, hw->info.freq, 4); - le_store (hdr + 28, hw->info.freq << (bits16 + (nchannels == 2)), 4); - le_store (hdr + 32, 1 << (bits16 + (nchannels == 2)), 2); + le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); + le_store (hdr + 32, 1 << (bits16 + stereo), 2); wav->f = fopen (conf.wav_path, "wb"); if (!wav->f) { @@ -175,7 +173,7 @@ static void wav_fini_out (HWVoiceOut *hw) uint32_t rifflen = (wav->total_samples << stereo) + 36; uint32_t datalen = wav->total_samples << stereo; - if (!wav->f || !hw->active) { + if (!wav->f) { return; } @@ -214,6 +212,15 @@ static void wav_audio_fini (void *opaque) } struct audio_option wav_options[] = { + {"FREQUENCY", AUD_OPT_INT, &conf.settings.freq, + "Frequency", NULL, 0}, + + {"FORMAT", AUD_OPT_FMT, &conf.settings.fmt, + "Format", NULL, 0}, + + {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels, + "Number of channels (1 - mono, 2 - stereo)", NULL, 0}, + {"PATH", AUD_OPT_STR, &conf.wav_path, "Path to wave file", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} diff --git a/hw/adlib.c b/hw/adlib.c index 70de4ffab..fa2a03dff 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -53,6 +53,7 @@ static struct { } conf = {0x220, 44100}; typedef struct { + QEMUSoundCard card; int ticking[2]; int enabled; int active; @@ -70,7 +71,7 @@ typedef struct { #endif } AdlibState; -static AdlibState adlib; +static AdlibState glob_adlib; static void adlib_stop_opl_timer (AdlibState *s, size_t n) { @@ -90,7 +91,7 @@ static void adlib_kill_timers (AdlibState *s) if (s->ticking[i]) { uint64_t delta; - delta = AUD_time_stamp_get_elapsed_usec_out (s->voice, &s->ats); + delta = AUD_get_elapsed_usec_out (s->voice, &s->ats); ldebug ( "delta = %f dexp = %f expired => %d\n", delta / 1000000.0, @@ -141,10 +142,11 @@ static IO_READ_PROTO(adlib_read) static void timer_handler (int c, double interval_Sec) { - AdlibState *s = &adlib; + AdlibState *s = &glob_adlib; unsigned n = c & 1; #ifdef DEBUG double interval; + int64_t exp; #endif if (interval_Sec == 0.0) { @@ -262,16 +264,23 @@ static void Adlib_fini (AdlibState *s) s->active = 0; s->enabled = 0; + AUD_remove_card (&s->card); } -void Adlib_init (void) +int Adlib_init (AudioState *audio) { - AdlibState *s = &adlib; + AdlibState *s = &glob_adlib; + audsettings_t as; + + if (!audio) { + dolog ("No audio state\n"); + return -1; + } #ifdef HAS_YMF262 if (YMF262Init (1, 14318180, conf.freq)) { dolog ("YMF262Init %d failed\n", conf.freq); - return; + return -1; } else { YMF262SetTimerHandler (0, timer_handler, 0); @@ -281,7 +290,7 @@ void Adlib_init (void) s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq); if (!s->opl) { dolog ("OPLCreate %d failed\n", conf.freq); - return; + return -1; } else { OPLSetTimerHandler (s->opl, timer_handler, 0); @@ -289,18 +298,23 @@ void Adlib_init (void) } #endif + as.freq = conf.freq; + as.nchannels = SHIFT; + as.fmt = AUD_FMT_S16; + + AUD_register_card (audio, "adlib", &s->card); + s->voice = AUD_open_out ( + &s->card, s->voice, "adlib", s, adlib_callback, - conf.freq, - SHIFT, - AUD_FMT_S16 + &as ); if (!s->voice) { Adlib_fini (s); - return; + return -1; } s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT; @@ -310,7 +324,7 @@ void Adlib_init (void) dolog ("not enough memory for adlib mixing buffer (%d)\n", s->samples << SHIFT); Adlib_fini (s); - return; + return -1; } register_ioport_read (0x388, 4, 1, adlib_read, s); @@ -321,4 +335,6 @@ void Adlib_init (void) register_ioport_read (conf.port + 8, 2, 1, adlib_read, s); register_ioport_write (conf.port + 8, 2, 1, adlib_write, s); + + return 0; } diff --git a/hw/es1370.c b/hw/es1370.c index 0191f5fdf..fc7ac0a96 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -265,6 +265,7 @@ struct chan { typedef struct ES1370State { PCIDevice *pci_dev; + QEMUSoundCard card; struct chan chan[NB_CHANNELS]; SWVoiceOut *dac_voice[2]; SWVoiceIn *adc_voice; @@ -341,11 +342,11 @@ static void es1370_reset (ES1370State *s) d->scount = 0; d->leftover = 0; if (i == ADC_CHANNEL) { - AUD_close_in (s->adc_voice); + AUD_close_in (&s->card, s->adc_voice); s->adc_voice = NULL; } else { - AUD_close_out (s->dac_voice[i]); + AUD_close_out (&s->card, s->dac_voice[i]); s->dac_voice[i] = NULL; } } @@ -417,28 +418,32 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8, d->shift); if (new_freq) { + audsettings_t as; + + as.freq = new_freq; + as.nchannels = 1 << (new_fmt & 1); + as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8; + if (i == ADC_CHANNEL) { s->adc_voice = AUD_open_in ( + &s->card, s->adc_voice, "es1370.adc", s, es1370_adc_callback, - new_freq, - 1 << (new_fmt & 1), - (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8 + &as ); } else { s->dac_voice[i] = AUD_open_out ( + &s->card, s->dac_voice[i], i ? "es1370.dac2" : "es1370.dac1", s, i ? es1370_dac2_callback : es1370_dac1_callback, - new_freq, - 1 << (new_fmt & 1), - (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8 + &as ); } } @@ -761,7 +766,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, while (temp) { int acquired, to_copy; - to_copy = audio_MIN (temp, sizeof (tmpbuf)); + to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); acquired = AUD_read (s->adc_voice, tmpbuf, to_copy); if (!acquired) break; @@ -779,7 +784,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, while (temp) { int copied, to_copy; - to_copy = audio_MIN (temp, sizeof (tmpbuf)); + to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); cpu_physical_memory_read (addr, tmpbuf, to_copy); copied = AUD_write (voice, tmpbuf, to_copy); if (!copied) @@ -812,7 +817,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, else { d->frame_cnt = size; - if (cnt <= d->frame_cnt) + if ((uint32_t) cnt <= d->frame_cnt) d->frame_cnt |= cnt << 16; } @@ -876,6 +881,10 @@ static void es1370_map (PCIDevice *pci_dev, int region_num, PCIES1370State *d = (PCIES1370State *) pci_dev; ES1370State *s = &d->es1370; + (void) region_num; + (void) size; + (void) type; + register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s); register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s); register_ioport_write (addr, 0x40, 4, es1370_writel, s); @@ -923,13 +932,13 @@ static int es1370_load (QEMUFile *f, void *opaque, int version_id) qemu_get_be32s (f, &d->frame_cnt); if (i == ADC_CHANNEL) { if (s->adc_voice) { - AUD_close_in (s->adc_voice); + AUD_close_in (&s->card, s->adc_voice); s->adc_voice = NULL; } } else { if (s->dac_voice[i]) { - AUD_close_out (s->dac_voice[i]); + AUD_close_out (&s->card, s->dac_voice[i]); s->dac_voice[i] = NULL; } } @@ -953,12 +962,22 @@ static void es1370_on_reset (void *opaque) es1370_reset (s); } -int es1370_init (PCIBus *bus) +int es1370_init (PCIBus *bus, AudioState *audio) { PCIES1370State *d; ES1370State *s; uint8_t *c; + if (!bus) { + dolog ("No PCI bus\n"); + return -1; + } + + if (!audio) { + dolog ("No audio state\n"); + return -1; + } + d = (PCIES1370State *) pci_register_device (bus, "ES1370", sizeof (PCIES1370State), -1, NULL, NULL); @@ -1002,6 +1021,8 @@ int es1370_init (PCIBus *bus) pci_register_io_region (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map); register_savevm ("es1370", 0, 1, es1370_save, es1370_load, s); qemu_register_reset (es1370_on_reset, s); + + AUD_register_card (audio, "es1370", &s->card); es1370_reset (s); return 0; } diff --git a/hw/pc.c b/hw/pc.c index 90a0e48fa..324f5367d 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -601,19 +601,23 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, DMA_init(0); if (audio_enabled) { - AUD_init(); - if (sb16_enabled) - SB16_init (); + AudioState *audio; + + audio = AUD_init(); + if (audio) { + if (sb16_enabled) + SB16_init (audio); #ifdef CONFIG_ADLIB - if (adlib_enabled) - Adlib_init (); + if (adlib_enabled) + Adlib_init (audio); #endif #ifdef CONFIG_GUS - if (gus_enabled) - GUS_init (); + if (gus_enabled) + GUS_init (audio); #endif - if (pci_enabled && es1370_enabled) - es1370_init (pci_bus); + if (pci_enabled && es1370_enabled) + es1370_init (pci_bus, audio); + } } floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); diff --git a/hw/sb16.c b/hw/sb16.c index e79d19278..4414af3d8 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -53,6 +53,7 @@ static struct { } conf = {5, 4, 5, 1, 5, 0x220}; typedef struct SB16State { + QEMUSoundCard card; int irq; int dma; int hdma; @@ -108,9 +109,6 @@ typedef struct SB16State { uint8_t mixer_regs[256]; } SB16State; -/* XXX: suppress that and use a context */ -static struct SB16State dsp; - static void SB_audio_callback (void *opaque, int free); static int magic_of_irq (int irq) @@ -242,15 +240,21 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->block_size, s->dma_auto, s->fifo, s->highspeed); if (s->freq) { + audsettings_t as; + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + s->voice = AUD_open_out ( + &s->card, s->voice, "sb16", s, SB_audio_callback, - s->freq, - 1 << s->fmt_stereo, - s->fmt + &as ); } @@ -330,15 +334,21 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) } if (s->freq) { + audsettings_t as; + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + s->voice = AUD_open_out ( + &s->card, s->voice, "sb16", s, SB_audio_callback, - s->freq, - 1 << s->fmt_stereo, - s->fmt + &as ); } @@ -349,7 +359,7 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) static inline void dsp_out_data (SB16State *s, uint8_t val) { ldebug ("outdata %#x\n", val); - if (s->out_data_len < sizeof (s->out_data)) { + if ((size_t) s->out_data_len < sizeof (s->out_data)) { s->out_data[s->out_data_len++] = val; } } @@ -1018,6 +1028,7 @@ static void reset_mixer (SB16State *s) static IO_WRITE_PROTO(mixer_write_indexb) { SB16State *s = opaque; + (void) nport; s->mixer_nreg = val; } @@ -1025,10 +1036,8 @@ static IO_WRITE_PROTO(mixer_write_datab) { SB16State *s = opaque; + (void) nport; ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); - if (s->mixer_nreg > sizeof (s->mixer_regs)) { - return; - } switch (s->mixer_nreg) { case 0x00: @@ -1088,6 +1097,8 @@ static IO_WRITE_PROTO(mixer_write_indexw) static IO_READ_PROTO(mixer_read) { SB16State *s = opaque; + + (void) nport; #ifndef DEBUG_SB16_MOST if (s->mixer_nreg != 0x82) { ldebug ("mixer_read[%#x] -> %#x\n", @@ -1111,11 +1122,12 @@ static int write_audio (SB16State *s, int nchan, int dma_pos, while (temp) { int left = dma_len - dma_pos; - int to_copy, copied; + int copied; + size_t to_copy; to_copy = audio_MIN (temp, left); - if (to_copy > sizeof(tmpbuf)) { - to_copy = sizeof(tmpbuf); + if (to_copy > sizeof (tmpbuf)) { + to_copy = sizeof (tmpbuf); } copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); @@ -1308,21 +1320,27 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) qemu_get_buffer (f, s->mixer_regs, 256); if (s->voice) { - AUD_close_out (s->voice); + AUD_close_out (&s->card, s->voice); s->voice = NULL; } if (s->dma_running) { if (s->freq) { + audsettings_t as; + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + s->voice = AUD_open_out ( + &s->card, s->voice, "sb16", s, SB_audio_callback, - s->freq, - 1 << s->fmt_stereo, - s->fmt + &as ); } @@ -1332,13 +1350,25 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) return 0; } -void SB16_init (void) +int SB16_init (AudioState *audio) { - SB16State *s = &dsp; + SB16State *s; int i; static const uint8_t dsp_write_ports[] = {0x6, 0xc}; static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; + if (!audio) { + dolog ("No audio state\n"); + return -1; + } + + s = qemu_mallocz (sizeof (*s)); + if (!s) { + dolog ("Could not allocate memory for SB16 (%d bytes)\n", + sizeof (*s)); + return -1; + } + s->cmd = -1; s->irq = conf.irq; s->dma = conf.dma; @@ -1356,7 +1386,7 @@ void SB16_init (void) reset_mixer (s); s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s); if (!s->aux_ts) { - dolog ("Can not create auxiliary timer\n"); + dolog ("warning: Could not create auxiliary timer\n"); } for (i = 0; i < LENOFA (dsp_write_ports); i++) { @@ -1377,4 +1407,6 @@ void SB16_init (void) s->can_write = 1; register_savevm ("sb16", 0, 1, SB_save, SB_load, s); + AUD_register_card (audio, "sb16", &s->card); + return 0; } diff --git a/qemu-doc.texi b/qemu-doc.texi index 51875d774..1c5b5b7be 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -95,12 +95,21 @@ NE2000 PCI network adapters @item Serial ports @item -Soundblaster 16 card +Creative SoundBlaster 16 sound card +@item +ENSONIQ AudioPCI ES1370 sound card +@item +Adlib(OPL2) - Yamaha YM3812 compatible chip @end itemize +Note that adlib is only available when QEMU was configured with +-enable-adlib + QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL VGA BIOS. +QEMU uses YM3812 emulation by Tatsuyuki Satoh. + @c man end @section Quick Start diff --git a/vl.c b/vl.c index d551a4e55..810db8152 100644 --- a/vl.c +++ b/vl.c @@ -2842,10 +2842,11 @@ void help(void) "-k language use keyboard layout (for example \"fr\" for French)\n" #endif #ifdef HAS_AUDIO - "-enable-audio enable audio support\n" + "-enable-audio enable audio support, and all the sound cars\n" "-audio-help print list of audio drivers and their options\n" - "-soundhw c1,... comma separated list of sound card names\n" - " use -soundhw ? to get the list of supported sound cards\n" + "-soundhw c1,... enable audio support\n" + " and only specified sound cards (comma separated list)\n" + " use -soundhw ? to get the list of supported cards\n" #endif "-localtime set the real time clock to local time [default=utc]\n" "-full-screen start in full screen\n" @@ -3145,9 +3146,9 @@ static void select_soundhw (const char *optarg) printf ("sb16 Creative Sound Blaster 16\n"); #ifdef CONFIG_ADLIB #ifdef HAS_YMF262 - printf ("adlib Ymaha YMF262 (OPL3)\n"); + printf ("adlib Yamaha YMF262 (OPL3)\n"); #else - printf ("adlib Ymaha YM3812 (OPL2)\n"); + printf ("adlib Yamaha YM3812 (OPL2)\n"); #endif #endif #ifdef CONFIG_GUS diff --git a/vl.h b/vl.h index e1a2ec3f1..72d4f8790 100644 --- a/vl.h +++ b/vl.h @@ -631,16 +631,16 @@ int pmac_ide_init (BlockDriverState **hd_table, SetIRQFunc *set_irq, void *irq_opaque, int irq); /* es1370.c */ -int es1370_init (PCIBus *bus); +int es1370_init (PCIBus *bus, AudioState *s); /* sb16.c */ -void SB16_init (void); +int SB16_init (AudioState *s); /* adlib.c */ -void Adlib_init (void); +int Adlib_init (AudioState *s); /* gus.c */ -void GUS_init (void); +int GUS_init (AudioState *s); /* dma.c */ typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); -- cgit v1.2.3 From 8738a8d079b661a612e89612844dc270ef5f0924 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Nov 2005 15:48:04 +0000 Subject: serial load/save VM support (Vincent Pelletier) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1602 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/serial.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/hw/serial.c b/hw/serial.c index 3fe482c39..ac04e6522 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -258,6 +258,41 @@ static void serial_event(void *opaque, int event) serial_receive_break(s); } +static void serial_save(QEMUFile *f, void *opaque) +{ + SerialState *s = opaque; + + qemu_put_8s(f,&s->divider); + qemu_put_8s(f,&s->rbr); + qemu_put_8s(f,&s->ier); + qemu_put_8s(f,&s->iir); + qemu_put_8s(f,&s->lcr); + qemu_put_8s(f,&s->mcr); + qemu_put_8s(f,&s->lsr); + qemu_put_8s(f,&s->msr); + qemu_put_8s(f,&s->scr); +} + +static int serial_load(QEMUFile *f, void *opaque, int version_id) +{ + SerialState *s = opaque; + + if(version_id != 1) + return -EINVAL; + + qemu_get_8s(f,&s->divider); + qemu_get_8s(f,&s->rbr); + qemu_get_8s(f,&s->ier); + qemu_get_8s(f,&s->iir); + qemu_get_8s(f,&s->lcr); + qemu_get_8s(f,&s->mcr); + qemu_get_8s(f,&s->lsr); + qemu_get_8s(f,&s->msr); + qemu_get_8s(f,&s->scr); + + return 0; +} + /* If fd is zero, it means that the serial device uses the console */ SerialState *serial_init(int base, int irq, CharDriverState *chr) { @@ -270,6 +305,8 @@ SerialState *serial_init(int base, int irq, CharDriverState *chr) s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; + register_savevm("serial", base, 1, serial_save, serial_load, s); + register_ioport_write(base, 8, 1, serial_ioport_write, s); register_ioport_read(base, 8, 1, serial_ioport_read, s); s->chr = chr; -- cgit v1.2.3 From a594cfbf3e1a38bc6f3908d7d0903d41e8ea9da8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Nov 2005 16:13:29 +0000 Subject: USB user interface git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1603 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/pc.c | 27 +---- hw/usb-uhci.c | 19 ++-- hw/usb.c | 15 ++- hw/usb.h | 18 ++- monitor.c | 9 +- usb-linux.c | 341 ++++++++++++++++++++++++++++++++++++++++++-------------- vl.c | 145 +++++++++++++++++++++++- vl.h | 11 ++ 9 files changed, 456 insertions(+), 133 deletions(-) diff --git a/Makefile.target b/Makefile.target index a22b2e080..30a21c5ee 100644 --- a/Makefile.target +++ b/Makefile.target @@ -290,12 +290,14 @@ ifdef CONFIG_ADLIB SOUND_HW += fmopl.o adlib.o endif +# USB layer +VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o + ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o -VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff --git a/hw/pc.c b/hw/pc.c index 324f5367d..918615c92 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -42,6 +42,7 @@ static fdctrl_t *floppy_controller; static RTCState *rtc_state; static PITState *pit; static IOAPICState *ioapic; +static USBPort *usb_root_ports[2]; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -625,32 +626,8 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, cmos_init(ram_size, boot_device, bs_table); if (pci_enabled && usb_enabled) { - USBPort *usb_root_ports[2]; - USBDevice *usb_dev; usb_uhci_init(pci_bus, usb_root_ports); -#if 0 - { - USBPort *usb_hub1_ports[4]; - USBPort *usb_hub2_ports[2]; - /* test: we simulate a USB hub */ - usb_dev = usb_hub_init(usb_hub1_ports, 4); - usb_attach(usb_root_ports[0], usb_dev); - - /* test: we simulate a USB hub */ - usb_dev = usb_hub_init(usb_hub2_ports, 2); - usb_attach(usb_hub1_ports[0], usb_dev); - } -#endif -#if 0 - /* USB mouse */ - usb_dev = usb_mouse_init(); - usb_attach(usb_root_ports[0], usb_dev); -#endif -#if 1 - /* simulated hub with the host USB devices connected to it */ - usb_dev = usb_host_hub_init(); - usb_attach(usb_root_ports[0], usb_dev); -#endif + usb_attach(usb_root_ports[0], vm_usb_hub); } /* must be done after all PCI devices are instanciated */ diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 4dd0c6381..0f0c185aa 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -63,7 +63,6 @@ typedef struct UHCIPort { USBPort port; uint16_t ctrl; - USBDevice *dev; /* connected device */ } UHCIPort; typedef struct UHCIState { @@ -128,8 +127,8 @@ static void uhci_reset(UHCIState *s) for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; port->ctrl = 0x0080; - if (port->dev) - uhci_attach(&port->port, port->dev); + if (port->port.dev) + uhci_attach(&port->port, port->port.dev); } } @@ -183,7 +182,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) /* send reset on the USB bus */ for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; - dev = port->dev; + dev = port->port.dev; if (dev) { dev->handle_packet(dev, USB_MSG_RESET, 0, 0, NULL, 0); @@ -224,7 +223,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) if (n >= NB_PORTS) return; port = &s->ports[n]; - dev = port->dev; + dev = port->port.dev; if (dev) { /* port reset */ if ( (val & UHCI_PORT_RESET) && @@ -320,7 +319,7 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) UHCIPort *port = &s->ports[port1->index]; if (dev) { - if (port->dev) { + if (port->port.dev) { usb_attach(port1, NULL); } /* set connect status */ @@ -332,7 +331,7 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) port->ctrl |= UHCI_PORT_LSDA; else port->ctrl &= ~UHCI_PORT_LSDA; - port->dev = dev; + port->port.dev = dev; /* send the attach message */ dev->handle_packet(dev, USB_MSG_ATTACH, 0, 0, NULL, 0); @@ -346,13 +345,13 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) port->ctrl &= ~UHCI_PORT_EN; port->ctrl |= UHCI_PORT_ENC; } - dev = port->dev; + dev = port->port.dev; if (dev) { /* send the detach message */ dev->handle_packet(dev, USB_MSG_DETACH, 0, 0, NULL, 0); } - port->dev = NULL; + port->port.dev = NULL; } } @@ -386,7 +385,7 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, #endif for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; - dev = port->dev; + dev = port->port.dev; if (dev && (port->ctrl & UHCI_PORT_EN)) { ret = dev->handle_packet(dev, pid, devaddr, devep, diff --git a/hw/usb.c b/hw/usb.c index 0728db29f..b2830c590 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -201,7 +201,6 @@ int set_usb_string(uint8_t *buf, const char *str) typedef struct USBHubPort { USBPort port; - USBDevice *dev; uint16_t wPortStatus; uint16_t wPortChange; } USBHubPort; @@ -342,7 +341,7 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) USBHubPort *port = &s->ports[port1->index]; if (dev) { - if (port->dev) + if (port->port.dev) usb_attach(port1, NULL); port->wPortStatus |= PORT_STAT_CONNECTION; @@ -351,9 +350,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) port->wPortStatus |= PORT_STAT_LOW_SPEED; else port->wPortStatus &= ~PORT_STAT_LOW_SPEED; - port->dev = dev; + port->port.dev = dev; } else { - dev = port->dev; + dev = port->port.dev; if (dev) { port->wPortStatus &= ~PORT_STAT_CONNECTION; port->wPortChange |= PORT_STAT_C_CONNECTION; @@ -361,7 +360,7 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE; } - port->dev = NULL; + port->port.dev = NULL; } } } @@ -498,7 +497,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, if (n >= s->nb_ports) goto fail; port = &s->ports[n]; - dev = port->dev; + dev = port->port.dev; switch(value) { case PORT_SUSPEND: port->wPortStatus |= PORT_STAT_SUSPEND; @@ -529,7 +528,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, if (n >= s->nb_ports) goto fail; port = &s->ports[n]; - dev = port->dev; + dev = port->port.dev; switch(value) { case PORT_ENABLE: port->wPortStatus &= ~PORT_STAT_ENABLE; @@ -624,7 +623,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, int pid, for(i = 0; i < s->nb_ports; i++) { port = &s->ports[i]; - dev = port->dev; + dev = port->port.dev; if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { ret = dev->handle_packet(dev, pid, devaddr, devep, diff --git a/hw/usb.h b/hw/usb.h index 7a5c8ad26..b4dee2340 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -47,6 +47,20 @@ //#define USB_STATE_CONFIGURED 5 #define USB_STATE_SUSPENDED 6 +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_CSCID 0x0b +#define USB_CLASS_CONTENT_SEC 0x0d +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff + #define USB_DIR_OUT 0 #define USB_DIR_IN 0x80 @@ -125,6 +139,7 @@ struct USBDevice { /* USB port on which a device can be connected */ struct USBPort { + USBDevice *dev; void (*attach)(USBPort *port, USBDevice *dev); void *opaque; int index; /* internal port index, may be used with the opaque */ @@ -143,7 +158,8 @@ USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports); void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); /* usb-linux.c */ -USBDevice *usb_host_hub_init(void); +USBDevice *usb_host_device_open(const char *devname); +void usb_host_info(void); /* usb-hid.c */ USBDevice *usb_mouse_init(void); diff --git a/monitor.c b/monitor.c index 0153e8d8b..cf70b575a 100644 --- a/monitor.c +++ b/monitor.c @@ -901,7 +901,6 @@ static void do_info_kqemu(void) #endif } - static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -948,6 +947,10 @@ static term_cmd_t term_cmds[] = { "", "send system power down event" }, { "sum", "ii", do_sum, "addr size", "compute the checksum of a memory region" }, + { "usb_add", "s", do_usb_add, + "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, + { "usb_del", "s", do_usb_del, + "device", "remove USB device 'bus.addr'" }, { NULL, NULL, }, }; @@ -978,6 +981,10 @@ static term_cmd_t info_cmds[] = { "", "show dynamic compiler info", }, { "kqemu", "", do_info_kqemu, "", "show kqemu information", }, + { "usb", "", usb_info, + "", "show guest USB devices", }, + { "usbhost", "", usb_host_info, + "", "show host USB devices", }, { NULL, NULL, }, }; diff --git a/usb-linux.c b/usb-linux.c index 87f3d120b..cde94cd0a 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -40,9 +40,13 @@ struct usb_ctrltransfer { void *data; }; -//#define DEBUG +typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id, + int vendor_id, int product_id, + const char *product_name, int speed); +static int usb_host_find_device(int *pbus_num, int *paddr, + const char *devname); -#define MAX_DEVICES 8 +//#define DEBUG #define USBDEVFS_PATH "/proc/bus/usb" @@ -51,12 +55,6 @@ typedef struct USBHostDevice { int fd; } USBHostDevice; -typedef struct USBHostHubState { - USBDevice *hub_dev; - USBPort *hub_ports[MAX_DEVICES]; - USBDevice *hub_devices[MAX_DEVICES]; -} USBHostHubState; - static void usb_host_handle_reset(USBDevice *dev) { #if 0 @@ -137,29 +135,26 @@ static int usb_host_handle_data(USBDevice *dev, int pid, } } -static int usb_host_handle_packet(USBDevice *dev, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len) -{ - return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); -} - /* XXX: exclude high speed devices or implement EHCI */ -static void scan_host_device(USBHostHubState *s, const char *filename) +USBDevice *usb_host_device_open(const char *devname) { int fd, interface, ret, i; USBHostDevice *dev; struct usbdevfs_connectinfo ci; uint8_t descr[1024]; + char buf[1024]; int descr_len, dev_descr_len, config_descr_len, nb_interfaces; + int bus_num, addr; -#ifdef DEBUG - printf("scanning %s\n", filename); -#endif - fd = open(filename, O_RDWR); + if (usb_host_find_device(&bus_num, &addr, devname) < 0) + return NULL; + + snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", + bus_num, addr); + fd = open(buf, O_RDWR); if (fd < 0) { - perror(filename); - return; + perror(buf); + return NULL; } /* read the config description */ @@ -180,22 +175,31 @@ static void scan_host_device(USBHostHubState *s, const char *filename) nb_interfaces = descr[i + 4]; if (nb_interfaces != 1) { /* NOTE: currently we grab only one interface */ + fprintf(stderr, "usb_host: only one interface supported\n"); + goto fail; + } + +#ifdef USBDEVFS_DISCONNECT + /* earlier Linux 2.4 do not support that */ + ret = ioctl(fd, USBDEVFS_DISCONNECT); + if (ret < 0 && errno != ENODATA) { + perror("USBDEVFS_DISCONNECT"); goto fail; } +#endif + /* XXX: only grab if all interfaces are free */ interface = 0; ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface); if (ret < 0) { if (errno == EBUSY) { -#ifdef DEBUG - printf("%s already grabbed\n", filename); -#endif + fprintf(stderr, "usb_host: device already grabbed\n"); } else { perror("USBDEVFS_CLAIMINTERFACE"); } fail: close(fd); - return; + return NULL; } ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); @@ -205,21 +209,9 @@ static void scan_host_device(USBHostHubState *s, const char *filename) } #ifdef DEBUG - printf("%s grabbed\n", filename); + printf("host USB device %d.%d grabbed\n", bus_num, addr); #endif - /* find a free slot */ - for(i = 0; i < MAX_DEVICES; i++) { - if (!s->hub_devices[i]) - break; - } - if (i == MAX_DEVICES) { -#ifdef DEBUG - printf("too many host devices\n"); - goto fail; -#endif - } - dev = qemu_mallocz(sizeof(USBHostDevice)); if (!dev) goto fail; @@ -228,80 +220,259 @@ static void scan_host_device(USBHostHubState *s, const char *filename) dev->dev.speed = USB_SPEED_LOW; else dev->dev.speed = USB_SPEED_HIGH; - dev->dev.handle_packet = usb_host_handle_packet; + dev->dev.handle_packet = usb_generic_handle_packet; dev->dev.handle_reset = usb_host_handle_reset; dev->dev.handle_control = usb_host_handle_control; dev->dev.handle_data = usb_host_handle_data; + return (USBDevice *)dev; +} - s->hub_devices[i] = (USBDevice *)dev; - - /* activate device on hub */ - usb_attach(s->hub_ports[i], s->hub_devices[i]); +static int get_tag_value(char *buf, int buf_size, + const char *str, const char *tag, + const char *stopchars) +{ + const char *p; + char *q; + p = strstr(str, tag); + if (!p) + return -1; + p += strlen(tag); + while (isspace(*p)) + p++; + q = buf; + while (*p != '\0' && !strchr(stopchars, *p)) { + if ((q - buf) < (buf_size - 1)) + *q++ = *p; + p++; + } + *q = '\0'; + return q - buf; } -static void scan_host_devices(USBHostHubState *s, const char *bus_path) +static int usb_host_scan(void *opaque, USBScanFunc *func) { - DIR *d; - struct dirent *de; + FILE *f; + char line[1024]; char buf[1024]; - - d = opendir(bus_path); - if (!d) - return; + int bus_num, addr, speed, device_count, class_id, product_id, vendor_id; + int ret; + char product_name[512]; + + f = fopen(USBDEVFS_PATH "/devices", "r"); + if (!f) { + term_printf("Could not open %s\n", USBDEVFS_PATH "/devices"); + return 0; + } + device_count = 0; + bus_num = addr = speed = class_id = product_id = vendor_id = 0; + ret = 0; for(;;) { - de = readdir(d); - if (!de) + if (fgets(line, sizeof(line), f) == NULL) break; - if (de->d_name[0] != '.') { - snprintf(buf, sizeof(buf), "%s/%s", bus_path, de->d_name); - scan_host_device(s, buf); + if (strlen(line) > 0) + line[strlen(line) - 1] = '\0'; + if (line[0] == 'T' && line[1] == ':') { + if (device_count) { + ret = func(opaque, bus_num, addr, class_id, vendor_id, + product_id, product_name, speed); + if (ret) + goto the_end; + } + if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) + goto fail; + bus_num = atoi(buf); + if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) + goto fail; + addr = atoi(buf); + if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) + goto fail; + if (!strcmp(buf, "480")) + speed = USB_SPEED_HIGH; + else if (!strcmp(buf, "1.5")) + speed = USB_SPEED_LOW; + else + speed = USB_SPEED_FULL; + product_name[0] = '\0'; + class_id = 0xff; + device_count++; + product_id = 0; + vendor_id = 0; + } else if (line[0] == 'P' && line[1] == ':') { + if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) + goto fail; + vendor_id = strtoul(buf, NULL, 16); + if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) + goto fail; + product_id = strtoul(buf, NULL, 16); + } else if (line[0] == 'S' && line[1] == ':') { + if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) + goto fail; + pstrcpy(product_name, sizeof(product_name), buf); + } else if (line[0] == 'D' && line[1] == ':') { + if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) + goto fail; + class_id = strtoul(buf, NULL, 16); } + fail: ; + } + if (device_count) { + ret = func(opaque, bus_num, addr, class_id, vendor_id, + product_id, product_name, speed); } - closedir(d); + the_end: + fclose(f); + return ret; } -static void scan_host_buses(USBHostHubState *s) +typedef struct FindDeviceState { + int vendor_id; + int product_id; + int bus_num; + int addr; +} FindDeviceState; + +static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, + int class_id, + int vendor_id, int product_id, + const char *product_name, int speed) { - DIR *d; - struct dirent *de; - char buf[1024]; + FindDeviceState *s = opaque; + if (vendor_id == s->vendor_id && + product_id == s->product_id) { + s->bus_num = bus_num; + s->addr = addr; + return 1; + } else { + return 0; + } +} - d = opendir(USBDEVFS_PATH); - if (!d) - return; - for(;;) { - de = readdir(d); - if (!de) - break; - if (isdigit(de->d_name[0])) { - snprintf(buf, sizeof(buf), "%s/%s", USBDEVFS_PATH, de->d_name); - scan_host_devices(s, buf); +/* the syntax is : + 'bus.addr' (decimal numbers) or + 'vendor_id:product_id' (hexa numbers) */ +static int usb_host_find_device(int *pbus_num, int *paddr, + const char *devname) +{ + const char *p; + int ret; + FindDeviceState fs; + + p = strchr(devname, '.'); + if (p) { + *pbus_num = strtoul(devname, NULL, 0); + *paddr = strtoul(p + 1, NULL, 0); + return 0; + } + p = strchr(devname, ':'); + if (p) { + fs.vendor_id = strtoul(devname, NULL, 16); + fs.product_id = strtoul(p + 1, NULL, 16); + ret = usb_host_scan(&fs, usb_host_find_device_scan); + if (ret) { + *pbus_num = fs.bus_num; + *paddr = fs.addr; + return 0; } } - closedir(d); + return -1; } -/* virtual hub containing the USB devices of the host */ -USBDevice *usb_host_hub_init(void) +/**********************/ +/* USB host device info */ + +struct usb_class_info { + int class; + const char *class_name; +}; + +static const struct usb_class_info usb_class_info[] = { + { USB_CLASS_AUDIO, "Audio"}, + { USB_CLASS_COMM, "Communication"}, + { USB_CLASS_HID, "HID"}, + { USB_CLASS_HUB, "Hub" }, + { USB_CLASS_PHYSICAL, "Physical" }, + { USB_CLASS_PRINTER, "Printer" }, + { USB_CLASS_MASS_STORAGE, "Storage" }, + { USB_CLASS_CDC_DATA, "Data" }, + { USB_CLASS_APP_SPEC, "Application Specific" }, + { USB_CLASS_VENDOR_SPEC, "Vendor Specific" }, + { USB_CLASS_STILL_IMAGE, "Still Image" }, + { USB_CLASS_CSCID, "Smart Card" }, + { USB_CLASS_CONTENT_SEC, "Content Security" }, + { -1, NULL } +}; + +static const char *usb_class_str(uint8_t class) { - USBHostHubState *s; - s = qemu_mallocz(sizeof(USBHostHubState)); - if (!s) - return NULL; - s->hub_dev = usb_hub_init(s->hub_ports, MAX_DEVICES); - if (!s->hub_dev) { - free(s); - return NULL; + const struct usb_class_info *p; + for(p = usb_class_info; p->class != -1; p++) { + if (p->class == class) + break; } - scan_host_buses(s); - return s->hub_dev; + return p->class_name; +} + +void usb_info_device(int bus_num, int addr, int class_id, + int vendor_id, int product_id, + const char *product_name, + int speed) +{ + const char *class_str, *speed_str; + + switch(speed) { + case USB_SPEED_LOW: + speed_str = "1.5"; + break; + case USB_SPEED_FULL: + speed_str = "12"; + break; + case USB_SPEED_HIGH: + speed_str = "480"; + break; + default: + speed_str = "?"; + break; + } + + term_printf(" Device %d.%d, speed %s Mb/s\n", + bus_num, addr, speed_str); + class_str = usb_class_str(class_id); + if (class_str) + term_printf(" %s:", class_str); + else + term_printf(" Class %02x:", class_id); + term_printf(" USB device %04x:%04x", vendor_id, product_id); + if (product_name[0] != '\0') + term_printf(", %s", product_name); + term_printf("\n"); +} + +static int usb_host_info_device(void *opaque, int bus_num, int addr, + int class_id, + int vendor_id, int product_id, + const char *product_name, + int speed) +{ + usb_info_device(bus_num, addr, class_id, vendor_id, product_id, + product_name, speed); + return 0; +} + +void usb_host_info(void) +{ + usb_host_scan(NULL, usb_host_info_device); } #else +void usb_host_info(void) +{ + term_printf("USB host devices not supported\n"); +} + /* XXX: modify configure to compile the right host driver */ -USBDevice *usb_host_hub_init(void) +USBDevice *usb_host_device_open(const char *devname) { return NULL; } diff --git a/vl.c b/vl.c index 810db8152..cab2eb05f 100644 --- a/vl.c +++ b/vl.c @@ -154,6 +154,8 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; int win2k_install_hack = 0; #endif int usb_enabled = 0; +USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; +USBDevice *vm_usb_hub; /***********************************************************/ /* x86 ISA bus support */ @@ -1737,6 +1739,117 @@ static int net_fd_init(NetDriverState *nd, int fd) #endif /* !_WIN32 */ +/***********************************************************/ +/* USB devices */ + +static int usb_device_add(const char *devname) +{ + const char *p; + USBDevice *dev; + int i; + + if (!vm_usb_hub) + return -1; + for(i = 0;i < MAX_VM_USB_PORTS; i++) { + if (!vm_usb_ports[i]->dev) + break; + } + if (i == MAX_VM_USB_PORTS) + return -1; + + if (strstart(devname, "host:", &p)) { + dev = usb_host_device_open(p); + if (!dev) + return -1; + } else if (!strcmp(devname, "mouse")) { + dev = usb_mouse_init(); + if (!dev) + return -1; + } else { + return -1; + } + usb_attach(vm_usb_ports[i], dev); + return 0; +} + +static int usb_device_del(const char *devname) +{ + USBDevice *dev; + int bus_num, addr, i; + const char *p; + + if (!vm_usb_hub) + return -1; + + p = strchr(devname, '.'); + if (!p) + return -1; + bus_num = strtoul(devname, NULL, 0); + addr = strtoul(p + 1, NULL, 0); + if (bus_num != 0) + return -1; + for(i = 0;i < MAX_VM_USB_PORTS; i++) { + dev = vm_usb_ports[i]->dev; + if (dev && dev->addr == addr) + break; + } + if (i == MAX_VM_USB_PORTS) + return -1; + usb_attach(vm_usb_ports[i], NULL); + return 0; +} + +void do_usb_add(const char *devname) +{ + int ret; + ret = usb_device_add(devname); + if (ret < 0) + term_printf("Could not add USB device '%s'\n", devname); +} + +void do_usb_del(const char *devname) +{ + int ret; + ret = usb_device_del(devname); + if (ret < 0) + term_printf("Could not remove USB device '%s'\n", devname); +} + +void usb_info(void) +{ + USBDevice *dev; + int i; + const char *speed_str; + + if (!vm_usb_hub) { + term_printf("USB support not enabled\n"); + return; + } + + for(i = 0; i < MAX_VM_USB_PORTS; i++) { + dev = vm_usb_ports[i]->dev; + if (dev) { + term_printf("Hub port %d:\n", i); + switch(dev->speed) { + case USB_SPEED_LOW: + speed_str = "1.5"; + break; + case USB_SPEED_FULL: + speed_str = "12"; + break; + case USB_SPEED_HIGH: + speed_str = "480"; + break; + default: + speed_str = "?"; + break; + } + term_printf(" Device %d.%d, speed %s Mb/s\n", + 0, dev->addr, speed_str); + } + } +} + /***********************************************************/ /* pid file */ @@ -2989,6 +3102,7 @@ enum { QEMU_OPTION_no_kqemu, QEMU_OPTION_win2k_hack, QEMU_OPTION_usb, + QEMU_OPTION_usbdevice, }; typedef struct QEMUOption { @@ -3063,9 +3177,10 @@ const QEMUOption qemu_options[] = { { "full-screen", 0, QEMU_OPTION_full_screen }, { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, - { "usb", 0, QEMU_OPTION_usb }, + { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, /* temporary options */ + { "usb", 0, QEMU_OPTION_usb }, { "pci", 0, QEMU_OPTION_pci }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, { NULL }, @@ -3239,7 +3354,9 @@ int main(int argc, char **argv) int parallel_device_index; const char *loadvm = NULL; QEMUMachine *machine; - + char usb_devices[MAX_VM_USB_PORTS][128]; + int usb_devices_index; + #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); @@ -3282,6 +3399,8 @@ int main(int argc, char **argv) parallel_devices[i][0] = '\0'; parallel_device_index = 0; + usb_devices_index = 0; + nb_tun_fds = 0; net_if_type = -1; nb_nics = 1; @@ -3653,6 +3772,17 @@ int main(int argc, char **argv) case QEMU_OPTION_usb: usb_enabled = 1; break; + case QEMU_OPTION_usbdevice: + usb_enabled = 1; + if (usb_devices_index >= MAX_VM_USB_PORTS) { + fprintf(stderr, "Too many USB devices\n"); + exit(1); + } + pstrcpy(usb_devices[usb_devices_index], + sizeof(usb_devices[usb_devices_index]), + optarg); + usb_devices_index++; + break; } } } @@ -3818,6 +3948,17 @@ int main(int argc, char **argv) } } + /* init USB devices */ + if (usb_enabled) { + vm_usb_hub = usb_hub_init(vm_usb_ports, MAX_VM_USB_PORTS); + for(i = 0; i < usb_devices_index; i++) { + if (usb_device_add(usb_devices[i]) < 0) { + fprintf(stderr, "Warning: could not add USB device %s\n", + usb_devices[i]); + } + } + } + /* init CPU state */ env = cpu_init(); global_env = env; diff --git a/vl.h b/vl.h index 72d4f8790..4f181c50e 100644 --- a/vl.h +++ b/vl.h @@ -862,6 +862,17 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); #include "hw/usb.h" +/* usb ports of the VM */ + +#define MAX_VM_USB_PORTS 8 + +extern USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; +extern USBDevice *vm_usb_hub; + +void do_usb_add(const char *devname); +void do_usb_del(const char *devname); +void usb_info(void); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From b389dbfb587e61ccc1c68e51f84f8fe050e7203e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Nov 2005 16:49:55 +0000 Subject: USB help git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1604 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 2 ++ 2 files changed, 108 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 1c5b5b7be..6d7e85cd6 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -100,6 +100,8 @@ Creative SoundBlaster 16 sound card ENSONIQ AudioPCI ES1370 sound card @item Adlib(OPL2) - Yamaha YM3812 compatible chip +@item +PCI UHCI USB controller and a virtual USB hub. @end itemize Note that adlib is only available when QEMU was configured with @@ -227,6 +229,17 @@ slows down the IDE transfers). @end table +USB options: +@table @option + +@item -usb +Enable the USB driver (will be the default soon) + +@item -usbdevice devname +Add the USB device @var{devname}. See the monitor command +@code{usb_add} to have more information. +@end table + Network options: @table @option @@ -495,6 +508,12 @@ show the block devices show the cpu registers @item info history show the command line history +@item info pci +show emulated PCI device +@item info usb +show USB devices plugged on the virtual USB hub +@item info usbhost +show all USB host devices @end table @item q or quit @@ -606,6 +625,19 @@ intercepts at low level, such as @code{ctrl-alt-f1} in X Window. Reset the system. +@item usb_add devname + +Plug the USB device devname to the QEMU virtual USB hub. @var{devname} +is either a virtual device name (for example @code{mouse}) or a host +USB device identifier. Host USB device identifiers have the following +syntax: @code{host:bus.addr} or @code{host:vendor_id:product_id}. + +@item usb_del devname + +Remove the USB device @var{devname} from the QEMU virtual USB +hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor +command @code{info usb} to see the devices you can remove. + @end table @subsection Integer expressions @@ -849,6 +881,80 @@ Lawton for the plex86 Project (@url{www.plex86.org}). @end enumerate +@section USB emulation + +QEMU emulates a PCI UHCI USB controller and a 8 port USB hub connected +to it. You can virtually plug to the hub virtual USB devices or real +host USB devices (experimental, works only on Linux hosts). + +@subsection Using virtual USB devices + +A virtual USB mouse device is available for testing in QEMU. + +You can try it with the following monitor commands: + +@example +# add the mouse device +(qemu) usb_add mouse + +# show the virtual USB devices plugged on the QEMU Virtual USB hub +(qemu) info usb + Device 0.3, speed 12 Mb/s + +# after some time you can try to remove the mouse +(qemu) usb_del 0.3 +@end example + +The option @option{-usbdevice} is similar to the monitor command +@code{usb_add}. + +@subsection Using host USB devices on a Linux host + +WARNING: this is an experimental feature. QEMU will slow down when +using it. USB devices requiring real time streaming (i.e. USB Video +Cameras) are not supported yet. + +@enumerate +@item If you use an early Linux 2.4 kernel, verify that no Linux driver +is actually using the USB device. A simple way to do that is simply to +disable the corresponding kernel module by renaming it from @file{mydriver.o} +to @file{mydriver.o.disabled}. + +@item Verify that @file{/proc/bus/usb} is working (most Linux distributions should enable it by default). You should see something like that: +@example +ls /proc/bus/usb +001 devices drivers +@end example + +@item Since only root can access to the USB devices directly, you can either launch QEMU as root or change the permissions of the USB devices you want to use. For testing, the following suffices: +@example +chown -R myuid /proc/bus/usb +@end example + +@item Launch QEMU and do in the monitor: +@example +info usbhost + Device 1.2, speed 480 Mb/s + Class 00: USB device 1234:5678, USB DISK +@end example +You should see the list of the devices you can use (Never try to use +hubs, it won't work). + +@item Add the device in QEMU by using: +@example +usb_add host:1234:5678 +@end example + +Normally the guest OS should report that a new USB device is +plugged. You can use the option @option{-usbdevice} to do the same. + +@item Now you can try to use the host USB device in QEMU. + +@end enumerate + +When relaunching QEMU, you may have to unplug and plug again the USB +device to make it work again (this is a bug). + @node gdb_usage @section GDB usage diff --git a/vl.c b/vl.c index cab2eb05f..b8088035f 100644 --- a/vl.c +++ b/vl.c @@ -2966,6 +2966,8 @@ void help(void) #ifdef TARGET_I386 "-win2k-hack use it when installing Windows 2000 to avoid a disk full bug\n" #endif + "-usb enable the USB driver (will be the default soon)\n" + "-usbdevice name add the host or guest USB device 'name'\n" #if defined(TARGET_PPC) || defined(TARGET_SPARC) "-g WxH[xDEPTH] Set the initial graphical resolution and depth\n" #endif -- cgit v1.2.3 From 48024e4a485fa82c103978c30c7d59d3a3a09262 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Nov 2005 16:52:11 +0000 Subject: m68k disassembler (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1605 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 + alpha-dis.c | 3 - dis-asm.h | 13 + disas.c | 6 + m68k-dis.c | 5051 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ mips-dis.c | 4 - 6 files changed, 5073 insertions(+), 7 deletions(-) create mode 100644 m68k-dis.c diff --git a/Makefile.target b/Makefile.target index 30a21c5ee..9e06fb635 100644 --- a/Makefile.target +++ b/Makefile.target @@ -240,6 +240,9 @@ 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 ($(ARCH),ia64) OBJS += ia64-syscall.o diff --git a/alpha-dis.c b/alpha-dis.c index e7a4fb402..81a55e9c0 100644 --- a/alpha-dis.c +++ b/alpha-dis.c @@ -23,9 +23,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include #include "dis-asm.h" -#define ATTRIBUTE_UNUSED __attribute__((unused)) -#define _(x) x - /* The opcode table is an array of struct alpha_opcode. */ struct alpha_opcode diff --git a/dis-asm.h b/dis-asm.h index 880baf19e..9d28785bc 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -56,6 +56,17 @@ enum bfd_architecture #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. @@ -417,6 +428,7 @@ extern int generic_symbol_at_address (INFO).insn_info_valid = 0 #define _(x) x +#define ATTRIBUTE_UNUSED __attribute__((unused)) /* from libbfd */ @@ -425,5 +437,6 @@ 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) */ diff --git a/disas.c b/disas.c index f8d8b9ead..feb8a93ca 100644 --- a/disas.c +++ b/disas.c @@ -187,6 +187,8 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) print_insn = print_insn_ppc; #elif defined(TARGET_MIPS) print_insn = print_insn_big_mips; +#elif defined(TARGET_M68K) + print_insn = print_insn_m68k; #else fprintf(out, "0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", code); @@ -251,6 +253,8 @@ void disas(FILE *out, void *code, unsigned long size) 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); @@ -374,6 +378,8 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) print_insn = print_insn_ppc; #elif defined(TARGET_MIPS) print_insn = print_insn_big_mips; +#elif defined(TARGET_M68K) + print_insn = print_insn_m68k; #else term_printf("0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", pc); diff --git a/m68k-dis.c b/m68k-dis.c new file mode 100644 index 000000000..dd195582e --- /dev/null +++ b/m68k-dis.c @@ -0,0 +1,5051 @@ +/* This file is composed of several different files from the upstream + sourceware.org CVS. Original file boundaries marked with **** */ + +#include +#include +#include + +#include "dis-asm.h" + +/* **** foatformat.h from sourceware.org CVS 2005-08-14. */ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright 1991, 1994, 1995, 1997, 2000, 2003 Free Software Foundation, Inc. + +This file is part of GDB. + +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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#if !defined (FLOATFORMAT_H) +#define FLOATFORMAT_H 1 + +/*#include "ansidecl.h" */ + +/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the + bytes are concatenated according to the byteorder flag, then each of those + fields is contiguous. We number the bits with 0 being the most significant + (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field + contains with the *_start and *_len fields. */ + +/* What is the order of the bytes. */ + +enum floatformat_byteorders { + + /* Standard little endian byte order. + EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */ + + floatformat_little, + + /* Standard big endian byte order. + EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */ + + floatformat_big, + + /* Little endian byte order but big endian word order. + EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */ + + floatformat_littlebyte_bigword + +}; + +enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no }; + +struct floatformat +{ + enum floatformat_byteorders byteorder; + unsigned int totalsize; /* Total size of number in bits */ + + /* Sign bit is always one bit long. 1 means negative, 0 means positive. */ + unsigned int sign_start; + + unsigned int exp_start; + unsigned int exp_len; + /* Bias added to a "true" exponent to form the biased exponent. It + is intentionally signed as, otherwize, -exp_bias can turn into a + very large number (e.g., given the exp_bias of 0x3fff and a 64 + bit long, the equation (long)(1 - exp_bias) evaluates to + 4294950914) instead of -16382). */ + int exp_bias; + /* Exponent value which indicates NaN. This is the actual value stored in + the float, not adjusted by the exp_bias. This usually consists of all + one bits. */ + unsigned int exp_nan; + + unsigned int man_start; + unsigned int man_len; + + /* Is the integer bit explicit or implicit? */ + enum floatformat_intbit intbit; + + /* Internal name for debugging. */ + const char *name; + + /* Validator method. */ + int (*is_valid) (const struct floatformat *fmt, const char *from); +}; + +/* floatformats for IEEE single and double, big and little endian. */ + +extern const struct floatformat floatformat_ieee_single_big; +extern const struct floatformat floatformat_ieee_single_little; +extern const struct floatformat floatformat_ieee_double_big; +extern const struct floatformat floatformat_ieee_double_little; + +/* floatformat for ARM IEEE double, little endian bytes and big endian words */ + +extern const struct floatformat floatformat_ieee_double_littlebyte_bigword; + +/* floatformats for various extendeds. */ + +extern const struct floatformat floatformat_i387_ext; +extern const struct floatformat floatformat_m68881_ext; +extern const struct floatformat floatformat_i960_ext; +extern const struct floatformat floatformat_m88110_ext; +extern const struct floatformat floatformat_m88110_harris_ext; +extern const struct floatformat floatformat_arm_ext_big; +extern const struct floatformat floatformat_arm_ext_littlebyte_bigword; +/* IA-64 Floating Point register spilt into memory. */ +extern const struct floatformat floatformat_ia64_spill_big; +extern const struct floatformat floatformat_ia64_spill_little; +extern const struct floatformat floatformat_ia64_quad_big; +extern const struct floatformat floatformat_ia64_quad_little; + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +floatformat_to_double (const struct floatformat *, const char *, double *); + +/* The converse: convert the double *FROM to FMT + and store where TO points. */ + +extern void +floatformat_from_double (const struct floatformat *, const double *, char *); + +/* Return non-zero iff the data at FROM is a valid number in format FMT. */ + +extern int +floatformat_is_valid (const struct floatformat *fmt, const char *from); + +#endif /* defined (FLOATFORMAT_H) */ +/* **** End of floatformat.h */ +/* **** m68k-dis.h from sourceware.org CVS 2005-08-14. */ +/* Opcode table header for m680[01234]0/m6888[12]/m68851. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2001, + 2003, 2004 Free Software Foundation, Inc. + + 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 + 1, 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* These are used as bit flags for the arch field in the m68k_opcode + structure. */ +#define _m68k_undef 0 +#define m68000 0x001 +#define m68008 m68000 /* Synonym for -m68000. otherwise unused. */ +#define m68010 0x002 +#define m68020 0x004 +#define m68030 0x008 +#define m68ec030 m68030 /* Similar enough to -m68030 to ignore differences; + gas will deal with the few differences. */ +#define m68040 0x010 +/* There is no 68050. */ +#define m68060 0x020 +#define m68881 0x040 +#define m68882 m68881 /* Synonym for -m68881. otherwise unused. */ +#define m68851 0x080 +#define cpu32 0x100 /* e.g., 68332 */ + +#define mcfmac 0x200 /* ColdFire MAC. */ +#define mcfemac 0x400 /* ColdFire EMAC. */ +#define cfloat 0x800 /* ColdFire FPU. */ +#define mcfhwdiv 0x1000 /* ColdFire hardware divide. */ + +#define mcfisa_a 0x2000 /* ColdFire ISA_A. */ +#define mcfisa_aa 0x4000 /* ColdFire ISA_A+. */ +#define mcfisa_b 0x8000 /* ColdFire ISA_B. */ +#define mcfusp 0x10000 /* ColdFire USP instructions. */ + +#define mcf5200 0x20000 +#define mcf5206e 0x40000 +#define mcf521x 0x80000 +#define mcf5249 0x100000 +#define mcf528x 0x200000 +#define mcf5307 0x400000 +#define mcf5407 0x800000 +#define mcf5470 0x1000000 +#define mcf5480 0x2000000 + + /* Handy aliases. */ +#define m68040up (m68040 | m68060) +#define m68030up (m68030 | m68040up) +#define m68020up (m68020 | m68030up) +#define m68010up (m68010 | cpu32 | m68020up) +#define m68000up (m68000 | m68010up) + +#define mfloat (m68881 | m68882 | m68040 | m68060) +#define mmmu (m68851 | m68030 | m68040 | m68060) + +/* The structure used to hold information for an opcode. */ + +struct m68k_opcode +{ + /* The opcode name. */ + const char *name; + /* The pseudo-size of the instruction(in bytes). Used to determine + number of bytes necessary to disassemble the instruction. */ + unsigned int size; + /* The opcode itself. */ + unsigned long opcode; + /* The mask used by the disassembler. */ + unsigned long match; + /* The arguments. */ + const char *args; + /* The architectures which support this opcode. */ + unsigned int arch; +}; + +/* The structure used to hold information for an opcode alias. */ + +struct m68k_opcode_alias +{ + /* The alias name. */ + const char *alias; + /* The instruction for which this is an alias. */ + const char *primary; +}; + +/* We store four bytes of opcode for all opcodes because that is the + most any of them need. The actual length of an instruction is + always at least 2 bytes, and is as much longer as necessary to hold + the operands it has. + + The match field is a mask saying which bits must match particular + opcode in order for an instruction to be an instance of that + opcode. + + The args field is a string containing two characters for each + operand of the instruction. The first specifies the kind of + operand; the second, the place it is stored. */ + +/* Kinds of operands: + Characters used: AaBbCcDdEeFfGgHIiJkLlMmnOopQqRrSsTtU VvWwXxYyZz01234|*~%;@!&$?/<>#^+- + + D data register only. Stored as 3 bits. + A address register only. Stored as 3 bits. + a address register indirect only. Stored as 3 bits. + R either kind of register. Stored as 4 bits. + r either kind of register indirect only. Stored as 4 bits. + At the moment, used only for cas2 instruction. + F floating point coprocessor register only. Stored as 3 bits. + O an offset (or width): immediate data 0-31 or data register. + Stored as 6 bits in special format for BF... insns. + + autoincrement only. Stored as 3 bits (number of the address register). + - autodecrement only. Stored as 3 bits (number of the address register). + Q quick immediate data. Stored as 3 bits. + This matches an immediate operand only when value is in range 1 .. 8. + M moveq immediate data. Stored as 8 bits. + This matches an immediate operand only when value is in range -128..127 + T trap vector immediate data. Stored as 4 bits. + + k K-factor for fmove.p instruction. Stored as a 7-bit constant or + a three bit register offset, depending on the field type. + + # immediate data. Stored in special places (b, w or l) + which say how many bits to store. + ^ immediate data for floating point instructions. Special places + are offset by 2 bytes from '#'... + B pc-relative address, converted to an offset + that is treated as immediate data. + d displacement and register. Stores the register as 3 bits + and stores the displacement in the entire second word. + + C the CCR. No need to store it; this is just for filtering validity. + S the SR. No need to store, just as with CCR. + U the USP. No need to store, just as with CCR. + E the MAC ACC. No need to store, just as with CCR. + e the EMAC ACC[0123]. + G the MAC/EMAC MACSR. No need to store, just as with CCR. + g the EMAC ACCEXT{01,23}. + H the MASK. No need to store, just as with CCR. + i the MAC/EMAC scale factor. + + I Coprocessor ID. Not printed if 1. The Coprocessor ID is always + extracted from the 'd' field of word one, which means that an extended + coprocessor opcode can be skipped using the 'i' place, if needed. + + s System Control register for the floating point coprocessor. + + J Misc register for movec instruction, stored in 'j' format. + Possible values: + 0x000 SFC Source Function Code reg [60, 40, 30, 20, 10] + 0x001 DFC Data Function Code reg [60, 40, 30, 20, 10] + 0x002 CACR Cache Control Register [60, 40, 30, 20, mcf] + 0x003 TC MMU Translation Control [60, 40] + 0x004 ITT0 Instruction Transparent + Translation reg 0 [60, 40] + 0x005 ITT1 Instruction Transparent + Translation reg 1 [60, 40] + 0x006 DTT0 Data Transparent + Translation reg 0 [60, 40] + 0x007 DTT1 Data Transparent + Translation reg 1 [60, 40] + 0x008 BUSCR Bus Control Register [60] + 0x800 USP User Stack Pointer [60, 40, 30, 20, 10] + 0x801 VBR Vector Base reg [60, 40, 30, 20, 10, mcf] + 0x802 CAAR Cache Address Register [ 30, 20] + 0x803 MSP Master Stack Pointer [ 40, 30, 20] + 0x804 ISP Interrupt Stack Pointer [ 40, 30, 20] + 0x805 MMUSR MMU Status reg [ 40] + 0x806 URP User Root Pointer [60, 40] + 0x807 SRP Supervisor Root Pointer [60, 40] + 0x808 PCR Processor Configuration reg [60] + 0xC00 ROMBAR ROM Base Address Register [520X] + 0xC04 RAMBAR0 RAM Base Address Register 0 [520X] + 0xC05 RAMBAR1 RAM Base Address Register 0 [520X] + 0xC0F MBAR0 RAM Base Address Register 0 [520X] + 0xC04 FLASHBAR FLASH Base Address Register [mcf528x] + 0xC05 RAMBAR Static RAM Base Address Register [mcf528x] + + L Register list of the type d0-d7/a0-a7 etc. + (New! Improved! Can also hold fp0-fp7, as well!) + The assembler tries to see if the registers match the insn by + looking at where the insn wants them stored. + + l Register list like L, but with all the bits reversed. + Used for going the other way. . . + + c cache identifier which may be "nc" for no cache, "ic" + for instruction cache, "dc" for data cache, or "bc" + for both caches. Used in cinv and cpush. Always + stored in position "d". + + u Any register, with ``upper'' or ``lower'' specification. Used + in the mac instructions with size word. + + The remainder are all stored as 6 bits using an address mode and a + register number; they differ in which addressing modes they match. + + * all (modes 0-6,7.0-4) + ~ alterable memory (modes 2-6,7.0,7.1) + (not 0,1,7.2-4) + % alterable (modes 0-6,7.0,7.1) + (not 7.2-4) + ; data (modes 0,2-6,7.0-4) + (not 1) + @ data, but not immediate (modes 0,2-6,7.0-3) + (not 1,7.4) + ! control (modes 2,5,6,7.0-3) + (not 0,1,3,4,7.4) + & alterable control (modes 2,5,6,7.0,7.1) + (not 0,1,3,4,7.2-4) + $ alterable data (modes 0,2-6,7.0,7.1) + (not 1,7.2-4) + ? alterable control, or data register (modes 0,2,5,6,7.0,7.1) + (not 1,3,4,7.2-4) + / control, or data register (modes 0,2,5,6,7.0-3) + (not 1,3,4,7.4) + > *save operands (modes 2,4,5,6,7.0,7.1) + (not 0,1,3,7.2-4) + < *restore operands (modes 2,3,5,6,7.0-3) + (not 0,1,4,7.4) + + coldfire move operands: + m (modes 0-4) + n (modes 5,7.2) + o (modes 6,7.0,7.1,7.3,7.4) + p (modes 0-5) + + coldfire bset/bclr/btst/mulsl/mulul operands: + q (modes 0,2-5) + v (modes 0,2-5,7.0,7.1) + b (modes 0,2-5,7.2) + w (modes 2-5,7.2) + y (modes 2,5) + z (modes 2,5,7.2) + x mov3q immediate operand. + 4 (modes 2,3,4,5) + */ + +/* For the 68851: */ +/* I didn't use much imagination in choosing the + following codes, so many of them aren't very + mnemonic. -rab + + 0 32 bit pmmu register + Possible values: + 000 TC Translation Control Register (68030, 68851) + + 1 16 bit pmmu register + 111 AC Access Control (68851) + + 2 8 bit pmmu register + 100 CAL Current Access Level (68851) + 101 VAL Validate Access Level (68851) + 110 SCC Stack Change Control (68851) + + 3 68030-only pmmu registers (32 bit) + 010 TT0 Transparent Translation reg 0 + (aka Access Control reg 0 -- AC0 -- on 68ec030) + 011 TT1 Transparent Translation reg 1 + (aka Access Control reg 1 -- AC1 -- on 68ec030) + + W wide pmmu registers + Possible values: + 001 DRP Dma Root Pointer (68851) + 010 SRP Supervisor Root Pointer (68030, 68851) + 011 CRP Cpu Root Pointer (68030, 68851) + + f function code register (68030, 68851) + 0 SFC + 1 DFC + + V VAL register only (68851) + + X BADx, BACx (16 bit) + 100 BAD Breakpoint Acknowledge Data (68851) + 101 BAC Breakpoint Acknowledge Control (68851) + + Y PSR (68851) (MMUSR on 68030) (ACUSR on 68ec030) + Z PCSR (68851) + + | memory (modes 2-6, 7.*) + + t address test level (68030 only) + Stored as 3 bits, range 0-7. + Also used for breakpoint instruction now. + +*/ + +/* Places to put an operand, for non-general operands: + Characters used: BbCcDdFfGgHhIijkLlMmNnostWw123456789/ + + s source, low bits of first word. + d dest, shifted 9 in first word + 1 second word, shifted 12 + 2 second word, shifted 6 + 3 second word, shifted 0 + 4 third word, shifted 12 + 5 third word, shifted 6 + 6 third word, shifted 0 + 7 second word, shifted 7 + 8 second word, shifted 10 + 9 second word, shifted 5 + D store in both place 1 and place 3; for divul and divsl. + B first word, low byte, for branch displacements + W second word (entire), for branch displacements + L second and third words (entire), for branch displacements + (also overloaded for move16) + b second word, low byte + w second word (entire) [variable word/long branch offset for dbra] + W second word (entire) (must be signed 16 bit value) + l second and third word (entire) + g variable branch offset for bra and similar instructions. + The place to store depends on the magnitude of offset. + t store in both place 7 and place 8; for floating point operations + c branch offset for cpBcc operations. + The place to store is word two if bit six of word one is zero, + and words two and three if bit six of word one is one. + i Increment by two, to skip over coprocessor extended operands. Only + works with the 'I' format. + k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number. + Also used for dynamic fmovem instruction. + C floating point coprocessor constant - 7 bits. Also used for static + K-factors... + j Movec register #, stored in 12 low bits of second word. + m For M[S]ACx; 4 bits split with MSB shifted 6 bits in first word + and remaining 3 bits of register shifted 9 bits in first word. + Indicate upper/lower in 1 bit shifted 7 bits in second word. + Use with `R' or `u' format. + n `m' withouth upper/lower indication. (For M[S]ACx; 4 bits split + with MSB shifted 6 bits in first word and remaining 3 bits of + register shifted 9 bits in first word. No upper/lower + indication is done.) Use with `R' or `u' format. + o For M[S]ACw; 4 bits shifted 12 in second word (like `1'). + Indicate upper/lower in 1 bit shifted 7 bits in second word. + Use with `R' or `u' format. + M For M[S]ACw; 4 bits in low bits of first word. Indicate + upper/lower in 1 bit shifted 6 bits in second word. Use with + `R' or `u' format. + N For M[S]ACw; 4 bits in low bits of second word. Indicate + upper/lower in 1 bit shifted 6 bits in second word. Use with + `R' or `u' format. + h shift indicator (scale factor), 1 bit shifted 10 in second word + + Places to put operand, for general operands: + d destination, shifted 6 bits in first word + b source, at low bit of first word, and immediate uses one byte + w source, at low bit of first word, and immediate uses two bytes + l source, at low bit of first word, and immediate uses four bytes + s source, at low bit of first word. + Used sometimes in contexts where immediate is not allowed anyway. + f single precision float, low bit of 1st word, immediate uses 4 bytes + F double precision float, low bit of 1st word, immediate uses 8 bytes + x extended precision float, low bit of 1st word, immediate uses 12 bytes + p packed float, low bit of 1st word, immediate uses 12 bytes + G EMAC accumulator, load (bit 4 2nd word, !bit8 first word) + H EMAC accumulator, non load (bit 4 2nd word, bit 8 first word) + F EMAC ACCx + f EMAC ACCy + I MAC/EMAC scale factor + / Like 's', but set 2nd word, bit 5 if trailing_ampersand set + ] first word, bit 10 +*/ + +extern const struct m68k_opcode m68k_opcodes[]; +extern const struct m68k_opcode_alias m68k_opcode_aliases[]; + +extern const int m68k_numopcodes, m68k_numaliases; + +/* **** End of m68k-opcode.h */ +/* **** m68k-dis.c from sourceware.org CVS 2005-08-14. */ +/* Print Motorola 68k instructions. + Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + This file 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., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* Local function prototypes. */ + +const char * const fpcr_names[] = +{ + "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr", + "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr" +}; + +static char *const reg_names[] = +{ + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp", + "%ps", "%pc" +}; + +/* Name of register halves for MAC/EMAC. + Seperate from reg_names since 'spu', 'fpl' look weird. */ +static char *const reg_half_names[] = +{ + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", + "%ps", "%pc" +}; + +/* Sign-extend an (unsigned char). */ +#if __STDC__ == 1 +#define COERCE_SIGNED_CHAR(ch) ((signed char) (ch)) +#else +#define COERCE_SIGNED_CHAR(ch) ((int) (((ch) ^ 0x80) & 0xFF) - 128) +#endif + +/* Get a 1 byte signed integer. */ +#define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1])) + +/* Get a 2 byte signed integer. */ +#define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000)) +#define NEXTWORD(p) \ + (p += 2, FETCH_DATA (info, p), \ + COERCE16 ((p[-2] << 8) + p[-1])) + +/* Get a 4 byte signed integer. */ +#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000) +#define NEXTLONG(p) \ + (p += 4, FETCH_DATA (info, p), \ + (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))) + +/* Get a 4 byte unsigned integer. */ +#define NEXTULONG(p) \ + (p += 4, FETCH_DATA (info, p), \ + (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])) + +/* Get a single precision float. */ +#define NEXTSINGLE(val, p) \ + (p += 4, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val)) + +/* Get a double precision float. */ +#define NEXTDOUBLE(val, p) \ + (p += 8, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val)) + +/* Get an extended precision float. */ +#define NEXTEXTEND(val, p) \ + (p += 12, FETCH_DATA (info, p), \ + floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val)) + +/* Need a function to convert from packed to double + precision. Actually, it's easier to print a + packed number than a double anyway, so maybe + there should be a special case to handle this... */ +#define NEXTPACKED(p) \ + (p += 12, FETCH_DATA (info, p), 0.0) + +/* Maximum length of an instruction. */ +#define MAXLEN 22 + +#include + +struct private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + jmp_buf bailout; +}; + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct private *) (info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (struct disassemble_info *info, bfd_byte *addr) +{ + int status; + struct private *priv = (struct private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + (*info->memory_error_func) (status, start, info); + longjmp (priv->bailout, 1); + } + else + priv->max_fetched = addr; + return 1; +} + +/* This function is used to print to the bit-bucket. */ +static int +dummy_printer (FILE *file ATTRIBUTE_UNUSED, + const char *format ATTRIBUTE_UNUSED, + ...) +{ + return 0; +} + +static void +dummy_print_address (bfd_vma vma ATTRIBUTE_UNUSED, + struct disassemble_info *info ATTRIBUTE_UNUSED) +{ +} + +/* Fetch BITS bits from a position in the instruction specified by CODE. + CODE is a "place to put an argument", or 'x' for a destination + that is a general address (mode and register). + BUFFER contains the instruction. */ + +static int +fetch_arg (unsigned char *buffer, + int code, + int bits, + disassemble_info *info) +{ + int val = 0; + + switch (code) + { + case '/': /* MAC/EMAC mask bit. */ + val = buffer[3] >> 5; + break; + + case 'G': /* EMAC ACC load. */ + val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1); + break; + + case 'H': /* EMAC ACC !load. */ + val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1); + break; + + case ']': /* EMAC ACCEXT bit. */ + val = buffer[0] >> 2; + break; + + case 'I': /* MAC/EMAC scale factor. */ + val = buffer[2] >> 1; + break; + + case 'F': /* EMAC ACCx. */ + val = buffer[0] >> 1; + break; + + case 'f': + val = buffer[1]; + break; + + case 's': + val = buffer[1]; + break; + + case 'd': /* Destination, for register or quick. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 9; + break; + + case 'x': /* Destination, for general arg. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 6; + break; + + case 'k': + FETCH_DATA (info, buffer + 3); + val = (buffer[3] >> 4); + break; + + case 'C': + FETCH_DATA (info, buffer + 3); + val = buffer[3]; + break; + + case '1': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 12; + break; + + case '2': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 6; + break; + + case '3': + case 'j': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + break; + + case '4': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + val >>= 12; + break; + + case '5': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + val >>= 6; + break; + + case '6': + FETCH_DATA (info, buffer + 5); + val = (buffer[4] << 8) + buffer[5]; + break; + + case '7': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 7; + break; + + case '8': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 10; + break; + + case '9': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] << 8) + buffer[3]; + val >>= 5; + break; + + case 'e': + val = (buffer[1] >> 6); + break; + + case 'm': + val = (buffer[1] & 0x40 ? 0x8 : 0) + | ((buffer[0] >> 1) & 0x7) + | (buffer[3] & 0x80 ? 0x10 : 0); + break; + + case 'n': + val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7); + break; + + case 'o': + val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0); + break; + + case 'M': + val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0); + break; + + case 'N': + val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0); + break; + + case 'h': + val = buffer[2] >> 2; + break; + + default: + abort (); + } + + switch (bits) + { + case 1: + return val & 1; + case 2: + return val & 3; + case 3: + return val & 7; + case 4: + return val & 017; + case 5: + return val & 037; + case 6: + return val & 077; + case 7: + return val & 0177; + case 8: + return val & 0377; + case 12: + return val & 07777; + default: + abort (); + } +} + +/* Check if an EA is valid for a particular code. This is required + for the EMAC instructions since the type of source address determines + if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it + is a non-load EMAC instruction and the bits mean register Ry. + A similar case exists for the movem instructions where the register + mask is interpreted differently for different EAs. */ + +static bfd_boolean +m68k_valid_ea (char code, int val) +{ + int mode, mask; +#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \ + (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \ + | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11) + + switch (code) + { + case '*': + mask = M (1,1,1,1,1,1,1,1,1,1,1,1); + break; + case '~': + mask = M (0,0,1,1,1,1,1,1,1,0,0,0); + break; + case '%': + mask = M (1,1,1,1,1,1,1,1,1,0,0,0); + break; + case ';': + mask = M (1,0,1,1,1,1,1,1,1,1,1,1); + break; + case '@': + mask = M (1,0,1,1,1,1,1,1,1,1,1,0); + break; + case '!': + mask = M (0,0,1,0,0,1,1,1,1,1,1,0); + break; + case '&': + mask = M (0,0,1,0,0,1,1,1,1,0,0,0); + break; + case '$': + mask = M (1,0,1,1,1,1,1,1,1,0,0,0); + break; + case '?': + mask = M (1,0,1,0,0,1,1,1,1,0,0,0); + break; + case '/': + mask = M (1,0,1,0,0,1,1,1,1,1,1,0); + break; + case '|': + mask = M (0,0,1,0,0,1,1,1,1,1,1,0); + break; + case '>': + mask = M (0,0,1,0,1,1,1,1,1,0,0,0); + break; + case '<': + mask = M (0,0,1,1,0,1,1,1,1,1,1,0); + break; + case 'm': + mask = M (1,1,1,1,1,0,0,0,0,0,0,0); + break; + case 'n': + mask = M (0,0,0,0,0,1,0,0,0,1,0,0); + break; + case 'o': + mask = M (0,0,0,0,0,0,1,1,1,0,1,1); + break; + case 'p': + mask = M (1,1,1,1,1,1,0,0,0,0,0,0); + break; + case 'q': + mask = M (1,0,1,1,1,1,0,0,0,0,0,0); + break; + case 'v': + mask = M (1,0,1,1,1,1,0,1,1,0,0,0); + break; + case 'b': + mask = M (1,0,1,1,1,1,0,0,0,1,0,0); + break; + case 'w': + mask = M (0,0,1,1,1,1,0,0,0,1,0,0); + break; + case 'y': + mask = M (0,0,1,0,0,1,0,0,0,0,0,0); + break; + case 'z': + mask = M (0,0,1,0,0,1,0,0,0,1,0,0); + break; + case '4': + mask = M (0,0,1,1,1,1,0,0,0,0,0,0); + break; + default: + abort (); + } +#undef M + + mode = (val >> 3) & 7; + if (mode == 7) + mode += val & 7; + return (mask & (1 << mode)) != 0; +} + +/* Print a base register REGNO and displacement DISP, on INFO->STREAM. + REGNO = -1 for pc, -2 for none (suppressed). */ + +static void +print_base (int regno, bfd_vma disp, disassemble_info *info) +{ + if (regno == -1) + { + (*info->fprintf_func) (info->stream, "%%pc@("); + (*info->print_address_func) (disp, info); + } + else + { + char buf[50]; + + if (regno == -2) + (*info->fprintf_func) (info->stream, "@("); + else if (regno == -3) + (*info->fprintf_func) (info->stream, "%%zpc@("); + else + (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]); + + sprintf_vma (buf, disp); + (*info->fprintf_func) (info->stream, "%s", buf); + } +} + +/* Print an indexed argument. The base register is BASEREG (-1 for pc). + P points to extension word, in buffer. + ADDR is the nominal core address of that extension word. */ + +static unsigned char * +print_indexed (int basereg, + unsigned char *p, + bfd_vma addr, + disassemble_info *info) +{ + int word; + static char *const scales[] = { "", ":2", ":4", ":8" }; + bfd_vma base_disp; + bfd_vma outer_disp; + char buf[40]; + char vmabuf[50]; + + word = NEXTWORD (p); + + /* Generate the text for the index register. + Where this will be output is not yet determined. */ + sprintf (buf, "%s:%c%s", + reg_names[(word >> 12) & 0xf], + (word & 0x800) ? 'l' : 'w', + scales[(word >> 9) & 3]); + + /* Handle the 68000 style of indexing. */ + + if ((word & 0x100) == 0) + { + base_disp = word & 0xff; + if ((base_disp & 0x80) != 0) + base_disp -= 0x100; + if (basereg == -1) + base_disp += addr; + print_base (basereg, base_disp, info); + (*info->fprintf_func) (info->stream, ",%s)", buf); + return p; + } + + /* Handle the generalized kind. */ + /* First, compute the displacement to add to the base register. */ + if (word & 0200) + { + if (basereg == -1) + basereg = -3; + else + basereg = -2; + } + if (word & 0100) + buf[0] = '\0'; + base_disp = 0; + switch ((word >> 4) & 3) + { + case 2: + base_disp = NEXTWORD (p); + break; + case 3: + base_disp = NEXTLONG (p); + } + if (basereg == -1) + base_disp += addr; + + /* Handle single-level case (not indirect). */ + if ((word & 7) == 0) + { + print_base (basereg, base_disp, info); + if (buf[0] != '\0') + (*info->fprintf_func) (info->stream, ",%s", buf); + (*info->fprintf_func) (info->stream, ")"); + return p; + } + + /* Two level. Compute displacement to add after indirection. */ + outer_disp = 0; + switch (word & 3) + { + case 2: + outer_disp = NEXTWORD (p); + break; + case 3: + outer_disp = NEXTLONG (p); + } + + print_base (basereg, base_disp, info); + if ((word & 4) == 0 && buf[0] != '\0') + { + (*info->fprintf_func) (info->stream, ",%s", buf); + buf[0] = '\0'; + } + sprintf_vma (vmabuf, outer_disp); + (*info->fprintf_func) (info->stream, ")@(%s", vmabuf); + if (buf[0] != '\0') + (*info->fprintf_func) (info->stream, ",%s", buf); + (*info->fprintf_func) (info->stream, ")"); + + return p; +} + +/* Returns number of bytes "eaten" by the operand, or + return -1 if an invalid operand was found, or -2 if + an opcode tabe error was found. + ADDR is the pc for this arg to be relative to. */ + +static int +print_insn_arg (const char *d, + unsigned char *buffer, + unsigned char *p0, + bfd_vma addr, + disassemble_info *info) +{ + int val = 0; + int place = d[1]; + unsigned char *p = p0; + int regno; + const char *regname; + unsigned char *p1; + double flval; + int flt_p; + bfd_signed_vma disp; + unsigned int uval; + + switch (*d) + { + case 'c': /* Cache identifier. */ + { + static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" }; + val = fetch_arg (buffer, place, 2, info); + (*info->fprintf_func) (info->stream, cacheFieldName[val]); + break; + } + + case 'a': /* Address register indirect only. Cf. case '+'. */ + { + (*info->fprintf_func) + (info->stream, + "%s@", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + } + + case '_': /* 32-bit absolute address for move16. */ + { + uval = NEXTULONG (p); + (*info->print_address_func) (uval, info); + break; + } + + case 'C': + (*info->fprintf_func) (info->stream, "%%ccr"); + break; + + case 'S': + (*info->fprintf_func) (info->stream, "%%sr"); + break; + + case 'U': + (*info->fprintf_func) (info->stream, "%%usp"); + break; + + case 'E': + (*info->fprintf_func) (info->stream, "%%acc"); + break; + + case 'G': + (*info->fprintf_func) (info->stream, "%%macsr"); + break; + + case 'H': + (*info->fprintf_func) (info->stream, "%%mask"); + break; + + case 'J': + { + /* FIXME: There's a problem here, different m68k processors call the + same address different names. This table can't get it right + because it doesn't know which processor it's disassembling for. */ + static const struct { char *name; int value; } names[] + = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002}, + {"%tc", 0x003}, {"%itt0",0x004}, {"%itt1", 0x005}, + {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008}, + {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802}, + {"%msp", 0x803}, {"%isp", 0x804}, + {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these. */ + + /* Should we be calling this psr like we do in case 'Y'? */ + {"%mmusr",0x805}, + + {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}}; + + val = fetch_arg (buffer, place, 12, info); + for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) + if (names[regno].value == val) + { + (*info->fprintf_func) (info->stream, "%s", names[regno].name); + break; + } + if (regno < 0) + (*info->fprintf_func) (info->stream, "%d", val); + } + break; + + case 'Q': + val = fetch_arg (buffer, place, 3, info); + /* 0 means 8, except for the bkpt instruction... */ + if (val == 0 && d[1] != 's') + val = 8; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'x': + val = fetch_arg (buffer, place, 3, info); + /* 0 means -1. */ + if (val == 0) + val = -1; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'M': + if (place == 'h') + { + static char *const scalefactor_name[] = { "<<", ">>" }; + val = fetch_arg (buffer, place, 1, info); + (*info->fprintf_func) (info->stream, scalefactor_name[val]); + } + else + { + val = fetch_arg (buffer, place, 8, info); + if (val & 0x80) + val = val - 0x100; + (*info->fprintf_func) (info->stream, "#%d", val); + } + break; + + case 'T': + val = fetch_arg (buffer, place, 4, info); + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'D': + (*info->fprintf_func) (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 3, info)]); + break; + + case 'A': + (*info->fprintf_func) + (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 3, info) + 010]); + break; + + case 'R': + (*info->fprintf_func) + (info->stream, "%s", + reg_names[fetch_arg (buffer, place, 4, info)]); + break; + + case 'r': + regno = fetch_arg (buffer, place, 4, info); + if (regno > 7) + (*info->fprintf_func) (info->stream, "%s@", reg_names[regno]); + else + (*info->fprintf_func) (info->stream, "@(%s)", reg_names[regno]); + break; + + case 'F': + (*info->fprintf_func) + (info->stream, "%%fp%d", + fetch_arg (buffer, place, 3, info)); + break; + + case 'O': + val = fetch_arg (buffer, place, 6, info); + if (val & 0x20) + (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]); + else + (*info->fprintf_func) (info->stream, "%d", val); + break; + + case '+': + (*info->fprintf_func) + (info->stream, "%s@+", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + + case '-': + (*info->fprintf_func) + (info->stream, "%s@-", + reg_names[fetch_arg (buffer, place, 3, info) + 8]); + break; + + case 'k': + if (place == 'k') + (*info->fprintf_func) + (info->stream, "{%s}", + reg_names[fetch_arg (buffer, place, 3, info)]); + else if (place == 'C') + { + val = fetch_arg (buffer, place, 7, info); + if (val > 63) /* This is a signed constant. */ + val -= 128; + (*info->fprintf_func) (info->stream, "{#%d}", val); + } + else + return -2; + break; + + case '#': + case '^': + p1 = buffer + (*d == '#' ? 2 : 4); + if (place == 's') + val = fetch_arg (buffer, place, 4, info); + else if (place == 'C') + val = fetch_arg (buffer, place, 7, info); + else if (place == '8') + val = fetch_arg (buffer, place, 3, info); + else if (place == '3') + val = fetch_arg (buffer, place, 8, info); + else if (place == 'b') + val = NEXTBYTE (p1); + else if (place == 'w' || place == 'W') + val = NEXTWORD (p1); + else if (place == 'l') + val = NEXTLONG (p1); + else + return -2; + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + case 'B': + if (place == 'b') + disp = NEXTBYTE (p); + else if (place == 'B') + disp = COERCE_SIGNED_CHAR (buffer[1]); + else if (place == 'w' || place == 'W') + disp = NEXTWORD (p); + else if (place == 'l' || place == 'L' || place == 'C') + disp = NEXTLONG (p); + else if (place == 'g') + { + disp = NEXTBYTE (buffer); + if (disp == 0) + disp = NEXTWORD (p); + else if (disp == -1) + disp = NEXTLONG (p); + } + else if (place == 'c') + { + if (buffer[1] & 0x40) /* If bit six is one, long offset. */ + disp = NEXTLONG (p); + else + disp = NEXTWORD (p); + } + else + return -2; + + (*info->print_address_func) (addr + disp, info); + break; + + case 'd': + val = NEXTWORD (p); + (*info->fprintf_func) + (info->stream, "%s@(%d)", + reg_names[fetch_arg (buffer, place, 3, info) + 8], val); + break; + + case 's': + (*info->fprintf_func) (info->stream, "%s", + fpcr_names[fetch_arg (buffer, place, 3, info)]); + break; + + case 'e': + val = fetch_arg(buffer, place, 2, info); + (*info->fprintf_func) (info->stream, "%%acc%d", val); + break; + + case 'g': + val = fetch_arg(buffer, place, 1, info); + (*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23"); + break; + + case 'i': + val = fetch_arg(buffer, place, 2, info); + if (val == 1) + (*info->fprintf_func) (info->stream, "<<"); + else if (val == 3) + (*info->fprintf_func) (info->stream, ">>"); + else + return -1; + break; + + case 'I': + /* Get coprocessor ID... */ + val = fetch_arg (buffer, 'd', 3, info); + + if (val != 1) /* Unusual coprocessor ID? */ + (*info->fprintf_func) (info->stream, "(cpid=%d) ", val); + break; + + case '4': + case '*': + case '~': + case '%': + case ';': + case '@': + case '!': + case '$': + case '?': + case '/': + case '&': + case '|': + case '<': + case '>': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'v': + case 'b': + case 'w': + case 'y': + case 'z': + if (place == 'd') + { + val = fetch_arg (buffer, 'x', 6, info); + val = ((val & 7) << 3) + ((val >> 3) & 7); + } + else + val = fetch_arg (buffer, 's', 6, info); + + /* If the is invalid for *d, then reject this match. */ + if (!m68k_valid_ea (*d, val)) + return -1; + + /* Get register number assuming address register. */ + regno = (val & 7) + 8; + regname = reg_names[regno]; + switch (val >> 3) + { + case 0: + (*info->fprintf_func) (info->stream, "%s", reg_names[val]); + break; + + case 1: + (*info->fprintf_func) (info->stream, "%s", regname); + break; + + case 2: + (*info->fprintf_func) (info->stream, "%s@", regname); + break; + + case 3: + (*info->fprintf_func) (info->stream, "%s@+", regname); + break; + + case 4: + (*info->fprintf_func) (info->stream, "%s@-", regname); + break; + + case 5: + val = NEXTWORD (p); + (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val); + break; + + case 6: + p = print_indexed (regno, p, addr, info); + break; + + case 7: + switch (val & 7) + { + case 0: + val = NEXTWORD (p); + (*info->print_address_func) (val, info); + break; + + case 1: + uval = NEXTULONG (p); + (*info->print_address_func) (uval, info); + break; + + case 2: + val = NEXTWORD (p); + (*info->fprintf_func) (info->stream, "%%pc@("); + (*info->print_address_func) (addr + val, info); + (*info->fprintf_func) (info->stream, ")"); + break; + + case 3: + p = print_indexed (-1, p, addr, info); + break; + + case 4: + flt_p = 1; /* Assume it's a float... */ + switch (place) + { + case 'b': + val = NEXTBYTE (p); + flt_p = 0; + break; + + case 'w': + val = NEXTWORD (p); + flt_p = 0; + break; + + case 'l': + val = NEXTLONG (p); + flt_p = 0; + break; + + case 'f': + NEXTSINGLE (flval, p); + break; + + case 'F': + NEXTDOUBLE (flval, p); + break; + + case 'x': + NEXTEXTEND (flval, p); + break; + + case 'p': + flval = NEXTPACKED (p); + break; + + default: + return -1; + } + if (flt_p) /* Print a float? */ + (*info->fprintf_func) (info->stream, "#%g", flval); + else + (*info->fprintf_func) (info->stream, "#%d", val); + break; + + default: + return -1; + } + } + + /* If place is '/', then this is the case of the mask bit for + mac/emac loads. Now that the arg has been printed, grab the + mask bit and if set, add a '&' to the arg. */ + if (place == '/') + { + val = fetch_arg (buffer, place, 1, info); + if (val) + info->fprintf_func (info->stream, "&"); + } + break; + + case 'L': + case 'l': + if (place == 'w') + { + char doneany; + p1 = buffer + 2; + val = NEXTWORD (p1); + /* Move the pointer ahead if this point is farther ahead + than the last. */ + p = p1 > p ? p1 : p; + if (val == 0) + { + (*info->fprintf_func) (info->stream, "#0"); + break; + } + if (*d == 'l') + { + int newval = 0; + + for (regno = 0; regno < 16; ++regno) + if (val & (0x8000 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xffff; + doneany = 0; + for (regno = 0; regno < 16; ++regno) + if (val & (1 << regno)) + { + int first_regno; + + if (doneany) + (*info->fprintf_func) (info->stream, "/"); + doneany = 1; + (*info->fprintf_func) (info->stream, "%s", reg_names[regno]); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + (*info->fprintf_func) (info->stream, "-%s", + reg_names[regno]); + } + } + else if (place == '3') + { + /* `fmovem' insn. */ + char doneany; + val = fetch_arg (buffer, place, 8, info); + if (val == 0) + { + (*info->fprintf_func) (info->stream, "#0"); + break; + } + if (*d == 'l') + { + int newval = 0; + + for (regno = 0; regno < 8; ++regno) + if (val & (0x80 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xff; + doneany = 0; + for (regno = 0; regno < 8; ++regno) + if (val & (1 << regno)) + { + int first_regno; + if (doneany) + (*info->fprintf_func) (info->stream, "/"); + doneany = 1; + (*info->fprintf_func) (info->stream, "%%fp%d", regno); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + (*info->fprintf_func) (info->stream, "-%%fp%d", regno); + } + } + else if (place == '8') + { + /* fmoveml for FP status registers. */ + (*info->fprintf_func) (info->stream, "%s", + fpcr_names[fetch_arg (buffer, place, 3, + info)]); + } + else + return -2; + break; + + case 'X': + place = '8'; + case 'Y': + case 'Z': + case 'W': + case '0': + case '1': + case '2': + case '3': + { + int val = fetch_arg (buffer, place, 5, info); + char *name = 0; + + switch (val) + { + case 2: name = "%tt0"; break; + case 3: name = "%tt1"; break; + case 0x10: name = "%tc"; break; + case 0x11: name = "%drp"; break; + case 0x12: name = "%srp"; break; + case 0x13: name = "%crp"; break; + case 0x14: name = "%cal"; break; + case 0x15: name = "%val"; break; + case 0x16: name = "%scc"; break; + case 0x17: name = "%ac"; break; + case 0x18: name = "%psr"; break; + case 0x19: name = "%pcsr"; break; + case 0x1c: + case 0x1d: + { + int break_reg = ((buffer[3] >> 2) & 7); + + (*info->fprintf_func) + (info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d", + break_reg); + } + break; + default: + (*info->fprintf_func) (info->stream, "", val); + } + if (name) + (*info->fprintf_func) (info->stream, "%s", name); + } + break; + + case 'f': + { + int fc = fetch_arg (buffer, place, 5, info); + + if (fc == 1) + (*info->fprintf_func) (info->stream, "%%dfc"); + else if (fc == 0) + (*info->fprintf_func) (info->stream, "%%sfc"); + else + /* xgettext:c-format */ + (*info->fprintf_func) (info->stream, _(""), fc); + } + break; + + case 'V': + (*info->fprintf_func) (info->stream, "%%val"); + break; + + case 't': + { + int level = fetch_arg (buffer, place, 3, info); + + (*info->fprintf_func) (info->stream, "%d", level); + } + break; + + case 'u': + { + short is_upper = 0; + int reg = fetch_arg (buffer, place, 5, info); + + if (reg & 0x10) + { + is_upper = 1; + reg &= 0xf; + } + (*info->fprintf_func) (info->stream, "%s%s", + reg_half_names[reg], + is_upper ? "u" : "l"); + } + break; + + default: + return -2; + } + + return p - p0; +} + +/* Try to match the current instruction to best and if so, return the + number of bytes consumed from the instruction stream, else zero. */ + +static int +match_insn_m68k (bfd_vma memaddr, + disassemble_info * info, + const struct m68k_opcode * best, + struct private * priv) +{ + unsigned char *save_p; + unsigned char *p; + const char *d; + + bfd_byte *buffer = priv->the_buffer; + fprintf_ftype save_printer = info->fprintf_func; + void (* save_print_address) (bfd_vma, struct disassemble_info *) + = info->print_address_func; + + /* Point at first word of argument data, + and at descriptor for first argument. */ + p = buffer + 2; + + /* Figure out how long the fixed-size portion of the instruction is. + The only place this is stored in the opcode table is + in the arguments--look for arguments which specify fields in the 2nd + or 3rd words of the instruction. */ + for (d = best->args; *d; d += 2) + { + /* I don't think it is necessary to be checking d[0] here; + I suspect all this could be moved to the case statement below. */ + if (d[0] == '#') + { + if (d[1] == 'l' && p - buffer < 6) + p = buffer + 6; + else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8') + p = buffer + 4; + } + + if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4) + p = buffer + 4; + + switch (d[1]) + { + case '1': + case '2': + case '3': + case '7': + case '8': + case '9': + case 'i': + if (p - buffer < 4) + p = buffer + 4; + break; + case '4': + case '5': + case '6': + if (p - buffer < 6) + p = buffer + 6; + break; + default: + break; + } + } + + /* pflusha is an exceptions. It takes no arguments but is two words + long. Recognize it by looking at the lower 16 bits of the mask. */ + if (p - buffer < 4 && (best->match & 0xFFFF) != 0) + p = buffer + 4; + + /* lpstop is another exception. It takes a one word argument but is + three words long. */ + if (p - buffer < 6 + && (best->match & 0xffff) == 0xffff + && best->args[0] == '#' + && best->args[1] == 'w') + { + /* Copy the one word argument into the usual location for a one + word argument, to simplify printing it. We can get away with + this because we know exactly what the second word is, and we + aren't going to print anything based on it. */ + p = buffer + 6; + FETCH_DATA (info, p); + buffer[2] = buffer[4]; + buffer[3] = buffer[5]; + } + + FETCH_DATA (info, p); + + d = best->args; + + save_p = p; + info->print_address_func = dummy_print_address; + info->fprintf_func = (fprintf_ftype) dummy_printer; + + /* We scan the operands twice. The first time we don't print anything, + but look for errors. */ + for (; *d; d += 2) + { + int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); + + if (eaten >= 0) + p += eaten; + else if (eaten == -1) + { + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + return 0; + } + else + { + info->fprintf_func (info->stream, + /* xgettext:c-format */ + _("\n"), + best->name, best->args); + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + return 2; + } + } + + p = save_p; + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + + d = best->args; + + info->fprintf_func (info->stream, "%s", best->name); + + if (*d) + info->fprintf_func (info->stream, " "); + + while (*d) + { + p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); + d += 2; + + if (*d && *(d - 2) != 'I' && *d != 'k') + info->fprintf_func (info->stream, ","); + } + + return p - buffer; +} + +/* Print the m68k instruction at address MEMADDR in debugged memory, + on INFO->STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn_m68k (bfd_vma memaddr, disassemble_info *info) +{ + int i; + const char *d; + unsigned int arch_mask; + struct private priv; + bfd_byte *buffer = priv.the_buffer; + int major_opcode; + static int numopcodes[16]; + static const struct m68k_opcode **opcodes[16]; + int val; + + if (!opcodes[0]) + { + /* Speed up the matching by sorting the opcode + table on the upper four bits of the opcode. */ + const struct m68k_opcode **opc_pointer[16]; + + /* First count how many opcodes are in each of the sixteen buckets. */ + for (i = 0; i < m68k_numopcodes; i++) + numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++; + + /* Then create a sorted table of pointers + that point into the unsorted table. */ + opc_pointer[0] = malloc (sizeof (struct m68k_opcode *) + * m68k_numopcodes); + opcodes[0] = opc_pointer[0]; + + for (i = 1; i < 16; i++) + { + opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1]; + opcodes[i] = opc_pointer[i]; + } + + for (i = 0; i < m68k_numopcodes; i++) + *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i]; + } + + info->private_data = (PTR) &priv; + /* Tell objdump to use two bytes per chunk + and six bytes per line for displaying raw data. */ + info->bytes_per_chunk = 2; + info->bytes_per_line = 6; + info->display_endian = BFD_ENDIAN_BIG; + priv.max_fetched = priv.the_buffer; + priv.insn_start = memaddr; + + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + switch (info->mach) + { + default: + case 0: + arch_mask = (unsigned int) -1; + break; + case bfd_mach_m68000: + arch_mask = m68000|m68881|m68851; + break; + case bfd_mach_m68008: + arch_mask = m68008|m68881|m68851; + break; + case bfd_mach_m68010: + arch_mask = m68010|m68881|m68851; + break; + case bfd_mach_m68020: + arch_mask = m68020|m68881|m68851; + break; + case bfd_mach_m68030: + arch_mask = m68030|m68881|m68851; + break; + case bfd_mach_m68040: + arch_mask = m68040|m68881|m68851; + break; + case bfd_mach_m68060: + arch_mask = m68060|m68881|m68851; + break; + case bfd_mach_mcf5200: + arch_mask = mcfisa_a; + break; + case bfd_mach_mcf521x: + case bfd_mach_mcf528x: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac; + break; + case bfd_mach_mcf5206e: + arch_mask = mcfisa_a|mcfhwdiv|mcfmac; + break; + case bfd_mach_mcf5249: + arch_mask = mcfisa_a|mcfhwdiv|mcfemac; + break; + case bfd_mach_mcf5307: + arch_mask = mcfisa_a|mcfhwdiv|mcfmac; + break; + case bfd_mach_mcf5407: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac; + break; + case bfd_mach_mcf547x: + case bfd_mach_mcf548x: + case bfd_mach_mcfv4e: + arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac; + break; + } + + FETCH_DATA (info, buffer + 2); + major_opcode = (buffer[0] >> 4) & 15; + + for (i = 0; i < numopcodes[major_opcode]; i++) + { + const struct m68k_opcode *opc = opcodes[major_opcode][i]; + unsigned long opcode = opc->opcode; + unsigned long match = opc->match; + + if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) + && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) + /* Only fetch the next two bytes if we need to. */ + && (((0xffff & match) == 0) + || + (FETCH_DATA (info, buffer + 4) + && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) + && ((0xff & buffer[3] & match) == (0xff & opcode))) + ) + && (opc->arch & arch_mask) != 0) + { + /* Don't use for printout the variants of divul and divsl + that have the same register number in two places. + The more general variants will match instead. */ + for (d = opc->args; *d; d += 2) + if (d[1] == 'D') + break; + + /* Don't use for printout the variants of most floating + point coprocessor instructions which use the same + register number in two places, as above. */ + if (*d == '\0') + for (d = opc->args; *d; d += 2) + if (d[1] == 't') + break; + + /* Don't match fmovel with more than one register; + wait for fmoveml. */ + if (*d == '\0') + { + for (d = opc->args; *d; d += 2) + { + if (d[0] == 's' && d[1] == '8') + { + val = fetch_arg (buffer, d[1], 3, info); + if ((val & (val - 1)) != 0) + break; + } + } + } + + if (*d == '\0') + if ((val = match_insn_m68k (memaddr, info, opc, & priv))) + return val; + } + } + + /* Handle undefined instructions. */ + info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]); + return 2; +} +/* **** End of m68k-dis.c */ +/* **** m68k-opc.h from sourceware.org CVS 2005-08-14. */ +/* Opcode table for m680[012346]0/m6888[12]/m68851/mcf5200. + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2003, 2004, 2005 + Free Software Foundation, Inc. + + 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 + 1, 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, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#define one(x) ((unsigned int) (x) << 16) +#define two(x, y) (((unsigned int) (x) << 16) + (y)) + +/* The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler will bomb at + runtime. */ + +const struct m68k_opcode m68k_opcodes[] = +{ +{"abcd", 2, one(0140400), one(0170770), "DsDd", m68000up }, +{"abcd", 2, one(0140410), one(0170770), "-s-d", m68000up }, + +{"addaw", 2, one(0150300), one(0170700), "*wAd", m68000up }, +{"addal", 2, one(0150700), one(0170700), "*lAd", m68000up | mcfisa_a }, + +{"addib", 4, one(0003000), one(0177700), "#b$s", m68000up }, +{"addiw", 4, one(0003100), one(0177700), "#w$s", m68000up }, +{"addil", 6, one(0003200), one(0177700), "#l$s", m68000up }, +{"addil", 6, one(0003200), one(0177700), "#lDs", mcfisa_a }, + +{"addqb", 2, one(0050000), one(0170700), "Qd$b", m68000up }, +{"addqw", 2, one(0050100), one(0170700), "Qd%w", m68000up }, +{"addql", 2, one(0050200), one(0170700), "Qd%l", m68000up | mcfisa_a }, + +/* The add opcode can generate the adda, addi, and addq instructions. */ +{"addb", 2, one(0050000), one(0170700), "Qd$b", m68000up }, +{"addb", 4, one(0003000), one(0177700), "#b$s", m68000up }, +{"addb", 2, one(0150000), one(0170700), ";bDd", m68000up }, +{"addb", 2, one(0150400), one(0170700), "Dd~b", m68000up }, +{"addw", 2, one(0050100), one(0170700), "Qd%w", m68000up }, +{"addw", 2, one(0150300), one(0170700), "*wAd", m68000up }, +{"addw", 4, one(0003100), one(0177700), "#w$s", m68000up }, +{"addw", 2, one(0150100), one(0170700), "*wDd", m68000up }, +{"addw", 2, one(0150500), one(0170700), "Dd~w", m68000up }, +{"addl", 2, one(0050200), one(0170700), "Qd%l", m68000up | mcfisa_a }, +{"addl", 6, one(0003200), one(0177700), "#l$s", m68000up }, +{"addl", 6, one(0003200), one(0177700), "#lDs", mcfisa_a }, +{"addl", 2, one(0150700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"addl", 2, one(0150200), one(0170700), "*lDd", m68000up | mcfisa_a }, +{"addl", 2, one(0150600), one(0170700), "Dd~l", m68000up | mcfisa_a }, + +{"addxb", 2, one(0150400), one(0170770), "DsDd", m68000up }, +{"addxb", 2, one(0150410), one(0170770), "-s-d", m68000up }, +{"addxw", 2, one(0150500), one(0170770), "DsDd", m68000up }, +{"addxw", 2, one(0150510), one(0170770), "-s-d", m68000up }, +{"addxl", 2, one(0150600), one(0170770), "DsDd", m68000up | mcfisa_a }, +{"addxl", 2, one(0150610), one(0170770), "-s-d", m68000up }, + +{"andib", 4, one(0001000), one(0177700), "#b$s", m68000up }, +{"andib", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andiw", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andiw", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"andil", 6, one(0001200), one(0177700), "#l$s", m68000up }, +{"andil", 6, one(0001200), one(0177700), "#lDs", mcfisa_a }, +{"andi", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andi", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andi", 4, one(0001174), one(0177777), "#wSs", m68000up }, + +/* The and opcode can generate the andi instruction. */ +{"andb", 4, one(0001000), one(0177700), "#b$s", m68000up }, +{"andb", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"andb", 2, one(0140000), one(0170700), ";bDd", m68000up }, +{"andb", 2, one(0140400), one(0170700), "Dd~b", m68000up }, +{"andw", 4, one(0001100), one(0177700), "#w$s", m68000up }, +{"andw", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"andw", 2, one(0140100), one(0170700), ";wDd", m68000up }, +{"andw", 2, one(0140500), one(0170700), "Dd~w", m68000up }, +{"andl", 6, one(0001200), one(0177700), "#l$s", m68000up }, +{"andl", 6, one(0001200), one(0177700), "#lDs", mcfisa_a }, +{"andl", 2, one(0140200), one(0170700), ";lDd", m68000up | mcfisa_a }, +{"andl", 2, one(0140600), one(0170700), "Dd~l", m68000up | mcfisa_a }, +{"and", 4, one(0001100), one(0177700), "#w$w", m68000up }, +{"and", 4, one(0001074), one(0177777), "#bCs", m68000up }, +{"and", 4, one(0001174), one(0177777), "#wSs", m68000up }, +{"and", 2, one(0140100), one(0170700), ";wDd", m68000up }, +{"and", 2, one(0140500), one(0170700), "Dd~w", m68000up }, + +{"aslb", 2, one(0160400), one(0170770), "QdDs", m68000up }, +{"aslb", 2, one(0160440), one(0170770), "DdDs", m68000up }, +{"aslw", 2, one(0160500), one(0170770), "QdDs", m68000up }, +{"aslw", 2, one(0160540), one(0170770), "DdDs", m68000up }, +{"aslw", 2, one(0160700), one(0177700), "~s", m68000up }, +{"asll", 2, one(0160600), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"asll", 2, one(0160640), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"asrb", 2, one(0160000), one(0170770), "QdDs", m68000up }, +{"asrb", 2, one(0160040), one(0170770), "DdDs", m68000up }, +{"asrw", 2, one(0160100), one(0170770), "QdDs", m68000up }, +{"asrw", 2, one(0160140), one(0170770), "DdDs", m68000up }, +{"asrw", 2, one(0160300), one(0177700), "~s", m68000up }, +{"asrl", 2, one(0160200), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"asrl", 2, one(0160240), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"bhiw", 2, one(0061000), one(0177777), "BW", m68000up | mcfisa_a }, +{"blsw", 2, one(0061400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bccw", 2, one(0062000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bcsw", 2, one(0062400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bnew", 2, one(0063000), one(0177777), "BW", m68000up | mcfisa_a }, +{"beqw", 2, one(0063400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bvcw", 2, one(0064000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bvsw", 2, one(0064400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bplw", 2, one(0065000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bmiw", 2, one(0065400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bgew", 2, one(0066000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bltw", 2, one(0066400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bgtw", 2, one(0067000), one(0177777), "BW", m68000up | mcfisa_a }, +{"blew", 2, one(0067400), one(0177777), "BW", m68000up | mcfisa_a }, + +{"bhil", 2, one(0061377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"blsl", 2, one(0061777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bccl", 2, one(0062377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bcsl", 2, one(0062777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bnel", 2, one(0063377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"beql", 2, one(0063777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bvcl", 2, one(0064377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bvsl", 2, one(0064777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bpll", 2, one(0065377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bmil", 2, one(0065777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bgel", 2, one(0066377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bltl", 2, one(0066777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bgtl", 2, one(0067377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"blel", 2, one(0067777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, + +{"bhis", 2, one(0061000), one(0177400), "BB", m68000up | mcfisa_a }, +{"blss", 2, one(0061400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bccs", 2, one(0062000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bcss", 2, one(0062400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bnes", 2, one(0063000), one(0177400), "BB", m68000up | mcfisa_a }, +{"beqs", 2, one(0063400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bvcs", 2, one(0064000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bvss", 2, one(0064400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bpls", 2, one(0065000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bmis", 2, one(0065400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bges", 2, one(0066000), one(0177400), "BB", m68000up | mcfisa_a }, +{"blts", 2, one(0066400), one(0177400), "BB", m68000up | mcfisa_a }, +{"bgts", 2, one(0067000), one(0177400), "BB", m68000up | mcfisa_a }, +{"bles", 2, one(0067400), one(0177400), "BB", m68000up | mcfisa_a }, + +{"jhi", 2, one(0061000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jls", 2, one(0061400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jcc", 2, one(0062000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jcs", 2, one(0062400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jne", 2, one(0063000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jeq", 2, one(0063400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jvc", 2, one(0064000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jvs", 2, one(0064400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jpl", 2, one(0065000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jmi", 2, one(0065400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jge", 2, one(0066000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jlt", 2, one(0066400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jgt", 2, one(0067000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jle", 2, one(0067400), one(0177400), "Bg", m68000up | mcfisa_a }, + +{"bchg", 2, one(0000500), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bchg", 4, one(0004100), one(0177700), "#b$s", m68000up }, +{"bchg", 4, one(0004100), one(0177700), "#bqs", mcfisa_a }, + +{"bclr", 2, one(0000600), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bclr", 4, one(0004200), one(0177700), "#b$s", m68000up }, +{"bclr", 4, one(0004200), one(0177700), "#bqs", mcfisa_a }, + +{"bfchg", 4, two(0165300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bfclr", 4, two(0166300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bfexts", 4, two(0165700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfextu", 4, two(0164700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfffo", 4, two(0166700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up }, +{"bfins", 4, two(0167700, 0), two(0177700, 0100000), "D1?sO2O3", m68020up }, +{"bfset", 4, two(0167300, 0), two(0177700, 0170000), "?sO2O3", m68020up }, +{"bftst", 4, two(0164300, 0), two(0177700, 0170000), "/sO2O3", m68020up }, + +{"bgnd", 2, one(0045372), one(0177777), "", cpu32 }, + +{"bitrev", 2, one(0000300), one(0177770), "Ds", mcfisa_aa}, + +{"bkpt", 2, one(0044110), one(0177770), "ts", m68010up }, + +{"braw", 2, one(0060000), one(0177777), "BW", m68000up | mcfisa_a }, +{"bral", 2, one(0060377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bras", 2, one(0060000), one(0177400), "BB", m68000up | mcfisa_a }, + +{"bset", 2, one(0000700), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"bset", 2, one(0000700), one(0170700), "Ddvs", mcfisa_a }, +{"bset", 4, one(0004300), one(0177700), "#b$s", m68000up }, +{"bset", 4, one(0004300), one(0177700), "#bqs", mcfisa_a }, + +{"bsrw", 2, one(0060400), one(0177777), "BW", m68000up | mcfisa_a }, +{"bsrl", 2, one(0060777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b}, +{"bsrs", 2, one(0060400), one(0177400), "BB", m68000up | mcfisa_a }, + +{"btst", 2, one(0000400), one(0170700), "Dd;b", m68000up | mcfisa_a }, +{"btst", 4, one(0004000), one(0177700), "#b@s", m68000up }, +{"btst", 4, one(0004000), one(0177700), "#bqs", mcfisa_a }, + +{"byterev", 2, one(0001300), one(0177770), "Ds", mcfisa_aa}, + +{"callm", 4, one(0003300), one(0177700), "#b!s", m68020 }, + +{"cas2w", 6, two(0006374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up }, +{"cas2w", 6, two(0006374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up }, +{"cas2l", 6, two(0007374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up }, +{"cas2l", 6, two(0007374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up }, + +{"casb", 4, two(0005300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, +{"casw", 4, two(0006300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, +{"casl", 4, two(0007300, 0), two(0177700, 0177070), "D3D2~s", m68020up }, + +{"chk2b", 4, two(0000300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"chk2w", 4, two(0001300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"chk2l", 4, two(0002300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 }, + +{"chkl", 2, one(0040400), one(0170700), ";lDd", m68000up }, +{"chkw", 2, one(0040600), one(0170700), ";wDd", m68000up }, + +#define SCOPE_LINE (0x1 << 3) +#define SCOPE_PAGE (0x2 << 3) +#define SCOPE_ALL (0x3 << 3) + +{"cinva", 2, one(0xf400|SCOPE_ALL), one(0xff38), "ce", m68040up }, +{"cinvl", 2, one(0xf400|SCOPE_LINE), one(0xff38), "ceas", m68040up }, +{"cinvp", 2, one(0xf400|SCOPE_PAGE), one(0xff38), "ceas", m68040up }, + +{"cpusha", 2, one(0xf420|SCOPE_ALL), one(0xff38), "ce", m68040up }, +{"cpushl", 2, one(0xf420|SCOPE_LINE), one(0xff38), "ceas", m68040up | mcfisa_a }, +{"cpushp", 2, one(0xf420|SCOPE_PAGE), one(0xff38), "ceas", m68040up }, + +#undef SCOPE_LINE +#undef SCOPE_PAGE +#undef SCOPE_ALL + +{"clrb", 2, one(0041000), one(0177700), "$s", m68000up | mcfisa_a }, +{"clrw", 2, one(0041100), one(0177700), "$s", m68000up | mcfisa_a }, +{"clrl", 2, one(0041200), one(0177700), "$s", m68000up | mcfisa_a }, + +{"cmp2b", 4, two(0000300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"cmp2w", 4, two(0001300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, +{"cmp2l", 4, two(0002300,0), two(0177700,07777), "!sR1", m68020up | cpu32 }, + +{"cmpaw", 2, one(0130300), one(0170700), "*wAd", m68000up }, +{"cmpal", 2, one(0130700), one(0170700), "*lAd", m68000up | mcfisa_a }, + +{"cmpib", 4, one(0006000), one(0177700), "#b@s", m68000up }, +{"cmpib", 4, one(0006000), one(0177700), "#bDs", mcfisa_b }, +{"cmpiw", 4, one(0006100), one(0177700), "#w@s", m68000up }, +{"cmpiw", 4, one(0006100), one(0177700), "#wDs", mcfisa_b }, +{"cmpil", 6, one(0006200), one(0177700), "#l@s", m68000up }, +{"cmpil", 6, one(0006200), one(0177700), "#lDs", mcfisa_a }, + +{"cmpmb", 2, one(0130410), one(0170770), "+s+d", m68000up }, +{"cmpmw", 2, one(0130510), one(0170770), "+s+d", m68000up }, +{"cmpml", 2, one(0130610), one(0170770), "+s+d", m68000up }, + +/* The cmp opcode can generate the cmpa, cmpm, and cmpi instructions. */ +{"cmpb", 4, one(0006000), one(0177700), "#b@s", m68000up }, +{"cmpb", 4, one(0006000), one(0177700), "#bDs", mcfisa_b }, +{"cmpb", 2, one(0130410), one(0170770), "+s+d", m68000up }, +{"cmpb", 2, one(0130000), one(0170700), ";bDd", m68000up }, +{"cmpb", 2, one(0130000), one(0170700), "*bDd", mcfisa_b }, +{"cmpw", 2, one(0130300), one(0170700), "*wAd", m68000up }, +{"cmpw", 4, one(0006100), one(0177700), "#w@s", m68000up }, +{"cmpw", 4, one(0006100), one(0177700), "#wDs", mcfisa_b }, +{"cmpw", 2, one(0130510), one(0170770), "+s+d", m68000up }, +{"cmpw", 2, one(0130100), one(0170700), "*wDd", m68000up | mcfisa_b }, +{"cmpl", 2, one(0130700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"cmpl", 6, one(0006200), one(0177700), "#l@s", m68000up }, +{"cmpl", 6, one(0006200), one(0177700), "#lDs", mcfisa_a }, +{"cmpl", 2, one(0130610), one(0170770), "+s+d", m68000up }, +{"cmpl", 2, one(0130200), one(0170700), "*lDd", m68000up | mcfisa_a }, + +{"dbcc", 2, one(0052310), one(0177770), "DsBw", m68000up }, +{"dbcs", 2, one(0052710), one(0177770), "DsBw", m68000up }, +{"dbeq", 2, one(0053710), one(0177770), "DsBw", m68000up }, +{"dbf", 2, one(0050710), one(0177770), "DsBw", m68000up }, +{"dbge", 2, one(0056310), one(0177770), "DsBw", m68000up }, +{"dbgt", 2, one(0057310), one(0177770), "DsBw", m68000up }, +{"dbhi", 2, one(0051310), one(0177770), "DsBw", m68000up }, +{"dble", 2, one(0057710), one(0177770), "DsBw", m68000up }, +{"dbls", 2, one(0051710), one(0177770), "DsBw", m68000up }, +{"dblt", 2, one(0056710), one(0177770), "DsBw", m68000up }, +{"dbmi", 2, one(0055710), one(0177770), "DsBw", m68000up }, +{"dbne", 2, one(0053310), one(0177770), "DsBw", m68000up }, +{"dbpl", 2, one(0055310), one(0177770), "DsBw", m68000up }, +{"dbt", 2, one(0050310), one(0177770), "DsBw", m68000up }, +{"dbvc", 2, one(0054310), one(0177770), "DsBw", m68000up }, +{"dbvs", 2, one(0054710), one(0177770), "DsBw", m68000up }, + +{"divsw", 2, one(0100700), one(0170700), ";wDd", m68000up | mcfhwdiv }, + +{"divsl", 4, two(0046100,0006000),two(0177700,0107770),";lD3D1", m68020up|cpu32 }, +{"divsl", 4, two(0046100,0004000),two(0177700,0107770),";lDD", m68020up|cpu32 }, +{"divsl", 4, two(0046100,0004000),two(0177700,0107770),"qsDD", mcfhwdiv }, + +{"divsll", 4, two(0046100,0004000),two(0177700,0107770),";lD3D1",m68020up|cpu32 }, +{"divsll", 4, two(0046100,0004000),two(0177700,0107770),";lDD", m68020up|cpu32 }, + +{"divuw", 2, one(0100300), one(0170700), ";wDd", m68000up | mcfhwdiv }, + +{"divul", 4, two(0046100,0002000),two(0177700,0107770),";lD3D1", m68020up|cpu32 }, +{"divul", 4, two(0046100,0000000),two(0177700,0107770),";lDD", m68020up|cpu32 }, +{"divul", 4, two(0046100,0000000),two(0177700,0107770),"qsDD", mcfhwdiv }, + +{"divull", 4, two(0046100,0000000),two(0177700,0107770),";lD3D1",m68020up|cpu32 }, +{"divull", 4, two(0046100,0000000),two(0177700,0107770),";lDD", m68020up|cpu32 }, + +{"eorib", 4, one(0005000), one(0177700), "#b$s", m68000up }, +{"eorib", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eoriw", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eoriw", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eoril", 6, one(0005200), one(0177700), "#l$s", m68000up }, +{"eoril", 6, one(0005200), one(0177700), "#lDs", mcfisa_a }, +{"eori", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eori", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eori", 4, one(0005100), one(0177700), "#w$s", m68000up }, + +/* The eor opcode can generate the eori instruction. */ +{"eorb", 4, one(0005000), one(0177700), "#b$s", m68000up }, +{"eorb", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eorb", 2, one(0130400), one(0170700), "Dd$s", m68000up }, +{"eorw", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eorw", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eorw", 2, one(0130500), one(0170700), "Dd$s", m68000up }, +{"eorl", 6, one(0005200), one(0177700), "#l$s", m68000up }, +{"eorl", 6, one(0005200), one(0177700), "#lDs", mcfisa_a }, +{"eorl", 2, one(0130600), one(0170700), "Dd$s", m68000up | mcfisa_a }, +{"eor", 4, one(0005074), one(0177777), "#bCs", m68000up }, +{"eor", 4, one(0005174), one(0177777), "#wSs", m68000up }, +{"eor", 4, one(0005100), one(0177700), "#w$s", m68000up }, +{"eor", 2, one(0130500), one(0170700), "Dd$s", m68000up }, + +{"exg", 2, one(0140500), one(0170770), "DdDs", m68000up }, +{"exg", 2, one(0140510), one(0170770), "AdAs", m68000up }, +{"exg", 2, one(0140610), one(0170770), "DdAs", m68000up }, +{"exg", 2, one(0140610), one(0170770), "AsDd", m68000up }, + +{"extw", 2, one(0044200), one(0177770), "Ds", m68000up|mcfisa_a }, +{"extl", 2, one(0044300), one(0177770), "Ds", m68000up|mcfisa_a }, +{"extbl", 2, one(0044700), one(0177770), "Ds", m68020up|cpu32|mcfisa_a }, + +{"ff1", 2, one(0002300), one(0177770), "Ds", mcfisa_aa}, + +/* float stuff starts here */ + +{"fabsb", 4, two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fabsb", 4, two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsd", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fabsd", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fabsd", 4, two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fabsd", 4, two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fabsl", 4, two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fabsl", 4, two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsp", 4, two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fabss", 4, two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", cfloat }, +{"fabss", 4, two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fabsw", 4, two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fabsw", 4, two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fabsx", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fabsx", 4, two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fabsx", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsabsb", 4, two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsabsb", 4, two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsd", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsabsd", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsabsd", 4, two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsabsd", 4, two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsabsl", 4, two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsabsl", 4, two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsp", 4, two(0xF000, 0x4C58), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsabss", 4, two(0xF000, 0x4258), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabss", 4, two(0xF000, 0x4458), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsabsw", 4, two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsabsw", 4, two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsabsx", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsabsx", 4, two(0xF000, 0x4858), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsabsx", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdabsb", 4, two(0xF000, 0x585C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsb", 4, two(0xF000, 0x585c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up}, +{"fdabsd", 4, two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdabsd", 4, two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdabsd", 4, two(0xF000, 0x545C), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdabsd", 4, two(0xF000, 0x545c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up}, +{"fdabsl", 4, two(0xF000, 0x405C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsl", 4, two(0xF000, 0x405c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up}, +{"fdabsp", 4, two(0xF000, 0x4C5c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up}, +{"fdabss", 4, two(0xF000, 0x425C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabss", 4, two(0xF000, 0x445c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up}, +{"fdabsw", 4, two(0xF000, 0x505C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdabsw", 4, two(0xF000, 0x505c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x485c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up}, +{"fdabsx", 4, two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiFt", m68040up}, + +{"facosb", 4, two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"facosd", 4, two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"facosl", 4, two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"facosp", 4, two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"facoss", 4, two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"facosw", 4, two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"facosx", 4, two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"facosx", 4, two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"facosx", 4, two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"faddb", 4, two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"faddb", 4, two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddd", 4, two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"faddl", 4, two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"faddl", 4, two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddp", 4, two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fadds", 4, two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fadds", 4, two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddw", 4, two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"faddw", 4, two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"faddx", 4, two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"faddx", 4, two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsaddb", 4, two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsaddb", 4, two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddd", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsaddd", 4, two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsaddd", 4, two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsaddl", 4, two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsaddl", 4, two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddp", 4, two(0xF000, 0x4C62), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsadds", 4, two(0xF000, 0x4462), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsadds", 4, two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddw", 4, two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsaddw", 4, two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsaddx", 4, two(0xF000, 0x0062), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsaddx", 4, two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fdaddb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddb", 4, two(0xF000, 0x5866), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdaddd", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdaddd", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddd", 4, two(0xF000, 0x5466), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdaddl", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdaddl", 4, two(0xF000, 0x4066), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdaddp", 4, two(0xF000, 0x4C66), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdadds", 4, two(0xF000, 0x4466), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdadds", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddw", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdaddw", 4, two(0xF000, 0x5066), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdaddx", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdaddx", 4, two(0xF000, 0x4866), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fasinb", 4, two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fasind", 4, two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fasinl", 4, two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fasinp", 4, two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fasins", 4, two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fasinw", 4, two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fasinx", 4, two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fasinx", 4, two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fasinx", 4, two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fatanb", 4, two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fatand", 4, two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fatanl", 4, two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fatanp", 4, two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fatans", 4, two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fatanw", 4, two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fatanx", 4, two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fatanx", 4, two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fatanx", 4, two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fatanhb", 4, two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fatanhd", 4, two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fatanhl", 4, two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fatanhp", 4, two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fatanhs", 4, two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fatanhw", 4, two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fbeq", 2, one(0xF081), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbf", 2, one(0xF080), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbge", 2, one(0xF093), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgl", 2, one(0xF096), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgle", 2, one(0xF097), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbgt", 2, one(0xF092), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fble", 2, one(0xF095), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fblt", 2, one(0xF094), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbne", 2, one(0xF08E), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnge", 2, one(0xF09C), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngl", 2, one(0xF099), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngle", 2, one(0xF098), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbngt", 2, one(0xF09D), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnle", 2, one(0xF09A), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbnlt", 2, one(0xF09B), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fboge", 2, one(0xF083), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbogl", 2, one(0xF086), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbogt", 2, one(0xF082), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbole", 2, one(0xF085), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbolt", 2, one(0xF084), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbor", 2, one(0xF087), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbseq", 2, one(0xF091), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbsf", 2, one(0xF090), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbsne", 2, one(0xF09E), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbst", 2, one(0xF09F), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbt", 2, one(0xF08F), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbueq", 2, one(0xF089), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbuge", 2, one(0xF08B), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbugt", 2, one(0xF08A), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbule", 2, one(0xF08D), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbult", 2, one(0xF08C), one(0xF1FF), "IdBW", mfloat | cfloat }, +{"fbun", 2, one(0xF088), one(0xF1FF), "IdBW", mfloat | cfloat }, + +{"fbeql", 2, one(0xF0C1), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbfl", 2, one(0xF0C0), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgel", 2, one(0xF0D3), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgll", 2, one(0xF0D6), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbglel", 2, one(0xF0D7), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbgtl", 2, one(0xF0D2), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fblel", 2, one(0xF0D5), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbltl", 2, one(0xF0D4), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnel", 2, one(0xF0CE), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngel", 2, one(0xF0DC), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngll", 2, one(0xF0D9), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnglel", 2, one(0xF0D8), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbngtl", 2, one(0xF0DD), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnlel", 2, one(0xF0DA), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbnltl", 2, one(0xF0DB), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogel", 2, one(0xF0C3), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogll", 2, one(0xF0C6), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbogtl", 2, one(0xF0C2), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbolel", 2, one(0xF0C5), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fboltl", 2, one(0xF0C4), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fborl", 2, one(0xF0C7), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbseql", 2, one(0xF0D1), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbsfl", 2, one(0xF0D0), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbsnel", 2, one(0xF0DE), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbstl", 2, one(0xF0DF), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbtl", 2, one(0xF0CF), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbueql", 2, one(0xF0C9), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbugel", 2, one(0xF0CB), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbugtl", 2, one(0xF0CA), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbulel", 2, one(0xF0CD), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbultl", 2, one(0xF0CC), one(0xF1FF), "IdBC", mfloat | cfloat }, +{"fbunl", 2, one(0xF0C8), one(0xF1FF), "IdBC", mfloat | cfloat }, + +{"fjeq", 2, one(0xF081), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjf", 2, one(0xF080), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjge", 2, one(0xF093), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgl", 2, one(0xF096), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgle", 2, one(0xF097), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjgt", 2, one(0xF092), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjle", 2, one(0xF095), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjlt", 2, one(0xF094), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjne", 2, one(0xF08E), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnge", 2, one(0xF09C), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngl", 2, one(0xF099), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngle", 2, one(0xF098), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjngt", 2, one(0xF09D), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnle", 2, one(0xF09A), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjnlt", 2, one(0xF09B), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjoge", 2, one(0xF083), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjogl", 2, one(0xF086), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjogt", 2, one(0xF082), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjole", 2, one(0xF085), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjolt", 2, one(0xF084), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjor", 2, one(0xF087), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjseq", 2, one(0xF091), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjsf", 2, one(0xF090), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjsne", 2, one(0xF09E), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjst", 2, one(0xF09F), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjt", 2, one(0xF08F), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjueq", 2, one(0xF089), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjuge", 2, one(0xF08B), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjugt", 2, one(0xF08A), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjule", 2, one(0xF08D), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjult", 2, one(0xF08C), one(0xF1BF), "IdBc", mfloat | cfloat }, +{"fjun", 2, one(0xF088), one(0xF1BF), "IdBc", mfloat | cfloat }, + +{"fcmpb", 4, two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpb", 4, two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcmpd", 4, two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcmpd", 4, two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fcmpd", 4, two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fcmpl", 4, two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcmpl", 4, two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpp", 4, two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcmps", 4, two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcmps", 4, two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpw", 4, two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcmpw", 4, two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fcmpx", 4, two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcmpx", 4, two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fcosb", 4, two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcosd", 4, two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcosl", 4, two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcosp", 4, two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcoss", 4, two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcosw", 4, two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcosx", 4, two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcosx", 4, two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fcosx", 4, two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fcoshb", 4, two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fcoshd", 4, two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fcoshl", 4, two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fcoshp", 4, two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fcoshs", 4, two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fcoshw", 4, two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fcoshx", 4, two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fdbeq", 4, two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbf", 4, two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbge", 4, two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgl", 4, two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgle", 4, two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbgt", 4, two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdble", 4, two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdblt", 4, two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbne", 4, two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnge", 4, two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngl", 4, two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngle", 4, two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbngt", 4, two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnle", 4, two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbnlt", 4, two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdboge", 4, two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbogl", 4, two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbogt", 4, two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbole", 4, two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbolt", 4, two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbor", 4, two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbseq", 4, two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbsf", 4, two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbsne", 4, two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbst", 4, two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbt", 4, two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbueq", 4, two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbuge", 4, two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbugt", 4, two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbule", 4, two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbult", 4, two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, +{"fdbun", 4, two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat }, + +{"fdivb", 4, two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fdivb", 4, two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivd", 4, two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdivd", 4, two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fdivd", 4, two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdivl", 4, two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fdivl", 4, two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivp", 4, two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fdivs", 4, two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fdivs", 4, two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivw", 4, two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fdivw", 4, two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdivx", 4, two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fdivx", 4, two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsdivb", 4, two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsdivb", 4, two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivd", 4, two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsdivd", 4, two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsdivd", 4, two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsdivl", 4, two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsdivl", 4, two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivp", 4, two(0xF000, 0x4C60), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsdivs", 4, two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsdivs", 4, two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivw", 4, two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsdivw", 4, two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsdivx", 4, two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsdivx", 4, two(0xF000, 0x4860), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fddivb", 4, two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fddivb", 4, two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivd", 4, two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fddivd", 4, two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fddivd", 4, two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fddivl", 4, two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fddivl", 4, two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivp", 4, two(0xF000, 0x4C64), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fddivs", 4, two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fddivs", 4, two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivw", 4, two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fddivw", 4, two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fddivx", 4, two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fddivx", 4, two(0xF000, 0x4864), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fetoxb", 4, two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fetoxd", 4, two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fetoxl", 4, two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fetoxp", 4, two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fetoxs", 4, two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fetoxw", 4, two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fetoxx", 4, two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fetoxm1b", 4, two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fetoxm1d", 4, two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fetoxm1l", 4, two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fetoxm1p", 4, two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fetoxm1s", 4, two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fetoxm1w", 4, two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fetoxm1x", 4, two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fgetexpb", 4, two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fgetexpd", 4, two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fgetexpl", 4, two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fgetexpp", 4, two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fgetexps", 4, two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fgetexpw", 4, two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fgetexpx", 4, two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fgetmanb", 4, two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fgetmand", 4, two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fgetmanl", 4, two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fgetmanp", 4, two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fgetmans", 4, two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fgetmanw", 4, two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fgetmanx", 4, two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fintb", 4, two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fintb", 4, two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintd", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fintd", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fintd", 4, two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fintd", 4, two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fintl", 4, two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fintl", 4, two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintp", 4, two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fints", 4, two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fints", 4, two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintw", 4, two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fintw", 4, two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintx", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fintx", 4, two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fintx", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzp", 4, two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fintrzx", 4, two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flog10b", 4, two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flog10d", 4, two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flog10l", 4, two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flog10p", 4, two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flog10s", 4, two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flog10w", 4, two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flog10x", 4, two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flog2b", 4, two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flog2d", 4, two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flog2l", 4, two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flog2p", 4, two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flog2s", 4, two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flog2w", 4, two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flog2x", 4, two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flog2x", 4, two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flog2x", 4, two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flognb", 4, two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flognd", 4, two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flognl", 4, two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flognp", 4, two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flogns", 4, two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flognw", 4, two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flognx", 4, two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flognx", 4, two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flognx", 4, two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"flognp1b", 4, two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"flognp1d", 4, two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"flognp1l", 4, two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"flognp1p", 4, two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"flognp1s", 4, two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"flognp1w", 4, two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"flognp1x", 4, two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fmodb", 4, two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmodd", 4, two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmodl", 4, two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmodp", 4, two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmods", 4, two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmodw", 4, two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmodx", 4, two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fmodx", 4, two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fmoveb", 4, two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmoveb", 4, two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat }, +{"fmoveb", 4, two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmoveb", 4, two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7$b", mfloat }, +{"fmoved", 4, two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmoved", 4, two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7~F", mfloat }, +{"fmoved", 4, two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fmoved", 4, two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fmoved", 4, two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat }, +{"fmovel", 4, two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmovel", 4, two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7$l", mfloat }, +/* FIXME: the next two variants should not permit moving an address + register to anything but the floating point instruction register. */ +{"fmovel", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmovel", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8", mfloat }, +{"fmovel", 4, two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmovel", 4, two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat }, + /* Move the FP control registers. */ +{"fmovel", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8ps", cfloat }, +{"fmovel", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Iibss8", cfloat }, +{"fmovep", 4, two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmovep", 4, two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7~pkC", mfloat }, +{"fmovep", 4, two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7~pDk", mfloat }, +{"fmoves", 4, two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmoves", 4, two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7$f", mfloat }, +{"fmoves", 4, two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmoves", 4, two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fmovew", 4, two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmovew", 4, two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7$w", mfloat }, +{"fmovew", 4, two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmovew", 4, two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fmovex", 4, two(0xF000, 0x0000), two(0xF1FF, 0xE07F), "IiF8F7", mfloat }, +{"fmovex", 4, two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fmovex", 4, two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7~x", mfloat }, + +{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmoveb", 4, two(0xF000, 0x7840), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmoved", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsmoved", 4, two(0xF000, 0x7440), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat }, +{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmovel", 4, two(0xF000, 0x6040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmoves", 4, two(0xF000, 0x6440), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmovew", 4, two(0xF000, 0x7040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fsmovex", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsmovex", 4, two(0xF000, 0x4840), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsmovep", 4, two(0xF000, 0x4C40), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, + +{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmoveb", 4, two(0xF000, 0x7844), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmoved", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdmoved", 4, two(0xF000, 0x7444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmovel", 4, two(0xF000, 0x6044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmoves", 4, two(0xF000, 0x6444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmovew", 4, two(0xF000, 0x7044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat }, +{"fdmovex", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdmovex", 4, two(0xF000, 0x4844), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdmovep", 4, two(0xF000, 0x4C44), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, + +{"fmovecrx", 4, two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat }, + +{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizsl3", cfloat }, +{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat }, +{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat }, +{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Iil3ys", cfloat }, + +{"fmovemx", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, +{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, +{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, +{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, +{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, + +{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat }, +/* FIXME: In the next instruction, we should only permit %dn if the + target is a single register. We should only permit %an if the + target is a single %fpiar. */ +{"fmoveml", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*lL8", mfloat }, + +{"fmovem", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "IizsL3", cfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "IiL3ys", cfloat }, + +{"fmovem", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat }, +{"fmovem", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat }, +{"fmovem", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat }, +{"fmovem", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat }, +{"fmovem", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat }, +{"fmovem", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat }, +{"fmovem", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat }, +{"fmovem", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat }, +{"fmovem", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat }, +{"fmovem", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat }, +{"fmovem", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat }, +{"fmovem", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat }, +{"fmovem", 4, two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat }, + +{"fmulb", 4, two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fmulb", 4, two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmuld", 4, two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fmuld", 4, two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fmuld", 4, two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fmull", 4, two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fmull", 4, two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulp", 4, two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fmuls", 4, two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fmuls", 4, two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulw", 4, two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fmulw", 4, two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fmulx", 4, two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fmulx", 4, two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"fsmulb", 4, two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsmulb", 4, two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmuld", 4, two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsmuld", 4, two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsmuld", 4, two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsmull", 4, two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsmull", 4, two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulp", 4, two(0xF000, 0x4C63), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsmuls", 4, two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsmuls", 4, two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulw", 4, two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsmulw", 4, two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsmulx", 4, two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsmulx", 4, two(0xF000, 0x4863), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fdmulb", 4, two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdmulb", 4, two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmuld", 4, two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdmuld", 4, two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdmuld", 4, two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdmull", 4, two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdmull", 4, two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulp", 4, two(0xF000, 0x4C67), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdmuls", 4, two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdmuls", 4, two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulw", 4, two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdmulw", 4, two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdmulx", 4, two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdmulx", 4, two(0xF000, 0x4867), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, + +{"fnegb", 4, two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fnegb", 4, two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegd", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fnegd", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fnegd", 4, two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fnegd", 4, two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fnegl", 4, two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fnegl", 4, two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegp", 4, two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fnegs", 4, two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fnegs", 4, two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegw", 4, two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fnegw", 4, two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fnegx", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fnegx", 4, two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fnegx", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsnegb", 4, two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fsnegb", 4, two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegd", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsnegd", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsnegd", 4, two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fsnegd", 4, two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsnegl", 4, two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fsnegl", 4, two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegp", 4, two(0xF000, 0x4C5A), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fsnegs", 4, two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fsnegs", 4, two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegw", 4, two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fsnegw", 4, two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsnegx", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fsnegx", 4, two(0xF000, 0x485A), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fsnegx", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdnegb", 4, two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdnegb", 4, two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegd", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdnegd", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdnegd", 4, two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdnegd", 4, two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdnegl", 4, two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdnegl", 4, two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegp", 4, two(0xF000, 0x4C5E), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdnegs", 4, two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdnegs", 4, two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegw", 4, two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdnegw", 4, two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdnegx", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdnegx", 4, two(0xF000, 0x485E), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdnegx", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fnop", 4, two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii", mfloat | cfloat }, + +{"fremb", 4, two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fremd", 4, two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"freml", 4, two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fremp", 4, two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"frems", 4, two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fremw", 4, two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fremx", 4, two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fremx", 4, two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +{"frestore", 2, one(0xF140), one(0xF1C0), "Ids", mfloat }, +{"fsave", 2, one(0xF100), one(0xF1C0), "Idzs", cfloat }, + +{"fscaleb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fscaled", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fscalel", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fscalep", 4, two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fscales", 4, two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fscalew", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fscalex", 4, two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fscalex", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, + +/* $ is necessary to prevent the assembler from using PC-relative. + If @ were used, "label: fseq label" could produce "ftrapeq", 2, + because "label" became "pc@label". */ +{"fseq", 4, two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsf", 4, two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsge", 4, two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgl", 4, two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgle", 4, two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsgt", 4, two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsle", 4, two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fslt", 4, two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsne", 4, two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnge", 4, two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngl", 4, two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngle", 4, two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsngt", 4, two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnle", 4, two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsnlt", 4, two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsoge", 4, two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsogl", 4, two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsogt", 4, two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsole", 4, two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsolt", 4, two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsor", 4, two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsseq", 4, two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fssf", 4, two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fssne", 4, two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsst", 4, two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fst", 4, two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsueq", 4, two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsuge", 4, two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsugt", 4, two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsule", 4, two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsult", 4, two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, +{"fsun", 4, two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s", mfloat }, + +{"fsgldivb", 4, two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsgldivd", 4, two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsgldivl", 4, two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsgldivp", 4, two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsgldivs", 4, two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsgldivw", 4, two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsgldivx", 4, two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsglmulb", 4, two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsglmuld", 4, two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsglmull", 4, two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsglmulp", 4, two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsglmuls", 4, two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsglmulw", 4, two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsglmulx", 4, two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsinb", 4, two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsind", 4, two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsinl", 4, two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsinp", 4, two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsins", 4, two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsinw", 4, two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsinx", 4, two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsinx", 4, two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsinx", 4, two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsincosb", 4, two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7", mfloat }, +{"fsincosd", 4, two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7", mfloat }, +{"fsincosl", 4, two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7", mfloat }, +{"fsincosp", 4, two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7", mfloat }, +{"fsincoss", 4, two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7", mfloat }, +{"fsincosw", 4, two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7", mfloat }, +{"fsincosx", 4, two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7", mfloat }, +{"fsincosx", 4, two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7", mfloat }, + +{"fsinhb", 4, two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsinhd", 4, two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsinhl", 4, two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsinhp", 4, two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsinhs", 4, two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsinhw", 4, two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsinhx", 4, two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fsqrtb", 4, two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsqrtb", 4, two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fsqrtd", 4, two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsqrtd", 4, two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsqrtl", 4, two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsqrtl", 4, two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtp", 4, two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsqrts", 4, two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsqrts", 4, two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtw", 4, two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsqrtw", 4, two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsqrtx", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsqrtx", 4, two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsqrtx", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtp", 4, two(0xF000, 0x4C41), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fssqrtx", 4, two(0xF000, 0x4841), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", cfloat }, +{"fdsqrtd", 4, two(0xF000, 0x5445), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtp", 4, two(0xF000, 0x4C45), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdsqrtx", 4, two(0xF000, 0x4845), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fsubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"fsubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubd", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fsubd", 4, two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"fsubd", 4, two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fsubl", 4, two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"fsubl", 4, two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubp", 4, two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"fsubs", 4, two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"fsubs", 4, two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubw", 4, two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"fsubw", 4, two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fsubx", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"fsubx", 4, two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"fsubx", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"fssubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubb", 4, two(0xF000, 0x5868), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fssubd", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fssubd", 4, two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fssubd", 4, two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fssubl", 4, two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fssubl", 4, two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubp", 4, two(0xF000, 0x4C68), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fssubs", 4, two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fssubs", 4, two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubw", 4, two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fssubw", 4, two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fssubx", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fssubx", 4, two(0xF000, 0x4868), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fssubx", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"fdsubb", 4, two(0xF000, 0x586A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubb", 4, two(0xF000, 0x586c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up }, +{"fdsubd", 4, two(0xF000, 0x006A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat }, +{"fdsubd", 4, two(0xF000, 0x546A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat }, +{"fdsubd", 4, two(0xF000, 0x546c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up }, +{"fdsubl", 4, two(0xF000, 0x406A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubl", 4, two(0xF000, 0x406c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up }, +{"fdsubp", 4, two(0xF000, 0x4C6c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up }, +{"fdsubs", 4, two(0xF000, 0x446A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubs", 4, two(0xF000, 0x446c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up }, +{"fdsubw", 4, two(0xF000, 0x506A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat }, +{"fdsubw", 4, two(0xF000, 0x506c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x486c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up }, +{"fdsubx", 4, two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiFt", m68040up }, + +{"ftanb", 4, two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftand", 4, two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftanl", 4, two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftanp", 4, two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftans", 4, two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftanw", 4, two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftanx", 4, two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftanx", 4, two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftanx", 4, two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftanhb", 4, two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftanhd", 4, two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftanhl", 4, two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftanhp", 4, two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftanhs", 4, two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftanhw", 4, two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftanhx", 4, two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftentoxb", 4, two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftentoxd", 4, two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftentoxl", 4, two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftentoxp", 4, two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftentoxs", 4, two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftentoxw", 4, two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftentoxx", 4, two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"ftrapeq", 4, two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapf", 4, two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapge", 4, two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgl", 4, two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgle", 4, two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapgt", 4, two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftraple", 4, two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftraplt", 4, two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapne", 4, two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnge", 4, two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngl", 4, two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngle", 4,two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapngt", 4, two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnle", 4, two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapnlt", 4, two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapoge", 4, two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapogl", 4, two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapogt", 4, two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapole", 4, two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapolt", 4, two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapor", 4, two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapseq", 4, two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapsf", 4, two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapsne", 4, two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapst", 4, two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapt", 4, two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapueq", 4, two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapuge", 4, two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapugt", 4, two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapule", 4, two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapult", 4, two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii", mfloat }, +{"ftrapun", 4, two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii", mfloat }, + +{"ftrapeqw", 4, two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapfw", 4, two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapgew", 4, two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapglw", 4, two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapglew", 4,two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapgtw", 4, two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraplew", 4, two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapltw", 4, two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnew", 4, two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapngew", 4,two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnglw", 4,two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnglew", 4,two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapngtw", 4,two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnlew", 4,two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapnltw", 4,two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapogew", 4,two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapoglw", 4,two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapogtw", 4,two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapolew", 4,two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapoltw", 4,two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraporw", 4, two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapseqw", 4,two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapsfw", 4, two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapsnew", 4,two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapstw", 4, two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftraptw", 4, two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapueqw", 4,two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapugew", 4,two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapugtw", 4,two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapulew", 4,two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapultw", 4,two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, +{"ftrapunw", 4, two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w", mfloat }, + +{"ftrapeql", 4, two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapfl", 4, two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgel", 4, two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgll", 4, two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapglel", 4,two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapgtl", 4, two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraplel", 4, two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapltl", 4, two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnel", 4, two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngel", 4,two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngll", 4,two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnglel", 4,two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapngtl", 4,two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnlel", 4,two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapnltl", 4,two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogel", 4,two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogll", 4,two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapogtl", 4,two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapolel", 4,two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapoltl", 4,two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraporl", 4, two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapseql", 4,two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapsfl", 4, two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapsnel", 4,two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapstl", 4, two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftraptl", 4, two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapueql", 4,two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapugel", 4,two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapugtl", 4,two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapulel", 4,two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapultl", 4,two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, +{"ftrapunl", 4, two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l", mfloat }, + +{"ftstb", 4, two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b", mfloat }, +{"ftstb", 4, two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstd", 4, two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", cfloat }, +{"ftstd", 4, two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F", mfloat }, +{"ftstd", 4, two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstl", 4, two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l", mfloat }, +{"ftstl", 4, two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstp", 4, two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p", mfloat }, +{"ftsts", 4, two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f", mfloat }, +{"ftsts", 4, two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstw", 4, two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w", mfloat }, +{"ftstw", 4, two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Iibs", cfloat }, +{"ftstx", 4, two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", mfloat }, +{"ftstx", 4, two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x", mfloat }, + +{"ftwotoxb", 4, two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat }, +{"ftwotoxd", 4, two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat }, +{"ftwotoxl", 4, two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat }, +{"ftwotoxp", 4, two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat }, +{"ftwotoxs", 4, two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat }, +{"ftwotoxw", 4, two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat }, +{"ftwotoxx", 4, two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt", mfloat }, + +{"halt", 2, one(0045310), one(0177777), "", m68060 | mcfisa_a }, + +{"illegal", 2, one(0045374), one(0177777), "", m68000up | mcfisa_a }, +{"intouch", 2, one(0xf428), one(0xfff8), "As", mcfisa_b }, + +{"jmp", 2, one(0047300), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jra", 2, one(0060000), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jra", 2, one(0047300), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jsr", 2, one(0047200), one(0177700), "!s", m68000up | mcfisa_a }, + +{"jbsr", 2, one(0060400), one(0177400), "Bg", m68000up | mcfisa_a }, +{"jbsr", 2, one(0047200), one(0177700), "!s", m68000up | mcfisa_a }, + +{"lea", 2, one(0040700), one(0170700), "!sAd", m68000up | mcfisa_a }, + +{"lpstop", 6, two(0174000,0000700),two(0177777,0177777),"#w", cpu32|m68060 }, + +{"linkw", 4, one(0047120), one(0177770), "As#w", m68000up | mcfisa_a }, +{"linkl", 6, one(0044010), one(0177770), "As#l", m68020up | cpu32 }, +{"link", 4, one(0047120), one(0177770), "As#W", m68000up | mcfisa_a }, +{"link", 6, one(0044010), one(0177770), "As#l", m68020up | cpu32 }, + +{"lslb", 2, one(0160410), one(0170770), "QdDs", m68000up }, +{"lslb", 2, one(0160450), one(0170770), "DdDs", m68000up }, +{"lslw", 2, one(0160510), one(0170770), "QdDs", m68000up }, +{"lslw", 2, one(0160550), one(0170770), "DdDs", m68000up }, +{"lslw", 2, one(0161700), one(0177700), "~s", m68000up }, +{"lsll", 2, one(0160610), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"lsll", 2, one(0160650), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"lsrb", 2, one(0160010), one(0170770), "QdDs", m68000up }, +{"lsrb", 2, one(0160050), one(0170770), "DdDs", m68000up }, +{"lsrw", 2, one(0160110), one(0170770), "QdDs", m68000up }, +{"lsrw", 2, one(0160150), one(0170770), "DdDs", m68000up }, +{"lsrw", 2, one(0161300), one(0177700), "~s", m68000up }, +{"lsrl", 2, one(0160210), one(0170770), "QdDs", m68000up | mcfisa_a }, +{"lsrl", 2, one(0160250), one(0170770), "DdDs", m68000up | mcfisa_a }, + +{"macw", 4, two(0xa080, 0x0000), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac }, +{"macw", 4, two(0xa080, 0x0200), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac }, +{"macw", 4, two(0xa080, 0x0000), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac }, +{"macw", 4, two(0xa000, 0x0000), two(0xf1b0, 0x0900), "uMumiI", mcfmac }, +{"macw", 4, two(0xa000, 0x0200), two(0xf1b0, 0x0900), "uMumMh", mcfmac }, +{"macw", 4, two(0xa000, 0x0000), two(0xf1b0, 0x0f00), "uMum", mcfmac }, + +{"macw", 4, two(0xa000, 0x0000), two(0xf100, 0x0900), "uNuoiI4/RneG", mcfemac },/* Ry,Rx,SF,,accX. */ +{"macw", 4, two(0xa000, 0x0200), two(0xf100, 0x0900), "uNuoMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf100, 0x0f00), "uNuo4/RneG", mcfemac },/* Ry,Rx,,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX. */ +{"macw", 4, two(0xa000, 0x0200), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX. */ +{"macw", 4, two(0xa000, 0x0000), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX. */ + +{"macl", 4, two(0xa080, 0x0800), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac }, +{"macl", 4, two(0xa080, 0x0a00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac }, +{"macl", 4, two(0xa080, 0x0800), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf1b0, 0x0800), "RMRm", mcfmac }, + +{"macl", 4, two(0xa000, 0x0800), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf130, 0x0900), "RMRmiIeH", mcfemac }, +{"macl", 4, two(0xa000, 0x0a00), two(0xf130, 0x0900), "RMRmMheH", mcfemac }, +{"macl", 4, two(0xa000, 0x0800), two(0xf130, 0x0f00), "RMRmeH", mcfemac }, + +/* NOTE: The mcf5200 family programmer's reference manual does not + indicate the byte form of the movea instruction is invalid (as it + is on 68000 family cpus). However, experiments on the 5202 yeild + unexpected results. The value is copied, but it is not sign extended + (as is done with movea.w) and the top three bytes in the address + register are not disturbed. I don't know if this is the intended + behavior --- it could be a hole in instruction decoding (Motorola + decided not to trap all invalid instructions for performance reasons) + --- but I suspect that it is not. + + I reported this to Motorola ISD Technical Communications Support, + which replied that other coldfire assemblers reject movea.b. For + this reason I've decided to not allow moveab. + + jtc@cygnus.com - 97/01/24. */ + +{"moveal", 2, one(0020100), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"moveaw", 2, one(0030100), one(0170700), "*wAd", m68000up | mcfisa_a }, + +{"movclrl", 2, one(0xA1C0), one(0xf9f0), "eFRs", mcfemac }, + +{"movec", 4, one(0047173), one(0177777), "R1Jj", m68010up | mcfisa_a }, +{"movec", 4, one(0047173), one(0177777), "R1#j", m68010up | mcfisa_a }, +{"movec", 4, one(0047172), one(0177777), "JjR1", m68010up }, +{"movec", 4, one(0047172), one(0177777), "#jR1", m68010up }, + +{"movemw", 4, one(0044200), one(0177700), "Lw&s", m68000up }, +{"movemw", 4, one(0044240), one(0177770), "lw-s", m68000up }, +{"movemw", 4, one(0044200), one(0177700), "#w>s", m68000up }, +{"movemw", 4, one(0046200), one(0177700), "s", m68000up }, +{"moveml", 4, one(0046300), one(0177700), ",accX. */ +{"msacw", 4, two(0xa000, 0x0300), two(0xf100, 0x0900), "uMumMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf100, 0x0f00), "uMum4/RneG", mcfemac },/* Ry,Rx,,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX. */ +{"msacw", 4, two(0xa000, 0x0300), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX. */ +{"msacw", 4, two(0xa000, 0x0100), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX. */ + +{"msacl", 4, two(0xa080, 0x0900), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac }, +{"msacl", 4, two(0xa080, 0x0b00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac }, +{"msacl", 4, two(0xa080, 0x0900), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf1b0, 0x0800), "RMRm", mcfmac }, + +{"msacl", 4, two(0xa000, 0x0900), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf130, 0x0900), "RMRmiIeH", mcfemac }, +{"msacl", 4, two(0xa000, 0x0b00), two(0xf130, 0x0900), "RMRmMheH", mcfemac }, +{"msacl", 4, two(0xa000, 0x0900), two(0xf130, 0x0f00), "RMRmeH", mcfemac }, + +{"mulsw", 2, one(0140700), one(0170700), ";wDd", m68000up|mcfisa_a }, +{"mulsl", 4, two(0046000,004000), two(0177700,0107770), ";lD1", m68020up|cpu32 }, +{"mulsl", 4, two(0046000,004000), two(0177700,0107770), "qsD1", mcfisa_a }, +{"mulsl", 4, two(0046000,006000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 }, + +{"muluw", 2, one(0140300), one(0170700), ";wDd", m68000up|mcfisa_a }, +{"mulul", 4, two(0046000,000000), two(0177700,0107770), ";lD1", m68020up|cpu32 }, +{"mulul", 4, two(0046000,000000), two(0177700,0107770), "qsD1", mcfisa_a }, +{"mulul", 4, two(0046000,002000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 }, + +{"nbcd", 2, one(0044000), one(0177700), "$s", m68000up }, + +{"negb", 2, one(0042000), one(0177700), "$s", m68000up }, +{"negw", 2, one(0042100), one(0177700), "$s", m68000up }, +{"negl", 2, one(0042200), one(0177700), "$s", m68000up }, +{"negl", 2, one(0042200), one(0177700), "Ds", mcfisa_a}, + +{"negxb", 2, one(0040000), one(0177700), "$s", m68000up }, +{"negxw", 2, one(0040100), one(0177700), "$s", m68000up }, +{"negxl", 2, one(0040200), one(0177700), "$s", m68000up }, +{"negxl", 2, one(0040200), one(0177700), "Ds", mcfisa_a}, + +{"nop", 2, one(0047161), one(0177777), "", m68000up | mcfisa_a}, + +{"notb", 2, one(0043000), one(0177700), "$s", m68000up }, +{"notw", 2, one(0043100), one(0177700), "$s", m68000up }, +{"notl", 2, one(0043200), one(0177700), "$s", m68000up }, +{"notl", 2, one(0043200), one(0177700), "Ds", mcfisa_a}, + +{"orib", 4, one(0000000), one(0177700), "#b$s", m68000up }, +{"orib", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"oriw", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"oriw", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"oril", 6, one(0000200), one(0177700), "#l$s", m68000up }, +{"oril", 6, one(0000200), one(0177700), "#lDs", mcfisa_a }, +{"ori", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"ori", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"ori", 4, one(0000174), one(0177777), "#wSs", m68000up }, + +/* The or opcode can generate the ori instruction. */ +{"orb", 4, one(0000000), one(0177700), "#b$s", m68000up }, +{"orb", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"orb", 2, one(0100000), one(0170700), ";bDd", m68000up }, +{"orb", 2, one(0100400), one(0170700), "Dd~s", m68000up }, +{"orw", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"orw", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"orw", 2, one(0100100), one(0170700), ";wDd", m68000up }, +{"orw", 2, one(0100500), one(0170700), "Dd~s", m68000up }, +{"orl", 6, one(0000200), one(0177700), "#l$s", m68000up }, +{"orl", 6, one(0000200), one(0177700), "#lDs", mcfisa_a }, +{"orl", 2, one(0100200), one(0170700), ";lDd", m68000up | mcfisa_a }, +{"orl", 2, one(0100600), one(0170700), "Dd~s", m68000up | mcfisa_a }, +{"or", 4, one(0000074), one(0177777), "#bCs", m68000up }, +{"or", 4, one(0000100), one(0177700), "#w$s", m68000up }, +{"or", 4, one(0000174), one(0177777), "#wSs", m68000up }, +{"or", 2, one(0100100), one(0170700), ";wDd", m68000up }, +{"or", 2, one(0100500), one(0170700), "Dd~s", m68000up }, + +{"pack", 4, one(0100500), one(0170770), "DsDd#w", m68020up }, +{"pack", 4, one(0100510), one(0170770), "-s-d#w", m68020up }, + +{"pbac", 2, one(0xf087), one(0xffbf), "Bc", m68851 }, +{"pbacw", 2, one(0xf087), one(0xffff), "BW", m68851 }, +{"pbas", 2, one(0xf086), one(0xffbf), "Bc", m68851 }, +{"pbasw", 2, one(0xf086), one(0xffff), "BW", m68851 }, +{"pbbc", 2, one(0xf081), one(0xffbf), "Bc", m68851 }, +{"pbbcw", 2, one(0xf081), one(0xffff), "BW", m68851 }, +{"pbbs", 2, one(0xf080), one(0xffbf), "Bc", m68851 }, +{"pbbsw", 2, one(0xf080), one(0xffff), "BW", m68851 }, +{"pbcc", 2, one(0xf08f), one(0xffbf), "Bc", m68851 }, +{"pbccw", 2, one(0xf08f), one(0xffff), "BW", m68851 }, +{"pbcs", 2, one(0xf08e), one(0xffbf), "Bc", m68851 }, +{"pbcsw", 2, one(0xf08e), one(0xffff), "BW", m68851 }, +{"pbgc", 2, one(0xf08d), one(0xffbf), "Bc", m68851 }, +{"pbgcw", 2, one(0xf08d), one(0xffff), "BW", m68851 }, +{"pbgs", 2, one(0xf08c), one(0xffbf), "Bc", m68851 }, +{"pbgsw", 2, one(0xf08c), one(0xffff), "BW", m68851 }, +{"pbic", 2, one(0xf08b), one(0xffbf), "Bc", m68851 }, +{"pbicw", 2, one(0xf08b), one(0xffff), "BW", m68851 }, +{"pbis", 2, one(0xf08a), one(0xffbf), "Bc", m68851 }, +{"pbisw", 2, one(0xf08a), one(0xffff), "BW", m68851 }, +{"pblc", 2, one(0xf083), one(0xffbf), "Bc", m68851 }, +{"pblcw", 2, one(0xf083), one(0xffff), "BW", m68851 }, +{"pbls", 2, one(0xf082), one(0xffbf), "Bc", m68851 }, +{"pblsw", 2, one(0xf082), one(0xffff), "BW", m68851 }, +{"pbsc", 2, one(0xf085), one(0xffbf), "Bc", m68851 }, +{"pbscw", 2, one(0xf085), one(0xffff), "BW", m68851 }, +{"pbss", 2, one(0xf084), one(0xffbf), "Bc", m68851 }, +{"pbssw", 2, one(0xf084), one(0xffff), "BW", m68851 }, +{"pbwc", 2, one(0xf089), one(0xffbf), "Bc", m68851 }, +{"pbwcw", 2, one(0xf089), one(0xffff), "BW", m68851 }, +{"pbws", 2, one(0xf088), one(0xffbf), "Bc", m68851 }, +{"pbwsw", 2, one(0xf088), one(0xffff), "BW", m68851 }, + +{"pdbac", 4, two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbas", 4, two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbbc", 4, two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbbs", 4, two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbcc", 4, two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbcs", 4, two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbgc", 4, two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbgs", 4, two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbic", 4, two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbis", 4, two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdblc", 4, two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbls", 4, two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbsc", 4, two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbss", 4, two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbwc", 4, two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw", m68851 }, +{"pdbws", 4, two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw", m68851 }, + +{"pea", 2, one(0044100), one(0177700), "!s", m68000up|mcfisa_a }, + +{"pflusha", 2, one(0xf518), one(0xfff8), "", m68040up }, +{"pflusha", 4, two(0xf000,0x2400), two(0xffff,0xffff), "", m68030 | m68851 }, + +{"pflush", 4, two(0xf000,0x3010), two(0xffc0,0xfe10), "T3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3810), two(0xffc0,0xfe10), "T3T9&s", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3008), two(0xffc0,0xfe18), "D3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3808), two(0xffc0,0xfe18), "D3T9&s", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3000), two(0xffc0,0xfe1e), "f3T9", m68030|m68851 }, +{"pflush", 4, two(0xf000,0x3800), two(0xffc0,0xfe1e), "f3T9&s", m68030|m68851 }, +{"pflush", 2, one(0xf508), one(0xfff8), "as", m68040up }, +{"pflush", 2, one(0xf508), one(0xfff8), "As", m68040up }, + +{"pflushan", 2, one(0xf510), one(0xfff8), "", m68040up }, +{"pflushn", 2, one(0xf500), one(0xfff8), "as", m68040up }, +{"pflushn", 2, one(0xf500), one(0xfff8), "As", m68040up }, + +{"pflushr", 4, two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s", m68851 }, + +{"pflushs", 4, two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c10), two(0xfff8, 0xfe10), "T3T9&s", m68851 }, +{"pflushs", 4, two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s", m68851 }, +{"pflushs", 4, two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9", m68851 }, +{"pflushs", 4, two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s", m68851 }, + +{"ploadr", 4, two(0xf000,0x2210), two(0xffc0,0xfff0), "T3&s", m68030|m68851 }, +{"ploadr", 4, two(0xf000,0x2208), two(0xffc0,0xfff8), "D3&s", m68030|m68851 }, +{"ploadr", 4, two(0xf000,0x2200), two(0xffc0,0xfffe), "f3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2010), two(0xffc0,0xfff0), "T3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2008), two(0xffc0,0xfff8), "D3&s", m68030|m68851 }, +{"ploadw", 4, two(0xf000,0x2000), two(0xffc0,0xfffe), "f3&s", m68030|m68851 }, + +{"plpar", 2, one(0xf5c8), one(0xfff8), "as", m68060 }, +{"plpaw", 2, one(0xf588), one(0xfff8), "as", m68060 }, + +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xffff), "*l08", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x5c00), two(0xffc0,0xffff), "*w18", m68851 }, +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xe3ff), "*b28", m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xffff), "08%s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x5e00), two(0xffc0,0xffff), "18%s", m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xe3ff), "28%s", m68851 }, +{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xe3ff), "|sW8", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xe3ff), "W8~s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6200), two(0xffc0,0xe3e3), "*wX3", m68851 }, +{"pmove", 4, two(0xf000,0x6000), two(0xffc0,0xe3e3), "X3%s", m68851 }, +{"pmove", 4, two(0xf000,0x6000), two(0xffc0,0xffff), "*wY8", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6200), two(0xffc0,0xffff), "Y8%s", m68030|m68851 }, +{"pmove", 4, two(0xf000,0x6600), two(0xffc0,0xffff), "Z8%s", m68851 }, +{"pmove", 4, two(0xf000,0x0800), two(0xffc0,0xfbff), "*l38", m68030 }, +{"pmove", 4, two(0xf000,0x0a00), two(0xffc0,0xfbff), "38%s", m68030 }, + +{"pmovefd", 4, two(0xf000, 0x4100), two(0xffc0, 0xe3ff), "*l08", m68030 }, +{"pmovefd", 4, two(0xf000, 0x4100), two(0xffc0, 0xe3ff), "|sW8", m68030 }, +{"pmovefd", 4, two(0xf000, 0x0900), two(0xffc0, 0xfbff), "*l38", m68030 }, + +{"prestore", 2, one(0xf140), one(0xffc0), "s", m68851 }, + +{"psac", 4, two(0xf040, 0x0007), two(0xffc0, 0xffff), "$s", m68851 }, +{"psas", 4, two(0xf040, 0x0006), two(0xffc0, 0xffff), "$s", m68851 }, +{"psbc", 4, two(0xf040, 0x0001), two(0xffc0, 0xffff), "$s", m68851 }, +{"psbs", 4, two(0xf040, 0x0000), two(0xffc0, 0xffff), "$s", m68851 }, +{"pscc", 4, two(0xf040, 0x000f), two(0xffc0, 0xffff), "$s", m68851 }, +{"pscs", 4, two(0xf040, 0x000e), two(0xffc0, 0xffff), "$s", m68851 }, +{"psgc", 4, two(0xf040, 0x000d), two(0xffc0, 0xffff), "$s", m68851 }, +{"psgs", 4, two(0xf040, 0x000c), two(0xffc0, 0xffff), "$s", m68851 }, +{"psic", 4, two(0xf040, 0x000b), two(0xffc0, 0xffff), "$s", m68851 }, +{"psis", 4, two(0xf040, 0x000a), two(0xffc0, 0xffff), "$s", m68851 }, +{"pslc", 4, two(0xf040, 0x0003), two(0xffc0, 0xffff), "$s", m68851 }, +{"psls", 4, two(0xf040, 0x0002), two(0xffc0, 0xffff), "$s", m68851 }, +{"pssc", 4, two(0xf040, 0x0005), two(0xffc0, 0xffff), "$s", m68851 }, +{"psss", 4, two(0xf040, 0x0004), two(0xffc0, 0xffff), "$s", m68851 }, +{"pswc", 4, two(0xf040, 0x0009), two(0xffc0, 0xffff), "$s", m68851 }, +{"psws", 4, two(0xf040, 0x0008), two(0xffc0, 0xffff), "$s", m68851 }, + +{"ptestr", 4, two(0xf000,0x8210), two(0xffc0, 0xe3f0), "T3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8310), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8208), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8308), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8200), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 }, +{"ptestr", 4, two(0xf000,0x8300), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 }, +{"ptestr", 2, one(0xf568), one(0xfff8), "as", m68040 }, + +{"ptestw", 4, two(0xf000,0x8010), two(0xffc0,0xe3f0), "T3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8110), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8008), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8108), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8000), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 }, +{"ptestw", 4, two(0xf000,0x8100), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 }, +{"ptestw", 2, one(0xf548), one(0xfff8), "as", m68040 }, + +{"ptrapacw", 6, two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapacl", 6, two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapac", 4, two(0xf07c, 0x0007), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapasw", 6, two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapasl", 6, two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapas", 4, two(0xf07c, 0x0006), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapbcw", 6, two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapbcl", 6, two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapbc", 4, two(0xf07c, 0x0001), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapbsw", 6, two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapbsl", 6, two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapbs", 4, two(0xf07c, 0x0000), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapccw", 6, two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapccl", 6, two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapcc", 4, two(0xf07c, 0x000f), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapcsw", 6, two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapcsl", 6, two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapcs", 4, two(0xf07c, 0x000e), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapgcw", 6, two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapgcl", 6, two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapgc", 4, two(0xf07c, 0x000d), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapgsw", 6, two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapgsl", 6, two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapgs", 4, two(0xf07c, 0x000c), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapicw", 6, two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapicl", 6, two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapic", 4, two(0xf07c, 0x000b), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapisw", 6, two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapisl", 6, two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapis", 4, two(0xf07c, 0x000a), two(0xffff, 0xffff), "", m68851 }, + +{"ptraplcw", 6, two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w", m68851 }, +{"ptraplcl", 6, two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l", m68851 }, +{"ptraplc", 4, two(0xf07c, 0x0003), two(0xffff, 0xffff), "", m68851 }, + +{"ptraplsw", 6, two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w", m68851 }, +{"ptraplsl", 6, two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapls", 4, two(0xf07c, 0x0002), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapscw", 6, two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapscl", 6, two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapsc", 4, two(0xf07c, 0x0005), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapssw", 6, two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapssl", 6, two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapss", 4, two(0xf07c, 0x0004), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapwcw", 6, two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapwcl", 6, two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapwc", 4, two(0xf07c, 0x0009), two(0xffff, 0xffff), "", m68851 }, + +{"ptrapwsw", 6, two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w", m68851 }, +{"ptrapwsl", 6, two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l", m68851 }, +{"ptrapws", 4, two(0xf07c, 0x0008), two(0xffff, 0xffff), "", m68851 }, + +{"pulse", 2, one(0045314), one(0177777), "", m68060 | mcfisa_a }, + +{"pvalid", 4, two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s", m68851 }, +{"pvalid", 4, two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s", m68851 }, + + /* FIXME: don't allow Dw==Dx. */ +{"remsl", 4, two(0x4c40, 0x0800), two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv }, +{"remul", 4, two(0x4c40, 0x0000), two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv }, + +{"reset", 2, one(0047160), one(0177777), "", m68000up }, + +{"rolb", 2, one(0160430), one(0170770), "QdDs", m68000up }, +{"rolb", 2, one(0160470), one(0170770), "DdDs", m68000up }, +{"rolw", 2, one(0160530), one(0170770), "QdDs", m68000up }, +{"rolw", 2, one(0160570), one(0170770), "DdDs", m68000up }, +{"rolw", 2, one(0163700), one(0177700), "~s", m68000up }, +{"roll", 2, one(0160630), one(0170770), "QdDs", m68000up }, +{"roll", 2, one(0160670), one(0170770), "DdDs", m68000up }, + +{"rorb", 2, one(0160030), one(0170770), "QdDs", m68000up }, +{"rorb", 2, one(0160070), one(0170770), "DdDs", m68000up }, +{"rorw", 2, one(0160130), one(0170770), "QdDs", m68000up }, +{"rorw", 2, one(0160170), one(0170770), "DdDs", m68000up }, +{"rorw", 2, one(0163300), one(0177700), "~s", m68000up }, +{"rorl", 2, one(0160230), one(0170770), "QdDs", m68000up }, +{"rorl", 2, one(0160270), one(0170770), "DdDs", m68000up }, + +{"roxlb", 2, one(0160420), one(0170770), "QdDs", m68000up }, +{"roxlb", 2, one(0160460), one(0170770), "DdDs", m68000up }, +{"roxlw", 2, one(0160520), one(0170770), "QdDs", m68000up }, +{"roxlw", 2, one(0160560), one(0170770), "DdDs", m68000up }, +{"roxlw", 2, one(0162700), one(0177700), "~s", m68000up }, +{"roxll", 2, one(0160620), one(0170770), "QdDs", m68000up }, +{"roxll", 2, one(0160660), one(0170770), "DdDs", m68000up }, + +{"roxrb", 2, one(0160020), one(0170770), "QdDs", m68000up }, +{"roxrb", 2, one(0160060), one(0170770), "DdDs", m68000up }, +{"roxrw", 2, one(0160120), one(0170770), "QdDs", m68000up }, +{"roxrw", 2, one(0160160), one(0170770), "DdDs", m68000up }, +{"roxrw", 2, one(0162300), one(0177700), "~s", m68000up }, +{"roxrl", 2, one(0160220), one(0170770), "QdDs", m68000up }, +{"roxrl", 2, one(0160260), one(0170770), "DdDs", m68000up }, + +{"rtd", 4, one(0047164), one(0177777), "#w", m68010up }, + +{"rte", 2, one(0047163), one(0177777), "", m68000up | mcfisa_a }, + +{"rtm", 2, one(0003300), one(0177760), "Rs", m68020 }, + +{"rtr", 2, one(0047167), one(0177777), "", m68000up }, + +{"rts", 2, one(0047165), one(0177777), "", m68000up | mcfisa_a }, + +{"satsl", 2, one(0046200), one(0177770), "Ds", mcfisa_b }, + +{"sbcd", 2, one(0100400), one(0170770), "DsDd", m68000up }, +{"sbcd", 2, one(0100410), one(0170770), "-s-d", m68000up }, + +{"scc", 2, one(0052300), one(0177700), "$s", m68000up }, +{"scc", 2, one(0052300), one(0177700), "Ds", mcfisa_a }, +{"scs", 2, one(0052700), one(0177700), "$s", m68000up }, +{"scs", 2, one(0052700), one(0177700), "Ds", mcfisa_a }, +{"seq", 2, one(0053700), one(0177700), "$s", m68000up }, +{"seq", 2, one(0053700), one(0177700), "Ds", mcfisa_a }, +{"sf", 2, one(0050700), one(0177700), "$s", m68000up }, +{"sf", 2, one(0050700), one(0177700), "Ds", mcfisa_a }, +{"sge", 2, one(0056300), one(0177700), "$s", m68000up }, +{"sge", 2, one(0056300), one(0177700), "Ds", mcfisa_a }, +{"sgt", 2, one(0057300), one(0177700), "$s", m68000up }, +{"sgt", 2, one(0057300), one(0177700), "Ds", mcfisa_a }, +{"shi", 2, one(0051300), one(0177700), "$s", m68000up }, +{"shi", 2, one(0051300), one(0177700), "Ds", mcfisa_a }, +{"sle", 2, one(0057700), one(0177700), "$s", m68000up }, +{"sle", 2, one(0057700), one(0177700), "Ds", mcfisa_a }, +{"sls", 2, one(0051700), one(0177700), "$s", m68000up }, +{"sls", 2, one(0051700), one(0177700), "Ds", mcfisa_a }, +{"slt", 2, one(0056700), one(0177700), "$s", m68000up }, +{"slt", 2, one(0056700), one(0177700), "Ds", mcfisa_a }, +{"smi", 2, one(0055700), one(0177700), "$s", m68000up }, +{"smi", 2, one(0055700), one(0177700), "Ds", mcfisa_a }, +{"sne", 2, one(0053300), one(0177700), "$s", m68000up }, +{"sne", 2, one(0053300), one(0177700), "Ds", mcfisa_a }, +{"spl", 2, one(0055300), one(0177700), "$s", m68000up }, +{"spl", 2, one(0055300), one(0177700), "Ds", mcfisa_a }, +{"st", 2, one(0050300), one(0177700), "$s", m68000up }, +{"st", 2, one(0050300), one(0177700), "Ds", mcfisa_a }, +{"svc", 2, one(0054300), one(0177700), "$s", m68000up }, +{"svc", 2, one(0054300), one(0177700), "Ds", mcfisa_a }, +{"svs", 2, one(0054700), one(0177700), "$s", m68000up }, +{"svs", 2, one(0054700), one(0177700), "Ds", mcfisa_a }, + +{"stop", 4, one(0047162), one(0177777), "#w", m68000up | mcfisa_a }, + +{"strldsr", 4, two(0040347,0043374), two(0177777,0177777), "#w", mcfisa_aa}, + +{"subal", 2, one(0110700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"subaw", 2, one(0110300), one(0170700), "*wAd", m68000up }, + +{"subib", 4, one(0002000), one(0177700), "#b$s", m68000up }, +{"subiw", 4, one(0002100), one(0177700), "#w$s", m68000up }, +{"subil", 6, one(0002200), one(0177700), "#l$s", m68000up }, +{"subil", 6, one(0002200), one(0177700), "#lDs", mcfisa_a }, + +{"subqb", 2, one(0050400), one(0170700), "Qd%s", m68000up }, +{"subqw", 2, one(0050500), one(0170700), "Qd%s", m68000up }, +{"subql", 2, one(0050600), one(0170700), "Qd%s", m68000up | mcfisa_a }, + +/* The sub opcode can generate the suba, subi, and subq instructions. */ +{"subb", 2, one(0050400), one(0170700), "Qd%s", m68000up }, +{"subb", 4, one(0002000), one(0177700), "#b$s", m68000up }, +{"subb", 2, one(0110000), one(0170700), ";bDd", m68000up }, +{"subb", 2, one(0110400), one(0170700), "Dd~s", m68000up }, +{"subw", 2, one(0050500), one(0170700), "Qd%s", m68000up }, +{"subw", 4, one(0002100), one(0177700), "#w$s", m68000up }, +{"subw", 2, one(0110300), one(0170700), "*wAd", m68000up }, +{"subw", 2, one(0110100), one(0170700), "*wDd", m68000up }, +{"subw", 2, one(0110500), one(0170700), "Dd~s", m68000up }, +{"subl", 2, one(0050600), one(0170700), "Qd%s", m68000up | mcfisa_a }, +{"subl", 6, one(0002200), one(0177700), "#l$s", m68000up }, +{"subl", 6, one(0002200), one(0177700), "#lDs", mcfisa_a }, +{"subl", 2, one(0110700), one(0170700), "*lAd", m68000up | mcfisa_a }, +{"subl", 2, one(0110200), one(0170700), "*lDd", m68000up | mcfisa_a }, +{"subl", 2, one(0110600), one(0170700), "Dd~s", m68000up | mcfisa_a }, + +{"subxb", 2, one(0110400), one(0170770), "DsDd", m68000up }, +{"subxb", 2, one(0110410), one(0170770), "-s-d", m68000up }, +{"subxw", 2, one(0110500), one(0170770), "DsDd", m68000up }, +{"subxw", 2, one(0110510), one(0170770), "-s-d", m68000up }, +{"subxl", 2, one(0110600), one(0170770), "DsDd", m68000up | mcfisa_a }, +{"subxl", 2, one(0110610), one(0170770), "-s-d", m68000up }, + +{"swap", 2, one(0044100), one(0177770), "Ds", m68000up | mcfisa_a }, + +/* swbeg and swbegl are magic constants used on sysV68. The compiler + generates them before a switch table. They tell the debugger and + disassembler that a switch table follows. The parameter is the + number of elements in the table. swbeg means that the entries in + the table are word (2 byte) sized, and swbegl means that the + entries in the table are longword (4 byte) sized. */ +{"swbeg", 4, one(0045374), one(0177777), "#w", m68000up | mcfisa_a }, +{"swbegl", 6, one(0045375), one(0177777), "#l", m68000up | mcfisa_a }, + +{"tas", 2, one(0045300), one(0177700), "$s", m68000up | mcfisa_b}, + +#define TBL1(name,insn_size,signed,round,size) \ + {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)|0000400), \ + two(0177700,0107777), "!sD1", cpu32 }, \ + {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)), \ + two(0177770,0107770), "DsD3D1", cpu32 } +#define TBL(name1, name2, name3, s, r) \ + TBL1(name1, 4, s, r, 0), TBL1(name2, 4, s, r, 1), TBL1(name3, 4, s, r, 2) +TBL("tblsb", "tblsw", "tblsl", 2, 1), +TBL("tblsnb", "tblsnw", "tblsnl", 2, 0), +TBL("tblub", "tbluw", "tblul", 0, 1), +TBL("tblunb", "tblunw", "tblunl", 0, 0), + +{"trap", 2, one(0047100), one(0177760), "Ts", m68000up | mcfisa_a }, + +{"trapcc", 2, one(0052374), one(0177777), "", m68020up | cpu32 }, +{"trapcs", 2, one(0052774), one(0177777), "", m68020up | cpu32 }, +{"trapeq", 2, one(0053774), one(0177777), "", m68020up | cpu32 }, +{"trapf", 2, one(0050774), one(0177777), "", m68020up | cpu32 | mcfisa_a }, +{"trapge", 2, one(0056374), one(0177777), "", m68020up | cpu32 }, +{"trapgt", 2, one(0057374), one(0177777), "", m68020up | cpu32 }, +{"traphi", 2, one(0051374), one(0177777), "", m68020up | cpu32 }, +{"traple", 2, one(0057774), one(0177777), "", m68020up | cpu32 }, +{"trapls", 2, one(0051774), one(0177777), "", m68020up | cpu32 }, +{"traplt", 2, one(0056774), one(0177777), "", m68020up | cpu32 }, +{"trapmi", 2, one(0055774), one(0177777), "", m68020up | cpu32 }, +{"trapne", 2, one(0053374), one(0177777), "", m68020up | cpu32 }, +{"trappl", 2, one(0055374), one(0177777), "", m68020up | cpu32 }, +{"trapt", 2, one(0050374), one(0177777), "", m68020up | cpu32 }, +{"trapvc", 2, one(0054374), one(0177777), "", m68020up | cpu32 }, +{"trapvs", 2, one(0054774), one(0177777), "", m68020up | cpu32 }, + +{"trapccw", 4, one(0052372), one(0177777), "#w", m68020up|cpu32 }, +{"trapcsw", 4, one(0052772), one(0177777), "#w", m68020up|cpu32 }, +{"trapeqw", 4, one(0053772), one(0177777), "#w", m68020up|cpu32 }, +{"trapfw", 4, one(0050772), one(0177777), "#w", m68020up|cpu32|mcfisa_a}, +{"trapgew", 4, one(0056372), one(0177777), "#w", m68020up|cpu32 }, +{"trapgtw", 4, one(0057372), one(0177777), "#w", m68020up|cpu32 }, +{"traphiw", 4, one(0051372), one(0177777), "#w", m68020up|cpu32 }, +{"traplew", 4, one(0057772), one(0177777), "#w", m68020up|cpu32 }, +{"traplsw", 4, one(0051772), one(0177777), "#w", m68020up|cpu32 }, +{"trapltw", 4, one(0056772), one(0177777), "#w", m68020up|cpu32 }, +{"trapmiw", 4, one(0055772), one(0177777), "#w", m68020up|cpu32 }, +{"trapnew", 4, one(0053372), one(0177777), "#w", m68020up|cpu32 }, +{"trapplw", 4, one(0055372), one(0177777), "#w", m68020up|cpu32 }, +{"traptw", 4, one(0050372), one(0177777), "#w", m68020up|cpu32 }, +{"trapvcw", 4, one(0054372), one(0177777), "#w", m68020up|cpu32 }, +{"trapvsw", 4, one(0054772), one(0177777), "#w", m68020up|cpu32 }, + +{"trapccl", 6, one(0052373), one(0177777), "#l", m68020up|cpu32 }, +{"trapcsl", 6, one(0052773), one(0177777), "#l", m68020up|cpu32 }, +{"trapeql", 6, one(0053773), one(0177777), "#l", m68020up|cpu32 }, +{"trapfl", 6, one(0050773), one(0177777), "#l", m68020up|cpu32|mcfisa_a}, +{"trapgel", 6, one(0056373), one(0177777), "#l", m68020up|cpu32 }, +{"trapgtl", 6, one(0057373), one(0177777), "#l", m68020up|cpu32 }, +{"traphil", 6, one(0051373), one(0177777), "#l", m68020up|cpu32 }, +{"traplel", 6, one(0057773), one(0177777), "#l", m68020up|cpu32 }, +{"traplsl", 6, one(0051773), one(0177777), "#l", m68020up|cpu32 }, +{"trapltl", 6, one(0056773), one(0177777), "#l", m68020up|cpu32 }, +{"trapmil", 6, one(0055773), one(0177777), "#l", m68020up|cpu32 }, +{"trapnel", 6, one(0053373), one(0177777), "#l", m68020up|cpu32 }, +{"trappll", 6, one(0055373), one(0177777), "#l", m68020up|cpu32 }, +{"traptl", 6, one(0050373), one(0177777), "#l", m68020up|cpu32 }, +{"trapvcl", 6, one(0054373), one(0177777), "#l", m68020up|cpu32 }, +{"trapvsl", 6, one(0054773), one(0177777), "#l", m68020up|cpu32 }, + +{"trapv", 2, one(0047166), one(0177777), "", m68000up }, + +{"tstb", 2, one(0045000), one(0177700), ";b", m68020up|cpu32|mcfisa_a }, +{"tstb", 2, one(0045000), one(0177700), "$b", m68000up }, +{"tstw", 2, one(0045100), one(0177700), "*w", m68020up|cpu32|mcfisa_a }, +{"tstw", 2, one(0045100), one(0177700), "$w", m68000up }, +{"tstl", 2, one(0045200), one(0177700), "*l", m68020up|cpu32|mcfisa_a }, +{"tstl", 2, one(0045200), one(0177700), "$l", m68000up }, + +{"unlk", 2, one(0047130), one(0177770), "As", m68000up | mcfisa_a }, + +{"unpk", 4, one(0100600), one(0170770), "DsDd#w", m68020up }, +{"unpk", 4, one(0100610), one(0170770), "-s-d#w", m68020up }, + +{"wddatab", 2, one(0175400), one(0177700), "~s", mcfisa_a }, +{"wddataw", 2, one(0175500), one(0177700), "~s", mcfisa_a }, +{"wddatal", 2, one(0175600), one(0177700), "~s", mcfisa_a }, + +{"wdebug", 4, two(0175720, 03), two(0177770, 0xffff), "as", mcfisa_a }, +{"wdebug", 4, two(0175750, 03), two(0177770, 0xffff), "ds", mcfisa_a }, +}; + +const int m68k_numopcodes = sizeof m68k_opcodes / sizeof m68k_opcodes[0]; + +/* These aliases used to be in the above table, each one duplicating + all of the entries for its primary exactly. This table was + constructed by mechanical processing of the opcode table, with a + small number of tweaks done by hand. There are probably a lot more + aliases above that could be moved down here, except for very minor + differences. */ + +const struct m68k_opcode_alias m68k_opcode_aliases[] = +{ + { "add", "addw", }, + { "adda", "addaw", }, + { "addi", "addiw", }, + { "addq", "addqw", }, + { "addx", "addxw", }, + { "asl", "aslw", }, + { "asr", "asrw", }, + { "bhi", "bhiw", }, + { "bls", "blsw", }, + { "bcc", "bccw", }, + { "bcs", "bcsw", }, + { "bne", "bnew", }, + { "beq", "beqw", }, + { "bvc", "bvcw", }, + { "bvs", "bvsw", }, + { "bpl", "bplw", }, + { "bmi", "bmiw", }, + { "bge", "bgew", }, + { "blt", "bltw", }, + { "bgt", "bgtw", }, + { "ble", "blew", }, + { "bra", "braw", }, + { "bsr", "bsrw", }, + { "bhib", "bhis", }, + { "blsb", "blss", }, + { "bccb", "bccs", }, + { "bcsb", "bcss", }, + { "bneb", "bnes", }, + { "beqb", "beqs", }, + { "bvcb", "bvcs", }, + { "bvsb", "bvss", }, + { "bplb", "bpls", }, + { "bmib", "bmis", }, + { "bgeb", "bges", }, + { "bltb", "blts", }, + { "bgtb", "bgts", }, + { "bleb", "bles", }, + { "brab", "bras", }, + { "bsrb", "bsrs", }, + { "bhs", "bccw" }, + { "bhss", "bccs" }, + { "bhsb", "bccs" }, + { "bhsw", "bccw" }, + { "bhsl", "bccl" }, + { "blo", "bcsw" }, + { "blos", "bcss" }, + { "blob", "bcss" }, + { "blow", "bcsw" }, + { "blol", "bcsl" }, + { "br", "braw", }, + { "brs", "bras", }, + { "brb", "bras", }, + { "brw", "braw", }, + { "brl", "bral", }, + { "jfnlt", "bcc", }, /* Apparently a sun alias. */ + { "jfngt", "ble", }, /* Apparently a sun alias. */ + { "jfeq", "beqs", }, /* Apparently a sun alias. */ + { "bchgb", "bchg", }, + { "bchgl", "bchg", }, + { "bclrb", "bclr", }, + { "bclrl", "bclr", }, + { "bsetb", "bset", }, + { "bsetl", "bset", }, + { "btstb", "btst", }, + { "btstl", "btst", }, + { "cas2", "cas2w", }, + { "cas", "casw", }, + { "chk2", "chk2w", }, + { "chk", "chkw", }, + { "clr", "clrw", }, + { "cmp2", "cmp2w", }, + { "cmpa", "cmpaw", }, + { "cmpi", "cmpiw", }, + { "cmpm", "cmpmw", }, + { "cmp", "cmpw", }, + { "dbccw", "dbcc", }, + { "dbcsw", "dbcs", }, + { "dbeqw", "dbeq", }, + { "dbfw", "dbf", }, + { "dbgew", "dbge", }, + { "dbgtw", "dbgt", }, + { "dbhiw", "dbhi", }, + { "dblew", "dble", }, + { "dblsw", "dbls", }, + { "dbltw", "dblt", }, + { "dbmiw", "dbmi", }, + { "dbnew", "dbne", }, + { "dbplw", "dbpl", }, + { "dbtw", "dbt", }, + { "dbvcw", "dbvc", }, + { "dbvsw", "dbvs", }, + { "dbhs", "dbcc", }, + { "dbhsw", "dbcc", }, + { "dbra", "dbf", }, + { "dbraw", "dbf", }, + { "tdivsl", "divsl", }, + { "divs", "divsw", }, + { "divu", "divuw", }, + { "ext", "extw", }, + { "extbw", "extw", }, + { "extwl", "extl", }, + { "fbneq", "fbne", }, + { "fbsneq", "fbsne", }, + { "fdbneq", "fdbne", }, + { "fdbsneq", "fdbsne", }, + { "fmovecr", "fmovecrx", }, + { "fmovm", "fmovem", }, + { "fsneq", "fsne", }, + { "fssneq", "fssne", }, + { "ftrapneq", "ftrapne", }, + { "ftrapsneq", "ftrapsne", }, + { "fjneq", "fjne", }, + { "fjsneq", "fjsne", }, + { "jmpl", "jmp", }, + { "jmps", "jmp", }, + { "jsrl", "jsr", }, + { "jsrs", "jsr", }, + { "leal", "lea", }, + { "lsl", "lslw", }, + { "lsr", "lsrw", }, + { "mac", "macw" }, + { "movea", "moveaw", }, + { "movem", "movemw", }, + { "movml", "moveml", }, + { "movmw", "movemw", }, + { "movm", "movemw", }, + { "movep", "movepw", }, + { "movpw", "movepw", }, + { "moves", "movesw" }, + { "muls", "mulsw", }, + { "mulu", "muluw", }, + { "msac", "msacw" }, + { "nbcdb", "nbcd" }, + { "neg", "negw", }, + { "negx", "negxw", }, + { "not", "notw", }, + { "peal", "pea", }, + { "rol", "rolw", }, + { "ror", "rorw", }, + { "roxl", "roxlw", }, + { "roxr", "roxrw", }, + { "sats", "satsl", }, + { "sbcdb", "sbcd", }, + { "sccb", "scc", }, + { "scsb", "scs", }, + { "seqb", "seq", }, + { "sfb", "sf", }, + { "sgeb", "sge", }, + { "sgtb", "sgt", }, + { "shib", "shi", }, + { "sleb", "sle", }, + { "slsb", "sls", }, + { "sltb", "slt", }, + { "smib", "smi", }, + { "sneb", "sne", }, + { "splb", "spl", }, + { "stb", "st", }, + { "svcb", "svc", }, + { "svsb", "svs", }, + { "sfge", "sge", }, + { "sfgt", "sgt", }, + { "sfle", "sle", }, + { "sflt", "slt", }, + { "sfneq", "sne", }, + { "suba", "subaw", }, + { "subi", "subiw", }, + { "subq", "subqw", }, + { "sub", "subw", }, + { "subx", "subxw", }, + { "swapw", "swap", }, + { "tasb", "tas", }, + { "tpcc", "trapcc", }, + { "tcc", "trapcc", }, + { "tst", "tstw", }, + { "jbra", "jra", }, + { "jbhi", "jhi", }, + { "jbls", "jls", }, + { "jbcc", "jcc", }, + { "jbcs", "jcs", }, + { "jbne", "jne", }, + { "jbeq", "jeq", }, + { "jbvc", "jvc", }, + { "jbvs", "jvs", }, + { "jbpl", "jpl", }, + { "jbmi", "jmi", }, + { "jbge", "jge", }, + { "jblt", "jlt", }, + { "jbgt", "jgt", }, + { "jble", "jle", }, + { "movql", "moveq", }, + { "moveql", "moveq", }, + { "movl", "movel", }, + { "movq", "moveq", }, + { "moval", "moveal", }, + { "movaw", "moveaw", }, + { "movb", "moveb", }, + { "movc", "movec", }, + { "movecl", "movec", }, + { "movpl", "movepl", }, + { "movw", "movew", }, + { "movsb", "movesb", }, + { "movsl", "movesl", }, + { "movsw", "movesw", }, + { "mov3q", "mov3ql", }, + + { "tdivul", "divul", }, /* For m68k-svr4. */ + { "fmovb", "fmoveb", }, + { "fsmovb", "fsmoveb", }, + { "fdmovb", "fdmoveb", }, + { "fmovd", "fmoved", }, + { "fsmovd", "fsmoved", }, + { "fmovl", "fmovel", }, + { "fsmovl", "fsmovel", }, + { "fdmovl", "fdmovel", }, + { "fmovp", "fmovep", }, + { "fsmovp", "fsmovep", }, + { "fdmovp", "fdmovep", }, + { "fmovs", "fmoves", }, + { "fsmovs", "fsmoves", }, + { "fdmovs", "fdmoves", }, + { "fmovw", "fmovew", }, + { "fsmovw", "fsmovew", }, + { "fdmovw", "fdmovew", }, + { "fmovx", "fmovex", }, + { "fsmovx", "fsmovex", }, + { "fdmovx", "fdmovex", }, + { "fmovcr", "fmovecr", }, + { "fmovcrx", "fmovecrx", }, + { "ftestb", "ftstb", }, + { "ftestd", "ftstd", }, + { "ftestl", "ftstl", }, + { "ftestp", "ftstp", }, + { "ftests", "ftsts", }, + { "ftestw", "ftstw", }, + { "ftestx", "ftstx", }, + + { "bitrevl", "bitrev", }, + { "byterevl", "byterev", }, + { "ff1l", "ff1", }, + +}; + +const int m68k_numaliases = + sizeof m68k_opcode_aliases / sizeof m68k_opcode_aliases[0]; +/* **** End of m68k-opc.c */ +/* **** floatformat.c from sourceware.org CVS 2005-08-14. */ +/* IEEE floating point support routines, for GDB, the GNU Debugger. + Copyright (C) 1991, 1994, 1999, 2000, 2003 Free Software Foundation, Inc. + +This file is part of GDB. + +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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This is needed to pick up the NAN macro on some systems. */ +//#define _GNU_SOURCE + +#ifndef INFINITY +#ifdef HUGE_VAL +#define INFINITY HUGE_VAL +#else +#define INFINITY (1.0 / 0.0) +#endif +#endif + +#ifndef NAN +#define NAN (0.0 / 0.0) +#endif + +static unsigned long get_field (const unsigned char *, + enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int); +static int floatformat_always_valid (const struct floatformat *fmt, + const char *from); + +static int +floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, + const char *from ATTRIBUTE_UNUSED) +{ + return 1; +} + +/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not + going to bother with trying to muck around with whether it is defined in + a system header, what we do if not, etc. */ +#define FLOATFORMAT_CHAR_BIT 8 + +/* floatformats for IEEE single and double, big and little endian. */ +const struct floatformat floatformat_ieee_single_big = +{ + floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, + floatformat_intbit_no, + "floatformat_ieee_single_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_single_little = +{ + floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, + floatformat_intbit_no, + "floatformat_ieee_single_little", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_double_big = +{ + floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ieee_double_little = +{ + floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_little", + floatformat_always_valid +}; + +/* floatformat for IEEE double, little endian byte order, with big endian word + ordering, as on the ARM. */ + +const struct floatformat floatformat_ieee_double_littlebyte_bigword = +{ + floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, + "floatformat_ieee_double_littlebyte_bigword", + floatformat_always_valid +}; + +static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from); + +static int +floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from) +{ + /* In the i387 double-extended format, if the exponent is all ones, + then the integer bit must be set. If the exponent is neither 0 + nor ~0, the intbit must also be set. Only if the exponent is + zero can it be zero, and then it must be zero. */ + unsigned long exponent, int_bit; + const unsigned char *ufrom = (const unsigned char *) from; + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->man_start, 1); + + if ((exponent == 0) != (int_bit == 0)) + return 0; + else + return 1; +} + +const struct floatformat floatformat_i387_ext = +{ + floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes, + "floatformat_i387_ext", + floatformat_i387_ext_is_valid +}; +const struct floatformat floatformat_m68881_ext = +{ + /* Note that the bits from 16 to 31 are unused. */ + floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_m68881_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_i960_ext = +{ + /* Note that the bits from 0 to 15 are unused. */ + floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_i960_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_m88110_ext = +{ + floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, + floatformat_intbit_yes, + "floatformat_m88110_ext", + floatformat_always_valid +}; +const struct floatformat floatformat_m88110_harris_ext = +{ + /* Harris uses raw format 128 bytes long, but the number is just an ieee + double, and the last 64 bits are wasted. */ + floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, + floatformat_intbit_no, + "floatformat_m88110_ext_harris", + floatformat_always_valid +}; +const struct floatformat floatformat_arm_ext_big = +{ + /* Bits 1 to 16 are unused. */ + floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_arm_ext_big", + floatformat_always_valid +}; +const struct floatformat floatformat_arm_ext_littlebyte_bigword = +{ + /* Bits 1 to 16 are unused. */ + floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, + floatformat_intbit_yes, + "floatformat_arm_ext_littlebyte_bigword", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_spill_big = +{ + floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, + "floatformat_ia64_spill_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_spill_little = +{ + floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, + "floatformat_ia64_spill_little", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_quad_big = +{ + floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, + floatformat_intbit_no, + "floatformat_ia64_quad_big", + floatformat_always_valid +}; +const struct floatformat floatformat_ia64_quad_little = +{ + floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, + floatformat_intbit_no, + "floatformat_ia64_quad_little", + floatformat_always_valid +}; + +/* Extract a field which starts at START and is LEN bits long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static unsigned long +get_field (const unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len) +{ + unsigned long result; + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + result = *(data + cur_byte) >> (-cur_bitshift); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while ((unsigned int) cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + /* This is the last byte; zero out the bits which are not part of + this field. */ + result |= + (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1)) + << cur_bitshift; + else + result |= *(data + cur_byte) << cur_bitshift; + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + } + return result; +} + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +void +floatformat_to_double (const struct floatformat *fmt, + const char *from, double *to) +{ + const unsigned char *ufrom = (const unsigned char *)from; + double dto; + long exponent; + unsigned long mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + int special_exponent; /* It's a NaN, denorm or zero */ + + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + + /* If the exponent indicates a NaN, we don't have information to + decide what to do. So we handle it like IEEE, except that we + don't try to preserve the type of NaN. FIXME. */ + if ((unsigned long) exponent == fmt->exp_nan) + { + int nan; + + mant_off = fmt->man_start; + mant_bits_left = fmt->man_len; + nan = 0; + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits) != 0) + { + /* This is a NaN. */ + nan = 1; + break; + } + + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* On certain systems (such as GNU/Linux), the use of the + INFINITY macro below may generate a warning that can not be + silenced due to a bug in GCC (PR preprocessor/11931). The + preprocessor fails to recognise the __extension__ keyword in + conjunction with the GNU/C99 extension for hexadecimal + floating point constants and will issue a warning when + compiling with -pedantic. */ + if (nan) + dto = NAN; + else + dto = INFINITY; + + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + + *to = dto; + + return; + } + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + dto = 0.0; + + special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan; + + /* Don't bias zero's, denorms or NaNs. */ + if (!special_exponent) + exponent -= fmt->exp_bias; + + /* Build the result algebraically. Might go infinite, underflow, etc; + who cares. */ + + /* If this format uses a hidden bit, explicitly add it in now. Otherwise, + increment the exponent by one to account for the integer bit. */ + + if (!special_exponent) + { + if (fmt->intbit == floatformat_intbit_no) + dto = ldexp (1.0, exponent); + else + exponent++; + } + + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits); + + /* Handle denormalized numbers. FIXME: What should we do for + non-IEEE formats? */ + if (exponent == 0 && mant != 0) + dto += ldexp ((double)mant, + (- fmt->exp_bias + - mant_bits + - (mant_off - fmt->man_start) + + 1)); + else + dto += ldexp ((double)mant, exponent - mant_bits); + if (exponent != 0) + exponent -= mant_bits; + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* Negate it if negative. */ + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + *to = dto; +} + +static void put_field (unsigned char *, enum floatformat_byteorders, + unsigned int, + unsigned int, + unsigned int, + unsigned long); + +/* Set a field which starts at START and is LEN bits long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static void +put_field (unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len, + unsigned long stuff_to_put) +{ + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + *(data + cur_byte) &= + ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift)); + *(data + cur_byte) |= + (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while ((unsigned int) cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + { + /* This is the last byte. */ + *(data + cur_byte) &= + ~((1 << (len - cur_bitshift)) - 1); + *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); + } + else + *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) + & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little) + ++cur_byte; + else + --cur_byte; + } +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. Neither FROM nor TO have any alignment + restrictions. */ + +void +floatformat_from_double (const struct floatformat *fmt, + const double *from, char *to) +{ + double dfrom; + int exponent; + double mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + unsigned char *uto = (unsigned char *)to; + + dfrom = *from; + memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); + + /* If negative, set the sign bit. */ + if (dfrom < 0) + { + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); + dfrom = -dfrom; + } + + if (dfrom == 0) + { + /* 0.0. */ + return; + } + + if (dfrom != dfrom) + { + /* NaN. */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + /* Be sure it's not infinity, but NaN value is irrelevant. */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, + 32, 1); + return; + } + + if (dfrom + dfrom == dfrom) + { + /* This can only happen for an infinite value (or zero, which we + already handled above). */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, fmt->exp_nan); + return; + } + + mant = frexp (dfrom, &exponent); + if (exponent + fmt->exp_bias - 1 > 0) + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, exponent + fmt->exp_bias - 1); + else + { + /* Handle a denormalized number. FIXME: What should we do for + non-IEEE formats? */ + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, + fmt->exp_len, 0); + mant = ldexp (mant, exponent + fmt->exp_bias - 1); + } + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + while (mant_bits_left > 0) + { + unsigned long mant_long; + mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; + + mant *= 4294967296.0; + mant_long = (unsigned long)mant; + mant -= mant_long; + + /* If the integer bit is implicit, and we are not creating a + denormalized number, then we need to discard it. */ + if ((unsigned int) mant_bits_left == fmt->man_len + && fmt->intbit == floatformat_intbit_no + && exponent + fmt->exp_bias - 1 > 0) + { + mant_long &= 0x7fffffff; + mant_bits -= 1; + } + else if (mant_bits < 32) + { + /* The bits we want are in the most significant MANT_BITS bits of + mant_long. Move them to the least significant. */ + mant_long >>= 32 - mant_bits; + } + + put_field (uto, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits, mant_long); + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } +} + +/* Return non-zero iff the data at FROM is a valid number in format FMT. */ + +int +floatformat_is_valid (const struct floatformat *fmt, const char *from) +{ + return fmt->is_valid (fmt, from); +} + + +#ifdef IEEE_DEBUG + +/* This is to be run on a host which uses IEEE floating point. */ + +void +ieee_test (double n) +{ + double result; + + floatformat_to_double (&floatformat_ieee_double_little, (char *) &n, + &result); + if ((n != result && (! isnan (n) || ! isnan (result))) + || (n < 0 && result >= 0) + || (n >= 0 && result < 0)) + printf ("Differ(to): %.20g -> %.20g\n", n, result); + + floatformat_from_double (&floatformat_ieee_double_little, &n, + (char *) &result); + if ((n != result && (! isnan (n) || ! isnan (result))) + || (n < 0 && result >= 0) + || (n >= 0 && result < 0)) + printf ("Differ(from): %.20g -> %.20g\n", n, result); + +#if 0 + { + char exten[16]; + + floatformat_from_double (&floatformat_m68881_ext, &n, exten); + floatformat_to_double (&floatformat_m68881_ext, exten, &result); + if (n != result) + printf ("Differ(to+from): %.20g -> %.20g\n", n, result); + } +#endif + +#if IEEE_DEBUG > 1 + /* This is to be run on a host which uses 68881 format. */ + { + long double ex = *(long double *)exten; + if (ex != n) + printf ("Differ(from vs. extended): %.20g\n", n); + } +#endif +} + +int +main (void) +{ + ieee_test (0.0); + ieee_test (0.5); + ieee_test (256.0); + ieee_test (0.12345); + ieee_test (234235.78907234); + ieee_test (-512.0); + ieee_test (-0.004321); + ieee_test (1.2E-70); + ieee_test (1.2E-316); + ieee_test (4.9406564584124654E-324); + ieee_test (- 4.9406564584124654E-324); + ieee_test (- 0.0); + ieee_test (- INFINITY); + ieee_test (- NAN); + ieee_test (INFINITY); + ieee_test (NAN); + return 0; +} +#endif +/* **** End of floatformat.c */ diff --git a/mips-dis.c b/mips-dis.c index fbc64c77c..f6128955c 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -2155,10 +2155,6 @@ struct mips_opcode *mips_opcodes = int bfd_mips_num_opcodes = MIPS_NUM_OPCODES; #undef MIPS_NUM_OPCODES -typedef int bfd_boolean; -#define TRUE (1) -#define FALSE (0) - /* Mips instructions are at maximum this many bytes long. */ #define INSNLEN 4 -- cgit v1.2.3 From 3dbbdc25557314f3338edd11b4569e4d6af600bf Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Nov 2005 18:20:37 +0000 Subject: suppressed unneeded options - added isapc machine git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1606 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 37 +++++++++++++++++++++++++++++++++++-- qemu-doc.texi | 8 +++----- vl.c | 20 +------------------- vl.h | 4 +--- 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 918615c92..399af2bd3 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -410,7 +410,8 @@ static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; static void pc_init1(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, + int pci_enabled) { char buf[1024]; int ret, linux_boot, initrd_size, i, nb_nics1; @@ -637,8 +638,40 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } } +static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + pc_init1(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 1); +} + +static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + pc_init1(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 0); +} + QEMUMachine pc_machine = { "pc", "Standard PC", - pc_init1, + pc_init_pci, +}; + +QEMUMachine isapc_machine = { + "isapc", + "ISA-only PC", + pc_init_isa, }; diff --git a/qemu-doc.texi b/qemu-doc.texi index 6d7e85cd6..df5f4e3c6 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -138,6 +138,9 @@ usage: qemu [options] [disk_image] General options: @table @option +@item -M machine +Select the emulated machine (@code{-M ?} for list) + @item -fda file @item -fdb file Use @var{file} as floppy disk 0/1 image (@xref{disk_images}). You can @@ -390,8 +393,6 @@ translation mode (@var{t}=none, lba or auto). Usually QEMU can guess all thoses parameters. This option is useful for old MS-DOS disk images. -@item -isa -Simulate an ISA-only system (default is PCI system). @item -std-vga Simulate a standard VGA card with Bochs VBE extensions (default is Cirrus Logic GD5446 PCI VGA) @@ -1137,9 +1138,6 @@ The following options are specific to the PowerPC emulation: @table @option -@item -prep -Simulate a PREP system (default is PowerMAC) - @item -g WxH[xDEPTH] Set the initial VGA graphic mode. The default is 800x600x15. diff --git a/vl.c b/vl.c index b8088035f..b1cd6553c 100644 --- a/vl.c +++ b/vl.c @@ -134,8 +134,6 @@ int adlib_enabled = 0; int gus_enabled = 0; int es1370_enabled = 0; #endif -int pci_enabled = 1; -int prep_enabled = 0; int rtc_utc = 1; int cirrus_vga_enabled = 1; #ifdef TARGET_SPARC @@ -3087,9 +3085,6 @@ enum { QEMU_OPTION_hdachs, QEMU_OPTION_L, QEMU_OPTION_no_code_copy, - QEMU_OPTION_pci, - QEMU_OPTION_isa, - QEMU_OPTION_prep, QEMU_OPTION_k, QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, @@ -3163,14 +3158,10 @@ const QEMUOption qemu_options[] = { #ifdef USE_KQEMU { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, #endif -#ifdef TARGET_PPC - { "prep", 0, QEMU_OPTION_prep }, -#endif #if defined(TARGET_PPC) || defined(TARGET_SPARC) { "g", 1, QEMU_OPTION_g }, #endif { "localtime", 0, QEMU_OPTION_localtime }, - { "isa", 0, QEMU_OPTION_isa }, { "std-vga", 0, QEMU_OPTION_std_vga }, { "monitor", 1, QEMU_OPTION_monitor }, { "serial", 1, QEMU_OPTION_serial }, @@ -3183,7 +3174,6 @@ const QEMUOption qemu_options[] = { /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, - { "pci", 0, QEMU_OPTION_pci }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, { NULL }, }; @@ -3239,6 +3229,7 @@ void register_machines(void) { #if defined(TARGET_I386) qemu_register_machine(&pc_machine); + qemu_register_machine(&isapc_machine); #elif defined(TARGET_PPC) qemu_register_machine(&heathrow_machine); qemu_register_machine(&core99_machine); @@ -3676,15 +3667,6 @@ int main(int argc, char **argv) case QEMU_OPTION_S: start_emulation = 0; break; - case QEMU_OPTION_pci: - pci_enabled = 1; - break; - case QEMU_OPTION_isa: - pci_enabled = 0; - break; - case QEMU_OPTION_prep: - prep_enabled = 1; - break; case QEMU_OPTION_k: keyboard_layout = optarg; break; diff --git a/vl.h b/vl.h index 4f181c50e..d31da1922 100644 --- a/vl.h +++ b/vl.h @@ -488,8 +488,6 @@ void isa_unassign_ioport(int start, int length); /* PCI bus */ -extern int pci_enabled; - extern target_phys_addr_t pci_mem_base; typedef struct PCIBus PCIBus; @@ -729,6 +727,7 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); /* pc.c */ extern QEMUMachine pc_machine; +extern QEMUMachine isapc_machine; /* ppc.c */ extern QEMUMachine prep_machine; @@ -745,7 +744,6 @@ void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); extern CPUWriteMemoryFunc *PPC_io_write[]; extern CPUReadMemoryFunc *PPC_io_read[]; -extern int prep_enabled; void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ -- cgit v1.2.3 From 2531fc7bc02f1ae1ddc5e313e5e6d7f9bf5f9225 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Nov 2005 19:36:29 +0000 Subject: thumb BLX insn fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1607 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index f954de3f7..96e7fd291 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2035,7 +2035,7 @@ static void disas_thumb_insn(DisasContext *s) gen_movl_reg_T1(s, 14); val += offset << 1; - if (insn & (1 << 11)) { + if (insn & (1 << 12)) { /* bl */ gen_jmp(s, val); } else { -- cgit v1.2.3 From 3f87bf69590c6b3aead85c4ebb8cc7c9c81ccda5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Nov 2005 19:56:23 +0000 Subject: use softfloat types in softmmu_header.h (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1608 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_header.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/softmmu_header.h b/softmmu_header.h index 0798cf572..81c65dc87 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -304,20 +304,20 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE #endif #if DATA_SIZE == 8 -static inline double glue(ldfq, MEMSUFFIX)(target_ulong ptr) +static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr) { union { - double d; + float64 d; uint64_t i; } u; u.i = glue(ldq, MEMSUFFIX)(ptr); return u.d; } -static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, double v) +static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v) { union { - double d; + float64 d; uint64_t i; } u; u.d = v; @@ -326,20 +326,20 @@ static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, double v) #endif /* DATA_SIZE == 8 */ #if DATA_SIZE == 4 -static inline float glue(ldfl, MEMSUFFIX)(target_ulong ptr) +static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr) { union { - float f; + float32 f; uint32_t i; } u; u.i = glue(ldl, MEMSUFFIX)(ptr); return u.f; } -static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float v) +static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) { union { - float f; + float32 f; uint32_t i; } u; u.f = v; -- cgit v1.2.3 From f8d179e33d71ddac580fb41f2b452099e7805d67 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 8 Nov 2005 22:30:36 +0000 Subject: use host serial port git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1609 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +- hw/serial.c | 40 ++++++++++++- qemu-doc.texi | 7 +++ vl.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- vl.h | 10 +++- 5 files changed, 232 insertions(+), 10 deletions(-) diff --git a/Changelog b/Changelog index 6aff1395d..32c417b6f 100644 --- a/Changelog +++ b/Changelog @@ -7,7 +7,8 @@ version 0.7.3: - new audio options: '-soundhw' and '-audio-help' (malc) - ES1370 PCI audio device (malc) - Initial USB support - + - Linux host serial port access + version 0.7.2: - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit) diff --git a/hw/serial.c b/hw/serial.c index ac04e6522..75be4de12 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -85,6 +85,7 @@ struct SerialState { int thr_ipending; int irq; CharDriverState *chr; + int last_break_enable; }; static void serial_update_irq(SerialState *s) @@ -103,6 +104,32 @@ static void serial_update_irq(SerialState *s) } } +static void serial_update_parameters(SerialState *s) +{ + int speed, parity, data_bits, stop_bits; + + if (s->lcr & 0x08) { + if (s->lcr & 0x10) + parity = 'E'; + else + parity = 'O'; + } else { + parity = 'N'; + } + if (s->lcr & 0x04) + stop_bits = 2; + else + stop_bits = 1; + data_bits = (s->lcr & 0x03) + 5; + if (s->divider == 0) + return; + speed = 115200 / s->divider; +#if 0 + printf("speed=%d parity=%c data=%d stop=%d\n", + speed, parity, data_bits, stop_bits); +#endif +} + static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) { SerialState *s = opaque; @@ -117,6 +144,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0: if (s->lcr & UART_LCR_DLAB) { s->divider = (s->divider & 0xff00) | val; + serial_update_parameters(s); } else { s->thr_ipending = 0; s->lsr &= ~UART_LSR_THRE; @@ -132,6 +160,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 1: if (s->lcr & UART_LCR_DLAB) { s->divider = (s->divider & 0x00ff) | (val << 8); + serial_update_parameters(s); } else { s->ier = val & 0x0f; if (s->lsr & UART_LSR_THRE) { @@ -143,7 +172,16 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 2: break; case 3: - s->lcr = val; + { + int break_enable; + s->lcr = val; + serial_update_parameters(s); + break_enable = (val >> 6) & 1; + if (break_enable != s->last_break_enable) { + s->last_break_enable = break_enable; + qemu_chr_set_serial_break(s, break_enable); + } + } break; case 4: s->mcr = val & 0x1f; diff --git a/qemu-doc.texi b/qemu-doc.texi index df5f4e3c6..253484fcd 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -363,8 +363,15 @@ Virtual console [Linux only] Pseudo TTY (a new PTY is automatically allocated) @item null void device +@item /dev/XXX +[Linux only]Use host tty, e.g. @file{/dev/ttyS0}. The host serial port +parameters are set according to the emulated ones. +@item file:filename +Write output to filename. No character can be read. @item stdio [Unix only] standard input/output +@item pipe:filename +[Unix only] name pipe @var{filename} @end table The default device is @code{vc} in graphical mode and @code{stdio} in non graphical mode. diff --git a/vl.c b/vl.c index b1cd6553c..75ec23bb3 100644 --- a/vl.c +++ b/vl.c @@ -1013,6 +1013,21 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) return s->chr_write(s, buf, len); } +void qemu_chr_set_serial_parameters(CharDriverState *s, + int speed, int parity, + int data_bits, int stop_bits) +{ + if (s->chr_set_serial_parameters) + s->chr_set_serial_parameters(s, speed, parity, data_bits, stop_bits); +} + +void qemu_chr_set_serial_break(CharDriverState *s, int enable) +{ + if (s->chr_set_serial_break) + s->chr_set_serial_break(s, enable); +} + + void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) { char buf[4096]; @@ -1111,12 +1126,14 @@ static void fd_chr_add_read_handler(CharDriverState *chr, { FDCharDriver *s = chr->opaque; - if (nographic && s->fd_in == 0) { - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; - } else { - qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque); + if (s->fd_in >= 0) { + if (nographic && s->fd_in == 0) { + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->fd_opaque = opaque; + } else { + qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque); + } } } @@ -1142,6 +1159,27 @@ CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) return chr; } +CharDriverState *qemu_chr_open_file_out(const char *file_out) +{ + int fd_out; + + fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY); + if (fd_out < 0) + return NULL; + return qemu_chr_open_fd(-1, fd_out); +} + +CharDriverState *qemu_chr_open_pipe(const char *filename) +{ + int fd; + + fd = open(filename, O_RDWR | O_BINARY); + if (fd < 0) + return NULL; + return qemu_chr_open_fd(fd, fd); +} + + /* for STDIO, we handle the case where several clients use it (nographic mode) */ @@ -1334,6 +1372,127 @@ CharDriverState *qemu_chr_open_pty(void) fprintf(stderr, "char device redirected to %s\n", slave_name); return qemu_chr_open_fd(master_fd, master_fd); } + +static void tty_serial_init(int fd, int speed, + int parity, int data_bits, int stop_bits) +{ + struct termios tty; + speed_t spd; + + tcgetattr (0, &tty); + + switch(speed) { + case 50: + spd = B50; + break; + case 75: + spd = B75; + break; + case 300: + spd = B300; + break; + case 600: + spd = B600; + break; + case 1200: + spd = B1200; + break; + case 2400: + spd = B2400; + break; + case 4800: + spd = B4800; + break; + case 9600: + spd = B9600; + break; + case 19200: + spd = B19200; + break; + case 38400: + spd = B38400; + break; + case 57600: + spd = B57600; + break; + default: + case 115200: + spd = B115200; + break; + } + + cfsetispeed(&tty, spd); + cfsetospeed(&tty, spd); + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); + tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS); + switch(data_bits) { + default: + case 8: + tty.c_cflag |= CS8; + break; + case 7: + tty.c_cflag |= CS7; + break; + case 6: + tty.c_cflag |= CS6; + break; + case 5: + tty.c_cflag |= CS5; + break; + } + switch(parity) { + default: + case 'N': + break; + case 'E': + tty.c_cflag |= PARENB; + break; + case 'O': + tty.c_cflag |= PARENB | PARODD; + break; + } + + tcsetattr (fd, TCSANOW, &tty); +} + +static void tty_set_serial_parameters(CharDriverState *chr, + int speed, int parity, + int data_bits, int stop_bits) +{ + FDCharDriver *s = chr->opaque; + tty_serial_init(s->fd_in, speed, parity, data_bits, stop_bits); +} + +static void tty_set_serial_break(CharDriverState *chr, int enable) +{ + FDCharDriver *s = chr->opaque; + /* XXX: find a better solution */ + if (enable) + tcsendbreak(s->fd_in, 1); +} + +CharDriverState *qemu_chr_open_tty(const char *filename) +{ + CharDriverState *chr; + int fd; + + fd = open(filename, O_RDWR); + if (fd < 0) + return NULL; + fcntl(fd, F_SETFL, O_NONBLOCK); + tty_serial_init(fd, 115200, 'N', 8, 1); + chr = qemu_chr_open_fd(fd, fd); + if (!chr) + return NULL; + chr->chr_set_serial_parameters = tty_set_serial_parameters; + chr->chr_set_serial_break = tty_set_serial_break; + return chr; +} + #else CharDriverState *qemu_chr_open_pty(void) { @@ -1345,10 +1504,15 @@ CharDriverState *qemu_chr_open_pty(void) CharDriverState *qemu_chr_open(const char *filename) { + const char *p; if (!strcmp(filename, "vc")) { return text_console_init(&display_state); } else if (!strcmp(filename, "null")) { return qemu_chr_open_null(); + } else if (strstart(filename, "file:", &p)) { + return qemu_chr_open_file_out(p); + } else if (strstart(filename, "pipe:", &p)) { + return qemu_chr_open_pipe(p); } else #ifndef _WIN32 if (!strcmp(filename, "pty")) { @@ -1356,6 +1520,11 @@ CharDriverState *qemu_chr_open(const char *filename) } else if (!strcmp(filename, "stdio")) { return qemu_chr_open_stdio(); } else +#endif +#if defined(__linux__) + if (strstart(filename, "/dev/", NULL)) { + return qemu_chr_open_tty(filename); + } else #endif { return NULL; @@ -3010,7 +3179,6 @@ void help(void) "-no-code-copy disable code copy acceleration\n" #endif #ifdef TARGET_I386 - "-isa simulate an ISA-only system (default is PCI system)\n" "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" #endif diff --git a/vl.h b/vl.h index d31da1922..40de851cc 100644 --- a/vl.h +++ b/vl.h @@ -207,6 +207,10 @@ typedef struct CharDriverState { void (*chr_add_read_handler)(struct CharDriverState *s, IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque); + void (*chr_set_serial_parameters)(struct CharDriverState *s, + int speed, int parity, + int data_bits, int stop_bits); + void (*chr_set_serial_break)(struct CharDriverState *s, int enable); IOEventHandler *chr_event; void (*chr_send_event)(struct CharDriverState *chr, int event); void *opaque; @@ -219,7 +223,11 @@ void qemu_chr_add_read_handler(CharDriverState *s, IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque); void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); - +void qemu_chr_set_serial_parameters(CharDriverState *s, + int speed, int parity, + int data_bits, int stop_bits); +void qemu_chr_set_serial_break(CharDriverState *s, int enable); + /* consoles */ typedef struct DisplayState DisplayState; -- cgit v1.2.3 From 2122c51a9c9d5935773d3a542248bd8f369b172c Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Nov 2005 23:58:33 +0000 Subject: char dev ioctls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1610 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/serial.c | 11 +++++++++-- vl.h | 28 ++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index 75be4de12..0250d77fb 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -107,6 +107,7 @@ static void serial_update_irq(SerialState *s) static void serial_update_parameters(SerialState *s) { int speed, parity, data_bits, stop_bits; + QEMUSerialSetParams ssp; if (s->lcr & 0x08) { if (s->lcr & 0x10) @@ -124,7 +125,12 @@ static void serial_update_parameters(SerialState *s) if (s->divider == 0) return; speed = 115200 / s->divider; -#if 0 + ssp.speed = speed; + ssp.parity = parity; + ssp.data_bits = data_bits; + ssp.stop_bits = stop_bits; + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); +#if 0 printf("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits); #endif @@ -179,7 +185,8 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) break_enable = (val >> 6) & 1; if (break_enable != s->last_break_enable) { s->last_break_enable = break_enable; - qemu_chr_set_serial_break(s, break_enable); + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, + &break_enable); } } break; diff --git a/vl.h b/vl.h index 40de851cc..574ec3e9e 100644 --- a/vl.h +++ b/vl.h @@ -200,6 +200,24 @@ void qemu_del_fd_read_handler(int fd); #define CHR_EVENT_BREAK 0 /* serial break char */ #define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */ + + +#define CHR_IOCTL_SERIAL_SET_PARAMS 1 +typedef struct { + int speed; + int parity; + int data_bits; + int stop_bits; +} QEMUSerialSetParams; + +#define CHR_IOCTL_SERIAL_SET_BREAK 2 + +#define CHR_IOCTL_PP_READ_DATA 3 +#define CHR_IOCTL_PP_WRITE_DATA 4 +#define CHR_IOCTL_PP_READ_CONTROL 5 +#define CHR_IOCTL_PP_WRITE_CONTROL 6 +#define CHR_IOCTL_PP_READ_STATUS 7 + typedef void IOEventHandler(void *opaque, int event); typedef struct CharDriverState { @@ -207,10 +225,7 @@ typedef struct CharDriverState { void (*chr_add_read_handler)(struct CharDriverState *s, IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque); - void (*chr_set_serial_parameters)(struct CharDriverState *s, - int speed, int parity, - int data_bits, int stop_bits); - void (*chr_set_serial_break)(struct CharDriverState *s, int enable); + int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); IOEventHandler *chr_event; void (*chr_send_event)(struct CharDriverState *chr, int event); void *opaque; @@ -223,10 +238,7 @@ void qemu_chr_add_read_handler(CharDriverState *s, IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque); void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); -void qemu_chr_set_serial_parameters(CharDriverState *s, - int speed, int parity, - int data_bits, int stop_bits); -void qemu_chr_set_serial_break(CharDriverState *s, int enable); +int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); /* consoles */ -- cgit v1.2.3 From e57a8c0eefcf648bd0f357abd94ee2871888f43d Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Nov 2005 23:58:52 +0000 Subject: low level host parallel port access git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1611 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + hw/parallel.c | 94 ++++++++++++++++++++++++++----------------- qemu-doc.texi | 14 ++++++- vl.c | 127 +++++++++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 171 insertions(+), 65 deletions(-) diff --git a/Changelog b/Changelog index 32c417b6f..6b8420fd9 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,7 @@ version 0.7.3: - ES1370 PCI audio device (malc) - Initial USB support - Linux host serial port access + - Linux host low level parallel port access version 0.7.2: diff --git a/hw/parallel.c b/hw/parallel.c index a304d7fdf..95ac7fd68 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -1,7 +1,7 @@ /* * QEMU Parallel PORT emulation * - * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2003-2005 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -50,6 +50,7 @@ struct ParallelState { int irq; int irq_pending; CharDriverState *chr; + int hw_driver; }; static void parallel_update_irq(ParallelState *s) @@ -70,29 +71,39 @@ static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val) #endif switch(addr) { case 0: - s->data = val; - parallel_update_irq(s); + if (s->hw_driver) { + s->data = val; + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data); + } else { + s->data = val; + parallel_update_irq(s); + } break; case 2: - if ((val & PARA_CTR_INIT) == 0 ) { - s->status = PARA_STS_BUSY; - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_ONLINE; - s->status |= PARA_STS_ERROR; - } - else if (val & PARA_CTR_SELECT) { - if (val & PARA_CTR_STROBE) { - s->status &= ~PARA_STS_BUSY; - if ((s->control & PARA_CTR_STROBE) == 0) - qemu_chr_write(s->chr, &s->data, 1); - } else { - if (s->control & PARA_CTR_INTEN) { - s->irq_pending = 1; + if (s->hw_driver) { + s->control = val; + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control); + } else { + if ((val & PARA_CTR_INIT) == 0 ) { + s->status = PARA_STS_BUSY; + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_ONLINE; + s->status |= PARA_STS_ERROR; + } + else if (val & PARA_CTR_SELECT) { + if (val & PARA_CTR_STROBE) { + s->status &= ~PARA_STS_BUSY; + if ((s->control & PARA_CTR_STROBE) == 0) + qemu_chr_write(s->chr, &s->data, 1); + } else { + if (s->control & PARA_CTR_INTEN) { + s->irq_pending = 1; + } } } + parallel_update_irq(s); + s->control = val; } - parallel_update_irq(s); - s->control = val; break; } } @@ -105,24 +116,35 @@ static uint32_t parallel_ioport_read(void *opaque, uint32_t addr) addr &= 7; switch(addr) { case 0: + if (s->hw_driver) { + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data); + } ret = s->data; break; case 1: - ret = s->status; - s->irq_pending = 0; - if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { - /* XXX Fixme: wait 5 microseconds */ - if (s->status & PARA_STS_ACK) - s->status &= ~PARA_STS_ACK; - else { - /* XXX Fixme: wait 5 microseconds */ - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_BUSY; + if (s->hw_driver) { + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status); + ret = s->status; + } else { + ret = s->status; + s->irq_pending = 0; + if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { + /* XXX Fixme: wait 5 microseconds */ + if (s->status & PARA_STS_ACK) + s->status &= ~PARA_STS_ACK; + else { + /* XXX Fixme: wait 5 microseconds */ + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_BUSY; + } } + parallel_update_irq(s); } - parallel_update_irq(s); break; case 2: + if (s->hw_driver) { + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control); + } ret = s->control; break; } @@ -153,18 +175,20 @@ static void parallel_receive1(void *opaque, const uint8_t *buf, int size) parallel_receive_byte(s, buf[0]); } -static void parallel_event(void *opaque, int event) -{ -} - /* If fd is zero, it means that the parallel device uses the console */ ParallelState *parallel_init(int base, int irq, CharDriverState *chr) { ParallelState *s; + uint8_t dummy; s = qemu_mallocz(sizeof(ParallelState)); if (!s) return NULL; + s->chr = chr; + s->hw_driver = 0; + if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) + s->hw_driver = 1; + s->irq = irq; s->data = 0; s->status = PARA_STS_BUSY; @@ -176,8 +200,6 @@ ParallelState *parallel_init(int base, int irq, CharDriverState *chr) register_ioport_write(base, 8, 1, parallel_ioport_write, s); register_ioport_read(base, 8, 1, parallel_ioport_read, s); - s->chr = chr; qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s); - qemu_chr_add_event_handler(chr, parallel_event); return s; } diff --git a/qemu-doc.texi b/qemu-doc.texi index 253484fcd..41b742278 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -364,8 +364,11 @@ Virtual console @item null void device @item /dev/XXX -[Linux only]Use host tty, e.g. @file{/dev/ttyS0}. The host serial port +[Linux only] Use host tty, e.g. @file{/dev/ttyS0}. The host serial port parameters are set according to the emulated ones. +@item /dev/parportN +[Linux only, parallel port only] Use host parallel port +@var{N}. Currently only SPP parallel port features can be used. @item file:filename Write output to filename. No character can be read. @item stdio @@ -379,6 +382,15 @@ non graphical mode. This option can be used several times to simulate up to 4 serials ports. +@item -parallel dev +Redirect the virtual parallel port to host device @var{dev} (same +devices as the serial port). On Linux hosts, @file{/dev/parportN} can +be used to use hardware devices connected on the corresponding host +parallel port. + +This option can be used several times to simulate up to 3 parallel +ports. + @item -monitor dev Redirect the monitor to host device @var{dev} (same devices as the serial port). diff --git a/vl.c b/vl.c index 75ec23bb3..2ced88868 100644 --- a/vl.c +++ b/vl.c @@ -51,6 +51,7 @@ #include #include #include +#include #endif #endif @@ -1013,21 +1014,13 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) return s->chr_write(s, buf, len); } -void qemu_chr_set_serial_parameters(CharDriverState *s, - int speed, int parity, - int data_bits, int stop_bits) +int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) { - if (s->chr_set_serial_parameters) - s->chr_set_serial_parameters(s, speed, parity, data_bits, stop_bits); + if (!s->chr_ioctl) + return -ENOTSUP; + return s->chr_ioctl(s, cmd, arg); } -void qemu_chr_set_serial_break(CharDriverState *s, int enable) -{ - if (s->chr_set_serial_break) - s->chr_set_serial_break(s, enable); -} - - void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) { char buf[4096]; @@ -1379,7 +1372,11 @@ static void tty_serial_init(int fd, int speed, struct termios tty; speed_t spd; - tcgetattr (0, &tty); +#if 0 + printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", + speed, parity, data_bits, stop_bits); +#endif + tcgetattr (fd, &tty); switch(speed) { case 50: @@ -1459,20 +1456,29 @@ static void tty_serial_init(int fd, int speed, tcsetattr (fd, TCSANOW, &tty); } -static void tty_set_serial_parameters(CharDriverState *chr, - int speed, int parity, - int data_bits, int stop_bits) +static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) { FDCharDriver *s = chr->opaque; - tty_serial_init(s->fd_in, speed, parity, data_bits, stop_bits); -} - -static void tty_set_serial_break(CharDriverState *chr, int enable) -{ - FDCharDriver *s = chr->opaque; - /* XXX: find a better solution */ - if (enable) - tcsendbreak(s->fd_in, 1); + + switch(cmd) { + case CHR_IOCTL_SERIAL_SET_PARAMS: + { + QEMUSerialSetParams *ssp = arg; + tty_serial_init(s->fd_in, ssp->speed, ssp->parity, + ssp->data_bits, ssp->stop_bits); + } + break; + case CHR_IOCTL_SERIAL_SET_BREAK: + { + int enable = *(int *)arg; + if (enable) + tcsendbreak(s->fd_in, 1); + } + break; + default: + return -ENOTSUP; + } + return 0; } CharDriverState *qemu_chr_open_tty(const char *filename) @@ -1480,7 +1486,7 @@ CharDriverState *qemu_chr_open_tty(const char *filename) CharDriverState *chr; int fd; - fd = open(filename, O_RDWR); + fd = open(filename, O_RDWR | O_NONBLOCK); if (fd < 0) return NULL; fcntl(fd, F_SETFL, O_NONBLOCK); @@ -1488,8 +1494,70 @@ CharDriverState *qemu_chr_open_tty(const char *filename) chr = qemu_chr_open_fd(fd, fd); if (!chr) return NULL; - chr->chr_set_serial_parameters = tty_set_serial_parameters; - chr->chr_set_serial_break = tty_set_serial_break; + chr->chr_ioctl = tty_serial_ioctl; + return chr; +} + +static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) +{ + int fd = (int)chr->opaque; + uint8_t b; + + switch(cmd) { + case CHR_IOCTL_PP_READ_DATA: + if (ioctl(fd, PPRDATA, &b) < 0) + return -ENOTSUP; + *(uint8_t *)arg = b; + break; + case CHR_IOCTL_PP_WRITE_DATA: + b = *(uint8_t *)arg; + if (ioctl(fd, PPWDATA, &b) < 0) + return -ENOTSUP; + break; + case CHR_IOCTL_PP_READ_CONTROL: + if (ioctl(fd, PPRCONTROL, &b) < 0) + return -ENOTSUP; + *(uint8_t *)arg = b; + break; + case CHR_IOCTL_PP_WRITE_CONTROL: + b = *(uint8_t *)arg; + if (ioctl(fd, PPWCONTROL, &b) < 0) + return -ENOTSUP; + break; + case CHR_IOCTL_PP_READ_STATUS: + if (ioctl(fd, PPRSTATUS, &b) < 0) + return -ENOTSUP; + *(uint8_t *)arg = b; + break; + default: + return -ENOTSUP; + } + return 0; +} + +CharDriverState *qemu_chr_open_pp(const char *filename) +{ + CharDriverState *chr; + int fd; + + fd = open(filename, O_RDWR); + if (fd < 0) + return NULL; + + if (ioctl(fd, PPCLAIM) < 0) { + close(fd); + return NULL; + } + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) { + close(fd); + return NULL; + } + chr->opaque = (void *)fd; + chr->chr_write = null_chr_write; + chr->chr_add_read_handler = null_chr_add_read_handler; + chr->chr_ioctl = pp_ioctl; return chr; } @@ -1522,6 +1590,9 @@ CharDriverState *qemu_chr_open(const char *filename) } else #endif #if defined(__linux__) + if (strstart(filename, "/dev/parport", NULL)) { + return qemu_chr_open_pp(filename); + } else if (strstart(filename, "/dev/", NULL)) { return qemu_chr_open_tty(filename); } else -- cgit v1.2.3 From a0d01ed9ea59e32d324ac7e43a5496b08e1bcf14 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 10 Nov 2005 23:59:38 +0000 Subject: spelling fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1612 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sb16.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sb16.c b/hw/sb16.c index 4414af3d8..8c633c310 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -1364,7 +1364,7 @@ int SB16_init (AudioState *audio) s = qemu_mallocz (sizeof (*s)); if (!s) { - dolog ("Could not allocate memory for SB16 (%d bytes)\n", + dolog ("Could not allocate memory for SB16 (%zu bytes)\n", sizeof (*s)); return -1; } -- cgit v1.2.3 From 946fc94733c9120ddc78512838d9087d01418eaa Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Nov 2005 00:00:09 +0000 Subject: ES1370 word sized read fix (aka Win9x bug) (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1613 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/es1370.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/hw/es1370.c b/hw/es1370.c index fc7ac0a96..217fd30b5 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -249,7 +249,7 @@ static void print_sctl (uint32_t val) #endif #ifndef SILENT_ES1370 -#define lwarn(...) AUD_log ("es1370: warning:", __VA_ARGS__) +#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__) #else #define lwarn(...) #endif @@ -590,6 +590,13 @@ IO_WRITE_PROTO (es1370_writel) ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val); break; + case ES1370_REG_PHANTOM_FRAMECNT: + lwarn ("writing to phantom frame count %#x\n", val); + break; + case ES1370_REG_PHANTOM_FRAMEADR: + lwarn ("writing to phantom frame address %#x\n", val); + break; + case ES1370_REG_ADC_FRAMECNT: d++; case ES1370_REG_DAC2_FRAMECNT: @@ -659,6 +666,22 @@ IO_READ_PROTO (es1370_readw) val = d->scount >> 16; break; + case ES1370_REG_ADC_FRAMECNT: + d++; + case ES1370_REG_DAC2_FRAMECNT: + d++; + case ES1370_REG_DAC1_FRAMECNT: + val = d->frame_cnt & 0xffff; + break; + + case ES1370_REG_ADC_FRAMECNT + 2: + d++; + case ES1370_REG_DAC2_FRAMECNT + 2: + d++; + case ES1370_REG_DAC1_FRAMECNT + 2: + val = d->frame_cnt >> 16; + break; + default: val = ~0; lwarn ("readw %#x -> %#x\n", addr, val); @@ -736,6 +759,15 @@ IO_READ_PROTO (es1370_readl) val = d->frame_addr; break; + case ES1370_REG_PHANTOM_FRAMECNT: + val = ~0U; + lwarn ("reading from phantom frame count\n"); + break; + case ES1370_REG_PHANTOM_FRAMEADR: + val = ~0U; + lwarn ("reading from phantom frame address\n"); + break; + default: val = ~0U; lwarn ("readl %#x -> %#x\n", addr, val); @@ -812,7 +844,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, if (s->sctl & loop_sel) { /* Bah, how stupid is that having a 0 represent true value? i just spent few hours on this shit */ - lwarn ("whoops non looping mode\n"); + AUD_log ("es1370: warning", "non looping mode\n"); } else { d->frame_cnt = size; @@ -983,7 +1015,7 @@ int es1370_init (PCIBus *bus, AudioState *audio) -1, NULL, NULL); if (!d) { - fprintf (stderr, "Failed to register PCI device for ES1370\n"); + AUD_log (NULL, "Failed to register PCI device for ES1370\n"); return -1; } -- cgit v1.2.3 From 0bd488500244aee6596097b564eb95a32823a6d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Nov 2005 00:00:47 +0000 Subject: API for changes in VM state (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1614 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- vl.h | 6 ++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index 2ced88868..62a2bbbbd 100644 --- a/vl.c +++ b/vl.c @@ -2935,9 +2935,47 @@ void gui_update(void *opaque) qemu_mod_timer(gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock)); } +struct vm_change_state_entry { + VMChangeStateHandler *cb; + void *opaque; + LIST_ENTRY (vm_change_state_entry) entries; +}; + +static LIST_HEAD(vm_change_state_head, vm_change_state_entry) vm_change_state_head; + +VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, + void *opaque) +{ + VMChangeStateEntry *e; + + e = qemu_mallocz(sizeof (*e)); + if (!e) + return NULL; + + e->cb = cb; + e->opaque = opaque; + LIST_INSERT_HEAD(&vm_change_state_head, e, entries); + return e; +} + +void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) +{ + LIST_REMOVE (e, entries); + qemu_free (e); +} + +static void vm_state_notify(int running) +{ + VMChangeStateEntry *e; + + for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) { + e->cb(e->opaque, running); + } +} + /* XXX: support several handlers */ -VMStopHandler *vm_stop_cb; -VMStopHandler *vm_stop_opaque; +static VMStopHandler *vm_stop_cb; +static void *vm_stop_opaque; int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque) { @@ -2956,6 +2994,7 @@ void vm_start(void) if (!vm_running) { cpu_enable_ticks(); vm_running = 1; + vm_state_notify(1); } } @@ -2969,6 +3008,7 @@ void vm_stop(int reason) vm_stop_cb(vm_stop_opaque, reason); } } + vm_state_notify(0); } } @@ -3588,7 +3628,8 @@ int main(int argc, char **argv) QEMUMachine *machine; char usb_devices[MAX_VM_USB_PORTS][128]; int usb_devices_index; - + + LIST_INIT (&vm_change_state_head); #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); diff --git a/vl.h b/vl.h index 574ec3e9e..10cfb5840 100644 --- a/vl.h +++ b/vl.h @@ -97,8 +97,14 @@ int strstart(const char *str, const char *val, const char **ptr); extern int vm_running; +typedef struct vm_change_state_entry VMChangeStateEntry; +typedef void VMChangeStateHandler(void *opaque, int running); typedef void VMStopHandler(void *opaque, int reason); +VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, + void *opaque); +void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); + int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque); void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque); -- cgit v1.2.3 From b41cffbeb4220dec30f512dc9e22cf5adfa3d49f Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Nov 2005 00:02:25 +0000 Subject: debug msg (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1615 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/ossaudio.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 507274249..d78e59019 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -506,8 +506,11 @@ static int oss_init_out (HWVoiceOut *hw, audsettings_t *as) 1 << hw->info.shift ); if (!oss->pcm_buf) { - dolog ("Could not allocate DAC buffer (%d bytes)\n", - hw->samples << hw->info.shift); + dolog ( + "Could not allocate DAC buffer (%d samples, each %d bytes)\n", + hw->samples, + 1 << hw->info.shift + ); oss_anal_close (&fd); return -1; } @@ -597,8 +600,8 @@ static int oss_init_in (HWVoiceIn *hw, audsettings_t *as) hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!oss->pcm_buf) { - dolog ("Could not allocate ADC buffer (%d bytes)\n", - hw->samples << hw->info.shift); + dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", + hw->samples, 1 << hw->info.shift); oss_anal_close (&fd); return -1; } @@ -657,7 +660,7 @@ static int oss_run_in (HWVoiceIn *hw) if (nread > 0) { if (nread & hw->info.align) { - dolog ("warning: Misaligned read %d (requested %d), " + dolog ("warning: Misaligned read %zd (requested %d), " "alignment %d\n", nread, bufs[i].add << hwshift, hw->info.align + 1); } -- cgit v1.2.3 From 575b5dc4dca9ba7cf61f85aa8b511477e2ebb03b Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Nov 2005 00:03:20 +0000 Subject: compile fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1616 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/coreaudio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 855193868..75e2b7d61 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -375,7 +375,8 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) propertySize, &core->outputStreamBasicDescription); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", freq); + coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", + as->freq); core->outputDeviceID = kAudioDeviceUnknown; return -1; } -- cgit v1.2.3 From e7cad33853d24c0df1f4fb566485a866a8f0e40a Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Nov 2005 00:03:36 +0000 Subject: size_t fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1617 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/audio_template.h | 3 ++- audio/mixeng.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/audio/audio_template.h b/audio/audio_template.h index d985c2eef..be32c68b3 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -131,6 +131,7 @@ static HW *glue (audio_pcm_hw_find_any_passive_, TYPE) (AudioState *s) if (!hw) { dolog ("Can not allocate voice `%s' size %d\n", drv->name, glue (drv->voice_size_, TYPE)); + return NULL; } LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); @@ -221,7 +222,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); if (!sw) { - dolog ("Could not allocate soft voice `%s' (%d bytes)\n", + dolog ("Could not allocate soft voice `%s' (%zu bytes)\n", sw_name ? sw_name : "unknown", sizeof (*sw)); goto err1; } diff --git a/audio/mixeng.c b/audio/mixeng.c index 14e37ae16..6308d4100 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -243,7 +243,7 @@ void *st_rate_start (int inrate, int outrate) struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate)); if (!rate) { - dolog ("Could not allocate resampler (%d bytes)\n", sizeof (*rate)); + dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate)); return NULL; } -- cgit v1.2.3 From 541e084426ba3788f19c25e0c442323c9d31bc8d Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Nov 2005 00:04:19 +0000 Subject: VM state change support (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1618 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/audio.c | 84 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 961654b00..eba4fdb12 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -70,6 +70,7 @@ static struct { int64_t ticks; } period; int plive; + int log_to_monitor; } conf = { { /* DAC fixed settings */ 1, /* enabled */ @@ -94,7 +95,8 @@ static struct { }, { 0 }, /* period */ - 0 /* plive */ + 0, /* plive */ + 0 }; static AudioState glob_audio_state; @@ -176,7 +178,7 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size) if (audio_bug ("audio_calloc", cond)) { AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n", funcname); - AUD_log (NULL, "nmemb=%d size=%d (len=%d)\n", nmemb, size, len); + AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len); return NULL; } @@ -300,23 +302,31 @@ static const char *audio_get_conf_str (const char *key, } } -void AUD_log (const char *cap, const char *fmt, ...) +void AUD_vlog (const char *cap, const char *fmt, va_list ap) { - va_list ap; - if (cap) { - fprintf (stderr, "%s: ", cap); + if (conf.log_to_monitor) { + if (cap) { + term_printf ("%s: ", cap); + } + + term_vprintf (fmt, ap); + } + else { + if (cap) { + fprintf (stderr, "%s: ", cap); + } + + vfprintf (stderr, fmt, ap); } - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); } -void AUD_vlog (const char *cap, const char *fmt, va_list ap) +void AUD_log (const char *cap, const char *fmt, ...) { - if (cap) { - fprintf (stderr, "%s: ", cap); - } - vfprintf (stderr, fmt, ap); + va_list ap; + + va_start (ap, fmt); + AUD_vlog (cap, fmt, ap); + va_end (ap); } static void audio_print_options (const char *prefix, @@ -625,8 +635,8 @@ static int audio_pcm_hw_alloc_resources_in (HWVoiceIn *hw) { hw->conv_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); if (!hw->conv_buf) { - dolog ("Could not allocate ADC conversion buffer (%d bytes)\n", - hw->samples * sizeof (st_sample_t)); + dolog ("Could not allocate ADC conversion buffer (%d samples)\n", + hw->samples); return -1; } return 0; @@ -677,8 +687,8 @@ static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw) int samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; sw->conv_buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t)); if (!sw->conv_buf) { - dolog ("Could not allocate buffer for `%s' (%d bytes)\n", - SW_NAME (sw), samples * sizeof (st_sample_t)); + dolog ("Could not allocate buffer for `%s' (%d samples)\n", + SW_NAME (sw), samples); return -1; } @@ -805,8 +815,8 @@ static int audio_pcm_hw_alloc_resources_out (HWVoiceOut *hw) { hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); if (!hw->mix_buf) { - dolog ("Could not allocate DAC mixing buffer (%d bytes)\n", - hw->samples * sizeof (st_sample_t)); + dolog ("Could not allocate DAC mixing buffer (%d samples)\n", + hw->samples); return -1; } @@ -884,8 +894,8 @@ static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw) { sw->buf = audio_calloc (AUDIO_FUNC, sw->hw->samples, sizeof (st_sample_t)); if (!sw->buf) { - dolog ("Could not allocate buffer for `%s' (%d bytes)\n", - SW_NAME (sw), sw->hw->samples * sizeof (st_sample_t)); + dolog ("Could not allocate buffer for `%s' (%d samples)\n", + SW_NAME (sw), sw->hw->samples); return -1; } @@ -1346,6 +1356,10 @@ static struct audio_option audio_options[] = { {"PLIVE", AUD_OPT_BOOL, &conf.plive, "(undocumented)", NULL, 0}, + + {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor, + "print logging messages to montior instead of stderr", NULL, 0}, + {NULL, 0, NULL, NULL, NULL, 0} }; @@ -1513,31 +1527,19 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv) } } -static void audio_vm_stop_handler (void *opaque, int reason) +static void audio_vm_change_state_handler (void *opaque, int running) { AudioState *s = opaque; HWVoiceOut *hwo = NULL; HWVoiceIn *hwi = NULL; - int op = reason ? VOICE_ENABLE : VOICE_DISABLE; - - while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) { - if (!hwo->pcm_ops) { - continue; - } + int op = running ? VOICE_ENABLE : VOICE_DISABLE; - if (hwo->enabled != reason) { - hwo->pcm_ops->ctl_out (hwo, op); - } + while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { + hwo->pcm_ops->ctl_out (hwo, op); } - while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) { - if (!hwi->pcm_ops) { - continue; - } - - if (hwi->enabled != reason) { - hwi->pcm_ops->ctl_in (hwi, op); - } + while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) { + hwi->pcm_ops->ctl_in (hwi, op); } } @@ -1690,7 +1692,7 @@ AudioState *AUD_init (void) conf.period.ticks = ticks_per_sec / conf.period.hz; } - qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); + qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s); } else { qemu_del_timer (s->ts); -- cgit v1.2.3 From 4787c71d179ae9b67b0e682a2a95b6ceca4e68c4 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Nov 2005 00:06:10 +0000 Subject: debug fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1619 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 63 +++++++++++++++++++++++++++++-------------------------- audio/audio_int.h | 2 +- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 65a0a0d2e..f7748ca82 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -570,36 +570,39 @@ static int alsa_run_out (HWVoiceOut *hw) hw->clip (dst, src, convert_samples); - again: - written = snd_pcm_writei (alsa->handle, dst, convert_samples); - - if (written < 0) { - switch (written) { - case -EPIPE: - if (!alsa_recover (alsa->handle)) { - goto again; - } - dolog ( - "Failed to write %d frames to %p, handle %p not prepared\n", - convert_samples, - dst, - alsa->handle - ); - goto exit; + while (convert_samples) { + written = snd_pcm_writei (alsa->handle, dst, convert_samples); - case -EAGAIN: - goto again; + if (written < 0) { + switch (written) { + case -EPIPE: + if (!alsa_recover (alsa->handle)) { + continue; + } + dolog ("Failed to write %d frames to %p, " + "handle %p not prepared\n", + convert_samples, + dst, + alsa->handle); + goto exit; - default: - alsa_logerr (written, "Failed to write %d frames to %p\n", - convert_samples, dst); - goto exit; + case -EAGAIN: + continue; + + default: + alsa_logerr (written, "Failed to write %d frames to %p\n", + convert_samples, dst); + goto exit; + } } - } - mixeng_clear (src, written); - rpos = (rpos + written) % hw->samples; - samples -= written; + mixeng_clear (src, written); + rpos = (rpos + written) % hw->samples; + samples -= written; + convert_samples -= written; + dst = advance (dst, written << hw->info.shift); + src += written; + } } exit: @@ -661,8 +664,8 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as) alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift); if (!alsa->pcm_buf) { - dolog ("Could not allocate DAC buffer (%d bytes)\n", - hw->samples << hw->info.shift); + dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n", + hw->samples, 1 << hw->info.shift); alsa_anal_close (&handle); return -1; } @@ -751,8 +754,8 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!alsa->pcm_buf) { - dolog ("Could not allocate ADC buffer (%d bytes)\n", - hw->samples << hw->info.shift); + dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", + hw->samples, 1 << hw->info.shift); alsa_anal_close (&handle); return -1; } diff --git a/audio/audio_int.h b/audio/audio_int.h index 6d4c32b06..8fee7b96f 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -216,7 +216,7 @@ static inline int audio_need_to_swap_endian (int endianness) #if defined __GNUC__ #define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2))) #define INIT_FIELD(f) . f -#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (printf, n, m))) +#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (__printf__, n, m))) #else #define GCC_ATTR /**/ #define INIT_FIELD(f) /**/ -- cgit v1.2.3 From 9e61bde56a65c92ff67559f8ab94887f8aa57a4d Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 11 Nov 2005 00:24:58 +0000 Subject: sparc merge (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1620 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 42 ++- pc-bios/proll.elf | Bin 152807 -> 132317 bytes pc-bios/proll.patch | 842 ++++++++++++++++++++++++++++++++++++++--------- target-sparc/helper.c | 8 +- target-sparc/op_helper.c | 8 + target-sparc/translate.c | 10 +- 6 files changed, 736 insertions(+), 174 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 6890bd144..169531ff1 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -29,6 +29,8 @@ #ifdef DEBUG_ESP #define DPRINTF(fmt, args...) \ do { printf("ESP: " fmt , ##args); } while (0) +#define pic_set_irq(irq, level) \ +do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0) #else #define DPRINTF(fmt, args...) #endif @@ -38,6 +40,8 @@ do { printf("ESP: " fmt , ##args); } while (0) #define ESP_MAXREG 0x3f #define TI_BUFSZ 65536 #define DMA_VER 0xa0000000 +#define DMA_INTR 1 +#define DMA_INTREN 0x10 #define DMA_LOADED 0x04000000 typedef struct ESPState { @@ -66,6 +70,7 @@ typedef struct ESPState { #define INTR_FC 0x08 #define INTR_BS 0x10 #define INTR_DC 0x20 +#define INTR_RST 0x80 #define SEQ_0 0x0 #define SEQ_CD 0x4 @@ -98,11 +103,11 @@ static void handle_satn(ESPState *s) s->ti_rptr = 0; s->ti_wptr = 0; - if (target > 4 || !s->bd[target]) { // No such drive + if (target >= 4 || !s->bd[target]) { // No such drive s->rregs[4] = STAT_IN; s->rregs[5] = INTR_DC; s->rregs[6] = SEQ_0; - s->espdmaregs[0] |= 1; + s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); return; } @@ -192,7 +197,7 @@ static void handle_satn(ESPState *s) s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= 1; + s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); } @@ -209,13 +214,14 @@ static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= 1; } else { memcpy(s->ti_buf, buf, len); s->ti_size = dmalen; s->ti_rptr = 0; s->ti_wptr = 0; + s->rregs[7] = dmalen; } + s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); } @@ -242,11 +248,12 @@ static void handle_ti(ESPState *s) s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS; s->rregs[6] = 0; - s->espdmaregs[0] |= 1; + s->espdmaregs[0] |= DMA_INTR; } else { s->ti_size = dmalen; s->ti_rptr = 0; s->ti_wptr = 0; + s->rregs[7] = dmalen; } pic_set_irq(s->irq, 1); } @@ -265,6 +272,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) uint32_t saddr; saddr = (addr & ESP_MAXREG) >> 2; + DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); switch (saddr) { case 2: // FIFO @@ -278,11 +286,16 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) s->ti_wptr = 0; } break; + case 5: + // interrupt + // Clear status bits except TC + s->rregs[4] &= STAT_TC; + pic_set_irq(s->irq, 0); + s->espdmaregs[0] &= ~DMA_INTR; + break; default: break; } - DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); - return s->rregs[saddr]; } @@ -317,8 +330,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 1: DPRINTF("Flush FIFO (%2.2x)\n", val); - s->rregs[6] = 0; + //s->ti_size = 0; s->rregs[5] = INTR_FC; + s->rregs[6] = 0; break; case 2: DPRINTF("Chip reset (%2.2x)\n", val); @@ -326,6 +340,11 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 3: DPRINTF("Bus reset (%2.2x)\n", val); + s->rregs[5] = INTR_RST; + if (!(s->wregs[8] & 0x40)) { + s->espdmaregs[0] |= DMA_INTR; + pic_set_irq(s->irq, 1); + } break; case 0x10: handle_ti(s); @@ -362,7 +381,10 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 9 ... 10: break; - case 11 ... 15: + case 11: + s->rregs[saddr] = val & 0x15; + break; + case 12 ... 15: s->rregs[saddr] = val; break; default: @@ -403,7 +425,7 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val); switch (saddr) { case 0: - if (!(val & 0x10)) + if (!(val & DMA_INTREN)) pic_set_irq(s->irq, 0); if (val & 0x80) { esp_reset(s); diff --git a/pc-bios/proll.elf b/pc-bios/proll.elf index f6198f4d6..21c739cac 100644 Binary files a/pc-bios/proll.elf and b/pc-bios/proll.elf differ diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch index fb215a0c6..dbe01e432 100644 --- a/pc-bios/proll.patch +++ b/pc-bios/proll.patch @@ -1,6 +1,6 @@ -diff -ruN proll_18.orig/Makefile proll-patch10/Makefile +diff -ruN proll_18.orig/Makefile proll-patch-15/Makefile --- proll_18.orig/Makefile 2002-09-13 14:16:59.000000000 +0000 -+++ proll-patch10/Makefile 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/Makefile 2005-11-09 18:14:51.000000000 +0000 @@ -4,6 +4,7 @@ make -C krups-ser all make -C espresso all @@ -14,14 +14,14 @@ diff -ruN proll_18.orig/Makefile proll-patch10/Makefile make -C espresso clean make -C espresso-ser clean + make -C qemu clean -diff -ruN proll_18.orig/qemu/Makefile proll-patch10/qemu/Makefile +diff -ruN proll_18.orig/qemu/Makefile proll-patch-15/qemu/Makefile --- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/qemu/Makefile 2005-04-12 14:42:23.000000000 +0000 ++++ proll-patch-15/qemu/Makefile 2005-08-14 10:25:06.000000000 +0000 @@ -0,0 +1,123 @@ +# +# proll: +# qemu/Makefile - make PROLL for QEMU -+# $Id: proll.patch,v 1.5 2005-04-26 21:02:48 bellard Exp $ ++# $Id: proll.patch,v 1.6 2005-11-11 00:24:57 bellard Exp $ +# +# Copyright 1999 Pete Zaitcev +# This is Free Software is licensed under terms of GNU General Public License. @@ -55,8 +55,8 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch10/qemu/Makefile +# Fixed %g6 is for arch/sparc/kernel/head.S, it seems ok w/o -ffixed-g6. +# Kernel uses -fcall-used-g5 -fcall-used-g7, we probably do not need them. +# __ANSI__ is supposed to be on by default but it is not. -+CFLAGS = -O2 -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -g -DQEMU -+ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g ++CFLAGS = -O2 -W -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -Wa,-xarch=v8 -g -DQEMU -m32 -fno-builtin ++ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g -Wa,-xarch=v8 -Wa,-32 +# Solaris or Linux/i386 cross compilation +#CFLAGS = -Iinclude -O + @@ -141,17 +141,17 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch10/qemu/Makefile + +proll.aout: $(PROLLEXE) + $(ELFTOAOUT) -o proll.aout $(PROLLEXE) -diff -ruN proll_18.orig/qemu/head.S proll-patch10/qemu/head.S +diff -ruN proll_18.orig/qemu/head.S proll-patch-15/qemu/head.S --- proll_18.orig/qemu/head.S 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/qemu/head.S 2005-03-02 15:30:47.000000000 +0000 -@@ -0,0 +1,539 @@ ++++ proll-patch-15/qemu/head.S 2005-07-12 22:24:17.000000000 +0000 +@@ -0,0 +1,543 @@ +/** + ** Standalone startup code for Linux PROM emulator. + ** Copyright 1999 Pete A. Zaitcev + ** This code is licensed under GNU General Public License. + **/ +/* -+ * $Id: proll.patch,v 1.5 2005-04-26 21:02:48 bellard Exp $ ++ * $Id: proll.patch,v 1.6 2005-11-11 00:24:57 bellard Exp $ + */ + +#include @@ -443,6 +443,10 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch10/qemu/head.S +C_LABEL(bootup_user_stack): .skip 0x2000 + + .section ".text" ++ .register %g2, #scratch ++ .register %g3, #scratch ++ .register %g6, #scratch ++ .register %g7, #scratch + +goprol: + ! %g1 contains end of memory @@ -684,9 +688,9 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch10/qemu/head.S +C_LABEL(ldb_bypass): + retl + lduba [%o0] ASI_M_BYPASS, %o0 -diff -ruN proll_18.orig/qemu/main.c proll-patch10/qemu/main.c +diff -ruN proll_18.orig/qemu/main.c proll-patch-15/qemu/main.c --- proll_18.orig/qemu/main.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/qemu/main.c 2005-04-16 18:03:23.000000000 +0000 ++++ proll-patch-15/qemu/main.c 2005-08-14 10:07:48.000000000 +0000 @@ -0,0 +1,185 @@ +/** + ** Proll (PROM replacement) @@ -852,7 +856,7 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch10/qemu/main.c + +/* + */ -+void udelay(unsigned long usecs) ++void udelay(__attribute__((unused)) unsigned long usecs) +{ + // Qemu hardware is perfect and does not need any delays! +} @@ -873,10 +877,10 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch10/qemu/main.c + hw_idprom = va_prom; +} + -diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c +diff -ruN proll_18.orig/qemu/openprom.c proll-patch-15/qemu/openprom.c --- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/qemu/openprom.c 2005-04-16 17:30:19.000000000 +0000 -@@ -0,0 +1,741 @@ ++++ proll-patch-15/qemu/openprom.c 2005-11-07 20:11:04.000000000 +0000 +@@ -0,0 +1,910 @@ +/* + * PROM interface support + * Copyright 1996 The Australian National University. @@ -900,7 +904,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c +struct property { + const char *name; + const char *value; -+ const int length; ++ int length; +}; + +struct node { @@ -920,12 +924,13 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c +static const struct property null_properties = { NULL, NULL, -1 }; +static const int prop_true = -1; + -+static const struct property propv_root[] = { -+ {"name", "SUNW,JavaStation-1", sizeof("SUNW,JavaStation-1") }, ++static struct property propv_root[7]; ++ ++static const struct property propv_root_templ[] = { ++ {"name", "SUNW,SparcStation-5", sizeof("SUNW,SparcStation-5") }, + {"idprom", obp_idprom, IDPROM_SIZE}, -+ {"banner-name", "JavaStation", sizeof("JavaStation")}, ++ {"banner-name", "SparcStation", sizeof("SparcStation")}, + {"compatible", "sun4m", 6}, -+ {NULL, NULL, -1} +}; + +static const int prop_iommu_reg[] = { @@ -986,7 +991,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c +static const int height = 0x300; +static const int width = 0x400; +static const int linebytes = 0x400; -+static const int depth = 8; ++static const int depth = 24; +static const int tcx_intr[] = { 5, 0 }; +static const int tcx_interrupts = 5; +static const struct property propv_sbus_tcx[] = { @@ -1004,7 +1009,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + {"linebytes", (char*)&linebytes, sizeof(int)}, + {"depth", (char*)&depth, sizeof(int)}, + {"reg", (char*)&prop_tcx_regs[0], sizeof(prop_tcx_regs)}, -+ {"tcx-8-bit", (char*)&prop_true, 0}, ++ {"tcx-8-bit", 0, -1}, + {"intr", (char*)&tcx_intr[0], sizeof(tcx_intr)}, + {"interrupts", (char*)&tcx_interrupts, sizeof(tcx_interrupts)}, + {"device_type", "display", sizeof("display")}, @@ -1101,15 +1106,17 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c +static const int prop_zs_reg[] = { + 0x0, 0x00000000, 0x00000008, +}; -+static const int prop_zs_slave[] = { 1 }; +static void *prop_zs_addr; ++static const int prop_zs_slave = 1; +static const struct property propv_obio_zs[] = { + {"name", "zs", sizeof("zs")}, + {"reg", (char*)&prop_zs_reg[0], sizeof(prop_zs_reg) }, -+ {"slave", (char*)&prop_zs_slave[0], sizeof(prop_zs_slave) }, ++ {"slave", (char*)&prop_zs_slave, sizeof(prop_zs_slave) }, + {"device_type", "serial", sizeof("serial") }, + {"intr", (char*)&prop_zs_intr[0], sizeof(prop_zs_intr) }, + {"address", (char*)&prop_zs_addr, sizeof(prop_zs_addr) }, ++ {"keyboard", (char*)&prop_true, 0}, ++ {"mouse", (char*)&prop_true, 0}, + {NULL, NULL, -1} +}; + @@ -1118,11 +1125,11 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + 0x0, 0x00100000, 0x00000008, +}; +static void *prop_zs1_addr; -+static const int prop_zs1_slave[] = { 0 }; ++static const int prop_zs1_slave = 0; +static const struct property propv_obio_zs1[] = { + {"name", "zs", sizeof("zs")}, + {"reg", (char*)&prop_zs1_reg[0], sizeof(prop_zs1_reg) }, -+ {"slave", (char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) }, ++ {"slave", (char*)&prop_zs1_slave, sizeof(prop_zs1_slave) }, + {"device_type", "serial", sizeof("serial") }, + {"intr", (char*)&prop_zs1_intr[0], sizeof(prop_zs1_intr) }, + {"address", (char*)&prop_zs1_addr, sizeof(prop_zs1_addr) }, @@ -1185,6 +1192,15 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + {NULL, NULL, -1} +}; + ++static const int prop_apc_reg[] = { ++ 0x4, 0x0a000000, 0x00000010, ++}; ++static const struct property propv_sbus_apc[] = { ++ {"name", "xxxpower-management", sizeof("xxxpower-management")}, ++ {"reg", (char*)&prop_apc_reg[0], sizeof(prop_apc_reg) }, ++ {NULL, NULL, -1} ++}; ++ +static const int prop_fd_intr[] = { 0x2b, 0x0 }; +static const int prop_fd_reg[] = { + 0x0, 0x00400000, 0x0000000f, @@ -1221,41 +1237,62 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + {"name", "options", sizeof("options")}, + {"screen-#columns", "80", sizeof("80")}, + {"screen-#rows", "25", sizeof("25")}, -+ {"tpe-link-test?", "true", sizeof("true")}, ++ {"tpe-link-test?", (char *)&prop_true, 0}, + {"ttya-mode", "9600,8,n,1,-", sizeof("9600,8,n,1,-")}, -+ {"ttya-ignore-cd", "true", sizeof("true")}, -+ {"ttya-rts-dtr-off", "false", sizeof("false")}, ++ {"ttya-ignore-cd", (char *)&prop_true, 0}, ++ {"ttya-rts-dtr-off", 0, -1}, + {"ttyb-mode", "9600,8,n,1,-", sizeof("9600,8,n,1,-")}, -+ {"ttyb-ignore-cd", "true", sizeof("true")}, -+ {"ttyb-rts-dtr-off", "false", sizeof("false")}, ++ {"ttyb-ignore-cd", (char *)&prop_true, 0}, ++ {"ttyb-rts-dtr-off", 0, -1}, ++ {NULL, NULL, -1} ++}; ++ ++static int prop_mem_reg[3]; ++static int prop_mem_avail[3]; ++ ++static const struct property propv_memory[] = { ++ {"name", "memory", sizeof("memory")}, ++ {"reg", (char*)&prop_mem_reg[0], sizeof(prop_mem_reg) }, ++ {"available", (char*)&prop_mem_avail[0], sizeof(prop_mem_avail) }, ++ {NULL, NULL, -1} ++}; ++ ++static int prop_vmem_avail[6]; ++ ++static const struct property propv_vmemory[] = { ++ {"name", "virtual-memory", sizeof("virtual-memory")}, ++ {"available", (char*)&prop_vmem_avail[0], sizeof(prop_vmem_avail) }, + {NULL, NULL, -1} +}; + +static const struct node nodes[] = { + { &null_properties, 1, 0 }, /* 0 = big brother of root */ + { propv_root, 0, 2 }, /* 1 "/" */ -+ { propv_iommu, 11, 3 }, /* 2 "/iommu" */ ++ { propv_iommu, 12, 3 }, /* 2 "/iommu" */ + { propv_sbus, 0, 4 }, /* 3 "/iommu/sbus" */ + { propv_sbus_tcx, 5, 0 }, /* 4 "/iommu/sbus/SUNW,tcx" */ + { propv_sbus_ledma, 7, 6 }, /* 5 "/iommu/sbus/ledma" */ + { propv_sbus_ledma_le, 0, 0 }, /* 6 "/iommu/sbus/ledma/le" */ + { propv_sbus_cs4231, 8, 0 }, /* 7 "/iommu/sbus/SUNW,CS4231 */ + { propv_sbus_bpp, 9, 0 }, /* 8 "/iommu/sbus/SUNW,bpp */ -+ { propv_sbus_espdma, 0, 10 }, /* 9 "/iommu/sbus/espdma" */ ++ { propv_sbus_espdma, 11, 10 }, /* 9 "/iommu/sbus/espdma" */ + { propv_sbus_espdma_esp, 0, 0 }, /* 10 "/iommu/sbus/espdma/esp" */ -+ { propv_cpu, 12, 0 }, /* 11 "/STP1012PGA" */ -+ { propv_obio, 22, 13 }, /* 12 "/obio" */ -+ { propv_obio_int, 14, 0 }, /* 13 "/obio/interrupt" */ -+ { propv_obio_cnt, 15, 0 }, /* 14 "/obio/counter" */ -+ { propv_obio_eep, 16, 0 }, /* 15 "/obio/eeprom" */ -+ { propv_obio_auxio, 17, 0 }, /* 16 "/obio/auxio" */ -+ { propv_obio_zs1, 18, 0 }, /* 17 "/obio/zs@0,100000" ++ { propv_sbus_apc, 0, 0 }, /* 11 "/iommu/sbus/power-management */ ++ { propv_cpu, 13, 0 }, /* 12 "/STP1012PGA" */ ++ { propv_obio, 23, 14 }, /* 13 "/obio" */ ++ { propv_obio_int, 15, 0 }, /* 14 "/obio/interrupt" */ ++ { propv_obio_cnt, 16, 0 }, /* 15 "/obio/counter" */ ++ { propv_obio_eep, 17, 0 }, /* 16 "/obio/eeprom" */ ++ { propv_obio_auxio, 18, 0 }, /* 17 "/obio/auxio" */ ++ { propv_obio_zs1, 19, 0 }, /* 18 "/obio/zs@0,100000" + Must be before zs@0,0! */ -+ { propv_obio_zs, 19, 0 }, /* 18 "/obio/zs@0,0" */ -+ { propv_obio_fd, 20, 0 }, /* 19 "/obio/SUNW,fdtwo" */ -+ { propv_obio_pw, 21, 0 }, /* 20 "/obio/power" */ -+ { propv_obio_cf, 0, 0 }, /* 21 "/obio/slavioconfig@0,800000" */ -+ { propv_options, 0, 0 }, /* 22 "/options" */ ++ { propv_obio_zs, 20, 0 }, /* 19 "/obio/zs@0,0" */ ++ { propv_obio_fd, 21, 0 }, /* 20 "/obio/SUNW,fdtwo" */ ++ { propv_obio_pw, 22, 0 }, /* 21 "/obio/power" */ ++ { propv_obio_cf, 0, 0 }, /* 22 "/obio/slavioconfig@0,800000" */ ++ { propv_options, 24, 0 }, /* 23 "/options" */ ++ { propv_memory, 25, 0 }, /* 24 "/memory" */ ++ { propv_vmemory, 0, 0 }, /* 25 "/virtual-memory" */ +}; + +static struct linux_mlist_v0 totphys[MAX_BANKS]; @@ -1281,6 +1318,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + +static void (*synch_hook)(void); +static char obp_stdin, obp_stdout; ++static int obp_fd_stdin, obp_fd_stdout; + +static int obp_nbgetchar(void); +static int obp_nbputchar(int ch); @@ -1289,9 +1327,13 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c +static void obp_halt(void); +static int obp_devopen(char *str); +static int obp_devclose(int dev_desc); ++static int obp_devread(int dev_desc, char *buf, int nbytes); ++static int obp_devwrite(int dev_desc, char *buf, int nbytes); ++static int obp_devseek(int dev_desc, int hi, int lo); +static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf); +static char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size); +static void obp_dumb_munmap(char *va, unsigned int size); ++static int obp_inst2pkg(int dev_desc); + +static void doublewalk(unsigned ptab1, unsigned va) +{ @@ -1304,6 +1346,17 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + +static struct linux_romvec romvec0; + ++struct fd { ++ int unit, part; ++ int offset; ++ int (*pread)(int dev_desc, int offset, char *buf, unsigned int nbytes); ++ int (*pwrite)(int dev_desc, int offset, char *buf, unsigned int nbytes); ++} fd_table[16]; ++ ++static int fd_index; ++static int con_pread(int dev_desc, int offset, char *buf, unsigned int nbytes); ++static int con_pwrite(int dev_desc, int offset, char *buf, unsigned int nbytes); ++ +void * +init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, + const char *cmdline, char boot_device, int nographic) @@ -1345,6 +1398,18 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + totmap[0].theres_more = 0; + totmap[0].start_adr = (char*) PROLBASE; + totmap[0].num_bytes = PROLSIZE; ++ prop_mem_reg[0] = 0; ++ prop_mem_reg[1] = 0; ++ prop_mem_reg[2] = bankv[0].length; ++ prop_mem_avail[0] = 0; ++ prop_mem_avail[1] = 0; ++ prop_mem_avail[2] = hiphybas; ++ prop_vmem_avail[0] = 0; ++ prop_vmem_avail[1] = 0; ++ prop_vmem_avail[2] = PROLBASE-1; ++ prop_vmem_avail[3] = 0; ++ prop_vmem_avail[4] = 0xffe00000; ++ prop_vmem_avail[5] = 0x00200000; + + /* + * idprom @@ -1353,6 +1418,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + + // Linux wants a R/W romvec table + romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; ++ romvec0.pv_romvers = 3; + romvec0.pv_plugin_revision = 77; + romvec0.pv_printrev = 0x10203; + romvec0.pv_v0mem.v0_totphys = &ptphys; @@ -1375,10 +1441,17 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + romvec0.pv_halt = obp_halt; + romvec0.pv_synchook = &synch_hook; + romvec0.pv_v0bootargs = &obp_argp; ++ romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg; + romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap; + romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap; ++ romvec0.pv_v2devops.v2_dev_open = obp_devopen; ++ romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose; ++ romvec0.pv_v2devops.v2_dev_read = obp_devread; ++ romvec0.pv_v2devops.v2_dev_write = obp_devwrite; ++ romvec0.pv_v2devops.v2_dev_seek = obp_devseek; + obp_arg.boot_dev_ctrl = 0; + obp_arg.boot_dev_unit = '0'; ++ obp_arg.argv[0] = "sd(0,0,0):d"; + switch(boot_device) { + default: + case 'a': @@ -1388,9 +1461,9 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + break; + case 'd': + obp_arg.boot_dev_unit = '2'; ++ obp_arg.argv[0] = "sd(0,2,0):d"; + // Fall through + case 'c': -+ obp_arg.argv[0] = "sd()"; + obp_arg.boot_dev[0] = 's'; + obp_arg.boot_dev[1] = 'd'; + break; @@ -1401,13 +1474,39 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + break; + } + obp_arg.argv[1] = cmdline; -+ ++ romvec0.pv_v2bootargs.bootpath = &obp_arg.argv[0]; ++ romvec0.pv_v2bootargs.bootargs = &cmdline; ++ romvec0.pv_v2bootargs.fd_stdin = &obp_fd_stdin; ++ romvec0.pv_v2bootargs.fd_stdout = &obp_fd_stdout; ++ ++ bcopy(propv_root_templ, propv_root, sizeof(propv_root_templ)); ++ propv_root[4].name = "stdin-path"; ++ propv_root[5].name = "stdout-path"; ++ obp_fd_stdin = 0; ++ obp_fd_stdout = 1; ++ fd_table[0].pread = con_pread; ++ fd_table[0].pwrite = con_pwrite; ++ fd_table[1].pread = con_pread; ++ fd_table[1].pwrite = con_pwrite; ++ fd_index = 2; + if (nographic) { + obp_stdin = PROMDEV_TTYA; ++ propv_root[4].value = "/obio/zs@0,100000:a"; ++ propv_root[4].length = sizeof("/obio/zs@0,100000:a"); ++ fd_table[0].unit = 18; + obp_stdout = PROMDEV_TTYA; ++ propv_root[5].value = "/obio/zs@0,100000:a"; ++ propv_root[5].length = sizeof("/obio/zs@0,100000:a"); ++ fd_table[1].unit = 18; + } else { + obp_stdin = PROMDEV_KBD; ++ propv_root[4].value = "/obio/zs@0,0"; ++ propv_root[4].length = sizeof("/obio/zs@0,0"); ++ fd_table[0].unit = 19; + obp_stdout = PROMDEV_SCREEN; ++ propv_root[5].value = "/iommu/sbus/SUNW,tcx"; ++ propv_root[5].length = sizeof("/iommu/sbus/SUNW,tcx"); ++ fd_table[1].unit = 4; + } + prop_zs_addr = map_io(0x71000000, 8); + prop_zs1_addr = map_io(0x71100000, 8); @@ -1481,7 +1580,10 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + return -1; +} + -+static int obp_setprop(int node, char *name, char *value, int len) ++static int obp_setprop(__attribute__((unused)) int node, ++ __attribute__((unused)) char *name, ++ __attribute__((unused)) char *value, ++ __attribute__((unused)) int len) +{ +#ifdef DEBUG_OBP + printk("obp_setprop(%d, %s) = %s (%d)\n", node, name, value, len); @@ -1511,7 +1613,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c +#ifdef DEBUG_OBP + printk("obp_nextprop(%d, %s): not found\n", node, name); +#endif -+ return (const char *)-1; ++ return ""; +} + +extern int (*getch_fn)(struct vconterm *v); @@ -1527,21 +1629,60 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c +} + +static void obp_reboot(char *str) { -+ printk("rebooting (%s): not implemented, freezing\n", str); ++ printk("rebooting (%s)\n", str); ++ stb_bypass(0x71f00000, 1); + for (;;) {} +} + +static void obp_abort() { -+ printk("abort, freezing\n"); ++ printk("abort, power off\n"); ++ stb_bypass(0x71910000, 1); + for (;;) {} +} + +static void obp_halt() { -+ printk("halt, freezing\n"); ++ printk("halt, power off\n"); ++ stb_bypass(0x71910000, 1); + for (;;) {} +} ++ ++extern void *esp_read(int unit, int part, int offset, short len); ++ ++static int esp_pread(int dev_desc, int offset, char *buf, unsigned int nbytes) ++{ ++ unsigned int i; ++ void *src; ++ ++ for(i = 0; i < nbytes; i += 512) { ++ src = esp_read(fd_table[dev_desc].unit, fd_table[dev_desc].part, (offset + i) / 512, 512); ++ memcpy(&buf[i], src, 512); ++ } ++ return nbytes; ++} ++ ++static int con_pread(__attribute__((unused)) int dev_desc, __attribute__((unused)) int offset, char *buf, unsigned int nbytes) ++{ ++ unsigned int i; ++ ++ for(i = 0; i < nbytes; i ++) { ++ buf[i] = obp_nbgetchar(); ++ } ++ return nbytes; ++} ++ ++static int con_pwrite(__attribute__((unused)) int dev_desc, __attribute__((unused)) int offset, char *buf, unsigned int nbytes) ++{ ++ unsigned int i; ++ ++ for(i = 0; i < nbytes; i ++) { ++ obp_nbputchar(buf[i]); ++ } ++ return nbytes; ++} ++ +#define isnum(c) ((c >= '0') && (c < '9')) +#define ctoi(c) (c - '0') ++ +static int obp_devopen(char *str) { +#ifdef DEBUG_OBP + printk("obp_devopen(%s)\n", str); @@ -1557,39 +1698,32 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + else { + target = ctoi(str[5]) & 7; + } -+ return 's' + target; ++ fd_table[fd_index].unit = target; ++ fd_table[fd_index].part = str[10] - 'a'; ++ fd_table[fd_index].pread = esp_pread; ++ return fd_index++; // XXX + } + return 0; +} + -+static int obp_devclose(int dev_desc) { ++static int obp_devclose(__attribute__((unused)) int dev_desc) { +#ifdef DEBUG_OBP + printk("obp_devclose %d\n", dev_desc); +#endif ++ fd_index--; // XXX + return 0; +} + -+extern void *esp_read(int unit, int offset, short len); -+ +static int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf) +{ -+ unsigned int i; -+ void *src; -+ +#ifdef DEBUG_OBP + printk("obp_rdblkdev: fd %d, num_blks %d, offset %d, buf 0x%x\n", dev_desc, num_blks, offset, buf); +#endif -+ if (dev_desc >= 's' && dev_desc < 'v') { -+ for(i = 0; i < num_blks; i++) { -+ src = esp_read(dev_desc - 's', offset + i, 1); -+ memcpy(&buf[i << 9], src, 512); -+ } -+ return num_blks; -+ } -+ return -1; ++ return fd_table[dev_desc].pread(dev_desc, offset, buf, num_blks * 512); +} + -+static char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size) ++static char *obp_dumb_mmap(char *va, __attribute__((unused)) int which_io, ++ unsigned int pa, unsigned int size) +{ + unsigned int npages; + unsigned int off; @@ -1611,16 +1745,55 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c + return va; +} + -+static void obp_dumb_munmap(char *va, unsigned int size) ++static void obp_dumb_munmap(__attribute__((unused)) char *va, ++ __attribute__((unused)) unsigned int size) +{ +#ifdef DEBUG_OBP + printk("obp_dumb_munmap: virta %x, sz %d\n", va, size); +#endif -+ +} -diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch10/qemu/system_qemu.c ++ ++static int obp_devread(int dev_desc, char *buf, int nbytes) ++{ ++ int ret; ++#ifdef DEBUG_OBP ++ printk("obp_devread: fd %d, nbytes %d\n", dev_desc, nbytes); ++#endif ++ ret = fd_table[dev_desc].pread(dev_desc, fd_table[dev_desc].offset, buf, nbytes); ++ fd_table[dev_desc].offset += nbytes; ++ return ret; ++} ++ ++static int obp_devwrite(int dev_desc, char *buf, int nbytes) ++{ ++ int ret; ++#ifdef DEBUG_OBP ++ printk("obp_devwrite: fd %d, buf %s, nbytes %d\n", dev_desc, buf, nbytes); ++#endif ++ ret = fd_table[dev_desc].pwrite(dev_desc, fd_table[dev_desc].offset, buf, nbytes); ++ fd_table[dev_desc].offset += nbytes; ++ return ret; ++} ++ ++static int obp_devseek(int dev_desc, __attribute__((unused)) int hi, int lo) ++{ ++#ifdef DEBUG_OBP ++ printk("obp_devseek: fd %d, hi %d, lo %d\n", dev_desc, hi, lo); ++#endif ++ fd_table[dev_desc].offset = lo; ++ return 0; ++} ++ ++static int obp_inst2pkg(int dev_desc) ++{ ++#ifdef DEBUG_OBP ++ printk("obp_inst2pkg: fd %d\n", dev_desc); ++#endif ++ return fd_table[dev_desc].unit; ++} +diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch-15/qemu/system_qemu.c --- proll_18.orig/qemu/system_qemu.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/qemu/system_qemu.c 2005-04-16 06:16:20.000000000 +0000 ++++ proll-patch-15/qemu/system_qemu.c 2005-04-16 06:16:20.000000000 +0000 @@ -0,0 +1,430 @@ +/** + ** Proll (PROM replacement) @@ -2052,9 +2225,9 @@ diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch10/qemu/system_qemu.c + n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); + st_bypass(ptr, n); +}; -diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c +diff -ruN proll_18.orig/src/arp.c proll-patch-15/src/arp.c --- proll_18.orig/src/arp.c 2001-12-24 05:12:31.000000000 +0000 -+++ proll-patch10/src/arp.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/arp.c 2005-08-14 10:10:11.000000000 +0000 @@ -45,7 +45,7 @@ #endif static struct arp_cache arp_list[ARPNUM]; /* ARP address cache */ @@ -2064,7 +2237,19 @@ diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c -@@ -144,7 +144,7 @@ +@@ -100,10 +100,7 @@ + * + * ARP receiver routine + */ +-static int arp_recv(buf, bufsize, addr) +-unsigned char *buf; +-int bufsize; +-unsigned char *addr; ++static int arp_recv(unsigned char *buf, unsigned int bufsize, unsigned char *addr) + { + register struct arphdr *ahp = (struct arphdr *)buf; + +@@ -144,7 +141,7 @@ * * Resolve IP address and return pointer to hardware address. */ @@ -2073,7 +2258,7 @@ diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c t_ipaddr ip; { int i; -@@ -230,14 +230,11 @@ +@@ -230,14 +227,11 @@ */ int init_arp() { @@ -2089,9 +2274,9 @@ diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c + def_gw = IP_ANY; return(TRUE); } -diff -ruN proll_18.orig/src/arp.h proll-patch10/src/arp.h +diff -ruN proll_18.orig/src/arp.h proll-patch-15/src/arp.h --- proll_18.orig/src/arp.h 1999-03-18 03:39:43.000000000 +0000 -+++ proll-patch10/src/arp.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/arp.h 2004-11-13 15:50:49.000000000 +0000 @@ -104,7 +104,7 @@ extern int init_arp __P((void)); @@ -2101,10 +2286,22 @@ diff -ruN proll_18.orig/src/arp.h proll-patch10/src/arp.h /* Add a new antry to the ARP cache */ extern void addcache __P((unsigned char *ha, t_ipaddr ip)); -diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c +diff -ruN proll_18.orig/src/bootp.c proll-patch-15/src/bootp.c +--- proll_18.orig/src/bootp.c 1999-12-15 17:20:30.000000000 +0000 ++++ proll-patch-15/src/bootp.c 2005-08-14 10:16:09.000000000 +0000 +@@ -151,7 +151,7 @@ + while (TRUE) { + boot_xid = get_ticks() + random(); + bootp_send(); +- i = udp_read((char *)(&boot_rec), BOOTP_REC_SIZE, timeout, CHR_ESC); ++ i = udp_read((char *)(&boot_rec), BOOTP_REC_SIZE, timeout); + if (i < 0) { /* user pressed ESC */ + printf("\nAborted\n"); + return(1); +diff -ruN proll_18.orig/src/esp.c proll-patch-15/src/esp.c --- proll_18.orig/src/esp.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/src/esp.c 2005-04-16 06:24:23.000000000 +0000 -@@ -0,0 +1,252 @@ ++++ proll-patch-15/src/esp.c 2005-08-15 18:42:46.000000000 +0000 +@@ -0,0 +1,305 @@ +#include /* == */ +#include /* __P for netpriv.h */ +#include /* dmaga */ @@ -2138,6 +2335,10 @@ diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c + struct esp_dma *espdma; /* If set this points to espdma */ + + unsigned char *buffer; ++ struct disk_info { ++ unsigned int hw_sector; ++ unsigned int part_offset[8]; ++ } disk[8]; +}; + +static void esp_interrupt(void *dev_id) @@ -2260,7 +2461,7 @@ diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c + return; +} + -+void *esp_read(int unit, int offset, short len) ++void esp_read_capacity(int unit) +{ + // Set SCSI target + stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7); @@ -2271,28 +2472,74 @@ diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c + stb_bypass(PHYS_JJ_ESP + 1*4, 0); + // Set DMA direction + st_bypass(PHYS_JJ_ESPDMA + 0, 0x000); ++ // Setup command = Read Capacity ++ esp.buffer[0] = 0x80; ++ esp.buffer[1] = 0x25; ++ esp.buffer[2] = 0x00; ++ esp.buffer[3] = 0x00; ++ esp.buffer[4] = 0x00; ++ esp.buffer[5] = 0x00; ++ esp.buffer[6] = 0x00; ++ esp.buffer[7] = 0x00; ++ esp.buffer[8] = 0x00; ++ esp.buffer[9] = 0x00; ++ esp.buffer[10] = 0x00; ++ // Set ATN, issue command ++ stb_bypass(PHYS_JJ_ESP + 3*4, 0xc2); ++ ++ // Set DMA length = 512 * read length ++ stb_bypass(PHYS_JJ_ESP + 0*4, 0); ++ stb_bypass(PHYS_JJ_ESP + 1*4, 8 & 0xff); ++ // Set DMA direction ++ st_bypass(PHYS_JJ_ESPDMA + 0, 0x100); ++ // Transfer ++ stb_bypass(PHYS_JJ_ESP + 3*4, 0x90); ++ esp.disk[unit].hw_sector = (esp.buffer[4] << 24) | (esp.buffer[5] << 16) | (esp.buffer[6] << 8) | esp.buffer[7]; ++} ++ ++// offset is multiple of 512, len in bytes ++void *esp_read(int unit, int part, int offset, short len) ++{ ++ int pos, hw_sect, sect_offset, spb; ++ ++ // Set SCSI target ++ stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7); ++ // Set DMA address ++ st_bypass(PHYS_JJ_ESPDMA + 4, esp.buffer_dvma); ++ // Set DMA length ++ stb_bypass(PHYS_JJ_ESP + 0*4, 10); ++ stb_bypass(PHYS_JJ_ESP + 1*4, 0); ++ // Set DMA direction ++ st_bypass(PHYS_JJ_ESPDMA + 0, 0x000); ++ hw_sect = esp.disk[unit].hw_sector; ++ offset += esp.disk[unit].part_offset[part]; ++ spb = hw_sect / 512; ++ sect_offset = offset / spb; ++ pos = (offset - sect_offset * spb) * 512; ++ len /= 512; ++ //printk("Read unit %d, offset %d -> offset %d, pos %d, hw_sect %d\n", unit, offset, sect_offset, pos, hw_sect); + // Setup command = Read(10) + esp.buffer[0] = 0x80; + esp.buffer[1] = 0x28; + esp.buffer[2] = 0x00; -+ esp.buffer[3] = (offset >> 24) & 0xff; -+ esp.buffer[4] = (offset >> 16) & 0xff; -+ esp.buffer[5] = (offset >> 8) & 0xff; -+ esp.buffer[6] = offset & 0xff; ++ esp.buffer[3] = (sect_offset >> 24) & 0xff; ++ esp.buffer[4] = (sect_offset >> 16) & 0xff; ++ esp.buffer[5] = (sect_offset >> 8) & 0xff; ++ esp.buffer[6] = sect_offset & 0xff; + esp.buffer[7] = 0x00; + esp.buffer[8] = (len >> 8) & 0xff; + esp.buffer[9] = len & 0xff; + // Set ATN, issue command -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0x42); ++ stb_bypass(PHYS_JJ_ESP + 3*4, 0xc2); + -+ // Set DMA length = 512 * read length -+ stb_bypass(PHYS_JJ_ESP + 0*4, 0); -+ stb_bypass(PHYS_JJ_ESP + 1*4, (len << 1) & 0xff); ++ // Set DMA length = sector size * read length ++ stb_bypass(PHYS_JJ_ESP + 0*4, (len * hw_sect) & 0xff); ++ stb_bypass(PHYS_JJ_ESP + 1*4, ((len * hw_sect) >> 8) & 0xff); + // Set DMA direction + st_bypass(PHYS_JJ_ESPDMA + 0, 0x100); + // Transfer -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0x10); -+ return esp.buffer; ++ stb_bypass(PHYS_JJ_ESP + 3*4, 0x90); ++ return esp.buffer + pos; +} + +// Sparc boot sequence can be found in SILO docs, @@ -2334,32 +2581,35 @@ diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c + stb_bypass(PHYS_JJ_ESP + 3*4, 2); + + esp_open(&esp); ++ esp_read_capacity(unit); + -+ label = esp_read(unit, 0, 1); -+ printk("CHS: %d/%d/%d, partitions:\n", label->ncyl, label->ntrks, label->nsect); ++ label = esp_read(unit, 0, 0, 512); ++ printk("hw sector: %d, CHS: %d/%d/%d, partitions:\n", esp.disk[unit].hw_sector, ++ label->ncyl, label->ntrks, label->nsect); + for (i = 0; i < 8; i++) { -+ printk("%c: %d + %d\n", 'a' + i, label->partitions[i].start_cylinder, -+ label->partitions[i].num_sectors); ++ printk("%c: %d + %d, id %x, flags %x\n", 'a' + i, label->partitions[i].start_cylinder, ++ label->partitions[i].num_sectors, label->infos[i].id, label->infos[i].flags); ++ esp.disk[unit].part_offset[i] = label->partitions[3].start_cylinder * label->ntrks * label->nsect; + } -+ offset = label->partitions[4].start_cylinder * label->ntrks * label->nsect + 1; ++ offset = 1; + printk("booting sd(0,%d,0):d (offset %d)\n", unit, offset); + // Skip a.out header (0x20) + dst = (void *)0x4000; -+ src = esp_read(unit, offset, 1); ++ src = esp_read(unit, 3, offset, 512); + src = (void *)((unsigned int) src + 0x20); + memcpy(dst, src, 512 - 0x20); + dst = (void *)0x4000 + 512 - 0x20; + for (i = 1; i < 7680/512; i++) { -+ src = esp_read(unit, offset + i, 1); ++ src = esp_read(unit, 3, offset + i, 512); + memcpy(dst, src, 512); + dst += 512; + } + esp_close(&esp); + return 0; +} -diff -ruN proll_18.orig/src/hconsole.c proll-patch10/src/hconsole.c +diff -ruN proll_18.orig/src/hconsole.c proll-patch-15/src/hconsole.c --- proll_18.orig/src/hconsole.c 2002-07-23 05:52:48.000000000 +0000 -+++ proll-patch10/src/hconsole.c 2005-03-02 17:03:09.000000000 +0000 ++++ proll-patch-15/src/hconsole.c 2005-11-09 18:46:34.000000000 +0000 @@ -29,6 +29,10 @@ struct raster r_master; /* For a case of resize, whole fb */ struct raster r_0; /* malloc() erzatz */ @@ -2383,9 +2633,84 @@ diff -ruN proll_18.orig/src/hconsole.c proll-patch10/src/hconsole.c t->r_ = r; t->r0_ = q; t->f_ = &f_master; -diff -ruN proll_18.orig/src/hme.c proll-patch10/src/hme.c +@@ -67,7 +75,7 @@ + return 0; + } + +-void hcon_fini (struct hconsole *t) ++void hcon_fini (__attribute((unused)) struct hconsole *t) + { + return; + } +@@ -77,12 +85,12 @@ + { + struct rfont *f = t->f_; + +- if (sy < 0 || sy >= t->ydim_) return -1; +- if (sx < 0 || sx >= t->xdim_) return -1; ++ if (sy < 0 || (unsigned)sy >= t->ydim_) return -1; ++ if (sx < 0 || (unsigned)sx >= t->xdim_) return -1; + if (height < 0) return -1; +- if (sy + height > t->ydim_) height = t->ydim_ - sy; ++ if ((unsigned)sy + (unsigned)height > t->ydim_) height = t->ydim_ - sy; + if (width < 0) return -1; +- if (sx + width > t->xdim_) width = t->xdim_ - sx; ++ if ((unsigned)sx + (unsigned)width > t->xdim_) width = t->xdim_ - sx; + + /* XXX Clear with correct background color */ + (*t->r_->clear_)(t->r_, +@@ -107,10 +115,10 @@ + char c0 = c; + RC_color rfg, rbg; + +- if (y < 0 || y >= t->ydim_) return -1; +- if (x < 0 || x >= t->xdim_) return -1; ++ if (y < 0 || (unsigned)y >= t->ydim_) return -1; ++ if (x < 0 || (unsigned)x >= t->xdim_) return -1; + +- if (t->curson_ && t->ypos_ == y && t->xpos_ == x) { ++ if (t->curson_ && t->ypos_ == (unsigned)y && t->xpos_ == (unsigned)x) { + rfg = t->bg_; rbg = t->fg_; + } else { + rfg = t->fg_; rbg = t->bg_; +@@ -126,9 +134,9 @@ + { + struct rfont *f = t->f_; + +- if (y < 0 || y >= t->ydim_) return -1; +- if (x < 0 || x >= t->xdim_) return -1; +- if (x + count >= t->xdim_) count = t->xdim_ - x; ++ if (y < 0 || (unsigned)y >= t->ydim_) return -1; ++ if (x < 0 || (unsigned)x >= t->xdim_) return -1; ++ if ((unsigned)x + (unsigned)count >= t->xdim_) count = t->xdim_ - x; + + (*t->r_->render_)(t->r_, y*f->height_, x*f->width_, + s, count, t->bg_, t->fg_, f); +@@ -200,8 +208,8 @@ + + rc = 0; + if (dir == SM_UP) { +- if (d < 0 || d >= t->ydim_) return -1; +- if (b <= d || b > t->ydim_) return -1; ++ if (d < 0 || (unsigned)d >= t->ydim_) return -1; ++ if (b <= d || (unsigned)b > t->ydim_) return -1; + if (d + count >= b) count = b - d; + if (d + count >= b) count = b - d; + (*t->r_->yscroll_)(t->r_, +@@ -213,8 +221,8 @@ + count*f->height_, raster_qwidth(t->r_), + t->bg_); + } else if (dir == SM_DOWN) { +- if (d < 0 || d >= t->ydim_) return -1; +- if (b <= d || b > t->ydim_) return -1; ++ if (d < 0 || (unsigned)d >= t->ydim_) return -1; ++ if (b <= d || (unsigned)b > t->ydim_) return -1; + if (d + count >= b) count = b - d; + (*t->r_->yscroll_)(t->r_, + d*f->height_, 0, +diff -ruN proll_18.orig/src/hme.c proll-patch-15/src/hme.c --- proll_18.orig/src/hme.c 2002-07-23 05:52:52.000000000 +0000 -+++ proll-patch10/src/hme.c 2005-04-16 06:16:20.000000000 +0000 ++++ proll-patch-15/src/hme.c 2005-04-16 06:16:20.000000000 +0000 @@ -655,10 +655,10 @@ unsigned int flags, unsigned int addr) @@ -2443,9 +2768,21 @@ diff -ruN proll_18.orig/src/hme.c proll-patch10/src/hme.c : "=r" (flags) : "r" (&this->rx_flags), "i" (ASI_PL)); #else -diff -ruN proll_18.orig/src/lat7_2.bm proll-patch10/src/lat7_2.bm +diff -ruN proll_18.orig/src/iommu.c proll-patch-15/src/iommu.c +--- proll_18.orig/src/iommu.c 2002-07-23 05:52:49.000000000 +0000 ++++ proll-patch-15/src/iommu.c 2005-08-14 10:08:17.000000000 +0000 +@@ -36,7 +36,7 @@ + unsigned int pa, ba; + unsigned int npages; + unsigned int mva, mpa; +- int i; ++ unsigned int i; + unsigned int *iopte; + + npages = (size + (PAGE_SIZE-1)) / PAGE_SIZE; +diff -ruN proll_18.orig/src/lat7_2.bm proll-patch-15/src/lat7_2.bm --- proll_18.orig/src/lat7_2.bm 1999-02-27 05:48:54.000000000 +0000 -+++ proll-patch10/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 @@ -1,6 +1,6 @@ #define lat7_2_width 128 #define lat7_2_height 88 @@ -2454,9 +2791,9 @@ diff -ruN proll_18.orig/src/lat7_2.bm proll-patch10/src/lat7_2.bm 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18, 0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02, -diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch10/src/lat7_2_swapped.bm +diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch-15/src/lat7_2_swapped.bm --- proll_18.orig/src/lat7_2_swapped.bm 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 @@ -0,0 +1,121 @@ +#define lat7_2_width 128 +#define lat7_2_height 88 @@ -2579,9 +2916,9 @@ diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch10/src/lat7_2_swapped.b + 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; -diff -ruN proll_18.orig/src/le.c proll-patch10/src/le.c +diff -ruN proll_18.orig/src/le.c proll-patch-15/src/le.c --- proll_18.orig/src/le.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch10/src/le.c 2005-04-16 06:16:20.000000000 +0000 ++++ proll-patch-15/src/le.c 2005-04-16 06:16:20.000000000 +0000 @@ -185,8 +185,6 @@ unsigned short rap; /* register address port */ }; @@ -2600,9 +2937,21 @@ diff -ruN proll_18.orig/src/le.c proll-patch10/src/le.c /* Now, give the packet to the lance */ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); -diff -ruN proll_18.orig/src/netinit.c proll-patch10/src/netinit.c +diff -ruN proll_18.orig/src/net.h proll-patch-15/src/net.h +--- proll_18.orig/src/net.h 1999-12-15 17:20:17.000000000 +0000 ++++ proll-patch-15/src/net.h 2005-08-14 10:17:02.000000000 +0000 +@@ -124,7 +124,7 @@ + extern int udp_open __P((t_ipaddr daddr, int source, int dest)); + + /* Read from a UDP socket */ +-extern int udp_read __P((char *buf, int bufsize, int timeout, char abortch)); ++extern int udp_read(char *buf, unsigned int bufsize, int timeout); + + /* Write to a UDP socket */ + extern int udp_write __P((char *buf, int writelen)); +diff -ruN proll_18.orig/src/netinit.c proll-patch-15/src/netinit.c --- proll_18.orig/src/netinit.c 2002-09-13 21:53:33.000000000 +0000 -+++ proll-patch10/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 @@ -49,13 +49,20 @@ unsigned char myhwaddr[ETH_ALEN]; /* my own hardware addr */ t_ipaddr myipaddr; /* my own IP address */ @@ -2646,9 +2995,18 @@ diff -ruN proll_18.orig/src/netinit.c proll-patch10/src/netinit.c fatal(); } } -diff -ruN proll_18.orig/src/netpriv.h proll-patch10/src/netpriv.h +diff -ruN proll_18.orig/src/netpriv.h proll-patch-15/src/netpriv.h --- proll_18.orig/src/netpriv.h 1999-04-27 05:39:37.000000000 +0000 -+++ proll-patch10/src/netpriv.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/netpriv.h 2005-08-14 10:12:20.000000000 +0000 +@@ -83,7 +83,7 @@ + */ + struct device *dev; + char *data; +- int len; ++ unsigned int len; + int protocol; + unsigned char ip_summed; + }; @@ -130,10 +130,9 @@ * */ @@ -2670,10 +3028,10 @@ diff -ruN proll_18.orig/src/netpriv.h proll-patch10/src/netpriv.h /* Empty read buffer */ extern void empty_buf __P((void)); -diff -ruN proll_18.orig/src/openprom.h proll-patch10/src/openprom.h +diff -ruN proll_18.orig/src/openprom.h proll-patch-15/src/openprom.h --- proll_18.orig/src/openprom.h 2002-07-14 02:26:30.000000000 +0000 -+++ proll-patch10/src/openprom.h 2004-11-13 15:50:49.000000000 +0000 -@@ -54,20 +54,20 @@ ++++ proll-patch-15/src/openprom.h 2005-05-13 16:23:14.000000000 +0000 +@@ -54,29 +54,29 @@ }; struct linux_mem_v0 { @@ -2699,6 +3057,19 @@ diff -ruN proll_18.orig/src/openprom.h proll-patch10/src/openprom.h void *aieee1; /* XXX */ }; + /* V2 and up boot things. */ + struct linux_bootargs_v2 { +- char **bootpath; +- char **bootargs; +- int *fd_stdin; +- int *fd_stdout; ++ const char **bootpath; ++ const char **bootargs; ++ const int *fd_stdin; ++ const int *fd_stdout; + }; + + /* The top level PROM vector. */ @@ -91,13 +91,13 @@ struct linux_mem_v0 pv_v0mem; @@ -2734,9 +3105,9 @@ diff -ruN proll_18.orig/src/openprom.h proll-patch10/src/openprom.h }; /* More fun PROM structures for device probing. */ -diff -ruN proll_18.orig/src/packet.c proll-patch10/src/packet.c +diff -ruN proll_18.orig/src/packet.c proll-patch-15/src/packet.c --- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000 -+++ proll-patch10/src/packet.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/packet.c 2005-08-14 10:12:49.000000000 +0000 @@ -41,7 +41,7 @@ int aligner; } wbuf; @@ -2764,9 +3135,24 @@ diff -ruN proll_18.orig/src/packet.c proll-patch10/src/packet.c { struct sk_buff *skb; unsigned char *s; -diff -ruN proll_18.orig/src/printf.c proll-patch10/src/printf.c +@@ -209,12 +211,12 @@ + /* + */ + void +-eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int len, int base) ++eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int len, __attribute__((unused)) int base) + { + bcopy(src, dest->data, len); + } + +-unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) ++unsigned short eth_type_trans(struct sk_buff *skb, __attribute__((unused)) struct device *dev) + { + unsigned char *s = skb->data + 12; + return s[0] << 8 | s[1]; /* Network order word */ +diff -ruN proll_18.orig/src/printf.c proll-patch-15/src/printf.c --- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000 -+++ proll-patch10/src/printf.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/printf.c 2005-08-14 10:07:26.000000000 +0000 @@ -19,7 +19,7 @@ static void printn(struct prf_fp *, unsigned long, unsigned int); static void putchar(char, struct prf_fp *); @@ -2794,9 +3180,20 @@ diff -ruN proll_18.orig/src/printf.c proll-patch10/src/printf.c putchar(c,filog); } else if (c == 'l' || c == 'O') { printn(filog, (long)va_arg(adx,long), c=='l'?10:8); -diff -ruN proll_18.orig/src/rconsole.c proll-patch10/src/rconsole.c +@@ -77,10 +77,6 @@ + char prbuf[24]; + register char *cp; + +- if (b == 10 && n < 0) { +- putchar('-',filog); +- n = (~n) + 1; /* n = -n */ +- } + cp = prbuf; + do + *cp++ = hextab[(unsigned int)(n%b)]; +diff -ruN proll_18.orig/src/rconsole.c proll-patch-15/src/rconsole.c --- proll_18.orig/src/rconsole.c 1999-01-16 07:16:55.000000000 +0000 -+++ proll-patch10/src/rconsole.c 2005-04-16 06:16:20.000000000 +0000 ++++ proll-patch-15/src/rconsole.c 2005-08-14 10:25:53.000000000 +0000 @@ -28,12 +28,18 @@ * move to California. Only plain lat7 survived. * I recreated lat7-1 changes in lat7-2. --zaitcev @@ -2882,9 +3279,18 @@ diff -ruN proll_18.orig/src/rconsole.c proll-patch10/src/rconsole.c p->nchars_ = LAT7_NCHARS; p->width_ = LAT7_WIDTH; p->height_ = LAT7_HEIGHT; -diff -ruN proll_18.orig/src/rconsole.h proll-patch10/src/rconsole.h +@@ -175,7 +188,7 @@ + r->render_ = p->render_; + } + +-void raster_dest(struct raster *r) ++void raster_dest(__attribute((unused)) struct raster *r) + { + } + +diff -ruN proll_18.orig/src/rconsole.h proll-patch-15/src/rconsole.h --- proll_18.orig/src/rconsole.h 1999-01-16 05:00:59.000000000 +0000 -+++ proll-patch10/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 @@ -13,10 +13,10 @@ */ @@ -2898,9 +3304,9 @@ diff -ruN proll_18.orig/src/rconsole.h proll-patch10/src/rconsole.h int nchars_; /* 128 for ASCII ... 65536 for Unicode */ int width_; /* [Pixels]. Maximum size is 16. */ int height_; /* [Pixels == scan lines]. */ -diff -ruN proll_18.orig/src/romlib.h proll-patch10/src/romlib.h +diff -ruN proll_18.orig/src/romlib.h proll-patch-15/src/romlib.h --- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000 -+++ proll-patch10/src/romlib.h 2005-04-16 20:32:49.000000000 +0000 ++++ proll-patch-15/src/romlib.h 2005-04-16 20:32:49.000000000 +0000 @@ -72,13 +72,13 @@ */ #define memcpy(dst, src, len) bcopy(src, dst, len) @@ -2920,9 +3326,9 @@ diff -ruN proll_18.orig/src/romlib.h proll-patch10/src/romlib.h /* -diff -ruN proll_18.orig/src/sched_4m.c proll-patch10/src/sched_4m.c +diff -ruN proll_18.orig/src/sched_4m.c proll-patch-15/src/sched_4m.c --- proll_18.orig/src/sched_4m.c 1999-04-27 05:48:51.000000000 +0000 -+++ proll-patch10/src/sched_4m.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/sched_4m.c 2005-08-14 10:18:14.000000000 +0000 @@ -108,7 +108,7 @@ static int set_bolt; /* Tick counter limit */ static struct handsc hndv[16]; @@ -2932,9 +3338,36 @@ diff -ruN proll_18.orig/src/sched_4m.c proll-patch10/src/sched_4m.c 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -diff -ruN proll_18.orig/src/swap.c proll-patch10/src/swap.c +@@ -130,7 +130,7 @@ + int /* 0 - not expired yet; <>0 - timer expired */ + chk_timeout() + { +- int lim = (((1000000/HZ) + 1) << 10); ++ unsigned int lim = (((1000000/HZ) + 1) << 10); + unsigned int clear; + unsigned int intc; + int n; +@@ -182,7 +182,7 @@ + struct handsc *hndp; + unsigned int mask; + +- if (irq < 0 || irq >= 16) { ++ if (irq == 0 || irq >= 16) { + printk("request_irq: bad irq %d\n", irq); + return -1; + } +@@ -207,7 +207,7 @@ + { + struct handsc *hndp; + +- if (irq < 0 || irq >= 16) { ++ if (irq == 0 || irq >= 16) { + printk("free_irq: bad irq %d\n", irq); + return; + } +diff -ruN proll_18.orig/src/swap.c proll-patch-15/src/swap.c --- proll_18.orig/src/swap.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/src/swap.c 2004-11-13 15:50:49.000000000 +0000 ++++ proll-patch-15/src/swap.c 2004-11-13 15:50:49.000000000 +0000 @@ -0,0 +1,21 @@ +// Convert the lat7 font so that no conversion is needed at runtime. +#define ORIG @@ -2957,9 +3390,9 @@ diff -ruN proll_18.orig/src/swap.c proll-patch10/src/swap.c + } + printf("\n"); +} -diff -ruN proll_18.orig/src/system.c proll-patch10/src/system.c +diff -ruN proll_18.orig/src/system.c proll-patch-15/src/system.c --- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch10/src/system.c 2005-04-16 06:16:20.000000000 +0000 ++++ proll-patch-15/src/system.c 2005-04-16 06:16:20.000000000 +0000 @@ -298,8 +298,8 @@ } @@ -3050,9 +3483,9 @@ diff -ruN proll_18.orig/src/system.c proll-patch10/src/system.c void fatal() { printk("fatal."); -diff -ruN proll_18.orig/src/system.h proll-patch10/src/system.h +diff -ruN proll_18.orig/src/system.h proll-patch-15/src/system.h --- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000 -+++ proll-patch10/src/system.h 2005-04-16 06:16:20.000000000 +0000 ++++ proll-patch-15/src/system.h 2005-04-16 06:16:20.000000000 +0000 @@ -16,7 +16,7 @@ #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */ #define NCTX_SWIFT 0x100 @@ -3171,19 +3604,72 @@ diff -ruN proll_18.orig/src/system.h proll-patch10/src/system.h : "i" (PSR_PIL) : "g1", "memory"); -diff -ruN proll_18.orig/src/udp.c proll-patch10/src/udp.c +diff -ruN proll_18.orig/src/tftp.c proll-patch-15/src/tftp.c +--- proll_18.orig/src/tftp.c 2002-09-13 21:53:34.000000000 +0000 ++++ proll-patch-15/src/tftp.c 2005-08-14 10:16:15.000000000 +0000 +@@ -127,7 +127,7 @@ + int len; + + /* Read packet with timeout */ +- len = udp_read((char *)(&inpbuf), sizeof(inpbuf), TFTP_TIMEOUT, CHR_ESC); ++ len = udp_read((char *)(&inpbuf), sizeof(inpbuf), TFTP_TIMEOUT); + if (len == 0) { + printf("TFTP: Timeout\n"); + return(ERR_TIMEOUT); +diff -ruN proll_18.orig/src/udp.c proll-patch-15/src/udp.c --- proll_18.orig/src/udp.c 2001-12-24 05:12:53.000000000 +0000 -+++ proll-patch10/src/udp.c 2004-11-13 15:50:49.000000000 +0000 -@@ -81,7 +81,7 @@ - int source; - int dest; ++++ proll-patch-15/src/udp.c 2005-08-14 10:17:19.000000000 +0000 +@@ -76,12 +76,9 @@ + * + * Open a new UDP socket. + */ +-int udp_open(daddr, source, dest) +-t_ipaddr daddr; +-int source; +-int dest; ++int udp_open(t_ipaddr daddr, int source, int dest) { - register unsigned char *addr; -+ const register unsigned char *addr; ++ const unsigned char *addr; /* Set global variables */ usource = source; -@@ -299,9 +299,6 @@ +@@ -101,16 +98,13 @@ + * + * IP receiver routine + */ +-static int ip_recv(buf, bufsize, addr) +-unsigned char *buf; +-int bufsize; +-unsigned char *addr; ++static int ip_recv(unsigned char *buf, unsigned int bufsize, unsigned char *addr) + { + struct iphdr *ipp = ((struct iphdr *)buf); + struct udphdr *udpp = ((struct udphdr *)(buf + IP_MIN_HSIZE)); + struct udp_pseudo psehdr; + +- int size; ++ unsigned int size; + t_ipaddr dadr; + + #ifdef DEBUG +@@ -194,13 +188,9 @@ + * + * Read one packet from a UDP socket + */ +-int udp_read(buf, bufsize, timeout, abortch) +-char *buf; +-int bufsize; +-int timeout; +-char abortch; ++int udp_read(char *buf, unsigned int bufsize, int timeout) + { +- int len; ++ unsigned int len; + + /* Wait until we get something */ + set_timeout(timeout); +@@ -299,9 +289,6 @@ */ int init_udp() { @@ -3193,9 +3679,21 @@ diff -ruN proll_18.orig/src/udp.c proll-patch10/src/udp.c /* Register IP packet type and set write buffer pointer */ if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL) return(FALSE); -diff -ruN proll_18.orig/src/vcons_zs.c proll-patch10/src/vcons_zs.c +diff -ruN proll_18.orig/src/udp.h proll-patch-15/src/udp.h +--- proll_18.orig/src/udp.h 2001-12-24 05:12:34.000000000 +0000 ++++ proll-patch-15/src/udp.h 2005-08-14 10:16:40.000000000 +0000 +@@ -53,7 +53,7 @@ + extern int udp_open __P((t_ipaddr daddr, int source, int dest)); + + /* Read from a UDP socket */ +-extern int udp_read __P((char *buf, int bufsize, int timeout, char abortch)); ++extern int udp_read(char *buf, unsigned int bufsize, int timeout); + + /* Write to a UDP socket */ + extern int udp_write __P((char *buf, int writelen)); +diff -ruN proll_18.orig/src/vcons_zs.c proll-patch-15/src/vcons_zs.c --- proll_18.orig/src/vcons_zs.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch10/src/vcons_zs.c 2005-04-10 07:01:03.000000000 +0000 ++++ proll-patch-15/src/vcons_zs.c 2005-08-14 10:25:51.000000000 +0000 @@ -0,0 +1,68 @@ +/** + ** Console over 'zs' (Zilog serial port) @@ -3243,7 +3741,7 @@ diff -ruN proll_18.orig/src/vcons_zs.c proll-patch10/src/vcons_zs.c + return leng; +} + -+int vcon_zs_read(struct vconterm *t, char *data, int leng) ++int vcon_zs_read(struct vconterm *t, char *data, __attribute((unused)) int leng) +{ + unsigned zs_ptr = (unsigned) t->impl; + @@ -3260,14 +3758,14 @@ diff -ruN proll_18.orig/src/vcons_zs.c proll-patch10/src/vcons_zs.c + return ldb_bypass(zs_ptr + ZS_DATA) & 0xff; +} + -+void vcon_zs_fini(struct vconterm *t) ++void vcon_zs_fini(__attribute((unused)) struct vconterm *t) +{ + /* violent crash in the end */ + ; +} -diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c +diff -ruN proll_18.orig/src/vconsole.c proll-patch-15/src/vconsole.c --- proll_18.orig/src/vconsole.c 1999-11-08 03:10:28.000000000 +0000 -+++ proll-patch10/src/vconsole.c 2005-04-17 19:23:21.000000000 +0000 ++++ proll-patch-15/src/vconsole.c 2005-08-14 10:24:49.000000000 +0000 @@ -7,12 +7,17 @@ #include "vconsole.h" @@ -3336,7 +3834,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c int vcon_write(struct vconterm *t, char *data, int leng) { int l = leng; -@@ -40,29 +83,99 @@ +@@ -40,29 +83,101 @@ if (l <= 0) break; c = *data++; --l; @@ -3358,7 +3856,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c + hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); + break; + default: -+ printk("Unhandled escape code '%c'\n", c); ++ //printk("Unhandled escape code '%c'\n", c); + break; + } break; @@ -3399,8 +3897,10 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c + case 'm': + break; + default: -+ printk("Unhandled escape code '%c', par[%d, %d, %d, %d, %d]\n", ++#if 0 ++ printk("Unhandled escape code '%c', par[%d, %d, %d, %d, %d]\n", + c, t->vc_par[0], t->vc_par[1], t->vc_par[2], t->vc_par[3], t->vc_par[4]); ++#endif + break; + } break; @@ -3446,7 +3946,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c + } else { + t->backc++; + } -+ if (t->vc_x + t->backc >= hcon_qxdim(hconp)) { ++ if ((unsigned int)t->vc_x + t->backc >= hcon_qxdim(hconp)) { + vcon_i_backflush(t); + t->vc_x = 0; + vcon_i_cursfeed(t); @@ -3454,10 +3954,32 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c } } } -@@ -100,9 +213,62 @@ +@@ -73,7 +188,7 @@ + static void vcon_i_cursfeed(struct vconterm *t) { + struct hconsole *hconp = t->impl; + +- if (++t->vc_y >= hcon_qydim(hconp)) { ++ if ((unsigned int)++t->vc_y >= hcon_qydim(hconp)) { + t->vc_y = hcon_qydim(hconp)-1; + hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); + } +@@ -90,22 +205,75 @@ + t->backp = 0; t->backc = 0; + } + +-int vcon_putch(struct vconterm *t, char c) ++int vcon_putch(__attribute__((unused)) struct vconterm *t, __attribute__((unused)) char c) + { + return -1; + } + +-int vcon_read(struct vconterm *t, char *data, int leng) ++int vcon_read(__attribute__((unused)) struct vconterm *t, __attribute__((unused)) char *data, __attribute__((unused)) int leng) + { return 0; } +-int vcon_getch(struct vconterm *t) +static const unsigned char sunkbd_keycode[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -3488,7 +4010,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c + +static int shiftstate; + - int vcon_getch(struct vconterm *t) ++int vcon_getch(__attribute__((unused)) struct vconterm *t) { - return -1; + int ch; @@ -3517,10 +4039,14 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c + return ch; } - void vcon_fini(struct vconterm *t) -diff -ruN proll_18.orig/src/vconsole.h proll-patch10/src/vconsole.h +-void vcon_fini(struct vconterm *t) ++void vcon_fini(__attribute__((unused)) struct vconterm *t) + { + /* violent crash in the end */ + ; +diff -ruN proll_18.orig/src/vconsole.h proll-patch-15/src/vconsole.h --- proll_18.orig/src/vconsole.h 1999-11-08 00:58:13.000000000 +0000 -+++ proll-patch10/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 ++++ proll-patch-15/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 @@ -6,6 +6,8 @@ #ifndef VCONSOLE_H #define VCONSOLE_H diff --git a/target-sparc/helper.c b/target-sparc/helper.c index ad1ae5bbb..7436e4ff4 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -195,15 +195,17 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { - target_ulong virt_addr; target_phys_addr_t paddr; unsigned long vaddr; int error_code = 0, prot, ret = 0, access_index; error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); if (error_code == 0) { - virt_addr = address & TARGET_PAGE_MASK; - vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + vaddr = address & TARGET_PAGE_MASK; + paddr &= TARGET_PAGE_MASK; +#ifdef DEBUG_MMU + printf("Translate at 0x%lx -> 0x%lx, vaddr 0x%lx\n", (long)address, (long)paddr, (long)vaddr); +#endif ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 695bc21e0..eaf5cb64e 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -276,6 +276,10 @@ void helper_ld_asi(int asi, int size, int sign) case 4: ret = ldl_phys(T0 & ~3); break; + case 8: + ret = ldl_phys(T0 & ~3); + T0 = ldl_phys((T0 + 4) & ~3); + break; } break; default: @@ -396,6 +400,10 @@ void helper_st_asi(int asi, int size, int sign) default: stl_phys(T0 & ~3, T1); break; + case 8: + stl_phys(T0 & ~3, T1); + stl_phys((T0 + 4) & ~3, T2); + break; } } return; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index c2ba2e35c..9abcedda7 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1897,6 +1897,11 @@ static void disas_sparc_insn(DisasContext * dc) #else gen_op_xor_T1_T0(); gen_op_wrpsr(); + save_state(dc); + gen_op_next_insn(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; #endif } break; @@ -2343,8 +2348,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x21: /* load fsr */ + gen_op_ldst(ldf); gen_op_ldfsr(); - gen_op_store_FT0_fpr(rd); break; case 0x22: /* load quad fpreg */ goto nfpu_insn; @@ -2426,9 +2431,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(stf); break; case 0x25: /* stfsr, V9 stxfsr */ - gen_op_load_fpr_FT0(rd); - // XXX gen_op_stfsr(); + gen_op_ldst(stf); break; case 0x26: /* stdfq */ goto nfpu_insn; -- cgit v1.2.3 From 868bfe2b2ba2c6c7e6580ad35af85ad3fcb994bb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 13 Nov 2005 21:53:15 +0000 Subject: correct use of USBDEVFS_DISCONNECT git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1621 c046a42c-6fe2-441c-8c8c-71466251a162 --- usb-linux.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/usb-linux.c b/usb-linux.c index cde94cd0a..216ac20f8 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -181,10 +181,15 @@ USBDevice *usb_host_device_open(const char *devname) #ifdef USBDEVFS_DISCONNECT /* earlier Linux 2.4 do not support that */ - ret = ioctl(fd, USBDEVFS_DISCONNECT); - if (ret < 0 && errno != ENODATA) { - perror("USBDEVFS_DISCONNECT"); - goto fail; + { + struct usbdevfs_ioctl ctrl; + ctrl.ioctl_code = USBDEVFS_DISCONNECT; + ctrl.ifno = 0; + ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl); + if (ret < 0 && errno != ENODATA) { + perror("USBDEVFS_DISCONNECT"); + goto fail; + } } #endif -- cgit v1.2.3 From 7c9d8e07e188597e570a311efc46cb1ab013e5e7 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Nov 2005 22:16:05 +0000 Subject: new network emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1622 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 24 +- hw/lance.c | 50 ++- hw/ne2000.c | 107 +++++- hw/parallel.c | 22 -- monitor.c | 17 - vl.c | 1034 ++++++++++++++++++++++++++++++++++++++++----------------- vl.h | 67 ++-- 7 files changed, 902 insertions(+), 419 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 96b3ae6d0..4ddf021e6 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -704,19 +704,19 @@ void gdb_exit(CPUState *env, int code) } #else -static int gdb_can_read(void *opaque) -{ - return 256; -} - -static void gdb_read(void *opaque, const uint8_t *buf, int size) +static void gdb_read(void *opaque) { GDBState *s = opaque; - int i; + int i, size; + uint8_t buf[4096]; + + size = read(s->fd, buf, sizeof(buf)); + if (size < 0) + return; if (size == 0) { /* end of connection */ qemu_del_vm_stop_handler(gdb_vm_stopped, s); - qemu_del_fd_read_handler(s->fd); + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); qemu_free(s); vm_start(); } else { @@ -727,7 +727,7 @@ static void gdb_read(void *opaque, const uint8_t *buf, int size) #endif -static void gdb_accept(void *opaque, const uint8_t *buf, int size) +static void gdb_accept(void *opaque) { GDBState *s; struct sockaddr_in sockaddr; @@ -768,7 +768,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size) vm_stop(EXCP_INTERRUPT); /* start handling I/O */ - qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s); + qemu_set_fd_handler(s->fd, gdb_read, NULL, s); /* when the VM is stopped, the following callback is called */ qemu_add_vm_stop_handler(gdb_vm_stopped, s); #endif @@ -815,9 +815,9 @@ int gdbserver_start(int port) return -1; /* accept connections */ #ifdef CONFIG_USER_ONLY - gdb_accept (NULL, NULL, 0); + gdb_accept (NULL); #else - qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL); + qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL); #endif return 0; } diff --git a/hw/lance.c b/hw/lance.c index 3a8a7d0b2..2fef6b1eb 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -154,7 +154,8 @@ struct lance_init_block { #define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) typedef struct LANCEState { - NetDriverState *nd; + VLANClientState *vc; + uint8_t macaddr[6]; /* init mac address */ uint32_t leptr; uint16_t addr; uint16_t regs[LE_NREGS]; @@ -169,7 +170,7 @@ static void lance_send(void *opaque); static void lance_reset(void *opaque) { LANCEState *s = opaque; - memcpy(s->phys, s->nd->macaddr, 6); + memcpy(s->phys, s->macaddr, 6); s->rxptr = 0; s->txptr = 0; memset(s->regs, 0, LE_NREGS * 2); @@ -280,31 +281,6 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { }; -/* return the max buffer size if the LANCE can receive more data */ -static int lance_can_receive(void *opaque) -{ - LANCEState *s = opaque; - uint32_t dmaptr = s->leptr + s->ledmaregs[3]; - struct lance_init_block *ib; - int i; - uint8_t temp8; - - if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) - return 0; - - ib = (void *) iommu_translate(dmaptr); - - for (i = 0; i < RX_RING_SIZE; i++) { - cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); - if (temp8 == (LE_R1_OWN)) { - DPRINTF("can receive %d\n", RX_BUFF_SIZE); - return RX_BUFF_SIZE; - } - } - DPRINTF("cannot receive\n"); - return 0; -} - #define MIN_BUF_SIZE 60 static void lance_receive(void *opaque, const uint8_t *buf, int size) @@ -368,7 +344,7 @@ static void lance_send(void *opaque) temp16 = (~temp16) + 1; cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16); DPRINTF("sending packet, len %d\n", temp16); - qemu_send_packet(s->nd, pkt_buf, temp16); + qemu_send_packet(s->vc, pkt_buf, temp16); temp8 = LE_T1_POK; cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; @@ -443,7 +419,7 @@ static int lance_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) +void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr) { LANCEState *s; int lance_io_memory, ledma_io_memory; @@ -452,7 +428,6 @@ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) if (!s) return; - s->nd = nd; s->irq = irq; lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); @@ -461,8 +436,21 @@ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr) ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); + memcpy(s->macaddr, nd->macaddr, 6); + lance_reset(s); - qemu_add_read_packet(nd, lance_can_receive, lance_receive, s); + + s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, s); + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->macaddr[0], + s->macaddr[1], + s->macaddr[2], + s->macaddr[3], + s->macaddr[4], + s->macaddr[5]); + register_savevm("lance", leaddr, 1, lance_save, lance_load, s); qemu_register_reset(lance_reset, s); } diff --git a/hw/ne2000.c b/hw/ne2000.c index db6133607..2b43ae46b 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -122,6 +122,7 @@ typedef struct NE2000State { uint16_t rcnt; uint32_t rsar; uint8_t rsr; + uint8_t rxcr; uint8_t isr; uint8_t dcfg; uint8_t imr; @@ -130,7 +131,8 @@ typedef struct NE2000State { uint8_t mult[8]; /* multicast mask array */ int irq; PCIDevice *pci_dev; - NetDriverState *nd; + VLANClientState *vc; + uint8_t macaddr[6]; uint8_t mem[NE2000_MEM_SIZE]; } NE2000State; @@ -139,7 +141,7 @@ static void ne2000_reset(NE2000State *s) int i; s->isr = ENISR_RESET; - memcpy(s->mem, s->nd->macaddr, 6); + memcpy(s->mem, s->macaddr, 6); s->mem[14] = 0x57; s->mem[15] = 0x57; @@ -167,6 +169,30 @@ static void ne2000_update_irq(NE2000State *s) } } +#define POLYNOMIAL 0x04c11db6 + +/* From FreeBSD */ +/* XXX: optimize */ +static int compute_mcast_idx(const uint8_t *ep) +{ + uint32_t crc; + int carry, i, j; + uint8_t b; + + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + b = *ep++; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); + crc <<= 1; + b >>= 1; + if (carry) + crc = ((crc ^ POLYNOMIAL) | carry); + } + } + return (crc >> 26); +} + /* return the max buffer size if the NE2000 can receive more data */ static int ne2000_can_receive(void *opaque) { @@ -192,13 +218,46 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) { NE2000State *s = opaque; uint8_t *p; - int total_len, next, avail, len, index; + int total_len, next, avail, len, index, mcast_idx; uint8_t buf1[60]; + static const uint8_t broadcast_macaddr[6] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #if defined(DEBUG_NE2000) printf("NE2000: received len=%d\n", size); #endif + if (!ne2000_can_receive(s)) + return; + + /* XXX: check this */ + if (s->rxcr & 0x10) { + /* promiscuous: receive all */ + } else { + if (!memcmp(buf, broadcast_macaddr, 6)) { + /* broadcast address */ + if (!(s->rxcr & 0x04)) + return; + } else if (buf[0] & 0x01) { + /* multicast */ + if (!(s->rxcr & 0x08)) + return; + mcast_idx = compute_mcast_idx(buf); + if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) + return; + } else if (s->mem[0] == buf[0] && + s->mem[2] == buf[1] && + s->mem[4] == buf[2] && + s->mem[6] == buf[3] && + s->mem[8] == buf[4] && + s->mem[10] == buf[5]) { + /* match */ + } else { + return; + } + } + + /* if too small buffer, then expand it */ if (size < MIN_BUF_SIZE) { memcpy(buf1, buf, size); @@ -273,7 +332,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) index -= NE2000_PMEM_SIZE; /* fail safe: check range on the transmitted length */ if (index + s->tcnt <= NE2000_PMEM_END) { - qemu_send_packet(s->nd, s->mem + index, s->tcnt); + qemu_send_packet(s->vc, s->mem + index, s->tcnt); } /* signal end of transfert */ s->tsr = ENTSR_PTX; @@ -320,6 +379,9 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) case EN0_RCNTHI: s->rcnt = (s->rcnt & 0x00ff) | (val << 8); break; + case EN0_RXCR: + s->rxcr = val; + break; case EN0_DCFG: s->dcfg = val; break; @@ -608,10 +670,10 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) return 0; } -void isa_ne2000_init(int base, int irq, NetDriverState *nd) +void isa_ne2000_init(int base, int irq, NICInfo *nd) { NE2000State *s; - + s = qemu_mallocz(sizeof(NE2000State)); if (!s) return; @@ -627,14 +689,22 @@ void isa_ne2000_init(int base, int irq, NetDriverState *nd) register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); s->irq = irq; - s->nd = nd; + memcpy(s->macaddr, nd->macaddr, 6); ne2000_reset(s); - qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); - + s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->macaddr[0], + s->macaddr[1], + s->macaddr[2], + s->macaddr[3], + s->macaddr[4], + s->macaddr[5]); + register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); - } /***********************************************************/ @@ -665,7 +735,7 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); } -void pci_ne2000_init(PCIBus *bus, NetDriverState *nd) +void pci_ne2000_init(PCIBus *bus, NICInfo *nd) { PCINE2000State *d; NE2000State *s; @@ -690,10 +760,19 @@ void pci_ne2000_init(PCIBus *bus, NetDriverState *nd) s = &d->ne2000; s->irq = 16; // PCI interrupt s->pci_dev = (PCIDevice *)d; - s->nd = nd; + memcpy(s->macaddr, nd->macaddr, 6); ne2000_reset(s); - qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); - + s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->macaddr[0], + s->macaddr[1], + s->macaddr[2], + s->macaddr[3], + s->macaddr[4], + s->macaddr[5]); + /* XXX: instance number ? */ register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, diff --git a/hw/parallel.c b/hw/parallel.c index 95ac7fd68..cba95610e 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -154,27 +154,6 @@ static uint32_t parallel_ioport_read(void *opaque, uint32_t addr) return ret; } -static int parallel_can_receive(ParallelState *s) -{ - return 0; -} - -static void parallel_receive_byte(ParallelState *s, int ch) -{ -} - -static int parallel_can_receive1(void *opaque) -{ - ParallelState *s = opaque; - return parallel_can_receive(s); -} - -static void parallel_receive1(void *opaque, const uint8_t *buf, int size) -{ - ParallelState *s = opaque; - parallel_receive_byte(s, buf[0]); -} - /* If fd is zero, it means that the parallel device uses the console */ ParallelState *parallel_init(int base, int irq, CharDriverState *chr) { @@ -200,6 +179,5 @@ ParallelState *parallel_init(int base, int irq, CharDriverState *chr) register_ioport_write(base, 8, 1, parallel_ioport_write, s); register_ioport_read(base, 8, 1, parallel_ioport_read, s); - qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s); return s; } diff --git a/monitor.c b/monitor.c index cf70b575a..18f0c8991 100644 --- a/monitor.c +++ b/monitor.c @@ -196,23 +196,6 @@ static void do_info_version(void) term_printf("%s\n", QEMU_VERSION); } -static void do_info_network(void) -{ - int i, j; - NetDriverState *nd; - - for(i = 0; i < nb_nics; i++) { - nd = &nd_table[i]; - term_printf("%d: ifname=%s macaddr=", i, nd->ifname); - for(j = 0; j < 6; j++) { - if (j > 0) - term_printf(":"); - term_printf("%02x", nd->macaddr[j]); - } - term_printf("\n"); - } -} - static void do_info_block(void) { bdrv_info(); diff --git a/vl.c b/vl.c index 62a2bbbbd..725e954d3 100644 --- a/vl.c +++ b/vl.c @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef _BSD #include #ifndef __APPLE__ @@ -122,10 +123,9 @@ const char* keyboard_layout = NULL; int64_t ticks_per_sec; int boot_device = 'c'; int ram_size; -static char network_script[1024]; int pit_min_timer_count = 0; int nb_nics; -NetDriverState nd_table[MAX_NICS]; +NICInfo nd_table[MAX_NICS]; QEMUTimer *gui_timer; int vm_running; #ifdef HAS_AUDIO @@ -155,6 +155,7 @@ int win2k_install_hack = 0; int usb_enabled = 0; USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; USBDevice *vm_usb_hub; +static VLANState *first_vlan; /***********************************************************/ /* x86 ISA bus support */ @@ -1076,10 +1077,10 @@ CharDriverState *qemu_chr_open_null(void) typedef struct { int fd_in, fd_out; - /* for nographic stdio only */ IOCanRWHandler *fd_can_read; IOReadHandler *fd_read; void *fd_opaque; + int max_size; } FDCharDriver; #define STDIO_MAX_CLIENTS 2 @@ -1113,6 +1114,33 @@ static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) return unix_write(s->fd_out, buf, len); } +static int fd_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + FDCharDriver *s = chr->opaque; + + s->max_size = s->fd_can_read(s->fd_opaque); + return s->max_size; +} + +static void fd_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + FDCharDriver *s = chr->opaque; + int size, len; + uint8_t buf[1024]; + + len = sizeof(buf); + if (len > s->max_size) + len = s->max_size; + if (len == 0) + return; + size = read(s->fd_in, buf, len); + if (size > 0) { + s->fd_read(s->fd_opaque, buf, size); + } +} + static void fd_chr_add_read_handler(CharDriverState *chr, IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, void *opaque) @@ -1120,12 +1148,13 @@ static void fd_chr_add_read_handler(CharDriverState *chr, FDCharDriver *s = chr->opaque; if (s->fd_in >= 0) { + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->fd_opaque = opaque; if (nographic && s->fd_in == 0) { - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; } else { - qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque); + qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, + fd_chr_read, NULL, chr); } } } @@ -1261,7 +1290,7 @@ static void stdio_received_byte(int ch) } } -static int stdio_can_read(void *opaque) +static int stdio_read_poll(void *opaque) { CharDriverState *chr; FDCharDriver *s; @@ -1284,11 +1313,14 @@ static int stdio_can_read(void *opaque) } } -static void stdio_read(void *opaque, const uint8_t *buf, int size) +static void stdio_read(void *opaque) { - int i; - for(i = 0; i < size; i++) - stdio_received_byte(buf[i]); + int size; + uint8_t buf[1]; + + size = read(0, buf, 1); + if (size > 0) + stdio_received_byte(buf[0]); } /* init terminal so that we can grab keys */ @@ -1337,7 +1369,7 @@ CharDriverState *qemu_chr_open_stdio(void) return NULL; chr = qemu_chr_open_fd(0, 1); if (stdio_nb_clients == 0) - qemu_add_fd_read_handler(0, stdio_can_read, stdio_read, NULL); + qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL); client_index = stdio_nb_clients; } else { if (stdio_nb_clients != 0) @@ -1603,7 +1635,7 @@ CharDriverState *qemu_chr_open(const char *filename) } /***********************************************************/ -/* Linux network device redirectors */ +/* network device redirectors */ void hex_dump(FILE *f, const uint8_t *buf, int size) { @@ -1631,107 +1663,171 @@ void hex_dump(FILE *f, const uint8_t *buf, int size) } } -void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +static int parse_macaddr(uint8_t *macaddr, const char *p) { - nd->send_packet(nd, buf, size); + int i; + for(i = 0; i < 6; i++) { + macaddr[i] = strtol(p, (char **)&p, 16); + if (i == 5) { + if (*p != '\0') + return -1; + } else { + if (*p != ':') + return -1; + p++; + } + } + return 0; } -void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) { - nd->add_read_packet(nd, fd_can_read, fd_read, opaque); + const char *p, *p1; + int len; + p = *pp; + p1 = strchr(p, sep); + if (!p1) + return -1; + len = p1 - p; + p1++; + if (buf_size > 0) { + if (len > buf_size - 1) + len = buf_size - 1; + memcpy(buf, p, len); + buf[len] = '\0'; + } + *pp = p1; + return 0; } -/* dummy network adapter */ +int parse_host_port(struct sockaddr_in *saddr, const char *str) +{ + char buf[512]; + struct hostent *he; + const char *p, *r; + int port; + + p = str; + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + return -1; + saddr->sin_family = AF_INET; + if (buf[0] == '\0') { + saddr->sin_addr.s_addr = 0; + } else { + if (isdigit(buf[0])) { + if (!inet_aton(buf, &saddr->sin_addr)) + return -1; + } else { +#ifdef _WIN32 + return -1; +#else + if ((he = gethostbyname(buf)) == NULL) + return - 1; + saddr->sin_addr = *(struct in_addr *)he->h_addr; +#endif + } + } + port = strtol(p, (char **)&r, 0); + if (r == p) + return -1; + saddr->sin_port = htons(port); + return 0; +} -static void dummy_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +/* find or alloc a new VLAN */ +VLANState *qemu_find_vlan(int id) { + VLANState **pvlan, *vlan; + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + if (vlan->id == id) + return vlan; + } + vlan = qemu_mallocz(sizeof(VLANState)); + if (!vlan) + return NULL; + vlan->id = id; + vlan->next = NULL; + pvlan = &first_vlan; + while (*pvlan != NULL) + pvlan = &(*pvlan)->next; + *pvlan = vlan; + return vlan; } -static void dummy_add_read_packet(NetDriverState *nd, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +VLANClientState *qemu_new_vlan_client(VLANState *vlan, + IOReadHandler *fd_read, void *opaque) { + VLANClientState *vc, **pvc; + vc = qemu_mallocz(sizeof(VLANClientState)); + if (!vc) + return NULL; + vc->fd_read = fd_read; + vc->opaque = opaque; + vc->vlan = vlan; + + vc->next = NULL; + pvc = &vlan->first_client; + while (*pvc != NULL) + pvc = &(*pvc)->next; + *pvc = vc; + return vc; } -static int net_dummy_init(NetDriverState *nd) +void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) { - nd->send_packet = dummy_send_packet; - nd->add_read_packet = dummy_add_read_packet; - pstrcpy(nd->ifname, sizeof(nd->ifname), "dummy"); - return 0; + VLANState *vlan = vc1->vlan; + VLANClientState *vc; + +#if 0 + printf("vlan %d send:\n", vlan->id); + hex_dump(stdout, buf, size); +#endif + for(vc = vlan->first_client; vc != NULL; vc = vc->next) { + if (vc != vc1) { + vc->fd_read(vc->opaque, buf, size); + } + } } #if defined(CONFIG_SLIRP) /* slirp network adapter */ -static void *slirp_fd_opaque; -static IOCanRWHandler *slirp_fd_can_read; -static IOReadHandler *slirp_fd_read; static int slirp_inited; +static VLANClientState *slirp_vc; int slirp_can_output(void) { - return slirp_fd_can_read(slirp_fd_opaque); + return 1; } void slirp_output(const uint8_t *pkt, int pkt_len) { #if 0 - printf("output:\n"); + printf("slirp output:\n"); hex_dump(stdout, pkt, pkt_len); #endif - slirp_fd_read(slirp_fd_opaque, pkt, pkt_len); + qemu_send_packet(slirp_vc, pkt, pkt_len); } -static void slirp_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +static void slirp_receive(void *opaque, const uint8_t *buf, int size) { #if 0 - printf("input:\n"); + printf("slirp input:\n"); hex_dump(stdout, buf, size); #endif slirp_input(buf, size); } -static void slirp_add_read_packet(NetDriverState *nd, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) -{ - slirp_fd_opaque = opaque; - slirp_fd_can_read = fd_can_read; - slirp_fd_read = fd_read; -} - -static int net_slirp_init(NetDriverState *nd) +static int net_slirp_init(VLANState *vlan) { if (!slirp_inited) { slirp_inited = 1; slirp_init(); } - nd->send_packet = slirp_send_packet; - nd->add_read_packet = slirp_add_read_packet; - pstrcpy(nd->ifname, sizeof(nd->ifname), "slirp"); - return 0; -} - -static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) -{ - const char *p, *p1; - int len; - p = *pp; - p1 = strchr(p, sep); - if (!p1) - return -1; - len = p1 - p; - p1++; - if (buf_size > 0) { - if (len > buf_size - 1) - len = buf_size - 1; - memcpy(buf, p, len); - buf[len] = '\0'; - } - *pp = p1; + slirp_vc = qemu_new_vlan_client(vlan, + slirp_receive, NULL); + snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector"); return 0; } @@ -1874,8 +1970,55 @@ void net_slirp_smb(const char *exported_dir) #endif /* CONFIG_SLIRP */ #if !defined(_WIN32) + +typedef struct TAPState { + VLANClientState *vc; + int fd; +} TAPState; + +static void tap_receive(void *opaque, const uint8_t *buf, int size) +{ + TAPState *s = opaque; + int ret; + for(;;) { + ret = write(s->fd, buf, size); + if (ret < 0 && (errno == EINTR || errno == EAGAIN)) { + } else { + break; + } + } +} + +static void tap_send(void *opaque) +{ + TAPState *s = opaque; + uint8_t buf[4096]; + int size; + + size = read(s->fd, buf, sizeof(buf)); + if (size > 0) { + qemu_send_packet(s->vc, buf, size); + } +} + +/* fd support */ + +static TAPState *net_tap_fd_init(VLANState *vlan, int fd) +{ + TAPState *s; + + s = qemu_mallocz(sizeof(TAPState)); + if (!s) + return NULL; + s->fd = fd; + s->vc = qemu_new_vlan_client(vlan, tap_receive, s); + qemu_set_fd_handler(s->fd, tap_send, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd); + return s; +} + #ifdef _BSD -static int tun_open(char *ifname, int ifname_size) +static int tap_open(char *ifname, int ifname_size) { int fd; char *dev; @@ -1895,7 +2038,7 @@ static int tun_open(char *ifname, int ifname_size) return fd; } #else -static int tun_open(char *ifname, int ifname_size) +static int tap_open(char *ifname, int ifname_size) { struct ifreq ifr; int fd, ret; @@ -1907,76 +2050,448 @@ static int tun_open(char *ifname, int ifname_size) } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d"); + if (ifname[0] != '\0') + pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname); + else + pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d"); ret = ioctl(fd, TUNSETIFF, (void *) &ifr); if (ret != 0) { fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); close(fd); return -1; } - printf("Connected to host network interface: %s\n", ifr.ifr_name); pstrcpy(ifname, ifname_size, ifr.ifr_name); fcntl(fd, F_SETFL, O_NONBLOCK); return fd; } #endif -static void tun_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +static int net_tap_init(VLANState *vlan, const char *ifname1, + const char *setup_script) +{ + TAPState *s; + int pid, status, fd; + char *args[3]; + char **parg; + char ifname[128]; + + if (ifname1 != NULL) + pstrcpy(ifname, sizeof(ifname), ifname1); + else + ifname[0] = '\0'; + fd = tap_open(ifname, sizeof(ifname)); + if (fd < 0) + return -1; + + if (!setup_script) + setup_script = ""; + if (setup_script[0] != '\0') { + /* try to launch network init script */ + pid = fork(); + if (pid >= 0) { + if (pid == 0) { + parg = args; + *parg++ = (char *)setup_script; + *parg++ = ifname; + *parg++ = NULL; + execv(setup_script, args); + exit(1); + } + while (waitpid(pid, &status, 0) != pid); + if (!WIFEXITED(status) || + WEXITSTATUS(status) != 0) { + fprintf(stderr, "%s: could not launch network script\n", + setup_script); + return -1; + } + } + } + s = net_tap_fd_init(vlan, fd); + if (!s) + return -1; + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "tap: ifname=%s setup_script=%s", ifname, setup_script); + return 0; +} + +/* network connection */ +typedef struct NetSocketState { + VLANClientState *vc; + int fd; + int state; /* 0 = getting length, 1 = getting data */ + int index; + int packet_len; + uint8_t buf[4096]; +} NetSocketState; + +typedef struct NetSocketListenState { + VLANState *vlan; + int fd; +} NetSocketListenState; + +/* XXX: we consider we can send the whole packet without blocking */ +static void net_socket_receive(void *opaque, const uint8_t *buf, int size) { - write(nd->fd, buf, size); + NetSocketState *s = opaque; + uint32_t len; + len = htonl(size); + + unix_write(s->fd, (const uint8_t *)&len, sizeof(len)); + unix_write(s->fd, buf, size); } -static void tun_add_read_packet(NetDriverState *nd, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +static void net_socket_send(void *opaque) { - qemu_add_fd_read_handler(nd->fd, fd_can_read, fd_read, opaque); + NetSocketState *s = opaque; + int l, size; + uint8_t buf1[4096]; + const uint8_t *buf; + + size = read(s->fd, buf1, sizeof(buf1)); + if (size < 0) + return; + if (size == 0) { + /* end of connection */ + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + return; + } + buf = buf1; + while (size > 0) { + /* reassemble a packet from the network */ + switch(s->state) { + case 0: + l = 4 - s->index; + if (l > size) + l = size; + memcpy(s->buf + s->index, buf, l); + buf += l; + size -= l; + s->index += l; + if (s->index == 4) { + /* got length */ + s->packet_len = ntohl(*(uint32_t *)s->buf); + s->index = 0; + s->state = 1; + } + break; + case 1: + l = s->packet_len - s->index; + if (l > size) + l = size; + memcpy(s->buf + s->index, buf, l); + s->index += l; + buf += l; + size -= l; + if (s->index >= s->packet_len) { + qemu_send_packet(s->vc, s->buf, s->packet_len); + s->index = 0; + s->state = 0; + } + break; + } + } } -static int net_tun_init(NetDriverState *nd) +static void net_socket_connect(void *opaque) { - int pid, status; - char *args[3]; - char **parg; + NetSocketState *s = opaque; + qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); +} - nd->fd = tun_open(nd->ifname, sizeof(nd->ifname)); - if (nd->fd < 0) - return -1; +static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, + int is_connected) +{ + NetSocketState *s; + s = qemu_mallocz(sizeof(NetSocketState)); + if (!s) + return NULL; + s->fd = fd; + s->vc = qemu_new_vlan_client(vlan, + net_socket_receive, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: fd=%d", fd); + if (is_connected) { + net_socket_connect(s); + } else { + qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); + } + return s; +} - /* try to launch network init script */ - pid = fork(); - if (pid >= 0) { - if (pid == 0) { - parg = args; - *parg++ = network_script; - *parg++ = nd->ifname; - *parg++ = NULL; - execv(network_script, args); - exit(1); - } - while (waitpid(pid, &status, 0) != pid); - if (!WIFEXITED(status) || - WEXITSTATUS(status) != 0) { - fprintf(stderr, "%s: could not launch network script\n", - network_script); +static void net_socket_accept(void *opaque) +{ + NetSocketListenState *s = opaque; + NetSocketState *s1; + struct sockaddr_in saddr; + socklen_t len; + int fd; + + for(;;) { + len = sizeof(saddr); + fd = accept(s->fd, (struct sockaddr *)&saddr, &len); + if (fd < 0 && errno != EINTR) { + return; + } else if (fd >= 0) { + break; } } - nd->send_packet = tun_send_packet; - nd->add_read_packet = tun_add_read_packet; + s1 = net_socket_fd_init(s->vlan, fd, 1); + if (!s1) { + close(fd); + } else { + snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), + "socket: connection from %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + } +} + +static int net_socket_listen_init(VLANState *vlan, const char *host_str) +{ + NetSocketListenState *s; + int fd, val, ret; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + s = qemu_mallocz(sizeof(NetSocketListenState)); + if (!s) + return -1; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + fcntl(fd, F_SETFL, O_NONBLOCK); + + /* allow fast reuse */ + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + perror("bind"); + return -1; + } + ret = listen(fd, 0); + if (ret < 0) { + perror("listen"); + return -1; + } + s->vlan = vlan; + s->fd = fd; + qemu_set_fd_handler(fd, net_socket_accept, NULL, s); return 0; } -static int net_fd_init(NetDriverState *nd, int fd) +static int net_socket_connect_init(VLANState *vlan, const char *host_str) { - nd->fd = fd; - nd->send_packet = tun_send_packet; - nd->add_read_packet = tun_add_read_packet; - pstrcpy(nd->ifname, sizeof(nd->ifname), "tunfd"); + NetSocketState *s; + int fd, connected, ret; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + return -1; + } + fcntl(fd, F_SETFL, O_NONBLOCK); + + connected = 0; + for(;;) { + ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + if (errno == EINTR || errno == EAGAIN) { + } else if (errno == EINPROGRESS) { + break; + } else { + perror("connect"); + close(fd); + return -1; + } + } else { + connected = 1; + break; + } + } + s = net_socket_fd_init(vlan, fd, connected); + if (!s) + return -1; + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: connect to %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; } #endif /* !_WIN32 */ +static int get_param_value(char *buf, int buf_size, + const char *tag, const char *str) +{ + const char *p; + char *q; + char option[128]; + + p = str; + for(;;) { + q = option; + while (*p != '\0' && *p != '=') { + if ((q - option) < sizeof(option) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + if (*p != '=') + break; + p++; + if (!strcmp(tag, option)) { + q = buf; + while (*p != '\0' && *p != ',') { + if ((q - buf) < buf_size - 1) + *q++ = *p; + p++; + } + *q = '\0'; + return q - buf; + } else { + while (*p != '\0' && *p != ',') { + p++; + } + } + if (*p != ',') + break; + p++; + } + return 0; +} + +int net_client_init(const char *str) +{ + const char *p; + char *q; + char device[64]; + char buf[1024]; + int vlan_id, ret; + VLANState *vlan; + + p = str; + q = device; + while (*p != '\0' && *p != ',') { + if ((q - device) < sizeof(device) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + if (*p == ',') + p++; + vlan_id = 0; + if (get_param_value(buf, sizeof(buf), "vlan", p)) { + vlan_id = strtol(buf, NULL, 0); + } + vlan = qemu_find_vlan(vlan_id); + if (!vlan) { + fprintf(stderr, "Could not create vlan %d\n", vlan_id); + return -1; + } + if (!strcmp(device, "nic")) { + NICInfo *nd; + uint8_t *macaddr; + + if (nb_nics >= MAX_NICS) { + fprintf(stderr, "Too Many NICs\n"); + return -1; + } + nd = &nd_table[nb_nics]; + macaddr = nd->macaddr; + macaddr[0] = 0x52; + macaddr[1] = 0x54; + macaddr[2] = 0x00; + macaddr[3] = 0x12; + macaddr[4] = 0x34; + macaddr[5] = 0x56 + nb_nics; + + if (get_param_value(buf, sizeof(buf), "macaddr", p)) { + if (parse_macaddr(macaddr, buf) < 0) { + fprintf(stderr, "invalid syntax for ethernet address\n"); + return -1; + } + } + nd->vlan = vlan; + nb_nics++; + ret = 0; + } else + if (!strcmp(device, "none")) { + /* does nothing. It is needed to signal that no network cards + are wanted */ + ret = 0; + } else +#ifdef CONFIG_SLIRP + if (!strcmp(device, "user")) { + ret = net_slirp_init(vlan); + } else +#endif +#ifndef _WIN32 + if (!strcmp(device, "tap")) { + char ifname[64]; + char setup_script[1024]; + int fd; + if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { + fd = strtol(buf, NULL, 0); + ret = -1; + if (net_tap_fd_init(vlan, fd)) + ret = 0; + } else { + get_param_value(ifname, sizeof(ifname), "ifname", p); + if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { + pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); + } + ret = net_tap_init(vlan, ifname, setup_script); + } + } else + if (!strcmp(device, "socket")) { + if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { + int fd; + fd = strtol(buf, NULL, 0); + ret = -1; + if (net_socket_fd_init(vlan, fd, 1)) + ret = 0; + } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) { + ret = net_socket_listen_init(vlan, buf); + } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) { + ret = net_socket_connect_init(vlan, buf); + } else { + fprintf(stderr, "Unknown socket options: %s\n", p); + return -1; + } + } else +#endif + { + fprintf(stderr, "Unknown network device: %s\n", device); + return -1; + } + if (ret < 0) { + fprintf(stderr, "Could not initialize device '%s'\n", device); + } + + return ret; +} + +void do_info_network(void) +{ + VLANState *vlan; + VLANClientState *vc; + + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + term_printf("VLAN %d devices:\n", vlan->id); + for(vc = vlan->first_client; vc != NULL; vc = vc->next) + term_printf(" %s\n", vc->info_str); + } +} + /***********************************************************/ /* USB devices */ @@ -2175,49 +2690,65 @@ static void host_segv_handler(int host_signum, siginfo_t *info, typedef struct IOHandlerRecord { int fd; - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; + IOCanRWHandler *fd_read_poll; + IOHandler *fd_read; + IOHandler *fd_write; void *opaque; /* temporary data */ struct pollfd *ufd; - int max_size; struct IOHandlerRecord *next; } IOHandlerRecord; static IOHandlerRecord *first_io_handler; -int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +/* XXX: fd_read_poll should be suppressed, but an API change is + necessary in the character devices to suppress fd_can_read(). */ +int qemu_set_fd_handler2(int fd, + IOCanRWHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) { - IOHandlerRecord *ioh; + IOHandlerRecord **pioh, *ioh; - ioh = qemu_mallocz(sizeof(IOHandlerRecord)); - if (!ioh) - return -1; - ioh->fd = fd; - ioh->fd_can_read = fd_can_read; - ioh->fd_read = fd_read; - ioh->opaque = opaque; - ioh->next = first_io_handler; - first_io_handler = ioh; + if (!fd_read && !fd_write) { + pioh = &first_io_handler; + for(;;) { + ioh = *pioh; + if (ioh == NULL) + break; + if (ioh->fd == fd) { + *pioh = ioh->next; + break; + } + pioh = &ioh->next; + } + } else { + for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { + if (ioh->fd == fd) + goto found; + } + ioh = qemu_mallocz(sizeof(IOHandlerRecord)); + if (!ioh) + return -1; + ioh->next = first_io_handler; + first_io_handler = ioh; + found: + ioh->fd = fd; + ioh->fd_read_poll = fd_read_poll; + ioh->fd_read = fd_read; + ioh->fd_write = fd_write; + ioh->opaque = opaque; + } return 0; } -void qemu_del_fd_read_handler(int fd) +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) { - IOHandlerRecord **pioh, *ioh; - - pioh = &first_io_handler; - for(;;) { - ioh = *pioh; - if (ioh == NULL) - break; - if (ioh->fd == fd) { - *pioh = ioh->next; - break; - } - pioh = &ioh->next; - } + return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); } /***********************************************************/ @@ -3080,8 +3611,6 @@ void main_loop_wait(int timeout) #ifndef _WIN32 struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf; IOHandlerRecord *ioh, *ioh_next; - uint8_t buf[4096]; - int n, max_size; #endif int ret; @@ -3093,26 +3622,18 @@ void main_loop_wait(int timeout) /* XXX: separate device handlers from system ones */ pf = ufds; for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { - if (!ioh->fd_can_read) { - max_size = 0; - pf->fd = ioh->fd; - pf->events = POLLIN; - ioh->ufd = pf; - pf++; - } else { - max_size = ioh->fd_can_read(ioh->opaque); - if (max_size > 0) { - if (max_size > sizeof(buf)) - max_size = sizeof(buf); - pf->fd = ioh->fd; - pf->events = POLLIN; - ioh->ufd = pf; - pf++; - } else { - ioh->ufd = NULL; - } + pf->events = 0; + pf->fd = ioh->fd; + if (ioh->fd_read && + (!ioh->fd_read_poll || + ioh->fd_read_poll(ioh->opaque) != 0)) { + pf->events |= POLLIN; + } + if (ioh->fd_write) { + pf->events |= POLLOUT; } - ioh->max_size = max_size; + ioh->ufd = pf; + pf++; } ret = poll(ufds, pf - ufds, timeout); @@ -3121,20 +3642,11 @@ void main_loop_wait(int timeout) for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { ioh_next = ioh->next; pf = ioh->ufd; - if (pf) { - if (pf->revents & POLLIN) { - if (ioh->max_size == 0) { - /* just a read event */ - ioh->fd_read(ioh->opaque, NULL, 0); - } else { - n = read(ioh->fd, buf, ioh->max_size); - if (n >= 0) { - ioh->fd_read(ioh->opaque, buf, n); - } else if (errno != EAGAIN) { - ioh->fd_read(ioh->opaque, NULL, -errno); - } - } - } + if (pf->revents & POLLIN) { + ioh->fd_read(ioh->opaque); + } + if (pf->revents & POLLOUT) { + ioh->fd_write(ioh->opaque); } } } @@ -3251,20 +3763,31 @@ void help(void) #endif "\n" "Network options:\n" - "-nics n simulate 'n' network cards [default=1]\n" - "-macaddr addr set the mac address of the first interface\n" - "-n script set tap/tun network init script [default=%s]\n" - "-tun-fd fd use this fd as already opened tap/tun interface\n" + "-net nic[,vlan=n][,macaddr=addr]\n" + " create a new Network Interface Card and connect it to VLAN 'n'\n" #ifdef CONFIG_SLIRP - "-user-net use user mode network stack [default if no tap/tun script]\n" - "-tftp prefix allow tftp access to files starting with prefix [-user-net]\n" + "-net user[,vlan=n]\n" + " connect the user mode network stack to VLAN 'n'\n" +#endif #ifndef _WIN32 - "-smb dir allow SMB access to files in 'dir' [-user-net]\n" + "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n" + " connect the host TAP network interface to VLAN 'n' and use\n" + " the network script 'file' (default=%s);\n" + " use 'fd=h' to connect to an already opened TAP interface\n" + "-net socket[,vlan=n][,fd=x][,listen=[host]:port][,connect=host:port]\n" + " connect the vlan 'n' to another VLAN using a socket connection\n" +#endif + "-net none use it alone to have zero network devices; if no -net option\n" + " is provided, the default is '-net nic -net user'\n" + "\n" +#ifdef CONFIG_SLIRP + "-tftp prefix allow tftp access to files starting with prefix [-net user]\n" +#ifndef _WIN32 + "-smb dir allow SMB access to files in 'dir' [-net user]\n" #endif "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" - " redirect TCP or UDP connections from host to guest [-user-net]\n" + " redirect TCP or UDP connections from host to guest [-net user]\n" #endif - "-dummy-net use dummy network stack\n" "\n" "Linux boot specific:\n" "-kernel bzImage use 'bzImage' as kernel image\n" @@ -3308,7 +3831,9 @@ void help(void) "qemu-fast", #endif DEFAULT_RAM_SIZE, +#ifndef _WIN32 DEFAULT_NETWORK_SCRIPT, +#endif DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); #ifndef CONFIG_SOFTMMU @@ -3343,15 +3868,10 @@ enum { QEMU_OPTION_soundhw, #endif - QEMU_OPTION_nics, - QEMU_OPTION_macaddr, - QEMU_OPTION_n, - QEMU_OPTION_tun_fd, - QEMU_OPTION_user_net, + QEMU_OPTION_net, QEMU_OPTION_tftp, QEMU_OPTION_smb, QEMU_OPTION_redir, - QEMU_OPTION_dummy_net, QEMU_OPTION_kernel, QEMU_OPTION_append, @@ -3409,19 +3929,14 @@ const QEMUOption qemu_options[] = { { "soundhw", HAS_ARG, QEMU_OPTION_soundhw }, #endif - { "nics", HAS_ARG, QEMU_OPTION_nics}, - { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, - { "n", HAS_ARG, QEMU_OPTION_n }, - { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, + { "net", HAS_ARG, QEMU_OPTION_net}, #ifdef CONFIG_SLIRP - { "user-net", 0, QEMU_OPTION_user_net }, { "tftp", HAS_ARG, QEMU_OPTION_tftp }, #ifndef _WIN32 { "smb", HAS_ARG, QEMU_OPTION_smb }, #endif { "redir", HAS_ARG, QEMU_OPTION_redir }, #endif - { "dummy-net", 0, QEMU_OPTION_dummy_net }, { "kernel", HAS_ARG, QEMU_OPTION_kernel }, { "append", HAS_ARG, QEMU_OPTION_append }, @@ -3596,9 +4111,7 @@ static void select_soundhw (const char *optarg) } #endif -#define NET_IF_TUN 0 -#define NET_IF_USER 1 -#define NET_IF_DUMMY 2 +#define MAX_NET_CLIENTS 32 int main(int argc, char **argv) { @@ -3614,8 +4127,8 @@ int main(int argc, char **argv) DisplayState *ds = &display_state; int cyls, heads, secs, translation; int start_emulation = 1; - uint8_t macaddr[6]; - int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; + char net_clients[MAX_NET_CLIENTS][256]; + int nb_net_clients; int optind; const char *r, *optarg; CharDriverState *monitor_hd; @@ -3644,7 +4157,6 @@ int main(int argc, char **argv) ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; - pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); #ifdef CONFIG_GDBSTUB use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; @@ -3674,16 +4186,10 @@ int main(int argc, char **argv) usb_devices_index = 0; - nb_tun_fds = 0; - net_if_type = -1; - nb_nics = 1; + nb_net_clients = 0; + + nb_nics = 0; /* default mac address of the first network interface */ - macaddr[0] = 0x52; - macaddr[1] = 0x54; - macaddr[2] = 0x00; - macaddr[3] = 0x12; - macaddr[4] = 0x34; - macaddr[5] = 0x56; optind = 1; for(;;) { @@ -3797,21 +4303,6 @@ int main(int argc, char **argv) case QEMU_OPTION_append: kernel_cmdline = optarg; break; - case QEMU_OPTION_tun_fd: - { - const char *p; - int fd; - net_if_type = NET_IF_TUN; - if (nb_tun_fds < MAX_NICS) { - fd = strtol(optarg, (char **)&p, 0); - if (*p != '\0') { - fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_tun_fds); - exit(1); - } - tun_fds[nb_tun_fds++] = fd; - } - } - break; case QEMU_OPTION_cdrom: if (cdrom_index >= 0) { hd_filename[cdrom_index] = optarg; @@ -3838,33 +4329,15 @@ int main(int argc, char **argv) case QEMU_OPTION_no_code_copy: code_copy_enabled = 0; break; - case QEMU_OPTION_nics: - nb_nics = atoi(optarg); - if (nb_nics < 0 || nb_nics > MAX_NICS) { - fprintf(stderr, "qemu: invalid number of network interfaces\n"); + case QEMU_OPTION_net: + if (nb_net_clients >= MAX_NET_CLIENTS) { + fprintf(stderr, "qemu: too many network clients\n"); exit(1); } - break; - case QEMU_OPTION_macaddr: - { - const char *p; - int i; - p = optarg; - for(i = 0; i < 6; i++) { - macaddr[i] = strtol(p, (char **)&p, 16); - if (i == 5) { - if (*p != '\0') - goto macaddr_error; - } else { - if (*p != ':') { - macaddr_error: - fprintf(stderr, "qemu: invalid syntax for ethernet address\n"); - exit(1); - } - p++; - } - } - } + pstrcpy(net_clients[nb_net_clients], + sizeof(net_clients[0]), + optarg); + nb_net_clients++; break; #ifdef CONFIG_SLIRP case QEMU_OPTION_tftp: @@ -3875,16 +4348,10 @@ int main(int argc, char **argv) net_slirp_smb(optarg); break; #endif - case QEMU_OPTION_user_net: - net_if_type = NET_IF_USER; - break; case QEMU_OPTION_redir: net_slirp_redir(optarg); break; #endif - case QEMU_OPTION_dummy_net: - net_if_type = NET_IF_DUMMY; - break; #ifdef HAS_AUDIO case QEMU_OPTION_enable_audio: audio_enabled = 1; @@ -3930,9 +4397,6 @@ int main(int argc, char **argv) cpu_set_log(mask); } break; - case QEMU_OPTION_n: - pstrcpy(network_script, sizeof(network_script), optarg); - break; #ifdef CONFIG_GDBSTUB case QEMU_OPTION_s: use_gdbstub = 1; @@ -4076,48 +4540,20 @@ int main(int argc, char **argv) #else setvbuf(stdout, NULL, _IOLBF, 0); #endif - - /* init host network redirectors */ - if (net_if_type == -1) { - net_if_type = NET_IF_TUN; -#if defined(CONFIG_SLIRP) - if (access(network_script, R_OK) < 0) { - net_if_type = NET_IF_USER; - } -#endif + + /* init network clients */ + if (nb_net_clients == 0) { + /* if no clients, we use a default config */ + pstrcpy(net_clients[0], sizeof(net_clients[0]), + "nic"); + pstrcpy(net_clients[1], sizeof(net_clients[0]), + "user"); + nb_net_clients = 2; } - for(i = 0; i < nb_nics; i++) { - NetDriverState *nd = &nd_table[i]; - nd->index = i; - /* init virtual mac address */ - nd->macaddr[0] = macaddr[0]; - nd->macaddr[1] = macaddr[1]; - nd->macaddr[2] = macaddr[2]; - nd->macaddr[3] = macaddr[3]; - nd->macaddr[4] = macaddr[4]; - nd->macaddr[5] = macaddr[5] + i; - switch(net_if_type) { -#if defined(CONFIG_SLIRP) - case NET_IF_USER: - net_slirp_init(nd); - break; -#endif -#if !defined(_WIN32) - case NET_IF_TUN: - if (i < nb_tun_fds) { - net_fd_init(nd, tun_fds[i]); - } else { - if (net_tun_init(nd) < 0) - net_dummy_init(nd); - } - break; -#endif - case NET_IF_DUMMY: - default: - net_dummy_init(nd); - break; - } + for(i = 0;i < nb_net_clients; i++) { + if (net_client_init(net_clients[i]) < 0) + exit(1); } /* init the memory */ diff --git a/vl.h b/vl.h index 10cfb5840..d5efcd2e7 100644 --- a/vl.h +++ b/vl.h @@ -196,10 +196,17 @@ void kbd_put_keysym(int keysym); typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); typedef int IOCanRWHandler(void *opaque); +typedef void IOHandler(void *opaque); -int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque); -void qemu_del_fd_read_handler(int fd); +int qemu_set_fd_handler2(int fd, + IOCanRWHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); /* character device */ @@ -270,30 +277,42 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; -/* network redirectors support */ +/* VLANs support */ + +typedef struct VLANClientState VLANClientState; + +struct VLANClientState { + IOReadHandler *fd_read; + void *opaque; + struct VLANClientState *next; + struct VLANState *vlan; + char info_str[256]; +}; + +typedef struct VLANState { + int id; + VLANClientState *first_client; + struct VLANState *next; +} VLANState; + +VLANState *qemu_find_vlan(int id); +VLANClientState *qemu_new_vlan_client(VLANState *vlan, + IOReadHandler *fd_read, void *opaque); +void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); + +void do_info_network(void); + +/* NIC info */ #define MAX_NICS 8 -typedef struct NetDriverState { - int index; /* index number in QEMU */ +typedef struct NICInfo { uint8_t macaddr[6]; - char ifname[16]; - void (*send_packet)(struct NetDriverState *nd, - const uint8_t *buf, int size); - void (*add_read_packet)(struct NetDriverState *nd, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque); - /* tun specific data */ - int fd; - /* slirp specific data */ -} NetDriverState; + VLANState *vlan; +} NICInfo; extern int nb_nics; -extern NetDriverState nd_table[MAX_NICS]; - -void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size); -void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque); +extern NICInfo nd_table[MAX_NICS]; /* timers */ @@ -692,8 +711,8 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); /* ne2000.c */ -void isa_ne2000_init(int base, int irq, NetDriverState *nd); -void pci_ne2000_init(PCIBus *bus, NetDriverState *nd); +void isa_ne2000_init(int base, int irq, NICInfo *nd); +void pci_ne2000_init(PCIBus *bus, NICInfo *nd); /* pckbd.c */ @@ -781,7 +800,7 @@ void *iommu_init(uint32_t addr); uint32_t iommu_translate_local(void *opaque, uint32_t addr); /* lance.c */ -void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr); +void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr); /* tcx.c */ void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, -- cgit v1.2.3 From 41d03949e198d4ac32cd42419e2b978fb89db461 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 15 Nov 2005 23:02:53 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1623 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + qemu-doc.texi | 119 +++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 82 insertions(+), 38 deletions(-) diff --git a/Changelog b/Changelog index 6b8420fd9..6cc809097 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,7 @@ version 0.7.3: - Initial USB support - Linux host serial port access - Linux host low level parallel port access + - New network emulation code supporting VLANs. version 0.7.2: diff --git a/qemu-doc.texi b/qemu-doc.texi index 41b742278..d0b0b34d1 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -247,29 +247,56 @@ Network options: @table @option -@item -n script -Set TUN/TAP network init script [default=/etc/qemu-ifup]. This script -is launched to configure the host network interface (usually tun0) -corresponding to the virtual NE2000 card. +@item -net nic[,vlan=n][,macaddr=addr] +Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n} += 0 is the default). The NIC is currently an NE2000 on the PC +target. Optionally, the MAC address can be changed. If no +@option{-net} option is specified, a single NIC is created. + +@item -net user[,vlan=n] +Use the user mode network stack which requires not administrator +priviledge to run. This is the default if no @option{-net} option is +specified. + +@item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file] +Connect the host TAP network interface @var{name} to VLAN @var{n} and +use the network script @var{file} to configure it. The default +network script is @file{/etc/qemu-ifup}. If @var{name} is not +provided, the OS automatically provides one. @option{fd=h} can be +used to specify the handle of an already opened host TAP interface. Example: -@item -nics n +@example +qemu linux.img -net nic -net tap +@end example + +More complicated example (two NICs, each one connected to a TAP device) +@example +qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \ + -net nic,vlan=1 -net tap,vlan=1,ifname=tap1 +@end example -Simulate @var{n} network cards (the default is 1). -@item -macaddr addr +@item -net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port] -Set the mac address of the first interface (the format is -aa:bb:cc:dd:ee:ff in hexa). The mac address is incremented for each -new network interface. +Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual +machine using a TCP socket connection. If @option{listen} is +specified, QEMU waits for incoming connections on @var{port} +(@var{host} is optional). @option{connect} is used to connect to +another QEMU instance using the @option{listen} option. @option{fd=h} +specifies an already opened socket. -@item -tun-fd fd -Assumes @var{fd} talks to a tap/tun host network interface and use -it. Read @url{http://bellard.org/qemu/tetrinet.html} to have an -example of its use. +Example: +@example +# launch a first QEMU instance +qemu linux.img -net nic -net socket,listen=:1234 +# connect the VLAN 0 of this instance to the VLAN 0 of the first instance +qemu linux.img -net nic -net socket,connect=127.0.0.1:1234 +@end example -@item -user-net -Use the user mode network stack. This is the default if no tun/tap -network init script is found. +@item -net none +Indicate that no network devices should be configured. It is used to +override the default configuration which is activated if no +@option{-net} options are provided. @item -tftp prefix When using the user mode network stack, activate a built-in TFTP @@ -327,13 +354,9 @@ telnet localhost 5555 Then when you use on the host @code{telnet localhost 5555}, you connect to the guest telnet server. -@item -dummy-net -Use the dummy network stack: no packet will be received by the network -cards. - @end table -Linux boot specific. When using this options, you can use a given +Linux boot specific: When using these options, you can use a given Linux kernel without installing it in the disk image. It can be useful for easier testing of various kernels. @@ -521,7 +544,7 @@ show various information about the system state @table @option @item info network -show the network state +show the various VLANs and the associated devices @item info block show the block devices @item info registers @@ -700,36 +723,49 @@ command (or @key{C-a s} in the serial console). @section Network emulation -QEMU simulates up to 6 networks cards (NE2000 boards). Each card can -be connected to a specific host network interface. +QEMU can simulate several networks cards (NE2000 boards on the PC +target) and can connect them to an arbitrary number of Virtual Local +Area Networks (VLANs). Host TAP devices can be connected to any QEMU +VLAN. VLAN can be connected between separate instances of QEMU to +simulate large networks. For simpler usage, a non priviledged user mode +network stack can replace the TAP device to have a basic network +connection. + +@subsection VLANs -@subsection Using tun/tap network interface +QEMU simulates several VLANs. A VLAN can be symbolised as a virtual +connection between several network devices. These devices can be for +example QEMU virtual Ethernet cards or virtual Host ethernet devices +(TAP devices). -This is the standard way to emulate network. QEMU adds a virtual -network device on your host (called @code{tun0}), and you can then -configure it as if it was a real ethernet card. +@subsection Using TAP network interfaces + +This is the standard way to connect QEMU to a real network. QEMU adds +a virtual network device on your host (called @code{tapN}), and you +can then configure it as if it was a real ethernet card. As an example, you can download the @file{linux-test-xxx.tar.gz} archive and copy the script @file{qemu-ifup} in @file{/etc} and configure properly @code{sudo} so that the command @code{ifconfig} contained in @file{qemu-ifup} can be executed as root. You must verify -that your host kernel supports the TUN/TAP network interfaces: the +that your host kernel supports the TAP network interfaces: the device @file{/dev/net/tun} must be present. See @ref{direct_linux_boot} to have an example of network use with a -Linux distribution. +Linux distribution and @ref{sec_invocation} to have examples of +command lines using the TAP network interfaces. @subsection Using the user mode network stack -By using the option @option{-user-net} or if you have no tun/tap init -script, QEMU uses a completely user mode network stack (you don't need -root priviledge to use the virtual network). The virtual network -configuration is the following: +By using the option @option{-net user} (default configuration if no +@option{-net} option is specified), QEMU uses a completely user mode +network stack (you don't need root priviledge to use the virtual +network). The virtual network configuration is the following: @example -QEMU Virtual Machine <------> Firewall/DHCP server <-----> Internet - (10.0.2.x) | (10.0.2.2) + QEMU VLAN <------> Firewall/DHCP server <-----> Internet + | (10.0.2.2) | ----> DNS server (10.0.2.3) | @@ -738,7 +774,8 @@ QEMU Virtual Machine <------> Firewall/DHCP server <-----> Internet The QEMU VM behaves as if it was behind a firewall which blocks all incoming connections. You can use a DHCP client to automatically -configure the network in the QEMU VM. +configure the network in the QEMU VM. The DHCP server assign addresses +to the hosts starting from 10.0.2.15. In order to check that the user mode network is working, you can ping the address 10.0.2.2 and verify that you got an address in the range @@ -755,6 +792,12 @@ When using the @option{-redir} option, TCP or UDP connections can be redirected from the host to the guest. It allows for example to redirect X11, telnet or SSH connections. +@subsection Connecting VLANs between QEMU instances + +Using the @option{-net socket} option, it is possible to make VLANs +that span several QEMU instances. See @ref{sec_invocation} to have a +basic example. + @node direct_linux_boot @section Direct Linux Boot -- cgit v1.2.3 From 7e89463d4a1495bf943aa20013331950916a0f31 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Nov 2005 17:42:52 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1624 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index d0b0b34d1..7ec41f527 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -254,7 +254,7 @@ target. Optionally, the MAC address can be changed. If no @option{-net} option is specified, a single NIC is created. @item -net user[,vlan=n] -Use the user mode network stack which requires not administrator +Use the user mode network stack which requires no administrator priviledge to run. This is the default if no @option{-net} option is specified. @@ -288,9 +288,9 @@ specifies an already opened socket. Example: @example # launch a first QEMU instance -qemu linux.img -net nic -net socket,listen=:1234 +qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,listen=:1234 # connect the VLAN 0 of this instance to the VLAN 0 of the first instance -qemu linux.img -net nic -net socket,connect=127.0.0.1:1234 +qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,connect=127.0.0.1:1234 @end example @item -net none -- cgit v1.2.3 From 5e9ab4c4930cb4ebc157f2ab8eaa5f274c031aeb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Nov 2005 17:43:37 +0000 Subject: USB reset typo (Lonnie Mendez) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1625 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 0f0c185aa..732b76a81 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -191,7 +191,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) uhci_reset(s); return; } - if (val & UHCI_CMD_GRESET) { + if (val & UHCI_CMD_HCRESET) { uhci_reset(s); return; } -- cgit v1.2.3 From 2df3b95dbba21e68284409e570fbb372bdee8ab8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Nov 2005 17:47:39 +0000 Subject: target independent memory access functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1626 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 190 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 139 insertions(+), 51 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index be42bc9eb..55ccbea64 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -188,10 +188,10 @@ static inline void stb_p(void *ptr, int v) /* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the kernel handles unaligned load/stores may give better results, but it is a system wide setting : bad */ -#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)) +#if defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) /* conservative code for little endian unaligned accesses */ -static inline int lduw_p(void *ptr) +static inline int lduw_le_p(void *ptr) { #ifdef __powerpc__ int val; @@ -203,7 +203,7 @@ static inline int lduw_p(void *ptr) #endif } -static inline int ldsw_p(void *ptr) +static inline int ldsw_le_p(void *ptr) { #ifdef __powerpc__ int val; @@ -215,7 +215,7 @@ static inline int ldsw_p(void *ptr) #endif } -static inline int ldl_p(void *ptr) +static inline int ldl_le_p(void *ptr) { #ifdef __powerpc__ int val; @@ -227,7 +227,7 @@ static inline int ldl_p(void *ptr) #endif } -static inline uint64_t ldq_p(void *ptr) +static inline uint64_t ldq_le_p(void *ptr) { uint8_t *p = ptr; uint32_t v1, v2; @@ -236,7 +236,7 @@ static inline uint64_t ldq_p(void *ptr) return v1 | ((uint64_t)v2 << 32); } -static inline void stw_p(void *ptr, int v) +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)); @@ -247,7 +247,7 @@ static inline void stw_p(void *ptr, int v) #endif } -static inline void stl_p(void *ptr, int v) +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)); @@ -260,7 +260,7 @@ static inline void stl_p(void *ptr, int v) #endif } -static inline void stq_p(void *ptr, uint64_t v) +static inline void stq_le_p(void *ptr, uint64_t v) { uint8_t *p = ptr; stl_p(p, (uint32_t)v); @@ -269,45 +269,105 @@ static inline void stq_p(void *ptr, uint64_t v) /* float access */ -static inline float32 ldfl_p(void *ptr) +static inline float32 ldfl_le_p(void *ptr) { union { float32 f; uint32_t i; } u; - u.i = ldl_p(ptr); + u.i = ldl_le_p(ptr); return u.f; } -static inline void stfl_p(void *ptr, float32 v) +static inline void stfl_le_p(void *ptr, float32 v) { union { float32 f; uint32_t i; } u; u.f = v; - stl_p(ptr, u.i); + stl_le_p(ptr, u.i); } -static inline float64 ldfq_p(void *ptr) +static inline float64 ldfq_le_p(void *ptr) { CPU_DoubleU u; - u.l.lower = ldl_p(ptr); - u.l.upper = ldl_p(ptr + 4); + u.l.lower = ldl_le_p(ptr); + u.l.upper = ldl_le_p(ptr + 4); return u.d; } -static inline void stfq_p(void *ptr, float64 v) +static inline void stfq_le_p(void *ptr, float64 v) { CPU_DoubleU u; u.d = v; - stl_p(ptr, u.l.lower); - stl_p(ptr + 4, u.l.upper); + stl_le_p(ptr, u.l.lower); + stl_le_p(ptr + 4, u.l.upper); } -#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)) +#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 lduw_p(void *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; @@ -322,7 +382,7 @@ static inline int lduw_p(void *ptr) #endif } -static inline int ldsw_p(void *ptr) +static inline int ldsw_be_p(void *ptr) { #if defined(__i386__) int val; @@ -337,7 +397,7 @@ static inline int ldsw_p(void *ptr) #endif } -static inline int ldl_p(void *ptr) +static inline int ldl_be_p(void *ptr) { #if defined(__i386__) || defined(__x86_64__) int val; @@ -352,15 +412,15 @@ static inline int ldl_p(void *ptr) #endif } -static inline uint64_t ldq_p(void *ptr) +static inline uint64_t ldq_be_p(void *ptr) { uint32_t a,b; - a = ldl_p(ptr); - b = ldl_p(ptr+4); + a = ldl_be_p(ptr); + b = ldl_be_p(ptr+4); return (((uint64_t)a<<32)|b); } -static inline void stw_p(void *ptr, int v) +static inline void stw_be_p(void *ptr, int v) { #if defined(__i386__) asm volatile ("xchgb %b0, %h0\n" @@ -374,7 +434,7 @@ static inline void stw_p(void *ptr, int v) #endif } -static inline void stl_p(void *ptr, int v) +static inline void stl_be_p(void *ptr, int v) { #if defined(__i386__) || defined(__x86_64__) asm volatile ("bswap %0\n" @@ -390,108 +450,136 @@ static inline void stl_p(void *ptr, int v) #endif } -static inline void stq_p(void *ptr, uint64_t v) +static inline void stq_be_p(void *ptr, uint64_t v) { - stl_p(ptr, v >> 32); - stl_p(ptr + 4, v); + stl_be_p(ptr, v >> 32); + stl_be_p(ptr + 4, v); } /* float access */ -static inline float32 ldfl_p(void *ptr) +static inline float32 ldfl_be_p(void *ptr) { union { float32 f; uint32_t i; } u; - u.i = ldl_p(ptr); + u.i = ldl_be_p(ptr); return u.f; } -static inline void stfl_p(void *ptr, float32 v) +static inline void stfl_be_p(void *ptr, float32 v) { union { float32 f; uint32_t i; } u; u.f = v; - stl_p(ptr, u.i); + stl_be_p(ptr, u.i); } -static inline float64 ldfq_p(void *ptr) +static inline float64 ldfq_be_p(void *ptr) { CPU_DoubleU u; - u.l.upper = ldl_p(ptr); - u.l.lower = ldl_p(ptr + 4); + u.l.upper = ldl_be_p(ptr); + u.l.lower = ldl_be_p(ptr + 4); return u.d; } -static inline void stfq_p(void *ptr, float64 v) +static inline void stfq_be_p(void *ptr, float64 v) { CPU_DoubleU u; u.d = v; - stl_p(ptr, u.l.upper); - stl_p(ptr + 4, u.l.lower); + stl_be_p(ptr, u.l.upper); + stl_be_p(ptr + 4, u.l.lower); } #else -static inline int lduw_p(void *ptr) +static inline int lduw_be_p(void *ptr) { return *(uint16_t *)ptr; } -static inline int ldsw_p(void *ptr) +static inline int ldsw_be_p(void *ptr) { return *(int16_t *)ptr; } -static inline int ldl_p(void *ptr) +static inline int ldl_be_p(void *ptr) { return *(uint32_t *)ptr; } -static inline uint64_t ldq_p(void *ptr) +static inline uint64_t ldq_be_p(void *ptr) { return *(uint64_t *)ptr; } -static inline void stw_p(void *ptr, int v) +static inline void stw_be_p(void *ptr, int v) { *(uint16_t *)ptr = v; } -static inline void stl_p(void *ptr, int v) +static inline void stl_be_p(void *ptr, int v) { *(uint32_t *)ptr = v; } -static inline void stq_p(void *ptr, uint64_t v) +static inline void stq_be_p(void *ptr, uint64_t v) { *(uint64_t *)ptr = v; } /* float access */ -static inline float32 ldfl_p(void *ptr) +static inline float32 ldfl_be_p(void *ptr) { return *(float32 *)ptr; } -static inline float64 ldfq_p(void *ptr) +static inline float64 ldfq_be_p(void *ptr) { return *(float64 *)ptr; } -static inline void stfl_p(void *ptr, float32 v) +static inline void stfl_be_p(void *ptr, float32 v) { *(float32 *)ptr = v; } -static inline void stfq_p(void *ptr, float64 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 */ -- cgit v1.2.3 From 0b7a4a97119eefc2c39c5f34602df9e1cc0f493b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Nov 2005 18:17:16 +0000 Subject: DOS 6.22 fix (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1627 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vvfat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-vvfat.c b/block-vvfat.c index 7bce91e41..3409f883a 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -703,7 +703,7 @@ static int init_directory(BDRVVVFATState* s,const char* dirname) memset(&(s->first_sectors[0]),0,0x40*0x200); /* TODO: if FAT32, this is probably wrong */ - s->sectors_per_fat=0xfc; + s->sectors_per_fat=0xec; s->sectors_per_cluster=0x10; s->cluster_size=s->sectors_per_cluster*0x200; s->cluster=malloc(s->cluster_size); -- cgit v1.2.3 From c1942362bcb9e7255d25eec219b2a61d6581615e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 10:31:08 +0000 Subject: use direct jump only for jumps in the same page - stop translation after mtsr[in] git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1628 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c04c0ef99..1ca7cbc7e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1727,16 +1727,25 @@ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) /*** Branch ***/ -static inline void gen_jmp_tb(long tb, int n, uint32_t dest) -{ - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); - gen_op_set_T1(dest); - gen_op_b_T1(); - gen_op_set_T0(tb + n); - gen_op_exit_tb(); +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + TranslationBlock *tb; + tb = ctx->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + if (n == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_op_set_T1(dest); + gen_op_b_T1(); + gen_op_set_T0((long)tb + n); + gen_op_exit_tb(); + } else { + gen_op_set_T1(dest); + gen_op_b_T1(); + gen_op_set_T0(0); + gen_op_exit_tb(); + } } /* b ba bl bla */ @@ -1754,7 +1763,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) if (LK(ctx->opcode)) { gen_op_setlr(ctx->nip); } - gen_jmp_tb((long)ctx->tb, 0, target); + gen_goto_tb(ctx, 0, target); ctx->exception = EXCP_BRANCH; } @@ -1805,7 +1814,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) case 4: case 6: if (type == BCOND_IM) { - gen_jmp_tb((long)ctx->tb, 0, target); + gen_goto_tb(ctx, 0, target); } else { gen_op_b_T1(); } @@ -1847,9 +1856,9 @@ static inline void gen_bcond(DisasContext *ctx, int type) if (type == BCOND_IM) { int l1 = gen_new_label(); gen_op_jz_T0(l1); - gen_jmp_tb((long)ctx->tb, 0, target); + gen_goto_tb(ctx, 0, target); gen_set_label(l1); - gen_jmp_tb((long)ctx->tb, 1, ctx->nip); + gen_goto_tb(ctx, 1, ctx->nip); } else { gen_op_btest_T1(ctx->nip); } @@ -2269,6 +2278,7 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_sr(SR(ctx->opcode)); + RET_MTMSR(ctx); #endif } @@ -2285,6 +2295,7 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_store_srin(); + RET_MTMSR(ctx); #endif } @@ -2598,7 +2609,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #endif } if (ctx.exception == EXCP_NONE) { - gen_jmp_tb((long)ctx.tb, 0, ctx.nip); + gen_goto_tb(&ctx, 0, ctx.nip); } else if (ctx.exception != EXCP_BRANCH) { gen_op_set_T0(0); } -- cgit v1.2.3 From 6e256c935cbd5ce9bf1891477188549bbb43e55b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 10:32:05 +0000 Subject: use direct jump only for jumps in the same page git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1629 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 35 +++++++++++++++++++----------- target-i386/translate.c | 53 +++++++++++++++++++++++++++++---------------- target-mips/translate.c | 38 +++++++++++++++++++------------- target-sparc/translate.c | 56 +++++++++++++++++++++++++++--------------------- 4 files changed, 110 insertions(+), 72 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 96e7fd291..afb9b57c8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -903,16 +903,26 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) return 0; } -static inline void gen_jmp_tb(long tb, int n, uint32_t dest) +static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) { - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); - gen_op_movl_T0_im(dest); - gen_op_movl_r15_T0(); - gen_op_movl_T0_im(tb + n); - gen_op_exit_tb(); + TranslationBlock *tb; + + tb = s->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + if (n == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_op_movl_T0_im(dest); + gen_op_movl_r15_T0(); + gen_op_movl_T0_im((long)tb + n); + gen_op_exit_tb(); + } else { + gen_op_movl_T0_im(dest); + gen_op_movl_r15_T0(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + } } static inline void gen_jmp (DisasContext *s, uint32_t dest) @@ -924,8 +934,7 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) gen_op_movl_T0_im(dest); gen_bx(s); } else { - long tb = (long)s->tb; - gen_jmp_tb(tb, 0, dest); + gen_goto_tb(s, 0, dest); s->is_jmp = DISAS_TB_JUMP; } } @@ -2137,7 +2146,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, } else { switch(dc->is_jmp) { case DISAS_NEXT: - gen_jmp_tb((long)dc->tb, 1, dc->pc); + gen_goto_tb(dc, 1, dc->pc); break; default: case DISAS_JUMP: @@ -2152,7 +2161,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, } if (dc->condjmp) { gen_set_label(dc->condlabel); - gen_jmp_tb((long)dc->tb, 1, dc->pc); + gen_goto_tb(dc, 1, dc->pc); dc->condjmp = 0; } } diff --git a/target-i386/translate.c b/target-i386/translate.c index 0f6b0eb7c..dab037807 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1700,6 +1700,31 @@ static inline int insn_const_size(unsigned int ot) return 4; } +static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip) +{ + TranslationBlock *tb; + target_ulong pc; + + pc = s->cs_base + eip; + tb = s->tb; + /* NOTE: we handle the case where the TB spans two pages here */ + if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) || + (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) { + /* jump to same page: we can use a direct jump */ + if (tb_num == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_jmp_im(eip); + gen_op_movl_T0_im((long)tb + tb_num); + gen_op_exit_tb(); + } else { + /* jump to another page: currently not optimized */ + gen_jmp_im(eip); + gen_eob(s); + } +} + static inline void gen_jcc(DisasContext *s, int b, target_ulong val, target_ulong next_eip) { @@ -1779,8 +1804,10 @@ static inline void gen_jcc(DisasContext *s, int b, break; } - if (s->cc_op != CC_OP_DYNAMIC) + if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } if (!func) { gen_setcc_slow[jcc_op](); @@ -1797,16 +1824,10 @@ static inline void gen_jcc(DisasContext *s, int b, l1 = gen_new_label(); func(l1); - gen_op_goto_tb0(TBPARAM(tb)); - gen_jmp_im(next_eip); - gen_op_movl_T0_im((long)tb + 0); - gen_op_exit_tb(); + gen_goto_tb(s, 0, next_eip); gen_set_label(l1); - gen_op_goto_tb1(TBPARAM(tb)); - gen_jmp_im(val); - gen_op_movl_T0_im((long)tb + 1); - gen_op_exit_tb(); + gen_goto_tb(s, 1, val); s->is_jmp = 3; } else { @@ -2217,18 +2238,12 @@ static void gen_eob(DisasContext *s) direct call to the next block may occur */ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num) { - TranslationBlock *tb = s->tb; - if (s->jmp_opt) { - if (s->cc_op != CC_OP_DYNAMIC) + if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); - if (tb_num) - gen_op_goto_tb1(TBPARAM(tb)); - else - gen_op_goto_tb0(TBPARAM(tb)); - gen_jmp_im(eip); - gen_op_movl_T0_im((long)tb + tb_num); - gen_op_exit_tb(); + s->cc_op = CC_OP_DYNAMIC; + } + gen_goto_tb(s, tb_num, eip); s->is_jmp = 3; } else { gen_jmp_im(eip); diff --git a/target-mips/translate.c b/target-mips/translate.c index 5e54dd84b..2dc33af72 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -928,15 +928,23 @@ static void gen_trap (DisasContext *ctx, uint16_t opc, ctx->bstate = BS_STOP; } -static inline void gen_jmp_tb(long tb, int n, uint32_t dest) +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { - if (n == 0) - gen_op_goto_tb0(TBPARAM(tb)); - else - gen_op_goto_tb1(TBPARAM(tb)); - gen_op_save_pc(dest); - gen_op_set_T0(tb + n); - gen_op_exit_tb(); + TranslationBlock *tb; + tb = ctx->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + if (n == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_op_save_pc(dest); + gen_op_set_T0((long)tb + n); + gen_op_exit_tb(); + } else { + gen_op_save_pc(dest); + gen_op_set_T0(0); + gen_op_exit_tb(); + } } /* Branches (before delay slot) */ @@ -1035,7 +1043,7 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, case OPC_BLTZL: /* 0 < 0 likely */ /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever and skip"); - gen_jmp_tb((long)ctx->tb, 0, ctx->pc + 4); + gen_goto_tb(ctx, 0, ctx->pc + 4); return; case OPC_J: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; @@ -1278,7 +1286,7 @@ static void gen_blikely(DisasContext *ctx) l1 = gen_new_label(); gen_op_jnz_T2(l1); gen_op_save_state(ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); - gen_jmp_tb((long)ctx->tb, 1, ctx->pc + 4); + gen_goto_tb(ctx, 1, ctx->pc + 4); } static void decode_opc (DisasContext *ctx) @@ -1502,12 +1510,12 @@ static void decode_opc (DisasContext *ctx) case MIPS_HFLAG_B: /* unconditional branch */ MIPS_DEBUG("unconditional branch"); - gen_jmp_tb((long)ctx->tb, 0, ctx->btarget); + gen_goto_tb(ctx, 0, ctx->btarget); break; case MIPS_HFLAG_BL: /* blikely taken case */ MIPS_DEBUG("blikely branch taken"); - gen_jmp_tb((long)ctx->tb, 0, ctx->btarget); + gen_goto_tb(ctx, 0, ctx->btarget); break; case MIPS_HFLAG_BC: /* Conditional branch */ @@ -1516,9 +1524,9 @@ static void decode_opc (DisasContext *ctx) int l1; l1 = gen_new_label(); gen_op_jnz_T2(l1); - gen_jmp_tb((long)ctx->tb, 0, ctx->btarget); + gen_goto_tb(ctx, 0, ctx->btarget); gen_set_label(l1); - gen_jmp_tb((long)ctx->tb, 1, ctx->pc + 4); + gen_goto_tb(ctx, 1, ctx->pc + 4); } break; case MIPS_HFLAG_BR: @@ -1603,7 +1611,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { save_cpu_state(ctxp, 0); - gen_jmp_tb((long)ctx.tb, 0, ctx.pc); + gen_goto_tb(&ctx, 0, ctx.pc); } gen_op_reset_T0(); /* Generate the return instruction */ diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 9abcedda7..6340e1522 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -561,6 +561,32 @@ static inline void gen_movl_npc_im(target_ulong npc) #endif } +static inline void gen_goto_tb(DisasContext *s, int tb_num, + target_ulong pc, target_ulong npc) +{ + TranslationBlock *tb; + + tb = s->tb; + if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && + (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK)) { + /* jump to same page: we can use a direct jump */ + if (tb_num == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_jmp_im(pc); + gen_movl_npc_im(npc); + gen_op_movl_T0_im((long)tb + tb_num); + gen_op_exit_tb(); + } else { + /* jump to another page: currently not optimized */ + gen_jmp_im(pc); + gen_movl_npc_im(npc); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + } +} + static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2) { int l1; @@ -569,18 +595,10 @@ static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, targ gen_op_jz_T2_label(l1); - gen_op_goto_tb0(TBPARAM(tb)); - gen_jmp_im(pc1); - gen_movl_npc_im(pc1 + 4); - gen_op_movl_T0_im((long)tb + 0); - gen_op_exit_tb(); + gen_goto_tb(dc, 0, pc1, pc1 + 4); gen_set_label(l1); - gen_op_goto_tb1(TBPARAM(tb)); - gen_jmp_im(pc2); - gen_movl_npc_im(pc2 + 4); - gen_op_movl_T0_im((long)tb + 1); - gen_op_exit_tb(); + gen_goto_tb(dc, 1, pc2, pc2 + 4); } static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2) @@ -591,27 +609,15 @@ static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, tar gen_op_jz_T2_label(l1); - gen_op_goto_tb0(TBPARAM(tb)); - gen_jmp_im(pc2); - gen_movl_npc_im(pc1); - gen_op_movl_T0_im((long)tb + 0); - gen_op_exit_tb(); + gen_goto_tb(dc, 0, pc2, pc1); gen_set_label(l1); - gen_op_goto_tb1(TBPARAM(tb)); - gen_jmp_im(pc2 + 4); - gen_movl_npc_im(pc2 + 8); - gen_op_movl_T0_im((long)tb + 1); - gen_op_exit_tb(); + gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8); } static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc) { - gen_op_goto_tb0(TBPARAM(tb)); - gen_jmp_im(pc); - gen_movl_npc_im(npc); - gen_op_movl_T0_im((long)tb + 0); - gen_op_exit_tb(); + gen_goto_tb(dc, 0, pc, npc); } static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2) -- cgit v1.2.3 From a316d3353cefb6634f8007c8bb18f4744a66766b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 10:32:34 +0000 Subject: added CPU_COMMON and CPUState.tb_jmp_cache[] git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1630 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 29 +++++++++++++++++++++++++++++ target-arm/cpu.h | 17 ++--------------- target-i386/cpu.h | 21 +-------------------- target-mips/cpu.h | 20 ++------------------ target-ppc/cpu.h | 22 ++-------------------- target-sparc/cpu.h | 20 ++------------------ 6 files changed, 38 insertions(+), 91 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 912133ee6..fb4f8e8a2 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -77,6 +77,9 @@ typedef unsigned long ram_addr_t; #define MAX_BREAKPOINTS 32 +#define TB_JMP_CACHE_BITS 12 +#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) + #define CPU_TLB_SIZE 256 typedef struct CPUTLBEntry { @@ -91,4 +94,30 @@ typedef struct CPUTLBEntry { 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_read[2][CPU_TLB_SIZE]; \ + CPUTLBEntry tlb_write[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; \ + \ + /* user data */ \ + void *opaque; + + + #endif diff --git a/target-arm/cpu.h b/target-arm/cpu.h index ef7469d0c..fc49b5a99 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -60,22 +60,9 @@ typedef struct CPUARMState { jmp_buf jmp_env; int exception_index; int interrupt_request; - struct TranslationBlock *current_tb; int user_mode_only; uint32_t address; - /* ICE debug support. */ - target_ulong breakpoints[MAX_BREAKPOINTS]; - int nb_breakpoints; - int singlestep_enabled; - - /* 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 */ - unsigned long mem_write_vaddr; /* target virtual addr at which the - memory was written */ /* VFP coprocessor state. */ struct { float64 regs[16]; @@ -93,8 +80,8 @@ typedef struct CPUARMState { float_status fp_status; } vfp; - /* user data */ - void *opaque; + CPU_COMMON + } CPUARMState; CPUARMState *cpu_arm_init(void); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index f8373a102..cd12ca17e 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -497,28 +497,11 @@ typedef struct CPUX86State { int error_code; int exception_is_int; target_ulong exception_next_eip; - struct TranslationBlock *current_tb; /* currently executing TB */ target_ulong dr[8]; /* debug registers */ int interrupt_request; int user_mode_only; /* user mode only simulation */ - /* 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_read[2][CPU_TLB_SIZE]; - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; - - /* from this point: preserved by CPU reset */ - /* ice debug support */ - target_ulong breakpoints[MAX_BREAKPOINTS]; - int nb_breakpoints; - int singlestep_enabled; + CPU_COMMON /* processor features (e.g. for CPUID insn) */ uint32_t cpuid_level; @@ -538,8 +521,6 @@ typedef struct CPUX86State { /* in order to simplify APIC support, we leave this pointer to the user */ struct APICState *apic_state; - /* user data */ - void *opaque; } CPUX86State; CPUX86State *cpu_x86_init(void); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 8ed09d584..3314c9d91 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -162,24 +162,8 @@ struct CPUMIPSState { #define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */ target_ulong btarget; /* Jump / branch target */ int bcond; /* Branch condition (if needed) */ - 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) */ - target_ulong mem_write_pc; /* host pc at which the memory was - written */ - unsigned long mem_write_vaddr; /* target virtual addr at which the - memory was written */ - /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ - CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; - /* ice debug support */ - target_ulong breakpoints[MAX_BREAKPOINTS]; - int nb_breakpoints; - int singlestep_enabled; /* XXX: should use CPU single step mode instead */ - /* user data */ - void *opaque; + + CPU_COMMON }; #include "cpu-all.h" diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8dd9cc12d..fa7f524e9 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -493,19 +493,10 @@ struct CPUPPCState { /* floating point status and control register */ uint8_t fpscr[8]; - /* soft mmu support */ - /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ - CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + CPU_COMMON + int access_type; /* when a memory exception occurs, the access type is stored here */ - /* 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 */ - unsigned long mem_write_vaddr; /* target virtual addr at which the - memory was written */ /* MMU context */ /* Address space register */ @@ -564,22 +555,13 @@ struct CPUPPCState { /* Those resources are used only in Qemu core */ jmp_buf jmp_env; int user_mode_only; /* user mode only simulation */ - struct TranslationBlock *current_tb; /* currently executing TB */ uint32_t hflags; - /* ice debug support */ - target_ulong breakpoints[MAX_BREAKPOINTS]; - int nb_breakpoints; - int singlestep_enabled; /* XXX: should use CPU single step mode instead */ - /* Power management */ int power_mode; /* temporary hack to handle OSI calls (only used if non NULL) */ int (*osi_call)(struct CPUPPCState *env); - - /* user data */ - void *opaque; }; /*****************************************************************************/ diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 999d5d7e6..baff0c460 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -166,21 +166,11 @@ typedef struct CPUSPARCState { int exception_index; int interrupt_index; int interrupt_request; - struct TranslationBlock *current_tb; - void *opaque; /* NOTE: we allow 8 more registers to handle wrapping */ target_ulong regbase[NWINDOWS * 16 + 8]; - /* 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 (may have 2 = kernel code, 3 = user code ?) */ - CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + CPU_COMMON + /* MMU regs */ #if defined(TARGET_SPARC64) uint64_t lsu; @@ -222,12 +212,6 @@ typedef struct CPUSPARCState { #if !defined(TARGET_SPARC64) && !defined(reg_T2) target_ulong t2; #endif - - /* ice debug support */ - target_ulong breakpoints[MAX_BREAKPOINTS]; - int nb_breakpoints; - int singlestep_enabled; /* XXX: should use CPU single step mode instead */ - } CPUSPARCState; #if defined(TARGET_SPARC64) #define GET_FSR32(env) (env->fsr & 0xcfc1ffff) -- cgit v1.2.3 From 313adae9051ce95fa6a4c6dc9cb2bda3a4a425fc Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 10:33:00 +0000 Subject: removed unneeded code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1631 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 66c26041c..c3b02d8cc 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -806,7 +806,7 @@ void do_compute_hflags (CPUPPCState *env) } void do_store_msr (CPUPPCState *env, target_ulong value) - { +{ value &= env->msr_mask; if (((value >> MSR_IR) & 1) != msr_ir || ((value >> MSR_DR) & 1) != msr_dr) { @@ -1436,15 +1436,5 @@ void do_interrupt (CPUState *env) /* Jump to handler */ env->nip = excp; env->exception_index = EXCP_NONE; -#if 0 - /* ensure that no TB jump will be modified as - the program flow was changed */ -#ifdef __sparc__ - tmp_T0 = 0; -#else - T0 = 0; -#endif -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; } #endif /* !CONFIG_USER_ONLY */ -- cgit v1.2.3 From 8a40a180d39ec535b16a9456965a59722950cee2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 10:35:40 +0000 Subject: make the TB cache independent of MMU mappings (faster MMU context switches and needed for SMP support) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1632 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 298 +++++++++++++++++++++++++++++++++--------------------------- exec-all.h | 35 +------- exec.c | 299 ++++++++----------------------------------------------------- 3 files changed, 206 insertions(+), 426 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index bdfc86550..9f6487adf 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -73,6 +73,137 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) 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 */ + T0 = 0; + } + 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: + 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; + } + /* 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); + cs_base = 0; + pc = env->regs[15]; +#elif defined(TARGET_SPARC) +#ifdef TARGET_SPARC64 + flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); +#else + flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); +#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_HFLAGS_TMASK; + cs_base = NULL; + 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); + } + return tb; +} + + /* main execution loop */ int cpu_exec(CPUState *env1) @@ -115,12 +246,10 @@ int cpu_exec(CPUState *env1) #ifdef __sparc__ int saved_i7, tmp_T0; #endif - int code_gen_size, ret, interrupt_request; + int ret, interrupt_request; void (*gen_func)(void); - TranslationBlock *tb, **ptb; - target_ulong cs_base, pc; + TranslationBlock *tb; uint8_t *tc_ptr; - unsigned int flags; /* first we save global registers */ saved_env = env; @@ -290,19 +419,29 @@ int cpu_exec(CPUState *env1) } #endif if (msr_ee != 0) { - if ((interrupt_request & CPU_INTERRUPT_HARD)) { + 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; - } 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_HARD; +#ifdef __sparc__ + 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; - } +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif + } } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -316,6 +455,11 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif } #elif defined(TARGET_SPARC) if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -329,6 +473,11 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_HARD; do_interrupt(env->interrupt_index); env->interrupt_index = 0; +#ifdef __sparc__ + tmp_T0 = 0; +#else + T0 = 0; +#endif } } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); @@ -399,123 +548,7 @@ int cpu_exec(CPUState *env1) #endif } #endif - /* 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); - cs_base = 0; - pc = env->regs[15]; -#elif defined(TARGET_SPARC) -#ifdef TARGET_SPARC64 - flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); -#else - flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); -#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_HFLAGS_TMASK; - cs_base = NULL; - pc = env->PC; -#else -#error unsupported CPU -#endif - tb = tb_find(&ptb, pc, cs_base, - flags); - if (!tb) { - TranslationBlock **ptb1; - unsigned int h; - target_ulong phys_pc, phys_page1, phys_page2, virt_page2; - - - 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 */ - ptb = &tb_hash[tb_hash_func(pc)]; - T0 = 0; - } - 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: - 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 */ - ptb = &tb_hash[tb_hash_func(pc)]; - while (*ptb != NULL) - ptb = &(*ptb)->hash_next; - T0 = 0; - } - /* we add the TB in the virtual pc hash table */ - *ptb = tb; - tb->hash_next = NULL; - tb_link(tb); - spin_unlock(&tb_lock); - } + tb = tb_find_fast(); #ifdef DEBUG_EXEC if ((loglevel & CPU_LOG_EXEC)) { fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", @@ -526,9 +559,12 @@ int cpu_exec(CPUState *env1) #ifdef __sparc__ T0 = tmp_T0; #endif - /* see if we can patch the calling TB. */ + /* 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 (T0 != 0 && + 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) diff --git a/exec-all.h b/exec-all.h index 380300698..874e9d9a3 100644 --- a/exec-all.h +++ b/exec-all.h @@ -105,9 +105,6 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, #define CODE_GEN_MAX_SIZE 65536 #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ -#define CODE_GEN_HASH_BITS 15 -#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) - #define CODE_GEN_PHYS_HASH_BITS 15 #define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) @@ -167,7 +164,6 @@ typedef struct TranslationBlock { #define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */ uint8_t *tc_ptr; /* pointer to the translated code */ - struct TranslationBlock *hash_next; /* next matching tb for virtual address */ /* next matching tb for physical address. */ struct TranslationBlock *phys_hash_next; /* first and second physical page containing code. The lower bit @@ -191,9 +187,9 @@ typedef struct TranslationBlock { struct TranslationBlock *jmp_first; } TranslationBlock; -static inline unsigned int tb_hash_func(target_ulong pc) +static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) { - return pc & (CODE_GEN_HASH_SIZE - 1); + return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1); } static inline unsigned int tb_phys_hash_func(unsigned long pc) @@ -203,41 +199,14 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc) TranslationBlock *tb_alloc(target_ulong pc); void tb_flush(CPUState *env); -void tb_link(TranslationBlock *tb); void tb_link_phys(TranslationBlock *tb, target_ulong phys_pc, target_ulong phys_page2); -extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; extern uint8_t *code_gen_ptr; -/* find a translation block in the translation cache. If not found, - return NULL and the pointer to the last element of the list in pptb */ -static inline TranslationBlock *tb_find(TranslationBlock ***pptb, - target_ulong pc, - target_ulong cs_base, - unsigned int flags) -{ - TranslationBlock **ptb, *tb; - unsigned int h; - - h = tb_hash_func(pc); - ptb = &tb_hash[h]; - for(;;) { - tb = *ptb; - if (!tb) - break; - if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) - return tb; - ptb = &tb->hash_next; - } - *pptb = ptb; - return NULL; -} - - #if defined(USE_DIRECT_JUMP) #if defined(__powerpc__) diff --git a/exec.c b/exec.c index a6f973eda..8aed3d00c 100644 --- a/exec.c +++ b/exec.c @@ -61,7 +61,6 @@ #endif TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; -TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; int nb_tbs; /* any access to the tbs or the page table must use this lock */ @@ -92,20 +91,6 @@ typedef struct PhysPageDesc { uint32_t phys_offset; } PhysPageDesc; -/* Note: the VirtPage handling is absolete and will be suppressed - ASAP */ -typedef struct VirtPageDesc { - /* physical address of code page. It is valid only if 'valid_tag' - matches 'virt_valid_tag' */ - target_ulong phys_addr; - unsigned int valid_tag; -#if !defined(CONFIG_SOFTMMU) - /* original page access rights. It is valid only if 'valid_tag' - matches 'virt_valid_tag' */ - unsigned int prot; -#endif -} VirtPageDesc; - #define L2_BITS 10 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) @@ -123,17 +108,6 @@ unsigned long qemu_host_page_mask; static PageDesc *l1_map[L1_SIZE]; PhysPageDesc **l1_phys_map; -#if !defined(CONFIG_USER_ONLY) -#if TARGET_LONG_BITS > 32 -#define VIRT_L_BITS 9 -#define VIRT_L_SIZE (1 << VIRT_L_BITS) -static void *l1_virt_map[VIRT_L_SIZE]; -#else -static VirtPageDesc *l1_virt_map[L1_SIZE]; -#endif -static unsigned int virt_valid_tag; -#endif - /* io memory support */ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; @@ -190,9 +164,6 @@ static void page_init(void) while ((1 << qemu_host_page_bits) < qemu_host_page_size) qemu_host_page_bits++; qemu_host_page_mask = ~(qemu_host_page_size - 1); -#if !defined(CONFIG_USER_ONLY) - virt_valid_tag = 1; -#endif l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *)); memset(l1_phys_map, 0, L1_SIZE * sizeof(void *)); } @@ -266,120 +237,6 @@ static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, target_ulong vaddr); static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, target_ulong vaddr); - -static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc) -{ -#if TARGET_LONG_BITS > 32 - void **p, **lp; - - p = l1_virt_map; - lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); - p = *lp; - if (!p) { - if (!alloc) - return NULL; - p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); - *lp = p; - } - lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); - p = *lp; - if (!p) { - if (!alloc) - return NULL; - p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); - *lp = p; - } - lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); - p = *lp; - if (!p) { - if (!alloc) - return NULL; - p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); - *lp = p; - } - lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); - p = *lp; - if (!p) { - if (!alloc) - return NULL; - p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); - *lp = p; - } - lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); - p = *lp; - if (!p) { - if (!alloc) - return NULL; - p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE); - *lp = p; - } - return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1)); -#else - VirtPageDesc *p, **lp; - - lp = &l1_virt_map[index >> L2_BITS]; - p = *lp; - if (!p) { - /* allocate if not found */ - if (!alloc) - return NULL; - p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE); - *lp = p; - } - return p + (index & (L2_SIZE - 1)); -#endif -} - -static inline VirtPageDesc *virt_page_find(target_ulong index) -{ - return virt_page_find_alloc(index, 0); -} - -#if TARGET_LONG_BITS > 32 -static void virt_page_flush_internal(void **p, int level) -{ - int i; - if (level == 0) { - VirtPageDesc *q = (VirtPageDesc *)p; - for(i = 0; i < VIRT_L_SIZE; i++) - q[i].valid_tag = 0; - } else { - level--; - for(i = 0; i < VIRT_L_SIZE; i++) { - if (p[i]) - virt_page_flush_internal(p[i], level); - } - } -} -#endif - -static void virt_page_flush(void) -{ - virt_valid_tag++; - - if (virt_valid_tag == 0) { - virt_valid_tag = 1; -#if TARGET_LONG_BITS > 32 - virt_page_flush_internal(l1_virt_map, 5); -#else - { - int i, j; - VirtPageDesc *p; - for(i = 0; i < L1_SIZE; i++) { - p = l1_virt_map[i]; - if (p) { - for(j = 0; j < L2_SIZE; j++) - p[j].valid_tag = 0; - } - } - } -#endif - } -} -#else -static void virt_page_flush(void) -{ -} #endif void cpu_exec_init(void) @@ -429,8 +286,7 @@ void tb_flush(CPUState *env) nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); #endif nb_tbs = 0; - memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); - virt_page_flush(); + memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); page_flush_tb(); @@ -566,28 +422,36 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); } -static inline void tb_invalidate(TranslationBlock *tb) +static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) { + PageDesc *p; unsigned int h, n1; - TranslationBlock *tb1, *tb2, **ptb; + target_ulong phys_pc; + TranslationBlock *tb1, *tb2; + /* remove the TB from the hash list */ + phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); + h = tb_phys_hash_func(phys_pc); + tb_remove(&tb_phys_hash[h], tb, + offsetof(TranslationBlock, phys_hash_next)); + + /* remove the TB from the page list */ + if (tb->page_addr[0] != page_addr) { + p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); + tb_page_remove(&p->first_tb, tb); + invalidate_page_bitmap(p); + } + if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) { + p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); + tb_page_remove(&p->first_tb, tb); + invalidate_page_bitmap(p); + } + tb_invalidated_flag = 1; /* remove the TB from the hash list */ - h = tb_hash_func(tb->pc); - ptb = &tb_hash[h]; - for(;;) { - tb1 = *ptb; - /* NOTE: the TB is not necessarily linked in the hash. It - indicates that it is not currently used */ - if (tb1 == NULL) - return; - if (tb1 == tb) { - *ptb = tb1->hash_next; - break; - } - ptb = &tb1->hash_next; - } + h = tb_jmp_cache_hash_func(tb->pc); + cpu_single_env->tb_jmp_cache[h] = NULL; /* suppress this TB from the two jump lists */ tb_jmp_remove(tb, 0); @@ -606,33 +470,7 @@ static inline void tb_invalidate(TranslationBlock *tb) tb1 = tb2; } tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ -} - -static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) -{ - PageDesc *p; - unsigned int h; - target_ulong phys_pc; - - /* remove the TB from the hash list */ - phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); - h = tb_phys_hash_func(phys_pc); - tb_remove(&tb_phys_hash[h], tb, - offsetof(TranslationBlock, phys_hash_next)); - - /* remove the TB from the page list */ - if (tb->page_addr[0] != page_addr) { - p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); - tb_page_remove(&p->first_tb, tb); - invalidate_page_bitmap(p); - } - if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) { - p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); - tb_page_remove(&p->first_tb, tb); - invalidate_page_bitmap(p); - } - tb_invalidate(tb); tb_phys_invalidate_count++; } @@ -1025,57 +863,6 @@ void tb_link_phys(TranslationBlock *tb, tb_alloc_page(tb, 1, phys_page2); else tb->page_addr[1] = -1; -#ifdef DEBUG_TB_CHECK - tb_page_check(); -#endif -} - -/* link the tb with the other TBs */ -void tb_link(TranslationBlock *tb) -{ -#if !defined(CONFIG_USER_ONLY) - { - VirtPageDesc *vp; - target_ulong addr; - - /* save the code memory mappings (needed to invalidate the code) */ - addr = tb->pc & TARGET_PAGE_MASK; - vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); -#ifdef DEBUG_TLB_CHECK - if (vp->valid_tag == virt_valid_tag && - vp->phys_addr != tb->page_addr[0]) { - printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n", - addr, tb->page_addr[0], vp->phys_addr); - } -#endif - vp->phys_addr = tb->page_addr[0]; - if (vp->valid_tag != virt_valid_tag) { - vp->valid_tag = virt_valid_tag; -#if !defined(CONFIG_SOFTMMU) - vp->prot = 0; -#endif - } - - if (tb->page_addr[1] != -1) { - addr += TARGET_PAGE_SIZE; - vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); -#ifdef DEBUG_TLB_CHECK - if (vp->valid_tag == virt_valid_tag && - vp->phys_addr != tb->page_addr[1]) { - printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n", - addr, tb->page_addr[1], vp->phys_addr); - } -#endif - vp->phys_addr = tb->page_addr[1]; - if (vp->valid_tag != virt_valid_tag) { - vp->valid_tag = virt_valid_tag; -#if !defined(CONFIG_SOFTMMU) - vp->prot = 0; -#endif - } - } - } -#endif tb->jmp_first = (TranslationBlock *)((long)tb | 2); tb->jmp_next[0] = NULL; @@ -1091,6 +878,10 @@ void tb_link(TranslationBlock *tb) tb_reset_jump(tb, 0); if (tb->tb_next_offset[1] != 0xffff) tb_reset_jump(tb, 1); + +#ifdef DEBUG_TB_CHECK + tb_page_check(); +#endif } /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < @@ -1396,8 +1187,7 @@ void tlb_flush(CPUState *env, int flush_global) env->tlb_write[1][i].address = -1; } - virt_page_flush(); - memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); + memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); #if !defined(CONFIG_SOFTMMU) munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); @@ -1419,9 +1209,7 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) void tlb_flush_page(CPUState *env, target_ulong addr) { - int i, n; - VirtPageDesc *vp; - PageDesc *p; + int i; TranslationBlock *tb; #if defined(DEBUG_TLB) @@ -1438,26 +1226,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr) tlb_flush_entry(&env->tlb_read[1][i], addr); tlb_flush_entry(&env->tlb_write[1][i], addr); - /* remove from the virtual pc hash table all the TB at this - virtual address */ - - vp = virt_page_find(addr >> TARGET_PAGE_BITS); - if (vp && vp->valid_tag == virt_valid_tag) { - p = page_find(vp->phys_addr >> TARGET_PAGE_BITS); - if (p) { - /* we remove all the links to the TBs in this virtual page */ - tb = p->first_tb; - while (tb != NULL) { - n = (long)tb & 3; - tb = (TranslationBlock *)((long)tb & ~3); - if ((tb->pc & TARGET_PAGE_MASK) == addr || - ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) { - tb_invalidate(tb); - } - tb = tb->page_next[n]; - } + for(i = 0; i < TB_JMP_CACHE_SIZE; i++) { + tb = env->tb_jmp_cache[i]; + if (tb && + ((tb->pc & TARGET_PAGE_MASK) == addr || + ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) { + env->tb_jmp_cache[i] = NULL; } - vp->valid_tag = 0; } #if !defined(CONFIG_SOFTMMU) -- cgit v1.2.3 From 546754dc1d799ebfba1b2654a9a75541e9187674 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 16:20:39 +0000 Subject: pcm endianness is now explicit (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1633 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adlib.c | 7 ++++--- hw/es1370.c | 6 ++++-- hw/sb16.c | 9 ++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/hw/adlib.c b/hw/adlib.c index fa2a03dff..f482d1fa8 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -310,7 +310,8 @@ int Adlib_init (AudioState *audio) "adlib", s, adlib_callback, - &as + &as, + 0 /* XXX: little endian? */ ); if (!s->voice) { Adlib_fini (s); @@ -321,8 +322,8 @@ int Adlib_init (AudioState *audio) s->mixbuf = qemu_mallocz (s->samples << SHIFT); if (!s->mixbuf) { - dolog ("not enough memory for adlib mixing buffer (%d)\n", - s->samples << SHIFT); + dolog ("Could not allocate mixing buffer, %d samples (each %d bytes)\n", + s->samples, 1 << SHIFT); Adlib_fini (s); return -1; } diff --git a/hw/es1370.c b/hw/es1370.c index 217fd30b5..9fddd9d8b 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -432,7 +432,8 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) "es1370.adc", s, es1370_adc_callback, - &as + &as, + 0 /* little endian */ ); } else { @@ -443,7 +444,8 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) i ? "es1370.dac2" : "es1370.dac1", s, i ? es1370_dac2_callback : es1370_dac1_callback, - &as + &as, + 0 /* litle endian */ ); } } diff --git a/hw/sb16.c b/hw/sb16.c index 8c633c310..f7b12e611 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -254,7 +254,8 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) "sb16", s, SB_audio_callback, - &as + &as, + 0 /* little endian */ ); } @@ -348,7 +349,8 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) "sb16", s, SB_audio_callback, - &as + &as, + 0 /* little endian */ ); } @@ -1340,7 +1342,8 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) "sb16", s, SB_audio_callback, - &as + &as, + 0 /* little endian */ ); } -- cgit v1.2.3 From 509035303d2dc77e96c857bedf3de472440ef76b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 16:22:16 +0000 Subject: wav finalization fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1634 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/wavaudio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 4cc9ca7f8..18d2bb0c7 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -167,11 +167,10 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) static void wav_fini_out (HWVoiceOut *hw) { WAVVoiceOut *wav = (WAVVoiceOut *) hw; - int stereo = hw->info.nchannels == 2; uint8_t rlen[4]; uint8_t dlen[4]; - uint32_t rifflen = (wav->total_samples << stereo) + 36; - uint32_t datalen = wav->total_samples << stereo; + uint32_t datalen = wav->total_samples << hw->info.shift; + uint32_t rifflen = datalen + 36; if (!wav->f) { return; -- cgit v1.2.3 From 5e941d4b51dd0888f4003e838c7e7499aa9e8a62 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 16:24:09 +0000 Subject: workaround for atexit - buffer size API change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1635 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/coreaudio.c | 138 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 44 deletions(-) diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 75e2b7d61..6afc55cb2 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -33,17 +33,19 @@ struct { int buffer_frames; + int isAtexit; } conf = { - .buffer_frames = 512 + .buffer_frames = 512, + .isAtexit = 0 }; typedef struct coreaudioVoiceOut { HWVoiceOut hw; pthread_mutex_t mutex; + int isAtexit; AudioDeviceID outputDeviceID; - UInt32 audioDevicePropertyBufferSize; + UInt32 audioDevicePropertyBufferFrameSize; AudioStreamBasicDescription outputStreamBasicDescription; - int isPlaying; int live; int decr; int rpos; @@ -139,6 +141,26 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 ( coreaudio_logstatus (status); } +static inline UInt32 isPlaying (AudioDeviceID outputDeviceID) +{ + OSStatus status; + UInt32 result = 0; + UInt32 propertySize = sizeof(outputDeviceID); + status = AudioDeviceGetProperty( + outputDeviceID, 0, 0, + kAudioDevicePropertyDeviceIsRunning, &propertySize, &result); + if (status != kAudioHardwareNoError) { + coreaudio_logerr(status, + "Could not determine whether Device is playing\n"); + } + return result; +} + +static void coreaudio_atexit (void) +{ + conf.isAtexit = 1; +} + static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name) { int err; @@ -203,7 +225,7 @@ static OSStatus audioDeviceIOProc( const AudioTimeStamp* inOutputTime, void* hwptr) { - unsigned int frame, frameCount; + UInt32 frame, frameCount; float *out = outOutputData->mBuffers[0].mData; HWVoiceOut *hw = hwptr; coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr; @@ -222,7 +244,7 @@ static OSStatus audioDeviceIOProc( return 0; } - frameCount = conf.buffer_frames; + frameCount = core->audioDevicePropertyBufferFrameSize; live = core->live; /* if there are not enough samples, set signal and return */ @@ -254,7 +276,7 @@ static OSStatus audioDeviceIOProc( /* cleanup */ mixeng_clear (src, frameCount); rpos = (rpos + frameCount) % hw->samples; - core->decr = frameCount; + core->decr += frameCount; core->rpos = rpos; coreaudio_unlock (core, "audioDeviceIOProc"); @@ -274,7 +296,8 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) int err; int bits = 8; int endianess = 0; - const char *typ = "DAC"; + const char *typ = "playback"; + AudioValueRange frameRange; /* create mutex */ err = pthread_mutex_init(&core->mutex, NULL); @@ -312,40 +335,65 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) return -1; } - /* set Buffersize to conf.buffer_frames frames */ - propertySize = sizeof(core->audioDevicePropertyBufferSize); - core->audioDevicePropertyBufferSize = - conf.buffer_frames * sizeof(float) << (as->nchannels == 2); + /* get minimum and maximum buffer frame sizes */ + propertySize = sizeof(frameRange); + status = AudioDeviceGetProperty( + core->outputDeviceID, + 0, + 0, + kAudioDevicePropertyBufferFrameSizeRange, + &propertySize, + &frameRange); + if (status != kAudioHardwareNoError) { + coreaudio_logerr2 (status, typ, + "Could not get device buffer frame range\n"); + return -1; + } + + if (frameRange.mMinimum > conf.buffer_frames) { + core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum; + dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum); + } + else if (frameRange.mMaximum < conf.buffer_frames) { + core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum; + dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum); + } + else { + core->audioDevicePropertyBufferFrameSize = conf.buffer_frames; + } + + /* set Buffer Frame Size */ + propertySize = sizeof(core->audioDevicePropertyBufferFrameSize); status = AudioDeviceSetProperty( core->outputDeviceID, NULL, 0, false, - kAudioDevicePropertyBufferSize, + kAudioDevicePropertyBufferFrameSize, propertySize, - &core->audioDevicePropertyBufferSize); + &core->audioDevicePropertyBufferFrameSize); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, - "Could not set device buffer size %d\n", - kAudioDevicePropertyBufferSize); + "Could not set device buffer frame size %ld\n", + core->audioDevicePropertyBufferFrameSize); return -1; } - /* get Buffersize */ - propertySize = sizeof(core->audioDevicePropertyBufferSize); + /* get Buffer Frame Size */ + propertySize = sizeof(core->audioDevicePropertyBufferFrameSize); status = AudioDeviceGetProperty( core->outputDeviceID, 0, false, - kAudioDevicePropertyBufferSize, + kAudioDevicePropertyBufferFrameSize, &propertySize, - &core->audioDevicePropertyBufferSize); + &core->audioDevicePropertyBufferFrameSize); if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Could not get device buffer size\n"); + coreaudio_logerr2 (status, typ, + "Could not get device buffer frame size\n"); return -1; } - hw->samples = (core->audioDevicePropertyBufferSize / sizeof (float)) - >> (as->nchannels == 2); + hw->samples = 4 * core->audioDevicePropertyBufferFrameSize; /* get StreamFormat */ propertySize = sizeof(core->outputStreamBasicDescription); @@ -364,7 +412,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) } /* set Samplerate */ - core->outputStreamBasicDescription.mSampleRate = (Float64)as->freq; + core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq; propertySize = sizeof(core->outputStreamBasicDescription); status = AudioDeviceSetProperty( core->outputDeviceID, @@ -390,7 +438,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) } /* start Playback */ - if (!core->isPlaying) { + if (!isPlaying(core->outputDeviceID)) { status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { coreaudio_logerr2 (status, typ, "Could not start playback\n"); @@ -398,7 +446,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) core->outputDeviceID = kAudioDeviceUnknown; return -1; } - core->isPlaying = 1; } return 0; @@ -410,19 +457,21 @@ static void coreaudio_fini_out (HWVoiceOut *hw) int err; coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; - /* stop playback */ - if (core->isPlaying) { - status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not stop playback\n"); + if (!conf.isAtexit) { + /* stop playback */ + if (isPlaying(core->outputDeviceID)) { + status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); + if (status != kAudioHardwareNoError) { + coreaudio_logerr (status, "Could not stop playback\n"); + } } - core->isPlaying = 0; - } - /* remove callback */ - status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not remove IOProc\n"); + /* remove callback */ + status = AudioDeviceRemoveIOProc(core->outputDeviceID, + audioDeviceIOProc); + if (status != kAudioHardwareNoError) { + coreaudio_logerr (status, "Could not remove IOProc\n"); + } } core->outputDeviceID = kAudioDeviceUnknown; @@ -441,23 +490,23 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) switch (cmd) { case VOICE_ENABLE: /* start playback */ - if (!core->isPlaying) { + if (!isPlaying(core->outputDeviceID)) { status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc); if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not unpause playback\n"); + coreaudio_logerr (status, "Could not resume playback\n"); } - core->isPlaying = 1; } break; case VOICE_DISABLE: /* stop playback */ - if (core->isPlaying) { - status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not pause playback\n"); + if (!conf.isAtexit) { + if (isPlaying(core->outputDeviceID)) { + status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc); + if (status != kAudioHardwareNoError) { + coreaudio_logerr (status, "Could not pause playback\n"); + } } - core->isPlaying = 0; } break; } @@ -466,6 +515,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) static void *coreaudio_audio_init (void) { + atexit(coreaudio_atexit); return &coreaudio_audio_init; } -- cgit v1.2.3 From 571ec3d68ddfa230f1c60eba1f7e24f5a3ffb03b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 16:24:34 +0000 Subject: audio merge (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1636 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 218 ++++++++++++++++++------------- audio/audio.c | 348 +++++++++---------------------------------------- audio/audio.h | 6 +- audio/audio_int.h | 2 +- audio/audio_template.h | 262 +++++++++++++++++++++++++++---------- audio/ossaudio.c | 8 +- 6 files changed, 396 insertions(+), 448 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index f7748ca82..3ab264e01 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -31,15 +31,12 @@ typedef struct ALSAVoiceOut { HWVoiceOut hw; void *pcm_buf; snd_pcm_t *handle; - int can_pause; - int was_enabled; } ALSAVoiceOut; typedef struct ALSAVoiceIn { HWVoiceIn hw; snd_pcm_t *handle; void *pcm_buf; - int can_pause; } ALSAVoiceIn; static struct { @@ -58,6 +55,7 @@ static struct { int buffer_size_out_overriden; int period_size_out_overriden; + int verbose; } conf = { #ifdef HIGH_LATENCY .size_in_usec_in = 1, @@ -73,8 +71,8 @@ static struct { #else #define DEFAULT_BUFFER_SIZE 1024 #define DEFAULT_PERIOD_SIZE 256 - .buffer_size_in = DEFAULT_BUFFER_SIZE, - .period_size_in = DEFAULT_PERIOD_SIZE, + .buffer_size_in = DEFAULT_BUFFER_SIZE * 4, + .period_size_in = DEFAULT_PERIOD_SIZE * 4, .buffer_size_out = DEFAULT_BUFFER_SIZE, .period_size_out = DEFAULT_PERIOD_SIZE, .buffer_size_in_overriden = 0, @@ -82,7 +80,8 @@ static struct { .period_size_in_overriden = 0, .period_size_out_overriden = 0, #endif - .threshold = 0 + .threshold = 0, + .verbose = 0 }; struct alsa_params_req { @@ -97,7 +96,6 @@ struct alsa_params_obt { int freq; audfmt_e fmt; int nchannels; - int can_pause; snd_pcm_uframes_t samples; }; @@ -474,12 +472,6 @@ static int alsa_open (int in, struct alsa_params_req *req, goto err; } - obt->can_pause = snd_pcm_hw_params_can_pause (hw_params); - if (obt->can_pause < 0) { - alsa_logerr (err, "Could not get pause capability for %s\n", typ); - obt->can_pause = 0; - } - if (!in && conf.threshold) { snd_pcm_uframes_t threshold; int bytes_per_sec; @@ -527,6 +519,28 @@ static int alsa_recover (snd_pcm_t *handle) return 0; } +static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle) +{ + snd_pcm_sframes_t avail; + + avail = snd_pcm_avail_update (handle); + if (avail < 0) { + if (avail == -EPIPE) { + if (!alsa_recover (handle)) { + avail = snd_pcm_avail_update (handle); + } + } + + if (avail < 0) { + alsa_logerr (avail, + "Could not obtain number of available frames\n"); + return -1; + } + } + + return avail; +} + static int alsa_run_out (HWVoiceOut *hw) { ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; @@ -541,57 +555,53 @@ static int alsa_run_out (HWVoiceOut *hw) return 0; } - avail = snd_pcm_avail_update (alsa->handle); + avail = alsa_get_avail (alsa->handle); if (avail < 0) { - if (avail == -EPIPE) { - if (!alsa_recover (alsa->handle)) { - avail = snd_pcm_avail_update (alsa->handle); - if (avail >= 0) { - goto ok; - } - } - } - - alsa_logerr (avail, "Could not get amount free space\n"); + dolog ("Could not get number of available playback frames\n"); return 0; } - ok: decr = audio_MIN (live, avail); samples = decr; rpos = hw->rpos; while (samples) { int left_till_end_samples = hw->samples - rpos; - int convert_samples = audio_MIN (samples, left_till_end_samples); + int len = audio_MIN (samples, left_till_end_samples); snd_pcm_sframes_t written; src = hw->mix_buf + rpos; dst = advance (alsa->pcm_buf, rpos << hw->info.shift); - hw->clip (dst, src, convert_samples); + hw->clip (dst, src, len); - while (convert_samples) { - written = snd_pcm_writei (alsa->handle, dst, convert_samples); + while (len) { + written = snd_pcm_writei (alsa->handle, dst, len); - if (written < 0) { + if (written <= 0) { switch (written) { - case -EPIPE: - if (!alsa_recover (alsa->handle)) { - continue; + case 0: + if (conf.verbose) { + dolog ("Failed to write %d frames (wrote zero)\n", len); } - dolog ("Failed to write %d frames to %p, " - "handle %p not prepared\n", - convert_samples, - dst, - alsa->handle); goto exit; - case -EAGAIN: + case -EPIPE: + if (alsa_recover (alsa->handle)) { + alsa_logerr (written, "Failed to write %d frames\n", + len); + goto exit; + } + if (conf.verbose) { + dolog ("Recovering from playback xrun\n"); + } continue; + case -EAGAIN: + goto exit; + default: alsa_logerr (written, "Failed to write %d frames to %p\n", - convert_samples, dst); + len, dst); goto exit; } } @@ -599,7 +609,7 @@ static int alsa_run_out (HWVoiceOut *hw) mixeng_clear (src, written); rpos = (rpos + written) % hw->samples; samples -= written; - convert_samples -= written; + len -= written; dst = advance (dst, written << hw->info.shift); src += written; } @@ -659,7 +669,6 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as) &obt_as, audio_need_to_swap_endian (endianness) ); - alsa->can_pause = obt.can_pause; hw->samples = obt.samples; alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift); @@ -671,46 +680,46 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as) } alsa->handle = handle; - alsa->was_enabled = 0; return 0; } -static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...) +static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause) { int err; + + if (pause) { + err = snd_pcm_drop (handle); + if (err < 0) { + alsa_logerr (err, "Could not stop %s", typ); + return -1; + } + } + else { + err = snd_pcm_prepare (handle); + if (err < 0) { + alsa_logerr (err, "Could not prepare handle for %s", typ); + return -1; + } + } + + return 0; +} + +static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...) +{ ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; switch (cmd) { case VOICE_ENABLE: ldebug ("enabling voice\n"); - audio_pcm_info_clear_buf (&hw->info, alsa->pcm_buf, hw->samples); - if (alsa->can_pause) { - /* Why this was_enabled madness is needed at all?? */ - if (alsa->was_enabled) { - err = snd_pcm_pause (alsa->handle, 0); - if (err < 0) { - alsa_logerr (err, "Failed to resume playing\n"); - /* not fatal really */ - } - } - else { - alsa->was_enabled = 1; - } - } - break; + return alsa_voice_ctl (alsa->handle, "playback", 0); case VOICE_DISABLE: ldebug ("disabling voice\n"); - if (alsa->can_pause) { - err = snd_pcm_pause (alsa->handle, 1); - if (err < 0) { - alsa_logerr (err, "Failed to stop playing\n"); - /* not fatal really */ - } - } - break; + return alsa_voice_ctl (alsa->handle, "playback", 1); } - return 0; + + return -1; } static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) @@ -749,7 +758,6 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) &obt_as, audio_need_to_swap_endian (endianness) ); - alsa->can_pause = obt.can_pause; hw->samples = obt.samples; alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); @@ -783,6 +791,7 @@ static int alsa_run_in (HWVoiceIn *hw) int i; int live = audio_pcm_hw_get_live_in (hw); int dead = hw->samples - live; + int decr; struct { int add; int len; @@ -790,22 +799,36 @@ static int alsa_run_in (HWVoiceIn *hw) { hw->wpos, 0 }, { 0, 0 } }; - + snd_pcm_sframes_t avail; snd_pcm_uframes_t read_samples = 0; if (!dead) { return 0; } - if (hw->wpos + dead > hw->samples) { + avail = alsa_get_avail (alsa->handle); + if (avail < 0) { + dolog ("Could not get number of captured frames\n"); + return 0; + } + + if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) { + avail = hw->samples; + } + + decr = audio_MIN (dead, avail); + if (!decr) { + return 0; + } + + if (hw->wpos + decr > hw->samples) { bufs[0].len = (hw->samples - hw->wpos); - bufs[1].len = (dead - (hw->samples - hw->wpos)); + bufs[1].len = (decr - (hw->samples - hw->wpos)); } else { - bufs[0].len = dead; + bufs[0].len = decr; } - for (i = 0; i < 2; ++i) { void *src; st_sample_t *dst; @@ -820,24 +843,27 @@ static int alsa_run_in (HWVoiceIn *hw) while (len) { nread = snd_pcm_readi (alsa->handle, src, len); - if (nread < 0) { + if (nread <= 0) { switch (nread) { - case -EPIPE: - if (!alsa_recover (alsa->handle)) { - continue; + case 0: + if (conf.verbose) { + dolog ("Failed to read %ld frames (read zero)\n", len); } - dolog ( - "Failed to read %ld frames from %p, " - "handle %p not prepared\n", - len, - src, - alsa->handle - ); goto exit; - case -EAGAIN: + case -EPIPE: + if (alsa_recover (alsa->handle)) { + alsa_logerr (nread, "Failed to read %ld frames\n", len); + goto exit; + } + if (conf.verbose) { + dolog ("Recovering from capture xrun\n"); + } continue; + case -EAGAIN: + goto exit; + default: alsa_logerr ( nread, @@ -871,9 +897,19 @@ static int alsa_read (SWVoiceIn *sw, void *buf, int size) static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...) { - (void) hw; - (void) cmd; - return 0; + ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; + + switch (cmd) { + case VOICE_ENABLE: + ldebug ("enabling voice\n"); + return alsa_voice_ctl (alsa->handle, "capture", 0); + + case VOICE_DISABLE: + ldebug ("disabling voice\n"); + return alsa_voice_ctl (alsa->handle, "capture", 1); + } + + return -1; } static void *alsa_audio_init (void) @@ -909,6 +945,10 @@ static struct audio_option alsa_options[] = { {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in, "ADC device name", NULL, 0}, + + {"VERBOSE", AUD_OPT_BOOL, &conf.verbose, + "Behave in a more verbose way", NULL, 0}, + {NULL, 0, NULL, NULL, NULL, 0} }; diff --git a/audio/audio.c b/audio/audio.c index eba4fdb12..763453523 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -96,7 +96,7 @@ static struct { { 0 }, /* period */ 0, /* plive */ - 0 + 0 /* log_to_monitor */ }; static AudioState glob_audio_state; @@ -623,25 +623,6 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) /* * Hard voice (capture) */ -static void audio_pcm_hw_free_resources_in (HWVoiceIn *hw) -{ - if (hw->conv_buf) { - qemu_free (hw->conv_buf); - } - hw->conv_buf = NULL; -} - -static int audio_pcm_hw_alloc_resources_in (HWVoiceIn *hw) -{ - hw->conv_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); - if (!hw->conv_buf) { - dolog ("Could not allocate ADC conversion buffer (%d samples)\n", - hw->samples); - return -1; - } - return 0; -} - static int audio_pcm_hw_find_min_in (HWVoiceIn *hw) { SWVoiceIn *sw; @@ -668,64 +649,6 @@ int audio_pcm_hw_get_live_in (HWVoiceIn *hw) /* * Soft voice (capture) */ -static void audio_pcm_sw_free_resources_in (SWVoiceIn *sw) -{ - if (sw->conv_buf) { - qemu_free (sw->conv_buf); - } - - if (sw->rate) { - st_rate_stop (sw->rate); - } - - sw->conv_buf = NULL; - sw->rate = NULL; -} - -static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw) -{ - int samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; - sw->conv_buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t)); - if (!sw->conv_buf) { - dolog ("Could not allocate buffer for `%s' (%d samples)\n", - SW_NAME (sw), samples); - return -1; - } - - sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq); - if (!sw->rate) { - qemu_free (sw->conv_buf); - sw->conv_buf = NULL; - return -1; - } - return 0; -} - -static int audio_pcm_sw_init_in ( - SWVoiceIn *sw, - HWVoiceIn *hw, - const char *name, - audsettings_t *as - ) -{ - /* None of the cards emulated by QEMU are big-endian - hence following shortcut */ - audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0)); - sw->hw = hw; - sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq; - - sw->clip = - mixeng_clip - [sw->info.nchannels == 2] - [sw->info.sign] - [sw->info.swap_endian] - [sw->info.bits == 16]; - - sw->name = qemu_strdup (name); - audio_pcm_sw_free_resources_in (sw); - return audio_pcm_sw_alloc_resources_in (sw); -} - static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw) { HWVoiceIn *hw = sw->hw; @@ -750,7 +673,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) { HWVoiceIn *hw = sw->hw; int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0; - st_sample_t *src, *dst = sw->conv_buf; + st_sample_t *src, *dst = sw->buf; rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples; @@ -794,7 +717,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) total += isamp; } - sw->clip (buf, sw->conv_buf, ret); + sw->clip (buf, sw->buf, ret); sw->total_hw_samples_acquired += total; return ret << sw->info.shift; } @@ -802,27 +725,6 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) /* * Hard voice (playback) */ -static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw) -{ - if (hw->mix_buf) { - qemu_free (hw->mix_buf); - } - - hw->mix_buf = NULL; -} - -static int audio_pcm_hw_alloc_resources_out (HWVoiceOut *hw) -{ - hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); - if (!hw->mix_buf) { - dolog ("Could not allocate DAC mixing buffer (%d samples)\n", - hw->samples); - return -1; - } - - return 0; -} - static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) { SWVoiceOut *sw; @@ -876,66 +778,6 @@ int audio_pcm_hw_get_live_out (HWVoiceOut *hw) /* * Soft voice (playback) */ -static void audio_pcm_sw_free_resources_out (SWVoiceOut *sw) -{ - if (sw->buf) { - qemu_free (sw->buf); - } - - if (sw->rate) { - st_rate_stop (sw->rate); - } - - sw->buf = NULL; - sw->rate = NULL; -} - -static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw) -{ - sw->buf = audio_calloc (AUDIO_FUNC, sw->hw->samples, sizeof (st_sample_t)); - if (!sw->buf) { - dolog ("Could not allocate buffer for `%s' (%d samples)\n", - SW_NAME (sw), sw->hw->samples); - return -1; - } - - sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq); - if (!sw->rate) { - qemu_free (sw->buf); - sw->buf = NULL; - return -1; - } - return 0; -} - -static int audio_pcm_sw_init_out ( - SWVoiceOut *sw, - HWVoiceOut *hw, - const char *name, - audsettings_t *as - ) -{ - /* None of the cards emulated by QEMU are big-endian - hence following shortcut */ - audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (0)); - sw->hw = hw; - sw->empty = 1; - sw->active = 0; - sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq; - sw->total_hw_samples_mixed = 0; - - sw->conv = - mixeng_conv - [sw->info.nchannels == 2] - [sw->info.sign] - [sw->info.swap_endian] - [sw->info.bits == 16]; - sw->name = qemu_strdup (name); - - audio_pcm_sw_free_resources_out (sw); - return audio_pcm_sw_alloc_resources_out (sw); -} - int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) { int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck; @@ -1316,6 +1158,16 @@ static void audio_run_in (AudioState *s) } } +static void audio_timer (void *opaque) +{ + AudioState *s = opaque; + + audio_run_out (s); + audio_run_in (s); + + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); +} + static struct audio_option audio_options[] = { /* DAC */ {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled, @@ -1356,13 +1208,31 @@ static struct audio_option audio_options[] = { {"PLIVE", AUD_OPT_BOOL, &conf.plive, "(undocumented)", NULL, 0}, - {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor, "print logging messages to montior instead of stderr", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} }; +static void audio_pp_nb_voices (const char *typ, int nb) +{ + switch (nb) { + case 0: + printf ("Does not support %s\n", typ); + break; + case 1: + printf ("One %s voice\n", typ); + break; + case INT_MAX: + printf ("Theoretically supports many %s voices\n", typ); + break; + default: + printf ("Theoretically supports upto %d %s voices\n", nb, typ); + break; + } + +} + void AUD_help (void) { size_t i; @@ -1387,37 +1257,8 @@ void AUD_help (void) printf ("Name: %s\n", d->name); printf ("Description: %s\n", d->descr); - switch (d->max_voices_out) { - case 0: - printf ("Does not support DAC\n"); - break; - case 1: - printf ("One DAC voice\n"); - break; - case INT_MAX: - printf ("Theoretically supports many DAC voices\n"); - break; - default: - printf ("Theoretically supports upto %d DAC voices\n", - d->max_voices_out); - break; - } - - switch (d->max_voices_in) { - case 0: - printf ("Does not support ADC\n"); - break; - case 1: - printf ("One ADC voice\n"); - break; - case INT_MAX: - printf ("Theoretically supports many ADC voices\n"); - break; - default: - printf ("Theoretically supports upto %d ADC voices\n", - d->max_voices_in); - break; - } + audio_pp_nb_voices ("playback", d->max_voices_out); + audio_pp_nb_voices ("capture", d->max_voices_in); if (d->options) { printf ("Options:\n"); @@ -1434,7 +1275,7 @@ void AUD_help (void) "Example:\n" #ifdef _WIN32 " set QEMU_AUDIO_DRV=wav\n" - " set QEMU_WAV_PATH=c:/tune.wav\n" + " set QEMU_WAV_PATH=c:\\tune.wav\n" #else " export QEMU_AUDIO_DRV=wav\n" " export QEMU_WAV_PATH=$HOME/tune.wav\n" @@ -1444,16 +1285,6 @@ void AUD_help (void) ); } -void audio_timer (void *opaque) -{ - AudioState *s = opaque; - - audio_run_out (s); - audio_run_in (s); - - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); -} - static int audio_driver_init (AudioState *s, struct audio_driver *drv) { if (drv->options) { @@ -1462,62 +1293,8 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv) s->drv_opaque = drv->init (); if (s->drv_opaque) { - if (s->nb_hw_voices_out > drv->max_voices_out) { - if (!drv->max_voices_out) { - dolog ("`%s' does not support DAC\n", drv->name); - } - else { - dolog ( - "`%s' does not support %d multiple DAC voicess\n" - "Resetting to %d\n", - drv->name, - s->nb_hw_voices_out, - drv->max_voices_out - ); - } - s->nb_hw_voices_out = drv->max_voices_out; - } - - - if (!drv->voice_size_in && drv->max_voices_in) { - ldebug ("warning: No ADC voice size defined for `%s'\n", - drv->name); - drv->max_voices_in = 0; - } - - if (!drv->voice_size_out && drv->max_voices_out) { - ldebug ("warning: No DAC voice size defined for `%s'\n", - drv->name); - } - - if (drv->voice_size_in && !drv->max_voices_in) { - ldebug ("warning: `%s' ADC voice size %d, zero voices \n", - drv->name, drv->voice_size_out); - } - - if (drv->voice_size_out && !drv->max_voices_out) { - ldebug ("warning: `%s' DAC voice size %d, zero voices \n", - drv->name, drv->voice_size_in); - } - - if (s->nb_hw_voices_in > drv->max_voices_in) { - if (!drv->max_voices_in) { - ldebug ("`%s' does not support ADC\n", drv->name); - } - else { - dolog ( - "`%s' does not support %d multiple ADC voices\n" - "Resetting to %d\n", - drv->name, - s->nb_hw_voices_in, - drv->max_voices_in - ); - } - s->nb_hw_voices_in = drv->max_voices_in; - } - - LIST_INIT (&s->hw_head_out); - LIST_INIT (&s->hw_head_in); + audio_init_nb_voices_out (s, drv); + audio_init_nb_voices_in (s, drv); s->drv = drv; return 0; } @@ -1549,25 +1326,13 @@ static void audio_atexit (void) HWVoiceOut *hwo = NULL; HWVoiceIn *hwi = NULL; - while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) { - if (!hwo->pcm_ops) { - continue; - } - - if (hwo->enabled) { - hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); - } + while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { + hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); hwo->pcm_ops->fini_out (hwo); } - while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) { - if (!hwi->pcm_ops) { - continue; - } - - if (hwi->enabled) { - hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE); - } + while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) { + hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE); hwi->pcm_ops->fini_in (hwi); } @@ -1616,21 +1381,31 @@ AudioState *AUD_init (void) const char *drvname; AudioState *s = &glob_audio_state; + LIST_INIT (&s->hw_head_out); + LIST_INIT (&s->hw_head_in); + atexit (audio_atexit); + + s->ts = qemu_new_timer (vm_clock, audio_timer, s); + if (!s->ts) { + dolog ("Could not create audio timer\n"); + return NULL; + } + audio_process_options ("AUDIO", audio_options); s->nb_hw_voices_out = conf.fixed_out.nb_voices; s->nb_hw_voices_in = conf.fixed_in.nb_voices; if (s->nb_hw_voices_out <= 0) { - dolog ("Bogus number of DAC voices %d\n", + dolog ("Bogus number of playback voices %d, setting to 1\n", s->nb_hw_voices_out); s->nb_hw_voices_out = 1; } if (s->nb_hw_voices_in <= 0) { - dolog ("Bogus number of ADC voices %d\n", + dolog ("Bogus number of capture voices %d, setting to 0\n", s->nb_hw_voices_in); - s->nb_hw_voices_in = 1; + s->nb_hw_voices_in = 0; } { @@ -1638,12 +1413,6 @@ AudioState *AUD_init (void) drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def); } - s->ts = qemu_new_timer (vm_clock, audio_timer, s); - if (!s->ts) { - dolog ("Could not create audio timer\n"); - return NULL; - } - if (drvname) { int found = 0; @@ -1680,6 +1449,8 @@ AudioState *AUD_init (void) } if (done) { + VMChangeStateEntry *e; + if (conf.period.hz <= 0) { if (conf.period.hz < 0) { dolog ("warning: Timer period is negative - %d " @@ -1692,7 +1463,11 @@ AudioState *AUD_init (void) conf.period.ticks = ticks_per_sec / conf.period.hz; } - qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s); + e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s); + if (!e) { + dolog ("warning: Could not register change state handler\n" + "(Audio can continue looping even after stopping the VM)\n"); + } } else { qemu_del_timer (s->ts); @@ -1701,7 +1476,6 @@ AudioState *AUD_init (void) LIST_INIT (&s->card_head); register_savevm ("audio", 0, 1, audio_save, audio_load, s); - atexit (audio_atexit); qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); return s; } diff --git a/audio/audio.h b/audio/audio.h index 682d0e000..169b5f636 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -73,7 +73,8 @@ SWVoiceOut *AUD_open_out ( const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - audsettings_t *settings + audsettings_t *settings, + int sw_endian ); void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw); @@ -91,7 +92,8 @@ SWVoiceIn *AUD_open_in ( const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - audsettings_t *settings + audsettings_t *settings, + int sw_endian ); void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw); diff --git a/audio/audio_int.h b/audio/audio_int.h index 8fee7b96f..ca240ccc7 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -123,7 +123,7 @@ struct SWVoiceIn { int64_t ratio; void *rate; int total_hw_samples_acquired; - st_sample_t *conv_buf; + st_sample_t *buf; f_sample *clip; HWVoiceIn *hw; char *name; diff --git a/audio/audio_template.h b/audio/audio_template.h index be32c68b3..23d024201 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -23,52 +23,159 @@ */ #ifdef DAC +#define NAME "playback" +#define HWBUF hw->mix_buf #define TYPE out -#define HW glue (HWVoice, Out) -#define SW glue (SWVoice, Out) +#define HW HWVoiceOut +#define SW SWVoiceOut #else +#define NAME "capture" #define TYPE in -#define HW glue (HWVoice, In) -#define SW glue (SWVoice, In) +#define HW HWVoiceIn +#define SW SWVoiceIn +#define HWBUF hw->conv_buf #endif -static int glue (audio_pcm_hw_init_, TYPE) ( - HW *hw, - audsettings_t *as +static void glue (audio_init_nb_voices_, TYPE) ( + AudioState *s, + struct audio_driver *drv ) { - glue (audio_pcm_hw_free_resources_, TYPE) (hw); + int max_voices = glue (drv->max_voices_, TYPE); + int voice_size = glue (drv->voice_size_, TYPE); - if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { - return -1; + if (glue (s->nb_hw_voices_, TYPE) > max_voices) { + if (!max_voices) { +#ifdef DAC + dolog ("Driver `%s' does not support " NAME "\n", drv->name); +#endif + } + else { + dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n", + drv->name, + glue (s->nb_hw_voices_, TYPE), + max_voices); + } + glue (s->nb_hw_voices_, TYPE) = max_voices; } - if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { - dolog ("hw->samples=%d\n", hw->samples); + if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) { + dolog ("drv=`%s' voice_size=0 max_voices=%d\n", + drv->name, max_voices); + glue (s->nb_hw_voices_, TYPE) = 0; + } + + if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) { + dolog ("drv=`%s' voice_size=%d max_voices=0\n", + drv->name, voice_size); + } +} + +static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) +{ + if (HWBUF) { + qemu_free (HWBUF); + } + + HWBUF = NULL; +} + +static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw) +{ + HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); + if (!HWBUF) { + dolog ("Could not allocate " NAME " buffer (%d samples)\n", + hw->samples); return -1; } - LIST_INIT (&hw->sw_head); + return 0; +} + +static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw) +{ + if (sw->buf) { + qemu_free (sw->buf); + } + + if (sw->rate) { + st_rate_stop (sw->rate); + } + + sw->buf = NULL; + sw->rate = NULL; +} + +static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) +{ + int samples; + #ifdef DAC - hw->clip = - mixeng_clip + samples = sw->hw->samples; #else - hw->conv = - mixeng_conv + samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; #endif - [hw->info.nchannels == 2] - [hw->info.sign] - [hw->info.swap_endian] - [hw->info.bits == 16]; - if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { - glue (hw->pcm_ops->fini_, TYPE) (hw); + sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t)); + if (!sw->buf) { + dolog ("Could not allocate buffer for `%s' (%d samples)\n", + SW_NAME (sw), samples); return -1; } +#ifdef DAC + sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq); +#else + sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq); +#endif + if (!sw->rate) { + qemu_free (sw->buf); + sw->buf = NULL; + return -1; + } return 0; } +static int glue (audio_pcm_sw_init_, TYPE) ( + SW *sw, + HW *hw, + const char *name, + audsettings_t *as, + int endian + ) +{ + int err; + + audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian)); + sw->hw = hw; + sw->active = 0; +#ifdef DAC + sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq; + sw->total_hw_samples_mixed = 0; + sw->empty = 1; +#else + sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq; +#endif + +#ifdef DAC + sw->conv = mixeng_conv +#else + sw->clip = mixeng_clip +#endif + [sw->info.nchannels == 2] + [sw->info.sign] + [sw->info.swap_endian] + [sw->info.bits == 16]; + + sw->name = qemu_strdup (name); + err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); + if (err) { + qemu_free (sw->name); + sw->name = NULL; + } + return err; +} + static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) { glue (audio_pcm_sw_free_resources_, TYPE) (sw); @@ -117,31 +224,6 @@ static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw) return NULL; } -static HW *glue (audio_pcm_hw_find_any_passive_, TYPE) (AudioState *s) -{ - if (glue (s->nb_hw_voices_, TYPE)) { - struct audio_driver *drv = s->drv; - - if (audio_bug (AUDIO_FUNC, !drv)) { - dolog ("No host audio driver\n"); - return NULL; - } - - HW *hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE)); - if (!hw) { - dolog ("Can not allocate voice `%s' size %d\n", - drv->name, glue (drv->voice_size_, TYPE)); - return NULL; - } - - LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); - glue (s->nb_hw_voices_, TYPE) -= 1; - return hw; - } - - return NULL; -} - static HW *glue (audio_pcm_hw_find_specific_, TYPE) ( AudioState *s, HW *hw, @@ -159,23 +241,63 @@ static HW *glue (audio_pcm_hw_find_specific_, TYPE) ( static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) { HW *hw; + struct audio_driver *drv = s->drv; - hw = glue (audio_pcm_hw_find_any_passive_, TYPE) (s); - if (hw) { - hw->pcm_ops = s->drv->pcm_ops; - if (!hw->pcm_ops) { - return NULL; - } + if (!glue (s->nb_hw_voices_, TYPE)) { + return NULL; + } - if (glue (audio_pcm_hw_init_, TYPE) (hw, as)) { - glue (audio_pcm_hw_gc_, TYPE) (s, &hw); - return NULL; - } - else { - return hw; - } + if (audio_bug (AUDIO_FUNC, !drv)) { + dolog ("No host audio driver\n"); + return NULL; } + if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) { + dolog ("Host audio driver without pcm_ops\n"); + return NULL; + } + + hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE)); + if (!hw) { + dolog ("Can not allocate voice `%s' size %d\n", + drv->name, glue (drv->voice_size_, TYPE)); + return NULL; + } + + hw->pcm_ops = drv->pcm_ops; + LIST_INIT (&hw->sw_head); + + if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { + goto err0; + } + + if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { + dolog ("hw->samples=%d\n", hw->samples); + goto err1; + } + +#ifdef DAC + hw->clip = mixeng_clip +#else + hw->conv = mixeng_conv +#endif + [hw->info.nchannels == 2] + [hw->info.sign] + [hw->info.swap_endian] + [hw->info.bits == 16]; + + if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { + goto err1; + } + + LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); + glue (s->nb_hw_voices_, TYPE) -= 1; + return hw; + + err1: + glue (hw->pcm_ops->fini_, TYPE) (hw); + err0: + qemu_free (hw); return NULL; } @@ -206,7 +328,8 @@ static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as) static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( AudioState *s, const char *sw_name, - audsettings_t *as + audsettings_t *as, + int sw_endian ) { SW *sw; @@ -234,7 +357,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) { goto err3; } @@ -256,6 +379,7 @@ static void glue (audio_close_, TYPE) (AudioState *s, SW *sw) glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw); qemu_free (sw); } + void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw) { if (sw) { @@ -275,7 +399,8 @@ SW *glue (AUD_open_, TYPE) ( const char *name, void *callback_opaque , audio_callback_fn_t callback_fn, - audsettings_t *as + audsettings_t *as, + int sw_endian ) { AudioState *s; @@ -347,15 +472,16 @@ SW *glue (AUD_open_, TYPE) ( goto fail; } - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) { + glue (audio_pcm_sw_fini_, TYPE) (sw); + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) { goto fail; } } else { - sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as); + sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian); if (!sw) { dolog ("Failed to create voice `%s'\n", name); - goto fail; + return NULL; } } @@ -435,3 +561,5 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) #undef TYPE #undef HW #undef SW +#undef HWBUF +#undef NAME diff --git a/audio/ossaudio.c b/audio/ossaudio.c index d78e59019..7d12f9e34 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -75,11 +75,11 @@ static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...) { va_list ap; + va_start (ap, fmt); AUD_vlog (AUDIO_CAP, fmt, ap); + va_end (ap); - va_start (ap, fmt); AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); - va_end (ap); } static void GCC_FMT_ATTR (3, 4) oss_logerr2 ( @@ -422,6 +422,8 @@ static int oss_init_out (HWVoiceOut *hw, audsettings_t *as) audfmt_e effective_fmt; audsettings_t obt_as; + oss->fd = -1; + req.fmt = aud_to_ossfmt (as->fmt); req.freq = as->freq; req.nchannels = as->nchannels; @@ -565,6 +567,8 @@ static int oss_init_in (HWVoiceIn *hw, audsettings_t *as) audfmt_e effective_fmt; audsettings_t obt_as; + oss->fd = -1; + req.fmt = aud_to_ossfmt (as->fmt); req.freq = as->freq; req.nchannels = as->nchannels; -- cgit v1.2.3 From 32d448c470861924648bed914d7d86b59e9dfeda Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 18:53:05 +0000 Subject: added LF missing in logs (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1637 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 3ab264e01..30f1e5076 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -690,14 +690,14 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause) if (pause) { err = snd_pcm_drop (handle); if (err < 0) { - alsa_logerr (err, "Could not stop %s", typ); + alsa_logerr (err, "Could not stop %s\n", typ); return -1; } } else { err = snd_pcm_prepare (handle); if (err < 0) { - alsa_logerr (err, "Could not prepare handle for %s", typ); + alsa_logerr (err, "Could not prepare handle for %s\n", typ); return -1; } } -- cgit v1.2.3 From e59c11393b3c30b29bbf3176f2771cfae9b5cd1f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 20 Nov 2005 18:53:42 +0000 Subject: make the number of buffers settable (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1638 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/coreaudio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 6afc55cb2..534fb3ef7 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -33,9 +33,11 @@ struct { int buffer_frames; + int nbuffers; int isAtexit; } conf = { .buffer_frames = 512, + .nbuffers = 4, .isAtexit = 0 }; @@ -393,7 +395,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) "Could not get device buffer frame size\n"); return -1; } - hw->samples = 4 * core->audioDevicePropertyBufferFrameSize; + hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize; /* get StreamFormat */ propertySize = sizeof(core->outputStreamBasicDescription); @@ -527,6 +529,8 @@ static void coreaudio_audio_fini (void *opaque) static struct audio_option coreaudio_options[] = { {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames, "Size of the buffer in frames", NULL, 0}, + {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers, + "Number of buffers", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} }; -- cgit v1.2.3 From f0aca8227fbdb0cec65331cb59dbe768e2586e7d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Nov 2005 23:22:06 +0000 Subject: fixed big endian host support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1639 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 55ccbea64..b1c4b2082 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -231,8 +231,8 @@ static inline uint64_t ldq_le_p(void *ptr) { uint8_t *p = ptr; uint32_t v1, v2; - v1 = ldl_p(p); - v2 = ldl_p(p + 4); + v1 = ldl_le_p(p); + v2 = ldl_le_p(p + 4); return v1 | ((uint64_t)v2 << 32); } @@ -263,8 +263,8 @@ static inline void stl_le_p(void *ptr, int v) static inline void stq_le_p(void *ptr, uint64_t v) { uint8_t *p = ptr; - stl_p(p, (uint32_t)v); - stl_p(p + 4, v >> 32); + stl_le_p(p, (uint32_t)v); + stl_le_p(p + 4, v >> 32); } /* float access */ @@ -725,6 +725,7 @@ void cpu_dump_state(CPUState *env, FILE *f, int flags); void cpu_abort(CPUState *env, const char *fmt, ...); +extern CPUState *first_cpu; extern CPUState *cpu_single_env; extern int code_copy_enabled; -- cgit v1.2.3 From 6a00d60127dc0e1d4efadafe1feb88f05030fe52 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Nov 2005 23:25:50 +0000 Subject: SMP support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1640 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 5 +- cpu-exec.c | 4 ++ disas.c | 10 +++- exec-all.h | 2 +- exec.c | 104 ++++++++++++++++----------------- gdbstub.c | 13 +++-- monitor.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++------------- vl.c | 99 ++++++++++++++++++++------------ vl.h | 7 +++ 9 files changed, 296 insertions(+), 138 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index fb4f8e8a2..c30825381 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -96,6 +96,7 @@ typedef struct CPUTLBEntry { #define CPU_COMMON \ struct TranslationBlock *current_tb; /* currently executing TB */ \ + int cpu_halted; /* TRUE if cpu is halted (sleep mode) */ \ /* 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 \ @@ -115,9 +116,9 @@ typedef struct CPUTLBEntry { 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 diff --git a/cpu-exec.c b/cpu-exec.c index 9f6487adf..72e32684a 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -251,6 +251,8 @@ int cpu_exec(CPUState *env1) TranslationBlock *tb; uint8_t *tc_ptr; + cpu_single_env = env1; + /* first we save global registers */ saved_env = env; env = env1; @@ -755,6 +757,8 @@ int cpu_exec(CPUState *env1) T2 = saved_T2; #endif env = saved_env; + /* fail safe : never use cpu_single_env outside cpu_exec() */ + cpu_single_env = NULL; return ret; } diff --git a/disas.c b/disas.c index feb8a93ca..78a72675d 100644 --- a/disas.c +++ b/disas.c @@ -138,6 +138,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info) 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) @@ -177,7 +178,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) disasm_info.mach = bfd_mach_sparc_v9b; #endif #elif defined(TARGET_PPC) - if (cpu_single_env->msr[MSR_LE]) + if (flags) disasm_info.endian = BFD_ENDIAN_LITTLE; #ifdef TARGET_PPC64 disasm_info.mach = bfd_mach_ppc64; @@ -314,6 +315,7 @@ 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) @@ -325,7 +327,7 @@ monitor_read_memory (memaddr, myaddr, length, info) if (monitor_disas_is_physical) { cpu_physical_memory_rw(memaddr, myaddr, length, 0); } else { - cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0); + cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0); } return 0; } @@ -339,7 +341,8 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...) return 0; } -void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) +void monitor_disas(CPUState *env, + target_ulong pc, int nb_insn, int is_physical, int flags) { int count, i; struct disassemble_info disasm_info; @@ -347,6 +350,7 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) 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; diff --git a/exec-all.h b/exec-all.h index 874e9d9a3..67aa227ad 100644 --- a/exec-all.h +++ b/exec-all.h @@ -91,7 +91,7 @@ int cpu_restore_state_copy(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); void cpu_resume_from_signal(CPUState *env1, void *puc); -void cpu_exec_init(void); +void cpu_exec_init(CPUState *env); int page_unprotect(unsigned long address, unsigned long pc, void *puc); void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, int is_cpu_write_access); diff --git a/exec.c b/exec.c index 8aed3d00c..3dbd3eb07 100644 --- a/exec.c +++ b/exec.c @@ -74,6 +74,11 @@ int phys_ram_fd; uint8_t *phys_ram_base; uint8_t *phys_ram_dirty; +CPUState *first_cpu; +/* current CPU in the current thread. It is only valid inside + cpu_exec() */ +CPUState *cpu_single_env; + typedef struct PageDesc { /* list of TBs intersecting this ram page */ TranslationBlock *first_tb; @@ -233,19 +238,30 @@ static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) } #if !defined(CONFIG_USER_ONLY) -static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, - target_ulong vaddr); +static void tlb_protect_code(ram_addr_t ram_addr); static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, target_ulong vaddr); #endif -void cpu_exec_init(void) +void cpu_exec_init(CPUState *env) { + CPUState **penv; + int cpu_index; + if (!code_gen_ptr) { code_gen_ptr = code_gen_buffer; page_init(); io_mem_init(); } + env->next_cpu = NULL; + penv = &first_cpu; + cpu_index = 0; + while (*penv != NULL) { + penv = (CPUState **)&(*penv)->next_cpu; + cpu_index++; + } + env->cpu_index = cpu_index; + *penv = env; } static inline void invalidate_page_bitmap(PageDesc *p) @@ -277,8 +293,9 @@ static void page_flush_tb(void) /* flush all the translation blocks */ /* XXX: tb_flush is currently not thread safe */ -void tb_flush(CPUState *env) +void tb_flush(CPUState *env1) { + CPUState *env; #if defined(DEBUG_FLUSH) printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", code_gen_ptr - code_gen_buffer, @@ -286,7 +303,10 @@ void tb_flush(CPUState *env) nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); #endif nb_tbs = 0; - memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); + } memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); page_flush_tb(); @@ -424,6 +444,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) { + CPUState *env; PageDesc *p; unsigned int h, n1; target_ulong phys_pc; @@ -451,7 +472,10 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad /* remove the TB from the hash list */ h = tb_jmp_cache_hash_func(tb->pc); - cpu_single_env->tb_jmp_cache[h] = NULL; + for(env = first_cpu; env != NULL; env = env->next_cpu) { + if (env->tb_jmp_cache[h] == tb) + env->tb_jmp_cache[h] = NULL; + } /* suppress this TB from the two jump lists */ tb_jmp_remove(tb, 0); @@ -818,10 +842,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, protected. So we handle the case where only the first TB is allocated in a physical page */ if (!last_first_tb) { - target_ulong virt_addr; - - virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS); - tlb_protect_code(cpu_single_env, page_addr, virt_addr); + tlb_protect_code(page_addr); } #endif @@ -1246,40 +1267,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr) #endif } -static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr) -{ - if (addr == (tlb_entry->address & - (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && - (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; - } -} - /* update the TLBs so that writes to code in the virtual page 'addr' can be detected */ -static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, - target_ulong vaddr) +static void tlb_protect_code(ram_addr_t ram_addr) { - int i; - - vaddr &= TARGET_PAGE_MASK; - i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_protect_code1(&env->tlb_write[0][i], vaddr); - tlb_protect_code1(&env->tlb_write[1][i], vaddr); - -#ifdef USE_KQEMU - if (env->kqemu_enabled) { - kqemu_set_notdirty(env, ram_addr); - } -#endif - phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG; - -#if !defined(CONFIG_SOFTMMU) - /* NOTE: as we generated the code for this page, it is already at - least readable */ - if (vaddr < MMAP_AREA_END) - mprotect((void *)vaddr, TARGET_PAGE_SIZE, PROT_READ); -#endif + cpu_physical_memory_reset_dirty(ram_addr, + ram_addr + TARGET_PAGE_SIZE, + CODE_DIRTY_FLAG); } /* update the TLB so that writes in physical page 'phys_addr' are no longer @@ -1317,8 +1311,9 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, if (length == 0) return; len = length >> TARGET_PAGE_BITS; - env = cpu_single_env; #ifdef USE_KQEMU + /* XXX: should not depend on cpu context */ + env = first_cpu; if (env->kqemu_enabled) { ram_addr_t addr; addr = start; @@ -1336,10 +1331,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, /* we modify the TLB cache so that the dirty bit will be set again when accessing the range */ start1 = start + (unsigned long)phys_ram_base; - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length); - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length); + for(env = first_cpu; env != NULL; env = env->next_cpu) { + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length); + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length); + } #if !defined(CONFIG_SOFTMMU) /* XXX: this is expensive */ @@ -1407,9 +1404,9 @@ static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, /* update the TLB corresponding to virtual page vaddr and phys addr addr so that it is no longer dirty */ -static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) +static inline void tlb_set_dirty(CPUState *env, + unsigned long addr, target_ulong vaddr) { - CPUState *env = cpu_single_env; int i; addr &= TARGET_PAGE_MASK; @@ -1723,7 +1720,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size) } } -static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) +static inline void tlb_set_dirty(CPUState *env, + unsigned long addr, target_ulong vaddr) { } #endif /* defined(CONFIG_USER_ONLY) */ @@ -1787,7 +1785,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); + tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); } static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -1808,7 +1806,7 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); + tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); } static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -1829,7 +1827,7 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t /* we remove the notdirty callback only if the code has been flushed */ if (dirty_flags == 0xff) - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); + tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); } static CPUReadMemoryFunc *error_mem_read[3] = { @@ -1953,6 +1951,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, if (is_write) { if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); + /* XXX: could force cpu_single_env to NULL to avoid + potential bugs */ if (l >= 4 && ((addr & 3) == 0)) { /* 32 bit write access */ val = ldl_p(buf); diff --git a/gdbstub.c b/gdbstub.c index 4ddf021e6..ef76fb06a 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -47,6 +47,7 @@ enum RSState { static int gdbserver_fd = -1; typedef struct GDBState { + CPUState *env; /* current CPU */ enum RSState state; /* parsing state */ int fd; char line_buf[4096]; @@ -576,10 +577,10 @@ static void gdb_vm_stopped(void *opaque, int reason) int ret; /* disable single step if it was enable */ - cpu_single_step(cpu_single_env, 0); + cpu_single_step(s->env, 0); if (reason == EXCP_DEBUG) { - tb_flush(cpu_single_env); + tb_flush(s->env); ret = SIGTRAP; } else @@ -589,8 +590,9 @@ static void gdb_vm_stopped(void *opaque, int reason) } #endif -static void gdb_read_byte(GDBState *s, CPUState *env, int ch) +static void gdb_read_byte(GDBState *s, int ch) { + CPUState *env = s->env; int i, csum; char reply[1]; @@ -676,7 +678,7 @@ gdb_handlesig (CPUState *env, int sig) int i; for (i = 0; i < n; i++) - gdb_read_byte (s, env, buf[i]); + gdb_read_byte (s, buf[i]); } else if (n == 0 || errno != EAGAIN) { @@ -721,7 +723,7 @@ static void gdb_read(void *opaque) vm_start(); } else { for(i = 0; i < size; i++) - gdb_read_byte(s, cpu_single_env, buf[i]); + gdb_read_byte(s, buf[i]); } } @@ -759,6 +761,7 @@ static void gdb_accept(void *opaque) return; } #endif + s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; fcntl(fd, F_SETFL, O_NONBLOCK); diff --git a/monitor.c b/monitor.c index 18f0c8991..85a997db8 100644 --- a/monitor.c +++ b/monitor.c @@ -64,6 +64,8 @@ static int term_outbuf_index; static void monitor_start_input(void); +CPUState *mon_cpu = NULL; + void term_flush(void) { if (term_outbuf_index > 0) { @@ -201,17 +203,69 @@ static void do_info_block(void) bdrv_info(); } +/* get the current CPU defined by the user */ +int mon_set_cpu(int cpu_index) +{ + CPUState *env; + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + if (env->cpu_index == cpu_index) { + mon_cpu = env; + return 0; + } + } + return -1; +} + +CPUState *mon_get_cpu(void) +{ + if (!mon_cpu) { + mon_set_cpu(0); + } + return mon_cpu; +} + static void do_info_registers(void) { + CPUState *env; + env = mon_get_cpu(); + if (!env) + return; #ifdef TARGET_I386 - cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, + cpu_dump_state(env, NULL, monitor_fprintf, X86_DUMP_FPU); #else - cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, + cpu_dump_state(env, NULL, monitor_fprintf, 0); #endif } +static void do_info_cpus(void) +{ + CPUState *env; + + /* just to set the default cpu if not already done */ + mon_get_cpu(); + + for(env = first_cpu; env != NULL; env = env->next_cpu) { + term_printf("%c CPU #%d:", + (env == mon_cpu) ? '*' : ' ', + env->cpu_index); +#if defined(TARGET_I386) + term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base); + if (env->cpu_halted) + term_printf(" (halted)"); +#endif + term_printf("\n"); + } +} + +static void do_cpu_set(int index) +{ + if (mon_set_cpu(index) < 0) + term_printf("Invalid CPU index\n"); +} + static void do_info_jit(void) { dump_exec_info(NULL, monitor_fprintf); @@ -381,6 +435,7 @@ static void term_printc(int c) static void memory_dump(int count, int format, int wsize, target_ulong addr, int is_physical) { + CPUState *env; int nb_per_line, l, line_size, i, max_digits, len; uint8_t buf[16]; uint64_t v; @@ -388,19 +443,22 @@ static void memory_dump(int count, int format, int wsize, if (format == 'i') { int flags; flags = 0; + env = mon_get_cpu(); + if (!env && !is_physical) + return; #ifdef TARGET_I386 if (wsize == 2) { flags = 1; } else if (wsize == 4) { flags = 0; } else { - /* as default we use the current CS size */ + /* as default we use the current CS size */ flags = 0; - if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK)) + if (env && !(env->segs[R_CS].flags & DESC_B_MASK)) flags = 1; } #endif - monitor_disas(addr, count, is_physical, flags); + monitor_disas(env, addr, count, is_physical, flags); return; } @@ -437,7 +495,10 @@ static void memory_dump(int count, int format, int wsize, if (is_physical) { cpu_physical_memory_rw(addr, buf, l, 0); } else { - cpu_memory_rw_debug(cpu_single_env, addr, buf, l, 0); + env = mon_get_cpu(); + if (!env) + break; + cpu_memory_rw_debug(env, addr, buf, l, 0); } i = 0; while (i < l) { @@ -776,10 +837,14 @@ static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask) static void tlb_info(void) { - CPUState *env = cpu_single_env; + CPUState *env; int l1, l2; uint32_t pgd, pde, pte; + env = mon_get_cpu(); + if (!env) + return; + if (!(env->cr[0] & CR0_PG_MASK)) { term_printf("PG disabled\n"); return; @@ -830,10 +895,14 @@ static void mem_print(uint32_t *pstart, int *plast_prot, static void mem_info(void) { - CPUState *env = cpu_single_env; + CPUState *env; int l1, l2, prot, last_prot; uint32_t pgd, pde, pte, start, end; + env = mon_get_cpu(); + if (!env) + return; + if (!(env->cr[0] & CR0_PG_MASK)) { term_printf("PG disabled\n"); return; @@ -874,10 +943,15 @@ static void mem_info(void) static void do_info_kqemu(void) { #ifdef USE_KQEMU + CPUState *env; int val; val = 0; - if (cpu_single_env) - val = cpu_single_env->kqemu_enabled; + env = mon_get_cpu(); + if (!env) { + term_printf("No cpu initialized yet"); + return; + } + val = env->kqemu_enabled; term_printf("kqemu is %s\n", val ? "enabled" : "disabled"); #else term_printf("kqemu support is not compiled\n"); @@ -934,6 +1008,8 @@ static term_cmd_t term_cmds[] = { "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, { "usb_del", "s", do_usb_del, "device", "remove USB device 'bus.addr'" }, + { "cpu", "i", do_cpu_set, + "index", "set the default CPU" }, { NULL, NULL, }, }; @@ -946,6 +1022,8 @@ static term_cmd_t info_cmds[] = { "", "show the block devices" }, { "registers", "", do_info_registers, "", "show the cpu registers" }, + { "cpus", "", do_info_cpus, + "", "show infos for each CPU" }, { "history", "", do_info_history, "", "show the command line history", }, { "irq", "", irq_info, @@ -989,63 +1067,85 @@ typedef struct MonitorDef { #if defined(TARGET_I386) static target_long monitor_get_pc (struct MonitorDef *md, int val) { - return cpu_single_env->eip + cpu_single_env->segs[R_CS].base; + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return env->eip + env->segs[R_CS].base; } #endif #if defined(TARGET_PPC) static target_long monitor_get_ccr (struct MonitorDef *md, int val) { + CPUState *env = mon_get_cpu(); unsigned int u; int i; + if (!env) + return 0; + u = 0; for (i = 0; i < 8; i++) - u |= cpu_single_env->crf[i] << (32 - (4 * i)); + u |= env->crf[i] << (32 - (4 * i)); return u; } static target_long monitor_get_msr (struct MonitorDef *md, int val) { - return (cpu_single_env->msr[MSR_POW] << MSR_POW) | - (cpu_single_env->msr[MSR_ILE] << MSR_ILE) | - (cpu_single_env->msr[MSR_EE] << MSR_EE) | - (cpu_single_env->msr[MSR_PR] << MSR_PR) | - (cpu_single_env->msr[MSR_FP] << MSR_FP) | - (cpu_single_env->msr[MSR_ME] << MSR_ME) | - (cpu_single_env->msr[MSR_FE0] << MSR_FE0) | - (cpu_single_env->msr[MSR_SE] << MSR_SE) | - (cpu_single_env->msr[MSR_BE] << MSR_BE) | - (cpu_single_env->msr[MSR_FE1] << MSR_FE1) | - (cpu_single_env->msr[MSR_IP] << MSR_IP) | - (cpu_single_env->msr[MSR_IR] << MSR_IR) | - (cpu_single_env->msr[MSR_DR] << MSR_DR) | - (cpu_single_env->msr[MSR_RI] << MSR_RI) | - (cpu_single_env->msr[MSR_LE] << MSR_LE); + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return (env->msr[MSR_POW] << MSR_POW) | + (env->msr[MSR_ILE] << MSR_ILE) | + (env->msr[MSR_EE] << MSR_EE) | + (env->msr[MSR_PR] << MSR_PR) | + (env->msr[MSR_FP] << MSR_FP) | + (env->msr[MSR_ME] << MSR_ME) | + (env->msr[MSR_FE0] << MSR_FE0) | + (env->msr[MSR_SE] << MSR_SE) | + (env->msr[MSR_BE] << MSR_BE) | + (env->msr[MSR_FE1] << MSR_FE1) | + (env->msr[MSR_IP] << MSR_IP) | + (env->msr[MSR_IR] << MSR_IR) | + (env->msr[MSR_DR] << MSR_DR) | + (env->msr[MSR_RI] << MSR_RI) | + (env->msr[MSR_LE] << MSR_LE); } static target_long monitor_get_xer (struct MonitorDef *md, int val) { - return (cpu_single_env->xer[XER_SO] << XER_SO) | - (cpu_single_env->xer[XER_OV] << XER_OV) | - (cpu_single_env->xer[XER_CA] << XER_CA) | - (cpu_single_env->xer[XER_BC] << XER_BC); + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return (env->xer[XER_SO] << XER_SO) | + (env->xer[XER_OV] << XER_OV) | + (env->xer[XER_CA] << XER_CA) | + (env->xer[XER_BC] << XER_BC); } static target_long monitor_get_decr (struct MonitorDef *md, int val) { - return cpu_ppc_load_decr(cpu_single_env); + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return cpu_ppc_load_decr(env); } static target_long monitor_get_tbu (struct MonitorDef *md, int val) { - return cpu_ppc_load_tbu(cpu_single_env); + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return cpu_ppc_load_tbu(env); } static target_long monitor_get_tbl (struct MonitorDef *md, int val) { - return cpu_ppc_load_tbl(cpu_single_env); + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return cpu_ppc_load_tbl(env); } #endif @@ -1053,13 +1153,19 @@ static target_long monitor_get_tbl (struct MonitorDef *md, int val) #ifndef TARGET_SPARC64 static target_long monitor_get_psr (struct MonitorDef *md, int val) { - return GET_PSR(cpu_single_env); + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return GET_PSR(env); } #endif static target_long monitor_get_reg(struct MonitorDef *md, int val) { - return cpu_single_env->regwptr[val]; + CPUState *env = mon_get_cpu(); + if (!env) + return 0; + return env->regwptr[val]; } #endif @@ -1269,6 +1375,7 @@ static void expr_error(const char *fmt) longjmp(expr_env, 1); } +/* return 0 if OK, -1 if not found, -2 if no CPU defined */ static int get_monitor_def(target_long *pval, const char *name) { MonitorDef *md; @@ -1279,7 +1386,10 @@ static int get_monitor_def(target_long *pval, const char *name) if (md->get_value) { *pval = md->get_value(md, md->offset); } else { - ptr = (uint8_t *)cpu_single_env + md->offset; + CPUState *env = mon_get_cpu(); + if (!env) + return -2; + ptr = (uint8_t *)env + md->offset; switch(md->type) { case MD_I32: *pval = *(int32_t *)ptr; @@ -1313,6 +1423,7 @@ static target_long expr_unary(void) { target_long n; char *p; + int ret; switch(*pch) { case '+': @@ -1362,8 +1473,11 @@ static target_long expr_unary(void) while (isspace(*pch)) pch++; *q = 0; - if (get_monitor_def(&n, buf)) + ret = get_monitor_def(&n, buf); + if (ret == -1) expr_error("unknown register"); + else if (ret == -2) + expr_error("no cpu defined"); } break; case '\0': diff --git a/vl.c b/vl.c index 725e954d3..b946390a1 100644 --- a/vl.c +++ b/vl.c @@ -83,8 +83,6 @@ #include "exec-all.h" -//#define DO_TB_FLUSH - #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" //#define DEBUG_UNUSED_IOPORT @@ -109,8 +107,6 @@ const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; -CPUState *global_env; -CPUState *cpu_single_env; void *ioport_opaque[MAX_IOPORTS]; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; @@ -156,6 +152,7 @@ int usb_enabled = 0; USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; USBDevice *vm_usb_hub; static VLANState *first_vlan; +int smp_cpus = 1; /***********************************************************/ /* x86 ISA bus support */ @@ -427,16 +424,20 @@ int cpu_inl(CPUState *env, int addr) void hw_error(const char *fmt, ...) { va_list ap; + CPUState *env; va_start(ap, fmt); fprintf(stderr, "qemu: hardware error: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); + for(env = first_cpu; env != NULL; env = env->next_cpu) { + fprintf(stderr, "CPU #%d:\n", env->cpu_index); #ifdef TARGET_I386 - cpu_dump_state(global_env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); + cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU); #else - cpu_dump_state(global_env, stderr, fprintf, 0); + cpu_dump_state(env, stderr, fprintf, 0); #endif + } va_end(ap); abort(); } @@ -879,13 +880,16 @@ static void host_alarm_handler(int host_signum) qemu_get_clock(vm_clock)) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { - /* stop the cpu because a timer occured */ - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); + 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 (global_env->kqemu_enabled) { - kqemu_cpu_interrupt(global_env); - } + if (env->kqemu_enabled) { + kqemu_cpu_interrupt(env); + } #endif + } } } @@ -2970,9 +2974,6 @@ int qemu_loadvm(const char *filename) goto the_end; } for(;;) { -#if defined (DO_TB_FLUSH) - tb_flush(global_env); -#endif len = qemu_get_byte(f); if (feof(f)) break; @@ -3583,27 +3584,22 @@ void qemu_system_reset(void) void qemu_system_reset_request(void) { reset_requested = 1; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + if (cpu_single_env) + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } void qemu_system_shutdown_request(void) { shutdown_requested = 1; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + if (cpu_single_env) + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } void qemu_system_powerdown_request(void) { powerdown_requested = 1; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); -} - -static void main_cpu_reset(void *opaque) -{ -#if defined(TARGET_I386) || defined(TARGET_SPARC) - CPUState *env = opaque; - cpu_reset(env); -#endif + if (cpu_single_env) + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } void main_loop_wait(int timeout) @@ -3684,14 +3680,42 @@ void main_loop_wait(int timeout) qemu_get_clock(rt_clock)); } +static CPUState *cur_cpu; + +static CPUState *find_next_cpu(void) +{ + CPUState *env; + env = cur_cpu; + for(;;) { + /* get next cpu */ + env = env->next_cpu; + if (!env) + env = first_cpu; + if (!env->cpu_halted) + break; + /* all CPUs are halted ? */ + if (env == cur_cpu) + return NULL; + } + cur_cpu = env; + return env; +} + int main_loop(void) { int ret, timeout; - CPUState *env = global_env; + CPUState *env; + cur_cpu = first_cpu; for(;;) { if (vm_running) { - ret = cpu_exec(env); + /* find next cpu to run */ + /* XXX: handle HLT correctly */ + env = find_next_cpu(); + if (!env) + ret = EXCP_HLT; + else + ret = cpu_exec(env); if (shutdown_requested) { ret = EXCP_INTERRUPT; break; @@ -3774,7 +3798,7 @@ void help(void) " connect the host TAP network interface to VLAN 'n' and use\n" " the network script 'file' (default=%s);\n" " use 'fd=h' to connect to an already opened TAP interface\n" - "-net socket[,vlan=n][,fd=x][,listen=[host]:port][,connect=host:port]\n" + "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n" " connect the vlan 'n' to another VLAN using a socket connection\n" #endif "-net none use it alone to have zero network devices; if no -net option\n" @@ -3899,6 +3923,7 @@ enum { QEMU_OPTION_win2k_hack, QEMU_OPTION_usb, QEMU_OPTION_usbdevice, + QEMU_OPTION_smp, }; typedef struct QEMUOption { @@ -3965,6 +3990,7 @@ const QEMUOption qemu_options[] = { { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, + { "smp", HAS_ARG, QEMU_OPTION_smp }, /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, @@ -4120,7 +4146,6 @@ int main(int argc, char **argv) #endif int i, cdrom_index; int snapshot, linux_boot; - CPUState *env; const char *initrd_filename; const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *kernel_filename, *kernel_cmdline; @@ -4511,6 +4536,13 @@ int main(int argc, char **argv) optarg); usb_devices_index++; break; + case QEMU_OPTION_smp: + smp_cpus = atoi(optarg); + if (smp_cpus < 1 || smp_cpus > 8) { + fprintf(stderr, "Invalid number of CPUs\n"); + exit(1); + } + break; } } } @@ -4659,15 +4691,8 @@ int main(int argc, char **argv) } } - /* init CPU state */ - env = cpu_init(); - global_env = env; - cpu_single_env = env; - - register_savevm("timer", 0, 1, timer_save, timer_load, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + register_savevm("timer", 0, 1, timer_save, timer_load, NULL); register_savevm("ram", 0, 1, ram_save, ram_load, NULL); - qemu_register_reset(main_cpu_reset, global_env); init_ioports(); cpu_calibrate_ticks(); diff --git a/vl.h b/vl.h index d5efcd2e7..1daae5042 100644 --- a/vl.h +++ b/vl.h @@ -142,6 +142,7 @@ extern const char *keyboard_layout; extern int kqemu_allowed; extern int win2k_install_hack; extern int usb_enabled; +extern int smp_cpus; /* XXX: make it dynamic */ #if defined (TARGET_PPC) @@ -429,6 +430,9 @@ int register_savevm(const char *idstr, void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); +void cpu_save(QEMUFile *f, void *opaque); +int cpu_load(QEMUFile *f, void *opaque, int version_id); + /* block.c */ typedef struct BlockDriverState BlockDriverState; typedef struct BlockDriver BlockDriver; @@ -774,6 +778,9 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; +void ioport_set_a20(int enable); +int ioport_get_a20(void); + /* ppc.c */ extern QEMUMachine prep_machine; extern QEMUMachine core99_machine; -- cgit v1.2.3 From e0fd87812f411342d88ada38a8b1d674c40b8173 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Nov 2005 23:26:26 +0000 Subject: APIC fixes - SIPI support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1641 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 71 ++++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index a66e03296..276dd456f 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -121,7 +121,8 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, /* normal INIT IPI sent to processors */ for (apic_iter = first_local_apic; apic_iter != NULL; apic_iter = apic_iter->next_apic) { - apic_init_ipi(apic_iter); + if (deliver_bitmask & (1 << apic_iter->id)) + apic_init_ipi(apic_iter); } return; @@ -317,7 +318,7 @@ static void apic_init_ipi(APICState *s) s->tpr = 0; s->spurious_vec = 0xff; s->log_dest = 0; - s->dest_mode = 0; + s->dest_mode = 0xf; memset(s->isr, 0, sizeof(s->isr)); memset(s->tmr, 0, sizeof(s->tmr)); memset(s->irr, 0, sizeof(s->irr)); @@ -331,6 +332,18 @@ static void apic_init_ipi(APICState *s) s->next_time = 0; } +/* send a SIPI message to the CPU to start it */ +static void apic_startup(APICState *s, int vector_num) +{ + CPUState *env = s->cpu_env; + if (!env->cpu_halted) + return; + env->eip = 0; + cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, + 0xffff, 0); + env->cpu_halted = 0; +} + static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) @@ -339,10 +352,26 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, int dest_shorthand = (s->icr[0] >> 18) & 3; APICState *apic_iter; + switch (dest_shorthand) { + case 0: + deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode); + break; + case 1: + deliver_bitmask = (1 << s->id); + break; + case 2: + deliver_bitmask = 0xffffffff; + break; + case 3: + deliver_bitmask = 0xffffffff & ~(1 << s->id); + break; + } + switch (delivery_mode) { case APIC_DM_LOWPRI: - /* XXX: serch for focus processor, arbitration */ + /* XXX: search for focus processor, arbitration */ dest = s->id; + break; case APIC_DM_INIT: { @@ -364,28 +393,12 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, for (apic_iter = first_local_apic; apic_iter != NULL; apic_iter = apic_iter->next_apic) { if (deliver_bitmask & (1 << apic_iter->id)) { - /* XXX: SMP support */ - /* apic_startup(apic_iter); */ + apic_startup(apic_iter, vector_num); } } return; } - switch (dest_shorthand) { - case 0: - deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode); - break; - case 1: - deliver_bitmask = (1 << s->id); - break; - case 2: - deliver_bitmask = 0xffffffff; - break; - case 3: - deliver_bitmask = 0xffffffff & ~(1 << s->id); - break; - } - apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity, trigger_mode); } @@ -534,13 +547,13 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) case 0x28: val = s->esr; break; - case 0x32 ... 0x37: - val = s->lvt[index - 0x32]; - break; case 0x30: case 0x31: val = s->icr[index & 1]; break; + case 0x32 ... 0x37: + val = s->lvt[index - 0x32]; + break; case 0x38: val = s->initial_count; break; @@ -581,10 +594,15 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) case 0x02: s->id = (val >> 24); break; + case 0x03: + break; case 0x08: s->tpr = val; apic_update_irq(s); break; + case 0x09: + case 0x0a: + break; case 0x0b: /* EOI */ apic_eoi(s); break; @@ -598,6 +616,11 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) s->spurious_vec = val & 0x1ff; apic_update_irq(s); break; + case 0x10 ... 0x17: + case 0x18 ... 0x1f: + case 0x20 ... 0x27: + case 0x28: + break; case 0x30: s->icr[0] = val; apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1, @@ -620,6 +643,8 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) s->initial_count_load_time = qemu_get_clock(vm_clock); apic_timer_update(s, s->initial_count_load_time); break; + case 0x39: + break; case 0x3e: { int v; -- cgit v1.2.3 From 0e1fd3694e5386e791d86fb6bd7ead4d0c86bd9a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Nov 2005 23:32:10 +0000 Subject: target_disas() little endian change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1642 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1ca7cbc7e..f2e0f94a7 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2643,7 +2643,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, ctx.nip - pc_start, 0); + target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le); fprintf(logfile, "\n"); } if (loglevel & CPU_LOG_TB_OP) { -- cgit v1.2.3 From 173d6cfe5129301a3a8f2570223aaa47a815f343 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Nov 2005 23:32:20 +0000 Subject: cpu_exec_init() change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1643 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 7 ++----- target-i386/helper2.c | 8 +++----- target-mips/translate.c | 5 +---- target-ppc/translate_init.c | 4 +--- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index afb9b57c8..601db555a 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2199,13 +2199,10 @@ CPUARMState *cpu_arm_init(void) { CPUARMState *env; - cpu_exec_init(); - - env = malloc(sizeof(CPUARMState)); + env = qemu_mallocz(sizeof(CPUARMState)); if (!env) return NULL; - memset(env, 0, sizeof(CPUARMState)); - cpu_single_env = env; + cpu_exec_init(env); return env; } diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 60335909a..943ff5907 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -47,12 +47,11 @@ CPUX86State *cpu_x86_init(void) CPUX86State *env; static int inited; - cpu_exec_init(); - - env = malloc(sizeof(CPUX86State)); + env = qemu_mallocz(sizeof(CPUX86State)); if (!env) return NULL; - memset(env, 0, sizeof(CPUX86State)); + cpu_exec_init(env); + /* init various static tables */ if (!inited) { inited = 1; @@ -135,7 +134,6 @@ CPUX86State *cpu_x86_init(void) env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA; #endif } - cpu_single_env = env; cpu_reset(env); #ifdef USE_KQEMU kqemu_init(env); diff --git a/target-mips/translate.c b/target-mips/translate.c index 2dc33af72..71b101be3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1694,10 +1694,10 @@ CPUMIPSState *cpu_mips_init (void) { CPUMIPSState *env; - cpu_exec_init(); env = qemu_mallocz(sizeof(CPUMIPSState)); if (!env) return NULL; + cpu_exec_init(env); tlb_flush(env, 1); /* Minimal init */ env->PC = 0xBFC00000; @@ -1722,8 +1722,5 @@ CPUMIPSState *cpu_mips_init (void) env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); env->CP0_PRid = MIPS_CPU; env->exception_index = EXCP_NONE; - - cpu_single_env = env; - return env; } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 624527d5f..012c34f73 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1081,11 +1081,10 @@ CPUPPCState *cpu_ppc_init(void) { CPUPPCState *env; - cpu_exec_init(); - env = qemu_mallocz(sizeof(CPUPPCState)); if (!env) return NULL; + cpu_exec_init(env); tlb_flush(env, 1); #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ @@ -1101,7 +1100,6 @@ CPUPPCState *cpu_ppc_init(void) #endif do_compute_hflags(env); env->reserve = -1; - cpu_single_env = env; return env; } -- cgit v1.2.3 From c68ea7043f2ed4c631d1e3a4f35afe247d5ca063 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Nov 2005 23:33:12 +0000 Subject: cpu_single_env usage fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1644 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 4 +++- hw/heathrow_pic.c | 4 ++-- hw/mips_r4k.c | 32 ++++++++++++++++----------- hw/openpic.c | 8 ++++--- hw/pci.c | 12 +++++------ hw/pckbd.c | 8 +++---- hw/ppc_chrp.c | 56 +++++++++++++++++++++++++++--------------------- hw/ppc_prep.c | 40 +++++++++++++++++++--------------- hw/slavio_intctl.c | 10 +++++---- hw/sun4m.c | 11 ++++++++++ hw/sun4u.c | 11 ++++++++++ linux-user/main.c | 6 ++---- target-sparc/op_helper.c | 4 ++-- target-sparc/translate.c | 9 ++++---- tests/qruncom.c | 2 -- 15 files changed, 129 insertions(+), 88 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index ce828699f..ea13eae49 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -427,7 +427,9 @@ int DMA_write_memory (int nchan, void *buf, int pos, int len) /* request the emulator to transfer a new DMA memory block ASAP */ void DMA_schedule(int nchan) { - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + CPUState *env = cpu_single_env; + if (env) + cpu_interrupt(env, CPU_INTERRUPT_EXIT); } static void dma_reset(void *opaque) diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index d65da9a9f..4980cef46 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -45,9 +45,9 @@ static inline int check_irq(HeathrowPIC *pic) static void heathrow_pic_update(HeathrowPICS *s) { if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) { - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); } else { - cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); } } diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index bf3376d4f..cfb907efe 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -11,12 +11,13 @@ static PITState *pit; static void pic_irq_request(void *opaque, int level) { + CPUState *env = first_cpu; if (level) { - cpu_single_env->CP0_Cause |= 0x00000400; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + env->CP0_Cause |= 0x00000400; + cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { - cpu_single_env->CP0_Cause &= ~0x00000400; - cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + env->CP0_Cause &= ~0x00000400; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } } @@ -74,8 +75,8 @@ void cpu_mips_store_count (CPUState *env, uint32_t value) void cpu_mips_store_compare (CPUState *env, uint32_t value) { cpu_mips_update_count(env, cpu_mips_get_count(env), value); - cpu_single_env->CP0_Cause &= ~0x00008000; - cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + env->CP0_Cause &= ~0x00008000; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } static void mips_timer_cb (void *opaque) @@ -89,8 +90,8 @@ static void mips_timer_cb (void *opaque) } #endif cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); - cpu_single_env->CP0_Cause |= 0x00008000; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + env->CP0_Cause |= 0x00008000; + cpu_interrupt(env, CPU_INTERRUPT_HARD); } void cpu_mips_clock_init (CPUState *env) @@ -181,9 +182,14 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, int io_memory; int linux_boot; int ret; + CPUState *env; printf("%s: start\n", __func__); linux_boot = (kernel_filename != NULL); + + env = cpu_init(); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); bios_offset = ram_size + vga_ram_size; @@ -198,9 +204,9 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, BIOS_SIZE, bios_offset | IO_MEM_ROM); #if 0 memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE); - cpu_single_env->PC = 0x80010004; + env->PC = 0x80010004; #else - cpu_single_env->PC = 0xBFC00004; + env->PC = 0xBFC00004; #endif if (linux_boot) { kernel_base = KERNEL_LOAD_ADDR; @@ -226,7 +232,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, initrd_base = 0; initrd_size = 0; } - cpu_single_env->PC = KERNEL_LOAD_ADDR; + env->PC = KERNEL_LOAD_ADDR; } else { kernel_base = 0; kernel_size = 0; @@ -235,7 +241,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, } /* Init internal devices */ - cpu_mips_clock_init(cpu_single_env); + cpu_mips_clock_init(env); cpu_mips_irqctrl_init(); /* Register 64 KB of ISA IO space at 0x14000000 */ @@ -243,7 +249,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x14000000, 0x00010000, io_memory); isa_mem_base = 0x10000000; - isa_pic = pic_init(pic_irq_request, cpu_single_env); + isa_pic = pic_init(pic_irq_request, env); pit = pit_init(0x40, 0); serial_init(0x3f8, 4, serial_hds[0]); vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, diff --git a/hw/openpic.c b/hw/openpic.c index 08fb9bd12..8068e7e59 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -265,7 +265,8 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) if (priority > dst->raised.priority) { IRQ_get_next(opp, &dst->raised); DPRINTF("Raise CPU IRQ\n"); - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + /* XXX: choose the correct cpu */ + cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); } } @@ -532,7 +533,7 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) /* XXX: Should be able to reset any CPU */ if (val & 1) { DPRINTF("Reset CPU IRQ\n"); - // cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET); + // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET); } break; #if MAX_IPI > 0 @@ -781,7 +782,8 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) src = &opp->src[n_IRQ]; if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { DPRINTF("Raise CPU IRQ\n"); - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + /* XXX: choose cpu */ + cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); } } break; diff --git a/hw/pci.c b/hw/pci.c index efca2cd53..f3456baca 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1616,32 +1616,32 @@ void pci_info(void) static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) { - return cpu_inb(cpu_single_env, addr); + return cpu_inb(NULL, addr); } static void isa_outb(uint32_t val, uint32_t addr) { - cpu_outb(cpu_single_env, addr, val); + cpu_outb(NULL, addr, val); } static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) { - return cpu_inw(cpu_single_env, addr); + return cpu_inw(NULL, addr); } static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) { - cpu_outw(cpu_single_env, addr, val); + cpu_outw(NULL, addr, val); } static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) { - return cpu_inl(cpu_single_env, addr); + return cpu_inl(NULL, addr); } static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) { - cpu_outl(cpu_single_env, addr, val); + cpu_outl(NULL, addr, val); } static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) diff --git a/hw/pckbd.c b/hw/pckbd.c index be559eb4f..1be1560ef 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -254,7 +254,7 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) case KBD_CCMD_READ_OUTPORT: /* XXX: check that */ #ifdef TARGET_I386 - val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1); + val = 0x01 | (ioport_get_a20() << 1); #else val = 0x01; #endif @@ -266,10 +266,10 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) break; #ifdef TARGET_I386 case KBD_CCMD_ENABLE_A20: - cpu_x86_set_a20(cpu_single_env, 1); + ioport_set_a20(1); break; case KBD_CCMD_DISABLE_A20: - cpu_x86_set_a20(cpu_single_env, 0); + ioport_set_a20(0); break; #endif case KBD_CCMD_RESET: @@ -611,7 +611,7 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) break; case KBD_CCMD_WRITE_OUTPORT: #ifdef TARGET_I386 - cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1); + ioport_set_a20((val >> 1) & 1); #endif if (!(val & 1)) { qemu_system_reset_request(); diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 46e903168..a0dfbf6b9 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -300,6 +300,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename, int is_heathrow) { + CPUState *env; char buf[1024]; SetIRQFunc *set_irq; void *pic; @@ -315,6 +316,36 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, linux_boot = (kernel_filename != NULL); + /* init CPUs */ + env = cpu_init(); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + + /* Register CPU as a 74x/75x */ + /* XXX: CPU model (or PVR) should be provided on command line */ + // ppc_find_by_name("750gx", &def); // Linux boot OK + // ppc_find_by_name("750fx", &def); // Linux boot OK + /* Linux does not boot on 750cxe (and probably other 750cx based) + * because it assumes it has 8 IBAT & DBAT pairs as it only have 4. + */ + // ppc_find_by_name("750cxe", &def); + // ppc_find_by_name("750p", &def); + // ppc_find_by_name("740p", &def); + ppc_find_by_name("750", &def); + // ppc_find_by_name("740", &def); + // ppc_find_by_name("G3", &def); + // ppc_find_by_name("604r", &def); + // ppc_find_by_name("604e", &def); + // ppc_find_by_name("604", &def); + if (def == NULL) { + cpu_abort(env, "Unable to find PowerPC CPU definition\n"); + } + cpu_ppc_register(env, def); + + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + + env->osi_call = vga_osi_call; + /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -381,31 +412,6 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, initrd_base = 0; initrd_size = 0; } - /* Register CPU as a 74x/75x */ - /* XXX: CPU model (or PVR) should be provided on command line */ - // ppc_find_by_name("750gx", &def); // Linux boot OK - // ppc_find_by_name("750fx", &def); // Linux boot OK - /* Linux does not boot on 750cxe (and probably other 750cx based) - * because it assumes it has 8 IBAT & DBAT pairs as it only have 4. - */ - // ppc_find_by_name("750cxe", &def); - // ppc_find_by_name("750p", &def); - // ppc_find_by_name("740p", &def); - ppc_find_by_name("750", &def); - // ppc_find_by_name("740", &def); - // ppc_find_by_name("G3", &def); - // ppc_find_by_name("604r", &def); - // ppc_find_by_name("604e", &def); - // ppc_find_by_name("604", &def); - if (def == NULL) { - cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n"); - } - cpu_ppc_register(cpu_single_env, def); - - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); - - cpu_single_env->osi_call = vga_osi_call; if (is_heathrow) { isa_mem_base = 0x80000000; diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 017457df2..2e401e2a6 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -99,9 +99,9 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) static void pic_irq_request(void *opaque, int level) { if (level) - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); else - cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); } /* PCI intack register */ @@ -294,7 +294,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) /* Special port 92 */ /* Check soft reset asked */ if (val & 0x01) { - // cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET); + // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET); } /* Check LE mode */ if (val & 0x02) { @@ -331,7 +331,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) break; case 0x0814: /* L2 invalidate register */ - // tlb_flush(cpu_single_env, 1); + // tlb_flush(first_cpu, 1); break; case 0x081C: /* system control register */ @@ -523,6 +523,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) { + CPUState *env; char buf[1024]; m48t59_t *nvram; int PPC_io_memory; @@ -537,6 +538,23 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, return; linux_boot = (kernel_filename != NULL); + + /* init CPUs */ + + env = cpu_init(); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + + /* Register CPU as a 604 */ + /* XXX: CPU model (or PVR) should be provided on command line */ + // ppc_find_by_name("604r", &def); + // ppc_find_by_name("604e", &def); + ppc_find_by_name("604", &def); + if (def == NULL) { + cpu_abort(env, "Unable to find PowerPC CPU definition\n"); + } + cpu_ppc_register(env, def); + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -584,18 +602,6 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, initrd_size = 0; } - /* Register CPU as a 604 */ - /* XXX: CPU model (or PVR) should be provided on command line */ - // ppc_find_by_name("604r", &def); - // ppc_find_by_name("604e", &def); - ppc_find_by_name("604", &def); - if (def == NULL) { - cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n"); - } - cpu_ppc_register(cpu_single_env, def); - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); - isa_mem_base = 0xc0000000; pci_bus = pci_prep_init(); // pci_bus = i440fx_init(); @@ -609,7 +615,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, vga_ram_size, 0, 0); rtc_init(0x70, 8); // openpic = openpic_init(0x00000000, 0xF0000000, 1); - isa_pic = pic_init(pic_irq_request, cpu_single_env); + isa_pic = pic_init(pic_irq_request, first_cpu); // pit = pit_init(0x40, 0); serial_init(0x3f8, 4, serial_hds[0]); diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 8a5db5c3c..9780785a4 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -213,6 +213,7 @@ static const uint32_t intbit_to_level[32] = { static void slavio_check_interrupts(void *opaque) { + CPUState *env; SLAVIO_INTCTLState *s = opaque; uint32_t pending = s->intregm_pending; unsigned int i, max = 0; @@ -226,16 +227,17 @@ static void slavio_check_interrupts(void *opaque) max = intbit_to_level[i]; } } - if (cpu_single_env->interrupt_index == 0) { + env = first_cpu; + if (env->interrupt_index == 0) { DPRINTF("Triggered pil %d\n", max); #ifdef DEBUG_IRQ_COUNT s->irq_count[max]++; #endif - cpu_single_env->interrupt_index = TT_EXTINT | max; - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + env->interrupt_index = TT_EXTINT | max; + cpu_interrupt(env, CPU_INTERRUPT_HARD); } else - DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, cpu_single_env->interrupt_index); + DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index); } else DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled); diff --git a/hw/sun4m.c b/hw/sun4m.c index 7174c23cb..3ac0886a4 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -210,12 +210,19 @@ void qemu_system_powerdown(void) slavio_set_power_fail(slavio_misc, 1); } +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); +} + /* Sun4m hardware initialisation */ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) { + CPUState *env; char buf[1024]; int ret, linux_boot; unsigned int i; @@ -223,6 +230,10 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, linux_boot = (kernel_filename != NULL); + env = cpu_init(); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + qemu_register_reset(main_cpu_reset, env); + /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); diff --git a/hw/sun4u.c b/hw/sun4u.c index 40d70a9ca..51db1f9bd 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -235,6 +235,12 @@ void qemu_system_powerdown(void) { } +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); +} + static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 14, 15 }; @@ -253,6 +259,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) { + CPUState *env; char buf[1024]; m48t59_t *nvram; int ret, linux_boot; @@ -262,6 +269,10 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, linux_boot = (kernel_filename != NULL); + env = cpu_init(); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + qemu_register_reset(main_cpu_reset, env); + /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); diff --git a/linux-user/main.c b/linux-user/main.c index 468cb9b89..1ae4656d3 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -997,8 +997,6 @@ void usage(void) /* XXX: currently only used for async signals (see signal.c) */ CPUState *global_env; -/* used only if single thread */ -CPUState *cpu_single_env = NULL; /* used to free thread contexts */ TaskState *first_task_state; @@ -1228,10 +1226,10 @@ int main(int argc, char **argv) // ppc_find_by_name("604e", &def); // ppc_find_by_name("604", &def); if (def == NULL) { - cpu_abort(cpu_single_env, + cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } - cpu_ppc_register(cpu_single_env, def); + cpu_ppc_register(env, def); for (i = 0; i < 32; i++) { if (i != 12 && i != 6 && i != 13) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index eaf5cb64e..030b2f78a 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -942,7 +942,7 @@ void do_interrupt(int intno) #endif #if !defined(CONFIG_USER_ONLY) if (env->tl == MAXTL) { - cpu_abort(cpu_single_env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); + cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); return; } #endif @@ -996,7 +996,7 @@ void do_interrupt(int intno) #endif #if !defined(CONFIG_USER_ONLY) if (env->psret == 0) { - cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); + cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); return; } #endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 6340e1522..8a8620fcf 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2672,11 +2672,10 @@ CPUSPARCState *cpu_sparc_init(void) { CPUSPARCState *env; - cpu_exec_init(); - - if (!(env = malloc(sizeof(CPUSPARCState)))) - return (NULL); - cpu_single_env = env; + env = qemu_mallocz(sizeof(CPUSPARCState)); + if (!env) + return NULL; + cpu_exec_init(env); cpu_reset(env); return (env); } diff --git a/tests/qruncom.c b/tests/qruncom.c index fcc069f6d..92b28ea68 100644 --- a/tests/qruncom.c +++ b/tests/qruncom.c @@ -15,8 +15,6 @@ //#define SIGTEST -CPUState *cpu_single_env = NULL; - void cpu_outb(CPUState *env, int addr, int val) { fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); -- cgit v1.2.3 From 59b8ad81c45c3db028875476c46da7c29f6a9440 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Nov 2005 23:34:32 +0000 Subject: SMP support - cpu_single_env usage fix - a20 helpers - dynamic Multi Processor BIOS table generation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1645 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 193 insertions(+), 6 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 399af2bd3..33d221963 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -86,10 +86,11 @@ int cpu_get_pic_interrupt(CPUState *env) static void pic_irq_request(void *opaque, int level) { + CPUState *env = opaque; if (level) - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + cpu_interrupt(env, CPU_INTERRUPT_HARD); else - cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } /* PC cmos mappings */ @@ -287,15 +288,26 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) (dummy_refresh_clock << 4); } +void ioport_set_a20(int enable) +{ + /* XXX: send to all CPUs ? */ + cpu_x86_set_a20(first_cpu, enable); +} + +int ioport_get_a20(void) +{ + return ((first_cpu->a20_mask >> 20) & 1); +} + static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) { - cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1); + ioport_set_a20((val >> 1) & 1); /* XXX: bit 0 is fast reset */ } static uint32_t ioport92_read(void *opaque, uint32_t addr) { - return ((cpu_single_env->a20_mask >> 20) & 1) << 1; + return ioport_get_a20() << 1; } /***********************************************************/ @@ -391,6 +403,162 @@ int load_kernel(const char *filename, uint8_t *addr, return -1; } +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); +} + +/*************************************************/ + +static void putb(uint8_t **pp, int val) +{ + uint8_t *q; + q = *pp; + *q++ = val; + *pp = q; +} + +static void putstr(uint8_t **pp, const char *str) +{ + uint8_t *q; + q = *pp; + while (*str) + *q++ = *str++; + *pp = q; +} + +static void putle16(uint8_t **pp, int val) +{ + uint8_t *q; + q = *pp; + *q++ = val; + *q++ = val >> 8; + *pp = q; +} + +static void putle32(uint8_t **pp, int val) +{ + uint8_t *q; + q = *pp; + *q++ = val; + *q++ = val >> 8; + *q++ = val >> 16; + *q++ = val >> 24; + *pp = q; +} + +static int mpf_checksum(const uint8_t *data, int len) +{ + int sum, i; + sum = 0; + for(i = 0; i < len; i++) + sum += data[i]; + return sum & 0xff; +} + +/* Build the Multi Processor table in the BIOS. Same values as Bochs. */ +static void bios_add_mptable(uint8_t *bios_data) +{ + uint8_t *mp_config_table, *q, *float_pointer_struct; + int ioapic_id, offset, i, len; + + if (smp_cpus <= 1) + return; + + mp_config_table = bios_data + 0xcc00; + q = mp_config_table; + putstr(&q, "PCMP"); /* "PCMP signature */ + putle16(&q, 0); /* table length (patched later) */ + putb(&q, 4); /* spec rev */ + putb(&q, 0); /* checksum (patched later) */ + putstr(&q, "QEMUCPU "); /* OEM id */ + putstr(&q, "0.1 "); /* vendor id */ + putle32(&q, 0); /* OEM table ptr */ + putle16(&q, 0); /* OEM table size */ + putle16(&q, 20); /* entry count */ + putle32(&q, 0xfee00000); /* local APIC addr */ + putle16(&q, 0); /* ext table length */ + putb(&q, 0); /* ext table checksum */ + putb(&q, 0); /* reserved */ + + for(i = 0; i < smp_cpus; i++) { + putb(&q, 0); /* entry type = processor */ + putb(&q, i); /* APIC id */ + putb(&q, 0x11); /* local APIC version number */ + if (i == 0) + putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */ + else + putb(&q, 1); /* cpu flags: enabled */ + putb(&q, 0); /* cpu signature */ + putb(&q, 6); + putb(&q, 0); + putb(&q, 0); + putle16(&q, 0x201); /* feature flags */ + putle16(&q, 0); + + putle16(&q, 0); /* reserved */ + putle16(&q, 0); + putle16(&q, 0); + putle16(&q, 0); + } + + /* isa bus */ + putb(&q, 1); /* entry type = bus */ + putb(&q, 0); /* bus ID */ + putstr(&q, "ISA "); + + /* ioapic */ + ioapic_id = smp_cpus; + putb(&q, 2); /* entry type = I/O APIC */ + putb(&q, ioapic_id); /* apic ID */ + putb(&q, 0x11); /* I/O APIC version number */ + putb(&q, 1); /* enable */ + putle32(&q, 0xfec00000); /* I/O APIC addr */ + + /* irqs */ + for(i = 0; i < 16; i++) { + putb(&q, 3); /* entry type = I/O interrupt */ + putb(&q, 0); /* interrupt type = vectored interrupt */ + putb(&q, 0); /* flags: po=0, el=0 */ + putb(&q, 0); + putb(&q, 0); /* source bus ID = ISA */ + putb(&q, i); /* source bus IRQ */ + putb(&q, ioapic_id); /* dest I/O APIC ID */ + putb(&q, i); /* dest I/O APIC interrupt in */ + } + /* patch length */ + len = q - mp_config_table; + mp_config_table[4] = len; + mp_config_table[5] = len >> 8; + + mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table); + + /* align to 16 */ + offset = q - bios_data; + offset = (offset + 15) & ~15; + float_pointer_struct = bios_data + offset; + + /* floating pointer structure */ + q = float_pointer_struct; + putstr(&q, "_MP_"); + /* pointer to MP config table */ + putle32(&q, mp_config_table - bios_data + 0x000f0000); + + putb(&q, 1); /* length in 16 byte units */ + putb(&q, 4); /* MP spec revision */ + putb(&q, 0); /* checksum (patched later) */ + putb(&q, 0); /* MP feature byte 1 */ + + putb(&q, 0); + putb(&q, 0); + putb(&q, 0); + putb(&q, 0); + float_pointer_struct[10] = + -mpf_checksum(float_pointer_struct, q - float_pointer_struct); +} + + static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 14, 15 }; @@ -418,9 +586,26 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, unsigned long bios_offset, vga_bios_offset; int bios_size, isa_bios_size; PCIBus *pci_bus; + CPUState *env; linux_boot = (kernel_filename != NULL); + /* init CPUs */ + for(i = 0; i < smp_cpus; i++) { + env = cpu_init(); + if (i != 0) + env->cpu_halted = 1; + if (smp_cpus > 1) { + /* XXX: enable it in all cases */ + env->cpuid_features |= CPUID_APIC; + } + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + qemu_register_reset(main_cpu_reset, env); + if (pci_enabled) { + apic_init(env); + } + } + /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); @@ -441,6 +626,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); exit(1); } + if (bios_size == 65536) { + bios_add_mptable(phys_ram_base + bios_offset); + } /* VGA BIOS load */ if (cirrus_vga_enabled) { @@ -559,10 +747,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, register_ioport_write(0x92, 1, 1, ioport92_write, NULL); if (pci_enabled) { - apic_init(cpu_single_env); ioapic = ioapic_init(); } - isa_pic = pic_init(pic_irq_request, cpu_single_env); + isa_pic = pic_init(pic_irq_request, first_cpu); pit = pit_init(0x40, 0); if (pci_enabled) { pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); -- cgit v1.2.3 From 3476562d361d641950d2b905b21824131dca5cf2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Nov 2005 23:35:10 +0000 Subject: monitor_disas() prototype change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1646 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/disas.h b/disas.h index 32da4ebcb..ee0a79c25 100644 --- a/disas.h +++ b/disas.h @@ -4,7 +4,8 @@ /* Disassemble this for me please... (debugging). */ void disas(FILE *out, void *code, unsigned long size); void target_disas(FILE *out, target_ulong code, target_ulong size, int flags); -void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags); +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); -- cgit v1.2.3 From 089af991182fb44915c30075ea4e202ad268afcb Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 22 Nov 2005 20:16:13 +0000 Subject: RTL8029 IDs support (Warner Losh) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1647 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/hw/ne2000.c b/hw/ne2000.c index 2b43ae46b..2940abd35 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -47,7 +47,9 @@ #define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ #define EN0_RSARHI 0x09 /* Remote start address reg 1 */ #define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ +#define EN0_RTL8029ID0 0x0a /* Realtek ID byte #1 RD */ #define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ +#define EN0_RTL8029ID1 0x0b /* Realtek ID byte #2 RD */ #define EN0_RSR 0x0c /* rx status reg RD */ #define EN0_RXCR 0x0c /* RX configuration reg WR */ #define EN0_TXCR 0x0d /* TX configuration reg WR */ @@ -64,6 +66,11 @@ #define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */ #define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */ +#define EN3_CONFIG0 0x33 +#define EN3_CONFIG1 0x34 +#define EN3_CONFIG2 0x35 +#define EN3_CONFIG3 0x36 + /* Register accessed at EN_CMD, the 8390 base addr. */ #define E8390_STOP 0x01 /* Stop and reset the chip */ #define E8390_START 0x02 /* Start the chip, clear reset */ @@ -447,6 +454,21 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) case EN2_STOPPG: ret = s->stop >> 8; break; + case EN0_RTL8029ID0: + ret = 0x50; + break; + case EN0_RTL8029ID1: + ret = 0x43; + break; + case EN3_CONFIG0: + ret = 0; /* 10baseT media */ + break; + case EN3_CONFIG2: + ret = 0x40; /* 10baseT active */ + break; + case EN3_CONFIG3: + ret = 0x40; /* Full duplex */ + break; default: ret = 0x00; break; -- cgit v1.2.3 From 8dd69b8f2cba91b7f2bcb3b4e12fbd35574869c1 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 20:59:44 +0000 Subject: fummy DM_LOWPRI handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1648 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index 276dd456f..64caadb81 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -109,8 +109,16 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, switch (delivery_mode) { case APIC_DM_LOWPRI: + /* XXX: search for focus processor, arbitration */ + if (deliver_bitmask) { + uint32_t m = 1; + while ((deliver_bitmask & m) == 0) + m <<= 1; + deliver_bitmask = m; + } + break; + case APIC_DM_FIXED: - /* XXX: arbitration */ break; case APIC_DM_SMI: @@ -336,12 +344,12 @@ static void apic_init_ipi(APICState *s) static void apic_startup(APICState *s, int vector_num) { CPUState *env = s->cpu_env; - if (!env->cpu_halted) + if (!(env->hflags & HF_HALTED_MASK)) return; env->eip = 0; cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, 0xffff, 0); - env->cpu_halted = 0; + env->hflags &= ~HF_HALTED_MASK; } static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, @@ -368,11 +376,6 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, } switch (delivery_mode) { - case APIC_DM_LOWPRI: - /* XXX: search for focus processor, arbitration */ - dest = s->id; - break; - case APIC_DM_INIT: { int trig_mode = (s->icr[0] >> 15) & 1; -- cgit v1.2.3 From 15a7644956c5265ed3e4d2817a9eca993d0b64fa Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 21:01:03 +0000 Subject: better SMP scheduling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1649 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/vl.c b/vl.c index b946390a1..eaf6a1d68 100644 --- a/vl.c +++ b/vl.c @@ -3682,25 +3682,6 @@ void main_loop_wait(int timeout) static CPUState *cur_cpu; -static CPUState *find_next_cpu(void) -{ - CPUState *env; - env = cur_cpu; - for(;;) { - /* get next cpu */ - env = env->next_cpu; - if (!env) - env = first_cpu; - if (!env->cpu_halted) - break; - /* all CPUs are halted ? */ - if (env == cur_cpu) - return NULL; - } - cur_cpu = env; - return env; -} - int main_loop(void) { int ret, timeout; @@ -3709,13 +3690,24 @@ int main_loop(void) cur_cpu = first_cpu; for(;;) { if (vm_running) { - /* find next cpu to run */ - /* XXX: handle HLT correctly */ - env = find_next_cpu(); - if (!env) - ret = EXCP_HLT; - else + + env = cur_cpu; + for(;;) { + /* get next cpu */ + env = env->next_cpu; + if (!env) + env = first_cpu; ret = cpu_exec(env); + if (ret != EXCP_HALTED) + break; + /* all CPUs are halted ? */ + if (env == cur_cpu) { + ret = EXCP_HLT; + break; + } + } + cur_cpu = env; + if (shutdown_requested) { ret = EXCP_INTERRUPT; break; -- cgit v1.2.3 From ad49ff9de3f15d1b91416ecd005cfae16aba0026 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 21:01:33 +0000 Subject: use HF_HALTED bit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1650 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- monitor.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 33d221963..b930e4053 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -594,7 +594,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < smp_cpus; i++) { env = cpu_init(); if (i != 0) - env->cpu_halted = 1; + env->hflags |= HF_HALTED_MASK; if (smp_cpus > 1) { /* XXX: enable it in all cases */ env->cpuid_features |= CPUID_APIC; diff --git a/monitor.c b/monitor.c index 85a997db8..9befd82b0 100644 --- a/monitor.c +++ b/monitor.c @@ -253,7 +253,7 @@ static void do_info_cpus(void) env->cpu_index); #if defined(TARGET_I386) term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base); - if (env->cpu_halted) + if (env->hflags & HF_HALTED_MASK) term_printf(" (halted)"); #endif term_printf("\n"); -- cgit v1.2.3 From d2ac63e03e21b1a4be24615792b36ec4e953333b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 21:02:10 +0000 Subject: added HF_HALTED bit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1651 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 4 +++- target-i386/helper2.c | 10 ++++++---- target-i386/op.c | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index cd12ca17e..068ebcddb 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -116,7 +116,7 @@ #define ID_MASK 0x00200000 /* hidden flags - used internally by qemu to represent additionnal cpu - states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid + states. Only the CPL, INHIBIT_IRQ and HALTED are not redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring with eflags. */ /* current cpl */ @@ -141,6 +141,7 @@ #define HF_CS64_SHIFT 15 /* only used on x86_64: 64 bit code segment */ #define HF_OSFXSR_SHIFT 16 /* CR4.OSFXSR */ #define HF_VM_SHIFT 17 /* must be same as eflags */ +#define HF_HALTED_SHIFT 18 /* CPU halted */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) @@ -156,6 +157,7 @@ #define HF_LMA_MASK (1 << HF_LMA_SHIFT) #define HF_CS64_MASK (1 << HF_CS64_SHIFT) #define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT) +#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT) #define CR0_PE_MASK (1 << 0) #define CR0_MP_MASK (1 << 1) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 943ff5907..1bc806640 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -265,7 +265,7 @@ void cpu_dump_state(CPUState *env, FILE *f, "RSI=%016llx RDI=%016llx RBP=%016llx RSP=%016llx\n" "R8 =%016llx R9 =%016llx R10=%016llx R11=%016llx\n" "R12=%016llx R13=%016llx R14=%016llx R15=%016llx\n" - "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d\n", + "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], @@ -292,13 +292,14 @@ void cpu_dump_state(CPUState *env, FILE *f, eflags & CC_C ? 'C' : '-', env->hflags & HF_CPL_MASK, (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, - (env->a20_mask >> 20) & 1); + (env->a20_mask >> 20) & 1, + (env->hflags >> HF_HALTED_SHIFT) & 1); } else #endif { cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d\n", + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n", (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_EBX], (uint32_t)env->regs[R_ECX], @@ -317,7 +318,8 @@ void cpu_dump_state(CPUState *env, FILE *f, eflags & CC_C ? 'C' : '-', env->hflags & HF_CPL_MASK, (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, - (env->a20_mask >> 20) & 1); + (env->a20_mask >> 20) & 1, + (env->hflags >> HF_HALTED_SHIFT) & 1); } #ifdef TARGET_X86_64 diff --git a/target-i386/op.c b/target-i386/op.c index 637004579..137f5726b 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -615,6 +615,7 @@ void OPPROTO op_movq_eip_im64(void) void OPPROTO op_hlt(void) { env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ + env->hflags |= HF_HALTED_MASK; env->exception_index = EXCP_HLT; cpu_loop_exit(); } -- cgit v1.2.3 From 5a1e3cfcb0f1b7108542d04fababd433938bf8fe Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 21:02:53 +0000 Subject: better halted state support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1652 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 3 +-- cpu-exec.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index c30825381..e095f8566 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -74,7 +74,7 @@ typedef unsigned long ram_addr_t; #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 @@ -96,7 +96,6 @@ typedef struct CPUTLBEntry { #define CPU_COMMON \ struct TranslationBlock *current_tb; /* currently executing TB */ \ - int cpu_halted; /* TRUE if cpu is halted (sleep mode) */ \ /* 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 \ diff --git a/cpu-exec.c b/cpu-exec.c index 72e32684a..de1fff212 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -251,6 +251,19 @@ int cpu_exec(CPUState *env1) 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; + } + } +#endif + cpu_single_env = env1; /* first we save global registers */ -- cgit v1.2.3 From 2023a2c836ed0a5af990ddbc927e0ea7fdc317d0 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 21:03:04 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1653 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + TODO | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Changelog b/Changelog index 6cc809097..041658d68 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,7 @@ version 0.7.3: - Linux host serial port access - Linux host low level parallel port access - New network emulation code supporting VLANs. + - SMP support version 0.7.2: diff --git a/TODO b/TODO index 088c26c69..8cc9aa55f 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,9 @@ short term: ---------- +- support variable tsc freq +- cpu_interrupt() win32/SMP fix +- 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 @@ -28,7 +32,6 @@ short term: - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). - fix arm fpu rounding (at least for float->integer conversions) -- SMP support ppc specific: ------------ @@ -36,22 +39,23 @@ ppc specific: - SPR_ENCODE() not useful - enable shift optimizations ? -lower priority: --------------- -- more friendly BIOS (logo) -- int15 ah=86: use better timing -- suppress shift_mem ops -- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret) -- optimize FPU operations (evaluate x87 stack pointer statically) +linux-user specific: +------------------- - add IPC syscalls -- use -msoft-float on ARM -- use kernel traps for unaligned accesses on ARM ? - handle rare page fault cases (in particular if page fault in helpers or in syscall emulation code). -- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID) - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues, fix 16 bit uid issues) - use page_unprotect_range in every suitable syscall to handle all cases of self modifying code. -- use gcc as a backend to generate better code (easy to do by using - op-i386.c operations as local inline functions). +- 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 -- cgit v1.2.3 From e5d13e2f64904a3181c7656f9d0eb884bb994bb1 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 21:11:49 +0000 Subject: more generic serial port (initial patch by Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1654 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 2 +- hw/pc.c | 5 +-- hw/ppc_chrp.c | 4 +-- hw/ppc_prep.c | 3 +- hw/serial.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- hw/sun4u.c | 3 +- vl.h | 6 +++- 7 files changed, 112 insertions(+), 11 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index cfb907efe..b1c708cfc 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -251,7 +251,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, isa_pic = pic_init(pic_irq_request, env); pit = pit_init(0x40, 0); - serial_init(0x3f8, 4, serial_hds[0]); + serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0, 0); diff --git a/hw/pc.c b/hw/pc.c index b930e4053..83d601fe9 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -599,7 +599,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, /* XXX: enable it in all cases */ env->cpuid_features |= CPUID_APIC; } - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + register_savevm("cpu", i, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); if (pci_enabled) { apic_init(env); @@ -757,7 +757,8 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(serial_io[i], serial_irq[i], serial_hds[i]); + serial_init(&pic_set_irq_new, isa_pic, + serial_io[i], serial_irq[i], serial_hds[i]); } } diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index a0dfbf6b9..395dd7f73 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -433,7 +433,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, isa_pic = pic_init(pic_irq_request, NULL); /* XXX: use Mac Serial port */ - serial_init(0x3f8, 4, serial_hds[0]); + serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); for(i = 0; i < nb_nics; i++) { pci_ne2000_init(pci_bus, &nd_table[i]); @@ -482,7 +482,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, isa_pic = pic_init(pic_irq_request, NULL); /* XXX: use Mac Serial port */ - serial_init(0x3f8, 4, serial_hds[0]); + serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); for(i = 0; i < nb_nics; i++) { pci_ne2000_init(pci_bus, &nd_table[i]); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 2e401e2a6..d4f302143 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -525,6 +525,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, { CPUState *env; char buf[1024]; + SetIRQFunc *set_irq; m48t59_t *nvram; int PPC_io_memory; int linux_boot, i, nb_nics1, bios_size; @@ -618,7 +619,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, isa_pic = pic_init(pic_irq_request, first_cpu); // pit = pit_init(0x40, 0); - serial_init(0x3f8, 4, serial_hds[0]); + serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; diff --git a/hw/serial.c b/hw/serial.c index 0250d77fb..254434e66 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -83,9 +83,13 @@ struct SerialState { /* NOTE: this hidden state is necessary for tx irq generation as it can be reset while reading iir */ int thr_ipending; + SetIRQFunc *set_irq; + void *irq_opaque; int irq; CharDriverState *chr; int last_break_enable; + target_ulong base; + int it_shift; }; static void serial_update_irq(SerialState *s) @@ -98,9 +102,9 @@ static void serial_update_irq(SerialState *s) s->iir = UART_IIR_NO_INT; } if (s->iir != UART_IIR_NO_INT) { - pic_set_irq(s->irq, 1); + s->set_irq(s->irq_opaque, s->irq, 1); } else { - pic_set_irq(s->irq, 0); + s->set_irq(s->irq_opaque, s->irq, 0); } } @@ -339,13 +343,16 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id) } /* If fd is zero, it means that the serial device uses the console */ -SerialState *serial_init(int base, int irq, CharDriverState *chr) +SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, + int base, int irq, CharDriverState *chr) { SerialState *s; s = qemu_mallocz(sizeof(SerialState)); if (!s) return NULL; + s->set_irq = set_irq; + s->irq_opaque = opaque; s->irq = irq; s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; @@ -359,3 +366,90 @@ SerialState *serial_init(int base, int irq, CharDriverState *chr) qemu_chr_add_event_handler(chr, serial_event); return s; } + +/* Memory mapped interface */ +static uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr) +{ + SerialState *s = opaque; + + return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF; +} + +static void serial_mm_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + SerialState *s = opaque; + + serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF); +} + +static uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr) +{ + SerialState *s = opaque; + + return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF; +} + +static void serial_mm_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + SerialState *s = opaque; + + serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF); +} + +static uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr) +{ + SerialState *s = opaque; + + return serial_ioport_read(s, (addr - s->base) >> s->it_shift); +} + +static void serial_mm_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + SerialState *s = opaque; + + serial_ioport_write(s, (addr - s->base) >> s->it_shift, value); +} + +static CPUReadMemoryFunc *serial_mm_read[] = { + &serial_mm_readb, + &serial_mm_readw, + &serial_mm_readl, +}; + +static CPUWriteMemoryFunc *serial_mm_write[] = { + &serial_mm_writeb, + &serial_mm_writew, + &serial_mm_writel, +}; + +SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, + target_ulong base, int it_shift, + int irq, CharDriverState *chr) +{ + SerialState *s; + int s_io_memory; + + s = qemu_mallocz(sizeof(SerialState)); + if (!s) + return NULL; + s->set_irq = set_irq; + s->irq_opaque = opaque; + s->irq = irq; + s->lsr = UART_LSR_TEMT | UART_LSR_THRE; + s->iir = UART_IIR_NO_INT; + s->base = base; + s->it_shift = it_shift; + + register_savevm("serial", base, 1, serial_save, serial_load, s); + + s_io_memory = cpu_register_io_memory(0, serial_mm_read, + serial_mm_write, s); + cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); + s->chr = chr; + qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s); + qemu_chr_add_event_handler(chr, serial_event); + return s; +} diff --git a/hw/sun4u.c b/hw/sun4u.c index 51db1f9bd..571e2b373 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -335,7 +335,8 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(serial_io[i], serial_irq[i], serial_hds[i]); + serial_init(&pic_set_irq_new, NULL, + serial_io[i], serial_irq[i], serial_hds[i]); } } diff --git a/vl.h b/vl.h index 1daae5042..fda99a7ef 100644 --- a/vl.h +++ b/vl.h @@ -733,7 +733,11 @@ void rtc_set_date(RTCState *s, const struct tm *tm); /* serial.c */ typedef struct SerialState SerialState; -SerialState *serial_init(int base, int irq, CharDriverState *chr); +SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, + int base, int irq, CharDriverState *chr); +SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, + target_ulong base, int it_shift, + int irq, CharDriverState *chr); /* parallel.c */ -- cgit v1.2.3 From 7668a27f1d3bced1b6f4b9727cc80dc769a19d8e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 21:13:45 +0000 Subject: openpic SMP support (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1655 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/openpic.c | 13 +++++++------ hw/ppc_chrp.c | 2 +- vl.h | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 8068e7e59..31773373a 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -159,7 +159,7 @@ typedef struct IRQ_dst_t { uint32_t pcsr; /* CPU sensitivity register */ IRQ_queue_t raised; IRQ_queue_t servicing; - CPUState *env; /* Needed if we did SMP */ + CPUState *env; } IRQ_dst_t; struct openpic_t { @@ -265,8 +265,7 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) if (priority > dst->raised.priority) { IRQ_get_next(opp, &dst->raised); DPRINTF("Raise CPU IRQ\n"); - /* XXX: choose the correct cpu */ - cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); + cpu_interrupt(dst->env, CPU_INTERRUPT_HARD); } } @@ -782,8 +781,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) src = &opp->src[n_IRQ]; if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { DPRINTF("Raise CPU IRQ\n"); - /* XXX: choose cpu */ - cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); + cpu_interrupt(dst->env, CPU_INTERRUPT_HARD); } } break; @@ -965,7 +963,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, #endif } -openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus) +openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + CPUPPCState **envp) { openpic_t *opp; uint8_t *pci_conf; @@ -1019,6 +1018,8 @@ openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus) for (; i < MAX_IRQ; i++) { opp->src[i].type = IRQ_INTERNAL; } + for (i = 0; i < nb_cpus; i++) + opp->dst[i].env = envp[i]; openpic_reset(opp); if (pmem_index) *pmem_index = opp->mem_index; diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 395dd7f73..5187372c6 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -474,7 +474,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - pic = openpic_init(NULL, &openpic_mem_index, 1); + pic = openpic_init(NULL, &openpic_mem_index, 1, &env); set_irq = openpic_set_irq; pci_set_pic(pci_bus, set_irq, pic); diff --git a/vl.h b/vl.h index fda99a7ef..2326c4c18 100644 --- a/vl.h +++ b/vl.h @@ -613,7 +613,8 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base); /* openpic.c */ typedef struct openpic_t openpic_t; void openpic_set_irq(void *opaque, int n_IRQ, int level); -openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus); +openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + CPUState **envp); /* heathrow_pic.c */ typedef struct HeathrowPICS HeathrowPICS; -- cgit v1.2.3 From f24e5695e5fab2d4d143c34ffe8164ddeac9b12b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 21:36:30 +0000 Subject: avoid generating useless exceptions (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1656 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f2e0f94a7..391f82f1d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -177,17 +177,16 @@ RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) #define RET_PRIVREG(ctx) \ RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) -#define RET_MTMSR(ctx) \ -RET_EXCP((ctx), EXCP_MTMSR, 0) - +/* Stop translation */ static inline void RET_STOP (DisasContext *ctx) { - RET_EXCP(ctx, EXCP_MTMSR, 0); + gen_op_update_nip((ctx)->nip); + ctx->exception = EXCP_MTMSR; } +/* No need to update nip here, as execution flow will change */ static inline void RET_CHG_FLOW (DisasContext *ctx) { - gen_op_raise_exception_err(EXCP_MTMSR, 0); ctx->exception = EXCP_MTMSR; } @@ -2051,11 +2050,19 @@ static inline void gen_op_mfspr (DisasContext *ctx) gen_op_store_T0_gpr(rD(ctx->opcode)); } else { /* Privilege exception */ + if (loglevel) { + fprintf(logfile, "Trying to read priviledged spr %d %03x\n", + sprn, sprn); + } printf("Trying to read priviledged spr %d %03x\n", sprn, sprn); RET_PRIVREG(ctx); } } else { /* Not defined */ + if (loglevel) { + fprintf(logfile, "Trying to read invalid spr %d %03x\n", + sprn, sprn); + } printf("Trying to read invalid spr %d %03x\n", sprn, sprn); RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); } @@ -2093,7 +2100,7 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - RET_MTMSR(ctx); + RET_STOP(ctx); #endif } @@ -2115,11 +2122,19 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) (*write_cb)(ctx, sprn); } else { /* Privilege exception */ + if (loglevel) { + fprintf(logfile, "Trying to write priviledged spr %d %03x\n", + sprn, sprn); + } printf("Trying to write priviledged spr %d %03x\n", sprn, sprn); RET_PRIVREG(ctx); } } else { /* Not defined */ + if (loglevel) { + fprintf(logfile, "Trying to write invalid spr %d %03x\n", + sprn, sprn); + } printf("Trying to write invalid spr %d %03x\n", sprn, sprn); RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); } @@ -2278,7 +2293,7 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_sr(SR(ctx->opcode)); - RET_MTMSR(ctx); + RET_STOP(ctx); #endif } @@ -2295,7 +2310,7 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_store_srin(); - RET_MTMSR(ctx); + RET_STOP(ctx); #endif } @@ -2314,7 +2329,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) return; } gen_op_tlbia(); - RET_MTMSR(ctx); + RET_STOP(ctx); #endif } @@ -2330,7 +2345,7 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) } gen_op_load_gpr_T0(rB(ctx->opcode)); gen_op_tlbie(); - RET_MTMSR(ctx); + RET_STOP(ctx); #endif } @@ -2347,7 +2362,7 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) /* This has no effect: it should ensure that all previous * tlbie have completed */ - RET_MTMSR(ctx); + RET_STOP(ctx); #endif } -- cgit v1.2.3 From e80e1cc4b18d388227d2fa6b8551929a381d2490 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Nov 2005 22:05:28 +0000 Subject: halt state support for ppc git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1657 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 10 ++++++++++ monitor.c | 4 ++++ target-ppc/helper.c | 5 +++++ target-ppc/translate.c | 3 ++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index de1fff212..9543c636c 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -262,6 +262,16 @@ int cpu_exec(CPUState *env1) return EXCP_HALTED; } } +#elif defined(TARGET_PPC) + if (env1->msr[MSR_POW]) { + if (env1->msr[MSR_EE] && + (env1->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) { + env1->msr[MSR_POW] = 0; + } else { + return EXCP_HALTED; + } + } #endif cpu_single_env = env1; diff --git a/monitor.c b/monitor.c index 9befd82b0..70b473ddb 100644 --- a/monitor.c +++ b/monitor.c @@ -255,6 +255,10 @@ static void do_info_cpus(void) term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base); if (env->hflags & HF_HALTED_MASK) term_printf(" (halted)"); +#elif defined(TARGET_PPC) + term_printf(" nip=0x" TARGET_FMT_lx, env->nip); + if (msr_pow) + term_printf(" (halted)"); #endif term_printf("\n"); } diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c3b02d8cc..ff1355c54 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -846,6 +846,11 @@ void do_store_msr (CPUPPCState *env, target_ulong value) msr_ri = (value >> MSR_RI) & 1; msr_le = (value >> MSR_LE) & 1; do_compute_hflags(env); + if (msr_pow) { + /* power save: exit cpu loop */ + env->exception_index = EXCP_HLT; + cpu_loop_exit(); + } } float64 do_load_fpscr (CPUPPCState *env) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 391f82f1d..3bc6aa376 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2097,10 +2097,11 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) RET_PRIVREG(ctx); return; } + gen_op_update_nip((ctx)->nip); gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - RET_STOP(ctx); + RET_CHG_FLOW(ctx); #endif } -- cgit v1.2.3 From daa579632da11bd3108326ed04de1c096fc5f849 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 10:14:03 +0000 Subject: PS2 mouse and keyboard separation (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1658 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 6 +- hw/pckbd.c | 418 ++++++-------------------------------------------------- vl.h | 8 ++ 3 files changed, 51 insertions(+), 381 deletions(-) diff --git a/Makefile.target b/Makefile.target index 9e06fb635..9280c5922 100644 --- a/Makefile.target +++ b/Makefile.target @@ -298,13 +298,13 @@ VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support -VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +VL_OBJS+= ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) -VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +VL_OBJS+= ppc.o ide.o ne2000.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 mixeng.o DEFINES += -DHAS_AUDIO @@ -315,7 +315,7 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o +VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o ps2.o vga.o VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o VL_OBJS+= cirrus_vga.o parallel.o VL_OBJS+= magic-load.o diff --git a/hw/pckbd.c b/hw/pckbd.c index 1be1560ef..61f8a63a8 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -110,32 +110,17 @@ #define KBD_QUEUE_SIZE 256 -typedef struct { - uint8_t aux[KBD_QUEUE_SIZE]; - uint8_t data[KBD_QUEUE_SIZE]; - int rptr, wptr, count; -} KBDQueue; +#define KBD_PENDING_KBD 1 +#define KBD_PENDING_AUX 2 typedef struct KBDState { - KBDQueue queue; uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ uint8_t status; uint8_t mode; - /* keyboard state */ - int kbd_write_cmd; - int scan_enabled; - /* mouse state */ - int mouse_write_cmd; - uint8_t mouse_status; - uint8_t mouse_resolution; - uint8_t mouse_sample_rate; - uint8_t mouse_wrap; - uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ - uint8_t mouse_detect_state; - int mouse_dx; /* current values, needed for 'poll' mode */ - int mouse_dy; - int mouse_dz; - uint8_t mouse_buttons; + /* Bitmask of devices with data available. */ + int pending; + void *kbd; + void *mouse; } KBDState; KBDState kbd_state; @@ -145,15 +130,15 @@ KBDState kbd_state; incorrect, but it avoids having to simulate exact delays */ static void kbd_update_irq(KBDState *s) { - KBDQueue *q = &s->queue; int irq12_level, irq1_level; irq1_level = 0; irq12_level = 0; s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); - if (q->count != 0) { + if (s->pending) { s->status |= KBD_STAT_OBF; - if (q->aux[q->rptr]) { + /* kdb data takes priority over aux data. */ + if (s->pending == KBD_PENDING_AUX) { s->status |= KBD_STAT_MOUSE_OBF; if (s->mode & KBD_MODE_MOUSE_INT) irq12_level = 1; @@ -167,32 +152,26 @@ static void kbd_update_irq(KBDState *s) pic_set_irq(12, irq12_level); } -static void kbd_queue(KBDState *s, int b, int aux) +static void kbd_update_kbd_irq(void *opaque, int level) { - KBDQueue *q = &s->queue; + KBDState *s = (KBDState *)opaque; -#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) - if (aux) - printf("mouse event: 0x%02x\n", b); -#ifdef DEBUG_KBD + if (level) + s->pending |= KBD_PENDING_KBD; else - printf("kbd event: 0x%02x\n", b); -#endif -#endif - if (q->count >= KBD_QUEUE_SIZE) - return; - q->aux[q->wptr] = aux; - q->data[q->wptr] = b; - if (++q->wptr == KBD_QUEUE_SIZE) - q->wptr = 0; - q->count++; + s->pending &= ~KBD_PENDING_KBD; kbd_update_irq(s); } -static void pc_kbd_put_keycode(void *opaque, int keycode) +static void kbd_update_aux_irq(void *opaque, int level) { - KBDState *s = opaque; - kbd_queue(s, keycode, 0); + KBDState *s = (KBDState *)opaque; + + if (level) + s->pending |= KBD_PENDING_AUX; + else + s->pending &= ~KBD_PENDING_AUX; + kbd_update_irq(s); } static uint32_t kbd_read_status(void *opaque, uint32_t addr) @@ -206,6 +185,14 @@ static uint32_t kbd_read_status(void *opaque, uint32_t addr) return val; } +static void kbd_queue(KBDState *s, int b, int aux) +{ + if (aux) + ps2_queue(s->mouse, b); + else + ps2_queue(s->kbd, b); +} + static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) { KBDState *s = opaque; @@ -285,306 +272,13 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) } static uint32_t kbd_read_data(void *opaque, uint32_t addr) -{ - KBDState *s = opaque; - KBDQueue *q; - int val, index, aux; - - q = &s->queue; - if (q->count == 0) { - /* NOTE: if no data left, we return the last keyboard one - (needed for EMM386) */ - /* XXX: need a timer to do things correctly */ - index = q->rptr - 1; - if (index < 0) - index = KBD_QUEUE_SIZE - 1; - val = q->data[index]; - } else { - aux = q->aux[q->rptr]; - val = q->data[q->rptr]; - if (++q->rptr == KBD_QUEUE_SIZE) - q->rptr = 0; - q->count--; - /* reading deasserts IRQ */ - if (aux) - pic_set_irq(12, 0); - else - pic_set_irq(1, 0); - } - /* reassert IRQs if data left */ - kbd_update_irq(s); -#ifdef DEBUG_KBD - printf("kbd: read data=0x%02x\n", val); -#endif - return val; -} - -static void kbd_reset_keyboard(KBDState *s) -{ - s->scan_enabled = 1; -} - -static void kbd_write_keyboard(KBDState *s, int val) -{ - switch(s->kbd_write_cmd) { - default: - case -1: - switch(val) { - case 0x00: - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case 0x05: - kbd_queue(s, KBD_REPLY_RESEND, 0); - break; - case KBD_CMD_GET_ID: - kbd_queue(s, KBD_REPLY_ACK, 0); - kbd_queue(s, 0xab, 0); - kbd_queue(s, 0x83, 0); - break; - case KBD_CMD_ECHO: - kbd_queue(s, KBD_CMD_ECHO, 0); - break; - case KBD_CMD_ENABLE: - s->scan_enabled = 1; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_SET_LEDS: - case KBD_CMD_SET_RATE: - s->kbd_write_cmd = val; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET_DISABLE: - kbd_reset_keyboard(s); - s->scan_enabled = 0; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET_ENABLE: - kbd_reset_keyboard(s); - s->scan_enabled = 1; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET: - kbd_reset_keyboard(s); - kbd_queue(s, KBD_REPLY_ACK, 0); - kbd_queue(s, KBD_REPLY_POR, 0); - break; - default: - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - } - break; - case KBD_CMD_SET_LEDS: - kbd_queue(s, KBD_REPLY_ACK, 0); - s->kbd_write_cmd = -1; - break; - case KBD_CMD_SET_RATE: - kbd_queue(s, KBD_REPLY_ACK, 0); - s->kbd_write_cmd = -1; - break; - } -} - -static void kbd_mouse_send_packet(KBDState *s) -{ - unsigned int b; - int dx1, dy1, dz1; - - dx1 = s->mouse_dx; - dy1 = s->mouse_dy; - dz1 = s->mouse_dz; - /* XXX: increase range to 8 bits ? */ - if (dx1 > 127) - dx1 = 127; - else if (dx1 < -127) - dx1 = -127; - if (dy1 > 127) - dy1 = 127; - else if (dy1 < -127) - dy1 = -127; - b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); - kbd_queue(s, b, 1); - kbd_queue(s, dx1 & 0xff, 1); - kbd_queue(s, dy1 & 0xff, 1); - /* extra byte for IMPS/2 or IMEX */ - switch(s->mouse_type) { - default: - break; - case 3: - if (dz1 > 127) - dz1 = 127; - else if (dz1 < -127) - dz1 = -127; - kbd_queue(s, dz1 & 0xff, 1); - break; - case 4: - if (dz1 > 7) - dz1 = 7; - else if (dz1 < -7) - dz1 = -7; - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); - kbd_queue(s, b, 1); - break; - } - - /* update deltas */ - s->mouse_dx -= dx1; - s->mouse_dy -= dy1; - s->mouse_dz -= dz1; -} - -static void pc_kbd_mouse_event(void *opaque, - int dx, int dy, int dz, int buttons_state) { KBDState *s = opaque; - /* check if deltas are recorded when disabled */ - if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) - return; - - s->mouse_dx += dx; - s->mouse_dy -= dy; - s->mouse_dz += dz; - /* XXX: SDL sometimes generates nul events: we delete them */ - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && - s->mouse_buttons == buttons_state) - return; - s->mouse_buttons = buttons_state; - - if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && - (s->queue.count < (KBD_QUEUE_SIZE - 16))) { - for(;;) { - /* if not remote, send event. Multiple events are sent if - too big deltas */ - kbd_mouse_send_packet(s); - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) - break; - } - } -} + if (s->pending == KBD_PENDING_AUX) + return ps2_read_data(s->mouse); -static void kbd_write_mouse(KBDState *s, int val) -{ -#ifdef DEBUG_MOUSE - printf("kbd: write mouse 0x%02x\n", val); -#endif - switch(s->mouse_write_cmd) { - default: - case -1: - /* mouse command */ - if (s->mouse_wrap) { - if (val == AUX_RESET_WRAP) { - s->mouse_wrap = 0; - kbd_queue(s, AUX_ACK, 1); - return; - } else if (val != AUX_RESET) { - kbd_queue(s, val, 1); - return; - } - } - switch(val) { - case AUX_SET_SCALE11: - s->mouse_status &= ~MOUSE_STATUS_SCALE21; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_SCALE21: - s->mouse_status |= MOUSE_STATUS_SCALE21; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_STREAM: - s->mouse_status &= ~MOUSE_STATUS_REMOTE; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_WRAP: - s->mouse_wrap = 1; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_REMOTE: - s->mouse_status |= MOUSE_STATUS_REMOTE; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_GET_TYPE: - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, s->mouse_type, 1); - break; - case AUX_SET_RES: - case AUX_SET_SAMPLE: - s->mouse_write_cmd = val; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_GET_SCALE: - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, s->mouse_status, 1); - kbd_queue(s, s->mouse_resolution, 1); - kbd_queue(s, s->mouse_sample_rate, 1); - break; - case AUX_POLL: - kbd_queue(s, AUX_ACK, 1); - kbd_mouse_send_packet(s); - break; - case AUX_ENABLE_DEV: - s->mouse_status |= MOUSE_STATUS_ENABLED; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_DISABLE_DEV: - s->mouse_status &= ~MOUSE_STATUS_ENABLED; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_DEFAULT: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_RESET: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - s->mouse_type = 0; - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, 0xaa, 1); - kbd_queue(s, s->mouse_type, 1); - break; - default: - break; - } - break; - case AUX_SET_SAMPLE: - s->mouse_sample_rate = val; - /* detect IMPS/2 or IMEX */ - switch(s->mouse_detect_state) { - default: - case 0: - if (val == 200) - s->mouse_detect_state = 1; - break; - case 1: - if (val == 100) - s->mouse_detect_state = 2; - else if (val == 200) - s->mouse_detect_state = 3; - else - s->mouse_detect_state = 0; - break; - case 2: - if (val == 80) - s->mouse_type = 3; /* IMPS/2 */ - s->mouse_detect_state = 0; - break; - case 3: - if (val == 80) - s->mouse_type = 4; /* IMEX */ - s->mouse_detect_state = 0; - break; - } - kbd_queue(s, AUX_ACK, 1); - s->mouse_write_cmd = -1; - break; - case AUX_SET_RES: - s->mouse_resolution = val; - kbd_queue(s, AUX_ACK, 1); - s->mouse_write_cmd = -1; - break; - } + return ps2_read_data(s->kbd); } void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) @@ -597,10 +291,11 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) switch(s->write_cmd) { case 0: - kbd_write_keyboard(s, val); + ps2_write_keyboard(s->kbd, val); break; case KBD_CCMD_WRITE_MODE: s->mode = val; + /* ??? */ kbd_update_irq(s); break; case KBD_CCMD_WRITE_OBUF: @@ -618,7 +313,7 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) } break; case KBD_CCMD_WRITE_MOUSE: - kbd_write_mouse(s, val); + ps2_write_mouse(s->mouse, val); break; default: break; @@ -629,16 +324,9 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) static void kbd_reset(void *opaque) { KBDState *s = opaque; - KBDQueue *q; - s->kbd_write_cmd = -1; - s->mouse_write_cmd = -1; s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; - q = &s->queue; - q->rptr = 0; - q->wptr = 0; - q->count = 0; } static void kbd_save(QEMUFile* f, void* opaque) @@ -648,43 +336,17 @@ static void kbd_save(QEMUFile* f, void* opaque) qemu_put_8s(f, &s->write_cmd); qemu_put_8s(f, &s->status); qemu_put_8s(f, &s->mode); - qemu_put_be32s(f, &s->kbd_write_cmd); - qemu_put_be32s(f, &s->scan_enabled); - qemu_put_be32s(f, &s->mouse_write_cmd); - qemu_put_8s(f, &s->mouse_status); - qemu_put_8s(f, &s->mouse_resolution); - qemu_put_8s(f, &s->mouse_sample_rate); - qemu_put_8s(f, &s->mouse_wrap); - qemu_put_8s(f, &s->mouse_type); - qemu_put_8s(f, &s->mouse_detect_state); - qemu_put_be32s(f, &s->mouse_dx); - qemu_put_be32s(f, &s->mouse_dy); - qemu_put_be32s(f, &s->mouse_dz); - qemu_put_8s(f, &s->mouse_buttons); } static int kbd_load(QEMUFile* f, void* opaque, int version_id) { KBDState *s = (KBDState*)opaque; - if (version_id != 1) + if (version_id != 2) return -EINVAL; qemu_get_8s(f, &s->write_cmd); qemu_get_8s(f, &s->status); qemu_get_8s(f, &s->mode); - qemu_get_be32s(f, &s->kbd_write_cmd); - qemu_get_be32s(f, &s->scan_enabled); - qemu_get_be32s(f, &s->mouse_write_cmd); - qemu_get_8s(f, &s->mouse_status); - qemu_get_8s(f, &s->mouse_resolution); - qemu_get_8s(f, &s->mouse_sample_rate); - qemu_get_8s(f, &s->mouse_wrap); - qemu_get_8s(f, &s->mouse_type); - qemu_get_8s(f, &s->mouse_detect_state); - qemu_get_be32s(f, &s->mouse_dx); - qemu_get_be32s(f, &s->mouse_dy); - qemu_get_be32s(f, &s->mouse_dz); - qemu_get_8s(f, &s->mouse_buttons); return 0; } @@ -693,13 +355,13 @@ void kbd_init(void) KBDState *s = &kbd_state; kbd_reset(s); - register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s); + register_savevm("pckbd", 0, 2, kbd_save, kbd_load, s); register_ioport_read(0x60, 1, 1, kbd_read_data, s); register_ioport_write(0x60, 1, 1, kbd_write_data, s); register_ioport_read(0x64, 1, 1, kbd_read_status, s); register_ioport_write(0x64, 1, 1, kbd_write_command, s); - qemu_add_kbd_event_handler(pc_kbd_put_keycode, s); - qemu_add_mouse_event_handler(pc_kbd_mouse_event, s); + s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); + s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); qemu_register_reset(kbd_reset, s); } diff --git a/vl.h b/vl.h index 2326c4c18..6f4ac7f88 100644 --- a/vl.h +++ b/vl.h @@ -928,6 +928,14 @@ void do_usb_add(const char *devname); void do_usb_del(const char *devname); void usb_info(void); +/* ps2.c */ +void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); +void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); +void ps2_write_mouse(void *, int val); +void ps2_write_keyboard(void *, int val); +uint32_t ps2_read_data(void *); +void ps2_queue(void *, int b); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From 98699967b8f49bb0537aab882242b2045bdb05fc Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 10:29:22 +0000 Subject: use TARGET_PAGE_SIZE (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1659 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 4 +++- softmmu_template.h | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index b1c4b2082..d2086d56b 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -733,6 +733,8 @@ extern int code_copy_enabled; #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. */ + void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); @@ -790,9 +792,9 @@ extern uint8_t *phys_ram_base; extern uint8_t *phys_ram_dirty; /* physical memory access */ -#define IO_MEM_NB_ENTRIES 256 #define TLB_INVALID_MASK (1 << 3) #define IO_MEM_SHIFT 4 +#define IO_MEM_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 */ diff --git a/softmmu_template.h b/softmmu_template.h index 558bb8be8..a99bedf48 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -91,7 +91,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; res = glue(io_read, SUFFIX)(physaddr, tlb_addr); - } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { /* slow unaligned access (it spans two pages or IO) */ do_unaligned_access: retaddr = GETPC(); @@ -130,7 +130,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; res = glue(io_read, SUFFIX)(physaddr, tlb_addr); - } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* slow unaligned access (it spans two pages) */ addr1 = addr & ~(DATA_SIZE - 1); @@ -208,7 +208,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, goto do_unaligned_access; retaddr = GETPC(); glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr); - } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: retaddr = GETPC(); glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, @@ -245,7 +245,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr); - } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* XXX: not efficient, but simple */ for(i = 0;i < DATA_SIZE; i++) { -- cgit v1.2.3 From 0e43e99c045eb22415a7e52e2f88dbdb8e2d96f5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 10:36:25 +0000 Subject: PS2 mouse and keyboard separation (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1660 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ps2.c | 512 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 512 insertions(+) create mode 100644 hw/ps2.c diff --git a/hw/ps2.c b/hw/ps2.c new file mode 100644 index 000000000..e7c66f648 --- /dev/null +++ b/hw/ps2.c @@ -0,0 +1,512 @@ +/* + * QEMU PS/2 keyboard/mouse emulation + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* debug PC keyboard */ +//#define DEBUG_KBD + +/* debug PC keyboard : only mouse */ +//#define DEBUG_MOUSE + +/* Keyboard Commands */ +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_ECHO 0xEE +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* Keyboard Replies */ +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* Mouse Commands */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_POLL 0xEB /* Poll */ +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ +#define AUX_GET_TYPE 0xF2 /* Get type */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_SET_DEFAULT 0xF6 +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define MOUSE_STATUS_REMOTE 0x40 +#define MOUSE_STATUS_ENABLED 0x20 +#define MOUSE_STATUS_SCALE21 0x10 + +#define PS2_QUEUE_SIZE 256 + +typedef struct { + uint8_t data[PS2_QUEUE_SIZE]; + int rptr, wptr, count; +} PS2Queue; + +typedef struct { + PS2Queue queue; + int32_t write_cmd; + void (*update_irq)(void *, int); + void *update_arg; +} PS2State; + +typedef struct { + PS2State common; + int scan_enabled; +} PS2KbdState; + +typedef struct { + PS2State common; + uint8_t mouse_status; + uint8_t mouse_resolution; + uint8_t mouse_sample_rate; + uint8_t mouse_wrap; + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ + uint8_t mouse_detect_state; + int mouse_dx; /* current values, needed for 'poll' mode */ + int mouse_dy; + int mouse_dz; + uint8_t mouse_buttons; +} PS2MouseState; + +void ps2_queue(void *opaque, int b) +{ + PS2State *s = (PS2State *)opaque; + PS2Queue *q = &s->queue; + + if (q->count >= PS2_QUEUE_SIZE) + return; + q->data[q->wptr] = b; + if (++q->wptr == PS2_QUEUE_SIZE) + q->wptr = 0; + q->count++; + s->update_irq(s->update_arg, 1); +} + +static void ps2_put_keycode(void *opaque, int keycode) +{ + PS2MouseState *s = opaque; + ps2_queue(&s->common, keycode); +} + +uint32_t ps2_read_data(void *opaque) +{ + PS2State *s = (PS2State *)opaque; + PS2Queue *q; + int val, index; + + q = &s->queue; + if (q->count == 0) { + /* NOTE: if no data left, we return the last keyboard one + (needed for EMM386) */ + /* XXX: need a timer to do things correctly */ + index = q->rptr - 1; + if (index < 0) + index = PS2_QUEUE_SIZE - 1; + val = q->data[index]; + } else { + val = q->data[q->rptr]; + if (++q->rptr == PS2_QUEUE_SIZE) + q->rptr = 0; + q->count--; + /* reading deasserts IRQ */ + s->update_irq(s->update_arg, 0); + /* reassert IRQs if data left */ + s->update_irq(s->update_arg, q->count != 0); + } + return val; +} + +static void ps2_reset_keyboard(PS2KbdState *s) +{ + s->scan_enabled = 1; +} + +void ps2_write_keyboard(void *opaque, int val) +{ + PS2KbdState *s = (PS2KbdState *)opaque; + + switch(s->common.write_cmd) { + default: + case -1: + switch(val) { + case 0x00: + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case 0x05: + ps2_queue(&s->common, KBD_REPLY_RESEND); + break; + case KBD_CMD_GET_ID: + ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue(&s->common, 0xab); + ps2_queue(&s->common, 0x83); + break; + case KBD_CMD_ECHO: + ps2_queue(&s->common, KBD_CMD_ECHO); + break; + case KBD_CMD_ENABLE: + s->scan_enabled = 1; + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case KBD_CMD_SET_LEDS: + case KBD_CMD_SET_RATE: + s->common.write_cmd = val; + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case KBD_CMD_RESET_DISABLE: + ps2_reset_keyboard(s); + s->scan_enabled = 0; + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case KBD_CMD_RESET_ENABLE: + ps2_reset_keyboard(s); + s->scan_enabled = 1; + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case KBD_CMD_RESET: + ps2_reset_keyboard(s); + ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue(&s->common, KBD_REPLY_POR); + break; + default: + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + } + break; + case KBD_CMD_SET_LEDS: + ps2_queue(&s->common, KBD_REPLY_ACK); + s->common.write_cmd = -1; + break; + case KBD_CMD_SET_RATE: + ps2_queue(&s->common, KBD_REPLY_ACK); + s->common.write_cmd = -1; + break; + } +} + +static void ps2_mouse_send_packet(PS2MouseState *s) +{ + unsigned int b; + int dx1, dy1, dz1; + + dx1 = s->mouse_dx; + dy1 = s->mouse_dy; + dz1 = s->mouse_dz; + /* XXX: increase range to 8 bits ? */ + if (dx1 > 127) + dx1 = 127; + else if (dx1 < -127) + dx1 = -127; + if (dy1 > 127) + dy1 = 127; + else if (dy1 < -127) + dy1 = -127; + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); + ps2_queue(&s->common, b); + ps2_queue(&s->common, dx1 & 0xff); + ps2_queue(&s->common, dy1 & 0xff); + /* extra byte for IMPS/2 or IMEX */ + switch(s->mouse_type) { + default: + break; + case 3: + if (dz1 > 127) + dz1 = 127; + else if (dz1 < -127) + dz1 = -127; + ps2_queue(&s->common, dz1 & 0xff); + break; + case 4: + if (dz1 > 7) + dz1 = 7; + else if (dz1 < -7) + dz1 = -7; + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); + ps2_queue(&s->common, b); + break; + } + + /* update deltas */ + s->mouse_dx -= dx1; + s->mouse_dy -= dy1; + s->mouse_dz -= dz1; +} + +static void ps2_mouse_event(void *opaque, + int dx, int dy, int dz, int buttons_state) +{ + PS2MouseState *s = opaque; + + /* check if deltas are recorded when disabled */ + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) + return; + + s->mouse_dx += dx; + s->mouse_dy -= dy; + s->mouse_dz += dz; + /* XXX: SDL sometimes generates nul events: we delete them */ + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && + s->mouse_buttons == buttons_state) + return; + s->mouse_buttons = buttons_state; + + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && + (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) { + for(;;) { + /* if not remote, send event. Multiple events are sent if + too big deltas */ + ps2_mouse_send_packet(s); + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) + break; + } + } +} + +void ps2_write_mouse(void *opaque, int val) +{ + PS2MouseState *s = (PS2MouseState *)opaque; +#ifdef DEBUG_MOUSE + printf("kbd: write mouse 0x%02x\n", val); +#endif + switch(s->common.write_cmd) { + default: + case -1: + /* mouse command */ + if (s->mouse_wrap) { + if (val == AUX_RESET_WRAP) { + s->mouse_wrap = 0; + ps2_queue(&s->common, AUX_ACK); + return; + } else if (val != AUX_RESET) { + ps2_queue(&s->common, val); + return; + } + } + switch(val) { + case AUX_SET_SCALE11: + s->mouse_status &= ~MOUSE_STATUS_SCALE21; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_SCALE21: + s->mouse_status |= MOUSE_STATUS_SCALE21; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_STREAM: + s->mouse_status &= ~MOUSE_STATUS_REMOTE; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_WRAP: + s->mouse_wrap = 1; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_REMOTE: + s->mouse_status |= MOUSE_STATUS_REMOTE; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_GET_TYPE: + ps2_queue(&s->common, AUX_ACK); + ps2_queue(&s->common, s->mouse_type); + break; + case AUX_SET_RES: + case AUX_SET_SAMPLE: + s->common.write_cmd = val; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_GET_SCALE: + ps2_queue(&s->common, AUX_ACK); + ps2_queue(&s->common, s->mouse_status); + ps2_queue(&s->common, s->mouse_resolution); + ps2_queue(&s->common, s->mouse_sample_rate); + break; + case AUX_POLL: + ps2_queue(&s->common, AUX_ACK); + ps2_mouse_send_packet(s); + break; + case AUX_ENABLE_DEV: + s->mouse_status |= MOUSE_STATUS_ENABLED; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_DISABLE_DEV: + s->mouse_status &= ~MOUSE_STATUS_ENABLED; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_DEFAULT: + s->mouse_sample_rate = 100; + s->mouse_resolution = 2; + s->mouse_status = 0; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_RESET: + s->mouse_sample_rate = 100; + s->mouse_resolution = 2; + s->mouse_status = 0; + s->mouse_type = 0; + ps2_queue(&s->common, AUX_ACK); + ps2_queue(&s->common, 0xaa); + ps2_queue(&s->common, s->mouse_type); + break; + default: + break; + } + break; + case AUX_SET_SAMPLE: + s->mouse_sample_rate = val; + /* detect IMPS/2 or IMEX */ + switch(s->mouse_detect_state) { + default: + case 0: + if (val == 200) + s->mouse_detect_state = 1; + break; + case 1: + if (val == 100) + s->mouse_detect_state = 2; + else if (val == 200) + s->mouse_detect_state = 3; + else + s->mouse_detect_state = 0; + break; + case 2: + if (val == 80) + s->mouse_type = 3; /* IMPS/2 */ + s->mouse_detect_state = 0; + break; + case 3: + if (val == 80) + s->mouse_type = 4; /* IMEX */ + s->mouse_detect_state = 0; + break; + } + ps2_queue(&s->common, AUX_ACK); + s->common.write_cmd = -1; + break; + case AUX_SET_RES: + s->mouse_resolution = val; + ps2_queue(&s->common, AUX_ACK); + s->common.write_cmd = -1; + break; + } +} + +static void ps2_reset(void *opaque) +{ + PS2State *s = (PS2State *)opaque; + PS2Queue *q; + s->write_cmd = -1; + q = &s->queue; + q->rptr = 0; + q->wptr = 0; + q->count = 0; +} + +static void ps2_kbd_save(QEMUFile* f, void* opaque) +{ + PS2KbdState *s = (PS2KbdState*)opaque; + + qemu_put_be32s(f, &s->common.write_cmd); + qemu_put_be32s(f, &s->scan_enabled); +} + +static void ps2_mouse_save(QEMUFile* f, void* opaque) +{ + PS2MouseState *s = (PS2MouseState*)opaque; + + qemu_put_be32s(f, &s->common.write_cmd); + qemu_put_8s(f, &s->mouse_status); + qemu_put_8s(f, &s->mouse_resolution); + qemu_put_8s(f, &s->mouse_sample_rate); + qemu_put_8s(f, &s->mouse_wrap); + qemu_put_8s(f, &s->mouse_type); + qemu_put_8s(f, &s->mouse_detect_state); + qemu_put_be32s(f, &s->mouse_dx); + qemu_put_be32s(f, &s->mouse_dy); + qemu_put_be32s(f, &s->mouse_dz); + qemu_put_8s(f, &s->mouse_buttons); +} + +static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id) +{ + PS2KbdState *s = (PS2KbdState*)opaque; + + if (version_id != 1) + return -EINVAL; + qemu_get_be32s(f, &s->common.write_cmd); + qemu_get_be32s(f, &s->scan_enabled); + return 0; +} + +static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id) +{ + PS2MouseState *s = (PS2MouseState*)opaque; + + if (version_id != 1) + return -EINVAL; + qemu_get_be32s(f, &s->common.write_cmd); + qemu_get_8s(f, &s->mouse_status); + qemu_get_8s(f, &s->mouse_resolution); + qemu_get_8s(f, &s->mouse_sample_rate); + qemu_get_8s(f, &s->mouse_wrap); + qemu_get_8s(f, &s->mouse_type); + qemu_get_8s(f, &s->mouse_detect_state); + qemu_get_be32s(f, &s->mouse_dx); + qemu_get_be32s(f, &s->mouse_dy); + qemu_get_be32s(f, &s->mouse_dz); + qemu_get_8s(f, &s->mouse_buttons); + return 0; +} + +void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) +{ + PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState)); + + s->common.update_irq = update_irq; + s->common.update_arg = update_arg; + ps2_reset(&s->common); + register_savevm("ps2kbd", 0, 1, ps2_kbd_save, ps2_kbd_load, s); + qemu_add_kbd_event_handler(ps2_put_keycode, s); + qemu_register_reset(ps2_reset, &s->common); + return s; +} + +void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) +{ + PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState)); + + s->common.update_irq = update_irq; + s->common.update_arg = update_arg; + ps2_reset(&s->common); + register_savevm("ps2mouse", 0, 1, ps2_mouse_save, ps2_mouse_load, s); + qemu_add_mouse_event_handler(ps2_mouse_event, s); + qemu_register_reset(ps2_reset, &s->common); + return s; +} -- cgit v1.2.3 From b5ff1b3127119aa430a6fd309591d584803b7b6e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 10:38:39 +0000 Subject: ARM system emulation (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1661 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 +- Makefile.target | 5 +- configure | 2 +- cpu-exec.c | 33 +- exec-all.h | 4 +- exec.c | 4 +- gdbstub.c | 8 +- hw/integratorcp.c | 1232 ++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/main.c | 10 +- linux-user/signal.c | 10 +- softmmu_header.h | 8 + target-arm/cpu.h | 100 +++- target-arm/exec.h | 17 +- target-arm/helper.c | 555 ++++++++++++++++++++++ target-arm/op.c | 184 ++++---- target-arm/op_helper.c | 51 ++ target-arm/op_mem.h | 70 +++ target-arm/translate.c | 470 +++++++++++++----- vl.c | 17 + vl.h | 3 + 20 files changed, 2539 insertions(+), 248 deletions(-) create mode 100644 hw/integratorcp.c create mode 100644 target-arm/helper.c create mode 100644 target-arm/op_mem.h diff --git a/Changelog b/Changelog index 041658d68..d386474ac 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,8 @@ version 0.7.3: + - 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) @@ -10,7 +13,6 @@ version 0.7.3: - Linux host serial port access - Linux host low level parallel port access - New network emulation code supporting VLANs. - - SMP support version 0.7.2: diff --git a/Makefile.target b/Makefile.target index 9280c5922..dd33e790a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -211,7 +211,7 @@ LIBOBJS+= op_helper.o helper.o endif ifeq ($(TARGET_BASE_ARCH), arm) -LIBOBJS+= op_helper.o +LIBOBJS+= op_helper.o helper.o endif # NOTE: the disassembler code is only needed for debugging @@ -324,6 +324,9 @@ VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o magic-load.o slavio_intctl.o VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o endif endif +ifeq ($(TARGET_BASE_ARCH), arm) +VL_OBJS+= integratorcp.o ps2.o +endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o endif diff --git a/configure b/configure index ee3b7f33e..bad61e960 100755 --- a/configure +++ b/configure @@ -227,7 +227,7 @@ fi if test -z "$target_list" ; then # these targets are portable - target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu arm-softmmu" # the following are Linux specific if [ "$linux" = "yes" ] ; then target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list" diff --git a/cpu-exec.c b/cpu-exec.c index 9543c636c..f411eccf8 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -172,7 +172,9 @@ static inline TranslationBlock *tb_find_fast(void) pc = cs_base + env->eip; #elif defined(TARGET_ARM) flags = env->thumb | (env->vfp.vec_len << 1) - | (env->vfp.vec_stride << 4); + | (env->vfp.vec_stride << 4); + if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) + flags |= (1 << 6); cs_base = 0; pc = env->regs[15]; #elif defined(TARGET_SPARC) @@ -322,15 +324,6 @@ int cpu_exec(CPUState *env1) CC_OP = CC_OP_EFLAGS; env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_ARM) - { - unsigned int psr; - psr = env->cpsr; - env->CF = (psr >> 29) & 1; - env->NZF = (psr & 0xc0000000) ^ 0x40000000; - env->VF = (psr << 3) & 0x80000000; - env->QF = (psr >> 27) & 1; - env->cpsr = psr & ~CACHED_CPSR_BITS; - } #elif defined(TARGET_SPARC) #if defined(reg_REGWPTR) saved_regwptr = REGWPTR; @@ -379,6 +372,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_SPARC) do_interrupt(env->exception_index); +#elif defined(TARGET_ARM) + do_interrupt(env); #endif } env->exception_index = -1; @@ -508,8 +503,19 @@ int cpu_exec(CPUState *env1) //do_interrupt(0, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; } +#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); + } #endif - if (interrupt_request & CPU_INTERRUPT_EXITTB) { + 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 */ @@ -526,7 +532,7 @@ int cpu_exec(CPUState *env1) } } #ifdef DEBUG_EXEC - if ((loglevel & CPU_LOG_EXEC)) { + if ((loglevel & CPU_LOG_TB_CPU)) { #if defined(TARGET_I386) /* restore flags in standard format */ #ifdef reg_EAX @@ -557,9 +563,7 @@ int cpu_exec(CPUState *env1) 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) - env->cpsr = compute_cpsr(); cpu_dump_state(env, logfile, fprintf, 0); - env->cpsr &= ~CACHED_CPSR_BITS; #elif defined(TARGET_SPARC) REGWPTR = env->regbase + (env->cwp * 16); env->regwptr = REGWPTR; @@ -760,7 +764,6 @@ int cpu_exec(CPUState *env1) EDI = saved_EDI; #endif #elif defined(TARGET_ARM) - env->cpsr = compute_cpsr(); /* XXX: Save/restore host fpu exception state?. */ #elif defined(TARGET_SPARC) #if defined(reg_REGWPTR) diff --git a/exec-all.h b/exec-all.h index 67aa227ad..9034ce869 100644 --- a/exec-all.h +++ b/exec-all.h @@ -549,8 +549,10 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); #elif defined (TARGET_SPARC) is_user = (env->psrs == 0); +#elif defined (TARGET_ARM) + is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR); #else -#error "Unimplemented !" +#error unimplemented CPU #endif if (__builtin_expect(env->tlb_read[is_user][index].address != (addr & TARGET_PAGE_MASK), 0)) { diff --git a/exec.c b/exec.c index 3dbd3eb07..b9009a1e9 100644 --- a/exec.c +++ b/exec.c @@ -1868,14 +1868,14 @@ int cpu_register_io_memory(int io_index, int i; if (io_index <= 0) { - if (io_index >= IO_MEM_NB_ENTRIES) + if (io_mem_nb >= IO_MEM_NB_ENTRIES) return -1; io_index = io_mem_nb++; } else { if (io_index >= IO_MEM_NB_ENTRIES) return -1; } - + for(i = 0;i < 3; i++) { io_mem_read[io_index][i] = mem_read[i]; io_mem_write[io_index][i] = mem_write[i]; diff --git a/gdbstub.c b/gdbstub.c index ef76fb06a..29c7a0108 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -399,7 +399,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) memset (ptr, 0, 8 * 12 + 4); ptr += 8 * 12 + 4; /* CPSR (4 bytes). */ - *(uint32_t *)ptr = tswapl (env->cpsr); + *(uint32_t *)ptr = tswapl (cpsr_read(env)); ptr += 4; return ptr - mem_buf; @@ -419,7 +419,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* Ignore FPA regs and scr. */ ptr += 8 * 12 + 4; - env->cpsr = tswapl(*(uint32_t *)ptr); + cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff); } #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) @@ -463,6 +463,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_SPARC) env->pc = addr; env->npc = addr + 4; +#elif defined (TARGET_ARM) + env->regs[15] = addr; #endif } #ifdef CONFIG_USER_ONLY @@ -481,6 +483,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_SPARC) env->pc = addr; env->npc = addr + 4; +#elif defined (TARGET_ARM) + env->regs[15] = addr; #endif } cpu_single_step(env, 1); diff --git a/hw/integratorcp.c b/hw/integratorcp.c new file mode 100644 index 000000000..957a94389 --- /dev/null +++ b/hw/integratorcp.c @@ -0,0 +1,1232 @@ +/* + * ARM Integrator CP System emulation. + * + * Copyright (c) 2005 CodeSourcery, LLC. + * Written by Paul Brook + * + * This code is licenced under the GPL + */ + +#include + +#define KERNEL_ARGS_ADDR 0x100 +#define KERNEL_LOAD_ADDR 0x00010000 +#define INITRD_LOAD_ADDR 0x00800000 + +/* Stub functions for hardware that doesn't exist. */ +void pic_set_irq(int irq, int level) +{ + cpu_abort (cpu_single_env, "pic_set_irq"); +} + +void pic_info(void) +{ +} + +void irq_info(void) +{ +} + +void vga_update_display(void) +{ +} + +void vga_screen_dump(const char *filename) +{ +} + +void vga_invalidate_display(void) +{ +} + +void DMA_run (void) +{ +} + +typedef struct { + uint32_t flash_offset; + uint32_t cm_osc; + uint32_t cm_ctrl; + uint32_t cm_lock; + uint32_t cm_auxosc; + uint32_t cm_sdram; + uint32_t cm_init; + uint32_t cm_flags; + uint32_t cm_nvflags; + uint32_t int_level; + uint32_t irq_enabled; + uint32_t fiq_enabled; +} integratorcm_state; + +static uint8_t integrator_spd[128] = { + 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1, + 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 +}; + +static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset) +{ + integratorcm_state *s = (integratorcm_state *)opaque; + offset -= 0x10000000; + if (offset >= 0x100 && offset < 0x200) { + /* CM_SPD */ + if (offset >= 0x180) + return 0; + return integrator_spd[offset >> 2]; + } + switch (offset >> 2) { + case 0: /* CM_ID */ + return 0x411a3001; + case 1: /* CM_PROC */ + return 0; + case 2: /* CM_OSC */ + return s->cm_osc; + case 3: /* CM_CTRL */ + return s->cm_ctrl; + case 4: /* CM_STAT */ + return 0x00100000; + case 5: /* CM_LOCK */ + if (s->cm_lock == 0xa05f) { + return 0x1a05f; + } else { + return s->cm_lock; + } + case 6: /* CM_LMBUSCNT */ + /* ??? High frequency timer. */ + cpu_abort(cpu_single_env, "integratorcm_read: CM_LMBUSCNT"); + case 7: /* CM_AUXOSC */ + return s->cm_auxosc; + case 8: /* CM_SDRAM */ + return s->cm_sdram; + case 9: /* CM_INIT */ + return s->cm_init; + case 10: /* CM_REFCT */ + /* ??? High frequency timer. */ + cpu_abort(cpu_single_env, "integratorcm_read: CM_REFCT"); + case 12: /* CM_FLAGS */ + return s->cm_flags; + case 14: /* CM_NVFLAGS */ + return s->cm_nvflags; + case 16: /* CM_IRQ_STAT */ + return s->int_level & s->irq_enabled; + case 17: /* CM_IRQ_RSTAT */ + return s->int_level; + case 18: /* CM_IRQ_ENSET */ + return s->irq_enabled; + case 20: /* CM_SOFT_INTSET */ + return s->int_level & 1; + case 24: /* CM_FIQ_STAT */ + return s->int_level & s->fiq_enabled; + case 25: /* CM_FIQ_RSTAT */ + return s->int_level; + case 26: /* CM_FIQ_ENSET */ + return s->fiq_enabled; + case 32: /* CM_VOLTAGE_CTL0 */ + case 33: /* CM_VOLTAGE_CTL1 */ + case 34: /* CM_VOLTAGE_CTL2 */ + case 35: /* CM_VOLTAGE_CTL3 */ + /* ??? Voltage control unimplemented. */ + return 0; + default: + cpu_abort (cpu_single_env, + "integratorcm_read: Unimplemented offset 0x%x\n", offset); + return 0; + } +} + +static void integratorcm_do_remap(integratorcm_state *s, int flash) +{ + if (flash) { + cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM); + } else { + cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM); + } + //??? tlb_flush (cpu_single_env, 1); +} + +static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) +{ + if (value & 8) { + cpu_abort(cpu_single_env, "Board reset\n"); + } + if ((s->cm_init ^ value) & 4) { + integratorcm_do_remap(s, (value & 4) == 0); + } + if ((s->cm_init ^ value) & 1) { + printf("Green LED %s\n", (value & 1) ? "on" : "off"); + } + s->cm_init = (s->cm_init & ~ 5) | (value ^ 5); +} + +static void integratorcm_update(integratorcm_state *s) +{ + /* ??? The CPU irq/fiq is raised when either the core module or base PIC + are active. */ + if (s->int_level & (s->irq_enabled | s->fiq_enabled)) + cpu_abort(cpu_single_env, "Core module interrupt\n"); +} + +static void integratorcm_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + integratorcm_state *s = (integratorcm_state *)opaque; + offset -= 0x10000000; + switch (offset >> 2) { + case 2: /* CM_OSC */ + if (s->cm_lock == 0xa05f) + s->cm_osc = value; + break; + case 3: /* CM_CTRL */ + integratorcm_set_ctrl(s, value); + break; + case 5: /* CM_LOCK */ + s->cm_lock = value & 0xffff; + break; + case 7: /* CM_AUXOSC */ + if (s->cm_lock == 0xa05f) + s->cm_auxosc = value; + break; + case 8: /* CM_SDRAM */ + s->cm_sdram = value; + break; + case 9: /* CM_INIT */ + /* ??? This can change the memory bus frequency. */ + s->cm_init = value; + break; + case 12: /* CM_FLAGSS */ + s->cm_flags |= value; + break; + case 13: /* CM_FLAGSC */ + s->cm_flags &= ~value; + break; + case 14: /* CM_NVFLAGSS */ + s->cm_nvflags |= value; + break; + case 15: /* CM_NVFLAGSS */ + s->cm_nvflags &= ~value; + break; + case 18: /* CM_IRQ_ENSET */ + s->irq_enabled |= value; + integratorcm_update(s); + break; + case 19: /* CM_IRQ_ENCLR */ + s->irq_enabled &= ~value; + integratorcm_update(s); + break; + case 20: /* CM_SOFT_INTSET */ + s->int_level |= (value & 1); + integratorcm_update(s); + break; + case 21: /* CM_SOFT_INTCLR */ + s->int_level &= ~(value & 1); + integratorcm_update(s); + break; + case 26: /* CM_FIQ_ENSET */ + s->fiq_enabled |= value; + integratorcm_update(s); + break; + case 27: /* CM_FIQ_ENCLR */ + s->fiq_enabled &= ~value; + integratorcm_update(s); + break; + case 32: /* CM_VOLTAGE_CTL0 */ + case 33: /* CM_VOLTAGE_CTL1 */ + case 34: /* CM_VOLTAGE_CTL2 */ + case 35: /* CM_VOLTAGE_CTL3 */ + /* ??? Voltage control unimplemented. */ + break; + default: + cpu_abort (cpu_single_env, + "integratorcm_write: Unimplemented offset 0x%x\n", offset); + break; + } +} + +/* Integrator/CM control registers. */ + +static CPUReadMemoryFunc *integratorcm_readfn[] = { + integratorcm_read, + integratorcm_read, + integratorcm_read +}; + +static CPUWriteMemoryFunc *integratorcm_writefn[] = { + integratorcm_write, + integratorcm_write, + integratorcm_write +}; + +static void integratorcm_init(int memsz, uint32_t flash_offset) +{ + int iomemtype; + integratorcm_state *s; + + s = (integratorcm_state *)qemu_mallocz(sizeof(integratorcm_state)); + s->cm_osc = 0x01000048; + /* ??? What should the high bits of this value be? */ + s->cm_auxosc = 0x0007feff; + s->cm_sdram = 0x00011122; + if (memsz >= 256) { + integrator_spd[31] = 64; + s->cm_sdram |= 0x10; + } else if (memsz >= 128) { + integrator_spd[31] = 32; + s->cm_sdram |= 0x0c; + } else if (memsz >= 64) { + integrator_spd[31] = 16; + s->cm_sdram |= 0x08; + } else if (memsz >= 32) { + integrator_spd[31] = 4; + s->cm_sdram |= 0x04; + } else { + integrator_spd[31] = 2; + } + memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); + s->cm_init = 0x00000112; + s->flash_offset = flash_offset; + + iomemtype = cpu_register_io_memory(0, integratorcm_readfn, + integratorcm_writefn, s); + cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype); + integratorcm_do_remap(s, 1); + /* ??? Save/restore. */ +} + +/* Integrator/CP hardware emulation. */ +/* Primary interrupt controller. */ + +typedef struct icp_pic_state +{ + uint32_t base; + uint32_t level; + uint32_t irq_enabled; + uint32_t fiq_enabled; + void *parent; + /* -1 if parent is a cpu, otherwise IRQ number on parent PIC. */ + int parent_irq; +} icp_pic_state; + +static void icp_pic_set_level(icp_pic_state *, int, int); + +static void icp_pic_update(icp_pic_state *s) +{ + CPUState *env; + if (s->parent_irq != -1) { + uint32_t flags; + + flags = (s->level & s->irq_enabled); + icp_pic_set_level((icp_pic_state *)s->parent, s->parent_irq, + flags != 0); + return; + } + /* Raise CPU interrupt. */ + env = (CPUState *)s->parent; + if (s->level & s->fiq_enabled) { + cpu_interrupt (env, CPU_INTERRUPT_FIQ); + } else { + cpu_reset_interrupt (env, CPU_INTERRUPT_FIQ); + } + if (s->level & s->irq_enabled) { + cpu_interrupt (env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt (env, CPU_INTERRUPT_HARD); + } +} + +static void icp_pic_set_level(icp_pic_state *s, int n, int level) +{ + if (level) + s->level |= 1 << n; + else + s->level &= ~(1 << n); + icp_pic_update(s); +} + +static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset) +{ + icp_pic_state *s = (icp_pic_state *)opaque; + + offset -= s->base; + switch (offset >> 2) { + case 0: /* IRQ_STATUS */ + return s->level & s->irq_enabled; + case 1: /* IRQ_RAWSTAT */ + return s->level; + case 2: /* IRQ_ENABLESET */ + return s->irq_enabled; + case 4: /* INT_SOFTSET */ + return s->level & 1; + case 8: /* FRQ_STATUS */ + return s->level & s->fiq_enabled; + case 9: /* FRQ_RAWSTAT */ + return s->level; + case 10: /* FRQ_ENABLESET */ + return s->fiq_enabled; + case 3: /* IRQ_ENABLECLR */ + case 5: /* INT_SOFTCLR */ + case 11: /* FRQ_ENABLECLR */ + default: + printf ("icp_pic_read: Bad register offset 0x%x\n", offset); + return 0; + } +} + +static void icp_pic_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + icp_pic_state *s = (icp_pic_state *)opaque; + offset -= s->base; + + switch (offset >> 2) { + case 2: /* IRQ_ENABLESET */ + s->irq_enabled |= value; + break; + case 3: /* IRQ_ENABLECLR */ + s->irq_enabled &= ~value; + break; + case 4: /* INT_SOFTSET */ + if (value & 1) + icp_pic_set_level(s, 0, 1); + break; + case 5: /* INT_SOFTCLR */ + if (value & 1) + icp_pic_set_level(s, 0, 0); + break; + case 10: /* FRQ_ENABLESET */ + s->fiq_enabled |= value; + break; + case 11: /* FRQ_ENABLECLR */ + s->fiq_enabled &= ~value; + break; + case 0: /* IRQ_STATUS */ + case 1: /* IRQ_RAWSTAT */ + case 8: /* FRQ_STATUS */ + case 9: /* FRQ_RAWSTAT */ + default: + printf ("icp_pic_write: Bad register offset 0x%x\n", offset); + return; + } + icp_pic_update(s); +} + +static CPUReadMemoryFunc *icp_pic_readfn[] = { + icp_pic_read, + icp_pic_read, + icp_pic_read +}; + +static CPUWriteMemoryFunc *icp_pic_writefn[] = { + icp_pic_write, + icp_pic_write, + icp_pic_write +}; + +static icp_pic_state *icp_pic_init(uint32_t base, void *parent, + int parent_irq) +{ + icp_pic_state *s; + int iomemtype; + + s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state)); + if (!s) + return NULL; + + s->base = base; + s->parent = parent; + s->parent_irq = parent_irq; + iomemtype = cpu_register_io_memory(0, icp_pic_readfn, + icp_pic_writefn, s); + cpu_register_physical_memory(base, 0x007fffff, iomemtype); + /* ??? Save/restore. */ + return s; +} + +/* Timers. */ + +/* System bus clock speed (40MHz) for timer 0. Not sure about this value. */ +#define ICP_BUS_FREQ 40000000 + +typedef struct { + int64_t next_time; + int64_t expires[3]; + int64_t loaded[3]; + QEMUTimer *timer; + icp_pic_state *pic; + uint32_t base; + uint32_t control[3]; + uint32_t count[3]; + uint32_t limit[3]; + int freq[3]; + int int_level[3]; +} icp_pit_state; + +/* Calculate the new expiry time of the given timer. */ + +static void icp_pit_reload(icp_pit_state *s, int n) +{ + int64_t delay; + + s->loaded[n] = s->expires[n]; + delay = muldiv64(s->count[n], ticks_per_sec, s->freq[n]); + if (delay == 0) + delay = 1; + s->expires[n] += delay; +} + +/* Check all active timers, and schedule the next timer interrupt. */ + +static void icp_pit_update(icp_pit_state *s, int64_t now) +{ + int n; + int64_t next; + + next = now; + for (n = 0; n < 3; n++) { + /* Ignore disabled timers. */ + if ((s->control[n] & 0x80) == 0) + continue; + /* Ignore expired one-shot timers. */ + if (s->count[n] == 0 && s->control[n] & 1) + continue; + if (s->expires[n] - now <= 0) { + /* Timer has expired. */ + s->int_level[n] = 1; + if (s->control[n] & 1) { + /* One-shot. */ + s->count[n] = 0; + } else { + if ((s->control[n] & 0x40) == 0) { + /* Free running. */ + if (s->control[n] & 2) + s->count[n] = 0xffffffff; + else + s->count[n] = 0xffff; + } else { + /* Periodic. */ + s->count[n] = s->limit[n]; + } + } + } + while (s->expires[n] - now <= 0) { + icp_pit_reload(s, n); + } + } + /* Update interrupts. */ + for (n = 0; n < 3; n++) { + if (s->int_level[n] && (s->control[n] & 0x20)) { + icp_pic_set_level(s->pic, 5 + n, 1); + } else { + icp_pic_set_level(s->pic, 5 + n, 0); + } + if (next - s->expires[n] < 0) + next = s->expires[n]; + } + /* Schedule the next timer interrupt. */ + if (next == now) { + qemu_del_timer(s->timer); + s->next_time = 0; + } else if (next != s->next_time) { + qemu_mod_timer(s->timer, next); + s->next_time = next; + } +} + +/* Return the current value of the timer. */ +static uint32_t icp_pit_getcount(icp_pit_state *s, int n, int64_t now) +{ + int64_t elapsed; + int64_t period; + + if (s->count[n] == 0) + return 0; + if ((s->control[n] & 0x80) == 0) + return s->count[n]; + elapsed = now - s->loaded[n]; + period = s->expires[n] - s->loaded[n]; + /* If the timer should have expired then return 0. This can happen + when the host timer signal doesnt occur immediately. It's better to + have a timer appear to sit at zero for a while than have it wrap + around before the guest interrupt is raised. */ + /* ??? Could we trigger the interrupt here? */ + if (elapsed > period) + return 0; + /* We need to calculate count * elapsed / period without overfowing. + Scale both elapsed and period so they fit in a 32-bit int. */ + while (period != (int32_t)period) { + period >>= 1; + elapsed >>= 1; + } + return ((uint64_t)s->count[n] * (uint64_t)(int32_t)elapsed) + / (int32_t)period; +} + +static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset) +{ + int n; + icp_pit_state *s = (icp_pit_state *)opaque; + + offset -= s->base; + n = offset >> 8; + if (n > 2) + cpu_abort (cpu_single_env, "icp_pit_read: Bad timer %x\n", offset); + switch ((offset & 0xff) >> 2) { + case 0: /* TimerLoad */ + case 6: /* TimerBGLoad */ + return s->limit[n]; + case 1: /* TimerValue */ + return icp_pit_getcount(s, n, qemu_get_clock(vm_clock)); + case 2: /* TimerControl */ + return s->control[n]; + case 4: /* TimerRIS */ + return s->int_level[n]; + case 5: /* TimerMIS */ + if ((s->control[n] & 0x20) == 0) + return 0; + return s->int_level[n]; + default: + cpu_abort (cpu_single_env, "icp_pit_read: Bad offset %x\n", offset); + return 0; + } +} + +static void icp_pit_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + icp_pit_state *s = (icp_pit_state *)opaque; + int n; + int64_t now; + + now = qemu_get_clock(vm_clock); + offset -= s->base; + n = offset >> 8; + if (n > 2) + cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset); + + switch ((offset & 0xff) >> 2) { + case 0: /* TimerLoad */ + s->limit[n] = value; + s->count[n] = value; + s->expires[n] = now; + icp_pit_reload(s, n); + break; + case 1: /* TimerValue */ + /* ??? Linux seems to want to write to this readonly register. + Ignore it. */ + break; + case 2: /* TimerControl */ + if (s->control[n] & 0x80) { + /* Pause the timer if it is running. This may cause some + inaccuracy dure to rounding, but avoids a whole lot of other + messyness. */ + s->count[n] = icp_pit_getcount(s, n, now); + } + s->control[n] = value; + if (n == 0) + s->freq[n] = ICP_BUS_FREQ; + else + s->freq[n] = 1000000; + /* ??? Need to recalculate expiry time after changing divisor. */ + switch ((value >> 2) & 3) { + case 1: s->freq[n] >>= 4; break; + case 2: s->freq[n] >>= 8; break; + } + if (s->control[n] & 0x80) { + /* Restart the timer if still enabled. */ + s->expires[n] = now; + icp_pit_reload(s, n); + } + break; + case 3: /* TimerIntClr */ + s->int_level[n] = 0; + break; + case 6: /* TimerBGLoad */ + s->limit[n] = value; + break; + default: + cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset); + } + icp_pit_update(s, now); +} + +static void icp_pit_tick(void *opaque) +{ + int64_t now; + + now = qemu_get_clock(vm_clock); + icp_pit_update((icp_pit_state *)opaque, now); +} + +static CPUReadMemoryFunc *icp_pit_readfn[] = { + icp_pit_read, + icp_pit_read, + icp_pit_read +}; + +static CPUWriteMemoryFunc *icp_pit_writefn[] = { + icp_pit_write, + icp_pit_write, + icp_pit_write +}; + +static void icp_pit_init(uint32_t base, icp_pic_state *pic) +{ + int iomemtype; + icp_pit_state *s; + int n; + + s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state)); + s->base = base; + s->pic = pic; + s->freq[0] = ICP_BUS_FREQ; + s->freq[1] = 1000000; + s->freq[2] = 1000000; + for (n = 0; n < 3; n++) { + s->control[n] = 0x20; + s->count[n] = 0xffffffff; + } + + iomemtype = cpu_register_io_memory(0, icp_pit_readfn, + icp_pit_writefn, s); + cpu_register_physical_memory(base, 0x007fffff, iomemtype); + s->timer = qemu_new_timer(vm_clock, icp_pit_tick, s); + /* ??? Save/restore. */ +} + +/* ARM PrimeCell PL011 UART */ + +typedef struct { + uint32_t base; + uint32_t readbuff; + uint32_t flags; + uint32_t lcr; + uint32_t cr; + uint32_t dmacr; + uint32_t int_enabled; + uint32_t int_level; + uint32_t read_fifo[16]; + uint32_t ilpr; + uint32_t ibrd; + uint32_t fbrd; + uint32_t ifl; + int read_pos; + int read_count; + int read_trigger; + CharDriverState *chr; + icp_pic_state *pic; + int irq; +} pl011_state; + +#define PL011_INT_TX 0x20 +#define PL011_INT_RX 0x10 + +#define PL011_FLAG_TXFE 0x80 +#define PL011_FLAG_RXFF 0x40 +#define PL011_FLAG_TXFF 0x20 +#define PL011_FLAG_RXFE 0x10 + +static const unsigned char pl011_id[] = +{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; + +static void pl011_update(pl011_state *s) +{ + uint32_t flags; + + flags = s->int_level & s->int_enabled; + icp_pic_set_level(s->pic, s->irq, flags != 0); +} + +static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) +{ + pl011_state *s = (pl011_state *)opaque; + uint32_t c; + + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) { + return pl011_id[(offset - 0xfe0) >> 2]; + } + switch (offset >> 2) { + case 0: /* UARTDR */ + s->flags &= ~PL011_FLAG_RXFF; + c = s->read_fifo[s->read_pos]; + if (s->read_count > 0) { + s->read_count--; + if (++s->read_pos == 16) + s->read_pos = 0; + } + if (s->read_count == 0) { + s->flags |= PL011_FLAG_RXFE; + } + if (s->read_count == s->read_trigger - 1) + s->int_level &= ~ PL011_INT_RX; + pl011_update(s); + return c; + case 1: /* UARTCR */ + return 0; + case 6: /* UARTFR */ + return s->flags; + case 8: /* UARTILPR */ + return s->ilpr; + case 9: /* UARTIBRD */ + return s->ibrd; + case 10: /* UARTFBRD */ + return s->fbrd; + case 11: /* UARTLCR_H */ + return s->lcr; + case 12: /* UARTCR */ + return s->cr; + case 13: /* UARTIFLS */ + return s->ifl; + case 14: /* UARTIMSC */ + return s->int_enabled; + case 15: /* UARTRIS */ + return s->int_level; + case 16: /* UARTMIS */ + return s->int_level & s->int_enabled; + case 18: /* UARTDMACR */ + return s->dmacr; + default: + cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset); + return 0; + } +} + +static void pl011_set_read_trigger(pl011_state *s) +{ +#if 0 + /* The docs say the RX interrupt is triggered when the FIFO exceeds + the threshold. However linux only reads the FIFO in response to an + interrupt. Triggering the interrupt when the FIFO is non-empty seems + to make things work. */ + if (s->lcr & 0x10) + s->read_trigger = (s->ifl >> 1) & 0x1c; + else +#endif + s->read_trigger = 1; +} + +static void pl011_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + pl011_state *s = (pl011_state *)opaque; + unsigned char ch; + + offset -= s->base; + switch (offset >> 2) { + case 0: /* UARTDR */ + /* ??? Check if transmitter is enabled. */ + ch = value; + if (s->chr) + qemu_chr_write(s->chr, &ch, 1); + s->int_level |= PL011_INT_TX; + pl011_update(s); + break; + case 1: /* UARTCR */ + s->cr = value; + break; + case 8: /* UARTUARTILPR */ + s->ilpr = value; + break; + case 9: /* UARTIBRD */ + s->ibrd = value; + break; + case 10: /* UARTFBRD */ + s->fbrd = value; + break; + case 11: /* UARTLCR_H */ + s->lcr = value; + pl011_set_read_trigger(s); + break; + case 12: /* UARTCR */ + /* ??? Need to implement the enable and loopback bits. */ + s->cr = value; + break; + case 13: /* UARTIFS */ + s->ifl = value; + pl011_set_read_trigger(s); + break; + case 14: /* UARTIMSC */ + s->int_enabled = value; + pl011_update(s); + break; + case 17: /* UARTICR */ + s->int_level &= ~value; + pl011_update(s); + break; + case 18: /* UARTDMACR */ + s->dmacr = value; + if (value & 3) + cpu_abort(cpu_single_env, "PL011: DMA not implemented\n"); + break; + default: + cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset); + } +} + +static int pl011_can_recieve(void *opaque) +{ + pl011_state *s = (pl011_state *)opaque; + + if (s->lcr & 0x10) + return s->read_count < 16; + else + return s->read_count < 1; +} + +static void pl011_recieve(void *opaque, const uint8_t *buf, int size) +{ + pl011_state *s = (pl011_state *)opaque; + int slot; + + slot = s->read_pos + s->read_count; + if (slot >= 16) + slot -= 16; + s->read_fifo[slot] = *buf; + s->read_count++; + s->flags &= ~PL011_FLAG_RXFE; + if (s->cr & 0x10 || s->read_count == 16) { + s->flags |= PL011_FLAG_RXFF; + } + if (s->read_count == s->read_trigger) { + s->int_level |= PL011_INT_RX; + pl011_update(s); + } +} + +static void pl011_event(void *opaque, int event) +{ + /* ??? Should probably implement break. */ +} + +static CPUReadMemoryFunc *pl011_readfn[] = { + pl011_read, + pl011_read, + pl011_read +}; + +static CPUWriteMemoryFunc *pl011_writefn[] = { + pl011_write, + pl011_write, + pl011_write +}; + +static void pl011_init(uint32_t base, icp_pic_state *pic, int irq, + CharDriverState *chr) +{ + int iomemtype; + pl011_state *s; + + s = (pl011_state *)qemu_mallocz(sizeof(pl011_state)); + iomemtype = cpu_register_io_memory(0, pl011_readfn, + pl011_writefn, s); + cpu_register_physical_memory(base, 0x007fffff, iomemtype); + s->base = base; + s->pic = pic; + s->irq = irq; + s->chr = chr; + s->read_trigger = 1; + s->ifl = 0x12; + s->cr = 0x300; + s->flags = 0x90; + if (chr){ + qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s); + qemu_chr_add_event_handler(chr, pl011_event); + } + /* ??? Save/restore. */ +} + +/* CP control registers. */ +typedef struct { + uint32_t base; +} icp_control_state; + +static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset) +{ + icp_control_state *s = (icp_control_state *)opaque; + offset -= s->base; + switch (offset >> 2) { + case 0: /* CP_IDFIELD */ + return 0x41034003; + case 1: /* CP_FLASHPROG */ + return 0; + case 2: /* CP_INTREG */ + return 0; + case 3: /* CP_DECODE */ + return 0x11; + default: + cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", offset); + return 0; + } +} + +static void icp_control_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + icp_control_state *s = (icp_control_state *)opaque; + offset -= s->base; + switch (offset >> 2) { + case 1: /* CP_FLASHPROG */ + case 2: /* CP_INTREG */ + case 3: /* CP_DECODE */ + /* Nothing interesting implemented yet. */ + break; + default: + cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", offset); + } +} +static CPUReadMemoryFunc *icp_control_readfn[] = { + icp_control_read, + icp_control_read, + icp_control_read +}; + +static CPUWriteMemoryFunc *icp_control_writefn[] = { + icp_control_write, + icp_control_write, + icp_control_write +}; + +static void icp_control_init(uint32_t base) +{ + int iomemtype; + icp_control_state *s; + + s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state)); + iomemtype = cpu_register_io_memory(0, icp_control_readfn, + icp_control_writefn, s); + cpu_register_physical_memory(base, 0x007fffff, iomemtype); + s->base = base; + /* ??? Save/restore. */ +} + + +/* Keyboard/Mouse Interface. */ + +typedef struct { + void *dev; + uint32_t base; + uint32_t cr; + uint32_t clk; + uint32_t last; + icp_pic_state *pic; + int pending; + int irq; + int is_mouse; +} icp_kmi_state; + +static void icp_kmi_update(void *opaque, int level) +{ + icp_kmi_state *s = (icp_kmi_state *)opaque; + int raise; + + s->pending = level; + raise = (s->pending && (s->cr & 0x10) != 0) + || (s->cr & 0x08) != 0; + icp_pic_set_level(s->pic, s->irq, raise); +} + +static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset) +{ + icp_kmi_state *s = (icp_kmi_state *)opaque; + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) + return 0; + + switch (offset >> 2) { + case 0: /* KMICR */ + return s->cr; + case 1: /* KMISTAT */ + /* KMIC and KMID bits not implemented. */ + if (s->pending) { + return 0x10; + } else { + return 0; + } + case 2: /* KMIDATA */ + if (s->pending) + s->last = ps2_read_data(s->dev); + return s->last; + case 3: /* KMICLKDIV */ + return s->clk; + case 4: /* KMIIR */ + return s->pending | 2; + default: + cpu_abort (cpu_single_env, "icp_kmi_read: Bad offset %x\n", offset); + return 0; + } +} + +static void icp_kmi_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + icp_kmi_state *s = (icp_kmi_state *)opaque; + offset -= s->base; + switch (offset >> 2) { + case 0: /* KMICR */ + s->cr = value; + icp_kmi_update(s, s->pending); + /* ??? Need to implement the enable/disable bit. */ + break; + case 2: /* KMIDATA */ + /* ??? This should toggle the TX interrupt line. */ + /* ??? This means kbd/mouse can block each other. */ + if (s->is_mouse) { + ps2_write_mouse(s->dev, value); + } else { + ps2_write_keyboard(s->dev, value); + } + break; + case 3: /* KMICLKDIV */ + s->clk = value; + return; + default: + cpu_abort (cpu_single_env, "icp_kmi_write: Bad offset %x\n", offset); + } +} +static CPUReadMemoryFunc *icp_kmi_readfn[] = { + icp_kmi_read, + icp_kmi_read, + icp_kmi_read +}; + +static CPUWriteMemoryFunc *icp_kmi_writefn[] = { + icp_kmi_write, + icp_kmi_write, + icp_kmi_write +}; + +static void icp_kmi_init(uint32_t base, icp_pic_state * pic, int irq, + int is_mouse) +{ + int iomemtype; + icp_kmi_state *s; + + s = (icp_kmi_state *)qemu_mallocz(sizeof(icp_kmi_state)); + iomemtype = cpu_register_io_memory(0, icp_kmi_readfn, + icp_kmi_writefn, s); + cpu_register_physical_memory(base, 0x007fffff, iomemtype); + s->base = base; + s->pic = pic; + s->irq = irq; + s->is_mouse = is_mouse; + if (is_mouse) + s->dev = ps2_mouse_init(icp_kmi_update, s); + else + s->dev = ps2_kbd_init(icp_kmi_update, s); + /* ??? Save/restore. */ +} + +/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ +static uint32_t bootloader[] = { + 0xe3a00000, /* mov r0, #0 */ + 0xe3a01013, /* mov r1, #0x13 */ + 0xe3811c01, /* orr r1, r1, #0x100 */ + 0xe59f2000, /* ldr r2, [pc, #0] */ + 0xe59ff000, /* ldr pc, [pc, #0] */ + 0, /* Address of kernel args. Set by integratorcp_init. */ + 0 /* Kernel entry point. Set by integratorcp_init. */ +}; + +static void set_kernel_args(uint32_t ram_size, int initrd_size, + const char *kernel_cmdline) +{ + uint32_t *p; + + p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); + /* ATAG_CORE */ + *(p++) = 5; + *(p++) = 0x54410001; + *(p++) = 1; + *(p++) = 0x1000; + *(p++) = 0; + /* ATAG_MEM */ + *(p++) = 4; + *(p++) = 0x54410002; + *(p++) = ram_size; + *(p++) = 0; + if (initrd_size) { + /* ATAG_INITRD2 */ + *(p++) = 4; + *(p++) = 0x54420005; + *(p++) = INITRD_LOAD_ADDR; + *(p++) = initrd_size; + } + if (kernel_cmdline && *kernel_cmdline) { + /* ATAG_CMDLINE */ + int cmdline_size; + + cmdline_size = strlen(kernel_cmdline); + memcpy (p + 2, kernel_cmdline, cmdline_size + 1); + cmdline_size = (cmdline_size >> 2) + 1; + *(p++) = cmdline_size + 2; + *(p++) = 0x54410009; + p += cmdline_size; + } + /* ATAG_END */ + *(p++) = 0; + *(p++) = 0; +} + +/* Board init. */ + +static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + CPUState *env; + uint32_t bios_offset; + icp_pic_state *pic; + int kernel_size; + int initrd_size; + + env = cpu_init(); + bios_offset = ram_size + vga_ram_size; + /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ + /* ??? RAM shoud repeat to fill physical memory space. */ + /* SDRAM at address zero*/ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + /* And again at address 0x80000000 */ + cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM); + + integratorcm_init(ram_size >> 20, bios_offset); + pic = icp_pic_init(0x14000000, env, -1); + icp_pic_init(0xca000000, pic, 26); + icp_pit_init(0x13000000, pic); + pl011_init(0x16000000, pic, 1, serial_hds[0]); + pl011_init(0x17000000, pic, 2, serial_hds[1]); + icp_control_init(0xcb000000); + icp_kmi_init(0x18000000, pic, 3, 0); + icp_kmi_init(0x19000000, pic, 4, 1); + + /* Load the kernel. */ + if (!kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + if (initrd_filename) { + initrd_size = load_image(initrd_filename, + phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_size = 0; + } + bootloader[5] = KERNEL_ARGS_ADDR; + bootloader[6] = KERNEL_LOAD_ADDR; + memcpy(phys_ram_base, bootloader, sizeof(bootloader)); + set_kernel_args(ram_size, initrd_size, kernel_cmdline); +} + +QEMUMachine integratorcp_machine = { + "integratorcp", + "ARM Integrator/CP", + integratorcp_init, +}; diff --git a/linux-user/main.c b/linux-user/main.c index 1ae4656d3..1b747d873 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -331,6 +331,7 @@ void cpu_loop(CPUARMState *env) int trapnr; unsigned int n, insn; target_siginfo_t info; + uint32_t addr; for(;;) { trapnr = cpu_arm_exec(env); @@ -397,13 +398,18 @@ void cpu_loop(CPUARMState *env) /* just indicate that signals should be handled asap */ break; case EXCP_PREFETCH_ABORT: + addr = env->cp15.c6_data; + goto do_segv; case EXCP_DATA_ABORT: + addr = env->cp15.c6_insn; + goto do_segv; + do_segv: { info.si_signo = SIGSEGV; info.si_errno = 0; /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->cp15_6; + info._sifields._sigfault._addr = addr; queue_signal(info.si_signo, &info); } break; @@ -1190,10 +1196,10 @@ int main(int argc, char **argv) #elif defined(TARGET_ARM) { int i; + cpsr_write(env, regs->uregs[16], 0xffffffff); for(i = 0; i < 16; i++) { env->regs[i] = regs->uregs[i]; } - env->cpsr = regs->uregs[16]; ts->stack_base = info->start_stack; ts->heap_base = info->brk; /* This will be filled in on the first SYS_HEAPINFO call. */ diff --git a/linux-user/signal.c b/linux-user/signal.c index a7c06c9fb..29933bda4 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1003,7 +1003,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ __put_user_error(env->regs[14], &sc->arm_lr, err); __put_user_error(env->regs[15], &sc->arm_pc, err); #ifdef TARGET_CONFIG_CPU_32 - __put_user_error(env->cpsr, &sc->arm_cpsr, err); + __put_user_error(cpsr_read(env), &sc->arm_cpsr, err); #endif __put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err); @@ -1040,9 +1040,9 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, target_ulong retcode; int thumb = 0; #if defined(TARGET_CONFIG_CPU_32) +#if 0 target_ulong cpsr = env->cpsr; -#if 0 /* * Maybe we need to deliver a 32-bit signal to a 26-bit task. */ @@ -1088,8 +1088,10 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, env->regs[14] = retcode; env->regs[15] = handler & (thumb ? ~1 : ~3); +#if 0 #ifdef TARGET_CONFIG_CPU_32 env->cpsr = cpsr; +#endif #endif return 0; @@ -1157,6 +1159,7 @@ static int restore_sigcontext(CPUState *env, struct target_sigcontext *sc) { int err = 0; + uint32_t cpsr; __get_user_error(env->regs[0], &sc->arm_r0, err); __get_user_error(env->regs[1], &sc->arm_r1, err); @@ -1175,7 +1178,8 @@ restore_sigcontext(CPUState *env, struct target_sigcontext *sc) __get_user_error(env->regs[14], &sc->arm_lr, err); __get_user_error(env->regs[15], &sc->arm_pc, err); #ifdef TARGET_CONFIG_CPU_32 - __get_user_error(env->cpsr, &sc->arm_cpsr, err); + __get_user_error(cpsr, &sc->arm_cpsr, err); + cpsr_write(env, cpsr, 0xffffffff); #endif err |= !valid_user_regs(env); diff --git a/softmmu_header.h b/softmmu_header.h index 81c65dc87..9f36f890c 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -59,6 +59,10 @@ #define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) #elif defined (TARGET_SPARC) #define CPU_MEM_INDEX ((env->psrs) == 0) +#elif defined (TARGET_ARM) +#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) +#else +#error unsupported CPU #endif #define MMUSUFFIX _mmu @@ -72,6 +76,10 @@ #define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) #elif defined (TARGET_SPARC) #define CPU_MEM_INDEX ((env->psrs) == 0) +#elif defined (TARGET_ARM) +#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) +#else +#error unsupported CPU #endif #define MMUSUFFIX _cmmu diff --git a/target-arm/cpu.h b/target-arm/cpu.h index fc49b5a99..1c1233c19 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -32,6 +32,8 @@ #define EXCP_SWI 2 /* software interrupt */ #define EXCP_PREFETCH_ABORT 3 #define EXCP_DATA_ABORT 4 +#define EXCP_IRQ 5 +#define EXCP_FIQ 6 /* We currently assume float and double are IEEE single and double precision respectively. @@ -42,8 +44,22 @@ */ typedef struct CPUARMState { + /* Regs for current mode. */ uint32_t regs[16]; - uint32_t cpsr; + /* Frequently accessed CPSR bits are stored separately for efficiently. + This contains all the other bits. Use cpsr_{read,write} to accless + the whole CPSR. */ + uint32_t uncached_cpsr; + uint32_t spsr; + + /* Banked registers. */ + uint32_t banked_spsr[6]; + uint32_t banked_r13[6]; + uint32_t banked_r14[6]; + + /* These hold r8-r12. */ + uint32_t usr_regs[5]; + uint32_t fiq_regs[5]; /* cpsr flag cache for faster execution */ uint32_t CF; /* 0 or 1 */ @@ -53,8 +69,21 @@ typedef struct CPUARMState { int thumb; /* 0 = arm mode, 1 = thumb mode */ - /* coprocessor 15 (MMU) status */ - uint32_t cp15_6; + /* System control coprocessor (cp15) */ + struct { + uint32_t c1_sys; /* System control register. */ + uint32_t c1_coproc; /* Coprocessor access register. */ + uint32_t c2; /* MMU translation table base. */ + uint32_t c3; /* MMU domain access control register. */ + uint32_t c5_insn; /* Fault status registers. */ + uint32_t c5_data; + uint32_t c6_insn; /* Fault address registers. */ + uint32_t c6_data; + uint32_t c9_insn; /* Cache lockdown registers. */ + uint32_t c9_data; + uint32_t c13_fcse; /* FCSE PID. */ + uint32_t c13_context; /* Context ID. */ + } cp15; /* exception/interrupt handling */ jmp_buf jmp_env; @@ -87,6 +116,9 @@ typedef struct CPUARMState { CPUARMState *cpu_arm_init(void); int cpu_arm_exec(CPUARMState *s); void cpu_arm_close(CPUARMState *s); +void do_interrupt(CPUARMState *); +void switch_mode(CPUARMState *, int); + /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ @@ -94,7 +126,69 @@ struct siginfo; int cpu_arm_signal_handler(int host_signum, struct siginfo *info, void *puc); +#define CPSR_M (0x1f) +#define CPSR_T (1 << 5) +#define CPSR_F (1 << 6) +#define CPSR_I (1 << 7) +#define CPSR_A (1 << 8) +#define CPSR_E (1 << 9) +#define CPSR_IT_2_7 (0xfc00) +/* Bits 20-23 reserved. */ +#define CPSR_J (1 << 24) +#define CPSR_IT_0_1 (3 << 25) +#define CPSR_Q (1 << 27) +#define CPSR_NZCV (0xf << 28) + +#define CACHED_CPSR_BITS (CPSR_T | CPSR_Q | CPSR_NZCV) +/* Return the current CPSR value. */ +static inline uint32_t cpsr_read(CPUARMState *env) +{ + int ZF; + ZF = (env->NZF == 0); + return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + | (env->thumb << 5); +} + +/* Set the CPSR. Note that some bits of mask must be all-set or all-clear. */ +static inline void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) +{ + /* NOTE: N = 1 and Z = 1 cannot be stored currently */ + if (mask & CPSR_NZCV) { + env->NZF = (val & 0xc0000000) ^ 0x40000000; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + if (mask & CPSR_Q) + env->QF = ((val & CPSR_Q) != 0); + if (mask & CPSR_T) + env->thumb = ((val & CPSR_T) != 0); + + if ((env->uncached_cpsr ^ val) & mask & CPSR_M) { + switch_mode(env, val & CPSR_M); + } + mask &= ~CACHED_CPSR_BITS; + env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); +} + +enum arm_cpu_mode { + ARM_CPU_MODE_USR = 0x10, + ARM_CPU_MODE_FIQ = 0x11, + ARM_CPU_MODE_IRQ = 0x12, + ARM_CPU_MODE_SVC = 0x13, + ARM_CPU_MODE_ABT = 0x17, + ARM_CPU_MODE_UND = 0x1b, + ARM_CPU_MODE_SYS = 0x1f +}; + +#if defined(CONFIG_USER_ONLY) #define TARGET_PAGE_BITS 12 +#else +/* The ARM MMU allows 1k pages. */ +/* ??? Linux doesn't actually use these, and they're deprecated in recent + architecture revisions. Maybe an a configure option to disable them. */ +#define TARGET_PAGE_BITS 10 +#endif #include "cpu-all.h" #endif diff --git a/target-arm/exec.h b/target-arm/exec.h index e4ea93f95..2d2b99aa3 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -34,16 +34,6 @@ register uint32_t T2 asm(AREG3); #include "cpu.h" #include "exec-all.h" -/* Implemented CPSR bits. */ -#define CACHED_CPSR_BITS 0xf8000000 -static inline int compute_cpsr(void) -{ - int ZF; - ZF = (env->NZF == 0); - return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27); -} - static inline void env_to_regs(void) { } @@ -55,10 +45,17 @@ static inline void regs_to_env(void) int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + /* In op_helper.c */ void cpu_lock(void); void cpu_unlock(void); +void helper_set_cp15(CPUState *, uint32_t, uint32_t); +uint32_t helper_get_cp15(CPUState *, uint32_t); + void cpu_loop_exit(void); void raise_exception(int); diff --git a/target-arm/helper.c b/target-arm/helper.c new file mode 100644 index 000000000..9cf159c07 --- /dev/null +++ b/target-arm/helper.c @@ -0,0 +1,555 @@ +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" + +#if defined(CONFIG_USER_ONLY) + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; +} + +int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + if (rw == 2) { + env->exception_index = EXCP_PREFETCH_ABORT; + env->cp15.c6_insn = address; + } else { + env->exception_index = EXCP_DATA_ABORT; + env->cp15.c6_data = address; + } + return 1; +} + +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} + +/* These should probably raise undefined insn exceptions. */ +void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) +{ + cpu_abort(env, "cp15 insn %08x\n", insn); +} + +uint32_t helper_get_cp15(CPUState *env, uint32_t insn) +{ + cpu_abort(env, "cp15 insn %08x\n", insn); + return 0; +} + +void switch_mode(CPUState *env, int mode) +{ + if (mode != ARM_CPU_MODE_USR) + cpu_abort(env, "Tried to switch out of user mode\n"); +} + +#else + +/* Map CPU modes onto saved register banks. */ +static inline int bank_number (int mode) +{ + switch (mode) { + case ARM_CPU_MODE_USR: + case ARM_CPU_MODE_SYS: + return 0; + case ARM_CPU_MODE_SVC: + return 1; + case ARM_CPU_MODE_ABT: + return 2; + case ARM_CPU_MODE_UND: + return 3; + case ARM_CPU_MODE_IRQ: + return 4; + case ARM_CPU_MODE_FIQ: + return 5; + } + cpu_abort(cpu_single_env, "Bad mode %x\n", mode); + return -1; +} + +void switch_mode(CPUState *env, int mode) +{ + int old_mode; + int i; + + old_mode = env->uncached_cpsr & CPSR_M; + if (mode == old_mode) + return; + + if (old_mode == ARM_CPU_MODE_FIQ) { + memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy (env->regs, env->usr_regs + 8, 5 * sizeof(uint32_t)); + } else if (mode == ARM_CPU_MODE_FIQ) { + memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); + memcpy (env->regs, env->fiq_regs + 8, 5 * sizeof(uint32_t)); + } + + i = bank_number(old_mode); + env->banked_r13[i] = env->regs[13]; + env->banked_r14[i] = env->regs[14]; + env->banked_spsr[i] = env->spsr; + + i = bank_number(mode); + env->regs[13] = env->banked_r13[i]; + env->regs[14] = env->banked_r14[i]; + env->spsr = env->banked_spsr[i]; +} + +/* Handle a CPU exception. */ +void do_interrupt(CPUARMState *env) +{ + uint32_t addr; + uint32_t mask; + int new_mode; + uint32_t offset; + + /* TODO: Vectored interrupt controller. */ + switch (env->exception_index) { + case EXCP_UDEF: + new_mode = ARM_CPU_MODE_UND; + addr = 0x04; + mask = CPSR_I; + if (env->thumb) + offset = 2; + else + offset = 4; + break; + case EXCP_SWI: + new_mode = ARM_CPU_MODE_SVC; + addr = 0x08; + mask = CPSR_I; + /* The PC already points to the next instructon. */ + offset = 0; + break; + case EXCP_PREFETCH_ABORT: + new_mode = ARM_CPU_MODE_ABT; + addr = 0x0c; + mask = CPSR_A | CPSR_I; + offset = 4; + break; + case EXCP_DATA_ABORT: + new_mode = ARM_CPU_MODE_ABT; + addr = 0x10; + mask = CPSR_A | CPSR_I; + offset = 8; + break; + case EXCP_IRQ: + new_mode = ARM_CPU_MODE_IRQ; + addr = 0x18; + /* Disable IRQ and imprecise data aborts. */ + mask = CPSR_A | CPSR_I; + offset = 4; + break; + case EXCP_FIQ: + new_mode = ARM_CPU_MODE_FIQ; + addr = 0x1c; + /* Disable FIQ, IRQ and imprecise data aborts. */ + mask = CPSR_A | CPSR_I | CPSR_F; + offset = 4; + break; + default: + cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index); + return; /* Never happens. Keep compiler happy. */ + } + /* High vectors. */ + if (env->cp15.c1_sys & (1 << 13)) { + addr += 0xffff0000; + } + switch_mode (env, new_mode); + env->spsr = cpsr_read(env); + /* Switch to the new mode, and clear the thumb bit. */ + /* ??? Thumb interrupt handlers not implemented. */ + env->uncached_cpsr = (env->uncached_cpsr & ~(CPSR_M | CPSR_T)) | new_mode; + env->uncached_cpsr |= mask; + env->regs[14] = env->regs[15] + offset; + env->regs[15] = addr; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; +} + +/* Check section/page access permissions. + Returns the page protection flags, or zero if the access is not + permitted. */ +static inline int check_ap(CPUState *env, int ap, int domain, int access_type, + int is_user) +{ + if (domain == 3) + return PAGE_READ | PAGE_WRITE; + + switch (ap) { + case 0: + if (access_type != 1) + return 0; + switch ((env->cp15.c1_sys >> 8) & 3) { + case 1: + return is_user ? 0 : PAGE_READ; + case 2: + return PAGE_READ; + default: + return 0; + } + case 1: + return is_user ? 0 : PAGE_READ | PAGE_WRITE; + case 2: + if (is_user) + return (access_type == 1) ? 0 : PAGE_READ; + else + return PAGE_READ | PAGE_WRITE; + case 3: + return PAGE_READ | PAGE_WRITE; + default: + abort(); + } +} + +static int get_phys_addr(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int code; + uint32_t table; + uint32_t desc; + int type; + int ap; + int domain; + uint32_t phys_addr; + + /* Fast Context Switch Extension. */ + if (address < 0x02000000) + address += env->cp15.c13_fcse; + + if ((env->cp15.c1_sys & 1) == 0) { + /* MMU diusabled. */ + *phys_ptr = address; + *prot = PAGE_READ | PAGE_WRITE; + } else { + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); + desc = ldl_phys(table); + type = (desc & 3); + domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; + if (type == 0) { + /* Secton translation fault. */ + code = 5; + goto do_fault; + } + if (domain == 0 || domain == 2) { + if (type == 2) + code = 9; /* Section domain fault. */ + else + code = 11; /* Page domain fault. */ + goto do_fault; + } + if (type == 2) { + /* 1Mb section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + ap = (desc >> 10) & 3; + code = 13; + } else { + /* Lookup l2 entry. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + desc = ldl_phys(table); + switch (desc & 3) { + case 0: /* Page translation fault. */ + code = 7; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; + break; + case 2: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; + break; + case 3: /* 1k page. */ + if (type == 1) { + /* Page translation fault. */ + code = 7; + goto do_fault; + } + phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); + ap = (desc >> 4) & 3; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + abort(); + } + code = 15; + } + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; + } + *phys_ptr = phys_addr; + } + return 0; +do_fault: + return code | (domain << 4); +} + +int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, + int access_type, int is_user, int is_softmmu) +{ + uint32_t phys_addr; + int prot; + int ret; + + ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot); + if (ret == 0) { + /* Map a single [sub]page. */ + phys_addr &= ~(uint32_t)0x3ff; + address &= ~(uint32_t)0x3ff; + return tlb_set_page (env, address, phys_addr, prot, is_user, + is_softmmu); + } + + if (access_type == 2) { + env->cp15.c5_insn = ret; + env->cp15.c6_insn = address; + env->exception_index = EXCP_PREFETCH_ABORT; + } else { + env->cp15.c5_data = ret; + env->cp15.c6_data = address; + env->exception_index = EXCP_DATA_ABORT; + } + return 1; +} + +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint32_t phys_addr; + int prot; + int ret; + + ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot); + + if (ret != 0) + return -1; + + return phys_addr; +} + +void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) +{ + uint32_t op2; + + op2 = (insn >> 5) & 7; + switch ((insn >> 16) & 0xf) { + case 0: /* ID codes. */ + goto bad_reg; + case 1: /* System configuration. */ + switch (op2) { + case 0: + env->cp15.c1_sys = val; + /* ??? Lots of these bits are not implemented. */ + /* This may enable/disable the MMU, so do a TLB flush. */ + tlb_flush(env, 1); + break; + case 2: + env->cp15.c1_coproc = val; + /* ??? Is this safe when called from within a TB? */ + tb_flush(env); + default: + goto bad_reg; + } + break; + case 2: /* MMU Page table control. */ + env->cp15.c2 = val; + break; + case 3: /* MMU Domain access control. */ + env->cp15.c3 = val; + break; + case 4: /* Reserved. */ + goto bad_reg; + case 5: /* MMU Fault status. */ + switch (op2) { + case 0: + env->cp15.c5_data = val; + break; + case 1: + env->cp15.c5_insn = val; + break; + default: + goto bad_reg; + } + break; + case 6: /* MMU Fault address. */ + switch (op2) { + case 0: + env->cp15.c6_data = val; + break; + case 1: + env->cp15.c6_insn = val; + break; + default: + goto bad_reg; + } + break; + case 7: /* Cache control. */ + /* No cache, so nothing to do. */ + break; + case 8: /* MMU TLB control. */ + switch (op2) { + case 0: /* Invalidate all. */ + tlb_flush(env, 0); + break; + case 1: /* Invalidate single TLB entry. */ +#if 0 + /* ??? This is wrong for large pages and sections. */ + /* As an ugly hack to make linux work we always flush a 4K + pages. */ + val &= 0xfffff000; + tlb_flush_page(env, val); + tlb_flush_page(env, val + 0x400); + tlb_flush_page(env, val + 0x800); + tlb_flush_page(env, val + 0xc00); +#else + tlb_flush(env, 1); +#endif + break; + default: + goto bad_reg; + } + break; + case 9: /* Cache lockdown. */ + switch (op2) { + case 0: + env->cp15.c9_data = val; + break; + case 1: + env->cp15.c9_insn = val; + break; + default: + goto bad_reg; + } + break; + case 10: /* MMU TLB lockdown. */ + /* ??? TLB lockdown not implemented. */ + break; + case 11: /* TCM DMA control. */ + case 12: /* Reserved. */ + goto bad_reg; + case 13: /* Process ID. */ + switch (op2) { + case 0: + env->cp15.c9_data = val; + break; + case 1: + env->cp15.c9_insn = val; + break; + default: + goto bad_reg; + } + break; + case 14: /* Reserved. */ + goto bad_reg; + case 15: /* Implementation specific. */ + /* ??? Internal registers not implemented. */ + break; + } + return; +bad_reg: + /* ??? For debugging only. Should raise illegal instruction exception. */ + cpu_abort(env, "Unimplemented cp15 register read\n"); +} + +uint32_t helper_get_cp15(CPUState *env, uint32_t insn) +{ + uint32_t op2; + + op2 = (insn >> 5) & 7; + switch ((insn >> 16) & 0xf) { + case 0: /* ID codes. */ + switch (op2) { + default: /* Device ID. */ + return 0x4106a262; + case 1: /* Cache Type. */ + return 0x1dd20d2; + case 2: /* TCM status. */ + return 0; + } + case 1: /* System configuration. */ + switch (op2) { + case 0: /* Control register. */ + return env->cp15.c1_sys; + case 1: /* Auxiliary control register. */ + return 1; + case 2: /* Coprocessor access register. */ + return env->cp15.c1_coproc; + default: + goto bad_reg; + } + case 2: /* MMU Page table control. */ + return env->cp15.c2; + case 3: /* MMU Domain access control. */ + return env->cp15.c3; + case 4: /* Reserved. */ + goto bad_reg; + case 5: /* MMU Fault status. */ + switch (op2) { + case 0: + return env->cp15.c5_data; + case 1: + return env->cp15.c5_insn; + default: + goto bad_reg; + } + case 6: /* MMU Fault address. */ + switch (op2) { + case 0: + return env->cp15.c6_data; + case 1: + return env->cp15.c6_insn; + default: + goto bad_reg; + } + case 7: /* Cache control. */ + /* ??? This is for test, clean and invaidate operations that set the + Z flag. We can't represent N = Z = 1, so it also clears clears + the N flag. Oh well. */ + env->NZF = 0; + return 0; + case 8: /* MMU TLB control. */ + goto bad_reg; + case 9: /* Cache lockdown. */ + switch (op2) { + case 0: + return env->cp15.c9_data; + case 1: + return env->cp15.c9_insn; + default: + goto bad_reg; + } + case 10: /* MMU TLB lockdown. */ + /* ??? TLB lockdown not implemented. */ + return 0; + case 11: /* TCM DMA control. */ + case 12: /* Reserved. */ + goto bad_reg; + case 13: /* Process ID. */ + switch (op2) { + case 0: + return env->cp15.c13_fcse; + case 1: + return env->cp15.c13_context; + default: + goto bad_reg; + } + case 14: /* Reserved. */ + goto bad_reg; + case 15: /* Implementation specific. */ + /* ??? Internal registers not implemented. */ + return 0; + } +bad_reg: + /* ??? For debugging only. Should raise illegal instruction exception. */ + cpu_abort(env, "Unimplemented cp15 register read\n"); + return 0; +} + +#endif diff --git a/target-arm/op.c b/target-arm/op.c index 1d30b1bda..09449f28e 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -101,6 +101,11 @@ void OPPROTO op_movl_T0_im(void) T0 = PARAM1; } +void OPPROTO op_movl_T0_T1(void) +{ + T0 = T1; +} + void OPPROTO op_movl_T1_im(void) { T1 = PARAM1; @@ -361,20 +366,27 @@ void OPPROTO op_exit_tb(void) EXIT_TB(); } -void OPPROTO op_movl_T0_psr(void) +void OPPROTO op_movl_T0_cpsr(void) { - T0 = compute_cpsr(); + T0 = cpsr_read(env); + FORCE_RET(); } -/* NOTE: N = 1 and Z = 1 cannot be stored currently */ -void OPPROTO op_movl_psr_T0(void) +void OPPROTO op_movl_T0_spsr(void) { - unsigned int psr; - psr = T0; - env->CF = (psr >> 29) & 1; - env->NZF = (psr & 0xc0000000) ^ 0x40000000; - env->VF = (psr << 3) & 0x80000000; - /* for user mode we do not update other state info */ + T0 = env->spsr; +} + +void OPPROTO op_movl_spsr_T0(void) +{ + uint32_t mask = PARAM1; + env->spsr = (env->spsr & ~mask) | (T0 & mask); +} + +void OPPROTO op_movl_cpsr_T0(void) +{ + cpsr_write(env, T0, PARAM1); + FORCE_RET(); } void OPPROTO op_mul_T0_T1(void) @@ -433,67 +445,15 @@ void OPPROTO op_logicq_cc(void) /* memory access */ -void OPPROTO op_ldub_T0_T1(void) -{ - T0 = ldub((void *)T1); -} - -void OPPROTO op_ldsb_T0_T1(void) -{ - T0 = ldsb((void *)T1); -} - -void OPPROTO op_lduw_T0_T1(void) -{ - T0 = lduw((void *)T1); -} - -void OPPROTO op_ldsw_T0_T1(void) -{ - T0 = ldsw((void *)T1); -} - -void OPPROTO op_ldl_T0_T1(void) -{ - T0 = ldl((void *)T1); -} - -void OPPROTO op_stb_T0_T1(void) -{ - stb((void *)T1, T0); -} - -void OPPROTO op_stw_T0_T1(void) -{ - stw((void *)T1, T0); -} - -void OPPROTO op_stl_T0_T1(void) -{ - stl((void *)T1, T0); -} - -void OPPROTO op_swpb_T0_T1(void) -{ - int tmp; +#define MEMSUFFIX _raw +#include "op_mem.h" - cpu_lock(); - tmp = ldub((void *)T1); - stb((void *)T1, T0); - T0 = tmp; - cpu_unlock(); -} - -void OPPROTO op_swpl_T0_T1(void) -{ - int tmp; - - cpu_lock(); - tmp = ldl((void *)T1); - stl((void *)T1, T0); - T0 = tmp; - cpu_unlock(); -} +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_mem.h" +#define MEMSUFFIX _kernel +#include "op_mem.h" +#endif /* shifts */ @@ -744,17 +704,48 @@ void OPPROTO op_sarl_T0_im(void) T0 = (int32_t)T0 >> PARAM1; } -/* 16->32 Sign extend */ -void OPPROTO op_sxl_T0(void) +/* Sign/zero extend */ +void OPPROTO op_sxth_T0(void) { T0 = (int16_t)T0; } -void OPPROTO op_sxl_T1(void) +void OPPROTO op_sxth_T1(void) { T1 = (int16_t)T1; } +void OPPROTO op_sxtb_T1(void) +{ + T1 = (int8_t)T1; +} + +void OPPROTO op_uxtb_T1(void) +{ + T1 = (uint8_t)T1; +} + +void OPPROTO op_uxth_T1(void) +{ + T1 = (uint16_t)T1; +} + +void OPPROTO op_sxtb16_T1(void) +{ + uint32_t res; + res = (uint16_t)(int8_t)T1; + res |= (uint32_t)(int8_t)(T1 >> 16) << 16; + T1 = res; +} + +void OPPROTO op_uxtb16_T1(void) +{ + uint32_t res; + res = (uint16_t)(uint8_t)T1; + res |= (uint32_t)(uint8_t)(T1 >> 16) << 16; + T1 = res; +} + #define SIGNBIT (uint32_t)0x80000000 /* saturating arithmetic */ void OPPROTO op_addl_T0_T1_setq(void) @@ -1128,23 +1119,52 @@ void OPPROTO op_vfp_mdrr(void) FT0d = u.d; } -/* Floating point load/store. Address is in T1 */ -void OPPROTO op_vfp_lds(void) +/* Copy the most significant bit to T0 to all bits of T1. */ +void OPPROTO op_signbit_T1_T0(void) { - FT0s = ldfl((void *)T1); + T1 = (int32_t)T0 >> 31; } -void OPPROTO op_vfp_ldd(void) +void OPPROTO op_movl_cp15_T0(void) { - FT0d = ldfq((void *)T1); + helper_set_cp15(env, PARAM1, T0); + FORCE_RET(); } -void OPPROTO op_vfp_sts(void) +void OPPROTO op_movl_T0_cp15(void) { - stfl((void *)T1, FT0s); + T0 = helper_get_cp15(env, PARAM1); + FORCE_RET(); } -void OPPROTO op_vfp_std(void) +/* Access to user mode registers from privileged modes. */ +void OPPROTO op_movl_T0_user(void) { - stfq((void *)T1, FT0d); + int regno = PARAM1; + if (regno == 13) { + T0 = env->banked_r13[0]; + } else if (regno == 14) { + T0 = env->banked_r14[0]; + } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { + T0 = env->usr_regs[regno - 8]; + } else { + T0 = env->regs[regno]; + } + FORCE_RET(); +} + + +void OPPROTO op_movl_user_T0(void) +{ + int regno = PARAM1; + if (regno == 13) { + env->banked_r13[0] = T0; + } else if (regno == 14) { + env->banked_r14[0] = T0; + } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) { + env->usr_regs[regno - 8] = T0; + } else { + env->regs[regno] = T0; + } + FORCE_RET(); } diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index a0cddb654..c075b53fc 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -172,3 +172,54 @@ void do_vfp_get_fpscr(void) i = get_float_exception_flags(&env->vfp.fp_status); T0 |= vfp_exceptbits_from_host(i); } + +#if !defined(CONFIG_USER_ONLY) + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + target_phys_addr_t pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_arm_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (__builtin_expect(ret, 0)) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (target_phys_addr_t)retaddr; + 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, NULL); + } + } + raise_exception(env->exception_index); + } + env = saved_env; +} + +#endif diff --git a/target-arm/op_mem.h b/target-arm/op_mem.h new file mode 100644 index 000000000..29fd85bc3 --- /dev/null +++ b/target-arm/op_mem.h @@ -0,0 +1,70 @@ +/* ARM memory operations. */ + +/* Load from address T1 into T0. */ +#define MEM_LD_OP(name) \ +void OPPROTO glue(op_ld##name,MEMSUFFIX)(void) \ +{ \ + T0 = glue(ld##name,MEMSUFFIX)(T1); \ + FORCE_RET(); \ +} + +MEM_LD_OP(ub) +MEM_LD_OP(sb) +MEM_LD_OP(uw) +MEM_LD_OP(sw) +MEM_LD_OP(l) + +#undef MEM_LD_OP + +/* Store T0 to address T1. */ +#define MEM_ST_OP(name) \ +void OPPROTO glue(op_st##name,MEMSUFFIX)(void) \ +{ \ + glue(st##name,MEMSUFFIX)(T1, T0); \ + FORCE_RET(); \ +} + +MEM_ST_OP(b) +MEM_ST_OP(w) +MEM_ST_OP(l) + +#undef MEM_ST_OP + +/* Swap T0 with memory at address T1. */ +/* ??? Is this exception safe? */ +#define MEM_SWP_OP(name, lname) \ +void OPPROTO glue(op_swp##name,MEMSUFFIX)(void) \ +{ \ + uint32_t tmp; \ + cpu_lock(); \ + tmp = glue(ld##lname,MEMSUFFIX)(T1); \ + glue(st##name,MEMSUFFIX)(T1, T0); \ + T0 = tmp; \ + cpu_unlock(); \ + FORCE_RET(); \ +} + +MEM_SWP_OP(b, ub) +MEM_SWP_OP(l, l) + +#undef MEM_SWP_OP + +/* Floating point load/store. Address is in T1 */ +#define VFP_MEM_OP(p, w) \ +void OPPROTO glue(op_vfp_ld##p,MEMSUFFIX)(void) \ +{ \ + FT0##p = glue(ldf##w,MEMSUFFIX)(T1); \ + FORCE_RET(); \ +} \ +void OPPROTO glue(op_vfp_st##p,MEMSUFFIX)(void) \ +{ \ + glue(stf##w,MEMSUFFIX)(T1, FT0##p); \ + FORCE_RET(); \ +} + +VFP_MEM_OP(s,l) +VFP_MEM_OP(d,q) + +#undef VFP_MEM_OP + +#undef MEMSUFFIX diff --git a/target-arm/translate.c b/target-arm/translate.c index 601db555a..8df10bebc 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -28,6 +28,12 @@ #include "exec-all.h" #include "disas.h" +#define ENABLE_ARCH_5J 0 +#define ENABLE_ARCH_6 1 +#define ENABLE_ARCH_6T2 1 + +#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op; + /* internal defines */ typedef struct DisasContext { target_ulong pc; @@ -39,8 +45,17 @@ typedef struct DisasContext { struct TranslationBlock *tb; int singlestep_enabled; int thumb; +#if !defined(CONFIG_USER_ONLY) + int user; +#endif } DisasContext; +#if defined(CONFIG_USER_ONLY) +#define IS_USER(s) 1 +#else +#define IS_USER(s) (s->user) +#endif + #define DISAS_JUMP_NEXT 4 #ifdef USE_DIRECT_JUMP @@ -270,6 +285,18 @@ static inline void gen_bx(DisasContext *s) gen_op_bx_T0(); } + +#if defined(CONFIG_USER_ONLY) +#define gen_ldst(name, s) gen_op_##name##_raw() +#else +#define gen_ldst(name, s) do { \ + if (IS_USER(s)) \ + gen_op_##name##_user(); \ + else \ + gen_op_##name##_kernel(); \ + } while (0) +#endif + static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t) { int val; @@ -319,6 +346,14 @@ static inline void gen_movl_reg_T1(DisasContext *s, int reg) gen_movl_reg_TN(s, reg, 1); } +/* Force a TB lookup after an instruction that changes the CPU state. */ +static inline void gen_lookup_tb(DisasContext *s) +{ + gen_op_movl_T0_im(s->pc); + gen_movl_reg_T0(s, 15); + s->is_jmp = DISAS_UPDATE; +} + static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) { int val, rm, shift, shiftop; @@ -395,11 +430,25 @@ VFP_OP(toui) VFP_OP(touiz) VFP_OP(tosi) VFP_OP(tosiz) -VFP_OP(ld) -VFP_OP(st) #undef VFP_OP +static inline void gen_vfp_ld(DisasContext *s, int dp) +{ + if (dp) + gen_ldst(vfp_ldd, s); + else + gen_ldst(vfp_lds, s); +} + +static inline void gen_vfp_st(DisasContext *s, int dp) +{ + if (dp) + gen_ldst(vfp_std, s); + else + gen_ldst(vfp_sts, s); +} + static inline long vfp_reg_offset (int dp, int reg) { @@ -437,6 +486,30 @@ static inline void gen_mov_vreg_F0(int dp, int reg) gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); } +/* Disassemble system coprocessor (cp15) instruction. Return nonzero if + instruction is not defined. */ +static int disas_cp15_insn(DisasContext *s, uint32_t insn) +{ + uint32_t rd; + + /* ??? Some cp15 registers are accessible from userspace. */ + if (IS_USER(s)) { + return 1; + } + rd = (insn >> 12) & 0xf; + if (insn & (1 << 20)) { + gen_op_movl_T0_cp15(insn); + /* If the destination register is r15 then sets condition codes. */ + if (rd != 15) + gen_movl_reg_T0(s, rd); + } else { + gen_movl_T0_reg(s, rd); + gen_op_movl_cp15_T0(insn); + } + gen_lookup_tb(s); + return 0; +} + /* Disassemble a VFP instruction. Returns nonzero if an error occured (ie. an undefined instruction). */ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) @@ -499,8 +572,8 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_op_vfp_mrs(); } if (rd == 15) { - /* This will only set the 4 flag bits */ - gen_op_movl_psr_T0(); + /* Set the 4 flag bits in the CPSR. */ + gen_op_movl_cpsr_T0(0xf0000000); } else gen_movl_reg_T0(s, rd); } else { @@ -516,9 +589,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_op_vfp_movl_fpscr_T0(); /* This could change vector settings, so jump to the next instuction. */ - gen_op_movl_T0_im(s->pc); - gen_movl_reg_T0(s, 15); - s->is_jmp = DISAS_UPDATE; + gen_lookup_tb(s); break; default: return 1; @@ -848,11 +919,11 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) offset = -offset; gen_op_addl_T1_im(offset); if (insn & (1 << 20)) { - gen_vfp_ld(dp); + gen_vfp_ld(s, dp); gen_mov_vreg_F0(dp, rd); } else { gen_mov_F0_vreg(dp, rd); - gen_vfp_st(dp); + gen_vfp_st(s, dp); } } else { /* load/store multiple */ @@ -871,12 +942,12 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) for (i = 0; i < n; i++) { if (insn & (1 << 20)) { /* load */ - gen_vfp_ld(dp); + gen_vfp_ld(s, dp); gen_mov_vreg_F0(dp, rd + i); } else { /* store */ gen_mov_F0_vreg(dp, rd + i); - gen_vfp_st(dp); + gen_vfp_st(s, dp); } gen_op_addl_T1_im(offset); } @@ -939,11 +1010,68 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) } } +static inline void gen_mulxy(int x, int y) +{ + if (x & 2) + gen_op_sarl_T0_im(16); + else + gen_op_sxth_T0(); + if (y & 1) + gen_op_sarl_T1_im(16); + else + gen_op_sxth_T1(); + gen_op_mul_T0_T1(); +} + +/* Return the mask of PSR bits set by a MSR instruction. */ +static uint32_t msr_mask(DisasContext *s, int flags) { + uint32_t mask; + + mask = 0; + if (flags & (1 << 0)) + mask |= 0xff; + if (flags & (1 << 1)) + mask |= 0xff00; + if (flags & (1 << 2)) + mask |= 0xff0000; + if (flags & (1 << 3)) + mask |= 0xff000000; + /* Mask out undefined bits and state bits. */ + mask &= 0xf89f03df; + /* Mask out privileged bits. */ + if (IS_USER(s)) + mask &= 0xf80f0200; + return mask; +} + +/* Returns nonzero if access to the PSR is not permitted. */ +static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr) +{ + if (spsr) { + /* ??? This is also undefined in system mode. */ + if (IS_USER(s)) + return 1; + gen_op_movl_spsr_T0(mask); + } else { + gen_op_movl_cpsr_T0(mask); + } + gen_lookup_tb(s); + return 0; +} + +static void gen_exception_return(DisasContext *s) +{ + gen_op_movl_reg_TN[0][15](); + gen_op_movl_T0_spsr(); + gen_op_movl_cpsr_T0(0xffffffff); + s->is_jmp = DISAS_UPDATE; +} + static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; - insn = ldl(s->pc); + insn = ldl_code(s->pc); s->pc += 4; cond = insn >> 28; @@ -971,6 +1099,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) /* Coprocessor double register transfer. */ } else if ((insn & 0x0f000010) == 0x0e000010) { /* Additional coprocessor register transfer. */ + } else if ((insn & 0x0ff10010) == 0x01000000) { + /* cps (privileged) */ + } else if ((insn & 0x0ffffdff) == 0x01010000) { + /* setend */ + if (insn & (1 << 9)) { + /* BE8 mode not implemented. */ + goto illegal_op; + } + return; } goto illegal_op; } @@ -984,7 +1121,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) //s->is_jmp = DISAS_JUMP_NEXT; } if ((insn & 0x0f900000) == 0x03000000) { - if ((insn & 0x0ff0f000) != 0x0360f000) + if ((insn & 0x0fb0f000) != 0x0320f000) goto illegal_op; /* CPSR = immediate */ val = insn & 0xff; @@ -992,8 +1129,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (shift) val = (val >> shift) | (val << (32 - shift)); gen_op_movl_T0_im(val); - if (insn & (1 << 19)) - gen_op_movl_psr_T0(); + if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf), + (insn & (1 << 22)) != 0)) + goto illegal_op; } else if ((insn & 0x0f900000) == 0x01000000 && (insn & 0x00000090) != 0x00000090) { /* miscellaneous instructions */ @@ -1002,19 +1140,22 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) rm = insn & 0xf; switch (sh) { case 0x0: /* move program status register */ - if (op1 & 2) { - /* SPSR not accessible in user mode */ - goto illegal_op; - } if (op1 & 1) { - /* CPSR = reg */ + /* PSR = reg */ gen_movl_T0_reg(s, rm); - if (insn & (1 << 19)) - gen_op_movl_psr_T0(); + if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf), + (op1 & 2) != 0)) + goto illegal_op; } else { /* reg = CPSR */ rd = (insn >> 12) & 0xf; - gen_op_movl_T0_psr(); + if (op1 & 2) { + if (IS_USER(s)) + goto illegal_op; + gen_op_movl_T0_spsr(); + } else { + gen_op_movl_T0_cpsr(); + } gen_movl_reg_T0(s, rd); } break; @@ -1033,6 +1174,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; } break; + case 0x2: + if (op1 == 1) { + ARCH(5J); /* bxj */ + /* Trivial implementation equivalent to bx. */ + gen_movl_T0_reg(s, rm); + gen_bx(s); + } else { + goto illegal_op; + } + break; case 0x3: if (op1 != 1) goto illegal_op; @@ -1071,7 +1222,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (sh & 4) gen_op_sarl_T1_im(16); else - gen_op_sxl_T1(); + gen_op_sxth_T1(); gen_op_imulw_T0_T1(); if ((sh & 2) == 0) { gen_movl_T1_reg(s, rn); @@ -1081,22 +1232,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } else { /* 16 * 16 */ gen_movl_T0_reg(s, rm); - if (sh & 2) - gen_op_sarl_T0_im(16); - else - gen_op_sxl_T0(); gen_movl_T1_reg(s, rs); - if (sh & 4) - gen_op_sarl_T1_im(16); - else - gen_op_sxl_T1(); + gen_mulxy(sh & 2, sh & 4); if (op1 == 2) { - gen_op_imull_T0_T1(); + gen_op_signbit_T1_T0(); gen_op_addq_T0_T1(rn, rd); gen_movl_reg_T0(s, rn); gen_movl_reg_T1(s, rd); } else { - gen_op_mul_T0_T1(); if (op1 == 0) { gen_movl_T1_reg(s, rn); gen_op_addl_T0_T1_setq(); @@ -1176,11 +1319,19 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_logic_T0_cc(); break; case 0x02: - if (set_cc) + if (set_cc && rd == 15) { + /* SUBS r15, ... is used for exception return. */ + if (IS_USER(s)) + goto illegal_op; gen_op_subl_T0_T1_cc(); - else - gen_op_subl_T0_T1(); - gen_movl_reg_T0(s, rd); + gen_exception_return(s); + } else { + if (set_cc) + gen_op_subl_T0_T1_cc(); + else + gen_op_subl_T0_T1(); + gen_movl_reg_T0(s, rd); + } break; case 0x03: if (set_cc) @@ -1246,9 +1397,17 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_logic_T0_cc(); break; case 0x0d: - gen_movl_reg_T1(s, rd); - if (logic_cc) - gen_op_logic_T1_cc(); + if (logic_cc && rd == 15) { + /* MOVS r15, ... is used for exception return. */ + if (IS_USER(s)) + goto illegal_op; + gen_op_movl_T0_T1(); + gen_exception_return(s); + } else { + gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); + } break; case 0x0e: gen_op_bicl_T0_T1(); @@ -1301,6 +1460,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (insn & (1 << 21)) /* mult accumulate */ gen_op_addq_T0_T1(rn, rd); if (!(insn & (1 << 23))) { /* double accumulate */ + ARCH(6); gen_op_addq_lo_T0_T1(rn); gen_op_addq_lo_T0_T1(rd); } @@ -1322,9 +1482,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_movl_T0_reg(s, rm); gen_movl_T1_reg(s, rn); if (insn & (1 << 22)) { - gen_op_swpb_T0_T1(); + gen_ldst(swpb, s); } else { - gen_op_swpl_T0_T1(); + gen_ldst(swpl, s); } gen_movl_reg_T0(s, rd); } @@ -1340,14 +1500,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) /* load */ switch(sh) { case 1: - gen_op_lduw_T0_T1(); + gen_ldst(lduw, s); break; case 2: - gen_op_ldsb_T0_T1(); + gen_ldst(ldsb, s); break; default: case 3: - gen_op_ldsw_T0_T1(); + gen_ldst(ldsw, s); break; } gen_movl_reg_T0(s, rd); @@ -1356,18 +1516,18 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (sh & 1) { /* store */ gen_movl_T0_reg(s, rd); - gen_op_stl_T0_T1(); + gen_ldst(stl, s); gen_op_addl_T1_im(4); gen_movl_T0_reg(s, rd + 1); - gen_op_stl_T0_T1(); + gen_ldst(stl, s); if ((insn & (1 << 24)) || (insn & (1 << 20))) gen_op_addl_T1_im(-4); } else { /* load */ - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); gen_movl_reg_T0(s, rd); gen_op_addl_T1_im(4); - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); gen_movl_reg_T0(s, rd + 1); if ((insn & (1 << 24)) || (insn & (1 << 20))) gen_op_addl_T1_im(-4); @@ -1375,7 +1535,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } else { /* store */ gen_movl_T0_reg(s, rd); - gen_op_stw_T0_T1(); + gen_ldst(stw, s); } if (!(insn & (1 << 24))) { gen_add_datah_offset(s, insn); @@ -1393,14 +1553,29 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; gen_movl_T1_reg(s, rn); + i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000); if (insn & (1 << 24)) gen_add_data_offset(s, insn); if (insn & (1 << 20)) { /* load */ +#if defined(CONFIG_USER_ONLY) if (insn & (1 << 22)) - gen_op_ldub_T0_T1(); + gen_op_ldub_raw(); else - gen_op_ldl_T0_T1(); + gen_op_ldl_raw(); +#else + if (insn & (1 << 22)) { + if (i) + gen_op_ldub_user(); + else + gen_op_ldub_kernel(); + } else { + if (i) + gen_op_ldl_user(); + else + gen_op_ldl_kernel(); + } +#endif if (rd == 15) gen_bx(s); else @@ -1408,10 +1583,24 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } else { /* store */ gen_movl_T0_reg(s, rd); +#if defined(CONFIG_USER_ONLY) if (insn & (1 << 22)) - gen_op_stb_T0_T1(); + gen_op_stb_raw(); else - gen_op_stl_T0_T1(); + gen_op_stl_raw(); +#else + if (insn & (1 << 22)) { + if (i) + gen_op_stb_user(); + else + gen_op_stb_kernel(); + } else { + if (i) + gen_op_stl_user(); + else + gen_op_stl_kernel(); + } +#endif } if (!(insn & (1 << 24))) { gen_add_data_offset(s, insn); @@ -1423,11 +1612,17 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0x08: case 0x09: { - int j, n; + int j, n, user; /* load/store multiple words */ /* XXX: store correct base if write back */ - if (insn & (1 << 22)) - goto illegal_op; /* only usable in supervisor mode */ + user = 0; + if (insn & (1 << 22)) { + if (IS_USER(s)) + goto illegal_op; /* only usable in supervisor mode */ + + if ((insn & (1 << 15)) == 0) + user = 1; + } rn = (insn >> 16) & 0xf; gen_movl_T1_reg(s, rn); @@ -1460,21 +1655,26 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (insn & (1 << i)) { if (insn & (1 << 20)) { /* load */ - gen_op_ldl_T0_T1(); - if (i == 15) + gen_ldst(ldl, s); + if (i == 15) { gen_bx(s); - else + } else if (user) { + gen_op_movl_user_T0(i); + } else { gen_movl_reg_T0(s, i); + } } else { /* store */ if (i == 15) { /* special case: r15 = PC + 12 */ val = (long)s->pc + 8; gen_op_movl_TN_im[0](val); + } else if (user) { + gen_op_movl_T0_user(i); } else { gen_movl_T0_reg(s, i); } - gen_op_stl_T0_T1(); + gen_ldst(stl, s); } j++; /* no need to add after the last transfer */ @@ -1503,6 +1703,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } gen_movl_reg_T1(s, rn); } + if ((insn & (1 << 22)) && !user) { + /* Restore CPSR from SPSR. */ + gen_op_movl_T0_spsr(); + gen_op_movl_cpsr_T0(0xffffffff); + s->is_jmp = DISAS_UPDATE; + } } break; case 0xa: @@ -1532,6 +1738,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (disas_vfp_insn (env, s, insn)) goto illegal_op; break; + case 15: + if (disas_cp15_insn (s, insn)) + goto illegal_op; + break; default: /* unknown coprocessor. */ goto illegal_op; @@ -1561,9 +1771,9 @@ static void disas_thumb_insn(DisasContext *s) int32_t offset; int i; - insn = lduw(s->pc); + insn = lduw_code(s->pc); s->pc += 2; - + switch (insn >> 12) { case 0: case 1: rd = insn & 7; @@ -1628,7 +1838,7 @@ static void disas_thumb_insn(DisasContext *s) val = s->pc + 2 + ((insn & 0xff) * 4); val &= ~(uint32_t)2; gen_op_movl_T1_im(val); - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); gen_movl_reg_T0(s, rd); break; } @@ -1771,28 +1981,28 @@ static void disas_thumb_insn(DisasContext *s) switch (op) { case 0: /* str */ - gen_op_stl_T0_T1(); + gen_ldst(stl, s); break; case 1: /* strh */ - gen_op_stw_T0_T1(); + gen_ldst(stw, s); break; case 2: /* strb */ - gen_op_stb_T0_T1(); + gen_ldst(stb, s); break; case 3: /* ldrsb */ - gen_op_ldsb_T0_T1(); + gen_ldst(ldsb, s); break; case 4: /* ldr */ - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); break; case 5: /* ldrh */ - gen_op_lduw_T0_T1(); + gen_ldst(lduw, s); break; case 6: /* ldrb */ - gen_op_ldub_T0_T1(); + gen_ldst(ldub, s); break; case 7: /* ldrsh */ - gen_op_ldsw_T0_T1(); + gen_ldst(ldsw, s); break; } if (op >= 3) /* load */ @@ -1810,12 +2020,12 @@ static void disas_thumb_insn(DisasContext *s) if (insn & (1 << 11)) { /* load */ - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); gen_movl_reg_T0(s, rd); } else { /* store */ gen_movl_T0_reg(s, rd); - gen_op_stl_T0_T1(); + gen_ldst(stl, s); } break; @@ -1830,12 +2040,12 @@ static void disas_thumb_insn(DisasContext *s) if (insn & (1 << 11)) { /* load */ - gen_op_ldub_T0_T1(); + gen_ldst(ldub, s); gen_movl_reg_T0(s, rd); } else { /* store */ gen_movl_T0_reg(s, rd); - gen_op_stb_T0_T1(); + gen_ldst(stb, s); } break; @@ -1850,12 +2060,12 @@ static void disas_thumb_insn(DisasContext *s) if (insn & (1 << 11)) { /* load */ - gen_op_lduw_T0_T1(); + gen_ldst(lduw, s); gen_movl_reg_T0(s, rd); } else { /* store */ gen_movl_T0_reg(s, rd); - gen_op_stw_T0_T1(); + gen_ldst(stw, s); } break; @@ -1869,12 +2079,12 @@ static void disas_thumb_insn(DisasContext *s) if (insn & (1 << 11)) { /* load */ - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); gen_movl_reg_T0(s, rd); } else { /* store */ gen_movl_T0_reg(s, rd); - gen_op_stl_T0_T1(); + gen_ldst(stl, s); } break; @@ -1929,12 +2139,12 @@ static void disas_thumb_insn(DisasContext *s) if (insn & (1 << i)) { if (insn & (1 << 11)) { /* pop */ - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); gen_movl_reg_T0(s, i); } else { /* push */ gen_movl_T0_reg(s, i); - gen_op_stl_T0_T1(); + gen_ldst(stl, s); } /* advance to the next address. */ gen_op_addl_T1_T2(); @@ -1943,13 +2153,13 @@ static void disas_thumb_insn(DisasContext *s) if (insn & (1 << 8)) { if (insn & (1 << 11)) { /* pop pc */ - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); /* don't set the pc until the rest of the instruction has completed */ } else { /* push lr */ gen_movl_T0_reg(s, 14); - gen_op_stl_T0_T1(); + gen_ldst(stl, s); } gen_op_addl_T1_T2(); } @@ -1978,19 +2188,20 @@ static void disas_thumb_insn(DisasContext *s) if (insn & (1 << i)) { if (insn & (1 << 11)) { /* load */ - gen_op_ldl_T0_T1(); + gen_ldst(ldl, s); gen_movl_reg_T0(s, i); } else { /* store */ gen_movl_T0_reg(s, i); - gen_op_stl_T0_T1(); + gen_ldst(stl, s); } /* advance to the next address */ gen_op_addl_T1_T2(); } } /* Base register writeback. */ - gen_movl_reg_T1(s, rn); + if ((insn & (1 << rn)) == 0) + gen_movl_reg_T1(s, rn); break; case 13: @@ -2036,7 +2247,7 @@ static void disas_thumb_insn(DisasContext *s) case 15: /* branch and link [and switch to arm] */ offset = ((int32_t)insn << 21) >> 10; - insn = lduw(s->pc); + insn = lduw_code(s->pc); offset |= insn & 0x7ff; val = (uint32_t)s->pc + 2; @@ -2073,6 +2284,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, uint16_t *gen_opc_end; int j, lj; target_ulong pc_start; + uint32_t next_page_start; /* generate intermediate code */ pc_start = tb->pc; @@ -2088,6 +2300,10 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->singlestep_enabled = env->singlestep_enabled; dc->condjmp = 0; dc->thumb = env->thumb; +#if !defined(CONFIG_USER_ONLY) + dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; +#endif + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; nb_gen_labels = 0; lj = -1; do { @@ -2124,12 +2340,13 @@ static inline int gen_intermediate_code_internal(CPUState *env, } /* Translation stops when a conditional branch is enoutered. * Otherwise the subsequent code could get translated several times. - */ + * Also stop translation when a page boundary is reached. This + * ensures prefech aborts occur at the right place. */ } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && - (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); - /* It this stage dc->condjmp will only be set when the skipped - * instruction was a conditional branch, and teh PC has already been + dc->pc < next_page_start); + /* At this stage dc->condjmp will only be set when the skipped + * instruction was a conditional branch, and the PC has already been * written. */ if (__builtin_expect(env->singlestep_enabled, 0)) { /* Make sure the pc is updated, and raise a debug exception. */ @@ -2180,8 +2397,15 @@ static inline int gen_intermediate_code_internal(CPUState *env, } } #endif - if (!search_pc) + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + tb->size = 0; + } else { tb->size = dc->pc - pc_start; + } return 0; } @@ -2195,6 +2419,17 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } +void cpu_reset(CPUARMState *env) +{ +#if defined (CONFIG_USER_ONLY) + /* SVC mode with interrupts disabled. */ + env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; +#else + env->uncached_cpsr = ARM_CPU_MODE_USR; +#endif + env->regs[15] = 0; +} + CPUARMState *cpu_arm_init(void) { CPUARMState *env; @@ -2203,6 +2438,8 @@ CPUARMState *cpu_arm_init(void) if (!env) return NULL; cpu_exec_init(env); + cpu_reset(env); + tlb_flush(env, 1); return env; } @@ -2211,6 +2448,10 @@ void cpu_arm_close(CPUARMState *env) free(env); } +static const char *cpu_mode_names[16] = { + "usr", "fiq", "irq", "svc", "???", "???", "???", "abt", + "???", "???", "???", "und", "???", "???", "???", "sys" +}; void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -2221,6 +2462,7 @@ void cpu_dump_state(CPUState *env, FILE *f, float s; } s0, s1; CPU_DoubleU d; + uint32_t psr; for(i=0;i<16;i++) { cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]); @@ -2229,13 +2471,15 @@ void cpu_dump_state(CPUState *env, FILE *f, else cpu_fprintf(f, " "); } - cpu_fprintf(f, "PSR=%08x %c%c%c%c %c\n", - env->cpsr, - env->cpsr & (1 << 31) ? 'N' : '-', - env->cpsr & (1 << 30) ? 'Z' : '-', - env->cpsr & (1 << 29) ? 'C' : '-', - env->cpsr & (1 << 28) ? 'V' : '-', - env->thumb ? 'T' : 'A'); + psr = cpsr_read(env); + cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d %x\n", + psr, + psr & (1 << 31) ? 'N' : '-', + psr & (1 << 30) ? 'Z' : '-', + psr & (1 << 29) ? 'C' : '-', + psr & (1 << 28) ? 'V' : '-', + psr & CPSR_T ? 'T' : 'A', + cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); for (i = 0; i < 16; i++) { d.d = env->vfp.regs[i]; @@ -2250,27 +2494,3 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr); } -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - return addr; -} - -#if defined(CONFIG_USER_ONLY) - -int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) -{ - env->cp15_6 = address; - if (rw == 2) { - env->exception_index = EXCP_PREFETCH_ABORT; - } else { - env->exception_index = EXCP_DATA_ABORT; - } - return 1; -} - -#else - -#error not implemented - -#endif diff --git a/vl.c b/vl.c index eaf6a1d68..4f19dd0f0 100644 --- a/vl.c +++ b/vl.c @@ -3359,6 +3359,19 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) tlb_flush(env, 1); return 0; } + +#elif defined(TARGET_ARM) + +/* ??? Need to implement these. */ +void cpu_save(QEMUFile *f, void *opaque) +{ +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} + #else #warning No CPU save/restore functions @@ -4054,6 +4067,10 @@ void register_machines(void) #else qemu_register_machine(&sun4m_machine); #endif +#elif defined(TARGET_ARM) + qemu_register_machine(&integratorcp_machine); +#else +#error unsupported CPU #endif } diff --git a/vl.h b/vl.h index 6f4ac7f88..42954ebc5 100644 --- a/vl.h +++ b/vl.h @@ -928,6 +928,9 @@ void do_usb_add(const char *devname); void do_usb_del(const char *devname); void usb_info(void); +/* integratorcp.c */ +extern QEMUMachine integratorcp_machine; + /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); -- cgit v1.2.3 From e8ebb8a8d7d10bd04eab9ae8ad3da707d178a02d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 10:39:51 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1662 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.cvsignore b/.cvsignore index 6d6858b65..7e7f5fa6b 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,4 +1,5 @@ arm-user +arm-softmmu armeb-user config-host.* dyngen -- cgit v1.2.3 From 9332f9dafa33b085488a5369333213d549dbdc7f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 10:46:39 +0000 Subject: ARM CPU suspend/halt (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1663 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 11 +++++++++++ target-arm/cpu.h | 2 +- target-arm/op.c | 7 +++++++ target-arm/translate.c | 9 +++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index f411eccf8..cddea532a 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -274,6 +274,17 @@ int cpu_exec(CPUState *env1) 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)) { + env1->halted = 0; + } else { + return EXCP_HALTED; + } + } #endif cpu_single_env = env1; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1c1233c19..3b36839e4 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -90,7 +90,7 @@ typedef struct CPUARMState { int exception_index; int interrupt_request; int user_mode_only; - uint32_t address; + int halted; /* VFP coprocessor state. */ struct { diff --git a/target-arm/op.c b/target-arm/op.c index 09449f28e..35419a1b7 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -878,6 +878,13 @@ void OPPROTO op_debug(void) cpu_loop_exit(); } +void OPPROTO op_wfi(void) +{ + env->exception_index = EXCP_HLT; + env->halted = 1; + cpu_loop_exit(); +} + /* VFP support. We follow the convention used for VFP instrunctions: Single precition routines have a "s" suffix, double precision a "d" suffix. */ diff --git a/target-arm/translate.c b/target-arm/translate.c index 8df10bebc..930826cab 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -496,6 +496,15 @@ static int disas_cp15_insn(DisasContext *s, uint32_t insn) if (IS_USER(s)) { return 1; } + if ((insn & 0x0fff0fff) == 0x0e070f90 + || (insn & 0x0fff0fff) == 0x0e070f58) { + /* Wait for interrupt. */ + gen_op_movl_T0_im((long)s->pc); + gen_op_movl_reg_TN[0][15](); + gen_op_wfi(); + s->is_jmp = DISAS_JUMP; + return 0; + } rd = (insn >> 12) & 0xf; if (insn & (1 << 20)) { gen_op_movl_T0_cp15(insn); -- cgit v1.2.3 From 79639d423f779e65f24d0fcc05b14d6c45b4a894 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 10:58:41 +0000 Subject: update boot sector when using -kernel (Magnus Damm) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1664 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block.c b/block.c index 077c27855..efd96e637 100644 --- a/block.c +++ b/block.c @@ -444,6 +444,9 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, return -1; if (bs->read_only) return -1; + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(bs->boot_sector_data, buf, 512); + } return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); } -- cgit v1.2.3 From 15338fd765041410bc1aa0d7fe7bea7c2849fcde Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 11:41:16 +0000 Subject: added AT_PLATFORM and AT_HWCAP for x86 (initial patch by Gwenole Beauchesne) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1665 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 53 ++++++++++++++++++++++++++++++++++++++++++++-------- linux-user/main.c | 3 +-- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 2ae1e5324..eda6e9ba2 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -25,6 +25,26 @@ #ifdef TARGET_I386 +#define ELF_PLATFORM get_elf_platform() + +static const char *get_elf_platform(void) +{ + static char elf_platform[] = "i386"; + int family = (global_env->cpuid_version >> 8) & 0xff; + if (family > 6) + family = 6; + if (family >= 3) + elf_platform[1] = '0' + family; + return elf_platform; +} + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + return global_env->cpuid_features; +} + #define ELF_START_MMAP 0x80000000 /* @@ -91,7 +111,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 -#define DLINFO_ARCH_ITEMS 1 enum { ARM_HWCAP_ARM_SWP = 1 << 0, @@ -104,15 +123,10 @@ enum ARM_HWCAP_ARM_EDSP = 1 << 7, }; -#define ARM_HWCAPS (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ +#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP) -#define ARCH_DLINFO \ -do { \ - NEW_AUX_ENT(AT_HWCAP, ARM_HWCAPS); \ -} while (0) - #endif #ifdef TARGET_SPARC @@ -233,6 +247,14 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * #endif +#ifndef ELF_PLATFORM +#define ELF_PLATFORM (NULL) +#endif + +#ifndef ELF_HWCAP +#define ELF_HWCAP 0 +#endif + #include "elf.h" /* @@ -314,7 +336,7 @@ struct exec #define INTERPRETER_AOUT 1 #define INTERPRETER_ELF 2 -#define DLINFO_ITEMS 11 +#define DLINFO_ITEMS 12 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { @@ -646,14 +668,26 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, { target_ulong *argv, *envp; target_ulong *sp, *csp; + target_ulong *u_platform; + const char *k_platform; int v; /* * Force 16 byte _final_ alignment here for generality. */ sp = (unsigned int *) (~15UL & (unsigned long) p); + u_platform = NULL; + k_platform = ELF_PLATFORM; + if (k_platform) { + size_t len = strlen(k_platform) + 1; + sp -= (len + sizeof(target_ulong) - 1) / sizeof(target_ulong); + u_platform = (target_ulong *)sp; + __copy_to_user(u_platform, k_platform, len); + } csp = sp; csp -= (DLINFO_ITEMS + 1) * 2; + if (k_platform) + csp -= 2; #ifdef DLINFO_ARCH_ITEMS csp -= DLINFO_ARCH_ITEMS*2; #endif @@ -681,6 +715,9 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid()); NEW_AUX_ENT(AT_GID, (target_ulong) getgid()); NEW_AUX_ENT(AT_EGID, (target_ulong) getegid()); + NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP); + if (k_platform) + NEW_AUX_ENT(AT_PLATFORM, (target_ulong) u_platform); #ifdef ARCH_DLINFO /* * ARCH_DLINFO must come last so platform specific code can enforce diff --git a/linux-user/main.c b/linux-user/main.c index 1b747d873..4b7fd7ca8 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1098,6 +1098,7 @@ int main(int argc, char **argv) /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ env = cpu_init(); + global_env = env; if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { printf("Error loading %s\n", filename); @@ -1120,8 +1121,6 @@ int main(int argc, char **argv) syscall_init(); signal_init(); - global_env = env; - /* build Task State */ memset(ts, 0, sizeof(TaskState)); env->opaque = ts; -- cgit v1.2.3 From cc9442b9fc4f86da341f9d4dcb0f04e8e013764d Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 18:43:28 +0000 Subject: fixed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1666 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index cddea532a..5c85c1e9d 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -192,7 +192,7 @@ static inline TranslationBlock *tb_find_fast(void) pc = env->nip; #elif defined(TARGET_MIPS) flags = env->hflags & MIPS_HFLAGS_TMASK; - cs_base = NULL; + cs_base = 0; pc = env->PC; #else #error unsupported CPU @@ -1056,7 +1056,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0); + ret = cpu_mips_handle_mmu_fault(env, address, is_write, 1, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) -- cgit v1.2.3 From eeef26cd428b584a8211cc42185585c840b778f4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 18:47:06 +0000 Subject: fixed BLTZAL and BLTZALL insns - fixed regressions from jmp opts git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1667 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 71b101be3..bb8128401 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -28,7 +28,7 @@ #include "exec-all.h" #include "disas.h" -#define MIPS_DEBUG_DISAS +//#define MIPS_DEBUG_DISAS //#define MIPS_SINGLE_STEP #ifdef USE_DIRECT_JUMP @@ -1033,13 +1033,20 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, case OPC_BNE: /* rx != rx */ case OPC_BGTZ: /* 0 > 0 */ case OPC_BLTZ: /* 0 < 0 */ - case OPC_BLTZAL: /* 0 < 0 */ /* Treated as NOP */ MIPS_DEBUG("bnever (NOP)"); return; + case OPC_BLTZAL: /* 0 < 0 */ + gen_op_set_T0(ctx->pc + 8); + gen_op_store_T0_gpr(31); + return; + case OPC_BLTZALL: /* 0 < 0 likely */ + gen_op_set_T0(ctx->pc + 8); + gen_op_store_T0_gpr(31); + gen_goto_tb(ctx, 0, ctx->pc + 4); + return; case OPC_BNEL: /* rx != rx likely */ case OPC_BGTZL: /* 0 > 0 likely */ - case OPC_BLTZALL: /* 0 < 0 likely */ case OPC_BLTZL: /* 0 < 0 likely */ /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever and skip"); @@ -1282,11 +1289,12 @@ static void gen_arith64 (DisasContext *ctx, uint16_t opc) static void gen_blikely(DisasContext *ctx) { - int l1; - l1 = gen_new_label(); - gen_op_jnz_T2(l1); - gen_op_save_state(ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); - gen_goto_tb(ctx, 1, ctx->pc + 4); + int l1; + l1 = gen_new_label(); + gen_op_jnz_T2(l1); + gen_op_save_state(ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); + gen_goto_tb(ctx, 1, ctx->pc + 4); + gen_set_label(l1); } static void decode_opc (DisasContext *ctx) @@ -1524,9 +1532,9 @@ static void decode_opc (DisasContext *ctx) int l1; l1 = gen_new_label(); gen_op_jnz_T2(l1); - gen_goto_tb(ctx, 0, ctx->btarget); - gen_set_label(l1); gen_goto_tb(ctx, 1, ctx->pc + 4); + gen_set_label(l1); + gen_goto_tb(ctx, 0, ctx->btarget); } break; case MIPS_HFLAG_BR: @@ -1722,5 +1730,8 @@ CPUMIPSState *cpu_mips_init (void) env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); env->CP0_PRid = MIPS_CPU; env->exception_index = EXCP_NONE; +#if defined(CONFIG_USER_ONLY) + env->hflags |= MIPS_HFLAG_UM; +#endif return env; } -- cgit v1.2.3 From 048f6b4df7ca3be292f40f7f56fd4e48edcabbe9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 18:47:20 +0000 Subject: mips user emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1668 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + configure | 2 +- linux-user/elfload.c | 25 +++ linux-user/main.c | 407 +++++++++++++++++++++++++++++++++++++++++++ linux-user/mips/syscall.h | 23 +++ linux-user/mips/syscall_nr.h | 288 ++++++++++++++++++++++++++++++ linux-user/mips/termbits.h | 214 +++++++++++++++++++++++ linux-user/syscall.c | 6 + linux-user/syscall_defs.h | 186 ++++++++++++++++++-- target-mips/op_helper.c | 33 ++++ 10 files changed, 1167 insertions(+), 18 deletions(-) create mode 100644 linux-user/mips/syscall.h create mode 100644 linux-user/mips/syscall_nr.h create mode 100644 linux-user/mips/termbits.h diff --git a/Changelog b/Changelog index d386474ac..8c97b8ec5 100644 --- a/Changelog +++ b/Changelog @@ -13,6 +13,7 @@ version 0.7.3: - Linux host serial port access - Linux host low level parallel port access - New network emulation code supporting VLANs. + - MIPS User Linux emulation version 0.7.2: diff --git a/configure b/configure index bad61e960..9a6e54735 100755 --- a/configure +++ b/configure @@ -230,7 +230,7 @@ if test -z "$target_list" ; then target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu arm-softmmu" # the following are Linux specific if [ "$linux" = "yes" ] ; then - target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list" + target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user $target_list" fi else target_list=$(echo "$target_list" | sed -e 's/,/ /g') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index eda6e9ba2..f1af656dc 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -247,6 +247,31 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * #endif +#ifdef TARGET_MIPS + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_MIPS ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_MIPS + +#define ELF_PLAT_INIT(_r) + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->cp0_status = CP0St_UM; + regs->cp0_epc = infop->entry; + regs->regs[29] = infop->start_stack; +} + +#endif /* TARGET_MIPS */ + #ifndef ELF_PLATFORM #define ELF_PLATFORM (NULL) #endif diff --git a/linux-user/main.c b/linux-user/main.c index 4b7fd7ca8..907f7109e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -977,6 +977,404 @@ void cpu_loop(CPUPPCState *env) } #endif +#ifdef TARGET_MIPS + +#define MIPS_SYS(name, args) args, + +static const uint8_t mips_syscall_args[] = { + MIPS_SYS(sys_syscall , 0) /* 4000 */ + MIPS_SYS(sys_exit , 1) + MIPS_SYS(sys_fork , 0) + MIPS_SYS(sys_read , 3) + MIPS_SYS(sys_write , 3) + MIPS_SYS(sys_open , 3) /* 4005 */ + MIPS_SYS(sys_close , 1) + MIPS_SYS(sys_waitpid , 3) + MIPS_SYS(sys_creat , 2) + MIPS_SYS(sys_link , 2) + MIPS_SYS(sys_unlink , 1) /* 4010 */ + MIPS_SYS(sys_execve , 0) + MIPS_SYS(sys_chdir , 1) + MIPS_SYS(sys_time , 1) + MIPS_SYS(sys_mknod , 3) + MIPS_SYS(sys_chmod , 2) /* 4015 */ + MIPS_SYS(sys_lchown , 3) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_stat */ + MIPS_SYS(sys_lseek , 3) + MIPS_SYS(sys_getpid , 0) /* 4020 */ + MIPS_SYS(sys_mount , 5) + MIPS_SYS(sys_oldumount , 1) + MIPS_SYS(sys_setuid , 1) + MIPS_SYS(sys_getuid , 0) + MIPS_SYS(sys_stime , 1) /* 4025 */ + MIPS_SYS(sys_ptrace , 4) + MIPS_SYS(sys_alarm , 1) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_fstat */ + MIPS_SYS(sys_pause , 0) + MIPS_SYS(sys_utime , 2) /* 4030 */ + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_access , 2) + MIPS_SYS(sys_nice , 1) + MIPS_SYS(sys_ni_syscall , 0) /* 4035 */ + MIPS_SYS(sys_sync , 0) + MIPS_SYS(sys_kill , 2) + MIPS_SYS(sys_rename , 2) + MIPS_SYS(sys_mkdir , 2) + MIPS_SYS(sys_rmdir , 1) /* 4040 */ + MIPS_SYS(sys_dup , 1) + MIPS_SYS(sys_pipe , 0) + MIPS_SYS(sys_times , 1) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_brk , 1) /* 4045 */ + MIPS_SYS(sys_setgid , 1) + MIPS_SYS(sys_getgid , 0) + MIPS_SYS(sys_ni_syscall , 0) /* was signal(2) */ + MIPS_SYS(sys_geteuid , 0) + MIPS_SYS(sys_getegid , 0) /* 4050 */ + MIPS_SYS(sys_acct , 0) + MIPS_SYS(sys_umount , 2) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_ioctl , 3) + MIPS_SYS(sys_fcntl , 3) /* 4055 */ + MIPS_SYS(sys_ni_syscall , 2) + MIPS_SYS(sys_setpgid , 2) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_olduname , 1) + MIPS_SYS(sys_umask , 1) /* 4060 */ + MIPS_SYS(sys_chroot , 1) + MIPS_SYS(sys_ustat , 2) + MIPS_SYS(sys_dup2 , 2) + MIPS_SYS(sys_getppid , 0) + MIPS_SYS(sys_getpgrp , 0) /* 4065 */ + MIPS_SYS(sys_setsid , 0) + MIPS_SYS(sys_sigaction , 3) + MIPS_SYS(sys_sgetmask , 0) + MIPS_SYS(sys_ssetmask , 1) + MIPS_SYS(sys_setreuid , 2) /* 4070 */ + MIPS_SYS(sys_setregid , 2) + MIPS_SYS(sys_sigsuspend , 0) + MIPS_SYS(sys_sigpending , 1) + MIPS_SYS(sys_sethostname , 2) + MIPS_SYS(sys_setrlimit , 2) /* 4075 */ + MIPS_SYS(sys_getrlimit , 2) + MIPS_SYS(sys_getrusage , 2) + MIPS_SYS(sys_gettimeofday, 2) + MIPS_SYS(sys_settimeofday, 2) + MIPS_SYS(sys_getgroups , 2) /* 4080 */ + MIPS_SYS(sys_setgroups , 2) + MIPS_SYS(sys_ni_syscall , 0) /* old_select */ + MIPS_SYS(sys_symlink , 2) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_lstat */ + MIPS_SYS(sys_readlink , 3) /* 4085 */ + MIPS_SYS(sys_uselib , 1) + MIPS_SYS(sys_swapon , 2) + MIPS_SYS(sys_reboot , 3) + MIPS_SYS(old_readdir , 3) + MIPS_SYS(old_mmap , 6) /* 4090 */ + MIPS_SYS(sys_munmap , 2) + MIPS_SYS(sys_truncate , 2) + MIPS_SYS(sys_ftruncate , 2) + MIPS_SYS(sys_fchmod , 2) + MIPS_SYS(sys_fchown , 3) /* 4095 */ + MIPS_SYS(sys_getpriority , 2) + MIPS_SYS(sys_setpriority , 3) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_statfs , 2) + MIPS_SYS(sys_fstatfs , 2) /* 4100 */ + MIPS_SYS(sys_ni_syscall , 0) /* was ioperm(2) */ + MIPS_SYS(sys_socketcall , 2) + MIPS_SYS(sys_syslog , 3) + MIPS_SYS(sys_setitimer , 3) + MIPS_SYS(sys_getitimer , 2) /* 4105 */ + MIPS_SYS(sys_newstat , 2) + MIPS_SYS(sys_newlstat , 2) + MIPS_SYS(sys_newfstat , 2) + MIPS_SYS(sys_uname , 1) + MIPS_SYS(sys_ni_syscall , 0) /* 4110 was iopl(2) */ + MIPS_SYS(sys_vhangup , 0) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_idle() */ + MIPS_SYS(sys_ni_syscall , 0) /* was sys_vm86 */ + MIPS_SYS(sys_wait4 , 4) + MIPS_SYS(sys_swapoff , 1) /* 4115 */ + MIPS_SYS(sys_sysinfo , 1) + MIPS_SYS(sys_ipc , 6) + MIPS_SYS(sys_fsync , 1) + MIPS_SYS(sys_sigreturn , 0) + MIPS_SYS(sys_clone , 0) /* 4120 */ + MIPS_SYS(sys_setdomainname, 2) + MIPS_SYS(sys_newuname , 1) + MIPS_SYS(sys_ni_syscall , 0) /* sys_modify_ldt */ + MIPS_SYS(sys_adjtimex , 1) + MIPS_SYS(sys_mprotect , 3) /* 4125 */ + MIPS_SYS(sys_sigprocmask , 3) + MIPS_SYS(sys_ni_syscall , 0) /* was create_module */ + MIPS_SYS(sys_init_module , 5) + MIPS_SYS(sys_delete_module, 1) + MIPS_SYS(sys_ni_syscall , 0) /* 4130 was get_kernel_syms */ + MIPS_SYS(sys_quotactl , 0) + MIPS_SYS(sys_getpgid , 1) + MIPS_SYS(sys_fchdir , 1) + MIPS_SYS(sys_bdflush , 2) + MIPS_SYS(sys_sysfs , 3) /* 4135 */ + MIPS_SYS(sys_personality , 1) + MIPS_SYS(sys_ni_syscall , 0) /* for afs_syscall */ + MIPS_SYS(sys_setfsuid , 1) + MIPS_SYS(sys_setfsgid , 1) + MIPS_SYS(sys_llseek , 5) /* 4140 */ + MIPS_SYS(sys_getdents , 3) + MIPS_SYS(sys_select , 5) + MIPS_SYS(sys_flock , 2) + MIPS_SYS(sys_msync , 3) + MIPS_SYS(sys_readv , 3) /* 4145 */ + MIPS_SYS(sys_writev , 3) + MIPS_SYS(sys_cacheflush , 3) + MIPS_SYS(sys_cachectl , 3) + MIPS_SYS(sys_sysmips , 4) + MIPS_SYS(sys_ni_syscall , 0) /* 4150 */ + MIPS_SYS(sys_getsid , 1) + MIPS_SYS(sys_fdatasync , 0) + MIPS_SYS(sys_sysctl , 1) + MIPS_SYS(sys_mlock , 2) + MIPS_SYS(sys_munlock , 2) /* 4155 */ + MIPS_SYS(sys_mlockall , 1) + MIPS_SYS(sys_munlockall , 0) + MIPS_SYS(sys_sched_setparam, 2) + MIPS_SYS(sys_sched_getparam, 2) + MIPS_SYS(sys_sched_setscheduler, 3) /* 4160 */ + MIPS_SYS(sys_sched_getscheduler, 1) + MIPS_SYS(sys_sched_yield , 0) + MIPS_SYS(sys_sched_get_priority_max, 1) + MIPS_SYS(sys_sched_get_priority_min, 1) + MIPS_SYS(sys_sched_rr_get_interval, 2) /* 4165 */ + MIPS_SYS(sys_nanosleep, 2) + MIPS_SYS(sys_mremap , 4) + MIPS_SYS(sys_accept , 3) + MIPS_SYS(sys_bind , 3) + MIPS_SYS(sys_connect , 3) /* 4170 */ + MIPS_SYS(sys_getpeername , 3) + MIPS_SYS(sys_getsockname , 3) + MIPS_SYS(sys_getsockopt , 5) + MIPS_SYS(sys_listen , 2) + MIPS_SYS(sys_recv , 4) /* 4175 */ + MIPS_SYS(sys_recvfrom , 6) + MIPS_SYS(sys_recvmsg , 3) + MIPS_SYS(sys_send , 4) + MIPS_SYS(sys_sendmsg , 3) + MIPS_SYS(sys_sendto , 6) /* 4180 */ + MIPS_SYS(sys_setsockopt , 5) + MIPS_SYS(sys_shutdown , 2) + MIPS_SYS(sys_socket , 3) + MIPS_SYS(sys_socketpair , 4) + MIPS_SYS(sys_setresuid , 3) /* 4185 */ + MIPS_SYS(sys_getresuid , 3) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_query_module */ + MIPS_SYS(sys_poll , 3) + MIPS_SYS(sys_nfsservctl , 3) + MIPS_SYS(sys_setresgid , 3) /* 4190 */ + MIPS_SYS(sys_getresgid , 3) + MIPS_SYS(sys_prctl , 5) + MIPS_SYS(sys_rt_sigreturn, 0) + MIPS_SYS(sys_rt_sigaction, 4) + MIPS_SYS(sys_rt_sigprocmask, 4) /* 4195 */ + MIPS_SYS(sys_rt_sigpending, 2) + MIPS_SYS(sys_rt_sigtimedwait, 4) + MIPS_SYS(sys_rt_sigqueueinfo, 3) + MIPS_SYS(sys_rt_sigsuspend, 0) + MIPS_SYS(sys_pread64 , 6) /* 4200 */ + MIPS_SYS(sys_pwrite64 , 6) + MIPS_SYS(sys_chown , 3) + MIPS_SYS(sys_getcwd , 2) + MIPS_SYS(sys_capget , 2) + MIPS_SYS(sys_capset , 2) /* 4205 */ + MIPS_SYS(sys_sigaltstack , 0) + MIPS_SYS(sys_sendfile , 4) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_mmap2 , 6) /* 4210 */ + MIPS_SYS(sys_truncate64 , 4) + MIPS_SYS(sys_ftruncate64 , 4) + MIPS_SYS(sys_stat64 , 2) + MIPS_SYS(sys_lstat64 , 2) + MIPS_SYS(sys_fstat64 , 2) /* 4215 */ + MIPS_SYS(sys_pivot_root , 2) + MIPS_SYS(sys_mincore , 3) + MIPS_SYS(sys_madvise , 3) + MIPS_SYS(sys_getdents64 , 3) + MIPS_SYS(sys_fcntl64 , 3) /* 4220 */ + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_gettid , 0) + MIPS_SYS(sys_readahead , 5) + MIPS_SYS(sys_setxattr , 5) + MIPS_SYS(sys_lsetxattr , 5) /* 4225 */ + MIPS_SYS(sys_fsetxattr , 5) + MIPS_SYS(sys_getxattr , 4) + MIPS_SYS(sys_lgetxattr , 4) + MIPS_SYS(sys_fgetxattr , 4) + MIPS_SYS(sys_listxattr , 3) /* 4230 */ + MIPS_SYS(sys_llistxattr , 3) + MIPS_SYS(sys_flistxattr , 3) + MIPS_SYS(sys_removexattr , 2) + MIPS_SYS(sys_lremovexattr, 2) + MIPS_SYS(sys_fremovexattr, 2) /* 4235 */ + MIPS_SYS(sys_tkill , 2) + MIPS_SYS(sys_sendfile64 , 5) + MIPS_SYS(sys_futex , 2) + MIPS_SYS(sys_sched_setaffinity, 3) + MIPS_SYS(sys_sched_getaffinity, 3) /* 4240 */ + MIPS_SYS(sys_io_setup , 2) + MIPS_SYS(sys_io_destroy , 1) + MIPS_SYS(sys_io_getevents, 5) + MIPS_SYS(sys_io_submit , 3) + MIPS_SYS(sys_io_cancel , 3) /* 4245 */ + MIPS_SYS(sys_exit_group , 1) + MIPS_SYS(sys_lookup_dcookie, 3) + MIPS_SYS(sys_epoll_create, 1) + MIPS_SYS(sys_epoll_ctl , 4) + MIPS_SYS(sys_epoll_wait , 3) /* 4250 */ + MIPS_SYS(sys_remap_file_pages, 5) + MIPS_SYS(sys_set_tid_address, 1) + MIPS_SYS(sys_restart_syscall, 0) + MIPS_SYS(sys_fadvise64_64, 7) + MIPS_SYS(sys_statfs64 , 3) /* 4255 */ + MIPS_SYS(sys_fstatfs64 , 2) + MIPS_SYS(sys_timer_create, 3) + MIPS_SYS(sys_timer_settime, 4) + MIPS_SYS(sys_timer_gettime, 2) + MIPS_SYS(sys_timer_getoverrun, 1) /* 4260 */ + MIPS_SYS(sys_timer_delete, 1) + MIPS_SYS(sys_clock_settime, 2) + MIPS_SYS(sys_clock_gettime, 2) + MIPS_SYS(sys_clock_getres, 2) + MIPS_SYS(sys_clock_nanosleep, 4) /* 4265 */ + MIPS_SYS(sys_tgkill , 3) + MIPS_SYS(sys_utimes , 2) + MIPS_SYS(sys_mbind , 4) + MIPS_SYS(sys_ni_syscall , 0) /* sys_get_mempolicy */ + MIPS_SYS(sys_ni_syscall , 0) /* 4270 sys_set_mempolicy */ + MIPS_SYS(sys_mq_open , 4) + MIPS_SYS(sys_mq_unlink , 1) + MIPS_SYS(sys_mq_timedsend, 5) + MIPS_SYS(sys_mq_timedreceive, 5) + MIPS_SYS(sys_mq_notify , 2) /* 4275 */ + MIPS_SYS(sys_mq_getsetattr, 3) + MIPS_SYS(sys_ni_syscall , 0) /* sys_vserver */ + MIPS_SYS(sys_waitid , 4) + MIPS_SYS(sys_ni_syscall , 0) /* available, was setaltroot */ + MIPS_SYS(sys_add_key , 5) + MIPS_SYS(sys_request_key , 4) + MIPS_SYS(sys_keyctl , 5) +}; + +#undef MIPS_SYS + +void cpu_loop(CPUMIPSState *env) +{ + target_siginfo_t info; + int trapnr, ret, nb_args; + unsigned int syscall_num; + target_ulong arg5, arg6, sp_reg; + + for(;;) { + trapnr = cpu_mips_exec(env); + switch(trapnr) { + case EXCP_SYSCALL: + { + syscall_num = env->gpr[2] - 4000; + if (syscall_num >= sizeof(mips_syscall_args)) { + ret = -ENOSYS; + } else { + nb_args = mips_syscall_args[syscall_num]; + if (nb_args >= 5) { + sp_reg = env->gpr[29]; + /* these arguments are taken from the stack */ + if (get_user(arg5, (target_ulong *)(sp_reg + 16))) { + ret = -EFAULT; + goto fail; + } + if (nb_args >= 6) { + if (get_user(arg6, (target_ulong *)(sp_reg + 20))) { + ret = -EFAULT; + goto fail; + } + } else { + arg6 = 0; + } + } else { + arg5 = 0; + arg6 = 0; + } + ret = do_syscall(env, + env->gpr[2], + env->gpr[4], + env->gpr[5], + env->gpr[6], + env->gpr[7], + arg5, + arg6); + } + fail: + env->PC += 4; + if ((unsigned int)ret >= (unsigned int)(-1133)) { + env->gpr[7] = 1; /* error flag */ + ret = -ret; + env->gpr[0] = ret; + env->gpr[2] = ret; + } else { + env->gpr[7] = 0; /* error flag */ + env->gpr[2] = ret; + } + } + break; + case EXCP_RI: + { + uint32_t insn, op; + + if (get_user(insn, (uint32_t *)env->PC) < 0) + goto sigill; + op = insn >> 26; + // printf("insn=%08x op=%02x\n", insn, op); + /* XXX: totally dummy FP ops just to be able to launch + a few executables */ + switch(op) { + case 0x31: /* LWC1 */ + env->PC += 4; + break; + case 0x39: /* SWC1 */ + env->PC += 4; + break; + case 0x11: + switch((insn >> 21) & 0x1f) { + case 0x02: /* CFC1 */ + env->PC += 4; + break; + default: + goto sigill; + } + break; + default: + sigill: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = 0; + queue_signal(info.si_signo, &info); + break; + } + } + break; + default: + // error: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); + } + process_pending_signals(env); + } +} +#endif + void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n" @@ -1245,6 +1643,15 @@ int main(int argc, char **argv) env->gpr[i] = regs->gpr[i]; } } +#elif defined(TARGET_MIPS) + { + int i; + + for(i = 0; i < 32; i++) { + env->gpr[i] = regs->regs[i]; + } + env->PC = regs->cp0_epc; + } #else #error unsupported target CPU #endif diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h new file mode 100644 index 000000000..4b3c7d625 --- /dev/null +++ b/linux-user/mips/syscall.h @@ -0,0 +1,23 @@ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { +#if 1 + /* Pad bytes for argument save space on the stack. */ + target_ulong pad0[6]; +#endif + + /* Saved main processor registers. */ + target_ulong regs[32]; + + /* Saved special registers. */ + target_ulong cp0_status; + target_ulong lo; + target_ulong hi; + target_ulong cp0_badvaddr; + target_ulong cp0_cause; + target_ulong cp0_epc; +}; + +#define UNAME_MACHINE "mips" diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h new file mode 100644 index 000000000..e635aa281 --- /dev/null +++ b/linux-user/mips/syscall_nr.h @@ -0,0 +1,288 @@ +/* + * Linux o32 style syscalls are in the range from 4000 to 4999. + */ +#define TARGET_NR_Linux 4000 +#define TARGET_NR_syscall (TARGET_NR_Linux + 0) +#define TARGET_NR_exit (TARGET_NR_Linux + 1) +#define TARGET_NR_fork (TARGET_NR_Linux + 2) +#define TARGET_NR_read (TARGET_NR_Linux + 3) +#define TARGET_NR_write (TARGET_NR_Linux + 4) +#define TARGET_NR_open (TARGET_NR_Linux + 5) +#define TARGET_NR_close (TARGET_NR_Linux + 6) +#define TARGET_NR_waitpid (TARGET_NR_Linux + 7) +#define TARGET_NR_creat (TARGET_NR_Linux + 8) +#define TARGET_NR_link (TARGET_NR_Linux + 9) +#define TARGET_NR_unlink (TARGET_NR_Linux + 10) +#define TARGET_NR_execve (TARGET_NR_Linux + 11) +#define TARGET_NR_chdir (TARGET_NR_Linux + 12) +#define TARGET_NR_time (TARGET_NR_Linux + 13) +#define TARGET_NR_mknod (TARGET_NR_Linux + 14) +#define TARGET_NR_chmod (TARGET_NR_Linux + 15) +#define TARGET_NR_lchown (TARGET_NR_Linux + 16) +#define TARGET_NR_break (TARGET_NR_Linux + 17) +#define TARGET_NR_unused18 (TARGET_NR_Linux + 18) +#define TARGET_NR_lseek (TARGET_NR_Linux + 19) +#define TARGET_NR_getpid (TARGET_NR_Linux + 20) +#define TARGET_NR_mount (TARGET_NR_Linux + 21) +#define TARGET_NR_umount (TARGET_NR_Linux + 22) +#define TARGET_NR_setuid (TARGET_NR_Linux + 23) +#define TARGET_NR_getuid (TARGET_NR_Linux + 24) +#define TARGET_NR_stime (TARGET_NR_Linux + 25) +#define TARGET_NR_ptrace (TARGET_NR_Linux + 26) +#define TARGET_NR_alarm (TARGET_NR_Linux + 27) +#define TARGET_NR_unused28 (TARGET_NR_Linux + 28) +#define TARGET_NR_pause (TARGET_NR_Linux + 29) +#define TARGET_NR_utime (TARGET_NR_Linux + 30) +#define TARGET_NR_stty (TARGET_NR_Linux + 31) +#define TARGET_NR_gtty (TARGET_NR_Linux + 32) +#define TARGET_NR_access (TARGET_NR_Linux + 33) +#define TARGET_NR_nice (TARGET_NR_Linux + 34) +#define TARGET_NR_ftime (TARGET_NR_Linux + 35) +#define TARGET_NR_sync (TARGET_NR_Linux + 36) +#define TARGET_NR_kill (TARGET_NR_Linux + 37) +#define TARGET_NR_rename (TARGET_NR_Linux + 38) +#define TARGET_NR_mkdir (TARGET_NR_Linux + 39) +#define TARGET_NR_rmdir (TARGET_NR_Linux + 40) +#define TARGET_NR_dup (TARGET_NR_Linux + 41) +#define TARGET_NR_pipe (TARGET_NR_Linux + 42) +#define TARGET_NR_times (TARGET_NR_Linux + 43) +#define TARGET_NR_prof (TARGET_NR_Linux + 44) +#define TARGET_NR_brk (TARGET_NR_Linux + 45) +#define TARGET_NR_setgid (TARGET_NR_Linux + 46) +#define TARGET_NR_getgid (TARGET_NR_Linux + 47) +#define TARGET_NR_signal (TARGET_NR_Linux + 48) +#define TARGET_NR_geteuid (TARGET_NR_Linux + 49) +#define TARGET_NR_getegid (TARGET_NR_Linux + 50) +#define TARGET_NR_acct (TARGET_NR_Linux + 51) +#define TARGET_NR_umount2 (TARGET_NR_Linux + 52) +#define TARGET_NR_lock (TARGET_NR_Linux + 53) +#define TARGET_NR_ioctl (TARGET_NR_Linux + 54) +#define TARGET_NR_fcntl (TARGET_NR_Linux + 55) +#define TARGET_NR_mpx (TARGET_NR_Linux + 56) +#define TARGET_NR_setpgid (TARGET_NR_Linux + 57) +#define TARGET_NR_ulimit (TARGET_NR_Linux + 58) +#define TARGET_NR_unused59 (TARGET_NR_Linux + 59) +#define TARGET_NR_umask (TARGET_NR_Linux + 60) +#define TARGET_NR_chroot (TARGET_NR_Linux + 61) +#define TARGET_NR_ustat (TARGET_NR_Linux + 62) +#define TARGET_NR_dup2 (TARGET_NR_Linux + 63) +#define TARGET_NR_getppid (TARGET_NR_Linux + 64) +#define TARGET_NR_getpgrp (TARGET_NR_Linux + 65) +#define TARGET_NR_setsid (TARGET_NR_Linux + 66) +#define TARGET_NR_sigaction (TARGET_NR_Linux + 67) +#define TARGET_NR_sgetmask (TARGET_NR_Linux + 68) +#define TARGET_NR_ssetmask (TARGET_NR_Linux + 69) +#define TARGET_NR_setreuid (TARGET_NR_Linux + 70) +#define TARGET_NR_setregid (TARGET_NR_Linux + 71) +#define TARGET_NR_sigsuspend (TARGET_NR_Linux + 72) +#define TARGET_NR_sigpending (TARGET_NR_Linux + 73) +#define TARGET_NR_sethostname (TARGET_NR_Linux + 74) +#define TARGET_NR_setrlimit (TARGET_NR_Linux + 75) +#define TARGET_NR_getrlimit (TARGET_NR_Linux + 76) +#define TARGET_NR_getrusage (TARGET_NR_Linux + 77) +#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 78) +#define TARGET_NR_settimeofday (TARGET_NR_Linux + 79) +#define TARGET_NR_getgroups (TARGET_NR_Linux + 80) +#define TARGET_NR_setgroups (TARGET_NR_Linux + 81) +#define TARGET_NR_reserved82 (TARGET_NR_Linux + 82) +#define TARGET_NR_symlink (TARGET_NR_Linux + 83) +#define TARGET_NR_unused84 (TARGET_NR_Linux + 84) +#define TARGET_NR_readlink (TARGET_NR_Linux + 85) +#define TARGET_NR_uselib (TARGET_NR_Linux + 86) +#define TARGET_NR_swapon (TARGET_NR_Linux + 87) +#define TARGET_NR_reboot (TARGET_NR_Linux + 88) +#define TARGET_NR_readdir (TARGET_NR_Linux + 89) +#define TARGET_NR_mmap (TARGET_NR_Linux + 90) +#define TARGET_NR_munmap (TARGET_NR_Linux + 91) +#define TARGET_NR_truncate (TARGET_NR_Linux + 92) +#define TARGET_NR_ftruncate (TARGET_NR_Linux + 93) +#define TARGET_NR_fchmod (TARGET_NR_Linux + 94) +#define TARGET_NR_fchown (TARGET_NR_Linux + 95) +#define TARGET_NR_getpriority (TARGET_NR_Linux + 96) +#define TARGET_NR_setpriority (TARGET_NR_Linux + 97) +#define TARGET_NR_profil (TARGET_NR_Linux + 98) +#define TARGET_NR_statfs (TARGET_NR_Linux + 99) +#define TARGET_NR_fstatfs (TARGET_NR_Linux + 100) +#define TARGET_NR_ioperm (TARGET_NR_Linux + 101) +#define TARGET_NR_socketcall (TARGET_NR_Linux + 102) +#define TARGET_NR_syslog (TARGET_NR_Linux + 103) +#define TARGET_NR_setitimer (TARGET_NR_Linux + 104) +#define TARGET_NR_getitimer (TARGET_NR_Linux + 105) +#define TARGET_NR_stat (TARGET_NR_Linux + 106) +#define TARGET_NR_lstat (TARGET_NR_Linux + 107) +#define TARGET_NR_fstat (TARGET_NR_Linux + 108) +#define TARGET_NR_unused109 (TARGET_NR_Linux + 109) +#define TARGET_NR_iopl (TARGET_NR_Linux + 110) +#define TARGET_NR_vhangup (TARGET_NR_Linux + 111) +#define TARGET_NR_idle (TARGET_NR_Linux + 112) +#define TARGET_NR_vm86 (TARGET_NR_Linux + 113) +#define TARGET_NR_wait4 (TARGET_NR_Linux + 114) +#define TARGET_NR_swapoff (TARGET_NR_Linux + 115) +#define TARGET_NR_sysinfo (TARGET_NR_Linux + 116) +#define TARGET_NR_ipc (TARGET_NR_Linux + 117) +#define TARGET_NR_fsync (TARGET_NR_Linux + 118) +#define TARGET_NR_sigreturn (TARGET_NR_Linux + 119) +#define TARGET_NR_clone (TARGET_NR_Linux + 120) +#define TARGET_NR_setdomainname (TARGET_NR_Linux + 121) +#define TARGET_NR_uname (TARGET_NR_Linux + 122) +#define TARGET_NR_modify_ldt (TARGET_NR_Linux + 123) +#define TARGET_NR_adjtimex (TARGET_NR_Linux + 124) +#define TARGET_NR_mprotect (TARGET_NR_Linux + 125) +#define TARGET_NR_sigprocmask (TARGET_NR_Linux + 126) +#define TARGET_NR_create_module (TARGET_NR_Linux + 127) +#define TARGET_NR_init_module (TARGET_NR_Linux + 128) +#define TARGET_NR_delete_module (TARGET_NR_Linux + 129) +#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 130) +#define TARGET_NR_quotactl (TARGET_NR_Linux + 131) +#define TARGET_NR_getpgid (TARGET_NR_Linux + 132) +#define TARGET_NR_fchdir (TARGET_NR_Linux + 133) +#define TARGET_NR_bdflush (TARGET_NR_Linux + 134) +#define TARGET_NR_sysfs (TARGET_NR_Linux + 135) +#define TARGET_NR_personality (TARGET_NR_Linux + 136) +#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 137) /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid (TARGET_NR_Linux + 138) +#define TARGET_NR_setfsgid (TARGET_NR_Linux + 139) +#define TARGET_NR__llseek (TARGET_NR_Linux + 140) +#define TARGET_NR_getdents (TARGET_NR_Linux + 141) +#define TARGET_NR__newselect (TARGET_NR_Linux + 142) +#define TARGET_NR_flock (TARGET_NR_Linux + 143) +#define TARGET_NR_msync (TARGET_NR_Linux + 144) +#define TARGET_NR_readv (TARGET_NR_Linux + 145) +#define TARGET_NR_writev (TARGET_NR_Linux + 146) +#define TARGET_NR_cacheflush (TARGET_NR_Linux + 147) +#define TARGET_NR_cachectl (TARGET_NR_Linux + 148) +#define TARGET_NR_sysmips (TARGET_NR_Linux + 149) +#define TARGET_NR_unused150 (TARGET_NR_Linux + 150) +#define TARGET_NR_getsid (TARGET_NR_Linux + 151) +#define TARGET_NR_fdatasync (TARGET_NR_Linux + 152) +#define TARGET_NR__sysctl (TARGET_NR_Linux + 153) +#define TARGET_NR_mlock (TARGET_NR_Linux + 154) +#define TARGET_NR_munlock (TARGET_NR_Linux + 155) +#define TARGET_NR_mlockall (TARGET_NR_Linux + 156) +#define TARGET_NR_munlockall (TARGET_NR_Linux + 157) +#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 158) +#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 159) +#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 160) +#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 161) +#define TARGET_NR_sched_yield (TARGET_NR_Linux + 162) +#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 163) +#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 164) +#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 165) +#define TARGET_NR_nanosleep (TARGET_NR_Linux + 166) +#define TARGET_NR_mremap (TARGET_NR_Linux + 167) +#define TARGET_NR_accept (TARGET_NR_Linux + 168) +#define TARGET_NR_bind (TARGET_NR_Linux + 169) +#define TARGET_NR_connect (TARGET_NR_Linux + 170) +#define TARGET_NR_getpeername (TARGET_NR_Linux + 171) +#define TARGET_NR_getsockname (TARGET_NR_Linux + 172) +#define TARGET_NR_getsockopt (TARGET_NR_Linux + 173) +#define TARGET_NR_listen (TARGET_NR_Linux + 174) +#define TARGET_NR_recv (TARGET_NR_Linux + 175) +#define TARGET_NR_recvfrom (TARGET_NR_Linux + 176) +#define TARGET_NR_recvmsg (TARGET_NR_Linux + 177) +#define TARGET_NR_send (TARGET_NR_Linux + 178) +#define TARGET_NR_sendmsg (TARGET_NR_Linux + 179) +#define TARGET_NR_sendto (TARGET_NR_Linux + 180) +#define TARGET_NR_setsockopt (TARGET_NR_Linux + 181) +#define TARGET_NR_shutdown (TARGET_NR_Linux + 182) +#define TARGET_NR_socket (TARGET_NR_Linux + 183) +#define TARGET_NR_socketpair (TARGET_NR_Linux + 184) +#define TARGET_NR_setresuid (TARGET_NR_Linux + 185) +#define TARGET_NR_getresuid (TARGET_NR_Linux + 186) +#define TARGET_NR_query_module (TARGET_NR_Linux + 187) +#define TARGET_NR_poll (TARGET_NR_Linux + 188) +#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 189) +#define TARGET_NR_setresgid (TARGET_NR_Linux + 190) +#define TARGET_NR_getresgid (TARGET_NR_Linux + 191) +#define TARGET_NR_prctl (TARGET_NR_Linux + 192) +#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 193) +#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 194) +#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 195) +#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 196) +#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 197) +#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 198) +#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 199) +#define TARGET_NR_pread64 (TARGET_NR_Linux + 200) +#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 201) +#define TARGET_NR_chown (TARGET_NR_Linux + 202) +#define TARGET_NR_getcwd (TARGET_NR_Linux + 203) +#define TARGET_NR_capget (TARGET_NR_Linux + 204) +#define TARGET_NR_capset (TARGET_NR_Linux + 205) +#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 206) +#define TARGET_NR_sendfile (TARGET_NR_Linux + 207) +#define TARGET_NR_getpmsg (TARGET_NR_Linux + 208) +#define TARGET_NR_putpmsg (TARGET_NR_Linux + 209) +#define TARGET_NR_mmap2 (TARGET_NR_Linux + 210) +#define TARGET_NR_truncate64 (TARGET_NR_Linux + 211) +#define TARGET_NR_ftruncate64 (TARGET_NR_Linux + 212) +#define TARGET_NR_stat64 (TARGET_NR_Linux + 213) +#define TARGET_NR_lstat64 (TARGET_NR_Linux + 214) +#define TARGET_NR_fstat64 (TARGET_NR_Linux + 215) +#define TARGET_NR_pivot_root (TARGET_NR_Linux + 216) +#define TARGET_NR_mincore (TARGET_NR_Linux + 217) +#define TARGET_NR_madvise (TARGET_NR_Linux + 218) +#define TARGET_NR_getdents64 (TARGET_NR_Linux + 219) +#define TARGET_NR_fcntl64 (TARGET_NR_Linux + 220) +#define TARGET_NR_reserved221 (TARGET_NR_Linux + 221) +#define TARGET_NR_gettid (TARGET_NR_Linux + 222) +#define TARGET_NR_readahead (TARGET_NR_Linux + 223) +#define TARGET_NR_setxattr (TARGET_NR_Linux + 224) +#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 225) +#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 226) +#define TARGET_NR_getxattr (TARGET_NR_Linux + 227) +#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 228) +#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 229) +#define TARGET_NR_listxattr (TARGET_NR_Linux + 230) +#define TARGET_NR_llistxattr (TARGET_NR_Linux + 231) +#define TARGET_NR_flistxattr (TARGET_NR_Linux + 232) +#define TARGET_NR_removexattr (TARGET_NR_Linux + 233) +#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 234) +#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 235) +#define TARGET_NR_tkill (TARGET_NR_Linux + 236) +#define TARGET_NR_sendfile64 (TARGET_NR_Linux + 237) +#define TARGET_NR_futex (TARGET_NR_Linux + 238) +#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 239) +#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 240) +#define TARGET_NR_io_setup (TARGET_NR_Linux + 241) +#define TARGET_NR_io_destroy (TARGET_NR_Linux + 242) +#define TARGET_NR_io_getevents (TARGET_NR_Linux + 243) +#define TARGET_NR_io_submit (TARGET_NR_Linux + 244) +#define TARGET_NR_io_cancel (TARGET_NR_Linux + 245) +#define TARGET_NR_exit_group (TARGET_NR_Linux + 246) +#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 247) +#define TARGET_NR_epoll_create (TARGET_NR_Linux + 248) +#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 249) +#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 250) +#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 251) +#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 252) +#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 253) +#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 254) +#define TARGET_NR_statfs64 (TARGET_NR_Linux + 255) +#define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 256) +#define TARGET_NR_timer_create (TARGET_NR_Linux + 257) +#define TARGET_NR_timer_settime (TARGET_NR_Linux + 258) +#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 259) +#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 260) +#define TARGET_NR_timer_delete (TARGET_NR_Linux + 261) +#define TARGET_NR_clock_settime (TARGET_NR_Linux + 262) +#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 263) +#define TARGET_NR_clock_getres (TARGET_NR_Linux + 264) +#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 265) +#define TARGET_NR_tgkill (TARGET_NR_Linux + 266) +#define TARGET_NR_utimes (TARGET_NR_Linux + 267) +#define TARGET_NR_mbind (TARGET_NR_Linux + 268) +#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 269) +#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 270) +#define TARGET_NR_mq_open (TARGET_NR_Linux + 271) +#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 272) +#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 273) +#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 274) +#define TARGET_NR_mq_notify (TARGET_NR_Linux + 275) +#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 276) +#define TARGET_NR_vserver (TARGET_NR_Linux + 277) +#define TARGET_NR_waitid (TARGET_NR_Linux + 278) +/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 279) */ +#define TARGET_NR_add_key (TARGET_NR_Linux + 280) +#define TARGET_NR_request_key (TARGET_NR_Linux + 281) +#define TARGET_NR_keyctl (TARGET_NR_Linux + 282) + diff --git a/linux-user/mips/termbits.h b/linux-user/mips/termbits.h new file mode 100644 index 000000000..7f428997c --- /dev/null +++ b/linux-user/mips/termbits.h @@ -0,0 +1,214 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 23 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e51f51353..f5b7f8e68 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1497,6 +1497,8 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) new_env->regs[0] = 0; #elif defined(TARGET_SPARC) printf ("HELPME: %s:%d\n", __FILE__, __LINE__); +#elif defined(TARGET_MIPS) + printf ("HELPME: %s:%d\n", __FILE__, __LINE__); #elif defined(TARGET_PPC) if (!newsp) newsp = env->gpr[1]; @@ -2184,6 +2186,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(settimeofday(&tv, NULL)); } break; +#ifdef TARGET_NR_select case TARGET_NR_select: { struct target_sel_arg_struct *sel = (void *)arg1; @@ -2196,6 +2199,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, (void *)sel->exp, (void *)sel->tvp); } break; +#endif case TARGET_NR_symlink: ret = get_errno(symlink((const char *)arg1, (const char *)arg2)); break; @@ -2802,9 +2806,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_putpmsg: goto unimplemented; #endif +#ifdef TARGET_NR_vfork case TARGET_NR_vfork: ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); break; +#endif #ifdef TARGET_NR_ugetrlimit case TARGET_NR_ugetrlimit: { diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index ae212ec32..ac12b52ee 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -57,7 +57,8 @@ #define TARGET_IOC_WRITE 1U #define TARGET_IOC_READ 2U -#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_SPARC) +#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \ + defined(TARGET_SPARC) || defined(TARGET_MIPS) #define TARGET_IOC_SIZEBITS 13 #define TARGET_IOC_DIRBITS 3 @@ -292,9 +293,26 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) -#if !defined(TARGET_SPARC) +#if defined(TARGET_SPARC) +#define TARGET_SA_NOCLDSTOP 8u +#define TARGET_SA_NOCLDWAIT 0x100u +#define TARGET_SA_SIGINFO 0x200u +#define TARGET_SA_ONSTACK 1u +#define TARGET_SA_RESTART 2u +#define TARGET_SA_NODEFER 0x20u +#define TARGET_SA_RESETHAND 4u +#elif defined(TARGET_MIPS) +#define TARGET_SA_NOCLDSTOP 0x00000001 +#define TARGET_SA_NOCLDWAIT 0x00010000 +#define TARGET_SA_SIGINFO 0x00000008 +#define TARGET_SA_ONSTACK 0x08000000 +#define TARGET_SA_NODEFER 0x40000000 +#define TARGET_SA_RESTART 0x10000000 +#define TARGET_SA_RESETHAND 0x80000000 +#define TARGET_SA_RESTORER 0x04000000 /* Only for o32 */ +#else #define TARGET_SA_NOCLDSTOP 0x00000001 #define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ #define TARGET_SA_SIGINFO 0x00000004 @@ -303,14 +321,6 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SA_NODEFER 0x40000000 #define TARGET_SA_RESETHAND 0x80000000 #define TARGET_SA_RESTORER 0x04000000 -#else /* TARGET_SPARC */ -#define TARGET_SA_NOCLDSTOP 8u -#define TARGET_SA_NOCLDWAIT 0x100u -#define TARGET_SA_SIGINFO 0x200u -#define TARGET_SA_ONSTACK 1u -#define TARGET_SA_RESTART 2u -#define TARGET_SA_NODEFER 0x20u -#define TARGET_SA_RESETHAND 4u #endif #if defined(TARGET_SPARC) @@ -353,6 +363,49 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SIG_UNBLOCK 0x02 /* for unblocking signals */ #define TARGET_SIG_SETMASK 0x04 /* for setting the signal mask */ +#elif defined(TARGET_MIPS) + +#define TARGET_SIGHUP 1 /* Hangup (POSIX). */ +#define TARGET_SIGINT 2 /* Interrupt (ANSI). */ +#define TARGET_SIGQUIT 3 /* Quit (POSIX). */ +#define TARGET_SIGILL 4 /* Illegal instruction (ANSI). */ +#define TARGET_SIGTRAP 5 /* Trace trap (POSIX). */ +#define TARGET_SIGIOT 6 /* IOT trap (4.2 BSD). */ +#define TARGET_SIGABRT TARGET_SIGIOT /* Abort (ANSI). */ +#define TARGET_SIGEMT 7 +#define TARGET_SIGSTKFLT 7 /* XXX: incorrect */ +#define TARGET_SIGFPE 8 /* Floating-point exception (ANSI). */ +#define TARGET_SIGKILL 9 /* Kill, unblockable (POSIX). */ +#define TARGET_SIGBUS 10 /* BUS error (4.2 BSD). */ +#define TARGET_SIGSEGV 11 /* Segmentation violation (ANSI). */ +#define TARGET_SIGSYS 12 +#define TARGET_SIGPIPE 13 /* Broken pipe (POSIX). */ +#define TARGET_SIGALRM 14 /* Alarm clock (POSIX). */ +#define TARGET_SIGTERM 15 /* Termination (ANSI). */ +#define TARGET_SIGUSR1 16 /* User-defined signal 1 (POSIX). */ +#define TARGET_SIGUSR2 17 /* User-defined signal 2 (POSIX). */ +#define TARGET_SIGCHLD 18 /* Child status has changed (POSIX). */ +#define TARGET_SIGCLD TARGET_SIGCHLD /* Same as TARGET_SIGCHLD (System V). */ +#define TARGET_SIGPWR 19 /* Power failure restart (System V). */ +#define TARGET_SIGWINCH 20 /* Window size change (4.3 BSD, Sun). */ +#define TARGET_SIGURG 21 /* Urgent condition on socket (4.2 BSD). */ +#define TARGET_SIGIO 22 /* I/O now possible (4.2 BSD). */ +#define TARGET_SIGPOLL TARGET_SIGIO /* Pollable event occurred (System V). */ +#define TARGET_SIGSTOP 23 /* Stop, unblockable (POSIX). */ +#define TARGET_SIGTSTP 24 /* Keyboard stop (POSIX). */ +#define TARGET_SIGCONT 25 /* Continue (POSIX). */ +#define TARGET_SIGTTIN 26 /* Background read from tty (POSIX). */ +#define TARGET_SIGTTOU 27 /* Background write to tty (POSIX). */ +#define TARGET_SIGVTALRM 28 /* Virtual alarm clock (4.2 BSD). */ +#define TARGET_SIGPROF 29 /* Profiling alarm clock (4.2 BSD). */ +#define TARGET_SIGXCPU 30 /* CPU limit exceeded (4.2 BSD). */ +#define TARGET_SIGXFSZ 31 /* File size limit exceeded (4.2 BSD). */ +#define TARGET_SIGRTMIN 32 + +#define TARGET_SIG_BLOCK 1 /* for blocking signals */ +#define TARGET_SIG_UNBLOCK 2 /* for unblocking signals */ +#define TARGET_SIG_SETMASK 3 /* for setting the signal mask */ + #else #define TARGET_SIGHUP 1 @@ -794,13 +847,21 @@ struct target_winsize { #define TARGET_MAP_PRIVATE 0x02 /* Changes are private */ #define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */ #define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ +#if defined(TARGET_MIPS) +#define TARGET_MAP_ANONYMOUS 0x0800 /* don't use a file */ +#define TARGET_MAP_GROWSDOWN 0x1000 /* stack-like segment */ +#define TARGET_MAP_DENYWRITE 0x2000 /* ETXTBSY */ +#define TARGET_MAP_EXECUTABLE 0x4000 /* mark it as an executable */ +#define TARGET_MAP_LOCKED 0x8000 /* pages are locked */ +#define TARGET_MAP_NORESERVE 0x0400 /* don't check for reservations */ +#else #define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ - #define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ #define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ +#endif #if defined(TARGET_I386) || defined(TARGET_ARM) struct target_stat { @@ -967,7 +1028,79 @@ struct target_stat64 { target_ulong __unused5; }; -#endif /* defined(TARGET_PPC) */ +#elif defined(TARGET_MIPS) + +struct target_stat { + unsigned st_dev; + target_long st_pad1[3]; /* Reserved for network id */ + target_ulong st_ino; + unsigned int st_mode; + unsigned int st_nlink; + int st_uid; + int st_gid; + unsigned st_rdev; + target_long st_pad2[2]; + target_long st_size; + target_long st_pad3; + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + target_long target_st_atime; + target_long target_st_atime_nsec; + target_long target_st_mtime; + target_long target_st_mtime_nsec; + target_long target_st_ctime; + target_long target_st_ctime_nsec; + target_long st_blksize; + target_long st_blocks; + target_long st_pad4[14]; +}; + +/* + * This matches struct stat64 in glibc2.1, hence the absolutely insane + * amounts of padding around dev_t's. The memory layout is the same as of + * struct stat of the 64-bit kernel. + */ + +struct target_stat64 { + target_ulong st_dev; + target_ulong st_pad0[3]; /* Reserved for st_dev expansion */ + + uint64_t st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + int st_uid; + int st_gid; + + target_ulong st_rdev; + target_ulong st_pad1[3]; /* Reserved for st_rdev expansion */ + + int64_t st_size; + + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + target_long target_st_atime; + target_ulong target_st_atime_nsec; /* Reserved for st_atime expansion */ + + target_long target_st_mtime; + target_ulong target_st_mtime_nsec; /* Reserved for st_mtime expansion */ + + target_long target_st_ctime; + target_ulong target_st_ctime_nsec; /* Reserved for st_ctime expansion */ + + target_ulong st_blksize; + target_ulong st_pad2; + + int64_t st_blocks; +}; +#else +#error unsupported CPU +#endif #define TARGET_F_DUPFD 0 /* dup */ #define TARGET_F_GETFD 1 /* get close_on_exec */ @@ -1007,7 +1140,7 @@ struct target_stat64 { #define TARGET_O_TRUNC 01000 /* not fcntl */ #define TARGET_O_APPEND 02000 #define TARGET_O_NONBLOCK 04000 -#define TARGET_O_NDELAY O_NONBLOCK +#define TARGET_O_NDELAY TARGET_O_NONBLOCK #define TARGET_O_SYNC 010000 #define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ #define TARGET_O_DIRECTORY 040000 /* must be a directory */ @@ -1025,7 +1158,7 @@ struct target_stat64 { #define TARGET_O_TRUNC 01000 /* not fcntl */ #define TARGET_O_APPEND 02000 #define TARGET_O_NONBLOCK 04000 -#define TARGET_O_NDELAY O_NONBLOCK +#define TARGET_O_NDELAY TARGET_O_NONBLOCK #define TARGET_O_SYNC 010000 #define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ #define TARGET_O_DIRECTORY 040000 /* must be a directory */ @@ -1044,12 +1177,31 @@ struct target_stat64 { #define TARGET_O_EXCL 0x0800 /* not fcntl */ #define TARGET_O_SYNC 0x2000 #define TARGET_O_NONBLOCK 0x4000 -#define TARGET_O_NDELAY (0x0004 | O_NONBLOCK) +#define TARGET_O_NDELAY (0x0004 | TARGET_O_NONBLOCK) #define TARGET_O_NOCTTY 0x8000 /* not fcntl */ #define TARGET_O_DIRECTORY 0x10000 /* must be a directory */ #define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */ #define TARGET_O_LARGEFILE 0x40000 #define TARGET_O_DIRECT 0x100000 /* direct disk access hint */ +#elif defined(TARGET_MIPS) +#define TARGET_O_ACCMODE 0x0003 +#define TARGET_O_RDONLY 0x0000 +#define TARGET_O_WRONLY 0x0001 +#define TARGET_O_RDWR 0x0002 +#define TARGET_O_APPEND 0x0008 +#define TARGET_O_SYNC 0x0010 +#define TARGET_O_NONBLOCK 0x0080 +#define TARGET_O_CREAT 0x0100 /* not fcntl */ +#define TARGET_O_TRUNC 0x0200 /* not fcntl */ +#define TARGET_O_EXCL 0x0400 /* not fcntl */ +#define TARGET_O_NOCTTY 0x0800 /* not fcntl */ +#define TARGET_FASYNC 0x1000 /* fcntl, for BSD compatibility */ +#define TARGET_O_LARGEFILE 0x2000 /* allow large file opens */ +#define TARGET_O_DIRECT 0x8000 /* direct disk access hint */ +#define TARGET_O_DIRECTORY 0x10000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */ +#define TARGET_O_NOATIME 0x40000 +#define TARGET_O_NDELAY TARGET_O_NONBLOCK #else #define TARGET_O_ACCMODE 0003 #define TARGET_O_RDONLY 00 @@ -1061,7 +1213,7 @@ struct target_stat64 { #define TARGET_O_TRUNC 01000 /* not fcntl */ #define TARGET_O_APPEND 02000 #define TARGET_O_NONBLOCK 04000 -#define TARGET_O_NDELAY O_NONBLOCK +#define TARGET_O_NDELAY TARGET_O_NONBLOCK #define TARGET_O_SYNC 010000 #define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ #define TARGET_O_DIRECT 040000 /* direct disk access hint */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index b8397be29..cb4789cfa 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -114,6 +114,37 @@ void do_msubu (void) } #endif +#if defined(CONFIG_USER_ONLY) +void do_mfc0 (int reg, int sel) +{ + cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel); +} +void do_mtc0 (int reg, int sel) +{ + cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel); +} + +void do_tlbwi (void) +{ + cpu_abort(env, "tlbwi\n"); +} + +void do_tlbwr (void) +{ + cpu_abort(env, "tlbwr\n"); +} + +void do_tlbp (void) +{ + cpu_abort(env, "tlbp\n"); +} + +void do_tlbr (void) +{ + cpu_abort(env, "tlbr\n"); +} +#else + /* CP0 helpers */ void do_mfc0 (int reg, int sel) { @@ -580,6 +611,8 @@ void do_tlbr (void) } #endif +#endif /* !CONFIG_USER_ONLY */ + void op_dump_ldst (const unsigned char *func) { if (loglevel) -- cgit v1.2.3 From 4a38940da0c0376ed29252757f3b2fa26944cd47 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 20:10:07 +0000 Subject: using _exit in fork() (Kamo Hiroyasu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1669 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 4f19dd0f0..06d41c15c 100644 --- a/vl.c +++ b/vl.c @@ -2099,7 +2099,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, *parg++ = ifname; *parg++ = NULL; execv(setup_script, args); - exit(1); + _exit(1); } while (waitpid(pid, &status, 0) != pid); if (!WIFEXITED(status) || -- cgit v1.2.3 From 6f5a9f7e56ab8dfeacca9ac779c0661261642873 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 20:12:28 +0000 Subject: fixed async signal support for tb_phys_invalidate() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1670 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/exec.c b/exec.c index b9009a1e9..70ad14dc1 100644 --- a/exec.c +++ b/exec.c @@ -672,12 +672,19 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, #endif } #endif /* TARGET_HAS_PRECISE_SMC */ - saved_tb = env->current_tb; - env->current_tb = NULL; + /* we need to do that to handle the case where a signal + occurs while doing tb_phys_invalidate() */ + saved_tb = NULL; + if (env) { + saved_tb = env->current_tb; + env->current_tb = NULL; + } tb_phys_invalidate(tb, -1); - env->current_tb = saved_tb; - if (env->interrupt_request && env->current_tb) - cpu_interrupt(env, env->interrupt_request); + if (env) { + env->current_tb = saved_tb; + if (env->interrupt_request && env->current_tb) + cpu_interrupt(env, env->interrupt_request); + } } tb = tb_next; } -- cgit v1.2.3 From 50443c98e4149e8cde3b371f9ed60d943d95d286 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Nov 2005 20:15:14 +0000 Subject: specialize the power save code for 7x0 CPUs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1671 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 ++-- monitor.c | 2 +- target-ppc/cpu.h | 2 ++ target-ppc/helper.c | 15 ++++++++++++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 5c85c1e9d..89bf8b85e 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -265,11 +265,11 @@ int cpu_exec(CPUState *env1) } } #elif defined(TARGET_PPC) - if (env1->msr[MSR_POW]) { + if (env1->halted) { if (env1->msr[MSR_EE] && (env1->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) { - env1->msr[MSR_POW] = 0; + env1->halted = 0; } else { return EXCP_HALTED; } diff --git a/monitor.c b/monitor.c index 70b473ddb..2f0e84d86 100644 --- a/monitor.c +++ b/monitor.c @@ -257,7 +257,7 @@ static void do_info_cpus(void) term_printf(" (halted)"); #elif defined(TARGET_PPC) term_printf(" nip=0x" TARGET_FMT_lx, env->nip); - if (msr_pow) + if (env->halted) term_printf(" (halted)"); #endif term_printf("\n"); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index fa7f524e9..88d91358e 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -495,6 +495,8 @@ struct CPUPPCState { CPU_COMMON + int halted; /* TRUE if the CPU is in suspend state */ + int access_type; /* when a memory exception occurs, the access type is stored here */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index ff1355c54..3f7a70871 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -807,6 +807,8 @@ void do_compute_hflags (CPUPPCState *env) void do_store_msr (CPUPPCState *env, target_ulong value) { + int enter_pm; + value &= env->msr_mask; if (((value >> MSR_IR) & 1) != msr_ir || ((value >> MSR_DR) & 1) != msr_dr) { @@ -846,8 +848,19 @@ void do_store_msr (CPUPPCState *env, target_ulong value) msr_ri = (value >> MSR_RI) & 1; msr_le = (value >> MSR_LE) & 1; do_compute_hflags(env); - if (msr_pow) { + + enter_pm = 0; + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_7x0: + if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0) + enter_pm = 1; + break; + default: + break; + } + if (enter_pm) { /* power save: exit cpu loop */ + env->halted = 1; env->exception_index = EXCP_HLT; cpu_loop_exit(); } -- cgit v1.2.3 From 7664728bdf58f008b2e807d5d271820a8532065f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 27 Nov 2005 19:10:42 +0000 Subject: win32 compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1672 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vl.c b/vl.c index 06d41c15c..aa28032b4 100644 --- a/vl.c +++ b/vl.c @@ -1613,13 +1613,13 @@ CharDriverState *qemu_chr_open(const char *filename) return text_console_init(&display_state); } else if (!strcmp(filename, "null")) { return qemu_chr_open_null(); - } else if (strstart(filename, "file:", &p)) { + } else +#ifndef _WIN32 + if (strstart(filename, "file:", &p)) { return qemu_chr_open_file_out(p); } else if (strstart(filename, "pipe:", &p)) { return qemu_chr_open_pipe(p); - } else -#ifndef _WIN32 - if (!strcmp(filename, "pty")) { + } else if (!strcmp(filename, "pty")) { return qemu_chr_open_pty(); } else if (!strcmp(filename, "stdio")) { return qemu_chr_open_stdio(); -- cgit v1.2.3 From 649ea05a2ca8f940e6e179490b67c217016124e2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 21:01:52 +0000 Subject: x86_64 lcall fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1673 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index e2f6fba2e..6939cb76c 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1732,11 +1732,11 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) /* protected mode call */ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) { - int new_cs, new_eip, new_stack, i; + int new_cs, new_stack, i; uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; uint32_t val, limit, old_sp_mask; - target_ulong ssp, old_ssp, next_eip; + target_ulong ssp, old_ssp, next_eip, new_eip; new_cs = T0; new_eip = T1; @@ -1744,7 +1744,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_PCALL) { fprintf(logfile, "lcall %04x:%08x s=%d\n", - new_cs, new_eip, shift); + new_cs, (uint32_t)new_eip, shift); cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); } #endif -- cgit v1.2.3 From 5732fd277903a026af79b75b5e7b19f66c5cb447 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 21:02:17 +0000 Subject: x86_64 ldl fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1674 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_mem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h index 0002f0dea..7ec84dde8 100644 --- a/target-i386/ops_mem.h +++ b/target-i386/ops_mem.h @@ -45,7 +45,7 @@ void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void) void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void) { - T1 = glue(ldl, MEMSUFFIX)(A0); + T1 = (uint32_t)glue(ldl, MEMSUFFIX)(A0); } void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void) -- cgit v1.2.3 From 5cf3839607a6883a16fe65124d2f8f244de0f8ac Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 21:02:43 +0000 Subject: nx defines git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1675 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 068ebcddb..450dd8cbe 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -189,6 +189,7 @@ #define PG_DIRTY_BIT 6 #define PG_PSE_BIT 7 #define PG_GLOBAL_BIT 8 +#define PG_NX_BIT 63 #define PG_PRESENT_MASK (1 << PG_PRESENT_BIT) #define PG_RW_MASK (1 << PG_RW_BIT) @@ -199,6 +200,7 @@ #define PG_DIRTY_MASK (1 << PG_DIRTY_BIT) #define PG_PSE_MASK (1 << PG_PSE_BIT) #define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT) +#define PG_NX_MASK (1LL << PG_NX_BIT) #define PG_ERROR_W_BIT 1 @@ -206,6 +208,7 @@ #define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT) #define PG_ERROR_U_MASK 0x04 #define PG_ERROR_RSVD_MASK 0x08 +#define PG_ERROR_I_D_MASK 0x10 #define MSR_IA32_APICBASE 0x1b #define MSR_IA32_APICBASE_BSP (1<<8) -- cgit v1.2.3 From 84b7b8e778937f1ec3cbdb8914261a2fe0067ef2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 21:19:04 +0000 Subject: PAGE_EXEC support in TLBs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1676 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 10 ++-- exec-all.h | 20 +++++--- exec.c | 142 +++++++++++++++++++++++++++++++++-------------------- softmmu_header.h | 54 +++++++++++++------- softmmu_template.h | 19 ++++--- 5 files changed, 155 insertions(+), 90 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index e095f8566..665158a38 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -80,7 +80,8 @@ typedef unsigned long ram_addr_t; #define TB_JMP_CACHE_BITS 12 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) -#define CPU_TLB_SIZE 256 +#define CPU_TLB_BITS 8 +#define CPU_TLB_SIZE (1 << CPU_TLB_BITS) typedef struct CPUTLBEntry { /* bit 31 to TARGET_PAGE_BITS : virtual address @@ -89,7 +90,9 @@ typedef struct CPUTLBEntry { bit 3 : indicates that the entry is invalid bit 2..0 : zero */ - target_ulong address; + 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; @@ -105,8 +108,7 @@ typedef struct CPUTLBEntry { target_ulong mem_write_vaddr; /* target virtual addr at which the \ memory was written */ \ /* 0 = kernel, 1 = user */ \ - CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; \ - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; \ + CPUTLBEntry tlb_table[2][CPU_TLB_SIZE]; \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ \ /* from this point: preserved by CPU reset */ \ diff --git a/exec-all.h b/exec-all.h index 9034ce869..08351354e 100644 --- a/exec-all.h +++ b/exec-all.h @@ -98,9 +98,17 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, void tb_invalidate_page_range(target_ulong start, target_ulong end); void tlb_flush_page(CPUState *env, target_ulong addr); void tlb_flush(CPUState *env, int flush_global); -int tlb_set_page(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu); +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int is_user, int is_softmmu); +static inline int tlb_set_page(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int is_user, int is_softmmu) +{ + if (prot & PAGE_READ) + prot |= PAGE_EXEC; + return tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); +} #define CODE_GEN_MAX_SIZE 65536 #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ @@ -554,15 +562,15 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) #else #error unimplemented CPU #endif - if (__builtin_expect(env->tlb_read[is_user][index].address != + if (__builtin_expect(env->tlb_table[is_user][index].addr_code != (addr & TARGET_PAGE_MASK), 0)) { ldub_code(addr); } - pd = env->tlb_read[is_user][index].address & ~TARGET_PAGE_MASK; + pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; if (pd > IO_MEM_ROM) { cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr); } - return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; + return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; } #endif diff --git a/exec.c b/exec.c index 70ad14dc1..3028a524e 100644 --- a/exec.c +++ b/exec.c @@ -1209,10 +1209,12 @@ void tlb_flush(CPUState *env, int flush_global) env->current_tb = NULL; for(i = 0; i < CPU_TLB_SIZE; i++) { - env->tlb_read[0][i].address = -1; - env->tlb_write[0][i].address = -1; - env->tlb_read[1][i].address = -1; - env->tlb_write[1][i].address = -1; + env->tlb_table[0][i].addr_read = -1; + env->tlb_table[0][i].addr_write = -1; + env->tlb_table[0][i].addr_code = -1; + env->tlb_table[1][i].addr_read = -1; + env->tlb_table[1][i].addr_write = -1; + env->tlb_table[1][i].addr_code = -1; } memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); @@ -1230,9 +1232,16 @@ void tlb_flush(CPUState *env, int flush_global) static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) { - if (addr == (tlb_entry->address & - (TARGET_PAGE_MASK | TLB_INVALID_MASK))) - tlb_entry->address = -1; + if (addr == (tlb_entry->addr_read & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || + addr == (tlb_entry->addr_write & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || + addr == (tlb_entry->addr_code & + (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + tlb_entry->addr_read = -1; + tlb_entry->addr_write = -1; + tlb_entry->addr_code = -1; + } } void tlb_flush_page(CPUState *env, target_ulong addr) @@ -1249,10 +1258,8 @@ void tlb_flush_page(CPUState *env, target_ulong addr) addr &= TARGET_PAGE_MASK; i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_flush_entry(&env->tlb_read[0][i], addr); - tlb_flush_entry(&env->tlb_write[0][i], addr); - tlb_flush_entry(&env->tlb_read[1][i], addr); - tlb_flush_entry(&env->tlb_write[1][i], addr); + tlb_flush_entry(&env->tlb_table[0][i], addr); + tlb_flush_entry(&env->tlb_table[1][i], addr); for(i = 0; i < TB_JMP_CACHE_SIZE; i++) { tb = env->tb_jmp_cache[i]; @@ -1295,10 +1302,10 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, unsigned long start, unsigned long length) { unsigned long addr; - if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { - addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend; + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; if ((addr - start) < length) { - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; + tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; } } } @@ -1340,9 +1347,9 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, start1 = start + (unsigned long)phys_ram_base; for(env = first_cpu; env != NULL; env = env->next_cpu) { for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length); + tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length); for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length); + tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length); } #if !defined(CONFIG_SOFTMMU) @@ -1378,11 +1385,11 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) { ram_addr_t ram_addr; - if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { - ram_addr = (tlb_entry->address & TARGET_PAGE_MASK) + + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend - (unsigned long)phys_ram_base; if (!cpu_physical_memory_is_dirty(ram_addr)) { - tlb_entry->address |= IO_MEM_NOTDIRTY; + tlb_entry->addr_write |= IO_MEM_NOTDIRTY; } } } @@ -1392,19 +1399,19 @@ void cpu_tlb_update_dirty(CPUState *env) { int i; for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_write[0][i]); + tlb_update_dirty(&env->tlb_table[0][i]); for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_write[1][i]); + tlb_update_dirty(&env->tlb_table[1][i]); } static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, unsigned long start) { unsigned long addr; - if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) { - addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend; + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) { + addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; if (addr == start) { - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM; + tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM; } } } @@ -1418,17 +1425,17 @@ static inline void tlb_set_dirty(CPUState *env, addr &= TARGET_PAGE_MASK; i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_set_dirty1(&env->tlb_write[0][i], addr); - tlb_set_dirty1(&env->tlb_write[1][i], addr); + tlb_set_dirty1(&env->tlb_table[0][i], addr); + tlb_set_dirty1(&env->tlb_table[1][i], addr); } /* add a new TLB entry. At most one entry for a given virtual address is permitted. Return 0 if OK or 2 if the page could not be mapped (can only happen in non SOFTMMU mode for I/O pages or pages conflicting with the host address space). */ -int tlb_set_page(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu) +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int is_user, int is_softmmu) { PhysPageDesc *p; unsigned long pd; @@ -1436,6 +1443,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, target_ulong address; target_phys_addr_t addend; int ret; + CPUTLBEntry *te; p = phys_page_find(paddr >> TARGET_PAGE_BITS); if (!p) { @@ -1445,7 +1453,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, } #if defined(DEBUG_TLB) printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n", - vaddr, paddr, prot, is_user, is_softmmu, pd); + vaddr, (int)paddr, prot, is_user, is_softmmu, pd); #endif ret = 0; @@ -1465,29 +1473,30 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); addend -= vaddr; + te = &env->tlb_table[is_user][index]; + te->addend = addend; if (prot & PAGE_READ) { - env->tlb_read[is_user][index].address = address; - env->tlb_read[is_user][index].addend = addend; + te->addr_read = address; + } else { + te->addr_read = -1; + } + if (prot & PAGE_EXEC) { + te->addr_code = address; } else { - env->tlb_read[is_user][index].address = -1; - env->tlb_read[is_user][index].addend = -1; + te->addr_code = -1; } if (prot & PAGE_WRITE) { if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { /* ROM: access is ignored (same as unassigned) */ - env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM; - env->tlb_write[is_user][index].addend = addend; + te->addr_write = vaddr | IO_MEM_ROM; } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd)) { - env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY; - env->tlb_write[is_user][index].addend = addend; + te->addr_write = vaddr | IO_MEM_NOTDIRTY; } else { - env->tlb_write[is_user][index].address = address; - env->tlb_write[is_user][index].addend = addend; + te->addr_write = address; } } else { - env->tlb_write[is_user][index].address = -1; - env->tlb_write[is_user][index].addend = -1; + te->addr_write = -1; } } #if !defined(CONFIG_SOFTMMU) @@ -1586,9 +1595,9 @@ void tlb_flush_page(CPUState *env, target_ulong addr) { } -int tlb_set_page(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu) +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int is_user, int is_softmmu) { return 0; } @@ -2052,6 +2061,41 @@ uint32_t ldl_phys(target_phys_addr_t addr) return val; } +/* warning: addr must be aligned */ +uint64_t ldq_phys(target_phys_addr_t addr) +{ + int io_index; + uint8_t *ptr; + uint64_t val; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); +#ifdef TARGET_WORDS_BIGENDIAN + val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32; + val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4); +#else + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32; +#endif + } else { + /* RAM case */ + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + val = ldq_p(ptr); + } + return val; +} + /* XXX: optimize */ uint32_t ldub_phys(target_phys_addr_t addr) { @@ -2068,14 +2112,6 @@ uint32_t lduw_phys(target_phys_addr_t addr) return tswap16(val); } -/* XXX: optimize */ -uint64_t ldq_phys(target_phys_addr_t addr) -{ - uint64_t val; - cpu_physical_memory_read(addr, (uint8_t *)&val, 8); - return tswap64(val); -} - /* warning: addr must be aligned. The ram page is not masked as dirty and the code inside is not invalidated. It is useful if the dirty bits are used to track modified PTEs */ diff --git a/softmmu_header.h b/softmmu_header.h index 9f36f890c..e79592f83 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -93,6 +93,11 @@ #define RES_TYPE int #endif +#if ACCESS_TYPE == 3 +#define ADDR_READ addr_code +#else +#define ADDR_READ addr_read +#endif DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user); @@ -101,6 +106,8 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE #if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \ (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) +#define CPU_TLB_ENTRY_BITS 4 + static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) { int res; @@ -120,7 +127,7 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) "movl %%eax, %0\n" "jmp 2f\n" "1:\n" - "addl 4(%%edx), %%eax\n" + "addl 12(%%edx), %%eax\n" #if DATA_SIZE == 1 "movzbl (%%eax), %0\n" #elif DATA_SIZE == 2 @@ -133,10 +140,10 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) "2:\n" : "=r" (res) : "r" (ptr), - "i" ((CPU_TLB_SIZE - 1) << 3), - "i" (TARGET_PAGE_BITS - 3), + "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_read[CPU_MEM_INDEX][0].address)), + "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)), "i" (CPU_MEM_INDEX), "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) : "%eax", "%ecx", "%edx", "memory", "cc"); @@ -169,7 +176,7 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) #endif "jmp 2f\n" "1:\n" - "addl 4(%%edx), %%eax\n" + "addl 12(%%edx), %%eax\n" #if DATA_SIZE == 1 "movsbl (%%eax), %0\n" #elif DATA_SIZE == 2 @@ -180,10 +187,10 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) "2:\n" : "=r" (res) : "r" (ptr), - "i" ((CPU_TLB_SIZE - 1) << 3), - "i" (TARGET_PAGE_BITS - 3), + "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_read[CPU_MEM_INDEX][0].address)), + "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)), "i" (CPU_MEM_INDEX), "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) : "%eax", "%ecx", "%edx", "memory", "cc"); @@ -216,7 +223,7 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE "popl %%eax\n" "jmp 2f\n" "1:\n" - "addl 4(%%edx), %%eax\n" + "addl 8(%%edx), %%eax\n" #if DATA_SIZE == 1 "movb %b1, (%%eax)\n" #elif DATA_SIZE == 2 @@ -232,10 +239,10 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE /* NOTE: 'q' would be needed as constraint, but we could not use it with T1 ! */ "r" (v), - "i" ((CPU_TLB_SIZE - 1) << 3), - "i" (TARGET_PAGE_BITS - 3), + "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_write[CPU_MEM_INDEX][0].address)), + "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)), "i" (CPU_MEM_INDEX), "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX)) : "%eax", "%ecx", "%edx", "memory", "cc"); @@ -256,11 +263,11 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_read[is_user][index].address != + if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user); } else { - physaddr = addr + env->tlb_read[is_user][index].addend; + physaddr = addr + env->tlb_table[is_user][index].addend; res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); } return res; @@ -277,17 +284,19 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_read[is_user][index].address != + if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user); } else { - physaddr = addr + env->tlb_read[is_user][index].addend; + physaddr = addr + env->tlb_table[is_user][index].addend; res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); } return res; } #endif +#if ACCESS_TYPE != 3 + /* generic store macro */ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) @@ -300,16 +309,20 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_write[is_user][index].address != + if (__builtin_expect(env->tlb_table[is_user][index].addr_write != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user); } else { - physaddr = addr + env->tlb_write[is_user][index].addend; + physaddr = addr + env->tlb_table[is_user][index].addend; glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); } } -#endif +#endif /* ACCESS_TYPE != 3 */ + +#endif /* !asm */ + +#if ACCESS_TYPE != 3 #if DATA_SIZE == 8 static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr) @@ -355,6 +368,8 @@ static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) } #endif /* DATA_SIZE == 4 */ +#endif /* ACCESS_TYPE != 3 */ + #undef RES_TYPE #undef DATA_TYPE #undef DATA_STYPE @@ -363,3 +378,4 @@ static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) #undef DATA_SIZE #undef CPU_MEM_INDEX #undef MMUSUFFIX +#undef ADDR_READ diff --git a/softmmu_template.h b/softmmu_template.h index a99bedf48..c14407d3f 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -41,8 +41,10 @@ #ifdef SOFTMMU_CODE_ACCESS #define READ_ACCESS_TYPE 2 +#define ADDR_READ addr_code #else #define READ_ACCESS_TYPE 0 +#define ADDR_READ addr_read #endif static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, @@ -83,9 +85,9 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, /* XXX: could done more in memory macro in a non portable way */ index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_read[is_user][index].address; + tlb_addr = env->tlb_table[is_user][index].ADDR_READ; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_read[is_user][index].addend; + physaddr = addr + env->tlb_table[is_user][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -122,9 +124,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_read[is_user][index].address; + tlb_addr = env->tlb_table[is_user][index].ADDR_READ; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_read[is_user][index].addend; + physaddr = addr + env->tlb_table[is_user][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -199,9 +201,9 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_write[is_user][index].address; + tlb_addr = env->tlb_table[is_user][index].addr_write; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_write[is_user][index].addend; + physaddr = addr + env->tlb_table[is_user][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -237,9 +239,9 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_write[is_user][index].address; + tlb_addr = env->tlb_table[is_user][index].addr_write; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_write[is_user][index].addend; + physaddr = addr + env->tlb_table[is_user][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -276,3 +278,4 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, #undef SUFFIX #undef USUFFIX #undef DATA_SIZE +#undef ADDR_READ -- cgit v1.2.3 From 4b4f782c78f49c78c912e1e44c6a63fb7bf9aab4 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 21:19:42 +0000 Subject: NX support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1677 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 160 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 120 insertions(+), 40 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 1bc806640..678c94168 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -127,7 +127,7 @@ CPUX86State *cpu_x86_init(void) /* currently not enabled for std i386 because not fully tested */ env->cpuid_features |= CPUID_APIC; env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF); - env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL; + env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX; env->cpuid_xlevel = 0x80000008; /* these features are needed for Win64 and aren't fully implemented */ @@ -576,6 +576,8 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) #else +#define PHYS_ADDR_MASK 0xfffff000 + /* return value: -1 = cannot handle fault 0 = nothing more to do @@ -583,37 +585,38 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) 2 = soft MMU activation required for this block */ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, - int is_write, int is_user, int is_softmmu) + int is_write1, int is_user, int is_softmmu) { + uint64_t ptep, pte; uint32_t pdpe_addr, pde_addr, pte_addr; - uint32_t pde, pte, ptep, pdpe; - int error_code, is_dirty, prot, page_size, ret; + int error_code, is_dirty, prot, page_size, ret, is_write; unsigned long paddr, page_offset; target_ulong vaddr, virt_addr; #if defined(DEBUG_MMU) printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", - addr, is_write, is_user, env->eip); + addr, is_write1, is_user, env->eip); #endif - is_write &= 1; + is_write = is_write1 & 1; if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr; virt_addr = addr & TARGET_PAGE_MASK; - prot = PAGE_READ | PAGE_WRITE; + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; page_size = 4096; goto do_mapping; } if (env->cr[4] & CR4_PAE_MASK) { + uint64_t pde, pdpe; + /* XXX: we only use 32 bit physical addresses */ #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - uint32_t pml4e_addr, pml4e; + uint32_t pml4e_addr; + uint64_t pml4e; int32_t sext; - /* XXX: handle user + rw rights */ - /* XXX: handle NX flag */ /* test virtual address sign extension */ sext = (int64_t)addr >> 47; if (sext != 0 && sext != -1) { @@ -623,61 +626,134 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; - pml4e = ldl_phys(pml4e_addr); + pml4e = ldq_phys(pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; } + if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) { + error_code = PG_ERROR_RSVD_MASK; + goto do_fault; + } if (!(pml4e & PG_ACCESSED_MASK)) { pml4e |= PG_ACCESSED_MASK; stl_phys_notdirty(pml4e_addr, pml4e); } - - pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & + ptep = pml4e ^ PG_NX_MASK; + pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; - pdpe = ldl_phys(pdpe_addr); + pdpe = ldq_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; } + if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) { + error_code = PG_ERROR_RSVD_MASK; + goto do_fault; + } + ptep &= pdpe ^ PG_NX_MASK; if (!(pdpe & PG_ACCESSED_MASK)) { pdpe |= PG_ACCESSED_MASK; stl_phys_notdirty(pdpe_addr, pdpe); } - } else + } else #endif { + /* XXX: load them when cr3 is loaded ? */ pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & env->a20_mask; - pdpe = ldl_phys(pdpe_addr); + pdpe = ldq_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; } + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; } - pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & + pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask; - pde = ldl_phys(pde_addr); + pde = ldq_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) { error_code = 0; goto do_fault; } + if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) { + error_code = PG_ERROR_RSVD_MASK; + goto do_fault; + } + ptep &= pde ^ PG_NX_MASK; if (pde & PG_PSE_MASK) { /* 2 MB page */ page_size = 2048 * 1024; - goto handle_big_page; + ptep ^= PG_NX_MASK; + if ((ptep & PG_NX_MASK) && is_write1 == 2) + goto do_fault_protect; + if (is_user) { + if (!(ptep & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pde & PG_DIRTY_MASK); + if (!(pde & PG_ACCESSED_MASK) || is_dirty) { + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_DIRTY_MASK; + stl_phys_notdirty(pde_addr, pde); + } + /* align to page_size */ + pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff); + virt_addr = addr & ~(page_size - 1); } else { /* 4 KB page */ if (!(pde & PG_ACCESSED_MASK)) { pde |= PG_ACCESSED_MASK; stl_phys_notdirty(pde_addr, pde); } - pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & + pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask; - goto handle_4k_page; + pte = ldq_phys(pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + error_code = 0; + goto do_fault; + } + if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) { + error_code = PG_ERROR_RSVD_MASK; + goto do_fault; + } + /* combine pde and pte nx, user and rw protections */ + ptep &= pte ^ PG_NX_MASK; + ptep ^= PG_NX_MASK; + if ((ptep & PG_NX_MASK) && is_write1 == 2) + goto do_fault_protect; + if (is_user) { + if (!(ptep & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(ptep & PG_RW_MASK)) + goto do_fault_protect; + } + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) + pte |= PG_DIRTY_MASK; + stl_phys_notdirty(pte_addr, pte); + } + page_size = 4096; + virt_addr = addr & ~0xfff; + pte = pte & (PHYS_ADDR_MASK | 0xfff); } } else { + uint32_t pde; + /* page directory entry */ pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask; @@ -689,7 +765,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, /* if PSE bit is set, then we use a 4MB page */ if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { page_size = 4096 * 1024; - handle_big_page: if (is_user) { if (!(pde & PG_USER_MASK)) goto do_fault_protect; @@ -720,7 +795,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, /* page directory entry */ pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; - handle_4k_page: pte = ldl_phys(pte_addr); if (!(pte & PG_PRESENT_MASK)) { error_code = 0; @@ -748,20 +822,21 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, page_size = 4096; virt_addr = addr & ~0xfff; } - - /* the page can be put in the TLB */ - prot = PAGE_READ; - if (pte & PG_DIRTY_MASK) { - /* only set write access if already dirty... otherwise wait - for dirty access */ - if (is_user) { - if (ptep & PG_RW_MASK) - prot |= PAGE_WRITE; - } else { - if (!(env->cr[0] & CR0_WP_MASK) || - (ptep & PG_RW_MASK)) - prot |= PAGE_WRITE; - } + } + /* the page can be put in the TLB */ + prot = PAGE_READ; + if (!(ptep & PG_NX_MASK)) + prot |= PAGE_EXEC; + if (pte & PG_DIRTY_MASK) { + /* only set write access if already dirty... otherwise wait + for dirty access */ + if (is_user) { + if (ptep & PG_RW_MASK) + prot |= PAGE_WRITE; + } else { + if (!(env->cr[0] & CR0_WP_MASK) || + (ptep & PG_RW_MASK)) + prot |= PAGE_WRITE; } } do_mapping: @@ -773,15 +848,20 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, paddr = (pte & TARGET_PAGE_MASK) + page_offset; vaddr = virt_addr + page_offset; - ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; do_fault_protect: error_code = PG_ERROR_P_MASK; do_fault: env->cr[2] = addr; - env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; + error_code |= (is_write << PG_ERROR_W_BIT); if (is_user) - env->error_code |= PG_ERROR_U_MASK; + error_code |= PG_ERROR_U_MASK; + if (is_write1 == 2 && + (env->efer & MSR_EFER_NXE) && + (env->cr[4] & CR4_PAE_MASK)) + error_code |= PG_ERROR_I_D_MASK; + env->error_code = error_code; return 1; } -- cgit v1.2.3 From 148f50581bc4686d16b9dd5d4536557aa7380b0f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 22:28:07 +0000 Subject: uid32 syscalls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1678 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mips/syscall_nr.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h index e635aa281..3593e65d0 100644 --- a/linux-user/mips/syscall_nr.h +++ b/linux-user/mips/syscall_nr.h @@ -18,15 +18,15 @@ #define TARGET_NR_time (TARGET_NR_Linux + 13) #define TARGET_NR_mknod (TARGET_NR_Linux + 14) #define TARGET_NR_chmod (TARGET_NR_Linux + 15) -#define TARGET_NR_lchown (TARGET_NR_Linux + 16) +#define TARGET_NR_lchown32 (TARGET_NR_Linux + 16) #define TARGET_NR_break (TARGET_NR_Linux + 17) #define TARGET_NR_unused18 (TARGET_NR_Linux + 18) #define TARGET_NR_lseek (TARGET_NR_Linux + 19) #define TARGET_NR_getpid (TARGET_NR_Linux + 20) #define TARGET_NR_mount (TARGET_NR_Linux + 21) #define TARGET_NR_umount (TARGET_NR_Linux + 22) -#define TARGET_NR_setuid (TARGET_NR_Linux + 23) -#define TARGET_NR_getuid (TARGET_NR_Linux + 24) +#define TARGET_NR_setuid32 (TARGET_NR_Linux + 23) +#define TARGET_NR_getuid32 (TARGET_NR_Linux + 24) #define TARGET_NR_stime (TARGET_NR_Linux + 25) #define TARGET_NR_ptrace (TARGET_NR_Linux + 26) #define TARGET_NR_alarm (TARGET_NR_Linux + 27) @@ -48,11 +48,11 @@ #define TARGET_NR_times (TARGET_NR_Linux + 43) #define TARGET_NR_prof (TARGET_NR_Linux + 44) #define TARGET_NR_brk (TARGET_NR_Linux + 45) -#define TARGET_NR_setgid (TARGET_NR_Linux + 46) -#define TARGET_NR_getgid (TARGET_NR_Linux + 47) +#define TARGET_NR_setgid32 (TARGET_NR_Linux + 46) +#define TARGET_NR_getgid32 (TARGET_NR_Linux + 47) #define TARGET_NR_signal (TARGET_NR_Linux + 48) -#define TARGET_NR_geteuid (TARGET_NR_Linux + 49) -#define TARGET_NR_getegid (TARGET_NR_Linux + 50) +#define TARGET_NR_geteuid32 (TARGET_NR_Linux + 49) +#define TARGET_NR_getegid32 (TARGET_NR_Linux + 50) #define TARGET_NR_acct (TARGET_NR_Linux + 51) #define TARGET_NR_umount2 (TARGET_NR_Linux + 52) #define TARGET_NR_lock (TARGET_NR_Linux + 53) @@ -72,8 +72,8 @@ #define TARGET_NR_sigaction (TARGET_NR_Linux + 67) #define TARGET_NR_sgetmask (TARGET_NR_Linux + 68) #define TARGET_NR_ssetmask (TARGET_NR_Linux + 69) -#define TARGET_NR_setreuid (TARGET_NR_Linux + 70) -#define TARGET_NR_setregid (TARGET_NR_Linux + 71) +#define TARGET_NR_setreuid32 (TARGET_NR_Linux + 70) +#define TARGET_NR_setregid32 (TARGET_NR_Linux + 71) #define TARGET_NR_sigsuspend (TARGET_NR_Linux + 72) #define TARGET_NR_sigpending (TARGET_NR_Linux + 73) #define TARGET_NR_sethostname (TARGET_NR_Linux + 74) @@ -82,8 +82,8 @@ #define TARGET_NR_getrusage (TARGET_NR_Linux + 77) #define TARGET_NR_gettimeofday (TARGET_NR_Linux + 78) #define TARGET_NR_settimeofday (TARGET_NR_Linux + 79) -#define TARGET_NR_getgroups (TARGET_NR_Linux + 80) -#define TARGET_NR_setgroups (TARGET_NR_Linux + 81) +#define TARGET_NR_getgroups32 (TARGET_NR_Linux + 80) +#define TARGET_NR_setgroups32 (TARGET_NR_Linux + 81) #define TARGET_NR_reserved82 (TARGET_NR_Linux + 82) #define TARGET_NR_symlink (TARGET_NR_Linux + 83) #define TARGET_NR_unused84 (TARGET_NR_Linux + 84) @@ -97,7 +97,7 @@ #define TARGET_NR_truncate (TARGET_NR_Linux + 92) #define TARGET_NR_ftruncate (TARGET_NR_Linux + 93) #define TARGET_NR_fchmod (TARGET_NR_Linux + 94) -#define TARGET_NR_fchown (TARGET_NR_Linux + 95) +#define TARGET_NR_fchown32 (TARGET_NR_Linux + 95) #define TARGET_NR_getpriority (TARGET_NR_Linux + 96) #define TARGET_NR_setpriority (TARGET_NR_Linux + 97) #define TARGET_NR_profil (TARGET_NR_Linux + 98) @@ -140,8 +140,8 @@ #define TARGET_NR_sysfs (TARGET_NR_Linux + 135) #define TARGET_NR_personality (TARGET_NR_Linux + 136) #define TARGET_NR_afs_syscall (TARGET_NR_Linux + 137) /* Syscall for Andrew File System */ -#define TARGET_NR_setfsuid (TARGET_NR_Linux + 138) -#define TARGET_NR_setfsgid (TARGET_NR_Linux + 139) +#define TARGET_NR_setfsuid32 (TARGET_NR_Linux + 138) +#define TARGET_NR_setfsgid32 (TARGET_NR_Linux + 139) #define TARGET_NR__llseek (TARGET_NR_Linux + 140) #define TARGET_NR_getdents (TARGET_NR_Linux + 141) #define TARGET_NR__newselect (TARGET_NR_Linux + 142) @@ -187,13 +187,13 @@ #define TARGET_NR_shutdown (TARGET_NR_Linux + 182) #define TARGET_NR_socket (TARGET_NR_Linux + 183) #define TARGET_NR_socketpair (TARGET_NR_Linux + 184) -#define TARGET_NR_setresuid (TARGET_NR_Linux + 185) -#define TARGET_NR_getresuid (TARGET_NR_Linux + 186) +#define TARGET_NR_setresuid32 (TARGET_NR_Linux + 185) +#define TARGET_NR_getresuid32 (TARGET_NR_Linux + 186) #define TARGET_NR_query_module (TARGET_NR_Linux + 187) #define TARGET_NR_poll (TARGET_NR_Linux + 188) #define TARGET_NR_nfsservctl (TARGET_NR_Linux + 189) -#define TARGET_NR_setresgid (TARGET_NR_Linux + 190) -#define TARGET_NR_getresgid (TARGET_NR_Linux + 191) +#define TARGET_NR_setresgid32 (TARGET_NR_Linux + 190) +#define TARGET_NR_getresgid32 (TARGET_NR_Linux + 191) #define TARGET_NR_prctl (TARGET_NR_Linux + 192) #define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 193) #define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 194) @@ -204,7 +204,7 @@ #define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 199) #define TARGET_NR_pread64 (TARGET_NR_Linux + 200) #define TARGET_NR_pwrite64 (TARGET_NR_Linux + 201) -#define TARGET_NR_chown (TARGET_NR_Linux + 202) +#define TARGET_NR_chown32 (TARGET_NR_Linux + 202) #define TARGET_NR_getcwd (TARGET_NR_Linux + 203) #define TARGET_NR_capget (TARGET_NR_Linux + 204) #define TARGET_NR_capset (TARGET_NR_Linux + 205) -- cgit v1.2.3 From c960bde13c2f9c807beb1c4e8c16cfde769e136a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 22:28:16 +0000 Subject: correct ioctls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1679 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mips/termbits.h | 153 +++++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 69 deletions(-) diff --git a/linux-user/mips/termbits.h b/linux-user/mips/termbits.h index 7f428997c..fea7940a4 100644 --- a/linux-user/mips/termbits.h +++ b/linux-user/mips/termbits.h @@ -137,78 +137,93 @@ struct target_termios { /* ioctls */ -#define TARGET_TCGETS 0x5401 -#define TARGET_TCSETS 0x5402 -#define TARGET_TCSETSW 0x5403 -#define TARGET_TCSETSF 0x5404 -#define TARGET_TCGETA 0x5405 -#define TARGET_TCSETA 0x5406 -#define TARGET_TCSETAW 0x5407 -#define TARGET_TCSETAF 0x5408 -#define TARGET_TCSBRK 0x5409 -#define TARGET_TCXONC 0x540A -#define TARGET_TCFLSH 0x540B - -#define TARGET_TIOCEXCL 0x540C -#define TARGET_TIOCNXCL 0x540D -#define TARGET_TIOCSCTTY 0x540E -#define TARGET_TIOCGPGRP 0x540F -#define TARGET_TIOCSPGRP 0x5410 -#define TARGET_TIOCOUTQ 0x5411 -#define TARGET_TIOCSTI 0x5412 -#define TARGET_TIOCGWINSZ 0x5413 -#define TARGET_TIOCSWINSZ 0x5414 -#define TARGET_TIOCMGET 0x5415 -#define TARGET_TIOCMBIS 0x5416 -#define TARGET_TIOCMBIC 0x5417 -#define TARGET_TIOCMSET 0x5418 -#define TARGET_TIOCGSOFTCAR 0x5419 -#define TARGET_TIOCSSOFTCAR 0x541A -#define TARGET_FIONREAD 0x541B +#define TARGET_TCGETA 0x5401 +#define TARGET_TCSETA 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ +#define TARGET_TCSETAW 0x5403 +#define TARGET_TCSETAF 0x5404 + +#define TARGET_TCSBRK 0x5405 +#define TARGET_TCXONC 0x5406 +#define TARGET_TCFLSH 0x5407 + +#define TARGET_TCGETS 0x540d +#define TARGET_TCSETS 0x540e +#define TARGET_TCSETSW 0x540f +#define TARGET_TCSETSF 0x5410 + +#define TARGET_TIOCEXCL 0x740d /* set exclusive use of tty */ +#define TARGET_TIOCNXCL 0x740e /* reset exclusive use of tty */ +#define TARGET_TIOCOUTQ 0x7472 /* output queue size */ +#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */ +#define TARGET_TIOCMGET 0x741d /* get all modem bits */ +#define TARGET_TIOCMBIS 0x741b /* bis modem bits */ +#define TARGET_TIOCMBIC 0x741c /* bic modem bits */ +#define TARGET_TIOCMSET 0x741a /* set all modem bits */ +#define TARGET_TIOCPKT 0x5470 /* pty: set/clear packet mode */ +#define TARGET_TIOCPKT_DATA 0x00 /* data packet */ +#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */ +#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */ +#define TARGET_TIOCPKT_STOP 0x04 /* stop output */ +#define TARGET_TIOCPKT_START 0x08 /* start output */ +#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ +#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ +/* #define TIOCPKT_IOCTL 0x40 state change of pty driver */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) /* set window size */ +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) /* get window size */ +#define TARGET_TIOCNOTTY 0x5471 /* void tty association */ +#define TARGET_TIOCSETD 0x7401 +#define TARGET_TIOCGETD 0x7400 + +#define TARGET_FIOCLEX 0x6601 +#define TARGET_FIONCLEX 0x6602 +#define TARGET_FIOASYNC 0x667d +#define TARGET_FIONBIO 0x667e +#define TARGET_FIOQSIZE 0x667f + +#define TARGET_TIOCGLTC 0x7474 /* get special local chars */ +#define TARGET_TIOCSLTC 0x7475 /* set special local chars */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */ +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */ +#define TARGET_TIOCCONS TARGET_IOW('t', 120, int) /* become virtual console */ + +#define TARGET_FIONREAD 0x467f #define TARGET_TIOCINQ TARGET_FIONREAD -#define TARGET_TIOCLINUX 0x541C -#define TARGET_TIOCCONS 0x541D -#define TARGET_TIOCGSERIAL 0x541E -#define TARGET_TIOCSSERIAL 0x541F -#define TARGET_TIOCPKT 0x5420 -#define TARGET_FIONBIO 0x5421 -#define TARGET_TIOCNOTTY 0x5422 -#define TARGET_TIOCSETD 0x5423 -#define TARGET_TIOCGETD 0x5424 -#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ + +#define TARGET_TIOCGETP 0x7408 +#define TARGET_TIOCSETP 0x7409 +#define TARGET_TIOCSETN 0x740a /* TIOCSETP wo flush */ + +/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct termios) set termios struct */ +/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct termios) drain output, set */ +/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct termios) drn out, fls in, set */ +/* #define TARGET_TIOCGETD TARGET_IOR('t', 26, int) get line discipline */ +/* #define TARGET_TIOCSETD TARGET_IOW('t', 27, int) set line discipline */ + /* 127-124 compat */ + #define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ #define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ -#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGSID 0x7416 /* Return the session ID of FD */ #define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ -#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ -#define TARGET_FIOCLEX 0x5451 -#define TARGET_FIOASYNC 0x5452 -#define TARGET_TIOCSERCONFIG 0x5453 -#define TARGET_TIOCSERGWILD 0x5454 -#define TARGET_TIOCSERSWILD 0x5455 -#define TARGET_TIOCGLCKTRMIOS 0x5456 -#define TARGET_TIOCSLCKTRMIOS 0x5457 -#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ - -#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ -#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ - -/* Used for packet mode */ -#define TARGET_TIOCPKT_DATA 0 -#define TARGET_TIOCPKT_FLUSHREAD 1 -#define TARGET_TIOCPKT_FLUSHWRITE 2 -#define TARGET_TIOCPKT_STOP 4 -#define TARGET_TIOCPKT_START 8 -#define TARGET_TIOCPKT_NOSTOP 16 -#define TARGET_TIOCPKT_DOSTOP 32 - -#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ - +/* I hope the range from 0x5480 on is free ... */ +#define TARGET_TIOCSCTTY 0x5480 /* become controlling tty */ +#define TARGET_TIOCGSOFTCAR 0x5481 +#define TARGET_TIOCSSOFTCAR 0x5482 +#define TARGET_TIOCLINUX 0x5483 +#define TARGET_TIOCGSERIAL 0x5484 +#define TARGET_TIOCSSERIAL 0x5485 +#define TARGET_TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSERCONFIG 0x5488 +#define TARGET_TIOCSERGWILD 0x5489 +#define TARGET_TIOCSERSWILD 0x548a +#define TARGET_TIOCGLCKTRMIOS 0x548b +#define TARGET_TIOCSLCKTRMIOS 0x548c +#define TARGET_TIOCSERGSTRUCT 0x548d /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x548e /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x5493 /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x5494 /* Set Hayes ESP configuration */ -- cgit v1.2.3 From 56c8f68f1d2e45ad740de8c01780c7a4830d2098 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 22:28:41 +0000 Subject: statfs fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1680 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 56 +++++++++++++++++++++++++++--------------- linux-user/syscall_defs.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 19 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f5b7f8e68..1f123b609 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include //#include @@ -202,8 +203,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __NR_sys_uname __NR_uname #define __NR_sys_getcwd1 __NR_getcwd -#define __NR_sys_statfs __NR_statfs -#define __NR_sys_fstatfs __NR_fstatfs #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo @@ -225,8 +224,6 @@ _syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); -_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf) -_syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf) _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) @@ -1659,7 +1656,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { long ret; struct stat st; - struct kernel_statfs *stfs; + struct statfs stfs; #ifdef DEBUG gemu_log("syscall %d", num); @@ -2298,26 +2295,47 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; #endif case TARGET_NR_statfs: - stfs = (void *)arg2; - ret = get_errno(sys_statfs(path((const char *)arg1), stfs)); + ret = get_errno(statfs(path((const char *)arg1), &stfs)); convert_statfs: if (!is_error(ret)) { - tswap32s(&stfs->f_type); - tswap32s(&stfs->f_bsize); - tswap32s(&stfs->f_blocks); - tswap32s(&stfs->f_bfree); - tswap32s(&stfs->f_bavail); - tswap32s(&stfs->f_files); - tswap32s(&stfs->f_ffree); - tswap32s(&stfs->f_fsid.val[0]); - tswap32s(&stfs->f_fsid.val[1]); - tswap32s(&stfs->f_namelen); + struct target_statfs *target_stfs = (void *)arg2; + + put_user(stfs.f_type, &target_stfs->f_type); + put_user(stfs.f_bsize, &target_stfs->f_bsize); + put_user(stfs.f_blocks, &target_stfs->f_blocks); + put_user(stfs.f_bfree, &target_stfs->f_bfree); + put_user(stfs.f_bavail, &target_stfs->f_bavail); + put_user(stfs.f_files, &target_stfs->f_files); + put_user(stfs.f_ffree, &target_stfs->f_ffree); + put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid); + put_user(stfs.f_namelen, &target_stfs->f_namelen); } break; case TARGET_NR_fstatfs: - stfs = (void *)arg2; - ret = get_errno(sys_fstatfs(arg1, stfs)); + ret = get_errno(fstatfs(arg1, &stfs)); goto convert_statfs; +#ifdef TARGET_NR_statfs64 + case TARGET_NR_statfs64: + ret = get_errno(statfs(path((const char *)arg1), &stfs)); + convert_statfs64: + if (!is_error(ret)) { + struct target_statfs64 *target_stfs = (void *)arg3; + + put_user(stfs.f_type, &target_stfs->f_type); + put_user(stfs.f_bsize, &target_stfs->f_bsize); + put_user(stfs.f_blocks, &target_stfs->f_blocks); + put_user(stfs.f_bfree, &target_stfs->f_bfree); + put_user(stfs.f_bavail, &target_stfs->f_bavail); + put_user(stfs.f_files, &target_stfs->f_files); + put_user(stfs.f_ffree, &target_stfs->f_ffree); + put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid); + put_user(stfs.f_namelen, &target_stfs->f_namelen); + } + break; + case TARGET_NR_fstatfs64: + ret = get_errno(fstatfs(arg1, &stfs)); + goto convert_statfs64; +#endif #ifdef TARGET_NR_ioperm case TARGET_NR_ioperm: goto unimplemented; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index ac12b52ee..68f7e7f01 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1102,6 +1102,68 @@ struct target_stat64 { #error unsupported CPU #endif +#ifdef TARGET_MIPS +struct target_statfs { + target_long f_type; + target_long f_bsize; + target_long f_frsize; /* Fragment size - unsupported */ + target_long f_blocks; + target_long f_bfree; + target_long f_files; + target_long f_ffree; + target_long f_bavail; + + /* Linux specials */ + int f_fsid; + target_long f_namelen; + target_long f_spare[6]; +}; + +struct target_statfs64 { + uint32_t f_type; + uint32_t f_bsize; + uint32_t f_frsize; /* Fragment size - unsupported */ + uint32_t __pad; + uint64_t f_blocks; + uint64_t f_bfree; + uint64_t f_files; + uint64_t f_ffree; + uint64_t f_bavail; + int f_fsid; + uint32_t f_namelen; + uint32_t f_spare[6]; +}; +#else +struct target_statfs { + uint32_t f_type; + uint32_t f_bsize; + uint32_t f_blocks; + uint32_t f_bfree; + uint32_t f_bavail; + uint32_t f_files; + uint32_t f_ffree; + int f_fsid; + uint32_t f_namelen; + uint32_t f_frsize; + uint32_t f_spare[5]; +}; + +struct target_statfs64 { + uint32_t f_type; + uint32_t f_bsize; + uint64_t f_blocks; + uint64_t f_bfree; + uint64_t f_bavail; + uint64_t f_files; + uint64_t f_ffree; + int f_fsid; + uint32_t f_namelen; + uint32_t f_frsize; + uint32_t f_spare[5]; +}; +#endif + + #define TARGET_F_DUPFD 0 /* dup */ #define TARGET_F_GETFD 1 /* get close_on_exec */ #define TARGET_F_SETFD 2 /* set/clear close_on_exec */ -- cgit v1.2.3 From 54ca9095f046dfa03c3d093cc55f6d76b61864e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Dec 2005 18:46:06 +0000 Subject: generate GPF if non canonical addresses git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1681 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- target-i386/helper.c | 4 ++-- target-i386/helper2.c | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 89bf8b85e..7c056d40b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -904,7 +904,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ sigprocmask(SIG_SETMASK, old_set, NULL); - raise_exception_err(EXCP0E_PAGE, env->error_code); + raise_exception_err(env->exception_index, env->error_code); } else { /* activate soft MMU for this block */ env->hflags |= HF_SOFTMMU_MASK; diff --git a/target-i386/helper.c b/target-i386/helper.c index 6939cb76c..5c1d6cd80 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3478,9 +3478,9 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) } } if (retaddr) - raise_exception_err(EXCP0E_PAGE, env->error_code); + raise_exception_err(env->exception_index, env->error_code); else - raise_exception_err_norestore(EXCP0E_PAGE, env->error_code); + raise_exception_err_norestore(env->exception_index, env->error_code); } env = saved_env; } diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 678c94168..cb896cb5e 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -566,6 +566,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, env->cr[2] = addr; env->error_code = (is_write << PG_ERROR_W_BIT); env->error_code |= PG_ERROR_U_MASK; + env->exception_index = EXCP0E_PAGE; return 1; } @@ -620,8 +621,9 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, /* test virtual address sign extension */ sext = (int64_t)addr >> 47; if (sext != 0 && sext != -1) { - error_code = 0; - goto do_fault; + env->error_code = 0; + env->exception_index = EXCP0D_GPF; + return 1; } pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & @@ -862,6 +864,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, (env->cr[4] & CR4_PAE_MASK)) error_code |= PG_ERROR_I_D_MASK; env->error_code = error_code; + env->exception_index = EXCP0E_PAGE; return 1; } -- cgit v1.2.3 From 80337b66a8e7a98963cb846f551d9ef533d7d489 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Dec 2005 18:54:21 +0000 Subject: NIC emulation for qemu arm-softmmu (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1682 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/integratorcp.c | 27 +-- hw/smc91c111.c | 680 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 3 + 4 files changed, 698 insertions(+), 14 deletions(-) create mode 100644 hw/smc91c111.c diff --git a/Makefile.target b/Makefile.target index dd33e790a..adc853713 100644 --- a/Makefile.target +++ b/Makefile.target @@ -325,7 +325,7 @@ VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o endif endif ifeq ($(TARGET_BASE_ARCH), arm) -VL_OBJS+= integratorcp.o ps2.o +VL_OBJS+= integratorcp.o ps2.o smc91c111.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 957a94389..1979c3943 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -305,8 +305,6 @@ typedef struct icp_pic_state int parent_irq; } icp_pic_state; -static void icp_pic_set_level(icp_pic_state *, int, int); - static void icp_pic_update(icp_pic_state *s) { CPUState *env; @@ -314,8 +312,8 @@ static void icp_pic_update(icp_pic_state *s) uint32_t flags; flags = (s->level & s->irq_enabled); - icp_pic_set_level((icp_pic_state *)s->parent, s->parent_irq, - flags != 0); + pic_set_irq_new(s->parent, s->parent_irq, + flags != 0); return; } /* Raise CPU interrupt. */ @@ -332,12 +330,13 @@ static void icp_pic_update(icp_pic_state *s) } } -static void icp_pic_set_level(icp_pic_state *s, int n, int level) +void pic_set_irq_new(void *opaque, int irq, int level) { + icp_pic_state *s = (icp_pic_state *)opaque; if (level) - s->level |= 1 << n; + s->level |= 1 << irq; else - s->level &= ~(1 << n); + s->level &= ~(1 << irq); icp_pic_update(s); } @@ -385,11 +384,11 @@ static void icp_pic_write(void *opaque, target_phys_addr_t offset, break; case 4: /* INT_SOFTSET */ if (value & 1) - icp_pic_set_level(s, 0, 1); + pic_set_irq_new(s, 0, 1); break; case 5: /* INT_SOFTCLR */ if (value & 1) - icp_pic_set_level(s, 0, 0); + pic_set_irq_new(s, 0, 0); break; case 10: /* FRQ_ENABLESET */ s->fiq_enabled |= value; @@ -513,9 +512,9 @@ static void icp_pit_update(icp_pit_state *s, int64_t now) /* Update interrupts. */ for (n = 0; n < 3; n++) { if (s->int_level[n] && (s->control[n] & 0x20)) { - icp_pic_set_level(s->pic, 5 + n, 1); + pic_set_irq_new(s->pic, 5 + n, 1); } else { - icp_pic_set_level(s->pic, 5 + n, 0); + pic_set_irq_new(s->pic, 5 + n, 0); } if (next - s->expires[n] < 0) next = s->expires[n]; @@ -731,7 +730,7 @@ static void pl011_update(pl011_state *s) uint32_t flags; flags = s->int_level & s->int_enabled; - icp_pic_set_level(s->pic, s->irq, flags != 0); + pic_set_irq_new(s->pic, s->irq, flags != 0); } static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) @@ -1020,7 +1019,7 @@ static void icp_kmi_update(void *opaque, int level) s->pending = level; raise = (s->pending && (s->cr & 0x10) != 0) || (s->cr & 0x08) != 0; - icp_pic_set_level(s->pic, s->irq, raise); + pic_set_irq_new(s->pic, s->irq, raise); } static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset) @@ -1196,6 +1195,8 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, icp_control_init(0xcb000000); icp_kmi_init(0x18000000, pic, 3, 0); icp_kmi_init(0x19000000, pic, 4, 1); + if (nd_table[0].vlan) + smc91c111_init(&nd_table[0], 0xc8000000, pic, 27); /* Load the kernel. */ if (!kernel_filename) { diff --git a/hw/smc91c111.c b/hw/smc91c111.c new file mode 100644 index 000000000..54433c432 --- /dev/null +++ b/hw/smc91c111.c @@ -0,0 +1,680 @@ +/* + * SMSC 91C111 Ethernet interface emulation + * + * Copyright (c) 2005 CodeSourcery, LLC. + * Written by Paul Brook + * + * This code is licenced under the GPL + */ + +#include "vl.h" +/* For crc32 */ +#include + +/* Number of 2k memory pages available. */ +#define NUM_PACKETS 4 + +typedef struct { + uint32_t base; + VLANClientState *vc; + uint16_t tcr; + uint16_t rcr; + uint16_t cr; + uint16_t ctr; + uint16_t gpr; + uint16_t ptr; + uint16_t ercv; + void *pic; + int irq; + int bank; + int packet_num; + int tx_alloc; + /* Bitmask of allocated packets. */ + int allocated; + int tx_fifo_len; + int tx_fifo[NUM_PACKETS]; + int rx_fifo_len; + int rx_fifo[NUM_PACKETS]; + /* Packet buffer memory. */ + uint8_t data[2048][NUM_PACKETS]; + uint8_t int_level; + uint8_t int_mask; + uint8_t macaddr[6]; +} smc91c111_state; + +#define RCR_SOFT_RST 0x8000 +#define RCR_STRIP_CRC 0x0200 +#define RCR_RXEN 0x0100 + +#define TCR_EPH_LOOP 0x2000 +#define TCR_NOCRC 0x0100 +#define TCR_PAD_EN 0x0080 +#define TCR_FORCOL 0x0004 +#define TCR_LOOP 0x0002 +#define TCR_TXEN 0x0001 + +#define INT_MD 0x80 +#define INT_ERCV 0x40 +#define INT_EPH 0x20 +#define INT_RX_OVRN 0x10 +#define INT_ALLOC 0x08 +#define INT_TX_EMPTY 0x04 +#define INT_TX 0x02 +#define INT_RCV 0x01 + +#define CTR_AUTO_RELEASE 0x0800 +#define CTR_RELOAD 0x0002 +#define CTR_STORE 0x0001 + +#define RS_ALGNERR 0x8000 +#define RS_BRODCAST 0x4000 +#define RS_BADCRC 0x2000 +#define RS_ODDFRAME 0x1000 +#define RS_TOOLONG 0x0800 +#define RS_TOOSHORT 0x0400 +#define RS_MULTICAST 0x0001 + +/* Update interrupt status. */ +static void smc91c111_update(smc91c111_state *s) +{ + int level; + + if (s->tx_fifo_len == 0) + s->int_level |= INT_TX_EMPTY; + level = (s->int_level & s->int_mask) != 0; + pic_set_irq_new(s->pic, s->irq, level); +} + +/* Try to allocate a packet. Returns 0x80 on failure. */ +static int smc91c111_allocate_packet(smc91c111_state *s) +{ + int i; + if (s->allocated == (1 << NUM_PACKETS) - 1) { + return 0x80; + } + + for (i = 0; i < NUM_PACKETS; i++) { + if ((s->allocated & (1 << i)) == 0) + break; + } + s->allocated |= 1 << i; + return i; +} + + +/* Process a pending TX allocate. */ +static void smc91c111_tx_alloc(smc91c111_state *s) +{ + s->tx_alloc = smc91c111_allocate_packet(s); + if (s->tx_alloc == 0x80) + return; + s->int_level |= INT_ALLOC; + smc91c111_update(s); +} + +/* Remove and item from the RX FIFO. */ +static void smc91c111_pop_rx_fifo(smc91c111_state *s) +{ + int i; + + s->rx_fifo_len--; + if (s->rx_fifo_len) { + for (i = 0; i < s->rx_fifo_len; i++) + s->rx_fifo[i] = s->rx_fifo[i + 1]; + s->int_level |= INT_RCV; + } else { + s->int_level &= ~INT_RCV; + } + smc91c111_update(s); +} + +/* Release the memory allocated to a packet. */ +static void smc91c111_release_packet(smc91c111_state *s, int packet) +{ + s->allocated &= ~(1 << packet); + if (s->tx_alloc == 0x80) + smc91c111_tx_alloc(s); +} + +/* Flush the TX FIFO. */ +static void smc91c111_do_tx(smc91c111_state *s) +{ + int i; + int len; + int control; + int add_crc; + uint32_t crc; + int packetnum; + uint8_t *p; + + if ((s->tcr & TCR_TXEN) == 0) + return; + if (s->tx_fifo_len == 0) + return; + for (i = 0; i < s->tx_fifo_len; i++) { + packetnum = s->tx_fifo[i]; + p = &s->data[packetnum][0]; + /* Set status word. */ + *(p++) = 0x01; + *(p++) = 0x40; + len = *(p++); + len |= ((int)*(p++)) << 8; + len -= 6; + control = p[len + 1]; + if (control & 0x20) + len++; + /* ??? This overwrites the data following the buffer. + Don't know what real hardware does. */ + if (len < 64 && (s->tcr & TCR_PAD_EN)) { + memset(p + len, 0, 64 - len); + len = 64; + } +#if 0 + /* The card is supposed to append the CRC to the frame. However + none of the other network traffic has the CRC appended. + Suspect this is low level ethernet detail we don't need to worry + about. */ + add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0; + if (add_crc) { + crc = crc32(~0, p, len); + memcpy(p + len, &crc, 4); + len += 4; + } +#else + add_crc = 0; +#endif + if (s->ctr & CTR_AUTO_RELEASE) + smc91c111_release_packet(s, packetnum); + qemu_send_packet(s->vc, p, len); + } + s->tx_fifo_len = 0; + if ((s->ctr & CTR_AUTO_RELEASE) == 0) + s->int_level |= INT_TX; + smc91c111_update(s); +} + +/* Add a packet to the TX FIFO. */ +static void smc91c111_queue_tx(smc91c111_state *s, int packet) +{ + if (s->tx_fifo_len == NUM_PACKETS) + return; + s->tx_fifo[s->tx_fifo_len++] = packet; + smc91c111_do_tx(s); +} + +static void smc91c111_reset(smc91c111_state *s) +{ + s->bank = 0; + s->tx_fifo_len = 0; + s->rx_fifo_len = 0; + s->allocated = 0; + s->packet_num = 0; + s->tx_alloc = 0; + s->tcr = 0; + s->rcr = 0; + s->cr = 0xa0b1; + s->ctr = 0x1210; + s->ptr = 0; + s->ercv = 0x1f; + s->int_level = INT_TX_EMPTY; + s->int_mask = 0; + smc91c111_update(s); +} + +#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val +#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8) + +static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + smc91c111_state *s = (smc91c111_state *)opaque; + + offset -= s->base; + if (offset == 14) { + s->bank = value; + return; + } + if (offset == 15) + return; + switch (s->bank) { + case 0: + switch (offset) { + case 0: /* TCR */ + SET_LOW(tcr, value); + return; + case 1: + SET_HIGH(tcr, value); + return; + case 4: /* RCR */ + SET_LOW(rcr, value); + return; + case 5: + SET_HIGH(rcr, value); + if (s->rcr & RCR_SOFT_RST) + smc91c111_reset(s); + return; + case 10: case 11: /* RPCR */ + /* Ignored */ + return; + } + break; + + case 1: + switch (offset) { + case 0: /* CONFIG */ + SET_LOW(cr, value); + return; + case 1: + SET_HIGH(cr,value); + return; + case 2: case 3: /* BASE */ + case 4: case 5: case 6: case 7: case 8: case 9: /* IA */ + /* Not implemented. */ + return; + case 10: /* Genral Purpose */ + SET_LOW(gpr, value); + return; + case 11: + SET_HIGH(gpr, value); + return; + case 12: /* Control */ + if (value & 1) + fprintf(stderr, "smc91c111:EEPROM store not implemented\n"); + if (value & 2) + fprintf(stderr, "smc91c111:EEPROM reload not implemented\n"); + value &= ~3; + SET_LOW(ctr, value); + return; + case 13: + SET_HIGH(ctr, value); + return; + } + break; + + case 2: + switch (offset) { + case 0: /* MMU Command */ + switch (value >> 5) { + case 0: /* no-op */ + break; + case 1: /* Allocate for TX. */ + s->tx_alloc = 0x80; + s->int_level &= ~INT_ALLOC; + smc91c111_update(s); + smc91c111_tx_alloc(s); + break; + case 2: /* Reset MMU. */ + s->allocated = 0; + s->tx_fifo_len = 0; + s->rx_fifo_len = 0; + s->tx_alloc = 0; + break; + case 3: /* Remove from RX FIFO. */ + smc91c111_pop_rx_fifo(s); + break; + case 4: /* Remove from RX FIFO and release. */ + if (s->rx_fifo_len > 0) { + smc91c111_release_packet(s, s->rx_fifo[0]); + } + smc91c111_pop_rx_fifo(s); + break; + case 5: /* Release. */ + smc91c111_release_packet(s, s->packet_num); + break; + case 6: /* Add to TX FIFO. */ + smc91c111_queue_tx(s, s->packet_num); + break; + case 7: /* Reset TX FIFO. */ + s->tx_fifo_len = 0; + break; + } + return; + case 1: + /* Ignore. */ + return; + case 2: /* Packet Number Register */ + s->packet_num = value; + return; + case 3: case 4: case 5: + /* Should be readonly, but linux writes to them anyway. Ignore. */ + return; + case 6: /* Pointer */ + SET_LOW(ptr, value); + return; + case 7: + SET_HIGH(ptr, value); + return; + case 8: case 9: case 10: case 11: /* Data */ + { + int p; + int n; + + if (s->ptr & 0x8000) + n = s->rx_fifo[0]; + else + n = s->packet_num; + p = s->ptr & 0x07ff; + if (s->ptr & 0x4000) { + s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff); + } else { + p += (offset & 3); + } + s->data[n][p] = value; + } + return; + case 12: /* Interrupt ACK. */ + s->int_level &= ~(value & 0xd6); + smc91c111_update(s); + return; + case 13: /* Interrupt mask. */ + s->int_mask = value; + smc91c111_update(s); + return; + } + break;; + + case 3: + switch (offset) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + /* Multicast table. */ + /* Not implemented. */ + return; + case 8: case 9: /* Management Interface. */ + /* Not implemented. */ + return; + case 12: /* Early receive. */ + s->ercv = value & 0x1f; + case 13: + /* Ignore. */ + return; + } + break; + } + cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n", + s->bank, offset); +} + +static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) +{ + smc91c111_state *s = (smc91c111_state *)opaque; + + offset -= s->base; + if (offset == 14) { + return s->bank; + } + if (offset == 15) + return 0x33; + switch (s->bank) { + case 0: + switch (offset) { + case 0: /* TCR */ + return s->tcr & 0xff; + case 1: + return s->tcr >> 8; + case 2: /* EPH Status */ + return 0; + case 3: + return 0x40; + case 4: /* RCR */ + return s->rcr & 0xff; + case 5: + return s->rcr >> 8; + case 6: /* Counter */ + case 7: + /* Not implemented. */ + return 0; + case 8: /* Free memory available. */ + { + int i; + int n; + n = 0; + for (i = 0; i < NUM_PACKETS; i++) { + if (s->allocated & (1 << i)) + n++; + } + return n; + } + case 9: /* Memory size. */ + return NUM_PACKETS; + case 10: case 11: /* RPCR */ + /* Not implemented. */ + return 0; + } + break; + + case 1: + switch (offset) { + case 0: /* CONFIG */ + return s->cr & 0xff; + case 1: + return s->cr >> 8; + case 2: case 3: /* BASE */ + /* Not implemented. */ + return 0; + case 4: case 5: case 6: case 7: case 8: case 9: /* IA */ + return s->macaddr[offset - 4]; + case 10: /* General Purpose */ + return s->gpr & 0xff; + case 11: + return s->gpr >> 8; + case 12: /* Control */ + return s->ctr & 0xff; + case 13: + return s->ctr >> 8; + } + break; + + case 2: + switch (offset) { + case 0: case 1: /* MMUCR Busy bit. */ + return 0; + case 2: /* Packet Number. */ + return s->packet_num; + case 3: /* Allocation Result. */ + return s->tx_alloc; + case 4: /* TX FIFO */ + if (s->tx_fifo_len == 0) + return 0x80; + else + return s->tx_fifo[0]; + case 5: /* RX FIFO */ + if (s->rx_fifo_len == 0) + return 0x80; + else + return s->rx_fifo[0]; + case 6: /* Pointer */ + return s->ptr & 0xff; + case 7: + return (s->ptr >> 8) & 0xf7; + case 8: case 9: case 10: case 11: /* Data */ + { + int p; + int n; + + if (s->ptr & 0x8000) + n = s->rx_fifo[0]; + else + n = s->packet_num; + p = s->ptr & 0x07ff; + if (s->ptr & 0x4000) { + s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff); + } else { + p += (offset & 3); + } + return s->data[n][p]; + } + case 12: /* Interrupt status. */ + return s->int_level; + case 13: /* Interrupt mask. */ + return s->int_mask; + } + break; + + case 3: + switch (offset) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + /* Multicast table. */ + /* Not implemented. */ + return 0; + case 8: /* Management Interface. */ + /* Not implemented. */ + return 0x30; + case 9: + return 0x33; + case 10: /* Revision. */ + return 0x91; + case 11: + return 0x33; + case 12: + return s->ercv; + case 13: + return 0; + } + break; + } + cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n", + s->bank, offset); + return 0; +} + +static void smc91c111_writew(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + smc91c111_writeb(opaque, offset, value & 0xff); + smc91c111_writeb(opaque, offset + 1, value >> 8); +} + +static void smc91c111_writel(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + smc91c111_state *s = (smc91c111_state *)opaque; + /* 32-bit writes to offset 0xc only actually write to the bank select + register (offset 0xe) */ + if (offset != s->base + 0xc) + smc91c111_writew(opaque, offset, value & 0xffff); + smc91c111_writew(opaque, offset + 2, value >> 16); +} + +static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset) +{ + uint32_t val; + val = smc91c111_readb(opaque, offset); + val |= smc91c111_readb(opaque, offset + 1) << 8; + return val; +} + +static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset) +{ + uint32_t val; + val = smc91c111_readw(opaque, offset); + val |= smc91c111_readw(opaque, offset + 2) << 16; + return val; +} + +static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) +{ + smc91c111_state *s = (smc91c111_state *)opaque; + int status; + int packetsize; + uint32_t crc; + int packetnum; + uint8_t *p; + + if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) + return; + /* Short packets are padded with zeros. Recieveing a packet + < 64 bytes long is considered an error condition. */ + if (size < 64) + packetsize = 64; + else + packetsize = (size & ~1); + packetsize += 6; + crc = (s->rcr & RCR_STRIP_CRC) == 0; + if (crc) + packetsize += 4; + /* TODO: Flag overrun and receive errors. */ + if (packetsize > 2048) + return; + packetnum = smc91c111_allocate_packet(s); + if (packetnum == 0x80) + return; + s->rx_fifo[s->rx_fifo_len++] = packetnum; + + p = &s->data[packetnum][0]; + /* ??? Multicast packets? */ + status = 0; + if (size > 1518) + status |= RS_TOOLONG; + if (size & 1) + status |= RS_ODDFRAME; + *(p++) = status & 0xff; + *(p++) = status >> 8; + *(p++) = packetsize & 0xff; + *(p++) = packetsize >> 8; + memcpy(p, buf, size & ~1); + p += (size & ~1); + /* Pad short packets. */ + if (size < 64) { + int pad; + + if (size & 1) + *(p++) = buf[size - 1]; + pad = 64 - size; + memset(p, 0, pad); + p += pad; + size = 64; + } + /* It's not clear if the CRC should go before or after the last byte in + odd sized packets. Linux disables the CRC, so that's no help. + The pictures in the documentation show the CRC aligned on a 16-bit + boundary before the last odd byte, so that's what we do. */ + if (crc) { + crc = crc32(~0, buf, size); + *(p++) = crc & 0xff; crc >>= 8; + *(p++) = crc & 0xff; crc >>= 8; + *(p++) = crc & 0xff; crc >>= 8; + *(p++) = crc & 0xff; crc >>= 8; + } + if (size & 1) { + *(p++) = buf[size - 1]; + *(p++) = 0x60; + } else { + *(p++) = 0; + *(p++) = 0x40; + } + /* TODO: Raise early RX interrupt? */ + s->int_level |= INT_RCV; + smc91c111_update(s); +} + +static CPUReadMemoryFunc *smc91c111_readfn[] = { + smc91c111_readb, + smc91c111_readw, + smc91c111_readl +}; + +static CPUWriteMemoryFunc *smc91c111_writefn[] = { + smc91c111_writeb, + smc91c111_writew, + smc91c111_writel +}; + +void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq) +{ + smc91c111_state *s; + int iomemtype; + + s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state)); + iomemtype = cpu_register_io_memory(0, smc91c111_readfn, + smc91c111_writefn, s); + cpu_register_physical_memory(base, 16, iomemtype); + s->base = base; + s->pic = pic; + s->irq = irq; + memcpy(s->macaddr, nd->macaddr, 6); + + smc91c111_reset(s); + + s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, s); + /* ??? Save/restore. */ +} diff --git a/vl.h b/vl.h index 42954ebc5..2ade7e9e9 100644 --- a/vl.h +++ b/vl.h @@ -939,6 +939,9 @@ void ps2_write_keyboard(void *, int val); uint32_t ps2_read_data(void *); void ps2_queue(void *, int b); +/* smc91c111.c */ +void smc91c111_init(NICInfo *, uint32_t, void *, int); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From ee0971849e6110e14e10eaabb12b7adec7169668 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Dec 2005 18:56:28 +0000 Subject: Arm mulxy insn fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1683 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 930826cab..a5eb3b4c7 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1021,11 +1021,11 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest) static inline void gen_mulxy(int x, int y) { - if (x & 2) + if (x) gen_op_sarl_T0_im(16); else gen_op_sxth_T0(); - if (y & 1) + if (y) gen_op_sarl_T1_im(16); else gen_op_sxth_T1(); -- cgit v1.2.3 From 89984cd2e5e70e23b63109988c1156c76a31121d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 4 Dec 2005 22:17:10 +0000 Subject: segment validation fix in lret/iret git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1684 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 5c1d6cd80..0c5e362c7 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1584,7 +1584,7 @@ void load_seg(int seg_reg, int selector) if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { /* if not conforming code, test rights */ - if (dpl < cpl || dpl < rpl) + if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); } } @@ -2152,10 +2152,10 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) sp_mask = get_sp_mask(ss_e2); /* validate data segments */ - validate_seg(R_ES, cpl); - validate_seg(R_DS, cpl); - validate_seg(R_FS, cpl); - validate_seg(R_GS, cpl); + validate_seg(R_ES, rpl); + validate_seg(R_DS, rpl); + validate_seg(R_FS, rpl); + validate_seg(R_GS, rpl); sp += addend; } -- cgit v1.2.3 From 6f970bd90ec4ee73cf7a27616d44f1a1e0056532 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 19:55:19 +0000 Subject: MIPS support and memory access error reporting (Daniel Jacobowitz) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1685 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 29c7a0108..5fdf800bd 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -421,6 +421,72 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) ptr += 8 * 12 + 4; cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff); } +#elif defined (TARGET_MIPS) +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + for (i = 0; i < 32; i++) + { + *(uint32_t *)ptr = tswapl(env->gpr[i]); + ptr += 4; + } + + *(uint32_t *)ptr = tswapl(env->CP0_Status); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->LO); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->HI); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->CP0_BadVAddr); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->CP0_Cause); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->PC); + ptr += 4; + + /* 32 FP registers, fsr, fir, fp. Not yet implemented. */ + + return ptr - mem_buf; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + int i; + uint8_t *ptr; + + ptr = mem_buf; + for (i = 0; i < 32; i++) + { + env->gpr[i] = tswapl(*(uint32_t *)ptr); + ptr += 4; + } + + env->CP0_Status = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->LO = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->HI = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->CP0_BadVAddr = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->CP0_Cause = tswapl(*(uint32_t *)ptr); + ptr += 4; + + env->PC = tswapl(*(uint32_t *)ptr); + ptr += 4; +} #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { @@ -511,10 +577,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) if (*p == ',') p++; len = strtoul(p, NULL, 16); - if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) - memset(mem_buf, 0, len); - memtohex(buf, mem_buf, len); - put_packet(s, buf); + if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) { + put_packet (s, "E14"); + } else { + memtohex(buf, mem_buf, len); + put_packet(s, buf); + } break; case 'M': addr = strtoul(p, (char **)&p, 16); -- cgit v1.2.3 From 30d6cb8479163676bf27bf73464a899db985f1f9 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 19:56:07 +0000 Subject: correct MIPS state restoring (Daniel Jacobowitz) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1686 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 1 + translate-all.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/exec-all.h b/exec-all.h index 08351354e..58debaa1b 100644 --- a/exec-all.h +++ b/exec-all.h @@ -62,6 +62,7 @@ extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; extern target_ulong gen_opc_jump_pc[2]; +extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; typedef void (GenOpFunc)(void); typedef void (GenOpFunc1)(long); diff --git a/translate-all.c b/translate-all.c index cac91c535..0de429f5b 100644 --- a/translate-all.c +++ b/translate-all.c @@ -53,6 +53,8 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; #elif defined(TARGET_SPARC) target_ulong gen_opc_npc[OPC_BUF_SIZE]; target_ulong gen_opc_jump_pc[2]; +#elif defined(TARGET_MIPS) +uint32_t gen_opc_hflags[OPC_BUF_SIZE]; #endif int code_copy_enabled = 1; @@ -302,6 +304,8 @@ int cpu_restore_state(TranslationBlock *tb, } #elif defined(TARGET_MIPS) env->PC = gen_opc_pc[j]; + env->hflags &= ~MIPS_HFLAG_BMASK; + env->hflags |= gen_opc_hflags[j]; #endif return 0; } -- cgit v1.2.3 From 2d7272a5884d90ed1ac78fdb436621db1f192909 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 19:56:38 +0000 Subject: kernel command line support (Daniel Jacobowitz) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1687 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index b1c708cfc..2b47ef584 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -53,7 +53,7 @@ static void cpu_mips_update_count (CPUState *env, uint32_t count, next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); if (next == now) next++; -#if 1 +#if 0 if (logfile) { fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n", __func__, now, count, compare, next - now); @@ -84,7 +84,7 @@ static void mips_timer_cb (void *opaque) CPUState *env; env = opaque; -#if 1 +#if 0 if (logfile) { fprintf(logfile, "%s\n", __func__); } @@ -103,23 +103,29 @@ void cpu_mips_clock_init (CPUState *env) static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); +#endif cpu_outb(NULL, addr & 0xffff, value); } static uint32_t io_readb (void *opaque, target_phys_addr_t addr) { uint32_t ret = cpu_inb(NULL, addr & 0xffff); +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); +#endif return ret; } static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); +#endif #ifdef TARGET_WORDS_BIGENDIAN value = bswap16(value); #endif @@ -132,15 +138,19 @@ static uint32_t io_readw (void *opaque, target_phys_addr_t addr) #ifdef TARGET_WORDS_BIGENDIAN ret = bswap16(ret); #endif +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); +#endif return ret; } static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); +#endif #ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); #endif @@ -154,8 +164,10 @@ static uint32_t io_readl (void *opaque, target_phys_addr_t addr) #ifdef TARGET_WORDS_BIGENDIAN ret = bswap32(ret); #endif +#if 0 if (logfile) fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); +#endif return ret; } @@ -233,6 +245,11 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, initrd_size = 0; } env->PC = KERNEL_LOAD_ADDR; + /* Store command line. */ + strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); + /* FIXME: little endian support */ + *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); + *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); } else { kernel_base = 0; kernel_size = 0; -- cgit v1.2.3 From a64d4718f1afde08fb74910242e7a7b946c3f162 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 19:57:57 +0000 Subject: MIPS unaligned accesses exceptions (Daniel Jacobowitz) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1688 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_template.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/softmmu_template.h b/softmmu_template.h index c14407d3f..9bae4f628 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -97,15 +97,28 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, /* slow unaligned access (it spans two pages or IO) */ do_unaligned_access: retaddr = GETPC(); +#ifdef ALIGNED_ONLY + do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); +#endif res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, is_user, retaddr); } else { - /* unaligned access in the same page */ + /* unaligned/aligned access in the same page */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); + do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); + } +#endif res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr); } } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) + do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); +#endif tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr); goto redo; } @@ -213,15 +226,28 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: retaddr = GETPC(); +#ifdef ALIGNED_ONLY + do_unaligned_access(addr, 1, is_user, retaddr); +#endif glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, is_user, retaddr); } else { /* aligned/unaligned access in the same page */ +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); + do_unaligned_access(addr, 1, is_user, retaddr); + } +#endif glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val); } } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); +#ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) + do_unaligned_access(addr, 1, is_user, retaddr); +#endif tlb_fill(addr, 1, is_user, retaddr); goto redo; } -- cgit v1.2.3 From 6810e154907c4ed3883f3f9fc03507fe45a679ea Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 19:59:05 +0000 Subject: MIPS halt support - MIPS static state fix (Daniel Jacobowitz) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1689 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 7c056d40b..128b5ff7a 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -191,7 +191,7 @@ static inline TranslationBlock *tb_find_fast(void) cs_base = 0; pc = env->nip; #elif defined(TARGET_MIPS) - flags = env->hflags & MIPS_HFLAGS_TMASK; + flags = env->hflags & (MIPS_HFLAGS_TMASK | MIPS_HFLAG_BMASK); cs_base = 0; pc = env->PC; #else @@ -285,6 +285,15 @@ int cpu_exec(CPUState *env1) 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; -- cgit v1.2.3 From 4ad40f366f20f6991b640d7af63c9fc3a59246fa Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 19:59:36 +0000 Subject: MIPS fixes (Daniel Jacobowitz) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1690 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 31 ++++++---- target-mips/exec.h | 25 ++++---- target-mips/helper.c | 21 ++++--- target-mips/op.c | 22 +++++-- target-mips/op_helper.c | 58 ++++++++++++++++-- target-mips/op_helper_mem.c | 20 ++----- target-mips/op_mem.c | 17 ++++-- target-mips/translate.c | 141 ++++++++++++++++++++++++++++++-------------- 8 files changed, 231 insertions(+), 104 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 3314c9d91..5e4b91dcc 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -1,6 +1,8 @@ #if !defined (__MIPS_CPU_H__) #define __MIPS_CPU_H__ +#define TARGET_HAS_ICE 1 + #include "mips-defs.h" #include "cpu-defs.h" #include "config.h" @@ -18,6 +20,7 @@ typedef struct tlb_t tlb_t; struct tlb_t { target_ulong VPN; target_ulong end; + target_ulong end2; uint8_t ASID; uint8_t G; uint8_t C[2]; @@ -151,18 +154,20 @@ struct CPUMIPSState { #define MIPS_HFLAG_DM 0x0008 /* Debug mode */ #define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ #define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ -#define MIPS_HFLAG_DS 0x0080 /* In / out of delay slot */ - /* Those flags keep the branch state if the translation is interrupted - * between the branch instruction and the delay slot - */ -#define MIPS_HFLAG_BMASK 0x0F00 -#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */ -#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */ -#define MIPS_HFLAG_BL 0x0400 /* Likely branch */ -#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */ + /* If translation is interrupted between the branch instruction and + * the delay slot, record what type of branch it is so that we can + * resume translation properly. It might be possible to reduce + * this from three bits to two. */ +#define MIPS_HFLAG_BMASK 0x0380 +#define MIPS_HFLAG_B 0x0080 /* Unconditional branch */ +#define MIPS_HFLAG_BC 0x0100 /* Conditional branch */ +#define MIPS_HFLAG_BL 0x0180 /* Likely branch */ +#define MIPS_HFLAG_BR 0x0200 /* branch to register (can't link TB) */ target_ulong btarget; /* Jump / branch target */ int bcond; /* Branch condition (if needed) */ + int halted; /* TRUE if the CPU is in suspend state */ + CPU_COMMON }; @@ -202,15 +207,15 @@ enum { EXCP_IBE, EXCP_DBp, EXCP_SYSCALL, - EXCP_BREAK, - EXCP_CpU, /* 16 */ + EXCP_BREAK, /* 16 */ + EXCP_CpU, EXCP_RI, EXCP_OVERFLOW, EXCP_TRAP, EXCP_DDBS, EXCP_DWATCH, - EXCP_LAE, /* 22 */ - EXCP_SAE, + EXCP_LAE, + EXCP_SAE, /* 24 */ EXCP_LTLBL, EXCP_TLBL, EXCP_TLBS, diff --git a/target-mips/exec.h b/target-mips/exec.h index b3e423493..7031862c1 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -65,19 +65,19 @@ void do_tlbwi (void); void do_tlbwr (void); void do_tlbp (void); void do_tlbr (void); -void do_lwl_raw (void); -void do_lwr_raw (void); -void do_swl_raw (void); -void do_swr_raw (void); +void do_lwl_raw (uint32_t); +void do_lwr_raw (uint32_t); +uint32_t do_swl_raw (uint32_t); +uint32_t do_swr_raw (uint32_t); #if !defined(CONFIG_USER_ONLY) -void do_lwl_user (void); -void do_lwl_kernel (void); -void do_lwr_user (void); -void do_lwr_kernel (void); -void do_swl_user (void); -void do_swl_kernel (void); -void do_swr_user (void); -void do_swr_kernel (void); +void do_lwl_user (uint32_t); +void do_lwl_kernel (uint32_t); +void do_lwr_user (uint32_t); +void do_lwr_kernel (uint32_t); +uint32_t do_swl_user (uint32_t); +uint32_t do_swl_kernel (uint32_t); +uint32_t do_swr_user (uint32_t); +uint32_t do_swr_kernel (uint32_t); #endif void do_pmon (int function); @@ -88,6 +88,7 @@ void do_interrupt (CPUState *env); void cpu_loop_exit(void); void do_raise_exception_err (uint32_t exception, int error_code); void do_raise_exception (uint32_t exception); +void do_raise_exception_direct (uint32_t exception); void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), diff --git a/target-mips/helper.c b/target-mips/helper.c index 8d2617557..8b4deb3dd 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -46,7 +46,7 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && - tlb->VPN == tag && address < tlb->end) { + tlb->VPN == tag && address < tlb->end2) { /* TLB match */ n = (address >> 12) & 1; /* Check access rights */ @@ -167,10 +167,15 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int ret = 0; if (logfile) { +#if 0 cpu_dump_state(env, logfile, fprintf, 0); +#endif fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n", __func__, env->PC, address, rw, is_user, is_softmmu); } + + rw &= 1; + /* data access */ /* XXX: put correct access by using cpu_restore_state() correctly */ @@ -226,7 +231,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /* Raise exception */ env->CP0_BadVAddr = address; env->CP0_Context = (env->CP0_Context & 0xff800000) | - ((address >> 8) & 0x007ffff0); + ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = (env->CP0_EntryHi & 0x000000FF) | (address & 0xFFFFF000); env->exception_index = exception; @@ -276,11 +281,12 @@ void do_interrupt (CPUState *env) env->CP0_Debug |= 1 << CP0DB_DDBL; goto set_DEPC; set_DEPC: - if (env->hflags & MIPS_HFLAG_DS) { + if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump */ env->CP0_DEPC = env->PC - 4; + env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_DEPC = env->PC; } @@ -316,8 +322,7 @@ void do_interrupt (CPUState *env) env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) | (1 << CP0St_NMI); set_error_EPC: - env->hflags = MIPS_HFLAG_ERL; - if (env->hflags & MIPS_HFLAG_DS) { + if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump */ @@ -325,6 +330,7 @@ void do_interrupt (CPUState *env) } else { env->CP0_ErrorEPC = env->PC; } + env->hflags = MIPS_HFLAG_ERL; pc = 0xBFC00000; break; case EXCP_MCHECK: @@ -366,7 +372,7 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_CpU: cause = 11; - /* XXX: fill in the faulty unit number */ + env->CP0_Cause = (env->CP0_Cause & ~0x03000000) | (env->error_code << 28); goto set_EPC; case EXCP_OVERFLOW: cause = 12; @@ -391,12 +397,13 @@ void do_interrupt (CPUState *env) env->hflags |= MIPS_HFLAG_EXL; pc += offset; env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); - if (env->hflags & MIPS_HFLAG_DS) { + if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump */ env->CP0_EPC = env->PC - 4; env->CP0_Cause |= 0x80000000; + env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_EPC = env->PC; env->CP0_Cause &= ~0x80000000; diff --git a/target-mips/op.c b/target-mips/op.c index 029ce5d00..71abd95be 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -207,7 +207,7 @@ void op_addo (void) tmp = T0; T0 += T1; if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) { - CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); + CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } RETURN(); } @@ -225,7 +225,7 @@ void op_subo (void) tmp = T0; T0 = (int32_t)T0 - (int32_t)T1; if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) { - CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); + CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } RETURN(); } @@ -364,7 +364,7 @@ static inline void set_HILO (uint64_t HILO) void op_mult (void) { - set_HILO((int64_t)T0 * (int64_t)T1); + set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); RETURN(); } @@ -378,7 +378,7 @@ void op_madd (void) { int64_t tmp; - tmp = ((int64_t)T0 * (int64_t)T1); + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() + tmp); RETURN(); } @@ -396,7 +396,7 @@ void op_msub (void) { int64_t tmp; - tmp = ((int64_t)T0 * (int64_t)T1); + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() - tmp); RETURN(); } @@ -595,11 +595,16 @@ void op_pmon (void) void op_trap (void) { if (T0) { - CALL_FROM_TB1(do_raise_exception, EXCP_TRAP); + CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP); } RETURN(); } +void op_debug (void) +{ + CALL_FROM_TB1(do_raise_exception_direct, EXCP_DEBUG); +} + void op_set_lladdr (void) { env->CP0_LLAddr = T2; @@ -654,3 +659,8 @@ void op_exit_tb (void) EXIT_TB(); } +void op_wait (void) +{ + env->halted = 1; + CALL_FROM_TB1(do_raise_exception, EXCP_HLT); +} diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index cb4789cfa..be207b9bb 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -22,6 +22,8 @@ #define MIPS_DEBUG_DISAS +#define GETPC() (__builtin_return_address(0)) + /*****************************************************************************/ /* Exceptions processing helpers */ void cpu_loop_exit(void) @@ -46,6 +48,21 @@ void do_raise_exception (uint32_t exception) do_raise_exception_err(exception, 0); } +void do_restore_state (void *pc_ptr) +{ + TranslationBlock *tb; + unsigned long pc = (unsigned long) pc_ptr; + + tb = tb_find_pc (pc); + cpu_restore_state (tb, env, pc, NULL); +} + +void do_raise_exception_direct (uint32_t exception) +{ + do_restore_state (GETPC ()); + do_raise_exception_err (exception, 0); +} + #define MEMSUFFIX _raw #include "op_helper_mem.c" #undef MEMSUFFIX @@ -73,7 +90,7 @@ static inline void set_HILO (uint64_t HILO) void do_mult (void) { - set_HILO((int64_t)T0 * (int64_t)T1); + set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); } void do_multu (void) @@ -85,7 +102,7 @@ void do_madd (void) { int64_t tmp; - tmp = ((int64_t)T0 * (int64_t)T1); + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() + tmp); } @@ -101,7 +118,7 @@ void do_msub (void) { int64_t tmp; - tmp = ((int64_t)T0 * (int64_t)T1); + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() - tmp); } @@ -353,6 +370,9 @@ void do_mtc0 (int reg, int sel) val = T0 & 0xFFFFF0FF; old = env->CP0_EntryHi; env->CP0_EntryHi = val; + /* If the ASID changes, flush qemu's TLB. */ + if ((old & 0xFF) != (val & 0xFF)) + tlb_flush (env, 1); rn = "EntryHi"; break; case 11: @@ -525,11 +545,25 @@ static void invalidate_tb (int idx) addr = tlb->PFN[0]; end = addr + (tlb->end - tlb->VPN); tb_invalidate_page_range(addr, end); + /* FIXME: Might be faster to just invalidate the whole "tlb" here + and refill it on demand from our simulated TLB. */ + addr = tlb->VPN; + while (addr < tlb->end) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } } if (tlb->V[1]) { addr = tlb->PFN[1]; end = addr + (tlb->end - tlb->VPN); tb_invalidate_page_range(addr, end); + /* FIXME: Might be faster to just invalidate the whole "tlb" here + and refill it on demand from our simulated TLB. */ + addr = tlb->end; + while (addr < tlb->end2) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } } } @@ -545,6 +579,7 @@ static void fill_tb (int idx) size = env->CP0_PageMask >> 13; size = 4 * (size + 1); tlb->end = tlb->VPN + (1 << (8 + size)); + tlb->end2 = tlb->end + (1 << (8 + size)); tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; tlb->V[0] = env->CP0_EntryLo0 & 2; tlb->D[0] = env->CP0_EntryLo0 & 4; @@ -601,6 +636,12 @@ void do_tlbr (void) int size; tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; + + /* If this will change the current ASID, flush qemu's TLB. */ + /* FIXME: Could avoid flushing things which match global entries... */ + if ((env->CP0_EntryHi & 0xFF) != tlb->ASID) + tlb_flush (env, 1); + env->CP0_EntryHi = tlb->VPN | tlb->ASID; size = (tlb->end - tlb->VPN) >> 12; env->CP0_PageMask = (size - 1) << 13; @@ -664,8 +705,10 @@ void do_pmon (int function) #if !defined(CONFIG_USER_ONLY) +static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr); + #define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) +#define ALIGNED_ONLY #define SHIFT 0 #include "softmmu_template.h" @@ -679,6 +722,13 @@ void do_pmon (int function) #define SHIFT 3 #include "softmmu_template.h" +static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + env->CP0_BadVAddr = addr; + do_restore_state (retaddr); + do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL); +} + void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index 69793b0b9..3a6d386a6 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -1,11 +1,9 @@ -void glue(do_lwl, MEMSUFFIX) (void) +void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) target_ulong sav = T0; #endif - uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); /* XXX: this is valid only in big-endian mode * should be reverted for little-endian... */ @@ -32,14 +30,12 @@ void glue(do_lwl, MEMSUFFIX) (void) RETURN(); } -void glue(do_lwr, MEMSUFFIX) (void) +void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) target_ulong sav = T0; #endif - uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); /* XXX: this is valid only in big-endian mode * should be reverted for little-endian... */ @@ -66,14 +62,12 @@ void glue(do_lwr, MEMSUFFIX) (void) RETURN(); } -void glue(do_swl, MEMSUFFIX) (void) +uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) target_ulong sav; #endif - uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); #if defined (DEBUG_OP) sav = tmp; #endif @@ -94,7 +88,6 @@ void glue(do_swl, MEMSUFFIX) (void) tmp = (tmp & 0xFFFFFF00) | (T1 >> 24); break; } - glue(stl, MEMSUFFIX)(T0 & ~3, tmp); #if defined (DEBUG_OP) if (logfile) { fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", @@ -102,16 +95,15 @@ void glue(do_swl, MEMSUFFIX) (void) } #endif RETURN(); + return tmp; } -void glue(do_swr, MEMSUFFIX) (void) +uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) target_ulong sav; #endif - uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); #if defined (DEBUG_OP) sav = tmp; #endif @@ -132,7 +124,6 @@ void glue(do_swr, MEMSUFFIX) (void) tmp = T1; break; } - glue(stl, MEMSUFFIX)(T0 & ~3, tmp); #if defined (DEBUG_OP) if (logfile) { fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", @@ -140,4 +131,5 @@ void glue(do_swr, MEMSUFFIX) (void) } #endif RETURN(); + return tmp; } diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index bbb322db4..7fcfc24a6 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -67,28 +67,35 @@ void glue(op_sw, MEMSUFFIX) (void) RETURN(); } -/* "half" load and stores */ +/* "half" load and stores. We must do the memory access inline, + or fault handling won't work. */ void glue(op_lwl, MEMSUFFIX) (void) { - CALL_FROM_TB0(glue(do_lwl, MEMSUFFIX)); + uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + CALL_FROM_TB1(glue(do_lwl, MEMSUFFIX), tmp); RETURN(); } void glue(op_lwr, MEMSUFFIX) (void) { - CALL_FROM_TB0(glue(do_lwr, MEMSUFFIX)); + uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + CALL_FROM_TB1(glue(do_lwr, MEMSUFFIX), tmp); RETURN(); } void glue(op_swl, MEMSUFFIX) (void) { - CALL_FROM_TB0(glue(do_swl, MEMSUFFIX)); + uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + tmp = CALL_FROM_TB1(glue(do_swl, MEMSUFFIX), tmp); + glue(stl, MEMSUFFIX)(T0 & ~3, tmp); RETURN(); } void glue(op_swr, MEMSUFFIX) (void) { - CALL_FROM_TB0(glue(do_swr, MEMSUFFIX)); + uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); + tmp = CALL_FROM_TB1(glue(do_swr, MEMSUFFIX), tmp); + glue(stl, MEMSUFFIX)(T0 & ~3, tmp); RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index bb8128401..418a7afa0 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -338,17 +338,25 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) } } -static inline void generate_exception (DisasContext *ctx, int excp) +static inline void generate_exception_err (DisasContext *ctx, int excp, int err) { #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) fprintf(logfile, "%s: raise exception %d\n", __func__, excp); #endif save_cpu_state(ctx, 1); - gen_op_raise_exception(excp); + if (err == 0) + gen_op_raise_exception(excp); + else + gen_op_raise_exception_err(excp, err); ctx->bstate = BS_EXCP; } +static inline void generate_exception (DisasContext *ctx, int excp) +{ + generate_exception_err (ctx, excp, 0); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -1020,14 +1028,14 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, case OPC_BLEZ: /* 0 <= 0 */ case OPC_BLEZL: /* 0 <= 0 likely */ /* Always take */ - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways"); break; case OPC_BGEZAL: /* 0 >= 0 */ case OPC_BGEZALL: /* 0 >= 0 likely */ /* Always take and link */ blink = 31; - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways and link"); break; case OPC_BNE: /* rx != rx */ @@ -1053,21 +1061,21 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, gen_goto_tb(ctx, 0, ctx->pc + 4); return; case OPC_J: - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("j %08x", btarget); break; case OPC_JAL: blink = 31; - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B; + ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("jal %08x", btarget); break; case OPC_JR: - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR; + ctx->hflags |= MIPS_HFLAG_BR; MIPS_DEBUG("jr %s", regnames[rs]); break; case OPC_JALR: blink = rt; - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR; + ctx->hflags |= MIPS_HFLAG_BR; MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); break; default: @@ -1144,14 +1152,14 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, blink = 31; MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); not_likely: - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BC; + ctx->hflags |= MIPS_HFLAG_BC; break; case OPC_BLTZALL: gen_op_ltz(); blink = 31; MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); likely: - ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BL; + ctx->hflags |= MIPS_HFLAG_BL; break; } gen_op_set_bcond(); @@ -1178,7 +1186,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "CP0 is not usable\n"); } - gen_op_raise_exception_err(EXCP_CpU, 0); + generate_exception_err (ctx, EXCP_CpU, 0); return; } switch (opc) { @@ -1236,7 +1244,15 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) ctx->bstate = BS_EXCP; } break; - /* XXX: TODO: WAIT */ + case OPC_WAIT: + opn = "wait"; + /* If we get an exception, we want to restart at next instruction */ + ctx->pc += 4; + save_cpu_state(ctx, 1); + ctx->pc -= 4; + gen_op_wait(); + ctx->bstate = BS_EXCP; + break; default: if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n", @@ -1292,7 +1308,7 @@ static void gen_blikely(DisasContext *ctx) int l1; l1 = gen_new_label(); gen_op_jnz_T2(l1); - gen_op_save_state(ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS)); + gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); gen_goto_tb(ctx, 1, ctx->pc + 4); gen_set_label(l1); } @@ -1304,8 +1320,7 @@ static void decode_opc (DisasContext *ctx) uint16_t op, op1; int16_t imm; - if ((ctx->hflags & MIPS_HFLAG_DS) && - (ctx->hflags & MIPS_HFLAG_BL)) { + if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { /* Handle blikely not taken case */ MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); gen_blikely(ctx); @@ -1361,9 +1376,16 @@ static void decode_opc (DisasContext *ctx) case 0x05: /* Pmon entry point */ gen_op_pmon((ctx->opcode >> 6) & 0x1F); break; -#if defined (MIPS_HAS_MOVCI) + case 0x01: /* MOVCI */ +#if defined (MIPS_HAS_MOVCI) + /* XXX */ +#else + /* Not implemented */ + generate_exception_err (ctx, EXCP_CpU, 1); #endif + break; + #if defined (TARGET_MIPS64) case 0x14: /* MIPS64 specific opcodes */ case 0x16: @@ -1438,7 +1460,7 @@ static void decode_opc (DisasContext *ctx) gen_cp0(ctx, op1 | EXT_CP0, rt, rd); break; default: - gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd); + gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd); break; } break; @@ -1467,23 +1489,35 @@ static void decode_opc (DisasContext *ctx) break; case 0x3F: /* HACK */ break; + + /* Floating point. */ + case 0x31: /* LWC1 */ + case 0x35: /* LDC1 */ + case 0x39: /* SWC1 */ + case 0x3D: /* SDC1 */ + case 0x11: /* CP1 opcode */ #if defined(MIPS_USES_FPU) - case 0x31 ... 0x32: /* Floating point load/store */ - case 0x35 ... 0x36: - case 0x3A ... 0x3B: - case 0x3D ... 0x3E: - /* Not implemented */ /* XXX: not correct */ +#else + generate_exception_err(ctx, EXCP_CpU, 1); #endif - case 0x11: /* CP1 opcode */ - /* Not implemented */ - /* XXX: not correct */ + break; + + /* COP2. */ + case 0x32: /* LWC2 */ + case 0x36: /* LDC2 */ + case 0x3A: /* SWC2 */ + case 0x3E: /* SDC2 */ case 0x12: /* CP2 opcode */ /* Not implemented */ - /* XXX: not correct */ + generate_exception_err(ctx, EXCP_CpU, 2); + break; + case 0x13: /* CP3 opcode */ /* Not implemented */ - /* XXX: not correct */ + generate_exception_err(ctx, EXCP_CpU, 3); + break; + #if defined (TARGET_MIPS64) case 0x18 ... 0x1B: case 0x27: @@ -1497,21 +1531,15 @@ static void decode_opc (DisasContext *ctx) #endif case 0x1E: /* ASE specific */ -#if defined (MIPS_HAS_LSC) - case 0x31: /* LWC1 */ - case 0x32: /* LWC2 */ - case 0x35: /* SDC1 */ - case 0x36: /* SDC2 */ -#endif default: /* Invalid */ MIPS_INVAL(""); generate_exception(ctx, EXCP_RI); break; } - if (ctx->hflags & MIPS_HFLAG_DS) { + if (ctx->hflags & MIPS_HFLAG_BMASK) { int hflags = ctx->hflags; /* Branches completion */ - ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS); + ctx->hflags &= ~MIPS_HFLAG_BMASK; ctx->bstate = BS_BRANCH; save_cpu_state(ctx, 0); switch (hflags & MIPS_HFLAG_BMASK) { @@ -1557,16 +1585,20 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, uint16_t *gen_opc_end; int j, lj = -1; + if (search_pc && loglevel) + fprintf (logfile, "search pc %d\n", search_pc); + pc_start = tb->pc; gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; nb_gen_labels = 0; ctx.pc = pc_start; + ctx.saved_pc = -1; ctx.tb = tb; ctx.bstate = BS_NONE; - /* Restore delay slot state */ - ctx.hflags = env->hflags; + /* Restore delay slot state from the tb context. */ + ctx.hflags = tb->flags; ctx.saved_hflags = ctx.hflags; if (ctx.hflags & MIPS_HFLAG_BR) { gen_op_restore_breg_target(); @@ -1588,42 +1620,65 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "------------------------------------------------\n"); + /* FIXME: This may print out stale hflags from env... */ cpu_dump_state(env, logfile, fprintf, 0); } #endif #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "\ntb %p super %d cond %04x %04x\n", - tb, ctx.mem_idx, ctx.hflags, env->hflags); + fprintf(logfile, "\ntb %p super %d cond %04x\n", + tb, ctx.mem_idx, ctx.hflags); #endif while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == ctx.pc) { + save_cpu_state(ctxp, 1); + ctx.bstate = BS_BRANCH; + gen_op_debug(); + goto done_generating; + } + } + } + if (search_pc) { j = gen_opc_ptr - gen_opc_buf; - save_cpu_state(ctxp, 1); if (lj < j) { lj++; while (lj < j) gen_opc_instr_start[lj++] = 0; - gen_opc_pc[lj] = ctx.pc; - gen_opc_instr_start[lj] = 1; } + gen_opc_pc[lj] = ctx.pc; + gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK; + gen_opc_instr_start[lj] = 1; } ctx.opcode = ldl_code(ctx.pc); decode_opc(&ctx); ctx.pc += 4; + + if (env->singlestep_enabled) + break; + if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) break; + #if defined (MIPS_SINGLE_STEP) break; #endif } - if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { + if (env->singlestep_enabled) { + save_cpu_state(ctxp, ctx.bstate == BS_NONE); + gen_op_debug(); + goto done_generating; + } + else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { save_cpu_state(ctxp, 0); gen_goto_tb(&ctx, 0, ctx.pc); } gen_op_reset_T0(); /* Generate the return instruction */ gen_op_exit_tb(); +done_generating: *gen_opc_ptr = INDEX_op_end; if (search_pc) { j = gen_opc_ptr - gen_opc_buf; -- cgit v1.2.3 From f881a0d4f6eed97eba4b9c32628f566d830ad65e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 20:00:00 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1691 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index 8c97b8ec5..a96a5a9dc 100644 --- a/Changelog +++ b/Changelog @@ -14,6 +14,8 @@ version 0.7.3: - Linux host low level parallel port access - New network emulation code supporting VLANs. - MIPS User Linux emulation + - MIPS fixes to boot Linux (Daniel Jacobowitz) + - NX bit support version 0.7.2: -- cgit v1.2.3 From 227671c93ba454a4687ba0ddc5c7f3c55a166900 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 20:29:47 +0000 Subject: PAGE_EXEC support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1692 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/helper.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 7436e4ff4..d011de7fb 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -75,10 +75,27 @@ static const int access_table[8][8] = { { 2, 2, 2, 0, 2, 2, 2, 0 } }; -/* 1 = write OK */ -static const int rw_table[2][8] = { - { 0, 1, 0, 1, 0, 1, 0, 1 }, - { 0, 1, 0, 1, 0, 0, 0, 0 } +static const int perm_table[2][8] = { + { + PAGE_READ, + PAGE_READ | PAGE_WRITE, + PAGE_READ | PAGE_EXEC, + PAGE_READ | PAGE_WRITE | PAGE_EXEC, + PAGE_EXEC, + PAGE_READ | PAGE_WRITE, + PAGE_READ | PAGE_EXEC, + PAGE_READ | PAGE_WRITE | PAGE_EXEC + }, + { + PAGE_READ, + PAGE_READ | PAGE_WRITE, + PAGE_READ | PAGE_EXEC, + PAGE_READ | PAGE_WRITE | PAGE_EXEC, + PAGE_EXEC, + PAGE_READ, + 0, + 0, + } }; int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, @@ -95,7 +112,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot virt_addr = address & TARGET_PAGE_MASK; if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ *physical = address; - *prot = PAGE_READ | PAGE_WRITE; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return 0; } @@ -177,12 +194,11 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot return error_code; /* the page can be put in the TLB */ - *prot = PAGE_READ; - if (pde & PG_MODIFIED_MASK) { + *prot = perm_table[is_user][access_perms]; + if (!(pde & PG_MODIFIED_MASK)) { /* only set write access if already dirty... otherwise wait for dirty access */ - if (rw_table[is_user][access_perms]) - *prot |= PAGE_WRITE; + *prot &= ~PAGE_WRITE; } /* Even if large ptes, we map only one 4KB page in the cache to @@ -206,7 +222,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #ifdef DEBUG_MMU printf("Translate at 0x%lx -> 0x%lx, vaddr 0x%lx\n", (long)address, (long)paddr, (long)vaddr); #endif - ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; } @@ -221,8 +237,8 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, // neverland. Fake/overridden mappings will be flushed when // switching to normal mode. vaddr = address & TARGET_PAGE_MASK; - prot = PAGE_READ | PAGE_WRITE; - ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; } else { if (rw & 2) @@ -405,7 +421,7 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */ *physical = address; - *prot = PAGE_READ; + *prot = PAGE_EXEC; return 0; } @@ -441,7 +457,7 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical return 1; } *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); - *prot = PAGE_READ; + *prot = PAGE_EXEC; return 0; } } @@ -477,7 +493,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #ifdef DEBUG_MMU printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr); #endif - ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu); + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; } // XXX -- cgit v1.2.3 From b9788fc4c4974a4871e0ee46b5c06fee105a6aff Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 20:30:36 +0000 Subject: cdrom_read_toc support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1693 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/hw/esp.c b/hw/esp.c index 169531ff1..9603b74b1 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -75,6 +75,148 @@ typedef struct ESPState { #define SEQ_0 0x0 #define SEQ_CD 0x4 +/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */ +static void lba_to_msf(uint8_t *buf, int lba) +{ + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; +} + +static inline void cpu_to_ube16(uint8_t *buf, int val) +{ + buf[0] = val >> 8; + buf[1] = val; +} + +static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) +{ + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; +} + +/* same toc as bochs. Return -1 if error or the toc length */ +/* XXX: check this */ +static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) +{ + uint8_t *q; + int len; + + if (start_track > 1 && start_track != 0xaa) + return -1; + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + if (start_track <= 1) { + *q++ = 0; /* reserved */ + *q++ = 0x14; /* ADR, control */ + *q++ = 1; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, 0); + q += 3; + } else { + /* sector 0 */ + cpu_to_ube32(q, 0); + q += 4; + } + } + /* lead out track */ + *q++ = 0; /* reserved */ + *q++ = 0x16; /* ADR, control */ + *q++ = 0xaa; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, nb_sectors); + q += 3; + } else { + cpu_to_ube32(q, nb_sectors); + q += 4; + } + len = q - buf; + cpu_to_ube16(buf, len - 2); + return len; +} + +/* mostly same info as PearPc */ +static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, + int session_num) +{ + uint8_t *q; + int len; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* first track */ + *q++ = 0x00; /* disk type */ + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa1; + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* last track */ + *q++ = 0x00; + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa2; /* lead-out */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, nb_sectors); + q += 3; + } else { + cpu_to_ube32(q, nb_sectors); + q += 4; + } + + *q++ = 1; /* session number */ + *q++ = 0x14; /* ADR, control */ + *q++ = 0; /* track number */ + *q++ = 1; /* point */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + if (msf) { + *q++ = 0; + lba_to_msf(q, 0); + q += 3; + } else { + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + } + + len = q - buf; + cpu_to_ube16(buf, len - 2); + return len; +} + static void handle_satn(ESPState *s) { uint8_t buf[32]; @@ -128,6 +270,7 @@ static void handle_satn(ESPState *s) memcpy(&s->ti_buf[8], "QEMU ", 8); s->ti_buf[2] = 1; s->ti_buf[3] = 2; + s->ti_buf[4] = 32; s->ti_dir = 1; s->ti_size = 36; break; @@ -190,6 +333,45 @@ static void handle_satn(ESPState *s) s->ti_dir = 0; break; } + case 0x43: + { + int start_track, format, msf, len; + + msf = buf[2] & 2; + format = buf[3] & 0xf; + start_track = buf[7]; + bdrv_get_geometry(s->bd[target], &nb_sectors); + DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); + switch(format) { + case 0: + len = cdrom_read_toc(nb_sectors, buf, msf, start_track); + if (len < 0) + goto error_cmd; + s->ti_size = len; + break; + case 1: + /* multi session : only a single session defined */ + memset(buf, 0, 12); + buf[1] = 0x0a; + buf[2] = 0x01; + buf[3] = 0x01; + s->ti_size = 12; + break; + case 2: + len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track); + if (len < 0) + goto error_cmd; + s->ti_size = len; + break; + default: + error_cmd: + DPRINTF("Read TOC error\n"); + // XXX error handling + break; + } + s->ti_dir = 1; + break; + } default: DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); break; -- cgit v1.2.3 From ba3c64fb476d57c35013970ac444f04f35893ca9 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 20:31:52 +0000 Subject: Initial SPARC SMP support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1694 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + cpu-all.h | 1 + cpu-exec.c | 14 ++++++++- hw/slavio_intctl.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++------- hw/slavio_misc.c | 5 ++-- hw/slavio_serial.c | 72 +++++++++++++++++++++++++++++++++++----------- hw/slavio_timer.c | 25 ++++++---------- hw/sun4m.c | 32 +++++++++++++++++---- monitor.c | 4 +++ target-sparc/cpu.h | 1 + vl.c | 7 ++++- vl.h | 5 +++- 12 files changed, 196 insertions(+), 54 deletions(-) diff --git a/Changelog b/Changelog index a96a5a9dc..737f3ede2 100644 --- a/Changelog +++ b/Changelog @@ -16,6 +16,7 @@ version 0.7.3: - MIPS User Linux emulation - MIPS fixes to boot Linux (Daniel Jacobowitz) - NX bit support + - Initial SPARC SMP support (Blue Swirl) version 0.7.2: diff --git a/cpu-all.h b/cpu-all.h index d2086d56b..b374fe86b 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -734,6 +734,7 @@ extern int code_copy_enabled; #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 */ void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); diff --git a/cpu-exec.c b/cpu-exec.c index 128b5ff7a..740037e4b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -274,6 +274,15 @@ int cpu_exec(CPUState *env1) 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 @@ -522,7 +531,10 @@ int cpu_exec(CPUState *env1) } 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) { + env1->halted = 1; + return EXCP_HALTED; + } #elif defined(TARGET_ARM) if (interrupt_request & CPU_INTERRUPT_FIQ && !(env->uncached_cpsr & CPSR_F)) { diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 9780785a4..e43151fad 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -53,6 +53,7 @@ typedef struct SLAVIO_INTCTLState { #ifdef DEBUG_IRQ_COUNT uint64_t irq_count[32]; #endif + CPUState *cpu_envs[MAX_CPUS]; } SLAVIO_INTCTLState; #define INTCTL_MAXADDR 0xf @@ -96,6 +97,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint case 2: // set softint val &= 0xfffe0000; s->intreg_pending[cpu] |= val; + slavio_check_interrupts(s); DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); break; default: @@ -216,7 +218,7 @@ static void slavio_check_interrupts(void *opaque) CPUState *env; SLAVIO_INTCTLState *s = opaque; uint32_t pending = s->intregm_pending; - unsigned int i, max = 0; + unsigned int i, j, max = 0; pending &= ~s->intregm_disabled; @@ -227,20 +229,52 @@ static void slavio_check_interrupts(void *opaque) max = intbit_to_level[i]; } } - env = first_cpu; - if (env->interrupt_index == 0) { - DPRINTF("Triggered pil %d\n", max); + env = s->cpu_envs[s->target_cpu]; + if (!env) { + DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending); + } + else { + if (env->halted) + env->halted = 0; + if (env->interrupt_index == 0) { + DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max); #ifdef DEBUG_IRQ_COUNT - s->irq_count[max]++; + s->irq_count[max]++; #endif - env->interrupt_index = TT_EXTINT | max; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + env->interrupt_index = TT_EXTINT | max; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + else + DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index); } - else - DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index); } else DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled); + + for (i = 0; i < MAX_CPUS; i++) { + max = 0; + env = s->cpu_envs[i]; + if (!env) + continue; + for (j = 17; j < 32; j++) { + if (s->intreg_pending[i] & (1 << j)) { + if (max < j - 16) + max = j - 16; + } + } + if (max > 0) { + if (env->halted) + env->halted = 0; + if (env->interrupt_index == 0) { + DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending); +#ifdef DEBUG_IRQ_COUNT + s->irq_count[max]++; +#endif + env->interrupt_index = TT_EXTINT | max; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + } + } } /* @@ -251,7 +285,7 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) { SLAVIO_INTCTLState *s = opaque; - DPRINTF("Set irq %d level %d\n", irq, level); + DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level); if (irq < 32) { uint32_t mask = 1 << irq; uint32_t pil = intbit_to_level[irq]; @@ -269,6 +303,29 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) slavio_check_interrupts(s); } +void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu) +{ + SLAVIO_INTCTLState *s = opaque; + + DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level); + if (cpu == (unsigned int)-1) { + slavio_pic_set_irq(opaque, irq, level); + return; + } + if (irq < 32) { + uint32_t pil = intbit_to_level[irq]; + if (pil > 0) { + if (level) { + s->intreg_pending[cpu] |= 1 << pil; + } + else { + s->intreg_pending[cpu] &= ~(1 << pil); + } + } + } + slavio_check_interrupts(s); +} + static void slavio_intctl_save(QEMUFile *f, void *opaque) { SLAVIO_INTCTLState *s = opaque; @@ -312,6 +369,12 @@ static void slavio_intctl_reset(void *opaque) s->target_cpu = 0; } +void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env) +{ + SLAVIO_INTCTLState *s = opaque; + s->cpu_envs[cpu] = env; +} + void *slavio_intctl_init(uint32_t addr, uint32_t addrg) { int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 1b681be48..904f44e51 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -124,9 +124,8 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32 case 0xa000000: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); #if 0 - // XXX: halting CPU does not work - raise_exception(EXCP_HLT); - cpu_loop_exit(); + // XXX almost works + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); #endif break; } diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index de45cc5de..2b89c6d62 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -45,6 +45,8 @@ #ifdef DEBUG_SERIAL #define SER_DPRINTF(fmt, args...) \ do { printf("SER: " fmt , ##args); } while (0) +#define pic_set_irq(irq, level) \ +do { printf("SER: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0) #else #define SER_DPRINTF(fmt, args...) #endif @@ -174,6 +176,50 @@ static void slavio_serial_reset(void *opaque) slavio_serial_reset_chn(&s->chn[1]); } +static inline void clr_rxint(ChannelState *s) +{ + s->rxint = 0; + if (s->chn == 0) + s->rregs[3] &= ~0x20; + else { + s->otherchn->rregs[3] &= ~4; + } + slavio_serial_update_irq(s); +} + +static inline void set_rxint(ChannelState *s) +{ + s->rxint = 1; + if (s->chn == 0) + s->rregs[3] |= 0x20; + else { + s->otherchn->rregs[3] |= 4; + } + slavio_serial_update_irq(s); +} + +static inline void clr_txint(ChannelState *s) +{ + s->txint = 0; + if (s->chn == 0) + s->rregs[3] &= ~0x10; + else { + s->otherchn->rregs[3] &= ~2; + } + slavio_serial_update_irq(s); +} + +static inline void set_txint(ChannelState *s) +{ + s->txint = 1; + if (s->chn == 0) + s->rregs[3] |= 0x10; + else { + s->otherchn->rregs[3] |= 2; + } + slavio_serial_update_irq(s); +} + static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { SerialState *ser = opaque; @@ -198,10 +244,14 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint newreg |= 0x8; break; case 0x20: - s->rxint = 0; + clr_rxint(s); break; case 0x28: - s->txint = 0; + clr_txint(s); + break; + case 0x38: + clr_rxint(s); + clr_txint(s); break; default: break; @@ -247,12 +297,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint s->txint = 1; s->rregs[0] |= 4; // Tx buffer empty s->rregs[1] |= 1; // All sent - // Interrupts reported only on channel A - if (s->chn == 0) - s->rregs[3] |= 0x10; - else { - s->otherchn->rregs[3] |= 2; - } + set_txint(s); slavio_serial_update_irq(s); } break; @@ -280,6 +325,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) return ret; case 1: s->rregs[0] &= ~1; + clr_rxint(s); if (s->type == kbd) ret = get_queue(s); else @@ -304,16 +350,10 @@ static int serial_can_receive(void *opaque) static void serial_receive_byte(ChannelState *s, int ch) { + SER_DPRINTF("put ch %d\n", ch); s->rregs[0] |= 1; - // Interrupts reported only on channel A - if (s->chn == 0) - s->rregs[3] |= 0x20; - else { - s->otherchn->rregs[3] |= 4; - } s->rx = ch; - s->rxint = 1; - slavio_serial_update_irq(s); + set_rxint(s); } static void serial_receive_break(ChannelState *s) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 47d538529..d75a76a63 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -42,6 +42,9 @@ do { printf("TIMER: " fmt , ##args); } while (0) * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 * are zero. Bit 31 is 1 when count has been reached. * + * Per-CPU timers interrupt local CPU, system timer uses normal + * interrupt routing. + * */ typedef struct SLAVIO_TIMERState { @@ -53,11 +56,11 @@ typedef struct SLAVIO_TIMERState { int irq; int reached, stopped; int mode; // 0 = processor, 1 = user, 2 = system + unsigned int cpu; } SLAVIO_TIMERState; #define TIMER_MAXADDR 0x1f #define CNT_FREQ 2000000 -#define MAX_CPUS 16 // Update count, set irq, update expire_time static void slavio_timer_get_out(SLAVIO_TIMERState *s) @@ -73,7 +76,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) else ticks = qemu_get_clock(vm_clock) - s->tick_offset; - out = (ticks >= s->expire_time); + out = (ticks > s->expire_time); if (out) s->reached = 0x80000000; if (!s->limit) @@ -100,7 +103,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); if (s->mode != 1) - pic_set_irq(s->irq, out); + pic_set_irq_cpu(s->irq, out, s->cpu); } // timer callback @@ -127,7 +130,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) // part of counter (user mode) if (s->mode != 1) { // clear irq - pic_set_irq(s->irq, 0); + pic_set_irq_cpu(s->irq, 0, s->cpu); s->count_load_time = qemu_get_clock(vm_clock); s->reached = 0; return s->limit; @@ -263,7 +266,7 @@ static void slavio_timer_reset(void *opaque) slavio_timer_get_out(s); } -static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) +void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu) { int slavio_timer_io_memory; SLAVIO_TIMERState *s; @@ -273,6 +276,7 @@ static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) return; s->irq = irq; s->mode = mode; + s->cpu = cpu; s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, @@ -282,14 +286,3 @@ static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) qemu_register_reset(slavio_timer_reset, s); slavio_timer_reset(s); } - -void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2) -{ - int i; - - for (i = 0; i < MAX_CPUS; i++) { - slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0); - } - - slavio_timer_init_internal(addr2, irq2, 2); -} diff --git a/hw/sun4m.c b/hw/sun4m.c index 3ac0886a4..5733fce5a 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -56,6 +56,7 @@ #define PHYS_JJ_FDC 0x71400000 /* Floppy */ #define PHYS_JJ_FLOPPY_IRQ 22 #define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */ +#define MAX_CPUS 16 /* TSC handling */ @@ -128,6 +129,8 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */ // NVRAM_size, arch not applicable + m48t59_write(nvram, 0x2D, smp_cpus & 0xff); + m48t59_write(nvram, 0x2E, 0); m48t59_write(nvram, 0x2F, nographic & 0xff); nvram_set_lword(nvram, 0x30, RAM_size); m48t59_write(nvram, 0x34, boot_device & 0xff); @@ -179,6 +182,11 @@ void pic_set_irq(int irq, int level) slavio_pic_set_irq(slavio_intctl, irq, level); } +void pic_set_irq_cpu(int irq, int level, unsigned int cpu) +{ + slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); +} + static void *tcx; void vga_update_display() @@ -222,7 +230,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) { - CPUState *env; + CPUState *env, *envs[MAX_CPUS]; char buf[1024]; int ret, linux_boot; unsigned int i; @@ -230,19 +238,31 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, linux_boot = (kernel_filename != NULL); - env = cpu_init(); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - qemu_register_reset(main_cpu_reset, env); - + /* init CPUs */ + for(i = 0; i < smp_cpus; i++) { + env = cpu_init(); + envs[i] = env; + if (i != 0) + env->halted = 1; + register_savevm("cpu", i, 3, cpu_save, cpu_load, env); + qemu_register_reset(main_cpu_reset, env); + } /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); iommu = iommu_init(PHYS_JJ_IOMMU); slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); + for(i = 0; i < smp_cpus; i++) { + slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); + } + tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8); - slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); + for (i = 0; i < MAX_CPUS; i++) { + slavio_timer_init(PHYS_JJ_CLOCK + i * TARGET_PAGE_SIZE, PHYS_JJ_CLOCK_IRQ, 0, i); + } + slavio_timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ, 2, (unsigned int)-1); slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device diff --git a/monitor.c b/monitor.c index 2f0e84d86..d7acaa420 100644 --- a/monitor.c +++ b/monitor.c @@ -259,6 +259,10 @@ static void do_info_cpus(void) term_printf(" nip=0x" TARGET_FMT_lx, env->nip); if (env->halted) term_printf(" (halted)"); +#elif defined(TARGET_SPARC) + term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc); + if (env->halted) + term_printf(" (halted)"); #endif term_printf("\n"); } diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index baff0c460..28efab758 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -166,6 +166,7 @@ typedef struct CPUSPARCState { int exception_index; int interrupt_index; int interrupt_request; + int halted; /* NOTE: we allow 8 more registers to handle wrapping */ target_ulong regbase[NWINDOWS * 16 + 8]; diff --git a/vl.c b/vl.c index aa28032b4..4b1e72e9e 100644 --- a/vl.c +++ b/vl.c @@ -153,6 +153,11 @@ USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; USBDevice *vm_usb_hub; static VLANState *first_vlan; int smp_cpus = 1; +#ifdef TARGET_SPARC +#define MAX_CPUS 16 +#else +#define MAX_CPUS 8 +#endif /***********************************************************/ /* x86 ISA bus support */ @@ -4547,7 +4552,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_smp: smp_cpus = atoi(optarg); - if (smp_cpus < 1 || smp_cpus > 8) { + if (smp_cpus < 1 || smp_cpus > MAX_CPUS) { fprintf(stderr, "Invalid number of CPUs\n"); exit(1); } diff --git a/vl.h b/vl.h index 2ade7e9e9..fbac80725 100644 --- a/vl.h +++ b/vl.h @@ -806,6 +806,7 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ extern QEMUMachine sun4m_machine; uint32_t iommu_translate(uint32_t addr); +void pic_set_irq_cpu(int irq, int level, unsigned int cpu); /* iommu.c */ void *iommu_init(uint32_t addr); @@ -823,16 +824,18 @@ void tcx_screen_dump(void *opaque, const char *filename); /* slavio_intctl.c */ void *slavio_intctl_init(); +void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); void slavio_pic_info(void *opaque); void slavio_irq_info(void *opaque); void slavio_pic_set_irq(void *opaque, int irq, int level); +void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); /* magic-load.c */ int load_elf(const char *filename, uint8_t *addr); int load_aout(const char *filename, uint8_t *addr); /* slavio_timer.c */ -void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2); +void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu); /* slavio_serial.c */ SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2); -- cgit v1.2.3 From 6900e84b20c85038be1721c97170e2367599f36b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 21:04:24 +0000 Subject: handle coprocessor exceptions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1695 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-user/main.c b/linux-user/main.c index 907f7109e..ef3a17116 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1327,6 +1327,7 @@ void cpu_loop(CPUMIPSState *env) } } break; + case EXCP_CpU: case EXCP_RI: { uint32_t insn, op; -- cgit v1.2.3 From cc4adeef9896be77cf3add189b2ee15b435d3669 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Dec 2005 21:04:50 +0000 Subject: added MIPS user in automatic tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1696 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 78a215bb1..ed643e348 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -83,7 +83,7 @@ hello-arm.o: hello-arm.c # XXX: find a way to compile easily a test for each arch test2: - @for arch in i386 arm sparc ppc; do \ + @for arch in i386 arm sparc ppc mips; do \ ../$${arch}-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \ done -- cgit v1.2.3 From ea31eb5b0ce0bd03d2ba2cccdd39991703c5398d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Dec 2005 21:42:03 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1697 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 +- Makefile | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 737f3ede2..6e42ec76c 100644 --- a/Changelog +++ b/Changelog @@ -13,7 +13,7 @@ version 0.7.3: - Linux host serial port access - Linux host low level parallel port access - New network emulation code supporting VLANs. - - MIPS User Linux emulation + - MIPS and MIPSel User Linux emulation - MIPS fixes to boot Linux (Daniel Jacobowitz) - NX bit support - Initial SPARC SMP support (Blue Swirl) diff --git a/Makefile b/Makefile index 332058642..cfa7df571 100644 --- a/Makefile +++ b/Makefile @@ -118,10 +118,14 @@ tarbin: $(bindir)/qemu-system-sparc \ $(bindir)/qemu-system-x86_64 \ $(bindir)/qemu-system-mips \ + $(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 \ -- cgit v1.2.3 From 01f5e596ed591e2e1fd1e84d13bcaac6d093fe2a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Dec 2005 21:42:17 +0000 Subject: mipsel target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1698 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile.target b/Makefile.target index adc853713..093d40c8e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -30,9 +30,17 @@ ifeq ($(TARGET_ARCH),arm) else QEMU_USER=qemu-arm endif +else +ifeq ($(TARGET_ARCH),mips) + ifeq ($(TARGET_WORDS_BIGENDIAN),yes) + QEMU_USER=qemu-mips + else + QEMU_USER=qemu-mipsel + endif else QEMU_USER=qemu-$(TARGET_ARCH) endif +endif # system emulator name ifdef CONFIG_SOFTMMU ifeq ($(TARGET_ARCH), i386) -- cgit v1.2.3 From c20eb473620d13c5913e2102e32a048599f62404 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Dec 2005 21:42:55 +0000 Subject: mipsel-user target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1699 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 9a6e54735..efd2679ce 100755 --- a/configure +++ b/configure @@ -230,7 +230,7 @@ if test -z "$target_list" ; then target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu arm-softmmu" # the following are Linux specific if [ "$linux" = "yes" ] ; then - target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user $target_list" + target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list" fi else target_list=$(echo "$target_list" | sed -e 's/,/ /g') @@ -744,7 +744,7 @@ elif test "$target_cpu" = "x86_64" ; then if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64" ; then echo "#define USE_KQEMU 1" >> $config_h fi -elif test "$target_cpu" = "mips" ; then +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 -- cgit v1.2.3 From 909a8762eeec347a5105e6b0e4eb59be7448aa3f Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Dec 2005 21:43:35 +0000 Subject: mips and mipsel support - fixed e_type mask git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1700 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-binfmt-conf.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh index ff09fc4f9..bd278d908 100644 --- a/qemu-binfmt-conf.sh +++ b/qemu-binfmt-conf.sh @@ -20,16 +20,20 @@ esac # register the interpreter for each cpu except for the native one if [ $cpu != "i386" ] ; then - echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register - echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register + echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register + echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "arm" ] ; then - echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register - echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register + echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register + echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "sparc" ] ; then - echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register + echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "ppc" ] ; then - echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register + echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register +fi +if [ $cpu != "mips" ] ; then + echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register + echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register fi -- cgit v1.2.3 From 9f25f11fe58e48d735339e1c8362e8ff242f02f5 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Dec 2005 21:44:28 +0000 Subject: fix for mipsel (will need change for softmmu case) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1701 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper_mem.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index 3a6d386a6..4711f7a6c 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -1,3 +1,9 @@ +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK(v) ((v) & 3) +#else +#define GET_LMASK(v) (((v) & 3) ^ 3) +#endif + void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) @@ -7,7 +13,7 @@ void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) /* XXX: this is valid only in big-endian mode * should be reverted for little-endian... */ - switch (T0 & 3) { + switch (GET_LMASK(T0)) { case 0: T0 = tmp; break; @@ -39,7 +45,7 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) /* XXX: this is valid only in big-endian mode * should be reverted for little-endian... */ - switch (T0 & 3) { + switch (GET_LMASK(T0)) { case 0: T0 = (tmp >> 24) | (T1 & 0xFFFFFF00); break; @@ -74,7 +80,7 @@ uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) /* XXX: this is valid only in big-endian mode * should be reverted for little-endian... */ - switch (T0 & 3) { + switch (GET_LMASK(T0)) { case 0: tmp = T1; break; @@ -110,7 +116,7 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) /* XXX: this is valid only in big-endian mode * should be reverted for little-endian... */ - switch (T0 & 3) { + switch (GET_LMASK(T0)) { case 0: tmp = (tmp & 0x00FFFFFF) | (T1 << 24); break; -- cgit v1.2.3 From 56902eee82c1af1e7786be3ca789ea261d9072e6 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Dec 2005 21:44:55 +0000 Subject: more targets git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1702 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index ed643e348..be26243e0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -83,7 +83,7 @@ hello-arm.o: hello-arm.c # XXX: find a way to compile easily a test for each arch test2: - @for arch in i386 arm sparc ppc mips; do \ + @for arch in i386 arm armeb sparc ppc mips mipsel; do \ ../$${arch}-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \ done -- cgit v1.2.3 From dbf2c23a60ab167e686ae2502900943a5be33210 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 6 Dec 2005 21:48:41 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1703 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cvsignore b/.cvsignore index 7e7f5fa6b..9ea66ba27 100644 --- a/.cvsignore +++ b/.cvsignore @@ -22,3 +22,5 @@ x86_64-softmmu sparc64-user sparc64-softmmu mips-softmmu +mips-user +mipsel-user -- cgit v1.2.3 From 265d3497763842573ab67bf67cedef2062f1b7ec Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 17 Dec 2005 01:05:42 +0000 Subject: switch_tss fix (aka spoon OS bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1704 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 0c5e362c7..531ba1b15 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -339,7 +339,7 @@ static void switch_tss(int tss_selector, necessary to valid the TLB after having done the accesses */ v1 = ldub_kernel(env->tr.base); - v2 = ldub(env->tr.base + old_tss_limit_max); + v2 = ldub_kernel(env->tr.base + old_tss_limit_max); stb_kernel(env->tr.base, v1); stb_kernel(env->tr.base + old_tss_limit_max, v2); -- cgit v1.2.3 From 76b3030c56bcc6b95bb71413d3a5024c22dd4c33 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 17 Dec 2005 01:10:04 +0000 Subject: mipsel disas fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1705 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/disas.c b/disas.c index 78a72675d..f8281b512 100644 --- a/disas.c +++ b/disas.c @@ -187,7 +187,11 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #endif print_insn = print_insn_ppc; #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_M68K) print_insn = print_insn_m68k; #else @@ -381,7 +385,11 @@ void monitor_disas(CPUState *env, #endif print_insn = print_insn_ppc; #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_M68K) print_insn = print_insn_m68k; #else -- cgit v1.2.3 From 01dbbdf1e505f78d440cf8b386092b3848d0a9fd Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 17 Dec 2005 01:11:12 +0000 Subject: disable debug mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1706 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index 7031862c1..ed9094c7e 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -1,7 +1,7 @@ #if !defined(__QEMU_MIPS_EXEC_H__) #define __QEMU_MIPS_EXEC_H__ -#define DEBUG_OP +//#define DEBUG_OP #include "mips-defs.h" #include "dyngen-exec.h" -- cgit v1.2.3 From d3e9db933f416c9f1c04df4834d36e2315952e42 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 17 Dec 2005 01:27:28 +0000 Subject: initial support for up to 255 CPUs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1707 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 254 ++++++++++++++++++++++++++++++++++++++------------------------ vl.c | 6 +- 2 files changed, 160 insertions(+), 100 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index 64caadb81..65f96a5b7 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -60,6 +60,9 @@ #define APIC_SV_ENABLE (1 << 8) +#define MAX_APICS 255 +#define MAX_APIC_WORDS 8 + typedef struct APICState { CPUState *cpu_env; uint32_t apicbase; @@ -81,8 +84,6 @@ typedef struct APICState { uint32_t initial_count; int64_t initial_count_load_time, next_time; QEMUTimer *timer; - - struct APICState *next_apic; } APICState; struct IOAPICState { @@ -94,14 +95,95 @@ struct IOAPICState { }; static int apic_io_memory; -static APICState *first_local_apic = NULL; +static APICState *local_apics[MAX_APICS + 1]; static int last_apic_id = 0; static void apic_init_ipi(APICState *s); static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); static void apic_update_irq(APICState *s); -static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, +/* Find first bit starting from msb. Return 0 if value = 0 */ +static int fls_bit(uint32_t value) +{ + unsigned int ret = 0; + +#if defined(HOST_I386) + __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value)); + return ret; +#else + if (value > 0xffff) + value >>= 16, ret = 16; + if (value > 0xff) + value >>= 8, ret += 8; + if (value > 0xf) + value >>= 4, ret += 4; + if (value > 0x3) + value >>= 2, ret += 2; + return ret + (value >> 1); +#endif +} + +/* Find first bit starting from lsb. Return 0 if value = 0 */ +static int ffs_bit(uint32_t value) +{ + unsigned int ret = 0; + +#if defined(HOST_I386) + __asm__ __volatile__ ("bsf %1, %0\n" : "+r" (ret) : "rm" (value)); + return ret; +#else + if (!value) + return 0; + if (!(value & 0xffff)) + value >>= 16, ret = 16; + if (!(value & 0xff)) + value >>= 8, ret += 8; + if (!(value & 0xf)) + value >>= 4, ret += 4; + if (!(value & 0x3)) + value >>= 2, ret += 2; + if (!(value & 0x1)) + ret++; + return ret; +#endif +} + +static inline void set_bit(uint32_t *tab, int index) +{ + int i, mask; + i = index >> 5; + mask = 1 << (index & 0x1f); + tab[i] |= mask; +} + +static inline void reset_bit(uint32_t *tab, int index) +{ + int i, mask; + i = index >> 5; + mask = 1 << (index & 0x1f); + tab[i] &= ~mask; +} + +#define foreach_apic(apic, deliver_bitmask, code) \ +{\ + int __i, __j, __mask;\ + for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\ + __mask = deliver_bitmask[__i];\ + if (__mask) {\ + for(__j = 0; __j < 32; __j++) {\ + if (__mask & (1 << __j)) {\ + apic = local_apics[__i * 32 + __j];\ + if (apic) {\ + code;\ + }\ + }\ + }\ + }\ + }\ +} + +static void apic_bus_deliver(const uint32_t *deliver_bitmask, + uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) { @@ -110,13 +192,23 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, switch (delivery_mode) { case APIC_DM_LOWPRI: /* XXX: search for focus processor, arbitration */ - if (deliver_bitmask) { - uint32_t m = 1; - while ((deliver_bitmask & m) == 0) - m <<= 1; - deliver_bitmask = m; + { + int i, d; + d = -1; + for(i = 0; i < MAX_APIC_WORDS; i++) { + if (deliver_bitmask[i]) { + d = i * 32 + ffs_bit(deliver_bitmask[i]); + break; + } + } + if (d >= 0) { + apic_iter = local_apics[d]; + if (apic_iter) { + apic_set_irq(apic_iter, vector_num, trigger_mode); + } + } } - break; + return; case APIC_DM_FIXED: break; @@ -127,11 +219,8 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, case APIC_DM_INIT: /* normal INIT IPI sent to processors */ - for (apic_iter = first_local_apic; apic_iter != NULL; - apic_iter = apic_iter->next_apic) { - if (deliver_bitmask & (1 << apic_iter->id)) - apic_init_ipi(apic_iter); - } + foreach_apic(apic_iter, deliver_bitmask, + apic_init_ipi(apic_iter) ); return; case APIC_DM_EXTINT: @@ -142,11 +231,8 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, return; } - for (apic_iter = first_local_apic; apic_iter != NULL; - apic_iter = apic_iter->next_apic) { - if (deliver_bitmask & (1 << apic_iter->id)) - apic_set_irq(apic_iter, vector_num, trigger_mode); - } + foreach_apic(apic_iter, deliver_bitmask, + apic_set_irq(apic_iter, vector_num, trigger_mode) ); } void cpu_set_apic_base(CPUState *env, uint64_t val) @@ -187,42 +273,6 @@ uint8_t cpu_get_apic_tpr(CPUX86State *env) return s->tpr >> 4; } -static int fls_bit(int value) -{ - unsigned int ret = 0; - -#ifdef HOST_I386 - __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value)); - return ret; -#else - if (value > 0xffff) - value >>= 16, ret = 16; - if (value > 0xff) - value >>= 8, ret += 8; - if (value > 0xf) - value >>= 4, ret += 4; - if (value > 0x3) - value >>= 2, ret += 2; - return ret + (value >> 1); -#endif -} - -static inline void set_bit(uint32_t *tab, int index) -{ - int i, mask; - i = index >> 5; - mask = 1 << (index & 0x1f); - tab[i] |= mask; -} - -static inline void reset_bit(uint32_t *tab, int index) -{ - int i, mask; - i = index >> 5; - mask = 1 << (index & 0x1f); - tab[i] &= ~mask; -} - /* return -1 if no bit is set */ static int get_highest_priority_int(uint32_t *tab) { @@ -294,26 +344,37 @@ static void apic_eoi(APICState *s) apic_update_irq(s); } -static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode) +static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, + uint8_t dest, uint8_t dest_mode) { - uint32_t mask = 0; APICState *apic_iter; + int i; if (dest_mode == 0) { - if (dest == 0xff) - mask = 0xff; - else - mask = 1 << dest; + if (dest == 0xff) { + memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t)); + } else { + memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); + set_bit(deliver_bitmask, dest); + } } else { /* XXX: cluster mode */ - for (apic_iter = first_local_apic; apic_iter != NULL; - apic_iter = apic_iter->next_apic) { - if (dest & apic_iter->log_dest) - mask |= (1 << apic_iter->id); + memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); + for(i = 0; i < MAX_APICS; i++) { + apic_iter = local_apics[i]; + if (apic_iter) { + if (apic_iter->dest_mode == 0xf) { + if (dest & apic_iter->log_dest) + set_bit(deliver_bitmask, i); + } else if (apic_iter->dest_mode == 0x0) { + if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) && + (dest & apic_iter->log_dest & 0x0f)) { + set_bit(deliver_bitmask, i); + } + } + } } } - - return mask; } @@ -356,23 +417,25 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) { - uint32_t deliver_bitmask = 0; + uint32_t deliver_bitmask[MAX_APIC_WORDS]; int dest_shorthand = (s->icr[0] >> 18) & 3; APICState *apic_iter; switch (dest_shorthand) { - case 0: - deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode); - break; - case 1: - deliver_bitmask = (1 << s->id); - break; - case 2: - deliver_bitmask = 0xffffffff; - break; - case 3: - deliver_bitmask = 0xffffffff & ~(1 << s->id); - break; + case 0: + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); + break; + case 1: + memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); + set_bit(deliver_bitmask, s->id); + break; + case 2: + memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); + break; + case 3: + memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); + reset_bit(deliver_bitmask, s->id); + break; } switch (delivery_mode) { @@ -381,24 +444,16 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, int trig_mode = (s->icr[0] >> 15) & 1; int level = (s->icr[0] >> 14) & 1; if (level == 0 && trig_mode == 1) { - for (apic_iter = first_local_apic; apic_iter != NULL; - apic_iter = apic_iter->next_apic) { - if (deliver_bitmask & (1 << apic_iter->id)) { - apic_iter->arb_id = apic_iter->id; - } - } + foreach_apic(apic_iter, deliver_bitmask, + apic_iter->arb_id = apic_iter->id ); return; } } break; case APIC_DM_SIPI: - for (apic_iter = first_local_apic; apic_iter != NULL; - apic_iter = apic_iter->next_apic) { - if (deliver_bitmask & (1 << apic_iter->id)) { - apic_startup(apic_iter, vector_num); - } - } + foreach_apic(apic_iter, deliver_bitmask, + apic_startup(apic_iter, vector_num) ); return; } @@ -749,6 +804,8 @@ int apic_init(CPUState *env) { APICState *s; + if (last_apic_id >= MAX_APICS) + return -1; s = qemu_mallocz(sizeof(APICState)); if (!s) return -1; @@ -772,10 +829,8 @@ int apic_init(CPUState *env) register_savevm("apic", 0, 1, apic_save, apic_load, s); qemu_register_reset(apic_reset, s); - - s->next_apic = first_local_apic; - first_local_apic = s; + local_apics[s->id] = s; return 0; } @@ -790,6 +845,7 @@ static void ioapic_service(IOAPICState *s) uint8_t dest; uint8_t dest_mode; uint8_t polarity; + uint32_t deliver_bitmask[MAX_APIC_WORDS]; for (i = 0; i < IOAPIC_NUM_PINS; i++) { mask = 1 << i; @@ -807,8 +863,10 @@ static void ioapic_service(IOAPICState *s) vector = pic_read_irq(isa_pic); else vector = entry & 0xff; - apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode), - delivery_mode, vector, polarity, trig_mode); + + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); + apic_bus_deliver(deliver_bitmask, delivery_mode, + vector, polarity, trig_mode); } } } diff --git a/vl.c b/vl.c index 4b1e72e9e..b68b20a40 100644 --- a/vl.c +++ b/vl.c @@ -153,10 +153,12 @@ USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; USBDevice *vm_usb_hub; static VLANState *first_vlan; int smp_cpus = 1; -#ifdef TARGET_SPARC +#if defined(TARGET_SPARC) #define MAX_CPUS 16 +#elif defined(TARGET_I386) +#define MAX_CPUS 255 #else -#define MAX_CPUS 8 +#define MAX_CPUS 1 #endif /***********************************************************/ -- cgit v1.2.3 From cd072e01d86b3d7adab35de03d242e3938e798df Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 17 Dec 2005 02:59:58 +0000 Subject: fixed null segment validation (aka x86_64 regression bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1708 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 531ba1b15..a64924222 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1986,7 +1986,14 @@ static inline void validate_seg(int seg_reg, int cpl) { int dpl; uint32_t e2; - + + /* XXX: on x86_64, we do not want to nullify FS and GS because + they may still contain a valid base. I would be interested to + know how a real x86_64 CPU behaves */ + if ((seg_reg == R_FS || seg_reg == R_GS) && + (env->segs[seg_reg].selector & 0xfffc) == 0) + return; + e2 = env->segs[seg_reg].flags; dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { -- cgit v1.2.3 From 87022ff52b7de5b2836a7f9d4b8a1727e1cc2ff7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 17 Dec 2005 14:02:29 +0000 Subject: moved mp config table to a safer place git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1709 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index 83d601fe9..41cfdcfea 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -466,7 +466,7 @@ static void bios_add_mptable(uint8_t *bios_data) if (smp_cpus <= 1) return; - mp_config_table = bios_data + 0xcc00; + mp_config_table = bios_data + 0xb000; q = mp_config_table; putstr(&q, "PCMP"); /* "PCMP signature */ putle16(&q, 0); /* table length (patched later) */ -- cgit v1.2.3 From 3d830459b1eccdb61b75e2712fd364012ce5a115 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 16:36:49 +0000 Subject: '-net socket,mcast=' option support (initial patch by Juan Jose Ciarlante) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1710 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 38 +++++++++++- vl.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 225 insertions(+), 3 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 7ec41f527..f970b2a59 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -282,8 +282,8 @@ Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual machine using a TCP socket connection. If @option{listen} is specified, QEMU waits for incoming connections on @var{port} (@var{host} is optional). @option{connect} is used to connect to -another QEMU instance using the @option{listen} option. @option{fd=h} -specifies an already opened socket. +another QEMU instance using the @option{listen} option. @option{fd=h} +specifies an already opened TCP socket. Example: @example @@ -293,6 +293,40 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,listen=:1234 qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,connect=127.0.0.1:1234 @end example +@item -net socket[,vlan=n][,fd=h][,mcast=maddr:port] + +Create a VLAN @var{n} shared with another QEMU virtual +machines using a UDP multicast socket, effectively making a bus for +every QEMU with same multicast address @var{maddr} and @var{port}. +NOTES: +@enumerate +@item +Several QEMU can be running on different hosts and share same bus (assuming +correct multicast setup for these hosts). +@item +mcast support is compatible with User Mode Linux (argument @option{eth@var{N}=mcast}), see +@url{http://user-mode-linux.sf.net}. +@item Use @option{fd=h} to specify an already opened UDP multicast socket. +@end enumerate + +Example: +@example +# launch one QEMU instance +qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234 +# launch another QEMU instance on same "bus" +qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234 +# launch yet another QEMU instance on same "bus" +qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234 +@end example + +Example (User Mode Linux compat.): +@example +# launch QEMU instance (note mcast address selected is UML's default) +qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102 +# launch UML +/path/to/linux ubd0=/path/to/root_fs eth0=mcast +@end example + @item -net none Indicate that no network devices should be configured. It is used to override the default configuration which is activated if no diff --git a/vl.c b/vl.c index b68b20a40..2baca1c01 100644 --- a/vl.c +++ b/vl.c @@ -2133,6 +2133,7 @@ typedef struct NetSocketState { int index; int packet_len; uint8_t buf[4096]; + struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ } NetSocketState; typedef struct NetSocketListenState { @@ -2151,6 +2152,13 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, int size) unix_write(s->fd, buf, size); } +static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) +{ + NetSocketState *s = opaque; + sendto(s->fd, buf, size, 0, + (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); +} + static void net_socket_send(void *opaque) { NetSocketState *s = opaque; @@ -2203,13 +2211,140 @@ static void net_socket_send(void *opaque) } } +static void net_socket_send_dgram(void *opaque) +{ + NetSocketState *s = opaque; + int size; + + size = recv(s->fd, s->buf, sizeof(s->buf), 0); + if (size < 0) + return; + if (size == 0) { + /* end of connection */ + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + return; + } + qemu_send_packet(s->vc, s->buf, size); +} + +static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) +{ + struct ip_mreq imr; + int fd; + int val, ret; + if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { + fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", + inet_ntoa(mcastaddr->sin_addr), ntohl(mcastaddr->sin_addr.s_addr)); + return -1; + + } + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + perror("socket(PF_INET, SOCK_DGRAM)"); + return -1; + } + + /* Add host to multicast group */ + imr.imr_multiaddr = mcastaddr->sin_addr; + imr.imr_interface.s_addr = htonl(INADDR_ANY); + + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *) &imr, sizeof(struct ip_mreq)); + if (ret < 0) { + perror("setsockopt(IP_ADD_MEMBERSHIP)"); + goto fail; + } + + /* Force mcast msgs to loopback (eg. several QEMUs in same host */ + val = 1; + ret=setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &val, sizeof(val)); + if (ret < 0) { + perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); + goto fail; + } + + ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + if (ret < 0) { + perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); + goto fail; + } + + ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); + if (ret < 0) { + perror("bind"); + goto fail; + } + + fcntl(fd, F_SETFL, O_NONBLOCK); + return fd; +fail: + if (fd>=0) close(fd); + return -1; +} + +static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, + int is_connected) +{ + struct sockaddr_in saddr; + int newfd; + socklen_t saddr_len; + NetSocketState *s; + + /* fd passed: multicast: "learn" dgram_dst address from bound address and save it + * Because this may be "shared" socket from a "master" process, datagrams would be recv() + * by ONLY ONE process: we must "clone" this dgram socket --jjo + */ + + if (is_connected) { + if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) { + /* must be bound */ + if (saddr.sin_addr.s_addr==0) { + fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n", + fd); + return NULL; + } + /* clone dgram socket */ + newfd = net_socket_mcast_create(&saddr); + if (newfd < 0) { + /* error already reported by net_socket_mcast_create() */ + close(fd); + return NULL; + } + /* clone newfd to fd, close newfd */ + dup2(newfd, fd); + close(newfd); + + } else { + fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", + fd, strerror(errno)); + return NULL; + } + } + + s = qemu_mallocz(sizeof(NetSocketState)); + if (!s) + return NULL; + s->fd = fd; + + s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, s); + qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); + + /* mcast: save bound address as dst */ + if (is_connected) s->dgram_dst=saddr; + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: fd=%d (%s mcast=%s:%d)", + fd, is_connected? "cloned" : "", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + return s; +} + static void net_socket_connect(void *opaque) { NetSocketState *s = opaque; qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); } -static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, +static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, int is_connected) { NetSocketState *s; @@ -2229,6 +2364,28 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, return s; } +static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, + int is_connected) +{ + int so_type=-1, optlen=sizeof(so_type); + + if(getsockopt(fd, SOL_SOCKET,SO_TYPE, &so_type, &optlen)< 0) { + fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd); + return NULL; + } + switch(so_type) { + case SOCK_DGRAM: + return net_socket_fd_init_dgram(vlan, fd, is_connected); + case SOCK_STREAM: + return net_socket_fd_init_stream(vlan, fd, is_connected); + default: + /* who knows ... this could be a eg. a pty, do warn and continue as stream */ + fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd); + return net_socket_fd_init_stream(vlan, fd, is_connected); + } + return NULL; +} + static void net_socket_accept(void *opaque) { NetSocketListenState *s = opaque; @@ -2338,6 +2495,33 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str) return 0; } +static int net_socket_mcast_init(VLANState *vlan, const char *host_str) +{ + NetSocketState *s; + int fd; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + + fd = net_socket_mcast_create(&saddr); + if (fd < 0) + return -1; + + s = net_socket_fd_init(vlan, fd, 0); + if (!s) + return -1; + + s->dgram_dst = saddr; + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "socket: mcast=%s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + return 0; + +} + #endif /* !_WIN32 */ static int get_param_value(char *buf, int buf_size, @@ -2474,6 +2658,8 @@ int net_client_init(const char *str) ret = net_socket_listen_init(vlan, buf); } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) { ret = net_socket_connect_init(vlan, buf); + } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) { + ret = net_socket_mcast_init(vlan, buf); } else { fprintf(stderr, "Unknown socket options: %s\n", p); return -1; @@ -3812,6 +3998,8 @@ void help(void) " use 'fd=h' to connect to an already opened TAP interface\n" "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n" " connect the vlan 'n' to another VLAN using a socket connection\n" + "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n" + " connect the vlan 'n' to multicast maddr and port\n" #endif "-net none use it alone to have zero network devices; if no -net option\n" " is provided, the default is '-net nic -net user'\n" -- cgit v1.2.3 From 6d7e63262c7e47400c37cb6b789b1e2df8d492e4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 16:54:08 +0000 Subject: switching to Arm mode in do_interrupt() (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1711 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 9cf159c07..538e17a35 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -162,10 +162,11 @@ void do_interrupt(CPUARMState *env) } switch_mode (env, new_mode); env->spsr = cpsr_read(env); - /* Switch to the new mode, and clear the thumb bit. */ + /* Switch to the new mode, and switch to Arm mode. */ /* ??? Thumb interrupt handlers not implemented. */ - env->uncached_cpsr = (env->uncached_cpsr & ~(CPSR_M | CPSR_T)) | new_mode; + env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode; env->uncached_cpsr |= mask; + env->thumb = 0; env->regs[14] = env->regs[15] + offset; env->regs[15] = addr; env->interrupt_request |= CPU_INTERRUPT_EXITTB; -- cgit v1.2.3 From 68998c5de3b92e7034aa9d8fecf53f0bc3ccc91e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 16:55:25 +0000 Subject: cpu_reset() fix (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1712 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index a5eb3b4c7..089fbf2fd 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2431,10 +2431,10 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) void cpu_reset(CPUARMState *env) { #if defined (CONFIG_USER_ONLY) + env->uncached_cpsr = ARM_CPU_MODE_USR; +#else /* SVC mode with interrupts disabled. */ env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; -#else - env->uncached_cpsr = ARM_CPU_MODE_USR; #endif env->regs[15] = 0; } -- cgit v1.2.3 From 5198cfd9277af376c0d1c667f5a1943f100fee45 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 17:39:52 +0000 Subject: smc91c111 fixes (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1713 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/smc91c111.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 54433c432..375debd1f 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -35,8 +35,10 @@ typedef struct { int tx_fifo[NUM_PACKETS]; int rx_fifo_len; int rx_fifo[NUM_PACKETS]; + int tx_fifo_done_len; + int tx_fifo_done[NUM_PACKETS]; /* Packet buffer memory. */ - uint8_t data[2048][NUM_PACKETS]; + uint8_t data[NUM_PACKETS][2048]; uint8_t int_level; uint8_t int_mask; uint8_t macaddr[6]; @@ -81,6 +83,8 @@ static void smc91c111_update(smc91c111_state *s) if (s->tx_fifo_len == 0) s->int_level |= INT_TX_EMPTY; + if (s->tx_fifo_done_len != 0) + s->int_level |= INT_TX; level = (s->int_level & s->int_mask) != 0; pic_set_irq_new(s->pic, s->irq, level); } @@ -128,6 +132,18 @@ static void smc91c111_pop_rx_fifo(smc91c111_state *s) smc91c111_update(s); } +/* Remove an item from the TX completion FIFO. */ +static void smc91c111_pop_tx_fifo_done(smc91c111_state *s) +{ + int i; + + if (s->tx_fifo_done_len == 0) + return; + s->tx_fifo_done_len--; + for (i = 0; i < s->tx_fifo_done_len; i++) + s->tx_fifo_done[i] = s->tx_fifo_done[i + 1]; +} + /* Release the memory allocated to a packet. */ static void smc91c111_release_packet(smc91c111_state *s, int packet) { @@ -184,12 +200,13 @@ static void smc91c111_do_tx(smc91c111_state *s) add_crc = 0; #endif if (s->ctr & CTR_AUTO_RELEASE) + /* Race? */ smc91c111_release_packet(s, packetnum); + else if (s->tx_fifo_done_len < NUM_PACKETS) + s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum; qemu_send_packet(s->vc, p, len); } s->tx_fifo_len = 0; - if ((s->ctr & CTR_AUTO_RELEASE) == 0) - s->int_level |= INT_TX; smc91c111_update(s); } @@ -206,6 +223,7 @@ static void smc91c111_reset(smc91c111_state *s) { s->bank = 0; s->tx_fifo_len = 0; + s->tx_fifo_done_len = 0; s->rx_fifo_len = 0; s->allocated = 0; s->packet_num = 0; @@ -306,6 +324,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, case 2: /* Reset MMU. */ s->allocated = 0; s->tx_fifo_len = 0; + s->tx_fifo_done_len = 0; s->rx_fifo_len = 0; s->tx_alloc = 0; break; @@ -326,6 +345,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, break; case 7: /* Reset TX FIFO. */ s->tx_fifo_len = 0; + s->tx_fifo_done_len = 0; break; } return; @@ -364,6 +384,8 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, return; case 12: /* Interrupt ACK. */ s->int_level &= ~(value & 0xd6); + if (value & INT_TX) + smc91c111_pop_tx_fifo_done(s); smc91c111_update(s); return; case 13: /* Interrupt mask. */ @@ -473,10 +495,10 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) case 3: /* Allocation Result. */ return s->tx_alloc; case 4: /* TX FIFO */ - if (s->tx_fifo_len == 0) + if (s->tx_fifo_done_len == 0) return 0x80; else - return s->tx_fifo[0]; + return s->tx_fifo_done[0]; case 5: /* RX FIFO */ if (s->rx_fifo_len == 0) return 0x80; -- cgit v1.2.3 From 183b4a380683751911a24a06abae6c9d8d58ac86 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 17:51:01 +0000 Subject: do not init ne2000 if no network enabled git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1714 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 2b47ef584..5f51f874c 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -272,7 +272,8 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0, 0); - isa_ne2000_init(0x300, 9, &nd_table[0]); + if (nd_table[0].vlan) + isa_ne2000_init(0x300, 9, &nd_table[0]); } QEMUMachine mips_machine = { -- cgit v1.2.3 From 1658b44bf506464cc811e421ac41372ee400371a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 18:02:24 +0000 Subject: use IPPROTO_IP instead of SOL_IP git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1715 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 2baca1c01..21dca789a 100644 --- a/vl.c +++ b/vl.c @@ -2256,7 +2256,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) /* Force mcast msgs to loopback (eg. several QEMUs in same host */ val = 1; - ret=setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &val, sizeof(val)); + ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &val, sizeof(val)); if (ret < 0) { perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); goto fail; -- cgit v1.2.3 From 95389c8681d4e52f9192fb15e12dba29c6807545 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 18:28:15 +0000 Subject: qcow_make_empty() support (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1716 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow.c | 58 ++++++++++++++++++++++++++++++++++++++++------------------ block.c | 16 +++++++++++++--- block_int.h | 3 +++ 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/block-qcow.c b/block-qcow.c index ca05be88b..34026a4f2 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -552,25 +552,28 @@ static int qcow_create(const char *filename, int64_t total_size, header_size = sizeof(header); backing_filename_len = 0; if (backing_file) { - const char *p; - /* XXX: this is a hack: we do not attempt to check for URL - like syntax */ - p = strchr(backing_file, ':'); - if (p && (p - backing_file) >= 2) { - /* URL like but exclude "c:" like filenames */ - pstrcpy(backing_filename, sizeof(backing_filename), - backing_file); - } else { - realpath(backing_file, backing_filename); - if (stat(backing_filename, &st) != 0) { - return -1; - } - } + if (strcmp(backing_file, "fat:")) { + const char *p; + /* XXX: this is a hack: we do not attempt to check for URL + like syntax */ + p = strchr(backing_file, ':'); + if (p && (p - backing_file) >= 2) { + /* URL like but exclude "c:" like filenames */ + pstrcpy(backing_filename, sizeof(backing_filename), + backing_file); + } else { + realpath(backing_file, backing_filename); + if (stat(backing_filename, &st) != 0) { + return -1; + } + } + header.backing_file_offset = cpu_to_be64(header_size); + backing_filename_len = strlen(backing_filename); + header.backing_file_size = cpu_to_be32(backing_filename_len); + header_size += backing_filename_len; + } else + backing_file = NULL; header.mtime = cpu_to_be32(st.st_mtime); - header.backing_file_offset = cpu_to_be64(header_size); - backing_filename_len = strlen(backing_filename); - header.backing_file_size = cpu_to_be32(backing_filename_len); - header_size += backing_filename_len; header.cluster_bits = 9; /* 512 byte cluster to avoid copying unmodifyed sectors */ header.l2_bits = 12; /* 32 KB L2 tables */ @@ -603,6 +606,24 @@ static int qcow_create(const char *filename, int64_t total_size, return 0; } +int qcow_make_empty(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + uint32_t l1_length = s->l1_size * sizeof(uint64_t); + + memset(s->l1_table, 0, l1_length); + lseek(s->fd, s->l1_table_offset, SEEK_SET); + if (write(s->fd, s->l1_table, l1_length) < 0) + return -1; + ftruncate(s->fd, s->l1_table_offset + l1_length); + + 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; +} + int qcow_get_cluster_size(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; @@ -683,6 +704,7 @@ BlockDriver bdrv_qcow = { qcow_create, qcow_is_allocated, qcow_set_key, + qcow_make_empty }; diff --git a/block.c b/block.c index efd96e637..6924cee67 100644 --- a/block.c +++ b/block.c @@ -150,13 +150,19 @@ int bdrv_create(BlockDriver *drv, } #ifdef _WIN32 -static void get_tmp_filename(char *filename, int size) +void get_tmp_filename(char *filename, int size) { + char* p = strrchr(filename, '/'); + + if (p == NULL) + return; + /* XXX: find a better function */ - tmpnam(filename); + tmpnam(p); + *p = '/'; } #else -static void get_tmp_filename(char *filename, int size) +void get_tmp_filename(char *filename, int size) { int fd; /* XXX: race condition possible */ @@ -394,6 +400,10 @@ int bdrv_commit(BlockDriverState *bs) i += n; } } + + if (bs->drv->bdrv_make_empty) + return bs->drv->bdrv_make_empty(bs); + return 0; } diff --git a/block_int.h b/block_int.h index 03744f734..e3038160e 100644 --- a/block_int.h +++ b/block_int.h @@ -39,6 +39,7 @@ struct BlockDriver { 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); struct BlockDriver *next; }; @@ -74,4 +75,6 @@ struct BlockDriverState { BlockDriverState *next; }; +void get_tmp_filename(char *filename, int size); + #endif /* BLOCK_INT_H */ -- cgit v1.2.3 From a046433a161a1f554be55df8421d92cbdc52779f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 18:29:50 +0000 Subject: Major overhaul of the virtual FAT driver for read/write support (Johannes Schindelin) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1717 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vvfat.c | 2944 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 2001 insertions(+), 943 deletions(-) diff --git a/block-vvfat.c b/block-vvfat.c index 3409f883a..b73a6f680 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -1,7 +1,8 @@ +/* vim:set shiftwidth=4 ts=8: */ /* * QEMU Block driver for virtual VFAT (shadows a local directory) * - * Copyright (c) 2004 Johannes E. Schindelin + * 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 @@ -27,19 +28,47 @@ #include "vl.h" #include "block_int.h" -// TODO: new file -// TODO: delete file -// TODO: make root directory larger -// TODO: make directory clusters connected, so they are reserved anyway... add a member which tells how many clusters are reserved after a directory -// TODO: introduce another member in mapping_t which says where the directory resides in s->directory (for mkdir and rmdir) -// in _read and _write, before treating direntries or file contents, get_mapping to know what it is. -// TODO: mkdir -// TODO: rmdir +#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; -// TODO: when commit_data'ing a direntry and is_consistent, commit_remove -// TODO: reset MODE_MODIFIED when commit_remove'ing +static void checkpoint(); -#define DEBUG +#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) if (!(a)) nonono(__FILE__, __LINE__, #a) +#endif + +#else + +#define DLOG(a) + +#endif /* dynamic array functions */ typedef struct array_t { @@ -62,23 +91,37 @@ static inline void array_free(array_t* array) array->size=array->next=0; } -/* make sure that memory is reserved at pointer[index*item_size] */ +/* does not automatically grow */ static inline void* array_get(array_t* array,unsigned 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 0; - array->size=new_size; - array->next=index+1; + 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 array->pointer+index*array->item_size; + + return 0; } static inline void* array_get_next(array_t* array) { - unsigned int next=array->next; - void* result=array_get(array,next); - array->next=next+1; + 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; } @@ -132,14 +175,32 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun return 0; } -int array_remove(array_t* array,int index) +inline int array_remove_slice(array_t* array,int index, int count) { - if(array_roll(array,array->next-1,index,1)) + assert(index >=0); + assert(count > 0); + assert(index + count <= array->next); + if(array_roll(array,array->next-1,index,count)) return -1; - array->next--; + 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)). */ @@ -151,7 +212,7 @@ typedef struct bootsector_t { uint16_t reserved_sectors; uint8_t number_of_fats; uint16_t root_entries; - uint16_t zero; + uint16_t total_sectors16; uint8_t media_type; uint16_t sectors_per_fat; uint16_t sectors_per_track; @@ -186,7 +247,7 @@ typedef struct partition_t { uint8_t start_head; uint8_t start_sector; uint8_t start_cylinder; - uint8_t fs_type; /* 0x6 = FAT16, 0xb = FAT32 */ + uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */ uint8_t end_head; uint8_t end_sector; uint8_t end_cylinder; @@ -218,32 +279,44 @@ typedef struct 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, - * offset is the offset in the file in clusters of this slice */ - off_t begin,end,offset; - char* filename; - + /* 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; - enum { MODE_NORMAL,MODE_UNDEFINED,MODE_MODIFIED,MODE_DELETED,MODE_DIRECTORY } mode; + /* 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; -/* this structure is used to hold sectors which need to be written, but it's - * not known yet where to write them. */ - -typedef struct commit_t { - uint32_t cluster_num; - uint8_t* buf; -} commit_t; - -/* write support exists for fat, direntry and file contents */ -typedef enum { - WRITE_UNDEFINED,WRITE_FAT,WRITE_DIRENTRY,WRITE_DATA -} write_action_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]; @@ -254,31 +327,33 @@ typedef struct BDRVVVFATState { unsigned int sectors_per_cluster; unsigned int sectors_per_fat; unsigned int sectors_of_root_directory; - unsigned int sectors_for_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 */ - unsigned int first_file_mapping; /* index of the first mapping which is not a directory, but a file */ uint32_t max_fat_value; int current_fd; - char current_fd_is_writable; /* =0 if read only, !=0 if read/writable */ mapping_t* current_mapping; - unsigned char* cluster; + 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 */ - array_t commit; - /* for each file, the file contents, the direntry, and the fat entries are - * written, but not necessarily in that order */ - write_action_t action[3]; + 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 int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename) { - if (strstart(filename, "fat:", NULL) || - strstart(filename, "fatrw:", NULL)) + if (strstart(filename, "fat:", NULL)) return 100; return 0; } @@ -295,16 +370,19 @@ static void init_mbr(BDRVVVFATState* s) partition->start_head=1; partition->start_sector=1; partition->start_cylinder=0; - partition->fs_type=(s->fat_type==16?0x6:0xb); /* FAT16/FAT32 */ - partition->end_head=0xf; + /* 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(0x3f); + 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) { @@ -344,9 +422,62 @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil 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(direntry_t* entry) +static inline uint8_t fat_chksum(const direntry_t* entry) { uint8_t chksum=0; int i; @@ -375,29 +506,39 @@ static uint16_t fat_datetime(time_t time,int return_time) { static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value) { - if(s->fat_type==12) { - assert(0); /* TODO */ + 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 { - uint32_t* entry=array_get(&(s->fat),cluster); - *entry=cpu_to_le32(value); + 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) { - //fprintf(stderr,"want to get fat for cluster %d\n",cluster); - if(s->fat_type==12) { - const uint8_t* x=s->fat.pointer+cluster*3/2; - return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; + 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 { - uint32_t* entry=array_get(&(s->fat),cluster); - return le32_to_cpu(*entry); + const uint8_t* x=s->fat.pointer+cluster*3/2; + return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; } } @@ -410,69 +551,32 @@ static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry) static inline void init_fat(BDRVVVFATState* s) { - int i; - - array_init(&(s->fat),(s->fat_type==32?4:2)); - array_get(&(s->fat),s->sectors_per_fat*0x200/s->fat.item_size-1); + 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); - fat_set(s,0,0x7ffffff8); - for(i=1;isectors_for_directory/s->sectors_per_cluster-1;i++) - fat_set(s,i,i+1); - fat_set(s,i,0x7fffffff); - 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=0xfffffff; break; + case 32: s->max_fat_value=0x0fffffff; break; default: s->max_fat_value=0; /* error... */ } } -static inline int long2unix_name(unsigned char* dest,int dest_size,direntry_t* direntry_short) { - int i=-1,j; - int chksum=fat_chksum(direntry_short); - while(1) { - char* buf=(char*)(direntry_short+i); - if((buf[0]&0x3f)!=-i || direntry_short[i].reserved[1]!=chksum || - direntry_short[i].attributes!=0xf) { - if(i<-1) - return -3; - /* take short name */ - for(j=7;j>0 && direntry_short->name[j]==' ';j--); - if(j+1>dest_size) - return -1; - strncpy(dest,direntry_short->name,j+1); - dest+=j+1; dest_size-=j+1; - for(j=2;j>=0 && direntry_short->extension[j]==' ';j--); - if(j>=0) { - if(j+2>dest_size) - return -1; - dest[0]='.'; - strncpy(dest+1,direntry_short->extension,j+1); - } - return 0; - } - for(j=0;j<13;j++) { - dest_size--; - if(dest_size<0) - return -2; - dest[0]=buf[2*j+((j<5)?1:(j<11)?4:6)]; - if(dest[0]==0 && (buf[0]&0x40)!=0) - return 0; - dest++; - } - /* last entry, but no trailing \0? */ - if(buf[0]&0x40) - return -3; - i--; - } -} - -static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int directory_start,const char* filename,int is_dot) +/* 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,long_index=s->directory.next; + int i,j,long_index=s->directory.next; direntry_t* entry=0; direntry_t* entry_long=0; @@ -483,26 +587,28 @@ static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int d return entry; } - for(i=1;i<8 && filename[i] && filename[i]!='.';i++); - 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(filename[i]) { - int len=strlen(filename); - for(i=len;i>0 && filename[i-1]!='.';i--); - if(i>0) - memcpy(entry->extension,filename+i,(len-i>3?3:len-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>1 && entry->name[i]==' ';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])) + || strchr(".*?<>|\":/\\[];,+='",entry->name[i])) entry->name[i]='_'; else if(entry->name[i]>='a' && entry->name[i]<='z') entry->name[i]+='A'-'a'; @@ -514,7 +620,7 @@ static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int d int j; for(;entry1attributes&0xf) && !memcmp(entry1->name,entry->name,11)) + if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11)) break; /* found dupe */ if(entry1==entry) /* no dupe found */ break; @@ -543,8 +649,7 @@ static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int d /* calculate anew, because realloc could have taken place */ entry_long=array_get(&(s->directory),long_index); - while(entry_longattributes==0xf) { + while(entry_longreserved[1]=chksum; entry_long++; } @@ -553,33 +658,48 @@ static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int d return entry; } -static int read_directory(BDRVVVFATState* s,const char* dirname, - int first_cluster_of_parent) +/* + * 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; - struct stat st; - unsigned int start_of_directory=s->directory.next; - /* mappings before first_file_mapping are directories */ - unsigned int first_directory_mapping=s->first_file_mapping; - unsigned int first_cluster=(start_of_directory/0x10/s->sectors_per_cluster); int i; - if(!dir) + 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(start_of_directory==1 && (is_dotdot || is_dot)) + 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) { @@ -588,8 +708,8 @@ static int read_directory(BDRVVVFATState* s,const char* dirname, } /* create directory entry for this file */ - //fprintf(stderr,"create direntry at %d (cluster %d) for %s\n",s->directory.next,s->directory.next/0x10/s->sectors_per_cluster,entry->d_name); - direntry=create_short_filename(s,start_of_directory,entry->d_name,is_dot||is_dotdot); + 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); @@ -599,25 +719,40 @@ static int read_directory(BDRVVVFATState* s,const char* dirname, direntry->mtime=fat_datetime(st.st_mtime,1); direntry->mdate=fat_datetime(st.st_mtime,0); if(is_dotdot) - direntry->begin=cpu_to_le16(first_cluster_of_parent); + set_begin_of_direntry(direntry, first_cluster_of_parent); else if(is_dot) - direntry->begin=cpu_to_le16(first_cluster); + set_begin_of_direntry(direntry, first_cluster); else - direntry->begin=cpu_to_le16(0); /* do that later */ - direntry->size=cpu_to_le32(st.st_size); + 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) { - if(S_ISDIR(st.st_mode)) - s->current_mapping=(mapping_t*)array_insert(&(s->mapping),s->first_file_mapping++,1); - else - s->current_mapping=(mapping_t*)array_get_next(&(s->mapping)); + 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; - s->current_mapping->offset=0; - s->current_mapping->filename=buffer; + /* + * 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->mode=(S_ISDIR(st.st_mode)?MODE_DIRECTORY:MODE_UNDEFINED); + 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); @@ -628,89 +763,78 @@ static int read_directory(BDRVVVFATState* s,const char* dirname, memset(direntry,0,sizeof(direntry_t)); } - /* reserve next cluster also (for new files) */ - for(i=0;i<0x10*s->sectors_per_cluster;i++) { - direntry_t* direntry=array_get_next(&(s->directory)); - memset(direntry,0,sizeof(direntry_t)); - } - - /* was it the first directory? */ - if(start_of_directory==1) { - mapping_t* mapping=array_insert(&(s->mapping),0,1); - mapping->filename=strdup(dirname); - mapping->mode=MODE_DIRECTORY; - mapping->begin=0; - mapping->end=1; - mapping->offset=0; - mapping->dir_index=0xffffffff; - s->sectors_of_root_directory=s->directory.next/0x10; +/* 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; +} - /* recurse directories */ - { - int i; - - //fprintf(stderr,"iterating subdirectories of %s (first cluster %d): %d to %d\n",dirname,first_cluster,first_directory_mapping,last_directory_mapping); - for(i=first_directory_mapping;ifirst_file_mapping;i++) { - mapping_t* mapping=array_get(&(s->mapping),i); - direntry_t* direntry=array_get(&(s->directory),mapping->dir_index); - /* the directory to be read can add more subdirectories */ - int last_dir_mapping=s->first_file_mapping; - - assert(mapping->mode==MODE_DIRECTORY); - /* first, tell the mapping where the directory will start */ - mapping->begin=s->directory.next/0x10/s->sectors_per_cluster; - if(i>0) { - mapping[-1].end=mapping->begin; - assert(mapping[-1].beginbegin); - } - /* then tell the direntry */ - direntry->begin=cpu_to_le16(mapping->begin); - //fprintf(stderr,"read directory %s (begin %d)\n",mapping->filename,(int)mapping->begin); - /* then read it */ - if(read_directory(s,mapping->filename,first_cluster)) - return -1; - - if(last_dir_mapping!=s->first_file_mapping) { - int diff=s->first_file_mapping-last_dir_mapping; - assert(diff>0); +static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) +{ + return (sector_num-s->faked_sectors)/s->sectors_per_cluster; +} - if(last_dir_mapping!=i+1) { - int count=last_dir_mapping-i-1; - int to=s->first_file_mapping-count; +static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num) +{ + return s->faked_sectors + s->sectors_per_cluster * cluster_num; +} - assert(count>0); - assert(to>i+1); - array_roll(&(s->mapping),to,i+1,count); - /* could have changed due to realloc */ - mapping=array_get(&(s->mapping),i); - mapping->end=mapping[1].begin; - } - i+=diff; - } - } - } +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; +} - return 0; +#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_directory(BDRVVVFATState* s,const char* dirname) +static int init_directories(BDRVVVFATState* s, + const char* dirname) { - bootsector_t* bootsector=(bootsector_t*)&(s->first_sectors[(s->first_sectors_number-1)*0x200]); + bootsector_t* bootsector; + mapping_t* mapping; unsigned int i; unsigned int cluster; memset(&(s->first_sectors[0]),0,0x40*0x200); - /* TODO: if FAT32, this is probably wrong */ - s->sectors_per_fat=0xec; - s->sectors_per_cluster=0x10; s->cluster_size=s->sectors_per_cluster*0x200; - s->cluster=malloc(s->cluster_size); + 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)); - array_init(&(s->commit),sizeof(commit_t)); /* add volume label */ { @@ -719,69 +843,86 @@ static int init_directory(BDRVVVFATState* s,const char* dirname) snprintf(entry->name,11,"QEMU VVFAT"); } - if(read_directory(s,dirname,0)) - return -1; - - /* make sure that the number of directory entries is multiple of 0x200/0x20 (to fit the last sector exactly) */ - s->sectors_for_directory=s->directory.next/0x10; - - s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2+s->sectors_for_directory; - s->cluster_count=(s->sector_count-s->faked_sectors)/s->sectors_per_cluster; - /* Now build FAT, and write back information into directory */ init_fat(s); - cluster=s->sectors_for_directory/s->sectors_per_cluster; - assert(s->sectors_for_directory%s->sectors_per_cluster==0); - - /* set the end of the last read directory */ - if(s->first_file_mapping>0) { - mapping_t* mapping=array_get(&(s->mapping),s->first_file_mapping-1); - mapping->end=cluster; - } - - for(i=1;imapping.next;i++) { - mapping_t* mapping=array_get(&(s->mapping),i); - direntry_t* direntry=array_get(&(s->directory),mapping->dir_index); - if(mapping->mode==MODE_DIRECTORY) { - /* directory */ - int i; -#ifdef DEBUG - fprintf(stderr,"assert: %s %d < %d\n",mapping->filename,(int)mapping->begin,(int)mapping->end); -#endif - assert(mapping->beginend); - for(i=mapping->begin;iend-1;i++) - fat_set(s,i,i+1); - fat_set(s,i,0x7fffffff); - } else { - /* as the space is virtual, we can be sloppy about it */ - unsigned int end_cluster=cluster+mapping->end/s->cluster_size; - - if(end_cluster>=s->cluster_count) { - fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type); + 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->begin=cluster; + mapping = array_get(&(s->mapping), i); + } else { + assert(mapping->mode == MODE_UNDEFINED); mapping->mode=MODE_NORMAL; - mapping->offset=0; - direntry->size=cpu_to_le32(mapping->end); - if(direntry->size==0) { - direntry->begin=0; - mapping->end=cluster; - continue; + 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; - direntry->begin=cpu_to_le16(cluster); - mapping->end=end_cluster+1; - for(;cluster s->cluster_count) { + fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type); + return -1; } } - s->current_mapping=0; + 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; @@ -791,17 +932,17 @@ static int init_directory(BDRVVVFATState* s,const char* dirname) 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->zero=0; - bootsector->media_type=(s->first_sectors_number==1?0xf0:0xf8); /* media descriptor */ + 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(0x3f); - bootsector->number_of_heads=cpu_to_le16(0x10); + 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); - /* TODO: if FAT32, adjust */ - bootsector->total_sectors=cpu_to_le32(s->sector_count); + bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); - /* TODO: if FAT32, this is wrong */ - bootsector->u.fat16.drive_number=0x80; /* assume this is hda (TODO) */ + /* 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); @@ -813,52 +954,106 @@ static int init_directory(BDRVVVFATState* s,const char* dirname) return 0; } +static BDRVVVFATState *vvv = NULL; + +static int enable_write_target(BDRVVVFATState *s); +static int is_consistent(BDRVVVFATState *s); + static int vvfat_open(BlockDriverState *bs, const char* dirname) { BDRVVVFATState *s = bs->opaque; + int floppy = 0; int i; - /* TODO: automatically determine which FAT type */ + vvv = s; + +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_file_mapping=0; - /* TODO: if simulating a floppy, this is 1, because there is no partition table */ 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:", &dirname)) { - /* read only is the default for safety */ - bs->read_only = 1; - } else if (strstart(dirname, "fatrw:", &dirname)) { - /* development only for now */ - bs->read_only = 0; - } else { - return -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; } - if(init_directory(s,dirname)) + + 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); - /* TODO: this could be wrong for FAT32 */ - bs->cyls=1023; bs->heads=15; bs->secs=63; - bs->total_sectors=bs->cyls*bs->heads*bs->secs; + /* 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)); - /* write support */ - for(i=0;i<3;i++) - s->action[i]=WRITE_UNDEFINED; return 0; } static inline void vvfat_close_current_file(BDRVVVFATState *s) { if(s->current_mapping) { - s->current_mapping = 0; - close(s->current_fd); + 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 @@ -867,23 +1062,27 @@ static inline void vvfat_close_current_file(BDRVVVFATState *s) static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2) { int index3=index1+1; - //fprintf(stderr,"find_aux: cluster_num=%d, index1=%d,index2=%d\n",cluster_num,index1,index2); while(1) { mapping_t* mapping; index3=(index1+index2)/2; mapping=array_get(&(s->mapping),index3); - //fprintf(stderr,"index3: %d = (%d+%d)/2, end: %d\n",index3,index1,index2,(int)mapping->end); - if(mapping->end>cluster_num) { + assert(mapping->begin < mapping->end); + if(mapping->begin>=cluster_num) { assert(index2!=index3 || index2==0); if(index2==index3) - return index2; + return index1; index2=index3; } else { if(index1==index3) - return index2; + 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))); } } @@ -896,24 +1095,41 @@ static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_ mapping=array_get(&(s->mapping),index); if(mapping->begin>cluster_num) return 0; + assert(mapping->begin<=cluster_num && mapping->end>cluster_num); return mapping; } -static int open_file(BDRVVVFATState* s,mapping_t* mapping,int flags) +/* + * 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; - assert(flags==O_RDONLY || flags==O_RDWR); if(!s->current_mapping || - strcmp(s->current_mapping->filename,mapping->filename) || - (flags==O_RDWR && !s->current_fd_is_writable)) { + strcmp(s->current_mapping->path,mapping->path)) { /* open file */ - int fd = open(mapping->filename, flags | O_BINARY | O_LARGEFILE); + 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_fd_is_writable = (flags==O_RDWR?-1:0); s->current_mapping = mapping; } return 0; @@ -924,18 +1140,39 @@ 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); - if(open_file(s,mapping,O_RDONLY)) + + assert(!mapping || (cluster_num>=mapping->begin && cluster_numend)); + + 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; - offset=s->cluster_size*(cluster_num-s->current_mapping->begin+s->current_mapping->offset); + 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; @@ -946,774 +1183,1565 @@ static inline int read_cluster(BDRVVVFATState *s,int cluster_num) return 0; } -static int vvfat_read(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors) +#ifdef DEBUG +static void hexdump(const void* address, uint32_t len) { - BDRVVVFATState *s = bs->opaque; - int i; - - // fprintf(stderr,"vvfat_read: sector %d+%d\n",(int)sector_num,nb_sectors); - - for(i=0;ifaked_sectors) { - if(sector_numfirst_sectors_number) - memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200); - else if(sector_num-s->first_sectors_numbersectors_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_fatsectors_per_fat) - memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200); - else if(sector_num-s->first_sectors_number-s->sectors_per_fat*2sectors_for_directory) - memcpy(buf+i*0x200,&(s->directory.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat*2)*0x200]),0x200); - } else { - uint32_t sector=sector_num-s->first_sectors_number-s->sectors_per_fat*2, - sector_offset_in_cluster=(sector%s->sectors_per_cluster), - cluster_num=sector/s->sectors_per_cluster; - if(read_cluster(s, cluster_num) != 0) { - //fprintf(stderr,"failed to read cluster %d\n",(int)cluster_num); - // TODO: strict: return -1; - memset(buf+i*0x200,0,0x200); - continue; - } - memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200); - } + 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"); } - return 0; } -static void print_direntry(direntry_t* direntry) +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(direntry->attributes==0xf) { + 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) - fputc(c[i],stderr); +#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) - fputc(c[i],stderr); + ADD_CHAR(c[i]); for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2) - fputc(c[i],stderr); - fputc('\n',stderr); + ADD_CHAR(c[i]); + buffer[j] = 0; + fprintf(stderr, "%s\n", buffer); } else { int i; for(i=0;i<11;i++) - fputc(direntry->name[i],stderr); - fprintf(stderr,"attributes=0x%02x begin=%d size=%d\n", + ADD_CHAR(direntry->name[i]); + buffer[j] = 0; + fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n", + buffer, direntry->attributes, - direntry->begin,direntry->size); + begin_of_direntry(direntry),le32_to_cpu(direntry->size)); } } -static void print_changed_sector(BlockDriverState *bs,int64_t sector_num,const uint8_t *buf) +static void print_mapping(const mapping_t* mapping) { - BDRVVVFATState *s = bs->opaque; - - if(sector_numfirst_sectors_number) - return; - if(sector_numfirst_sectors_number+s->sectors_per_fat*2) { - int first=((sector_num-s->first_sectors_number)%s->sectors_per_fat); - int first_fat_entry=first*0x200/2; - int i; - - fprintf(stderr, "fat:\n"); - for(i=0;i<0x200;i+=2) { - uint16_t* f=array_get(&(s->fat),first_fat_entry+i/2); - if(memcmp(buf+i,f,2)) - fprintf(stderr,"%d(%d->%d) ",first_fat_entry+i/2,*f,*(uint16_t*)(buf+i)); - } - fprintf(stderr, "\n"); - } else if(sector_numfaked_sectors) { - direntry_t* d=(direntry_t*)buf; - int i; - fprintf(stderr, "directory:\n"); - for(i=0;i<0x200/sizeof(direntry_t);i++) { - direntry_t* d_old=(direntry_t*)(s->directory.pointer+0x200*(sector_num-s->first_sectors_number-s->sectors_per_fat*2)+i*sizeof(direntry_t)); - if(memcmp(d+i,d_old,sizeof(direntry_t))) { - fprintf(stderr, "old: "); print_direntry(d_old); - fprintf(stderr, "new: "); print_direntry(d+i); - fprintf(stderr, "\n"); - } - } - } else { - int sec=(sector_num-s->first_sectors_number-2*s->sectors_per_fat); - fprintf(stderr, "\tcluster: %d(+%d sectors)\n",sec/s->sectors_per_cluster,sec%s->sectors_per_cluster); - } + 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 -char direntry_is_free(const direntry_t* direntry) +static int vvfat_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) { - return direntry->name[0]==0 || direntry->name[0]==0xe5; -} - -/* TODO: use this everywhere */ -static inline uint32_t begin_of_direntry(direntry_t* direntry) -{ - return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16); -} - -int consistency_check1(BDRVVVFATState *s) { - /* check all mappings */ + BDRVVVFATState *s = bs->opaque; int i; - for(i=0;imapping.next;i++) { - mapping_t* mapping=array_get(&(s->mapping),i); - int j; - for(j=mapping->begin;jend-1;j++) - assert(fat_get(s,j)==j+1); - assert(fat_get(s,j)==(0x7fffffff&s->max_fat_value)); - } - return 0; -} -int consistency_check2(BDRVVVFATState *s) { - /* check fat entries: consecutive fat entries should be mapped in one mapping */ - int i; - /* TODO: i=0 (mappings for direntries have to be sorted) */ - for(i=s->sectors_for_directory/s->sectors_per_cluster;ifat.next-1;i++) { - uint32_t j=fat_get(s,i); - if(j!=i+1 && j!=0 && !fat_eof(s,j)) { - mapping_t* mapping=find_mapping_for_cluster(s,i+1); - assert(mapping->begin==i+1); + for(i=0;i= 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)); } - } - return 0; -} - -int consistency_check3(BDRVVVFATState *s) { - /* check that for each file there is exactly one mapping per cluster */ - int i,count_non_next=0; - for(i=0;imapping.next;i++) { - mapping_t* mapping=array_get(&(s->mapping),i); - /* TODO: when directories are correctly adapted, add them here */ - assert(mapping->beginend); - if(mapping->mode==MODE_NORMAL) { - int j,count=0,count_next=0; - for(j=0;jmapping.next;j++) { - mapping_t* other=array_get(&(s->mapping),j); - if(mapping->beginend&&mapping->end>other->begin) - count++; - if(mapping->end==other->begin) - count_next++; + if(sector_numfaked_sectors) { + if(sector_numfirst_sectors_number) + memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200); + else if(sector_num-s->first_sectors_numbersectors_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_fatsectors_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; } - assert(count==1); /* no overlapping mappings */ - assert(count_next==1 || count_next==0); /* every mapping except the last one has a successor */ - if(!count_next) - count_non_next++; + memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200); } } - assert(count_non_next==1); /* only one last mapping */ return 0; } -static inline commit_t* commit_get_next(BDRVVVFATState* s) -{ - commit_t* commit=array_get_next(&(s->commit)); - if((commit->buf=malloc(s->cluster_size))==0) { - /* out of memory */ - s->commit.next--; - return 0; - } - return commit; -} +/* LATER TODO: statify all functions */ -int commit_remove(BDRVVVFATState* s,commit_t* commit) -{ - int index=commit-(commit_t*)s->commit.pointer; - free(commit->buf); - if(array_roll(&(s->commit),s->commit.next-1,index,1)) - return -1; - s->commit.next--; - return 0; -} - -/* TODO: the plan for write support: - * - * it seems that the direntries are written first, then the data is committed - * to the free sectors, then fat 1 is updated, then fat2. - * - * Plan: when sectors are written, do the following: - * - * - if they are in a directory, check if the entry has changed. if yes, - * look what has changed (different strategies for name, begin & size). - * - * if it is new (old entry is only 0's or has E5 at the start), create it, - * and also create mapping, but in a special mode "undefined" (TODO), - * because we cannot know which clusters belong to it yet. +/* + * Idea of the write support (use snapshot): * - * if it is zeroed, or has E5 at the start, look if has just moved. If yes, - * copy the entry to the new position. If no, delete the file. + * 1. check if all data is consistent, recording renames, modifications, + * new files and directories (in s->commits). * - * - if they are in data, and the cluster is undefined, add it to the commit - * list. if the cluster is defined (find_mapping), then write it into the - * corresponding file. + * 2. if the data is not consistent, stop committing * - * If it is the last cluster (TODO: add a function - * fat_get(s,cluster); ), make sure not to write a complete cluster_size. + * 3. handle renames, and create new files and directories (do not yet + * write their contents) * - * If the data is in current_cluster, update s->cluster. + * 4. walk the directories, fixing the mapping and direntries, and marking + * the handled mappings as not deleted * - * - if they are in fat 1, update mappings, look in the commit list - * (assertions!) and if the cluster is now known (or changed from undefined - * state to defined state, like when begin or size changed in a direntry), - * write it. + * 5. commit the contents of the files * - * - if they are in fat 2, make sure they match with current fat. + * 6. handle deleted files and directories * */ -void mapping_modify_from_direntry(BDRVVVFATState* s,mapping_t* mapping,direntry_t* direntry) -{ - int begin=le16_to_cpu(direntry->begin), - end=begin+le32_to_cpu(direntry->size)/s->cluster_size+1, - i; - mapping->mode = MODE_MODIFIED; - /* TODO: what if begin==0 (size==0)? */ - mapping->begin = begin; - /* TODO: why not just mapping->end = begin+1 ? */ - for(i=begin+1;iend = i; -} +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; -mapping_t* find_mapping_for_direntry(BDRVVVFATState* s,direntry_t* direntry) +static void clear_commits(BDRVVVFATState* s) { int i; - int dir_index=direntry-((direntry_t*)s->directory.pointer); - - /* TODO: support allocation for new clusters for directories (new/larger directory */ - assert(dir_index<0x200/0x20*s->sectors_for_directory); - - for(i=0;imapping.next;i++) { - mapping_t* mapping=array_get(&(s->mapping),i); - if(mapping->dir_index==dir_index && mapping->offset==0 && - mapping->mode!=MODE_UNDEFINED) - return mapping; +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); } - return 0; + s->commits.next = 0; } -static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) +static void schedule_rename(BDRVVVFATState* s, + uint32_t cluster, char* new_path) { - return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)/s->sectors_per_cluster; + commit_t* commit = array_get_next(&(s->commits)); + commit->path = new_path; + commit->param.rename.cluster = cluster; + commit->action = ACTION_RENAME; } -static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num) +static void schedule_writeout(BDRVVVFATState* s, + int dir_index, uint32_t modified_offset) { - return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster; + 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 commit_t* get_commit_for_cluster(BDRVVVFATState* s,uint32_t cluster_num) +static void schedule_new_file(BDRVVVFATState* s, + char* path, uint32_t first_cluster) { - int i; - for(i=0;icommit.next;i++) { - commit_t* commit=array_get(&(s->commit),i); - if(commit->cluster_num==cluster_num) - return commit; + 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; } -static inline commit_t* create_or_get_commit_for_sector(BDRVVVFATState* s,off_t sector_num) +/* 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; - commit_t* commit; - uint32_t cluster_num=sector2cluster(s,sector_num); + int i, j; - for(i=0;icommit.next;i++) { - commit=array_get(&(s->commit),i); - if(commit->cluster_num==cluster_num) - return commit; + 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]; } - commit=commit_get_next(s); - commit->cluster_num=cluster_num; - /* we can ignore read errors here */ - read_cluster(s,cluster_num); - memcpy(commit->buf,s->cluster,s->cluster_size); - return commit; + 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 direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping) +static inline uint32_t modified_fat_get(BDRVVVFATState* s, + unsigned int cluster) { - if(mapping->mode==MODE_UNDEFINED) - return 0; - if(mapping->dir_index>=0x200/0x20*s->sectors_for_directory) + 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; - return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index); + + 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 void print_mappings(BDRVVVFATState* s) +static const char* get_basename(const char* path) { - int i; - fprintf(stderr,"mapping:\n"); - for(i=0;imapping.next;i++) { - mapping_t* m=array_get(&(s->mapping),i); - direntry_t* d=get_direntry_for_mapping(s,m); - fprintf(stderr,"%02d %d-%d (%d) %s (dir: %d)",i,(int)m->begin,(int)m->end,(int)m->offset,m->filename,m->dir_index); - print_direntry(d); - fprintf(stderr,"\n"); - } - fprintf(stderr,"mappings end.\n"); + char* basename = strrchr(path, '/'); + if (basename == NULL) + return path; + else + return basename + 1; /* strip '/' */ } -/* TODO: statify all functions */ +/* + * 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; -/* This function is only meant for file contents. - * It will return an error if used for other sectors. */ -static int write_cluster(BDRVVVFATState* s,uint32_t cluster_num,const uint8_t* buf) +/* + * 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) { - /* sector_offset is the sector_num relative to the first cluster */ - mapping_t* mapping=find_mapping_for_cluster(s,cluster_num); - direntry_t* direntry; - int next_cluster,write_size,last_cluster; - off_t offset; + /* + * 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; - /* if this cluster is free, return error */ - next_cluster=fat_get(s,cluster_num); - if(next_cluster<2) - return -1; - - /* TODO: MODE_DIRECTORY */ - if(!mapping || mapping->mode==MODE_UNDEFINED || mapping->mode==MODE_DIRECTORY) - return -1; - direntry=get_direntry_for_mapping(s,mapping); - if(!direntry) - return -2; + vvfat_close_current_file(s); - /* get size to write */ - last_cluster=fat_eof(s,next_cluster); - write_size=!last_cluster?s->cluster_size: - (le32_to_cpu(direntry->size)%s->cluster_size); - if(write_size<=0) + /* the root directory */ + if (cluster_num == 0) return 0; - //fprintf(stderr,"next_cluster: %d (%d), write_size: %d, %d, %d\n",next_cluster,s->max_fat_value-8,write_size,direntry->size,s->cluster_size); - if(open_file(s,mapping,O_RDWR)) - return -4; - - offset=(cluster_num-mapping->begin+mapping->offset)*s->cluster_size; - if(lseek(s->current_fd,offset,SEEK_SET)!=offset) - return -3; - if(write(s->current_fd,buf,write_size)!=write_size) { - lseek(s->current_fd,0,SEEK_END); - vvfat_close_current_file(s); - return -2; - } + /* write support */ + if (s->qcow) { + basename2 = get_basename(path); - /* seek to end of file, so it doesn't get truncated */ - if(!last_cluster) - lseek(s->current_fd,0,SEEK_END); - else { - ftruncate(s->current_fd,le32_to_cpu(direntry->size)); - vvfat_close_current_file(s); + mapping = find_mapping_for_cluster(s, cluster_num); + + if (mapping) { + assert(mapping->mode & MODE_DELETED); + mapping->mode &= ~MODE_DELETED; + + const char* 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; + } } - /* update s->cluster if necessary */ - if(cluster_num==s->current_cluster && s->cluster!=buf) - memcpy(s->cluster,buf,s->cluster_size); + 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); - return 0; + + 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 returns !=0 on error */ -int mapping_is_consistent(BDRVVVFATState* s,mapping_t* mapping) +/* + * 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) { - direntry_t* direntry=get_direntry_for_mapping(s,mapping); - uint32_t cluster_count=0; - int commit_count=0; /* number of commits for this file (we also write incomplete files; think "append") */ - //fprintf(stderr,"check direntry for %s\n",mapping->filename); - while(mapping) { + 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; - assert(mapping->beginend); - for(i=mapping->begin;iend-1;i++) { - if(i<=0 || fat_get(s,i)!=i+1) { - /*fprintf(stderr,"the fat mapping of %d is not %d, but %d\n", - i,i+1,fat_get(s,i));*/ - return -1; + 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(get_commit_for_cluster(s,i)) - commit_count++; + 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; } - if(get_commit_for_cluster(s,i)) - commit_count++; - cluster_count+=mapping->end-mapping->begin; - - i=fat_get(s,mapping->end-1); - if(fat_eof(s,i)) - break; + cluster_num = modified_fat_get(s, cluster_num); + } while(!fat_eof(s, cluster_num)); - mapping=find_mapping_for_cluster(s,i); - if(!mapping) { - //fprintf(stderr,"No mapping found for %d\n",i); - print_mappings(s); - return -2; + 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; } - if(cluster_count!=(le32_to_cpu(direntry->size)+s->cluster_size-1)/s->cluster_size) { - //fprintf(stderr,"cluster_count is %d, but size is %d\n",cluster_count,le32_to_cpu(direntry->size)); - return -3; + 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; - if(commit_count==0) - return -4; +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); - //fprintf(stderr,"okay\n"); return 0; } -/* TODO: remember what comes third, and what's first in this OS: - * FAT, direntry or data. - * If the last written sector is either last in cluster or sector_num+nb_sectors-1, - * - commit every cluster for this file if mapping_is_consistent()==0 - * - if the last written sector is first_action, and last_action=third_action, clear commit - */ +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 int commit_cluster_aux(BDRVVVFATState* s,commit_t* commit) +static direntry_t* insert_direntries(BDRVVVFATState* s, + int dir_index, int count) { - int result=write_cluster(s,commit->cluster_num,commit->buf); + /* + * 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; +} -static int commit_cluster(BDRVVVFATState* s,uint32_t cluster_num) +/* + * 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) { - commit_t* commit; + 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; + } - /* commit the sectors of this cluster */ - commit=get_commit_for_cluster(s,cluster_num); - if(commit) - return commit_cluster_aux(s,commit); return 0; } -/* this function checks the consistency for the direntry which belongs to - * the mapping. if everything is found consistent, the data is committed. - * this returns 0 if no error occurred (even if inconsistencies were found) */ -static inline int commit_data_if_consistent(BDRVVVFATState* s,mapping_t* mapping,write_action_t action) +static int commit_direntries(BDRVVVFATState* s, + int dir_index, int parent_mapping_index) { - direntry_t* direntry; - - if(!mapping) - return 0; + 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++; - //fprintf(stderr,"7\n"); -#define d(x) fprintf(stderr,#x "\n") - direntry=get_direntry_for_mapping(s,mapping); + for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c); + c = modified_fat_get(s, c)) + new_cluster_count++; + } - //d(8); + 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; + } - assert(action==WRITE_FAT || action==WRITE_DIRENTRY || action==WRITE_DATA); + 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; + } + } - //d(9); - //fprintf(stderr,"mapping: 0x%x s=0x%x\n",(uint32_t)mapping,(uint32_t)s); - /*fprintf(stderr,"commit? file=%s, action=%s\n", - mapping->filename,action==WRITE_FAT?"fat":action==WRITE_DIRENTRY?"direntry":"data");*/ + return 0; +} - //d(10); - if(s->action[2]==WRITE_UNDEFINED) { - int i; - for(i=2;i>0 && s->action[i-1]==WRITE_UNDEFINED;i--); - if(i>0 && action!=s->action[i-1]) - s->action[i]=action; - assert(i<2 || s->action[0]!=s->action[2]); +/* 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, 0666); + if (fd < 0) { + fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path, + strerror(errno), errno); + return fd; } - //d(11); - - if(mapping_is_consistent(s,mapping)==0) { - uint32_t cluster_num=begin_of_direntry(direntry); - off_t remaining_bytes=le32_to_cpu(direntry->size); - //fprintf(stderr,"the data for %s was found consistent\n",mapping->filename); - while(remaining_bytes>0) { - commit_t* commit=get_commit_for_cluster(s,cluster_num); - if(!commit) - continue; - - //fprintf(stderr,"commit_cluster %d (%d), remaining: %d\n",cluster_num,s->max_fat_value-15,(int)remaining_bytes); - assert(cluster_num>1); - assert(cluster_nummax_fat_value-15); - if(commit_cluster(s,cluster_num)) { - fprintf(stderr,"error committing cluster %d\n",cluster_num); - return -1; - } - cluster_num=fat_get(s,cluster_num); - remaining_bytes-=s->cluster_size; - /* TODO: if(action==s->action[2]) { - commit_t* commit=get_commit_for_cluster(s,cluster_num); - commit_remove(s,commit); - } */ + 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); } } - //print_mappings(s); - //fprintf(stderr,"finish vvfat_write\n"); - return 0; } -static int vvfat_write(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors) +/* test, if all direntries have mappings */ +static void check2(BDRVVVFATState* s) { - BDRVVVFATState *s = bs->opaque; int i; + int first_mapping = -1; - /* fprintf(stderr,"vvfat_write %d+%d (%s)\n",(int)sector_num,nb_sectors, - (sector_num>=s->faked_sectors?"data": - (sector_num>=s->first_sectors_number+2*s->sectors_per_fat?"directory": - (sector_num>=s->first_sectors_number+s->sectors_per_fat?"fat 2": - (sector_num>=s->first_sectors_number?"fat 1":"boot sector"))))); */ + for (i = 0; i < s->directory.next; i++) { + direntry_t* direntry = array_get(&(s->directory), i); - for(i=0;idir_index == i || is_dot(direntry)); + assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry)); + } - if(sector_numfirst_sectors_number) { - /* change the bootsector or partition table? no! */ - return -1; - } else if(sector_numfirst_sectors_number+s->sectors_per_fat) { - /* FAT 1 */ - int fat_entries_per_cluster=s->cluster_size*8/s->fat_type; - int first_cluster=(sector_num-s->first_sectors_number)*fat_entries_per_cluster,i; - mapping_t* mapping=0; - - /* write back */ - memcpy(s->fat.pointer+0x200*(sector_num-s->first_sectors_number), - buf,0x200); - - /* for each changed FAT entry, */ - for(i=0;isectors_for_directory/s->sectors_per_cluster) - continue; + if ((i % (0x10 * s->sectors_per_cluster)) == 0) { + /* cluster start */ + int j, count = 0; - new_value=fat_get(s,first_cluster+i); - - /* check the current fat entry */ - if(new_value<2 || (new_value>=s->max_fat_value-0xf && !fat_eof(s,new_value))) { - /* free, reserved or bad cluster */ - mapping=find_mapping_for_cluster(s,first_cluster+i); - //assert(!mapping || mapping->mode==MODE_DELETED); - if(mapping && mapping->mode==MODE_DELETED && - first_cluster+i+1==mapping->end) - array_remove(&(s->mapping),mapping-(mapping_t*)s->mapping.pointer); - mapping=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 - /* get the mapping for the current entry */ - if(!mapping || mapping->begin>new_value || mapping->end<=new_value) { - mapping=find_mapping_for_cluster(s,first_cluster+i); - } +static int handle_renames_and_mkdirs(BDRVVVFATState* s) +{ + int i; - print_mappings(s); - fprintf(stderr,"fat_get(%d)=%d\n",first_cluster+i,new_value); - /* TODO: what if there's no mapping? this is valid. */ - /* TODO: refactor the rest of this clause so it can be called when the direntry changes, too */ - assert(mapping); - - if(new_value>1 && new_valuemax_fat_value-0xf) { - /* the cluster new_value points to is valid */ - - if(first_cluster+i+1==new_value) { - /* consecutive cluster */ - if(mapping->end<=new_value) - mapping->end=new_value+1; - } else { - mapping_t* next_mapping; - - /* the current mapping ends here */ - mapping->end=first_cluster+i+1; - - /* the next mapping */ - next_mapping=find_mapping_for_cluster(s,new_value); - if(next_mapping) { - assert(mapping!=next_mapping); - /* assert next mapping's filename is the same */ - assert(next_mapping->filename==mapping->filename); - assert(next_mapping->dir_index==mapping->dir_index); - /* assert next mapping is MODIFIED or UNDEFINED */ - assert(next_mapping->mode==MODE_MODIFIED || next_mapping->mode==MODE_UNDEFINED); - } else { - int index=find_mapping_for_cluster_aux(s,new_value,0,s->mapping.next); - next_mapping=array_insert(&(s->mapping),index,1); - next_mapping->filename=mapping->filename; - next_mapping->dir_index=mapping->dir_index; - next_mapping->mode=MODE_MODIFIED; - next_mapping->begin=0; - } - /* adjust offset of next mapping */ - next_mapping->offset=mapping->offset+mapping->end-mapping->begin; - /* set begin and possible end */ - if(next_mapping->begin!=new_value) { - next_mapping->begin=new_value; - next_mapping->end=new_value+1; +#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); } - if(commit_data_if_consistent(s,mapping,WRITE_FAT)) - return -4; - mapping=0; - } - } else if(fat_eof(s,new_value)) { - /* the last cluster of the file */ - mapping->end=first_cluster+i+1; - if(commit_data_if_consistent(s,mapping,WRITE_FAT)) - return -4; - mapping=0; + i++; + } while((i % (0x10 * s->sectors_per_cluster)) != 0); + c = fat_get(s, c); } } - } else if(sector_numfirst_sectors_number+2*s->sectors_per_fat) { - /* FAT 2: check if it is the same as FAT 1 */ - if(memcmp(array_get(&(s->fat),sector_num-s->first_sectors_number),buf,0x200)) - return -1; /* mismatch */ - } else if(sector_numfaked_sectors) { - /* direntry */ - /* - if they are in a directory, check if the entry has changed. - * if yes, look what has changed (different strategies for name, - * begin & size). - * - * if it is new (old entry is only 0's or has E5 at the start), - * create it, and also create mapping, but in a special mode - * "undefined", because we cannot know which clusters belong - * to it yet. - * - * if it is zeroed, or has E5 at the start, look if has just - * moved. If yes, copy the entry to the new position. If no, - * delete the file. - */ - mapping_t* dir_mapping=find_mapping_for_cluster(s,sector2cluster(s,sector_num)); - direntry_t *original=array_get(&(s->directory),sector_num-s->first_sectors_number-2*s->sectors_per_fat); - direntry_t *new_=(direntry_t*)buf; - int first_dir_index=(sector_num-s->first_sectors_number-2*s->sectors_per_fat)*0x200/0x20; - int j; -#if 0 - fprintf(stderr,"direntry: consistency check\n"); + free(old_path); + array_remove(&(s->commits), i); + continue; + } else if (commit->action == ACTION_MKDIR) { + mapping_t* mapping; + int j, parent_path_len; + + if (mkdir(commit->path, 0755)) + return -5; + + 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; - if(s->commit.next==0) { - consistency_check1(s); - consistency_check2(s); - consistency_check3(s); + /* 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; } -#endif - assert(sizeof(direntry_t)==0x20); - - for(j=0;j<0x200/0x20;j++) { - //fprintf(stderr,"compare direntry %d: 0x%x,0x%x\n",j,(uint32_t)original+j,(uint32_t)new_+j); - if(memcmp(original+j,new_+j,sizeof(direntry_t))) { - //fprintf(stderr,"different\n"); - /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */ - if(direntry_is_free(original+j)) { - mapping_t* mapping; - char buffer[4096]; - int fd,i; - - if(new_[j].attributes==0xf) - continue; /* long entry */ - - print_mappings(s); - //fprintf(stderr,"sector: %d cluster: %d\n",(int)sector_num,(int)sector2cluster(s,sector_num)); - - /* construct absolute path */ - strncpy(buffer,dir_mapping->filename,4096); - i=strlen(buffer); - if(i+2>=4096) - return -1; - buffer[i]='/'; - if(long2unix_name(buffer+i+1,4096-i-1,new_+j)) - return -2; - - /* new file/directory */ - if(new_[j].attributes&0x10) { -#ifdef _WIN32 -#define SEVENFIVEFIVE -#else -#define SEVENFIVEFIVE ,0755 -#endif - if(mkdir(buffer SEVENFIVEFIVE)) - return -3; - /* TODO: map direntry.begin as directory, together with new array_t direntries */ - assert(0); - } else { - fd=open(buffer,O_CREAT|O_EXCL,0644); - if(!fd) - return -3; - close(fd); - } + if (i >= s->directory.next) { + fail = -6; + continue; + } - /* create mapping */ - i=find_mapping_for_cluster_aux(s,begin_of_direntry(new_+j),0,s->mapping.next); - mapping=array_insert(&(s->mapping),i,1); - mapping->filename=strdup(buffer); - mapping->offset=0; - /* back pointer to direntry */ - mapping->dir_index=first_dir_index+j; - /* set mode to modified */ - mapping->mode=MODE_MODIFIED; - /* set begin to direntry.begin */ - mapping->begin=begin_of_direntry(new_+j); - /* set end to begin+1 */ - mapping->end=mapping->begin+1; - /* commit file contents */ - if(commit_data_if_consistent(s,mapping,WRITE_DIRENTRY)) { - fprintf(stderr,"error committing file contents for new file %s!\n",buffer); - return -4; + /* 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; } - } else if(direntry_is_free(new_+j)) { - assert(0); - /* TODO: delete file */ - /* TODO: write direntry */ - /* TODO: modify mapping: set mode=deleted */ - } else { - /* modified file */ - mapping_t* mapping=0; - /* if direntry.begin has changed, - * set mode to modified, - * adapt begin, - * adapt end */ - /* TODO: handle rename */ - assert(!memcmp(new_[j].name,original[j].name,11)); - //fprintf(stderr,"1\n"); - if(new_[j].begin!=original[j].begin || new_[j].size/s->cluster_size!=original[j].size/s->cluster_size) { - //fprintf(stderr,"2\n"); - mapping = find_mapping_for_direntry(s,original+j); - //fprintf(stderr,"3\n"); - if(!mapping) /* this should never happen! */ - return -2; - mapping_modify_from_direntry(s,mapping,new_+j); - //fprintf(stderr,"4\n"); - if(commit_data_if_consistent(s,mapping,WRITE_DIRENTRY)) { - fprintf(stderr,"big error\n"); - return -4; - } + + 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; } - /* TODO: handle modified times and other attributes */ + remove_direntries(s, first_dir_index, + next_dir_index - first_dir_index); - //fprintf(stderr,"5: mapping=0x%x, s=0x%x, s->mapping.pointer=0x%x\n",(uint32_t)mapping,(uint32_t)s,(uint32_t)s->mapping.pointer); - //fprintf(stderr,"6\n"); + deleted++; } + } else { + if (unlink(mapping->path)) + return -4; + deleted++; } - } - /* write back direntries */ - memcpy(original,new_,0x200); - } else { - /* data */ - off_t sector=sector_num-s->first_sectors_number-2*s->sectors_per_fat; - off_t cluster=sector/s->sectors_per_cluster; - mapping_t* mapping=find_mapping_for_cluster(s,cluster); - if(mapping && mapping->mode==MODE_DELETED) - return -3; /* this is an error: no writes to these clusters before committed */ - { - /* as of yet, undefined: put into commits */ - commit_t* commit=create_or_get_commit_for_sector(s,sector_num); - - if(!commit) - return -1; /* out of memory */ - memcpy(commit->buf+0x200*sector_offset_in_cluster(s,sector_num),buf,0x200); - - //fprintf(stderr,"mapping: 0x%x\n",(uint32_t)mapping); - if(commit_data_if_consistent(s,mapping,WRITE_DATA)) - return -4; + 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); + strcpy(s->qcow_filename, "/tmp/vl.XXXXXX"); + get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1); + 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; } @@ -1725,8 +2753,8 @@ static void vvfat_close(BlockDriverState *bs) array_free(&(s->fat)); array_free(&(s->directory)); array_free(&(s->mapping)); - if(s->cluster) - free(s->cluster); + if(s->cluster_buffer) + free(s->cluster_buffer); } BlockDriver bdrv_vvfat = { @@ -1737,6 +2765,36 @@ BlockDriver bdrv_vvfat = { vvfat_read, vvfat_write, vvfat_close, + NULL, + vvfat_is_allocated }; +#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 -- cgit v1.2.3 From 2c6cadd49ee86bf2df6bf61c614258dfd97f7115 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 18:31:45 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1718 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ qemu-doc.texi | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/Changelog b/Changelog index 6e42ec76c..9fa027945 100644 --- a/Changelog +++ b/Changelog @@ -17,6 +17,8 @@ version 0.7.3: - 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: diff --git a/qemu-doc.texi b/qemu-doc.texi index f970b2a59..41227977b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -755,6 +755,39 @@ command (or @key{C-a s} in the serial console). @include qemu-img.texi +@subsection Virtual FAT disk images + +QEMU can automatically create a virtual FAT disk image from a +directory tree. In order to use it, just type: + +@example +qemu linux.img -hdb fat:/my_directory +@end example + +Then you access access to all the files in the @file{/my_directory} +directory without having to copy them in a disk image or to export +them via SAMBA or NFS. The default access is @emph{read-only}. + +Floppies can be emulated with the @code{:floppy:} option: + +@example +qemu linux.img -fda fat:floppy:/my_directory +@end example + +A read/write support is available for testing (beta stage) with the +@code{:rw:} option: + +@example +qemu linux.img -fda fat:floppy:rw:/my_directory +@end example + +What you should @emph{never} do: +@itemize +@item use non-ASCII filenames ; +@item use "-snapshot" together with ":rw:" ; +@item expect it to work when loadvm'ing. +@end itemize + @section Network emulation QEMU can simulate several networks cards (NE2000 boards on the PC -- cgit v1.2.3 From 91fc2119745dd3cdd70570c65f05296958da1542 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 19:09:37 +0000 Subject: avoid echo on pty devices (David Decotigny) - fixes in the command line help git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1719 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 21dca789a..6f01077d3 100644 --- a/vl.c +++ b/vl.c @@ -1398,6 +1398,7 @@ CharDriverState *qemu_chr_open_stdio(void) #if defined(__linux__) CharDriverState *qemu_chr_open_pty(void) { + struct termios tty; char slave_name[1024]; int master_fd, slave_fd; @@ -1405,6 +1406,14 @@ CharDriverState *qemu_chr_open_pty(void) if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { return NULL; } + + /* Disabling local echo and line-buffered output */ + tcgetattr (master_fd, &tty); + tty.c_lflag &= ~(ECHO|ICANON|ISIG); + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + tcsetattr (master_fd, TCSAFLUSH, &tty); + fprintf(stderr, "char device redirected to %s\n", slave_name); return qemu_chr_open_fd(master_fd, master_fd); } @@ -3962,12 +3971,13 @@ void help(void) "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" "-m megs set virtual RAM size to megs MB [default=%d]\n" + "-smp n set the number of CPUs to 'n' [default=1]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" #ifndef _WIN32 "-k language use keyboard layout (for example \"fr\" for French)\n" #endif #ifdef HAS_AUDIO - "-enable-audio enable audio support, and all the sound cars\n" + "-enable-audio enable audio support, and all the sound cards\n" "-audio-help print list of audio drivers and their options\n" "-soundhw c1,... enable audio support\n" " and only specified sound cards (comma separated list)\n" -- cgit v1.2.3 From 2efc32658e7517e8e555a31fe99303757cb6bbb5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 19:14:49 +0000 Subject: better help option support (Bernhard Fischer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1720 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/configure b/configure index efd2679ce..3471193ed 100755 --- a/configure +++ b/configure @@ -147,6 +147,8 @@ fi for opt do case "$opt" in + --help|-h) show_help=yes + ;; --prefix=*) prefix=`echo $opt | cut -d '=' -f 2` ;; --interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2` @@ -348,7 +350,7 @@ fi # sdl compile test fi # cross compilation fi # -z $sdl -if test x"$1" = x"-h" -o x"$1" = x"--help" ; then +if test x"$show_help" = x"yes" ; then cat << EOF Usage: configure [options] @@ -370,7 +372,7 @@ echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]" echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" echo " --cc=CC use C compiler CC [$cc]" -echo " --host-cc=CC use C compiler CC [$cc] for dyngen etc." +echo " --host-cc=CC use C compiler CC [$host_cc] for dyngen etc." echo " --make=MAKE use specified make [$make]" echo " --static enable static build [$static]" echo " --enable-mingw32 enable Win32 cross compilation with mingw32" -- cgit v1.2.3 From 7c206a754afa8657bc5b4562b45aacd5cdab4817 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 19:18:45 +0000 Subject: (Joachim Henke) - suppress unwanted kernel logs - avoids passing modifier keys to the guest OS when typing in the Monitor - fixes the bug that the mouse cursor grab is released with _any_ modifier key (should be only ctrl+alt) - removes some code redundancies git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1721 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/cocoa.m b/cocoa.m index 895e96f98..27773e9fd 100644 --- a/cocoa.m +++ b/cocoa.m @@ -375,36 +375,39 @@ static void cocoa_refresh(DisplayState *ds) case NSFlagsChanged: { int keycode = cocoa_keycode_to_qemu([event keyCode]); - modifiers_state[keycode] = (modifiers_state[keycode] == 0) ? 1 : 0; - - if ( modifiers_state[keycode] ) { /* Keydown */ - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode & 0x7f); - } else { /* Keyup */ - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); - } - - /* emulate caps lock and num lock keyup */ - if ((keycode == 58) || (keycode == 69)) + + if (keycode) { - modifiers_state[keycode] = 0; - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); + 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_active_console(vga_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]); -- cgit v1.2.3 From 2d7a3b9d7bf8959077ad19951d7f30dc87da9838 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 19:28:08 +0000 Subject: qruncom compile fixes (initial patch by Even Rouault) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1722 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- tests/qruncom.c | 41 +++++++++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index be26243e0..59a0b6d99 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -71,7 +71,7 @@ runcom: runcom.c # NOTE: -fomit-frame-pointer is currently needed : this is a bug in libqemu qruncom: qruncom.c ../i386-user/libqemu.a - $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -I../target-i386 -I.. -I../i386-user \ + $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -I../target-i386 -I.. -I../i386-user -I../fpu \ -o $@ $< -L../i386-user -lqemu -lm # arm test diff --git a/tests/qruncom.c b/tests/qruncom.c index 92b28ea68..421e6a99f 100644 --- a/tests/qruncom.c +++ b/tests/qruncom.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "cpu.h" @@ -86,6 +87,26 @@ void *qemu_malloc(size_t size) return malloc(size); } +void *qemu_mallocz(size_t size) +{ + void *ptr; + ptr = qemu_malloc(size); + if (!ptr) + return NULL; + memset(ptr, 0, size); + return ptr; +} + +void *qemu_vmalloc(size_t size) +{ + return memalign(4096, size); +} + +void qemu_vfree(void *ptr) +{ + free(ptr); +} + void qemu_printf(const char *fmt, ...) { va_list ap; @@ -204,20 +225,20 @@ int main(int argc, char **argv) seg = (COM_BASE_ADDR - 0x100) >> 4; cpu_x86_load_seg_cache(env, R_CS, seg, - (uint8_t *)(seg << 4), 0xffff, 0); + (seg << 4), 0xffff, 0); cpu_x86_load_seg_cache(env, R_SS, seg, - (uint8_t *)(seg << 4), 0xffff, 0); + (seg << 4), 0xffff, 0); cpu_x86_load_seg_cache(env, R_DS, seg, - (uint8_t *)(seg << 4), 0xffff, 0); + (seg << 4), 0xffff, 0); cpu_x86_load_seg_cache(env, R_ES, seg, - (uint8_t *)(seg << 4), 0xffff, 0); + (seg << 4), 0xffff, 0); cpu_x86_load_seg_cache(env, R_FS, seg, - (uint8_t *)(seg << 4), 0xffff, 0); + (seg << 4), 0xffff, 0); cpu_x86_load_seg_cache(env, R_GS, seg, - (uint8_t *)(seg << 4), 0xffff, 0); + (seg << 4), 0xffff, 0); /* exception support */ - env->idt.base = (void *)idt_table; + env->idt.base = (unsigned long)idt_table; env->idt.limit = sizeof(idt_table) - 1; set_idt(0, 0); set_idt(1, 0); @@ -263,7 +284,7 @@ int main(int argc, char **argv) case EXCP0D_GPF: { int int_num, ah; - int_num = *(env->segs[R_CS].base + env->eip + 1); + int_num = *(uint8_t *)(env->segs[R_CS].base + env->eip + 1); if (int_num != 0x21) goto unknown_int; ah = (env->regs[R_EAX] >> 8) & 0xff; @@ -291,7 +312,7 @@ int main(int argc, char **argv) default: unknown_int: fprintf(stderr, "unsupported int 0x%02x\n", int_num); - cpu_dump_state(env, stderr, 0); + cpu_dump_state(env, stderr, fprintf, 0); // exit(1); } env->eip += 2; @@ -299,7 +320,7 @@ int main(int argc, char **argv) break; default: fprintf(stderr, "unhandled cpu_exec return code (0x%x)\n", ret); - cpu_dump_state(env, stderr, 0); + cpu_dump_state(env, stderr, fprintf, 0); exit(1); } } -- cgit v1.2.3 From 31febb71f47eba2a840728012b771194ef2586a3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 20:03:27 +0000 Subject: log typos git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1723 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1f123b609..164eb394a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -457,7 +457,7 @@ static inline void target_to_host_cmsg(struct msghdr *msgh, space += CMSG_SPACE(len); if (space > msgh->msg_controllen) { space -= CMSG_SPACE(len); - gemu_log("Host cmsg overflow"); + gemu_log("Host cmsg overflow\n"); break; } @@ -500,7 +500,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, space += TARGET_CMSG_SPACE(len); if (space > tswapl(target_msgh->msg_controllen)) { space -= TARGET_CMSG_SPACE(len); - gemu_log("Target cmsg overflow"); + gemu_log("Target cmsg overflow\n"); break; } -- cgit v1.2.3 From 3f9f3aa1ca1322edb565d4efc3ad14dcebd2ec21 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 20:11:37 +0000 Subject: MIPS, ARM and SMP updates git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1724 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 79 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 19 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 41227977b..244781e3c 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -22,9 +22,9 @@ QEMU has two operating modes: @item Full system emulation. In this mode, QEMU emulates a full system (for -example a PC), including a processor and various peripherals. It can -be used to launch different Operating Systems without rebooting the -PC or to debug system code. +example a PC), including one or several processors and various +peripherals. It can be used to launch different Operating Systems +without rebooting the PC or to debug system code. @item User mode emulation (Linux host only). In this mode, QEMU can launch @@ -40,15 +40,17 @@ performance. For system emulation, the following hardware targets are supported: @itemize @item PC (x86 or x86_64 processor) +@item ISA PC (old style PC without PCI bus) @item PREP (PowerPC processor) @item G3 BW PowerMac (PowerPC processor) @item Mac99 PowerMac (PowerPC processor, in progress) @item Sun4m (32-bit Sparc processor) @item Sun4u (64-bit Sparc processor, in progress) -@item Malta board (32-bit MIPS processor, in progress) +@item Malta board (32-bit MIPS processor) +@item ARM Integrator/CP (ARM1026E processor) @end itemize -For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported. +For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported. @chapter Installation @@ -69,14 +71,14 @@ Download the experimental binary installer at Download the experimental binary installer at @url{http://www.freeoszoo.org/download.php}. -@chapter QEMU PC System emulator invocation +@chapter QEMU PC System emulator @section Introduction @c man begin DESCRIPTION -The QEMU System emulator simulates the -following PC peripherals: +The QEMU PC System emulator simulates the +following peripherals: @itemize @minus @item @@ -104,6 +106,8 @@ Adlib(OPL2) - Yamaha YM3812 compatible chip PCI UHCI USB controller and a virtual USB hub. @end itemize +SMP is supported with up to 255 CPUs. + Note that adlib is only available when QEMU was configured with -enable-adlib @@ -169,6 +173,10 @@ the write back by pressing @key{C-a s} (@xref{disk_images}). @item -m megs Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. +@item -smp n +Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255 +CPUs are supported. + @item -nographic Normally, QEMU uses SDL to display the VGA output. With this option, @@ -1212,7 +1220,13 @@ it takes host CPU cycles even when idle. You can install the utility from @url{http://www.vmware.com/software/dosidle210.zip} to solve this problem. -@chapter QEMU PowerPC System emulator invocation +@chapter QEMU System emulator for non PC targets + +QEMU is a generic emulator and it emulates many non PC +machines. Most of the options are similar to the PC emulator. The +differences are mentionned in the following sections. + +@section QEMU PowerPC System emulator Use the executable @file{qemu-system-ppc} to simulate a complete PREP or PowerMac PowerPC system. @@ -1256,10 +1270,7 @@ PC compatible keyboard and mouse. @end itemize QEMU uses the Open Hack'Ware Open Firmware Compatible BIOS available at -@url{http://site.voila.fr/jmayer/OpenHackWare/index.htm}. - -You can read the qemu PC system emulation chapter to have more -informations about QEMU usage. +@url{http://perso.magic.fr/l_indien/OpenHackWare/index.htm}. @c man begin OPTIONS @@ -1277,9 +1288,9 @@ Set the initial VGA graphic mode. The default is 800x600x15. More information is available at -@url{http://jocelyn.mayer.free.fr/qemu-ppc/}. +@url{http://perso.magic.fr/l_indien/qemu-ppc/}. -@chapter Sparc32 System emulator invocation +@section Sparc32 System emulator invocation Use the executable @file{qemu-system-sparc} to simulate a JavaStation (sun4m architecture). The emulation is somewhat complete. @@ -1328,7 +1339,7 @@ Set the initial TCX graphic mode. The default is 1024x768. @c man end -@chapter Sparc64 System emulator invocation +@section Sparc64 System emulator invocation Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine. The emulator is not usable for anything yet. @@ -1346,12 +1357,42 @@ Non Volatile RAM M48T59 PC-compatible serial ports @end itemize -@chapter MIPS System emulator invocation +@section MIPS System emulator invocation Use the executable @file{qemu-system-mips} to simulate a MIPS machine. -The emulator begins to launch a Linux kernel. +The emulator is able to boot a Linux kernel and to run a Linux Debian +installation from NFS. The following devices are emulated: + +@itemize @minus +@item +MIPS R4K CPU +@item +PC style serial port +@item +NE2000 network card +@end itemize + +More information is available in the QEMU mailing-list archive. + +@section ARM System emulator invocation + +Use the executable @file{qemu-system-arm} to simulate a ARM +machine. The ARM Integrator/CP board is emulated with the following +devices: + +@itemize @minus +@item +ARM1026E CPU +@item +Two PL011 UARTs +@item +SMC 91c111 Ethernet adapter +@end itemize + +A Linux 2.6 test image is available on the QEMU web site. More +information is available in the QEMU mailing-list archive. -@chapter QEMU User space emulator invocation +@chapter QEMU Linux User space emulator @section Quick Start -- cgit v1.2.3 From 6a36d84e1024ce41860751b449727f4ddca91aa2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 18 Dec 2005 20:34:32 +0000 Subject: suppressed -enable-audio and simplified -soundhw option handling (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1725 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 53 +++++++++++++++++---------- qemu-doc.texi | 7 ++-- vl.c | 112 +++++++++++++++++++++++++++++++++------------------------- vl.h | 20 ++++++++--- 4 files changed, 115 insertions(+), 77 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 41cfdcfea..8e750b684 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -574,6 +574,38 @@ static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; +#ifdef HAS_AUDIO +static void audio_init (PCIBus *pci_bus) +{ + struct soundhw *c; + int audio_enabled = 0; + + for (c = soundhw; !audio_enabled && c->name; ++c) { + audio_enabled = c->enabled; + } + + if (audio_enabled) { + AudioState *s; + + s = AUD_init (); + if (s) { + for (c = soundhw; c->name; ++c) { + if (c->enabled) { + if (c->isa) { + c->init.init_isa (s); + } + else { + if (pci_bus) { + c->init.init_pci (pci_bus, s); + } + } + } + } + } + } +} +#endif + /* PC hardware initialisation */ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -789,26 +821,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, kbd_init(); DMA_init(0); - - if (audio_enabled) { - AudioState *audio; - - audio = AUD_init(); - if (audio) { - if (sb16_enabled) - SB16_init (audio); -#ifdef CONFIG_ADLIB - if (adlib_enabled) - Adlib_init (audio); -#endif -#ifdef CONFIG_GUS - if (gus_enabled) - GUS_init (audio); +#ifdef HAS_AUDIO + audio_init(pci_enabled ? pci_bus : NULL); #endif - if (pci_enabled && es1370_enabled) - es1370_init (pci_bus, audio); - } - } floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); diff --git a/qemu-doc.texi b/qemu-doc.texi index 244781e3c..94d6fbdfa 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -201,16 +201,12 @@ de en-us fi fr-be hr it lv nl-be pt sl tr The default is @code{en-us}. -@item -enable-audio - -Will enable audio and all the sound hardware QEMU was built with. - @item -audio-help Will show the audio subsystem help: list of drivers, tunable parameters. -@item -soundhw card1,card2,... +@item -soundhw card1,card2,... or -soundhw all Enable audio and selected sound hardware. Use ? to print all available sound hardware. @@ -218,6 +214,7 @@ available sound hardware. @example qemu -soundhw sb16,adlib hda qemu -soundhw es1370 hda +qemu -soundhw all hda qemu -soundhw ? @end example diff --git a/vl.c b/vl.c index 6f01077d3..70da05377 100644 --- a/vl.c +++ b/vl.c @@ -124,13 +124,6 @@ int nb_nics; NICInfo nd_table[MAX_NICS]; QEMUTimer *gui_timer; int vm_running; -#ifdef HAS_AUDIO -int audio_enabled = 0; -int sb16_enabled = 0; -int adlib_enabled = 0; -int gus_enabled = 0; -int es1370_enabled = 0; -#endif int rtc_utc = 1; int cirrus_vga_enabled = 1; #ifdef TARGET_SPARC @@ -3977,11 +3970,11 @@ void help(void) "-k language use keyboard layout (for example \"fr\" for French)\n" #endif #ifdef HAS_AUDIO - "-enable-audio enable audio support, and all the sound cards\n" "-audio-help print list of audio drivers and their options\n" "-soundhw c1,... enable audio support\n" " and only specified sound cards (comma separated list)\n" " use -soundhw ? to get the list of supported cards\n" + " use -soundhw all to enable all of them\n" #endif "-localtime set the real time clock to local time [default=utc]\n" "-full-screen start in full screen\n" @@ -4097,7 +4090,6 @@ enum { QEMU_OPTION_m, QEMU_OPTION_nographic, #ifdef HAS_AUDIO - QEMU_OPTION_enable_audio, QEMU_OPTION_audio_help, QEMU_OPTION_soundhw, #endif @@ -4159,7 +4151,6 @@ const QEMUOption qemu_options[] = { { "nographic", 0, QEMU_OPTION_nographic }, { "k", HAS_ARG, QEMU_OPTION_k }, #ifdef HAS_AUDIO - { "enable-audio", 0, QEMU_OPTION_enable_audio }, { "audio-help", 0, QEMU_OPTION_audio_help }, { "soundhw", HAS_ARG, QEMU_OPTION_soundhw }, #endif @@ -4280,58 +4271,90 @@ void register_machines(void) } #ifdef HAS_AUDIO -static void select_soundhw (const char *optarg) -{ - if (*optarg == '?') { - show_valid_cards: - printf ("Valid sound card names (comma separated):\n"); - printf ("sb16 Creative Sound Blaster 16\n"); +struct soundhw soundhw[] = { + { + "sb16", + "Creative Sound Blaster 16", + 0, + 1, + { .init_isa = SB16_init } + }, + #ifdef CONFIG_ADLIB + { + "adlib", #ifdef HAS_YMF262 - printf ("adlib Yamaha YMF262 (OPL3)\n"); + "Yamaha YMF262 (OPL3)", #else - printf ("adlib Yamaha YM3812 (OPL2)\n"); + "Yamaha YM3812 (OPL2)", #endif + 0, + 1, + { .init_isa = Adlib_init } + }, #endif + #ifdef CONFIG_GUS - printf ("gus Gravis Ultrasound GF1\n"); + { + "gus", + "Gravis Ultrasound GF1", + 0, + 1, + { .init_isa = GUS_init } + }, #endif - printf ("es1370 ENSONIQ AudioPCI ES1370\n"); + + { + "es1370", + "ENSONIQ AudioPCI ES1370", + 0, + 0, + { .init_pci = es1370_init } + }, + + { NULL, NULL, 0, 0, { NULL } } +}; + +static void select_soundhw (const char *optarg) +{ + struct soundhw *c; + + if (*optarg == '?') { + show_valid_cards: + + printf ("Valid sound card names (comma separated):\n"); + for (c = soundhw; c->name; ++c) { + printf ("%-11s %s\n", c->name, c->descr); + } + printf ("\n-soundhw all will enable all of the above\n"); exit (*optarg != '?'); } else { - struct { - char *name; - int *enabledp; - } soundhw_tab[] = { - { "sb16", &sb16_enabled }, -#ifdef CONFIG_ADLIB - { "adlib", &adlib_enabled }, -#endif -#ifdef CONFIG_GUS - { "gus", &gus_enabled }, -#endif - { "es1370", &es1370_enabled }, - }; - size_t tablen, l, i; + size_t l; const char *p; char *e; int bad_card = 0; - p = optarg; - tablen = sizeof (soundhw_tab) / sizeof (soundhw_tab[0]); + if (!strcmp (optarg, "all")) { + for (c = soundhw; c->name; ++c) { + c->enabled = 1; + } + return; + } + p = optarg; while (*p) { e = strchr (p, ','); l = !e ? strlen (p) : (size_t) (e - p); - for (i = 0; i < tablen; ++i) { - if (!strncmp (soundhw_tab[i].name, p, l)) { - audio_enabled = 1; - *soundhw_tab[i].enabledp = 1; + + for (c = soundhw; c->name; ++c) { + if (!strncmp (c->name, p, l)) { + c->enabled = 1; break; } } - if (i == tablen) { + + if (!c->name) { if (l > 80) { fprintf (stderr, "Unknown sound card name (too big to show)\n"); @@ -4592,13 +4615,6 @@ int main(int argc, char **argv) break; #endif #ifdef HAS_AUDIO - case QEMU_OPTION_enable_audio: - audio_enabled = 1; - sb16_enabled = 1; - adlib_enabled = 1; - gus_enabled = 1; - es1370_enabled = 1; - break; case QEMU_OPTION_audio_help: AUD_help (); exit (0); diff --git a/vl.h b/vl.h index fbac80725..7a107281d 100644 --- a/vl.h +++ b/vl.h @@ -126,11 +126,6 @@ void qemu_system_powerdown(void); void main_loop_wait(int timeout); -extern int audio_enabled; -extern int sb16_enabled; -extern int adlib_enabled; -extern int gus_enabled; -extern int es1370_enabled; extern int ram_size; extern int bios_size; extern int rtc_utc; @@ -621,6 +616,21 @@ typedef struct HeathrowPICS HeathrowPICS; void heathrow_pic_set_irq(void *opaque, int num, int level); HeathrowPICS *heathrow_pic_init(int *pmem_index); +#ifdef HAS_AUDIO +struct soundhw { + const char *name; + const char *descr; + int enabled; + int isa; + union { + int (*init_isa) (AudioState *s); + int (*init_pci) (PCIBus *bus, AudioState *s); + } init; +}; + +extern struct soundhw soundhw[]; +#endif + /* vga.c */ #define VGA_RAM_SIZE (4096 * 1024) -- cgit v1.2.3 From 1538800276aa7228d74f9d00bf275f54dc9e9b43 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Dec 2005 01:42:32 +0000 Subject: workaround for gcc bug on PowerPC git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1726 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 740037e4b..1ec49c2d6 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -126,7 +126,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc, /* cannot fail at this point */ tb = tb_alloc(pc); /* don't forget to invalidate previous TB info */ - T0 = 0; + tb_invalidated_flag = 1; } tc_ptr = code_gen_ptr; tb->tc_ptr = tc_ptr; @@ -144,12 +144,6 @@ static TranslationBlock *tb_find_slow(target_ulong pc, tb_link_phys(tb, phys_pc, phys_page2); found: - 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; - } /* 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); @@ -201,6 +195,14 @@ static inline TranslationBlock *tb_find_fast(void) 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; } -- cgit v1.2.3 From 48c2f068e4c1e3480d82b76d78503dd5da93a748 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Dec 2005 22:11:49 +0000 Subject: win32 compile fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1727 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vvfat.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/block-vvfat.c b/block-vvfat.c index b73a6f680..36f97134d 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -2351,8 +2351,13 @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s) mapping_t* mapping; int j, parent_path_len; - if (mkdir(commit->path, 0755)) - return -5; +#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); -- cgit v1.2.3 From 85b2c688328d949a0848ce6d3b0e536dd48df29d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Dec 2005 22:12:34 +0000 Subject: vvfat note git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1728 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 94d6fbdfa..97cb49af1 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -790,7 +790,8 @@ What you should @emph{never} do: @itemize @item use non-ASCII filenames ; @item use "-snapshot" together with ":rw:" ; -@item expect it to work when loadvm'ing. +@item expect it to work when loadvm'ing ; +@item write to the FAT directory on the host system while accessing it with the guest system. @end itemize @section Network emulation -- cgit v1.2.3 From 90dc3b395f746f9dc2be1b32251e8fbc866cf379 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Dec 2005 22:28:04 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1729 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 9fa027945..4ad7ceea2 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -version 0.7.3: +version 0.8.0: - ARM system emulation: Arm Integrator/CP board with an arm1026ej-s cpu (Paul Brook) diff --git a/VERSION b/VERSION index d5cc44d1d..8adc70fdd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.2 \ No newline at end of file +0.8.0 \ No newline at end of file -- cgit v1.2.3 From ff3fbb307d6bfbdc83730db14713d62f92b3a841 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 8 Jan 2006 10:53:14 +0000 Subject: kqemu and SMP are currently not compatible git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1730 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vl.c b/vl.c index 70da05377..94e989f00 100644 --- a/vl.c +++ b/vl.c @@ -4777,6 +4777,10 @@ int main(int argc, char **argv) } } +#ifdef USE_KQEMU + if (smp_cpus > 1) + kqemu_allowed = 0; +#endif linux_boot = (kernel_filename != NULL); if (!linux_boot && -- cgit v1.2.3 From fd1dff4b418e28302018f37371dd515150f23534 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Feb 2006 21:29:26 +0000 Subject: win32 socket support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1731 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 321 +++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 209 insertions(+), 112 deletions(-) diff --git a/vl.c b/vl.c index 94e989f00..47056f894 100644 --- a/vl.c +++ b/vl.c @@ -64,6 +64,8 @@ #include #include #include +#include +#include #define getopt_long_only getopt_long #define memalign(align, size) malloc(size) #endif @@ -1077,20 +1079,67 @@ CharDriverState *qemu_chr_open_null(void) return chr; } -#ifndef _WIN32 +#ifdef _WIN32 -typedef struct { - int fd_in, fd_out; - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; - int max_size; -} FDCharDriver; +#define socket_error() WSAGetLastError() +#undef EINTR +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINTR WSAEINTR +#define EINPROGRESS WSAEINPROGRESS -#define STDIO_MAX_CLIENTS 2 +static void socket_cleanup(void) +{ + WSACleanup(); +} -static int stdio_nb_clients; -static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; +static int socket_init(void) +{ + WSADATA Data; + int ret, err; + + ret = WSAStartup(MAKEWORD(2,2), &Data); + if (ret != 0) { + err = WSAGetLastError(); + fprintf(stderr, "WSAStartup: %d\n", err); + return -1; + } + atexit(socket_cleanup); + return 0; +} + +static int send_all(int fd, const uint8_t *buf, int len1) +{ + int ret, len; + + len = len1; + while (len > 0) { + ret = send(fd, buf, len, 0); + if (ret < 0) { + int errno; + errno = WSAGetLastError(); + if (errno != WSAEWOULDBLOCK) { + return -1; + } + } else if (ret == 0) { + break; + } else { + buf += ret; + len -= ret; + } + } + return len1 - len; +} + +void socket_set_nonblock(int fd) +{ + unsigned long opt = 1; + ioctlsocket(fd, FIONBIO, &opt); +} + +#else + +#define socket_error() errno +#define closesocket(s) close(s) static int unix_write(int fd, const uint8_t *buf, int len1) { @@ -1112,6 +1161,32 @@ static int unix_write(int fd, const uint8_t *buf, int len1) return len1 - len; } +static inline int send_all(int fd, const uint8_t *buf, int len1) +{ + return unix_write(fd, buf, len1); +} + +void socket_set_nonblock(int fd) +{ + fcntl(fd, F_SETFL, O_NONBLOCK); +} +#endif /* !_WIN32 */ + +#ifndef _WIN32 + +typedef struct { + int fd_in, fd_out; + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *fd_opaque; + int max_size; +} FDCharDriver; + +#define STDIO_MAX_CLIENTS 2 + +static int stdio_nb_clients; +static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; + static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { FDCharDriver *s = chr->opaque; @@ -1617,7 +1692,10 @@ CharDriverState *qemu_chr_open_pty(void) CharDriverState *qemu_chr_open(const char *filename) { +#ifndef _WIN32 const char *p; +#endif + if (!strcmp(filename, "vc")) { return text_console_init(&display_state); } else if (!strcmp(filename, "null")) { @@ -1731,13 +1809,9 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str) if (!inet_aton(buf, &saddr->sin_addr)) return -1; } else { -#ifdef _WIN32 - return -1; -#else if ((he = gethostbyname(buf)) == NULL) return - 1; saddr->sin_addr = *(struct in_addr *)he->h_addr; -#endif } } port = strtol(p, (char **)&r, 0); @@ -2127,6 +2201,8 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, return 0; } +#endif /* !_WIN32 */ + /* network connection */ typedef struct NetSocketState { VLANClientState *vc; @@ -2150,8 +2226,8 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, int size) uint32_t len; len = htonl(size); - unix_write(s->fd, (const uint8_t *)&len, sizeof(len)); - unix_write(s->fd, buf, size); + send_all(s->fd, (const uint8_t *)&len, sizeof(len)); + send_all(s->fd, buf, size); } static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) @@ -2164,16 +2240,20 @@ static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) static void net_socket_send(void *opaque) { NetSocketState *s = opaque; - int l, size; + int l, size, err; uint8_t buf1[4096]; const uint8_t *buf; - size = read(s->fd, buf1, sizeof(buf1)); - if (size < 0) - return; - if (size == 0) { + size = recv(s->fd, buf1, sizeof(buf1), 0); + if (size < 0) { + err = socket_error(); + if (err != EWOULDBLOCK) + goto eoc; + } else if (size == 0) { /* end of connection */ + eoc: qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + closesocket(s->fd); return; } buf = buf1; @@ -2236,7 +2316,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) int val, ret; if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", - inet_ntoa(mcastaddr->sin_addr), ntohl(mcastaddr->sin_addr.s_addr)); + inet_ntoa(mcastaddr->sin_addr), + (int)ntohl(mcastaddr->sin_addr.s_addr)); return -1; } @@ -2246,11 +2327,26 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) return -1; } + val = 1; + ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (const char *)&val, sizeof(val)); + if (ret < 0) { + perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); + goto fail; + } + + ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); + if (ret < 0) { + perror("bind"); + goto fail; + } + /* Add host to multicast group */ imr.imr_multiaddr = mcastaddr->sin_addr; imr.imr_interface.s_addr = htonl(INADDR_ANY); - ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *) &imr, sizeof(struct ip_mreq)); + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const char *)&imr, sizeof(struct ip_mreq)); if (ret < 0) { perror("setsockopt(IP_ADD_MEMBERSHIP)"); goto fail; @@ -2258,25 +2354,14 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) /* Force mcast msgs to loopback (eg. several QEMUs in same host */ val = 1; - ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &val, sizeof(val)); + ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + (const char *)&val, sizeof(val)); if (ret < 0) { perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); goto fail; } - ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); - if (ret < 0) { - perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); - goto fail; - } - - ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); - if (ret < 0) { - perror("bind"); - goto fail; - } - - fcntl(fd, F_SETFL, O_NONBLOCK); + socket_set_nonblock(fd); return fd; fail: if (fd>=0) close(fd); @@ -2371,7 +2456,7 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, { int so_type=-1, optlen=sizeof(so_type); - if(getsockopt(fd, SOL_SOCKET,SO_TYPE, &so_type, &optlen)< 0) { + if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, &optlen)< 0) { fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd); return NULL; } @@ -2433,11 +2518,11 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str) perror("socket"); return -1; } - fcntl(fd, F_SETFL, O_NONBLOCK); + socket_set_nonblock(fd); /* allow fast reuse */ val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { @@ -2458,7 +2543,7 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str) static int net_socket_connect_init(VLANState *vlan, const char *host_str) { NetSocketState *s; - int fd, connected, ret; + int fd, connected, ret, err; struct sockaddr_in saddr; if (parse_host_port(&saddr, host_str) < 0) @@ -2469,18 +2554,19 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str) perror("socket"); return -1; } - fcntl(fd, F_SETFL, O_NONBLOCK); + socket_set_nonblock(fd); connected = 0; for(;;) { ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { - if (errno == EINTR || errno == EAGAIN) { - } else if (errno == EINPROGRESS) { + err = socket_error(); + if (err == EINTR || err == EWOULDBLOCK) { + } else if (err == EINPROGRESS) { break; } else { perror("connect"); - close(fd); + closesocket(fd); return -1; } } else { @@ -2524,8 +2610,6 @@ static int net_socket_mcast_init(VLANState *vlan, const char *host_str) } -#endif /* !_WIN32 */ - static int get_param_value(char *buf, int buf_size, const char *tag, const char *str) { @@ -2649,6 +2733,7 @@ int net_client_init(const char *str) ret = net_tap_init(vlan, ifname, setup_script); } } else +#endif if (!strcmp(device, "socket")) { if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { int fd; @@ -2667,7 +2752,6 @@ int net_client_init(const char *str) return -1; } } else -#endif { fprintf(stderr, "Unknown network device: %s\n", device); return -1; @@ -2918,6 +3002,7 @@ int qemu_set_fd_handler2(int fd, break; if (ioh->fd == fd) { *pioh = ioh->next; + qemu_free(ioh); break; } pioh = &ioh->next; @@ -3812,80 +3897,88 @@ void qemu_system_powerdown_request(void) void main_loop_wait(int timeout) { -#ifndef _WIN32 - struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf; IOHandlerRecord *ioh, *ioh_next; -#endif - int ret; + fd_set rfds, wfds; + int ret, nfds; + struct timeval tv; #ifdef _WIN32 - if (timeout > 0) - Sleep(timeout); + /* XXX: see how to merge it with the select. The constraint is + that the select must be interrupted by the timer */ + if (timeout > 0) + Sleep(timeout); +#endif + /* poll any events */ + /* XXX: separate device handlers from system ones */ + nfds = -1; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { + if (ioh->fd_read && + (!ioh->fd_read_poll || + ioh->fd_read_poll(ioh->opaque) != 0)) { + FD_SET(ioh->fd, &rfds); + if (ioh->fd > nfds) + nfds = ioh->fd; + } + if (ioh->fd_write) { + FD_SET(ioh->fd, &wfds); + if (ioh->fd > nfds) + nfds = ioh->fd; + } + } + + tv.tv_sec = 0; +#ifdef _WIN32 + tv.tv_usec = 0; #else - /* poll any events */ - /* XXX: separate device handlers from system ones */ - pf = ufds; - for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { - pf->events = 0; - pf->fd = ioh->fd; - if (ioh->fd_read && - (!ioh->fd_read_poll || - ioh->fd_read_poll(ioh->opaque) != 0)) { - pf->events |= POLLIN; + tv.tv_usec = timeout * 1000; +#endif + ret = select(nfds + 1, &rfds, &wfds, NULL, &tv); + if (ret > 0) { + /* XXX: better handling of removal */ + for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { + ioh_next = ioh->next; + if (FD_ISSET(ioh->fd, &rfds)) { + ioh->fd_read(ioh->opaque); } - if (ioh->fd_write) { - pf->events |= POLLOUT; + if (FD_ISSET(ioh->fd, &wfds)) { + ioh->fd_write(ioh->opaque); } - ioh->ufd = pf; - pf++; } - - ret = poll(ufds, pf - ufds, timeout); - if (ret > 0) { - /* XXX: better handling of removal */ - for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { - ioh_next = ioh->next; - pf = ioh->ufd; - if (pf->revents & POLLIN) { - ioh->fd_read(ioh->opaque); - } - if (pf->revents & POLLOUT) { - ioh->fd_write(ioh->opaque); - } - } - } -#endif /* !defined(_WIN32) */ + } + #if defined(CONFIG_SLIRP) - /* XXX: merge with poll() */ - if (slirp_inited) { - fd_set rfds, wfds, xfds; - int nfds; - struct timeval tv; - - nfds = -1; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&xfds); - slirp_select_fill(&nfds, &rfds, &wfds, &xfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); - if (ret >= 0) { - slirp_select_poll(&rfds, &wfds, &xfds); - } + /* XXX: merge with the previous select() */ + if (slirp_inited) { + fd_set rfds, wfds, xfds; + int nfds; + struct timeval tv; + + nfds = -1; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + slirp_select_fill(&nfds, &rfds, &wfds, &xfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); + if (ret >= 0) { + slirp_select_poll(&rfds, &wfds, &xfds); } + } #endif - if (vm_running) { - qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], - qemu_get_clock(vm_clock)); - /* run dma transfers, if any */ - DMA_run(); - } - - /* real time timers */ - qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], - qemu_get_clock(rt_clock)); + if (vm_running) { + qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], + qemu_get_clock(vm_clock)); + /* run dma transfers, if any */ + DMA_run(); + } + + /* real time timers */ + qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], + qemu_get_clock(rt_clock)); } static CPUState *cur_cpu; @@ -4807,6 +4900,10 @@ int main(int argc, char **argv) setvbuf(stdout, NULL, _IOLBF, 0); #endif +#ifdef _WIN32 + socket_init(); +#endif + /* init network clients */ if (nb_net_clients == 0) { /* if no clients, we use a default config */ -- cgit v1.2.3 From 039af320d9b116a325ee55ebab2edf60f3bdc252 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Feb 2006 21:30:55 +0000 Subject: clearer -net doc (Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1732 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 97cb49af1..fdf8ba2d4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -260,8 +260,7 @@ target. Optionally, the MAC address can be changed. If no @item -net user[,vlan=n] Use the user mode network stack which requires no administrator -priviledge to run. This is the default if no @option{-net} option is -specified. +priviledge to run. @item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file] Connect the host TAP network interface @var{name} to VLAN @var{n} and @@ -334,8 +333,8 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168. @item -net none Indicate that no network devices should be configured. It is used to -override the default configuration which is activated if no -@option{-net} options are provided. +override the default configuration (@option{-net nic -net user}) which +is activated if no @option{-net} options are provided. @item -tftp prefix When using the user mode network stack, activate a built-in TFTP -- cgit v1.2.3 From acff9df6a80455a8228dd6547cdd2714dbbe93ec Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Feb 2006 21:40:18 +0000 Subject: rxcr save/restore (initial patch by Jürgen Pfennig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1733 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 2940abd35..efc3ea8ec 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -643,6 +643,8 @@ static void ne2000_save(QEMUFile* f,void* opaque) { NE2000State* s=(NE2000State*)opaque; + qemu_put_8s(f, &s->rxcr); + qemu_put_8s(f, &s->cmd); qemu_put_be32s(f, &s->start); qemu_put_be32s(f, &s->stop); @@ -667,8 +669,13 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) { NE2000State* s=(NE2000State*)opaque; - if (version_id != 1) + if (version_id == 2) { + qemu_get_8s(f, &s->rxcr); + } else if (version_id == 1) { + s->rxcr = 0x0c; + } else { return -EINVAL; + } qemu_get_8s(f, &s->cmd); qemu_get_be32s(f, &s->start); @@ -726,7 +733,7 @@ void isa_ne2000_init(int base, int irq, NICInfo *nd) s->macaddr[4], s->macaddr[5]); - register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); + register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); } /***********************************************************/ @@ -796,7 +803,7 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd) s->macaddr[5]); /* XXX: instance number ? */ - register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); + register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, &d->dev); } -- cgit v1.2.3 From 28a5c9c8b26d7737b9908f912754711399954837 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Feb 2006 21:43:52 +0000 Subject: use uint8_t instead of char git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1734 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-cloop.c | 8 ++++---- block-dmg.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/block-cloop.c b/block-cloop.c index de9085538..c617e1b64 100644 --- a/block-cloop.c +++ b/block-cloop.c @@ -32,8 +32,8 @@ typedef struct BDRVCloopState { uint64_t* offsets; uint32_t sectors_per_block; uint32_t current_block; - char* compressed_block; - char* uncompressed_block; + uint8_t *compressed_block; + uint8_t *uncompressed_block; z_stream zstream; } BDRVCloopState; @@ -89,9 +89,9 @@ cloop_close: } /* initialize zlib engine */ - if(!(s->compressed_block=(char*)malloc(max_compressed_block_size+1))) + if(!(s->compressed_block = malloc(max_compressed_block_size+1))) goto cloop_close; - if(!(s->uncompressed_block=(char*)malloc(s->block_size))) + if(!(s->uncompressed_block = malloc(s->block_size))) goto cloop_close; if(inflateInit(&s->zstream) != Z_OK) goto cloop_close; diff --git a/block-dmg.c b/block-dmg.c index 5df723543..a16ab926b 100644 --- a/block-dmg.c +++ b/block-dmg.c @@ -44,8 +44,8 @@ typedef struct BDRVDMGState { uint64_t* sectors; uint64_t* sectorcounts; uint32_t current_chunk; - char* compressed_chunk; - char* uncompressed_chunk; + uint8_t *compressed_chunk; + uint8_t *uncompressed_chunk; z_stream zstream; } BDRVDMGState; @@ -159,9 +159,9 @@ dmg_close: } /* initialize zlib engine */ - if(!(s->compressed_chunk=(char*)malloc(max_compressed_size+1))) + if(!(s->compressed_chunk = malloc(max_compressed_size+1))) goto dmg_close; - if(!(s->uncompressed_chunk=(char*)malloc(512*max_sectors_per_chunk))) + if(!(s->uncompressed_chunk = malloc(512*max_sectors_per_chunk))) goto dmg_close; if(inflateInit(&s->zstream) != Z_OK) goto dmg_close; -- cgit v1.2.3 From 8147cfca569182708430d0ca167786565bc5e11b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Feb 2006 21:45:16 +0000 Subject: added --enable-cocoa in help (Pavel Janík) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1735 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 3471193ed..fa05bbf38 100755 --- a/configure +++ b/configure @@ -375,6 +375,7 @@ 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 " --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" -- cgit v1.2.3 From 944588029809b29c800f081d812153f559ec523a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Feb 2006 22:20:12 +0000 Subject: correct DMA and transfer mode reporting (Jens Axboe) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1736 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 28ed5abbe..50b8e6375 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -296,6 +296,8 @@ typedef struct IDEState { int cylinders, heads, sectors; int64_t nb_sectors; int mult_sectors; + int identify_set; + uint16_t identify_data[256]; SetIRQFunc *set_irq; void *irq_opaque; int irq; @@ -414,6 +416,11 @@ static void ide_identify(IDEState *s) unsigned int oldsize; char buf[20]; + if (s->identify_set) { + memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); + return; + } + memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; put_le16(p + 0, 0x0040); @@ -433,10 +440,10 @@ static void ide_identify(IDEState *s) put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); #endif put_le16(p + 48, 1); /* dword I/O */ - put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ + put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */ put_le16(p + 51, 0x200); /* PIO transfer cycle */ put_le16(p + 52, 0x200); /* DMA transfer cycle */ - put_le16(p + 53, 1 | 1 << 2); /* words 54-58,88 are valid */ + put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */ put_le16(p + 54, s->cylinders); put_le16(p + 55, s->heads); put_le16(p + 56, s->sectors); @@ -447,15 +454,24 @@ static void ide_identify(IDEState *s) put_le16(p + 59, 0x100 | s->mult_sectors); put_le16(p + 60, s->nb_sectors); put_le16(p + 61, s->nb_sectors >> 16); - put_le16(p + 80, (1 << 1) | (1 << 2)); + put_le16(p + 63, 0x07); /* mdma0-2 supported */ + put_le16(p + 65, 120); + put_le16(p + 66, 120); + put_le16(p + 67, 120); + put_le16(p + 68, 120); + put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ + put_le16(p + 81, 0x16); /* conforms to ata5 */ put_le16(p + 82, (1 << 14)); put_le16(p + 83, (1 << 14)); put_le16(p + 84, (1 << 14)); put_le16(p + 85, (1 << 14)); put_le16(p + 86, 0); put_le16(p + 87, (1 << 14)); - put_le16(p + 88, 0x1f | (1 << 13)); - put_le16(p + 93, 1 | (1 << 14) | 0x2000 | 0x4000); + put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ + put_le16(p + 93, 1 | (1 << 14) | 0x2000); + + memcpy(s->identify_data, p, sizeof(s->identify_data)); + s->identify_set = 1; } static void ide_atapi_identify(IDEState *s) @@ -463,6 +479,11 @@ static void ide_atapi_identify(IDEState *s) uint16_t *p; char buf[20]; + if (s->identify_set) { + memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); + return; + } + memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; /* Removable CDROM, 50us response, 12 byte packets */ @@ -483,11 +504,14 @@ static void ide_atapi_identify(IDEState *s) put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ - + put_le16(p + 71, 30); /* in ns */ put_le16(p + 72, 30); /* in ns */ put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ + + memcpy(s->identify_data, p, sizeof(s->identify_data)); + s->identify_set = 1; } static void ide_set_signature(IDEState *s) @@ -1601,13 +1625,36 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* XXX: valid for CDROM ? */ switch(s->feature) { case 0x02: /* write cache enable */ - case 0x03: /* set transfer mode */ case 0x82: /* write cache disable */ case 0xaa: /* read look-ahead enable */ case 0x55: /* read look-ahead disable */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; + case 0x03: { /* set transfer mode */ + uint8_t val = s->nsector & 0x07; + + switch (s->nsector >> 3) { + case 0x00: /* pio default */ + case 0x01: /* pio mode */ + put_le16(s->identify_data + 63,0x07); + put_le16(s->identify_data + 88,0x3f); + break; + case 0x04: /* mdma mode */ + put_le16(s->identify_data + 63,0x07 | (1 << (val + 8))); + put_le16(s->identify_data + 88,0x3f); + break; + case 0x08: /* udma mode */ + put_le16(s->identify_data + 63,0x07); + put_le16(s->identify_data + 88,0x3f | (1 << (val + 8))); + break; + default: + goto abort_cmd; + } + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + break; + } default: goto abort_cmd; } -- cgit v1.2.3 From 7fb843f8cc67805d66db9e2ec3d482c8a928bdab Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Feb 2006 23:06:55 +0000 Subject: tap win32 support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1737 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 + tap-win32.c | 680 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 21 +- vl.h | 4 + 4 files changed, 705 insertions(+), 3 deletions(-) create mode 100644 tap-win32.c diff --git a/Makefile.target b/Makefile.target index 093d40c8e..a5a2aa0a5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -272,6 +272,9 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o +ifdef CONFIG_WIN32 +VL_OBJS+=tap-win32.o +endif SOUND_HW = sb16.o es1370.o AUDIODRV = audio.o noaudio.o wavaudio.o diff --git a/tap-win32.c b/tap-win32.c new file mode 100644 index 000000000..32baf22da --- /dev/null +++ b/tap-win32.c @@ -0,0 +1,680 @@ +/* + * TAP-Win32 -- A kernel driver to provide virtual tap device functionality + * on Windows. Originally derived from the CIPE-Win32 + * project by Damion K. Wilson, with extensive modifications by + * James Yonan. + * + * All source code which derives from the CIPE-Win32 project is + * Copyright (C) Damion K. Wilson, 2003, and is released under the + * GPL version 2 (see below). + * + * All other source code is Copyright (C) James Yonan, 2003-2004, + * and is released under the GPL version 2 (see below). + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "vl.h" +#include +#include + +/* NOTE: PCIBus is redefined in winddk.h */ +#define PCIBus _PCIBus +#include +#include +#include +#undef PCIBus + +//============= +// TAP IOCTLs +//============= + +#define TAP_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) + +//================= +// Registry keys +//================= + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +//====================== +// Filesystem prefixes +//====================== + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define TAPSUFFIX ".tap" + + +//====================== +// Compile time configuration +//====================== + +//#define DEBUG_TAP_WIN32 1 + +#define TUN_ASYNCHRONOUS_WRITES 1 + +#define TUN_BUFFER_SIZE 1560 +#define TUN_MAX_BUFFER_COUNT 32 + +/* + * The data member "buffer" must be the first element in the tun_buffer + * structure. See the function, tap_win32_free_buffer. + */ +typedef struct tun_buffer_s { + unsigned char buffer [TUN_BUFFER_SIZE]; + unsigned long read_size; + struct tun_buffer_s* next; +} tun_buffer_t; + +typedef struct tap_win32_overlapped { + HANDLE handle; + HANDLE read_event; + HANDLE write_event; + HANDLE output_queue_semaphore; + HANDLE free_list_semaphore; + CRITICAL_SECTION output_queue_cs; + CRITICAL_SECTION free_list_cs; + OVERLAPPED read_overlapped; + OVERLAPPED write_overlapped; + tun_buffer_t buffers[TUN_MAX_BUFFER_COUNT]; + tun_buffer_t* free_list; + tun_buffer_t* output_queue_front; + tun_buffer_t* output_queue_back; +} tap_win32_overlapped_t; + +static tap_win32_overlapped_t tap_overlapped; + +static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped) +{ + tun_buffer_t* buffer = NULL; + WaitForSingleObject(overlapped->free_list_semaphore, INFINITE); + EnterCriticalSection(&overlapped->free_list_cs); + buffer = overlapped->free_list; +// assert(buffer != NULL); + overlapped->free_list = buffer->next; + LeaveCriticalSection(&overlapped->free_list_cs); + buffer->next = NULL; + return buffer; +} + +static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer) +{ + EnterCriticalSection(&overlapped->free_list_cs); + buffer->next = overlapped->free_list; + overlapped->free_list = buffer; + LeaveCriticalSection(&overlapped->free_list_cs); + ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL); +} + +static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block) +{ + tun_buffer_t* buffer = NULL; + DWORD result, timeout = block ? INFINITE : 0L; + + // Non-blocking call + result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout); + + switch (result) + { + // The semaphore object was signaled. + case WAIT_OBJECT_0: + EnterCriticalSection(&overlapped->output_queue_cs); + + buffer = overlapped->output_queue_front; + overlapped->output_queue_front = buffer->next; + + if(overlapped->output_queue_front == NULL) { + overlapped->output_queue_back = NULL; + } + + LeaveCriticalSection(&overlapped->output_queue_cs); + break; + + // Semaphore was nonsignaled, so a time-out occurred. + case WAIT_TIMEOUT: + // Cannot open another window. + break; + } + + return buffer; +} + +static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped) +{ + return get_buffer_from_output_queue(overlapped, 0); +} + +static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer) +{ + EnterCriticalSection(&overlapped->output_queue_cs); + + if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) { + overlapped->output_queue_front = overlapped->output_queue_back = buffer; + } else { + buffer->next = NULL; + overlapped->output_queue_back->next = buffer; + overlapped->output_queue_back = buffer; + } + + LeaveCriticalSection(&overlapped->output_queue_cs); + + ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL); +} + + +static int is_tap_win32_dev(const char *guid) +{ + HKEY netcard_key; + LONG status; + DWORD len; + int i = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + ADAPTER_KEY, + 0, + KEY_READ, + &netcard_key); + + if (status != ERROR_SUCCESS) { + return FALSE; + } + + for (;;) { + char enum_name[256]; + char unit_string[256]; + HKEY unit_key; + char component_id_string[] = "ComponentId"; + char component_id[256]; + char net_cfg_instance_id_string[] = "NetCfgInstanceId"; + char net_cfg_instance_id[256]; + DWORD data_type; + + len = sizeof (enum_name); + status = RegEnumKeyEx( + netcard_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) { + return FALSE; + } + + snprintf (unit_string, sizeof(unit_string), "%s\\%s", + ADAPTER_KEY, enum_name); + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + unit_string, + 0, + KEY_READ, + &unit_key); + + if (status != ERROR_SUCCESS) { + return FALSE; + } else { + len = sizeof (component_id); + status = RegQueryValueEx( + unit_key, + component_id_string, + NULL, + &data_type, + component_id, + &len); + + if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) { + len = sizeof (net_cfg_instance_id); + status = RegQueryValueEx( + unit_key, + net_cfg_instance_id_string, + NULL, + &data_type, + net_cfg_instance_id, + &len); + + if (status == ERROR_SUCCESS && data_type == REG_SZ) { + if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/ + !strcmp (net_cfg_instance_id, guid)) { + RegCloseKey (unit_key); + RegCloseKey (netcard_key); + return TRUE; + } + } + } + RegCloseKey (unit_key); + } + ++i; + } + + RegCloseKey (netcard_key); + return FALSE; +} + +static int get_device_guid( + char *name, + int name_size, + char *actual_name, + int actual_name_size) +{ + LONG status; + HKEY control_net_key; + DWORD len; + int i = 0; + int stop = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + NETWORK_CONNECTIONS_KEY, + 0, + KEY_READ, + &control_net_key); + + if (status != ERROR_SUCCESS) { + return -1; + } + + while (!stop) + { + char enum_name[256]; + char connection_string[256]; + HKEY connection_key; + char name_data[256]; + DWORD name_type; + const char name_string[] = "Name"; + + len = sizeof (enum_name); + status = RegEnumKeyEx( + control_net_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + + if (status == ERROR_NO_MORE_ITEMS) + break; + else if (status != ERROR_SUCCESS) { + return -1; + } + + snprintf(connection_string, + sizeof(connection_string), + "%s\\%s\\Connection", + NETWORK_CONNECTIONS_KEY, enum_name); + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + connection_string, + 0, + KEY_READ, + &connection_key); + + if (status == ERROR_SUCCESS) { + len = sizeof (name_data); + status = RegQueryValueEx( + connection_key, + name_string, + NULL, + &name_type, + name_data, + &len); + + if (status != ERROR_SUCCESS || name_type != REG_SZ) { + return -1; + } + else { + if (is_tap_win32_dev(enum_name)) { + snprintf(name, name_size, "%s", enum_name); + if (actual_name) { + if (strcmp(actual_name, "") != 0) { + if (strcmp(name_data, actual_name) != 0) { + RegCloseKey (connection_key); + ++i; + continue; + } + } + else { + snprintf(actual_name, actual_name_size, "%s", name_data); + } + } + stop = 1; + } + } + + RegCloseKey (connection_key); + } + ++i; + } + + RegCloseKey (control_net_key); + + if (stop == 0) + return -1; + + return 0; +} + +static int tap_win32_set_status(HANDLE handle, int status) +{ + unsigned long len = 0; + + return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS, + &status, sizeof (status), + &status, sizeof (status), &len, NULL); +} + +static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle) +{ + overlapped->handle = handle; + + overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL); + overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL); + + overlapped->read_overlapped.Offset = 0; + overlapped->read_overlapped.OffsetHigh = 0; + overlapped->read_overlapped.hEvent = overlapped->read_event; + + overlapped->write_overlapped.Offset = 0; + overlapped->write_overlapped.OffsetHigh = 0; + overlapped->write_overlapped.hEvent = overlapped->write_event; + + InitializeCriticalSection(&overlapped->output_queue_cs); + InitializeCriticalSection(&overlapped->free_list_cs); + + overlapped->output_queue_semaphore = CreateSemaphore( + NULL, // default security attributes + 0, // initial count + TUN_MAX_BUFFER_COUNT, // maximum count + NULL); // unnamed semaphore + + if(!overlapped->output_queue_semaphore) { + fprintf(stderr, "error creating output queue semaphore!\n"); + } + + overlapped->free_list_semaphore = CreateSemaphore( + NULL, // default security attributes + TUN_MAX_BUFFER_COUNT, // initial count + TUN_MAX_BUFFER_COUNT, // maximum count + NULL); // unnamed semaphore + + if(!overlapped->free_list_semaphore) { + fprintf(stderr, "error creating free list semaphore!\n"); + } + + overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL; + + { + unsigned index; + for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) { + tun_buffer_t* element = &overlapped->buffers[index]; + element->next = overlapped->free_list; + overlapped->free_list = element; + } + } +} + +static int tap_win32_write(tap_win32_overlapped_t *overlapped, + const void *buffer, unsigned long size) +{ + unsigned long write_size; + BOOL result; + DWORD error; + + result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped, + &write_size, FALSE); + + if (!result && GetLastError() == ERROR_IO_INCOMPLETE) + WaitForSingleObject(overlapped->write_event, INFINITE); + + result = WriteFile(overlapped->handle, buffer, size, + &write_size, &overlapped->write_overlapped); + + if (!result) { + switch (error = GetLastError()) + { + case ERROR_IO_PENDING: +#ifndef TUN_ASYNCHRONOUS_WRITES + WaitForSingleObject(overlapped->write_event, INFINITE); +#endif + break; + default: + return -1; + } + } + + return 0; +} + +static DWORD WINAPI tap_win32_thread_entry(LPVOID param) +{ + tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param; + unsigned long read_size; + BOOL result; + DWORD dwError; + tun_buffer_t* buffer = get_buffer_from_free_list(overlapped); + + + for (;;) { + result = ReadFile(overlapped->handle, + buffer->buffer, + sizeof(buffer->buffer), + &read_size, + &overlapped->read_overlapped); + if (!result) { + dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) { + WaitForSingleObject(overlapped->read_event, INFINITE); + result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped, + &read_size, FALSE); + if (!result) { +#if DEBUG_TAP_WIN32 + LPVOID lpBuffer; + dwError = GetLastError(); + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) & lpBuffer, 0, NULL ); + fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer); + LocalFree( lpBuffer ); +#endif + } + } else { +#if DEBUG_TAP_WIN32 + LPVOID lpBuffer; + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) & lpBuffer, 0, NULL ); + fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer); + LocalFree( lpBuffer ); +#endif + } + } + + if(read_size > 0) { + buffer->read_size = read_size; + put_buffer_on_output_queue(overlapped, buffer); + buffer = get_buffer_from_free_list(overlapped); + } + } + + return 0; +} + +static int tap_win32_read(tap_win32_overlapped_t *overlapped, + uint8_t **pbuf, int max_size) +{ + int size = 0; + + tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped); + + if(buffer != NULL) { + *pbuf = buffer->buffer; + size = (int)buffer->read_size; + if(size > max_size) { + size = max_size; + } + } + + return size; +} + +static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, + char* pbuf) +{ + tun_buffer_t* buffer = (tun_buffer_t*)pbuf; + put_buffer_on_free_list(overlapped, buffer); +} + +static int tap_win32_open(tap_win32_overlapped_t **phandle, + const char *prefered_name) +{ + char device_path[256]; + char device_guid[0x100]; + int rc; + HANDLE handle; + BOOL bret; + char name_buffer[0x100] = {0, }; + struct { + unsigned long major; + unsigned long minor; + unsigned long debug; + } version; + LONG version_len; + DWORD idThread; + HANDLE hThread; + + if (prefered_name != NULL) + snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name); + + rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer)); + if (rc) + return -1; + + snprintf (device_path, sizeof(device_path), "%s%s%s", + USERMODEDEVICEDIR, + device_guid, + TAPSUFFIX); + + handle = CreateFile ( + device_path, + GENERIC_READ | GENERIC_WRITE, + 0, + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 ); + + if (handle == INVALID_HANDLE_VALUE) { + return -1; + } + + bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION, + &version, sizeof (version), + &version, sizeof (version), &version_len, NULL); + + if (bret == FALSE) { + CloseHandle(handle); + return -1; + } + + if (!tap_win32_set_status(handle, TRUE)) { + return -1; + } + + tap_win32_overlapped_init(&tap_overlapped, handle); + + *phandle = &tap_overlapped; + + hThread = CreateThread(NULL, 0, tap_win32_thread_entry, + (LPVOID)&tap_overlapped, 0, &idThread); + SetThreadPriority(hThread,THREAD_PRIORITY_TIME_CRITICAL); + + return 0; +} + +/********************************************/ + + typedef struct TAPState { + VLANClientState *vc; + tap_win32_overlapped_t *handle; + } TAPState; + +static TAPState *tap_win32_state = NULL; + +static void tap_receive(void *opaque, const uint8_t *buf, int size) +{ + TAPState *s = opaque; + + tap_win32_write(s->handle, buf, size); +} + +/* XXX: horrible, suppress this by using proper thread signaling */ +void tap_win32_poll(void) +{ + TAPState *s = tap_win32_state; + uint8_t *buf; + int max_size = 4096; + int size; + + if (!s) + return; + + size = tap_win32_read(s->handle, &buf, max_size); + if (size > 0) { + qemu_send_packet(s->vc, buf, size); + tap_win32_free_buffer(s->handle, buf); + } +} + +int tap_win32_init(VLANState *vlan, const char *ifname) +{ + TAPState *s; + + s = qemu_mallocz(sizeof(TAPState)); + if (!s) + return -1; + if (tap_win32_open(&s->handle, ifname) < 0) { + printf("tap: Could not open '%s'\n", ifname); + return -1; + } + + s->vc = qemu_new_vlan_client(vlan, tap_receive, s); + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "tap: ifname=%s", ifname); + tap_win32_state = s; + return 0; +} diff --git a/vl.c b/vl.c index 47056f894..d875f2ac0 100644 --- a/vl.c +++ b/vl.c @@ -2715,7 +2715,16 @@ int net_client_init(const char *str) ret = net_slirp_init(vlan); } else #endif -#ifndef _WIN32 +#ifdef _WIN32 + if (!strcmp(device, "tap")) { + char ifname[64]; + if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { + fprintf(stderr, "tap: no interface name\n"); + return -1; + } + ret = tap_win32_init(vlan, ifname); + } else +#else if (!strcmp(device, "tap")) { char ifname[64]; char setup_script[1024]; @@ -3947,6 +3956,9 @@ void main_loop_wait(int timeout) } } } +#ifdef _WIN32 + tap_win32_poll(); +#endif #if defined(CONFIG_SLIRP) /* XXX: merge with the previous select() */ @@ -4087,16 +4099,19 @@ void help(void) "-net user[,vlan=n]\n" " connect the user mode network stack to VLAN 'n'\n" #endif -#ifndef _WIN32 +#ifdef _WIN32 + "-net tap[,vlan=n],ifname=name\n" + " connect the host TAP network interface to VLAN 'n'\n" +#else "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n" " connect the host TAP network interface to VLAN 'n' and use\n" " the network script 'file' (default=%s);\n" " use 'fd=h' to connect to an already opened TAP interface\n" +#endif "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n" " connect the vlan 'n' to another VLAN using a socket connection\n" "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n" " connect the vlan 'n' to multicast maddr and port\n" -#endif "-net none use it alone to have zero network devices; if no -net option\n" " is provided, the default is '-net nic -net user'\n" "\n" diff --git a/vl.h b/vl.h index 7a107281d..004498f6d 100644 --- a/vl.h +++ b/vl.h @@ -298,6 +298,10 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); void do_info_network(void); +/* TAP win32 */ +int tap_win32_init(VLANState *vlan, const char *ifname); +void tap_win32_poll(void); + /* NIC info */ #define MAX_NICS 8 -- cgit v1.2.3 From 0fd14b72ac91516a0415f626d632ffa86f1e1a05 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 4 Feb 2006 17:40:20 +0000 Subject: fxsave/fxrstor fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1738 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index dab037807..0db0d4a4b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5803,14 +5803,24 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) op = (modrm >> 3) & 7; switch(op) { case 0: /* fxsave */ - if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || + (s->flags & HF_EM_MASK)) goto illegal_op; + if (s->flags & HF_TS_MASK) { + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + break; + } gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_fxsave_A0((s->dflag == 2)); break; case 1: /* fxrstor */ - if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || + (s->flags & HF_EM_MASK)) goto illegal_op; + if (s->flags & HF_TS_MASK) { + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + break; + } gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_fxrstor_A0((s->dflag == 2)); break; -- cgit v1.2.3 From 0240ded8bb1580147ed2ff1748df439a3b41e38f Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 4 Feb 2006 19:30:51 +0000 Subject: Correctly initialize Arm CPU for Thumb entry points. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1739 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index f1af656dc..29730dca7 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -100,7 +100,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i target_long *stack = (void *)infop->start_stack; memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; - regs->ARM_pc = infop->entry; + if (infop->entry & 1) + regs->ARM_cpsr |= CPSR_T; + regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; regs->ARM_r2 = tswapl(stack[2]); /* envp */ regs->ARM_r1 = tswapl(stack[1]); /* argv */ -- cgit v1.2.3 From 06c949e62a098f97bd68a7382eb1953898a11e09 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 4 Feb 2006 19:35:26 +0000 Subject: Implement Arm BKPT instruction. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1740 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 23 ++++++++++++++++++----- target-arm/cpu.h | 1 + target-arm/helper.c | 1 + target-arm/op.c | 6 ++++++ target-arm/translate.c | 13 +++++++++++++ 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index ef3a17116..56accfbb5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -358,14 +358,27 @@ void cpu_loop(CPUARMState *env) } break; case EXCP_SWI: + case EXCP_BKPT: { /* system call */ - if (env->thumb) { - insn = lduw((void *)(env->regs[15] - 2)); - n = insn & 0xff; + if (trapnr == EXCP_BKPT) { + if (env->thumb) { + insn = lduw((void *)(env->regs[15])); + n = insn & 0xff; + env->regs[15] += 2; + } else { + insn = ldl((void *)(env->regs[15])); + n = (insn & 0xf) | ((insn >> 4) & 0xff0); + env->regs[15] += 4; + } } else { - insn = ldl((void *)(env->regs[15] - 4)); - n = insn & 0xffffff; + if (env->thumb) { + insn = lduw((void *)(env->regs[15] - 2)); + n = insn & 0xff; + } else { + insn = ldl((void *)(env->regs[15] - 4)); + n = insn & 0xffffff; + } } if (n == ARM_NR_cacheflush) { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 3b36839e4..7cc7da60e 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -34,6 +34,7 @@ #define EXCP_DATA_ABORT 4 #define EXCP_IRQ 5 #define EXCP_FIQ 6 +#define EXCP_BKPT 7 /* We currently assume float and double are IEEE single and double precision respectively. diff --git a/target-arm/helper.c b/target-arm/helper.c index 538e17a35..5804df826 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -127,6 +127,7 @@ void do_interrupt(CPUARMState *env) offset = 0; break; case EXCP_PREFETCH_ABORT: + case EXCP_BKPT: new_mode = ARM_CPU_MODE_ABT; addr = 0x0c; mask = CPSR_A | CPSR_I; diff --git a/target-arm/op.c b/target-arm/op.c index 35419a1b7..acac2394a 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -885,6 +885,12 @@ void OPPROTO op_wfi(void) cpu_loop_exit(); } +void OPPROTO op_bkpt(void) +{ + env->exception_index = EXCP_BKPT; + cpu_loop_exit(); +} + /* VFP support. We follow the convention used for VFP instrunctions: Single precition routines have a "s" suffix, double precision a "d" suffix. */ diff --git a/target-arm/translate.c b/target-arm/translate.c index 089fbf2fd..5f817080f 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1217,6 +1217,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_addl_T0_T1_saturate(); gen_movl_reg_T0(s, rd); break; + case 7: /* bkpt */ + gen_op_movl_T0_im((long)s->pc - 4); + gen_op_movl_reg_TN[0][15](); + gen_op_bkpt(); + s->is_jmp = DISAS_JUMP; + break; case 0x8: /* signed multiply */ case 0xa: case 0xc: @@ -2183,6 +2189,13 @@ static void disas_thumb_insn(DisasContext *s) gen_bx(s); break; + case 0xe: /* bkpt */ + gen_op_movl_T0_im((long)s->pc - 2); + gen_op_movl_reg_TN[0][15](); + gen_op_bkpt(); + s->is_jmp = DISAS_JUMP; + break; + default: goto undef; } -- cgit v1.2.3 From e89f07d38427dc9e3aab17298d1bc0d339ed3004 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 4 Feb 2006 20:46:24 +0000 Subject: Make target_mmap always return -1 on failure. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1741 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 2 +- linux-user/mmap.c | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 29730dca7..c934fb831 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -890,7 +890,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, interpreter_fd, eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); - if (error > -1024UL) { + if (error == -1) { /* Real error */ close(interpreter_fd); free(elf_phdata); diff --git a/linux-user/mmap.c b/linux-user/mmap.c index a404ef3b0..948f2f6b2 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -183,8 +183,10 @@ long target_mmap(unsigned long start, unsigned long len, int prot, } #endif - if (offset & ~TARGET_PAGE_MASK) - return -EINVAL; + if (offset & ~TARGET_PAGE_MASK) { + errno = EINVAL; + return -1; + } len = TARGET_PAGE_ALIGN(len); if (len == 0) @@ -232,8 +234,10 @@ long target_mmap(unsigned long start, unsigned long len, int prot, } } - if (start & ~TARGET_PAGE_MASK) - return -EINVAL; + if (start & ~TARGET_PAGE_MASK) { + errno = EINVAL; + return -1; + } end = start + len; host_end = HOST_PAGE_ALIGN(end); @@ -244,8 +248,10 @@ long target_mmap(unsigned long start, unsigned long len, int prot, /* msync() won't work here, so we return an error if write is possible while it is a shared mapping */ if ((flags & MAP_TYPE) == MAP_SHARED && - (prot & PROT_WRITE)) - return -EINVAL; + (prot & PROT_WRITE)) { + errno = EINVAL; + return -1; + } retaddr = target_mmap(start, len, prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -- cgit v1.2.3 From 3442e8964e7ed6a79cf22e82232e4341a1805d82 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 4 Feb 2006 20:47:57 +0000 Subject: 64-bit host/cross fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1742 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 110 +++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 58 insertions(+), 52 deletions(-) diff --git a/dyngen.c b/dyngen.c index d95d6a452..fc4722ef9 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1679,7 +1679,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #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, val - start_offset); + fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset)); } } } @@ -1696,12 +1696,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); @@ -1710,10 +1712,10 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, chaining: the offset of the instruction needs to be stored */ fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", - n, rel->r_offset - start_offset); + n, reloc_offset); continue; } - + get_reloc_expr(name, sizeof(name), sym_name); addend = get32((uint32_t *)(text + rel->r_offset)); #ifdef CONFIG_FORMAT_ELF @@ -1721,11 +1723,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case R_386_32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - start_offset, name, addend); + 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", - rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + reloc_offset, name, reloc_offset, addend); break; default: error("unsupported i386 relocation (%d)", type); @@ -1748,11 +1750,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case DIR32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case DISP32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", - rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + reloc_offset, name, reloc_offset, addend); break; default: error("unsupported i386 relocation (%d)", type); @@ -1768,6 +1770,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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) { @@ -1775,18 +1778,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_X86_64_32S: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", - rel->r_offset - start_offset, name, addend); + 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", - rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + reloc_offset, name, reloc_offset, addend); break; default: error("unsupported X86_64 relocation (%d)", type); @@ -1800,10 +1804,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); @@ -1812,7 +1818,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, chaining: the offset of the instruction needs to be stored */ fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", - n, rel->r_offset - start_offset); + n, reloc_offset); continue; } @@ -1822,24 +1828,24 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case R_PPC_ADDR32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_PPC_ADDR16_LO: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_PPC_ADDR16_HI: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_PPC_ADDR16_HA: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", - rel->r_offset - start_offset, name, addend); + 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", - rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend); + reloc_offset, reloc_offset, name, reloc_offset, addend); break; default: error("unsupported powerpc relocation (%d)", type); @@ -1941,6 +1947,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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) { @@ -1948,18 +1955,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_390_16: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_390_8: fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; default: error("unsupported s390 relocation (%d)", type); @@ -1972,17 +1980,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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", - rel->r_offset - start_offset); + reloc_offset); fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n", - rel->r_offset - start_offset + rel->r_addend); + reloc_offset + (int)rel->r_addend); break; case R_ALPHA_LITUSE: /* jsr to literal hint. Could be used to optimize to bsr. Ignore for @@ -2002,18 +2012,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, special treatment. */ if (strstart(sym_name, "__op_param", &p)) fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n", - rel->r_offset - start_offset, p); + 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", - rel->r_offset - start_offset, p); + 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", - rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset); + reloc_offset, sym_name, reloc_offset); break; default: error("unsupported Alpha relocation (%d)", type); @@ -2035,6 +2045,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, || 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); @@ -2044,13 +2055,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, needs to be stored */ fprintf(outfile, " jmp_offsets[%d] =" "%ld + (gen_code_ptr - gen_code_buf);\n", - n, rel->r_offset - start_offset); + n, code_offset); continue; } get_reloc_expr(name, sizeof(name), sym_name); type = ELF64_R_TYPE(rel->r_info); addend = rel->r_addend; - code_offset = rel->r_offset - start_offset; switch(type) { case R_IA64_IMM64: fprintf(outfile, @@ -2101,6 +2111,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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) { @@ -2108,10 +2119,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_SPARC_HI22: fprintf(outfile, @@ -2119,9 +2131,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffff) " " | (((%s + %d) >> 10) & 0x3fffff);\n", - rel->r_offset - start_offset, - rel->r_offset - start_offset, - name, addend); + reloc_offset, reloc_offset, name, addend); break; case R_SPARC_LO10: fprintf(outfile, @@ -2129,9 +2139,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - rel->r_offset - start_offset, - rel->r_offset - start_offset, - name, addend); + reloc_offset, reloc_offset, name, addend); break; case R_SPARC_WDISP30: fprintf(outfile, @@ -2140,10 +2148,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " & ~0x3fffffff) " " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffffff);\n", - rel->r_offset - start_offset, - rel->r_offset - start_offset, - name, addend, - rel->r_offset - start_offset); + reloc_offset, reloc_offset, name, addend, + reloc_offset); break; default: error("unsupported sparc relocation (%d)", type); @@ -2156,6 +2162,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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) { @@ -2163,10 +2170,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, get_reloc_expr(name, sizeof(name), sym_name); type = ELF64_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", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_SPARC_HI22: fprintf(outfile, @@ -2174,9 +2182,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffff) " " | (((%s + %d) >> 10) & 0x3fffff);\n", - rel->r_offset - start_offset, - rel->r_offset - start_offset, - name, addend); + reloc_offset, reloc_offset, name, addend); break; case R_SPARC_LO10: fprintf(outfile, @@ -2184,9 +2190,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - rel->r_offset - start_offset, - rel->r_offset - start_offset, - name, addend); + reloc_offset, reloc_offset, name, addend); break; case R_SPARC_WDISP30: fprintf(outfile, @@ -2195,10 +2199,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " & ~0x3fffffff) " " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffffff);\n", - rel->r_offset - start_offset, - rel->r_offset - start_offset, - name, addend, - rel->r_offset - start_offset); + reloc_offset, reloc_offset, name, addend, + reloc_offset); break; default: error("unsupported sparc64 relocation (%d)", type); @@ -2211,6 +2213,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, char name[256]; int type; int addend; + int reloc_offset; arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end, relocs, nb_relocs); @@ -2225,14 +2228,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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", - rel->r_offset - start_offset, name, addend); + reloc_offset, name, addend); break; case R_ARM_PC24: fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", - rel->r_offset - start_offset, addend, name); + reloc_offset, addend, name); break; default: error("unsupported arm relocation (%d)", type); @@ -2245,6 +2249,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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 && @@ -2254,16 +2259,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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", - rel->r_offset - start_offset, name, addend ); + 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", - rel->r_offset - start_offset, name, rel->r_offset - start_offset, /*sym->st_value+*/ addend); + reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend); break; default: error("unsupported m68k relocation (%d)", type); -- cgit v1.2.3 From 191abaa2f0aca0c6ebca06f3e985da02ac950d14 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 4 Feb 2006 21:50:36 +0000 Subject: Fix Arm interrupted ldm bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1743 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 10 ++++++++++ target-arm/translate.c | 10 +++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/target-arm/op.c b/target-arm/op.c index acac2394a..f06b06b90 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -1181,3 +1181,13 @@ void OPPROTO op_movl_user_T0(void) } FORCE_RET(); } + +void OPPROTO op_movl_T2_T0(void) +{ + T2 = T0; +} + +void OPPROTO op_movl_T0_T2(void) +{ + T0 = T2; +} diff --git a/target-arm/translate.c b/target-arm/translate.c index 5f817080f..d5cbc5ee1 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1627,7 +1627,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0x08: case 0x09: { - int j, n, user; + int j, n, user, loaded_base; /* load/store multiple words */ /* XXX: store correct base if write back */ user = 0; @@ -1642,6 +1642,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_movl_T1_reg(s, rn); /* compute total size */ + loaded_base = 0; n = 0; for(i=0;i<16;i++) { if (insn & (1 << i)) @@ -1675,6 +1676,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_bx(s); } else if (user) { gen_op_movl_user_T0(i); + } else if (i == rn) { + gen_op_movl_T2_T0(); + loaded_base = 1; } else { gen_movl_reg_T0(s, i); } @@ -1718,6 +1722,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } gen_movl_reg_T1(s, rn); } + if (loaded_base) { + gen_op_movl_T0_T2(); + gen_movl_reg_T0(s, rn); + } if ((insn & (1 << 22)) && !user) { /* Restore CPSR from SPSR. */ gen_op_movl_T0_spsr(); -- cgit v1.2.3 From d861b05ea30e6ac177de9b679da96194ebe21afc Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 4 Feb 2006 22:15:28 +0000 Subject: Avoid buffer overflow when sending slirp packets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1744 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lance.c | 7 ++++++- hw/ne2000.c | 29 ++++++++++++++++++----------- hw/smc91c111.c | 14 +++++++++++++- vl.c | 29 +++++++++++++++++++++++------ vl.h | 9 ++++++++- 5 files changed, 68 insertions(+), 20 deletions(-) diff --git a/hw/lance.c b/hw/lance.c index 2fef6b1eb..c0cb0f98d 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -283,6 +283,11 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { #define MIN_BUF_SIZE 60 +static void lance_can_receive(void *opaque) +{ + return 1; +} + static void lance_receive(void *opaque, const uint8_t *buf, int size) { LANCEState *s = opaque; @@ -440,7 +445,7 @@ void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr) lance_reset(s); - s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, s); + s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", diff --git a/hw/ne2000.c b/hw/ne2000.c index efc3ea8ec..674d83e49 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -200,14 +200,10 @@ static int compute_mcast_idx(const uint8_t *ep) return (crc >> 26); } -/* return the max buffer size if the NE2000 can receive more data */ -static int ne2000_can_receive(void *opaque) +static int ne2000_buffer_full(NE2000State *s) { - NE2000State *s = opaque; int avail, index, boundary; - - if (s->cmd & E8390_STOP) - return 0; + index = s->curpag << 8; boundary = s->boundary << 8; if (index < boundary) @@ -215,8 +211,17 @@ static int ne2000_can_receive(void *opaque) else avail = (s->stop - s->start) - (index - boundary); if (avail < (MAX_ETH_FRAME_SIZE + 4)) - return 0; - return MAX_ETH_FRAME_SIZE; + return 1; + return 0; +} + +static int ne2000_can_receive(void *opaque) +{ + NE2000State *s = opaque; + + if (s->cmd & E8390_STOP) + return 1; + return !ne2000_buffer_full(s); } #define MIN_BUF_SIZE 60 @@ -234,7 +239,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) printf("NE2000: received len=%d\n", size); #endif - if (!ne2000_can_receive(s)) + if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) return; /* XXX: check this */ @@ -722,7 +727,8 @@ void isa_ne2000_init(int base, int irq, NICInfo *nd) ne2000_reset(s); - s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); + s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, + ne2000_can_receive, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x", @@ -791,7 +797,8 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd) s->pci_dev = (PCIDevice *)d; memcpy(s->macaddr, nd->macaddr, 6); ne2000_reset(s); - s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); + s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, + ne2000_can_receive, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 375debd1f..214e92efc 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -593,6 +593,17 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset) return val; } +static int smc91c111_can_receive(void *opaque) +{ + smc91c111_state *s = (smc91c111_state *)opaque; + + if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) + return 1; + if (s->allocated == (1 << NUM_PACKETS) - 1) + return 0; + return 1; +} + static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) { smc91c111_state *s = (smc91c111_state *)opaque; @@ -697,6 +708,7 @@ void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq) smc91c111_reset(s); - s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, s); + s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, + smc91c111_can_receive, s); /* ??? Save/restore. */ } diff --git a/vl.c b/vl.c index d875f2ac0..6d319bc33 100644 --- a/vl.c +++ b/vl.c @@ -1842,13 +1842,16 @@ VLANState *qemu_find_vlan(int id) } VLANClientState *qemu_new_vlan_client(VLANState *vlan, - IOReadHandler *fd_read, void *opaque) + IOReadHandler *fd_read, + IOCanRWHandler *fd_can_read, + void *opaque) { VLANClientState *vc, **pvc; vc = qemu_mallocz(sizeof(VLANClientState)); if (!vc) return NULL; vc->fd_read = fd_read; + vc->fd_can_read = fd_can_read; vc->opaque = opaque; vc->vlan = vlan; @@ -1860,6 +1863,20 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, return vc; } +int qemu_can_send_packet(VLANClientState *vc1) +{ + VLANState *vlan = vc1->vlan; + VLANClientState *vc; + + for(vc = vlan->first_client; vc != NULL; vc = vc->next) { + if (vc != vc1) { + if (vc->fd_can_read && !vc->fd_can_read(vc->opaque)) + return 0; + } + } + return 1; +} + void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) { VLANState *vlan = vc1->vlan; @@ -1885,7 +1902,7 @@ static VLANClientState *slirp_vc; int slirp_can_output(void) { - return 1; + return qemu_can_send_packet(slirp_vc); } void slirp_output(const uint8_t *pkt, int pkt_len) @@ -1913,7 +1930,7 @@ static int net_slirp_init(VLANState *vlan) slirp_init(); } slirp_vc = qemu_new_vlan_client(vlan, - slirp_receive, NULL); + slirp_receive, NULL, NULL); snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector"); return 0; } @@ -2098,7 +2115,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan, int fd) if (!s) return NULL; s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, tap_receive, s); + s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s); qemu_set_fd_handler(s->fd, tap_send, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd); return s; @@ -2412,7 +2429,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, return NULL; s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, s); + s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, NULL, s); qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); /* mcast: save bound address as dst */ @@ -2440,7 +2457,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, return NULL; s->fd = fd; s->vc = qemu_new_vlan_client(vlan, - net_socket_receive, s); + net_socket_receive, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "socket: fd=%d", fd); if (is_connected) { diff --git a/vl.h b/vl.h index 004498f6d..5986d5067 100644 --- a/vl.h +++ b/vl.h @@ -279,6 +279,9 @@ typedef struct VLANClientState VLANClientState; struct VLANClientState { IOReadHandler *fd_read; + /* Packets may still be sent if this returns zero. It's used to + rate-limit the slirp code. */ + IOCanRWHandler *fd_can_read; void *opaque; struct VLANClientState *next; struct VLANState *vlan; @@ -293,8 +296,12 @@ typedef struct VLANState { VLANState *qemu_find_vlan(int id); VLANClientState *qemu_new_vlan_client(VLANState *vlan, - IOReadHandler *fd_read, void *opaque); + IOReadHandler *fd_read, + IOCanRWHandler *fd_can_read, + void *opaque); +int qemu_can_send_packet(VLANClientState *vc); void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); +void qemu_handler_true(void *opaque); void do_info_network(void); -- cgit v1.2.3 From a41b2ff2ddd0ba05ac2ca1bb657603b1d09dc9bc Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 5 Feb 2006 04:14:41 +0000 Subject: Allow selection of emulated network card. rtl8139 emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1745 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 11 +- hw/integratorcp.c | 11 +- hw/mips_r4k.c | 11 +- hw/pc.c | 42 +- hw/pci.c | 14 + hw/ppc_chrp.c | 4 +- hw/ppc_prep.c | 8 +- hw/rtl8139.c | 2875 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/sun4m.c | 10 +- hw/sun4u.c | 4 +- qemu-doc.texi | 6 +- vl.c | 5 +- vl.h | 7 + 13 files changed, 2983 insertions(+), 25 deletions(-) create mode 100644 hw/rtl8139.c diff --git a/Makefile.target b/Makefile.target index a5a2aa0a5..2215f185f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -307,26 +307,29 @@ endif # USB layer VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o +# PCI network cards +VL_OBJS+= ne2000.o rtl8139.o + ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support -VL_OBJS+= ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +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 pc.o VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) -VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +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 mixeng.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) -VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.o +VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o #VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o ps2.o vga.o +VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o VL_OBJS+= cirrus_vga.o parallel.o VL_OBJS+= magic-load.o diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 1979c3943..d2b437ce1 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -1195,8 +1195,15 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, icp_control_init(0xcb000000); icp_kmi_init(0x18000000, pic, 3, 0); icp_kmi_init(0x19000000, pic, 4, 1); - if (nd_table[0].vlan) - smc91c111_init(&nd_table[0], 0xc8000000, pic, 27); + if (nd_table[0].vlan) { + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "smc91c111") == 0) { + smc91c111_init(&nd_table[0], 0xc8000000, pic, 27); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } + } /* Load the kernel. */ if (!kernel_filename) { diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 5f51f874c..eaaaad284 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -272,8 +272,15 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0, 0); - if (nd_table[0].vlan) - isa_ne2000_init(0x300, 9, &nd_table[0]); + if (nd_table[0].vlan) { + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "ne2k_isa") == 0) { + isa_ne2000_init(0x300, 9, &nd_table[0]); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } + } } QEMUMachine mips_machine = { diff --git a/hw/pc.c b/hw/pc.c index 8e750b684..fb8f87032 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -606,6 +606,16 @@ static void audio_init (PCIBus *pci_bus) } #endif +static void pc_init_ne2k_isa(NICInfo *nd) +{ + static int nb_ne2k = 0; + + if (nb_ne2k == NE2000_NB_MAX) + return; + isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd); + nb_ne2k++; +} + /* PC hardware initialisation */ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -614,11 +624,12 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, int pci_enabled) { char buf[1024]; - int ret, linux_boot, initrd_size, i, nb_nics1; + int ret, linux_boot, initrd_size, i; unsigned long bios_offset, vga_bios_offset; int bios_size, isa_bios_size; PCIBus *pci_bus; CPUState *env; + NICInfo *nd; linux_boot = (kernel_filename != NULL); @@ -800,19 +811,28 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } } - if (pci_enabled) { - for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(pci_bus, &nd_table[i]); + for(i = 0; i < nb_nics; i++) { + nd = &nd_table[i]; + if (!nd->model) { + if (pci_enabled) { + nd->model = "ne2k_pci"; + } else { + nd->model = "ne2k_isa"; + } } - pci_piix3_ide_init(pci_bus, bs_table); - } else { - nb_nics1 = nb_nics; - if (nb_nics1 > NE2000_NB_MAX) - nb_nics1 = NE2000_NB_MAX; - for(i = 0; i < nb_nics1; i++) { - isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + if (strcmp(nd->model, "ne2k_isa") == 0) { + pc_init_ne2k_isa(nd); + } else if (pci_enabled) { + pci_nic_init(pci_bus, nd); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); + exit(1); } + } + if (pci_enabled) { + pci_piix3_ide_init(pci_bus, bs_table); + } else { for(i = 0; i < 2; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], bs_table[2 * i], bs_table[2 * i + 1]); diff --git a/hw/pci.c b/hw/pci.c index f3456baca..e415ccf6c 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1837,3 +1837,17 @@ void pci_bios_init(void) } } } + +/* Initialize a PCI NIC. */ +void pci_nic_init(PCIBus *bus, NICInfo *nd) +{ + if (strcmp(nd->model, "ne2k_pci") == 0) { + pci_ne2000_init(bus, nd); + } else if (strcmp(nd->model, "rtl8139") == 0) { + pci_rtl8139_init(bus, nd); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); + exit (1); + } +} + diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 5187372c6..33167cdf7 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -436,7 +436,9 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(pci_bus, &nd_table[i]); + if (!nd_table[i].model) + nd_table[i].model = "ne2k_pci"; + pci_nic_init(pci_bus, &nd_table[i]); } pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index d4f302143..9df430775 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -624,7 +624,13 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; for(i = 0; i < nb_nics1; i++) { - isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "ne2k_isa") == 0) { + isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } } for(i = 0; i < 2; i++) { diff --git a/hw/rtl8139.c b/hw/rtl8139.c new file mode 100644 index 000000000..49c4c916b --- /dev/null +++ b/hw/rtl8139.c @@ -0,0 +1,2875 @@ +/** + * QEMU RTL8139 emulation + * + * Copyright (c) 2006 Igor Kovalenko + * + * 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. + + * Modifications: + * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver) + * + */ + +#include "vl.h" + + +/* debug RTL8139 card */ +//#define DEBUG_RTL8139 1 + +/* debug RTL8139 card C+ mode only */ +//#define DEBUG_RTL8139CP 1 + +/* RTL8139 provides frame CRC with received packet, this feature seems to be + ignored by most drivers, disabled by default */ +//#define RTL8139_CALCULATE_RXCRC 1 + + +#if defined(RTL8139_CALCULATE_RXCRC) +/* For crc32 */ +#include +#endif + +#define SET_MASKED(input, mask, curr) \ + ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) ) + +/* arg % size for size which is a power of 2 */ +#define MOD2(input, size) \ + ( ( input ) & ( size - 1 ) ) + +/* Symbolic offsets to registers. */ +enum RTL8139_registers { + MAC0 = 0, /* Ethernet hardware address. */ + MAR0 = 8, /* Multicast filter. */ + TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ + TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ + RxBuf = 0x30, + ChipCmd = 0x37, + RxBufPtr = 0x38, + RxBufAddr = 0x3A, + IntrMask = 0x3C, + IntrStatus = 0x3E, + TxConfig = 0x40, + RxConfig = 0x44, + Timer = 0x48, /* A general-purpose counter. */ + RxMissed = 0x4C, /* 24 bits valid, write clears. */ + Cfg9346 = 0x50, + Config0 = 0x51, + Config1 = 0x52, + FlashReg = 0x54, + MediaStatus = 0x58, + Config3 = 0x59, + Config4 = 0x5A, /* absent on RTL-8139A */ + HltClk = 0x5B, + MultiIntr = 0x5C, + PCIRevisionID = 0x5E, + TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/ + BasicModeCtrl = 0x62, + BasicModeStatus = 0x64, + NWayAdvert = 0x66, + NWayLPAR = 0x68, + NWayExpansion = 0x6A, + /* Undocumented registers, but required for proper operation. */ + FIFOTMS = 0x70, /* FIFO Control and test. */ + CSCR = 0x74, /* Chip Status and Configuration Register. */ + PARA78 = 0x78, + PARA7c = 0x7c, /* Magic transceiver parameter register. */ + Config5 = 0xD8, /* absent on RTL-8139A */ + /* C+ mode */ + TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */ + RxMaxSize = 0xDA, /* Max size of an Rx packet (8169 only) */ + CpCmd = 0xE0, /* C+ Command register (C+ mode only) */ + IntrMitigate = 0xE2, /* rx/tx interrupt mitigation control */ + RxRingAddrLO = 0xE4, /* 64-bit start addr of Rx ring */ + RxRingAddrHI = 0xE8, /* 64-bit start addr of Rx ring */ + TxThresh = 0xEC, /* Early Tx threshold */ +}; + +enum ClearBitMasks { + MultiIntrClear = 0xF000, + ChipCmdClear = 0xE2, + Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), +}; + +enum ChipCmdBits { + CmdReset = 0x10, + CmdRxEnb = 0x08, + CmdTxEnb = 0x04, + RxBufEmpty = 0x01, +}; + +/* C+ mode */ +enum CplusCmdBits { + CPlusRxEnb = 0x0002, + CPlusTxEnb = 0x0001, +}; + +/* Interrupt register bits, using my own meaningful names. */ +enum IntrStatusBits { + PCIErr = 0x8000, + PCSTimeout = 0x4000, + RxFIFOOver = 0x40, + RxUnderrun = 0x20, + RxOverflow = 0x10, + TxErr = 0x08, + TxOK = 0x04, + RxErr = 0x02, + RxOK = 0x01, + + RxAckBits = RxFIFOOver | RxOverflow | RxOK, +}; + +enum TxStatusBits { + TxHostOwns = 0x2000, + TxUnderrun = 0x4000, + TxStatOK = 0x8000, + TxOutOfWindow = 0x20000000, + TxAborted = 0x40000000, + TxCarrierLost = 0x80000000, +}; +enum RxStatusBits { + RxMulticast = 0x8000, + RxPhysical = 0x4000, + RxBroadcast = 0x2000, + RxBadSymbol = 0x0020, + RxRunt = 0x0010, + RxTooLong = 0x0008, + RxCRCErr = 0x0004, + RxBadAlign = 0x0002, + RxStatusOK = 0x0001, +}; + +/* Bits in RxConfig. */ +enum rx_mode_bits { + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0x08, + AcceptMulticast = 0x04, + AcceptMyPhys = 0x02, + AcceptAllPhys = 0x01, +}; + +/* Bits in TxConfig. */ +enum tx_config_bits { + + /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */ + TxIFGShift = 24, + TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */ + TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */ + TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */ + TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */ + + TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ + TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ + TxClearAbt = (1 << 0), /* Clear abort (WO) */ + TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */ + TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */ + + TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ +}; + + +/* Transmit Status of All Descriptors (TSAD) Register */ +enum TSAD_bits { + TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3 + TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2 + TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1 + TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0 + TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3 + TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2 + TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1 + TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0 + TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3 + TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2 + TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1 + TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0 + TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3 + TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2 + TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1 + TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0 +}; + + +/* Bits in Config1 */ +enum Config1Bits { + Cfg1_PM_Enable = 0x01, + Cfg1_VPD_Enable = 0x02, + Cfg1_PIO = 0x04, + Cfg1_MMIO = 0x08, + LWAKE = 0x10, /* not on 8139, 8139A */ + Cfg1_Driver_Load = 0x20, + Cfg1_LED0 = 0x40, + Cfg1_LED1 = 0x80, + SLEEP = (1 << 1), /* only on 8139, 8139A */ + PWRDN = (1 << 0), /* only on 8139, 8139A */ +}; + +/* Bits in Config3 */ +enum Config3Bits { + Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */ + Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */ + Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */ + Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */ + Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */ + Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */ + Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */ + Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */ +}; + +/* Bits in Config4 */ +enum Config4Bits { + LWPTN = (1 << 2), /* not on 8139, 8139A */ +}; + +/* Bits in Config5 */ +enum Config5Bits { + Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */ + Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */ + Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */ + Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */ + Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */ + Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */ + Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */ +}; + +enum RxConfigBits { + /* rx fifo threshold */ + RxCfgFIFOShift = 13, + RxCfgFIFONone = (7 << RxCfgFIFOShift), + + /* Max DMA burst */ + RxCfgDMAShift = 8, + RxCfgDMAUnlimited = (7 << RxCfgDMAShift), + + /* rx ring buffer length */ + RxCfgRcv8K = 0, + RxCfgRcv16K = (1 << 11), + RxCfgRcv32K = (1 << 12), + RxCfgRcv64K = (1 << 11) | (1 << 12), + + /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */ + RxNoWrap = (1 << 7), +}; + +/* Twister tuning parameters from RealTek. + Completely undocumented, but required to tune bad links on some boards. */ +/* +enum CSCRBits { + CSCR_LinkOKBit = 0x0400, + CSCR_LinkChangeBit = 0x0800, + CSCR_LinkStatusBits = 0x0f000, + CSCR_LinkDownOffCmd = 0x003c0, + CSCR_LinkDownCmd = 0x0f3c0, +*/ +enum CSCRBits { + CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */ + CSCR_LD = 1<<9, /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/ + CSCR_HEART_BIT = 1<<8, /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/ + CSCR_JBEN = 1<<7, /* 1 = enable jabber function. 0 = disable jabber function, def 1*/ + CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/ + CSCR_F_Connect = 1<<5, /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/ + CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/ + CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/ + CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/ +}; + +enum Cfg9346Bits { + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xC0, +}; + +typedef enum { + CH_8139 = 0, + CH_8139_K, + CH_8139A, + CH_8139A_G, + CH_8139B, + CH_8130, + CH_8139C, + CH_8100, + CH_8100B_8139D, + CH_8101, +} chip_t; + +enum chip_flags { + HasHltClk = (1 << 0), + HasLWake = (1 << 1), +}; + +#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \ + (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22) +#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1) + +/* Size is 64 * 16bit words */ +#define EEPROM_9346_ADDR_BITS 6 +#define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS) +#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1) + +enum Chip9346Operation +{ + Chip9346_op_mask = 0xc0, /* 10 zzzzzz */ + Chip9346_op_read = 0x80, /* 10 AAAAAA */ + Chip9346_op_write = 0x40, /* 01 AAAAAA D(15)..D(0) */ + Chip9346_op_ext_mask = 0xf0, /* 11 zzzzzz */ + Chip9346_op_write_enable = 0x30, /* 00 11zzzz */ + Chip9346_op_write_all = 0x10, /* 00 01zzzz */ + Chip9346_op_write_disable = 0x00, /* 00 00zzzz */ +}; + +enum Chip9346Mode +{ + Chip9346_none = 0, + Chip9346_enter_command_mode, + Chip9346_read_command, + Chip9346_data_read, /* from output register */ + Chip9346_data_write, /* to input register, then to contents at specified address */ + Chip9346_data_write_all, /* to input register, then filling contents */ +}; + +typedef struct EEprom9346 +{ + uint16_t contents[EEPROM_9346_SIZE]; + int mode; + uint32_t tick; + uint8_t address; + uint16_t input; + uint16_t output; + + uint8_t eecs; + uint8_t eesk; + uint8_t eedi; + uint8_t eedo; +} EEprom9346; + +typedef struct RTL8139State { + uint8_t phys[8]; /* mac address */ + uint8_t mult[8]; /* multicast mask array */ + + uint32_t TxStatus[4]; /* TxStatus0 */ + uint32_t TxAddr[4]; /* TxAddr0 */ + uint32_t RxBuf; /* Receive buffer */ + uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */ + uint32_t RxBufPtr; + uint32_t RxBufAddr; + + uint16_t IntrStatus; + uint16_t IntrMask; + + uint32_t TxConfig; + uint32_t RxConfig; + uint32_t RxMissed; + + uint16_t CSCR; + + uint8_t Cfg9346; + uint8_t Config0; + uint8_t Config1; + uint8_t Config3; + uint8_t Config4; + uint8_t Config5; + + uint8_t clock_enabled; + uint8_t bChipCmdState; + + uint16_t MultiIntr; + + uint16_t BasicModeCtrl; + uint16_t BasicModeStatus; + uint16_t NWayAdvert; + uint16_t NWayLPAR; + uint16_t NWayExpansion; + + uint16_t CpCmd; + uint8_t TxThresh; + + int irq; + PCIDevice *pci_dev; + VLANClientState *vc; + uint8_t macaddr[6]; + int rtl8139_mmio_io_addr; + + /* C ring mode */ + uint32_t currTxDesc; + + /* C+ mode */ + uint32_t currCPlusRxDesc; + uint32_t currCPlusTxDesc; + + uint32_t RxRingAddrLO; + uint32_t RxRingAddrHI; + + EEprom9346 eeprom; + +} RTL8139State; + +void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) +{ +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom command 0x%02x\n", command); +#endif + + switch (command & Chip9346_op_mask) + { + case Chip9346_op_read: + { + eeprom->address = command & EEPROM_9346_ADDR_MASK; + eeprom->output = eeprom->contents[eeprom->address]; + eeprom->eedo = 0; + eeprom->tick = 0; + eeprom->mode = Chip9346_data_read; +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output); +#endif + } + break; + + case Chip9346_op_write: + { + eeprom->address = command & EEPROM_9346_ADDR_MASK; + eeprom->input = 0; + eeprom->tick = 0; + eeprom->mode = Chip9346_none; /* Chip9346_data_write */ +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom begin write to address 0x%02x\n", + eeprom->address); +#endif + } + break; + default: + eeprom->mode = Chip9346_none; + switch (command & Chip9346_op_ext_mask) + { + case Chip9346_op_write_enable: +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom write enabled\n"); +#endif + break; + case Chip9346_op_write_all: +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom begin write all\n"); +#endif + break; + case Chip9346_op_write_disable: +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom write disabled\n"); +#endif + break; + } + break; + } +} + +void prom9346_shift_clock(EEprom9346 *eeprom) +{ + int bit = eeprom->eedi?1:0; + + ++ eeprom->tick; + +#if defined(DEBUG_RTL8139) + printf("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo); +#endif + + switch (eeprom->mode) + { + case Chip9346_enter_command_mode: + if (bit) + { + eeprom->mode = Chip9346_read_command; + eeprom->tick = 0; + eeprom->input = 0; +#if defined(DEBUG_RTL8139) + printf("eeprom: +++ synchronized, begin command read\n"); +#endif + } + break; + + case Chip9346_read_command: + eeprom->input = (eeprom->input << 1) | (bit & 1); + if (eeprom->tick == 8) + { + prom9346_decode_command(eeprom, eeprom->input & 0xff); + } + break; + + case Chip9346_data_read: + eeprom->eedo = (eeprom->output & 0x8000)?1:0; + eeprom->output <<= 1; + if (eeprom->tick == 16) + { + ++eeprom->address; + eeprom->address &= EEPROM_9346_ADDR_MASK; + eeprom->output = eeprom->contents[eeprom->address]; + eeprom->tick = 0; + +#if defined(DEBUG_RTL8139) + printf("eeprom: +++ read next address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output); +#endif + } + break; + + case Chip9346_data_write: + eeprom->input = (eeprom->input << 1) | (bit & 1); + if (eeprom->tick == 16) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->input); +#endif + eeprom->contents[eeprom->address] = eeprom->input; + eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */ + eeprom->tick = 0; + eeprom->input = 0; + } + break; + + case Chip9346_data_write_all: + eeprom->input = (eeprom->input << 1) | (bit & 1); + if (eeprom->tick == 16) + { + int i; + for (i = 0; i < EEPROM_9346_SIZE; i++) + { + eeprom->contents[i] = eeprom->input; + } +#if defined(DEBUG_RTL8139) + printf("RTL8139: eeprom filled with data=0x%04x\n", + eeprom->input); +#endif + eeprom->mode = Chip9346_enter_command_mode; + eeprom->tick = 0; + eeprom->input = 0; + } + break; + + default: + break; + } +} + +int prom9346_get_wire(RTL8139State *s) +{ + EEprom9346 *eeprom = &s->eeprom; + if (!eeprom->eecs) + return 0; + + return eeprom->eedo; +} + +void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) +{ + EEprom9346 *eeprom = &s->eeprom; + uint8_t old_eecs = eeprom->eecs; + uint8_t old_eesk = eeprom->eesk; + + eeprom->eecs = eecs; + eeprom->eesk = eesk; + eeprom->eedi = eedi; + +#if defined(DEBUG_RTL8139) + printf("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo); +#endif + + if (!old_eecs && eecs) + { + /* Synchronize start */ + eeprom->tick = 0; + eeprom->input = 0; + eeprom->output = 0; + eeprom->mode = Chip9346_enter_command_mode; + +#if defined(DEBUG_RTL8139) + printf("=== eeprom: begin access, enter command mode\n"); +#endif + + } + + if (!eecs) + { +#if defined(DEBUG_RTL8139) + printf("=== eeprom: end access\n"); +#endif + return; + } + + if (!old_eesk && eesk) + { + /* SK front rules */ + prom9346_shift_clock(eeprom); + } +} + +static void rtl8139_update_irq(RTL8139State *s) +{ + int isr; + isr = (s->IntrStatus & s->IntrMask) & 0xffff; +#if defined(DEBUG_RTL8139) + printf("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", + s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask); +#endif + if (s->irq == 16) { + /* PCI irq */ + pci_set_irq(s->pci_dev, 0, (isr != 0)); + } else { + /* ISA irq */ + pic_set_irq(s->irq, (isr != 0)); + } +} + +#define POLYNOMIAL 0x04c11db6 + +/* From FreeBSD */ +/* XXX: optimize */ +static int compute_mcast_idx(const uint8_t *ep) +{ + uint32_t crc; + int carry, i, j; + uint8_t b; + + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + b = *ep++; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); + crc <<= 1; + b >>= 1; + if (carry) + crc = ((crc ^ POLYNOMIAL) | carry); + } + } + return (crc >> 26); +} + +static int rtl8139_RxWrap(RTL8139State *s) +{ + /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */ + return (s->RxConfig & (1 << 7)); +} + +static int rtl8139_receiver_enabled(RTL8139State *s) +{ + return s->bChipCmdState & CmdRxEnb; +} + +static int rtl8139_transmitter_enabled(RTL8139State *s) +{ + return s->bChipCmdState & CmdTxEnb; +} + +static int rtl8139_cp_receiver_enabled(RTL8139State *s) +{ + return s->CpCmd & CPlusRxEnb; +} + +static int rtl8139_cp_transmitter_enabled(RTL8139State *s) +{ + return s->CpCmd & CPlusTxEnb; +} + +static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) +{ + if (s->RxBufAddr + size > s->RxBufferSize) + { + int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize); + + /* write packet data */ + if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s)) + { + #if defined(DEBUG_RTL8139) + printf(">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped); + #endif + + if (size > wrapped) + { + cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, + buf, size-wrapped ); + } + + /* reset buffer pointer */ + s->RxBufAddr = 0; + + cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, + buf + (size-wrapped), wrapped ); + + s->RxBufAddr = wrapped; + + return; + } + } + + /* non-wrapping path or overwrapping enabled */ + cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size ); + + s->RxBufAddr += size; +} + +#define MIN_BUF_SIZE 60 +static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high) +{ +#if TARGET_PHYS_ADDR_BITS > 32 + return low | ((target_phys_addr_t)high << 32); +#else + return low; +#endif +} + +static int rtl8139_can_receive(void *opaque) +{ + RTL8139State *s = opaque; + int avail; + + /* Recieve (drop) packets if card is disabled. */ + if (!s->clock_enabled) + return 1; + if (!rtl8139_receiver_enabled(s)) + return 1; + + if (rtl8139_cp_receiver_enabled(s)) { + /* ??? Flow control not implemented in c+ mode. + This is a hack to work around slirp deficiencies anyway. */ + return 1; + } else { + avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, + s->RxBufferSize); + return (avail == 0 || avail >= 1514); + } +} + +static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +{ + RTL8139State *s = opaque; + + uint32_t packet_header = 0; + + uint8_t buf1[60]; + static const uint8_t broadcast_macaddr[6] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: received len=%d\n", size); +#endif + + /* test if board clock is stopped */ + if (!s->clock_enabled) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: stopped ==========================\n"); +#endif + return; + } + + /* first check if receiver is enabled */ + + if (!rtl8139_receiver_enabled(s)) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: receiver disabled ================\n"); +#endif + return; + } + + /* XXX: check this */ + if (s->RxConfig & AcceptAllPhys) { + /* promiscuous: receive all */ +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: packet received in promiscuous mode\n"); +#endif + + } else { + if (!memcmp(buf, broadcast_macaddr, 6)) { + /* broadcast address */ + if (!(s->RxConfig & AcceptBroadcast)) + { +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: broadcast packet rejected\n"); +#endif + return; + } + + packet_header |= RxBroadcast; + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: broadcast packet received\n"); +#endif + } else if (buf[0] & 0x01) { + /* multicast */ + if (!(s->RxConfig & AcceptMulticast)) + { +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: multicast packet rejected\n"); +#endif + return; + } + + int mcast_idx = compute_mcast_idx(buf); + + if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) + { +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: multicast address mismatch\n"); +#endif + return; + } + + packet_header |= RxMulticast; + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: multicast packet received\n"); +#endif + } else if (s->phys[0] == buf[0] && + s->phys[1] == buf[1] && + s->phys[2] == buf[2] && + s->phys[3] == buf[3] && + s->phys[4] == buf[4] && + s->phys[5] == buf[5]) { + /* match */ + if (!(s->RxConfig & AcceptMyPhys)) + { +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: rejecting physical address matching packet\n"); +#endif + return; + } + + packet_header |= RxPhysical; + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: physical address matching packet received\n"); +#endif + + } else { + +#if defined(DEBUG_RTL8139) + printf(">>> RTL8139: unknown packet\n"); +#endif + return; + } + } + + /* if too small buffer, then expand it */ + if (size < MIN_BUF_SIZE) { + memcpy(buf1, buf, size); + memset(buf1 + size, 0, MIN_BUF_SIZE - size); + buf = buf1; + size = MIN_BUF_SIZE; + } + + if (rtl8139_cp_receiver_enabled(s)) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: in C+ Rx mode ================\n"); +#endif + + /* begin C+ receiver mode */ + +/* w0 ownership flag */ +#define CP_RX_OWN (1<<31) +/* w0 end of ring flag */ +#define CP_RX_EOR (1<<30) +/* w0 bits 0...12 : buffer size */ +#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1) +/* w1 tag available flag */ +#define CP_RX_TAVA (1<<16) +/* w1 bits 0...15 : VLAN tag */ +#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1) +/* w2 low 32bit of Rx buffer ptr */ +/* w3 high 32bit of Rx buffer ptr */ + + int descriptor = s->currCPlusRxDesc; + target_phys_addr_t cplus_rx_ring_desc; + + cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); + cplus_rx_ring_desc += 16 * descriptor; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = 0x%8lx\n", + descriptor, s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc); +#endif + + uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; + + cpu_physical_memory_read(cplus_rx_ring_desc, (uint8_t *)&val, 4); + rxdw0 = le32_to_cpu(val); + cpu_physical_memory_read(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); + rxdw1 = le32_to_cpu(val); + cpu_physical_memory_read(cplus_rx_ring_desc+8, (uint8_t *)&val, 4); + rxbufLO = le32_to_cpu(val); + cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4); + rxbufHI = le32_to_cpu(val); + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", + descriptor, + rxdw0, rxdw1, rxbufLO, rxbufHI); +#endif + + if (!(rxdw0 & CP_RX_OWN)) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor); +#endif + s->IntrStatus |= RxOverflow; + ++s->RxMissed; + rtl8139_update_irq(s); + return; + } + + uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; + + if (size+4 > rx_space) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", + descriptor, rx_space, size); +#endif + s->IntrStatus |= RxOverflow; + ++s->RxMissed; + rtl8139_update_irq(s); + return; + } + + target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI); + + /* receive/copy to target memory */ + cpu_physical_memory_write( rx_addr, buf, size ); + + /* write checksum */ +#if defined (RTL8139_CALCULATE_RXCRC) + val = cpu_to_le32(crc32(~0, buf, size)); +#else + val = 0; +#endif + cpu_physical_memory_write( rx_addr+size, (uint8_t *)&val, 4); + +/* first segment of received packet flag */ +#define CP_RX_STATUS_FS (1<<29) +/* last segment of received packet flag */ +#define CP_RX_STATUS_LS (1<<28) +/* multicast packet flag */ +#define CP_RX_STATUS_MAR (1<<26) +/* physical-matching packet flag */ +#define CP_RX_STATUS_PAM (1<<25) +/* broadcast packet flag */ +#define CP_RX_STATUS_BAR (1<<24) +/* runt packet flag */ +#define CP_RX_STATUS_RUNT (1<<19) +/* crc error flag */ +#define CP_RX_STATUS_CRC (1<<18) +/* IP checksum error flag */ +#define CP_RX_STATUS_IPF (1<<15) +/* UDP checksum error flag */ +#define CP_RX_STATUS_UDPF (1<<14) +/* TCP checksum error flag */ +#define CP_RX_STATUS_TCPF (1<<13) + + /* transfer ownership to target */ + rxdw0 &= ~CP_RX_OWN; + + /* set first segment bit */ + rxdw0 |= CP_RX_STATUS_FS; + + /* set last segment bit */ + rxdw0 |= CP_RX_STATUS_LS; + + /* set received packet type flags */ + if (packet_header & RxBroadcast) + rxdw0 |= CP_RX_STATUS_BAR; + if (packet_header & RxMulticast) + rxdw0 |= CP_RX_STATUS_MAR; + if (packet_header & RxPhysical) + rxdw0 |= CP_RX_STATUS_PAM; + + /* set received size */ + rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK; + rxdw0 |= (size+4); + + /* reset VLAN tag flag */ + rxdw1 &= ~CP_RX_TAVA; + + /* update ring data */ + val = cpu_to_le32(rxdw0); + cpu_physical_memory_write(cplus_rx_ring_desc, (uint8_t *)&val, 4); + val = cpu_to_le32(rxdw1); + cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); + + /* seek to next Rx descriptor */ + if (rxdw0 & CP_RX_EOR) + { + s->currCPlusRxDesc = 0; + } + else + { + ++s->currCPlusRxDesc; + } + +#if defined(DEBUG_RTL8139) + printf("RTL8139: done C+ Rx mode ----------------\n"); +#endif + + } + else + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: in ring Rx mode ================\n"); +#endif + /* begin ring receiver mode */ + int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize); + + /* if receiver buffer is empty then avail == 0 */ + + if (avail != 0 && size + 8 >= avail) + { +#if defined(DEBUG_RTL8139) + printf("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8); +#endif + s->IntrStatus |= RxOverflow; + ++s->RxMissed; + rtl8139_update_irq(s); + return; + } + + packet_header |= RxStatusOK; + + packet_header |= (((size+4) << 16) & 0xffff0000); + + /* write header */ + uint32_t val = cpu_to_le32(packet_header); + + rtl8139_write_buffer(s, (uint8_t *)&val, 4); + + rtl8139_write_buffer(s, buf, size); + + /* write checksum */ +#if defined (RTL8139_CALCULATE_RXCRC) + val = cpu_to_le32(crc32(~0, buf, size)); +#else + val = 0; +#endif + + rtl8139_write_buffer(s, (uint8_t *)&val, 4); + + /* correct buffer write pointer */ + s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize); + + /* now we can signal we have received something */ + +#if defined(DEBUG_RTL8139) + printf(" received: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); +#endif + + } + + s->IntrStatus |= RxOK; + rtl8139_update_irq(s); +} + +static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) +{ + s->RxBufferSize = bufferSize; + s->RxBufPtr = 0; + s->RxBufAddr = 0; +} + +static void rtl8139_reset(RTL8139State *s) +{ + int i; + + /* restore MAC address */ + memcpy(s->phys, s->macaddr, 6); + + /* reset interrupt mask */ + s->IntrStatus = 0; + s->IntrMask = 0; + + rtl8139_update_irq(s); + + /* prepare eeprom */ + s->eeprom.contents[0] = 0x8129; + memcpy(&s->eeprom.contents[7], s->macaddr, 6); + + /* mark all status registers as owned by host */ + for (i = 0; i < 4; ++i) + { + s->TxStatus[i] = TxHostOwns; + } + + s->currTxDesc = 0; + s->currCPlusRxDesc = 0; + s->currCPlusTxDesc = 0; + + s->RxRingAddrLO = 0; + s->RxRingAddrHI = 0; + + s->RxBuf = 0; + + rtl8139_reset_rxring(s, 8192); + + /* ACK the reset */ + s->TxConfig = 0; + +#if 0 +// s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk + s->clock_enabled = 0; +#else + s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 0, 0); // RTL-8139C HasLWake + s->clock_enabled = 1; +#endif + + s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */; + + /* set initial state data */ + s->Config0 = 0x0; /* No boot ROM */ + s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */ + s->Config3 = 0x1; /* fast back-to-back compatible */ + s->Config5 = 0x0; + + s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; + + s->CpCmd = 0x0; /* reset C+ mode */ + +// s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation +// s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex + s->BasicModeCtrl = 0x1000; // autonegotiation + + s->BasicModeStatus = 0x7809; + //s->BasicModeStatus |= 0x0040; /* UTP medium */ + s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ + s->BasicModeStatus |= 0x0004; /* link is up */ + + s->NWayAdvert = 0x05e1; /* all modes, full duplex */ + s->NWayLPAR = 0x05e1; /* all modes, full duplex */ + s->NWayExpansion = 0x0001; /* autonegotiation supported */ +} + +static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) +{ + val &= 0xff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd write val=0x%08x\n", val); +#endif + + if (val & CmdReset) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd reset\n"); +#endif + rtl8139_reset(s); + } + if (val & CmdRxEnb) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd enable receiver\n"); +#endif + } + if (val & CmdTxEnb) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd enable transmitter\n"); +#endif + } + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0xe3, s->bChipCmdState); + + /* Deassert reset pin before next read */ + val &= ~CmdReset; + + s->bChipCmdState = val; +} + +static int rtl8139_RxBufferEmpty(RTL8139State *s) +{ + int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize); + + if (unread != 0) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: receiver buffer data available 0x%04x\n", unread); +#endif + return 0; + } + +#ifdef DEBUG_RTL8139 + printf("RTL8139: receiver buffer is empty\n"); +#endif + + return 1; +} + +static uint32_t rtl8139_ChipCmd_read(RTL8139State *s) +{ + uint32_t ret = s->bChipCmdState; + + if (rtl8139_RxBufferEmpty(s)) + ret |= RxBufEmpty; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: ChipCmd read val=0x%04x\n", ret); +#endif + + return ret; +} + +static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val) +{ + val &= 0xffff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139C+ command register write(w) val=0x%04x\n", val); +#endif + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0xff84, s->CpCmd); + + s->CpCmd = val; +} + +static uint32_t rtl8139_CpCmd_read(RTL8139State *s) +{ + uint32_t ret = s->CpCmd; + +#ifdef DEBUG_RTL8139 + printf("RTL8139C+ command register read(w) val=0x%04x\n", ret); +#endif + + return ret; +} + +int rtl8139_config_writeable(RTL8139State *s) +{ + if (s->Cfg9346 & Cfg9346_Unlock) + { + return 1; + } + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Configuration registers are write-protected\n"); +#endif + + return 0; +} + +static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) +{ + val &= 0xffff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val); +#endif + + /* mask unwriteable bits */ + uint32 mask = 0x4cff; + + if (1 || !rtl8139_config_writeable(s)) + { + /* Speed setting and autonegotiation enable bits are read-only */ + mask |= 0x3000; + /* Duplex mode setting is read-only */ + mask |= 0x0100; + } + + val = SET_MASKED(val, mask, s->BasicModeCtrl); + + s->BasicModeCtrl = val; +} + +static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s) +{ + uint32_t ret = s->BasicModeCtrl; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret); +#endif + + return ret; +} + +static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val) +{ + val &= 0xffff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val); +#endif + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0xff3f, s->BasicModeStatus); + + s->BasicModeStatus = val; +} + +static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s) +{ + uint32_t ret = s->BasicModeStatus; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret); +#endif + + return ret; +} + +static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val) +{ + val &= 0xff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Cfg9346 write val=0x%02x\n", val); +#endif + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0x31, s->Cfg9346); + + uint32_t opmode = val & 0xc0; + uint32_t eeprom_val = val & 0xf; + + if (opmode == 0x80) { + /* eeprom access */ + int eecs = (eeprom_val & 0x08)?1:0; + int eesk = (eeprom_val & 0x04)?1:0; + int eedi = (eeprom_val & 0x02)?1:0; + prom9346_set_wire(s, eecs, eesk, eedi); + } else if (opmode == 0x40) { + /* Reset. */ + val = 0; + rtl8139_reset(s); + } + + s->Cfg9346 = val; +} + +static uint32_t rtl8139_Cfg9346_read(RTL8139State *s) +{ + uint32_t ret = s->Cfg9346; + + uint32_t opmode = ret & 0xc0; + + if (opmode == 0x80) + { + /* eeprom access */ + int eedo = prom9346_get_wire(s); + if (eedo) + { + ret |= 0x01; + } + else + { + ret &= ~0x01; + } + } + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Cfg9346 read val=0x%02x\n", ret); +#endif + + return ret; +} + +static void rtl8139_Config0_write(RTL8139State *s, uint32_t val) +{ + val &= 0xff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config0 write val=0x%02x\n", val); +#endif + + if (!rtl8139_config_writeable(s)) + return; + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0xf8, s->Config0); + + s->Config0 = val; +} + +static uint32_t rtl8139_Config0_read(RTL8139State *s) +{ + uint32_t ret = s->Config0; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config0 read val=0x%02x\n", ret); +#endif + + return ret; +} + +static void rtl8139_Config1_write(RTL8139State *s, uint32_t val) +{ + val &= 0xff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config1 write val=0x%02x\n", val); +#endif + + if (!rtl8139_config_writeable(s)) + return; + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0xC, s->Config1); + + s->Config1 = val; +} + +static uint32_t rtl8139_Config1_read(RTL8139State *s) +{ + uint32_t ret = s->Config1; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config1 read val=0x%02x\n", ret); +#endif + + return ret; +} + +static void rtl8139_Config3_write(RTL8139State *s, uint32_t val) +{ + val &= 0xff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config3 write val=0x%02x\n", val); +#endif + + if (!rtl8139_config_writeable(s)) + return; + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0x8F, s->Config3); + + s->Config3 = val; +} + +static uint32_t rtl8139_Config3_read(RTL8139State *s) +{ + uint32_t ret = s->Config3; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config3 read val=0x%02x\n", ret); +#endif + + return ret; +} + +static void rtl8139_Config4_write(RTL8139State *s, uint32_t val) +{ + val &= 0xff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config4 write val=0x%02x\n", val); +#endif + + if (!rtl8139_config_writeable(s)) + return; + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0x0a, s->Config4); + + s->Config4 = val; +} + +static uint32_t rtl8139_Config4_read(RTL8139State *s) +{ + uint32_t ret = s->Config4; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config4 read val=0x%02x\n", ret); +#endif + + return ret; +} + +static void rtl8139_Config5_write(RTL8139State *s, uint32_t val) +{ + val &= 0xff; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config5 write val=0x%02x\n", val); +#endif + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0x80, s->Config5); + + s->Config5 = val; +} + +static uint32_t rtl8139_Config5_read(RTL8139State *s) +{ + uint32_t ret = s->Config5; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: Config5 read val=0x%02x\n", ret); +#endif + + return ret; +} + +static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val) +{ + if (!rtl8139_transmitter_enabled(s)) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val); +#endif + return; + } + +#ifdef DEBUG_RTL8139 + printf("RTL8139: TxConfig write val=0x%08x\n", val); +#endif + + val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig); + + s->TxConfig = val; +} + +static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val) +{ +#ifdef DEBUG_RTL8139 + printf("RTL8139C TxConfig via write(b) val=0x%02x\n", val); +#endif + uint32_t tc = s->TxConfig; + tc &= 0xFFFFFF00; + tc |= (val & 0x000000FF); + rtl8139_TxConfig_write(s, tc); +} + +static uint32_t rtl8139_TxConfig_read(RTL8139State *s) +{ + uint32_t ret = s->TxConfig; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: TxConfig read val=0x%04x\n", ret); +#endif + + return ret; +} + +static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) +{ +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxConfig write val=0x%08x\n", val); +#endif + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0xf0fc0040, s->RxConfig); + + s->RxConfig = val; + + /* reset buffer size and read/write pointers */ + rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3)); + +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize); +#endif +} + +static uint32_t rtl8139_RxConfig_read(RTL8139State *s) +{ + uint32_t ret = s->RxConfig; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxConfig read val=0x%08x\n", ret); +#endif + + return ret; +} + +static int rtl8139_transmit_one(RTL8139State *s, int descriptor) +{ + if (!rtl8139_transmitter_enabled(s)) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", descriptor); +#endif + return 0; + } + + if (s->TxStatus[descriptor] & TxHostOwns) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", descriptor, s->TxStatus[descriptor]); +#endif + return 0; + } + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ transmitting from descriptor %d\n", descriptor); +#endif + + int txsize = s->TxStatus[descriptor] & 0x1fff; + uint8_t txbuffer[0x2000]; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", txsize, s->TxAddr[descriptor]); +#endif + cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); + + qemu_send_packet(s->vc, txbuffer, txsize); + + /* Mark descriptor as transferred */ + s->TxStatus[descriptor] |= TxHostOwns; + s->TxStatus[descriptor] |= TxStatOK; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor); +#endif + + /* update interrupt */ + s->IntrStatus |= TxOK; + rtl8139_update_irq(s); + + return 1; +} + +static int rtl8139_cplus_transmit_one(RTL8139State *s) +{ + if (!rtl8139_transmitter_enabled(s)) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode: transmitter disabled\n"); +#endif + return 0; + } + + if (!rtl8139_cp_transmitter_enabled(s)) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode: C+ transmitter disabled\n"); +#endif + return 0 ; + } + + int descriptor = s->currCPlusTxDesc; + + target_phys_addr_t cplus_tx_ring_desc = + rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]); + + /* Normal priority ring */ + cplus_tx_ring_desc += 16 * descriptor; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", + descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc); +#endif + + uint32_t val, txdw0,txdw1,txbufLO,txbufHI; + + cpu_physical_memory_read(cplus_tx_ring_desc, (uint8_t *)&val, 4); + txdw0 = le32_to_cpu(val); + cpu_physical_memory_read(cplus_tx_ring_desc+4, (uint8_t *)&val, 4); + txdw1 = le32_to_cpu(val); + cpu_physical_memory_read(cplus_tx_ring_desc+8, (uint8_t *)&val, 4); + txbufLO = le32_to_cpu(val); + cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4); + txbufHI = le32_to_cpu(val); + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", + descriptor, + txdw0, txdw1, txbufLO, txbufHI); +#endif + +/* w0 ownership flag */ +#define CP_TX_OWN (1<<31) +/* w0 end of ring flag */ +#define CP_TX_EOR (1<<30) +/* first segment of received packet flag */ +#define CP_TX_FS (1<<29) +/* last segment of received packet flag */ +#define CP_TX_LS (1<<28) +/* large send packet flag */ +#define CP_TX_LGSEN (1<<27) +/* IP checksum offload flag */ +#define CP_TX_IPCS (1<<18) +/* UDP checksum offload flag */ +#define CP_TX_UDPCS (1<<17) +/* TCP checksum offload flag */ +#define CP_TX_TCPCS (1<<16) + +/* w0 bits 0...15 : buffer size */ +#define CP_TX_BUFFER_SIZE (1<<16) +#define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1) +/* w1 tag available flag */ +#define CP_RX_TAGC (1<<17) +/* w1 bits 0...15 : VLAN tag */ +#define CP_TX_VLAN_TAG_MASK ((1<<16) - 1) +/* w2 low 32bit of Rx buffer ptr */ +/* w3 high 32bit of Rx buffer ptr */ + +/* set after transmission */ +/* FIFO underrun flag */ +#define CP_TX_STATUS_UNF (1<<25) +/* transmit error summary flag, valid if set any of three below */ +#define CP_TX_STATUS_TES (1<<23) +/* out-of-window collision flag */ +#define CP_TX_STATUS_OWC (1<<22) +/* link failure flag */ +#define CP_TX_STATUS_LNKF (1<<21) +/* excessive collisions flag */ +#define CP_TX_STATUS_EXC (1<<20) + + if (!(txdw0 & CP_TX_OWN)) + { +#if defined(DEBUG_RTL8139) + printf("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor); +#endif + return 0 ; + } + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor); +#endif + + int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK; + target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI); + + uint8_t txbuffer[CP_TX_BUFFER_SIZE]; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at 0x%08x\n", txsize, tx_addr); +#endif + cpu_physical_memory_read(tx_addr, txbuffer, txsize); + + /* transmit the packet */ + qemu_send_packet(s->vc, txbuffer, txsize); + + /* transfer ownership to target */ + txdw0 &= ~CP_RX_OWN; + + /* reset error indicator bits */ + txdw0 &= ~CP_TX_STATUS_UNF; + txdw0 &= ~CP_TX_STATUS_TES; + txdw0 &= ~CP_TX_STATUS_OWC; + txdw0 &= ~CP_TX_STATUS_LNKF; + txdw0 &= ~CP_TX_STATUS_EXC; + + /* update ring data */ + val = cpu_to_le32(txdw0); + cpu_physical_memory_write(cplus_tx_ring_desc, (uint8_t *)&val, 4); +// val = cpu_to_le32(txdw1); +// cpu_physical_memory_write(cplus_tx_ring_desc+4, &val, 4); + + /* seek to next Rx descriptor */ + if (txdw0 & CP_TX_EOR) + { + s->currCPlusTxDesc = 0; + } + else + { + ++s->currCPlusTxDesc; + } + +#ifdef DEBUG_RTL8139 + printf("RTL8139: +++ C+ mode transmitted %d bytes from descriptor %d\n", txsize, descriptor); +#endif + return 1; +} + +static void rtl8139_cplus_transmit(RTL8139State *s) +{ + int txcount = 0; + + while (rtl8139_cplus_transmit_one(s)) + { + ++txcount; + } + + /* Mark transfer completed */ + if (!txcount) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", s->currCPlusTxDesc); +#endif + } + else + { + /* update interrupt status */ + s->IntrStatus |= TxOK; + rtl8139_update_irq(s); + } +} + +static void rtl8139_transmit(RTL8139State *s) +{ + int descriptor = s->currTxDesc, txcount = 0; + + /*while*/ + if (rtl8139_transmit_one(s, descriptor)) + { + ++s->currTxDesc; + s->currTxDesc %= 4; + ++txcount; + } + + /* Mark transfer completed */ + if (!txcount) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc); +#endif + } +} + +static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32_t val) +{ + + int descriptor = txRegOffset/4; +#ifdef DEBUG_RTL8139 + printf("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor); +#endif + + /* mask only reserved bits */ + val &= ~0xff00c000; /* these bits are reset on write */ + val = SET_MASKED(val, 0x00c00000, s->TxStatus[descriptor]); + + s->TxStatus[descriptor] = val; + + /* attempt to start transmission */ + rtl8139_transmit(s); +} + +static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset) +{ + uint32_t ret = s->TxStatus[txRegOffset/4]; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret); +#endif + + return ret; +} + +static uint16_t rtl8139_TSAD_read(RTL8139State *s) +{ + uint16_t ret = 0; + + /* Simulate TSAD, it is read only anyway */ + + ret = ((s->TxStatus[3] & TxStatOK )?TSAD_TOK3:0) + |((s->TxStatus[2] & TxStatOK )?TSAD_TOK2:0) + |((s->TxStatus[1] & TxStatOK )?TSAD_TOK1:0) + |((s->TxStatus[0] & TxStatOK )?TSAD_TOK0:0) + + |((s->TxStatus[3] & TxUnderrun)?TSAD_TUN3:0) + |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0) + |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0) + |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0) + + |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0) + |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0) + |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0) + |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0) + + |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0) + |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0) + |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0) + |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ; + + +#ifdef DEBUG_RTL8139 + printf("RTL8139: TSAD read val=0x%04x\n", ret); +#endif + + return ret; +} + +static uint16_t rtl8139_CSCR_read(RTL8139State *s) +{ + uint16_t ret = s->CSCR; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: CSCR read val=0x%04x\n", ret); +#endif + + return ret; +} + +static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val) +{ +#ifdef DEBUG_RTL8139 + printf("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val); +#endif + + s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); +} + +static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) +{ + uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]); + +#ifdef DEBUG_RTL8139 + printf("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret); +#endif + + return ret; +} + +static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val) +{ +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxBufPtr write val=0x%04x\n", val); +#endif + + /* this value is off by 16 */ + s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize); + +#if defined(DEBUG_RTL8139) + printf(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); +#endif +} + +static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) +{ + /* this value is off by 16 */ + uint32_t ret = s->RxBufPtr - 0x10; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxBufPtr read val=0x%04x\n", ret); +#endif + + return ret; +} + +static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val) +{ +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxBuf write val=0x%08x\n", val); +#endif + + s->RxBuf = val; + + /* may need to reset rxring here */ +} + +static uint32_t rtl8139_RxBuf_read(RTL8139State *s) +{ + uint32_t ret = s->RxBuf; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxBuf read val=0x%08x\n", ret); +#endif + + return ret; +} + +static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) +{ +#ifdef DEBUG_RTL8139 + printf("RTL8139: IntrMask write(w) val=0x%04x\n", val); +#endif + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0x1e00, s->IntrMask); + + s->IntrMask = val; + + rtl8139_update_irq(s); +} + +static uint32_t rtl8139_IntrMask_read(RTL8139State *s) +{ + uint32_t ret = s->IntrMask; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: IntrMask read(w) val=0x%04x\n", ret); +#endif + + return ret; +} + +static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) +{ +#ifdef DEBUG_RTL8139 + printf("RTL8139: IntrStatus write(w) val=0x%04x\n", val); +#endif + +#if 0 + + /* writing to ISR has no effect */ + + return; + +#else + uint16_t newStatus = s->IntrStatus & ~val; + + /* mask unwriteable bits */ + newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus); + + /* writing 1 to interrupt status register bit clears it */ + s->IntrStatus = 0; + rtl8139_update_irq(s); + + s->IntrStatus = newStatus; + rtl8139_update_irq(s); +#endif +} + +static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) +{ + uint32_t ret = s->IntrStatus; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: IntrStatus read(w) val=0x%04x\n", ret); +#endif + +#if 0 + + /* reading ISR clears all interrupts */ + s->IntrStatus = 0; + + rtl8139_update_irq(s); + +#endif + + return ret; +} + +static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val) +{ +#ifdef DEBUG_RTL8139 + printf("RTL8139: MultiIntr write(w) val=0x%04x\n", val); +#endif + + /* mask unwriteable bits */ + val = SET_MASKED(val, 0xf000, s->MultiIntr); + + s->MultiIntr = val; +} + +static uint32_t rtl8139_MultiIntr_read(RTL8139State *s) +{ + uint32_t ret = s->MultiIntr; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: MultiIntr read(w) val=0x%04x\n", ret); +#endif + + return ret; +} + +static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) +{ + RTL8139State *s = opaque; + + addr &= 0xff; + + switch (addr) + { + case MAC0 ... MAC0+5: + s->phys[addr - MAC0] = val; + break; + case MAC0+6 ... MAC0+7: + /* reserved */ + break; + case MAR0 ... MAR0+7: + s->mult[addr - MAR0] = val; + break; + case ChipCmd: + rtl8139_ChipCmd_write(s, val); + break; + case Cfg9346: + rtl8139_Cfg9346_write(s, val); + break; + case TxConfig: /* windows driver sometimes writes using byte-lenth call */ + rtl8139_TxConfig_writeb(s, val); + break; + case Config0: + rtl8139_Config0_write(s, val); + break; + case Config1: + rtl8139_Config1_write(s, val); + break; + case Config3: + rtl8139_Config3_write(s, val); + break; + case Config4: + rtl8139_Config4_write(s, val); + break; + case Config5: + rtl8139_Config5_write(s, val); + break; + case MediaStatus: + /* ignore */ +#ifdef DEBUG_RTL8139 + printf("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val); +#endif + break; + + case HltClk: +#ifdef DEBUG_RTL8139 + printf("RTL8139: HltClk write val=0x%08x\n", val); +#endif + if (val == 'R') + { + s->clock_enabled = 1; + } + else if (val == 'H') + { + s->clock_enabled = 0; + } + break; + + case TxThresh: +#ifdef DEBUG_RTL8139 + printf("RTL8139C+ TxThresh write(b) val=0x%02x\n", val); +#endif + s->TxThresh = val; + break; + + case TxPoll: +#ifdef DEBUG_RTL8139 + printf("RTL8139C+ TxPoll write(b) val=0x%02x\n", val); +#endif + if (val & (1 << 7)) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139C+ TxPoll high priority transmission (not implemented)\n"); +#endif + //rtl8139_cplus_transmit(s); + } + if (val & (1 << 6)) + { +#ifdef DEBUG_RTL8139 + printf("RTL8139C+ TxPoll normal priority transmission\n"); +#endif + rtl8139_cplus_transmit(s); + } + + break; + + default: +#ifdef DEBUG_RTL8139 + printf("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val); +#endif + break; + } +} + +static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) +{ + RTL8139State *s = opaque; + + addr &= 0xfe; + + switch (addr) + { + case IntrMask: + rtl8139_IntrMask_write(s, val); + break; + + case IntrStatus: + rtl8139_IntrStatus_write(s, val); + break; + + case MultiIntr: + rtl8139_MultiIntr_write(s, val); + break; + + case RxBufPtr: + rtl8139_RxBufPtr_write(s, val); + break; + + case BasicModeCtrl: + rtl8139_BasicModeCtrl_write(s, val); + break; + case BasicModeStatus: + rtl8139_BasicModeStatus_write(s, val); + break; + case NWayAdvert: +#ifdef DEBUG_RTL8139 + printf("RTL8139: NWayAdvert write(w) val=0x%04x\n", val); +#endif + s->NWayAdvert = val; + break; + case NWayLPAR: +#ifdef DEBUG_RTL8139 + printf("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val); +#endif + break; + case NWayExpansion: +#ifdef DEBUG_RTL8139 + printf("RTL8139: NWayExpansion write(w) val=0x%04x\n", val); +#endif + s->NWayExpansion = val; + break; + + case CpCmd: + rtl8139_CpCmd_write(s, val); + break; + + default: +#ifdef DEBUG_RTL8139 + printf("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val); +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff); + rtl8139_io_writeb(opaque, addr + 1, val & 0xff); +#else + rtl8139_io_writeb(opaque, addr, val & 0xff); + rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); +#endif + break; + } +} + +static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) +{ + RTL8139State *s = opaque; + + addr &= 0xfc; + + switch (addr) + { + case RxMissed: +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxMissed clearing on write\n"); +#endif + s->RxMissed = 0; + break; + + case TxConfig: + rtl8139_TxConfig_write(s, val); + break; + + case RxConfig: + rtl8139_RxConfig_write(s, val); + break; + + case TxStatus0 ... TxStatus0+4*4-1: + rtl8139_TxStatus_write(s, addr-TxStatus0, val); + break; + + case TxAddr0 ... TxAddr0+4*4-1: + rtl8139_TxAddr_write(s, addr-TxAddr0, val); + break; + + case RxBuf: + rtl8139_RxBuf_write(s, val); + break; + + case RxRingAddrLO: +#ifdef DEBUG_RTL8139 + printf("RTL8139: C+ RxRing low bits write val=0x%08x\n", val); +#endif + s->RxRingAddrLO = val; + break; + + case RxRingAddrHI: +#ifdef DEBUG_RTL8139 + printf("RTL8139: C+ RxRing high bits write val=0x%08x\n", val); +#endif + s->RxRingAddrHI = val; + break; + + default: +#ifdef DEBUG_RTL8139 + printf("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val); +#endif +#ifdef TARGET_WORDS_BIGENDIAN + rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff); + rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff); + rtl8139_io_writeb(opaque, addr + 2, (val >> 8) & 0xff); + rtl8139_io_writeb(opaque, addr + 3, val & 0xff); +#else + rtl8139_io_writeb(opaque, addr, val & 0xff); + rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); + rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff); + rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff); +#endif + break; + } +} + +static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) +{ + RTL8139State *s = opaque; + int ret; + + addr &= 0xff; + + switch (addr) + { + case MAC0 ... MAC0+5: + ret = s->phys[addr - MAC0]; + break; + case MAC0+6 ... MAC0+7: + ret = 0; + break; + case MAR0 ... MAR0+7: + ret = s->mult[addr - MAR0]; + break; + case ChipCmd: + ret = rtl8139_ChipCmd_read(s); + break; + case Cfg9346: + ret = rtl8139_Cfg9346_read(s); + break; + case Config0: + ret = rtl8139_Config0_read(s); + break; + case Config1: + ret = rtl8139_Config1_read(s); + break; + case Config3: + ret = rtl8139_Config3_read(s); + break; + case Config4: + ret = rtl8139_Config4_read(s); + break; + case Config5: + ret = rtl8139_Config5_read(s); + break; + + case MediaStatus: + ret = 0xd0; +#ifdef DEBUG_RTL8139 + printf("RTL8139: MediaStatus read 0x%x\n", ret); +#endif + break; + + case HltClk: + ret = s->clock_enabled; +#ifdef DEBUG_RTL8139 + printf("RTL8139: HltClk read 0x%x\n", ret); +#endif + break; + + case PCIRevisionID: + ret = 0x10; +#ifdef DEBUG_RTL8139 + printf("RTL8139: PCI Revision ID read 0x%x\n", ret); +#endif + break; + + case TxThresh: + ret = s->TxThresh; +#ifdef DEBUG_RTL8139 + printf("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret); +#endif + break; + + case 0x43: /* Part of TxConfig register. Windows driver tries to read it */ + ret = s->TxConfig >> 24; +#ifdef DEBUG_RTL8139 + printf("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret); +#endif + break; + + default: +#ifdef DEBUG_RTL8139 + printf("RTL8139: not implemented read(b) addr=0x%x\n", addr); +#endif + ret = 0; + break; + } + + return ret; +} + +static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) +{ + RTL8139State *s = opaque; + uint32_t ret; + + addr &= 0xfe; /* mask lower bit */ + + switch (addr) + { + case IntrMask: + ret = rtl8139_IntrMask_read(s); + break; + + case IntrStatus: + ret = rtl8139_IntrStatus_read(s); + break; + + case MultiIntr: + ret = rtl8139_MultiIntr_read(s); + break; + + case RxBufPtr: + ret = rtl8139_RxBufPtr_read(s); + break; + + case BasicModeCtrl: + ret = rtl8139_BasicModeCtrl_read(s); + break; + case BasicModeStatus: + ret = rtl8139_BasicModeStatus_read(s); + break; + case NWayAdvert: + ret = s->NWayAdvert; +#ifdef DEBUG_RTL8139 + printf("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret); +#endif + break; + case NWayLPAR: + ret = s->NWayLPAR; +#ifdef DEBUG_RTL8139 + printf("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret); +#endif + break; + case NWayExpansion: + ret = s->NWayExpansion; +#ifdef DEBUG_RTL8139 + printf("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret); +#endif + break; + + case CpCmd: + ret = rtl8139_CpCmd_read(s); + break; + + case TxSummary: + ret = rtl8139_TSAD_read(s); + break; + + case CSCR: + ret = rtl8139_CSCR_read(s); + break; + + default: +#ifdef DEBUG_RTL8139 + printf("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr); +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + ret = rtl8139_io_readb(opaque, addr) << 8; + ret |= rtl8139_io_readb(opaque, addr + 1); +#else + ret = rtl8139_io_readb(opaque, addr); + ret |= rtl8139_io_readb(opaque, addr + 1) << 8; +#endif + +#ifdef DEBUG_RTL8139 + printf("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret); +#endif + break; + } + + return ret; +} + +static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) +{ + RTL8139State *s = opaque; + uint32_t ret; + + addr &= 0xfc; /* also mask low 2 bits */ + + switch (addr) + { + case RxMissed: + ret = s->RxMissed; + +#ifdef DEBUG_RTL8139 + printf("RTL8139: RxMissed read val=0x%08x\n", ret); +#endif + break; + + case TxConfig: + ret = rtl8139_TxConfig_read(s); + break; + + case RxConfig: + ret = rtl8139_RxConfig_read(s); + break; + + case TxStatus0 ... TxStatus0+4*4-1: + ret = rtl8139_TxStatus_read(s, addr-TxStatus0); + break; + + case TxAddr0 ... TxAddr0+4*4-1: + ret = rtl8139_TxAddr_read(s, addr-TxAddr0); + break; + + case RxBuf: + ret = rtl8139_RxBuf_read(s); + break; + + case RxRingAddrLO: + ret = s->RxRingAddrLO; +#ifdef DEBUG_RTL8139 + printf("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret); +#endif + break; + + case RxRingAddrHI: + ret = s->RxRingAddrHI; +#ifdef DEBUG_RTL8139 + printf("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret); +#endif + break; + + default: +#ifdef DEBUG_RTL8139 + printf("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr); +#endif + +#ifdef TARGET_WORDS_BIGENDIAN + ret = rtl8139_io_readb(opaque, addr) << 24; + ret |= rtl8139_io_readb(opaque, addr + 1) << 16; + ret |= rtl8139_io_readb(opaque, addr + 2) << 8; + ret |= rtl8139_io_readb(opaque, addr + 3); +#else + ret = rtl8139_io_readb(opaque, addr); + ret |= rtl8139_io_readb(opaque, addr + 1) << 8; + ret |= rtl8139_io_readb(opaque, addr + 2) << 16; + ret |= rtl8139_io_readb(opaque, addr + 3) << 24; +#endif + +#ifdef DEBUG_RTL8139 + printf("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret); +#endif + break; + } + + return ret; +} + +/* */ + +static void rtl8139_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + rtl8139_io_writeb(opaque, addr & 0xFF, val); +} + +static void rtl8139_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +{ + rtl8139_io_writew(opaque, addr & 0xFF, val); +} + +static void rtl8139_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +{ + rtl8139_io_writel(opaque, addr & 0xFF, val); +} + +static uint32_t rtl8139_ioport_readb(void *opaque, uint32_t addr) +{ + return rtl8139_io_readb(opaque, addr & 0xFF); +} + +static uint32_t rtl8139_ioport_readw(void *opaque, uint32_t addr) +{ + return rtl8139_io_readw(opaque, addr & 0xFF); +} + +static uint32_t rtl8139_ioport_readl(void *opaque, uint32_t addr) +{ + return rtl8139_io_readl(opaque, addr & 0xFF); +} + +/* */ + +static void rtl8139_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + rtl8139_io_writeb(opaque, addr & 0xFF, val); +} + +static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + rtl8139_io_writew(opaque, addr & 0xFF, val); +} + +static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + rtl8139_io_writel(opaque, addr & 0xFF, val); +} + +static uint32_t rtl8139_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + return rtl8139_io_readb(opaque, addr & 0xFF); +} + +static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + return rtl8139_io_readw(opaque, addr & 0xFF); +} + +static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + return rtl8139_io_readl(opaque, addr & 0xFF); +} + +/* */ + +static void rtl8139_save(QEMUFile* f,void* opaque) +{ + RTL8139State* s=(RTL8139State*)opaque; + int i; + + qemu_put_buffer(f, s->phys, 6); + qemu_put_buffer(f, s->mult, 8); + + for (i=0; i<4; ++i) + { + qemu_put_be32s(f, &s->TxStatus[i]); /* TxStatus0 */ + } + for (i=0; i<4; ++i) + { + qemu_put_be32s(f, &s->TxAddr[i]); /* TxAddr0 */ + } + + qemu_put_be32s(f, &s->RxBuf); /* Receive buffer */ + qemu_put_be32s(f, &s->RxBufferSize);/* internal variable, receive ring buffer size in C mode */ + qemu_put_be32s(f, &s->RxBufPtr); + qemu_put_be32s(f, &s->RxBufAddr); + + qemu_put_be16s(f, &s->IntrStatus); + qemu_put_be16s(f, &s->IntrMask); + + qemu_put_be32s(f, &s->TxConfig); + qemu_put_be32s(f, &s->RxConfig); + qemu_put_be32s(f, &s->RxMissed); + qemu_put_be16s(f, &s->CSCR); + + qemu_put_8s(f, &s->Cfg9346); + qemu_put_8s(f, &s->Config0); + qemu_put_8s(f, &s->Config1); + qemu_put_8s(f, &s->Config3); + qemu_put_8s(f, &s->Config4); + qemu_put_8s(f, &s->Config5); + + qemu_put_8s(f, &s->clock_enabled); + qemu_put_8s(f, &s->bChipCmdState); + + qemu_put_be16s(f, &s->MultiIntr); + + qemu_put_be16s(f, &s->BasicModeCtrl); + qemu_put_be16s(f, &s->BasicModeStatus); + qemu_put_be16s(f, &s->NWayAdvert); + qemu_put_be16s(f, &s->NWayLPAR); + qemu_put_be16s(f, &s->NWayExpansion); + + qemu_put_be16s(f, &s->CpCmd); + qemu_put_8s(f, &s->TxThresh); + + qemu_put_be32s(f, &s->irq); + qemu_put_buffer(f, s->macaddr, 6); + qemu_put_be32s(f, &s->rtl8139_mmio_io_addr); + + qemu_put_be32s(f, &s->currTxDesc); + qemu_put_be32s(f, &s->currCPlusRxDesc); + qemu_put_be32s(f, &s->currCPlusTxDesc); + qemu_put_be32s(f, &s->RxRingAddrLO); + qemu_put_be32s(f, &s->RxRingAddrHI); + + for (i=0; ieeprom.contents[i]); + } + qemu_put_be32s(f, &s->eeprom.mode); + qemu_put_be32s(f, &s->eeprom.tick); + qemu_put_8s(f, &s->eeprom.address); + qemu_put_be16s(f, &s->eeprom.input); + qemu_put_be16s(f, &s->eeprom.output); + + qemu_put_8s(f, &s->eeprom.eecs); + qemu_put_8s(f, &s->eeprom.eesk); + qemu_put_8s(f, &s->eeprom.eedi); + qemu_put_8s(f, &s->eeprom.eedo); +} + +static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) +{ + RTL8139State* s=(RTL8139State*)opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + qemu_get_buffer(f, s->phys, 6); + qemu_get_buffer(f, s->mult, 8); + + for (i=0; i<4; ++i) + { + qemu_get_be32s(f, &s->TxStatus[i]); /* TxStatus0 */ + } + for (i=0; i<4; ++i) + { + qemu_get_be32s(f, &s->TxAddr[i]); /* TxAddr0 */ + } + + qemu_get_be32s(f, &s->RxBuf); /* Receive buffer */ + qemu_get_be32s(f, &s->RxBufferSize);/* internal variable, receive ring buffer size in C mode */ + qemu_get_be32s(f, &s->RxBufPtr); + qemu_get_be32s(f, &s->RxBufAddr); + + qemu_get_be16s(f, &s->IntrStatus); + qemu_get_be16s(f, &s->IntrMask); + + qemu_get_be32s(f, &s->TxConfig); + qemu_get_be32s(f, &s->RxConfig); + qemu_get_be32s(f, &s->RxMissed); + qemu_get_be16s(f, &s->CSCR); + + qemu_get_8s(f, &s->Cfg9346); + qemu_get_8s(f, &s->Config0); + qemu_get_8s(f, &s->Config1); + qemu_get_8s(f, &s->Config3); + qemu_get_8s(f, &s->Config4); + qemu_get_8s(f, &s->Config5); + + qemu_get_8s(f, &s->clock_enabled); + qemu_get_8s(f, &s->bChipCmdState); + + qemu_get_be16s(f, &s->MultiIntr); + + qemu_get_be16s(f, &s->BasicModeCtrl); + qemu_get_be16s(f, &s->BasicModeStatus); + qemu_get_be16s(f, &s->NWayAdvert); + qemu_get_be16s(f, &s->NWayLPAR); + qemu_get_be16s(f, &s->NWayExpansion); + + qemu_get_be16s(f, &s->CpCmd); + qemu_get_8s(f, &s->TxThresh); + + qemu_get_be32s(f, &s->irq); + qemu_get_buffer(f, s->macaddr, 6); + qemu_get_be32s(f, &s->rtl8139_mmio_io_addr); + + qemu_get_be32s(f, &s->currTxDesc); + qemu_get_be32s(f, &s->currCPlusRxDesc); + qemu_get_be32s(f, &s->currCPlusTxDesc); + qemu_get_be32s(f, &s->RxRingAddrLO); + qemu_get_be32s(f, &s->RxRingAddrHI); + + for (i=0; ieeprom.contents[i]); + } + qemu_get_be32s(f, &s->eeprom.mode); + qemu_get_be32s(f, &s->eeprom.tick); + qemu_get_8s(f, &s->eeprom.address); + qemu_get_be16s(f, &s->eeprom.input); + qemu_get_be16s(f, &s->eeprom.output); + + qemu_get_8s(f, &s->eeprom.eecs); + qemu_get_8s(f, &s->eeprom.eesk); + qemu_get_8s(f, &s->eeprom.eedi); + qemu_get_8s(f, &s->eeprom.eedo); + + return 0; +} + +/***********************************************************/ +/* PCI RTL8139 definitions */ + +typedef struct PCIRTL8139State { + PCIDevice dev; + RTL8139State rtl8139; +} PCIRTL8139State; + +static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIRTL8139State *d = (PCIRTL8139State *)pci_dev; + RTL8139State *s = &d->rtl8139; + + cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr); +} + +static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIRTL8139State *d = (PCIRTL8139State *)pci_dev; + RTL8139State *s = &d->rtl8139; + + register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s); + register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb, s); + + register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s); + register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw, s); + + register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s); + register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl, s); +} + +static CPUReadMemoryFunc *rtl8139_mmio_read[3] = { + rtl8139_mmio_readb, + rtl8139_mmio_readw, + rtl8139_mmio_readl, +}; + +static CPUWriteMemoryFunc *rtl8139_mmio_write[3] = { + rtl8139_mmio_writeb, + rtl8139_mmio_writew, + rtl8139_mmio_writel, +}; + +void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) +{ + PCIRTL8139State *d; + RTL8139State *s; + uint8_t *pci_conf; + + d = (PCIRTL8139State *)pci_register_device(bus, + "RTL8139", sizeof(PCIRTL8139State), + -1, + NULL, NULL); + pci_conf = d->dev.config; + pci_conf[0x00] = 0xec; /* Realtek 8139 */ + pci_conf[0x01] = 0x10; + pci_conf[0x02] = 0x39; + pci_conf[0x03] = 0x81; + pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */ + pci_conf[0x08] = 0x20; /* 0x10 */ /* PCI revision ID; >=0x20 is for 8139C+ */ + pci_conf[0x0a] = 0x00; /* ethernet network controller */ + pci_conf[0x0b] = 0x02; + pci_conf[0x0e] = 0x00; /* header_type */ + pci_conf[0x3d] = 1; /* interrupt pin 0 */ + pci_conf[0x34] = 0xdc; + + s = &d->rtl8139; + + /* I/O handler for memory-mapped I/O */ + s->rtl8139_mmio_io_addr = + cpu_register_io_memory(0, rtl8139_mmio_read, rtl8139_mmio_write, s); + + pci_register_io_region(&d->dev, 0, 0x100, + PCI_ADDRESS_SPACE_IO, rtl8139_ioport_map); + + pci_register_io_region(&d->dev, 1, 0x100, + PCI_ADDRESS_SPACE_MEM, rtl8139_mmio_map); + + s->irq = 16; /* PCI interrupt */ + s->pci_dev = (PCIDevice *)d; + memcpy(s->macaddr, nd->macaddr, 6); + rtl8139_reset(s); + s->vc = qemu_new_vlan_client(nd->vlan, rtl8139_receive, + rtl8139_can_receive, s); + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "rtl8139 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->macaddr[0], + s->macaddr[1], + s->macaddr[2], + s->macaddr[3], + s->macaddr[4], + s->macaddr[5]); + + /* XXX: instance number ? */ + register_savevm("rtl8139", 0, 1, rtl8139_save, rtl8139_load, s); + register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load, + &d->dev); +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 5733fce5a..b41ee2582 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -257,7 +257,15 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, } tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); - lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); + if (nd_table[0].vlan) { + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "lance") == 0) { + lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } + } nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8); for (i = 0; i < MAX_CPUS; i++) { slavio_timer_init(PHYS_JJ_CLOCK + i * TARGET_PAGE_SIZE, PHYS_JJ_CLOCK_IRQ, 0, i); diff --git a/hw/sun4u.c b/hw/sun4u.c index 571e2b373..0cf538179 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -347,7 +347,9 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(pci_bus, &nd_table[i]); + if (!nd_table[i].model) + nd_table[i].model = "ne2k_pci"; + pci_nic_init(pci_bus, &nd_table[i]); } pci_cmd646_ide_init(pci_bus, bs_table, 1); diff --git a/qemu-doc.texi b/qemu-doc.texi index fdf8ba2d4..eafdb806f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -252,11 +252,15 @@ Network options: @table @option -@item -net nic[,vlan=n][,macaddr=addr] +@item -net nic[,vlan=n][,macaddr=addr][,model=type] Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n} = 0 is the default). The NIC is currently an NE2000 on the PC target. Optionally, the MAC address can be changed. If no @option{-net} option is specified, a single NIC is created. +Qemu can emulate several different models of network card. Valid values for +@var{type} are @code{ne2k_pci}, @code{ne2k_isa}, @code{rtl8139}, +@code{smc91c111} and @code{lance}. Not all devices are supported on all +targets. @item -net user[,vlan=n] Use the user mode network stack which requires no administrator diff --git a/vl.c b/vl.c index 6d319bc33..eaa4560c7 100644 --- a/vl.c +++ b/vl.c @@ -2718,6 +2718,9 @@ int net_client_init(const char *str) return -1; } } + if (get_param_value(buf, sizeof(buf), "model", p)) { + nd->model = strdup(buf); + } nd->vlan = vlan; nb_nics++; ret = 0; @@ -4110,7 +4113,7 @@ void help(void) #endif "\n" "Network options:\n" - "-net nic[,vlan=n][,macaddr=addr]\n" + "-net nic[,vlan=n][,macaddr=addr][,model=type]\n" " create a new Network Interface Card and connect it to VLAN 'n'\n" #ifdef CONFIG_SLIRP "-net user[,vlan=n]\n" diff --git a/vl.h b/vl.h index 5986d5067..00d4c9447 100644 --- a/vl.h +++ b/vl.h @@ -315,6 +315,7 @@ void tap_win32_poll(void); typedef struct NICInfo { uint8_t macaddr[6]; + const char *model; VLANState *vlan; } NICInfo; @@ -616,6 +617,8 @@ PCIBus *pci_grackle_init(uint32_t base); PCIBus *pci_pmac_init(void); PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base); +void pci_nic_init(PCIBus *bus, NICInfo *nd); + /* openpic.c */ typedef struct openpic_t openpic_t; void openpic_set_irq(void *opaque, int n_IRQ, int level); @@ -740,6 +743,10 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); void isa_ne2000_init(int base, int irq, NICInfo *nd); void pci_ne2000_init(PCIBus *bus, NICInfo *nd); +/* rtl8139.c */ + +void pci_rtl8139_init(PCIBus *bus, NICInfo *nd); + /* pckbd.c */ void kbd_init(void); -- cgit v1.2.3 From bdd5003ae58baf4fb3fde9862630b97b2c1f058c Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 6 Feb 2006 04:11:15 +0000 Subject: Arm display emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1746 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +- hw/integratorcp.c | 5 + hw/pl110.c | 393 ++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pl110_template.h | 252 +++++++++++++++++++++++++++++++++ vl.h | 5 + 5 files changed, 657 insertions(+), 1 deletion(-) create mode 100644 hw/pl110.c create mode 100644 hw/pl110_template.h diff --git a/Makefile.target b/Makefile.target index 2215f185f..a5c728baa 100644 --- a/Makefile.target +++ b/Makefile.target @@ -339,7 +339,7 @@ VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o endif endif ifeq ($(TARGET_BASE_ARCH), arm) -VL_OBJS+= integratorcp.o ps2.o smc91c111.o +VL_OBJS+= integratorcp.o ps2.o smc91c111.o pl110.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o @@ -439,6 +439,7 @@ endif ifeq ($(TARGET_ARCH), arm) op.o: op.c op_template.h +pl110.o: pl110_template.h endif ifeq ($(TARGET_BASE_ARCH), sparc) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index d2b437ce1..0e3d1e3f0 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -27,8 +27,11 @@ void irq_info(void) { } +static void *lcd; + void vga_update_display(void) { + pl110_update_display(lcd); } void vga_screen_dump(const char *filename) @@ -37,6 +40,7 @@ void vga_screen_dump(const char *filename) void vga_invalidate_display(void) { + pl110_invalidate_display(lcd); } void DMA_run (void) @@ -1204,6 +1208,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, exit (1); } } + lcd = pl110_init(ds, 0xc0000000, pic, 22); /* Load the kernel. */ if (!kernel_filename) { diff --git a/hw/pl110.c b/hw/pl110.c new file mode 100644 index 000000000..8a4d5807a --- /dev/null +++ b/hw/pl110.c @@ -0,0 +1,393 @@ +/* + * Arm PrimeCell PL110 Color LCD Controller + * + * Copyright (c) 2005 CodeSourcery, LLC. + * Written by Paul Brook + * + * This code is licenced under the GNU LGPL + */ + +#include "vl.h" + +#define PL110_CR_EN 0x001 +#define PL110_CR_BEBO 0x200 +#define PL110_CR_BEPO 0x400 +#define PL110_CR_PWR 0x800 + +enum pl110_bppmode +{ + BPP_1, + BPP_2, + BPP_4, + BPP_8, + BPP_16, + BPP_32 +}; + +typedef struct { + uint32_t base; + DisplayState *ds; + void *pic; + uint32_t timing[4]; + uint32_t cr; + uint32_t upbase; + uint32_t lpbase; + uint32_t int_status; + uint32_t int_mask; + int cols; + int rows; + enum pl110_bppmode bpp; + int invalidate; + uint32_t pallette[256]; + uint32_t raw_pallette[128]; + int irq; +} pl110_state; + +static const unsigned char pl110_id[] = +{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; + +static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); +} + +static inline uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); +} + +static inline uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); +} + +static inline uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b) +{ + return (r << 16) | (g << 8) | b; +} + +static inline uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) +{ + return (r << 16) | (g << 8) | b; +} + +typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int); + +#define BITS 8 +#include "pl110_template.h" +#define BITS 15 +#include "pl110_template.h" +#define BITS 16 +#include "pl110_template.h" +#define BITS 24 +#include "pl110_template.h" +#define BITS 32 +#include "pl110_template.h" + +static int pl110_enabled(pl110_state *s) +{ + return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR); +} + +void pl110_update_display(void *opaque) +{ + pl110_state *s = (pl110_state *)opaque; + drawfn* fntable; + drawfn fn; + uint32_t *pallette; + uint32_t addr; + uint32_t base; + int dest_width; + int src_width; + uint8_t *dest; + uint8_t *src; + int first, last; + int dirty, new_dirty; + int i; + + if (!pl110_enabled(s)) + return; + + switch (s->ds->depth) { + case 8: + fntable = pl110_draw_fn_8; + dest_width = 1; + break; + case 15: + fntable = pl110_draw_fn_15; + dest_width = 2; + break; + case 16: + fntable = pl110_draw_fn_16; + dest_width = 2; + break; + case 24: + fntable = pl110_draw_fn_24; + dest_width = 3; + break; + case 32: + fntable = pl110_draw_fn_32; + dest_width = 4; + break; + default: + fprintf(stderr, "qemu: Bad color depth\n"); + exit(1); + } + if (s->cr & PL110_CR_BEBO) + fn = fntable[s->bpp + 6]; + else if (s->cr & PL110_CR_BEPO) + fn = fntable[s->bpp + 12]; + else + fn = fntable[s->bpp]; + + src_width = s->cols; + switch (s->bpp) { + case BPP_1: + src_width >>= 3; + break; + case BPP_2: + src_width >>= 2; + break; + case BPP_4: + src_width >>= 1; + break; + case BPP_8: + break; + case BPP_16: + src_width <<= 1; + break; + case BPP_32: + src_width <<= 2; + break; + } + dest_width *= s->cols; + pallette = s->pallette; + base = s->upbase; + /* HACK: Arm aliases physical memory at 0x80000000. */ + if (base > 0x80000000) + base -= 0x80000000; + src = phys_ram_base + base; + dest = s->ds->data; + first = -1; + addr = base; + + dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); + for (i = 0; i < s->rows; i++) { + new_dirty = 0; + if ((addr & TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) { + uint32_t tmp; + for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) { + new_dirty |= cpu_physical_memory_get_dirty(addr + tmp, + VGA_DIRTY_FLAG); + } + } + + if (dirty || new_dirty || s->invalidate) { + fn(pallette, dest, src, s->cols); + if (first == -1) + first = i; + last = i; + } + dirty = new_dirty; + addr += src_width; + dest += dest_width; + src += src_width; + } + if (first < 0) + return; + + s->invalidate = 0; + cpu_physical_memory_reset_dirty(base + first * src_width, + base + (last + 1) * src_width, + VGA_DIRTY_FLAG); + dpy_update(s->ds, 0, first, s->cols, last - first + 1); +} + +void pl110_invalidate_display(void * opaque) +{ + pl110_state *s = (pl110_state *)opaque; + s->invalidate = 1; +} + +static void pl110_update_pallette(pl110_state *s, int n) +{ + int i; + uint32_t raw; + unsigned int r, g, b; + + raw = s->raw_pallette[n]; + n <<= 1; + for (i = 0; i < 2; i++) { + r = (raw & 0x1f) << 3; + raw >>= 5; + g = (raw & 0x1f) << 3; + raw >>= 5; + b = (raw & 0x1f) << 3; + /* The I bit is ignored. */ + raw >>= 6; + switch (s->ds->depth) { + case 8: + s->pallette[n] = rgb_to_pixel8(r, g, b); + break; + case 15: + s->pallette[n] = rgb_to_pixel15(r, g, b); + break; + case 16: + s->pallette[n] = rgb_to_pixel16(r, g, b); + break; + case 24: + case 32: + s->pallette[n] = rgb_to_pixel32(r, g, b); + break; + } + n++; + } +} + +static void pl110_resize(pl110_state *s, int width, int height) +{ + if (width != s->cols || height != s->rows) { + if (pl110_enabled(s)) { + dpy_resize(s->ds, s->cols, s->rows); + } + } + s->cols = width; + s->rows = height; +} + +/* Update interrupts. */ +static void pl110_update(pl110_state *s) +{ + /* TODO: Implement interrupts. */ +} + +static uint32_t pl110_read(void *opaque, target_phys_addr_t offset) +{ + pl110_state *s = (pl110_state *)opaque; + + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) { + return pl110_id[(offset - 0xfe0) >> 2]; + } + if (offset >= 0x200 && offset < 0x400) { + return s->raw_pallette[(offset - 0x200) >> 2]; + } + switch (offset >> 2) { + case 0: /* LCDTiming0 */ + return s->timing[0]; + case 1: /* LCDTiming1 */ + return s->timing[1]; + case 2: /* LCDTiming2 */ + return s->timing[2]; + case 3: /* LCDTiming3 */ + return s->timing[3]; + case 4: /* LCDUPBASE */ + return s->upbase; + case 5: /* LCDLPBASE */ + return s->lpbase; + case 6: /* LCDIMSC */ + return s->int_mask; + case 7: /* LCDControl */ + return s->cr; + case 8: /* LCDRIS */ + return s->int_status; + case 9: /* LCDMIS */ + return s->int_status & s->int_mask; + case 11: /* LCDUPCURR */ + /* TODO: Implement vertical refresh. */ + return s->upbase; + case 12: /* LCDLPCURR */ + return s->lpbase; + default: + cpu_abort (cpu_single_env, "pl110_read: Bad offset %x\n", offset); + return 0; + } +} + +static void pl110_write(void *opaque, target_phys_addr_t offset, + uint32_t val) +{ + pl110_state *s = (pl110_state *)opaque; + int n; + + /* For simplicity invalidate the display whenever a control register + is writen to. */ + s->invalidate = 1; + offset -= s->base; + if (offset >= 0x200 && offset < 0x400) { + /* Pallette. */ + n = (offset - 0x200) >> 2; + s->raw_pallette[(offset - 0x200) >> 2] = val; + pl110_update_pallette(s, n); + } + switch (offset >> 2) { + case 0: /* LCDTiming0 */ + s->timing[0] = val; + n = ((val & 0xfc) + 4) * 4; + pl110_resize(s, n, s->rows); + break; + case 1: /* LCDTiming1 */ + s->timing[1] = val; + n = (val & 0x3ff) + 1; + pl110_resize(s, s->cols, n); + break; + case 2: /* LCDTiming2 */ + s->timing[2] = val; + break; + case 3: /* LCDTiming3 */ + s->timing[3] = val; + break; + case 4: /* LCDUPBASE */ + s->upbase = val; + break; + case 5: /* LCDLPBASE */ + s->lpbase = val; + break; + case 6: /* LCDIMSC */ + s->int_mask = val; + pl110_update(s); + break; + case 7: /* LCDControl */ + s->cr = val; + s->bpp = (val >> 1) & 7; + if (pl110_enabled(s)) { + dpy_resize(s->ds, s->cols, s->rows); + } + break; + case 10: /* LCDICR */ + s->int_status &= ~val; + pl110_update(s); + break; + default: + cpu_abort (cpu_single_env, "pl110_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *pl110_readfn[] = { + pl110_read, + pl110_read, + pl110_read +}; + +static CPUWriteMemoryFunc *pl110_writefn[] = { + pl110_write, + pl110_write, + pl110_write +}; + +void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq) +{ + pl110_state *s; + int iomemtype; + + s = (pl110_state *)qemu_mallocz(sizeof(pl110_state)); + iomemtype = cpu_register_io_memory(0, pl110_readfn, + pl110_writefn, s); + cpu_register_physical_memory(base, 0x007fffff, iomemtype); + s->base = base; + s->ds = ds; + s->pic = pic; + s->irq = irq; + /* ??? Save/restore. */ + return s; +} diff --git a/hw/pl110_template.h b/hw/pl110_template.h new file mode 100644 index 000000000..1ab77777c --- /dev/null +++ b/hw/pl110_template.h @@ -0,0 +1,252 @@ +/* + * Arm PrimeCell PL110 Color LCD Controller + * + * Copyright (c) 2005 CodeSourcery, LLC. + * Written by Paul Brook + * + * This code is licenced under the GNU LGPL + * + * Framebuffer format conversion routines. + */ + +#ifndef ORDER + +#if BITS == 8 +#define COPY_PIXEL(to, from) *(to++) = from +#elif BITS == 15 || BITS == 16 +#define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2; +#elif BITS == 24 +#define COPY_PIXEL(to, from) \ + *(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16 +#elif BITS == 32 +#define COPY_PIXEL(to, from) *(uint32_t *)to = from; to += 4; +#else +#error unknown bit depth +#endif + +#define ORDER 0 +#include "pl110_template.h" +#define ORDER 1 +#include "pl110_template.h" +#define ORDER 2 +#include "pl110_template.h" + +static drawfn glue(pl110_draw_fn_,BITS)[18] = +{ + glue(pl110_draw_line1_lblp,BITS), + glue(pl110_draw_line2_lblp,BITS), + glue(pl110_draw_line4_lblp,BITS), + glue(pl110_draw_line8_lblp,BITS), + glue(pl110_draw_line16_lblp,BITS), + glue(pl110_draw_line32_lblp,BITS), + + glue(pl110_draw_line1_bbbp,BITS), + glue(pl110_draw_line2_bbbp,BITS), + glue(pl110_draw_line4_bbbp,BITS), + glue(pl110_draw_line8_bbbp,BITS), + glue(pl110_draw_line16_bbbp,BITS), + glue(pl110_draw_line32_bbbp,BITS), + + glue(pl110_draw_line1_lbbp,BITS), + glue(pl110_draw_line2_lbbp,BITS), + glue(pl110_draw_line4_lbbp,BITS), + glue(pl110_draw_line8_lbbp,BITS), + glue(pl110_draw_line16_lbbp,BITS), + glue(pl110_draw_line32_lbbp,BITS) +}; + +#undef BITS +#undef COPY_PIXEL + +#else + +#if ORDER == 0 +#define NAME glue(lblp, BITS) +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 1 +#endif +#elif ORDER == 1 +#define NAME glue(bbbp, BITS) +#ifndef WORDS_BIGENDIAN +#define SWAP_WORDS 1 +#endif +#else +#define SWAP_PIXELS 1 +#define NAME glue(lbbp, BITS) +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 1 +#endif +#endif + +#define FN_2(x, y) FN(x, y) FN(x+1, y) +#define FN_4(x, y) FN_2(x, y) FN_2(x+1, y) +#define FN_8(y) FN_4(0, y) FN_4(4, y) + +static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +{ + uint32_t data; + while (width > 0) { + data = *(uint32_t *)src; +#ifdef SWAP_PIXELS +#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]); +#else +#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]); +#endif +#ifdef SWAP_BYTES + FN_8(24) + FN_8(16) + FN_8(8) + FN_8(0) +#else + FN_8(0) + FN_8(8) + FN_8(16) + FN_8(24) +#endif +#undef FN + width -= 32; + src += 4; + } +} + +static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +{ + uint32_t data; + while (width > 0) { + data = *(uint32_t *)src; +#ifdef SWAP_PIXELS +#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]); +#else +#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]); +#endif +#ifdef SWAP_BYTES + FN_4(0, 24) + FN_4(0, 16) + FN_4(0, 8) + FN_4(0, 0) +#else + FN_4(0, 0) + FN_4(0, 8) + FN_4(0, 16) + FN_4(0, 24) +#endif +#undef FN + width -= 16; + src += 4; + } +} + +static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +{ + uint32_t data; + while (width > 0) { + data = *(uint32_t *)src; +#ifdef SWAP_PIXELS +#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]); +#else +#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]); +#endif +#ifdef SWAP_BYTES + FN_2(0, 24) + FN_2(0, 16) + FN_2(0, 8) + FN_2(0, 0) +#else + FN_2(0, 0) + FN_2(0, 8) + FN_2(0, 16) + FN_2(0, 24) +#endif +#undef FN + width -= 8; + src += 4; + } +} + +static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +{ + uint32_t data; + while (width > 0) { + data = *(uint32_t *)src; +#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]); +#ifdef SWAP_BYTES + FN(24) + FN(16) + FN(8) + FN(0) +#else + FN(0) + FN(8) + FN(16) + FN(24) +#endif +#undef FN + width -= 4; + src += 4; + } +} + +static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *)src; +#ifdef SWAP_BYTES + data = bswap32(data); +#endif +#if 0 + r = data & 0x1f; + data >>= 5; + g = data & 0x3f; + data >>= 6; + b = data & 0x1f; + data >>= 5; +#else + r = (data & 0x1f) << 3; + data >>= 5; + g = (data & 0x3f) << 2; + data >>= 6; + b = (data & 0x1f) << 3; + data >>= 5; +#endif + COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); + r = (data & 0x1f) << 3; + data >>= 5; + g = (data & 0x3f) << 2; + data >>= 6; + b = (data & 0x1f) << 3; + data >>= 5; + COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); + width -= 2; + src += 4; + } +} + +static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *)src; +#ifdef SWAP_BYTES + r = data & 0xff; + g = (data >> 8) & 0xff; + b = (data >> 16) & 0xff; +#else + r = (data >> 24) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 8) & 0xff; +#endif + COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); + width--; + src += 4; + } +} + +#undef SWAP_PIXELS +#undef NAME +#undef SWAP_WORDS +#undef ORDER + +#endif diff --git a/vl.h b/vl.h index 00d4c9447..5e56ee422 100644 --- a/vl.h +++ b/vl.h @@ -973,6 +973,11 @@ void ps2_queue(void *, int b); /* smc91c111.c */ void smc91c111_init(NICInfo *, uint32_t, void *, int); +/* pl110.c */ +void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq); +void pl110_update_display(void *opaque); +void pl110_invalidate_display(void *opaque); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From af2f67333f0b45b3f95103f580752f3f0514cf8f Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 6 Feb 2006 16:05:19 +0000 Subject: Fix -nographic on Arm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1747 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl110.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/pl110.c b/hw/pl110.c index 8a4d5807a..5a6638cbe 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -109,6 +109,8 @@ void pl110_update_display(void *opaque) return; switch (s->ds->depth) { + case 0: + return; case 8: fntable = pl110_draw_fn_8; dest_width = 1; @@ -130,7 +132,7 @@ void pl110_update_display(void *opaque) dest_width = 4; break; default: - fprintf(stderr, "qemu: Bad color depth\n"); + fprintf(stderr, "pl110: Bad color depth\n"); exit(1); } if (s->cr & PL110_CR_BEBO) -- cgit v1.2.3 From 3aa22b4b53d4a8f5ae6b073c7c267b6ec9aabf63 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 7 Feb 2006 03:34:35 +0000 Subject: Fix Thumb variable shift condition code bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1748 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-arm/translate.c b/target-arm/translate.c index d5cbc5ee1..77c8957af 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1930,12 +1930,15 @@ static void disas_thumb_insn(DisasContext *s) break; case 0x2: /* lsl */ gen_op_shll_T1_T0_cc(); + gen_op_logic_T1_cc(); break; case 0x3: /* lsr */ gen_op_shrl_T1_T0_cc(); + gen_op_logic_T1_cc(); break; case 0x4: /* asr */ gen_op_sarl_T1_T0_cc(); + gen_op_logic_T1_cc(); break; case 0x5: /* adc */ gen_op_adcl_T0_T1_cc(); @@ -1945,6 +1948,7 @@ static void disas_thumb_insn(DisasContext *s) break; case 0x7: /* ror */ gen_op_rorl_T1_T0_cc(); + gen_op_logic_T1_cc(); break; case 0x8: /* tst */ gen_op_andl_T0_T1(); -- cgit v1.2.3 From f94f5d717c14d18e0a4af2b157ca5a231d7bcc38 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 8 Feb 2006 04:42:17 +0000 Subject: Add support for raw AT keyboard scancodes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1749 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 1 + hw/ps2.c | 34 +++++++++++++++++++++++++++++++++- vl.h | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index 61f8a63a8..7d0f49b76 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -295,6 +295,7 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) break; case KBD_CCMD_WRITE_MODE: s->mode = val; + ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0); /* ??? */ kbd_update_irq(s); break; diff --git a/hw/ps2.c b/hw/ps2.c index e7c66f648..be6b31ce7 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -83,6 +83,10 @@ typedef struct { typedef struct { PS2State common; int scan_enabled; + /* Qemu uses translated PC scancodes internally. To avoid multiple + conversions we do the translation (if any) in the PS/2 emulation + not the keyboard controller. */ + int translate; } PS2KbdState; typedef struct { @@ -99,6 +103,18 @@ typedef struct { uint8_t mouse_buttons; } PS2MouseState; +/* Table to convert from PC scancodes to raw scancodes. */ +static const unsigned char ps2_raw_keycode[128] = { + 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, + 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, + 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, + 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, + 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, + 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, + 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, + 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 +}; + void ps2_queue(void *opaque, int b) { PS2State *s = (PS2State *)opaque; @@ -115,7 +131,13 @@ void ps2_queue(void *opaque, int b) static void ps2_put_keycode(void *opaque, int keycode) { - PS2MouseState *s = opaque; + PS2KbdState *s = opaque; + if (!s->translate && keycode < 0xe0) + { + if (keycode & 0x80) + ps2_queue(&s->common, 0xf0); + keycode = ps2_raw_keycode[keycode & 0x7f]; + } ps2_queue(&s->common, keycode); } @@ -214,6 +236,16 @@ void ps2_write_keyboard(void *opaque, int val) } } +/* Set the scancode translation mode. + 0 = raw scancodes. + 1 = translated scancodes (used by qemu internally). */ + +void ps2_keyboard_set_translation(void *opaque, int mode) +{ + PS2KbdState *s = (PS2KbdState *)opaque; + s->translate = mode; +} + static void ps2_mouse_send_packet(PS2MouseState *s) { unsigned int b; diff --git a/vl.h b/vl.h index 5e56ee422..4d215e7dd 100644 --- a/vl.h +++ b/vl.h @@ -969,6 +969,7 @@ void ps2_write_mouse(void *, int val); void ps2_write_keyboard(void *, int val); uint32_t ps2_read_data(void *); void ps2_queue(void *, int b); +void ps2_keyboard_set_translation(void *opaque, int mode); /* smc91c111.c */ void smc91c111_init(NICInfo *, uint32_t, void *, int); -- cgit v1.2.3 From 05c2a3e7313870811c8a7ec9837f5e75d40ea080 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Feb 2006 22:39:17 +0000 Subject: kqemu/qvm86 must now be compiled outside QEMU git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1750 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 13 ------- configure | 74 ++++++----------------------------- kqemu.h | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 76 deletions(-) create mode 100644 kqemu.h diff --git a/Makefile b/Makefile index cfa7df571..e69cf47da 100644 --- a/Makefile +++ b/Makefile @@ -17,13 +17,6 @@ all: dyngen$(EXESUF) $(TOOLS) $(DOCS) for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ done -ifdef CONFIG_KQEMU -ifdef CONFIG_WIN32 - $(MAKE) -C kqemu -f Makefile.winnt -else - $(MAKE) -C kqemu -endif -endif qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) @@ -39,9 +32,6 @@ clean: for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ done -ifdef CONFIG_KQEMU - $(MAKE) -C kqemu clean -endif distclean: clean rm -f config-host.mak config-host.h @@ -73,9 +63,6 @@ endif for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ done -ifdef CONFIG_KQEMU - cd kqemu ; ./install.sh -endif # various test targets test speed test2: all diff --git a/configure b/configure index fa05bbf38..64cb745dc 100755 --- a/configure +++ b/configure @@ -85,6 +85,7 @@ fmod_lib="" fmod_inc="" linux="no" kqemu="no" +profiler="no" kernel_path="" cocoa="no" check_gfx="yes" @@ -197,6 +198,8 @@ for opt do ;; --disable-kqemu) kqemu="no" ;; + --enable-profiler) profiler="yes" + ;; --kernel-path=*) kernel_path=${opt#--kernel-path=} ;; --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" @@ -365,7 +368,7 @@ echo " use %M for cpu name [$interp_prefix]" echo " --target-list=LIST set target list [$target_list]" echo "" echo "kqemu kernel acceleration support:" -echo " --disable-kqemu disable kqemu build" +echo " --disable-kqemu disable kqemu support" echo " --kernel-path=PATH set the kernel path (configure probes it)" echo "" echo "Advanced options (experts only):" @@ -407,48 +410,6 @@ docdir="$prefix/share/doc/qemu" bindir="$prefix/bin" fi -# kqemu support -if test $kqemu = "yes" ; then - # test if the source code is installed - if test '!' -f "kqemu/Makefile" ; then - kqemu="no" - fi -fi - -# Linux specific kqemu configuration -if test $kqemu = "yes" -a $linux = "yes" ; then -# find the kernel path -if test -z "$kernel_path" ; then -kernel_version=`uname -r` -kernel_path="/lib/modules/$kernel_version/build" -if test '!' -d "$kernel_path/include" ; then - kernel_path="/usr/src/linux" - if test '!' -d "$kernel_path/include" ; then - echo "Could not find kernel includes in /lib/modules or /usr/src/linux - cannot build the kqemu module" - kqemu="no" - fi -fi -fi - -if test $kqemu = "yes" ; then - -# test that the kernel config is present -if test '!' -f "$kernel_path/Makefile" ; then - echo "No Makefile file present in $kernel_path - kqemu cannot be built" - kqemu="no" -fi - -# find build system (2.6 or legacy) -kbuild26="yes" -if grep -q "PATCHLEVEL = 4" $kernel_path/Makefile ; then -kbuild26="no" -fi - -fi # kqemu - -fi # kqemu and linux - - echo "Install prefix $prefix" echo "BIOS directory $datadir" echo "binary directory $bindir" @@ -464,6 +425,7 @@ 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" @@ -490,17 +452,6 @@ if test "$fmod" = "yes"; then fi echo "" echo "kqemu support $kqemu" -if test $kqemu = "yes" -a $linux = "yes" ; then -echo "" -echo "KQEMU Linux module configuration:" -echo "kernel sources $kernel_path" -echo -n "kbuild type " -if test $kbuild26 = "yes"; then -echo "2.6" -else -echo "2.4" -fi -fi if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -601,6 +552,9 @@ 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 @@ -638,15 +592,6 @@ echo -n "#define QEMU_VERSION \"" >> $config_h head $source_path/VERSION >> $config_h echo "\"" >> $config_h -if test $kqemu = "yes" ; then - echo "CONFIG_KQEMU=yes" >> $config_mak - if test $linux = "yes" ; then - echo "KERNEL_PATH=$kernel_path" >> $config_mak - if test $kbuild26 = "yes" ; then - echo "CONFIG_KBUILD26=yes" >> $config_mak - fi - fi -fi echo "SRC_PATH=$source_path" >> $config_mak echo "TARGET_DIRS=$target_list" >> $config_mak @@ -746,6 +691,9 @@ elif test "$target_cpu" = "x86_64" ; then 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 + if test $kqemu_profile = "yes" ; then + echo "#define CONFIG_KQEMU_PROFILE 1" >> $config_h + fi fi elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then echo "TARGET_ARCH=mips" >> $config_mak diff --git a/kqemu.h b/kqemu.h new file mode 100644 index 000000000..892e33593 --- /dev/null +++ b/kqemu.h @@ -0,0 +1,132 @@ +/* + * KQEMU header + * + * 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. + */ +#ifndef KQEMU_H +#define KQEMU_H + +#define KQEMU_VERSION 0x010300 + +struct kqemu_segment_cache { + uint32_t selector; + unsigned long base; + uint32_t limit; + uint32_t flags; +}; + +struct kqemu_cpu_state { +#ifdef __x86_64__ + unsigned long regs[16]; +#else + unsigned long regs[8]; +#endif + unsigned long eip; + unsigned long eflags; + + uint32_t dummy0, dummy1, dumm2, dummy3, dummy4; + + struct kqemu_segment_cache segs[6]; /* selector values */ + struct kqemu_segment_cache ldt; + struct kqemu_segment_cache tr; + struct kqemu_segment_cache gdt; /* only base and limit are used */ + struct kqemu_segment_cache idt; /* only base and limit are used */ + + unsigned long cr0; + unsigned long dummy5; + unsigned long cr2; + unsigned long cr3; + unsigned long cr4; + uint32_t a20_mask; + + /* sysenter registers */ + uint32_t sysenter_cs; + uint32_t sysenter_esp; + uint32_t sysenter_eip; + uint64_t efer __attribute__((aligned(8))); + uint64_t star; +#ifdef __x86_64__ + unsigned long lstar; + unsigned long cstar; + unsigned long fmask; + unsigned long kernelgsbase; +#endif + uint64_t tsc_offset; + + unsigned long dr0; + unsigned long dr1; + unsigned long dr2; + unsigned long dr3; + unsigned long dr6; + unsigned long dr7; + + uint8_t cpl; + uint8_t user_only; + + uint32_t error_code; /* error_code when exiting with an exception */ + unsigned long next_eip; /* next eip value when exiting with an interrupt */ + unsigned int nb_pages_to_flush; /* number of pages to flush, + KQEMU_FLUSH_ALL means full flush */ +#define KQEMU_MAX_PAGES_TO_FLUSH 512 +#define KQEMU_FLUSH_ALL (KQEMU_MAX_PAGES_TO_FLUSH + 1) + + long retval; + + /* number of ram_dirty entries to update */ + unsigned int nb_ram_pages_to_update; +#define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512 +#define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1) + +#define KQEMU_MAX_MODIFIED_RAM_PAGES 512 + unsigned int nb_modified_ram_pages; +}; + +struct kqemu_init { + uint8_t *ram_base; /* must be page aligned */ + unsigned long ram_size; /* must be multiple of 4 KB */ + uint8_t *ram_dirty; /* must be page aligned */ + uint32_t **phys_to_ram_map; /* must be page aligned */ + unsigned long *pages_to_flush; /* must be page aligned */ + unsigned long *ram_pages_to_update; /* must be page aligned */ + unsigned long *modified_ram_pages; /* must be page aligned */ +}; + +#define KQEMU_RET_ABORT (-1) +#define KQEMU_RET_EXCEPTION 0x0000 /* 8 low order bit are the exception */ +#define KQEMU_RET_INT 0x0100 /* 8 low order bit are the interrupt */ +#define KQEMU_RET_SOFTMMU 0x0200 /* emulation needed (I/O or + unsupported INSN) */ +#define KQEMU_RET_INTR 0x0201 /* interrupted by a signal */ +#define KQEMU_RET_SYSCALL 0x0300 /* syscall insn */ + +#ifdef _WIN32 +#define KQEMU_EXEC CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define KQEMU_INIT CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define KQEMU_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_READ_ACCESS) +#define KQEMU_MODIFY_RAM_PAGES CTL_CODE(FILE_DEVICE_UNKNOWN, 4, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#else +#define KQEMU_EXEC _IOWR('q', 1, struct kqemu_cpu_state) +#define KQEMU_INIT _IOW('q', 2, struct kqemu_init) +#define KQEMU_GET_VERSION _IOR('q', 3, int) +#define KQEMU_MODIFY_RAM_PAGES _IOW('q', 4, int) +#endif + +#endif /* KQEMU_H */ -- cgit v1.2.3 From 5f1ce9487c7ab600433d6ebf059b45adad267c27 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Feb 2006 22:40:15 +0000 Subject: support for builtin profiler git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1751 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 20 +++++++++++++++++++ monitor.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index b374fe86b..e0b60d96d 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -867,4 +867,24 @@ void cpu_tlb_update_dirty(CPUState *env); void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +/* profiling */ +#ifdef CONFIG_PROFILER +static inline int64_t profile_getclock(void) +{ + int64_t val; + asm volatile ("rdtsc" : "=A" (val)); + return val; +} + +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 */ diff --git a/monitor.c b/monitor.c index d7acaa420..6b98cf13f 100644 --- a/monitor.c +++ b/monitor.c @@ -296,9 +296,6 @@ static void do_info_history (void) static void do_quit(void) { -#ifdef USE_KQEMU - kqemu_record_dump(); -#endif exit(0); } @@ -960,12 +957,69 @@ static void do_info_kqemu(void) return; } val = env->kqemu_enabled; - term_printf("kqemu is %s\n", val ? "enabled" : "disabled"); + term_printf("kqemu support: "); + switch(val) { + default: + case 0: + term_printf("disabled\n"); + break; + case 1: + term_printf("enabled for user code\n"); + break; + case 2: + term_printf("enabled for user and kernel code\n"); + break; + } #else - term_printf("kqemu support is not compiled\n"); + term_printf("kqemu support: not compiled\n"); #endif } +#ifdef CONFIG_PROFILER + +int64_t kqemu_time; +int64_t qemu_time; +int64_t kqemu_exec_count; +int64_t dev_time; +int64_t kqemu_ret_int_count; +int64_t kqemu_ret_excp_count; +int64_t kqemu_ret_intr_count; + +static void do_info_profile(void) +{ + int64_t total; + total = qemu_time; + if (total == 0) + total = 1; + term_printf("async time %lld (%0.3f)\n", + dev_time, dev_time / (double)ticks_per_sec); + term_printf("qemu time %lld (%0.3f)\n", + qemu_time, qemu_time / (double)ticks_per_sec); + term_printf("kqemu time %lld (%0.3f %0.1f%%) count=%lld int=%lld excp=%lld intr=%lld\n", + kqemu_time, kqemu_time / (double)ticks_per_sec, + kqemu_time / (double)total * 100.0, + kqemu_exec_count, + kqemu_ret_int_count, + kqemu_ret_excp_count, + kqemu_ret_intr_count); + qemu_time = 0; + kqemu_time = 0; + kqemu_exec_count = 0; + dev_time = 0; + kqemu_ret_int_count = 0; + kqemu_ret_excp_count = 0; + kqemu_ret_intr_count = 0; +#ifdef USE_KQEMU + kqemu_record_dump(); +#endif +} +#else +static void do_info_profile(void) +{ + term_printf("Internal profiler not compiled\n"); +} +#endif + static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -1054,6 +1108,8 @@ static term_cmd_t info_cmds[] = { "", "show guest USB devices", }, { "usbhost", "", usb_host_info, "", "show host USB devices", }, + { "profile", "", do_info_profile, + "", "show profiling information", }, { NULL, NULL, }, }; -- cgit v1.2.3 From f1c85677fc83b82e737223bfbff11241caa050b4 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Feb 2006 22:41:53 +0000 Subject: added last_io_time field git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1752 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_template.h | 6 ++++++ target-i386/cpu.h | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/softmmu_template.h b/softmmu_template.h index 9bae4f628..1c12c4241 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -68,6 +68,9 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32; #endif #endif /* SHIFT > 2 */ +#ifdef USE_KQEMU + env->last_io_time = cpu_get_time_fast(); +#endif return res; } @@ -201,6 +204,9 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32); #endif #endif /* SHIFT > 2 */ +#ifdef USE_KQEMU + env->last_io_time = cpu_get_time_fast(); +#endif } void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 450dd8cbe..eca3993b9 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -522,6 +522,7 @@ typedef struct CPUX86State { #ifdef USE_KQEMU int kqemu_enabled; + int last_io_time; #endif /* in order to simplify APIC support, we leave this pointer to the user */ @@ -637,6 +638,15 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); #define X86_DUMP_FPU 0x0001 /* dump FPU state too */ #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ +#ifdef USE_KQEMU +static inline int cpu_get_time_fast(void) +{ + int low, high; + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + return low; +} +#endif + #define TARGET_PAGE_BITS 12 #include "cpu-all.h" -- cgit v1.2.3 From f32fc64851c28e2dd3976d08f93006a3eff68a3d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Feb 2006 22:43:39 +0000 Subject: optional support for kernel code virtualization git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1753 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 10 +++ exec-all.h | 12 +++- exec.c | 15 +++++ kqemu.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 216 insertions(+), 37 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 1ec49c2d6..3bf4b370a 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -627,6 +627,9 @@ int cpu_exec(CPUState *env1) 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) == @@ -755,6 +758,13 @@ int cpu_exec(CPUState *env1) /* 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 { diff --git a/exec-all.h b/exec-all.h index 58debaa1b..cc55ab44d 100644 --- a/exec-all.h +++ b/exec-all.h @@ -577,21 +577,27 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) #ifdef USE_KQEMU +#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG)) + int kqemu_init(CPUState *env); int kqemu_cpu_exec(CPUState *env); void kqemu_flush_page(CPUState *env, target_ulong addr); void kqemu_flush(CPUState *env, int global); void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr); +void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr); void kqemu_cpu_interrupt(CPUState *env); +void kqemu_record_dump(void); static inline int kqemu_is_ok(CPUState *env) { return(env->kqemu_enabled && - (env->hflags & HF_CPL_MASK) == 3 && - (env->eflags & IOPL_MASK) != IOPL_MASK && (env->cr[0] & CR0_PE_MASK) && + !(env->hflags & HF_INHIBIT_IRQ_MASK) && (env->eflags & IF_MASK) && - !(env->eflags & VM_MASK)); + !(env->eflags & VM_MASK) && + (env->kqemu_enabled == 2 || + ((env->hflags & HF_CPL_MASK) == 3 && + (env->eflags & IOPL_MASK) != IOPL_MASK))); } #endif diff --git a/exec.c b/exec.c index 3028a524e..e4e68d9dc 100644 --- a/exec.c +++ b/exec.c @@ -1796,6 +1796,11 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t #endif } stb_p((uint8_t *)(long)addr, val); +#ifdef USE_KQEMU + if (cpu_single_env->kqemu_enabled && + (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK) + kqemu_modify_page(cpu_single_env, ram_addr); +#endif dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; /* we remove the notdirty callback only if the code has been @@ -1817,6 +1822,11 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t #endif } stw_p((uint8_t *)(long)addr, val); +#ifdef USE_KQEMU + if (cpu_single_env->kqemu_enabled && + (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK) + kqemu_modify_page(cpu_single_env, ram_addr); +#endif dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; /* we remove the notdirty callback only if the code has been @@ -1838,6 +1848,11 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t #endif } stl_p((uint8_t *)(long)addr, val); +#ifdef USE_KQEMU + if (cpu_single_env->kqemu_enabled && + (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK) + kqemu_modify_page(cpu_single_env, ram_addr); +#endif dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; /* we remove the notdirty callback only if the code has been diff --git a/kqemu.c b/kqemu.c index 70cfe2879..846a89d2d 100644 --- a/kqemu.c +++ b/kqemu.c @@ -54,6 +54,9 @@ #define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512 #define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1) #endif +#ifndef KQEMU_MAX_MODIFIED_RAM_PAGES +#define KQEMU_MAX_MODIFIED_RAM_PAGES 512 +#endif #ifdef _WIN32 #define KQEMU_DEVICE "\\\\.\\kqemu" @@ -71,11 +74,18 @@ int kqemu_fd = KQEMU_INVALID_FD; #define kqemu_closefd(x) close(x) #endif +/* 0 = not allowed + 1 = user kqemu + 2 = kernel kqemu +*/ int kqemu_allowed = 1; unsigned long *pages_to_flush; unsigned int nb_pages_to_flush; unsigned long *ram_pages_to_update; unsigned int nb_ram_pages_to_update; +unsigned long *modified_ram_pages; +unsigned int nb_modified_ram_pages; +uint8_t *modified_ram_pages_table; extern uint32_t **l1_phys_map; #define cpuid(index, eax, ebx, ecx, edx) \ @@ -185,6 +195,14 @@ int kqemu_init(CPUState *env) if (!ram_pages_to_update) goto fail; + modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES * + sizeof(unsigned long)); + if (!modified_ram_pages) + goto fail; + modified_ram_pages_table = qemu_mallocz(phys_ram_size >> TARGET_PAGE_BITS); + if (!modified_ram_pages_table) + goto fail; + init.ram_base = phys_ram_base; init.ram_size = phys_ram_size; init.ram_dirty = phys_ram_dirty; @@ -193,6 +211,9 @@ int kqemu_init(CPUState *env) #if KQEMU_VERSION >= 0x010200 init.ram_pages_to_update = ram_pages_to_update; #endif +#if KQEMU_VERSION >= 0x010300 + init.modified_ram_pages = modified_ram_pages; +#endif #ifdef _WIN32 ret = DeviceIoControl(kqemu_fd, KQEMU_INIT, &init, sizeof(init), NULL, 0, &temp, NULL) == TRUE ? 0 : -1; @@ -207,7 +228,7 @@ int kqemu_init(CPUState *env) return -1; } kqemu_update_cpuid(env); - env->kqemu_enabled = 1; + env->kqemu_enabled = kqemu_allowed; nb_pages_to_flush = 0; nb_ram_pages_to_update = 0; return 0; @@ -215,7 +236,7 @@ int kqemu_init(CPUState *env) void kqemu_flush_page(CPUState *env, target_ulong addr) { -#ifdef DEBUG +#if defined(DEBUG) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr); } @@ -252,6 +273,49 @@ void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr) ram_pages_to_update[nb_ram_pages_to_update++] = ram_addr; } +static void kqemu_reset_modified_ram_pages(void) +{ + int i; + unsigned long page_index; + + for(i = 0; i < nb_modified_ram_pages; i++) { + page_index = modified_ram_pages[i] >> TARGET_PAGE_BITS; + modified_ram_pages_table[page_index] = 0; + } + nb_modified_ram_pages = 0; +} + +void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr) +{ + unsigned long page_index; + int ret; +#ifdef _WIN32 + DWORD temp; +#endif + + page_index = ram_addr >> TARGET_PAGE_BITS; + if (!modified_ram_pages_table[page_index]) { +#if 0 + printf("%d: modify_page=%08lx\n", nb_modified_ram_pages, ram_addr); +#endif + modified_ram_pages_table[page_index] = 1; + modified_ram_pages[nb_modified_ram_pages++] = ram_addr; + if (nb_modified_ram_pages >= KQEMU_MAX_MODIFIED_RAM_PAGES) { + /* flush */ +#ifdef _WIN32 + ret = DeviceIoControl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, + &nb_modified_ram_pages, + sizeof(nb_modified_ram_pages), + NULL, 0, &temp, NULL); +#else + ret = ioctl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, + &nb_modified_ram_pages); +#endif + kqemu_reset_modified_ram_pages(); + } + } +} + struct fpstate { uint16_t fpuc; uint16_t dummy1; @@ -442,7 +506,7 @@ static int do_syscall(CPUState *env, return 2; } -#ifdef PROFILE +#ifdef CONFIG_PROFILER #define PC_REC_SIZE 1 #define PC_REC_HASH_BITS 16 @@ -454,10 +518,10 @@ typedef struct PCRecord { struct PCRecord *next; } PCRecord; -PCRecord *pc_rec_hash[PC_REC_HASH_SIZE]; -int nb_pc_records; +static PCRecord *pc_rec_hash[PC_REC_HASH_SIZE]; +static int nb_pc_records; -void kqemu_record_pc(unsigned long pc) +static void kqemu_record_pc(unsigned long pc) { unsigned long h; PCRecord **pr, *r; @@ -484,7 +548,7 @@ void kqemu_record_pc(unsigned long pc) nb_pc_records++; } -int pc_rec_cmp(const void *p1, const void *p2) +static int pc_rec_cmp(const void *p1, const void *p2) { PCRecord *r1 = *(PCRecord **)p1; PCRecord *r2 = *(PCRecord **)p2; @@ -496,6 +560,21 @@ int pc_rec_cmp(const void *p1, const void *p2) return -1; } +static void kqemu_record_flush(void) +{ + PCRecord *r, *r_next; + int h; + + for(h = 0; h < PC_REC_HASH_SIZE; h++) { + for(r = pc_rec_hash[h]; r != NULL; r = r_next) { + r_next = r->next; + free(r); + } + pc_rec_hash[h] = NULL; + } + nb_pc_records = 0; +} + void kqemu_record_dump(void) { PCRecord **pr, *r; @@ -532,21 +611,26 @@ void kqemu_record_dump(void) } fclose(f); free(pr); -} -#else -void kqemu_record_dump(void) -{ + + kqemu_record_flush(); } #endif int kqemu_cpu_exec(CPUState *env) { struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state; - int ret; + int ret, cpl, i; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif + #ifdef _WIN32 DWORD temp; #endif +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif #ifdef DEBUG if (loglevel & CPU_LOG_INT) { fprintf(logfile, "kqemu: cpu_exec: enter\n"); @@ -568,6 +652,19 @@ int kqemu_cpu_exec(CPUState *env) kenv->a20_mask = env->a20_mask; #if KQEMU_VERSION >= 0x010100 kenv->efer = env->efer; +#endif +#if KQEMU_VERSION >= 0x010300 + kenv->tsc_offset = 0; + kenv->star = env->star; + kenv->sysenter_cs = env->sysenter_cs; + kenv->sysenter_esp = env->sysenter_esp; + kenv->sysenter_eip = env->sysenter_eip; +#ifdef __x86_64__ + kenv->lstar = env->lstar; + kenv->cstar = env->cstar; + kenv->fmask = env->fmask; + kenv->kernelgsbase = env->kernelgsbase; +#endif #endif if (env->dr[7] & 0xff) { kenv->dr7 = env->dr[7]; @@ -579,21 +676,24 @@ int kqemu_cpu_exec(CPUState *env) kenv->dr7 = 0; } kenv->dr6 = env->dr[6]; - kenv->cpl = 3; + cpl = (env->hflags & HF_CPL_MASK); + kenv->cpl = cpl; kenv->nb_pages_to_flush = nb_pages_to_flush; - nb_pages_to_flush = 0; #if KQEMU_VERSION >= 0x010200 - kenv->user_only = 1; + kenv->user_only = (env->kqemu_enabled == 1); kenv->nb_ram_pages_to_update = nb_ram_pages_to_update; #endif nb_ram_pages_to_update = 0; - if (!(kenv->cr0 & CR0_TS_MASK)) { - if (env->cpuid_features & CPUID_FXSR) - restore_native_fp_fxrstor(env); - else - restore_native_fp_frstor(env); - } +#if KQEMU_VERSION >= 0x010300 + kenv->nb_modified_ram_pages = nb_modified_ram_pages; +#endif + kqemu_reset_modified_ram_pages(); + + if (env->cpuid_features & CPUID_FXSR) + restore_native_fp_fxrstor(env); + else + restore_native_fp_frstor(env); #ifdef _WIN32 if (DeviceIoControl(kqemu_fd, KQEMU_EXEC, @@ -612,30 +712,49 @@ int kqemu_cpu_exec(CPUState *env) ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv); #endif #endif - if (!(kenv->cr0 & CR0_TS_MASK)) { - if (env->cpuid_features & CPUID_FXSR) - save_native_fp_fxsave(env); - else - save_native_fp_fsave(env); - } + if (env->cpuid_features & CPUID_FXSR) + save_native_fp_fxsave(env); + else + save_native_fp_fsave(env); memcpy(env->regs, kenv->regs, sizeof(env->regs)); env->eip = kenv->eip; env->eflags = kenv->eflags; memcpy(env->segs, kenv->segs, sizeof(env->segs)); + cpu_x86_set_cpl(env, kenv->cpl); + memcpy(&env->ldt, &kenv->ldt, sizeof(env->ldt)); #if 0 /* no need to restore that */ - memcpy(env->ldt, kenv->ldt, sizeof(env->ldt)); memcpy(env->tr, kenv->tr, sizeof(env->tr)); memcpy(env->gdt, kenv->gdt, sizeof(env->gdt)); memcpy(env->idt, kenv->idt, sizeof(env->idt)); - env->cr[0] = kenv->cr0; - env->cr[3] = kenv->cr3; - env->cr[4] = kenv->cr4; env->a20_mask = kenv->a20_mask; #endif + env->cr[0] = kenv->cr0; + env->cr[4] = kenv->cr4; + env->cr[3] = kenv->cr3; env->cr[2] = kenv->cr2; env->dr[6] = kenv->dr6; +#if KQEMU_VERSION >= 0x010300 +#ifdef __x86_64__ + env->kernelgsbase = kenv->kernelgsbase; +#endif +#endif + + /* flush pages as indicated by kqemu */ + if (kenv->nb_pages_to_flush >= KQEMU_FLUSH_ALL) { + tlb_flush(env, 1); + } else { + for(i = 0; i < kenv->nb_pages_to_flush; i++) { + tlb_flush_page(env, pages_to_flush[i]); + } + } + nb_pages_to_flush = 0; + +#ifdef CONFIG_PROFILER + kqemu_time += profile_getclock() - ti; + kqemu_exec_count++; +#endif #if KQEMU_VERSION >= 0x010200 if (kenv->nb_ram_pages_to_update > 0) { @@ -643,6 +762,16 @@ int kqemu_cpu_exec(CPUState *env) } #endif +#if KQEMU_VERSION >= 0x010300 + if (kenv->nb_modified_ram_pages > 0) { + for(i = 0; i < kenv->nb_modified_ram_pages; i++) { + unsigned long addr; + addr = modified_ram_pages[i]; + tb_invalidate_phys_page_range(addr, addr + TARGET_PAGE_SIZE, 0); + } + } +#endif + /* restore the hidden flags */ { unsigned int new_hflags; @@ -679,7 +808,14 @@ int kqemu_cpu_exec(CPUState *env) ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) | new_hflags; } - + /* update FPU flags */ + env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) | + ((env->cr[0] << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)); + if (env->cr[4] & CR4_OSFXSR_MASK) + env->hflags |= HF_OSFXSR_MASK; + else + env->hflags &= ~HF_OSFXSR_MASK; + #ifdef DEBUG if (loglevel & CPU_LOG_INT) { fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret); @@ -694,6 +830,9 @@ int kqemu_cpu_exec(CPUState *env) env->error_code = 0; env->exception_is_int = 1; env->exception_next_eip = kenv->next_eip; +#ifdef CONFIG_PROFILER + kqemu_ret_int_count++; +#endif #ifdef DEBUG if (loglevel & CPU_LOG_INT) { fprintf(logfile, "kqemu: interrupt v=%02x:\n", @@ -707,6 +846,9 @@ int kqemu_cpu_exec(CPUState *env) env->error_code = kenv->error_code; env->exception_is_int = 0; env->exception_next_eip = 0; +#ifdef CONFIG_PROFILER + kqemu_ret_excp_count++; +#endif #ifdef DEBUG if (loglevel & CPU_LOG_INT) { fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n", @@ -716,6 +858,9 @@ int kqemu_cpu_exec(CPUState *env) #endif return 1; } else if (ret == KQEMU_RET_INTR) { +#ifdef CONFIG_PROFILER + kqemu_ret_intr_count++; +#endif #ifdef DEBUG if (loglevel & CPU_LOG_INT) { cpu_dump_state(env, logfile, fprintf, 0); @@ -723,8 +868,11 @@ int kqemu_cpu_exec(CPUState *env) #endif return 0; } else if (ret == KQEMU_RET_SOFTMMU) { -#ifdef PROFILE - kqemu_record_pc(env->eip + env->segs[R_CS].base); +#ifdef CONFIG_PROFILER + { + unsigned long pc = env->eip + env->segs[R_CS].base; + kqemu_record_pc(pc); + } #endif #ifdef DEBUG if (loglevel & CPU_LOG_INT) { -- cgit v1.2.3 From 89bfc105d00202551fa669c2e2779dc15457a227 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Feb 2006 22:46:31 +0000 Subject: added last_io_time field - '-kernel-kqemu' experimental option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1754 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/vl.c b/vl.c index eaa4560c7..97eddbf49 100644 --- a/vl.c +++ b/vl.c @@ -369,6 +369,10 @@ void cpu_outb(CPUState *env, int addr, int val) fprintf(logfile, "outb: %04x %02x\n", addr, val); #endif ioport_write_table[0][addr](ioport_opaque[addr], addr, val); +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif } void cpu_outw(CPUState *env, int addr, int val) @@ -378,6 +382,10 @@ void cpu_outw(CPUState *env, int addr, int val) fprintf(logfile, "outw: %04x %04x\n", addr, val); #endif ioport_write_table[1][addr](ioport_opaque[addr], addr, val); +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif } void cpu_outl(CPUState *env, int addr, int val) @@ -387,6 +395,10 @@ void cpu_outl(CPUState *env, int addr, int val) fprintf(logfile, "outl: %04x %08x\n", addr, val); #endif ioport_write_table[2][addr](ioport_opaque[addr], addr, val); +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif } int cpu_inb(CPUState *env, int addr) @@ -396,6 +408,10 @@ int cpu_inb(CPUState *env, int addr) #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inb : %04x %02x\n", addr, val); +#endif +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); #endif return val; } @@ -407,6 +423,10 @@ int cpu_inw(CPUState *env, int addr) #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inw : %04x %04x\n", addr, val); +#endif +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); #endif return val; } @@ -418,6 +438,10 @@ int cpu_inl(CPUState *env, int addr) #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inl : %04x %08x\n", addr, val); +#endif +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); #endif return val; } @@ -4018,6 +4042,9 @@ static CPUState *cur_cpu; int main_loop(void) { int ret, timeout; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif CPUState *env; cur_cpu = first_cpu; @@ -4030,7 +4057,13 @@ int main_loop(void) env = env->next_cpu; if (!env) env = first_cpu; +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif ret = cpu_exec(env); +#ifdef CONFIG_PROFILER + qemu_time += profile_getclock() - ti; +#endif if (ret != EXCP_HALTED) break; /* all CPUs are halted ? */ @@ -4067,7 +4100,13 @@ int main_loop(void) } else { timeout = 10; } +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif main_loop_wait(timeout); +#ifdef CONFIG_PROFILER + dev_time += profile_getclock() - ti; +#endif } cpu_disable_ticks(); return ret; @@ -4250,6 +4289,7 @@ enum { QEMU_OPTION_full_screen, QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, + QEMU_OPTION_kernel_kqemu, QEMU_OPTION_win2k_hack, QEMU_OPTION_usb, QEMU_OPTION_usbdevice, @@ -4305,6 +4345,7 @@ const QEMUOption qemu_options[] = { { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, #ifdef USE_KQEMU { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, + { "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu }, #endif #if defined(TARGET_PPC) || defined(TARGET_SPARC) { "g", 1, QEMU_OPTION_g }, @@ -4879,6 +4920,9 @@ int main(int argc, char **argv) case QEMU_OPTION_no_kqemu: kqemu_allowed = 0; break; + case QEMU_OPTION_kernel_kqemu: + kqemu_allowed = 2; + break; #endif case QEMU_OPTION_usb: usb_enabled = 1; -- cgit v1.2.3 From b88a38324b9cc469d6fffaecacbeb106a248a4cf Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 8 Feb 2006 22:59:35 +0000 Subject: kqemu.h include path fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1755 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kqemu.c b/kqemu.c index 846a89d2d..bd70474d6 100644 --- a/kqemu.c +++ b/kqemu.c @@ -44,7 +44,7 @@ #include #include -#include "kqemu/kqemu.h" +#include "kqemu.h" /* compatibility stuff */ #ifndef KQEMU_RET_SYSCALL -- cgit v1.2.3 From ce4defa062c5e6d940f73a1013f8770f23b0f4bf Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 9 Feb 2006 16:49:55 +0000 Subject: Arm Linux EABI syscall support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1756 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 6 +- linux-user/syscall.c | 149 ++++++++++++++++++++++++++++++++++++---------- linux-user/syscall_defs.h | 44 +++++++++++++- target-arm/cpu.h | 5 ++ 4 files changed, 171 insertions(+), 33 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 56accfbb5..afcf4f4b1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -360,6 +360,7 @@ void cpu_loop(CPUARMState *env) case EXCP_SWI: case EXCP_BKPT: { + env->eabi = 1; /* system call */ if (trapnr == EXCP_BKPT) { if (env->thumb) { @@ -386,13 +387,14 @@ void cpu_loop(CPUARMState *env) } else if (n == ARM_NR_semihosting || n == ARM_NR_thumb_semihosting) { env->regs[0] = do_arm_semihosting (env); - } else if (n >= ARM_SYSCALL_BASE + } else if (n == 0 || n >= ARM_SYSCALL_BASE || (env->thumb && n == ARM_THUMB_SYSCALL)) { /* linux syscall */ - if (env->thumb) { + if (env->thumb || n == 0) { n = env->regs[7]; } else { n -= ARM_SYSCALL_BASE; + env->eabi = 0; } env->regs[0] = do_syscall(env, n, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 164eb394a..ab7846d7a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1651,6 +1651,45 @@ void syscall_init(void) } } +static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) +{ +#ifdef TARGET_WORDS_BIG_ENDIAN + return ((uint64_t)word0 << 32) | word1; +#else + return ((uint64_t)word1 << 32) | word0; +#endif +} + +#ifdef TARGET_NR_truncate64 +static inline long target_truncate64(void *cpu_env, const char *arg1, + long arg2, long arg3, long arg4) +{ +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) + { + arg2 = arg3; + arg3 = arg4; + } +#endif + return get_errno(truncate64(arg1, target_offset64(arg2, arg3))); +} +#endif + +#ifdef TARGET_NR_ftruncate64 +static inline long target_ftruncate64(void *cpu_env, long arg1, long arg2, + long arg3, long arg4) +{ +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) + { + arg2 = arg3; + arg3 = arg4; + } +#endif + return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3))); +} +#endif + long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { @@ -2844,12 +2883,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_truncate64 case TARGET_NR_truncate64: - ret = get_errno(truncate64((const char *)arg1, arg2)); + ret = target_truncate64(cpu_env, (const char *)arg1, arg2, arg3, arg4); break; #endif #ifdef TARGET_NR_ftruncate64 case TARGET_NR_ftruncate64: - ret = get_errno(ftruncate64(arg1, arg2)); + ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4); break; #endif #ifdef TARGET_NR_stat64 @@ -2868,25 +2907,50 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(fstat(arg1, &st)); do_stat64: if (!is_error(ret)) { - struct target_stat64 *target_st = (void *)arg2; - memset(target_st, 0, sizeof(struct target_stat64)); - put_user(st.st_dev, &target_st->st_dev); - put_user(st.st_ino, &target_st->st_ino); +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) { + struct target_eabi_stat64 *target_st = (void *)arg2; + memset(target_st, 0, sizeof(struct target_eabi_stat64)); + put_user(st.st_dev, &target_st->st_dev); + put_user(st.st_ino, &target_st->st_ino); +#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO + put_user(st.st_ino, &target_st->__st_ino); +#endif + put_user(st.st_mode, &target_st->st_mode); + put_user(st.st_nlink, &target_st->st_nlink); + put_user(st.st_uid, &target_st->st_uid); + put_user(st.st_gid, &target_st->st_gid); + put_user(st.st_rdev, &target_st->st_rdev); + /* XXX: better use of kernel struct */ + put_user(st.st_size, &target_st->st_size); + put_user(st.st_blksize, &target_st->st_blksize); + put_user(st.st_blocks, &target_st->st_blocks); + put_user(st.st_atime, &target_st->target_st_atime); + put_user(st.st_mtime, &target_st->target_st_mtime); + put_user(st.st_ctime, &target_st->target_st_ctime); + } else +#endif + { + struct target_stat64 *target_st = (void *)arg2; + memset(target_st, 0, sizeof(struct target_stat64)); + put_user(st.st_dev, &target_st->st_dev); + put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - put_user(st.st_ino, &target_st->__st_ino); -#endif - put_user(st.st_mode, &target_st->st_mode); - put_user(st.st_nlink, &target_st->st_nlink); - put_user(st.st_uid, &target_st->st_uid); - put_user(st.st_gid, &target_st->st_gid); - put_user(st.st_rdev, &target_st->st_rdev); - /* XXX: better use of kernel struct */ - put_user(st.st_size, &target_st->st_size); - put_user(st.st_blksize, &target_st->st_blksize); - put_user(st.st_blocks, &target_st->st_blocks); - put_user(st.st_atime, &target_st->target_st_atime); - put_user(st.st_mtime, &target_st->target_st_mtime); - put_user(st.st_ctime, &target_st->target_st_ctime); + put_user(st.st_ino, &target_st->__st_ino); +#endif + put_user(st.st_mode, &target_st->st_mode); + put_user(st.st_nlink, &target_st->st_nlink); + put_user(st.st_uid, &target_st->st_uid); + put_user(st.st_gid, &target_st->st_gid); + put_user(st.st_rdev, &target_st->st_rdev); + /* XXX: better use of kernel struct */ + put_user(st.st_size, &target_st->st_size); + put_user(st.st_blksize, &target_st->st_blksize); + put_user(st.st_blocks, &target_st->st_blocks); + put_user(st.st_atime, &target_st->target_st_atime); + put_user(st.st_mtime, &target_st->target_st_mtime); + put_user(st.st_ctime, &target_st->target_st_ctime); + } } } break; @@ -3150,26 +3214,51 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { struct flock64 fl; struct target_flock64 *target_fl = (void *)arg3; +#ifdef TARGET_ARM + struct target_eabi_flock64 *target_efl = (void *)arg3; +#endif switch(arg2) { case F_GETLK64: ret = get_errno(fcntl(arg1, arg2, &fl)); if (ret == 0) { - target_fl->l_type = tswap16(fl.l_type); - target_fl->l_whence = tswap16(fl.l_whence); - target_fl->l_start = tswap64(fl.l_start); - target_fl->l_len = tswap64(fl.l_len); - target_fl->l_pid = tswapl(fl.l_pid); +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) { + target_efl->l_type = tswap16(fl.l_type); + target_efl->l_whence = tswap16(fl.l_whence); + target_efl->l_start = tswap64(fl.l_start); + target_efl->l_len = tswap64(fl.l_len); + target_efl->l_pid = tswapl(fl.l_pid); + } else +#endif + { + target_fl->l_type = tswap16(fl.l_type); + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswap64(fl.l_start); + target_fl->l_len = tswap64(fl.l_len); + target_fl->l_pid = tswapl(fl.l_pid); + } } break; case F_SETLK64: case F_SETLKW64: - fl.l_type = tswap16(target_fl->l_type); - fl.l_whence = tswap16(target_fl->l_whence); - fl.l_start = tswap64(target_fl->l_start); - fl.l_len = tswap64(target_fl->l_len); - fl.l_pid = tswapl(target_fl->l_pid); +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) { + fl.l_type = tswap16(target_efl->l_type); + fl.l_whence = tswap16(target_efl->l_whence); + fl.l_start = tswap64(target_efl->l_start); + fl.l_len = tswap64(target_efl->l_len); + fl.l_pid = tswapl(target_efl->l_pid); + } else +#endif + { + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswap64(target_fl->l_start); + fl.l_len = tswap64(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + } ret = get_errno(fcntl(arg1, arg2, &fl)); break; default: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 68f7e7f01..c722e3a42 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -924,6 +924,38 @@ struct target_stat64 { unsigned long long st_ino; } __attribute__((packed)); +#ifdef TARGET_ARM +struct target_eabi_stat64 { + unsigned long long st_dev; + unsigned int __pad1; + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned long long st_rdev; + unsigned int __pad2[2]; + + long long st_size; + unsigned long st_blksize; + unsigned int __pad3; + unsigned long long st_blocks; + + unsigned long target_st_atime; + unsigned long target_st_atime_nsec; + + unsigned long target_st_mtime; + unsigned long target_st_mtime_nsec; + + unsigned long target_st_ctime; + unsigned long target_st_ctime_nsec; + + unsigned long long st_ino; +} __attribute__ ((packed)); +#endif + #elif defined(TARGET_SPARC) struct target_stat { @@ -1298,8 +1330,18 @@ struct target_flock64 { unsigned long long l_start; unsigned long long l_len; int l_pid; -}; +}__attribute__((packed)); +#ifdef TARGET_ARM +struct target_eabi_flock64 { + short l_type; + short l_whence; + int __pad; + unsigned long long l_start; + unsigned long long l_len; + int l_pid; +}__attribute__((packed)); +#endif /* soundcard defines */ /* XXX: convert them all to arch indepedent entries */ diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7cc7da60e..052634cd5 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -110,6 +110,11 @@ typedef struct CPUARMState { float_status fp_status; } vfp; +#if defined(CONFIG_USER_ONLY) + /* For usermode syscall translation. */ + int eabi; +#endif + CPU_COMMON } CPUARMState; -- cgit v1.2.3 From 29517134c63315ae6d36100fd4d0736f8e8803a7 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 9 Feb 2006 17:58:47 +0000 Subject: Record configure commandline. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1757 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 64cb745dc..a320c71b2 100755 --- a/configure +++ b/configure @@ -466,6 +466,7 @@ 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 -- cgit v1.2.3 From e0b3073f53dd9c0a2206932c58b5f83a87f7525b Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 9 Feb 2006 21:51:02 +0000 Subject: BIOS workarounds for kqemu git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1758 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index f3e40c240..710885076 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 7ba84d7c1..4f33a0a98 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -4,7 +4,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.130 diff -u -w -r1.130 rombios.c --- rombios.c 13 Feb 2005 08:47:30 -0000 1.130 -+++ rombios.c 6 Apr 2005 22:38:16 -0000 ++++ rombios.c 9 Feb 2006 21:49:38 -0000 @@ -8570,7 +8570,10 @@ use32 386 #define APM_PROT32 @@ -16,13 +16,41 @@ diff -u -w -r1.130 rombios.c #define APM_REAL #include "apmbios.S" +@@ -8611,6 +8614,7 @@ + mov al, #0x80 + bios32_end: + popf ++ and dword ptr[esp+4],0xfffffffc ;; reset CS.RPL for kqemu + retf + + .align 16 +@@ -8721,17 +8725,17 @@ + pci_pro_fail: + pop edi + pop esi +- sti + popf + stc ++ and dword ptr[esp+4],0xfffffffc ;; reset CS.RPL for kqemu + retf + pci_pro_ok: + xor ah, ah + pop edi + pop esi +- sti + popf + clc ++ and dword ptr[esp+4],0xfffffffc ;; reset CS.RPL for kqemu + retf + + pci_pro_select_reg: Index: apmbios.S =================================================================== RCS file: /cvsroot/bochs/bochs/bios/apmbios.S,v retrieving revision 1.1 diff -u -w -r1.1 apmbios.S --- apmbios.S 20 Jun 2004 18:27:09 -0000 1.1 -+++ apmbios.S 6 Apr 2005 22:38:16 -0000 ++++ apmbios.S 9 Feb 2006 21:49:38 -0000 @@ -1,6 +1,9 @@ // APM BIOS support for the Bochs BIOS // Copyright (C) 2004 Fabrice Bellard -- cgit v1.2.3 From 1247c5f7be51595edd622e0e0a8d26e24fb88327 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 9 Feb 2006 21:54:36 +0000 Subject: always compile 'int' traces git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1759 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index a64924222..46cbe8b8d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1122,8 +1122,7 @@ void do_interrupt_user(int intno, int is_int, int error_code, void do_interrupt(int intno, int is_int, int error_code, target_ulong next_eip, int is_hw) { -#ifdef DEBUG_PCALL - if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) { + if (loglevel & CPU_LOG_INT) { if ((env->cr[0] & CR0_PE_MASK)) { static int count; fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx, @@ -1138,8 +1137,8 @@ void do_interrupt(int intno, int is_int, int error_code, fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX); } fprintf(logfile, "\n"); -#if 0 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); +#if 0 { int i; uint8_t *ptr; @@ -1154,7 +1153,6 @@ void do_interrupt(int intno, int is_int, int error_code, count++; } } -#endif if (env->cr[0] & CR0_PE_MASK) { #if TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { -- cgit v1.2.3 From 3b7f5d479caf9b51e99da9940619db720637d5b4 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 10 Feb 2006 17:34:02 +0000 Subject: Avoid crash if -redir or -smb used without -net user. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1760 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 97eddbf49..8d1fa3747 100644 --- a/vl.c +++ b/vl.c @@ -1926,7 +1926,7 @@ static VLANClientState *slirp_vc; int slirp_can_output(void) { - return qemu_can_send_packet(slirp_vc); + return !slirp_vc || qemu_can_send_packet(slirp_vc); } void slirp_output(const uint8_t *pkt, int pkt_len) @@ -1935,6 +1935,8 @@ void slirp_output(const uint8_t *pkt, int pkt_len) printf("slirp output:\n"); hex_dump(stdout, pkt, pkt_len); #endif + if (!slirp_vc) + return; qemu_send_packet(slirp_vc, pkt, pkt_len); } -- cgit v1.2.3 From 2ae23e75045095151c3b754e7e4e36b23f053264 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Feb 2006 16:20:39 +0000 Subject: Fix Arm msr spsr bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1761 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 77c8957af..93905793a 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1033,7 +1033,7 @@ static inline void gen_mulxy(int x, int y) } /* Return the mask of PSR bits set by a MSR instruction. */ -static uint32_t msr_mask(DisasContext *s, int flags) { +static uint32_t msr_mask(DisasContext *s, int flags, int spsr) { uint32_t mask; mask = 0; @@ -1045,8 +1045,11 @@ static uint32_t msr_mask(DisasContext *s, int flags) { mask |= 0xff0000; if (flags & (1 << 3)) mask |= 0xff000000; - /* Mask out undefined bits and state bits. */ - mask &= 0xf89f03df; + /* Mask out undefined bits. */ + mask &= 0xf90f03ff; + /* Mask out state bits. */ + if (!spsr) + mask &= ~0x01000020; /* Mask out privileged bits. */ if (IS_USER(s)) mask &= 0xf80f0200; @@ -1138,8 +1141,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (shift) val = (val >> shift) | (val << (32 - shift)); gen_op_movl_T0_im(val); - if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf), - (insn & (1 << 22)) != 0)) + i = ((insn & (1 << 22)) != 0); + if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i)) goto illegal_op; } else if ((insn & 0x0f900000) == 0x01000000 && (insn & 0x00000090) != 0x00000090) { @@ -1152,11 +1155,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) if (op1 & 1) { /* PSR = reg */ gen_movl_T0_reg(s, rm); - if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf), - (op1 & 2) != 0)) + i = ((op1 & 2) != 0); + if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i)) goto illegal_op; } else { - /* reg = CPSR */ + /* reg = PSR */ rd = (insn >> 12) & 0xf; if (op1 & 2) { if (IS_USER(s)) -- cgit v1.2.3 From 242011157f0d454bf5a57541ebeba2c17611298e Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 13 Feb 2006 14:16:52 +0000 Subject: Fix Arm big-endian host bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1762 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/integratorcp.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 0e3d1e3f0..8f91b582f 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -1135,22 +1135,22 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size, p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); /* ATAG_CORE */ - *(p++) = 5; - *(p++) = 0x54410001; - *(p++) = 1; - *(p++) = 0x1000; - *(p++) = 0; + stl_raw(p++, 5); + stl_raw(p++, 0x54410001); + stl_raw(p++, 1); + stl_raw(p++, 0x1000); + stl_raw(p++, 0); /* ATAG_MEM */ - *(p++) = 4; - *(p++) = 0x54410002; - *(p++) = ram_size; - *(p++) = 0; + stl_raw(p++, 4); + stl_raw(p++, 0x54410002); + stl_raw(p++, ram_size); + stl_raw(p++, 0); if (initrd_size) { /* ATAG_INITRD2 */ - *(p++) = 4; - *(p++) = 0x54420005; - *(p++) = INITRD_LOAD_ADDR; - *(p++) = initrd_size; + stl_raw(p++, 4); + stl_raw(p++, 0x54420005); + stl_raw(p++, INITRD_LOAD_ADDR); + stl_raw(p++, initrd_size); } if (kernel_cmdline && *kernel_cmdline) { /* ATAG_CMDLINE */ @@ -1159,13 +1159,13 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size, cmdline_size = strlen(kernel_cmdline); memcpy (p + 2, kernel_cmdline, cmdline_size + 1); cmdline_size = (cmdline_size >> 2) + 1; - *(p++) = cmdline_size + 2; - *(p++) = 0x54410009; + stl_raw(p++, cmdline_size + 2); + stl_raw(p++, 0x54410009); p += cmdline_size; } /* ATAG_END */ - *(p++) = 0; - *(p++) = 0; + stl_raw(p++, 0); + stl_raw(p++, 0); } /* Board init. */ @@ -1180,6 +1180,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, icp_pic_state *pic; int kernel_size; int initrd_size; + int n; env = cpu_init(); bios_offset = ram_size + vga_ram_size; @@ -1234,7 +1235,8 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, } bootloader[5] = KERNEL_ARGS_ADDR; bootloader[6] = KERNEL_LOAD_ADDR; - memcpy(phys_ram_base, bootloader, sizeof(bootloader)); + for (n = 0; n < sizeof(bootloader) / 4; n++) + stl_raw(phys_ram_base + (n * 4), bootloader[n]); set_kernel_args(ram_size, initrd_size, kernel_cmdline); } -- cgit v1.2.3 From be9d365723740a8bf4f11d2eb3e9099c99019a57 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 19 Feb 2006 12:31:32 +0000 Subject: PL110 byteswapping fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1763 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl110_template.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/pl110_template.h b/hw/pl110_template.h index 1ab77777c..db05035b0 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -92,7 +92,7 @@ static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const u #else #define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]); #endif -#ifdef SWAP_BYTES +#ifdef SWAP_WORDS FN_8(24) FN_8(16) FN_8(8) @@ -119,7 +119,7 @@ static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const u #else #define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]); #endif -#ifdef SWAP_BYTES +#ifdef SWAP_WORDS FN_4(0, 24) FN_4(0, 16) FN_4(0, 8) @@ -146,7 +146,7 @@ static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const u #else #define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]); #endif -#ifdef SWAP_BYTES +#ifdef SWAP_WORDS FN_2(0, 24) FN_2(0, 16) FN_2(0, 8) @@ -169,7 +169,7 @@ static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const u while (width > 0) { data = *(uint32_t *)src; #define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]); -#ifdef SWAP_BYTES +#ifdef SWAP_WORDS FN(24) FN(16) FN(8) @@ -192,7 +192,7 @@ static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const unsigned int r, g, b; while (width > 0) { data = *(uint32_t *)src; -#ifdef SWAP_BYTES +#ifdef SWAP_WORDS data = bswap32(data); #endif #if 0 @@ -229,7 +229,7 @@ static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const unsigned int r, g, b; while (width > 0) { data = *(uint32_t *)src; -#ifdef SWAP_BYTES +#ifdef SWAP_WORDS r = data & 0xff; g = (data >> 8) & 0xff; b = (data >> 16) & 0xff; -- cgit v1.2.3 From 4081fccf14166c018a5694c9c0679496de69b679 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 19 Feb 2006 12:40:00 +0000 Subject: WIn32 compile fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1764 c046a42c-6fe2-441c-8c8c-71466251a162 --- tap-win32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tap-win32.c b/tap-win32.c index 32baf22da..b6056955c 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -671,7 +671,7 @@ int tap_win32_init(VLANState *vlan, const char *ifname) return -1; } - s->vc = qemu_new_vlan_client(vlan, tap_receive, s); + s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s", ifname); -- cgit v1.2.3 From 40f137e1eadbc202daf00bd6f43a997ccfb28b70 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 20 Feb 2006 00:33:36 +0000 Subject: Add Arm926 core support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1765 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 ++ hw/integratorcp.c | 37 ++++++++++++++++++++++++---- linux-user/main.c | 1 + target-arm/cpu.h | 32 +++++++++++++++++++++--- target-arm/helper.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-- target-arm/op.c | 12 ++++++++- target-arm/op_helper.c | 12 +++++---- target-arm/translate.c | 67 ++++++++++++++++++++++---------------------------- vl.c | 3 ++- vl.h | 3 ++- 10 files changed, 177 insertions(+), 55 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 3bf4b370a..3a537fc46 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -169,6 +169,8 @@ static inline TranslationBlock *tb_find_fast(void) | (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) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 8f91b582f..db73efda1 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -1173,7 +1173,7 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size, static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, uint32_t cpuid) { CPUState *env; uint32_t bios_offset; @@ -1183,6 +1183,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, int n; env = cpu_init(); + cpu_arm_set_model(env, cpuid); bios_offset = ram_size + vga_ram_size; /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ /* ??? RAM shoud repeat to fill physical memory space. */ @@ -1240,8 +1241,34 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, set_kernel_args(ram_size, initrd_size, kernel_cmdline); } -QEMUMachine integratorcp_machine = { - "integratorcp", - "ARM Integrator/CP", - integratorcp_init, +static void integratorcp926_init(int ram_size, int vga_ram_size, + int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, + initrd_filename, ARM_CPUID_ARM926); +} + +static void integratorcp1026_init(int ram_size, int vga_ram_size, + int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, + initrd_filename, ARM_CPUID_ARM1026); +} + +QEMUMachine integratorcp926_machine = { + "integratorcp926", + "ARM Integrator/CP (ARM926EJ-S)", + integratorcp926_init, +}; + +QEMUMachine integratorcp1026_machine = { + "integratorcp1026", + "ARM Integrator/CP (ARM1026EJ-S)", + integratorcp1026_init, }; diff --git a/linux-user/main.c b/linux-user/main.c index afcf4f4b1..1402fd95b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1609,6 +1609,7 @@ int main(int argc, char **argv) #elif defined(TARGET_ARM) { int i; + cpu_arm_set_model(env, ARM_CPUID_ARM1026); cpsr_write(env, regs->uregs[16], 0xffffffff); for(i = 0; i < 16; i++) { env->regs[i] = regs->uregs[i]; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 052634cd5..75a1f1314 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -72,6 +72,7 @@ typedef struct CPUARMState { /* System control coprocessor (cp15) */ struct { + uint32_t c0_cpuid; uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ uint32_t c2; /* MMU translation table base. */ @@ -85,7 +86,10 @@ typedef struct CPUARMState { uint32_t c13_fcse; /* FCSE PID. */ uint32_t c13_context; /* Context ID. */ } cp15; - + + /* Internal CPU feature flags. */ + uint32_t features; + /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; @@ -97,12 +101,11 @@ typedef struct CPUARMState { struct { float64 regs[16]; + uint32_t xregs[16]; /* We store these fpcsr fields separately for convenience. */ int vec_len; int vec_stride; - uint32_t fpscr; - /* Temporary variables if we don't have spare fp regs. */ float32 tmp0s, tmp1s; float64 tmp0d, tmp1d; @@ -187,6 +190,29 @@ enum arm_cpu_mode { ARM_CPU_MODE_SYS = 0x1f }; +/* VFP system registers. */ +#define ARM_VFP_FPSID 0 +#define ARM_VFP_FPSCR 1 +#define ARM_VFP_FPEXC 8 +#define ARM_VFP_FPINST 9 +#define ARM_VFP_FPINST2 10 + + +enum arm_features { + ARM_FEATURE_VFP, + ARM_FEATURE_AUXCR /* ARM1026 Auxiliary control register. */ +}; + +static inline int arm_feature(CPUARMState *env, int feature) +{ + return (env->features & (1u << feature)) != 0; +} + +void cpu_arm_set_model(CPUARMState *env, uint32_t id); + +#define ARM_CPUID_ARM1026 0x4106a262 +#define ARM_CPUID_ARM926 0x41069265 + #if defined(CONFIG_USER_ONLY) #define TARGET_PAGE_BITS 12 #else diff --git a/target-arm/helper.c b/target-arm/helper.c index 5804df826..d0cd6d8e5 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5,6 +5,61 @@ #include "cpu.h" #include "exec-all.h" +void cpu_reset(CPUARMState *env) +{ +#if defined (CONFIG_USER_ONLY) + env->uncached_cpsr = ARM_CPU_MODE_USR; + env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30; +#else + /* SVC mode with interrupts disabled. */ + env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + env->vfp.xregs[ARM_VFP_FPEXC] = 0; +#endif + env->regs[15] = 0; +} + +CPUARMState *cpu_arm_init(void) +{ + CPUARMState *env; + + env = qemu_mallocz(sizeof(CPUARMState)); + if (!env) + return NULL; + cpu_exec_init(env); + cpu_reset(env); + tlb_flush(env, 1); + return env; +} + +static inline void set_feature(CPUARMState *env, int feature) +{ + env->features |= 1u << feature; +} + +void cpu_arm_set_model(CPUARMState *env, uint32_t id) +{ + env->cp15.c0_cpuid = id; + switch (id) { + case ARM_CPUID_ARM926: + set_feature(env, ARM_FEATURE_VFP); + env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; + break; + case ARM_CPUID_ARM1026: + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; + break; + default: + cpu_abort(env, "Bad CPU ID: %x\n", id); + break; + } +} + +void cpu_arm_close(CPUARMState *env) +{ + free(env); +} + #if defined(CONFIG_USER_ONLY) void do_interrupt (CPUState *env) @@ -469,7 +524,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 0: /* ID codes. */ switch (op2) { default: /* Device ID. */ - return 0x4106a262; + return env->cp15.c0_cpuid; case 1: /* Cache Type. */ return 0x1dd20d2; case 2: /* TCM status. */ @@ -480,7 +535,9 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 0: /* Control register. */ return env->cp15.c1_sys; case 1: /* Auxiliary control register. */ - return 1; + if (arm_feature(env, ARM_FEATURE_AUXCR)) + return 1; + goto bad_reg; case 2: /* Coprocessor access register. */ return env->cp15.c1_coproc; default: @@ -506,6 +563,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 0: return env->cp15.c6_data; case 1: + /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't + do any harm. */ return env->cp15.c6_insn; default: goto bad_reg; diff --git a/target-arm/op.c b/target-arm/op.c index f06b06b90..619066d29 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -1094,7 +1094,7 @@ void OPPROTO op_vfp_movl_T0_fpscr(void) void OPPROTO op_vfp_movl_T0_fpscr_flags(void) { - T0 = env->vfp.fpscr & (0xf << 28); + T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28); } void OPPROTO op_vfp_movl_fpscr_T0(void) @@ -1102,6 +1102,16 @@ void OPPROTO op_vfp_movl_fpscr_T0(void) do_vfp_set_fpscr(); } +void OPPROTO op_vfp_movl_T0_xreg(void) +{ + T0 = env->vfp.xregs[PARAM1]; +} + +void OPPROTO op_vfp_movl_xreg_T0(void) +{ + env->vfp.xregs[PARAM1] = T0; +} + /* Move between FT0s to T0 */ void OPPROTO op_vfp_mrs(void) { diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index c075b53fc..af5c61d0b 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -72,7 +72,8 @@ void do_vfp_cmp##p(void) \ case 1: flags = 0x2; break;\ default: case 2: flags = 0x3; break;\ }\ - env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ FORCE_RET(); \ }\ \ @@ -85,7 +86,8 @@ void do_vfp_cmpe##p(void) \ case 1: flags = 0x2; break;\ default: case 2: flags = 0x3; break;\ }\ - env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ FORCE_RET(); \ } DO_VFP_cmp(s, 32) @@ -133,8 +135,8 @@ void do_vfp_set_fpscr(void) int i; uint32_t changed; - changed = env->vfp.fpscr; - env->vfp.fpscr = (T0 & 0xffc8ffff); + changed = env->vfp.xregs[ARM_VFP_FPSCR]; + env->vfp.xregs[ARM_VFP_FPSCR] = (T0 & 0xffc8ffff); env->vfp.vec_len = (T0 >> 16) & 7; env->vfp.vec_stride = (T0 >> 20) & 3; @@ -167,7 +169,7 @@ void do_vfp_get_fpscr(void) { int i; - T0 = (env->vfp.fpscr & 0xffc8ffff) | (env->vfp.vec_len << 16) + T0 = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) | (env->vfp.vec_len << 16) | (env->vfp.vec_stride << 20); i = get_float_exception_flags(&env->vfp.fp_status); T0 |= vfp_exceptbits_from_host(i); diff --git a/target-arm/translate.c b/target-arm/translate.c index 93905793a..1f8a4853b 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -526,6 +526,17 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask; int dp, veclen; + if (!arm_feature(env, ARM_FEATURE_VFP)) + return 1; + + if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) { + /* VFP disabled. Only allow fmxr/fmrx to/from fpexc and fpsid. */ + if ((insn & 0x0fe00fff) != 0x0ee00a10) + return 1; + rn = (insn >> 16) & 0xf; + if (rn != 0 && rn != 8) + return 1; + } dp = ((insn & 0xf00) == 0xb00); switch ((insn >> 24) & 0xf) { case 0xe: @@ -563,11 +574,15 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) /* vfp->arm */ if (insn & (1 << 21)) { /* system register */ + rn >>= 1; switch (rn) { - case 0: /* fpsid */ - n = 0x0091A0000; + case ARM_VFP_FPSID: + case ARM_VFP_FPEXC: + case ARM_VFP_FPINST: + case ARM_VFP_FPINST2: + gen_op_vfp_movl_T0_xreg(rn); break; - case 2: /* fpscr */ + case ARM_VFP_FPSCR: if (rd == 15) gen_op_vfp_movl_T0_fpscr_flags(); else @@ -589,17 +604,24 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) /* arm->vfp */ gen_movl_T0_reg(s, rd); if (insn & (1 << 21)) { + rn >>= 1; /* system register */ switch (rn) { - case 0: /* fpsid */ + case ARM_VFP_FPSID: /* Writes are ignored. */ break; - case 2: /* fpscr */ + case ARM_VFP_FPSCR: gen_op_vfp_movl_fpscr_T0(); - /* This could change vector settings, so jump to - the next instuction. */ gen_lookup_tb(s); break; + case ARM_VFP_FPEXC: + gen_op_vfp_movl_xreg_T0(rn); + gen_lookup_tb(s); + break; + case ARM_VFP_FPINST: + case ARM_VFP_FPINST2: + gen_op_vfp_movl_xreg_T0(rn); + break; default: return 1; } @@ -2456,35 +2478,6 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } -void cpu_reset(CPUARMState *env) -{ -#if defined (CONFIG_USER_ONLY) - env->uncached_cpsr = ARM_CPU_MODE_USR; -#else - /* SVC mode with interrupts disabled. */ - env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; -#endif - env->regs[15] = 0; -} - -CPUARMState *cpu_arm_init(void) -{ - CPUARMState *env; - - env = qemu_mallocz(sizeof(CPUARMState)); - if (!env) - return NULL; - cpu_exec_init(env); - cpu_reset(env); - tlb_flush(env, 1); - return env; -} - -void cpu_arm_close(CPUARMState *env) -{ - free(env); -} - static const char *cpu_mode_names[16] = { "usr", "fiq", "irq", "svc", "???", "???", "???", "abt", "???", "???", "???", "und", "???", "???", "???", "sys" @@ -2528,6 +2521,6 @@ void cpu_dump_state(CPUState *env, FILE *f, i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower, d.d); } - cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr); + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); } diff --git a/vl.c b/vl.c index 8d1fa3747..e0406eae9 100644 --- a/vl.c +++ b/vl.c @@ -4435,7 +4435,8 @@ void register_machines(void) qemu_register_machine(&sun4m_machine); #endif #elif defined(TARGET_ARM) - qemu_register_machine(&integratorcp_machine); + qemu_register_machine(&integratorcp926_machine); + qemu_register_machine(&integratorcp1026_machine); #else #error unsupported CPU #endif diff --git a/vl.h b/vl.h index 4d215e7dd..ada078819 100644 --- a/vl.h +++ b/vl.h @@ -960,7 +960,8 @@ void do_usb_del(const char *devname); void usb_info(void); /* integratorcp.c */ -extern QEMUMachine integratorcp_machine; +extern QEMUMachine integratorcp926_machine; +extern QEMUMachine integratorcp1026_machine; /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); -- cgit v1.2.3 From ed96ca357123afb55d910be6ff72a5100c73c2dd Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 20 Feb 2006 00:35:00 +0000 Subject: Update Arm docs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1766 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index eafdb806f..114e2cec3 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -47,7 +47,7 @@ For system emulation, the following hardware targets are supported: @item Sun4m (32-bit Sparc processor) @item Sun4u (64-bit Sparc processor, in progress) @item Malta board (32-bit MIPS processor) -@item ARM Integrator/CP (ARM1026E processor) +@item ARM Integrator/CP (ARM926E or 1026E processor) @end itemize For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported. @@ -1383,7 +1383,7 @@ devices: @itemize @minus @item -ARM1026E CPU +ARM926E or ARM1026E CPU @item Two PL011 UARTs @item -- cgit v1.2.3 From 023e9351d0b8d2643058caff595ea4bc8d6003fa Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 2 Mar 2006 21:52:18 +0000 Subject: suppressed invalid test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1767 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 3 --- 1 file changed, 3 deletions(-) diff --git a/configure b/configure index a320c71b2..58759337a 100755 --- a/configure +++ b/configure @@ -692,9 +692,6 @@ elif test "$target_cpu" = "x86_64" ; then 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 - if test $kqemu_profile = "yes" ; then - echo "#define CONFIG_KQEMU_PROFILE 1" >> $config_h - fi fi elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then echo "TARGET_ARCH=mips" >> $config_mak -- cgit v1.2.3 From e10c2bfb73d7f9e9f7bf29a77e30b8260c1506bc Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 2 Mar 2006 23:58:13 +0000 Subject: Add missing return statement. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1768 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl110.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/pl110.c b/hw/pl110.c index 5a6638cbe..2506dfd39 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -321,6 +321,7 @@ static void pl110_write(void *opaque, target_phys_addr_t offset, n = (offset - 0x200) >> 2; s->raw_pallette[(offset - 0x200) >> 2] = val; pl110_update_pallette(s, n); + return; } switch (offset >> 2) { case 0: /* LCDTiming0 */ -- cgit v1.2.3 From 9540a78b90c9c0240d9054b5b80de8d1a16a489e Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 3 Mar 2006 01:54:40 +0000 Subject: x86_64 stack alignment fixes - x86_64 32 bit syscall fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1769 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 46cbe8b8d..7bd545e81 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -24,7 +24,8 @@ #if 0 #define raise_exception_err(a, b)\ do {\ - fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ + if (logfile)\ + fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ (raise_exception_err)(a, b);\ } while (0) #endif @@ -215,11 +216,11 @@ static void tss_load_seg(int seg_reg, int selector) if (seg_reg == R_CS) { if (!(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0A_TSS, selector & 0xfffc); + /* XXX: is it correct ? */ if (dpl != rpl) raise_exception_err(EXCP0A_TSS, selector & 0xfffc); if ((e2 & DESC_C_MASK) && dpl > rpl) raise_exception_err(EXCP0A_TSS, selector & 0xfffc); - } else if (seg_reg == R_SS) { /* SS must be writable data */ if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) @@ -890,6 +891,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, esp = get_rsp_from_tss(ist + 3); else esp = get_rsp_from_tss(dpl); + esp &= ~0xfLL; /* align stack */ ss = 0; new_stack = 1; } else if ((e2 & DESC_C_MASK) || dpl == cpl) { @@ -897,7 +899,11 @@ static void do_interrupt64(int intno, int is_int, int error_code, if (env->eflags & VM_MASK) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; - esp = ESP & ~0xf; /* align stack */ + if (ist != 0) + esp = get_rsp_from_tss(ist + 3); + else + esp = ESP; + esp &= ~0xfLL; /* align stack */ dpl = cpl; } else { raise_exception_err(EXCP0D_GPF, selector & 0xfffc); @@ -946,8 +952,12 @@ void helper_syscall(int next_eip_addend) selector = (env->star >> 32) & 0xffff; #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { + int code64; + ECX = env->eip + next_eip_addend; env->regs[11] = compute_eflags(); + + code64 = env->hflags & HF_CS64_MASK; cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, @@ -961,7 +971,7 @@ void helper_syscall(int next_eip_addend) DESC_S_MASK | DESC_W_MASK | DESC_A_MASK); env->eflags &= ~env->fmask; - if (env->hflags & HF_CS64_MASK) + if (code64) env->eip = env->lstar; else env->eip = env->cstar; -- cgit v1.2.3 From 647c593038ea677c11eafa14a7e234d88ea67c90 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 14:46:59 +0000 Subject: Add missing FORCE_RET() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1770 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-i386/op.c b/target-i386/op.c index 137f5726b..93cc3c42e 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1032,6 +1032,7 @@ void OPPROTO op_aaa(void) } EAX = (EAX & ~0xffff) | al | (ah << 8); CC_SRC = eflags; + FORCE_RET(); } void OPPROTO op_aas(void) @@ -1056,6 +1057,7 @@ void OPPROTO op_aas(void) } EAX = (EAX & ~0xffff) | al | (ah << 8); CC_SRC = eflags; + FORCE_RET(); } void OPPROTO op_daa(void) @@ -1083,6 +1085,7 @@ void OPPROTO op_daa(void) eflags |= parity_table[al]; /* pf */ eflags |= (al & 0x80); /* sf */ CC_SRC = eflags; + FORCE_RET(); } void OPPROTO op_das(void) @@ -1113,6 +1116,7 @@ void OPPROTO op_das(void) eflags |= parity_table[al]; /* pf */ eflags |= (al & 0x80); /* sf */ CC_SRC = eflags; + FORCE_RET(); } /* segment handling */ -- cgit v1.2.3 From 38260998a207df693747877e8d96aa6c68ea29c6 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 14:51:13 +0000 Subject: mipsel configure support (Thiemo Seufer). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1771 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + Makefile | 1 + configure | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.cvsignore b/.cvsignore index 9ea66ba27..2627cd0bd 100644 --- a/.cvsignore +++ b/.cvsignore @@ -22,5 +22,6 @@ x86_64-softmmu sparc64-user sparc64-softmmu mips-softmmu +mipsel-softmmu mips-user mipsel-user diff --git a/Makefile b/Makefile index e69cf47da..bcc2e07d4 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,7 @@ tarbin: $(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 \ diff --git a/configure b/configure index 58759337a..a0bc4d731 100755 --- a/configure +++ b/configure @@ -232,7 +232,7 @@ fi if test -z "$target_list" ; then # these targets are portable - target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu arm-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu" # the following are Linux specific if [ "$linux" = "yes" ] ; then target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list" -- cgit v1.2.3 From d2ec1774eb53ef4bf8bcc6686245739317b6315d Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 15:00:08 +0000 Subject: Add missing function prototype. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1772 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-mips/exec.h b/target-mips/exec.h index ed9094c7e..2cd1e02c4 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -81,6 +81,8 @@ uint32_t do_swr_kernel (uint32_t); #endif void do_pmon (int function); +void dump_sc (void); + int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); void do_interrupt (CPUState *env); -- cgit v1.2.3 From 6d6f7c288dbd892fb85028cb7a7fe8812ac11135 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 15:35:30 +0000 Subject: Improved terminal emulation (Piotr Esden-Tempski). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1773 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 316 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 268 insertions(+), 48 deletions(-) diff --git a/console.c b/console.c index b99a3bf18..d1eb40655 100644 --- a/console.c +++ b/console.c @@ -23,16 +23,26 @@ */ #include "vl.h" +//#define DEBUG_CONSOLE #define DEFAULT_BACKSCROLL 512 #define MAX_CONSOLES 12 #define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) #define RGB(r, g, b) RGBA(r, g, b, 0xff) +typedef struct 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; - uint8_t bgcol:4; - uint8_t fgcol:4; + TextAttributes t_attrib; } TextCell; #define MAX_ESC_PARAMS 3 @@ -43,6 +53,7 @@ enum TTYState { TTY_STATE_CSI, }; + struct TextConsole { int text_console; /* true if text console */ DisplayState *ds; @@ -51,11 +62,11 @@ struct TextConsole { int height; int total_height; int backscroll_height; - int fgcol; - int bgcol; 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; @@ -221,17 +232,40 @@ static const uint32_t dmask4[4] = { PAT(0xffffffff), }; -static uint32_t color_table[8]; - -static const uint32_t color_table_rgb[8] = { - RGB(0x00, 0x00, 0x00), - RGB(0xff, 0x00, 0x00), - RGB(0x00, 0xff, 0x00), - RGB(0xff, 0xff, 0x00), - RGB(0x00, 0x00, 0xff), - RGB(0xff, 0x00, 0xff), - RGB(0x00, 0xff, 0xff), - RGB(0xff, 0xff, 0xff), +static 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 */ + RGB(0x00, 0x00, 0x00), /* black */ + RGB(0xaa, 0x00, 0x00), /* red */ + RGB(0x00, 0xaa, 0x00), /* green */ + RGB(0xaa, 0xaa, 0x00), /* yellow */ + RGB(0x00, 0x00, 0xaa), /* blue */ + RGB(0xaa, 0x00, 0xaa), /* magenta */ + RGB(0x00, 0xaa, 0xaa), /* cyan */ + RGB(0xaa, 0xaa, 0xaa), /* white */ + }, + { /* bright */ + RGB(0x00, 0x00, 0x00), /* black */ + RGB(0xff, 0x00, 0x00), /* red */ + RGB(0x00, 0xff, 0x00), /* green */ + RGB(0xff, 0xff, 0x00), /* yellow */ + RGB(0x00, 0x00, 0xff), /* blue */ + RGB(0xff, 0x00, 0xff), /* magenta */ + RGB(0x00, 0xff, 0xff), /* cyan */ + RGB(0xff, 0xff, 0xff), /* white */ + } }; static inline unsigned int col_expand(DisplayState *ds, unsigned int col) @@ -251,14 +285,60 @@ static inline unsigned int col_expand(DisplayState *ds, unsigned int col) 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, - unsigned int fgcol, unsigned int bgcol) + 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 + @@ -270,6 +350,10 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 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; @@ -279,6 +363,10 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 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; @@ -289,6 +377,9 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 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; @@ -327,8 +418,7 @@ static void text_console_resize(TextConsole *s) } for(x = w1; x < s->width; x++) { c->ch = ' '; - c->fgcol = 7; - c->bgcol = 0; + c->t_attrib = s->t_attrib_default; c++; } } @@ -349,7 +439,7 @@ static void update_xy(TextConsole *s, int x, int y) if (y2 < s->height) { c = &s->cells[y1 * s->width + x]; vga_putcharxy(s->ds, x, y2, c->ch, - color_table[c->fgcol], color_table[c->bgcol]); + &(c->t_attrib)); dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, FONT_WIDTH, FONT_HEIGHT); } @@ -369,11 +459,12 @@ static void console_show_cursor(TextConsole *s, int show) if (y < s->height) { c = &s->cells[y1 * s->width + s->x]; if (show) { - vga_putcharxy(s->ds, s->x, y, c->ch, - color_table[0], color_table[7]); + 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, - color_table[c->fgcol], color_table[c->bgcol]); + &(c->t_attrib)); } dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, FONT_WIDTH, FONT_HEIGHT); @@ -390,13 +481,13 @@ static void console_refresh(TextConsole *s) return; vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, - color_table[0]); + 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, - color_table[c->fgcol], color_table[c->bgcol]); + &(c->t_attrib)); c++; } if (++y1 == s->total_height) @@ -449,7 +540,7 @@ static void console_put_lf(TextConsole *s) 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; @@ -462,8 +553,7 @@ static void console_put_lf(TextConsole *s) c = &s->cells[y1 * s->width]; for(x = 0; x < s->width; x++) { c->ch = ' '; - c->fgcol = s->fgcol; - c->bgcol = s->bgcol; + c->t_attrib = s->t_attrib_default; c++; } if (s == active_console && s->y_displayed == s->y_base) { @@ -472,13 +562,114 @@ static void console_put_lf(TextConsole *s) (s->height - 1) * FONT_HEIGHT); vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT, s->width * FONT_WIDTH, FONT_HEIGHT, - color_table[s->bgcol]); + 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; inb_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; @@ -487,21 +678,38 @@ static void console_putchar(TextConsole *s, int ch) switch(s->state) { case TTY_STATE_NORM: switch(ch) { - case '\r': + case '\r': /* carriage return */ s->x = 0; break; - case '\n': + case '\n': /* newline */ console_put_lf(s); break; - case 27: + case '\b': /* backspace */ + if(s->x > 0) s->x--; + y1 = (s->y_base + s->y) % s->total_height; + c = &s->cells[y1 * s->width + s->x]; + c->ch = ' '; + c->t_attrib = s->t_attrib; + update_xy(s, s->x, s->y); + break; + case '\t': /* tabspace */ + if (s->x + (8 - (s->x % 8)) > s->width) { + 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->fgcol = s->fgcol; - c->bgcol = s->bgcol; + c->t_attrib = s->t_attrib; update_xy(s, s->x, s->y); s->x++; if (s->x >= s->width) @@ -509,7 +717,7 @@ static void console_putchar(TextConsole *s, int ch) break; } break; - case TTY_STATE_ESC: + case TTY_STATE_ESC: /* check if it is a terminal escape sequence */ if (ch == '[') { for(i=0;iesc_params[i] = 0; @@ -519,7 +727,7 @@ static void console_putchar(TextConsole *s, int ch) s->state = TTY_STATE_NORM; } break; - case TTY_STATE_CSI: + 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] = @@ -545,8 +753,7 @@ static void console_putchar(TextConsole *s, int ch) for(x = s->x; x < s->width; x++) { c = &s->cells[y1 * s->width + x]; c->ch = ' '; - c->fgcol = s->fgcol; - c->bgcol = s->bgcol; + c->t_attrib = s->t_attrib_default; c++; update_xy(s, x, s->y); } @@ -554,6 +761,7 @@ static void console_putchar(TextConsole *s, int ch) default: break; } + console_handle_escape(s); break; } } @@ -562,7 +770,7 @@ static void console_putchar(TextConsole *s, int ch) void console_select(unsigned int index) { TextConsole *s; - + if (index >= MAX_CONSOLES) return; s = consoles[index]; @@ -571,10 +779,10 @@ void console_select(unsigned int index) 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; + s->g_width = s->ds->width; + s->g_height = s->ds->height; text_console_resize(s); - } + } console_refresh(s); } } @@ -692,9 +900,9 @@ CharDriverState *text_console_init(DisplayState *ds) { CharDriverState *chr; TextConsole *s; - int i; + int i,j; static int color_inited; - + chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; @@ -711,9 +919,11 @@ CharDriverState *text_console_init(DisplayState *ds) if (!color_inited) { color_inited = 1; - for(i = 0; i < 8; i++) { - color_table[i] = col_expand(s->ds, - vga_get_color(s->ds, color_table_rgb[i])); + 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; @@ -721,10 +931,20 @@ CharDriverState *text_console_init(DisplayState *ds) s->total_height = DEFAULT_BACKSCROLL; s->x = 0; s->y = 0; - s->fgcol = 7; - s->bgcol = 0; s->g_width = s->ds->width; s->g_height = s->ds->height; + + /* 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); return chr; -- cgit v1.2.3 From 98c1b82b6cf96d650bf07a6a2bf0414907924ffe Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 16:20:36 +0000 Subject: e bitfields in mips TLB structures (Thiemo Seufer). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1774 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 13 ++++++++----- target-mips/helper.c | 11 +++++------ target-mips/op_helper.c | 52 +++++++++++++++++++++---------------------------- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 5e4b91dcc..809c586a0 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -21,11 +21,14 @@ struct tlb_t { target_ulong VPN; target_ulong end; target_ulong end2; - uint8_t ASID; - uint8_t G; - uint8_t C[2]; - uint8_t V[2]; - uint8_t D[2]; + uint_fast8_t ASID; + uint_fast16_t G:1; + uint_fast16_t C0:3; + uint_fast16_t C1:3; + uint_fast16_t V0:1; + uint_fast16_t V1:1; + uint_fast16_t D0:1; + uint_fast16_t D1:1; target_ulong PFN[2]; }; #endif diff --git a/target-mips/helper.c b/target-mips/helper.c index 8b4deb3dd..62c53a0bf 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -50,17 +50,16 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, /* TLB match */ n = (address >> 12) & 1; /* Check access rights */ - if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) { + if (!(n ? tlb->V1 : tlb->V0)) + return -3; + if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { *physical = tlb->PFN[n] | (address & 0xFFF); *prot = PAGE_READ; - if (tlb->D[n]) + if (n ? tlb->D1 : tlb->D0) *prot |= PAGE_WRITE; return 0; - } else if (!(tlb->V[n] & 2)) { - return -3; - } else { - return -4; } + return -4; } } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index be207b9bb..b1a308e67 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -535,30 +535,22 @@ void do_mtc0 (int reg, int sel) /* TLB management */ #if defined(MIPS_USES_R4K_TLB) -static void invalidate_tb (int idx) +static void invalidate_tlb (int idx) { tlb_t *tlb; - target_ulong addr, end; + target_ulong addr; tlb = &env->tlb[idx]; - if (tlb->V[0]) { - addr = tlb->PFN[0]; - end = addr + (tlb->end - tlb->VPN); - tb_invalidate_page_range(addr, end); - /* FIXME: Might be faster to just invalidate the whole "tlb" here - and refill it on demand from our simulated TLB. */ + if (tlb->V0) { + tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN); addr = tlb->VPN; while (addr < tlb->end) { tlb_flush_page (env, addr); addr += TARGET_PAGE_SIZE; } } - if (tlb->V[1]) { - addr = tlb->PFN[1]; - end = addr + (tlb->end - tlb->VPN); - tb_invalidate_page_range(addr, end); - /* FIXME: Might be faster to just invalidate the whole "tlb" here - and refill it on demand from our simulated TLB. */ + if (tlb->V1) { + tb_invalidate_page_range(tlb->PFN[1], tlb->end2 - tlb->end); addr = tlb->end; while (addr < tlb->end2) { tlb_flush_page (env, addr); @@ -567,7 +559,7 @@ static void invalidate_tb (int idx) } } -static void fill_tb (int idx) +static void fill_tlb (int idx) { tlb_t *tlb; int size; @@ -575,19 +567,19 @@ static void fill_tb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb[idx]; tlb->VPN = env->CP0_EntryHi & 0xFFFFE000; - tlb->ASID = env->CP0_EntryHi & 0x000000FF; + tlb->ASID = env->CP0_EntryHi & 0xFF; size = env->CP0_PageMask >> 13; size = 4 * (size + 1); tlb->end = tlb->VPN + (1 << (8 + size)); tlb->end2 = tlb->end + (1 << (8 + size)); tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; - tlb->V[0] = env->CP0_EntryLo0 & 2; - tlb->D[0] = env->CP0_EntryLo0 & 4; - tlb->C[0] = (env->CP0_EntryLo0 >> 3) & 0x7; + tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; + tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; + tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12; - tlb->V[1] = env->CP0_EntryLo1 & 2; - tlb->D[1] = env->CP0_EntryLo1 & 4; - tlb->C[1] = (env->CP0_EntryLo1 >> 3) & 0x7; + tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; + tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; + tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; } @@ -595,16 +587,16 @@ void do_tlbwi (void) { /* Wildly undefined effects for CP0_index containing a too high value and MIPS_TLB_NB not being a power of two. But so does real silicon. */ - invalidate_tb(env->CP0_index & (MIPS_TLB_NB - 1)); - fill_tb(env->CP0_index & (MIPS_TLB_NB - 1)); + invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); + fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); } void do_tlbwr (void) { int r = cpu_mips_get_random(env); - invalidate_tb(r); - fill_tb(r); + invalidate_tlb(r); + fill_tlb(r); } void do_tlbp (void) @@ -645,10 +637,10 @@ void do_tlbr (void) env->CP0_EntryHi = tlb->VPN | tlb->ASID; size = (tlb->end - tlb->VPN) >> 12; env->CP0_PageMask = (size - 1) << 13; - env->CP0_EntryLo0 = tlb->V[0] | tlb->D[0] | (tlb->C[0] << 3) | - (tlb->PFN[0] >> 6); - env->CP0_EntryLo1 = tlb->V[1] | tlb->D[1] | (tlb->C[1] << 3) | - (tlb->PFN[1] >> 6); + env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) + | (tlb->C0 << 3) | (tlb->PFN[0] >> 6); + env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) + | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); } #endif -- cgit v1.2.3 From 56b194039eb3a2a9d239662c004367c726a5ab4f Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 16:23:39 +0000 Subject: Rename MIPS_HFLAG(S)_TMASK (Thiemo Seufer). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1775 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- target-mips/cpu.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 3a537fc46..4741a2526 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -187,7 +187,7 @@ static inline TranslationBlock *tb_find_fast(void) cs_base = 0; pc = env->nip; #elif defined(TARGET_MIPS) - flags = env->hflags & (MIPS_HFLAGS_TMASK | MIPS_HFLAG_BMASK); + flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK); cs_base = 0; pc = env->PC; #else diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 809c586a0..af5a97e68 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -149,7 +149,7 @@ struct CPUMIPSState { int user_mode_only; /* user mode only simulation */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAGS_TMASK 0x00FF +#define MIPS_HFLAG_TMASK 0x007F #define MIPS_HFLAG_MODE 0x001F /* execution modes */ #define MIPS_HFLAG_UM 0x0001 /* user mode */ #define MIPS_HFLAG_ERL 0x0002 /* Error mode */ -- cgit v1.2.3 From 4e9aec746e8d87fbe8805b881d6dae898a75372b Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 16:29:14 +0000 Subject: Sparcf ESP dma fixes (Blue Swirl). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1776 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 9603b74b1..c0acbe678 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -1,7 +1,7 @@ /* * QEMU ESP emulation * - * Copyright (c) 2005 Fabrice Bellard + * Copyright (c) 2005-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 @@ -38,13 +38,18 @@ do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level) #define ESPDMA_REGS 4 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) #define ESP_MAXREG 0x3f -#define TI_BUFSZ 65536 +#define TI_BUFSZ 1024*1024 // XXX #define DMA_VER 0xa0000000 #define DMA_INTR 1 #define DMA_INTREN 0x10 #define DMA_LOADED 0x04000000 +typedef struct ESPState ESPState; -typedef struct ESPState { +typedef int ESPDMAFunc(ESPState *s, + target_phys_addr_t phys_addr, + int transfer_size1); + +struct ESPState { BlockDriverState **bd; uint8_t rregs[ESP_MAXREG]; uint8_t wregs[ESP_MAXREG]; @@ -55,7 +60,10 @@ typedef struct ESPState { int ti_dir; uint8_t ti_buf[TI_BUFSZ]; int dma; -} ESPState; + ESPDMAFunc *dma_cb; + int64_t offset, len; + int target; +}; #define STAT_DO 0x00 #define STAT_DI 0x01 @@ -217,6 +225,19 @@ static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, return len; } +static int esp_write_dma_cb(ESPState *s, + target_phys_addr_t phys_addr, + int transfer_size1) +{ + DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n", + s->offset, s->len, s->ti_size, transfer_size1); + bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len); + s->offset = 0; + s->len = 0; + s->target = 0; + return 0; +} + static void handle_satn(ESPState *s) { uint8_t buf[32]; @@ -309,6 +330,9 @@ static void handle_satn(ESPState *s) s->ti_size = len * 512; } DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); + if (s->ti_size > TI_BUFSZ) { + DPRINTF("size too large %d\n", s->ti_size); + } bdrv_read(s->bd[target], offset, s->ti_buf, len); // XXX error handling s->ti_dir = 1; @@ -328,7 +352,13 @@ static void handle_satn(ESPState *s) s->ti_size = len * 512; } DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); - bdrv_write(s->bd[target], offset, s->ti_buf, len); + if (s->ti_size > TI_BUFSZ) { + DPRINTF("size too large %d\n", s->ti_size); + } + s->dma_cb = esp_write_dma_cb; + s->offset = offset; + s->len = len; + s->target = target; // XXX error handling s->ti_dir = 0; break; @@ -427,6 +457,10 @@ static void handle_ti(ESPState *s) else cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); } + if (s->dma_cb) { + s->dma_cb(s, s->espdmaregs[1], dmalen); + s->dma_cb = NULL; + } s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS; s->rregs[6] = 0; @@ -444,8 +478,15 @@ static void esp_reset(void *opaque) { ESPState *s = opaque; memset(s->rregs, 0, ESP_MAXREG); + memset(s->wregs, 0, ESP_MAXREG); s->rregs[0x0e] = 0x4; // Indicate fas100a memset(s->espdmaregs, 0, ESPDMA_REGS * 4); + s->ti_size = 0; + s->ti_rptr = 0; + s->ti_wptr = 0; + s->ti_dir = 0; + s->dma = 0; + s->dma_cb = NULL; } static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) -- cgit v1.2.3 From ecd78a0ac7a7f5f37638a1847391206bb04c48e1 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 16:35:30 +0000 Subject: Clear MIPS_HFLAG_BMASK for ErrorEPC (Thiemo Seufer). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1777 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-mips/helper.c b/target-mips/helper.c index 62c53a0bf..752ee7275 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -326,6 +326,7 @@ void do_interrupt (CPUState *env) * come back to the jump */ env->CP0_ErrorEPC = env->PC - 4; + env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_ErrorEPC = env->PC; } -- cgit v1.2.3 From 09c56b842ee3a1e5efbf98540408cdcafe451ab0 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 16:39:23 +0000 Subject: Avoid flushing of global TLB entries for differing ASIDs (Thiemo Seufer). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1778 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index b1a308e67..9066ce7d1 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -625,13 +625,14 @@ void do_tlbp (void) void do_tlbr (void) { tlb_t *tlb; + uint8_t ASID; int size; + ASID = env->CP0_EntryHi & 0xFF; tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; /* If this will change the current ASID, flush qemu's TLB. */ - /* FIXME: Could avoid flushing things which match global entries... */ - if ((env->CP0_EntryHi & 0xFF) != tlb->ASID) + if (ASID != tlb->ASID && tlb->G != 1) tlb_flush (env, 1); env->CP0_EntryHi = tlb->VPN | tlb->ASID; -- cgit v1.2.3 From 38ca0f6deebe286a521d6dfaf6583e9216b441ee Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 18:03:38 +0000 Subject: Tweak UHCI device settings. Ignore host root hubs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1779 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 5 ++++- usb-linux.c | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 732b76a81..e93db5716 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -654,6 +654,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) pci_conf[0x0b] = 0x0c; pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 4; // interrupt pin 3 + pci_conf[0x60] = 0x10; // release number for(i = 0; i < NB_PORTS; i++) { port = &s->ports[i]; @@ -666,6 +667,8 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) uhci_reset(s); - pci_register_io_region(&s->dev, 0, 0x20, + /* Use region 4 for consistency with real hardware. BSD guests seem + to rely on this. */ + pci_register_io_region(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); } diff --git a/usb-linux.c b/usb-linux.c index 216ac20f8..9cd543d71 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -278,7 +278,8 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) if (strlen(line) > 0) line[strlen(line) - 1] = '\0'; if (line[0] == 'T' && line[1] == ':') { - if (device_count) { + if (device_count && (vendor_id || product_id)) { + /* New device. Add the previously discovered device. */ ret = func(opaque, bus_num, addr, class_id, vendor_id, product_id, product_name, speed); if (ret) @@ -321,7 +322,8 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) } fail: ; } - if (device_count) { + if (device_count && (vendor_id || product_id)) { + /* Add the last device. */ ret = func(opaque, bus_num, addr, class_id, vendor_id, product_id, product_name, speed); } -- cgit v1.2.3 From 5b31187812694ef575c20fc3fe3123685a306fde Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 20:07:45 +0000 Subject: Make sure gui_key_modifier_pressed is cleared correctly. Use correct event fields for SDL_ACTIVEEVENT. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1780 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdl.c b/sdl.c index 9c7afd907..d53f3e957 100644 --- a/sdl.c +++ b/sdl.c @@ -404,6 +404,7 @@ static void sdl_refresh(DisplayState *ds) mod_state = (ev->key.keysym.mod & gui_grab_code); if (!mod_state) { if (gui_key_modifier_pressed) { + gui_key_modifier_pressed = 0; if (gui_keysym == 0) { /* exit/enter grab if pressing Ctrl-Alt */ if (!gui_grab) @@ -415,7 +416,6 @@ static void sdl_refresh(DisplayState *ds) reset_keys(); break; } - gui_key_modifier_pressed = 0; gui_keysym = 0; } } @@ -456,8 +456,8 @@ static void sdl_refresh(DisplayState *ds) } break; case SDL_ACTIVEEVENT: - if (gui_grab && (ev->active.gain & SDL_ACTIVEEVENTMASK) == 0 && - !gui_fullscreen_initial_grab) { + if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS && + !ev->active.gain && !gui_fullscreen_initial_grab) { sdl_grab_end(); } break; -- cgit v1.2.3 From ce5c37c2a4f90473af5255e4ff3ea2c2f260718f Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 20:37:58 +0000 Subject: Fix off by one length calciulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1781 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb.c b/hw/usb.c index b2830c590..758b341ff 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -183,7 +183,7 @@ int set_usb_string(uint8_t *buf, const char *str) q = buf; len = strlen(str); - *q++ = 2 * len + 1; + *q++ = 2 * len + 2; *q++ = 3; for(i = 0; i < len; i++) { *q++ = str[i]; -- cgit v1.2.3 From f5ba07d399ff205da3e91de4389e936027856b48 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 20:43:48 +0000 Subject: Fix typo in ppc icache flush. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1782 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyngen.h b/dyngen.h index e0e1f4a13..76866d4a1 100644 --- a/dyngen.h +++ b/dyngen.h @@ -59,7 +59,7 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) { unsigned long p; - p = start & ~(MIN_CACHE_LINE_SIZE - 1); + 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) { -- cgit v1.2.3 From b55669bf570339188461a9ba755c2386f549de90 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 20:48:36 +0000 Subject: Set SO_REUSEADDR before calling bind(). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1783 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp/socket.c b/slirp/socket.c index 47ed44b93..fbd9e960d 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -573,6 +573,7 @@ solisten(port, laddr, lport, flags) addr.sin_port = port; if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || + (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (listen(s,1) < 0)) { int tmperrno = errno; /* Don't clobber the real reason we failed */ @@ -587,7 +588,6 @@ solisten(port, laddr, lport, flags) #endif return NULL; } - setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); getsockname(s,(struct sockaddr *)&addr,&addrlen); -- cgit v1.2.3 From 19b045dec90378e63496f7ebf86b4f81fdcc5fd3 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 21:03:16 +0000 Subject: Fix FPA condition codes (Ulrich Hecht). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1784 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- target-arm/nwfpe/fpa11.c | 5 +++-- target-arm/nwfpe/fpa11.h | 29 +++++++---------------------- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 1402fd95b..81450051b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -345,7 +345,7 @@ void cpu_loop(CPUARMState *env) /* we get the opcode */ opcode = ldl_raw((uint8_t *)env->regs[15]); - if (EmulateAll(opcode, &ts->fpa, env->regs) == 0) { + if (EmulateAll(opcode, &ts->fpa, env) == 0) { info.si_signo = SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; diff --git a/target-arm/nwfpe/fpa11.c b/target-arm/nwfpe/fpa11.c index cfbe700c0..a8141e7e5 100644 --- a/target-arm/nwfpe/fpa11.c +++ b/target-arm/nwfpe/fpa11.c @@ -36,7 +36,7 @@ unsigned int EmulateCPDT(const unsigned int); unsigned int EmulateCPRT(const unsigned int); FPA11* qemufpa=0; -unsigned int* user_registers=0; +CPUARMState* user_registers; /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ void resetFPA11(void) @@ -137,7 +137,8 @@ void SetRoundingPrecision(const unsigned int opcode) } /* Emulate the instruction in the opcode. */ -unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs) +/* ??? This is not thread safe. */ +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) { unsigned int nRc = 0; // unsigned long flags; diff --git a/target-arm/nwfpe/fpa11.h b/target-arm/nwfpe/fpa11.h index 668393cff..8751696de 100644 --- a/target-arm/nwfpe/fpa11.h +++ b/target-arm/nwfpe/fpa11.h @@ -26,6 +26,8 @@ #include #include +#include + #define GET_FPA11() (qemufpa) /* @@ -33,7 +35,7 @@ * stack+task struct. Use the same method as 'current' uses to * reach them. */ -extern unsigned int *user_registers; +extern CPUARMState *user_registers; #define GET_USERREG() (user_registers) @@ -94,7 +96,7 @@ extern void SetRoundingPrecision(const unsigned int); static inline unsigned int readRegister(unsigned int reg) { - return (user_registers[(reg)]); + return (user_registers->regs[(reg)]); } static inline void writeRegister(unsigned int x, unsigned int y) @@ -102,34 +104,17 @@ static inline void writeRegister(unsigned int x, unsigned int y) #if 0 printf("writing %d to r%d\n",y,x); #endif - user_registers[(x)]=(y); + user_registers->regs[(x)]=(y); } static inline void writeConditionCodes(unsigned int x) { -#if 0 -unsigned int y; -unsigned int ZF; - printf("setting flags to %x from %x\n",x,user_registers[16]); -#endif - user_registers[16]=(x); // cpsr - user_registers[17]=(x>>29)&1; // cf - user_registers[18]=(x<<3)&(1<<31); // vf - user_registers[19]=x&(1<<31); // nzf - if(!(x&(1<<30))) user_registers[19]++; // nzf must be non-zero for zf to be cleared - -#if 0 - ZF = (user_registers[19] == 0); - y=user_registers[16] | (user_registers[19] & 0x80000000) | (ZF << 30) | - (user_registers[17] << 29) | ((user_registers[18] & 0x80000000) >> 3); - if(y != x) - printf("GODDAM SHIIIIIIIIIIIIIIIIT! %x %x nzf %x zf %x\n",x,y,user_registers[19],ZF); -#endif + cpsr_write(user_registers,x,CPSR_NZCV); } #define REG_PC 15 -unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, unsigned int* qregs); +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs); /* included only for get_user/put_user macros */ #include "qemu.h" -- cgit v1.2.3 From d80cfb3f705e88b1074f3b781c476618d2d24c0e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 11 Mar 2006 21:46:12 +0000 Subject: Add missing break statement. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1785 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index e93db5716..f902d4615 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -153,6 +153,7 @@ static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) switch(addr) { case 0x0c: val = s->sof_timing; + break; default: val = 0xff; break; -- cgit v1.2.3 From 8637c67fc56c70a029c8f4c2ca99e2c89e804703 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 14 Mar 2006 14:20:32 +0000 Subject: Fix FIQ bank switching. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1786 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index d0cd6d8e5..60eee5c2c 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -138,10 +138,10 @@ void switch_mode(CPUState *env, int mode) if (old_mode == ARM_CPU_MODE_FIQ) { memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); - memcpy (env->regs, env->usr_regs + 8, 5 * sizeof(uint32_t)); + memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); } else if (mode == ARM_CPU_MODE_FIQ) { memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); - memcpy (env->regs, env->fiq_regs + 8, 5 * sizeof(uint32_t)); + memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); } i = bank_number(old_mode); -- cgit v1.2.3 From 0a8e90f401ec602c007ae591138160b4de838630 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 19 Mar 2006 14:54:16 +0000 Subject: Configure options to enable/disable all softmmu/user targets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1787 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/configure b/configure index a0bc4d731..3f9ee4782 100755 --- a/configure +++ b/configure @@ -90,6 +90,8 @@ kernel_path="" cocoa="no" check_gfx="yes" check_gcc="yes" +softmmu="yes" +user="no" # OS specific targetos=`uname -s` @@ -123,6 +125,7 @@ darwin="yes" *) oss="yes" linux="yes" +user="yes" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" fi @@ -208,6 +211,14 @@ for opt do ;; --disable-gcc-check) check_gcc="no" ;; + --disable-softmmu) softmmu="no" + ;; + --enable-softmmu) softmmu="yes" + ;; + --disable-user) user="no" + ;; + --enable-user) user="yes" + ;; esac done @@ -232,14 +243,20 @@ fi if test -z "$target_list" ; then # these targets are portable - target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu" + 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 [ "$linux" = "yes" ] ; then + if [ "$user" = "yes" ] ; then target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-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 @@ -385,6 +402,10 @@ 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 "" -- cgit v1.2.3 From cad25d69ad99673a376866d930b4621abb52d56f Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 19 Mar 2006 16:31:11 +0000 Subject: Rename --*able-softmmu --*able-system. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1788 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 3f9ee4782..19334da61 100755 --- a/configure +++ b/configure @@ -211,9 +211,9 @@ for opt do ;; --disable-gcc-check) check_gcc="no" ;; - --disable-softmmu) softmmu="no" + --disable-system) softmmu="no" ;; - --enable-softmmu) softmmu="yes" + --enable-system) softmmu="yes" ;; --disable-user) user="no" ;; -- cgit v1.2.3 From 26f69dc09fa3c459fca53bbfd267cbfc2682201e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 25 Mar 2006 01:25:02 +0000 Subject: upgrade to latest vgabios version - added Video Parameter Table support - added 1600x1200x8 Cirrus mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1789 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/vgabios-cirrus.bin | Bin 32768 -> 32768 bytes pc-bios/vgabios.bin | Bin 32768 -> 32768 bytes pc-bios/vgabios.diff | 864 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 789 insertions(+), 75 deletions(-) diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 4978e42cd..6f72d1ebd 100644 Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index 072f8bd2b..1d6e51175 100644 Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ diff --git a/pc-bios/vgabios.diff b/pc-bios/vgabios.diff index d3a3ef7a2..73159a0fd 100644 --- a/pc-bios/vgabios.diff +++ b/pc-bios/vgabios.diff @@ -1,97 +1,811 @@ -? biossums -? vgabios.cirrus.debug.txt -? vgabios.cirrus.txt -? vgabios.debug.txt -? vgabios.txt -? tests/Makefile -? tests/setmode.S -? tests/setmode.c -? tests/setmode.com -? tests/setmode.elf Index: Makefile =================================================================== -RCS file: /cvsroot/vgabios/vgabios/Makefile,v -retrieving revision 1.15 -diff -u -w -r1.15 Makefile -Index: VGABIOS-lgpl-latest.bin -=================================================================== -RCS file: /cvsroot/vgabios/vgabios/VGABIOS-lgpl-latest.bin,v -retrieving revision 1.60 -diff -u -w -r1.60 VGABIOS-lgpl-latest.bin -Binary files /tmp/cvsCahrMA and VGABIOS-lgpl-latest.bin differ -Index: VGABIOS-lgpl-latest.cirrus.bin -=================================================================== -RCS file: /cvsroot/vgabios/vgabios/VGABIOS-lgpl-latest.cirrus.bin,v -retrieving revision 1.12 -diff -u -w -r1.12 VGABIOS-lgpl-latest.cirrus.bin -Binary files /tmp/cvsewygNU and VGABIOS-lgpl-latest.cirrus.bin differ -Index: VGABIOS-lgpl-latest.cirrus.debug.bin -=================================================================== -RCS file: /cvsroot/vgabios/vgabios/VGABIOS-lgpl-latest.cirrus.debug.bin,v -retrieving revision 1.12 -diff -u -w -r1.12 VGABIOS-lgpl-latest.cirrus.debug.bin -Binary files /tmp/cvsey9TQf and VGABIOS-lgpl-latest.cirrus.debug.bin differ -Index: VGABIOS-lgpl-latest.debug.bin -=================================================================== -RCS file: /cvsroot/vgabios/vgabios/VGABIOS-lgpl-latest.debug.bin,v -retrieving revision 1.60 -diff -u -w -r1.60 VGABIOS-lgpl-latest.debug.bin -Binary files /tmp/cvskxbTbC and VGABIOS-lgpl-latest.debug.bin differ +RCS file: /sources/vgabios/vgabios/Makefile,v +retrieving revision 1.17 +diff -u -w -r1.17 Makefile +--- Makefile 6 Mar 2005 13:06:47 -0000 1.17 ++++ Makefile 25 Mar 2006 01:19:02 -0000 +@@ -17,9 +17,9 @@ + all: bios cirrus-bios + + +-bios: biossums vgabios.bin vgabios.debug.bin ++bios: biossums vgabios.bin #vgabios.debug.bin + +-cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin ++cirrus-bios: vgabios-cirrus.bin #vgabios-cirrus.debug.bin + + clean: + /bin/rm -f biossums *.o *.s *.ld86 \ Index: clext.c =================================================================== -RCS file: /cvsroot/vgabios/vgabios/clext.c,v -retrieving revision 1.8 -diff -u -w -r1.8 clext.c ---- clext.c 8 Aug 2004 16:52:55 -0000 1.8 -+++ clext.c 30 Nov 2004 23:38:32 -0000 -@@ -222,7 +222,21 @@ - 0x001a,0x221b,0x001d, +RCS file: /sources/vgabios/vgabios/clext.c,v +retrieving revision 1.9 +diff -u -w -r1.9 clext.c +--- clext.c 4 Dec 2004 15:26:17 -0000 1.9 ++++ clext.c 25 Mar 2006 01:19:03 -0000 +@@ -238,6 +238,21 @@ 0xffff }; -- -+/* 1280x1024x16 */ -+unsigned short cseq_1280x1024x16[] = { -+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, + ++/* 1600x1200x8 */ ++unsigned short cseq_1600x1200x8[] = { ++0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, +0x760b,0x760c,0x760d,0x760e, +0x0412,0x0013,0x2017, +0x341b,0x341c,0x341d,0x341e, +0xffff +}; -+unsigned short ccrtc_1280x1024x16[] = { ++unsigned short ccrtc_1600x1200x8[] = { +0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, +0x6009,0x000c,0x000d, -+0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18, -+0x001a,0x321b,0x001d, ++0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18, ++0x001a,0x221b,0x001d, +0xffff +}; cirrus_mode_t cirrus_modes[] = { -@@ -269,6 +283,12 @@ - {0x6d,1280,1024,8,0x00, - cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8, - 4,0,0,0,0,0,0,0,0}, -+ {0x69,1280,1024,15,0xf0, -+ cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, -+ 6,5,10,5,5,5,0,1,15}, -+ {0x75,1280,1024,16,0xe1, -+ cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, -+ 6,5,11,6,5,5,0,0,0}, +@@ -291,6 +306,10 @@ + cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, + 6,5,11,6,5,5,0,0,0}, ++ {0x7b,1600,1200,8,0x00, ++ cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8, ++ 4,0,0,0,0,0,0,0,0}, ++ {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0, 0xff,0,0,0,0,0,0,0,0}, -@@ -310,9 +330,13 @@ - // 1024x768x16 - 0x117, 0x74, - // 1024x768x24 --//0x118, 0x79, -+ 0x118, 0x79, - // 1280x1024x8 - 0x107, 0x6d, -+// 1280x1024x15 -+ 0x119, 0x69, -+// 1280x1024x16 -+ 0x11a, 0x75, - // invalid - 0xffff,0xffff + {0xff,0,0,0,0,0,0,0,0, +Index: vgabios.c +=================================================================== +RCS file: /sources/vgabios/vgabios/vgabios.c,v +retrieving revision 1.63 +diff -u -w -r1.63 vgabios.c +--- vgabios.c 26 Dec 2005 19:50:26 -0000 1.63 ++++ vgabios.c 25 Mar 2006 01:19:03 -0000 +@@ -111,6 +111,7 @@ + static void biosfn_read_video_state_size(); + static void biosfn_save_video_state(); + static void biosfn_restore_video_state(); ++extern Bit8u video_save_pointer_table[]; + + // This is for compiling with gcc2 and gcc3 + #define ASM_START #asm +@@ -459,6 +460,29 @@ + + pop ds + ret ++ ++_video_save_pointer_table: ++ .word _video_param_table ++ .word 0xc000 ++ ++ .word 0 /* XXX: fill it */ ++ .word 0 ++ ++ .word 0 /* XXX: fill it */ ++ .word 0 ++ ++ .word 0 /* XXX: fill it */ ++ .word 0 ++ ++ .word 0 /* XXX: fill it */ ++ .word 0 ++ ++ .word 0 /* XXX: fill it */ ++ .word 0 ++ ++ .word 0 /* XXX: fill it */ ++ .word 0 ++ + ASM_END + + // -------------------------------------------------------------------------------------------- +@@ -780,8 +804,8 @@ + + // Should we clear the screen ? + Bit8u noclearmem=mode&0x80; +- Bit8u line,mmask,*palette; +- Bit16u i,twidth,theight,cheight; ++ Bit8u line,mmask,*palette,vpti; ++ Bit16u i,twidth,theightm1,cheight; + Bit8u modeset_ctl,video_ctl,vga_switches; + Bit16u crtc_addr; + +@@ -804,9 +828,10 @@ + if(line==0xFF) + return; + +- twidth=vga_modes[line].twidth; +- theight=vga_modes[line].theight; +- cheight=vga_modes[line].cheight; ++ vpti=line_to_vpti[line]; ++ twidth=video_param_table[vpti].twidth; ++ theightm1=video_param_table[vpti].theightm1; ++ cheight=video_param_table[vpti].cheight; + + // Read the bios vga control + video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL); +@@ -866,21 +891,25 @@ + inb(VGAREG_ACTL_RESET); + + // Set Attribute Ctl +- for(i=0;i<=ACTL_MAX_REG;i++) ++ for(i=0;i<=0x13;i++) + {outb(VGAREG_ACTL_ADDRESS,i); +- outb(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]); ++ outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]); + } ++ outb(VGAREG_ACTL_ADDRESS,0x14); ++ outb(VGAREG_ACTL_WRITE_DATA,0x00); + + // Set Sequencer Ctl +- for(i=0;i<=SEQU_MAX_REG;i++) ++ outb(VGAREG_SEQU_ADDRESS,0); ++ outb(VGAREG_SEQU_DATA,0x03); ++ for(i=1;i<=4;i++) + {outb(VGAREG_SEQU_ADDRESS,i); +- outb(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]); ++ outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]); + } + + // Set Grafx Ctl +- for(i=0;i<=GRDC_MAX_REG;i++) ++ for(i=0;i<=8;i++) + {outb(VGAREG_GRDC_ADDRESS,i); +- outb(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]); ++ outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]); + } + + // Set CRTC address VGA or MDA +@@ -889,13 +918,13 @@ + // Disable CRTC write protection + outw(crtc_addr,0x0011); + // Set CRTC regs +- for(i=0;i<=CRTC_MAX_REG;i++) ++ for(i=0;i<=0x18;i++) + {outb(crtc_addr,i); +- outb(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]); ++ outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]); + } + + // Set the misc register +- outb(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg); ++ outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg); + + // Enable video + outb(VGAREG_ACTL_ADDRESS,0x20); +@@ -927,9 +956,9 @@ + // Set the BIOS mem + write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode); + write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth); +- write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vga_modes[line].slength); ++ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l); + write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr); +- write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1); ++ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1); + write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight); + write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem)); + write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9); +@@ -937,8 +966,8 @@ + + // FIXME We nearly have the good tables. to be reworked + write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now +- write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER,0x00); +- write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2,0x00); ++ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table); ++ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000); + + // FIXME + write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but... +@@ -1114,7 +1143,7 @@ + } + else + { +- address = page*vga_modes[line].slength; ++ address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l); + } + + // CRTC regs 0x0c and 0x0d +@@ -1271,7 +1300,7 @@ + else + { + // FIXME gfx mode not complete +- cheight=vga_modes[line].cheight; ++ cheight=video_param_table[line_to_vpti[line]].cheight; + switch(vga_modes[line].memmodel) + { + case PLANAR4: +@@ -1581,7 +1610,7 @@ + else + { + // FIXME gfx mode not complete +- cheight=vga_modes[line].cheight; ++ cheight=video_param_table[line_to_vpti[line]].cheight; + bpp=vga_modes[line].pixbits; + while((count-->0) && (xcurs0) && (xcurs Date: Sat, 25 Mar 2006 19:31:22 +0000 Subject: Avoid accessing guest memory directly in usermode emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1790 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 54 +- cpu-exec.c | 10 +- exec-all.h | 2 +- exec.c | 58 ++- linux-user/arm-semi.c | 41 +- linux-user/elfload.c | 178 +++---- linux-user/ioctls.h | 2 +- linux-user/main.c | 58 +-- linux-user/mmap.c | 164 +++--- linux-user/qemu.h | 141 +++--- linux-user/signal.c | 32 +- linux-user/syscall.c | 1118 +++++++++++++++++++++++++++-------------- linux-user/syscall_types.h | 3 + linux-user/vm86.c | 43 +- target-arm/nwfpe/fpa11_cpdt.c | 62 ++- 15 files changed, 1194 insertions(+), 772 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index e0b60d96d..eb65b59ea 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -584,22 +584,41 @@ static inline void stfq_be_p(void *ptr, float64 v) /* 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 ldub_raw(p) ldub_p((uint8_t *)(long)(p)) -#define ldsb_raw(p) ldsb_p((uint8_t *)(long)(p)) -#define lduw_raw(p) lduw_p((uint8_t *)(long)(p)) -#define ldsw_raw(p) ldsw_p((uint8_t *)(long)(p)) -#define ldl_raw(p) ldl_p((uint8_t *)(long)(p)) -#define ldq_raw(p) ldq_p((uint8_t *)(long)(p)) -#define ldfl_raw(p) ldfl_p((uint8_t *)(long)(p)) -#define ldfq_raw(p) ldfq_p((uint8_t *)(long)(p)) -#define stb_raw(p, v) stb_p((uint8_t *)(long)(p), v) -#define stw_raw(p, v) stw_p((uint8_t *)(long)(p), v) -#define stl_raw(p, v) stl_p((uint8_t *)(long)(p), v) -#define stq_raw(p, v) stq_p((uint8_t *)(long)(p), v) -#define stfl_raw(p, v) stfl_p((uint8_t *)(long)(p), v) -#define stfq_raw(p, v) stfq_p((uint8_t *)(long)(p), v) +#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) @@ -648,6 +667,7 @@ static inline void stfq_be_p(void *ptr, float64 v) #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; @@ -666,9 +686,9 @@ extern unsigned long qemu_host_page_mask; #define PAGE_WRITE_ORG 0x0010 void page_dump(FILE *f); -int page_get_flags(unsigned long address); -void page_set_flags(unsigned long start, unsigned long end, int flags); -void page_unprotect_range(uint8_t *data, unsigned long data_size); +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 diff --git a/cpu-exec.c b/cpu-exec.c index 4741a2526..872f51f62 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -913,7 +913,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } @@ -964,7 +964,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } /* see if it is an MMU fault */ @@ -1000,7 +1000,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } /* see if it is an MMU fault */ @@ -1036,7 +1036,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } @@ -1086,7 +1086,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, pc, address, is_write, *(unsigned long *)old_set); #endif /* XXX: locking issue */ - if (is_write && page_unprotect(address, pc, puc)) { + if (is_write && page_unprotect(h2g(address), pc, puc)) { return 1; } diff --git a/exec-all.h b/exec-all.h index cc55ab44d..e4fc1d673 100644 --- a/exec-all.h +++ b/exec-all.h @@ -93,7 +93,7 @@ int cpu_restore_state_copy(struct TranslationBlock *tb, void *puc); void cpu_resume_from_signal(CPUState *env1, void *puc); void cpu_exec_init(CPUState *env); -int page_unprotect(unsigned long address, unsigned long pc, void *puc); +int page_unprotect(target_ulong address, unsigned long pc, void *puc); void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, int is_cpu_write_access); void tb_invalidate_page_range(target_ulong start, target_ulong end); diff --git a/exec.c b/exec.c index e4e68d9dc..9ad2edcf3 100644 --- a/exec.c +++ b/exec.c @@ -34,6 +34,9 @@ #include "cpu.h" #include "exec-all.h" +#if defined(CONFIG_USER_ONLY) +#include +#endif //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH @@ -810,7 +813,7 @@ static void tb_invalidate_phys_page(target_ulong addr, /* add the tb in the target page and protect it if necessary */ static inline void tb_alloc_page(TranslationBlock *tb, - unsigned int n, unsigned int page_addr) + unsigned int n, target_ulong page_addr) { PageDesc *p; TranslationBlock *last_first_tb; @@ -826,23 +829,30 @@ static inline void tb_alloc_page(TranslationBlock *tb, #if defined(CONFIG_USER_ONLY) if (p->flags & PAGE_WRITE) { - unsigned long host_start, host_end, addr; + target_ulong addr; + PageDesc *p2; int prot; /* force the host page as non writable (writes will have a page fault + mprotect overhead) */ - host_start = page_addr & qemu_host_page_mask; - host_end = host_start + qemu_host_page_size; + page_addr &= qemu_host_page_mask; prot = 0; - for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) - prot |= page_get_flags(addr); - mprotect((void *)host_start, qemu_host_page_size, + for(addr = page_addr; addr < page_addr + qemu_host_page_size; + addr += TARGET_PAGE_SIZE) { + + p2 = page_find (addr >> TARGET_PAGE_BITS); + if (!p2) + continue; + prot |= p2->flags; + p2->flags &= ~PAGE_WRITE; + page_get_flags(addr); + } + mprotect(g2h(page_addr), qemu_host_page_size, (prot & PAGE_BITS) & ~PAGE_WRITE); #ifdef DEBUG_TB_INVALIDATE printf("protecting code page: 0x%08lx\n", - host_start); + page_addr); #endif - p->flags &= ~PAGE_WRITE; } #else /* if some code is already present, then the pages are already @@ -1546,7 +1556,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, /* called from signal handler: invalidate the code and unprotect the page. Return TRUE if the fault was succesfully handled. */ -int page_unprotect(unsigned long addr, unsigned long pc, void *puc) +int page_unprotect(target_ulong addr, unsigned long pc, void *puc) { #if !defined(CONFIG_SOFTMMU) VirtPageDesc *vp; @@ -1645,7 +1655,7 @@ void page_dump(FILE *f) } } -int page_get_flags(unsigned long address) +int page_get_flags(target_ulong address) { PageDesc *p; @@ -1658,10 +1668,10 @@ int page_get_flags(unsigned long address) /* modify the flags of a page and invalidate the code if necessary. The flag PAGE_WRITE_ORG is positionned automatically depending on PAGE_WRITE */ -void page_set_flags(unsigned long start, unsigned long end, int flags) +void page_set_flags(target_ulong start, target_ulong end, int flags) { PageDesc *p; - unsigned long addr; + target_ulong addr; start = start & TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); @@ -1684,11 +1694,11 @@ void page_set_flags(unsigned long start, unsigned long end, int flags) /* called from signal handler: invalidate the code and unprotect the page. Return TRUE if the fault was succesfully handled. */ -int page_unprotect(unsigned long address, unsigned long pc, void *puc) +int page_unprotect(target_ulong address, unsigned long pc, void *puc) { unsigned int page_index, prot, pindex; PageDesc *p, *p1; - unsigned long host_start, host_end, addr; + target_ulong host_start, host_end, addr; host_start = address & qemu_host_page_mask; page_index = host_start >> TARGET_PAGE_BITS; @@ -1707,7 +1717,7 @@ int page_unprotect(unsigned long address, unsigned long pc, void *puc) if (prot & PAGE_WRITE_ORG) { pindex = (address - host_start) >> TARGET_PAGE_BITS; if (!(p1[pindex].flags & PAGE_WRITE)) { - mprotect((void *)host_start, qemu_host_page_size, + mprotect((void *)g2h(host_start), qemu_host_page_size, (prot & PAGE_BITS) | PAGE_WRITE); p1[pindex].flags |= PAGE_WRITE; /* and since the content will be modified, we must invalidate @@ -1723,11 +1733,12 @@ int page_unprotect(unsigned long address, unsigned long pc, void *puc) } /* call this function when system calls directly modify a memory area */ -void page_unprotect_range(uint8_t *data, unsigned long data_size) +/* ??? This should be redundant now we have lock_user. */ +void page_unprotect_range(target_ulong data, target_ulong data_size) { - unsigned long start, end, addr; + target_ulong start, end, addr; - start = (unsigned long)data; + start = data; end = start + data_size; start &= TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); @@ -1932,6 +1943,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, { int l, flags; target_ulong page; + void * p; while (len > 0) { page = addr & TARGET_PAGE_MASK; @@ -1944,11 +1956,15 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, if (is_write) { if (!(flags & PAGE_WRITE)) return; - memcpy((uint8_t *)addr, buf, len); + p = lock_user(addr, len, 0); + memcpy(p, buf, len); + unlock_user(p, addr, len); } else { if (!(flags & PAGE_READ)) return; - memcpy(buf, (uint8_t *)addr, len); + p = lock_user(addr, len, 1); + memcpy(buf, p, len); + unlock_user(p, addr, 0); } len -= l; buf += l; diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c index 472361a47..250d5b75c 100644 --- a/linux-user/arm-semi.c +++ b/linux-user/arm-semi.c @@ -77,20 +77,20 @@ static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code) return code; } -#define ARG(x) tswap32(args[x]) +#define ARG(n) tget32(args + n * 4) uint32_t do_arm_semihosting(CPUState *env) { - uint32_t *args; + target_ulong args; char * s; int nr; uint32_t ret; TaskState *ts = env->opaque; nr = env->regs[0]; - args = (uint32_t *)env->regs[1]; + args = env->regs[1]; switch (nr) { case SYS_OPEN: - s = (char *)ARG(0); + s = (char *)g2h(ARG(0)); if (ARG(1) >= 12) return (uint32_t)-1; if (strcmp(s, ":tt") == 0) { @@ -103,18 +103,23 @@ uint32_t do_arm_semihosting(CPUState *env) case SYS_CLOSE: return set_swi_errno(ts, close(ARG(0))); case SYS_WRITEC: - /* Write to debug console. stderr is near enough. */ - return write(STDERR_FILENO, args, 1); + { + char c = tget8(args); + /* Write to debug console. stderr is near enough. */ + return write(STDERR_FILENO, &c, 1); + } case SYS_WRITE0: - s = (char *)args; - return write(STDERR_FILENO, s, strlen(s)); + s = lock_user_string(args); + ret = write(STDERR_FILENO, s, strlen(s)); + unlock_user(s, args, 0); + return ret; case SYS_WRITE: - ret = set_swi_errno(ts, write(ARG(0), (void *)ARG(1), ARG(2))); + ret = set_swi_errno(ts, write(ARG(0), g2h(ARG(1)), ARG(2))); if (ret == (uint32_t)-1) return -1; return ARG(2) - ret; case SYS_READ: - ret = set_swi_errno(ts, read(ARG(0), (void *)ARG(1), ARG(2))); + ret = set_swi_errno(ts, read(ARG(0), g2h(ARG(1)), ARG(2))); if (ret == (uint32_t)-1) return -1; return ARG(2) - ret; @@ -140,20 +145,21 @@ uint32_t do_arm_semihosting(CPUState *env) /* XXX: Not implemented. */ return -1; case SYS_REMOVE: - return set_swi_errno(ts, remove((char *)ARG(0))); + return set_swi_errno(ts, remove((char *)g2h(ARG(0)))); case SYS_RENAME: - return set_swi_errno(ts, rename((char *)ARG(0), (char *)ARG(2))); + return set_swi_errno(ts, rename((char *)g2h(ARG(0)), + (char *)g2h(ARG(2)))); case SYS_CLOCK: return clock() / (CLOCKS_PER_SEC / 100); case SYS_TIME: return set_swi_errno(ts, time(NULL)); case SYS_SYSTEM: - return set_swi_errno(ts, system((char *)ARG(0))); + return set_swi_errno(ts, system((char *)g2h(ARG(0)))); case SYS_ERRNO: return ts->swi_errno; case SYS_GET_CMDLINE: /* XXX: Not implemented. */ - s = (char *)ARG(0); + s = (char *)g2h(ARG(0)); *s = 0; return -1; case SYS_HEAPINFO: @@ -166,11 +172,11 @@ uint32_t do_arm_semihosting(CPUState *env) if (!ts->heap_limit) { long ret; - ts->heap_base = do_brk(NULL); + ts->heap_base = do_brk(0); limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE; /* Try a big heap, and reduce the size if that fails. */ for (;;) { - ret = do_brk((char *)limit); + ret = do_brk(limit); if (ret != -1) break; limit = (ts->heap_base >> 1) + (limit >> 1); @@ -178,7 +184,8 @@ uint32_t do_arm_semihosting(CPUState *env) ts->heap_limit = limit; } - ptr = (uint32_t *)ARG(0); + page_unprotect_range (ARG(0), 32); + ptr = (uint32_t *)g2h(ARG(0)); ptr[0] = tswap32(ts->heap_base); ptr[1] = tswap32(ts->heap_limit); ptr[2] = tswap32(ts->stack_base); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c934fb831..14c00852a 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -97,17 +97,17 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - target_long *stack = (void *)infop->start_stack; + target_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; if (infop->entry & 1) regs->ARM_cpsr |= CPSR_T; regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; - regs->ARM_r2 = tswapl(stack[2]); /* envp */ - regs->ARM_r1 = tswapl(stack[1]); /* argv */ + regs->ARM_r2 = tgetl(stack + 8); /* envp */ + regs->ARM_r1 = tgetl(stack + 4); /* envp */ /* XXX: it seems that r0 is zeroed after ! */ - // regs->ARM_r0 = tswapl(stack[0]); /* argc */ + // regs->ARM_r0 = tgetl(stack); /* argc */ } #define USE_ELF_CORE_DUMP @@ -202,7 +202,7 @@ do { \ _r->gpr[3] = bprm->argc; \ _r->gpr[4] = (unsigned long)++pos; \ for (; tmp != 0; pos++) \ - tmp = *pos; \ + tmp = ldl(pos); \ _r->gpr[5] = (unsigned long)pos; \ } while (0) @@ -297,7 +297,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i */ struct linux_binprm { char buf[128]; - unsigned long page[MAX_ARG_PAGES]; + void *page[MAX_ARG_PAGES]; unsigned long p; int sh_bang; int fd; @@ -427,37 +427,13 @@ static void bswap_sym(Elf32_Sym *sym) } #endif -static void * get_free_page(void) -{ - void * retval; - - /* User-space version of kernel get_free_page. Returns a page-aligned - * page-sized chunk of memory. - */ - retval = (void *)target_mmap(0, qemu_host_page_size, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - - if((long)retval == -1) { - perror("get_free_page"); - exit(-1); - } - else { - return(retval); - } -} - -static void free_page(void * pageaddr) -{ - target_munmap((unsigned long)pageaddr, qemu_host_page_size); -} - /* * 'copy_string()' copies argument/envelope strings from user * memory to free pages in kernel mem. These are in a format ready * to be put directly into the top of new user memory. * */ -static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, +static unsigned long copy_strings(int argc,char ** argv, void **page, unsigned long p) { char *tmp, *tmp1, *pag = NULL; @@ -482,10 +458,10 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, --p; --tmp; --len; if (--offset < 0) { offset = p % TARGET_PAGE_SIZE; - pag = (char *) page[p/TARGET_PAGE_SIZE]; + pag = (char *)page[p/TARGET_PAGE_SIZE]; if (!pag) { - pag = (char *)get_free_page(); - page[p/TARGET_PAGE_SIZE] = (unsigned long)pag; + pag = (char *)malloc(TARGET_PAGE_SIZE); + page[p/TARGET_PAGE_SIZE] = pag; if (!pag) return 0; } @@ -591,10 +567,20 @@ static int prepare_binprm(struct linux_binprm *bprm) } } -unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, - struct image_info * info) +static inline void memcpy_to_target(target_ulong dest, const void *src, + unsigned long len) { - unsigned long stack_base, size, error; + void *host_ptr; + + host_ptr = lock_user(dest, len, 0); + memcpy(host_ptr, src, len); + unlock_user(host_ptr, dest, 1); +} + +unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, + struct image_info * info) +{ + target_ulong stack_base, size, error; int i; /* Create enough stack to hold everything. If we don't use @@ -627,10 +613,10 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm, if (bprm->page[i]) { info->rss++; - memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE); - free_page((void *)bprm->page[i]); + memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); + free(bprm->page[i]); } - stack_base += TARGET_PAGE_SIZE; + stack_base += TARGET_PAGE_SIZE; } return p; } @@ -657,7 +643,6 @@ static void set_brk(unsigned long start, unsigned long end) static void padzero(unsigned long elf_bss) { unsigned long nbyte; - char * fpnt; /* XXX: this is really a hack : if the real host page size is smaller than the target page size, some pages after the end @@ -679,55 +664,57 @@ static void padzero(unsigned long elf_bss) nbyte = elf_bss & (qemu_host_page_size-1); if (nbyte) { nbyte = qemu_host_page_size - nbyte; - fpnt = (char *) elf_bss; do { - *fpnt++ = 0; + tput8(elf_bss, 0); + elf_bss++; } while (--nbyte); } } -static unsigned int * create_elf_tables(char *p, int argc, int envc, - struct elfhdr * exec, - unsigned long load_addr, - unsigned long load_bias, - unsigned long interp_load_addr, int ibcs, - struct image_info *info) + +static unsigned long create_elf_tables(target_ulong p, int argc, int envc, + struct elfhdr * exec, + unsigned long load_addr, + unsigned long load_bias, + unsigned long interp_load_addr, int ibcs, + struct image_info *info) { - target_ulong *argv, *envp; - target_ulong *sp, *csp; - target_ulong *u_platform; + target_ulong argv, envp; + target_ulong sp; + int size; + target_ulong u_platform; const char *k_platform; - int v; + const int n = sizeof(target_ulong); - /* - * Force 16 byte _final_ alignment here for generality. - */ - sp = (unsigned int *) (~15UL & (unsigned long) p); - u_platform = NULL; + sp = p; + u_platform = 0; k_platform = ELF_PLATFORM; if (k_platform) { size_t len = strlen(k_platform) + 1; - sp -= (len + sizeof(target_ulong) - 1) / sizeof(target_ulong); - u_platform = (target_ulong *)sp; - __copy_to_user(u_platform, k_platform, len); + sp -= (len + n - 1) & ~(n - 1); + u_platform = sp; + memcpy_to_target(sp, k_platform, len); } - csp = sp; - csp -= (DLINFO_ITEMS + 1) * 2; + /* + * Force 16 byte _final_ alignment here for generality. + */ + sp = sp &~ (target_ulong)15; + size = (DLINFO_ITEMS + 1) * 2; if (k_platform) - csp -= 2; + size += 2; #ifdef DLINFO_ARCH_ITEMS - csp -= DLINFO_ARCH_ITEMS*2; + size += DLINFO_ARCH_ITEMS * 2; #endif - csp -= envc+1; - csp -= argc+1; - csp -= (!ibcs ? 3 : 1); /* argc itself */ - if ((unsigned long)csp & 15UL) - sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); + size += envc + argc + 2; + size += (!ibcs ? 3 : 1); /* argc itself */ + size *= n; + if (size & 15) + sp -= 16 - (size & 15); -#define NEW_AUX_ENT(id, val) \ - sp -= 2; \ - put_user (id, sp); \ - put_user (val, sp + 1) +#define NEW_AUX_ENT(id, val) do { \ + sp -= n; tputl(sp, val); \ + sp -= n; tputl(sp, id); \ + } while(0) NEW_AUX_ENT (AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ @@ -744,7 +731,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, NEW_AUX_ENT(AT_EGID, (target_ulong) getegid()); NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP); if (k_platform) - NEW_AUX_ENT(AT_PLATFORM, (target_ulong) u_platform); + NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO /* * ARCH_DLINFO must come last so platform specific code can enforce @@ -754,39 +741,32 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, #endif #undef NEW_AUX_ENT - sp -= envc+1; + sp -= (envc + 1) * n; envp = sp; - sp -= argc+1; + sp -= (argc + 1) * n; argv = sp; if (!ibcs) { - put_user((target_ulong)envp,--sp); - put_user((target_ulong)argv,--sp); + sp -= n; tputl(sp, envp); + sp -= n; tputl(sp, argv); } - put_user(argc,--sp); - info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); + sp -= n; tputl(sp, argc); + info->arg_start = p; while (argc-->0) { - put_user((target_ulong)p,argv++); - do { - get_user(v, p); - p++; - } while (v != 0); + tputl(argv, p); argv += n; + p += target_strlen(p) + 1; } - put_user(0,argv); - info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff); + tputl(argv, 0); + info->arg_end = info->env_start = p; while (envc-->0) { - put_user((target_ulong)p,envp++); - do { - get_user(v, p); - p++; - } while (v != 0); + tputl(envp, p); envp += n; + p += target_strlen(p) + 1; } - put_user(0,envp); - info->env_end = (unsigned int)((unsigned long)p & 0xffffffff); + tputl(envp, 0); + info->env_end = p; return sp; } - static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, int interpreter_fd, unsigned long *interp_load_addr) @@ -1335,8 +1315,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r #ifdef LOW_ELF_STACK info->start_stack = bprm->p = elf_stack - 4; #endif - bprm->p = (unsigned long) - create_elf_tables((char *)bprm->p, + bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex, @@ -1432,6 +1411,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, if(retval>=0) { retval = load_elf_binary(&bprm,regs,infop); } + if(retval>=0) { /* success. Initialize important registers */ init_thread(regs, infop); @@ -1440,7 +1420,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, /* Something went wrong, return the inode and free the argument pages*/ for (i=0 ; i> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); e2 |= flags; - stl((uint8_t *)ptr, e1); - stl((uint8_t *)ptr + 4, e2); + p = ptr; + p[0] = tswapl(e1); + p[1] = tswapl(e2); } static void set_gate(void *ptr, unsigned int type, unsigned int dpl, unsigned long addr, unsigned int sel) { unsigned int e1, e2; + uint32_t *p; e1 = (addr & 0xffff) | (sel << 16); e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); - stl((uint8_t *)ptr, e1); - stl((uint8_t *)ptr + 4, e2); + p = ptr; + p[0] = tswapl(e1); + p[1] = tswapl(e2); } uint64_t gdt_table[6]; @@ -343,7 +347,7 @@ void cpu_loop(CPUARMState *env) /* we handle the FPU emulation here, as Linux */ /* we get the opcode */ - opcode = ldl_raw((uint8_t *)env->regs[15]); + opcode = tget32(env->regs[15]); if (EmulateAll(opcode, &ts->fpa, env) == 0) { info.si_signo = SIGILL; @@ -364,20 +368,20 @@ void cpu_loop(CPUARMState *env) /* system call */ if (trapnr == EXCP_BKPT) { if (env->thumb) { - insn = lduw((void *)(env->regs[15])); + insn = tget16(env->regs[15]); n = insn & 0xff; env->regs[15] += 2; } else { - insn = ldl((void *)(env->regs[15])); + insn = tget32(env->regs[15]); n = (insn & 0xf) | ((insn >> 4) & 0xff0); env->regs[15] += 4; } } else { if (env->thumb) { - insn = lduw((void *)(env->regs[15] - 2)); + insn = tget16(env->regs[15] - 2); n = insn & 0xff; } else { - insn = ldl((void *)(env->regs[15] - 4)); + insn = tget32(env->regs[15] - 4); n = insn & 0xffffff; } } @@ -475,16 +479,16 @@ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) static inline void save_window_offset(CPUSPARCState *env, int cwp1) { unsigned int i; - uint32_t *sp_ptr; + target_ulong sp_ptr; - sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); + sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #if defined(DEBUG_WIN) printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", (int)sp_ptr, cwp1); #endif for(i = 0; i < 16; i++) { - put_user(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); - sp_ptr++; + tputl(sp_ptr, env->regbase[get_reg_index(env, cwp1, 8 + i)]); + sp_ptr += sizeof(target_ulong); } } @@ -500,22 +504,21 @@ static void save_window(CPUSPARCState *env) static void restore_window(CPUSPARCState *env) { unsigned int new_wim, i, cwp1; - uint32_t *sp_ptr, reg; + target_ulong sp_ptr; new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & ((1LL << NWINDOWS) - 1); /* restore the invalid window */ cwp1 = (env->cwp + 1) & (NWINDOWS - 1); - sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); + sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #if defined(DEBUG_WIN) printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", (int)sp_ptr, cwp1); #endif for(i = 0; i < 16; i++) { - get_user(reg, sp_ptr); - env->regbase[get_reg_index(env, cwp1, 8 + i)] = reg; - sp_ptr++; + env->regbase[get_reg_index(env, cwp1, 8 + i)] = tgetl(sp_ptr); + sp_ptr += sizeof(target_ulong); } env->wim = new_wim; } @@ -1304,15 +1307,9 @@ void cpu_loop(CPUMIPSState *env) if (nb_args >= 5) { sp_reg = env->gpr[29]; /* these arguments are taken from the stack */ - if (get_user(arg5, (target_ulong *)(sp_reg + 16))) { - ret = -EFAULT; - goto fail; - } + arg5 = tgetl(sp_reg + 16); if (nb_args >= 6) { - if (get_user(arg6, (target_ulong *)(sp_reg + 20))) { - ret = -EFAULT; - goto fail; - } + arg6 = tgetl(sp_reg + 20); } else { arg6 = 0; } @@ -1347,8 +1344,7 @@ void cpu_loop(CPUMIPSState *env) { uint32_t insn, op; - if (get_user(insn, (uint32_t *)env->PC) < 0) - goto sigill; + insn = tget32(env->PC); op = insn >> 26; // printf("insn=%08x op=%02x\n", insn, op); /* XXX: totally dummy FP ops just to be able to launch @@ -1531,7 +1527,7 @@ int main(int argc, char **argv) fprintf(logfile, "entry 0x%08lx\n" , info->entry); } - target_set_brk((char *)info->brk); + target_set_brk(info->brk); syscall_init(); signal_init(); @@ -1566,7 +1562,7 @@ int main(int argc, char **argv) env->eip = regs->eip; /* linux interrupt setup */ - env->idt.base = (long)idt_table; + env->idt.base = h2g(idt_table); env->idt.limit = sizeof(idt_table) - 1; set_idt(0, 0); set_idt(1, 0); @@ -1591,7 +1587,7 @@ int main(int argc, char **argv) set_idt(0x80, 3); /* linux segment setup */ - env->gdt.base = (long)gdt_table; + env->gdt.base = h2g(gdt_table); env->gdt.limit = sizeof(gdt_table) - 1; write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 948f2f6b2..0c906257b 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -29,10 +29,10 @@ //#define DEBUG_MMAP -/* NOTE: all the constants are the HOST ones */ -int target_mprotect(unsigned long start, unsigned long len, int prot) +/* NOTE: all the constants are the HOST ones, but addresses are target. */ +int target_mprotect(target_ulong start, target_ulong len, int prot) { - unsigned long end, host_start, host_end, addr; + target_ulong end, host_start, host_end, addr; int prot1, ret; #ifdef DEBUG_MMAP @@ -67,7 +67,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) } end = host_end; } - ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS); + ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) return ret; host_start += qemu_host_page_size; @@ -77,7 +77,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } - ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size, + ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) return ret; @@ -86,7 +86,7 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) /* handle the pages in the middle */ if (host_start < host_end) { - ret = mprotect((void *)host_start, host_end - host_start, prot); + ret = mprotect(g2h(host_start), host_end - host_start, prot); if (ret != 0) return ret; } @@ -95,28 +95,31 @@ int target_mprotect(unsigned long start, unsigned long len, int prot) } /* map an incomplete host page */ -int mmap_frag(unsigned long host_start, - unsigned long start, unsigned long end, - int prot, int flags, int fd, unsigned long offset) +static int mmap_frag(target_ulong real_start, + target_ulong start, target_ulong end, + int prot, int flags, int fd, target_ulong offset) { - unsigned long host_end, ret, addr; + target_ulong real_end, ret, addr; + void *host_start; int prot1, prot_new; - host_end = host_start + qemu_host_page_size; + real_end = real_start + qemu_host_page_size; + host_start = g2h(real_start); /* get the protection of the target pages outside the mapping */ prot1 = 0; - for(addr = host_start; addr < host_end; addr++) { + for(addr = real_start; addr < real_end; addr++) { if (addr < start || addr >= end) prot1 |= page_get_flags(addr); } if (prot1 == 0) { /* no page was there, so we allocate one */ - ret = (long)mmap((void *)host_start, qemu_host_page_size, prot, + ret = (long)mmap(host_start, qemu_host_page_size, prot, flags | MAP_ANONYMOUS, -1, 0); if (ret == -1) return ret; + prot1 = prot; } prot1 &= PAGE_BITS; @@ -130,31 +133,35 @@ int mmap_frag(unsigned long host_start, /* adjust protection to be able to read */ if (!(prot1 & PROT_WRITE)) - mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE); + mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); /* read the corresponding file data */ - pread(fd, (void *)start, end - start, offset); + pread(fd, g2h(start), end - start, offset); /* put final protection */ if (prot_new != (prot1 | PROT_WRITE)) - mprotect((void *)host_start, qemu_host_page_size, prot_new); + mprotect(host_start, qemu_host_page_size, prot_new); } else { /* just update the protection */ if (prot_new != prot1) { - mprotect((void *)host_start, qemu_host_page_size, prot_new); + mprotect(host_start, qemu_host_page_size, prot_new); } } return 0; } /* NOTE: all the constants are the HOST ones */ -long target_mmap(unsigned long start, unsigned long len, int prot, - int flags, int fd, unsigned long offset) +long target_mmap(target_ulong start, target_ulong len, int prot, + int flags, int fd, target_ulong offset) { - unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; + target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; + long host_start; #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ defined(__ia64) - static unsigned long last_start = 0x40000000; + static target_ulong last_start = 0x40000000; +#elif defined(__CYGWIN__) + /* Cygwin doesn't have a whole lot of address space. */ + static target_ulong last_start = 0x18000000; #endif #ifdef DEBUG_MMAP @@ -191,45 +198,49 @@ long target_mmap(unsigned long start, unsigned long len, int prot, len = TARGET_PAGE_ALIGN(len); if (len == 0) return start; - host_start = start & qemu_host_page_mask; + real_start = start & qemu_host_page_mask; if (!(flags & MAP_FIXED)) { #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ - defined(__ia64) + defined(__ia64) || defined(__CYGWIN__) /* tell the kenel to search at the same place as i386 */ - if (host_start == 0) { - host_start = last_start; + if (real_start == 0) { + real_start = last_start; last_start += HOST_PAGE_ALIGN(len); } #endif if (qemu_host_page_size != qemu_real_host_page_size) { /* NOTE: this code is only for debugging with '-p' option */ + /* ??? Can also occur when TARGET_PAGE_SIZE > host page size. */ /* reserve a memory area */ + /* ??? This needs fixing for remapping. */ +abort(); host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; - host_start = (long)mmap((void *)host_start, host_len, PROT_NONE, + real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (host_start == -1) - return host_start; - host_end = host_start + host_len; - start = HOST_PAGE_ALIGN(host_start); + if (real_start == -1) + return real_start; + real_end = real_start + host_len; + start = HOST_PAGE_ALIGN(real_start); end = start + HOST_PAGE_ALIGN(len); - if (start > host_start) - munmap((void *)host_start, start - host_start); - if (end < host_end) - munmap((void *)end, host_end - end); + if (start > real_start) + munmap((void *)real_start, start - real_start); + if (end < real_end) + munmap((void *)end, real_end - end); /* use it as a fixed mapping */ flags |= MAP_FIXED; } else { /* if not fixed, no need to do anything */ host_offset = offset & qemu_host_page_mask; host_len = len + offset - host_offset; - start = (long)mmap((void *)host_start, host_len, - prot, flags, fd, host_offset); - if (start == -1) - return start; + host_start = (long)mmap(real_start ? g2h(real_start) : NULL, + host_len, prot, flags, fd, host_offset); + if (host_start == -1) + return host_start; /* update start so that it points to the file position at 'offset' */ if (!(flags & MAP_ANONYMOUS)) - start += offset - host_offset; + host_start += offset - host_offset; + start = h2g(host_start); goto the_end1; } } @@ -239,7 +250,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, return -1; } end = start + len; - host_end = HOST_PAGE_ALIGN(end); + real_end = HOST_PAGE_ALIGN(end); /* worst case: we cannot map the file because the offset is not aligned, so we read it */ @@ -257,7 +268,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, -1, 0); if (retaddr == -1) return retaddr; - pread(fd, (void *)start, len, offset); + pread(fd, g2h(start), len, offset); if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); if (ret != 0) @@ -267,40 +278,40 @@ long target_mmap(unsigned long start, unsigned long len, int prot, } /* handle the start of the mapping */ - if (start > host_start) { - if (host_end == host_start + qemu_host_page_size) { + if (start > real_start) { + if (real_end == real_start + qemu_host_page_size) { /* one single host page */ - ret = mmap_frag(host_start, start, end, + ret = mmap_frag(real_start, start, end, prot, flags, fd, offset); if (ret == -1) return ret; goto the_end1; } - ret = mmap_frag(host_start, start, host_start + qemu_host_page_size, + ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, prot, flags, fd, offset); if (ret == -1) return ret; - host_start += qemu_host_page_size; + real_start += qemu_host_page_size; } /* handle the end of the mapping */ - if (end < host_end) { - ret = mmap_frag(host_end - qemu_host_page_size, - host_end - qemu_host_page_size, host_end, + if (end < real_end) { + ret = mmap_frag(real_end - qemu_host_page_size, + real_end - qemu_host_page_size, real_end, prot, flags, fd, - offset + host_end - qemu_host_page_size - start); + offset + real_end - qemu_host_page_size - start); if (ret == -1) return ret; - host_end -= qemu_host_page_size; + real_end -= qemu_host_page_size; } /* map the middle (easier) */ - if (host_start < host_end) { + if (real_start < real_end) { unsigned long offset1; if (flags & MAP_ANONYMOUS) offset1 = 0; else - offset1 = offset + host_start - start; - ret = (long)mmap((void *)host_start, host_end - host_start, + offset1 = offset + real_start - start; + ret = (long)mmap(g2h(real_start), real_end - real_start, prot, flags, fd, offset1); if (ret == -1) return ret; @@ -316,9 +327,9 @@ long target_mmap(unsigned long start, unsigned long len, int prot, return start; } -int target_munmap(unsigned long start, unsigned long len) +int target_munmap(target_ulong start, target_ulong len) { - unsigned long end, host_start, host_end, addr; + target_ulong end, real_start, real_end, addr; int prot, ret; #ifdef DEBUG_MMAP @@ -330,36 +341,36 @@ int target_munmap(unsigned long start, unsigned long len) if (len == 0) return -EINVAL; end = start + len; - host_start = start & qemu_host_page_mask; - host_end = HOST_PAGE_ALIGN(end); + real_start = start & qemu_host_page_mask; + real_end = HOST_PAGE_ALIGN(end); - if (start > host_start) { + if (start > real_start) { /* handle host page containing start */ prot = 0; - for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } - if (host_end == host_start + qemu_host_page_size) { - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + if (real_end == real_start + qemu_host_page_size) { + for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } - end = host_end; + end = real_end; } if (prot != 0) - host_start += qemu_host_page_size; + real_start += qemu_host_page_size; } - if (end < host_end) { + if (end < real_end) { prot = 0; - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } if (prot != 0) - host_end -= qemu_host_page_size; + real_end -= qemu_host_page_size; } /* unmap what we can */ - if (host_start < host_end) { - ret = munmap((void *)host_start, host_end - host_start); + if (real_start < real_end) { + ret = munmap((void *)real_start, real_end - real_start); if (ret != 0) return ret; } @@ -370,25 +381,26 @@ int target_munmap(unsigned long start, unsigned long len) /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED blocks which have been allocated starting on a host page */ -long target_mremap(unsigned long old_addr, unsigned long old_size, - unsigned long new_size, unsigned long flags, - unsigned long new_addr) +long target_mremap(target_ulong old_addr, target_ulong old_size, + target_ulong new_size, unsigned long flags, + target_ulong new_addr) { int prot; /* XXX: use 5 args syscall */ - new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags); + new_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); if (new_addr == -1) return new_addr; + new_addr = h2g(new_addr); prot = page_get_flags(old_addr); page_set_flags(old_addr, old_addr + old_size, 0); page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); return new_addr; } -int target_msync(unsigned long start, unsigned long len, int flags) +int target_msync(target_ulong start, target_ulong len, int flags) { - unsigned long end; + target_ulong end; if (start & ~TARGET_PAGE_MASK) return -EINVAL; @@ -400,6 +412,6 @@ int target_msync(unsigned long start, unsigned long len, int flags) return 0; start &= qemu_host_page_mask; - return msync((void *)start, end - start, flags); + return msync(g2h(start), end - start, flags); } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index f385a1c92..a797c512b 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -69,7 +69,7 @@ typedef struct TaskState { int swi_errno; #endif #ifdef TARGET_I386 - struct target_vm86plus_struct *target_v86; + target_ulong target_v86; struct vm86_saved_state vm86_saved_regs; struct target_vm86plus_struct vm86plus; uint32_t v86flags; @@ -84,8 +84,8 @@ extern TaskState *first_task_state; int elf_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); -void target_set_brk(char *new_brk); -long do_brk(char *new_brk); +void target_set_brk(target_ulong new_brk); +long do_brk(target_ulong new_brk); void syscall_init(void); long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); @@ -112,19 +112,18 @@ long do_rt_sigreturn(CPUState *env); void save_v86_state(CPUX86State *env); void handle_vm86_trap(CPUX86State *env, int trapno); void handle_vm86_fault(CPUX86State *env); -int do_vm86(CPUX86State *env, long subfunction, - struct target_vm86plus_struct * target_v86); +int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr); #endif /* mmap.c */ -int target_mprotect(unsigned long start, unsigned long len, int prot); -long target_mmap(unsigned long start, unsigned long len, int prot, - int flags, int fd, unsigned long offset); -int target_munmap(unsigned long start, unsigned long len); -long target_mremap(unsigned long old_addr, unsigned long old_size, - unsigned long new_size, unsigned long flags, - unsigned long new_addr); -int target_msync(unsigned long start, unsigned long len, int flags); +int target_mprotect(target_ulong start, target_ulong len, int prot); +long target_mmap(target_ulong start, target_ulong len, int prot, + int flags, int fd, target_ulong offset); +int target_munmap(target_ulong start, target_ulong len); +long target_mremap(target_ulong old_addr, target_ulong old_size, + target_ulong new_size, unsigned long flags, + target_ulong new_addr); +int target_msync(target_ulong start, target_ulong len, int flags); /* user access */ @@ -133,21 +132,22 @@ int target_msync(unsigned long start, unsigned long len, int flags); #define access_ok(type,addr,size) (1) +/* NOTE get_user and put_user use host addresses. */ #define __put_user(x,ptr)\ ({\ int size = sizeof(*ptr);\ switch(size) {\ case 1:\ - stb(ptr, (typeof(*ptr))(x));\ + *(uint8_t *)(ptr) = (typeof(*ptr))(x);\ break;\ case 2:\ - stw(ptr, (typeof(*ptr))(x));\ + *(uint16_t *)(ptr) = tswap16((typeof(*ptr))(x));\ break;\ case 4:\ - stl(ptr, (typeof(*ptr))(x));\ + *(uint32_t *)(ptr) = tswap32((typeof(*ptr))(x));\ break;\ case 8:\ - stq(ptr, (typeof(*ptr))(x));\ + *(uint64_t *)(ptr) = tswap64((typeof(*ptr))(x));\ break;\ default:\ abort();\ @@ -160,16 +160,16 @@ int target_msync(unsigned long start, unsigned long len, int flags); int size = sizeof(*ptr);\ switch(size) {\ case 1:\ - x = (typeof(*ptr))ldub((void *)ptr);\ + x = (typeof(*ptr))*(uint8_t *)(ptr);\ break;\ case 2:\ - x = (typeof(*ptr))lduw((void *)ptr);\ + x = (typeof(*ptr))tswap16(*(uint16_t *)(ptr));\ break;\ case 4:\ - x = (typeof(*ptr))ldl((void *)ptr);\ + x = (typeof(*ptr))tswap32(*(uint32_t *)(ptr));\ break;\ case 8:\ - x = (typeof(*ptr))ldq((void *)ptr);\ + x = (typeof(*ptr))tswap64(*(uint64_t *)(ptr));\ break;\ default:\ abort();\ @@ -177,26 +177,6 @@ int target_msync(unsigned long start, unsigned long len, int flags); 0;\ }) -static inline unsigned long __copy_to_user(void *dst, const void *src, - unsigned long size) -{ - memcpy(dst, src, size); - return 0; -} - -static inline unsigned long __copy_from_user(void *dst, const void *src, - unsigned long size) -{ - memcpy(dst, src, size); - return 0; -} - -static inline unsigned long __clear_user(void *dst, unsigned long size) -{ - memset(dst, 0, size); - return 0; -} - #define put_user(x,ptr)\ ({\ int __ret;\ @@ -217,30 +197,77 @@ static inline unsigned long __clear_user(void *dst, unsigned long size) __ret;\ }) -static inline unsigned long copy_to_user(void *dst, const void *src, - unsigned long size) +/* Functions for accessing guest memory. The tget and tput functions + read/write single values, byteswapping as neccessary. The lock_user + gets a pointer to a contiguous area of guest memory, but does not perform + and byteswapping. lock_user may return either a pointer to the guest + memory, or a temporary buffer. */ + +/* Lock an area of guest memory into the host. If copy is true then the + host area will have the same contents as the guest. */ +static inline void *lock_user(target_ulong guest_addr, long len, int copy) { - if (access_ok(VERIFY_WRITE, dst, size)) - return __copy_to_user(dst, src, size); +#ifdef DEBUG_REMAP + void *addr; + addr = malloc(len); + if (copy) + memcpy(addr, g2h(guest_addr), len); else - return size; + memset(addr, 0, len); + return addr; +#else + return g2h(guest_addr); +#endif } -static inline unsigned long copy_from_user(void *dst, const void *src, - unsigned long size) +/* Unlock an area of guest memory. The first LEN bytes must be flushed back + to guest memory. */ +static inline void unlock_user(void *host_addr, target_ulong guest_addr, + long len) { - if (access_ok(VERIFY_READ, src, size)) - return __copy_from_user(dst, src, size); - else - return size; +#ifdef DEBUG_REMAP + if (host_addr == g2h(guest_addr)) + return; + if (len > 0) + memcpy(g2h(guest_addr), host_addr, len); + free(host_addr); +#endif } -static inline unsigned long clear_user(void *dst, unsigned long size) +/* Return the length of a string in target memory. */ +static inline int target_strlen(target_ulong ptr) { - if (access_ok(VERIFY_WRITE, dst, size)) - return __clear_user(dst, size); - else - return size; + return strlen(g2h(ptr)); +} + +/* Like lock_user but for null terminated strings. */ +static inline void *lock_user_string(target_ulong guest_addr) +{ + long len; + len = target_strlen(guest_addr) + 1; + return lock_user(guest_addr, len, 1); } +/* Helper macros for locking/ulocking a target struct. */ +#define lock_user_struct(host_ptr, guest_addr, copy) \ + host_ptr = lock_user(guest_addr, sizeof(*host_ptr), copy) +#define unlock_user_struct(host_ptr, guest_addr, copy) \ + unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) + +#define tget8(addr) ldub(addr) +#define tput8(addr, val) stb(addr, val) +#define tget16(addr) lduw(addr) +#define tput16(addr, val) stw(addr, val) +#define tget32(addr) ldl(addr) +#define tput32(addr, val) stl(addr, val) +#define tget64(addr) ldq(addr) +#define tput64(addr, val) stq(addr, val) +#if TARGET_LONG_BITS == 64 +#define tgetl(addr) ldq(addr) +#define tputl(addr, val) stq(addr, val) +#else +#define tgetl(addr) ldl(addr) +#define tputl(addr, val) stl(addr, val) +#endif + #endif /* QEMU_H */ diff --git a/linux-user/signal.c b/linux-user/signal.c index 29933bda4..ac4b2897f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -135,7 +135,7 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) host_to_target_sigset_internal(&d1, s); for(i = 0;i < TARGET_NSIG_WORDS; i++) - __put_user(d1.sig[i], &d->sig[i]); + d->sig[i] = tswapl(d1.sig[i]); } void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) @@ -168,7 +168,7 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) int i; for(i = 0;i < TARGET_NSIG_WORDS; i++) - __get_user(s1.sig[i], &s->sig[i]); + s1.sig[i] = tswapl(s->sig[i]); target_to_host_sigset_internal(d, &s1); } @@ -647,7 +647,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) ka->sa.sa_restorer) { esp = (unsigned long) ka->sa.sa_restorer; } - return (void *)((esp - frame_size) & -8ul); + return g2h((esp - frame_size) & -8ul); } static void setup_frame(int sig, struct emulated_sigaction *ka, @@ -694,7 +694,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, goto give_sigsegv; /* Set up registers for signal handler */ - env->regs[R_ESP] = (unsigned long) frame; + env->regs[R_ESP] = h2g(frame); env->eip = (unsigned long) ka->sa._sa_handler; cpu_x86_load_seg(env, R_DS, __USER_DS); @@ -835,7 +835,7 @@ badframe: long do_sigreturn(CPUX86State *env) { - struct sigframe *frame = (struct sigframe *)(env->regs[R_ESP] - 8); + struct sigframe *frame = (struct sigframe *)g2h(env->regs[R_ESP] - 8); target_sigset_t target_set; sigset_t set; int eax, i; @@ -866,7 +866,7 @@ badframe: long do_rt_sigreturn(CPUX86State *env) { - struct rt_sigframe *frame = (struct rt_sigframe *)(env->regs[R_ESP] - 4); + struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env->regs[R_ESP] - 4); sigset_t set; // stack_t st; int eax; @@ -1029,7 +1029,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) /* * ATPCS B01 mandates 8-byte alignment */ - return (void *)((sp - framesize) & ~7); + return g2h((sp - framesize) & ~7); } static int @@ -1084,7 +1084,7 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, } env->regs[0] = usig; - env->regs[13] = (target_ulong)frame; + env->regs[13] = h2g(frame); env->regs[14] = retcode; env->regs[15] = handler & (thumb ? ~1 : ~3); @@ -1130,7 +1130,7 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, err |= copy_siginfo_to_user(&frame->info, info); /* Clear all the bits of the ucontext we don't use. */ - err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext)); err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ env, set->sig[0]); @@ -1202,7 +1202,7 @@ long do_sigreturn(CPUState *env) if (env->regs[13] & 7) goto badframe; - frame = (struct sigframe *)env->regs[13]; + frame = (struct sigframe *)g2h(env->regs[13]); #if 0 if (verify_area(VERIFY_READ, frame, sizeof (*frame))) @@ -1378,7 +1378,7 @@ static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, u sp = current->sas_ss_sp + current->sas_ss_size; } #endif - return (void *)(sp - framesize); + return g2h(sp - framesize); } static int @@ -1461,10 +1461,10 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, goto sigsegv; /* 3. signal handler back-trampoline and parameters */ - env->regwptr[UREG_FP] = (target_ulong) sf; + env->regwptr[UREG_FP] = h2g(sf); env->regwptr[UREG_I0] = sig; - env->regwptr[UREG_I1] = (target_ulong) &sf->info; - env->regwptr[UREG_I2] = (target_ulong) &sf->info; + env->regwptr[UREG_I1] = h2g(&sf->info); + env->regwptr[UREG_I2] = h2g(&sf->info); /* 4. signal handler */ env->pc = (unsigned long) ka->sa._sa_handler; @@ -1473,7 +1473,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, if (ka->sa.sa_restorer) env->regwptr[UREG_I7] = (unsigned long)ka->sa.sa_restorer; else { - env->regwptr[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); + env->regwptr[UREG_I7] = h2g(&(sf->insns[0]) - 2); /* mov __NR_sigreturn, %g1 */ err |= __put_user(0x821020d8, &sf->insns[0]); @@ -1548,7 +1548,7 @@ long do_sigreturn(CPUState *env) target_ulong fpu_save; int err, i; - sf = (struct target_signal_frame *) env->regwptr[UREG_FP]; + sf = (struct target_signal_frame *)g2h(env->regwptr[UREG_FP]); #if 0 fprintf(stderr, "sigreturn\n"); fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ab7846d7a..2b132477f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -252,44 +252,43 @@ static inline int is_error(long ret) return (unsigned long)ret >= (unsigned long)(-4096); } -static char *target_brk; -static char *target_original_brk; +static target_ulong target_brk; +static target_ulong target_original_brk; -void target_set_brk(char *new_brk) +void target_set_brk(target_ulong new_brk) { - target_brk = new_brk; - target_original_brk = new_brk; + target_original_brk = target_brk = new_brk; } -long do_brk(char *new_brk) +long do_brk(target_ulong new_brk) { - char *brk_page; + target_ulong brk_page; long mapped_addr; int new_alloc_size; if (!new_brk) - return (long)target_brk; + return target_brk; if (new_brk < target_original_brk) return -ENOMEM; - brk_page = (char *)HOST_PAGE_ALIGN((unsigned long)target_brk); + brk_page = HOST_PAGE_ALIGN(target_brk); /* If the new brk is less than this, set it and we're done... */ if (new_brk < brk_page) { target_brk = new_brk; - return (long)target_brk; + return target_brk; } /* We need to allocate more memory after the brk... */ new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); - mapped_addr = get_errno(target_mmap((unsigned long)brk_page, new_alloc_size, + mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); if (is_error(mapped_addr)) { return mapped_addr; } else { target_brk = new_brk; - return (long)target_brk; + return target_brk; } } @@ -354,9 +353,12 @@ static inline long host_to_target_clock_t(long ticks) #endif } -static inline void host_to_target_rusage(struct target_rusage *target_rusage, +static inline void host_to_target_rusage(target_ulong target_addr, const struct rusage *rusage) { + struct target_rusage *target_rusage; + + lock_user_struct(target_rusage, target_addr, 0); target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec); target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec); target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec); @@ -375,35 +377,64 @@ static inline void host_to_target_rusage(struct target_rusage *target_rusage, target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals); target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw); target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw); + unlock_user_struct(target_rusage, target_addr, 1); } -static inline void target_to_host_timeval(struct timeval *tv, - const struct target_timeval *target_tv) +static inline void target_to_host_timeval(struct timeval *tv, + target_ulong target_addr) { + struct target_timeval *target_tv; + + lock_user_struct(target_tv, target_addr, 1); tv->tv_sec = tswapl(target_tv->tv_sec); tv->tv_usec = tswapl(target_tv->tv_usec); + unlock_user_struct(target_tv, target_addr, 0); } -static inline void host_to_target_timeval(struct target_timeval *target_tv, +static inline void host_to_target_timeval(target_ulong target_addr, const struct timeval *tv) { + struct target_timeval *target_tv; + + lock_user_struct(target_tv, target_addr, 0); target_tv->tv_sec = tswapl(tv->tv_sec); target_tv->tv_usec = tswapl(tv->tv_usec); + unlock_user_struct(target_tv, target_addr, 1); } static long do_select(long n, - target_long *target_rfds, target_long *target_wfds, - target_long *target_efds, struct target_timeval *target_tv) + target_ulong rfd_p, target_ulong wfd_p, + target_ulong efd_p, target_ulong target_tv) { fd_set rfds, wfds, efds; fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; + target_long *target_rfds, *target_wfds, *target_efds; struct timeval tv, *tv_ptr; long ret; + int ok; - rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); - wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); - efds_ptr = target_to_host_fds(&efds, target_efds, n); + if (rfd_p) { + target_rfds = lock_user(rfd_p, sizeof(target_long) * n, 1); + rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); + } else { + target_rfds = NULL; + rfds_ptr = NULL; + } + if (wfd_p) { + target_wfds = lock_user(wfd_p, sizeof(target_long) * n, 1); + wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); + } else { + target_wfds = NULL; + wfds_ptr = NULL; + } + if (efd_p) { + target_efds = lock_user(efd_p, sizeof(target_long) * n, 1); + efds_ptr = target_to_host_fds(&efds, target_efds, n); + } else { + target_efds = NULL; + efds_ptr = NULL; + } if (target_tv) { target_to_host_timeval(&tv, target_tv); @@ -412,7 +443,9 @@ static long do_select(long n, tv_ptr = NULL; } ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); - if (!is_error(ret)) { + ok = !is_error(ret); + + if (ok) { host_to_target_fds(target_rfds, rfds_ptr, n); host_to_target_fds(target_wfds, wfds_ptr, n); host_to_target_fds(target_efds, efds_ptr, n); @@ -421,25 +454,41 @@ static long do_select(long n, host_to_target_timeval(target_tv, &tv); } } + if (target_rfds) + unlock_user(target_rfds, rfd_p, ok ? sizeof(target_long) * n : 0); + if (target_wfds) + unlock_user(target_wfds, wfd_p, ok ? sizeof(target_long) * n : 0); + if (target_efds) + unlock_user(target_efds, efd_p, ok ? sizeof(target_long) * n : 0); + return ret; } static inline void target_to_host_sockaddr(struct sockaddr *addr, - struct target_sockaddr *target_addr, + target_ulong target_addr, socklen_t len) { - memcpy(addr, target_addr, len); - addr->sa_family = tswap16(target_addr->sa_family); + struct target_sockaddr *target_saddr; + + target_saddr = lock_user(target_addr, len, 1); + memcpy(addr, target_saddr, len); + addr->sa_family = tswap16(target_saddr->sa_family); + unlock_user(target_saddr, target_addr, 0); } -static inline void host_to_target_sockaddr(struct target_sockaddr *target_addr, +static inline void host_to_target_sockaddr(target_ulong target_addr, struct sockaddr *addr, socklen_t len) { - memcpy(target_addr, addr, len); - target_addr->sa_family = tswap16(addr->sa_family); + struct target_sockaddr *target_saddr; + + target_saddr = lock_user(target_addr, len, 0); + memcpy(target_saddr, addr, len); + target_saddr->sa_family = tswap16(addr->sa_family); + unlock_user(target_saddr, target_addr, len); } +/* ??? Should this also swap msgh->name? */ static inline void target_to_host_cmsg(struct msghdr *msgh, struct target_msghdr *target_msgh) { @@ -484,6 +533,7 @@ static inline void target_to_host_cmsg(struct msghdr *msgh, msgh->msg_controllen = space; } +/* ??? Should this also swap msgh->name? */ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, struct msghdr *msgh) { @@ -528,7 +578,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, } static long do_setsockopt(int sockfd, int level, int optname, - void *optval, socklen_t optlen) + target_ulong optval, socklen_t optlen) { int val, ret; @@ -538,8 +588,7 @@ static long do_setsockopt(int sockfd, int level, int optname, if (optlen < sizeof(uint32_t)) return -EINVAL; - if (get_user(val, (uint32_t *)optval)) - return -EFAULT; + val = tget32(optval); ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; case SOL_IP: @@ -561,11 +610,9 @@ static long do_setsockopt(int sockfd, int level, int optname, case IP_MULTICAST_LOOP: val = 0; if (optlen >= sizeof(uint32_t)) { - if (get_user(val, (uint32_t *)optval)) - return -EFAULT; + val = tget32(optval); } else if (optlen >= 1) { - if (get_user(val, (uint8_t *)optval)) - return -EFAULT; + val = tget8(optval); } ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; @@ -598,8 +645,8 @@ static long do_setsockopt(int sockfd, int level, int optname, case SO_SNDTIMEO: if (optlen < sizeof(uint32_t)) return -EINVAL; - if (get_user(val, (uint32_t *)optval)) - return -EFAULT; + + val = tget32(optval); ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; default: @@ -615,7 +662,7 @@ static long do_setsockopt(int sockfd, int level, int optname, } static long do_getsockopt(int sockfd, int level, int optname, - void *optval, socklen_t *optlen) + target_ulong optval, target_ulong optlen) { int len, lv, val, ret; @@ -636,8 +683,7 @@ static long do_getsockopt(int sockfd, int level, int optname, case SOL_TCP: /* TCP options all take an 'int' value. */ int_case: - if (get_user(len, optlen)) - return -EFAULT; + len = tget32(optlen); if (len < 0) return -EINVAL; lv = sizeof(int); @@ -647,10 +693,11 @@ static long do_getsockopt(int sockfd, int level, int optname, val = tswap32(val); if (len > lv) len = lv; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - if (put_user(len, optlen)) - return -EFAULT; + if (len == 4) + tput32(optval, val); + else + tput8(optval, val); + tput32(optlen, len); break; case SOL_IP: switch(optname) { @@ -669,8 +716,7 @@ static long do_getsockopt(int sockfd, int level, int optname, #endif case IP_MULTICAST_TTL: case IP_MULTICAST_LOOP: - if (get_user(len, optlen)) - return -EFAULT; + len = tget32(optlen); if (len < 0) return -EINVAL; lv = sizeof(int); @@ -678,20 +724,14 @@ static long do_getsockopt(int sockfd, int level, int optname, if (ret < 0) return ret; if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { - unsigned char ucval = val; len = 1; - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval,&ucval,1)) - return -EFAULT; + tput32(optlen, len); + tput8(optval, val); } else { - val = tswap32(val); if (len > sizeof(int)) len = sizeof(int); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; + tput32(optlen, len); + tput32(optval, val); } break; default: @@ -708,25 +748,57 @@ static long do_getsockopt(int sockfd, int level, int optname, return ret; } -static long do_socketcall(int num, int32_t *vptr) +static void lock_iovec(struct iovec *vec, target_ulong target_addr, + int count, int copy) +{ + struct target_iovec *target_vec; + target_ulong base; + int i; + + target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + for(i = 0;i < count; i++) { + base = tswapl(target_vec[i].iov_base); + vec[i].iov_len = tswapl(target_vec[i].iov_len); + vec[i].iov_base = lock_user(base, vec[i].iov_len, copy); + } + unlock_user (target_vec, target_addr, 0); +} + +static void unlock_iovec(struct iovec *vec, target_ulong target_addr, + int count, int copy) +{ + struct target_iovec *target_vec; + target_ulong base; + int i; + + target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + for(i = 0;i < count; i++) { + base = tswapl(target_vec[i].iov_base); + unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); + } + unlock_user (target_vec, target_addr, 0); +} + +static long do_socketcall(int num, target_ulong vptr) { long ret; + const int n = sizeof(target_ulong); switch(num) { case SOCKOP_socket: { - int domain = tswap32(vptr[0]); - int type = tswap32(vptr[1]); - int protocol = tswap32(vptr[2]); + int domain = tgetl(vptr); + int type = tgetl(vptr + n); + int protocol = tgetl(vptr + 2 * n); ret = get_errno(socket(domain, type, protocol)); } break; case SOCKOP_bind: { - int sockfd = tswap32(vptr[0]); - void *target_addr = (void *)tswap32(vptr[1]); - socklen_t addrlen = tswap32(vptr[2]); + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + socklen_t addrlen = tgetl(vptr + 2 * n); void *addr = alloca(addrlen); target_to_host_sockaddr(addr, target_addr, addrlen); @@ -735,9 +807,9 @@ static long do_socketcall(int num, int32_t *vptr) break; case SOCKOP_connect: { - int sockfd = tswap32(vptr[0]); - void *target_addr = (void *)tswap32(vptr[1]); - socklen_t addrlen = tswap32(vptr[2]); + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + socklen_t addrlen = tgetl(vptr + 2 * n); void *addr = alloca(addrlen); target_to_host_sockaddr(addr, target_addr, addrlen); @@ -746,128 +818,142 @@ static long do_socketcall(int num, int32_t *vptr) break; case SOCKOP_listen: { - int sockfd = tswap32(vptr[0]); - int backlog = tswap32(vptr[1]); + int sockfd = tgetl(vptr); + int backlog = tgetl(vptr + n); ret = get_errno(listen(sockfd, backlog)); } break; case SOCKOP_accept: { - int sockfd = tswap32(vptr[0]); - void *target_addr = (void *)tswap32(vptr[1]); - uint32_t *target_addrlen = (void *)tswap32(vptr[2]); - socklen_t addrlen = tswap32(*target_addrlen); + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + target_ulong target_addrlen = tgetl(vptr + 2 * n); + socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); ret = get_errno(accept(sockfd, addr, &addrlen)); if (!is_error(ret)) { host_to_target_sockaddr(target_addr, addr, addrlen); - *target_addrlen = tswap32(addrlen); + tput32(target_addrlen, addrlen); } } break; case SOCKOP_getsockname: { - int sockfd = tswap32(vptr[0]); - void *target_addr = (void *)tswap32(vptr[1]); - uint32_t *target_addrlen = (void *)tswap32(vptr[2]); - socklen_t addrlen = tswap32(*target_addrlen); + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + target_ulong target_addrlen = tgetl(vptr + 2 * n); + socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); ret = get_errno(getsockname(sockfd, addr, &addrlen)); if (!is_error(ret)) { host_to_target_sockaddr(target_addr, addr, addrlen); - *target_addrlen = tswap32(addrlen); + tput32(target_addrlen, addrlen); } } break; case SOCKOP_getpeername: { - int sockfd = tswap32(vptr[0]); - void *target_addr = (void *)tswap32(vptr[1]); - uint32_t *target_addrlen = (void *)tswap32(vptr[2]); - socklen_t addrlen = tswap32(*target_addrlen); + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + target_ulong target_addrlen = tgetl(vptr + 2 * n); + socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); ret = get_errno(getpeername(sockfd, addr, &addrlen)); if (!is_error(ret)) { host_to_target_sockaddr(target_addr, addr, addrlen); - *target_addrlen = tswap32(addrlen); + tput32(target_addrlen, addrlen); } } break; case SOCKOP_socketpair: { - int domain = tswap32(vptr[0]); - int type = tswap32(vptr[1]); - int protocol = tswap32(vptr[2]); - int32_t *target_tab = (void *)tswap32(vptr[3]); + int domain = tgetl(vptr); + int type = tgetl(vptr + n); + int protocol = tgetl(vptr + 2 * n); + target_ulong target_tab = tgetl(vptr + 3 * n); int tab[2]; ret = get_errno(socketpair(domain, type, protocol, tab)); if (!is_error(ret)) { - target_tab[0] = tswap32(tab[0]); - target_tab[1] = tswap32(tab[1]); + tput32(target_tab, tab[0]); + tput32(target_tab + 4, tab[1]); } } break; case SOCKOP_send: { - int sockfd = tswap32(vptr[0]); - void *msg = (void *)tswap32(vptr[1]); - size_t len = tswap32(vptr[2]); - int flags = tswap32(vptr[3]); + int sockfd = tgetl(vptr); + target_ulong msg = tgetl(vptr + n); + size_t len = tgetl(vptr + 2 * n); + int flags = tgetl(vptr + 3 * n); + void *host_msg; - ret = get_errno(send(sockfd, msg, len, flags)); + host_msg = lock_user(msg, len, 1); + ret = get_errno(send(sockfd, host_msg, len, flags)); + unlock_user(host_msg, msg, 0); } break; case SOCKOP_recv: { - int sockfd = tswap32(vptr[0]); - void *msg = (void *)tswap32(vptr[1]); - size_t len = tswap32(vptr[2]); - int flags = tswap32(vptr[3]); + int sockfd = tgetl(vptr); + target_ulong msg = tgetl(vptr + n); + size_t len = tgetl(vptr + 2 * n); + int flags = tgetl(vptr + 3 * n); + void *host_msg; - ret = get_errno(recv(sockfd, msg, len, flags)); + host_msg = lock_user(msg, len, 0); + ret = get_errno(recv(sockfd, host_msg, len, flags)); + unlock_user(host_msg, msg, ret); } break; case SOCKOP_sendto: { - int sockfd = tswap32(vptr[0]); - void *msg = (void *)tswap32(vptr[1]); - size_t len = tswap32(vptr[2]); - int flags = tswap32(vptr[3]); - void *target_addr = (void *)tswap32(vptr[4]); - socklen_t addrlen = tswap32(vptr[5]); + int sockfd = tgetl(vptr); + target_ulong msg = tgetl(vptr + n); + size_t len = tgetl(vptr + 2 * n); + int flags = tgetl(vptr + 3 * n); + target_ulong target_addr = tgetl(vptr + 4 * n); + socklen_t addrlen = tgetl(vptr + 5 * n); void *addr = alloca(addrlen); + void *host_msg; + host_msg = lock_user(msg, len, 1); target_to_host_sockaddr(addr, target_addr, addrlen); - ret = get_errno(sendto(sockfd, msg, len, flags, addr, addrlen)); + ret = get_errno(sendto(sockfd, host_msg, len, flags, addr, addrlen)); + unlock_user(host_msg, msg, 0); } break; case SOCKOP_recvfrom: { - int sockfd = tswap32(vptr[0]); - void *msg = (void *)tswap32(vptr[1]); - size_t len = tswap32(vptr[2]); - int flags = tswap32(vptr[3]); - void *target_addr = (void *)tswap32(vptr[4]); - uint32_t *target_addrlen = (void *)tswap32(vptr[5]); - socklen_t addrlen = tswap32(*target_addrlen); + int sockfd = tgetl(vptr); + target_ulong msg = tgetl(vptr + n); + size_t len = tgetl(vptr + 2 * n); + int flags = tgetl(vptr + 3 * n); + target_ulong target_addr = tgetl(vptr + 4 * n); + target_ulong target_addrlen = tgetl(vptr + 5 * n); + socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); + void *host_msg; - ret = get_errno(recvfrom(sockfd, msg, len, flags, addr, &addrlen)); + host_msg = lock_user(msg, len, 0); + ret = get_errno(recvfrom(sockfd, host_msg, len, flags, addr, &addrlen)); if (!is_error(ret)) { host_to_target_sockaddr(target_addr, addr, addrlen); - *target_addrlen = tswap32(addrlen); + tput32(target_addrlen, addrlen); + unlock_user(host_msg, msg, len); + } else { + unlock_user(host_msg, msg, 0); } } break; case SOCKOP_shutdown: { - int sockfd = tswap32(vptr[0]); - int how = tswap32(vptr[1]); + int sockfd = tgetl(vptr); + int how = tgetl(vptr + n); ret = get_errno(shutdown(sockfd, how)); } @@ -876,32 +962,39 @@ static long do_socketcall(int num, int32_t *vptr) case SOCKOP_recvmsg: { int fd; + target_ulong target_msg; struct target_msghdr *msgp; struct msghdr msg; - int flags, count, i; + int flags, count; struct iovec *vec; - struct target_iovec *target_vec; - - msgp = (void *)tswap32(vptr[1]); - msg.msg_name = (void *)tswapl(msgp->msg_name); - msg.msg_namelen = tswapl(msgp->msg_namelen); + target_ulong target_vec; + int send = (num == SOCKOP_sendmsg); + + target_msg = tgetl(vptr + n); + lock_user_struct(msgp, target_msg, 1); + if (msgp->msg_name) { + msg.msg_namelen = tswap32(msgp->msg_namelen); + msg.msg_name = alloca(msg.msg_namelen); + target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), + msg.msg_namelen); + } else { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); msg.msg_control = alloca(msg.msg_controllen); msg.msg_flags = tswap32(msgp->msg_flags); count = tswapl(msgp->msg_iovlen); vec = alloca(count * sizeof(struct iovec)); - target_vec = (void *)tswapl(msgp->msg_iov); - for(i = 0;i < count; i++) { - vec[i].iov_base = (void *)tswapl(target_vec[i].iov_base); - vec[i].iov_len = tswapl(target_vec[i].iov_len); - } + target_vec = tswapl(msgp->msg_iov); + lock_iovec(vec, target_vec, count, send); msg.msg_iovlen = count; msg.msg_iov = vec; - fd = tswap32(vptr[0]); - flags = tswap32(vptr[2]); - if (num == SOCKOP_sendmsg) { + fd = tgetl(vptr); + flags = tgetl(vptr + 2 * n); + if (send) { target_to_host_cmsg(&msg, msgp); ret = get_errno(sendmsg(fd, &msg, flags)); } else { @@ -909,26 +1002,27 @@ static long do_socketcall(int num, int32_t *vptr) if (!is_error(ret)) host_to_target_cmsg(msgp, &msg); } + unlock_iovec(vec, target_vec, count, !send); } break; case SOCKOP_setsockopt: { - int sockfd = tswap32(vptr[0]); - int level = tswap32(vptr[1]); - int optname = tswap32(vptr[2]); - void *optval = (void *)tswap32(vptr[3]); - socklen_t optlen = tswap32(vptr[4]); + int sockfd = tgetl(vptr); + int level = tgetl(vptr + n); + int optname = tgetl(vptr + 2 * n); + target_ulong optval = tgetl(vptr + 3 * n); + socklen_t optlen = tgetl(vptr + 4 * n); ret = do_setsockopt(sockfd, level, optname, optval, optlen); } break; case SOCKOP_getsockopt: { - int sockfd = tswap32(vptr[0]); - int level = tswap32(vptr[1]); - int optname = tswap32(vptr[2]); - void *optval = (void *)tswap32(vptr[3]); - uint32_t *poptlen = (void *)tswap32(vptr[4]); + int sockfd = tgetl(vptr); + int level = tgetl(vptr + n); + int optname = tgetl(vptr + 2 * n); + target_ulong optval = tgetl(vptr + 3 * n); + target_ulong poptlen = tgetl(vptr + 4 * n); ret = do_getsockopt(sockfd, level, optname, optval, poptlen); } @@ -949,6 +1043,7 @@ static struct shm_region { uint32_t size; } shm_regions[N_SHM_REGIONS]; +/* ??? This only works with linear mappings. */ static long do_ipc(long call, long first, long second, long third, long ptr, long fifth) { @@ -1065,12 +1160,15 @@ IOCTLEntry ioctl_entries[] = { { 0, 0, }, }; +/* ??? Implement proper locking for ioctls. */ static long do_ioctl(long fd, long cmd, long arg) { const IOCTLEntry *ie; const argtype *arg_type; long ret; uint8_t buf_temp[MAX_STRUCT_SIZE]; + int target_size; + void *argptr; ie = ioctl_entries; for(;;) { @@ -1098,23 +1196,32 @@ static long do_ioctl(long fd, long cmd, long arg) break; case TYPE_PTR: arg_type++; + target_size = thunk_type_size(arg_type, 0); switch(ie->access) { case IOC_R: ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { - thunk_convert((void *)arg, buf_temp, arg_type, THUNK_TARGET); + argptr = lock_user(arg, target_size, 0); + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); } break; case IOC_W: - thunk_convert(buf_temp, (void *)arg, arg_type, THUNK_HOST); + argptr = lock_user(arg, target_size, 1); + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); break; default: case IOC_RW: - thunk_convert(buf_temp, (void *)arg, arg_type, THUNK_HOST); + argptr = lock_user(arg, target_size, 1); + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { - thunk_convert((void *)arg, buf_temp, arg_type, THUNK_TARGET); + argptr = lock_user(arg, target_size, 0); + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); } break; } @@ -1338,35 +1445,41 @@ static bitmask_transtbl fcntl_flags_tbl[] = { /* NOTE: there is really one LDT for all the threads */ uint8_t *ldt_table; -static int read_ldt(void *ptr, unsigned long bytecount) +static int read_ldt(target_ulong ptr, unsigned long bytecount) { int size; + void *p; if (!ldt_table) return 0; size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; - memcpy(ptr, ldt_table, size); + p = lock_user(ptr, size, 0); + /* ??? Shoudl this by byteswapped? */ + memcpy(p, ldt_table, size); + unlock_user(p, ptr, size); return size; } /* XXX: add locking support */ static int write_ldt(CPUX86State *env, - void *ptr, unsigned long bytecount, int oldmode) + target_ulong ptr, unsigned long bytecount, int oldmode) { struct target_modify_ldt_ldt_s ldt_info; + struct target_modify_ldt_ldt_s *target_ldt_info; int seg_32bit, contents, read_exec_only, limit_in_pages; int seg_not_present, useable; uint32_t *lp, entry_1, entry_2; if (bytecount != sizeof(ldt_info)) return -EINVAL; - memcpy(&ldt_info, ptr, sizeof(ldt_info)); - tswap32s(&ldt_info.entry_number); - tswapls((long *)&ldt_info.base_addr); - tswap32s(&ldt_info.limit); - tswap32s(&ldt_info.flags); + lock_user_struct(target_ldt_info, ptr, 1); + ldt_info.entry_number = tswap32(target_ldt_info->entry_number); + ldt_info.base_addr = tswapl(target_ldt_info->base_addr); + ldt_info.limit = tswap32(target_ldt_info->limit); + ldt_info.flags = tswap32(target_ldt_info->flags); + unlock_user_struct(target_ldt_info, ptr, 0); if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) return -EINVAL; @@ -1389,7 +1502,7 @@ static int write_ldt(CPUX86State *env, if (!ldt_table) return -ENOMEM; memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); - env->ldt.base = (long)ldt_table; + env->ldt.base = h2g(ldt_table); env->ldt.limit = 0xffff; } @@ -1432,7 +1545,7 @@ install: } /* specific and weird i386 syscalls */ -int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount) +int do_modify_ldt(CPUX86State *env, int func, target_ulong ptr, unsigned long bytecount) { int ret = -ENOSYS; @@ -1523,31 +1636,35 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) return ret; } -static long do_fcntl(int fd, int cmd, unsigned long arg) +static long do_fcntl(int fd, int cmd, target_ulong arg) { struct flock fl; - struct target_flock *target_fl = (void *)arg; + struct target_flock *target_fl; long ret; - + switch(cmd) { case TARGET_F_GETLK: ret = fcntl(fd, cmd, &fl); if (ret == 0) { + lock_user_struct(target_fl, arg, 0); target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswapl(fl.l_start); target_fl->l_len = tswapl(fl.l_len); target_fl->l_pid = tswapl(fl.l_pid); + unlock_user_struct(target_fl, arg, 1); } break; case TARGET_F_SETLK: case TARGET_F_SETLKW: + lock_user_struct(target_fl, arg, 1); fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); fl.l_len = tswapl(target_fl->l_len); fl.l_pid = tswapl(target_fl->l_pid); + unlock_user_struct(target_fl, arg, 0); ret = fcntl(fd, cmd, &fl); break; @@ -1690,12 +1807,35 @@ static inline long target_ftruncate64(void *cpu_env, long arg1, long arg2, } #endif +static inline void target_to_host_timespec(struct timespec *host_ts, + target_ulong target_addr) +{ + struct target_timespec *target_ts; + + lock_user_struct(target_ts, target_addr, 1); + host_ts->tv_sec = tswapl(target_ts->tv_sec); + host_ts->tv_nsec = tswapl(target_ts->tv_nsec); + unlock_user_struct(target_ts, target_addr, 0); +} + +static inline void host_to_target_timespec(target_ulong target_addr, + struct timespec *host_ts) +{ + struct target_timespec *target_ts; + + lock_user_struct(target_ts, target_addr, 0); + target_ts->tv_sec = tswapl(host_ts->tv_sec); + target_ts->tv_nsec = tswapl(host_ts->tv_nsec); + unlock_user_struct(target_ts, target_addr, 1); +} + long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { long ret; struct stat st; struct statfs stfs; + void *p; #ifdef DEBUG gemu_log("syscall %d", num); @@ -1711,89 +1851,140 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = 0; /* avoid warning */ break; case TARGET_NR_read: - page_unprotect_range((void *)arg2, arg3); - ret = get_errno(read(arg1, (void *)arg2, arg3)); + page_unprotect_range(arg2, arg3); + p = lock_user(arg2, arg3, 0); + ret = get_errno(read(arg1, p, arg3)); + unlock_user(p, arg2, ret); break; case TARGET_NR_write: - ret = get_errno(write(arg1, (void *)arg2, arg3)); + p = lock_user(arg2, arg3, 1); + ret = get_errno(write(arg1, p, arg3)); + unlock_user(p, arg2, 0); break; case TARGET_NR_open: - ret = get_errno(open(path((const char *)arg1), + p = lock_user_string(arg1); + ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3)); + unlock_user(p, arg1, 0); break; case TARGET_NR_close: ret = get_errno(close(arg1)); break; case TARGET_NR_brk: - ret = do_brk((char *)arg1); + ret = do_brk(arg1); break; case TARGET_NR_fork: ret = get_errno(do_fork(cpu_env, SIGCHLD, 0)); break; case TARGET_NR_waitpid: { - int *status = (int *)arg2; - ret = get_errno(waitpid(arg1, status, arg3)); - if (!is_error(ret) && status) - tswapls((long *)&status); + int status; + ret = get_errno(waitpid(arg1, &status, arg3)); + if (!is_error(ret) && arg2) + tput32(arg2, status); } break; case TARGET_NR_creat: - ret = get_errno(creat((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(creat(p, arg2)); + unlock_user(p, arg1, 0); break; case TARGET_NR_link: - ret = get_errno(link((const char *)arg1, (const char *)arg2)); + { + void * p2; + p = lock_user_string(arg1); + p2 = lock_user_string(arg2); + ret = get_errno(link(p, p2)); + unlock_user(p2, arg2, 0); + unlock_user(p, arg1, 0); + } break; case TARGET_NR_unlink: - ret = get_errno(unlink((const char *)arg1)); + p = lock_user_string(arg1); + ret = get_errno(unlink(p)); + unlock_user(p, arg1, 0); break; case TARGET_NR_execve: { char **argp, **envp; int argc, envc; - uint32_t *p; + target_ulong gp; + target_ulong guest_argp; + target_ulong guest_envp; + target_ulong addr; char **q; argc = 0; - for (p = (void *)arg2; *p; p++) + guest_argp = arg2; + for (gp = guest_argp; tgetl(gp); gp++) argc++; envc = 0; - for (p = (void *)arg3; *p; p++) + guest_envp = arg3; + for (gp = guest_envp; tgetl(gp); gp++) envc++; argp = alloca((argc + 1) * sizeof(void *)); envp = alloca((envc + 1) * sizeof(void *)); - for (p = (void *)arg2, q = argp; *p; p++, q++) - *q = (void *)tswap32(*p); + for (gp = guest_argp, q = argp; ; + gp += sizeof(target_ulong), q++) { + addr = tgetl(gp); + if (!addr) + break; + *q = lock_user_string(addr); + } *q = NULL; - for (p = (void *)arg3, q = envp; *p; p++, q++) - *q = (void *)tswap32(*p); + for (gp = guest_envp, q = envp; ; + gp += sizeof(target_ulong), q++) { + addr = tgetl(gp); + if (!addr) + break; + *q = lock_user_string(addr); + } *q = NULL; - ret = get_errno(execve((const char *)arg1, argp, envp)); + p = lock_user_string(arg1); + ret = get_errno(execve(p, argp, envp)); + unlock_user(p, arg1, 0); + + for (gp = guest_argp, q = argp; *q; + gp += sizeof(target_ulong), q++) { + addr = tgetl(gp); + unlock_user(*q, addr, 0); + } + for (gp = guest_envp, q = envp; *q; + gp += sizeof(target_ulong), q++) { + addr = tgetl(gp); + unlock_user(*q, addr, 0); + } } break; case TARGET_NR_chdir: - ret = get_errno(chdir((const char *)arg1)); + p = lock_user_string(arg1); + ret = get_errno(chdir(p)); + unlock_user(p, arg1, 0); break; #ifdef TARGET_NR_time case TARGET_NR_time: { - int *time_ptr = (int *)arg1; - ret = get_errno(time((time_t *)time_ptr)); - if (!is_error(ret) && time_ptr) - tswap32s(time_ptr); + time_t host_time; + ret = get_errno(time(&host_time)); + if (!is_error(ret) && arg1) + tputl(arg1, host_time); } break; #endif case TARGET_NR_mknod: - ret = get_errno(mknod((const char *)arg1, arg2, arg3)); + p = lock_user_string(arg1); + ret = get_errno(mknod(p, arg2, arg3)); + unlock_user(p, arg1, 0); break; case TARGET_NR_chmod: - ret = get_errno(chmod((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(chmod(p, arg2)); + unlock_user(p, arg1, 0); break; #ifdef TARGET_NR_break case TARGET_NR_break: @@ -1813,14 +2004,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, /* need to look at the data field */ goto unimplemented; case TARGET_NR_umount: - ret = get_errno(umount((const char *)arg1)); + p = lock_user_string(arg1); + ret = get_errno(umount(p)); + unlock_user(p, arg1, 0); break; case TARGET_NR_stime: { - int *time_ptr = (int *)arg1; - if (time_ptr) - tswap32s(time_ptr); - ret = get_errno(stime((time_t *)time_ptr)); + time_t host_time; + host_time = tgetl(arg1); + ret = get_errno(stime(&host_time)); } break; case TARGET_NR_ptrace: @@ -1837,30 +2029,36 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_utime: { - struct utimbuf tbuf, *tbuf1; - struct target_utimbuf *target_tbuf = (void *)arg2; - if (target_tbuf) { - get_user(tbuf.actime, &target_tbuf->actime); - get_user(tbuf.modtime, &target_tbuf->modtime); - tbuf1 = &tbuf; + struct utimbuf tbuf, *host_tbuf; + struct target_utimbuf *target_tbuf; + if (arg2) { + lock_user_struct(target_tbuf, arg2, 1); + tbuf.actime = tswapl(target_tbuf->actime); + tbuf.modtime = tswapl(target_tbuf->modtime); + unlock_user_struct(target_tbuf, arg2, 0); + host_tbuf = &tbuf; } else { - tbuf1 = NULL; + host_tbuf = NULL; } - ret = get_errno(utime((const char *)arg1, tbuf1)); + p = lock_user_string(arg1); + ret = get_errno(utime(p, host_tbuf)); + unlock_user(p, arg1, 0); } break; case TARGET_NR_utimes: { - struct target_timeval *target_tvp = (struct target_timeval *)arg2; struct timeval *tvp, tv[2]; - if (target_tvp) { - target_to_host_timeval(&tv[0], &target_tvp[0]); - target_to_host_timeval(&tv[1], &target_tvp[1]); + if (arg2) { + target_to_host_timeval(&tv[0], arg2); + target_to_host_timeval(&tv[1], + arg2 + sizeof (struct target_timeval)); tvp = tv; } else { tvp = NULL; } - ret = get_errno(utimes((const char *)arg1, tvp)); + p = lock_user_string(arg1); + ret = get_errno(utimes(p, tvp)); + unlock_user(p, arg1, 0); } break; #ifdef TARGET_NR_stty @@ -1872,7 +2070,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; #endif case TARGET_NR_access: - ret = get_errno(access((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(access(p, arg2)); + unlock_user(p, arg1, 0); break; case TARGET_NR_nice: ret = get_errno(nice(arg1)); @@ -1889,33 +2089,45 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(kill(arg1, arg2)); break; case TARGET_NR_rename: - ret = get_errno(rename((const char *)arg1, (const char *)arg2)); + { + void *p2; + p = lock_user_string(arg1); + p2 = lock_user_string(arg2); + ret = get_errno(rename(p, p2)); + unlock_user(p2, arg2, 0); + unlock_user(p, arg1, 0); + } break; case TARGET_NR_mkdir: - ret = get_errno(mkdir((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(mkdir(p, arg2)); + unlock_user(p, arg1, 0); break; case TARGET_NR_rmdir: - ret = get_errno(rmdir((const char *)arg1)); + p = lock_user_string(arg1); + ret = get_errno(rmdir(p)); + unlock_user(p, arg1, 0); break; case TARGET_NR_dup: ret = get_errno(dup(arg1)); break; case TARGET_NR_pipe: { - int *pipe_ptr = (int *)arg1; - ret = get_errno(pipe(pipe_ptr)); + int host_pipe[2]; + ret = get_errno(pipe(host_pipe)); if (!is_error(ret)) { - tswap32s(&pipe_ptr[0]); - tswap32s(&pipe_ptr[1]); + tput32(arg1, host_pipe[0]); + tput32(arg1 + 4, host_pipe[1]); } } break; case TARGET_NR_times: { - struct target_tms *tmsp = (void *)arg1; + struct target_tms *tmsp; struct tms tms; ret = get_errno(times(&tms)); - if (tmsp) { + if (arg1) { + tmsp = lock_user(arg1, sizeof(struct target_tms), 0); tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime)); tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime)); tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime)); @@ -1935,7 +2147,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_acct: goto unimplemented; case TARGET_NR_umount2: - ret = get_errno(umount2((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(umount2(p, arg2)); + unlock_user(p, arg1, 0); break; #ifdef TARGET_NR_lock case TARGET_NR_lock: @@ -1966,7 +2180,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(umask(arg1)); break; case TARGET_NR_chroot: - ret = get_errno(chroot((const char *)arg1)); + p = lock_user_string(arg1); + ret = get_errno(chroot(p)); + unlock_user(p, arg1, 0); break; case TARGET_NR_ustat: goto unimplemented; @@ -1984,29 +2200,49 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_sigaction: { - struct target_old_sigaction *old_act = (void *)arg2; - struct target_old_sigaction *old_oact = (void *)arg3; + struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; - if (old_act) { + if (arg2) { + lock_user_struct(old_act, arg2, 1); act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask); act.sa_flags = old_act->sa_flags; act.sa_restorer = old_act->sa_restorer; + unlock_user_struct(old_act, arg2, 0); pact = &act; } else { pact = NULL; } ret = get_errno(do_sigaction(arg1, pact, &oact)); - if (!is_error(ret) && old_oact) { - old_oact->_sa_handler = oact._sa_handler; - old_oact->sa_mask = oact.sa_mask.sig[0]; - old_oact->sa_flags = oact.sa_flags; - old_oact->sa_restorer = oact.sa_restorer; + if (!is_error(ret) && arg3) { + lock_user_struct(old_act, arg3, 0); + old_act->_sa_handler = oact._sa_handler; + old_act->sa_mask = oact.sa_mask.sig[0]; + old_act->sa_flags = oact.sa_flags; + old_act->sa_restorer = oact.sa_restorer; + unlock_user_struct(old_act, arg3, 1); } } break; case TARGET_NR_rt_sigaction: - ret = get_errno(do_sigaction(arg1, (void *)arg2, (void *)arg3)); + { + struct target_sigaction *act; + struct target_sigaction *oact; + + if (arg2) + lock_user_struct(act, arg2, 1); + else + act = NULL; + if (arg3) + lock_user_struct(oact, arg3, 0); + else + oact = NULL; + ret = get_errno(do_sigaction(arg1, act, oact)); + if (arg2) + unlock_user_struct(act, arg2, 0); + if (arg3) + unlock_user_struct(oact, arg3, 1); + } break; case TARGET_NR_sgetmask: { @@ -2033,9 +2269,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { int how = arg1; sigset_t set, oldset, *set_ptr; - target_ulong *pset = (void *)arg2, *poldset = (void *)arg3; - if (pset) { + if (arg2) { switch(how) { case TARGET_SIG_BLOCK: how = SIG_BLOCK; @@ -2050,15 +2285,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = -EINVAL; goto fail; } - target_to_host_old_sigset(&set, pset); + p = lock_user(arg2, sizeof(target_sigset_t), 1); + target_to_host_old_sigset(&set, p); + unlock_user(p, arg2, 0); set_ptr = &set; } else { how = 0; set_ptr = NULL; } ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); - if (!is_error(ret) && poldset) { - host_to_target_old_sigset(poldset, &oldset); + if (!is_error(ret) && arg3) { + p = lock_user(arg3, sizeof(target_sigset_t), 0); + host_to_target_old_sigset(p, &oldset); + unlock_user(p, arg3, sizeof(target_sigset_t)); } } break; @@ -2066,10 +2305,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { int how = arg1; sigset_t set, oldset, *set_ptr; - target_sigset_t *pset = (void *)arg2; - target_sigset_t *poldset = (void *)arg3; - if (pset) { + if (arg2) { switch(how) { case TARGET_SIG_BLOCK: how = SIG_BLOCK; @@ -2084,15 +2321,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = -EINVAL; goto fail; } - target_to_host_sigset(&set, pset); + p = lock_user(arg2, sizeof(target_sigset_t), 1); + target_to_host_sigset(&set, p); + unlock_user(p, arg2, 0); set_ptr = &set; } else { how = 0; set_ptr = NULL; } ret = get_errno(sigprocmask(how, set_ptr, &oldset)); - if (!is_error(ret) && poldset) { - host_to_target_sigset(poldset, &oldset); + if (!is_error(ret) && arg3) { + p = lock_user(arg3, sizeof(target_sigset_t), 0); + host_to_target_sigset(p, &oldset); + unlock_user(p, arg3, sizeof(target_sigset_t)); } } break; @@ -2101,7 +2342,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - host_to_target_old_sigset((target_ulong *)arg1, &set); + p = lock_user(arg1, sizeof(target_sigset_t), 0); + host_to_target_old_sigset(p, &set); + unlock_user(p, arg1, sizeof(target_sigset_t)); } } break; @@ -2110,51 +2353,59 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - host_to_target_sigset((target_sigset_t *)arg1, &set); + p = lock_user(arg1, sizeof(target_sigset_t), 0); + host_to_target_sigset(p, &set); + unlock_user(p, arg1, sizeof(target_sigset_t)); } } break; case TARGET_NR_sigsuspend: { sigset_t set; - target_to_host_old_sigset(&set, (target_ulong *)arg1); + p = lock_user(arg1, sizeof(target_sigset_t), 1); + target_to_host_old_sigset(&set, p); + unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); } break; case TARGET_NR_rt_sigsuspend: { sigset_t set; - target_to_host_sigset(&set, (target_sigset_t *)arg1); + p = lock_user(arg1, sizeof(target_sigset_t), 1); + target_to_host_sigset(&set, p); + unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); } break; case TARGET_NR_rt_sigtimedwait: { - target_sigset_t *target_set = (void *)arg1; - target_siginfo_t *target_uinfo = (void *)arg2; - struct target_timespec *target_uts = (void *)arg3; sigset_t set; struct timespec uts, *puts; siginfo_t uinfo; - target_to_host_sigset(&set, target_set); - if (target_uts) { + p = lock_user(arg1, sizeof(target_sigset_t), 1); + target_to_host_sigset(&set, p); + unlock_user(p, arg1, 0); + if (arg3) { puts = &uts; - puts->tv_sec = tswapl(target_uts->tv_sec); - puts->tv_nsec = tswapl(target_uts->tv_nsec); + target_to_host_timespec(puts, arg3); } else { puts = NULL; } ret = get_errno(sigtimedwait(&set, &uinfo, puts)); - if (!is_error(ret) && target_uinfo) { - host_to_target_siginfo(target_uinfo, &uinfo); + if (!is_error(ret) && arg2) { + p = lock_user(arg2, sizeof(target_sigset_t), 0); + host_to_target_siginfo(p, &uinfo); + unlock_user(p, arg2, sizeof(target_sigset_t)); } } break; case TARGET_NR_rt_sigqueueinfo: { siginfo_t uinfo; - target_to_host_siginfo(&uinfo, (target_siginfo_t *)arg3); + p = lock_user(arg3, sizeof(target_sigset_t), 1); + target_to_host_siginfo(&uinfo, p); + unlock_user(p, arg1, 0); ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); } break; @@ -2167,16 +2418,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = do_rt_sigreturn(cpu_env); break; case TARGET_NR_sethostname: - ret = get_errno(sethostname((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(sethostname(p, arg2)); + unlock_user(p, arg1, 0); break; case TARGET_NR_setrlimit: { /* XXX: convert resource ? */ int resource = arg1; - struct target_rlimit *target_rlim = (void *)arg2; + struct target_rlimit *target_rlim; struct rlimit rlim; + lock_user_struct(target_rlim, arg2, 1); rlim.rlim_cur = tswapl(target_rlim->rlim_cur); rlim.rlim_max = tswapl(target_rlim->rlim_max); + unlock_user_struct(target_rlim, arg2, 0); ret = get_errno(setrlimit(resource, &rlim)); } break; @@ -2184,72 +2439,91 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { /* XXX: convert resource ? */ int resource = arg1; - struct target_rlimit *target_rlim = (void *)arg2; + struct target_rlimit *target_rlim; struct rlimit rlim; ret = get_errno(getrlimit(resource, &rlim)); if (!is_error(ret)) { - target_rlim->rlim_cur = tswapl(rlim.rlim_cur); - target_rlim->rlim_max = tswapl(rlim.rlim_max); + lock_user_struct(target_rlim, arg2, 0); + rlim.rlim_cur = tswapl(target_rlim->rlim_cur); + rlim.rlim_max = tswapl(target_rlim->rlim_max); + unlock_user_struct(target_rlim, arg2, 1); } } break; case TARGET_NR_getrusage: { struct rusage rusage; - struct target_rusage *target_rusage = (void *)arg2; ret = get_errno(getrusage(arg1, &rusage)); if (!is_error(ret)) { - host_to_target_rusage(target_rusage, &rusage); + host_to_target_rusage(arg2, &rusage); } } break; case TARGET_NR_gettimeofday: { - struct target_timeval *target_tv = (void *)arg1; struct timeval tv; ret = get_errno(gettimeofday(&tv, NULL)); if (!is_error(ret)) { - host_to_target_timeval(target_tv, &tv); + host_to_target_timeval(arg1, &tv); } } break; case TARGET_NR_settimeofday: { - struct target_timeval *target_tv = (void *)arg1; struct timeval tv; - target_to_host_timeval(&tv, target_tv); + target_to_host_timeval(&tv, arg1); ret = get_errno(settimeofday(&tv, NULL)); } break; #ifdef TARGET_NR_select case TARGET_NR_select: { - struct target_sel_arg_struct *sel = (void *)arg1; - sel->n = tswapl(sel->n); - sel->inp = tswapl(sel->inp); - sel->outp = tswapl(sel->outp); - sel->exp = tswapl(sel->exp); - sel->tvp = tswapl(sel->tvp); - ret = do_select(sel->n, (void *)sel->inp, (void *)sel->outp, - (void *)sel->exp, (void *)sel->tvp); + struct target_sel_arg_struct *sel; + target_ulong inp, outp, exp, tvp; + long nsel; + + lock_user_struct(sel, arg1, 1); + nsel = tswapl(sel->n); + inp = tswapl(sel->inp); + outp = tswapl(sel->outp); + exp = tswapl(sel->exp); + tvp = tswapl(sel->tvp); + unlock_user_struct(sel, arg1, 0); + ret = do_select(nsel, inp, outp, exp, tvp); } break; #endif case TARGET_NR_symlink: - ret = get_errno(symlink((const char *)arg1, (const char *)arg2)); + { + void *p2; + p = lock_user_string(arg1); + p2 = lock_user_string(arg2); + ret = get_errno(symlink(p, p2)); + unlock_user(p2, arg2, 0); + unlock_user(p, arg1, 0); + } break; #ifdef TARGET_NR_oldlstat case TARGET_NR_oldlstat: goto unimplemented; #endif case TARGET_NR_readlink: - ret = get_errno(readlink(path((const char *)arg1), (char *)arg2, arg3)); + { + void *p2; + p = lock_user_string(arg1); + p2 = lock_user(arg2, arg3, 0); + ret = get_errno(readlink(path(p), p2, arg3)); + unlock_user(p2, arg2, ret); + unlock_user(p, arg1, 0); + } break; case TARGET_NR_uselib: goto unimplemented; case TARGET_NR_swapon: - ret = get_errno(swapon((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(swapon(p, arg2)); + unlock_user(p, arg1, 0); break; case TARGET_NR_reboot: goto unimplemented; @@ -2258,14 +2532,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_mmap: #if defined(TARGET_I386) || defined(TARGET_ARM) { - uint32_t v1, v2, v3, v4, v5, v6, *vptr; - vptr = (uint32_t *)arg1; - v1 = tswap32(vptr[0]); - v2 = tswap32(vptr[1]); - v3 = tswap32(vptr[2]); - v4 = tswap32(vptr[3]); - v5 = tswap32(vptr[4]); - v6 = tswap32(vptr[5]); + target_ulong *v; + target_ulong v1, v2, v3, v4, v5, v6; + v = lock_user(arg1, 6 * sizeof(target_ulong), 1); + v1 = tswapl(v[0]); + v2 = tswapl(v[1]); + v3 = tswapl(v[2]); + v4 = tswapl(v[3]); + v5 = tswapl(v[4]); + v6 = tswapl(v[5]); + unlock_user(v, arg1, 0); ret = get_errno(target_mmap(v1, v2, v3, target_to_host_bitmask(v4, mmap_flags_tbl), v5, v6)); @@ -2299,14 +2575,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_mremap: ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5)); break; + /* ??? msync/mlock/munlock are broken for softmmu. */ case TARGET_NR_msync: - ret = get_errno(msync((void *)arg1, arg2, arg3)); + ret = get_errno(msync(g2h(arg1), arg2, arg3)); break; case TARGET_NR_mlock: - ret = get_errno(mlock((void *)arg1, arg2)); + ret = get_errno(mlock(g2h(arg1), arg2)); break; case TARGET_NR_munlock: - ret = get_errno(munlock((void *)arg1, arg2)); + ret = get_errno(munlock(g2h(arg1), arg2)); break; case TARGET_NR_mlockall: ret = get_errno(mlockall(arg1)); @@ -2315,7 +2592,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(munlockall()); break; case TARGET_NR_truncate: - ret = get_errno(truncate((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(truncate(p, arg2)); + unlock_user(p, arg1, 0); break; case TARGET_NR_ftruncate: ret = get_errno(ftruncate(arg1, arg2)); @@ -2334,11 +2613,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; #endif case TARGET_NR_statfs: - ret = get_errno(statfs(path((const char *)arg1), &stfs)); + p = lock_user_string(arg1); + ret = get_errno(statfs(path(p), &stfs)); + unlock_user(p, arg1, 0); convert_statfs: if (!is_error(ret)) { - struct target_statfs *target_stfs = (void *)arg2; + struct target_statfs *target_stfs; + lock_user_struct(target_stfs, arg2, 0); + /* ??? put_user is probably wrong. */ put_user(stfs.f_type, &target_stfs->f_type); put_user(stfs.f_bsize, &target_stfs->f_bsize); put_user(stfs.f_blocks, &target_stfs->f_blocks); @@ -2348,6 +2631,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, put_user(stfs.f_ffree, &target_stfs->f_ffree); put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid); put_user(stfs.f_namelen, &target_stfs->f_namelen); + unlock_user_struct(target_stfs, arg2, 1); } break; case TARGET_NR_fstatfs: @@ -2355,11 +2639,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto convert_statfs; #ifdef TARGET_NR_statfs64 case TARGET_NR_statfs64: - ret = get_errno(statfs(path((const char *)arg1), &stfs)); + p = lock_user_string(arg1); + ret = get_errno(statfs(path(p), &stfs)); + unlock_user(p, arg1, 0); convert_statfs64: if (!is_error(ret)) { - struct target_statfs64 *target_stfs = (void *)arg3; - + struct target_statfs64 *target_stfs; + + lock_user_struct(target_stfs, arg3, 0); + /* ??? put_user is probably wrong. */ put_user(stfs.f_type, &target_stfs->f_type); put_user(stfs.f_bsize, &target_stfs->f_bsize); put_user(stfs.f_blocks, &target_stfs->f_blocks); @@ -2369,6 +2657,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, put_user(stfs.f_ffree, &target_stfs->f_ffree); put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid); put_user(stfs.f_namelen, &target_stfs->f_namelen); + unlock_user_struct(target_stfs, arg3, 0); } break; case TARGET_NR_fstatfs64: @@ -2380,60 +2669,63 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; #endif case TARGET_NR_socketcall: - ret = do_socketcall(arg1, (int32_t *)arg2); + ret = do_socketcall(arg1, arg2); break; case TARGET_NR_syslog: goto unimplemented; case TARGET_NR_setitimer: { - struct target_itimerval *target_value = (void *)arg2; - struct target_itimerval *target_ovalue = (void *)arg3; struct itimerval value, ovalue, *pvalue; - if (target_value) { + if (arg2) { pvalue = &value; target_to_host_timeval(&pvalue->it_interval, - &target_value->it_interval); + arg2); target_to_host_timeval(&pvalue->it_value, - &target_value->it_value); + arg2 + sizeof(struct target_timeval)); } else { pvalue = NULL; } ret = get_errno(setitimer(arg1, pvalue, &ovalue)); - if (!is_error(ret) && target_ovalue) { - host_to_target_timeval(&target_ovalue->it_interval, + if (!is_error(ret) && arg3) { + host_to_target_timeval(arg3, &ovalue.it_interval); - host_to_target_timeval(&target_ovalue->it_value, + host_to_target_timeval(arg3 + sizeof(struct target_timeval), &ovalue.it_value); } } break; case TARGET_NR_getitimer: { - struct target_itimerval *target_value = (void *)arg2; struct itimerval value; ret = get_errno(getitimer(arg1, &value)); - if (!is_error(ret) && target_value) { - host_to_target_timeval(&target_value->it_interval, + if (!is_error(ret) && arg2) { + host_to_target_timeval(arg2, &value.it_interval); - host_to_target_timeval(&target_value->it_value, + host_to_target_timeval(arg2 + sizeof(struct target_timeval), &value.it_value); } } break; case TARGET_NR_stat: - ret = get_errno(stat(path((const char *)arg1), &st)); + p = lock_user_string(arg1); + ret = get_errno(stat(path(p), &st)); + unlock_user(p, arg1, 0); goto do_stat; case TARGET_NR_lstat: - ret = get_errno(lstat(path((const char *)arg1), &st)); + p = lock_user_string(arg1); + ret = get_errno(lstat(path(p), &st)); + unlock_user(p, arg1, 0); goto do_stat; case TARGET_NR_fstat: { ret = get_errno(fstat(arg1, &st)); do_stat: if (!is_error(ret)) { - struct target_stat *target_st = (void *)arg2; + struct target_stat *target_st; + + lock_user_struct(target_st, arg2, 0); target_st->st_dev = tswap16(st.st_dev); target_st->st_ino = tswapl(st.st_ino); #if defined(TARGET_PPC) @@ -2453,6 +2745,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, target_st->target_st_atime = tswapl(st.st_atime); target_st->target_st_mtime = tswapl(st.st_mtime); target_st->target_st_ctime = tswapl(st.st_ctime); + unlock_user_struct(target_st, arg2, 1); } } break; @@ -2479,9 +2772,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_wait4: { int status; - target_long *status_ptr = (void *)arg2; + target_long status_ptr = arg2; struct rusage rusage, *rusage_ptr; - struct target_rusage *target_rusage = (void *)arg4; + target_ulong target_rusage = arg4; if (target_rusage) rusage_ptr = &rusage; else @@ -2489,7 +2782,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); if (!is_error(ret)) { if (status_ptr) - *status_ptr = tswap32(status); + tputl(status_ptr, status); if (target_rusage) { host_to_target_rusage(target_rusage, &rusage); } @@ -2497,15 +2790,19 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; case TARGET_NR_swapoff: - ret = get_errno(swapoff((const char *)arg1)); + p = lock_user_string(arg1); + ret = get_errno(swapoff(p)); + unlock_user(p, arg1, 0); break; case TARGET_NR_sysinfo: { - struct target_sysinfo *target_value = (void *)arg1; + struct target_sysinfo *target_value; struct sysinfo value; ret = get_errno(sysinfo(&value)); - if (!is_error(ret) && target_value) + if (!is_error(ret) && arg1) { + /* ??? __put_user is probably wrong. */ + lock_user_struct(target_value, arg1, 0); __put_user(value.uptime, &target_value->uptime); __put_user(value.loads[0], &target_value->loads[0]); __put_user(value.loads[1], &target_value->loads[1]); @@ -2520,6 +2817,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, __put_user(value.totalhigh, &target_value->totalhigh); __put_user(value.freehigh, &target_value->freehigh); __put_user(value.mem_unit, &target_value->mem_unit); + unlock_user_struct(target_value, arg1, 1); } } break; @@ -2540,30 +2838,33 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #endif case TARGET_NR_setdomainname: - ret = get_errno(setdomainname((const char *)arg1, arg2)); + p = lock_user_string(arg1); + ret = get_errno(setdomainname(p, arg2)); + unlock_user(p, arg1, 0); break; case TARGET_NR_uname: /* no need to transcode because we use the linux syscall */ { struct new_utsname * buf; - buf = (struct new_utsname *)arg1; + lock_user_struct(buf, arg1, 0); ret = get_errno(sys_uname(buf)); if (!is_error(ret)) { /* Overrite the native machine name with whatever is being emulated. */ strcpy (buf->machine, UNAME_MACHINE); } + unlock_user_struct(buf, arg1, 1); } break; #ifdef TARGET_I386 case TARGET_NR_modify_ldt: - ret = get_errno(do_modify_ldt(cpu_env, arg1, (void *)arg2, arg3)); + ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3)); break; case TARGET_NR_vm86old: goto unimplemented; case TARGET_NR_vm86: - ret = do_vm86(cpu_env, arg1, (void *)arg2); + ret = do_vm86(cpu_env, arg1, arg2); break; #endif case TARGET_NR_adjtimex: @@ -2594,20 +2895,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { #if defined (__x86_64__) ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5)); - *(int64_t *)arg4 = ret; + tput64(arg4, ret); #else int64_t res; ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5)); - *(int64_t *)arg4 = tswap64(res); + tput64(arg4, res); #endif } break; case TARGET_NR_getdents: #if TARGET_LONG_SIZE != 4 + goto unimplemented; #warning not supported #elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8 { - struct target_dirent *target_dirp = (void *)arg2; + struct target_dirent *target_dirp; struct dirent *dirp; long count = arg3; @@ -2625,6 +2927,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, count1 = 0; de = dirp; + target_dirp = lock_user(arg2, count, 0); tde = target_dirp; while (len > 0) { reclen = de->d_reclen; @@ -2644,13 +2947,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } ret = count1; } + unlock_user(target_dirp, arg2, ret); free(dirp); } #else { - struct dirent *dirp = (void *)arg2; + struct dirent *dirp; long count = arg3; + dirp = lock_user(arg2, count, 0); ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { struct dirent *de; @@ -2668,14 +2973,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, len -= reclen; } } + unlock_user(dirp, arg2, ret); } #endif break; #ifdef TARGET_NR_getdents64 case TARGET_NR_getdents64: { - struct dirent64 *dirp = (void *)arg2; + struct dirent64 *dirp; long count = arg3; + dirp = lock_user(arg2, count, 0); ret = get_errno(sys_getdents64(arg1, dirp, count)); if (!is_error(ret)) { struct dirent64 *de; @@ -2693,21 +3000,22 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, len -= reclen; } } + unlock_user(dirp, arg2, ret); } break; #endif /* TARGET_NR_getdents64 */ case TARGET_NR__newselect: - ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, - (void *)arg5); + ret = do_select(arg1, arg2, arg3, arg4, arg5); break; case TARGET_NR_poll: { - struct target_pollfd *target_pfd = (void *)arg1; + struct target_pollfd *target_pfd; unsigned int nfds = arg2; int timeout = arg3; struct pollfd *pfd; unsigned int i; + target_pfd = lock_user(arg1, sizeof(struct target_pollfd) * nfds, 1); pfd = alloca(sizeof(struct pollfd) * nfds); for(i = 0; i < nfds; i++) { pfd[i].fd = tswap32(target_pfd[i].fd); @@ -2718,7 +3026,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, for(i = 0; i < nfds; i++) { target_pfd[i].revents = tswap16(pfd[i].revents); } + ret += nfds * (sizeof(struct target_pollfd) + - sizeof(struct pollfd)); } + unlock_user(target_pfd, arg1, ret); } break; case TARGET_NR_flock: @@ -2729,31 +3040,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_readv: { int count = arg3; - int i; struct iovec *vec; - struct target_iovec *target_vec = (void *)arg2; vec = alloca(count * sizeof(struct iovec)); - for(i = 0;i < count; i++) { - vec[i].iov_base = (void *)tswapl(target_vec[i].iov_base); - vec[i].iov_len = tswapl(target_vec[i].iov_len); - } + lock_iovec(vec, arg2, count, 0); ret = get_errno(readv(arg1, vec, count)); + unlock_iovec(vec, arg2, count, 1); } break; case TARGET_NR_writev: { int count = arg3; - int i; struct iovec *vec; - struct target_iovec *target_vec = (void *)arg2; vec = alloca(count * sizeof(struct iovec)); - for(i = 0;i < count; i++) { - vec[i].iov_base = (void *)tswapl(target_vec[i].iov_base); - vec[i].iov_len = tswapl(target_vec[i].iov_len); - } + lock_iovec(vec, arg2, count, 1); ret = get_errno(writev(arg1, vec, count)); + unlock_iovec(vec, arg2, count, 0); } break; case TARGET_NR_getsid: @@ -2768,27 +3071,34 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, return -ENOTDIR; case TARGET_NR_sched_setparam: { - struct sched_param *target_schp = (void *)arg2; + struct sched_param *target_schp; struct sched_param schp; + + lock_user_struct(target_schp, arg2, 1); schp.sched_priority = tswap32(target_schp->sched_priority); + unlock_user_struct(target_schp, arg2, 0); ret = get_errno(sched_setparam(arg1, &schp)); } break; case TARGET_NR_sched_getparam: { - struct sched_param *target_schp = (void *)arg2; + struct sched_param *target_schp; struct sched_param schp; ret = get_errno(sched_getparam(arg1, &schp)); if (!is_error(ret)) { + lock_user_struct(target_schp, arg2, 0); target_schp->sched_priority = tswap32(schp.sched_priority); + unlock_user_struct(target_schp, arg2, 1); } } break; case TARGET_NR_sched_setscheduler: { - struct sched_param *target_schp = (void *)arg3; + struct sched_param *target_schp; struct sched_param schp; + lock_user_struct(target_schp, arg3, 1); schp.sched_priority = tswap32(target_schp->sched_priority); + unlock_user_struct(target_schp, arg3, 0); ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); } break; @@ -2806,26 +3116,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_sched_rr_get_interval: { - struct target_timespec *target_ts = (void *)arg2; struct timespec ts; ret = get_errno(sched_rr_get_interval(arg1, &ts)); if (!is_error(ret)) { - target_ts->tv_sec = tswapl(ts.tv_sec); - target_ts->tv_nsec = tswapl(ts.tv_nsec); + host_to_target_timespec(arg2, &ts); } } break; case TARGET_NR_nanosleep: { - struct target_timespec *target_req = (void *)arg1; - struct target_timespec *target_rem = (void *)arg2; struct timespec req, rem; - req.tv_sec = tswapl(target_req->tv_sec); - req.tv_nsec = tswapl(target_req->tv_nsec); + target_to_host_timespec(&req, arg1); ret = get_errno(nanosleep(&req, &rem)); - if (is_error(ret) && target_rem) { - target_rem->tv_sec = tswapl(rem.tv_sec); - target_rem->tv_nsec = tswapl(rem.tv_nsec); + if (is_error(ret) && arg2) { + host_to_target_timespec(arg2, &rem); } } break; @@ -2837,15 +3141,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; #ifdef TARGET_NR_pread case TARGET_NR_pread: - page_unprotect_range((void *)arg2, arg3); - ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4)); + page_unprotect_range(arg2, arg3); + p = lock_user(arg2, arg3, 0); + ret = get_errno(pread(arg1, p, arg3, arg4)); + unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite: - ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4)); + p = lock_user(arg2, arg3, 1); + ret = get_errno(pwrite(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_getcwd: - ret = get_errno(sys_getcwd1((char *)arg1, arg2)); + p = lock_user(arg1, arg2, 0); + ret = get_errno(sys_getcwd1(p, arg2)); + unlock_user(p, arg1, ret); break; case TARGET_NR_capget: goto unimplemented; @@ -2874,16 +3184,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct rlimit rlim; ret = get_errno(getrlimit(arg1, &rlim)); if (!is_error(ret)) { - struct target_rlimit *target_rlim = (void *)arg2; + struct target_rlimit *target_rlim; + lock_user_struct(target_rlim, arg2, 0); target_rlim->rlim_cur = tswapl(rlim.rlim_cur); target_rlim->rlim_max = tswapl(rlim.rlim_max); + unlock_user_struct(target_rlim, arg2, 1); } break; } #endif #ifdef TARGET_NR_truncate64 case TARGET_NR_truncate64: - ret = target_truncate64(cpu_env, (const char *)arg1, arg2, arg3, arg4); + p = lock_user_string(arg1); + ret = target_truncate64(cpu_env, p, arg2, arg3, arg4); + unlock_user(p, arg1, 0); break; #endif #ifdef TARGET_NR_ftruncate64 @@ -2893,12 +3207,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_stat64 case TARGET_NR_stat64: - ret = get_errno(stat(path((const char *)arg1), &st)); + p = lock_user_string(arg1); + ret = get_errno(stat(path(p), &st)); + unlock_user(p, arg1, 0); goto do_stat64; #endif #ifdef TARGET_NR_lstat64 case TARGET_NR_lstat64: - ret = get_errno(lstat(path((const char *)arg1), &st)); + p = lock_user_string(arg1); + ret = get_errno(lstat(path(p), &st)); + unlock_user(p, arg1, 0); goto do_stat64; #endif #ifdef TARGET_NR_fstat64 @@ -2909,8 +3227,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, if (!is_error(ret)) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - struct target_eabi_stat64 *target_st = (void *)arg2; + struct target_eabi_stat64 *target_st; + lock_user_struct(target_st, arg2, 1); memset(target_st, 0, sizeof(struct target_eabi_stat64)); + /* put_user is probably wrong. */ put_user(st.st_dev, &target_st->st_dev); put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO @@ -2928,11 +3248,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, put_user(st.st_atime, &target_st->target_st_atime); put_user(st.st_mtime, &target_st->target_st_mtime); put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 0); } else #endif { - struct target_stat64 *target_st = (void *)arg2; + struct target_stat64 *target_st; + lock_user_struct(target_st, arg2, 1); memset(target_st, 0, sizeof(struct target_stat64)); + /* ??? put_user is probably wrong. */ put_user(st.st_dev, &target_st->st_dev); put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO @@ -2950,6 +3273,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, put_user(st.st_atime, &target_st->target_st_atime); put_user(st.st_mtime, &target_st->target_st_mtime); put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 0); } } } @@ -2957,7 +3281,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef USE_UID16 case TARGET_NR_lchown: - ret = get_errno(lchown((const char *)arg1, low2highuid(arg2), low2highgid(arg3))); + p = lock_user_string(arg1); + ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3))); + unlock_user(p, arg1, 0); break; case TARGET_NR_getuid: ret = get_errno(high2lowuid(getuid())); @@ -2980,28 +3306,32 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getgroups: { int gidsetsize = arg1; - uint16_t *target_grouplist = (void *)arg2; + uint16_t *target_grouplist; gid_t *grouplist; int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); if (!is_error(ret)) { + target_grouplist = lock_user(arg2, gidsetsize * 2, 0); for(i = 0;i < gidsetsize; i++) target_grouplist[i] = tswap16(grouplist[i]); + unlock_user(target_grouplist, arg2, gidsetsize * 2); } } break; case TARGET_NR_setgroups: { int gidsetsize = arg1; - uint16_t *target_grouplist = (void *)arg2; + uint16_t *target_grouplist; gid_t *grouplist; int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); + target_grouplist = lock_user(arg2, gidsetsize * 2, 1); for(i = 0;i < gidsetsize; i++) grouplist[i] = tswap16(target_grouplist[i]); + unlock_user(target_grouplist, arg2, 0); ret = get_errno(setgroups(gidsetsize, grouplist)); } break; @@ -3018,12 +3348,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_getresuid case TARGET_NR_getresuid: { - int ruid, euid, suid; + uid_t ruid, euid, suid; ret = get_errno(getresuid(&ruid, &euid, &suid)); if (!is_error(ret)) { - *(uint16_t *)arg1 = tswap16(high2lowuid(ruid)); - *(uint16_t *)arg2 = tswap16(high2lowuid(euid)); - *(uint16_t *)arg3 = tswap16(high2lowuid(suid)); + tput16(arg1, tswap16(high2lowuid(ruid))); + tput16(arg2, tswap16(high2lowuid(euid))); + tput16(arg3, tswap16(high2lowuid(suid))); } } break; @@ -3038,18 +3368,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_getresgid case TARGET_NR_getresgid: { - int rgid, egid, sgid; + gid_t rgid, egid, sgid; ret = get_errno(getresgid(&rgid, &egid, &sgid)); if (!is_error(ret)) { - *(uint16_t *)arg1 = tswap16(high2lowgid(rgid)); - *(uint16_t *)arg2 = tswap16(high2lowgid(egid)); - *(uint16_t *)arg3 = tswap16(high2lowgid(sgid)); + tput16(arg1, tswap16(high2lowgid(rgid))); + tput16(arg2, tswap16(high2lowgid(egid))); + tput16(arg3, tswap16(high2lowgid(sgid))); } } break; #endif case TARGET_NR_chown: - ret = get_errno(chown((const char *)arg1, low2highuid(arg2), low2highgid(arg3))); + p = lock_user_string(arg1); + ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3))); + unlock_user(p, arg1, 0); break; case TARGET_NR_setuid: ret = get_errno(setuid(low2highuid(arg1))); @@ -3067,7 +3399,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_lchown32 case TARGET_NR_lchown32: - ret = get_errno(lchown((const char *)arg1, arg2, arg3)); + p = lock_user_string(arg1); + ret = get_errno(lchown(p, arg2, arg3)); + unlock_user(p, arg1, 0); break; #endif #ifdef TARGET_NR_getuid32 @@ -3104,15 +3438,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getgroups32: { int gidsetsize = arg1; - uint32_t *target_grouplist = (void *)arg2; + uint32_t *target_grouplist; gid_t *grouplist; int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); if (!is_error(ret)) { + target_grouplist = lock_user(arg2, gidsetsize * 4, 0); for(i = 0;i < gidsetsize; i++) - put_user(grouplist[i], &target_grouplist[i]); + target_grouplist[i] = tswap32(grouplist[i]); + unlock_user(target_grouplist, arg2, gidsetsize * 4); } } break; @@ -3121,13 +3457,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_setgroups32: { int gidsetsize = arg1; - uint32_t *target_grouplist = (void *)arg2; + uint32_t *target_grouplist; gid_t *grouplist; int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); + target_grouplist = lock_user(arg2, gidsetsize * 4, 1); for(i = 0;i < gidsetsize; i++) - get_user(grouplist[i], &target_grouplist[i]); + grouplist[i] = tswap32(target_grouplist[i]); + unlock_user(target_grouplist, arg2, 0); ret = get_errno(setgroups(gidsetsize, grouplist)); } break; @@ -3145,12 +3483,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_getresuid32 case TARGET_NR_getresuid32: { - int ruid, euid, suid; + uid_t ruid, euid, suid; ret = get_errno(getresuid(&ruid, &euid, &suid)); if (!is_error(ret)) { - *(uint32_t *)arg1 = tswap32(ruid); - *(uint32_t *)arg2 = tswap32(euid); - *(uint32_t *)arg3 = tswap32(suid); + tput32(arg1, tswap32(ruid)); + tput32(arg2, tswap32(euid)); + tput32(arg3, tswap32(suid)); } } break; @@ -3163,19 +3501,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_getresgid32 case TARGET_NR_getresgid32: { - int rgid, egid, sgid; + gid_t rgid, egid, sgid; ret = get_errno(getresgid(&rgid, &egid, &sgid)); if (!is_error(ret)) { - *(uint32_t *)arg1 = tswap32(rgid); - *(uint32_t *)arg2 = tswap32(egid); - *(uint32_t *)arg3 = tswap32(sgid); + tput32(arg1, tswap32(rgid)); + tput32(arg2, tswap32(egid)); + tput32(arg3, tswap32(sgid)); } } break; #endif #ifdef TARGET_NR_chown32 case TARGET_NR_chown32: - ret = get_errno(chown((const char *)arg1, arg2, arg3)); + p = lock_user_string(arg1); + ret = get_errno(chown(p, arg2, arg3)); + unlock_user(p, arg1, 0); break; #endif #ifdef TARGET_NR_setuid32 @@ -3213,9 +3553,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_fcntl64: { struct flock64 fl; - struct target_flock64 *target_fl = (void *)arg3; + struct target_flock64 *target_fl; #ifdef TARGET_ARM - struct target_eabi_flock64 *target_efl = (void *)arg3; + struct target_eabi_flock64 *target_efl; #endif switch(arg2) { @@ -3224,19 +3564,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, if (ret == 0) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { + lock_user_struct(target_efl, arg3, 0); target_efl->l_type = tswap16(fl.l_type); target_efl->l_whence = tswap16(fl.l_whence); target_efl->l_start = tswap64(fl.l_start); target_efl->l_len = tswap64(fl.l_len); target_efl->l_pid = tswapl(fl.l_pid); + unlock_user_struct(target_efl, arg3, 1); } else #endif { + lock_user_struct(target_fl, arg3, 0); target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswap64(fl.l_start); target_fl->l_len = tswap64(fl.l_len); target_fl->l_pid = tswapl(fl.l_pid); + unlock_user_struct(target_fl, arg3, 1); } } break; @@ -3245,19 +3589,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case F_SETLKW64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { + lock_user_struct(target_efl, arg3, 1); fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); fl.l_len = tswap64(target_efl->l_len); fl.l_pid = tswapl(target_efl->l_pid); + unlock_user_struct(target_efl, arg3, 0); } else #endif { + lock_user_struct(target_fl, arg3, 1); fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); fl.l_len = tswap64(target_fl->l_len); fl.l_pid = tswapl(target_fl->l_pid); + unlock_user_struct(target_fl, arg3, 0); } ret = get_errno(fcntl(arg1, arg2, &fl)); break; diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 4db47da0f..308da4857 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -68,6 +68,9 @@ STRUCT(dirent, STRUCT(kbentry, TYPE_CHAR, TYPE_CHAR, TYPE_SHORT) +STRUCT(kbsentry, + TYPE_CHAR, MK_ARRAY(TYPE_CHAR, 512)) + STRUCT(audio_buf_info, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 360d52592..b28eea60d 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -62,25 +62,28 @@ static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16) void save_v86_state(CPUX86State *env) { TaskState *ts = env->opaque; + struct target_vm86plus_struct * target_v86; + lock_user_struct(target_v86, ts->target_v86, 0); /* put the VM86 registers in the userspace register structure */ - ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); - ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); - ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); - ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); - ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); - ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); - ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); - ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); - ts->target_v86->regs.eip = tswap32(env->eip); - ts->target_v86->regs.cs = tswap16(env->segs[R_CS].selector); - ts->target_v86->regs.ss = tswap16(env->segs[R_SS].selector); - ts->target_v86->regs.ds = tswap16(env->segs[R_DS].selector); - ts->target_v86->regs.es = tswap16(env->segs[R_ES].selector); - ts->target_v86->regs.fs = tswap16(env->segs[R_FS].selector); - ts->target_v86->regs.gs = tswap16(env->segs[R_GS].selector); + target_v86->regs.eax = tswap32(env->regs[R_EAX]); + target_v86->regs.ebx = tswap32(env->regs[R_EBX]); + target_v86->regs.ecx = tswap32(env->regs[R_ECX]); + target_v86->regs.edx = tswap32(env->regs[R_EDX]); + target_v86->regs.esi = tswap32(env->regs[R_ESI]); + target_v86->regs.edi = tswap32(env->regs[R_EDI]); + target_v86->regs.ebp = tswap32(env->regs[R_EBP]); + target_v86->regs.esp = tswap32(env->regs[R_ESP]); + target_v86->regs.eip = tswap32(env->eip); + target_v86->regs.cs = tswap16(env->segs[R_CS].selector); + target_v86->regs.ss = tswap16(env->segs[R_SS].selector); + target_v86->regs.ds = tswap16(env->segs[R_DS].selector); + target_v86->regs.es = tswap16(env->segs[R_ES].selector); + target_v86->regs.fs = tswap16(env->segs[R_FS].selector); + target_v86->regs.gs = tswap16(env->segs[R_GS].selector); set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask); - ts->target_v86->regs.eflags = tswap32(env->eflags); + target_v86->regs.eflags = tswap32(env->eflags); + unlock_user_struct(target_v86, ts->target_v86, 1); #ifdef DEBUG_VM86 fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n", env->eflags, env->segs[R_CS].selector, env->eip); @@ -378,10 +381,10 @@ void handle_vm86_fault(CPUX86State *env) } } -int do_vm86(CPUX86State *env, long subfunction, - struct target_vm86plus_struct * target_v86) +int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) { TaskState *ts = env->opaque; + struct target_vm86plus_struct * target_v86; int ret; switch (subfunction) { @@ -402,7 +405,6 @@ int do_vm86(CPUX86State *env, long subfunction, goto out; } - ts->target_v86 = target_v86; /* save current CPU regs */ ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ ts->vm86_saved_regs.ebx = env->regs[R_EBX]; @@ -421,6 +423,8 @@ int do_vm86(CPUX86State *env, long subfunction, ts->vm86_saved_regs.fs = env->segs[R_FS].selector; ts->vm86_saved_regs.gs = env->segs[R_GS].selector; + ts->target_v86 = vm86_addr; + lock_user_struct(target_v86, vm86_addr, 1); /* build vm86 CPU state */ ts->v86flags = tswap32(target_v86->regs.eflags); env->eflags = (env->eflags & ~SAFE_MASK) | @@ -465,6 +469,7 @@ int do_vm86(CPUX86State *env, long subfunction, ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags); memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, target_v86->vm86plus.vm86dbg_intxxtab, 32); + unlock_user_struct(target_v86, vm86_addr, 0); #ifdef DEBUG_VM86 fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", diff --git a/target-arm/nwfpe/fpa11_cpdt.c b/target-arm/nwfpe/fpa11_cpdt.c index 3319d88e1..914a86fbc 100644 --- a/target-arm/nwfpe/fpa11_cpdt.c +++ b/target-arm/nwfpe/fpa11_cpdt.c @@ -31,48 +31,52 @@ static inline void loadSingle(const unsigned int Fn,const unsigned int *pMem) { + target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); fpa11->fType[Fn] = typeSingle; - get_user(fpa11->fpreg[Fn].fSingle, pMem); + fpa11->fpreg[Fn].fSingle = tget32(addr); } static inline void loadDouble(const unsigned int Fn,const unsigned int *pMem) { + target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); unsigned int *p; p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; fpa11->fType[Fn] = typeDouble; #ifdef WORDS_BIGENDIAN - get_user(p[0], &pMem[0]); /* sign & exponent */ - get_user(p[1], &pMem[1]); + p[0] = tget32(addr); /* sign & exponent */ + p[1] = tget32(addr + 4); #else - get_user(p[0], &pMem[1]); - get_user(p[1], &pMem[0]); /* sign & exponent */ + p[0] = tget32(addr + 4); + p[1] = tget32(addr); /* sign & exponent */ #endif } static inline void loadExtended(const unsigned int Fn,const unsigned int *pMem) { + target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); unsigned int *p; p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; fpa11->fType[Fn] = typeExtended; - get_user(p[0], &pMem[0]); /* sign & exponent */ - get_user(p[1], &pMem[2]); /* ls bits */ - get_user(p[2], &pMem[1]); /* ms bits */ + p[0] = tget32(addr); /* sign & exponent */ + p[1] = tget32(addr + 8); /* ls bits */ + p[2] = tget32(addr + 4); /* ms bits */ } static inline void loadMultiple(const unsigned int Fn,const unsigned int *pMem) { + target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); register unsigned int *p; unsigned long x; p = (unsigned int*)&(fpa11->fpreg[Fn]); - get_user(x, &pMem[0]); + x = tget32(addr); fpa11->fType[Fn] = (x >> 14) & 0x00000003; switch (fpa11->fType[Fn]) @@ -80,16 +84,16 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) case typeSingle: case typeDouble: { - get_user(p[0], &pMem[2]); /* Single */ - get_user(p[1], &pMem[1]); /* double msw */ + p[0] = tget32(addr + 8); /* Single */ + p[1] = tget32(addr + 4); /* double msw */ p[2] = 0; /* empty */ } break; case typeExtended: { - get_user(p[1], &pMem[2]); - get_user(p[2], &pMem[1]); /* msw */ + p[1] = tget32(addr + 8); + p[2] = tget32(addr + 4); /* msw */ p[0] = (x & 0x80003fff); } break; @@ -99,6 +103,7 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) static inline void storeSingle(const unsigned int Fn,unsigned int *pMem) { + target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); float32 val; register unsigned int *p = (unsigned int*)&val; @@ -116,12 +121,13 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fSingle; } - put_user(p[0], pMem); + tput32(addr, p[0]); } static inline void storeDouble(const unsigned int Fn,unsigned int *pMem) { + target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); float64 val; register unsigned int *p = (unsigned int*)&val; @@ -139,17 +145,18 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fDouble; } #ifdef WORDS_BIGENDIAN - put_user(p[0], &pMem[0]); /* msw */ - put_user(p[1], &pMem[1]); /* lsw */ + tput32(addr, p[0]); /* msw */ + tput32(addr + 4, p[1]); /* lsw */ #else - put_user(p[1], &pMem[0]); /* msw */ - put_user(p[0], &pMem[1]); /* lsw */ + tput32(addr, p[1]); /* msw */ + tput32(addr + 4, p[0]); /* lsw */ #endif } static inline void storeExtended(const unsigned int Fn,unsigned int *pMem) { + target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); floatx80 val; register unsigned int *p = (unsigned int*)&val; @@ -167,14 +174,15 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fExtended; } - put_user(p[0], &pMem[0]); /* sign & exp */ - put_user(p[1], &pMem[2]); - put_user(p[2], &pMem[1]); /* msw */ + tput32(addr, p[0]); /* sign & exp */ + tput32(addr + 8, p[1]); + tput32(addr + 4, p[2]); /* msw */ } static inline void storeMultiple(const unsigned int Fn,unsigned int *pMem) { + target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); register unsigned int nType, *p; @@ -186,17 +194,17 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem) case typeSingle: case typeDouble: { - put_user(p[0], &pMem[2]); /* single */ - put_user(p[1], &pMem[1]); /* double msw */ - put_user(nType << 14, &pMem[0]); + tput32(addr + 8, p[0]); /* single */ + tput32(addr + 4, p[1]); /* double msw */ + tput32(addr, nType << 14); } break; case typeExtended: { - put_user(p[2], &pMem[1]); /* msw */ - put_user(p[1], &pMem[2]); - put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); + tput32(addr + 4, p[2]); /* msw */ + tput32(addr + 8, p[1]); + tput32(addr, (p[0] & 0x80003fff) | (nType << 14)); } break; } -- cgit v1.2.3 From 89ba1a738e9ed8c2712524336de1add8ddc25f7e Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 28 Mar 2006 20:20:38 +0000 Subject: Use 3-argument open call when creating file. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1791 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index e0406eae9..3a99cbd79 100644 --- a/vl.c +++ b/vl.c @@ -1288,7 +1288,7 @@ CharDriverState *qemu_chr_open_file_out(const char *file_out) { int fd_out; - fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY); + fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666); if (fd_out < 0) return NULL; return qemu_chr_open_fd(-1, fd_out); -- cgit v1.2.3 From 61b941569162c92b947561ce56fe046588aaf957 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 31 Mar 2006 21:17:44 +0000 Subject: update links git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1792 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 114e2cec3..7ab052062 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -64,12 +64,12 @@ have to install it. Otherwise, see @ref{compilation}. @section Windows Download the experimental binary installer at -@url{http://www.freeoszoo.org/download.php}. +@url{http://www.free.oszoo.org/download.html}. @section Mac OS X Download the experimental binary installer at -@url{http://www.freeoszoo.org/download.php}. +@url{http://www.free.oszoo.org/download.html}. @chapter QEMU PC System emulator -- cgit v1.2.3 From 307b0c24de782119953a9dd12c4b0ece0313dea6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 2 Apr 2006 19:10:24 +0000 Subject: update to latest Bochs bios - added PCI BIOS real mode 'get irq routing options' function git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1793 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 154 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 93 insertions(+), 61 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 710885076..8c3141ef6 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 4f33a0a98..a54235df4 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,22 +1,29 @@ Index: rombios.c =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v -retrieving revision 1.130 -diff -u -w -r1.130 rombios.c ---- rombios.c 13 Feb 2005 08:47:30 -0000 1.130 -+++ rombios.c 9 Feb 2006 21:49:38 -0000 -@@ -8570,7 +8570,10 @@ - use32 386 - #define APM_PROT32 - #include "apmbios.S" -+ - use16 386 -+#define APM_PROT16 -+#include "apmbios.S" +retrieving revision 1.160 +diff -u -w -r1.160 rombios.c +--- rombios.c 25 Jan 2006 17:51:49 -0000 1.160 ++++ rombios.c 2 Apr 2006 18:29:51 -0000 +@@ -1816,6 +1816,7 @@ + { + printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ", + BIOS_BUILD_DATE, bios_cvs_version_string); ++#if 0 + printf( + #ifdef BX_APM + "apmbios " +@@ -1827,6 +1828,9 @@ + "eltorito " + #endif + "\n\n"); ++#else ++ printf("apmbios pcibios eltorito \n\n"); ++#endif + } - #define APM_REAL - #include "apmbios.S" -@@ -8611,6 +8614,7 @@ + //-------------------------------------------------------------------------- +@@ -8713,6 +8717,7 @@ mov al, #0x80 bios32_end: popf @@ -24,7 +31,7 @@ diff -u -w -r1.130 rombios.c retf .align 16 -@@ -8721,17 +8725,17 @@ +@@ -8823,17 +8828,17 @@ pci_pro_fail: pop edi pop esi @@ -44,50 +51,75 @@ diff -u -w -r1.130 rombios.c retf pci_pro_select_reg: -Index: apmbios.S -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/apmbios.S,v -retrieving revision 1.1 -diff -u -w -r1.1 apmbios.S ---- apmbios.S 20 Jun 2004 18:27:09 -0000 1.1 -+++ apmbios.S 9 Feb 2006 21:49:38 -0000 -@@ -1,6 +1,9 @@ - // APM BIOS support for the Bochs BIOS - // Copyright (C) 2004 Fabrice Bellard - // -+// 16-bit interface activation -+// Copyright (C) 2005 Struan Bartlett -+// - // 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 -@@ -111,13 +114,28 @@ - mov bl, #0x4d // 'M' - // bit 0 : 16 bit interface supported - // bit 1 : 32 bit interface supported -- mov cx, #0x2 -+ mov cx, #0x3 - jmp APMSYM(ok) - - ;----------------- - ; APM real mode interface connect - APMSYM(01): - cmp al, #0x01 -+ jne APMSYM(02) -+ jmp APMSYM(ok) -+ -+;----------------- -+; APM 16 bit protected mode interface connect -+APMSYM(02): -+ cmp al, #0x02 -+ jne APMSYM(03) +@@ -8971,7 +8976,7 @@ + jmp pci_real_ok + pci_real_f0d: ;; write configuration dword + cmp al, #0x0d +- jne pci_real_unknown ++ jne pci_real_f0e + call pci_real_select_reg + push dx + mov dx, #0x0cfc +@@ -8979,6 +8984,46 @@ + out dx, eax + pop dx + jmp pci_real_ok ++pci_real_f0e: ;; get irq routing options ++ cmp al, #0x0e ++ jne pci_real_unknown ++ SEG ES ++ cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start ++ jb pci_real_too_small ++ SEG ES ++ mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start ++ pushf ++ push ds ++ push es ++ push cx ++ push si ++ push di ++ cld ++ mov si, #pci_routing_table_structure_start ++ push cs ++ pop ds ++ SEG ES ++ mov cx, [di+2] ++ SEG ES ++ mov es, [di+4] ++ mov di, cx ++ mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start ++ rep ++ movsb ++ pop di ++ pop si ++ pop cx ++ pop es ++ pop ds ++ popf ++ mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used ++ jmp pci_real_ok ++pci_real_too_small: ++ SEG ES ++ mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start ++ mov ah, #0x89 ++ jmp pci_real_fail + -+ mov bx, #_apm16_entry -+ -+ mov ax, #0xf000 // 16 bit code segment base -+ mov si, #0xfff0 // 16 bit code segment size -+ mov cx, #0xf000 // data segment address -+ mov di, #0xfff0 // data segment length - jne APMSYM(03) - jmp APMSYM(ok) + pci_real_unknown: + mov ah, #0x81 + pci_real_fail: +@@ -9019,6 +9064,7 @@ + dw 0,0 ;; Miniport data + db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved + db 0x07 ;; checksum ++pci_routing_table_structure_start: + ;; first slot entry PCI-to-ISA (embedded) + db 0 ;; pci bus number + db 0x08 ;; pci device number (bit 7-3) +@@ -9097,6 +9143,7 @@ + dw 0xdef8 ;; IRQ bitmap INTD# + db 5 ;; physical slot (0 = embedded) + db 0 ;; reserved ++pci_routing_table_structure_end: + pci_irq_list: + db 11, 10, 9, 5; -- cgit v1.2.3 From 1298fe631660abd913eba86567c8caeb9caf6ebc Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 2 Apr 2006 19:10:47 +0000 Subject: CDROM detection fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1794 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index 50b8e6375..cf9a9a7bb 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1669,7 +1669,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case WIN_PIDENTIFY: if (s->is_cdrom) { ide_atapi_identify(s); - s->status = READY_STAT; + s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); } else { ide_abort_command(s); -- cgit v1.2.3 From 894244f6cad355bf118cf6523296a06df1617f9d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 2 Apr 2006 19:11:31 +0000 Subject: do not test reserved config bits git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1795 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index e415ccf6c..fd4ccd947 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -353,9 +353,6 @@ static void pci_data_write(void *opaque, uint32_t addr, if (!(s->config_reg & (1 << 31))) { return; } - if ((s->config_reg & 0x3) != 0) { - return; - } bus_num = (s->config_reg >> 16) & 0xff; if (bus_num != 0) return; @@ -380,8 +377,6 @@ static uint32_t pci_data_read(void *opaque, uint32_t addr, if (!(s->config_reg & (1 << 31))) goto fail; - if ((s->config_reg & 0x3) != 0) - goto fail; bus_num = (s->config_reg >> 16) & 0xff; if (bus_num != 0) goto fail; -- cgit v1.2.3 From 33698e5ffce099286b7788a63142f603b4cd7f38 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 2 Apr 2006 19:13:41 +0000 Subject: btx decode fix on x86_64 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1796 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 0db0d4a4b..cca456086 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5085,7 +5085,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0x1ba: /* bt/bts/btr/btc Gv, im */ ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - op = ((modrm >> 3) & 7) | rex_r; + op = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod != 3) { -- cgit v1.2.3 From 7783e9f0029819101e206d7baf6db445e6e4692f Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 8 Apr 2006 14:12:31 +0000 Subject: Keyboard savevm fix (malc). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1797 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 8 +++++--- hw/ps2.c | 46 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index 7d0f49b76..3c41e5f60 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -118,7 +118,7 @@ typedef struct KBDState { uint8_t status; uint8_t mode; /* Bitmask of devices with data available. */ - int pending; + uint8_t pending; void *kbd; void *mouse; } KBDState; @@ -337,17 +337,19 @@ static void kbd_save(QEMUFile* f, void* opaque) qemu_put_8s(f, &s->write_cmd); qemu_put_8s(f, &s->status); qemu_put_8s(f, &s->mode); + qemu_put_8s(f, &s->pending); } static int kbd_load(QEMUFile* f, void* opaque, int version_id) { KBDState *s = (KBDState*)opaque; - if (version_id != 2) + if (version_id != 3) return -EINVAL; qemu_get_8s(f, &s->write_cmd); qemu_get_8s(f, &s->status); qemu_get_8s(f, &s->mode); + qemu_get_8s(f, &s->pending); return 0; } @@ -356,7 +358,7 @@ void kbd_init(void) KBDState *s = &kbd_state; kbd_reset(s); - register_savevm("pckbd", 0, 2, kbd_save, kbd_load, s); + register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); register_ioport_read(0x60, 1, 1, kbd_read_data, s); register_ioport_write(0x60, 1, 1, kbd_write_data, s); register_ioport_read(0x64, 1, 1, kbd_read_status, s); diff --git a/hw/ps2.c b/hw/ps2.c index be6b31ce7..40be0449f 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -461,19 +461,38 @@ static void ps2_reset(void *opaque) q->count = 0; } +static void ps2_common_save (QEMUFile *f, PS2State *s) +{ + qemu_put_be32s (f, &s->write_cmd); + qemu_put_be32s (f, &s->queue.rptr); + qemu_put_be32s (f, &s->queue.wptr); + qemu_put_be32s (f, &s->queue.count); + qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data)); +} + +static void ps2_common_load (QEMUFile *f, PS2State *s) +{ + qemu_get_be32s (f, &s->write_cmd); + qemu_get_be32s (f, &s->queue.rptr); + qemu_get_be32s (f, &s->queue.wptr); + qemu_get_be32s (f, &s->queue.count); + qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data)); +} + static void ps2_kbd_save(QEMUFile* f, void* opaque) { PS2KbdState *s = (PS2KbdState*)opaque; - - qemu_put_be32s(f, &s->common.write_cmd); + + ps2_common_save (f, &s->common); qemu_put_be32s(f, &s->scan_enabled); + qemu_put_be32s(f, &s->translate); } static void ps2_mouse_save(QEMUFile* f, void* opaque) { PS2MouseState *s = (PS2MouseState*)opaque; - - qemu_put_be32s(f, &s->common.write_cmd); + + ps2_common_save (f, &s->common); qemu_put_8s(f, &s->mouse_status); qemu_put_8s(f, &s->mouse_resolution); qemu_put_8s(f, &s->mouse_sample_rate); @@ -489,21 +508,24 @@ static void ps2_mouse_save(QEMUFile* f, void* opaque) static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id) { PS2KbdState *s = (PS2KbdState*)opaque; - - if (version_id != 1) + + if (version_id != 2) return -EINVAL; - qemu_get_be32s(f, &s->common.write_cmd); + + ps2_common_load (f, &s->common); qemu_get_be32s(f, &s->scan_enabled); + qemu_get_be32s(f, &s->translate); return 0; } static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id) { PS2MouseState *s = (PS2MouseState*)opaque; - - if (version_id != 1) + + if (version_id != 2) return -EINVAL; - qemu_get_be32s(f, &s->common.write_cmd); + + ps2_common_load (f, &s->common); qemu_get_8s(f, &s->mouse_status); qemu_get_8s(f, &s->mouse_resolution); qemu_get_8s(f, &s->mouse_sample_rate); @@ -524,7 +546,7 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_irq = update_irq; s->common.update_arg = update_arg; ps2_reset(&s->common); - register_savevm("ps2kbd", 0, 1, ps2_kbd_save, ps2_kbd_load, s); + register_savevm("ps2kbd", 0, 2, ps2_kbd_save, ps2_kbd_load, s); qemu_add_kbd_event_handler(ps2_put_keycode, s); qemu_register_reset(ps2_reset, &s->common); return s; @@ -537,7 +559,7 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_irq = update_irq; s->common.update_arg = update_arg; ps2_reset(&s->common); - register_savevm("ps2mouse", 0, 1, ps2_mouse_save, ps2_mouse_load, s); + register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s); qemu_add_mouse_event_handler(ps2_mouse_event, s); qemu_register_reset(ps2_reset, &s->common); return s; -- cgit v1.2.3 From af5db58e8b8a997fb3849046ec1f5df4527ff8b8 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 8 Apr 2006 14:26:41 +0000 Subject: Move configure --help output before gcc checks. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1798 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 86 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/configure b/configure index 19334da61..ff504b2b3 100755 --- a/configure +++ b/configure @@ -227,6 +227,49 @@ if test -z "$CFLAGS"; then CFLAGS="-O2" fi +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 " --kernel-path=PATH set the kernel path (configure probes it)" +echo "" +echo "Advanced options (experts only):" +echo " --source-path=PATH path of source code [$source_path]" +echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" +echo " --cc=CC use C compiler CC [$cc]" +echo " --host-cc=CC use C compiler CC [$host_cc] for dyngen etc." +echo " --make=MAKE use specified make [$make]" +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 "" +echo "NOTE: The object files are build at the place where configure is launched" +exit 1 +fi + cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" @@ -370,49 +413,6 @@ fi # sdl compile test fi # cross compilation fi # -z $sdl -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 " --kernel-path=PATH set the kernel path (configure probes it)" -echo "" -echo "Advanced options (experts only):" -echo " --source-path=PATH path of source code [$source_path]" -echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" -echo " --cc=CC use C compiler CC [$cc]" -echo " --host-cc=CC use C compiler CC [$host_cc] for dyngen etc." -echo " --make=MAKE use specified make [$make]" -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 "" -echo "NOTE: The object files are build at the place where configure is launched" -exit 1 -fi - if test "$mingw32" = "yes" ; then if test -z "$prefix" ; then prefix="/c/Program Files/Qemu" -- cgit v1.2.3 From c2f07f81a2d52d9d5243ead61d93e875487acf70 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 8 Apr 2006 17:14:56 +0000 Subject: Fix breakpoint TLB invalidation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1799 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/exec.c b/exec.c index 9ad2edcf3..4b5300382 100644 --- a/exec.c +++ b/exec.c @@ -1003,10 +1003,19 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) #if defined(TARGET_HAS_ICE) static void breakpoint_invalidate(CPUState *env, target_ulong pc) { - target_ulong phys_addr; + target_ulong addr, pd; + ram_addr_t ram_addr; + PhysPageDesc *p; - phys_addr = cpu_get_phys_page_debug(env, pc); - tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0); + addr = cpu_get_phys_page_debug(env, pc); + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK); + tb_invalidate_ram_page_range(ram_addr, ram_addr + 1, 0); } #endif -- cgit v1.2.3 From 706cd4b547db5c27585b6125a43663aba3404dfe Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 8 Apr 2006 17:36:21 +0000 Subject: Fix typo in previous patch. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1800 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 4b5300382..2a13c592f 100644 --- a/exec.c +++ b/exec.c @@ -1015,7 +1015,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) pd = p->phys_offset; } ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK); - tb_invalidate_ram_page_range(ram_addr, ram_addr + 1, 0); + tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0); } #endif -- cgit v1.2.3 From e3f4e2a4b0df510e441badb85c9398516c27bd66 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 8 Apr 2006 20:02:06 +0000 Subject: Initialize physical memory space to IO_MEM_UNASSIGNED. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1801 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/exec.c b/exec.c index 2a13c592f..9843ae5e7 100644 --- a/exec.c +++ b/exec.c @@ -204,6 +204,7 @@ static inline PageDesc *page_find(unsigned int index) static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc) { void **lp, **p; + PhysPageDesc *pd; p = (void **)l1_phys_map; #if TARGET_PHYS_ADDR_SPACE_BITS > 32 @@ -223,16 +224,18 @@ static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc) } #endif lp = p + ((index >> L2_BITS) & (L1_SIZE - 1)); - p = *lp; - if (!p) { + pd = *lp; + if (!pd) { + int i; /* allocate if not found */ if (!alloc) return NULL; - p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE); - memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE); - *lp = p; + pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE); + *lp = pd; + for (i = 0; i < L2_SIZE; i++) + pd[i].phys_offset = IO_MEM_UNASSIGNED; } - return ((PhysPageDesc *)p) + (index & (L2_SIZE - 1)); + return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1)); } static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) -- cgit v1.2.3 From 07435f7462e789a8df4718c9b2fc849b54446319 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 8 Apr 2006 23:32:52 +0000 Subject: Fix incorrect return type. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1802 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/lance.c b/hw/lance.c index c0cb0f98d..d1679375d 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -283,7 +283,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { #define MIN_BUF_SIZE 60 -static void lance_can_receive(void *opaque) +static int lance_can_receive(void *opaque) { return 1; } -- cgit v1.2.3 From 95219897ff4e6d0502b920c521fccc612ad913dd Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 9 Apr 2006 01:06:34 +0000 Subject: Allow multiple graphics devices. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1803 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 13 ++++------ console.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++------- hw/integratorcp.c | 18 +------------ hw/pl110.c | 11 +++++--- hw/sun4m.c | 19 +------------- hw/tcx.c | 17 +++++++------ hw/vga.c | 20 +++++++++------ monitor.c | 2 +- sdl.c | 16 +++++------- vl.c | 5 +--- vl.h | 29 ++++++++++----------- 11 files changed, 125 insertions(+), 100 deletions(-) diff --git a/cocoa.m b/cocoa.m index 27773e9fd..2e2908f51 100644 --- a/cocoa.m +++ b/cocoa.m @@ -365,8 +365,8 @@ static void cocoa_refresh(DisplayState *ds) pool = [ [ NSAutoreleasePool alloc ] init ]; distantPast = [ NSDate distantPast ]; - if (is_active_console(vga_console)) - vga_update_display(); + vga_hw_update(); + do { event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast inMode: NSDefaultRunLoopMode dequeue:YES ]; @@ -382,7 +382,7 @@ static void cocoa_refresh(DisplayState *ds) /* emulate caps lock and num lock keydown and keyup */ kbd_put_keycode(keycode); kbd_put_keycode(keycode | 0x80); - } else if (is_active_console(vga_console)) { + } else if (is_graphic_console()) { if (keycode & 0x80) kbd_put_keycode(0xe0); if (modifiers_state[keycode] == 0) { @@ -429,15 +429,12 @@ static void cocoa_refresh(DisplayState *ds) /* toggle Monitor */ case 0x02 ... 0x0a: /* '1' to '9' keys */ console_select(keycode - 0x02); - if (is_active_console(vga_console)) { - /* tell the vga console to redisplay itself */ - vga_invalidate_display(); break; } } } else { /* handle standard key events */ - if (is_active_console(vga_console)) { + 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 @@ -468,7 +465,7 @@ static void cocoa_refresh(DisplayState *ds) case NSKeyUp: { int keycode = cocoa_keycode_to_qemu([event keyCode]); - if (is_active_console(vga_console)) { + if (is_graphic_console()) { if (keycode & 0x80) kbd_put_keycode(0xe0); kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key diff --git a/console.c b/console.c index d1eb40655..6f9dc1fea 100644 --- a/console.c +++ b/console.c @@ -53,10 +53,17 @@ enum TTYState { TTY_STATE_CSI, }; - +/* ??? 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; @@ -82,6 +89,26 @@ 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) { @@ -782,8 +809,10 @@ void console_select(unsigned int index) s->g_width = s->ds->width; s->g_height = s->ds->height; text_console_resize(s); - } + } console_refresh(s); + } else { + vga_hw_invalidate(); } } } @@ -874,9 +903,10 @@ void kbd_put_keysym(int keysym) } } -TextConsole *graphic_console_init(DisplayState *ds) +static TextConsole *new_console(DisplayState *ds, int text) { TextConsole *s; + int i; if (nb_consoles >= MAX_CONSOLES) return NULL; @@ -884,16 +914,44 @@ TextConsole *graphic_console_init(DisplayState *ds) if (!s) { return NULL; } - if (!active_console) + if (!active_console || (active_console->text_console && !text)) active_console = s; s->ds = ds; - consoles[nb_consoles++] = s; + 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_active_console(TextConsole *s) +int is_graphic_console(void) { - return s == active_console; + return !active_console->text_console; } CharDriverState *text_console_init(DisplayState *ds) @@ -906,12 +964,11 @@ CharDriverState *text_console_init(DisplayState *ds) chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; - s = graphic_console_init(ds); + s = new_console(ds, 1); if (!s) { free(chr); return NULL; } - s->text_console = 1; chr->opaque = s; chr->chr_write = console_puts; chr->chr_add_read_handler = console_chr_add_read_handler; diff --git a/hw/integratorcp.c b/hw/integratorcp.c index db73efda1..1bcd734b8 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -27,22 +27,6 @@ void irq_info(void) { } -static void *lcd; - -void vga_update_display(void) -{ - pl110_update_display(lcd); -} - -void vga_screen_dump(const char *filename) -{ -} - -void vga_invalidate_display(void) -{ - pl110_invalidate_display(lcd); -} - void DMA_run (void) { } @@ -1210,7 +1194,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, exit (1); } } - lcd = pl110_init(ds, 0xc0000000, pic, 22); + pl110_init(ds, 0xc0000000, pic, 22, 0); /* Load the kernel. */ if (!kernel_filename) { diff --git a/hw/pl110.c b/hw/pl110.c index 2506dfd39..839f103b1 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -89,7 +89,7 @@ static int pl110_enabled(pl110_state *s) return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR); } -void pl110_update_display(void *opaque) +static void pl110_update_display(void *opaque) { pl110_state *s = (pl110_state *)opaque; drawfn* fntable; @@ -205,7 +205,7 @@ void pl110_update_display(void *opaque) dpy_update(s->ds, 0, first, s->cols, last - first + 1); } -void pl110_invalidate_display(void * opaque) +static void pl110_invalidate_display(void * opaque) { pl110_state *s = (pl110_state *)opaque; s->invalidate = 1; @@ -378,7 +378,8 @@ static CPUWriteMemoryFunc *pl110_writefn[] = { pl110_write }; -void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq) +void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, + int versatile) { pl110_state *s; int iomemtype; @@ -386,11 +387,13 @@ void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq) s = (pl110_state *)qemu_mallocz(sizeof(pl110_state)); iomemtype = cpu_register_io_memory(0, pl110_readfn, pl110_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); s->base = base; s->ds = ds; s->pic = pic; s->irq = irq; + graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, + NULL, s); /* ??? Save/restore. */ return s; } diff --git a/hw/sun4m.c b/hw/sun4m.c index b41ee2582..435ac02bd 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -187,23 +187,6 @@ void pic_set_irq_cpu(int irq, int level, unsigned int cpu) slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); } -static void *tcx; - -void vga_update_display() -{ - tcx_update_display(tcx); -} - -void vga_invalidate_display() -{ - tcx_invalidate_display(tcx); -} - -void vga_screen_dump(const char *filename) -{ - tcx_screen_dump(tcx, filename); -} - static void *iommu; uint32_t iommu_translate(uint32_t addr) @@ -256,7 +239,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } - tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); + tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { diff --git a/hw/tcx.c b/hw/tcx.c index c0fddf31d..a3a2114e8 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -37,6 +37,8 @@ typedef struct TCXState { uint8_t dac_index, dac_state; } TCXState; +static void tcx_screen_dump(void *opaque, const char *filename); + static void tcx_draw_line32(TCXState *s1, uint8_t *d, const uint8_t *s, int width) { @@ -81,7 +83,7 @@ static void tcx_draw_line8(TCXState *s1, uint8_t *d, /* Fixed line length 1024 allows us to do nice tricks not possible on VGA... */ -void tcx_update_display(void *opaque) +static void tcx_update_display(void *opaque) { TCXState *ts = opaque; uint32_t page; @@ -158,7 +160,7 @@ void tcx_update_display(void *opaque) } } -void tcx_invalidate_display(void *opaque) +static void tcx_invalidate_display(void *opaque) { TCXState *s = opaque; int i; @@ -269,15 +271,15 @@ static CPUWriteMemoryFunc *tcx_dac_write[3] = { tcx_dac_writel, }; -void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, - unsigned long vram_offset, int vram_size, int width, int height) +void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size, int width, int height) { TCXState *s; int io_memory; s = qemu_mallocz(sizeof(TCXState)); if (!s) - return NULL; + return; s->ds = ds; s->addr = addr; s->vram = vram_base; @@ -289,14 +291,15 @@ void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory); + graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, + tcx_screen_dump, s); register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); qemu_register_reset(tcx_reset, s); tcx_reset(s); dpy_resize(s->ds, width, height); - return s; } -void tcx_screen_dump(void *opaque, const char *filename) +static void tcx_screen_dump(void *opaque, const char *filename) { TCXState *s = opaque; FILE *f; diff --git a/hw/vga.c b/hw/vga.c index 49e5b211f..a712790c7 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -146,6 +146,8 @@ static uint8_t expand4to8[16]; VGAState *vga_state; int vga_io_memory; +static void vga_screen_dump(void *opaque, const char *filename); + static uint32_t vga_ioport_read(void *opaque, uint32_t addr) { VGAState *s = opaque; @@ -1482,9 +1484,9 @@ static void vga_draw_blank(VGAState *s, int full_update) #define GMODE_GRAPH 1 #define GMODE_BLANK 2 -void vga_update_display(void) +static void vga_update_display(void *opaque) { - VGAState *s = vga_state; + VGAState *s = (VGAState *)opaque; int full_update, graphic_mode; if (s->ds->depth == 0) { @@ -1532,9 +1534,9 @@ void vga_update_display(void) } /* force a full display refresh */ -void vga_invalidate_display(void) +static void vga_invalidate_display(void *opaque) { - VGAState *s = vga_state; + VGAState *s = (VGAState *)opaque; s->last_width = -1; s->last_height = -1; @@ -1698,6 +1700,8 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, s->get_bpp = vga_get_bpp; s->get_offsets = vga_get_offsets; s->get_resolution = vga_get_resolution; + graphic_console_init(s->ds, vga_update_display, vga_invalidate_display, + vga_screen_dump, s); /* XXX: currently needed for display */ vga_state = s; } @@ -1854,13 +1858,13 @@ static int ppm_save(const char *filename, uint8_t *data, /* save the vga display in a PPM image even if no display is available */ -void vga_screen_dump(const char *filename) +static void vga_screen_dump(void *opaque, const char *filename) { - VGAState *s = vga_state; + VGAState *s = (VGAState *)opaque; DisplayState *saved_ds, ds1, *ds = &ds1; /* XXX: this is a little hackish */ - vga_invalidate_display(); + vga_invalidate_display(s); saved_ds = s->ds; memset(ds, 0, sizeof(DisplayState)); @@ -1871,7 +1875,7 @@ void vga_screen_dump(const char *filename) s->ds = ds; s->graphic_mode = -1; - vga_update_display(); + vga_update_display(s); if (ds->data) { ppm_save(filename, ds->data, vga_save_w, vga_save_h, diff --git a/monitor.c b/monitor.c index 6b98cf13f..3078b1d4b 100644 --- a/monitor.c +++ b/monitor.c @@ -356,7 +356,7 @@ static void do_change(const char *device, const char *filename) static void do_screen_dump(const char *filename) { - vga_screen_dump(filename); + vga_hw_screen_dump(filename); } static void do_log(const char *items) diff --git a/sdl.c b/sdl.c index d53f3e957..b8c82fd66 100644 --- a/sdl.c +++ b/sdl.c @@ -314,8 +314,8 @@ static void toggle_full_screen(DisplayState *ds) if (!gui_saved_grab) sdl_grab_end(); } - vga_invalidate_display(); - vga_update_display(); + vga_hw_invalidate(); + vga_hw_update(); } static void sdl_refresh(DisplayState *ds) @@ -328,8 +328,7 @@ static void sdl_refresh(DisplayState *ds) sdl_update_caption(); } - if (is_active_console(vga_console)) - vga_update_display(); + vga_hw_update(); while (SDL_PollEvent(ev)) { switch (ev->type) { @@ -352,10 +351,7 @@ static void sdl_refresh(DisplayState *ds) break; case 0x02 ... 0x0a: /* '1' to '9' keys */ console_select(keycode - 0x02); - if (is_active_console(vga_console)) { - /* tell the vga console to redisplay itself */ - vga_invalidate_display(); - } else { + if (!is_graphic_console()) { /* display grab if going to a text console */ if (gui_grab) sdl_grab_end(); @@ -365,7 +361,7 @@ static void sdl_refresh(DisplayState *ds) default: break; } - } else if (!is_active_console(vga_console)) { + } else if (!is_graphic_console()) { int keysym; keysym = 0; if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) { @@ -420,7 +416,7 @@ static void sdl_refresh(DisplayState *ds) } } } - if (is_active_console(vga_console)) + if (is_graphic_console()) sdl_process_key(&ev->key); break; case SDL_QUIT: diff --git a/vl.c b/vl.c index 3a99cbd79..ed59988d3 100644 --- a/vl.c +++ b/vl.c @@ -137,7 +137,6 @@ int graphic_height = 600; #endif int graphic_depth = 15; int full_screen = 0; -TextConsole *vga_console; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; #ifdef TARGET_I386 @@ -2994,7 +2993,7 @@ static void dumb_resize(DisplayState *ds, int w, int h) static void dumb_refresh(DisplayState *ds) { - vga_update_display(); + vga_hw_update(); } void dumb_display_init(DisplayState *ds) @@ -5123,8 +5122,6 @@ int main(int argc, char **argv) #endif } - vga_console = graphic_console_init(ds); - monitor_hd = qemu_chr_open(monitor_device); if (!monitor_hd) { fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); diff --git a/vl.h b/vl.h index ada078819..0c6f0132f 100644 --- a/vl.h +++ b/vl.h @@ -254,10 +254,19 @@ int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); typedef struct DisplayState DisplayState; typedef struct TextConsole TextConsole; -extern TextConsole *vga_console; - -TextConsole *graphic_console_init(DisplayState *ds); -int is_active_console(TextConsole *s); +typedef void (*vga_hw_update_ptr)(void *); +typedef void (*vga_hw_invalidate_ptr)(void *); +typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); + +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); +void vga_hw_update(void); +void vga_hw_invalidate(void); +void vga_hw_screen_dump(const char *filename); + +int is_graphic_console(void); CharDriverState *text_console_init(DisplayState *ds); void console_select(unsigned int index); @@ -673,9 +682,6 @@ static inline void dpy_resize(DisplayState *s, int w, int h) int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size, unsigned long vga_bios_offset, int vga_bios_size); -void vga_update_display(void); -void vga_invalidate_display(void); -void vga_screen_dump(const char *filename); /* cirrus_vga.c */ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, @@ -844,11 +850,8 @@ uint32_t iommu_translate_local(void *opaque, uint32_t addr); void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr); /* tcx.c */ -void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, +void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, unsigned long vram_offset, int vram_size, int width, int height); -void tcx_update_display(void *opaque); -void tcx_invalidate_display(void *opaque); -void tcx_screen_dump(void *opaque, const char *filename); /* slavio_intctl.c */ void *slavio_intctl_init(); @@ -976,9 +979,7 @@ void ps2_keyboard_set_translation(void *opaque, int mode); void smc91c111_init(NICInfo *, uint32_t, void *, int); /* pl110.c */ -void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq); -void pl110_update_display(void *opaque); -void pl110_invalidate_display(void *opaque); +void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int); #endif /* defined(QEMU_TOOL) */ -- cgit v1.2.3 From cdbdb648b7c2867f0bb7dce27efb1986f770dedb Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 9 Apr 2006 01:32:52 +0000 Subject: ARM Versatile Platform Baseboard emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1804 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +- hw/arm_pic.c | 73 ++++++ hw/arm_pic.h | 27 +++ hw/arm_timer.c | 383 +++++++++++++++++++++++++++++++ hw/integratorcp.c | 673 ++---------------------------------------------------- hw/pl011.c | 251 ++++++++++++++++++++ hw/pl050.c | 127 +++++++++++ hw/pl080.c | 328 ++++++++++++++++++++++++++ hw/pl110.c | 27 ++- hw/pl190.c | 252 ++++++++++++++++++++ hw/versatilepb.c | 321 ++++++++++++++++++++++++++ vl.c | 1 + vl.h | 19 ++ 13 files changed, 1830 insertions(+), 655 deletions(-) create mode 100644 hw/arm_pic.c create mode 100644 hw/arm_pic.h create mode 100644 hw/arm_timer.c create mode 100644 hw/pl011.c create mode 100644 hw/pl050.c create mode 100644 hw/pl080.c create mode 100644 hw/pl190.c create mode 100644 hw/versatilepb.c diff --git a/Makefile.target b/Makefile.target index a5c728baa..da69393c5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -339,7 +339,8 @@ VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o endif endif ifeq ($(TARGET_BASE_ARCH), arm) -VL_OBJS+= integratorcp.o ps2.o smc91c111.o pl110.o +VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o +VL_OBJS+= pl011.o pl050.o pl080.o pl110.o pl190.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/hw/arm_pic.c b/hw/arm_pic.c new file mode 100644 index 000000000..fbc2d67d0 --- /dev/null +++ b/hw/arm_pic.c @@ -0,0 +1,73 @@ +/* + * Generic ARM Programmable Interrupt Controller support. + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL + */ + +#include "vl.h" +#include "arm_pic.h" + +/* Stub functions for hardware that doesn't exist. */ +void pic_set_irq(int irq, int level) +{ + cpu_abort(cpu_single_env, "pic_set_irq"); +} + +void pic_info(void) +{ +} + +void irq_info(void) +{ +} + + +void pic_set_irq_new(void *opaque, int irq, int level) +{ + arm_pic_handler *p = (arm_pic_handler *)opaque; + /* Call the real handler. */ + (*p)(opaque, irq, level); +} + +/* Model the IRQ/FIQ CPU interrupt lines as a two input interrupt controller. + Input 0 is IRQ and input 1 is FIQ. */ +typedef struct +{ + arm_pic_handler handler; + CPUState *cpu_env; +} arm_pic_cpu_state; + +static void arm_pic_cpu_handler(void *opaque, int irq, int level) +{ + arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque; + switch (irq) { + case ARM_PIC_CPU_IRQ: + if (level) + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + break; + case ARM_PIC_CPU_FIQ: + if (level) + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + else + cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + break; + default: + cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n", + irq); + } +} + +void *arm_pic_init_cpu(CPUState *env) +{ + arm_pic_cpu_state *s; + + s = (arm_pic_cpu_state *)malloc(sizeof(arm_pic_cpu_state)); + s->handler = arm_pic_cpu_handler; + s->cpu_env = env; + return s; +} diff --git a/hw/arm_pic.h b/hw/arm_pic.h new file mode 100644 index 000000000..b29914985 --- /dev/null +++ b/hw/arm_pic.h @@ -0,0 +1,27 @@ +/* + * Generic ARM Programmable Interrupt Controller support. + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + * + * Arm hardware uses a wide variety of interrupt handling hardware. + * This provides a generic framework for connecting interrupt sources and + * inputs. + */ + +#ifndef ARM_INTERRUPT_H +#define ARM_INTERRUPT_H 1 + +/* The first element of an individual PIC state structures should + be a pointer to the handler routine. */ +typedef void (*arm_pic_handler)(void *opaque, int irq, int level); + +/* The CPU is also modeled as an interrupt controller. */ +#define ARM_PIC_CPU_IRQ 0 +#define ARM_PIC_CPU_FIQ 1 +void *arm_pic_init_cpu(CPUState *env); + +#endif /* !ARM_INTERRUPT_H */ + diff --git a/hw/arm_timer.c b/hw/arm_timer.c new file mode 100644 index 000000000..a97d73e44 --- /dev/null +++ b/hw/arm_timer.c @@ -0,0 +1,383 @@ +/* + * ARM PrimeCell Timer modules. + * + * Copyright (c) 2005-2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "arm_pic.h" + +/* Common timer implementation. */ + +#define TIMER_CTRL_ONESHOT (1 << 0) +#define TIMER_CTRL_32BIT (1 << 1) +#define TIMER_CTRL_DIV1 (0 << 2) +#define TIMER_CTRL_DIV16 (1 << 2) +#define TIMER_CTRL_DIV256 (2 << 2) +#define TIMER_CTRL_IE (1 << 5) +#define TIMER_CTRL_PERIODIC (1 << 6) +#define TIMER_CTRL_ENABLE (1 << 7) + +typedef struct { + int64_t next_time; + int64_t expires; + int64_t loaded; + QEMUTimer *timer; + uint32_t control; + uint32_t count; + uint32_t limit; + int raw_freq; + int freq; + int int_level; + void *pic; + int irq; +} arm_timer_state; + +/* Calculate the new expiry time of the given timer. */ + +static void arm_timer_reload(arm_timer_state *s) +{ + int64_t delay; + + s->loaded = s->expires; + delay = muldiv64(s->count, ticks_per_sec, s->freq); + if (delay == 0) + delay = 1; + s->expires += delay; +} + +/* Check all active timers, and schedule the next timer interrupt. */ + +static void arm_timer_update(arm_timer_state *s, int64_t now) +{ + int64_t next; + + /* Ignore disabled timers. */ + if ((s->control & TIMER_CTRL_ENABLE) == 0) + return; + /* Ignore expired one-shot timers. */ + if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT)) + return; + if (s->expires - now <= 0) { + /* Timer has expired. */ + s->int_level = 1; + if (s->control & TIMER_CTRL_ONESHOT) { + /* One-shot. */ + s->count = 0; + } else { + if ((s->control & TIMER_CTRL_PERIODIC) == 0) { + /* Free running. */ + if (s->control & TIMER_CTRL_32BIT) + s->count = 0xffffffff; + else + s->count = 0xffff; + } else { + /* Periodic. */ + s->count = s->limit; + } + } + } + while (s->expires - now <= 0) { + arm_timer_reload(s); + } + /* Update interrupts. */ + if (s->int_level && (s->control & TIMER_CTRL_IE)) { + pic_set_irq_new(s->pic, s->irq, 1); + } else { + pic_set_irq_new(s->pic, s->irq, 0); + } + + next = now; + if (next - s->expires < 0) + next = s->expires; + + /* Schedule the next timer interrupt. */ + if (next == now) { + qemu_del_timer(s->timer); + s->next_time = 0; + } else if (next != s->next_time) { + qemu_mod_timer(s->timer, next); + s->next_time = next; + } +} + +/* Return the current value of the timer. */ +static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now) +{ + int64_t elapsed; + int64_t period; + + if (s->count == 0) + return 0; + if ((s->control & TIMER_CTRL_ENABLE) == 0) + return s->count; + elapsed = now - s->loaded; + period = s->expires - s->loaded; + /* If the timer should have expired then return 0. This can happen + when the host timer signal doesnt occur immediately. It's better to + have a timer appear to sit at zero for a while than have it wrap + around before the guest interrupt is raised. */ + /* ??? Could we trigger the interrupt here? */ + if (elapsed > period) + return 0; + /* We need to calculate count * elapsed / period without overfowing. + Scale both elapsed and period so they fit in a 32-bit int. */ + while (period != (int32_t)period) { + period >>= 1; + elapsed >>= 1; + } + return ((uint64_t)s->count * (uint64_t)(int32_t)elapsed) + / (int32_t)period; +} + +uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) +{ + arm_timer_state *s = (arm_timer_state *)opaque; + + switch (offset >> 2) { + case 0: /* TimerLoad */ + case 6: /* TimerBGLoad */ + return s->limit; + case 1: /* TimerValue */ + return arm_timer_getcount(s, qemu_get_clock(vm_clock)); + case 2: /* TimerControl */ + return s->control; + case 4: /* TimerRIS */ + return s->int_level; + case 5: /* TimerMIS */ + if ((s->control & TIMER_CTRL_IE) == 0) + return 0; + return s->int_level; + default: + cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset); + return 0; + } +} + +static void arm_timer_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + arm_timer_state *s = (arm_timer_state *)opaque; + int64_t now; + + now = qemu_get_clock(vm_clock); + switch (offset >> 2) { + case 0: /* TimerLoad */ + s->limit = value; + s->count = value; + s->expires = now; + arm_timer_reload(s); + break; + case 1: /* TimerValue */ + /* ??? Linux seems to want to write to this readonly register. + Ignore it. */ + break; + case 2: /* TimerControl */ + if (s->control & TIMER_CTRL_ENABLE) { + /* Pause the timer if it is running. This may cause some + inaccuracy dure to rounding, but avoids a whole lot of other + messyness. */ + s->count = arm_timer_getcount(s, now); + } + s->control = value; + s->freq = s->raw_freq; + /* ??? Need to recalculate expiry time after changing divisor. */ + switch ((value >> 2) & 3) { + case 1: s->freq >>= 4; break; + case 2: s->freq >>= 8; break; + } + if (s->control & TIMER_CTRL_ENABLE) { + /* Restart the timer if still enabled. */ + s->expires = now; + arm_timer_reload(s); + } + break; + case 3: /* TimerIntClr */ + s->int_level = 0; + break; + case 6: /* TimerBGLoad */ + s->limit = value; + break; + default: + cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset); + } + arm_timer_update(s, now); +} + +static void arm_timer_tick(void *opaque) +{ + int64_t now; + + now = qemu_get_clock(vm_clock); + arm_timer_update((arm_timer_state *)opaque, now); +} + +static void *arm_timer_init(uint32_t freq, void *pic, int irq) +{ + arm_timer_state *s; + + s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state)); + s->pic = pic; + s->irq = irq; + s->raw_freq = s->freq = 1000000; + s->control = TIMER_CTRL_IE; + s->count = 0xffffffff; + + s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s); + /* ??? Save/restore. */ + return s; +} + +/* ARM PrimeCell SP804 dual timer module. + Docs for this device don't seem to be publicly available. This + implementation is based on gueswork, the linux kernel sources and the + Integrator/CP timer modules. */ + +typedef struct { + /* Include a pseudo-PIC device to merge the two interrupt sources. */ + arm_pic_handler handler; + void *timer[2]; + int level[2]; + uint32_t base; + /* The output PIC device. */ + void *pic; + int irq; +} sp804_state; + +static void sp804_set_irq(void *opaque, int irq, int level) +{ + sp804_state *s = (sp804_state *)opaque; + + s->level[irq] = level; + pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]); +} + +static uint32_t sp804_read(void *opaque, target_phys_addr_t offset) +{ + sp804_state *s = (sp804_state *)opaque; + + /* ??? Don't know the PrimeCell ID for this device. */ + offset -= s->base; + if (offset < 0x20) { + return arm_timer_read(s->timer[0], offset); + } else { + return arm_timer_read(s->timer[1], offset - 0x20); + } +} + +static void sp804_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + sp804_state *s = (sp804_state *)opaque; + + offset -= s->base; + if (offset < 0x20) { + arm_timer_write(s->timer[0], offset, value); + } else { + arm_timer_write(s->timer[1], offset - 0x20, value); + } +} + +static CPUReadMemoryFunc *sp804_readfn[] = { + sp804_read, + sp804_read, + sp804_read +}; + +static CPUWriteMemoryFunc *sp804_writefn[] = { + sp804_write, + sp804_write, + sp804_write +}; + +void sp804_init(uint32_t base, void *pic, int irq) +{ + int iomemtype; + sp804_state *s; + + s = (sp804_state *)qemu_mallocz(sizeof(sp804_state)); + s->handler = sp804_set_irq; + s->base = base; + s->pic = pic; + s->irq = irq; + /* ??? The timers are actually configurable between 32kHz and 1MHz, but + we don't implement that. */ + s->timer[0] = arm_timer_init(1000000, s, 0); + s->timer[1] = arm_timer_init(1000000, s, 1); + iomemtype = cpu_register_io_memory(0, sp804_readfn, + sp804_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + /* ??? Save/restore. */ +} + + +/* Integrator/CP timer module. */ + +typedef struct { + void *timer[3]; + uint32_t base; +} icp_pit_state; + +static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset) +{ + icp_pit_state *s = (icp_pit_state *)opaque; + int n; + + /* ??? Don't know the PrimeCell ID for this device. */ + offset -= s->base; + n = offset >> 8; + if (n > 3) + cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n); + + return arm_timer_read(s->timer[n], offset & 0xff); +} + +static void icp_pit_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + icp_pit_state *s = (icp_pit_state *)opaque; + int n; + + offset -= s->base; + n = offset >> 8; + if (n > 3) + cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n); + + arm_timer_write(s->timer[n], offset & 0xff, value); +} + + +static CPUReadMemoryFunc *icp_pit_readfn[] = { + icp_pit_read, + icp_pit_read, + icp_pit_read +}; + +static CPUWriteMemoryFunc *icp_pit_writefn[] = { + icp_pit_write, + icp_pit_write, + icp_pit_write +}; + +void icp_pit_init(uint32_t base, void *pic, int irq) +{ + int iomemtype; + icp_pit_state *s; + + s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state)); + s->base = base; + /* Timer 0 runs at the system clock speed (40MHz). */ + s->timer[0] = arm_timer_init(40000000, pic, irq); + /* The other two timers run at 1MHz. */ + s->timer[1] = arm_timer_init(1000000, pic, irq + 1); + s->timer[2] = arm_timer_init(1000000, pic, irq + 2); + + iomemtype = cpu_register_io_memory(0, icp_pit_readfn, + icp_pit_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + /* ??? Save/restore. */ +} + diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 1bcd734b8..bce9b592c 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -1,32 +1,19 @@ /* * ARM Integrator CP System emulation. * - * Copyright (c) 2005 CodeSourcery, LLC. + * Copyright (c) 2005-2006 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL */ -#include +#include "vl.h" +#include "arm_pic.h" #define KERNEL_ARGS_ADDR 0x100 #define KERNEL_LOAD_ADDR 0x00010000 #define INITRD_LOAD_ADDR 0x00800000 -/* Stub functions for hardware that doesn't exist. */ -void pic_set_irq(int irq, int level) -{ - cpu_abort (cpu_single_env, "pic_set_irq"); -} - -void pic_info(void) -{ -} - -void irq_info(void) -{ -} - void DMA_run (void) { } @@ -284,41 +271,31 @@ static void integratorcm_init(int memsz, uint32_t flash_offset) typedef struct icp_pic_state { + arm_pic_handler handler; uint32_t base; uint32_t level; uint32_t irq_enabled; uint32_t fiq_enabled; void *parent; - /* -1 if parent is a cpu, otherwise IRQ number on parent PIC. */ int parent_irq; + int parent_fiq; } icp_pic_state; static void icp_pic_update(icp_pic_state *s) { - CPUState *env; - if (s->parent_irq != -1) { - uint32_t flags; + uint32_t flags; + if (s->parent_irq != -1) { flags = (s->level & s->irq_enabled); - pic_set_irq_new(s->parent, s->parent_irq, - flags != 0); - return; + pic_set_irq_new(s->parent, s->parent_irq, flags != 0); } - /* Raise CPU interrupt. */ - env = (CPUState *)s->parent; - if (s->level & s->fiq_enabled) { - cpu_interrupt (env, CPU_INTERRUPT_FIQ); - } else { - cpu_reset_interrupt (env, CPU_INTERRUPT_FIQ); - } - if (s->level & s->irq_enabled) { - cpu_interrupt (env, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt (env, CPU_INTERRUPT_HARD); + if (s->parent_fiq != -1) { + flags = (s->level & s->fiq_enabled); + pic_set_irq_new(s->parent, s->parent_fiq, flags != 0); } } -void pic_set_irq_new(void *opaque, int irq, int level) +static void icp_pic_set_irq(void *opaque, int irq, int level) { icp_pic_state *s = (icp_pic_state *)opaque; if (level) @@ -408,7 +385,7 @@ static CPUWriteMemoryFunc *icp_pic_writefn[] = { }; static icp_pic_state *icp_pic_init(uint32_t base, void *parent, - int parent_irq) + int parent_irq, int parent_fiq) { icp_pic_state *s; int iomemtype; @@ -416,10 +393,11 @@ static icp_pic_state *icp_pic_init(uint32_t base, void *parent, s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state)); if (!s) return NULL; - + s->handler = icp_pic_set_irq; s->base = base; s->parent = parent; s->parent_irq = parent_irq; + s->parent_fiq = parent_fiq; iomemtype = cpu_register_io_memory(0, icp_pic_readfn, icp_pic_writefn, s); cpu_register_physical_memory(base, 0x007fffff, iomemtype); @@ -427,499 +405,6 @@ static icp_pic_state *icp_pic_init(uint32_t base, void *parent, return s; } -/* Timers. */ - -/* System bus clock speed (40MHz) for timer 0. Not sure about this value. */ -#define ICP_BUS_FREQ 40000000 - -typedef struct { - int64_t next_time; - int64_t expires[3]; - int64_t loaded[3]; - QEMUTimer *timer; - icp_pic_state *pic; - uint32_t base; - uint32_t control[3]; - uint32_t count[3]; - uint32_t limit[3]; - int freq[3]; - int int_level[3]; -} icp_pit_state; - -/* Calculate the new expiry time of the given timer. */ - -static void icp_pit_reload(icp_pit_state *s, int n) -{ - int64_t delay; - - s->loaded[n] = s->expires[n]; - delay = muldiv64(s->count[n], ticks_per_sec, s->freq[n]); - if (delay == 0) - delay = 1; - s->expires[n] += delay; -} - -/* Check all active timers, and schedule the next timer interrupt. */ - -static void icp_pit_update(icp_pit_state *s, int64_t now) -{ - int n; - int64_t next; - - next = now; - for (n = 0; n < 3; n++) { - /* Ignore disabled timers. */ - if ((s->control[n] & 0x80) == 0) - continue; - /* Ignore expired one-shot timers. */ - if (s->count[n] == 0 && s->control[n] & 1) - continue; - if (s->expires[n] - now <= 0) { - /* Timer has expired. */ - s->int_level[n] = 1; - if (s->control[n] & 1) { - /* One-shot. */ - s->count[n] = 0; - } else { - if ((s->control[n] & 0x40) == 0) { - /* Free running. */ - if (s->control[n] & 2) - s->count[n] = 0xffffffff; - else - s->count[n] = 0xffff; - } else { - /* Periodic. */ - s->count[n] = s->limit[n]; - } - } - } - while (s->expires[n] - now <= 0) { - icp_pit_reload(s, n); - } - } - /* Update interrupts. */ - for (n = 0; n < 3; n++) { - if (s->int_level[n] && (s->control[n] & 0x20)) { - pic_set_irq_new(s->pic, 5 + n, 1); - } else { - pic_set_irq_new(s->pic, 5 + n, 0); - } - if (next - s->expires[n] < 0) - next = s->expires[n]; - } - /* Schedule the next timer interrupt. */ - if (next == now) { - qemu_del_timer(s->timer); - s->next_time = 0; - } else if (next != s->next_time) { - qemu_mod_timer(s->timer, next); - s->next_time = next; - } -} - -/* Return the current value of the timer. */ -static uint32_t icp_pit_getcount(icp_pit_state *s, int n, int64_t now) -{ - int64_t elapsed; - int64_t period; - - if (s->count[n] == 0) - return 0; - if ((s->control[n] & 0x80) == 0) - return s->count[n]; - elapsed = now - s->loaded[n]; - period = s->expires[n] - s->loaded[n]; - /* If the timer should have expired then return 0. This can happen - when the host timer signal doesnt occur immediately. It's better to - have a timer appear to sit at zero for a while than have it wrap - around before the guest interrupt is raised. */ - /* ??? Could we trigger the interrupt here? */ - if (elapsed > period) - return 0; - /* We need to calculate count * elapsed / period without overfowing. - Scale both elapsed and period so they fit in a 32-bit int. */ - while (period != (int32_t)period) { - period >>= 1; - elapsed >>= 1; - } - return ((uint64_t)s->count[n] * (uint64_t)(int32_t)elapsed) - / (int32_t)period; -} - -static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset) -{ - int n; - icp_pit_state *s = (icp_pit_state *)opaque; - - offset -= s->base; - n = offset >> 8; - if (n > 2) - cpu_abort (cpu_single_env, "icp_pit_read: Bad timer %x\n", offset); - switch ((offset & 0xff) >> 2) { - case 0: /* TimerLoad */ - case 6: /* TimerBGLoad */ - return s->limit[n]; - case 1: /* TimerValue */ - return icp_pit_getcount(s, n, qemu_get_clock(vm_clock)); - case 2: /* TimerControl */ - return s->control[n]; - case 4: /* TimerRIS */ - return s->int_level[n]; - case 5: /* TimerMIS */ - if ((s->control[n] & 0x20) == 0) - return 0; - return s->int_level[n]; - default: - cpu_abort (cpu_single_env, "icp_pit_read: Bad offset %x\n", offset); - return 0; - } -} - -static void icp_pit_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - icp_pit_state *s = (icp_pit_state *)opaque; - int n; - int64_t now; - - now = qemu_get_clock(vm_clock); - offset -= s->base; - n = offset >> 8; - if (n > 2) - cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset); - - switch ((offset & 0xff) >> 2) { - case 0: /* TimerLoad */ - s->limit[n] = value; - s->count[n] = value; - s->expires[n] = now; - icp_pit_reload(s, n); - break; - case 1: /* TimerValue */ - /* ??? Linux seems to want to write to this readonly register. - Ignore it. */ - break; - case 2: /* TimerControl */ - if (s->control[n] & 0x80) { - /* Pause the timer if it is running. This may cause some - inaccuracy dure to rounding, but avoids a whole lot of other - messyness. */ - s->count[n] = icp_pit_getcount(s, n, now); - } - s->control[n] = value; - if (n == 0) - s->freq[n] = ICP_BUS_FREQ; - else - s->freq[n] = 1000000; - /* ??? Need to recalculate expiry time after changing divisor. */ - switch ((value >> 2) & 3) { - case 1: s->freq[n] >>= 4; break; - case 2: s->freq[n] >>= 8; break; - } - if (s->control[n] & 0x80) { - /* Restart the timer if still enabled. */ - s->expires[n] = now; - icp_pit_reload(s, n); - } - break; - case 3: /* TimerIntClr */ - s->int_level[n] = 0; - break; - case 6: /* TimerBGLoad */ - s->limit[n] = value; - break; - default: - cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset); - } - icp_pit_update(s, now); -} - -static void icp_pit_tick(void *opaque) -{ - int64_t now; - - now = qemu_get_clock(vm_clock); - icp_pit_update((icp_pit_state *)opaque, now); -} - -static CPUReadMemoryFunc *icp_pit_readfn[] = { - icp_pit_read, - icp_pit_read, - icp_pit_read -}; - -static CPUWriteMemoryFunc *icp_pit_writefn[] = { - icp_pit_write, - icp_pit_write, - icp_pit_write -}; - -static void icp_pit_init(uint32_t base, icp_pic_state *pic) -{ - int iomemtype; - icp_pit_state *s; - int n; - - s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state)); - s->base = base; - s->pic = pic; - s->freq[0] = ICP_BUS_FREQ; - s->freq[1] = 1000000; - s->freq[2] = 1000000; - for (n = 0; n < 3; n++) { - s->control[n] = 0x20; - s->count[n] = 0xffffffff; - } - - iomemtype = cpu_register_io_memory(0, icp_pit_readfn, - icp_pit_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - s->timer = qemu_new_timer(vm_clock, icp_pit_tick, s); - /* ??? Save/restore. */ -} - -/* ARM PrimeCell PL011 UART */ - -typedef struct { - uint32_t base; - uint32_t readbuff; - uint32_t flags; - uint32_t lcr; - uint32_t cr; - uint32_t dmacr; - uint32_t int_enabled; - uint32_t int_level; - uint32_t read_fifo[16]; - uint32_t ilpr; - uint32_t ibrd; - uint32_t fbrd; - uint32_t ifl; - int read_pos; - int read_count; - int read_trigger; - CharDriverState *chr; - icp_pic_state *pic; - int irq; -} pl011_state; - -#define PL011_INT_TX 0x20 -#define PL011_INT_RX 0x10 - -#define PL011_FLAG_TXFE 0x80 -#define PL011_FLAG_RXFF 0x40 -#define PL011_FLAG_TXFF 0x20 -#define PL011_FLAG_RXFE 0x10 - -static const unsigned char pl011_id[] = -{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; - -static void pl011_update(pl011_state *s) -{ - uint32_t flags; - - flags = s->int_level & s->int_enabled; - pic_set_irq_new(s->pic, s->irq, flags != 0); -} - -static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) -{ - pl011_state *s = (pl011_state *)opaque; - uint32_t c; - - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) { - return pl011_id[(offset - 0xfe0) >> 2]; - } - switch (offset >> 2) { - case 0: /* UARTDR */ - s->flags &= ~PL011_FLAG_RXFF; - c = s->read_fifo[s->read_pos]; - if (s->read_count > 0) { - s->read_count--; - if (++s->read_pos == 16) - s->read_pos = 0; - } - if (s->read_count == 0) { - s->flags |= PL011_FLAG_RXFE; - } - if (s->read_count == s->read_trigger - 1) - s->int_level &= ~ PL011_INT_RX; - pl011_update(s); - return c; - case 1: /* UARTCR */ - return 0; - case 6: /* UARTFR */ - return s->flags; - case 8: /* UARTILPR */ - return s->ilpr; - case 9: /* UARTIBRD */ - return s->ibrd; - case 10: /* UARTFBRD */ - return s->fbrd; - case 11: /* UARTLCR_H */ - return s->lcr; - case 12: /* UARTCR */ - return s->cr; - case 13: /* UARTIFLS */ - return s->ifl; - case 14: /* UARTIMSC */ - return s->int_enabled; - case 15: /* UARTRIS */ - return s->int_level; - case 16: /* UARTMIS */ - return s->int_level & s->int_enabled; - case 18: /* UARTDMACR */ - return s->dmacr; - default: - cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset); - return 0; - } -} - -static void pl011_set_read_trigger(pl011_state *s) -{ -#if 0 - /* The docs say the RX interrupt is triggered when the FIFO exceeds - the threshold. However linux only reads the FIFO in response to an - interrupt. Triggering the interrupt when the FIFO is non-empty seems - to make things work. */ - if (s->lcr & 0x10) - s->read_trigger = (s->ifl >> 1) & 0x1c; - else -#endif - s->read_trigger = 1; -} - -static void pl011_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - pl011_state *s = (pl011_state *)opaque; - unsigned char ch; - - offset -= s->base; - switch (offset >> 2) { - case 0: /* UARTDR */ - /* ??? Check if transmitter is enabled. */ - ch = value; - if (s->chr) - qemu_chr_write(s->chr, &ch, 1); - s->int_level |= PL011_INT_TX; - pl011_update(s); - break; - case 1: /* UARTCR */ - s->cr = value; - break; - case 8: /* UARTUARTILPR */ - s->ilpr = value; - break; - case 9: /* UARTIBRD */ - s->ibrd = value; - break; - case 10: /* UARTFBRD */ - s->fbrd = value; - break; - case 11: /* UARTLCR_H */ - s->lcr = value; - pl011_set_read_trigger(s); - break; - case 12: /* UARTCR */ - /* ??? Need to implement the enable and loopback bits. */ - s->cr = value; - break; - case 13: /* UARTIFS */ - s->ifl = value; - pl011_set_read_trigger(s); - break; - case 14: /* UARTIMSC */ - s->int_enabled = value; - pl011_update(s); - break; - case 17: /* UARTICR */ - s->int_level &= ~value; - pl011_update(s); - break; - case 18: /* UARTDMACR */ - s->dmacr = value; - if (value & 3) - cpu_abort(cpu_single_env, "PL011: DMA not implemented\n"); - break; - default: - cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset); - } -} - -static int pl011_can_recieve(void *opaque) -{ - pl011_state *s = (pl011_state *)opaque; - - if (s->lcr & 0x10) - return s->read_count < 16; - else - return s->read_count < 1; -} - -static void pl011_recieve(void *opaque, const uint8_t *buf, int size) -{ - pl011_state *s = (pl011_state *)opaque; - int slot; - - slot = s->read_pos + s->read_count; - if (slot >= 16) - slot -= 16; - s->read_fifo[slot] = *buf; - s->read_count++; - s->flags &= ~PL011_FLAG_RXFE; - if (s->cr & 0x10 || s->read_count == 16) { - s->flags |= PL011_FLAG_RXFF; - } - if (s->read_count == s->read_trigger) { - s->int_level |= PL011_INT_RX; - pl011_update(s); - } -} - -static void pl011_event(void *opaque, int event) -{ - /* ??? Should probably implement break. */ -} - -static CPUReadMemoryFunc *pl011_readfn[] = { - pl011_read, - pl011_read, - pl011_read -}; - -static CPUWriteMemoryFunc *pl011_writefn[] = { - pl011_write, - pl011_write, - pl011_write -}; - -static void pl011_init(uint32_t base, icp_pic_state *pic, int irq, - CharDriverState *chr) -{ - int iomemtype; - pl011_state *s; - - s = (pl011_state *)qemu_mallocz(sizeof(pl011_state)); - iomemtype = cpu_register_io_memory(0, pl011_readfn, - pl011_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - s->base = base; - s->pic = pic; - s->irq = irq; - s->chr = chr; - s->read_trigger = 1; - s->ifl = 0x12; - s->cr = 0x300; - s->flags = 0x90; - if (chr){ - qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s); - qemu_chr_add_event_handler(chr, pl011_event); - } - /* ??? Save/restore. */ -} - /* CP control registers. */ typedef struct { uint32_t base; @@ -985,122 +470,6 @@ static void icp_control_init(uint32_t base) } -/* Keyboard/Mouse Interface. */ - -typedef struct { - void *dev; - uint32_t base; - uint32_t cr; - uint32_t clk; - uint32_t last; - icp_pic_state *pic; - int pending; - int irq; - int is_mouse; -} icp_kmi_state; - -static void icp_kmi_update(void *opaque, int level) -{ - icp_kmi_state *s = (icp_kmi_state *)opaque; - int raise; - - s->pending = level; - raise = (s->pending && (s->cr & 0x10) != 0) - || (s->cr & 0x08) != 0; - pic_set_irq_new(s->pic, s->irq, raise); -} - -static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset) -{ - icp_kmi_state *s = (icp_kmi_state *)opaque; - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) - return 0; - - switch (offset >> 2) { - case 0: /* KMICR */ - return s->cr; - case 1: /* KMISTAT */ - /* KMIC and KMID bits not implemented. */ - if (s->pending) { - return 0x10; - } else { - return 0; - } - case 2: /* KMIDATA */ - if (s->pending) - s->last = ps2_read_data(s->dev); - return s->last; - case 3: /* KMICLKDIV */ - return s->clk; - case 4: /* KMIIR */ - return s->pending | 2; - default: - cpu_abort (cpu_single_env, "icp_kmi_read: Bad offset %x\n", offset); - return 0; - } -} - -static void icp_kmi_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - icp_kmi_state *s = (icp_kmi_state *)opaque; - offset -= s->base; - switch (offset >> 2) { - case 0: /* KMICR */ - s->cr = value; - icp_kmi_update(s, s->pending); - /* ??? Need to implement the enable/disable bit. */ - break; - case 2: /* KMIDATA */ - /* ??? This should toggle the TX interrupt line. */ - /* ??? This means kbd/mouse can block each other. */ - if (s->is_mouse) { - ps2_write_mouse(s->dev, value); - } else { - ps2_write_keyboard(s->dev, value); - } - break; - case 3: /* KMICLKDIV */ - s->clk = value; - return; - default: - cpu_abort (cpu_single_env, "icp_kmi_write: Bad offset %x\n", offset); - } -} -static CPUReadMemoryFunc *icp_kmi_readfn[] = { - icp_kmi_read, - icp_kmi_read, - icp_kmi_read -}; - -static CPUWriteMemoryFunc *icp_kmi_writefn[] = { - icp_kmi_write, - icp_kmi_write, - icp_kmi_write -}; - -static void icp_kmi_init(uint32_t base, icp_pic_state * pic, int irq, - int is_mouse) -{ - int iomemtype; - icp_kmi_state *s; - - s = (icp_kmi_state *)qemu_mallocz(sizeof(icp_kmi_state)); - iomemtype = cpu_register_io_memory(0, icp_kmi_readfn, - icp_kmi_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - s->base = base; - s->pic = pic; - s->irq = irq; - s->is_mouse = is_mouse; - if (is_mouse) - s->dev = ps2_mouse_init(icp_kmi_update, s); - else - s->dev = ps2_kbd_init(icp_kmi_update, s); - /* ??? Save/restore. */ -} - /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ static uint32_t bootloader[] = { 0xe3a00000, /* mov r0, #0 */ @@ -1162,6 +531,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, CPUState *env; uint32_t bios_offset; icp_pic_state *pic; + void *cpu_pic; int kernel_size; int initrd_size; int n; @@ -1177,14 +547,15 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM); integratorcm_init(ram_size >> 20, bios_offset); - pic = icp_pic_init(0x14000000, env, -1); - icp_pic_init(0xca000000, pic, 26); - icp_pit_init(0x13000000, pic); + cpu_pic = arm_pic_init_cpu(env); + pic = icp_pic_init(0x14000000, cpu_pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); + icp_pic_init(0xca000000, pic, 26, -1); + icp_pit_init(0x13000000, pic, 5); pl011_init(0x16000000, pic, 1, serial_hds[0]); pl011_init(0x17000000, pic, 2, serial_hds[1]); icp_control_init(0xcb000000); - icp_kmi_init(0x18000000, pic, 3, 0); - icp_kmi_init(0x19000000, pic, 4, 1); + pl050_init(0x18000000, pic, 3, 0); + pl050_init(0x19000000, pic, 4, 1); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "smc91c111") == 0) { diff --git a/hw/pl011.c b/hw/pl011.c new file mode 100644 index 000000000..657f03bbe --- /dev/null +++ b/hw/pl011.c @@ -0,0 +1,251 @@ +/* + * Arm PrimeCell PL011 UART + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +typedef struct { + uint32_t base; + uint32_t readbuff; + uint32_t flags; + uint32_t lcr; + uint32_t cr; + uint32_t dmacr; + uint32_t int_enabled; + uint32_t int_level; + uint32_t read_fifo[16]; + uint32_t ilpr; + uint32_t ibrd; + uint32_t fbrd; + uint32_t ifl; + int read_pos; + int read_count; + int read_trigger; + CharDriverState *chr; + void *pic; + int irq; +} pl011_state; + +#define PL011_INT_TX 0x20 +#define PL011_INT_RX 0x10 + +#define PL011_FLAG_TXFE 0x80 +#define PL011_FLAG_RXFF 0x40 +#define PL011_FLAG_TXFF 0x20 +#define PL011_FLAG_RXFE 0x10 + +static const unsigned char pl011_id[] = +{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; + +static void pl011_update(pl011_state *s) +{ + uint32_t flags; + + flags = s->int_level & s->int_enabled; + pic_set_irq_new(s->pic, s->irq, flags != 0); +} + +static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) +{ + pl011_state *s = (pl011_state *)opaque; + uint32_t c; + + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) { + return pl011_id[(offset - 0xfe0) >> 2]; + } + switch (offset >> 2) { + case 0: /* UARTDR */ + s->flags &= ~PL011_FLAG_RXFF; + c = s->read_fifo[s->read_pos]; + if (s->read_count > 0) { + s->read_count--; + if (++s->read_pos == 16) + s->read_pos = 0; + } + if (s->read_count == 0) { + s->flags |= PL011_FLAG_RXFE; + } + if (s->read_count == s->read_trigger - 1) + s->int_level &= ~ PL011_INT_RX; + pl011_update(s); + return c; + case 1: /* UARTCR */ + return 0; + case 6: /* UARTFR */ + return s->flags; + case 8: /* UARTILPR */ + return s->ilpr; + case 9: /* UARTIBRD */ + return s->ibrd; + case 10: /* UARTFBRD */ + return s->fbrd; + case 11: /* UARTLCR_H */ + return s->lcr; + case 12: /* UARTCR */ + return s->cr; + case 13: /* UARTIFLS */ + return s->ifl; + case 14: /* UARTIMSC */ + return s->int_enabled; + case 15: /* UARTRIS */ + return s->int_level; + case 16: /* UARTMIS */ + return s->int_level & s->int_enabled; + case 18: /* UARTDMACR */ + return s->dmacr; + default: + cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset); + return 0; + } +} + +static void pl011_set_read_trigger(pl011_state *s) +{ +#if 0 + /* The docs say the RX interrupt is triggered when the FIFO exceeds + the threshold. However linux only reads the FIFO in response to an + interrupt. Triggering the interrupt when the FIFO is non-empty seems + to make things work. */ + if (s->lcr & 0x10) + s->read_trigger = (s->ifl >> 1) & 0x1c; + else +#endif + s->read_trigger = 1; +} + +static void pl011_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + pl011_state *s = (pl011_state *)opaque; + unsigned char ch; + + offset -= s->base; + switch (offset >> 2) { + case 0: /* UARTDR */ + /* ??? Check if transmitter is enabled. */ + ch = value; + if (s->chr) + qemu_chr_write(s->chr, &ch, 1); + s->int_level |= PL011_INT_TX; + pl011_update(s); + break; + case 1: /* UARTCR */ + s->cr = value; + break; + case 8: /* UARTUARTILPR */ + s->ilpr = value; + break; + case 9: /* UARTIBRD */ + s->ibrd = value; + break; + case 10: /* UARTFBRD */ + s->fbrd = value; + break; + case 11: /* UARTLCR_H */ + s->lcr = value; + pl011_set_read_trigger(s); + break; + case 12: /* UARTCR */ + /* ??? Need to implement the enable and loopback bits. */ + s->cr = value; + break; + case 13: /* UARTIFS */ + s->ifl = value; + pl011_set_read_trigger(s); + break; + case 14: /* UARTIMSC */ + s->int_enabled = value; + pl011_update(s); + break; + case 17: /* UARTICR */ + s->int_level &= ~value; + pl011_update(s); + break; + case 18: /* UARTDMACR */ + s->dmacr = value; + if (value & 3) + cpu_abort(cpu_single_env, "PL011: DMA not implemented\n"); + break; + default: + cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset); + } +} + +static int pl011_can_recieve(void *opaque) +{ + pl011_state *s = (pl011_state *)opaque; + + if (s->lcr & 0x10) + return s->read_count < 16; + else + return s->read_count < 1; +} + +static void pl011_recieve(void *opaque, const uint8_t *buf, int size) +{ + pl011_state *s = (pl011_state *)opaque; + int slot; + + slot = s->read_pos + s->read_count; + if (slot >= 16) + slot -= 16; + s->read_fifo[slot] = *buf; + s->read_count++; + s->flags &= ~PL011_FLAG_RXFE; + if (s->cr & 0x10 || s->read_count == 16) { + s->flags |= PL011_FLAG_RXFF; + } + if (s->read_count == s->read_trigger) { + s->int_level |= PL011_INT_RX; + pl011_update(s); + } +} + +static void pl011_event(void *opaque, int event) +{ + /* ??? Should probably implement break. */ +} + +static CPUReadMemoryFunc *pl011_readfn[] = { + pl011_read, + pl011_read, + pl011_read +}; + +static CPUWriteMemoryFunc *pl011_writefn[] = { + pl011_write, + pl011_write, + pl011_write +}; + +void pl011_init(uint32_t base, void *pic, int irq, + CharDriverState *chr) +{ + int iomemtype; + pl011_state *s; + + s = (pl011_state *)qemu_mallocz(sizeof(pl011_state)); + iomemtype = cpu_register_io_memory(0, pl011_readfn, + pl011_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + s->base = base; + s->pic = pic; + s->irq = irq; + s->chr = chr; + s->read_trigger = 1; + s->ifl = 0x12; + s->cr = 0x300; + s->flags = 0x90; + if (chr){ + qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s); + qemu_chr_add_event_handler(chr, pl011_event); + } + /* ??? Save/restore. */ +} + diff --git a/hw/pl050.c b/hw/pl050.c new file mode 100644 index 000000000..a71ccf614 --- /dev/null +++ b/hw/pl050.c @@ -0,0 +1,127 @@ +/* + * Arm PrimeCell PL050 Kyeboard / Mouse Interface + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +typedef struct { + void *dev; + uint32_t base; + uint32_t cr; + uint32_t clk; + uint32_t last; + void *pic; + int pending; + int irq; + int is_mouse; +} pl050_state; + +static const unsigned char pl050_id[] = +{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; + +static void pl050_update(void *opaque, int level) +{ + pl050_state *s = (pl050_state *)opaque; + int raise; + + s->pending = level; + raise = (s->pending && (s->cr & 0x10) != 0) + || (s->cr & 0x08) != 0; + pic_set_irq_new(s->pic, s->irq, raise); +} + +static uint32_t pl050_read(void *opaque, target_phys_addr_t offset) +{ + pl050_state *s = (pl050_state *)opaque; + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) + return pl050_id[(offset - 0xfe0) >> 2]; + + switch (offset >> 2) { + case 0: /* KMICR */ + return s->cr; + case 1: /* KMISTAT */ + /* KMIC and KMID bits not implemented. */ + if (s->pending) { + return 0x10; + } else { + return 0; + } + case 2: /* KMIDATA */ + if (s->pending) + s->last = ps2_read_data(s->dev); + return s->last; + case 3: /* KMICLKDIV */ + return s->clk; + case 4: /* KMIIR */ + return s->pending | 2; + default: + cpu_abort (cpu_single_env, "pl050_read: Bad offset %x\n", offset); + return 0; + } +} + +static void pl050_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + pl050_state *s = (pl050_state *)opaque; + offset -= s->base; + switch (offset >> 2) { + case 0: /* KMICR */ + s->cr = value; + pl050_update(s, s->pending); + /* ??? Need to implement the enable/disable bit. */ + break; + case 2: /* KMIDATA */ + /* ??? This should toggle the TX interrupt line. */ + /* ??? This means kbd/mouse can block each other. */ + if (s->is_mouse) { + ps2_write_mouse(s->dev, value); + } else { + ps2_write_keyboard(s->dev, value); + } + break; + case 3: /* KMICLKDIV */ + s->clk = value; + return; + default: + cpu_abort (cpu_single_env, "pl050_write: Bad offset %x\n", offset); + } +} +static CPUReadMemoryFunc *pl050_readfn[] = { + pl050_read, + pl050_read, + pl050_read +}; + +static CPUWriteMemoryFunc *pl050_writefn[] = { + pl050_write, + pl050_write, + pl050_write +}; + +void pl050_init(uint32_t base, void *pic, int irq, int is_mouse) +{ + int iomemtype; + pl050_state *s; + + s = (pl050_state *)qemu_mallocz(sizeof(pl050_state)); + iomemtype = cpu_register_io_memory(0, pl050_readfn, + pl050_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + s->base = base; + s->pic = pic; + s->irq = irq; + s->is_mouse = is_mouse; + if (is_mouse) + s->dev = ps2_mouse_init(pl050_update, s); + else + s->dev = ps2_kbd_init(pl050_update, s); + /* ??? Save/restore. */ +} + diff --git a/hw/pl080.c b/hw/pl080.c new file mode 100644 index 000000000..49996ca91 --- /dev/null +++ b/hw/pl080.c @@ -0,0 +1,328 @@ +/* + * Arm PrimeCell PL080 DMA controller + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +#define PL080_NUM_CHANNELS 8 +#define PL080_CONF_E 0x1 +#define PL080_CONF_M1 0x2 +#define PL080_CONF_M2 0x4 + +#define PL080_CCONF_H 0x40000 +#define PL080_CCONF_A 0x20000 +#define PL080_CCONF_L 0x10000 +#define PL080_CCONF_ITC 0x08000 +#define PL080_CCONF_IE 0x04000 +#define PL080_CCONF_E 0x00001 + +#define PL080_CCTRL_I 0x80000000 +#define PL080_CCTRL_DI 0x08000000 +#define PL080_CCTRL_SI 0x04000000 +#define PL080_CCTRL_D 0x02000000 +#define PL080_CCTRL_S 0x01000000 + +typedef struct { + uint32_t src; + uint32_t dest; + uint32_t lli; + uint32_t ctrl; + uint32_t conf; +} pl080_channel; + +typedef struct { + uint32_t base; + uint8_t tc_int; + uint8_t tc_mask; + uint8_t err_int; + uint8_t err_mask; + uint32_t conf; + uint32_t sync; + uint32_t req_single; + uint32_t req_burst; + pl080_channel chan[PL080_NUM_CHANNELS]; + /* Flag to avoid recursive DMA invocations. */ + int running; + void *pic; + int irq; +} pl080_state; + +static const unsigned char pl080_id[] = +{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; + +static void pl080_update(pl080_state *s) +{ + if ((s->tc_int & s->tc_mask) + || (s->err_int & s->err_mask)) + pic_set_irq_new(s->pic, s->irq, 1); + else + pic_set_irq_new(s->pic, s->irq, 1); +} + +static void pl080_run(pl080_state *s) +{ + int c; + int flow; + pl080_channel *ch; + int swidth; + int dwidth; + int xsize; + int n; + int src_id; + int dest_id; + int size; + char buff[4]; + uint32_t req; + + s->tc_mask = 0; + for (c = 0; c < PL080_NUM_CHANNELS; c++) { + if (s->chan[c].conf & PL080_CCONF_ITC) + s->tc_mask |= 1 << c; + if (s->chan[c].conf & PL080_CCONF_IE) + s->err_mask |= 1 << c; + } + + if ((s->conf & PL080_CONF_E) == 0) + return; + +cpu_abort(cpu_single_env, "DMA active\n"); + /* If we are already in the middle of a DMA operation then indicate that + there may be new DMA requests and return immediately. */ + if (s->running) { + s->running++; + return; + } + s->running = 1; + while (s->running) { + for (c = 0; c < PL080_NUM_CHANNELS; c++) { + ch = &s->chan[c]; +again: + /* Test if thiws channel has any pending DMA requests. */ + if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E)) + != PL080_CCONF_E) + continue; + flow = (ch->conf >> 11) & 7; + if (flow >= 4) { + cpu_abort(cpu_single_env, + "pl080_run: Peripheral flow control not implemented\n"); + } + src_id = (ch->conf >> 1) & 0x1f; + dest_id = (ch->conf >> 6) & 0x1f; + size = ch->ctrl & 0xfff; + req = s->req_single | s->req_burst; + switch (flow) { + case 0: + break; + case 1: + if ((req & (1u << dest_id)) == 0) + size = 0; + break; + case 2: + if ((req & (1u << src_id)) == 0) + size = 0; + break; + case 3: + if ((req & (1u << src_id)) == 0 + || (req & (1u << dest_id)) == 0) + size = 0; + break; + } + if (!size) + continue; + + /* Transfer one element. */ + /* ??? Should transfer multiple elements for a burst request. */ + /* ??? Unclear what the proper behavior is when source and + destination widths are different. */ + swidth = 1 << ((ch->ctrl >> 18) & 7); + dwidth = 1 << ((ch->ctrl >> 21) & 7); + for (n = 0; n < dwidth; n+= swidth) { + cpu_physical_memory_read(ch->src, buff + n, swidth); + if (ch->ctrl & PL080_CCTRL_SI) + ch->src += swidth; + } + xsize = (dwidth < swidth) ? swidth : dwidth; + /* ??? This may pad the value incorrectly for dwidth < 32. */ + for (n = 0; n < xsize; n += dwidth) { + cpu_physical_memory_write(ch->dest + n, buff + n, dwidth); + if (ch->ctrl & PL080_CCTRL_DI) + ch->dest += swidth; + } + + size--; + ch->ctrl = (ch->ctrl & 0xfffff000) | size; + if (size == 0) { + /* Transfer complete. */ + if (ch->lli) { + ch->src = ldl_phys(ch->lli); + ch->dest = ldl_phys(ch->lli + 4); + ch->ctrl = ldl_phys(ch->lli + 12); + ch->lli = ldl_phys(ch->lli + 8); + } else { + ch->conf &= ~PL080_CCONF_E; + } + if (ch->ctrl & PL080_CCTRL_I) { + s->tc_int |= 1 << c; + } + } + goto again; + } + if (--s->running) + s->running = 1; + } +} + +static uint32_t pl080_read(void *opaque, target_phys_addr_t offset) +{ + pl080_state *s = (pl080_state *)opaque; + uint32_t i; + uint32_t mask; + + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) { + return pl080_id[(offset - 0xfe0) >> 2]; + } + if (offset >= 0x100 && offset < 0x200) { + i = (offset & 0xe0) >> 5; + switch (offset >> 2) { + case 0: /* SrcAddr */ + return s->chan[i].src; + case 1: /* DestAddr */ + return s->chan[i].dest; + case 2: /* LLI */ + return s->chan[i].lli; + case 3: /* Control */ + return s->chan[i].ctrl; + case 4: /* Configuration */ + return s->chan[i].conf; + default: + goto bad_offset; + } + } + switch (offset >> 2) { + case 0: /* IntStatus */ + return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask); + case 1: /* IntTCStatus */ + return (s->tc_int & s->tc_mask); + case 3: /* IntErrorStatus */ + return (s->err_int & s->err_mask); + case 5: /* RawIntTCStatus */ + return s->tc_int; + case 6: /* RawIntErrorStatus */ + return s->err_int; + case 7: /* EnbldChns */ + mask = 0; + for (i = 0; i < PL080_NUM_CHANNELS; i++) { + if (s->chan[i].conf & PL080_CCONF_E) + mask |= 1 << i; + } + return mask; + case 8: /* SoftBReq */ + case 9: /* SoftSReq */ + case 10: /* SoftLBReq */ + case 11: /* SoftLSReq */ + /* ??? Implement these. */ + return 0; + case 12: /* Configuration */ + return s->conf; + case 13: /* Sync */ + return s->sync; + default: + bad_offset: + cpu_abort(cpu_single_env, "pl080_read: Bad offset %x\n", offset); + return 0; + } +} + +static void pl080_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + pl080_state *s = (pl080_state *)opaque; + int i; + + offset -= s->base; + if (offset >= 0x100 && offset < 0x200) { + i = (offset & 0xe0) >> 5; + switch (offset >> 2) { + case 0: /* SrcAddr */ + s->chan[i].src = value; + break; + case 1: /* DestAddr */ + s->chan[i].dest = value; + break; + case 2: /* LLI */ + s->chan[i].lli = value; + break; + case 3: /* Control */ + s->chan[i].ctrl = value; + break; + case 4: /* Configuration */ + s->chan[i].conf = value; + pl080_run(s); + break; + } + } + switch (offset >> 2) { + case 2: /* IntTCClear */ + s->tc_int &= ~value; + break; + case 4: /* IntErrorClear */ + s->err_int &= ~value; + break; + case 8: /* SoftBReq */ + case 9: /* SoftSReq */ + case 10: /* SoftLBReq */ + case 11: /* SoftLSReq */ + /* ??? Implement these. */ + cpu_abort(cpu_single_env, "pl080_write: Soft DMA not implemented\n"); + break; + case 12: /* Configuration */ + s->conf = value; + if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) { + cpu_abort(cpu_single_env, + "pl080_write: Big-endian DMA not implemented\n"); + } + pl080_run(s); + break; + case 13: /* Sync */ + s->sync = value; + break; + default: + cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset); + } + pl080_update(s); +} + +static CPUReadMemoryFunc *pl080_readfn[] = { + pl080_read, + pl080_read, + pl080_read +}; + +static CPUWriteMemoryFunc *pl080_writefn[] = { + pl080_write, + pl080_write, + pl080_write +}; + +void *pl080_init(uint32_t base, void *pic, int irq) +{ + int iomemtype; + pl080_state *s; + + s = (pl080_state *)qemu_mallocz(sizeof(pl080_state)); + iomemtype = cpu_register_io_memory(0, pl080_readfn, + pl080_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + s->base = base; + s->pic = pic; + s->irq = irq; + /* ??? Save/restore. */ + return s; +} + diff --git a/hw/pl110.c b/hw/pl110.c index 839f103b1..09352e742 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -1,7 +1,7 @@ /* * Arm PrimeCell PL110 Color LCD Controller * - * Copyright (c) 2005 CodeSourcery, LLC. + * Copyright (c) 2005-2006 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GNU LGPL @@ -27,6 +27,8 @@ enum pl110_bppmode typedef struct { uint32_t base; DisplayState *ds; + /* The Versatile/PB uses a slightly modified PL110 controller. */ + int versatile; void *pic; uint32_t timing[4]; uint32_t cr; @@ -46,6 +48,15 @@ typedef struct { static const unsigned char pl110_id[] = { 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; +/* The Arm documentation (DDI0224C) says the CLDC on the Versatile board + has a different ID. However Linux only looks for the normal ID. */ +#if 0 +static const unsigned char pl110_versatile_id[] = +{ 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; +#else +#define pl110_versatile_id pl110_id +#endif + static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) { return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); @@ -101,7 +112,7 @@ static void pl110_update_display(void *opaque) int src_width; uint8_t *dest; uint8_t *src; - int first, last; + int first, last = 0; int dirty, new_dirty; int i; @@ -269,7 +280,10 @@ static uint32_t pl110_read(void *opaque, target_phys_addr_t offset) offset -= s->base; if (offset >= 0xfe0 && offset < 0x1000) { - return pl110_id[(offset - 0xfe0) >> 2]; + if (s->versatile) + return pl110_versatile_id[(offset - 0xfe0) >> 2]; + else + return pl110_id[(offset - 0xfe0) >> 2]; } if (offset >= 0x200 && offset < 0x400) { return s->raw_pallette[(offset - 0x200) >> 2]; @@ -347,10 +361,16 @@ static void pl110_write(void *opaque, target_phys_addr_t offset, s->lpbase = val; break; case 6: /* LCDIMSC */ + if (s->versatile) + goto control; + imsc: s->int_mask = val; pl110_update(s); break; case 7: /* LCDControl */ + if (s->versatile) + goto imsc; + control: s->cr = val; s->bpp = (val >> 1) & 7; if (pl110_enabled(s)) { @@ -390,6 +410,7 @@ void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, cpu_register_physical_memory(base, 0x00000fff, iomemtype); s->base = base; s->ds = ds; + s->versatile = versatile; s->pic = pic; s->irq = irq; graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, diff --git a/hw/pl190.c b/hw/pl190.c new file mode 100644 index 000000000..55c7180f5 --- /dev/null +++ b/hw/pl190.c @@ -0,0 +1,252 @@ +/* + * Arm PrimeCell PL190 Vector Interrupt Controller + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "arm_pic.h" + +/* The number of virtual priority levels. 16 user vectors plus the + unvectored IRQ. Chained interrupts would require an additional level + if implemented. */ + +#define PL190_NUM_PRIO 17 + +typedef struct { + arm_pic_handler handler; + uint32_t base; + DisplayState *ds; + uint32_t level; + uint32_t soft_level; + uint32_t irq_enable; + uint32_t fiq_select; + uint32_t default_addr; + uint8_t vect_control[16]; + uint32_t vect_addr[PL190_NUM_PRIO]; + /* Mask containing interrupts with higher priority than this one. */ + uint32_t prio_mask[PL190_NUM_PRIO + 1]; + int protected; + /* Current priority level. */ + int priority; + int prev_prio[PL190_NUM_PRIO]; + void *parent; + int irq; + int fiq; +} pl190_state; + +static const unsigned char pl190_id[] = +{ 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 }; + +static inline uint32_t pl190_irq_level(pl190_state *s) +{ + return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select; +} + +/* Update interrupts. */ +static void pl190_update(pl190_state *s) +{ + uint32_t level = pl190_irq_level(s); + int set; + + set = (level & s->prio_mask[s->priority]) != 0; + pic_set_irq_new(s->parent, s->irq, set); + set = ((s->level | s->soft_level) & s->fiq_select) != 0; + pic_set_irq_new(s->parent, s->fiq, set); +} + +static void pl190_set_irq(void *opaque, int irq, int level) +{ + pl190_state *s = (pl190_state *)opaque; + + if (level) + s->level |= 1u << irq; + else + s->level &= ~(1u << irq); + pl190_update(s); +} + +static void pl190_update_vectors(pl190_state *s) +{ + uint32_t mask; + int i; + int n; + + mask = 0; + for (i = 0; i < 16; i++) + { + s->prio_mask[i] = mask; + if (s->vect_control[i] & 0x20) + { + n = s->vect_control[i] & 0x1f; + mask |= 1 << n; + } + } + s->prio_mask[16] = mask; + pl190_update(s); +} + +static uint32_t pl190_read(void *opaque, target_phys_addr_t offset) +{ + pl190_state *s = (pl190_state *)opaque; + int i; + + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) { + return pl190_id[(offset - 0xfe0) >> 2]; + } + if (offset >= 0x100 && offset < 0x140) { + return s->vect_addr[(offset - 0x100) >> 2]; + } + if (offset >= 0x200 && offset < 0x240) { + return s->vect_control[(offset - 0x200) >> 2]; + } + switch (offset >> 2) { + case 0: /* IRQSTATUS */ + return pl190_irq_level(s); + case 1: /* FIQSATUS */ + return (s->level | s->soft_level) & s->fiq_select; + case 2: /* RAWINTR */ + return s->level | s->soft_level; + case 3: /* INTSELECT */ + return s->fiq_select; + case 4: /* INTENABLE */ + return s->irq_enable; + case 6: /* SOFTINT */ + return s->soft_level; + case 8: /* PROTECTION */ + return s->protected; + case 12: /* VECTADDR */ + /* Read vector address at the start of an ISR. Increases the + current priority level to that of the current interrupt. */ + for (i = 0; i < s->priority; i++) + { + if ((s->level | s->soft_level) & s->prio_mask[i]) + break; + } + /* Reading this value with no pending interrupts is undefined. + We return the default address. */ + if (i == PL190_NUM_PRIO) + return s->vect_addr[16]; + if (i < s->priority) + { + s->prev_prio[i] = s->priority; + s->priority = i; + pl190_update(s); + } + return s->vect_addr[s->priority]; + case 13: /* DEFVECTADDR */ + return s->vect_addr[16]; + default: + cpu_abort (cpu_single_env, "pl190_read: Bad offset %x\n", offset); + return 0; + } +} + +static void pl190_write(void *opaque, target_phys_addr_t offset, uint32_t val) +{ + pl190_state *s = (pl190_state *)opaque; + + offset -= s->base; + if (offset >= 0x100 && offset < 0x140) { + s->vect_addr[(offset - 0x100) >> 2] = val; + pl190_update_vectors(s); + return; + } + if (offset >= 0x200 && offset < 0x240) { + s->vect_control[(offset - 0x200) >> 2] = val; + pl190_update_vectors(s); + return; + } + switch (offset >> 2) { + case 0: /* SELECT */ + /* This is a readonly register, but linux tries to write to it + anyway. Ignore the write. */ + break; + case 3: /* INTSELECT */ + s->fiq_select = val; + break; + case 4: /* INTENABLE */ + s->irq_enable |= val; + break; + case 5: /* INTENCLEAR */ + s->irq_enable &= ~val; + break; + case 6: /* SOFTINT */ + s->soft_level |= val; + break; + case 7: /* SOFTINTCLEAR */ + s->soft_level &= ~val; + break; + case 8: /* PROTECTION */ + /* TODO: Protection (supervisor only access) is not implemented. */ + s->protected = val & 1; + break; + case 12: /* VECTADDR */ + /* Restore the previous priority level. The value written is + ignored. */ + if (s->priority < PL190_NUM_PRIO) + s->priority = s->prev_prio[s->priority]; + break; + case 13: /* DEFVECTADDR */ + s->default_addr = val; + break; + case 0xc0: /* ITCR */ + if (val) + cpu_abort(cpu_single_env, "pl190: Test mode not implemented\n"); + break; + default: + cpu_abort(cpu_single_env, "pl190_write: Bad offset %x\n", offset); + return; + } + pl190_update(s); +} + +static CPUReadMemoryFunc *pl190_readfn[] = { + pl190_read, + pl190_read, + pl190_read +}; + +static CPUWriteMemoryFunc *pl190_writefn[] = { + pl190_write, + pl190_write, + pl190_write +}; + +void pl190_reset(pl190_state *s) +{ + int i; + + for (i = 0; i < 16; i++) + { + s->vect_addr[i] = 0; + s->vect_control[i] = 0; + } + s->vect_addr[16] = 0; + s->prio_mask[17] = 0xffffffff; + s->priority = PL190_NUM_PRIO; + pl190_update_vectors(s); +} + +void *pl190_init(uint32_t base, void *parent, int irq, int fiq) +{ + pl190_state *s; + int iomemtype; + + s = (pl190_state *)qemu_mallocz(sizeof(pl190_state)); + iomemtype = cpu_register_io_memory(0, pl190_readfn, + pl190_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + s->handler = pl190_set_irq; + s->base = base; + s->parent = parent; + s->irq = irq; + s->fiq = fiq; + pl190_reset(s); + /* ??? Save/restore. */ + return s; +} diff --git a/hw/versatilepb.c b/hw/versatilepb.c new file mode 100644 index 000000000..6d2e2dcfe --- /dev/null +++ b/hw/versatilepb.c @@ -0,0 +1,321 @@ +/* + * ARM Versatile Platform Baseboard System emulation. + * + * Copyright (c) 2005-2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "arm_pic.h" + +#define KERNEL_ARGS_ADDR 0x100 +#define KERNEL_LOAD_ADDR 0x00010000 +#define INITRD_LOAD_ADDR 0x00800000 + +/* Primary interrupt controller. */ + +typedef struct vpb_sic_state +{ + arm_pic_handler handler; + uint32_t base; + uint32_t level; + uint32_t mask; + uint32_t pic_enable; + void *parent; + int irq; +} vpb_sic_state; + +static void vpb_sic_update(vpb_sic_state *s) +{ + uint32_t flags; + + flags = s->level & s->mask; + pic_set_irq_new(s->parent, s->irq, flags != 0); +} + +static void vpb_sic_update_pic(vpb_sic_state *s) +{ + int i; + uint32_t mask; + + for (i = 21; i <= 30; i++) { + mask = 1u << i; + if (!(s->pic_enable & mask)) + continue; + pic_set_irq_new(s->parent, i, (s->level & mask) != 0); + } +} + +static void vpb_sic_set_irq(void *opaque, int irq, int level) +{ + vpb_sic_state *s = (vpb_sic_state *)opaque; + if (level) + s->level |= 1u << irq; + else + s->level &= ~(1u << irq); + if (s->pic_enable & (1u << irq)) + pic_set_irq_new(s->parent, irq, level); + vpb_sic_update(s); +} + +static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset) +{ + vpb_sic_state *s = (vpb_sic_state *)opaque; + + offset -= s->base; + switch (offset >> 2) { + case 0: /* STATUS */ + return s->level & s->mask; + case 1: /* RAWSTAT */ + return s->level; + case 2: /* ENABLE */ + return s->mask; + case 4: /* SOFTINT */ + return s->level & 1; + case 8: /* PICENABLE */ + return s->pic_enable; + default: + printf ("vpb_sic_read: Bad register offset 0x%x\n", offset); + return 0; + } +} + +static void vpb_sic_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + vpb_sic_state *s = (vpb_sic_state *)opaque; + offset -= s->base; + + switch (offset >> 2) { + case 2: /* ENSET */ + s->mask |= value; + break; + case 3: /* ENCLR */ + s->mask &= ~value; + break; + case 4: /* SOFTINTSET */ + if (value) + s->mask |= 1; + break; + case 5: /* SOFTINTCLR */ + if (value) + s->mask &= ~1u; + break; + case 8: /* PICENSET */ + s->pic_enable |= (value & 0x7fe00000); + vpb_sic_update_pic(s); + break; + case 9: /* PICENCLR */ + s->pic_enable &= ~value; + vpb_sic_update_pic(s); + break; + default: + printf ("vpb_sic_write: Bad register offset 0x%x\n", offset); + return; + } + vpb_sic_update(s); +} + +static CPUReadMemoryFunc *vpb_sic_readfn[] = { + vpb_sic_read, + vpb_sic_read, + vpb_sic_read +}; + +static CPUWriteMemoryFunc *vpb_sic_writefn[] = { + vpb_sic_write, + vpb_sic_write, + vpb_sic_write +}; + +static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) +{ + vpb_sic_state *s; + int iomemtype; + + s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state)); + if (!s) + return NULL; + s->handler = vpb_sic_set_irq; + s->base = base; + s->parent = parent; + s->irq = irq; + iomemtype = cpu_register_io_memory(0, vpb_sic_readfn, + vpb_sic_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + /* ??? Save/restore. */ + return s; +} + +/* Board init. */ + +/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ +static uint32_t bootloader[] = { + 0xe3a00000, /* mov r0, #0 */ + 0xe3a01083, /* mov r1, #0x83 */ + 0xe3811c01, /* orr r1, r1, #0x100 */ + 0xe59f2000, /* ldr r2, [pc, #0] */ + 0xe59ff000, /* ldr pc, [pc, #0] */ + 0, /* Address of kernel args. Set by integratorcp_init. */ + 0 /* Kernel entry point. Set by integratorcp_init. */ +}; + +static void set_kernel_args(uint32_t ram_size, int initrd_size, + const char *kernel_cmdline) +{ + uint32_t *p; + + p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); + /* ATAG_CORE */ + stl_raw(p++, 5); + stl_raw(p++, 0x54410001); + stl_raw(p++, 1); + stl_raw(p++, 0x1000); + stl_raw(p++, 0); + /* ATAG_MEM */ + stl_raw(p++, 4); + stl_raw(p++, 0x54410002); + stl_raw(p++, ram_size); + stl_raw(p++, 0); + if (initrd_size) { + /* ATAG_INITRD2 */ + stl_raw(p++, 4); + stl_raw(p++, 0x54420005); + stl_raw(p++, INITRD_LOAD_ADDR); + stl_raw(p++, initrd_size); + } + if (kernel_cmdline && *kernel_cmdline) { + /* ATAG_CMDLINE */ + int cmdline_size; + + cmdline_size = strlen(kernel_cmdline); + memcpy (p + 2, kernel_cmdline, cmdline_size + 1); + cmdline_size = (cmdline_size >> 2) + 1; + stl_raw(p++, cmdline_size + 2); + stl_raw(p++, 0x54410009); + p += cmdline_size; + } + /* ATAG_END */ + stl_raw(p++, 0); + stl_raw(p++, 0); +} + +static void vpb_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + CPUState *env; + int kernel_size; + int initrd_size; + int n; + void *pic; + void *sic; + + env = cpu_init(); + cpu_arm_set_model(env, ARM_CPUID_ARM926); + /* ??? RAM shoud repeat to fill physical memory space. */ + /* SDRAM at address zero. */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + pic = arm_pic_init_cpu(env); + pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); + sic = vpb_sic_init(0x10003000, pic, 31); + pl050_init(0x10006000, sic, 3, 0); + pl050_init(0x10007000, sic, 4, 1); + + /* TODO: Init PCI NICs. */ + if (nd_table[0].vlan) { + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "smc91c111") == 0) { + smc91c111_init(&nd_table[0], 0x10010000, sic, 25); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } + } + + pl011_init(0x101f1000, pic, 12, serial_hds[0]); + pl011_init(0x101f2000, pic, 13, serial_hds[1]); + pl011_init(0x101f3000, pic, 14, serial_hds[2]); + pl011_init(0x10009000, sic, 6, serial_hds[3]); + + pl080_init(0x10130000, pic, 17); + sp804_init(0x101e2000, pic, 4); + sp804_init(0x101e3000, pic, 5); + + /* The versatile/PB actually has a modified Color LCD controller + that includes hardware cursor support from the PL111. */ + pl110_init(ds, 0x10120000, pic, 16, 1); + + /* 0x10000000 System registers. */ + /* 0x10001000 PCI controller config registers. */ + /* 0x10002000 Serial bus interface. */ + /* 0x10003000 Secondary interrupt controller. */ + /* 0x10004000 AACI (audio). */ + /* 0x10005000 MMCI0. */ + /* 0x10006000 KMI0 (keyboard). */ + /* 0x10007000 KMI1 (mouse). */ + /* 0x10008000 Character LCD Interface. */ + /* 0x10009000 UART3. */ + /* 0x1000a000 Smart card 1. */ + /* 0x1000b000 MMCI1. */ + /* 0x10010000 Ethernet. */ + /* 0x10020000 USB. */ + /* 0x10100000 SSMC. */ + /* 0x10110000 MPMC. */ + /* 0x10120000 CLCD Controller. */ + /* 0x10130000 DMA Controller. */ + /* 0x10140000 Vectored interrupt controller. */ + /* 0x101d0000 AHB Monitor Interface. */ + /* 0x101e0000 System Controller. */ + /* 0x101e1000 Watchdog Interface. */ + /* 0x101e2000 Timer 0/1. */ + /* 0x101e3000 Timer 2/3. */ + /* 0x101e4000 GPIO port 0. */ + /* 0x101e5000 GPIO port 1. */ + /* 0x101e6000 GPIO port 2. */ + /* 0x101e7000 GPIO port 3. */ + /* 0x101e8000 RTC. */ + /* 0x101f0000 Smart card 0. */ + /* 0x101f1000 UART0. */ + /* 0x101f2000 UART1. */ + /* 0x101f3000 UART2. */ + /* 0x101f4000 SSPI. */ + + /* Load the kernel. */ + if (!kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + if (initrd_filename) { + initrd_size = load_image(initrd_filename, + phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_size = 0; + } + bootloader[5] = KERNEL_ARGS_ADDR; + bootloader[6] = KERNEL_LOAD_ADDR; + for (n = 0; n < sizeof(bootloader) / 4; n++) + stl_raw(phys_ram_base + (n * 4), bootloader[n]); + set_kernel_args(ram_size, initrd_size, kernel_cmdline); +} + +QEMUMachine versatilepb_machine = { + "versatilepb", + "ARM Versatile/PB (ARM926EJ-S)", + vpb_init, +}; diff --git a/vl.c b/vl.c index ed59988d3..e13ad3d3d 100644 --- a/vl.c +++ b/vl.c @@ -4436,6 +4436,7 @@ void register_machines(void) #elif defined(TARGET_ARM) qemu_register_machine(&integratorcp926_machine); qemu_register_machine(&integratorcp1026_machine); + qemu_register_machine(&versatilepb_machine); #else #error unsupported CPU #endif diff --git a/vl.h b/vl.h index 0c6f0132f..4f118fbfa 100644 --- a/vl.h +++ b/vl.h @@ -966,6 +966,9 @@ void usb_info(void); extern QEMUMachine integratorcp926_machine; extern QEMUMachine integratorcp1026_machine; +/* versatilepb.c */ +extern QEMUMachine versatilepb_machine; + /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); @@ -981,6 +984,22 @@ void smc91c111_init(NICInfo *, uint32_t, void *, int); /* pl110.c */ void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int); +/* pl011.c */ +void pl011_init(uint32_t base, void *pic, int irq, CharDriverState *chr); + +/* pl050.c */ +void pl050_init(uint32_t base, void *pic, int irq, int is_mouse); + +/* pl080.c */ +void *pl080_init(uint32_t base, void *pic, int irq); + +/* pl190.c */ +void *pl190_init(uint32_t base, void *parent, int irq, int fiq); + +/* arm-timer.c */ +void sp804_init(uint32_t base, void *pic, int irq); +void icp_pit_init(uint32_t base, void *pic, int irq); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From 358bf29e802e7f03d32dd4ba2064e1bba23a11fa Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 9 Apr 2006 14:38:57 +0000 Subject: Thumb prefetch abort fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1805 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 1f8a4853b..e6e8c6835 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2295,8 +2295,21 @@ static void disas_thumb_insn(DisasContext *s) case 14: /* unconditional branch */ - if (insn & (1 << 11)) - goto undef; /* Second half of a blx */ + if (insn & (1 << 11)) { + /* Second half of blx. */ + offset = ((insn & 0x7ff) << 1); + gen_movl_T0_reg(s, 14); + gen_op_movl_T1_im(offset); + gen_op_addl_T0_T1(); + gen_op_movl_T1_im(0xfffffffc); + gen_op_andl_T0_T1(); + + val = (uint32_t)s->pc; + gen_op_movl_T1_im(val | 1); + gen_movl_reg_T1(s, 14); + gen_bx(s); + break; + } val = (uint32_t)s->pc; offset = ((int32_t)insn << 21) >> 21; val += (offset << 1) + 2; @@ -2305,6 +2318,29 @@ static void disas_thumb_insn(DisasContext *s) case 15: /* branch and link [and switch to arm] */ + if ((s->pc & ~TARGET_PAGE_MASK) == 0) { + /* Instruction spans a page boundary. Implement it as two + 16-bit instructions in case the second half causes an + prefetch abort. */ + offset = ((int32_t)insn << 21) >> 9; + val = s->pc + 2 + offset; + gen_op_movl_T0_im(val); + gen_movl_reg_T0(s, 14); + break; + } + if (insn & (1 << 11)) { + /* Second half of bl. */ + offset = ((insn & 0x7ff) << 1) | 1; + gen_movl_T0_reg(s, 14); + gen_op_movl_T1_im(offset); + gen_op_addl_T0_T1(); + + val = (uint32_t)s->pc; + gen_op_movl_T1_im(val | 1); + gen_movl_reg_T1(s, 14); + gen_bx(s); + break; + } offset = ((int32_t)insn << 21) >> 10; insn = lduw_code(s->pc); offset |= insn & 0x7ff; -- cgit v1.2.3 From 1236cab73dc7531154f195bb5905d783e3c0487a Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 9 Apr 2006 20:47:35 +0000 Subject: DESTDIR makefile support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1806 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 20 ++++++++++---------- Makefile.target | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index bcc2e07d4..59a549a5c 100644 --- a/Makefile +++ b/Makefile @@ -44,21 +44,21 @@ 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: all - mkdir -p "$(bindir)" - install -m 755 -s $(TOOLS) "$(bindir)" - mkdir -p "$(datadir)" + mkdir -p "$(DESTDIR)$(bindir)" + install -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" + mkdir -p "$(DESTDIR)$(datadir)" install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ pc-bios/vgabios-cirrus.bin \ pc-bios/ppc_rom.bin pc-bios/video.x \ pc-bios/proll.elf \ - pc-bios/linux_boot.bin "$(datadir)" - mkdir -p "$(docdir)" - install -m 644 qemu-doc.html qemu-tech.html "$(docdir)" + pc-bios/linux_boot.bin "$(DESTDIR)$(datadir)" + mkdir -p "$(DESTDIR)$(docdir)" + install -m 644 qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)" ifndef CONFIG_WIN32 - mkdir -p "$(mandir)/man1" - install qemu.1 qemu-img.1 "$(mandir)/man1" - mkdir -p "$(datadir)/keymaps" - install -m 644 $(addprefix keymaps/,$(KEYMAPS)) "$(datadir)/keymaps" + mkdir -p "$(DESTDIR)$(mandir)/man1" + install qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1" + mkdir -p "$(DESTDIR)$(datadir)/keymaps" + install -m 644 $(addprefix keymaps/,$(KEYMAPS)) "$(DESTDIR)$(datadir)/keymaps" endif for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ diff --git a/Makefile.target b/Makefile.target index da69393c5..755fba1e7 100644 --- a/Makefile.target +++ b/Makefile.target @@ -470,7 +470,7 @@ clean: install: all ifneq ($(PROGS),) - install -m 755 -s $(PROGS) "$(bindir)" + install -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)" endif ifneq ($(wildcard .depend),) -- cgit v1.2.3 From f331110f3539ee590b3a856d157f92fb34a88bce Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Apr 2006 20:21:17 +0000 Subject: win32 serial port support (initial patch by kazu git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1807 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 440 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- vl.h | 9 ++ 2 files changed, 444 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index e13ad3d3d..83c671612 100644 --- a/vl.c +++ b/vl.c @@ -1713,11 +1713,381 @@ CharDriverState *qemu_chr_open_pty(void) #endif /* !defined(_WIN32) */ +#ifdef _WIN32 +typedef struct { + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *win_opaque; + int max_size; + HANDLE hcom, hrecv, hsend; + OVERLAPPED orecv, osend; + BOOL fpipe; + DWORD len; +} WinCharState; + +#define NSENDBUF 2048 +#define NRECVBUF 2048 +#define MAXCONNECT 1 +#define NTIMEOUT 5000 + +static int win_chr_poll(void *opaque); +static int win_chr_pipe_poll(void *opaque); + +static void win_chr_close2(WinCharState *s) +{ + if (s->hsend) { + CloseHandle(s->hsend); + s->hsend = NULL; + } + if (s->hrecv) { + CloseHandle(s->hrecv); + s->hrecv = NULL; + } + if (s->hcom) { + CloseHandle(s->hcom); + s->hcom = NULL; + } + if (s->fpipe) + qemu_del_polling_cb(win_chr_pipe_poll, s); + else + qemu_del_polling_cb(win_chr_poll, s); +} + +static void win_chr_close(CharDriverState *chr) +{ + WinCharState *s = chr->opaque; + win_chr_close2(s); +} + +static int win_chr_init(WinCharState *s, const char *filename) +{ + COMMCONFIG comcfg; + COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; + COMSTAT comstat; + DWORD size; + DWORD err; + + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hsend) { + fprintf(stderr, "Failed CreateEvent\n"); + goto fail; + } + s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hrecv) { + fprintf(stderr, "Failed CreateEvent\n"); + goto fail; + } + + s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (s->hcom == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError()); + s->hcom = NULL; + goto fail; + } + + if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { + fprintf(stderr, "Failed SetupComm\n"); + goto fail; + } + + ZeroMemory(&comcfg, sizeof(COMMCONFIG)); + size = sizeof(COMMCONFIG); + GetDefaultCommConfig(filename, &comcfg, &size); + comcfg.dcb.DCBlength = sizeof(DCB); + CommConfigDialog(filename, NULL, &comcfg); + + if (!SetCommState(s->hcom, &comcfg.dcb)) { + fprintf(stderr, "Failed SetCommState\n"); + goto fail; + } + + if (!SetCommMask(s->hcom, EV_ERR)) { + fprintf(stderr, "Failed SetCommMask\n"); + goto fail; + } + + cto.ReadIntervalTimeout = MAXDWORD; + if (!SetCommTimeouts(s->hcom, &cto)) { + fprintf(stderr, "Failed SetCommTimeouts\n"); + goto fail; + } + + if (!ClearCommError(s->hcom, &err, &comstat)) { + fprintf(stderr, "Failed ClearCommError\n"); + goto fail; + } + qemu_add_polling_cb(win_chr_poll, s); + return 0; + + fail: + win_chr_close2(s); + return -1; +} + +static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1) +{ + WinCharState *s = chr->opaque; + DWORD len, ret, size, err; + + len = len1; + ZeroMemory(&s->osend, sizeof(s->osend)); + s->osend.hEvent = s->hsend; + while (len > 0) { + if (s->hsend) + ret = WriteFile(s->hcom, buf, len, &size, &s->osend); + else + ret = WriteFile(s->hcom, buf, len, &size, NULL); + if (!ret) { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE); + if (ret) { + buf += size; + len -= size; + } else { + break; + } + } else { + break; + } + } else { + buf += size; + len -= size; + } + } + return len1 - len; +} + +static int win_chr_read_poll(WinCharState *s) +{ + s->max_size = s->fd_can_read(s->win_opaque); + return s->max_size; +} + +static void win_chr_readfile(WinCharState *s) +{ + int ret, err; + uint8_t buf[1024]; + DWORD size; + + ZeroMemory(&s->orecv, sizeof(s->orecv)); + s->orecv.hEvent = s->hrecv; + ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); + if (!ret) { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE); + } + } + + if (size > 0) { + s->fd_read(s->win_opaque, buf, size); + } +} + +static void win_chr_read(WinCharState *s) +{ + if (s->len > s->max_size) + s->len = s->max_size; + if (s->len == 0) + return; + + win_chr_readfile(s); +} + +static int win_chr_poll(void *opaque) +{ + WinCharState *s = opaque; + COMSTAT status; + DWORD comerr; + + ClearCommError(s->hcom, &comerr, &status); + if (status.cbInQue > 0) { + s->len = status.cbInQue; + win_chr_read_poll(s); + win_chr_read(s); + return 1; + } + return 0; +} + +static void win_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + WinCharState *s = chr->opaque; + + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->win_opaque = opaque; +} + +CharDriverState *qemu_chr_open_win(const char *filename) +{ + CharDriverState *chr; + WinCharState *s; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(WinCharState)); + if (!s) { + free(chr); + return NULL; + } + chr->opaque = s; + chr->chr_write = win_chr_write; + chr->chr_add_read_handler = win_chr_add_read_handler; + chr->chr_close = win_chr_close; + + if (win_chr_init(s, filename) < 0) { + free(s); + free(chr); + return NULL; + } + return chr; +} + +static int win_chr_pipe_poll(void *opaque) +{ + WinCharState *s = opaque; + DWORD size; + + PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); + if (size > 0) { + s->len = size; + win_chr_read_poll(s); + win_chr_read(s); + return 1; + } + return 0; +} + +static int win_chr_pipe_init(WinCharState *s, const char *filename) +{ + OVERLAPPED ov; + int ret; + DWORD size; + char openname[256]; + + s->fpipe = TRUE; + + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hsend) { + fprintf(stderr, "Failed CreateEvent\n"); + goto fail; + } + s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hrecv) { + fprintf(stderr, "Failed CreateEvent\n"); + goto fail; + } + + snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename); + s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | + PIPE_WAIT, + MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL); + if (s->hcom == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError()); + s->hcom = NULL; + goto fail; + } + + ZeroMemory(&ov, sizeof(ov)); + ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + ret = ConnectNamedPipe(s->hcom, &ov); + if (ret) { + fprintf(stderr, "Failed ConnectNamedPipe\n"); + goto fail; + } + + ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE); + if (!ret) { + fprintf(stderr, "Failed GetOverlappedResult\n"); + if (ov.hEvent) { + CloseHandle(ov.hEvent); + ov.hEvent = NULL; + } + goto fail; + } + + if (ov.hEvent) { + CloseHandle(ov.hEvent); + ov.hEvent = NULL; + } + qemu_add_polling_cb(win_chr_pipe_poll, s); + return 0; + + fail: + win_chr_close2(s); + return -1; +} + + +CharDriverState *qemu_chr_open_win_pipe(const char *filename) +{ + CharDriverState *chr; + WinCharState *s; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(WinCharState)); + if (!s) { + free(chr); + return NULL; + } + chr->opaque = s; + chr->chr_write = win_chr_write; + chr->chr_add_read_handler = win_chr_add_read_handler; + chr->chr_close = win_chr_close; + + if (win_chr_pipe_init(s, filename) < 0) { + free(s); + free(chr); + return NULL; + } + return chr; +} + +CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) +{ + CharDriverState *chr; + WinCharState *s; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + s = qemu_mallocz(sizeof(WinCharState)); + if (!s) { + free(chr); + return NULL; + } + s->hcom = fd_out; + chr->opaque = s; + chr->chr_write = win_chr_write; + chr->chr_add_read_handler = win_chr_add_read_handler; + return chr; +} + +CharDriverState *qemu_chr_open_win_file_out(const char *file_out) +{ + HANDLE fd_out; + + fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (fd_out == INVALID_HANDLE_VALUE) + return NULL; + + return qemu_chr_open_win_file(fd_out); +} +#endif + CharDriverState *qemu_chr_open(const char *filename) { -#ifndef _WIN32 const char *p; -#endif if (!strcmp(filename, "vc")) { return text_console_init(&display_state); @@ -1742,12 +2112,29 @@ CharDriverState *qemu_chr_open(const char *filename) if (strstart(filename, "/dev/", NULL)) { return qemu_chr_open_tty(filename); } else +#endif +#ifdef _WIN32 + if (strstart(filename, "COM", NULL)) { + return qemu_chr_open_win(filename); + } else + if (strstart(filename, "pipe:", &p)) { + return qemu_chr_open_win_pipe(p); + } else + if (strstart(filename, "file:", &p)) { + return qemu_chr_open_win_file_out(p); + } #endif { return NULL; } } +void qemu_chr_close(CharDriverState *chr) +{ + if (chr->chr_close) + chr->chr_close(chr); +} + /***********************************************************/ /* network device redirectors */ @@ -3089,6 +3476,43 @@ int qemu_set_fd_handler(int fd, return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); } +/***********************************************************/ +/* Polling handling */ + +typedef struct PollingEntry { + PollingFunc *func; + void *opaque; + struct PollingEntry *next; +} PollingEntry; + +static PollingEntry *first_polling_entry; + +int qemu_add_polling_cb(PollingFunc *func, void *opaque) +{ + PollingEntry **ppe, *pe; + pe = qemu_mallocz(sizeof(PollingEntry)); + if (!pe) + return -1; + pe->func = func; + pe->opaque = opaque; + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next); + *ppe = pe; + return 0; +} + +void qemu_del_polling_cb(PollingFunc *func, void *opaque) +{ + PollingEntry **ppe, *pe; + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) { + pe = *ppe; + if (pe->func == func && pe->opaque == opaque) { + *ppe = pe->next; + qemu_free(pe); + break; + } + } +} + /***********************************************************/ /* savevm/loadvm support */ @@ -3955,12 +4379,18 @@ void main_loop_wait(int timeout) fd_set rfds, wfds; int ret, nfds; struct timeval tv; + PollingEntry *pe; + + /* XXX: need to suppress polling by better using win32 events */ + ret = 0; + for(pe = first_polling_entry; pe != NULL; pe = pe->next) { + ret |= pe->func(pe->opaque); + } #ifdef _WIN32 - /* XXX: see how to merge it with the select. The constraint is - that the select must be interrupted by the timer */ - if (timeout > 0) + if (ret == 0 && timeout > 0) { Sleep(timeout); + } #endif /* poll any events */ /* XXX: separate device handlers from system ones */ diff --git a/vl.h b/vl.h index 4f118fbfa..9b09fa4f9 100644 --- a/vl.h +++ b/vl.h @@ -204,6 +204,14 @@ int qemu_set_fd_handler(int fd, IOHandler *fd_write, void *opaque); +/* Polling handling */ + +/* return TRUE if no sleep should be done afterwards */ +typedef int PollingFunc(void *opaque); + +int qemu_add_polling_cb(PollingFunc *func, void *opaque); +void qemu_del_polling_cb(PollingFunc *func, void *opaque); + /* character device */ #define CHR_EVENT_BREAK 0 /* serial break char */ @@ -237,6 +245,7 @@ typedef struct CharDriverState { int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); IOEventHandler *chr_event; void (*chr_send_event)(struct CharDriverState *chr, int event); + void (*chr_close)(struct CharDriverState *chr); void *opaque; } CharDriverState; -- cgit v1.2.3 From 3e749fe1f75f4b84ee6d8141b65acde9215484b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Apr 2006 20:42:42 +0000 Subject: simulate a null modem cable git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1808 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/serial.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index 254434e66..f36beb209 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -78,7 +78,7 @@ struct SerialState { uint8_t lcr; uint8_t mcr; uint8_t lsr; /* read only */ - uint8_t msr; + uint8_t msr; /* read only */ uint8_t scr; /* NOTE: this hidden state is necessary for tx irq generation as it can be reset while reading iir */ @@ -200,7 +200,6 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 5: break; case 6: - s->msr = val; break; case 7: s->scr = val; @@ -356,6 +355,7 @@ SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, s->irq = irq; s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; + s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; register_savevm("serial", base, 1, serial_save, serial_load, s); @@ -440,6 +440,7 @@ SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, s->irq = irq; s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; + s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; s->base = base; s->it_shift = it_shift; -- cgit v1.2.3 From 6a15fd12ca1bccb72335132686db7adef5937a0a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Apr 2006 21:07:07 +0000 Subject: 64 bit disassembly git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1809 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index 3078b1d4b..3c0fd916f 100644 --- a/monitor.c +++ b/monitor.c @@ -457,10 +457,18 @@ static void memory_dump(int count, int format, int wsize, } else if (wsize == 4) { flags = 0; } else { - /* as default we use the current CS size */ + /* as default we use the current CS size */ flags = 0; - if (env && !(env->segs[R_CS].flags & DESC_B_MASK)) - flags = 1; + if (env) { +#ifdef TARGET_X86_64 + if ((env->efer & MSR_EFER_LMA) && + (env->segs[R_CS].flags & DESC_L_MASK)) + flags = 2; + else +#endif + if (!(env->segs[R_CS].flags & DESC_B_MASK)) + flags = 1; + } } #endif monitor_disas(env, addr, count, is_physical, flags); @@ -1549,6 +1557,7 @@ static target_long expr_unary(void) n = 0; break; default: + /* XXX: 64 bit version */ n = strtoul(pch, &p, 0); if (pch == p) { expr_error("invalid char in expression"); -- cgit v1.2.3 From 09b26c5ec06ff7531a2a2a7b1146011c87285f81 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Apr 2006 21:09:08 +0000 Subject: USB tablet support (Brad Campbell, Anthony Liguori) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1810 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ps2.c | 2 +- hw/usb-hid.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- hw/usb.h | 1 + sdl.c | 50 ++++++++++++-- vl.c | 13 +++- vl.h | 3 +- 6 files changed, 265 insertions(+), 24 deletions(-) diff --git a/hw/ps2.c b/hw/ps2.c index 40be0449f..8438a5e85 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -560,7 +560,7 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_arg = update_arg; ps2_reset(&s->common); register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s); - qemu_add_mouse_event_handler(ps2_mouse_event, s); + qemu_add_mouse_event_handler(ps2_mouse_event, s, 0); qemu_register_reset(ps2_reset, &s->common); return s; } diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 6f9ee827d..17160ebe3 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -30,9 +30,15 @@ #define SET_IDLE 0x210a #define SET_PROTOCOL 0x210b +#define USB_MOUSE 1 +#define USB_TABLET 2 + typedef struct USBMouseState { USBDevice dev; int dx, dy, dz, buttons_state; + int x, y; + int kind; + int mouse_grabbed; } USBMouseState; /* mostly the same values as the Bochs USB Mouse device */ @@ -93,6 +99,15 @@ static const uint8_t qemu_mouse_config_descriptor[] = { 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x05, /* u8 if_iInterface; */ + /* HID descriptor */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 50, 0, /* u16 len */ + /* one endpoint (status change endpoint) */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ @@ -100,6 +115,44 @@ static const uint8_t qemu_mouse_config_descriptor[] = { 0x03, /* u8 ep_bmAttributes; Interrupt */ 0x03, 0x00, /* u16 ep_wMaxPacketSize; */ 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_tablet_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x04, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 50, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; */ + 0x01, /* u8 if_bInterfaceSubClass; */ + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x05, /* u8 if_iInterface; */ /* HID descriptor */ 0x09, /* u8 bLength; */ @@ -108,7 +161,15 @@ static const uint8_t qemu_mouse_config_descriptor[] = { 0x00, /* u8 country_code */ 0x01, /* u8 num_descriptors */ 0x22, /* u8 type; Report */ - 50, 0, /* u16 len */ + 74, 0, /* u16 len */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; static const uint8_t qemu_mouse_hid_report_descriptor[] = { @@ -121,6 +182,46 @@ static const uint8_t qemu_mouse_hid_report_descriptor[] = { 0xC0, 0xC0, }; +static const uint8_t qemu_tablet_hid_report_descriptor[] = { + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x01, /* Usage Mouse */ + 0xA1, 0x01, /* Collection Application */ + 0x09, 0x01, /* Usage Pointer */ + 0xA1, 0x00, /* Collection Physical */ + 0x05, 0x09, /* Usage Page Button */ + 0x19, 0x01, /* Usage Minimum Button 1 */ + 0x29, 0x03, /* Usage Maximum Button 3 */ + 0x15, 0x00, /* Logical Minimum 0 */ + 0x25, 0x01, /* Logical Maximum 1 */ + 0x95, 0x03, /* Report Count 3 */ + 0x75, 0x01, /* Report Size 1 */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x95, 0x01, /* Report Count 1 */ + 0x75, 0x05, /* Report Size 5 */ + 0x81, 0x01, /* Input (Cnst, Var, Abs) */ + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x30, /* Usage X */ + 0x09, 0x31, /* Usage Y */ + 0x15, 0x00, /* Logical Minimum 0 */ + 0x26, 0xFF, 0x7F, /* Logical Maximum 0x7fff */ + 0x35, 0x00, /* Physical Minimum 0 */ + 0x46, 0xFE, 0x7F, /* Physical Maximum 0x7fff */ + 0x75, 0x10, /* Report Size 16 */ + 0x95, 0x02, /* Report Count 2 */ + 0x81, 0x02, /* Input (Data, Var, Abs) */ + 0x05, 0x01, /* Usage Page Generic Desktop */ + 0x09, 0x38, /* Usage Wheel */ + 0x15, 0x81, /* Logical Minimum -127 */ + 0x25, 0x7F, /* Logical Maximum 127 */ + 0x35, 0x00, /* Physical Minimum 0 (same as logical) */ + 0x45, 0x00, /* Physical Maximum 0 (same as logical) */ + 0x75, 0x08, /* Report Size 8 */ + 0x95, 0x01, /* Report Count 1 */ + 0x81, 0x02, /* Input (Data, Var, Rel) */ + 0xC0, /* End Collection */ + 0xC0, /* End Collection */ +}; + static void usb_mouse_event(void *opaque, int dx1, int dy1, int dz1, int buttons_state) { @@ -132,6 +233,17 @@ static void usb_mouse_event(void *opaque, s->buttons_state = buttons_state; } +static void usb_tablet_event(void *opaque, + int x, int y, int dz, int buttons_state) +{ + USBMouseState *s = opaque; + + s->x = x; + s->y = y; + s->dz += dz; + s->buttons_state = buttons_state; +} + static inline int int_clamp(int val, int vmin, int vmax) { if (val < vmin) @@ -146,6 +258,11 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) { int dx, dy, dz, b, l; + if (!s->mouse_grabbed) { + qemu_add_mouse_event_handler(usb_mouse_event, s, 0); + s->mouse_grabbed = 1; + } + dx = int_clamp(s->dx, -128, 127); dy = int_clamp(s->dy, -128, 127); dz = int_clamp(s->dz, -128, 127); @@ -173,6 +290,39 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) return l; } +static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) +{ + int dz, b, l; + + if (!s->mouse_grabbed) { + qemu_add_mouse_event_handler(usb_tablet_event, s, 1); + s->mouse_grabbed = 1; + } + + dz = int_clamp(s->dz, -128, 127); + s->dz -= dz; + + /* Appears we have to invert the wheel direction */ + dz = 0 - dz; + b = 0; + if (s->buttons_state & MOUSE_EVENT_LBUTTON) + b |= 0x01; + if (s->buttons_state & MOUSE_EVENT_RBUTTON) + b |= 0x02; + if (s->buttons_state & MOUSE_EVENT_MBUTTON) + b |= 0x04; + + buf[0] = b; + buf[1] = s->x & 0xff; + buf[2] = s->x >> 8; + buf[3] = s->y & 0xff; + buf[4] = s->y >> 8; + buf[5] = dz; + l = 6; + + return l; +} + static void usb_mouse_handle_reset(USBDevice *dev) { USBMouseState *s = (USBMouseState *)dev; @@ -180,6 +330,8 @@ static void usb_mouse_handle_reset(USBDevice *dev) s->dx = 0; s->dy = 0; s->dz = 0; + s->x = 0; + s->y = 0; s->buttons_state = 0; } @@ -187,7 +339,7 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { USBMouseState *s = (USBMouseState *)dev; - int ret; + int ret = 0; switch(request) { case DeviceRequest | USB_REQ_GET_STATUS: @@ -224,9 +376,15 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, ret = sizeof(qemu_mouse_dev_descriptor); break; case USB_DT_CONFIG: - memcpy(data, qemu_mouse_config_descriptor, - sizeof(qemu_mouse_config_descriptor)); - ret = sizeof(qemu_mouse_config_descriptor); + if (s->kind == USB_MOUSE) { + memcpy(data, qemu_mouse_config_descriptor, + sizeof(qemu_mouse_config_descriptor)); + ret = sizeof(qemu_mouse_config_descriptor); + } else if (s->kind == USB_TABLET) { + memcpy(data, qemu_tablet_config_descriptor, + sizeof(qemu_tablet_config_descriptor)); + ret = sizeof(qemu_tablet_config_descriptor); + } break; case USB_DT_STRING: switch(value & 0xff) { @@ -244,7 +402,10 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, break; case 2: /* product description */ - ret = set_usb_string(data, "QEMU USB Mouse"); + if (s->kind == USB_MOUSE) + ret = set_usb_string(data, "QEMU USB Mouse"); + else if (s->kind == USB_TABLET) + ret = set_usb_string(data, "QEMU USB Tablet"); break; case 3: /* vendor description */ @@ -282,16 +443,25 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: switch(value >> 8) { case 0x22: - memcpy(data, qemu_mouse_hid_report_descriptor, - sizeof(qemu_mouse_hid_report_descriptor)); - ret = sizeof(qemu_mouse_hid_report_descriptor); - break; + if (s->kind == USB_MOUSE) { + memcpy(data, qemu_mouse_hid_report_descriptor, + sizeof(qemu_mouse_hid_report_descriptor)); + ret = sizeof(qemu_mouse_hid_report_descriptor); + } else if (s->kind == USB_TABLET) { + memcpy(data, qemu_tablet_hid_report_descriptor, + sizeof(qemu_tablet_hid_report_descriptor)); + ret = sizeof(qemu_tablet_hid_report_descriptor); + } + break; default: goto fail; } break; case GET_REPORT: - ret = usb_mouse_poll(s, data, length); + if (s->kind == USB_MOUSE) + ret = usb_mouse_poll(s, data, length); + else if (s->kind == USB_TABLET) + ret = usb_tablet_poll(s, data, length); break; case SET_IDLE: ret = 0; @@ -308,12 +478,15 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, uint8_t devep, uint8_t *data, int len) { USBMouseState *s = (USBMouseState *)dev; - int ret; + int ret = 0; switch(pid) { case USB_TOKEN_IN: if (devep == 1) { - ret = usb_mouse_poll(s, data, len); + if (s->kind == USB_MOUSE) + ret = usb_mouse_poll(s, data, len); + else if (s->kind == USB_TABLET) + ret = usb_tablet_poll(s, data, len); } else { goto fail; } @@ -327,6 +500,24 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, return ret; } +USBDevice *usb_tablet_init(void) +{ + USBMouseState *s; + + s = qemu_mallocz(sizeof(USBMouseState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_mouse_handle_reset; + s->dev.handle_control = usb_mouse_handle_control; + s->dev.handle_data = usb_mouse_handle_data; + s->kind = USB_TABLET; + + return (USBDevice *)s; +} + USBDevice *usb_mouse_init(void) { USBMouseState *s; @@ -340,8 +531,7 @@ USBDevice *usb_mouse_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; + s->kind = USB_MOUSE; - qemu_add_mouse_event_handler(usb_mouse_event, s); - return (USBDevice *)s; } diff --git a/hw/usb.h b/hw/usb.h index b4dee2340..05502e04d 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -163,3 +163,4 @@ void usb_host_info(void); /* usb-hid.c */ USBDevice *usb_mouse_init(void); +USBDevice *usb_tablet_init(void); diff --git a/sdl.c b/sdl.c index b8c82fd66..72a70808d 100644 --- a/sdl.c +++ b/sdl.c @@ -39,6 +39,10 @@ static int gui_keysym; static int gui_fullscreen_initial_grab; static int gui_grab_code = KMOD_LALT | KMOD_LCTRL; static uint8_t modifiers_state[256]; +static int width, height; +static SDL_Cursor *sdl_cursor_normal; +static SDL_Cursor *sdl_cursor_hidden; +static int absolute_enabled = 0; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { @@ -56,6 +60,9 @@ static void sdl_resize(DisplayState *ds, int w, int h) if (gui_fullscreen) flags |= SDL_FULLSCREEN; + width = w; + height = h; + again: screen = SDL_SetVideoMode(w, h, 0, flags); if (!screen) { @@ -271,9 +278,21 @@ static void sdl_update_caption(void) SDL_WM_SetCaption(buf, "QEMU"); } +static void sdl_hide_cursor(void) +{ + SDL_SetCursor(sdl_cursor_hidden); +} + +static void sdl_show_cursor(void) +{ + if (!kbd_mouse_is_absolute()) { + SDL_SetCursor(sdl_cursor_normal); + } +} + static void sdl_grab_start(void) { - SDL_ShowCursor(0); + sdl_hide_cursor(); SDL_WM_GrabInput(SDL_GRAB_ON); /* dummy read to avoid moving the mouse */ SDL_GetRelativeMouseState(NULL, NULL); @@ -284,7 +303,7 @@ static void sdl_grab_start(void) static void sdl_grab_end(void) { SDL_WM_GrabInput(SDL_GRAB_OFF); - SDL_ShowCursor(1); + sdl_show_cursor(); gui_grab = 0; sdl_update_caption(); } @@ -300,6 +319,21 @@ static void sdl_send_mouse_event(int dz) buttons |= MOUSE_EVENT_RBUTTON; if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) buttons |= MOUSE_EVENT_MBUTTON; + + if (kbd_mouse_is_absolute()) { + if (!absolute_enabled) { + sdl_hide_cursor(); + if (gui_grab) { + sdl_grab_end(); + } + absolute_enabled = 1; + } + + SDL_GetMouseState(&dx, &dy); + dx = dx * 0x7FFF / width; + dy = dy * 0x7FFF / height; + } + kbd_mouse_event(dx, dy, dz, buttons); } @@ -423,7 +457,7 @@ static void sdl_refresh(DisplayState *ds) qemu_system_shutdown_request(); break; case SDL_MOUSEMOTION: - if (gui_grab) { + if (gui_grab || kbd_mouse_is_absolute()) { sdl_send_mouse_event(0); } break; @@ -431,7 +465,7 @@ static void sdl_refresh(DisplayState *ds) case SDL_MOUSEBUTTONUP: { SDL_MouseButtonEvent *bev = &ev->button; - if (!gui_grab) { + if (!gui_grab && !kbd_mouse_is_absolute()) { if (ev->type == SDL_MOUSEBUTTONDOWN && (bev->state & SDL_BUTTON_LMASK)) { /* start grabbing all events */ @@ -441,9 +475,9 @@ static void sdl_refresh(DisplayState *ds) int dz; dz = 0; #ifdef SDL_BUTTON_WHEELUP - if (bev->button == SDL_BUTTON_WHEELUP) { + if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) { dz = -1; - } else if (bev->button == SDL_BUTTON_WHEELDOWN) { + } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) { dz = 1; } #endif @@ -471,6 +505,7 @@ static void sdl_cleanup(void) void sdl_display_init(DisplayState *ds, int full_screen) { int flags; + uint8_t data = 0; #if defined(__APPLE__) /* always use generic keymaps */ @@ -504,6 +539,9 @@ void sdl_display_init(DisplayState *ds, int full_screen) SDL_EnableUNICODE(1); gui_grab = 0; + sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); + sdl_cursor_normal = SDL_GetCursor(); + atexit(sdl_cleanup); if (full_screen) { gui_fullscreen = 1; diff --git a/vl.c b/vl.c index 83c671612..8fba6e76e 100644 --- a/vl.c +++ b/vl.c @@ -474,6 +474,7 @@ static QEMUPutKBDEvent *qemu_put_kbd_event; static void *qemu_put_kbd_event_opaque; static QEMUPutMouseEvent *qemu_put_mouse_event; static void *qemu_put_mouse_event_opaque; +static int qemu_put_mouse_event_absolute; void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { @@ -481,10 +482,11 @@ void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) qemu_put_kbd_event = func; } -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque) +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute) { qemu_put_mouse_event_opaque = opaque; qemu_put_mouse_event = func; + qemu_put_mouse_event_absolute = absolute; } void kbd_put_keycode(int keycode) @@ -502,6 +504,11 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) } } +int kbd_mouse_is_absolute(void) +{ + return qemu_put_mouse_event_absolute; +} + /***********************************************************/ /* timers */ @@ -3242,6 +3249,10 @@ static int usb_device_add(const char *devname) dev = usb_mouse_init(); if (!dev) return -1; + } else if (!strcmp(devname, "tablet")) { + dev = usb_tablet_init(); + if (!dev) + return -1; } else { return -1; } diff --git a/vl.h b/vl.h index 9b09fa4f9..16d7e2993 100644 --- a/vl.h +++ b/vl.h @@ -158,10 +158,11 @@ typedef void QEMUPutKBDEvent(void *opaque, int keycode); typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque); +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute); void kbd_put_keycode(int keycode); void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); +int kbd_mouse_is_absolute(void); /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx constants) */ -- cgit v1.2.3 From 210fe0be2aaff0583163ef58fd9de055b577752e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Apr 2006 21:09:31 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1811 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changelog b/Changelog index 4ad7ceea2..d07a7ebb7 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,8 @@ +version 0.8.1: + + - USB tablet support (Brad Campbell, Anthony Liguori) + - win32 host serial support (Kazu) + version 0.8.0: - ARM system emulation: Arm Integrator/CP board with an arm1026ej-s -- cgit v1.2.3 From ffcdb539debe426e75290cb76f73e5c7b4fc645d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 12 Apr 2006 21:59:55 +0000 Subject: mouse API change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1812 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adb.c | 2 +- hw/slavio_serial.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index 2acfe65bf..8e08cb143 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -406,5 +406,5 @@ void adb_mouse_init(ADBBusState *bus) d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, adb_mouse_reset, s); adb_mouse_reset(d); - qemu_add_mouse_event_handler(adb_mouse_event, d); + qemu_add_mouse_event_handler(adb_mouse_event, d, 0); } diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 2b89c6d62..b13e7c46f 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -538,7 +538,7 @@ void slavio_serial_ms_kbd_init(int base, int irq) slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); - qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0]); + qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0); qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); qemu_register_reset(slavio_serial_reset, s); slavio_serial_reset(s); -- cgit v1.2.3 From 115defd163ff4977cfffbaa5a02e8d19d89e03d2 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 11:06:58 +0000 Subject: Set slirp client hostname. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1813 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 5 +++-- slirp/bootp.c | 8 ++++++++ slirp/libslirp.h | 1 + slirp/slirp.c | 2 ++ vl.c | 10 ++++++++-- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 7ab052062..e97e51a99 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -262,9 +262,10 @@ Qemu can emulate several different models of network card. Valid values for @code{smc91c111} and @code{lance}. Not all devices are supported on all targets. -@item -net user[,vlan=n] +@item -net user[,vlan=n][,hostname=name] Use the user mode network stack which requires no administrator -priviledge to run. +priviledge to run. @option{hotname=name} can be used to specify the client +hostname reported by the builtin DHCP server. @item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file] Connect the host TAP network interface @var{name} to VLAN @var{n} and diff --git a/slirp/bootp.c b/slirp/bootp.c index 9f0652fd6..62cbcfd8f 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -228,6 +228,14 @@ static void bootp_reply(struct bootp_t *bp) val = htonl(LEASE_TIME); memcpy(q, &val, 4); q += 4; + + if (*slirp_hostname) { + val = strlen(slirp_hostname); + *q++ = RFC1533_HOSTNAME; + *q++ = val; + memcpy(q, slirp_hostname, val); + q += val; + } } *q++ = RFC1533_END; diff --git a/slirp/libslirp.h b/slirp/libslirp.h index cff159e79..36c8ec21f 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -32,6 +32,7 @@ int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, int guest_port); extern const char *tftp_prefix; +extern const char slirp_hostname[33]; #ifdef __cplusplus } diff --git a/slirp/slirp.c b/slirp/slirp.c index 404cce8f7..28b8c887a 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -25,6 +25,8 @@ struct ex_list *exec_list; /* XXX: suppress those select globals */ fd_set *global_readfds, *global_writefds, *global_xfds; +const char slirp_hostname[33]; + #ifdef _WIN32 static int get_dns_addr(struct in_addr *pdns_addr) diff --git a/vl.c b/vl.c index 8fba6e76e..4f9b8c854 100644 --- a/vl.c +++ b/vl.c @@ -3151,6 +3151,11 @@ int net_client_init(const char *str) } else #ifdef CONFIG_SLIRP if (!strcmp(device, "user")) { + if (get_param_value(buf, sizeof(buf), "hostname", p)) { + if (strlen(buf) > 32) + buf[32] = 0; + strcpy(slirp_hostname, buf); + } ret = net_slirp_init(vlan); } else #endif @@ -4597,8 +4602,9 @@ void help(void) "-net nic[,vlan=n][,macaddr=addr][,model=type]\n" " create a new Network Interface Card and connect it to VLAN 'n'\n" #ifdef CONFIG_SLIRP - "-net user[,vlan=n]\n" - " connect the user mode network stack to VLAN 'n'\n" + "-net user[,vlan=n][,hostname=host]\n" + " connect the user mode network stack to VLAN 'n' and send\n" + " hostname 'host' to DHCP clients\n" #endif #ifdef _WIN32 "-net tap[,vlan=n],ifname=name\n" -- cgit v1.2.3 From ad06484063972abdf3f426412af9aa101bea26a8 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 12:41:07 +0000 Subject: Fix out of tree builds. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1814 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 21 +++++++++++---------- Makefile.target | 2 +- configure | 18 ++++++++++++------ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 59a549a5c..a8fd496eb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ --include config-host.mak +include config-host.mak -CFLAGS=-Wall -O2 -g -fno-strict-aliasing +CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I. ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic endif @@ -47,18 +47,19 @@ install: all mkdir -p "$(DESTDIR)$(bindir)" install -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" mkdir -p "$(DESTDIR)$(datadir)" - install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \ - pc-bios/vgabios-cirrus.bin \ - pc-bios/ppc_rom.bin pc-bios/video.x \ - pc-bios/proll.elf \ - pc-bios/linux_boot.bin "$(DESTDIR)$(datadir)" + for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ + video.x proll.elf linux_boot.bin; do \ + install -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ + done 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" mkdir -p "$(DESTDIR)$(datadir)/keymaps" - install -m 644 $(addprefix keymaps/,$(KEYMAPS)) "$(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 ; \ @@ -81,11 +82,11 @@ cscope: texi2html -monolithic -number $< qemu.1: qemu-doc.texi - ./texi2pod.pl $< qemu.pod + $(SRC_PATH)/texi2pod.pl $< qemu.pod pod2man --section=1 --center=" " --release=" " qemu.pod > $@ qemu-img.1: qemu-img.texi - ./texi2pod.pl $< qemu-img.pod + $(SRC_PATH)/texi2pod.pl $< qemu-img.pod pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@ FILE=qemu-$(shell cat VERSION) diff --git a/Makefile.target b/Makefile.target index 755fba1e7..abe19c0a6 100644 --- a/Makefile.target +++ b/Makefile.target @@ -12,7 +12,7 @@ TARGET_BASE_ARCH:=sparc endif TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio -DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH) +DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) ifdef CONFIG_USER_ONLY VPATH+=:$(SRC_PATH)/linux-user DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) diff --git a/configure b/configure index ff504b2b3..8331e4f25 100755 --- a/configure +++ b/configure @@ -139,14 +139,16 @@ if [ "$bsd" = "yes" ] ; then fi # find source path -# XXX: we assume an absolute path is given when launching configure, -# except in './configure' case. -source_path=${0%configure} -source_path=${source_path%/} -source_path_used="yes" -if test -z "$source_path" -o "$source_path" = "." ; then +source_path=`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 @@ -158,6 +160,7 @@ for opt do --interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2` ;; --source-path=*) source_path=`echo $opt | cut -d '=' -f 2` + source_path_used="yes" ;; --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` ;; @@ -615,6 +618,9 @@ head $source_path/VERSION >> $config_h echo "\"" >> $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 # XXX: suppress that -- cgit v1.2.3 From 0f8134bfd62a26d44b031723109f26660c995241 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 13:02:00 +0000 Subject: Downgrade DNS failure to a warning. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1815 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/slirp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slirp/slirp.c b/slirp/slirp.c index 28b8c887a..a7d3f6911 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -150,8 +150,8 @@ void slirp_init(void) inet_aton("127.0.0.1", &loopback_addr); if (get_dns_addr(&dns_addr) < 0) { - fprintf(stderr, "Could not get DNS address\n"); - exit(1); + dns_addr = loopback_addr; + fprintf (stderr, "Warning: No DNS servers found\n"); } inet_aton(CTL_SPECIAL, &special_addr); -- cgit v1.2.3 From b1a550a0da91d0b14e9202f1f5a84c4a920d5812 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 13:28:56 +0000 Subject: Remove non-portable code from configure. Allow newline at end of VERSION file. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1816 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- configure | 66 +++++++++++++++++++++++++++++++-------------------------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/VERSION b/VERSION index 8adc70fdd..a3df0a695 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.0 \ No newline at end of file +0.8.0 diff --git a/configure b/configure index 8331e4f25..f315c1938 100755 --- a/configure +++ b/configure @@ -83,6 +83,7 @@ alsa="no" fmod="no" fmod_lib="" fmod_inc="" +bsd="no" linux="no" kqemu="no" profiler="no" @@ -133,7 +134,7 @@ fi esac if [ "$bsd" = "yes" ] ; then - if [ ! "$darwin" = "yes" ] ; then + if [ "$darwin" != "yes" ] ; then make="gmake" fi fi @@ -152,31 +153,32 @@ else fi for opt do + optarg=`expr "$opt" : '[^=]*=\(.*\)'` case "$opt" in --help|-h) show_help=yes ;; - --prefix=*) prefix=`echo $opt | cut -d '=' -f 2` + --prefix=*) prefix="$optarg" ;; - --interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2` + --interp-prefix=*) interp_prefix="$optarg" ;; - --source-path=*) source_path=`echo $opt | cut -d '=' -f 2` + --source-path=*) source_path="$optarg" source_path_used="yes" ;; - --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` + --cross-prefix=*) cross_prefix="$optarg" ;; - --cc=*) cc=`echo $opt | cut -d '=' -f 2` + --cc=*) cc="$optarg" ;; - --host-cc=*) host_cc=`echo $opt | cut -d '=' -f 2` + --host-cc=*) host_cc="$optarg" ;; - --make=*) make=`echo $opt | cut -d '=' -f 2` + --make=*) make="$optarg" ;; - --extra-cflags=*) CFLAGS="${opt#--extra-cflags=}" + --extra-cflags=*) CFLAGS="$optarg" ;; - --extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}" + --extra-ldflags=*) LDFLAGS="$optarg" ;; - --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` + --cpu=*) cpu="$optarg" ;; - --target-list=*) target_list=${opt#--target-list=} + --target-list=*) target_list="$optarg" ;; --enable-gprof) gprof="yes" ;; @@ -192,9 +194,9 @@ for opt do ;; --enable-fmod) fmod="yes" ;; - --fmod-lib=*) fmod_lib=${opt#--fmod-lib=} + --fmod-lib=*) fmod_lib="$optarg" ;; - --fmod-inc=*) fmod_inc=${opt#--fmod-inc=} + --fmod-inc=*) fmod_inc="$optarg" ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ;; @@ -206,7 +208,7 @@ for opt do ;; --enable-profiler) profiler="yes" ;; - --kernel-path=*) kernel_path=${opt#--kernel-path=} + --kernel-path=*) kernel_path="$optarg" ;; --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" ;; @@ -297,7 +299,7 @@ if test -z "$target_list" ; then target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list" fi else - target_list=$(echo "$target_list" | sed -e 's/,/ /g') + target_list=`echo "$target_list" | sed -e 's/,/ /g'` fi if test -z "$target_list" ; then echo "No targets enabled" @@ -348,15 +350,15 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu have_gcc3_options="yes" fi -# Check for gcc4 +# Check for gcc4, error if pre-gcc4 if test "$check_gcc" = "yes" ; then cat > $TMPC <= 4 -#error gcc4 +#if __GNUC__ < 4 +#error gcc3 #endif int main(){return 0;} EOF - if ! $cc -o $TMPO $TMPC 2>/dev/null ; then + if $cc -o $TMPO $TMPC 2>/dev/null ; then echo "ERROR: \"$cc\" looks like gcc 4.x" 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" @@ -463,7 +465,6 @@ echo "Adlib support $adlib" echo "CoreAudio support $coreaudio" echo "ALSA support $alsa" echo "DSound support $dsound" -echo -n "FMOD support $fmod" if test "$fmod" = "yes"; then if test -z $fmod_lib || test -z $fmod_inc; then echo @@ -472,9 +473,11 @@ if test "$fmod" = "yes"; then echo exit 1 fi - echo -n " (lib='$fmod_lib' include='$fmod_inc')" + fmod_support=" (lib='$fmod_lib' include='$fmod_inc')" +else + fmod_support="" fi -echo "" +echo "FMOD support $fmod $fmod_support" echo "kqemu support $kqemu" if test $sdl_too_old = "yes"; then @@ -483,7 +486,6 @@ 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" @@ -610,12 +612,9 @@ if test "$fmod" = "yes" ; then echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak echo "#define CONFIG_FMOD 1" >> $config_h fi -echo -n "VERSION=" >>$config_mak -head $source_path/VERSION >>$config_mak -echo "" >>$config_mak -echo -n "#define QEMU_VERSION \"" >> $config_h -head $source_path/VERSION >> $config_h -echo "\"" >> $config_h +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 @@ -631,7 +630,6 @@ if [ "$bsd" = "yes" ] ; then fi for target in $target_list; do - target_dir="$target" config_mak=$target_dir/config.mak config_h=$target_dir/config.h @@ -761,11 +759,11 @@ if test "$target_user_only" = "no"; then else echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak fi - echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak if [ "${aa}" = "yes" ] ; then - echo -n " `aalib-config --cflags`" >> $config_mak ; + echo "SDL_CFLAGS=`$sdl_config --cflags` `aalib-config --cflags`" >> $config_mak + else + echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak fi - echo "" >> $config_mak fi fi -- cgit v1.2.3 From 8606e5b4502584b50bf4239ba79091efa8676ad0 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 13:34:44 +0000 Subject: Remove stray "}". git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1817 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 1 - 1 file changed, 1 deletion(-) diff --git a/cocoa.m b/cocoa.m index 2e2908f51..b508b5214 100644 --- a/cocoa.m +++ b/cocoa.m @@ -430,7 +430,6 @@ static void cocoa_refresh(DisplayState *ds) case 0x02 ... 0x0a: /* '1' to '9' keys */ console_select(keycode - 0x02); break; - } } } else { /* handle standard key events */ -- cgit v1.2.3 From d4b8f0396a04309454e0e48aacb7809cf08ab8e2 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 13:49:23 +0000 Subject: Add quotes missing from previous patch. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1818 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index f315c1938..5367e65f1 100755 --- a/configure +++ b/configure @@ -614,7 +614,7 @@ if test "$fmod" = "yes" ; then fi qemu_version=`head $source_path/VERSION` echo "VERSION=$qemu_version" >>$config_mak -echo "#define QEMU_VERSION $qemu_version" >> $config_h +echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h echo "SRC_PATH=$source_path" >> $config_mak if [ "$source_path_used" = "yes" ]; then -- cgit v1.2.3 From 248366894044f564ce56ac6340882bde17d24ec7 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 14:14:53 +0000 Subject: Implement acct and pretend to implement madvise. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1819 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2b132477f..516b32bf9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2145,7 +2145,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented; case TARGET_NR_acct: - goto unimplemented; + p = lock_user_string(arg1); + ret = get_errno(acct(path(p))); + unlock_user(p, arg1, 0); + break; case TARGET_NR_umount2: p = lock_user_string(arg1); ret = get_errno(umount2(p, arg2)); @@ -3547,7 +3550,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_madvise case TARGET_NR_madvise: - goto unimplemented; + /* A straight passthrough may not be safe because qemu sometimes + turns private flie-backed mappings into anonymous mappings. + This will break MADV_DONTNEED. + This is a hint, so ignoring and returning success is ok. */ + ret = get_errno(0); + break; #endif #if TARGET_LONG_BITS == 32 case TARGET_NR_fcntl64: -- cgit v1.2.3 From 99773bd4b4e848955851bec18ae4b7daca8ed306 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 15:14:59 +0000 Subject: Fix DEBUG_TB_CHECK build failure (balrog). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1820 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/exec.c b/exec.c index 9843ae5e7..56a8c4c53 100644 --- a/exec.c +++ b/exec.c @@ -46,6 +46,11 @@ //#define DEBUG_TB_CHECK //#define DEBUG_TLB_CHECK +#if !defined(CONFIG_USER_ONLY) +/* TB consistency checks only implemented for usermode emulation. */ +#undef DEBUG_TB_CHECK +#endif + /* threshold to flush the translated code buffer */ #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) @@ -330,12 +335,12 @@ static void tb_invalidate_check(unsigned long address) TranslationBlock *tb; int i; address &= TARGET_PAGE_MASK; - for(i = 0;i < CODE_GEN_HASH_SIZE; i++) { - for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) { + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) { + for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { if (!(address + TARGET_PAGE_SIZE <= tb->pc || address >= tb->pc + tb->size)) { printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n", - address, tb->pc, tb->size); + address, (long)tb->pc, tb->size); } } } @@ -347,13 +352,13 @@ static void tb_page_check(void) TranslationBlock *tb; int i, flags1, flags2; - for(i = 0;i < CODE_GEN_HASH_SIZE; i++) { - for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) { + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) { + for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { flags1 = page_get_flags(tb->pc); flags2 = page_get_flags(tb->pc + tb->size - 1); if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n", - tb->pc, tb->size, flags1, flags2); + (long)tb->pc, tb->size, flags1, flags2); } } } -- cgit v1.2.3 From 9c038506841a3d1200a2b71701e1ea155c6d4b93 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 15:19:15 +0000 Subject: Typo in error message. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1821 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 5367e65f1..a1de008c5 100755 --- a/configure +++ b/configure @@ -653,7 +653,7 @@ fi if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ -a "$sdl" = "no" -a "$cocoa" = "no" ; then echo "ERROR: QEMU requires SDL or Cocoa for graphical output" - echo "To build QEMU with graphical output configure with --disable-gfx-check" + echo "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 -- cgit v1.2.3 From a03a60532aa137e27bdd8ff8738d56b8ba2126cd Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 16 Apr 2006 18:46:12 +0000 Subject: Fix typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1822 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index e97e51a99..9862637e0 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -264,7 +264,7 @@ targets. @item -net user[,vlan=n][,hostname=name] Use the user mode network stack which requires no administrator -priviledge to run. @option{hotname=name} can be used to specify the client +priviledge to run. @option{hostname=name} can be used to specify the client hostname reported by the builtin DHCP server. @item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file] -- cgit v1.2.3 From 6a8826434fb98d7bcf870d9f3e2e90a672bc9f03 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 17 Apr 2006 13:57:12 +0000 Subject: Allow user to specify "install" utility. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1823 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 10 +++++----- Makefile.target | 2 +- configure | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index a8fd496eb..0c2ab09dd 100644 --- a/Makefile +++ b/Makefile @@ -45,20 +45,20 @@ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr install: all mkdir -p "$(DESTDIR)$(bindir)" - install -m 755 -s $(TOOLS) "$(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 proll.elf linux_boot.bin; do \ - install -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ + $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ done mkdir -p "$(DESTDIR)$(docdir)" - install -m 644 qemu-doc.html qemu-tech.html "$(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" + $(INSTALL) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1" mkdir -p "$(DESTDIR)$(datadir)/keymaps" for x in $(KEYMAPS); do \ - install -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \ + $(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \ done endif for d in $(TARGET_DIRS); do \ diff --git a/Makefile.target b/Makefile.target index abe19c0a6..af5e432dc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -470,7 +470,7 @@ clean: install: all ifneq ($(PROGS),) - install -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)" + $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)" endif ifneq ($(wildcard .depend),) diff --git a/configure b/configure index a1de008c5..6e5073b6f 100755 --- a/configure +++ b/configure @@ -25,6 +25,7 @@ cc="gcc" host_cc="gcc" ar="ar" make="make" +install="install" strip="strip" cpu=`uname -m` target_list="" @@ -172,6 +173,8 @@ for opt do ;; --make=*) make="$optarg" ;; + --install=*) install="$optarg" + ;; --extra-cflags=*) CFLAGS="$optarg" ;; --extra-ldflags=*) LDFLAGS="$optarg" @@ -256,6 +259,7 @@ 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" @@ -447,6 +451,7 @@ 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" @@ -502,6 +507,7 @@ 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 -- cgit v1.2.3 From d7ce493a38680aeb9283129cf4f4ea576da62997 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 18 Apr 2006 16:55:22 +0000 Subject: Initialize PCI BAR config data. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1824 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/pci.c b/hw/pci.c index fd4ccd947..30342d44e 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -124,6 +124,7 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, PCIMapIORegionFunc *map_func) { PCIIORegion *r; + uint32_t addr; if ((unsigned int)region_num >= PCI_NUM_REGIONS) return; @@ -132,6 +133,12 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, r->size = size; r->type = type; r->map_func = map_func; + if (region_num == PCI_ROM_SLOT) { + addr = 0x30; + } else { + addr = 0x10 + region_num * 4; + } + *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); } static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val) -- cgit v1.2.3 From 132ea32fae4857b518475f8cded52f5ace56a399 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 18 Apr 2006 19:02:59 +0000 Subject: Fix display resize bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1825 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl110.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pl110.c b/hw/pl110.c index 09352e742..ecebe35eb 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -261,7 +261,7 @@ static void pl110_resize(pl110_state *s, int width, int height) { if (width != s->cols || height != s->rows) { if (pl110_enabled(s)) { - dpy_resize(s->ds, s->cols, s->rows); + dpy_resize(s->ds, width, height); } } s->cols = width; -- cgit v1.2.3 From a7350fa109d9b6d33f6a0501ed9fc45d0fba27d0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 14:35:23 +0000 Subject: check if specified compiler exists git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1826 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure b/configure index 6e5073b6f..356461775 100755 --- a/configure +++ b/configure @@ -283,6 +283,11 @@ cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" +if [ -z `which $cc` ] ; then + echo "Compiler $cc could not be found" + exit +fi + if test "$mingw32" = "yes" ; then linux="no" EXESUF=".exe" -- cgit v1.2.3 From da2414e9335d2116687fdc914daf12f443d9b87c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 14:36:41 +0000 Subject: moved misplaced declaration git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1827 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vvfat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block-vvfat.c b/block-vvfat.c index 36f97134d..84d2a08ad 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -1578,10 +1578,12 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, mapping = find_mapping_for_cluster(s, cluster_num); if (mapping) { + const char* basename; + assert(mapping->mode & MODE_DELETED); mapping->mode &= ~MODE_DELETED; - const char* basename = get_basename(mapping->path); + basename = get_basename(mapping->path); assert(mapping->mode & MODE_NORMAL); -- cgit v1.2.3 From 76e050c2e62995f1d6905e28674dea3a7fcff1a5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 15:18:58 +0000 Subject: Fix overflow conditions for MIPS add / subtract (Stefan Weil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1828 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 71abd95be..e0d3463be 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -206,7 +206,8 @@ void op_addo (void) tmp = T0; T0 += T1; - if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) { + if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) { + /* operands of same sign, result different sign */ CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } RETURN(); @@ -224,7 +225,8 @@ void op_subo (void) tmp = T0; T0 = (int32_t)T0 - (int32_t)T1; - if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) { + if (((tmp ^ T1) & (tmp ^ T0)) >> 31) { + /* operands of different sign, first operand and result different sign */ CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } RETURN(); -- cgit v1.2.3 From cd7dd10f09a66b0e356f7164850f9270268c0a94 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 15:21:24 +0000 Subject: MIPS CP0 not usable in kernel mode (Stefan Weil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1829 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 418a7afa0..fd1faf149 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1180,7 +1180,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) const unsigned char *opn = "unk"; if (!(ctx->CP0_Status & (1 << CP0St_CU0)) && - !(ctx->hflags & MIPS_HFLAG_UM) && + (ctx->hflags & MIPS_HFLAG_UM) && !(ctx->hflags & MIPS_HFLAG_ERL) && !(ctx->hflags & MIPS_HFLAG_EXL)) { if (loglevel & CPU_LOG_TB_IN_ASM) { -- cgit v1.2.3 From ce2f4b3cb9c1c542a6de6f0cdcd4771fe03a8bb6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 15:23:48 +0000 Subject: MIPS single stepping fix (Dirk Behme) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1830 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op.c b/target-mips/op.c index e0d3463be..3f9b36462 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -604,7 +604,7 @@ void op_trap (void) void op_debug (void) { - CALL_FROM_TB1(do_raise_exception_direct, EXCP_DEBUG); + CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG); } void op_set_lladdr (void) -- cgit v1.2.3 From 5fe141fd30d35516eac3674f7b62be51ba34543f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 17:12:42 +0000 Subject: generic ELF loader git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1831 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 7 +- elf_ops.h | 197 +++++++++++++++++++++++++++++++++++++++++++++++ loader.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 29 ------- vl.h | 8 +- 5 files changed, 439 insertions(+), 36 deletions(-) create mode 100644 elf_ops.h create mode 100644 loader.c diff --git a/Makefile.target b/Makefile.target index af5e432dc..9b5ebcde0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -270,7 +270,7 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o +VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.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 ifdef CONFIG_WIN32 VL_OBJS+=tap-win32.o @@ -332,9 +332,8 @@ ifeq ($(TARGET_ARCH), sparc64) VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o VL_OBJS+= cirrus_vga.o parallel.o -VL_OBJS+= magic-load.o else -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o magic-load.o slavio_intctl.o +VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o slavio_intctl.o VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o endif endif @@ -459,6 +458,8 @@ 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 + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< diff --git a/elf_ops.h b/elf_ops.h new file mode 100644 index 000000000..a7d027e1a --- /dev/null +++ b/elf_ops.h @@ -0,0 +1,197 @@ +static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr) +{ + bswap16s(&ehdr->e_type); /* Object file type */ + bswap16s(&ehdr->e_machine); /* Architecture */ + bswap32s(&ehdr->e_version); /* Object file version */ + bswapSZs(&ehdr->e_entry); /* Entry point virtual address */ + bswapSZs(&ehdr->e_phoff); /* Program header table file offset */ + bswapSZs(&ehdr->e_shoff); /* Section header table file offset */ + bswap32s(&ehdr->e_flags); /* Processor-specific flags */ + bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ + bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ +} + +static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr) +{ + bswap32s(&phdr->p_type); /* Segment type */ + bswapSZs(&phdr->p_offset); /* Segment file offset */ + bswapSZs(&phdr->p_vaddr); /* Segment virtual address */ + bswapSZs(&phdr->p_paddr); /* Segment physical address */ + bswapSZs(&phdr->p_filesz); /* Segment size in file */ + bswapSZs(&phdr->p_memsz); /* Segment size in memory */ + bswap32s(&phdr->p_flags); /* Segment flags */ + bswapSZs(&phdr->p_align); /* Segment alignment */ +} + +static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr) +{ + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswapSZs(&shdr->sh_flags); + bswapSZs(&shdr->sh_addr); + bswapSZs(&shdr->sh_offset); + bswapSZs(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswapSZs(&shdr->sh_addralign); + bswapSZs(&shdr->sh_entsize); +} + +static void glue(bswap_sym, SZ)(struct elf_sym *sym) +{ + bswap32s(&sym->st_name); + bswapSZs(&sym->st_value); + bswapSZs(&sym->st_size); + bswap16s(&sym->st_shndx); +} + +static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, + int n, int type) +{ + int i; + for(i=0;ie_shoff, + sizeof(struct elf_shdr) * ehdr->e_shnum); + if (!shdr_table) + return -1; + + if (must_swab) { + for (i = 0; i < ehdr->e_shnum; i++) { + glue(bswap_shdr, SZ)(shdr_table + i); + } + } + + symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); + if (!symtab) + goto fail; + syms = load_at(fd, symtab->sh_offset, symtab->sh_size); + if (!syms) + goto fail; + + nsyms = symtab->sh_size / sizeof(struct elf_sym); +#if (SZ == 64) + syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym)); +#endif + for (i = 0; i < nsyms; i++) { + if (must_swab) + glue(bswap_sym, SZ)(&syms[i]); +#if (SZ == 64) + syms32[i].st_name = syms[i].st_name; + syms32[i].st_info = syms[i].st_info; + syms32[i].st_other = syms[i].st_other; + syms32[i].st_shndx = syms[i].st_shndx; + syms32[i].st_value = syms[i].st_value & 0xffffffff; + syms32[i].st_size = syms[i].st_size & 0xffffffff; +#endif + } + /* String table */ + if (symtab->sh_link >= ehdr->e_shnum) + goto fail; + strtab = &shdr_table[symtab->sh_link]; + + str = load_at(fd, strtab->sh_offset, strtab->sh_size); + if (!str) + goto fail; + + /* Commit */ + s = qemu_mallocz(sizeof(*s)); +#if (SZ == 64) + s->disas_symtab = syms32; + qemu_free(syms); +#else + s->disas_symtab = syms; +#endif + s->disas_num_syms = nsyms; + s->disas_strtab = str; + s->next = syminfos; + syminfos = s; + qemu_free(shdr_table); + return 0; + fail: +#if (SZ == 64) + qemu_free(syms32); +#endif + qemu_free(syms); + qemu_free(str); + qemu_free(shdr_table); + return -1; +} + +int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, int must_swab) +{ + struct elfhdr ehdr; + struct elf_phdr *phdr = NULL, *ph; + int size, i, total_size; + elf_word mem_size, addr; + uint8_t *data; + + if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) + goto fail; + if (must_swab) { + glue(bswap_ehdr, SZ)(&ehdr); + } + + glue(load_symbols, SZ)(&ehdr, fd, must_swab); + + size = ehdr.e_phnum * sizeof(phdr[0]); + lseek(fd, ehdr.e_phoff, SEEK_SET); + phdr = qemu_mallocz(size); + if (!phdr) + goto fail; + if (read(fd, phdr, size) != size) + goto fail; + if (must_swab) { + for(i = 0; i < ehdr.e_phnum; i++) { + ph = &phdr[i]; + glue(bswap_phdr, SZ)(ph); + } + } + + total_size = 0; + for(i = 0; i < ehdr.e_phnum; i++) { + ph = &phdr[i]; + if (ph->p_type == PT_LOAD) { + mem_size = ph->p_memsz; + /* XXX: avoid allocating */ + data = qemu_mallocz(mem_size); + if (ph->p_filesz > 0) { + lseek(fd, ph->p_offset, SEEK_SET); + if (read(fd, data, ph->p_filesz) != ph->p_filesz) + goto fail; + } + addr = ph->p_vaddr + virt_to_phys_addend; + + cpu_physical_memory_write_rom(addr, data, mem_size); + + total_size += mem_size; + + qemu_free(data); + } + } + return total_size; + fail: + qemu_free(phdr); + return -1; +} + diff --git a/loader.c b/loader.c new file mode 100644 index 000000000..c4bde55c1 --- /dev/null +++ b/loader.c @@ -0,0 +1,234 @@ +/* + * QEMU Executable loader + * + * 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 "disas.h" + +/* return the size or -1 if error */ +int get_image_size(const char *filename) +{ + int fd, size; + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return -1; + size = lseek(fd, 0, SEEK_END); + close(fd); + return size; +} + +/* return the size or -1 if error */ +int load_image(const char *filename, uint8_t *addr) +{ + int fd, size; + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return -1; + size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + if (read(fd, addr, size) != size) { + close(fd); + return -1; + } + close(fd); + return size; +} + +/* A.OUT loader */ + +struct exec +{ + uint32_t a_info; /* Use macros N_MAGIC, etc for access */ + uint32_t a_text; /* length of text, in bytes */ + uint32_t a_data; /* length of data, in bytes */ + uint32_t a_bss; /* length of uninitialized data area, in bytes */ + uint32_t a_syms; /* length of symbol table data in file, in bytes */ + uint32_t a_entry; /* start address */ + uint32_t a_trsize; /* length of relocation info for text, in bytes */ + uint32_t a_drsize; /* length of relocation info for data, in bytes */ +}; + +#ifdef BSWAP_NEEDED +static void bswap_ahdr(struct exec *e) +{ + bswap32s(&e->a_info); + bswap32s(&e->a_text); + bswap32s(&e->a_data); + bswap32s(&e->a_bss); + bswap32s(&e->a_syms); + bswap32s(&e->a_entry); + bswap32s(&e->a_trsize); + bswap32s(&e->a_drsize); +} +#else +#define bswap_ahdr(x) do { } while (0) +#endif + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 +#define _N_HDROFF(x) (1024 - sizeof (struct exec)) +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ + (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) +#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) +#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) + +#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) + +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) + + +int load_aout(const char *filename, uint8_t *addr) +{ + int fd, size, ret; + struct exec e; + uint32_t magic; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return -1; + + size = read(fd, &e, sizeof(e)); + if (size < 0) + goto fail; + + bswap_ahdr(&e); + + magic = N_MAGIC(e); + switch (magic) { + case ZMAGIC: + case QMAGIC: + case OMAGIC: + lseek(fd, N_TXTOFF(e), SEEK_SET); + size = read(fd, addr, e.a_text + e.a_data); + if (size < 0) + goto fail; + break; + case NMAGIC: + lseek(fd, N_TXTOFF(e), SEEK_SET); + size = read(fd, addr, e.a_text); + if (size < 0) + goto fail; + ret = read(fd, addr + N_DATADDR(e), e.a_data); + if (ret < 0) + goto fail; + size += ret; + break; + default: + goto fail; + } + close(fd); + return size; + fail: + close(fd); + return -1; +} + +/* ELF loader */ + +static void *load_at(int fd, int offset, int size) +{ + void *ptr; + if (lseek(fd, offset, SEEK_SET) < 0) + return NULL; + ptr = qemu_malloc(size); + if (!ptr) + return NULL; + if (read(fd, ptr, size) != size) { + qemu_free(ptr); + return NULL; + } + return ptr; +} + + +#define ELF_CLASS ELFCLASS32 +#include "elf.h" + +#define SZ 32 +#define elf_word uint32_t +#define bswapSZs bswap32s +#include "elf_ops.h" + +#undef elfhdr +#undef elf_phdr +#undef elf_shdr +#undef elf_sym +#undef elf_note +#undef elf_word +#undef bswapSZs +#undef SZ +#define elfhdr elf64_hdr +#define elf_phdr elf64_phdr +#define elf_note elf64_note +#define elf_shdr elf64_shdr +#define elf_sym elf64_sym +#define elf_word uint64_t +#define bswapSZs bswap64s +#define SZ 64 +#include "elf_ops.h" + +/* return < 0 if error, otherwise the number of bytes loaded in memory */ +int load_elf(const char *filename, int64_t virt_to_phys_addend) +{ + int fd, data_order, must_swab, ret; + uint8_t e_ident[EI_NIDENT]; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + return -1; + } + if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) + goto fail; + if (e_ident[0] != ELFMAG0 || + e_ident[1] != ELFMAG1 || + e_ident[2] != ELFMAG2 || + e_ident[3] != ELFMAG3) + goto fail; +#ifdef WORDS_BIGENDIAN + data_order = ELFDATA2MSB; +#else + data_order = ELFDATA2LSB; +#endif + must_swab = data_order != e_ident[EI_DATA]; + + lseek(fd, 0, SEEK_SET); + if (e_ident[EI_CLASS] == ELFCLASS64) { + ret = load_elf64(fd, virt_to_phys_addend, must_swab); + } else { + ret = load_elf32(fd, virt_to_phys_addend, must_swab); + } + + close(fd); + return ret; + + fail: + close(fd); + return -1; +} diff --git a/vl.c b/vl.c index 4f9b8c854..36b7e24fe 100644 --- a/vl.c +++ b/vl.c @@ -332,35 +332,6 @@ int strstart(const char *str, const char *val, const char **ptr) return 1; } -/* return the size or -1 if error */ -int get_image_size(const char *filename) -{ - int fd, size; - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return -1; - size = lseek(fd, 0, SEEK_END); - close(fd); - return size; -} - -/* return the size or -1 if error */ -int load_image(const char *filename, uint8_t *addr) -{ - int fd, size; - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return -1; - size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - if (read(fd, addr, size) != size) { - close(fd); - return -1; - } - close(fd); - return size; -} - void cpu_outb(CPUState *env, int addr, int val) { #ifdef DEBUG_IOPORT diff --git a/vl.h b/vl.h index 16d7e2993..72381ec8f 100644 --- a/vl.h +++ b/vl.h @@ -87,8 +87,6 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); void hw_error(const char *fmt, ...); -int get_image_size(const char *filename); -int load_image(const char *filename, uint8_t *addr); extern const char *bios_dir; void pstrcpy(char *buf, int buf_size, const char *str); @@ -871,8 +869,10 @@ void slavio_irq_info(void *opaque); void slavio_pic_set_irq(void *opaque, int irq, int level); void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); -/* magic-load.c */ -int load_elf(const char *filename, uint8_t *addr); +/* loader.c */ +int get_image_size(const char *filename); +int load_image(const char *filename, uint8_t *addr); +int load_elf(const char *filename, int64_t virt_to_phys_addend); int load_aout(const char *filename, uint8_t *addr); /* slavio_timer.c */ -- cgit v1.2.3 From b37837317fb3177755c592591d7f53826c6afae5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 17:14:05 +0000 Subject: use generic ELF loader git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1832 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/elf_ops.h | 218 -------------------------------------------------------- hw/magic-load.c | 201 --------------------------------------------------- hw/sun4m.c | 10 +-- hw/sun4u.c | 11 +-- 4 files changed, 13 insertions(+), 427 deletions(-) delete mode 100644 hw/elf_ops.h delete mode 100644 hw/magic-load.c diff --git a/hw/elf_ops.h b/hw/elf_ops.h deleted file mode 100644 index 1f3232d47..000000000 --- a/hw/elf_ops.h +++ /dev/null @@ -1,218 +0,0 @@ -#ifdef BSWAP_NEEDED -static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr) -{ - bswap16s(&ehdr->e_type); /* Object file type */ - bswap16s(&ehdr->e_machine); /* Architecture */ - bswap32s(&ehdr->e_version); /* Object file version */ - bswapSZs(&ehdr->e_entry); /* Entry point virtual address */ - bswapSZs(&ehdr->e_phoff); /* Program header table file offset */ - bswapSZs(&ehdr->e_shoff); /* Section header table file offset */ - bswap32s(&ehdr->e_flags); /* Processor-specific flags */ - bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ - bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ - bswap16s(&ehdr->e_phnum); /* Program header table entry count */ - bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ - bswap16s(&ehdr->e_shnum); /* Section header table entry count */ - bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ -} - -static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr) -{ - bswap32s(&phdr->p_type); /* Segment type */ - bswapSZs(&phdr->p_offset); /* Segment file offset */ - bswapSZs(&phdr->p_vaddr); /* Segment virtual address */ - bswapSZs(&phdr->p_paddr); /* Segment physical address */ - bswapSZs(&phdr->p_filesz); /* Segment size in file */ - bswapSZs(&phdr->p_memsz); /* Segment size in memory */ - bswap32s(&phdr->p_flags); /* Segment flags */ - bswapSZs(&phdr->p_align); /* Segment alignment */ -} - -static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr) -{ - bswap32s(&shdr->sh_name); - bswap32s(&shdr->sh_type); - bswapSZs(&shdr->sh_flags); - bswapSZs(&shdr->sh_addr); - bswapSZs(&shdr->sh_offset); - bswapSZs(&shdr->sh_size); - bswap32s(&shdr->sh_link); - bswap32s(&shdr->sh_info); - bswapSZs(&shdr->sh_addralign); - bswapSZs(&shdr->sh_entsize); -} - -static void glue(bswap_sym, SZ)(struct elf_sym *sym) -{ - bswap32s(&sym->st_name); - bswapSZs(&sym->st_value); - bswapSZs(&sym->st_size); - bswap16s(&sym->st_shndx); -} -#endif - -static int glue(find_phdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, elf_word type) -{ - int i, retval; - - retval = lseek(fd, ehdr->e_phoff, SEEK_SET); - if (retval < 0) - return -1; - - for (i = 0; i < ehdr->e_phnum; i++) { - retval = read(fd, phdr, sizeof(*phdr)); - if (retval < 0) - return -1; - glue(bswap_phdr, SZ)(phdr); - if (phdr->p_type == type) - return 0; - } - return -1; -} - -static void * glue(find_shdr, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type) -{ - int i, retval; - - retval = lseek(fd, ehdr->e_shoff, SEEK_SET); - if (retval < 0) - return NULL; - - for (i = 0; i < ehdr->e_shnum; i++) { - retval = read(fd, shdr, sizeof(*shdr)); - if (retval < 0) - return NULL; - glue(bswap_shdr, SZ)(shdr); - if (shdr->sh_type == type) - return qemu_malloc(shdr->sh_size); - } - return NULL; -} - -static void * glue(find_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) -{ - int retval; - - retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); - if (retval < 0) - return NULL; - - retval = read(fd, shdr, sizeof(*shdr)); - if (retval < 0) - return NULL; - glue(bswap_shdr, SZ)(shdr); - if (shdr->sh_type == SHT_STRTAB) - return qemu_malloc(shdr->sh_size);; - return NULL; -} - -static int glue(read_program, SZ)(int fd, struct elf_phdr *phdr, void *dst, elf_word entry) -{ - int retval; - retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); - if (retval < 0) - return -1; - return read(fd, dst, phdr->p_filesz); -} - -static int glue(read_section, SZ)(int fd, struct elf_shdr *s, void *dst) -{ - int retval; - - retval = lseek(fd, s->sh_offset, SEEK_SET); - if (retval < 0) - return -1; - retval = read(fd, dst, s->sh_size); - if (retval < 0) - return -1; - return 0; -} - -static void * glue(process_section, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, elf_word type) -{ - void *dst; - - dst = glue(find_shdr, SZ)(ehdr, fd, shdr, type); - if (!dst) - goto error; - - if (glue(read_section, SZ)(fd, shdr, dst)) - goto error; - return dst; - error: - qemu_free(dst); - return NULL; -} - -static void * glue(process_strtab, SZ)(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) -{ - void *dst; - - dst = glue(find_strtab, SZ)(ehdr, fd, shdr, symtab); - if (!dst) - goto error; - - if (glue(read_section, SZ)(fd, shdr, dst)) - goto error; - return dst; - error: - qemu_free(dst); - return NULL; -} - -static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd) -{ - struct elf_shdr symtab, strtab; - struct elf_sym *syms; -#if (SZ == 64) - struct elf32_sym *syms32; -#endif - struct syminfo *s; - int nsyms, i; - char *str; - - /* Symbol table */ - syms = glue(process_section, SZ)(ehdr, fd, &symtab, SHT_SYMTAB); - if (!syms) - return; - - nsyms = symtab.sh_size / sizeof(struct elf_sym); -#if (SZ == 64) - syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym)); -#endif - for (i = 0; i < nsyms; i++) { - glue(bswap_sym, SZ)(&syms[i]); -#if (SZ == 64) - syms32[i].st_name = syms[i].st_name; - syms32[i].st_info = syms[i].st_info; - syms32[i].st_other = syms[i].st_other; - syms32[i].st_shndx = syms[i].st_shndx; - syms32[i].st_value = syms[i].st_value & 0xffffffff; - syms32[i].st_size = syms[i].st_size & 0xffffffff; -#endif - } - /* String table */ - str = glue(process_strtab, SZ)(ehdr, fd, &strtab, &symtab); - if (!str) - goto error_freesyms; - - /* Commit */ - s = qemu_mallocz(sizeof(*s)); -#if (SZ == 64) - s->disas_symtab = syms32; - qemu_free(syms); -#else - s->disas_symtab = syms; -#endif - s->disas_num_syms = nsyms; - s->disas_strtab = str; - s->next = syminfos; - syminfos = s; - return; - error_freesyms: -#if (SZ == 64) - qemu_free(syms32); -#endif - qemu_free(syms); - return; -} diff --git a/hw/magic-load.c b/hw/magic-load.c deleted file mode 100644 index d5c098fb4..000000000 --- a/hw/magic-load.c +++ /dev/null @@ -1,201 +0,0 @@ -#include "vl.h" -#include "disas.h" -#include "exec-all.h" - -struct exec -{ - uint32_t a_info; /* Use macros N_MAGIC, etc for access */ - uint32_t a_text; /* length of text, in bytes */ - uint32_t a_data; /* length of data, in bytes */ - uint32_t a_bss; /* length of uninitialized data area, in bytes */ - uint32_t a_syms; /* length of symbol table data in file, in bytes */ - uint32_t a_entry; /* start address */ - uint32_t a_trsize; /* length of relocation info for text, in bytes */ - uint32_t a_drsize; /* length of relocation info for data, in bytes */ -}; - -#ifdef BSWAP_NEEDED -static void bswap_ahdr(struct exec *e) -{ - bswap32s(&e->a_info); - bswap32s(&e->a_text); - bswap32s(&e->a_data); - bswap32s(&e->a_bss); - bswap32s(&e->a_syms); - bswap32s(&e->a_entry); - bswap32s(&e->a_trsize); - bswap32s(&e->a_drsize); -} -#else -#define bswap_ahdr(x) do { } while (0) -#endif - -#define N_MAGIC(exec) ((exec).a_info & 0xffff) -#define OMAGIC 0407 -#define NMAGIC 0410 -#define ZMAGIC 0413 -#define QMAGIC 0314 -#define _N_HDROFF(x) (1024 - sizeof (struct exec)) -#define N_TXTOFF(x) \ - (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ - (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) -#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) -#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) -#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) - -#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) - -#define N_DATADDR(x) \ - (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ - : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) - - -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB -#define ELF_ARCH EM_SPARC - -#include "elf.h" - -#ifndef BSWAP_NEEDED -#define bswap_ehdr32(e) do { } while (0) -#define bswap_phdr32(e) do { } while (0) -#define bswap_shdr32(e) do { } while (0) -#define bswap_sym32(e) do { } while (0) -#ifdef TARGET_SPARC64 -#define bswap_ehdr64(e) do { } while (0) -#define bswap_phdr64(e) do { } while (0) -#define bswap_shdr64(e) do { } while (0) -#define bswap_sym64(e) do { } while (0) -#endif -#endif - -#define SZ 32 -#define elf_word uint32_t -#define bswapSZs bswap32s -#include "elf_ops.h" - -#ifdef TARGET_SPARC64 -#undef elfhdr -#undef elf_phdr -#undef elf_shdr -#undef elf_sym -#undef elf_note -#undef elf_word -#undef bswapSZs -#undef SZ -#define elfhdr elf64_hdr -#define elf_phdr elf64_phdr -#define elf_note elf64_note -#define elf_shdr elf64_shdr -#define elf_sym elf64_sym -#define elf_word uint64_t -#define bswapSZs bswap64s -#define SZ 64 -#include "elf_ops.h" -#endif - -int load_elf(const char *filename, uint8_t *addr) -{ - struct elf32_hdr ehdr; - int retval, fd; - Elf32_Half machine; - - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - goto error; - - retval = read(fd, &ehdr, sizeof(ehdr)); - if (retval < 0) - goto error; - - if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' - || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F') - goto error; - machine = tswap16(ehdr.e_machine); - if (machine == EM_SPARC || machine == EM_SPARC32PLUS) { - struct elf32_phdr phdr; - - bswap_ehdr32(&ehdr); - - if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD)) - goto error; - retval = read_program32(fd, &phdr, addr, ehdr.e_entry); - if (retval < 0) - goto error; - load_symbols32(&ehdr, fd); - } -#ifdef TARGET_SPARC64 - else if (machine == EM_SPARCV9) { - struct elf64_hdr ehdr64; - struct elf64_phdr phdr; - - lseek(fd, 0, SEEK_SET); - - retval = read(fd, &ehdr64, sizeof(ehdr64)); - if (retval < 0) - goto error; - - bswap_ehdr64(&ehdr64); - - if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD)) - goto error; - retval = read_program64(fd, &phdr, phys_ram_base + ehdr64.e_entry, ehdr64.e_entry); - if (retval < 0) - goto error; - load_symbols64(&ehdr64, fd); - } -#endif - - close(fd); - return retval; - error: - close(fd); - return -1; -} - -int load_aout(const char *filename, uint8_t *addr) -{ - int fd, size, ret; - struct exec e; - uint32_t magic; - - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return -1; - - size = read(fd, &e, sizeof(e)); - if (size < 0) - goto fail; - - bswap_ahdr(&e); - - magic = N_MAGIC(e); - switch (magic) { - case ZMAGIC: - case QMAGIC: - case OMAGIC: - lseek(fd, N_TXTOFF(e), SEEK_SET); - size = read(fd, addr, e.a_text + e.a_data); - if (size < 0) - goto fail; - break; - case NMAGIC: - lseek(fd, N_TXTOFF(e), SEEK_SET); - size = read(fd, addr, e.a_text); - if (size < 0) - goto fail; - ret = read(fd, addr + N_DATADDR(e), e.a_data); - if (ret < 0) - goto fail; - size += ret; - break; - default: - goto fail; - } - close(fd); - return size; - fail: - close(fd); - return -1; -} - diff --git a/hw/sun4m.c b/hw/sun4m.c index 435ac02bd..014ed0926 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -26,6 +26,7 @@ #define KERNEL_LOAD_ADDR 0x00004000 #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 +#define PROM_SIZE_MAX (256 * 1024) #define PROM_ADDR 0xffd00000 #define PROM_FILENAMEB "proll.bin" #define PROM_FILENAMEE "proll.elf" @@ -263,9 +264,12 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); prom_offset = ram_size + vram_size; + cpu_register_physical_memory(PROM_ADDR, + (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, + prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); - ret = load_elf(buf, phys_ram_base + prom_offset); + ret = load_elf(buf, 0); if (ret < 0) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); ret = load_image(buf, phys_ram_base + prom_offset); @@ -275,12 +279,10 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, buf); exit(1); } - cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, - prom_offset | IO_MEM_ROM); kernel_size = 0; if (linux_boot) { - kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + kernel_size = load_elf(kernel_filename, -0xf0000000); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) diff --git a/hw/sun4u.c b/hw/sun4u.c index 0cf538179..bb40697c4 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -27,6 +27,7 @@ #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 #define INITRD_LOAD_ADDR 0x00300000 +#define PROM_SIZE_MAX (256 * 1024) #define PROM_ADDR 0x1fff0000000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL #define APB_MEM_BASE 0x1ff00000000ULL @@ -277,9 +278,12 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0, ram_size, 0); prom_offset = ram_size + vga_ram_size; + cpu_register_physical_memory(PROM_ADDR, + (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, + prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); - ret = load_elf(buf, phys_ram_base + prom_offset); + ret = load_elf(buf, 0); if (ret < 0) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); ret = load_image(buf, phys_ram_base + prom_offset); @@ -289,13 +293,12 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, buf); exit(1); } - cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, - prom_offset | IO_MEM_ROM); kernel_size = 0; initrd_size = 0; if (linux_boot) { - kernel_size = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + /* XXX: put correct offset */ + kernel_size = load_elf(kernel_filename, 0); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) -- cgit v1.2.3 From d0ecd2aaf9ecc2c434eed4c5de7917787476223e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 17:14:48 +0000 Subject: added cpu_physical_memory_write_rom() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1833 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 2 ++ exec.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index eb65b59ea..9abdf2a5e 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -857,6 +857,8 @@ 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); diff --git a/exec.c b/exec.c index 56a8c4c53..f900e09f0 100644 --- a/exec.c +++ b/exec.c @@ -2080,6 +2080,45 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } +/* used for ROM loading : can write in RAM and ROM */ +void cpu_physical_memory_write_rom(target_phys_addr_t addr, + const uint8_t *buf, int len) +{ + int l; + uint8_t *ptr; + target_phys_addr_t page; + unsigned long pd; + PhysPageDesc *p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + p = phys_page_find(page >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && + (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM) { + /* do nothing */ + } else { + unsigned long addr1; + addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); + /* ROM/RAM case */ + ptr = phys_ram_base + addr1; + memcpy(ptr, buf, l); + } + len -= l; + buf += l; + addr += l; + } +} + + /* warning: addr must be aligned */ uint32_t ldl_phys(target_phys_addr_t addr) { -- cgit v1.2.3 From cc8ae6de58eb6cd8748197442bbcdc165b5f87a2 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 23 Apr 2006 17:57:59 +0000 Subject: Autodetect tools neccessary for building documentation. Make distclean remove generated documentation files. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1834 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 6 +++++- configure | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0c2ab09dd..ff60329ad 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,11 @@ TOOLS=qemu-img$(EXESUF) ifdef CONFIG_STATIC LDFLAGS+=-static endif +ifdef BUILD_DOCS DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 +else +DOCS= +endif all: dyngen$(EXESUF) $(TOOLS) $(DOCS) for d in $(TARGET_DIRS); do \ @@ -34,7 +38,7 @@ clean: done distclean: clean - rm -f config-host.mak config-host.h + rm -f config-host.mak config-host.h $(DOCS) for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ done diff --git a/configure b/configure index 356461775..120e03d7b 100755 --- a/configure +++ b/configure @@ -94,6 +94,7 @@ check_gfx="yes" check_gcc="yes" softmmu="yes" user="no" +build_docs="no" # OS specific targetos=`uname -s` @@ -427,6 +428,11 @@ fi # sdl compile test fi # cross compilation fi # -z $sdl +# Check if tools are available to build documentation. +if [ ! -z `which texi2html` ] && [ ! -z `which pod2man` ]; then + build_docs="yes" +fi + if test "$mingw32" = "yes" ; then if test -z "$prefix" ; then prefix="/c/Program Files/Qemu" @@ -489,6 +495,7 @@ else fi echo "FMOD support $fmod $fmod_support" echo "kqemu support $kqemu" +echo "Documentation $build_docs" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -632,6 +639,9 @@ 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 -- cgit v1.2.3 From f9ebe432db4e0933bdedae021d3b1e23f188be12 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 18:18:10 +0000 Subject: removed unnecessary header git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1835 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 1 - target-ppc/op_helper.c | 1 - 2 files changed, 2 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9066ce7d1..d9f1c9990 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -17,7 +17,6 @@ * 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 #include "exec.h" #define MIPS_DEBUG_DISAS diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 06fa6d4fa..e949eb42e 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -17,7 +17,6 @@ * 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 #include "exec.h" #define MEMSUFFIX _raw -- cgit v1.2.3 From bbeb7b5cbd312b4690843499e0061691b8ae1fd8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 18:42:15 +0000 Subject: SIGINT generation (Jason Wessel) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1836 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 5fdf800bd..8157160fd 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -654,9 +654,11 @@ static void gdb_vm_stopped(void *opaque, int reason) if (reason == EXCP_DEBUG) { tb_flush(s->env); ret = SIGTRAP; - } - else + } else if (reason == EXCP_INTERRUPT) { + ret = SIGINT; + } else { ret = 0; + } snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(s, buf); } -- cgit v1.2.3 From f4e15b4b4b0b8dcecf056ea817aae967de401b45 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 23 Apr 2006 19:41:17 +0000 Subject: Fix slirp redirection on systems without a useful host IP address. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1837 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/misc.c | 19 ++++++++++--------- slirp/slirp.c | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/slirp/misc.c b/slirp/misc.c index a58b63100..1cd874973 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -88,15 +88,16 @@ void getouraddr() { char buff[256]; - struct hostent *he; - - if (gethostname(buff,256) < 0) - return; - - if ((he = gethostbyname(buff)) == NULL) - return; - - our_addr = *(struct in_addr *)he->h_addr; + struct hostent *he = NULL; + + if (gethostname(buff,256) == 0) + he = gethostbyname(buff); + if (he) + our_addr = *(struct in_addr *)he->h_addr; + /* If the host doesn't have a useful IP address then use the + guest side address. */ + if (our_addr.s_addr == 0 || our_addr.s_addr == loopback_addr.s_addr) + our_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); } #if SIZEOF_CHAR_P == 8 diff --git a/slirp/slirp.c b/slirp/slirp.c index a7d3f6911..b4ab12a08 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -146,7 +146,6 @@ void slirp_init(void) m_init(); /* set default addresses */ - getouraddr(); inet_aton("127.0.0.1", &loopback_addr); if (get_dns_addr(&dns_addr) < 0) { @@ -155,6 +154,7 @@ void slirp_init(void) } inet_aton(CTL_SPECIAL, &special_addr); + getouraddr(); } #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) -- cgit v1.2.3 From b854608e0c10eb31d545d1fa7db2412522a315f5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 21:33:48 +0000 Subject: sparc condition code computation fix (Even Rouault) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1838 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 80 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 67de62f4c..4609cdf1e 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -415,28 +415,50 @@ void OPPROTO op_addx_T1_T0(void) void OPPROTO op_addx_T1_T0_cc(void) { target_ulong src1; - src1 = T0; - T0 += T1 + FLAG_SET(PSR_CARRY); - env->psr = 0; + if (FLAG_SET(PSR_CARRY)) + { + T0 += T1 + 1; + env->psr = 0; +#ifdef TARGET_SPARC64 + if ((T0 & 0xffffffff) <= (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + env->xcc = 0; + if (T0 <= src1) + env->xcc |= PSR_CARRY; +#else + if (T0 <= src1) + env->psr |= PSR_CARRY; +#endif + } + else + { + T0 += T1; + env->psr = 0; +#ifdef TARGET_SPARC64 + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + env->xcc = 0; + if (T0 < src1) + env->xcc |= PSR_CARRY; +#else + if (T0 < src1) + env->psr |= PSR_CARRY; +#endif + } #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) env->psr |= PSR_OVF; - env->xcc = 0; if (!T0) env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) env->xcc |= PSR_NEG; - if (T0 < src1) - env->xcc |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) env->xcc |= PSR_OVF; #else @@ -444,8 +466,6 @@ void OPPROTO op_addx_T1_T0_cc(void) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if (T0 < src1) - env->psr |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) env->psr |= PSR_OVF; #endif @@ -505,28 +525,50 @@ void OPPROTO op_subx_T1_T0(void) void OPPROTO op_subx_T1_T0_cc(void) { target_ulong src1; - src1 = T0; - T0 -= T1 + FLAG_SET(PSR_CARRY); - env->psr = 0; + if (FLAG_SET(PSR_CARRY)) + { + T0 -= T1 + 1; + env->psr = 0; +#ifdef TARGET_SPARC64 + if ((src1 & 0xffffffff) <= (T1 & 0xffffffff)) + env->psr |= PSR_CARRY; + env->xcc = 0; + if (src1 <= T1) + env->xcc |= PSR_CARRY; +#else + if (src1 <= T1) + env->psr |= PSR_CARRY; +#endif + } + else + { + T0 -= T1; + env->psr = 0; +#ifdef TARGET_SPARC64 + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) + env->psr |= PSR_CARRY; + env->xcc = 0; + if (src1 < T1) + env->xcc |= PSR_CARRY; +#else + if (src1 < T1) + env->psr |= PSR_CARRY; +#endif + } #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) env->psr |= PSR_OVF; - env->xcc = 0; if (!T0) env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) env->xcc |= PSR_NEG; - if (src1 < T1) - env->xcc |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) env->xcc |= PSR_OVF; #else @@ -534,8 +576,6 @@ void OPPROTO op_subx_T1_T0_cc(void) env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) env->psr |= PSR_NEG; - if (src1 < T1) - env->psr |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) env->psr |= PSR_OVF; #endif -- cgit v1.2.3 From 465e983875be3d7c8cb8f53628e090f15417b4f7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 21:54:01 +0000 Subject: SSE3 support (Joachim Henke) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1839 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 2 +- target-i386/exec.h | 4 ++++ target-i386/helper2.c | 2 +- target-i386/op.c | 47 ++++++++++++++++++++++++++++++++++++ target-i386/translate.c | 63 ++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 102 insertions(+), 16 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index eca3993b9..2f2361730 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -265,7 +265,7 @@ #define CPUID_SSE (1 << 25) #define CPUID_SSE2 (1 << 26) -#define CPUID_EXT_SS3 (1 << 0) +#define CPUID_EXT_SSE3 (1 << 0) #define CPUID_EXT_MONITOR (1 << 3) #define CPUID_EXT_CX16 (1 << 13) diff --git a/target-i386/exec.h b/target-i386/exec.h index 61ba3cd6d..8299af4e7 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -260,6 +260,8 @@ static inline void stfl(target_ulong ptr, float v) /* use long double functions */ #define floatx_to_int32 floatx80_to_int32 #define floatx_to_int64 floatx80_to_int64 +#define floatx_to_int32_round_to_zero floatx80_to_int32_round_to_zero +#define floatx_to_int64_round_to_zero floatx80_to_int64_round_to_zero #define floatx_abs floatx80_abs #define floatx_chs floatx80_chs #define floatx_round_to_int floatx80_round_to_int @@ -278,6 +280,8 @@ static inline void stfl(target_ulong ptr, float v) #else #define floatx_to_int32 float64_to_int32 #define floatx_to_int64 float64_to_int64 +#define floatx_to_int32_round_to_zero float64_to_int32_round_to_zero +#define floatx_to_int64_round_to_zero float64_to_int64_round_to_zero #define floatx_abs float64_abs #define floatx_chs float64_chs #define floatx_round_to_int float64_round_to_int diff --git a/target-i386/helper2.c b/target-i386/helper2.c index cb896cb5e..5195fa3d3 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -108,7 +108,7 @@ CPUX86State *cpu_x86_init(void) CPUID_CX8 | CPUID_PGE | CPUID_CMOV | CPUID_PAT); env->pat = 0x0007040600070406ULL; - env->cpuid_ext_features = 0; + env->cpuid_ext_features = CPUID_EXT_SSE3; env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP; env->cpuid_xlevel = 0; { diff --git a/target-i386/op.c b/target-i386/op.c index 93cc3c42e..20eeaa440 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1911,6 +1911,53 @@ void OPPROTO op_fistll_ST0_A0(void) FORCE_RET(); } +void OPPROTO op_fistt_ST0_A0(void) +{ +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif + int val; + + d = ST0; + val = floatx_to_int32_round_to_zero(d, &env->fp_status); + if (val != (int16_t)val) + val = -32768; + stw(A0, val); + FORCE_RET(); +} + +void OPPROTO op_fisttl_ST0_A0(void) +{ +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif + int val; + + d = ST0; + val = floatx_to_int32_round_to_zero(d, &env->fp_status); + stl(A0, val); + FORCE_RET(); +} + +void OPPROTO op_fisttll_ST0_A0(void) +{ +#if defined(__sparc__) && !defined(__sparc_v9__) + register CPU86_LDouble d asm("o0"); +#else + CPU86_LDouble d; +#endif + int64_t val; + + d = ST0; + val = floatx_to_int64_round_to_zero(d, &env->fp_status); + stq(A0, val); + FORCE_RET(); +} + void OPPROTO op_fbld_ST0_A0(void) { helper_fbld_ST0_A0(); diff --git a/target-i386/translate.c b/target-i386/translate.c index cca456086..6dcaf5d89 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2334,7 +2334,7 @@ static GenOpFunc2 *sse_op_table1[256][4] = { /* pure SSE operations */ [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ - [0x12] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */ + [0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd, movsldup, movddup */ [0x13] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */ [0x14] = { gen_op_punpckldq_xmm, gen_op_punpcklqdq_xmm }, [0x15] = { gen_op_punpckhdq_xmm, gen_op_punpckhqdq_xmm }, @@ -2436,7 +2436,7 @@ static GenOpFunc2 *sse_op_table1[256][4] = { [0xed] = MMX_OP2(paddsw), [0xee] = MMX_OP2(pmaxsw), [0xef] = MMX_OP2(pxor), - [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu (PNI) */ + [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu */ [0xf1] = MMX_OP2(psllw), [0xf2] = MMX_OP2(pslld), [0xf3] = MMX_OP2(psllq), @@ -2563,8 +2563,8 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) case 0x1e7: /* movntdq */ case 0x02b: /* movntps */ case 0x12b: /* movntps */ - case 0x2f0: /* lddqu */ - if (mod == 3) + case 0x3f0: /* lddqu */ + if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); @@ -2642,6 +2642,34 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1))); } break; + case 0x212: /* movsldup */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)), + offsetof(CPUX86State,xmm_regs[rm].XMM_L(0))); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)), + offsetof(CPUX86State,xmm_regs[rm].XMM_L(2))); + } + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)), + offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)), + offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); + break; + case 0x312: /* movddup */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); + } + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); + break; case 0x016: /* movhps */ case 0x116: /* movhpd */ if (mod != 3) { @@ -4278,16 +4306,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0x08: /* flds */ case 0x0a: /* fsts */ case 0x0b: /* fstps */ - case 0x18: /* fildl */ - case 0x1a: /* fistl */ - case 0x1b: /* fistpl */ - case 0x28: /* fldl */ - case 0x2a: /* fstl */ - case 0x2b: /* fstpl */ - case 0x38: /* filds */ - case 0x3a: /* fists */ - case 0x3b: /* fistps */ - + case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */ + case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */ + case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */ switch(op & 7) { case 0: switch(op >> 4) { @@ -4306,6 +4327,20 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; } break; + case 1: + switch(op >> 4) { + case 1: + gen_op_fisttl_ST0_A0(); + break; + case 2: + gen_op_fisttll_ST0_A0(); + break; + case 3: + default: + gen_op_fistt_ST0_A0(); + } + gen_op_fpop(); + break; default: switch(op >> 4) { case 0: -- cgit v1.2.3 From fa7cf687ac84f2cecdedec86fa4d5297c2415db0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 21:57:03 +0000 Subject: warning fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1840 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 9862637e0..89ae6befc 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -904,7 +904,7 @@ seen from the emulated kernel at IP address 172.20.0.1. @example > ./qemu.sh Connected to host network interface: tun0 -Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 +Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 BIOS-provided physical RAM map: BIOS-e801: 0000000000000000 - 000000000009f000 (usable) BIOS-e801: 0000000000100000 - 0000000002000000 (usable) @@ -941,7 +941,7 @@ Detected PS/2 Mouse Port. pty: 256 Unix98 ptys configured Serial driver version 5.05c (2001-07-08) with no serial options enabled ttyS00 at 0x03f8 (irq = 4) is a 16450 -ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com) +ne.c:v1.10 9/23/94 Donald Becker (becker@@scyld.com) Last modified Nov 1, 2000 by Paul Gortmaker NE*000 ethercard probe at 0x300: 52 54 00 12 34 56 eth0: NE2000 found at 0x300, using IRQ 9. @@ -964,7 +964,7 @@ EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended VFS: Mounted root (ext2 filesystem). Freeing unused kernel memory: 64k freed -Linux version 2.4.21 (bellard@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 +Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 QEMU Linux test distribution (based on Redhat 9) -- cgit v1.2.3 From e774a278d82c9391c9fb6c9af42cd08bb9364b9f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 22:21:30 +0000 Subject: -win2k-hack performance+DMA support (Leonardo E. Reiter) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1841 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index cf9a9a7bb..decf34582 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -336,6 +336,7 @@ typedef struct IDEState { uint8_t *data_end; uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; QEMUTimer *sector_write_timer; /* only used for win2k instal hack */ + uint32_t irq_count; /* counts IRQs when using win2k install hack */ } IDEState; #define BM_STATUS_DMAING 0x01 @@ -712,7 +713,7 @@ static void ide_sector_write(IDEState *s) ide_set_sector(s, sector_num + n); #ifdef TARGET_I386 - if (win2k_install_hack) { + if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { /* It seems there is a bug in the Windows 2000 installer HDD IDE driver which fills the disk with empty logs when the IDE write IRQ comes too early. This hack tries to correct @@ -750,7 +751,19 @@ static int ide_write_dma_cb(IDEState *s, if (n == 0) { /* end of transfer */ s->status = READY_STAT | SEEK_STAT; - ide_set_irq(s); +#ifdef TARGET_I386 + if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { + /* It seems there is a bug in the Windows 2000 installer + HDD IDE driver which fills the disk with empty logs + when the IDE write IRQ comes too early. This hack tries + to correct that at the expense of slower write + performances. Use this option _only_ to install Windows + 2000. You must disable it for normal use. */ + qemu_mod_timer(s->sector_write_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); + } else +#endif + ide_set_irq(s); return 0; } if (n > MAX_MULT_SECTORS) -- cgit v1.2.3 From 1b2b0af50d4845aa867b2bdbb57dc62149e3ce1a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 23 Apr 2006 22:59:41 +0000 Subject: 64 bit fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1842 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 89c0842af..e54820239 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -23,8 +23,8 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) #endif #if defined(_BSD) -#define lrint(d) ((int32_t)rint(d)) -#define llrint(d) ((int64_t)rint(d)) +#define lrint(d) ((long)rint(d)) +#define llrint(d) ((long long)rint(d)) #endif #if defined(__powerpc__) @@ -80,12 +80,27 @@ floatx80 int64_to_floatx80( int64_t v STATUS_PARAM) } #endif +/* XXX: this code implements the x86 behaviour, not the IEEE one. */ +#if HOST_LONG_BITS == 32 +static inline int long_to_int32(long a) +{ + return a; +} +#else +static inline int long_to_int32(long a) +{ + if (a != (int32_t)a) + a = 0x80000000; + return a; +} +#endif + /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ int float32_to_int32( float32 a STATUS_PARAM) { - return lrintf(a); + return long_to_int32(lrintf(a)); } int float32_to_int32_round_to_zero( float32 a STATUS_PARAM) { @@ -167,7 +182,7 @@ char float32_is_signaling_nan( float32 a1) *----------------------------------------------------------------------------*/ int float64_to_int32( float64 a STATUS_PARAM) { - return lrint(a); + return long_to_int32(lrint(a)); } int float64_to_int32_round_to_zero( float64 a STATUS_PARAM) { @@ -276,7 +291,7 @@ char float64_is_signaling_nan( float64 a1) *----------------------------------------------------------------------------*/ int floatx80_to_int32( floatx80 a STATUS_PARAM) { - return lrintl(a); + return long_to_int32(lrintl(a)); } int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM) { -- cgit v1.2.3 From ba6526df383a9cbc500b77ef3726631ab7453286 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 20:14:56 +0000 Subject: movddup fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1843 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 6dcaf5d89..a1b91d353 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2668,7 +2668,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); } gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)), - offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); + offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); break; case 0x016: /* movhps */ case 0x116: /* movhpd */ -- cgit v1.2.3 From 6c3ee14ff37551b0a490aeca6f7fc45aae3424e3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 20:18:26 +0000 Subject: better shift tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1844 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386-shift.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-i386-shift.h b/tests/test-i386-shift.h index 7a98e27a4..c1ed489f1 100644 --- a/tests/test-i386-shift.h +++ b/tests/test-i386-shift.h @@ -174,7 +174,7 @@ void glue(test_, OP)(void) for(i = 0; i < n; i++) exec_op(0x21ad3d34, 0x12345678, i); for(i = 0; i < n; i++) - exec_op(0x813f3421, 0x82345678, i); + exec_op(0x813f3421, 0x82345679, i); } void *glue(_test_, OP) __init_call = glue(test_, OP); -- cgit v1.2.3 From ad1a5b7853dbc510a9f6c9628ff623148d06c9d5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 20:19:07 +0000 Subject: rol/ror cc fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1845 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_template_mem.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h index a999e2d44..9f72a8c96 100644 --- a/target-i386/ops_template_mem.h +++ b/target-i386/ops_template_mem.h @@ -73,8 +73,8 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) int count; target_long src; - count = T1 & SHIFT_MASK; - if (count) { + if (T1 & SHIFT1_MASK) { + count = T1 & SHIFT_MASK; src = T0; T0 &= DATA_MASK; T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); @@ -97,8 +97,8 @@ void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) int count; target_long src; - count = T1 & SHIFT_MASK; - if (count) { + if (T1 & SHIFT1_MASK) { + count = T1 & SHIFT_MASK; src = T0; T0 &= DATA_MASK; T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); -- cgit v1.2.3 From fd4a43e4e28a594a20beefe78b0fe7ecd34bd981 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 20:32:17 +0000 Subject: ia64 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1846 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 --- cpu-exec.c | 3 +-- dyngen.c | 6 ++++-- dyngen.h | 3 +++ ia64-syscall.S | 32 -------------------------------- linux-user/syscall.c | 2 +- 6 files changed, 9 insertions(+), 40 deletions(-) delete mode 100644 ia64-syscall.S diff --git a/Makefile.target b/Makefile.target index 9b5ebcde0..20fb8f0d1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -252,9 +252,6 @@ ifeq ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k) LIBOBJS+=m68k-dis.o endif -ifeq ($(ARCH),ia64) -OBJS += ia64-syscall.o -endif ifdef CONFIG_GDBSTUB OBJS+=gdbstub.o endif diff --git a/cpu-exec.c b/cpu-exec.c index 872f51f62..ca4695343 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1363,7 +1363,6 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #ifndef __ISR_VALID /* This ought to be in ... */ # define __ISR_VALID 1 -# define si_flags _sifields._sigfault._si_pad0 #endif int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) @@ -1379,7 +1378,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) case SIGSEGV: case SIGBUS: case SIGTRAP: - if (info->si_code && (info->si_flags & __ISR_VALID)) + if (info->si_code && (info->si_segvflags & __ISR_VALID)) /* ISR.W (write-access) is bit 33: */ is_write = (info->si_isr >> 33) & 1; break; diff --git a/dyngen.c b/dyngen.c index fc4722ef9..c1f348a94 100644 --- a/dyngen.c +++ b/dyngen.c @@ -2475,10 +2475,12 @@ fprintf(outfile, ); #ifdef HOST_IA64 fprintf(outfile, - " ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, " + " {\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"); + "plt_target, plt_offset);\n }\n"); #endif /* generate some code patching */ diff --git a/dyngen.h b/dyngen.h index 76866d4a1..5bb170e94 100644 --- a/dyngen.h +++ b/dyngen.h @@ -420,6 +420,9 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp, } 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; } diff --git a/ia64-syscall.S b/ia64-syscall.S deleted file mode 100644 index ab073f22b..000000000 --- a/ia64-syscall.S +++ /dev/null @@ -1,32 +0,0 @@ -/* derived from glibc sysdeps/unix/sysv/linux/ia64/sysdep.S */ - -#define __ASSEMBLY__ - -#include -#include - -ENTRY(__syscall_error) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0) - alloc r33=ar.pfs, 0, 4, 0, 0 - mov r32=rp - .body - mov r35=r8 - mov r34=r1 - ;; - br.call.sptk.many b0 = __errno_location -.Lret0: /* force new bundle */ - st4 [r8]=r35 - mov r1=r34 - mov rp=r32 - mov r8=-1 - mov ar.pfs=r33 - br.ret.sptk.few b0 -END(__syscall_error) - -GLOBAL_ENTRY(__ia64_syscall) - mov r15=r37 /* syscall number */ - break __BREAK_SYSCALL - cmp.eq p6,p0=-1,r10 /* r10 = -1 on error */ -(p6) br.cond.spnt.few __syscall_error - br.ret.sptk.few b0 -.endp __ia64_syscall diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 516b32bf9..c3b22ce72 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1623,7 +1623,7 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) #endif new_env->opaque = ts; #ifdef __ia64__ - ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); + ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); #else ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); #endif -- cgit v1.2.3 From 56bebe70bd3659e046e6a6be08492061fedd1ad1 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 21:10:52 +0000 Subject: usb setup state machine fix when driver reads or writes too many bytes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1847 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/usb.c b/hw/usb.c index 758b341ff..ca1489621 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -91,8 +91,8 @@ int usb_generic_handle_packet(USBDevice *s, int pid, case 0: switch(s->setup_state) { case SETUP_STATE_ACK: - s->setup_state = SETUP_STATE_IDLE; if (!(s->setup_buf[0] & USB_DIR_IN)) { + s->setup_state = SETUP_STATE_IDLE; ret = s->handle_control(s, (s->setup_buf[0] << 8) | s->setup_buf[1], (s->setup_buf[3] << 8) | s->setup_buf[2], @@ -102,7 +102,7 @@ int usb_generic_handle_packet(USBDevice *s, int pid, if (ret > 0) ret = 0; } else { - goto fail; + /* return 0 byte */ } break; case SETUP_STATE_DATA: @@ -136,11 +136,11 @@ int usb_generic_handle_packet(USBDevice *s, int pid, case 0: switch(s->setup_state) { case SETUP_STATE_ACK: - s->setup_state = SETUP_STATE_IDLE; if (s->setup_buf[0] & USB_DIR_IN) { + s->setup_state = SETUP_STATE_IDLE; /* transfer OK */ } else { - goto fail; + /* ignore additionnal output */ } break; case SETUP_STATE_DATA: -- cgit v1.2.3 From 72899afc5d2a33576094a80d1eba797e293c975a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 21:18:20 +0000 Subject: separate file for usb hub device git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1848 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/usb-hub.c | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb.c | 497 ----------------------------------------------------- 3 files changed, 519 insertions(+), 498 deletions(-) create mode 100644 hw/usb-hub.c diff --git a/Makefile.target b/Makefile.target index 20fb8f0d1..be2fcfe4a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -302,7 +302,7 @@ SOUND_HW += fmopl.o adlib.o endif # USB layer -VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o +VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o # PCI network cards VL_OBJS+= ne2000.o rtl8139.o diff --git a/hw/usb-hub.c b/hw/usb-hub.c new file mode 100644 index 000000000..4d4cb167f --- /dev/null +++ b/hw/usb-hub.c @@ -0,0 +1,518 @@ +/* + * QEMU USB HUB emulation + * + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG + +#define MAX_PORTS 8 + +typedef struct USBHubPort { + USBPort port; + uint16_t wPortStatus; + uint16_t wPortChange; +} USBHubPort; + +typedef struct USBHubState { + USBDevice dev; + int nb_ports; + USBHubPort ports[MAX_PORTS]; +} USBHubState; + +#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) +#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) +#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) +#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) + +#define PORT_STAT_CONNECTION 0x0001 +#define PORT_STAT_ENABLE 0x0002 +#define PORT_STAT_SUSPEND 0x0004 +#define PORT_STAT_OVERCURRENT 0x0008 +#define PORT_STAT_RESET 0x0010 +#define PORT_STAT_POWER 0x0100 +#define PORT_STAT_LOW_SPEED 0x0200 +#define PORT_STAT_HIGH_SPEED 0x0400 +#define PORT_STAT_TEST 0x0800 +#define PORT_STAT_INDICATOR 0x1000 + +#define PORT_STAT_C_CONNECTION 0x0001 +#define PORT_STAT_C_ENABLE 0x0002 +#define PORT_STAT_C_SUSPEND 0x0004 +#define PORT_STAT_C_OVERCURRENT 0x0008 +#define PORT_STAT_C_RESET 0x0010 + +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 +#define PORT_OVERCURRENT 3 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOWSPEED 9 +#define PORT_HIGHSPEED 10 +#define PORT_C_CONNECTION 16 +#define PORT_C_ENABLE 17 +#define PORT_C_SUSPEND 18 +#define PORT_C_OVERCURRENT 19 +#define PORT_C_RESET 20 +#define PORT_TEST 21 +#define PORT_INDICATOR 22 + +/* same as Linux kernel root hubs */ + +static const uint8_t qemu_hub_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x01, /* u16 bcdUSB; v1.1 */ + + 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + 0x00, 0x00, /* u16 idVendor; */ + 0x00, 0x00, /* u16 idProduct; */ + 0x01, 0x01, /* u16 bcdDevice */ + + 0x03, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x01, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +/* XXX: patch interrupt size */ +static const uint8_t qemu_hub_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x19, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xc0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x00, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* u8 if_bInterfaceSubClass; */ + 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* u8 if_iInterface; */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + +static const uint8_t qemu_hub_hub_descriptor[] = +{ + 0x09, /* u8 bLength; */ + 0x29, /* u8 bDescriptorType; Hub-descriptor */ + 0x00, /* u8 bNbrPorts; (patched later) */ + 0x0a, /* u16 wHubCharacteristics; */ + 0x00, /* (per-port OC, no power switching) */ + 0x01, /* u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* u8 bHubContrCurrent; 0 mA */ + 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */ +}; + +static void usb_hub_attach(USBPort *port1, USBDevice *dev) +{ + USBHubState *s = port1->opaque; + USBHubPort *port = &s->ports[port1->index]; + + if (dev) { + if (port->port.dev) + usb_attach(port1, NULL); + + port->wPortStatus |= PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (dev->speed == USB_SPEED_LOW) + port->wPortStatus |= PORT_STAT_LOW_SPEED; + else + port->wPortStatus &= ~PORT_STAT_LOW_SPEED; + port->port.dev = dev; + } else { + dev = port->port.dev; + if (dev) { + port->wPortStatus &= ~PORT_STAT_CONNECTION; + port->wPortChange |= PORT_STAT_C_CONNECTION; + if (port->wPortStatus & PORT_STAT_ENABLE) { + port->wPortStatus &= ~PORT_STAT_ENABLE; + port->wPortChange |= PORT_STAT_C_ENABLE; + } + port->port.dev = NULL; + } + } +} + +static void usb_hub_handle_reset(USBDevice *dev) +{ + /* XXX: do it */ +} + +static int usb_hub_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBHubState *s = (USBHubState *)dev; + int ret; + + switch(request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_hub_dev_descriptor, + sizeof(qemu_hub_dev_descriptor)); + ret = sizeof(qemu_hub_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_hub_config_descriptor, + sizeof(qemu_hub_config_descriptor)); + ret = sizeof(qemu_hub_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "314159"); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "QEMU USB Hub"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "QEMU " QEMU_VERSION); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + /* usb specific requests */ + case GetHubStatus: + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + ret = 4; + break; + case GetPortStatus: + { + unsigned int n = index - 1; + USBHubPort *port; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + data[0] = port->wPortStatus; + data[1] = port->wPortStatus >> 8; + data[2] = port->wPortChange; + data[3] = port->wPortChange >> 8; + ret = 4; + } + break; + case SetHubFeature: + case ClearHubFeature: + if (value == 0 || value == 1) { + } else { + goto fail; + } + ret = 0; + break; + case SetPortFeature: + { + unsigned int n = index - 1; + USBHubPort *port; + USBDevice *dev; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + dev = port->port.dev; + switch(value) { + case PORT_SUSPEND: + port->wPortStatus |= PORT_STAT_SUSPEND; + break; + case PORT_RESET: + if (dev) { + dev->handle_packet(dev, + USB_MSG_RESET, 0, 0, NULL, 0); + port->wPortChange |= PORT_STAT_C_RESET; + /* set enable bit */ + port->wPortChange |= PORT_STAT_C_ENABLE; + port->wPortStatus |= PORT_STAT_ENABLE; + } + break; + case PORT_POWER: + break; + default: + goto fail; + } + ret = 0; + } + break; + case ClearPortFeature: + { + unsigned int n = index - 1; + USBHubPort *port; + USBDevice *dev; + if (n >= s->nb_ports) + goto fail; + port = &s->ports[n]; + dev = port->port.dev; + switch(value) { + case PORT_ENABLE: + port->wPortStatus &= ~PORT_STAT_ENABLE; + break; + case PORT_C_ENABLE: + port->wPortChange &= ~PORT_STAT_C_ENABLE; + break; + case PORT_SUSPEND: + port->wPortStatus &= ~PORT_STAT_SUSPEND; + break; + case PORT_C_SUSPEND: + port->wPortChange &= ~PORT_STAT_C_SUSPEND; + break; + case PORT_C_CONNECTION: + port->wPortChange &= ~PORT_STAT_C_CONNECTION; + break; + case PORT_C_OVERCURRENT: + port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; + break; + case PORT_C_RESET: + port->wPortChange &= ~PORT_STAT_C_RESET; + break; + default: + goto fail; + } + ret = 0; + } + break; + case GetHubDescriptor: + memcpy(data, qemu_hub_hub_descriptor, + sizeof(qemu_hub_hub_descriptor)); + data[2] = s->nb_ports; + ret = sizeof(qemu_hub_hub_descriptor); + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_hub_handle_data(USBDevice *dev, int pid, + uint8_t devep, uint8_t *data, int len) +{ + USBHubState *s = (USBHubState *)dev; + int ret; + + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { + USBHubPort *port; + unsigned int status; + int i, n; + n = (s->nb_ports + 1 + 7) / 8; + if (n > len) + return USB_RET_BABBLE; + status = 0; + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + if (port->wPortChange) + status |= (1 << (i + 1)); + } + if (status != 0) { + for(i = 0; i < n; i++) { + data[i] = status >> (8 * i); + } + ret = n; + } else { + ret = 0; + } + } else { + goto fail; + } + break; + case USB_TOKEN_OUT: + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_hub_broadcast_packet(USBHubState *s, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + USBHubPort *port; + USBDevice *dev; + int i, ret; + + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + dev = port->port.dev; + if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { + ret = dev->handle_packet(dev, pid, + devaddr, devep, + data, len); + if (ret != USB_RET_NODEV) { + return ret; + } + } + } + return USB_RET_NODEV; +} + +static int usb_hub_handle_packet(USBDevice *dev, int pid, + uint8_t devaddr, uint8_t devep, + uint8_t *data, int len) +{ + USBHubState *s = (USBHubState *)dev; + +#if defined(DEBUG) && 0 + printf("usb_hub: pid=0x%x\n", pid); +#endif + if (dev->state == USB_STATE_DEFAULT && + dev->addr != 0 && + devaddr != dev->addr && + (pid == USB_TOKEN_SETUP || + pid == USB_TOKEN_OUT || + pid == USB_TOKEN_IN)) { + /* broadcast the packet to the devices */ + return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); + } + return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); +} + +USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) +{ + USBHubState *s; + USBHubPort *port; + int i; + + if (nb_ports > MAX_PORTS) + return NULL; + s = qemu_mallocz(sizeof(USBHubState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_hub_handle_packet; + + /* generic USB device init */ + s->dev.handle_reset = usb_hub_handle_reset; + s->dev.handle_control = usb_hub_handle_control; + s->dev.handle_data = usb_hub_handle_data; + + s->nb_ports = nb_ports; + for(i = 0; i < s->nb_ports; i++) { + port = &s->ports[i]; + port->wPortStatus = PORT_STAT_POWER; + port->wPortChange = 0; + port->port.attach = usb_hub_attach; + port->port.opaque = s; + port->port.index = i; + usb_ports[i] = &port->port; + } + return (USBDevice *)s; +} diff --git a/hw/usb.c b/hw/usb.c index ca1489621..34aac5fa9 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -191,500 +191,3 @@ int set_usb_string(uint8_t *buf, const char *str) } return q - buf; } - -/**********************/ -/* USB hub emulation */ - -//#define DEBUG - -#define MAX_PORTS 8 - -typedef struct USBHubPort { - USBPort port; - uint16_t wPortStatus; - uint16_t wPortChange; -} USBHubPort; - -typedef struct USBHubState { - USBDevice dev; - int nb_ports; - USBHubPort ports[MAX_PORTS]; -} USBHubState; - -#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) -#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) -#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) -#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) -#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) -#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) -#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) - -#define PORT_STAT_CONNECTION 0x0001 -#define PORT_STAT_ENABLE 0x0002 -#define PORT_STAT_SUSPEND 0x0004 -#define PORT_STAT_OVERCURRENT 0x0008 -#define PORT_STAT_RESET 0x0010 -#define PORT_STAT_POWER 0x0100 -#define PORT_STAT_LOW_SPEED 0x0200 -#define PORT_STAT_HIGH_SPEED 0x0400 -#define PORT_STAT_TEST 0x0800 -#define PORT_STAT_INDICATOR 0x1000 - -#define PORT_STAT_C_CONNECTION 0x0001 -#define PORT_STAT_C_ENABLE 0x0002 -#define PORT_STAT_C_SUSPEND 0x0004 -#define PORT_STAT_C_OVERCURRENT 0x0008 -#define PORT_STAT_C_RESET 0x0010 - -#define PORT_CONNECTION 0 -#define PORT_ENABLE 1 -#define PORT_SUSPEND 2 -#define PORT_OVERCURRENT 3 -#define PORT_RESET 4 -#define PORT_POWER 8 -#define PORT_LOWSPEED 9 -#define PORT_HIGHSPEED 10 -#define PORT_C_CONNECTION 16 -#define PORT_C_ENABLE 17 -#define PORT_C_SUSPEND 18 -#define PORT_C_OVERCURRENT 19 -#define PORT_C_RESET 20 -#define PORT_TEST 21 -#define PORT_INDICATOR 22 - -/* same as Linux kernel root hubs */ - -static const uint8_t qemu_hub_dev_descriptor[] = { - 0x12, /* u8 bLength; */ - 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x01, /* u16 bcdUSB; v1.1 */ - - 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* u8 bDeviceSubClass; */ - 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* u16 idVendor; */ - 0x00, 0x00, /* u16 idProduct; */ - 0x01, 0x01, /* u16 bcdDevice */ - - 0x03, /* u8 iManufacturer; */ - 0x02, /* u8 iProduct; */ - 0x01, /* u8 iSerialNumber; */ - 0x01 /* u8 bNumConfigurations; */ -}; - -/* XXX: patch interrupt size */ -static const uint8_t qemu_hub_config_descriptor[] = { - - /* one configuration */ - 0x09, /* u8 bLength; */ - 0x02, /* u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* u16 wTotalLength; */ - 0x01, /* u8 bNumInterfaces; (1) */ - 0x01, /* u8 bConfigurationValue; */ - 0x00, /* u8 iConfiguration; */ - 0xc0, /* u8 bmAttributes; - Bit 7: must be set, - 6: Self-powered, - 5: Remote wakeup, - 4..0: resvd */ - 0x00, /* u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* u8 if_bLength; */ - 0x04, /* u8 if_bDescriptorType; Interface */ - 0x00, /* u8 if_bInterfaceNumber; */ - 0x00, /* u8 if_bAlternateSetting; */ - 0x01, /* u8 if_bNumEndpoints; */ - 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* u8 if_bInterfaceSubClass; */ - 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* u8 if_iInterface; */ - - /* one endpoint (status change endpoint) */ - 0x07, /* u8 ep_bLength; */ - 0x05, /* u8 ep_bDescriptorType; Endpoint */ - 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - -static const uint8_t qemu_hub_hub_descriptor[] = -{ - 0x09, /* u8 bLength; */ - 0x29, /* u8 bDescriptorType; Hub-descriptor */ - 0x00, /* u8 bNbrPorts; (patched later) */ - 0x0a, /* u16 wHubCharacteristics; */ - 0x00, /* (per-port OC, no power switching) */ - 0x01, /* u8 bPwrOn2pwrGood; 2ms */ - 0x00, /* u8 bHubContrCurrent; 0 mA */ - 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */ - 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */ -}; - -static void usb_hub_attach(USBPort *port1, USBDevice *dev) -{ - USBHubState *s = port1->opaque; - USBHubPort *port = &s->ports[port1->index]; - - if (dev) { - if (port->port.dev) - usb_attach(port1, NULL); - - port->wPortStatus |= PORT_STAT_CONNECTION; - port->wPortChange |= PORT_STAT_C_CONNECTION; - if (dev->speed == USB_SPEED_LOW) - port->wPortStatus |= PORT_STAT_LOW_SPEED; - else - port->wPortStatus &= ~PORT_STAT_LOW_SPEED; - port->port.dev = dev; - } else { - dev = port->port.dev; - if (dev) { - port->wPortStatus &= ~PORT_STAT_CONNECTION; - port->wPortChange |= PORT_STAT_C_CONNECTION; - if (port->wPortStatus & PORT_STAT_ENABLE) { - port->wPortStatus &= ~PORT_STAT_ENABLE; - port->wPortChange |= PORT_STAT_C_ENABLE; - } - port->port.dev = NULL; - } - } -} - -static void usb_hub_handle_reset(USBDevice *dev) -{ - /* XXX: do it */ -} - -static int usb_hub_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) -{ - USBHubState *s = (USBHubState *)dev; - int ret; - - switch(request) { - case DeviceRequest | USB_REQ_GET_STATUS: - data[0] = (1 << USB_DEVICE_SELF_POWERED) | - (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); - data[1] = 0x00; - ret = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 0; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (value == USB_DEVICE_REMOTE_WAKEUP) { - dev->remote_wakeup = 1; - } else { - goto fail; - } - ret = 0; - break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - dev->addr = value; - ret = 0; - break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch(value >> 8) { - case USB_DT_DEVICE: - memcpy(data, qemu_hub_dev_descriptor, - sizeof(qemu_hub_dev_descriptor)); - ret = sizeof(qemu_hub_dev_descriptor); - break; - case USB_DT_CONFIG: - memcpy(data, qemu_hub_config_descriptor, - sizeof(qemu_hub_config_descriptor)); - ret = sizeof(qemu_hub_config_descriptor); - break; - case USB_DT_STRING: - switch(value & 0xff) { - case 0: - /* language ids */ - data[0] = 4; - data[1] = 3; - data[2] = 0x09; - data[3] = 0x04; - ret = 4; - break; - case 1: - /* serial number */ - ret = set_usb_string(data, "314159"); - break; - case 2: - /* product description */ - ret = set_usb_string(data, "QEMU USB Hub"); - break; - case 3: - /* vendor description */ - ret = set_usb_string(data, "QEMU " QEMU_VERSION); - break; - default: - goto fail; - } - break; - default: - goto fail; - } - break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = 1; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = 0; - break; - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; - /* usb specific requests */ - case GetHubStatus: - data[0] = 0; - data[1] = 0; - data[2] = 0; - data[3] = 0; - ret = 4; - break; - case GetPortStatus: - { - unsigned int n = index - 1; - USBHubPort *port; - if (n >= s->nb_ports) - goto fail; - port = &s->ports[n]; - data[0] = port->wPortStatus; - data[1] = port->wPortStatus >> 8; - data[2] = port->wPortChange; - data[3] = port->wPortChange >> 8; - ret = 4; - } - break; - case SetHubFeature: - case ClearHubFeature: - if (value == 0 || value == 1) { - } else { - goto fail; - } - ret = 0; - break; - case SetPortFeature: - { - unsigned int n = index - 1; - USBHubPort *port; - USBDevice *dev; - if (n >= s->nb_ports) - goto fail; - port = &s->ports[n]; - dev = port->port.dev; - switch(value) { - case PORT_SUSPEND: - port->wPortStatus |= PORT_STAT_SUSPEND; - break; - case PORT_RESET: - if (dev) { - dev->handle_packet(dev, - USB_MSG_RESET, 0, 0, NULL, 0); - port->wPortChange |= PORT_STAT_C_RESET; - /* set enable bit */ - port->wPortChange |= PORT_STAT_C_ENABLE; - port->wPortStatus |= PORT_STAT_ENABLE; - } - break; - case PORT_POWER: - break; - default: - goto fail; - } - ret = 0; - } - break; - case ClearPortFeature: - { - unsigned int n = index - 1; - USBHubPort *port; - USBDevice *dev; - if (n >= s->nb_ports) - goto fail; - port = &s->ports[n]; - dev = port->port.dev; - switch(value) { - case PORT_ENABLE: - port->wPortStatus &= ~PORT_STAT_ENABLE; - break; - case PORT_C_ENABLE: - port->wPortChange &= ~PORT_STAT_C_ENABLE; - break; - case PORT_SUSPEND: - port->wPortStatus &= ~PORT_STAT_SUSPEND; - break; - case PORT_C_SUSPEND: - port->wPortChange &= ~PORT_STAT_C_SUSPEND; - break; - case PORT_C_CONNECTION: - port->wPortChange &= ~PORT_STAT_C_CONNECTION; - break; - case PORT_C_OVERCURRENT: - port->wPortChange &= ~PORT_STAT_C_OVERCURRENT; - break; - case PORT_C_RESET: - port->wPortChange &= ~PORT_STAT_C_RESET; - break; - default: - goto fail; - } - ret = 0; - } - break; - case GetHubDescriptor: - memcpy(data, qemu_hub_hub_descriptor, - sizeof(qemu_hub_hub_descriptor)); - data[2] = s->nb_ports; - ret = sizeof(qemu_hub_hub_descriptor); - break; - default: - fail: - ret = USB_RET_STALL; - break; - } - return ret; -} - -static int usb_hub_handle_data(USBDevice *dev, int pid, - uint8_t devep, uint8_t *data, int len) -{ - USBHubState *s = (USBHubState *)dev; - int ret; - - switch(pid) { - case USB_TOKEN_IN: - if (devep == 1) { - USBHubPort *port; - unsigned int status; - int i, n; - n = (s->nb_ports + 1 + 7) / 8; - if (n > len) - return USB_RET_BABBLE; - status = 0; - for(i = 0; i < s->nb_ports; i++) { - port = &s->ports[i]; - if (port->wPortChange) - status |= (1 << (i + 1)); - } - if (status != 0) { - for(i = 0; i < n; i++) { - data[i] = status >> (8 * i); - } - ret = n; - } else { - ret = 0; - } - } else { - goto fail; - } - break; - case USB_TOKEN_OUT: - default: - fail: - ret = USB_RET_STALL; - break; - } - return ret; -} - -static int usb_hub_broadcast_packet(USBHubState *s, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len) -{ - USBHubPort *port; - USBDevice *dev; - int i, ret; - - for(i = 0; i < s->nb_ports; i++) { - port = &s->ports[i]; - dev = port->port.dev; - if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { - ret = dev->handle_packet(dev, pid, - devaddr, devep, - data, len); - if (ret != USB_RET_NODEV) { - return ret; - } - } - } - return USB_RET_NODEV; -} - -static int usb_hub_handle_packet(USBDevice *dev, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len) -{ - USBHubState *s = (USBHubState *)dev; - -#if defined(DEBUG) && 0 - printf("usb_hub: pid=0x%x\n", pid); -#endif - if (dev->state == USB_STATE_DEFAULT && - dev->addr != 0 && - devaddr != dev->addr && - (pid == USB_TOKEN_SETUP || - pid == USB_TOKEN_OUT || - pid == USB_TOKEN_IN)) { - /* broadcast the packet to the devices */ - return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); - } - return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); -} - -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) -{ - USBHubState *s; - USBHubPort *port; - int i; - - if (nb_ports > MAX_PORTS) - return NULL; - s = qemu_mallocz(sizeof(USBHubState)); - if (!s) - return NULL; - s->dev.speed = USB_SPEED_FULL; - s->dev.handle_packet = usb_hub_handle_packet; - - /* generic USB device init */ - s->dev.handle_reset = usb_hub_handle_reset; - s->dev.handle_control = usb_hub_handle_control; - s->dev.handle_data = usb_hub_handle_data; - - s->nb_ports = nb_ports; - for(i = 0; i < s->nb_ports; i++) { - port = &s->ports[i]; - port->wPortStatus = PORT_STAT_POWER; - port->wPortChange = 0; - port->port.attach = usb_hub_attach; - port->port.opaque = s; - port->port.index = i; - usb_ports[i] = &port->port; - } - return (USBDevice *)s; -} -- cgit v1.2.3 From 135e73c5f7e6a5630a445ca87059701c267f5193 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 21:25:26 +0000 Subject: do not set PORT_STAT_C_ENABLE when doing port reset (Lonnie Mendez) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1849 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hub.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 4d4cb167f..6f6e429a0 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -336,7 +336,6 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, USB_MSG_RESET, 0, 0, NULL, 0); port->wPortChange |= PORT_STAT_C_RESET; /* set enable bit */ - port->wPortChange |= PORT_STAT_C_ENABLE; port->wPortStatus |= PORT_STAT_ENABLE; } break; -- cgit v1.2.3 From 52328140e2892c0f7033f6857f1a96da1680bf79 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 21:38:50 +0000 Subject: HCHALTED status bit handling (Lonnie Mendez) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1850 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index f902d4615..10b3fa6fd 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -174,6 +174,9 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { /* start frame processing */ qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock)); + s->status &= ~UHCI_STS_HCHALTED; + } else if (!(val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { + s->status |= UHCI_STS_HCHALTED; } if (val & UHCI_CMD_GRESET) { UHCIPort *port; @@ -528,6 +531,8 @@ static void uhci_frame_timer(void *opaque) if (!(s->cmd & UHCI_CMD_RS)) { qemu_del_timer(s->frame_timer); + /* set hchalted bit in status - UHCI11D 2.1.2 */ + s->status |= UHCI_STS_HCHALTED; return; } frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); -- cgit v1.2.3 From fd06c37550b43980e8d641bb109c219cbe001d13 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 24 Apr 2006 21:58:30 +0000 Subject: PC speaker emulation (Joachim Henke) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1851 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 2 +- hw/i8254.c | 12 +++++ hw/pc.c | 20 +------- hw/pcspk.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 9 ++++ vl.h | 6 +++ 7 files changed, 177 insertions(+), 20 deletions(-) create mode 100644 hw/pcspk.c diff --git a/Changelog b/Changelog index d07a7ebb7..871d8fcd6 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,7 @@ version 0.8.1: - USB tablet support (Brad Campbell, Anthony Liguori) - win32 host serial support (Kazu) + - PC speaker support (Joachim Henke) version 0.8.0: diff --git a/Makefile.target b/Makefile.target index be2fcfe4a..bbb755d2d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -310,7 +310,7 @@ VL_OBJS+= ne2000.o rtl8139.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 pc.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o DEFINES += -DHAS_AUDIO endif diff --git a/hw/i8254.c b/hw/i8254.c index 6f0516827..a4097632e 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -209,6 +209,18 @@ int pit_get_gate(PITState *pit, int channel) return s->gate; } +int pit_get_initial_count(PITState *pit, int channel) +{ + PITChannelState *s = &pit->channels[channel]; + return s->count; +} + +int pit_get_mode(PITState *pit, int channel) +{ + PITChannelState *s = &pit->channels[channel]; + return s->mode; +} + static inline void pit_load_count(PITChannelState *s, int val) { if (val == 0) diff --git a/hw/pc.c b/hw/pc.c index fb8f87032..38c75d471 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -36,8 +36,6 @@ #define KERNEL_PARAMS_ADDR 0x00090000 #define KERNEL_CMDLINE_ADDR 0x00099000 -int speaker_data_on; -int dummy_refresh_clock; static fdctrl_t *floppy_controller; static RTCState *rtc_state; static PITState *pit; @@ -273,21 +271,6 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table // rtc_set_memory(s, 0x38, 1); } -static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - speaker_data_on = (val >> 1) & 1; - pit_set_gate(pit, 2, val & 1); -} - -static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) -{ - int out; - out = pit_get_out(pit, 2, qemu_get_clock(vm_clock)); - dummy_refresh_clock ^= 1; - return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | - (dummy_refresh_clock << 4); -} - void ioport_set_a20(int enable) { /* XXX: send to all CPUs ? */ @@ -783,8 +766,6 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } rtc_state = rtc_init(0x70, 8); - register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); - register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); register_ioport_read(0x92, 1, 1, ioport92_read, NULL); register_ioport_write(0x92, 1, 1, ioport92_write, NULL); @@ -794,6 +775,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } isa_pic = pic_init(pic_irq_request, first_cpu); pit = pit_init(0x40, 0); + pcspk_init(pit); if (pci_enabled) { pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); } diff --git a/hw/pcspk.c b/hw/pcspk.c new file mode 100644 index 000000000..2e30662a2 --- /dev/null +++ b/hw/pcspk.c @@ -0,0 +1,147 @@ +/* + * QEMU PC speaker emulation + * + * Copyright (c) 2006 Joachim Henke + * + * 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 PCSPK_BUF_LEN 1792 +#define PCSPK_SAMPLE_RATE 32000 +#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1) +#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ) + +typedef struct { + uint8_t sample_buf[PCSPK_BUF_LEN]; + QEMUSoundCard card; + SWVoiceOut *voice; + PITState *pit; + unsigned int pit_count; + unsigned int samples; + unsigned int play_pos; + int data_on; + int dummy_refresh_clock; +} PCSpkState; + +static const char *s_spk = "pcspk"; +static PCSpkState pcspk_state; + +static inline void generate_samples(PCSpkState *s) +{ + unsigned int i; + + if (s->pit_count) { + const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count; + const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m; + + /* multiple of wavelength for gapless looping */ + s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1; + for (i = 0; i < s->samples; ++i) + s->sample_buf[i] = (64 & (n * i >> 25)) - 32; + } else { + s->samples = PCSPK_BUF_LEN; + for (i = 0; i < PCSPK_BUF_LEN; ++i) + s->sample_buf[i] = 128; /* silence */ + } +} + +static void pcspk_callback(void *opaque, int free) +{ + PCSpkState *s = opaque; + unsigned int n; + + if (pit_get_mode(s->pit, 2) != 3) + return; + + n = pit_get_initial_count(s->pit, 2); + /* avoid frequencies that are not reproducible with sample rate */ + if (n < PCSPK_MIN_COUNT) + n = 0; + + if (s->pit_count != n) { + s->pit_count = n; + s->play_pos = 0; + generate_samples(s); + } + + while (free > 0) { + n = audio_MIN(s->samples - s->play_pos, (unsigned int)free); + n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n); + if (!n) + break; + s->play_pos = (s->play_pos + n) % s->samples; + free -= n; + } +} + +int pcspk_audio_init(AudioState *audio) +{ + PCSpkState *s = &pcspk_state; + audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8}; + + if (!audio) { + AUD_log(s_spk, "No audio state\n"); + return -1; + } + AUD_register_card(audio, s_spk, &s->card); + + s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as, 0); + if (!s->voice) { + AUD_log(s_spk, "Could not open voice\n"); + return -1; + } + + return 0; +} + +static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr) +{ + PCSpkState *s = opaque; + int out; + + s->dummy_refresh_clock ^= (1 << 4); + out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5; + + return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out; +} + +static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + PCSpkState *s = opaque; + const int gate = val & 1; + + s->data_on = (val >> 1) & 1; + pit_set_gate(s->pit, 2, gate); + if (s->voice) { + if (gate) /* restart */ + s->play_pos = 0; + AUD_set_active_out(s->voice, gate & s->data_on); + } +} + +void pcspk_init(PITState *pit) +{ + PCSpkState *s = &pcspk_state; + + s->pit = pit; + register_ioport_read(0x61, 1, 1, pcspk_ioport_read, s); + register_ioport_write(0x61, 1, 1, pcspk_ioport_write, s); +} diff --git a/vl.c b/vl.c index 36b7e24fe..3b83ed2f2 100644 --- a/vl.c +++ b/vl.c @@ -4862,6 +4862,15 @@ void register_machines(void) #ifdef HAS_AUDIO struct soundhw soundhw[] = { +#ifdef TARGET_I386 + { + "pcspk", + "PC speaker", + 0, + 1, + { .init_isa = pcspk_audio_init } + }, +#endif { "sb16", "Creative Sound Blaster 16", diff --git a/vl.h b/vl.h index 72381ec8f..964ca8a8f 100644 --- a/vl.h +++ b/vl.h @@ -819,8 +819,14 @@ typedef struct PITState PITState; PITState *pit_init(int base, int irq); void pit_set_gate(PITState *pit, int channel, int val); int pit_get_gate(PITState *pit, int channel); +int pit_get_initial_count(PITState *pit, int channel); +int pit_get_mode(PITState *pit, int channel); int pit_get_out(PITState *pit, int channel, int64_t current_time); +/* pcspk.c */ +void pcspk_init(PITState *); +int pcspk_audio_init(AudioState *); + /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; -- cgit v1.2.3 From 467d409f7e7b30da22497fdcd6fe45f1369eed74 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 25 Apr 2006 21:01:19 +0000 Subject: fix for HCHALTED status bit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1852 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 10b3fa6fd..23964f36a 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -175,7 +175,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) /* start frame processing */ qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock)); s->status &= ~UHCI_STS_HCHALTED; - } else if (!(val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { + } else if (!(val & UHCI_CMD_RS)) { s->status |= UHCI_STS_HCHALTED; } if (val & UHCI_CMD_GRESET) { -- cgit v1.2.3 From c2ff060fd4c7389de2016442e3327538a66696bd Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 25 Apr 2006 21:24:22 +0000 Subject: LBA48 support (Jens Axboe) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1853 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 137 insertions(+), 20 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index decf34582..64b026d7f 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -307,14 +307,24 @@ typedef struct IDEState { /* ide regs */ uint8_t feature; uint8_t error; - uint16_t nsector; /* 0 is 256 to ease computations */ + uint32_t nsector; uint8_t sector; uint8_t lcyl; uint8_t hcyl; + /* other part of tf for lba48 support */ + uint8_t hob_feature; + uint8_t hob_nsector; + uint8_t hob_sector; + uint8_t hob_lcyl; + uint8_t hob_hcyl; + uint8_t select; uint8_t status; + /* 0x3f6 command, only meaningful for drive 0 */ uint8_t cmd; + /* set for lba48 access */ + uint8_t lba48; /* depends on bit 4 in select, only meaningful for drive 0 */ struct IDEState *cur_drive; BlockDriverState *bs; @@ -463,13 +473,19 @@ static void ide_identify(IDEState *s) put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ put_le16(p + 81, 0x16); /* conforms to ata5 */ put_le16(p + 82, (1 << 14)); - put_le16(p + 83, (1 << 14)); + /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ + put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); put_le16(p + 84, (1 << 14)); put_le16(p + 85, (1 << 14)); - put_le16(p + 86, 0); + /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ + put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); put_le16(p + 87, (1 << 14)); put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ put_le16(p + 93, 1 | (1 << 14) | 0x2000); + put_le16(p + 100, s->nb_sectors); + put_le16(p + 101, s->nb_sectors >> 16); + put_le16(p + 102, s->nb_sectors >> 32); + put_le16(p + 103, s->nb_sectors >> 48); memcpy(s->identify_data, p, sizeof(s->identify_data)); s->identify_set = 1; @@ -573,12 +589,19 @@ static int64_t ide_get_sector(IDEState *s) int64_t sector_num; if (s->select & 0x40) { /* lba */ - sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | - (s->lcyl << 8) | s->sector; + if (!s->lba48) { + sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | + (s->lcyl << 8) | s->sector; + } else { + sector_num = ((int64_t)s->hob_hcyl << 40) | + ((int64_t) s->hob_lcyl << 32) | + ((int64_t) s->hob_sector << 24) | + ((int64_t) s->hcyl << 16) | + ((int64_t) s->lcyl << 8) | s->sector; + } } else { sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors + - (s->select & 0x0f) * s->sectors + - (s->sector - 1); + (s->select & 0x0f) * s->sectors + (s->sector - 1); } return sector_num; } @@ -587,10 +610,19 @@ static void ide_set_sector(IDEState *s, int64_t sector_num) { unsigned int cyl, r; if (s->select & 0x40) { - s->select = (s->select & 0xf0) | (sector_num >> 24); - s->hcyl = (sector_num >> 16); - s->lcyl = (sector_num >> 8); - s->sector = (sector_num); + if (!s->lba48) { + s->select = (s->select & 0xf0) | (sector_num >> 24); + s->hcyl = (sector_num >> 16); + s->lcyl = (sector_num >> 8); + s->sector = (sector_num); + } else { + s->sector = sector_num; + s->lcyl = sector_num >> 8; + s->hcyl = sector_num >> 16; + s->hob_sector = sector_num >> 24; + s->hob_lcyl = sector_num >> 32; + s->hob_hcyl = sector_num >> 40; + } } else { cyl = sector_num / (s->heads * s->sectors); r = sector_num % (s->heads * s->sectors); @@ -1488,43 +1520,89 @@ static void cdrom_change_cb(void *opaque) s->nb_sectors = nb_sectors; } +static void ide_cmd_lba48_transform(IDEState *s, int lba48) +{ + s->lba48 = lba48; + + /* handle the 'magic' 0 nsector count conversion here. to avoid + * fiddling with the rest of the read logic, we just store the + * full sector count in ->nsector and ignore ->hob_nsector from now + */ + if (!s->lba48) { + if (!s->nsector) + s->nsector = 256; + } else { + if (!s->nsector && !s->hob_nsector) + s->nsector = 65536; + else { + int lo = s->nsector; + int hi = s->hob_nsector; + + s->nsector = (hi << 8) | lo; + } + } +} + +static void ide_clear_hob(IDEState *ide_if) +{ + /* any write clears HOB high bit of device control register */ + ide_if[0].select &= ~(1 << 7); + ide_if[1].select &= ~(1 << 7); +} + static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) { IDEState *ide_if = opaque; IDEState *s; int unit, n; + int lba48 = 0; #ifdef DEBUG_IDE printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); #endif + addr &= 7; switch(addr) { case 0: break; case 1: + ide_clear_hob(ide_if); /* NOTE: data is written to the two drives */ + ide_if[0].hob_feature = ide_if[0].feature; + ide_if[1].hob_feature = ide_if[1].feature; ide_if[0].feature = val; ide_if[1].feature = val; break; case 2: - if (val == 0) - val = 256; + ide_clear_hob(ide_if); + ide_if[0].hob_nsector = ide_if[0].nsector; + ide_if[1].hob_nsector = ide_if[1].nsector; ide_if[0].nsector = val; ide_if[1].nsector = val; break; case 3: + ide_clear_hob(ide_if); + ide_if[0].hob_sector = ide_if[0].sector; + ide_if[1].hob_sector = ide_if[1].sector; ide_if[0].sector = val; ide_if[1].sector = val; break; case 4: + ide_clear_hob(ide_if); + ide_if[0].hob_lcyl = ide_if[0].lcyl; + ide_if[1].hob_lcyl = ide_if[1].lcyl; ide_if[0].lcyl = val; ide_if[1].lcyl = val; break; case 5: + ide_clear_hob(ide_if); + ide_if[0].hob_hcyl = ide_if[0].hcyl; + ide_if[1].hob_hcyl = ide_if[1].hcyl; ide_if[0].hcyl = val; ide_if[1].hcyl = val; break; case 6: + /* FIXME: HOB readback uses bit 7 */ ide_if[0].select = (val & ~0x10) | 0xa0; ide_if[1].select = (val | 0x10) | 0xa0; /* select drive */ @@ -1542,6 +1620,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* ignore commands to non existant slave */ if (s != ide_if && !s->bs) break; + switch(val) { case WIN_IDENTIFY: if (s->bs && !s->is_cdrom) { @@ -1573,35 +1652,50 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) } ide_set_irq(s); break; + case WIN_VERIFY_EXT: + lba48 = 1; case WIN_VERIFY: case WIN_VERIFY_ONCE: /* do sector number check ? */ + ide_cmd_lba48_transform(s, lba48); s->status = READY_STAT; ide_set_irq(s); break; + case WIN_READ_EXT: + lba48 = 1; case WIN_READ: case WIN_READ_ONCE: if (!s->bs) goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); s->req_nb_sectors = 1; ide_sector_read(s); break; + case WIN_WRITE_EXT: + lba48 = 1; case WIN_WRITE: case WIN_WRITE_ONCE: + ide_cmd_lba48_transform(s, lba48); s->error = 0; s->status = SEEK_STAT | READY_STAT; s->req_nb_sectors = 1; ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); break; + case WIN_MULTREAD_EXT: + lba48 = 1; case WIN_MULTREAD: if (!s->mult_sectors) goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); s->req_nb_sectors = s->mult_sectors; ide_sector_read(s); break; + case WIN_MULTWRITE_EXT: + lba48 = 1; case WIN_MULTWRITE: if (!s->mult_sectors) goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); s->error = 0; s->status = SEEK_STAT | READY_STAT; s->req_nb_sectors = s->mult_sectors; @@ -1610,19 +1704,28 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) n = s->req_nb_sectors; ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); break; + case WIN_READDMA_EXT: + lba48 = 1; case WIN_READDMA: case WIN_READDMA_ONCE: if (!s->bs) goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); ide_sector_read_dma(s); break; + case WIN_WRITEDMA_EXT: + lba48 = 1; case WIN_WRITEDMA: case WIN_WRITEDMA_ONCE: if (!s->bs) goto abort_cmd; + ide_cmd_lba48_transform(s, lba48); ide_sector_write_dma(s); break; + case WIN_READ_NATIVE_MAX_EXT: + lba48 = 1; case WIN_READ_NATIVE_MAX: + ide_cmd_lba48_transform(s, lba48); ide_set_sector(s, s->nb_sectors - 1); s->status = READY_STAT; ide_set_irq(s); @@ -1672,9 +1775,10 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) goto abort_cmd; } break; + case WIN_FLUSH_CACHE: + case WIN_FLUSH_CACHE_EXT: case WIN_STANDBYNOW1: case WIN_IDLEIMMEDIATE: - case WIN_FLUSH_CACHE: s->status = READY_STAT; ide_set_irq(s); break; @@ -1726,9 +1830,12 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) IDEState *ide_if = opaque; IDEState *s = ide_if->cur_drive; uint32_t addr; - int ret; + int ret, hob; addr = addr1 & 7; + /* FIXME: HOB readback uses bit 7, but it's always set right now */ + //hob = s->select & (1 << 7); + hob = 0; switch(addr) { case 0: ret = 0xff; @@ -1736,32 +1843,42 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) case 1: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; - else + else if (!hob) ret = s->error; + else + ret = s->hob_feature; break; case 2: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; - else + else if (!hob) ret = s->nsector & 0xff; + else + ret = s->hob_nsector; break; case 3: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; - else + else if (!hob) ret = s->sector; + else + ret = s->hob_sector; break; case 4: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; - else + else if (!hob) ret = s->lcyl; + else + ret = s->hob_lcyl; break; case 5: if (!ide_if[0].bs && !ide_if[1].bs) ret = 0; - else + else if (!hob) ret = s->hcyl; + else + ret = s->hob_hcyl; break; case 6: if (!ide_if[0].bs && !ide_if[1].bs) -- cgit v1.2.3 From 96b74a0221a7d552a4b3016af2b8bc87628fdab3 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 25 Apr 2006 21:27:42 +0000 Subject: enable APIC by default git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1854 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 5195fa3d3..9d5d9b564 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -110,6 +110,7 @@ CPUX86State *cpu_x86_init(void) env->pat = 0x0007040600070406ULL; env->cpuid_ext_features = CPUID_EXT_SSE3; env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP; + env->cpuid_features |= CPUID_APIC; env->cpuid_xlevel = 0; { const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION; @@ -125,7 +126,6 @@ CPUX86State *cpu_x86_init(void) } #ifdef TARGET_X86_64 /* currently not enabled for std i386 because not fully tested */ - env->cpuid_features |= CPUID_APIC; env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF); env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX; env->cpuid_xlevel = 0x80000008; -- cgit v1.2.3 From ec530c81efea6ddb1f75758658fd6769a29c3ade Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 25 Apr 2006 22:36:06 +0000 Subject: Solaris port (Ben Taylor) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1855 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 ++++ block.c | 20 ++++++++++++- configure | 80 ++++++++++++++++++++++++++++++++++++++++++++++++-- dyngen-exec.h | 14 +++++++++ fpu/softfloat-native.h | 3 ++ fpu/softfloat.h | 2 +- slirp/slirp_config.h | 3 ++ slirp/socket.c | 3 ++ vl.c | 8 +++++ 9 files changed, 134 insertions(+), 4 deletions(-) diff --git a/Makefile.target b/Makefile.target index bbb755d2d..031515346 100644 --- a/Makefile.target +++ b/Makefile.target @@ -166,6 +166,9 @@ endif ifdef CONFIG_WIN32 LIBS+=-lwinmm -lws2_32 -liphlpapi endif +ifdef CONFIG_SOLARIS +LIBS+=-lsocket -lnsl -lresolv +endif # profiling code ifdef TARGET_GPROF @@ -369,9 +372,11 @@ 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: CFLAGS+=-p VL_LDFLAGS+=-p diff --git a/block.c b/block.c index 6924cee67..b90816718 100644 --- a/block.c +++ b/block.c @@ -44,6 +44,10 @@ #include #endif +#ifdef __sun__ +#include +#endif + static BlockDriverState *bdrv_first; static BlockDriver *first_drv; @@ -648,7 +652,6 @@ void bdrv_info(void) } } - /**************************************************************/ /* RAW block driver */ @@ -669,6 +672,10 @@ static int raw_open(BlockDriverState *bs, const char *filename) #ifdef _BSD struct stat sb; #endif +#ifdef __sun__ + struct dk_minfo minfo; + int rv; +#endif fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); if (fd < 0) { @@ -688,6 +695,17 @@ static int raw_open(BlockDriverState *bs, const char *filename) 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); diff --git a/configure b/configure index 120e03d7b..cae6f6ea9 100755 --- a/configure +++ b/configure @@ -125,6 +125,9 @@ Darwin) bsd="yes" darwin="yes" ;; +SunOS) +solaris="yes" +;; *) oss="yes" linux="yes" @@ -141,6 +144,15 @@ if [ "$bsd" = "yes" ] ; then fi fi +if [ "$solaris" = "yes" ] ; then + make="gmake" + install="ginstall" + solarisrev=`uname -r | cut -f2 -d.` + if test $solarisrev -lt 10 ; then + presolaris10="yes" + fi +fi + # find source path source_path=`dirname "$0"` if [ -z "$source_path" ]; then @@ -299,6 +311,57 @@ if test "$mingw32" = "yes" ; then 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 + soltexi2html=`which texi2html 2> /dev/null | /usr/bin/grep -v "no texi2html in"` + if test -z "$soltexi2html" ; then + echo "Error: No path includes texi2html." + if test -f /usr/sfw/bin/texi2html ; then + echo "Add /usr/sfw/bin to your path and rerun configure" + else + echo "Add the directory holding the texi2html to your path and rerun configure" + fi + 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 @@ -585,6 +648,12 @@ 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 + if test "$presolaris10" = "yes" ; then + echo "#define _PRESOLARIS10 1" >> $config_h + fi +fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak echo "#define CONFIG_GDBSTUB 1" >> $config_h @@ -690,7 +759,12 @@ if test "$target_user_only" = "no" ; then mkdir -p $target_dir/slirp fi -ln -sf $source_path/Makefile.target $target_dir/Makefile +# +# 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 @@ -802,8 +876,10 @@ if test "$source_path_used" = "yes" ; then 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 - ln -sf $source_path/$f $f + rm -f $f + ln -s $source_path/$f $f done fi diff --git a/dyngen-exec.h b/dyngen-exec.h index 946347d6c..6952c3a2c 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -20,6 +20,13 @@ #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. */ @@ -35,7 +42,12 @@ typedef unsigned long uint64_t; typedef unsigned long long uint64_t; #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; #if defined (__x86_64__) || defined(__ia64) @@ -231,6 +243,8 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __sparc__ #define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \ "nop") +#define GOTO_LABEL_PARAM(n) asm volatile ( \ + "set " ASM_NAME(__op_gen_label) #n ", %g1; jmp %g1; nop") #endif #ifdef __arm__ #define EXIT_TB() asm volatile ("b exec_loop") diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 9017ea582..6f3b6a98a 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -3,8 +3,11 @@ #if defined(_BSD) && !defined(__APPLE__) #include #else +#if !defined(_PRESOLARIS10) #include #endif +#endif +#include "gnu-c99-math.h" typedef float float32; typedef double float64; diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 666d6a017..fdc80f32d 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -177,7 +177,7 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM); | Routine to raise any or all of the software IEC/IEEE floating-point | exception flags. *----------------------------------------------------------------------------*/ -void float_raise( signed char STATUS_PARAM); +void float_raise( int8 flags STATUS_PARAM); /*---------------------------------------------------------------------------- | Software IEC/IEEE integer-to-floating-point conversion routines. diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h index a0795ef6b..e7e95dd5a 100644 --- a/slirp/slirp_config.h +++ b/slirp/slirp_config.h @@ -138,6 +138,9 @@ /* Define if you don't have u_int32_t etc. typedef'd */ #undef NEED_TYPEDEFS +#ifdef __sun__ +#define NEED_TYPEDEFS +#endif /* Define to sizeof(char) */ #define SIZEOF_CHAR 1 diff --git a/slirp/socket.c b/slirp/socket.c index fbd9e960d..ce6528fc4 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -9,6 +9,9 @@ #include #include "ip_icmp.h" #include "main.h" +#ifdef __sun__ +#include +#endif void so_init() diff --git a/vl.c b/vl.c index 3b83ed2f2..8b6b33ce9 100644 --- a/vl.c +++ b/vl.c @@ -47,6 +47,7 @@ #include #endif #else +#ifndef __sun__ #include #include #include @@ -55,6 +56,7 @@ #include #endif #endif +#endif #if defined(CONFIG_SLIRP) #include "libslirp.h" @@ -2531,6 +2533,12 @@ static int tap_open(char *ifname, int ifname_size) fcntl(fd, F_SETFL, O_NONBLOCK); return fd; } +#elif defined(__sun__) +static int tap_open(char *ifname, int ifname_size) +{ + fprintf(stderr, "warning: tap_open not yet implemented\n"); + return -1; +} #else static int tap_open(char *ifname, int ifname_size) { -- cgit v1.2.3 From a8ca632cc08d88213635af84830c98e2473c7d04 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 25 Apr 2006 22:36:31 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1856 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index 871d8fcd6..fb28ee0c1 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,9 @@ 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) version 0.8.0: -- cgit v1.2.3 From 3598ecb6206a49ce8bf104e445fead6875b0050d Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 26 Apr 2006 15:55:55 +0000 Subject: Remove missing include. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1857 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 6f3b6a98a..a246eaf16 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -7,7 +7,6 @@ #include #endif #endif -#include "gnu-c99-math.h" typedef float float32; typedef double float64; -- cgit v1.2.3 From 94ac51588972366287fa359a1e7d37b5e08f9bef Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 26 Apr 2006 16:07:35 +0000 Subject: Solaris configure hacks. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1858 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/configure b/configure index cae6f6ea9..07c373848 100755 --- a/configure +++ b/configure @@ -51,7 +51,7 @@ case "$cpu" in s390) cpu="s390" ;; - sparc) + sparc|sun4[muv]) cpu="sparc" ;; sparc64) @@ -296,7 +296,7 @@ cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" -if [ -z `which $cc` ] ; then +if [ ! -x "`which $cc`" ] ; then echo "Compiler $cc could not be found" exit fi @@ -341,16 +341,6 @@ if test "$solaris" = "yes" ; then echo "using pkg-get -i fileutils, or use --install=/usr/ucb/install" exit 1 fi - soltexi2html=`which texi2html 2> /dev/null | /usr/bin/grep -v "no texi2html in"` - if test -z "$soltexi2html" ; then - echo "Error: No path includes texi2html." - if test -f /usr/sfw/bin/texi2html ; then - echo "Add /usr/sfw/bin to your path and rerun configure" - else - echo "Add the directory holding the texi2html to your path and rerun configure" - fi - 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" @@ -492,7 +482,7 @@ fi # cross compilation fi # -z $sdl # Check if tools are available to build documentation. -if [ ! -z `which texi2html` ] && [ ! -z `which pod2man` ]; then +if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then build_docs="yes" fi -- cgit v1.2.3 From 9ee3c029425a20ed16831c92c4cb3e192a909a61 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 Apr 2006 22:05:26 +0000 Subject: added entry parameter to ELF loader git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1859 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf_ops.h | 13 ++++++++++--- hw/sun4m.c | 4 ++-- hw/sun4u.c | 4 ++-- loader.c | 7 ++++--- vl.h | 2 +- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/elf_ops.h b/elf_ops.h index a7d027e1a..4da755e1b 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -138,13 +138,14 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) return -1; } -int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, int must_swab) +int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, + int must_swab, uint64_t *pentry) { struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; elf_word mem_size, addr; - uint8_t *data; + uint8_t *data = NULL; if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) goto fail; @@ -152,6 +153,9 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, int must_swab) glue(bswap_ehdr, SZ)(&ehdr); } + if (pentry) + *pentry = (uint64_t)ehdr.e_entry; + glue(load_symbols, SZ)(&ehdr, fd, must_swab); size = ehdr.e_phnum * sizeof(phdr[0]); @@ -176,7 +180,8 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, int must_swab) /* XXX: avoid allocating */ data = qemu_mallocz(mem_size); if (ph->p_filesz > 0) { - lseek(fd, ph->p_offset, SEEK_SET); + if (lseek(fd, ph->p_offset, SEEK_SET) < 0) + goto fail; if (read(fd, data, ph->p_filesz) != ph->p_filesz) goto fail; } @@ -187,10 +192,12 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, int must_swab) total_size += mem_size; qemu_free(data); + data = NULL; } } return total_size; fail: + qemu_free(data); qemu_free(phdr); return -1; } diff --git a/hw/sun4m.c b/hw/sun4m.c index 014ed0926..3619005d7 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -269,7 +269,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); - ret = load_elf(buf, 0); + ret = load_elf(buf, 0, NULL); if (ret < 0) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); ret = load_image(buf, phys_ram_base + prom_offset); @@ -282,7 +282,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, kernel_size = 0; if (linux_boot) { - kernel_size = load_elf(kernel_filename, -0xf0000000); + kernel_size = load_elf(kernel_filename, -0xf0000000, NULL); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) diff --git a/hw/sun4u.c b/hw/sun4u.c index bb40697c4..208d3dd63 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -283,7 +283,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); - ret = load_elf(buf, 0); + ret = load_elf(buf, 0, NULL); if (ret < 0) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); ret = load_image(buf, phys_ram_base + prom_offset); @@ -298,7 +298,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, initrd_size = 0; if (linux_boot) { /* XXX: put correct offset */ - kernel_size = load_elf(kernel_filename, 0); + kernel_size = load_elf(kernel_filename, 0, NULL); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) diff --git a/loader.c b/loader.c index c4bde55c1..b2d6423fe 100644 --- a/loader.c +++ b/loader.c @@ -194,7 +194,8 @@ static void *load_at(int fd, int offset, int size) #include "elf_ops.h" /* return < 0 if error, otherwise the number of bytes loaded in memory */ -int load_elf(const char *filename, int64_t virt_to_phys_addend) +int load_elf(const char *filename, int64_t virt_to_phys_addend, + uint64_t *pentry) { int fd, data_order, must_swab, ret; uint8_t e_ident[EI_NIDENT]; @@ -220,9 +221,9 @@ int load_elf(const char *filename, int64_t virt_to_phys_addend) lseek(fd, 0, SEEK_SET); if (e_ident[EI_CLASS] == ELFCLASS64) { - ret = load_elf64(fd, virt_to_phys_addend, must_swab); + ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry); } else { - ret = load_elf32(fd, virt_to_phys_addend, must_swab); + ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry); } close(fd); diff --git a/vl.h b/vl.h index 964ca8a8f..fdf8c6867 100644 --- a/vl.h +++ b/vl.h @@ -878,7 +878,7 @@ void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); /* loader.c */ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); -int load_elf(const char *filename, int64_t virt_to_phys_addend); +int load_elf(const char *filename, int64_t virt_to_phys_addend, uint64_t *pentry); int load_aout(const char *filename, uint8_t *addr); /* slavio_timer.c */ -- cgit v1.2.3 From 66a93e0f47fa9869178008c7bc38d66a7c5e45f4 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 26 Apr 2006 22:06:55 +0000 Subject: ELF loader (Thiemo Seufer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1860 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 80 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index eaaaad284..6b6b6cb33 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -5,6 +5,8 @@ #define KERNEL_LOAD_ADDR 0x80010000 #define INITRD_LOAD_ADDR 0x80800000 +#define VIRT_TO_PHYS_ADDEND (-0x80000000LL) + extern FILE *logfile; static PITState *pit; @@ -101,6 +103,7 @@ void cpu_mips_clock_init (CPUState *env) cpu_mips_update_count(env, 1, 0); } + static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { #if 0 @@ -189,72 +192,71 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; - target_ulong kernel_base, kernel_size, initrd_base, initrd_size; + int64_t entry = 0; unsigned long bios_offset; int io_memory; - int linux_boot; int ret; CPUState *env; - - printf("%s: start\n", __func__); - linux_boot = (kernel_filename != NULL); + long kernel_size; env = cpu_init(); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + /* Try to load a BIOS image. If this fails, we continue regardless, + but initialize the hardware ourselves. When a kernel gets + preloaded we also initialize the hardware, since the BIOS wasn't + run. */ bios_offset = ram_size + vga_ram_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE); ret = load_image(buf, phys_ram_base + bios_offset); - if (ret != BIOS_SIZE) { - fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf); - exit(1); + if (ret == BIOS_SIZE) { + cpu_register_physical_memory((uint32_t)(0x1fc00000), + BIOS_SIZE, bios_offset | IO_MEM_ROM); + env->PC = 0xBFC00000; + if (!kernel_filename) + return; + } else { + /* not fatal */ + fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", + buf); } - cpu_register_physical_memory((uint32_t)(0x1fc00000), - BIOS_SIZE, bios_offset | IO_MEM_ROM); -#if 0 - memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE); - env->PC = 0x80010004; -#else - env->PC = 0xBFC00004; -#endif - if (linux_boot) { - kernel_base = KERNEL_LOAD_ADDR; - /* now we can load the kernel */ - kernel_size = load_image(kernel_filename, - phys_ram_base + (kernel_base - 0x80000000)); - if (kernel_size == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } + + kernel_size = 0; + if (kernel_filename) { + kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); + if (kernel_size >= 0) + env->PC = entry; + else { + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + env->PC = KERNEL_LOAD_ADDR; + } + /* load initrd */ if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; - initrd_size = load_image(initrd_filename, - phys_ram_base + initrd_base); - if (initrd_size == (target_ulong) -1) { + if (load_image(initrd_filename, + phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND) + == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } - } else { - initrd_base = 0; - initrd_size = 0; } - env->PC = KERNEL_LOAD_ADDR; + /* Store command line. */ strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); /* FIXME: little endian support */ *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); - } else { - kernel_base = 0; - kernel_size = 0; - initrd_base = 0; - initrd_size = 0; } /* Init internal devices */ -- cgit v1.2.3 From fdf9b3e831e8e6b5ceb2a44c742da7d1ab558242 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 27 Apr 2006 21:07:38 +0000 Subject: sh4 target (Samuel Tardieu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1861 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 20 + configure | 6 +- cpu-all.h | 7 + cpu-exec.c | 63 ++ dis-asm.h | 15 +- disas.c | 5 +- exec-all.h | 2 + gdbstub.c | 43 + linux-user/elfload.c | 24 + linux-user/main.c | 41 + linux-user/sh4/syscall.h | 12 + linux-user/sh4/syscall_nr.h | 292 ++++++ linux-user/sh4/termbits.h | 274 ++++++ linux-user/syscall.c | 5 + linux-user/syscall_defs.h | 6 +- sh4-dis.c | 2096 +++++++++++++++++++++++++++++++++++++++++++ softmmu_header.h | 4 + target-sh4/cpu.h | 138 +++ target-sh4/exec.h | 75 ++ target-sh4/helper.c | 398 ++++++++ target-sh4/op.c | 882 ++++++++++++++++++ target-sh4/op_helper.c | 372 ++++++++ target-sh4/op_mem.c | 58 ++ target-sh4/translate.c | 1073 ++++++++++++++++++++++ 24 files changed, 5905 insertions(+), 6 deletions(-) create mode 100644 linux-user/sh4/syscall.h create mode 100644 linux-user/sh4/syscall_nr.h create mode 100644 linux-user/sh4/termbits.h create mode 100644 sh4-dis.c create mode 100644 target-sh4/cpu.h create mode 100644 target-sh4/exec.h create mode 100644 target-sh4/helper.c create mode 100644 target-sh4/op.c create mode 100644 target-sh4/op_helper.c create mode 100644 target-sh4/op_mem.c create mode 100644 target-sh4/translate.c diff --git a/Makefile.target b/Makefile.target index 031515346..6c2bd35cd 100644 --- a/Makefile.target +++ b/Makefile.target @@ -225,6 +225,10 @@ ifeq ($(TARGET_BASE_ARCH), arm) LIBOBJS+= op_helper.o helper.o endif +ifeq ($(TARGET_BASE_ARCH), sh4) +LIBOBJS+= op_helper.o helper.o +endif + # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) @@ -254,6 +258,9 @@ 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 @@ -341,6 +348,9 @@ ifeq ($(TARGET_BASE_ARCH), arm) VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o VL_OBJS+= pl011.o pl050.o pl080.o pl110.o pl190.o 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 @@ -462,6 +472,16 @@ 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.h sh7750_regs.h sh7750_regnames.h cpu.h +shix.o: shix.c sh7750.h sh7750_regs.h sh7750_regnames.h tc58128.h +sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h +tc58128.o: tc58128.c tc58128.h sh7750.h +endif + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< diff --git a/configure b/configure index 07c373848..92632e24d 100755 --- a/configure +++ b/configure @@ -359,7 +359,7 @@ if test -z "$target_list" ; then 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 $target_list" + target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user sh4-user $target_list" fi else target_list=`echo "$target_list" | sed -e 's/,/ /g'` @@ -807,6 +807,10 @@ 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 +elif test "$target_cpu" = "sh4" ; then + echo "TARGET_ARCH=sh4" >> $config_mak + echo "#define TARGET_ARCH \"sh4\"" >> $config_h + echo "#define TARGET_SH4 1" >> $config_h else echo "Unsupported target CPU" exit 1 diff --git a/cpu-all.h b/cpu-all.h index 9abdf2a5e..ac65043d5 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -732,6 +732,13 @@ void page_unprotect_range(target_ulong data, target_ulong data_size); #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 diff --git a/cpu-exec.c b/cpu-exec.c index ca4695343..8a585c106 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -190,6 +190,10 @@ static inline TranslationBlock *tb_find_fast(void) flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK); 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 @@ -363,6 +367,8 @@ int cpu_exec(CPUState *env1) #endif #elif defined(TARGET_PPC) #elif defined(TARGET_MIPS) +#elif defined(TARGET_SH4) + /* XXXXX */ #else #error unsupported target CPU #endif @@ -407,6 +413,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env->exception_index); #elif defined(TARGET_ARM) do_interrupt(env); +#elif defined(TARGET_SH4) + do_interrupt(env); #endif } env->exception_index = -1; @@ -550,6 +558,8 @@ int cpu_exec(CPUState *env1) env->exception_index = EXCP_IRQ; do_interrupt(env); } +#elif defined(TARGET_SH4) + /* XXXXX */ #endif if (env->interrupt_request & CPU_INTERRUPT_EXITTB) { env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; @@ -608,6 +618,8 @@ int cpu_exec(CPUState *env1) 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 @@ -817,6 +829,8 @@ int cpu_exec(CPUState *env1) #endif #elif defined(TARGET_PPC) #elif defined(TARGET_MIPS) +#elif defined(TARGET_SH4) + /* XXXXX */ #else #error unsupported target CPU #endif @@ -1121,6 +1135,55 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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 (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; +} #else #error unsupported target CPU #endif diff --git a/dis-asm.h b/dis-asm.h index 9d28785bc..73b4380b7 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -163,10 +163,23 @@ enum bfd_architecture #define bfd_mach_z8002 2 bfd_arch_h8500, /* Hitachi H8/500 */ bfd_arch_sh, /* Hitachi SH */ -#define bfd_mach_sh 0 +#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 diff --git a/disas.c b/disas.c index f8281b512..c38da08fd 100644 --- a/disas.c +++ b/disas.c @@ -73,7 +73,7 @@ generic_print_address (addr, info) bfd_vma addr; struct disassemble_info *info; { - (*info->fprintf_func) (info->stream, "0x%llx", addr); + (*info->fprintf_func) (info->stream, "0x%llx", addr); } /* Just return the given address. */ @@ -194,6 +194,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #endif #elif defined(TARGET_M68K) print_insn = print_insn_m68k; +#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); diff --git a/exec-all.h b/exec-all.h index e4fc1d673..bc91f71ca 100644 --- a/exec-all.h +++ b/exec-all.h @@ -560,6 +560,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) is_user = (env->psrs == 0); #elif defined (TARGET_ARM) is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR); +#elif defined (TARGET_SH4) + is_user = ((env->sr & SR_MD) == 0); #else #error unimplemented CPU #endif diff --git a/gdbstub.c b/gdbstub.c index 8157160fd..bca9b1e2a 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -487,6 +487,45 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->PC = tswapl(*(uint32_t *)ptr); ptr += 4; } +#elif defined (TARGET_SH4) +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + uint32_t *ptr = (uint32_t *)mem_buf; + int i; + +#define SAVE(x) *ptr++=tswapl(x) + for (i = 0; i < 16; i++) SAVE(env->gregs[i]); + SAVE (env->pc); + SAVE (env->pr); + SAVE (env->gbr); + SAVE (env->vbr); + SAVE (env->mach); + SAVE (env->macl); + SAVE (env->sr); + SAVE (0); /* TICKS */ + SAVE (0); /* STALLS */ + SAVE (0); /* CYCLES */ + SAVE (0); /* INSTS */ + SAVE (0); /* PLR */ + + return ((uint8_t *)ptr - mem_buf); +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + uint32_t *ptr = (uint32_t *)mem_buf; + int i; + +#define LOAD(x) (x)=*ptr++; + for (i = 0; i < 16; i++) LOAD(env->gregs[i]); + LOAD (env->pc); + LOAD (env->pr); + LOAD (env->gbr); + LOAD (env->vbr); + LOAD (env->mach); + LOAD (env->macl); + LOAD (env->sr); +} #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { @@ -531,6 +570,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) env->npc = addr + 4; #elif defined (TARGET_ARM) env->regs[15] = addr; +#elif defined (TARGET_SH4) + env->pc = addr; #endif } #ifdef CONFIG_USER_ONLY @@ -551,6 +592,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) env->npc = addr + 4; #elif defined (TARGET_ARM) env->regs[15] = addr; +#elif defined (TARGET_SH4) + env->pc = addr; #endif } cpu_single_step(env, 1); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 14c00852a..98c6e3f85 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -274,6 +274,30 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif /* TARGET_MIPS */ +#ifdef TARGET_SH4 + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SH ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_SH + +#define ELF_PLAT_INIT(_r) /* XXXXX */ + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + /* Check other registers XXXXX */ + regs->pc = infop->entry; + regs->regs[15] = infop->start_stack - 16 * 4; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + #ifndef ELF_PLATFORM #define ELF_PLATFORM (NULL) #endif diff --git a/linux-user/main.c b/linux-user/main.c index 1f4720516..78f45a5f9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1387,6 +1387,38 @@ void cpu_loop(CPUMIPSState *env) } #endif +#ifdef TARGET_SH4 +void cpu_loop (CPUState *env) +{ + int trapnr, ret; + // target_siginfo_t info; + + while (1) { + trapnr = cpu_sh4_exec (env); + + switch (trapnr) { + case 0x160: + ret = do_syscall(env, + env->gregs[0x13], + env->gregs[0x14], + env->gregs[0x15], + env->gregs[0x16], + env->gregs[0x17], + env->gregs[0x10], + 0); + env->gregs[0x10] = ret; + env->pc += 2; + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + exit (1); + } + process_pending_signals (env); + } +} +#endif + void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n" @@ -1665,6 +1697,15 @@ int main(int argc, char **argv) } env->PC = regs->cp0_epc; } +#elif defined(TARGET_SH4) + { + int i; + + for(i = 0; i < 16; i++) { + env->gregs[i] = regs->regs[i]; + } + env->pc = regs->pc; + } #else #error unsupported target CPU #endif diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h new file mode 100644 index 000000000..014bf58fc --- /dev/null +++ b/linux-user/sh4/syscall.h @@ -0,0 +1,12 @@ +struct target_pt_regs { + unsigned long regs[16]; + unsigned long pc; + unsigned long pr; + unsigned long sr; + unsigned long gbr; + unsigned long mach; + unsigned long macl; + long tra; +}; + +#define UNAME_MACHINE "sh4" diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h new file mode 100644 index 000000000..c91ba1b3d --- /dev/null +++ b/linux-user/sh4/syscall_nr.h @@ -0,0 +1,292 @@ +/* + * This file contains the system call numbers. + */ + +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86old 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_vm86 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread64 180 +#define TARGET_NR_pwrite64 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 +#define TARGET_NR_streams1 188 /* some people actually want it */ +#define TARGET_NR_streams2 189 /* some people actually want it */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_pivot_root 217 +#define TARGET_NR_mincore 218 +#define TARGET_NR_madvise 219 +#define TARGET_NR_getdents64 220 +#define TARGET_NR_fcntl64 221 +/* 223 is unused */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_set_thread_area 243 +#define TARGET_NR_get_thread_area 244 +#define TARGET_NR_io_setup 245 +#define TARGET_NR_io_destroy 246 +#define TARGET_NR_io_getevents 247 +#define TARGET_NR_io_submit 248 +#define TARGET_NR_io_cancel 249 +#define TARGET_NR_fadvise64 250 + +#define TARGET_NR_exit_group 252 +#define TARGET_NR_lookup_dcookie 253 +#define TARGET_NR_epoll_create 254 +#define TARGET_NR_epoll_ctl 255 +#define TARGET_NR_epoll_wait 256 +#define TARGET_NR_remap_file_pages 257 +#define TARGET_NR_set_tid_address 258 +#define TARGET_NR_timer_create 259 +#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) +#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) +#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) +#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) +#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) +#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) +#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) +#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) +#define TARGET_NR_statfs64 268 +#define TARGET_NR_fstatfs64 269 +#define TARGET_NR_tgkill 270 +#define TARGET_NR_utimes 271 +#define TARGET_NR_fadvise64_64 272 +#define TARGET_NR_vserver 273 +#define TARGET_NR_mbind 274 +#define TARGET_NR_get_mempolicy 275 +#define TARGET_NR_set_mempolicy 276 +#define TARGET_NR_mq_open 277 +#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1) +#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2) +#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3) +#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4) +#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5) +#define TARGET_NR_sys_kexec_load 283 +#define TARGET_NR_waitid 284 +#define TARGET_NR_add_key 285 +#define TARGET_NR_request_key 286 +#define TARGET_NR_keyctl 287 + +#define TARGET_NR_readahead 225 /* XXXXX */ diff --git a/linux-user/sh4/termbits.h b/linux-user/sh4/termbits.h new file mode 100644 index 000000000..6dd5845bc --- /dev/null +++ b/linux-user/sh4/termbits.h @@ -0,0 +1,274 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* tcflow() and TCXONC use these */ +#define TARGET_TCOOFF 0 +#define TARGET_TCOON 1 +#define TARGET_TCIOFF 2 +#define TARGET_TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TARGET_TCIFLUSH 0 +#define TARGET_TCOFLUSH 1 +#define TARGET_TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TARGET_TCSANOW 0 +#define TARGET_TCSADRAIN 1 +#define TARGET_TARGET_TCSAFLUSH 2 + +/* ioctl */ +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA TARGET_IOR('t', 23, struct termio) +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) + +#define TARGET_TCSETA TARGET_IOW('t', 24, struct termio) +#define TARGET_TCSETAW TARGET_IOW('t', 25, struct termio) +#define TARGET_TCSETAF TARGET_IOW('t', 28, struct termio) +#define TARGET_TCSBRK TARGET_IO('t', 29) +#define TARGET_TCXONC TARGET_IO('t', 30) +#define TARGET_TCFLSH TARGET_IO('t', 31) + +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) +#define TARGET_TIOCEXCL TARGET_IO('T', 12) /* 0x540C */ +#define TARGET_TIOCNXCL TARGET_IO('T', 13) /* 0x540D */ +#define TARGET_TIOCSCTTY TARGET_IO('T', 14) /* 0x540E */ + +#define TARGET_TIOCSTI TARGET_IOW('T', 18, char) /* 0x5412 */ +#define TARGET_TIOCMGET TARGET_IOR('T', 21, unsigned int) /* 0x5415 */ +#define TARGET_TIOCMBIS TARGET_IOW('T', 22, unsigned int) /* 0x5416 */ +#define TARGET_TIOCMBIC TARGET_IOW('T', 23, unsigned int) /* 0x5417 */ +#define TARGET_TIOCMSET TARGET_IOW('T', 24, unsigned int) /* 0x5418 */ +#define TARGET_TIOCM_LE 0x001 +#define TARGET_TIOCM_DTR 0x002 +#define TARGET_TIOCM_RTS 0x004 +#define TARGET_TIOCM_ST 0x008 +#define TARGET_TIOCM_SR 0x010 +#define TARGET_TIOCM_CTS 0x020 +#define TARGET_TIOCM_CAR 0x040 +#define TARGET_TIOCM_RNG 0x080 +#define TARGET_TIOCM_DSR 0x100 +#define TARGET_TIOCM_CD TARGET_TIOCM_CAR +#define TARGET_TIOCM_RI TARGET_TIOCM_RNG + +#define TARGET_TIOCGSOFTCAR TARGET_IOR('T', 25, unsigned int) /* 0x5419 */ +#define TARGET_TIOCSSOFTCAR TARGET_IOW('T', 26, unsigned int) /* 0x541A */ +#define TARGET_TIOCLINUX TARGET_IOW('T', 28, char) /* 0x541C */ +#define TARGET_TIOCCONS TARGET_IO('T', 29) /* 0x541D */ +#define TARGET_TIOCGSERIAL TARGET_IOR('T', 30, int) /* 0x541E */ +#define TARGET_TIOCSSERIAL TARGET_IOW('T', 31, int) /* 0x541F */ +#define TARGET_TIOCPKT TARGET_IOW('T', 32, int) /* 0x5420 */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + + +#define TARGET_TIOCNOTTY TARGET_IO('T', 34) /* 0x5422 */ +#define TARGET_TIOCSETD TARGET_IOW('T', 35, int) /* 0x5423 */ +#define TARGET_TIOCGETD TARGET_IOR('T', 36, int) /* 0x5424 */ +#define TARGET_TCSBRKP TARGET_IOW('T', 37, int) /* 0x5425 */ /* Needed for POSIX tcse +ndbreak() */ +#define TARGET_TIOCSBRK TARGET_IO('T', 39) /* 0x5427 */ /* BSD compatibility */ +#define TARGET_TIOCCBRK TARGET_IO('T', 40) /* 0x5428 */ /* BSD compatibility */ +#define TARGET_TIOCGSID TARGET_IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session +ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-m +ux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + + +#define TARGET_TIOCSERCONFIG TARGET_IO('T', 83) /* 0x5453 */ +#define TARGET_TIOCSERGWILD TARGET_IOR('T', 84, int) /* 0x5454 */ +#define TARGET_TIOCSERSWILD TARGET_IOW('T', 85, int) /* 0x5455 */ +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT TARGET_IOR('T', 88, int) /* 0x5458 */ /* For d +ebugging only */ +#define TARGET_TIOCSERGETLSR TARGET_IOR('T', 89, unsigned int) /* 0x5459 */ /* Get line sta +tus register */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +# define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TARGET_TIOCSERGETMULTI TARGET_IOR('T', 90, int) /* 0x545A +*/ /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI TARGET_IOW('T', 91, int) /* 0x545B +*/ /* Set multiport config */ + +#define TARGET_TIOCMIWAIT TARGET_IO('T', 92) /* 0x545C */ /* wait for a change on +serial input line(s) */ +#define TARGET_TIOCGICOUNT TARGET_IOR('T', 93, int) /* 0x545D */ /* read +serial port inline interrupt counts */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c3b22ce72..7da469aa8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1618,6 +1618,11 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) for (i = 7; i < 32; i++) new_env->gpr[i] = 0; } +#elif defined(TARGET_SH4) + if (!newsp) + newsp = env->gregs[15]; + new_env->gregs[15] = newsp; + /* XXXXX */ #else #error unsupported target CPU #endif diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index c722e3a42..4e2dd17de 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -48,7 +48,7 @@ #define TARGET_IOC_NRBITS 8 #define TARGET_IOC_TYPEBITS 8 -#if defined(TARGET_I386) || defined(TARGET_ARM) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -293,7 +293,7 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) #if defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u @@ -863,7 +863,7 @@ struct target_winsize { #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ #endif -#if defined(TARGET_I386) || defined(TARGET_ARM) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) struct target_stat { unsigned short st_dev; unsigned short __pad1; diff --git a/sh4-dis.c b/sh4-dis.c new file mode 100644 index 000000000..5f45e5ed2 --- /dev/null +++ b/sh4-dis.c @@ -0,0 +1,2096 @@ +/* Disassemble SH instructions. + Copyright 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "dis-asm.h" + +#define DEFINE_TABLE + +typedef enum + { + HEX_0, + HEX_1, + HEX_2, + HEX_3, + HEX_4, + HEX_5, + HEX_6, + HEX_7, + HEX_8, + HEX_9, + HEX_A, + HEX_B, + HEX_C, + HEX_D, + HEX_E, + HEX_F, + HEX_XX00, + HEX_00YY, + REG_N, + REG_N_D, /* nnn0 */ + REG_N_B01, /* nn01 */ + REG_M, + SDT_REG_N, + REG_NM, + REG_B, + BRANCH_12, + BRANCH_8, + IMM0_4, + IMM0_4BY2, + IMM0_4BY4, + IMM1_4, + IMM1_4BY2, + IMM1_4BY4, + PCRELIMM_8BY2, + PCRELIMM_8BY4, + IMM0_8, + IMM0_8BY2, + IMM0_8BY4, + IMM1_8, + IMM1_8BY2, + IMM1_8BY4, + PPI, + NOPX, + NOPY, + MOVX, + MOVY, + MOVX_NOPY, + MOVY_NOPX, + PSH, + PMUL, + PPI3, + PPI3NC, + PDC, + PPIC, + REPEAT, + IMM0_3c, /* xxxx 0iii */ + IMM0_3s, /* xxxx 1iii */ + IMM0_3Uc, /* 0iii xxxx */ + IMM0_3Us, /* 1iii xxxx */ + IMM0_20_4, + IMM0_20, /* follows IMM0_20_4 */ + IMM0_20BY8, /* follows IMM0_20_4 */ + DISP0_12, + DISP0_12BY2, + DISP0_12BY4, + DISP0_12BY8, + DISP1_12, + DISP1_12BY2, + DISP1_12BY4, + DISP1_12BY8 + } +sh_nibble_type; + +typedef enum + { + A_END, + A_BDISP12, + A_BDISP8, + A_DEC_M, + A_DEC_N, + A_DISP_GBR, + A_PC, + A_DISP_PC, + A_DISP_PC_ABS, + A_DISP_REG_M, + A_DISP_REG_N, + A_GBR, + A_IMM, + A_INC_M, + A_INC_N, + A_IND_M, + A_IND_N, + A_IND_R0_REG_M, + A_IND_R0_REG_N, + A_MACH, + A_MACL, + A_PR, + A_R0, + A_R0_GBR, + A_REG_M, + A_REG_N, + A_REG_B, + A_SR, + A_VBR, + A_TBR, + A_DISP_TBR, + A_DISP2_TBR, + A_DEC_R15, + A_INC_R15, + A_MOD, + A_RE, + A_RS, + A_DSR, + DSP_REG_M, + DSP_REG_N, + DSP_REG_X, + DSP_REG_Y, + DSP_REG_E, + DSP_REG_F, + DSP_REG_G, + DSP_REG_A_M, + DSP_REG_AX, + DSP_REG_XY, + DSP_REG_AY, + DSP_REG_YX, + AX_INC_N, + AY_INC_N, + AXY_INC_N, + AYX_INC_N, + AX_IND_N, + AY_IND_N, + AXY_IND_N, + AYX_IND_N, + AX_PMOD_N, + AXY_PMOD_N, + AY_PMOD_N, + AYX_PMOD_N, + AS_DEC_N, + AS_INC_N, + AS_IND_N, + AS_PMOD_N, + A_A0, + A_X0, + A_X1, + A_Y0, + A_Y1, + A_SSR, + A_SPC, + A_SGR, + A_DBR, + F_REG_N, + F_REG_M, + D_REG_N, + D_REG_M, + X_REG_N, /* Only used for argument parsing. */ + X_REG_M, /* Only used for argument parsing. */ + DX_REG_N, + DX_REG_M, + V_REG_N, + V_REG_M, + XMTRX_M4, + F_FR0, + FPUL_N, + FPUL_M, + FPSCR_N, + FPSCR_M + } +sh_arg_type; + +typedef enum + { + A_A1_NUM = 5, + A_A0_NUM = 7, + A_X0_NUM, A_X1_NUM, A_Y0_NUM, A_Y1_NUM, + A_M0_NUM, A_A1G_NUM, A_M1_NUM, A_A0G_NUM + } +sh_dsp_reg_nums; + +#define arch_sh1_base 0x0001 +#define arch_sh2_base 0x0002 +#define arch_sh3_base 0x0004 +#define arch_sh4_base 0x0008 +#define arch_sh4a_base 0x0010 +#define arch_sh2a_base 0x0020 + +/* This is an annotation on instruction types, but we abuse the arch + field in instructions to denote it. */ +#define arch_op32 0x00100000 /* This is a 32-bit opcode. */ + +#define arch_sh_no_mmu 0x04000000 +#define arch_sh_has_mmu 0x08000000 +#define arch_sh_no_co 0x10000000 /* neither FPU nor DSP co-processor */ +#define arch_sh_sp_fpu 0x20000000 /* single precision FPU */ +#define arch_sh_dp_fpu 0x40000000 /* double precision FPU */ +#define arch_sh_has_dsp 0x80000000 + + +#define arch_sh_base_mask 0x0000003f +#define arch_opann_mask 0x00100000 +#define arch_sh_mmu_mask 0x0c000000 +#define arch_sh_co_mask 0xf0000000 + + +#define arch_sh1 (arch_sh1_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2 (arch_sh2_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2a (arch_sh2a_base|arch_sh_no_mmu|arch_sh_dp_fpu) +#define arch_sh2a_nofpu (arch_sh2a_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh2e (arch_sh2_base|arch_sh2a_base|arch_sh_no_mmu|arch_sh_sp_fpu) +#define arch_sh_dsp (arch_sh2_base|arch_sh_no_mmu|arch_sh_has_dsp) +#define arch_sh3_nommu (arch_sh3_base|arch_sh_no_mmu|arch_sh_no_co) +#define arch_sh3 (arch_sh3_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh3e (arch_sh3_base|arch_sh_has_mmu|arch_sh_sp_fpu) +#define arch_sh3_dsp (arch_sh3_base|arch_sh_has_mmu|arch_sh_has_dsp) +#define arch_sh4 (arch_sh4_base|arch_sh_has_mmu|arch_sh_dp_fpu) +#define arch_sh4a (arch_sh4a_base|arch_sh_has_mmu|arch_sh_dp_fpu) +#define arch_sh4al_dsp (arch_sh4a_base|arch_sh_has_mmu|arch_sh_has_dsp) +#define arch_sh4_nofpu (arch_sh4_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh4a_nofpu (arch_sh4a_base|arch_sh_has_mmu|arch_sh_no_co) +#define arch_sh4_nommu_nofpu (arch_sh4_base|arch_sh_no_mmu|arch_sh_no_co) + +#define SH_MERGE_ARCH_SET(SET1, SET2) ((SET1) & (SET2)) +#define SH_VALID_BASE_ARCH_SET(SET) (((SET) & arch_sh_base_mask) != 0) +#define SH_VALID_MMU_ARCH_SET(SET) (((SET) & arch_sh_mmu_mask) != 0) +#define SH_VALID_CO_ARCH_SET(SET) (((SET) & arch_sh_co_mask) != 0) +#define SH_VALID_ARCH_SET(SET) \ + (SH_VALID_BASE_ARCH_SET (SET) \ + && SH_VALID_MMU_ARCH_SET (SET) \ + && SH_VALID_CO_ARCH_SET (SET)) +#define SH_MERGE_ARCH_SET_VALID(SET1, SET2) \ + SH_VALID_ARCH_SET (SH_MERGE_ARCH_SET (SET1, SET2)) + +#define SH_ARCH_SET_HAS_FPU(SET) \ + (((SET) & (arch_sh_sp_fpu | arch_sh_dp_fpu)) != 0) +#define SH_ARCH_SET_HAS_DSP(SET) \ + (((SET) & arch_sh_has_dsp) != 0) + +/* This is returned from the functions below when an error occurs + (in addition to a call to BFD_FAIL). The value should allow + the tools to continue to function in most cases - there may + be some confusion between DSP and FPU etc. */ +#define SH_ARCH_UNKNOWN_ARCH 0xffffffff + +/* These are defined in bfd/cpu-sh.c . */ +unsigned int sh_get_arch_from_bfd_mach (unsigned long mach); +unsigned int sh_get_arch_up_from_bfd_mach (unsigned long mach); +unsigned long sh_get_bfd_mach_from_arch_set (unsigned int arch_set); +/* bfd_boolean sh_merge_bfd_arch (bfd *ibfd, bfd *obfd); */ + +/* Below are the 'architecture sets'. + They describe the following inheritance graph: + + SH1 + | + SH2 + .------------'|`--------------------. + / | \ +SH-DSP SH3-nommu SH2E + | |`--------. | + | | \ | + | SH3 SH4-nommu-nofpu | + | | | | + | .------------'|`----------+---------. | + |/ / \| + | | .-------' | + | |/ | +SH3-dsp SH4-nofpu SH3E + | |`--------------------. | + | | \| + | SH4A-nofpu SH4 + | .------------' `--------------------. | + |/ \| +SH4AL-dsp SH4A + +*/ + +/* Central branches */ +#define arch_sh1_up (arch_sh1 | arch_sh2_up) +#define arch_sh2_up (arch_sh2 | arch_sh2e_up | arch_sh2a_nofpu_up | arch_sh3_nommu_up | arch_sh_dsp_up) +#define arch_sh3_nommu_up (arch_sh3_nommu | arch_sh3_up | arch_sh4_nommu_nofpu_up) +#define arch_sh3_up (arch_sh3 | arch_sh3e_up | arch_sh3_dsp_up | arch_sh4_nofp_up) +#define arch_sh4_nommu_nofpu_up (arch_sh4_nommu_nofpu | arch_sh4_nofp_up) +#define arch_sh4_nofp_up (arch_sh4_nofpu | arch_sh4_up | arch_sh4a_nofp_up) +#define arch_sh4a_nofp_up (arch_sh4a_nofpu | arch_sh4a_up | arch_sh4al_dsp_up) + +/* Right branch */ +#define arch_sh2e_up (arch_sh2e | arch_sh2a_up | arch_sh3e_up) +#define arch_sh3e_up (arch_sh3e | arch_sh4_up) +#define arch_sh4_up (arch_sh4 | arch_sh4a_up) +#define arch_sh4a_up (arch_sh4a) + +/* Left branch */ +#define arch_sh_dsp_up (arch_sh_dsp | arch_sh3_dsp_up) +#define arch_sh3_dsp_up (arch_sh3_dsp | arch_sh4al_dsp_up) +#define arch_sh4al_dsp_up (arch_sh4al_dsp) + +/* SH 2a branched off SH2e, adding a lot but not all of SH4 and SH4a. */ +#define arch_sh2a_up (arch_sh2a) +#define arch_sh2a_nofpu_up (arch_sh2a_nofpu | arch_sh2a_up) + + +typedef struct +{ + char *name; + sh_arg_type arg[4]; + sh_nibble_type nibbles[9]; + unsigned int arch; +} sh_opcode_info; + +#ifdef DEFINE_TABLE + +const sh_opcode_info sh_table[] = + { +/* 0111nnnni8*1.... add #, */{"add",{A_IMM,A_REG_N},{HEX_7,REG_N,IMM0_8}, arch_sh1_up}, + +/* 0011nnnnmmmm1100 add , */{"add",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0011nnnnmmmm1110 addc ,*/{"addc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0011nnnnmmmm1111 addv ,*/{"addv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 11001001i8*1.... and #,R0 */{"and",{A_IMM,A_R0},{HEX_C,HEX_9,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1001 and , */{"and",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_9}, arch_sh1_up}, + +/* 11001101i8*1.... and.b #,@(R0,GBR)*/{"and.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_D,IMM0_8}, arch_sh1_up}, + +/* 1010i12......... bra */{"bra",{A_BDISP12},{HEX_A,BRANCH_12}, arch_sh1_up}, + +/* 1011i12......... bsr */{"bsr",{A_BDISP12},{HEX_B,BRANCH_12}, arch_sh1_up}, + +/* 10001001i8p1.... bt */{"bt",{A_BDISP8},{HEX_8,HEX_9,BRANCH_8}, arch_sh1_up}, + +/* 10001011i8p1.... bf */{"bf",{A_BDISP8},{HEX_8,HEX_B,BRANCH_8}, arch_sh1_up}, + +/* 10001101i8p1.... bt.s */{"bt.s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up}, + +/* 10001101i8p1.... bt/s */{"bt/s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up}, + +/* 10001111i8p1.... bf.s */{"bf.s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up}, + +/* 10001111i8p1.... bf/s */{"bf/s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up}, + +/* 0000000010001000 clrdmxy */{"clrdmxy",{0},{HEX_0,HEX_0,HEX_8,HEX_8}, arch_sh4al_dsp_up}, + +/* 0000000000101000 clrmac */{"clrmac",{0},{HEX_0,HEX_0,HEX_2,HEX_8}, arch_sh1_up}, + +/* 0000000001001000 clrs */{"clrs",{0},{HEX_0,HEX_0,HEX_4,HEX_8}, arch_sh1_up}, + +/* 0000000000001000 clrt */{"clrt",{0},{HEX_0,HEX_0,HEX_0,HEX_8}, arch_sh1_up}, + +/* 10001000i8*1.... cmp/eq #,R0 */{"cmp/eq",{A_IMM,A_R0},{HEX_8,HEX_8,IMM0_8}, arch_sh1_up}, + +/* 0011nnnnmmmm0000 cmp/eq ,*/{"cmp/eq",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 0011nnnnmmmm0011 cmp/ge ,*/{"cmp/ge",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_3}, arch_sh1_up}, + +/* 0011nnnnmmmm0111 cmp/gt ,*/{"cmp/gt",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0011nnnnmmmm0110 cmp/hi ,*/{"cmp/hi",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0011nnnnmmmm0010 cmp/hs ,*/{"cmp/hs",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00010101 cmp/pl */{"cmp/pl",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_5}, arch_sh1_up}, + +/* 0100nnnn00010001 cmp/pz */{"cmp/pz",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_1}, arch_sh1_up}, + +/* 0010nnnnmmmm1100 cmp/str ,*/{"cmp/str",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0010nnnnmmmm0111 div0s ,*/{"div0s",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0000000000011001 div0u */{"div0u",{0},{HEX_0,HEX_0,HEX_1,HEX_9}, arch_sh1_up}, + +/* 0011nnnnmmmm0100 div1 ,*/{"div1",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0110nnnnmmmm1110 exts.b ,*/{"exts.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm1111 exts.w ,*/{"exts.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 0110nnnnmmmm1100 extu.b ,*/{"extu.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0110nnnnmmmm1101 extu.w ,*/{"extu.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0000nnnn11100011 icbi @ */{"icbi",{A_IND_N},{HEX_0,REG_N,HEX_E,HEX_3}, arch_sh4a_nofp_up}, + +/* 0100nnnn00101011 jmp @ */{"jmp",{A_IND_N},{HEX_4,REG_N,HEX_2,HEX_B}, arch_sh1_up}, + +/* 0100nnnn00001011 jsr @ */{"jsr",{A_IND_N},{HEX_4,REG_N,HEX_0,HEX_B}, arch_sh1_up}, + +/* 0100nnnn00001110 ldc ,SR */{"ldc",{A_REG_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_E}, arch_sh1_up}, + +/* 0100nnnn00011110 ldc ,GBR */{"ldc",{A_REG_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_E}, arch_sh1_up}, + +/* 0100nnnn00111010 ldc ,SGR */{"ldc",{A_REG_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0100mmmm01001010 ldc ,TBR */{"ldc",{A_REG_M,A_TBR},{HEX_4,REG_M,HEX_4,HEX_A}, arch_sh2a_nofpu_up}, + +/* 0100nnnn00101110 ldc ,VBR */{"ldc",{A_REG_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_E}, arch_sh1_up}, + +/* 0100nnnn01011110 ldc ,MOD */{"ldc",{A_REG_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn01111110 ldc ,RE */{"ldc",{A_REG_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn01101110 ldc ,RS */{"ldc",{A_REG_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_E}, arch_sh_dsp_up}, + +/* 0100nnnn00111110 ldc ,SSR */{"ldc",{A_REG_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn01001110 ldc ,SPC */{"ldc",{A_REG_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn11111010 ldc ,DBR */{"ldc",{A_REG_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx1110 ldc ,Rn_BANK */{"ldc",{A_REG_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_E}, arch_sh3_nommu_up}, + +/* 0100nnnn00000111 ldc.l @+,SR */{"ldc.l",{A_INC_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00010111 ldc.l @+,GBR */{"ldc.l",{A_INC_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00100111 ldc.l @+,VBR */{"ldc.l",{A_INC_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00110110 ldc.l @+,SGR */{"ldc.l",{A_INC_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_6}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn01010111 ldc.l @+,MOD */{"ldc.l",{A_INC_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn01110111 ldc.l @+,RE */{"ldc.l",{A_INC_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn01100111 ldc.l @+,RS */{"ldc.l",{A_INC_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_7}, arch_sh_dsp_up}, + +/* 0100nnnn00110111 ldc.l @+,SSR */{"ldc.l",{A_INC_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_7}, arch_sh3_nommu_up}, + +/* 0100nnnn01000111 ldc.l @+,SPC */{"ldc.l",{A_INC_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_7}, arch_sh3_nommu_up}, + +/* 0100nnnn11110110 ldc.l @+,DBR */{"ldc.l",{A_INC_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_6}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx0111 ldc.l ,Rn_BANK */{"ldc.l",{A_INC_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_7}, arch_sh3_nommu_up}, + +/* 0100mmmm00110100 ldrc */{"ldrc",{A_REG_M},{HEX_4,REG_M,HEX_3,HEX_4}, arch_sh4al_dsp_up}, +/* 10001010i8*1.... ldrc # */{"ldrc",{A_IMM},{HEX_8,HEX_A,IMM0_8}, arch_sh4al_dsp_up}, + +/* 10001110i8p2.... ldre @(,PC) */{"ldre",{A_DISP_PC},{HEX_8,HEX_E,PCRELIMM_8BY2}, arch_sh_dsp_up}, + +/* 10001100i8p2.... ldrs @(,PC) */{"ldrs",{A_DISP_PC},{HEX_8,HEX_C,PCRELIMM_8BY2}, arch_sh_dsp_up}, + +/* 0100nnnn00001010 lds ,MACH */{"lds",{A_REG_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_A}, arch_sh1_up}, + +/* 0100nnnn00011010 lds ,MACL */{"lds",{A_REG_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_A}, arch_sh1_up}, + +/* 0100nnnn00101010 lds ,PR */{"lds",{A_REG_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_A}, arch_sh1_up}, + +/* 0100nnnn01101010 lds ,DSR */{"lds",{A_REG_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn01111010 lds ,A0 */{"lds",{A_REG_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10001010 lds ,X0 */{"lds",{A_REG_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10011010 lds ,X1 */{"lds",{A_REG_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10101010 lds ,Y0 */{"lds",{A_REG_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn10111010 lds ,Y1 */{"lds",{A_REG_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, + +/* 0100nnnn01011010 lds ,FPUL */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn01101010 lds ,FPSCR */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn00000110 lds.l @+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}, arch_sh1_up}, + +/* 0100nnnn00010110 lds.l @+,MACL*/{"lds.l",{A_INC_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_6}, arch_sh1_up}, + +/* 0100nnnn00100110 lds.l @+,PR */{"lds.l",{A_INC_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_6}, arch_sh1_up}, + +/* 0100nnnn01100110 lds.l @+,DSR */{"lds.l",{A_INC_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn01110110 lds.l @+,A0 */{"lds.l",{A_INC_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10000110 lds.l @+,X0 */{"lds.l",{A_INC_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10010110 lds.l @+,X1 */{"lds.l",{A_INC_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10100110 lds.l @+,Y0 */{"lds.l",{A_INC_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn10110110 lds.l @+,Y1 */{"lds.l",{A_INC_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_6}, arch_sh_dsp_up}, + +/* 0100nnnn01010110 lds.l @+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}, arch_sh2e_up}, + +/* 0100nnnn01100110 lds.l @+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}, arch_sh2e_up}, + +/* 0000000000111000 ldtlb */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}, arch_sh3_up}, + +/* 0100nnnnmmmm1111 mac.w @+,@+*/{"mac.w",{A_INC_M,A_INC_N},{HEX_4,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 1110nnnni8*1.... mov #, */{"mov",{A_IMM,A_REG_N},{HEX_E,REG_N,IMM0_8}, arch_sh1_up}, + +/* 0110nnnnmmmm0011 mov , */{"mov",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_3}, arch_sh1_up}, + +/* 0000nnnnmmmm0100 mov.b ,@(R0,)*/{"mov.b",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0010nnnnmmmm0100 mov.b ,@-*/{"mov.b",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0010nnnnmmmm0000 mov.b ,@*/{"mov.b",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 10000100mmmmi4*1 mov.b @(,),R0*/{"mov.b",{A_DISP_REG_M,A_R0},{HEX_8,HEX_4,REG_M,IMM0_4}, arch_sh1_up}, + +/* 11000100i8*1.... mov.b @(,GBR),R0*/{"mov.b",{A_DISP_GBR,A_R0},{HEX_C,HEX_4,IMM0_8}, arch_sh1_up}, + +/* 0000nnnnmmmm1100 mov.b @(R0,),*/{"mov.b",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_C}, arch_sh1_up}, + +/* 0110nnnnmmmm0100 mov.b @+,*/{"mov.b",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_4}, arch_sh1_up}, + +/* 0110nnnnmmmm0000 mov.b @,*/{"mov.b",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_0}, arch_sh1_up}, + +/* 10000000mmmmi4*1 mov.b R0,@(,)*/{"mov.b",{A_R0,A_DISP_REG_M},{HEX_8,HEX_0,REG_M,IMM1_4}, arch_sh1_up}, + +/* 11000000i8*1.... mov.b R0,@(,GBR)*/{"mov.b",{A_R0,A_DISP_GBR},{HEX_C,HEX_0,IMM1_8}, arch_sh1_up}, + +/* 0100nnnn10001011 mov.b R0,@+ */{"mov.b",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_8,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11001011 mov.b @-,R0 */{"mov.b",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_C,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0000dddddddddddd mov.b ,@(,) */ +{"mov.b",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0100dddddddddddd mov.b @(,), */ +{"mov.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_4,DISP0_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0001nnnnmmmmi4*4 mov.l ,@(,)*/{"mov.l",{ A_REG_M,A_DISP_REG_N},{HEX_1,REG_N,REG_M,IMM1_4BY4}, arch_sh1_up}, + +/* 0000nnnnmmmm0110 mov.l ,@(R0,)*/{"mov.l",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0010nnnnmmmm0110 mov.l ,@-*/{"mov.l",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0010nnnnmmmm0010 mov.l ,@*/{"mov.l",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 0101nnnnmmmmi4*4 mov.l @(,),*/{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_5,REG_N,REG_M,IMM0_4BY4}, arch_sh1_up}, + +/* 11000110i8*4.... mov.l @(,GBR),R0*/{"mov.l",{A_DISP_GBR,A_R0},{HEX_C,HEX_6,IMM0_8BY4}, arch_sh1_up}, + +/* 1101nnnni8p4.... mov.l @(,PC),*/{"mov.l",{A_DISP_PC,A_REG_N},{HEX_D,REG_N,PCRELIMM_8BY4}, arch_sh1_up}, + +/* 0000nnnnmmmm1110 mov.l @(R0,),*/{"mov.l",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm0110 mov.l @+,*/{"mov.l",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_6}, arch_sh1_up}, + +/* 0110nnnnmmmm0010 mov.l @,*/{"mov.l",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_2}, arch_sh1_up}, + +/* 11000010i8*4.... mov.l R0,@(,GBR)*/{"mov.l",{A_R0,A_DISP_GBR},{HEX_C,HEX_2,IMM1_8BY4}, arch_sh1_up}, + +/* 0100nnnn10101011 mov.l R0,@+ */{"mov.l",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_A,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11001011 mov.l @-,R0 */{"mov.l",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0010dddddddddddd mov.l ,@(,) */ +{"mov.l",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_2,DISP1_12BY4}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0110dddddddddddd mov.l @(,), */ +{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_6,DISP0_12BY4}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnnmmmm0101 mov.w ,@(R0,)*/{"mov.w",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0010nnnnmmmm0101 mov.w ,@-*/{"mov.w",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0010nnnnmmmm0001 mov.w ,@*/{"mov.w",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_1}, arch_sh1_up}, + +/* 10000101mmmmi4*2 mov.w @(,),R0*/{"mov.w",{A_DISP_REG_M,A_R0},{HEX_8,HEX_5,REG_M,IMM0_4BY2}, arch_sh1_up}, + +/* 11000101i8*2.... mov.w @(,GBR),R0*/{"mov.w",{A_DISP_GBR,A_R0},{HEX_C,HEX_5,IMM0_8BY2}, arch_sh1_up}, + +/* 1001nnnni8p2.... mov.w @(,PC),*/{"mov.w",{A_DISP_PC,A_REG_N},{HEX_9,REG_N,PCRELIMM_8BY2}, arch_sh1_up}, + +/* 0000nnnnmmmm1101 mov.w @(R0,),*/{"mov.w",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0110nnnnmmmm0101 mov.w @+,*/{"mov.w",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_5}, arch_sh1_up}, + +/* 0110nnnnmmmm0001 mov.w @,*/{"mov.w",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_1}, arch_sh1_up}, + +/* 10000001mmmmi4*2 mov.w R0,@(,)*/{"mov.w",{A_R0,A_DISP_REG_M},{HEX_8,HEX_1,REG_M,IMM1_4BY2}, arch_sh1_up}, + +/* 11000001i8*2.... mov.w R0,@(,GBR)*/{"mov.w",{A_R0,A_DISP_GBR},{HEX_C,HEX_1,IMM1_8BY2}, arch_sh1_up}, + +/* 0100nnnn10011011 mov.w R0,@+ */{"mov.w",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_9,HEX_B}, arch_sh2a_nofpu_up}, +/* 0100nnnn11011011 mov.w @-,R0 */{"mov.w",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_D,HEX_B}, arch_sh2a_nofpu_up}, +/* 0011nnnnmmmm0001 0001dddddddddddd mov.w ,@(,) */ +{"mov.w",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_1,DISP1_12BY2}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 0101dddddddddddd mov.w @(,), */ +{"mov.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_5,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32}, +/* 11000111i8p4.... mova @(,PC),R0*/{"mova",{A_DISP_PC,A_R0},{HEX_C,HEX_7,PCRELIMM_8BY4}, arch_sh1_up}, +/* 0000nnnn11000011 movca.l R0,@ */{"movca.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_C,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn01110011 movco.l r0,@ */{"movco.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_7,HEX_3}, arch_sh4a_nofp_up}, +/* 0000mmmm01100011 movli.l @,r0 */{"movli.l",{A_IND_M,A_R0},{HEX_0,REG_M,HEX_6,HEX_3}, arch_sh4a_nofp_up}, + +/* 0000nnnn00101001 movt */{"movt",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_9}, arch_sh1_up}, + +/* 0100mmmm10101001 movua.l @,r0 */{"movua.l",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_A,HEX_9}, arch_sh4a_nofp_up}, +/* 0100mmmm11101001 movua.l @+,r0 */{"movua.l",{A_INC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_9}, arch_sh4a_nofp_up}, + +/* 0010nnnnmmmm1111 muls.w ,*/{"muls.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up}, +/* 0010nnnnmmmm1111 muls ,*/{"muls",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up}, + +/* 0000nnnnmmmm0111 mul.l ,*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh2_up}, + +/* 0010nnnnmmmm1110 mulu.w ,*/{"mulu.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up}, +/* 0010nnnnmmmm1110 mulu ,*/{"mulu",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up}, + +/* 0110nnnnmmmm1011 neg , */{"neg",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 0110nnnnmmmm1010 negc ,*/{"negc",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 0000000000001001 nop */{"nop",{0},{HEX_0,HEX_0,HEX_0,HEX_9}, arch_sh1_up}, + +/* 0110nnnnmmmm0111 not , */{"not",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_7}, arch_sh1_up}, +/* 0000nnnn10010011 ocbi @ */{"ocbi",{A_IND_N},{HEX_0,REG_N,HEX_9,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn10100011 ocbp @ */{"ocbp",{A_IND_N},{HEX_0,REG_N,HEX_A,HEX_3}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn10110011 ocbwb @ */{"ocbwb",{A_IND_N},{HEX_0,REG_N,HEX_B,HEX_3}, arch_sh4_nommu_nofpu_up}, + + +/* 11001011i8*1.... or #,R0 */{"or",{A_IMM,A_R0},{HEX_C,HEX_B,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1011 or , */{"or",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 11001111i8*1.... or.b #,@(R0,GBR)*/{"or.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_F,IMM0_8}, arch_sh1_up}, + +/* 0000nnnn10000011 pref @ */{"pref",{A_IND_N},{HEX_0,REG_N,HEX_8,HEX_3}, arch_sh4_nommu_nofpu_up | arch_sh2a_nofpu_up}, + +/* 0000nnnn11010011 prefi @ */{"prefi",{A_IND_N},{HEX_0,REG_N,HEX_D,HEX_3}, arch_sh4a_nofp_up}, + +/* 0100nnnn00100100 rotcl */{"rotcl",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_4}, arch_sh1_up}, + +/* 0100nnnn00100101 rotcr */{"rotcr",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_5}, arch_sh1_up}, + +/* 0100nnnn00000100 rotl */{"rotl",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_4}, arch_sh1_up}, + +/* 0100nnnn00000101 rotr */{"rotr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_5}, arch_sh1_up}, + +/* 0000000000101011 rte */{"rte",{0},{HEX_0,HEX_0,HEX_2,HEX_B}, arch_sh1_up}, + +/* 0000000000001011 rts */{"rts",{0},{HEX_0,HEX_0,HEX_0,HEX_B}, arch_sh1_up}, + +/* 0000000010011000 setdmx */{"setdmx",{0},{HEX_0,HEX_0,HEX_9,HEX_8}, arch_sh4al_dsp_up}, +/* 0000000011001000 setdmy */{"setdmy",{0},{HEX_0,HEX_0,HEX_C,HEX_8}, arch_sh4al_dsp_up}, + +/* 0000000001011000 sets */{"sets",{0},{HEX_0,HEX_0,HEX_5,HEX_8}, arch_sh1_up}, +/* 0000000000011000 sett */{"sett",{0},{HEX_0,HEX_0,HEX_1,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00010100 setrc */{"setrc",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up}, + +/* 10000010i8*1.... setrc # */{"setrc",{A_IMM},{HEX_8,HEX_2,IMM0_8}, arch_sh_dsp_up}, + +/* repeat start end */{"repeat",{A_DISP_PC,A_DISP_PC,A_REG_N},{REPEAT,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up}, + +/* repeat start end # */{"repeat",{A_DISP_PC,A_DISP_PC,A_IMM},{REPEAT,HEX_2,IMM0_8,HEX_8}, arch_sh_dsp_up}, + +/* 0100nnnnmmmm1100 shad ,*/{"shad",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_C}, arch_sh3_nommu_up | arch_sh2a_nofpu_up}, + +/* 0100nnnnmmmm1101 shld ,*/{"shld",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_D}, arch_sh3_nommu_up | arch_sh2a_nofpu_up}, + +/* 0100nnnn00100000 shal */{"shal",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_0}, arch_sh1_up}, + +/* 0100nnnn00100001 shar */{"shar",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_1}, arch_sh1_up}, + +/* 0100nnnn00000000 shll */{"shll",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_0}, arch_sh1_up}, + +/* 0100nnnn00101000 shll16 */{"shll16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00001000 shll2 */{"shll2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00011000 shll8 */{"shll8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_8}, arch_sh1_up}, + +/* 0100nnnn00000001 shlr */{"shlr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_1}, arch_sh1_up}, + +/* 0100nnnn00101001 shlr16 */{"shlr16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_9}, arch_sh1_up}, + +/* 0100nnnn00001001 shlr2 */{"shlr2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_9}, arch_sh1_up}, + +/* 0100nnnn00011001 shlr8 */{"shlr8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_9}, arch_sh1_up}, + +/* 0000000000011011 sleep */{"sleep",{0},{HEX_0,HEX_0,HEX_1,HEX_B}, arch_sh1_up}, + +/* 0000nnnn00000010 stc SR, */{"stc",{A_SR,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_2}, arch_sh1_up}, + +/* 0000nnnn00010010 stc GBR, */{"stc",{A_GBR,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_2}, arch_sh1_up}, + +/* 0000nnnn00100010 stc VBR, */{"stc",{A_VBR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_2}, arch_sh1_up}, + +/* 0000nnnn01010010 stc MOD, */{"stc",{A_MOD,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn01110010 stc RE, */{"stc",{A_RE,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn01100010 stc RS, */{"stc",{A_RS,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up}, + +/* 0000nnnn00110010 stc SSR, */{"stc",{A_SSR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn01000010 stc SPC, */{"stc",{A_SPC,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn00111010 stc SGR, */{"stc",{A_SGR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn11111010 stc DBR, */{"stc",{A_DBR,A_REG_N},{HEX_0,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up}, + +/* 0000nnnn1xxx0010 stc Rn_BANK, */{"stc",{A_REG_B,A_REG_N},{HEX_0,REG_N,REG_B,HEX_2}, arch_sh3_nommu_up}, + +/* 0000nnnn01001010 stc TBR, */ {"stc",{A_TBR,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_A}, arch_sh2a_nofpu_up}, + +/* 0100nnnn00000011 stc.l SR,@- */{"stc.l",{A_SR,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_3}, arch_sh1_up}, + +/* 0100nnnn00100011 stc.l VBR,@- */{"stc.l",{A_VBR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_3}, arch_sh1_up}, + +/* 0100nnnn01010011 stc.l MOD,@- */{"stc.l",{A_MOD,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn01110011 stc.l RE,@- */{"stc.l",{A_RE,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn01100011 stc.l RS,@- */{"stc.l",{A_RS,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_3}, arch_sh_dsp_up}, + +/* 0100nnnn00110011 stc.l SSR,@- */{"stc.l",{A_SSR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_3}, arch_sh3_nommu_up}, + +/* 0100nnnn01000011 stc.l SPC,@- */{"stc.l",{A_SPC,A_DEC_N},{HEX_4,REG_N,HEX_4,HEX_3}, arch_sh3_nommu_up}, + +/* 0100nnnn00010011 stc.l GBR,@- */{"stc.l",{A_GBR,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_3}, arch_sh1_up}, + +/* 0100nnnn00110010 stc.l SGR,@- */{"stc.l",{A_SGR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_2}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn11110010 stc.l DBR,@- */{"stc.l",{A_DBR,A_DEC_N},{HEX_4,REG_N,HEX_F,HEX_2}, arch_sh4_nommu_nofpu_up}, + +/* 0100nnnn1xxx0011 stc.l Rn_BANK,@- */{"stc.l",{A_REG_B,A_DEC_N},{HEX_4,REG_N,REG_B,HEX_3}, arch_sh3_nommu_up}, + +/* 0000nnnn00001010 sts MACH, */{"sts",{A_MACH,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_A}, arch_sh1_up}, + +/* 0000nnnn00011010 sts MACL, */{"sts",{A_MACL,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_A}, arch_sh1_up}, + +/* 0000nnnn00101010 sts PR, */{"sts",{A_PR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_A}, arch_sh1_up}, + +/* 0000nnnn01101010 sts DSR, */{"sts",{A_DSR,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn01111010 sts A0, */{"sts",{A_A0,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10001010 sts X0, */{"sts",{A_X0,A_REG_N},{HEX_0,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10011010 sts X1, */{"sts",{A_X1,A_REG_N},{HEX_0,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10101010 sts Y0, */{"sts",{A_Y0,A_REG_N},{HEX_0,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn10111010 sts Y1, */{"sts",{A_Y1,A_REG_N},{HEX_0,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, + +/* 0000nnnn01011010 sts FPUL, */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}, arch_sh2e_up}, + +/* 0000nnnn01101010 sts FPSCR, */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh2e_up}, + +/* 0100nnnn00000010 sts.l MACH,@-*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00010010 sts.l MACL,@-*/{"sts.l",{A_MACL,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_2}, arch_sh1_up}, + +/* 0100nnnn00100010 sts.l PR,@- */{"sts.l",{A_PR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_2}, arch_sh1_up}, + +/* 0100nnnn01100110 sts.l DSR,@- */{"sts.l",{A_DSR,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn01110110 sts.l A0,@- */{"sts.l",{A_A0,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10000110 sts.l X0,@- */{"sts.l",{A_X0,A_DEC_N},{HEX_4,REG_N,HEX_8,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10010110 sts.l X1,@- */{"sts.l",{A_X1,A_DEC_N},{HEX_4,REG_N,HEX_9,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10100110 sts.l Y0,@- */{"sts.l",{A_Y0,A_DEC_N},{HEX_4,REG_N,HEX_A,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn10110110 sts.l Y1,@- */{"sts.l",{A_Y1,A_DEC_N},{HEX_4,REG_N,HEX_B,HEX_2}, arch_sh_dsp_up}, + +/* 0100nnnn01010010 sts.l FPUL,@-*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}, arch_sh2e_up}, + +/* 0100nnnn01100010 sts.l FPSCR,@-*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh2e_up}, + +/* 0011nnnnmmmm1000 sub , */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 0011nnnnmmmm1010 subc ,*/{"subc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 0011nnnnmmmm1011 subv ,*/{"subv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_B}, arch_sh1_up}, + +/* 0110nnnnmmmm1000 swap.b ,*/{"swap.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 0110nnnnmmmm1001 swap.w ,*/{"swap.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_9}, arch_sh1_up}, + +/* 0000000010101011 synco */{"synco",{0},{HEX_0,HEX_0,HEX_A,HEX_B}, arch_sh4a_nofp_up}, + +/* 0100nnnn00011011 tas.b @ */{"tas.b",{A_IND_N},{HEX_4,REG_N,HEX_1,HEX_B}, arch_sh1_up}, + +/* 11000011i8*1.... trapa # */{"trapa",{A_IMM},{HEX_C,HEX_3,IMM0_8}, arch_sh1_up}, + +/* 11001000i8*1.... tst #,R0 */{"tst",{A_IMM,A_R0},{HEX_C,HEX_8,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1000 tst , */{"tst",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_8}, arch_sh1_up}, + +/* 11001100i8*1.... tst.b #,@(R0,GBR)*/{"tst.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_C,IMM0_8}, arch_sh1_up}, + +/* 11001010i8*1.... xor #,R0 */{"xor",{A_IMM,A_R0},{HEX_C,HEX_A,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1010 xor , */{"xor",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_A}, arch_sh1_up}, + +/* 11001110i8*1.... xor.b #,@(R0,GBR)*/{"xor.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_E,IMM0_8}, arch_sh1_up}, + +/* 0010nnnnmmmm1101 xtrct ,*/{"xtrct",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_D}, arch_sh1_up}, + +/* 0000nnnnmmmm0111 mul.l ,*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh1_up}, + +/* 0100nnnn00010000 dt */{"dt",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_0}, arch_sh2_up}, + +/* 0011nnnnmmmm1101 dmuls.l ,*/{"dmuls.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_D}, arch_sh2_up}, + +/* 0011nnnnmmmm0101 dmulu.l ,*/{"dmulu.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_5}, arch_sh2_up}, + +/* 0000nnnnmmmm1111 mac.l @+,@+*/{"mac.l",{A_INC_M,A_INC_N},{HEX_0,REG_N,REG_M,HEX_F}, arch_sh2_up}, + +/* 0000nnnn00100011 braf */{"braf",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_3}, arch_sh2_up}, + +/* 0000nnnn00000011 bsrf */{"bsrf",{A_REG_N},{HEX_0,REG_N,HEX_0,HEX_3}, arch_sh2_up}, + +/* 111101nnmmmm0000 movs.w @-, */ {"movs.w",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_0}, arch_sh_dsp_up}, + +/* 111101nnmmmm0001 movs.w @, */ {"movs.w",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_4}, arch_sh_dsp_up}, + +/* 111101nnmmmm0010 movs.w @+, */ {"movs.w",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_8}, arch_sh_dsp_up}, + +/* 111101nnmmmm0011 movs.w @+r8, */ {"movs.w",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_C}, arch_sh_dsp_up}, + +/* 111101nnmmmm0100 movs.w ,@- */ {"movs.w",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_1}, arch_sh_dsp_up}, + +/* 111101nnmmmm0101 movs.w ,@ */ {"movs.w",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_5}, arch_sh_dsp_up}, + +/* 111101nnmmmm0110 movs.w ,@+ */ {"movs.w",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_9}, arch_sh_dsp_up}, + +/* 111101nnmmmm0111 movs.w ,@+r8 */ {"movs.w",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_D}, arch_sh_dsp_up}, + +/* 111101nnmmmm1000 movs.l @-, */ {"movs.l",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_2}, arch_sh_dsp_up}, + +/* 111101nnmmmm1001 movs.l @, */ {"movs.l",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_6}, arch_sh_dsp_up}, + +/* 111101nnmmmm1010 movs.l @+, */ {"movs.l",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_A}, arch_sh_dsp_up}, + +/* 111101nnmmmm1011 movs.l @+r8, */ {"movs.l",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_E}, arch_sh_dsp_up}, + +/* 111101nnmmmm1100 movs.l ,@- */ {"movs.l",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_3}, arch_sh_dsp_up}, + +/* 111101nnmmmm1101 movs.l ,@ */ {"movs.l",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_7}, arch_sh_dsp_up}, + +/* 111101nnmmmm1110 movs.l ,@+ */ {"movs.l",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_B}, arch_sh_dsp_up}, + +/* 111101nnmmmm1111 movs.l ,@+r8 */ {"movs.l",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_F}, arch_sh_dsp_up}, + +/* 0*0*0*00** nopx */ {"nopx",{0},{PPI,NOPX}, arch_sh_dsp_up}, +/* *0*0*0**00 nopy */ {"nopy",{0},{PPI,NOPY}, arch_sh_dsp_up}, +/* n*m*0*01** movx.w @, */ {"movx.w",{AX_IND_N,DSP_REG_X},{PPI,MOVX,HEX_1}, arch_sh_dsp_up}, +/* n*m*0*10** movx.w @+, */ {"movx.w",{AX_INC_N,DSP_REG_X},{PPI,MOVX,HEX_2}, arch_sh_dsp_up}, +/* n*m*0*11** movx.w @+r8, */ {"movx.w",{AX_PMOD_N,DSP_REG_X},{PPI,MOVX,HEX_3}, arch_sh_dsp_up}, +/* n*m*1*01** movx.w ,@ */ {"movx.w",{DSP_REG_A_M,AX_IND_N},{PPI,MOVX,HEX_9}, arch_sh_dsp_up}, +/* n*m*1*10** movx.w ,@+ */ {"movx.w",{DSP_REG_A_M,AX_INC_N},{PPI,MOVX,HEX_A}, arch_sh_dsp_up}, +/* n*m*1*11** movx.w ,@+r8 */ {"movx.w",{DSP_REG_A_M,AX_PMOD_N},{PPI,MOVX,HEX_B}, arch_sh_dsp_up}, + +/* nnmm000100 movx.w @, */ {"movx.w",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm001000 movx.w @+, */{"movx.w",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm001100 movx.w @+r8, */{"movx.w",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_C}, arch_sh4al_dsp_up}, +/* nnmm100100 movx.w ,@ */ {"movx.w",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_2,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm101000 movx.w ,@+ */{"movx.w",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_2,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm101100 movx.w ,@+r8 */{"movx.w",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_2,HEX_C}, arch_sh4al_dsp_up}, + +/* nnmm010100 movx.l @, */ {"movx.l",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm011000 movx.l @+, */{"movx.l",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm011100 movx.l @+r8, */{"movx.l",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_C}, arch_sh4al_dsp_up}, +/* nnmm110100 movx.l ,@ */ {"movx.l",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_3,HEX_4}, arch_sh4al_dsp_up}, +/* nnmm111000 movx.l ,@+ */{"movx.l",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_3,HEX_8}, arch_sh4al_dsp_up}, +/* nnmm111100 movx.l ,@+r8 */{"movx.l",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_3,HEX_C}, arch_sh4al_dsp_up}, + +/* *n*m*0**01 movy.w @, */ {"movy.w",{AY_IND_N,DSP_REG_Y},{PPI,MOVY,HEX_1}, arch_sh_dsp_up}, +/* *n*m*0**10 movy.w @+, */ {"movy.w",{AY_INC_N,DSP_REG_Y},{PPI,MOVY,HEX_2}, arch_sh_dsp_up}, +/* *n*m*0**11 movy.w @+r9, */ {"movy.w",{AY_PMOD_N,DSP_REG_Y},{PPI,MOVY,HEX_3}, arch_sh_dsp_up}, +/* *n*m*1**01 movy.w ,@ */ {"movy.w",{DSP_REG_A_M,AY_IND_N},{PPI,MOVY,HEX_9}, arch_sh_dsp_up}, +/* *n*m*1**10 movy.w ,@+ */ {"movy.w",{DSP_REG_A_M,AY_INC_N},{PPI,MOVY,HEX_A}, arch_sh_dsp_up}, +/* *n*m*1**11 movy.w ,@+r9 */ {"movy.w",{DSP_REG_A_M,AY_PMOD_N},{PPI,MOVY,HEX_B}, arch_sh_dsp_up}, + +/* nnmm000001 movy.w @, */ {"movy.w",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm000010 movy.w @+, */{"movy.w",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm000011 movy.w @+r8, */{"movy.w",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_3}, arch_sh4al_dsp_up}, +/* nnmm010001 movy.w ,@ */ {"movy.w",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_1,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm010010 movy.w ,@+ */{"movy.w",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_1,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm010011 movy.w ,@+r8 */{"movy.w",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_1,HEX_3}, arch_sh4al_dsp_up}, + +/* nnmm100001 movy.l @, */ {"movy.l",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm100010 movy.l @+, */{"movy.l",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm100011 movy.l @+r8, */{"movy.l",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_3}, arch_sh4al_dsp_up}, +/* nnmm110001 movy.l ,@ */ {"movy.l",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_3,HEX_1}, arch_sh4al_dsp_up}, +/* nnmm110010 movy.l ,@+ */{"movy.l",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_3,HEX_2}, arch_sh4al_dsp_up}, +/* nnmm110011 movy.l ,@+r8 */{"movy.l",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_3,HEX_3}, arch_sh4al_dsp_up}, + +/* 01aaeeffxxyyggnn pmuls Se,Sf,Dg */ {"pmuls",{DSP_REG_E,DSP_REG_F,DSP_REG_G},{PPI,PMUL}, arch_sh_dsp_up}, +/* 10100000xxyynnnn psubc ,, */ +{"psubc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_0}, arch_sh_dsp_up}, +/* 10110000xxyynnnn paddc ,, */ +{"paddc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_0}, arch_sh_dsp_up}, +/* 10000100xxyynnnn pcmp , */ +{"pcmp", {DSP_REG_X,DSP_REG_Y},{PPI,PPI3,HEX_8,HEX_4}, arch_sh_dsp_up}, +/* 10100100xxyynnnn pwsb ,, */ +{"pwsb", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_4}, arch_sh_dsp_up}, +/* 10110100xxyynnnn pwad ,, */ +{"pwad", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_4}, arch_sh_dsp_up}, +/* 10001000xxyynnnn pabs , */ +{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_8,HEX_8}, arch_sh_dsp_up}, +/* 1000100!xx01nnnn pabs , */ +{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9,HEX_1}, arch_sh4al_dsp_up}, +/* 10101000xxyynnnn pabs , */ +{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_A,HEX_8}, arch_sh_dsp_up}, +/* 1010100!01yynnnn pabs , */ +{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9,HEX_4}, arch_sh4al_dsp_up}, +/* 10011000xxyynnnn prnd , */ +{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_9,HEX_8}, arch_sh_dsp_up}, +/* 1001100!xx01nnnn prnd , */ +{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_1}, arch_sh4al_dsp_up}, +/* 10111000xxyynnnn prnd , */ +{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_B,HEX_8}, arch_sh_dsp_up}, +/* 1011100!01yynnnn prnd , */ +{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_4}, arch_sh4al_dsp_up}, + +{"dct",{0},{PPI,PDC,HEX_1}, arch_sh_dsp_up}, +{"dcf",{0},{PPI,PDC,HEX_2}, arch_sh_dsp_up}, + +/* 10000001xxyynnnn pshl ,, */ +{"pshl", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_1}, arch_sh_dsp_up}, +/* 00000iiiiiiinnnn pshl #, */ {"pshl",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_0}, arch_sh_dsp_up}, +/* 10010001xxyynnnn psha ,, */ +{"psha", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_1}, arch_sh_dsp_up}, +/* 00010iiiiiiinnnn psha #, */ {"psha",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_1}, arch_sh_dsp_up}, +/* 10100001xxyynnnn psub ,, */ +{"psub", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_1}, arch_sh_dsp_up}, +/* 10000101xxyynnnn psub ,, */ +{"psub", {DSP_REG_Y,DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_5}, arch_sh4al_dsp_up}, +/* 10110001xxyynnnn padd ,, */ +{"padd", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_1}, arch_sh_dsp_up}, +/* 10010101xxyynnnn pand ,, */ +{"pand", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_5}, arch_sh_dsp_up}, +/* 10100101xxyynnnn pxor ,, */ +{"pxor", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_5}, arch_sh_dsp_up}, +/* 10110101xxyynnnn por ,, */ +{"por", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_5}, arch_sh_dsp_up}, +/* 10001001xxyynnnn pdec , */ +{"pdec", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9}, arch_sh_dsp_up}, +/* 10101001xxyynnnn pdec , */ +{"pdec", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9}, arch_sh_dsp_up}, +/* 10011001xx00nnnn pinc , */ +{"pinc", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_XX00}, arch_sh_dsp_up}, +/* 1011100100yynnnn pinc , */ +{"pinc", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_00YY}, arch_sh_dsp_up}, +/* 10001101xxyynnnn pclr */ +{"pclr", {DSP_REG_N},{PPI,PPIC,HEX_8,HEX_D}, arch_sh_dsp_up}, +/* 10011101xx00nnnn pdmsb , */ +{"pdmsb", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_XX00}, arch_sh_dsp_up}, +/* 1011110100yynnnn pdmsb , */ +{"pdmsb", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_00YY}, arch_sh_dsp_up}, +/* 11001001xxyynnnn pneg , */ +{"pneg", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_9}, arch_sh_dsp_up}, +/* 11101001xxyynnnn pneg , */ +{"pneg", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_E,HEX_9}, arch_sh_dsp_up}, +/* 11011001xxyynnnn pcopy , */ +{"pcopy", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_9}, arch_sh_dsp_up}, +/* 11111001xxyynnnn pcopy , */ +{"pcopy", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_F,HEX_9}, arch_sh_dsp_up}, +/* 11001101xxyynnnn psts MACH, */ +{"psts", {A_MACH,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_D}, arch_sh_dsp_up}, +/* 11011101xxyynnnn psts MACL, */ +{"psts", {A_MACL,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_D}, arch_sh_dsp_up}, +/* 11101101xxyynnnn plds ,MACH */ +{"plds", {DSP_REG_N,A_MACH},{PPI,PPIC,HEX_E,HEX_D}, arch_sh_dsp_up}, +/* 11111101xxyynnnn plds ,MACL */ +{"plds", {DSP_REG_N,A_MACL},{PPI,PPIC,HEX_F,HEX_D}, arch_sh_dsp_up}, +/* 10011101xx01zzzz pswap , */ +{"pswap", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_1}, arch_sh4al_dsp_up}, +/* 1011110101yyzzzz pswap , */ +{"pswap", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_4}, arch_sh4al_dsp_up}, + +/* 1111nnnn01011101 fabs */{"fabs",{F_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh2e_up}, +/* 1111nnn001011101 fabs */{"fabs",{D_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0000 fadd ,*/{"fadd",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh2e_up}, +/* 1111nnn0mmm00000 fadd ,*/{"fadd",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0100 fcmp/eq ,*/{"fcmp/eq",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh2e_up}, +/* 1111nnn0mmm00100 fcmp/eq ,*/{"fcmp/eq",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0101 fcmp/gt ,*/{"fcmp/gt",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh2e_up}, +/* 1111nnn0mmm00101 fcmp/gt ,*/{"fcmp/gt",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn010111101 fcnvds ,FPUL*/{"fcnvds",{D_REG_N,FPUL_M},{HEX_F,REG_N_D,HEX_B,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn010101101 fcnvsd FPUL,*/{"fcnvsd",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_A,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0011 fdiv ,*/{"fdiv",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh2e_up}, +/* 1111nnn0mmm00011 fdiv ,*/{"fdiv",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnmm11101101 fipr ,*/{"fipr",{V_REG_M,V_REG_N},{HEX_F,REG_NM,HEX_E,HEX_D}, arch_sh4_up}, + +/* 1111nnnn10001101 fldi0 */{"fldi0",{F_REG_N},{HEX_F,REG_N,HEX_8,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn10011101 fldi1 */{"fldi1",{F_REG_N},{HEX_F,REG_N,HEX_9,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn00011101 flds ,FPUL*/{"flds",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_1,HEX_D}, arch_sh2e_up}, + +/* 1111nnnn00101101 float FPUL,*/{"float",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh2e_up}, +/* 1111nnn000101101 float FPUL,*/{"float",{FPUL_M,D_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1110 fmac FR0,,*/{"fmac",{F_FR0,F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_E}, arch_sh2e_up}, + +/* 1111nnnnmmmm1100 fmov ,*/{"fmov",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh2e_up}, +/* 1111nnn1mmmm1100 fmov ,*/{"fmov",{DX_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1000 fmov @,*/{"fmov",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up}, +/* 1111nnn1mmmm1000 fmov @,*/{"fmov",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1010 fmov ,@*/{"fmov",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up}, +/* 1111nnnnmmm11010 fmov ,@*/{"fmov",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1001 fmov @+,*/{"fmov",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up}, +/* 1111nnn1mmmm1001 fmov @+,*/{"fmov",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm1011 fmov ,@-*/{"fmov",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up}, +/* 1111nnnnmmm11011 fmov ,@-*/{"fmov",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0110 fmov @(R0,),*/{"fmov",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up}, +/* 1111nnn1mmmm0110 fmov @(R0,),*/{"fmov",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmmm0111 fmov ,@(R0,)*/{"fmov",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up}, +/* 1111nnnnmmm10111 fmov ,@(R0,)*/{"fmov",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm1000 fmov.d @,*/{"fmov.d",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm11010 fmov.d ,@*/{"fmov.d",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm1001 fmov.d @+,*/{"fmov.d",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm11011 fmov.d ,@-*/{"fmov.d",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnn1mmmm0110 fmov.d @(R0,),*/{"fmov.d",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnnmmm10111 fmov.d ,@(R0,)*/{"fmov.d",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up}, +/* 0011nnnnmmmm0001 0011dddddddddddd fmov.d ,@(,) */ +{"fmov.d",{DX_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY8}, arch_sh2a_up | arch_op32}, +/* 0011nnnnmmmm0001 0111dddddddddddd fmov.d @(,),F_REG_N */ +{"fmov.d",{A_DISP_REG_M,DX_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY8}, arch_sh2a_up | arch_op32}, + +/* 1111nnnnmmmm1000 fmov.s @,*/{"fmov.s",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up}, + +/* 1111nnnnmmmm1010 fmov.s ,@*/{"fmov.s",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up}, + +/* 1111nnnnmmmm1001 fmov.s @+,*/{"fmov.s",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up}, + +/* 1111nnnnmmmm1011 fmov.s ,@-*/{"fmov.s",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up}, + +/* 1111nnnnmmmm0110 fmov.s @(R0,),*/{"fmov.s",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up}, + +/* 1111nnnnmmmm0111 fmov.s ,@(R0,)*/{"fmov.s",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up}, +/* 0011nnnnmmmm0001 0011dddddddddddd fmov.s ,@(,) */ +{"fmov.s",{F_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY4}, arch_sh2a_up | arch_op32}, +/* 0011nnnnmmmm0001 0111dddddddddddd fmov.s @(,),F_REG_N */ +{"fmov.s",{A_DISP_REG_M,F_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY4}, arch_sh2a_up | arch_op32}, + +/* 1111nnnnmmmm0010 fmul ,*/{"fmul",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh2e_up}, +/* 1111nnn0mmm00010 fmul ,*/{"fmul",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01001101 fneg */{"fneg",{F_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh2e_up}, +/* 1111nnn001001101 fneg */{"fneg",{D_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111011111111101 fpchg */{"fpchg",{0},{HEX_F,HEX_7,HEX_F,HEX_D}, arch_sh4a_up}, + +/* 1111101111111101 frchg */{"frchg",{0},{HEX_F,HEX_B,HEX_F,HEX_D}, arch_sh4_up}, + +/* 1111nnn011111101 fsca FPUL, */{"fsca",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_F,HEX_D}, arch_sh4_up}, + +/* 1111001111111101 fschg */{"fschg",{0},{HEX_F,HEX_3,HEX_F,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01101101 fsqrt */{"fsqrt",{F_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh3e_up | arch_sh2a_up}, +/* 1111nnn001101101 fsqrt */{"fsqrt",{D_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn01111101 fsrra */{"fsrra",{F_REG_N},{HEX_F,REG_N,HEX_7,HEX_D}, arch_sh4_up}, + +/* 1111nnnn00001101 fsts FPUL,*/{"fsts",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_0,HEX_D}, arch_sh2e_up}, + +/* 1111nnnnmmmm0001 fsub ,*/{"fsub",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh2e_up}, +/* 1111nnn0mmm00001 fsub ,*/{"fsub",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nnnn00111101 ftrc ,FPUL*/{"ftrc",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh2e_up}, +/* 1111nnnn00111101 ftrc ,FPUL*/{"ftrc",{D_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh4_up | arch_sh2a_up}, + +/* 1111nn0111111101 ftrv XMTRX_M4,*/{"ftrv",{XMTRX_M4,V_REG_N},{HEX_F,REG_N_B01,HEX_F,HEX_D}, arch_sh4_up}, + + /* 10000110nnnn0iii bclr #, */ {"bclr",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3c}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0000dddddddddddd bclr.b #,@(,) */ +{"bclr.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000111nnnn1iii bld #, */ {"bld",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3s}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0011dddddddddddd bld.b #,@(,) */ +{"bld.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_3,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000110nnnn1iii bset #, */ {"bset",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3s}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0001dddddddddddd bset.b #,@(,) */ +{"bset.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_1,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 10000111nnnn0iii bst #, */ {"bst",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3c}, arch_sh2a_nofpu_up}, + /* 0011nnnn0iii1001 0010dddddddddddd bst.b #,@(,) */ +{"bst.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_2,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, + /* 0100nnnn10010001 clips.b */ {"clips.b",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100nnnn10010101 clips.w */ {"clips.w",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000001 clipu.b */ {"clipu.b",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000101 clipu.w */ {"clipu.w",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100nnnn10010100 divs R0, */ {"divs",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_9,HEX_4}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000100 divu R0, */ {"divu",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_4}, arch_sh2a_nofpu_up}, + /* 0100mmmm01001011 jsr/n @ */ {"jsr/n",{A_IND_M},{HEX_4,REG_M,HEX_4,HEX_B}, arch_sh2a_nofpu_up}, + /* 10000011dddddddd jsr/n @@(,TBR) */ {"jsr/n",{A_DISP2_TBR},{HEX_8,HEX_3,IMM0_8BY4}, arch_sh2a_nofpu_up}, + /* 0100mmmm11100101 ldbank @,R0 */ {"ldbank",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110001 movml.l ,@-R15 */ {"movml.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_1}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110101 movml.l @R15+, */ {"movml.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_5}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110000 movml.l ,@-R15 */ {"movmu.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_0}, arch_sh2a_nofpu_up}, + /* 0100mmmm11110100 movml.l @R15+, */ {"movmu.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_4}, arch_sh2a_nofpu_up}, + /* 0000nnnn00111001 movrt */ {"movrt",{A_REG_N},{HEX_0,REG_N,HEX_3,HEX_9}, arch_sh2a_nofpu_up}, + /* 0100nnnn10000000 mulr R0, */ {"mulr",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_0}, arch_sh2a_nofpu_up}, + /* 0000000001101000 nott */ {"nott",{A_END},{HEX_0,HEX_0,HEX_6,HEX_8}, arch_sh2a_nofpu_up}, + /* 0000000001011011 resbank */ {"resbank",{A_END},{HEX_0,HEX_0,HEX_5,HEX_B}, arch_sh2a_nofpu_up}, + /* 0000000001101011 rts/n */ {"rts/n",{A_END},{HEX_0,HEX_0,HEX_6,HEX_B}, arch_sh2a_nofpu_up}, + /* 0000mmmm01111011 rtv/n */ {"rtv/n",{A_REG_M},{HEX_0,REG_M,HEX_7,HEX_B}, arch_sh2a_nofpu_up}, + /* 0100nnnn11100001 stbank R0,@*/ {"stbank",{A_R0,A_IND_N},{HEX_4,REG_N,HEX_E,HEX_1}, arch_sh2a_nofpu_up}, + +/* 0011nnnn0iii1001 0100dddddddddddd band.b #,@(,) */ +{"band.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_4,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1100dddddddddddd bandnot.b #,@(,) */ +{"bandnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_C,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1011dddddddddddd bldnot.b #,@(,) */ +{"bldnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_B,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 0101dddddddddddd bor.b #,@(,) */ +{"bor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_5,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 1101dddddddddddd bornot.b #,@(,) */ +{"bornot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_D,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnn0iii1001 0110dddddddddddd bxor.b #,@(,) */ +{"bxor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_6,DISP1_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnniiii0000 iiiiiiiiiiiiiiii movi20 #, */ +{"movi20",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_0,IMM0_20}, arch_sh2a_nofpu_up | arch_op32}, +/* 0000nnnniiii0001 iiiiiiiiiiiiiiii movi20s #, */ +{"movi20s",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_1,IMM0_20BY8}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 1000dddddddddddd movu.b @(,), */ +{"movu.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_8,DISP0_12}, arch_sh2a_nofpu_up | arch_op32}, +/* 0011nnnnmmmm0001 1001dddddddddddd movu.w @(,), */ +{"movu.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_9,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32}, + +{ 0, {0}, {0}, 0 } +}; + +#endif + +#ifdef ARCH_all +#define INCLUDE_SHMEDIA +#endif + +static void print_movxy + PARAMS ((const sh_opcode_info *, int, int, fprintf_ftype, void *)); +static void print_insn_ddt PARAMS ((int, struct disassemble_info *)); +static void print_dsp_reg PARAMS ((int, fprintf_ftype, void *)); +static void print_insn_ppi PARAMS ((int, struct disassemble_info *)); + +static void +print_movxy (op, rn, rm, fprintf_fn, stream) + const sh_opcode_info *op; + int rn, rm; + fprintf_ftype fprintf_fn; + void *stream; +{ + int n; + + fprintf_fn (stream, "%s\t", op->name); + for (n = 0; n < 2; n++) + { + switch (op->arg[n]) + { + case A_IND_N: + case AX_IND_N: + case AXY_IND_N: + case AY_IND_N: + case AYX_IND_N: + fprintf_fn (stream, "@r%d", rn); + break; + case A_INC_N: + case AX_INC_N: + case AXY_INC_N: + case AY_INC_N: + case AYX_INC_N: + fprintf_fn (stream, "@r%d+", rn); + break; + case AX_PMOD_N: + case AXY_PMOD_N: + fprintf_fn (stream, "@r%d+r8", rn); + break; + case AY_PMOD_N: + case AYX_PMOD_N: + fprintf_fn (stream, "@r%d+r9", rn); + break; + case DSP_REG_A_M: + fprintf_fn (stream, "a%c", '0' + rm); + break; + case DSP_REG_X: + fprintf_fn (stream, "x%c", '0' + rm); + break; + case DSP_REG_Y: + fprintf_fn (stream, "y%c", '0' + rm); + break; + case DSP_REG_AX: + fprintf_fn (stream, "%c%c", + (rm & 1) ? 'x' : 'a', + (rm & 2) ? '1' : '0'); + break; + case DSP_REG_XY: + fprintf_fn (stream, "%c%c", + (rm & 1) ? 'y' : 'x', + (rm & 2) ? '1' : '0'); + break; + case DSP_REG_AY: + fprintf_fn (stream, "%c%c", + (rm & 2) ? 'y' : 'a', + (rm & 1) ? '1' : '0'); + break; + case DSP_REG_YX: + fprintf_fn (stream, "%c%c", + (rm & 2) ? 'x' : 'y', + (rm & 1) ? '1' : '0'); + break; + default: + abort (); + } + if (n == 0) + fprintf_fn (stream, ","); + } +} + +/* Print a double data transfer insn. INSN is just the lower three + nibbles of the insn, i.e. field a and the bit that indicates if + a parallel processing insn follows. + Return nonzero if a field b of a parallel processing insns follows. */ + +static void +print_insn_ddt (insn, info) + int insn; + struct disassemble_info *info; +{ + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + + /* If this is just a nop, make sure to emit something. */ + if (insn == 0x000) + fprintf_fn (stream, "nopx\tnopy"); + + /* If a parallel processing insn was printed before, + and we got a non-nop, emit a tab. */ + if ((insn & 0x800) && (insn & 0x3ff)) + fprintf_fn (stream, "\t"); + + /* Check if either the x or y part is invalid. */ + if (((insn & 0xc) == 0 && (insn & 0x2a0)) + || ((insn & 3) == 0 && (insn & 0x150))) + if (info->mach != bfd_mach_sh_dsp + && info->mach != bfd_mach_sh3_dsp) + { + static const sh_opcode_info *first_movx, *first_movy; + const sh_opcode_info *op; + int is_movy; + + if (! first_movx) + { + for (first_movx = sh_table; first_movx->nibbles[1] != MOVX_NOPY;) + first_movx++; + for (first_movy = first_movx; first_movy->nibbles[1] != MOVY_NOPX;) + first_movy++; + } + + is_movy = ((insn & 3) != 0); + + if (is_movy) + op = first_movy; + else + op = first_movx; + + while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3) + || op->nibbles[3] != (unsigned) (insn & 0xf)) + op++; + + print_movxy (op, + (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0) + + 2 * is_movy + + 1 * ((insn & (is_movy ? 0x100 : 0x200)) != 0)), + (insn >> 6) & 3, + fprintf_fn, stream); + } + else + fprintf_fn (stream, ".word 0x%x", insn); + else + { + static const sh_opcode_info *first_movx, *first_movy; + const sh_opcode_info *opx, *opy; + unsigned int insn_x, insn_y; + + if (! first_movx) + { + for (first_movx = sh_table; first_movx->nibbles[1] != MOVX;) + first_movx++; + for (first_movy = first_movx; first_movy->nibbles[1] != MOVY;) + first_movy++; + } + insn_x = (insn >> 2) & 0xb; + if (insn_x) + { + for (opx = first_movx; opx->nibbles[2] != insn_x;) + opx++; + print_movxy (opx, ((insn >> 9) & 1) + 4, (insn >> 7) & 1, + fprintf_fn, stream); + } + insn_y = (insn & 3) | ((insn >> 1) & 8); + if (insn_y) + { + if (insn_x) + fprintf_fn (stream, "\t"); + for (opy = first_movy; opy->nibbles[2] != insn_y;) + opy++; + print_movxy (opy, ((insn >> 8) & 1) + 6, (insn >> 6) & 1, + fprintf_fn, stream); + } + } +} + +static void +print_dsp_reg (rm, fprintf_fn, stream) + int rm; + fprintf_ftype fprintf_fn; + void *stream; +{ + switch (rm) + { + case A_A1_NUM: + fprintf_fn (stream, "a1"); + break; + case A_A0_NUM: + fprintf_fn (stream, "a0"); + break; + case A_X0_NUM: + fprintf_fn (stream, "x0"); + break; + case A_X1_NUM: + fprintf_fn (stream, "x1"); + break; + case A_Y0_NUM: + fprintf_fn (stream, "y0"); + break; + case A_Y1_NUM: + fprintf_fn (stream, "y1"); + break; + case A_M0_NUM: + fprintf_fn (stream, "m0"); + break; + case A_A1G_NUM: + fprintf_fn (stream, "a1g"); + break; + case A_M1_NUM: + fprintf_fn (stream, "m1"); + break; + case A_A0G_NUM: + fprintf_fn (stream, "a0g"); + break; + default: + fprintf_fn (stream, "0x%x", rm); + break; + } +} + +static void +print_insn_ppi (field_b, info) + int field_b; + struct disassemble_info *info; +{ + static char *sx_tab[] = { "x0", "x1", "a0", "a1" }; + static char *sy_tab[] = { "y0", "y1", "m0", "m1" }; + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + unsigned int nib1, nib2, nib3; + unsigned int altnib1, nib4; + char *dc = NULL; + const sh_opcode_info *op; + + if ((field_b & 0xe800) == 0) + { + fprintf_fn (stream, "psh%c\t#%d,", + field_b & 0x1000 ? 'a' : 'l', + (field_b >> 4) & 127); + print_dsp_reg (field_b & 0xf, fprintf_fn, stream); + return; + } + if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000) + { + static char *du_tab[] = { "x0", "y0", "a0", "a1" }; + static char *se_tab[] = { "x0", "x1", "y0", "a1" }; + static char *sf_tab[] = { "y0", "y1", "x0", "a1" }; + static char *sg_tab[] = { "m0", "m1", "a0", "a1" }; + + if (field_b & 0x2000) + { + fprintf_fn (stream, "p%s %s,%s,%s\t", + (field_b & 0x1000) ? "add" : "sub", + sx_tab[(field_b >> 6) & 3], + sy_tab[(field_b >> 4) & 3], + du_tab[(field_b >> 0) & 3]); + } + else if ((field_b & 0xf0) == 0x10 + && info->mach != bfd_mach_sh_dsp + && info->mach != bfd_mach_sh3_dsp) + { + fprintf_fn (stream, "pclr %s \t", du_tab[(field_b >> 0) & 3]); + } + else if ((field_b & 0xf3) != 0) + { + fprintf_fn (stream, ".word 0x%x\t", field_b); + } + fprintf_fn (stream, "pmuls%c%s,%s,%s", + field_b & 0x2000 ? ' ' : '\t', + se_tab[(field_b >> 10) & 3], + sf_tab[(field_b >> 8) & 3], + sg_tab[(field_b >> 2) & 3]); + return; + } + + nib1 = PPIC; + nib2 = field_b >> 12 & 0xf; + nib3 = field_b >> 8 & 0xf; + nib4 = field_b >> 4 & 0xf; + switch (nib3 & 0x3) + { + case 0: + dc = ""; + nib1 = PPI3; + break; + case 1: + dc = ""; + break; + case 2: + dc = "dct "; + nib3 -= 1; + break; + case 3: + dc = "dcf "; + nib3 -= 2; + break; + } + if (nib1 == PPI3) + altnib1 = PPI3NC; + else + altnib1 = nib1; + for (op = sh_table; op->name; op++) + { + if ((op->nibbles[1] == nib1 || op->nibbles[1] == altnib1) + && op->nibbles[2] == nib2 + && op->nibbles[3] == nib3) + { + int n; + + switch (op->nibbles[4]) + { + case HEX_0: + break; + case HEX_XX00: + if ((nib4 & 3) != 0) + continue; + break; + case HEX_1: + if ((nib4 & 3) != 1) + continue; + break; + case HEX_00YY: + if ((nib4 & 0xc) != 0) + continue; + break; + case HEX_4: + if ((nib4 & 0xc) != 4) + continue; + break; + default: + abort (); + } + fprintf_fn (stream, "%s%s\t", dc, op->name); + for (n = 0; n < 3 && op->arg[n] != A_END; n++) + { + if (n && op->arg[1] != A_END) + fprintf_fn (stream, ","); + switch (op->arg[n]) + { + case DSP_REG_N: + print_dsp_reg (field_b & 0xf, fprintf_fn, stream); + break; + case DSP_REG_X: + fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]); + break; + case DSP_REG_Y: + fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]); + break; + case A_MACH: + fprintf_fn (stream, "mach"); + break; + case A_MACL: + fprintf_fn (stream, "macl"); + break; + default: + abort (); + } + } + return; + } + } + /* Not found. */ + fprintf_fn (stream, ".word 0x%x", field_b); +} + +/* FIXME mvs: movx insns print as ".word 0x%03x", insn & 0xfff + (ie. the upper nibble is missing). */ +int +print_insn_sh (memaddr, info) + bfd_vma memaddr; + struct disassemble_info *info; +{ + fprintf_ftype fprintf_fn = info->fprintf_func; + void *stream = info->stream; + unsigned char insn[4]; + unsigned char nibs[8]; + int status; + bfd_vma relmask = ~(bfd_vma) 0; + const sh_opcode_info *op; + unsigned int target_arch; + int allow_op32; + + switch (info->mach) + { + case bfd_mach_sh: + target_arch = arch_sh1; + break; + case bfd_mach_sh4: + target_arch = arch_sh4; + break; + case bfd_mach_sh5: +#ifdef INCLUDE_SHMEDIA + status = print_insn_sh64 (memaddr, info); + if (status != -2) + return status; +#endif + /* When we get here for sh64, it's because we want to disassemble + SHcompact, i.e. arch_sh4. */ + target_arch = arch_sh4; + break; + default: + fprintf (stderr, "sh architecture not supported\n"); + return -1; + } + + status = info->read_memory_func (memaddr, insn, 2, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_LITTLE) + { + nibs[0] = (insn[1] >> 4) & 0xf; + nibs[1] = insn[1] & 0xf; + + nibs[2] = (insn[0] >> 4) & 0xf; + nibs[3] = insn[0] & 0xf; + } + else + { + nibs[0] = (insn[0] >> 4) & 0xf; + nibs[1] = insn[0] & 0xf; + + nibs[2] = (insn[1] >> 4) & 0xf; + nibs[3] = insn[1] & 0xf; + } + status = info->read_memory_func (memaddr + 2, insn + 2, 2, info); + if (status != 0) + allow_op32 = 0; + else + { + allow_op32 = 1; + + if (info->endian == BFD_ENDIAN_LITTLE) + { + nibs[4] = (insn[3] >> 4) & 0xf; + nibs[5] = insn[3] & 0xf; + + nibs[6] = (insn[2] >> 4) & 0xf; + nibs[7] = insn[2] & 0xf; + } + else + { + nibs[4] = (insn[2] >> 4) & 0xf; + nibs[5] = insn[2] & 0xf; + + nibs[6] = (insn[3] >> 4) & 0xf; + nibs[7] = insn[3] & 0xf; + } + } + + if (nibs[0] == 0xf && (nibs[1] & 4) == 0 + && SH_MERGE_ARCH_SET_VALID (target_arch, arch_sh_dsp_up)) + { + if (nibs[1] & 8) + { + int field_b; + + status = info->read_memory_func (memaddr + 2, insn, 2, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr + 2, info); + return -1; + } + + if (info->endian == BFD_ENDIAN_LITTLE) + field_b = insn[1] << 8 | insn[0]; + else + field_b = insn[0] << 8 | insn[1]; + + print_insn_ppi (field_b, info); + print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info); + return 4; + } + print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info); + return 2; + } + for (op = sh_table; op->name; op++) + { + int n; + int imm = 0; + int rn = 0; + int rm = 0; + int rb = 0; + int disp_pc; + bfd_vma disp_pc_addr = 0; + int disp = 0; + int has_disp = 0; + int max_n = SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 8 : 4; + + if (!allow_op32 + && SH_MERGE_ARCH_SET (op->arch, arch_op32)) + goto fail; + + if (!SH_MERGE_ARCH_SET_VALID (op->arch, target_arch)) + goto fail; + for (n = 0; n < max_n; n++) + { + int i = op->nibbles[n]; + + if (i < 16) + { + if (nibs[n] == i) + continue; + goto fail; + } + switch (i) + { + case BRANCH_8: + imm = (nibs[2] << 4) | (nibs[3]); + if (imm & 0x80) + imm |= ~0xff; + imm = ((char) imm) * 2 + 4; + goto ok; + case BRANCH_12: + imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]); + if (imm & 0x800) + imm |= ~0xfff; + imm = imm * 2 + 4; + goto ok; + case IMM0_3c: + if (nibs[3] & 0x8) + goto fail; + imm = nibs[3] & 0x7; + break; + case IMM0_3s: + if (!(nibs[3] & 0x8)) + goto fail; + imm = nibs[3] & 0x7; + break; + case IMM0_3Uc: + if (nibs[2] & 0x8) + goto fail; + imm = nibs[2] & 0x7; + break; + case IMM0_3Us: + if (!(nibs[2] & 0x8)) + goto fail; + imm = nibs[2] & 0x7; + break; + case DISP0_12: + case DISP1_12: + disp = (nibs[5] << 8) | (nibs[6] << 4) | nibs[7]; + has_disp = 1; + goto ok; + case DISP0_12BY2: + case DISP1_12BY2: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 1; + relmask = ~(bfd_vma) 1; + has_disp = 1; + goto ok; + case DISP0_12BY4: + case DISP1_12BY4: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 2; + relmask = ~(bfd_vma) 3; + has_disp = 1; + goto ok; + case DISP0_12BY8: + case DISP1_12BY8: + disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 3; + relmask = ~(bfd_vma) 7; + has_disp = 1; + goto ok; + case IMM0_20_4: + break; + case IMM0_20: + imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8) + | (nibs[6] << 4) | nibs[7]); + if (imm & 0x80000) + imm -= 0x100000; + goto ok; + case IMM0_20BY8: + imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8) + | (nibs[6] << 4) | nibs[7]); + imm <<= 8; + if (imm & 0x8000000) + imm -= 0x10000000; + goto ok; + case IMM0_4: + case IMM1_4: + imm = nibs[3]; + goto ok; + case IMM0_4BY2: + case IMM1_4BY2: + imm = nibs[3] << 1; + goto ok; + case IMM0_4BY4: + case IMM1_4BY4: + imm = nibs[3] << 2; + goto ok; + case IMM0_8: + case IMM1_8: + imm = (nibs[2] << 4) | nibs[3]; + disp = imm; + has_disp = 1; + if (imm & 0x80) + imm -= 0x100; + goto ok; + case PCRELIMM_8BY2: + imm = ((nibs[2] << 4) | nibs[3]) << 1; + relmask = ~(bfd_vma) 1; + goto ok; + case PCRELIMM_8BY4: + imm = ((nibs[2] << 4) | nibs[3]) << 2; + relmask = ~(bfd_vma) 3; + goto ok; + case IMM0_8BY2: + case IMM1_8BY2: + imm = ((nibs[2] << 4) | nibs[3]) << 1; + goto ok; + case IMM0_8BY4: + case IMM1_8BY4: + imm = ((nibs[2] << 4) | nibs[3]) << 2; + goto ok; + case REG_N_D: + if ((nibs[n] & 1) != 0) + goto fail; + /* fall through */ + case REG_N: + rn = nibs[n]; + break; + case REG_M: + rm = nibs[n]; + break; + case REG_N_B01: + if ((nibs[n] & 0x3) != 1 /* binary 01 */) + goto fail; + rn = (nibs[n] & 0xc) >> 2; + break; + case REG_NM: + rn = (nibs[n] & 0xc) >> 2; + rm = (nibs[n] & 0x3); + break; + case REG_B: + rb = nibs[n] & 0x07; + break; + case SDT_REG_N: + /* sh-dsp: single data transfer. */ + rn = nibs[n]; + if ((rn & 0xc) != 4) + goto fail; + rn = rn & 0x3; + rn |= (!(rn & 2)) << 2; + break; + case PPI: + case REPEAT: + goto fail; + default: + abort (); + } + } + + ok: + /* sh2a has D_REG but not X_REG. We don't know the pattern + doesn't match unless we check the output args to see if they + make sense. */ + if (target_arch == arch_sh2a + && ((op->arg[0] == DX_REG_M && (rm & 1) != 0) + || (op->arg[1] == DX_REG_N && (rn & 1) != 0))) + goto fail; + + fprintf_fn (stream, "%s\t", op->name); + disp_pc = 0; + for (n = 0; n < 3 && op->arg[n] != A_END; n++) + { + if (n && op->arg[1] != A_END) + fprintf_fn (stream, ","); + switch (op->arg[n]) + { + case A_IMM: + fprintf_fn (stream, "#%d", imm); + break; + case A_R0: + fprintf_fn (stream, "r0"); + break; + case A_REG_N: + fprintf_fn (stream, "r%d", rn); + break; + case A_INC_N: + case AS_INC_N: + fprintf_fn (stream, "@r%d+", rn); + break; + case A_DEC_N: + case AS_DEC_N: + fprintf_fn (stream, "@-r%d", rn); + break; + case A_IND_N: + case AS_IND_N: + fprintf_fn (stream, "@r%d", rn); + break; + case A_DISP_REG_N: + fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rn); + break; + case AS_PMOD_N: + fprintf_fn (stream, "@r%d+r8", rn); + break; + case A_REG_M: + fprintf_fn (stream, "r%d", rm); + break; + case A_INC_M: + fprintf_fn (stream, "@r%d+", rm); + break; + case A_DEC_M: + fprintf_fn (stream, "@-r%d", rm); + break; + case A_IND_M: + fprintf_fn (stream, "@r%d", rm); + break; + case A_DISP_REG_M: + fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rm); + break; + case A_REG_B: + fprintf_fn (stream, "r%d_bank", rb); + break; + case A_DISP_PC: + disp_pc = 1; + disp_pc_addr = imm + 4 + (memaddr & relmask); + (*info->print_address_func) (disp_pc_addr, info); + break; + case A_IND_R0_REG_N: + fprintf_fn (stream, "@(r0,r%d)", rn); + break; + case A_IND_R0_REG_M: + fprintf_fn (stream, "@(r0,r%d)", rm); + break; + case A_DISP_GBR: + fprintf_fn (stream, "@(%d,gbr)", has_disp?disp:imm); + break; + case A_TBR: + fprintf_fn (stream, "tbr"); + break; + case A_DISP2_TBR: + fprintf_fn (stream, "@@(%d,tbr)", has_disp?disp:imm); + break; + case A_INC_R15: + fprintf_fn (stream, "@r15+"); + break; + case A_DEC_R15: + fprintf_fn (stream, "@-r15"); + break; + case A_R0_GBR: + fprintf_fn (stream, "@(r0,gbr)"); + break; + case A_BDISP12: + case A_BDISP8: + { + bfd_vma addr; + addr = imm + memaddr; + (*info->print_address_func) (addr, info); + } + break; + case A_SR: + fprintf_fn (stream, "sr"); + break; + case A_GBR: + fprintf_fn (stream, "gbr"); + break; + case A_VBR: + fprintf_fn (stream, "vbr"); + break; + case A_DSR: + fprintf_fn (stream, "dsr"); + break; + case A_MOD: + fprintf_fn (stream, "mod"); + break; + case A_RE: + fprintf_fn (stream, "re"); + break; + case A_RS: + fprintf_fn (stream, "rs"); + break; + case A_A0: + fprintf_fn (stream, "a0"); + break; + case A_X0: + fprintf_fn (stream, "x0"); + break; + case A_X1: + fprintf_fn (stream, "x1"); + break; + case A_Y0: + fprintf_fn (stream, "y0"); + break; + case A_Y1: + fprintf_fn (stream, "y1"); + break; + case DSP_REG_M: + print_dsp_reg (rm, fprintf_fn, stream); + break; + case A_SSR: + fprintf_fn (stream, "ssr"); + break; + case A_SPC: + fprintf_fn (stream, "spc"); + break; + case A_MACH: + fprintf_fn (stream, "mach"); + break; + case A_MACL: + fprintf_fn (stream, "macl"); + break; + case A_PR: + fprintf_fn (stream, "pr"); + break; + case A_SGR: + fprintf_fn (stream, "sgr"); + break; + case A_DBR: + fprintf_fn (stream, "dbr"); + break; + case F_REG_N: + fprintf_fn (stream, "fr%d", rn); + break; + case F_REG_M: + fprintf_fn (stream, "fr%d", rm); + break; + case DX_REG_N: + if (rn & 1) + { + fprintf_fn (stream, "xd%d", rn & ~1); + break; + } + case D_REG_N: + fprintf_fn (stream, "dr%d", rn); + break; + case DX_REG_M: + if (rm & 1) + { + fprintf_fn (stream, "xd%d", rm & ~1); + break; + } + case D_REG_M: + fprintf_fn (stream, "dr%d", rm); + break; + case FPSCR_M: + case FPSCR_N: + fprintf_fn (stream, "fpscr"); + break; + case FPUL_M: + case FPUL_N: + fprintf_fn (stream, "fpul"); + break; + case F_FR0: + fprintf_fn (stream, "fr0"); + break; + case V_REG_N: + fprintf_fn (stream, "fv%d", rn * 4); + break; + case V_REG_M: + fprintf_fn (stream, "fv%d", rm * 4); + break; + case XMTRX_M4: + fprintf_fn (stream, "xmtrx"); + break; + default: + abort (); + } + } + +#if 0 + /* This code prints instructions in delay slots on the same line + as the instruction which needs the delay slots. This can be + confusing, since other disassembler don't work this way, and + it means that the instructions are not all in a line. So I + disabled it. Ian. */ + if (!(info->flags & 1) + && (op->name[0] == 'j' + || (op->name[0] == 'b' + && (op->name[1] == 'r' + || op->name[1] == 's')) + || (op->name[0] == 'r' && op->name[1] == 't') + || (op->name[0] == 'b' && op->name[2] == '.'))) + { + info->flags |= 1; + fprintf_fn (stream, "\t(slot "); + print_insn_sh (memaddr + 2, info); + info->flags &= ~1; + fprintf_fn (stream, ")"); + return 4; + } +#endif + + if (disp_pc && strcmp (op->name, "mova") != 0) + { + int size; + bfd_byte bytes[4]; + + if (relmask == ~(bfd_vma) 1) + size = 2; + else + size = 4; + status = info->read_memory_func (disp_pc_addr, bytes, size, info); + if (status == 0) + { + unsigned int val; + + if (size == 2) + { + if (info->endian == BFD_ENDIAN_LITTLE) + val = bfd_getl16 (bytes); + else + val = bfd_getb16 (bytes); + } + else + { + if (info->endian == BFD_ENDIAN_LITTLE) + val = bfd_getl32 (bytes); + else + val = bfd_getb32 (bytes); + } + if ((*info->symbol_at_address_func) (val, info)) + { + fprintf_fn (stream, "\t! 0x"); + (*info->print_address_func) (val, info); + } + else + fprintf_fn (stream, "\t! 0x%x", val); + } + } + + return SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 4 : 2; + fail: + ; + + } + fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]); + return 2; +} diff --git a/softmmu_header.h b/softmmu_header.h index e79592f83..d5b3debc7 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -61,6 +61,8 @@ #define CPU_MEM_INDEX ((env->psrs) == 0) #elif defined (TARGET_ARM) #define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) +#elif defined (TARGET_SH4) +#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) #else #error unsupported CPU #endif @@ -78,6 +80,8 @@ #define CPU_MEM_INDEX ((env->psrs) == 0) #elif defined (TARGET_ARM) #define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) +#elif defined (TARGET_SH4) +#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) #else #error unsupported CPU #endif diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h new file mode 100644 index 000000000..d99ff8e80 --- /dev/null +++ b/target-sh4/cpu.h @@ -0,0 +1,138 @@ +/* + * SH4 emulation + * + * Copyright (c) 2005 Samuel Tardieu + * + * 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_SH4_H +#define _CPU_SH4_H + +#include "config.h" + +#define TARGET_LONG_BITS 32 +#define TARGET_HAS_ICE 1 + +#include "cpu-defs.h" + +#define TARGET_PAGE_BITS 12 /* 4k XXXXX */ + +#define SR_MD (1 << 30) +#define SR_RB (1 << 29) +#define SR_BL (1 << 28) +#define SR_FD (1 << 15) +#define SR_M (1 << 9) +#define SR_Q (1 << 8) +#define SR_S (1 << 1) +#define SR_T (1 << 0) + +#define FPSCR_FR (1 << 21) +#define FPSCR_SZ (1 << 20) +#define FPSCR_PR (1 << 19) +#define FPSCR_DN (1 << 18) + +#define DELAY_SLOT (1 << 0) +#define DELAY_SLOT_CONDITIONAL (1 << 1) +/* Those are used in contexts only */ +#define BRANCH (1 << 2) +#define BRANCH_CONDITIONAL (1 << 3) +#define MODE_CHANGE (1 << 4) /* Potential MD|RB change */ +#define BRANCH_EXCEPTION (1 << 5) /* Branch after exception */ + +/* XXXXX The structure could be made more compact */ +typedef struct tlb_t { + uint8_t asid; /* address space identifier */ + uint32_t vpn; /* virtual page number */ + uint8_t v; /* validity */ + uint32_t ppn; /* physical page number */ + uint8_t sz; /* page size */ + uint32_t size; /* cached page size in bytes */ + uint8_t sh; /* share status */ + uint8_t c; /* cacheability */ + uint8_t pr; /* protection key */ + uint8_t d; /* dirty */ + uint8_t wt; /* write through */ + uint8_t sa; /* space attribute (PCMCIA) */ + uint8_t tc; /* timing control */ +} tlb_t; + +#define UTLB_SIZE 64 +#define ITLB_SIZE 4 + +typedef struct CPUSH4State { + uint32_t flags; /* general execution flags */ + uint32_t gregs[24]; /* general registers */ + uint32_t fregs[32]; /* floating point registers */ + uint32_t sr; /* status register */ + uint32_t ssr; /* saved status register */ + uint32_t spc; /* saved program counter */ + uint32_t gbr; /* global base register */ + uint32_t vbr; /* vector base register */ + uint32_t sgr; /* saved global register 15 */ + uint32_t dbr; /* debug base register */ + uint32_t pc; /* program counter */ + uint32_t delayed_pc; /* target of delayed jump */ + uint32_t mach; /* multiply and accumulate high */ + uint32_t macl; /* multiply and accumulate low */ + uint32_t pr; /* procedure register */ + uint32_t fpscr; /* floating point status/control register */ + uint32_t fpul; /* floating point communication register */ + + /* Those belong to the specific unit (SH7750) but are handled here */ + uint32_t mmucr; /* MMU control register */ + uint32_t pteh; /* page table entry high register */ + uint32_t ptel; /* page table entry low register */ + uint32_t ptea; /* page table entry assistance register */ + uint32_t ttb; /* tranlation table base register */ + uint32_t tea; /* TLB exception address register */ + uint32_t tra; /* TRAPA exception register */ + uint32_t expevt; /* exception event register */ + uint32_t intevt; /* interrupt event register */ + + jmp_buf jmp_env; + int user_mode_only; + int interrupt_request; + int exception_index; + CPU_COMMON tlb_t utlb[UTLB_SIZE]; /* unified translation table */ + tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ +} CPUSH4State; + +CPUSH4State *cpu_sh4_init(void); +int cpu_sh4_exec(CPUSH4State * s); +struct siginfo; +int cpu_sh4_signal_handler(int hostsignum, struct siginfo *info, + void *puc); + +#include "softfloat.h" + +#include "cpu-all.h" + +/* Memory access type */ +enum { + /* Privilege */ + ACCESS_PRIV = 0x01, + /* Direction */ + ACCESS_WRITE = 0x02, + /* Type of instruction */ + ACCESS_CODE = 0x10, + ACCESS_INT = 0x20 +}; + +/* MMU control register */ +#define MMUCR 0x1F000010 +#define MMUCR_AT (1<<0) +#define MMUCR_SV (1<<8) + +#endif /* _CPU_SH4_H */ diff --git a/target-sh4/exec.h b/target-sh4/exec.h new file mode 100644 index 000000000..c219fef91 --- /dev/null +++ b/target-sh4/exec.h @@ -0,0 +1,75 @@ +/* + * SH4 emulation + * + * Copyright (c) 2005 Samuel Tardieu + * + * 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 _EXEC_SH4_H +#define _EXEC_SH4_H + +#include "config.h" +#include "dyngen-exec.h" + +register struct CPUSH4State *env asm(AREG0); +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +register uint32_t T2 asm(AREG3); + +#include "cpu.h" +#include "exec-all.h" + +#ifndef CONFIG_USER_ONLY +#include "softmmu_exec.h" +#endif + +#define RETURN() __asm__ __volatile__("") + +static inline void regs_to_env(void) +{ + /* XXXXX */ +} + +static inline void env_to_regs(void) +{ + /* XXXXX */ +} + +int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, + int is_user, int is_softmmu); + +int find_itlb_entry(CPUState * env, target_ulong address, + int use_asid, int update); +int find_utlb_entry(CPUState * env, target_ulong address, int use_asid); + +void helper_addc_T0_T1(void); +void helper_addv_T0_T1(void); +void helper_div1_T0_T1(void); +void helper_dmulsl_T0_T1(void); +void helper_dmulul_T0_T1(void); +void helper_macl_T0_T1(void); +void helper_macw_T0_T1(void); +void helper_negc_T0(void); +void helper_subc_T0_T1(void); +void helper_subv_T0_T1(void); +void helper_rotcl(uint32_t * addr); +void helper_rotcr(uint32_t * addr); + +void do_interrupt(CPUState * env); + +void cpu_loop_exit(void); +void do_raise_exception(void); + +#endif /* _EXEC_SH4_H */ diff --git a/target-sh4/helper.c b/target-sh4/helper.c new file mode 100644 index 000000000..5ab505aed --- /dev/null +++ b/target-sh4/helper.c @@ -0,0 +1,398 @@ +/* + * SH4 emulation + * + * Copyright (c) 2005 Samuel Tardieu + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" + +#define MMU_OK 0 +#define MMU_ITLB_MISS (-1) +#define MMU_ITLB_MULTIPLE (-2) +#define MMU_ITLB_VIOLATION (-3) +#define MMU_DTLB_MISS_READ (-4) +#define MMU_DTLB_MISS_WRITE (-5) +#define MMU_DTLB_INITIAL_WRITE (-6) +#define MMU_DTLB_VIOLATION_READ (-7) +#define MMU_DTLB_VIOLATION_WRITE (-8) +#define MMU_DTLB_MULTIPLE (-9) +#define MMU_DTLB_MISS (-10) + +void do_interrupt(CPUState * env) +{ + if (loglevel & CPU_LOG_INT) { + const char *expname; + switch (env->exception_index) { + case 0x0e0: + expname = "addr_error"; + break; + case 0x040: + expname = "tlb_miss"; + break; + case 0x0a0: + expname = "tlb_violation"; + break; + case 0x180: + expname = "illegal_instruction"; + break; + case 0x1a0: + expname = "slot_illegal_instruction"; + break; + case 0x800: + expname = "fpu_disable"; + break; + case 0x820: + expname = "slot_fpu"; + break; + case 0x100: + expname = "data_write"; + break; + case 0x060: + expname = "dtlb_miss_write"; + break; + case 0x0c0: + expname = "dtlb_violation_write"; + break; + case 0x120: + expname = "fpu_exception"; + break; + case 0x080: + expname = "initial_page_write"; + break; + case 0x160: + expname = "trapa"; + break; + default: + expname = "???"; + break; + } + fprintf(logfile, "exception 0x%03x [%s] raised\n", + env->exception_index, expname); + cpu_dump_state(env, logfile, fprintf, 0); + } + + env->ssr = env->sr; + env->spc = env->spc; + env->sgr = env->gregs[15]; + env->sr |= SR_BL | SR_MD | SR_RB; + + env->expevt = env->exception_index & 0x7ff; + switch (env->exception_index) { + case 0x040: + case 0x060: + case 0x080: + env->pc = env->vbr + 0x400; + break; + case 0x140: + env->pc = 0xa0000000; + break; + default: + env->pc = env->vbr + 0x100; + break; + } +} + +static void update_itlb_use(CPUState * env, int itlbnb) +{ + uint8_t or_mask = 0, and_mask = (uint8_t) - 1; + + switch (itlbnb) { + case 0: + and_mask = 0x7f; + break; + case 1: + and_mask = 0xe7; + or_mask = 0x80; + break; + case 2: + and_mask = 0xfb; + or_mask = 0x50; + break; + case 3: + or_mask = 0x2c; + break; + } + + env->mmucr &= (and_mask << 24); + env->mmucr |= (or_mask << 24); +} + +static int itlb_replacement(CPUState * env) +{ + if ((env->mmucr & 0xe0000000) == 0xe0000000) + return 0; + if ((env->mmucr & 0x98000000) == 0x08000000) + return 1; + if ((env->mmucr & 0x54000000) == 0x04000000) + return 2; + if ((env->mmucr & 0x2c000000) == 0x00000000) + return 3; + assert(0); +} + +/* Find the corresponding entry in the right TLB + Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE +*/ +static int find_tlb_entry(CPUState * env, target_ulong address, + tlb_t * entries, uint8_t nbtlb, int use_asid) +{ + int match = MMU_DTLB_MISS; + uint32_t start, end; + uint8_t asid; + int i; + + asid = env->pteh & 0xff; + + for (i = 0; i < nbtlb; i++) { + if (!entries[i].v) + continue; /* Invalid entry */ + if (use_asid && entries[i].asid != asid && !entries[i].sh) + continue; /* Bad ASID */ +#if 0 + switch (entries[i].sz) { + case 0: + size = 1024; /* 1kB */ + break; + case 1: + size = 4 * 1024; /* 4kB */ + break; + case 2: + size = 64 * 1024; /* 64kB */ + break; + case 3: + size = 1024 * 1024; /* 1MB */ + break; + default: + assert(0); + } +#endif + start = (entries[i].vpn << 10) & ~(entries[i].size - 1); + end = start + entries[i].size - 1; + if (address >= start && address <= end) { /* Match */ + if (match != -1) + return MMU_DTLB_MULTIPLE; /* Multiple match */ + match = i; + } + } + return match; +} + +/* Find itlb entry - update itlb from utlb if necessary and asked for + Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE + Update the itlb from utlb if update is not 0 +*/ +int find_itlb_entry(CPUState * env, target_ulong address, + int use_asid, int update) +{ + int e, n; + + e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid); + if (e == MMU_DTLB_MULTIPLE) + e = MMU_ITLB_MULTIPLE; + else if (e == MMU_DTLB_MISS && update) { + e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); + if (e >= 0) { + n = itlb_replacement(env); + env->itlb[n] = env->utlb[e]; + e = n; + } + } + if (e >= 0) + update_itlb_use(env, e); + return e; +} + +/* Find utlb entry + Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */ +int find_utlb_entry(CPUState * env, target_ulong address, int use_asid) +{ + uint8_t urb, urc; + + /* Increment URC */ + urb = ((env->mmucr) >> 18) & 0x3f; + urc = ((env->mmucr) >> 10) & 0x3f; + urc++; + if (urc == urb || urc == UTLB_SIZE - 1) + urc = 0; + env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); + + /* Return entry */ + return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); +} + +/* Match address against MMU + Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE, + MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ, + MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS, + MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION +*/ +static int get_mmu_address(CPUState * env, target_ulong * physical, + int *prot, target_ulong address, + int rw, int access_type) +{ + int use_asid, is_code, n; + tlb_t *matching = NULL; + + use_asid = (env->mmucr & MMUCR_SV) == 0 && (env->sr & SR_MD) == 0; + is_code = env->pc == address; /* Hack */ + + /* Use a hack to find if this is an instruction or data access */ + if (env->pc == address && !(rw & PAGE_WRITE)) { + n = find_itlb_entry(env, address, use_asid, 1); + if (n >= 0) { + matching = &env->itlb[n]; + if ((env->sr & SR_MD) & !(matching->pr & 2)) + n = MMU_ITLB_VIOLATION; + else + *prot = PAGE_READ; + } + } else { + n = find_utlb_entry(env, address, use_asid); + if (n >= 0) { + matching = &env->utlb[n]; + switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) { + case 0: /* 000 */ + case 2: /* 010 */ + n = (rw & PAGE_WRITE) ? MMU_DTLB_VIOLATION_WRITE : + MMU_DTLB_VIOLATION_READ; + break; + case 1: /* 001 */ + case 4: /* 100 */ + case 5: /* 101 */ + if (rw & PAGE_WRITE) + n = MMU_DTLB_VIOLATION_WRITE; + else + *prot = PAGE_READ; + break; + case 3: /* 011 */ + case 6: /* 110 */ + case 7: /* 111 */ + *prot = rw & (PAGE_READ | PAGE_WRITE); + break; + } + } else if (n == MMU_DTLB_MISS) { + n = (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE : + MMU_DTLB_MISS_READ; + } + } + if (n >= 0) { + *physical = ((matching->ppn << 10) & ~(matching->size - 1)) | + (address & (matching->size - 1)); + if ((rw & PAGE_WRITE) & !matching->d) + n = MMU_DTLB_INITIAL_WRITE; + else + n = MMU_OK; + } + return n; +} + +int get_physical_address(CPUState * env, target_ulong * physical, + int *prot, target_ulong address, + int rw, int access_type) +{ + /* P1, P2 and P4 areas do not use translation */ + if ((address >= 0x80000000 && address < 0xc0000000) || + address >= 0xe0000000) { + if (!(env->sr & SR_MD) + && (address < 0xe0000000 || address > 0xe4000000)) { + /* Unauthorized access in user mode (only store queues are available) */ + fprintf(stderr, "Unauthorized access\n"); + return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE : + MMU_DTLB_MISS_READ; + } + /* Mask upper 3 bits */ + *physical = address & 0x1FFFFFFF; + *prot = PAGE_READ | PAGE_WRITE; + return MMU_OK; + } + + /* If MMU is disabled, return the corresponding physical page */ + if (!env->mmucr & MMUCR_AT) { + *physical = address & 0x1FFFFFFF; + *prot = PAGE_READ | PAGE_WRITE; + return MMU_OK; + } + + /* We need to resort to the MMU */ + return get_mmu_address(env, physical, prot, address, rw, access_type); +} + +int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + target_ulong physical, page_offset, page_size; + int prot, ret, access_type; + + /* XXXXX */ +#if 0 + fprintf(stderr, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n", + __func__, env->pc, address, rw, is_user, is_softmmu); +#endif + + access_type = ACCESS_INT; + ret = + get_physical_address(env, &physical, &prot, address, rw, + access_type); + + if (ret != MMU_OK) { + env->tea = address; + switch (ret) { + case MMU_ITLB_MISS: + case MMU_DTLB_MISS_READ: + env->exception_index = 0x040; + break; + case MMU_DTLB_MULTIPLE: + case MMU_ITLB_MULTIPLE: + env->exception_index = 0x140; + break; + case MMU_ITLB_VIOLATION: + env->exception_index = 0x0a0; + break; + case MMU_DTLB_MISS_WRITE: + env->exception_index = 0x060; + break; + case MMU_DTLB_INITIAL_WRITE: + env->exception_index = 0x080; + break; + case MMU_DTLB_VIOLATION_READ: + env->exception_index = 0x0a0; + break; + case MMU_DTLB_VIOLATION_WRITE: + env->exception_index = 0x0c0; + break; + default: + assert(0); + } + return 1; + } + + page_size = TARGET_PAGE_SIZE; + page_offset = + (address - (address & TARGET_PAGE_MASK)) & ~(page_size - 1); + address = (address & TARGET_PAGE_MASK) + page_offset; + physical = (physical & TARGET_PAGE_MASK) + page_offset; + + return tlb_set_page(env, address, physical, prot, is_user, is_softmmu); +} diff --git a/target-sh4/op.c b/target-sh4/op.c new file mode 100644 index 000000000..dbab658db --- /dev/null +++ b/target-sh4/op.c @@ -0,0 +1,882 @@ +/* + * SH4 emulation + * + * Copyright (c) 2005 Samuel Tardieu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "exec.h" + +static inline void set_flag(uint32_t flag) +{ + env->flags |= flag; +} + +static inline void clr_flag(uint32_t flag) +{ + env->flags &= ~flag; +} + +static inline void set_t(void) +{ + env->sr |= SR_T; +} + +static inline void clr_t(void) +{ + env->sr &= ~SR_T; +} + +static inline void cond_t(int cond) +{ + if (cond) + set_t(); + else + clr_t(); +} + +void OPPROTO op_movl_imm_T0(void) +{ + T0 = (uint32_t) PARAM1; + RETURN(); +} + +void OPPROTO op_movl_imm_T1(void) +{ + T0 = (uint32_t) PARAM1; + RETURN(); +} + +void OPPROTO op_movl_imm_T2(void) +{ + T0 = (uint32_t) PARAM1; + RETURN(); +} + +void OPPROTO op_cmp_eq_imm_T0(void) +{ + cond_t((int32_t) T0 == (int32_t) PARAM1); + RETURN(); +} + +void OPPROTO op_cmd_eq_T0_T1(void) +{ + cond_t(T0 == T1); + RETURN(); +} + +void OPPROTO op_cmd_hs_T0_T1(void) +{ + cond_t((uint32_t) T0 <= (uint32_t) T1); + RETURN(); +} + +void OPPROTO op_cmd_ge_T0_T1(void) +{ + cond_t((int32_t) T0 <= (int32_t) T1); + RETURN(); +} + +void OPPROTO op_cmd_hi_T0_T1(void) +{ + cond_t((uint32_t) T0 < (uint32_t) T1); + RETURN(); +} + +void OPPROTO op_cmd_gt_T0_T1(void) +{ + cond_t((int32_t) T0 < (int32_t) T1); + RETURN(); +} + +void OPPROTO op_not_T0(void) +{ + T0 = ~T0; + RETURN(); +} + +void OPPROTO op_bf_s(void) +{ + T2 = ~env->sr; + env->delayed_pc = PARAM1; + set_flag(DELAY_SLOT_CONDITIONAL); + RETURN(); +} + +void OPPROTO op_bt_s(void) +{ + T2 = env->sr; + env->delayed_pc = PARAM1; + set_flag(DELAY_SLOT_CONDITIONAL); + RETURN(); +} + +void OPPROTO op_bra(void) +{ + env->delayed_pc = PARAM1; + set_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_braf_T0(void) +{ + env->delayed_pc = PARAM1 + T0; + set_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_bsr(void) +{ + env->pr = PARAM1; + env->delayed_pc = PARAM2; + set_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_bsrf_T0(void) +{ + env->pr = PARAM1; + env->delayed_pc = PARAM1 + T0; + set_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_jsr_T0(void) +{ + env->pr = PARAM1; + env->delayed_pc = T0; + set_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_rts(void) +{ + env->delayed_pc = env->pr; + set_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_clr_delay_slot(void) +{ + clr_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_clr_delay_slot_conditional(void) +{ + clr_flag(DELAY_SLOT_CONDITIONAL); + RETURN(); +} + +void OPPROTO op_exit_tb(void) +{ + EXIT_TB(); + RETURN(); +} + +void OPPROTO op_addl_imm_T0(void) +{ + T0 += PARAM1; + RETURN(); +} + +void OPPROTO op_addl_imm_T1(void) +{ + T1 += PARAM1; + RETURN(); +} + +void OPPROTO op_clrmac(void) +{ + env->mach = env->macl = 0; + RETURN(); +} + +void OPPROTO op_clrs(void) +{ + env->sr &= ~SR_S; + RETURN(); +} + +void OPPROTO op_clrt(void) +{ + env->sr &= ~SR_T; + RETURN(); +} + +void OPPROTO op_sets(void) +{ + env->sr |= SR_S; + RETURN(); +} + +void OPPROTO op_sett(void) +{ + env->sr |= SR_T; + RETURN(); +} + +void OPPROTO op_rte(void) +{ + env->sr = env->ssr; + env->delayed_pc = env->spc; + set_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_swapb_T0(void) +{ + T0 = (T0 & 0xffff0000) | ((T0 & 0xff) << 8) | ((T0 >> 8) & 0xff); + RETURN(); +} + +void OPPROTO op_swapw_T0(void) +{ + T0 = ((T0 & 0xffff) << 16) | ((T0 >> 16) & 0xffff); + RETURN(); +} + +void OPPROTO op_xtrct_T0_T1(void) +{ + T1 = ((T0 & 0xffff) << 16) | ((T1 >> 16) & 0xffff); + RETURN(); +} + +void OPPROTO op_addc_T0_T1(void) +{ + helper_addc_T0_T1(); + RETURN(); +} + +void OPPROTO op_addv_T0_T1(void) +{ + helper_addv_T0_T1(); + RETURN(); +} + +void OPPROTO op_cmp_eq_T0_T1(void) +{ + cond_t(T1 == T0); + RETURN(); +} + +void OPPROTO op_cmp_ge_T0_T1(void) +{ + cond_t((int32_t) T1 >= (int32_t) T0); + RETURN(); +} + +void OPPROTO op_cmp_gt_T0_T1(void) +{ + cond_t((int32_t) T1 > (int32_t) T0); + RETURN(); +} + +void OPPROTO op_cmp_hi_T0_T1(void) +{ + cond_t((uint32_t) T1 > (uint32_t) T0); + RETURN(); +} + +void OPPROTO op_cmp_hs_T0_T1(void) +{ + cond_t((uint32_t) T1 >= (uint32_t) T0); + RETURN(); +} + +void OPPROTO op_cmp_str_T0_T1(void) +{ + cond_t((T0 & 0x000000ff) == (T1 & 0x000000ff) || + (T0 & 0x0000ff00) == (T1 & 0x0000ff00) || + (T0 & 0x00ff0000) == (T1 & 0x00ff0000) || + (T0 & 0xff000000) == (T1 & 0xff000000)); + RETURN(); +} + +void OPPROTO op_tst_T0_T1(void) +{ + cond_t((T1 & T0) == 0); + RETURN(); +} + +void OPPROTO op_div0s_T0_T1(void) +{ + if (T1 & 0x80000000) + env->sr |= SR_Q; + else + env->sr &= ~SR_Q; + if (T0 & 0x80000000) + env->sr |= SR_M; + else + env->sr &= ~SR_M; + cond_t((T1 ^ T0) & 0x80000000); + RETURN(); +} + +void OPPROTO op_div0u(void) +{ + env->sr &= ~(SR_M | SR_Q | SR_T); + RETURN(); +} + +void OPPROTO op_div1_T0_T1(void) +{ + helper_div1_T0_T1(); + RETURN(); +} + +void OPPROTO op_dmulsl_T0_T1(void) +{ + helper_dmulsl_T0_T1(); + RETURN(); +} + +void OPPROTO op_dmulul_T0_T1(void) +{ + helper_dmulul_T0_T1(); + RETURN(); +} + +void OPPROTO op_macl_T0_T1(void) +{ + helper_macl_T0_T1(); + RETURN(); +} + +void OPPROTO op_macw_T0_T1(void) +{ + helper_macw_T0_T1(); + RETURN(); +} + +void OPPROTO op_mull_T0_T1(void) +{ + env->macl = (T0 * T1) & 0xffffffff; + RETURN(); +} + +void OPPROTO op_mulsw_T0_T1(void) +{ + env->macl = (int32_t) T0 *(int32_t) T1; + RETURN(); +} + +void OPPROTO op_muluw_T0_T1(void) +{ + env->macl = (uint32_t) T0 *(uint32_t) T1; + RETURN(); +} + +void OPPROTO op_neg_T0(void) +{ + T0 = -T0; + RETURN(); +} + +void OPPROTO op_negc_T0(void) +{ + helper_negc_T0(); + RETURN(); +} + +void OPPROTO op_shad_T0_T1(void) +{ + if ((T0 & 0x80000000) == 0) + T1 <<= (T0 & 0x1f); + else if ((T0 & 0x1f) == 0) + T1 = 0; + else + T1 = ((int32_t) T1) >> ((~T0 & 0x1f) + 1); + RETURN(); +} + +void OPPROTO op_shld_T0_T1(void) +{ + if ((T0 & 0x80000000) == 0) + T1 <<= (T0 & 0x1f); + else if ((T0 & 0x1f) == 0) + T1 = 0; + else + T1 = ((uint32_t) T1) >> ((~T0 & 0x1f) + 1); + RETURN(); +} + +void OPPROTO op_subc_T0_T1(void) +{ + helper_subc_T0_T1(); + RETURN(); +} + +void OPPROTO op_subv_T0_T1(void) +{ + helper_subv_T0_T1(); + RETURN(); +} + +void OPPROTO op_trapa(void) +{ + env->tra = PARAM1 * 2; + env->exception_index = 0x160; + do_raise_exception(); + RETURN(); +} + +void OPPROTO op_cmp_pl_T0(void) +{ + cond_t((int32_t) T0 > 0); + RETURN(); +} + +void OPPROTO op_cmp_pz_T0(void) +{ + cond_t((int32_t) T0 >= 0); + RETURN(); +} + +void OPPROTO op_jmp_T0(void) +{ + env->delayed_pc = T0; + set_flag(DELAY_SLOT); + RETURN(); +} + +void OPPROTO op_movl_rN_rN(void) +{ + env->gregs[PARAM2] = env->gregs[PARAM1]; + RETURN(); +} + +void OPPROTO op_ldcl_rMplus_rN_bank(void) +{ + env->gregs[PARAM2] = env->gregs[PARAM1]; + env->gregs[PARAM1] += 4; + RETURN(); +} + +#define LDSTOPS(target,load,store) \ +void OPPROTO op_##load##_T0_##target (void) \ +{ env ->target = T0; RETURN(); \ +} \ +void OPPROTO op_##store##_##target##_T0 (void) \ +{ T0 = env->target; RETURN(); \ +} \ + +LDSTOPS(sr, ldc, stc) + LDSTOPS(gbr, ldc, stc) + LDSTOPS(vbr, ldc, stc) + LDSTOPS(ssr, ldc, stc) + LDSTOPS(spc, ldc, stc) + LDSTOPS(sgr, ldc, stc) + LDSTOPS(dbr, ldc, stc) + LDSTOPS(mach, lds, sts) + LDSTOPS(macl, lds, sts) + LDSTOPS(pr, lds, sts) + +void OPPROTO op_movt_rN(void) +{ + env->gregs[PARAM1] = env->sr & SR_T; + RETURN(); +} + +void OPPROTO op_rotcl_Rn(void) +{ + helper_rotcl(&env->gregs[PARAM1]); + RETURN(); +} + +void OPPROTO op_rotcr_Rn(void) +{ + helper_rotcr(&env->gregs[PARAM1]); + RETURN(); +} + +void OPPROTO op_rotl_Rn(void) +{ + cond_t(env->gregs[PARAM1] & 0x80000000); + env->gregs[PARAM1] = (env->gregs[PARAM1] << 1) | (env->sr & SR_T); + RETURN(); +} + +void OPPROTO op_rotr_Rn(void) +{ + cond_t(env->gregs[PARAM1] & 1); + env->gregs[PARAM1] = (env->gregs[PARAM1] >> 1) | + ((env->sr & SR_T) ? 0x80000000 : 0); + RETURN(); +} + +void OPPROTO op_shal_Rn(void) +{ + cond_t(env->gregs[PARAM1] & 0x80000000); + env->gregs[PARAM1] <<= 1; + RETURN(); +} + +void OPPROTO op_shar_Rn(void) +{ + cond_t(env->gregs[PARAM1] & 1); + *(int32_t *) & env->gregs[PARAM1] >>= 1; + RETURN(); +} + +void OPPROTO op_shlr_Rn(void) +{ + cond_t(env->gregs[PARAM1] & 1); + *(uint32_t *) & env->gregs[PARAM1] >>= 1; + RETURN(); +} + +void OPPROTO op_shll2_Rn(void) +{ + env->gregs[PARAM1] <<= 2; + RETURN(); +} + +void OPPROTO op_shll8_Rn(void) +{ + env->gregs[PARAM1] <<= 8; + RETURN(); +} + +void OPPROTO op_shll16_Rn(void) +{ + env->gregs[PARAM1] <<= 16; + RETURN(); +} + +void OPPROTO op_shlr2_Rn(void) +{ + *(uint32_t *) & env->gregs[PARAM1] >>= 2; + RETURN(); +} + +void OPPROTO op_shlr8_Rn(void) +{ + *(uint32_t *) & env->gregs[PARAM1] >>= 8; + RETURN(); +} + +void OPPROTO op_shlr16_Rn(void) +{ + *(uint32_t *) & env->gregs[PARAM1] >>= 16; + RETURN(); +} + +void OPPROTO op_tasb_rN(void) +{ + cond_t(*(int8_t *) env->gregs[PARAM1] == 0); + *(int8_t *) env->gregs[PARAM1] |= 0x80; + RETURN(); +} + +void OPPROTO op_movl_T0_rN(void) +{ + env->gregs[PARAM1] = T0; + RETURN(); +} + +void OPPROTO op_movl_T1_rN(void) +{ + env->gregs[PARAM1] = T1; + RETURN(); +} + +void OPPROTO op_movb_rN_T0(void) +{ + T0 = (int32_t) (int8_t) (env->gregs[PARAM1] & 0xff); + RETURN(); +} + +void OPPROTO op_movub_rN_T0(void) +{ + T0 = env->gregs[PARAM1] & 0xff; + RETURN(); +} + +void OPPROTO op_movw_rN_T0(void) +{ + T0 = (int32_t) (int16_t) (env->gregs[PARAM1] & 0xffff); + RETURN(); +} + +void OPPROTO op_movuw_rN_T0(void) +{ + T0 = env->gregs[PARAM1] & 0xffff; + RETURN(); +} + +void OPPROTO op_movl_rN_T0(void) +{ + T0 = env->gregs[PARAM1]; + RETURN(); +} + +void OPPROTO op_movb_rN_T1(void) +{ + T1 = (int32_t) (int8_t) (env->gregs[PARAM1] & 0xff); + RETURN(); +} + +void OPPROTO op_movub_rN_T1(void) +{ + T1 = env->gregs[PARAM1] & 0xff; + RETURN(); +} + +void OPPROTO op_movw_rN_T1(void) +{ + T1 = (int32_t) (int16_t) (env->gregs[PARAM1] & 0xffff); + RETURN(); +} + +void OPPROTO op_movuw_rN_T1(void) +{ + T1 = env->gregs[PARAM1] & 0xffff; + RETURN(); +} + +void OPPROTO op_movl_rN_T1(void) +{ + T1 = env->gregs[PARAM1]; + RETURN(); +} + +void OPPROTO op_movl_imm_rN(void) +{ + env->gregs[PARAM2] = PARAM1; + RETURN(); +} + +void OPPROTO op_dec1_rN(void) +{ + env->gregs[PARAM1] -= 1; + RETURN(); +} + +void OPPROTO op_dec2_rN(void) +{ + env->gregs[PARAM1] -= 2; + RETURN(); +} + +void OPPROTO op_dec4_rN(void) +{ + env->gregs[PARAM1] -= 4; + RETURN(); +} + +void OPPROTO op_inc1_rN(void) +{ + env->gregs[PARAM1] += 1; + RETURN(); +} + +void OPPROTO op_inc2_rN(void) +{ + env->gregs[PARAM1] += 2; + RETURN(); +} + +void OPPROTO op_inc4_rN(void) +{ + env->gregs[PARAM1] += 4; + RETURN(); +} + +void OPPROTO op_add_T0_rN(void) +{ + env->gregs[PARAM1] += T0; + RETURN(); +} + +void OPPROTO op_sub_T0_rN(void) +{ + env->gregs[PARAM1] -= T0; + RETURN(); +} + +void OPPROTO op_and_T0_rN(void) +{ + env->gregs[PARAM1] &= T0; + RETURN(); +} + +void OPPROTO op_or_T0_rN(void) +{ + env->gregs[PARAM1] |= T0; + RETURN(); +} + +void OPPROTO op_xor_T0_rN(void) +{ + env->gregs[PARAM1] ^= T0; + RETURN(); +} + +void OPPROTO op_add_rN_T0(void) +{ + T0 += env->gregs[PARAM1]; + RETURN(); +} + +void OPPROTO op_add_rN_T1(void) +{ + T1 += env->gregs[PARAM1]; + RETURN(); +} + +void OPPROTO op_add_imm_rN(void) +{ + env->gregs[PARAM2] += PARAM1; + RETURN(); +} + +void OPPROTO op_and_imm_rN(void) +{ + env->gregs[PARAM2] &= PARAM1; + RETURN(); +} + +void OPPROTO op_or_imm_rN(void) +{ + env->gregs[PARAM2] |= PARAM1; + RETURN(); +} + +void OPPROTO op_xor_imm_rN(void) +{ + env->gregs[PARAM2] ^= PARAM1; + RETURN(); +} + +void OPPROTO op_dt_rN(void) +{ + cond_t((--env->gregs[PARAM1]) == 0); + RETURN(); +} + +void OPPROTO op_tst_imm_rN(void) +{ + cond_t((env->gregs[PARAM2] & PARAM1) == 0); + RETURN(); +} + +void OPPROTO op_movl_T0_T1(void) +{ + T1 = T0; + RETURN(); +} + +void OPPROTO op_goto_tb0(void) +{ + GOTO_TB(op_goto_tb0, PARAM1, 0); + RETURN(); +} + +void OPPROTO op_goto_tb1(void) +{ + GOTO_TB(op_goto_tb1, PARAM1, 1); + RETURN(); +} + +void OPPROTO op_movl_imm_PC(void) +{ + env->pc = PARAM1; + RETURN(); +} + +void OPPROTO op_jT(void) +{ + if (env->sr & SR_T) + GOTO_LABEL_PARAM(1); + RETURN(); +} + +void OPPROTO op_jTT2(void) +{ + if (T2 & SR_T) + GOTO_LABEL_PARAM(1); + RETURN(); +} + +void OPPROTO op_movl_delayed_pc_PC(void) +{ + env->pc = env->delayed_pc; + RETURN(); +} + +void OPPROTO op_addl_GBR_T0(void) +{ + T0 += env->gbr; + RETURN(); +} + +void OPPROTO op_and_imm_T0(void) +{ + T0 &= PARAM1; + RETURN(); +} + +void OPPROTO op_or_imm_T0(void) +{ + T0 |= PARAM1; + RETURN(); +} + +void OPPROTO op_xor_imm_T0(void) +{ + T0 ^= PARAM1; + RETURN(); +} + +void OPPROTO op_tst_imm_T0(void) +{ + cond_t((T0 & PARAM1) == 0); + RETURN(); +} + +void OPPROTO op_raise_illegal_instruction(void) +{ + env->exception_index = 0x180; + do_raise_exception(); + RETURN(); +} + +void OPPROTO op_raise_slot_illegal_instruction(void) +{ + env->exception_index = 0x1a0; + do_raise_exception(); + RETURN(); +} + +void OPPROTO op_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + +/* Load and store */ +#define MEMSUFFIX _raw +#include "op_mem.c" +#undef MEMSUFFIX +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_mem.c" +#undef MEMSUFFIX + +#define MEMSUFFIX _kernel +#include "op_mem.c" +#undef MEMSUFFIX +#endif diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c new file mode 100644 index 000000000..1c63fe587 --- /dev/null +++ b/target-sh4/op_helper.c @@ -0,0 +1,372 @@ +/* + * SH4 emulation + * + * Copyright (c) 2005 Samuel Tardieu + * + * 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 +#include "exec.h" + +void cpu_loop_exit(void) +{ + longjmp(env->jmp_env, 1); +} + +void do_raise_exception(void) +{ + cpu_loop_exit(); +} + +#ifndef CONFIG_USER_ONLY + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + unsigned long pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (ret) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long) retaddr; + 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, NULL); + } + } + do_raise_exception(); + } + env = saved_env; +} + +#endif + +void helper_addc_T0_T1(void) +{ + uint32_t tmp0, tmp1; + + tmp1 = T0 + T1; + tmp0 = T1; + T1 = tmp1 + (env->sr & 1); + if (tmp0 > tmp1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + if (tmp1 > T1) + env->sr |= SR_T; +} + +void helper_addv_T0_T1(void) +{ + uint32_t dest, src, ans; + + if ((int32_t) T1 >= 0) + dest = 0; + else + dest = 1; + if ((int32_t) T0 >= 0) + src = 0; + else + src = 1; + src += dest; + T1 += T0; + if ((int32_t) T1 >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 0 || src == 2) { + if (ans == 1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + } else + env->sr &= ~SR_T; +} + +#define T (env->sr & SR_T) +#define Q (env->sr & SR_Q ? 1 : 0) +#define M (env->sr & SR_M ? 1 : 0) +#define SETT env->sr |= SR_T +#define CLRT env->sr &= ~SR_T +#define SETQ env->sr |= SR_Q +#define CLRQ env->sr &= ~SR_Q +#define SETM env->sr |= SR_M +#define CLRM env->sr &= ~SR_M + +void helper_div1_T0_T1(void) +{ + uint32_t tmp0, tmp2; + uint8_t old_q, tmp1 = 0xff; + + printf("div1 T0=0x%08x T1=0x%08x M=%d Q=%d T=%d\n", T0, T1, M, Q, T); + old_q = Q; + if ((0x80000000 & T1) != 0) + SETQ; + else + CLRQ; + tmp2 = T0; + T1 <<= 1; + T1 |= T; + switch (old_q) { + case 0: + switch (M) { + case 0: + tmp0 = T1; + T1 -= tmp2; + tmp1 = T1 > tmp0; + switch (Q) { + case 0: + if (tmp1) + SETQ; + else + CLRQ; + break; + case 1: + if (tmp1 == 0) + SETQ; + else + CLRQ; + break; + } + break; + case 1: + tmp0 = T1; + T1 += tmp2; + tmp1 = T1 < tmp0; + switch (Q) { + case 0: + if (tmp1 == 0) + SETQ; + else + CLRQ; + break; + case 1: + if (tmp1) + SETQ; + else + CLRQ; + break; + } + break; + } + break; + case 1: + switch (M) { + case 0: + tmp0 = T1; + T1 += tmp2; + tmp1 = T1 < tmp0; + switch (Q) { + case 0: + if (tmp1) + SETQ; + else + CLRQ; + break; + case 1: + if (tmp1 == 0) + SETQ; + else + CLRQ; + break; + } + break; + case 1: + tmp0 = T1; + T1 -= tmp2; + tmp1 = T1 > tmp0; + switch (Q) { + case 0: + if (tmp1 == 0) + SETQ; + else + CLRQ; + break; + case 1: + if (tmp1) + SETQ; + else + CLRQ; + break; + } + break; + } + break; + } + if (Q == M) + SETT; + else + CLRT; + printf("Output: T1=0x%08x M=%d Q=%d T=%d\n", T1, M, Q, T); +} + +void helper_dmulsl_T0_T1() +{ + int64_t res; + + res = (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1; + env->mach = (res >> 32) & 0xffffffff; + env->macl = res & 0xffffffff; +} + +void helper_dmulul_T0_T1() +{ + uint64_t res; + + res = (uint64_t) (uint32_t) T0 *(uint64_t) (uint32_t) T1; + env->mach = (res >> 32) & 0xffffffff; + env->macl = res & 0xffffffff; +} + +void helper_macl_T0_T1() +{ + int64_t res; + + res = ((uint64_t) env->mach << 32) | env->macl; + res += (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1; + env->mach = (res >> 32) & 0xffffffff; + env->macl = res & 0xffffffff; + if (env->sr & SR_S) { + if (res < 0) + env->mach |= 0xffff0000; + else + env->mach &= 0x00007fff; + } +} + +void helper_macw_T0_T1() +{ + int64_t res; + + res = ((uint64_t) env->mach << 32) | env->macl; + res += (int64_t) (int16_t) T0 *(int64_t) (int16_t) T1; + env->mach = (res >> 32) & 0xffffffff; + env->macl = res & 0xffffffff; + if (env->sr & SR_S) { + if (res < -0x80000000) { + env->mach = 1; + env->macl = 0x80000000; + } else if (res > 0x000000007fffffff) { + env->mach = 1; + env->macl = 0x7fffffff; + } + } +} + +void helper_negc_T0() +{ + uint32_t temp; + + temp = -T0; + T0 = temp - (env->sr & SR_T); + if (0 < temp) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + if (temp < T0) + env->sr |= SR_T; +} + +void helper_subc_T0_T1() +{ + uint32_t tmp0, tmp1; + + tmp1 = T1 - T0; + tmp0 = T1; + T1 = tmp1 - (env->sr & SR_T); + if (tmp0 < tmp1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + if (tmp1 < T1) + env->sr |= SR_T; +} + +void helper_subv_T0_T1() +{ + int32_t dest, src, ans; + + if ((int32_t) T1 >= 0) + dest = 0; + else + dest = 1; + if ((int32_t) T0 >= 0) + src = 0; + else + src = 1; + src += dest; + T1 -= T0; + if ((int32_t) T1 >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 1) { + if (ans == 1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + } else + env->sr &= ~SR_T; +} + +void helper_rotcl(uint32_t * addr) +{ + uint32_t new; + + new = (*addr << 1) | (env->sr & SR_T); + if (*addr & 0x80000000) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + *addr = new; +} + +void helper_rotcr(uint32_t * addr) +{ + uint32_t new; + + new = (*addr >> 1) | ((env->sr & SR_T) ? 0x80000000 : 0); + if (*addr & 1) + env->sr |= SR_T; + else + env->sr &= ~SR_T; + *addr = new; +} diff --git a/target-sh4/op_mem.c b/target-sh4/op_mem.c new file mode 100644 index 000000000..9ab75f4ce --- /dev/null +++ b/target-sh4/op_mem.c @@ -0,0 +1,58 @@ +/* + * SH4 emulation + * + * Copyright (c) 2005 Samuel Tardieu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +void glue(op_ldb_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldsb, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_ldub_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldub, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stb_T0_T1, MEMSUFFIX) (void) { + glue(stb, MEMSUFFIX) (T1, T0); + RETURN(); +} + +void glue(op_ldw_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldsw, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_lduw_T0_T0, MEMSUFFIX) (void) { + T0 = glue(lduw, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stw_T0_T1, MEMSUFFIX) (void) { + glue(stw, MEMSUFFIX) (T1, T0); + RETURN(); +} + +void glue(op_ldl_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldl, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stl_T0_T1, MEMSUFFIX) (void) { + glue(stl, MEMSUFFIX) (T1, T0); + RETURN(); +} diff --git a/target-sh4/translate.c b/target-sh4/translate.c new file mode 100644 index 000000000..0013e492d --- /dev/null +++ b/target-sh4/translate.c @@ -0,0 +1,1073 @@ +/* + * SH4 translation + * + * Copyright (c) 2005 Samuel Tardieu + * + * 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 +#include +#include +#include +#include +#include + +#define DEBUG_DISAS +#define SH4_DEBUG_DISAS +//#define SH4_SINGLE_STEP + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) ((long)(x)) +#endif + +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; + +#include "gen-op.h" + +typedef struct DisasContext { + struct TranslationBlock *tb; + target_ulong pc; + uint32_t sr; + uint16_t opcode; + uint32_t flags; + int memidx; + uint32_t delayed_pc; + int singlestep_enabled; +} DisasContext; + +#ifdef CONFIG_USER_ONLY + +#define GEN_OP_LD(width) \ + void gen_op_ld##width##_T0_T0 (DisasContext *ctx) { \ + gen_op_ld##width##_T0_T0_raw(); \ + } +#define GEN_OP_ST(width) \ + void gen_op_st##width##_T0_T1 (DisasContext *ctx) { \ + gen_op_st##width##_T0_T1_raw(); \ + } + +#else + +#define GEN_OP_LD(width) \ + void gen_op_ld##width##_T0_T0 (DisasContext *ctx) { \ + if (ctx->memidx) gen_op_ld##width##_T0_T0_kernel(); \ + else gen_op_ld##width##_T0_T0_user();\ + } +#define GEN_OP_ST(width) \ + void gen_op_st##width##_T0_T1 (DisasContext *ctx) { \ + if (ctx->memidx) gen_op_st##width##_T0_T1_kernel(); \ + else gen_op_st##width##_T0_T1_user();\ + } + +#endif + +GEN_OP_LD(ub) + GEN_OP_LD(b) + GEN_OP_ST(b) + GEN_OP_LD(uw) + GEN_OP_LD(w) + GEN_OP_ST(w) + GEN_OP_LD(l) + GEN_OP_ST(l) + +void cpu_dump_state(CPUState * env, FILE * f, + int (*cpu_fprintf) (FILE * f, const char *fmt, ...), + int flags) +{ + int i; + cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x\n", + env->pc, env->sr, env->pr); + for (i = 0; i < 24; i += 4) { + cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n", + i, env->gregs[i], i + 1, env->gregs[i + 1], + i + 2, env->gregs[i + 2], i + 3, env->gregs[i + 3]); + } + if (env->flags & DELAY_SLOT) { + cpu_fprintf(f, "in delay slot (delayed_pc=0x%08x)\n", + env->delayed_pc); + } else if (env->flags & DELAY_SLOT_CONDITIONAL) { + cpu_fprintf(f, "in conditional delay slot (delayed_pc=0x%08x)\n", + env->delayed_pc); + } +} + +void cpu_sh4_reset(CPUSH4State * env) +{ + env->sr = 0x700000F0; /* MD, RB, BL, I3-I0 */ + env->vbr = 0; + env->pc = 0xA0000000; + env->fpscr = 0x00040001; + env->mmucr = 0; +} + +CPUSH4State *cpu_sh4_init(void) +{ + CPUSH4State *env; + + env = qemu_mallocz(sizeof(CPUSH4State)); + if (!env) + return NULL; + cpu_exec_init(env); + cpu_sh4_reset(env); + tlb_flush(env, 1); + return env; +} + +#ifdef CONFIG_USER_ONLY +target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ + return addr; +} +#else +target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ + target_ulong physical; + int prot; + + get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0); + return physical; +} +#endif + +static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) +{ + TranslationBlock *tb; + tb = ctx->tb; + + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && + !ctx->singlestep_enabled) { + /* Use a direct jump if in same page and singlestep not enabled */ + if (n == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_op_movl_imm_T0((long) tb + n); + } else { + gen_op_movl_imm_T0(0); + } + gen_op_movl_imm_PC(dest); + if (ctx->singlestep_enabled) + gen_op_debug(); + gen_op_exit_tb(); +} + +/* Jump to pc after an exception */ +static void gen_jump_exception(DisasContext * ctx) +{ + gen_op_movl_imm_T0(0); + if (ctx->singlestep_enabled) + gen_op_debug(); + gen_op_exit_tb(); +} + +static void gen_jump(DisasContext * ctx) +{ + if (ctx->delayed_pc == (uint32_t) - 1) { + /* Target is not statically known, it comes necessarily from a + delayed jump as immediate jump are conditinal jumps */ + gen_op_movl_delayed_pc_PC(); + gen_op_movl_imm_T0(0); + if (ctx->singlestep_enabled) + gen_op_debug(); + gen_op_exit_tb(); + } else { + gen_goto_tb(ctx, 0, ctx->delayed_pc); + } +} + +/* Immediate conditional jump (bt or bf) */ +static void gen_conditional_jump(DisasContext * ctx, + target_ulong ift, target_ulong ifnott) +{ + int l1; + + l1 = gen_new_label(); + gen_op_jT(l1); + gen_goto_tb(ctx, 0, ifnott); + gen_set_label(l1); + gen_goto_tb(ctx, 1, ift); +} + +/* Delayed conditional jump (bt or bf) */ +static void gen_delayed_conditional_jump(DisasContext * ctx) +{ + int l1; + + l1 = gen_new_label(); + gen_op_jTT2(l1); + gen_goto_tb(ctx, 0, ctx->pc); + gen_set_label(l1); + gen_goto_tb(ctx, 1, ctx->delayed_pc); +} + +#define B3_0 (ctx->opcode & 0xf) +#define B6_4 ((ctx->opcode >> 4) & 0x7) +#define B7_4 ((ctx->opcode >> 4) & 0xf) +#define B7_0 (ctx->opcode & 0xff) +#define B7_0s ((int32_t) (int8_t) (ctx->opcode & 0xff)) +#define B11_0s (ctx->opcode & 0x800 ? 0xfffff000 | (ctx->opcode & 0xfff) : \ + (ctx->opcode & 0xfff)) +#define B11_8 ((ctx->opcode >> 8) & 0xf) +#define B15_12 ((ctx->opcode >> 12) & 0xf) + +#define REG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB) ? \ + (x) + 16 : (x)) + +#define ALTREG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) != (SR_MD | SR_RB) \ + ? (x) + 16 : (x)) + +#define CHECK_NOT_DELAY_SLOT \ + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ + {gen_op_raise_slot_illegal_instruction (); ctx->flags |= BRANCH_EXCEPTION; \ + return;} + +void decode_opc(DisasContext * ctx) +{ +#if 0 + fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); +#endif + switch (ctx->opcode) { + case 0x0019: /* div0u */ + printf("div0u\n"); + gen_op_div0u(); + return; + case 0x000b: /* rts */ + CHECK_NOT_DELAY_SLOT gen_op_rts(); + ctx->flags |= DELAY_SLOT; + ctx->delayed_pc = (uint32_t) - 1; + return; + case 0x0028: /* clrmac */ + gen_op_clrmac(); + return; + case 0x0048: /* clrs */ + gen_op_clrs(); + return; + case 0x0008: /* clrt */ + gen_op_clrt(); + return; + case 0x0038: /* ldtlb */ + assert(0); /* XXXXX */ + return; + case 0x004b: /* rte */ + CHECK_NOT_DELAY_SLOT gen_op_rte(); + ctx->flags |= DELAY_SLOT; + ctx->delayed_pc = (uint32_t) - 1; + return; + case 0x0058: /* sets */ + gen_op_sets(); + return; + case 0x0018: /* sett */ + gen_op_sett(); + return; + case 0xfbfb: /* frchg */ + assert(0); /* XXXXX */ + return; + case 0xf3fb: /* fschg */ + assert(0); /* XXXXX */ + return; + case 0x0009: /* nop */ + return; + case 0x001b: /* sleep */ + assert(0); /* XXXXX */ + return; + } + + switch (ctx->opcode & 0xf000) { + case 0x1000: /* mov.l Rm,@(disp,Rn) */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_addl_imm_T1(B3_0 * 4); + gen_op_stl_T0_T1(ctx); + return; + case 0x5000: /* mov.l @(disp,Rm),Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_addl_imm_T0(B3_0 * 4); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0xe000: /* mov.l #imm,Rn */ + gen_op_movl_imm_rN(B7_0s, REG(B11_8)); + return; + case 0x9000: /* mov.w @(disp,PC),Rn */ + gen_op_movl_imm_T0(ctx->pc + 4 + B7_0 * 2); + gen_op_ldw_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0xd000: /* mov.l @(disp,PC),Rn */ + gen_op_movl_imm_T0((ctx->pc + 4 + B7_0 * 4) & ~3); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x7000: /* add.l #imm,Rn */ + gen_op_add_imm_rN(B7_0s, REG(B11_8)); + return; + case 0xa000: /* bra disp */ + CHECK_NOT_DELAY_SLOT + gen_op_bra(ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2); + ctx->flags |= DELAY_SLOT; + return; + case 0xb000: /* bsr disp */ + CHECK_NOT_DELAY_SLOT + gen_op_bsr(ctx->pc + 4, ctx->delayed_pc = + ctx->pc + 4 + B11_0s * 2); + ctx->flags |= DELAY_SLOT; + return; + } + + switch (ctx->opcode & 0xf00f) { + case 0x6003: /* mov Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x2000: /* mov.b Rm,@Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stb_T0_T1(ctx); + return; + case 0x2001: /* mov.w Rm,@Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stw_T0_T1(ctx); + return; + case 0x2002: /* mov.l Rm,@Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stl_T0_T1(ctx); + return; + case 0x6000: /* mov.b @Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldb_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x6001: /* mov.w @Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldw_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x6002: /* mov.l @Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x2004: /* mov.b Rm,@-Rn */ + gen_op_dec1_rN(REG(B11_8)); + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stb_T0_T1(ctx); + return; + case 0x2005: /* mov.w Rm,@-Rn */ + gen_op_dec2_rN(REG(B11_8)); + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stw_T0_T1(ctx); + return; + case 0x2006: /* mov.l Rm,@-Rn */ + gen_op_dec4_rN(REG(B11_8)); + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stl_T0_T1(ctx); + return; + case 0x6004: /* mov.l @Rm+,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldb_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + gen_op_inc1_rN(REG(B7_4)); + return; + case 0x6005: /* mov.w @Rm+,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldw_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + gen_op_inc2_rN(REG(B7_4)); + return; + case 0x6006: /* mov.l @Rm+,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + gen_op_inc4_rN(REG(B7_4)); + return; + case 0x0004: /* mov.b Rm,@(R0,Rn) */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_add_rN_T1(REG(0)); + gen_op_stb_T0_T1(ctx); + return; + case 0x0005: /* mov.w Rm,@(R0,Rn) */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_add_rN_T1(REG(0)); + gen_op_stw_T0_T1(ctx); + return; + case 0x0006: /* mov.l Rm,@(R0,Rn) */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_add_rN_T1(REG(0)); + gen_op_stl_T0_T1(ctx); + return; + case 0x000c: /* mov.b @(R0,Rm),Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_add_rN_T0(REG(0)); + gen_op_ldb_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x000d: /* mov.w @(R0,Rm),Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_add_rN_T0(REG(0)); + gen_op_ldw_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x000e: /* mov.l @(R0,Rm),Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_add_rN_T0(REG(0)); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x6008: /* swap.b Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_swapb_T0(); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x6009: /* swap.w Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_swapw_T0(); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x200d: /* xtrct Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_xtrct_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x300c: /* add Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_add_T0_rN(REG(B11_8)); + return; + case 0x300e: /* addc Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_addc_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x300f: /* addv Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_addv_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x2009: /* and Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_and_T0_rN(REG(B11_8)); + return; + case 0x3000: /* cmp/eq Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_cmp_eq_T0_T1(); + return; + case 0x3003: /* cmp/ge Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_cmp_ge_T0_T1(); + return; + case 0x3007: /* cmp/gt Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_cmp_gt_T0_T1(); + return; + case 0x3006: /* cmp/hi Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_cmp_hi_T0_T1(); + return; + case 0x3002: /* cmp/hs Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_cmp_hs_T0_T1(); + return; + case 0x200c: /* cmp/str Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_cmp_str_T0_T1(); + return; + case 0x2007: /* div0s Rm,Rn */ + printf("div0s\n"); + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_div0s_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x3004: /* div1 Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_div1_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x300d: /* dmuls.l Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_dmulsl_T0_T1(); + return; + case 0x3005: /* dmulu.l Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_dmulul_T0_T1(); + return; + case 0x600e: /* exts.b Rm,Rn */ + gen_op_movb_rN_T0(REG(B7_4)); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x600f: /* exts.w Rm,Rn */ + gen_op_movw_rN_T0(REG(B7_4)); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x600c: /* extu.b Rm,Rn */ + gen_op_movub_rN_T0(REG(B7_4)); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x600d: /* extu.w Rm,Rn */ + gen_op_movuw_rN_T0(REG(B7_4)); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x000f: /* mac.l @Rm+,@Rn- */ + gen_op_movl_rN_T0(REG(B11_8)); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_T1(); + gen_op_movl_rN_T1(REG(B7_4)); + gen_op_ldl_T0_T0(ctx); + gen_op_macl_T0_T1(); + gen_op_inc4_rN(REG(B7_4)); + gen_op_inc4_rN(REG(B11_8)); + return; + case 0x400f: /* mac.w @Rm+,@Rn+ */ + gen_op_movl_rN_T0(REG(B11_8)); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_T1(); + gen_op_movl_rN_T1(REG(B7_4)); + gen_op_ldl_T0_T0(ctx); + gen_op_macw_T0_T1(); + gen_op_inc2_rN(REG(B7_4)); + gen_op_inc2_rN(REG(B11_8)); + return; + case 0x0007: /* mul.l Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_mull_T0_T1(); + return; + case 0x200f: /* muls.w Rm,Rn */ + gen_op_movw_rN_T0(REG(B7_4)); + gen_op_movw_rN_T1(REG(B11_8)); + gen_op_mulsw_T0_T1(); + return; + case 0x200e: /* mulu.w Rm,Rn */ + gen_op_movuw_rN_T0(REG(B7_4)); + gen_op_movuw_rN_T1(REG(B11_8)); + gen_op_muluw_T0_T1(); + return; + case 0x600b: /* neg Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_neg_T0(); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x600a: /* negc Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_negc_T0(); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x6007: /* not Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_not_T0(); + gen_op_movl_T0_rN(REG(B11_8)); + return; + case 0x200b: /* or Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_or_T0_rN(REG(B11_8)); + return; + case 0x400c: /* shad Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_shad_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x400d: /* shld Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_shld_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x3008: /* sub Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_sub_T0_rN(REG(B11_8)); + return; + case 0x300a: /* subc Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_subc_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x300b: /* subv Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_subv_T0_T1(); + gen_op_movl_T1_rN(REG(B11_8)); + return; + case 0x2008: /* tst Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_tst_T0_T1(); + return; + case 0x200a: /* xor Rm,Rn */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_xor_T0_rN(REG(B11_8)); + return; + } + + switch (ctx->opcode & 0xff00) { + case 0xc900: /* and #imm,R0 */ + gen_op_and_imm_rN(B7_0, REG(0)); + return; + case 0xcd00: /* and.b #imm,@(R0+GBR) */ + gen_op_movl_rN_T0(REG(0)); + gen_op_addl_GBR_T0(); + gen_op_movl_T0_T1(); + gen_op_ldb_T0_T0(ctx); + gen_op_and_imm_T0(B7_0); + gen_op_stb_T0_T1(ctx); + return; + case 0x8b00: /* bf label */ + CHECK_NOT_DELAY_SLOT + gen_conditional_jump(ctx, ctx->pc + 2, + ctx->pc + 4 + B7_0s * 2); + ctx->flags |= BRANCH_CONDITIONAL; + return; + case 0x8f00: /* bf/s label */ + CHECK_NOT_DELAY_SLOT + gen_op_bf_s(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2); + ctx->flags |= DELAY_SLOT_CONDITIONAL; + return; + case 0x8900: /* bt label */ + CHECK_NOT_DELAY_SLOT + gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, + ctx->pc + 2); + ctx->flags |= BRANCH_CONDITIONAL; + return; + case 0x8d00: /* bt/s label */ + CHECK_NOT_DELAY_SLOT + gen_op_bt_s(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2); + ctx->flags |= DELAY_SLOT_CONDITIONAL; + return; + case 0x8800: /* cmp/eq #imm,R0 */ + gen_op_movl_rN_T0(REG(0)); + gen_op_cmp_eq_imm_T0(B7_0s); + return; + case 0xc400: /* mov.b @(disp,GBR),R0 */ + gen_op_stc_gbr_T0(); + gen_op_addl_imm_T0(B7_0); + gen_op_ldb_T0_T0(ctx); + gen_op_movl_T0_rN(REG(0)); + return; + case 0xc500: /* mov.w @(disp,GBR),R0 */ + gen_op_stc_gbr_T0(); + gen_op_addl_imm_T0(B7_0); + gen_op_ldw_T0_T0(ctx); + gen_op_movl_T0_rN(REG(0)); + return; + case 0xc600: /* mov.l @(disp,GBR),R0 */ + gen_op_stc_gbr_T0(); + gen_op_addl_imm_T0(B7_0); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_rN(REG(0)); + return; + case 0xc000: /* mov.b R0,@(disp,GBR) */ + gen_op_stc_gbr_T0(); + gen_op_addl_imm_T0(B7_0); + gen_op_movl_T0_T1(); + gen_op_movl_rN_T0(REG(0)); + gen_op_stb_T0_T1(ctx); + return; + case 0xc100: /* mov.w R0,@(disp,GBR) */ + gen_op_stc_gbr_T0(); + gen_op_addl_imm_T0(B7_0); + gen_op_movl_T0_T1(); + gen_op_movl_rN_T0(REG(0)); + gen_op_stw_T0_T1(ctx); + return; + case 0xc200: /* mov.l R0,@(disp,GBR) */ + gen_op_stc_gbr_T0(); + gen_op_addl_imm_T0(B7_0); + gen_op_movl_T0_T1(); + gen_op_movl_rN_T0(REG(0)); + gen_op_stl_T0_T1(ctx); + return; + case 0x8000: /* mov.b R0,@(disp,Rn) */ + gen_op_movl_rN_T0(REG(0)); + gen_op_movl_rN_T1(REG(B7_4)); + gen_op_addl_imm_T1(B3_0); + gen_op_stb_T0_T1(ctx); + return; + case 0x8100: /* mov.w R0,@(disp,Rn) */ + gen_op_movl_rN_T0(REG(0)); + gen_op_movl_rN_T1(REG(B7_4)); + gen_op_addl_imm_T1(B3_0 * 2); + gen_op_stw_T0_T1(ctx); + return; + case 0x8400: /* mov.b @(disp,Rn),R0 */ + gen_op_movl_rN_T0(REG(0)); + gen_op_movl_rN_T1(REG(B7_4)); + gen_op_addl_imm_T1(B3_0); + gen_op_stb_T0_T1(ctx); + return; + case 0x8500: /* mov.w @(disp,Rn),R0 */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_addl_imm_T0(B3_0 * 2); + gen_op_ldw_T0_T0(ctx); + gen_op_movl_T0_rN(REG(0)); + return; + case 0xc700: /* mova @(disp,PC),R0 */ + gen_op_movl_imm_rN(((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3, + REG(0)); + return; + case 0xcb00: /* or #imm,R0 */ + gen_op_or_imm_rN(B7_0, REG(0)); + return; + case 0xcf00: /* or.b #imm,@(R0+GBR) */ + gen_op_movl_rN_T0(REG(0)); + gen_op_addl_GBR_T0(); + gen_op_movl_T0_T1(); + gen_op_ldb_T0_T0(ctx); + gen_op_or_imm_T0(B7_0); + gen_op_stb_T0_T1(ctx); + return; + case 0xc300: /* trapa #imm */ + CHECK_NOT_DELAY_SLOT gen_op_movl_imm_PC(ctx->pc); + gen_op_trapa(B7_0); + ctx->flags |= BRANCH; + return; + case 0xc800: /* tst #imm,R0 */ + gen_op_tst_imm_rN(B7_0, REG(0)); + return; + case 0xcc00: /* tst #imm,@(R0+GBR) */ + gen_op_movl_rN_T0(REG(0)); + gen_op_addl_GBR_T0(); + gen_op_ldb_T0_T0(ctx); + gen_op_tst_imm_T0(B7_0); + return; + case 0xca00: /* xor #imm,R0 */ + gen_op_xor_imm_rN(B7_0, REG(0)); + return; + case 0xce00: /* xor.b #imm,@(R0+GBR) */ + gen_op_movl_rN_T0(REG(0)); + gen_op_addl_GBR_T0(); + gen_op_movl_T0_T1(); + gen_op_ldb_T0_T0(ctx); + gen_op_xor_imm_T0(B7_0); + gen_op_stb_T0_T1(ctx); + return; + } + + switch (ctx->opcode & 0xf08f) { + case 0x408e: /* ldc Rm,Rn_BANK */ + gen_op_movl_rN_rN(REG(B11_8), ALTREG(B6_4)); + return; + case 0x4087: /* ldc.l @Rm+,Rn_BANK */ + gen_op_movl_rN_T0(REG(B11_8)); + gen_op_ldl_T0_T0(ctx); + gen_op_movl_T0_rN(ALTREG(B6_4)); + gen_op_inc4_rN(REG(B11_8)); + return; + case 0x0082: /* stc Rm_BANK,Rn */ + gen_op_movl_rN_rN(ALTREG(B6_4), REG(B11_8)); + return; + case 0x4083: /* stc.l Rm_BANK,@-Rn */ + gen_op_dec4_rN(REG(B11_8)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_movl_rN_T0(ALTREG(B6_4)); + gen_op_stl_T0_T1(ctx); + return; + } + + switch (ctx->opcode & 0xf0ff) { + case 0x0023: /* braf Rn */ + CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); + gen_op_braf_T0(ctx->pc + 4); + ctx->flags |= DELAY_SLOT; + ctx->delayed_pc = (uint32_t) - 1; + return; + case 0x0003: /* bsrf Rn */ + CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); + gen_op_bsrf_T0(ctx->pc + 4); + ctx->flags |= DELAY_SLOT; + ctx->delayed_pc = (uint32_t) - 1; + return; + case 0x4015: /* cmp/pl Rn */ + gen_op_movl_rN_T0(REG(B11_8)); + gen_op_cmp_pl_T0(); + return; + case 0x4011: /* cmp/pz Rn */ + gen_op_movl_rN_T0(REG(B11_8)); + gen_op_cmp_pz_T0(); + return; + case 0x4010: /* dt Rn */ + gen_op_dt_rN(REG(B11_8)); + return; + case 0x402b: /* jmp @Rn */ + CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); + gen_op_jmp_T0(); + ctx->flags |= DELAY_SLOT; + ctx->delayed_pc = (uint32_t) - 1; + return; + case 0x400b: /* jsr @Rn */ + CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8)); + gen_op_jsr_T0(ctx->pc + 4); + ctx->flags |= DELAY_SLOT; + ctx->delayed_pc = (uint32_t) - 1; + return; +#define LDST(reg,ldnum,ldpnum,ldop,stnum,stpnum,stop,extrald) \ + case ldnum: \ + gen_op_movl_rN_T0 (REG(B11_8)); \ + gen_op_##ldop##_T0_##reg (); \ + extrald \ + return; \ + case ldpnum: \ + gen_op_movl_rN_T0 (REG(B11_8)); \ + gen_op_ldl_T0_T0 (ctx); \ + gen_op_inc4_rN (REG(B11_8)); \ + gen_op_##ldop##_T0_##reg (); \ + extrald \ + return; \ + case stnum: \ + gen_op_##stop##_##reg##_T0 (); \ + gen_op_movl_T0_rN (REG(B11_8)); \ + return; \ + case stpnum: \ + gen_op_##stop##_##reg##_T0 (); \ + gen_op_dec4_rN (REG(B11_8)); \ + gen_op_movl_rN_T1 (REG(B11_8)); \ + gen_op_stl_T0_T1 (ctx); \ + return; + LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |= + MODE_CHANGE; + ) + LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,) + LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,) + LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,) + LDST(spc, 0x404e, 0x4047, ldc, 0x0042, 0x4043, stc,) + LDST(dbr, 0x40fa, 0x40f6, ldc, 0x00fa, 0x40f2, stc,) + LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,) + LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,) + LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,) + case 0x00c3: /* movca.l R0,@Rm */ + gen_op_movl_rN_T0(REG(0)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stl_T0_T1(ctx); + return; + case 0x0029: /* movt Rn */ + gen_op_movt_rN(REG(B11_8)); + return; + case 0x0093: /* ocbi @Rn */ + gen_op_movl_rN_T0(REG(B11_8)); + gen_op_ldl_T0_T0(ctx); + return; + case 0x00a2: /* ocbp @Rn */ + gen_op_movl_rN_T0(REG(B11_8)); + gen_op_ldl_T0_T0(ctx); + return; + case 0x00b3: /* ocbwb @Rn */ + gen_op_movl_rN_T0(REG(B11_8)); + gen_op_ldl_T0_T0(ctx); + return; + case 0x0083: /* pref @Rn */ + return; + case 0x4024: /* rotcl Rn */ + gen_op_rotcl_Rn(REG(B11_8)); + return; + case 0x4025: /* rotcr Rn */ + gen_op_rotcr_Rn(REG(B11_8)); + return; + case 0x4004: /* rotl Rn */ + gen_op_rotl_Rn(REG(B11_8)); + return; + case 0x4005: /* rotr Rn */ + gen_op_rotr_Rn(REG(B11_8)); + return; + case 0x4000: /* shll Rn */ + case 0x4020: /* shal Rn */ + gen_op_shal_Rn(REG(B11_8)); + return; + case 0x4021: /* shar Rn */ + gen_op_shar_Rn(REG(B11_8)); + return; + case 0x4001: /* shlr Rn */ + gen_op_shlr_Rn(REG(B11_8)); + return; + case 0x4008: /* shll2 Rn */ + gen_op_shll2_Rn(REG(B11_8)); + return; + case 0x4018: /* shll8 Rn */ + gen_op_shll8_Rn(REG(B11_8)); + return; + case 0x4028: /* shll16 Rn */ + gen_op_shll16_Rn(REG(B11_8)); + return; + case 0x4009: /* shlr2 Rn */ + gen_op_shlr2_Rn(REG(B11_8)); + return; + case 0x4019: /* shlr8 Rn */ + gen_op_shlr8_Rn(REG(B11_8)); + return; + case 0x4029: /* shlr16 Rn */ + gen_op_shlr16_Rn(REG(B11_8)); + return; + case 0x401b: /* tas.b @Rn */ + gen_op_tasb_rN(REG(B11_8)); + return; + } + + fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", + ctx->opcode, ctx->pc); + gen_op_raise_illegal_instruction(); + ctx->flags |= BRANCH_EXCEPTION; +} + +int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, + int search_pc) +{ + DisasContext ctx; + target_ulong pc_start; + static uint16_t *gen_opc_end; + uint32_t old_flags; + int i; + + pc_start = tb->pc; + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + ctx.pc = pc_start; + ctx.flags = env->flags; + old_flags = 0; + ctx.sr = env->sr; + ctx.memidx = (env->sr & SR_MD) ? 1 : 0; + ctx.delayed_pc = env->delayed_pc; + ctx.tb = tb; + ctx.singlestep_enabled = env->singlestep_enabled; + nb_gen_labels = 0; + +#ifdef DEBUG_DISAS + if (loglevel & CPU_LOG_TB_CPU) { + fprintf(logfile, + "------------------------------------------------\n"); + cpu_dump_state(env, logfile, fprintf, 0); + } +#endif + + while ((old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) == 0 && + (ctx.flags & (BRANCH | BRANCH_CONDITIONAL | MODE_CHANGE | + BRANCH_EXCEPTION)) == 0 && + gen_opc_ptr < gen_opc_end && ctx.sr == env->sr) { + old_flags = ctx.flags; + if (env->nb_breakpoints > 0) { + for (i = 0; i < env->nb_breakpoints; i++) { + if (ctx.pc == env->breakpoints[i]) { + /* We have hit a breakpoint - make sure PC is up-to-date */ + gen_op_movl_imm_PC(ctx.pc); + gen_op_debug(); + ctx.flags |= BRANCH_EXCEPTION; + break; + } + } + } +#if 0 + fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc); + fflush(stderr); +#endif + ctx.opcode = lduw_code(ctx.pc); + decode_opc(&ctx); + ctx.pc += 2; + if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) + break; + if (env->singlestep_enabled) + break; +#ifdef SH4_SINGLE_STEP + break; +#endif + } + + switch (old_flags & (DELAY_SLOT_CONDITIONAL | DELAY_SLOT)) { + case DELAY_SLOT_CONDITIONAL: + gen_op_clr_delay_slot_conditional(); + gen_delayed_conditional_jump(&ctx); + break; + case DELAY_SLOT: + gen_op_clr_delay_slot(); + gen_jump(&ctx); + break; + case 0: + if (ctx.flags & BRANCH_EXCEPTION) { + gen_jump_exception(&ctx); + } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) { + gen_goto_tb(&ctx, 0, ctx.pc); + } + break; + default: + /* Both cannot be set at the same time */ + assert(0); + } + + if (env->singlestep_enabled) { + gen_op_debug(); + } + *gen_opc_ptr = INDEX_op_end; + tb->size = ctx.pc - pc_start; + +#ifdef DEBUG_DISAS +#ifdef SH4_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "\n"); +#endif + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "IN:\n"); /* , lookup_symbol(pc_start)); */ + target_disas(logfile, pc_start, ctx.pc - pc_start, 0); + fprintf(logfile, "\n"); + } + if (loglevel & CPU_LOG_TB_OP) { + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + return 0; +} + +int gen_intermediate_code(CPUState * env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb) +{ + assert(0); + return gen_intermediate_code_internal(env, tb, 1); +} -- cgit v1.2.3 From 27c7ca7e7750063f6e83e4d126bbd4de2d83f79e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 27 Apr 2006 21:32:09 +0000 Subject: SHIX board emulation (Samuel Tardieu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1862 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 6 +- hw/sh7750.c | 836 +++++++++++++++++++++++++ hw/sh7750_regnames.c | 128 ++++ hw/sh7750_regnames.h | 6 + hw/sh7750_regs.h | 1623 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/shix.c | 111 ++++ hw/tc58128.c | 181 ++++++ target-sh4/README.sh4 | 150 +++++ vl.c | 2 + vl.h | 25 + 11 files changed, 3066 insertions(+), 3 deletions(-) create mode 100644 hw/sh7750.c create mode 100644 hw/sh7750_regnames.c create mode 100644 hw/sh7750_regnames.h create mode 100644 hw/sh7750_regs.h create mode 100644 hw/shix.c create mode 100644 hw/tc58128.c create mode 100644 target-sh4/README.sh4 diff --git a/Changelog b/Changelog index fb28ee0c1..d6f34fea5 100644 --- a/Changelog +++ b/Changelog @@ -6,6 +6,7 @@ version 0.8.1: - IDE LBA48 support (Jens Axboe) - SSE3 support - Solaris port (Ben Taylor) + - Preliminary SH4 target (Samuel Tardieu) version 0.8.0: diff --git a/Makefile.target b/Makefile.target index 6c2bd35cd..751edc858 100644 --- a/Makefile.target +++ b/Makefile.target @@ -476,10 +476,10 @@ 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.h sh7750_regs.h sh7750_regnames.h cpu.h -shix.o: shix.c sh7750.h sh7750_regs.h sh7750_regnames.h tc58128.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 tc58128.h sh7750.h +tc58128.o: tc58128.c endif %.o: %.c diff --git a/hw/sh7750.c b/hw/sh7750.c new file mode 100644 index 000000000..041e3eed1 --- /dev/null +++ b/hw/sh7750.c @@ -0,0 +1,836 @@ +/* + * SH7750 device + * + * Copyright (c) 2005 Samuel Tardieu + * + * 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 +#include +#include "vl.h" +#include "sh7750_regs.h" +#include "sh7750_regnames.h" + +typedef struct { + uint8_t data[16]; + uint8_t length; /* Number of characters in the FIFO */ + uint8_t write_idx; /* Index of first character to write */ + uint8_t read_idx; /* Index of first character to read */ +} fifo; + +#define NB_DEVICES 4 + +typedef struct SH7750State { + /* CPU */ + CPUSH4State *cpu; + /* Peripheral frequency in Hz */ + uint32_t periph_freq; + /* SDRAM controller */ + uint16_t rfcr; + /* First serial port */ + CharDriverState *serial1; + uint8_t scscr1; + uint8_t scsmr1; + uint8_t scbrr1; + uint8_t scssr1; + uint8_t scssr1_read; + uint8_t sctsr1; + uint8_t sctsr1_loaded; + uint8_t sctdr1; + uint8_t scrdr1; + /* Second serial port */ + CharDriverState *serial2; + uint16_t sclsr2; + uint16_t scscr2; + uint16_t scfcr2; + uint16_t scfsr2; + uint16_t scsmr2; + uint8_t scbrr2; + fifo serial2_receive_fifo; + fifo serial2_transmit_fifo; + /* Timers */ + uint8_t tstr; + /* Timer 0 */ + QEMUTimer *timer0; + uint16_t tcr0; + uint32_t tcor0; + uint32_t tcnt0; + /* IO ports */ + uint16_t gpioic; + uint32_t pctra; + uint32_t pctrb; + uint16_t portdira; /* Cached */ + uint16_t portpullupa; /* Cached */ + uint16_t portdirb; /* Cached */ + uint16_t portpullupb; /* Cached */ + uint16_t pdtra; + uint16_t pdtrb; + uint16_t periph_pdtra; /* Imposed by the peripherals */ + uint16_t periph_portdira; /* Direction seen from the peripherals */ + uint16_t periph_pdtrb; /* Imposed by the peripherals */ + uint16_t periph_portdirb; /* Direction seen from the peripherals */ + sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ + /* Cache */ + uint32_t ccr; +} SH7750State; + +/********************************************************************** + Timers +**********************************************************************/ + +/* XXXXX At this time, timer0 works in underflow only mode, that is + the value of tcnt0 is read at alarm computation time and cannot + be read back by the guest OS */ + +static void start_timer0(SH7750State * s) +{ + uint64_t now, next, prescaler; + + if ((s->tcr0 & 6) == 6) { + fprintf(stderr, "rtc clock for timer 0 not supported\n"); + assert(0); + } + + if ((s->tcr0 & 7) == 5) { + fprintf(stderr, "timer 0 configuration not supported\n"); + assert(0); + } + + if ((s->tcr0 & 4) == 4) + prescaler = 1024; + else + prescaler = 4 << (s->tcr0 & 3); + + now = qemu_get_clock(vm_clock); + /* XXXXX */ + next = + now + muldiv64(prescaler * s->tcnt0, ticks_per_sec, + s->periph_freq); + if (next == now) + next = now + 1; + fprintf(stderr, "now=%016llx, next=%016llx\n", now, next); + fprintf(stderr, "timer will underflow in %f seconds\n", + (float) (next - now) / (float) ticks_per_sec); + + qemu_mod_timer(s->timer0, next); +} + +static void timer_start_changed(SH7750State * s) +{ + if (s->tstr & SH7750_TSTR_STR0) { + start_timer0(s); + } else { + fprintf(stderr, "timer 0 is stopped\n"); + qemu_del_timer(s->timer0); + } +} + +static void timer0_cb(void *opaque) +{ + SH7750State *s = opaque; + + s->tcnt0 = (uint32_t) 0; /* XXXXX */ + if (--s->tcnt0 == (uint32_t) - 1) { + fprintf(stderr, "timer 0 underflow\n"); + s->tcnt0 = s->tcor0; + s->tcr0 |= SH7750_TCR_UNF; + if (s->tcr0 & SH7750_TCR_UNIE) { + fprintf(stderr, + "interrupt generation for timer 0 not supported\n"); + assert(0); + } + } + start_timer0(s); +} + +static void init_timers(SH7750State * s) +{ + s->tcor0 = 0xffffffff; + s->tcnt0 = 0xffffffff; + s->timer0 = qemu_new_timer(vm_clock, &timer0_cb, s); +} + +/********************************************************************** + First serial port +**********************************************************************/ + +static int serial1_can_receive(void *opaque) +{ + SH7750State *s = opaque; + + return s->scscr1 & SH7750_SCSCR_RE; +} + +static void serial1_receive_char(SH7750State * s, uint8_t c) +{ + if (s->scssr1 & SH7750_SCSSR1_RDRF) { + s->scssr1 |= SH7750_SCSSR1_ORER; + return; + } + + s->scrdr1 = c; + s->scssr1 |= SH7750_SCSSR1_RDRF; +} + +static void serial1_receive(void *opaque, const uint8_t * buf, int size) +{ + SH7750State *s = opaque; + int i; + + for (i = 0; i < size; i++) { + serial1_receive_char(s, buf[i]); + } +} + +static void serial1_event(void *opaque, int event) +{ + assert(0); +} + +static void serial1_maybe_send(SH7750State * s) +{ + uint8_t c; + + if (s->scssr1 & SH7750_SCSSR1_TDRE) + return; + c = s->sctdr1; + s->scssr1 |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND; + if (s->scscr1 & SH7750_SCSCR_TIE) { + fprintf(stderr, "interrupts for serial port 1 not implemented\n"); + assert(0); + } + /* XXXXX Check for errors in write */ + qemu_chr_write(s->serial1, &c, 1); +} + +static void serial1_change_scssr1(SH7750State * s, uint8_t mem_value) +{ + uint8_t new_flags; + + /* If transmit disable, TDRE and TEND stays up */ + if ((s->scscr1 & SH7750_SCSCR_TE) == 0) { + mem_value |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND; + } + + /* Only clear bits which have been read before and do not set any bit + in the flags */ + new_flags = s->scssr1 & ~s->scssr1_read; /* Preserve unread flags */ + new_flags &= mem_value | ~s->scssr1_read; /* Clear read flags */ + + s->scssr1 = (new_flags & 0xf8) | (mem_value & 1); + s->scssr1_read &= mem_value; + + /* If TDRE has been cleared, TEND will also be cleared */ + if ((s->scssr1 & SH7750_SCSSR1_TDRE) == 0) { + s->scssr1 &= ~SH7750_SCSSR1_TEND; + } + + /* Check for transmission to start */ + serial1_maybe_send(s); +} + +static void serial1_update_parameters(SH7750State * s) +{ + QEMUSerialSetParams ssp; + + if (s->scsmr1 & SH7750_SCSMR_CHR_7) + ssp.data_bits = 7; + else + ssp.data_bits = 8; + if (s->scsmr1 & SH7750_SCSMR_PE) { + if (s->scsmr1 & SH7750_SCSMR_PM_ODD) + ssp.parity = 'O'; + else + ssp.parity = 'E'; + } else + ssp.parity = 'N'; + if (s->scsmr1 & SH7750_SCSMR_STOP_2) + ssp.stop_bits = 2; + else + ssp.stop_bits = 1; + fprintf(stderr, "SCSMR1=%04x SCBRR1=%02x\n", s->scsmr1, s->scbrr1); + ssp.speed = s->periph_freq / + (32 * s->scbrr1 * (1 << (2 * (s->scsmr1 & 3)))) - 1; + fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n", + ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed); + qemu_chr_ioctl(s->serial1, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); +} + +static void scscr1_changed(SH7750State * s) +{ + if (s->scscr1 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) { + if (!s->serial1) { + fprintf(stderr, "serial port 1 not bound to anything\n"); + assert(0); + } + serial1_update_parameters(s); + } + if ((s->scscr1 & SH7750_SCSCR_RE) == 0) { + s->scssr1 |= SH7750_SCSSR1_TDRE; + } +} + +static void init_serial1(SH7750State * s, int serial_nb) +{ + CharDriverState *chr; + + s->scssr1 = 0x84; + chr = serial_hds[serial_nb]; + if (!chr) { + fprintf(stderr, + "no serial port associated to SH7750 first serial port\n"); + return; + } + + s->serial1 = chr; + qemu_chr_add_read_handler(chr, serial1_can_receive, + serial1_receive, s); + qemu_chr_add_event_handler(chr, serial1_event); +} + +/********************************************************************** + Second serial port +**********************************************************************/ + +static int serial2_can_receive(void *opaque) +{ + SH7750State *s = opaque; + static uint8_t max_fifo_size[] = { 15, 1, 4, 6, 8, 10, 12, 14 }; + + return s->serial2_receive_fifo.length < + max_fifo_size[(s->scfcr2 >> 9) & 7]; +} + +static void serial2_adjust_receive_flags(SH7750State * s) +{ + static uint8_t max_fifo_size[] = { 1, 4, 8, 14 }; + + /* XXXXX Add interrupt generation */ + if (s->serial2_receive_fifo.length >= + max_fifo_size[(s->scfcr2 >> 7) & 3]) { + s->scfsr2 |= SH7750_SCFSR2_RDF; + s->scfsr2 &= ~SH7750_SCFSR2_DR; + } else { + s->scfsr2 &= ~SH7750_SCFSR2_RDF; + if (s->serial2_receive_fifo.length > 0) + s->scfsr2 |= SH7750_SCFSR2_DR; + else + s->scfsr2 &= ~SH7750_SCFSR2_DR; + } +} + +static void serial2_append_char(SH7750State * s, uint8_t c) +{ + if (s->serial2_receive_fifo.length == 16) { + /* Overflow */ + s->sclsr2 |= SH7750_SCLSR2_ORER; + return; + } + + s->serial2_receive_fifo.data[s->serial2_receive_fifo.write_idx++] = c; + s->serial2_receive_fifo.length++; + serial2_adjust_receive_flags(s); +} + +static void serial2_receive(void *opaque, const uint8_t * buf, int size) +{ + SH7750State *s = opaque; + int i; + + for (i = 0; i < size; i++) + serial2_append_char(s, buf[i]); +} + +static void serial2_event(void *opaque, int event) +{ + /* XXXXX */ + assert(0); +} + +static void serial2_update_parameters(SH7750State * s) +{ + QEMUSerialSetParams ssp; + + if (s->scsmr2 & SH7750_SCSMR_CHR_7) + ssp.data_bits = 7; + else + ssp.data_bits = 8; + if (s->scsmr2 & SH7750_SCSMR_PE) { + if (s->scsmr2 & SH7750_SCSMR_PM_ODD) + ssp.parity = 'O'; + else + ssp.parity = 'E'; + } else + ssp.parity = 'N'; + if (s->scsmr2 & SH7750_SCSMR_STOP_2) + ssp.stop_bits = 2; + else + ssp.stop_bits = 1; + fprintf(stderr, "SCSMR2=%04x SCBRR2=%02x\n", s->scsmr2, s->scbrr2); + ssp.speed = s->periph_freq / + (32 * s->scbrr2 * (1 << (2 * (s->scsmr2 & 3)))) - 1; + fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n", + ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed); + qemu_chr_ioctl(s->serial2, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); +} + +static void scscr2_changed(SH7750State * s) +{ + if (s->scscr2 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) { + if (!s->serial2) { + fprintf(stderr, "serial port 2 not bound to anything\n"); + assert(0); + } + serial2_update_parameters(s); + } +} + +static void init_serial2(SH7750State * s, int serial_nb) +{ + CharDriverState *chr; + + s->scfsr2 = 0x0060; + + chr = serial_hds[serial_nb]; + if (!chr) { + fprintf(stderr, + "no serial port associated to SH7750 second serial port\n"); + return; + } + + s->serial2 = chr; + qemu_chr_add_read_handler(chr, serial2_can_receive, + serial2_receive, s); + qemu_chr_add_event_handler(chr, serial2_event); +} + +static void init_serial_ports(SH7750State * s) +{ + init_serial1(s, 0); + init_serial2(s, 1); +} + +/********************************************************************** + I/O ports +**********************************************************************/ + +int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device) +{ + int i; + + for (i = 0; i < NB_DEVICES; i++) { + if (s->devices[i] == NULL) { + s->devices[i] = device; + return 0; + } + } + return -1; +} + +static uint16_t portdir(uint32_t v) +{ +#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n)) + return + EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) | + EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) | + EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) | + EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) | + EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) | + EVENPORTMASK(0); +} + +static uint16_t portpullup(uint32_t v) +{ +#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n)) + return + ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) | + ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) | + ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) | + ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) | + ODDPORTMASK(1) | ODDPORTMASK(0); +} + +static uint16_t porta_lines(SH7750State * s) +{ + return (s->portdira & s->pdtra) | /* CPU */ + (s->periph_portdira & s->periph_pdtra) | /* Peripherals */ + (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */ +} + +static uint16_t portb_lines(SH7750State * s) +{ + return (s->portdirb & s->pdtrb) | /* CPU */ + (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */ + (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */ +} + +static void gen_port_interrupts(SH7750State * s) +{ + /* XXXXX interrupts not generated */ +} + +static void porta_changed(SH7750State * s, uint16_t prev) +{ + uint16_t currenta, changes; + int i, r = 0; + +#if 0 + fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n", + prev, porta_lines(s)); + fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra); +#endif + currenta = porta_lines(s); + if (currenta == prev) + return; + changes = currenta ^ prev; + + for (i = 0; i < NB_DEVICES; i++) { + if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) { + r |= s->devices[i]->port_change_cb(currenta, portb_lines(s), + &s->periph_pdtra, + &s->periph_portdira, + &s->periph_pdtrb, + &s->periph_portdirb); + } + } + + if (r) + gen_port_interrupts(s); +} + +static void portb_changed(SH7750State * s, uint16_t prev) +{ + uint16_t currentb, changes; + int i, r = 0; + + currentb = portb_lines(s); + if (currentb == prev) + return; + changes = currentb ^ prev; + + for (i = 0; i < NB_DEVICES; i++) { + if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) { + r |= s->devices[i]->port_change_cb(portb_lines(s), currentb, + &s->periph_pdtra, + &s->periph_portdira, + &s->periph_pdtrb, + &s->periph_portdirb); + } + } + + if (r) + gen_port_interrupts(s); +} + +/********************************************************************** + Memory +**********************************************************************/ + +static void error_access(const char *kind, target_phys_addr_t addr) +{ + fprintf(stderr, "%s to %s (0x%08x) not supported\n", + kind, regname(addr), addr); +} + +static void ignore_access(const char *kind, target_phys_addr_t addr) +{ + fprintf(stderr, "%s to %s (0x%08x) ignored\n", + kind, regname(addr), addr); +} + +static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr) +{ + SH7750State *s = opaque; + uint8_t r; + + switch (addr) { + case SH7750_SCSSR1_A7: + r = s->scssr1; + s->scssr1_read |= r; + return s->scssr1; + case SH7750_SCRDR1_A7: + s->scssr1 &= ~SH7750_SCSSR1_RDRF; + return s->scrdr1; + default: + error_access("byte read", addr); + assert(0); + } +} + +static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) +{ + SH7750State *s = opaque; + uint16_t r; + + switch (addr) { + case SH7750_RFCR_A7: + fprintf(stderr, + "Read access to refresh count register, incrementing\n"); + return s->rfcr++; + case SH7750_TCR0_A7: + return s->tcr0; + case SH7750_SCLSR2_A7: + /* Read and clear overflow bit */ + r = s->sclsr2; + s->sclsr2 = 0; + return r; + case SH7750_SCSFR2_A7: + return s->scfsr2; + case SH7750_PDTRA_A7: + return porta_lines(s); + case SH7750_PDTRB_A7: + return portb_lines(s); + default: + error_access("word read", addr); + assert(0); + } +} + +static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) +{ + SH7750State *s = opaque; + + switch (addr) { + case SH7750_MMUCR_A7: + return s->cpu->mmucr; + case SH7750_PTEH_A7: + return s->cpu->pteh; + case SH7750_PTEL_A7: + return s->cpu->ptel; + case SH7750_TTB_A7: + return s->cpu->ttb; + case SH7750_TEA_A7: + return s->cpu->tea; + case SH7750_TRA_A7: + return s->cpu->tra; + case SH7750_EXPEVT_A7: + return s->cpu->expevt; + case SH7750_INTEVT_A7: + return s->cpu->intevt; + case SH7750_CCR_A7: + return s->ccr; + case 0x1f000030: /* Processor version PVR */ + return 0x00050000; /* SH7750R */ + case 0x1f000040: /* Processor version CVR */ + return 0x00110000; /* Minimum caches */ + case 0x1f000044: /* Processor version PRR */ + return 0x00000100; /* SH7750R */ + default: + error_access("long read", addr); + assert(0); + } +} + +static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t mem_value) +{ + SH7750State *s = opaque; + + switch (addr) { + /* PRECHARGE ? XXXXX */ + case SH7750_PRECHARGE0_A7: + case SH7750_PRECHARGE1_A7: + ignore_access("byte write", addr); + return; + case SH7750_SCBRR2_A7: + s->scbrr2 = mem_value; + return; + case SH7750_TSTR_A7: + s->tstr = mem_value; + timer_start_changed(s); + return; + case SH7750_SCSCR1_A7: + s->scscr1 = mem_value; + scscr1_changed(s); + return; + case SH7750_SCSMR1_A7: + s->scsmr1 = mem_value; + return; + case SH7750_SCBRR1_A7: + s->scbrr1 = mem_value; + return; + case SH7750_SCTDR1_A7: + s->scssr1 &= ~SH7750_SCSSR1_TEND; + s->sctdr1 = mem_value; + return; + case SH7750_SCSSR1_A7: + serial1_change_scssr1(s, mem_value); + return; + default: + error_access("byte write", addr); + assert(0); + } +} + +static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t mem_value) +{ + SH7750State *s = opaque; + uint16_t temp; + + switch (addr) { + /* SDRAM controller */ + case SH7750_SCBRR1_A7: + case SH7750_SCBRR2_A7: + case SH7750_BCR2_A7: + case SH7750_BCR3_A7: + case SH7750_RTCOR_A7: + case SH7750_RTCNT_A7: + case SH7750_RTCSR_A7: + ignore_access("word write", addr); + return; + /* IO ports */ + case SH7750_PDTRA_A7: + temp = porta_lines(s); + s->pdtra = mem_value; + porta_changed(s, temp); + return; + case SH7750_PDTRB_A7: + temp = portb_lines(s); + s->pdtrb = mem_value; + portb_changed(s, temp); + return; + case SH7750_RFCR_A7: + fprintf(stderr, "Write access to refresh count register\n"); + s->rfcr = mem_value; + return; + case SH7750_SCLSR2_A7: + s->sclsr2 = mem_value; + return; + case SH7750_SCSCR2_A7: + s->scscr2 = mem_value; + scscr2_changed(s); + return; + case SH7750_SCFCR2_A7: + s->scfcr2 = mem_value; + return; + case SH7750_SCSMR2_A7: + s->scsmr2 = mem_value; + return; + case SH7750_TCR0_A7: + s->tcr0 = mem_value; + return; + case SH7750_GPIOIC_A7: + s->gpioic = mem_value; + if (mem_value != 0) { + fprintf(stderr, "I/O interrupts not implemented\n"); + assert(0); + } + return; + default: + error_access("word write", addr); + assert(0); + } +} + +static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t mem_value) +{ + SH7750State *s = opaque; + uint16_t temp; + + switch (addr) { + /* SDRAM controller */ + case SH7750_BCR1_A7: + case SH7750_BCR4_A7: + case SH7750_WCR1_A7: + case SH7750_WCR2_A7: + case SH7750_WCR3_A7: + case SH7750_MCR_A7: + ignore_access("long write", addr); + return; + /* IO ports */ + case SH7750_PCTRA_A7: + temp = porta_lines(s); + s->pctra = mem_value; + s->portdira = portdir(mem_value); + s->portpullupa = portpullup(mem_value); + porta_changed(s, temp); + return; + case SH7750_PCTRB_A7: + temp = portb_lines(s); + s->pctrb = mem_value; + s->portdirb = portdir(mem_value); + s->portpullupb = portpullup(mem_value); + portb_changed(s, temp); + return; + case SH7750_TCNT0_A7: + s->tcnt0 = mem_value & 0xf; + return; + case SH7750_MMUCR_A7: + s->cpu->mmucr = mem_value; + return; + case SH7750_PTEH_A7: + s->cpu->pteh = mem_value; + return; + case SH7750_PTEL_A7: + s->cpu->ptel = mem_value; + return; + case SH7750_TTB_A7: + s->cpu->ttb = mem_value; + return; + case SH7750_TEA_A7: + s->cpu->tea = mem_value; + return; + case SH7750_TRA_A7: + s->cpu->tra = mem_value & 0x000007ff; + return; + case SH7750_EXPEVT_A7: + s->cpu->expevt = mem_value & 0x000007ff; + return; + case SH7750_INTEVT_A7: + s->cpu->intevt = mem_value & 0x000007ff; + return; + case SH7750_CCR_A7: + s->ccr = mem_value; + return; + default: + error_access("long write", addr); + assert(0); + } +} + +static CPUReadMemoryFunc *sh7750_mem_read[] = { + sh7750_mem_readb, + sh7750_mem_readw, + sh7750_mem_readl +}; + +static CPUWriteMemoryFunc *sh7750_mem_write[] = { + sh7750_mem_writeb, + sh7750_mem_writew, + sh7750_mem_writel +}; + +SH7750State *sh7750_init(CPUSH4State * cpu) +{ + SH7750State *s; + int sh7750_io_memory; + + s = qemu_mallocz(sizeof(SH7750State)); + s->cpu = cpu; + s->periph_freq = 60000000; /* 60MHz */ + sh7750_io_memory = cpu_register_io_memory(0, + sh7750_mem_read, + sh7750_mem_write, s); + cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); + init_timers(s); + init_serial_ports(s); + return s; +} diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c new file mode 100644 index 000000000..5fcb0d6cc --- /dev/null +++ b/hw/sh7750_regnames.c @@ -0,0 +1,128 @@ +#include "vl.h" +#include "sh7750_regs.h" + +#define REGNAME(r) {r, #r}, + +typedef struct { + uint32_t regaddr; + const char *regname; +} regname_t; + +static regname_t regnames[] = { + REGNAME(SH7750_PTEH_A7) + REGNAME(SH7750_PTEL_A7) + REGNAME(SH7750_PTEA_A7) + REGNAME(SH7750_TTB_A7) + REGNAME(SH7750_TEA_A7) + REGNAME(SH7750_MMUCR_A7) + REGNAME(SH7750_CCR_A7) + REGNAME(SH7750_QACR0_A7) + REGNAME(SH7750_QACR1_A7) + REGNAME(SH7750_TRA_A7) + REGNAME(SH7750_EXPEVT_A7) + REGNAME(SH7750_INTEVT_A7) + REGNAME(SH7750_STBCR_A7) + REGNAME(SH7750_STBCR2_A7) + REGNAME(SH7750_FRQCR_A7) + REGNAME(SH7750_WTCNT_A7) + REGNAME(SH7750_WTCSR_A7) + REGNAME(SH7750_R64CNT_A7) + REGNAME(SH7750_RSECCNT_A7) + REGNAME(SH7750_RMINCNT_A7) + REGNAME(SH7750_RHRCNT_A7) + REGNAME(SH7750_RWKCNT_A7) + REGNAME(SH7750_RDAYCNT_A7) + REGNAME(SH7750_RMONCNT_A7) + REGNAME(SH7750_RYRCNT_A7) + REGNAME(SH7750_RSECAR_A7) + REGNAME(SH7750_RMINAR_A7) + REGNAME(SH7750_RHRAR_A7) + REGNAME(SH7750_RWKAR_A7) + REGNAME(SH7750_RDAYAR_A7) + REGNAME(SH7750_RMONAR_A7) + REGNAME(SH7750_RCR1_A7) + REGNAME(SH7750_RCR2_A7) + REGNAME(SH7750_TOCR_A7) + REGNAME(SH7750_TSTR_A7) + REGNAME(SH7750_TCOR0_A7) + REGNAME(SH7750_TCOR1_A7) + REGNAME(SH7750_TCOR2_A7) + REGNAME(SH7750_TCNT0_A7) + REGNAME(SH7750_TCNT1_A7) + REGNAME(SH7750_TCNT2_A7) + REGNAME(SH7750_TCR0_A7) + REGNAME(SH7750_TCR1_A7) + REGNAME(SH7750_TCR2_A7) + REGNAME(SH7750_TCPR2_A7) + REGNAME(SH7750_BCR1_A7) + REGNAME(SH7750_BCR2_A7) + REGNAME(SH7750_WCR1_A7) + REGNAME(SH7750_WCR2_A7) + REGNAME(SH7750_WCR3_A7) + REGNAME(SH7750_MCR_A7) + REGNAME(SH7750_PCR_A7) + REGNAME(SH7750_RTCSR_A7) + REGNAME(SH7750_RTCNT_A7) + REGNAME(SH7750_RTCOR_A7) + REGNAME(SH7750_RFCR_A7) + REGNAME(SH7750_SAR0_A7) + REGNAME(SH7750_SAR1_A7) + REGNAME(SH7750_SAR2_A7) + REGNAME(SH7750_SAR3_A7) + REGNAME(SH7750_DAR0_A7) + REGNAME(SH7750_DAR1_A7) + REGNAME(SH7750_DAR2_A7) + REGNAME(SH7750_DAR3_A7) + REGNAME(SH7750_DMATCR0_A7) + REGNAME(SH7750_DMATCR1_A7) + REGNAME(SH7750_DMATCR2_A7) + REGNAME(SH7750_DMATCR3_A7) + REGNAME(SH7750_CHCR0_A7) + REGNAME(SH7750_CHCR1_A7) + REGNAME(SH7750_CHCR2_A7) + REGNAME(SH7750_CHCR3_A7) + REGNAME(SH7750_DMAOR_A7) + REGNAME(SH7750_SCRDR1_A7) + REGNAME(SH7750_SCRDR2_A7) + REGNAME(SH7750_SCTDR1_A7) + REGNAME(SH7750_SCTDR2_A7) + REGNAME(SH7750_SCSMR1_A7) + REGNAME(SH7750_SCSMR2_A7) + REGNAME(SH7750_SCSCR1_A7) + REGNAME(SH7750_SCSCR2_A7) + REGNAME(SH7750_SCSSR1_A7) + REGNAME(SH7750_SCSFR2_A7) + REGNAME(SH7750_SCSPTR1_A7) + REGNAME(SH7750_SCSPTR2_A7) + REGNAME(SH7750_SCBRR1_A7) + REGNAME(SH7750_SCBRR2_A7) + REGNAME(SH7750_SCFCR2_A7) + REGNAME(SH7750_SCFDR2_A7) + REGNAME(SH7750_SCLSR2_A7) + REGNAME(SH7750_SCSCMR1_A7) + REGNAME(SH7750_PCTRA_A7) + REGNAME(SH7750_PDTRA_A7) + REGNAME(SH7750_PCTRB_A7) + REGNAME(SH7750_PDTRB_A7) + REGNAME(SH7750_GPIOIC_A7) + REGNAME(SH7750_ICR_A7) + REGNAME(SH7750_IPRA_A7) + REGNAME(SH7750_IPRB_A7) + REGNAME(SH7750_IPRC_A7) + REGNAME(SH7750_BCR3_A7) + REGNAME(SH7750_BCR4_A7) + REGNAME(SH7750_PRECHARGE0_A7) + REGNAME(SH7750_PRECHARGE1_A7) {(uint32_t) - 1, 0} +}; + +const char *regname(uint32_t addr) +{ + unsigned int i; + + for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) { + if (regnames[i].regaddr == addr) + return regnames[i].regname; + } + + return ""; +} diff --git a/hw/sh7750_regnames.h b/hw/sh7750_regnames.h new file mode 100644 index 000000000..7463709b4 --- /dev/null +++ b/hw/sh7750_regnames.h @@ -0,0 +1,6 @@ +#ifndef _SH7750_REGNAMES_H +#define _SH7750_REGNAMES_H + +const char *regname(uint32_t addr); + +#endif /* _SH7750_REGNAMES_H */ diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h new file mode 100644 index 000000000..44ae95be2 --- /dev/null +++ b/hw/sh7750_regs.h @@ -0,0 +1,1623 @@ +/* + * SH-7750 memory-mapped registers + * This file based on information provided in the following document: + * "Hitachi SuperH (tm) RISC engine. SH7750 Series (SH7750, SH7750S) + * Hardware Manual" + * Document Number ADE-602-124C, Rev. 4.0, 4/21/00, Hitachi Ltd. + * + * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia + * Author: Alexandra Kossovsky + * Victor V. Vengerov + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp + */ + +#ifndef __SH7750_REGS_H__ +#define __SH7750_REGS_H__ + +/* + * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and + * in 0x1f000000 - 0x1fffffff (area 7 address) + */ +#define SH7750_P4_BASE 0xff000000 /* Accessable only in + priveleged mode */ +#define SH7750_A7_BASE 0x1f000000 /* Accessable only using TLB */ + +#define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs)) +#define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs)) + +/* + * MMU Registers + */ + +/* Page Table Entry High register - PTEH */ +#define SH7750_PTEH_REGOFS 0x000000 /* offset */ +#define SH7750_PTEH SH7750_P4_REG32(SH7750_PTEH_REGOFS) +#define SH7750_PTEH_A7 SH7750_A7_REG32(SH7750_PTEH_REGOFS) +#define SH7750_PTEH_VPN 0xfffffd00 /* Virtual page number */ +#define SH7750_PTEH_VPN_S 10 +#define SH7750_PTEH_ASID 0x000000ff /* Address space identifier */ +#define SH7750_PTEH_ASID_S 0 + +/* Page Table Entry Low register - PTEL */ +#define SH7750_PTEL_REGOFS 0x000004 /* offset */ +#define SH7750_PTEL SH7750_P4_REG32(SH7750_PTEL_REGOFS) +#define SH7750_PTEL_A7 SH7750_A7_REG32(SH7750_PTEL_REGOFS) +#define SH7750_PTEL_PPN 0x1ffffc00 /* Physical page number */ +#define SH7750_PTEL_PPN_S 10 +#define SH7750_PTEL_V 0x00000100 /* Validity (0-entry is invalid) */ +#define SH7750_PTEL_SZ1 0x00000080 /* Page size bit 1 */ +#define SH7750_PTEL_SZ0 0x00000010 /* Page size bit 0 */ +#define SH7750_PTEL_SZ_1KB 0x00000000 /* 1-kbyte page */ +#define SH7750_PTEL_SZ_4KB 0x00000010 /* 4-kbyte page */ +#define SH7750_PTEL_SZ_64KB 0x00000080 /* 64-kbyte page */ +#define SH7750_PTEL_SZ_1MB 0x00000090 /* 1-Mbyte page */ +#define SH7750_PTEL_PR 0x00000060 /* Protection Key Data */ +#define SH7750_PTEL_PR_ROPO 0x00000000 /* read-only in priv mode */ +#define SH7750_PTEL_PR_RWPO 0x00000020 /* read-write in priv mode */ +#define SH7750_PTEL_PR_ROPU 0x00000040 /* read-only in priv or user mode */ +#define SH7750_PTEL_PR_RWPU 0x00000060 /* read-write in priv or user mode */ +#define SH7750_PTEL_C 0x00000008 /* Cacheability + (0 - page not cacheable) */ +#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been + performed to a page) */ +#define SH7750_PTEL_SH 0x00000002 /* Share Status bit (1 - page are + shared by processes) */ +#define SH7750_PTEL_WT 0x00000001 /* Write-through bit, specifies the + cache write mode: + 0 - Copy-back mode + 1 - Write-through mode */ + +/* Page Table Entry Assistance register - PTEA */ +#define SH7750_PTEA_REGOFS 0x000034 /* offset */ +#define SH7750_PTEA SH7750_P4_REG32(SH7750_PTEA_REGOFS) +#define SH7750_PTEA_A7 SH7750_A7_REG32(SH7750_PTEA_REGOFS) +#define SH7750_PTEA_TC 0x00000008 /* Timing Control bit + 0 - use area 5 wait states + 1 - use area 6 wait states */ +#define SH7750_PTEA_SA 0x00000007 /* Space Attribute bits: */ +#define SH7750_PTEA_SA_UNDEF 0x00000000 /* 0 - undefined */ +#define SH7750_PTEA_SA_IOVAR 0x00000001 /* 1 - variable-size I/O space */ +#define SH7750_PTEA_SA_IO8 0x00000002 /* 2 - 8-bit I/O space */ +#define SH7750_PTEA_SA_IO16 0x00000003 /* 3 - 16-bit I/O space */ +#define SH7750_PTEA_SA_CMEM8 0x00000004 /* 4 - 8-bit common memory space */ +#define SH7750_PTEA_SA_CMEM16 0x00000005 /* 5 - 16-bit common memory space */ +#define SH7750_PTEA_SA_AMEM8 0x00000006 /* 6 - 8-bit attr memory space */ +#define SH7750_PTEA_SA_AMEM16 0x00000007 /* 7 - 16-bit attr memory space */ + + +/* Translation table base register */ +#define SH7750_TTB_REGOFS 0x000008 /* offset */ +#define SH7750_TTB SH7750_P4_REG32(SH7750_TTB_REGOFS) +#define SH7750_TTB_A7 SH7750_A7_REG32(SH7750_TTB_REGOFS) + +/* TLB exeption address register - TEA */ +#define SH7750_TEA_REGOFS 0x00000c /* offset */ +#define SH7750_TEA SH7750_P4_REG32(SH7750_TEA_REGOFS) +#define SH7750_TEA_A7 SH7750_A7_REG32(SH7750_TEA_REGOFS) + +/* MMU control register - MMUCR */ +#define SH7750_MMUCR_REGOFS 0x000010 /* offset */ +#define SH7750_MMUCR SH7750_P4_REG32(SH7750_MMUCR_REGOFS) +#define SH7750_MMUCR_A7 SH7750_A7_REG32(SH7750_MMUCR_REGOFS) +#define SH7750_MMUCR_AT 0x00000001 /* Address translation bit */ +#define SH7750_MMUCR_TI 0x00000004 /* TLB invalidate */ +#define SH7750_MMUCR_SV 0x00000100 /* Single Virtual Mode bit */ +#define SH7750_MMUCR_SQMD 0x00000200 /* Store Queue Mode bit */ +#define SH7750_MMUCR_URC 0x0000FC00 /* UTLB Replace Counter */ +#define SH7750_MMUCR_URC_S 10 +#define SH7750_MMUCR_URB 0x00FC0000 /* UTLB Replace Boundary */ +#define SH7750_MMUCR_URB_S 18 +#define SH7750_MMUCR_LRUI 0xFC000000 /* Least Recently Used ITLB */ +#define SH7750_MMUCR_LRUI_S 26 + + + + +/* + * Cache registers + * IC -- instructions cache + * OC -- operand cache + */ + +/* Cache Control Register - CCR */ +#define SH7750_CCR_REGOFS 0x00001c /* offset */ +#define SH7750_CCR SH7750_P4_REG32(SH7750_CCR_REGOFS) +#define SH7750_CCR_A7 SH7750_A7_REG32(SH7750_CCR_REGOFS) + +#define SH7750_CCR_IIX 0x00008000 /* IC index enable bit */ +#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit: + set it to clear IC */ +#define SH7750_CCR_ICE 0x00000100 /* IC enable bit */ +#define SH7750_CCR_OIX 0x00000080 /* OC index enable bit */ +#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit + if you set OCE = 0, + you should set ORA = 0 */ +#define SH7750_CCR_OCI 0x00000008 /* OC invalidation bit */ +#define SH7750_CCR_CB 0x00000004 /* Copy-back bit for P1 area */ +#define SH7750_CCR_WT 0x00000002 /* Write-through bit for P0,U0,P3 area */ +#define SH7750_CCR_OCE 0x00000001 /* OC enable bit */ + +/* Queue address control register 0 - QACR0 */ +#define SH7750_QACR0_REGOFS 0x000038 /* offset */ +#define SH7750_QACR0 SH7750_P4_REG32(SH7750_QACR0_REGOFS) +#define SH7750_QACR0_A7 SH7750_A7_REG32(SH7750_QACR0_REGOFS) + +/* Queue address control register 1 - QACR1 */ +#define SH7750_QACR1_REGOFS 0x00003c /* offset */ +#define SH7750_QACR1 SH7750_P4_REG32(SH7750_QACR1_REGOFS) +#define SH7750_QACR1_A7 SH7750_A7_REG32(SH7750_QACR1_REGOFS) + + +/* + * Exeption-related registers + */ + +/* Immediate data for TRAPA instuction - TRA */ +#define SH7750_TRA_REGOFS 0x000020 /* offset */ +#define SH7750_TRA SH7750_P4_REG32(SH7750_TRA_REGOFS) +#define SH7750_TRA_A7 SH7750_A7_REG32(SH7750_TRA_REGOFS) + +#define SH7750_TRA_IMM 0x000003fd /* Immediate data operand */ +#define SH7750_TRA_IMM_S 2 + +/* Exeption event register - EXPEVT */ +#define SH7750_EXPEVT_REGOFS 0x000024 +#define SH7750_EXPEVT SH7750_P4_REG32(SH7750_EXPEVT_REGOFS) +#define SH7750_EXPEVT_A7 SH7750_A7_REG32(SH7750_EXPEVT_REGOFS) + +#define SH7750_EXPEVT_EX 0x00000fff /* Exeption code */ +#define SH7750_EXPEVT_EX_S 0 + +/* Interrupt event register */ +#define SH7750_INTEVT_REGOFS 0x000028 +#define SH7750_INTEVT SH7750_P4_REG32(SH7750_INTEVT_REGOFS) +#define SH7750_INTEVT_A7 SH7750_A7_REG32(SH7750_INTEVT_REGOFS) +#define SH7750_INTEVT_EX 0x00000fff /* Exeption code */ +#define SH7750_INTEVT_EX_S 0 + +/* + * Exception/interrupt codes + */ +#define SH7750_EVT_TO_NUM(evt) ((evt) >> 5) + +/* Reset exception category */ +#define SH7750_EVT_POWER_ON_RST 0x000 /* Power-on reset */ +#define SH7750_EVT_MANUAL_RST 0x020 /* Manual reset */ +#define SH7750_EVT_TLB_MULT_HIT 0x140 /* TLB multiple-hit exception */ + +/* General exception category */ +#define SH7750_EVT_USER_BREAK 0x1E0 /* User break */ +#define SH7750_EVT_IADDR_ERR 0x0E0 /* Instruction address error */ +#define SH7750_EVT_TLB_READ_MISS 0x040 /* ITLB miss exception / + DTLB miss exception (read) */ +#define SH7750_EVT_TLB_READ_PROTV 0x0A0 /* ITLB protection violation / + DTLB protection violation (read) */ +#define SH7750_EVT_ILLEGAL_INSTR 0x180 /* General Illegal Instruction + exception */ +#define SH7750_EVT_SLOT_ILLEGAL_INSTR 0x1A0 /* Slot Illegal Instruction + exception */ +#define SH7750_EVT_FPU_DISABLE 0x800 /* General FPU disable exception */ +#define SH7750_EVT_SLOT_FPU_DISABLE 0x820 /* Slot FPU disable exception */ +#define SH7750_EVT_DATA_READ_ERR 0x0E0 /* Data address error (read) */ +#define SH7750_EVT_DATA_WRITE_ERR 0x100 /* Data address error (write) */ +#define SH7750_EVT_DTLB_WRITE_MISS 0x060 /* DTLB miss exception (write) */ +#define SH7750_EVT_DTLB_WRITE_PROTV 0x0C0 /* DTLB protection violation + exception (write) */ +#define SH7750_EVT_FPU_EXCEPTION 0x120 /* FPU exception */ +#define SH7750_EVT_INITIAL_PGWRITE 0x080 /* Initial Page Write exception */ +#define SH7750_EVT_TRAPA 0x160 /* Unconditional trap (TRAPA) */ + +/* Interrupt exception category */ +#define SH7750_EVT_NMI 0x1C0 /* Non-maskable interrupt */ +#define SH7750_EVT_IRQ0 0x200 /* External Interrupt 0 */ +#define SH7750_EVT_IRQ1 0x220 /* External Interrupt 1 */ +#define SH7750_EVT_IRQ2 0x240 /* External Interrupt 2 */ +#define SH7750_EVT_IRQ3 0x260 /* External Interrupt 3 */ +#define SH7750_EVT_IRQ4 0x280 /* External Interrupt 4 */ +#define SH7750_EVT_IRQ5 0x2A0 /* External Interrupt 5 */ +#define SH7750_EVT_IRQ6 0x2C0 /* External Interrupt 6 */ +#define SH7750_EVT_IRQ7 0x2E0 /* External Interrupt 7 */ +#define SH7750_EVT_IRQ8 0x300 /* External Interrupt 8 */ +#define SH7750_EVT_IRQ9 0x320 /* External Interrupt 9 */ +#define SH7750_EVT_IRQA 0x340 /* External Interrupt A */ +#define SH7750_EVT_IRQB 0x360 /* External Interrupt B */ +#define SH7750_EVT_IRQC 0x380 /* External Interrupt C */ +#define SH7750_EVT_IRQD 0x3A0 /* External Interrupt D */ +#define SH7750_EVT_IRQE 0x3C0 /* External Interrupt E */ + +/* Peripheral Module Interrupts - Timer Unit (TMU) */ +#define SH7750_EVT_TUNI0 0x400 /* TMU Underflow Interrupt 0 */ +#define SH7750_EVT_TUNI1 0x420 /* TMU Underflow Interrupt 1 */ +#define SH7750_EVT_TUNI2 0x440 /* TMU Underflow Interrupt 2 */ +#define SH7750_EVT_TICPI2 0x460 /* TMU Input Capture Interrupt 2 */ + +/* Peripheral Module Interrupts - Real-Time Clock (RTC) */ +#define SH7750_EVT_RTC_ATI 0x480 /* Alarm Interrupt Request */ +#define SH7750_EVT_RTC_PRI 0x4A0 /* Periodic Interrupt Request */ +#define SH7750_EVT_RTC_CUI 0x4C0 /* Carry Interrupt Request */ + +/* Peripheral Module Interrupts - Serial Communication Interface (SCI) */ +#define SH7750_EVT_SCI_ERI 0x4E0 /* Receive Error */ +#define SH7750_EVT_SCI_RXI 0x500 /* Receive Data Register Full */ +#define SH7750_EVT_SCI_TXI 0x520 /* Transmit Data Register Empty */ +#define SH7750_EVT_SCI_TEI 0x540 /* Transmit End */ + +/* Peripheral Module Interrupts - Watchdog Timer (WDT) */ +#define SH7750_EVT_WDT_ITI 0x560 /* Interval Timer Interrupt + (used when WDT operates in + interval timer mode) */ + +/* Peripheral Module Interrupts - Memory Refresh Unit (REF) */ +#define SH7750_EVT_REF_RCMI 0x580 /* Compare-match Interrupt */ +#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow + interrupt */ + +/* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */ +#define SH7750_EVT_HUDI 0x600 /* UDI interrupt */ + +/* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */ +#define SH7750_EVT_GPIO 0x620 /* GPIO Interrupt */ + +/* Peripheral Module Interrupts - DMA Controller (DMAC) */ +#define SH7750_EVT_DMAC_DMTE0 0x640 /* DMAC 0 Transfer End Interrupt */ +#define SH7750_EVT_DMAC_DMTE1 0x660 /* DMAC 1 Transfer End Interrupt */ +#define SH7750_EVT_DMAC_DMTE2 0x680 /* DMAC 2 Transfer End Interrupt */ +#define SH7750_EVT_DMAC_DMTE3 0x6A0 /* DMAC 3 Transfer End Interrupt */ +#define SH7750_EVT_DMAC_DMAE 0x6C0 /* DMAC Address Error Interrupt */ + +/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */ +/* (SCIF) */ +#define SH7750_EVT_SCIF_ERI 0x700 /* Receive Error */ +#define SH7750_EVT_SCIF_RXI 0x720 /* Receive FIFO Data Full or + Receive Data ready interrupt */ +#define SH7750_EVT_SCIF_BRI 0x740 /* Break or overrun error */ +#define SH7750_EVT_SCIF_TXI 0x760 /* Transmit FIFO Data Empty */ + +/* + * Power Management + */ +#define SH7750_STBCR_REGOFS 0xC00004 /* offset */ +#define SH7750_STBCR SH7750_P4_REG32(SH7750_STBCR_REGOFS) +#define SH7750_STBCR_A7 SH7750_A7_REG32(SH7750_STBCR_REGOFS) + +#define SH7750_STBCR_STBY 0x80 /* Specifies a transition to standby mode: + 0 - Transition to SLEEP mode on SLEEP + 1 - Transition to STANDBY mode on SLEEP */ +#define SH7750_STBCR_PHZ 0x40 /* State of peripheral module pins in + standby mode: + 0 - normal state + 1 - high-impendance state */ + +#define SH7750_STBCR_PPU 0x20 /* Peripheral module pins pull-up controls */ +#define SH7750_STBCR_MSTP4 0x10 /* Stopping the clock supply to DMAC */ +#define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4 +#define SH7750_STBCR_MSTP3 0x08 /* Stopping the clock supply to SCIF */ +#define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3 +#define SH7750_STBCR_MSTP2 0x04 /* Stopping the clock supply to TMU */ +#define SH7750_STBCR_TMU_STP SH7750_STBCR_MSTP2 +#define SH7750_STBCR_MSTP1 0x02 /* Stopping the clock supply to RTC */ +#define SH7750_STBCR_RTC_STP SH7750_STBCR_MSTP1 +#define SH7750_STBCR_MSPT0 0x01 /* Stopping the clock supply to SCI */ +#define SH7750_STBCR_SCI_STP SH7750_STBCR_MSTP0 + +#define SH7750_STBCR_STBY 0x80 + + +#define SH7750_STBCR2_REGOFS 0xC00010 /* offset */ +#define SH7750_STBCR2 SH7750_P4_REG32(SH7750_STBCR2_REGOFS) +#define SH7750_STBCR2_A7 SH7750_A7_REG32(SH7750_STBCR2_REGOFS) + +#define SH7750_STBCR2_DSLP 0x80 /* Specifies transition to deep sleep mode: + 0 - transition to sleep or standby mode + as it is specified in STBY bit + 1 - transition to deep sleep mode on + execution of SLEEP instruction */ +#define SH7750_STBCR2_MSTP6 0x02 /* Stopping the clock supply to Store Queue + in the cache controller */ +#define SH7750_STBCR2_SQ_STP SH7750_STBCR2_MSTP6 +#define SH7750_STBCR2_MSTP5 0x01 /* Stopping the clock supply to the User + Break Controller (UBC) */ +#define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5 + +/* + * Clock Pulse Generator (CPG) + */ +#define SH7750_FRQCR_REGOFS 0xC00000 /* offset */ +#define SH7750_FRQCR SH7750_P4_REG32(SH7750_FRQCR_REGOFS) +#define SH7750_FRQCR_A7 SH7750_A7_REG32(SH7750_FRQCR_REGOFS) + +#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable + 0 - CKIO pin goes to HiZ/pullup + 1 - Clock is output from CKIO */ +#define SH7750_FRQCR_PLL1EN 0x0400 /* PLL circuit 1 enable */ +#define SH7750_FRQCR_PLL2EN 0x0200 /* PLL circuit 2 enable */ + +#define SH7750_FRQCR_IFC 0x01C0 /* CPU clock frequency division ratio: */ +#define SH7750_FRQCR_IFCDIV1 0x0000 /* 0 - * 1 */ +#define SH7750_FRQCR_IFCDIV2 0x0040 /* 1 - * 1/2 */ +#define SH7750_FRQCR_IFCDIV3 0x0080 /* 2 - * 1/3 */ +#define SH7750_FRQCR_IFCDIV4 0x00C0 /* 3 - * 1/4 */ +#define SH7750_FRQCR_IFCDIV6 0x0100 /* 4 - * 1/6 */ +#define SH7750_FRQCR_IFCDIV8 0x0140 /* 5 - * 1/8 */ + +#define SH7750_FRQCR_BFC 0x0038 /* Bus clock frequency division ratio: */ +#define SH7750_FRQCR_BFCDIV1 0x0000 /* 0 - * 1 */ +#define SH7750_FRQCR_BFCDIV2 0x0008 /* 1 - * 1/2 */ +#define SH7750_FRQCR_BFCDIV3 0x0010 /* 2 - * 1/3 */ +#define SH7750_FRQCR_BFCDIV4 0x0018 /* 3 - * 1/4 */ +#define SH7750_FRQCR_BFCDIV6 0x0020 /* 4 - * 1/6 */ +#define SH7750_FRQCR_BFCDIV8 0x0028 /* 5 - * 1/8 */ + +#define SH7750_FRQCR_PFC 0x0007 /* Peripheral module clock frequency + division ratio: */ +#define SH7750_FRQCR_PFCDIV2 0x0000 /* 0 - * 1/2 */ +#define SH7750_FRQCR_PFCDIV3 0x0001 /* 1 - * 1/3 */ +#define SH7750_FRQCR_PFCDIV4 0x0002 /* 2 - * 1/4 */ +#define SH7750_FRQCR_PFCDIV6 0x0003 /* 3 - * 1/6 */ +#define SH7750_FRQCR_PFCDIV8 0x0004 /* 4 - * 1/8 */ + +/* + * Watchdog Timer (WDT) + */ + +/* Watchdog Timer Counter register - WTCNT */ +#define SH7750_WTCNT_REGOFS 0xC00008 /* offset */ +#define SH7750_WTCNT SH7750_P4_REG32(SH7750_WTCNT_REGOFS) +#define SH7750_WTCNT_A7 SH7750_A7_REG32(SH7750_WTCNT_REGOFS) +#define SH7750_WTCNT_KEY 0x5A00 /* When WTCNT byte register written, + you have to set the upper byte to + 0x5A */ + +/* Watchdog Timer Control/Status register - WTCSR */ +#define SH7750_WTCSR_REGOFS 0xC0000C /* offset */ +#define SH7750_WTCSR SH7750_P4_REG32(SH7750_WTCSR_REGOFS) +#define SH7750_WTCSR_A7 SH7750_A7_REG32(SH7750_WTCSR_REGOFS) +#define SH7750_WTCSR_KEY 0xA500 /* When WTCSR byte register written, + you have to set the upper byte to + 0xA5 */ +#define SH7750_WTCSR_TME 0x80 /* Timer enable (1-upcount start) */ +#define SH7750_WTCSR_MODE 0x40 /* Timer Mode Select: */ +#define SH7750_WTCSR_MODE_WT 0x40 /* Watchdog Timer Mode */ +#define SH7750_WTCSR_MODE_IT 0x00 /* Interval Timer Mode */ +#define SH7750_WTCSR_RSTS 0x20 /* Reset Select: */ +#define SH7750_WTCSR_RST_MAN 0x20 /* Manual Reset */ +#define SH7750_WTCSR_RST_PWR 0x00 /* Power-on Reset */ +#define SH7750_WTCSR_WOVF 0x10 /* Watchdog Timer Overflow Flag */ +#define SH7750_WTCSR_IOVF 0x08 /* Interval Timer Overflow Flag */ +#define SH7750_WTCSR_CKS 0x07 /* Clock Select: */ +#define SH7750_WTCSR_CKS_DIV32 0x00 /* 1/32 of frequency divider 2 input */ +#define SH7750_WTCSR_CKS_DIV64 0x01 /* 1/64 */ +#define SH7750_WTCSR_CKS_DIV128 0x02 /* 1/128 */ +#define SH7750_WTCSR_CKS_DIV256 0x03 /* 1/256 */ +#define SH7750_WTCSR_CKS_DIV512 0x04 /* 1/512 */ +#define SH7750_WTCSR_CKS_DIV1024 0x05 /* 1/1024 */ +#define SH7750_WTCSR_CKS_DIV2048 0x06 /* 1/2048 */ +#define SH7750_WTCSR_CKS_DIV4096 0x07 /* 1/4096 */ + +/* + * Real-Time Clock (RTC) + */ +/* 64-Hz Counter Register (byte, read-only) - R64CNT */ +#define SH7750_R64CNT_REGOFS 0xC80000 /* offset */ +#define SH7750_R64CNT SH7750_P4_REG32(SH7750_R64CNT_REGOFS) +#define SH7750_R64CNT_A7 SH7750_A7_REG32(SH7750_R64CNT_REGOFS) + +/* Second Counter Register (byte, BCD-coded) - RSECCNT */ +#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */ +#define SH7750_RSECCNT SH7750_P4_REG32(SH7750_RSECCNT_REGOFS) +#define SH7750_RSECCNT_A7 SH7750_A7_REG32(SH7750_RSECCNT_REGOFS) + +/* Minute Counter Register (byte, BCD-coded) - RMINCNT */ +#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */ +#define SH7750_RMINCNT SH7750_P4_REG32(SH7750_RMINCNT_REGOFS) +#define SH7750_RMINCNT_A7 SH7750_A7_REG32(SH7750_RMINCNT_REGOFS) + +/* Hour Counter Register (byte, BCD-coded) - RHRCNT */ +#define SH7750_RHRCNT_REGOFS 0xC8000C /* offset */ +#define SH7750_RHRCNT SH7750_P4_REG32(SH7750_RHRCNT_REGOFS) +#define SH7750_RHRCNT_A7 SH7750_A7_REG32(SH7750_RHRCNT_REGOFS) + +/* Day-of-Week Counter Register (byte) - RWKCNT */ +#define SH7750_RWKCNT_REGOFS 0xC80010 /* offset */ +#define SH7750_RWKCNT SH7750_P4_REG32(SH7750_RWKCNT_REGOFS) +#define SH7750_RWKCNT_A7 SH7750_A7_REG32(SH7750_RWKCNT_REGOFS) + +#define SH7750_RWKCNT_SUN 0 /* Sunday */ +#define SH7750_RWKCNT_MON 1 /* Monday */ +#define SH7750_RWKCNT_TUE 2 /* Tuesday */ +#define SH7750_RWKCNT_WED 3 /* Wednesday */ +#define SH7750_RWKCNT_THU 4 /* Thursday */ +#define SH7750_RWKCNT_FRI 5 /* Friday */ +#define SH7750_RWKCNT_SAT 6 /* Saturday */ + +/* Day Counter Register (byte, BCD-coded) - RDAYCNT */ +#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */ +#define SH7750_RDAYCNT SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS) +#define SH7750_RDAYCNT_A7 SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS) + +/* Month Counter Register (byte, BCD-coded) - RMONCNT */ +#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */ +#define SH7750_RMONCNT SH7750_P4_REG32(SH7750_RMONCNT_REGOFS) +#define SH7750_RMONCNT_A7 SH7750_A7_REG32(SH7750_RMONCNT_REGOFS) + +/* Year Counter Register (half, BCD-coded) - RYRCNT */ +#define SH7750_RYRCNT_REGOFS 0xC8001C /* offset */ +#define SH7750_RYRCNT SH7750_P4_REG32(SH7750_RYRCNT_REGOFS) +#define SH7750_RYRCNT_A7 SH7750_A7_REG32(SH7750_RYRCNT_REGOFS) + +/* Second Alarm Register (byte, BCD-coded) - RSECAR */ +#define SH7750_RSECAR_REGOFS 0xC80020 /* offset */ +#define SH7750_RSECAR SH7750_P4_REG32(SH7750_RSECAR_REGOFS) +#define SH7750_RSECAR_A7 SH7750_A7_REG32(SH7750_RSECAR_REGOFS) +#define SH7750_RSECAR_ENB 0x80 /* Second Alarm Enable */ + +/* Minute Alarm Register (byte, BCD-coded) - RMINAR */ +#define SH7750_RMINAR_REGOFS 0xC80024 /* offset */ +#define SH7750_RMINAR SH7750_P4_REG32(SH7750_RMINAR_REGOFS) +#define SH7750_RMINAR_A7 SH7750_A7_REG32(SH7750_RMINAR_REGOFS) +#define SH7750_RMINAR_ENB 0x80 /* Minute Alarm Enable */ + +/* Hour Alarm Register (byte, BCD-coded) - RHRAR */ +#define SH7750_RHRAR_REGOFS 0xC80028 /* offset */ +#define SH7750_RHRAR SH7750_P4_REG32(SH7750_RHRAR_REGOFS) +#define SH7750_RHRAR_A7 SH7750_A7_REG32(SH7750_RHRAR_REGOFS) +#define SH7750_RHRAR_ENB 0x80 /* Hour Alarm Enable */ + +/* Day-of-Week Alarm Register (byte) - RWKAR */ +#define SH7750_RWKAR_REGOFS 0xC8002C /* offset */ +#define SH7750_RWKAR SH7750_P4_REG32(SH7750_RWKAR_REGOFS) +#define SH7750_RWKAR_A7 SH7750_A7_REG32(SH7750_RWKAR_REGOFS) +#define SH7750_RWKAR_ENB 0x80 /* Day-of-week Alarm Enable */ + +#define SH7750_RWKAR_SUN 0 /* Sunday */ +#define SH7750_RWKAR_MON 1 /* Monday */ +#define SH7750_RWKAR_TUE 2 /* Tuesday */ +#define SH7750_RWKAR_WED 3 /* Wednesday */ +#define SH7750_RWKAR_THU 4 /* Thursday */ +#define SH7750_RWKAR_FRI 5 /* Friday */ +#define SH7750_RWKAR_SAT 6 /* Saturday */ + +/* Day Alarm Register (byte, BCD-coded) - RDAYAR */ +#define SH7750_RDAYAR_REGOFS 0xC80030 /* offset */ +#define SH7750_RDAYAR SH7750_P4_REG32(SH7750_RDAYAR_REGOFS) +#define SH7750_RDAYAR_A7 SH7750_A7_REG32(SH7750_RDAYAR_REGOFS) +#define SH7750_RDAYAR_ENB 0x80 /* Day Alarm Enable */ + +/* Month Counter Register (byte, BCD-coded) - RMONAR */ +#define SH7750_RMONAR_REGOFS 0xC80034 /* offset */ +#define SH7750_RMONAR SH7750_P4_REG32(SH7750_RMONAR_REGOFS) +#define SH7750_RMONAR_A7 SH7750_A7_REG32(SH7750_RMONAR_REGOFS) +#define SH7750_RMONAR_ENB 0x80 /* Month Alarm Enable */ + +/* RTC Control Register 1 (byte) - RCR1 */ +#define SH7750_RCR1_REGOFS 0xC80038 /* offset */ +#define SH7750_RCR1 SH7750_P4_REG32(SH7750_RCR1_REGOFS) +#define SH7750_RCR1_A7 SH7750_A7_REG32(SH7750_RCR1_REGOFS) +#define SH7750_RCR1_CF 0x80 /* Carry Flag */ +#define SH7750_RCR1_CIE 0x10 /* Carry Interrupt Enable */ +#define SH7750_RCR1_AIE 0x08 /* Alarm Interrupt Enable */ +#define SH7750_RCR1_AF 0x01 /* Alarm Flag */ + +/* RTC Control Register 2 (byte) - RCR2 */ +#define SH7750_RCR2_REGOFS 0xC8003C /* offset */ +#define SH7750_RCR2 SH7750_P4_REG32(SH7750_RCR2_REGOFS) +#define SH7750_RCR2_A7 SH7750_A7_REG32(SH7750_RCR2_REGOFS) +#define SH7750_RCR2_PEF 0x80 /* Periodic Interrupt Flag */ +#define SH7750_RCR2_PES 0x70 /* Periodic Interrupt Enable: */ +#define SH7750_RCR2_PES_DIS 0x00 /* Periodic Interrupt Disabled */ +#define SH7750_RCR2_PES_DIV256 0x10 /* Generated at 1/256 sec interval */ +#define SH7750_RCR2_PES_DIV64 0x20 /* Generated at 1/64 sec interval */ +#define SH7750_RCR2_PES_DIV16 0x30 /* Generated at 1/16 sec interval */ +#define SH7750_RCR2_PES_DIV4 0x40 /* Generated at 1/4 sec interval */ +#define SH7750_RCR2_PES_DIV2 0x50 /* Generated at 1/2 sec interval */ +#define SH7750_RCR2_PES_x1 0x60 /* Generated at 1 sec interval */ +#define SH7750_RCR2_PES_x2 0x70 /* Generated at 2 sec interval */ +#define SH7750_RCR2_RTCEN 0x08 /* RTC Crystal Oscillator is Operated */ +#define SH7750_RCR2_ADJ 0x04 /* 30-Second Adjastment */ +#define SH7750_RCR2_RESET 0x02 /* Frequency divider circuits are reset */ +#define SH7750_RCR2_START 0x01 /* 0 - sec, min, hr, day-of-week, month, + year counters are stopped + 1 - sec, min, hr, day-of-week, month, + year counters operate normally */ + + +/* + * Timer Unit (TMU) + */ +/* Timer Output Control Register (byte) - TOCR */ +#define SH7750_TOCR_REGOFS 0xD80000 /* offset */ +#define SH7750_TOCR SH7750_P4_REG32(SH7750_TOCR_REGOFS) +#define SH7750_TOCR_A7 SH7750_A7_REG32(SH7750_TOCR_REGOFS) +#define SH7750_TOCR_TCOE 0x01 /* Timer Clock Pin Control: + 0 - TCLK is used as external clock + input or input capture control + 1 - TCLK is used as on-chip RTC + output clock pin */ + +/* Timer Start Register (byte) - TSTR */ +#define SH7750_TSTR_REGOFS 0xD80004 /* offset */ +#define SH7750_TSTR SH7750_P4_REG32(SH7750_TSTR_REGOFS) +#define SH7750_TSTR_A7 SH7750_A7_REG32(SH7750_TSTR_REGOFS) +#define SH7750_TSTR_STR2 0x04 /* TCNT2 performs count operations */ +#define SH7750_TSTR_STR1 0x02 /* TCNT1 performs count operations */ +#define SH7750_TSTR_STR0 0x01 /* TCNT0 performs count operations */ +#define SH7750_TSTR_STR(n) (1 << (n)) + +/* Timer Constant Register - TCOR0, TCOR1, TCOR2 */ +#define SH7750_TCOR_REGOFS(n) (0xD80008 + ((n)*12)) /* offset */ +#define SH7750_TCOR(n) SH7750_P4_REG32(SH7750_TCOR_REGOFS(n)) +#define SH7750_TCOR_A7(n) SH7750_A7_REG32(SH7750_TCOR_REGOFS(n)) +#define SH7750_TCOR0 SH7750_TCOR(0) +#define SH7750_TCOR1 SH7750_TCOR(1) +#define SH7750_TCOR2 SH7750_TCOR(2) +#define SH7750_TCOR0_A7 SH7750_TCOR_A7(0) +#define SH7750_TCOR1_A7 SH7750_TCOR_A7(1) +#define SH7750_TCOR2_A7 SH7750_TCOR_A7(2) + +/* Timer Counter Register - TCNT0, TCNT1, TCNT2 */ +#define SH7750_TCNT_REGOFS(n) (0xD8000C + ((n)*12)) /* offset */ +#define SH7750_TCNT(n) SH7750_P4_REG32(SH7750_TCNT_REGOFS(n)) +#define SH7750_TCNT_A7(n) SH7750_A7_REG32(SH7750_TCNT_REGOFS(n)) +#define SH7750_TCNT0 SH7750_TCNT(0) +#define SH7750_TCNT1 SH7750_TCNT(1) +#define SH7750_TCNT2 SH7750_TCNT(2) +#define SH7750_TCNT0_A7 SH7750_TCNT_A7(0) +#define SH7750_TCNT1_A7 SH7750_TCNT_A7(1) +#define SH7750_TCNT2_A7 SH7750_TCNT_A7(2) + +/* Timer Control Register (half) - TCR0, TCR1, TCR2 */ +#define SH7750_TCR_REGOFS(n) (0xD80010 + ((n)*12)) /* offset */ +#define SH7750_TCR(n) SH7750_P4_REG32(SH7750_TCR_REGOFS(n)) +#define SH7750_TCR_A7(n) SH7750_A7_REG32(SH7750_TCR_REGOFS(n)) +#define SH7750_TCR0 SH7750_TCR(0) +#define SH7750_TCR1 SH7750_TCR(1) +#define SH7750_TCR2 SH7750_TCR(2) +#define SH7750_TCR0_A7 SH7750_TCR_A7(0) +#define SH7750_TCR1_A7 SH7750_TCR_A7(1) +#define SH7750_TCR2_A7 SH7750_TCR_A7(2) + +#define SH7750_TCR2_ICPF 0x200 /* Input Capture Interrupt Flag + (1 - input capture has occured) */ +#define SH7750_TCR_UNF 0x100 /* Underflow flag */ +#define SH7750_TCR2_ICPE 0x0C0 /* Input Capture Control: */ +#define SH7750_TCR2_ICPE_DIS 0x000 /* Input Capture function is not used */ +#define SH7750_TCR2_ICPE_NOINT 0x080 /* Input Capture function is used, but + input capture interrupt is not + enabled */ +#define SH7750_TCR2_ICPE_INT 0x0C0 /* Input Capture function is used, + input capture interrupt enabled */ +#define SH7750_TCR_UNIE 0x020 /* Underflow Interrupt Control + (1 - underflow interrupt enabled) */ +#define SH7750_TCR_CKEG 0x018 /* Clock Edge selection: */ +#define SH7750_TCR_CKEG_RAISE 0x000 /* Count/capture on rising edge */ +#define SH7750_TCR_CKEG_FALL 0x008 /* Count/capture on falling edge */ +#define SH7750_TCR_CKEG_BOTH 0x018 /* Count/capture on both rising and + falling edges */ +#define SH7750_TCR_TPSC 0x007 /* Timer prescaler */ +#define SH7750_TCR_TPSC_DIV4 0x000 /* Counts on peripheral clock/4 */ +#define SH7750_TCR_TPSC_DIV16 0x001 /* Counts on peripheral clock/16 */ +#define SH7750_TCR_TPSC_DIV64 0x002 /* Counts on peripheral clock/64 */ +#define SH7750_TCR_TPSC_DIV256 0x003 /* Counts on peripheral clock/256 */ +#define SH7750_TCR_TPSC_DIV1024 0x004 /* Counts on peripheral clock/1024 */ +#define SH7750_TCR_TPSC_RTC 0x006 /* Counts on on-chip RTC output clk */ +#define SH7750_TCR_TPSC_EXT 0x007 /* Counts on external clock */ + +/* Input Capture Register (read-only) - TCPR2 */ +#define SH7750_TCPR2_REGOFS 0xD8002C /* offset */ +#define SH7750_TCPR2 SH7750_P4_REG32(SH7750_TCPR2_REGOFS) +#define SH7750_TCPR2_A7 SH7750_A7_REG32(SH7750_TCPR2_REGOFS) + +/* + * Bus State Controller - BSC + */ +/* Bus Control Register 1 - BCR1 */ +#define SH7750_BCR1_REGOFS 0x800000 /* offset */ +#define SH7750_BCR1 SH7750_P4_REG32(SH7750_BCR1_REGOFS) +#define SH7750_BCR1_A7 SH7750_A7_REG32(SH7750_BCR1_REGOFS) +#define SH7750_BCR1_ENDIAN 0x80000000 /* Endianness (1 - little endian) */ +#define SH7750_BCR1_MASTER 0x40000000 /* Master/Slave mode (1-master) */ +#define SH7750_BCR1_A0MPX 0x20000000 /* Area 0 Memory Type (0-SRAM,1-MPX) */ +#define SH7750_BCR1_IPUP 0x02000000 /* Input Pin Pull-up Control: + 0 - pull-up resistor is on for + control input pins + 1 - pull-up resistor is off */ +#define SH7750_BCR1_OPUP 0x01000000 /* Output Pin Pull-up Control: + 0 - pull-up resistor is on for + control output pins + 1 - pull-up resistor is off */ +#define SH7750_BCR1_A1MBC 0x00200000 /* Area 1 SRAM Byte Control Mode: + 0 - Area 1 SRAM is set to + normal mode + 1 - Area 1 SRAM is set to byte + control mode */ +#define SH7750_BCR1_A4MBC 0x00100000 /* Area 4 SRAM Byte Control Mode: + 0 - Area 4 SRAM is set to + normal mode + 1 - Area 4 SRAM is set to byte + control mode */ +#define SH7750_BCR1_BREQEN 0x00080000 /* BREQ Enable: + 0 - External requests are not + accepted + 1 - External requests are + accepted */ +#define SH7750_BCR1_PSHR 0x00040000 /* Partial Sharing Bit: + 0 - Master Mode + 1 - Partial-sharing Mode */ +#define SH7750_BCR1_MEMMPX 0x00020000 /* Area 1 to 6 MPX Interface: + 0 - SRAM/burst ROM interface + 1 - MPX interface */ +#define SH7750_BCR1_HIZMEM 0x00008000 /* High Impendance Control. Specifies + the state of A[25:0], BS\, CSn\, + RD/WR\, CE2A\, CE2B\ in standby + mode and when bus is released: + 0 - signals go to High-Z mode + 1 - signals driven */ +#define SH7750_BCR1_HIZCNT 0x00004000 /* High Impendance Control. Specifies + the state of the RAS\, RAS2\, WEn\, + CASn\, DQMn, RD\, CASS\, FRAME\, + RD2\ signals in standby mode and + when bus is released: + 0 - signals go to High-Z mode + 1 - signals driven */ +#define SH7750_BCR1_A0BST 0x00003800 /* Area 0 Burst ROM Control */ +#define SH7750_BCR1_A0BST_SRAM 0x0000 /* Area 0 accessed as SRAM i/f */ +#define SH7750_BCR1_A0BST_ROM4 0x0800 /* Area 0 accessed as burst ROM + interface, 4 cosequtive access */ +#define SH7750_BCR1_A0BST_ROM8 0x1000 /* Area 0 accessed as burst ROM + interface, 8 cosequtive access */ +#define SH7750_BCR1_A0BST_ROM16 0x1800 /* Area 0 accessed as burst ROM + interface, 16 cosequtive access */ +#define SH7750_BCR1_A0BST_ROM32 0x2000 /* Area 0 accessed as burst ROM + interface, 32 cosequtive access */ + +#define SH7750_BCR1_A5BST 0x00000700 /* Area 5 Burst ROM Control */ +#define SH7750_BCR1_A5BST_SRAM 0x0000 /* Area 5 accessed as SRAM i/f */ +#define SH7750_BCR1_A5BST_ROM4 0x0100 /* Area 5 accessed as burst ROM + interface, 4 cosequtive access */ +#define SH7750_BCR1_A5BST_ROM8 0x0200 /* Area 5 accessed as burst ROM + interface, 8 cosequtive access */ +#define SH7750_BCR1_A5BST_ROM16 0x0300 /* Area 5 accessed as burst ROM + interface, 16 cosequtive access */ +#define SH7750_BCR1_A5BST_ROM32 0x0400 /* Area 5 accessed as burst ROM + interface, 32 cosequtive access */ + +#define SH7750_BCR1_A6BST 0x000000E0 /* Area 6 Burst ROM Control */ +#define SH7750_BCR1_A6BST_SRAM 0x0000 /* Area 6 accessed as SRAM i/f */ +#define SH7750_BCR1_A6BST_ROM4 0x0020 /* Area 6 accessed as burst ROM + interface, 4 cosequtive access */ +#define SH7750_BCR1_A6BST_ROM8 0x0040 /* Area 6 accessed as burst ROM + interface, 8 cosequtive access */ +#define SH7750_BCR1_A6BST_ROM16 0x0060 /* Area 6 accessed as burst ROM + interface, 16 cosequtive access */ +#define SH7750_BCR1_A6BST_ROM32 0x0080 /* Area 6 accessed as burst ROM + interface, 32 cosequtive access */ + +#define SH7750_BCR1_DRAMTP 0x001C /* Area 2 and 3 Memory Type */ +#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM 0x0000 /* Area 2 and 3 are SRAM or MPX + interface. */ +#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM 0x0008 /* Area 2 - SRAM/MPX, Area 3 - + synchronous DRAM */ +#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C /* Area 2 and 3 are synchronous + DRAM interface */ +#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM 0x0010 /* Area 2 - SRAM/MPX, Area 3 - + DRAM interface */ +#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM 0x0014 /* Area 2 and 3 are DRAM + interface */ + +#define SH7750_BCR1_A56PCM 0x00000001 /* Area 5 and 6 Bus Type: + 0 - SRAM interface + 1 - PCMCIA interface */ + +/* Bus Control Register 2 (half) - BCR2 */ +#define SH7750_BCR2_REGOFS 0x800004 /* offset */ +#define SH7750_BCR2 SH7750_P4_REG32(SH7750_BCR2_REGOFS) +#define SH7750_BCR2_A7 SH7750_A7_REG32(SH7750_BCR2_REGOFS) + +#define SH7750_BCR2_A0SZ 0xC000 /* Area 0 Bus Width */ +#define SH7750_BCR2_A0SZ_S 14 +#define SH7750_BCR2_A6SZ 0x3000 /* Area 6 Bus Width */ +#define SH7750_BCR2_A6SZ_S 12 +#define SH7750_BCR2_A5SZ 0x0C00 /* Area 5 Bus Width */ +#define SH7750_BCR2_A5SZ_S 10 +#define SH7750_BCR2_A4SZ 0x0300 /* Area 4 Bus Width */ +#define SH7750_BCR2_A4SZ_S 8 +#define SH7750_BCR2_A3SZ 0x00C0 /* Area 3 Bus Width */ +#define SH7750_BCR2_A3SZ_S 6 +#define SH7750_BCR2_A2SZ 0x0030 /* Area 2 Bus Width */ +#define SH7750_BCR2_A2SZ_S 4 +#define SH7750_BCR2_A1SZ 0x000C /* Area 1 Bus Width */ +#define SH7750_BCR2_A1SZ_S 2 +#define SH7750_BCR2_SZ_64 0 /* 64 bits */ +#define SH7750_BCR2_SZ_8 1 /* 8 bits */ +#define SH7750_BCR2_SZ_16 2 /* 16 bits */ +#define SH7750_BCR2_SZ_32 3 /* 32 bits */ +#define SH7750_BCR2_PORTEN 0x0001 /* Port Function Enable : + 0 - D51-D32 are not used as a port + 1 - D51-D32 are used as a port */ + +/* Wait Control Register 1 - WCR1 */ +#define SH7750_WCR1_REGOFS 0x800008 /* offset */ +#define SH7750_WCR1 SH7750_P4_REG32(SH7750_WCR1_REGOFS) +#define SH7750_WCR1_A7 SH7750_A7_REG32(SH7750_WCR1_REGOFS) +#define SH7750_WCR1_DMAIW 0x70000000 /* DACK Device Inter-Cycle Idle + specification */ +#define SH7750_WCR1_DMAIW_S 28 +#define SH7750_WCR1_A6IW 0x07000000 /* Area 6 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A6IW_S 24 +#define SH7750_WCR1_A5IW 0x00700000 /* Area 5 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A5IW_S 20 +#define SH7750_WCR1_A4IW 0x00070000 /* Area 4 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A4IW_S 16 +#define SH7750_WCR1_A3IW 0x00007000 /* Area 3 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A3IW_S 12 +#define SH7750_WCR1_A2IW 0x00000700 /* Area 2 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A2IW_S 8 +#define SH7750_WCR1_A1IW 0x00000070 /* Area 1 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A1IW_S 4 +#define SH7750_WCR1_A0IW 0x00000007 /* Area 0 Inter-Cycle Idle spec. */ +#define SH7750_WCR1_A0IW_S 0 + +/* Wait Control Register 2 - WCR2 */ +#define SH7750_WCR2_REGOFS 0x80000C /* offset */ +#define SH7750_WCR2 SH7750_P4_REG32(SH7750_WCR2_REGOFS) +#define SH7750_WCR2_A7 SH7750_A7_REG32(SH7750_WCR2_REGOFS) + +#define SH7750_WCR2_A6W 0xE0000000 /* Area 6 Wait Control */ +#define SH7750_WCR2_A6W_S 29 +#define SH7750_WCR2_A6B 0x1C000000 /* Area 6 Burst Pitch */ +#define SH7750_WCR2_A6B_S 26 +#define SH7750_WCR2_A5W 0x03800000 /* Area 5 Wait Control */ +#define SH7750_WCR2_A5W_S 23 +#define SH7750_WCR2_A5B 0x00700000 /* Area 5 Burst Pitch */ +#define SH7750_WCR2_A5B_S 20 +#define SH7750_WCR2_A4W 0x000E0000 /* Area 4 Wait Control */ +#define SH7750_WCR2_A4W_S 17 +#define SH7750_WCR2_A3W 0x0000E000 /* Area 3 Wait Control */ +#define SH7750_WCR2_A3W_S 13 +#define SH7750_WCR2_A2W 0x00000E00 /* Area 2 Wait Control */ +#define SH7750_WCR2_A2W_S 9 +#define SH7750_WCR2_A1W 0x000001C0 /* Area 1 Wait Control */ +#define SH7750_WCR2_A1W_S 6 +#define SH7750_WCR2_A0W 0x00000038 /* Area 0 Wait Control */ +#define SH7750_WCR2_A0W_S 3 +#define SH7750_WCR2_A0B 0x00000007 /* Area 0 Burst Pitch */ +#define SH7750_WCR2_A0B_S 0 + +#define SH7750_WCR2_WS0 0 /* 0 wait states inserted */ +#define SH7750_WCR2_WS1 1 /* 1 wait states inserted */ +#define SH7750_WCR2_WS2 2 /* 2 wait states inserted */ +#define SH7750_WCR2_WS3 3 /* 3 wait states inserted */ +#define SH7750_WCR2_WS6 4 /* 6 wait states inserted */ +#define SH7750_WCR2_WS9 5 /* 9 wait states inserted */ +#define SH7750_WCR2_WS12 6 /* 12 wait states inserted */ +#define SH7750_WCR2_WS15 7 /* 15 wait states inserted */ + +#define SH7750_WCR2_BPWS0 0 /* 0 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS1 1 /* 1 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS2 2 /* 2 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS3 3 /* 3 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS4 4 /* 4 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS5 5 /* 5 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS6 6 /* 6 wait states inserted from 2nd access */ +#define SH7750_WCR2_BPWS7 7 /* 7 wait states inserted from 2nd access */ + +/* DRAM CAS\ Assertion Delay (area 3,2) */ +#define SH7750_WCR2_DRAM_CAS_ASW1 0 /* 1 cycle */ +#define SH7750_WCR2_DRAM_CAS_ASW2 1 /* 2 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW3 2 /* 3 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW4 3 /* 4 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW7 4 /* 7 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW10 5 /* 10 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW13 6 /* 13 cycles */ +#define SH7750_WCR2_DRAM_CAS_ASW16 7 /* 16 cycles */ + +/* SDRAM CAS\ Latency Cycles */ +#define SH7750_WCR2_SDRAM_CAS_LAT1 1 /* 1 cycle */ +#define SH7750_WCR2_SDRAM_CAS_LAT2 2 /* 2 cycles */ +#define SH7750_WCR2_SDRAM_CAS_LAT3 3 /* 3 cycles */ +#define SH7750_WCR2_SDRAM_CAS_LAT4 4 /* 4 cycles */ +#define SH7750_WCR2_SDRAM_CAS_LAT5 5 /* 5 cycles */ + +/* Wait Control Register 3 - WCR3 */ +#define SH7750_WCR3_REGOFS 0x800010 /* offset */ +#define SH7750_WCR3 SH7750_P4_REG32(SH7750_WCR3_REGOFS) +#define SH7750_WCR3_A7 SH7750_A7_REG32(SH7750_WCR3_REGOFS) + +#define SH7750_WCR3_A6S 0x04000000 /* Area 6 Write Strobe Setup time */ +#define SH7750_WCR3_A6H 0x03000000 /* Area 6 Data Hold Time */ +#define SH7750_WCR3_A6H_S 24 +#define SH7750_WCR3_A5S 0x00400000 /* Area 5 Write Strobe Setup time */ +#define SH7750_WCR3_A5H 0x00300000 /* Area 5 Data Hold Time */ +#define SH7750_WCR3_A5H_S 20 +#define SH7750_WCR3_A4S 0x00040000 /* Area 4 Write Strobe Setup time */ +#define SH7750_WCR3_A4H 0x00030000 /* Area 4 Data Hold Time */ +#define SH7750_WCR3_A4H_S 16 +#define SH7750_WCR3_A3S 0x00004000 /* Area 3 Write Strobe Setup time */ +#define SH7750_WCR3_A3H 0x00003000 /* Area 3 Data Hold Time */ +#define SH7750_WCR3_A3H_S 12 +#define SH7750_WCR3_A2S 0x00000400 /* Area 2 Write Strobe Setup time */ +#define SH7750_WCR3_A2H 0x00000300 /* Area 2 Data Hold Time */ +#define SH7750_WCR3_A2H_S 8 +#define SH7750_WCR3_A1S 0x00000040 /* Area 1 Write Strobe Setup time */ +#define SH7750_WCR3_A1H 0x00000030 /* Area 1 Data Hold Time */ +#define SH7750_WCR3_A1H_S 4 +#define SH7750_WCR3_A0S 0x00000004 /* Area 0 Write Strobe Setup time */ +#define SH7750_WCR3_A0H 0x00000003 /* Area 0 Data Hold Time */ +#define SH7750_WCR3_A0H_S 0 + +#define SH7750_WCR3_DHWS_0 0 /* 0 wait states data hold time */ +#define SH7750_WCR3_DHWS_1 1 /* 1 wait states data hold time */ +#define SH7750_WCR3_DHWS_2 2 /* 2 wait states data hold time */ +#define SH7750_WCR3_DHWS_3 3 /* 3 wait states data hold time */ + +#define SH7750_MCR_REGOFS 0x800014 /* offset */ +#define SH7750_MCR SH7750_P4_REG32(SH7750_MCR_REGOFS) +#define SH7750_MCR_A7 SH7750_A7_REG32(SH7750_MCR_REGOFS) + +#define SH7750_MCR_RASD 0x80000000 /* RAS Down mode */ +#define SH7750_MCR_MRSET 0x40000000 /* SDRAM Mode Register Set */ +#define SH7750_MCR_PALL 0x00000000 /* SDRAM Precharge All cmd. Mode */ +#define SH7750_MCR_TRC 0x38000000 /* RAS Precharge Time at End of + Refresh: */ +#define SH7750_MCR_TRC_0 0x00000000 /* 0 */ +#define SH7750_MCR_TRC_3 0x08000000 /* 3 */ +#define SH7750_MCR_TRC_6 0x10000000 /* 6 */ +#define SH7750_MCR_TRC_9 0x18000000 /* 9 */ +#define SH7750_MCR_TRC_12 0x20000000 /* 12 */ +#define SH7750_MCR_TRC_15 0x28000000 /* 15 */ +#define SH7750_MCR_TRC_18 0x30000000 /* 18 */ +#define SH7750_MCR_TRC_21 0x38000000 /* 21 */ + +#define SH7750_MCR_TCAS 0x00800000 /* CAS Negation Period */ +#define SH7750_MCR_TCAS_1 0x00000000 /* 1 */ +#define SH7750_MCR_TCAS_2 0x00800000 /* 2 */ + +#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period + SDRAM: minimum number of cycles + until the next bank active cmd + is output after precharging */ +#define SH7750_MCR_TPC_S 19 +#define SH7750_MCR_TPC_SDRAM_1 0x00000000 /* 1 cycle */ +#define SH7750_MCR_TPC_SDRAM_2 0x00080000 /* 2 cycles */ +#define SH7750_MCR_TPC_SDRAM_3 0x00100000 /* 3 cycles */ +#define SH7750_MCR_TPC_SDRAM_4 0x00180000 /* 4 cycles */ +#define SH7750_MCR_TPC_SDRAM_5 0x00200000 /* 5 cycles */ +#define SH7750_MCR_TPC_SDRAM_6 0x00280000 /* 6 cycles */ +#define SH7750_MCR_TPC_SDRAM_7 0x00300000 /* 7 cycles */ +#define SH7750_MCR_TPC_SDRAM_8 0x00380000 /* 8 cycles */ + +#define SH7750_MCR_RCD 0x00030000 /* DRAM: RAS-CAS Assertion Delay time + SDRAM: bank active-read/write cmd + delay time */ +#define SH7750_MCR_RCD_DRAM_2 0x00000000 /* DRAM delay 2 clocks */ +#define SH7750_MCR_RCD_DRAM_3 0x00010000 /* DRAM delay 3 clocks */ +#define SH7750_MCR_RCD_DRAM_4 0x00020000 /* DRAM delay 4 clocks */ +#define SH7750_MCR_RCD_DRAM_5 0x00030000 /* DRAM delay 5 clocks */ +#define SH7750_MCR_RCD_SDRAM_2 0x00010000 /* DRAM delay 2 clocks */ +#define SH7750_MCR_RCD_SDRAM_3 0x00020000 /* DRAM delay 3 clocks */ +#define SH7750_MCR_RCD_SDRAM_4 0x00030000 /* DRAM delay 4 clocks */ + +#define SH7750_MCR_TRWL 0x0000E000 /* SDRAM Write Precharge Delay */ +#define SH7750_MCR_TRWL_1 0x00000000 /* 1 */ +#define SH7750_MCR_TRWL_2 0x00002000 /* 2 */ +#define SH7750_MCR_TRWL_3 0x00004000 /* 3 */ +#define SH7750_MCR_TRWL_4 0x00006000 /* 4 */ +#define SH7750_MCR_TRWL_5 0x00008000 /* 5 */ + +#define SH7750_MCR_TRAS 0x00001C00 /* DRAM: CAS-Before-RAS Refresh RAS + asserting period + SDRAM: Command interval after + synchronous DRAM refresh */ +#define SH7750_MCR_TRAS_DRAM_2 0x00000000 /* 2 */ +#define SH7750_MCR_TRAS_DRAM_3 0x00000400 /* 3 */ +#define SH7750_MCR_TRAS_DRAM_4 0x00000800 /* 4 */ +#define SH7750_MCR_TRAS_DRAM_5 0x00000C00 /* 5 */ +#define SH7750_MCR_TRAS_DRAM_6 0x00001000 /* 6 */ +#define SH7750_MCR_TRAS_DRAM_7 0x00001400 /* 7 */ +#define SH7750_MCR_TRAS_DRAM_8 0x00001800 /* 8 */ +#define SH7750_MCR_TRAS_DRAM_9 0x00001C00 /* 9 */ + +#define SH7750_MCR_TRAS_SDRAM_TRC_4 0x00000000 /* 4 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_5 0x00000400 /* 5 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_6 0x00000800 /* 6 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_7 0x00000C00 /* 7 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_8 0x00001000 /* 8 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_9 0x00001400 /* 9 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_10 0x00001800 /* 10 + TRC */ +#define SH7750_MCR_TRAS_SDRAM_TRC_11 0x00001C00 /* 11 + TRC */ + +#define SH7750_MCR_BE 0x00000200 /* Burst Enable */ +#define SH7750_MCR_SZ 0x00000180 /* Memory Data Size */ +#define SH7750_MCR_SZ_64 0x00000000 /* 64 bits */ +#define SH7750_MCR_SZ_16 0x00000100 /* 16 bits */ +#define SH7750_MCR_SZ_32 0x00000180 /* 32 bits */ + +#define SH7750_MCR_AMX 0x00000078 /* Address Multiplexing */ +#define SH7750_MCR_AMX_S 3 +#define SH7750_MCR_AMX_DRAM_8BIT_COL 0x00000000 /* 8-bit column addr */ +#define SH7750_MCR_AMX_DRAM_9BIT_COL 0x00000008 /* 9-bit column addr */ +#define SH7750_MCR_AMX_DRAM_10BIT_COL 0x00000010 /* 10-bit column addr */ +#define SH7750_MCR_AMX_DRAM_11BIT_COL 0x00000018 /* 11-bit column addr */ +#define SH7750_MCR_AMX_DRAM_12BIT_COL 0x00000020 /* 12-bit column addr */ +/* See SH7750 Hardware Manual for SDRAM address multiplexor selection */ + +#define SH7750_MCR_RFSH 0x00000004 /* Refresh Control */ +#define SH7750_MCR_RMODE 0x00000002 /* Refresh Mode: */ +#define SH7750_MCR_RMODE_NORMAL 0x00000000 /* Normal Refresh Mode */ +#define SH7750_MCR_RMODE_SELF 0x00000002 /* Self-Refresh Mode */ +#define SH7750_MCR_RMODE_EDO 0x00000001 /* EDO Mode */ + +/* SDRAM Mode Set address */ +#define SH7750_SDRAM_MODE_A2_BASE 0xFF900000 +#define SH7750_SDRAM_MODE_A3_BASE 0xFF940000 +#define SH7750_SDRAM_MODE_A2_32BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 2)) +#define SH7750_SDRAM_MODE_A3_32BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 2)) +#define SH7750_SDRAM_MODE_A2_64BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 3)) +#define SH7750_SDRAM_MODE_A3_64BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 3)) + + +/* PCMCIA Control Register (half) - PCR */ +#define SH7750_PCR_REGOFS 0x800018 /* offset */ +#define SH7750_PCR SH7750_P4_REG32(SH7750_PCR_REGOFS) +#define SH7750_PCR_A7 SH7750_A7_REG32(SH7750_PCR_REGOFS) + +#define SH7750_PCR_A5PCW 0xC000 /* Area 5 PCMCIA Wait - Number of wait + states to be added to the number of + waits specified by WCR2 in a low-speed + PCMCIA wait cycle */ +#define SH7750_PCR_A5PCW_0 0x0000 /* 0 waits inserted */ +#define SH7750_PCR_A5PCW_15 0x4000 /* 15 waits inserted */ +#define SH7750_PCR_A5PCW_30 0x8000 /* 30 waits inserted */ +#define SH7750_PCR_A5PCW_50 0xC000 /* 50 waits inserted */ + +#define SH7750_PCR_A6PCW 0x3000 /* Area 6 PCMCIA Wait - Number of wait + states to be added to the number of + waits specified by WCR2 in a low-speed + PCMCIA wait cycle */ +#define SH7750_PCR_A6PCW_0 0x0000 /* 0 waits inserted */ +#define SH7750_PCR_A6PCW_15 0x1000 /* 15 waits inserted */ +#define SH7750_PCR_A6PCW_30 0x2000 /* 30 waits inserted */ +#define SH7750_PCR_A6PCW_50 0x3000 /* 50 waits inserted */ + +#define SH7750_PCR_A5TED 0x0E00 /* Area 5 Address-OE\/WE\ Assertion Delay, + delay time from address output to + OE\/WE\ assertion on the connected + PCMCIA interface */ +#define SH7750_PCR_A5TED_S 9 +#define SH7750_PCR_A6TED 0x01C0 /* Area 6 Address-OE\/WE\ Assertion Delay */ +#define SH7750_PCR_A6TED_S 6 + +#define SH7750_PCR_TED_0WS 0 /* 0 Waits inserted */ +#define SH7750_PCR_TED_1WS 1 /* 1 Waits inserted */ +#define SH7750_PCR_TED_2WS 2 /* 2 Waits inserted */ +#define SH7750_PCR_TED_3WS 3 /* 3 Waits inserted */ +#define SH7750_PCR_TED_6WS 4 /* 6 Waits inserted */ +#define SH7750_PCR_TED_9WS 5 /* 9 Waits inserted */ +#define SH7750_PCR_TED_12WS 6 /* 12 Waits inserted */ +#define SH7750_PCR_TED_15WS 7 /* 15 Waits inserted */ + +#define SH7750_PCR_A5TEH 0x0038 /* Area 5 OE\/WE\ Negation Address delay, + address hold delay time from OE\/WE\ + negation in a write on the connected + PCMCIA interface */ +#define SH7750_PCR_A5TEH_S 3 + +#define SH7750_PCR_A6TEH 0x0007 /* Area 6 OE\/WE\ Negation Address delay */ +#define SH7750_PCR_A6TEH_S 0 + +#define SH7750_PCR_TEH_0WS 0 /* 0 Waits inserted */ +#define SH7750_PCR_TEH_1WS 1 /* 1 Waits inserted */ +#define SH7750_PCR_TEH_2WS 2 /* 2 Waits inserted */ +#define SH7750_PCR_TEH_3WS 3 /* 3 Waits inserted */ +#define SH7750_PCR_TEH_6WS 4 /* 6 Waits inserted */ +#define SH7750_PCR_TEH_9WS 5 /* 9 Waits inserted */ +#define SH7750_PCR_TEH_12WS 6 /* 12 Waits inserted */ +#define SH7750_PCR_TEH_15WS 7 /* 15 Waits inserted */ + +/* Refresh Timer Control/Status Register (half) - RTSCR */ +#define SH7750_RTCSR_REGOFS 0x80001C /* offset */ +#define SH7750_RTCSR SH7750_P4_REG32(SH7750_RTCSR_REGOFS) +#define SH7750_RTCSR_A7 SH7750_A7_REG32(SH7750_RTCSR_REGOFS) + +#define SH7750_RTCSR_KEY 0xA500 /* RTCSR write key */ +#define SH7750_RTCSR_CMF 0x0080 /* Compare-Match Flag (indicates a + match between the refresh timer + counter and refresh time constant) */ +#define SH7750_RTCSR_CMIE 0x0040 /* Compare-Match Interrupt Enable */ +#define SH7750_RTCSR_CKS 0x0038 /* Refresh Counter Clock Selects */ +#define SH7750_RTCSR_CKS_DIS 0x0000 /* Clock Input Disabled */ +#define SH7750_RTCSR_CKS_CKIO_DIV4 0x0008 /* Bus Clock / 4 */ +#define SH7750_RTCSR_CKS_CKIO_DIV16 0x0010 /* Bus Clock / 16 */ +#define SH7750_RTCSR_CKS_CKIO_DIV64 0x0018 /* Bus Clock / 64 */ +#define SH7750_RTCSR_CKS_CKIO_DIV256 0x0020 /* Bus Clock / 256 */ +#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028 /* Bus Clock / 1024 */ +#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030 /* Bus Clock / 2048 */ +#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038 /* Bus Clock / 4096 */ + +#define SH7750_RTCSR_OVF 0x0004 /* Refresh Count Overflow Flag */ +#define SH7750_RTCSR_OVIE 0x0002 /* Refresh Count Overflow Interrupt + Enable */ +#define SH7750_RTCSR_LMTS 0x0001 /* Refresh Count Overflow Limit Select */ +#define SH7750_RTCSR_LMTS_1024 0x0000 /* Count Limit is 1024 */ +#define SH7750_RTCSR_LMTS_512 0x0001 /* Count Limit is 512 */ + +/* Refresh Timer Counter (half) - RTCNT */ +#define SH7750_RTCNT_REGOFS 0x800020 /* offset */ +#define SH7750_RTCNT SH7750_P4_REG32(SH7750_RTCNT_REGOFS) +#define SH7750_RTCNT_A7 SH7750_A7_REG32(SH7750_RTCNT_REGOFS) + +#define SH7750_RTCNT_KEY 0xA500 /* RTCNT write key */ + +/* Refresh Time Constant Register (half) - RTCOR */ +#define SH7750_RTCOR_REGOFS 0x800024 /* offset */ +#define SH7750_RTCOR SH7750_P4_REG32(SH7750_RTCOR_REGOFS) +#define SH7750_RTCOR_A7 SH7750_A7_REG32(SH7750_RTCOR_REGOFS) + +#define SH7750_RTCOR_KEY 0xA500 /* RTCOR write key */ + +/* Refresh Count Register (half) - RFCR */ +#define SH7750_RFCR_REGOFS 0x800028 /* offset */ +#define SH7750_RFCR SH7750_P4_REG32(SH7750_RFCR_REGOFS) +#define SH7750_RFCR_A7 SH7750_A7_REG32(SH7750_RFCR_REGOFS) + +#define SH7750_RFCR_KEY 0xA400 /* RFCR write key */ + +/* + * Direct Memory Access Controller (DMAC) + */ + +/* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */ +#define SH7750_SAR_REGOFS(n) (0xA00000 + ((n)*16)) /* offset */ +#define SH7750_SAR(n) SH7750_P4_REG32(SH7750_SAR_REGOFS(n)) +#define SH7750_SAR_A7(n) SH7750_A7_REG32(SH7750_SAR_REGOFS(n)) +#define SH7750_SAR0 SH7750_SAR(0) +#define SH7750_SAR1 SH7750_SAR(1) +#define SH7750_SAR2 SH7750_SAR(2) +#define SH7750_SAR3 SH7750_SAR(3) +#define SH7750_SAR0_A7 SH7750_SAR_A7(0) +#define SH7750_SAR1_A7 SH7750_SAR_A7(1) +#define SH7750_SAR2_A7 SH7750_SAR_A7(2) +#define SH7750_SAR3_A7 SH7750_SAR_A7(3) + +/* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */ +#define SH7750_DAR_REGOFS(n) (0xA00004 + ((n)*16)) /* offset */ +#define SH7750_DAR(n) SH7750_P4_REG32(SH7750_DAR_REGOFS(n)) +#define SH7750_DAR_A7(n) SH7750_A7_REG32(SH7750_DAR_REGOFS(n)) +#define SH7750_DAR0 SH7750_DAR(0) +#define SH7750_DAR1 SH7750_DAR(1) +#define SH7750_DAR2 SH7750_DAR(2) +#define SH7750_DAR3 SH7750_DAR(3) +#define SH7750_DAR0_A7 SH7750_DAR_A7(0) +#define SH7750_DAR1_A7 SH7750_DAR_A7(1) +#define SH7750_DAR2_A7 SH7750_DAR_A7(2) +#define SH7750_DAR3_A7 SH7750_DAR_A7(3) + +/* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */ +#define SH7750_DMATCR_REGOFS(n) (0xA00008 + ((n)*16)) /* offset */ +#define SH7750_DMATCR(n) SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n)) +#define SH7750_DMATCR_A7(n) SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n)) +#define SH7750_DMATCR0_P4 SH7750_DMATCR(0) +#define SH7750_DMATCR1_P4 SH7750_DMATCR(1) +#define SH7750_DMATCR2_P4 SH7750_DMATCR(2) +#define SH7750_DMATCR3_P4 SH7750_DMATCR(3) +#define SH7750_DMATCR0_A7 SH7750_DMATCR_A7(0) +#define SH7750_DMATCR1_A7 SH7750_DMATCR_A7(1) +#define SH7750_DMATCR2_A7 SH7750_DMATCR_A7(2) +#define SH7750_DMATCR3_A7 SH7750_DMATCR_A7(3) + +/* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */ +#define SH7750_CHCR_REGOFS(n) (0xA0000C + ((n)*16)) /* offset */ +#define SH7750_CHCR(n) SH7750_P4_REG32(SH7750_CHCR_REGOFS(n)) +#define SH7750_CHCR_A7(n) SH7750_A7_REG32(SH7750_CHCR_REGOFS(n)) +#define SH7750_CHCR0 SH7750_CHCR(0) +#define SH7750_CHCR1 SH7750_CHCR(1) +#define SH7750_CHCR2 SH7750_CHCR(2) +#define SH7750_CHCR3 SH7750_CHCR(3) +#define SH7750_CHCR0_A7 SH7750_CHCR_A7(0) +#define SH7750_CHCR1_A7 SH7750_CHCR_A7(1) +#define SH7750_CHCR2_A7 SH7750_CHCR_A7(2) +#define SH7750_CHCR3_A7 SH7750_CHCR_A7(3) + +#define SH7750_CHCR_SSA 0xE0000000 /* Source Address Space Attribute */ +#define SH7750_CHCR_SSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ +#define SH7750_CHCR_SSA_DYNBSZ 0x20000000 /* Dynamic Bus Sizing I/O space */ +#define SH7750_CHCR_SSA_IO8 0x40000000 /* 8-bit I/O space */ +#define SH7750_CHCR_SSA_IO16 0x60000000 /* 16-bit I/O space */ +#define SH7750_CHCR_SSA_CMEM8 0x80000000 /* 8-bit common memory space */ +#define SH7750_CHCR_SSA_CMEM16 0xA0000000 /* 16-bit common memory space */ +#define SH7750_CHCR_SSA_AMEM8 0xC0000000 /* 8-bit attribute memory space */ +#define SH7750_CHCR_SSA_AMEM16 0xE0000000 /* 16-bit attribute memory space */ + +#define SH7750_CHCR_STC 0x10000000 /* Source Address Wait Control Select, + specifies CS5 or CS6 space wait + control for PCMCIA access */ + +#define SH7750_CHCR_DSA 0x0E000000 /* Source Address Space Attribute */ +#define SH7750_CHCR_DSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ +#define SH7750_CHCR_DSA_DYNBSZ 0x02000000 /* Dynamic Bus Sizing I/O space */ +#define SH7750_CHCR_DSA_IO8 0x04000000 /* 8-bit I/O space */ +#define SH7750_CHCR_DSA_IO16 0x06000000 /* 16-bit I/O space */ +#define SH7750_CHCR_DSA_CMEM8 0x08000000 /* 8-bit common memory space */ +#define SH7750_CHCR_DSA_CMEM16 0x0A000000 /* 16-bit common memory space */ +#define SH7750_CHCR_DSA_AMEM8 0x0C000000 /* 8-bit attribute memory space */ +#define SH7750_CHCR_DSA_AMEM16 0x0E000000 /* 16-bit attribute memory space */ + +#define SH7750_CHCR_DTC 0x01000000 /* Destination Address Wait Control + Select, specifies CS5 or CS6 + space wait control for PCMCIA + access */ + +#define SH7750_CHCR_DS 0x00080000 /* DREQ\ Select : */ +#define SH7750_CHCR_DS_LOWLVL 0x00000000 /* Low Level Detection */ +#define SH7750_CHCR_DS_FALL 0x00080000 /* Falling Edge Detection */ + +#define SH7750_CHCR_RL 0x00040000 /* Request Check Level: */ +#define SH7750_CHCR_RL_ACTH 0x00000000 /* DRAK is an active high out */ +#define SH7750_CHCR_RL_ACTL 0x00040000 /* DRAK is an active low out */ + +#define SH7750_CHCR_AM 0x00020000 /* Acknowledge Mode: */ +#define SH7750_CHCR_AM_RD 0x00000000 /* DACK is output in read cycle */ +#define SH7750_CHCR_AM_WR 0x00020000 /* DACK is output in write cycle */ + +#define SH7750_CHCR_AL 0x00010000 /* Acknowledge Level: */ +#define SH7750_CHCR_AL_ACTH 0x00000000 /* DACK is an active high out */ +#define SH7750_CHCR_AL_ACTL 0x00010000 /* DACK is an active low out */ + +#define SH7750_CHCR_DM 0x0000C000 /* Destination Address Mode: */ +#define SH7750_CHCR_DM_FIX 0x00000000 /* Destination Addr Fixed */ +#define SH7750_CHCR_DM_INC 0x00004000 /* Destination Addr Incremented */ +#define SH7750_CHCR_DM_DEC 0x00008000 /* Destination Addr Decremented */ + +#define SH7750_CHCR_SM 0x00003000 /* Source Address Mode: */ +#define SH7750_CHCR_SM_FIX 0x00000000 /* Source Addr Fixed */ +#define SH7750_CHCR_SM_INC 0x00001000 /* Source Addr Incremented */ +#define SH7750_CHCR_SM_DEC 0x00002000 /* Source Addr Decremented */ + +#define SH7750_CHCR_RS 0x00000F00 /* Request Source Select: */ +#define SH7750_CHCR_RS_ER_DA_EA_TO_EA 0x000 /* External Request, Dual Address + Mode (External Addr Space-> + External Addr Space) */ +#define SH7750_CHCR_RS_ER_SA_EA_TO_ED 0x200 /* External Request, Single + Address Mode (External Addr + Space -> External Device) */ +#define SH7750_CHCR_RS_ER_SA_ED_TO_EA 0x300 /* External Request, Single + Address Mode, (External + Device -> External Addr + Space) */ +#define SH7750_CHCR_RS_AR_EA_TO_EA 0x400 /* Auto-Request (External Addr + Space -> External Addr Space) */ + +#define SH7750_CHCR_RS_AR_EA_TO_OCP 0x500 /* Auto-Request (External Addr + Space -> On-chip Peripheral + Module) */ +#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip + Peripheral Module -> + External Addr Space */ +#define SH7750_CHCR_RS_SCITX_EA_TO_SC 0x800 /* SCI Transmit-Data-Empty intr + transfer request (external + address space -> SCTDR1) */ +#define SH7750_CHCR_RS_SCIRX_SC_TO_EA 0x900 /* SCI Receive-Data-Full intr + transfer request (SCRDR1 -> + External Addr Space) */ +#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC 0xA00 /* SCIF Transmit-Data-Empty intr + transfer request (external + address space -> SCFTDR1) */ +#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA 0xB00 /* SCIF Receive-Data-Full intr + transfer request (SCFRDR2 -> + External Addr Space) */ +#define SH7750_CHCR_RS_TMU2_EA_TO_EA 0xC00 /* TMU Channel 2 (input capture + interrupt), (external address + space -> external address + space) */ +#define SH7750_CHCR_RS_TMU2_EA_TO_OCP 0xD00 /* TMU Channel 2 (input capture + interrupt), (external address + space -> on-chip peripheral + module) */ +#define SH7750_CHCR_RS_TMU2_OCP_TO_EA 0xE00 /* TMU Channel 2 (input capture + interrupt), (on-chip + peripheral module -> external + address space) */ + +#define SH7750_CHCR_TM 0x00000080 /* Transmit mode: */ +#define SH7750_CHCR_TM_CSTEAL 0x00000000 /* Cycle Steal Mode */ +#define SH7750_CHCR_TM_BURST 0x00000080 /* Burst Mode */ + +#define SH7750_CHCR_TS 0x00000070 /* Transmit Size: */ +#define SH7750_CHCR_TS_QUAD 0x00000000 /* Quadword Size (64 bits) */ +#define SH7750_CHCR_TS_BYTE 0x00000010 /* Byte Size (8 bit) */ +#define SH7750_CHCR_TS_WORD 0x00000020 /* Word Size (16 bit) */ +#define SH7750_CHCR_TS_LONG 0x00000030 /* Longword Size (32 bit) */ +#define SH7750_CHCR_TS_BLOCK 0x00000040 /* 32-byte block transfer */ + +#define SH7750_CHCR_IE 0x00000004 /* Interrupt Enable */ +#define SH7750_CHCR_TE 0x00000002 /* Transfer End */ +#define SH7750_CHCR_DE 0x00000001 /* DMAC Enable */ + +/* DMA Operation Register - DMAOR */ +#define SH7750_DMAOR_REGOFS 0xA00040 /* offset */ +#define SH7750_DMAOR SH7750_P4_REG32(SH7750_DMAOR_REGOFS) +#define SH7750_DMAOR_A7 SH7750_A7_REG32(SH7750_DMAOR_REGOFS) + +#define SH7750_DMAOR_DDT 0x00008000 /* On-Demand Data Transfer Mode */ + +#define SH7750_DMAOR_PR 0x00000300 /* Priority Mode: */ +#define SH7750_DMAOR_PR_0123 0x00000000 /* CH0 > CH1 > CH2 > CH3 */ +#define SH7750_DMAOR_PR_0231 0x00000100 /* CH0 > CH2 > CH3 > CH1 */ +#define SH7750_DMAOR_PR_2013 0x00000200 /* CH2 > CH0 > CH1 > CH3 */ +#define SH7750_DMAOR_PR_RR 0x00000300 /* Round-robin mode */ + +#define SH7750_DMAOR_COD 0x00000010 /* Check Overrun for DREQ\ */ +#define SH7750_DMAOR_AE 0x00000004 /* Address Error flag */ +#define SH7750_DMAOR_NMIF 0x00000002 /* NMI Flag */ +#define SH7750_DMAOR_DME 0x00000001 /* DMAC Master Enable */ + +/* + * Serial Communication Interface - SCI + * Serial Communication Interface with FIFO - SCIF + */ +/* SCI Receive Data Register (byte, read-only) - SCRDR1, SCFRDR2 */ +#define SH7750_SCRDR_REGOFS(n) ((n) == 1 ? 0xE00014 : 0xE80014) /* offset */ +#define SH7750_SCRDR(n) SH7750_P4_REG32(SH7750_SCRDR_REGOFS(n)) +#define SH7750_SCRDR1 SH7750_SCRDR(1) +#define SH7750_SCRDR2 SH7750_SCRDR(2) +#define SH7750_SCRDR_A7(n) SH7750_A7_REG32(SH7750_SCRDR_REGOFS(n)) +#define SH7750_SCRDR1_A7 SH7750_SCRDR_A7(1) +#define SH7750_SCRDR2_A7 SH7750_SCRDR_A7(2) + +/* SCI Transmit Data Register (byte) - SCTDR1, SCFTDR2 */ +#define SH7750_SCTDR_REGOFS(n) ((n) == 1 ? 0xE0000C : 0xE8000C) /* offset */ +#define SH7750_SCTDR(n) SH7750_P4_REG32(SH7750_SCTDR_REGOFS(n)) +#define SH7750_SCTDR1 SH7750_SCTDR(1) +#define SH7750_SCTDR2 SH7750_SCTDR(2) +#define SH7750_SCTDR_A7(n) SH7750_A7_REG32(SH7750_SCTDR_REGOFS(n)) +#define SH7750_SCTDR1_A7 SH7750_SCTDR_A7(1) +#define SH7750_SCTDR2_A7 SH7750_SCTDR_A7(2) + +/* SCI Serial Mode Register - SCSMR1(byte), SCSMR2(half) */ +#define SH7750_SCSMR_REGOFS(n) ((n) == 1 ? 0xE00000 : 0xE80000) /* offset */ +#define SH7750_SCSMR(n) SH7750_P4_REG32(SH7750_SCSMR_REGOFS(n)) +#define SH7750_SCSMR1 SH7750_SCSMR(1) +#define SH7750_SCSMR2 SH7750_SCSMR(2) +#define SH7750_SCSMR_A7(n) SH7750_A7_REG32(SH7750_SCSMR_REGOFS(n)) +#define SH7750_SCSMR1_A7 SH7750_SCSMR_A7(1) +#define SH7750_SCSMR2_A7 SH7750_SCSMR_A7(2) + +#define SH7750_SCSMR1_CA 0x80 /* Communication Mode (C/A\): */ +#define SH7750_SCSMR1_CA_ASYNC 0x00 /* Asynchronous Mode */ +#define SH7750_SCSMR1_CA_SYNC 0x80 /* Synchronous Mode */ +#define SH7750_SCSMR_CHR 0x40 /* Character Length: */ +#define SH7750_SCSMR_CHR_8 0x00 /* 8-bit data */ +#define SH7750_SCSMR_CHR_7 0x40 /* 7-bit data */ +#define SH7750_SCSMR_PE 0x20 /* Parity Enable */ +#define SH7750_SCSMR_PM 0x10 /* Parity Mode: */ +#define SH7750_SCSMR_PM_EVEN 0x00 /* Even Parity */ +#define SH7750_SCSMR_PM_ODD 0x10 /* Odd Parity */ +#define SH7750_SCSMR_STOP 0x08 /* Stop Bit Length: */ +#define SH7750_SCSMR_STOP_1 0x00 /* 1 stop bit */ +#define SH7750_SCSMR_STOP_2 0x08 /* 2 stop bit */ +#define SH7750_SCSMR1_MP 0x04 /* Multiprocessor Mode */ +#define SH7750_SCSMR_CKS 0x03 /* Clock Select */ +#define SH7750_SCSMR_CKS_S 0 +#define SH7750_SCSMR_CKS_DIV1 0x00 /* Periph clock */ +#define SH7750_SCSMR_CKS_DIV4 0x01 /* Periph clock / 4 */ +#define SH7750_SCSMR_CKS_DIV16 0x02 /* Periph clock / 16 */ +#define SH7750_SCSMR_CKS_DIV64 0x03 /* Periph clock / 64 */ + +/* SCI Serial Control Register - SCSCR1(byte), SCSCR2(half) */ +#define SH7750_SCSCR_REGOFS(n) ((n) == 1 ? 0xE00008 : 0xE80008) /* offset */ +#define SH7750_SCSCR(n) SH7750_P4_REG32(SH7750_SCSCR_REGOFS(n)) +#define SH7750_SCSCR1 SH7750_SCSCR(1) +#define SH7750_SCSCR2 SH7750_SCSCR(2) +#define SH7750_SCSCR_A7(n) SH7750_A7_REG32(SH7750_SCSCR_REGOFS(n)) +#define SH7750_SCSCR1_A7 SH7750_SCSCR_A7(1) +#define SH7750_SCSCR2_A7 SH7750_SCSCR_A7(2) + +#define SH7750_SCSCR_TIE 0x80 /* Transmit Interrupt Enable */ +#define SH7750_SCSCR_RIE 0x40 /* Receive Interrupt Enable */ +#define SH7750_SCSCR_TE 0x20 /* Transmit Enable */ +#define SH7750_SCSCR_RE 0x10 /* Receive Enable */ +#define SH7750_SCSCR1_MPIE 0x08 /* Multiprocessor Interrupt Enable */ +#define SH7750_SCSCR2_REIE 0x08 /* Receive Error Interrupt Enable */ +#define SH7750_SCSCR1_TEIE 0x04 /* Transmit End Interrupt Enable */ +#define SH7750_SCSCR1_CKE 0x03 /* Clock Enable: */ +#define SH7750_SCSCR_CKE_INTCLK 0x00 /* Use Internal Clock */ +#define SH7750_SCSCR_CKE_EXTCLK 0x02 /* Use External Clock from SCK */ +#define SH7750_SCSCR1_CKE_ASYNC_SCK_CLKOUT 0x01 /* Use SCK as a clock output + in asynchronous mode */ + +/* SCI Serial Status Register - SCSSR1(byte), SCSFR2(half) */ +#define SH7750_SCSSR_REGOFS(n) ((n) == 1 ? 0xE00010 : 0xE80010) /* offset */ +#define SH7750_SCSSR(n) SH7750_P4_REG32(SH7750_SCSSR_REGOFS(n)) +#define SH7750_SCSSR1 SH7750_SCSSR(1) +#define SH7750_SCSFR2 SH7750_SCSSR(2) +#define SH7750_SCSSR_A7(n) SH7750_A7_REG32(SH7750_SCSSR_REGOFS(n)) +#define SH7750_SCSSR1_A7 SH7750_SCSSR_A7(1) +#define SH7750_SCSFR2_A7 SH7750_SCSSR_A7(2) + +#define SH7750_SCSSR1_TDRE 0x80 /* Transmit Data Register Empty */ +#define SH7750_SCSSR1_RDRF 0x40 /* Receive Data Register Full */ +#define SH7750_SCSSR1_ORER 0x20 /* Overrun Error */ +#define SH7750_SCSSR1_FER 0x10 /* Framing Error */ +#define SH7750_SCSSR1_PER 0x08 /* Parity Error */ +#define SH7750_SCSSR1_TEND 0x04 /* Transmit End */ +#define SH7750_SCSSR1_MPB 0x02 /* Multiprocessor Bit */ +#define SH7750_SCSSR1_MPBT 0x01 /* Multiprocessor Bit Transfer */ + +#define SH7750_SCFSR2_PERN 0xF000 /* Number of Parity Errors */ +#define SH7750_SCFSR2_PERN_S 12 +#define SH7750_SCFSR2_FERN 0x0F00 /* Number of Framing Errors */ +#define SH7750_SCFSR2_FERN_S 8 +#define SH7750_SCFSR2_ER 0x0080 /* Receive Error */ +#define SH7750_SCFSR2_TEND 0x0040 /* Transmit End */ +#define SH7750_SCFSR2_TDFE 0x0020 /* Transmit FIFO Data Empty */ +#define SH7750_SCFSR2_BRK 0x0010 /* Break Detect */ +#define SH7750_SCFSR2_FER 0x0008 /* Framing Error */ +#define SH7750_SCFSR2_PER 0x0004 /* Parity Error */ +#define SH7750_SCFSR2_RDF 0x0002 /* Receive FIFO Data Full */ +#define SH7750_SCFSR2_DR 0x0001 /* Receive Data Ready */ + +/* SCI Serial Port Register - SCSPTR1(byte) */ +#define SH7750_SCSPTR1_REGOFS 0xE0001C /* offset */ +#define SH7750_SCSPTR1 SH7750_P4_REG32(SH7750_SCSPTR1_REGOFS) +#define SH7750_SCSPTR1_A7 SH7750_A7_REG32(SH7750_SCSPTR1_REGOFS) + +#define SH7750_SCSPTR1_EIO 0x80 /* Error Interrupt Only */ +#define SH7750_SCSPTR1_SPB1IO 0x08 /* 1: Output SPB1DT bit to SCK pin */ +#define SH7750_SCSPTR1_SPB1DT 0x04 /* Serial Port Clock Port Data */ +#define SH7750_SCSPTR1_SPB0IO 0x02 /* 1: Output SPB0DT bit to TxD pin */ +#define SH7750_SCSPTR1_SPB0DT 0x01 /* Serial Port Break Data */ + +/* SCIF Serial Port Register - SCSPTR2(half) */ +#define SH7750_SCSPTR2_REGOFS 0xE80020 /* offset */ +#define SH7750_SCSPTR2 SH7750_P4_REG32(SH7750_SCSPTR2_REGOFS) +#define SH7750_SCSPTR2_A7 SH7750_A7_REG32(SH7750_SCSPTR2_REGOFS) + +#define SH7750_SCSPTR2_RTSIO 0x80 /* 1: Output RTSDT bit to RTS2\ pin */ +#define SH7750_SCSPTR2_RTSDT 0x40 /* RTS Port Data */ +#define SH7750_SCSPTR2_CTSIO 0x20 /* 1: Output CTSDT bit to CTS2\ pin */ +#define SH7750_SCSPTR2_CTSDT 0x10 /* CTS Port Data */ +#define SH7750_SCSPTR2_SPB2IO 0x02 /* 1: Output SPBDT bit to TxD2 pin */ +#define SH7750_SCSPTR2_SPB2DT 0x01 /* Serial Port Break Data */ + +/* SCI Bit Rate Register - SCBRR1(byte), SCBRR2(byte) */ +#define SH7750_SCBRR_REGOFS(n) ((n) == 1 ? 0xE00004 : 0xE80004) /* offset */ +#define SH7750_SCBRR(n) SH7750_P4_REG32(SH7750_SCBRR_REGOFS(n)) +#define SH7750_SCBRR1 SH7750_SCBRR_P4(1) +#define SH7750_SCBRR2 SH7750_SCBRR_P4(2) +#define SH7750_SCBRR_A7(n) SH7750_A7_REG32(SH7750_SCBRR_REGOFS(n)) +#define SH7750_SCBRR1_A7 SH7750_SCBRR_A7(1) +#define SH7750_SCBRR2_A7 SH7750_SCBRR_A7(2) + +/* SCIF FIFO Control Register - SCFCR2(half) */ +#define SH7750_SCFCR2_REGOFS 0xE80018 /* offset */ +#define SH7750_SCFCR2 SH7750_P4_REG32(SH7750_SCFCR2_REGOFS) +#define SH7750_SCFCR2_A7 SH7750_A7_REG32(SH7750_SCFCR2_REGOFS) + +#define SH7750_SCFCR2_RSTRG 0x700 /* RTS2\ Output Active Trigger; RTS2\ + signal goes to high level when the + number of received data stored in + FIFO exceeds the trigger number */ +#define SH7750_SCFCR2_RSTRG_15 0x000 /* 15 bytes */ +#define SH7750_SCFCR2_RSTRG_1 0x000 /* 1 byte */ +#define SH7750_SCFCR2_RSTRG_4 0x000 /* 4 bytes */ +#define SH7750_SCFCR2_RSTRG_6 0x000 /* 6 bytes */ +#define SH7750_SCFCR2_RSTRG_8 0x000 /* 8 bytes */ +#define SH7750_SCFCR2_RSTRG_10 0x000 /* 10 bytes */ +#define SH7750_SCFCR2_RSTRG_14 0x000 /* 14 bytes */ + +#define SH7750_SCFCR2_RTRG 0x0C0 /* Receive FIFO Data Number Trigger, + Receive Data Full (RDF) Flag sets + when number of receive data bytes is + equal or greater than the trigger + number */ +#define SH7750_SCFCR2_RTRG_1 0x000 /* 1 byte */ +#define SH7750_SCFCR2_RTRG_4 0x040 /* 4 bytes */ +#define SH7750_SCFCR2_RTRG_8 0x080 /* 8 bytes */ +#define SH7750_SCFCR2_RTRG_14 0x0C0 /* 14 bytes */ + +#define SH7750_SCFCR2_TTRG 0x030 /* Transmit FIFO Data Number Trigger, + Transmit FIFO Data Register Empty (TDFE) + flag sets when the number of remaining + transmit data bytes is equal or less + than the trigger number */ +#define SH7750_SCFCR2_TTRG_8 0x000 /* 8 bytes */ +#define SH7750_SCFCR2_TTRG_4 0x010 /* 4 bytes */ +#define SH7750_SCFCR2_TTRG_2 0x020 /* 2 bytes */ +#define SH7750_SCFCR2_TTRG_1 0x030 /* 1 byte */ + +#define SH7750_SCFCR2_MCE 0x008 /* Modem Control Enable */ +#define SH7750_SCFCR2_TFRST 0x004 /* Transmit FIFO Data Register Reset, + invalidates the transmit data in the + transmit FIFO */ +#define SH7750_SCFCR2_RFRST 0x002 /* Receive FIFO Data Register Reset, + invalidates the receive data in the + receive FIFO data register and resets + it to the empty state */ +#define SH7750_SCFCR2_LOOP 0x001 /* Loopback Test */ + +/* SCIF FIFO Data Count Register - SCFDR2(half, read-only) */ +#define SH7750_SCFDR2_REGOFS 0xE8001C /* offset */ +#define SH7750_SCFDR2 SH7750_P4_REG32(SH7750_SCFDR2_REGOFS) +#define SH7750_SCFDR2_A7 SH7750_A7_REG32(SH7750_SCFDR2_REGOFS) + +#define SH7750_SCFDR2_T 0x1F00 /* Number of untransmitted data bytes + in transmit FIFO */ +#define SH7750_SCFDR2_T_S 8 +#define SH7750_SCFDR2_R 0x001F /* Number of received data bytes in + receive FIFO */ +#define SH7750_SCFDR2_R_S 0 + +/* SCIF Line Status Register - SCLSR2(half, read-only) */ +#define SH7750_SCLSR2_REGOFS 0xE80024 /* offset */ +#define SH7750_SCLSR2 SH7750_P4_REG32(SH7750_SCLSR2_REGOFS) +#define SH7750_SCLSR2_A7 SH7750_A7_REG32(SH7750_SCLSR2_REGOFS) + +#define SH7750_SCLSR2_ORER 0x0001 /* Overrun Error */ + +/* + * SCI-based Smart Card Interface + */ +/* Smart Card Mode Register - SCSCMR1(byte) */ +#define SH7750_SCSCMR1_REGOFS 0xE00018 /* offset */ +#define SH7750_SCSCMR1 SH7750_P4_REG32(SH7750_SCSCMR1_REGOFS) +#define SH7750_SCSCMR1_A7 SH7750_A7_REG32(SH7750_SCSCMR1_REGOFS) + +#define SH7750_SCSCMR1_SDIR 0x08 /* Smart Card Data Transfer Direction: */ +#define SH7750_SCSCMR1_SDIR_LSBF 0x00 /* LSB-first */ +#define SH7750_SCSCMR1_SDIR_MSBF 0x08 /* MSB-first */ + +#define SH7750_SCSCMR1_SINV 0x04 /* Smart Card Data Inversion */ +#define SH7750_SCSCMR1_SMIF 0x01 /* Smart Card Interface Mode Select */ + +/* Smart-card specific bits in other registers */ +/* SCSMR1: */ +#define SH7750_SCSMR1_GSM 0x80 /* GSM mode select */ + +/* SCSSR1: */ +#define SH7750_SCSSR1_ERS 0x10 /* Error Signal Status */ + +/* + * I/O Ports + */ +/* Port Control Register A - PCTRA */ +#define SH7750_PCTRA_REGOFS 0x80002C /* offset */ +#define SH7750_PCTRA SH7750_P4_REG32(SH7750_PCTRA_REGOFS) +#define SH7750_PCTRA_A7 SH7750_A7_REG32(SH7750_PCTRA_REGOFS) + +#define SH7750_PCTRA_PBPUP(n) 0 /* Bit n is pulled up */ +#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1)) /* Bit n is not pulled up */ +#define SH7750_PCTRA_PBINP(n) 0 /* Bit n is an input */ +#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2)) /* Bit n is an output */ + +/* Port Data Register A - PDTRA(half) */ +#define SH7750_PDTRA_REGOFS 0x800030 /* offset */ +#define SH7750_PDTRA SH7750_P4_REG32(SH7750_PDTRA_REGOFS) +#define SH7750_PDTRA_A7 SH7750_A7_REG32(SH7750_PDTRA_REGOFS) + +#define SH7750_PDTRA_BIT(n) (1 << (n)) + +/* Port Control Register B - PCTRB */ +#define SH7750_PCTRB_REGOFS 0x800040 /* offset */ +#define SH7750_PCTRB SH7750_P4_REG32(SH7750_PCTRB_REGOFS) +#define SH7750_PCTRB_A7 SH7750_A7_REG32(SH7750_PCTRB_REGOFS) + +#define SH7750_PCTRB_PBPUP(n) 0 /* Bit n is pulled up */ +#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1)) /* Bit n is not pulled up */ +#define SH7750_PCTRB_PBINP(n) 0 /* Bit n is an input */ +#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2)) /* Bit n is an output */ + +/* Port Data Register B - PDTRB(half) */ +#define SH7750_PDTRB_REGOFS 0x800044 /* offset */ +#define SH7750_PDTRB SH7750_P4_REG32(SH7750_PDTRB_REGOFS) +#define SH7750_PDTRB_A7 SH7750_A7_REG32(SH7750_PDTRB_REGOFS) + +#define SH7750_PDTRB_BIT(n) (1 << ((n)-16)) + +/* GPIO Interrupt Control Register - GPIOIC(half) */ +#define SH7750_GPIOIC_REGOFS 0x800048 /* offset */ +#define SH7750_GPIOIC SH7750_P4_REG32(SH7750_GPIOIC_REGOFS) +#define SH7750_GPIOIC_A7 SH7750_A7_REG32(SH7750_GPIOIC_REGOFS) + +#define SH7750_GPIOIC_PTIREN(n) (1 << (n)) /* Port n is used as a GPIO int */ + +/* + * Interrupt Controller - INTC + */ +/* Interrupt Control Register - ICR (half) */ +#define SH7750_ICR_REGOFS 0xD00000 /* offset */ +#define SH7750_ICR SH7750_P4_REG32(SH7750_ICR_REGOFS) +#define SH7750_ICR_A7 SH7750_A7_REG32(SH7750_ICR_REGOFS) + +#define SH7750_ICR_NMIL 0x8000 /* NMI Input Level */ +#define SH7750_ICR_MAI 0x4000 /* NMI Interrupt Mask */ + +#define SH7750_ICR_NMIB 0x0200 /* NMI Block Mode: */ +#define SH7750_ICR_NMIB_BLK 0x0000 /* NMI requests held pending while + SR.BL bit is set to 1 */ +#define SH7750_ICR_NMIB_NBLK 0x0200 /* NMI requests detected when SR.BL bit + set to 1 */ + +#define SH7750_ICR_NMIE 0x0100 /* NMI Edge Select: */ +#define SH7750_ICR_NMIE_FALL 0x0000 /* Interrupt request detected on falling + edge of NMI input */ +#define SH7750_ICR_NMIE_RISE 0x0100 /* Interrupt request detected on rising + edge of NMI input */ + +#define SH7750_ICR_IRLM 0x0080 /* IRL Pin Mode: */ +#define SH7750_ICR_IRLM_ENC 0x0000 /* IRL\ pins used as a level-encoded + interrupt requests */ +#define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent + interrupt requests */ + +/* Interrupt Priority Register A - IPRA (half) */ +#define SH7750_IPRA_REGOFS 0xD00004 /* offset */ +#define SH7750_IPRA SH7750_P4_REG32(SH7750_IPRA_REGOFS) +#define SH7750_IPRA_A7 SH7750_A7_REG32(SH7750_IPRA_REGOFS) + +#define SH7750_IPRA_TMU0 0xF000 /* TMU0 interrupt priority */ +#define SH7750_IPRA_TMU0_S 12 +#define SH7750_IPRA_TMU1 0x0F00 /* TMU1 interrupt priority */ +#define SH7750_IPRA_TMU1_S 8 +#define SH7750_IPRA_TMU2 0x00F0 /* TMU2 interrupt priority */ +#define SH7750_IPRA_TMU2_S 4 +#define SH7750_IPRA_RTC 0x000F /* RTC interrupt priority */ +#define SH7750_IPRA_RTC_S 0 + +/* Interrupt Priority Register B - IPRB (half) */ +#define SH7750_IPRB_REGOFS 0xD00008 /* offset */ +#define SH7750_IPRB SH7750_P4_REG32(SH7750_IPRB_REGOFS) +#define SH7750_IPRB_A7 SH7750_A7_REG32(SH7750_IPRB_REGOFS) + +#define SH7750_IPRB_WDT 0xF000 /* WDT interrupt priority */ +#define SH7750_IPRB_WDT_S 12 +#define SH7750_IPRB_REF 0x0F00 /* Memory Refresh unit interrupt + priority */ +#define SH7750_IPRB_REF_S 8 +#define SH7750_IPRB_SCI1 0x00F0 /* SCI1 interrupt priority */ +#define SH7750_IPRB_SCI1_S 4 + +/* Interrupt Priority Register - IPR (half) */ +#define SH7750_IPRC_REGOFS 0xD00004 /* offset */ +#define SH7750_IPRC SH7750_P4_REG32(SH7750_IPRC_REGOFS) +#define SH7750_IPRC_A7 SH7750_A7_REG32(SH7750_IPRC_REGOFS) + +#define SH7750_IPRC_GPIO 0xF000 /* GPIO interrupt priority */ +#define SH7750_IPRC_GPIO_S 12 +#define SH7750_IPRC_DMAC 0x0F00 /* DMAC interrupt priority */ +#define SH7750_IPRC_DMAC_S 8 +#define SH7750_IPRC_SCIF 0x00F0 /* SCIF interrupt priority */ +#define SH7750_IPRC_SCIF_S 4 +#define SH7750_IPRC_HUDI 0x000F /* H-UDI interrupt priority */ +#define SH7750_IPRC_HUDI_S 0 + + +/* + * User Break Controller registers + */ +#define SH7750_BARA 0x200000 /* Break address regiser A */ +#define SH7750_BAMRA 0x200004 /* Break address mask regiser A */ +#define SH7750_BBRA 0x200008 /* Break bus cycle regiser A */ +#define SH7750_BARB 0x20000c /* Break address regiser B */ +#define SH7750_BAMRB 0x200010 /* Break address mask regiser B */ +#define SH7750_BBRB 0x200014 /* Break bus cycle regiser B */ +#define SH7750_BASRB 0x000018 /* Break ASID regiser B */ +#define SH7750_BDRB 0x200018 /* Break data regiser B */ +#define SH7750_BDMRB 0x20001c /* Break data mask regiser B */ +#define SH7750_BRCR 0x200020 /* Break control register */ + +#define SH7750_BRCR_UDBE 0x0001 /* User break debug enable bit */ + +/* + * Missing in RTEMS, added for QEMU + */ +#define SH7750_BCR3_A7 0x1f800050 +#define SH7750_BCR4_A7 0x1e0a00f0 +#define SH7750_PRECHARGE0_A7 0x1f900088 +#define SH7750_PRECHARGE1_A7 0x1f940088 + +#endif diff --git a/hw/shix.c b/hw/shix.c new file mode 100644 index 000000000..9577c092c --- /dev/null +++ b/hw/shix.c @@ -0,0 +1,111 @@ +/* + * SHIX 2.0 board description + * + * Copyright (c) 2005 Samuel Tardieu + * + * 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. + */ +/* + Shix 2.0 board by Alexis Polti, described at + http://perso.enst.fr/~polti/realisations/shix20/ + + More information in target-sh4/README.sh4 +*/ +#include "vl.h" + +#define BIOS_FILENAME "shix_bios.bin" +#define BIOS_ADDRESS 0xA0000000 + +void DMA_run(void) +{ + /* XXXXX */ +} + +void irq_info(void) +{ + /* XXXXX */ +} + +void pic_set_irq(int irq, int level) +{ + /* XXXXX */ +} + +void pic_info() +{ + /* XXXXX */ +} + +void vga_update_display() +{ + /* XXXXX */ +} + +void vga_invalidate_display() +{ + /* XXXXX */ +} + +void vga_screen_dump(const char *filename) +{ + /* XXXXX */ +} + +void shix_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState * ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + int ret; + CPUState *env; + struct SH7750State *s; + + printf("Initializing CPU\n"); + env = cpu_init(); + + /* Allocate memory space */ + printf("Allocating ROM\n"); + cpu_register_physical_memory(0x00000000, 0x00004000, IO_MEM_ROM); + printf("Allocating SDRAM 1\n"); + cpu_register_physical_memory(0x08000000, 0x01000000, 0x00004000); + printf("Allocating SDRAM 2\n"); + cpu_register_physical_memory(0x0c000000, 0x01000000, 0x01004000); + + /* Load BIOS in 0 (and access it through P2, 0xA0000000) */ + printf("%s: load BIOS '%s'\n", __func__, BIOS_FILENAME); + ret = load_image(BIOS_FILENAME, phys_ram_base); + if (ret < 0) { /* Check bios size */ + fprintf(stderr, "ret=%d\n", ret); + fprintf(stderr, "qemu: could not load SHIX bios '%s'\n", + BIOS_FILENAME); + exit(1); + } + + /* Register peripherals */ + s = sh7750_init(env); + /* XXXXX Check success */ + tc58128_init(s, "shix_linux_nand.bin", NULL); + fprintf(stderr, "initialization terminated\n"); +} + +QEMUMachine shix_machine = { + "shix", + "shix card", + shix_init +}; diff --git a/hw/tc58128.c b/hw/tc58128.c new file mode 100644 index 000000000..a8b26f7e8 --- /dev/null +++ b/hw/tc58128.c @@ -0,0 +1,181 @@ +#include +#include "vl.h" + +#define CE1 0x0100 +#define CE2 0x0200 +#define RE 0x0400 +#define WE 0x0800 +#define ALE 0x1000 +#define CLE 0x2000 +#define RDY1 0x4000 +#define RDY2 0x8000 +#define RDY(n) ((n) == 0 ? RDY1 : RDY2) + +typedef enum { WAIT, READ1, READ2, READ3 } state_t; + +typedef struct { + uint8_t *flash_contents; + state_t state; + uint32_t address; + uint8_t address_cycle; +} tc58128_dev; + +static tc58128_dev tc58128_devs[2]; + +#define FLASH_SIZE (16*1024*1024) + +void init_dev(tc58128_dev * dev, char *filename) +{ + int ret, blocks; + + dev->state = WAIT; + dev->flash_contents = qemu_mallocz(FLASH_SIZE); + memset(dev->flash_contents, 0xff, FLASH_SIZE); + if (!dev->flash_contents) { + fprintf(stderr, "could not alloc memory for flash\n"); + exit(1); + } + if (filename) { + /* Load flash image skipping the first block */ + ret = load_image(filename, dev->flash_contents + 528 * 32); + if (ret < 0) { + fprintf(stderr, "ret=%d\n", ret); + fprintf(stderr, "qemu: could not load flash image %s\n", + filename); + exit(1); + } else { + /* Build first block with number of blocks */ + blocks = (ret + 528 * 32 - 1) / (528 * 32); + dev->flash_contents[0] = blocks & 0xff; + dev->flash_contents[1] = (blocks >> 8) & 0xff; + dev->flash_contents[2] = (blocks >> 16) & 0xff; + dev->flash_contents[3] = (blocks >> 24) & 0xff; + fprintf(stderr, "loaded %d bytes for %s into flash\n", ret, + filename); + } + } +} + +void handle_command(tc58128_dev * dev, uint8_t command) +{ + switch (command) { + case 0xff: + fprintf(stderr, "reset flash device\n"); + dev->state = WAIT; + break; + case 0x00: + fprintf(stderr, "read mode 1\n"); + dev->state = READ1; + dev->address_cycle = 0; + break; + case 0x01: + fprintf(stderr, "read mode 2\n"); + dev->state = READ2; + dev->address_cycle = 0; + break; + case 0x50: + fprintf(stderr, "read mode 3\n"); + dev->state = READ3; + dev->address_cycle = 0; + break; + default: + fprintf(stderr, "unknown flash command 0x%02x\n", command); + assert(0); + } +} + +void handle_address(tc58128_dev * dev, uint8_t data) +{ + switch (dev->state) { + case READ1: + case READ2: + case READ3: + switch (dev->address_cycle) { + case 0: + dev->address = data; + if (dev->state == READ2) + dev->address |= 0x100; + else if (dev->state == READ3) + dev->address |= 0x200; + break; + case 1: + dev->address += data * 528 * 0x100; + break; + case 2: + dev->address += data * 528; + fprintf(stderr, "address pointer in flash: 0x%08x\n", + dev->address); + break; + default: + /* Invalid data */ + assert(0); + } + dev->address_cycle++; + break; + default: + assert(0); + } +} + +uint8_t handle_read(tc58128_dev * dev) +{ +#if 0 + if (dev->address % 0x100000 == 0) + fprintf(stderr, "reading flash at address 0x%08x\n", dev->address); +#endif + return dev->flash_contents[dev->address++]; +} + +/* We never mark the device as busy, so interrupts cannot be triggered + XXXXX */ + +int tc58128_cb(uint16_t porta, uint16_t portb, + uint16_t * periph_pdtra, uint16_t * periph_portadir, + uint16_t * periph_pdtrb, uint16_t * periph_portbdir) +{ + int dev; + + if ((porta & CE1) == 0) + dev = 0; + else if ((porta & CE2) == 0) + dev = 1; + else + return 0; /* No device selected */ + + if ((porta & RE) && (porta & WE)) { + /* Nothing to do, assert ready and return to input state */ + *periph_portadir &= 0xff00; + *periph_portadir |= RDY(dev); + *periph_pdtra |= RDY(dev); + return 1; + } + + if (porta & CLE) { + /* Command */ + assert((porta & WE) == 0); + handle_command(&tc58128_devs[dev], porta & 0x00ff); + } else if (porta & ALE) { + assert((porta & WE) == 0); + handle_address(&tc58128_devs[dev], porta & 0x00ff); + } else if ((porta & RE) == 0) { + *periph_portadir |= 0x00ff; + *periph_pdtra &= 0xff00; + *periph_pdtra |= handle_read(&tc58128_devs[dev]); + } else { + assert(0); + } + return 1; +} + +static sh7750_io_device tc58128 = { + RE | WE, /* Port A triggers */ + 0, /* Port B triggers */ + tc58128_cb /* Callback */ +}; + +int tc58128_init(struct SH7750State *s, char *zone1, char *zone2) +{ + init_dev(&tc58128_devs[0], zone1); + init_dev(&tc58128_devs[1], zone2); + return sh7750_register_io_device(s, &tc58128); +} diff --git a/target-sh4/README.sh4 b/target-sh4/README.sh4 new file mode 100644 index 000000000..b88717532 --- /dev/null +++ b/target-sh4/README.sh4 @@ -0,0 +1,150 @@ +qemu target: sh4 +author: Samuel Tardieu +last modified: Tue Dec 6 07:22:44 CET 2005 + +The sh4 target is not ready at all yet for integration in qemu. This +file describes the current state of implementation. + +Most places requiring attention and/or modification can be detected by +looking for "XXXXX" or "assert (0)". + +The sh4 core is located in target-sh4/*, while the 7750 peripheral +features (IO ports for example) are located in hw/sh7750.[ch]. The +main board description is in hw/shix.c, and the NAND flash in +hw/tc58128.[ch]. + +All the shortcomings indicated here will eventually be resolved. This +is a work in progress. Features are added in a semi-random order: if a +point is blocking to progress on booting the Linux kernel for the shix +board, it is addressed first; if feedback is necessary and no progress +can be made on blocking points until it is received, a random feature +is worked on. + +Goals +----- + +The primary model being worked on is the soft MMU target to be able to +emulate the Shix 2.0 board by Alexis Polti, described at +http://perso.enst.fr/~polti/realisations/shix20/ + +Ultimately, qemu will be coupled with a system C or a verilog +simulator to simulate the whole board functionalities. + +A sh4 user-mode has also somewhat started but will be worked on +afterwards. The goal is to automate tests for GNAT (GNU Ada) compiler +that I ported recently to the sh4-linux target. + +Registers +--------- + +16 general purpose registers are available at any time. The first 8 +registers are banked and the non-directly visible ones can be accessed +by privileged instructions. In qemu, we define 24 general purpose +registers and the code generation use either [0-7]+[8-15] or +[16-23]+[8-15] depending on the MD and RB flags in the sr +configuration register. + +Instructions +------------ + +Most sh4 instructions have been implemented. The missing ones at this +time are: + - FPU related instructions + - LDTLB to load a new MMU entry + - SLEEP to put the processor in sleep mode + +Most instructions could be optimized a lot. This will be worked on +after the current model is fully functional unless debugging +convenience requires that it is done early. + +Many instructions did not have a chance to be tested yet. The plan is +to implement unit and regression testing of those in the future. + +MMU +--- + +The MMU is implemented in the sh4 core. MMU management has not been +tested at all yet. In the sh7750, it can be manipulated through memory +mapped registers and this part has not yet been implemented. + +Exceptions +---------- + +Exceptions are implemented as described in the sh4 reference manual +but have not been tested yet. They do not use qemu EXCP_ features +yet. + +IRQ +--- + +IRQ are not implemented yet. + +Peripheral features +------------------- + + + Serial ports + +Configuration and use of the first serial port (SCI) without +interrupts is supported. Input has not yet been tested. + +Configuration of the second serial port (SCIF) is supported. FIFO +handling infrastructure has been started but is not completed yet. + + + GPIO ports + +GPIO ports have been implemented. A registration function allows +external modules to register interest in some port changes (see +hw/tc58128.[ch] for an example) and will be called back. Interrupt +generation is not yet supported but some infrastructure is in place +for this purpose. Note that in the current model a peripheral module +cannot directly simulate a H->L->H input port transition and have an +interrupt generated on the low level. + + + TC58128 NAND flash + +TC58128 NAND flash is partially implemented through GPIO ports. It +supports reading from flash. + +GDB +--- + +GDB remote target support has been implemented and lightly tested. + +Files +----- + +File names are harcoded at this time. The bootloader must be stored in +shix_bios.bin in the current directory. The initial Linux image must +be stored in shix_linux_nand.bin in the current directory in NAND +format. Test files can be obtained from +http://perso.enst.fr/~polti/robot/ as well as the various datasheets I +use. + +qemu disk parameter on the command line is unused. You can supply any +existing image and it will be ignored. As the goal is to simulate an +embedded target, it is not clear how this parameter will be handled in +the future. + +To build an ELF kernel image from the NAND image, 16 bytes have to be +stripped off the end of every 528 bytes, keeping only 512 of them. The +following Python code snippet does it: + +#! /usr/bin/python + +def denand (infd, outfd): + while True: + d = infd.read (528) + if not d: return + outfd.write (d[:512]) + +if __name__ == '__main__': + import sys + denand (open (sys.argv[1], 'rb'), + open (sys.argv[2], 'wb')) + +Style isssues +------------- + +There is currently a mix between my style (space before opening +parenthesis) and qemu style. This will be resolved before final +integration is proposed. diff --git a/vl.c b/vl.c index 8b6b33ce9..a7f77c9d1 100644 --- a/vl.c +++ b/vl.c @@ -4863,6 +4863,8 @@ void register_machines(void) qemu_register_machine(&integratorcp926_machine); qemu_register_machine(&integratorcp1026_machine); qemu_register_machine(&versatilepb_machine); +#elif defined(TARGET_SH4) + qemu_register_machine(&shix_machine); #else #error unsupported CPU #endif diff --git a/vl.h b/vl.h index fdf8c6867..8b935a962 100644 --- a/vl.h +++ b/vl.h @@ -842,6 +842,9 @@ extern QEMUMachine heathrow_machine; /* mips_r4k.c */ extern QEMUMachine mips_machine; +/* shix.c */ +extern QEMUMachine shix_machine; + #ifdef TARGET_PPC ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); #endif @@ -1016,6 +1019,28 @@ void *pl190_init(uint32_t base, void *parent, int irq, int fiq); void sp804_init(uint32_t base, void *pic, int irq); void icp_pit_init(uint32_t base, void *pic, int irq); +/* sh7750.c */ +struct SH7750State; + +struct SH7750State *sh7750_init(CPUSH4State * cpu); + +typedef struct { + /* The callback will be triggered if any of the designated lines change */ + uint16_t portamask_trigger; + uint16_t portbmask_trigger; + /* Return 0 if no action was taken */ + int (*port_change_cb) (uint16_t porta, uint16_t portb, + uint16_t * periph_pdtra, + uint16_t * periph_portdira, + uint16_t * periph_pdtrb, + uint16_t * periph_portdirb); +} sh7750_io_device; + +int sh7750_register_io_device(struct SH7750State *s, + sh7750_io_device * device); +/* tc58128.c */ +int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From 008a8818d91418254a94d7e5f6f66b1435a1edaf Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 27 Apr 2006 22:32:36 +0000 Subject: Fix build failure. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1863 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.h b/vl.h index 8b935a962..8b905b713 100644 --- a/vl.h +++ b/vl.h @@ -1022,7 +1022,7 @@ void icp_pit_init(uint32_t base, void *pic, int irq); /* sh7750.c */ struct SH7750State; -struct SH7750State *sh7750_init(CPUSH4State * cpu); +struct SH7750State *sh7750_init(CPUState * cpu); typedef struct { /* The callback will be triggered if any of the designated lines change */ -- cgit v1.2.3 From 1640695026373034f9740ad1bcb69f27e584218c Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 27 Apr 2006 23:15:07 +0000 Subject: Add nominal ARM Versatil/AB board emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1864 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/arm_boot.c | 105 +++++++++++++++++++++++++++++++++++++++++++++ hw/integratorcp.c | 87 +------------------------------------- hw/versatilepb.c | 124 ++++++++++++++++-------------------------------------- vl.c | 1 + vl.h | 7 +++ 6 files changed, 153 insertions(+), 173 deletions(-) create mode 100644 hw/arm_boot.c diff --git a/Makefile.target b/Makefile.target index 751edc858..f335b024f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -346,7 +346,7 @@ 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+= pl011.o pl050.o pl080.o pl110.o pl190.o +VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o diff --git a/hw/arm_boot.c b/hw/arm_boot.c new file mode 100644 index 000000000..0e28d4a07 --- /dev/null +++ b/hw/arm_boot.c @@ -0,0 +1,105 @@ +/* + * ARM kernel loader. + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +#define KERNEL_ARGS_ADDR 0x100 +#define KERNEL_LOAD_ADDR 0x00010000 +#define INITRD_LOAD_ADDR 0x00800000 + +/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ +static uint32_t bootloader[] = { + 0xe3a00000, /* mov r0, #0 */ + 0xe3a01000, /* mov r1, #0x?? */ + 0xe3811c00, /* orr r1, r1, #0x??00 */ + 0xe59f2000, /* ldr r2, [pc, #0] */ + 0xe59ff000, /* ldr pc, [pc, #0] */ + 0, /* Address of kernel args. Set by integratorcp_init. */ + 0 /* Kernel entry point. Set by integratorcp_init. */ +}; + +static void set_kernel_args(uint32_t ram_size, int initrd_size, + const char *kernel_cmdline) +{ + uint32_t *p; + + p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); + /* ATAG_CORE */ + stl_raw(p++, 5); + stl_raw(p++, 0x54410001); + stl_raw(p++, 1); + stl_raw(p++, 0x1000); + stl_raw(p++, 0); + /* ATAG_MEM */ + stl_raw(p++, 4); + stl_raw(p++, 0x54410002); + stl_raw(p++, ram_size); + stl_raw(p++, 0); + if (initrd_size) { + /* ATAG_INITRD2 */ + stl_raw(p++, 4); + stl_raw(p++, 0x54420005); + stl_raw(p++, INITRD_LOAD_ADDR); + stl_raw(p++, initrd_size); + } + if (kernel_cmdline && *kernel_cmdline) { + /* ATAG_CMDLINE */ + int cmdline_size; + + cmdline_size = strlen(kernel_cmdline); + memcpy (p + 2, kernel_cmdline, cmdline_size + 1); + cmdline_size = (cmdline_size >> 2) + 1; + stl_raw(p++, cmdline_size + 2); + stl_raw(p++, 0x54410009); + p += cmdline_size; + } + /* ATAG_END */ + stl_raw(p++, 0); + stl_raw(p++, 0); +} + +void arm_load_kernel(int ram_size, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + int board_id) +{ + int kernel_size; + int initrd_size; + int n; + + /* Load the kernel. */ + if (!kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + if (initrd_filename) { + initrd_size = load_image(initrd_filename, + phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_size = 0; + } + bootloader[1] |= board_id & 0xff; + bootloader[2] |= (board_id >> 8) & 0xff; + bootloader[5] = KERNEL_ARGS_ADDR; + bootloader[6] = KERNEL_LOAD_ADDR; + for (n = 0; n < sizeof(bootloader) / 4; n++) + stl_raw(phys_ram_base + (n * 4), bootloader[n]); + set_kernel_args(ram_size, initrd_size, kernel_cmdline); +} + diff --git a/hw/integratorcp.c b/hw/integratorcp.c index bce9b592c..f438af733 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -10,10 +10,6 @@ #include "vl.h" #include "arm_pic.h" -#define KERNEL_ARGS_ADDR 0x100 -#define KERNEL_LOAD_ADDR 0x00010000 -#define INITRD_LOAD_ADDR 0x00800000 - void DMA_run (void) { } @@ -470,57 +466,6 @@ static void icp_control_init(uint32_t base) } -/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ -static uint32_t bootloader[] = { - 0xe3a00000, /* mov r0, #0 */ - 0xe3a01013, /* mov r1, #0x13 */ - 0xe3811c01, /* orr r1, r1, #0x100 */ - 0xe59f2000, /* ldr r2, [pc, #0] */ - 0xe59ff000, /* ldr pc, [pc, #0] */ - 0, /* Address of kernel args. Set by integratorcp_init. */ - 0 /* Kernel entry point. Set by integratorcp_init. */ -}; - -static void set_kernel_args(uint32_t ram_size, int initrd_size, - const char *kernel_cmdline) -{ - uint32_t *p; - - p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); - /* ATAG_CORE */ - stl_raw(p++, 5); - stl_raw(p++, 0x54410001); - stl_raw(p++, 1); - stl_raw(p++, 0x1000); - stl_raw(p++, 0); - /* ATAG_MEM */ - stl_raw(p++, 4); - stl_raw(p++, 0x54410002); - stl_raw(p++, ram_size); - stl_raw(p++, 0); - if (initrd_size) { - /* ATAG_INITRD2 */ - stl_raw(p++, 4); - stl_raw(p++, 0x54420005); - stl_raw(p++, INITRD_LOAD_ADDR); - stl_raw(p++, initrd_size); - } - if (kernel_cmdline && *kernel_cmdline) { - /* ATAG_CMDLINE */ - int cmdline_size; - - cmdline_size = strlen(kernel_cmdline); - memcpy (p + 2, kernel_cmdline, cmdline_size + 1); - cmdline_size = (cmdline_size >> 2) + 1; - stl_raw(p++, cmdline_size + 2); - stl_raw(p++, 0x54410009); - p += cmdline_size; - } - /* ATAG_END */ - stl_raw(p++, 0); - stl_raw(p++, 0); -} - /* Board init. */ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, @@ -532,9 +477,6 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, uint32_t bios_offset; icp_pic_state *pic; void *cpu_pic; - int kernel_size; - int initrd_size; - int n; env = cpu_init(); cpu_arm_set_model(env, cpuid); @@ -567,33 +509,8 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, } pl110_init(ds, 0xc0000000, pic, 22, 0); - /* Load the kernel. */ - if (!kernel_filename) { - fprintf(stderr, "Kernel image must be specified\n"); - exit(1); - } - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } - if (initrd_filename) { - initrd_size = load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", - initrd_filename); - exit(1); - } - } else { - initrd_size = 0; - } - bootloader[5] = KERNEL_ARGS_ADDR; - bootloader[6] = KERNEL_LOAD_ADDR; - for (n = 0; n < sizeof(bootloader) / 4; n++) - stl_raw(phys_ram_base + (n * 4), bootloader[n]); - set_kernel_args(ram_size, initrd_size, kernel_cmdline); + arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, + initrd_filename, 0x113); } static void integratorcp926_init(int ram_size, int vga_ram_size, diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 6d2e2dcfe..e198a518e 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -1,5 +1,5 @@ /* - * ARM Versatile Platform Baseboard System emulation. + * ARM Versatile Platform/Application Baseboard System emulation. * * Copyright (c) 2005-2006 CodeSourcery. * Written by Paul Brook @@ -10,10 +10,6 @@ #include "vl.h" #include "arm_pic.h" -#define KERNEL_ARGS_ADDR 0x100 -#define KERNEL_LOAD_ADDR 0x00010000 -#define INITRD_LOAD_ADDR 0x00800000 - /* Primary interrupt controller. */ typedef struct vpb_sic_state @@ -151,66 +147,16 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) /* Board init. */ -/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ -static uint32_t bootloader[] = { - 0xe3a00000, /* mov r0, #0 */ - 0xe3a01083, /* mov r1, #0x83 */ - 0xe3811c01, /* orr r1, r1, #0x100 */ - 0xe59f2000, /* ldr r2, [pc, #0] */ - 0xe59ff000, /* ldr pc, [pc, #0] */ - 0, /* Address of kernel args. Set by integratorcp_init. */ - 0 /* Kernel entry point. Set by integratorcp_init. */ -}; - -static void set_kernel_args(uint32_t ram_size, int initrd_size, - const char *kernel_cmdline) -{ - uint32_t *p; - - p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); - /* ATAG_CORE */ - stl_raw(p++, 5); - stl_raw(p++, 0x54410001); - stl_raw(p++, 1); - stl_raw(p++, 0x1000); - stl_raw(p++, 0); - /* ATAG_MEM */ - stl_raw(p++, 4); - stl_raw(p++, 0x54410002); - stl_raw(p++, ram_size); - stl_raw(p++, 0); - if (initrd_size) { - /* ATAG_INITRD2 */ - stl_raw(p++, 4); - stl_raw(p++, 0x54420005); - stl_raw(p++, INITRD_LOAD_ADDR); - stl_raw(p++, initrd_size); - } - if (kernel_cmdline && *kernel_cmdline) { - /* ATAG_CMDLINE */ - int cmdline_size; +/* The AB and PB boards both use the same core, just with different + peripherans and expansion busses. For now we emulate a subset of the + PB peripherals and just change the board ID. */ - cmdline_size = strlen(kernel_cmdline); - memcpy (p + 2, kernel_cmdline, cmdline_size + 1); - cmdline_size = (cmdline_size >> 2) + 1; - stl_raw(p++, cmdline_size + 2); - stl_raw(p++, 0x54410009); - p += cmdline_size; - } - /* ATAG_END */ - stl_raw(p++, 0); - stl_raw(p++, 0); -} - -static void vpb_init(int ram_size, int vga_ram_size, int boot_device, +static void versatile_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, int board_id) { CPUState *env; - int kernel_size; - int initrd_size; - int n; void *pic; void *sic; @@ -250,6 +196,7 @@ static void vpb_init(int ram_size, int vga_ram_size, int boot_device, that includes hardware cursor support from the PL111. */ pl110_init(ds, 0x10120000, pic, 16, 1); + /* Memory map for Versatile/PB: */ /* 0x10000000 System registers. */ /* 0x10001000 PCI controller config registers. */ /* 0x10002000 Serial bus interface. */ @@ -285,33 +232,30 @@ static void vpb_init(int ram_size, int vga_ram_size, int boot_device, /* 0x101f3000 UART2. */ /* 0x101f4000 SSPI. */ - /* Load the kernel. */ - if (!kernel_filename) { - fprintf(stderr, "Kernel image must be specified\n"); - exit(1); - } - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } - if (initrd_filename) { - initrd_size = load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", - initrd_filename); - exit(1); - } - } else { - initrd_size = 0; - } - bootloader[5] = KERNEL_ARGS_ADDR; - bootloader[6] = KERNEL_LOAD_ADDR; - for (n = 0; n < sizeof(bootloader) / 4; n++) - stl_raw(phys_ram_base + (n * 4), bootloader[n]); - set_kernel_args(ram_size, initrd_size, kernel_cmdline); + arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, + initrd_filename, board_id); +} + +static void vpb_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + versatile_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 0x183); +} + +static void vab_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + versatile_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, + initrd_filename, 0x25e); } QEMUMachine versatilepb_machine = { @@ -319,3 +263,9 @@ QEMUMachine versatilepb_machine = { "ARM Versatile/PB (ARM926EJ-S)", vpb_init, }; + +QEMUMachine versatileab_machine = { + "versatileab", + "ARM Versatile/AB (ARM926EJ-S)", + vab_init, +}; diff --git a/vl.c b/vl.c index a7f77c9d1..ef5bee56c 100644 --- a/vl.c +++ b/vl.c @@ -4863,6 +4863,7 @@ void register_machines(void) qemu_register_machine(&integratorcp926_machine); qemu_register_machine(&integratorcp1026_machine); qemu_register_machine(&versatilepb_machine); + qemu_register_machine(&versatileab_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); #else diff --git a/vl.h b/vl.h index 8b905b713..4ae3d611c 100644 --- a/vl.h +++ b/vl.h @@ -987,6 +987,7 @@ extern QEMUMachine integratorcp1026_machine; /* versatilepb.c */ extern QEMUMachine versatilepb_machine; +extern QEMUMachine versatileab_machine; /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); @@ -1019,6 +1020,12 @@ void *pl190_init(uint32_t base, void *parent, int irq, int fiq); void sp804_init(uint32_t base, void *pic, int irq); void icp_pit_init(uint32_t base, void *pic, int irq); +/* arm_boot.c */ + +void arm_load_kernel(int ram_size, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + int board_id); + /* sh7750.c */ struct SH7750State; -- cgit v1.2.3 From 7918bf476b8b32a65b6d254f393e00325f2b7f4b Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 28 Apr 2006 15:26:51 +0000 Subject: Fix typo in BSD FP rounding mode names. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1865 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index a246eaf16..b0264d52e 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -38,9 +38,9 @@ typedef union { #if defined(_BSD) && !defined(__APPLE__) enum { float_round_nearest_even = FP_RN, - float_round_down = FE_RM, - float_round_up = FE_RP, - float_round_to_zero = FE_RZ + float_round_down = FP_RM, + float_round_up = FP_RP, + float_round_to_zero = FP_RZ }; #elif defined(__arm__) enum { -- cgit v1.2.3 From a1e7547389feeea0c777f558f47a0185f3fe2543 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 28 Apr 2006 22:47:21 +0000 Subject: APM CPU idle fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1866 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 8c3141ef6..537851abb 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index a54235df4..647025b88 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,10 +1,25 @@ +Index: apmbios.S +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/apmbios.S,v +retrieving revision 1.4 +diff -u -w -r1.4 apmbios.S +--- apmbios.S 26 Dec 2005 10:35:51 -0000 1.4 ++++ apmbios.S 28 Apr 2006 22:41:19 -0000 +@@ -225,6 +225,7 @@ + APMSYM(05): + cmp al, #0x05 + jne APMSYM(07) ++ sti + hlt + jmp APMSYM(ok) + Index: rombios.c =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.160 diff -u -w -r1.160 rombios.c --- rombios.c 25 Jan 2006 17:51:49 -0000 1.160 -+++ rombios.c 2 Apr 2006 18:29:51 -0000 ++++ rombios.c 28 Apr 2006 22:41:21 -0000 @@ -1816,6 +1816,7 @@ { printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ", -- cgit v1.2.3 From 4dbe19e18139a9e6f736630707e6e459696cbb5f Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 29 Apr 2006 15:52:14 +0000 Subject: ELCR is not reset by PIC reset (bug report by malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1867 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i8259.c b/hw/i8259.c index 00d5068ea..6c2ddfff8 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -271,7 +271,7 @@ static void pic_reset(void *opaque) s->rotate_on_auto_eoi = 0; s->special_fully_nested_mode = 0; s->init4 = 0; - s->elcr = 0; + /* Note: ELCR is not reset */ } static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) -- cgit v1.2.3 From a46e4035e22c81cd3942b936cebe6f6037e17ec2 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 29 Apr 2006 23:05:22 +0000 Subject: Fix non-portable use of expr. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1868 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 92632e24d..695fdb680 100755 --- a/configure +++ b/configure @@ -167,7 +167,7 @@ else fi for opt do - optarg=`expr "$opt" : '[^=]*=\(.*\)'` + optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'` case "$opt" in --help|-h) show_help=yes ;; -- cgit v1.2.3 From 24236869fbff210b356b6626e6e9e9eadc8a976c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Apr 2006 21:28:36 +0000 Subject: VNC server (Anthony Liguori) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1869 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 4 + hw/cirrus_vga.c | 83 +++++- keymaps.c | 2 + qemu-doc.texi | 7 + vl.c | 13 + vl.h | 13 + vnc.c | 894 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vnc_keysym.h | 275 +++++++++++++++++ vnchextile.h | 189 ++++++++++++ 10 files changed, 1477 insertions(+), 4 deletions(-) create mode 100644 vnc.c create mode 100644 vnc_keysym.h create mode 100644 vnchextile.h diff --git a/Changelog b/Changelog index d6f34fea5..27c6009fb 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,7 @@ version 0.8.1: - SSE3 support - Solaris port (Ben Taylor) - Preliminary SH4 target (Samuel Tardieu) + - VNC server (Anthony Liguori) version 0.8.0: diff --git a/Makefile.target b/Makefile.target index f335b024f..77eaa1e76 100644 --- a/Makefile.target +++ b/Makefile.target @@ -357,6 +357,7 @@ 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 @@ -409,6 +410,9 @@ cocoa.o: cocoa.m sdl.o: sdl.c keymaps.c sdl_keysym.h $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< +vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h + $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + sdlaudio.o: sdlaudio.c $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 934cde990..d186d797a 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -644,15 +644,90 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) (s->cirrus_blt_srcaddr & ~7)); } -static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) +static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) { + int sx, sy; + int dx, dy; + int width, height; + int depth; + int notify = 0; + + depth = s->get_bpp((VGAState *)s) / 8; + s->get_resolution((VGAState *)s, &width, &height); + + /* extra x, y */ + sx = (src % (width * depth)) / depth; + sy = (src / (width * depth)); + dx = (dst % (width *depth)) / depth; + dy = (dst / (width * depth)); + + /* normalize width */ + w /= depth; + + /* if we're doing a backward copy, we have to adjust + our x/y to be the upper left corner (instead of the lower + right corner) */ + if (s->cirrus_blt_dstpitch < 0) { + sx -= (s->cirrus_blt_width / depth) - 1; + dx -= (s->cirrus_blt_width / depth) - 1; + sy -= s->cirrus_blt_height - 1; + dy -= s->cirrus_blt_height - 1; + } + + /* are we in the visible portion of memory? */ + if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 && + (sx + w) <= width && (sy + h) <= height && + (dx + w) <= width && (dy + h) <= height) { + notify = 1; + } + + /* make to sure only copy if it's a plain copy ROP */ + if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src && + *s->cirrus_rop != cirrus_bitblt_rop_bkwd_src) + notify = 0; + + /* we have to flush all pending changes so that the copy + is generated at the appropriate moment in time */ + if (notify) + vga_hw_update(); + (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, s->vram_ptr + s->cirrus_blt_srcaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_width, s->cirrus_blt_height); - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); + + if (notify) + s->ds->dpy_copy(s->ds, + sx, sy, dx, dy, + s->cirrus_blt_width / depth, + s->cirrus_blt_height); + + /* we don't have to notify the display that this portion has + changed since dpy_copy implies this */ + + if (!notify) + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); +} + +static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) +{ + if (s->ds->dpy_copy) { + cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr, + s->cirrus_blt_srcaddr - s->start_addr, + s->cirrus_blt_width, s->cirrus_blt_height); + } else { + (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, + s->vram_ptr + s->cirrus_blt_srcaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, + s->cirrus_blt_width, s->cirrus_blt_height); + + cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, + s->cirrus_blt_dstpitch, s->cirrus_blt_width, + s->cirrus_blt_height); + } + return 1; } diff --git a/keymaps.c b/keymaps.c index c3de8d764..bd893288a 100644 --- a/keymaps.c +++ b/keymaps.c @@ -99,8 +99,10 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, "Warning: Could not assign keysym %s (0x%x) because of memory constraints.\n", line, keysym); } else { +#if 0 fprintf(stderr, "Setting %d: %d,%d\n", k->extra_count, keysym, keycode); +#endif k->keysym2keycode_extra[k->extra_count]. keysym = keysym; k->keysym2keycode_extra[k->extra_count]. diff --git a/qemu-doc.texi b/qemu-doc.texi index 89ae6befc..7068d2a88 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -185,6 +185,13 @@ command line application. The emulated serial port is redirected on the console. Therefore, you can still use QEMU to debug a Linux kernel with a serial console. +@item -vnc d + +Normally, QEMU uses SDL to display the VGA output. With this option, +you can have QEMU listen on VNC display d and redirect the VGA display +over the VNC session. It is very useful to enable the usb tablet device +when using this option (option @option{-usbdevice tablet}). + @item -k language Use keyboard layout @var{language} (for example @code{fr} for diff --git a/vl.c b/vl.c index ef5bee56c..64fcfb458 100644 --- a/vl.c +++ b/vl.c @@ -149,6 +149,7 @@ USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; USBDevice *vm_usb_hub; static VLANState *first_vlan; int smp_cpus = 1; +int vnc_display = -1; #if defined(TARGET_SPARC) #define MAX_CPUS 16 #elif defined(TARGET_I386) @@ -4638,6 +4639,7 @@ void help(void) " (default is CL-GD5446 PCI VGA)\n" #endif "-loadvm file start right away with a saved state (loadvm in monitor)\n" + "-vnc display start a VNC server on display\n" "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -4721,6 +4723,7 @@ enum { QEMU_OPTION_usb, QEMU_OPTION_usbdevice, QEMU_OPTION_smp, + QEMU_OPTION_vnc, }; typedef struct QEMUOption { @@ -4788,6 +4791,7 @@ const QEMUOption qemu_options[] = { { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, + { "vnc", HAS_ARG, QEMU_OPTION_vnc }, /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, @@ -5386,6 +5390,13 @@ int main(int argc, char **argv) exit(1); } break; + case QEMU_OPTION_vnc: + vnc_display = atoi(optarg); + if (vnc_display < 0) { + fprintf(stderr, "Invalid VNC display\n"); + exit(1); + } + break; } } } @@ -5551,6 +5562,8 @@ int main(int argc, char **argv) /* terminal init */ if (nographic) { dumb_display_init(ds); + } if (vnc_display != -1) { + vnc_display_init(ds, vnc_display); } else { #if defined(CONFIG_SDL) sdl_display_init(ds, full_screen); diff --git a/vl.h b/vl.h index 4ae3d611c..ddf8892c5 100644 --- a/vl.h +++ b/vl.h @@ -82,6 +82,13 @@ static inline char *realpath(const char *path, char *resolved_path) #define tostring(s) #s #endif +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + /* vl.c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); @@ -672,9 +679,12 @@ struct DisplayState { int depth; int width; int height; + void *opaque; + void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); void (*dpy_resize)(struct DisplayState *s, int w, int h); void (*dpy_refresh)(struct DisplayState *s); + void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h); }; static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) @@ -703,6 +713,9 @@ void sdl_display_init(DisplayState *ds, int full_screen); /* cocoa.m */ void cocoa_display_init(DisplayState *ds, int full_screen); +/* vnc.c */ +void vnc_display_init(DisplayState *ds, int display); + /* ide.c */ #define MAX_DISKS 4 diff --git a/vnc.c b/vnc.c new file mode 100644 index 000000000..f461de6a9 --- /dev/null +++ b/vnc.c @@ -0,0 +1,894 @@ +#include "vl.h" + +#include +#include +#include +#include + +#define VNC_REFRESH_INTERVAL (1000 / 30) + +#include "vnc_keysym.h" +#include "keymaps.c" + +typedef struct Buffer +{ + size_t capacity; + size_t offset; + char *buffer; +} Buffer; + +typedef struct VncState VncState; + +typedef int VncReadEvent(VncState *vs, char *data, size_t len); + +struct VncState +{ + QEMUTimer *timer; + int lsock; + int csock; + DisplayState *ds; + int need_update; + int width; + int height; + uint64_t dirty_row[768]; + char *old_data; + int depth; + int has_resize; + int has_hextile; + Buffer output; + Buffer input; + kbd_layout_t *kbd_layout; + + VncReadEvent *read_handler; + size_t read_handler_expect; +}; + +/* TODO + 1) Get the queue working for IO. + 2) there is some weirdness when using the -S option (the screen is grey + and not totally invalidated + 3) resolutions > 1024 +*/ + +static void vnc_write(VncState *vs, const void *data, size_t len); +static void vnc_write_u32(VncState *vs, uint32_t value); +static void vnc_write_s32(VncState *vs, int32_t value); +static void vnc_write_u16(VncState *vs, uint16_t value); +static void vnc_write_u8(VncState *vs, uint8_t value); +static void vnc_flush(VncState *vs); +static void vnc_update_client(void *opaque); +static void vnc_client_read(void *opaque); + +static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) +{ + VncState *vs = ds->opaque; + int i; + + h += y; + + for (; y < h; y++) + for (i = 0; i < w; i += 16) + vs->dirty_row[y] |= (1ULL << ((x + i) / 16)); +} + +static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, + int32_t encoding) +{ + vnc_write_u16(vs, x); + vnc_write_u16(vs, y); + vnc_write_u16(vs, w); + vnc_write_u16(vs, h); + + vnc_write_s32(vs, encoding); +} + +static void vnc_dpy_resize(DisplayState *ds, int w, int h) +{ + VncState *vs = ds->opaque; + + ds->data = realloc(ds->data, w * h * vs->depth); + vs->old_data = realloc(vs->old_data, w * h * vs->depth); + + if (ds->data == NULL || vs->old_data == NULL) { + fprintf(stderr, "vnc: memory allocation failed\n"); + exit(1); + } + + ds->depth = vs->depth * 8; + ds->width = w; + ds->height = h; + ds->linesize = w * vs->depth; + if (vs->csock != -1 && vs->has_resize) { + vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); /* number of rects */ + vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223); + vnc_flush(vs); + vs->width = ds->width; + vs->height = ds->height; + } +} + +static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h) +{ + int i; + char *row; + + vnc_framebuffer_update(vs, x, y, w, h, 0); + + row = vs->ds->data + y * vs->ds->linesize + x * vs->depth; + for (i = 0; i < h; i++) { + vnc_write(vs, row, w * vs->depth); + row += vs->ds->linesize; + } +} + +static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h) +{ + ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F); + ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F); +} + +#define BPP 8 +#include "vnchextile.h" +#undef BPP + +#define BPP 16 +#include "vnchextile.h" +#undef BPP + +#define BPP 32 +#include "vnchextile.h" +#undef BPP + +static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h) +{ + int i, j; + int has_fg, has_bg; + uint32_t last_fg32, last_bg32; + uint16_t last_fg16, last_bg16; + uint8_t last_fg8, last_bg8; + + vnc_framebuffer_update(vs, x, y, w, h, 5); + + has_fg = has_bg = 0; + for (j = y; j < (y + h); j += 16) { + for (i = x; i < (x + w); i += 16) { + switch (vs->depth) { + case 1: + send_hextile_tile_8(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), + &last_bg8, &last_fg8, &has_bg, &has_fg); + break; + case 2: + send_hextile_tile_16(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), + &last_bg16, &last_fg16, &has_bg, &has_fg); + break; + case 4: + send_hextile_tile_32(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), + &last_bg32, &last_fg32, &has_bg, &has_fg); + break; + default: + break; + } + } + } +} + +static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) +{ + if (vs->has_hextile) + send_framebuffer_update_hextile(vs, x, y, w, h); + else + send_framebuffer_update_raw(vs, x, y, w, h); +} + +static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) +{ + int src, dst; + char *src_row; + char *dst_row; + char *old_row; + int y = 0; + int pitch = ds->linesize; + VncState *vs = ds->opaque; + + vnc_update_client(vs); + + if (dst_y > src_y) { + y = h - 1; + pitch = -pitch; + } + + src = (ds->linesize * (src_y + y) + vs->depth * src_x); + dst = (ds->linesize * (dst_y + y) + vs->depth * dst_x); + + src_row = ds->data + src; + dst_row = ds->data + dst; + old_row = vs->old_data + dst; + + for (y = 0; y < h; y++) { + memmove(old_row, src_row, w * vs->depth); + memmove(dst_row, src_row, w * vs->depth); + src_row += pitch; + dst_row += pitch; + old_row += pitch; + } + + vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); /* number of rects */ + vnc_framebuffer_update(vs, dst_x, dst_y, w, h, 1); + vnc_write_u16(vs, src_x); + vnc_write_u16(vs, src_y); + vnc_flush(vs); +} + +static int find_dirty_height(VncState *vs, int y, int last_x, int x) +{ + int h; + + for (h = 1; h < (vs->height - y); h++) { + int tmp_x; + if (!(vs->dirty_row[y + h] & (1ULL << last_x))) + break; + for (tmp_x = last_x; tmp_x < x; tmp_x++) + vs->dirty_row[y + h] &= ~(1ULL << tmp_x); + } + + return h; +} + +static void vnc_update_client(void *opaque) +{ + VncState *vs = opaque; + + if (vs->need_update && vs->csock != -1) { + int y; + char *row; + char *old_row; + uint64_t width_mask; + int n_rectangles; + int saved_offset; + int has_dirty = 0; + + width_mask = (1ULL << (vs->width / 16)) - 1; + + if (vs->width == 1024) + width_mask = ~(0ULL); + + /* Walk through the dirty map and eliminate tiles that + really aren't dirty */ + row = vs->ds->data; + old_row = vs->old_data; + + for (y = 0; y < vs->height; y++) { + if (vs->dirty_row[y] & width_mask) { + int x; + char *ptr, *old_ptr; + + ptr = row; + old_ptr = old_row; + + for (x = 0; x < vs->ds->width; x += 16) { + if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) { + vs->dirty_row[y] &= ~(1ULL << (x / 16)); + } else { + has_dirty = 1; + memcpy(old_ptr, ptr, 16 * vs->depth); + } + + ptr += 16 * vs->depth; + old_ptr += 16 * vs->depth; + } + } + + row += vs->ds->linesize; + old_row += vs->ds->linesize; + } + + if (!has_dirty) { + qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); + return; + } + + /* Count rectangles */ + n_rectangles = 0; + vnc_write_u8(vs, 0); /* msg id */ + vnc_write_u8(vs, 0); + saved_offset = vs->output.offset; + vnc_write_u16(vs, 0); + + for (y = 0; y < vs->height; y++) { + int x; + int last_x = -1; + for (x = 0; x < vs->width / 16; x++) { + if (vs->dirty_row[y] & (1ULL << x)) { + if (last_x == -1) { + last_x = x; + } + vs->dirty_row[y] &= ~(1ULL << x); + } else { + if (last_x != -1) { + int h = find_dirty_height(vs, y, last_x, x); + send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h); + n_rectangles++; + } + last_x = -1; + } + } + if (last_x != -1) { + int h = find_dirty_height(vs, y, last_x, x); + send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h); + n_rectangles++; + } + } + vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; + vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; + vnc_flush(vs); + + } + qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); +} + +static void vnc_timer_init(VncState *vs) +{ + if (vs->timer == NULL) { + vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); + qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock)); + } +} + +static void vnc_dpy_refresh(DisplayState *ds) +{ + VncState *vs = ds->opaque; + vnc_timer_init(vs); + vga_hw_update(); +} + +static int vnc_listen_poll(void *opaque) +{ + VncState *vs = opaque; + if (vs->csock == -1) + return 1; + return 0; +} + +static void buffer_reserve(Buffer *buffer, size_t len) +{ + if ((buffer->capacity - buffer->offset) < len) { + buffer->capacity += (len + 1024); + buffer->buffer = realloc(buffer->buffer, buffer->capacity); + if (buffer->buffer == NULL) { + fprintf(stderr, "vnc: out of memory\n"); + exit(1); + } + } +} + +static int buffer_empty(Buffer *buffer) +{ + return buffer->offset == 0; +} + +static char *buffer_end(Buffer *buffer) +{ + return buffer->buffer + buffer->offset; +} + +static void buffer_reset(Buffer *buffer) +{ + buffer->offset = 0; +} + +static void buffer_append(Buffer *buffer, const void *data, size_t len) +{ + memcpy(buffer->buffer + buffer->offset, data, len); + buffer->offset += len; +} + +static int vnc_client_io_error(VncState *vs, int ret) +{ + if (ret == 0 || ret == -1) { + if (ret == -1 && (errno == EINTR || errno == EAGAIN)) + return 0; + + qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); + close(vs->csock); + vs->csock = -1; + buffer_reset(&vs->input); + buffer_reset(&vs->output); + vs->need_update = 0; + return 0; + } + return ret; +} + +static void vnc_client_error(VncState *vs) +{ + errno = EINVAL; + vnc_client_io_error(vs, -1); +} + +static void vnc_client_write(void *opaque) +{ + ssize_t ret; + VncState *vs = opaque; + + ret = write(vs->csock, vs->output.buffer, vs->output.offset); + ret = vnc_client_io_error(vs, ret); + if (!ret) + return; + + memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret)); + vs->output.offset -= ret; + + if (vs->output.offset == 0) { + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + } +} + +static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) +{ + vs->read_handler = func; + vs->read_handler_expect = expecting; +} + +static void vnc_client_read(void *opaque) +{ + VncState *vs = opaque; + ssize_t ret; + + buffer_reserve(&vs->input, 4096); + + ret = read(vs->csock, buffer_end(&vs->input), 4096); + ret = vnc_client_io_error(vs, ret); + if (!ret) + return; + + vs->input.offset += ret; + + while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) { + size_t len = vs->read_handler_expect; + int ret; + + ret = vs->read_handler(vs, vs->input.buffer, len); + if (vs->csock == -1) + return; + + if (!ret) { + memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len)); + vs->input.offset -= len; + } else { + vs->read_handler_expect = ret; + } + } +} + +static void vnc_write(VncState *vs, const void *data, size_t len) +{ + buffer_reserve(&vs->output, len); + + if (buffer_empty(&vs->output)) { + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); + } + + buffer_append(&vs->output, data, len); +} + +static void vnc_write_s32(VncState *vs, int32_t value) +{ + vnc_write_u32(vs, *(uint32_t *)&value); +} + +static void vnc_write_u32(VncState *vs, uint32_t value) +{ + uint8_t buf[4]; + + buf[0] = (value >> 24) & 0xFF; + buf[1] = (value >> 16) & 0xFF; + buf[2] = (value >> 8) & 0xFF; + buf[3] = value & 0xFF; + + vnc_write(vs, buf, 4); +} + +static void vnc_write_u16(VncState *vs, uint16_t value) +{ + char buf[2]; + + buf[0] = (value >> 8) & 0xFF; + buf[1] = value & 0xFF; + + vnc_write(vs, buf, 2); +} + +static void vnc_write_u8(VncState *vs, uint8_t value) +{ + vnc_write(vs, (char *)&value, 1); +} + +static void vnc_flush(VncState *vs) +{ + if (vs->output.offset) + vnc_client_write(vs); +} + +static uint8_t read_u8(char *data, size_t offset) +{ + return data[offset]; +} + +static uint16_t read_u16(char *data, size_t offset) +{ + return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); +} + +static int32_t read_s32(char *data, size_t offset) +{ + return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) | + (data[offset + 2] << 8) | data[offset + 3]); +} + +static uint32_t read_u32(char *data, size_t offset) +{ + return ((data[offset] << 24) | (data[offset + 1] << 16) | + (data[offset + 2] << 8) | data[offset + 3]); +} + +static void client_cut_text(VncState *vs, size_t len, char *text) +{ +} + +static void pointer_event(VncState *vs, int button_mask, int x, int y) +{ + int buttons = 0; + int dz = 0; + + if (button_mask & 0x01) + buttons |= MOUSE_EVENT_LBUTTON; + if (button_mask & 0x02) + buttons |= MOUSE_EVENT_MBUTTON; + if (button_mask & 0x04) + buttons |= MOUSE_EVENT_RBUTTON; + if (button_mask & 0x08) + dz = -1; + if (button_mask & 0x10) + dz = 1; + + if (kbd_mouse_is_absolute()) { + kbd_mouse_event(x * 0x7FFF / vs->ds->width, + y * 0x7FFF / vs->ds->height, + dz, buttons); + } else { + static int last_x = -1; + static int last_y = -1; + + if (last_x != -1) + kbd_mouse_event(x - last_x, y - last_y, dz, buttons); + + last_x = x; + last_y = y; + } +} + +static void key_event(VncState *vs, int down, uint32_t sym) +{ + int keycode; + + keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); + + if (keycode & 0x80) + kbd_put_keycode(0xe0); + if (down) + kbd_put_keycode(keycode & 0x7f); + else + kbd_put_keycode(keycode | 0x80); +} + +static void framebuffer_update_request(VncState *vs, int incremental, + int x_position, int y_position, + int w, int h) +{ + int i; + vs->need_update = 1; + if (!incremental) { + char *old_row = vs->old_data + y_position * vs->ds->linesize; + + for (i = 0; i < h; i++) { + vs->dirty_row[y_position + i] = (1ULL << (vs->ds->width / 16)) - 1; + if (vs->ds->width == 1024) { + vs->dirty_row[y_position + i] = ~(0ULL); + } + memset(old_row, 42, vs->ds->width * vs->depth); + old_row += vs->ds->linesize; + } + } +} + +static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) +{ + int i; + + vs->has_hextile = 0; + vs->has_resize = 0; + vs->ds->dpy_copy = NULL; + + for (i = n_encodings - 1; i >= 0; i--) { + switch (encodings[i]) { + case 0: /* Raw */ + vs->has_hextile = 0; + break; + case 1: /* CopyRect */ + vs->ds->dpy_copy = vnc_copy; + break; + case 5: /* Hextile */ + vs->has_hextile = 1; + break; + case -223: /* DesktopResize */ + vs->has_resize = 1; + break; + default: + break; + } + } +} + +static void set_pixel_format(VncState *vs, + int bits_per_pixel, int depth, + int big_endian_flag, int true_color_flag, + int red_max, int green_max, int blue_max, + int red_shift, int green_shift, int blue_shift) +{ + switch (bits_per_pixel) { + case 32: + case 24: + vs->depth = 4; + break; + case 16: + vs->depth = 2; + break; + case 8: + vs->depth = 1; + break; + default: + vnc_client_error(vs); + break; + } + + if (!true_color_flag) + vnc_client_error(vs); + + vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); + memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); + memset(vs->old_data, 42, vs->ds->linesize * vs->ds->height); + + vga_hw_invalidate(); + vga_hw_update(); +} + +static int protocol_client_msg(VncState *vs, char *data, size_t len) +{ + int i; + uint16_t limit; + + switch (data[0]) { + case 0: + if (len == 1) + return 20; + + set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5), + read_u8(data, 6), read_u8(data, 7), + read_u16(data, 8), read_u16(data, 10), + read_u16(data, 12), read_u8(data, 14), + read_u8(data, 15), read_u8(data, 16)); + break; + case 2: + if (len == 1) + return 4; + + if (len == 4) + return 4 + (read_u16(data, 2) * 4); + + limit = read_u16(data, 2); + for (i = 0; i < limit; i++) { + int32_t val = read_s32(data, 4 + (i * 4)); + memcpy(data + 4 + (i * 4), &val, sizeof(val)); + } + + set_encodings(vs, (int32_t *)(data + 4), limit); + break; + case 3: + if (len == 1) + return 10; + + framebuffer_update_request(vs, + read_u8(data, 1), read_u16(data, 2), read_u16(data, 4), + read_u16(data, 6), read_u16(data, 8)); + break; + case 4: + if (len == 1) + return 8; + + key_event(vs, read_u8(data, 1), read_u32(data, 4)); + break; + case 5: + if (len == 1) + return 6; + + pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); + break; + case 6: + if (len == 1) + return 8; + + if (len == 8) + return 8 + read_u32(data, 4); + + client_cut_text(vs, read_u32(data, 4), data + 8); + break; + default: + printf("Msg: %d\n", data[0]); + vnc_client_error(vs); + break; + } + + vnc_read_when(vs, protocol_client_msg, 1); + return 0; +} + +static int protocol_client_init(VncState *vs, char *data, size_t len) +{ + char pad[3] = { 0, 0, 0 }; + + vs->width = vs->ds->width; + vs->height = vs->ds->height; + vnc_write_u16(vs, vs->ds->width); + vnc_write_u16(vs, vs->ds->height); + + vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ + vnc_write_u8(vs, vs->depth * 8); /* depth */ + vnc_write_u8(vs, 0); /* big-endian-flag */ + vnc_write_u8(vs, 1); /* true-color-flag */ + if (vs->depth == 4) { + vnc_write_u16(vs, 0xFF); /* red-max */ + vnc_write_u16(vs, 0xFF); /* green-max */ + vnc_write_u16(vs, 0xFF); /* blue-max */ + vnc_write_u8(vs, 16); /* red-shift */ + vnc_write_u8(vs, 8); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + } else if (vs->depth == 2) { + vnc_write_u16(vs, 31); /* red-max */ + vnc_write_u16(vs, 63); /* green-max */ + vnc_write_u16(vs, 31); /* blue-max */ + vnc_write_u8(vs, 11); /* red-shift */ + vnc_write_u8(vs, 5); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + } else if (vs->depth == 1) { + vnc_write_u16(vs, 3); /* red-max */ + vnc_write_u16(vs, 7); /* green-max */ + vnc_write_u16(vs, 3); /* blue-max */ + vnc_write_u8(vs, 5); /* red-shift */ + vnc_write_u8(vs, 2); /* green-shift */ + vnc_write_u8(vs, 0); /* blue-shift */ + } + + vnc_write(vs, pad, 3); /* padding */ + + vnc_write_u32(vs, 4); + vnc_write(vs, "QEMU", 4); + vnc_flush(vs); + + vnc_read_when(vs, protocol_client_msg, 1); + + return 0; +} + +static int protocol_version(VncState *vs, char *version, size_t len) +{ + char local[13]; + int maj, min; + + memcpy(local, version, 12); + local[12] = 0; + + if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) { + vnc_client_error(vs); + return 0; + } + + vnc_write_u32(vs, 1); /* None */ + vnc_flush(vs); + + vnc_read_when(vs, protocol_client_init, 1); + + return 0; +} + +static void vnc_listen_read(void *opaque) +{ + VncState *vs = opaque; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + + vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); + if (vs->csock != -1) { + fcntl(vs->csock, F_SETFL, O_NONBLOCK); + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); + vnc_write(vs, "RFB 003.003\n", 12); + vnc_flush(vs); + vnc_read_when(vs, protocol_version, 12); + memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height); + memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); + vs->has_resize = 0; + vs->has_hextile = 0; + vs->ds->dpy_copy = NULL; + } +} + +void vnc_display_init(DisplayState *ds, int display) +{ + struct sockaddr_in addr; + int reuse_addr, ret; + VncState *vs; + + vs = qemu_mallocz(sizeof(VncState)); + if (!vs) + exit(1); + + ds->opaque = vs; + + vs->lsock = -1; + vs->csock = -1; + vs->depth = 4; + + vs->ds = ds; + + if (!keyboard_layout) + keyboard_layout = "en-us"; + + vs->kbd_layout = init_keyboard_layout(keyboard_layout); + if (!vs->kbd_layout) + exit(1); + + vs->lsock = socket(PF_INET, SOCK_STREAM, 0); + if (vs->lsock == -1) { + fprintf(stderr, "Could not create socket\n"); + exit(1); + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(5900 + display); + memset(&addr.sin_addr, 0, sizeof(addr.sin_addr)); + + reuse_addr = 1; + ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, + &reuse_addr, sizeof(reuse_addr)); + if (ret == -1) { + fprintf(stderr, "setsockopt() failed\n"); + exit(1); + } + + if (bind(vs->lsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + fprintf(stderr, "bind() failed\n"); + exit(1); + } + + if (listen(vs->lsock, 1) == -1) { + fprintf(stderr, "listen() failed\n"); + exit(1); + } + + ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); + if (ret == -1) { + exit(1); + } + + vs->ds->data = NULL; + vs->ds->dpy_update = vnc_dpy_update; + vs->ds->dpy_resize = vnc_dpy_resize; + vs->ds->dpy_refresh = vnc_dpy_refresh; + + memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); + + vnc_dpy_resize(vs->ds, 640, 400); +} diff --git a/vnc_keysym.h b/vnc_keysym.h new file mode 100644 index 000000000..a4ac6885b --- /dev/null +++ b/vnc_keysym.h @@ -0,0 +1,275 @@ +typedef struct { + const char* name; + int keysym; +} name2keysym_t; +static name2keysym_t name2keysym[]={ +/* ascii */ + { "space", 0x020}, + { "exclam", 0x021}, + { "quotedbl", 0x022}, + { "numbersign", 0x023}, + { "dollar", 0x024}, + { "percent", 0x025}, + { "ampersand", 0x026}, + { "apostrophe", 0x027}, + { "parenleft", 0x028}, + { "parenright", 0x029}, + { "asterisk", 0x02a}, + { "plus", 0x02b}, + { "comma", 0x02c}, + { "minus", 0x02d}, + { "period", 0x02e}, + { "slash", 0x02f}, + { "0", 0x030}, + { "1", 0x031}, + { "2", 0x032}, + { "3", 0x033}, + { "4", 0x034}, + { "5", 0x035}, + { "6", 0x036}, + { "7", 0x037}, + { "8", 0x038}, + { "9", 0x039}, + { "colon", 0x03a}, + { "semicolon", 0x03b}, + { "less", 0x03c}, + { "equal", 0x03d}, + { "greater", 0x03e}, + { "question", 0x03f}, + { "at", 0x040}, + { "A", 0x041}, + { "B", 0x042}, + { "C", 0x043}, + { "D", 0x044}, + { "E", 0x045}, + { "F", 0x046}, + { "G", 0x047}, + { "H", 0x048}, + { "I", 0x049}, + { "J", 0x04a}, + { "K", 0x04b}, + { "L", 0x04c}, + { "M", 0x04d}, + { "N", 0x04e}, + { "O", 0x04f}, + { "P", 0x050}, + { "Q", 0x051}, + { "R", 0x052}, + { "S", 0x053}, + { "T", 0x054}, + { "U", 0x055}, + { "V", 0x056}, + { "W", 0x057}, + { "X", 0x058}, + { "Y", 0x059}, + { "Z", 0x05a}, + { "bracketleft", 0x05b}, + { "backslash", 0x05c}, + { "bracketright", 0x05d}, + { "asciicircum", 0x05e}, + { "underscore", 0x05f}, + { "grave", 0x060}, + { "a", 0x061}, + { "b", 0x062}, + { "c", 0x063}, + { "d", 0x064}, + { "e", 0x065}, + { "f", 0x066}, + { "g", 0x067}, + { "h", 0x068}, + { "i", 0x069}, + { "j", 0x06a}, + { "k", 0x06b}, + { "l", 0x06c}, + { "m", 0x06d}, + { "n", 0x06e}, + { "o", 0x06f}, + { "p", 0x070}, + { "q", 0x071}, + { "r", 0x072}, + { "s", 0x073}, + { "t", 0x074}, + { "u", 0x075}, + { "v", 0x076}, + { "w", 0x077}, + { "x", 0x078}, + { "y", 0x079}, + { "z", 0x07a}, + { "braceleft", 0x07b}, + { "bar", 0x07c}, + { "braceright", 0x07d}, + { "asciitilde", 0x07e}, + +/* latin 1 extensions */ +{ "nobreakspace", 0x0a0}, +{ "exclamdown", 0x0a1}, +{ "cent", 0x0a2}, +{ "sterling", 0x0a3}, +{ "currency", 0x0a4}, +{ "yen", 0x0a5}, +{ "brokenbar", 0x0a6}, +{ "section", 0x0a7}, +{ "diaeresis", 0x0a8}, +{ "copyright", 0x0a9}, +{ "ordfeminine", 0x0aa}, +{ "guillemotleft", 0x0ab}, +{ "notsign", 0x0ac}, +{ "hyphen", 0x0ad}, +{ "registered", 0x0ae}, +{ "macron", 0x0af}, +{ "degree", 0x0b0}, +{ "plusminus", 0x0b1}, +{ "twosuperior", 0x0b2}, +{ "threesuperior", 0x0b3}, +{ "acute", 0x0b4}, +{ "mu", 0x0b5}, +{ "paragraph", 0x0b6}, +{ "periodcentered", 0x0b7}, +{ "cedilla", 0x0b8}, +{ "onesuperior", 0x0b9}, +{ "masculine", 0x0ba}, +{ "guillemotright", 0x0bb}, +{ "onequarter", 0x0bc}, +{ "onehalf", 0x0bd}, +{ "threequarters", 0x0be}, +{ "questiondown", 0x0bf}, +{ "Agrave", 0x0c0}, +{ "Aacute", 0x0c1}, +{ "Acircumflex", 0x0c2}, +{ "Atilde", 0x0c3}, +{ "Adiaeresis", 0x0c4}, +{ "Aring", 0x0c5}, +{ "AE", 0x0c6}, +{ "Ccedilla", 0x0c7}, +{ "Egrave", 0x0c8}, +{ "Eacute", 0x0c9}, +{ "Ecircumflex", 0x0ca}, +{ "Ediaeresis", 0x0cb}, +{ "Igrave", 0x0cc}, +{ "Iacute", 0x0cd}, +{ "Icircumflex", 0x0ce}, +{ "Idiaeresis", 0x0cf}, +{ "ETH", 0x0d0}, +{ "Eth", 0x0d0}, +{ "Ntilde", 0x0d1}, +{ "Ograve", 0x0d2}, +{ "Oacute", 0x0d3}, +{ "Ocircumflex", 0x0d4}, +{ "Otilde", 0x0d5}, +{ "Odiaeresis", 0x0d6}, +{ "multiply", 0x0d7}, +{ "Ooblique", 0x0d8}, +{ "Oslash", 0x0d8}, +{ "Ugrave", 0x0d9}, +{ "Uacute", 0x0da}, +{ "Ucircumflex", 0x0db}, +{ "Udiaeresis", 0x0dc}, +{ "Yacute", 0x0dd}, +{ "THORN", 0x0de}, +{ "Thorn", 0x0de}, +{ "ssharp", 0x0df}, +{ "agrave", 0x0e0}, +{ "aacute", 0x0e1}, +{ "acircumflex", 0x0e2}, +{ "atilde", 0x0e3}, +{ "adiaeresis", 0x0e4}, +{ "aring", 0x0e5}, +{ "ae", 0x0e6}, +{ "ccedilla", 0x0e7}, +{ "egrave", 0x0e8}, +{ "eacute", 0x0e9}, +{ "ecircumflex", 0x0ea}, +{ "ediaeresis", 0x0eb}, +{ "igrave", 0x0ec}, +{ "iacute", 0x0ed}, +{ "icircumflex", 0x0ee}, +{ "idiaeresis", 0x0ef}, +{ "eth", 0x0f0}, +{ "ntilde", 0x0f1}, +{ "ograve", 0x0f2}, +{ "oacute", 0x0f3}, +{ "ocircumflex", 0x0f4}, +{ "otilde", 0x0f5}, +{ "odiaeresis", 0x0f6}, +{ "division", 0x0f7}, +{ "oslash", 0x0f8}, +{ "ooblique", 0x0f8}, +{ "ugrave", 0x0f9}, +{ "uacute", 0x0fa}, +{ "ucircumflex", 0x0fb}, +{ "udiaeresis", 0x0fc}, +{ "yacute", 0x0fd}, +{ "thorn", 0x0fe}, +{ "ydiaeresis", 0x0ff}, +{"EuroSign", 0x20ac}, /* XK_EuroSign */ + + /* modifiers */ +{"Control_L", 0xffe3}, /* XK_Control_L */ +{"Control_R", 0xffe4}, /* XK_Control_R */ +{"Alt_L", 0xffe9}, /* XK_Alt_L */ +{"Alt_R", 0xffea}, /* XK_Alt_R */ +{"Caps_Lock", 0xffe5}, /* XK_Caps_Lock */ +{"Meta_L", 0xffe7}, /* XK_Meta_L */ +{"Meta_R", 0xffe8}, /* XK_Meta_R */ +{"Shift_L", 0xffe1}, /* XK_Shift_L */ +{"Shift_R", 0xffe2}, /* XK_Shift_R */ +{"Super_L", 0xffeb}, /* XK_Super_L */ +{"Super_R", 0xffec}, /* XK_Super_R */ + + /* special keys */ +{"BackSpace", 0xff08}, /* XK_BackSpace */ +{"Tab", 0xff09}, /* XK_Tab */ +{"Return", 0xff0d}, /* XK_Return */ +{"Right", 0xff53}, /* XK_Right */ +{"Left", 0xff51}, /* XK_Left */ +{"Up", 0xff52}, /* XK_Up */ +{"Down", 0xff54}, /* XK_Down */ +{"Page_Down", 0xff56}, /* XK_Page_Down */ +{"Page_Up", 0xff55}, /* XK_Page_Up */ +{"Insert", 0xff63}, /* XK_Insert */ +{"Delete", 0xffff}, /* XK_Delete */ +{"Home", 0xff50}, /* XK_Home */ +{"End", 0xff57}, /* XK_End */ +{"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */ +{"F1", 0xffbe}, /* XK_F1 */ +{"F2", 0xffbf}, /* XK_F2 */ +{"F3", 0xffc0}, /* XK_F3 */ +{"F4", 0xffc1}, /* XK_F4 */ +{"F5", 0xffc2}, /* XK_F5 */ +{"F6", 0xffc3}, /* XK_F6 */ +{"F7", 0xffc4}, /* XK_F7 */ +{"F8", 0xffc5}, /* XK_F8 */ +{"F9", 0xffc6}, /* XK_F9 */ +{"F10", 0xffc7}, /* XK_F10 */ +{"F11", 0xffc8}, /* XK_F11 */ +{"F12", 0xffc9}, /* XK_F12 */ +{"F13", 0xffca}, /* XK_F13 */ +{"F14", 0xffcb}, /* XK_F14 */ +{"F15", 0xffcc}, /* XK_F15 */ +{"Sys_Req", 0xff15}, /* XK_Sys_Req */ +{"KP_0", 0xffb0}, /* XK_KP_0 */ +{"KP_1", 0xffb1}, /* XK_KP_1 */ +{"KP_2", 0xffb2}, /* XK_KP_2 */ +{"KP_3", 0xffb3}, /* XK_KP_3 */ +{"KP_4", 0xffb4}, /* XK_KP_4 */ +{"KP_5", 0xffb5}, /* XK_KP_5 */ +{"KP_6", 0xffb6}, /* XK_KP_6 */ +{"KP_7", 0xffb7}, /* XK_KP_7 */ +{"KP_8", 0xffb8}, /* XK_KP_8 */ +{"KP_9", 0xffb9}, /* XK_KP_9 */ +{"KP_Add", 0xffab}, /* XK_KP_Add */ +{"KP_Decimal", 0xffae}, /* XK_KP_Decimal */ +{"KP_Divide", 0xffaf}, /* XK_KP_Divide */ +{"KP_Enter", 0xff8d}, /* XK_KP_Enter */ +{"KP_Equal", 0xffbd}, /* XK_KP_Equal */ +{"KP_Multiply", 0xffaa}, /* XK_KP_Multiply */ +{"KP_Subtract", 0xffad}, /* XK_KP_Subtract */ +{"help", 0xff6a}, /* XK_Help */ +{"Menu", 0xff67}, /* XK_Menu */ +{"Print", 0xff61}, /* XK_Print */ +{"Mode_switch", 0xff7e}, /* XK_Mode_switch */ +{"Num_Lock", 0xff7f}, /* XK_Num_Lock */ +{"Pause", 0xff13}, /* XK_Pause */ +{"Escape", 0xff1b}, /* XK_Escape */ +{0,0}, +}; diff --git a/vnchextile.h b/vnchextile.h new file mode 100644 index 000000000..7277670a5 --- /dev/null +++ b/vnchextile.h @@ -0,0 +1,189 @@ +#define CONCAT_I(a, b) a ## b +#define CONCAT(a, b) CONCAT_I(a, b) +#define pixel_t CONCAT(uint, CONCAT(BPP, _t)) + +static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, + int x, int y, int w, int h, + pixel_t *last_bg, pixel_t *last_fg, + int *has_bg, int *has_fg) +{ + char *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth); + pixel_t *irow = (pixel_t *)row; + int j, i; + pixel_t bg = 0; + pixel_t fg = 0; + int n_colors = 0; + int bg_count = 0; + int fg_count = 0; + int flags = 0; + uint8_t data[(sizeof(pixel_t) + 2) * 16 * 16]; + int n_data = 0; + int n_subtiles = 0; + + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + switch (n_colors) { + case 0: + bg = irow[i]; + n_colors = 1; + break; + case 1: + if (irow[i] != bg) { + fg = irow[i]; + n_colors = 2; + } + break; + case 2: + if (irow[i] != bg && irow[i] != fg) { + n_colors = 3; + } else { + if (irow[i] == bg) + bg_count++; + else if (irow[i] == fg) + fg_count++; + } + break; + default: + break; + } + } + if (n_colors > 2) + break; + irow += vs->ds->linesize / sizeof(pixel_t); + } + + if (n_colors > 1 && fg_count > bg_count) { + pixel_t tmp = fg; + fg = bg; + bg = tmp; + } + + if (!*has_bg || *last_bg != bg) { + flags |= 0x02; + *has_bg = 1; + *last_bg = bg; + } + + if (!*has_fg || *last_fg != fg) { + flags |= 0x04; + *has_fg = 1; + *last_fg = fg; + } + + switch (n_colors) { + case 1: + n_data = 0; + break; + case 2: + flags |= 0x08; + + irow = (pixel_t *)row; + + for (j = 0; j < h; j++) { + int min_x = -1; + for (i = 0; i < w; i++) { + if (irow[i] == fg) { + if (min_x == -1) + min_x = i; + } else if (min_x != -1) { + hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); + n_data += 2; + n_subtiles++; + min_x = -1; + } + } + if (min_x != -1) { + hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); + n_data += 2; + n_subtiles++; + } + irow += vs->ds->linesize / sizeof(pixel_t); + } + break; + case 3: + flags |= 0x18; + + irow = (pixel_t *)row; + + if (!*has_bg || *last_bg != bg) + flags |= 0x02; + + for (j = 0; j < h; j++) { + int has_color = 0; + int min_x = -1; + pixel_t color; + + for (i = 0; i < w; i++) { + if (!has_color) { + if (irow[i] == bg) + continue; + color = irow[i]; + min_x = i; + has_color = 1; + } else if (irow[i] != color) { + has_color = 0; + + memcpy(data + n_data, &color, sizeof(color)); + hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1); + n_data += 2 + sizeof(pixel_t); + n_subtiles++; + + min_x = -1; + if (irow[i] != bg) { + color = irow[i]; + min_x = i; + has_color = 1; + } + } + } + if (has_color) { + memcpy(data + n_data, &color, sizeof(color)); + hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1); + n_data += 2 + sizeof(pixel_t); + n_subtiles++; + } + irow += vs->ds->linesize / sizeof(pixel_t); + } + + /* A SubrectsColoured subtile invalidates the foreground color */ + *has_fg = 0; + if (n_data > (w * h * sizeof(pixel_t))) { + n_colors = 4; + flags = 0x01; + *has_bg = 0; + + /* we really don't have to invalidate either the bg or fg + but we've lost the old values. oh well. */ + } + default: + break; + } + + if (n_colors > 3) { + flags = 0x01; + *has_fg = 0; + *has_bg = 0; + n_colors = 4; + } + + vnc_write_u8(vs, flags); + if (n_colors < 4) { + if (flags & 0x02) + vnc_write(vs, last_bg, sizeof(pixel_t)); + if (flags & 0x04) + vnc_write(vs, last_fg, sizeof(pixel_t)); + if (n_subtiles) { + vnc_write_u8(vs, n_subtiles); + vnc_write(vs, data, n_data); + } + } else { + for (j = 0; j < h; j++) { + vnc_write(vs, row, w * vs->depth); + row += vs->ds->linesize; + } + } +} + +#undef pixel_t +#undef CONCAT_I +#undef CONCAT -- cgit v1.2.3 From 7f881e5674f9a3839e454436ed6c1c5ca3a6b757 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Apr 2006 21:33:34 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1870 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cvsignore b/.cvsignore index 2627cd0bd..101139fc8 100644 --- a/.cvsignore +++ b/.cvsignore @@ -25,3 +25,5 @@ mips-softmmu mipsel-softmmu mips-user mipsel-user +sh4-user +sh4-softmmu -- cgit v1.2.3 From 3f423c9c8fe197af5fa3b5945bc7d3f3ceec3512 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Apr 2006 21:34:15 +0000 Subject: removed warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1871 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/libslirp.h | 2 +- slirp/slirp.c | 2 +- vl.c | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 36c8ec21f..a9260afeb 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -32,7 +32,7 @@ int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, int guest_port); extern const char *tftp_prefix; -extern const char slirp_hostname[33]; +extern char slirp_hostname[33]; #ifdef __cplusplus } diff --git a/slirp/slirp.c b/slirp/slirp.c index b4ab12a08..1331d0ead 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -25,7 +25,7 @@ struct ex_list *exec_list; /* XXX: suppress those select globals */ fd_set *global_readfds, *global_writefds, *global_xfds; -const char slirp_hostname[33]; +char slirp_hostname[33]; #ifdef _WIN32 diff --git a/vl.c b/vl.c index 64fcfb458..bfc14902f 100644 --- a/vl.c +++ b/vl.c @@ -3132,9 +3132,7 @@ int net_client_init(const char *str) #ifdef CONFIG_SLIRP if (!strcmp(device, "user")) { if (get_param_value(buf, sizeof(buf), "hostname", p)) { - if (strlen(buf) > 32) - buf[32] = 0; - strcpy(slirp_hostname, buf); + pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); } ret = net_slirp_init(vlan); } else -- cgit v1.2.3 From 985d1742dbf75e2d5b2814d0dfa25b1d578874b2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Apr 2006 21:53:59 +0000 Subject: fixes for more than 8 ports - return NAK if no change - FreeBSD workaround (Lonnie Mendez) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1872 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hub.c | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 6f6e429a0..fd916128c 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -158,9 +158,9 @@ static const uint8_t qemu_hub_hub_descriptor[] = 0x0a, /* u16 wHubCharacteristics; */ 0x00, /* (per-port OC, no power switching) */ 0x01, /* u8 bPwrOn2pwrGood; 2ms */ - 0x00, /* u8 bHubContrCurrent; 0 mA */ - 0x00, /* u8 DeviceRemovable; *** 7 Ports max *** */ - 0xff /* u8 PortPwrCtrlMask; *** 7 ports max *** */ + 0x00 /* u8 bHubContrCurrent; 0 mA */ + + /* DeviceRemovable and PortPwrCtrlMask patched in later */ }; static void usb_hub_attach(USBPort *port1, USBDevice *dev) @@ -219,6 +219,12 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, } ret = 0; break; + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == 0 && index != 0x81) { /* clear ep halt */ + goto fail; + } + ret = 0; + break; case DeviceOutRequest | USB_REQ_SET_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 1; @@ -241,6 +247,11 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, case USB_DT_CONFIG: memcpy(data, qemu_hub_config_descriptor, sizeof(qemu_hub_config_descriptor)); + + /* status change endpoint size based on number + * of ports */ + data[22] = (s->nb_ports + 1 + 7) / 8; + ret = sizeof(qemu_hub_config_descriptor); break; case USB_DT_STRING: @@ -385,11 +396,29 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, } break; case GetHubDescriptor: - memcpy(data, qemu_hub_hub_descriptor, - sizeof(qemu_hub_hub_descriptor)); - data[2] = s->nb_ports; - ret = sizeof(qemu_hub_hub_descriptor); - break; + { + unsigned int n, limit, var_hub_size = 0; + memcpy(data, qemu_hub_hub_descriptor, + sizeof(qemu_hub_hub_descriptor)); + data[2] = s->nb_ports; + + /* fill DeviceRemovable bits */ + limit = ((s->nb_ports + 1 + 7) / 8) + 7; + for (n = 7; n < limit; n++) { + data[n] = 0x00; + var_hub_size++; + } + + /* fill PortPwrCtrlMask bits */ + limit = limit + ((s->nb_ports + 7) / 8); + for (;n < limit; n++) { + data[n] = 0xff; + var_hub_size++; + } + + ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; + break; + } default: fail: ret = USB_RET_STALL; @@ -411,8 +440,11 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, unsigned int status; int i, n; n = (s->nb_ports + 1 + 7) / 8; - if (n > len) + if (len == 1) { /* FreeBSD workaround */ + n = 1; + } else if (n > len) { return USB_RET_BABBLE; + } status = 0; for(i = 0; i < s->nb_ports; i++) { port = &s->ports[i]; @@ -425,7 +457,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, } ret = n; } else { - ret = 0; + ret = USB_RET_NAK; /* usb11 11.13.1 */ } } else { goto fail; -- cgit v1.2.3 From debc70650a973b0c67bd8ea69f8887cd41961ba8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Apr 2006 21:58:41 +0000 Subject: Enhanced Documentation (Stefan Weil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1873 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 190 ++++++++++++++++++++++++++++++++++++++++++++++----------- qemu-tech.texi | 86 ++++++++++++++++++++++++-- 2 files changed, 236 insertions(+), 40 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 7068d2a88..9e4735016 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1,16 +1,46 @@ \input texinfo @c -*- texinfo -*- +@c %**start of header +@setfilename qemu-doc.info +@settitle QEMU CPU Emulator User Documentation +@exampleindent 0 +@paragraphindent 0 +@c %**end of header @iftex -@settitle QEMU CPU Emulator User Documentation @titlepage @sp 7 -@center @titlefont{QEMU CPU Emulator User Documentation} +@center @titlefont{QEMU CPU Emulator} +@sp 1 +@center @titlefont{User Documentation} @sp 3 @end titlepage @end iftex +@ifnottex +@node Top +@top + +@menu +* Introduction:: +* Installation:: +* QEMU PC System emulator:: +* QEMU System emulator for non PC targets:: +* QEMU Linux User space emulator:: +* compilation:: Compilation from the sources +* Index:: +@end menu +@end ifnottex + +@contents + +@node Introduction @chapter Introduction +@menu +* intro_features:: Features +@end menu + +@node intro_features @section Features QEMU is a FAST! processor emulator using dynamic translation to @@ -52,27 +82,53 @@ For system emulation, the following hardware targets are supported: For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported. +@node Installation @chapter Installation If you want to compile QEMU yourself, see @ref{compilation}. +@menu +* install_linux:: Linux +* install_windows:: Windows +* install_mac:: Macintosh +@end menu + +@node install_linux @section Linux If a precompiled package is available for your distribution - you just have to install it. Otherwise, see @ref{compilation}. +@node install_windows @section Windows Download the experimental binary installer at -@url{http://www.free.oszoo.org/download.html}. +@url{http://www.free.oszoo.org/@/download.html}. +@node install_mac @section Mac OS X Download the experimental binary installer at -@url{http://www.free.oszoo.org/download.html}. +@url{http://www.free.oszoo.org/@/download.html}. +@node QEMU PC System emulator @chapter QEMU PC System emulator +@menu +* pcsys_introduction:: Introduction +* pcsys_quickstart:: Quick Start +* sec_invocation:: Invocation +* pcsys_keys:: Keys +* pcsys_monitor:: QEMU Monitor +* disk_images:: Disk Images +* pcsys_network:: Network emulation +* direct_linux_boot:: Direct Linux Boot +* pcsys_usb:: USB emulation +* gdb_usage:: GDB usage +* pcsys_os_specific:: Target OS specific information +@end menu + +@node pcsys_introduction @section Introduction @c man begin DESCRIPTION @@ -118,6 +174,7 @@ QEMU uses YM3812 emulation by Tatsuyuki Satoh. @c man end +@node pcsys_quickstart @section Quick Start Download and uncompress the linux image (@file{linux.img}) and type: @@ -147,14 +204,14 @@ Select the emulated machine (@code{-M ?} for list) @item -fda file @item -fdb file -Use @var{file} as floppy disk 0/1 image (@xref{disk_images}). You can +Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can use the host floppy by using @file{/dev/fd0} as filename. @item -hda file @item -hdb file @item -hdc file @item -hdd file -Use @var{file} as hard disk 0, 1, 2 or 3 image (@xref{disk_images}). +Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}). @item -cdrom file Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and @@ -168,7 +225,7 @@ the default. @item -snapshot Write to temporary files instead of disk image files. In this case, the raw disk image you use is not written back. You can however force -the write back by pressing @key{C-a s} (@xref{disk_images}). +the write back by pressing @key{C-a s} (@pxref{disk_images}). @item -m megs Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. @@ -304,9 +361,12 @@ specifies an already opened TCP socket. Example: @example # launch a first QEMU instance -qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,listen=:1234 -# connect the VLAN 0 of this instance to the VLAN 0 of the first instance -qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,connect=127.0.0.1:1234 +qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \ + -net socket,listen=:1234 +# connect the VLAN 0 of this instance to the VLAN 0 +# of the first instance +qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \ + -net socket,connect=127.0.0.1:1234 @end example @item -net socket[,vlan=n][,fd=h][,mcast=maddr:port] @@ -328,17 +388,22 @@ mcast support is compatible with User Mode Linux (argument @option{eth@var{N}=mc Example: @example # launch one QEMU instance -qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234 +qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \ + -net socket,mcast=230.0.0.1:1234 # launch another QEMU instance on same "bus" -qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234 +qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \ + -net socket,mcast=230.0.0.1:1234 # launch yet another QEMU instance on same "bus" -qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234 +qemu linux.img -net nic,macaddr=52:54:00:12:34:58 \ + -net socket,mcast=230.0.0.1:1234 @end example Example (User Mode Linux compat.): @example -# launch QEMU instance (note mcast address selected is UML's default) -qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102 +# launch QEMU instance (note mcast address selected +# is UML's default) +qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \ + -net socket,mcast=239.192.168.1:1102 # launch UML /path/to/linux ubd0=/path/to/root_fs eth0=mcast @end example @@ -471,7 +536,7 @@ The default device is @code{vc} in graphical mode and @code{stdio} in non graphical mode. @item -s -Wait gdb connection to port 1234 (@xref{gdb_usage}). +Wait gdb connection to port 1234 (@pxref{gdb_usage}). @item -p port Change gdb connection port. @item -S @@ -494,6 +559,7 @@ Start right away with a saved state (@code{loadvm} in monitor) @c man end +@node pcsys_keys @section Keys @c man begin OPTIONS @@ -542,9 +608,6 @@ Send Ctrl-a @ignore -@setfilename qemu -@settitle QEMU System Emulator - @c man begin SEEALSO The HTML documentation of QEMU for more precise information and Linux user mode emulator invocation. @@ -556,8 +619,7 @@ Fabrice Bellard @end ignore -@end ignore - +@node pcsys_monitor @section QEMU Monitor The QEMU monitor is used to give complex commands to the QEMU @@ -683,7 +745,7 @@ Dump 10 instructions at the current instruction pointer: @item Dump 80 16 bit values at the start of the video memory. -@example +@smallexample (qemu) xp/80hx 0xb8000 0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42 0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41 @@ -695,7 +757,7 @@ Dump 80 16 bit values at the start of the video memory. 0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 -@end example +@end smallexample @end itemize @item p or print/fmt expr @@ -746,6 +808,14 @@ Since version 0.6.1, QEMU supports many disk image formats, including growable disk images (their size increase as non empty sectors are written), compressed and encrypted disk images. +@menu +* disk_images_quickstart:: Quick start for disk image creation +* disk_images_snapshot_mode:: Snapshot mode +* qemu_img_invocation:: qemu-img Invocation +* disk_images_fat_images:: Virtual FAT disk images +@end menu + +@node disk_images_quickstart @subsection Quick start for disk image creation You can create a disk image with the command: @@ -756,8 +826,9 @@ where @var{myimage.img} is the disk image filename and @var{mysize} is its size in kilobytes. You can add an @code{M} suffix to give the size in megabytes and a @code{G} suffix for gigabytes. -@xref{qemu_img_invocation} for more information. +See @ref{qemu_img_invocation} for more information. +@node disk_images_snapshot_mode @subsection Snapshot mode If you use the option @option{-snapshot}, all disk images are @@ -771,6 +842,7 @@ command (or @key{C-a s} in the serial console). @include qemu-img.texi +@node disk_images_fat_images @subsection Virtual FAT disk images QEMU can automatically create a virtual FAT disk image from a @@ -805,6 +877,7 @@ What you should @emph{never} do: @item write to the FAT directory on the host system while accessing it with the guest system. @end itemize +@node pcsys_network @section Network emulation QEMU can simulate several networks cards (NE2000 boards on the PC @@ -908,10 +981,10 @@ seen from the emulated kernel at IP address 172.20.0.1. @item Launch @code{qemu.sh}. You should have the following output: -@example +@smallexample > ./qemu.sh Connected to host network interface: tun0 -Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 +Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 @/(Red Hat @/Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 BIOS-provided physical RAM map: BIOS-e801: 0000000000000000 - 000000000009f000 (usable) BIOS-e801: 0000000000100000 - 0000000002000000 (usable) @@ -920,7 +993,7 @@ On node 0 totalpages: 8192 zone(0): 4096 pages. zone(1): 4096 pages. zone(2): 0 pages. -Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe console=ttyS0 +Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe @/ide5=noprobe console=ttyS0 ide_setup: ide2=noprobe ide_setup: ide3=noprobe ide_setup: ide4=noprobe @@ -929,7 +1002,7 @@ Initializing CPU#0 Detected 2399.621 MHz processor. Console: colour EGA 80x25 Calibrating delay loop... 4744.80 BogoMIPS -Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, 0k highmem) +Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, @/0k highmem) Dentry cache hash table entries: 4096 (order: 3, 32768 bytes) Inode cache hash table entries: 2048 (order: 2, 16384 bytes) Mount cache hash table entries: 512 (order: 0, 4096 bytes) @@ -971,14 +1044,14 @@ EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended VFS: Mounted root (ext2 filesystem). Freeing unused kernel memory: 64k freed -Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 +Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 @/(Red Hat @/Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 QEMU Linux test distribution (based on Redhat 9) Type 'exit' to halt the system sh-2.05b# -@end example +@end smallexample @item Then you can play with the kernel inside the virtual serial console. You @@ -1028,6 +1101,7 @@ Lawton for the plex86 Project (@url{www.plex86.org}). @end enumerate +@node pcsys_usb @section USB emulation QEMU emulates a PCI UHCI USB controller and a 8 port USB hub connected @@ -1111,7 +1185,8 @@ QEMU has a primitive support to work with gdb, so that you can do In order to use gdb, launch qemu with the '-s' option. It will wait for a gdb connection: @example -> qemu -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda" +> qemu -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \ + -append "root=/dev/hda" Connected to host network interface: tun0 Waiting gdb connection on port 1234 @end example @@ -1143,6 +1218,7 @@ Use @code{set architecture i8086} to dump 16 bit code. Then use @code{x/10i $cs*16+*eip} to dump the code at the PC position. @end enumerate +@node pcsys_os_specific @section Target OS specific information @subsection Linux @@ -1229,12 +1305,22 @@ it takes host CPU cycles even when idle. You can install the utility from @url{http://www.vmware.com/software/dosidle210.zip} to solve this problem. +@node QEMU System emulator for non PC targets @chapter QEMU System emulator for non PC targets QEMU is a generic emulator and it emulates many non PC machines. Most of the options are similar to the PC emulator. The differences are mentionned in the following sections. +@menu +* QEMU PowerPC System emulator:: +* Sparc32 System emulator invocation:: +* Sparc64 System emulator invocation:: +* MIPS System emulator invocation:: +* ARM System emulator invocation:: +@end menu + +@node QEMU PowerPC System emulator @section QEMU PowerPC System emulator Use the executable @file{qemu-system-ppc} to simulate a complete PREP @@ -1299,6 +1385,7 @@ Set the initial VGA graphic mode. The default is 800x600x15. More information is available at @url{http://perso.magic.fr/l_indien/qemu-ppc/}. +@node Sparc32 System emulator invocation @section Sparc32 System emulator invocation Use the executable @file{qemu-system-sparc} to simulate a JavaStation @@ -1327,7 +1414,7 @@ Floppy drive The number of peripherals is fixed in the architecture. QEMU uses the Proll, a PROM replacement available at -@url{http://people.redhat.com/zaitcev/linux/}. The required +@url{http://people.redhat.com/@/zaitcev/linux/}. The required QEMU-specific patches are included with the sources. A sample Linux 2.6 series kernel and ram disk image are available on @@ -1348,6 +1435,7 @@ Set the initial TCX graphic mode. The default is 1024x768. @c man end +@node Sparc64 System emulator invocation @section Sparc64 System emulator invocation Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine. @@ -1366,6 +1454,7 @@ Non Volatile RAM M48T59 PC-compatible serial ports @end itemize +@node MIPS System emulator invocation @section MIPS System emulator invocation Use the executable @file{qemu-system-mips} to simulate a MIPS machine. @@ -1383,6 +1472,7 @@ NE2000 network card More information is available in the QEMU mailing-list archive. +@node ARM System emulator invocation @section ARM System emulator invocation Use the executable @file{qemu-system-arm} to simulate a ARM @@ -1401,8 +1491,16 @@ SMC 91c111 Ethernet adapter A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. +@node QEMU Linux User space emulator @chapter QEMU Linux User space emulator +@menu +* Quick Start:: +* Wine launch:: +* Command line options:: +@end menu + +@node Quick Start @section Quick Start In order to launch a Linux process, QEMU needs the process executable @@ -1446,11 +1544,13 @@ Linux kernel. @item The x86 version of QEMU is also included. You can try weird things such as: @example -qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386 +qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 \ + /usr/local/qemu-i386/bin/ls-i386 @end example @end itemize +@node Wine launch @section Wine launch @itemize @@ -1467,17 +1567,19 @@ qemu-i386 /usr/local/qemu-i386/bin/ls-i386 (@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page). @item Configure Wine on your account. Look at the provided script -@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous +@file{/usr/local/qemu-i386/@/bin/wine-conf.sh}. Your previous @code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}. @item Then you can try the example @file{putty.exe}: @example -qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe +qemu-i386 /usr/local/qemu-i386/wine/bin/wine \ + /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe @end example @end itemize +@node Command line options @section Command line options @example @@ -1505,6 +1607,14 @@ Act as if the host page size was 'pagesize' bytes @node compilation @chapter Compilation from the sources +@menu +* Linux/Unix:: +* Windows:: +* Cross compilation for Windows with Linux:: +* Mac OS X:: +@end menu + +@node Linux/Unix @section Linux/Unix @subsection Compilation @@ -1562,6 +1672,7 @@ ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0 variables. You must use gcc 3.x on PowerPC. @end example +@node Windows @section Windows @itemize @@ -1571,7 +1682,7 @@ instructions in the download section and the FAQ. @item Download the MinGW development library of SDL 1.2.x -(@file{SDL-devel-1.2.x-mingw32.tar.gz}) from +(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from @url{http://www.libsdl.org}. Unpack it in a temporary place, and unpack the archive @file{i386-mingw32msvc.tar.gz} in the MinGW tool directory. Edit the @file{sdl-config} script so that it gives the @@ -1591,6 +1702,7 @@ correct SDL directory when invoked. @end itemize +@node Cross compilation for Windows with Linux @section Cross compilation for Windows with Linux @itemize @@ -1622,9 +1734,15 @@ installation directory. Note: Currently, Wine does not seem able to launch QEMU for Win32. +@node Mac OS X @section Mac OS X The Mac OS X patches are not fully merged in QEMU, so you should look at the QEMU mailing list archive to have all the necessary information. +@node Index +@chapter Index +@printindex cp + +@bye diff --git a/qemu-tech.texi b/qemu-tech.texi index 95d1787e3..77bda8637 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -1,7 +1,12 @@ \input texinfo @c -*- texinfo -*- +@c %**start of header +@setfilename qemu-tech.info +@settitle QEMU Internals +@exampleindent 0 +@paragraphindent 0 +@c %**end of header @iftex -@settitle QEMU Internals @titlepage @sp 7 @center @titlefont{QEMU Internals} @@ -9,8 +14,32 @@ @end titlepage @end iftex +@ifnottex +@node Top +@top + +@menu +* Introduction:: +* QEMU Internals:: +* Regression Tests:: +* Index:: +@end menu +@end ifnottex + +@contents + +@node Introduction @chapter Introduction +@menu +* intro_features:: Features +* intro_x86_emulation:: x86 emulation +* intro_arm_emulation:: ARM emulation +* intro_ppc_emulation:: PowerPC emulation +* intro_sparc_emulation:: SPARC emulation +@end menu + +@node intro_features @section Features QEMU is a FAST! processor emulator using a portable dynamic @@ -43,7 +72,7 @@ QEMU generic features: @item User space only or full system emulation. -@item Using dynamic translation to native code for reasonnable speed. +@item Using dynamic translation to native code for reasonable speed. @item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390. @@ -65,13 +94,13 @@ QEMU user mode emulation features: @item Accurate signal handling by remapping host signals to target signals. @end itemize -@end itemize QEMU full system emulation features: @itemize @item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU. @end itemize +@node intro_x86_emulation @section x86 emulation QEMU x86 target features: @@ -110,6 +139,7 @@ maximum performances. @end itemize +@node intro_arm_emulation @section ARM emulation @itemize @@ -122,6 +152,7 @@ maximum performances. @end itemize +@node intro_ppc_emulation @section PowerPC emulation @itemize @@ -133,6 +164,7 @@ FPU and MMU. @end itemize +@node intro_sparc_emulation @section SPARC emulation @itemize @@ -166,8 +198,26 @@ implemented. Floating point exception support is untested. @end itemize +@node QEMU Internals @chapter QEMU Internals +@menu +* QEMU compared to other emulators:: +* Portable dynamic translation:: +* Register allocation:: +* Condition code optimisations:: +* CPU state optimisations:: +* Translation cache:: +* Direct block chaining:: +* Self-modifying code and translated code invalidation:: +* Exception support:: +* MMU emulation:: +* Hardware interrupts:: +* User emulation specific details:: +* Bibliography:: +@end menu + +@node QEMU compared to other emulators @section QEMU compared to other emulators Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than @@ -214,6 +264,7 @@ The commercial PC Virtualizers (VMWare [9], VirtualPC [10], TwoOStwo and potentially unsafe host drivers. Moreover, they are unable to provide cycle exact simulation as an emulator can. +@node Portable dynamic translation @section Portable dynamic translation QEMU is a dynamic translator. When it first encounters a piece of code, @@ -243,6 +294,7 @@ That way, QEMU is no more difficult to port than a dynamic linker. To go even faster, GCC static register variables are used to keep the state of the virtual CPU. +@node Register allocation @section Register allocation Since QEMU uses fixed simple instructions, no efficient register @@ -250,6 +302,7 @@ allocation can be done. However, because RISC CPUs have a lot of register, most of the virtual CPU state can be put in registers without doing complicated register allocation. +@node Condition code optimisations @section Condition code optimisations Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a @@ -268,6 +321,7 @@ generated simple instructions (see the condition codes are not needed by the next instructions, no condition codes are computed at all. +@node CPU state optimisations @section CPU state optimisations The x86 CPU has many internal states which change the way it evaluates @@ -279,6 +333,7 @@ segment base. [The FPU stack pointer register is not handled that way yet]. +@node Translation cache @section Translation cache A 16 MByte cache holds the most recently used translations. For @@ -287,6 +342,7 @@ contains just a single basic block (a block of x86 instructions terminated by a jump or by a virtual CPU state change which the translator cannot deduce statically). +@node Direct block chaining @section Direct block chaining After each translated basic block is executed, QEMU uses the simulated @@ -302,6 +358,7 @@ it easier to make the jump target modification atomic. On some host architectures (such as x86 or PowerPC), the @code{JUMP} opcode is directly patched so that the block chaining has no overhead. +@node Self-modifying code and translated code invalidation @section Self-modifying code and translated code invalidation Self-modifying code is a special challenge in x86 emulation because no @@ -332,6 +389,7 @@ built. Every store into that page checks the bitmap to see if the code really needs to be invalidated. It avoids invalidating the code when only data is modified in the page. +@node Exception support @section Exception support longjmp() is used when an exception such as division by zero is @@ -348,6 +406,7 @@ in some cases it is not computed because of condition code optimisations. It is not a big concern because the emulated code can still be restarted in any cases. +@node MMU emulation @section MMU emulation For system emulation, QEMU uses the mmap() system call to emulate the @@ -367,6 +426,7 @@ means that each basic block is indexed with its physical address. When MMU mappings change, only the chaining of the basic blocks is reset (i.e. a basic block can no longer jump directly to another one). +@node Hardware interrupts @section Hardware interrupts In order to be faster, QEMU does not check at every basic block if an @@ -377,6 +437,7 @@ block. It ensures that the execution will return soon in the main loop of the CPU emulator. Then the main loop can test if the interrupt is pending and handle it. +@node User emulation specific details @section User emulation specific details @subsection Linux system call translation @@ -434,6 +495,7 @@ space conflicts. QEMU solves this problem by being an executable ELF shared object as the ld-linux.so ELF interpreter. That way, it can be relocated at load time. +@node Bibliography @section Bibliography @table @asis @@ -456,7 +518,7 @@ by Kevin Lawton et al. x86 emulator on Alpha-Linux. @item [5] -@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/full_papers/chernoff/chernoff.pdf}, +@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/@/full_papers/chernoff/chernoff.pdf}, DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton Chernoff and Ray Hookway. @@ -486,11 +548,19 @@ The TwoOStwo PC virtualizer. @end table +@node Regression Tests @chapter Regression Tests In the directory @file{tests/}, various interesting testing programs are available. There are used for regression testing. +@menu +* test-i386:: +* linux-test:: +* qruncom.c:: +@end menu + +@node test-i386 @section @file{test-i386} This program executes most of the 16 bit and 32 bit x86 instructions and @@ -506,12 +576,20 @@ The Linux system call @code{vm86()} is used to test vm86 emulation. Various exceptions are raised to test most of the x86 user space exception reporting. +@node linux-test @section @file{linux-test} This program tests various Linux system calls. It is used to verify that the system call parameters are correctly converted between target and host CPUs. +@node qruncom.c @section @file{qruncom.c} Example of usage of @code{libqemu} to emulate a user mode i386 CPU. + +@node Index +@chapter Index +@printindex cp + +@bye -- cgit v1.2.3 From 45a8f3ca063cd38c851f8795c4b11add034ba300 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Apr 2006 22:20:58 +0000 Subject: typo git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1874 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index bfc14902f..ef61918e2 100644 --- a/vl.c +++ b/vl.c @@ -5560,7 +5560,7 @@ int main(int argc, char **argv) /* terminal init */ if (nographic) { dumb_display_init(ds); - } if (vnc_display != -1) { + } else if (vnc_display != -1) { vnc_display_init(ds, vnc_display); } else { #if defined(CONFIG_SDL) -- cgit v1.2.3 From f3548328783d49bb3f22c16b644b1156361e6678 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Apr 2006 22:51:54 +0000 Subject: info and dvi doc targets git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1875 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index ff60329ad..44e56a0a0 100644 --- a/Makefile +++ b/Makefile @@ -85,6 +85,12 @@ cscope: %.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 > $@ -- cgit v1.2.3 From 6ca957f08f272321e32ccef2f4053e93dc10f4ad Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 30 Apr 2006 22:53:25 +0000 Subject: win32 socket fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1876 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu_socket.h | 30 ++++++++++++++++++++++++++++++ vl.c | 13 ++----------- vnc.c | 27 +++++++++++---------------- 3 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 qemu_socket.h diff --git a/qemu_socket.h b/qemu_socket.h new file mode 100644 index 000000000..64b7d4e5e --- /dev/null +++ b/qemu_socket.h @@ -0,0 +1,30 @@ +/* headers to use the BSD sockets */ +#ifndef QEMU_SOCKET_H +#define QEMU_SOCKET_H + +#ifdef _WIN32 + +#include +#include +#include + +#define socket_error() WSAGetLastError() +#undef EINTR +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINTR WSAEINTR +#define EINPROGRESS WSAEINPROGRESS + +#else + +#include +#include +#include + +#define socket_error() errno +#define closesocket(s) close(s) + +#endif /* !_WIN32 */ + +void socket_set_nonblock(int fd); + +#endif /* QEMU_SOCKET_H */ diff --git a/vl.c b/vl.c index ef61918e2..26d3cce58 100644 --- a/vl.c +++ b/vl.c @@ -66,12 +66,12 @@ #include #include #include -#include -#include #define getopt_long_only getopt_long #define memalign(align, size) malloc(size) #endif +#include "qemu_socket.h" + #ifdef CONFIG_SDL #ifdef __APPLE__ #include @@ -1085,12 +1085,6 @@ CharDriverState *qemu_chr_open_null(void) #ifdef _WIN32 -#define socket_error() WSAGetLastError() -#undef EINTR -#define EWOULDBLOCK WSAEWOULDBLOCK -#define EINTR WSAEINTR -#define EINPROGRESS WSAEINPROGRESS - static void socket_cleanup(void) { WSACleanup(); @@ -1142,9 +1136,6 @@ void socket_set_nonblock(int fd) #else -#define socket_error() errno -#define closesocket(s) close(s) - static int unix_write(int fd, const uint8_t *buf, int len1) { int ret, len; diff --git a/vnc.c b/vnc.c index f461de6a9..52c137db9 100644 --- a/vnc.c +++ b/vnc.c @@ -1,9 +1,5 @@ #include "vl.h" - -#include -#include -#include -#include +#include "qemu_socket.h" #define VNC_REFRESH_INTERVAL (1000 / 30) @@ -386,14 +382,14 @@ static void buffer_append(Buffer *buffer, const void *data, size_t len) buffer->offset += len; } -static int vnc_client_io_error(VncState *vs, int ret) +static int vnc_client_io_error(VncState *vs, int ret, int last_errno) { if (ret == 0 || ret == -1) { - if (ret == -1 && (errno == EINTR || errno == EAGAIN)) + if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN)) return 0; qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); - close(vs->csock); + closesocket(vs->csock); vs->csock = -1; buffer_reset(&vs->input); buffer_reset(&vs->output); @@ -405,8 +401,7 @@ static int vnc_client_io_error(VncState *vs, int ret) static void vnc_client_error(VncState *vs) { - errno = EINVAL; - vnc_client_io_error(vs, -1); + vnc_client_io_error(vs, -1, EINVAL); } static void vnc_client_write(void *opaque) @@ -414,8 +409,8 @@ static void vnc_client_write(void *opaque) ssize_t ret; VncState *vs = opaque; - ret = write(vs->csock, vs->output.buffer, vs->output.offset); - ret = vnc_client_io_error(vs, ret); + ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); + ret = vnc_client_io_error(vs, ret, socket_error()); if (!ret) return; @@ -440,8 +435,8 @@ static void vnc_client_read(void *opaque) buffer_reserve(&vs->input, 4096); - ret = read(vs->csock, buffer_end(&vs->input), 4096); - ret = vnc_client_io_error(vs, ret); + ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); + ret = vnc_client_io_error(vs, ret, socket_error()); if (!ret) return; @@ -812,7 +807,7 @@ static void vnc_listen_read(void *opaque) vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (vs->csock != -1) { - fcntl(vs->csock, F_SETFL, O_NONBLOCK); + socket_set_nonblock(vs->csock); qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); vnc_write(vs, "RFB 003.003\n", 12); vnc_flush(vs); @@ -862,7 +857,7 @@ void vnc_display_init(DisplayState *ds, int display) reuse_addr = 1; ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, - &reuse_addr, sizeof(reuse_addr)); + (const char *)&reuse_addr, sizeof(reuse_addr)); if (ret == -1) { fprintf(stderr, "setsockopt() failed\n"); exit(1); -- cgit v1.2.3 From 38954dca9ffbdfa9cf46a16d6134cc00491aba6f Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 30 Apr 2006 23:54:18 +0000 Subject: Add install-doc rule. Use it when building docs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1877 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 44e56a0a0..2a5425e6a 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,15 @@ 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: all +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)" @@ -55,11 +63,7 @@ install: all video.x proll.elf linux_boot.bin; do \ $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ done - 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" mkdir -p "$(DESTDIR)$(datadir)/keymaps" for x in $(KEYMAPS); do \ $(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \ -- cgit v1.2.3 From 7d510b8c0c31645a1600e7a2e196f4629a472ae0 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 10:38:19 +0000 Subject: copyright git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1878 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/vnc.c b/vnc.c index 52c137db9..aa4c38ac8 100644 --- a/vnc.c +++ b/vnc.c @@ -1,3 +1,28 @@ +/* + * QEMU VNC display driver + * + * Copyright (C) 2006 Anthony Liguori + * 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 "qemu_socket.h" -- cgit v1.2.3 From 4b6ccfdec99e9e3a22566beac76b83d7ff025bff Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 10:59:02 +0000 Subject: fixed realloc logic (Ed Swierk) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1879 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/mbuf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/slirp/mbuf.c b/slirp/mbuf.c index fa36d8950..3769bafd2 100644 --- a/slirp/mbuf.c +++ b/slirp/mbuf.c @@ -146,18 +146,19 @@ m_inc(m, size) struct mbuf *m; int size; { + int datasize; + /* some compiles throw up on gotos. This one we can fake. */ if(m->m_size>size) return; if (m->m_flags & M_EXT) { - /* datasize = m->m_data - m->m_ext; */ + datasize = m->m_data - m->m_ext; m->m_ext = (char *)realloc(m->m_ext,size); /* if (m->m_ext == NULL) * return (struct mbuf *)NULL; */ - /* m->m_data = m->m_ext + datasize; */ + m->m_data = m->m_ext + datasize; } else { - int datasize; char *dat; datasize = m->m_data - m->m_dat; dat = (char *)malloc(size); -- cgit v1.2.3 From fedc54adaa4c36da28a726a1f56e1db53f699a50 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 11:02:11 +0000 Subject: fixed IP packet rassembly logic (Ed Swierk) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1880 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/ip_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp/ip_input.c b/slirp/ip_input.c index 74b922316..4f5bfd9a5 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -344,8 +344,8 @@ insert: while (q != (struct ipasfrag *)fp) { struct mbuf *t; t = dtom(q); - m_cat(m, t); q = (struct ipasfrag *) q->ipf_next; + m_cat(m, t); } /* -- cgit v1.2.3 From 773f2cdd3c288b6881986c32d8dbe24d4d8af4e1 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 11:17:27 +0000 Subject: set TCP_MSS to 1460 (Ed Swierk) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1881 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/tcp.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/slirp/tcp.h b/slirp/tcp.h index 3e0b4dd8f..cd7e89110 100644 --- a/slirp/tcp.h +++ b/slirp/tcp.h @@ -100,8 +100,10 @@ struct tcphdr { * With an IP MSS of 576, this is 536, * but 512 is probably more convenient. * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). + * + * We make this 1460 because we only care about Ethernet in the qemu context. */ -#define TCP_MSS 512 +#define TCP_MSS 1460 #define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ -- cgit v1.2.3 From 4f552e3b9a21df7d04850dcd58da505eec197b00 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 11:18:01 +0000 Subject: do not delay TCP acks (Ed Swierk) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1882 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/tcp_input.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 8729d76a7..c01516101 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -580,28 +580,11 @@ findso: * congestion avoidance sender won't send more until * he gets an ACK. * - * Here are 3 interpretations of what should happen. - * The best (for me) is to delay-ack everything except - * if it's a one-byte packet containing an ESC - * (this means it's an arrow key (or similar) sent using - * Nagel, hence there will be no echo) - * The first of these is the original, the second is the - * middle ground between the other 2 + * It is better to not delay acks at all to maximize + * TCP throughput. See RFC 2581. */ -/* if (((unsigned)ti->ti_len < tp->t_maxseg)) { - */ -/* if (((unsigned)ti->ti_len < tp->t_maxseg && - * (so->so_iptos & IPTOS_LOWDELAY) == 0) || - * ((so->so_iptos & IPTOS_LOWDELAY) && - * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { - */ - if ((unsigned)ti->ti_len == 1 && - ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { - tp->t_flags |= TF_ACKNOW; - tcp_output(tp); - } else { - tp->t_flags |= TF_DELACK; - } + tp->t_flags |= TF_ACKNOW; + tcp_output(tp); return; } } /* header prediction */ -- cgit v1.2.3 From 07de1eaa9d48a70950af271b68f49fd2970ecfd5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 12:31:24 +0000 Subject: increase max kernel size with initrd git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1883 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index 38c75d471..4add257dc 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -32,7 +32,7 @@ #define LINUX_BOOT_FILENAME "linux_boot.bin" #define KERNEL_LOAD_ADDR 0x00100000 -#define INITRD_LOAD_ADDR 0x00400000 +#define INITRD_LOAD_ADDR 0x00600000 #define KERNEL_PARAMS_ADDR 0x00090000 #define KERNEL_CMDLINE_ADDR 0x00099000 -- cgit v1.2.3 From eade0f192eef92f6c43ab036407cff46148be842 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 12:43:29 +0000 Subject: fix for hosts resuming from software suspend (initial patch by John Coiner) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1884 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 26d3cce58..8984c489e 100644 --- a/vl.c +++ b/vl.c @@ -558,6 +558,7 @@ int64_t cpu_get_real_ticks(void) #error unsupported CPU #endif +static int64_t cpu_ticks_prev; static int64_t cpu_ticks_offset; static int cpu_ticks_enabled; @@ -566,7 +567,15 @@ static inline int64_t cpu_get_ticks(void) if (!cpu_ticks_enabled) { return cpu_ticks_offset; } else { - return cpu_get_real_ticks() + cpu_ticks_offset; + int64_t ticks; + ticks = cpu_get_real_ticks(); + if (cpu_ticks_prev > ticks) { + /* Note: non increasing ticks may happen if the host uses + software suspend */ + cpu_ticks_offset += cpu_ticks_prev - ticks; + } + cpu_ticks_prev = ticks; + return ticks + cpu_ticks_offset; } } -- cgit v1.2.3 From 06d9f2f7d468d8ffdae107f33bc0391e42f4c6b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 13:23:04 +0000 Subject: better win32 timers - use win32 event to wake up cpu in idle mode (kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1885 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/vl.c b/vl.c index 8984c489e..a671682d1 100644 --- a/vl.c +++ b/vl.c @@ -518,9 +518,15 @@ int64_t cpu_get_real_ticks(void) int64_t cpu_get_real_ticks(void) { +#ifdef _WIN32 + LARGE_INTEGER ti; + QueryPerformanceCounter(&ti); + return ti.QuadPart; +#else int64_t val; asm volatile ("rdtsc" : "=A" (val)); return val; +#endif } #elif defined(__x86_64__) @@ -598,17 +604,26 @@ void cpu_disable_ticks(void) } } -static int64_t get_clock(void) -{ #ifdef _WIN32 - struct _timeb tb; - _ftime(&tb); - return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000; +void cpu_calibrate_ticks(void) +{ + LARGE_INTEGER freq; + int ret; + + ret = QueryPerformanceFrequency(&freq); + if (ret == 0) { + fprintf(stderr, "Could not calibrate ticks\n"); + exit(1); + } + ticks_per_sec = freq.QuadPart; +} + #else +static int64_t get_clock(void) +{ struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000000LL + tv.tv_usec; -#endif } void cpu_calibrate_ticks(void) @@ -617,15 +632,12 @@ void cpu_calibrate_ticks(void) usec = get_clock(); ticks = cpu_get_real_ticks(); -#ifdef _WIN32 - Sleep(50); -#else usleep(50 * 1000); -#endif usec = get_clock() - usec; ticks = cpu_get_real_ticks() - ticks; ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; } +#endif /* !_WIN32 */ /* compute with 96 bit intermediate result: (a*b)/c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) @@ -673,6 +685,8 @@ QEMUClock *vm_clock; static QEMUTimer *active_timers[2]; #ifdef _WIN32 static MMRESULT timerID; +static HANDLE host_alarm = NULL; +static unsigned int period = 1; #else /* frequency of the times() clock tick */ static int timer_freq; @@ -895,6 +909,9 @@ static void host_alarm_handler(int host_signum) qemu_get_clock(vm_clock)) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { +#ifdef _WIN32 + SetEvent(host_alarm); +#endif CPUState *env = cpu_single_env; if (env) { /* stop the currently executing cpu because a timer occured */ @@ -955,8 +972,15 @@ static void init_timers(void) #ifdef _WIN32 { int count=0; + TIMECAPS tc; + + ZeroMemory(&tc, sizeof(TIMECAPS)); + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + if (period < tc.wPeriodMin) + period = tc.wPeriodMin; + timeBeginPeriod(period); timerID = timeSetEvent(1, // interval (ms) - 0, // resolution + period, // resolution host_alarm_handler, // function (DWORD)&count, // user parameter TIME_PERIODIC | TIME_CALLBACK_FUNCTION); @@ -964,6 +988,12 @@ static void init_timers(void) perror("failed timer alarm"); exit(1); } + host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!host_alarm) { + perror("failed CreateEvent"); + exit(1); + } + ResetEvent(host_alarm); } pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; #else @@ -1023,6 +1053,11 @@ void quit_timers(void) { #ifdef _WIN32 timeKillEvent(timerID); + timeEndPeriod(period); + if (host_alarm) { + CloseHandle(host_alarm); + host_alarm = NULL; + } #endif } @@ -4383,7 +4418,21 @@ void main_loop_wait(int timeout) } #ifdef _WIN32 if (ret == 0 && timeout > 0) { - Sleep(timeout); + int err; + HANDLE hEvents[1]; + + hEvents[0] = host_alarm; + ret = WaitForMultipleObjects(1, hEvents, FALSE, timeout); + switch(ret) { + case WAIT_OBJECT_0 + 0: + break; + case WAIT_TIMEOUT: + break; + default: + err = GetLastError(); + fprintf(stderr, "Wait error %d %d\n", ret, err); + break; + } } #endif /* poll any events */ -- cgit v1.2.3 From 29e3055c370c2fae64470cdce213607d4fa4d85c Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 13:28:36 +0000 Subject: workaround: force /dev/rtc usage on Linux git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1886 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index a671682d1..71d5f57a9 100644 --- a/vl.c +++ b/vl.c @@ -1023,7 +1023,11 @@ static void init_timers(void) getitimer(ITIMER_REAL, &itv); #if defined(__linux__) - if (itv.it_interval.tv_usec > 1000) { + /* XXX: force /dev/rtc usage because even 2.6 kernels may not + have timers with 1 ms resolution. The correct solution will + be to use the POSIX real time timers available in recent + 2.6 kernels */ + if (itv.it_interval.tv_usec > 1000 || 1) { /* try to use /dev/rtc to have a faster timer */ if (start_rtc_timer() < 0) goto use_itimer; -- cgit v1.2.3 From e035649ea3d6d3f845c4ffd686f00dedb9999292 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 13:33:02 +0000 Subject: use a single select for slirp and qemu sockets git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1887 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/vl.c b/vl.c index 71d5f57a9..c08b39d94 100644 --- a/vl.c +++ b/vl.c @@ -4409,7 +4409,7 @@ void qemu_system_powerdown_request(void) void main_loop_wait(int timeout) { IOHandlerRecord *ioh, *ioh_next; - fd_set rfds, wfds; + fd_set rfds, wfds, xfds; int ret, nfds; struct timeval tv; PollingEntry *pe; @@ -4444,6 +4444,7 @@ void main_loop_wait(int timeout) nfds = -1; FD_ZERO(&rfds); FD_ZERO(&wfds); + FD_ZERO(&xfds); for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { if (ioh->fd_read && (!ioh->fd_read_poll || @@ -4465,7 +4466,12 @@ void main_loop_wait(int timeout) #else tv.tv_usec = timeout * 1000; #endif - ret = select(nfds + 1, &rfds, &wfds, NULL, &tv); +#if defined(CONFIG_SLIRP) + if (slirp_inited) { + slirp_select_fill(&nfds, &rfds, &wfds, &xfds); + } +#endif + ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); if (ret > 0) { /* XXX: better handling of removal */ for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { @@ -4478,30 +4484,19 @@ void main_loop_wait(int timeout) } } } -#ifdef _WIN32 - tap_win32_poll(); -#endif - #if defined(CONFIG_SLIRP) - /* XXX: merge with the previous select() */ if (slirp_inited) { - fd_set rfds, wfds, xfds; - int nfds; - struct timeval tv; - - nfds = -1; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&xfds); - slirp_select_fill(&nfds, &rfds, &wfds, &xfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); - if (ret >= 0) { - slirp_select_poll(&rfds, &wfds, &xfds); + if (ret < 0) { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); } + slirp_select_poll(&rfds, &wfds, &xfds); } #endif +#ifdef _WIN32 + tap_win32_poll(); +#endif if (vm_running) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], -- cgit v1.2.3 From 38cfa06cbd27375226acf06083aa4301b085cbf2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 13:58:07 +0000 Subject: Solaris port (Ben Taylor) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1888 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 7 +------ fpu/softfloat-native.h | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 695fdb680..6845fccca 100755 --- a/configure +++ b/configure @@ -148,9 +148,6 @@ if [ "$solaris" = "yes" ] ; then make="gmake" install="ginstall" solarisrev=`uname -r | cut -f2 -d.` - if test $solarisrev -lt 10 ; then - presolaris10="yes" - fi fi # find source path @@ -640,9 +637,7 @@ if test "$darwin" = "yes" ; then fi if test "$solaris" = "yes" ; then echo "CONFIG_SOLARIS=yes" >> $config_mak - if test "$presolaris10" = "yes" ; then - echo "#define _PRESOLARIS10 1" >> $config_h - fi + echo "#define HOST_SOLARIS $solarisrev" >> $config_h fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index b0264d52e..e7c08b89f 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -1,11 +1,36 @@ /* Native implementation of soft float functions */ #include -#if defined(_BSD) && !defined(__APPLE__) + +#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS) #include +#define fabsf(f) ((float)fabs(f)) #else -#if !defined(_PRESOLARIS10) #include #endif + +/* + * Define some C99-7.12.3 classification macros and + * some C99-.12.4 for Solaris systems OS less than 10, + * or Solaris 10 systems running GCC 3.x or less. + * Solaris 10 with GCC4 does not need these macros as they + * are defined in with a compiler directive + */ +#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ( ( HOST_SOLARIS >= 10 ) && ( __GNUC__ <= 4) )) +/* + * C99 7.12.3 classification macros + * and + * C99 7.12.14 comparison macros + * + * ... do not work on Solaris 10 using GNU CC 3.4.x. + * Try to workaround the missing / broken C99 math macros. + */ + +#define isnormal(x) (fpclass(x) >= FP_NZERO) +#define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y))) +#define isgreaterequal(x, y) ((!unordered(x, y)) && ((x) >= (y))) +#define isless(x, y) ((!unordered(x, y)) && ((x) < (y))) +#define islessequal(x, y) ((!unordered(x, y)) && ((x) <= (y))) +#define isunordered(x,y) unordered(x, y) #endif typedef float float32; @@ -35,7 +60,7 @@ typedef union { /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point rounding mode. *----------------------------------------------------------------------------*/ -#if defined(_BSD) && !defined(__APPLE__) +#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS) enum { float_round_nearest_even = FP_RN, float_round_down = FP_RM, -- cgit v1.2.3 From bdbd7676fd84066e710fab187c343174bb9592cd Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 1 May 2006 21:44:22 +0000 Subject: uppercase fix (Anthony Liguori) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1889 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vnc.c b/vnc.c index aa4c38ac8..088f9cfac 100644 --- a/vnc.c +++ b/vnc.c @@ -591,7 +591,7 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) } } -static void key_event(VncState *vs, int down, uint32_t sym) +static void do_key_event(VncState *vs, int down, uint32_t sym) { int keycode; @@ -605,6 +605,13 @@ static void key_event(VncState *vs, int down, uint32_t sym) kbd_put_keycode(keycode | 0x80); } +static void key_event(VncState *vs, int down, uint32_t sym) +{ + if (sym >= 'A' && sym <= 'Z') + sym = sym - 'A' + 'a'; + do_key_event(vs, down, sym); +} + static void framebuffer_update_request(VncState *vs, int incremental, int x_position, int y_position, int w, int h) -- cgit v1.2.3 From 3aee288bc8e120bd022cbfede2aaf2b2a7ab1dcc Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 2 May 2006 20:54:12 +0000 Subject: fixed memory leak git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1890 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf_ops.h | 1 + 1 file changed, 1 insertion(+) diff --git a/elf_ops.h b/elf_ops.h index 4da755e1b..122bf10c1 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -195,6 +195,7 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, data = NULL; } } + qemu_free(phdr); return total_size; fail: qemu_free(data); -- cgit v1.2.3 From e553272d759b41e6d1de226c8fad0aab56fefdd6 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 2 May 2006 21:09:02 +0000 Subject: > 32 KB packet handling (Ed Swierk) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1891 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/ip.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/slirp/ip.h b/slirp/ip.h index 8280e55b8..371537d48 100644 --- a/slirp/ip.h +++ b/slirp/ip.h @@ -75,10 +75,6 @@ typedef u_int32_t n_long; /* long as received from the net */ /* * Structure of an internet header, naked of options. - * - * We declare ip_len and ip_off to be short, rather than u_short - * pragmatically since otherwise unsigned comparisons can result - * against negative integers quite easily, and fail in subtle ways. */ struct ip { #ifdef WORDS_BIGENDIAN @@ -89,9 +85,9 @@ struct ip { ip_v:4; /* version */ #endif u_int8_t ip_tos; /* type of service */ - int16_t ip_len; /* total length */ + u_int16_t ip_len; /* total length */ u_int16_t ip_id; /* identification */ - int16_t ip_off; /* fragment offset field */ + u_int16_t ip_off; /* fragment offset field */ #define IP_DF 0x4000 /* don't fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ @@ -212,7 +208,7 @@ struct ipovly { caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ u_int8_t ih_x1; /* (unused) */ u_int8_t ih_pr; /* protocol */ - int16_t ih_len; /* protocol length */ + u_int16_t ih_len; /* protocol length */ struct in_addr ih_src; /* source internet address */ struct in_addr ih_dst; /* destination internet address */ }; @@ -253,9 +249,9 @@ struct ipasfrag { u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit * to avoid destroying tos (PPPDTRuu); * copied from (ip_off&IP_MF) */ - int16_t ip_len; + u_int16_t ip_len; u_int16_t ip_id; - int16_t ip_off; + u_int16_t ip_off; u_int8_t ip_ttl; u_int8_t ip_p; u_int16_t ip_sum; -- cgit v1.2.3 From f5d2a381d1fb5f7def1c86c95d0c093e54e3aa67 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 2 May 2006 22:18:28 +0000 Subject: performance boost (on P4 hosts at least, rdtsc is a _very_ bad random generator) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1892 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 6b6b6cb33..0cb11683a 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -27,11 +27,14 @@ void cpu_mips_irqctrl_init (void) { } +/* XXX: do not use a global */ uint32_t cpu_mips_get_random (CPUState *env) { - uint32_t now = qemu_get_clock(vm_clock); - - return now % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired; + static uint32_t seed = 0; + uint32_t idx; + seed = seed * 314159 + 1; + idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired; + return idx; } /* MIPS R4K timer */ -- cgit v1.2.3 From c91fde65f410bca632113e98c700759950de2e93 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 2 May 2006 22:52:36 +0000 Subject: correct qemu-system-mipsel naming git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1893 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Makefile.target b/Makefile.target index 77eaa1e76..aff19c5c8 100644 --- a/Makefile.target +++ b/Makefile.target @@ -24,29 +24,24 @@ LIBS= HELPER_CFLAGS=$(CFLAGS) DYNGEN=../dyngen$(EXESUF) # user emulator name +TARGET_ARCH2=$(TARGET_ARCH) ifeq ($(TARGET_ARCH),arm) ifeq ($(TARGET_WORDS_BIGENDIAN),yes) - QEMU_USER=qemu-armeb - else - QEMU_USER=qemu-arm + TARGET_ARCH2=armeb endif -else +endif ifeq ($(TARGET_ARCH),mips) - ifeq ($(TARGET_WORDS_BIGENDIAN),yes) - QEMU_USER=qemu-mips - else - QEMU_USER=qemu-mipsel + ifneq ($(TARGET_WORDS_BIGENDIAN),yes) + TARGET_ARCH2=mipsel endif -else - QEMU_USER=qemu-$(TARGET_ARCH) -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_ARCH)$(EXESUF) +QEMU_SYSTEM=qemu-system-$(TARGET_ARCH2)$(EXESUF) endif else QEMU_SYSTEM=qemu-fast -- cgit v1.2.3 From 68cae3d8c10f914296dfc52cebe214264031df7d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 19:17:26 +0000 Subject: bswapq fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1894 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 1 + target-i386/helper.c | 4 ++++ target-i386/op.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 8299af4e7..4ff527f84 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -187,6 +187,7 @@ void helper_imulq_EAX_T0(void); void helper_imulq_T0_T1(void); void helper_divq_EAX_T0(void); void helper_idivq_EAX_T0(void); +void helper_bswapq_T0(void); void helper_cmpxchg8b(void); void helper_cpuid(void); void helper_enter_level(int level, int data32); diff --git a/target-i386/helper.c b/target-i386/helper.c index 7bd545e81..123f51049 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3395,6 +3395,10 @@ void helper_idivq_EAX_T0(void) EDX = r1; } +void helper_bswapq_T0(void) +{ + T0 = bswap64(T0); +} #endif float approx_rsqrt(float a) diff --git a/target-i386/op.c b/target-i386/op.c index 20eeaa440..a9a8665a1 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -225,7 +225,7 @@ void OPPROTO op_bswapl_T0(void) #ifdef TARGET_X86_64 void OPPROTO op_bswapq_T0(void) { - T0 = bswap64(T0); + helper_bswapq_T0(); } #endif -- cgit v1.2.3 From 8dbca8dd8a81d7f1afd6ef23b418c8f9d292b65d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 19:58:17 +0000 Subject: separate alias_addr (10.0.2.2) from our_addr (Ed Swierk) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1895 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/ip_icmp.c | 7 +++---- slirp/main.h | 1 + slirp/misc.c | 6 ++---- slirp/slirp.c | 3 +++ slirp/socket.c | 2 +- slirp/tcp_subr.c | 4 ++-- slirp/udp.c | 2 +- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 8bc97a078..b67a37359 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -114,8 +114,7 @@ icmp_input(m, hlen) case ICMP_ECHO: icp->icmp_type = ICMP_ECHOREPLY; ip->ip_len += hlen; /* since ip_input subtracts this */ - if (ip->ip_dst.s_addr == our_addr.s_addr || - (ip->ip_dst.s_addr == (special_addr.s_addr|htonl(CTL_ALIAS))) ) { + if (ip->ip_dst.s_addr == alias_addr.s_addr) { icmp_reflect(m); } else { struct socket *so; @@ -161,7 +160,7 @@ icmp_input(m, hlen) icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); udp_detach(so); } - } /* if ip->ip_dst.s_addr == our_addr.s_addr */ + } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ break; case ICMP_UNREACH: /* XXX? report error? close socket? */ @@ -311,7 +310,7 @@ icmp_error(msrc, type, code, minsize, message) ip->ip_ttl = MAXTTL; ip->ip_p = IPPROTO_ICMP; ip->ip_dst = ip->ip_src; /* ip adresses */ - ip->ip_src = our_addr; + ip->ip_src = alias_addr; (void ) ip_output((struct socket *)NULL, m); diff --git a/slirp/main.h b/slirp/main.h index 2d6f43bcc..181b6ae88 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -34,6 +34,7 @@ extern u_int curtime; extern fd_set *global_readfds, *global_writefds, *global_xfds; extern struct in_addr ctl_addr; extern struct in_addr special_addr; +extern struct in_addr alias_addr; extern struct in_addr our_addr; extern struct in_addr loopback_addr; extern struct in_addr dns_addr; diff --git a/slirp/misc.c b/slirp/misc.c index 1cd874973..2c42fd15b 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -94,10 +94,8 @@ getouraddr() he = gethostbyname(buff); if (he) our_addr = *(struct in_addr *)he->h_addr; - /* If the host doesn't have a useful IP address then use the - guest side address. */ - if (our_addr.s_addr == 0 || our_addr.s_addr == loopback_addr.s_addr) - our_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); + if (our_addr.s_addr == 0) + our_addr.s_addr = loopback_addr.s_addr; } #if SIZEOF_CHAR_P == 8 diff --git a/slirp/slirp.c b/slirp/slirp.c index 1331d0ead..e88745e8a 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -9,6 +9,8 @@ struct in_addr loopback_addr; /* address for slirp virtual addresses */ struct in_addr special_addr; +/* virtual address alias for host */ +struct in_addr alias_addr; const uint8_t special_ethaddr[6] = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 @@ -154,6 +156,7 @@ void slirp_init(void) } inet_aton(CTL_SPECIAL, &special_addr); + alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); getouraddr(); } diff --git a/slirp/socket.c b/slirp/socket.c index ce6528fc4..0ae1f8701 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -596,7 +596,7 @@ solisten(port, laddr, lport, flags) getsockname(s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) - so->so_faddr = our_addr; + so->so_faddr = alias_addr; else so->so_faddr = addr.sin_addr; diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index fd3f21a69..e66987eea 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -504,7 +504,7 @@ tcp_connect(inso) so->so_faddr = addr.sin_addr; /* Translate connections from localhost to the real hostname */ if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) - so->so_faddr = our_addr; + so->so_faddr = alias_addr; /* Close the accept() socket, set right state */ if (inso->so_state & SS_FACCEPTONCE) { @@ -840,7 +840,7 @@ tcp_emu(so, m) if (ns->so_faddr.s_addr == 0 || ns->so_faddr.s_addr == loopback_addr.s_addr) - ns->so_faddr = our_addr; + ns->so_faddr = alias_addr; ns->so_iptos = tcp_tos(ns); tp = sototcpcb(ns); diff --git a/slirp/udp.c b/slirp/udp.c index be51af679..dbccccc4f 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -657,7 +657,7 @@ udp_listen(port, laddr, lport, flags) getsockname(so->s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) - so->so_faddr = our_addr; + so->so_faddr = alias_addr; else so->so_faddr = addr.sin_addr; -- cgit v1.2.3 From 691fce48a30ecdc024cac03bf51909f3ac3da2bb Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 20:15:47 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1896 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ VERSION | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 27c6009fb..659b5017b 100644 --- a/Changelog +++ b/Changelog @@ -8,6 +8,9 @@ version 0.8.1: - 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: diff --git a/VERSION b/VERSION index a3df0a695..c18d72be3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.0 +0.8.1 \ No newline at end of file -- cgit v1.2.3 From 215cf0bed85ea55efbc53306e092c4780bf4933c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 20:18:43 +0000 Subject: removed sh4 user build (not usable yet) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1897 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 6845fccca..ae10b581c 100755 --- a/configure +++ b/configure @@ -356,7 +356,7 @@ if test -z "$target_list" ; then 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 sh4-user $target_list" + target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list" fi else target_list=`echo "$target_list" | sed -e 's/,/ /g'` -- cgit v1.2.3 From c904d61f78479b46a154273960e5f4e2b22d6b55 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 20:53:46 +0000 Subject: UDP broadcast translation error (Mark Jonckheere) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1899 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/udp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/slirp/udp.c b/slirp/udp.c index dbccccc4f..0d7097027 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -312,8 +312,11 @@ int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in saddr, daddr; saddr = *addr; - if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { saddr.sin_addr.s_addr = so->so_faddr.s_addr; + if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff)) + saddr.sin_addr.s_addr = alias_addr.s_addr; + } daddr.sin_addr = so->so_laddr; daddr.sin_port = so->so_lport; -- cgit v1.2.3 From ceb5caaf1823492e2dde7dd7e1e73634b1fc9d93 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 21:18:59 +0000 Subject: removed ssize_t for win32 compatibility git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1900 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vnc.c b/vnc.c index 088f9cfac..93f61a70b 100644 --- a/vnc.c +++ b/vnc.c @@ -431,7 +431,7 @@ static void vnc_client_error(VncState *vs) static void vnc_client_write(void *opaque) { - ssize_t ret; + long ret; VncState *vs = opaque; ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); @@ -456,7 +456,7 @@ static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) static void vnc_client_read(void *opaque) { VncState *vs = opaque; - ssize_t ret; + long ret; buffer_reserve(&vs->input, 4096); -- cgit v1.2.3 From 107654552cb442b8b95c1f3ebc18dd64c6c0f0d5 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 21:24:55 +0000 Subject: more correct e820 ranges for ACPI compatibility git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1901 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 65536 bytes pc-bios/bios.diff | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 138 insertions(+), 8 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 537851abb..64be517b2 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 647025b88..e87592784 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -4,7 +4,7 @@ RCS file: /cvsroot/bochs/bochs/bios/apmbios.S,v retrieving revision 1.4 diff -u -w -r1.4 apmbios.S --- apmbios.S 26 Dec 2005 10:35:51 -0000 1.4 -+++ apmbios.S 28 Apr 2006 22:41:19 -0000 ++++ apmbios.S 3 May 2006 21:22:46 -0000 @@ -225,6 +225,7 @@ APMSYM(05): cmp al, #0x05 @@ -19,7 +19,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v retrieving revision 1.160 diff -u -w -r1.160 rombios.c --- rombios.c 25 Jan 2006 17:51:49 -0000 1.160 -+++ rombios.c 28 Apr 2006 22:41:21 -0000 ++++ rombios.c 3 May 2006 21:22:48 -0000 @@ -1816,6 +1816,7 @@ { printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ", @@ -38,7 +38,137 @@ diff -u -w -r1.160 rombios.c } //-------------------------------------------------------------------------- -@@ -8713,6 +8717,7 @@ +@@ -3999,6 +4003,29 @@ + } + #endif + ++ ++void set_e820_range(ES, DI, start, end, type) ++ Bit16u ES; ++ Bit16u DI; ++ Bit32u start; ++ Bit32u end; ++ Bit16u type; ++{ ++ write_word(ES, DI, start); ++ write_word(ES, DI+2, start >> 16); ++ write_word(ES, DI+4, 0x00); ++ write_word(ES, DI+6, 0x00); ++ ++ end -= start; ++ write_word(ES, DI+8, end); ++ write_word(ES, DI+10, end >> 16); ++ write_word(ES, DI+12, 0x0000); ++ write_word(ES, DI+14, 0x0000); ++ ++ write_word(ES, DI+16, type); ++ write_word(ES, DI+18, 0x0); ++} ++ + void + int15_function32(regs, ES, DS, FLAGS) + pushad_regs_t regs; // REGS pushed via pushad +@@ -4063,19 +4090,8 @@ + switch(regs.u.r16.bx) + { + case 0: +- write_word(ES, regs.u.r16.di, 0x00); +- write_word(ES, regs.u.r16.di+2, 0x00); +- write_word(ES, regs.u.r16.di+4, 0x00); +- write_word(ES, regs.u.r16.di+6, 0x00); +- +- write_word(ES, regs.u.r16.di+8, 0xFC00); +- write_word(ES, regs.u.r16.di+10, 0x0009); +- write_word(ES, regs.u.r16.di+12, 0x0000); +- write_word(ES, regs.u.r16.di+14, 0x0000); +- +- write_word(ES, regs.u.r16.di+16, 0x1); +- write_word(ES, regs.u.r16.di+18, 0x0); +- ++ set_e820_range(ES, regs.u.r16.di, ++ 0x0000000L, 0x0009fc00L, 1); + regs.u.r32.ebx = 1; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; +@@ -4083,6 +4099,24 @@ + return; + break; + case 1: ++ set_e820_range(ES, regs.u.r16.di, ++ 0x0009fc00L, 0x000a0000L, 2); ++ regs.u.r32.ebx = 2; ++ regs.u.r32.eax = 0x534D4150; ++ regs.u.r32.ecx = 0x14; ++ CLEAR_CF(); ++ return; ++ break; ++ case 2: ++ set_e820_range(ES, regs.u.r16.di, ++ 0x000e8000L, 0x00100000L, 2); ++ regs.u.r32.ebx = 3; ++ regs.u.r32.eax = 0x534D4150; ++ regs.u.r32.ecx = 0x14; ++ CLEAR_CF(); ++ return; ++ break; ++ case 3: + extended_memory_size = inb_cmos(0x35); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x34); +@@ -4092,9 +4126,9 @@ + extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 + } + extended_memory_size *= 1024; +- extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off ++ extended_memory_size += (16L * 1024 * 1024); + +- if(extended_memory_size <= 15728640) ++ if(extended_memory_size <= (16L * 1024 * 1024)) + { + extended_memory_size = inb_cmos(0x31); + extended_memory_size <<= 8; +@@ -4102,28 +4136,23 @@ + extended_memory_size *= 1024; + } + +- write_word(ES, regs.u.r16.di, 0x0000); +- write_word(ES, regs.u.r16.di+2, 0x0010); +- write_word(ES, regs.u.r16.di+4, 0x0000); +- write_word(ES, regs.u.r16.di+6, 0x0000); +- +- write_word(ES, regs.u.r16.di+8, extended_memory_size); +- extended_memory_size >>= 16; +- write_word(ES, regs.u.r16.di+10, extended_memory_size); +- extended_memory_size >>= 16; +- write_word(ES, regs.u.r16.di+12, extended_memory_size); +- extended_memory_size >>= 16; +- write_word(ES, regs.u.r16.di+14, extended_memory_size); +- +- write_word(ES, regs.u.r16.di+16, 0x1); +- write_word(ES, regs.u.r16.di+18, 0x0); +- +- regs.u.r32.ebx = 0; ++ set_e820_range(ES, regs.u.r16.di, ++ 0x00100000L, extended_memory_size, 1); ++ regs.u.r32.ebx = 4; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; ++ case 4: ++ /* 256KB BIOS area at the end of 4 GB */ ++ set_e820_range(ES, regs.u.r16.di, ++ 0xfffc0000L, 0x00000000L, 2); ++ regs.u.r32.ebx = 0; ++ regs.u.r32.eax = 0x534D4150; ++ regs.u.r32.ecx = 0x14; ++ CLEAR_CF(); ++ return; + default: /* AX=E820, DX=534D4150, BX unrecognized */ + goto int15_unimplemented; + break; +@@ -8713,6 +8742,7 @@ mov al, #0x80 bios32_end: popf @@ -46,7 +176,7 @@ diff -u -w -r1.160 rombios.c retf .align 16 -@@ -8823,17 +8828,17 @@ +@@ -8823,17 +8853,17 @@ pci_pro_fail: pop edi pop esi @@ -66,7 +196,7 @@ diff -u -w -r1.160 rombios.c retf pci_pro_select_reg: -@@ -8971,7 +8976,7 @@ +@@ -8971,7 +9001,7 @@ jmp pci_real_ok pci_real_f0d: ;; write configuration dword cmp al, #0x0d @@ -75,7 +205,7 @@ diff -u -w -r1.160 rombios.c call pci_real_select_reg push dx mov dx, #0x0cfc -@@ -8979,6 +8984,46 @@ +@@ -8979,6 +9009,46 @@ out dx, eax pop dx jmp pci_real_ok @@ -122,7 +252,7 @@ diff -u -w -r1.160 rombios.c pci_real_unknown: mov ah, #0x81 pci_real_fail: -@@ -9019,6 +9064,7 @@ +@@ -9019,6 +9089,7 @@ dw 0,0 ;; Miniport data db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved db 0x07 ;; checksum @@ -130,7 +260,7 @@ diff -u -w -r1.160 rombios.c ;; first slot entry PCI-to-ISA (embedded) db 0 ;; pci bus number db 0x08 ;; pci device number (bit 7-3) -@@ -9097,6 +9143,7 @@ +@@ -9097,6 +9168,7 @@ dw 0xdef8 ;; IRQ bitmap INTD# db 5 ;; physical slot (0 = embedded) db 0 ;; reserved -- cgit v1.2.3 From 6515b203702b01cd7d4ef8f9cbad77474fc2ed42 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 22:02:44 +0000 Subject: ACPI support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1902 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 7 +- hw/acpi-dsdt.dsl | 432 +++++++++++++++++++++++++++++++++++++++ hw/acpi-dsdt.hex | 222 ++++++++++++++++++++ hw/acpi.c | 609 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.c | 5 + vl.c | 8 + vl.h | 5 + 7 files changed, 1287 insertions(+), 1 deletion(-) create mode 100644 hw/acpi-dsdt.dsl create mode 100644 hw/acpi-dsdt.hex create mode 100644 hw/acpi.c diff --git a/Makefile.target b/Makefile.target index aff19c5c8..f25153b84 100644 --- a/Makefile.target +++ b/Makefile.target @@ -316,7 +316,7 @@ 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 mixeng.o apic.o parallel.o +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) @@ -471,6 +471,11 @@ endif loader.o: loader.c elf_ops.h +acpi.o: acpi.c acpi-dsdt.hex + +#$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl +# iasl -tc -p $@ $< + ifeq ($(TARGET_ARCH), sh4) op.o: op.c op_mem.c cpu.h op_helper.o: op_helper.c exec.h cpu.h diff --git a/hw/acpi-dsdt.dsl b/hw/acpi-dsdt.dsl new file mode 100644 index 000000000..b94df01ba --- /dev/null +++ b/hw/acpi-dsdt.dsl @@ -0,0 +1,432 @@ +/* + * QEMU ACPI DSDT ASL definition + * + * Copyright (c) 2006 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 version 2 as published by the Free Software Foundation. + * + * 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 + */ +DefinitionBlock ( + "acpi-dsdt.aml", // Output Filename + "DSDT", // Signature + 0x01, // DSDT Compliance Revision + "QEMU", // OEMID + "QEMUDSDT", // TABLE ID + 0x1 // OEM Revision + ) +{ + Scope (\) + { + /* CMOS memory access */ + OperationRegion (CMS, SystemIO, 0x70, 0x02) + Field (CMS, ByteAcc, NoLock, Preserve) + { + CMSI, 8, + CMSD, 8 + } + Method (CMRD, 1, NotSerialized) + { + Store (Arg0, CMSI) + Store (CMSD, Local0) + Return (Local0) + } + + /* Debug Output */ + OperationRegion (DBG, SystemIO, 0xb044, 0x04) + Field (DBG, DWordAcc, NoLock, Preserve) + { + DBGL, 32, + } + } + + + /* PCI Bus definition */ + Scope(\_SB) { + Device(PCI0) { + Name (_HID, EisaId ("PNP0A03")) + Name (_ADR, 0x00) + Name (_UID, 1) + Name(_PRT, Package() { + /* PCI IRQ routing table, example from ACPI 2.0a specification, + section 6.2.8.1 */ + /* Note: we provide the same info as the PCI routing + table of the Bochs BIOS */ + + // PCI Slot 0 + Package() {0x0000ffff, 0, LNKA, 0}, + Package() {0x0000ffff, 1, LNKB, 0}, + Package() {0x0000ffff, 2, LNKC, 0}, + Package() {0x0000ffff, 3, LNKD, 0}, + + // PCI Slot 1 + Package() {0x0001ffff, 0, LNKB, 0}, + Package() {0x0001ffff, 1, LNKC, 0}, + Package() {0x0001ffff, 2, LNKD, 0}, + Package() {0x0001ffff, 3, LNKA, 0}, + + // PCI Slot 2 + Package() {0x0002ffff, 0, LNKC, 0}, + Package() {0x0002ffff, 1, LNKD, 0}, + Package() {0x0002ffff, 2, LNKA, 0}, + Package() {0x0002ffff, 3, LNKB, 0}, + + // PCI Slot 3 + Package() {0x0003ffff, 0, LNKD, 0}, + Package() {0x0003ffff, 1, LNKA, 0}, + Package() {0x0003ffff, 2, LNKB, 0}, + Package() {0x0003ffff, 3, LNKC, 0}, + + // PCI Slot 4 + Package() {0x0004ffff, 0, LNKA, 0}, + Package() {0x0004ffff, 1, LNKB, 0}, + Package() {0x0004ffff, 2, LNKC, 0}, + Package() {0x0004ffff, 3, LNKD, 0}, + + // PCI Slot 5 + Package() {0x0005ffff, 0, LNKB, 0}, + Package() {0x0005ffff, 1, LNKC, 0}, + Package() {0x0005ffff, 2, LNKD, 0}, + Package() {0x0005ffff, 3, LNKA, 0}, + }) + + Method (_CRS, 0, NotSerialized) + { + Name (MEMP, ResourceTemplate () + { + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x00FF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0100, // Address Length + ,, ) + IO (Decode16, + 0x0CF8, // Address Range Minimum + 0x0CF8, // Address Range Maximum + 0x01, // Address Alignment + 0x08, // Address Length + ) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0000, // Address Range Minimum + 0x0CF7, // Address Range Maximum + 0x0000, // Address Translation Offset + 0x0CF8, // Address Length + ,, , TypeStatic) + WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, // Address Space Granularity + 0x0D00, // Address Range Minimum + 0xFFFF, // Address Range Maximum + 0x0000, // Address Translation Offset + 0xF300, // Address Length + ,, , TypeStatic) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x00000000, // Address Space Granularity + 0x000A0000, // Address Range Minimum + 0x000BFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x00020000, // Address Length + ,, , AddressRangeMemory, TypeStatic) + DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite, + 0x00000000, // Address Space Granularity + 0x00000000, // Address Range Minimum + 0xFEBFFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x00000000, // Address Length + ,, MEMF, AddressRangeMemory, TypeStatic) + }) + CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN) + CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX) + CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN) + /* compute available RAM */ + Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0) + ShiftLeft(Local0, 16, Local0) + Add(Local0, 0x1000000, Local0) + /* update field of last region */ + Store(Local0, PMIN) + Subtract (PMAX, PMIN, PLEN) + Increment (PLEN) + Return (MEMP) + } + } + } + + /* PIIX3 ISA bridge */ + Scope(\_SB.PCI0) { + Device (ISA) { + Name (_ADR, 0x00010000) + + /* PIIX PCI to ISA irq remapping */ + OperationRegion (P40C, PCI_Config, 0x60, 0x04) + + + /* Keyboard seems to be important for WinXP install */ + Device (KBD) + { + Name (_HID, EisaId ("PNP0303")) + Method (_STA, 0, NotSerialized) + { + Return (0x0f) + } + + Method (_CRS, 0, NotSerialized) + { + Name (TMP, ResourceTemplate () + { + IO (Decode16, + 0x0060, // Address Range Minimum + 0x0060, // Address Range Maximum + 0x01, // Address Alignment + 0x01, // Address Length + ) + IO (Decode16, + 0x0064, // Address Range Minimum + 0x0064, // Address Range Maximum + 0x01, // Address Alignment + 0x01, // Address Length + ) + IRQNoFlags () + {1} + }) + Return (TMP) + } + } + + Device (MOU) + { + Name (_HID, EisaId ("PNP0F13")) + Method (_STA, 0, NotSerialized) + { + Return (0x0f) + } + + Method (_CRS, 0, NotSerialized) + { + Name (TMP, ResourceTemplate () + { + IRQNoFlags () {12} + }) + Return (TMP) + } + } + } + } + + /* PCI IRQs */ + Scope(\_SB) { + Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) + { + PRQ0, 8, + PRQ1, 8, + PRQ2, 8, + PRQ3, 8 + } + + Device(LNKA){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 1) + Name(_PRS, ResourceTemplate(){ + IRQ (Level, ActiveLow, Shared) + {3,4,5,6,7,9,10,11,12} + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ0, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ0, 0x80, PRQ0) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + IRQ (Level, ActiveLow, Shared) + {1} + }) + CreateWordField (PRR0, 0x01, TMP) + Store (PRQ0, Local0) + If (LLess (Local0, 0x80)) + { + ShiftLeft (One, Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateWordField (Arg0, 0x01, TMP) + FindSetRightBit (TMP, Local0) + Decrement (Local0) + Store (Local0, PRQ0) + } + } + Device(LNKB){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 2) + Name(_PRS, ResourceTemplate(){ + IRQ (Level, ActiveLow, Shared) + {3,4,5,6,7,9,10,11,12} + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ1, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ1, 0x80, PRQ1) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + IRQ (Level, ActiveLow, Shared) + {1} + }) + CreateWordField (PRR0, 0x01, TMP) + Store (PRQ1, Local0) + If (LLess (Local0, 0x80)) + { + ShiftLeft (One, Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateWordField (Arg0, 0x01, TMP) + FindSetRightBit (TMP, Local0) + Decrement (Local0) + Store (Local0, PRQ1) + } + } + Device(LNKC){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 3) + Name(_PRS, ResourceTemplate(){ + IRQ (Level, ActiveLow, Shared) + {3,4,5,6,7,9,10,11,12} + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ2, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ2, 0x80, PRQ2) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + IRQ (Level, ActiveLow, Shared) + {1} + }) + CreateWordField (PRR0, 0x01, TMP) + Store (PRQ2, Local0) + If (LLess (Local0, 0x80)) + { + ShiftLeft (One, Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateWordField (Arg0, 0x01, TMP) + FindSetRightBit (TMP, Local0) + Decrement (Local0) + Store (Local0, PRQ2) + } + } + Device(LNKD){ + Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link + Name(_UID, 4) + Name(_PRS, ResourceTemplate(){ + IRQ (Level, ActiveLow, Shared) + {3,4,5,6,7,9,10,11,12} + }) + Method (_STA, 0, NotSerialized) + { + Store (0x0B, Local0) + If (And (0x80, PRQ3, Local1)) + { + Store (0x09, Local0) + } + Return (Local0) + } + Method (_DIS, 0, NotSerialized) + { + Or (PRQ3, 0x80, PRQ3) + } + Method (_CRS, 0, NotSerialized) + { + Name (PRR0, ResourceTemplate () + { + IRQ (Level, ActiveLow, Shared) + {1} + }) + CreateWordField (PRR0, 0x01, TMP) + Store (PRQ3, Local0) + If (LLess (Local0, 0x80)) + { + ShiftLeft (One, Local0, TMP) + } + Else + { + Store (Zero, TMP) + } + Return (PRR0) + } + Method (_SRS, 1, NotSerialized) + { + CreateWordField (Arg0, 0x01, TMP) + FindSetRightBit (TMP, Local0) + Decrement (Local0) + Store (Local0, PRQ3) + } + } + } + + /* S5 = power off state */ + Name (_S5, Package (4) { + 0x00, // PM1a_CNT.SLP_TYP + 0x00, // PM2a_CNT.SLP_TYP + 0x00, // reserved + 0x00, // reserved + }) +} diff --git a/hw/acpi-dsdt.hex b/hw/acpi-dsdt.hex new file mode 100644 index 000000000..d58bd6fe5 --- /dev/null +++ b/hw/acpi-dsdt.hex @@ -0,0 +1,222 @@ +/* + * + * Intel ACPI Component Architecture + * ASL Optimizing Compiler version 20060421 [Apr 29 2006] + * Copyright (C) 2000 - 2006 Intel Corporation + * Supports ACPI Specification Revision 3.0a + * + * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed May 3 22:49:16 2006 + * + * C source code output + * + */ +unsigned char AmlCode[] = +{ + 0x44,0x53,0x44,0x54,0x73,0x06,0x00,0x00, /* 00000000 "DSDTs..." */ + 0x01,0x39,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".9QEMU.." */ + 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */ + 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ + 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */ + 0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */ + 0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */ + 0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */ + 0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */ + 0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */ + 0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */ + 0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */ + 0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */ + 0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */ + 0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */ + 0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */ + 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */ + 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */ + 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */ + 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */ + 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */ + 0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0B, /* 000000A8 ".LNKA..." */ + 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */ + 0x42,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "B......." */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000C0 "..LNKC.." */ + 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */ + 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKD....." */ + 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */ + 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "B......." */ + 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x43,0x00, /* 000000E8 "...LNKC." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x44,0x00,0x12, /* 000000F8 "..LNKD.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */ + 0x03,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D, /* 00000108 ".LNKA..." */ + 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */ + 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKC....." */ + 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */ + 0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "D......." */ + 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x41, /* 00000130 "....LNKA" */ + 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x42,0x00, /* 00000140 "...LNKB." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */ + 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000150 ".LNKD..." */ + 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */ + 0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKA....." */ + 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */ + 0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KB......" */ + 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */ + 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "C......." */ + 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x41,0x00, /* 00000188 "...LNKA." */ + 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */ + 0x01,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E, /* 00000198 ".LNKB..." */ + 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */ + 0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKC...." */ + 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */ + 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKD....." */ + 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */ + 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "B......." */ + 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x43,0x00, /* 000001D0 "...LNKC." */ + 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x44,0x00,0x12, /* 000001E0 "..LNKD.." */ + 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */ + 0x03,0x4C,0x4E,0x4B,0x41,0x00,0x14,0x4C, /* 000001F0 ".LNKA..L" */ + 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */ + 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */ + 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */ + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */ + 0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */ + 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */ + 0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */ + 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */ + 0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */ + 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */ + 0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */ + 0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */ + 0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */ + 0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */ + 0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */ + 0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */ + 0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */ + 0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */ + 0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */ + 0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */ + 0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */ + 0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */ + 0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */ + 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */ + 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */ + 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */ + 0x45,0x4D,0x50,0x10,0x43,0x0A,0x2E,0x5F, /* 000002D0 "EMP.C.._" */ + 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */ + 0x82,0x46,0x09,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".F.ISA_." */ + 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */ + 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */ + 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */ + 0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */ + 0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */ + 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */ + 0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */ + 0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */ + 0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */ + 0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */ + 0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */ + 0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */ + 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */ + 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */ + 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */ + 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */ + 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */ + 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x10, /* 00000370 "y..TMP_." */ + 0x4F,0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81, /* 00000378 "O._SB_[." */ + 0x24,0x2F,0x03,0x50,0x43,0x49,0x30,0x49, /* 00000380 "$/.PCI0I" */ + 0x53,0x41,0x5F,0x50,0x34,0x30,0x43,0x01, /* 00000388 "SA_P40C." */ + 0x50,0x52,0x51,0x30,0x08,0x50,0x52,0x51, /* 00000390 "PRQ0.PRQ" */ + 0x31,0x08,0x50,0x52,0x51,0x32,0x08,0x50, /* 00000398 "1.PRQ2.P" */ + 0x52,0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A, /* 000003A0 "RQ3.[.N." */ + 0x4C,0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49, /* 000003A8 "LNKA._HI" */ + 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000003B0 "D.A...._" */ + 0x55,0x49,0x44,0x01,0x08,0x5F,0x50,0x52, /* 000003B8 "UID.._PR" */ + 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 000003C0 "S....#.." */ + 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 000003C8 ".y..._ST" */ + 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 000003D0 "A.p..`.." */ + 0x7B,0x0A,0x80,0x50,0x52,0x51,0x30,0x61, /* 000003D8 "{..PRQ0a" */ + 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 000003E0 "p..`.`.." */ + 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 000003E8 "_DIS.}PR" */ + 0x51,0x30,0x0A,0x80,0x50,0x52,0x51,0x30, /* 000003F0 "Q0..PRQ0" */ + 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 000003F8 ".?_CRS.." */ + 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000400 "PRR0...." */ + 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000408 "#...y..P" */ + 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000410 "RR0.TMP_" */ + 0x70,0x50,0x52,0x51,0x30,0x60,0xA0,0x0C, /* 00000418 "pPRQ0`.." */ + 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000420 ".`..y.`T" */ + 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000428 "MP_..p.T" */ + 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00000430 "MP_.PRR0" */ + 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 00000438 ".._SRS.." */ + 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 00000440 "h.TMP_.T" */ + 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 00000448 "MP_`v`p`" */ + 0x50,0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A, /* 00000450 "PRQ0[.O." */ + 0x4C,0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49, /* 00000458 "LNKB._HI" */ + 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 00000460 "D.A...._" */ + 0x55,0x49,0x44,0x0A,0x02,0x08,0x5F,0x50, /* 00000468 "UID..._P" */ + 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 00000470 "RS....#." */ + 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 00000478 "..y..._S" */ + 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 00000480 "TA.p..`." */ + 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000488 ".{..PRQ1" */ + 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000490 "ap..`.`." */ + 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000498 "._DIS.}P" */ + 0x52,0x51,0x31,0x0A,0x80,0x50,0x52,0x51, /* 000004A0 "RQ1..PRQ" */ + 0x31,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 000004A8 "1.?_CRS." */ + 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 000004B0 ".PRR0..." */ + 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 000004B8 ".#...y.." */ + 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 000004C0 "PRR0.TMP" */ + 0x5F,0x70,0x50,0x52,0x51,0x31,0x60,0xA0, /* 000004C8 "_pPRQ1`." */ + 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 000004D0 "..`..y.`" */ + 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 000004D8 "TMP_..p." */ + 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 000004E0 "TMP_.PRR" */ + 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 000004E8 "0.._SRS." */ + 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 000004F0 ".h.TMP_." */ + 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 000004F8 "TMP_`v`p" */ + 0x60,0x50,0x52,0x51,0x31,0x5B,0x82,0x4F, /* 00000500 "`PRQ1[.O" */ + 0x0A,0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48, /* 00000508 ".LNKC._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000510 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x0A,0x03,0x08,0x5F, /* 00000518 "_UID..._" */ + 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000520 "PRS....#" */ + 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000528 "...y..._" */ + 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00000530 "STA.p..`" */ + 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 00000538 "..{..PRQ" */ + 0x32,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 00000540 "2ap..`.`" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00000548 ".._DIS.}" */ + 0x50,0x52,0x51,0x32,0x0A,0x80,0x50,0x52, /* 00000550 "PRQ2..PR" */ + 0x51,0x32,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 00000558 "Q2.?_CRS" */ + 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 00000560 "..PRR0.." */ + 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 00000568 "..#...y." */ + 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 00000570 ".PRR0.TM" */ + 0x50,0x5F,0x70,0x50,0x52,0x51,0x32,0x60, /* 00000578 "P_pPRQ2`" */ + 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 00000580 "...`..y." */ + 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 00000588 "`TMP_..p" */ + 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000590 ".TMP_.PR" */ + 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000598 "R0.._SRS" */ + 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 000005A0 "..h.TMP_" */ + 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 000005A8 ".TMP_`v`" */ + 0x70,0x60,0x50,0x52,0x51,0x32,0x5B,0x82, /* 000005B0 "p`PRQ2[." */ + 0x4F,0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F, /* 000005B8 "O.LNKD._" */ + 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 000005C0 "HID.A..." */ + 0x08,0x5F,0x55,0x49,0x44,0x0A,0x04,0x08, /* 000005C8 "._UID..." */ + 0x5F,0x50,0x52,0x53,0x11,0x09,0x0A,0x06, /* 000005D0 "_PRS...." */ + 0x23,0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A, /* 000005D8 "#...y..." */ + 0x5F,0x53,0x54,0x41,0x00,0x70,0x0A,0x0B, /* 000005E0 "_STA.p.." */ + 0x60,0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52, /* 000005E8 "`..{..PR" */ + 0x51,0x33,0x61,0x70,0x0A,0x09,0x60,0xA4, /* 000005F0 "Q3ap..`." */ + 0x60,0x14,0x11,0x5F,0x44,0x49,0x53,0x00, /* 000005F8 "`.._DIS." */ + 0x7D,0x50,0x52,0x51,0x33,0x0A,0x80,0x50, /* 00000600 "}PRQ3..P" */ + 0x52,0x51,0x33,0x14,0x3F,0x5F,0x43,0x52, /* 00000608 "RQ3.?_CR" */ + 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00000610 "S..PRR0." */ + 0x09,0x0A,0x06,0x23,0x02,0x00,0x18,0x79, /* 00000618 "...#...y" */ + 0x00,0x8B,0x50,0x52,0x52,0x30,0x01,0x54, /* 00000620 "..PRR0.T" */ + 0x4D,0x50,0x5F,0x70,0x50,0x52,0x51,0x33, /* 00000628 "MP_pPRQ3" */ + 0x60,0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79, /* 00000630 "`...`..y" */ + 0x01,0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07, /* 00000638 ".`TMP_.." */ + 0x70,0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50, /* 00000640 "p.TMP_.P" */ + 0x52,0x52,0x30,0x14,0x1B,0x5F,0x53,0x52, /* 00000648 "RR0.._SR" */ + 0x53,0x01,0x8B,0x68,0x01,0x54,0x4D,0x50, /* 00000650 "S..h.TMP" */ + 0x5F,0x82,0x54,0x4D,0x50,0x5F,0x60,0x76, /* 00000658 "_.TMP_`v" */ + 0x60,0x70,0x60,0x50,0x52,0x51,0x33,0x08, /* 00000660 "`p`PRQ3." */ + 0x5F,0x53,0x35,0x5F,0x12,0x06,0x04,0x00, /* 00000668 "_S5_...." */ + 0x00,0x00,0x00, +}; diff --git a/hw/acpi.c b/hw/acpi.c new file mode 100644 index 000000000..9053142f3 --- /dev/null +++ b/hw/acpi.c @@ -0,0 +1,609 @@ +/* + * ACPI implementation + * + * Copyright (c) 2006 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 version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "vl.h" + +//#define DEBUG + +/* i82731AB (PIIX4) compatible power management function */ +#define PM_FREQ 3579545 + +/* XXX: make them variable */ +#define PM_IO_BASE 0xb000 +#define SMI_CMD_IO_ADDR 0xb040 +#define ACPI_DBG_IO_ADDR 0xb044 + +typedef struct PIIX4PMState { + PCIDevice dev; + uint16_t pmsts; + uint16_t pmen; + uint16_t pmcntrl; + QEMUTimer *tmr_timer; + int64_t tmr_overflow_time; +} PIIX4PMState; + +#define RTC_EN (1 << 10) +#define PWRBTN_EN (1 << 8) +#define GBL_EN (1 << 5) +#define TMROF_EN (1 << 0) + +#define SCI_EN (1 << 0) + +#define SUS_EN (1 << 13) + +/* Note: only used for ACPI bios init. Could be deleted when ACPI init + is integrated in Bochs BIOS */ +static PIIX4PMState *piix4_pm_state; + +static uint32_t get_pmtmr(PIIX4PMState *s) +{ + uint32_t d; + d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); + return d & 0xffffff; +} + +static int get_pmsts(PIIX4PMState *s) +{ + int64_t d; + int pmsts; + pmsts = s->pmsts; + d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); + if (d >= s->tmr_overflow_time) + s->pmsts |= TMROF_EN; + return pmsts; +} + +static void pm_update_sci(PIIX4PMState *s) +{ + int sci_level, pmsts; + int64_t expire_time; + + pmsts = get_pmsts(s); + sci_level = (((pmsts & s->pmen) & + (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); + pci_set_irq(&s->dev, 0, sci_level); + /* schedule a timer interruption if needed */ + if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { + expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ); + qemu_mod_timer(s->tmr_timer, expire_time); + } else { + qemu_del_timer(s->tmr_timer); + } +} + +static void pm_tmr_timer(void *opaque) +{ + PIIX4PMState *s = opaque; + pm_update_sci(s); +} + +static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +{ + PIIX4PMState *s = opaque; + addr &= 0x3f; + switch(addr) { + case 0x00: + { + int64_t d; + int pmsts; + pmsts = get_pmsts(s); + if (pmsts & val & TMROF_EN) { + /* if TMRSTS is reset, then compute the new overflow time */ + d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); + s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; + } + s->pmsts &= ~val; + pm_update_sci(s); + } + break; + case 0x02: + s->pmen = val; + pm_update_sci(s); + break; + case 0x04: + { + int sus_typ; + s->pmcntrl = val & ~(SUS_EN); + if (val & SUS_EN) { + /* change suspend type */ + sus_typ = (val >> 10) & 3; + switch(sus_typ) { + case 0: /* soft power off */ + qemu_system_shutdown_request(); + break; + default: + break; + } + } + } + break; + default: + break; + } +#ifdef DEBUG + printf("PM writew port=0x%04x val=0x%04x\n", addr, val); +#endif +} + +static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val; + + addr &= 0x3f; + switch(addr) { + case 0x00: + val = get_pmsts(s); + break; + case 0x02: + val = s->pmen; + break; + case 0x04: + val = s->pmcntrl; + break; + default: + val = 0; + break; + } +#ifdef DEBUG + printf("PM readw port=0x%04x val=0x%04x\n", addr, val); +#endif + return val; +} + +static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +{ + // PIIX4PMState *s = opaque; + addr &= 0x3f; +#ifdef DEBUG + printf("PM writel port=0x%04x val=0x%08x\n", addr, val); +#endif +} + +static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val; + + addr &= 0x3f; + switch(addr) { + case 0x08: + val = get_pmtmr(s); + break; + default: + val = 0; + break; + } +#ifdef DEBUG + printf("PM readl port=0x%04x val=0x%08x\n", addr, val); +#endif + return val; +} + +static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PIIX4PMState *s = opaque; +#ifdef DEBUG + printf("SMI cmd val=0x%02x\n", val); +#endif + switch(val) { + case 0xf0: /* ACPI disable */ + s->pmcntrl &= ~SCI_EN; + break; + case 0xf1: /* ACPI enable */ + s->pmcntrl |= SCI_EN; + break; + } +} + +static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) +{ +#if defined(DEBUG) + printf("ACPI: DBG: 0x%08x\n", val); +#endif +} + +/* XXX: we still add it to the PIIX3 and we count on the fact that + OSes are smart enough to accept this strange configuration */ +void piix4_pm_init(PCIBus *bus) +{ + PIIX4PMState *s; + uint8_t *pci_conf; + uint32_t pm_io_base; + + s = (PIIX4PMState *)pci_register_device(bus, + "PM", sizeof(PIIX4PMState), + ((PCIDevice *)piix3_state)->devfn + 3, + NULL, NULL); + pci_conf = s->dev.config; + pci_conf[0x00] = 0x86; + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x13; + pci_conf[0x03] = 0x70; + pci_conf[0x08] = 0x00; // revision number + pci_conf[0x09] = 0x00; + pci_conf[0x0a] = 0x80; // other bridge device + pci_conf[0x0b] = 0x06; // bridge device + pci_conf[0x0e] = 0x00; // header_type + pci_conf[0x3d] = 0x01; // interrupt pin 1 + pci_conf[0x60] = 0x10; // release number + + pm_io_base = PM_IO_BASE; + pci_conf[0x40] = pm_io_base | 1; + pci_conf[0x41] = pm_io_base >> 8; + register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); + register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); + register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); + register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); + + register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s); + register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); + + s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); + piix4_pm_state = s; +} + +/* ACPI tables */ +/* XXX: move them in the Bochs BIOS ? */ + +/*************************************************/ + +/* Table structure from Linux kernel (the ACPI tables are under the + BSD license) */ + +#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ + uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\ + uint32_t length; /* Length of table, in bytes, including header */\ + uint8_t revision; /* ACPI Specification minor version # */\ + uint8_t checksum; /* To make sum of entire table == 0 */\ + uint8_t oem_id [6]; /* OEM identification */\ + uint8_t oem_table_id [8]; /* OEM table identification */\ + uint32_t oem_revision; /* OEM revision number */\ + uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\ + uint32_t asl_compiler_revision; /* ASL compiler revision number */ + + +struct acpi_table_header /* ACPI common table header */ +{ + ACPI_TABLE_HEADER_DEF +}; + +struct rsdp_descriptor /* Root System Descriptor Pointer */ +{ + uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */ + uint8_t checksum; /* To make sum of struct == 0 */ + uint8_t oem_id [6]; /* OEM identification */ + uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ + uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */ + uint32_t length; /* XSDT Length in bytes including hdr */ + uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */ + uint8_t extended_checksum; /* Checksum of entire table */ + uint8_t reserved [3]; /* Reserved field must be 0 */ +}; + +/* + * ACPI 1.0 Root System Description Table (RSDT) + */ +struct rsdt_descriptor_rev1 +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + uint32_t table_offset_entry [2]; /* Array of pointers to other */ + /* ACPI tables */ +}; + +/* + * ACPI 1.0 Firmware ACPI Control Structure (FACS) + */ +struct facs_descriptor_rev1 +{ + uint8_t signature[4]; /* ACPI Signature */ + uint32_t length; /* Length of structure, in bytes */ + uint32_t hardware_signature; /* Hardware configuration signature */ + uint32_t firmware_waking_vector; /* ACPI OS waking vector */ + uint32_t global_lock; /* Global Lock */ + uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */ + uint32_t reserved1 : 31; /* Must be 0 */ + uint8_t resverved3 [40]; /* Reserved - must be zero */ +}; + + +/* + * ACPI 1.0 Fixed ACPI Description Table (FADT) + */ +struct fadt_descriptor_rev1 +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + uint32_t firmware_ctrl; /* Physical address of FACS */ + uint32_t dsdt; /* Physical address of DSDT */ + uint8_t model; /* System Interrupt Model */ + uint8_t reserved1; /* Reserved */ + uint16_t sci_int; /* System vector of SCI interrupt */ + uint32_t smi_cmd; /* Port address of SMI command port */ + uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */ + uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */ + uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ + uint8_t reserved2; /* Reserved - must be zero */ + uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ + uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ + uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ + uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ + uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ + uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ + uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ + uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ + uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ + uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ + uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ + uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ + uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ + uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ + uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */ + uint8_t reserved3; /* Reserved */ + uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ + uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ + uint16_t flush_size; /* Size of area read to flush caches */ + uint16_t flush_stride; /* Stride used in flushing caches */ + uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */ + uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */ + uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ + uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ + uint8_t century; /* Index to century in RTC CMOS RAM */ + uint8_t reserved4; /* Reserved */ + uint8_t reserved4a; /* Reserved */ + uint8_t reserved4b; /* Reserved */ +#if 0 + uint32_t wb_invd : 1; /* The wbinvd instruction works properly */ + uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ + uint32_t proc_c1 : 1; /* All processors support C1 state */ + uint32_t plvl2_up : 1; /* C2 state works on MP system */ + uint32_t pwr_button : 1; /* Power button is handled as a generic feature */ + uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ + uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ + uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ + uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */ + uint32_t reserved5 : 23; /* Reserved - must be zero */ +#else + uint32_t flags; +#endif +}; + +/* + * MADT values and structures + */ + +/* Values for MADT PCATCompat */ + +#define DUAL_PIC 0 +#define MULTIPLE_APIC 1 + + +/* Master MADT */ + +struct multiple_apic_table +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + uint32_t local_apic_address; /* Physical address of local APIC */ +#if 0 + uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */ + uint32_t reserved1 : 31; +#else + uint32_t flags; +#endif +}; + + +/* Values for Type in APIC_HEADER_DEF */ + +#define APIC_PROCESSOR 0 +#define APIC_IO 1 +#define APIC_XRUPT_OVERRIDE 2 +#define APIC_NMI 3 +#define APIC_LOCAL_NMI 4 +#define APIC_ADDRESS_OVERRIDE 5 +#define APIC_IO_SAPIC 6 +#define APIC_LOCAL_SAPIC 7 +#define APIC_XRUPT_SOURCE 8 +#define APIC_RESERVED 9 /* 9 and greater are reserved */ + +/* + * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) + */ +#define APIC_HEADER_DEF /* Common APIC sub-structure header */\ + uint8_t type; \ + uint8_t length; + +/* Sub-structures for MADT */ + +struct madt_processor_apic +{ + APIC_HEADER_DEF + uint8_t processor_id; /* ACPI processor id */ + uint8_t local_apic_id; /* Processor's local APIC id */ +#if 0 + uint32_t processor_enabled: 1; /* Processor is usable if set */ + uint32_t reserved2 : 31; /* Reserved, must be zero */ +#else + uint32_t flags; +#endif +}; + +struct madt_io_apic +{ + APIC_HEADER_DEF + uint8_t io_apic_id; /* I/O APIC ID */ + uint8_t reserved; /* Reserved - must be zero */ + uint32_t address; /* APIC physical address */ + uint32_t interrupt; /* Global system interrupt where INTI + * lines start */ +}; + +#include "acpi-dsdt.hex" + +static int acpi_checksum(const uint8_t *data, int len) +{ + int sum, i; + sum = 0; + for(i = 0; i < len; i++) + sum += data[i]; + return (-sum) & 0xff; +} + +static void acpi_build_table_header(struct acpi_table_header *h, + char *sig, int len) +{ + memcpy(h->signature, sig, 4); + h->length = cpu_to_le32(len); + h->revision = 0; + memcpy(h->oem_id, "QEMU ", 6); + memcpy(h->oem_table_id, "QEMU", 4); + memcpy(h->oem_table_id + 4, sig, 4); + h->oem_revision = cpu_to_le32(1); + memcpy(h->asl_compiler_id, "QEMU", 4); + h->asl_compiler_revision = cpu_to_le32(1); + h->checksum = acpi_checksum((void *)h, len); +} + +#define ACPI_TABLES_BASE 0x000e8000 + +/* base_addr must be a multiple of 4KB */ +void acpi_bios_init(void) +{ + struct rsdp_descriptor *rsdp; + struct rsdt_descriptor_rev1 *rsdt; + struct fadt_descriptor_rev1 *fadt; + struct facs_descriptor_rev1 *facs; + struct multiple_apic_table *madt; + uint8_t *dsdt; + uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr; + uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size; + int i; + + /* compute PCI I/O addresses */ + pm_io_base = (piix4_pm_state->dev.config[0x40] | + (piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f; + + base_addr = ACPI_TABLES_BASE; + + /* reserve memory space for tables */ + addr = base_addr; + rsdp = (void *)(phys_ram_base + addr); + addr += sizeof(*rsdp); + + rsdt_addr = addr; + rsdt = (void *)(phys_ram_base + addr); + addr += sizeof(*rsdt); + + fadt_addr = addr; + fadt = (void *)(phys_ram_base + addr); + addr += sizeof(*fadt); + + /* XXX: FACS should be in RAM */ + addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */ + facs_addr = addr; + facs = (void *)(phys_ram_base + addr); + addr += sizeof(*facs); + + dsdt_addr = addr; + dsdt = (void *)(phys_ram_base + addr); + addr += sizeof(AmlCode); + + madt_addr = addr; + madt_size = sizeof(*madt) + + sizeof(struct madt_processor_apic) * smp_cpus + + sizeof(struct madt_io_apic); + madt = (void *)(phys_ram_base + addr); + addr += madt_size; + + acpi_tables_size = addr - base_addr; + + cpu_register_physical_memory(base_addr, acpi_tables_size, + base_addr | IO_MEM_ROM); + + /* RSDP */ + memset(rsdp, 0, sizeof(*rsdp)); + memcpy(rsdp->signature, "RSD PTR ", 8); + memcpy(rsdp->oem_id, "QEMU ", 6); + rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr); + rsdp->checksum = acpi_checksum((void *)rsdp, 20); + + /* RSDT */ + rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr); + rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr); + acpi_build_table_header((struct acpi_table_header *)rsdt, + "RSDT", sizeof(*rsdt)); + + /* FADT */ + memset(fadt, 0, sizeof(*fadt)); + fadt->firmware_ctrl = cpu_to_le32(facs_addr); + fadt->dsdt = cpu_to_le32(dsdt_addr); + fadt->model = 1; + fadt->reserved1 = 0; + fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]); + fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR); + fadt->acpi_enable = 0xf1; + fadt->acpi_disable = 0xf0; + fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base); + fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04); + fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08); + fadt->pm1_evt_len = 4; + fadt->pm1_cnt_len = 2; + fadt->pm_tmr_len = 4; + fadt->plvl2_lat = cpu_to_le16(50); + fadt->plvl3_lat = cpu_to_le16(50); + fadt->plvl3_lat = cpu_to_le16(50); + /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */ + fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6)); + acpi_build_table_header((struct acpi_table_header *)fadt, "FACP", + sizeof(*fadt)); + + /* FACS */ + memset(facs, 0, sizeof(*facs)); + memcpy(facs->signature, "FACS", 4); + facs->length = cpu_to_le32(sizeof(*facs)); + + /* DSDT */ + memcpy(dsdt, AmlCode, sizeof(AmlCode)); + + /* MADT */ + { + struct madt_processor_apic *apic; + struct madt_io_apic *io_apic; + + memset(madt, 0, madt_size); + madt->local_apic_address = cpu_to_le32(0xfee00000); + madt->flags = cpu_to_le32(1); + apic = (void *)(madt + 1); + for(i=0;itype = APIC_PROCESSOR; + apic->length = sizeof(*apic); + apic->processor_id = i; + apic->local_apic_id = i; + apic->flags = cpu_to_le32(1); + apic++; + } + io_apic = (void *)apic; + io_apic->type = APIC_IO; + io_apic->length = sizeof(*io_apic); + io_apic->io_apic_id = smp_cpus; + io_apic->address = cpu_to_le32(0xfec00000); + io_apic->interrupt = cpu_to_le32(0); + + acpi_build_table_header((struct acpi_table_header *)madt, + "APIC", madt_size); + } +} diff --git a/hw/pc.c b/hw/pc.c index 4add257dc..b9bfd83a5 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -836,10 +836,15 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, usb_attach(usb_root_ports[0], vm_usb_hub); } + if (pci_enabled && acpi_enabled) { + piix4_pm_init(pci_bus); + } /* must be done after all PCI devices are instanciated */ /* XXX: should be done in the Bochs BIOS */ if (pci_enabled) { pci_bios_init(); + if (acpi_enabled) + acpi_bios_init(); } } diff --git a/vl.c b/vl.c index c08b39d94..e828d316a 100644 --- a/vl.c +++ b/vl.c @@ -157,6 +157,7 @@ int vnc_display = -1; #else #define MAX_CPUS 1 #endif +int acpi_enabled = 1; /***********************************************************/ /* x86 ISA bus support */ @@ -4675,6 +4676,7 @@ void help(void) " translation (t=none or lba) (usually qemu can guess them)\n" "-L path set the directory for the BIOS and VGA BIOS\n" #ifdef USE_KQEMU + "-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n" "-no-kqemu disable KQEMU kernel module usage\n" #endif #ifdef USE_CODE_COPY @@ -4683,6 +4685,7 @@ void help(void) #ifdef TARGET_I386 "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" + "-no-acpi disable ACPI\n" #endif "-loadvm file start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" @@ -4770,6 +4773,7 @@ enum { QEMU_OPTION_usbdevice, QEMU_OPTION_smp, QEMU_OPTION_vnc, + QEMU_OPTION_no_acpi, }; typedef struct QEMUOption { @@ -4842,6 +4846,7 @@ const QEMUOption qemu_options[] = { /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, + { "no-acpi", 0, QEMU_OPTION_no_acpi }, { NULL }, }; @@ -5443,6 +5448,9 @@ int main(int argc, char **argv) exit(1); } break; + case QEMU_OPTION_no_acpi: + acpi_enabled = 0; + break; } } } diff --git a/vl.h b/vl.h index ddf8892c5..58a7877d1 100644 --- a/vl.h +++ b/vl.h @@ -840,6 +840,11 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); void pcspk_init(PITState *); int pcspk_audio_init(AudioState *); +/* acpi.c */ +extern int acpi_enabled; +void piix4_pm_init(PCIBus *bus); +void acpi_bios_init(void); + /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; -- cgit v1.2.3 From 6583391f0de86f6bec28ea13a0c16c9ee2fa6b8f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 May 2006 23:13:13 +0000 Subject: PCI irq mapping fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1903 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi-dsdt.dsl | 52 ++++++++++++++++++++++++++-------------------------- hw/acpi-dsdt.hex | 50 +++++++++++++++++++++++++------------------------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/hw/acpi-dsdt.dsl b/hw/acpi-dsdt.dsl index b94df01ba..8ccb757d8 100644 --- a/hw/acpi-dsdt.dsl +++ b/hw/acpi-dsdt.dsl @@ -63,40 +63,40 @@ DefinitionBlock ( table of the Bochs BIOS */ // PCI Slot 0 - Package() {0x0000ffff, 0, LNKA, 0}, - Package() {0x0000ffff, 1, LNKB, 0}, - Package() {0x0000ffff, 2, LNKC, 0}, - Package() {0x0000ffff, 3, LNKD, 0}, - - // PCI Slot 1 - Package() {0x0001ffff, 0, LNKB, 0}, - Package() {0x0001ffff, 1, LNKC, 0}, - Package() {0x0001ffff, 2, LNKD, 0}, - Package() {0x0001ffff, 3, LNKA, 0}, + Package() {0x0000ffff, 0, LNKD, 0}, + Package() {0x0000ffff, 1, LNKA, 0}, + Package() {0x0000ffff, 2, LNKB, 0}, + Package() {0x0000ffff, 3, LNKC, 0}, + // PCI Slot 1 + Package() {0x0001ffff, 0, LNKA, 0}, + Package() {0x0001ffff, 1, LNKB, 0}, + Package() {0x0001ffff, 2, LNKC, 0}, + Package() {0x0001ffff, 3, LNKD, 0}, + // PCI Slot 2 - Package() {0x0002ffff, 0, LNKC, 0}, - Package() {0x0002ffff, 1, LNKD, 0}, - Package() {0x0002ffff, 2, LNKA, 0}, - Package() {0x0002ffff, 3, LNKB, 0}, + Package() {0x0002ffff, 0, LNKB, 0}, + Package() {0x0002ffff, 1, LNKC, 0}, + Package() {0x0002ffff, 2, LNKD, 0}, + Package() {0x0002ffff, 3, LNKA, 0}, // PCI Slot 3 - Package() {0x0003ffff, 0, LNKD, 0}, - Package() {0x0003ffff, 1, LNKA, 0}, - Package() {0x0003ffff, 2, LNKB, 0}, - Package() {0x0003ffff, 3, LNKC, 0}, + Package() {0x0003ffff, 0, LNKC, 0}, + Package() {0x0003ffff, 1, LNKD, 0}, + Package() {0x0003ffff, 2, LNKA, 0}, + Package() {0x0003ffff, 3, LNKB, 0}, // PCI Slot 4 - Package() {0x0004ffff, 0, LNKA, 0}, - Package() {0x0004ffff, 1, LNKB, 0}, - Package() {0x0004ffff, 2, LNKC, 0}, - Package() {0x0004ffff, 3, LNKD, 0}, + Package() {0x0004ffff, 0, LNKD, 0}, + Package() {0x0004ffff, 1, LNKA, 0}, + Package() {0x0004ffff, 2, LNKB, 0}, + Package() {0x0004ffff, 3, LNKC, 0}, // PCI Slot 5 - Package() {0x0005ffff, 0, LNKB, 0}, - Package() {0x0005ffff, 1, LNKC, 0}, - Package() {0x0005ffff, 2, LNKD, 0}, - Package() {0x0005ffff, 3, LNKA, 0}, + Package() {0x0005ffff, 0, LNKA, 0}, + Package() {0x0005ffff, 1, LNKB, 0}, + Package() {0x0005ffff, 2, LNKC, 0}, + Package() {0x0005ffff, 3, LNKD, 0}, }) Method (_CRS, 0, NotSerialized) diff --git a/hw/acpi-dsdt.hex b/hw/acpi-dsdt.hex index d58bd6fe5..bc542fc58 100644 --- a/hw/acpi-dsdt.hex +++ b/hw/acpi-dsdt.hex @@ -5,7 +5,7 @@ * Copyright (C) 2000 - 2006 Intel Corporation * Supports ACPI Specification Revision 3.0a * - * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed May 3 22:49:16 2006 + * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Thu May 4 01:07:59 2006 * * C source code output * @@ -33,48 +33,48 @@ unsigned char AmlCode[] = 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */ 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */ 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */ - 0x00,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0B, /* 000000A8 ".LNKA..." */ + 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */ 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */ - 0x42,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "B......." */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000C0 "..LNKC.." */ + 0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */ 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */ - 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKD....." */ + 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */ 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */ - 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "B......." */ - 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x43,0x00, /* 000000E8 "...LNKC." */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */ + 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x44,0x00,0x12, /* 000000F8 "..LNKD.." */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */ 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */ - 0x03,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0D, /* 00000108 ".LNKA..." */ + 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */ 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */ - 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKC....." */ + 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */ 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */ - 0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "D......." */ - 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x41, /* 00000130 "....LNKA" */ + 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */ + 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */ - 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x42,0x00, /* 00000140 "...LNKB." */ + 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */ - 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000150 ".LNKD..." */ + 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */ 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */ - 0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKA....." */ + 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */ 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */ - 0x4B,0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KB......" */ + 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */ 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */ - 0x43,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "C......." */ - 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x41,0x00, /* 00000188 "...LNKA." */ + 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */ + 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */ - 0x01,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E, /* 00000198 ".LNKB..." */ + 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */ 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */ - 0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKC...." */ + 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */ 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */ - 0x4E,0x4B,0x44,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKD....." */ + 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */ 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */ - 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "B......." */ - 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x43,0x00, /* 000001D0 "...LNKC." */ + 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */ + 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x44,0x00,0x12, /* 000001E0 "..LNKD.." */ + 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */ 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */ - 0x03,0x4C,0x4E,0x4B,0x41,0x00,0x14,0x4C, /* 000001F0 ".LNKA..L" */ + 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */ 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */ 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */ 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */ -- cgit v1.2.3 From 7ef4da1c3a753888e2678388150f1b846b025168 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 5 May 2006 20:03:45 +0000 Subject: typo git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1904 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/acpi.c b/hw/acpi.c index 9053142f3..40fc3345f 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -234,7 +234,7 @@ void piix4_pm_init(PCIBus *bus) pci_conf[0x00] = 0x86; pci_conf[0x01] = 0x80; pci_conf[0x02] = 0x13; - pci_conf[0x03] = 0x70; + pci_conf[0x03] = 0x71; pci_conf[0x08] = 0x00; // revision number pci_conf[0x09] = 0x00; pci_conf[0x0a] = 0x80; // other bridge device -- cgit v1.2.3 From 67f3656039748a7765c9983aba49d774edb58bc1 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 5 May 2006 20:05:35 +0000 Subject: patch in bLength for hub descriptor (Lonnie Mendez) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1905 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index fd916128c..ec51ad929 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -152,7 +152,7 @@ static const uint8_t qemu_hub_config_descriptor[] = { static const uint8_t qemu_hub_hub_descriptor[] = { - 0x09, /* u8 bLength; */ + 0x00, /* u8 bLength; patched in later */ 0x29, /* u8 bDescriptorType; Hub-descriptor */ 0x00, /* u8 bNbrPorts; (patched later) */ 0x0a, /* u16 wHubCharacteristics; */ @@ -417,6 +417,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, } ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; + data[0] = ret; break; } default: -- cgit v1.2.3 From 294e863721c6bf0930585982363c92cbdea64e64 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 6 May 2006 14:23:06 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1906 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 9e4735016..01f33f7e7 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1215,7 +1215,7 @@ Use @code{info reg} to display all the CPU registers. Use @code{x/10i $eip} to display the code at the PC position. @item Use @code{set architecture i8086} to dump 16 bit code. Then use -@code{x/10i $cs*16+*eip} to dump the code at the PC position. +@code{x/10i $cs*16+$eip} to dump the code at the PC position. @end enumerate @node pcsys_os_specific -- cgit v1.2.3 From 64866c3d5c20fa5e7cc5838030e59965e55f7a85 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 May 2006 18:03:31 +0000 Subject: more keycodes - hexa keycodes - keycode completion git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1907 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/monitor.c b/monitor.c index 3c0fd916f..d9257ffb3 100644 --- a/monitor.c +++ b/monitor.c @@ -666,6 +666,8 @@ static const KeyDef key_defs[] = { { 0x09, "8" }, { 0x0a, "9" }, { 0x0b, "0" }, + { 0x0c, "minus" }, + { 0x0d, "equal" }, { 0x0e, "backspace" }, { 0x0f, "tab" }, @@ -715,6 +717,24 @@ static const KeyDef key_defs[] = { { 0x45, "num_lock" }, { 0x46, "scroll_lock" }, + { 0xb5, "kp_divide" }, + { 0x37, "kp_multiply" }, + { 0x4a, "kp_substract" }, + { 0x4e, "kp_add" }, + { 0x9c, "kp_enter" }, + { 0x53, "kp_decimal" }, + + { 0x52, "kp_0" }, + { 0x4f, "kp_1" }, + { 0x50, "kp_2" }, + { 0x51, "kp_3" }, + { 0x4b, "kp_4" }, + { 0x4c, "kp_5" }, + { 0x4d, "kp_6" }, + { 0x47, "kp_7" }, + { 0x48, "kp_8" }, + { 0x49, "kp_9" }, + { 0x56, "<" }, { 0x57, "f11" }, @@ -740,11 +760,18 @@ static const KeyDef key_defs[] = { static int get_keycode(const char *key) { const KeyDef *p; + char *endp; + int ret; for(p = key_defs; p->name != NULL; p++) { if (!strcmp(key, p->name)) return p->keycode; } + if (strstart(key, "0x", NULL)) { + ret = strtoul(key, &endp, 0); + if (*endp == '\0' && ret >= 0x01 && ret <= 0xff) + return ret; + } return -1; } @@ -2152,6 +2179,7 @@ void readline_find_completion(const char *cmdline) int nb_args, i, len; const char *ptype, *str; term_cmd_t *cmd; + const KeyDef *key; parse_cmdline(cmdline, &nb_args, args); #ifdef DEBUG_COMPLETION @@ -2213,6 +2241,11 @@ void readline_find_completion(const char *cmdline) for(cmd = info_cmds; cmd->name != NULL; cmd++) { cmd_completion(str, cmd->name); } + } else if (!strcmp(cmd->name, "sendkey")) { + completion_index = strlen(str); + for(key = key_defs; key->name != NULL; key++) { + cmd_completion(str, key->name); + } } break; default: -- cgit v1.2.3 From 699e4642a9df17591e7586c91921fc3d6b31616e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 May 2006 18:06:27 +0000 Subject: win32 fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1908 c046a42c-6fe2-441c-8c8c-71466251a162 --- loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader.c b/loader.c index b2d6423fe..3fa681dbb 100644 --- a/loader.c +++ b/loader.c @@ -200,7 +200,7 @@ int load_elf(const char *filename, int64_t virt_to_phys_addend, int fd, data_order, must_swab, ret; uint8_t e_ident[EI_NIDENT]; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) { perror(filename); return -1; -- cgit v1.2.3 From 064aae138b1b26d326603c5c46763e6bde4bf5f2 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 8 May 2006 00:51:44 +0000 Subject: Test if compiler works instead of checking if binary exists. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1909 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/configure b/configure index ae10b581c..aae84af9c 100755 --- a/configure +++ b/configure @@ -293,9 +293,16 @@ cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" -if [ ! -x "`which $cc`" ] ; then - echo "Compiler $cc could not be found" - exit +# check that the C compiler works. +cat > $TMPC </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 -- cgit v1.2.3 From 73540ca962d94c4bfc8fd178590172f0a9f81bfc Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 8 May 2006 13:38:46 +0000 Subject: alignment fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1910 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/acpi.c b/hw/acpi.c index 40fc3345f..3ffdfdddb 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -521,7 +521,8 @@ void acpi_bios_init(void) dsdt_addr = addr; dsdt = (void *)(phys_ram_base + addr); addr += sizeof(AmlCode); - + + addr = (addr + 7) & ~7; madt_addr = addr; madt_size = sizeof(*madt) + sizeof(struct madt_processor_apic) * smp_cpus + -- cgit v1.2.3 From 38f3e7c2f526fb70d7bc52ed62910fea506dc84f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 10 May 2006 19:21:58 +0000 Subject: suppressed unaligned accesses git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1911 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/if.c | 4 ++-- slirp/slirp.c | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/slirp/if.c b/slirp/if.c index 2ce9a6424..94132ca88 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -52,8 +52,8 @@ if_init() if_maxlinkhdr = 40; #endif #else - /* 14 for ethernet + 40 */ - if_maxlinkhdr = 14 + 40; + /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ + if_maxlinkhdr = 2 + 14 + 40; #endif if_mtu = 1500; if_mru = 1500; diff --git a/slirp/slirp.c b/slirp/slirp.c index e88745e8a..6ba753e73 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -610,11 +610,12 @@ void slirp_input(const uint8_t *pkt, int pkt_len) m = m_get(); if (!m) return; - m->m_len = pkt_len; - memcpy(m->m_data, pkt, pkt_len); + /* Note: we add to align the IP header */ + m->m_len = pkt_len + 2; + memcpy(m->m_data + 2, pkt, pkt_len); - m->m_data += ETH_HLEN; - m->m_len -= ETH_HLEN; + m->m_data += 2 + ETH_HLEN; + m->m_len -= 2 + ETH_HLEN; ip_input(m); break; -- cgit v1.2.3 From d3079cd241329456462e5b9d1bce7ddcf658fe35 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 10 May 2006 22:17:36 +0000 Subject: bgr32 pixel format support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1912 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 79 +++++++++++++++++++-------- hw/vga_template.h | 160 ++++++++++++++++++++++++++++-------------------------- sdl.c | 5 ++ vl.h | 1 + 4 files changed, 144 insertions(+), 101 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index a712790c7..b4eacc35b 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -808,6 +808,11 @@ static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsign return (r << 16) | (g << 8) | b; } +static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b) +{ + return (b << 16) | (g << 8) | r; +} + #define DEPTH 8 #include "vga_template.h" @@ -820,6 +825,10 @@ static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsign #define DEPTH 32 #include "vga_template.h" +#define BGR_FORMAT +#define DEPTH 32 +#include "vga_template.h" + static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) { unsigned int col; @@ -852,6 +861,13 @@ static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned return col; } +static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel32bgr(r, g, b); + return col; +} + /* return true if the palette was modified */ static int update_palette16(VGAState *s) { @@ -948,9 +964,11 @@ static int update_basic_params(VGAState *s) return full_update; } -static inline int get_depth_index(int depth) +#define NB_DEPTHS 5 + +static inline int get_depth_index(DisplayState *s) { - switch(depth) { + switch(s->depth) { default: case 8: return 0; @@ -959,29 +977,35 @@ static inline int get_depth_index(int depth) case 16: return 2; case 32: - return 3; + if (s->bgr) + return 4; + else + return 3; } } -static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = { +static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = { vga_draw_glyph8_8, vga_draw_glyph8_16, vga_draw_glyph8_16, vga_draw_glyph8_32, + vga_draw_glyph8_32, }; -static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = { +static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = { vga_draw_glyph16_8, vga_draw_glyph16_16, vga_draw_glyph16_16, vga_draw_glyph16_32, + vga_draw_glyph16_32, }; -static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = { +static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { vga_draw_glyph9_8, vga_draw_glyph9_16, vga_draw_glyph9_16, vga_draw_glyph9_32, + vga_draw_glyph9_32, }; static const uint8_t cursor_glyph[32 * 4] = { @@ -1103,7 +1127,7 @@ static void vga_draw_text(VGAState *s, int full_update) } cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; - depth_index = get_depth_index(s->ds->depth); + depth_index = get_depth_index(s->ds); if (cw == 16) vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; else @@ -1196,56 +1220,76 @@ enum { VGA_DRAW_LINE_NB, }; -static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = { +static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = { vga_draw_line2_8, vga_draw_line2_16, vga_draw_line2_16, vga_draw_line2_32, + vga_draw_line2_32, vga_draw_line2d2_8, vga_draw_line2d2_16, vga_draw_line2d2_16, vga_draw_line2d2_32, + vga_draw_line2d2_32, vga_draw_line4_8, vga_draw_line4_16, vga_draw_line4_16, vga_draw_line4_32, + vga_draw_line4_32, vga_draw_line4d2_8, vga_draw_line4d2_16, vga_draw_line4d2_16, vga_draw_line4d2_32, + vga_draw_line4d2_32, vga_draw_line8d2_8, vga_draw_line8d2_16, vga_draw_line8d2_16, vga_draw_line8d2_32, + vga_draw_line8d2_32, vga_draw_line8_8, vga_draw_line8_16, vga_draw_line8_16, vga_draw_line8_32, + vga_draw_line8_32, vga_draw_line15_8, vga_draw_line15_15, vga_draw_line15_16, vga_draw_line15_32, + vga_draw_line15_32bgr, vga_draw_line16_8, vga_draw_line16_15, vga_draw_line16_16, vga_draw_line16_32, + vga_draw_line16_32bgr, vga_draw_line24_8, vga_draw_line24_15, vga_draw_line24_16, vga_draw_line24_32, + vga_draw_line24_32bgr, vga_draw_line32_8, vga_draw_line32_15, vga_draw_line32_16, vga_draw_line32_32, + vga_draw_line32_32bgr, +}; + +typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b); + +static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = { + rgb_to_pixel8_dup, + rgb_to_pixel15_dup, + rgb_to_pixel16_dup, + rgb_to_pixel32_dup, + rgb_to_pixel32bgr_dup, }; static int vga_get_bpp(VGAState *s) @@ -1362,7 +1406,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) break; } } - vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)]; + vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; if (disp_width != s->last_width || height != s->last_height) { @@ -1492,21 +1536,8 @@ static void vga_update_display(void *opaque) if (s->ds->depth == 0) { /* nothing to do */ } else { - switch(s->ds->depth) { - case 8: - s->rgb_to_pixel = rgb_to_pixel8_dup; - break; - case 15: - s->rgb_to_pixel = rgb_to_pixel15_dup; - break; - default: - case 16: - s->rgb_to_pixel = rgb_to_pixel16_dup; - break; - case 32: - s->rgb_to_pixel = rgb_to_pixel32_dup; - break; - } + s->rgb_to_pixel = + rgb_to_pixel_dup_table[get_depth_index(s->ds)]; full_update = 0; if (!(s->ar_index & 0x20)) { diff --git a/hw/vga_template.h b/hw/vga_template.h index 909571ebb..4ea938e01 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -35,7 +35,13 @@ #error unsupport depth #endif -#if DEPTH != 15 +#ifdef BGR_FORMAT +#define PIXEL_NAME glue(DEPTH, bgr) +#else +#define PIXEL_NAME DEPTH +#endif /* BGR_FORMAT */ + +#if DEPTH != 15 && !defined(BGR_FORMAT) static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, uint32_t font_data, @@ -334,6 +340,72 @@ static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, } } +void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, + const uint8_t *src1, + int poffset, int w, + unsigned int color0, + unsigned int color1, + unsigned int color_xor) +{ + const uint8_t *plane0, *plane1; + int x, b0, b1; + uint8_t *d; + + d = d1; + plane0 = src1; + plane1 = src1 + poffset; + for(x = 0; x < w; x++) { + b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1; + b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1; +#if DEPTH == 8 + switch(b0 | (b1 << 1)) { + case 0: + break; + case 1: + d[0] ^= color_xor; + break; + case 2: + d[0] = color0; + break; + case 3: + d[0] = color1; + break; + } +#elif DEPTH == 16 + switch(b0 | (b1 << 1)) { + case 0: + break; + case 1: + ((uint16_t *)d)[0] ^= color_xor; + break; + case 2: + ((uint16_t *)d)[0] = color0; + break; + case 3: + ((uint16_t *)d)[0] = color1; + break; + } +#elif DEPTH == 32 + switch(b0 | (b1 << 1)) { + case 0: + break; + case 1: + ((uint32_t *)d)[0] ^= color_xor; + break; + case 2: + ((uint32_t *)d)[0] = color0; + break; + case 3: + ((uint32_t *)d)[0] = color1; + break; + } +#else +#error unsupported depth +#endif + d += BPP; + } +} + #endif /* DEPTH != 15 */ @@ -342,7 +414,7 @@ static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, /* * 15 bit color */ -static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { #if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) @@ -357,7 +429,7 @@ static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d, r = (v >> 7) & 0xf8; g = (v >> 2) & 0xf8; b = (v << 3) & 0xf8; - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); s += 2; d += BPP; } while (--w != 0); @@ -367,7 +439,7 @@ static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d, /* * 16 bit color */ -static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { #if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) @@ -382,7 +454,7 @@ static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d, r = (v >> 8) & 0xf8; g = (v >> 3) & 0xfc; b = (v << 3) & 0xf8; - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); s += 2; d += BPP; } while (--w != 0); @@ -392,7 +464,7 @@ static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d, /* * 24 bit color */ -static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { int w; @@ -409,7 +481,7 @@ static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d, g = s[1]; r = s[2]; #endif - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); s += 3; d += BPP; } while (--w != 0); @@ -418,7 +490,7 @@ static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d, /* * 32 bit color */ -static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { #if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) @@ -438,82 +510,16 @@ static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d, g = s[1]; r = s[2]; #endif - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); s += 4; d += BPP; } while (--w != 0); #endif } -#if DEPTH != 15 -void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, - const uint8_t *src1, - int poffset, int w, - unsigned int color0, - unsigned int color1, - unsigned int color_xor) -{ - const uint8_t *plane0, *plane1; - int x, b0, b1; - uint8_t *d; - - d = d1; - plane0 = src1; - plane1 = src1 + poffset; - for(x = 0; x < w; x++) { - b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1; - b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1; -#if DEPTH == 8 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - d[0] ^= color_xor; - break; - case 2: - d[0] = color0; - break; - case 3: - d[0] = color1; - break; - } -#elif DEPTH == 16 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - ((uint16_t *)d)[0] ^= color_xor; - break; - case 2: - ((uint16_t *)d)[0] = color0; - break; - case 3: - ((uint16_t *)d)[0] = color1; - break; - } -#elif DEPTH == 32 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - ((uint32_t *)d)[0] ^= color_xor; - break; - case 2: - ((uint32_t *)d)[0] = color0; - break; - case 3: - ((uint32_t *)d)[0] = color1; - break; - } -#else -#error unsupported depth -#endif - d += BPP; - } -} -#endif - #undef PUT_PIXEL2 #undef DEPTH #undef BPP #undef PIXEL_TYPE +#undef PIXEL_NAME +#undef BGR_FORMAT diff --git a/sdl.c b/sdl.c index 72a70808d..ec4f93c5e 100644 --- a/sdl.c +++ b/sdl.c @@ -81,6 +81,11 @@ static void sdl_resize(DisplayState *ds, int w, int h) ds->data = screen->pixels; ds->linesize = screen->pitch; ds->depth = screen->format->BitsPerPixel; + if (ds->depth == 32 && screen->format->Rshift == 0) { + ds->bgr = 1; + } else { + ds->bgr = 0; + } ds->width = w; ds->height = h; } diff --git a/vl.h b/vl.h index 58a7877d1..7d51ff576 100644 --- a/vl.h +++ b/vl.h @@ -677,6 +677,7 @@ struct DisplayState { uint8_t *data; int linesize; int depth; + int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ int width; int height; void *opaque; -- cgit v1.2.3 From 1fc2244d8779378e89184554c8f6f0bd3bfe8e0f Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 11 May 2006 21:15:08 +0000 Subject: mips bios loading fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1913 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 0cb11683a..f10430013 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -214,14 +214,10 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, run. */ bios_offset = ram_size + vga_ram_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE); ret = load_image(buf, phys_ram_base + bios_offset); if (ret == BIOS_SIZE) { cpu_register_physical_memory((uint32_t)(0x1fc00000), BIOS_SIZE, bios_offset | IO_MEM_ROM); - env->PC = 0xBFC00000; - if (!kernel_filename) - return; } else { /* not fatal */ fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", -- cgit v1.2.3 From 5627148a1980fcdca7201bd797b8692ee501c408 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 11 May 2006 21:54:44 +0000 Subject: BGR_FORMAT fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1914 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga_template.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vga_template.h b/hw/vga_template.h index 4ea938e01..e7e8cb853 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -493,7 +493,7 @@ static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d, static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { -#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) +#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT) memcpy(d, s, width * 4); #else int w; -- cgit v1.2.3 From 4aa4253115255d79fe510ba15a68dad8f4ba4499 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 13 May 2006 13:55:08 +0000 Subject: Allow parallel make. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1915 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 2a5425e6a..3a69a0494 100644 --- a/Makefile +++ b/Makefile @@ -17,10 +17,12 @@ else DOCS= endif -all: dyngen$(EXESUF) $(TOOLS) $(DOCS) - for d in $(TARGET_DIRS); do \ - $(MAKE) -C $$d $@ || exit 1 ; \ - done +subdir-%: dyngen$(EXESUF) + $(MAKE) -C $(subst subdir-,,$@) all + +recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) + +all: $(TOOLS) $(DOCS) recurse-all qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) -- cgit v1.2.3 From 502a53952d574717bdb626b651b16cadacab46f4 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 13 May 2006 16:11:23 +0000 Subject: Rearrange PCI host emulation code. Add ARM PCI emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1916 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 9 +- hw/acpi.c | 5 +- hw/apb_pci.c | 232 ++++++++ hw/grackle_pci.c | 156 ++++++ hw/ide.c | 4 +- hw/pc.c | 9 +- hw/pci.c | 1524 +++------------------------------------------------- hw/pci_host.h | 93 ++++ hw/piix_pci.c | 419 +++++++++++++++ hw/ppc_chrp.c | 14 +- hw/prep_pci.c | 167 ++++++ hw/sun4m.c | 5 + hw/sun4u.c | 2 +- hw/unin_pci.c | 261 +++++++++ hw/usb-uhci.c | 5 +- hw/usb.h | 2 +- hw/versatile_pci.c | 119 ++++ hw/versatilepb.c | 206 ++++++- vl.h | 55 +- 19 files changed, 1798 insertions(+), 1489 deletions(-) create mode 100644 hw/apb_pci.c create mode 100644 hw/grackle_pci.c create mode 100644 hw/pci_host.h create mode 100644 hw/piix_pci.c create mode 100644 hw/prep_pci.c create mode 100644 hw/unin_pci.c create mode 100644 hw/versatile_pci.c diff --git a/Makefile.target b/Makefile.target index f25153b84..1e8cc9ccf 100644 --- a/Makefile.target +++ b/Makefile.target @@ -307,7 +307,7 @@ SOUND_HW += fmopl.o adlib.o endif # USB layer -VL_OBJS+= usb.o usb-hub.o usb-uhci.o usb-linux.o usb-hid.o +VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o # PCI network cards VL_OBJS+= ne2000.o rtl8139.o @@ -316,13 +316,15 @@ 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 mixeng.o apic.o parallel.o acpi.o +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o +VL_OBJS+= usb-uhci.o DEFINES += -DHAS_AUDIO 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 mixeng.o +VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) @@ -331,7 +333,7 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o +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 @@ -342,6 +344,7 @@ 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 endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o diff --git a/hw/acpi.c b/hw/acpi.c index 3ffdfdddb..8fb054428 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -220,7 +220,7 @@ static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) /* XXX: we still add it to the PIIX3 and we count on the fact that OSes are smart enough to accept this strange configuration */ -void piix4_pm_init(PCIBus *bus) +void piix4_pm_init(PCIBus *bus, int devfn) { PIIX4PMState *s; uint8_t *pci_conf; @@ -228,8 +228,7 @@ void piix4_pm_init(PCIBus *bus) s = (PIIX4PMState *)pci_register_device(bus, "PM", sizeof(PIIX4PMState), - ((PCIDevice *)piix3_state)->devfn + 3, - NULL, NULL); + devfn, NULL, NULL); pci_conf = s->dev.config; pci_conf[0x00] = 0x86; pci_conf[0x01] = 0x80; diff --git a/hw/apb_pci.c b/hw/apb_pci.c new file mode 100644 index 000000000..02e9824b3 --- /dev/null +++ b/hw/apb_pci.c @@ -0,0 +1,232 @@ +/* + * QEMU Ultrasparc APB PCI host + * + * 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" +typedef target_phys_addr_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState APBState; + +static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + APBState *s = opaque; + int i; + + for (i = 11; i < 32; i++) { + if ((val & (1 << i)) != 0) + break; + } + s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11); +} + +static uint32_t pci_apb_config_readl (void *opaque, + target_phys_addr_t addr) +{ + APBState *s = opaque; + uint32_t val; + int devfn; + + devfn = (s->config_reg >> 8) & 0xFF; + val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); + return val; +} + +static CPUWriteMemoryFunc *pci_apb_config_write[] = { + &pci_apb_config_writel, + &pci_apb_config_writel, + &pci_apb_config_writel, +}; + +static CPUReadMemoryFunc *pci_apb_config_read[] = { + &pci_apb_config_readl, + &pci_apb_config_readl, + &pci_apb_config_readl, +}; + +static void apb_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + //PCIBus *s = opaque; + + switch (addr & 0x3f) { + case 0x00: // Control/Status + case 0x10: // AFSR + case 0x18: // AFAR + case 0x20: // Diagnostic + case 0x28: // Target address space + // XXX + default: + break; + } +} + +static uint32_t apb_config_readl (void *opaque, + target_phys_addr_t addr) +{ + //PCIBus *s = opaque; + uint32_t val; + + switch (addr & 0x3f) { + case 0x00: // Control/Status + case 0x10: // AFSR + case 0x18: // AFAR + case 0x20: // Diagnostic + case 0x28: // Target address space + // XXX + default: + val = 0; + break; + } + return val; +} + +static CPUWriteMemoryFunc *apb_config_write[] = { + &apb_config_writel, + &apb_config_writel, + &apb_config_writel, +}; + +static CPUReadMemoryFunc *apb_config_read[] = { + &apb_config_readl, + &apb_config_readl, + &apb_config_readl, +}; + +static CPUWriteMemoryFunc *pci_apb_write[] = { + &pci_host_data_writeb, + &pci_host_data_writew, + &pci_host_data_writel, +}; + +static CPUReadMemoryFunc *pci_apb_read[] = { + &pci_host_data_readb, + &pci_host_data_readw, + &pci_host_data_readl, +}; + +static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outb(NULL, addr & 0xffff, val); +} + +static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outw(NULL, addr & 0xffff, val); +} + +static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outl(NULL, addr & 0xffff, val); +} + +static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inb(NULL, addr & 0xffff); + return val; +} + +static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inw(NULL, addr & 0xffff); + return val; +} + +static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inl(NULL, addr & 0xffff); + return val; +} + +static CPUWriteMemoryFunc *pci_apb_iowrite[] = { + &pci_apb_iowriteb, + &pci_apb_iowritew, + &pci_apb_iowritel, +}; + +static CPUReadMemoryFunc *pci_apb_ioread[] = { + &pci_apb_ioreadb, + &pci_apb_ioreadw, + &pci_apb_ioreadl, +}; + +/* ??? This is probably wrong. */ +static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, + void *pic) +{ + APBState *s; + PCIDevice *d; + int pci_mem_config, pci_mem_data, apb_config, pci_ioport; + + s = qemu_mallocz(sizeof(APBState)); + /* Ultrasparc APB main bus */ + s->bus = pci_register_bus(pci_apb_set_irq, pic, 0); + + pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, + pci_apb_config_write, s); + apb_config = cpu_register_io_memory(0, apb_config_read, + apb_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_apb_read, + pci_apb_write, s); + pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, + pci_apb_iowrite, s); + + cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); + cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); + cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); + cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom + + d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice), + -1, NULL, NULL); + d->config[0x00] = 0x8e; // vendor_id : Sun + d->config[0x01] = 0x10; + d->config[0x02] = 0x00; // device_id + d->config[0x03] = 0xa0; + d->config[0x04] = 0x06; // command = bus master, pci mem + d->config[0x05] = 0x00; + d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error + d->config[0x07] = 0x03; // status = medium devsel + d->config[0x08] = 0x00; // revision + d->config[0x09] = 0x00; // programming i/f + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + return s->bus; +} + + diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c new file mode 100644 index 000000000..e3cbceb49 --- /dev/null +++ b/hw/grackle_pci.c @@ -0,0 +1,156 @@ +/* + * QEMU Grackle (heathrow PPC) PCI host + * + * 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" +typedef target_phys_addr_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState GrackleState; + +static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + GrackleState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + s->config_reg = val; +} + +static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) +{ + GrackleState *s = opaque; + uint32_t val; + + val = s->config_reg; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *pci_grackle_config_write[] = { + &pci_grackle_config_writel, + &pci_grackle_config_writel, + &pci_grackle_config_writel, +}; + +static CPUReadMemoryFunc *pci_grackle_config_read[] = { + &pci_grackle_config_readl, + &pci_grackle_config_readl, + &pci_grackle_config_readl, +}; + +static CPUWriteMemoryFunc *pci_grackle_write[] = { + &pci_host_data_writeb, + &pci_host_data_writew, + &pci_host_data_writel, +}; + +static CPUReadMemoryFunc *pci_grackle_read[] = { + &pci_host_data_readb, + &pci_host_data_readw, + &pci_host_data_readl, +}; + +/* XXX: we do not simulate the hardware - we rely on the BIOS to + set correctly for irq line field */ +static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_grackle_init(uint32_t base, void *pic) +{ + GrackleState *s; + PCIDevice *d; + int pci_mem_config, pci_mem_data; + + s = qemu_mallocz(sizeof(GrackleState)); + s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0); + + pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, + pci_grackle_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, + pci_grackle_write, s); + cpu_register_physical_memory(base, 0x1000, pci_mem_config); + cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); + d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice), + 0, NULL, NULL); + d->config[0x00] = 0x57; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x02; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x09] = 0x01; + d->config[0x0a] = 0x00; // class_sub = host + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x00; // header_type + + d->config[0x18] = 0x00; // primary_bus + d->config[0x19] = 0x01; // secondary_bus + d->config[0x1a] = 0x00; // subordinate_bus + d->config[0x1c] = 0x00; + d->config[0x1d] = 0x00; + + d->config[0x20] = 0x00; // memory_base + d->config[0x21] = 0x00; + d->config[0x22] = 0x01; // memory_limit + d->config[0x23] = 0x00; + + d->config[0x24] = 0x00; // prefetchable_memory_base + d->config[0x25] = 0x00; + d->config[0x26] = 0x00; // prefetchable_memory_limit + d->config[0x27] = 0x00; + +#if 0 + /* PCI2PCI bridge same values as PearPC - check this */ + d->config[0x00] = 0x11; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x26; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x02; // revision + d->config[0x0a] = 0x04; // class_sub = pci2pci + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x01; // header_type + + d->config[0x18] = 0x0; // primary_bus + d->config[0x19] = 0x1; // secondary_bus + d->config[0x1a] = 0x1; // subordinate_bus + d->config[0x1c] = 0x10; // io_base + d->config[0x1d] = 0x20; // io_limit + + d->config[0x20] = 0x80; // memory_base + d->config[0x21] = 0x80; + d->config[0x22] = 0x90; // memory_limit + d->config[0x23] = 0x80; + + d->config[0x24] = 0x00; // prefetchable_memory_base + d->config[0x25] = 0x84; + d->config[0x26] = 0x00; // prefetchable_memory_limit + d->config[0x27] = 0x85; +#endif + return s->bus; +} + diff --git a/hw/ide.c b/hw/ide.c index 64b026d7f..ed6357362 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2490,7 +2490,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, /* hd_table must contain 4 block drivers */ /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ -void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) { PCIIDEState *d; uint8_t *pci_conf; @@ -2498,7 +2498,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table) /* register a function 1 of PIIX3 */ d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", sizeof(PCIIDEState), - ((PCIDevice *)piix3_state)->devfn + 1, + devfn, NULL, NULL); d->type = IDE_TYPE_PIIX3; diff --git a/hw/pc.c b/hw/pc.c index b9bfd83a5..642af5e2b 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -611,6 +611,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, unsigned long bios_offset, vga_bios_offset; int bios_size, isa_bios_size; PCIBus *pci_bus; + int piix3_devfn; CPUState *env; NICInfo *nd; @@ -741,7 +742,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled) { pci_bus = i440fx_init(); - piix3_init(pci_bus); + piix3_devfn = piix3_init(pci_bus); } else { pci_bus = NULL; } @@ -813,7 +814,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } if (pci_enabled) { - pci_piix3_ide_init(pci_bus, bs_table); + pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1); } else { for(i = 0; i < 2; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], @@ -832,12 +833,12 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, cmos_init(ram_size, boot_device, bs_table); if (pci_enabled && usb_enabled) { - usb_uhci_init(pci_bus, usb_root_ports); + usb_uhci_init(pci_bus, usb_root_ports, piix3_devfn + 2); usb_attach(usb_root_ports[0], vm_usb_hub); } if (pci_enabled && acpi_enabled) { - piix4_pm_init(pci_bus); + piix4_pm_init(pci_bus, piix3_devfn + 3); } /* must be done after all PCI devices are instanciated */ /* XXX: should be done in the Bochs BIOS */ diff --git a/hw/pci.c b/hw/pci.c index 30342d44e..a287648da 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -25,25 +25,10 @@ //#define DEBUG_PCI -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -/* just used for simpler irq handling. */ -#define PCI_DEVICES_MAX 64 -#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) - struct PCIBus { int bus_num; int devfn_min; - void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level); + pci_set_irq_fn set_irq; uint32_t config_reg; /* XXX: suppress */ /* low level pic */ SetIRQFunc *low_set_irq; @@ -53,17 +38,24 @@ struct PCIBus { target_phys_addr_t pci_mem_base; static int pci_irq_index; -static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; static PCIBus *first_bus; -static PCIBus *pci_register_bus(void) +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min) { PCIBus *bus; bus = qemu_mallocz(sizeof(PCIBus)); + bus->set_irq = set_irq; + bus->irq_opaque = pic; + bus->devfn_min = devfn_min; first_bus = bus; return bus; } +int pci_bus_num(PCIBus *s) +{ + return s->bus_num; +} + void generic_pci_save(QEMUFile* f, void *opaque) { PCIDevice* s=(PCIDevice*)opaque; @@ -141,16 +133,9 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); } -static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val) -{ - PCIBus *s = opaque; - s->config_reg = val; -} - -static uint32_t pci_addr_readl(void* opaque, uint32_t addr) +target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr) { - PCIBus *s = opaque; - return s->config_reg; + return addr + pci_mem_base; } static void pci_update_mappings(PCIDevice *d) @@ -218,7 +203,7 @@ static void pci_update_mappings(PCIDevice *d) isa_unassign_ioport(r->addr, r->size); } } else { - cpu_register_physical_memory(r->addr + pci_mem_base, + cpu_register_physical_memory(pci_to_cpu_addr(r->addr), r->size, IO_MEM_UNASSIGNED); } @@ -346,8 +331,7 @@ void pci_default_write_config(PCIDevice *d, } } -static void pci_data_write(void *opaque, uint32_t addr, - uint32_t val, int len) +void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) { PCIBus *s = opaque; PCIDevice *pci_dev; @@ -355,18 +339,15 @@ static void pci_data_write(void *opaque, uint32_t addr, #if defined(DEBUG_PCI) && 0 printf("pci_data_write: addr=%08x val=%08x len=%d\n", - s->config_reg, val, len); + addr, val, len); #endif - if (!(s->config_reg & (1 << 31))) { - return; - } - bus_num = (s->config_reg >> 16) & 0xff; + bus_num = (addr >> 16) & 0xff; if (bus_num != 0) return; - pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; + pci_dev = s->devices[(addr >> 8) & 0xff]; if (!pci_dev) return; - config_addr = (s->config_reg & 0xfc) | (addr & 3); + config_addr = addr & 0xff; #if defined(DEBUG_PCI) printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len); @@ -374,20 +355,17 @@ static void pci_data_write(void *opaque, uint32_t addr, pci_dev->config_write(pci_dev, config_addr, val, len); } -static uint32_t pci_data_read(void *opaque, uint32_t addr, - int len) +uint32_t pci_data_read(void *opaque, uint32_t addr, int len) { PCIBus *s = opaque; PCIDevice *pci_dev; int config_addr, bus_num; uint32_t val; - if (!(s->config_reg & (1 << 31))) - goto fail; - bus_num = (s->config_reg >> 16) & 0xff; + bus_num = (addr >> 16) & 0xff; if (bus_num != 0) goto fail; - pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; + pci_dev = s->devices[(addr >> 8) & 0xff]; if (!pci_dev) { fail: switch(len) { @@ -404,7 +382,7 @@ static uint32_t pci_data_read(void *opaque, uint32_t addr, } goto the_end; } - config_addr = (s->config_reg & 0xfc) | (addr & 3); + config_addr = addr & 0xff; val = pci_dev->config_read(pci_dev, config_addr, len); #if defined(DEBUG_PCI) printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n", @@ -413,1431 +391,87 @@ static uint32_t pci_data_read(void *opaque, uint32_t addr, the_end: #if defined(DEBUG_PCI) && 0 printf("pci_data_read: addr=%08x val=%08x len=%d\n", - s->config_reg, val, len); + addr, val, len); #endif return val; } -static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 1); -} - -static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 2); -} - -static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 4); -} - -static uint32_t pci_data_readb(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 1); -} - -static uint32_t pci_data_readw(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 2); -} - -static uint32_t pci_data_readl(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 4); -} - -/* i440FX PCI bridge */ - -static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level); +/***********************************************************/ +/* generic PCI irq support */ -PCIBus *i440fx_init(void) +/* 0 <= irq_num <= 3. level must be 0 or 1 */ +void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) { - PCIBus *s; - PCIDevice *d; - - s = pci_register_bus(); - s->set_irq = piix3_set_irq; - - register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); - register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); - - register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); - register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); - register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); - register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); - register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); - register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); - - d = pci_register_device(s, "i440FX", sizeof(PCIDevice), 0, - NULL, NULL); - - d->config[0x00] = 0x86; // vendor_id - d->config[0x01] = 0x80; - d->config[0x02] = 0x37; // device_id - d->config[0x03] = 0x12; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x00; // class_sub = host2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x00; // header_type - return s; + PCIBus *bus = pci_dev->bus; + bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level); } -/* PIIX3 PCI to ISA bridge */ - -typedef struct PIIX3State { - PCIDevice dev; -} PIIX3State; - -PIIX3State *piix3_state; +/***********************************************************/ +/* monitor info on PCI */ -/* return the global irq number corresponding to a given device irq - pin. We could also use the bus number to have a more precise - mapping. */ -static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +static void pci_info_device(PCIDevice *d) { - int slot_addend; - slot_addend = (pci_dev->devfn >> 3) - 1; - return (irq_num + slot_addend) & 3; -} + int i, class; + PCIIORegion *r; -static inline int get_pci_irq_level(int irq_num) -{ - int pic_level; -#if (PCI_IRQ_WORDS == 2) - pic_level = ((pci_irq_levels[irq_num][0] | - pci_irq_levels[irq_num][1]) != 0); -#else - { - int i; - pic_level = 0; - for(i = 0; i < PCI_IRQ_WORDS; i++) { - if (pci_irq_levels[irq_num][i]) { - pic_level = 1; - break; - } - } + term_printf(" Bus %2d, device %3d, function %d:\n", + d->bus->bus_num, d->devfn >> 3, d->devfn & 7); + class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); + term_printf(" "); + switch(class) { + case 0x0101: + term_printf("IDE controller"); + break; + case 0x0200: + term_printf("Ethernet controller"); + break; + case 0x0300: + term_printf("VGA controller"); + break; + default: + term_printf("Class %04x", class); + break; } -#endif - return pic_level; -} - -static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level) -{ - int irq_index, shift, pic_irq, pic_level; - uint32_t *p; - - irq_num = pci_slot_get_pirq(pci_dev, irq_num); - irq_index = pci_dev->irq_index; - p = &pci_irq_levels[irq_num][irq_index >> 5]; - shift = (irq_index & 0x1f); - *p = (*p & ~(1 << shift)) | (level << shift); + term_printf(": PCI device %04x:%04x\n", + le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), + le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID)))); - /* now we change the pic irq level according to the piix irq mappings */ - /* XXX: optimize */ - pic_irq = piix3_state->dev.config[0x60 + irq_num]; - if (pic_irq < 16) { - /* the pic level is the logical OR of all the PCI irqs mapped - to it */ - pic_level = 0; - if (pic_irq == piix3_state->dev.config[0x60]) - pic_level |= get_pci_irq_level(0); - if (pic_irq == piix3_state->dev.config[0x61]) - pic_level |= get_pci_irq_level(1); - if (pic_irq == piix3_state->dev.config[0x62]) - pic_level |= get_pci_irq_level(2); - if (pic_irq == piix3_state->dev.config[0x63]) - pic_level |= get_pci_irq_level(3); - pic_set_irq(pic_irq, pic_level); + if (d->config[PCI_INTERRUPT_PIN] != 0) { + term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); } -} - -static void piix3_reset(PIIX3State *d) -{ - uint8_t *pci_conf = d->dev.config; - - pci_conf[0x04] = 0x07; // master, memory and I/O - pci_conf[0x05] = 0x00; - pci_conf[0x06] = 0x00; - pci_conf[0x07] = 0x02; // PCI_status_devsel_medium - pci_conf[0x4c] = 0x4d; - pci_conf[0x4e] = 0x03; - pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x80; - pci_conf[0x69] = 0x02; - pci_conf[0x70] = 0x80; - pci_conf[0x76] = 0x0c; - pci_conf[0x77] = 0x0c; - pci_conf[0x78] = 0x02; - pci_conf[0x79] = 0x00; - pci_conf[0x80] = 0x00; - pci_conf[0x82] = 0x00; - pci_conf[0xa0] = 0x08; - pci_conf[0xa0] = 0x08; - pci_conf[0xa2] = 0x00; - pci_conf[0xa3] = 0x00; - pci_conf[0xa4] = 0x00; - pci_conf[0xa5] = 0x00; - pci_conf[0xa6] = 0x00; - pci_conf[0xa7] = 0x00; - pci_conf[0xa8] = 0x0f; - pci_conf[0xaa] = 0x00; - pci_conf[0xab] = 0x00; - pci_conf[0xac] = 0x00; - pci_conf[0xae] = 0x00; -} - -void piix3_init(PCIBus *bus) -{ - PIIX3State *d; - uint8_t *pci_conf; - - d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State), - -1, NULL, NULL); - register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); - - piix3_state = d; - pci_conf = d->dev.config; - - pci_conf[0x00] = 0x86; // Intel - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) - pci_conf[0x03] = 0x70; - pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA - pci_conf[0x0b] = 0x06; // class_base = PCI_bridge - pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic - - piix3_reset(d); -} - -/* PREP pci init */ - -static inline void set_config(PCIBus *s, target_phys_addr_t addr) -{ - int devfn, i; - - for(i = 0; i < 11; i++) { - if ((addr & (1 << (11 + i))) != 0) - break; + for(i = 0;i < PCI_NUM_REGIONS; i++) { + r = &d->io_regions[i]; + if (r->size != 0) { + term_printf(" BAR%d: ", i); + if (r->type & PCI_ADDRESS_SPACE_IO) { + term_printf("I/O at 0x%04x [0x%04x].\n", + r->addr, r->addr + r->size - 1); + } else { + term_printf("32 bit memory at 0x%08x [0x%08x].\n", + r->addr, r->addr + r->size - 1); + } + } } - devfn = ((addr >> 8) & 7) | (i << 3); - s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8); -} - -static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); - pci_data_write(s, addr, val, 1); -} - -static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr, val, 2); -} - -static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr, val, 4); -} - -static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 1); - return val; -} - -static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { - &PPC_PCIIO_writeb, - &PPC_PCIIO_writew, - &PPC_PCIIO_writel, -}; - -static CPUReadMemoryFunc *PPC_PCIIO_read[] = { - &PPC_PCIIO_readb, - &PPC_PCIIO_readw, - &PPC_PCIIO_readl, -}; - -static void prep_set_irq(PCIDevice *d, int irq_num, int level) -{ - /* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ - pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_prep_init(void) -{ - PCIBus *s; - PCIDevice *d; - int PPC_io_memory; - - s = pci_register_bus(); - s->set_irq = prep_set_irq; - - register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); - register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); - - register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); - register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); - register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); - register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); - register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); - register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); - - PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, - PPC_PCIIO_write, s); - cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); - - /* PCI host bridge */ - d = pci_register_device(s, "PREP Host Bridge - Motorola Raven", - sizeof(PCIDevice), 0, NULL, NULL); - d->config[0x00] = 0x57; // vendor_id : Motorola - d->config[0x01] = 0x10; - d->config[0x02] = 0x01; // device_id : Raven - d->config[0x03] = 0x48; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer - - return s; -} - - -/* Grackle PCI host */ -static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - s->config_reg = val; -} - -static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = s->config_reg; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *pci_grackle_config_write[] = { - &pci_grackle_config_writel, - &pci_grackle_config_writel, - &pci_grackle_config_writel, -}; - -static CPUReadMemoryFunc *pci_grackle_config_read[] = { - &pci_grackle_config_readl, - &pci_grackle_config_readl, - &pci_grackle_config_readl, -}; - -static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr, val, 1); -} - -static void pci_grackle_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr, val, 2); -} - -static void pci_grackle_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr, val, 4); -} - -static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - val = pci_data_read(s, addr, 1); - return val; -} - -static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - val = pci_data_read(s, addr, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *pci_grackle_write[] = { - &pci_grackle_writeb, - &pci_grackle_writew, - &pci_grackle_writel, -}; - -static CPUReadMemoryFunc *pci_grackle_read[] = { - &pci_grackle_readb, - &pci_grackle_readw, - &pci_grackle_readl, -}; - -void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque) -{ - bus->low_set_irq = set_irq; - bus->irq_opaque = irq_opaque; -} - -/* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ -static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level) -{ - PCIBus *s = d->bus; - s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level); } -PCIBus *pci_grackle_init(uint32_t base) +void pci_for_each_device(void (*fn)(PCIDevice *d)) { - PCIBus *s; + PCIBus *bus = first_bus; PCIDevice *d; - int pci_mem_config, pci_mem_data; - - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, - pci_grackle_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, - pci_grackle_write, s); - cpu_register_physical_memory(base, 0x1000, pci_mem_config); - cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); - d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice), - 0, NULL, NULL); - d->config[0x00] = 0x57; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x02; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x01; - d->config[0x0a] = 0x00; // class_sub = host - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x00; // header_type - - d->config[0x18] = 0x00; // primary_bus - d->config[0x19] = 0x01; // secondary_bus - d->config[0x1a] = 0x00; // subordinate_bus - d->config[0x1c] = 0x00; - d->config[0x1d] = 0x00; - - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x00; - d->config[0x22] = 0x01; // memory_limit - d->config[0x23] = 0x00; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x00; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x00; - -#if 0 - /* PCI2PCI bridge same values as PearPC - check this */ - d->config[0x00] = 0x11; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x04; // class_sub = pci2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x01; // header_type - - d->config[0x18] = 0x0; // primary_bus - d->config[0x19] = 0x1; // secondary_bus - d->config[0x1a] = 0x1; // subordinate_bus - d->config[0x1c] = 0x10; // io_base - d->config[0x1d] = 0x20; // io_limit - - d->config[0x20] = 0x80; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x90; // memory_limit - d->config[0x23] = 0x80; + int devfn; - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x84; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x85; -#endif - return s; -} - -/* Uninorth PCI host (for all Mac99 and newer machines */ -static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - int i; - -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; + if (bus) { + for(devfn = 0; devfn < 256; devfn++) { + d = bus->devices[devfn]; + if (d) + fn(d); + } } -#if 0 - s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); -#else - s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); -#endif } -static uint32_t pci_unin_main_config_readl (void *opaque, - target_phys_addr_t addr) +void pci_info(void) { - PCIBus *s = opaque; - uint32_t val; - int devfn; - - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { - &pci_unin_main_config_writel, - &pci_unin_main_config_writel, - &pci_unin_main_config_writel, -}; - -static CPUReadMemoryFunc *pci_unin_main_config_read[] = { - &pci_unin_main_config_readl, - &pci_unin_main_config_readl, - &pci_unin_main_config_readl, -}; - -static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr & 7, val, 1); -} - -static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr & 7, val, 2); -} - -static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr & 7, val, 4); -} - -static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 1); - - return val; -} - -static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - - return val; -} - -static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_main_write[] = { - &pci_unin_main_writeb, - &pci_unin_main_writew, - &pci_unin_main_writel, -}; - -static CPUReadMemoryFunc *pci_unin_main_read[] = { - &pci_unin_main_readb, - &pci_unin_main_readw, - &pci_unin_main_readl, -}; - -#if 0 - -static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - s->config_reg = 0x80000000 | (val & ~0x00000001); -} - -static uint32_t pci_unin_config_readl (void *opaque, - target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = (s->config_reg | 0x00000001) & ~0x80000000; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_config_write[] = { - &pci_unin_config_writel, - &pci_unin_config_writel, - &pci_unin_config_writel, -}; - -static CPUReadMemoryFunc *pci_unin_config_read[] = { - &pci_unin_config_readl, - &pci_unin_config_readl, - &pci_unin_config_readl, -}; - -static void pci_unin_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr & 3, val, 1); -} - -static void pci_unin_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr & 3, val, 2); -} - -static void pci_unin_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr & 3, val, 4); -} - -static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 1); - - return val; -} - -static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - - return val; -} - -static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_write[] = { - &pci_unin_writeb, - &pci_unin_writew, - &pci_unin_writel, -}; - -static CPUReadMemoryFunc *pci_unin_read[] = { - &pci_unin_readb, - &pci_unin_readw, - &pci_unin_readl, -}; -#endif - -PCIBus *pci_pmac_init(void) -{ - PCIBus *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data; - - /* Use values found on a real PowerMac */ - /* Uninorth main bus */ - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, - pci_unin_main_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, - pci_unin_main_write, s); - cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); - s->devfn_min = 11 << 3; - d = pci_register_device(s, "Uni-north main", sizeof(PCIDevice), - 11 << 3, NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x1F; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer - -#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly - /* pci-to-pci bridge */ - d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, - NULL, NULL); - d->config[0x00] = 0x11; // vendor_id : TI - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x05; // revision - d->config[0x0A] = 0x04; // class_sub = pci2pci - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x20; // latency_timer - d->config[0x0E] = 0x01; // header_type - - d->config[0x18] = 0x01; // primary_bus - d->config[0x19] = 0x02; // secondary_bus - d->config[0x1A] = 0x02; // subordinate_bus - d->config[0x1B] = 0x20; // secondary_latency_timer - d->config[0x1C] = 0x11; // io_base - d->config[0x1D] = 0x01; // io_limit - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x00; // memory_limit - d->config[0x23] = 0x80; - d->config[0x24] = 0x01; // prefetchable_memory_base - d->config[0x25] = 0x80; - d->config[0x26] = 0xF1; // prefectchable_memory_limit - d->config[0x27] = 0x7F; - // d->config[0x34] = 0xdc // capabilities_pointer -#endif -#if 0 // XXX: not needed for now - /* Uninorth AGP bus */ - s = &pci_bridge[1]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, - pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, - pci_unin_write, s); - cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, - NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x20; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - // d->config[0x34] = 0x80; // capabilities_pointer -#endif - -#if 0 // XXX: not needed for now - /* Uninorth internal bus */ - s = &pci_bridge[2]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, - pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, - pci_unin_write, s); - cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north internal", sizeof(PCIDevice), - 3, 11 << 3, NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x1E; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer -#endif - return s; -} - -/* Ultrasparc APB PCI host */ -static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - int i; - - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; - } - s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); -} - -static uint32_t pci_apb_config_readl (void *opaque, - target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - int devfn; - - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_config_write[] = { - &pci_apb_config_writel, - &pci_apb_config_writel, - &pci_apb_config_writel, -}; - -static CPUReadMemoryFunc *pci_apb_config_read[] = { - &pci_apb_config_readl, - &pci_apb_config_readl, - &pci_apb_config_readl, -}; - -static void apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - //PCIBus *s = opaque; - - switch (addr & 0x3f) { - case 0x00: // Control/Status - case 0x10: // AFSR - case 0x18: // AFAR - case 0x20: // Diagnostic - case 0x28: // Target address space - // XXX - default: - break; - } -} - -static uint32_t apb_config_readl (void *opaque, - target_phys_addr_t addr) -{ - //PCIBus *s = opaque; - uint32_t val; - - switch (addr & 0x3f) { - case 0x00: // Control/Status - case 0x10: // AFSR - case 0x18: // AFAR - case 0x20: // Diagnostic - case 0x28: // Target address space - // XXX - default: - val = 0; - break; - } - return val; -} - -static CPUWriteMemoryFunc *apb_config_write[] = { - &apb_config_writel, - &apb_config_writel, - &apb_config_writel, -}; - -static CPUReadMemoryFunc *apb_config_read[] = { - &apb_config_readl, - &apb_config_readl, - &apb_config_readl, -}; - -static void pci_apb_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 1); -} - -static void pci_apb_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 2); -} - -static void pci_apb_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 4); -} - -static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 1); - return val; -} - -static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 2); - return val; -} - -static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_write[] = { - &pci_apb_writeb, - &pci_apb_writew, - &pci_apb_writel, -}; - -static CPUReadMemoryFunc *pci_apb_read[] = { - &pci_apb_readb, - &pci_apb_readw, - &pci_apb_readl, -}; - -static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outb(NULL, addr & 0xffff, val); -} - -static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outw(NULL, addr & 0xffff, val); -} - -static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outl(NULL, addr & 0xffff, val); -} - -static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inb(NULL, addr & 0xffff); - return val; -} - -static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inw(NULL, addr & 0xffff); - return val; -} - -static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inl(NULL, addr & 0xffff); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_iowrite[] = { - &pci_apb_iowriteb, - &pci_apb_iowritew, - &pci_apb_iowritel, -}; - -static CPUReadMemoryFunc *pci_apb_ioread[] = { - &pci_apb_ioreadb, - &pci_apb_ioreadw, - &pci_apb_ioreadl, -}; - -PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base) -{ - PCIBus *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data, apb_config, pci_ioport; - - /* Ultrasparc APB main bus */ - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, - pci_apb_config_write, s); - apb_config = cpu_register_io_memory(0, apb_config_read, - apb_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_apb_read, - pci_apb_write, s); - pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, - pci_apb_iowrite, s); - - cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); - cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); - cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); - cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom - - d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice), - -1, NULL, NULL); - d->config[0x00] = 0x8e; // vendor_id : Sun - d->config[0x01] = 0x10; - d->config[0x02] = 0x00; // device_id - d->config[0x03] = 0xa0; - d->config[0x04] = 0x06; // command = bus master, pci mem - d->config[0x05] = 0x00; - d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error - d->config[0x07] = 0x03; // status = medium devsel - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x00; // programming i/f - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - return s; -} - -/***********************************************************/ -/* generic PCI irq support */ - -/* 0 <= irq_num <= 3. level must be 0 or 1 */ -void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) -{ - PCIBus *bus = pci_dev->bus; - bus->set_irq(pci_dev, irq_num, level); -} - -/***********************************************************/ -/* monitor info on PCI */ - -static void pci_info_device(PCIDevice *d) -{ - int i, class; - PCIIORegion *r; - - term_printf(" Bus %2d, device %3d, function %d:\n", - d->bus->bus_num, d->devfn >> 3, d->devfn & 7); - class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); - term_printf(" "); - switch(class) { - case 0x0101: - term_printf("IDE controller"); - break; - case 0x0200: - term_printf("Ethernet controller"); - break; - case 0x0300: - term_printf("VGA controller"); - break; - default: - term_printf("Class %04x", class); - break; - } - term_printf(": PCI device %04x:%04x\n", - le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), - le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID)))); - - if (d->config[PCI_INTERRUPT_PIN] != 0) { - term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); - } - for(i = 0;i < PCI_NUM_REGIONS; i++) { - r = &d->io_regions[i]; - if (r->size != 0) { - term_printf(" BAR%d: ", i); - if (r->type & PCI_ADDRESS_SPACE_IO) { - term_printf("I/O at 0x%04x [0x%04x].\n", - r->addr, r->addr + r->size - 1); - } else { - term_printf("32 bit memory at 0x%08x [0x%08x].\n", - r->addr, r->addr + r->size - 1); - } - } - } -} - -void pci_info(void) -{ - PCIBus *bus = first_bus; - PCIDevice *d; - int devfn; - - if (bus) { - for(devfn = 0; devfn < 256; devfn++) { - d = bus->devices[devfn]; - if (d) - pci_info_device(d); - } - } -} - -/***********************************************************/ -/* XXX: the following should be moved to the PC BIOS */ - -static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) -{ - return cpu_inb(NULL, addr); -} - -static void isa_outb(uint32_t val, uint32_t addr) -{ - cpu_outb(NULL, addr, val); -} - -static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) -{ - return cpu_inw(NULL, addr); -} - -static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) -{ - cpu_outw(NULL, addr, val); -} - -static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) -{ - return cpu_inl(NULL, addr); -} - -static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) -{ - cpu_outl(NULL, addr, val); -} - -static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | addr; - pci_data_write(s, 0, val, 4); -} - -static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - pci_data_write(s, addr & 3, val, 2); -} - -static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - pci_data_write(s, addr & 3, val, 1); -} - -static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | addr; - return pci_data_read(s, 0, 4); -} - -static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - return pci_data_read(s, addr & 3, 2); -} - -static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - return pci_data_read(s, addr & 3, 1); -} - -static uint32_t pci_bios_io_addr; -static uint32_t pci_bios_mem_addr; -/* host irqs corresponding to PCI irqs A-D */ -static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; - -static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) -{ - PCIIORegion *r; - uint16_t cmd; - uint32_t ofs; - - if ( region_num == PCI_ROM_SLOT ) { - ofs = 0x30; - }else{ - ofs = 0x10 + region_num * 4; - } - - pci_config_writel(d, ofs, addr); - r = &d->io_regions[region_num]; - - /* enable memory mappings */ - cmd = pci_config_readw(d, PCI_COMMAND); - if ( region_num == PCI_ROM_SLOT ) - cmd |= 2; - else if (r->type & PCI_ADDRESS_SPACE_IO) - cmd |= 1; - else - cmd |= 2; - pci_config_writew(d, PCI_COMMAND, cmd); -} - -static void pci_bios_init_device(PCIDevice *d) -{ - int class; - PCIIORegion *r; - uint32_t *paddr; - int i, pin, pic_irq, vendor_id, device_id; - - class = pci_config_readw(d, PCI_CLASS_DEVICE); - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); - switch(class) { - case 0x0101: - if (vendor_id == 0x8086 && device_id == 0x7010) { - /* PIIX3 IDE */ - pci_config_writew(d, 0x40, 0x8000); // enable IDE0 - pci_config_writew(d, 0x42, 0x8000); // enable IDE1 - goto default_map; - } else { - /* IDE: we map it as in ISA mode */ - pci_set_io_region_addr(d, 0, 0x1f0); - pci_set_io_region_addr(d, 1, 0x3f4); - pci_set_io_region_addr(d, 2, 0x170); - pci_set_io_region_addr(d, 3, 0x374); - } - break; - case 0x0300: - if (vendor_id != 0x1234) - goto default_map; - /* VGA: map frame buffer to default Bochs VBE address */ - pci_set_io_region_addr(d, 0, 0xE0000000); - break; - case 0x0800: - /* PIC */ - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); - if (vendor_id == 0x1014) { - /* IBM */ - if (device_id == 0x0046 || device_id == 0xFFFF) { - /* MPIC & MPIC2 */ - pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); - } - } - break; - case 0xff00: - if (vendor_id == 0x0106b && - (device_id == 0x0017 || device_id == 0x0022)) { - /* macio bridge */ - pci_set_io_region_addr(d, 0, 0x80800000); - } - break; - default: - default_map: - /* default memory mappings */ - for(i = 0; i < PCI_NUM_REGIONS; i++) { - r = &d->io_regions[i]; - if (r->size) { - if (r->type & PCI_ADDRESS_SPACE_IO) - paddr = &pci_bios_io_addr; - else - paddr = &pci_bios_mem_addr; - *paddr = (*paddr + r->size - 1) & ~(r->size - 1); - pci_set_io_region_addr(d, i, *paddr); - *paddr += r->size; - } - } - break; - } - - /* map the interrupt */ - pin = pci_config_readb(d, PCI_INTERRUPT_PIN); - if (pin != 0) { - pin = pci_slot_get_pirq(d, pin - 1); - pic_irq = pci_irqs[pin]; - pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); - } -} - -/* - * This function initializes the PCI devices as a normal PCI BIOS - * would do. It is provided just in case the BIOS has no support for - * PCI. - */ -void pci_bios_init(void) -{ - PCIBus *bus; - PCIDevice *d; - int devfn, i, irq; - uint8_t elcr[2]; - - pci_bios_io_addr = 0xc000; - pci_bios_mem_addr = 0xf0000000; - - /* activate IRQ mappings */ - elcr[0] = 0x00; - elcr[1] = 0x00; - for(i = 0; i < 4; i++) { - irq = pci_irqs[i]; - /* set to trigger level */ - elcr[irq >> 3] |= (1 << (irq & 7)); - /* activate irq remapping in PIIX */ - pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); - } - isa_outb(elcr[0], 0x4d0); - isa_outb(elcr[1], 0x4d1); - - bus = first_bus; - if (bus) { - for(devfn = 0; devfn < 256; devfn++) { - d = bus->devices[devfn]; - if (d) - pci_bios_init_device(d); - } - } + pci_for_each_device(pci_info_device); } /* Initialize a PCI NIC. */ diff --git a/hw/pci_host.h b/hw/pci_host.h new file mode 100644 index 000000000..708dae25e --- /dev/null +++ b/hw/pci_host.h @@ -0,0 +1,93 @@ +/* + * QEMU Common PCI Host bridge configuration data space access routines. + * + * 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. + */ + +/* Worker routines for a PCI host controller that uses an {address,data} + register pair to access PCI configuration space. */ + +typedef struct { + uint32_t config_reg; + PCIBus *bus; +} PCIHostState; + +static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1); +} + +static void pci_host_data_writew(void* opaque, pci_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2); +} + +static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val) +{ + PCIHostState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg, val, 4); +} + +static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr) +{ + PCIHostState *s = opaque; + if (!(s->config_reg & (1 << 31))) + return 0xff; + return pci_data_read(s->bus, s->config_reg | (addr & 3), 1); +} + +static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr) +{ + PCIHostState *s = opaque; + uint32_t val; + if (!(s->config_reg & (1 << 31))) + return 0xffff; + val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t pci_host_data_readl(void* opaque, pci_addr_t addr) +{ + PCIHostState *s = opaque; + uint32_t val; + if (!(s->config_reg & (1 << 31))) + return 0xffffffff; + val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + diff --git a/hw/piix_pci.c b/hw/piix_pci.c new file mode 100644 index 000000000..1f7ad94c6 --- /dev/null +++ b/hw/piix_pci.c @@ -0,0 +1,419 @@ +/* + * QEMU i440FX/PIIX3 PCI Bridge Emulation + * + * 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" +typedef uint32_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState I440FXState; + +static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val) +{ + I440FXState *s = opaque; + s->config_reg = val; +} + +static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr) +{ + I440FXState *s = opaque; + return s->config_reg; +} + +static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level); + +PCIBus *i440fx_init(void) +{ + PCIBus *b; + PCIDevice *d; + I440FXState *s; + + s = qemu_mallocz(sizeof(I440FXState)); + b = pci_register_bus(piix3_set_irq, NULL, 0); + s->bus = b; + + register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); + register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s); + + register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s); + register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s); + register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s); + register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s); + register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); + register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); + + d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, + NULL, NULL); + + d->config[0x00] = 0x86; // vendor_id + d->config[0x01] = 0x80; + d->config[0x02] = 0x37; // device_id + d->config[0x03] = 0x12; + d->config[0x08] = 0x02; // revision + d->config[0x0a] = 0x00; // class_sub = host2pci + d->config[0x0b] = 0x06; // class_base = PCI_bridge + d->config[0x0e] = 0x00; // header_type + return b; +} + +/* PIIX3 PCI to ISA bridge */ + +static PCIDevice *piix3_dev; + +/* just used for simpler irq handling. */ +#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) + +static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; + +/* return the global irq number corresponding to a given device irq + pin. We could also use the bus number to have a more precise + mapping. */ +static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + int slot_addend; + slot_addend = (pci_dev->devfn >> 3) - 1; + return (irq_num + slot_addend) & 3; +} + +static inline int get_pci_irq_level(int irq_num) +{ + int pic_level; +#if (PCI_IRQ_WORDS == 2) + pic_level = ((pci_irq_levels[irq_num][0] | + pci_irq_levels[irq_num][1]) != 0); +#else + { + int i; + pic_level = 0; + for(i = 0; i < PCI_IRQ_WORDS; i++) { + if (pci_irq_levels[irq_num][i]) { + pic_level = 1; + break; + } + } + } +#endif + return pic_level; +} + +static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level) +{ + int irq_index, shift, pic_irq, pic_level; + uint32_t *p; + + irq_num = pci_slot_get_pirq(pci_dev, irq_num); + irq_index = pci_dev->irq_index; + p = &pci_irq_levels[irq_num][irq_index >> 5]; + shift = (irq_index & 0x1f); + *p = (*p & ~(1 << shift)) | (level << shift); + + /* now we change the pic irq level according to the piix irq mappings */ + /* XXX: optimize */ + pic_irq = piix3_dev->config[0x60 + irq_num]; + if (pic_irq < 16) { + /* the pic level is the logical OR of all the PCI irqs mapped + to it */ + pic_level = 0; + if (pic_irq == piix3_dev->config[0x60]) + pic_level |= get_pci_irq_level(0); + if (pic_irq == piix3_dev->config[0x61]) + pic_level |= get_pci_irq_level(1); + if (pic_irq == piix3_dev->config[0x62]) + pic_level |= get_pci_irq_level(2); + if (pic_irq == piix3_dev->config[0x63]) + pic_level |= get_pci_irq_level(3); + pic_set_irq(pic_irq, pic_level); + } +} + +static void piix3_reset(PCIDevice *d) +{ + uint8_t *pci_conf = d->config; + + pci_conf[0x04] = 0x07; // master, memory and I/O + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x00; + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium + pci_conf[0x4c] = 0x4d; + pci_conf[0x4e] = 0x03; + pci_conf[0x4f] = 0x00; + pci_conf[0x60] = 0x80; + pci_conf[0x69] = 0x02; + pci_conf[0x70] = 0x80; + pci_conf[0x76] = 0x0c; + pci_conf[0x77] = 0x0c; + pci_conf[0x78] = 0x02; + pci_conf[0x79] = 0x00; + pci_conf[0x80] = 0x00; + pci_conf[0x82] = 0x00; + pci_conf[0xa0] = 0x08; + pci_conf[0xa0] = 0x08; + pci_conf[0xa2] = 0x00; + pci_conf[0xa3] = 0x00; + pci_conf[0xa4] = 0x00; + pci_conf[0xa5] = 0x00; + pci_conf[0xa6] = 0x00; + pci_conf[0xa7] = 0x00; + pci_conf[0xa8] = 0x0f; + pci_conf[0xaa] = 0x00; + pci_conf[0xab] = 0x00; + pci_conf[0xac] = 0x00; + pci_conf[0xae] = 0x00; +} + +int piix3_init(PCIBus *bus) +{ + PCIDevice *d; + uint8_t *pci_conf; + + d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice), + -1, NULL, NULL); + register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); + + piix3_dev = d; + pci_conf = d->config; + + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) + pci_conf[0x03] = 0x70; + pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA + pci_conf[0x0b] = 0x06; // class_base = PCI_bridge + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic + + piix3_reset(d); + return d->devfn; +} + +/***********************************************************/ +/* XXX: the following should be moved to the PC BIOS */ + +static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) +{ + return cpu_inb(NULL, addr); +} + +static void isa_outb(uint32_t val, uint32_t addr) +{ + cpu_outb(NULL, addr, val); +} + +static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) +{ + return cpu_inw(NULL, addr); +} + +static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) +{ + cpu_outw(NULL, addr, val); +} + +static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) +{ + return cpu_inl(NULL, addr); +} + +static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) +{ + cpu_outl(NULL, addr, val); +} + +static uint32_t pci_bios_io_addr; +static uint32_t pci_bios_mem_addr; +/* host irqs corresponding to PCI irqs A-D */ +static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; + +static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + pci_data_write(s, addr, val, 4); +} + +static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + pci_data_write(s, addr, val, 2); +} + +static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + pci_data_write(s, addr, val, 1); +} + +static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + return pci_data_read(s, addr, 4); +} + +static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + return pci_data_read(s, addr, 2); +} + +static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) +{ + PCIBus *s = d->bus; + addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); + return pci_data_read(s, addr, 1); +} + +static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) +{ + PCIIORegion *r; + uint16_t cmd; + uint32_t ofs; + + if ( region_num == PCI_ROM_SLOT ) { + ofs = 0x30; + }else{ + ofs = 0x10 + region_num * 4; + } + + pci_config_writel(d, ofs, addr); + r = &d->io_regions[region_num]; + + /* enable memory mappings */ + cmd = pci_config_readw(d, PCI_COMMAND); + if ( region_num == PCI_ROM_SLOT ) + cmd |= 2; + else if (r->type & PCI_ADDRESS_SPACE_IO) + cmd |= 1; + else + cmd |= 2; + pci_config_writew(d, PCI_COMMAND, cmd); +} + +static void pci_bios_init_device(PCIDevice *d) +{ + int class; + PCIIORegion *r; + uint32_t *paddr; + int i, pin, pic_irq, vendor_id, device_id; + + class = pci_config_readw(d, PCI_CLASS_DEVICE); + vendor_id = pci_config_readw(d, PCI_VENDOR_ID); + device_id = pci_config_readw(d, PCI_DEVICE_ID); + switch(class) { + case 0x0101: + if (vendor_id == 0x8086 && device_id == 0x7010) { + /* PIIX3 IDE */ + pci_config_writew(d, 0x40, 0x8000); // enable IDE0 + pci_config_writew(d, 0x42, 0x8000); // enable IDE1 + goto default_map; + } else { + /* IDE: we map it as in ISA mode */ + pci_set_io_region_addr(d, 0, 0x1f0); + pci_set_io_region_addr(d, 1, 0x3f4); + pci_set_io_region_addr(d, 2, 0x170); + pci_set_io_region_addr(d, 3, 0x374); + } + break; + case 0x0300: + if (vendor_id != 0x1234) + goto default_map; + /* VGA: map frame buffer to default Bochs VBE address */ + pci_set_io_region_addr(d, 0, 0xE0000000); + break; + case 0x0800: + /* PIC */ + vendor_id = pci_config_readw(d, PCI_VENDOR_ID); + device_id = pci_config_readw(d, PCI_DEVICE_ID); + if (vendor_id == 0x1014) { + /* IBM */ + if (device_id == 0x0046 || device_id == 0xFFFF) { + /* MPIC & MPIC2 */ + pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); + } + } + break; + case 0xff00: + if (vendor_id == 0x0106b && + (device_id == 0x0017 || device_id == 0x0022)) { + /* macio bridge */ + pci_set_io_region_addr(d, 0, 0x80800000); + } + break; + default: + default_map: + /* default memory mappings */ + for(i = 0; i < PCI_NUM_REGIONS; i++) { + r = &d->io_regions[i]; + if (r->size) { + if (r->type & PCI_ADDRESS_SPACE_IO) + paddr = &pci_bios_io_addr; + else + paddr = &pci_bios_mem_addr; + *paddr = (*paddr + r->size - 1) & ~(r->size - 1); + pci_set_io_region_addr(d, i, *paddr); + *paddr += r->size; + } + } + break; + } + + /* map the interrupt */ + pin = pci_config_readb(d, PCI_INTERRUPT_PIN); + if (pin != 0) { + pin = pci_slot_get_pirq(d, pin - 1); + pic_irq = pci_irqs[pin]; + pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); + } +} + +/* + * This function initializes the PCI devices as a normal PCI BIOS + * would do. It is provided just in case the BIOS has no support for + * PCI. + */ +void pci_bios_init(void) +{ + int i, irq; + uint8_t elcr[2]; + + pci_bios_io_addr = 0xc000; + pci_bios_mem_addr = 0xf0000000; + + /* activate IRQ mappings */ + elcr[0] = 0x00; + elcr[1] = 0x00; + for(i = 0; i < 4; i++) { + irq = pci_irqs[i]; + /* set to trigger level */ + elcr[irq >> 3] |= (1 << (irq & 7)); + /* activate irq remapping in PIIX */ + pci_config_writeb(piix3_dev, 0x60 + i, irq); + } + isa_outb(elcr[0], 0x4d0); + isa_outb(elcr[1], 0x4d1); + + pci_for_each_device(pci_bios_init_device); +} + diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 33167cdf7..24830457a 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -415,19 +415,18 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, if (is_heathrow) { isa_mem_base = 0x80000000; - pci_bus = pci_grackle_init(0xfec00000); /* Register 2 MB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory); /* init basic PC hardware */ + pic = heathrow_pic_init(&heathrow_pic_mem_index); + set_irq = heathrow_pic_set_irq; + pci_bus = pci_grackle_init(0xfec00000, pic); vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - pic = heathrow_pic_init(&heathrow_pic_mem_index); - set_irq = heathrow_pic_set_irq; - pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); @@ -462,7 +461,6 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, arch_name = "HEATHROW"; } else { isa_mem_base = 0x80000000; - pci_bus = pci_pmac_init(); /* Register 8 MB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); @@ -472,13 +470,13 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); + pic = openpic_init(NULL, &openpic_mem_index, 1, &env); + set_irq = openpic_set_irq; + pci_bus = pci_pmac_init(pic); /* init basic PC hardware */ vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - pic = openpic_init(NULL, &openpic_mem_index, 1, &env); - set_irq = openpic_set_irq; - pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); diff --git a/hw/prep_pci.c b/hw/prep_pci.c new file mode 100644 index 000000000..a31b74c80 --- /dev/null +++ b/hw/prep_pci.c @@ -0,0 +1,167 @@ +/* + * QEMU PREP PCI host + * + * 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" +typedef uint32_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState PREPPCIState; + +static void pci_prep_addr_writel(void* opaque, uint32_t addr, uint32_t val) +{ + PREPPCIState *s = opaque; + s->config_reg = val; +} + +static uint32_t pci_prep_addr_readl(void* opaque, uint32_t addr) +{ + PREPPCIState *s = opaque; + return s->config_reg; +} + +static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr) +{ + int i; + + for(i = 0; i < 11; i++) { + if ((addr & (1 << (11 + i))) != 0) + break; + } + return (addr & 0x7ff) | (i << 11); +} + +static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PREPPCIState *s = opaque; + pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1); +} + +static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PREPPCIState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2); +} + +static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PREPPCIState *s = opaque; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4); +} + +static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) +{ + PREPPCIState *s = opaque; + uint32_t val; + val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1); + return val; +} + +static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) +{ + PREPPCIState *s = opaque; + uint32_t val; + val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) +{ + PREPPCIState *s = opaque; + uint32_t val; + val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { + &PPC_PCIIO_writeb, + &PPC_PCIIO_writew, + &PPC_PCIIO_writel, +}; + +static CPUReadMemoryFunc *PPC_PCIIO_read[] = { + &PPC_PCIIO_readb, + &PPC_PCIIO_readw, + &PPC_PCIIO_readl, +}; + +static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + /* XXX: we do not simulate the hardware - we rely on the BIOS to + set correctly for irq line field */ + pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_prep_init(void) +{ + PREPPCIState *s; + PCIDevice *d; + int PPC_io_memory; + + s = qemu_mallocz(sizeof(PREPPCIState)); + s->bus = pci_register_bus(prep_set_irq, NULL, 0); + + register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); + register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); + + register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s); + register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s); + register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s); + register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s); + register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); + register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); + + PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, + PPC_PCIIO_write, s); + cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); + + /* PCI host bridge */ + d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven", + sizeof(PCIDevice), 0, NULL, NULL); + d->config[0x00] = 0x57; // vendor_id : Motorola + d->config[0x01] = 0x10; + d->config[0x02] = 0x01; // device_id : Raven + d->config[0x03] = 0x48; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer + + return s->bus; +} + diff --git a/hw/sun4m.c b/hw/sun4m.c index 3619005d7..f25fa3eea 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -183,6 +183,11 @@ void pic_set_irq(int irq, int level) slavio_pic_set_irq(slavio_intctl, irq, level); } +void pic_set_irq_new(void *opaque, int irq, int level) +{ + pic_set_irq(irq, level); +} + void pic_set_irq_cpu(int irq, int level, unsigned int cpu) { slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); diff --git a/hw/sun4u.c b/hw/sun4u.c index 208d3dd63..5e6f8baf9 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -329,7 +329,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } } } - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE); + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL); isa_mem_base = VGA_BASE; vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0, 0); diff --git a/hw/unin_pci.c b/hw/unin_pci.c new file mode 100644 index 000000000..a7e360004 --- /dev/null +++ b/hw/unin_pci.c @@ -0,0 +1,261 @@ +/* + * QEMU Uninorth PCI host (for all Mac99 and newer machines) + * + * 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" +typedef target_phys_addr_t pci_addr_t; +#include "pci_host.h" + +typedef PCIHostState UNINState; + +static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + UNINState *s = opaque; + int i; + +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + for (i = 11; i < 32; i++) { + if ((val & (1 << i)) != 0) + break; + } +#if 0 + s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); +#else + s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); +#endif +} + +static uint32_t pci_unin_main_config_readl (void *opaque, + target_phys_addr_t addr) +{ + UNINState *s = opaque; + uint32_t val; + int devfn; + + devfn = (s->config_reg >> 8) & 0xFF; + val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + return val; +} + +static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { + &pci_unin_main_config_writel, + &pci_unin_main_config_writel, + &pci_unin_main_config_writel, +}; + +static CPUReadMemoryFunc *pci_unin_main_config_read[] = { + &pci_unin_main_config_readl, + &pci_unin_main_config_readl, + &pci_unin_main_config_readl, +}; + +static CPUWriteMemoryFunc *pci_unin_main_write[] = { + &pci_host_data_writeb, + &pci_host_data_writew, + &pci_host_data_writel, +}; + +static CPUReadMemoryFunc *pci_unin_main_read[] = { + &pci_host_data_readb, + &pci_host_data_readw, + &pci_host_data_readl, +}; + +#if 0 + +static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + UNINState *s = opaque; + +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + s->config_reg = 0x80000000 | (val & ~0x00000001); +} + +static uint32_t pci_unin_config_readl (void *opaque, + target_phys_addr_t addr) +{ + UNINState *s = opaque; + uint32_t val; + + val = (s->config_reg | 0x00000001) & ~0x80000000; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + + return val; +} + +static CPUWriteMemoryFunc *pci_unin_config_write[] = { + &pci_unin_config_writel, + &pci_unin_config_writel, + &pci_unin_config_writel, +}; + +static CPUReadMemoryFunc *pci_unin_config_read[] = { + &pci_unin_config_readl, + &pci_unin_config_readl, + &pci_unin_config_readl, +}; + +static CPUWriteMemoryFunc *pci_unin_write[] = { + &pci_host_pci_writeb, + &pci_host_pci_writew, + &pci_host_pci_writel, +}; + +static CPUReadMemoryFunc *pci_unin_read[] = { + &pci_host_pci_readb, + &pci_host_pci_readw, + &pci_host_pci_readl, +}; +#endif + +static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); +} + +PCIBus *pci_pmac_init(void *pic) +{ + UNINState *s; + PCIDevice *d; + int pci_mem_config, pci_mem_data; + + /* Use values found on a real PowerMac */ + /* Uninorth main bus */ + s = qemu_mallocz(sizeof(UNINState)); + s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3); + + pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, + pci_unin_main_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, + pci_unin_main_write, s); + cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); + d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice), + 11 << 3, NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x1F; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer + +#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly + /* pci-to-pci bridge */ + d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, + NULL, NULL); + d->config[0x00] = 0x11; // vendor_id : TI + d->config[0x01] = 0x10; + d->config[0x02] = 0x26; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x05; // revision + d->config[0x0A] = 0x04; // class_sub = pci2pci + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x20; // latency_timer + d->config[0x0E] = 0x01; // header_type + + d->config[0x18] = 0x01; // primary_bus + d->config[0x19] = 0x02; // secondary_bus + d->config[0x1A] = 0x02; // subordinate_bus + d->config[0x1B] = 0x20; // secondary_latency_timer + d->config[0x1C] = 0x11; // io_base + d->config[0x1D] = 0x01; // io_limit + d->config[0x20] = 0x00; // memory_base + d->config[0x21] = 0x80; + d->config[0x22] = 0x00; // memory_limit + d->config[0x23] = 0x80; + d->config[0x24] = 0x01; // prefetchable_memory_base + d->config[0x25] = 0x80; + d->config[0x26] = 0xF1; // prefectchable_memory_limit + d->config[0x27] = 0x7F; + // d->config[0x34] = 0xdc // capabilities_pointer +#endif +#if 0 // XXX: not needed for now + /* Uninorth AGP bus */ + s = &pci_bridge[1]; + pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_unin_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_read, + pci_unin_write, s); + cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); + + d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, + NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x20; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + // d->config[0x34] = 0x80; // capabilities_pointer +#endif + +#if 0 // XXX: not needed for now + /* Uninorth internal bus */ + s = &pci_bridge[2]; + pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_unin_config_write, s); + pci_mem_data = cpu_register_io_memory(0, pci_unin_read, + pci_unin_write, s); + cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); + cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); + + d = pci_register_device("Uni-north internal", sizeof(PCIDevice), + 3, 11 << 3, NULL, NULL); + d->config[0x00] = 0x6b; // vendor_id : Apple + d->config[0x01] = 0x10; + d->config[0x02] = 0x1E; // device_id + d->config[0x03] = 0x00; + d->config[0x08] = 0x00; // revision + d->config[0x0A] = 0x00; // class_sub = pci host + d->config[0x0B] = 0x06; // class_base = PCI_bridge + d->config[0x0C] = 0x08; // cache_line_size + d->config[0x0D] = 0x10; // latency_timer + d->config[0x0E] = 0x00; // header_type + d->config[0x34] = 0x00; // capabilities_pointer +#endif + return s->bus; +} + diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 23964f36a..a18833da8 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -638,7 +638,7 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) +void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn) { UHCIState *s; uint8_t *pci_conf; @@ -647,8 +647,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) s = (UHCIState *)pci_register_device(bus, "USB-UHCI", sizeof(UHCIState), - ((PCIDevice *)piix3_state)->devfn + 2, - NULL, NULL); + devfn, NULL, NULL); pci_conf = s->dev.config; pci_conf[0x00] = 0x86; pci_conf[0x01] = 0x80; diff --git a/hw/usb.h b/hw/usb.h index 05502e04d..cb654e000 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -155,7 +155,7 @@ int set_usb_string(uint8_t *buf, const char *str); USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports); /* usb-uhci.c */ -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); +void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn); /* usb-linux.c */ USBDevice *usb_host_device_open(const char *devname); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c new file mode 100644 index 000000000..34a4bc6c5 --- /dev/null +++ b/hw/versatile_pci.c @@ -0,0 +1,119 @@ +/* + * ARM Versatile/PB PCI host controller + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +#include "vl.h" + +static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr) +{ + return addr & 0xf8ff; +} + +static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1); +} + +static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2); +} + +static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4); +} + +static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1); + return val; +} + +static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *pci_vpb_config_write[] = { + &pci_vpb_config_writeb, + &pci_vpb_config_writew, + &pci_vpb_config_writel, +}; + +static CPUReadMemoryFunc *pci_vpb_config_read[] = { + &pci_vpb_config_readb, + &pci_vpb_config_readw, + &pci_vpb_config_readl, +}; + +static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +{ + pic_set_irq_new(pic, 27 + irq_num, level); +} + +PCIBus *pci_vpb_init(void *pic) +{ + PCIBus *s; + PCIDevice *d; + int mem_config; + + s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3); + /* ??? Register memory space. */ + + mem_config = cpu_register_io_memory(0, pci_vpb_config_read, + pci_vpb_config_write, s); + /* Selfconfig area. */ + cpu_register_physical_memory(0x41000000, 0x10000, mem_config); + /* Normal config area. */ + cpu_register_physical_memory(0x42000000, 0x10000, mem_config); + + d = pci_register_device(s, "Versatile/PB PCI Controller", + sizeof(PCIDevice), -1, NULL, NULL); + d->config[0x00] = 0xee; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = 0x00; // device_id + d->config[0x03] = 0x03; + d->config[0x04] = 0x00; + d->config[0x05] = 0x00; + d->config[0x06] = 0x20; + d->config[0x07] = 0x02; + d->config[0x08] = 0x00; // revision + d->config[0x09] = 0x00; // programming i/f + d->config[0x0A] = 0x40; // class_sub = pci host + d->config[0x0B] = 0x0b; // class_base = PCI_bridge + d->config[0x0D] = 0x10; // latency_timer + + return s; +} + diff --git a/hw/versatilepb.c b/hw/versatilepb.c index e198a518e..8a821d42d 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -10,6 +10,8 @@ #include "vl.h" #include "arm_pic.h" +#define LOCK_VALUE 0xa05f + /* Primary interrupt controller. */ typedef struct vpb_sic_state @@ -145,6 +147,188 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) return s; } +/* System controller. */ + +typedef struct { + uint32_t base; + uint32_t leds; + uint16_t lockval; + uint32_t cfgdata1; + uint32_t cfgdata2; + uint32_t flags; + uint32_t nvflags; + uint32_t resetlevel; +} vpb_sys_state; + +static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset) +{ + vpb_sys_state *s = (vpb_sys_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* ID */ + return 0x41007004; + case 0x04: /* SW */ + /* General purpose hardware switches. + We don't have a useful way of exposing these to the user. */ + return 0; + case 0x08: /* LED */ + return s->leds; + case 0x20: /* LOCK */ + return s->lockval; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + case 0x24: /* 100HZ */ + /* ??? Implement these. */ + return 0; + case 0x28: /* CFGDATA1 */ + return s->cfgdata1; + case 0x2c: /* CFGDATA2 */ + return s->cfgdata2; + case 0x30: /* FLAGS */ + return s->flags; + case 0x38: /* NVFLAGS */ + return s->nvflags; + case 0x40: /* RESETCTL */ + return s->resetlevel; + case 0x44: /* PCICTL */ + return 1; + case 0x48: /* MCI */ + return 0; + case 0x4c: /* FLASH */ + return 0; + case 0x50: /* CLCD */ + return 0x1000; + case 0x54: /* CLCDSER */ + return 0; + case 0x58: /* BOOTCS */ + return 0; + case 0x5c: /* 24MHz */ + /* ??? not implemented. */ + return 0; + case 0x60: /* MISC */ + return 0; + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + case 0xc0: /* SYS_TEST_OSC0 */ + case 0xc4: /* SYS_TEST_OSC1 */ + case 0xc8: /* SYS_TEST_OSC2 */ + case 0xcc: /* SYS_TEST_OSC3 */ + case 0xd0: /* SYS_TEST_OSC4 */ + return 0; + default: + printf ("vpb_sys_read: Bad register offset 0x%x\n", offset); + return 0; + } +} + +static void vpb_sys_write(void *opaque, target_phys_addr_t offset, + uint32_t val) +{ + vpb_sys_state *s = (vpb_sys_state *)opaque; + offset -= s->base; + + switch (offset) { + case 0x08: /* LED */ + s->leds = val; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + /* ??? */ + break; + case 0x20: /* LOCK */ + if (val == LOCK_VALUE) + s->lockval = val; + else + s->lockval = val & 0x7fff; + break; + case 0x28: /* CFGDATA1 */ + /* ??? Need to implement this. */ + s->cfgdata1 = val; + break; + case 0x2c: /* CFGDATA2 */ + /* ??? Need to implement this. */ + s->cfgdata2 = val; + break; + case 0x30: /* FLAGSSET */ + s->flags |= val; + break; + case 0x34: /* FLAGSCLR */ + s->flags &= ~val; + break; + case 0x38: /* NVFLAGSSET */ + s->nvflags |= val; + break; + case 0x3c: /* NVFLAGSCLR */ + s->nvflags &= ~val; + break; + case 0x40: /* RESETCTL */ + if (s->lockval == LOCK_VALUE) { + s->resetlevel = val; + if (val & 0x100) + cpu_abort(cpu_single_env, "Board reset\n"); + } + break; + case 0x44: /* PCICTL */ + /* nothing to do. */ + break; + case 0x4c: /* FLASH */ + case 0x50: /* CLCD */ + case 0x54: /* CLCDSER */ + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + break; + default: + printf ("vpb_sys_write: Bad register offset 0x%x\n", offset); + return; + } +} + +static CPUReadMemoryFunc *vpb_sys_readfn[] = { + vpb_sys_read, + vpb_sys_read, + vpb_sys_read +}; + +static CPUWriteMemoryFunc *vpb_sys_writefn[] = { + vpb_sys_write, + vpb_sys_write, + vpb_sys_write +}; + +static vpb_sys_state *vpb_sys_init(uint32_t base) +{ + vpb_sys_state *s; + int iomemtype; + + s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state)); + if (!s) + return NULL; + s->base = base; + iomemtype = cpu_register_io_memory(0, vpb_sys_readfn, + vpb_sys_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + /* ??? Save/restore. */ + return s; +} + /* Board init. */ /* The AB and PB boards both use the same core, just with different @@ -159,6 +343,10 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, CPUState *env; void *pic; void *sic; + PCIBus *pci_bus; + NICInfo *nd; + int n; + int done_smc = 0; env = cpu_init(); cpu_arm_set_model(env, ARM_CPUID_ARM926); @@ -166,20 +354,24 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + vpb_sys_init(0x10000000); pic = arm_pic_init_cpu(env); pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); sic = vpb_sic_init(0x10003000, pic, 31); pl050_init(0x10006000, sic, 3, 0); pl050_init(0x10007000, sic, 4, 1); - /* TODO: Init PCI NICs. */ - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "smc91c111") == 0) { - smc91c111_init(&nd_table[0], 0x10010000, sic, 25); + pci_bus = pci_vpb_init(sic); + /* The Versatile PCI bridge does not provide access to PCI IO space, + so many of the qemu PCI devices are not useable. */ + for(n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + if (!nd->model) + nd->model = done_smc ? "rtl8139" : "smc91c111"; + if (strcmp(nd->model, "smc91c111") == 0) { + smc91c111_init(nd, 0x10010000, sic, 25); } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); + pci_nic_init(pci_bus, nd); } } diff --git a/vl.h b/vl.h index 7d51ff576..bdfcfb1d8 100644 --- a/vl.h +++ b/vl.h @@ -593,6 +593,20 @@ typedef struct PCIIORegion { #define PCI_ROM_SLOT 6 #define PCI_NUM_REGIONS 7 + +#define PCI_DEVICES_MAX 64 + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ +#define PCI_MIN_GNT 0x3e /* 8 bits */ +#define PCI_MAX_LAT 0x3f /* 8 bits */ + struct PCIDevice { /* PCI config space */ uint8_t config[256]; @@ -606,6 +620,7 @@ struct PCIDevice { /* do not access the following fields */ PCIConfigReadFunc *config_read; PCIConfigWriteFunc *config_write; + /* ??? This is a PC-specific hack, and should be removed. */ int irq_index; }; @@ -627,21 +642,37 @@ void pci_default_write_config(PCIDevice *d, void generic_pci_save(QEMUFile* f, void *opaque); int generic_pci_load(QEMUFile* f, void *opaque, int version_id); -extern struct PIIX3State *piix3_state; +typedef void (*pci_set_irq_fn)(PCIDevice *pci_dev, void *pic, + int irq_num, int level); +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min); + +void pci_nic_init(PCIBus *bus, NICInfo *nd); +void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); +uint32_t pci_data_read(void *opaque, uint32_t addr, int len); +int pci_bus_num(PCIBus *s); +void pci_for_each_device(void (*fn)(PCIDevice *d)); -PCIBus *i440fx_init(void); -void piix3_init(PCIBus *bus); -void pci_bios_init(void); void pci_info(void); -/* temporary: will be moved in platform specific file */ -void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque); +/* prep_pci.c */ PCIBus *pci_prep_init(void); -PCIBus *pci_grackle_init(uint32_t base); -PCIBus *pci_pmac_init(void); -PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base); -void pci_nic_init(PCIBus *bus, NICInfo *nd); +/* grackle_pci.c */ +PCIBus *pci_grackle_init(uint32_t base, void *pic); + +/* unin_pci.c */ +PCIBus *pci_pmac_init(void *pic); + +/* apb_pci.c */ +PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, + void *pic); + +PCIBus *pci_vpb_init(void *pic); + +/* piix_pci.c */ +PCIBus *i440fx_init(void); +int piix3_init(PCIBus *bus); +void pci_bios_init(void); /* openpic.c */ typedef struct openpic_t openpic_t; @@ -726,7 +757,7 @@ void isa_ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1); void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, int secondary_ide_enabled); -void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table); +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn); int pmac_ide_init (BlockDriverState **hd_table, SetIRQFunc *set_irq, void *irq_opaque, int irq); @@ -843,7 +874,7 @@ int pcspk_audio_init(AudioState *); /* acpi.c */ extern int acpi_enabled; -void piix4_pm_init(PCIBus *bus); +void piix4_pm_init(PCIBus *bus, int devfn); void acpi_bios_init(void); /* pc.c */ -- cgit v1.2.3 From 214feb514bb66f652c09f425b67828898110b6c0 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 13 May 2006 16:30:17 +0000 Subject: Add dependency on config.h and config-host.h. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1917 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.target b/Makefile.target index 1e8cc9ccf..dd62f5ce6 100644 --- a/Makefile.target +++ b/Makefile.target @@ -489,6 +489,8 @@ 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) $(DEFINES) -c -o $@ $< -- cgit v1.2.3 From b9dea4fbc65fbfad4ea7ffb79e7cf7f280bd7f64 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 13 May 2006 16:54:03 +0000 Subject: Move all: target first. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1918 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3a69a0494..e6cff9a9e 100644 --- a/Makefile +++ b/Makefile @@ -17,13 +17,13 @@ else DOCS= endif +all: $(TOOLS) $(DOCS) recurse-all + subdir-%: dyngen$(EXESUF) $(MAKE) -C $(subst subdir-,,$@) all recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) -all: $(TOOLS) $(DOCS) recurse-all - qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) -- cgit v1.2.3 From 00a9bf191b9353e1bd981539c25821bf6a81e00f Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 13 May 2006 16:55:46 +0000 Subject: Update ARM board documentation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1919 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 01f33f7e7..d11ccd2ad 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -78,6 +78,7 @@ For system emulation, the following hardware targets are supported: @item Sun4u (64-bit Sparc processor, in progress) @item Malta board (32-bit MIPS processor) @item ARM Integrator/CP (ARM926E or 1026E processor) +@item ARM Versatile baseboard (ARM926E) @end itemize For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported. @@ -1486,6 +1487,33 @@ ARM926E or ARM1026E CPU Two PL011 UARTs @item SMC 91c111 Ethernet adapter +@item +PL110 LCD controller +@item +PL050 KMI with PS/2 keyboard and mouse. +@end itemize + +The ARM Versatile baseboard is emulated with the following devices: + +@itemize @minus +@item +ARM926E CPU +@item +PL190 Vectored Interrupt Controller +@item +Four PL011 UARTs +@item +SMC 91c111 Ethernet adapter +@item +PL110 LCD controller +@item +PL050 KMI with PS/2 keyboard and mouse. +@item +PCI host bridge. Note the emulated PCI bridge only provides access to +PCI memory space. It does not provide access to PCI IO space. +This means some devices (eg. ne2k_pci NIC) are not useable, and others +(eg. rtl8139 NIC) are only useable when the guest drivers use the memory +mapped control registers. @end itemize A Linux 2.6 test image is available on the QEMU web site. More -- cgit v1.2.3 From c59372208a928828dd7d1cceaee78b48e5e03611 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 14 May 2006 11:30:38 +0000 Subject: Teach usermode emulation how to lie about uname -r. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1920 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 8 ++++++++ linux-user/main.c | 3 +++ linux-user/qemu.h | 1 + linux-user/syscall.c | 3 +++ 4 files changed, 15 insertions(+) diff --git a/configure b/configure index aae84af9c..d33e20210 100755 --- a/configure +++ b/configure @@ -95,6 +95,7 @@ check_gcc="yes" softmmu="yes" user="no" build_docs="no" +uname_release="" # OS specific targetos=`uname -s` @@ -237,6 +238,8 @@ for opt do ;; --enable-user) user="yes" ;; + --enable-uname-release=*) uname_release="$optarg" + ;; esac done @@ -284,6 +287,7 @@ 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 build at the place where configure is launched" exit 1 @@ -553,6 +557,8 @@ 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" @@ -711,6 +717,8 @@ if [ "$bsd" = "yes" ] ; then 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 diff --git a/linux-user/main.c b/linux-user/main.c index 78f45a5f9..23e9e85b1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -34,6 +34,7 @@ #endif static const char *interp_prefix = CONFIG_QEMU_PREFIX; +const char *qemu_uname_release = CONFIG_UNAME_RELEASE; #if defined(__i386__) && !defined(CONFIG_STATIC) /* Force usage of an ELF interpreter even if it is an ELF shared @@ -1514,6 +1515,8 @@ int main(int argc, char **argv) } } else if (!strcmp(r, "g")) { gdbstub_port = atoi(argv[optind++]); + } else if (!strcmp(r, "r")) { + qemu_uname_release = argv[optind++]; } else #ifdef USE_CODE_COPY if (!strcmp(r, "no-code-copy")) { diff --git a/linux-user/qemu.h b/linux-user/qemu.h index a797c512b..7c7bcf34e 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -80,6 +80,7 @@ typedef struct TaskState { } __attribute__((aligned(16))) TaskState; extern TaskState *first_task_state; +extern const char *qemu_uname_release; int elf_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7da469aa8..4afc6d888 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2861,6 +2861,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, /* Overrite the native machine name with whatever is being emulated. */ strcpy (buf->machine, UNAME_MACHINE); + /* Allow the user to override the reported release. */ + if (qemu_uname_release && *qemu_uname_release) + strcpy (buf->release, qemu_uname_release); } unlock_user_struct(buf, arg1, 1); } -- cgit v1.2.3 From 0cb3fb1e30a7789881e184b1134f2f47752b64d5 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 14 May 2006 12:07:53 +0000 Subject: Add doc, html, dvi and .PHONY Makefile targets. Add resulting files to .cvsignore. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1921 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 13 +++++++++++++ Makefile | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/.cvsignore b/.cvsignore index 101139fc8..7be41c433 100644 --- a/.cvsignore +++ b/.cvsignore @@ -11,6 +11,8 @@ ppc64-softmmu ppc-user qemu-doc.html qemu-tech.html +qemu-doc.info +qemu-tech.info qemu.1 qemu.pod qemu-img.1 @@ -25,5 +27,16 @@ mips-softmmu mipsel-softmmu mips-user mipsel-user +.gdbinit sh4-user sh4-softmmu +*.aux +*.cp +*.dvi +*.fn +*.ky +*.log +*.pg +*.toc +*.tp +*.vr diff --git a/Makefile b/Makefile index e6cff9a9e..b6f496e6a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,10 @@ +# Makefile for QEMU. + include config-host.mak +.PHONY: all clean distclean dvi info install install-doc tar tarbin \ + speed test test2 html dvi info + CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I. ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic @@ -41,6 +46,7 @@ clean: 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 @@ -105,6 +111,12 @@ 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) -- cgit v1.2.3 From 5c3ff3a7be1b6fa0ad071a8de98400e24e158dcc Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 14 May 2006 13:44:07 +0000 Subject: Avoid compiler warning. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1922 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index 642af5e2b..6175d871a 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -611,7 +611,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, unsigned long bios_offset, vga_bios_offset; int bios_size, isa_bios_size; PCIBus *pci_bus; - int piix3_devfn; + int piix3_devfn = -1; CPUState *env; NICInfo *nd; -- cgit v1.2.3 From 3512779a88128808eee4c5ecbeb3ad7679f97a50 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 May 2006 18:11:49 +0000 Subject: support for all VNC pixel formats git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1923 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++----------- vnchextile.h | 48 ++++++++++----- 2 files changed, 195 insertions(+), 51 deletions(-) diff --git a/vnc.c b/vnc.c index 93f61a70b..812f87a97 100644 --- a/vnc.c +++ b/vnc.c @@ -42,6 +42,14 @@ typedef struct VncState VncState; typedef int VncReadEvent(VncState *vs, char *data, size_t len); +typedef void VncWritePixels(VncState *vs, void *data, int size); + +typedef void VncSendHextileTile(VncState *vs, + int x, int y, int w, int h, + uint32_t *last_bg, + uint32_t *last_fg, + int *has_bg, int *has_fg); + struct VncState { QEMUTimer *timer; @@ -53,12 +61,19 @@ struct VncState int height; uint64_t dirty_row[768]; char *old_data; - int depth; + int depth; /* internal VNC frame buffer byte per pixel */ int has_resize; int has_hextile; Buffer output; Buffer input; kbd_layout_t *kbd_layout; + /* current output mode information */ + VncWritePixels *write_pixels; + VncSendHextileTile *send_hextile_tile; + int pix_bpp, pix_big_endian; + int red_shift, red_max, red_shift1; + int green_shift, green_max, green_shift1; + int blue_shift, blue_max, blue_shift1; VncReadEvent *read_handler; size_t read_handler_expect; @@ -130,6 +145,66 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h) } } +/* fastest code */ +static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size) +{ + vnc_write(vs, pixels, size); +} + +/* slowest but generic code. */ +static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) +{ + unsigned int r, g, b; + + r = (v >> vs->red_shift1) & vs->red_max; + g = (v >> vs->green_shift1) & vs->green_max; + b = (v >> vs->blue_shift1) & vs->blue_max; + v = (r << vs->red_shift) | + (g << vs->green_shift) | + (b << vs->blue_shift); + switch(vs->pix_bpp) { + case 1: + buf[0] = v; + break; + case 2: + if (vs->pix_big_endian) { + buf[0] = v >> 8; + buf[1] = v; + } else { + buf[1] = v >> 8; + buf[0] = v; + } + break; + default: + case 4: + if (vs->pix_big_endian) { + buf[0] = v >> 24; + buf[1] = v >> 16; + buf[2] = v >> 8; + buf[3] = v; + } else { + buf[3] = v >> 24; + buf[2] = v >> 16; + buf[1] = v >> 8; + buf[0] = v; + } + break; + } +} + +static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size) +{ + uint32_t *pixels = pixels1; + uint8_t buf[4]; + int n, i; + + n = size >> 2; + for(i = 0; i < n; i++) { + vnc_convert_pixel(vs, buf, pixels[i]); + vnc_write(vs, buf, vs->pix_bpp); + } +} + static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h) { int i; @@ -139,7 +214,7 @@ static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h row = vs->ds->data + y * vs->ds->linesize + x * vs->depth; for (i = 0; i < h; i++) { - vnc_write(vs, row, w * vs->depth); + vs->write_pixels(vs, row, w * vs->depth); row += vs->ds->linesize; } } @@ -162,35 +237,26 @@ static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h) #include "vnchextile.h" #undef BPP +#define GENERIC +#define BPP 32 +#include "vnchextile.h" +#undef BPP +#undef GENERIC + static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h) { int i, j; int has_fg, has_bg; uint32_t last_fg32, last_bg32; - uint16_t last_fg16, last_bg16; - uint8_t last_fg8, last_bg8; vnc_framebuffer_update(vs, x, y, w, h, 5); has_fg = has_bg = 0; for (j = y; j < (y + h); j += 16) { for (i = x; i < (x + w); i += 16) { - switch (vs->depth) { - case 1: - send_hextile_tile_8(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), - &last_bg8, &last_fg8, &has_bg, &has_fg); - break; - case 2: - send_hextile_tile_16(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), - &last_bg16, &last_fg16, &has_bg, &has_fg); - break; - case 4: - send_hextile_tile_32(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), - &last_bg32, &last_fg32, &has_bg, &has_fg); - break; - default: - break; - } + vs->send_hextile_tile(vs, i, j, + MIN(16, x + w - i), MIN(16, y + h - j), + &last_bg32, &last_fg32, &has_bg, &has_fg); } } } @@ -660,30 +726,79 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) } } +static int compute_nbits(unsigned int val) +{ + int n; + n = 0; + while (val != 0) { + n++; + val >>= 1; + } + return n; +} + static void set_pixel_format(VncState *vs, int bits_per_pixel, int depth, int big_endian_flag, int true_color_flag, int red_max, int green_max, int blue_max, int red_shift, int green_shift, int blue_shift) { - switch (bits_per_pixel) { - case 32: - case 24: - vs->depth = 4; - break; - case 16: - vs->depth = 2; - break; - case 8: - vs->depth = 1; - break; - default: + int host_big_endian_flag; + +#ifdef WORDS_BIGENDIAN + host_big_endian_flag = 1; +#else + host_big_endian_flag = 0; +#endif + if (!true_color_flag) { + fail: vnc_client_error(vs); - break; + return; + } + if (bits_per_pixel == 32 && + host_big_endian_flag == big_endian_flag && + red_max == 0xff && green_max == 0xff && blue_max == 0xff && + red_shift == 16 && green_shift == 8 && blue_shift == 0) { + vs->depth = 4; + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_32; + } else + if (bits_per_pixel == 16 && + host_big_endian_flag == big_endian_flag && + red_max == 31 && green_max == 63 && blue_max == 31 && + red_shift == 11 && green_shift == 5 && blue_shift == 0) { + vs->depth = 2; + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_16; + } else + if (bits_per_pixel == 8 && + red_max == 7 && green_max == 7 && blue_max == 3 && + red_shift == 5 && green_shift == 2 && blue_shift == 0) { + vs->depth = 1; + vs->write_pixels = vnc_write_pixels_copy; + vs->send_hextile_tile = send_hextile_tile_8; + } else + { + /* generic and slower case */ + if (bits_per_pixel != 8 && + bits_per_pixel != 16 && + bits_per_pixel != 32) + goto fail; + vs->depth = 4; + vs->red_shift = red_shift; + vs->red_max = red_max; + vs->red_shift1 = 24 - compute_nbits(red_max); + vs->green_shift = green_shift; + vs->green_max = green_max; + vs->green_shift1 = 16 - compute_nbits(green_max); + vs->blue_shift = blue_shift; + vs->blue_max = blue_max; + vs->blue_shift1 = 8 - compute_nbits(blue_max); + vs->pix_bpp = bits_per_pixel / 8; + vs->pix_big_endian = big_endian_flag; + vs->write_pixels = vnc_write_pixels_generic; + vs->send_hextile_tile = send_hextile_tile_generic; } - - if (!true_color_flag) - vnc_client_error(vs); vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); @@ -774,7 +889,11 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ vnc_write_u8(vs, vs->depth * 8); /* depth */ +#ifdef WORDS_BIGENDIAN + vnc_write_u8(vs, 1); /* big-endian-flag */ +#else vnc_write_u8(vs, 0); /* big-endian-flag */ +#endif vnc_write_u8(vs, 1); /* true-color-flag */ if (vs->depth == 4) { vnc_write_u16(vs, 0xFF); /* red-max */ @@ -783,6 +902,7 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) vnc_write_u8(vs, 16); /* red-shift */ vnc_write_u8(vs, 8); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_32; } else if (vs->depth == 2) { vnc_write_u16(vs, 31); /* red-max */ vnc_write_u16(vs, 63); /* green-max */ @@ -790,14 +910,18 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) vnc_write_u8(vs, 11); /* red-shift */ vnc_write_u8(vs, 5); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_16; } else if (vs->depth == 1) { - vnc_write_u16(vs, 3); /* red-max */ + /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */ + vnc_write_u16(vs, 7); /* red-max */ vnc_write_u16(vs, 7); /* green-max */ vnc_write_u16(vs, 3); /* blue-max */ vnc_write_u8(vs, 5); /* red-shift */ vnc_write_u8(vs, 2); /* green-shift */ vnc_write_u8(vs, 0); /* blue-shift */ + vs->send_hextile_tile = send_hextile_tile_8; } + vs->write_pixels = vnc_write_pixels_copy; vnc_write(vs, pad, 3); /* padding */ diff --git a/vnchextile.h b/vnchextile.h index 7277670a5..16a354d60 100644 --- a/vnchextile.h +++ b/vnchextile.h @@ -1,15 +1,23 @@ #define CONCAT_I(a, b) a ## b #define CONCAT(a, b) CONCAT_I(a, b) #define pixel_t CONCAT(uint, CONCAT(BPP, _t)) - -static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, - int x, int y, int w, int h, - pixel_t *last_bg, pixel_t *last_fg, - int *has_bg, int *has_fg) +#ifdef GENERIC +#define NAME generic +#else +#define NAME BPP +#endif + +static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, + int x, int y, int w, int h, + uint32_t *last_bg32, + uint32_t *last_fg32, + int *has_bg, int *has_fg) { char *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth); pixel_t *irow = (pixel_t *)row; int j, i; + pixel_t *last_bg = (pixel_t *)last_bg32; + pixel_t *last_fg = (pixel_t *)last_fg32; pixel_t bg = 0; pixel_t fg = 0; int n_colors = 0; @@ -122,10 +130,15 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, has_color = 1; } else if (irow[i] != color) { has_color = 0; - +#ifdef GENERIC + vnc_convert_pixel(vs, data + n_data, color); + n_data += vs->pix_bpp; +#else memcpy(data + n_data, &color, sizeof(color)); - hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1); - n_data += 2 + sizeof(pixel_t); + n_data += sizeof(pixel_t); +#endif + hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); + n_data += 2; n_subtiles++; min_x = -1; @@ -137,9 +150,15 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, } } if (has_color) { - memcpy(data + n_data, &color, sizeof(color)); - hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1); - n_data += 2 + sizeof(pixel_t); +#ifdef GENERIC + vnc_convert_pixel(vs, data + n_data, color); + n_data += vs->pix_bpp; +#else + memcpy(data + n_data, &color, sizeof(color)); + n_data += sizeof(pixel_t); +#endif + hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); + n_data += 2; n_subtiles++; } irow += vs->ds->linesize / sizeof(pixel_t); @@ -169,21 +188,22 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs, vnc_write_u8(vs, flags); if (n_colors < 4) { if (flags & 0x02) - vnc_write(vs, last_bg, sizeof(pixel_t)); + vs->write_pixels(vs, last_bg, sizeof(pixel_t)); if (flags & 0x04) - vnc_write(vs, last_fg, sizeof(pixel_t)); + vs->write_pixels(vs, last_fg, sizeof(pixel_t)); if (n_subtiles) { vnc_write_u8(vs, n_subtiles); vnc_write(vs, data, n_data); } } else { for (j = 0; j < h; j++) { - vnc_write(vs, row, w * vs->depth); + vs->write_pixels(vs, row, w * vs->depth); row += vs->ds->linesize; } } } +#undef NAME #undef pixel_t #undef CONCAT_I #undef CONCAT -- cgit v1.2.3 From f815fa45da704086eafbab1709e85be5dc727f4b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 May 2006 18:41:52 +0000 Subject: ne2000 buffer fulness fix (Han Zhu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1924 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 674d83e49..e23c6df06 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -206,7 +206,7 @@ static int ne2000_buffer_full(NE2000State *s) index = s->curpag << 8; boundary = s->boundary << 8; - if (index < boundary) + if (index <= boundary) avail = boundary - index; else avail = (s->stop - s->start) - (index - boundary); -- cgit v1.2.3 From 1c46d7139a4d2c4491ce2459f9a32c1be85e23d5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 14 May 2006 21:03:52 +0000 Subject: clear screen when changing graphic mode in Cirrus VGA BIOS (aka win2k mode change bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1925 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/vgabios-cirrus.bin | Bin 32768 -> 32768 bytes pc-bios/vgabios.bin | Bin 32768 -> 32768 bytes pc-bios/vgabios.diff | 869 ++++----------------------------------------- 3 files changed, 66 insertions(+), 803 deletions(-) diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 6f72d1ebd..b9229f663 100644 Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index 1d6e51175..10b2ad8e3 100644 Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ diff --git a/pc-bios/vgabios.diff b/pc-bios/vgabios.diff index 73159a0fd..c2594b845 100644 --- a/pc-bios/vgabios.diff +++ b/pc-bios/vgabios.diff @@ -1,811 +1,74 @@ -Index: Makefile -=================================================================== -RCS file: /sources/vgabios/vgabios/Makefile,v -retrieving revision 1.17 -diff -u -w -r1.17 Makefile ---- Makefile 6 Mar 2005 13:06:47 -0000 1.17 -+++ Makefile 25 Mar 2006 01:19:02 -0000 -@@ -17,9 +17,9 @@ - all: bios cirrus-bios - - --bios: biossums vgabios.bin vgabios.debug.bin -+bios: biossums vgabios.bin #vgabios.debug.bin - --cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin -+cirrus-bios: vgabios-cirrus.bin #vgabios-cirrus.debug.bin - - clean: - /bin/rm -f biossums *.o *.s *.ld86 \ Index: clext.c =================================================================== RCS file: /sources/vgabios/vgabios/clext.c,v -retrieving revision 1.9 -diff -u -w -r1.9 clext.c ---- clext.c 4 Dec 2004 15:26:17 -0000 1.9 -+++ clext.c 25 Mar 2006 01:19:03 -0000 -@@ -238,6 +238,21 @@ - 0xffff - }; - -+/* 1600x1200x8 */ -+unsigned short cseq_1600x1200x8[] = { -+0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, -+0x760b,0x760c,0x760d,0x760e, -+0x0412,0x0013,0x2017, -+0x341b,0x341c,0x341d,0x341e, -+0xffff -+}; -+unsigned short ccrtc_1600x1200x8[] = { -+0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, -+0x6009,0x000c,0x000d, -+0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18, -+0x001a,0x221b,0x001d, -+0xffff -+}; - - cirrus_mode_t cirrus_modes[] = - { -@@ -291,6 +306,10 @@ - cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, - 6,5,11,6,5,5,0,0,0}, - -+ {0x7b,1600,1200,8,0x00, -+ cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8, -+ 4,0,0,0,0,0,0,0,0}, -+ - {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0, - 0xff,0,0,0,0,0,0,0,0}, - {0xff,0,0,0,0,0,0,0,0, -Index: vgabios.c -=================================================================== -RCS file: /sources/vgabios/vgabios/vgabios.c,v -retrieving revision 1.63 -diff -u -w -r1.63 vgabios.c ---- vgabios.c 26 Dec 2005 19:50:26 -0000 1.63 -+++ vgabios.c 25 Mar 2006 01:19:03 -0000 -@@ -111,6 +111,7 @@ - static void biosfn_read_video_state_size(); - static void biosfn_save_video_state(); - static void biosfn_restore_video_state(); -+extern Bit8u video_save_pointer_table[]; - - // This is for compiling with gcc2 and gcc3 - #define ASM_START #asm -@@ -459,6 +460,29 @@ - - pop ds +retrieving revision 1.10 +diff -u -w -r1.10 clext.c +--- clext.c 25 Mar 2006 10:19:15 -0000 1.10 ++++ clext.c 14 May 2006 20:49:29 -0000 +@@ -544,6 +544,13 @@ + cirrus_set_video_mode_extended: + call cirrus_switch_mode + pop ax ;; mode ++ test al, #0x80 ++ jnz cirrus_set_video_mode_extended_1 ++ push ax ++ mov ax, #0xffff ; set to 0xff to keep win 2K happy ++ call cirrus_clear_vram ++ pop ax ++cirrus_set_video_mode_extended_1: + and al, #0x7f + + push ds +@@ -1011,6 +1018,13 @@ + jnz cirrus_vesa_02h_3 + call cirrus_enable_16k_granularity + cirrus_vesa_02h_3: ++ test bx, #0x8000 ;; no clear ++ jnz cirrus_vesa_02h_4 ++ push ax ++ xor ax,ax ++ call cirrus_clear_vram ++ pop ax ++cirrus_vesa_02h_4: + pop ax + push ds + #ifdef CIRRUS_VESA3_PMINFO +@@ -1479,6 +1493,38 @@ + pop bx ret -+ -+_video_save_pointer_table: -+ .word _video_param_table -+ .word 0xc000 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ -+ .word 0 /* XXX: fill it */ -+ .word 0 -+ - ASM_END - - // -------------------------------------------------------------------------------------------- -@@ -780,8 +804,8 @@ - - // Should we clear the screen ? - Bit8u noclearmem=mode&0x80; -- Bit8u line,mmask,*palette; -- Bit16u i,twidth,theight,cheight; -+ Bit8u line,mmask,*palette,vpti; -+ Bit16u i,twidth,theightm1,cheight; - Bit8u modeset_ctl,video_ctl,vga_switches; - Bit16u crtc_addr; - -@@ -804,9 +828,10 @@ - if(line==0xFF) - return; - -- twidth=vga_modes[line].twidth; -- theight=vga_modes[line].theight; -- cheight=vga_modes[line].cheight; -+ vpti=line_to_vpti[line]; -+ twidth=video_param_table[vpti].twidth; -+ theightm1=video_param_table[vpti].theightm1; -+ cheight=video_param_table[vpti].cheight; - - // Read the bios vga control - video_ctl=read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL); -@@ -866,21 +891,25 @@ - inb(VGAREG_ACTL_RESET); - - // Set Attribute Ctl -- for(i=0;i<=ACTL_MAX_REG;i++) -+ for(i=0;i<=0x13;i++) - {outb(VGAREG_ACTL_ADDRESS,i); -- outb(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]); -+ outb(VGAREG_ACTL_WRITE_DATA,video_param_table[vpti].actl_regs[i]); - } -+ outb(VGAREG_ACTL_ADDRESS,0x14); -+ outb(VGAREG_ACTL_WRITE_DATA,0x00); - - // Set Sequencer Ctl -- for(i=0;i<=SEQU_MAX_REG;i++) -+ outb(VGAREG_SEQU_ADDRESS,0); -+ outb(VGAREG_SEQU_DATA,0x03); -+ for(i=1;i<=4;i++) - {outb(VGAREG_SEQU_ADDRESS,i); -- outb(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]); -+ outb(VGAREG_SEQU_DATA,video_param_table[vpti].sequ_regs[i - 1]); - } - - // Set Grafx Ctl -- for(i=0;i<=GRDC_MAX_REG;i++) -+ for(i=0;i<=8;i++) - {outb(VGAREG_GRDC_ADDRESS,i); -- outb(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]); -+ outb(VGAREG_GRDC_DATA,video_param_table[vpti].grdc_regs[i]); - } - - // Set CRTC address VGA or MDA -@@ -889,13 +918,13 @@ - // Disable CRTC write protection - outw(crtc_addr,0x0011); - // Set CRTC regs -- for(i=0;i<=CRTC_MAX_REG;i++) -+ for(i=0;i<=0x18;i++) - {outb(crtc_addr,i); -- outb(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]); -+ outb(crtc_addr+1,video_param_table[vpti].crtc_regs[i]); - } - - // Set the misc register -- outb(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg); -+ outb(VGAREG_WRITE_MISC_OUTPUT,video_param_table[vpti].miscreg); - // Enable video - outb(VGAREG_ACTL_ADDRESS,0x20); -@@ -927,9 +956,9 @@ - // Set the BIOS mem - write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode); - write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth); -- write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vga_modes[line].slength); -+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,*(Bit16u *)&video_param_table[vpti].slength_l); - write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr); -- write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1); -+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theightm1); - write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight); - write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|noclearmem)); - write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9); -@@ -937,8 +966,8 @@ - - // FIXME We nearly have the good tables. to be reworked - write_byte(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now -- write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER,0x00); -- write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2,0x00); -+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER, video_save_pointer_table); -+ write_word(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2, 0xc000); - - // FIXME - write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but... -@@ -1114,7 +1143,7 @@ - } - else - { -- address = page*vga_modes[line].slength; -+ address = page * (*(Bit16u *)&video_param_table[line_to_vpti[line]].slength_l); - } - - // CRTC regs 0x0c and 0x0d -@@ -1271,7 +1300,7 @@ - else - { - // FIXME gfx mode not complete -- cheight=vga_modes[line].cheight; -+ cheight=video_param_table[line_to_vpti[line]].cheight; - switch(vga_modes[line].memmodel) - { - case PLANAR4: -@@ -1581,7 +1610,7 @@ - else - { - // FIXME gfx mode not complete -- cheight=vga_modes[line].cheight; -+ cheight=video_param_table[line_to_vpti[line]].cheight; - bpp=vga_modes[line].pixbits; - while((count-->0) && (xcurs0) && (xcurs Date: Sun, 21 May 2006 12:46:31 +0000 Subject: ESP DMA fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1926 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 70 +++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index c0acbe678..5c8400d96 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -229,12 +229,17 @@ static int esp_write_dma_cb(ESPState *s, target_phys_addr_t phys_addr, int transfer_size1) { + int len; + if (bdrv_get_type_hint(s->bd[s->target]) == BDRV_TYPE_CDROM) { + len = transfer_size1/2048; + } else { + len = transfer_size1/512; + } DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n", s->offset, s->len, s->ti_size, transfer_size1); - bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len); - s->offset = 0; - s->len = 0; - s->target = 0; + + bdrv_write(s->bd[s->target], s->offset, s->ti_buf+s->ti_rptr, len); + s->offset+=len; return 0; } @@ -336,6 +341,7 @@ static void handle_satn(ESPState *s) bdrv_read(s->bd[target], offset, s->ti_buf, len); // XXX error handling s->ti_dir = 1; + s->ti_rptr = 0; break; } case 0x2a: @@ -359,6 +365,7 @@ static void handle_satn(ESPState *s) s->offset = offset; s->len = len; s->target = target; + s->ti_rptr = 0; // XXX error handling s->ti_dir = 0; break; @@ -415,10 +422,9 @@ static void handle_satn(ESPState *s) static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) { - uint32_t dmaptr, dmalen; + uint32_t dmaptr; - dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer status len %d\n", dmalen); + DPRINTF("Transfer status len %d\n", len); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); @@ -428,10 +434,10 @@ static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) s->rregs[6] = SEQ_CD; } else { memcpy(s->ti_buf, buf, len); - s->ti_size = dmalen; + s->ti_size = len; s->ti_rptr = 0; s->ti_wptr = 0; - s->rregs[7] = dmalen; + s->rregs[7] = len; } s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); @@ -442,34 +448,58 @@ static const uint8_t okbuf[] = {0, 0}; static void handle_ti(ESPState *s) { - uint32_t dmaptr, dmalen; + uint32_t dmaptr, dmalen, minlen, len, from, to; unsigned int i; dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer Information len %d\n", dmalen); + if (dmalen==0) { + dmalen=0x10000; + } + + minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; + DPRINTF("Transfer Information len %d\n", minlen); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); - for (i = 0; i < s->ti_size; i++) { + DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x %d %d\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr, s->ti_size, s->ti_rptr, s->ti_dir); + from = s->espdmaregs[1]; + to = from + minlen; + for (i = 0; i < minlen; i += len, from += len) { dmaptr = iommu_translate(s->espdmaregs[1] + i); + if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { + len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); + } else { + len = to - from; + } + DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); if (s->ti_dir) - cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); + cpu_physical_memory_write(dmaptr, &s->ti_buf[s->ti_rptr + i], len); else - cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); + cpu_physical_memory_read(dmaptr, &s->ti_buf[s->ti_rptr + i], len); } if (s->dma_cb) { - s->dma_cb(s, s->espdmaregs[1], dmalen); + s->dma_cb(s, s->espdmaregs[1], minlen); + } + if (minlen < s->ti_size) { + s->rregs[4] = STAT_IN | STAT_TC | (s->ti_dir ? STAT_DO : STAT_DI); + s->ti_size -= minlen; + s->ti_rptr += minlen; + } else { + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->dma_cb = NULL; + s->offset = 0; + s->len = 0; + s->target = 0; + s->ti_rptr = 0; } - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS; + s->rregs[5] = INTR_BS; s->rregs[6] = 0; + s->rregs[7] = 0; s->espdmaregs[0] |= DMA_INTR; } else { - s->ti_size = dmalen; + s->ti_size = minlen; s->ti_rptr = 0; s->ti_wptr = 0; - s->rregs[7] = dmalen; + s->rregs[7] = minlen; } pic_set_irq(s->irq, 1); } -- cgit v1.2.3 From 6650ee6d3365d7f246cd7a6523c15fb542fc6032 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 21 May 2006 13:45:09 +0000 Subject: Use lookup table for PCI class descriptions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1927 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index a287648da..ebe606814 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -409,28 +409,40 @@ void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) /***********************************************************/ /* monitor info on PCI */ +typedef struct { + uint16_t class; + const char *desc; +} pci_class_desc; + +static pci_class_desc pci_class_descriptions[] = +{ + { 0x0101, "IDE controller"}, + { 0x0200, "Ethernet controller"}, + { 0x0300, "VGA controller"}, + { 0x0600, "Host bridge"}, + { 0x0601, "ISA bridge"}, + { 0x0604, "PCI bridge"}, + { 0x0c03, "USB controller"}, + { 0, NULL} +}; + static void pci_info_device(PCIDevice *d) { int i, class; PCIIORegion *r; + pci_class_desc *desc; term_printf(" Bus %2d, device %3d, function %d:\n", d->bus->bus_num, d->devfn >> 3, d->devfn & 7); class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); term_printf(" "); - switch(class) { - case 0x0101: - term_printf("IDE controller"); - break; - case 0x0200: - term_printf("Ethernet controller"); - break; - case 0x0300: - term_printf("VGA controller"); - break; - default: + desc = pci_class_descriptions; + while (desc->desc && class != desc->class) + desc++; + if (desc->desc) { + term_printf("%s", desc->desc); + } else { term_printf("Class %04x", class); - break; } term_printf(": PCI device %04x:%04x\n", le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), -- cgit v1.2.3 From 0d92ed3022694aa6ec9172938e999871fa04f711 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 21 May 2006 16:30:15 +0000 Subject: OHCI USB host emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1928 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/pc.c | 4 +- hw/ppc_chrp.c | 6 +- hw/ppc_prep.c | 4 + hw/usb-hub.c | 13 +- hw/usb-ohci.c | 1179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb-uhci.c | 9 +- hw/usb.h | 12 +- hw/versatilepb.c | 3 + vl.c | 152 ++++--- vl.h | 6 +- 11 files changed, 1306 insertions(+), 84 deletions(-) create mode 100644 hw/usb-ohci.c diff --git a/Makefile.target b/Makefile.target index dd62f5ce6..2b346172e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -307,7 +307,7 @@ SOUND_HW += fmopl.o adlib.o endif # USB layer -VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o +VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o # PCI network cards VL_OBJS+= ne2000.o rtl8139.o diff --git a/hw/pc.c b/hw/pc.c index 6175d871a..f9a7e8637 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -40,7 +40,6 @@ static fdctrl_t *floppy_controller; static RTCState *rtc_state; static PITState *pit; static IOAPICState *ioapic; -static USBPort *usb_root_ports[2]; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -833,8 +832,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, cmos_init(ram_size, boot_device, bs_table); if (pci_enabled && usb_enabled) { - usb_uhci_init(pci_bus, usb_root_ports, piix3_devfn + 2); - usb_attach(usb_root_ports[0], vm_usb_hub); + usb_uhci_init(pci_bus, piix3_devfn + 2); } if (pci_enabled && acpi_enabled) { diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 24830457a..42d599588 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -506,7 +506,11 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, arch_name = "MAC99"; } - + + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) graphic_depth = 15; diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 9df430775..a4d7ddfe7 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -665,6 +665,10 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); #endif + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); if (nvram == NULL) return; diff --git a/hw/usb-hub.c b/hw/usb-hub.c index ec51ad929..e2cb283ef 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -179,6 +179,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) else port->wPortStatus &= ~PORT_STAT_LOW_SPEED; port->port.dev = dev; + /* send the attach message */ + dev->handle_packet(dev, + USB_MSG_ATTACH, 0, 0, NULL, 0); } else { dev = port->port.dev; if (dev) { @@ -188,6 +191,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE; } + /* send the detach message */ + dev->handle_packet(dev, + USB_MSG_DETACH, 0, 0, NULL, 0); port->port.dev = NULL; } } @@ -517,7 +523,7 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); } -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) +USBDevice *usb_hub_init(int nb_ports) { USBHubState *s; USBHubPort *port; @@ -539,12 +545,9 @@ USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) s->nb_ports = nb_ports; for(i = 0; i < s->nb_ports; i++) { port = &s->ports[i]; + qemu_register_usb_port(&port->port, s, i, usb_hub_attach); port->wPortStatus = PORT_STAT_POWER; port->wPortChange = 0; - port->port.attach = usb_hub_attach; - port->port.opaque = s; - port->port.index = i; - usb_ports[i] = &port->port; } return (USBDevice *)s; } diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c new file mode 100644 index 000000000..73d262036 --- /dev/null +++ b/hw/usb-ohci.c @@ -0,0 +1,1179 @@ +/* + * QEMU USB OHCI Emulation + * Copyright (c) 2004 Gianni Tedesco + * Copyright (c) 2006 CodeSourcery + * + * 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 + * + * TODO: + * o Isochronous transfers + * o Allocate bandwidth in frames properly + * o Disable timers when nothing needs to be done, or remove timer usage + * all together. + * o Handle unrecoverable errors properly + * o BIOS work to boot from USB storage +*/ + +#include "vl.h" + +//#define DEBUG_OHCI +/* Dump packet contents. */ +//#define DEBUG_PACKET +/* This causes frames to occur 1000x slower */ +//#define OHCI_TIME_WARP 1 + +#ifdef DEBUG_OHCI +#define dprintf printf +#else +#define dprintf(...) +#endif + +/* Number of Downstream Ports on the root hub. */ + +#define OHCI_MAX_PORTS 15 + +static int64_t usb_frame_time; +static int64_t usb_bit_time; + +typedef struct OHCIPort { + USBPort port; + uint32_t ctrl; +} OHCIPort; + +typedef struct { + struct PCIDevice pci_dev; + target_phys_addr_t mem_base; + int mem; + int num_ports; + + QEMUTimer *eof_timer; + int64_t sof_time; + + /* OHCI state */ + /* Control partition */ + uint32_t ctl, status; + uint32_t intr_status; + uint32_t intr; + + /* memory pointer partition */ + uint32_t hcca; + uint32_t ctrl_head, ctrl_cur; + uint32_t bulk_head, bulk_cur; + uint32_t per_cur; + uint32_t done; + int done_count; + + /* Frame counter partition */ + uint32_t fsmps:15; + uint32_t fit:1; + uint32_t fi:14; + uint32_t frt:1; + uint16_t frame_number; + uint16_t padding; + uint32_t pstart; + uint32_t lst; + + /* Root Hub partition */ + uint32_t rhdesc_a, rhdesc_b; + uint32_t rhstatus; + OHCIPort rhport[OHCI_MAX_PORTS]; +} OHCIState; + +/* Host Controller Communications Area */ +struct ohci_hcca { + uint32_t intr[32]; + uint16_t frame, pad; + uint32_t done; +}; + +/* Bitfields for the first word of an Endpoint Desciptor. */ +#define OHCI_ED_FA_SHIFT 0 +#define OHCI_ED_FA_MASK (0x7f<> OHCI_##field##_SHIFT) + +#define OHCI_SET_BM(val, field, newval) do { \ + val &= ~OHCI_##field##_MASK; \ + val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \ + } while(0) + +/* endpoint descriptor */ +struct ohci_ed { + uint32_t flags; + uint32_t tail; + uint32_t head; + uint32_t next; +}; + +/* General transfer descriptor */ +struct ohci_td { + uint32_t flags; + uint32_t cbp; + uint32_t next; + uint32_t be; +}; + +#define USB_HZ 12000000 + +/* OHCI Local stuff */ +#define OHCI_CTL_CBSR ((1<<0)|(1<<1)) +#define OHCI_CTL_PLE (1<<2) +#define OHCI_CTL_IE (1<<3) +#define OHCI_CTL_CLE (1<<4) +#define OHCI_CTL_BLE (1<<5) +#define OHCI_CTL_HCFS ((1<<6)|(1<<7)) +#define OHCI_USB_RESET 0x00 +#define OHCI_USB_RESUME 0x40 +#define OHCI_USB_OPERATIONAL 0x80 +#define OHCI_USB_SUSPEND 0xc0 +#define OHCI_CTL_IR (1<<8) +#define OHCI_CTL_RWC (1<<9) +#define OHCI_CTL_RWE (1<<10) + +#define OHCI_STATUS_HCR (1<<0) +#define OHCI_STATUS_CLF (1<<1) +#define OHCI_STATUS_BLF (1<<2) +#define OHCI_STATUS_OCR (1<<3) +#define OHCI_STATUS_SOC ((1<<6)|(1<<7)) + +#define OHCI_INTR_SO (1<<0) /* Scheduling overrun */ +#define OHCI_INTR_WD (1<<1) /* HcDoneHead writeback */ +#define OHCI_INTR_SF (1<<2) /* Start of frame */ +#define OHCI_INTR_RD (1<<3) /* Resume detect */ +#define OHCI_INTR_UE (1<<4) /* Unrecoverable error */ +#define OHCI_INTR_FNO (1<<5) /* Frame number overflow */ +#define OHCI_INTR_RHSC (1<<6) /* Root hub status change */ +#define OHCI_INTR_OC (1<<30) /* Ownership change */ +#define OHCI_INTR_MIE (1<<31) /* Master Interrupt Enable */ + +#define OHCI_HCCA_SIZE 0x100 +#define OHCI_HCCA_MASK 0xffffff00 + +#define OHCI_EDPTR_MASK 0xfffffff0 + +#define OHCI_FMI_FI 0x00003fff +#define OHCI_FMI_FSMPS 0xffff0000 +#define OHCI_FMI_FIT 0x80000000 + +#define OHCI_FR_RT (1<<31) + +#define OHCI_LS_THRESH 0x628 + +#define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */ +#define OHCI_RHA_PSM (1<<8) +#define OHCI_RHA_NPS (1<<9) +#define OHCI_RHA_DT (1<<10) +#define OHCI_RHA_OCPM (1<<11) +#define OHCI_RHA_NOCP (1<<12) +#define OHCI_RHA_POTPGT_MASK 0xff000000 + +#define OHCI_RHS_LPS (1<<0) +#define OHCI_RHS_OCI (1<<1) +#define OHCI_RHS_DRWE (1<<15) +#define OHCI_RHS_LPSC (1<<16) +#define OHCI_RHS_OCIC (1<<17) +#define OHCI_RHS_CRWE (1<<31) + +#define OHCI_PORT_CCS (1<<0) +#define OHCI_PORT_PES (1<<1) +#define OHCI_PORT_PSS (1<<2) +#define OHCI_PORT_POCI (1<<3) +#define OHCI_PORT_PRS (1<<4) +#define OHCI_PORT_PPS (1<<8) +#define OHCI_PORT_LSDA (1<<9) +#define OHCI_PORT_CSC (1<<16) +#define OHCI_PORT_PESC (1<<17) +#define OHCI_PORT_PSSC (1<<18) +#define OHCI_PORT_OCIC (1<<19) +#define OHCI_PORT_PRSC (1<<20) +#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \ + |OHCI_PORT_OCIC|OHCI_PORT_PRSC) + +#define OHCI_TD_DIR_SETUP 0x0 +#define OHCI_TD_DIR_OUT 0x1 +#define OHCI_TD_DIR_IN 0x2 +#define OHCI_TD_DIR_RESERVED 0x3 + +#define OHCI_CC_NOERROR 0x0 +#define OHCI_CC_CRC 0x1 +#define OHCI_CC_BITSTUFFING 0x2 +#define OHCI_CC_DATATOGGLEMISMATCH 0x3 +#define OHCI_CC_STALL 0x4 +#define OHCI_CC_DEVICENOTRESPONDING 0x5 +#define OHCI_CC_PIDCHECKFAILURE 0x6 +#define OHCI_CC_UNDEXPETEDPID 0x7 +#define OHCI_CC_DATAOVERRUN 0x8 +#define OHCI_CC_DATAUNDERRUN 0x9 +#define OHCI_CC_BUFFEROVERRUN 0xc +#define OHCI_CC_BUFFERUNDERRUN 0xd + +static void ohci_attach(USBPort *port1, USBDevice *dev) +{ + OHCIState *s = port1->opaque; + OHCIPort *port = &s->rhport[port1->index]; + + if (dev) { + if (port->port.dev) { + usb_attach(port1, NULL); + } + /* set connect status */ + if (!(port->ctrl & OHCI_PORT_CCS)) { + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + } + /* update speed */ + if (dev->speed == USB_SPEED_LOW) + port->ctrl |= OHCI_PORT_LSDA; + else + port->ctrl &= ~OHCI_PORT_LSDA; + port->port.dev = dev; + /* send the attach message */ + dev->handle_packet(dev, + USB_MSG_ATTACH, 0, 0, NULL, 0); + dprintf("usb-ohci: Attached port %d\n", port1->index); + } else { + /* set connect status */ + if (!(port->ctrl & OHCI_PORT_CCS)) { + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + } + /* disable port */ + if (port->ctrl & OHCI_PORT_PES) { + port->ctrl &= ~OHCI_PORT_PES; + port->ctrl |= OHCI_PORT_PESC; + } + dev = port->port.dev; + if (dev) { + /* send the detach message */ + dev->handle_packet(dev, + USB_MSG_DETACH, 0, 0, NULL, 0); + } + port->port.dev = NULL; + dprintf("usb-ohci: Detached port %d\n", port1->index); + } +} + +/* Reset the controller */ +static void ohci_reset(OHCIState *ohci) +{ + OHCIPort *port; + int i; + + ohci->ctl = 0; + ohci->status = 0; + ohci->intr_status = 0; + ohci->intr = OHCI_INTR_MIE; + + ohci->hcca = 0; + ohci->ctrl_head = ohci->ctrl_cur = 0; + ohci->bulk_head = ohci->bulk_cur = 0; + ohci->per_cur = 0; + ohci->done = 0; + ohci->done_count = 7; + + /* FSMPS is marked TBD in OCHI 1.0, what gives ffs? + * I took the value linux sets ... + */ + ohci->fsmps = 0x2778; + ohci->fi = 0x2edf; + ohci->fit = 0; + ohci->frt = 0; + ohci->frame_number = 0; + ohci->pstart = 0; + ohci->lst = OHCI_LS_THRESH; + + ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; + ohci->rhdesc_b = 0x0; /* Impl. specific */ + ohci->rhstatus = 0; + + for (i = 0; i < ohci->num_ports; i++) + { + port = &ohci->rhport[i]; + port->ctrl = 0; + if (port->port.dev) + ohci_attach(&port->port, port->port.dev); + } + dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); +} + +/* Update IRQ levels */ +static inline void ohci_intr_update(OHCIState *ohci) +{ + int level = 0; + + if ((ohci->intr & OHCI_INTR_MIE) && + (ohci->intr_status & ohci->intr)) + level = 1; + + pci_set_irq(&ohci->pci_dev, 0, level); +} + +/* Set an interrupt */ +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) +{ + ohci->intr_status |= intr; + ohci_intr_update(ohci); +} + +/* Get an array of dwords from main memory */ +static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) +{ + int i; + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0); + *buf = le32_to_cpu(*buf); + } + + return 1; +} + +/* Put an array of dwords in to main memory */ +static inline int put_dwords(uint32_t addr, uint32_t *buf, int num) +{ + int i; + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint32_t tmp = cpu_to_le32(*buf); + cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1); + } + + return 1; +} + +static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed) +{ + return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); +} + +static inline int ohci_read_td(uint32_t addr, struct ohci_td *td) +{ + return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); +} + +static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed) +{ + return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); +} + +static inline int ohci_put_td(uint32_t addr, struct ohci_td *td) +{ + return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); +} + +/* Read/Write the contents of a TD from/to main memory. */ +static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) +{ + uint32_t ptr; + uint32_t n; + + ptr = td->cbp; + n = 0x1000 - (ptr & 0xfff); + if (n > len) + n = len; + cpu_physical_memory_rw(ptr, buf, n, write); + if (n == len) + return; + ptr = td->be & ~0xfffu; + cpu_physical_memory_rw(ptr, buf, len - n, write); +} + +/* Service a transport descriptor. + Returns nonzero to terminate processing of this endpoint. */ + +static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) +{ + int dir; + size_t len = 0; + uint8_t buf[8192]; + char *str = NULL; + int pid; + int ret; + int i; + USBDevice *dev; + struct ohci_td td; + uint32_t addr; + int flag_r; + + addr = ed->head & OHCI_DPTR_MASK; + if (!ohci_read_td(addr, &td)) { + fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); + return 0; + } + + dir = OHCI_BM(ed->flags, ED_D); + switch (dir) { + case OHCI_TD_DIR_OUT: + case OHCI_TD_DIR_IN: + /* Same value. */ + break; + default: + dir = OHCI_BM(td.flags, TD_DP); + break; + } + + switch (dir) { + case OHCI_TD_DIR_IN: + str = "in"; + pid = USB_TOKEN_IN; + break; + case OHCI_TD_DIR_OUT: + str = "out"; + pid = USB_TOKEN_OUT; + break; + case OHCI_TD_DIR_SETUP: + str = "setup"; + pid = USB_TOKEN_SETUP; + break; + default: + fprintf(stderr, "usb-ohci: Bad direction\n"); + return 1; + } + if (td.cbp && td.be) { + len = (td.be - td.cbp) + 1; + if (len && dir != OHCI_TD_DIR_IN) { + ohci_copy_td(&td, buf, len, 0); + } + } + + flag_r = (td.flags & OHCI_TD_R) != 0; +#ifdef DEBUG_PACKET + dprintf(" TD @ 0x%.8x %u bytes %s r=%d cbp=0x%.8x be=0x%.8x\n", + addr, len, str, flag_r, td.cbp, td.be); + + if (len >= 0 && dir != OHCI_TD_DIR_IN) { + dprintf(" data:"); + for (i = 0; i < len; i++) + printf(" %.2x", buf[i]); + dprintf("\n"); + } +#endif + ret = USB_RET_NODEV; + for (i = 0; i < ohci->num_ports; i++) { + dev = ohci->rhport[i].port.dev; + if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) + continue; + + ret = dev->handle_packet(dev, pid, OHCI_BM(ed->flags, ED_FA), + OHCI_BM(ed->flags, ED_EN), buf, len); + if (ret != USB_RET_NODEV) + break; + } +#ifdef DEBUG_PACKET + dprintf("ret=%d\n", ret); +#endif + if (ret >= 0) { + if (dir == OHCI_TD_DIR_IN) { + ohci_copy_td(&td, buf, ret, 1); +#ifdef DEBUG_PACKET + dprintf(" data:"); + for (i = 0; i < ret; i++) + printf(" %.2x", buf[i]); + dprintf("\n"); +#endif + } else { + ret = len; + } + } + + /* Writeback */ + if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { + /* Transmission succeeded. */ + if (ret == len) { + td.cbp = 0; + } else { + td.cbp += ret; + if ((td.cbp & 0xfff) + ret > 0xfff) { + td.cbp &= 0xfff; + td.cbp |= td.be & ~0xfff; + } + } + td.flags |= OHCI_TD_T1; + td.flags ^= OHCI_TD_T0; + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); + OHCI_SET_BM(td.flags, TD_EC, 0); + + ed->head &= ~OHCI_ED_C; + if (td.flags & OHCI_TD_T0) + ed->head |= OHCI_ED_C; + } else { + if (ret >= 0) { + dprintf("usb-ohci: Underrun\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); + } else { + switch (ret) { + case USB_RET_NODEV: + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); + case USB_RET_NAK: + dprintf("usb-ohci: got NAK\n"); + return 1; + case USB_RET_STALL: + dprintf("usb-ohci: got STALL\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); + break; + case USB_RET_BABBLE: + dprintf("usb-ohci: got BABBLE\n"); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); + break; + default: + fprintf(stderr, "usb-ohci: Bad device response %d\n", ret); + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); + OHCI_SET_BM(td.flags, TD_EC, 3); + break; + } + } + ed->head |= OHCI_ED_H; + } + + /* Retire this TD */ + ed->head &= ~OHCI_DPTR_MASK; + ed->head |= td.next & OHCI_DPTR_MASK; + td.next = ohci->done; + ohci->done = addr; + i = OHCI_BM(td.flags, TD_DI); + if (i < ohci->done_count) + ohci->done_count = i; + ohci_put_td(addr, &td); + return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; +} + +/* Service an endpoint list. Returns nonzero if active TD were found. */ +static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) +{ + struct ohci_ed ed; + uint32_t next_ed; + uint32_t cur; + int active; + + active = 0; + + if (head == 0) + return 0; + + for (cur = head; cur; cur = next_ed) { + if (!ohci_read_ed(cur, &ed)) { + fprintf(stderr, "usb-ohci: ED read error at %x\n", cur); + return 0; + } + + next_ed = ed.next & OHCI_DPTR_MASK; + + if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) + continue; + + /* Skip isochronous endpoints. */ + if (ed.flags & OHCI_ED_F) + continue; + + while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { +#ifdef DEBUG_PACKET + dprintf("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u " + "h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur, + OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), + OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, + (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, + OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0, + (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, + ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); +#endif + active = 1; + + if (ohci_service_td(ohci, &ed)) + break; + } + + ohci_put_ed(cur, &ed); + } + + return active; +} + +/* Generate a SOF event, and set a timer for EOF */ +static void ohci_sof(OHCIState *ohci) +{ + ohci->sof_time = qemu_get_clock(vm_clock); + qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time); + ohci_set_interrupt(ohci, OHCI_INTR_SF); +} + +/* Do frame processing on frame boundary */ +static void ohci_frame_boundary(void *opaque) +{ + OHCIState *ohci = opaque; + struct ohci_hcca hcca; + + cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 0); + + /* Process all the lists at the end of the frame */ + if (ohci->ctl & OHCI_CTL_PLE) { + int n; + + n = ohci->frame_number & 0x1f; + ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n])); + } + if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { + if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) + dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); + if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { + ohci->ctrl_cur = 0; + ohci->status &= ~OHCI_STATUS_CLF; + } + } + + if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { + if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { + ohci->bulk_cur = 0; + ohci->status &= ~OHCI_STATUS_BLF; + } + } + + /* Frame boundary, so do EOF stuf here */ + ohci->frt = ohci->fit; + + /* XXX: endianness */ + ohci->frame_number = (ohci->frame_number + 1) & 0xffff; + hcca.frame = cpu_to_le32(ohci->frame_number); + + if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { + if (!ohci->done) + abort(); + if (ohci->intr & ohci->intr_status) + ohci->done |= 1; + hcca.done = cpu_to_le32(ohci->done); + ohci->done = 0; + ohci->done_count = 7; + ohci_set_interrupt(ohci, OHCI_INTR_WD); + } + + if (ohci->done_count != 7 && ohci->done_count != 0) + ohci->done_count--; + + /* Do SOF stuff here */ + ohci_sof(ohci); + + /* Writeback HCCA */ + cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 1); +} + +/* Start sending SOF tokens across the USB bus, lists are processed in + * next frame + */ +static int ohci_bus_start(OHCIState *ohci) +{ + ohci->eof_timer = qemu_new_timer(vm_clock, + ohci_frame_boundary, + ohci); + + if (ohci->eof_timer == NULL) { + fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", + ohci->pci_dev.name); + /* TODO: Signal unrecoverable error */ + return 0; + } + + dprintf("usb-ohci: %s: USB Operational\n", ohci->pci_dev.name); + + ohci_sof(ohci); + + return 1; +} + +/* Stop sending SOF tokens on the bus */ +static void ohci_bus_stop(OHCIState *ohci) +{ + if (ohci->eof_timer) + qemu_del_timer(ohci->eof_timer); +} + +/* Sets a flag in a port status register but only set it if the port is + * connected, if not set ConnectStatusChange flag. If flag is enabled + * return 1. + */ +static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val) +{ + int ret = 1; + + /* writing a 0 has no effect */ + if (val == 0) + return 0; + + /* If CurrentConnectStatus is cleared we set + * ConnectStatusChange + */ + if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) { + ohci->rhport[i].ctrl |= OHCI_PORT_CSC; + if (ohci->rhstatus & OHCI_RHS_DRWE) { + /* TODO: CSC is a wakeup event */ + } + return 0; + } + + if (ohci->rhport[i].ctrl & val) + ret = 0; + + /* set the bit */ + ohci->rhport[i].ctrl |= val; + + return ret; +} + +/* Set the frame interval - frame interval toggle is manipulated by the hcd only */ +static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) +{ + val &= OHCI_FMI_FI; + + if (val != ohci->fi) { + dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n", + ohci->pci_dev.name, ohci->fi, ohci->fi); + } + + ohci->fi = val; +} + +static void ohci_port_power(OHCIState *ohci, int i, int p) +{ + if (p) { + ohci->rhport[i].ctrl |= OHCI_PORT_PPS; + } else { + ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| + OHCI_PORT_CCS| + OHCI_PORT_PSS| + OHCI_PORT_PRS); + } +} + +/* Set HcControlRegister */ +static void ohci_set_ctl(OHCIState *ohci, uint32_t val) +{ + uint32_t old_state; + uint32_t new_state; + + old_state = ohci->ctl & OHCI_CTL_HCFS; + ohci->ctl = val; + new_state = ohci->ctl & OHCI_CTL_HCFS; + + /* no state change */ + if (old_state == new_state) + return; + + switch (new_state) { + case OHCI_USB_OPERATIONAL: + ohci_bus_start(ohci); + break; + case OHCI_USB_SUSPEND: + ohci_bus_stop(ohci); + dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name); + break; + case OHCI_USB_RESUME: + dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name); + break; + case OHCI_USB_RESET: + dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name); + break; + } +} + +static uint32_t ohci_get_frame_remaining(OHCIState *ohci) +{ + uint16_t fr; + int64_t tks; + + if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) + return (ohci->frt << 31); + + /* Being in USB operational state guarnatees sof_time was + * set already. + */ + tks = qemu_get_clock(vm_clock) - ohci->sof_time; + + /* avoid muldiv if possible */ + if (tks >= usb_frame_time) + return (ohci->frt << 31); + + tks = muldiv64(1, tks, usb_bit_time); + fr = (uint16_t)(ohci->fi - tks); + + return (ohci->frt << 31) | fr; +} + + +/* Set root hub status */ +static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) +{ + uint32_t old_state; + + old_state = ohci->rhstatus; + + /* write 1 to clear OCIC */ + if (val & OHCI_RHS_OCIC) + ohci->rhstatus &= ~OHCI_RHS_OCIC; + + if (val & OHCI_RHS_LPS) { + int i; + + for (i = 0; i < ohci->num_ports; i++) + ohci_port_power(ohci, i, 0); + dprintf("usb-ohci: powered down all ports\n"); + } + + if (val & OHCI_RHS_LPSC) { + int i; + + for (i = 0; i < ohci->num_ports; i++) + ohci_port_power(ohci, i, 1); + dprintf("usb-ohci: powered up all ports\n"); + } + + if (val & OHCI_RHS_DRWE) + ohci->rhstatus |= OHCI_RHS_DRWE; + + if (val & OHCI_RHS_CRWE) + ohci->rhstatus &= ~OHCI_RHS_DRWE; + + if (old_state != ohci->rhstatus) + ohci_set_interrupt(ohci, OHCI_INTR_RHSC); +} + +/* Set root hub port status */ +static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) +{ + uint32_t old_state; + OHCIPort *port; + + port = &ohci->rhport[portnum]; + old_state = port->ctrl; + + /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ + if (val & OHCI_PORT_WTC) + port->ctrl &= ~(val & OHCI_PORT_WTC); + + if (val & OHCI_PORT_CCS) + port->ctrl &= ~OHCI_PORT_PES; + + ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); + + if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) + dprintf("usb-ohci: port %d: SUSPEND\n", portnum); + + if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { + dprintf("usb-ohci: port %d: RESET\n", portnum); + port->port.dev->handle_packet(port->port.dev, USB_MSG_RESET, + 0, 0, NULL, 0); + port->ctrl &= ~OHCI_PORT_PRS; + /* ??? Should this also set OHCI_PORT_PESC. */ + port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; + } + + /* Invert order here to ensure in ambiguous case, device is + * powered up... + */ + if (val & OHCI_PORT_LSDA) + ohci_port_power(ohci, portnum, 0); + if (val & OHCI_PORT_PPS) + ohci_port_power(ohci, portnum, 1); + + if (old_state != port->ctrl) + ohci_set_interrupt(ohci, OHCI_INTR_RHSC); + + return; +} + +static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr) +{ + OHCIState *ohci = ptr; + + addr -= ohci->mem_base; + + /* Only aligned reads are allowed on OHCI */ + if (addr & 3) { + fprintf(stderr, "usb-ohci: Mis-aligned read\n"); + return 0xffffffff; + } + + if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { + /* HcRhPortStatus */ + return ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; + } + + switch (addr >> 2) { + case 0: /* HcRevision */ + return 0x10; + + case 1: /* HcControl */ + return ohci->ctl; + + case 2: /* HcCommandStatus */ + return ohci->status; + + case 3: /* HcInterruptStatus */ + return ohci->intr_status; + + case 4: /* HcInterruptEnable */ + case 5: /* HcInterruptDisable */ + return ohci->intr; + + case 6: /* HcHCCA */ + return ohci->hcca; + + case 7: /* HcPeriodCurrentED */ + return ohci->per_cur; + + case 8: /* HcControlHeadED */ + return ohci->ctrl_head; + + case 9: /* HcControlCurrentED */ + return ohci->ctrl_cur; + + case 10: /* HcBulkHeadED */ + return ohci->bulk_head; + + case 11: /* HcBulkCurrentED */ + return ohci->bulk_cur; + + case 12: /* HcDoneHead */ + return ohci->done; + + case 13: /* HcFmInterval */ + return (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); + + case 14: /* HcFmRemaining */ + return ohci_get_frame_remaining(ohci); + + case 15: /* HcFmNumber */ + return ohci->frame_number; + + case 16: /* HcPeriodicStart */ + return ohci->pstart; + + case 17: /* HcLSThreshold */ + return ohci->lst; + + case 18: /* HcRhDescriptorA */ + return ohci->rhdesc_a; + + case 19: /* HcRhDescriptorB */ + return ohci->rhdesc_b; + + case 20: /* HcRhStatus */ + return ohci->rhstatus; + + default: + fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr); + return 0xffffffff; + } +} + +static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) +{ + OHCIState *ohci = ptr; + + addr -= ohci->mem_base; + + /* Only aligned reads are allowed on OHCI */ + if (addr & 3) { + fprintf(stderr, "usb-ohci: Mis-aligned write\n"); + return; + } + + if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { + /* HcRhPortStatus */ + ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); + return; + } + + switch (addr >> 2) { + case 1: /* HcControl */ + ohci_set_ctl(ohci, val); + break; + + case 2: /* HcCommandStatus */ + /* SOC is read-only */ + val = (val & ~OHCI_STATUS_SOC); + + /* Bits written as '0' remain unchanged in the register */ + ohci->status |= val; + + if (ohci->status & OHCI_STATUS_HCR) + ohci_reset(ohci); + break; + + case 3: /* HcInterruptStatus */ + ohci->intr_status &= ~val; + ohci_intr_update(ohci); + break; + + case 4: /* HcInterruptEnable */ + ohci->intr |= val; + ohci_intr_update(ohci); + break; + + case 5: /* HcInterruptDisable */ + ohci->intr &= ~val; + ohci_intr_update(ohci); + break; + + case 6: /* HcHCCA */ + ohci->hcca = val & OHCI_HCCA_MASK; + break; + + case 8: /* HcControlHeadED */ + ohci->ctrl_head = val & OHCI_EDPTR_MASK; + break; + + case 9: /* HcControlCurrentED */ + ohci->ctrl_cur = val & OHCI_EDPTR_MASK; + break; + + case 10: /* HcBulkHeadED */ + ohci->bulk_head = val & OHCI_EDPTR_MASK; + break; + + case 11: /* HcBulkCurrentED */ + ohci->bulk_cur = val & OHCI_EDPTR_MASK; + break; + + case 13: /* HcFmInterval */ + ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; + ohci->fit = (val & OHCI_FMI_FIT) >> 31; + ohci_set_frame_interval(ohci, val); + break; + + case 16: /* HcPeriodicStart */ + ohci->pstart = val & 0xffff; + break; + + case 17: /* HcLSThreshold */ + ohci->lst = val & 0xffff; + break; + + case 18: /* HcRhDescriptorA */ + ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; + ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; + break; + + case 19: /* HcRhDescriptorB */ + break; + + case 20: /* HcRhStatus */ + ohci_set_hub_status(ohci, val); + break; + + default: + fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr); + break; + } +} + +/* Only dword reads are defined on OHCI register space */ +static CPUReadMemoryFunc *ohci_readfn[3]={ + ohci_mem_read, + ohci_mem_read, + ohci_mem_read +}; + +/* Only dword writes are defined on OHCI register space */ +static CPUWriteMemoryFunc *ohci_writefn[3]={ + ohci_mem_write, + ohci_mem_write, + ohci_mem_write +}; + +static void ohci_mapfunc(PCIDevice *pci_dev, int i, + uint32_t addr, uint32_t size, int type) +{ + OHCIState *ohci = (OHCIState *)pci_dev; + ohci->mem_base = addr; + cpu_register_physical_memory(addr, size, ohci->mem); +} + +void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) +{ + OHCIState *ohci; + int vid = 0x106b; + int did = 0x003f; + int i; + + + if (usb_frame_time == 0) { +#if OHCI_TIME_WARP + usb_frame_time = ticks_per_sec; + usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ/1000); +#else + usb_frame_time = muldiv64(1, ticks_per_sec, 1000); + if (ticks_per_sec >= USB_HZ) { + usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ); + } else { + usb_bit_time = 1; + } +#endif + dprintf("usb-ohci: usb_bit_time=%lli usb_frame_time=%lli\n", + usb_frame_time, usb_bit_time); + } + + ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci), + devfn, NULL, NULL); + if (ohci == NULL) { + fprintf(stderr, "usb-ohci: Failed to register PCI device\n"); + return; + } + + ohci->pci_dev.config[0x00] = vid & 0xff; + ohci->pci_dev.config[0x01] = (vid >> 8) & 0xff; + ohci->pci_dev.config[0x02] = did & 0xff; + ohci->pci_dev.config[0x03] = (did >> 8) & 0xff; + ohci->pci_dev.config[0x09] = 0x10; /* OHCI */ + ohci->pci_dev.config[0x0a] = 0x3; + ohci->pci_dev.config[0x0b] = 0xc; + ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ + + ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); + + pci_register_io_region((struct PCIDevice *)ohci, 0, 256, + PCI_ADDRESS_SPACE_MEM, ohci_mapfunc); + + ohci->num_ports = num_ports; + for (i = 0; i < num_ports; i++) { + qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); + } + + ohci_reset(ohci); +} diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index a18833da8..d3358febc 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -638,11 +638,10 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn) +void usb_uhci_init(PCIBus *bus, int devfn) { UHCIState *s; uint8_t *pci_conf; - UHCIPort *port; int i; s = (UHCIState *)pci_register_device(bus, @@ -662,11 +661,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn) pci_conf[0x60] = 0x10; // release number for(i = 0; i < NB_PORTS; i++) { - port = &s->ports[i]; - port->port.opaque = s; - port->port.index = i; - port->port.attach = uhci_attach; - usb_ports[i] = &port->port; + qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); } s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); diff --git a/hw/usb.h b/hw/usb.h index cb654e000..c92fd01b9 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -137,12 +137,15 @@ struct USBDevice { int setup_index; }; +typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev); + /* USB port on which a device can be connected */ struct USBPort { USBDevice *dev; - void (*attach)(USBPort *port, USBDevice *dev); + usb_attachfn attach; void *opaque; int index; /* internal port index, may be used with the opaque */ + struct USBPort *next; /* Used internally by qemu. */ }; void usb_attach(USBPort *port, USBDevice *dev); @@ -152,10 +155,13 @@ int usb_generic_handle_packet(USBDevice *s, int pid, int set_usb_string(uint8_t *buf, const char *str); /* usb hub */ -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports); +USBDevice *usb_hub_init(int nb_ports); /* usb-uhci.c */ -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn); +void usb_uhci_init(PCIBus *bus, int devfn); + +/* usb-ohci.c */ +void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn); /* usb-linux.c */ USBDevice *usb_host_device_open(const char *devname); diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 8a821d42d..c22e38a96 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -374,6 +374,9 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, pci_nic_init(pci_bus, nd); } } + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } pl011_init(0x101f1000, pic, 12, serial_hds[0]); pl011_init(0x101f2000, pic, 13, serial_hds[1]); diff --git a/vl.c b/vl.c index e828d316a..b641299cd 100644 --- a/vl.c +++ b/vl.c @@ -106,6 +106,9 @@ /* in ms */ #define GUI_REFRESH_INTERVAL 30 +/* Max number of USB devices that can be specified on the commandline. */ +#define MAX_USB_CMDLINE 8 + /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 @@ -145,8 +148,6 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; int win2k_install_hack = 0; #endif int usb_enabled = 0; -USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; -USBDevice *vm_usb_hub; static VLANState *first_vlan; int smp_cpus = 1; int vnc_display = -1; @@ -3249,47 +3250,71 @@ void do_info_network(void) /***********************************************************/ /* USB devices */ +static USBPort *used_usb_ports; +static USBPort *free_usb_ports; + +/* ??? Maybe change this to register a hub to keep track of the topology. */ +void qemu_register_usb_port(USBPort *port, void *opaque, int index, + usb_attachfn attach) +{ + port->opaque = opaque; + port->index = index; + port->attach = attach; + port->next = free_usb_ports; + free_usb_ports = port; +} + static int usb_device_add(const char *devname) { const char *p; USBDevice *dev; - int i; + USBPort *port; - if (!vm_usb_hub) - return -1; - for(i = 0;i < MAX_VM_USB_PORTS; i++) { - if (!vm_usb_ports[i]->dev) - break; - } - if (i == MAX_VM_USB_PORTS) + if (!free_usb_ports) return -1; if (strstart(devname, "host:", &p)) { dev = usb_host_device_open(p); - if (!dev) - return -1; } else if (!strcmp(devname, "mouse")) { dev = usb_mouse_init(); - if (!dev) - return -1; } else if (!strcmp(devname, "tablet")) { dev = usb_tablet_init(); - if (!dev) - return -1; } else { return -1; } - usb_attach(vm_usb_ports[i], dev); + if (!dev) + return -1; + + /* Find a USB port to add the device to. */ + port = free_usb_ports; + if (!port->next) { + USBDevice *hub; + + /* Create a new hub and chain it on. */ + free_usb_ports = NULL; + port->next = used_usb_ports; + used_usb_ports = port; + + hub = usb_hub_init(VM_USB_HUB_SIZE); + usb_attach(port, hub); + port = free_usb_ports; + } + + free_usb_ports = port->next; + port->next = used_usb_ports; + used_usb_ports = port; + usb_attach(port, dev); return 0; } static int usb_device_del(const char *devname) { - USBDevice *dev; - int bus_num, addr, i; + USBPort *port; + USBPort **lastp; + int bus_num, addr; const char *p; - if (!vm_usb_hub) + if (!used_usb_ports) return -1; p = strchr(devname, '.'); @@ -3299,14 +3324,21 @@ static int usb_device_del(const char *devname) addr = strtoul(p + 1, NULL, 0); if (bus_num != 0) return -1; - for(i = 0;i < MAX_VM_USB_PORTS; i++) { - dev = vm_usb_ports[i]->dev; - if (dev && dev->addr == addr) - break; + + lastp = &used_usb_ports; + port = used_usb_ports; + while (port && port->dev->addr != addr) { + lastp = &port->next; + port = port->next; } - if (i == MAX_VM_USB_PORTS) + + if (!port) return -1; - usb_attach(vm_usb_ports[i], NULL); + + *lastp = port->next; + usb_attach(port, NULL); + port->next = free_usb_ports; + free_usb_ports = port; return 0; } @@ -3329,35 +3361,34 @@ void do_usb_del(const char *devname) void usb_info(void) { USBDevice *dev; - int i; + USBPort *port; const char *speed_str; - if (!vm_usb_hub) { + if (!usb_enabled) { term_printf("USB support not enabled\n"); return; } - for(i = 0; i < MAX_VM_USB_PORTS; i++) { - dev = vm_usb_ports[i]->dev; - if (dev) { - term_printf("Hub port %d:\n", i); - switch(dev->speed) { - case USB_SPEED_LOW: - speed_str = "1.5"; - break; - case USB_SPEED_FULL: - speed_str = "12"; - break; - case USB_SPEED_HIGH: - speed_str = "480"; - break; - default: - speed_str = "?"; - break; - } - term_printf(" Device %d.%d, speed %s Mb/s\n", - 0, dev->addr, speed_str); + for (port = used_usb_ports; port; port = port->next) { + dev = port->dev; + if (!dev) + continue; + switch(dev->speed) { + case USB_SPEED_LOW: + speed_str = "1.5"; + break; + case USB_SPEED_FULL: + speed_str = "12"; + break; + case USB_SPEED_HIGH: + speed_str = "480"; + break; + default: + speed_str = "?"; + break; } + term_printf(" Device %d.%d, speed %s Mb/s\n", + 0, dev->addr, speed_str); } } @@ -5066,7 +5097,7 @@ int main(int argc, char **argv) int parallel_device_index; const char *loadvm = NULL; QEMUMachine *machine; - char usb_devices[MAX_VM_USB_PORTS][128]; + char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; LIST_INIT (&vm_change_state_head); @@ -5425,7 +5456,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_usbdevice: usb_enabled = 1; - if (usb_devices_index >= MAX_VM_USB_PORTS) { + if (usb_devices_index >= MAX_USB_CMDLINE) { fprintf(stderr, "Too many USB devices\n"); exit(1); } @@ -5596,17 +5627,6 @@ int main(int argc, char **argv) } } - /* init USB devices */ - if (usb_enabled) { - vm_usb_hub = usb_hub_init(vm_usb_ports, MAX_VM_USB_PORTS); - for(i = 0; i < usb_devices_index; i++) { - if (usb_device_add(usb_devices[i]) < 0) { - fprintf(stderr, "Warning: could not add USB device %s\n", - usb_devices[i]); - } - } - } - register_savevm("timer", 0, 1, timer_save, timer_load, NULL); register_savevm("ram", 0, 1, ram_save, ram_load, NULL); @@ -5710,6 +5730,16 @@ int main(int argc, char **argv) ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, initrd_filename); + /* init USB devices */ + if (usb_enabled) { + for(i = 0; i < usb_devices_index; i++) { + if (usb_device_add(usb_devices[i]) < 0) { + fprintf(stderr, "Warning: could not add USB device %s\n", + usb_devices[i]); + } + } + } + gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); diff --git a/vl.h b/vl.h index bdfcfb1d8..a98406504 100644 --- a/vl.h +++ b/vl.h @@ -1022,10 +1022,10 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); /* usb ports of the VM */ -#define MAX_VM_USB_PORTS 8 +void qemu_register_usb_port(USBPort *port, void *opaque, int index, + usb_attachfn attach); -extern USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; -extern USBDevice *vm_usb_hub; +#define VM_USB_HUB_SIZE 8 void do_usb_add(const char *devname); void do_usb_del(const char *devname); -- cgit v1.2.3 From e4d165c24b1975478476722a9ef384147721807a Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 21 May 2006 22:20:03 +0000 Subject: Don't clear DMA status register when loading address. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1929 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/esp.c b/hw/esp.c index 5c8400d96..30708a1a0 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -690,7 +690,7 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va val |= DMA_VER; break; case 1: - s->espdmaregs[0] = DMA_LOADED; + s->espdmaregs[0] |= DMA_LOADED; break; default: break; -- cgit v1.2.3 From 6cb7ee859a1b28aae8eab7f88908c9c9262b8a5c Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 22 May 2006 14:10:48 +0000 Subject: Only use /dev/shm hack when kqemu is enabled. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1930 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/osdep.c b/osdep.c index f2a69d9a7..ffa29fe8e 100644 --- a/osdep.c +++ b/osdep.c @@ -29,6 +29,9 @@ #include #include "cpu.h" +#if defined(USE_KQEMU) +#include "vl.h" +#endif #if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) @@ -321,13 +324,15 @@ void qemu_vfree(void *ptr) VirtualFree(ptr, 0, MEM_RELEASE); } -#elif defined(USE_KQEMU) +#else + +#if defined(USE_KQEMU) #include #include #include -void *qemu_vmalloc(size_t size) +void *kqemu_vmalloc(size_t size) { static int phys_ram_fd = -1; static int phys_ram_size = 0; @@ -362,6 +367,7 @@ void *qemu_vmalloc(size_t size) "QEMU_TMPDIR environment variable to set another directory where the QEMU\n" "temporary RAM file will be opened.\n"); } + fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n"); exit(1); } } @@ -403,16 +409,20 @@ void *qemu_vmalloc(size_t size) return ptr; } -void qemu_vfree(void *ptr) +void kqemu_vfree(void *ptr) { /* may be useful some day, but currently we do not need to free */ } -#else +#endif /* alloc shared memory pages */ void *qemu_vmalloc(size_t size) { +#if defined(USE_KQEMU) + if (kqemu_allowed) + return kqemu_vmalloc(size); +#endif #ifdef _BSD return valloc(size); #else @@ -422,6 +432,10 @@ void *qemu_vmalloc(size_t size) void qemu_vfree(void *ptr) { +#if defined(USE_KQEMU) + if (kqemu_allowed) + kqemu_vfree(ptr); +#endif free(ptr); } -- cgit v1.2.3 From 6106487019177fa2bf61fa1beab11b3b113ad858 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 22 May 2006 17:17:06 +0000 Subject: Fix USB root hub hotplugging. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1931 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-ohci.c | 53 +++++++++++++++++++++++++++++------------------------ hw/usb-uhci.c | 10 +++++----- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 73d262036..0cc27232d 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -248,19 +248,39 @@ struct ohci_td { #define OHCI_CC_BUFFEROVERRUN 0xc #define OHCI_CC_BUFFERUNDERRUN 0xd +/* Update IRQ levels */ +static inline void ohci_intr_update(OHCIState *ohci) +{ + int level = 0; + + if ((ohci->intr & OHCI_INTR_MIE) && + (ohci->intr_status & ohci->intr)) + level = 1; + + pci_set_irq(&ohci->pci_dev, 0, level); +} + +/* Set an interrupt */ +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) +{ + ohci->intr_status |= intr; + ohci_intr_update(ohci); +} + +/* Attach or detach a device on a root hub port. */ static void ohci_attach(USBPort *port1, USBDevice *dev) { OHCIState *s = port1->opaque; OHCIPort *port = &s->rhport[port1->index]; + uint32_t old_state = port->ctrl; if (dev) { if (port->port.dev) { usb_attach(port1, NULL); } /* set connect status */ - if (!(port->ctrl & OHCI_PORT_CCS)) { - port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; - } + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + /* update speed */ if (dev->speed == USB_SPEED_LOW) port->ctrl |= OHCI_PORT_LSDA; @@ -273,8 +293,9 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) dprintf("usb-ohci: Attached port %d\n", port1->index); } else { /* set connect status */ - if (!(port->ctrl & OHCI_PORT_CCS)) { - port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + if (port->ctrl & OHCI_PORT_CCS) { + port->ctrl &= ~OHCI_PORT_CCS; + port->ctrl |= OHCI_PORT_CSC; } /* disable port */ if (port->ctrl & OHCI_PORT_PES) { @@ -290,6 +311,9 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) port->port.dev = NULL; dprintf("usb-ohci: Detached port %d\n", port1->index); } + + if (old_state != port->ctrl) + ohci_set_interrupt(s, OHCI_INTR_RHSC); } /* Reset the controller */ @@ -335,25 +359,6 @@ static void ohci_reset(OHCIState *ohci) dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); } -/* Update IRQ levels */ -static inline void ohci_intr_update(OHCIState *ohci) -{ - int level = 0; - - if ((ohci->intr & OHCI_INTR_MIE) && - (ohci->intr_status & ohci->intr)) - level = 1; - - pci_set_irq(&ohci->pci_dev, 0, level); -} - -/* Set an interrupt */ -static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) -{ - ohci->intr_status |= intr; - ohci_intr_update(ohci); -} - /* Get an array of dwords from main memory */ static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) { diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index d3358febc..1a6e0130f 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -327,9 +327,8 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) usb_attach(port1, NULL); } /* set connect status */ - if (!(port->ctrl & UHCI_PORT_CCS)) { - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; - } + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + /* update speed */ if (dev->speed == USB_SPEED_LOW) port->ctrl |= UHCI_PORT_LSDA; @@ -341,8 +340,9 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) USB_MSG_ATTACH, 0, 0, NULL, 0); } else { /* set connect status */ - if (!(port->ctrl & UHCI_PORT_CCS)) { - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + if (port->ctrl & UHCI_PORT_CCS) { + port->ctrl &= ~UHCI_PORT_CCS; + port->ctrl |= UHCI_PORT_CSC; } /* disable port */ if (port->ctrl & UHCI_PORT_EN) { -- cgit v1.2.3 From cae41b10a4c7bd76e582bd9ed7fc9480b72c9709 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 22 May 2006 21:25:04 +0000 Subject: fix missing type declarations (Joachim Henke) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1932 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cocoa.m b/cocoa.m index b508b5214..65f1fc324 100644 --- a/cocoa.m +++ b/cocoa.m @@ -867,10 +867,9 @@ static void setupWindowMenu(void) /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; - } -static void CustomApplicationMain (argc, argv) +static void CustomApplicationMain(void) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; QemuCocoaGUIController *gui_controller; @@ -904,8 +903,8 @@ int main(int argc, char **argv) { gArgc = argc; gArgv = argv; - - CustomApplicationMain (argc, argv); - + + CustomApplicationMain(); + return 0; } -- cgit v1.2.3 From ea4e754f5a3c44d82ae7a09daad97e67c4b956a0 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 22 May 2006 21:50:20 +0000 Subject: PPC Breakpoints for gdb-stub (Jason Wessel) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1933 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 5 +++++ target-ppc/translate.c | 23 +++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 4b0af5587..ca1dbc5eb 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -204,6 +204,11 @@ PPC_OP(update_nip) env->nip = PARAM(1); } +PPC_OP(debug) +{ + do_raise_exception(EXCP_DEBUG); +} + /* Segment registers load and store with immediate index */ PPC_OP(load_srin) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3bc6aa376..9eb3e6197 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -148,6 +148,7 @@ typedef struct DisasContext { #endif int fpu_enabled; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ + int singlestep_enabled; } DisasContext; struct opc_handler_t { @@ -1738,10 +1739,14 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) gen_op_set_T1(dest); gen_op_b_T1(); gen_op_set_T0((long)tb + n); + if (ctx->singlestep_enabled) + gen_op_debug(); gen_op_exit_tb(); } else { gen_op_set_T1(dest); gen_op_b_T1(); + if (ctx->singlestep_enabled) + gen_op_debug(); gen_op_set_T0(0); gen_op_exit_tb(); } @@ -2520,12 +2525,22 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le; #endif ctx.fpu_enabled = msr_fp; + ctx.singlestep_enabled = env->singlestep_enabled; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; #endif /* Set env in case of segfault during code fetch */ while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == ctx.nip) { + gen_op_update_nip(ctx.nip); + gen_op_debug(); + break; + } + } + } if (search_pc) { j = gen_opc_ptr - gen_opc_buf; if (lj < j) { @@ -2616,8 +2631,12 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.exception != EXCP_TRAP)) { RET_EXCP(ctxp, EXCP_TRACE, 0); } - /* if we reach a page boundary, stop generation */ - if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { + + /* if we reach a page boundary or are single stepping, stop + * generation + */ + if (((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || + (env->singlestep_enabled)) { break; } #if defined (DO_SINGLE_STEP) -- cgit v1.2.3 From 9d05095e5fc0609bfb1f46379791abb664680e4b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 22 May 2006 22:03:52 +0000 Subject: mips cleanup (Thiemo Seufer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1934 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 ++ target-mips/helper.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 8a585c106..b6df3bef1 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -561,6 +561,8 @@ int cpu_exec(CPUState *env1) #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 diff --git a/target-mips/helper.c b/target-mips/helper.c index 752ee7275..d3c64bb7e 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -219,7 +219,6 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, exception = EXCP_TLBS; else exception = EXCP_TLBL; - error_code = 0; break; case -4: /* TLB match but 'D' bit is cleared */ @@ -350,7 +349,6 @@ void do_interrupt (CPUState *env) cause = 4; goto set_EPC; case EXCP_TLBL: - case EXCP_TLBF: cause = 2; if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) offset = 0x000; -- cgit v1.2.3 From 42fe404458731c0cf753a8d6d34d7116c08e79f7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 22 May 2006 22:05:04 +0000 Subject: dump all mips insn (Thiemo Seufer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1935 c046a42c-6fe2-441c-8c8c-71466251a162 --- mips-dis.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mips-dis.c b/mips-dis.c index f6128955c..2e7dc85d1 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -528,6 +528,7 @@ struct mips_opcode ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to test, or zero if no CPU specific ISA test is desired. */ +#if 0 #define OPCODE_IS_MEMBER(insn, isa, cpu) \ (((insn)->membership & isa) != 0 \ || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0) \ @@ -543,6 +544,10 @@ struct mips_opcode || (cpu == CPU_VR5400 && ((insn)->membership & INSN_5400) != 0) \ || (cpu == CPU_VR5500 && ((insn)->membership & INSN_5500) != 0) \ || 0) /* Please keep this term for easier source merging. */ +#else +#define OPCODE_IS_MEMBER(insn, isa, cpu) \ + (1 != 0) +#endif /* This is a list of macro expanded instructions. -- cgit v1.2.3 From 3d9fb9fefe3f4e209b57443bed18691a2c6f3e7a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 22 May 2006 22:13:29 +0000 Subject: cosmetics (Thiemo Seufer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1936 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 8 ++++---- target-mips/op_helper.c | 17 +++++++---------- target-mips/translate.c | 2 +- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index d3c64bb7e..014f35d2d 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -40,8 +40,8 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, int ret; ret = -2; - tag = (address & 0xFFFFE000); - ASID = env->CP0_EntryHi & 0x000000FF; + tag = address & 0xFFFFE000; + ASID = env->CP0_EntryHi & 0xFF; for (i = 0; i < MIPS_TLB_NB; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ @@ -74,7 +74,7 @@ int get_physical_address (CPUState *env, target_ulong *physical, int *prot, int ret; /* User mode can only access useg */ - user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0; + user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM; #if 0 if (logfile) { fprintf(logfile, "user mode %d h %08x\n", @@ -231,7 +231,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->CP0_Context = (env->CP0_Context & 0xff800000) | ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = - (env->CP0_EntryHi & 0x000000FF) | (address & 0xFFFFF000); + (env->CP0_EntryHi & 0xFF) | (address & 0xFFFFF000); env->exception_index = exception; env->error_code = error_code; ret = 1; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d9f1c9990..03e13a40f 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -330,13 +330,13 @@ void do_mtc0 (int reg, int sel) rn = "Index"; break; case 2: - val = T0 & 0x03FFFFFFF; + val = T0 & 0x3FFFFFFF; old = env->CP0_EntryLo0; env->CP0_EntryLo0 = val; rn = "EntryLo0"; break; case 3: - val = T0 & 0x03FFFFFFF; + val = T0 & 0x3FFFFFFF; old = env->CP0_EntryLo1; env->CP0_EntryLo1 = val; rn = "EntryLo1"; @@ -403,20 +403,17 @@ void do_mtc0 (int reg, int sel) old, val, env->CP0_Cause, old & mask, val & mask, env->CP0_Cause & mask); } -#if 1 if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) && !(env->hflags & MIPS_HFLAG_EXL) && !(env->hflags & MIPS_HFLAG_ERL) && - !(env->hflags & MIPS_HFLAG_DM) && + !(env->hflags & MIPS_HFLAG_DM) && (env->CP0_Status & env->CP0_Cause & mask)) { if (logfile) fprintf(logfile, "Raise pending IRQs\n"); env->interrupt_request |= CPU_INTERRUPT_HARD; - do_raise_exception(EXCP_EXT_INTERRUPT); - } else if (!(val & 0x00000001) && (old & 0x00000001)) { + } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) { env->interrupt_request &= ~CPU_INTERRUPT_HARD; } -#endif rn = "Status"; break; case 13: @@ -605,9 +602,9 @@ void do_tlbp (void) uint8_t ASID; int i; - tag = (env->CP0_EntryHi & 0xFFFFE000); - ASID = env->CP0_EntryHi & 0x000000FF; - for (i = 0; i < MIPS_TLB_NB; i++) { + tag = env->CP0_EntryHi & 0xFFFFE000; + ASID = env->CP0_EntryHi & 0xFF; + for (i = 0; i < MIPS_TLB_NB; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { diff --git a/target-mips/translate.c b/target-mips/translate.c index fd1faf149..4df691c88 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1614,7 +1614,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #if defined(CONFIG_USER_ONLY) ctx.mem_idx = 0; #else - ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1; + ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); #endif ctx.CP0_Status = env->CP0_Status; #ifdef DEBUG_DISAS -- cgit v1.2.3 From ba9a74dae0bb696ceab1ee2291cee43ef241a639 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 22 May 2006 22:14:43 +0000 Subject: fix wrong bitmasks for CP0_Context and CP0_EntryHi (Thiemo Seufer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1937 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 2 +- target-mips/op_helper.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 014f35d2d..8b60b2ce9 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -231,7 +231,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->CP0_Context = (env->CP0_Context & 0xff800000) | ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = - (env->CP0_EntryHi & 0xFF) | (address & 0xFFFFF000); + (env->CP0_EntryHi & 0xFF) | (address & 0xFFFFE000); env->exception_index = exception; env->error_code = error_code; ret = 1; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 03e13a40f..fbd693fb2 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -342,7 +342,7 @@ void do_mtc0 (int reg, int sel) rn = "EntryLo1"; break; case 4: - val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0); + val = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0); old = env->CP0_Context; env->CP0_Context = val; rn = "Context"; @@ -366,7 +366,7 @@ void do_mtc0 (int reg, int sel) rn = "Count"; break; case 10: - val = T0 & 0xFFFFF0FF; + val = T0 & 0xFFFFE0FF; old = env->CP0_EntryHi; env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ -- cgit v1.2.3 From 159f36638898f4ea671b7f56707dc6f1ec9681d4 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 22 May 2006 23:06:04 +0000 Subject: ARM undefined instruction execution (Jason Wessel) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1938 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-arm/translate.c b/target-arm/translate.c index e6e8c6835..c582d4bea 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1589,6 +1589,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0x5: case 0x6: case 0x7: + /* Check for undefined extension instructions + * per the ARM Bible IE: + * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx + */ + sh = (0xf << 20) | (0xf << 4); + if (op1 == 0x7 && ((insn & sh) == sh)) + { + goto illegal_op; + } /* load/store byte/word */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; -- cgit v1.2.3 From e6f3e5e016cc7473bc008f341d8e22bd989e03cb Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 25 May 2006 23:37:07 +0000 Subject: OHCI large packet fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1939 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-ohci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 0cc27232d..e87d9da70 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -419,6 +419,7 @@ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) if (n == len) return; ptr = td->be & ~0xfffu; + buf += n; cpu_physical_memory_rw(ptr, buf, len - n, write); } @@ -474,7 +475,12 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) return 1; } if (td.cbp && td.be) { - len = (td.be - td.cbp) + 1; + if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) { + len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff); + } else { + len = (td.be - td.cbp) + 1; + } + if (len && dir != OHCI_TD_DIR_IN) { ohci_copy_td(&td, buf, len, 0); } -- cgit v1.2.3 From 2e5d83bbef5a539f22970c2bccd19b125d82aab0 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 25 May 2006 23:58:51 +0000 Subject: Rearrange SCSI disk emulation code. Add USB mass storage device emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1940 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 +- hw/cdrom.c | 156 +++++++++++++++++++++ hw/esp.c | 417 +++++++++++--------------------------------------------- hw/ide.c | 125 +---------------- hw/scsi-disk.c | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb-hid.c | 8 +- hw/usb-hub.c | 4 +- hw/usb-msd.c | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb.c | 5 +- hw/usb.h | 6 +- usb-linux.c | 2 +- vl.c | 2 + vl.h | 17 +++ 13 files changed, 1080 insertions(+), 470 deletions(-) create mode 100644 hw/cdrom.c create mode 100644 hw/scsi-disk.c create mode 100644 hw/usb-msd.c diff --git a/Makefile.target b/Makefile.target index 2b346172e..4bf558fef 100644 --- a/Makefile.target +++ b/Makefile.target @@ -306,8 +306,11 @@ ifdef CONFIG_ADLIB SOUND_HW += fmopl.o adlib.o endif +# SCSI layer +VL_OBJS+= scsi-disk.o cdrom.o + # USB layer -VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o +VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o # PCI network cards VL_OBJS+= ne2000.o rtl8139.o diff --git a/hw/cdrom.c b/hw/cdrom.c new file mode 100644 index 000000000..a43b41790 --- /dev/null +++ b/hw/cdrom.c @@ -0,0 +1,156 @@ +/* + * QEMU ATAPI CD-ROM Emulator + * + * 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. + */ + +/* ??? Most of the ATAPI emulation is still in ide.c. It should be moved + here. */ + +#include + +static void lba_to_msf(uint8_t *buf, int lba) +{ + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; +} + +/* same toc as bochs. Return -1 if error or the toc length */ +/* XXX: check this */ +int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) +{ + uint8_t *q; + int len; + + if (start_track > 1 && start_track != 0xaa) + return -1; + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + if (start_track <= 1) { + *q++ = 0; /* reserved */ + *q++ = 0x14; /* ADR, control */ + *q++ = 1; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, 0); + q += 3; + } else { + /* sector 0 */ + cpu_to_be32wu((uint32_t *)q, 0); + q += 4; + } + } + /* lead out track */ + *q++ = 0; /* reserved */ + *q++ = 0x16; /* ADR, control */ + *q++ = 0xaa; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, nb_sectors); + q += 3; + } else { + cpu_to_be32wu((uint32_t *)q, nb_sectors); + q += 4; + } + len = q - buf; + cpu_to_be16wu((uint16_t *)buf, len - 2); + return len; +} + +/* mostly same info as PearPc */ +int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) +{ + uint8_t *q; + int len; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* first track */ + *q++ = 0x00; /* disk type */ + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa1; + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* last track */ + *q++ = 0x00; + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa2; /* lead-out */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, nb_sectors); + q += 3; + } else { + cpu_to_be32wu((uint32_t *)q, nb_sectors); + q += 4; + } + + *q++ = 1; /* session number */ + *q++ = 0x14; /* ADR, control */ + *q++ = 0; /* track number */ + *q++ = 1; /* point */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + if (msf) { + *q++ = 0; + lba_to_msf(q, 0); + q += 3; + } else { + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + } + + len = q - buf; + cpu_to_be16wu((uint16_t *)buf, len - 2); + return len; +} + + diff --git a/hw/esp.c b/hw/esp.c index 30708a1a0..787892bfe 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -38,17 +38,14 @@ do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level) #define ESPDMA_REGS 4 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) #define ESP_MAXREG 0x3f -#define TI_BUFSZ 1024*1024 // XXX +#define TI_BUFSZ 32 #define DMA_VER 0xa0000000 #define DMA_INTR 1 #define DMA_INTREN 0x10 +#define DMA_WRITE_MEM 0x100 #define DMA_LOADED 0x04000000 typedef struct ESPState ESPState; -typedef int ESPDMAFunc(ESPState *s, - target_phys_addr_t phys_addr, - int transfer_size1); - struct ESPState { BlockDriverState **bd; uint8_t rregs[ESP_MAXREG]; @@ -57,12 +54,10 @@ struct ESPState { uint32_t espdmaregs[ESPDMA_REGS]; uint32_t ti_size; uint32_t ti_rptr, ti_wptr; - int ti_dir; uint8_t ti_buf[TI_BUFSZ]; int dma; - ESPDMAFunc *dma_cb; - int64_t offset, len; - int target; + SCSIDevice *scsi_dev[MAX_DISKS]; + SCSIDevice *current_dev; }; #define STAT_DO 0x00 @@ -83,195 +78,33 @@ struct ESPState { #define SEQ_0 0x0 #define SEQ_CD 0x4 -/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */ -static void lba_to_msf(uint8_t *buf, int lba) -{ - lba += 150; - buf[0] = (lba / 75) / 60; - buf[1] = (lba / 75) % 60; - buf[2] = lba % 75; -} - -static inline void cpu_to_ube16(uint8_t *buf, int val) -{ - buf[0] = val >> 8; - buf[1] = val; -} - -static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) -{ - buf[0] = val >> 24; - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val; -} - -/* same toc as bochs. Return -1 if error or the toc length */ -/* XXX: check this */ -static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) -{ - uint8_t *q; - int len; - - if (start_track > 1 && start_track != 0xaa) - return -1; - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - if (start_track <= 1) { - *q++ = 0; /* reserved */ - *q++ = 0x14; /* ADR, control */ - *q++ = 1; /* track number */ - *q++ = 0; /* reserved */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, 0); - q += 3; - } else { - /* sector 0 */ - cpu_to_ube32(q, 0); - q += 4; - } - } - /* lead out track */ - *q++ = 0; /* reserved */ - *q++ = 0x16; /* ADR, control */ - *q++ = 0xaa; /* track number */ - *q++ = 0; /* reserved */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, nb_sectors); - q += 3; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - -/* mostly same info as PearPc */ -static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, - int session_num) -{ - uint8_t *q; - int len; - - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa0; /* lead-in */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* first track */ - *q++ = 0x00; /* disk type */ - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa1; - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* last track */ - *q++ = 0x00; - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa2; /* lead-out */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, nb_sectors); - q += 3; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - - *q++ = 1; /* session number */ - *q++ = 0x14; /* ADR, control */ - *q++ = 0; /* track number */ - *q++ = 1; /* point */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - if (msf) { - *q++ = 0; - lba_to_msf(q, 0); - q += 3; - } else { - *q++ = 0; - *q++ = 0; - *q++ = 0; - *q++ = 0; - } - - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - -static int esp_write_dma_cb(ESPState *s, - target_phys_addr_t phys_addr, - int transfer_size1) -{ - int len; - if (bdrv_get_type_hint(s->bd[s->target]) == BDRV_TYPE_CDROM) { - len = transfer_size1/2048; - } else { - len = transfer_size1/512; - } - DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n", - s->offset, s->len, s->ti_size, transfer_size1); - - bdrv_write(s->bd[s->target], s->offset, s->ti_buf+s->ti_rptr, len); - s->offset+=len; - return 0; -} - static void handle_satn(ESPState *s) { uint8_t buf[32]; uint32_t dmaptr, dmalen; - unsigned int i; - int64_t nb_sectors; int target; + int32_t datalen; dmalen = s->wregs[0] | (s->wregs[1] << 8); target = s->wregs[4] & 7; DPRINTF("Select with ATN len %d target %d\n", dmalen, target); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); + DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", + s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr); cpu_physical_memory_read(dmaptr, buf, dmalen); } else { buf[0] = 0; memcpy(&buf[1], s->ti_buf, dmalen); dmalen++; } - for (i = 0; i < dmalen; i++) { - DPRINTF("Command %2.2x\n", buf[i]); - } - s->ti_dir = 0; + s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; - if (target >= 4 || !s->bd[target]) { // No such drive + if (target >= 4 || !s->scsi_dev[target]) { + // No such drive s->rregs[4] = STAT_IN; s->rregs[5] = INTR_DC; s->rregs[6] = SEQ_0; @@ -279,141 +112,20 @@ static void handle_satn(ESPState *s) pic_set_irq(s->irq, 1); return; } - switch (buf[1]) { - case 0x0: - DPRINTF("Test Unit Ready (len %d)\n", buf[5]); - break; - case 0x12: - DPRINTF("Inquiry (len %d)\n", buf[5]); - memset(s->ti_buf, 0, 36); - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { - s->ti_buf[0] = 5; - memcpy(&s->ti_buf[16], "QEMU CDROM ", 16); - } else { - s->ti_buf[0] = 0; - memcpy(&s->ti_buf[16], "QEMU HARDDISK ", 16); - } - memcpy(&s->ti_buf[8], "QEMU ", 8); - s->ti_buf[2] = 1; - s->ti_buf[3] = 2; - s->ti_buf[4] = 32; - s->ti_dir = 1; - s->ti_size = 36; - break; - case 0x1a: - DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]); - break; - case 0x25: - DPRINTF("Read Capacity (len %d)\n", buf[5]); - memset(s->ti_buf, 0, 8); - bdrv_get_geometry(s->bd[target], &nb_sectors); - s->ti_buf[0] = (nb_sectors >> 24) & 0xff; - s->ti_buf[1] = (nb_sectors >> 16) & 0xff; - s->ti_buf[2] = (nb_sectors >> 8) & 0xff; - s->ti_buf[3] = nb_sectors & 0xff; - s->ti_buf[4] = 0; - s->ti_buf[5] = 0; - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) - s->ti_buf[6] = 8; // sector size 2048 - else - s->ti_buf[6] = 2; // sector size 512 - s->ti_buf[7] = 0; - s->ti_dir = 1; - s->ti_size = 8; - break; - case 0x28: - { - int64_t offset, len; - - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { - offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; - len = ((buf[8] << 8) | buf[9]) * 4; - s->ti_size = len * 2048; - } else { - offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; - len = (buf[8] << 8) | buf[9]; - s->ti_size = len * 512; - } - DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); - if (s->ti_size > TI_BUFSZ) { - DPRINTF("size too large %d\n", s->ti_size); - } - bdrv_read(s->bd[target], offset, s->ti_buf, len); - // XXX error handling - s->ti_dir = 1; - s->ti_rptr = 0; - break; - } - case 0x2a: - { - int64_t offset, len; - - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { - offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; - len = ((buf[8] << 8) | buf[9]) * 4; - s->ti_size = len * 2048; - } else { - offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; - len = (buf[8] << 8) | buf[9]; - s->ti_size = len * 512; - } - DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); - if (s->ti_size > TI_BUFSZ) { - DPRINTF("size too large %d\n", s->ti_size); - } - s->dma_cb = esp_write_dma_cb; - s->offset = offset; - s->len = len; - s->target = target; - s->ti_rptr = 0; - // XXX error handling - s->ti_dir = 0; - break; - } - case 0x43: - { - int start_track, format, msf, len; - - msf = buf[2] & 2; - format = buf[3] & 0xf; - start_track = buf[7]; - bdrv_get_geometry(s->bd[target], &nb_sectors); - DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); - switch(format) { - case 0: - len = cdrom_read_toc(nb_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - s->ti_size = len; - break; - case 1: - /* multi session : only a single session defined */ - memset(buf, 0, 12); - buf[1] = 0x0a; - buf[2] = 0x01; - buf[3] = 0x01; - s->ti_size = 12; - break; - case 2: - len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - s->ti_size = len; - break; - default: - error_cmd: - DPRINTF("Read TOC error\n"); - // XXX error handling - break; - } - s->ti_dir = 1; - break; + s->current_dev = s->scsi_dev[target]; + datalen = scsi_send_command(s->current_dev, 0, &buf[1]); + if (datalen == 0) { + s->ti_size = 0; + } else { + s->rregs[4] = STAT_IN | STAT_TC; + if (datalen > 0) { + s->rregs[4] |= STAT_DI; + s->ti_size = datalen; + } else { + s->rregs[4] |= STAT_DO; + s->ti_size = -datalen; } - default: - DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); - break; } - s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; s->espdmaregs[0] |= DMA_INTR; @@ -427,7 +139,8 @@ static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) DPRINTF("Transfer status len %d\n", len); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); + DPRINTF("DMA Direction: %c\n", + s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); cpu_physical_memory_write(dmaptr, buf, len); s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS | INTR_FC; @@ -446,10 +159,26 @@ static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) static const uint8_t okbuf[] = {0, 0}; +static void esp_command_complete(void *opaque, uint32_t tag, int fail) +{ + ESPState *s = (ESPState *)opaque; + + DPRINTF("SCSI Command complete\n"); + if (s->ti_size != 0) + DPRINTF("SCSI command completed unexpectedly\n"); + s->ti_size = 0; + /* ??? Report failures. */ + if (fail) + DPRINTF("Command failed\n"); + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; +} + static void handle_ti(ESPState *s) { uint32_t dmaptr, dmalen, minlen, len, from, to; unsigned int i; + int to_device; + uint8_t buf[TARGET_PAGE_SIZE]; dmalen = s->wregs[0] | (s->wregs[1] << 8); if (dmalen==0) { @@ -460,7 +189,10 @@ static void handle_ti(ESPState *s) DPRINTF("Transfer Information len %d\n", minlen); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x %d %d\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr, s->ti_size, s->ti_rptr, s->ti_dir); + /* Check if the transfer writes to to reads from the device. */ + to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; + DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n", + to_device ? 'r': 'w', dmaptr, s->ti_size); from = s->espdmaregs[1]; to = from + minlen; for (i = 0; i < minlen; i += len, from += len) { @@ -471,35 +203,23 @@ static void handle_ti(ESPState *s) len = to - from; } DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); - if (s->ti_dir) - cpu_physical_memory_write(dmaptr, &s->ti_buf[s->ti_rptr + i], len); - else - cpu_physical_memory_read(dmaptr, &s->ti_buf[s->ti_rptr + i], len); + s->ti_size -= len; + if (to_device) { + cpu_physical_memory_read(dmaptr, buf, len); + scsi_write_data(s->current_dev, buf, len); + } else { + scsi_read_data(s->current_dev, buf, len); + cpu_physical_memory_write(dmaptr, buf, len); + } } - if (s->dma_cb) { - s->dma_cb(s, s->espdmaregs[1], minlen); - } - if (minlen < s->ti_size) { - s->rregs[4] = STAT_IN | STAT_TC | (s->ti_dir ? STAT_DO : STAT_DI); + if (s->ti_size) { + s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); s->ti_size -= minlen; - s->ti_rptr += minlen; - } else { - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->dma_cb = NULL; - s->offset = 0; - s->len = 0; - s->target = 0; - s->ti_rptr = 0; } s->rregs[5] = INTR_BS; s->rregs[6] = 0; s->rregs[7] = 0; s->espdmaregs[0] |= DMA_INTR; - } else { - s->ti_size = minlen; - s->ti_rptr = 0; - s->ti_wptr = 0; - s->rregs[7] = minlen; } pic_set_irq(s->irq, 1); } @@ -514,9 +234,7 @@ static void esp_reset(void *opaque) s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; - s->ti_dir = 0; s->dma = 0; - s->dma_cb = NULL; } static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) @@ -531,7 +249,12 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) // FIFO if (s->ti_size > 0) { s->ti_size--; - s->rregs[saddr] = s->ti_buf[s->ti_rptr++]; + if ((s->rregs[4] & 6) == 0) { + /* Data in/out. */ + scsi_read_data(s->current_dev, &s->rregs[2], 0); + } else { + s->rregs[2] = s->ti_buf[s->ti_rptr++]; + } pic_set_irq(s->irq, 1); } if (s->ti_size == 0) { @@ -566,8 +289,15 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 2: // FIFO - s->ti_size++; - s->ti_buf[s->ti_wptr++] = val & 0xff; + if ((s->rregs[4] & 6) == 0) { + uint8_t buf; + buf = val & 0xff; + s->ti_size--; + scsi_write_data(s->current_dev, &buf, 0); + } else { + s->ti_size++; + s->ti_buf[s->ti_wptr++] = val & 0xff; + } break; case 3: s->rregs[saddr] = val; @@ -723,7 +453,6 @@ static void esp_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->ti_size); qemu_put_be32s(f, &s->ti_rptr); qemu_put_be32s(f, &s->ti_wptr); - qemu_put_be32s(f, &s->ti_dir); qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); qemu_put_be32s(f, &s->dma); } @@ -744,7 +473,6 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->ti_size); qemu_get_be32s(f, &s->ti_rptr); qemu_get_be32s(f, &s->ti_wptr); - qemu_get_be32s(f, &s->ti_dir); qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); qemu_get_be32s(f, &s->dma); @@ -755,6 +483,7 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd { ESPState *s; int esp_io_memory, espdma_io_memory; + int i; s = qemu_mallocz(sizeof(ESPState)); if (!s) @@ -773,5 +502,11 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd register_savevm("esp", espaddr, 1, esp_save, esp_load, s); qemu_register_reset(esp_reset, s); + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) { + s->scsi_dev[i] = + scsi_disk_init(bs_table[i], esp_command_complete, s); + } + } } diff --git a/hw/ide.c b/hw/ide.c index ed6357362..ffe0230d8 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1082,127 +1082,6 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, } } -/* same toc as bochs. Return -1 if error or the toc length */ -/* XXX: check this */ -static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track) -{ - uint8_t *q; - int nb_sectors, len; - - if (start_track > 1 && start_track != 0xaa) - return -1; - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - if (start_track <= 1) { - *q++ = 0; /* reserved */ - *q++ = 0x14; /* ADR, control */ - *q++ = 1; /* track number */ - *q++ = 0; /* reserved */ - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, 0); - q += 3; - } else { - /* sector 0 */ - cpu_to_ube32(q, 0); - q += 4; - } - } - /* lead out track */ - *q++ = 0; /* reserved */ - *q++ = 0x16; /* ADR, control */ - *q++ = 0xaa; /* track number */ - *q++ = 0; /* reserved */ - nb_sectors = s->nb_sectors >> 2; - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, nb_sectors); - q += 3; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - -/* mostly same info as PearPc */ -static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf, - int session_num) -{ - uint8_t *q; - int nb_sectors, len; - - q = buf + 2; - *q++ = 1; /* first session */ - *q++ = 1; /* last session */ - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa0; /* lead-in */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* first track */ - *q++ = 0x00; /* disk type */ - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa1; - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - *q++ = 0; - *q++ = 1; /* last track */ - *q++ = 0x00; - *q++ = 0x00; - - *q++ = 1; /* session number */ - *q++ = 0x14; /* data track */ - *q++ = 0; /* track number */ - *q++ = 0xa2; /* lead-out */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - nb_sectors = s->nb_sectors >> 2; - if (msf) { - *q++ = 0; /* reserved */ - lba_to_msf(q, nb_sectors); - q += 3; - } else { - cpu_to_ube32(q, nb_sectors); - q += 4; - } - - *q++ = 1; /* session number */ - *q++ = 0x14; /* ADR, control */ - *q++ = 0; /* track number */ - *q++ = 1; /* point */ - *q++ = 0; /* min */ - *q++ = 0; /* sec */ - *q++ = 0; /* frame */ - if (msf) { - *q++ = 0; - lba_to_msf(q, 0); - q += 3; - } else { - *q++ = 0; - *q++ = 0; - *q++ = 0; - *q++ = 0; - } - - len = q - buf; - cpu_to_ube16(buf, len - 2); - return len; -} - static void ide_atapi_cmd(IDEState *s) { const uint8_t *packet; @@ -1449,7 +1328,7 @@ static void ide_atapi_cmd(IDEState *s) start_track = packet[6]; switch(format) { case 0: - len = cdrom_read_toc(s, buf, msf, start_track); + len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1463,7 +1342,7 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 12, max_len); break; case 2: - len = cdrom_read_toc_raw(s, buf, msf, start_track); + len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c new file mode 100644 index 000000000..937eb94ec --- /dev/null +++ b/hw/scsi-disk.c @@ -0,0 +1,408 @@ +/* + * SCSI Device emulation + * + * Copyright (c) 2006 CodeSourcery. + * Based on code by Fabrice Bellard + * + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +//#define DEBUG_SCSI + +#ifdef DEBUG_SCSI +#define DPRINTF(fmt, args...) \ +do { printf("scsi-disk: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +#define BADF(fmt, args...) \ +do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) + +#include "vl.h" + +#define SENSE_NO_SENSE 0 +#define SENSE_ILLEGAL_REQUEST 5 + +struct SCSIDevice +{ + int command; + uint32_t tag; + BlockDriverState *bdrv; + int sector_size; + /* When transfering data buf_pos and buf_len contain a partially + transferred block of data (or response to a command), and + sector/sector_count identify any remaining sectors. */ + /* ??? We should probably keep track of whether the data trasfer is + a read or a write. Currently we rely on the host getting it right. */ + int sector; + int sector_count; + int buf_pos; + int buf_len; + int sense; + char buf[2048]; + scsi_completionfn completion; + void *opaque; +}; + +static void scsi_command_complete(SCSIDevice *s, int sense) +{ + s->sense = sense; + s->completion(s->opaque, s->tag, sense != SENSE_NO_SENSE); +} + +/* Read data from a scsi device. Returns nonzero on failure. */ +int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) +{ + uint32_t n; + + DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count); + if (s->buf_len == 0 && s->sector_count == 0) + return 1; + + if (s->buf_len) { + n = s->buf_len; + if (n > len) + n = len; + memcpy(data, s->buf + s->buf_pos, n); + s->buf_pos += n; + s->buf_len -= n; + data += n; + len -= n; + if (s->buf_len == 0) + s->buf_pos = 0; + } + + n = len / s->sector_size; + if (n > s->sector_count) + n = s->sector_count; + + if (n != 0) { + bdrv_read(s->bdrv, s->sector, data, n); + data += n * s->sector_size; + len -= n * s->sector_size; + s->sector += n; + s->sector_count -= n; + } + + if (len && s->sector_count) { + bdrv_read(s->bdrv, s->sector, s->buf, 1); + s->sector++; + s->sector_count--; + s->buf_pos = 0; + s->buf_len = s->sector_size; + /* Recurse to complete the partial read. */ + return scsi_read_data(s, data, len); + } + + if (len != 0) + return 1; + + if (s->buf_len == 0 && s->sector_count == 0) + scsi_command_complete(s, SENSE_NO_SENSE); + + return 0; +} + +/* Read data to a scsi device. Returns nonzero on failure. */ +int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) +{ + uint32_t n; + + DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count); + if (s->buf_pos != 0) { + BADF("Bad state on write\n"); + return 1; + } + + if (s->sector_count == 0) + return 1; + + if (s->buf_len != 0 || len < s->sector_size) { + n = s->sector_size - s->buf_len; + if (n > len) + n = len; + + memcpy(s->buf + s->buf_len, data, n); + data += n; + s->buf_len += n; + len -= n; + if (s->buf_len == s->sector_size) { + /* A full sector has been accumulated. Write it to disk. */ + bdrv_write(s->bdrv, s->sector, s->buf, 1); + s->buf_len = 0; + s->sector++; + s->sector_count--; + } + } + + n = len / s->sector_size; + if (n > s->sector_count) + n = s->sector_count; + + if (n != 0) { + bdrv_write(s->bdrv, s->sector, data, n); + data += n * s->sector_size; + len -= n * s->sector_size; + s->sector += n; + s->sector_count -= n; + } + + if (len >= s->sector_size) + return 1; + + if (len && s->sector_count) { + /* Recurse to complete the partial write. */ + return scsi_write_data(s, data, len); + } + + if (len != 0) + return 1; + + if (s->sector_count == 0) + scsi_command_complete(s, SENSE_NO_SENSE); + + return 0; +} + +/* Execute a scsi command. Returns the length of the data expected by the + command. This will be Positive for data transfers from the device + (eg. disk reads), negative for transfers to the device (eg. disk writes), + and zero if the command does not transfer any data. */ + +int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf) +{ + int64_t nb_sectors; + uint32_t lba; + uint32_t len; + int cmdlen; + int is_write; + + s->command = buf[0]; + s->tag = tag; + s->sector_count = 0; + s->buf_pos = 0; + s->buf_len = 0; + is_write = 0; + DPRINTF("Command: 0x%02x", buf[0]); + switch (s->command >> 5) { + case 0: + lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); + len = buf[4]; + cmdlen = 6; + break; + case 1: + case 2: + lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); + len = buf[8] | (buf[7] << 8); + cmdlen = 10; + break; + case 4: + lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); + len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); + cmdlen = 16; + break; + case 5: + lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24); + len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); + cmdlen = 12; + break; + default: + BADF("Unsupported command length\n"); + goto fail; + } +#ifdef DEBUG_SCSI + { + int i; + for (i = 1; i < cmdlen; i++) { + printf(" 0x%02x", buf[i]); + } + printf("\n"); + } +#endif + if (buf[1] >> 5) { + /* Only LUN 0 supported. */ + goto fail; + } + switch (s->command) { + case 0x0: + DPRINTF("Test Unit Ready\n"); + break; + case 0x03: + DPRINTF("Request Sense (len %d)\n", len); + if (len < 4) + goto fail; + memset(buf, 0, 4); + s->buf[0] = 0xf0; + s->buf[1] = 0; + s->buf[2] = s->sense; + s->buf_len = 4; + break; + case 0x12: + DPRINTF("Inquiry (len %d)\n", len); + if (len < 36) { + BADF("Inquiry buffer too small (%d)\n", len); + } + memset(s->buf, 0, 36); + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + s->buf[0] = 5; + s->buf[1] = 0x80; + memcpy(&s->buf[16], "QEMU CDROM ", 16); + } else { + s->buf[0] = 0; + memcpy(&s->buf[16], "QEMU HARDDISK ", 16); + } + memcpy(&s->buf[8], "QEMU ", 8); + s->buf[2] = 3; /* SCSI-3 */ + s->buf[3] = 2; /* Format 2 */ + s->buf[4] = 32; + s->buf_len = 36; + break; + case 0x16: + DPRINTF("Reserve(6)\n"); + if (buf[1] & 1) + goto fail; + break; + case 0x17: + DPRINTF("Release(6)\n"); + if (buf[1] & 1) + goto fail; + break; + case 0x1a: + DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[2], len); + memset(s->buf, 0, 4); + s->buf[0] = 0x16; /* Mode data length (4 + 0x12). */ + s->buf[1] = 0; /* Default media type. */ + s->buf[2] = 0; /* Write enabled. */ + s->buf[3] = 0; /* Block descriptor length. */ + /* Caching page. */ + s->buf[4 + 0] = 8; + s->buf[4 + 1] = 0x12; + s->buf[4 + 2] = 4; /* WCE */ + if (len > 0x16) + len = 0x16; + s->buf_len = len; + break; + case 0x25: + DPRINTF("Read Capacity\n"); + /* The normal LEN field for this command is zero. */ + memset(s->buf, 0, 8); + bdrv_get_geometry(s->bdrv, &nb_sectors); + s->buf[0] = (nb_sectors >> 24) & 0xff; + s->buf[1] = (nb_sectors >> 16) & 0xff; + s->buf[2] = (nb_sectors >> 8) & 0xff; + s->buf[3] = nb_sectors & 0xff; + s->buf[4] = 0; + s->buf[5] = 0; + s->buf[6] = s->sector_size >> 8; + s->buf[7] = s->sector_size & 0xff; + s->buf_len = 8; + break; + case 0x08: + case 0x28: + DPRINTF("Read (sector %d, count %d)\n", lba, len); + s->sector = lba; + s->sector_count = len; + break; + case 0x0a: + case 0x2a: + DPRINTF("Write (sector %d, count %d)\n", lba, len); + s->sector = lba; + s->sector_count = len; + is_write = 1; + break; + case 0x43: + { + int start_track, format, msf; + + msf = buf[1] & 2; + format = buf[2] & 0xf; + start_track = buf[6]; + bdrv_get_geometry(s->bdrv, &nb_sectors); + DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); + switch(format) { + case 0: + len = cdrom_read_toc(nb_sectors, s->buf, msf, start_track); + if (len < 0) + goto error_cmd; + s->buf_len = len; + break; + case 1: + /* multi session : only a single session defined */ + memset(s->buf, 0, 12); + s->buf[1] = 0x0a; + s->buf[2] = 0x01; + s->buf[3] = 0x01; + s->buf_len = 12; + break; + case 2: + len = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track); + if (len < 0) + goto error_cmd; + s->buf_len = len; + break; + default: + error_cmd: + DPRINTF("Read TOC error\n"); + goto fail; + } + break; + } + case 0x56: + DPRINTF("Reserve(10)\n"); + if (buf[1] & 3) + goto fail; + break; + case 0x57: + DPRINTF("Release(10)\n"); + if (buf[1] & 3) + goto fail; + break; + case 0xa0: + DPRINTF("Report LUNs (len %d)\n", len); + if (len < 16) + goto fail; + memset(s->buf, 0, 16); + s->buf[3] = 8; + s->buf_len = 16; + break; + default: + DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); + fail: + scsi_command_complete(s, SENSE_ILLEGAL_REQUEST); + return 0; + } + if (s->sector_count == 0 && s->buf_len == 0) { + scsi_command_complete(s, SENSE_NO_SENSE); + } + len = s->sector_count * s->sector_size + s->buf_len; + return is_write ? -len : len; +} + +void scsi_disk_destroy(SCSIDevice *s) +{ + bdrv_close(s->bdrv); + qemu_free(s); +} + +SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, + scsi_completionfn completion, + void *opaque) +{ + SCSIDevice *s; + + s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); + s->bdrv = bdrv; + s->completion = completion; + s->opaque = opaque; + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + s->sector_size = 2048; + } else { + s->sector_size = 512; + } + + return s; +} + diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 17160ebe3..883befcc3 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -323,10 +323,16 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) return l; } -static void usb_mouse_handle_reset(USBDevice *dev) +static void usb_mouse_handle_reset(USBDevice *dev, int destroy) { USBMouseState *s = (USBMouseState *)dev; + if (destroy) { + qemu_add_mouse_event_handler(NULL, NULL, 0); + qemu_free(s); + return; + } + s->dx = 0; s->dy = 0; s->dz = 0; diff --git a/hw/usb-hub.c b/hw/usb-hub.c index e2cb283ef..c69d69cc8 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -199,9 +199,11 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) } } -static void usb_hub_handle_reset(USBDevice *dev) +static void usb_hub_handle_reset(USBDevice *dev, int destroy) { /* XXX: do it */ + if (destroy) + qemu_free(dev); } static int usb_hub_handle_control(USBDevice *dev, int request, int value, diff --git a/hw/usb-msd.c b/hw/usb-msd.c new file mode 100644 index 000000000..6b4cb81eb --- /dev/null +++ b/hw/usb-msd.c @@ -0,0 +1,395 @@ +/* + * USB Mass Storage Device emulation + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +#include "vl.h" + +//#define DEBUG_MSD + +#ifdef DEBUG_MSD +#define DPRINTF(fmt, args...) \ +do { printf("usb-msd: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +/* USB requests. */ +#define MassStorageReset 0xff +#define GetMaxLun 0xfe + +enum USBMSDMode { + USB_MSDM_CBW, /* Command Block. */ + USB_MSDM_DATAOUT, /* Tranfer data to device. */ + USB_MSDM_DATAIN, /* Transfer data from device. */ + USB_MSDM_CSW /* Command Status. */ +}; + +typedef struct { + USBDevice dev; + enum USBMSDMode mode; + uint32_t data_len; + uint32_t tag; + SCSIDevice *scsi_dev; + int result; +} MSDState; + +static const uint8_t qemu_msd_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + /* Vendor and product id are arbitrary. */ + 0x00, 0x00, /* u16 idVendor; */ + 0x00, 0x00, /* u16 idProduct; */ + 0x00, 0x00, /* u16 bcdDevice */ + + 0x01, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x03, /* u8 iSerialNumber; */ + 0x01 /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_msd_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x20, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xc0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x00, /* u8 MaxPower; */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x02, /* u8 if_bNumEndpoints; */ + 0x08, /* u8 if_bInterfaceClass; MASS STORAGE */ + 0x06, /* u8 if_bInterfaceSubClass; SCSI */ + 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */ + 0x00, /* u8 if_iInterface; */ + + /* Bulk-In endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00, /* u8 ep_bInterval; */ + + /* Bulk-Out endpoint */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */ + 0x02, /* u8 ep_bmAttributes; Bulk */ + 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x00 /* u8 ep_bInterval; */ +}; + +static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail) +{ + MSDState *s = (MSDState *)opaque; + + DPRINTF("Command complete\n"); + s->result = fail; + s->mode = USB_MSDM_CSW; +} + +static void usb_msd_handle_reset(USBDevice *dev, int destroy) +{ + MSDState *s = (MSDState *)dev; + + DPRINTF("Reset\n"); + s->mode = USB_MSDM_CBW; + if (destroy) { + scsi_disk_destroy(s->scsi_dev); + qemu_free(s); + } +} + +static int usb_msd_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + MSDState *s = (MSDState *)dev; + int ret = 0; + + switch (request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_msd_dev_descriptor, + sizeof(qemu_msd_dev_descriptor)); + ret = sizeof(qemu_msd_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_msd_config_descriptor, + sizeof(qemu_msd_config_descriptor)); + ret = sizeof(qemu_msd_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* vendor description */ + ret = set_usb_string(data, "QEMU " QEMU_VERSION); + break; + case 2: + /* product description */ + ret = set_usb_string(data, "QEMU USB HARDDRIVE"); + break; + case 3: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == 0 && index != 0x81) { /* clear ep halt */ + goto fail; + } + ret = 0; + break; + /* Class specific requests. */ + case MassStorageReset: + /* Reset state ready for the next CBW. */ + s->mode = USB_MSDM_CBW; + ret = 0; + break; + case GetMaxLun: + data[0] = 0; + ret = 1; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +struct usb_msd_cbw { + uint32_t sig; + uint32_t tag; + uint32_t data_len; + uint8_t flags; + uint8_t lun; + uint8_t cmd_len; + uint8_t cmd[16]; +}; + +struct usb_msd_csw { + uint32_t sig; + uint32_t tag; + uint32_t residue; + uint8_t status; +}; + +static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, + uint8_t *data, int len) +{ + MSDState *s = (MSDState *)dev; + int ret = 0; + struct usb_msd_cbw cbw; + struct usb_msd_csw csw; + + switch (pid) { + case USB_TOKEN_OUT: + if (devep != 2) + goto fail; + + switch (s->mode) { + case USB_MSDM_CBW: + if (len != 31) { + fprintf(stderr, "usb-msd: Bad CBW size"); + goto fail; + } + memcpy(&cbw, data, 31); + if (le32_to_cpu(cbw.sig) != 0x43425355) { + fprintf(stderr, "usb-msd: Bad signature %08x\n", + le32_to_cpu(cbw.sig)); + goto fail; + } + DPRINTF("Command on LUN %d\n", cbw.lun); + if (cbw.lun != 0) { + fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); + goto fail; + } + s->tag = le32_to_cpu(cbw.tag); + s->data_len = le32_to_cpu(cbw.data_len); + if (s->data_len == 0) { + s->mode = USB_MSDM_CSW; + } else if (cbw.flags & 0x80) { + s->mode = USB_MSDM_DATAIN; + } else { + s->mode = USB_MSDM_DATAOUT; + } + DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", + s->tag, cbw.flags, cbw.cmd_len, s->data_len); + scsi_send_command(s->scsi_dev, s->tag, cbw.cmd); + ret = len; + break; + + case USB_MSDM_DATAOUT: + DPRINTF("Data out %d/%d\n", len, s->data_len); + if (len > s->data_len) + goto fail; + + if (scsi_write_data(s->scsi_dev, data, len)) + goto fail; + + s->data_len -= len; + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + ret = len; + break; + + default: + DPRINTF("Unexpected write (len %d)\n", len); + goto fail; + } + break; + + case USB_TOKEN_IN: + if (devep != 1) + goto fail; + + switch (s->mode) { + case USB_MSDM_CSW: + DPRINTF("Command status %d tag 0x%x, len %d\n", + s->result, s->tag, len); + if (len < 13) + goto fail; + + csw.sig = cpu_to_le32(0x53425355); + csw.tag = cpu_to_le32(s->tag); + csw.residue = 0; + csw.status = s->result; + memcpy(data, &csw, 13); + ret = 13; + s->mode = USB_MSDM_CBW; + break; + + case USB_MSDM_DATAIN: + DPRINTF("Data in %d/%d\n", len, s->data_len); + if (len > s->data_len) + len = s->data_len; + + if (scsi_read_data(s->scsi_dev, data, len)) + goto fail; + + s->data_len -= len; + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + ret = len; + break; + + default: + DPRINTF("Unexpected read (len %d)\n", len); + goto fail; + } + break; + + default: + DPRINTF("Bad token\n"); + fail: + ret = USB_RET_STALL; + break; + } + + return ret; +} + + +USBDevice *usb_msd_init(const char *filename) +{ + MSDState *s; + BlockDriverState *bdrv; + + s = qemu_mallocz(sizeof(MSDState)); + if (!s) + return NULL; + + bdrv = bdrv_new("usb"); + bdrv_open(bdrv, filename, 0); + + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_msd_handle_reset; + s->dev.handle_control = usb_msd_handle_control; + s->dev.handle_data = usb_msd_handle_data; + + s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); + usb_msd_handle_reset((USBDevice *)s, 0); + return (USBDevice *)s; +} diff --git a/hw/usb.c b/hw/usb.c index 34aac5fa9..a00d94532 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -55,7 +55,10 @@ int usb_generic_handle_packet(USBDevice *s, int pid, s->remote_wakeup = 0; s->addr = 0; s->state = USB_STATE_DEFAULT; - s->handle_reset(s); + s->handle_reset(s, 0); + break; + case USB_MSG_DESTROY: + s->handle_reset(s, 1); break; case USB_TOKEN_SETUP: if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) diff --git a/hw/usb.h b/hw/usb.h index c92fd01b9..abdbb45d2 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -29,6 +29,7 @@ #define USB_MSG_ATTACH 0x100 #define USB_MSG_DETACH 0x101 #define USB_MSG_RESET 0x102 +#define USB_MSG_DESTROY 0x103 #define USB_RET_NODEV (-1) #define USB_RET_NAK (-2) @@ -121,7 +122,7 @@ struct USBDevice { /* The following fields are used by the generic USB device layer. They are here just to avoid creating a new structure for them. */ - void (*handle_reset)(USBDevice *dev); + void (*handle_reset)(USBDevice *dev, int destroy); int (*handle_control)(USBDevice *dev, int request, int value, int index, int length, uint8_t *data); int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, @@ -170,3 +171,6 @@ void usb_host_info(void); /* usb-hid.c */ USBDevice *usb_mouse_init(void); USBDevice *usb_tablet_init(void); + +/* usb-msd.c */ +USBDevice *usb_msd_init(const char *filename); diff --git a/usb-linux.c b/usb-linux.c index 9cd543d71..8009a1b60 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -55,7 +55,7 @@ typedef struct USBHostDevice { int fd; } USBHostDevice; -static void usb_host_handle_reset(USBDevice *dev) +static void usb_host_handle_reset(USBDevice *dev, int destroy) { #if 0 USBHostDevice *s = (USBHostDevice *)dev; diff --git a/vl.c b/vl.c index b641299cd..5cbd1644a 100644 --- a/vl.c +++ b/vl.c @@ -3279,6 +3279,8 @@ static int usb_device_add(const char *devname) dev = usb_mouse_init(); } else if (!strcmp(devname, "tablet")) { dev = usb_tablet_init(); + } else if (strstart(devname, "disk:", &p)) { + dev = usb_msd_init(p); } else { return -1; } diff --git a/vl.h b/vl.h index a98406504..f8414ea3f 100644 --- a/vl.h +++ b/vl.h @@ -761,6 +761,10 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn); int pmac_ide_init (BlockDriverState **hd_table, SetIRQFunc *set_irq, void *irq_opaque, int irq); +/* cdrom.c */ +int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); +int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); + /* es1370.c */ int es1370_init (PCIBus *bus, AudioState *s); @@ -1031,6 +1035,19 @@ void do_usb_add(const char *devname); void do_usb_del(const char *devname); void usb_info(void); +/* scsi-disk.c */ +typedef struct SCSIDevice SCSIDevice; +typedef void (*scsi_completionfn)(void *, uint32_t, int); + +SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, + scsi_completionfn completion, + void *opaque); +void scsi_disk_destroy(SCSIDevice *s); + +int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf); +int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); +int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); + /* integratorcp.c */ extern QEMUMachine integratorcp926_machine; extern QEMUMachine integratorcp1026_machine; -- cgit v1.2.3 From 0aff66b5c8bbe89cb61df75e0511af2c1802a593 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 26 May 2006 00:49:52 +0000 Subject: Update USB documentation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1941 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 59 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index d11ccd2ad..4cb034c7c 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -309,8 +309,7 @@ USB options: Enable the USB driver (will be the default soon) @item -usbdevice devname -Add the USB device @var{devname}. See the monitor command -@code{usb_add} to have more information. +Add the USB device @var{devname}. @xref{usb_devices}. @end table Network options: @@ -783,10 +782,8 @@ Reset the system. @item usb_add devname -Plug the USB device devname to the QEMU virtual USB hub. @var{devname} -is either a virtual device name (for example @code{mouse}) or a host -USB device identifier. Host USB device identifiers have the following -syntax: @code{host:bus.addr} or @code{host:vendor_id:product_id}. +Add the USB device @var{devname}. For details of available devices see +@ref{usb_devices} @item usb_del devname @@ -1105,31 +1102,39 @@ Lawton for the plex86 Project (@url{www.plex86.org}). @node pcsys_usb @section USB emulation -QEMU emulates a PCI UHCI USB controller and a 8 port USB hub connected -to it. You can virtually plug to the hub virtual USB devices or real -host USB devices (experimental, works only on Linux hosts). +QEMU emulates a PCI UHCI USB controller. You can virtually plug +virtual USB devices or real host USB devices (experimental, works only +on Linux hosts). Qemu will automatically create and connect virtual USB hubs +as neccessary to connect multiple USB devices. -@subsection Using virtual USB devices - -A virtual USB mouse device is available for testing in QEMU. - -You can try it with the following monitor commands: - -@example -# add the mouse device -(qemu) usb_add mouse - -# show the virtual USB devices plugged on the QEMU Virtual USB hub -(qemu) info usb - Device 0.3, speed 12 Mb/s +@menu +* usb_devices:: +* host_usb_devices:: +@end menu +@node usb_devices +@subsection Connecting USB devices -# after some time you can try to remove the mouse -(qemu) usb_del 0.3 -@end example +USB devices can be connected with the @option{-usbdevice} commandline option +or the @code{usb_add} monitor command. Available devices are: -The option @option{-usbdevice} is similar to the monitor command -@code{usb_add}. +@table @var +@item @code{mouse} +Virtual Mouse. This will override the PS/2 mouse emulation when activated. +@item @code{tablet} +Pointer device that uses abolsute coordinates (like a touchscreen). +This means qemu is able to report the mouse position without having +to grab the mouse. Also overrides the PS/2 mouse emulation when activated. +@item @code{disk:file} +Mass storage device based on @var{file} (@pxref{disk_images}) +@item @code{host:bus.addr} +Pass through the host device identified by @var{bus.addr} +(Linux only) +@item @code{host:vendor_id:product_id} +Pass through the host device identified by @var{vendor_id:product_id} +(Linux only) +@end table +@node host_usb_devices @subsection Using host USB devices on a Linux host WARNING: this is an experimental feature. QEMU will slow down when -- cgit v1.2.3 From 7c22dd5216a7c1ff941e37bc30a6ade6e1370ca1 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 26 May 2006 16:46:55 +0000 Subject: Fix scsi sector size confusion (Blue Swirl). Fix short TOC read. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1942 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/scsi-disk.c | 79 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 937eb94ec..d6c7aa6f6 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -31,10 +31,13 @@ struct SCSIDevice int command; uint32_t tag; BlockDriverState *bdrv; - int sector_size; + /* The qemu block layer uses a fixed 512 byte sector size. + This is the number of 512 byte blocks in a single scsi sector. */ + int cluster_size; /* When transfering data buf_pos and buf_len contain a partially transferred block of data (or response to a command), and - sector/sector_count identify any remaining sectors. */ + sector/sector_count identify any remaining sectors. + Both sector and sector_count are in terms of qemu 512 byte blocks. */ /* ??? We should probably keep track of whether the data trasfer is a read or a write. Currently we rely on the host getting it right. */ int sector; @@ -42,7 +45,7 @@ struct SCSIDevice int buf_pos; int buf_len; int sense; - char buf[2048]; + char buf[512]; scsi_completionfn completion; void *opaque; }; @@ -75,24 +78,24 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) s->buf_pos = 0; } - n = len / s->sector_size; + n = len / 512; if (n > s->sector_count) n = s->sector_count; if (n != 0) { bdrv_read(s->bdrv, s->sector, data, n); - data += n * s->sector_size; - len -= n * s->sector_size; + data += n * 512; + len -= n * 512; s->sector += n; s->sector_count -= n; } if (len && s->sector_count) { - bdrv_read(s->bdrv, s->sector, s->buf, 1); + bdrv_read(s->bdrv, s->sector, s->buf, 512); s->sector++; s->sector_count--; s->buf_pos = 0; - s->buf_len = s->sector_size; + s->buf_len = 512; /* Recurse to complete the partial read. */ return scsi_read_data(s, data, len); } @@ -120,8 +123,8 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) if (s->sector_count == 0) return 1; - if (s->buf_len != 0 || len < s->sector_size) { - n = s->sector_size - s->buf_len; + if (s->buf_len != 0 || len < 512) { + n = 512 - s->buf_len; if (n > len) n = len; @@ -129,7 +132,7 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) data += n; s->buf_len += n; len -= n; - if (s->buf_len == s->sector_size) { + if (s->buf_len == 512) { /* A full sector has been accumulated. Write it to disk. */ bdrv_write(s->bdrv, s->sector, s->buf, 1); s->buf_len = 0; @@ -138,19 +141,19 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) } } - n = len / s->sector_size; + n = len / 512; if (n > s->sector_count) n = s->sector_count; if (n != 0) { bdrv_write(s->bdrv, s->sector, data, n); - data += n * s->sector_size; - len -= n * s->sector_size; + data += n * 512; + len -= n * 512; s->sector += n; s->sector_count -= n; } - if (len >= s->sector_size) + if (len >= 512) return 1; if (len && s->sector_count) { @@ -296,26 +299,26 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf) s->buf[3] = nb_sectors & 0xff; s->buf[4] = 0; s->buf[5] = 0; - s->buf[6] = s->sector_size >> 8; - s->buf[7] = s->sector_size & 0xff; + s->buf[6] = s->cluster_size * 2; + s->buf[7] = 0; s->buf_len = 8; break; case 0x08: case 0x28: DPRINTF("Read (sector %d, count %d)\n", lba, len); - s->sector = lba; - s->sector_count = len; + s->sector = lba * s->cluster_size; + s->sector_count = len * s->cluster_size; break; case 0x0a: case 0x2a: DPRINTF("Write (sector %d, count %d)\n", lba, len); - s->sector = lba; - s->sector_count = len; + s->sector = lba * s->cluster_size; + s->sector_count = len * s->cluster_size; is_write = 1; break; case 0x43: { - int start_track, format, msf; + int start_track, format, msf, toclen; msf = buf[1] & 2; format = buf[2] & 0xf; @@ -324,31 +327,31 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf) DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); switch(format) { case 0: - len = cdrom_read_toc(nb_sectors, s->buf, msf, start_track); - if (len < 0) - goto error_cmd; - s->buf_len = len; + toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track); break; case 1: /* multi session : only a single session defined */ + toclen = 12; memset(s->buf, 0, 12); s->buf[1] = 0x0a; s->buf[2] = 0x01; s->buf[3] = 0x01; - s->buf_len = 12; break; case 2: - len = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track); - if (len < 0) - goto error_cmd; - s->buf_len = len; + toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track); break; default: - error_cmd: - DPRINTF("Read TOC error\n"); - goto fail; + goto error_cmd; + } + if (toclen > 0) { + if (len > toclen) + len = toclen; + s->buf_len = len; + break; } - break; + error_cmd: + DPRINTF("Read TOC error\n"); + goto fail; } case 0x56: DPRINTF("Reserve(10)\n"); @@ -377,7 +380,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf) if (s->sector_count == 0 && s->buf_len == 0) { scsi_command_complete(s, SENSE_NO_SENSE); } - len = s->sector_count * s->sector_size + s->buf_len; + len = s->sector_count * 512 + s->buf_len; return is_write ? -len : len; } @@ -398,9 +401,9 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, s->completion = completion; s->opaque = opaque; if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { - s->sector_size = 2048; + s->cluster_size = 4; } else { - s->sector_size = 512; + s->cluster_size = 1; } return s; -- cgit v1.2.3 From 4be9a500e7db7a16807d7bbeaa9e7f87ab4af5f7 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 26 May 2006 17:15:13 +0000 Subject: Fix partial transfer bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1943 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/esp.c b/hw/esp.c index 787892bfe..68e15dd81 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -214,7 +214,6 @@ static void handle_ti(ESPState *s) } if (s->ti_size) { s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); - s->ti_size -= minlen; } s->rregs[5] = INTR_BS; s->rregs[6] = 0; -- cgit v1.2.3 From cac782d496c0160aba9ae8df53a3504599a4c721 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 26 May 2006 18:08:11 +0000 Subject: Small read fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1944 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/scsi-disk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index d6c7aa6f6..9285c18ce 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -91,7 +91,7 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) } if (len && s->sector_count) { - bdrv_read(s->bdrv, s->sector, s->buf, 512); + bdrv_read(s->bdrv, s->sector, s->buf, 1); s->sector++; s->sector_count--; s->buf_pos = 0; -- cgit v1.2.3 From 0fc5c15a4fad2dac00126c802554d9ca33c4ccc7 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 26 May 2006 21:53:41 +0000 Subject: SCSI lun probing fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1945 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 31 +++++++++++++++++-------------- hw/scsi-disk.c | 7 ++++--- hw/usb-msd.c | 2 +- vl.h | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 68e15dd81..908767943 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -55,6 +55,7 @@ struct ESPState { uint32_t ti_size; uint32_t ti_rptr, ti_wptr; uint8_t ti_buf[TI_BUFSZ]; + int sense; int dma; SCSIDevice *scsi_dev[MAX_DISKS]; SCSIDevice *current_dev; @@ -84,6 +85,7 @@ static void handle_satn(ESPState *s) uint32_t dmaptr, dmalen; int target; int32_t datalen; + int lun; dmalen = s->wregs[0] | (s->wregs[1] << 8); target = s->wregs[4] & 7; @@ -98,6 +100,8 @@ static void handle_satn(ESPState *s) memcpy(&buf[1], s->ti_buf, dmalen); dmalen++; } + DPRINTF("busid 0x%x\n", buf[0]); + lun = buf[0] & 7; s->ti_size = 0; s->ti_rptr = 0; @@ -113,7 +117,7 @@ static void handle_satn(ESPState *s) return; } s->current_dev = s->scsi_dev[target]; - datalen = scsi_send_command(s->current_dev, 0, &buf[1]); + datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); if (datalen == 0) { s->ti_size = 0; } else { @@ -132,34 +136,33 @@ static void handle_satn(ESPState *s) pic_set_irq(s->irq, 1); } -static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) +static void write_response(ESPState *s) { uint32_t dmaptr; - DPRINTF("Transfer status len %d\n", len); + DPRINTF("Transfer status (sense=%d)\n", s->sense); + s->ti_buf[0] = s->sense; + s->ti_buf[1] = 0; if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); - cpu_physical_memory_write(dmaptr, buf, len); + cpu_physical_memory_write(dmaptr, s->ti_buf, 2); s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; } else { - memcpy(s->ti_buf, buf, len); - s->ti_size = len; + s->ti_size = 2; s->ti_rptr = 0; s->ti_wptr = 0; - s->rregs[7] = len; + s->rregs[7] = 2; } s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); } -static const uint8_t okbuf[] = {0, 0}; - -static void esp_command_complete(void *opaque, uint32_t tag, int fail) +static void esp_command_complete(void *opaque, uint32_t tag, int sense) { ESPState *s = (ESPState *)opaque; @@ -167,9 +170,9 @@ static void esp_command_complete(void *opaque, uint32_t tag, int fail) if (s->ti_size != 0) DPRINTF("SCSI command completed unexpectedly\n"); s->ti_size = 0; - /* ??? Report failures. */ - if (fail) + if (sense) DPRINTF("Command failed\n"); + s->sense = sense; s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; } @@ -333,11 +336,11 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 0x11: DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); - dma_write(s, okbuf, 2); + write_response(s); break; case 0x12: DPRINTF("Message Accepted (%2.2x)\n", val); - dma_write(s, okbuf, 2); + write_response(s); s->rregs[5] = INTR_DC; s->rregs[6] = 0; break; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 9285c18ce..c15486b2b 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -53,7 +53,7 @@ struct SCSIDevice static void scsi_command_complete(SCSIDevice *s, int sense) { s->sense = sense; - s->completion(s->opaque, s->tag, sense != SENSE_NO_SENSE); + s->completion(s->opaque, s->tag, sense); } /* Read data from a scsi device. Returns nonzero on failure. */ @@ -175,7 +175,7 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) (eg. disk reads), negative for transfers to the device (eg. disk writes), and zero if the command does not transfer any data. */ -int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf) +int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) { int64_t nb_sectors; uint32_t lba; @@ -225,8 +225,9 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf) printf("\n"); } #endif - if (buf[1] >> 5) { + if (lun || buf[1] >> 5) { /* Only LUN 0 supported. */ + DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); goto fail; } switch (s->command) { diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 6b4cb81eb..bcca6d4ed 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -295,7 +295,7 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, } DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", s->tag, cbw.flags, cbw.cmd_len, s->data_len); - scsi_send_command(s->scsi_dev, s->tag, cbw.cmd); + scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); ret = len; break; diff --git a/vl.h b/vl.h index f8414ea3f..26e009fdc 100644 --- a/vl.h +++ b/vl.h @@ -1044,7 +1044,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, void *opaque); void scsi_disk_destroy(SCSIDevice *s); -int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf); +int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); -- cgit v1.2.3 From 7d8406be69ce936839300159fcf2a0c4863f7f08 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 30 May 2006 01:48:12 +0000 Subject: PCI SCSI HBA emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1946 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/lsi53c895a.c | 1571 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.c | 18 + hw/scsi-disk.c | 42 +- hw/versatilepb.c | 7 + vl.h | 4 + 6 files changed, 1629 insertions(+), 15 deletions(-) create mode 100644 hw/lsi53c895a.c diff --git a/Makefile.target b/Makefile.target index 4bf558fef..6d284d8ef 100644 --- a/Makefile.target +++ b/Makefile.target @@ -307,7 +307,7 @@ SOUND_HW += fmopl.o adlib.o endif # SCSI layer -VL_OBJS+= scsi-disk.o cdrom.o +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 diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c new file mode 100644 index 000000000..24dff0eff --- /dev/null +++ b/hw/lsi53c895a.c @@ -0,0 +1,1571 @@ +/* + * QEMU LSI53C895A SCSI Host Bus Adapter emulation + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +/* ??? Need to check if the {read,write}[wl] routines work properly on + big-endian targets. */ + +#include "vl.h" + +//#define DEBUG_LSI +//#define DEBUG_LSI_REG + +#ifdef DEBUG_LSI +#define DPRINTF(fmt, args...) \ +do { printf("lsi_scsi: " fmt , ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "lsi_scsi: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) +#endif + +#define LSI_SCNTL0_TRG 0x01 +#define LSI_SCNTL0_AAP 0x02 +#define LSI_SCNTL0_EPC 0x08 +#define LSI_SCNTL0_WATN 0x10 +#define LSI_SCNTL0_START 0x20 + +#define LSI_SCNTL1_SST 0x01 +#define LSI_SCNTL1_IARB 0x02 +#define LSI_SCNTL1_AESP 0x04 +#define LSI_SCNTL1_RST 0x08 +#define LSI_SCNTL1_CON 0x10 +#define LSI_SCNTL1_DHP 0x20 +#define LSI_SCNTL1_ADB 0x40 +#define LSI_SCNTL1_EXC 0x80 + +#define LSI_SCNTL2_WSR 0x01 +#define LSI_SCNTL2_VUE0 0x02 +#define LSI_SCNTL2_VUE1 0x04 +#define LSI_SCNTL2_WSS 0x08 +#define LSI_SCNTL2_SLPHBEN 0x10 +#define LSI_SCNTL2_SLPMD 0x20 +#define LSI_SCNTL2_CHM 0x40 +#define LSI_SCNTL2_SDU 0x80 + +#define LSI_ISTAT0_DIP 0x01 +#define LSI_ISTAT0_SIP 0x02 +#define LSI_ISTAT0_INTF 0x04 +#define LSI_ISTAT0_CON 0x08 +#define LSI_ISTAT0_SEM 0x10 +#define LSI_ISTAT0_SIGP 0x20 +#define LSI_ISTAT0_SRST 0x40 +#define LSI_ISTAT0_ABRT 0x80 + +#define LSI_ISTAT1_SI 0x01 +#define LSI_ISTAT1_SRUN 0x02 +#define LSI_ISTAT1_FLSH 0x04 + +#define LSI_SSTAT0_SDP0 0x01 +#define LSI_SSTAT0_RST 0x02 +#define LSI_SSTAT0_WOA 0x04 +#define LSI_SSTAT0_LOA 0x08 +#define LSI_SSTAT0_AIP 0x10 +#define LSI_SSTAT0_OLF 0x20 +#define LSI_SSTAT0_ORF 0x40 +#define LSI_SSTAT0_ILF 0x80 + +#define LSI_SIST0_PAR 0x01 +#define LSI_SIST0_RST 0x02 +#define LSI_SIST0_UDC 0x04 +#define LSI_SIST0_SGE 0x08 +#define LSI_SIST0_RSL 0x10 +#define LSI_SIST0_SEL 0x20 +#define LSI_SIST0_CMP 0x40 +#define LSI_SIST0_MA 0x80 + +#define LSI_SIST1_HTH 0x01 +#define LSI_SIST1_GEN 0x02 +#define LSI_SIST1_STO 0x04 +#define LSI_SIST1_SBMC 0x10 + +#define LSI_SOCL_IO 0x01 +#define LSI_SOCL_CD 0x02 +#define LSI_SOCL_MSG 0x04 +#define LSI_SOCL_ATN 0x08 +#define LSI_SOCL_SEL 0x10 +#define LSI_SOCL_BSY 0x20 +#define LSI_SOCL_ACK 0x40 +#define LSI_SOCL_REQ 0x80 + +#define LSI_DSTAT_IID 0x01 +#define LSI_DSTAT_SIR 0x04 +#define LSI_DSTAT_SSI 0x08 +#define LSI_DSTAT_ABRT 0x10 +#define LSI_DSTAT_BF 0x20 +#define LSI_DSTAT_MDPE 0x40 +#define LSI_DSTAT_DFE 0x80 + +#define LSI_DCNTL_COM 0x01 +#define LSI_DCNTL_IRQD 0x02 +#define LSI_DCNTL_STD 0x04 +#define LSI_DCNTL_IRQM 0x08 +#define LSI_DCNTL_SSM 0x10 +#define LSI_DCNTL_PFEN 0x20 +#define LSI_DCNTL_PFF 0x40 +#define LSI_DCNTL_CLSE 0x80 + +#define LSI_DMODE_MAN 0x01 +#define LSI_DMODE_BOF 0x02 +#define LSI_DMODE_ERMP 0x04 +#define LSI_DMODE_ERL 0x08 +#define LSI_DMODE_DIOM 0x10 +#define LSI_DMODE_SIOM 0x20 + +#define LSI_CTEST2_DACK 0x01 +#define LSI_CTEST2_DREQ 0x02 +#define LSI_CTEST2_TEOP 0x04 +#define LSI_CTEST2_PCICIE 0x08 +#define LSI_CTEST2_CM 0x10 +#define LSI_CTEST2_CIO 0x20 +#define LSI_CTEST2_SIGP 0x40 +#define LSI_CTEST2_DDIR 0x80 + +#define LSI_CTEST5_BL2 0x04 +#define LSI_CTEST5_DDIR 0x08 +#define LSI_CTEST5_MASR 0x10 +#define LSI_CTEST5_DFSN 0x20 +#define LSI_CTEST5_BBCK 0x40 +#define LSI_CTEST5_ADCK 0x80 + +#define LSI_CCNTL0_DILS 0x01 +#define LSI_CCNTL0_DISFC 0x10 +#define LSI_CCNTL0_ENNDJ 0x20 +#define LSI_CCNTL0_PMJCTL 0x40 +#define LSI_CCNTL0_ENPMJ 0x80 + +#define PHASE_DO 0 +#define PHASE_DI 1 +#define PHASE_CMD 2 +#define PHASE_ST 3 +#define PHASE_MO 6 +#define PHASE_MI 7 +#define PHASE_MASK 7 + +/* The HBA is ID 7, so for simplicitly limit to 7 devices. */ +#define LSI_MAX_DEVS 7 + +typedef struct { + PCIDevice pci_dev; + int mmio_io_addr; + int ram_io_addr; + uint32_t script_ram_base; + uint32_t data_len; + + int carry; /* ??? Should this be an a visible register somewhere? */ + int sense; + uint8_t msg; + /* Nonzero if a Wait Reselect instruction has been issued. */ + int waiting; + SCSIDevice *scsi_dev[LSI_MAX_DEVS]; + SCSIDevice *current_dev; + int current_lun; + + uint32_t dsa; + uint32_t temp; + uint32_t dnad; + uint32_t dbc; + uint8_t istat0; + uint8_t istat1; + uint8_t dcmd; + uint8_t dstat; + uint8_t dien; + uint8_t sist0; + uint8_t sist1; + uint8_t sien0; + uint8_t sien1; + uint8_t mbox0; + uint8_t mbox1; + uint8_t dfifo; + uint8_t ctest3; + uint8_t ctest4; + uint8_t ctest5; + uint8_t ccntl0; + uint8_t ccntl1; + uint32_t dsp; + uint32_t dsps; + uint8_t dmode; + uint8_t dcntl; + uint8_t scntl0; + uint8_t scntl1; + uint8_t scntl2; + uint8_t scntl3; + uint8_t sstat0; + uint8_t sstat1; + uint8_t scid; + uint8_t sxfer; + uint8_t socl; + uint8_t sdid; + uint8_t sfbr; + uint8_t stest1; + uint8_t stest2; + uint8_t stest3; + uint8_t stime0; + uint8_t respid0; + uint8_t respid1; + uint32_t mmrs; + uint32_t mmws; + uint32_t sfs; + uint32_t drs; + uint32_t sbms; + uint32_t dmbs; + uint32_t dnad64; + uint32_t pmjad1; + uint32_t pmjad2; + uint32_t rbc; + uint32_t ua; + uint32_t ia; + uint32_t sbc; + uint32_t csbc; + uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ + + /* Script ram is stored as 32-bit words in host byteorder. */ + uint32_t script_ram[2048]; +} LSIState; + +static void lsi_soft_reset(LSIState *s) +{ + DPRINTF("Reset\n"); + s->carry = 0; + + s->waiting = 0; + s->dsa = 0; + s->dnad = 0; + s->dbc = 0; + s->temp = 0; + memset(s->scratch, 0, sizeof(s->scratch)); + s->istat0 = 0; + s->istat1 = 0; + s->dcmd = 0; + s->dstat = 0; + s->dien = 0; + s->sist0 = 0; + s->sist1 = 0; + s->sien0 = 0; + s->sien1 = 0; + s->mbox0 = 0; + s->mbox1 = 0; + s->dfifo = 0; + s->ctest3 = 0; + s->ctest4 = 0; + s->ctest5 = 0; + s->ccntl0 = 0; + s->ccntl1 = 0; + s->dsp = 0; + s->dsps = 0; + s->dmode = 0; + s->dcntl = 0; + s->scntl0 = 0xc0; + s->scntl1 = 0; + s->scntl2 = 0; + s->scntl3 = 0; + s->sstat0 = 0; + s->sstat1 = 0; + s->scid = 7; + s->sxfer = 0; + s->socl = 0; + s->stest1 = 0; + s->stest2 = 0; + s->stest3 = 0; + s->stime0 = 0; + s->respid0 = 0x80; + s->respid1 = 0; + s->mmrs = 0; + s->mmws = 0; + s->sfs = 0; + s->drs = 0; + s->sbms = 0; + s->dmbs = 0; + s->dnad64 = 0; + s->pmjad1 = 0; + s->pmjad2 = 0; + s->rbc = 0; + s->ua = 0; + s->ia = 0; + s->sbc = 0; + s->csbc = 0; +} + +static uint8_t lsi_reg_readb(LSIState *s, int offset); +static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); + +static inline uint32_t read_dword(LSIState *s, uint32_t addr) +{ + uint32_t buf; + + /* Optimize reading from SCRIPTS RAM. */ + if ((addr & 0xffffe000) == s->script_ram_base) { + return s->script_ram[(addr & 0x1fff) >> 2]; + } + cpu_physical_memory_read(addr, (uint8_t *)&buf, 4); + return cpu_to_le32(buf); +} + +static void lsi_stop_script(LSIState *s) +{ + s->istat1 &= ~LSI_ISTAT1_SRUN; +} + +static void lsi_update_irq(LSIState *s) +{ + int level; + static int last_level; + + /* It's unclear whether the DIP/SIP bits should be cleared when the + Interrupt Status Registers are cleared or when istat0 is read. + We currently do the formwer, which seems to work. */ + level = 0; + if (s->dstat) { + if (s->dstat & s->dien) + level = 1; + s->istat0 |= LSI_ISTAT0_DIP; + } else { + s->istat0 &= ~LSI_ISTAT0_DIP; + } + + if (s->sist0 || s->sist1) { + if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1)) + level = 1; + s->istat0 |= LSI_ISTAT0_SIP; + } else { + s->istat0 &= ~LSI_ISTAT0_SIP; + } + if (s->istat0 & LSI_ISTAT0_INTF) + level = 1; + + if (level != last_level) { + DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n", + level, s->dstat, s->sist1, s->sist0); + last_level = level; + } + pci_set_irq(&s->pci_dev, 0, level); +} + +/* Stop SCRIPTS execution and raise a SCSI interrupt. */ +static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1) +{ + uint32_t mask0; + uint32_t mask1; + + DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", + stat1, stat0, s->sist1, s->sist0); + s->sist0 |= stat0; + s->sist1 |= stat1; + /* Stop processor on fatal or unmasked interrupt. As a special hack + we don't stop processing when raising STO. Instead continue + execution and stop at the next insn that accesses the SCSI bus. */ + mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL); + mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH); + mask1 &= ~LSI_SIST1_STO; + if (s->sist0 & mask0 || s->sist1 & mask1) { + lsi_stop_script(s); + } + lsi_update_irq(s); +} + +/* Stop SCRIPTS execution and raise a DMA interrupt. */ +static void lsi_script_dma_interrupt(LSIState *s, int stat) +{ + DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat); + s->dstat |= stat; + lsi_update_irq(s); + lsi_stop_script(s); +} + +static inline void lsi_set_phase(LSIState *s, int phase) +{ + s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase; +} + +static void lsi_bad_phase(LSIState *s, int out, int new_phase) +{ + /* Trigger a phase mismatch. */ + if (s->ccntl0 & LSI_CCNTL0_ENPMJ) { + if ((s->ccntl0 & LSI_CCNTL0_PMJCTL) || out) { + s->dsp = s->pmjad1; + } else { + s->dsp = s->pmjad2; + } + DPRINTF("Data phase mismatch jump to %08x\n", s->dsp); + } else { + DPRINTF("Phase mismatch interrupt\n"); + lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0); + lsi_stop_script(s); + } + lsi_set_phase(s, new_phase); +} + +static void lsi_do_dma(LSIState *s, int out) +{ + uint8_t buf[TARGET_PAGE_SIZE]; + uint32_t addr; + uint32_t count; + int n; + + count = s->dbc; + addr = s->dnad; + DPRINTF("DMA %s addr=0x%08x len=%d avail=%d\n", out ? "out" : "in", + addr, count, s->data_len); + /* ??? Too long transfers are truncated. Don't know if this is the + correct behavior. */ + if (count > s->data_len) { + /* If the DMA length is greater then the device data length then + a phase mismatch will occur. */ + count = s->data_len; + s->dbc = count; + lsi_bad_phase(s, out, PHASE_ST); + } + + s->csbc += count; + + /* ??? Set SFBR to first data byte. */ + while (count) { + n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count; + if (out) { + cpu_physical_memory_read(addr, buf, n); + scsi_write_data(s->current_dev, buf, n); + } else { + scsi_read_data(s->current_dev, buf, n); + cpu_physical_memory_write(addr, buf, n); + } + addr += n; + count -= n; + } +} + + +static void lsi_do_command(LSIState *s) +{ + uint8_t buf[16]; + int n; + + DPRINTF("Send command len=%d\n", s->dbc); + if (s->dbc > 16) + s->dbc = 16; + cpu_physical_memory_read(s->dnad, buf, s->dbc); + s->sfbr = buf[0]; + n = scsi_send_command(s->current_dev, 0, buf, s->current_lun); + if (n > 0) { + s->data_len = n; + lsi_set_phase(s, PHASE_DI); + } else if (n < 0) { + s->data_len = -n; + lsi_set_phase(s, PHASE_DO); + } +} + +static void lsi_command_complete(void *opaque, uint32_t tag, int sense) +{ + LSIState *s = (LSIState *)opaque; + + DPRINTF("Command complete sense=%d\n", sense); + s->sense = sense; + lsi_set_phase(s, PHASE_ST); +} + +static void lsi_do_status(LSIState *s) +{ + DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); + if (s->dbc != 1) + BADF("Bad Status move\n"); + s->dbc = 1; + s->msg = s->sense; + cpu_physical_memory_write(s->dnad, &s->msg, 1); + s->sfbr = s->msg; + lsi_set_phase(s, PHASE_MI); + s->msg = 0; /* COMMAND COMPLETE */ +} + +static void lsi_disconnect(LSIState *s) +{ + s->scntl1 &= ~LSI_SCNTL1_CON; + s->sstat1 &= ~PHASE_MASK; +} + +static void lsi_do_msgin(LSIState *s) +{ + DPRINTF("Message in len=%d\n", s->dbc); + s->dbc = 1; + s->sfbr = s->msg; + cpu_physical_memory_write(s->dnad, &s->msg, 1); + if (s->msg == 0) { + lsi_disconnect(s); + } else { + /* ??? Check if ATN (not yet implemented) is asserted and maybe + switch to PHASE_MO. */ + lsi_set_phase(s, PHASE_CMD); + } +} + +static void lsi_do_msgout(LSIState *s) +{ + uint8_t msg; + + DPRINTF("MSG out len=%d\n", s->dbc); + if (s->dbc != 1) { + /* Multibyte messages not implemented. */ + s->msg = 7; /* MESSAGE REJECT */ + //s->dbc = 1; + //lsi_bad_phase(s, 1, PHASE_MI); + lsi_set_phase(s, PHASE_MI); + return; + } + cpu_physical_memory_read(s->dnad, &msg, 1); + s->sfbr = msg; + s->dnad++; + + switch (msg) { + case 0x00: + DPRINTF("Got Disconnect\n"); + lsi_disconnect(s); + return; + case 0x08: + DPRINTF("Got No Operation\n"); + lsi_set_phase(s, PHASE_CMD); + return; + } + if ((msg & 0x80) == 0) { + DPRINTF("Unimplemented message 0x%d\n", msg); + s->msg = 7; /* MESSAGE REJECT */ + lsi_bad_phase(s, 1, PHASE_MI); + return; + } + s->current_lun = msg & 7; + DPRINTF("Select LUN %d\n", s->current_lun); + lsi_set_phase(s, PHASE_CMD); +} + +/* Sign extend a 24-bit value. */ +static inline int32_t sxt24(int32_t n) +{ + return (n << 8) >> 8; +} + +static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) +{ + int n; + uint8_t buf[TARGET_PAGE_SIZE]; + + DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); + while (count) { + n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count; + cpu_physical_memory_read(src, buf, n); + cpu_physical_memory_write(dest, buf, n); + src += n; + dest += n; + count -= n; + } +} + +static void lsi_execute_script(LSIState *s) +{ + uint32_t insn; + uint32_t addr; + int opcode; + + s->istat1 |= LSI_ISTAT1_SRUN; +again: + insn = read_dword(s, s->dsp); + addr = read_dword(s, s->dsp + 4); + DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr); + s->dsps = addr; + s->dcmd = insn >> 24; + s->dsp += 8; + switch (insn >> 30) { + case 0: /* Block move. */ + if (s->sist1 & LSI_SIST1_STO) { + DPRINTF("Delayed select timeout\n"); + lsi_stop_script(s); + break; + } + s->dbc = insn & 0xffffff; + s->rbc = s->dbc; + if (insn & (1 << 29)) { + /* Indirect addressing. */ + addr = read_dword(s, addr); + } else if (insn & (1 << 28)) { + uint32_t buf[2]; + int32_t offset; + /* Table indirect addressing. */ + offset = sxt24(addr); + cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8); + s->dbc = cpu_to_le32(buf[0]); + addr = cpu_to_le32(buf[1]); + } + if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { + DPRINTF("Wrong phase got %d expected %d\n", + s->sstat1 & PHASE_MASK, (insn >> 24) & 7); + lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0); + break; + } + s->dnad = addr; + switch (s->sstat1 & 0x7) { + case PHASE_DO: + lsi_do_dma(s, 1); + break; + case PHASE_DI: + lsi_do_dma(s, 0); + break; + case PHASE_CMD: + lsi_do_command(s); + break; + case PHASE_ST: + lsi_do_status(s); + break; + case PHASE_MO: + lsi_do_msgout(s); + break; + case PHASE_MI: + lsi_do_msgin(s); + break; + default: + BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK); + exit(1); + } + s->dfifo = s->dbc & 0xff; + s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3); + s->sbc = s->dbc; + s->rbc -= s->dbc; + s->ua = addr + s->dbc; + /* ??? Set ESA. */ + s->ia = s->dsp - 8; + break; + + case 1: /* IO or Read/Write instruction. */ + opcode = (insn >> 27) & 7; + if (opcode < 5) { + uint32_t id; + + if (insn & (1 << 25)) { + id = read_dword(s, s->dsa + sxt24(insn)); + } else { + id = addr; + } + id = (id >> 16) & 0xf; + if (insn & (1 << 26)) { + addr = s->dsp + sxt24(addr); + } + s->dnad = addr; + switch (opcode) { + case 0: /* Select */ + s->sstat0 |= LSI_SSTAT0_WOA; + s->scntl1 &= ~LSI_SCNTL1_IARB; + s->sdid = id; + if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) { + DPRINTF("Selected absent target %d\n", id); + lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO); + lsi_disconnect(s); + break; + } + DPRINTF("Selected target %d%s\n", + id, insn & (1 << 3) ? " ATN" : ""); + /* ??? Linux drivers compain when this is set. Maybe + it only applies in low-level mode (unimplemented). + lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ + s->current_dev = s->scsi_dev[id]; + s->scntl1 |= LSI_SCNTL1_CON; + if (insn & (1 << 3)) { + s->socl |= LSI_SOCL_ATN; + } + lsi_set_phase(s, PHASE_MO); + break; + case 1: /* Disconnect */ + DPRINTF("Wait Disconect\n"); + s->scntl1 &= ~LSI_SCNTL1_CON; + break; + case 2: /* Wait Reselect */ + DPRINTF("Wait Reselect\n"); + s->waiting = 1; + break; + case 3: /* Set */ + DPRINTF("Set%s%s%s%s\n", + insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) { + s->socl |= LSI_SOCL_ATN; + lsi_set_phase(s, PHASE_MO); + } + if (insn & (1 << 9)) { + BADF("Target mode not implemented\n"); + exit(1); + } + if (insn & (1 << 10)) + s->carry = 1; + break; + case 4: /* Clear */ + DPRINTF("Clear%s%s%s%s\n", + insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) { + s->socl &= ~LSI_SOCL_ATN; + } + if (insn & (1 << 10)) + s->carry = 0; + break; + } + } else { + uint8_t op0; + uint8_t op1; + uint8_t data8; + int reg; + int operator; +#ifdef DEBUG_LSI + static const char *opcode_names[3] = + {"Write", "Read", "Read-Modify-Write"}; + static const char *operator_names[8] = + {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"}; +#endif + + reg = ((insn >> 16) & 0x7f) | (insn & 0x80); + data8 = (insn >> 8) & 0xff; + opcode = (insn >> 27) & 7; + operator = (insn >> 24) & 7; + DPRINTF("%s reg 0x%x %s data8 %d%s\n", + opcode_names[opcode - 5], reg, + operator_names[operator], data8, + (insn & (1 << 23)) ? " SFBR" : ""); + op0 = op1 = 0; + switch (opcode) { + case 5: /* From SFBR */ + op0 = s->sfbr; + op1 = data8; + break; + case 6: /* To SFBR */ + if (operator) + op0 = lsi_reg_readb(s, reg); + op1 = data8; + break; + case 7: /* Read-modify-write */ + if (operator) + op0 = lsi_reg_readb(s, reg); + if (insn & (1 << 23)) { + op1 = s->sfbr; + } else { + op1 = data8; + } + break; + } + + switch (operator) { + case 0: /* move */ + op0 = op1; + break; + case 1: /* Shift left */ + op1 = op0 >> 7; + op0 = (op0 << 1) | s->carry; + s->carry = op1; + break; + case 2: /* OR */ + op0 |= op1; + break; + case 3: /* XOR */ + op0 |= op1; + break; + case 4: /* AND */ + op0 &= op1; + break; + case 5: /* SHR */ + op1 = op0 & 1; + op0 = (op0 >> 1) | (s->carry << 7); + break; + case 6: /* ADD */ + op0 += op1; + s->carry = op0 < op1; + break; + case 7: /* ADC */ + op0 += op1 + s->carry; + if (s->carry) + s->carry = op0 <= op1; + else + s->carry = op0 < op1; + break; + } + + switch (opcode) { + case 5: /* From SFBR */ + case 7: /* Read-modify-write */ + lsi_reg_writeb(s, reg, op0); + break; + case 6: /* To SFBR */ + s->sfbr = op0; + break; + } + } + break; + + case 2: /* Transfer Control. */ + { + int cond; + int jmp; + + if ((insn & 0x002e0000) == 0) { + DPRINTF("NOP\n"); + break; + } + if (s->sist1 & LSI_SIST1_STO) { + DPRINTF("Delayed select timeout\n"); + lsi_stop_script(s); + break; + } + cond = jmp = (insn & (1 << 19)) != 0; + if (cond == jmp && (insn & (1 << 21))) { + DPRINTF("Compare carry %d\n", s->carry == jmp); + cond = s->carry != 0; + } + if (cond == jmp && (insn & (1 << 17))) { + DPRINTF("Compare phase %d %c= %d\n", + (s->sstat1 & PHASE_MASK), + jmp ? '=' : '!', + ((insn >> 24) & 7)); + cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); + } + if (cond == jmp && (insn & (1 << 18))) { + uint8_t mask; + + mask = (~insn >> 8) & 0xff; + DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n", + s->sfbr, mask, jmp ? '=' : '!', insn & mask); + cond = (s->sfbr & mask) == (insn & mask); + } + if (cond == jmp) { + if (insn & (1 << 23)) { + /* Relative address. */ + addr = s->dsp + sxt24(addr); + } + switch ((insn >> 27) & 7) { + case 0: /* Jump */ + DPRINTF("Jump to 0x%08x\n", addr); + s->dsp = addr; + break; + case 1: /* Call */ + DPRINTF("Call 0x%08x\n", addr); + s->temp = s->dsp; + s->dsp = addr; + break; + case 2: /* Return */ + DPRINTF("Return to 0x%08x\n", s->temp); + s->dsp = s->temp; + break; + case 3: /* Interrupt */ + DPRINTF("Interrupt 0x%08x\n", s->dsps); + if ((insn & (1 << 20)) != 0) { + s->istat0 |= LSI_ISTAT0_INTF; + lsi_update_irq(s); + } else { + lsi_script_dma_interrupt(s, LSI_DSTAT_SIR); + } + break; + default: + DPRINTF("Illegal transfer control\n"); + lsi_script_dma_interrupt(s, LSI_DSTAT_IID); + break; + } + } else { + DPRINTF("Control condition failed\n"); + } + } + break; + + case 3: + if ((insn & (1 << 29)) == 0) { + /* Memory move. */ + uint32_t dest; + /* ??? The docs imply the destination address is loaded into + the TEMP register. However the Linux drivers rely on + the value being presrved. */ + dest = read_dword(s, s->dsp); + s->dsp += 4; + lsi_memcpy(s, dest, addr, insn & 0xffffff); + } else { + uint8_t data[7]; + int reg; + int n; + int i; + + if (insn & (1 << 28)) { + addr = s->dsa + sxt24(addr); + } + n = (insn & 7); + reg = (insn >> 16) & 0xff; + if (insn & (1 << 24)) { + DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + cpu_physical_memory_read(addr, data, n); + for (i = 0; i < n; i++) { + lsi_reg_writeb(s, reg + i, data[i]); + } + } else { + DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + for (i = 0; i < n; i++) { + data[i] = lsi_reg_readb(s, reg + i); + } + cpu_physical_memory_write(addr, data, n); + } + } + } + /* ??? Need to avoid infinite loops. */ + if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) { + if (s->dcntl & LSI_DCNTL_SSM) { + lsi_script_dma_interrupt(s, LSI_DSTAT_SSI); + } else { + goto again; + } + } + DPRINTF("SCRIPTS execution stopped\n"); +} + +static uint8_t lsi_reg_readb(LSIState *s, int offset) +{ + uint8_t tmp; +#define CASE_GET_REG32(name, addr) \ + case addr: return s->name & 0xff; \ + case addr + 1: return (s->name >> 8) & 0xff; \ + case addr + 2: return (s->name >> 16) & 0xff; \ + case addr + 3: return (s->name >> 24) & 0xff; + +#ifdef DEBUG_LSI_REG + DPRINTF("Read reg %x\n", offset); +#endif + switch (offset) { + case 0x00: /* SCNTL0 */ + return s->scntl0; + case 0x01: /* SCNTL1 */ + return s->scntl1; + case 0x02: /* SCNTL2 */ + return s->scntl2; + case 0x03: /* SCNTL3 */ + return s->scntl3; + case 0x04: /* SCID */ + return s->scid; + case 0x05: /* SXFER */ + return s->sxfer; + case 0x06: /* SDID */ + return s->sdid; + case 0x07: /* GPREG0 */ + return 0x7f; + case 0xb: /* SBCL */ + /* ??? This is not correct. However it's (hopefully) only + used for diagnostics, so should be ok. */ + return 0; + case 0xc: /* DSTAT */ + tmp = s->dstat | 0x80; + if ((s->istat0 & LSI_ISTAT0_INTF) == 0) + s->dstat = 0; + lsi_update_irq(s); + return tmp; + case 0x0d: /* SSTAT0 */ + return s->sstat0; + case 0x0e: /* SSTAT1 */ + return s->sstat1; + case 0x0f: /* SSTAT2 */ + return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2; + CASE_GET_REG32(dsa, 0x10) + case 0x14: /* ISTAT0 */ + return s->istat0; + case 0x16: /* MBOX0 */ + return s->mbox0; + case 0x17: /* MBOX1 */ + return s->mbox1; + case 0x18: /* CTEST0 */ + return 0xff; + case 0x19: /* CTEST1 */ + return 0; + case 0x1a: /* CTEST2 */ + tmp = LSI_CTEST2_DACK | LSI_CTEST2_CM; + if (s->istat0 & LSI_ISTAT0_SIGP) { + s->istat0 &= ~LSI_ISTAT0_SIGP; + tmp |= LSI_CTEST2_SIGP; + } + return tmp; + case 0x1b: /* CTEST3 */ + return s->ctest3; + CASE_GET_REG32(temp, 0x1c) + case 0x20: /* DFIFO */ + return 0; + case 0x21: /* CTEST4 */ + return s->ctest4; + case 0x22: /* CTEST5 */ + return s->ctest5; + case 0x24: /* DBC[0:7] */ + return s->dbc & 0xff; + case 0x25: /* DBC[8:15] */ + return (s->dbc >> 8) & 0xff; + case 0x26: /* DBC[16->23] */ + return (s->dbc >> 16) & 0xff; + case 0x27: /* DCMD */ + return s->dcmd; + CASE_GET_REG32(dsp, 0x2c) + CASE_GET_REG32(dsps, 0x30) + CASE_GET_REG32(scratch[0], 0x34) + case 0x38: /* DMODE */ + return s->dmode; + case 0x39: /* DIEN */ + return s->dien; + case 0x3b: /* DCNTL */ + return s->dcntl; + case 0x40: /* SIEN0 */ + return s->sien0; + case 0x41: /* SIEN1 */ + return s->sien1; + case 0x42: /* SIST0 */ + tmp = s->sist0; + s->sist0 = 0; + lsi_update_irq(s); + return tmp; + case 0x43: /* SIST1 */ + tmp = s->sist1; + s->sist1 = 0; + lsi_update_irq(s); + return tmp; + case 0x47: /* GPCNTL0 */ + return 0x0f; + case 0x48: /* STIME0 */ + return s->stime0; + case 0x4a: /* RESPID0 */ + return s->respid0; + case 0x4b: /* RESPID1 */ + return s->respid1; + case 0x4d: /* STEST1 */ + return s->stest1; + case 0x4e: /* STEST2 */ + return s->stest2; + case 0x4f: /* STEST3 */ + return s->stest3; + case 0x52: /* STEST4 */ + return 0xe0; + case 0x56: /* CCNTL0 */ + return s->ccntl0; + case 0x57: /* CCNTL1 */ + return s->ccntl1; + case 0x58: case 0x59: /* SBDL */ + return 0; + CASE_GET_REG32(mmrs, 0xa0) + CASE_GET_REG32(mmws, 0xa4) + CASE_GET_REG32(sfs, 0xa8) + CASE_GET_REG32(drs, 0xac) + CASE_GET_REG32(sbms, 0xb0) + CASE_GET_REG32(dmbs, 0xb4) + CASE_GET_REG32(dnad64, 0xb8) + CASE_GET_REG32(pmjad1, 0xc0) + CASE_GET_REG32(pmjad2, 0xc4) + CASE_GET_REG32(rbc, 0xc8) + CASE_GET_REG32(ua, 0xcc) + CASE_GET_REG32(ia, 0xd4) + CASE_GET_REG32(sbc, 0xd8) + CASE_GET_REG32(csbc, 0xdc) + } + if (offset >= 0x5c && offset < 0xa0) { + int n; + int shift; + n = (offset - 0x58) >> 2; + shift = (offset & 3) * 8; + return (s->scratch[n] >> shift) & 0xff; + } + BADF("readb 0x%x\n", offset); + exit(1); +#undef CASE_GET_REG32 +} + +static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) +{ +#define CASE_SET_REG32(name, addr) \ + case addr : s->name &= 0xffffff00; s->name |= val; break; \ + case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \ + case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \ + case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break; + +#ifdef DEBUG_LSI_REG + DPRINTF("Write reg %x = %02x\n", offset, val); +#endif + switch (offset) { + case 0x00: /* SCNTL0 */ + s->scntl0 = val; + if (val & LSI_SCNTL0_START) { + BADF("Start sequence not implemented\n"); + } + break; + case 0x01: /* SCNTL1 */ + s->scntl1 = val & ~LSI_SCNTL1_SST; + if (val & LSI_SCNTL1_IARB) { + BADF("Immediate Arbritration not implemented\n"); + } + if (val & LSI_SCNTL1_RST) { + s->sstat0 |= LSI_SSTAT0_RST; + lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); + } else { + s->sstat0 &= ~LSI_SSTAT0_RST; + } + break; + case 0x02: /* SCNTL2 */ + val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS); + s->scntl3 = val; + break; + case 0x03: /* SCNTL3 */ + s->scntl3 = val; + break; + case 0x04: /* SCID */ + s->scid = val; + break; + case 0x05: /* SXFER */ + s->sxfer = val; + break; + case 0x07: /* GPREG0 */ + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* Linux writes to these readonly registers on startup. */ + return; + CASE_SET_REG32(dsa, 0x10) + case 0x14: /* ISTAT0 */ + s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0); + if (val & LSI_ISTAT0_ABRT) { + lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT); + } + if (val & LSI_ISTAT0_INTF) { + s->istat0 &= ~LSI_ISTAT0_INTF; + lsi_update_irq(s); + } + if (s->waiting && val & LSI_ISTAT0_SIGP) { + DPRINTF("Woken by SIGP\n"); + s->waiting = 0; + s->dsp = s->dnad; + lsi_execute_script(s); + } + if (val & LSI_ISTAT0_SRST) { + lsi_soft_reset(s); + } + case 0x16: /* MBOX0 */ + s->mbox0 = val; + case 0x17: /* MBOX1 */ + s->mbox1 = val; + case 0x1b: /* CTEST3 */ + s->ctest3 = val & 0x0f; + break; + CASE_SET_REG32(temp, 0x1c) + case 0x21: /* CTEST4 */ + if (val & 7) { + BADF("Unimplemented CTEST4-FBL 0x%x\n", val); + } + s->ctest4 = val; + break; + case 0x22: /* CTEST5 */ + if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) { + BADF("CTEST5 DMA increment not implemented\n"); + } + s->ctest5 = val; + break; + case 0x2c: /* DSPS[0:7] */ + s->dsp &= 0xffffff00; + s->dsp |= val; + break; + case 0x2d: /* DSPS[8:15] */ + s->dsp &= 0xffff00ff; + s->dsp |= val << 8; + break; + case 0x2e: /* DSPS[16:23] */ + s->dsp &= 0xff00ffff; + s->dsp |= val << 16; + break; + case 0x2f: /* DSPS[14:31] */ + s->dsp &= 0x00ffffff; + s->dsp |= val << 24; + if ((s->dmode & LSI_DMODE_MAN) == 0 + && (s->istat1 & LSI_ISTAT1_SRUN) == 0) + lsi_execute_script(s); + break; + CASE_SET_REG32(dsps, 0x30) + CASE_SET_REG32(scratch[0], 0x34) + case 0x38: /* DMODE */ + if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) { + BADF("IO mappings not implemented\n"); + } + s->dmode = val; + break; + case 0x39: /* DIEN */ + s->dien = val; + lsi_update_irq(s); + break; + case 0x3b: /* DCNTL */ + s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD); + if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0) + lsi_execute_script(s); + break; + case 0x40: /* SIEN0 */ + s->sien0 = val; + lsi_update_irq(s); + break; + case 0x41: /* SIEN1 */ + s->sien1 = val; + lsi_update_irq(s); + break; + case 0x47: /* GPCNTL0 */ + break; + case 0x48: /* STIME0 */ + s->stime0 = val; + break; + case 0x49: /* STIME1 */ + if (val & 0xf) { + DPRINTF("General purpose timer not implemented\n"); + /* ??? Raising the interrupt immediately seems to be sufficient + to keep the FreeBSD driver happy. */ + lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN); + } + break; + case 0x4a: /* RESPID0 */ + s->respid0 = val; + break; + case 0x4b: /* RESPID1 */ + s->respid1 = val; + break; + case 0x4d: /* STEST1 */ + s->stest1 = val; + break; + case 0x4e: /* STEST2 */ + if (val & 1) { + BADF("Low level mode not implemented\n"); + } + s->stest2 = val; + break; + case 0x4f: /* STEST3 */ + if (val & 0x41) { + BADF("SCSI FIFO test mode not implemented\n"); + } + s->stest3 = val; + break; + case 0x56: /* CCNTL0 */ + s->ccntl0 = val; + break; + case 0x57: /* CCNTL1 */ + s->ccntl1 = val; + break; + CASE_SET_REG32(mmrs, 0xa0) + CASE_SET_REG32(mmws, 0xa4) + CASE_SET_REG32(sfs, 0xa8) + CASE_SET_REG32(drs, 0xac) + CASE_SET_REG32(sbms, 0xb0) + CASE_SET_REG32(dmbs, 0xb4) + CASE_SET_REG32(dnad64, 0xb8) + CASE_SET_REG32(pmjad1, 0xc0) + CASE_SET_REG32(pmjad2, 0xc4) + CASE_SET_REG32(rbc, 0xc8) + CASE_SET_REG32(ua, 0xcc) + CASE_SET_REG32(ia, 0xd4) + CASE_SET_REG32(sbc, 0xd8) + CASE_SET_REG32(csbc, 0xdc) + default: + if (offset >= 0x5c && offset < 0xa0) { + int n; + int shift; + n = (offset - 0x58) >> 2; + shift = (offset & 3) * 8; + s->scratch[n] &= ~(0xff << shift); + s->scratch[n] |= (val & 0xff) << shift; + } else { + BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val); + } + } +#undef CASE_SET_REG32 +} + +static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + + lsi_reg_writeb(s, addr & 0xff, val); +} + +static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + + addr &= 0xff; + lsi_reg_writeb(s, addr, val & 0xff); + lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); +} + +static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + + addr &= 0xff; + lsi_reg_writeb(s, addr, val & 0xff); + lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); + lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff); + lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff); +} + +static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + + return lsi_reg_readb(s, addr & 0xff); +} + +static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + + addr &= 0xff; + val = lsi_reg_readb(s, addr); + val |= lsi_reg_readb(s, addr + 1) << 8; + return val; +} + +static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + addr &= 0xff; + val = lsi_reg_readb(s, addr); + val |= lsi_reg_readb(s, addr + 1) << 8; + val |= lsi_reg_readb(s, addr + 2) << 16; + val |= lsi_reg_readb(s, addr + 3) << 24; + return val; +} + +static CPUReadMemoryFunc *lsi_mmio_readfn[3] = { + lsi_mmio_readb, + lsi_mmio_readw, + lsi_mmio_readl, +}; + +static CPUWriteMemoryFunc *lsi_mmio_writefn[3] = { + lsi_mmio_writeb, + lsi_mmio_writew, + lsi_mmio_writel, +}; + +static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + uint32_t newval; + int shift; + + addr &= 0x1fff; + newval = s->script_ram[addr >> 2]; + shift = (addr & 3) * 8; + newval &= ~(0xff << shift); + newval |= val << shift; + s->script_ram[addr >> 2] = newval; +} + +static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + uint32_t newval; + + addr &= 0x1fff; + newval = s->script_ram[addr >> 2]; + if (addr & 2) { + newval = (newval & 0xffff) | (val << 16); + } else { + newval = (newval & 0xffff0000) | val; + } + s->script_ram[addr >> 2] = newval; +} + + +static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + + addr &= 0x1fff; + s->script_ram[addr >> 2] = val; +} + +static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + + addr &= 0x1fff; + val = s->script_ram[addr >> 2]; + val >>= (addr & 3) * 8; + return val & 0xff; +} + +static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + + addr &= 0x1fff; + val = s->script_ram[addr >> 2]; + if (addr & 2) + val >>= 16; + return le16_to_cpu(val); +} + +static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr) +{ + LSIState *s = (LSIState *)opaque; + + addr &= 0x1fff; + return le32_to_cpu(s->script_ram[addr >> 2]); +} + +static CPUReadMemoryFunc *lsi_ram_readfn[3] = { + lsi_ram_readb, + lsi_ram_readw, + lsi_ram_readl, +}; + +static CPUWriteMemoryFunc *lsi_ram_writefn[3] = { + lsi_ram_writeb, + lsi_ram_writew, + lsi_ram_writel, +}; + +static uint32_t lsi_io_readb(void *opaque, uint32_t addr) +{ + LSIState *s = (LSIState *)opaque; + return lsi_reg_readb(s, addr & 0xff); +} + +static uint32_t lsi_io_readw(void *opaque, uint32_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + addr &= 0xff; + val = lsi_reg_readb(s, addr); + val |= lsi_reg_readb(s, addr + 1) << 8; + return val; +} + +static uint32_t lsi_io_readl(void *opaque, uint32_t addr) +{ + LSIState *s = (LSIState *)opaque; + uint32_t val; + addr &= 0xff; + val = lsi_reg_readb(s, addr); + val |= lsi_reg_readb(s, addr + 1) << 8; + val |= lsi_reg_readb(s, addr + 2) << 16; + val |= lsi_reg_readb(s, addr + 3) << 24; + return val; +} + +static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + lsi_reg_writeb(s, addr & 0xff, val); +} + +static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + addr &= 0xff; + lsi_reg_writeb(s, addr, val & 0xff); + lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); +} + +static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val) +{ + LSIState *s = (LSIState *)opaque; + addr &= 0xff; + lsi_reg_writeb(s, addr, val & 0xff); + lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); + lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff); + lsi_reg_writeb(s, addr + 2, (val >> 24) & 0xff); +} + +static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + LSIState *s = (LSIState *)pci_dev; + + DPRINTF("Mapping IO at %08x\n", addr); + + register_ioport_write(addr, 256, 1, lsi_io_writeb, s); + register_ioport_read(addr, 256, 1, lsi_io_readb, s); + register_ioport_write(addr, 256, 2, lsi_io_writew, s); + register_ioport_read(addr, 256, 2, lsi_io_readw, s); + register_ioport_write(addr, 256, 4, lsi_io_writel, s); + register_ioport_read(addr, 256, 4, lsi_io_readl, s); +} + +static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + LSIState *s = (LSIState *)pci_dev; + + DPRINTF("Mapping ram at %08x\n", addr); + s->script_ram_base = addr; + cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr); +} + +static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + LSIState *s = (LSIState *)pci_dev; + + DPRINTF("Mapping registers at %08x\n", addr); + cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr); +} + +void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id) +{ + LSIState *s = (LSIState *)opaque; + + if (id < 0) { + for (id = 0; id < LSI_MAX_DEVS; id++) { + if (s->scsi_dev[id] == NULL) + break; + } + } + if (id >= LSI_MAX_DEVS) { + BADF("Bad Device ID %d\n", id); + return; + } + if (s->scsi_dev[id]) { + DPRINTF("Destroying device %d\n", id); + scsi_disk_destroy(s->scsi_dev[id]); + } + DPRINTF("Attaching block device %d\n", id); + s->scsi_dev[id] = scsi_disk_init(bd, lsi_command_complete, s); +} + +void *lsi_scsi_init(PCIBus *bus, int devfn) +{ + LSIState *s; + + s = (LSIState *)pci_register_device(bus, "LSI53C895A SCSI HBA", + sizeof(*s), devfn, NULL, NULL); + if (s == NULL) { + fprintf(stderr, "lsi-scsi: Failed to register PCI device\n"); + return NULL; + } + + s->pci_dev.config[0x00] = 0x00; + s->pci_dev.config[0x01] = 0x10; + s->pci_dev.config[0x02] = 0x12; + s->pci_dev.config[0x03] = 0x00; + s->pci_dev.config[0x0b] = 0x01; + s->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ + + s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn, + lsi_mmio_writefn, s); + s->ram_io_addr = cpu_register_io_memory(0, lsi_ram_readfn, + lsi_ram_writefn, s); + + pci_register_io_region((struct PCIDevice *)s, 0, 256, + PCI_ADDRESS_SPACE_IO, lsi_io_mapfunc); + pci_register_io_region((struct PCIDevice *)s, 1, 0x400, + PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc); + pci_register_io_region((struct PCIDevice *)s, 2, 0x2000, + PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc); + + lsi_soft_reset(s); + + return s; +} + diff --git a/hw/pc.c b/hw/pc.c index f9a7e8637..b72219027 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -838,6 +838,24 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled && acpi_enabled) { piix4_pm_init(pci_bus, piix3_devfn + 3); } + +#if 0 + /* ??? Need to figure out some way for the user to + specify SCSI devices. */ + if (pci_enabled) { + void *scsi; + BlockDriverState *bdrv; + + scsi = lsi_scsi_init(pci_bus, -1); + bdrv = bdrv_new("scsidisk"); + bdrv_open(bdrv, "scsi_disk.img", 0); + lsi_scsi_attach(scsi, bdrv, -1); + bdrv = bdrv_new("scsicd"); + bdrv_open(bdrv, "scsi_cd.iso", 0); + bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); + lsi_scsi_attach(scsi, bdrv, -1); + } +#endif /* must be done after all PCI devices are instanciated */ /* XXX: should be done in the Bochs BIOS */ if (pci_enabled) { diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index c15486b2b..226840157 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -245,7 +245,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) s->buf_len = 4; break; case 0x12: - DPRINTF("Inquiry (len %d)\n", len); + DPRINTF("Inquiry (len %d)\n", len); if (len < 36) { BADF("Inquiry buffer too small (%d)\n", len); } @@ -253,12 +253,13 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { s->buf[0] = 5; s->buf[1] = 0x80; - memcpy(&s->buf[16], "QEMU CDROM ", 16); + memcpy(&s->buf[16], "QEMU CD-ROM ", 16); } else { s->buf[0] = 0; memcpy(&s->buf[16], "QEMU HARDDISK ", 16); } memcpy(&s->buf[8], "QEMU ", 8); + memcpy(&s->buf[32], QEMU_VERSION, 4); s->buf[2] = 3; /* SCSI-3 */ s->buf[3] = 2; /* Format 2 */ s->buf[4] = 32; @@ -275,18 +276,27 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) goto fail; break; case 0x1a: - DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[2], len); - memset(s->buf, 0, 4); - s->buf[0] = 0x16; /* Mode data length (4 + 0x12). */ - s->buf[1] = 0; /* Default media type. */ - s->buf[2] = 0; /* Write enabled. */ - s->buf[3] = 0; /* Block descriptor length. */ - /* Caching page. */ - s->buf[4 + 0] = 8; - s->buf[4 + 1] = 0x12; - s->buf[4 + 2] = 4; /* WCE */ - if (len > 0x16) - len = 0x16; + case 0x5a: + DPRINTF("Mode Sense (page %d, len %d)\n", buf[2], len); + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + memset(s->buf, 0, 4); + s->buf[0] = 4; /* Mode data length. */ + s->buf[1] = 0; /* Default media type. */ + s->buf[2] = 0x80; /* Readonly. */ + s->buf[3] = 0; /* Block descriptor length. */ + } else { + memset(s->buf, 0, 0x16); + s->buf[0] = 0x16; /* Mode data length (4 + 0x12). */ + s->buf[1] = 0; /* Default media type. */ + s->buf[2] = 0; /* Write enabled. */ + s->buf[3] = 0; /* Block descriptor length. */ + /* Caching page. */ + s->buf[4 + 0] = 8; + s->buf[4 + 1] = 0x12; + s->buf[4 + 2] = 4; /* WCE */ + if (len > 0x16) + len = 0x16; + } s->buf_len = len; break; case 0x25: @@ -317,6 +327,10 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) s->sector_count = len * s->cluster_size; is_write = 1; break; + case 0x35: + DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len); + /* ??? Extend block layer and use fsync to implement this. */ + break; case 0x43: { int start_track, format, msf, toclen; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index c22e38a96..28ec1374b 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -343,6 +343,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, CPUState *env; void *pic; void *sic; + void *scsi_hba; PCIBus *pci_bus; NICInfo *nd; int n; @@ -377,6 +378,12 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, if (usb_enabled) { usb_ohci_init(pci_bus, 3, -1); } + scsi_hba = lsi_scsi_init(pci_bus, -1); + for (n = 0; n < MAX_DISKS; n++) { + if (bs_table[n]) { + lsi_scsi_attach(scsi_hba, bs_table[n], n); + } + } pl011_init(0x101f1000, pic, 12, serial_hds[0]); pl011_init(0x101f2000, pic, 13, serial_hds[1]); diff --git a/vl.h b/vl.h index 26e009fdc..944240957 100644 --- a/vl.h +++ b/vl.h @@ -1048,6 +1048,10 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); +/* lsi53c895a.c */ +void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); +void *lsi_scsi_init(PCIBus *bus, int devfn); + /* integratorcp.c */ extern QEMUMachine integratorcp926_machine; extern QEMUMachine integratorcp1026_machine; -- cgit v1.2.3 From 9f149aa9c1a04117d03de16bb0f8d2dad8c4f8c1 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 3 Jun 2006 14:19:19 +0000 Subject: SATN fixes (Blue Swirl). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1947 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 18 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 908767943..cdd062f78 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -59,6 +59,9 @@ struct ESPState { int dma; SCSIDevice *scsi_dev[MAX_DISKS]; SCSIDevice *current_dev; + uint8_t cmdbuf[TI_BUFSZ]; + int cmdlen; + int do_cmd; }; #define STAT_DO 0x00 @@ -79,17 +82,14 @@ struct ESPState { #define SEQ_0 0x0 #define SEQ_CD 0x4 -static void handle_satn(ESPState *s) +static int get_cmd(ESPState *s, uint8_t *buf) { - uint8_t buf[32]; uint32_t dmaptr, dmalen; int target; - int32_t datalen; - int lun; dmalen = s->wregs[0] | (s->wregs[1] << 8); target = s->wregs[4] & 7; - DPRINTF("Select with ATN len %d target %d\n", dmalen, target); + DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", @@ -100,8 +100,6 @@ static void handle_satn(ESPState *s) memcpy(&buf[1], s->ti_buf, dmalen); dmalen++; } - DPRINTF("busid 0x%x\n", buf[0]); - lun = buf[0] & 7; s->ti_size = 0; s->ti_rptr = 0; @@ -114,9 +112,19 @@ static void handle_satn(ESPState *s) s->rregs[6] = SEQ_0; s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); - return; + return 0; } s->current_dev = s->scsi_dev[target]; + return dmalen; +} + +static void do_cmd(ESPState *s, uint8_t *buf) +{ + int32_t datalen; + int lun; + + DPRINTF("do_cmd: busid 0x%x\n", buf[0]); + lun = buf[0] & 7; datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); if (datalen == 0) { s->ti_size = 0; @@ -136,6 +144,31 @@ static void handle_satn(ESPState *s) pic_set_irq(s->irq, 1); } +static void handle_satn(ESPState *s) +{ + uint8_t buf[32]; + int len; + + len = get_cmd(s, buf); + if (len) + do_cmd(s, buf); +} + +static void handle_satn_stop(ESPState *s) +{ + s->cmdlen = get_cmd(s, s->cmdbuf); + if (s->cmdlen) { + DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); + s->do_cmd = 1; + s->espdmaregs[1] += s->cmdlen; + s->rregs[4] = STAT_IN | STAT_TC | STAT_CD; + s->rregs[5] = INTR_BS | INTR_FC; + s->rregs[6] = SEQ_CD; + s->espdmaregs[0] |= DMA_INTR; + pic_set_irq(s->irq, 1); + } +} + static void write_response(ESPState *s) { uint32_t dmaptr; @@ -188,7 +221,10 @@ static void handle_ti(ESPState *s) dmalen=0x10000; } - minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; + if (s->do_cmd) + minlen = (dmalen < 32) ? dmalen : 32; + else + minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; DPRINTF("Transfer Information len %d\n", minlen); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); @@ -207,14 +243,24 @@ static void handle_ti(ESPState *s) } DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); s->ti_size -= len; - if (to_device) { - cpu_physical_memory_read(dmaptr, buf, len); - scsi_write_data(s->current_dev, buf, len); + if (s->do_cmd) { + DPRINTF("command len %d + %d\n", s->cmdlen, len); + cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); + s->ti_size = 0; + s->cmdlen = 0; + s->do_cmd = 0; + do_cmd(s, s->cmdbuf); + return; } else { - scsi_read_data(s->current_dev, buf, len); - cpu_physical_memory_write(dmaptr, buf, len); + if (to_device) { + cpu_physical_memory_read(dmaptr, buf, len); + scsi_write_data(s->current_dev, buf, len); + } else { + scsi_read_data(s->current_dev, buf, len); + cpu_physical_memory_write(dmaptr, buf, len); + } } - } + } if (s->ti_size) { s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); } @@ -222,7 +268,14 @@ static void handle_ti(ESPState *s) s->rregs[6] = 0; s->rregs[7] = 0; s->espdmaregs[0] |= DMA_INTR; - } + } else if (s->do_cmd) { + DPRINTF("command len %d\n", s->cmdlen); + s->ti_size = 0; + s->cmdlen = 0; + s->do_cmd = 0; + do_cmd(s, s->cmdbuf); + return; + } pic_set_irq(s->irq, 1); } @@ -237,6 +290,7 @@ static void esp_reset(void *opaque) s->ti_rptr = 0; s->ti_wptr = 0; s->dma = 0; + s->do_cmd = 0; } static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) @@ -291,7 +345,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 2: // FIFO - if ((s->rregs[4] & 6) == 0) { + if (s->do_cmd) { + s->cmdbuf[s->cmdlen++] = val & 0xff; + } else if ((s->rregs[4] & 6) == 0) { uint8_t buf; buf = val & 0xff; s->ti_size--; @@ -348,11 +404,12 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) DPRINTF("Set ATN (%2.2x)\n", val); break; case 0x42: + DPRINTF("Set ATN (%2.2x)\n", val); handle_satn(s); break; case 0x43: DPRINTF("Set ATN & stop (%2.2x)\n", val); - handle_satn(s); + handle_satn_stop(s); break; default: DPRINTF("Unhandled ESP command (%2.2x)\n", val); -- cgit v1.2.3 From 17acfe326ce2038033934485145ddd2390337986 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 3 Jun 2006 14:23:34 +0000 Subject: More SCSI commands (Blue Swirl). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1948 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/scsi-disk.c | 92 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 20 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 226840157..7390805d2 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -213,7 +213,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) cmdlen = 12; break; default: - BADF("Unsupported command length\n"); + BADF("Unsupported command length, command %x\n", s->command); goto fail; } #ifdef DEBUG_SCSI @@ -260,7 +260,9 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) } memcpy(&s->buf[8], "QEMU ", 8); memcpy(&s->buf[32], QEMU_VERSION, 4); - s->buf[2] = 3; /* SCSI-3 */ + /* Identify device as SCSI-3 rev 1. + Some later commands are also implemented. */ + s->buf[2] = 3; s->buf[3] = 2; /* Format 2 */ s->buf[4] = 32; s->buf_len = 36; @@ -277,27 +279,69 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) break; case 0x1a: case 0x5a: - DPRINTF("Mode Sense (page %d, len %d)\n", buf[2], len); - if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { - memset(s->buf, 0, 4); - s->buf[0] = 4; /* Mode data length. */ - s->buf[1] = 0; /* Default media type. */ - s->buf[2] = 0x80; /* Readonly. */ - s->buf[3] = 0; /* Block descriptor length. */ - } else { - memset(s->buf, 0, 0x16); - s->buf[0] = 0x16; /* Mode data length (4 + 0x12). */ + { + char *p; + int page; + + page = buf[2] & 0x3f; + DPRINTF("Mode Sense (page %d, len %d)\n", page, len); + p = s->buf; + memset(p, 0, 4); s->buf[1] = 0; /* Default media type. */ - s->buf[2] = 0; /* Write enabled. */ s->buf[3] = 0; /* Block descriptor length. */ - /* Caching page. */ - s->buf[4 + 0] = 8; - s->buf[4 + 1] = 0x12; - s->buf[4 + 2] = 4; /* WCE */ - if (len > 0x16) - len = 0x16; + if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { + s->buf[2] = 0x80; /* Readonly. */ + } + p += 4; + if ((page == 8 || page == 0x3f)) { + /* Caching page. */ + p[0] = 8; + p[1] = 0x12; + p[2] = 4; /* WCE */ + p += 19; + } + if ((page == 0x3f || page == 0x2a) + && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) { + /* CD Capabilities and Mechanical Status page. */ + p[0] = 0x2a; + p[1] = 0x14; + p[2] = 3; // CD-R & CD-RW read + p[3] = 0; // Writing not supported + p[4] = 0x7f; /* Audio, composite, digital out, + mode 2 form 1&2, multi session */ + p[5] = 0xff; /* CD DA, DA accurate, RW supported, + RW corrected, C2 errors, ISRC, + UPC, Bar code */ + p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0); + /* Locking supported, jumper present, eject, tray */ + p[7] = 0; /* no volume & mute control, no + changer */ + p[8] = (50 * 176) >> 8; // 50x read speed + p[9] = (50 * 176) & 0xff; + p[10] = 0 >> 8; // No volume + p[11] = 0 & 0xff; + p[12] = 2048 >> 8; // 2M buffer + p[13] = 2048 & 0xff; + p[14] = (16 * 176) >> 8; // 16x read speed current + p[15] = (16 * 176) & 0xff; + p[18] = (16 * 176) >> 8; // 16x write speed + p[19] = (16 * 176) & 0xff; + p[20] = (16 * 176) >> 8; // 16x write speed current + p[21] = (16 * 176) & 0xff; + p += 21; + } + s->buf_len = p - s->buf; + s->buf[0] = s->buf_len - 4; + if (s->buf_len > len) + s->buf_len = len; } - s->buf_len = len; + break; + case 0x1b: + DPRINTF("Start Stop Unit\n"); + break; + case 0x1e: + DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3); + bdrv_set_locked(s->bdrv, buf[4] & 1); break; case 0x25: DPRINTF("Read Capacity\n"); @@ -368,6 +412,14 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) DPRINTF("Read TOC error\n"); goto fail; } + case 0x46: + DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); + memset(s->buf, 0, 8); + /* ??? This shoud probably return much more information. For now + just return the basic header indicating the CD-ROM profile. */ + s->buf[7] = 8; // CD-ROM + s->buf_len = 8; + break; case 0x56: DPRINTF("Reserve(10)\n"); if (buf[1] & 3) -- cgit v1.2.3 From 7a6cba611d09f8eccdfc90d5ad3eb03762e60ce9 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 4 Jun 2006 11:39:07 +0000 Subject: Disk cache flush support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1949 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-cow.c | 7 +++++++ block-qcow.c | 7 +++++++ block-vmdk.c | 7 +++++++ block-vvfat.c | 1 + block.c | 15 +++++++++++++++ block_int.h | 1 + hw/ide.c | 5 +++++ hw/scsi-disk.c | 2 +- vl.h | 2 ++ 9 files changed, 46 insertions(+), 1 deletion(-) diff --git a/block-cow.c b/block-cow.c index eeeab7068..6af8b7497 100644 --- a/block-cow.c +++ b/block-cow.c @@ -250,6 +250,12 @@ static int cow_create(const char *filename, int64_t image_sectors, return 0; } +static void cow_flush(BlockDriverState *bs) +{ + BDRVCowState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_cow = { "cow", sizeof(BDRVCowState), @@ -259,6 +265,7 @@ BlockDriver bdrv_cow = { cow_write, cow_close, cow_create, + cow_flush, cow_is_allocated, }; #endif diff --git a/block-qcow.c b/block-qcow.c index 34026a4f2..e5b52fb86 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -693,6 +693,12 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, return 0; } +static void qcow_flush(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_qcow = { "qcow", sizeof(BDRVQcowState), @@ -702,6 +708,7 @@ BlockDriver bdrv_qcow = { qcow_write, qcow_close, qcow_create, + qcow_flush, qcow_is_allocated, qcow_set_key, qcow_make_empty diff --git a/block-vmdk.c b/block-vmdk.c index fc87be353..4cc3db84a 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -426,6 +426,12 @@ static void vmdk_close(BlockDriverState *bs) close(s->fd); } +static void vmdk_flush(BlockDriverState *bs) +{ + BDRVVmdkState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_vmdk = { "vmdk", sizeof(BDRVVmdkState), @@ -435,5 +441,6 @@ BlockDriver bdrv_vmdk = { vmdk_write, vmdk_close, vmdk_create, + vmdk_flush, vmdk_is_allocated, }; diff --git a/block-vvfat.c b/block-vvfat.c index 84d2a08ad..9dedf9115 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -2772,6 +2772,7 @@ BlockDriver bdrv_vvfat = { vvfat_read, vvfat_write, vvfat_close, + NULL, /* ??? Not sure if we can do any meaningful flushing. */ NULL, vvfat_is_allocated }; diff --git a/block.c b/block.c index b90816718..c25c6869a 100644 --- a/block.c +++ b/block.c @@ -615,6 +615,14 @@ 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; @@ -770,6 +778,12 @@ static int raw_create(const char *filename, int64_t total_size, return 0; } +static void raw_flush(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_raw = { "raw", sizeof(BDRVRawState), @@ -779,6 +793,7 @@ BlockDriver bdrv_raw = { raw_write, raw_close, raw_create, + raw_flush, }; void bdrv_init(void) diff --git a/block_int.h b/block_int.h index e3038160e..c2a2e30a9 100644 --- a/block_int.h +++ b/block_int.h @@ -36,6 +36,7 @@ struct BlockDriver { 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); diff --git a/hw/ide.c b/hw/ide.c index ffe0230d8..debbc0f41 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1656,6 +1656,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case WIN_FLUSH_CACHE: case WIN_FLUSH_CACHE_EXT: + if (s->bs) + bdrv_flush(s->bs); + s->status = READY_STAT; + ide_set_irq(s); + break; case WIN_STANDBYNOW1: case WIN_IDLEIMMEDIATE: s->status = READY_STAT; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 7390805d2..decab1f42 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -373,7 +373,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) break; case 0x35: DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len); - /* ??? Extend block layer and use fsync to implement this. */ + bdrv_flush(s->bdrv); break; case 0x43: { diff --git a/vl.h b/vl.h index 944240957..2bd49e8dd 100644 --- a/vl.h +++ b/vl.h @@ -496,6 +496,8 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); +/* Ensure contents are flushed to disk. */ +void bdrv_flush(BlockDriverState *bs); #define BDRV_TYPE_HD 0 #define BDRV_TYPE_CDROM 1 -- cgit v1.2.3 From ac62f715c6b8bde0fc4cfb0bed8e4f12ad4b5503 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 8 Jun 2006 21:51:27 +0000 Subject: Win32 build fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1950 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.h b/vl.h index 2bd49e8dd..ecfc0c417 100644 --- a/vl.h +++ b/vl.h @@ -47,6 +47,7 @@ #endif #ifdef _WIN32 +#define fsync _commit #define lseek _lseeki64 #define ENOTSUP 4096 /* XXX: find 64 bit version */ -- cgit v1.2.3 From e5fe0c5230cc7780de852cefb5df57e05e2c613e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Jun 2006 13:32:59 +0000 Subject: bFLT loader (for uClinux binaries). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1951 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 7 +- configure | 6 + linux-user/elfload.c | 310 +++---------------- linux-user/flat.h | 67 +++++ linux-user/flatload.c | 790 +++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/linuxload.c | 195 ++++++++++++ linux-user/main.c | 3 +- linux-user/qemu.h | 41 ++- 8 files changed, 1147 insertions(+), 272 deletions(-) create mode 100644 linux-user/flat.h create mode 100644 linux-user/flatload.c create mode 100644 linux-user/linuxload.c diff --git a/Makefile.target b/Makefile.target index 6d284d8ef..b0efd856f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -171,7 +171,12 @@ LDFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o +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 diff --git a/configure b/configure index d33e20210..3672fe087 100755 --- a/configure +++ b/configure @@ -773,6 +773,7 @@ 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 @@ -787,6 +788,7 @@ 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 @@ -842,6 +844,10 @@ if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; 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 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 98c6e3f85..687ff77b4 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -59,19 +58,19 @@ static uint32_t get_elf_hwcap(void) #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_386 - /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program - starts %edx contains a pointer to a function which might be - registered using `atexit'. This provides a mean for the - dynamic linker to call DT_FINI functions for shared libraries - that have been loaded before the code runs. - - A value of 0 tells we have no such handler. */ -#define ELF_PLAT_INIT(_r) _r->edx = 0 - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { regs->esp = infop->start_stack; regs->eip = infop->entry; + + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts %edx contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ + regs->edx = 0; } #define USE_ELF_CORE_DUMP @@ -93,8 +92,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif #define ELF_ARCH EM_ARM -#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0 - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { target_long stack = infop->start_stack; @@ -107,7 +104,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->ARM_r2 = tgetl(stack + 8); /* envp */ regs->ARM_r1 = tgetl(stack + 4); /* envp */ /* XXX: it seems that r0 is zeroed after ! */ - // regs->ARM_r0 = tgetl(stack); /* argc */ + regs->ARM_r0 = 0; + /* For uClinux PIC binaries. */ + regs->ARM_r10 = infop->start_data; } #define USE_ELF_CORE_DUMP @@ -142,9 +141,6 @@ enum #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_SPARC -/*XXX*/ -#define ELF_PLAT_INIT(_r) - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { regs->tstate = 0; @@ -163,9 +159,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_SPARC -/*XXX*/ -#define ELF_PLAT_INIT(_r) - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { regs->psr = 0; @@ -192,20 +185,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif #define ELF_ARCH EM_PPC -/* Note that isn't exactly what regular kernel does - * but this is what the ABI wants and is needed to allow - * execution of PPC BSD programs. - */ -#define ELF_PLAT_INIT(_r) \ -do { \ - target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \ - _r->gpr[3] = bprm->argc; \ - _r->gpr[4] = (unsigned long)++pos; \ - for (; tmp != 0; pos++) \ - tmp = ldl(pos); \ - _r->gpr[5] = (unsigned long)pos; \ -} while (0) - /* * We need to put in some extra aux table entries to tell glibc what * the cache block size is, so it can use the dcbz instruction safely. @@ -239,9 +218,22 @@ do { \ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) { + target_ulong pos = infop->start_stack; + target_ulong tmp; + _regs->msr = 1 << MSR_PR; /* Set user mode */ _regs->gpr[1] = infop->start_stack; _regs->nip = infop->entry; + /* Note that isn't exactly what regular kernel does + * but this is what the ABI wants and is needed to allow + * execution of PPC BSD programs. + */ + _regs->gpr[3] = tgetl(pos); + pos += sizeof(target_ulong); + _regs->gpr[4] = pos; + for (tmp = 1; tmp != 0; pos += sizeof(target_ulong)) + tmp = ldl(pos); + _regs->gpr[5] = pos; } #define USE_ELF_CORE_DUMP @@ -263,8 +255,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * #endif #define ELF_ARCH EM_MIPS -#define ELF_PLAT_INIT(_r) - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { regs->cp0_status = CP0St_UM; @@ -284,8 +274,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_SH -#define ELF_PLAT_INIT(_r) /* XXXXX */ - static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { /* Check other registers XXXXX */ @@ -308,30 +296,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #include "elf.h" -/* - * MAX_ARG_PAGES defines the number of pages allocated for arguments - * and envelope for the new program. 32 should suffice, this gives - * a maximum env+arg of 128kB w/4KB pages! - */ -#define MAX_ARG_PAGES 32 - -/* - * This structure is used to hold the arguments that are - * used when loading binaries. - */ -struct linux_binprm { - char buf[128]; - void *page[MAX_ARG_PAGES]; - unsigned long p; - int sh_bang; - int fd; - int e_uid, e_gid; - int argc, envc; - char * filename; /* Name of binary */ - unsigned long loader, exec; - int dont_iput; /* binfmt handler has put inode */ -}; - struct exec { unsigned int a_info; /* Use macros N_MAGIC, etc for access */ @@ -377,8 +341,6 @@ struct exec #define PER_XENIX (0x0007 | STICKY_TIMEOUTS) /* Necessary parameters */ -#define NGROUPS 32 - #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) #define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) @@ -452,13 +414,13 @@ static void bswap_sym(Elf32_Sym *sym) #endif /* - * 'copy_string()' copies argument/envelope strings from user + * 'copy_elf_strings()' copies argument/envelope strings from user * memory to free pages in kernel mem. These are in a format ready * to be put directly into the top of new user memory. * */ -static unsigned long copy_strings(int argc,char ** argv, void **page, - unsigned long p) +static unsigned long copy_elf_strings(int argc,char ** argv, void **page, + unsigned long p) { char *tmp, *tmp1, *pag = NULL; int len, offset = 0; @@ -506,101 +468,6 @@ static unsigned long copy_strings(int argc,char ** argv, void **page, return p; } -static int in_group_p(gid_t g) -{ - /* return TRUE if we're in the specified group, FALSE otherwise */ - int ngroup; - int i; - gid_t grouplist[NGROUPS]; - - ngroup = getgroups(NGROUPS, grouplist); - for(i = 0; i < ngroup; i++) { - if(grouplist[i] == g) { - return 1; - } - } - return 0; -} - -static int count(char ** vec) -{ - int i; - - for(i = 0; *vec; i++) { - vec++; - } - - return(i); -} - -static int prepare_binprm(struct linux_binprm *bprm) -{ - struct stat st; - int mode; - int retval, id_change; - - if(fstat(bprm->fd, &st) < 0) { - return(-errno); - } - - mode = st.st_mode; - if(!S_ISREG(mode)) { /* Must be regular file */ - return(-EACCES); - } - if(!(mode & 0111)) { /* Must have at least one execute bit set */ - return(-EACCES); - } - - bprm->e_uid = geteuid(); - bprm->e_gid = getegid(); - id_change = 0; - - /* Set-uid? */ - if(mode & S_ISUID) { - bprm->e_uid = st.st_uid; - if(bprm->e_uid != geteuid()) { - id_change = 1; - } - } - - /* Set-gid? */ - /* - * If setgid is set but no group execute bit then this - * is a candidate for mandatory locking, not a setgid - * executable. - */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { - bprm->e_gid = st.st_gid; - if (!in_group_p(bprm->e_gid)) { - id_change = 1; - } - } - - memset(bprm->buf, 0, sizeof(bprm->buf)); - retval = lseek(bprm->fd, 0L, SEEK_SET); - if(retval >= 0) { - retval = read(bprm->fd, bprm->buf, 128); - } - if(retval < 0) { - perror("prepare_binprm"); - exit(-1); - /* return(-errno); */ - } - else { - return(retval); - } -} - -static inline void memcpy_to_target(target_ulong dest, const void *src, - unsigned long len) -{ - void *host_ptr; - - host_ptr = lock_user(dest, len, 0); - memcpy(host_ptr, src, len); - unlock_user(host_ptr, dest, 1); -} - unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, struct image_info * info) { @@ -628,11 +495,6 @@ unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; p += stack_base; - if (bprm->loader) { - bprm->loader += stack_base; - } - bprm->exec += stack_base; - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { info->rss++; @@ -703,7 +565,6 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, unsigned long interp_load_addr, int ibcs, struct image_info *info) { - target_ulong argv, envp; target_ulong sp; int size; target_ulong u_platform; @@ -765,28 +626,7 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, #endif #undef NEW_AUX_ENT - sp -= (envc + 1) * n; - envp = sp; - sp -= (argc + 1) * n; - argv = sp; - if (!ibcs) { - sp -= n; tputl(sp, envp); - sp -= n; tputl(sp, argv); - } - sp -= n; tputl(sp, argc); - info->arg_start = p; - while (argc-->0) { - tputl(argv, p); argv += n; - p += target_strlen(p) + 1; - } - tputl(argv, 0); - info->arg_end = info->env_start = p; - while (envc-->0) { - tputl(envp, p); envp += n; - p += target_strlen(p) + 1; - } - tputl(envp, 0); - info->env_end = p; + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); return sp; } @@ -1001,8 +841,8 @@ static void load_symbols(struct elfhdr *hdr, int fd) syminfos = s; } -static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info) +int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; @@ -1034,17 +874,19 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r bswap_ehdr(&elf_ex); #endif - if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) { - return -ENOEXEC; - } - /* First of all, some simple consistency checks */ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || (! elf_check_arch(elf_ex.e_machine))) { return -ENOEXEC; } + bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); + bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + if (!bprm->p) { + retval = -E2BIG; + } + /* Now read in all of the header information */ elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); if (elf_phdata == NULL) { @@ -1188,7 +1030,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ - if (!bprm->sh_bang) { + { char * passed_p; if (interpreter_type == INTERPRETER_AOUT) { @@ -1196,7 +1038,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r passed_p = passed_fileno; if (elf_interpreter) { - bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p); + bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); bprm->argc++; } } @@ -1347,11 +1189,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1), info); - if (interpreter_type == INTERPRETER_AOUT) - info->arg_start += strlen(passed_fileno) + 1; info->start_brk = info->brk = elf_brk; info->end_code = end_code; info->start_code = start_code; + info->start_data = end_code; info->end_data = end_data; info->start_stack = bprm->p; @@ -1380,79 +1221,18 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r MAP_FIXED | MAP_PRIVATE, -1, 0); } -#ifdef ELF_PLAT_INIT - /* - * The ABI may specify that certain registers be set up in special - * ways (on i386 %edx is the address of a DT_FINI function, for - * example. This macro performs whatever initialization to - * the regs structure is required. - */ - ELF_PLAT_INIT(regs); -#endif - - info->entry = elf_entry; return 0; } - - -int elf_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop) -{ - struct linux_binprm bprm; - int retval; - int i; - - bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); - for (i=0 ; i=0) { - bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p); - bprm.exec = bprm.p; - bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p); - bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p); - if (!bprm.p) { - retval = -E2BIG; - } - } - - if(retval>=0) { - retval = load_elf_binary(&bprm,regs,infop); - } - - if(retval>=0) { - /* success. Initialize important registers */ - init_thread(regs, infop); - return retval; - } - - /* Something went wrong, return the inode and free the argument pages*/ - for (i=0 ; i + * Copyright (C) 1998 Kenneth Albanowski + * The Silver Hammer Group, Ltd. + * + * This file provides the definitions and structures needed to + * support uClinux flat-format executables. + */ + +#define FLAT_VERSION 0x00000004L + +#ifdef CONFIG_BINFMT_SHARED_FLAT +#define MAX_SHARED_LIBS (4) +#else +#define MAX_SHARED_LIBS (1) +#endif + +/* + * To make everything easier to port and manage cross platform + * development, all fields are in network byte order. + */ + +struct flat_hdr { + char magic[4]; + unsigned long rev; /* version (as above) */ + unsigned long entry; /* Offset of first executable instruction + with text segment from beginning of file */ + unsigned long data_start; /* Offset of data segment from beginning of + file */ + unsigned long data_end; /* Offset of end of data segment + from beginning of file */ + unsigned long bss_end; /* Offset of end of bss segment from beginning + of file */ + + /* (It is assumed that data_end through bss_end forms the bss segment.) */ + + unsigned long stack_size; /* Size of stack, in bytes */ + unsigned long reloc_start; /* Offset of relocation records from + beginning of file */ + unsigned long reloc_count; /* Number of relocation records */ + unsigned long flags; + unsigned long build_date; /* When the program/library was built */ + unsigned long filler[5]; /* Reservered, set to zero */ +}; + +#define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */ +#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */ +#define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */ +#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */ +#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */ + + +/* + * While it would be nice to keep this header clean, users of older + * tools still need this support in the kernel. So this section is + * purely for compatibility with old tool chains. + * + * DO NOT make changes or enhancements to the old format please, just work + * with the format above, except to fix bugs with old format support. + */ + +#define OLD_FLAT_VERSION 0x00000002L +#define OLD_FLAT_RELOC_TYPE_TEXT 0 +#define OLD_FLAT_RELOC_TYPE_DATA 1 +#define OLD_FLAT_RELOC_TYPE_BSS 2 + +# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */ diff --git a/linux-user/flatload.c b/linux-user/flatload.c new file mode 100644 index 000000000..1e2634b5a --- /dev/null +++ b/linux-user/flatload.c @@ -0,0 +1,790 @@ +/****************************************************************************/ +/* + * QEMU bFLT binary loader. Based on linux/fs/binfmt_flat.c + * + * 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. + * + * Copyright (C) 2006 CodeSourcery. + * Copyright (C) 2000-2003 David McCullough + * Copyright (C) 2002 Greg Ungerer + * Copyright (C) 2002 SnapGear, by Paul Dale + * Copyright (C) 2000, 2001 Lineo, by David McCullough + * based heavily on: + * + * linux/fs/binfmt_aout.c: + * Copyright (C) 1991, 1992, 1996 Linus Torvalds + * linux/fs/binfmt_flat.c for 2.0 kernel + * Copyright (C) 1998 Kenneth Albanowski + * JAN/99 -- coded full program relocation (gerg@snapgear.com) + */ + +/* ??? ZFLAT and shared library support is currently disabled. */ + +/****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "qemu.h" +#include "flat.h" + +//#define DEBUG + +#ifdef DEBUG +#define DBG_FLT(a...) printf(a) +#else +#define DBG_FLT(a...) +#endif + +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) +#define flat_old_ram_flag(flag) (flag) +#ifdef TARGET_WORDS_BIGENDIAN +#define flat_get_relocate_addr(relval) (relval) +#else +#define flat_get_relocate_addr(relval) bswap32(relval) +#endif + +#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ +#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ + +struct lib_info { + target_ulong start_code; /* Start of text segment */ + target_ulong start_data; /* Start of data segment */ + target_ulong end_data; /* Start of bss section */ + target_ulong start_brk; /* End of data segment */ + target_ulong text_len; /* Length of text segment */ + target_ulong entry; /* Start address for this module */ + target_ulong build_date; /* When this one was compiled */ + short loaded; /* Has this library been loaded? */ +}; + +#ifdef CONFIG_BINFMT_SHARED_FLAT +static int load_flat_shared_library(int id, struct lib_info *p); +#endif + +struct linux_binprm; + +#define ntohl(x) be32_to_cpu(x) + +/****************************************************************************/ +/* + * create_flat_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ + +/* Push a block of strings onto the guest stack. */ +static target_ulong copy_strings(target_ulong p, int n, char **s) +{ + int len; + + while (n-- > 0) { + len = strlen(s[n]) + 1; + p -= len; + memcpy_to_target(p, s[n], len); + } + + return p; +} + +int target_pread(int fd, target_ulong ptr, target_ulong len, + target_ulong offset) +{ + void *buf; + int ret; + + buf = lock_user(ptr, len, 0); + ret = pread(fd, buf, len, offset); + unlock_user(buf, ptr, len); + return ret; +} +/****************************************************************************/ + +#ifdef CONFIG_BINFMT_ZFLAT + +#include + +#define LBUFSIZE 4000 + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +static int decompress_exec( + struct linux_binprm *bprm, + unsigned long offset, + char *dst, + long len, + int fd) +{ + unsigned char *buf; + z_stream strm; + loff_t fpos; + int ret, retval; + + DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len); + + memset(&strm, 0, sizeof(strm)); + strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (strm.workspace == NULL) { + DBG_FLT("binfmt_flat: no memory for decompress workspace\n"); + return -ENOMEM; + } + buf = kmalloc(LBUFSIZE, GFP_KERNEL); + if (buf == NULL) { + DBG_FLT("binfmt_flat: no memory for read buffer\n"); + retval = -ENOMEM; + goto out_free; + } + + /* Read in first chunk of data and parse gzip header. */ + fpos = offset; + ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); + + strm.next_in = buf; + strm.avail_in = ret; + strm.total_in = 0; + + retval = -ENOEXEC; + + /* Check minimum size -- gzip header */ + if (ret < 10) { + DBG_FLT("binfmt_flat: file too small?\n"); + goto out_free_buf; + } + + /* Check gzip magic number */ + if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) { + DBG_FLT("binfmt_flat: unknown compression magic?\n"); + goto out_free_buf; + } + + /* Check gzip method */ + if (buf[2] != 8) { + DBG_FLT("binfmt_flat: unknown compression method?\n"); + goto out_free_buf; + } + /* Check gzip flags */ + if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) || + (buf[3] & RESERVED)) { + DBG_FLT("binfmt_flat: unknown flags?\n"); + goto out_free_buf; + } + + ret = 10; + if (buf[3] & EXTRA_FIELD) { + ret += 2 + buf[10] + (buf[11] << 8); + if (unlikely(LBUFSIZE == ret)) { + DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n"); + goto out_free_buf; + } + } + if (buf[3] & ORIG_NAME) { + for (; ret < LBUFSIZE && (buf[ret] != 0); ret++) + ; + if (unlikely(LBUFSIZE == ret)) { + DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n"); + goto out_free_buf; + } + } + if (buf[3] & COMMENT) { + for (; ret < LBUFSIZE && (buf[ret] != 0); ret++) + ; + if (unlikely(LBUFSIZE == ret)) { + DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n"); + goto out_free_buf; + } + } + + strm.next_in += ret; + strm.avail_in -= ret; + + strm.next_out = dst; + strm.avail_out = len; + strm.total_out = 0; + + if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) { + DBG_FLT("binfmt_flat: zlib init failed?\n"); + goto out_free_buf; + } + + while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) { + ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); + if (ret <= 0) + break; + if (ret >= (unsigned long) -4096) + break; + len -= ret; + + strm.next_in = buf; + strm.avail_in = ret; + strm.total_in = 0; + } + + if (ret < 0) { + DBG_FLT("binfmt_flat: decompression failed (%d), %s\n", + ret, strm.msg); + goto out_zlib; + } + + retval = 0; +out_zlib: + zlib_inflateEnd(&strm); +out_free_buf: + kfree(buf); +out_free: + kfree(strm.workspace); +out: + return retval; +} + +#endif /* CONFIG_BINFMT_ZFLAT */ + +/****************************************************************************/ + +static target_ulong +calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp) +{ + target_ulong addr; + int id; + target_ulong start_brk; + target_ulong start_data; + target_ulong text_len; + target_ulong start_code; + +#ifdef CONFIG_BINFMT_SHARED_FLAT +#error needs checking + if (r == 0) + id = curid; /* Relocs of 0 are always self referring */ + else { + id = (r >> 24) & 0xff; /* Find ID for this reloc */ + r &= 0x00ffffff; /* Trim ID off here */ + } + if (id >= MAX_SHARED_LIBS) { + fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n", + (unsigned) r, id); + goto failed; + } + if (curid != id) { + if (internalp) { + fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not " + "in same module (%d != %d)\n", + (unsigned) r, curid, id); + goto failed; + } else if ( ! p[id].loaded && + load_flat_shared_library(id, p) > (unsigned long) -4096) { + fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id); + goto failed; + } + /* Check versioning information (i.e. time stamps) */ + if (p[id].build_date && p[curid].build_date + && p[curid].build_date < p[id].build_date) { + fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n", + id, curid); + goto failed; + } + } +#else + id = 0; +#endif + + start_brk = p[id].start_brk; + start_data = p[id].start_data; + start_code = p[id].start_code; + text_len = p[id].text_len; + + if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { + fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x " + "(0 - 0x%x/0x%x)\n", + (int) r,(int)(start_brk-start_code),(int)text_len); + goto failed; + } + + if (r < text_len) /* In text segment */ + addr = r + start_code; + else /* In data segment */ + addr = r - text_len + start_data; + + /* Range checked already above so doing the range tests is redundant...*/ + return(addr); + +failed: + abort(); + return RELOC_FAILED; +} + +/****************************************************************************/ + +/* ??? This does not handle endianness correctly. */ +void old_reloc(struct lib_info *libinfo, uint32_t rl) +{ +#ifdef DEBUG + char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; +#endif + uint32_t *ptr; + uint32_t offset; + int reloc_type; + + offset = rl & 0x3fffffff; + reloc_type = rl >> 30; + /* ??? How to handle this? */ +#if defined(CONFIG_COLDFIRE) + ptr = (uint32_t *) (libinfo->start_code + offset); +#else + ptr = (uint32_t *) (libinfo->start_data + offset); +#endif + +#ifdef DEBUG + fprintf(stderr, "Relocation of variable at DATASEG+%x " + "(address %p, currently %x) into segment %s\n", + offset, ptr, (int)*ptr, segment[reloc_type]); +#endif + + switch (reloc_type) { + case OLD_FLAT_RELOC_TYPE_TEXT: + *ptr += libinfo->start_code; + break; + case OLD_FLAT_RELOC_TYPE_DATA: + *ptr += libinfo->start_data; + break; + case OLD_FLAT_RELOC_TYPE_BSS: + *ptr += libinfo->end_data; + break; + default: + fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n", + reloc_type); + break; + } + DBG_FLT("Relocation became %x\n", (int)*ptr); +} + +/****************************************************************************/ + +static int load_flat_file(struct linux_binprm * bprm, + struct lib_info *libinfo, int id, target_ulong *extra_stack) +{ + struct flat_hdr * hdr; + target_ulong textpos = 0, datapos = 0, result; + target_ulong realdatastart = 0; + target_ulong text_len, data_len, bss_len, stack_len, flags; + target_ulong memp = 0; /* for finding the brk area */ + target_ulong extra; + target_ulong reloc = 0, rp; + int i, rev, relocs = 0; + target_ulong fpos; + target_ulong start_code, end_code; + + hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ + + text_len = ntohl(hdr->data_start); + data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start); + bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end); + stack_len = ntohl(hdr->stack_size); + if (extra_stack) { + stack_len += *extra_stack; + *extra_stack = stack_len; + } + relocs = ntohl(hdr->reloc_count); + flags = ntohl(hdr->flags); + rev = ntohl(hdr->rev); + + DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename); + + if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) { + fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n", + rev, (int) FLAT_VERSION); + return -ENOEXEC; + } + + /* Don't allow old format executables to use shared libraries */ + if (rev == OLD_FLAT_VERSION && id != 0) { + fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n"); + return -ENOEXEC; + } + + /* + * fix up the flags for the older format, there were all kinds + * of endian hacks, this only works for the simple cases + */ + if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags)) + flags = FLAT_FLAG_RAM; + +#ifndef CONFIG_BINFMT_ZFLAT + if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { + fprintf(stderr, "Support for ZFLAT executables is not enabled\n"); + return -ENOEXEC; + } +#endif + + /* + * calculate the extra space we need to map in + */ + extra = relocs * sizeof(target_ulong); + if (extra < bss_len + stack_len) + extra = bss_len + stack_len; + + /* + * there are a couple of cases here, the separate code/data + * case, and then the fully copied to RAM case which lumps + * it all together. + */ + if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) { + /* + * this should give us a ROM ptr, but if it doesn't we don't + * really care + */ + DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); + + textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC, + MAP_PRIVATE, bprm->fd, 0); + if (textpos == -1) { + fprintf(stderr, "Unable to mmap process text\n"); + return -1; + } + + realdatastart = target_mmap(0, data_len + extra + + MAX_SHARED_LIBS * sizeof(target_ulong), + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (realdatastart == -1) { + fprintf(stderr, "Unable to allocate RAM for process data\n"); + return realdatastart; + } + datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong); + + DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", + (int)(data_len + bss_len + stack_len), (int)datapos); + + fpos = ntohl(hdr->data_start); +#ifdef CONFIG_BINFMT_ZFLAT + if (flags & FLAT_FLAG_GZDATA) { + result = decompress_exec(bprm, fpos, (char *) datapos, + data_len + (relocs * sizeof(target_ulong))) + } else +#endif + { + result = target_pread(bprm->fd, datapos, + data_len + (relocs * sizeof(target_ulong)), + fpos); + } + if (result < 0) { + fprintf(stderr, "Unable to read data+bss\n"); + return result; + } + + reloc = datapos + (ntohl(hdr->reloc_start) - text_len); + memp = realdatastart; + + } else { + + textpos = target_mmap(0, text_len + data_len + extra + + MAX_SHARED_LIBS * sizeof(target_ulong), + PROT_READ | PROT_EXEC | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (textpos == -1 ) { + fprintf(stderr, "Unable to allocate RAM for process text/data\n"); + return -1; + } + + realdatastart = textpos + ntohl(hdr->data_start); + datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong); + reloc = (textpos + ntohl(hdr->reloc_start) + + MAX_SHARED_LIBS * sizeof(target_ulong)); + memp = textpos; + +#ifdef CONFIG_BINFMT_ZFLAT +#error code needs checking + /* + * load it all in and treat it like a RAM load from now on + */ + if (flags & FLAT_FLAG_GZIP) { + result = decompress_exec(bprm, sizeof (struct flat_hdr), + (((char *) textpos) + sizeof (struct flat_hdr)), + (text_len + data_len + (relocs * sizeof(unsigned long)) + - sizeof (struct flat_hdr)), + 0); + memmove((void *) datapos, (void *) realdatastart, + data_len + (relocs * sizeof(unsigned long))); + } else if (flags & FLAT_FLAG_GZDATA) { + fpos = 0; + result = bprm->file->f_op->read(bprm->file, + (char *) textpos, text_len, &fpos); + if (result < (unsigned long) -4096) + result = decompress_exec(bprm, text_len, (char *) datapos, + data_len + (relocs * sizeof(unsigned long)), 0); + } + else +#endif + { + result = target_pread(bprm->fd, textpos, + text_len, 0); + if (result >= 0) { + result = target_pread(bprm->fd, datapos, + data_len + (relocs * sizeof(target_ulong)), + ntohl(hdr->data_start)); + } + } + if (result < 0) { + fprintf(stderr, "Unable to read code+data+bss\n"); + return result; + } + } + + DBG_FLT("Mapping is 0x%x, Entry point is 0x%x, data_start is 0x%x\n", + (int)textpos, 0x00ffffff&ntohl(hdr->entry), + ntohl(hdr->data_start)); + + /* The main program needs a little extra setup in the task structure */ + start_code = textpos + sizeof (struct flat_hdr); + end_code = textpos + text_len; + + DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n", + id ? "Lib" : "Load", bprm->filename, + (int) start_code, (int) end_code, + (int) datapos, + (int) (datapos + data_len), + (int) (datapos + data_len), + (int) (((datapos + data_len + bss_len) + 3) & ~3)); + + text_len -= sizeof(struct flat_hdr); /* the real code len */ + + /* Store the current module values into the global library structure */ + libinfo[id].start_code = start_code; + libinfo[id].start_data = datapos; + libinfo[id].end_data = datapos + data_len; + libinfo[id].start_brk = datapos + data_len + bss_len; + libinfo[id].text_len = text_len; + libinfo[id].loaded = 1; + libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos; + libinfo[id].build_date = ntohl(hdr->build_date); + + /* + * We just load the allocations into some temporary memory to + * help simplify all this mumbo jumbo + * + * We've got two different sections of relocation entries. + * The first is the GOT which resides at the begining of the data segment + * and is terminated with a -1. This one can be relocated in place. + * The second is the extra relocation entries tacked after the image's + * data segment. These require a little more processing as the entry is + * really an offset into the image which contains an offset into the + * image. + */ + if (flags & FLAT_FLAG_GOTPIC) { + rp = datapos; + while (1) { + target_ulong addr; + addr = tgetl(rp); + if (addr == -1) + break; + if (addr) { + addr = calc_reloc(addr, libinfo, id, 0); + if (addr == RELOC_FAILED) + return -ENOEXEC; + tputl(rp, addr); + } + rp += sizeof(target_ulong); + } + } + + /* + * Now run through the relocation entries. + * We've got to be careful here as C++ produces relocatable zero + * entries in the constructor and destructor tables which are then + * tested for being not zero (which will always occur unless we're + * based from address zero). This causes an endless loop as __start + * is at zero. The solution used is to not relocate zero addresses. + * This has the negative side effect of not allowing a global data + * reference to be statically initialised to _stext (I've moved + * __start to address 4 so that is okay). + */ + if (rev > OLD_FLAT_VERSION) { + for (i = 0; i < relocs; i++) { + target_ulong addr, relval; + + /* Get the address of the pointer to be + relocated (of course, the address has to be + relocated first). */ + relval = tgetl(reloc + i * sizeof (target_ulong)); + addr = flat_get_relocate_addr(relval); + rp = calc_reloc(addr, libinfo, id, 1); + if (rp == RELOC_FAILED) + return -ENOEXEC; + + /* Get the pointer's value. */ + addr = tgetl(rp); + if (addr != 0) { + /* + * Do the relocation. PIC relocs in the data section are + * already in target order + */ + +#ifndef TARGET_WORDS_BIGENDIAN + if ((flags & FLAT_FLAG_GOTPIC) == 0) + addr = bswap32(addr); +#endif + addr = calc_reloc(addr, libinfo, id, 0); + if (addr == RELOC_FAILED) + return -ENOEXEC; + + /* Write back the relocated pointer. */ + tputl(rp, addr); + } + } + } else { + for (i = 0; i < relocs; i++) { + target_ulong relval; + relval = tgetl(reloc + i * sizeof (target_ulong)); + old_reloc(&libinfo[0], relval); + } + } + + /* zero the BSS. */ + memset((void*)(datapos + data_len), 0, bss_len); + + return 0; +} + + +/****************************************************************************/ +#ifdef CONFIG_BINFMT_SHARED_FLAT + +/* + * Load a shared library into memory. The library gets its own data + * segment (including bss) but not argv/argc/environ. + */ + +static int load_flat_shared_library(int id, struct lib_info *libs) +{ + struct linux_binprm bprm; + int res; + char buf[16]; + + /* Create the file name */ + sprintf(buf, "/lib/lib%d.so", id); + + /* Open the file up */ + bprm.filename = buf; + bprm.file = open_exec(bprm.filename); + res = PTR_ERR(bprm.file); + if (IS_ERR(bprm.file)) + return res; + + res = prepare_binprm(&bprm); + + if (res <= (unsigned long)-4096) + res = load_flat_file(&bprm, libs, id, NULL); + if (bprm.file) { + allow_write_access(bprm.file); + fput(bprm.file); + bprm.file = NULL; + } + return(res); +} + +#endif /* CONFIG_BINFMT_SHARED_FLAT */ + +int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) +{ + struct lib_info libinfo[MAX_SHARED_LIBS]; + target_ulong p = bprm->p; + target_ulong stack_len; + target_ulong start_addr; + target_ulong sp; + int res; + int i, j; + + memset(libinfo, 0, sizeof(libinfo)); + /* + * We have to add the size of our arguments to our stack size + * otherwise it's too easy for users to create stack overflows + * by passing in a huge argument list. And yes, we have to be + * pedantic and include space for the argv/envp array as it may have + * a lot of entries. + */ +#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *)) + stack_len = TOP_OF_ARGS - bprm->p; /* the strings */ + stack_len += (bprm->argc + 1) * 4; /* the argv array */ + stack_len += (bprm->envc + 1) * 4; /* the envp array */ + + + res = load_flat_file(bprm, libinfo, 0, &stack_len); + if (res > (unsigned long)-4096) + return res; + + /* Update data segment pointers for all libraries */ + for (i=0; iargc, bprm->argv); + p = copy_strings(p, bprm->envc, bprm->envp); + /* Align stack. */ + sp = p & ~(target_ulong)(sizeof(target_ulong) - 1); + sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1); + + /* Fake some return addresses to ensure the call chain will + * initialise library in order for us. We are required to call + * lib 1 first, then 2, ... and finally the main program (id 0). + */ + start_addr = libinfo[0].entry; + +#ifdef CONFIG_BINFMT_SHARED_FLAT +#error here + for (i = MAX_SHARED_LIBS-1; i>0; i--) { + if (libinfo[i].loaded) { + /* Push previos first to call address */ + --sp; put_user(start_addr, sp); + start_addr = libinfo[i].entry; + } + } +#endif + + /* Stash our initial stack pointer into the mm structure */ + info->start_code = libinfo[0].start_code; + info->end_code = libinfo[0].start_code = libinfo[0].text_len; + info->start_data = libinfo[0].start_data; + info->end_data = libinfo[0].end_data; + info->start_brk = libinfo[0].start_brk; + info->start_stack = sp; + info->entry = start_addr; + DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n", + (int)info->entry, (int)info->start_stack); + + return 0; +} diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c new file mode 100644 index 000000000..ef5409b95 --- /dev/null +++ b/linux-user/linuxload.c @@ -0,0 +1,195 @@ +/* Code for loading Linux executables. Mostly linux kenrel code. */ + +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +#define NGROUPS 32 + +/* ??? This should really be somewhere else. */ +void memcpy_to_target(target_ulong dest, const void *src, + unsigned long len) +{ + void *host_ptr; + + host_ptr = lock_user(dest, len, 0); + memcpy(host_ptr, src, len); + unlock_user(host_ptr, dest, 1); +} + +static int in_group_p(gid_t g) +{ + /* return TRUE if we're in the specified group, FALSE otherwise */ + int ngroup; + int i; + gid_t grouplist[NGROUPS]; + + ngroup = getgroups(NGROUPS, grouplist); + for(i = 0; i < ngroup; i++) { + if(grouplist[i] == g) { + return 1; + } + } + return 0; +} + +static int count(char ** vec) +{ + int i; + + for(i = 0; *vec; i++) { + vec++; + } + + return(i); +} + +static int prepare_binprm(struct linux_binprm *bprm) +{ + struct stat st; + int mode; + int retval, id_change; + + if(fstat(bprm->fd, &st) < 0) { + return(-errno); + } + + mode = st.st_mode; + if(!S_ISREG(mode)) { /* Must be regular file */ + return(-EACCES); + } + if(!(mode & 0111)) { /* Must have at least one execute bit set */ + return(-EACCES); + } + + bprm->e_uid = geteuid(); + bprm->e_gid = getegid(); + id_change = 0; + + /* Set-uid? */ + if(mode & S_ISUID) { + bprm->e_uid = st.st_uid; + if(bprm->e_uid != geteuid()) { + id_change = 1; + } + } + + /* Set-gid? */ + /* + * If setgid is set but no group execute bit then this + * is a candidate for mandatory locking, not a setgid + * executable. + */ + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { + bprm->e_gid = st.st_gid; + if (!in_group_p(bprm->e_gid)) { + id_change = 1; + } + } + + memset(bprm->buf, 0, sizeof(bprm->buf)); + retval = lseek(bprm->fd, 0L, SEEK_SET); + if(retval >= 0) { + retval = read(bprm->fd, bprm->buf, 128); + } + if(retval < 0) { + perror("prepare_binprm"); + exit(-1); + /* return(-errno); */ + } + else { + return(retval); + } +} + +/* Construct the envp and argv tables on the target stack. */ +target_ulong loader_build_argptr(int envc, int argc, target_ulong sp, + target_ulong stringp, int push_ptr) +{ + int n = sizeof(target_ulong); + target_ulong envp; + target_ulong argv; + + sp -= (envc + 1) * n; + envp = sp; + sp -= (argc + 1) * n; + argv = sp; + if (push_ptr) { + sp -= n; tputl(sp, envp); + sp -= n; tputl(sp, argv); + } + sp -= n; tputl(sp, argc); + + while (argc-- > 0) { + tputl(argv, stringp); argv += n; + stringp += target_strlen(stringp) + 1; + } + tputl(argv, 0); + while (envc-- > 0) { + tputl(envp, stringp); envp += n; + stringp += target_strlen(stringp) + 1; + } + tputl(envp, 0); + + return sp; +} + +int loader_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs, struct image_info *infop) +{ + struct linux_binprm bprm; + int retval; + int i; + + bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); + for (i=0 ; i=0) { + if (bprm.buf[0] == 0x7f + && bprm.buf[1] == 'E' + && bprm.buf[2] == 'L' + && bprm.buf[3] == 'F') { + retval = load_elf_binary(&bprm,regs,infop); +#if defined(TARGET_HAS_BFLT) + } else if (bprm.buf[0] == 'b' + && bprm.buf[1] == 'F' + && bprm.buf[2] == 'L' + && bprm.buf[3] == 'T') { + retval = load_flt_binary(&bprm,regs,infop); +#endif + } else { + fprintf(stderr, "Unknown binary format\n"); + return -1; + } + } + + if(retval>=0) { + /* success. Initialize important registers */ + do_init_thread(regs, infop); + return retval; + } + + /* Something went wrong, return the inode and free the argument pages*/ + for (i=0 ; istart_brk); fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); + fprintf(logfile, "start_data 0x%08lx\n" , info->start_data); fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); fprintf(logfile, "brk 0x%08lx\n" , info->brk); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 7c7bcf34e..9047fcf14 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -18,6 +18,7 @@ struct image_info { unsigned long start_code; unsigned long end_code; + unsigned long start_data; unsigned long end_data; unsigned long start_brk; unsigned long brk; @@ -25,10 +26,6 @@ struct image_info { unsigned long mmap; unsigned long rss; unsigned long start_stack; - unsigned long arg_start; - unsigned long arg_end; - unsigned long env_start; - unsigned long env_end; unsigned long entry; int personality; }; @@ -82,9 +79,43 @@ typedef struct TaskState { extern TaskState *first_task_state; extern const char *qemu_uname_release; -int elf_exec(const char * filename, char ** argv, char ** envp, +/* ??? See if we can avoid exposing so much of the loader internals. */ +/* + * MAX_ARG_PAGES defines the number of pages allocated for arguments + * and envelope for the new program. 32 should suffice, this gives + * a maximum env+arg of 128kB w/4KB pages! + */ +#define MAX_ARG_PAGES 32 + +/* + * This structure is used to hold the arguments that are + * used when loading binaries. + */ +struct linux_binprm { + char buf[128]; + void *page[MAX_ARG_PAGES]; + unsigned long p; + int fd; + int e_uid, e_gid; + int argc, envc; + char **argv; + char **envp; + char * filename; /* Name of binary */ +}; + +void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); +target_ulong loader_build_argptr(int envc, int argc, target_ulong sp, + target_ulong stringp, int push_ptr); +int loader_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); +int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); +int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); + +void memcpy_to_target(target_ulong dest, const void *src, + unsigned long len); void target_set_brk(target_ulong new_brk); long do_brk(target_ulong new_brk); void syscall_init(void); -- cgit v1.2.3 From 79737e4a7da78d13bd195014f5767d1519dbdfcb Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Jun 2006 16:28:41 +0000 Subject: Document new arm-user features. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1952 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 4cb034c7c..2b37179c5 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1531,6 +1531,7 @@ information is available in the QEMU mailing-list archive. * Quick Start:: * Wine launch:: * Command line options:: +* Other binaries:: @end menu @node Quick Start @@ -1637,6 +1638,15 @@ Activate log (logfile=/tmp/qemu.log) Act as if the host page size was 'pagesize' bytes @end table +@node Other binaries +@section Other binaries + +@command{qemu-arm} is also capable of running ARM "Angel" semihosted ELF +binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB +configurations), and arm-uclinux bFLT format binaries. + +The binary format is detected automatically. + @node compilation @chapter Compilation from the sources -- cgit v1.2.3 From 8785a8ddcc6e772d82744279447bb9541da5a407 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 Jun 2006 10:49:12 +0000 Subject: 'invisible wall' patch (Anthony Liguori) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1953 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sdl.c b/sdl.c index ec4f93c5e..d99505ef1 100644 --- a/sdl.c +++ b/sdl.c @@ -285,13 +285,18 @@ static void sdl_update_caption(void) static void sdl_hide_cursor(void) { - SDL_SetCursor(sdl_cursor_hidden); + if (kbd_mouse_is_absolute()) { + SDL_ShowCursor(1); + SDL_SetCursor(sdl_cursor_hidden); + } else { + SDL_ShowCursor(0); + } } static void sdl_show_cursor(void) { if (!kbd_mouse_is_absolute()) { - SDL_SetCursor(sdl_cursor_normal); + SDL_ShowCursor(1); } } -- cgit v1.2.3 From c66b0d4cf4ef84325d3f579c0e3ea5254d7b348a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 Jun 2006 12:03:53 +0000 Subject: avoid stopping QEMU when switching desktops with Ctrl-Alt-x git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1954 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sdl.c b/sdl.c index d99505ef1..38d75536d 100644 --- a/sdl.c +++ b/sdl.c @@ -447,10 +447,18 @@ static void sdl_refresh(DisplayState *ds) gui_key_modifier_pressed = 0; if (gui_keysym == 0) { /* exit/enter grab if pressing Ctrl-Alt */ - if (!gui_grab) - sdl_grab_start(); - else + if (!gui_grab) { + /* if the application is not active, + do not try to enter grab state. It + prevents + 'SDL_WM_GrabInput(SDL_GRAB_ON)' + from blocking all the application + (SDL bug). */ + if (SDL_GetAppState() & SDL_APPACTIVE) + sdl_grab_start(); + } else { sdl_grab_end(); + } /* SDL does not send back all the modifiers key, so we must correct it */ reset_keys(); -- cgit v1.2.3 From 74a14f22b8c273e7473e941beb861a827723c66a Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 Jun 2006 15:57:21 +0000 Subject: increase video memory to 8MB git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1955 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.h b/vl.h index ecfc0c417..94da5a6e3 100644 --- a/vl.h +++ b/vl.h @@ -705,7 +705,7 @@ extern struct soundhw soundhw[]; /* vga.c */ -#define VGA_RAM_SIZE (4096 * 1024) +#define VGA_RAM_SIZE (8192 * 1024) struct DisplayState { uint8_t *data; -- cgit v1.2.3 From 99589bdcd16f20ac5fc45a518fb4633eb90abbfe Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 Jun 2006 16:35:24 +0000 Subject: support for higher resolutions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1956 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/vnc.c b/vnc.c index 812f87a97..1bea9661d 100644 --- a/vnc.c +++ b/vnc.c @@ -50,6 +50,10 @@ typedef void VncSendHextileTile(VncState *vs, uint32_t *last_fg, int *has_bg, int *has_fg); +#define VNC_MAX_WIDTH 2048 +#define VNC_MAX_HEIGHT 2048 +#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) + struct VncState { QEMUTimer *timer; @@ -59,7 +63,7 @@ struct VncState int need_update; int width; int height; - uint64_t dirty_row[768]; + uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS]; char *old_data; int depth; /* internal VNC frame buffer byte per pixel */ int has_resize; @@ -95,6 +99,47 @@ static void vnc_flush(VncState *vs); static void vnc_update_client(void *opaque); static void vnc_client_read(void *opaque); +static inline void vnc_set_bit(uint32_t *d, int k) +{ + d[k >> 5] |= 1 << (k & 0x1f); +} + +static inline void vnc_clear_bit(uint32_t *d, int k) +{ + d[k >> 5] &= ~(1 << (k & 0x1f)); +} + +static inline void vnc_set_bits(uint32_t *d, int n, int nb_words) +{ + int j; + + j = 0; + while (n >= 32) { + d[j++] = -1; + n -= 32; + } + if (n > 0) + d[j++] = (1 << n) - 1; + while (j < nb_words) + d[j++] = 0; +} + +static inline int vnc_get_bit(const uint32_t *d, int k) +{ + return (d[k >> 5] >> (k & 0x1f)) & 1; +} + +static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2, + int nb_words) +{ + int i; + for(i = 0; i < nb_words; i++) { + if ((d1[i] & d2[i]) != 0) + return 1; + } + return 0; +} + static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) { VncState *vs = ds->opaque; @@ -104,7 +149,7 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) for (; y < h; y++) for (i = 0; i < w; i += 16) - vs->dirty_row[y] |= (1ULL << ((x + i) / 16)); + vnc_set_bit(vs->dirty_row[y], (x + i) / 16); } static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, @@ -316,10 +361,10 @@ static int find_dirty_height(VncState *vs, int y, int last_x, int x) for (h = 1; h < (vs->height - y); h++) { int tmp_x; - if (!(vs->dirty_row[y + h] & (1ULL << last_x))) + if (!vnc_get_bit(vs->dirty_row[y + h], last_x)) break; for (tmp_x = last_x; tmp_x < x; tmp_x++) - vs->dirty_row[y + h] &= ~(1ULL << tmp_x); + vnc_clear_bit(vs->dirty_row[y + h], tmp_x); } return h; @@ -333,15 +378,12 @@ static void vnc_update_client(void *opaque) int y; char *row; char *old_row; - uint64_t width_mask; + uint32_t width_mask[VNC_DIRTY_WORDS]; int n_rectangles; int saved_offset; int has_dirty = 0; - width_mask = (1ULL << (vs->width / 16)) - 1; - - if (vs->width == 1024) - width_mask = ~(0ULL); + vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS); /* Walk through the dirty map and eliminate tiles that really aren't dirty */ @@ -349,7 +391,7 @@ static void vnc_update_client(void *opaque) old_row = vs->old_data; for (y = 0; y < vs->height; y++) { - if (vs->dirty_row[y] & width_mask) { + if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) { int x; char *ptr, *old_ptr; @@ -358,7 +400,7 @@ static void vnc_update_client(void *opaque) for (x = 0; x < vs->ds->width; x += 16) { if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) { - vs->dirty_row[y] &= ~(1ULL << (x / 16)); + vnc_clear_bit(vs->dirty_row[y], (x / 16)); } else { has_dirty = 1; memcpy(old_ptr, ptr, 16 * vs->depth); @@ -389,11 +431,11 @@ static void vnc_update_client(void *opaque) int x; int last_x = -1; for (x = 0; x < vs->width / 16; x++) { - if (vs->dirty_row[y] & (1ULL << x)) { + if (vnc_get_bit(vs->dirty_row[y], x)) { if (last_x == -1) { last_x = x; } - vs->dirty_row[y] &= ~(1ULL << x); + vnc_clear_bit(vs->dirty_row[y], x); } else { if (last_x != -1) { int h = find_dirty_height(vs, y, last_x, x); @@ -688,10 +730,8 @@ static void framebuffer_update_request(VncState *vs, int incremental, char *old_row = vs->old_data + y_position * vs->ds->linesize; for (i = 0; i < h; i++) { - vs->dirty_row[y_position + i] = (1ULL << (vs->ds->width / 16)) - 1; - if (vs->ds->width == 1024) { - vs->dirty_row[y_position + i] = ~(0ULL); - } + vnc_set_bits(vs->dirty_row[y_position + i], + (vs->ds->width / 16), VNC_DIRTY_WORDS); memset(old_row, 42, vs->ds->width * vs->depth); old_row += vs->ds->linesize; } -- cgit v1.2.3 From 8454df8b1e7662bdbe423e6494200a5aa9d619ae Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 Jun 2006 16:37:40 +0000 Subject: support for Bochs VBE GETCAPS call so that -std-vga works again with new VGA BIOSes - added support for modes up to 1600x1200x32 in -std-vga case git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1957 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 50 +++++++++++++++++++++++++++++++++++++++----------- hw/vga_int.h | 9 ++++++--- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index b4eacc35b..8f748b371 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -378,10 +378,29 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) VGAState *s = opaque; uint32_t val; - if (s->vbe_index <= VBE_DISPI_INDEX_NB) - val = s->vbe_regs[s->vbe_index]; - else + if (s->vbe_index <= VBE_DISPI_INDEX_NB) { + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) { + switch(s->vbe_index) { + /* XXX: do not hardcode ? */ + case VBE_DISPI_INDEX_XRES: + val = VBE_DISPI_MAX_XRES; + break; + case VBE_DISPI_INDEX_YRES: + val = VBE_DISPI_MAX_YRES; + break; + case VBE_DISPI_INDEX_BPP: + val = VBE_DISPI_MAX_BPP; + break; + default: + val = s->vbe_regs[s->vbe_index]; + break; + } + } else { + val = s->vbe_regs[s->vbe_index]; + } + } else { val = 0; + } #ifdef DEBUG_BOCHS_VBE printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); #endif @@ -434,7 +453,8 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->bank_offset = (val << 16); break; case VBE_DISPI_INDEX_ENABLE: - if (val & VBE_DISPI_ENABLED) { + if ((val & VBE_DISPI_ENABLED) && + !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { int h, shift_control; s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = @@ -450,7 +470,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); s->vbe_start_addr = 0; - + /* clear the screen (should be done in BIOS) */ if (!(val & VBE_DISPI_NOCLEARMEM)) { memset(s->vram_ptr, 0, @@ -464,7 +484,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->cr[0x13] = s->vbe_line_offset >> 3; /* width */ s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; - /* height */ + /* height (only meaningful if < 1024) */ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; s->cr[0x12] = h; s->cr[0x07] = (s->cr[0x07] & ~0x42) | @@ -1310,11 +1330,19 @@ static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight) { int width, height; - width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); - height = (height + 1); +#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; + height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; + } else +#endif + { + width = (s->cr[0x01] + 1) * 8; + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | + ((s->cr[0x07] & 0x40) << 3); + height = (height + 1); + } *pwidth = width; *pheight = height; } diff --git a/hw/vga_int.h b/hw/vga_int.h index 621268de4..b33ab575d 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -30,8 +30,9 @@ /* bochs VBE support */ #define CONFIG_BOCHS_VBE -#define VBE_DISPI_MAX_XRES 1024 -#define VBE_DISPI_MAX_YRES 768 +#define VBE_DISPI_MAX_XRES 1600 +#define VBE_DISPI_MAX_YRES 1200 +#define VBE_DISPI_MAX_BPP 32 #define VBE_DISPI_INDEX_ID 0x0 #define VBE_DISPI_INDEX_XRES 0x1 @@ -51,6 +52,8 @@ #define VBE_DISPI_DISABLED 0x00 #define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 #define VBE_DISPI_LFB_ENABLED 0x40 #define VBE_DISPI_NOCLEARMEM 0x80 @@ -72,7 +75,7 @@ #endif /* !CONFIG_BOCHS_VBE */ #define CH_ATTR_SIZE (160 * 100) -#define VGA_MAX_HEIGHT 1024 +#define VGA_MAX_HEIGHT 2048 #define VGA_STATE_COMMON \ uint8_t *vram_ptr; \ -- cgit v1.2.3 From 8fa00e0fec0e57cd2d08cee27391925b9ea9eb93 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 13 Jun 2006 16:54:27 +0000 Subject: more high resolution VESA modes in -std-vga case - changed video memory size to 8 MB git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1958 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/vgabios.bin | Bin 32768 -> 34304 bytes pc-bios/vgabios.diff | 2406 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 2405 insertions(+), 1 deletion(-) diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index 10b2ad8e3..9b815bc78 100644 Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ diff --git a/pc-bios/vgabios.diff b/pc-bios/vgabios.diff index c2594b845..93e23d3a4 100644 --- a/pc-bios/vgabios.diff +++ b/pc-bios/vgabios.diff @@ -4,7 +4,7 @@ RCS file: /sources/vgabios/vgabios/clext.c,v retrieving revision 1.10 diff -u -w -r1.10 clext.c --- clext.c 25 Mar 2006 10:19:15 -0000 1.10 -+++ clext.c 14 May 2006 20:49:29 -0000 ++++ clext.c 13 Jun 2006 16:47:23 -0000 @@ -544,6 +544,13 @@ cirrus_set_video_mode_extended: call cirrus_switch_mode @@ -72,3 +72,2407 @@ diff -u -w -r1.10 clext.c cirrus_extbios_handlers: ;; 80h dw cirrus_extbios_80h +Index: vbe.h +=================================================================== +RCS file: /sources/vgabios/vgabios/vbe.h,v +retrieving revision 1.24 +diff -u -w -r1.24 vbe.h +--- vbe.h 9 May 2004 20:31:31 -0000 1.24 ++++ vbe.h 13 Jun 2006 16:47:24 -0000 +@@ -193,6 +193,10 @@ + #define VBE_VESA_MODE_1280X1024X1555 0x119 + #define VBE_VESA_MODE_1280X1024X565 0x11A + #define VBE_VESA_MODE_1280X1024X888 0x11B ++#define VBE_VESA_MODE_1600X1200X8 0x11C ++#define VBE_VESA_MODE_1600X1200X1555 0x11D ++#define VBE_VESA_MODE_1600X1200X565 0x11E ++#define VBE_VESA_MODE_1600X1200X888 0x11F + + // BOCHS/PLEX86 'own' mode numbers + #define VBE_OWN_MODE_320X200X8888 0x140 +@@ -202,6 +206,12 @@ + #define VBE_OWN_MODE_1024X768X8888 0x144 + #define VBE_OWN_MODE_1280X1024X8888 0x145 + #define VBE_OWN_MODE_320X200X8 0x146 ++#define VBE_OWN_MODE_1600X1200X8888 0x147 ++#define VBE_OWN_MODE_1152X864X8 0x148 ++#define VBE_OWN_MODE_1152X864X1555 0x149 ++#define VBE_OWN_MODE_1152X864X565 0x14a ++#define VBE_OWN_MODE_1152X864X888 0x14b ++#define VBE_OWN_MODE_1152X864X8888 0x14c + + #define VBE_VESA_MODE_END_OF_LIST 0xFFFF + +@@ -259,7 +269,7 @@ + // like 0xE0000000 + + +- #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4 ++ #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 8 + + #define VBE_DISPI_BANK_ADDRESS 0xA0000 + #define VBE_DISPI_BANK_SIZE_KB 64 +Index: vbetables.h +=================================================================== +RCS file: /sources/vgabios/vgabios/vbetables.h,v +retrieving revision 1.24 +diff -u -w -r1.24 vbetables.h +--- vbetables.h 22 Jul 2004 18:37:29 -0000 1.24 ++++ vbetables.h 13 Jun 2006 16:47:24 -0000 +@@ -14,46 +14,29 @@ + ModeInfoBlockCompact info; + } ModeInfoListItem; + +-// FIXME: check all member variables to be correct for the different modi +-// FIXME: add more modi + static ModeInfoListItem mode_info_list[]= + { +- { +- VBE_VESA_MODE_640X400X8, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++{ 0x0100, /* 640x400x8 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 640, +-// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 400, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, +- /*Bit8u NumberOfBanks*/ 4, // 640x400/64kb == 4 ++/*Bit8u NumberOfBanks*/ 4, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 15, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, +@@ -63,15 +46,9 @@ + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 640, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +@@ -84,45 +61,28 @@ + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_640X480X8, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0101, /* 640x480x8 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 640, +-// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, +- /*Bit8u NumberOfBanks*/ 5, // 640x480/64kb == 5 ++/*Bit8u NumberOfBanks*/ 5, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 11, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, +@@ -132,15 +92,9 @@ + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 640, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +@@ -153,44 +107,28 @@ + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_800X600X4, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0102, /* 800x600x4 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 100, +-// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 4, + /*Bit8u BitsPerPixel*/ 4, +- /*Bit8u NumberOfBanks*/ 16, ++/*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PLANAR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 15, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, +@@ -200,11 +138,9 @@ + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +- /*Bit32u PhysBasePtr*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 100, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +@@ -217,46 +153,28 @@ + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_800X600X8, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0103, /* 800x600x8 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 800, +-// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, +- /*Bit8u NumberOfBanks*/ 8, // 800x600/64kb == 8 ++/*Bit8u NumberOfBanks*/ 8, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 7, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, +@@ -266,15 +184,9 @@ + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 800, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +@@ -287,46 +199,28 @@ + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_1024X768X8, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0105, /* 1024x768x8 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 1024, +-// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 1024, + /*Bit16u YResolution*/ 768, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 8, +- /*Bit8u NumberOfBanks*/ 12, // 1024x768/64kb == 12 ++/*Bit8u NumberOfBanks*/ 12, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 3, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, +@@ -336,15 +230,9 @@ + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 1024, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +@@ -357,116 +245,74 @@ + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_640X480X1555, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0107, /* 1280x1024x8 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 640*2, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 640, +- /*Bit16u YResolution*/ 480, ++/*Bit16u BytesPerScanLine*/ 1280, ++/*Bit16u XResolution*/ 1280, ++/*Bit16u YResolution*/ 1024, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, +- /*Bit8u BitsPerPixel*/ 15, +- /*Bit8u NumberOfBanks*/ 1, +- /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BitsPerPixel*/ 8, ++/*Bit8u NumberOfBanks*/ 20, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 5, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) +- /*Bit8u RedMaskSize*/ 5, +- /*Bit8u RedFieldPosition*/ 10, +- /*Bit8u GreenMaskSize*/ 5, +- /*Bit8u GreenFieldPosition*/ 5, +- /*Bit8u BlueMaskSize*/ 5, ++/*Bit8u RedMaskSize*/ 0, ++/*Bit8u RedFieldPosition*/ 0, ++/*Bit8u GreenMaskSize*/ 0, ++/*Bit8u GreenFieldPosition*/ 0, ++/*Bit8u BlueMaskSize*/ 0, + /*Bit8u BlueFieldPosition*/ 0, +- /*Bit8u RsvdMaskSize*/ 1, +- /*Bit8u RsvdFieldPosition*/ 15, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 640*2, ++/*Bit16u LinBytesPerScanLine*/ 1280, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +- /*Bit8u LinRedMaskSize*/ 5, +- /*Bit8u LinRedFieldPosition*/ 10, ++/*Bit8u LinRedMaskSize*/ 0, ++/*Bit8u LinRedFieldPosition*/ 0, + /*Bit8u LinGreenMaskSize*/ 0, +- /*Bit8u LinGreenFieldPosition*/ 5, +- /*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinGreenFieldPosition*/ 0, ++/*Bit8u LinBlueMaskSize*/ 0, + /*Bit8u LinBlueFieldPosition*/ 0, +- /*Bit8u LinRsvdMaskSize*/ 1, +- /*Bit8u LinRsvdFieldPosition*/ 15, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_800X600X1555, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x010d, /* 320x200x15 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 800*2, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 800, +- /*Bit16u YResolution*/ 600, ++/*Bit16u BytesPerScanLine*/ 640, ++/*Bit16u XResolution*/ 320, ++/*Bit16u YResolution*/ 200, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 15, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u NumberOfBanks*/ 2, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 3, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, + /*Bit8u RedFieldPosition*/ 10, + /*Bit8u GreenMaskSize*/ 5, +@@ -476,16 +322,10 @@ + /*Bit8u RsvdMaskSize*/ 1, + /*Bit8u RsvdFieldPosition*/ 15, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 800*2, ++/*Bit16u LinBytesPerScanLine*/ 640, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, +@@ -497,256 +337,166 @@ + /*Bit8u LinRsvdMaskSize*/ 1, + /*Bit8u LinRsvdFieldPosition*/ 15, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_1024X768X1555, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x010e, /* 320x200x16 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 1024*2, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 1024, +- /*Bit16u YResolution*/ 768, ++/*Bit16u BytesPerScanLine*/ 640, ++/*Bit16u XResolution*/ 320, ++/*Bit16u YResolution*/ 200, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, +- /*Bit8u BitsPerPixel*/ 15, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u BitsPerPixel*/ 16, ++/*Bit8u NumberOfBanks*/ 2, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 1, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, +- /*Bit8u RedFieldPosition*/ 10, +- /*Bit8u GreenMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 11, ++/*Bit8u GreenMaskSize*/ 6, + /*Bit8u GreenFieldPosition*/ 5, + /*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, +- /*Bit8u RsvdMaskSize*/ 1, +- /*Bit8u RsvdFieldPosition*/ 15, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 1024*2, ++/*Bit16u LinBytesPerScanLine*/ 640, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, +- /*Bit8u LinRedFieldPosition*/ 10, +- /*Bit8u LinGreenMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 11, ++/*Bit8u LinGreenMaskSize*/ 6, + /*Bit8u LinGreenFieldPosition*/ 5, + /*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, +- /*Bit8u LinRsvdMaskSize*/ 1, +- /*Bit8u LinRsvdFieldPosition*/ 15, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_640X480X565, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x010f, /* 320x200x24 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 640*2, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 640, +- /*Bit16u YResolution*/ 480, ++/*Bit16u BytesPerScanLine*/ 960, ++/*Bit16u XResolution*/ 320, ++/*Bit16u YResolution*/ 200, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, +- /*Bit8u BitsPerPixel*/ 16, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u BitsPerPixel*/ 24, ++/*Bit8u NumberOfBanks*/ 3, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 5, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) +- /*Bit8u RedMaskSize*/ 5, +- /*Bit8u RedFieldPosition*/ 11, +- /*Bit8u GreenMaskSize*/ 6, +- /*Bit8u GreenFieldPosition*/ 5, +- /*Bit8u BlueMaskSize*/ 5, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 640*2, ++/*Bit16u LinBytesPerScanLine*/ 960, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +- /*Bit8u LinRedMaskSize*/ 5, +- /*Bit8u LinRedFieldPosition*/ 11, +- /*Bit8u LinGreenMaskSize*/ 6, +- /*Bit8u LinGreenFieldPosition*/ 5, +- /*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_800X600X565, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0110, /* 640x480x15 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 800*2, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 800, +- /*Bit16u YResolution*/ 600, ++/*Bit16u BytesPerScanLine*/ 1280, ++/*Bit16u XResolution*/ 640, ++/*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, +- /*Bit8u BitsPerPixel*/ 16, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u BitsPerPixel*/ 15, ++/*Bit8u NumberOfBanks*/ 10, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 3, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, +- /*Bit8u RedFieldPosition*/ 11, +- /*Bit8u GreenMaskSize*/ 6, ++/*Bit8u RedFieldPosition*/ 10, ++/*Bit8u GreenMaskSize*/ 5, + /*Bit8u GreenFieldPosition*/ 5, + /*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, +- /*Bit8u RsvdMaskSize*/ 0, +- /*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 1, ++/*Bit8u RsvdFieldPosition*/ 15, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 800*2, ++/*Bit16u LinBytesPerScanLine*/ 1280, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, +- /*Bit8u LinRedFieldPosition*/ 11, +- /*Bit8u LinGreenMaskSize*/ 6, ++/*Bit8u LinRedFieldPosition*/ 10, ++/*Bit8u LinGreenMaskSize*/ 5, + /*Bit8u LinGreenFieldPosition*/ 5, + /*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, +- /*Bit8u LinRsvdMaskSize*/ 0, +- /*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 1, ++/*Bit8u LinRsvdFieldPosition*/ 15, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_1024X768X565, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0111, /* 640x480x16 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 1024*2, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 1024, +- /*Bit16u YResolution*/ 768, ++/*Bit16u BytesPerScanLine*/ 1280, ++/*Bit16u XResolution*/ 640, ++/*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 16, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u NumberOfBanks*/ 10, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 1, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 5, + /*Bit8u RedFieldPosition*/ 11, + /*Bit8u GreenMaskSize*/ 6, +@@ -756,16 +506,10 @@ + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 1024*2, ++/*Bit16u LinBytesPerScanLine*/ 1280, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 5, +@@ -777,46 +521,28 @@ + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_640X480X888, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0112, /* 640x480x24 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 640*3, +-// Mandatory information for VBE 1.2 and above ++/*Bit16u BytesPerScanLine*/ 1920, + /*Bit16u XResolution*/ 640, + /*Bit16u YResolution*/ 480, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 24, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u NumberOfBanks*/ 15, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 3, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, +@@ -826,16 +552,10 @@ + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 640*3, ++/*Bit16u LinBytesPerScanLine*/ 1920, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, +@@ -847,186 +567,764 @@ + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_800X600X888, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0113, /* 800x600x15 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 800*3, +-// Mandatory information for VBE 1.2 and above ++/*Bit16u BytesPerScanLine*/ 1600, + /*Bit16u XResolution*/ 800, + /*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, +- /*Bit8u BitsPerPixel*/ 24, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u BitsPerPixel*/ 15, ++/*Bit8u NumberOfBanks*/ 15, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 1, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) +- /*Bit8u RedMaskSize*/ 8, +- /*Bit8u RedFieldPosition*/ 16, +- /*Bit8u GreenMaskSize*/ 8, +- /*Bit8u GreenFieldPosition*/ 8, +- /*Bit8u BlueMaskSize*/ 8, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 10, ++/*Bit8u GreenMaskSize*/ 5, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, +- /*Bit8u RsvdMaskSize*/ 0, +- /*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 1, ++/*Bit8u RsvdFieldPosition*/ 15, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 800*3, ++/*Bit16u LinBytesPerScanLine*/ 1600, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +- /*Bit8u LinRedMaskSize*/ 8, +- /*Bit8u LinRedFieldPosition*/ 16, +- /*Bit8u LinGreenMaskSize*/ 8, +- /*Bit8u LinGreenFieldPosition*/ 8, +- /*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 10, ++/*Bit8u LinGreenMaskSize*/ 5, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, + /*Bit8u LinBlueFieldPosition*/ 0, +- /*Bit8u LinRsvdMaskSize*/ 0, +- /*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 1, ++/*Bit8u LinRsvdFieldPosition*/ 15, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_VESA_MODE_1024X768X888, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0114, /* 800x600x16 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 1024*3, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 1024, +- /*Bit16u YResolution*/ 768, ++/*Bit16u BytesPerScanLine*/ 1600, ++/*Bit16u XResolution*/ 800, ++/*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, +- /*Bit8u BitsPerPixel*/ 24, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u BitsPerPixel*/ 16, ++/*Bit8u NumberOfBanks*/ 15, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, + /*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) +- /*Bit8u RedMaskSize*/ 8, +- /*Bit8u RedFieldPosition*/ 16, +- /*Bit8u GreenMaskSize*/ 8, +- /*Bit8u GreenFieldPosition*/ 8, +- /*Bit8u BlueMaskSize*/ 8, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 11, ++/*Bit8u GreenMaskSize*/ 6, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 1024*3, ++/*Bit16u LinBytesPerScanLine*/ 1600, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +- /*Bit8u LinRedMaskSize*/ 8, +- /*Bit8u LinRedFieldPosition*/ 16, +- /*Bit8u LinGreenMaskSize*/ 8, +- /*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 11, ++/*Bit8u LinGreenMaskSize*/ 6, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0115, /* 800x600x24 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2400, ++/*Bit16u XResolution*/ 800, ++/*Bit16u YResolution*/ 600, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 24, ++/*Bit8u NumberOfBanks*/ 22, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2400, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0116, /* 1024x768x15 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2048, ++/*Bit16u XResolution*/ 1024, ++/*Bit16u YResolution*/ 768, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 15, ++/*Bit8u NumberOfBanks*/ 24, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 10, ++/*Bit8u GreenMaskSize*/ 5, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 1, ++/*Bit8u RsvdFieldPosition*/ 15, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2048, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 10, ++/*Bit8u LinGreenMaskSize*/ 5, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 1, ++/*Bit8u LinRsvdFieldPosition*/ 15, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0117, /* 1024x768x16 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2048, ++/*Bit16u XResolution*/ 1024, ++/*Bit16u YResolution*/ 768, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 16, ++/*Bit8u NumberOfBanks*/ 24, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 11, ++/*Bit8u GreenMaskSize*/ 6, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2048, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 11, ++/*Bit8u LinGreenMaskSize*/ 6, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0118, /* 1024x768x24 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 3072, ++/*Bit16u XResolution*/ 1024, ++/*Bit16u YResolution*/ 768, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 24, ++/*Bit8u NumberOfBanks*/ 36, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 3072, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0119, /* 1280x1024x15 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2560, ++/*Bit16u XResolution*/ 1280, ++/*Bit16u YResolution*/ 1024, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 15, ++/*Bit8u NumberOfBanks*/ 40, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 10, ++/*Bit8u GreenMaskSize*/ 5, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 1, ++/*Bit8u RsvdFieldPosition*/ 15, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2560, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 10, ++/*Bit8u LinGreenMaskSize*/ 5, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 1, ++/*Bit8u LinRsvdFieldPosition*/ 15, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x011a, /* 1280x1024x16 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2560, ++/*Bit16u XResolution*/ 1280, ++/*Bit16u YResolution*/ 1024, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 16, ++/*Bit8u NumberOfBanks*/ 40, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 11, ++/*Bit8u GreenMaskSize*/ 6, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2560, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 11, ++/*Bit8u LinGreenMaskSize*/ 6, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x011b, /* 1280x1024x24 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 3840, ++/*Bit16u XResolution*/ 1280, ++/*Bit16u YResolution*/ 1024, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 24, ++/*Bit8u NumberOfBanks*/ 60, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 3840, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x011c, /* 1600x1200x8 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 1600, ++/*Bit16u XResolution*/ 1600, ++/*Bit16u YResolution*/ 1200, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 8, ++/*Bit8u NumberOfBanks*/ 30, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 0, ++/*Bit8u RedFieldPosition*/ 0, ++/*Bit8u GreenMaskSize*/ 0, ++/*Bit8u GreenFieldPosition*/ 0, ++/*Bit8u BlueMaskSize*/ 0, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 1600, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 0, ++/*Bit8u LinRedFieldPosition*/ 0, ++/*Bit8u LinGreenMaskSize*/ 0, ++/*Bit8u LinGreenFieldPosition*/ 0, ++/*Bit8u LinBlueMaskSize*/ 0, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x011d, /* 1600x1200x15 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 3200, ++/*Bit16u XResolution*/ 1600, ++/*Bit16u YResolution*/ 1200, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 15, ++/*Bit8u NumberOfBanks*/ 59, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 10, ++/*Bit8u GreenMaskSize*/ 5, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 1, ++/*Bit8u RsvdFieldPosition*/ 15, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 3200, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 10, ++/*Bit8u LinGreenMaskSize*/ 5, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 1, ++/*Bit8u LinRsvdFieldPosition*/ 15, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x011e, /* 1600x1200x16 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 3200, ++/*Bit16u XResolution*/ 1600, ++/*Bit16u YResolution*/ 1200, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 16, ++/*Bit8u NumberOfBanks*/ 59, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 11, ++/*Bit8u GreenMaskSize*/ 6, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 3200, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 11, ++/*Bit8u LinGreenMaskSize*/ 6, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x011f, /* 1600x1200x24 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 4800, ++/*Bit16u XResolution*/ 1600, ++/*Bit16u YResolution*/ 1200, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 24, ++/*Bit8u NumberOfBanks*/ 88, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 4800, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, + /*Bit8u LinBlueMaskSize*/ 8, + /*Bit8u LinBlueFieldPosition*/ 0, + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_OWN_MODE_640X480X8888, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0140, /* 320x200x32 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 1280, ++/*Bit16u XResolution*/ 320, ++/*Bit16u YResolution*/ 200, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 32, ++/*Bit8u NumberOfBanks*/ 4, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 8, ++/*Bit8u RsvdFieldPosition*/ 24, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 1280, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 8, ++/*Bit8u LinRsvdFieldPosition*/ 24, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0141, /* 640x400x32 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2560, ++/*Bit16u XResolution*/ 640, ++/*Bit16u YResolution*/ 400, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 32, ++/*Bit8u NumberOfBanks*/ 16, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 8, ++/*Bit8u RsvdFieldPosition*/ 24, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2560, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 8, ++/*Bit8u LinRsvdFieldPosition*/ 24, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0142, /* 640x480x32 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2560, ++/*Bit16u XResolution*/ 640, ++/*Bit16u YResolution*/ 480, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 32, ++/*Bit8u NumberOfBanks*/ 19, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 8, ++/*Bit8u RsvdFieldPosition*/ 24, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2560, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 8, ++/*Bit8u LinRsvdFieldPosition*/ 24, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0143, /* 800x600x32 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 640*4, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 640, +- /*Bit16u YResolution*/ 480, ++/*Bit16u BytesPerScanLine*/ 3200, ++/*Bit16u XResolution*/ 800, ++/*Bit16u YResolution*/ 600, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 32, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u NumberOfBanks*/ 30, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 1, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, +@@ -1035,17 +1333,11 @@ + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 8, + /*Bit8u RsvdFieldPosition*/ 24, +- /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB ++/*Bit8u DirectColorModeInfo*/ 0, + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 640*4, ++/*Bit16u LinBytesPerScanLine*/ 3200, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, +@@ -1057,46 +1349,28 @@ + /*Bit8u LinRsvdMaskSize*/ 8, + /*Bit8u LinRsvdFieldPosition*/ 24, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_OWN_MODE_800X600X8888, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0144, /* 1024x768x32 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 800*4, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 800, +- /*Bit16u YResolution*/ 600, ++/*Bit16u BytesPerScanLine*/ 4096, ++/*Bit16u XResolution*/ 1024, ++/*Bit16u YResolution*/ 768, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 32, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u NumberOfBanks*/ 48, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 1, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, +@@ -1105,17 +1379,11 @@ + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 8, + /*Bit8u RsvdFieldPosition*/ 24, +- /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB ++/*Bit8u DirectColorModeInfo*/ 0, + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 800*4, ++/*Bit16u LinBytesPerScanLine*/ 4096, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, +@@ -1127,46 +1395,28 @@ + /*Bit8u LinRsvdMaskSize*/ 8, + /*Bit8u LinRsvdFieldPosition*/ 24, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_OWN_MODE_1024X768X8888, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | +- VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0145, /* 1280x1024x32 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, +- /*Bit16u BytesPerScanLine*/ 1024*4, +-// Mandatory information for VBE 1.2 and above +- /*Bit16u XResolution*/ 1024, +- /*Bit16u YResolution*/ 768, ++/*Bit16u BytesPerScanLine*/ 5120, ++/*Bit16u XResolution*/ 1280, ++/*Bit16u YResolution*/ 1024, + /*Bit8u XCharSize*/ 8, + /*Bit8u YCharSize*/ 16, + /*Bit8u NumberOfPlanes*/ 1, + /*Bit8u BitsPerPixel*/ 32, +- /*Bit8u NumberOfBanks*/ 1, ++/*Bit8u NumberOfBanks*/ 80, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 1, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 8, + /*Bit8u RedFieldPosition*/ 16, + /*Bit8u GreenMaskSize*/ 8, +@@ -1175,17 +1425,11 @@ + /*Bit8u BlueFieldPosition*/ 0, + /*Bit8u RsvdMaskSize*/ 8, + /*Bit8u RsvdFieldPosition*/ 24, +- /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB ++/*Bit8u DirectColorModeInfo*/ 0, + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above +- /*Bit16u LinBytesPerScanLine*/ 1024*4, ++/*Bit16u LinBytesPerScanLine*/ 5120, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, + /*Bit8u LinRedMaskSize*/ 8, +@@ -1197,33 +1441,17 @@ + /*Bit8u LinRsvdMaskSize*/ 8, + /*Bit8u LinRsvdFieldPosition*/ 24, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +- { +- VBE_OWN_MODE_320X200X8, +- { +-/*typedef struct ModeInfoBlock +-{*/ +-// Mandatory information for all VBE revisions +- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | +- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | +- VBE_MODE_ATTRIBUTE_COLOR_MODE | +-#ifdef VBE_HAVE_LFB +- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#endif +- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, +- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_READABLE | +- VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++} }, ++{ 0x0146, /* 320x200x8 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, + /*Bit8u WinBAttributes*/ 0, + /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, + /*Bit16u WinASegment*/ VGAMEM_GRAPH, +- /*Bit16u WinBSegment*/ 0, ++/*Bit16u WinBSegment*/ 0x0000, + /*Bit32u WinFuncPtr*/ 0, + /*Bit16u BytesPerScanLine*/ 320, +-// Mandatory information for VBE 1.2 and above + /*Bit16u XResolution*/ 320, + /*Bit16u YResolution*/ 200, + /*Bit8u XCharSize*/ 8, +@@ -1233,9 +1461,8 @@ + /*Bit8u NumberOfBanks*/ 1, + /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, + /*Bit8u BankSize*/ 0, +- /*Bit8u NumberOfImagePages*/ 3, ++/*Bit8u NumberOfImagePages*/ 0, + /*Bit8u Reserved_page*/ 0, +-// Direct Color fields (required for direct/6 and YUV/7 memory models) + /*Bit8u RedMaskSize*/ 0, + /*Bit8u RedFieldPosition*/ 0, + /*Bit8u GreenMaskSize*/ 0, +@@ -1245,15 +1472,9 @@ + /*Bit8u RsvdMaskSize*/ 0, + /*Bit8u RsvdFieldPosition*/ 0, + /*Bit8u DirectColorModeInfo*/ 0, +-// Mandatory information for VBE 2.0 and above +-#ifdef VBE_HAVE_LFB + /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, +-#else +- /*Bit32u PhysBasePtr*/ 0, +-#endif + /*Bit32u OffScreenMemOffset*/ 0, + /*Bit16u OffScreenMemSize*/ 0, +-// Mandatory information for VBE 3.0 and above + /*Bit16u LinBytesPerScanLine*/ 320, + /*Bit8u BnkNumberOfPages*/ 0, + /*Bit8u LinNumberOfPages*/ 0, +@@ -1266,17 +1487,286 @@ + /*Bit8u LinRsvdMaskSize*/ 0, + /*Bit8u LinRsvdFieldPosition*/ 0, + /*Bit32u MaxPixelClock*/ 0, +-/*} ModeInfoBlock;*/ +- } +- }, +- +-/** END OF THE LIST **/ +- { +- VBE_VESA_MODE_END_OF_LIST, +- { +- 0, +- } +- } ++} }, ++{ 0x0147, /* 1600x1200x32 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 6400, ++/*Bit16u XResolution*/ 1600, ++/*Bit16u YResolution*/ 1200, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 32, ++/*Bit8u NumberOfBanks*/ 118, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 8, ++/*Bit8u RsvdFieldPosition*/ 24, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 6400, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 8, ++/*Bit8u LinRsvdFieldPosition*/ 24, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0148, /* 1152x864x8 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 1152, ++/*Bit16u XResolution*/ 1152, ++/*Bit16u YResolution*/ 864, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 8, ++/*Bit8u NumberOfBanks*/ 16, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 0, ++/*Bit8u RedFieldPosition*/ 0, ++/*Bit8u GreenMaskSize*/ 0, ++/*Bit8u GreenFieldPosition*/ 0, ++/*Bit8u BlueMaskSize*/ 0, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 1152, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 0, ++/*Bit8u LinRedFieldPosition*/ 0, ++/*Bit8u LinGreenMaskSize*/ 0, ++/*Bit8u LinGreenFieldPosition*/ 0, ++/*Bit8u LinBlueMaskSize*/ 0, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x0149, /* 1152x864x15 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2304, ++/*Bit16u XResolution*/ 1152, ++/*Bit16u YResolution*/ 864, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 15, ++/*Bit8u NumberOfBanks*/ 31, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 10, ++/*Bit8u GreenMaskSize*/ 5, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 1, ++/*Bit8u RsvdFieldPosition*/ 15, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2304, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 10, ++/*Bit8u LinGreenMaskSize*/ 5, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 1, ++/*Bit8u LinRsvdFieldPosition*/ 15, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x014a, /* 1152x864x16 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 2304, ++/*Bit16u XResolution*/ 1152, ++/*Bit16u YResolution*/ 864, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 16, ++/*Bit8u NumberOfBanks*/ 31, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 5, ++/*Bit8u RedFieldPosition*/ 11, ++/*Bit8u GreenMaskSize*/ 6, ++/*Bit8u GreenFieldPosition*/ 5, ++/*Bit8u BlueMaskSize*/ 5, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 2304, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 5, ++/*Bit8u LinRedFieldPosition*/ 11, ++/*Bit8u LinGreenMaskSize*/ 6, ++/*Bit8u LinGreenFieldPosition*/ 5, ++/*Bit8u LinBlueMaskSize*/ 5, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x014b, /* 1152x864x24 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 3456, ++/*Bit16u XResolution*/ 1152, ++/*Bit16u YResolution*/ 864, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 24, ++/*Bit8u NumberOfBanks*/ 46, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 0, ++/*Bit8u RsvdFieldPosition*/ 0, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 3456, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 0, ++/*Bit8u LinRsvdFieldPosition*/ 0, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ 0x014c, /* 1152x864x32 */ ++{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, ++/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, ++/*Bit8u WinBAttributes*/ 0, ++/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, ++/*Bit16u WinASegment*/ VGAMEM_GRAPH, ++/*Bit16u WinBSegment*/ 0x0000, ++/*Bit32u WinFuncPtr*/ 0, ++/*Bit16u BytesPerScanLine*/ 4608, ++/*Bit16u XResolution*/ 1152, ++/*Bit16u YResolution*/ 864, ++/*Bit8u XCharSize*/ 8, ++/*Bit8u YCharSize*/ 16, ++/*Bit8u NumberOfPlanes*/ 1, ++/*Bit8u BitsPerPixel*/ 32, ++/*Bit8u NumberOfBanks*/ 61, ++/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, ++/*Bit8u BankSize*/ 0, ++/*Bit8u NumberOfImagePages*/ 0, ++/*Bit8u Reserved_page*/ 0, ++/*Bit8u RedMaskSize*/ 8, ++/*Bit8u RedFieldPosition*/ 16, ++/*Bit8u GreenMaskSize*/ 8, ++/*Bit8u GreenFieldPosition*/ 8, ++/*Bit8u BlueMaskSize*/ 8, ++/*Bit8u BlueFieldPosition*/ 0, ++/*Bit8u RsvdMaskSize*/ 8, ++/*Bit8u RsvdFieldPosition*/ 24, ++/*Bit8u DirectColorModeInfo*/ 0, ++/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, ++/*Bit32u OffScreenMemOffset*/ 0, ++/*Bit16u OffScreenMemSize*/ 0, ++/*Bit16u LinBytesPerScanLine*/ 4608, ++/*Bit8u BnkNumberOfPages*/ 0, ++/*Bit8u LinNumberOfPages*/ 0, ++/*Bit8u LinRedMaskSize*/ 8, ++/*Bit8u LinRedFieldPosition*/ 16, ++/*Bit8u LinGreenMaskSize*/ 8, ++/*Bit8u LinGreenFieldPosition*/ 8, ++/*Bit8u LinBlueMaskSize*/ 8, ++/*Bit8u LinBlueFieldPosition*/ 0, ++/*Bit8u LinRsvdMaskSize*/ 8, ++/*Bit8u LinRsvdFieldPosition*/ 24, ++/*Bit32u MaxPixelClock*/ 0, ++} }, ++{ VBE_VESA_MODE_END_OF_LIST, ++{ 0, ++} }, + }; + + #endif -- cgit v1.2.3 From 9d0869b630baf5b94c6cb6a87520dd881ae08613 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 00:58:54 +0000 Subject: fixed VBE protected mode calls - added VGA and VBE save restore support (not fully tested) - automatic generation of VBE mode table git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1959 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/vgabios-cirrus.bin | Bin 32768 -> 35328 bytes pc-bios/vgabios.bin | Bin 34304 -> 37888 bytes pc-bios/vgabios.diff | 3144 +++++++++++--------------------------------- 3 files changed, 781 insertions(+), 2363 deletions(-) diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index b9229f663..34f9a9ff7 100644 Binary files a/pc-bios/vgabios-cirrus.bin and b/pc-bios/vgabios-cirrus.bin differ diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin index 9b815bc78..17cb63f6a 100644 Binary files a/pc-bios/vgabios.bin and b/pc-bios/vgabios.bin differ diff --git a/pc-bios/vgabios.diff b/pc-bios/vgabios.diff index 93e23d3a4..661c032e4 100644 --- a/pc-bios/vgabios.diff +++ b/pc-bios/vgabios.diff @@ -1,10 +1,36 @@ +Index: Makefile +=================================================================== +RCS file: /sources/vgabios/vgabios/Makefile,v +retrieving revision 1.17 +diff -u -w -r1.17 Makefile +--- Makefile 6 Mar 2005 13:06:47 -0000 1.17 ++++ Makefile 14 Jun 2006 00:51:06 -0000 +@@ -22,7 +22,7 @@ + cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin + + clean: +- /bin/rm -f biossums *.o *.s *.ld86 \ ++ /bin/rm -f biossums vbetables-gen vbetables.h *.o *.s *.ld86 \ + temp.awk.* vgabios*.orig _vgabios_* _vgabios-debug_* core vgabios*.bin vgabios*.txt $(RELEASE).bin *.bak + + dist-clean: clean +@@ -79,3 +79,9 @@ + + biossums: biossums.c + $(CC) -o biossums biossums.c ++ ++vbetables-gen: vbetables-gen.c ++ $(CC) -o vbetables-gen vbetables-gen.c ++ ++vbetables.h: vbetables-gen ++ ./vbetables-gen > $@ Index: clext.c =================================================================== RCS file: /sources/vgabios/vgabios/clext.c,v retrieving revision 1.10 diff -u -w -r1.10 clext.c --- clext.c 25 Mar 2006 10:19:15 -0000 1.10 -+++ clext.c 13 Jun 2006 16:47:23 -0000 ++++ clext.c 14 Jun 2006 00:51:06 -0000 @@ -544,6 +544,13 @@ cirrus_set_video_mode_extended: call cirrus_switch_mode @@ -72,14 +98,289 @@ diff -u -w -r1.10 clext.c cirrus_extbios_handlers: ;; 80h dw cirrus_extbios_80h +Index: vbe.c +=================================================================== +RCS file: /sources/vgabios/vgabios/vbe.c,v +retrieving revision 1.48 +diff -u -w -r1.48 vbe.c +--- vbe.c 26 Dec 2005 19:50:26 -0000 1.48 ++++ vbe.c 14 Jun 2006 00:51:07 -0000 +@@ -118,21 +118,114 @@ + .word VBE_VESA_MODE_END_OF_LIST + #endif + ++ .align 2 + vesa_pm_start: + dw vesa_pm_set_window - vesa_pm_start +- dw vesa_pm_set_display_strt - vesa_pm_start ++ dw vesa_pm_set_display_start - vesa_pm_start + dw vesa_pm_unimplemented - vesa_pm_start +- dw 0 ++ dw vesa_pm_io_ports_table - vesa_pm_start ++vesa_pm_io_ports_table: ++ dw VBE_DISPI_IOPORT_INDEX ++ dw VBE_DISPI_IOPORT_INDEX + 1 ++ dw VBE_DISPI_IOPORT_DATA ++ dw VBE_DISPI_IOPORT_DATA + 1 ++ dw 0xffff ++ dw 0xffff + + USE32 + vesa_pm_set_window: +- mov ax, #0x4f05 +- int #0x10 ++ cmp bx, #0x00 ++ je vesa_pm_set_display_window1 ++ mov ax, #0x0100 ++ ret ++vesa_pm_set_display_window1: ++ mov ax, dx ++ push dx ++ push ax ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_BANK ++ out dx, ax ++ pop ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ out dx, ax ++ pop dx ++ mov ax, #0x004f + ret + + vesa_pm_set_display_start: +- mov ax, #0x4f07 +- int #0x10 ++ cmp bl, #0x80 ++ je vesa_pm_set_display_start1 ++ cmp bl, #0x00 ++ je vesa_pm_set_display_start1 ++ mov ax, #0x0100 ++ ret ++vesa_pm_set_display_start1: ++; convert offset to (X, Y) coordinate ++; (would be simpler to change Bochs VBE API...) ++ push eax ++ push ecx ++ push edx ++ push esi ++ push edi ++ shl edx, #16 ++ and ecx, #0xffff ++ or ecx, edx ++ shl ecx, #2 ++ mov eax, ecx ++ ++ push eax ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH ++ out dx, ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ in ax, dx ++ movzx ecx, ax ++ ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_BPP ++ out dx, ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ in ax, dx ++ movzx esi, ax ++ pop eax ++ ++ add esi, #7 ++ shr esi, #3 ++ imul ecx, esi ++ xor edx, edx ++ div ecx ++ mov edi, eax ++ mov eax, edx ++ xor edx, edx ++ div esi ++ ++ push dx ++ push ax ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_X_OFFSET ++ out dx, ax ++ pop ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ out dx, ax ++ pop dx ++ ++ mov ax, di ++ push dx ++ push ax ++ mov dx, # VBE_DISPI_IOPORT_INDEX ++ mov ax, # VBE_DISPI_INDEX_Y_OFFSET ++ out dx, ax ++ pop ax ++ mov dx, # VBE_DISPI_IOPORT_DATA ++ out dx, ax ++ pop dx ++ ++ pop edi ++ pop esi ++ pop edx ++ pop ecx ++ pop eax ++ mov ax, #0x004f + ret + + vesa_pm_unimplemented: +@@ -835,6 +928,64 @@ + ASM_END + + ++Bit16u vbe_biosfn_read_video_state_size() ++{ ++ return 9 * 2; ++} ++ ++void vbe_biosfn_save_video_state(ES, BX) ++ Bit16u ES; Bit16u BX; ++{ ++ Bit16u enable, i; ++ ++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); ++ enable = inw(VBE_DISPI_IOPORT_DATA); ++ write_word(ES, BX, enable); ++ BX += 2; ++ if (!(enable & VBE_DISPI_ENABLED)) ++ return; ++ for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) { ++ if (i != VBE_DISPI_INDEX_ENABLE) { ++ outw(VBE_DISPI_IOPORT_INDEX, i); ++ write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA)); ++ BX += 2; ++ } ++ } ++} ++ ++ ++void vbe_biosfn_restore_video_state(ES, BX) ++ Bit16u ES; Bit16u BX; ++{ ++ Bit16u enable, i; ++ ++ enable = read_word(ES, BX); ++ BX += 2; ++ ++ if (!(enable & VBE_DISPI_ENABLED)) { ++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); ++ outw(VBE_DISPI_IOPORT_DATA, enable); ++ } else { ++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES); ++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); ++ BX += 2; ++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES); ++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); ++ BX += 2; ++ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP); ++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); ++ BX += 2; ++ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); ++ outw(VBE_DISPI_IOPORT_DATA, enable); ++ ++ for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) { ++ outw(VBE_DISPI_IOPORT_INDEX, i); ++ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); ++ BX += 2; ++ } ++ } ++} ++ + /** Function 04h - Save/Restore State + * + * Input: +@@ -849,10 +1000,48 @@ + * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h) + * + */ +-void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX) ++void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX) ++Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX; + { +-} ++ Bit16u ss=get_SS(); ++ Bit16u result, val; + ++ result = 0x4f; ++ switch(GET_DL()) { ++ case 0x00: ++ val = biosfn_read_video_state_size2(CX); ++#ifdef DEBUG ++ printf("VGA state size=%x\n", val); ++#endif ++ if (CX & 8) ++ val += vbe_biosfn_read_video_state_size(); ++ write_word(ss, BX, val); ++ break; ++ case 0x01: ++ val = read_word(ss, BX); ++ val = biosfn_save_video_state(CX, ES, val); ++#ifdef DEBUG ++ printf("VGA save_state offset=%x\n", val); ++#endif ++ if (CX & 8) ++ vbe_biosfn_save_video_state(ES, val); ++ break; ++ case 0x02: ++ val = read_word(ss, BX); ++ val = biosfn_restore_video_state(CX, ES, val); ++#ifdef DEBUG ++ printf("VGA restore_state offset=%x\n", val); ++#endif ++ if (CX & 8) ++ vbe_biosfn_restore_video_state(ES, val); ++ break; ++ default: ++ // function failed ++ result = 0x100; ++ break; ++ } ++ write_word(ss, AX, result); ++} + + /** Function 05h - Display Window Control + * +@@ -1090,7 +1279,7 @@ + */ + ASM_START + vbe_biosfn_return_protected_mode_interface: +- test bx, bx ++ test bl, bl + jnz _fail + mov di, #0xc000 + mov es, di Index: vbe.h =================================================================== RCS file: /sources/vgabios/vgabios/vbe.h,v retrieving revision 1.24 diff -u -w -r1.24 vbe.h --- vbe.h 9 May 2004 20:31:31 -0000 1.24 -+++ vbe.h 13 Jun 2006 16:47:24 -0000 -@@ -193,6 +193,10 @@ ++++ vbe.h 14 Jun 2006 00:51:07 -0000 +@@ -14,7 +14,7 @@ + void vbe_biosfn_return_controller_information(AX, ES, DI); + void vbe_biosfn_return_mode_information(AX, CX, ES, DI); + void vbe_biosfn_set_mode(AX, BX, ES, DI); +-void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX); ++void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX); + void vbe_biosfn_set_get_palette_data(AX); + void vbe_biosfn_return_protected_mode_interface(AX); + +@@ -151,6 +151,12 @@ + Bit8u Reserved[189]; + } ModeInfoBlock; + ++typedef struct ModeInfoListItem ++{ ++ Bit16u mode; ++ ModeInfoBlockCompact info; ++} ModeInfoListItem; ++ + // VBE Return Status Info + // AL + #define VBE_RETURN_STATUS_SUPPORTED 0x4F +@@ -193,6 +199,10 @@ #define VBE_VESA_MODE_1280X1024X1555 0x119 #define VBE_VESA_MODE_1280X1024X565 0x11A #define VBE_VESA_MODE_1280X1024X888 0x11B @@ -90,7 +391,7 @@ diff -u -w -r1.24 vbe.h // BOCHS/PLEX86 'own' mode numbers #define VBE_OWN_MODE_320X200X8888 0x140 -@@ -202,6 +206,12 @@ +@@ -202,6 +212,12 @@ #define VBE_OWN_MODE_1024X768X8888 0x144 #define VBE_OWN_MODE_1280X1024X8888 0x145 #define VBE_OWN_MODE_320X200X8 0x146 @@ -103,7 +404,7 @@ diff -u -w -r1.24 vbe.h #define VBE_VESA_MODE_END_OF_LIST 0xFFFF -@@ -259,7 +269,7 @@ +@@ -259,7 +275,7 @@ // like 0xE0000000 @@ -112,2367 +413,484 @@ diff -u -w -r1.24 vbe.h #define VBE_DISPI_BANK_ADDRESS 0xA0000 #define VBE_DISPI_BANK_SIZE_KB 64 -Index: vbetables.h +Index: vgabios.c =================================================================== -RCS file: /sources/vgabios/vgabios/vbetables.h,v -retrieving revision 1.24 -diff -u -w -r1.24 vbetables.h ---- vbetables.h 22 Jul 2004 18:37:29 -0000 1.24 -+++ vbetables.h 13 Jun 2006 16:47:24 -0000 -@@ -14,46 +14,29 @@ - ModeInfoBlockCompact info; - } ModeInfoListItem; +RCS file: /sources/vgabios/vgabios/vgabios.c,v +retrieving revision 1.64 +diff -u -w -r1.64 vgabios.c +--- vgabios.c 25 Mar 2006 10:19:16 -0000 1.64 ++++ vgabios.c 14 Jun 2006 00:51:07 -0000 +@@ -109,8 +109,8 @@ + static void biosfn_write_string(); + static void biosfn_read_state_info(); + static void biosfn_read_video_state_size(); +-static void biosfn_save_video_state(); +-static void biosfn_restore_video_state(); ++static Bit16u biosfn_save_video_state(); ++static Bit16u biosfn_restore_video_state(); + extern Bit8u video_save_pointer_table[]; + + // This is for compiling with gcc2 and gcc3 +@@ -748,12 +748,7 @@ + vbe_biosfn_set_mode(&AX,BX,ES,DI); + break; + case 0x04: +- //FIXME +-#ifdef DEBUG +- unimplemented(); +-#endif +- // function failed +- AX=0x100; ++ vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX); + break; + case 0x09: + //FIXME +@@ -3138,23 +3133,215 @@ + } --// FIXME: check all member variables to be correct for the different modi --// FIXME: add more modi - static ModeInfoListItem mode_info_list[]= + // -------------------------------------------------------------------------------------------- +-static void biosfn_read_video_state_size (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; ++// -------------------------------------------------------------------------------------------- ++static Bit16u biosfn_read_video_state_size2 (CX) ++ Bit16u CX; { -- { -- VBE_VESA_MODE_640X400X8, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+{ 0x0100, /* 640x400x8 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, - /*Bit16u BytesPerScanLine*/ 640, --// Mandatory information for VBE 1.2 and above - /*Bit16u XResolution*/ 640, - /*Bit16u YResolution*/ 400, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 8, -- /*Bit8u NumberOfBanks*/ 4, // 640x400/64kb == 4 -+/*Bit8u NumberOfBanks*/ 4, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 15, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 0, - /*Bit8u RedFieldPosition*/ 0, - /*Bit8u GreenMaskSize*/ 0, -@@ -63,15 +46,9 @@ - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above - /*Bit16u LinBytesPerScanLine*/ 640, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -@@ -84,45 +61,28 @@ - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_640X480X8, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0101, /* 640x480x8 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, - /*Bit16u BytesPerScanLine*/ 640, --// Mandatory information for VBE 1.2 and above - /*Bit16u XResolution*/ 640, - /*Bit16u YResolution*/ 480, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 8, -- /*Bit8u NumberOfBanks*/ 5, // 640x480/64kb == 5 -+/*Bit8u NumberOfBanks*/ 5, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 11, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 0, - /*Bit8u RedFieldPosition*/ 0, - /*Bit8u GreenMaskSize*/ 0, -@@ -132,15 +92,9 @@ - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above - /*Bit16u LinBytesPerScanLine*/ 640, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -@@ -153,44 +107,28 @@ - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_800X600X4, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0102, /* 800x600x4 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, - /*Bit16u BytesPerScanLine*/ 100, --// Mandatory information for VBE 1.2 and above - /*Bit16u XResolution*/ 800, - /*Bit16u YResolution*/ 600, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 4, - /*Bit8u BitsPerPixel*/ 4, -- /*Bit8u NumberOfBanks*/ 16, -+/*Bit8u NumberOfBanks*/ 1, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PLANAR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 15, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 0, - /*Bit8u RedFieldPosition*/ 0, - /*Bit8u GreenMaskSize*/ 0, -@@ -200,11 +138,9 @@ - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above -- /*Bit32u PhysBasePtr*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above - /*Bit16u LinBytesPerScanLine*/ 100, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -@@ -217,46 +153,28 @@ - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_800X600X8, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0103, /* 800x600x8 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, - /*Bit16u BytesPerScanLine*/ 800, --// Mandatory information for VBE 1.2 and above - /*Bit16u XResolution*/ 800, - /*Bit16u YResolution*/ 600, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 8, -- /*Bit8u NumberOfBanks*/ 8, // 800x600/64kb == 8 -+/*Bit8u NumberOfBanks*/ 8, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 7, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 0, - /*Bit8u RedFieldPosition*/ 0, - /*Bit8u GreenMaskSize*/ 0, -@@ -266,15 +184,9 @@ - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above - /*Bit16u LinBytesPerScanLine*/ 800, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -@@ -287,46 +199,28 @@ - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_1024X768X8, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0105, /* 1024x768x8 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, - /*Bit16u BytesPerScanLine*/ 1024, --// Mandatory information for VBE 1.2 and above - /*Bit16u XResolution*/ 1024, - /*Bit16u YResolution*/ 768, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 8, -- /*Bit8u NumberOfBanks*/ 12, // 1024x768/64kb == 12 -+/*Bit8u NumberOfBanks*/ 12, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 3, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 0, - /*Bit8u RedFieldPosition*/ 0, - /*Bit8u GreenMaskSize*/ 0, -@@ -336,15 +230,9 @@ - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above - /*Bit16u LinBytesPerScanLine*/ 1024, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -@@ -357,116 +245,74 @@ - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_640X480X1555, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0107, /* 1280x1024x8 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 640*2, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 640, -- /*Bit16u YResolution*/ 480, -+/*Bit16u BytesPerScanLine*/ 1280, -+/*Bit16u XResolution*/ 1280, -+/*Bit16u YResolution*/ 1024, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, -- /*Bit8u BitsPerPixel*/ 15, -- /*Bit8u NumberOfBanks*/ 1, -- /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BitsPerPixel*/ 8, -+/*Bit8u NumberOfBanks*/ 20, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 5, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) -- /*Bit8u RedMaskSize*/ 5, -- /*Bit8u RedFieldPosition*/ 10, -- /*Bit8u GreenMaskSize*/ 5, -- /*Bit8u GreenFieldPosition*/ 5, -- /*Bit8u BlueMaskSize*/ 5, -+/*Bit8u RedMaskSize*/ 0, -+/*Bit8u RedFieldPosition*/ 0, -+/*Bit8u GreenMaskSize*/ 0, -+/*Bit8u GreenFieldPosition*/ 0, -+/*Bit8u BlueMaskSize*/ 0, - /*Bit8u BlueFieldPosition*/ 0, -- /*Bit8u RsvdMaskSize*/ 1, -- /*Bit8u RsvdFieldPosition*/ 15, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 640*2, -+/*Bit16u LinBytesPerScanLine*/ 1280, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -- /*Bit8u LinRedMaskSize*/ 5, -- /*Bit8u LinRedFieldPosition*/ 10, -+/*Bit8u LinRedMaskSize*/ 0, -+/*Bit8u LinRedFieldPosition*/ 0, - /*Bit8u LinGreenMaskSize*/ 0, -- /*Bit8u LinGreenFieldPosition*/ 5, -- /*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinGreenFieldPosition*/ 0, -+/*Bit8u LinBlueMaskSize*/ 0, - /*Bit8u LinBlueFieldPosition*/ 0, -- /*Bit8u LinRsvdMaskSize*/ 1, -- /*Bit8u LinRsvdFieldPosition*/ 15, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_800X600X1555, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x010d, /* 320x200x15 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 800*2, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 800, -- /*Bit16u YResolution*/ 600, -+/*Bit16u BytesPerScanLine*/ 640, -+/*Bit16u XResolution*/ 320, -+/*Bit16u YResolution*/ 200, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 15, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u NumberOfBanks*/ 2, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 3, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 5, - /*Bit8u RedFieldPosition*/ 10, - /*Bit8u GreenMaskSize*/ 5, -@@ -476,16 +322,10 @@ - /*Bit8u RsvdMaskSize*/ 1, - /*Bit8u RsvdFieldPosition*/ 15, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 800*2, -+/*Bit16u LinBytesPerScanLine*/ 640, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, - /*Bit8u LinRedMaskSize*/ 5, -@@ -497,256 +337,166 @@ - /*Bit8u LinRsvdMaskSize*/ 1, - /*Bit8u LinRsvdFieldPosition*/ 15, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_1024X768X1555, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x010e, /* 320x200x16 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 1024*2, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 1024, -- /*Bit16u YResolution*/ 768, -+/*Bit16u BytesPerScanLine*/ 640, -+/*Bit16u XResolution*/ 320, -+/*Bit16u YResolution*/ 200, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, -- /*Bit8u BitsPerPixel*/ 15, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u BitsPerPixel*/ 16, -+/*Bit8u NumberOfBanks*/ 2, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 1, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 5, -- /*Bit8u RedFieldPosition*/ 10, -- /*Bit8u GreenMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 11, -+/*Bit8u GreenMaskSize*/ 6, - /*Bit8u GreenFieldPosition*/ 5, - /*Bit8u BlueMaskSize*/ 5, - /*Bit8u BlueFieldPosition*/ 0, -- /*Bit8u RsvdMaskSize*/ 1, -- /*Bit8u RsvdFieldPosition*/ 15, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 1024*2, -+/*Bit16u LinBytesPerScanLine*/ 640, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, - /*Bit8u LinRedMaskSize*/ 5, -- /*Bit8u LinRedFieldPosition*/ 10, -- /*Bit8u LinGreenMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 11, -+/*Bit8u LinGreenMaskSize*/ 6, - /*Bit8u LinGreenFieldPosition*/ 5, - /*Bit8u LinBlueMaskSize*/ 5, - /*Bit8u LinBlueFieldPosition*/ 0, -- /*Bit8u LinRsvdMaskSize*/ 1, -- /*Bit8u LinRsvdFieldPosition*/ 15, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_640X480X565, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x010f, /* 320x200x24 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 640*2, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 640, -- /*Bit16u YResolution*/ 480, -+/*Bit16u BytesPerScanLine*/ 960, -+/*Bit16u XResolution*/ 320, -+/*Bit16u YResolution*/ 200, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, -- /*Bit8u BitsPerPixel*/ 16, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u BitsPerPixel*/ 24, -+/*Bit8u NumberOfBanks*/ 3, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 5, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) -- /*Bit8u RedMaskSize*/ 5, -- /*Bit8u RedFieldPosition*/ 11, -- /*Bit8u GreenMaskSize*/ 6, -- /*Bit8u GreenFieldPosition*/ 5, -- /*Bit8u BlueMaskSize*/ 5, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, - /*Bit8u BlueFieldPosition*/ 0, - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 640*2, -+/*Bit16u LinBytesPerScanLine*/ 960, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -- /*Bit8u LinRedMaskSize*/ 5, -- /*Bit8u LinRedFieldPosition*/ 11, -- /*Bit8u LinGreenMaskSize*/ 6, -- /*Bit8u LinGreenFieldPosition*/ 5, -- /*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, - /*Bit8u LinBlueFieldPosition*/ 0, - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_800X600X565, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0110, /* 640x480x15 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 800*2, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 800, -- /*Bit16u YResolution*/ 600, -+/*Bit16u BytesPerScanLine*/ 1280, -+/*Bit16u XResolution*/ 640, -+/*Bit16u YResolution*/ 480, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, -- /*Bit8u BitsPerPixel*/ 16, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u BitsPerPixel*/ 15, -+/*Bit8u NumberOfBanks*/ 10, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 3, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 5, -- /*Bit8u RedFieldPosition*/ 11, -- /*Bit8u GreenMaskSize*/ 6, -+/*Bit8u RedFieldPosition*/ 10, -+/*Bit8u GreenMaskSize*/ 5, - /*Bit8u GreenFieldPosition*/ 5, - /*Bit8u BlueMaskSize*/ 5, - /*Bit8u BlueFieldPosition*/ 0, -- /*Bit8u RsvdMaskSize*/ 0, -- /*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 1, -+/*Bit8u RsvdFieldPosition*/ 15, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 800*2, -+/*Bit16u LinBytesPerScanLine*/ 1280, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, - /*Bit8u LinRedMaskSize*/ 5, -- /*Bit8u LinRedFieldPosition*/ 11, -- /*Bit8u LinGreenMaskSize*/ 6, -+/*Bit8u LinRedFieldPosition*/ 10, -+/*Bit8u LinGreenMaskSize*/ 5, - /*Bit8u LinGreenFieldPosition*/ 5, - /*Bit8u LinBlueMaskSize*/ 5, - /*Bit8u LinBlueFieldPosition*/ 0, -- /*Bit8u LinRsvdMaskSize*/ 0, -- /*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 1, -+/*Bit8u LinRsvdFieldPosition*/ 15, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_1024X768X565, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0111, /* 640x480x16 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 1024*2, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 1024, -- /*Bit16u YResolution*/ 768, -+/*Bit16u BytesPerScanLine*/ 1280, -+/*Bit16u XResolution*/ 640, -+/*Bit16u YResolution*/ 480, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 16, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u NumberOfBanks*/ 10, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 1, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 5, - /*Bit8u RedFieldPosition*/ 11, - /*Bit8u GreenMaskSize*/ 6, -@@ -756,16 +506,10 @@ - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 1024*2, -+/*Bit16u LinBytesPerScanLine*/ 1280, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, - /*Bit8u LinRedMaskSize*/ 5, -@@ -777,46 +521,28 @@ - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_640X480X888, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0112, /* 640x480x24 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 640*3, --// Mandatory information for VBE 1.2 and above -+/*Bit16u BytesPerScanLine*/ 1920, - /*Bit16u XResolution*/ 640, - /*Bit16u YResolution*/ 480, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 24, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u NumberOfBanks*/ 15, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 3, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 8, - /*Bit8u RedFieldPosition*/ 16, - /*Bit8u GreenMaskSize*/ 8, -@@ -826,16 +552,10 @@ - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 640*3, -+/*Bit16u LinBytesPerScanLine*/ 1920, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, - /*Bit8u LinRedMaskSize*/ 8, -@@ -847,186 +567,764 @@ - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_800X600X888, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0113, /* 800x600x15 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 800*3, --// Mandatory information for VBE 1.2 and above -+/*Bit16u BytesPerScanLine*/ 1600, - /*Bit16u XResolution*/ 800, - /*Bit16u YResolution*/ 600, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, -- /*Bit8u BitsPerPixel*/ 24, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u BitsPerPixel*/ 15, -+/*Bit8u NumberOfBanks*/ 15, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 1, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) -- /*Bit8u RedMaskSize*/ 8, -- /*Bit8u RedFieldPosition*/ 16, -- /*Bit8u GreenMaskSize*/ 8, -- /*Bit8u GreenFieldPosition*/ 8, -- /*Bit8u BlueMaskSize*/ 8, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 10, -+/*Bit8u GreenMaskSize*/ 5, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, - /*Bit8u BlueFieldPosition*/ 0, -- /*Bit8u RsvdMaskSize*/ 0, -- /*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 1, -+/*Bit8u RsvdFieldPosition*/ 15, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 800*3, -+/*Bit16u LinBytesPerScanLine*/ 1600, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -- /*Bit8u LinRedMaskSize*/ 8, -- /*Bit8u LinRedFieldPosition*/ 16, -- /*Bit8u LinGreenMaskSize*/ 8, -- /*Bit8u LinGreenFieldPosition*/ 8, -- /*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 10, -+/*Bit8u LinGreenMaskSize*/ 5, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, - /*Bit8u LinBlueFieldPosition*/ 0, -- /*Bit8u LinRsvdMaskSize*/ 0, -- /*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 1, -+/*Bit8u LinRsvdFieldPosition*/ 15, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_VESA_MODE_1024X768X888, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0114, /* 800x600x16 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 1024*3, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 1024, -- /*Bit16u YResolution*/ 768, -+/*Bit16u BytesPerScanLine*/ 1600, -+/*Bit16u XResolution*/ 800, -+/*Bit16u YResolution*/ 600, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, -- /*Bit8u BitsPerPixel*/ 24, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u BitsPerPixel*/ 16, -+/*Bit8u NumberOfBanks*/ 15, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, - /*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) -- /*Bit8u RedMaskSize*/ 8, -- /*Bit8u RedFieldPosition*/ 16, -- /*Bit8u GreenMaskSize*/ 8, -- /*Bit8u GreenFieldPosition*/ 8, -- /*Bit8u BlueMaskSize*/ 8, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 11, -+/*Bit8u GreenMaskSize*/ 6, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, - /*Bit8u BlueFieldPosition*/ 0, - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 1024*3, -+/*Bit16u LinBytesPerScanLine*/ 1600, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -- /*Bit8u LinRedMaskSize*/ 8, -- /*Bit8u LinRedFieldPosition*/ 16, -- /*Bit8u LinGreenMaskSize*/ 8, -- /*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 11, -+/*Bit8u LinGreenMaskSize*/ 6, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0115, /* 800x600x24 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2400, -+/*Bit16u XResolution*/ 800, -+/*Bit16u YResolution*/ 600, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 24, -+/*Bit8u NumberOfBanks*/ 22, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2400, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0116, /* 1024x768x15 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2048, -+/*Bit16u XResolution*/ 1024, -+/*Bit16u YResolution*/ 768, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 15, -+/*Bit8u NumberOfBanks*/ 24, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 10, -+/*Bit8u GreenMaskSize*/ 5, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 1, -+/*Bit8u RsvdFieldPosition*/ 15, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2048, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 10, -+/*Bit8u LinGreenMaskSize*/ 5, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 1, -+/*Bit8u LinRsvdFieldPosition*/ 15, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0117, /* 1024x768x16 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2048, -+/*Bit16u XResolution*/ 1024, -+/*Bit16u YResolution*/ 768, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 16, -+/*Bit8u NumberOfBanks*/ 24, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 11, -+/*Bit8u GreenMaskSize*/ 6, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2048, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 11, -+/*Bit8u LinGreenMaskSize*/ 6, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0118, /* 1024x768x24 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 3072, -+/*Bit16u XResolution*/ 1024, -+/*Bit16u YResolution*/ 768, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 24, -+/*Bit8u NumberOfBanks*/ 36, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 3072, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0119, /* 1280x1024x15 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2560, -+/*Bit16u XResolution*/ 1280, -+/*Bit16u YResolution*/ 1024, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 15, -+/*Bit8u NumberOfBanks*/ 40, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 10, -+/*Bit8u GreenMaskSize*/ 5, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 1, -+/*Bit8u RsvdFieldPosition*/ 15, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2560, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 10, -+/*Bit8u LinGreenMaskSize*/ 5, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 1, -+/*Bit8u LinRsvdFieldPosition*/ 15, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x011a, /* 1280x1024x16 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2560, -+/*Bit16u XResolution*/ 1280, -+/*Bit16u YResolution*/ 1024, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 16, -+/*Bit8u NumberOfBanks*/ 40, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 11, -+/*Bit8u GreenMaskSize*/ 6, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2560, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 11, -+/*Bit8u LinGreenMaskSize*/ 6, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x011b, /* 1280x1024x24 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 3840, -+/*Bit16u XResolution*/ 1280, -+/*Bit16u YResolution*/ 1024, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 24, -+/*Bit8u NumberOfBanks*/ 60, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 3840, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x011c, /* 1600x1200x8 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 1600, -+/*Bit16u XResolution*/ 1600, -+/*Bit16u YResolution*/ 1200, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 8, -+/*Bit8u NumberOfBanks*/ 30, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 0, -+/*Bit8u RedFieldPosition*/ 0, -+/*Bit8u GreenMaskSize*/ 0, -+/*Bit8u GreenFieldPosition*/ 0, -+/*Bit8u BlueMaskSize*/ 0, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 1600, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 0, -+/*Bit8u LinRedFieldPosition*/ 0, -+/*Bit8u LinGreenMaskSize*/ 0, -+/*Bit8u LinGreenFieldPosition*/ 0, -+/*Bit8u LinBlueMaskSize*/ 0, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x011d, /* 1600x1200x15 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 3200, -+/*Bit16u XResolution*/ 1600, -+/*Bit16u YResolution*/ 1200, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 15, -+/*Bit8u NumberOfBanks*/ 59, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 10, -+/*Bit8u GreenMaskSize*/ 5, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 1, -+/*Bit8u RsvdFieldPosition*/ 15, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 3200, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 10, -+/*Bit8u LinGreenMaskSize*/ 5, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 1, -+/*Bit8u LinRsvdFieldPosition*/ 15, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x011e, /* 1600x1200x16 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 3200, -+/*Bit16u XResolution*/ 1600, -+/*Bit16u YResolution*/ 1200, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 16, -+/*Bit8u NumberOfBanks*/ 59, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 11, -+/*Bit8u GreenMaskSize*/ 6, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 3200, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 11, -+/*Bit8u LinGreenMaskSize*/ 6, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x011f, /* 1600x1200x24 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 4800, -+/*Bit16u XResolution*/ 1600, -+/*Bit16u YResolution*/ 1200, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 24, -+/*Bit8u NumberOfBanks*/ 88, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 4800, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, - /*Bit8u LinBlueMaskSize*/ 8, - /*Bit8u LinBlueFieldPosition*/ 0, - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_OWN_MODE_640X480X8888, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0140, /* 320x200x32 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 1280, -+/*Bit16u XResolution*/ 320, -+/*Bit16u YResolution*/ 200, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 32, -+/*Bit8u NumberOfBanks*/ 4, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 8, -+/*Bit8u RsvdFieldPosition*/ 24, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 1280, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 8, -+/*Bit8u LinRsvdFieldPosition*/ 24, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0141, /* 640x400x32 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2560, -+/*Bit16u XResolution*/ 640, -+/*Bit16u YResolution*/ 400, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 32, -+/*Bit8u NumberOfBanks*/ 16, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 8, -+/*Bit8u RsvdFieldPosition*/ 24, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2560, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 8, -+/*Bit8u LinRsvdFieldPosition*/ 24, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0142, /* 640x480x32 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2560, -+/*Bit16u XResolution*/ 640, -+/*Bit16u YResolution*/ 480, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 32, -+/*Bit8u NumberOfBanks*/ 19, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 8, -+/*Bit8u RsvdFieldPosition*/ 24, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2560, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 8, -+/*Bit8u LinRsvdFieldPosition*/ 24, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0143, /* 800x600x32 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 640*4, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 640, -- /*Bit16u YResolution*/ 480, -+/*Bit16u BytesPerScanLine*/ 3200, -+/*Bit16u XResolution*/ 800, -+/*Bit16u YResolution*/ 600, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 32, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u NumberOfBanks*/ 30, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 1, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 8, - /*Bit8u RedFieldPosition*/ 16, - /*Bit8u GreenMaskSize*/ 8, -@@ -1035,17 +1333,11 @@ - /*Bit8u BlueFieldPosition*/ 0, - /*Bit8u RsvdMaskSize*/ 8, - /*Bit8u RsvdFieldPosition*/ 24, -- /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB -+/*Bit8u DirectColorModeInfo*/ 0, - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 640*4, -+/*Bit16u LinBytesPerScanLine*/ 3200, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, - /*Bit8u LinRedMaskSize*/ 8, -@@ -1057,46 +1349,28 @@ - /*Bit8u LinRsvdMaskSize*/ 8, - /*Bit8u LinRsvdFieldPosition*/ 24, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_OWN_MODE_800X600X8888, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0144, /* 1024x768x32 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 800*4, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 800, -- /*Bit16u YResolution*/ 600, -+/*Bit16u BytesPerScanLine*/ 4096, -+/*Bit16u XResolution*/ 1024, -+/*Bit16u YResolution*/ 768, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 32, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u NumberOfBanks*/ 48, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 1, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 8, - /*Bit8u RedFieldPosition*/ 16, - /*Bit8u GreenMaskSize*/ 8, -@@ -1105,17 +1379,11 @@ - /*Bit8u BlueFieldPosition*/ 0, - /*Bit8u RsvdMaskSize*/ 8, - /*Bit8u RsvdFieldPosition*/ 24, -- /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB -+/*Bit8u DirectColorModeInfo*/ 0, - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 800*4, -+/*Bit16u LinBytesPerScanLine*/ 4096, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, - /*Bit8u LinRedMaskSize*/ 8, -@@ -1127,46 +1395,28 @@ - /*Bit8u LinRsvdMaskSize*/ 8, - /*Bit8u LinRsvdFieldPosition*/ 24, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_OWN_MODE_1024X768X8888, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | --#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | -- VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0145, /* 1280x1024x32 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, -- /*Bit16u BytesPerScanLine*/ 1024*4, --// Mandatory information for VBE 1.2 and above -- /*Bit16u XResolution*/ 1024, -- /*Bit16u YResolution*/ 768, -+/*Bit16u BytesPerScanLine*/ 5120, -+/*Bit16u XResolution*/ 1280, -+/*Bit16u YResolution*/ 1024, - /*Bit8u XCharSize*/ 8, - /*Bit8u YCharSize*/ 16, - /*Bit8u NumberOfPlanes*/ 1, - /*Bit8u BitsPerPixel*/ 32, -- /*Bit8u NumberOfBanks*/ 1, -+/*Bit8u NumberOfBanks*/ 80, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 1, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 8, - /*Bit8u RedFieldPosition*/ 16, - /*Bit8u GreenMaskSize*/ 8, -@@ -1175,17 +1425,11 @@ - /*Bit8u BlueFieldPosition*/ 0, - /*Bit8u RsvdMaskSize*/ 8, - /*Bit8u RsvdFieldPosition*/ 24, -- /*Bit8u DirectColorModeInfo*/ VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB -+/*Bit8u DirectColorModeInfo*/ 0, - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, --#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above -- /*Bit16u LinBytesPerScanLine*/ 1024*4, -+/*Bit16u LinBytesPerScanLine*/ 5120, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, - /*Bit8u LinRedMaskSize*/ 8, -@@ -1197,33 +1441,17 @@ - /*Bit8u LinRsvdMaskSize*/ 8, - /*Bit8u LinRsvdFieldPosition*/ 24, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- -- { -- VBE_OWN_MODE_320X200X8, -- { --/*typedef struct ModeInfoBlock --{*/ --// Mandatory information for all VBE revisions -- /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | -- VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | -- VBE_MODE_ATTRIBUTE_COLOR_MODE | --#ifdef VBE_HAVE_LFB -- VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | +-#ifdef DEBUG +- unimplemented(); +-#endif ++ Bit16u size; ++ size = 0; ++ if (CX & 1) { ++ size += 0x46; ++ } ++ if (CX & 2) { ++ size += (5 + 8 + 5) * 2 + 6; ++ } ++ if (CX & 4) { ++ size += 3 + 256 * 3 + 1; + } +-static void biosfn_save_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; ++ return size; ++} ++ ++static void biosfn_read_video_state_size (CX, BX) ++ Bit16u CX; Bit16u *BX; + { +-#ifdef DEBUG +- unimplemented(); -#endif -- VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -- /*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_READABLE | -- VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+} }, -+{ 0x0146, /* 320x200x8 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, - /*Bit8u WinBAttributes*/ 0, - /*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, - /*Bit16u WinASegment*/ VGAMEM_GRAPH, -- /*Bit16u WinBSegment*/ 0, -+/*Bit16u WinBSegment*/ 0x0000, - /*Bit32u WinFuncPtr*/ 0, - /*Bit16u BytesPerScanLine*/ 320, --// Mandatory information for VBE 1.2 and above - /*Bit16u XResolution*/ 320, - /*Bit16u YResolution*/ 200, - /*Bit8u XCharSize*/ 8, -@@ -1233,9 +1461,8 @@ - /*Bit8u NumberOfBanks*/ 1, - /*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, - /*Bit8u BankSize*/ 0, -- /*Bit8u NumberOfImagePages*/ 3, -+/*Bit8u NumberOfImagePages*/ 0, - /*Bit8u Reserved_page*/ 0, --// Direct Color fields (required for direct/6 and YUV/7 memory models) - /*Bit8u RedMaskSize*/ 0, - /*Bit8u RedFieldPosition*/ 0, - /*Bit8u GreenMaskSize*/ 0, -@@ -1245,15 +1472,9 @@ - /*Bit8u RsvdMaskSize*/ 0, - /*Bit8u RsvdFieldPosition*/ 0, - /*Bit8u DirectColorModeInfo*/ 0, --// Mandatory information for VBE 2.0 and above --#ifdef VBE_HAVE_LFB - /*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, --#else -- /*Bit32u PhysBasePtr*/ 0, ++ Bit16u ss=get_SS(); ++ write_word(ss, BX, biosfn_read_video_state_size2(CX)); + } +-static void biosfn_restore_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX; ++ ++static Bit16u biosfn_save_video_state (CX,ES,BX) ++ Bit16u CX;Bit16u ES;Bit16u BX; + { +-#ifdef DEBUG +- unimplemented(); -#endif - /*Bit32u OffScreenMemOffset*/ 0, - /*Bit16u OffScreenMemSize*/ 0, --// Mandatory information for VBE 3.0 and above - /*Bit16u LinBytesPerScanLine*/ 320, - /*Bit8u BnkNumberOfPages*/ 0, - /*Bit8u LinNumberOfPages*/ 0, -@@ -1266,17 +1487,286 @@ - /*Bit8u LinRsvdMaskSize*/ 0, - /*Bit8u LinRsvdFieldPosition*/ 0, - /*Bit32u MaxPixelClock*/ 0, --/*} ModeInfoBlock;*/ -- } -- }, -- --/** END OF THE LIST **/ -- { -- VBE_VESA_MODE_END_OF_LIST, -- { -- 0, -- } -- } -+} }, -+{ 0x0147, /* 1600x1200x32 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 6400, -+/*Bit16u XResolution*/ 1600, -+/*Bit16u YResolution*/ 1200, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 32, -+/*Bit8u NumberOfBanks*/ 118, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 8, -+/*Bit8u RsvdFieldPosition*/ 24, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 6400, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 8, -+/*Bit8u LinRsvdFieldPosition*/ 24, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0148, /* 1152x864x8 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 1152, -+/*Bit16u XResolution*/ 1152, -+/*Bit16u YResolution*/ 864, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 8, -+/*Bit8u NumberOfBanks*/ 16, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_PACKED_PIXEL, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 0, -+/*Bit8u RedFieldPosition*/ 0, -+/*Bit8u GreenMaskSize*/ 0, -+/*Bit8u GreenFieldPosition*/ 0, -+/*Bit8u BlueMaskSize*/ 0, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 1152, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 0, -+/*Bit8u LinRedFieldPosition*/ 0, -+/*Bit8u LinGreenMaskSize*/ 0, -+/*Bit8u LinGreenFieldPosition*/ 0, -+/*Bit8u LinBlueMaskSize*/ 0, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x0149, /* 1152x864x15 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2304, -+/*Bit16u XResolution*/ 1152, -+/*Bit16u YResolution*/ 864, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 15, -+/*Bit8u NumberOfBanks*/ 31, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 10, -+/*Bit8u GreenMaskSize*/ 5, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 1, -+/*Bit8u RsvdFieldPosition*/ 15, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2304, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 10, -+/*Bit8u LinGreenMaskSize*/ 5, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 1, -+/*Bit8u LinRsvdFieldPosition*/ 15, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x014a, /* 1152x864x16 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 2304, -+/*Bit16u XResolution*/ 1152, -+/*Bit16u YResolution*/ 864, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 16, -+/*Bit8u NumberOfBanks*/ 31, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 5, -+/*Bit8u RedFieldPosition*/ 11, -+/*Bit8u GreenMaskSize*/ 6, -+/*Bit8u GreenFieldPosition*/ 5, -+/*Bit8u BlueMaskSize*/ 5, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 2304, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 5, -+/*Bit8u LinRedFieldPosition*/ 11, -+/*Bit8u LinGreenMaskSize*/ 6, -+/*Bit8u LinGreenFieldPosition*/ 5, -+/*Bit8u LinBlueMaskSize*/ 5, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x014b, /* 1152x864x24 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 3456, -+/*Bit16u XResolution*/ 1152, -+/*Bit16u YResolution*/ 864, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 24, -+/*Bit8u NumberOfBanks*/ 46, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 0, -+/*Bit8u RsvdFieldPosition*/ 0, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 3456, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 0, -+/*Bit8u LinRsvdFieldPosition*/ 0, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ 0x014c, /* 1152x864x32 */ -+{ /*Bit16u ModeAttributes*/ VBE_MODE_ATTRIBUTE_SUPPORTED | VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | VBE_MODE_ATTRIBUTE_COLOR_MODE | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | VBE_MODE_ATTRIBUTE_GRAPHICS_MODE, -+/*Bit8u WinAAttributes*/ VBE_WINDOW_ATTRIBUTE_RELOCATABLE | VBE_WINDOW_ATTRIBUTE_READABLE | VBE_WINDOW_ATTRIBUTE_WRITEABLE, -+/*Bit8u WinBAttributes*/ 0, -+/*Bit16u WinGranularity*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinSize*/ VBE_DISPI_BANK_SIZE_KB, -+/*Bit16u WinASegment*/ VGAMEM_GRAPH, -+/*Bit16u WinBSegment*/ 0x0000, -+/*Bit32u WinFuncPtr*/ 0, -+/*Bit16u BytesPerScanLine*/ 4608, -+/*Bit16u XResolution*/ 1152, -+/*Bit16u YResolution*/ 864, -+/*Bit8u XCharSize*/ 8, -+/*Bit8u YCharSize*/ 16, -+/*Bit8u NumberOfPlanes*/ 1, -+/*Bit8u BitsPerPixel*/ 32, -+/*Bit8u NumberOfBanks*/ 61, -+/*Bit8u MemoryModel*/ VBE_MEMORYMODEL_DIRECT_COLOR, -+/*Bit8u BankSize*/ 0, -+/*Bit8u NumberOfImagePages*/ 0, -+/*Bit8u Reserved_page*/ 0, -+/*Bit8u RedMaskSize*/ 8, -+/*Bit8u RedFieldPosition*/ 16, -+/*Bit8u GreenMaskSize*/ 8, -+/*Bit8u GreenFieldPosition*/ 8, -+/*Bit8u BlueMaskSize*/ 8, -+/*Bit8u BlueFieldPosition*/ 0, -+/*Bit8u RsvdMaskSize*/ 8, -+/*Bit8u RsvdFieldPosition*/ 24, -+/*Bit8u DirectColorModeInfo*/ 0, -+/*Bit32u PhysBasePtr*/ VBE_DISPI_LFB_PHYSICAL_ADDRESS, -+/*Bit32u OffScreenMemOffset*/ 0, -+/*Bit16u OffScreenMemSize*/ 0, -+/*Bit16u LinBytesPerScanLine*/ 4608, -+/*Bit8u BnkNumberOfPages*/ 0, -+/*Bit8u LinNumberOfPages*/ 0, -+/*Bit8u LinRedMaskSize*/ 8, -+/*Bit8u LinRedFieldPosition*/ 16, -+/*Bit8u LinGreenMaskSize*/ 8, -+/*Bit8u LinGreenFieldPosition*/ 8, -+/*Bit8u LinBlueMaskSize*/ 8, -+/*Bit8u LinBlueFieldPosition*/ 0, -+/*Bit8u LinRsvdMaskSize*/ 8, -+/*Bit8u LinRsvdFieldPosition*/ 24, -+/*Bit32u MaxPixelClock*/ 0, -+} }, -+{ VBE_VESA_MODE_END_OF_LIST, -+{ 0, -+} }, - }; ++ Bit16u i, v, crtc_addr, ar_index; ++ ++ crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS); ++ if (CX & 1) { ++ write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++; ++ write_byte(ES, BX, inb(crtc_addr)); BX++; ++ write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++; ++ inb(VGAREG_ACTL_RESET); ++ ar_index = inb(VGAREG_ACTL_ADDRESS); ++ write_byte(ES, BX, ar_index); BX++; ++ write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++; ++ ++ for(i=1;i<=4;i++){ ++ outb(VGAREG_SEQU_ADDRESS, i); ++ write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++; ++ } ++ outb(VGAREG_SEQU_ADDRESS, 0); ++ write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++; ++ ++ for(i=0;i<=0x18;i++) { ++ outb(crtc_addr,i); ++ write_byte(ES, BX, inb(crtc_addr+1)); BX++; ++ } ++ ++ for(i=0;i<=0x13;i++) { ++ inb(VGAREG_ACTL_RESET); ++ outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20)); ++ write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++; ++ } ++ inb(VGAREG_ACTL_RESET); ++ ++ for(i=0;i<=8;i++) { ++ outb(VGAREG_GRDC_ADDRESS,i); ++ write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++; ++ } ++ ++ write_word(ES, BX, crtc_addr); BX+= 2; ++ ++ /* XXX: read plane latches */ ++ write_byte(ES, BX, 0); BX++; ++ write_byte(ES, BX, 0); BX++; ++ write_byte(ES, BX, 0); BX++; ++ write_byte(ES, BX, 0); BX++; ++ } ++ if (CX & 2) { ++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++; ++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2; ++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2; ++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2; ++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++; ++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2; ++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++; ++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++; ++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++; ++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2; ++ for(i=0;i<8;i++) { ++ write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i)); ++ BX += 2; ++ } ++ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2; ++ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++; ++ /* current font */ ++ write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2; ++ write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2; ++ write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2; ++ write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2; ++ } ++ if (CX & 4) { ++ /* XXX: check this */ ++ write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */ ++ write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */ ++ write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++; ++ // Set the whole dac always, from 0 ++ outb(VGAREG_DAC_WRITE_ADDRESS,0x00); ++ for(i=0;i<256*3;i++) { ++ write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++; ++ } ++ write_byte(ES, BX, 0); BX++; /* color select register */ ++ } ++ return BX; ++} ++ ++static Bit16u biosfn_restore_video_state (CX,ES,BX) ++ Bit16u CX;Bit16u ES;Bit16u BX; ++{ ++ Bit16u i, crtc_addr, v, addr1, ar_index; ++ ++ if (CX & 1) { ++ // Reset Attribute Ctl flip-flop ++ inb(VGAREG_ACTL_RESET); ++ ++ crtc_addr = read_word(ES, BX + 0x40); ++ addr1 = BX; ++ BX += 5; ++ ++ for(i=1;i<=4;i++){ ++ outb(VGAREG_SEQU_ADDRESS, i); ++ outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++; ++ } ++ outb(VGAREG_SEQU_ADDRESS, 0); ++ outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++; ++ ++ // Disable CRTC write protection ++ outw(crtc_addr,0x0011); ++ // Set CRTC regs ++ for(i=0;i<=0x18;i++) { ++ if (i != 0x11) { ++ outb(crtc_addr,i); ++ outb(crtc_addr+1, read_byte(ES, BX)); ++ } ++ BX++; ++ } ++ // select crtc base address ++ v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01; ++ if (crtc_addr = 0x3d4) ++ v |= 0x01; ++ outb(VGAREG_WRITE_MISC_OUTPUT, v); ++ ++ // enable write protection if needed ++ outb(crtc_addr, 0x11); ++ outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11)); ++ ++ // Set Attribute Ctl ++ ar_index = read_byte(ES, addr1 + 0x03); ++ inb(VGAREG_ACTL_RESET); ++ for(i=0;i<=0x13;i++) { ++ outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20)); ++ outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++; ++ } ++ outb(VGAREG_ACTL_ADDRESS, ar_index); ++ inb(VGAREG_ACTL_RESET); ++ ++ for(i=0;i<=8;i++) { ++ outb(VGAREG_GRDC_ADDRESS,i); ++ outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++; ++ } ++ BX += 2; /* crtc_addr */ ++ BX += 4; /* plane latches */ ++ ++ outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++; ++ outb(crtc_addr, read_byte(ES, addr1)); addr1++; ++ outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++; ++ addr1++; ++ outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++; ++ } ++ if (CX & 2) { ++ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++; ++ write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2; ++ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2; ++ write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2; ++ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++; ++ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2; ++ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++; ++ write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++; ++ write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++; ++ write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2; ++ for(i=0;i<8;i++) { ++ write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX)); ++ BX += 2; ++ } ++ write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2; ++ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++; ++ /* current font */ ++ write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2; ++ write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2; ++ write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2; ++ write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2; ++ } ++ if (CX & 4) { ++ BX++; ++ v = read_byte(ES, BX); BX++; ++ outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++; ++ // Set the whole dac always, from 0 ++ outb(VGAREG_DAC_WRITE_ADDRESS,0x00); ++ for(i=0;i<256*3;i++) { ++ outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++; ++ } ++ BX++; ++ outb(VGAREG_DAC_WRITE_ADDRESS, v); ++ } ++ return BX; + } - #endif + // ============================================================================================ +diff -u -w vbetables-gen.c +--- vbetables-gen.c 1970-01-01 01:00:00.000000000 +0100 ++++ vbetables-gen.c 2006-06-14 00:52:18.000000000 +0200 +@@ -0,0 +1,217 @@ ++/* Generate the VGABIOS VBE Tables */ ++#include ++#include ++ ++typedef struct { ++ int width; ++ int height; ++ int depth; ++ int mode; ++} ModeInfo; ++ ++ModeInfo modes[] = { ++ /* standard VESA modes */ ++{ 640, 400, 8 , 0x100}, ++{ 640, 480, 8 , 0x101}, ++{ 800, 600, 4 , 0x102}, ++{ 800, 600, 8 , 0x103}, ++ //{ 1024, 768, 4 , 0x104}, ++{ 1024, 768, 8 , 0x105}, ++ //{ 1280, 1024, 4 , 0x106}, ++{ 1280, 1024, 8 , 0x107}, ++{ 320, 200, 15 , 0x10D}, ++{ 320, 200, 16 , 0x10E}, ++{ 320, 200, 24 , 0x10F}, ++{ 640, 480, 15 , 0x110}, ++{ 640, 480, 16 , 0x111}, ++{ 640, 480, 24 , 0x112}, ++{ 800, 600, 15 , 0x113}, ++{ 800, 600, 16 , 0x114}, ++{ 800, 600, 24 , 0x115}, ++{ 1024, 768, 15 , 0x116}, ++{ 1024, 768, 16 , 0x117}, ++{ 1024, 768, 24 , 0x118}, ++{ 1280, 1024, 15 , 0x119}, ++{ 1280, 1024, 16 , 0x11A}, ++{ 1280, 1024, 24 , 0x11B}, ++{ 1600, 1200, 8 , 0x11C}, ++{ 1600, 1200, 15 , 0x11D}, ++{ 1600, 1200, 16 , 0x11E}, ++{ 1600, 1200, 24 , 0x11F}, ++ ++ /* BOCHS/PLE, 86 'own' mode numbers */ ++{ 320, 200, 32 , 0x140}, ++{ 640, 400, 32 , 0x141}, ++{ 640, 480, 32 , 0x142}, ++{ 800, 600, 32 , 0x143}, ++{ 1024, 768, 32 , 0x144}, ++{ 1280, 1024, 32 , 0x145}, ++{ 320, 200, 8 , 0x146}, ++{ 1600, 1200, 32 , 0x147}, ++{ 1152, 864, 8 , 0x148}, ++{ 1152, 864, 15 , 0x149}, ++{ 1152, 864, 16 , 0x14a}, ++{ 1152, 864, 24 , 0x14b}, ++{ 1152, 864, 32 , 0x14c}, ++{ 0, }, ++}; ++ ++int main(int argc, char **argv) ++{ ++ const ModeInfo *pm; ++ int pitch, r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos; ++ const char *str; ++ ++ printf("/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT */\n"); ++ printf("static ModeInfoListItem mode_info_list[]=\n"); ++ printf("{\n"); ++ for(pm = modes; pm->mode != 0; pm++) { ++ printf("{ 0x%04x, /* %dx%dx%d */\n", ++ pm->mode, pm->width, pm->height, pm->depth); ++ printf("{ /*Bit16u ModeAttributes*/ %s,\n", ++ "VBE_MODE_ATTRIBUTE_SUPPORTED | " ++ "VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | " ++ "VBE_MODE_ATTRIBUTE_COLOR_MODE | " ++ "VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | " ++ "VBE_MODE_ATTRIBUTE_GRAPHICS_MODE"); ++ ++ printf("/*Bit8u WinAAttributes*/ %s,\n", ++ "VBE_WINDOW_ATTRIBUTE_RELOCATABLE | " ++ "VBE_WINDOW_ATTRIBUTE_READABLE | " ++ "VBE_WINDOW_ATTRIBUTE_WRITEABLE"); ++ ++ printf("/*Bit8u WinBAttributes*/ %d,\n", 0); ++ ++ printf("/*Bit16u WinGranularity*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB"); ++ ++ printf("/*Bit16u WinSize*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB"); ++ ++ printf("/*Bit16u WinASegment*/ %s,\n", "VGAMEM_GRAPH"); ++ ++ printf("/*Bit16u WinBSegment*/ 0x%04x,\n", 0); ++ ++ printf("/*Bit32u WinFuncPtr*/ %d,\n", 0); ++ ++ if (pm->depth == 4) ++ pitch = (pm->width + 7) / 8; ++ else ++ pitch = pm->width * ((pm->depth + 7) / 8); ++ printf("/*Bit16u BytesPerScanLine*/ %d,\n", pitch); ++ ++ // Mandatory information for VBE 1.2 and above ++ printf("/*Bit16u XResolution*/ %d,\n", pm->width); ++ printf("/*Bit16u YResolution*/ %d,\n", pm->height); ++ printf("/*Bit8u XCharSize*/ %d,\n", 8); ++ printf("/*Bit8u YCharSize*/ %d,\n", 16); ++ if (pm->depth == 4) { ++ printf("/*Bit8u NumberOfPlanes*/ %d,\n", 4); ++ printf("/*Bit8u BitsPerPixel*/ %d,\n", pm->depth); ++ } else { ++ printf("/*Bit8u NumberOfPlanes*/ %d,\n", 1); ++ printf("/*Bit8u BitsPerPixel*/ %d,\n", pm->depth); ++ } ++ printf("/*Bit8u NumberOfBanks*/ %d,\n", ++ (pm->height * pitch + 65535) / 65536); ++ ++ if (pm->depth == 4) ++ str = "VBE_MEMORYMODEL_PLANAR"; ++ else if (pm->depth == 8) ++ str = "VBE_MEMORYMODEL_PACKED_PIXEL"; ++ else ++ str = "VBE_MEMORYMODEL_DIRECT_COLOR"; ++ printf("/*Bit8u MemoryModel*/ %s,\n", str); ++ printf("/*Bit8u BankSize*/ %d,\n", 0); ++ /* XXX: check */ ++ printf("/*Bit8u NumberOfImagePages*/ %d,\n", 0); ++ printf("/*Bit8u Reserved_page*/ %d,\n", 0); ++ ++ // Direct Color fields (required for direct/6 and YUV/7 memory models) ++ switch(pm->depth) { ++ case 15: ++ r_size = 5; ++ r_pos = 10; ++ g_size = 5; ++ g_pos = 5; ++ b_size = 5; ++ b_pos = 0; ++ a_size = 1; ++ a_pos = 15; ++ break; ++ case 16: ++ r_size = 5; ++ r_pos = 11; ++ g_size = 6; ++ g_pos = 5; ++ b_size = 5; ++ b_pos = 0; ++ a_size = 0; ++ a_pos = 0; ++ break; ++ case 24: ++ r_size = 8; ++ r_pos = 16; ++ g_size = 8; ++ g_pos = 8; ++ b_size = 8; ++ b_pos = 0; ++ a_size = 0; ++ a_pos = 0; ++ break; ++ case 32: ++ r_size = 8; ++ r_pos = 16; ++ g_size = 8; ++ g_pos = 8; ++ b_size = 8; ++ b_pos = 0; ++ a_size = 8; ++ a_pos = 24; ++ break; ++ default: ++ r_size = 0; ++ r_pos = 0; ++ g_size = 0; ++ g_pos = 0; ++ b_size = 0; ++ b_pos = 0; ++ a_size = 0; ++ a_pos = 0; ++ break; ++ } ++ ++ printf("/*Bit8u RedMaskSize*/ %d,\n", r_size); ++ printf("/*Bit8u RedFieldPosition*/ %d,\n", r_pos); ++ printf("/*Bit8u GreenMaskSize*/ %d,\n", g_size); ++ printf("/*Bit8u GreenFieldPosition*/ %d,\n", g_pos); ++ printf("/*Bit8u BlueMaskSize*/ %d,\n", b_size); ++ printf("/*Bit8u BlueFieldPosition*/ %d,\n", b_pos); ++ printf("/*Bit8u RsvdMaskSize*/ %d,\n", a_size); ++ printf("/*Bit8u RsvdFieldPosition*/ %d,\n", a_pos); ++ printf("/*Bit8u DirectColorModeInfo*/ %d,\n", 0); ++ ++// Mandatory information for VBE 2.0 and above ++ printf("/*Bit32u PhysBasePtr*/ %s,\n", ++ "VBE_DISPI_LFB_PHYSICAL_ADDRESS"); ++ printf("/*Bit32u OffScreenMemOffset*/ %d,\n", 0); ++ printf("/*Bit16u OffScreenMemSize*/ %d,\n", 0); ++ // Mandatory information for VBE 3.0 and above ++ printf("/*Bit16u LinBytesPerScanLine*/ %d,\n", pitch); ++ printf("/*Bit8u BnkNumberOfPages*/ %d,\n", 0); ++ printf("/*Bit8u LinNumberOfPages*/ %d,\n", 0); ++ printf("/*Bit8u LinRedMaskSize*/ %d,\n", r_size); ++ printf("/*Bit8u LinRedFieldPosition*/ %d,\n", r_pos); ++ printf("/*Bit8u LinGreenMaskSize*/ %d,\n", g_size); ++ printf("/*Bit8u LinGreenFieldPosition*/ %d,\n", g_pos); ++ printf("/*Bit8u LinBlueMaskSize*/ %d,\n", b_size); ++ printf("/*Bit8u LinBlueFieldPosition*/ %d,\n", b_pos); ++ printf("/*Bit8u LinRsvdMaskSize*/ %d,\n", a_size); ++ printf("/*Bit8u LinRsvdFieldPosition*/ %d,\n", a_pos); ++ printf("/*Bit32u MaxPixelClock*/ %d,\n", 0); ++ printf("} },\n"); ++ } ++ printf("{ VBE_VESA_MODE_END_OF_LIST,\n"); ++ printf("{ 0,\n"); ++ printf("} },\n"); ++ printf("};\n"); ++ return 0; ++} -- cgit v1.2.3 From 0986ac3be2989f37cec262f3370bac77999a52bf Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 12:36:32 +0000 Subject: use OpenBIOS instead of Proll on sparc (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1960 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- hw/sun4m.c | 9 ++------- hw/sun4u.c | 9 ++------- pc-bios/README | 9 ++++----- pc-bios/openbios-sparc32 | Bin 0 -> 506966 bytes pc-bios/proll.elf | Bin 132317 -> 0 bytes qemu-doc.texi | 13 +++++++------ 7 files changed, 17 insertions(+), 27 deletions(-) create mode 100644 pc-bios/openbios-sparc32 delete mode 100644 pc-bios/proll.elf diff --git a/Makefile b/Makefile index b6f496e6a..6716ccf37 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ install: all $(if $(BUILD_DOCS),install-doc) $(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 proll.elf linux_boot.bin; do \ + video.x openbios-sparc32 linux_boot.bin; do \ $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ done ifndef CONFIG_WIN32 @@ -149,7 +149,7 @@ tarbin: $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ $(datadir)/video.x \ - $(datadir)/proll.elf \ + $(datadir)/openbios-sparc32 \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff --git a/hw/sun4m.c b/hw/sun4m.c index f25fa3eea..203732f21 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -28,8 +28,7 @@ #define INITRD_LOAD_ADDR 0x00800000 #define PROM_SIZE_MAX (256 * 1024) #define PROM_ADDR 0xffd00000 -#define PROM_FILENAMEB "proll.bin" -#define PROM_FILENAMEE "proll.elf" +#define PROM_FILENAME "openbios-sparc32" #define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ #define PHYS_JJ_IDPROM_OFF 0x1FD8 #define PHYS_JJ_EEPROM_SIZE 0x2000 @@ -273,12 +272,8 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); ret = load_elf(buf, 0, NULL); - if (ret < 0) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_image(buf, phys_ram_base + prom_offset); - } if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); diff --git a/hw/sun4u.c b/hw/sun4u.c index 5e6f8baf9..22ab4e1d7 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -32,8 +32,7 @@ #define APB_SPECIAL_BASE 0x1fe00000000ULL #define APB_MEM_BASE 0x1ff00000000ULL #define VGA_BASE (APB_MEM_BASE + 0x400000ULL) -#define PROM_FILENAMEB "proll-sparc64.bin" -#define PROM_FILENAMEE "proll-sparc64.elf" +#define PROM_FILENAME "openbios-sparc64" #define NVRAM_SIZE 0x2000 /* TSC handling */ @@ -282,12 +281,8 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); ret = load_elf(buf, 0, NULL); - if (ret < 0) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_image(buf, phys_ram_base + prom_offset); - } if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); diff --git a/pc-bios/README b/pc-bios/README index 5e61a28fc..fc85eb429 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -7,11 +7,10 @@ - The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm. -- Proll is a GPL'd boot PROM for Sparc JavaStations - (http://people.redhat.com/zaitcev/linux/). - Applying proll.patch allows circumventing some bugs and enables - faster kernel load through a hack. - - video.x is a PowerMac NDRV compatible driver for a VGA frame buffer. It comes from the Mac-on-Linux project (http://www.maconlinux.org/). + +- OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable + firmware implementation. The goal is to implement a 100% IEEE + 1275-1994 (referred to as Open Firmware) compliant firmware. diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 new file mode 100644 index 000000000..7a729aa81 Binary files /dev/null and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/proll.elf b/pc-bios/proll.elf deleted file mode 100644 index 21c739cac..000000000 Binary files a/pc-bios/proll.elf and /dev/null differ diff --git a/qemu-doc.texi b/qemu-doc.texi index 2b37179c5..23bf68008 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1394,7 +1394,7 @@ More information is available at @node Sparc32 System emulator invocation @section Sparc32 System emulator invocation -Use the executable @file{qemu-system-sparc} to simulate a JavaStation +Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5 (sun4m architecture). The emulation is somewhat complete. QEMU emulates the following sun4m peripherals: @@ -1419,13 +1419,14 @@ Floppy drive The number of peripherals is fixed in the architecture. -QEMU uses the Proll, a PROM replacement available at -@url{http://people.redhat.com/@/zaitcev/linux/}. The required -QEMU-specific patches are included with the sources. +Since version 0.8.1, QEMU uses OpenBIOS +@url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable +firmware implementation. The goal is to implement a 100% IEEE +1275-1994 (referred to as Open Firmware) compliant firmware. A sample Linux 2.6 series kernel and ram disk image are available on -the QEMU web site. Please note that currently neither Linux 2.4 -series, NetBSD, nor OpenBSD kernels work. +the QEMU web site. Please note that currently NetBSD, OpenBSD or +Solaris kernels don't work. @c man begin OPTIONS -- cgit v1.2.3 From d8e3326c8efe811d6275a1eaa19d570b1ab66927 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 12:37:30 +0000 Subject: MMU no fault fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1961 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index d011de7fb..982b7fcde 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -190,7 +190,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot /* check access */ access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; error_code = access_table[*access_index][access_perms]; - if (error_code && !(env->mmuregs[0] & MMU_NF)) + if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) return error_code; /* the page can be put in the TLB */ -- cgit v1.2.3 From 55e4f6644e32bfb8fe84c8b8eab95ec5984679cf Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 12:37:58 +0000 Subject: FPU fix (Joerg Platte) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1962 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 8a8620fcf..f2646684c 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -982,6 +982,7 @@ static void disas_sparc_insn(DisasContext * dc) { int cc = GET_FIELD_SP(insn, 20, 21); #if !defined(CONFIG_USER_ONLY) + save_state(dc); gen_op_trap_ifnofpu(); #endif target = GET_FIELD_SP(insn, 0, 18); @@ -1002,6 +1003,7 @@ static void disas_sparc_insn(DisasContext * dc) case 0x6: /* FBN+x */ { #if !defined(CONFIG_USER_ONLY) + save_state(dc); gen_op_trap_ifnofpu(); #endif target = GET_FIELD(insn, 10, 31); @@ -1236,6 +1238,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif } else if (xop == 0x34) { /* FPU Operations */ #if !defined(CONFIG_USER_ONLY) + save_state(dc); gen_op_trap_ifnofpu(); #endif rs1 = GET_FIELD(insn, 13, 17); @@ -1424,6 +1427,7 @@ static void disas_sparc_insn(DisasContext * dc) int cond; #endif #if !defined(CONFIG_USER_ONLY) + save_state(dc); gen_op_trap_ifnofpu(); #endif rs1 = GET_FIELD(insn, 13, 17); @@ -2346,6 +2350,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif } else if (xop >= 0x20 && xop < 0x24) { #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) + save_state(dc); gen_op_trap_ifnofpu(); #endif switch (xop) { -- cgit v1.2.3 From 180b700dc7227d454d30656662912c79ffc3a62f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 12:41:34 +0000 Subject: clock year fix for sparc (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1963 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index 81e64e441..daa1c524d 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -332,7 +332,10 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) tmp = fromBCD(val); if (tmp >= 0 && tmp <= 99) { get_time(NVRAM, &tm); - tm.tm_year = fromBCD(val); + if (NVRAM->type == 8) + tm.tm_year = fromBCD(val) + 68; // Base year is 1968 + else + tm.tm_year = fromBCD(val); set_time(NVRAM, &tm); } break; @@ -421,7 +424,10 @@ uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) case 0x1FFF: /* year */ get_time(NVRAM, &tm); - retval = toBCD(tm.tm_year); + if (NVRAM->type == 8) + retval = toBCD(tm.tm_year - 68); // Base year is 1968 + else + retval = toBCD(tm.tm_year); break; default: /* Check lock registers state */ -- cgit v1.2.3 From 6ea83fedc802c6d678e36c380d72733d89d17bba Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 12:56:19 +0000 Subject: MIPS FPU support (Marius Goeger) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1964 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 + target-mips/cpu.h | 55 +++- target-mips/exec.h | 26 +- target-mips/fop_template.c | 99 +++++++ target-mips/mips-defs.h | 12 +- target-mips/op.c | 485 ++++++++++++++++++++++++++++++++++ target-mips/op_helper.c | 41 +++ target-mips/op_mem.c | 23 ++ target-mips/translate.c | 644 ++++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 1364 insertions(+), 23 deletions(-) create mode 100644 target-mips/fop_template.c diff --git a/configure b/configure index 3672fe087..f9417a6fa 100755 --- a/configure +++ b/configure @@ -819,6 +819,8 @@ 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" ; then echo "TARGET_ARCH=sh4" >> $config_mak echo "#define TARGET_ARCH \"sh4\"" >> $config_h diff --git a/target-mips/cpu.h b/target-mips/cpu.h index af5a97e68..556f0fd96 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -10,10 +10,19 @@ typedef union fpr_t fpr_t; union fpr_t { - double d; - float f; - uint32_t u[2]; + float64 fd; /* ieee double precision */ + float32 fs[2];/* ieee single precision */ + uint64_t d; /* binary single fixed-point */ + uint32_t w[2]; /* binary single fixed-point */ }; +/* define FP_ENDIAN_IDX to access the same location + * in the fpr_t union regardless of the host endianess + */ +#if defined(WORDS_BIGENDIAN) +# define FP_ENDIAN_IDX 1 +#else +# define FP_ENDIAN_IDX 0 +#endif #if defined(MIPS_USES_R4K_TLB) typedef struct tlb_t tlb_t; @@ -44,12 +53,38 @@ struct CPUMIPSState { #if defined(MIPS_USES_FPU) /* Floating point registers */ fpr_t fpr[16]; - /* Floating point special purpose registers */ +#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2]) +#define FPR_FD(cpu, n) (FPR(cpu, n)->fd) +#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX]) +#define FPR_D(cpu, n) (FPR(cpu, n)->d) +#define FPR_W(cpu, n) (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX]) + +#ifndef USE_HOST_FLOAT_REGS + fpr_t ft0; + fpr_t ft1; + fpr_t ft2; +#endif + float_status fp_status; + /* fpu implementation/revision register */ uint32_t fcr0; - uint32_t fcr25; - uint32_t fcr26; - uint32_t fcr28; - uint32_t fcsr; + /* fcsr */ + uint32_t fcr31; +#define SET_FP_COND(reg) do { (reg) |= (1<<23); } while(0) +#define CLEAR_FP_COND(reg) do { (reg) &= ~(1<<23); } while(0) +#define IS_FP_COND_SET(reg) (((reg) & (1<<23)) != 0) +#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) +#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) +#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) +#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 12); } while(0) +#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v) << 7); } while(0) +#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v) << 2); } while(0) +#define FP_INEXACT 1 +#define FP_UNDERFLOW 2 +#define FP_OVERFLOW 4 +#define FP_DIV0 8 +#define FP_INVALID 16 +#define FP_UNIMPLEMENTED 32 + #endif #if defined(MIPS_USES_R4K_TLB) tlb_t tlb[16]; @@ -71,6 +106,7 @@ struct CPUMIPSState { #define CP0St_CU1 29 #define CP0St_CU0 28 #define CP0St_RP 27 +#define CP0St_FR 26 #define CP0St_RE 25 #define CP0St_BEV 22 #define CP0St_TS 21 @@ -138,9 +174,6 @@ struct CPUMIPSState { uint32_t CP0_ErrorEPC; uint32_t CP0_DESAVE; /* Qemu */ -#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU) - double ft0, ft1, ft2; -#endif struct QEMUTimer *timer; /* Internal timer */ int interrupt_request; jmp_buf jmp_env; diff --git a/target-mips/exec.h b/target-mips/exec.h index 2cd1e02c4..93014d6df 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -21,13 +21,20 @@ register host_uint_t T1 asm(AREG2); register host_uint_t T2 asm(AREG3); #if defined (USE_HOST_FLOAT_REGS) -register double FT0 asm(FREG0); -register double FT1 asm(FREG1); -register double FT2 asm(FREG2); +#error "implement me." #else -#define FT0 (env->ft0.d) -#define FT1 (env->ft1.d) -#define FT2 (env->ft2.d) +#define FDT0 (env->ft0.fd) +#define FDT1 (env->ft1.fd) +#define FDT2 (env->ft2.fd) +#define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) +#define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) +#define FST2 (env->ft2.fs[FP_ENDIAN_IDX]) +#define DT0 (env->ft0.d) +#define DT1 (env->ft1.d) +#define DT2 (env->ft2.d) +#define WT0 (env->ft0.w[FP_ENDIAN_IDX]) +#define WT1 (env->ft1.w[FP_ENDIAN_IDX]) +#define WT2 (env->ft2.w[FP_ENDIAN_IDX]) #endif #if defined (DEBUG_OP) @@ -65,6 +72,13 @@ void do_tlbwi (void); void do_tlbwr (void); void do_tlbp (void); void do_tlbr (void); +#ifdef MIPS_USES_FPU +void dump_fpu(CPUState *env); +void fpu_dump_state(CPUState *env, FILE *f, + int (*fpu_fprintf)(FILE *f, const char *fmt, ...), + int flags); +#endif +void dump_sc (void); void do_lwl_raw (uint32_t); void do_lwr_raw (uint32_t); uint32_t do_swl_raw (uint32_t); diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c new file mode 100644 index 000000000..bc0a6e03e --- /dev/null +++ b/target-mips/fop_template.c @@ -0,0 +1,99 @@ +/* + * MIPS emulation micro-operations templates for floating point reg + * load & store for qemu. + * + * Copyright (c) 2006 Marius Groeger + * + * 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(SFREG) + +#define OP_WLOAD_FREG(treg, tregname, SFREG) \ + void glue(glue(op_load_fpr_,tregname), SFREG) (void) \ + { \ + treg = FPR_W(env, SFREG); \ + RETURN(); \ + } + +#define OP_WSTORE_FREG(treg, tregname, SFREG) \ + void glue(glue(op_store_fpr_,tregname), SFREG) (void)\ + { \ + FPR_W(env, SFREG) = treg; \ + RETURN(); \ + } + +/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */ +OP_WLOAD_FREG(WT0, WT0_fpr, SFREG) +/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */ +OP_WSTORE_FREG(WT0, WT0_fpr, SFREG) + +OP_WLOAD_FREG(WT1, WT1_fpr, SFREG) +OP_WSTORE_FREG(WT1, WT1_fpr, SFREG) + +OP_WLOAD_FREG(WT2, WT2_fpr, SFREG) +OP_WSTORE_FREG(WT2, WT2_fpr, SFREG) + +#endif + +#if defined(DFREG) + +#define OP_DLOAD_FREG(treg, tregname, DFREG) \ + void glue(glue(op_load_fpr_,tregname), DFREG) (void) \ + { \ + treg = FPR_D(env, DFREG); \ + RETURN(); \ + } + +#define OP_DSTORE_FREG(treg, tregname, DFREG) \ + void glue(glue(op_store_fpr_,tregname), DFREG) (void)\ + { \ + FPR_D(env, DFREG) = treg; \ + RETURN(); \ + } + +OP_DLOAD_FREG(DT0, DT0_fpr, DFREG) +OP_DSTORE_FREG(DT0, DT0_fpr, DFREG) + +OP_DLOAD_FREG(DT1, DT1_fpr, DFREG) +OP_DSTORE_FREG(DT1, DT1_fpr, DFREG) + +OP_DLOAD_FREG(DT2, DT2_fpr, DFREG) +OP_DSTORE_FREG(DT2, DT2_fpr, DFREG) + +#endif + +#if defined (FTN) + +#define SET_RESET(treg, tregname) \ + void glue(op_set, tregname)(void) \ + { \ + treg = PARAM1; \ + RETURN(); \ + } \ + void glue(op_reset, tregname)(void) \ + { \ + treg = 0; \ + RETURN(); \ + } \ + +SET_RESET(WT0, _WT0) +SET_RESET(WT1, _WT1) +SET_RESET(WT2, _WT2) +SET_RESET(DT0, _DT0) +SET_RESET(DT1, _DT1) +SET_RESET(DT2, _DT2) + +#endif diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 6d28e9cd0..317f6a47f 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -24,6 +24,12 @@ enum { /* Uses MIPS R4Kc TLB model */ #define MIPS_USES_R4K_TLB #define MIPS_TLB_NB 16 +/* basic FPU register support */ +#define MIPS_USES_FPU 1 +/* Define a implementation number of 1. + * Define a major version 1, minor version 0. + */ +#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0) /* Have config1, runs in big-endian mode, uses TLB */ #define MIPS_CONFIG0 \ ((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \ @@ -31,14 +37,14 @@ enum { /* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache, * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, * no performance counters, watch registers present, no code compression, - * EJTAG present, no FPU + * EJTAG present, FPU enable bit depending on MIPS_USES_FPU */ #define MIPS_CONFIG1 \ ((15 << CP0C1_MMU) | \ (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \ (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \ (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \ - (1 << CP0C1_EP) | (0 << CP0C1_FP)) + (1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP)) #elif defined (MIPS_CPU == MIPS_R4Kp) /* 32 bits target */ #define TARGET_LONG_BITS 32 @@ -52,7 +58,7 @@ enum { #error "MIPS CPU not defined" /* Remainder for other flags */ //#define TARGET_MIPS64 -//define MIPS_USES_FPU +//#define MIPS_USES_FPU #endif #endif /* !defined (__QEMU_MIPS_DEFS_H__) */ diff --git a/target-mips/op.c b/target-mips/op.c index 3f9b36462..bc7f81949 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -2,6 +2,7 @@ * MIPS emulation micro-operations for qemu. * * Copyright (c) 2004-2005 Jocelyn Mayer + * Copyright (c) 2006 Marius Groeger (FPU operations) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -149,6 +150,143 @@ CALL_FROM_TB2(func, arg0, arg1); #include "op_template.c" #undef TN +#ifdef MIPS_USES_FPU + +#define SFREG 0 +#define DFREG 0 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 1 +#include "fop_template.c" +#undef SFREG +#define SFREG 2 +#define DFREG 2 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 3 +#include "fop_template.c" +#undef SFREG +#define SFREG 4 +#define DFREG 4 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 5 +#include "fop_template.c" +#undef SFREG +#define SFREG 6 +#define DFREG 6 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 7 +#include "fop_template.c" +#undef SFREG +#define SFREG 8 +#define DFREG 8 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 9 +#include "fop_template.c" +#undef SFREG +#define SFREG 10 +#define DFREG 10 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 11 +#include "fop_template.c" +#undef SFREG +#define SFREG 12 +#define DFREG 12 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 13 +#include "fop_template.c" +#undef SFREG +#define SFREG 14 +#define DFREG 14 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 15 +#include "fop_template.c" +#undef SFREG +#define SFREG 16 +#define DFREG 16 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 17 +#include "fop_template.c" +#undef SFREG +#define SFREG 18 +#define DFREG 18 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 19 +#include "fop_template.c" +#undef SFREG +#define SFREG 20 +#define DFREG 20 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 21 +#include "fop_template.c" +#undef SFREG +#define SFREG 22 +#define DFREG 22 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 23 +#include "fop_template.c" +#undef SFREG +#define SFREG 24 +#define DFREG 24 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 25 +#include "fop_template.c" +#undef SFREG +#define SFREG 26 +#define DFREG 26 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 27 +#include "fop_template.c" +#undef SFREG +#define SFREG 28 +#define DFREG 28 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 29 +#include "fop_template.c" +#undef SFREG +#define SFREG 30 +#define DFREG 30 +#include "fop_template.c" +#undef SFREG +#undef DFREG +#define SFREG 31 +#include "fop_template.c" +#undef SFREG + +#define FTN +#include "fop_template.c" +#undef FTN + +#endif + void op_dup_T0 (void) { T2 = T0; @@ -562,6 +700,353 @@ void op_mtc0 (void) RETURN(); } +#ifdef MIPS_USES_FPU + +#if 0 +# define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) +#else +# define DEBUG_FPU_STATE() do { } while(0) +#endif + +void op_cp1_enabled(void) +{ + if (!(env->CP0_Status & (1 << CP0St_CU1))) { + CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1); + } + RETURN(); +} + +/* CP1 functions */ +void op_cfc1 (void) +{ + if (T1 == 0) { + T0 = env->fcr0; + } + else { + /* fetch fcr31, masking unused bits */ + T0 = env->fcr31 & 0x0183FFFF; + } + DEBUG_FPU_STATE(); + RETURN(); +} + +/* convert MIPS rounding mode in FCR31 to IEEE library */ +unsigned int ieee_rm[] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + +#define RESTORE_ROUNDING_MODE \ + set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) + +void op_ctc1 (void) +{ + if (T1 == 0) { + /* XXX should this throw an exception? + * don't write to FCR0. + * env->fcr0 = T0; + */ + } + else { + /* store new fcr31, masking unused bits */ + env->fcr31 = T0 & 0x0183FFFF; + + /* set rounding mode */ + RESTORE_ROUNDING_MODE; + +#ifndef CONFIG_SOFTFLOAT + /* no floating point exception for native float */ + SET_FP_ENABLE(env->fcr31, 0); +#endif + } + DEBUG_FPU_STATE(); + RETURN(); +} + +void op_mfc1 (void) +{ + T0 = WT0; + DEBUG_FPU_STATE(); + RETURN(); +} + +void op_mtc1 (void) +{ + WT0 = T0; + DEBUG_FPU_STATE(); + RETURN(); +} + +/* Float support. + Single precition routines have a "s" suffix, double precision a + "d" suffix. */ + +#define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) + +FLOAT_OP(cvtd, w) +{ + FDT2 = int32_to_float64(WT0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvts, w) +{ + FST2 = int32_to_float32(WT0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvtw, s) +{ + WT2 = float32_to_int32(FST0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvtw, d) +{ + WT2 = float64_to_int32(FDT0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} + +FLOAT_OP(roundw, d) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(roundw, s) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} + +FLOAT_OP(truncw, d) +{ + WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(truncw, s) +{ + WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} + +FLOAT_OP(ceilw, d) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(ceilw, s) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} + +FLOAT_OP(floorw, d) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(floorw, s) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} + +/* binary operations */ +#define FLOAT_BINOP(name) \ +FLOAT_OP(name, d) \ +{ \ + FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ + DEBUG_FPU_STATE(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ + DEBUG_FPU_STATE(); \ +} +FLOAT_BINOP(add) +FLOAT_BINOP(sub) +FLOAT_BINOP(mul) +FLOAT_BINOP(div) +#undef FLOAT_BINOP + +/* unary operations, modifying fp status */ +#define FLOAT_UNOP(name) \ +FLOAT_OP(name, d) \ +{ \ + FDT2 = float64_ ## name(FDT0, &env->fp_status); \ + DEBUG_FPU_STATE(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + FST2 = float32_ ## name(FST0, &env->fp_status); \ + DEBUG_FPU_STATE(); \ +} +FLOAT_UNOP(sqrt) +#undef FLOAT_UNOP + +/* unary operations, not modifying fp status */ +#define FLOAT_UNOP(name) \ +FLOAT_OP(name, d) \ +{ \ + FDT2 = float64_ ## name(FDT0); \ + DEBUG_FPU_STATE(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + FST2 = float32_ ## name(FST0); \ + DEBUG_FPU_STATE(); \ +} +FLOAT_UNOP(abs) +FLOAT_UNOP(chs) +#undef FLOAT_UNOP + +FLOAT_OP(mov, d) +{ + FDT2 = FDT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(mov, s) +{ + FST2 = FST0; + DEBUG_FPU_STATE(); + RETURN(); +} + +#ifdef CONFIG_SOFTFLOAT +#define clear_invalid() do { \ + int flags = get_float_exception_flags(&env->fp_status); \ + flags &= ~float_flag_invalid; \ + set_float_exception_flags(flags, &env->fp_status); \ +} while(0) +#else +#define clear_invalid() do { } while(0) +#endif + +extern void dump_fpu_s(CPUState *env); + +#define FOP_COND(fmt, op, sig, cond) \ +void op_cmp_ ## fmt ## _ ## op (void) \ +{ \ + if (cond) \ + SET_FP_COND(env->fcr31); \ + else \ + CLEAR_FP_COND(env->fcr31); \ + if (!sig) \ + clear_invalid(); \ + /*CALL_FROM_TB1(dump_fpu_s, env);*/ \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} + +flag float64_is_unordered(float64 a, float64 b STATUS_PARAM) +{ + extern flag float64_is_nan( float64 a ); + if (float64_is_nan(a) || float64_is_nan(b)) { + float_raise(float_flag_invalid, status); + return 1; + } + else { + return 0; + } +} + +FOP_COND(d, f, 0, 0) +FOP_COND(d, un, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status)) +FOP_COND(d, eq, 0, float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, olt, 0, float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, ole, 0, float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, ule, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called + */ +FOP_COND(d, sf, 1, (float64_is_unordered(FDT0, FDT1, &env->fp_status), 0)) +FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status)) +FOP_COND(d, seq, 1, float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, lt, 1, float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, le, 1, float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) + +flag float32_is_unordered(float32 a, float32 b STATUS_PARAM) +{ + extern flag float32_is_nan( float32 a ); + if (float32_is_nan(a) || float32_is_nan(b)) { + float_raise(float_flag_invalid, status); + return 1; + } + else { + return 0; + } +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called + */ +FOP_COND(s, f, 0, 0) +FOP_COND(s, un, 0, float32_is_unordered(FST1, FST0, &env->fp_status)) +FOP_COND(s, eq, 0, float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND(s, olt, 0, float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND(s, ole, 0, float32_le(FST0, FST1, &env->fp_status)) +FOP_COND(s, ule, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called + */ +FOP_COND(s, sf, 1, (float32_is_unordered(FST0, FST1, &env->fp_status), 0)) +FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status)) +FOP_COND(s, seq, 1, float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND(s, lt, 1, float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND(s, le, 1, float32_le(FST0, FST1, &env->fp_status)) +FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) + +void op_bc1f (void) +{ + T0 = ! IS_FP_COND_SET(env->fcr31); + DEBUG_FPU_STATE(); + RETURN(); +} + +void op_bc1t (void) +{ + T0 = IS_FP_COND_SET(env->fcr31); + DEBUG_FPU_STATE(); + RETURN(); +} +#endif /* MIPS_USES_FPU */ + #if defined(MIPS_USES_R4K_TLB) void op_tlbwi (void) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index fbd693fb2..37f260430 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -529,6 +529,47 @@ void do_mtc0 (int reg, int sel) return; } +#ifdef MIPS_USES_FPU +#include "softfloat.h" + +void fpu_handle_exception(void) +{ +#ifdef CONFIG_SOFTFLOAT + int flags = get_float_exception_flags(&env->fp_status); + unsigned int cpuflags = 0, enable, cause = 0; + + enable = GET_FP_ENABLE(env->fcr31); + + /* determine current flags */ + if (flags & float_flag_invalid) { + cpuflags |= FP_INVALID; + cause |= FP_INVALID & enable; + } + if (flags & float_flag_divbyzero) { + cpuflags |= FP_DIV0; + cause |= FP_DIV0 & enable; + } + if (flags & float_flag_overflow) { + cpuflags |= FP_OVERFLOW; + cause |= FP_OVERFLOW & enable; + } + if (flags & float_flag_underflow) { + cpuflags |= FP_UNDERFLOW; + cause |= FP_UNDERFLOW & enable; + } + if (flags & float_flag_inexact) { + cpuflags |= FP_INEXACT; + cause |= FP_INEXACT & enable; + } + SET_FP_FLAGS(env->fcr31, cpuflags); + SET_FP_CAUSE(env->fcr31, cause); +#else + SET_FP_FLAGS(env->fcr31, 0); + SET_FP_CAUSE(env->fcr31, 0); +#endif +} +#endif /* MIPS_USES_FPU */ + /* TLB management */ #if defined(MIPS_USES_R4K_TLB) static void invalidate_tlb (int idx) diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 7fcfc24a6..b5308bea5 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -118,3 +118,26 @@ void glue(op_sc, MEMSUFFIX) (void) } RETURN(); } + +#ifdef MIPS_USES_FPU +void glue(op_lwc1, MEMSUFFIX) (void) +{ + WT0 = glue(ldl, MEMSUFFIX)(T0); + RETURN(); +} +void glue(op_swc1, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)(T0, WT0); + RETURN(); +} +void glue(op_ldc1, MEMSUFFIX) (void) +{ + DT0 = glue(ldq, MEMSUFFIX)(T0); + RETURN(); +} +void glue(op_sdc1, MEMSUFFIX) (void) +{ + glue(stq, MEMSUFFIX)(T0, DT0); + RETURN(); +} +#endif diff --git a/target-mips/translate.c b/target-mips/translate.c index 4df691c88..fcee08747 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2,6 +2,7 @@ * MIPS32 emulation for qemu: main translation routines. * * Copyright (c) 2004-2005 Jocelyn Mayer + * Copyright (c) 2006 Marius Groeger (FPU operations) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -217,6 +218,16 @@ enum { OPC_WAIT = 0x20 | EXT_CP0, }; +#ifdef MIPS_USES_FPU +enum { + /* Coprocessor 1 (FPU) */ + OPC_MFC1 = 0x00 | EXT_CP1, + OPC_MTC1 = 0x04 | EXT_CP1, + OPC_CFC1 = 0x02 | EXT_CP1, + OPC_CTC1 = 0x06 | EXT_CP1, +}; +#endif + const unsigned char *regnames[] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", @@ -248,6 +259,92 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); +#ifdef MIPS_USES_FPU +const unsigned char *fregnames[] = + { "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", }; + +# define SFGEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} + +# define DFGEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = { \ +NAME ## 0, 0, NAME ## 2, 0, \ +NAME ## 4, 0, NAME ## 6, 0, \ +NAME ## 8, 0, NAME ## 10, 0, \ +NAME ## 12, 0, NAME ## 14, 0, \ +NAME ## 16, 0, NAME ## 18, 0, \ +NAME ## 20, 0, NAME ## 22, 0, \ +NAME ## 24, 0, NAME ## 26, 0, \ +NAME ## 28, 0, NAME ## 30, 0, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} + +SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); +SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); + +SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); +SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); + +SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); +SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); + +DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); +DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); + +DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); +DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); + +DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); +DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); + +#define FOP_CONDS(fmt) \ +static GenOpFunc * cond_ ## fmt ## _table[16] = { \ + gen_op_cmp_ ## fmt ## _f, \ + gen_op_cmp_ ## fmt ## _un, \ + gen_op_cmp_ ## fmt ## _eq, \ + gen_op_cmp_ ## fmt ## _ueq, \ + gen_op_cmp_ ## fmt ## _olt, \ + gen_op_cmp_ ## fmt ## _ult, \ + gen_op_cmp_ ## fmt ## _ole, \ + gen_op_cmp_ ## fmt ## _ule, \ + gen_op_cmp_ ## fmt ## _sf, \ + gen_op_cmp_ ## fmt ## _ngle, \ + gen_op_cmp_ ## fmt ## _seq, \ + gen_op_cmp_ ## fmt ## _ngl, \ + gen_op_cmp_ ## fmt ## _lt, \ + gen_op_cmp_ ## fmt ## _nge, \ + gen_op_cmp_ ## fmt ## _le, \ + gen_op_cmp_ ## fmt ## _ngt, \ +}; \ +static inline void gen_cmp_ ## fmt(int n) \ +{ \ + cond_ ## fmt ## _table[n](); \ +} + +FOP_CONDS(d) +FOP_CONDS(s) + +#endif + typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; @@ -312,6 +409,20 @@ do { \ } \ } while (0) +#ifdef MIPS_USES_FPU + +# define GEN_LOAD_FREG_FTN(FTn, Fn) \ +do { \ + glue(gen_op_load_fpr_, FTn)(Fn); \ +} while (0) + +#define GEN_STORE_FTN_FREG(Fn, FTn) \ +do { \ + glue(gen_op_store_fpr_, FTn)(Fn); \ +} while (0) + +#endif + static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) { #if defined MIPS_DEBUG_DISAS @@ -397,6 +508,12 @@ OP_LD_TABLE(bu); OP_ST_TABLE(b); OP_LD_TABLE(l); OP_ST_TABLE(c); +#ifdef MIPS_USES_FPU +OP_LD_TABLE(wc1); +OP_ST_TABLE(wc1); +OP_LD_TABLE(dc1); +OP_ST_TABLE(dc1); +#endif /* Load and store */ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, @@ -551,6 +668,56 @@ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); } +#ifdef MIPS_USES_FPU + +/* Load and store */ +static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft, + int base, int16_t offset) +{ + const unsigned char *opn = "unk"; + + if (base == 0) { + GEN_LOAD_IMM_TN(T0, offset); + } else if (offset == 0) { + gen_op_load_gpr_T0(base); + } else { + gen_op_load_gpr_T0(base); + gen_op_set_T1(offset); + gen_op_add(); + } + /* Don't do NOP if destination is zero: we must perform the actual + * memory access + */ + switch (opc) { + case OPC_LWC1: + op_ldst(lwc1); + GEN_STORE_FTN_FREG(ft, WT0); + opn = "lwc1"; + break; + case OPC_SWC1: + GEN_LOAD_FREG_FTN(WT0, ft); + op_ldst(swc1); + opn = "swc1"; + break; + case OPC_LDC1: + op_ldst(ldc1); + GEN_STORE_FTN_FREG(ft, DT0); + opn = "ldc1"; + break; + case OPC_SDC1: + GEN_LOAD_FREG_FTN(DT0, ft); + op_ldst(sdc1); + opn = "sdc1"; + break; + default: + MIPS_INVAL("float load/store"); + generate_exception(ctx, EXCP_CpU); + return; + } + MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); +} +#endif + /* Arithmetic with immediate operand */ static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, int rs, int16_t imm) @@ -1265,7 +1432,406 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); } +#ifdef MIPS_USES_FPU +/* CP1 Branches (before delay slot) */ +static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond, + int32_t offset) +{ + target_ulong btarget; + + btarget = ctx->pc + 4 + offset; + + switch (cond) { + case 0x0000: /* bc1f */ + gen_op_bc1f(); + MIPS_DEBUG("bc1f %08x", btarget); + goto not_likely; + case 0x0002: /* bc1fl */ + gen_op_bc1f(); + MIPS_DEBUG("bc1fl %08x", btarget); + goto likely; + case 0x0001: /* bc1t */ + gen_op_bc1t(); + MIPS_DEBUG("bc1t %08x", btarget); + not_likely: + ctx->hflags |= MIPS_HFLAG_BC; + break; + case 0x0003: /* bc1tl */ + gen_op_bc1t(); + MIPS_DEBUG("bc1tl %08x", btarget); + likely: + ctx->hflags |= MIPS_HFLAG_BL; + break; + default: + MIPS_INVAL("cp1 branch/jump"); + generate_exception(ctx, EXCP_RI); + return; + } + gen_op_set_bcond(); + + MIPS_DEBUG("enter ds: cond %02x target %08x", + ctx->hflags, btarget); + ctx->btarget = btarget; + + return; +} + /* Coprocessor 1 (FPU) */ +static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) +{ + const unsigned char *opn = "unk"; + + switch (opc) { + case OPC_MFC1: + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_mfc1(); + GEN_STORE_TN_REG(rt, T0); + opn = "mfc1"; + break; + case OPC_MTC1: + GEN_LOAD_REG_TN(T0, rt); + gen_op_mtc1(); + GEN_STORE_FTN_FREG(fs, WT0); + opn = "mtc1"; + break; + case OPC_CFC1: + if (fs != 0 && fs != 31) { + MIPS_INVAL("cfc1 freg"); + generate_exception(ctx, EXCP_RI); + return; + } + GEN_LOAD_IMM_TN(T1, fs); + gen_op_cfc1(); + GEN_STORE_TN_REG(rt, T0); + opn = "cfc1"; + break; + case OPC_CTC1: + if (fs != 0 && fs != 31) { + MIPS_INVAL("ctc1 freg"); + generate_exception(ctx, EXCP_RI); + return; + } + GEN_LOAD_IMM_TN(T1, fs); + GEN_LOAD_REG_TN(T0, rt); + gen_op_ctc1(); + opn = "ctc1"; + break; + default: + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", + ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, + ((ctx->opcode >> 16) & 0x1F)); + } + generate_exception(ctx, EXCP_RI); + return; + } + MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); +} + +/* verify if floating point register is valid; an operation is not defined + * if bit 0 of any register specification is set and the FR bit in the + * Status register equals zero, since the register numbers specify an + * even-odd pair of adjacent coprocessor general registers. When the FR bit + * in the Status register equals one, both even and odd register numbers + * are valid. + * + * Multiple float registers can be checked by calling + * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); + */ +#define CHECK_FR(ctx, freg) do { \ + if (!((ctx)->CP0_Status & (1<opcode & FOP(0x3f, 0x1f)) { + case FOP(0, 17): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + gen_op_float_add_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "add.d"; + binary = 1; + break; + case FOP(1, 17): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + gen_op_float_sub_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "sub.d"; + binary = 1; + break; + case FOP(2, 17): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + gen_op_float_mul_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "mul.d"; + binary = 1; + break; + case FOP(3, 17): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + gen_op_float_div_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "div.d"; + binary = 1; + break; + case FOP(4, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_sqrt_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "sqrt.d"; + break; + case FOP(5, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_abs_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "abs.d"; + break; + case FOP(6, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_mov_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "mov.d"; + break; + case FOP(7, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_chs_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "neg.d"; + break; + /* 8 - round.l */ + /* 9 - trunc.l */ + /* 10 - ceil.l */ + /* 11 - floor.l */ + case FOP(12, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_roundw_d(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "round.w.d"; + break; + case FOP(13, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_truncw_d(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "trunc.w.d"; + break; + case FOP(14, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_ceilw_d(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "ceil.w.d"; + break; + case FOP(15, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_floorw_d(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "ceil.w.d"; + break; + case FOP(33, 20): /* cvt.d.w */ + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvtd_w(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "cvt.d.w"; + break; + case FOP(48, 17): + case FOP(49, 17): + case FOP(50, 17): + case FOP(51, 17): + case FOP(52, 17): + case FOP(53, 17): + case FOP(54, 17): + case FOP(55, 17): + case FOP(56, 17): + case FOP(57, 17): + case FOP(58, 17): + case FOP(59, 17): + case FOP(60, 17): + case FOP(61, 17): + case FOP(62, 17): + case FOP(63, 17): + CHECK_FR(ctx, fs | ft); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + gen_cmp_d(func-48); + opn = condnames[func-48]; + break; + case FOP(0, 16): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_add_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "add.s"; + binary = 1; + break; + case FOP(1, 16): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_sub_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "sub.s"; + binary = 1; + break; + case FOP(2, 16): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_mul_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "mul.s"; + binary = 1; + break; + case FOP(3, 16): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_div_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "div.s"; + binary = 1; + break; + case FOP(4, 16): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_sqrt_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "sqrt.s"; + break; + case FOP(5, 16): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_abs_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "abs.s"; + break; + case FOP(6, 16): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_mov_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "mov.s"; + break; + case FOP(7, 16): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_chs_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "neg.s"; + break; + case FOP(12, 16): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_roundw_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "round.w.s"; + break; + case FOP(13, 16): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_truncw_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "trunc.w.s"; + break; + case FOP(32, 20): /* cvt.s.w */ + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvts_w(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "cvt.s.w"; + break; + case FOP(36, 16): /* cvt.w.s */ + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvtw_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "cvt.w.s"; + break; + case FOP(36, 17): /* cvt.w.d */ + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvtw_d(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "cvt.w.d"; + break; + case FOP(48, 16): + case FOP(49, 16): + case FOP(50, 16): + case FOP(51, 16): + case FOP(52, 16): + case FOP(53, 16): + case FOP(54, 16): + case FOP(55, 16): + case FOP(56, 16): + case FOP(57, 16): + case FOP(58, 16): + case FOP(59, 16): + case FOP(60, 16): + case FOP(61, 16): + case FOP(62, 16): + case FOP(63, 16): + CHECK_FR(ctx, fs | ft); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_cmp_s(func-48); + opn = condnames[func-48]; + break; + default: + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n", + ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, + ((ctx->opcode >> 16) & 0x1F)); + } + generate_exception(ctx, EXCP_RI); + return; + } + if (binary) + MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]); + else + MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]); +} +#endif /* ISA extensions */ /* MIPS16 extension to MIPS32 */ @@ -1495,9 +2061,39 @@ static void decode_opc (DisasContext *ctx) case 0x35: /* LDC1 */ case 0x39: /* SWC1 */ case 0x3D: /* SDC1 */ +#if defined(MIPS_USES_FPU) + gen_op_cp1_enabled(); + gen_flt_ldst(ctx, op, rt, rs, imm); +#else + generate_exception_err(ctx, EXCP_CpU, 1); +#endif + break; + case 0x11: /* CP1 opcode */ #if defined(MIPS_USES_FPU) - /* XXX: not correct */ + gen_op_cp1_enabled(); + op1 = ((ctx->opcode >> 21) & 0x1F); + switch (op1) { + case 0x00: /* mfc1 */ + case 0x02: /* cfc1 */ + case 0x04: /* mtc1 */ + case 0x06: /* ctc1 */ + gen_cp1(ctx, op1 | EXT_CP1, rt, rd); + break; + case 0x08: /* bc */ + gen_compute_branch1(ctx, rt, imm << 2); + return; + case 0x10: /* 16: fmt=single fp */ + case 0x11: /* 17: fmt=double fp */ + case 0x14: /* 20: fmt=32bit fixed */ + case 0x15: /* 21: fmt=64bit fixed */ + gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f); + break; + default: + generate_exception_err(ctx, EXCP_RI, 1); + break; + } + break; #else generate_exception_err(ctx, EXCP_CpU, 1); #endif @@ -1586,7 +2182,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int j, lj = -1; if (search_pc && loglevel) - fprintf (logfile, "search pc %d\n", search_pc); + fprintf (logfile, "search pc %d\n", search_pc); pc_start = tb->pc; gen_opc_ptr = gen_opc_buf; @@ -1696,7 +2292,7 @@ done_generating: #endif if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, ctx.pc - pc_start, 0); + target_disas(logfile, pc_start, ctx.pc - pc_start, 0); fprintf(logfile, "\n"); } if (loglevel & CPU_LOG_TB_OP) { @@ -1722,6 +2318,42 @@ int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } +#ifdef MIPS_USES_FPU +void fpu_dump_state(CPUState *env, FILE *f, + int (*fpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; + +# define printfpr(fp) do { \ + fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \ + (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \ + } while(0) + + fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n", + env->fcr0, env->fcr31, + (env->CP0_Status & (1<ft0); + fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); + fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); + for(i=0; i < 32; i+=2) { + fpu_fprintf(f, "f%02d: ", i); + printfpr(FPR(env, i)); + } + +#undef printfpr +} + +void dump_fpu(CPUState *env) +{ + if (loglevel) { + fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n", + env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); + fpu_dump_state(env, logfile, fprintf, 0); + } +} +#endif /* MIPS_USES_FPU */ + void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -1751,6 +2383,9 @@ void cpu_dump_state (CPUState *env, FILE *f, c0_status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n", env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); +#ifdef MIPS_USES_FPU + fpu_dump_state(env, f, cpu_fprintf, flags); +#endif } CPUMIPSState *cpu_mips_init (void) @@ -1787,6 +2422,9 @@ CPUMIPSState *cpu_mips_init (void) env->exception_index = EXCP_NONE; #if defined(CONFIG_USER_ONLY) env->hflags |= MIPS_HFLAG_UM; +#endif +#ifdef MIPS_USES_FPU + env->fcr0 = MIPS_FCR0; #endif return env; } -- cgit v1.2.3 From 5b9053a5ea29f51a6058a5ce76daee6f80efb0b2 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 12:57:01 +0000 Subject: remove proll git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1965 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/proll.patch | 4067 --------------------------------------------------- 1 file changed, 4067 deletions(-) delete mode 100644 pc-bios/proll.patch diff --git a/pc-bios/proll.patch b/pc-bios/proll.patch deleted file mode 100644 index dbe01e432..000000000 --- a/pc-bios/proll.patch +++ /dev/null @@ -1,4067 +0,0 @@ -diff -ruN proll_18.orig/Makefile proll-patch-15/Makefile ---- proll_18.orig/Makefile 2002-09-13 14:16:59.000000000 +0000 -+++ proll-patch-15/Makefile 2005-11-09 18:14:51.000000000 +0000 -@@ -4,6 +4,7 @@ - make -C krups-ser all - make -C espresso all - make -C espresso-ser all -+ make -C qemu all - - clean: - make -C mrcoffee clean -@@ -11,3 +12,4 @@ - make -C krups-ser clean - make -C espresso clean - make -C espresso-ser clean -+ make -C qemu clean -diff -ruN proll_18.orig/qemu/Makefile proll-patch-15/qemu/Makefile ---- proll_18.orig/qemu/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/Makefile 2005-08-14 10:25:06.000000000 +0000 -@@ -0,0 +1,123 @@ -+# -+# proll: -+# qemu/Makefile - make PROLL for QEMU -+# $Id: proll.patch,v 1.6 2005-11-11 00:24:57 bellard Exp $ -+# -+# Copyright 1999 Pete Zaitcev -+# This is Free Software is licensed under terms of GNU General Public License. -+# -+ -+CC = gcc -+ -+#CROSS = /usr/local/sparc/bin/sparc-sun-linux- -+CROSS = sparc-unknown-linux-gnu- -+ -+CROSSCC = $(CROSS)gcc -+CROSSLD = $(CROSS)ld -+CROSSNM = $(CROSS)nm -+ -+RM = /bin/rm -f -+ELFTOAOUT = elftoaout -+ -+# -+SRC = ../src -+ -+# Due to remapping algorithm PROLBASE should be algned on PMD. -+# We make PROLBASE a define instead of using _start because we -+# want to shift it to form a PGD entry. A relocatable label will not work. -+# Linux kernel expects us to be at LINUX_OPPROM_BEGVM . -+PROLBASE = 0xffd00000 -+PROLRODATA = 0xffd08000 -+PROLDATA = 0xffd0b000 -+PROLSIZE = 240*1024 -+ -+# Linux -+# Fixed %g6 is for arch/sparc/kernel/head.S, it seems ok w/o -ffixed-g6. -+# Kernel uses -fcall-used-g5 -fcall-used-g7, we probably do not need them. -+# __ANSI__ is supposed to be on by default but it is not. -+CFLAGS = -O2 -W -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -Wa,-xarch=v8 -g -DQEMU -m32 -fno-builtin -+ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g -Wa,-xarch=v8 -Wa,-32 -+# Solaris or Linux/i386 cross compilation -+#CFLAGS = -Iinclude -O -+ -+LDFLAGS = -N -Ttext $(PROLBASE) --section-start .rodata=$(PROLRODATA) -Tdata $(PROLDATA) -Tbss $(PROLDATA) -+ -+ALL = proll.aout -+PROLLEXE = proll.elf -+ -+OBJS = head.o wuf.o wof.o main.o $(CONSOLE) \ -+ printf.o le.o system_qemu.o iommu.o \ -+ arp.o netinit.o bootp.o packet.o tftp.o udp.o sched_4m.o openprom.o \ -+ vconsole.o hconsole.o rconsole.o vcons_zs.o esp.o -+ -+all: $(ALL) -+ -+$(PROLLEXE): $(OBJS) -+ $(CROSSLD) $(LDFLAGS) -o $(PROLLEXE) $(OBJS) -+ -+head.o: head.S $(SRC)/phys_jj.h \ -+ $(SRC)/asi.h $(SRC)/psr.h $(SRC)/crs.h -+ $(CROSSCC) $(ASFLAGS) -DPROLBASE=$(PROLBASE) -o $*.o -c $*.S -+ -+main.o: main.c $(SRC)/asi.h $(SRC)/pgtsrmmu.h $(SRC)/iommu.h \ -+ $(SRC)/phys_jj.h $(SRC)/vconsole.h $(SRC)/version.h $(SRC)/general.h \ -+ $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h -+ $(CROSSCC) $(CFLAGS) -c $*.c -+openprom.o: openprom.c $(SRC)/openprom.h $(SRC)/general.h $(SRC)/romlib.h \ -+ $(SRC)/vconsole.h $(SRC)/system.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $*.c -+ -+system_qemu.o: system_qemu.c $(SRC)/vconsole.h $(SRC)/pgtsrmmu.h \ -+ $(SRC)/timer.h $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/asi.h \ -+ $(SRC)/netpriv.h $(SRC)/arpa.h $(SRC)/system.h $(SRC)/crs.h -+ $(CROSSCC) $(CFLAGS) -c $*.c -+iommu.o: $(SRC)/iommu.c $(SRC)/pgtsrmmu.h $(SRC)/phys_jj.h $(SRC)/iommu.h \ -+ $(SRC)/vconsole.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/asi.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+vconsole.o: $(SRC)/vconsole.c $(SRC)/vconsole.h $(SRC)/hconsole.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+vcons_zs.o: $(SRC)/vcons_zs.c $(SRC)/vconsole.h $(SRC)/system.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+hconsole.o: $(SRC)/hconsole.c $(SRC)/hconsole.h $(SRC)/rconsole.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+rconsole.o: $(SRC)/rconsole.c $(SRC)/rconsole.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+printf.o: $(SRC)/printf.c -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+le.o: $(SRC)/le.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/netpriv.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/net.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+esp.o: $(SRC)/esp.c $(SRC)/dma.h $(SRC)/system.h $(SRC)/romlib.h $(SRC)/general.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+arp.o: $(SRC)/arp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+netinit.o: $(SRC)/netinit.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+tftp.o: $(SRC)/tftp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/tftp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+udp.o: $(SRC)/udp.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h $(SRC)/arp.h $(SRC)/ip.h $(SRC)/udp.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+packet.o: $(SRC)/packet.c $(SRC)/general.h $(SRC)/net.h $(SRC)/romlib.h $(SRC)/netpriv.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+sched_4m.o: $(SRC)/sched_4m.c $(SRC)/system.h $(SRC)/general.h $(SRC)/romlib.h $(SRC)/phys_jj.h -+ $(CROSSCC) $(CFLAGS) -c $(SRC)/$*.c -+bootp.o: $(SRC)/bootp.c $(SRC)/general.h $(SRC)/net.h \ -+ $(SRC)/arpa.h $(SRC)/romlib.h $(SRC)/system.h $(SRC)/bootp.h -+ $(CROSSCC) $(CFLAGS) -DNOBPEXT=1 -c $(SRC)/$*.c -+ -+wuf.o: $(SRC)/wuf.S -+ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S -+wof.o: $(SRC)/wof.S -+ $(CROSSCC) $(ASFLAGS) -o $*.o -c $(SRC)/$*.S -+ -+#genlab.o: genlab.c -+# $(CC) -c $*.c -+# -+#genlab: genlab.o -+# $(CC) -o genlab genlab.o -+ -+clean: -+ $(RM) $(OBJS) -+ $(RM) $(PROLLEXE) proll.aout -+ -+proll.aout: $(PROLLEXE) -+ $(ELFTOAOUT) -o proll.aout $(PROLLEXE) -diff -ruN proll_18.orig/qemu/head.S proll-patch-15/qemu/head.S ---- proll_18.orig/qemu/head.S 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/head.S 2005-07-12 22:24:17.000000000 +0000 -@@ -0,0 +1,543 @@ -+/** -+ ** Standalone startup code for Linux PROM emulator. -+ ** Copyright 1999 Pete A. Zaitcev -+ ** This code is licensed under GNU General Public License. -+ **/ -+/* -+ * $Id: proll.patch,v 1.6 2005-11-11 00:24:57 bellard Exp $ -+ */ -+ -+#include -+#include -+#include -+/* #include */ /* Trap entries. Do not use. */ -+#include "phys_jj.h" -+ -+#define C_LABEL(name) name -+#define REGWIN_SZ 0x40 -+ -+#define WRITE_PAUSE nop; nop; nop; /* Have to do this after %wim/%psr chg */ -+ -+ /* 22 is 24-2, (va)>>(SRMMU_PGDIR_SHIFT-PTESIZESHFT) */ -+#define VATOPGDOFF(va) (((va)>>22)&0x3FC) -+#define VATOPMDOFF(va) (((va)>>16)&0xFC) -+ -+#define NOP_INSN 0x01000000 /* Used to patch sparc_save_state */ -+ -+/* Here are some trap goodies */ -+ -+#if 0 -+/* Generic trap entry. */ -+#define TRAP_ENTRY(type, label) \ -+ rd %psr, %l0; b label; rd %wim, %l3; nop; -+#endif -+ -+/* Data/text faults. */ -+#define SRMMU_TFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 1, %l7; -+#define SRMMU_DFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 0, %l7; -+ -+#if 0 -+/* This is for traps we should NEVER get. */ -+#define BAD_TRAP(num) \ -+ rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3; -+ -+/* This is for traps when we want just skip the instruction which caused it */ -+#define SKIP_TRAP(type, name) \ -+ jmpl %l2, %g0; rett %l2 + 4; nop; nop; -+ -+/* Notice that for the system calls we pull a trick. We load up a -+ * different pointer to the system call vector table in %l7, but call -+ * the same generic system call low-level entry point. The trap table -+ * entry sequences are also HyperSparc pipeline friendly ;-) -+ */ -+ -+/* Software trap for Linux system calls. */ -+#define LINUX_SYSCALL_TRAP \ -+ sethi %hi(C_LABEL(sys_call_table)), %l7; \ -+ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ -+ b linux_sparc_syscall; \ -+ rd %psr, %l0; -+ -+/* Software trap for SunOS4.1.x system calls. */ -+#define SUNOS_SYSCALL_TRAP \ -+ rd %psr, %l0; \ -+ sethi %hi(C_LABEL(sunos_sys_table)), %l7; \ -+ b linux_sparc_syscall; \ -+ or %l7, %lo(C_LABEL(sunos_sys_table)), %l7; -+ -+/* Software trap for Slowaris system calls. */ -+#define SOLARIS_SYSCALL_TRAP \ -+ b solaris_syscall; \ -+ rd %psr, %l0; \ -+ nop; \ -+ nop; -+ -+#define INDIRECT_SOLARIS_SYSCALL(x) \ -+ mov x, %g1; \ -+ b solaris_syscall; \ -+ rd %psr, %l0; \ -+ nop; -+ -+#define BREAKPOINT_TRAP \ -+ b breakpoint_trap; \ -+ rd %psr,%l0; \ -+ nop; \ -+ nop; -+ -+/* Software trap for Sparc-netbsd system calls. */ -+#define NETBSD_SYSCALL_TRAP \ -+ sethi %hi(C_LABEL(sys_call_table)), %l7; \ -+ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ -+ b bsd_syscall; \ -+ rd %psr, %l0; -+ -+/* The Get Condition Codes software trap for userland. */ -+#define GETCC_TRAP \ -+ b getcc_trap_handler; mov %psr, %l0; nop; nop; -+ -+/* The Set Condition Codes software trap for userland. */ -+#define SETCC_TRAP \ -+ b setcc_trap_handler; mov %psr, %l0; nop; nop; -+ -+/* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and -+ * gets handled with another macro. -+ */ -+#define TRAP_ENTRY_INTERRUPT(int_level) \ -+ mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3; -+ -+/* NMI's (Non Maskable Interrupts) are special, you can't keep them -+ * from coming in, and basically if you get one, the shows over. ;( -+ * On the sun4c they are usually asynchronous memory errors, on the -+ * the sun4m they could be either due to mem errors or a software -+ * initiated interrupt from the prom/kern on an SMP box saying "I -+ * command you to do CPU tricks, read your mailbox for more info." -+ */ -+#define NMI_TRAP \ -+ rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop; -+ -+#endif -+ -+/* Window overflows/underflows are special and we need to try to be as -+ * efficient as possible here.... -+ */ -+#define WINDOW_SPILL \ -+ rd %psr, %l0; rd %wim, %l3; b spill_window_entry; nop; -+ -+#define WINDOW_FILL \ -+ rd %psr, %l0; rd %wim, %l3; b fill_window_entry; nop; -+ -+#define STUB_TRAP ba stub_trap; nop; nop; nop; -+ -+#define TRAP_ENTRY(a,b) STUB_TRAP -+#define SKIP_TRAP(a,b) STUB_TRAP -+#define SUNOS_SYSCALL_TRAP STUB_TRAP -+#define SOLARIS_SYSCALL_TRAP STUB_TRAP -+#define NETBSD_SYSCALL_TRAP STUB_TRAP -+#define LINUX_SYSCALL_TRAP STUB_TRAP -+#define BREAKPOINT_TRAP STUB_TRAP -+#define NMI_TRAP STUB_TRAP -+#define GETCC_TRAP STUB_TRAP -+#define SETCC_TRAP STUB_TRAP -+#define BAD_TRAP(n) STUB_TRAP -+#define TRAP_ENTRY_INTERRUPT(i) STUB_TRAP -+#define INDIRECT_SOLARIS_SYSCALL(i) STUB_TRAP -+ -+ .section ".text" -+ .globl start, _start -+_start: -+start: -+ .globl spill_window_entry, fill_window_entry -+ -+#define EXPORT_TRAP(trap) \ -+ .globl trap; \ -+ .type trap,function; \ -+ .size trap, 16 -+ -+EXPORT_TRAP(t_zero) -+EXPORT_TRAP(t_wovf) -+EXPORT_TRAP(t_wunf) -+EXPORT_TRAP(t_irq1) -+EXPORT_TRAP(t_irq2) -+EXPORT_TRAP(t_irq3) -+EXPORT_TRAP(t_irq4) -+EXPORT_TRAP(t_irq5) -+EXPORT_TRAP(t_irq6) -+EXPORT_TRAP(t_irq7) -+EXPORT_TRAP(t_irq8) -+EXPORT_TRAP(t_irq9) -+EXPORT_TRAP(t_irq10) -+EXPORT_TRAP(t_irq11) -+EXPORT_TRAP(t_irq12) -+EXPORT_TRAP(t_irq13) -+EXPORT_TRAP(t_irq14) -+EXPORT_TRAP(t_irq15) -+ -+C_LABEL(trapbase): -+t_zero: b goprol; nop; nop; nop; -+t_tflt: SRMMU_TFAULT /* Inst. Access Exception */ -+t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ -+t_pins: TRAP_ENTRY(0x3, priv_instruction) /* Privileged Instruction */ -+t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ -+t_wovf: WINDOW_SPILL /* Window Overflow */ -+t_wunf: WINDOW_FILL /* Window Underflow */ -+t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ -+t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ -+t_dflt: SRMMU_DFAULT /* Data Miss Exception */ -+t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ -+t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ -+t_badc: BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) -+t_irq1: TRAP_ENTRY_INTERRUPT(1) /* IRQ Software/SBUS Level 1 */ -+t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ -+t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ -+t_irq4: TRAP_ENTRY_INTERRUPT(4) /* IRQ Software Level 4 */ -+t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ -+t_irq6: TRAP_ENTRY_INTERRUPT(6) /* IRQ Software Level 6 */ -+t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ -+t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ -+t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ -+t_irq10:TRAP_ENTRY_INTERRUPT(10) /* IRQ Timer #1 (one we use) */ -+t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ -+t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ -+t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ -+t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ -+t_nmi: NMI_TRAP /* Level 15 (NMI) */ -+t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ -+t_iacce:BAD_TRAP(0x21) /* Instr Access Error */ -+t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23) -+t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ -+t_uflsh:SKIP_TRAP(0x25, unimp_flush) /* Unimplemented FLUSH inst. */ -+t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27) -+t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ -+t_dacce:SRMMU_DFAULT /* Data Access Error */ -+t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ -+t_dserr:BAD_TRAP(0x2b) /* Data Store Error */ -+t_daccm:BAD_TRAP(0x2c) /* Data Access MMU-Miss */ -+t_bad2d: BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) -+ BAD_TRAP(0x30) BAD_TRAP(0x31) BAD_TRAP(0x32) BAD_TRAP(0x33) -+ BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) BAD_TRAP(0x37) -+ BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) -+t_iaccm:BAD_TRAP(0x3c) /* Instr Access MMU-Miss */ -+ BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) -+ BAD_TRAP(0x40) BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) -+ BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46) BAD_TRAP(0x47) -+ BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b) -+ BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) -+ BAD_TRAP(0x50) BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) -+ BAD_TRAP(0x54) BAD_TRAP(0x55) BAD_TRAP(0x56) BAD_TRAP(0x57) -+ BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) BAD_TRAP(0x5b) -+ BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) -+ BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) -+ BAD_TRAP(0x64) BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) -+ BAD_TRAP(0x68) BAD_TRAP(0x69) BAD_TRAP(0x6a) BAD_TRAP(0x6b) -+ BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) BAD_TRAP(0x6f) -+ BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) -+ BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) -+ BAD_TRAP(0x78) BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) -+ BAD_TRAP(0x7c) BAD_TRAP(0x7d) BAD_TRAP(0x7e) BAD_TRAP(0x7f) -+t_sunos:SUNOS_SYSCALL_TRAP /* SunOS System Call */ -+t_sbkpt:BREAKPOINT_TRAP /* Software Breakpoint/KGDB */ -+t_divz: BAD_TRAP(0x82) /* Divide by zero trap */ -+t_flwin:TRAP_ENTRY(0x83, do_flush_windows) /* Flush Windows Trap */ -+t_clwin:BAD_TRAP(0x84) /* Clean Windows Trap */ -+t_rchk: BAD_TRAP(0x85) /* Range Check */ -+t_funal:BAD_TRAP(0x86) /* Fix Unaligned Access Trap */ -+t_iovf: BAD_TRAP(0x87) /* Integer Overflow Trap */ -+t_slowl:SOLARIS_SYSCALL_TRAP /* Slowaris System Call */ -+t_netbs:NETBSD_SYSCALL_TRAP /* Net-B.S. System Call */ -+t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) -+ BAD_TRAP(0x8e) BAD_TRAP(0x8f) -+t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ -+t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) -+ BAD_TRAP(0x94) BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) -+ BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) -+t_getcc:GETCC_TRAP /* Get Condition Codes */ -+t_setcc:SETCC_TRAP /* Set Condition Codes */ -+t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3) -+ BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) -+t_slowi:INDIRECT_SOLARIS_SYSCALL(156) -+ BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) -+ BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) -+ BAD_TRAP(0xb0) BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) -+ BAD_TRAP(0xb4) BAD_TRAP(0xb5) BAD_TRAP(0xb6) BAD_TRAP(0xb7) -+ BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) BAD_TRAP(0xbb) -+ BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) -+t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) -+ BAD_TRAP(0xc4) BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) -+ BAD_TRAP(0xc8) BAD_TRAP(0xc9) BAD_TRAP(0xca) BAD_TRAP(0xcb) -+ BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) BAD_TRAP(0xcf) -+ BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) -+t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) -+ BAD_TRAP(0xd8) BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) -+ BAD_TRAP(0xdc) BAD_TRAP(0xdd) BAD_TRAP(0xde) BAD_TRAP(0xdf) -+ BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) BAD_TRAP(0xe3) -+ BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) -+t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) -+ BAD_TRAP(0xec) BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) -+ BAD_TRAP(0xf0) BAD_TRAP(0xf1) BAD_TRAP(0xf2) BAD_TRAP(0xf3) -+ BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) BAD_TRAP(0xf7) -+ BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) -+t_badfc:BAD_TRAP(0xfc) BAD_TRAP(0xfd) -+dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */ -+dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */ -+ -+stub_trap: -+ set (PHYS_JJ_TCX_FB + 0xbf0), %g5 /* 2 cells from side */ -+ set 0x00ffffff, %g4 -+ sta %g4, [%g5] ASI_M_BYPASS -+1: ba 1b; nop -+ -+ .section ".bss" -+ .align 8 -+bss_start: -+ .align 0x1000 ! PAGE_SIZE -+ .globl C_LABEL(bootup_user_stack) -+ .type bootup_user_stack,#object -+ .size bootup_user_stack,0x2000 -+C_LABEL(bootup_user_stack): .skip 0x2000 -+ -+ .section ".text" -+ .register %g2, #scratch -+ .register %g3, #scratch -+ .register %g6, #scratch -+ .register %g7, #scratch -+ -+goprol: -+ ! %g1 contains end of memory -+ set PHYS_JJ_EEPROM + 0x30, %g1 -+ lda [%g1] ASI_M_BYPASS, %g1 -+ ! map PROLDATA to PROLBASE+PROLSIZE to end of ram -+ set PROLSIZE+0x1000-PROLDATA+PROLBASE, %g2 ! add 0x1000 for temp tables -+ sub %g1, %g2, %g2 ! start of private memory -+ srl %g2, 0x4, %g7 ! ctx table at s+0x0 -+ add %g2, 0x400, %g3 ! l1 table at s+0x400 -+ srl %g3, 0x4, %g3 -+ or %g3, 0x1, %g3 -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x400, %g2 ! s+0x400 -+ add %g2, 0x800, %g3 ! l2 table for ram (00xxxxxx) at s+0x800 -+ srl %g3, 0x4, %g3 -+ or %g3, 0x1, %g3 -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x500, %g3 ! l2 table for rom (ffxxxxxx) at s+0x900 -+ add %g2, 0x3fc, %g2 ! s+0x7fc -+ srl %g3, 0x4, %g3 -+ or %g3, 0x1, %g3 -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x4, %g2 ! s+0x800 -+ set ((7 << 2) | 2), %g3 ! 7 = U: --- S: RWX (main memory) -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x200, %g3 ! l3 table for rom at s+0xa00 -+ add %g2, 0x1d0, %g2 ! s+0x9d0 -+ srl %g3, 0x4, %g3 -+ or %g3, 0x1, %g3 -+ sta %g3, [%g2] ASI_M_BYPASS -+ add %g2, 0x30, %g2 ! s+0xa00 -+ -+ set PROLBASE, %g3 -+ set 0x1000, %g5 -+ set (PROLDATA-PROLBASE)/0x1000, %g6 ! # of .text pages -+1: srl %g3, 0x4, %g4 -+ or %g4, ((7 << 2) | 2), %g4 ! 4 = U: --X S: --X (rom, execute only) -+ sta %g4, [%g2] ASI_M_BYPASS -+ add %g2, 4, %g2 -+ add %g3, %g5, %g3 -+ deccc %g6 -+ bne 1b -+ nop -+#if 0 -+ set (PROLDATA-PROLRODATA)/0x1000, %g6 ! # of .rodata pages -+1: srl %g3, 0x4, %g4 -+ or %g4, ((0 << 2) | 2), %g4 ! 0 = U: R-- S: R-- (rom, read only) -+ sta %g4, [%g2] ASI_M_BYPASS -+ add %g2, 4, %g2 -+ add %g3, %g5, %g3 -+ deccc %g6 -+ bne 1b -+ nop -+#endif -+ set (PROLBASE+PROLSIZE-PROLDATA)/0x1000, %g6 ! # of .bss pages -+ set 0x1000, %g4 -+ sll %g7, 0x4, %g3 -+ add %g4, %g3, %g3 -+1: srl %g3, 0x4, %g4 -+ or %g4, ((7 << 2) | 2), %g4 ! 5 = U: R-- S: RW- (data area, read/write) -+ sta %g4, [%g2] ASI_M_BYPASS -+ add %g2, 4, %g2 -+ add %g3, %g5, %g3 -+ deccc %g6 -+ bne 1b -+ nop -+ -+ mov %g1, %g3 -+ -+ set AC_M_CTPR, %g2 -+ sta %g7, [%g2] ASI_M_MMUREGS ! set ctx table ptr -+ set 1, %g1 -+ sta %g1, [%g0] ASI_M_MMUREGS ! enable mmu -+ -+ /* -+ * The code which enables traps is a simplified version of -+ * kernel head.S. -+ * -+ * We know number of windows as 8 so we do not calculate them. -+ * The deadwood is here for any case. -+ */ -+ -+ /* Turn on Supervisor, EnableFloating, and all the PIL bits. -+ * Also puts us in register window zero with traps off. -+ */ -+ set (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 -+ wr %g2, 0x0, %psr -+ WRITE_PAUSE -+ -+ /* I want a kernel stack NOW! */ -+ set C_LABEL(bootup_user_stack), %g1 -+ set (0x2000 - REGWIN_SZ), %g2 -+ add %g1, %g2, %sp -+ mov 0, %fp /* And for good luck */ -+ -+ /* Zero out our BSS section. */ -+ set C_LABEL(bss_start) , %o0 ! First address of BSS -+ set C_LABEL(end) , %o1 ! Last address of BSS -+ ba 2f -+ nop -+1: -+ st %g0, [%o0] -+2: -+ subcc %o0, %o1, %g0 -+ bl 1b -+ add %o0, 0x4, %o0 -+ -+ mov 2, %g1 -+ wr %g1, 0x0, %wim ! make window 1 invalid -+ WRITE_PAUSE -+ -+#if 0 -+ wr %g0, 0x0, %wim -+ WRITE_PAUSE -+ save -+ rd %psr, %g3 -+ restore -+ and %g3, PSR_CWP, %g3 -+ add %g3, 0x1, %g3 -+#else -+ or %g0, 8, %g3 -+#endif -+ -+#if 0 -+ sethi %hi( C_LABEL(cputyp) ), %o0 -+ st %g7, [%o0 + %lo( C_LABEL(cputyp) )] -+ -+ sethi %hi( C_LABEL(nwindows) ), %g4 -+ st %g3, [%g4 + %lo( C_LABEL(nwindows) )] -+ -+ sub %g3, 0x1, %g3 -+ sethi %hi( C_LABEL(nwindowsm1) ), %g4 -+ st %g3, [%g4 + %lo( C_LABEL(nwindowsm1) )] -+#endif -+ -+ /* Here we go, start using Linux's trap table... */ -+ set C_LABEL(trapbase), %g3 -+ wr %g3, 0x0, %tbr -+ WRITE_PAUSE -+ -+ /* Finally, turn on traps so that we can call c-code. */ -+ rd %psr, %g3 -+ wr %g3, 0x0, %psr -+ WRITE_PAUSE -+ -+ wr %g3, PSR_ET, %psr -+ WRITE_PAUSE -+ -+ .globl prolmain -+ call C_LABEL(prolmain) -+ nop -+ -+3: -+ b 3b -+ nop -+ -+/* -+ * Memory access trap handler -+ * %l0 program %psr from trap table entry -+ * %l1 program %pc from hardware -+ * %l2 program %npc from hardware -+ * %l3 program %wim from trap table entry -+ * %l4 -+ * %l5 -+ * %l6 -+ * %l7 text flag from trap table entry -+ */ -+ -+ .section ".text" -+ .globl srmmu_fault -+C_LABEL(srmmu_fault): -+ -+ set AC_M_SFAR, %l6 -+ set AC_M_SFSR, %l5 -+ lda [%l6] ASI_M_MMUREGS, %l6 -+ lda [%l5] ASI_M_MMUREGS, %l5 -+ -+ set ignore_fault, %l5 -+ ld [%l5], %l5 -+ subcc %l5, %g0, %g0 /* NULL pointer trap faults always */ -+ be 3f -+ nop -+ subcc %l5, %l6, %g0 -+ be 2f -+ nop -+3: -+ -+ set (PHYS_JJ_TCX_FB + 0xbf0), %g5 /* 2 cells from side */ -+ set 0x00ffffff, %g4 -+ sta %g4, [%g5] ASI_M_BYPASS -+ add %g5, 8, %g5 /* On right side */ -+ sta %g4, [%g5] ASI_M_BYPASS -+1: ba 1b; nop -+ -+2: -+ set C_LABEL(fault_ignored), %l5 -+ mov 1, %l6 -+ st %l6, [%l5] -+ -+ /* -+ * Skip the faulting instruction. -+ * I think it works when next instruction is a branch even. -+ */ -+ or %l2, 0, %l1 -+ add %l2, 4, %l2 -+ -+ wr %l0, 0, %psr -+ WRITE_PAUSE -+ jmp %l1 -+ rett %l2 -+ -+/* -+ * Slow external versions of st_bypass and ld_bypass. -+ * rconsole.c uses inlines. We call these in places which are not speed -+ * critical, to avoid compiler bugs. -+ */ -+ .globl C_LABEL(st_bypass) -+C_LABEL(st_bypass): -+ retl -+ sta %o1, [%o0] ASI_M_BYPASS -+ .globl C_LABEL(ld_bypass) -+C_LABEL(ld_bypass): -+ retl -+ lda [%o0] ASI_M_BYPASS, %o0 -+ .globl C_LABEL(sth_bypass) -+C_LABEL(sth_bypass): -+ retl -+ stha %o1, [%o0] ASI_M_BYPASS -+ .globl C_LABEL(ldh_bypass) -+C_LABEL(ldh_bypass): -+ retl -+ lduha [%o0] ASI_M_BYPASS, %o0 -+ .globl C_LABEL(stb_bypass) -+C_LABEL(stb_bypass): -+ retl -+ stba %o1, [%o0] ASI_M_BYPASS -+ .globl C_LABEL(ldb_bypass) -+C_LABEL(ldb_bypass): -+ retl -+ lduba [%o0] ASI_M_BYPASS, %o0 -diff -ruN proll_18.orig/qemu/main.c proll-patch-15/qemu/main.c ---- proll_18.orig/qemu/main.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/main.c 2005-08-14 10:07:48.000000000 +0000 -@@ -0,0 +1,185 @@ -+/** -+ ** Proll (PROM replacement) -+ ** Copyright 1999 Pete Zaitcev -+ ** This code is licensed under GNU General Public License. -+ **/ -+#include -+ -+// #include -+#include -+#include "pgtsrmmu.h" -+#include "iommu.h" /* Typical SBus IOMMU for sun4m */ -+#include "phys_jj.h" -+#include "vconsole.h" -+#include "version.h" -+#include /* __P() */ -+#include /* init_net() */ -+#include /* we are a provider for part of this. */ -+#include /* myipaddr */ -+#include -+#include /* our own prototypes */ -+ -+void *init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, const char *cmdline, char boot_device, int nographic); -+int vcon_zs_init(struct vconterm *t, unsigned int a0); -+int vcon_zs_write(struct vconterm *t, char *data, int leng); -+int vcon_zs_getch(struct vconterm *t); -+void esp_probe(); -+int esp_boot(int unit); -+static void init_idprom(void); -+ -+struct vconterm dp0; -+struct mem cmem; /* Current memory, virtual */ -+struct mem cio; /* Current I/O space */ -+struct phym pmem; /* Current phys. mem. */ -+struct iommu ciommu; /* Our IOMMU on sun4m */ -+ -+static struct { -+ const char id[16]; -+ unsigned int version; -+ char pad1[0x1c]; // Pad to 0x30 -+ unsigned int ram_size; -+ char boot_device; -+ unsigned int load_addr, kernel_size; -+ unsigned int cmdline, cmdline_len; -+ char pad2[0x0c]; // Pad to 0x54 -+ unsigned short width, height, depth; -+} *hw_idprom; -+ -+int ignore_fault, fault_ignored; -+void *printk_fn, *getch_fn; -+unsigned int q_height, q_width; -+ -+/* -+ */ -+void prolmain() -+{ -+ static char fname[14]; -+ static struct banks bb; -+ unsigned int hiphybas; -+ const void *romvec; -+ unsigned int ram_size; -+ char nographic, bootdev; -+ -+ nographic = ldb_bypass(PHYS_JJ_EEPROM + 0x2F); -+ if (!nographic) { -+ q_width = ldh_bypass(PHYS_JJ_EEPROM + 0x54); -+ q_height = ldh_bypass(PHYS_JJ_EEPROM + 0x56); -+ vcon_init(&dp0, PHYS_JJ_TCX_FB); -+ printk_fn = vcon_write; -+ getch_fn = vcon_getch; -+ } -+ else { -+ vcon_zs_init(&dp0, 0x71100004); -+ printk_fn = vcon_zs_write; -+ getch_fn = vcon_zs_getch; -+ } -+ -+ -+ printk("PROLL %s QEMU\n", PROLL_VERSION_STRING); -+ ram_size = ld_bypass(PHYS_JJ_EEPROM + 0x30); -+ printk("%d MB total\n", ram_size/(1024*1024)); -+ -+ bb.nbanks = 1; -+ bb.bankv[0].start = 0; -+ bb.bankv[0].length = ram_size; -+ -+ hiphybas = ram_size - PROLSIZE; -+ -+ mem_init(&cmem, (char *) &_end, (char *)(PROLBASE+PROLSIZE)); -+ makepages(&pmem, hiphybas); -+ init_mmu_swift((unsigned int)pmem.pctp - PROLBASE + hiphybas); -+ -+ mem_init(&cio, (char *)(PROLBASE+PROLSIZE), -+ (char *)(PROLBASE+PROLSIZE+IOMAPSIZE)); -+ -+ iommu_init(&ciommu, hiphybas); -+ -+ /* -+ */ -+ init_idprom(); -+ printk("NVRAM: id %s version %d\n", hw_idprom->id, hw_idprom->version); -+ if (!nographic) -+ printk("Prom console: TCX %dx%d\n", q_width, q_height); -+ else -+ printk("Prom console: serial\n"); -+ sched_init(); -+ le_probe(); -+ init_net(); -+ esp_probe(); -+ -+ bootdev = hw_idprom->boot_device; -+ printk("Boot device: %c\n", bootdev); -+ if (hw_idprom->kernel_size > 0) { -+ printk("Kernel already loaded\n"); -+ } else if (bootdev == 'n') { -+ if (bootp() != 0) fatal(); -+ /* -+ * boot_rec.bp_file cannot be used because system PROM -+ * uses it to locate ourselves. If we load from boot_rec.bp_file, -+ * we will loop reloading PROLL over and over again. -+ * Thus we use traditional PROLL scheme HEXIPADDR.PROL (single L). -+ */ -+ xtoa(myipaddr, fname, 8); -+ fname[9] = '.'; -+ fname[10] = 'P'; -+ fname[11] = 'R'; -+ fname[12] = 'O'; -+ fname[13] = 'L'; -+ fname[14] = 0; -+ -+ if (load(boot_rec.bp_siaddr, fname) != 0) fatal(); -+ } else if (bootdev == 'c') { -+ if (esp_boot(0) != 0) fatal(); -+ } else if (bootdev == 'd') { -+ if (esp_boot(2) != 0) fatal(); -+ } -+ -+ romvec = init_openprom_qemu(bb.nbanks, bb.bankv, hiphybas, -+ (void *)hw_idprom->cmdline, hw_idprom->boot_device, nographic); -+ -+ printk("Memory used: virt 0x%x:0x%x[%dK] iomap 0x%x:0x%x\n", -+ PROLBASE, (int)cmem.curp, ((unsigned) cmem.curp - PROLBASE)/1024, -+ (int)cio.start, (int)cio.curp); -+ -+ { -+ void (*entry)(const void *, int, int, int, int) = (void *) hw_idprom->load_addr; -+ printk("Kernel loaded at 0x%x, size %dK, command line = '%s'\n", -+ *entry, hw_idprom->kernel_size/1024, hw_idprom->cmdline); -+ entry(romvec, 0, 0, 0, 0); -+ } -+ -+ mem_fini(&cmem); -+ vcon_fini(&dp0); -+} -+ -+/* -+ * dvma_alloc over iommu_alloc. -+ */ -+void *dvma_alloc(int size, unsigned int *pphys) -+{ -+ return iommu_alloc(&ciommu, size, pphys); -+} -+ -+/* -+ */ -+void udelay(__attribute__((unused)) unsigned long usecs) -+{ -+ // Qemu hardware is perfect and does not need any delays! -+} -+ -+static void init_idprom() -+{ -+ void *va_prom; -+ -+ if ((va_prom = map_io(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE)) == NULL) { -+ printk("init_idprom: cannot map eeprom\n"); -+ fatal(); -+ } -+ bcopy(va_prom + PHYS_JJ_IDPROM_OFF, idprom, IDPROM_SIZE); -+ /* -+ * hw_idprom is not used anywhere. -+ * It's just as we hate to leave hanging pointers (I/O page here). -+ */ -+ hw_idprom = va_prom; -+} -+ -diff -ruN proll_18.orig/qemu/openprom.c proll-patch-15/qemu/openprom.c ---- proll_18.orig/qemu/openprom.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/openprom.c 2005-11-07 20:11:04.000000000 +0000 -@@ -0,0 +1,910 @@ -+/* -+ * PROM interface support -+ * Copyright 1996 The Australian National University. -+ * Copyright 1996 Fujitsu Laboratories Limited -+ * Copyright 1999 Pete A. Zaitcev -+ * This software may be distributed under the terms of the Gnu -+ * Public License version 2 or later -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "phys_jj.h" -+ -+//#define DEBUG_OBP -+ -+#define PAGE_SIZE 4096 -+ -+struct property { -+ const char *name; -+ const char *value; -+ int length; -+}; -+ -+struct node { -+ const struct property *properties; -+ /* short */ const int sibling; -+ /* short */ const int child; -+}; -+ -+static int obp_nextnode(int node); -+static int obp_child(int node); -+static int obp_proplen(int node, char *name); -+static int obp_getprop(int node, char *name, char *val); -+static int obp_setprop(int node, char *name, char *val, int len); -+static const char *obp_nextprop(int node, char *name); -+ -+static char obp_idprom[IDPROM_SIZE]; -+static const struct property null_properties = { NULL, NULL, -1 }; -+static const int prop_true = -1; -+ -+static struct property propv_root[7]; -+ -+static const struct property propv_root_templ[] = { -+ {"name", "SUNW,SparcStation-5", sizeof("SUNW,SparcStation-5") }, -+ {"idprom", obp_idprom, IDPROM_SIZE}, -+ {"banner-name", "SparcStation", sizeof("SparcStation")}, -+ {"compatible", "sun4m", 6}, -+}; -+ -+static const int prop_iommu_reg[] = { -+ 0x0, 0x10000000, 0x00000300, -+}; -+static const struct property propv_iommu[] = { -+ {"name", "iommu", sizeof("iommu")}, -+ {"reg", (char*)&prop_iommu_reg[0], sizeof(prop_iommu_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_sbus_ranges[] = { -+ 0x0, 0x0, 0x0, 0x30000000, 0x10000000, -+ 0x1, 0x0, 0x0, 0x40000000, 0x10000000, -+ 0x2, 0x0, 0x0, 0x50000000, 0x10000000, -+ 0x3, 0x0, 0x0, 0x60000000, 0x10000000, -+ 0x4, 0x0, 0x0, 0x70000000, 0x10000000, -+}; -+static const struct property propv_sbus[] = { -+ {"name", "sbus", 5}, -+ {"ranges", (char*)&prop_sbus_ranges[0], sizeof(prop_sbus_ranges)}, -+ {"device_type", "hierarchical", sizeof("hierarchical") }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_tcx_regs[] = { -+ 0x2, 0x00800000, 0x00100000, -+ 0x2, 0x02000000, 0x00000001, -+ 0x2, 0x04000000, 0x00800000, -+ 0x2, 0x06000000, 0x00800000, -+ 0x2, 0x0a000000, 0x00000001, -+ 0x2, 0x0c000000, 0x00000001, -+ 0x2, 0x0e000000, 0x00000001, -+ 0x2, 0x00700000, 0x00001000, -+ 0x2, 0x00200000, 0x00000004, -+ 0x2, 0x00300000, 0x0000081c, -+ 0x2, 0x00000000, 0x00010000, -+ 0x2, 0x00240000, 0x00000004, -+ 0x2, 0x00280000, 0x00000001, -+}; -+ -+#if 1 /* Zaitcev */ -+static const int pixfreq = 0x03dfd240; -+static const int hbporch = 0xa0; -+static const int vfreq = 0x3c; -+#endif -+#if 0 /* Kevin Boone - 70Hz refresh */ -+static const int pixfreq = 0x047868C0; -+static const int hbporch = 0x90; -+static const int vfreq = 0x46; -+#endif -+ -+static const int vbporch = 0x1d; -+static const int vsync = 0x6; -+static const int hsync = 0x88; -+static const int vfporch = 0x3; -+static const int hfporch = 0x18; -+static const int height = 0x300; -+static const int width = 0x400; -+static const int linebytes = 0x400; -+static const int depth = 24; -+static const int tcx_intr[] = { 5, 0 }; -+static const int tcx_interrupts = 5; -+static const struct property propv_sbus_tcx[] = { -+ {"name", "SUNW,tcx", sizeof("SUNW,tcx")}, -+ {"vbporch", (char*)&vbporch, sizeof(int)}, -+ {"hbporch", (char*)&hbporch, sizeof(int)}, -+ {"vsync", (char*)&vsync, sizeof(int)}, -+ {"hsync", (char*)&hsync, sizeof(int)}, -+ {"vfporch", (char*)&vfporch, sizeof(int)}, -+ {"hfporch", (char*)&hfporch, sizeof(int)}, -+ {"pixfreq", (char*)&pixfreq, sizeof(int)}, -+ {"vfreq", (char*)&vfreq, sizeof(int)}, -+ {"height", (char*)&height, sizeof(int)}, -+ {"width", (char*)&width, sizeof(int)}, -+ {"linebytes", (char*)&linebytes, sizeof(int)}, -+ {"depth", (char*)&depth, sizeof(int)}, -+ {"reg", (char*)&prop_tcx_regs[0], sizeof(prop_tcx_regs)}, -+ {"tcx-8-bit", 0, -1}, -+ {"intr", (char*)&tcx_intr[0], sizeof(tcx_intr)}, -+ {"interrupts", (char*)&tcx_interrupts, sizeof(tcx_interrupts)}, -+ {"device_type", "display", sizeof("display")}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_cs4231_reg[] = { -+ 0x3, 0x0C000000, 0x00000040 -+}; -+static const int cs4231_interrupts = 5; -+static const int cs4231_intr[] = { 5, 0 }; -+ -+static const struct property propv_sbus_cs4231[] = { -+ {"name", "SUNW,CS4231", sizeof("SUNW,CS4231") }, -+ {"intr", (char*)&cs4231_intr[0], sizeof(cs4231_intr) }, -+ {"interrupts", (char*)&cs4231_interrupts, sizeof(cs4231_interrupts) }, -+ {"reg", (char*)&prop_cs4231_reg[0], sizeof(prop_cs4231_reg) }, -+ {"device_type", "serial", sizeof("serial") }, -+ {"alias", "audio", sizeof("audio") }, -+ {NULL, NULL, -1} -+}; -+ -+static const int cpu_nctx = NCTX_SWIFT; -+static const int cpu_cache_line_size = 0x20; -+static const int cpu_cache_nlines = 0x200; -+static const struct property propv_cpu[] = { -+ {"name", "STP1012PGA", sizeof("STP1012PGA") }, -+ {"device_type", "cpu", 4 }, -+ {"mmu-nctx", (char*)&cpu_nctx, sizeof(int)}, -+ {"cache-line-size", (char*)&cpu_cache_line_size, sizeof(int)}, -+ {"cache-nlines", (char*)&cpu_cache_nlines, sizeof(int)}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_obio_ranges[] = { -+ 0x0, 0x0, 0x0, 0x71000000, 0x01000000, -+}; -+static const struct property propv_obio[] = { -+ {"name", "obio", 5 }, -+ {"ranges", (char*)&prop_obio_ranges[0], sizeof(prop_obio_ranges) }, -+ {"device_type", "hierarchical", sizeof("hierarchical") }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_auxio_reg[] = { -+ 0x0, 0x00900000, 0x00000001, -+}; -+static const struct property propv_obio_auxio[] = { -+ {"name", "auxio", sizeof("auxio") }, -+ {"reg", (char*)&prop_auxio_reg[0], sizeof(prop_auxio_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_int_reg[] = { -+ 0x0, 0x00e00000, 0x00000010, -+ 0x0, 0x00e10000, 0x00000010, -+}; -+static const struct property propv_obio_int[] = { -+ {"name", "interrupt", sizeof("interrupt")}, -+ {"reg", (char*)&prop_int_reg[0], sizeof(prop_int_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_cnt_reg[] = { -+ 0x0, 0x00d00000, 0x00000010, -+ 0x0, 0x00d10000, 0x00000010, -+}; -+static const struct property propv_obio_cnt[] = { -+ {"name", "counter", sizeof("counter")}, -+ {"reg", (char*)&prop_cnt_reg[0], sizeof(prop_cnt_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_eeprom_reg[] = { -+ 0x0, 0x00200000, 0x00002000, -+}; -+static const struct property propv_obio_eep[] = { -+ {"name", "eeprom", sizeof("eeprom")}, -+ {"reg", (char*)&prop_eeprom_reg[0], sizeof(prop_eeprom_reg) }, -+ {"model", "mk48t08", sizeof("mk48t08")}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_su_reg[] = { -+ 0x0, 0x003002f8, 0x00000008, -+}; -+static const struct property propv_obio_su[] = { -+ {"name", "su", sizeof("su")}, -+ {"reg", (char*)&prop_su_reg[0], sizeof(prop_su_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_zs_intr[] = { 0x2c, 0x0 }; -+static const int prop_zs_reg[] = { -+ 0x0, 0x00000000, 0x00000008, -+}; -+static void *prop_zs_addr; -+static const int prop_zs_slave = 1; -+static const struct property propv_obio_zs[] = { -+ {"name", "zs", sizeof("zs")}, -+ {"reg", (char*)&prop_zs_reg[0], sizeof(prop_zs_reg) }, -+ {"slave", (char*)&prop_zs_slave, sizeof(prop_zs_slave) }, -+ {"device_type", "serial", sizeof("serial") }, -+ {"intr", (char*)&prop_zs_intr[0], sizeof(prop_zs_intr) }, -+ {"address", (char*)&prop_zs_addr, sizeof(prop_zs_addr) }, -+ {"keyboard", (char*)&prop_true, 0}, -+ {"mouse", (char*)&prop_true, 0}, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_zs1_intr[] = { 0x2c, 0x0 }; -+static const int prop_zs1_reg[] = { -+ 0x0, 0x00100000, 0x00000008, -+}; -+static void *prop_zs1_addr; -+static const int prop_zs1_slave = 0; -+static const struct property propv_obio_zs1[] = { -+ {"name", "zs", sizeof("zs")}, -+ {"reg", (char*)&prop_zs1_reg[0], sizeof(prop_zs1_reg) }, -+ {"slave", (char*)&prop_zs1_slave, sizeof(prop_zs1_slave) }, -+ {"device_type", "serial", sizeof("serial") }, -+ {"intr", (char*)&prop_zs1_intr[0], sizeof(prop_zs1_intr) }, -+ {"address", (char*)&prop_zs1_addr, sizeof(prop_zs1_addr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_ledma_reg[] = { -+ 0x4, 0x08400010, 0x00000020, -+}; -+static const int prop_ledma_burst = 0x3f; -+static const struct property propv_sbus_ledma[] = { -+ {"name", "ledma", sizeof("ledma")}, -+ {"reg", (char*)&prop_ledma_reg[0], sizeof(prop_ledma_reg) }, -+ {"burst-sizes", (char*)&prop_ledma_burst, sizeof(int) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_le_reg[] = { -+ 0x4, 0x08c00000, 0x00000004, -+}; -+static const int prop_le_busmaster_regval = 0x7; -+static const int prop_le_intr[] = { 0x26, 0x0 }; -+static const struct property propv_sbus_ledma_le[] = { -+ {"name", "le", sizeof("le")}, -+ {"reg", (char*)&prop_le_reg[0], sizeof(prop_le_reg) }, -+ {"busmaster-regval", (char*)&prop_le_busmaster_regval, sizeof(int)}, -+ {"intr", (char*)&prop_le_intr[0], sizeof(prop_le_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_espdma_reg[] = { -+ 0x4, 0x08400000, 0x00000010, -+}; -+ -+static const struct property propv_sbus_espdma[] = { -+ {"name", "espdma", sizeof("espdma")}, -+ {"reg", (char*)&prop_espdma_reg[0], sizeof(prop_espdma_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_esp_reg[] = { -+ 0x4, 0x08800000, 0x00000040, -+}; -+static const int prop_esp_intr[] = { 0x24, 0x0 }; -+static const struct property propv_sbus_espdma_esp[] = { -+ {"name", "esp", sizeof("esp")}, -+ {"reg", (char*)&prop_esp_reg[0], sizeof(prop_esp_reg) }, -+ {"intr", (char*)&prop_esp_intr[0], sizeof(prop_esp_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_bpp_reg[] = { -+ 0x4, 0x0c800000, 0x0000001c, -+}; -+static const int prop_bpp_intr[] = { 0x33, 0x0 }; -+static const struct property propv_sbus_bpp[] = { -+ {"name", "SUNW,bpp", sizeof("SUNW,bpp")}, -+ {"reg", (char*)&prop_bpp_reg[0], sizeof(prop_bpp_reg) }, -+ {"intr", (char*)&prop_bpp_intr[0], sizeof(prop_bpp_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_apc_reg[] = { -+ 0x4, 0x0a000000, 0x00000010, -+}; -+static const struct property propv_sbus_apc[] = { -+ {"name", "xxxpower-management", sizeof("xxxpower-management")}, -+ {"reg", (char*)&prop_apc_reg[0], sizeof(prop_apc_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_fd_intr[] = { 0x2b, 0x0 }; -+static const int prop_fd_reg[] = { -+ 0x0, 0x00400000, 0x0000000f, -+}; -+static const struct property propv_obio_fd[] = { -+ {"name", "SUNW,fdtwo", sizeof("SUNW,fdtwo")}, -+ {"reg", (char*)&prop_fd_reg[0], sizeof(prop_fd_reg) }, -+ {"device_type", "block", sizeof("block") }, -+ {"intr", (char*)&prop_fd_intr[0], sizeof(prop_fd_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_pw_intr[] = { 0x22, 0x0 }; -+static const int prop_pw_reg[] = { -+ 0x0, 0x00910000, 0x00000001, -+}; -+static const struct property propv_obio_pw[] = { -+ {"name", "power", sizeof("power")}, -+ {"reg", (char*)&prop_pw_reg[0], sizeof(prop_pw_reg) }, -+ {"intr", (char*)&prop_pw_intr[0], sizeof(prop_pw_intr) }, -+ {NULL, NULL, -1} -+}; -+ -+static const int prop_cf_reg[] = { -+ 0x0, 0x00800000, 0x00000001, -+}; -+static const struct property propv_obio_cf[] = { -+ {"name", "slavioconfig", sizeof("slavioconfig")}, -+ {"reg", (char*)&prop_cf_reg[0], sizeof(prop_cf_reg) }, -+ {NULL, NULL, -1} -+}; -+ -+static const struct property propv_options[] = { -+ {"name", "options", sizeof("options")}, -+ {"screen-#columns", "80", sizeof("80")}, -+ {"screen-#rows", "25", sizeof("25")}, -+ {"tpe-link-test?", (char *)&prop_true, 0}, -+ {"ttya-mode", "9600,8,n,1,-", sizeof("9600,8,n,1,-")}, -+ {"ttya-ignore-cd", (char *)&prop_true, 0}, -+ {"ttya-rts-dtr-off", 0, -1}, -+ {"ttyb-mode", "9600,8,n,1,-", sizeof("9600,8,n,1,-")}, -+ {"ttyb-ignore-cd", (char *)&prop_true, 0}, -+ {"ttyb-rts-dtr-off", 0, -1}, -+ {NULL, NULL, -1} -+}; -+ -+static int prop_mem_reg[3]; -+static int prop_mem_avail[3]; -+ -+static const struct property propv_memory[] = { -+ {"name", "memory", sizeof("memory")}, -+ {"reg", (char*)&prop_mem_reg[0], sizeof(prop_mem_reg) }, -+ {"available", (char*)&prop_mem_avail[0], sizeof(prop_mem_avail) }, -+ {NULL, NULL, -1} -+}; -+ -+static int prop_vmem_avail[6]; -+ -+static const struct property propv_vmemory[] = { -+ {"name", "virtual-memory", sizeof("virtual-memory")}, -+ {"available", (char*)&prop_vmem_avail[0], sizeof(prop_vmem_avail) }, -+ {NULL, NULL, -1} -+}; -+ -+static const struct node nodes[] = { -+ { &null_properties, 1, 0 }, /* 0 = big brother of root */ -+ { propv_root, 0, 2 }, /* 1 "/" */ -+ { propv_iommu, 12, 3 }, /* 2 "/iommu" */ -+ { propv_sbus, 0, 4 }, /* 3 "/iommu/sbus" */ -+ { propv_sbus_tcx, 5, 0 }, /* 4 "/iommu/sbus/SUNW,tcx" */ -+ { propv_sbus_ledma, 7, 6 }, /* 5 "/iommu/sbus/ledma" */ -+ { propv_sbus_ledma_le, 0, 0 }, /* 6 "/iommu/sbus/ledma/le" */ -+ { propv_sbus_cs4231, 8, 0 }, /* 7 "/iommu/sbus/SUNW,CS4231 */ -+ { propv_sbus_bpp, 9, 0 }, /* 8 "/iommu/sbus/SUNW,bpp */ -+ { propv_sbus_espdma, 11, 10 }, /* 9 "/iommu/sbus/espdma" */ -+ { propv_sbus_espdma_esp, 0, 0 }, /* 10 "/iommu/sbus/espdma/esp" */ -+ { propv_sbus_apc, 0, 0 }, /* 11 "/iommu/sbus/power-management */ -+ { propv_cpu, 13, 0 }, /* 12 "/STP1012PGA" */ -+ { propv_obio, 23, 14 }, /* 13 "/obio" */ -+ { propv_obio_int, 15, 0 }, /* 14 "/obio/interrupt" */ -+ { propv_obio_cnt, 16, 0 }, /* 15 "/obio/counter" */ -+ { propv_obio_eep, 17, 0 }, /* 16 "/obio/eeprom" */ -+ { propv_obio_auxio, 18, 0 }, /* 17 "/obio/auxio" */ -+ { propv_obio_zs1, 19, 0 }, /* 18 "/obio/zs@0,100000" -+ Must be before zs@0,0! */ -+ { propv_obio_zs, 20, 0 }, /* 19 "/obio/zs@0,0" */ -+ { propv_obio_fd, 21, 0 }, /* 20 "/obio/SUNW,fdtwo" */ -+ { propv_obio_pw, 22, 0 }, /* 21 "/obio/power" */ -+ { propv_obio_cf, 0, 0 }, /* 22 "/obio/slavioconfig@0,800000" */ -+ { propv_options, 24, 0 }, /* 23 "/options" */ -+ { propv_memory, 25, 0 }, /* 24 "/memory" */ -+ { propv_vmemory, 0, 0 }, /* 25 "/virtual-memory" */ -+}; -+ -+static struct linux_mlist_v0 totphys[MAX_BANKS]; -+static struct linux_mlist_v0 totmap[1]; -+static struct linux_mlist_v0 totavail[MAX_BANKS]; -+ -+static struct linux_mlist_v0 *ptphys; -+static struct linux_mlist_v0 *ptmap; -+static struct linux_mlist_v0 *ptavail; -+ -+static const struct linux_nodeops nodeops0 = { -+ obp_nextnode, /* int (*no_nextnode)(int node); */ -+ obp_child, /* int (*no_child)(int node); */ -+ obp_proplen, /* int (*no_proplen)(int node, char *name); */ -+ obp_getprop, /* int (*no_getprop)(int node,char *name,char *val); */ -+ obp_setprop, /* int (*no_setprop)(int node, char *name, -+ char *val, int len); */ -+ obp_nextprop /* char * (*no_nextprop)(int node, char *name); */ -+}; -+ -+static struct linux_arguments_v0 obp_arg; -+static const struct linux_arguments_v0 * const obp_argp = &obp_arg; -+ -+static void (*synch_hook)(void); -+static char obp_stdin, obp_stdout; -+static int obp_fd_stdin, obp_fd_stdout; -+ -+static int obp_nbgetchar(void); -+static int obp_nbputchar(int ch); -+static void obp_reboot(char *); -+static void obp_abort(void); -+static void obp_halt(void); -+static int obp_devopen(char *str); -+static int obp_devclose(int dev_desc); -+static int obp_devread(int dev_desc, char *buf, int nbytes); -+static int obp_devwrite(int dev_desc, char *buf, int nbytes); -+static int obp_devseek(int dev_desc, int hi, int lo); -+static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf); -+static char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size); -+static void obp_dumb_munmap(char *va, unsigned int size); -+static int obp_inst2pkg(int dev_desc); -+ -+static void doublewalk(unsigned ptab1, unsigned va) -+{ -+unsigned int proc_tablewalk(int ctx, unsigned int va); -+unsigned int mem_tablewalk(unsigned int pa, unsigned int va); -+ -+ proc_tablewalk(0, va); -+ if (ptab1 != 0) mem_tablewalk(ptab1, va); -+} -+ -+static struct linux_romvec romvec0; -+ -+struct fd { -+ int unit, part; -+ int offset; -+ int (*pread)(int dev_desc, int offset, char *buf, unsigned int nbytes); -+ int (*pwrite)(int dev_desc, int offset, char *buf, unsigned int nbytes); -+} fd_table[16]; -+ -+static int fd_index; -+static int con_pread(int dev_desc, int offset, char *buf, unsigned int nbytes); -+static int con_pwrite(int dev_desc, int offset, char *buf, unsigned int nbytes); -+ -+void * -+init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas, -+ const char *cmdline, char boot_device, int nographic) -+{ -+ int i; -+ -+ /* -+ * Avoid data segment allocations -+ */ -+ ptphys = totphys; -+ ptmap = totmap; -+ ptavail = totavail; -+ /* -+ * Form memory descriptors. -+ */ -+ for (i = 0; i < bankc; i++) { -+ totphys[i].theres_more = &totphys[i+1]; -+ totphys[i].start_adr = (char*) bankv[i].start; -+ totphys[i].num_bytes = bankv[i].length; -+ } -+ totphys[i-1].theres_more = 0; -+ -+ /* -+ * XXX Merged in normal PROM when full banks touch. -+ */ -+ for (i = 0; i < bankc; i++) { -+ unsigned bankbase = bankv[i].start; -+ unsigned banksize = bankv[i].length; -+ if (hiphybas > bankbase && -+ hiphybas < bankbase + banksize) { -+ banksize = hiphybas - bankbase; -+ } -+ totavail[i].theres_more = &totavail[i+1]; -+ totavail[i].start_adr = (char*) bankbase; -+ totavail[i].num_bytes = banksize; -+ } -+ totavail[i-1].theres_more = 0; -+ -+ totmap[0].theres_more = 0; -+ totmap[0].start_adr = (char*) PROLBASE; -+ totmap[0].num_bytes = PROLSIZE; -+ prop_mem_reg[0] = 0; -+ prop_mem_reg[1] = 0; -+ prop_mem_reg[2] = bankv[0].length; -+ prop_mem_avail[0] = 0; -+ prop_mem_avail[1] = 0; -+ prop_mem_avail[2] = hiphybas; -+ prop_vmem_avail[0] = 0; -+ prop_vmem_avail[1] = 0; -+ prop_vmem_avail[2] = PROLBASE-1; -+ prop_vmem_avail[3] = 0; -+ prop_vmem_avail[4] = 0xffe00000; -+ prop_vmem_avail[5] = 0x00200000; -+ -+ /* -+ * idprom -+ */ -+ bcopy(idprom, obp_idprom, IDPROM_SIZE); -+ -+ // Linux wants a R/W romvec table -+ romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC; -+ romvec0.pv_romvers = 3; -+ romvec0.pv_plugin_revision = 77; -+ romvec0.pv_printrev = 0x10203; -+ romvec0.pv_v0mem.v0_totphys = &ptphys; -+ romvec0.pv_v0mem.v0_prommap = &ptmap; -+ romvec0.pv_v0mem.v0_available = &ptavail; -+ romvec0.pv_nodeops = &nodeops0; -+ romvec0.pv_bootstr = (void *)doublewalk; -+ romvec0.pv_v0devops.v0_devopen = &obp_devopen; -+ romvec0.pv_v0devops.v0_devclose = &obp_devclose; -+ romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev; -+ romvec0.pv_stdin = &obp_stdin; -+ romvec0.pv_stdout = &obp_stdout; -+ romvec0.pv_getchar = obp_nbgetchar; -+ romvec0.pv_putchar = (void (*)(int))obp_nbputchar; -+ romvec0.pv_nbgetchar = obp_nbgetchar; -+ romvec0.pv_nbputchar = obp_nbputchar; -+ romvec0.pv_reboot = obp_reboot; -+ romvec0.pv_printf = (void (*)(const char *fmt, ...))printk; -+ romvec0.pv_abort = obp_abort; -+ romvec0.pv_halt = obp_halt; -+ romvec0.pv_synchook = &synch_hook; -+ romvec0.pv_v0bootargs = &obp_argp; -+ romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg; -+ romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap; -+ romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap; -+ romvec0.pv_v2devops.v2_dev_open = obp_devopen; -+ romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose; -+ romvec0.pv_v2devops.v2_dev_read = obp_devread; -+ romvec0.pv_v2devops.v2_dev_write = obp_devwrite; -+ romvec0.pv_v2devops.v2_dev_seek = obp_devseek; -+ obp_arg.boot_dev_ctrl = 0; -+ obp_arg.boot_dev_unit = '0'; -+ obp_arg.argv[0] = "sd(0,0,0):d"; -+ switch(boot_device) { -+ default: -+ case 'a': -+ obp_arg.argv[0] = "fd()"; -+ obp_arg.boot_dev[0] = 'f'; -+ obp_arg.boot_dev[1] = 'd'; -+ break; -+ case 'd': -+ obp_arg.boot_dev_unit = '2'; -+ obp_arg.argv[0] = "sd(0,2,0):d"; -+ // Fall through -+ case 'c': -+ obp_arg.boot_dev[0] = 's'; -+ obp_arg.boot_dev[1] = 'd'; -+ break; -+ case 'n': -+ obp_arg.argv[0] = "le()"; -+ obp_arg.boot_dev[0] = 'l'; -+ obp_arg.boot_dev[1] = 'e'; -+ break; -+ } -+ obp_arg.argv[1] = cmdline; -+ romvec0.pv_v2bootargs.bootpath = &obp_arg.argv[0]; -+ romvec0.pv_v2bootargs.bootargs = &cmdline; -+ romvec0.pv_v2bootargs.fd_stdin = &obp_fd_stdin; -+ romvec0.pv_v2bootargs.fd_stdout = &obp_fd_stdout; -+ -+ bcopy(propv_root_templ, propv_root, sizeof(propv_root_templ)); -+ propv_root[4].name = "stdin-path"; -+ propv_root[5].name = "stdout-path"; -+ obp_fd_stdin = 0; -+ obp_fd_stdout = 1; -+ fd_table[0].pread = con_pread; -+ fd_table[0].pwrite = con_pwrite; -+ fd_table[1].pread = con_pread; -+ fd_table[1].pwrite = con_pwrite; -+ fd_index = 2; -+ if (nographic) { -+ obp_stdin = PROMDEV_TTYA; -+ propv_root[4].value = "/obio/zs@0,100000:a"; -+ propv_root[4].length = sizeof("/obio/zs@0,100000:a"); -+ fd_table[0].unit = 18; -+ obp_stdout = PROMDEV_TTYA; -+ propv_root[5].value = "/obio/zs@0,100000:a"; -+ propv_root[5].length = sizeof("/obio/zs@0,100000:a"); -+ fd_table[1].unit = 18; -+ } else { -+ obp_stdin = PROMDEV_KBD; -+ propv_root[4].value = "/obio/zs@0,0"; -+ propv_root[4].length = sizeof("/obio/zs@0,0"); -+ fd_table[0].unit = 19; -+ obp_stdout = PROMDEV_SCREEN; -+ propv_root[5].value = "/iommu/sbus/SUNW,tcx"; -+ propv_root[5].length = sizeof("/iommu/sbus/SUNW,tcx"); -+ fd_table[1].unit = 4; -+ } -+ prop_zs_addr = map_io(0x71000000, 8); -+ prop_zs1_addr = map_io(0x71100000, 8); -+ return &romvec0; -+} -+ -+static const struct property *find_property(int node,char *name) -+{ -+ const struct property *prop = &nodes[node].properties[0]; -+ while (prop && prop->name) { -+ if (bcmp(prop->name, name, 128) == 0) return prop; -+ prop++; -+ } -+ return NULL; -+} -+ -+static int obp_nextnode(int node) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_nextnode(%d) = %d\n", node, nodes[node].sibling); -+#endif -+ return nodes[node].sibling; -+} -+ -+static int obp_child(int node) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_child(%d) = %d\n", node, nodes[node].child); -+#endif -+ return nodes[node].child; -+} -+ -+static int obp_proplen(int node, char *name) -+{ -+ const struct property *prop = find_property(node,name); -+ if (prop) { -+#ifdef DEBUG_OBP -+ printk("obp_proplen(%d, %s) = %d\n", node, name, prop->length); -+#endif -+ return prop->length; -+ } -+#ifdef DEBUG_OBP -+ printk("obp_proplen(%d, %s) (no prop)\n", node, name); -+#endif -+ return -1; -+} -+ -+static int obp_getprop(int node, char *name, char *value) -+{ -+ const struct property *prop; -+ -+ if (!name) { -+ // NULL name means get first property -+#ifdef DEBUG_OBP -+ printk("obp_getprop(%d, %x (NULL)) = %s\n", node, name, -+ nodes[node].properties[0].name); -+#endif -+ return (int)nodes[node].properties[0].name; -+ } -+ prop = find_property(node,name); -+ if (prop) { -+ memcpy(value,prop->value,prop->length); -+#ifdef DEBUG_OBP -+ printk("obp_getprop(%d, %s) = %s\n", node, name, value); -+#endif -+ return prop->length; -+ } -+#ifdef DEBUG_OBP -+ printk("obp_getprop(%d, %s): not found\n", node, name); -+#endif -+ return -1; -+} -+ -+static int obp_setprop(__attribute__((unused)) int node, -+ __attribute__((unused)) char *name, -+ __attribute__((unused)) char *value, -+ __attribute__((unused)) int len) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_setprop(%d, %s) = %s (%d)\n", node, name, value, len); -+#endif -+ return -1; -+} -+ -+static const char *obp_nextprop(int node,char *name) -+{ -+ const struct property *prop; -+ -+ if (!name || *name == '\0') { -+ // NULL name means get first property -+#ifdef DEBUG_OBP -+ printk("obp_nextprop(%d, NULL) = %s\n", node, -+ nodes[node].properties[0].name); -+#endif -+ return nodes[node].properties[0].name; -+ } -+ prop = find_property(node,name); -+ if (prop && prop[1].name) { -+#ifdef DEBUG_OBP -+ printk("obp_nextprop(%d, %s) = %s\n", node, name, prop[1].name); -+#endif -+ return prop[1].name; -+ } -+#ifdef DEBUG_OBP -+ printk("obp_nextprop(%d, %s): not found\n", node, name); -+#endif -+ return ""; -+} -+ -+extern int (*getch_fn)(struct vconterm *v); -+ -+static int obp_nbgetchar(void) { -+ extern struct vconterm dp0; -+ return getch_fn(&dp0); -+} -+ -+static int obp_nbputchar(int ch) { -+ printk("%c", ch); -+ return 0; -+} -+ -+static void obp_reboot(char *str) { -+ printk("rebooting (%s)\n", str); -+ stb_bypass(0x71f00000, 1); -+ for (;;) {} -+} -+ -+static void obp_abort() { -+ printk("abort, power off\n"); -+ stb_bypass(0x71910000, 1); -+ for (;;) {} -+} -+ -+static void obp_halt() { -+ printk("halt, power off\n"); -+ stb_bypass(0x71910000, 1); -+ for (;;) {} -+} -+ -+extern void *esp_read(int unit, int part, int offset, short len); -+ -+static int esp_pread(int dev_desc, int offset, char *buf, unsigned int nbytes) -+{ -+ unsigned int i; -+ void *src; -+ -+ for(i = 0; i < nbytes; i += 512) { -+ src = esp_read(fd_table[dev_desc].unit, fd_table[dev_desc].part, (offset + i) / 512, 512); -+ memcpy(&buf[i], src, 512); -+ } -+ return nbytes; -+} -+ -+static int con_pread(__attribute__((unused)) int dev_desc, __attribute__((unused)) int offset, char *buf, unsigned int nbytes) -+{ -+ unsigned int i; -+ -+ for(i = 0; i < nbytes; i ++) { -+ buf[i] = obp_nbgetchar(); -+ } -+ return nbytes; -+} -+ -+static int con_pwrite(__attribute__((unused)) int dev_desc, __attribute__((unused)) int offset, char *buf, unsigned int nbytes) -+{ -+ unsigned int i; -+ -+ for(i = 0; i < nbytes; i ++) { -+ obp_nbputchar(buf[i]); -+ } -+ return nbytes; -+} -+ -+#define isnum(c) ((c >= '0') && (c < '9')) -+#define ctoi(c) (c - '0') -+ -+static int obp_devopen(char *str) { -+#ifdef DEBUG_OBP -+ printk("obp_devopen(%s)\n", str); -+#endif -+ if (str[0] == 's' && str[1] == 'd' && str[4] == ',') { -+ unsigned int target; -+ -+ if (str[5] < 7) -+ target = str[5]; -+ else if (isnum(str[6]) && isnum(str[5])) { -+ target = (ctoi(str[5]) * 10 + ctoi(str[6])) & 7; -+ } -+ else { -+ target = ctoi(str[5]) & 7; -+ } -+ fd_table[fd_index].unit = target; -+ fd_table[fd_index].part = str[10] - 'a'; -+ fd_table[fd_index].pread = esp_pread; -+ return fd_index++; // XXX -+ } -+ return 0; -+} -+ -+static int obp_devclose(__attribute__((unused)) int dev_desc) { -+#ifdef DEBUG_OBP -+ printk("obp_devclose %d\n", dev_desc); -+#endif -+ fd_index--; // XXX -+ return 0; -+} -+ -+static int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_rdblkdev: fd %d, num_blks %d, offset %d, buf 0x%x\n", dev_desc, num_blks, offset, buf); -+#endif -+ return fd_table[dev_desc].pread(dev_desc, offset, buf, num_blks * 512); -+} -+ -+static char *obp_dumb_mmap(char *va, __attribute__((unused)) int which_io, -+ unsigned int pa, unsigned int size) -+{ -+ unsigned int npages; -+ unsigned int off; -+ unsigned int mva; -+ -+#ifdef DEBUG_OBP -+ printk("obp_dumb_mmap: virta %x, which_io %d, paddr %x, sz %d\n", va, which_io, pa, size); -+#endif -+ off = pa & (PAGE_SIZE-1); -+ npages = (off + size + (PAGE_SIZE-1)) / PAGE_SIZE; -+ pa &= ~(PAGE_SIZE-1); -+ -+ mva = (unsigned int) va; -+ while (npages-- != 0) { -+ map_page(pmem.pl1, mva, pa, 1, pmem.pbas); -+ mva += PAGE_SIZE; -+ pa += PAGE_SIZE; -+ } -+ return va; -+} -+ -+static void obp_dumb_munmap(__attribute__((unused)) char *va, -+ __attribute__((unused)) unsigned int size) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_dumb_munmap: virta %x, sz %d\n", va, size); -+#endif -+} -+ -+static int obp_devread(int dev_desc, char *buf, int nbytes) -+{ -+ int ret; -+#ifdef DEBUG_OBP -+ printk("obp_devread: fd %d, nbytes %d\n", dev_desc, nbytes); -+#endif -+ ret = fd_table[dev_desc].pread(dev_desc, fd_table[dev_desc].offset, buf, nbytes); -+ fd_table[dev_desc].offset += nbytes; -+ return ret; -+} -+ -+static int obp_devwrite(int dev_desc, char *buf, int nbytes) -+{ -+ int ret; -+#ifdef DEBUG_OBP -+ printk("obp_devwrite: fd %d, buf %s, nbytes %d\n", dev_desc, buf, nbytes); -+#endif -+ ret = fd_table[dev_desc].pwrite(dev_desc, fd_table[dev_desc].offset, buf, nbytes); -+ fd_table[dev_desc].offset += nbytes; -+ return ret; -+} -+ -+static int obp_devseek(int dev_desc, __attribute__((unused)) int hi, int lo) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_devseek: fd %d, hi %d, lo %d\n", dev_desc, hi, lo); -+#endif -+ fd_table[dev_desc].offset = lo; -+ return 0; -+} -+ -+static int obp_inst2pkg(int dev_desc) -+{ -+#ifdef DEBUG_OBP -+ printk("obp_inst2pkg: fd %d\n", dev_desc); -+#endif -+ return fd_table[dev_desc].unit; -+} -diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch-15/qemu/system_qemu.c ---- proll_18.orig/qemu/system_qemu.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/qemu/system_qemu.c 2005-04-16 06:16:20.000000000 +0000 -@@ -0,0 +1,430 @@ -+/** -+ ** Proll (PROM replacement) -+ ** system.c: shared miscallenea. -+ ** Copyright 1999 Pete Zaitcev -+ ** This code is licensed under GNU General Public License. -+ **/ -+#include -+#include -+#include -+#ifndef NULL -+#define NULL ((void*)0) -+#endif -+ -+#include "pgtsrmmu.h" -+ -+#include "vconsole.h" -+#include /* Local copy of 2.2 style include */ -+#include /* __P() */ -+#include /* init_net() */ -+#include /* we are a provider for part of this. */ -+#include /* myipaddr */ -+#include -+#include /* our own prototypes */ -+ -+/* -+ * We export this. -+ */ -+char idprom[IDPROM_SIZE]; -+ -+ -+/* -+ * Create an I/O mapping to pa[size]. -+ * Returns va of the mapping or 0 if unsuccessful. -+ */ -+void * -+map_io(unsigned pa, int size) -+{ -+ void *va; -+ unsigned int npages; -+ unsigned int off; -+ unsigned int mva; -+ -+ off = pa & (PAGE_SIZE-1); -+ npages = (off + size + (PAGE_SIZE-1)) / PAGE_SIZE; -+ pa &= ~(PAGE_SIZE-1); -+ -+ va = mem_alloc(&cio, npages*PAGE_SIZE, PAGE_SIZE); -+ if (va == 0) return va; -+ -+ mva = (unsigned int) va; -+ /* printk("map_io: va 0x%x pa 0x%x off 0x%x npages %d\n", va, pa, off, npages); */ /* P3 */ -+ while (npages-- != 0) { -+ map_page(pmem.pl1, mva, pa, 1, pmem.pbas); -+ mva += PAGE_SIZE; -+ pa += PAGE_SIZE; -+ } -+ -+ return (void *)((unsigned int)va + off); -+} -+ -+/* -+ * Tablewalk routine used for testing. -+ * Returns PTP/PTE. -+ */ -+unsigned int -+proc_tablewalk(int ctx, unsigned int va) -+{ -+ unsigned int pa1; -+ -+ __asm__ __volatile__ ("lda [%1] %2, %0" : -+ "=r" (pa1) : -+ "r" (AC_M_CTPR), "i" (ASI_M_MMUREGS)); -+ /* printk(" ctpr %x ctx %x\n", pa1, ctx); */ /* P3 */ -+ pa1 <<= 4; -+ pa1 = ld_bypass(pa1 + (ctx << 2)); -+ if ((pa1 & 0x03) == 0) goto invalid; -+ return mem_tablewalk((pa1 & 0xFFFFFFF0) << 4, va); -+ -+invalid: -+ printk(" invalid %x\n", pa1); -+ return 0; -+} -+ -+/* -+ * Walk the tables in memory, starting at physical address pa. -+ */ -+unsigned int -+mem_tablewalk(unsigned int pa, unsigned int va) -+{ -+ unsigned int pa1; -+ -+ printk("pa %x va %x", pa, va); -+ pa1 = ld_bypass(pa + (((va&0xFF000000)>>24) << 2)); -+ if ((pa1 & 0x03) == 0) goto invalid; -+ printk(" l1 %x", pa1); -+ pa1 <<= 4; pa1 &= 0xFFFFFF00; -+ pa1 = ld_bypass(pa1 + (((va&0x00FC0000)>>18) << 2)); -+ if ((pa1 & 0x03) == 0) goto invalid; -+ printk(" l2 %x", pa1); -+ pa1 <<= 4; pa1 &= 0xFFFFFF00; -+ pa1 = ld_bypass(pa1 + (((va&0x0003F000)>>12) << 2)); -+ if ((pa1 & 0x03) == 0) goto invalid; -+ printk(" l3 %x", pa1); -+ printk(" off %x\n", va&0x00000FFF); -+ return pa1; -+invalid: -+ printk(" invalid %x\n", pa1); -+ return 0; -+} -+ -+/* -+ * Make CPU page tables. -+ * Returns pointer to context table. -+ * Here we ignore memory allocation errors which "should not happen" -+ * because we cannot print anything anyways if memory initialization fails. -+ */ -+void makepages(struct phym *t, unsigned int highbase) -+{ -+ unsigned int *ctp, *l1, pte; -+ int i; -+ unsigned int pa, va; -+ -+ ctp = mem_zalloc(&cmem, NCTX_SWIFT*sizeof(int), NCTX_SWIFT*sizeof(int)); -+ l1 = mem_zalloc(&cmem, 256*sizeof(int), 256*sizeof(int)); -+ -+ pte = SRMMU_ET_PTD | (((unsigned int)l1 - PROLBASE + highbase) >> 4); -+ for (i = 0; i < NCTX_SWIFT; i++) { -+ ctp[i] = pte; -+ } -+ -+ pa = PROLBASE; -+ for (va = PROLBASE; va < PROLDATA; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } -+ pa = highbase + PROLDATA - PROLBASE; -+ for (va = PROLDATA; va < PROLBASE + PROLSIZE; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } -+ -+ /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ -+ pa = 0; -+ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { -+ map_page(l1, va, pa, 0, highbase); -+ pa += PAGE_SIZE; -+ } -+ -+ t->pctp = ctp; -+ t->pl1 = l1; -+ t->pbas = highbase; -+} -+ -+/* -+ * Create a memory mapping from va to epa in page table pgd. -+ * highbase is used for v2p translation. -+ */ -+int -+map_page(unsigned int *pgd, unsigned int va, -+ unsigned int epa, int type, unsigned int highbase) -+{ -+ unsigned int pte; -+ unsigned int *p; -+ unsigned int pa; -+ -+ pte = pgd[((va)>>SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD-1)]; -+ if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { -+ p = mem_zalloc(&cmem, SRMMU_PTRS_PER_PMD*sizeof(int), -+ SRMMU_PTRS_PER_PMD*sizeof(int)); -+ if (p == 0) goto drop; -+ pte = SRMMU_ET_PTD | -+ (((unsigned int)p - PROLBASE + highbase) >> 4); -+ pgd[((va)>>SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD-1)] = pte; -+ /* barrier() */ -+ } -+ -+ pa = ((pte & 0xFFFFFFF0) << 4); -+ pa += (((va)>>SRMMU_PMD_SHIFT & (SRMMU_PTRS_PER_PMD-1)) << 2); -+ pte = ld_bypass(pa); -+ if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { -+ p = mem_zalloc(&cmem, SRMMU_PTRS_PER_PTE*sizeof(int), -+ SRMMU_PTRS_PER_PTE*sizeof(int)); -+ if (p == 0) goto drop; -+ pte = SRMMU_ET_PTD | -+ (((unsigned int)p - PROLBASE + highbase) >> 4); -+ st_bypass(pa, pte); -+ } -+ -+ pa = ((pte & 0xFFFFFFF0) << 4); -+ pa += (((va)>>PAGE_SHIFT & (SRMMU_PTRS_PER_PTE-1)) << 2); -+ -+ pte = SRMMU_ET_PTE | ((epa & PAGE_MASK) >> 4); -+ if (type) { /* I/O */ -+ pte |= SRMMU_REF; -+ /* SRMMU cannot make Supervisor-only, but not exectutable */ -+ pte |= SRMMU_PRIV; -+ } else { /* memory */ -+ pte |= SRMMU_REF|SRMMU_CACHE; -+ pte |= SRMMU_PRIV; /* Supervisor only access */ -+ } -+ st_bypass(pa, pte); -+ return 0; -+ -+drop: -+ return -1; -+} -+ -+/* -+ * Switch page tables. -+ */ -+void -+init_mmu_swift(unsigned int ctp_phy) -+{ -+ unsigned int addr; -+ -+ /* -+ * Flush cache -+ */ -+ for (addr = 0; addr < 0x2000; addr += 0x10) { -+ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : -+ "r" (addr), "i" (ASI_M_DATAC_TAG)); -+ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : -+ "r" (addr<<1), "i" (ASI_M_TXTC_TAG)); -+ } -+ -+ /* -+ * Switch ctx table -+ */ -+ ctp_phy >>= 4; -+ /* printk("done flushing, switching to %x\n", ctp_phy); */ -+ __asm__ __volatile__ ("sta %0, [%1] %2\n\t" : : -+ "r" (ctp_phy), "r" (AC_M_CTPR), "i" (ASI_M_MMUREGS)); -+ -+ /* -+ * Flush old page table references -+ */ -+ __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : -+ "r" (0x400), "i" (ASI_M_FLUSH_PROBE) : "memory"); -+} -+ -+/* -+ * add_timer, del_timer -+ * This should go into sched.c, but we have it split for different archs. -+ */ -+struct timer_list_head { -+ struct timer_list *head, *tail; -+}; -+ -+static struct timer_list_head timers; /* Anonymous heap of timers */ -+ -+void add_timer(struct timer_list *timer) { -+ struct timer_list *p; -+ if (timer->prev != NULL || timer->next != NULL) { -+ printk("bug: kernel timer added twice at 0x%x.\n", -+ __builtin_return_address(0)); -+ return; -+ } -+ if ((p = timers.tail) != NULL) { -+ timer->prev = p; -+ p->next = timer; -+ timers.tail = timer; -+ } else { -+ timers.head = timer; -+ timers.tail = timer; -+ } -+ return; -+} -+ -+int del_timer(struct timer_list *timer) { -+ struct timer_list *p; -+ int ret; -+ -+ if (timers.head == timer) timers.head = timer->next; -+ if (timers.tail == timer) timers.tail = timer->prev; -+ if ((p = timer->prev) != NULL) p->next = timer->next; -+ if ((p = timer->next) != NULL) p->prev = timer->prev; -+ ret = timer->next != 0 || timer->prev != 0; -+ timer->next = NULL; -+ timer->prev = NULL; -+ return ret; -+} -+ -+void run_timers() { -+ struct timer_list *p; -+ -+ p = timers.head; -+ while (p != NULL) { -+ if (p->expires < jiffies) { -+ del_timer(p); /* XXX make nonstatic member */ -+ (*p->function)(p->data); -+ p = timers.head; -+ } else { -+ p = p->next; -+ } -+ } -+} -+ -+/* -+ * Allocate memory. This is reusable. -+ */ -+void mem_init(struct mem *t, char *begin, char *limit) -+{ -+ t->start = begin; -+ t->uplim = limit; -+ t->curp = begin; -+} -+ -+void mem_fini(struct mem *t) -+{ -+ t->curp = 0; -+} -+ -+void *mem_alloc(struct mem *t, int size, int align) -+{ -+ char *p; -+ -+ p = (char *)((((unsigned int)t->curp) + (align-1)) & ~(align-1)); -+ if (p >= t->uplim || p + size > t->uplim) return 0; -+ t->curp = p + size; -+ return p; -+} -+ -+void *mem_zalloc(struct mem *t, int size, int align) -+{ -+ char *p; -+ -+ if ((p = mem_alloc(t, size, align)) != 0) memset(p, 0, size); -+ return p; -+} -+ -+/* -+ * Library functions -+ */ -+void *memset(void *s, int c, size_t len) -+{ -+ void *p = s; -+ -+ while (len--) { -+ *(char *)s = c; -+ s++; -+ } -+ return p; -+} -+ -+void bcopy(const void *f, void *t, int len) { -+ while (len--) { -+ *(char *)t = *(char *)f; -+ f++; -+ t++; -+ } -+} -+ -+/* Comparison is 7-bit */ -+int bcmp(const void *s1, const void *s2, int len) -+{ -+ int i; -+ char ch; -+ -+ while (len--) { -+ ch = *(char *)s1; -+ i = ch - *(char *)s2; -+ s1++; -+ s2++; -+ if (i != 0) -+ return i; -+ if (ch == 0) -+ return 0; -+ } -+ return 0; -+} -+ -+int strlen(const char *s) { -+ const char *p; -+ for (p = s; *p != 0; p++) { } -+ return p - s; -+} -+ -+extern void *printk_fn; -+ -+void printk(char *fmt, ...) -+{ -+ struct prf_fp { -+ void *xfp; -+ void (*write)(void *, char *, int); -+ } prfa; -+ extern void prf(struct prf_fp *, char *fmt, va_list adx); -+ va_list x1; -+ -+ va_start(x1, fmt); -+ prfa.xfp = &dp0; -+ prfa.write = printk_fn; -+ prf(&prfa, fmt, x1); -+ va_end(x1); -+} -+ -+void fatal() -+{ -+ printk("fatal."); -+loop: goto loop; -+} -+ -+/* -+ * Get the highest bit number from the mask. -+ */ -+int highc(int mask, int size) -+{ -+ int m1; -+ -+ m1 = 1 << size; -+ while (size != 0) { -+ size--; -+ m1 >>= 1; -+ if (m1 & mask) break; -+ } -+ return size; -+} -+ -+/* -+ */ -+unsigned int ld_bp_swap(unsigned int ptr) { -+ unsigned int n; -+ n = ld_bypass(ptr); -+ n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); -+ return n; -+} -+ -+void st_bp_swap(unsigned int ptr, unsigned int n) { -+ n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24); -+ st_bypass(ptr, n); -+}; -diff -ruN proll_18.orig/src/arp.c proll-patch-15/src/arp.c ---- proll_18.orig/src/arp.c 2001-12-24 05:12:31.000000000 +0000 -+++ proll-patch-15/src/arp.c 2005-08-14 10:10:11.000000000 +0000 -@@ -45,7 +45,7 @@ - #endif - static struct arp_cache arp_list[ARPNUM]; /* ARP address cache */ - static int next_arp; /* next table entry */ --static t_ipaddr def_gw = IP_ANY; /* default routing */ -+static t_ipaddr def_gw; /* default routing */ - - - -@@ -100,10 +100,7 @@ - * - * ARP receiver routine - */ --static int arp_recv(buf, bufsize, addr) --unsigned char *buf; --int bufsize; --unsigned char *addr; -+static int arp_recv(unsigned char *buf, unsigned int bufsize, unsigned char *addr) - { - register struct arphdr *ahp = (struct arphdr *)buf; - -@@ -144,7 +141,7 @@ - * - * Resolve IP address and return pointer to hardware address. - */ --unsigned char *ip_resolve(ip) -+const unsigned char *ip_resolve(ip) - t_ipaddr ip; - { - int i; -@@ -230,14 +227,11 @@ - */ - int init_arp() - { -- /* Set name of module for error messages */ -- net_module_name = "arp"; -- - #ifndef NOARP - /* Register ARP packet type and set send buffer pointer */ - if ((arpbuf = (struct arphdr *)reg_type(htons(ETH_P_ARP), arp_recv)) == NULL) - return(FALSE); - #endif -- -+ def_gw = IP_ANY; - return(TRUE); - } -diff -ruN proll_18.orig/src/arp.h proll-patch-15/src/arp.h ---- proll_18.orig/src/arp.h 1999-03-18 03:39:43.000000000 +0000 -+++ proll-patch-15/src/arp.h 2004-11-13 15:50:49.000000000 +0000 -@@ -104,7 +104,7 @@ - extern int init_arp __P((void)); - - /* Resolve IP address and return pointer to hardware address */ --extern unsigned char *ip_resolve __P((t_ipaddr ip)); -+extern const unsigned char *ip_resolve __P((t_ipaddr ip)); - - /* Add a new antry to the ARP cache */ - extern void addcache __P((unsigned char *ha, t_ipaddr ip)); -diff -ruN proll_18.orig/src/bootp.c proll-patch-15/src/bootp.c ---- proll_18.orig/src/bootp.c 1999-12-15 17:20:30.000000000 +0000 -+++ proll-patch-15/src/bootp.c 2005-08-14 10:16:09.000000000 +0000 -@@ -151,7 +151,7 @@ - while (TRUE) { - boot_xid = get_ticks() + random(); - bootp_send(); -- i = udp_read((char *)(&boot_rec), BOOTP_REC_SIZE, timeout, CHR_ESC); -+ i = udp_read((char *)(&boot_rec), BOOTP_REC_SIZE, timeout); - if (i < 0) { /* user pressed ESC */ - printf("\nAborted\n"); - return(1); -diff -ruN proll_18.orig/src/esp.c proll-patch-15/src/esp.c ---- proll_18.orig/src/esp.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/src/esp.c 2005-08-15 18:42:46.000000000 +0000 -@@ -0,0 +1,305 @@ -+#include /* == */ -+#include /* __P for netpriv.h */ -+#include /* dmaga */ -+#include -+ -+#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */ -+#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ -+#define PHYS_JJ_ESP_IRQ 4 -+#define BUFSIZE 4096 -+/* -+ * XXX Crude -+ */ -+struct esp_dma { -+ struct sparc_dma_registers *regs; -+ enum dvma_rev revision; -+}; -+ -+struct esp_regs { -+ unsigned int regs[16]; -+}; -+ -+struct esp_private { -+ int active; /* initialized */ -+ int inst; /* iface number */ -+ -+ volatile struct esp_regs *ll; -+ __u32 buffer_dvma; -+ unsigned int irq; /* device IRQ number */ -+ int interrupt; -+ -+ struct esp_dma *espdma; /* If set this points to espdma */ -+ -+ unsigned char *buffer; -+ struct disk_info { -+ unsigned int hw_sector; -+ unsigned int part_offset[8]; -+ } disk[8]; -+}; -+ -+static void esp_interrupt(void *dev_id) -+{ -+ struct esp_private *lp = (struct esp_private *)dev_id; -+ -+ lp->interrupt = 1; -+ /* Acknowledge all the interrupt sources ASAP */ -+ -+ lp->interrupt = 0; -+} -+ -+static int esp_open (void *dev) -+{ -+ struct esp_private *lp = (struct esp_private *)dev; -+ int status = 0; -+ -+ if (request_irq(lp->irq, &esp_interrupt, (void *)dev)) { -+ printk ("Esp: Can't get irq %d\n", lp->irq); -+ return -1; -+ } -+ -+ /* On the 4m, setup the espdma to provide the upper bits for buffers */ -+ if (lp->espdma) -+ lp->espdma->regs->dma_test = ((__u32) lp->buffer_dvma) & 0xff000000; -+ -+ return status; -+} -+ -+static int esp_close (void *dev) -+{ -+ struct esp_private *lp = (struct esp_private *)dev; -+ -+ free_irq (lp->irq, (void *) dev); -+ return 0; -+} -+ -+static int -+esp_init(struct esp_private *esp, struct esp_dma *espdma, int irq) -+{ -+ volatile struct esp_regs *ll; -+ -+ /* Get the IO region */ -+ ll = map_io(PHYS_JJ_ESP, sizeof (struct esp_regs)); -+ if (ll == 0) return -1; -+ -+ esp->buffer = dvma_alloc(BUFSIZE, &esp->buffer_dvma); -+ esp->ll = ll; -+ esp->espdma = espdma; -+ esp->irq = irq; -+ -+ // Chip reset -+ stb_bypass((int)ll + 3*2, 2); -+ return 0; -+} -+ -+static int espdma_init(struct esp_dma *espdma) -+{ -+ void *p; -+ -+ /* Hardcode everything for MrCoffee. */ -+ if ((p = map_io(PHYS_JJ_ESPDMA, 0x10)) == 0) { -+ printk("espdma_init: cannot map registers\n"); -+ return -1; -+ } -+ espdma->regs = p; -+ -+ printk("dma1: "); -+ -+ switch((espdma->regs->cond_reg)&DMA_DEVICE_ID) { -+ case DMA_VERS0: -+ espdma->revision=dvmarev0; -+ printk("Revision 0 "); -+ break; -+ case DMA_ESCV1: -+ espdma->revision=dvmaesc1; -+ printk("ESC Revision 1 "); -+ break; -+ case DMA_VERS1: -+ espdma->revision=dvmarev1; -+ printk("Revision 1 "); -+ break; -+ case DMA_VERS2: -+ espdma->revision=dvmarev2; -+ printk("Revision 2 "); -+ break; -+ case DMA_VERHME: -+ espdma->revision=dvmahme; -+ printk("HME DVMA gate array "); -+ break; -+ case DMA_VERSPLUS: -+ espdma->revision=dvmarevplus; -+ printk("Revision 1 PLUS "); -+ break; -+ default: -+ printk("unknown dma version %x", -+ (espdma->regs->cond_reg)&DMA_DEVICE_ID); -+ /* espdma->allocated = 1; */ -+ break; -+ } -+ printk("\n"); -+ return 0; -+} -+ -+static struct esp_dma espdma0; -+static struct esp_private esp; -+/* -+ * Find all the esp cards on the system and initialize them -+ */ -+void esp_probe () -+{ -+ if (espdma_init(&espdma0) != 0) { -+ return; -+ } -+ -+ if (esp_init(&esp, &espdma0, PHYS_JJ_ESP_IRQ) != 0) { -+ printk("esp_probe: esp0 init failed\n"); -+ return; -+ } -+ return; -+} -+ -+void esp_read_capacity(int unit) -+{ -+ // Set SCSI target -+ stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7); -+ // Set DMA address -+ st_bypass(PHYS_JJ_ESPDMA + 4, esp.buffer_dvma); -+ // Set DMA length -+ stb_bypass(PHYS_JJ_ESP + 0*4, 10); -+ stb_bypass(PHYS_JJ_ESP + 1*4, 0); -+ // Set DMA direction -+ st_bypass(PHYS_JJ_ESPDMA + 0, 0x000); -+ // Setup command = Read Capacity -+ esp.buffer[0] = 0x80; -+ esp.buffer[1] = 0x25; -+ esp.buffer[2] = 0x00; -+ esp.buffer[3] = 0x00; -+ esp.buffer[4] = 0x00; -+ esp.buffer[5] = 0x00; -+ esp.buffer[6] = 0x00; -+ esp.buffer[7] = 0x00; -+ esp.buffer[8] = 0x00; -+ esp.buffer[9] = 0x00; -+ esp.buffer[10] = 0x00; -+ // Set ATN, issue command -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0xc2); -+ -+ // Set DMA length = 512 * read length -+ stb_bypass(PHYS_JJ_ESP + 0*4, 0); -+ stb_bypass(PHYS_JJ_ESP + 1*4, 8 & 0xff); -+ // Set DMA direction -+ st_bypass(PHYS_JJ_ESPDMA + 0, 0x100); -+ // Transfer -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0x90); -+ esp.disk[unit].hw_sector = (esp.buffer[4] << 24) | (esp.buffer[5] << 16) | (esp.buffer[6] << 8) | esp.buffer[7]; -+} -+ -+// offset is multiple of 512, len in bytes -+void *esp_read(int unit, int part, int offset, short len) -+{ -+ int pos, hw_sect, sect_offset, spb; -+ -+ // Set SCSI target -+ stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7); -+ // Set DMA address -+ st_bypass(PHYS_JJ_ESPDMA + 4, esp.buffer_dvma); -+ // Set DMA length -+ stb_bypass(PHYS_JJ_ESP + 0*4, 10); -+ stb_bypass(PHYS_JJ_ESP + 1*4, 0); -+ // Set DMA direction -+ st_bypass(PHYS_JJ_ESPDMA + 0, 0x000); -+ hw_sect = esp.disk[unit].hw_sector; -+ offset += esp.disk[unit].part_offset[part]; -+ spb = hw_sect / 512; -+ sect_offset = offset / spb; -+ pos = (offset - sect_offset * spb) * 512; -+ len /= 512; -+ //printk("Read unit %d, offset %d -> offset %d, pos %d, hw_sect %d\n", unit, offset, sect_offset, pos, hw_sect); -+ // Setup command = Read(10) -+ esp.buffer[0] = 0x80; -+ esp.buffer[1] = 0x28; -+ esp.buffer[2] = 0x00; -+ esp.buffer[3] = (sect_offset >> 24) & 0xff; -+ esp.buffer[4] = (sect_offset >> 16) & 0xff; -+ esp.buffer[5] = (sect_offset >> 8) & 0xff; -+ esp.buffer[6] = sect_offset & 0xff; -+ esp.buffer[7] = 0x00; -+ esp.buffer[8] = (len >> 8) & 0xff; -+ esp.buffer[9] = len & 0xff; -+ // Set ATN, issue command -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0xc2); -+ -+ // Set DMA length = sector size * read length -+ stb_bypass(PHYS_JJ_ESP + 0*4, (len * hw_sect) & 0xff); -+ stb_bypass(PHYS_JJ_ESP + 1*4, ((len * hw_sect) >> 8) & 0xff); -+ // Set DMA direction -+ st_bypass(PHYS_JJ_ESPDMA + 0, 0x100); -+ // Transfer -+ stb_bypass(PHYS_JJ_ESP + 3*4, 0x90); -+ return esp.buffer + pos; -+} -+ -+// Sparc boot sequence can be found in SILO docs, -+// first-isofs/README.SILO_ISOFS -+int esp_boot(int unit) -+{ -+ struct sun_disklabel { -+ unsigned char info[128]; /* Informative text string */ -+ unsigned char spare0[14]; -+ struct sun_info { -+ unsigned char spare1; -+ unsigned char id; -+ unsigned char spare2; -+ unsigned char flags; -+ } infos[8]; -+ unsigned char spare[246]; /* Boot information etc. */ -+ short rspeed; /* Disk rotational speed */ -+ short pcylcount; /* Physical cylinder count */ -+ short sparecyl; /* extra sects per cylinder */ -+ unsigned char spare2[4]; /* More magic... */ -+ short ilfact; /* Interleave factor */ -+ short ncyl; /* Data cylinder count */ -+ short nacyl; /* Alt. cylinder count */ -+ short ntrks; /* Tracks per cylinder */ -+ short nsect; /* Sectors per track */ -+ unsigned char spare3[4]; /* Even more magic... */ -+ struct sun_partition { -+ int start_cylinder; -+ int num_sectors; -+ } partitions[8]; -+ short magic; /* Magic number */ -+ short csum; /* Label xor'd checksum */ -+ } *label; -+ unsigned int i, offset; -+ void *src, *dst; -+ -+ printk("Loading partition table from target %d:\n", unit); -+ // Chip reset -+ stb_bypass(PHYS_JJ_ESP + 3*4, 2); -+ -+ esp_open(&esp); -+ esp_read_capacity(unit); -+ -+ label = esp_read(unit, 0, 0, 512); -+ printk("hw sector: %d, CHS: %d/%d/%d, partitions:\n", esp.disk[unit].hw_sector, -+ label->ncyl, label->ntrks, label->nsect); -+ for (i = 0; i < 8; i++) { -+ printk("%c: %d + %d, id %x, flags %x\n", 'a' + i, label->partitions[i].start_cylinder, -+ label->partitions[i].num_sectors, label->infos[i].id, label->infos[i].flags); -+ esp.disk[unit].part_offset[i] = label->partitions[3].start_cylinder * label->ntrks * label->nsect; -+ } -+ offset = 1; -+ printk("booting sd(0,%d,0):d (offset %d)\n", unit, offset); -+ // Skip a.out header (0x20) -+ dst = (void *)0x4000; -+ src = esp_read(unit, 3, offset, 512); -+ src = (void *)((unsigned int) src + 0x20); -+ memcpy(dst, src, 512 - 0x20); -+ dst = (void *)0x4000 + 512 - 0x20; -+ for (i = 1; i < 7680/512; i++) { -+ src = esp_read(unit, 3, offset + i, 512); -+ memcpy(dst, src, 512); -+ dst += 512; -+ } -+ esp_close(&esp); -+ return 0; -+} -diff -ruN proll_18.orig/src/hconsole.c proll-patch-15/src/hconsole.c ---- proll_18.orig/src/hconsole.c 2002-07-23 05:52:48.000000000 +0000 -+++ proll-patch-15/src/hconsole.c 2005-11-09 18:46:34.000000000 +0000 -@@ -29,6 +29,10 @@ - struct raster r_master; /* For a case of resize, whole fb */ - struct raster r_0; /* malloc() erzatz */ - -+#ifdef QEMU -+extern unsigned int q_height, q_width; -+#endif -+ - int hcon_init(struct hconsole *t, unsigned int a0) - { - struct raster *q, *r; -@@ -42,7 +46,11 @@ - * No probing sequence or argument passing, hardcode everything. XXX - */ - raster8_cons_a(q, 768, 1024, (char *)a0); -+#ifndef QEMU - raster_cons_2(r, q, 768-(24*11)-1, 1024-(8*80)-1, (24*11), (8*80)); -+#else -+ raster_cons_2(r, q, 0, 0, q_height, q_width); -+#endif - t->r_ = r; - t->r0_ = q; - t->f_ = &f_master; -@@ -67,7 +75,7 @@ - return 0; - } - --void hcon_fini (struct hconsole *t) -+void hcon_fini (__attribute((unused)) struct hconsole *t) - { - return; - } -@@ -77,12 +85,12 @@ - { - struct rfont *f = t->f_; - -- if (sy < 0 || sy >= t->ydim_) return -1; -- if (sx < 0 || sx >= t->xdim_) return -1; -+ if (sy < 0 || (unsigned)sy >= t->ydim_) return -1; -+ if (sx < 0 || (unsigned)sx >= t->xdim_) return -1; - if (height < 0) return -1; -- if (sy + height > t->ydim_) height = t->ydim_ - sy; -+ if ((unsigned)sy + (unsigned)height > t->ydim_) height = t->ydim_ - sy; - if (width < 0) return -1; -- if (sx + width > t->xdim_) width = t->xdim_ - sx; -+ if ((unsigned)sx + (unsigned)width > t->xdim_) width = t->xdim_ - sx; - - /* XXX Clear with correct background color */ - (*t->r_->clear_)(t->r_, -@@ -107,10 +115,10 @@ - char c0 = c; - RC_color rfg, rbg; - -- if (y < 0 || y >= t->ydim_) return -1; -- if (x < 0 || x >= t->xdim_) return -1; -+ if (y < 0 || (unsigned)y >= t->ydim_) return -1; -+ if (x < 0 || (unsigned)x >= t->xdim_) return -1; - -- if (t->curson_ && t->ypos_ == y && t->xpos_ == x) { -+ if (t->curson_ && t->ypos_ == (unsigned)y && t->xpos_ == (unsigned)x) { - rfg = t->bg_; rbg = t->fg_; - } else { - rfg = t->fg_; rbg = t->bg_; -@@ -126,9 +134,9 @@ - { - struct rfont *f = t->f_; - -- if (y < 0 || y >= t->ydim_) return -1; -- if (x < 0 || x >= t->xdim_) return -1; -- if (x + count >= t->xdim_) count = t->xdim_ - x; -+ if (y < 0 || (unsigned)y >= t->ydim_) return -1; -+ if (x < 0 || (unsigned)x >= t->xdim_) return -1; -+ if ((unsigned)x + (unsigned)count >= t->xdim_) count = t->xdim_ - x; - - (*t->r_->render_)(t->r_, y*f->height_, x*f->width_, - s, count, t->bg_, t->fg_, f); -@@ -200,8 +208,8 @@ - - rc = 0; - if (dir == SM_UP) { -- if (d < 0 || d >= t->ydim_) return -1; -- if (b <= d || b > t->ydim_) return -1; -+ if (d < 0 || (unsigned)d >= t->ydim_) return -1; -+ if (b <= d || (unsigned)b > t->ydim_) return -1; - if (d + count >= b) count = b - d; - if (d + count >= b) count = b - d; - (*t->r_->yscroll_)(t->r_, -@@ -213,8 +221,8 @@ - count*f->height_, raster_qwidth(t->r_), - t->bg_); - } else if (dir == SM_DOWN) { -- if (d < 0 || d >= t->ydim_) return -1; -- if (b <= d || b > t->ydim_) return -1; -+ if (d < 0 || (unsigned)d >= t->ydim_) return -1; -+ if (b <= d || (unsigned)b > t->ydim_) return -1; - if (d + count >= b) count = b - d; - (*t->r_->yscroll_)(t->r_, - d*f->height_, 0, -diff -ruN proll_18.orig/src/hme.c proll-patch-15/src/hme.c ---- proll_18.orig/src/hme.c 2002-07-23 05:52:52.000000000 +0000 -+++ proll-patch-15/src/hme.c 2005-04-16 06:16:20.000000000 +0000 -@@ -655,10 +655,10 @@ - unsigned int flags, - unsigned int addr) - { -- __asm__ __volatile__(" -- stwa %3, [%0] %2 -- stwa %4, [%1] %2 --" : /* no outputs */ -+ __asm__ __volatile__( -+ "stwa %3, [%0] %2\n\t" -+ "stwa %4, [%1] %2\n\t" -+ : /* no outputs */ - : "r" (&rp->rx_addr), "r" (&rp->rx_flags), - "i" (ASI_PL), "r" (addr), "r" (flags)); - } -@@ -667,10 +667,10 @@ - unsigned int flags, - unsigned int addr) - { -- __asm__ __volatile__(" -- stwa %3, [%0] %2 -- stwa %4, [%1] %2 --" : /* no outputs */ -+ __asm__ __volatile__( -+ "stwa %3, [%0] %2\n\t" -+ "stwa %4, [%1] %2\n\t" -+ : /* no outputs */ - : "r" (&tp->tx_addr), "r" (&tp->tx_flags), - "i" (ASI_PL), "r" (addr), "r" (flags)); - } -@@ -2404,7 +2404,7 @@ - TXD(("[%d]", elem)); - this = &txbase[elem]; - #ifdef __sparc_v9__ -- __asm__ __volatile__("lduwa [%1] %2, %0" -+ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" - : "=r" (flags) - : "r" (&this->tx_flags), "i" (ASI_PL)); - #else -@@ -2447,7 +2447,7 @@ - RXD(("RX<")); - this = &rxbase[elem]; - #ifdef __sparc_v9__ -- __asm__ __volatile__("lduwa [%1] %2, %0" -+ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" - : "=r" (flags) - : "r" (&this->rx_flags), "i" (ASI_PL)); - #else -@@ -2530,7 +2530,7 @@ - elem = NEXT_RX(elem); - this = &rxbase[elem]; - #ifdef __sparc_v9__ -- __asm__ __volatile__("lduwa [%1] %2, %0" -+ __asm__ __volatile__("lduwa [%1] %2, %0\n\t" - : "=r" (flags) - : "r" (&this->rx_flags), "i" (ASI_PL)); - #else -diff -ruN proll_18.orig/src/iommu.c proll-patch-15/src/iommu.c ---- proll_18.orig/src/iommu.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch-15/src/iommu.c 2005-08-14 10:08:17.000000000 +0000 -@@ -36,7 +36,7 @@ - unsigned int pa, ba; - unsigned int npages; - unsigned int mva, mpa; -- int i; -+ unsigned int i; - unsigned int *iopte; - - npages = (size + (PAGE_SIZE-1)) / PAGE_SIZE; -diff -ruN proll_18.orig/src/lat7_2.bm proll-patch-15/src/lat7_2.bm ---- proll_18.orig/src/lat7_2.bm 1999-02-27 05:48:54.000000000 +0000 -+++ proll-patch-15/src/lat7_2.bm 2004-11-13 15:50:49.000000000 +0000 -@@ -1,6 +1,6 @@ - #define lat7_2_width 128 - #define lat7_2_height 88 --static unsigned char lat7_2_bits[] = { -+static unsigned const char lat7_2_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18, - 0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02, -diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch-15/src/lat7_2_swapped.bm ---- proll_18.orig/src/lat7_2_swapped.bm 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/src/lat7_2_swapped.bm 2004-11-13 15:50:49.000000000 +0000 -@@ -0,0 +1,121 @@ -+#define lat7_2_width 128 -+#define lat7_2_height 88 -+static unsigned const char lat7_2_bits[] = { -+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x2a, 0x00, 0x55, 0x00, 0x00, 0x48, -+ 0x48, 0x78, 0x48, 0x5f, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x78, 0x40, -+ 0x70, 0x40, 0x4f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x30, 0x40, 0x40, -+ 0x40, 0x3e, 0x09, 0x0e, 0x0a, 0x09, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, -+ 0x7f, 0x08, 0x0e, 0x08, 0x08, 0x00, 0x00, 0x0e, 0x0a, 0x0e, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, -+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x44, 0x64, 0x54, 0x4c, 0x54, 0x10, 0x10, -+ 0x10, 0x1f, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x1f, 0x04, 0x04, 0x04, -+ 0x04, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, -+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, -+ 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, -+ 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, -+ 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x00, -+ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, -+ 0x06, 0x0c, 0x18, 0x30, 0x18, 0x6c, 0x36, 0x18, 0x0c, 0x00, 0x00, 0x60, -+ 0x30, 0x18, 0x0c, 0x18, 0x36, 0x6c, 0x18, 0x30, 0x00, 0x00, 0x7f, 0x36, -+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x7e, -+ 0x18, 0x7e, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x78, -+ 0x30, 0x72, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, -+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, -+ 0x00, 0x00, 0x00, 0x66, 0x66, 0x22, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x00, 0x00, 0x00, -+ 0x00, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, -+ 0x72, 0x56, 0x6c, 0x18, 0x36, 0x6a, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x18, -+ 0x24, 0x28, 0x30, 0x4a, 0x44, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x18, -+ 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x18, -+ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0x7e, 0x3c, -+ 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -+ 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, -+ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00, -+ 0x00, 0x3c, 0x46, 0x4e, 0x5a, 0x72, 0x62, 0x3c, 0x00, 0x00, 0x00, 0x00, -+ 0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, -+ 0x66, 0x06, 0x0c, 0x18, 0x32, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -+ 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, -+ 0x66, 0x7e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x60, 0x7c, 0x66, -+ 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x7c, 0x66, 0x66, -+ 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x06, 0x0c, 0x18, 0x30, -+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, -+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, -+ 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, -+ 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -+ 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x5e, -+ 0x56, 0x5e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x66, -+ 0x7e, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x66, -+ 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, -+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, -+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x62, 0x7e, 0x00, -+ 0x00, 0x00, 0x00, 0x7e, 0x62, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, 0x00, -+ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x6e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, -+ 0x00, 0x66, 0x66, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, -+ 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7e, -+ 0x46, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6c, -+ 0x78, 0x70, 0x78, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, -+ 0x60, 0x60, 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x77, 0x7f, -+ 0x6b, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x76, 0x7e, 0x6e, -+ 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, -+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, -+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x6e, 0x3c, 0x02, -+ 0x00, 0x00, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x00, 0x00, -+ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x3c, 0x06, 0x66, 0x3c, 0x00, 0x00, 0x00, -+ 0x00, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, -+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x66, -+ 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, -+ 0x63, 0x6b, 0x6b, 0x7f, 0x36, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3c, -+ 0x18, 0x3c, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, -+ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x46, 0x0c, 0x18, 0x30, -+ 0x62, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, -+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, -+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, -+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, -+ 0x00, 0x08, 0x10, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x60, -+ 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, -+ 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -+ 0x7e, 0x60, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x78, -+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x66, 0x66, -+ 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x60, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, -+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x1c, 0x00, -+ 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, -+ 0x00, 0x00, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x7c, 0x66, 0x00, 0x00, 0x00, -+ 0x00, 0x60, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x76, 0x7f, 0x6b, 0x6b, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, -+ 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, -+ 0x66, 0x66, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x72, 0x60, -+ 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x3c, 0x06, -+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x78, 0x30, 0x30, 0x36, 0x1c, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3a, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x63, 0x6b, 0x6b, 0x6b, 0x36, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, 0x00, 0x00, 0x00, -+ 0x00, 0x7e, 0x0c, 0x18, 0x30, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, -+ 0x18, 0x30, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, -+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x30, 0x18, 0x18, 0x0c, -+ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00}; -diff -ruN proll_18.orig/src/le.c proll-patch-15/src/le.c ---- proll_18.orig/src/le.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch-15/src/le.c 2005-04-16 06:16:20.000000000 +0000 -@@ -185,8 +185,6 @@ - unsigned short rap; /* register address port */ - }; - --int sparc_lance_debug = 2; -- - /* The Lance uses 24 bit addresses */ - /* On the Sun4c the DVMA will provide the remaining bytes for us */ - /* On the Sun4m we have to instruct the ledma to provide them */ -@@ -771,7 +769,7 @@ - /* Clear the slack of the packet, do I need this? */ - /* For a firewall its a good idea - AC */ - if (len != skblen) -- bzero((char *) &ib->tx_buf [entry][skblen], len - skblen); -+ memset((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); - - /* Now, give the packet to the lance */ - ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); -diff -ruN proll_18.orig/src/net.h proll-patch-15/src/net.h ---- proll_18.orig/src/net.h 1999-12-15 17:20:17.000000000 +0000 -+++ proll-patch-15/src/net.h 2005-08-14 10:17:02.000000000 +0000 -@@ -124,7 +124,7 @@ - extern int udp_open __P((t_ipaddr daddr, int source, int dest)); - - /* Read from a UDP socket */ --extern int udp_read __P((char *buf, int bufsize, int timeout, char abortch)); -+extern int udp_read(char *buf, unsigned int bufsize, int timeout); - - /* Write to a UDP socket */ - extern int udp_write __P((char *buf, int writelen)); -diff -ruN proll_18.orig/src/netinit.c proll-patch-15/src/netinit.c ---- proll_18.orig/src/netinit.c 2002-09-13 21:53:33.000000000 +0000 -+++ proll-patch-15/src/netinit.c 2004-11-13 15:50:49.000000000 +0000 -@@ -49,13 +49,20 @@ - unsigned char myhwaddr[ETH_ALEN]; /* my own hardware addr */ - t_ipaddr myipaddr; /* my own IP address */ - t_ipaddr mynetmask; /* my own netmask */ -- char *net_module_name; /* name of init module */ - t_ipaddr servaddr; /* IP of RARP&TFTP server */ - - /* Broadcast hardware address */ --unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -+const unsigned char bcasthw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - -+unsigned int seed; -+ -+/* This is taken from x86 to be used in network kernel. Returns 15 bits. */ -+short int random() -+{ -+ seed = (seed + 23968)*0x015A4E35 >> 1; -+ return seed & 0x7FFF; -+} - - /* - ************************************************************************** -@@ -104,10 +111,17 @@ - */ - void init_net() - { -+ /* Avoid data segment allocations */ -+ seed = 151; -+ - /* Initialize the different network layer modules */ - init_packet(); -- if (!init_arp() || !init_udp()) { -- printf("\nERROR: init_%s\n", net_module_name); -+ if (!init_arp()) { -+ printf("\nERROR: init_arp\n"); -+ fatal(); -+ } -+ if (!init_udp()) { -+ printf("\nERROR: init_udp\n"); - fatal(); - } - } -diff -ruN proll_18.orig/src/netpriv.h proll-patch-15/src/netpriv.h ---- proll_18.orig/src/netpriv.h 1999-04-27 05:39:37.000000000 +0000 -+++ proll-patch-15/src/netpriv.h 2005-08-14 10:12:20.000000000 +0000 -@@ -83,7 +83,7 @@ - */ - struct device *dev; - char *data; -- int len; -+ unsigned int len; - int protocol; - unsigned char ip_summed; - }; -@@ -130,10 +130,9 @@ - * - */ - extern unsigned char myhwaddr[ETH_ALEN]; /* my own hardware address */ --extern unsigned char bcasthw[ETH_ALEN]; /* broadcast hardware addr */ -+extern const unsigned char bcasthw[ETH_ALEN]; /* broadcast hardware addr */ - extern t_ipaddr myipaddr; /* my own IP address */ - extern t_ipaddr mynetmask; /* netmask for my network */ --extern char *net_module_name; /* initialized module's name */ - extern t_ipaddr servaddr; /* server IP address */ - - -@@ -150,7 +149,7 @@ - extern unsigned char *reg_type __P((int typeval, int (* receive)())); - - /* Write a packet to the network */ --extern int write_packet __P((int bufsize, int typeval, unsigned char *addr)); -+extern int write_packet __P((int bufsize, int typeval, const unsigned char *addr)); - - /* Empty read buffer */ - extern void empty_buf __P((void)); -diff -ruN proll_18.orig/src/openprom.h proll-patch-15/src/openprom.h ---- proll_18.orig/src/openprom.h 2002-07-14 02:26:30.000000000 +0000 -+++ proll-patch-15/src/openprom.h 2005-05-13 16:23:14.000000000 +0000 -@@ -54,29 +54,29 @@ - }; - - struct linux_mem_v0 { -- struct linux_mlist_v0 **v0_totphys; -- struct linux_mlist_v0 **v0_prommap; -- struct linux_mlist_v0 **v0_available; /* What we can use */ -+ struct linux_mlist_v0 * const *v0_totphys; -+ struct linux_mlist_v0 * const *v0_prommap; -+ struct linux_mlist_v0 * const *v0_available; /* What we can use */ - }; - - /* Arguments sent to the kernel from the boot prompt. */ - struct linux_arguments_v0 { -- char *argv[8]; -+ const char *argv[8]; - char args[100]; - char boot_dev[2]; - int boot_dev_ctrl; - int boot_dev_unit; - int dev_partition; -- char *kernel_file_name; -+ const char *kernel_file_name; - void *aieee1; /* XXX */ - }; - - /* V2 and up boot things. */ - struct linux_bootargs_v2 { -- char **bootpath; -- char **bootargs; -- int *fd_stdin; -- int *fd_stdout; -+ const char **bootpath; -+ const char **bootargs; -+ const int *fd_stdin; -+ const int *fd_stdout; - }; - - /* The top level PROM vector. */ -@@ -91,13 +91,13 @@ - struct linux_mem_v0 pv_v0mem; - - /* Node operations. */ -- struct linux_nodeops *pv_nodeops; -+ const struct linux_nodeops *pv_nodeops; - - char **pv_bootstr; - struct linux_dev_v0_funcs pv_v0devops; - -- char *pv_stdin; -- char *pv_stdout; -+ const char *pv_stdin; -+ const char *pv_stdout; - #define PROMDEV_KBD 0 /* input from keyboard */ - #define PROMDEV_SCREEN 0 /* output to screen */ - #define PROMDEV_TTYA 1 /* in/out to ttya */ -@@ -127,7 +127,7 @@ - void (*v2_eval)(char *str); - } pv_fortheval; - -- struct linux_arguments_v0 **pv_v0bootargs; -+ const struct linux_arguments_v0 * const *pv_v0bootargs; - - /* Get ether address. */ - unsigned int (*pv_enaddr)(int d, char *enaddr); -@@ -175,7 +175,7 @@ - int (*no_proplen)(int node, char *name); - int (*no_getprop)(int node, char *name, char *val); - int (*no_setprop)(int node, char *name, char *val, int len); -- char * (*no_nextprop)(int node, char *name); -+ const char * (*no_nextprop)(int node, char *name); - }; - - /* More fun PROM structures for device probing. */ -diff -ruN proll_18.orig/src/packet.c proll-patch-15/src/packet.c ---- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000 -+++ proll-patch-15/src/packet.c 2005-08-14 10:12:49.000000000 +0000 -@@ -41,7 +41,7 @@ - int aligner; - } wbuf; - static struct sk_buff *rskb; --static int nqskb = 0; -+static int nqskb; - - - void init_packet() -@@ -62,6 +62,8 @@ - for (i = 0; i < MAXSKBS; i++) { - skev[i].skb.allocn = i; - } -+ -+ nqskb = 0; - } - - unsigned char *reg_type(int ptype, int (*func)()) -@@ -81,7 +83,7 @@ - return wbuf.s; - } - --int write_packet(int leng, int type, unsigned char *dst) -+int write_packet(int leng, int type, const unsigned char *dst) - { - struct sk_buff *skb; - unsigned char *s; -@@ -209,12 +211,12 @@ - /* - */ - void --eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int len, int base) -+eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int len, __attribute__((unused)) int base) - { - bcopy(src, dest->data, len); - } - --unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) -+unsigned short eth_type_trans(struct sk_buff *skb, __attribute__((unused)) struct device *dev) - { - unsigned char *s = skb->data + 12; - return s[0] << 8 | s[1]; /* Network order word */ -diff -ruN proll_18.orig/src/printf.c proll-patch-15/src/printf.c ---- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000 -+++ proll-patch-15/src/printf.c 2005-08-14 10:07:26.000000000 +0000 -@@ -19,7 +19,7 @@ - static void printn(struct prf_fp *, unsigned long, unsigned int); - static void putchar(char, struct prf_fp *); - --static char hextab[] = "0123456789ABCDEF"; -+static const char hextab[] = "0123456789ABCDEF"; - - /* - * Scaled down version of C Library printf. -@@ -41,7 +41,7 @@ - void - prf(struct prf_fp *filog, char *fmt, va_list adx) - { -- register c; -+ register int c; - char *s; - - for(;;) { -@@ -60,7 +60,7 @@ - putchar(va_arg(adx,unsigned), filog); - } else if(c == 's') { - s = va_arg(adx,char*); -- while(c = *s++) -+ while((c = *s++)) - putchar(c,filog); - } else if (c == 'l' || c == 'O') { - printn(filog, (long)va_arg(adx,long), c=='l'?10:8); -@@ -77,10 +77,6 @@ - char prbuf[24]; - register char *cp; - -- if (b == 10 && n < 0) { -- putchar('-',filog); -- n = (~n) + 1; /* n = -n */ -- } - cp = prbuf; - do - *cp++ = hextab[(unsigned int)(n%b)]; -diff -ruN proll_18.orig/src/rconsole.c proll-patch-15/src/rconsole.c ---- proll_18.orig/src/rconsole.c 1999-01-16 07:16:55.000000000 +0000 -+++ proll-patch-15/src/rconsole.c 2005-08-14 10:25:53.000000000 +0000 -@@ -28,12 +28,18 @@ - * move to California. Only plain lat7 survived. - * I recreated lat7-1 changes in lat7-2. --zaitcev - */ -+#ifdef ORIG - #include "lat7_2.bm" /* lat7_1.bm */ -+#else -+#include "lat7_2_swapped.bm" /* lat7_1.bm */ -+#endif - #define LAT7_NCHARS 128 - #define LAT7_HEIGHT 11 - #define LAT7_WIDTH 8 - -+#ifdef ORIG - static Rf_scan lat7_body[ LAT7_NCHARS*LAT7_HEIGHT ]; -+#endif - - #if 1 - /* -@@ -46,18 +52,18 @@ - #endif - - static __inline__ void stfb_w(void *ptr, unsigned int data) { -- __asm__ __volatile__ ("sta %0, [%1] %2" : : -+ __asm__ __volatile__ ("sta %0, [%1] %2\n\t" : : - "r" (data), "r" (ptr), "i" (ASI_M_BYPASS)); - } - - static __inline__ void stfb_b(void *ptr, unsigned int data) { -- __asm__ __volatile__ ("stba %0, [%1] %2" : : -+ __asm__ __volatile__ ("stba %0, [%1] %2\n\t" : : - "r" (data), "r" (ptr), "i" (ASI_M_BYPASS)); - } - - static __inline__ unsigned int ldfb_w(void *ptr) { - unsigned int data; -- __asm__ __volatile__ ("lda [%1] %2, %0" : -+ __asm__ __volatile__ ("lda [%1] %2, %0\n\t" : - "=r" (data) : - "r" (ptr), "i" (ASI_M_BYPASS)); - return data; -@@ -65,7 +71,7 @@ - - static __inline__ unsigned int ldfb_b(void *ptr) { - unsigned int data; -- __asm__ __volatile__ ("lduba [%1] %2, %0" : -+ __asm__ __volatile__ ("lduba [%1] %2, %0\n\t" : - "=r" (data) : - "r" (ptr), "i" (ASI_M_BYPASS)); - return data; -@@ -94,6 +100,7 @@ - - #endif - -+#ifdef ORIG - static inline int swapbits(int w0) - { - int w1 = 0; -@@ -105,13 +112,16 @@ - } - return w1; - } -+#endif - - void font_cons_7(struct rfont *p) - { -+#ifdef ORIG - int x; - int col = 0; - int row = 0; - int erow = 0; -+ - for (x = 0; x < LAT7_NCHARS*LAT7_HEIGHT; x++ ) { - lat7_body[ (erow * lat7_2_width/8 + col) * LAT7_HEIGHT + row ] = - swapbits(lat7_2_bits[x]) & 0xFF; -@@ -124,6 +134,9 @@ - } - } - p->body_ = lat7_body; -+#else -+ p->body_ = lat7_2_bits; -+#endif - p->nchars_ = LAT7_NCHARS; - p->width_ = LAT7_WIDTH; - p->height_ = LAT7_HEIGHT; -@@ -175,7 +188,7 @@ - r->render_ = p->render_; - } - --void raster_dest(struct raster *r) -+void raster_dest(__attribute((unused)) struct raster *r) - { - } - -diff -ruN proll_18.orig/src/rconsole.h proll-patch-15/src/rconsole.h ---- proll_18.orig/src/rconsole.h 1999-01-16 05:00:59.000000000 +0000 -+++ proll-patch-15/src/rconsole.h 2004-11-13 15:50:49.000000000 +0000 -@@ -13,10 +13,10 @@ - */ - - #define RF_MAXWIDTH 16 --typedef unsigned short Rf_scan; /* __w16 to be used */ -+typedef unsigned char Rf_scan; /* __w16 to be used */ - - struct rfont { -- Rf_scan *body_; -+ const Rf_scan *body_; - int nchars_; /* 128 for ASCII ... 65536 for Unicode */ - int width_; /* [Pixels]. Maximum size is 16. */ - int height_; /* [Pixels == scan lines]. */ -diff -ruN proll_18.orig/src/romlib.h proll-patch-15/src/romlib.h ---- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000 -+++ proll-patch-15/src/romlib.h 2005-04-16 20:32:49.000000000 +0000 -@@ -72,13 +72,13 @@ - */ - #define memcpy(dst, src, len) bcopy(src, dst, len) - #define memcmp(x1, x2, len) bcmp(x1, x2, len) --#define memset(p, len, zero) bzero(p, len) --extern void bcopy(void *b1, void *b2, int length); --extern int bcmp(void *b1, void *b2, int length); --extern void bzero(void *b, int c); -+extern void bcopy(const void *b1, void *b2, int length); -+extern int bcmp(const void *b1, const void *b2, int length); -+typedef unsigned int size_t; -+extern void *memset(void *p, int c, size_t len); - /* gcc complains about "conflicting types for builtin function strlen". */ - #define strlen(s) ssize(s) --extern int ssize(char *s); -+extern int ssize(const char *s); - - - /* -diff -ruN proll_18.orig/src/sched_4m.c proll-patch-15/src/sched_4m.c ---- proll_18.orig/src/sched_4m.c 1999-04-27 05:48:51.000000000 +0000 -+++ proll-patch-15/src/sched_4m.c 2005-08-14 10:18:14.000000000 +0000 -@@ -108,7 +108,7 @@ - static int set_bolt; /* Tick counter limit */ - static struct handsc hndv[16]; - --static unsigned int intr_to_mask[16] = { -+static unsigned const int intr_to_mask[16] = { - 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - }; -@@ -130,7 +130,7 @@ - int /* 0 - not expired yet; <>0 - timer expired */ - chk_timeout() - { -- int lim = (((1000000/HZ) + 1) << 10); -+ unsigned int lim = (((1000000/HZ) + 1) << 10); - unsigned int clear; - unsigned int intc; - int n; -@@ -182,7 +182,7 @@ - struct handsc *hndp; - unsigned int mask; - -- if (irq < 0 || irq >= 16) { -+ if (irq == 0 || irq >= 16) { - printk("request_irq: bad irq %d\n", irq); - return -1; - } -@@ -207,7 +207,7 @@ - { - struct handsc *hndp; - -- if (irq < 0 || irq >= 16) { -+ if (irq == 0 || irq >= 16) { - printk("free_irq: bad irq %d\n", irq); - return; - } -diff -ruN proll_18.orig/src/swap.c proll-patch-15/src/swap.c ---- proll_18.orig/src/swap.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/src/swap.c 2004-11-13 15:50:49.000000000 +0000 -@@ -0,0 +1,21 @@ -+// Convert the lat7 font so that no conversion is needed at runtime. -+#define ORIG -+#include "rconsole.c" -+ -+#include -+ -+int main() -+{ -+ struct rfont p; -+ int i; -+ -+ font_cons_7(&p); -+ -+ printf(" "); -+ for (i = 0; i < LAT7_NCHARS*LAT7_HEIGHT; i++) { -+ printf("0x%02x, ", p.body_[i]); -+ if ((i % 12) == 11) -+ printf("\n "); -+ } -+ printf("\n"); -+} -diff -ruN proll_18.orig/src/system.c proll-patch-15/src/system.c ---- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000 -+++ proll-patch-15/src/system.c 2005-04-16 06:16:20.000000000 +0000 -@@ -298,8 +298,8 @@ - } - - /* We need to start from LOADBASE, but kernel wants PAGE_SIZE. */ -- pa = PAGE_SIZE; -- for (va = PAGE_SIZE; va < LOWMEMSZ; va += PAGE_SIZE) { -+ pa = 0; -+ for (va = 0; va < LOWMEMSZ; va += PAGE_SIZE) { - map_page(l1, va, pa, 0, highbase); - pa += PAGE_SIZE; - } -@@ -507,30 +507,44 @@ - { - char *p; - -- if ((p = mem_alloc(t, size, align)) != 0) bzero(p, size); -+ if ((p = mem_alloc(t, size, align)) != 0) memset(p, 0, size); - return p; - } - - /* - * Library functions - */ --void bzero(void *s, int len) { -- while (len--) *((char *)s)++ = 0; -+void *memset(void *s, int c, size_t len) -+{ -+ void *p = s; -+ -+ while (len--) { -+ *(char *)s = c; -+ s++; -+ } -+ return p; - } - --void bcopy(void *f, void *t, int len) { -- while (len--) *((char *)t)++ = *((char *)f)++; -+void bcopy(const void *f, void *t, int len) { -+ while (len--) { -+ *(char *)t = *(char *)f; -+ f++; -+ t++; -+ } - } - - /* Comparison is 7-bit */ --int bcmp(void *s1, void *s2, int len) -+int bcmp(const void *s1, const void *s2, int len) - { - int i; - char ch; - - while (len--) { -- ch = *((char *)s1)++; -- if ((i = ch - *((char *)s2)++) != 0) -+ ch = *(char *)s1; -+ i = ch - *(char *)s2; -+ s1++; -+ s2++; -+ if (i != 0) - return i; - if (ch == 0) - return 0; -@@ -538,8 +552,8 @@ - return 0; - } - --int strlen(char *s) { -- char *p; -+int strlen(const char *s) { -+ const char *p; - for (p = s; *p != 0; p++) { } - return p - s; - } -@@ -560,14 +574,6 @@ - va_end(x1); - } - --/* This is taken from x86 to be used in network kernel. Returns 15 bits. */ --short int random() --{ -- static unsigned int seed = 151; -- seed = (seed + 23968)*0x015A4E35 >> 1; -- return seed & 0x7FFF; --} -- - void fatal() - { - printk("fatal."); -diff -ruN proll_18.orig/src/system.h proll-patch-15/src/system.h ---- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000 -+++ proll-patch-15/src/system.h 2005-04-16 06:16:20.000000000 +0000 -@@ -16,7 +16,7 @@ - #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */ - #define NCTX_SWIFT 0x100 - --#define MAX_BANKS 3 /* Allocation for all machines */ -+#define MAX_BANKS 8 /* Allocation for all machines */ - - #ifndef __ASSEMBLY__ - struct bank { -@@ -164,10 +164,10 @@ - - extern __inline__ void setipl(unsigned long __orig_psr) - { -- __asm__ __volatile__(" -- wr %0, 0x0, %%psr -- nop; nop; nop --" : /* no outputs */ -+ __asm__ __volatile__( -+ "wr %0, 0x0, %%psr\n\t" -+ "nop; nop; nop\n\t" -+ : /* no outputs */ - : "r" (__orig_psr) - : "memory", "cc"); - } -@@ -176,13 +176,13 @@ - { - unsigned long tmp; - -- __asm__ __volatile__(" -- rd %%psr, %0 -- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ -- or %0, %1, %0 -- wr %0, 0x0, %%psr -- nop; nop; nop --" : "=r" (tmp) -+ __asm__ __volatile__( -+ "rd %%psr, %0\n\t" -+ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ -+ "or %0, %1, %0\n\t" -+ "wr %0, 0x0, %%psr\n\t" -+ "nop; nop; nop\n\t" -+ : "=r" (tmp) - : "i" (PSR_PIL) - : "memory"); - } -@@ -191,13 +191,13 @@ - { - unsigned long tmp; - -- __asm__ __volatile__(" -- rd %%psr, %0 -- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ -- andn %0, %1, %0 -- wr %0, 0x0, %%psr -- nop; nop; nop --" : "=r" (tmp) -+ __asm__ __volatile__( -+ "rd %%psr, %0\n\t" -+ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ -+ "andn %0, %1, %0\n\t" -+ "wr %0, 0x0, %%psr\n\t" -+ "nop; nop; nop\n\t" -+ : "=r" (tmp) - : "i" (PSR_PIL) - : "memory"); - } -@@ -214,18 +214,18 @@ - { - unsigned long retval; - -- __asm__ __volatile__(" -- rd %%psr, %0 -- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ -- and %0, %2, %%g1 -- and %1, %2, %%g2 -- xorcc %%g1, %%g2, %%g0 -- be 1f -- nop -- wr %0, %2, %%psr -- nop; nop; nop; --1: --" : "=r" (retval) -+ __asm__ __volatile__( -+ "rd %%psr, %0\n\t" -+ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ -+ "and %0, %2, %%g1\n\t" -+ "and %1, %2, %%g2\n\t" -+ "xorcc %%g1, %%g2, %%g0\n\t" -+ "be 1f\n\t" -+ "nop\n\t" -+ "wr %0, %2, %%psr\n\t" -+ "nop; nop; nop;\n\t" -+ "1:\n\t" -+ : "=r" (retval) - : "r" (__new_psr), "i" (PSR_PIL) - : "g1", "g2", "memory", "cc"); - -@@ -236,13 +236,13 @@ - { - unsigned long retval; - -- __asm__ __volatile__(" -- rd %%psr, %0 -- nop; nop; nop; /* Sun4m + Cypress + SMP bug */ -- or %0, %1, %%g1 -- wr %%g1, 0x0, %%psr -- nop; nop; nop --" : "=r" (retval) -+ __asm__ __volatile__( -+ "rd %%psr, %0\n\t" -+ "nop; nop; nop;\n\t" /* Sun4m + Cypress + SMP bug */ -+ "or %0, %1, %%g1\n\t" -+ "wr %%g1, 0x0, %%psr\n\t" -+ "nop; nop; nop\n\t" -+ : "=r" (retval) - : "i" (PSR_PIL) - : "g1", "memory"); - -diff -ruN proll_18.orig/src/tftp.c proll-patch-15/src/tftp.c ---- proll_18.orig/src/tftp.c 2002-09-13 21:53:34.000000000 +0000 -+++ proll-patch-15/src/tftp.c 2005-08-14 10:16:15.000000000 +0000 -@@ -127,7 +127,7 @@ - int len; - - /* Read packet with timeout */ -- len = udp_read((char *)(&inpbuf), sizeof(inpbuf), TFTP_TIMEOUT, CHR_ESC); -+ len = udp_read((char *)(&inpbuf), sizeof(inpbuf), TFTP_TIMEOUT); - if (len == 0) { - printf("TFTP: Timeout\n"); - return(ERR_TIMEOUT); -diff -ruN proll_18.orig/src/udp.c proll-patch-15/src/udp.c ---- proll_18.orig/src/udp.c 2001-12-24 05:12:53.000000000 +0000 -+++ proll-patch-15/src/udp.c 2005-08-14 10:17:19.000000000 +0000 -@@ -76,12 +76,9 @@ - * - * Open a new UDP socket. - */ --int udp_open(daddr, source, dest) --t_ipaddr daddr; --int source; --int dest; -+int udp_open(t_ipaddr daddr, int source, int dest) - { -- register unsigned char *addr; -+ const unsigned char *addr; - - /* Set global variables */ - usource = source; -@@ -101,16 +98,13 @@ - * - * IP receiver routine - */ --static int ip_recv(buf, bufsize, addr) --unsigned char *buf; --int bufsize; --unsigned char *addr; -+static int ip_recv(unsigned char *buf, unsigned int bufsize, unsigned char *addr) - { - struct iphdr *ipp = ((struct iphdr *)buf); - struct udphdr *udpp = ((struct udphdr *)(buf + IP_MIN_HSIZE)); - struct udp_pseudo psehdr; - -- int size; -+ unsigned int size; - t_ipaddr dadr; - - #ifdef DEBUG -@@ -194,13 +188,9 @@ - * - * Read one packet from a UDP socket - */ --int udp_read(buf, bufsize, timeout, abortch) --char *buf; --int bufsize; --int timeout; --char abortch; -+int udp_read(char *buf, unsigned int bufsize, int timeout) - { -- int len; -+ unsigned int len; - - /* Wait until we get something */ - set_timeout(timeout); -@@ -299,9 +289,6 @@ - */ - int init_udp() - { -- /* Set module name for error handling */ -- net_module_name = "udp"; -- - /* Register IP packet type and set write buffer pointer */ - if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL) - return(FALSE); -diff -ruN proll_18.orig/src/udp.h proll-patch-15/src/udp.h ---- proll_18.orig/src/udp.h 2001-12-24 05:12:34.000000000 +0000 -+++ proll-patch-15/src/udp.h 2005-08-14 10:16:40.000000000 +0000 -@@ -53,7 +53,7 @@ - extern int udp_open __P((t_ipaddr daddr, int source, int dest)); - - /* Read from a UDP socket */ --extern int udp_read __P((char *buf, int bufsize, int timeout, char abortch)); -+extern int udp_read(char *buf, unsigned int bufsize, int timeout); - - /* Write to a UDP socket */ - extern int udp_write __P((char *buf, int writelen)); -diff -ruN proll_18.orig/src/vcons_zs.c proll-patch-15/src/vcons_zs.c ---- proll_18.orig/src/vcons_zs.c 1970-01-01 00:00:00.000000000 +0000 -+++ proll-patch-15/src/vcons_zs.c 2005-08-14 10:25:51.000000000 +0000 -@@ -0,0 +1,68 @@ -+/** -+ ** Console over 'zs' (Zilog serial port) -+ ** Copyright 1999 Pete Zaitcev -+ ** This code is licensed under GNU General Public License. -+ **/ -+ -+#include "vconsole.h" -+#include -+ -+#define ZS_DATA 0x02 -+ -+int vcon_zs_init(struct vconterm *t, unsigned int a0) -+{ -+ -+ t->impl = (void *) a0; -+ -+ t->vc_x = 0; t->vc_y = 0; -+ t->backp = 0; t->backc = 0; -+ -+ stb_bypass(a0, 3); // reg 3 -+ stb_bypass(a0, 1); // enable rx -+ -+ stb_bypass(a0, 5); // reg 5 -+ stb_bypass(a0, 8); // enable tx -+ -+ return 0; -+} -+ -+int vcon_zs_putch(struct vconterm *t, char c) -+{ -+ unsigned zs_ptr = (unsigned) t->impl; -+ -+ //while ((ldb_bypass(zs_ptr + ZS_LSR) & 0x60) != 0x60) { } -+ stb_bypass(zs_ptr + ZS_DATA, c); -+ return 0; -+} -+ -+int vcon_zs_write(struct vconterm *t, char *data, int leng) -+{ -+ while (leng != 0) { -+ leng--; -+ vcon_zs_putch(t, *data++); -+ } -+ return leng; -+} -+ -+int vcon_zs_read(struct vconterm *t, char *data, __attribute((unused)) int leng) -+{ -+ unsigned zs_ptr = (unsigned) t->impl; -+ -+ while ((ldb_bypass(zs_ptr) & 1) != 1) { } -+ *data = ldb_bypass(zs_ptr + ZS_DATA); -+ return 0; -+} -+ -+int vcon_zs_getch(struct vconterm *t) -+{ -+ unsigned zs_ptr = (unsigned) t->impl; -+ -+ while ((ldb_bypass(zs_ptr) & 1) != 1) { } -+ return ldb_bypass(zs_ptr + ZS_DATA) & 0xff; -+} -+ -+void vcon_zs_fini(__attribute((unused)) struct vconterm *t) -+{ -+ /* violent crash in the end */ -+ ; -+} -diff -ruN proll_18.orig/src/vconsole.c proll-patch-15/src/vconsole.c ---- proll_18.orig/src/vconsole.c 1999-11-08 03:10:28.000000000 +0000 -+++ proll-patch-15/src/vconsole.c 2005-08-14 10:24:49.000000000 +0000 -@@ -7,12 +7,17 @@ - #include "vconsole.h" - - #include "hconsole.h" -+#include - - static void vcon_i_cursfeed(struct vconterm *t); - static void vcon_i_backflush(struct vconterm *t); - - struct hconsole hcons0; - -+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, -+ EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, -+ ESpalette }; -+ - int vcon_init(struct vconterm *t, unsigned int a0) - { - struct hconsole *hconp; -@@ -25,11 +30,49 @@ - - t->vc_x = 0; t->vc_y = 0; - t->backp = 0; t->backc = 0; -+ t->vc_state = ESnormal; - - hcon_clear(hconp, 0, 0, hconp->ydim_, hconp->xdim_); - return 0; - } - -+/* -+ * gotoxy() must verify all boundaries, because the arguments -+ * might also be negative. If the given position is out of -+ * bounds, the cursor is placed at the nearest margin. -+ */ -+static void gotoxy(struct vconterm *vc, int new_x, int new_y) -+{ -+ int max_x, max_y; -+ struct hconsole *hconp = vc->impl; -+ -+ max_x = hcon_qxdim(hconp); -+ max_y = hcon_qydim(hconp); -+ -+ if (new_x < 0) -+ vc->vc_x = 0; -+ else { -+ if (new_x >= max_x) -+ vc->vc_x = max_x - 1; -+ else -+ vc->vc_x = new_x; -+ } -+ -+ if (new_y < 0) -+ vc->vc_y = 0; -+ else if (new_y >= max_y) -+ vc->vc_y = max_y - 1; -+ else -+ vc->vc_y = new_y; -+ -+} -+ -+/* for absolute user moves, when decom is set */ -+static void gotoxay(struct vconterm *t, int new_x, int new_y) -+{ -+ gotoxy(t, new_x, new_y); -+} -+ - int vcon_write(struct vconterm *t, char *data, int leng) - { - int l = leng; -@@ -40,29 +83,101 @@ - if (l <= 0) break; - c = *data++; --l; - -- switch (c) { -- case 0x07: /* Bell */ -- vcon_i_backflush(t); -- break; -- case 0x0A: /* Linefeed */ -- vcon_i_backflush(t); -- vcon_i_cursfeed(t); -+ switch(t->vc_state) { -+ case ESesc: -+ t->vc_state = ESnormal; -+ switch (c) { -+ case '[': -+ t->vc_state = ESsquare; -+ break; -+ case 'M': -+ hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); -+ break; -+ default: -+ //printk("Unhandled escape code '%c'\n", c); -+ break; -+ } - break; -- case 0x0D: /* Return */ -- vcon_i_backflush(t); -- t->vc_x = 0; -+ case ESsquare: -+ for(t->vc_npar = 0 ; t->vc_npar < NPAR ; t->vc_npar++) -+ t->vc_par[t->vc_npar] = 0; -+ t->vc_npar = 0; -+ t->vc_state = ESgetpars; -+ case ESgetpars: -+ if (c==';' && t->vc_nparvc_npar++; -+ break; -+ } else if (c>='0' && c<='9') { -+ t->vc_par[t->vc_npar] *= 10; -+ t->vc_par[t->vc_npar] += c-'0'; -+ break; -+ } else t->vc_state=ESgotpars; -+ case ESgotpars: -+ t->vc_state = ESnormal; -+ switch(c) { -+ case 'H': case 'f': -+ if (t->vc_par[0]) t->vc_par[0]--; -+ if (t->vc_par[1]) t->vc_par[1]--; -+ gotoxay(t, t->vc_par[1], t->vc_par[0]); -+ break; -+ case 'J': -+ if (t->vc_par[0] == 0) { -+ //erase from cursor to end of display -+ hcon_clear(hconp, t->vc_y, t->vc_x, hconp->ydim_, hconp->xdim_); -+ } -+ break; -+ case 'M': -+ hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); -+ break; -+ case 'm': -+ break; -+ default: -+#if 0 -+ printk("Unhandled escape code '%c', par[%d, %d, %d, %d, %d]\n", -+ c, t->vc_par[0], t->vc_par[1], t->vc_par[2], t->vc_par[3], t->vc_par[4]); -+#endif -+ break; -+ } - break; - default: -- if (t->backp == 0) { -- t->backc = 1; -- t->backp = data-1; -- } else { -- t->backc++; -- } -- if (t->vc_x + t->backc >= hcon_qxdim(hconp)) { -+ t->vc_state = ESnormal; -+ switch (c) { -+ case 0x07: /* Bell */ -+ vcon_i_backflush(t); -+ break; -+ case 0x08: /* BS */ -+ vcon_i_backflush(t); -+ if (t->vc_x > 0) -+ t->vc_x--; -+ break; -+ case 0x0A: /* Linefeed */ - vcon_i_backflush(t); -- t->vc_x = 0; - vcon_i_cursfeed(t); -+ break; -+ case 0x0D: /* Return */ -+ vcon_i_backflush(t); -+ t->vc_x = 0; -+ break; -+ case 24: case 26: -+ vcon_i_backflush(t); -+ t->vc_state = ESnormal; -+ break; -+ case 27: -+ vcon_i_backflush(t); -+ t->vc_state = ESesc; -+ break; -+ default: -+ if (t->backp == 0) { -+ t->backc = 1; -+ t->backp = data-1; -+ } else { -+ t->backc++; -+ } -+ if ((unsigned int)t->vc_x + t->backc >= hcon_qxdim(hconp)) { -+ vcon_i_backflush(t); -+ t->vc_x = 0; -+ vcon_i_cursfeed(t); -+ } - } - } - } -@@ -73,7 +188,7 @@ - static void vcon_i_cursfeed(struct vconterm *t) { - struct hconsole *hconp = t->impl; - -- if (++t->vc_y >= hcon_qydim(hconp)) { -+ if ((unsigned int)++t->vc_y >= hcon_qydim(hconp)) { - t->vc_y = hcon_qydim(hconp)-1; - hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1); - } -@@ -90,22 +205,75 @@ - t->backp = 0; t->backc = 0; - } - --int vcon_putch(struct vconterm *t, char c) -+int vcon_putch(__attribute__((unused)) struct vconterm *t, __attribute__((unused)) char c) - { - return -1; - } - --int vcon_read(struct vconterm *t, char *data, int leng) -+int vcon_read(__attribute__((unused)) struct vconterm *t, __attribute__((unused)) char *data, __attribute__((unused)) int leng) - { - return 0; - } - --int vcon_getch(struct vconterm *t) -+static const unsigned char sunkbd_keycode[128] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 8, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '\\', 13, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ ' ', -+}; -+ -+static const unsigned char sunkbd_keycode_shifted[128] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0, 8, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '|', 13, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ ' ', -+}; -+ -+static int shiftstate; -+ -+int vcon_getch(__attribute__((unused)) struct vconterm *t) - { -- return -1; -+ int ch; -+ -+ while ((ldb_bypass(0x71000004) & 1) != 1) { } -+ do { -+ ch = ldb_bypass(0x71000006) & 0xff; -+ if (ch == 99) -+ shiftstate |= 1; -+ else if (ch == 110) -+ shiftstate |= 2; -+ else if (ch == 227) -+ shiftstate &= ~1; -+ else if (ch == 238) -+ shiftstate &= ~2; -+ //printk("getch: %d\n", ch); -+ } -+ while ((ch & 0x80) == 0 || ch == 238 || ch == 227); // Wait for key release -+ //printk("getch rel: %d\n", ch); -+ ch &= 0x7f; -+ if (shiftstate) -+ ch = sunkbd_keycode_shifted[ch]; -+ else -+ ch = sunkbd_keycode[ch]; -+ //printk("getch xlate: %d\n", ch); -+ return ch; - } - --void vcon_fini(struct vconterm *t) -+void vcon_fini(__attribute__((unused)) struct vconterm *t) - { - /* violent crash in the end */ - ; -diff -ruN proll_18.orig/src/vconsole.h proll-patch-15/src/vconsole.h ---- proll_18.orig/src/vconsole.h 1999-11-08 00:58:13.000000000 +0000 -+++ proll-patch-15/src/vconsole.h 2005-03-02 12:40:12.000000000 +0000 -@@ -6,6 +6,8 @@ - #ifndef VCONSOLE_H - #define VCONSOLE_H - -+#define NPAR 16 -+ - struct vconterm { - void *impl; - -@@ -13,6 +15,8 @@ - int backc; /* Same, count */ - - int vc_x, vc_y; /* XXX Make vcon_xxx() to use cellmap->xpos_ */ -+ int vc_state; -+ unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */ - }; - - int vcon_init(struct vconterm *t, unsigned int a0); -- cgit v1.2.3 From 83fcb515481f72b9bc74c22490fe5a4f4de20dd6 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 13:37:16 +0000 Subject: use glibc syscall (David Woodhouse) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1966 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 136 +++++++++++++------------------------------------- target-i386/helper2.c | 5 +- 2 files changed, 38 insertions(+), 103 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 4afc6d888..3ce55f903 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -79,127 +79,59 @@ #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) -#if defined(__powerpc__) -#undef __syscall_nr -#undef __sc_loadargs_0 -#undef __sc_loadargs_1 -#undef __sc_loadargs_2 -#undef __sc_loadargs_3 -#undef __sc_loadargs_4 -#undef __sc_loadargs_5 -#undef __sc_asm_input_0 -#undef __sc_asm_input_1 -#undef __sc_asm_input_2 -#undef __sc_asm_input_3 -#undef __sc_asm_input_4 -#undef __sc_asm_input_5 #undef _syscall0 #undef _syscall1 #undef _syscall2 #undef _syscall3 #undef _syscall4 #undef _syscall5 +#undef _syscall6 -/* need to redefine syscalls as Linux kernel defines are incorrect for - the clobber list */ -/* On powerpc a system call basically clobbers the same registers like a - * function call, with the exception of LR (which is needed for the - * "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal - * an error return status). - */ +#define _syscall0(type,name) \ +type name (void) \ +{ \ + return syscall(__NR_##name); \ +} -#define __syscall_nr(nr, type, name, args...) \ - unsigned long __sc_ret, __sc_err; \ - { \ - register unsigned long __sc_0 __asm__ ("r0"); \ - register unsigned long __sc_3 __asm__ ("r3"); \ - register unsigned long __sc_4 __asm__ ("r4"); \ - register unsigned long __sc_5 __asm__ ("r5"); \ - register unsigned long __sc_6 __asm__ ("r6"); \ - register unsigned long __sc_7 __asm__ ("r7"); \ - \ - __sc_loadargs_##nr(name, args); \ - __asm__ __volatile__ \ - ("sc \n\t" \ - "mfcr %0 " \ - : "=&r" (__sc_0), \ - "=&r" (__sc_3), "=&r" (__sc_4), \ - "=&r" (__sc_5), "=&r" (__sc_6), \ - "=&r" (__sc_7) \ - : __sc_asm_input_##nr \ - : "cr0", "ctr", "memory", \ - "r8", "r9", "r10","r11", "r12"); \ - __sc_ret = __sc_3; \ - __sc_err = __sc_0; \ - } \ - if (__sc_err & 0x10000000) \ - { \ - errno = __sc_ret; \ - __sc_ret = -1; \ - } \ - return (type) __sc_ret - -#define __sc_loadargs_0(name, dummy...) \ - __sc_0 = __NR_##name -#define __sc_loadargs_1(name, arg1) \ - __sc_loadargs_0(name); \ - __sc_3 = (unsigned long) (arg1) -#define __sc_loadargs_2(name, arg1, arg2) \ - __sc_loadargs_1(name, arg1); \ - __sc_4 = (unsigned long) (arg2) -#define __sc_loadargs_3(name, arg1, arg2, arg3) \ - __sc_loadargs_2(name, arg1, arg2); \ - __sc_5 = (unsigned long) (arg3) -#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4) \ - __sc_loadargs_3(name, arg1, arg2, arg3); \ - __sc_6 = (unsigned long) (arg4) -#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5) \ - __sc_loadargs_4(name, arg1, arg2, arg3, arg4); \ - __sc_7 = (unsigned long) (arg5) - -#define __sc_asm_input_0 "0" (__sc_0) -#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3) -#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4) -#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5) -#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6) -#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7) - -#define _syscall0(type,name) \ -type name(void) \ -{ \ - __syscall_nr(0, type, name); \ +#define _syscall1(type,name,type1,arg1) \ +type name (type1 arg1) \ +{ \ + return syscall(__NR_##name, arg1); \ } -#define _syscall1(type,name,type1,arg1) \ -type name(type1 arg1) \ -{ \ - __syscall_nr(1, type, name, arg1); \ +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name (type1 arg1,type2 arg2) \ +{ \ + return syscall(__NR_##name, arg1, arg2); \ } -#define _syscall2(type,name,type1,arg1,type2,arg2) \ -type name(type1 arg1, type2 arg2) \ -{ \ - __syscall_nr(2, type, name, arg1, arg2); \ +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name (type1 arg1,type2 arg2,type3 arg3) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3); \ } -#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name(type1 arg1, type2 arg2, type3 arg3) \ -{ \ - __syscall_nr(3, type, name, arg1, arg2, arg3); \ +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4); \ } -#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ -{ \ - __syscall_nr(4, type, name, arg1, arg2, arg3, arg4); \ +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \ } -#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ -{ \ - __syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5); \ + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ } -#endif + #define __NR_sys_uname __NR_uname #define __NR_sys_getcwd1 __NR_getcwd diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 9d5d9b564..ac7d0568b 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -35,7 +35,10 @@ #include #include -_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) +int modify_ldt(int func, void *ptr, unsigned long bytecount) +{ + return syscall(__NR_modify_ldt, func, ptr, bytecount); +} #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) #define modify_ldt_ldt_s user_desc -- cgit v1.2.3 From bc1ad2decd3e5caeca90c09382b0a99e1c8d011e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 13:37:55 +0000 Subject: MIPS FPU support in linux user emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1967 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 41 +++++++---------------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index d4f094710..49b2166bc 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1327,7 +1327,6 @@ void cpu_loop(CPUMIPSState *env) arg5, arg6); } - fail: env->PC += 4; if ((unsigned int)ret >= (unsigned int)(-1133)) { env->gpr[7] = 1; /* error flag */ @@ -1342,39 +1341,10 @@ void cpu_loop(CPUMIPSState *env) break; case EXCP_CpU: case EXCP_RI: - { - uint32_t insn, op; - - insn = tget32(env->PC); - op = insn >> 26; - // printf("insn=%08x op=%02x\n", insn, op); - /* XXX: totally dummy FP ops just to be able to launch - a few executables */ - switch(op) { - case 0x31: /* LWC1 */ - env->PC += 4; - break; - case 0x39: /* SWC1 */ - env->PC += 4; - break; - case 0x11: - switch((insn >> 21) & 0x1f) { - case 0x02: /* CFC1 */ - env->PC += 4; - break; - default: - goto sigill; - } - break; - default: - sigill: - info.si_signo = TARGET_SIGILL; - info.si_errno = 0; - info.si_code = 0; - queue_signal(info.si_signo, &info); - break; - } - } + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = 0; + queue_signal(info.si_signo, &info); break; default: // error: @@ -1700,6 +1670,9 @@ int main(int argc, char **argv) env->gpr[i] = regs->regs[i]; } env->PC = regs->cp0_epc; +#ifdef MIPS_USES_FPU + env->CP0_Status |= (1 << CP0St_CU1); +#endif } #elif defined(TARGET_SH4) { -- cgit v1.2.3 From 4bb3973f616c433524709c3cf11c6d3bf28452dd Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 13:41:08 +0000 Subject: typo in get_reloc_expr() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1968 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dyngen.c b/dyngen.c index c1f348a94..ed580ff5c 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1196,7 +1196,7 @@ void get_reloc_expr(char *name, int name_size, const char *sym_name) } else { #ifdef HOST_SPARC if (sym_name[0] == '.') - snprintf(name, sizeof(name), + snprintf(name, name_size, "(long)(&__dot_%s)", sym_name + 1); else -- cgit v1.2.3 From d1e42c5c1e312320460509c5ab1e94fb17cb7515 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 14:29:34 +0000 Subject: x86_64 mmx/sse fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1969 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index a1b91d353..fb7b88aea 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2905,6 +2905,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) break; case 0xc4: /* pinsrw */ case 0x1c4: + s->rip_offset = 1; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); val = ldub_code(s->pc++); if (b1) { @@ -2975,7 +2976,8 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) } } else { /* generic MMX or SSE operation */ - if (b == 0xf7) { + switch(b) { + case 0xf7: /* maskmov : we must prepare A0 */ if (mod != 3) goto illegal_op; @@ -2990,6 +2992,14 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) gen_op_andl_A0_ffff(); } gen_add_A0_ds_seg(s); + break; + case 0x70: /* pshufx insn */ + case 0xc6: /* pshufx insn */ + case 0xc2: /* compare insns */ + s->rip_offset = 1; + break; + default: + break; } if (is_xmm) { op1_offset = offsetof(CPUX86State,xmm_regs[reg]); -- cgit v1.2.3 From 191f9a93f48ba8859bbbc8d5ac9b401568c2c6f4 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 14 Jun 2006 14:36:07 +0000 Subject: ARM postincrememnt addressing fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1970 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index c582d4bea..fa7ad6086 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -383,19 +383,23 @@ static inline void gen_add_data_offset(DisasContext *s, unsigned int insn) } } -static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn) +static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, + int extra) { int val, rm; if (insn & (1 << 22)) { /* immediate */ val = (insn & 0xf) | ((insn >> 4) & 0xf0); + val += extra; if (!(insn & (1 << 23))) val = -val; if (val != 0) gen_op_addl_T1_im(val); } else { /* register */ + if (extra) + gen_op_addl_T1_im(extra); rm = (insn) & 0xf; gen_movl_T2_reg(s, rm); if (!(insn & (1 << 23))) @@ -1530,12 +1534,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } } } else { + int address_offset; /* Misc load/store */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; gen_movl_T1_reg(s, rn); if (insn & (1 << 24)) - gen_add_datah_offset(s, insn); + gen_add_datah_offset(s, insn, 0); + address_offset = 0; if (insn & (1 << 20)) { /* load */ switch(sh) { @@ -1560,8 +1566,6 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_addl_T1_im(4); gen_movl_T0_reg(s, rd + 1); gen_ldst(stl, s); - if ((insn & (1 << 24)) || (insn & (1 << 20))) - gen_op_addl_T1_im(-4); } else { /* load */ gen_ldst(ldl, s); @@ -1569,18 +1573,19 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_addl_T1_im(4); gen_ldst(ldl, s); gen_movl_reg_T0(s, rd + 1); - if ((insn & (1 << 24)) || (insn & (1 << 20))) - gen_op_addl_T1_im(-4); } + address_offset = -4; } else { /* store */ gen_movl_T0_reg(s, rd); gen_ldst(stw, s); } if (!(insn & (1 << 24))) { - gen_add_datah_offset(s, insn); + gen_add_datah_offset(s, insn, address_offset); gen_movl_reg_T1(s, rn); } else if (insn & (1 << 21)) { + if (address_offset) + gen_op_addl_T1_im(address_offset); gen_movl_reg_T1(s, rn); } } -- cgit v1.2.3 From eda9b09b1df1efea4275baadb9743ff5124bd7c2 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 15:02:05 +0000 Subject: sh4 fmov et al instructions (amatus) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1971 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/cpu.h | 6 ++ target-sh4/exec.h | 5 ++ target-sh4/op.c | 86 ++++++++++++++++++- target-sh4/op_mem.c | 20 +++++ target-sh4/translate.c | 224 +++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 303 insertions(+), 38 deletions(-) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index d99ff8e80..c71af7437 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -27,6 +27,8 @@ #include "cpu-defs.h" +#include "softfloat.h" + #define TARGET_PAGE_BITS 12 /* 4k XXXXX */ #define SR_MD (1 << 30) @@ -90,6 +92,10 @@ typedef struct CPUSH4State { uint32_t fpscr; /* floating point status/control register */ uint32_t fpul; /* floating point communication register */ + /* temporary float registers */ + float32 ft0, ft1; + float64 dt0, dt1; + /* Those belong to the specific unit (SH7750) but are handled here */ uint32_t mmucr; /* MMU control register */ uint32_t pteh; /* page table entry high register */ diff --git a/target-sh4/exec.h b/target-sh4/exec.h index c219fef91..b82820612 100644 --- a/target-sh4/exec.h +++ b/target-sh4/exec.h @@ -28,6 +28,11 @@ register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); register uint32_t T2 asm(AREG3); +#define FT0 (env->ft0) +#define FT1 (env->ft1) +#define DT0 (env->dt0) +#define DT1 (env->dt1) + #include "cpu.h" #include "exec-all.h" diff --git a/target-sh4/op.c b/target-sh4/op.c index dbab658db..64f952fc5 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -228,6 +228,18 @@ void OPPROTO op_sett(void) RETURN(); } +void OPPROTO op_frchg(void) +{ + env->fpscr ^= FPSCR_FR; + RETURN(); +} + +void OPPROTO op_fschg(void) +{ + env->fpscr ^= FPSCR_SZ; + RETURN(); +} + void OPPROTO op_rte(void) { env->sr = env->ssr; @@ -465,6 +477,18 @@ void OPPROTO op_ldcl_rMplus_rN_bank(void) RETURN(); } +void OPPROTO op_ldc_T0_sr(void) +{ + env->sr = T0 & 0x700083f3; + RETURN(); +} + +void OPPROTO op_stc_sr_T0(void) +{ + T0 = env->sr; + RETURN(); +} + #define LDSTOPS(target,load,store) \ void OPPROTO op_##load##_T0_##target (void) \ { env ->target = T0; RETURN(); \ @@ -473,7 +497,6 @@ void OPPROTO op_##store##_##target##_T0 (void) \ { T0 = env->target; RETURN(); \ } \ -LDSTOPS(sr, ldc, stc) LDSTOPS(gbr, ldc, stc) LDSTOPS(vbr, ldc, stc) LDSTOPS(ssr, ldc, stc) @@ -483,6 +506,19 @@ LDSTOPS(sr, ldc, stc) LDSTOPS(mach, lds, sts) LDSTOPS(macl, lds, sts) LDSTOPS(pr, lds, sts) + LDSTOPS(fpul, lds, sts) + +void OPPROTO op_lds_T0_fpscr(void) +{ + env->fpscr = T0 & 0x003fffff; + RETURN(); +} + +void OPPROTO op_sts_fpscr_T0(void) +{ + T0 = env->fpscr & 0x003fffff; + RETURN(); +} void OPPROTO op_movt_rN(void) { @@ -659,6 +695,30 @@ void OPPROTO op_movl_imm_rN(void) RETURN(); } +void OPPROTO op_fmov_frN_FT0(void) +{ + FT0 = *(float32 *)&env->fregs[PARAM1]; + RETURN(); +} + +void OPPROTO op_fmov_drN_DT0(void) +{ + DT0 = *(float64 *)&env->fregs[PARAM1]; + RETURN(); +} + +void OPPROTO op_fmov_FT0_frN(void) +{ + *(float32 *)&env->fregs[PARAM1] = FT0; + RETURN(); +} + +void OPPROTO op_fmov_DT0_drN(void) +{ + *(float64 *)&env->fregs[PARAM1] = DT0; + RETURN(); +} + void OPPROTO op_dec1_rN(void) { env->gregs[PARAM1] -= 1; @@ -677,6 +737,12 @@ void OPPROTO op_dec4_rN(void) RETURN(); } +void OPPROTO op_dec8_rN(void) +{ + env->gregs[PARAM1] -= 4; + RETURN(); +} + void OPPROTO op_inc1_rN(void) { env->gregs[PARAM1] += 1; @@ -695,6 +761,12 @@ void OPPROTO op_inc4_rN(void) RETURN(); } +void OPPROTO op_inc8_rN(void) +{ + env->gregs[PARAM1] += 4; + RETURN(); +} + void OPPROTO op_add_T0_rN(void) { env->gregs[PARAM1] += T0; @@ -779,6 +851,18 @@ void OPPROTO op_movl_T0_T1(void) RETURN(); } +void OPPROTO op_movl_fpul_FT0(void) +{ + FT0 = *(float32 *)&env->fpul; + RETURN(); +} + +void OPPROTO op_movl_FT0_fpul(void) +{ + *(float32 *)&env->fpul = FT0; + RETURN(); +} + void OPPROTO op_goto_tb0(void) { GOTO_TB(op_goto_tb0, PARAM1, 0); diff --git a/target-sh4/op_mem.c b/target-sh4/op_mem.c index 9ab75f4ce..ca39abf96 100644 --- a/target-sh4/op_mem.c +++ b/target-sh4/op_mem.c @@ -56,3 +56,23 @@ void glue(op_stl_T0_T1, MEMSUFFIX) (void) { glue(stl, MEMSUFFIX) (T1, T0); RETURN(); } + +void glue(op_ldfl_T0_FT0, MEMSUFFIX) (void) { + FT0 = glue(ldfl, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stfl_FT0_T1, MEMSUFFIX) (void) { + glue(stfl, MEMSUFFIX) (T1, FT0); + RETURN(); +} + +void glue(op_ldfq_T0_DT0, MEMSUFFIX) (void) { + DT0 = glue(ldfq, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stfq_DT0_T1, MEMSUFFIX) (void) { + glue(stfq, MEMSUFFIX) (T1, DT0); + RETURN(); +} diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 0013e492d..e7dd1b5bc 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -54,6 +54,7 @@ typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc; uint32_t sr; + uint32_t fpscr; uint16_t opcode; uint32_t flags; int memidx; @@ -63,46 +64,50 @@ typedef struct DisasContext { #ifdef CONFIG_USER_ONLY -#define GEN_OP_LD(width) \ - void gen_op_ld##width##_T0_T0 (DisasContext *ctx) { \ - gen_op_ld##width##_T0_T0_raw(); \ +#define GEN_OP_LD(width, reg) \ + void gen_op_ld##width##_T0_##reg (DisasContext *ctx) { \ + gen_op_ld##width##_T0_##reg##_raw(); \ } -#define GEN_OP_ST(width) \ - void gen_op_st##width##_T0_T1 (DisasContext *ctx) { \ - gen_op_st##width##_T0_T1_raw(); \ +#define GEN_OP_ST(width, reg) \ + void gen_op_st##width##_##reg##_T1 (DisasContext *ctx) { \ + gen_op_st##width##_##reg##_T1_raw(); \ } #else -#define GEN_OP_LD(width) \ - void gen_op_ld##width##_T0_T0 (DisasContext *ctx) { \ - if (ctx->memidx) gen_op_ld##width##_T0_T0_kernel(); \ - else gen_op_ld##width##_T0_T0_user();\ +#define GEN_OP_LD(width, reg) \ + void gen_op_ld##width##_T0_##reg (DisasContext *ctx) { \ + if (ctx->memidx) gen_op_ld##width##_T0_##reg##_kernel(); \ + else gen_op_ld##width##_T0_##reg##_user();\ } -#define GEN_OP_ST(width) \ - void gen_op_st##width##_T0_T1 (DisasContext *ctx) { \ - if (ctx->memidx) gen_op_st##width##_T0_T1_kernel(); \ - else gen_op_st##width##_T0_T1_user();\ +#define GEN_OP_ST(width, reg) \ + void gen_op_st##width##_##reg##_T1 (DisasContext *ctx) { \ + if (ctx->memidx) gen_op_st##width##_##reg##_T1_kernel(); \ + else gen_op_st##width##_##reg##_T1_user();\ } #endif -GEN_OP_LD(ub) - GEN_OP_LD(b) - GEN_OP_ST(b) - GEN_OP_LD(uw) - GEN_OP_LD(w) - GEN_OP_ST(w) - GEN_OP_LD(l) - GEN_OP_ST(l) +GEN_OP_LD(ub, T0) +GEN_OP_LD(b, T0) +GEN_OP_ST(b, T0) +GEN_OP_LD(uw, T0) +GEN_OP_LD(w, T0) +GEN_OP_ST(w, T0) +GEN_OP_LD(l, T0) +GEN_OP_ST(l, T0) +GEN_OP_LD(fl, FT0) +GEN_OP_ST(fl, FT0) +GEN_OP_LD(fq, DT0) +GEN_OP_ST(fq, DT0) void cpu_dump_state(CPUState * env, FILE * f, int (*cpu_fprintf) (FILE * f, const char *fmt, ...), int flags) { int i; - cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x\n", - env->pc, env->sr, env->pr); + cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n", + env->pc, env->sr, env->pr, env->fpscr); for (i = 0; i < 24; i += 4) { cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n", i, env->gregs[i], i + 1, env->gregs[i + 1], @@ -242,6 +247,10 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) #define ALTREG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) != (SR_MD | SR_RB) \ ? (x) + 16 : (x)) +#define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x)) +#define XHACK(x) (((x) & 1 ) << 4 | ((x) & 0xe ) << 1) +#define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x)) + #define CHECK_NOT_DELAY_SLOT \ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ {gen_op_raise_slot_illegal_instruction (); ctx->flags |= BRANCH_EXCEPTION; \ @@ -286,10 +295,12 @@ void decode_opc(DisasContext * ctx) gen_op_sett(); return; case 0xfbfb: /* frchg */ - assert(0); /* XXXXX */ + gen_op_frchg(); + ctx->flags |= MODE_CHANGE; return; case 0xf3fb: /* fschg */ - assert(0); /* XXXXX */ + gen_op_fschg(); + ctx->flags |= MODE_CHANGE; return; case 0x0009: /* nop */ return; @@ -393,7 +404,7 @@ void decode_opc(DisasContext * ctx) gen_op_movl_rN_T1(REG(B11_8)); gen_op_stl_T0_T1(ctx); return; - case 0x6004: /* mov.l @Rm+,Rn */ + case 0x6004: /* mov.b @Rm+,Rn */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldb_T0_T0(ctx); gen_op_movl_T0_rN(REG(B11_8)); @@ -643,6 +654,134 @@ void decode_opc(DisasContext * ctx) gen_op_movl_rN_T0(REG(B7_4)); gen_op_xor_T0_rN(REG(B11_8)); return; + case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn */ + if (ctx->fpscr & FPSCR_PR) { + gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_fmov_DT0_drN(XREG(B11_8)); + } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->opcode & 0x0110) + break; /* illegal instruction */ + gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_fmov_DT0_drN(XREG(B11_8)); + } else { + gen_op_fmov_frN_FT0(FREG(B7_4)); + gen_op_fmov_FT0_frN(FREG(B11_8)); + } + return; + case 0xf00a: /* fmov {F,D,X}Rm,@Rn */ + if (ctx->fpscr & FPSCR_PR) { + gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stfq_DT0_T1(ctx); + } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->opcode & 0x0010) + break; /* illegal instruction */ + gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stfq_DT0_T1(ctx); + } else { + gen_op_fmov_frN_FT0(FREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stfl_FT0_T1(ctx); + } + return; + case 0xf008: /* fmov @Rm,{F,D,X}Rn */ + if (ctx->fpscr & FPSCR_PR) { + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldfq_T0_DT0(ctx); + gen_op_fmov_DT0_drN(XREG(B11_8)); + } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldfq_T0_DT0(ctx); + gen_op_fmov_DT0_drN(XREG(B11_8)); + } else { + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldfl_T0_FT0(ctx); + gen_op_fmov_FT0_frN(XREG(B11_8)); + } + return; + case 0xf009: /* fmov @Rm+,{F,D,X}Rn */ + if (ctx->fpscr & FPSCR_PR) { + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldfq_T0_DT0(ctx); + gen_op_fmov_DT0_drN(XREG(B11_8)); + gen_op_inc8_rN(REG(B7_4)); + } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldfq_T0_DT0(ctx); + gen_op_fmov_DT0_drN(XREG(B11_8)); + gen_op_inc8_rN(REG(B7_4)); + } else { + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_ldfl_T0_FT0(ctx); + gen_op_fmov_FT0_frN(XREG(B11_8)); + gen_op_inc4_rN(REG(B7_4)); + } + return; + case 0xf00b: /* fmov {F,D,X}Rm,@-Rn */ + if (ctx->fpscr & FPSCR_PR) { + gen_op_dec8_rN(REG(B11_8)); + gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stfq_DT0_T1(ctx); + } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + gen_op_dec8_rN(REG(B11_8)); + gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stfq_DT0_T1(ctx); + } else { + gen_op_dec4_rN(REG(B11_8)); + gen_op_fmov_frN_FT0(FREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_stfl_FT0_T1(ctx); + } + return; + case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm */ + if (ctx->fpscr & FPSCR_PR) { + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_add_rN_T0(REG(0)); + gen_op_ldfq_T0_DT0(ctx); + gen_op_fmov_DT0_drN(XREG(B11_8)); + } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_add_rN_T0(REG(0)); + gen_op_ldfq_T0_DT0(ctx); + gen_op_fmov_DT0_drN(XREG(B11_8)); + } else { + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_add_rN_T0(REG(0)); + gen_op_ldfl_T0_FT0(ctx); + gen_op_fmov_FT0_frN(XREG(B11_8)); + } + return; + case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) */ + if (ctx->fpscr & FPSCR_PR) { + gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_add_rN_T1(REG(0)); + gen_op_stfq_DT0_T1(ctx); + } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->opcode & 0x0010) + break; /* illegal instruction */ + gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_add_rN_T1(REG(0)); + gen_op_stfq_DT0_T1(ctx); + } else { + gen_op_fmov_frN_FT0(FREG(B7_4)); + gen_op_movl_rN_T1(REG(B11_8)); + gen_op_add_rN_T1(REG(0)); + gen_op_stfl_FT0_T1(ctx); + } + return; } switch (ctx->opcode & 0xff00) { @@ -869,16 +1008,18 @@ void decode_opc(DisasContext * ctx) gen_op_stl_T0_T1 (ctx); \ return; LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |= - MODE_CHANGE; - ) - LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,) - LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,) - LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,) - LDST(spc, 0x404e, 0x4047, ldc, 0x0042, 0x4043, stc,) - LDST(dbr, 0x40fa, 0x40f6, ldc, 0x00fa, 0x40f2, stc,) - LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,) - LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,) - LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,) + MODE_CHANGE;) + LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,) + LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,) + LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,) + LDST(spc, 0x404e, 0x4047, ldc, 0x0042, 0x4043, stc,) + LDST(dbr, 0x40fa, 0x40f6, ldc, 0x00fa, 0x40f2, stc,) + LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,) + LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,) + LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,) + LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x0052, sts,) + LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x0062, sts, ctx->flags |= + MODE_CHANGE;) case 0x00c3: /* movca.l R0,@Rm */ gen_op_movl_rN_T0(REG(0)); gen_op_movl_rN_T1(REG(B11_8)); @@ -944,6 +1085,14 @@ void decode_opc(DisasContext * ctx) case 0x401b: /* tas.b @Rn */ gen_op_tasb_rN(REG(B11_8)); return; + case 0xf00d: /* fsts FPUL,FRn */ + gen_op_movl_fpul_FT0(); + gen_op_fmov_FT0_frN(FREG(B11_8)); + return; + case 0xf01d: /* flds FRm.FPUL */ + gen_op_fmov_frN_FT0(FREG(B11_8)); + gen_op_movl_FT0_fpul(); + return; } fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", @@ -969,6 +1118,7 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, ctx.flags = env->flags; old_flags = 0; ctx.sr = env->sr; + ctx.fpscr = env->fpscr; ctx.memidx = (env->sr & SR_MD) ? 1 : 0; ctx.delayed_pc = env->delayed_pc; ctx.tb = tb; -- cgit v1.2.3 From 8f447cc753ac5f095be3cd9c404bf590319bc696 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 15:21:14 +0000 Subject: gdb stub for win32 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1972 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 1 - gdbstub.c | 30 ++++++++++++++++++++---------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/configure b/configure index f9417a6fa..fa81febb4 100755 --- a/configure +++ b/configure @@ -312,7 +312,6 @@ fi if test "$mingw32" = "yes" ; then linux="no" EXESUF=".exe" - gdbstub="no" oss="no" if [ "$cpu" = "i386" ] ; then kqemu="yes" diff --git a/gdbstub.c b/gdbstub.c index bca9b1e2a..1b93cf4ba 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -30,10 +30,18 @@ #include "vl.h" #endif -#include -#include -#include +#include "qemu_socket.h" +#ifdef _WIN32 +/* XXX: these constants may be independent of the host ones even for Unix */ +#ifndef SIGTRAP +#define SIGTRAP 5 +#endif +#ifndef SIGINT +#define SIGINT 2 +#endif +#else #include +#endif //#define DEBUG_GDB @@ -69,7 +77,7 @@ static int get_char(GDBState *s) int ret; for(;;) { - ret = read(s->fd, &ch, 1); + ret = recv(s->fd, &ch, 1, 0); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return -1; @@ -87,7 +95,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len) int ret; while (len > 0) { - ret = write(s->fd, buf, len); + ret = send(s->fd, buf, len, 0); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return; @@ -829,7 +837,7 @@ static void gdb_read(void *opaque) int i, size; uint8_t buf[4096]; - size = read(s->fd, buf, sizeof(buf)); + size = recv(s->fd, buf, sizeof(buf), 0); if (size < 0) return; if (size == 0) { @@ -866,7 +874,7 @@ static void gdb_accept(void *opaque) /* set short latency */ val = 1; - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); #ifdef CONFIG_USER_ONLY s = &gdbserver_state; @@ -881,9 +889,11 @@ static void gdb_accept(void *opaque) s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; +#ifdef CONFIG_USER_ONLY fcntl(fd, F_SETFL, O_NONBLOCK); +#else + socket_set_nonblock(fd); -#ifndef CONFIG_USER_ONLY /* stop the VM */ vm_stop(EXCP_INTERRUPT); @@ -907,7 +917,7 @@ static int gdbserver_open(int port) /* allow fast reuse */ val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); @@ -923,7 +933,7 @@ static int gdbserver_open(int port) return -1; } #ifndef CONFIG_USER_ONLY - fcntl(fd, F_SETFL, O_NONBLOCK); + socket_set_nonblock(fd); #endif return fd; } -- cgit v1.2.3 From e8445331b61e3d253665e03d0b376e464216806f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 15:32:10 +0000 Subject: show real allocated disk image size on Windows (Frediano Ziglio) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1973 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/qemu-img.c b/qemu-img.c index 3a18c9325..44f9092e7 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -23,6 +23,10 @@ */ #include "vl.h" +#ifdef _WIN32 +#include +#endif + void *get_mmap_addr(unsigned long size) { return NULL; @@ -598,7 +602,19 @@ static int img_convert(int argc, char **argv) #ifdef _WIN32 static int64_t get_allocated_file_size(const char *filename) { + typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high); + get_compressed_t get_compressed; struct _stati64 st; + + /* WinNT support GetCompressedFileSize to determine allocate size */ + get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA"); + if (get_compressed) { + DWORD high, low; + low = get_compressed(filename, &high); + if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) + return (((int64_t) high) << 32) + low; + } + if (_stati64(filename, &st) < 0) return -1; return st.st_size; -- cgit v1.2.3 From ec3757de320f5cc847fb51bff8bc99a9d264389d Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 15:50:07 +0000 Subject: use C99 64 bit printf format to ease win32 porting git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1974 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 17 +++++++++-------- vl.h | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 44f9092e7..c5a8e1a61 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -164,12 +164,12 @@ void help(void) static void get_human_readable_size(char *buf, int buf_size, int64_t size) { - char suffixes[NB_SUFFIXES] = "KMGT"; + static const char suffixes[NB_SUFFIXES] = "KMGT"; int64_t base; int i; if (size <= 999) { - snprintf(buf, buf_size, "%lld", (long long) size); + snprintf(buf, buf_size, "%" PRId64, size); } else { base = 1024; for(i = 0; i < NB_SUFFIXES; i++) { @@ -179,8 +179,8 @@ static void get_human_readable_size(char *buf, int buf_size, int64_t size) suffixes[i]); break; } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { - snprintf(buf, buf_size, "%lld%c", - (long long) ((size + (base >> 1)) / base), + snprintf(buf, buf_size, "%" PRId64 "%c", + ((size + (base >> 1)) / base), suffixes[i]); break; } @@ -373,7 +373,7 @@ static int img_create(int argc, char **argv) printf(", backing_file=%s", base_filename); } - printf(", size=%lld kB\n", (long long) (size / 1024)); + printf(", size=%" PRId64 " kB\n", (int64_t) (size / 1024)); ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted); if (ret < 0) { if (ret == -ENOTSUP) { @@ -563,7 +563,8 @@ static int img_convert(int argc, char **argv) memset(buf + n * 512, 0, cluster_size - n * 512); if (is_not_zero(buf, cluster_size)) { if (qcow_compress_cluster(out_bs, sector_num, buf) != 0) - error("error while compressing sector %lld", sector_num); + error("error while compressing sector %" PRId64, + sector_num); } sector_num += n; } @@ -680,10 +681,10 @@ static int img_info(int argc, char **argv) allocated_size); printf("image: %s\n" "file format: %s\n" - "virtual size: %s (%lld bytes)\n" + "virtual size: %s (%" PRId64 " bytes)\n" "disk size: %s\n", filename, fmt_name, size_buf, - (long long) (total_sectors * 512), + (total_sectors * 512), dsize_buf); if (bdrv_is_encrypted(bs)) printf("encrypted: yes\n"); diff --git a/vl.h b/vl.h index 94da5a6e3..ba99d4647 100644 --- a/vl.h +++ b/vl.h @@ -58,6 +58,8 @@ static inline char *realpath(const char *path, char *resolved_path) _fullpath(resolved_path, path, _MAX_PATH); return resolved_path; } + +#define PRId64 "I64d" #endif #ifdef QEMU_TOOL -- cgit v1.2.3 From 5cbfcd00b0822d9a1a69a65a2d6927f6c4142787 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 15:53:24 +0000 Subject: cocoa monitor fix regarding the handling of dead keys (Joachim Henke) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1975 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/cocoa.m b/cocoa.m index 65f1fc324..9551affa3 100644 --- a/cocoa.m +++ b/cocoa.m @@ -439,23 +439,40 @@ static void cocoa_refresh(DisplayState *ds) kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front /* handle monitor key events */ } else { + int keysym = 0; + switch([event keyCode]) { - case 123: - kbd_put_keysym(QEMU_KEY_LEFT); - break; - case 124: - kbd_put_keysym(QEMU_KEY_RIGHT); - break; - case 125: - kbd_put_keysym(QEMU_KEY_DOWN); - break; - case 126: - kbd_put_keysym(QEMU_KEY_UP); - break; - default: - kbd_put_keysym([[event characters] characterAtIndex:0]); - break; + 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); } } } -- cgit v1.2.3 From 52ca8d6af01d140b1a022958bb5953f00bb7c714 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 16:03:05 +0000 Subject: -no-fd-bootchk option (Lonnie Mendez) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1976 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 6 ++---- qemu-doc.texi | 4 ++++ vl.c | 15 +++++++++++++++ vl.h | 1 + 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index b72219027..361f4bb93 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -193,6 +193,8 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table case 'a': case 'b': rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ + if (!fd_bootchk) + rtc_set_memory(s, 0x38, 0x01); /* disable signature check */ break; default: case 'c': @@ -264,10 +266,6 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table } } rtc_set_memory(s, 0x39, val); - - /* Disable check of 0x55AA signature on the last two bytes of - first sector of disk. XXX: make it the default ? */ - // rtc_set_memory(s, 0x38, 1); } void ioport_set_a20(int enable) diff --git a/qemu-doc.texi b/qemu-doc.texi index 23bf68008..5a3f8f4d4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -228,6 +228,10 @@ Write to temporary files instead of disk image files. In this case, the raw disk image you use is not written back. You can however force the write back by pressing @key{C-a s} (@pxref{disk_images}). +@item -no-fd-bootchk +Disable boot signature checking for floppy disks in Bochs BIOS. It may +be needed to boot from old floppy disks. + @item -m megs Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. diff --git a/vl.c b/vl.c index 5cbd1644a..3d80ec82d 100644 --- a/vl.c +++ b/vl.c @@ -159,6 +159,7 @@ int vnc_display = -1; #define MAX_CPUS 1 #endif int acpi_enabled = 1; +int fd_bootchk = 1; /***********************************************************/ /* x86 ISA bus support */ @@ -4634,6 +4635,9 @@ void help(void) "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" "-snapshot write to temporary files instead of disk image files\n" +#ifdef TARGET_I386 + "-no-fd-bootchk disable boot signature checking for floppy disks\n" +#endif "-m megs set virtual RAM size to megs MB [default=%d]\n" "-smp n set the number of CPUs to 'n' [default=1]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" @@ -4765,6 +4769,9 @@ enum { QEMU_OPTION_cdrom, QEMU_OPTION_boot, QEMU_OPTION_snapshot, +#ifdef TARGET_I386 + QEMU_OPTION_no_fd_bootchk, +#endif QEMU_OPTION_m, QEMU_OPTION_nographic, #ifdef HAS_AUDIO @@ -4828,6 +4835,9 @@ const QEMUOption qemu_options[] = { { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, +#ifdef TARGET_I386 + { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk }, +#endif { "m", HAS_ARG, QEMU_OPTION_m }, { "nographic", 0, QEMU_OPTION_nographic }, { "k", HAS_ARG, QEMU_OPTION_k }, @@ -5286,6 +5296,11 @@ int main(int argc, char **argv) case QEMU_OPTION_fdb: fd_filename[1] = optarg; break; +#ifdef TARGET_I386 + case QEMU_OPTION_no_fd_bootchk: + fd_bootchk = 0; + break; +#endif case QEMU_OPTION_no_code_copy: code_copy_enabled = 0; break; diff --git a/vl.h b/vl.h index ba99d4647..d2010f1ee 100644 --- a/vl.h +++ b/vl.h @@ -889,6 +889,7 @@ void acpi_bios_init(void); /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; +extern int fd_bootchk; void ioport_set_a20(int enable); int ioport_get_a20(void); -- cgit v1.2.3 From c5d6edc3fc660fa188e3161f364ba73940219c10 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 16:49:24 +0000 Subject: mips config fixes (initial patch by Stefan Weil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1977 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 2 +- target-mips/mips-defs.h | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 556f0fd96..de6be29d9 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -3,9 +3,9 @@ #define TARGET_HAS_ICE 1 +#include "config.h" #include "mips-defs.h" #include "cpu-defs.h" -#include "config.h" #include "softfloat.h" typedef union fpr_t fpr_t; diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 317f6a47f..c6f9e9cbe 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -6,10 +6,8 @@ /* If we want to use host float regs... */ //#define USE_HOST_FLOAT_REGS -enum { - MIPS_R4Kc = 0x00018000, - MIPS_R4Kp = 0x00018300, -}; +#define MIPS_R4Kc 0x00018000 +#define MIPS_R4Kp 0x00018300 /* Emulate MIPS R4Kc for now */ #define MIPS_CPU MIPS_R4Kc @@ -19,7 +17,7 @@ enum { #define TARGET_LONG_BITS 32 /* real pages are variable size... */ #define TARGET_PAGE_BITS 12 -/* Uses MIPS R4Kx ehancements to MIPS32 architecture */ +/* Uses MIPS R4Kx enhancements to MIPS32 architecture */ #define MIPS_USES_R4K_EXT /* Uses MIPS R4Kc TLB model */ #define MIPS_USES_R4K_TLB @@ -30,10 +28,15 @@ enum { * Define a major version 1, minor version 0. */ #define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0) -/* Have config1, runs in big-endian mode, uses TLB */ -#define MIPS_CONFIG0 \ -((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \ - (1 << CP0C0_BE) | (0x001 << CP0C0_MT) | (0x010 << CP0C0_K0)) +/* Have config1, uses TLB */ +#define MIPS_CONFIG0_1 \ +((1 << CP0C0_M) | (0 << CP0C0_K23) | (0 << CP0C0_KU) | \ + (1 << CP0C0_MT) | (2 << CP0C0_K0)) +#ifdef TARGET_WORDS_BIGENDIAN +#define MIPS_CONFIG0 (MIPS_CONFIG0_1 | (1 << CP0C0_BE)) +#else +#define MIPS_CONFIG0 MIPS_CONFIG0_1 +#endif /* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache, * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, * no performance counters, watch registers present, no code compression, @@ -45,12 +48,12 @@ enum { (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \ (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \ (1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP)) -#elif defined (MIPS_CPU == MIPS_R4Kp) +#elif (MIPS_CPU == MIPS_R4Kp) /* 32 bits target */ #define TARGET_LONG_BITS 32 /* real pages are variable size... */ #define TARGET_PAGE_BITS 12 -/* Uses MIPS R4Kx ehancements to MIPS32 architecture */ +/* Uses MIPS R4Kx enhancements to MIPS32 architecture */ #define MIPS_USES_R4K_EXT /* Uses MIPS R4Km FPM MMU model */ #define MIPS_USES_R4K_FPM -- cgit v1.2.3 From 43057ab1272ba2b9b052b19a3453fb0f3b510149 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 17:15:19 +0000 Subject: use constants for TLB handling (Thiemo Seufer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1978 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 2 +- target-mips/helper.c | 67 +++++++++++++++++++++++++++------------------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index de6be29d9..fcc1fdf88 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -87,7 +87,7 @@ struct CPUMIPSState { #endif #if defined(MIPS_USES_R4K_TLB) - tlb_t tlb[16]; + tlb_t tlb[MIPS_TLB_NB]; #endif uint32_t CP0_index; uint32_t CP0_random; diff --git a/target-mips/helper.c b/target-mips/helper.c index 8b60b2ce9..8325d4843 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -28,53 +28,56 @@ #include "cpu.h" #include "exec-all.h" +enum { + TLBRET_DIRTY = -4, + TLBRET_INVALID = -3, + TLBRET_NOMATCH = -2, + TLBRET_BADADDR = -1, + TLBRET_MATCH = 0 +}; + /* MIPS32 4K MMU emulation */ #ifdef MIPS_USES_R4K_TLB static int map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) { + target_ulong tag = address & (TARGET_PAGE_MASK << 1); + uint8_t ASID = env->CP0_EntryHi & 0xFF; tlb_t *tlb; - target_ulong tag; - uint8_t ASID; int i, n; - int ret; - ret = -2; - tag = address & 0xFFFFE000; - ASID = env->CP0_EntryHi & 0xFF; for (i = 0; i < MIPS_TLB_NB; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag && address < tlb->end2) { /* TLB match */ - n = (address >> 12) & 1; + n = (address >> TARGET_PAGE_BITS) & 1; /* Check access rights */ - if (!(n ? tlb->V1 : tlb->V0)) - return -3; - if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { - *physical = tlb->PFN[n] | (address & 0xFFF); + if (!(n ? tlb->V1 : tlb->V0)) + return TLBRET_INVALID; + if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { + *physical = tlb->PFN[n] | (address & ~TARGET_PAGE_MASK); *prot = PAGE_READ; if (n ? tlb->D1 : tlb->D0) *prot |= PAGE_WRITE; - return 0; + return TLBRET_MATCH; } - return -4; + return TLBRET_DIRTY; } } - - return ret; + return TLBRET_NOMATCH; } #endif -int get_physical_address (CPUState *env, target_ulong *physical, int *prot, - target_ulong address, int rw, int access_type) +static int get_physical_address (CPUState *env, target_ulong *physical, + int *prot, target_ulong address, + int rw, int access_type) { - int user_mode; - int ret; - /* User mode can only access useg */ - user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM; + int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM; + int ret = TLBRET_MATCH; + #if 0 if (logfile) { fprintf(logfile, "user mode %d h %08x\n", @@ -82,8 +85,7 @@ int get_physical_address (CPUState *env, target_ulong *physical, int *prot, } #endif if (user_mode && address > 0x7FFFFFFFUL) - return -1; - ret = 0; + return TLBRET_BADADDR; if (address < 0x80000000UL) { if (!(env->hflags & MIPS_HFLAG_ERL)) { #ifdef MIPS_USES_R4K_TLB @@ -181,7 +183,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, access_type = ACCESS_INT; if (env->user_mode_only) { /* user mode only emulation */ - ret = -2; + ret = TLBRET_NOMATCH; goto do_fault; } ret = get_physical_address(env, &physical, &prot, @@ -190,14 +192,15 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n", __func__, address, ret, physical, prot); } - if (ret == 0) { - ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot, - is_user, is_softmmu); + if (ret == TLBRET_MATCH) { + ret = tlb_set_page(env, address & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot, + is_user, is_softmmu); } else if (ret < 0) { do_fault: switch (ret) { default: - case -1: + case TLBRET_BADADDR: /* Reference to kernel address from user mode or supervisor mode */ /* Reference to supervisor address from user mode */ if (rw) @@ -205,7 +208,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, else exception = EXCP_AdEL; break; - case -2: + case TLBRET_NOMATCH: /* No TLB match for a mapped address */ if (rw) exception = EXCP_TLBS; @@ -213,14 +216,14 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, exception = EXCP_TLBL; error_code = 1; break; - case -3: + case TLBRET_INVALID: /* TLB match with no valid bit */ if (rw) exception = EXCP_TLBS; else exception = EXCP_TLBL; break; - case -4: + case TLBRET_DIRTY: /* TLB match but 'D' bit is cleared */ exception = EXCP_LTLBL; break; @@ -231,7 +234,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->CP0_Context = (env->CP0_Context & 0xff800000) | ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = - (env->CP0_EntryHi & 0xFF) | (address & 0xFFFFE000); + (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); env->exception_index = exception; env->error_code = error_code; ret = 1; -- cgit v1.2.3 From fdbb46910a2033bd748681346d4261725f5e184b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 17:32:25 +0000 Subject: Solaris/SPARC host port (Ben Taylor) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1979 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 +++ Makefile.target | 6 ++++++ cpu-exec.c | 26 ++++++++++++++------------ dyngen-exec.h | 14 ++++++++++---- dyngen.c | 29 ++++++++++++++++++++++++++--- dyngen.h | 8 +++++++- fpu/softfloat-native.c | 13 +++++++++---- target-mips/cpu.h | 7 +++++++ vl.c | 22 ++++++++++++++++++++++ 9 files changed, 104 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 6716ccf37..d6e6f61eb 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,9 @@ CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I. ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic endif +ifeq ($(ARCH),sparc) +CFLAGS+=-mcpu=ultrasparc +endif LDFLAGS=-g LIBS= DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE diff --git a/Makefile.target b/Makefile.target index b0efd856f..551f7e13e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -102,6 +102,11 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld endif ifeq ($(ARCH),sparc) +ifeq ($(CONFIG_SOLARIS),yes) +CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3 +LDFLAGS+=-m32 +OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0 +else CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 LDFLAGS+=-m32 OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 @@ -109,6 +114,7 @@ HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat # -static is used to avoid g1/g3 usage by the dynamic linker LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static endif +endif ifeq ($(ARCH),sparc64) CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 diff --git a/cpu-exec.c b/cpu-exec.c index b6df3bef1..b08f7af89 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -253,7 +253,7 @@ int cpu_exec(CPUState *env1) uint32_t *saved_regwptr; #endif #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) int saved_i7, tmp_T0; #endif int ret, interrupt_request; @@ -323,7 +323,7 @@ int cpu_exec(CPUState *env1) #if defined(reg_T2) saved_T2 = T2; #endif -#ifdef __sparc__ +#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 @@ -447,7 +447,7 @@ int cpu_exec(CPUState *env1) T0 = 0; /* force lookup of first TB */ for(;;) { -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) /* g1 can be modified by some libc? functions */ tmp_T0 = T0; #endif @@ -467,7 +467,7 @@ int cpu_exec(CPUState *env1) do_interrupt(intno, 0, 0, 0, 1); /* ensure that no TB jump will be modified as the program flow was changed */ -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -486,7 +486,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -497,7 +497,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -516,7 +516,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -534,7 +534,7 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_HARD; do_interrupt(env->interrupt_index); env->interrupt_index = 0; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -567,7 +567,7 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; /* ensure that no TB jump will be modified as the program flow was changed */ -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -635,7 +635,7 @@ int cpu_exec(CPUState *env1) lookup_symbol(tb->pc)); } #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) T0 = tmp_T0; #endif /* see if we can patch the calling TB. When the TB @@ -671,7 +671,9 @@ int cpu_exec(CPUState *env1) "mov %%o7,%%i0" : /* no outputs */ : "r" (gen_func) - : "i0", "i1", "i2", "i3", "i4", "i5"); + : "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" @@ -836,7 +838,7 @@ int cpu_exec(CPUState *env1) #else #error unsupported target CPU #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); #endif T0 = saved_T0; diff --git a/dyngen-exec.h b/dyngen-exec.h index 6952c3a2c..0478ade88 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -121,6 +121,13 @@ extern int printf(const char *, ...); #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 #define AREG0 "g6" #define AREG1 "g1" #define AREG2 "g2" @@ -133,6 +140,7 @@ extern int printf(const char *, ...); #define AREG9 "l5" #define AREG10 "l6" #define AREG11 "l7" +#endif #define USE_FP_CONVERT #endif #ifdef __s390__ @@ -241,10 +249,8 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; ASM_NAME(__op_gen_label) #n) #endif #ifdef __sparc__ -#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \ - "nop") -#define GOTO_LABEL_PARAM(n) asm volatile ( \ - "set " ASM_NAME(__op_gen_label) #n ", %g1; jmp %g1; nop") +#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") diff --git a/dyngen.c b/dyngen.c index ed580ff5c..a8e2958e8 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1440,6 +1440,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC) { +#define INSN_SAVE 0x9de3a000 +#define INSN_RET 0x81c7e008 +#define INSN_RESTORE 0x81e80000 +#define INSN_RETURN 0x81cfe008 +#define INSN_NOP 0x01000000 + uint32_t start_insn, end_insn1, end_insn2; uint8_t *p; p = (void *)(p_end - 8); @@ -1448,12 +1454,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, start_insn = get32((uint32_t *)(p_start + 0x0)); end_insn1 = get32((uint32_t *)(p + 0x0)); end_insn2 = get32((uint32_t *)(p + 0x4)); - if ((start_insn & ~0x1fff) == 0x9de3a000) { + if ((start_insn & ~0x1fff) == INSN_SAVE) { p_start += 0x4; start_offset += 0x4; if ((int)(start_insn | ~0x1fff) < -128) error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + 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 + error("ret; restore; not found at end of %s", name); } else { error("No save at the beginning of %s", name); @@ -1462,7 +1473,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* Skip a preceeding nop, if present. */ if (p > p_start) { skip_insn = get32((uint32_t *)(p - 0x4)); - if (skip_insn == 0x01000000) + if (skip_insn == INSN_NOP) p -= 4; } #endif @@ -2151,6 +2162,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); } diff --git a/dyngen.h b/dyngen.h index 5bb170e94..fe0a9364e 100644 --- a/dyngen.h +++ b/dyngen.h @@ -19,7 +19,13 @@ */ int __op_param1, __op_param2, __op_param3; -int __op_gen_label1, __op_gen_label2, __op_gen_label3; +#ifdef __sparc__ + 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__ diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index e54820239..bbdb3d66d 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -6,7 +6,7 @@ void set_float_rounding_mode(int val STATUS_PARAM) { STATUS(float_rounding_mode) = val; -#if defined(_BSD) && !defined(__APPLE__) +#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) fpsetround(val); #elif defined(__arm__) /* nothing to do */ @@ -22,9 +22,14 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) } #endif -#if defined(_BSD) -#define lrint(d) ((long)rint(d)) -#define llrint(d) ((long long)rint(d)) +#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) +#define lrint(d) ((int32_t)rint(d)) +#define llrint(d) ((int64_t)rint(d)) +#define lrintf(f) ((int32_t)rint(f)) +#define llrintf(f) ((int64_t)rint(f)) +#define sqrtf(f) ((float)sqrt(f)) +#define remainderf(fa, fb) ((float)remainder(fa, fb)) +#define rintf(f) ((float)rint(f)) #endif #if defined(__powerpc__) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index fcc1fdf88..330f9eb19 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -8,6 +8,13 @@ #include "cpu-defs.h" #include "softfloat.h" +// uint_fast8_t and uint_fast16_t not in +// XXX: move that elsewhere +#if defined(HOST_SOLARIS) && SOLARISREV < 10 +typedef unsigned char uint_fast8_t; +typedef unsigned int uint_fast16_t; +#endif + typedef union fpr_t fpr_t; union fpr_t { float64 fd; /* ieee double precision */ diff --git a/vl.c b/vl.c index 3d80ec82d..d1aad0753 100644 --- a/vl.c +++ b/vl.c @@ -563,6 +563,28 @@ int64_t cpu_get_real_ticks(void) return val; } +#elif defined(__sparc__) && defined(HOST_SOLARIS) + +uint64_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 #error unsupported CPU #endif -- cgit v1.2.3 From a08beb33cdce6b9009fd8b744ed66453f127e78e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 17:32:56 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1980 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Changelog b/Changelog index 659b5017b..e9eb6a483 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,11 @@ +version 0.8.2: + + - 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) + version 0.8.1: - USB tablet support (Brad Campbell, Anthony Liguori) -- cgit v1.2.3 From 1ce549abf9192681a482e3c05a9587693219e9be Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 18:17:04 +0000 Subject: more ACPI definition to keep Solaris Happy (Juergen Kiel) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1981 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi-dsdt.dsl | 129 ++++++++++++++++++++++++++- hw/acpi-dsdt.hex | 260 +++++++++++++++++++++++++++++++++---------------------- hw/acpi.c | 8 +- 3 files changed, 293 insertions(+), 104 deletions(-) diff --git a/hw/acpi-dsdt.dsl b/hw/acpi-dsdt.dsl index 8ccb757d8..fc4081fd8 100644 --- a/hw/acpi-dsdt.dsl +++ b/hw/acpi-dsdt.dsl @@ -161,8 +161,9 @@ DefinitionBlock ( } } - /* PIIX3 ISA bridge */ Scope(\_SB.PCI0) { + + /* PIIX3 ISA bridge */ Device (ISA) { Name (_ADR, 0x00010000) @@ -202,6 +203,7 @@ DefinitionBlock ( } } + /* PS/2 mouse */ Device (MOU) { Name (_HID, EisaId ("PNP0F13")) @@ -219,7 +221,132 @@ DefinitionBlock ( Return (TMP) } } + + /* PS/2 floppy controller */ + Device (FDC0) + { + Name (_HID, EisaId ("PNP0700")) + Method (_STA, 0, NotSerialized) + { + Return (0x0F) + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04) + IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01) + IRQNoFlags () {6} + DMA (Compatibility, NotBusMaster, Transfer8) {2} + }) + Return (BUF0) + } + } + + /* Parallel port */ + Device (LPT) + { + Name (_HID, EisaId ("PNP0400")) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSA, Local0) + And (Local0, 0x80000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x0378, 0x0378, 0x08, 0x08) + IRQNoFlags () {7} + }) + Return (BUF0) + } + } + + /* Serial Ports */ + Device (COM1) + { + Name (_HID, EisaId ("PNP0501")) + Name (_UID, 0x01) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSC, Local0) + And (Local0, 0x08000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08) + IRQNoFlags () {4} + }) + Return (BUF0) + } + } + + Device (COM2) + { + Name (_HID, EisaId ("PNP0501")) + Name (_UID, 0x02) + Method (_STA, 0, NotSerialized) + { + Store (\_SB.PCI0.PX13.DRSC, Local0) + And (Local0, 0x80000000, Local0) + If (LEqual (Local0, 0)) + { + Return (0x00) + } + Else + { + Return (0x0F) + } + } + Method (_CRS, 0, NotSerialized) + { + Name (BUF0, ResourceTemplate () + { + IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08) + IRQNoFlags () {3} + }) + Return (BUF0) + } + } } + + /* PIIX4 PM */ + Device (PX13) { + Name (_ADR, 0x00010003) + + OperationRegion (P13C, PCI_Config, 0x5c, 0x24) + Field (P13C, DWordAcc, NoLock, Preserve) + { + DRSA, 32, + DRSB, 32, + DRSC, 32, + DRSE, 32, + DRSF, 32, + DRSG, 32, + DRSH, 32, + DRSI, 32, + DRSJ, 32 + } + } } /* PCI IRQs */ diff --git a/hw/acpi-dsdt.hex b/hw/acpi-dsdt.hex index bc542fc58..f4f50bd65 100644 --- a/hw/acpi-dsdt.hex +++ b/hw/acpi-dsdt.hex @@ -5,15 +5,15 @@ * Copyright (C) 2000 - 2006 Intel Corporation * Supports ACPI Specification Revision 3.0a * - * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Thu May 4 01:07:59 2006 + * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006 * * C source code output * */ unsigned char AmlCode[] = { - 0x44,0x53,0x44,0x54,0x73,0x06,0x00,0x00, /* 00000000 "DSDTs..." */ - 0x01,0x39,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".9QEMU.." */ + 0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */ + 0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */ 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */ 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */ @@ -102,9 +102,9 @@ unsigned char AmlCode[] = 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */ 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */ 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */ - 0x45,0x4D,0x50,0x10,0x43,0x0A,0x2E,0x5F, /* 000002D0 "EMP.C.._" */ + 0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */ - 0x82,0x46,0x09,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".F.ISA_." */ + 0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */ 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */ 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */ @@ -122,101 +122,157 @@ unsigned char AmlCode[] = 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */ 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */ 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */ - 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x10, /* 00000370 "y..TMP_." */ - 0x4F,0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81, /* 00000378 "O._SB_[." */ - 0x24,0x2F,0x03,0x50,0x43,0x49,0x30,0x49, /* 00000380 "$/.PCI0I" */ - 0x53,0x41,0x5F,0x50,0x34,0x30,0x43,0x01, /* 00000388 "SA_P40C." */ - 0x50,0x52,0x51,0x30,0x08,0x50,0x52,0x51, /* 00000390 "PRQ0.PRQ" */ - 0x31,0x08,0x50,0x52,0x51,0x32,0x08,0x50, /* 00000398 "1.PRQ2.P" */ - 0x52,0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A, /* 000003A0 "RQ3.[.N." */ - 0x4C,0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49, /* 000003A8 "LNKA._HI" */ - 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000003B0 "D.A...._" */ - 0x55,0x49,0x44,0x01,0x08,0x5F,0x50,0x52, /* 000003B8 "UID.._PR" */ - 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 000003C0 "S....#.." */ - 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 000003C8 ".y..._ST" */ - 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 000003D0 "A.p..`.." */ - 0x7B,0x0A,0x80,0x50,0x52,0x51,0x30,0x61, /* 000003D8 "{..PRQ0a" */ - 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 000003E0 "p..`.`.." */ - 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 000003E8 "_DIS.}PR" */ - 0x51,0x30,0x0A,0x80,0x50,0x52,0x51,0x30, /* 000003F0 "Q0..PRQ0" */ - 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 000003F8 ".?_CRS.." */ - 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000400 "PRR0...." */ - 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000408 "#...y..P" */ - 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000410 "RR0.TMP_" */ - 0x70,0x50,0x52,0x51,0x30,0x60,0xA0,0x0C, /* 00000418 "pPRQ0`.." */ - 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000420 ".`..y.`T" */ - 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000428 "MP_..p.T" */ - 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00000430 "MP_.PRR0" */ - 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 00000438 ".._SRS.." */ - 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 00000440 "h.TMP_.T" */ - 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 00000448 "MP_`v`p`" */ - 0x50,0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A, /* 00000450 "PRQ0[.O." */ - 0x4C,0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49, /* 00000458 "LNKB._HI" */ - 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 00000460 "D.A...._" */ - 0x55,0x49,0x44,0x0A,0x02,0x08,0x5F,0x50, /* 00000468 "UID..._P" */ - 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 00000470 "RS....#." */ - 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 00000478 "..y..._S" */ - 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 00000480 "TA.p..`." */ - 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000488 ".{..PRQ1" */ - 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000490 "ap..`.`." */ - 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000498 "._DIS.}P" */ - 0x52,0x51,0x31,0x0A,0x80,0x50,0x52,0x51, /* 000004A0 "RQ1..PRQ" */ - 0x31,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 000004A8 "1.?_CRS." */ - 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 000004B0 ".PRR0..." */ - 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 000004B8 ".#...y.." */ - 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 000004C0 "PRR0.TMP" */ - 0x5F,0x70,0x50,0x52,0x51,0x31,0x60,0xA0, /* 000004C8 "_pPRQ1`." */ - 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 000004D0 "..`..y.`" */ - 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 000004D8 "TMP_..p." */ - 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 000004E0 "TMP_.PRR" */ - 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 000004E8 "0.._SRS." */ - 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 000004F0 ".h.TMP_." */ - 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 000004F8 "TMP_`v`p" */ - 0x60,0x50,0x52,0x51,0x31,0x5B,0x82,0x4F, /* 00000500 "`PRQ1[.O" */ - 0x0A,0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48, /* 00000508 ".LNKC._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000510 "ID.A...." */ - 0x5F,0x55,0x49,0x44,0x0A,0x03,0x08,0x5F, /* 00000518 "_UID..._" */ - 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000520 "PRS....#" */ - 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000528 "...y..._" */ - 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00000530 "STA.p..`" */ - 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 00000538 "..{..PRQ" */ - 0x32,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 00000540 "2ap..`.`" */ - 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00000548 ".._DIS.}" */ - 0x50,0x52,0x51,0x32,0x0A,0x80,0x50,0x52, /* 00000550 "PRQ2..PR" */ - 0x51,0x32,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 00000558 "Q2.?_CRS" */ - 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 00000560 "..PRR0.." */ - 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 00000568 "..#...y." */ - 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 00000570 ".PRR0.TM" */ - 0x50,0x5F,0x70,0x50,0x52,0x51,0x32,0x60, /* 00000578 "P_pPRQ2`" */ - 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 00000580 "...`..y." */ - 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 00000588 "`TMP_..p" */ - 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000590 ".TMP_.PR" */ - 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000598 "R0.._SRS" */ - 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 000005A0 "..h.TMP_" */ - 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 000005A8 ".TMP_`v`" */ - 0x70,0x60,0x50,0x52,0x51,0x32,0x5B,0x82, /* 000005B0 "p`PRQ2[." */ - 0x4F,0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F, /* 000005B8 "O.LNKD._" */ - 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F, /* 000005C0 "HID.A..." */ - 0x08,0x5F,0x55,0x49,0x44,0x0A,0x04,0x08, /* 000005C8 "._UID..." */ - 0x5F,0x50,0x52,0x53,0x11,0x09,0x0A,0x06, /* 000005D0 "_PRS...." */ - 0x23,0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A, /* 000005D8 "#...y..." */ - 0x5F,0x53,0x54,0x41,0x00,0x70,0x0A,0x0B, /* 000005E0 "_STA.p.." */ - 0x60,0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52, /* 000005E8 "`..{..PR" */ - 0x51,0x33,0x61,0x70,0x0A,0x09,0x60,0xA4, /* 000005F0 "Q3ap..`." */ - 0x60,0x14,0x11,0x5F,0x44,0x49,0x53,0x00, /* 000005F8 "`.._DIS." */ - 0x7D,0x50,0x52,0x51,0x33,0x0A,0x80,0x50, /* 00000600 "}PRQ3..P" */ - 0x52,0x51,0x33,0x14,0x3F,0x5F,0x43,0x52, /* 00000608 "RQ3.?_CR" */ - 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00000610 "S..PRR0." */ - 0x09,0x0A,0x06,0x23,0x02,0x00,0x18,0x79, /* 00000618 "...#...y" */ - 0x00,0x8B,0x50,0x52,0x52,0x30,0x01,0x54, /* 00000620 "..PRR0.T" */ - 0x4D,0x50,0x5F,0x70,0x50,0x52,0x51,0x33, /* 00000628 "MP_pPRQ3" */ - 0x60,0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79, /* 00000630 "`...`..y" */ - 0x01,0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07, /* 00000638 ".`TMP_.." */ - 0x70,0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50, /* 00000640 "p.TMP_.P" */ - 0x52,0x52,0x30,0x14,0x1B,0x5F,0x53,0x52, /* 00000648 "RR0.._SR" */ - 0x53,0x01,0x8B,0x68,0x01,0x54,0x4D,0x50, /* 00000650 "S..h.TMP" */ - 0x5F,0x82,0x54,0x4D,0x50,0x5F,0x60,0x76, /* 00000658 "_.TMP_`v" */ - 0x60,0x70,0x60,0x50,0x52,0x51,0x33,0x08, /* 00000660 "`p`PRQ3." */ - 0x5F,0x53,0x35,0x5F,0x12,0x06,0x04,0x00, /* 00000668 "_S5_...." */ - 0x00,0x00,0x00, + 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */ + 0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */ + 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */ + 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */ + 0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */ + 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */ + 0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */ + 0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */ + 0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */ + 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */ + 0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */ + 0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */ + 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */ + 0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */ + 0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */ + 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */ + 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */ + 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */ + 0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */ + 0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */ + 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */ + 0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */ + 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */ + 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */ + 0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */ + 0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */ + 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */ + 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */ + 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */ + 0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */ + 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */ + 0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */ + 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */ + 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */ + 0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */ + 0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */ + 0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */ + 0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */ + 0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */ + 0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */ + 0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */ + 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */ + 0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */ + 0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */ + 0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */ + 0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */ + 0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */ + 0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */ + 0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */ + 0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */ + 0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */ + 0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */ + 0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */ + 0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */ + 0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */ + 0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */ + 0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */ + 0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */ + 0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */ + 0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */ + 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */ + 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */ + 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */ + 0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */ + 0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */ + 0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */ + 0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */ + 0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */ + 0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */ + 0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */ + 0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */ + 0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */ + 0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */ + 0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */ + 0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */ + 0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */ + 0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */ + 0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */ + 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */ + 0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */ + 0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */ + 0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */ + 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */ + 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */ + 0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */ + 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */ + 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */ + 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */ + 0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */ + 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */ + 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */ + 0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */ + 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */ + 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */ + 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */ + 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */ + 0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */ + 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */ + 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */ + 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */ + 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */ + 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */ + 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */ + 0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */ + 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */ + 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */ + 0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */ + 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */ + 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */ + 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */ + 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */ + 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */ + 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */ + 0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */ + 0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */ + 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */ + 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */ + 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */ + 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */ + 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */ + 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */ + 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */ + 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */ + 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */ + 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */ + 0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */ + 0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */ + 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */ + 0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */ + 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */ + 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */ + 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */ + 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */ + 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */ + 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */ + 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */ + 0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */ + 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */ + 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */ + 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */ + 0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */ + 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */ + 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */ + 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */ + 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */ + 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */ + 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */ + 0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */ + 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */ + 0x00,0x00, }; diff --git a/hw/acpi.c b/hw/acpi.c index 8fb054428..6c20a4e93 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -240,7 +240,6 @@ void piix4_pm_init(PCIBus *bus, int devfn) pci_conf[0x0b] = 0x06; // bridge device pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 0x01; // interrupt pin 1 - pci_conf[0x60] = 0x10; // release number pm_io_base = PM_IO_BASE; pci_conf[0x40] = pm_io_base | 1; @@ -253,6 +252,13 @@ void piix4_pm_init(PCIBus *bus, int devfn) register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s); register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); + /* XXX: which specification is used ? The i82731AB has different + mappings */ + pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10; + pci_conf[0x63] = 0x60; + pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) | + (serial_hds[1] != NULL ? 0x90 : 0); + s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); piix4_pm_state = s; } -- cgit v1.2.3 From ce05c32384e1698053b862dbf1932cee69d99276 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 18:17:46 +0000 Subject: allow ACPI table build git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1982 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 6 ++++-- configure | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index 551f7e13e..1626833bc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -490,8 +490,10 @@ loader.o: loader.c elf_ops.h acpi.o: acpi.c acpi-dsdt.hex -#$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl -# iasl -tc -p $@ $< +ifdef BUILD_ACPI_TABLES +$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl + iasl -tc -p $@ $< +endif ifeq ($(TARGET_ARCH), sh4) op.o: op.c op_mem.c cpu.h diff --git a/configure b/configure index fa81febb4..ef73a9f31 100755 --- a/configure +++ b/configure @@ -95,6 +95,7 @@ check_gcc="yes" softmmu="yes" user="no" build_docs="no" +build_acpi_tables="no" uname_release="" # OS specific @@ -240,6 +241,8 @@ for opt do ;; --enable-uname-release=*) uname_release="$optarg" ;; + --enable-iasl) build_acpi_tables="yes" + ;; esac done @@ -288,6 +291,7 @@ 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 " --enable-iasl compilation of ACPI tables with the IASL compiler" echo "" echo "NOTE: The object files are build at the place where configure is launched" exit 1 @@ -708,6 +712,9 @@ echo "TARGET_DIRS=$target_list" >> $config_mak if [ "$build_docs" = "yes" ] ; then echo "BUILD_DOCS=yes" >> $config_mak fi +if [ "$build_acpi_tables" = "yes" ] ; then + echo "BUILD_ACPI_TABLES=yes" >> $config_mak +fi # XXX: suppress that if [ "$bsd" = "yes" ] ; then -- cgit v1.2.3 From 856860f5e333b2416c5e403ece32ae68f21cd195 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 18:18:38 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1983 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index e9eb6a483..20f6ebfb5 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,6 @@ version 0.8.2: + - ACPI support - PC VGA BIOS fixes - switch to OpenBios for SPARC targets (Blue Swirl) - VNC server fixes -- cgit v1.2.3 From 30a604f363628bc1867e91fbc0660615e730e393 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Jun 2006 18:35:18 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1984 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 5a3f8f4d4..06fedd042 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1423,7 +1423,7 @@ Floppy drive The number of peripherals is fixed in the architecture. -Since version 0.8.1, QEMU uses OpenBIOS +Since version 0.8.2, QEMU uses OpenBIOS @url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. -- cgit v1.2.3 From e6de1bad4619dbbc40938449a53c4c27c418fdc6 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 16 Jun 2006 21:48:48 +0000 Subject: Arm h/w doc updates. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1985 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 06fedd042..3da557788 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1524,6 +1524,10 @@ PCI memory space. It does not provide access to PCI IO space. This means some devices (eg. ne2k_pci NIC) are not useable, and others (eg. rtl8139 NIC) are only useable when the guest drivers use the memory mapped control registers. +@item +PCI OHCI USB controller. +@item +LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices. @end itemize A Linux 2.6 test image is available on the QEMU web site. More -- cgit v1.2.3 From 978efd6aac65bc1e025472859eb738839425318b Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Jun 2006 18:30:42 +0000 Subject: Respond to qOffsets gdb packet (for debugging bFLT binaries). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1986 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 14 ++++++++++++++ linux-user/flatload.c | 3 +++ linux-user/main.c | 1 + linux-user/qemu.h | 3 +++ 4 files changed, 21 insertions(+) diff --git a/gdbstub.c b/gdbstub.c index 1b93cf4ba..37241ce58 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -17,6 +17,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" #ifdef CONFIG_USER_ONLY #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include "qemu.h" #else @@ -680,6 +682,18 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) goto breakpoint_error; } break; +#ifdef CONFIG_USER_ONLY + case 'q': + if (strncmp(p, "Offsets", 7) == 0) { + TaskState *ts = env->opaque; + + sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset, + ts->info->data_offset, ts->info->data_offset); + put_packet(s, buf); + break; + } + /* Fall through. */ +#endif default: // unknown_command: /* put empty packet */ diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 1e2634b5a..bf55be2b7 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -783,6 +783,9 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, info->start_brk = libinfo[0].start_brk; info->start_stack = sp; info->entry = start_addr; + info->code_offset = info->start_code; + info->data_offset = info->start_data - libinfo[0].text_len; + DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n", (int)info->entry, (int)info->start_stack); diff --git a/linux-user/main.c b/linux-user/main.c index 49b2166bc..5b4182bd8 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1541,6 +1541,7 @@ int main(int argc, char **argv) memset(ts, 0, sizeof(TaskState)); env->opaque = ts; ts->used = 1; + ts->info = info; env->user_mode_only = 1; #if defined(TARGET_I386) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 9047fcf14..218e846a0 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -27,6 +27,8 @@ struct image_info { unsigned long rss; unsigned long start_stack; unsigned long entry; + target_ulong code_offset; + target_ulong data_offset; int personality; }; @@ -73,6 +75,7 @@ typedef struct TaskState { uint32_t v86mask; #endif int used; /* non zero if used */ + struct image_info *info; uint8_t stack[0]; } __attribute__((aligned(16))) TaskState; -- cgit v1.2.3 From 9854bc4662906a60c35c64c1e5b4d76eee4ac631 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Jun 2006 18:48:31 +0000 Subject: SH4 rts fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1987 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index e7dd1b5bc..b08d25a15 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1120,7 +1120,9 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, ctx.sr = env->sr; ctx.fpscr = env->fpscr; ctx.memidx = (env->sr & SR_MD) ? 1 : 0; - ctx.delayed_pc = env->delayed_pc; + /* We don't know if the delayed pc came from a dynamic or static branch, + so assume it is a dynamic branch. */ + ctx.delayed_pc = -1; ctx.tb = tb; ctx.singlestep_enabled = env->singlestep_enabled; nb_gen_labels = 0; -- cgit v1.2.3 From 355fb23d83aad9ffae376cac09c6b52656e7d083 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Jun 2006 19:58:25 +0000 Subject: SH usermode fault handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1988 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 9 ++------- linux-user/main.c | 16 +++++++++++++++- target-sh4/helper.c | 43 +++++++++++++++++++++++++++++++++++++++++++ target-sh4/translate.c | 40 +++++++++++++++++++++------------------- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index b08f7af89..9d5c35e78 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1172,19 +1172,14 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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); - } + sigprocmask(SIG_SETMASK, old_set, NULL); + cpu_loop_exit(); /* never comes here */ return 1; } diff --git a/linux-user/main.c b/linux-user/main.c index 5b4182bd8..74642cc36 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1362,7 +1362,7 @@ void cpu_loop(CPUMIPSState *env) void cpu_loop (CPUState *env) { int trapnr, ret; - // target_siginfo_t info; + target_siginfo_t info; while (1) { trapnr = cpu_sh4_exec (env); @@ -1380,6 +1380,20 @@ void cpu_loop (CPUState *env) env->gregs[0x10] = ret; env->pc += 2; break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 5ab505aed..1839c96dd 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -28,6 +28,38 @@ #include "cpu.h" #include "exec-all.h" +#if defined(CONFIG_USER_ONLY) + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; +} + +int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + env->tea = address; + switch (rw) { + case 0: + env->exception_index = 0x0a0; + break; + case 1: + env->exception_index = 0x0c0; + break; + case 2: + env->exception_index = 0x0a0; + break; + } + return 1; +} + +target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ + return addr; +} + +#else /* !CONFIG_USER_ONLY */ + #define MMU_OK 0 #define MMU_ITLB_MISS (-1) #define MMU_ITLB_MULTIPLE (-2) @@ -396,3 +428,14 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, return tlb_set_page(env, address, physical, prot, is_user, is_softmmu); } + +target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ + target_ulong physical; + int prot; + + get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0); + return physical; +} + +#endif diff --git a/target-sh4/translate.c b/target-sh4/translate.c index b08d25a15..84deced19 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -144,22 +144,6 @@ CPUSH4State *cpu_sh4_init(void) return env; } -#ifdef CONFIG_USER_ONLY -target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr) -{ - return addr; -} -#else -target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr) -{ - target_ulong physical; - int prot; - - get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0); - return physical; -} -#endif - static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) { TranslationBlock *tb; @@ -1108,7 +1092,7 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, target_ulong pc_start; static uint16_t *gen_opc_end; uint32_t old_flags; - int i; + int i, ii; pc_start = tb->pc; gen_opc_ptr = gen_opc_buf; @@ -1135,6 +1119,7 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, } #endif + ii = -1; while ((old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) == 0 && (ctx.flags & (BRANCH | BRANCH_CONDITIONAL | MODE_CHANGE | BRANCH_EXCEPTION)) == 0 && @@ -1151,6 +1136,16 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, } } } + if (search_pc) { + i = gen_opc_ptr - gen_opc_buf; + if (ii < i) { + ii++; + while (ii < i) + gen_opc_instr_start[ii++] = 0; + } + gen_opc_pc[ii] = ctx.pc; + gen_opc_instr_start[ii] = 1; + } #if 0 fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc); fflush(stderr); @@ -1192,7 +1187,15 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, gen_op_debug(); } *gen_opc_ptr = INDEX_op_end; - tb->size = ctx.pc - pc_start; + if (search_pc) { + i = gen_opc_ptr - gen_opc_buf; + ii++; + while (ii <= i) + gen_opc_instr_start[ii++] = 0; + tb->size = 0; + } else { + tb->size = ctx.pc - pc_start; + } #ifdef DEBUG_DISAS #ifdef SH4_DEBUG_DISAS @@ -1220,6 +1223,5 @@ int gen_intermediate_code(CPUState * env, struct TranslationBlock *tb) int gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb) { - assert(0); return gen_intermediate_code_internal(env, tb, 1); } -- cgit v1.2.3 From 4dbed8972b14f7bae70b32632d2f5ed1635cba50 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Jun 2006 20:01:14 +0000 Subject: Enable SH bFLT loader. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1989 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index ef73a9f31..9ab270e28 100755 --- a/configure +++ b/configure @@ -831,6 +831,7 @@ elif test "$target_cpu" = "sh4" ; then echo "TARGET_ARCH=sh4" >> $config_mak echo "#define TARGET_ARCH \"sh4\"" >> $config_h echo "#define TARGET_SH4 1" >> $config_h + bflt="yes" else echo "Unsupported target CPU" exit 1 -- cgit v1.2.3 From 397e923f7f78e99bc547b0a730c225d78dfe878b Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Jun 2006 20:04:26 +0000 Subject: Remove debug output. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1990 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/op_helper.c | 4 ++-- target-sh4/translate.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index 1c63fe587..f02fa588f 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -135,7 +135,7 @@ void helper_div1_T0_T1(void) uint32_t tmp0, tmp2; uint8_t old_q, tmp1 = 0xff; - printf("div1 T0=0x%08x T1=0x%08x M=%d Q=%d T=%d\n", T0, T1, M, Q, T); + //printf("div1 T0=0x%08x T1=0x%08x M=%d Q=%d T=%d\n", T0, T1, M, Q, T); old_q = Q; if ((0x80000000 & T1) != 0) SETQ; @@ -234,7 +234,7 @@ void helper_div1_T0_T1(void) SETT; else CLRT; - printf("Output: T1=0x%08x M=%d Q=%d T=%d\n", T1, M, Q, T); + //printf("Output: T1=0x%08x M=%d Q=%d T=%d\n", T1, M, Q, T); } void helper_dmulsl_T0_T1() diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 84deced19..0dca45ee9 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -247,7 +247,6 @@ void decode_opc(DisasContext * ctx) #endif switch (ctx->opcode) { case 0x0019: /* div0u */ - printf("div0u\n"); gen_op_div0u(); return; case 0x000b: /* rts */ @@ -509,7 +508,6 @@ void decode_opc(DisasContext * ctx) gen_op_cmp_str_T0_T1(); return; case 0x2007: /* div0s Rm,Rn */ - printf("div0s\n"); gen_op_movl_rN_T0(REG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_div0s_T0_T1(); -- cgit v1.2.3 From 9c2a9ea1b1fe221566ca6c3f873da1454cadd263 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Jun 2006 19:12:54 +0000 Subject: SH bugfixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1991 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- gdbstub.c | 14 ++++++++++++-- linux-user/main.c | 14 +++++++------- target-sh4/cpu.h | 4 +++- target-sh4/exec.h | 2 +- target-sh4/op.c | 13 +++++++------ target-sh4/translate.c | 32 +++++++++++++------------------- 7 files changed, 44 insertions(+), 37 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 9d5c35e78..926093afb 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -47,7 +47,7 @@ void cpu_loop_exit(void) longjmp(env->jmp_env, 1); } #endif -#ifndef TARGET_SPARC +#if !(defined(TARGET_SPARC) || defined(TARGET_SH4)) #define reg_T2 #endif diff --git a/gdbstub.c b/gdbstub.c index 37241ce58..3dcaa4c9c 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -504,7 +504,12 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) int i; #define SAVE(x) *ptr++=tswapl(x) - for (i = 0; i < 16; i++) SAVE(env->gregs[i]); + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]); + } else { + for (i = 0; i < 8; i++) SAVE(env->gregs[i]); + } + for (i = 8; i < 16; i++) SAVE(env->gregs[i]); SAVE (env->pc); SAVE (env->pr); SAVE (env->gbr); @@ -527,7 +532,12 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) int i; #define LOAD(x) (x)=*ptr++; - for (i = 0; i < 16; i++) LOAD(env->gregs[i]); + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]); + } else { + for (i = 0; i < 8; i++) LOAD(env->gregs[i]); + } + for (i = 8; i < 16; i++) LOAD(env->gregs[i]); LOAD (env->pc); LOAD (env->pr); LOAD (env->gbr); diff --git a/linux-user/main.c b/linux-user/main.c index 74642cc36..a73919ec3 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1370,14 +1370,14 @@ void cpu_loop (CPUState *env) switch (trapnr) { case 0x160: ret = do_syscall(env, - env->gregs[0x13], - env->gregs[0x14], - env->gregs[0x15], - env->gregs[0x16], - env->gregs[0x17], - env->gregs[0x10], + env->gregs[3], + env->gregs[4], + env->gregs[5], + env->gregs[6], + env->gregs[7], + env->gregs[0], 0); - env->gregs[0x10] = ret; + env->gregs[0] = ret; env->pc += 2; break; case EXCP_DEBUG: diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index c71af7437..ef818fdf2 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -45,7 +45,9 @@ #define FPSCR_PR (1 << 19) #define FPSCR_DN (1 << 18) -#define DELAY_SLOT (1 << 0) +#define DELAY_SLOT (1 << 0) /* Must be the same as SR_T. */ +/* This flag is set if the next insn is a delay slot for a conditional jump. + The dynamic value of the DELAY_SLOT determines whether the jup is taken. */ #define DELAY_SLOT_CONDITIONAL (1 << 1) /* Those are used in contexts only */ #define BRANCH (1 << 2) diff --git a/target-sh4/exec.h b/target-sh4/exec.h index b82820612..356330030 100644 --- a/target-sh4/exec.h +++ b/target-sh4/exec.h @@ -26,7 +26,7 @@ register struct CPUSH4State *env asm(AREG0); register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); -register uint32_t T2 asm(AREG3); +//register uint32_t T2 asm(AREG3); #define FT0 (env->ft0) #define FT1 (env->ft1) diff --git a/target-sh4/op.c b/target-sh4/op.c index 64f952fc5..d3b68bc66 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -109,17 +109,15 @@ void OPPROTO op_not_T0(void) void OPPROTO op_bf_s(void) { - T2 = ~env->sr; env->delayed_pc = PARAM1; - set_flag(DELAY_SLOT_CONDITIONAL); + set_flag(DELAY_SLOT_CONDITIONAL | ((~env->sr) & SR_T)); RETURN(); } void OPPROTO op_bt_s(void) { - T2 = env->sr; env->delayed_pc = PARAM1; - set_flag(DELAY_SLOT_CONDITIONAL); + set_flag(DELAY_SLOT_CONDITIONAL | (env->sr & SR_T)); RETURN(); } @@ -888,9 +886,12 @@ void OPPROTO op_jT(void) RETURN(); } -void OPPROTO op_jTT2(void) +void OPPROTO op_jdelayed(void) { - if (T2 & SR_T) + uint32_t flags; + flags = env->flags; + env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); + if (flags & DELAY_SLOT) GOTO_LABEL_PARAM(1); RETURN(); } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 0dca45ee9..358f975e0 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -124,7 +124,11 @@ void cpu_dump_state(CPUState * env, FILE * f, void cpu_sh4_reset(CPUSH4State * env) { +#if defined(CONFIG_USER_ONLY) + env->sr = 0x00000000; +#else env->sr = 0x700000F0; /* MD, RB, BL, I3-I0 */ +#endif env->vbr = 0; env->pc = 0xA0000000; env->fpscr = 0x00040001; @@ -209,10 +213,10 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) int l1; l1 = gen_new_label(); - gen_op_jTT2(l1); - gen_goto_tb(ctx, 0, ctx->pc); + gen_op_jdelayed(l1); + gen_goto_tb(ctx, 1, ctx->pc); gen_set_label(l1); - gen_goto_tb(ctx, 1, ctx->delayed_pc); + gen_jump(ctx); } #define B3_0 (ctx->opcode & 0xf) @@ -1160,25 +1164,15 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, #endif } - switch (old_flags & (DELAY_SLOT_CONDITIONAL | DELAY_SLOT)) { - case DELAY_SLOT_CONDITIONAL: - gen_op_clr_delay_slot_conditional(); + if (old_flags & DELAY_SLOT_CONDITIONAL) { gen_delayed_conditional_jump(&ctx); - break; - case DELAY_SLOT: + } else if (old_flags & DELAY_SLOT) { gen_op_clr_delay_slot(); gen_jump(&ctx); - break; - case 0: - if (ctx.flags & BRANCH_EXCEPTION) { - gen_jump_exception(&ctx); - } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) { - gen_goto_tb(&ctx, 0, ctx.pc); - } - break; - default: - /* Both cannot be set at the same time */ - assert(0); + } else if (ctx.flags & BRANCH_EXCEPTION) { + gen_jump_exception(&ctx); + } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) { + gen_goto_tb(&ctx, 0, ctx.pc); } if (env->singlestep_enabled) { -- cgit v1.2.3 From 908f52b05c517b07509b2b66fcb73e9506827340 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Jun 2006 19:16:53 +0000 Subject: Add big-endian SH4-user target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1992 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 +++++ configure | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 1626833bc..169ab775a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -30,6 +30,11 @@ ifeq ($(TARGET_ARCH),arm) 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 diff --git a/configure b/configure index 9ab270e28..57b59aaa0 100755 --- a/configure +++ b/configure @@ -737,6 +737,7 @@ target_bigendian="no" [ "$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_softmmu="no" if expr $target : '.*-softmmu' > /dev/null ; then target_softmmu="yes" @@ -827,7 +828,7 @@ elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then 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" ; then +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 -- cgit v1.2.3 From ded3ab80dd384715dff3741e4ac8a015933cb180 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Jun 2006 19:36:58 +0000 Subject: Sparc64 insn fixes (Blue Swirl). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1993 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index f2646684c..22d3ebcb2 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1123,7 +1123,11 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; case 0x5: /* V9 rdpc */ - gen_op_movl_T0_im(dc->pc); + if (dc->pc == (uint32_t)dc->pc) { + gen_op_movl_T0_im(dc->pc); + } else { + gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); + } gen_movl_T0_reg(rd); break; case 0x6: /* V9 rdfprs */ @@ -1765,6 +1769,11 @@ static void disas_sparc_insn(DisasContext * dc) else gen_op_addx_T1_T0(); break; +#ifdef TARGET_SPARC64 + case 0x9: /* V9 mulx */ + gen_op_mulx_T1_T0(); + break; +#endif case 0xa: gen_op_umul_T1_T0(); if (xop & 0x10) @@ -1781,6 +1790,11 @@ static void disas_sparc_insn(DisasContext * dc) else gen_op_subx_T1_T0(); break; +#ifdef TARGET_SPARC64 + case 0xd: /* V9 udivx */ + gen_op_udivx_T1_T0(); + break; +#endif case 0xe: gen_op_udiv_T1_T0(); if (xop & 0x10) @@ -1797,16 +1811,6 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); } else { switch (xop) { -#ifdef TARGET_SPARC64 - case 0x9: /* V9 mulx */ - gen_op_mulx_T1_T0(); - gen_movl_T0_reg(rd); - break; - case 0xd: /* V9 udivx */ - gen_op_udivx_T1_T0(); - gen_movl_T0_reg(rd); - break; -#endif case 0x20: /* taddcc */ case 0x21: /* tsubcc */ case 0x22: /* taddcctv */ @@ -1942,6 +1946,11 @@ static void disas_sparc_insn(DisasContext * dc) break; case 6: // pstate gen_op_wrpstate(); + save_state(dc); + gen_op_next_insn(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; break; case 7: // tl gen_op_movl_env_T0(offsetof(CPUSPARCState, tl)); @@ -2121,7 +2130,15 @@ static void disas_sparc_insn(DisasContext * dc) case 0x38: /* jmpl */ { if (rd != 0) { +#ifdef TARGET_SPARC64 + if (dc->pc == (uint32_t)dc->pc) { + gen_op_movl_T1_im(dc->pc); + } else { + gen_op_movq_T1_im64(dc->pc >> 32, dc->pc); + } +#else gen_op_movl_T1_im(dc->pc); +#endif gen_movl_T1_reg(rd); } gen_mov_pc_npc(dc); @@ -2721,11 +2738,19 @@ void cpu_dump_state(CPUState *env, FILE *f, if ((i & 3) == 3) cpu_fprintf(f, "\n"); } +#ifdef TARGET_SPARC64 + cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d\n", + env->pstate, GET_CCR(env), env->asi, env->tl); + cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d cleanwin %d cwp %d\n", + env->cansave, env->canrestore, env->otherwin, env->wstate, + env->cleanwin, NWINDOWS - 1 - env->cwp); +#else cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), env->psrs?'S':'-', env->psrps?'P':'-', env->psret?'E':'-', env->wim); +#endif cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env)); } -- cgit v1.2.3 From 75956cf032c707155419729ea47179ef1bc357af Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Jun 2006 19:41:28 +0000 Subject: Sun4u vga+bios tweaks (Blue Swirl). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1994 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4u.c | 7 ++----- vl.h | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/sun4u.c b/hw/sun4u.c index 22ab4e1d7..6d413691d 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -27,7 +27,7 @@ #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 #define INITRD_LOAD_ADDR 0x00300000 -#define PROM_SIZE_MAX (256 * 1024) +#define PROM_SIZE_MAX (512 * 1024) #define PROM_ADDR 0x1fff0000000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL #define APB_MEM_BASE 0x1ff00000000ULL @@ -326,10 +326,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL); isa_mem_base = VGA_BASE; - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); - cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size); - //pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); + pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { diff --git a/vl.h b/vl.h index d2010f1ee..331245157 100644 --- a/vl.h +++ b/vl.h @@ -148,7 +148,7 @@ extern int usb_enabled; extern int smp_cpus; /* XXX: make it dynamic */ -#if defined (TARGET_PPC) +#if defined (TARGET_PPC) || defined (TARGET_SPARC64) #define BIOS_SIZE ((512 + 32) * 1024) #elif defined(TARGET_MIPS) #define BIOS_SIZE (128 * 1024) -- cgit v1.2.3 From 447c2cefcb6b52c659f474490377b2721ff6a00a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Jun 2006 22:06:13 +0000 Subject: switch_tss eflags restore fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1995 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/helper.c b/target-i386/helper.c index 123f51049..29185ceb9 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1674,6 +1674,7 @@ void helper_ljmp_protected_T0_T1(int next_eip_addend) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); next_eip = env->eip + next_eip_addend; switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); + CC_OP = CC_OP_EFLAGS; break; case 4: /* 286 call gate */ case 12: /* 386 call gate */ @@ -1834,6 +1835,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip); + CC_OP = CC_OP_EFLAGS; return; case 4: /* 286 call gate */ case 12: /* 386 call gate */ -- cgit v1.2.3 From b2a8e5922426a9b8080f63b757bf302797f83fcc Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Jun 2006 22:42:57 +0000 Subject: fxam test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1996 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 310a93aeb..df7c1bf8e 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -789,6 +789,12 @@ void test_fcmp(double a, double b) a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); } fpu_clear_exceptions(); + asm volatile("fxam\n" + "fstsw %%ax\n" + : "=a" (fpus) + : "t" (a)); + printf("fxam(%f)=%04lx\n", a, fpus & 0x4700); + fpu_clear_exceptions(); } void test_fcvt(double a) @@ -958,12 +964,17 @@ void test_floats(void) test_fcmp(2, 3); test_fcmp(2, q_nan.d); test_fcmp(q_nan.d, -1); + test_fcmp(-1.0/0.0, -1); + test_fcmp(1.0/0.0, -1); test_fcvt(0.5); test_fcvt(-0.5); test_fcvt(1.0/7.0); test_fcvt(-1.0/9.0); test_fcvt(32768); test_fcvt(-1e20); + test_fcvt(-1.0/0.0); + test_fcvt(1.0/0.0); + test_fcvt(q_nan.d); test_fconst(); test_fbcd(1234567890123456); test_fbcd(-123451234567890); -- cgit v1.2.3 From a891c7a1947995eae84345719a197b6da14f96cc Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 19 Jun 2006 22:43:38 +0000 Subject: fxam fix (Julian Seward) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1997 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-i386/helper.c b/target-i386/helper.c index 29185ceb9..379cfd5a4 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2950,9 +2950,14 @@ void helper_fxam_ST0(void) if (SIGND(temp)) env->fpus |= 0x200; /* C1 <-- 1 */ + /* XXX: test fptags too */ expdif = EXPD(temp); if (expdif == MAXEXPD) { +#ifdef USE_X86LDOUBLE + if (MANTD(temp) == 0x8000000000000000ULL) +#else if (MANTD(temp) == 0) +#endif env->fpus |= 0x500 /*Infinity*/; else env->fpus |= 0x100 /*NaN*/; -- cgit v1.2.3 From 48dc41eb8bdccef274172ba8148c324d1ae9782b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 21 Jun 2006 18:15:50 +0000 Subject: sparc user fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1998 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 5 +++-- linux-user/syscall.c | 11 ++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index a73919ec3..6b8337fc7 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -598,8 +598,9 @@ void cpu_loop (CPUSPARCState *env) #else // XXX #endif - case 0x100: // XXX, why do we get these? - break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; case EXCP_DEBUG: { int sig; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3ce55f903..12dbf3891 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1538,6 +1538,11 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) new_env->regs[13] = newsp; new_env->regs[0] = 0; #elif defined(TARGET_SPARC) + if (!newsp) + newsp = env->regwptr[22]; + new_env->regwptr[22] = newsp; + new_env->regwptr[0] = 0; + /* XXXXX */ printf ("HELPME: %s:%d\n", __FILE__, __LINE__); #elif defined(TARGET_MIPS) printf ("HELPME: %s:%d\n", __FILE__, __LINE__); @@ -3597,11 +3602,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_set_thread_area: case TARGET_NR_get_thread_area: goto unimplemented_nowarn; +#endif +#ifdef TARGET_NR_getdomainname + case TARGET_NR_getdomainname: + goto unimplemented_nowarn; #endif default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) +#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) || defined(TARGET_NR_getdomainname) unimplemented_nowarn: #endif ret = -ENOSYS; -- cgit v1.2.3 From ee6c0b51e97c8bcad32181f42e63765b18c30354 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 21 Jun 2006 18:26:15 +0000 Subject: sparc branch fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1999 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 22d3ebcb2..c19797e3b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -956,8 +956,8 @@ static void disas_sparc_insn(DisasContext * dc) int cc; target = GET_FIELD_SP(insn, 0, 18); - target <<= 2; target = sign_extend(target, 18); + target <<= 2; cc = GET_FIELD_SP(insn, 20, 21); if (cc == 0) do_branch(dc, target, insn, 0); @@ -971,8 +971,8 @@ static void disas_sparc_insn(DisasContext * dc) { target = GET_FIELD_SP(insn, 0, 13) | (GET_FIELD_SP(insn, 20, 21) >> 7); - target <<= 2; target = sign_extend(target, 16); + target <<= 2; rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); do_branch_reg(dc, target, insn); @@ -986,8 +986,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_trap_ifnofpu(); #endif target = GET_FIELD_SP(insn, 0, 18); - target <<= 2; target = sign_extend(target, 19); + target <<= 2; do_fbranch(dc, target, insn, cc); goto jmp_insn; } @@ -995,8 +995,8 @@ static void disas_sparc_insn(DisasContext * dc) case 0x2: /* BN+x */ { target = GET_FIELD(insn, 10, 31); - target <<= 2; target = sign_extend(target, 22); + target <<= 2; do_branch(dc, target, insn, 0); goto jmp_insn; } @@ -1007,8 +1007,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_trap_ifnofpu(); #endif target = GET_FIELD(insn, 10, 31); - target <<= 2; target = sign_extend(target, 22); + target <<= 2; do_fbranch(dc, target, insn, 0); goto jmp_insn; } -- cgit v1.2.3 From 65ce8c2fb438c8685dbcd28784a0b0ba2b484e5f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 21 Jun 2006 18:37:05 +0000 Subject: soft floats for SPARC (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2000 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- target-sparc/cpu.h | 10 +-- target-sparc/op.c | 148 +++++++++++++------------------ target-sparc/op_helper.c | 220 ++++++++--------------------------------------- 4 files changed, 98 insertions(+), 282 deletions(-) diff --git a/configure b/configure index 57b59aaa0..59dcee48f 100755 --- a/configure +++ b/configure @@ -850,7 +850,7 @@ if test "$target_user_only" = "yes" ; then echo "#define CONFIG_USER_ONLY 1" >> $config_h fi -if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then +if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h fi diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 28efab758..c6d5621b1 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -12,7 +12,7 @@ #define TARGET_FPREGS 64 #define TARGET_PAGE_BITS 12 /* XXX */ #endif -#define TARGET_FPREG_T float +#define TARGET_FPREG_T float32 #include "cpu-defs.h" @@ -146,7 +146,7 @@ typedef struct CPUSPARCState { target_ulong gregs[8]; /* general registers */ target_ulong *regwptr; /* pointer to current register window */ - TARGET_FPREG_T fpr[TARGET_FPREGS]; /* floating point registers */ + float32 fpr[TARGET_FPREGS]; /* floating point registers */ target_ulong pc; /* program counter */ target_ulong npc; /* next program counter */ target_ulong y; /* multiply/divide register */ @@ -187,8 +187,8 @@ typedef struct CPUSPARCState { uint32_t mmuregs[16]; #endif /* temporary float registers */ - float ft0, ft1; - double dt0, dt1; + float32 ft0, ft1; + float64 dt0, dt1; float_status fp_status; #if defined(TARGET_SPARC64) #define MAXTL 4 @@ -236,8 +236,6 @@ typedef struct CPUSPARCState { CPUSPARCState *cpu_sparc_init(void); int cpu_sparc_exec(CPUSPARCState *s); int cpu_sparc_close(CPUSPARCState *s); -void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f); -double cpu_put_fp64(uint64_t mant, uint16_t exp); /* Fake impl 0, version 4 */ #define GET_PSR(env) ((0 << 28) | (4 << 24) | (env->psr & PSR_ICC) | \ diff --git a/target-sparc/op.c b/target-sparc/op.c index 4609cdf1e..d5df859db 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1339,94 +1339,66 @@ void OPPROTO op_flush_T0(void) helper_flush(T0); } -void OPPROTO op_fnegs(void) -{ - FT0 = -FT1; -} - -void OPPROTO op_fabss(void) -{ - do_fabss(); -} - -#ifdef TARGET_SPARC64 -void OPPROTO op_fnegd(void) -{ - DT0 = -DT1; -} - -void OPPROTO op_fabsd(void) -{ - do_fabsd(); -} -#endif - -void OPPROTO op_fsqrts(void) -{ - do_fsqrts(); -} - -void OPPROTO op_fsqrtd(void) -{ - do_fsqrtd(); -} - -void OPPROTO op_fmuls(void) -{ - FT0 *= FT1; -} +#define F_OP(name, p) void OPPROTO op_f##name##p(void) + +#define F_BINOP(name) \ + F_OP(name, s) \ + { \ + FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \ + } \ + F_OP(name, d) \ + { \ + DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ + } -void OPPROTO op_fmuld(void) -{ - DT0 *= DT1; -} +F_BINOP(add); +F_BINOP(sub); +F_BINOP(mul); +F_BINOP(div); +#undef F_BINOP void OPPROTO op_fsmuld(void) { - DT0 = FT0 * FT1; -} - -void OPPROTO op_fadds(void) -{ - FT0 += FT1; + DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status), + float32_to_float64(FT1, &env->fp_status), + &env->fp_status); } -void OPPROTO op_faddd(void) -{ - DT0 += DT1; -} +#define F_HELPER(name) \ + F_OP(name, s) \ + { \ + do_f##name##s(); \ + } \ + F_OP(name, d) \ + { \ + do_f##name##d(); \ + } -void OPPROTO op_fsubs(void) -{ - FT0 -= FT1; -} +F_HELPER(sqrt); -void OPPROTO op_fsubd(void) +F_OP(neg, s) { - DT0 -= DT1; + FT0 = float32_chs(FT1); } -void OPPROTO op_fdivs(void) +F_OP(abs, s) { - FT0 /= FT1; + do_fabss(); } -void OPPROTO op_fdivd(void) -{ - DT0 /= DT1; -} +F_HELPER(cmp); -void OPPROTO op_fcmps(void) +#ifdef TARGET_SPARC64 +F_OP(neg, d) { - do_fcmps(); + DT0 = float64_chs(DT1); } -void OPPROTO op_fcmpd(void) +F_OP(abs, d) { - do_fcmpd(); + do_fabsd(); } -#ifdef TARGET_SPARC64 void OPPROTO op_fcmps_fcc1(void) { do_fcmps_fcc1(); @@ -1458,69 +1430,65 @@ void OPPROTO op_fcmpd_fcc3(void) } #endif +/* Integer to float conversion. */ #ifdef USE_INT_TO_FLOAT_HELPERS -void OPPROTO op_fitos(void) -{ - do_fitos(); -} - -void OPPROTO op_fitod(void) -{ - do_fitod(); -} +F_HELPER(ito); #else -void OPPROTO op_fitos(void) +F_OP(ito, s) { - FT0 = (float) *((int32_t *)&FT1); + FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status); } -void OPPROTO op_fitod(void) +F_OP(ito, d) { - DT0 = (double) *((int32_t *)&FT1); + DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); } #ifdef TARGET_SPARC64 -void OPPROTO op_fxtos(void) +F_OP(xto, s) { - FT0 = (float) *((int64_t *)&DT1); + FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status); } -void OPPROTO op_fxtod(void) +F_OP(xto, d) { - DT0 = (double) *((int64_t *)&DT1); + DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); } #endif #endif +#undef F_HELPER +/* floating point conversion */ void OPPROTO op_fdtos(void) { - FT0 = (float) DT1; + FT0 = float64_to_float32(DT1, &env->fp_status); } void OPPROTO op_fstod(void) { - DT0 = (double) FT1; + DT0 = float32_to_float64(FT1, &env->fp_status); } +/* Float to integer conversion. */ void OPPROTO op_fstoi(void) { - *((int32_t *)&FT0) = (int32_t) FT1; + *((int32_t *)&FT0) = float32_to_int32(FT1, &env->fp_status); } void OPPROTO op_fdtoi(void) { - *((int32_t *)&FT0) = (int32_t) DT1; + *((int32_t *)&FT0) = float64_to_int32(DT1, &env->fp_status); } #ifdef TARGET_SPARC64 void OPPROTO op_fstox(void) { - *((int64_t *)&DT0) = (int64_t) FT1; + *((int64_t *)&DT0) = float32_to_int64(FT1, &env->fp_status); } void OPPROTO op_fdtox(void) { - *((int64_t *)&DT0) = (int64_t) DT1; + *((int64_t *)&DT0) = float64_to_int64(DT1, &env->fp_status); } void OPPROTO op_fmovs_cc(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 030b2f78a..5f88459ab 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -12,12 +12,12 @@ void raise_exception(int tt) #ifdef USE_INT_TO_FLOAT_HELPERS void do_fitos(void) { - FT0 = (float) *((int32_t *)&FT1); + FT0 = int32_to_float32(*((int32_t *)&FT1)); } void do_fitod(void) { - DT0 = (double) *((int32_t *)&FT1); + DT0 = int32_to_float64(*((int32_t *)&FT1)); } #endif @@ -43,182 +43,45 @@ void do_fsqrtd(void) DT0 = float64_sqrt(DT1, &env->fp_status); } -#define FS 0 -void do_fcmps (void) -{ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); - if (isnan(FT0) || isnan(FT1)) { - T0 = (FSR_FCC1 | FSR_FCC0) << FS; - if (env->fsr & FSR_NVM) { - env->fsr |= T0; - raise_exception(TT_FP_EXCP); - } else { - env->fsr |= FSR_NVA; - } - } else if (FT0 < FT1) { - T0 = FSR_FCC0 << FS; - } else if (FT0 > FT1) { - T0 = FSR_FCC1 << FS; - } else { - T0 = 0; +#define GEN_FCMP(name, size, reg1, reg2, FS) \ + void glue(do_, name) (void) \ + { \ + env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ + case float_relation_unordered: \ + T0 = (FSR_FCC1 | FSR_FCC0) << FS; \ + if (env->fsr & FSR_NVM) { \ + env->fsr |= T0; \ + raise_exception(TT_FP_EXCP); \ + } else { \ + env->fsr |= FSR_NVA; \ + } \ + break; \ + case float_relation_less: \ + T0 = FSR_FCC0 << FS; \ + break; \ + case float_relation_greater: \ + T0 = FSR_FCC1 << FS; \ + break; \ + default: \ + T0 = 0; \ + break; \ + } \ + env->fsr |= T0; \ } - env->fsr |= T0; -} -void do_fcmpd (void) -{ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); - if (isnan(DT0) || isnan(DT1)) { - T0 = (FSR_FCC1 | FSR_FCC0) << FS; - if (env->fsr & FSR_NVM) { - env->fsr |= T0; - raise_exception(TT_FP_EXCP); - } else { - env->fsr |= FSR_NVA; - } - } else if (DT0 < DT1) { - T0 = FSR_FCC0 << FS; - } else if (DT0 > DT1) { - T0 = FSR_FCC1 << FS; - } else { - T0 = 0; - } - env->fsr |= T0; -} +GEN_FCMP(fcmps, float32, FT0, FT1, 0); +GEN_FCMP(fcmpd, float64, DT0, DT1, 0); #ifdef TARGET_SPARC64 -#undef FS -#define FS 22 -void do_fcmps_fcc1 (void) -{ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); - if (isnan(FT0) || isnan(FT1)) { - T0 = (FSR_FCC1 | FSR_FCC0) << FS; - if (env->fsr & FSR_NVM) { - env->fsr |= T0; - raise_exception(TT_FP_EXCP); - } else { - env->fsr |= FSR_NVA; - } - } else if (FT0 < FT1) { - T0 = FSR_FCC0 << FS; - } else if (FT0 > FT1) { - T0 = FSR_FCC1 << FS; - } else { - T0 = 0; - } - env->fsr |= T0; -} - -void do_fcmpd_fcc1 (void) -{ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); - if (isnan(DT0) || isnan(DT1)) { - T0 = (FSR_FCC1 | FSR_FCC0) << FS; - if (env->fsr & FSR_NVM) { - env->fsr |= T0; - raise_exception(TT_FP_EXCP); - } else { - env->fsr |= FSR_NVA; - } - } else if (DT0 < DT1) { - T0 = FSR_FCC0 << FS; - } else if (DT0 > DT1) { - T0 = FSR_FCC1 << FS; - } else { - T0 = 0; - } - env->fsr |= T0; -} +GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22); +GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22); -#undef FS -#define FS 24 -void do_fcmps_fcc2 (void) -{ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); - if (isnan(FT0) || isnan(FT1)) { - T0 = (FSR_FCC1 | FSR_FCC0) << FS; - if (env->fsr & FSR_NVM) { - env->fsr |= T0; - raise_exception(TT_FP_EXCP); - } else { - env->fsr |= FSR_NVA; - } - } else if (FT0 < FT1) { - T0 = FSR_FCC0 << FS; - } else if (FT0 > FT1) { - T0 = FSR_FCC1 << FS; - } else { - T0 = 0; - } - env->fsr |= T0; -} +GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24); +GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24); -void do_fcmpd_fcc2 (void) -{ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); - if (isnan(DT0) || isnan(DT1)) { - T0 = (FSR_FCC1 | FSR_FCC0) << FS; - if (env->fsr & FSR_NVM) { - env->fsr |= T0; - raise_exception(TT_FP_EXCP); - } else { - env->fsr |= FSR_NVA; - } - } else if (DT0 < DT1) { - T0 = FSR_FCC0 << FS; - } else if (DT0 > DT1) { - T0 = FSR_FCC1 << FS; - } else { - T0 = 0; - } - env->fsr |= T0; -} - -#undef FS -#define FS 26 -void do_fcmps_fcc3 (void) -{ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); - if (isnan(FT0) || isnan(FT1)) { - T0 = (FSR_FCC1 | FSR_FCC0) << FS; - if (env->fsr & FSR_NVM) { - env->fsr |= T0; - raise_exception(TT_FP_EXCP); - } else { - env->fsr |= FSR_NVA; - } - } else if (FT0 < FT1) { - T0 = FSR_FCC0 << FS; - } else if (FT0 > FT1) { - T0 = FSR_FCC1 << FS; - } else { - T0 = 0; - } - env->fsr |= T0; -} - -void do_fcmpd_fcc3 (void) -{ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); - if (isnan(DT0) || isnan(DT1)) { - T0 = (FSR_FCC1 | FSR_FCC0) << FS; - if (env->fsr & FSR_NVM) { - env->fsr |= T0; - raise_exception(TT_FP_EXCP); - } else { - env->fsr |= FSR_NVA; - } - } else if (DT0 < DT1) { - T0 = FSR_FCC0 << FS; - } else if (DT0 > DT1) { - T0 = FSR_FCC1 << FS; - } else { - T0 = 0; - } - env->fsr |= T0; -} -#undef FS +GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26); +GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26); #endif #if defined(CONFIG_USER_ONLY) @@ -783,19 +646,6 @@ void helper_ldfsr(void) set_float_rounding_mode(rnd_mode, &env->fp_status); } -void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f) -{ - int exptemp; - - *pmant = ldexp(frexp(f, &exptemp), 53); - *pexp = exptemp; -} - -double cpu_put_fp64(uint64_t mant, uint16_t exp) -{ - return ldexp((double) mant, exp - 53); -} - void helper_debug() { env->exception_index = EXCP_DEBUG; -- cgit v1.2.3 From 1bdb68ea139143922b2887ccb337dcd9b534aa3c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 21 Jun 2006 18:48:01 +0000 Subject: fixed sparc64 cpu fp save/restore git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2001 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 1 - vl.c | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index c6d5621b1..90f6fb23d 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -12,7 +12,6 @@ #define TARGET_FPREGS 64 #define TARGET_PAGE_BITS 12 /* XXX */ #endif -#define TARGET_FPREG_T float32 #include "cpu-defs.h" diff --git a/vl.c b/vl.c index d1aad0753..76cfe71e9 100644 --- a/vl.c +++ b/vl.c @@ -4146,11 +4146,11 @@ void cpu_save(QEMUFile *f, void *opaque) /* FPU */ for(i = 0; i < TARGET_FPREGS; i++) { union { - TARGET_FPREG_T f; - target_ulong i; + float32 f; + uint32_t i; } u; u.f = env->fpr[i]; - qemu_put_betl(f, u.i); + qemu_put_be32(f, u.i); } qemu_put_betls(f, &env->pc); @@ -4182,10 +4182,10 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) /* FPU */ for(i = 0; i < TARGET_FPREGS; i++) { union { - TARGET_FPREG_T f; - target_ulong i; + float32 f; + uint32_t i; } u; - u.i = qemu_get_betl(f); + u.i = qemu_get_be32(f); env->fpr[i] = u.f; } -- cgit v1.2.3 From 3cb0853ad7105efdcc15df5ef9bee48d102ca922 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 21 Jun 2006 21:19:50 +0000 Subject: more info about -std-vga git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2002 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 3da557788..e4985e26f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -556,7 +556,10 @@ images. @item -std-vga Simulate a standard VGA card with Bochs VBE extensions (default is -Cirrus Logic GD5446 PCI VGA) +Cirrus Logic GD5446 PCI VGA). If your guest OS supports the VESA 2.0 +VBE extensions (e.g. Windows XP) and if you want to use high +resolution modes (>= 1280x1024x16) then you should use this option. + @item -loadvm file Start right away with a saved state (@code{loadvm} in monitor) @end table @@ -1260,6 +1263,11 @@ card. All Windows versions starting from Windows 95 should recognize and use this graphic card. For optimal performances, use 16 bit color depth in the guest and the host OS. +If you are using Windows XP as guest OS and if you want to use high +resolution modes which the Cirrus Logic BIOS does not support (i.e. >= +1280x1024x16), then you should use the VESA VBE virtual graphic card +(option @option{-std-vga}). + @subsubsection CPU usage reduction Windows 9x does not correctly use the CPU HLT -- cgit v1.2.3 From 13846e700f7415b388f06ef912c772907a95e62e Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 23 Jun 2006 21:01:56 +0000 Subject: Sparc64 BPr branch target fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2003 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index c19797e3b..bbd072c37 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -970,7 +970,7 @@ static void disas_sparc_insn(DisasContext * dc) case 0x3: /* V9 BPr */ { target = GET_FIELD_SP(insn, 0, 13) | - (GET_FIELD_SP(insn, 20, 21) >> 7); + (GET_FIELD_SP(insn, 20, 21) << 14); target = sign_extend(target, 16); target <<= 2; rs1 = GET_FIELD(insn, 13, 17); -- cgit v1.2.3 From 80e7d5210305d1acff06fd59de2982826cb880c7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jun 2006 14:01:32 +0000 Subject: added movdq2q and movq2dq git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2004 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index df7c1bf8e..64802690f 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -2199,9 +2199,12 @@ void test_sse_comi(double a1, double b1) r.q[1], r.q[0]);\ } +/* Force %xmm0 usage to avoid the case where both register index are 0 + to test intruction decoding more extensively */ #define CVT_OP_XMM2MMX(op)\ {\ - asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq));\ + asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq) \ + : "%xmm0");\ printf("%-9s: a=" FMT64X "" FMT64X " r=" FMT64X "\n",\ #op,\ a.q[1], a.q[0],\ @@ -2555,6 +2558,10 @@ void test_sse(void) CVT_OP_XMM(cvtpd2dq); CVT_OP_XMM(cvttpd2dq); + /* sse/mmx moves */ + CVT_OP_XMM2MMX(movdq2q); + CVT_OP_MMX2XMM(movq2dq); + /* int to float */ a.l[0] = -6; a.l[1] = 2; -- cgit v1.2.3 From 480c1cdb394fc9c0726b09891c573ee1a92765a3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jun 2006 14:03:10 +0000 Subject: fix for movq2dq, movdq2q and cvttps2dq (thanx to Julian Seward and malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2005 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index fb7b88aea..c61f964c0 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2946,16 +2946,16 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) break; case 0x2d6: /* movq2dq */ gen_op_enter_mmx(); - rm = (modrm & 7) | REX_B(s); - gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)), - offsetof(CPUX86State,fpregs[reg & 7].mmx)); - gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1))); + rm = (modrm & 7); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), + offsetof(CPUX86State,fpregs[rm].mmx)); + gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); break; case 0x3d6: /* movdq2q */ gen_op_enter_mmx(); - rm = (modrm & 7); - gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx), - offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); break; case 0xd7: /* pmovmskb */ case 0x1d7: @@ -3006,7 +3006,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); op2_offset = offsetof(CPUX86State,xmm_t0); - if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f) || + if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) || b == 0xc2)) { /* specific case for SSE single instructions */ if (b1 == 2) { -- cgit v1.2.3 From 3532fa7402cda16f7b95261b0339c58630051f0b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 24 Jun 2006 15:06:03 +0000 Subject: mips socket calls (initial patch by Raphael Rigo) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2006 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/socket.h | 138 ++++++++++++++++++ linux-user/syscall.c | 350 +++++++++++++++++++++++++++++++++++----------- linux-user/syscall_defs.h | 2 + 3 files changed, 409 insertions(+), 81 deletions(-) create mode 100644 linux-user/socket.h diff --git a/linux-user/socket.h b/linux-user/socket.h new file mode 100644 index 000000000..f13ca45e3 --- /dev/null +++ b/linux-user/socket.h @@ -0,0 +1,138 @@ + +#if defined(TARGET_MIPS) + // MIPS special values for constants + + /* + * For setsockopt(2) + * + * This defines are ABI conformant as far as Linux supports these ... + */ + #define TARGET_SOL_SOCKET 0xffff + + #define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */ + #define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */ + #define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send + SIGPIPE when they die. */ + #define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */ + #define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of + broadcast messages. */ + #define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable + socket to transmit pending data. */ + #define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. */ + #if 0 + To add: #define TARGET_SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ + #endif + + #define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */ + #define TARGET_SO_STYLE SO_TYPE /* Synonym */ + #define TARGET_SO_ERROR 0x1007 /* get error status and clear */ + #define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */ + #define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */ + #define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */ + #define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */ + #define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */ + #define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */ + #define TARGET_SO_ACCEPTCONN 0x1009 + + /* linux-specific, might as well be the same as on i386 */ + #define TARGET_SO_NO_CHECK 11 + #define TARGET_SO_PRIORITY 12 + #define TARGET_SO_BSDCOMPAT 14 + + #define TARGET_SO_PASSCRED 17 + #define TARGET_SO_PEERCRED 18 + + /* Security levels - as per NRL IPv6 - don't actually do anything */ + #define TARGET_SO_SECURITY_AUTHENTICATION 22 + #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 + #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 + + #define TARGET_SO_BINDTODEVICE 25 + + /* Socket filtering */ + #define TARGET_SO_ATTACH_FILTER 26 + #define TARGET_SO_DETACH_FILTER 27 + + #define TARGET_SO_PEERNAME 28 + #define TARGET_SO_TIMESTAMP 29 + #define SCM_TIMESTAMP SO_TIMESTAMP + + #define TARGET_SO_PEERSEC 30 + #define TARGET_SO_SNDBUFFORCE 31 + #define TARGET_SO_RCVBUFFORCE 33 + + /** sock_type - Socket types + * + * Please notice that for binary compat reasons MIPS has to + * override the enum sock_type in include/linux/net.h, so + * we define ARCH_HAS_SOCKET_TYPES here. + * + * @SOCK_DGRAM - datagram (conn.less) socket + * @SOCK_STREAM - stream (connection) socket + * @SOCK_RAW - raw socket + * @SOCK_RDM - reliably-delivered message + * @SOCK_SEQPACKET - sequential packet socket + * @SOCK_PACKET - linux specific way of getting packets at the dev level. + * For writing rarp and other similar things on the user level. + */ + enum sock_type { + TARGET_SOCK_DGRAM = 1, + TARGET_SOCK_STREAM = 2, + TARGET_SOCK_RAW = 3, + TARGET_SOCK_RDM = 4, + TARGET_SOCK_SEQPACKET = 5, + TARGET_SOCK_DCCP = 6, + TARGET_SOCK_PACKET = 10, + }; + + #define TARGET_SOCK_MAX (SOCK_PACKET + 1) + +#else + + /* For setsockopt(2) */ + #define TARGET_SOL_SOCKET 1 + + #define TARGET_SO_DEBUG 1 + #define TARGET_SO_REUSEADDR 2 + #define TARGET_SO_TYPE 3 + #define TARGET_SO_ERROR 4 + #define TARGET_SO_DONTROUTE 5 + #define TARGET_SO_BROADCAST 6 + #define TARGET_SO_SNDBUF 7 + #define TARGET_SO_RCVBUF 8 + #define TARGET_SO_SNDBUFFORCE 32 + #define TARGET_SO_RCVBUFFORCE 33 + #define TARGET_SO_KEEPALIVE 9 + #define TARGET_SO_OOBINLINE 10 + #define TARGET_SO_NO_CHECK 11 + #define TARGET_SO_PRIORITY 12 + #define TARGET_SO_LINGER 13 + #define TARGET_SO_BSDCOMPAT 14 + /* To add :#define TARGET_SO_REUSEPORT 15 */ + #define TARGET_SO_PASSCRED 16 + #define TARGET_SO_PEERCRED 17 + #define TARGET_SO_RCVLOWAT 18 + #define TARGET_SO_SNDLOWAT 19 + #define TARGET_SO_RCVTIMEO 20 + #define TARGET_SO_SNDTIMEO 21 + + /* Security levels - as per NRL IPv6 - don't actually do anything */ + #define TARGET_SO_SECURITY_AUTHENTICATION 22 + #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 + #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 + + #define TARGET_SO_BINDTODEVICE 25 + + /* Socket filtering */ + #define TARGET_SO_ATTACH_FILTER 26 + #define TARGET_SO_DETACH_FILTER 27 + + #define TARGET_SO_PEERNAME 28 + #define TARGET_SO_TIMESTAMP 29 + #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP + + #define TARGET_SO_ACCEPTCONN 30 + + #define TARGET_SO_PEERSEC 31 + +#endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 12dbf3891..229b08935 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -446,7 +446,7 @@ static inline void target_to_host_cmsg(struct msghdr *msgh, cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type); cmsg->cmsg_len = CMSG_LEN(len); - if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); memcpy(data, target_data, len); } else { @@ -490,7 +490,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len)); - if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); memcpy(target_data, data, len); } else { @@ -552,38 +552,74 @@ static long do_setsockopt(int sockfd, int level, int optname, goto unimplemented; } break; - case SOL_SOCKET: + case TARGET_SOL_SOCKET: switch (optname) { /* Options with 'int' argument. */ - case SO_DEBUG: - case SO_REUSEADDR: - case SO_TYPE: - case SO_ERROR: - case SO_DONTROUTE: - case SO_BROADCAST: - case SO_SNDBUF: - case SO_RCVBUF: - case SO_KEEPALIVE: - case SO_OOBINLINE: - case SO_NO_CHECK: - case SO_PRIORITY: + case TARGET_SO_DEBUG: + optname = SO_DEBUG; + break; + case TARGET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + case TARGET_SO_TYPE: + optname = SO_TYPE; + break; + case TARGET_SO_ERROR: + optname = SO_ERROR; + break; + case TARGET_SO_DONTROUTE: + optname = SO_DONTROUTE; + break; + case TARGET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + case TARGET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + case TARGET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + case TARGET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + case TARGET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + case TARGET_SO_NO_CHECK: + optname = SO_NO_CHECK; + break; + case TARGET_SO_PRIORITY: + optname = SO_PRIORITY; + break; #ifdef SO_BSDCOMPAT - case SO_BSDCOMPAT: -#endif - case SO_PASSCRED: - case SO_TIMESTAMP: - case SO_RCVLOWAT: - case SO_RCVTIMEO: - case SO_SNDTIMEO: - if (optlen < sizeof(uint32_t)) - return -EINVAL; - - val = tget32(optval); - ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + case TARGET_SO_BSDCOMPAT: + optname = SO_BSDCOMPAT; + break; +#endif + case TARGET_SO_PASSCRED: + optname = SO_PASSCRED; + break; + case TARGET_SO_TIMESTAMP: + optname = SO_TIMESTAMP; + break; + case TARGET_SO_RCVLOWAT: + optname = SO_RCVLOWAT; + break; + case TARGET_SO_RCVTIMEO: + optname = SO_RCVTIMEO; + break; + case TARGET_SO_SNDTIMEO: + optname = SO_SNDTIMEO; + break; break; default: goto unimplemented; } + if (optlen < sizeof(uint32_t)) + return -EINVAL; + + val = tget32(optval); + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); break; default: unimplemented: @@ -599,13 +635,14 @@ static long do_getsockopt(int sockfd, int level, int optname, int len, lv, val, ret; switch(level) { - case SOL_SOCKET: + case TARGET_SOL_SOCKET: + level = SOL_SOCKET; switch (optname) { - case SO_LINGER: - case SO_RCVTIMEO: - case SO_SNDTIMEO: - case SO_PEERCRED: - case SO_PEERNAME: + case TARGET_SO_LINGER: + case TARGET_SO_RCVTIMEO: + case TARGET_SO_SNDTIMEO: + case TARGET_SO_PEERCRED: + case TARGET_SO_PEERNAME: /* These don't just return a single integer */ goto unimplemented; default: @@ -711,6 +748,94 @@ static void unlock_iovec(struct iovec *vec, target_ulong target_addr, unlock_user (target_vec, target_addr, 0); } +static long do_socket(int domain, int type, int protocol) +{ +#if defined(TARGET_MIPS) + switch(type) { + case TARGET_SOCK_DGRAM: + type = SOCK_DGRAM; + break; + case TARGET_SOCK_STREAM: + type = SOCK_STREAM; + break; + case TARGET_SOCK_RAW: + type = SOCK_RAW; + break; + case TARGET_SOCK_RDM: + type = SOCK_RDM; + break; + case TARGET_SOCK_SEQPACKET: + type = SOCK_SEQPACKET; + break; + case TARGET_SOCK_PACKET: + type = SOCK_PACKET; + break; + } +#endif + return get_errno(socket(domain, type, protocol)); +} + +static long do_bind(int sockfd, target_ulong target_addr, + socklen_t addrlen) +{ + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + return get_errno(bind(sockfd, addr, addrlen)); +} + +static long do_connect(int sockfd, target_ulong target_addr, + socklen_t addrlen) +{ + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + return get_errno(connect(sockfd, addr, addrlen)); +} + +static long do_sendrecvmsg(int fd, target_ulong target_msg, + int flags, int send) +{ + long ret; + struct target_msghdr *msgp; + struct msghdr msg; + int count; + struct iovec *vec; + target_ulong target_vec; + + lock_user_struct(msgp, target_msg, 1); + if (msgp->msg_name) { + msg.msg_namelen = tswap32(msgp->msg_namelen); + msg.msg_name = alloca(msg.msg_namelen); + target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), + msg.msg_namelen); + } else { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } + msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); + msg.msg_control = alloca(msg.msg_controllen); + msg.msg_flags = tswap32(msgp->msg_flags); + + count = tswapl(msgp->msg_iovlen); + vec = alloca(count * sizeof(struct iovec)); + target_vec = tswapl(msgp->msg_iov); + lock_iovec(vec, target_vec, count, send); + msg.msg_iovlen = count; + msg.msg_iov = vec; + + if (send) { + target_to_host_cmsg(&msg, msgp); + ret = get_errno(sendmsg(fd, &msg, flags)); + } else { + ret = get_errno(recvmsg(fd, &msg, flags)); + if (!is_error(ret)) + host_to_target_cmsg(msgp, &msg); + } + unlock_iovec(vec, target_vec, count, !send); + return ret; +} + static long do_socketcall(int num, target_ulong vptr) { long ret; @@ -722,8 +847,7 @@ static long do_socketcall(int num, target_ulong vptr) int domain = tgetl(vptr); int type = tgetl(vptr + n); int protocol = tgetl(vptr + 2 * n); - - ret = get_errno(socket(domain, type, protocol)); + ret = do_socket(domain, type, protocol); } break; case SOCKOP_bind: @@ -731,10 +855,7 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); socklen_t addrlen = tgetl(vptr + 2 * n); - void *addr = alloca(addrlen); - - target_to_host_sockaddr(addr, target_addr, addrlen); - ret = get_errno(bind(sockfd, addr, addrlen)); + ret = do_bind(sockfd, target_addr, addrlen); } break; case SOCKOP_connect: @@ -742,17 +863,13 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); socklen_t addrlen = tgetl(vptr + 2 * n); - void *addr = alloca(addrlen); - - target_to_host_sockaddr(addr, target_addr, addrlen); - ret = get_errno(connect(sockfd, addr, addrlen)); + ret = do_connect(sockfd, target_addr, addrlen); } break; case SOCKOP_listen: { int sockfd = tgetl(vptr); int backlog = tgetl(vptr + n); - ret = get_errno(listen(sockfd, backlog)); } break; @@ -895,46 +1012,14 @@ static long do_socketcall(int num, target_ulong vptr) { int fd; target_ulong target_msg; - struct target_msghdr *msgp; - struct msghdr msg; - int flags, count; - struct iovec *vec; - target_ulong target_vec; - int send = (num == SOCKOP_sendmsg); - - target_msg = tgetl(vptr + n); - lock_user_struct(msgp, target_msg, 1); - if (msgp->msg_name) { - msg.msg_namelen = tswap32(msgp->msg_namelen); - msg.msg_name = alloca(msg.msg_namelen); - target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), - msg.msg_namelen); - } else { - msg.msg_name = NULL; - msg.msg_namelen = 0; - } - msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); - msg.msg_control = alloca(msg.msg_controllen); - msg.msg_flags = tswap32(msgp->msg_flags); - - count = tswapl(msgp->msg_iovlen); - vec = alloca(count * sizeof(struct iovec)); - target_vec = tswapl(msgp->msg_iov); - lock_iovec(vec, target_vec, count, send); - msg.msg_iovlen = count; - msg.msg_iov = vec; + int flags; fd = tgetl(vptr); + target_msg = tgetl(vptr + n); flags = tgetl(vptr + 2 * n); - if (send) { - target_to_host_cmsg(&msg, msgp); - ret = get_errno(sendmsg(fd, &msg, flags)); - } else { - ret = get_errno(recvmsg(fd, &msg, flags)); - if (!is_error(ret)) - host_to_target_cmsg(msgp, &msg); - } - unlock_iovec(vec, target_vec, count, !send); + + ret = do_sendrecvmsg(fd, target_msg, flags, + (num == SOCKOP_sendmsg)); } break; case SOCKOP_setsockopt: @@ -967,6 +1052,22 @@ static long do_socketcall(int num, target_ulong vptr) return ret; } +/* XXX: suppress this function and call directly the related socket + functions */ +static long do_socketcallwrapper(int num, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) +{ + target_long args[6]; + + tputl(args, arg1); + tputl(args+1, arg2); + tputl(args+2, arg3); + tputl(args+3, arg4); + tputl(args+4, arg5); + tputl(args+5, arg6); + + return do_socketcall(num, (target_ulong) args); +} #define N_SHM_REGIONS 32 @@ -2616,6 +2717,93 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_socketcall: ret = do_socketcall(arg1, arg2); break; + +#ifdef TARGET_NR_accept + case TARGET_NR_accept: + ret = do_socketcallwrapper(SOCKOP_accept, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_bind + case TARGET_NR_bind: + ret = do_bind(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_connect + case TARGET_NR_connect: + ret = do_connect(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_getpeername + case TARGET_NR_getpeername: + ret = do_socketcallwrapper(SOCKOP_getpeername, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_getsockname + case TARGET_NR_getsockname: + ret = do_socketcallwrapper(SOCKOP_getsockname, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_getsockopt + case TARGET_NR_getsockopt: + ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5); + break; +#endif +#ifdef TARGET_NR_listen + case TARGET_NR_listen: + ret = do_socketcallwrapper(SOCKOP_listen, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_recv + case TARGET_NR_recv: + ret = do_socketcallwrapper(SOCKOP_recv, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_recvfrom + case TARGET_NR_recvfrom: + ret = do_socketcallwrapper(SOCKOP_recvfrom, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_recvmsg + case TARGET_NR_recvmsg: + ret = do_sendrecvmsg(arg1, arg2, arg3, 0); + break; +#endif +#ifdef TARGET_NR_send + case TARGET_NR_send: + ret = do_socketcallwrapper(SOCKOP_send, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_sendmsg + case TARGET_NR_sendmsg: + ret = do_sendrecvmsg(arg1, arg2, arg3, 1); + break; +#endif +#ifdef TARGET_NR_sendto + case TARGET_NR_sendto: + ret = do_socketcallwrapper(SOCKOP_sendto, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_shutdown + case TARGET_NR_shutdown: + ret = do_socketcallwrapper(SOCKOP_shutdown, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_socket + case TARGET_NR_socket: + ret = do_socket(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_socketpair + case TARGET_NR_socketpair: + ret = do_socketcallwrapper(SOCKOP_socketpair, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_setsockopt + case TARGET_NR_setsockopt: + ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5); + break; +#endif + case TARGET_NR_syslog: goto unimplemented; case TARGET_NR_setitimer: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 4e2dd17de..b5fafcc5a 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1502,3 +1502,5 @@ struct target_sysinfo { unsigned int mem_unit; /* Memory unit size in bytes */ char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */ }; + +#include "socket.h" -- cgit v1.2.3 From 0bab00f30f798bd8ae4366a4516d2149174aa714 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 14:49:44 +0000 Subject: UDP char device (initial patch by Jason Wessel) - TCP char device git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2007 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 54 +++++++-- vl.c | 381 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 426 insertions(+), 9 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index e4985e26f..02bfc2150 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -496,8 +496,14 @@ Debug/Expert options: @table @option @item -serial dev -Redirect the virtual serial port to host device @var{dev}. Available -devices are: +Redirect the virtual serial port to host character device +@var{dev}. The default device is @code{vc} in graphical mode and +@code{stdio} in non graphical mode. + +This option can be used several times to simulate up to 4 serials +ports. + +Available character devices are: @table @code @item vc Virtual console @@ -516,13 +522,47 @@ Write output to filename. No character can be read. @item stdio [Unix only] standard input/output @item pipe:filename -[Unix only] name pipe @var{filename} +name pipe @var{filename} +@item COMn +[Windows only] Use host serial port @var{n} +@item udp:remote_port +UDP Net Console sent to locahost at remote_port +@item udp:remote_host:remote_port +UDP Net Console sent to remote_host at remote_port +@item udp:src_port:remote_host:remote_port +UDP Net Console sent from src_port to remote_host at the remote_port. + +The udp:* sub options are primary intended for netconsole. If you +just want a simple readonly console you can use @code{netcat} or +@code{nc}, by starting qemu with: @code{-serial udp:4555} and nc as: +@code{nc -u -l -p 4555}. Any time qemu writes something to that port +it will appear in the netconsole session. + +If you plan to send characters back via netconsole or you want to stop +and start qemu a lot of times, you should have qemu use the same +source port each time by using something like @code{-serial +udp:4556:localhost:4555} to qemu. Another approach is to use a patched +version of netcat which can listen to a TCP port and send and receive +characters via udp. If you have a patched version of netcat which +activates telnet remote echo and single char transfer, then you can +use the following options to step up a netcat redirector to allow +telnet on port 5555 to access the qemu port. +@table @code +@item Qemu Options +-serial udp:4556:localhost:4555 +@item netcat options +-u -P 4555 -L localhost:4556 -t -p 5555 -I -T @end table -The default device is @code{vc} in graphical mode and @code{stdio} in -non graphical mode. -This option can be used several times to simulate up to 4 serials -ports. + +@item tcp:remote_host:remote_port +TCP Net Console sent to remote_host at the remote_port +@item tcpl:host:port +TCP Net Console: wait for connection on @var{host} on the local port +@var{port}. If host is omitted, 0.0.0.0 is assumed. Only one TCP +connection at a time is accepted. You can use @code{telnet} to connect +to the corresponding character device. +@end table @item -parallel dev Redirect the virtual parallel port to host device @var{dev} (same diff --git a/vl.c b/vl.c index 76cfe71e9..7d7723460 100644 --- a/vl.c +++ b/vl.c @@ -2130,6 +2130,373 @@ CharDriverState *qemu_chr_open_win_file_out(const char *file_out) } #endif +/***********************************************************/ +/* UDP Net console */ + +typedef struct { + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *fd_opaque; + int fd; + struct sockaddr_in daddr; + char buf[1024]; + int bufcnt; + int bufptr; + int max_size; +} NetCharDriver; + +static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + NetCharDriver *s = chr->opaque; + + return sendto(s->fd, buf, len, 0, + (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in)); +} + +static int udp_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + NetCharDriver *s = chr->opaque; + + s->max_size = s->fd_can_read(s->fd_opaque); + + /* If there were any stray characters in the queue process them + * first + */ + while (s->max_size > 0 && s->bufptr < s->bufcnt) { + s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1); + s->bufptr++; + s->max_size = s->fd_can_read(s->fd_opaque); + } + return s->max_size; +} + +static void udp_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + NetCharDriver *s = chr->opaque; + + if (s->max_size == 0) + return; + s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0); + s->bufptr = s->bufcnt; + if (s->bufcnt <= 0) + return; + + s->bufptr = 0; + while (s->max_size > 0 && s->bufptr < s->bufcnt) { + s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1); + s->bufptr++; + s->max_size = s->fd_can_read(s->fd_opaque); + } +} + +static void udp_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + NetCharDriver *s = chr->opaque; + + if (s->fd >= 0) { + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->fd_opaque = opaque; + qemu_set_fd_handler2(s->fd, udp_chr_read_poll, + udp_chr_read, NULL, chr); + } +} + +int parse_host_port(struct sockaddr_in *saddr, const char *str); + +CharDriverState *qemu_chr_open_udp(const char *def) +{ + CharDriverState *chr = NULL; + NetCharDriver *s = NULL; + int fd = -1; + int con_type; + struct sockaddr_in addr; + const char *p, *r; + int port; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + goto return_err; + s = qemu_mallocz(sizeof(NetCharDriver)); + if (!s) + goto return_err; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + perror("socket(PF_INET, SOCK_DGRAM)"); + goto return_err; + } + + /* There are three types of port definitions + * 1) udp:remote_port + * Juse use 0.0.0.0 for the IP and send to remote + * 2) udp:remote_host:port + * Use a IP and send traffic to remote + * 3) udp:local_port:remote_host:remote_port + * Use local_port as the originator + #2 + */ + con_type = 0; + p = def; + while ((p = strchr(p, ':'))) { + p++; + con_type++; + } + + p = def; + memset(&addr,0,sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + s->daddr.sin_family = AF_INET; + s->daddr.sin_addr.s_addr = htonl(INADDR_ANY); + + switch (con_type) { + case 0: + port = strtol(p, (char **)&r, 0); + if (r == p) { + fprintf(stderr, "Error parsing port number\n"); + goto return_err; + } + s->daddr.sin_port = htons((short)port); + break; + case 2: + port = strtol(p, (char **)&r, 0); + if (r == p) { + fprintf(stderr, "Error parsing port number\n"); + goto return_err; + } + addr.sin_port = htons((short)port); + p = r + 1; + /* Fall through to case 1 now that we have the local port */ + case 1: + if (parse_host_port(&s->daddr, p) < 0) { + fprintf(stderr, "Error parsing host name and port\n"); + goto return_err; + } + break; + default: + fprintf(stderr, "Too many ':' characters\n"); + goto return_err; + } + + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + perror("bind"); + goto return_err; + } + + s->fd = fd; + s->bufcnt = 0; + s->bufptr = 0; + chr->opaque = s; + chr->chr_write = udp_chr_write; + chr->chr_add_read_handler = udp_chr_add_read_handler; + return chr; + +return_err: + if (chr) + free(chr); + if (s) + free(s); + if (fd >= 0) + closesocket(fd); + return NULL; +} + +/***********************************************************/ +/* TCP Net console */ + +typedef struct { + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *fd_opaque; + int fd, listen_fd; + int connected; + int max_size; +} TCPCharDriver; + +static void tcp_chr_accept(void *opaque); + +static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + TCPCharDriver *s = chr->opaque; + if (s->connected) { + return send_all(s->fd, buf, len); + } else { + /* XXX: indicate an error ? */ + return len; + } +} + +static int tcp_chr_read_poll(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + if (!s->connected) + return 0; + s->max_size = s->fd_can_read(s->fd_opaque); + return s->max_size; +} + +static void tcp_chr_read(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + uint8_t buf[1024]; + int len, size; + + if (!s->connected || s->max_size <= 0) + return; + len = sizeof(buf); + if (len > s->max_size) + len = s->max_size; + size = recv(s->fd, buf, len, 0); + if (size == 0) { + /* connection closed */ + s->connected = 0; + if (s->listen_fd >= 0) { + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + } + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + closesocket(s->fd); + s->fd = -1; + } else if (size > 0) { + s->fd_read(s->fd_opaque, buf, size); + } +} + +static void tcp_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + TCPCharDriver *s = chr->opaque; + + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->fd_opaque = opaque; +} + +static void tcp_chr_connect(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + + s->connected = 1; + qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, + tcp_chr_read, NULL, chr); +} + +static void tcp_chr_accept(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + struct sockaddr_in saddr; + socklen_t len; + int fd; + + for(;;) { + len = sizeof(saddr); + fd = accept(s->listen_fd, (struct sockaddr *)&saddr, &len); + if (fd < 0 && errno != EINTR) { + return; + } else if (fd >= 0) { + break; + } + } + socket_set_nonblock(fd); + s->fd = fd; + qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); + tcp_chr_connect(chr); +} + +static void tcp_chr_close(CharDriverState *chr) +{ + TCPCharDriver *s = chr->opaque; + if (s->fd >= 0) + closesocket(s->fd); + if (s->listen_fd >= 0) + closesocket(s->listen_fd); + qemu_free(s); +} + +static CharDriverState *qemu_chr_open_tcp(const char *host_str, + int is_listen) +{ + CharDriverState *chr = NULL; + TCPCharDriver *s = NULL; + int fd = -1, ret, err, val; + struct sockaddr_in saddr; + + if (parse_host_port(&saddr, host_str) < 0) + goto fail; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + goto fail; + s = qemu_mallocz(sizeof(TCPCharDriver)); + if (!s) + goto fail; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + goto fail; + socket_set_nonblock(fd); + + s->connected = 0; + s->fd = -1; + s->listen_fd = -1; + if (is_listen) { + /* allow fast reuse */ + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); + + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) + goto fail; + ret = listen(fd, 0); + if (ret < 0) + goto fail; + s->listen_fd = fd; + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + } else { + for(;;) { + ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + err = socket_error(); + if (err == EINTR || err == EWOULDBLOCK) { + } else if (err == EINPROGRESS) { + break; + } else { + goto fail; + } + } else { + s->connected = 1; + break; + } + } + s->fd = fd; + if (s->connected) + tcp_chr_connect(chr); + else + qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr); + } + + chr->opaque = s; + chr->chr_write = tcp_chr_write; + chr->chr_add_read_handler = tcp_chr_add_read_handler; + chr->chr_close = tcp_chr_close; + return chr; + fail: + if (fd >= 0) + closesocket(fd); + qemu_free(s); + qemu_free(chr); + return NULL; +} + CharDriverState *qemu_chr_open(const char *filename) { const char *p; @@ -2139,6 +2506,15 @@ CharDriverState *qemu_chr_open(const char *filename) } else if (!strcmp(filename, "null")) { return qemu_chr_open_null(); } else + if (strstart(filename, "tcp:", &p)) { + return qemu_chr_open_tcp(p, 0); + } else + if (strstart(filename, "tcpl:", &p)) { + return qemu_chr_open_tcp(p, 1); + } else + if (strstart(filename, "udp:", &p)) { + return qemu_chr_open_udp(p); + } else #ifndef _WIN32 if (strstart(filename, "file:", &p)) { return qemu_chr_open_file_out(p); @@ -2844,7 +3220,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) socket_set_nonblock(fd); return fd; fail: - if (fd>=0) close(fd); + if (fd >= 0) + closesocket(fd); return -1; } @@ -2972,7 +3349,7 @@ static void net_socket_accept(void *opaque) } s1 = net_socket_fd_init(s->vlan, fd, 1); if (!s1) { - close(fd); + closesocket(fd); } else { snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), "socket: connection from %s:%d", -- cgit v1.2.3 From 1579bde84d37aada4054ee40e1e333930211f495 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 14:50:00 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2008 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changelog b/Changelog index 20f6ebfb5..0b0d2a45f 100644 --- a/Changelog +++ b/Changelog @@ -6,6 +6,10 @@ version 0.8.2: - 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 character devices (Jason Wessel) + - TCP character devices version 0.8.1: -- cgit v1.2.3 From 9d9754a31dd1e954c95d7cc3553845677a1a9f63 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 15:32:37 +0000 Subject: sparc fpu fix - allow 64 bit addresses (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2009 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 67 +++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 3dcaa4c9c..6ad393f79 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -315,11 +315,11 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) for(i = 0; i < 24; i++) { registers[i + 8] = tswapl(env->regwptr[i]); } +#ifndef TARGET_SPARC64 /* fill in fprs */ for (i = 0; i < 32; i++) { registers[i + 32] = tswapl(*((uint32_t *)&env->fpr[i])); } -#ifndef TARGET_SPARC64 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ registers[64] = tswapl(env->y); { @@ -337,16 +337,21 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) registers[72] = 0; return 73 * sizeof(target_ulong); #else - for (i = 0; i < 32; i += 2) { - registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i])); + /* fill in fprs */ + for (i = 0; i < 64; i += 2) { + uint64_t tmp; + + tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32; + tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1])); + registers[i/2 + 32] = tmp; } - registers[81] = tswapl(env->pc); - registers[82] = tswapl(env->npc); - registers[83] = tswapl(env->tstate[env->tl]); - registers[84] = tswapl(env->fsr); - registers[85] = tswapl(env->fprs); - registers[86] = tswapl(env->y); - return 87 * sizeof(target_ulong); + registers[64] = tswapl(env->pc); + registers[65] = tswapl(env->npc); + registers[66] = tswapl(env->tstate[env->tl]); + registers[67] = tswapl(env->fsr); + registers[68] = tswapl(env->fprs); + registers[69] = tswapl(env->y); + return 70 * sizeof(target_ulong); #endif } @@ -363,11 +368,11 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) for(i = 0; i < 24; i++) { env->regwptr[i] = tswapl(registers[i + 8]); } +#ifndef TARGET_SPARC64 /* fill in fprs */ for (i = 0; i < 32; i++) { *((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]); } -#ifndef TARGET_SPARC64 /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ env->y = tswapl(registers[64]); PUT_PSR(env, tswapl(registers[65])); @@ -377,18 +382,16 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->npc = tswapl(registers[69]); env->fsr = tswapl(registers[70]); #else - for (i = 0; i < 32; i += 2) { - uint64_t tmp; - tmp = tswapl(registers[i/2 + 64]) << 32; - tmp |= tswapl(registers[i/2 + 64 + 1]); - *((uint64_t *)&env->fpr[i]) = tmp; + for (i = 0; i < 64; i += 2) { + *((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32); + *((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 0xffffffff); } - env->pc = tswapl(registers[81]); - env->npc = tswapl(registers[82]); - env->tstate[env->tl] = tswapl(registers[83]); - env->fsr = tswapl(registers[84]); - env->fprs = tswapl(registers[85]); - env->y = tswapl(registers[86]); + env->pc = tswapl(registers[64]); + env->npc = tswapl(registers[65]); + env->tstate[env->tl] = tswapl(registers[66]); + env->fsr = tswapl(registers[67]); + env->fprs = tswapl(registers[68]); + env->y = tswapl(registers[69]); #endif } #elif defined (TARGET_ARM) @@ -565,7 +568,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; - uint32_t addr, len; + target_ulong addr, len; #ifdef DEBUG_GDB printf("command='%s'\n", line_buf); @@ -580,7 +583,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) break; case 'c': if (*p != '\0') { - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); #if defined(TARGET_I386) env->eip = addr; #elif defined (TARGET_PPC) @@ -636,10 +639,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) put_packet(s, "OK"); break; case 'm': - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, NULL, 16); + len = strtoull(p, NULL, 16); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) { put_packet (s, "E14"); } else { @@ -648,10 +651,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) } break; case 'M': - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (*p == ':') p++; hextomem(mem_buf, p, len); @@ -664,10 +667,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (type == 0 || type == 1) { if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; @@ -681,10 +684,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (type == 0 || type == 1) { cpu_breakpoint_remove(env, addr); put_packet(s, "OK"); -- cgit v1.2.3 From 6b1575b74689c77e7bd9d8aafe63ed5cbd22f72d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 15:33:53 +0000 Subject: cpu_get_phys_page_debug fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2010 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index bbd072c37..65ee97599 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2771,7 +2771,8 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) int prot, access_index; if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) - return -1; + if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 0, 0) != 0) + return -1; return phys_addr; } #endif -- cgit v1.2.3 From be995c27640a82c7056b6f53d02ec823570114e5 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 16:25:21 +0000 Subject: removed unused code - init timers earlier git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2011 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 128 ++++++------------------------------------------------------------- 1 file changed, 10 insertions(+), 118 deletions(-) diff --git a/vl.c b/vl.c index 7d7723460..9f7143cd8 100644 --- a/vl.c +++ b/vl.c @@ -92,11 +92,7 @@ //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IOPORT -#if !defined(CONFIG_SOFTMMU) -#define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) -#else #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024) -#endif #ifdef TARGET_PPC #define DEFAULT_RAM_SIZE 144 @@ -3860,20 +3856,6 @@ void dumb_display_init(DisplayState *ds) ds->dpy_refresh = dumb_refresh; } -#if !defined(CONFIG_SOFTMMU) -/***********************************************************/ -/* cpu signal handler */ -static void host_segv_handler(int host_signum, siginfo_t *info, - void *puc) -{ - if (cpu_signal_handler(host_signum, info, puc)) - return; - if (stdio_nb_clients > 0) - term_exit(); - abort(); -} -#endif - /***********************************************************/ /* I/O handling */ @@ -5133,23 +5115,13 @@ void help(void) "\n" "When using -nographic, press 'ctrl-a h' to get some help.\n" , -#ifdef CONFIG_SOFTMMU "qemu", -#else - "qemu-fast", -#endif DEFAULT_RAM_SIZE, #ifndef _WIN32 DEFAULT_NETWORK_SCRIPT, #endif DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); -#ifndef CONFIG_SOFTMMU - printf("\n" - "NOTE: this version of QEMU is faster but it needs slightly patched OSes to\n" - "work. Please use the 'qemu' executable to have a more accurate (but slower)\n" - "PC emulation.\n"); -#endif exit(1); } @@ -5512,10 +5484,17 @@ int main(int argc, char **argv) int usb_devices_index; LIST_INIT (&vm_change_state_head); -#if !defined(CONFIG_SOFTMMU) - /* we never want that malloc() uses mmap() */ - mallopt(M_MMAP_THRESHOLD, 4096 * 1024); +#ifndef _WIN32 + { + struct sigaction act; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + } #endif + init_timers(); + register_machines(); machine = first_machine; initrd_filename = NULL; @@ -5922,15 +5901,7 @@ int main(int argc, char **argv) boot_device = 'd'; } -#if !defined(CONFIG_SOFTMMU) - /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ - { - static uint8_t stdout_buf[4096]; - setvbuf(stdout, stdout_buf, _IOLBF, sizeof(stdout_buf)); - } -#else setvbuf(stdout, NULL, _IOLBF, 0); -#endif #ifdef _WIN32 socket_init(); @@ -5954,45 +5925,11 @@ int main(int argc, char **argv) /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; -#ifdef CONFIG_SOFTMMU phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { fprintf(stderr, "Could not allocate physical memory\n"); exit(1); } -#else - /* as we must map the same page at several addresses, we must use - a fd */ - { - const char *tmpdir; - - tmpdir = getenv("QEMU_TMPDIR"); - if (!tmpdir) - tmpdir = "/tmp"; - snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/vlXXXXXX", tmpdir); - if (mkstemp(phys_ram_file) < 0) { - fprintf(stderr, "Could not create temporary memory file '%s'\n", - phys_ram_file); - exit(1); - } - phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); - if (phys_ram_fd < 0) { - fprintf(stderr, "Could not open temporary memory file '%s'\n", - phys_ram_file); - exit(1); - } - ftruncate(phys_ram_fd, phys_ram_size); - unlink(phys_ram_file); - phys_ram_base = mmap(get_mmap_addr(phys_ram_size), - phys_ram_size, - PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, - phys_ram_fd, 0); - if (phys_ram_base == MAP_FAILED) { - fprintf(stderr, "Could not map physical memory\n"); - exit(1); - } - } -#endif /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); @@ -6097,51 +6034,6 @@ int main(int argc, char **argv) } } - /* setup cpu signal handlers for MMU / self modifying code handling */ -#if !defined(CONFIG_SOFTMMU) - -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - { - stack_t stk; - signal_stack = memalign(16, SIGNAL_STACK_SIZE); - stk.ss_sp = signal_stack; - stk.ss_size = SIGNAL_STACK_SIZE; - stk.ss_flags = 0; - - if (sigaltstack(&stk, NULL) < 0) { - perror("sigaltstack"); - exit(1); - } - } -#endif - { - struct sigaction act; - - sigfillset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; -#endif - act.sa_sigaction = host_segv_handler; - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGBUS, &act, NULL); -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - sigaction(SIGFPE, &act, NULL); -#endif - } -#endif - -#ifndef _WIN32 - { - struct sigaction act; - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &act, NULL); - } -#endif - init_timers(); - machine->init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, initrd_filename); -- cgit v1.2.3 From e15d737181c9e7da2274ca62a3f4f28b7a5cbeb7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 16:26:29 +0000 Subject: send correctly long key sequences on slow terminals - fixes backspace handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2012 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 24 deletions(-) diff --git a/console.c b/console.c index 6f9dc1fea..279b7e01e 100644 --- a/console.c +++ b/console.c @@ -53,6 +53,57 @@ enum TTYState { 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 { @@ -81,8 +132,13 @@ struct TextConsole { 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; @@ -712,12 +768,8 @@ static void console_putchar(TextConsole *s, int ch) console_put_lf(s); break; case '\b': /* backspace */ - if(s->x > 0) s->x--; - y1 = (s->y_base + s->y) % s->total_height; - c = &s->cells[y1 * s->width + s->x]; - c->ch = ' '; - c->t_attrib = s->t_attrib; - update_xy(s, s->x, s->y); + if (s->x > 0) + s->x--; break; case '\t': /* tabspace */ if (s->x + (8 - (s->x % 8)) > s->width) { @@ -835,6 +887,7 @@ static void console_chr_add_read_handler(CharDriverState *chr, 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; } @@ -854,6 +907,28 @@ static void console_send_event(CharDriverState *chr, int event) } } +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) { @@ -879,25 +954,26 @@ void kbd_put_keysym(int keysym) console_scroll(10); break; default: - if (s->fd_read) { - /* convert the QEMU keysym to VT100 key string */ - q = buf; - if (keysym >= 0xe100 && keysym <= 0xe11f) { - *q++ = '\033'; - *q++ = '['; - c = keysym - 0xe100; - if (c >= 10) - *q++ = '0' + (c / 10); - *q++ = '0' + (c % 10); - *q++ = '~'; - } else if (keysym >= 0xe120 && keysym <= 0xe17f) { - *q++ = '\033'; - *q++ = '['; - *q++ = keysym & 0xff; - } else { + /* convert the QEMU keysym to VT100 key string */ + q = buf; + if (keysym >= 0xe100 && keysym <= 0xe11f) { + *q++ = '\033'; + *q++ = '['; + c = keysym - 0xe100; + if (c >= 10) + *q++ = '0' + (c / 10); + *q++ = '0' + (c % 10); + *q++ = '~'; + } else if (keysym >= 0xe120 && keysym <= 0xe17f) { + *q++ = '\033'; + *q++ = '['; + *q++ = keysym & 0xff; + } else { *q++ = keysym; - } - s->fd_read(s->fd_opaque, buf, q - buf); + } + if (s->fd_read) { + qemu_fifo_write(&s->out_fifo, buf, q - buf); + kbd_send_chars(s); } break; } @@ -974,6 +1050,10 @@ CharDriverState *text_console_init(DisplayState *ds) 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++) { -- cgit v1.2.3 From a18e524af0c23b083dc69f9a2eed563893d01f22 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 17:18:27 +0000 Subject: multiple wait object support for win32 (kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2013 c046a42c-6fe2-441c-8c8c-71466251a162 --- tap-win32.c | 8 +++++++ vl.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++------------- vl.h | 9 ++++++++ 3 files changed, 75 insertions(+), 16 deletions(-) diff --git a/tap-win32.c b/tap-win32.c index b6056955c..af5e25e68 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -630,6 +630,7 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, typedef struct TAPState { VLANClientState *vc; tap_win32_overlapped_t *handle; + HANDLE tap_event; } TAPState; static TAPState *tap_win32_state = NULL; @@ -656,6 +657,7 @@ void tap_win32_poll(void) if (size > 0) { qemu_send_packet(s->vc, buf, size); tap_win32_free_buffer(s->handle, buf); + SetEvent(s->tap_event); } } @@ -676,5 +678,11 @@ int tap_win32_init(VLANState *vlan, const char *ifname) snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s", ifname); tap_win32_state = s; + + s->tap_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!s->tap_event) { + fprintf(stderr, "tap-win32: Failed CreateEvent\n"); + } + qemu_add_wait_object(s->tap_event, NULL, NULL); return 0; } diff --git a/vl.c b/vl.c index 9f7143cd8..118a1e211 100644 --- a/vl.c +++ b/vl.c @@ -1014,7 +1014,7 @@ static void init_timers(void) perror("failed CreateEvent"); exit(1); } - ResetEvent(host_alarm); + qemu_add_wait_object(host_alarm, NULL, NULL); } pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; #else @@ -3962,6 +3962,51 @@ void qemu_del_polling_cb(PollingFunc *func, void *opaque) } } +#ifdef _WIN32 +/***********************************************************/ +/* Wait objects support */ +typedef struct WaitObjects { + int num; + HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; + WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; + void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; +} WaitObjects; + +static WaitObjects wait_objects = {0}; + +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) +{ + WaitObjects *w = &wait_objects; + + if (w->num >= MAXIMUM_WAIT_OBJECTS) + return -1; + w->events[w->num] = handle; + w->func[w->num] = func; + w->opaque[w->num] = opaque; + w->num++; + return 0; +} + +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) +{ + int i, found; + WaitObjects *w = &wait_objects; + + found = 0; + for (i = 0; i < w->num; i++) { + if (w->events[i] == handle) + found = 1; + if (found) { + w->events[i] = w->events[i + 1]; + w->func[i] = w->func[i + 1]; + w->opaque[i] = w->opaque[i + 1]; + } + } + if (found) + w->num--; +} +#endif + /***********************************************************/ /* savevm/loadvm support */ @@ -4838,21 +4883,18 @@ void main_loop_wait(int timeout) } #ifdef _WIN32 if (ret == 0 && timeout > 0) { - int err; - HANDLE hEvents[1]; - - hEvents[0] = host_alarm; - ret = WaitForMultipleObjects(1, hEvents, FALSE, timeout); - switch(ret) { - case WAIT_OBJECT_0 + 0: - break; - case WAIT_TIMEOUT: - break; - default: - err = GetLastError(); - fprintf(stderr, "Wait error %d %d\n", ret, err); - break; - } + int err; + WaitObjects *w = &wait_objects; + + ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout); + if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { + if (w->func[ret - WAIT_OBJECT_0]) + w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); + } else if (ret == WAIT_TIMEOUT) { + } else { + err = GetLastError(); + fprintf(stderr, "Wait error %d %d\n", ret, err); + } } #endif /* poll any events */ diff --git a/vl.h b/vl.h index 331245157..3cc4621bc 100644 --- a/vl.h +++ b/vl.h @@ -47,6 +47,7 @@ #endif #ifdef _WIN32 +#include #define fsync _commit #define lseek _lseeki64 #define ENOTSUP 4096 @@ -221,6 +222,14 @@ typedef int PollingFunc(void *opaque); int qemu_add_polling_cb(PollingFunc *func, void *opaque); void qemu_del_polling_cb(PollingFunc *func, void *opaque); +#ifdef _WIN32 +/* Wait objects handling */ +typedef void WaitObjectFunc(void *opaque); + +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +#endif + /* character device */ #define CHR_EVENT_BREAK 0 /* serial break char */ -- cgit v1.2.3 From 87ac54273f756f87a5fa8b369cc21430d4e3168b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 17:35:56 +0000 Subject: disable user targets by default for cross compile with mingw32 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2014 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 59dcee48f..e6c74e4ec 100755 --- a/configure +++ b/configure @@ -213,7 +213,7 @@ for opt do ;; --fmod-inc=*) fmod_inc="$optarg" ;; - --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" + --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no" ;; --disable-slirp) slirp="no" ;; -- cgit v1.2.3 From 26489844dcc1d2f3e17c92210475e6f3e54b503e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 17:37:36 +0000 Subject: avoid name conflicts git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2015 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/console.c b/console.c index 279b7e01e..0dfed7129 100644 --- a/console.c +++ b/console.c @@ -27,8 +27,8 @@ #define DEFAULT_BACKSCROLL 512 #define MAX_CONSOLES 12 -#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) -#define RGB(r, g, b) RGBA(r, g, b, 0xff) +#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; @@ -330,24 +330,24 @@ enum color_names { static const uint32_t color_table_rgb[2][8] = { { /* dark */ - RGB(0x00, 0x00, 0x00), /* black */ - RGB(0xaa, 0x00, 0x00), /* red */ - RGB(0x00, 0xaa, 0x00), /* green */ - RGB(0xaa, 0xaa, 0x00), /* yellow */ - RGB(0x00, 0x00, 0xaa), /* blue */ - RGB(0xaa, 0x00, 0xaa), /* magenta */ - RGB(0x00, 0xaa, 0xaa), /* cyan */ - RGB(0xaa, 0xaa, 0xaa), /* white */ + 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 */ - RGB(0x00, 0x00, 0x00), /* black */ - RGB(0xff, 0x00, 0x00), /* red */ - RGB(0x00, 0xff, 0x00), /* green */ - RGB(0xff, 0xff, 0x00), /* yellow */ - RGB(0x00, 0x00, 0xff), /* blue */ - RGB(0xff, 0x00, 0xff), /* magenta */ - RGB(0x00, 0xff, 0xff), /* cyan */ - RGB(0xff, 0xff, 0xff), /* white */ + 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 */ } }; -- cgit v1.2.3 From 755d13753b32702fe8897ab0c0658ac7b04a9ff8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 18:02:02 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2016 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osdep.h b/osdep.h index f818ce03a..29a261cbd 100644 --- a/osdep.h +++ b/osdep.h @@ -27,6 +27,8 @@ extern void __longjmp(jmp_buf env, int val); #include +struct siginfo; + /* NOTE: it works only because the glibc sigset_t is >= kernel sigset_t */ struct qemu_sigaction { union { -- cgit v1.2.3 From 3b42c9794cb17f6af380dab2f08e1b1618f3b247 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 18:02:38 +0000 Subject: sse2 comment git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2017 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 59a0b6d99..d7abae69e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,7 @@ -include ../config-host.mak -CFLAGS=-Wall -O2 -g #-msse2 +CFLAGS=-Wall -O2 -g +#CFLAGS+=-msse2 LDFLAGS= ifeq ($(ARCH),i386) -- cgit v1.2.3 From 26a76461f259031f2c30cd5843a5ca91e056cf03 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 18:15:32 +0000 Subject: C99 64 bit printf git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2018 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/audio.c | 4 ++-- audio/audio_template.h | 2 +- block-vpc.c | 2 +- cpu-defs.h | 2 +- disas.c | 4 ++-- hw/apic.c | 4 ++-- hw/cuda.c | 2 +- hw/i8259.c | 2 +- hw/mips_r4k.c | 2 +- hw/sb16.c | 2 +- hw/sh7750.c | 2 +- hw/slavio_intctl.c | 2 +- hw/slavio_timer.c | 2 +- kqemu.c | 4 ++-- monitor.c | 22 +++++++++++----------- target-arm/nwfpe/fpa11_cprt.c | 2 +- target-i386/helper.c | 4 ++-- target-i386/helper2.c | 28 ++++++++++++++-------------- target-ppc/translate.c | 6 +++--- target-ppc/translate_init.c | 2 +- target-sparc/helper.c | 16 ++++++++-------- target-sparc/op_helper.c | 8 ++++---- tests/test-i386.c | 2 +- vl.c | 2 +- vl.h | 3 +++ 25 files changed, 67 insertions(+), 64 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 763453523..f10025bf4 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -997,7 +997,7 @@ static int audio_get_avail (SWVoiceIn *sw) } ldebug ( - "%s: get_avail live %d ret %lld\n", + "%s: get_avail live %d ret %" PRId64 "\n", SW_NAME (sw), live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift ); @@ -1023,7 +1023,7 @@ static int audio_get_free (SWVoiceOut *sw) dead = sw->hw->samples - live; #ifdef DEBUG_OUT - dolog ("%s: get_free live %d dead %d ret %lld\n", + dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", SW_NAME (sw), live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); #endif diff --git a/audio/audio_template.h b/audio/audio_template.h index 23d024201..419a4aa46 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -542,7 +542,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) cur_ts = sw->hw->ts_helper; old_ts = ts->old_ts; - /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */ + /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */ if (cur_ts >= old_ts) { delta = cur_ts - old_ts; diff --git a/block-vpc.c b/block-vpc.c index e4c51bab2..bdc3b8891 100644 --- a/block-vpc.c +++ b/block-vpc.c @@ -163,7 +163,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) bitmap_offset = 512 * s->pagetable[pagetable_index]; block_offset = bitmap_offset + 512 + (512 * pageentry_index); -// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n", +// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n", // sector_num, pagetable_index, pageentry_index, // bitmap_offset, block_offset); diff --git a/cpu-defs.h b/cpu-defs.h index 665158a38..674c0bd3f 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -47,7 +47,7 @@ typedef uint32_t target_ulong; #elif TARGET_LONG_SIZE == 8 typedef int64_t target_long; typedef uint64_t target_ulong; -#define TARGET_FMT_lx "%016llx" +#define TARGET_FMT_lx "%016" PRIx64 #else #error TARGET_LONG_SIZE undefined #endif diff --git a/disas.c b/disas.c index c38da08fd..fd91b9220 100644 --- a/disas.c +++ b/disas.c @@ -58,7 +58,7 @@ perror_memory (status, memaddr, info) /* Actually, address between memaddr and memaddr + len was out of bounds. */ (*info->fprintf_func) (info->stream, - "Address 0x%llx is out of bounds.\n", memaddr); + "Address 0x%" PRIx64 " is out of bounds.\n", memaddr); } /* This could be in a separate file, to save miniscule amounts of space @@ -73,7 +73,7 @@ generic_print_address (addr, info) bfd_vma addr; struct disassemble_info *info; { - (*info->fprintf_func) (info->stream, "0x%llx", addr); + (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); } /* Just return the given address. */ diff --git a/hw/apic.c b/hw/apic.c index 65f96a5b7..8f88cce01 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -239,7 +239,7 @@ void cpu_set_apic_base(CPUState *env, uint64_t val) { APICState *s = env->apic_state; #ifdef DEBUG_APIC - printf("cpu_set_apic_base: %016llx\n", val); + printf("cpu_set_apic_base: %016" PRIx64 "\n", val); #endif s->apicbase = (val & 0xfffff000) | (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); @@ -255,7 +255,7 @@ uint64_t cpu_get_apic_base(CPUState *env) { APICState *s = env->apic_state; #ifdef DEBUG_APIC - printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase); + printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase); #endif return s->apicbase; } diff --git a/hw/cuda.c b/hw/cuda.c index dec5ffb31..f3c2b5601 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -209,7 +209,7 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) } #if 0 #ifdef DEBUG_CUDA - printf("latch=%d counter=%lld delta_next=%lld\n", + printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", s->latch, d, next_time - d); #endif #endif diff --git a/hw/i8259.c b/hw/i8259.c index 6c2ddfff8..c747f106e 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -531,7 +531,7 @@ void irq_info(void) for (i = 0; i < 16; i++) { count = irq_count[i]; if (count > 0) - term_printf("%2d: %lld\n", i, count); + term_printf("%2d: %" PRId64 "\n", i, count); } #endif } diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index f10430013..22d742a2e 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -60,7 +60,7 @@ static void cpu_mips_update_count (CPUState *env, uint32_t count, next++; #if 0 if (logfile) { - fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n", + fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", __func__, now, count, compare, next - now); } #endif diff --git a/hw/sb16.c b/hw/sb16.c index f7b12e611..f5eb7fe80 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -765,7 +765,7 @@ static void complete (SB16State *s) ); } } - ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks); + ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks); } break; diff --git a/hw/sh7750.c b/hw/sh7750.c index 041e3eed1..21f9bc0ae 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -124,7 +124,7 @@ static void start_timer0(SH7750State * s) s->periph_freq); if (next == now) next = now + 1; - fprintf(stderr, "now=%016llx, next=%016llx\n", now, next); + fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next); fprintf(stderr, "timer will underflow in %f seconds\n", (float) (next - now) / (float) ticks_per_sec); diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index e43151fad..288fb50f0 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -203,7 +203,7 @@ void slavio_irq_info(void *opaque) for (i = 0; i < 32; i++) { count = s->irq_count[i]; if (count > 0) - term_printf("%2d: %lld\n", i, count); + term_printf("%2d: %" PRId64 "\n", i, count); } #endif } diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index d75a76a63..976f0d4db 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -100,7 +100,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) // Convert remaining counter ticks to CPU ticks s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); - DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); + DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); if (s->mode != 1) pic_set_irq_cpu(s->irq, out, s->cpu); diff --git a/kqemu.c b/kqemu.c index bd70474d6..61983d01d 100644 --- a/kqemu.c +++ b/kqemu.c @@ -598,12 +598,12 @@ void kqemu_record_dump(void) perror("/tmp/kqemu.stats"); exit(1); } - fprintf(f, "total: %lld\n", total); + fprintf(f, "total: %" PRId64 "\n", total); sum = 0; for(i = 0; i < nb_pc_records; i++) { r = pr[i]; sum += r->count; - fprintf(f, "%08lx: %lld %0.2f%% %0.2f%%\n", + fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n", r->pc, r->count, (double)r->count / (double)total * 100.0, diff --git a/monitor.c b/monitor.c index d9257ffb3..e495c5096 100644 --- a/monitor.c +++ b/monitor.c @@ -533,16 +533,16 @@ static void memory_dump(int count, int format, int wsize, term_printf(" "); switch(format) { case 'o': - term_printf("%#*llo", max_digits, v); + term_printf("%#*" PRIo64, max_digits, v); break; case 'x': - term_printf("0x%0*llx", max_digits, v); + term_printf("0x%0*" PRIx64, max_digits, v); break; case 'u': - term_printf("%*llu", max_digits, v); + term_printf("%*" PRIu64, max_digits, v); break; case 'd': - term_printf("%*lld", max_digits, v); + term_printf("%*" PRId64, max_digits, v); break; case 'c': term_printc(v); @@ -602,17 +602,17 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne #else switch(format) { case 'o': - term_printf("%#llo", val); + term_printf("%#" PRIo64, val); break; case 'x': - term_printf("%#llx", val); + term_printf("%#" PRIx64, val); break; case 'u': - term_printf("%llu", val); + term_printf("%" PRIu64, val); break; default: case 'd': - term_printf("%lld", val); + term_printf("%" PRId64, val); break; case 'c': term_printc(val); @@ -1026,11 +1026,11 @@ static void do_info_profile(void) total = qemu_time; if (total == 0) total = 1; - term_printf("async time %lld (%0.3f)\n", + term_printf("async time %" PRId64 " (%0.3f)\n", dev_time, dev_time / (double)ticks_per_sec); - term_printf("qemu time %lld (%0.3f)\n", + term_printf("qemu time %" PRId64 " (%0.3f)\n", qemu_time, qemu_time / (double)ticks_per_sec); - term_printf("kqemu time %lld (%0.3f %0.1f%%) count=%lld int=%lld excp=%lld intr=%lld\n", + term_printf("kqemu time %" PRId64 " (%0.3f %0.1f%%) count=%" PRId64 " int=%" PRId64 " excp=%" PRId64 " intr=%" PRId64 "\n", kqemu_time, kqemu_time / (double)ticks_per_sec, kqemu_time / (double)total * 100.0, kqemu_exec_count, diff --git a/target-arm/nwfpe/fpa11_cprt.c b/target-arm/nwfpe/fpa11_cprt.c index fe295e1aa..91f2d8001 100644 --- a/target-arm/nwfpe/fpa11_cprt.c +++ b/target-arm/nwfpe/fpa11_cprt.c @@ -133,7 +133,7 @@ unsigned int PerformFIX(const unsigned int opcode) case typeDouble: { - //printf("F%d is 0x%llx\n",Fn,fpa11->fpreg[Fn].fDouble); + //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble); writeRegister(getRd(opcode), float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status)); } diff --git a/target-i386/helper.c b/target-i386/helper.c index 379cfd5a4..d7b41ea0b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3259,7 +3259,7 @@ static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) v = (uint64_t)a1 * (uint64_t)b1; *phigh += v; #ifdef DEBUG_MULDIV - printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n", a, b, *phigh, *plow); #endif } @@ -3308,7 +3308,7 @@ static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) a0 = (a0 << 1) | qb; } #if defined(DEBUG_MULDIV) - printf("div: 0x%016llx%016llx / 0x%016llx: q=0x%016llx r=0x%016llx\n", + printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n", *phigh, *plow, b, a0, a1); #endif *plow = a0; diff --git a/target-i386/helper2.c b/target-i386/helper2.c index ac7d0568b..19af159f9 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -264,11 +264,11 @@ void cpu_dump_state(CPUState *env, FILE *f, #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { cpu_fprintf(f, - "RAX=%016llx RBX=%016llx RCX=%016llx RDX=%016llx\n" - "RSI=%016llx RDI=%016llx RBP=%016llx RSP=%016llx\n" - "R8 =%016llx R9 =%016llx R10=%016llx R11=%016llx\n" - "R12=%016llx R13=%016llx R14=%016llx R15=%016llx\n" - "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n", + "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n" + "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" + "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" + "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" + "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], @@ -329,28 +329,28 @@ void cpu_dump_state(CPUState *env, FILE *f, if (env->hflags & HF_LMA_MASK) { for(i = 0; i < 6; i++) { SegmentCache *sc = &env->segs[i]; - cpu_fprintf(f, "%s =%04x %016llx %08x %08x\n", + cpu_fprintf(f, "%s =%04x %016" PRIx64 " %08x %08x\n", seg_name[i], sc->selector, sc->base, sc->limit, sc->flags); } - cpu_fprintf(f, "LDT=%04x %016llx %08x %08x\n", + cpu_fprintf(f, "LDT=%04x %016" PRIx64 " %08x %08x\n", env->ldt.selector, env->ldt.base, env->ldt.limit, env->ldt.flags); - cpu_fprintf(f, "TR =%04x %016llx %08x %08x\n", + cpu_fprintf(f, "TR =%04x %016" PRIx64 " %08x %08x\n", env->tr.selector, env->tr.base, env->tr.limit, env->tr.flags); - cpu_fprintf(f, "GDT= %016llx %08x\n", + cpu_fprintf(f, "GDT= %016" PRIx64 " %08x\n", env->gdt.base, env->gdt.limit); - cpu_fprintf(f, "IDT= %016llx %08x\n", + cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n", env->idt.base, env->idt.limit); - cpu_fprintf(f, "CR0=%08x CR2=%016llx CR3=%016llx CR4=%08x\n", + cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n", (uint32_t)env->cr[0], env->cr[2], env->cr[3], @@ -394,7 +394,7 @@ void cpu_dump_state(CPUState *env, FILE *f, snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { - cpu_fprintf(f, "CCS=%016llx CCD=%016llx CCO=%-8s\n", + cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n", env->cc_src, env->cc_dst, cc_op_name); } else @@ -427,10 +427,10 @@ void cpu_dump_state(CPUState *env, FILE *f, } l; } tmp; tmp.d = env->fpregs[i].d; - cpu_fprintf(f, "FPR%d=%016llx %04x", + cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x", i, tmp.l.lower, tmp.l.upper); #else - cpu_fprintf(f, "FPR%d=%016llx", + cpu_fprintf(f, "FPR%d=%016" PRIx64, i, env->fpregs[i].mmx.q); #endif if ((i & 1) == 1) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 9eb3e6197..046f168bf 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2443,12 +2443,12 @@ void cpu_dump_state(CPUState *env, FILE *f, { #if defined(TARGET_PPC64) || 1 #define FILL "" -#define REGX "%016llx" +#define REGX "%016" PRIx64 #define RGPL 4 #define RFPL 4 #else #define FILL " " -#define REGX "%08llx" +#define REGX "%08" PRIx64 #define RGPL 8 #define RFPL 4 #endif @@ -2485,7 +2485,7 @@ void cpu_dump_state(CPUState *env, FILE *f, for (i = 0; i < 32; i++) { if ((i & (RFPL - 1)) == 0) cpu_fprintf(f, "FPR%02d", i); - cpu_fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i])); + cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i])); if ((i & (RFPL - 1)) == (RFPL - 1)) cpu_fprintf(f, "\n"); } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 012c34f73..ddf0c9126 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -252,7 +252,7 @@ static inline void spr_register (CPUPPCState *env, int num, exit(1); } #if defined(PPC_DEBUG_SPR) - printf("*** register spr %d (%03x) %s val %08llx\n", num, num, name, + printf("*** register spr %d (%03x) %s val %08" PRIx64 "\n", num, num, name, (unsigned long long)initial_value); #endif spr->name = name; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 982b7fcde..8f12667df 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -394,7 +394,7 @@ static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical env->dmmuregs[4] = address; /* Fault address register */ env->exception_index = TT_DFAULT; #ifdef DEBUG_MMU - printf("DFAULT at 0x%llx\n", address); + printf("DFAULT at 0x%" PRIx64 "\n", address); #endif return 1; } @@ -406,7 +406,7 @@ static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical } } #ifdef DEBUG_MMU - printf("DMISS at 0x%llx\n", address); + printf("DMISS at 0x%" PRIx64 "\n", address); #endif env->exception_index = TT_DMISS; return 1; @@ -452,7 +452,7 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical env->immuregs[3] |= (is_user << 3) | 1; env->exception_index = TT_TFAULT; #ifdef DEBUG_MMU - printf("TFAULT at 0x%llx\n", address); + printf("TFAULT at 0x%" PRIx64 "\n", address); #endif return 1; } @@ -462,7 +462,7 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical } } #ifdef DEBUG_MMU - printf("TMISS at 0x%llx\n", address); + printf("TMISS at 0x%" PRIx64 "\n", address); #endif env->exception_index = TT_TMISS; return 1; @@ -491,7 +491,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, virt_addr = address & TARGET_PAGE_MASK; vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); #ifdef DEBUG_MMU - printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr); + printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr); #endif ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; @@ -506,7 +506,7 @@ void dump_mmu(CPUState *env) unsigned int i; const char *mask; - printf("MMU contexts: Primary: %lld, Secondary: %lld\n", env->dmmuregs[1], env->dmmuregs[2]); + printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", env->dmmuregs[1], env->dmmuregs[2]); if ((env->lsu & DMMU_E) == 0) { printf("DMMU disabled\n"); } else { @@ -528,7 +528,7 @@ void dump_mmu(CPUState *env) break; } if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %lld\n", + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n", env->dtlb_tag[i] & ~0x1fffULL, env->dtlb_tte[i] & 0x1ffffffe000ULL, mask, @@ -560,7 +560,7 @@ void dump_mmu(CPUState *env) break; } if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %lld\n", + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n", env->itlb_tag[i] & ~0x1fffULL, env->itlb_tte[i] & 0x1ffffffe000ULL, mask, diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 5f88459ab..f4f725d6c 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -446,7 +446,7 @@ void helper_st_asi(int asi, int size, int sign) // invalid in normal mode if (oldreg != env->lsu) { #ifdef DEBUG_MMU - printf("LSU change: 0x%llx -> 0x%llx\n", oldreg, env->lsu); + printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu); dump_mmu(env); #endif tlb_flush(env, 1); @@ -480,7 +480,7 @@ void helper_st_asi(int asi, int size, int sign) env->immuregs[reg] = T1; #ifdef DEBUG_MMU if (oldreg != env->immuregs[reg]) { - printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->immuregs[reg]); + printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]); } dump_mmu(env); #endif @@ -549,7 +549,7 @@ void helper_st_asi(int asi, int size, int sign) env->dmmuregs[reg] = T1; #ifdef DEBUG_MMU if (oldreg != env->dmmuregs[reg]) { - printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->dmmuregs[reg]); + printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); } dump_mmu(env); #endif @@ -769,7 +769,7 @@ void do_interrupt(int intno) #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_INT) { static int count; - fprintf(logfile, "%6d: v=%04x pc=%016llx npc=%016llx SP=%016llx\n", + fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n", count, intno, env->pc, env->npc, env->regwptr[6]); diff --git a/tests/test-i386.c b/tests/test-i386.c index 64802690f..4a25d03b6 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -50,7 +50,7 @@ #define FMTLX "%016lx" #define X86_64_ONLY(x) x #else -#define FMT64X "%016llx" +#define FMT64X "%016" PRIx64 #define FMTLX "%08lx" #define X86_64_ONLY(x) #endif diff --git a/vl.c b/vl.c index 118a1e211..51ad671b7 100644 --- a/vl.c +++ b/vl.c @@ -912,7 +912,7 @@ static void host_alarm_handler(int host_signum) delta_max = delta; delta_cum += delta; if (++count == DISP_FREQ) { - printf("timer: min=%lld us max=%lld us avg=%lld us avg_freq=%0.3f Hz\n", + printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n", muldiv64(delta_min, 1000000, ticks_per_sec), muldiv64(delta_max, 1000000, ticks_per_sec), muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec), diff --git a/vl.h b/vl.h index 3cc4621bc..58dc17add 100644 --- a/vl.h +++ b/vl.h @@ -61,6 +61,9 @@ static inline char *realpath(const char *path, char *resolved_path) } #define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIu64 "I64u" +#define PRIo64 "I64o" #endif #ifdef QEMU_TOOL -- cgit v1.2.3 From 4f4fbf77ade902f929959b0e10fbf7e56bb85816 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 18:28:12 +0000 Subject: 64 bit support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2019 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index e495c5096..9a18639c4 100644 --- a/monitor.c +++ b/monitor.c @@ -1584,8 +1584,11 @@ static target_long expr_unary(void) n = 0; break; default: - /* XXX: 64 bit version */ +#if TARGET_LONG_BITS == 64 + n = strtoull(pch, &p, 0); +#else n = strtoul(pch, &p, 0); +#endif if (pch == p) { expr_error("invalid char in expression"); } -- cgit v1.2.3 From 2a4188a38fa3a91a9286da6fe077b6218378504d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 21:54:59 +0000 Subject: low level support for memory mapped flash devices (initial patch by Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2020 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 4 ++++ exec-all.h | 2 +- exec.c | 17 +++++++++++------ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index ac65043d5..6d6eb1a4c 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -828,6 +828,10 @@ extern uint8_t *phys_ram_dirty; #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); diff --git a/exec-all.h b/exec-all.h index bc91f71ca..b598948e3 100644 --- a/exec-all.h +++ b/exec-all.h @@ -570,7 +570,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) ldub_code(addr); } pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; - if (pd > IO_MEM_ROM) { + if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr); } return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; diff --git a/exec.c b/exec.c index f900e09f0..7e6f96688 100644 --- a/exec.c +++ b/exec.c @@ -1488,7 +1488,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, if (is_softmmu) #endif { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { /* IO memory case */ address = vaddr | pd; addend = paddr; @@ -1785,7 +1785,8 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); p->phys_offset = phys_offset; - if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) phys_offset += TARGET_PAGE_SIZE; } } @@ -2048,7 +2049,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } } else { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { @@ -2103,7 +2105,8 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, } if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && - (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM) { + (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* do nothing */ } else { unsigned long addr1; @@ -2135,7 +2138,8 @@ uint32_t ldl_phys(target_phys_addr_t addr) pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); @@ -2164,7 +2168,8 @@ uint64_t ldq_phys(target_phys_addr_t addr) pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); #ifdef TARGET_WORDS_BIGENDIAN -- cgit v1.2.3 From 9d42037b1d75c8f1b187d0b3187bd7891b909a56 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 22:25:22 +0000 Subject: support for dynamic address space changes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2021 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/exec.c b/exec.c index 7e6f96688..dd42f77d8 100644 --- a/exec.c +++ b/exec.c @@ -1779,6 +1779,7 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, { target_phys_addr_t addr, end_addr; PhysPageDesc *p; + CPUState *env; size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; end_addr = start_addr + size; @@ -1789,6 +1790,13 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, (phys_offset & IO_MEM_ROMD)) phys_offset += TARGET_PAGE_SIZE; } + + /* since each CPU stores ram addresses in its TLB cache, we must + reset the modified entries */ + /* XXX: slow ! */ + for(env = first_cpu; env != NULL; env = env->next_cpu) { + tlb_flush(env, 1); + } } static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) -- cgit v1.2.3 From 29133e9a0fff5775f8a1bef8671802a8624fc2c4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 25 Jun 2006 22:28:15 +0000 Subject: AMD NOR flash device support (initial patch by Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2022 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pflash_cfi02.c | 627 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 9 + 2 files changed, 636 insertions(+) create mode 100644 hw/pflash_cfi02.c diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c new file mode 100644 index 000000000..1f0cbe2f9 --- /dev/null +++ b/hw/pflash_cfi02.c @@ -0,0 +1,627 @@ +/* + * CFI parallel flash with AMD command set emulation + * + * Copyright (c) 2005 Jocelyn Mayer + * + * 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 + */ + +/* + * For now, this code can emulate flashes of 1, 2 or 4 bytes width. + * Supported commands/modes are: + * - flash read + * - flash write + * - flash ID read + * - sector erase + * - chip erase + * - unlock bypass command + * - CFI queries + * + * It does not support flash interleaving. + * It does not implement boot blocs with reduced size + * It does not implement software data protection as found in many real chips + * It does not implement erase suspend/resume commands + * It does not implement multiple sectors erase + */ + +#include "vl.h" + +//#define PFLASH_DEBUG +#ifdef PFLASH_DEBUG +#define DPRINTF(fmt, args...) \ +do { \ + if (loglevel) \ + fprintf(logfile, "PFLASH: " fmt , ##args); \ + else \ + printf("PFLASH: " fmt , ##args); \ +} while (0) +#else +#define DPRINTF(fmt, args...) do { } while (0) +#endif + +struct pflash_t { + BlockDriverState *bs; + target_ulong base; + target_ulong sector_len; + target_ulong total_len; + int width; + int wcycle; /* if 0, the flash is read normally */ + int bypass; + int ro; + uint8_t cmd; + uint8_t status; + uint16_t ident[4]; + uint8_t cfi_len; + uint8_t cfi_table[0x52]; + QEMUTimer *timer; + ram_addr_t off; + int fl_mem; + void *storage; +}; + +static void pflash_timer (void *opaque) +{ + pflash_t *pfl = opaque; + + DPRINTF("%s: command %02x done\n", __func__, pfl->cmd); + /* Reset flash */ + pfl->status ^= 0x80; + if (pfl->bypass) { + pfl->wcycle = 2; + } else { + cpu_register_physical_memory(pfl->base, pfl->total_len, + pfl->off | IO_MEM_ROMD | pfl->fl_mem); + pfl->wcycle = 0; + } + pfl->cmd = 0; +} + +static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width) +{ + target_ulong boff; + uint32_t ret; + uint8_t *p; + + DPRINTF("%s: offset %08x\n", __func__, offset); + ret = -1; + offset -= pfl->base; + boff = offset & 0xFF; + if (pfl->width == 2) + boff = boff >> 1; + else if (pfl->width == 4) + boff = boff >> 2; + switch (pfl->cmd) { + default: + /* This should never happen : reset state & treat it as a read*/ + DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); + pfl->wcycle = 0; + pfl->cmd = 0; + case 0x80: + /* We accept reads during second unlock sequence... */ + case 0x00: + flash_read: + /* Flash area read */ + p = pfl->storage; + switch (width) { + case 1: + ret = p[offset]; +// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret); + break; + case 2: +#if defined(TARGET_WORDS_BIGENDIAN) + ret = p[offset] << 8; + ret |= p[offset + 1]; +#else + ret = p[offset]; + ret |= p[offset + 1] << 8; +#endif +// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret); + break; + case 4: +#if defined(TARGET_WORDS_BIGENDIAN) + ret = p[offset] << 24; + ret |= p[offset + 1] << 16; + ret |= p[offset + 2] << 8; + ret |= p[offset + 3]; +#else + ret = p[offset]; + ret |= p[offset + 1] << 8; + ret |= p[offset + 1] << 8; + ret |= p[offset + 2] << 16; + ret |= p[offset + 3] << 24; +#endif +// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret); + break; + } + break; + case 0x90: + /* flash ID read */ + switch (boff) { + case 0x00: + case 0x01: + ret = pfl->ident[boff & 0x01]; + break; + case 0x02: + ret = 0x00; /* Pretend all sectors are unprotected */ + break; + case 0x0E: + case 0x0F: + if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1) + goto flash_read; + ret = pfl->ident[2 + (boff & 0x01)]; + break; + default: + goto flash_read; + } + DPRINTF("%s: ID %d %x\n", __func__, boff, ret); + break; + case 0xA0: + case 0x10: + case 0x30: + /* Status register read */ + ret = pfl->status; + DPRINTF("%s: status %x\n", __func__, ret); + /* Toggle bit 6 */ + pfl->status ^= 0x40; + break; + case 0x98: + /* CFI query mode */ + if (boff > pfl->cfi_len) + ret = 0; + else + ret = pfl->cfi_table[boff]; + break; + } + + return ret; +} + +/* update flash content on disk */ +static void pflash_update(pflash_t *pfl, int offset, + int size) +{ + int offset_end; + if (pfl->bs) { + offset_end = offset + size; + /* round to sectors */ + offset = offset >> 9; + offset_end = (offset_end + 511) >> 9; + bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), + offset_end - offset); + } +} + +static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, + int width) +{ + target_ulong boff; + uint8_t *p; + uint8_t cmd; + + /* WARNING: when the memory area is in ROMD mode, the offset is a + ram offset, not a physical address */ + if (pfl->wcycle == 0) + offset -= pfl->off; + else + offset -= pfl->base; + + cmd = value; + DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width); + if (pfl->cmd != 0xA0 && cmd == 0xF0) { + DPRINTF("%s: flash reset asked (%02x %02x)\n", + __func__, pfl->cmd, cmd); + goto reset_flash; + } + /* Set the device in I/O access mode */ + cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem); + boff = offset & (pfl->sector_len - 1); + if (pfl->width == 2) + boff = boff >> 1; + else if (pfl->width == 4) + boff = boff >> 2; + switch (pfl->wcycle) { + case 0: + /* We're in read mode */ + check_unlock0: + if (boff == 0x55 && cmd == 0x98) { + enter_CFI_mode: + /* Enter CFI query mode */ + pfl->wcycle = 7; + pfl->cmd = 0x98; + return; + } + if (boff != 0x555 || cmd != 0xAA) { + DPRINTF("%s: unlock0 failed %04x %02x %04x\n", + __func__, boff, cmd, 0x555); + goto reset_flash; + } + DPRINTF("%s: unlock sequence started\n", __func__); + break; + case 1: + /* We started an unlock sequence */ + check_unlock1: + if (boff != 0x2AA || cmd != 0x55) { + DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd); + goto reset_flash; + } + DPRINTF("%s: unlock sequence done\n", __func__); + break; + case 2: + /* We finished an unlock sequence */ + if (!pfl->bypass && boff != 0x555) { + DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd); + goto reset_flash; + } + switch (cmd) { + case 0x20: + pfl->bypass = 1; + goto do_bypass; + case 0x80: + case 0x90: + case 0xA0: + pfl->cmd = cmd; + DPRINTF("%s: starting command %02x\n", __func__, cmd); + break; + default: + DPRINTF("%s: unknown command %02x\n", __func__, cmd); + goto reset_flash; + } + break; + case 3: + switch (pfl->cmd) { + case 0x80: + /* We need another unlock sequence */ + goto check_unlock0; + case 0xA0: + DPRINTF("%s: write data offset %08x %08x %d\n", + __func__, offset, value, width); + p = pfl->storage; + switch (width) { + case 1: + p[offset] &= value; + pflash_update(pfl, offset, 1); + break; + case 2: +#if defined(TARGET_WORDS_BIGENDIAN) + p[offset] &= value >> 8; + p[offset + 1] &= value; +#else + p[offset] &= value; + p[offset + 1] &= value >> 8; +#endif + pflash_update(pfl, offset, 2); + break; + case 4: +#if defined(TARGET_WORDS_BIGENDIAN) + p[offset] &= value >> 24; + p[offset + 1] &= value >> 16; + p[offset + 2] &= value >> 8; + p[offset + 3] &= value; +#else + p[offset] &= value; + p[offset + 1] &= value >> 8; + p[offset + 2] &= value >> 16; + p[offset + 3] &= value >> 24; +#endif + pflash_update(pfl, offset, 4); + break; + } + pfl->status = 0x00 | ~(value & 0x80); + /* Let's pretend write is immediate */ + if (pfl->bypass) + goto do_bypass; + goto reset_flash; + case 0x90: + if (pfl->bypass && cmd == 0x00) { + /* Unlock bypass reset */ + goto reset_flash; + } + /* We can enter CFI query mode from autoselect mode */ + if (boff == 0x55 && cmd == 0x98) + goto enter_CFI_mode; + /* No break here */ + default: + DPRINTF("%s: invalid write for command %02x\n", + __func__, pfl->cmd); + goto reset_flash; + } + case 4: + switch (pfl->cmd) { + case 0xA0: + /* Ignore writes while flash data write is occuring */ + /* As we suppose write is immediate, this should never happen */ + return; + case 0x80: + goto check_unlock1; + default: + /* Should never happen */ + DPRINTF("%s: invalid command state %02x (wc 4)\n", + __func__, pfl->cmd); + goto reset_flash; + } + break; + case 5: + switch (cmd) { + case 0x10: + if (boff != 0x555) { + DPRINTF("%s: chip erase: invalid address %04x\n", + __func__, offset); + goto reset_flash; + } + /* Chip erase */ + DPRINTF("%s: start chip erase\n", __func__); + memset(pfl->storage, 0xFF, pfl->total_len); + pfl->status = 0x00; + pflash_update(pfl, 0, pfl->total_len); + /* Let's wait 5 seconds before chip erase is done */ + qemu_mod_timer(pfl->timer, + qemu_get_clock(vm_clock) + (ticks_per_sec * 5)); + break; + case 0x30: + /* Sector erase */ + p = pfl->storage; + offset &= ~(pfl->sector_len - 1); + DPRINTF("%s: start sector erase at %08x\n", __func__, offset); + memset(p + offset, 0xFF, pfl->sector_len); + pflash_update(pfl, offset, pfl->sector_len); + pfl->status = 0x00; + /* Let's wait 1/2 second before sector erase is done */ + qemu_mod_timer(pfl->timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 2)); + break; + default: + DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd); + goto reset_flash; + } + pfl->cmd = cmd; + break; + case 6: + switch (pfl->cmd) { + case 0x10: + /* Ignore writes during chip erase */ + return; + case 0x30: + /* Ignore writes during sector erase */ + return; + default: + /* Should never happen */ + DPRINTF("%s: invalid command state %02x (wc 6)\n", + __func__, pfl->cmd); + goto reset_flash; + } + break; + case 7: /* Special value for CFI queries */ + DPRINTF("%s: invalid write in CFI query mode\n", __func__); + goto reset_flash; + default: + /* Should never happen */ + DPRINTF("%s: invalid write state (wc 7)\n", __func__); + goto reset_flash; + } + pfl->wcycle++; + + return; + + /* Reset flash */ + reset_flash: + if (pfl->wcycle != 0) { + cpu_register_physical_memory(pfl->base, pfl->total_len, + pfl->off | IO_MEM_ROMD | pfl->fl_mem); + } + pfl->bypass = 0; + pfl->wcycle = 0; + pfl->cmd = 0; + return; + + do_bypass: + pfl->wcycle = 2; + pfl->cmd = 0; + return; +} + + +static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr) +{ + return pflash_read(opaque, addr, 1); +} + +static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr) +{ + pflash_t *pfl = opaque; + + return pflash_read(pfl, addr, 2); +} + +static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr) +{ + pflash_t *pfl = opaque; + + return pflash_read(pfl, addr, 4); +} + +static void pflash_writeb (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_write(opaque, addr, value, 1); +} + +static void pflash_writew (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_t *pfl = opaque; + + pflash_write(pfl, addr, value, 2); +} + +static void pflash_writel (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_t *pfl = opaque; + + pflash_write(pfl, addr, value, 4); +} + +static CPUWriteMemoryFunc *pflash_write_ops[] = { + &pflash_writeb, + &pflash_writew, + &pflash_writel, +}; + +static CPUReadMemoryFunc *pflash_read_ops[] = { + &pflash_readb, + &pflash_readw, + &pflash_readl, +}; + +/* Count trailing zeroes of a 32 bits quantity */ +static int ctz32 (uint32_t n) +{ + int ret; + + ret = 0; + if (!(n & 0xFFFF)) { + ret += 16; + n = n >> 16; + } + if (!(n & 0xFF)) { + ret += 8; + n = n >> 8; + } + if (!(n & 0xF)) { + ret += 4; + n = n >> 4; + } + if (!(n & 0x3)) { + ret += 2; + n = n >> 2; + } + if (!(n & 0x1)) { + ret++; + n = n >> 1; + } +#if 0 /* This is not necessary as n is never 0 */ + if (!n) + ret++; +#endif + + return ret; +} + +pflash_t *pflash_register (target_ulong base, ram_addr_t off, + BlockDriverState *bs, + target_ulong sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3) +{ + pflash_t *pfl; + target_long total_len; + + total_len = sector_len * nb_blocs; + /* XXX: to be fixed */ + if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && + total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024)) + return NULL; + pfl = qemu_mallocz(sizeof(pflash_t)); + if (pfl == NULL) + return NULL; + pfl->storage = phys_ram_base + off; + pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl); + pfl->off = off; + cpu_register_physical_memory(base, total_len, + off | pfl->fl_mem | IO_MEM_ROMD); + pfl->bs = bs; + if (pfl->bs) { + /* read the initial flash content */ + bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9); + } +#if 0 /* XXX: there should be a bit to set up read-only, + * the same way the hardware does (with WP pin). + */ + pfl->ro = 1; +#else + pfl->ro = 0; +#endif + pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl); + pfl->base = base; + pfl->sector_len = sector_len; + pfl->total_len = total_len; + pfl->width = width; + pfl->wcycle = 0; + pfl->cmd = 0; + pfl->status = 0; + pfl->ident[0] = id0; + pfl->ident[1] = id1; + pfl->ident[2] = id2; + pfl->ident[3] = id3; + /* Hardcoded CFI table (mostly from SG29 Spansion flash) */ + pfl->cfi_len = 0x52; + /* Standard "QRY" string */ + pfl->cfi_table[0x10] = 'Q'; + pfl->cfi_table[0x11] = 'R'; + pfl->cfi_table[0x12] = 'Y'; + /* Command set (AMD/Fujitsu) */ + pfl->cfi_table[0x13] = 0x02; + pfl->cfi_table[0x14] = 0x00; + /* Primary extended table address (none) */ + pfl->cfi_table[0x15] = 0x00; + pfl->cfi_table[0x16] = 0x00; + /* Alternate command set (none) */ + pfl->cfi_table[0x17] = 0x00; + pfl->cfi_table[0x18] = 0x00; + /* Alternate extended table (none) */ + pfl->cfi_table[0x19] = 0x00; + pfl->cfi_table[0x1A] = 0x00; + /* Vcc min */ + pfl->cfi_table[0x1B] = 0x27; + /* Vcc max */ + pfl->cfi_table[0x1C] = 0x36; + /* Vpp min (no Vpp pin) */ + pfl->cfi_table[0x1D] = 0x00; + /* Vpp max (no Vpp pin) */ + pfl->cfi_table[0x1E] = 0x00; + /* Reserved */ + pfl->cfi_table[0x1F] = 0x07; + /* Timeout for min size buffer write (16 s) */ + pfl->cfi_table[0x20] = 0x04; + /* Typical timeout for block erase (512 ms) */ + pfl->cfi_table[0x21] = 0x09; + /* Typical timeout for full chip erase (4096 ms) */ + pfl->cfi_table[0x22] = 0x0C; + /* Reserved */ + pfl->cfi_table[0x23] = 0x01; + /* Max timeout for buffer write */ + pfl->cfi_table[0x24] = 0x04; + /* Max timeout for block erase */ + pfl->cfi_table[0x25] = 0x0A; + /* Max timeout for chip erase */ + pfl->cfi_table[0x26] = 0x0D; + /* Device size */ + pfl->cfi_table[0x27] = ctz32(total_len) + 1; + /* Flash device interface (8 & 16 bits) */ + pfl->cfi_table[0x28] = 0x02; + pfl->cfi_table[0x29] = 0x00; + /* Max number of bytes in multi-bytes write */ + pfl->cfi_table[0x2A] = 0x05; + pfl->cfi_table[0x2B] = 0x00; + /* Number of erase block regions (uniform) */ + pfl->cfi_table[0x2C] = 0x01; + /* Erase block region 1 */ + pfl->cfi_table[0x2D] = nb_blocs - 1; + pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8; + pfl->cfi_table[0x2F] = sector_len >> 8; + pfl->cfi_table[0x30] = sector_len >> 16; + + return pfl; +} diff --git a/vl.h b/vl.h index 58dc17add..fb72dd55e 100644 --- a/vl.h +++ b/vl.h @@ -1137,6 +1137,15 @@ int sh7750_register_io_device(struct SH7750State *s, /* tc58128.c */ int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); +/* NOR flash devices */ +typedef struct pflash_t pflash_t; + +pflash_t *pflash_register (target_ulong base, ram_addr_t off, + BlockDriverState *bs, + target_ulong sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From a80dde08372ca86b48363dfee019af0dc3bc97aa Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Jun 2006 19:53:29 +0000 Subject: SPARC FPU optimization (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2023 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 8 ++++-- target-sparc/cpu.h | 2 ++ target-sparc/op.c | 9 ------- target-sparc/translate.c | 68 ++++++++++++++++++++++++++++++------------------ 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 926093afb..60239d4b9 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -175,9 +175,13 @@ static inline TranslationBlock *tb_find_fast(void) pc = env->regs[15]; #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 - flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); + // 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 - flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); + // 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; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 90f6fb23d..d0bcd4067 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -78,6 +78,8 @@ #define PS_PRIV (1<<2) #define PS_IE (1<<1) #define PS_AG (1<<0) + +#define FPRS_FEF (1<<2) #endif /* Fcc */ diff --git a/target-sparc/op.c b/target-sparc/op.c index d5df859db..f6d417f47 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1017,15 +1017,6 @@ void OPPROTO op_trapcc_T0(void) FORCE_RET(); } -void OPPROTO op_trap_ifnofpu(void) -{ - if (!env->psref) { - env->exception_index = TT_NFPU_INSN; - cpu_loop_exit(); - } - FORCE_RET(); -} - void OPPROTO op_fpexception_im(void) { env->exception_index = TT_FP_EXCP; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 65ee97599..26c81454a 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -52,6 +52,7 @@ typedef struct DisasContext { target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ int is_br; int mem_idx; + int fpu_enabled; struct TranslationBlock *tb; } DisasContext; @@ -935,6 +936,19 @@ static GenOpFunc * const gen_fcmpd[4] = { }; #endif +static int gen_trap_ifnofpu(DisasContext * dc) +{ +#if !defined(CONFIG_USER_ONLY) + if (!dc->fpu_enabled) { + save_state(dc); + gen_op_exception(TT_NFPU_INSN); + dc->is_br = 1; + return 1; + } +#endif + return 0; +} + /* before an instruction, dc->pc must be static */ static void disas_sparc_insn(DisasContext * dc) { @@ -981,10 +995,8 @@ static void disas_sparc_insn(DisasContext * dc) case 0x5: /* V9 FBPcc */ { int cc = GET_FIELD_SP(insn, 20, 21); -#if !defined(CONFIG_USER_ONLY) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; target = GET_FIELD_SP(insn, 0, 18); target = sign_extend(target, 19); target <<= 2; @@ -1002,10 +1014,8 @@ static void disas_sparc_insn(DisasContext * dc) } case 0x6: /* FBN+x */ { -#if !defined(CONFIG_USER_ONLY) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; @@ -1079,16 +1089,16 @@ static void disas_sparc_insn(DisasContext * dc) } #endif } - save_state(dc); cond = GET_FIELD(insn, 3, 6); if (cond == 0x8) { + save_state(dc); gen_op_trap_T0(); - dc->is_br = 1; - goto jmp_insn; } else if (cond != 0) { #ifdef TARGET_SPARC64 /* V9 icc/xcc */ int cc = GET_FIELD_SP(insn, 11, 12); + flush_T2(dc); + save_state(dc); if (cc == 0) gen_cond[0][cond](); else if (cc == 2) @@ -1096,10 +1106,17 @@ static void disas_sparc_insn(DisasContext * dc) else goto illegal_insn; #else + flush_T2(dc); + save_state(dc); gen_cond[0][cond](); #endif gen_op_trapcc_T0(); } + gen_op_next_insn(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; + goto jmp_insn; } else if (xop == 0x28) { rs1 = GET_FIELD(insn, 13, 17); switch(rs1) { @@ -1241,10 +1258,8 @@ static void disas_sparc_insn(DisasContext * dc) break; #endif } else if (xop == 0x34) { /* FPU Operations */ -#if !defined(CONFIG_USER_ONLY) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); @@ -1430,10 +1445,8 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef TARGET_SPARC64 int cond; #endif -#if !defined(CONFIG_USER_ONLY) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); @@ -2366,10 +2379,8 @@ static void disas_sparc_insn(DisasContext * dc) skip_move: ; #endif } else if (xop >= 0x20 && xop < 0x24) { -#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - save_state(dc); - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; switch (xop) { case 0x20: /* load fpreg */ gen_op_ldst(ldf); @@ -2450,9 +2461,8 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { -#if !defined(CONFIG_USER_ONLY) - gen_op_trap_ifnofpu(); -#endif + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; switch (xop) { case 0x24: gen_op_load_fpr_FT0(rd); @@ -2548,8 +2558,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, dc->npc = (target_ulong) tb->cs_base; #if defined(CONFIG_USER_ONLY) dc->mem_idx = 0; + dc->fpu_enabled = 1; #else dc->mem_idx = ((env->psrs) != 0); +#ifdef TARGET_SPARC64 + dc->fpu_enabled = (((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0)); +#else + dc->fpu_enabled = ((env->psref) != 0); +#endif #endif gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; -- cgit v1.2.3 From 567d4107a67571f57bb5f8879258414a87f98a2b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Jun 2006 19:55:19 +0000 Subject: qsub fix (Wolfgang Schildbach) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2024 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/op.c b/target-arm/op.c index 619066d29..f17b81273 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -786,7 +786,7 @@ void OPPROTO op_subl_T0_T1_saturate(void) if (((res ^ T0) & SIGNBIT) && ((T0 ^ T1) & SIGNBIT)) { env->QF = 1; if (T0 & SIGNBIT) - T0 = 0x8000000; + T0 = 0x80000000; else T0 = 0x7fffffff; } -- cgit v1.2.3 From d796321b6b552284080af5560030e9c8d0f06321 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Jun 2006 20:02:45 +0000 Subject: lwu support - generate exception if unaligned pc (Marius Groeger) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2025 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_mem.c | 6 ++++++ target-mips/translate.c | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index b5308bea5..35ccd44c6 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -61,6 +61,12 @@ void glue(op_lw, MEMSUFFIX) (void) RETURN(); } +void glue(op_lwu, MEMSUFFIX) (void) +{ + T0 = glue(ldl, MEMSUFFIX)(T0); + RETURN(); +} + void glue(op_sw, MEMSUFFIX) (void) { glue(stl, MEMSUFFIX)(T0, T1); diff --git a/target-mips/translate.c b/target-mips/translate.c index fcee08747..7ad8ebddf 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -97,6 +97,7 @@ enum { OPC_LBU = 0x24, OPC_LHU = 0x25, OPC_LWR = 0x26, + OPC_LWU = 0x27, OPC_SB = 0x28, OPC_SH = 0x29, OPC_SWL = 0x2A, @@ -495,6 +496,7 @@ OP_ST_TABLE(dl); OP_ST_TABLE(dr); #endif OP_LD_TABLE(w); +OP_LD_TABLE(wu); OP_LD_TABLE(wl); OP_LD_TABLE(wr); OP_ST_TABLE(w); @@ -580,6 +582,11 @@ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, GEN_STORE_TN_REG(rt, T0); opn = "lw"; break; + case OPC_LWU: + op_ldst(lwu); + GEN_STORE_TN_REG(rt, T0); + opn = "lwu"; + break; case OPC_SW: #if defined (MIPS_HAS_UNALIGNED_LS) case OPC_USW: @@ -1356,6 +1363,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) generate_exception_err (ctx, EXCP_CpU, 0); return; } + switch (opc) { case OPC_MFC0: if (rt == 0) { @@ -1886,6 +1894,12 @@ static void decode_opc (DisasContext *ctx) uint16_t op, op1; int16_t imm; + /* make sure instructions are on a word boundary */ + if (ctx->pc & 0x3) { + generate_exception(ctx, EXCP_AdEL); + return; + } + if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { /* Handle blikely not taken case */ MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); @@ -2041,8 +2055,7 @@ static void decode_opc (DisasContext *ctx) case 0x14 ... 0x17: gen_compute_branch(ctx, op, rs, rt, imm << 2); return; - case 0x20 ... 0x26: /* Load and stores */ - case 0x28 ... 0x2E: + case 0x20 ... 0x2E: /* Load and stores */ case 0x30: case 0x38: gen_ldst(ctx, op, rt, rs, imm); -- cgit v1.2.3 From 3587d7e69cd25f14eccec01c547f1257171fde7b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Jun 2006 20:03:44 +0000 Subject: fix crash when closing windows (Frediano Ziglio) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2026 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/vl.c b/vl.c index 51ad671b7..b01c9b31b 100644 --- a/vl.c +++ b/vl.c @@ -5495,6 +5495,14 @@ static void select_soundhw (const char *optarg) } #endif +#ifdef _WIN32 +static BOOL WINAPI qemu_ctrl_handler(DWORD type) +{ + exit(STATUS_CONTROL_C_EXIT); + return TRUE; +} +#endif + #define MAX_NET_CLIENTS 32 int main(int argc, char **argv) @@ -5534,6 +5542,8 @@ int main(int argc, char **argv) act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); } +#else + SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE); #endif init_timers(); -- cgit v1.2.3 From beac80cd437fb383eeaccc4224a4d7faebd77a23 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Jun 2006 20:08:57 +0000 Subject: Windows sparse file support (Frediano Ziglio) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2027 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + block.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 5 +++-- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 0b0d2a45f..df487a54e 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,7 @@ version 0.8.2: - USB updates (Paul Brook) - UDP character devices (Jason Wessel) - TCP character devices + - Windows sparse file support (Frediano Ziglio) version 0.8.1: diff --git a/block.c b/block.c index c25c6869a..ceb0532bd 100644 --- a/block.c +++ b/block.c @@ -761,6 +761,51 @@ static void raw_close(BlockDriverState *bs) close(s->fd); } +#ifdef _WIN32 +#include +#include + +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); +} +#else +static inline int set_sparse(int fd) +{ + return 1; +} +#endif + static int raw_create(const char *filename, int64_t total_size, const char *backing_file, int flags) { @@ -773,6 +818,7 @@ static int raw_create(const char *filename, int64_t total_size, 0644); if (fd < 0) return -EIO; + set_sparse(fd); ftruncate(fd, total_size * 512); close(fd); return 0; diff --git a/vl.h b/vl.h index fb72dd55e..244310fee 100644 --- a/vl.h +++ b/vl.h @@ -51,8 +51,9 @@ #define fsync _commit #define lseek _lseeki64 #define ENOTSUP 4096 -/* XXX: find 64 bit version */ -#define ftruncate chsize +extern int qemu_ftruncate64(int, int64_t); +#define ftruncate qemu_ftruncate64 + static inline char *realpath(const char *path, char *resolved_path) { -- cgit v1.2.3 From 3e382bc84ce93df505b48fc4e305fcc5f4ac4567 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Jun 2006 20:29:47 +0000 Subject: consistent update of ERL and EXL (Dirk Behme) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2028 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 4 +++- target-mips/op.c | 2 ++ target-mips/op_helper.c | 4 ---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 8325d4843..9c8e4f68d 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -332,7 +332,8 @@ void do_interrupt (CPUState *env) } else { env->CP0_ErrorEPC = env->PC; } - env->hflags = MIPS_HFLAG_ERL; + env->hflags |= MIPS_HFLAG_ERL; + env->CP0_Status |= (1 << CP0St_ERL); pc = 0xBFC00000; break; case EXCP_MCHECK: @@ -396,6 +397,7 @@ void do_interrupt (CPUState *env) pc = 0x80000000; } env->hflags |= MIPS_HFLAG_EXL; + env->CP0_Status |= (1 << CP0St_EXL); pc += offset; env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); if (env->hflags & MIPS_HFLAG_BMASK) { diff --git a/target-mips/op.c b/target-mips/op.c index bc7f81949..457551725 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1104,9 +1104,11 @@ void op_eret (void) if (env->hflags & MIPS_HFLAG_ERL) { env->PC = env->CP0_ErrorEPC; env->hflags &= ~MIPS_HFLAG_ERL; + env->CP0_Status &= ~(1 << CP0St_ERL); } else { env->PC = env->CP0_EPC; env->hflags &= ~MIPS_HFLAG_EXL; + env->CP0_Status &= ~(1 << CP0St_EXL); } env->CP0_LLAddr = 1; } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 37f260430..bf397c9b4 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -219,10 +219,6 @@ void do_mfc0 (int reg, int sel) T0 = env->CP0_Status; if (env->hflags & MIPS_HFLAG_UM) T0 |= (1 << CP0St_UM); - if (env->hflags & MIPS_HFLAG_ERL) - T0 |= (1 << CP0St_ERL); - if (env->hflags & MIPS_HFLAG_EXL) - T0 |= (1 << CP0St_EXL); rn = "Status"; break; case 13: -- cgit v1.2.3 From 1f6e24e73ccdca64864da009a21f5b7051d200a1 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 26 Jun 2006 21:00:51 +0000 Subject: display device identifier string for user with info usb (Lonnie Mendez) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2029 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hid.c | 4 ++++ hw/usb-hub.c | 2 ++ hw/usb-msd.c | 3 +++ hw/usb.h | 1 + usb-linux.c | 30 +++++++++++++++++++++++++++--- vl.c | 4 ++-- 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 883befcc3..93f46dbf9 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -521,6 +521,8 @@ USBDevice *usb_tablet_init(void) s->dev.handle_data = usb_mouse_handle_data; s->kind = USB_TABLET; + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); + return (USBDevice *)s; } @@ -539,5 +541,7 @@ USBDevice *usb_mouse_init(void) s->dev.handle_data = usb_mouse_handle_data; s->kind = USB_MOUSE; + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); + return (USBDevice *)s; } diff --git a/hw/usb-hub.c b/hw/usb-hub.c index c69d69cc8..2eba905ff 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -544,6 +544,8 @@ USBDevice *usb_hub_init(int nb_ports) s->dev.handle_control = usb_hub_handle_control; s->dev.handle_data = usb_hub_handle_data; + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub"); + s->nb_ports = nb_ports; for(i = 0; i < s->nb_ports; i++) { port = &s->ports[i]; diff --git a/hw/usb-msd.c b/hw/usb-msd.c index bcca6d4ed..3dccfb955 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -389,6 +389,9 @@ USBDevice *usb_msd_init(const char *filename) s->dev.handle_control = usb_msd_handle_control; s->dev.handle_data = usb_msd_handle_data; + snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", + filename); + s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); usb_msd_handle_reset((USBDevice *)s, 0); return (USBDevice *)s; diff --git a/hw/usb.h b/hw/usb.h index abdbb45d2..b0887d680 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -128,6 +128,7 @@ struct USBDevice { int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, uint8_t *data, int len); uint8_t addr; + char devname[32]; int state; uint8_t setup_buf[8]; diff --git a/usb-linux.c b/usb-linux.c index 8009a1b60..aa1ded23d 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -44,11 +44,13 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id, int vendor_id, int product_id, const char *product_name, int speed); static int usb_host_find_device(int *pbus_num, int *paddr, + char *product_name, int product_name_size, const char *devname); //#define DEBUG #define USBDEVFS_PATH "/proc/bus/usb" +#define PRODUCT_NAME_SZ 32 typedef struct USBHostDevice { USBDevice dev; @@ -145,8 +147,11 @@ USBDevice *usb_host_device_open(const char *devname) char buf[1024]; int descr_len, dev_descr_len, config_descr_len, nb_interfaces; int bus_num, addr; + char product_name[PRODUCT_NAME_SZ]; - if (usb_host_find_device(&bus_num, &addr, devname) < 0) + if (usb_host_find_device(&bus_num, &addr, + product_name, sizeof(product_name), + devname) < 0) return NULL; snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", @@ -230,6 +235,14 @@ USBDevice *usb_host_device_open(const char *devname) dev->dev.handle_reset = usb_host_handle_reset; dev->dev.handle_control = usb_host_handle_control; dev->dev.handle_data = usb_host_handle_data; + + if (product_name[0] == '\0') + snprintf(dev->dev.devname, sizeof(dev->dev.devname), + "host:%s", devname); + else + pstrcpy(dev->dev.devname, sizeof(dev->dev.devname), + product_name); + return (USBDevice *)dev; } @@ -337,6 +350,7 @@ typedef struct FindDeviceState { int product_id; int bus_num; int addr; + char product_name[PRODUCT_NAME_SZ]; } FindDeviceState; static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, @@ -345,8 +359,11 @@ static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, const char *product_name, int speed) { FindDeviceState *s = opaque; - if (vendor_id == s->vendor_id && - product_id == s->product_id) { + if ((vendor_id == s->vendor_id && + product_id == s->product_id) || + (bus_num == s->bus_num && + addr == s->addr)) { + pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name); s->bus_num = bus_num; s->addr = addr; return 1; @@ -359,6 +376,7 @@ static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, 'bus.addr' (decimal numbers) or 'vendor_id:product_id' (hexa numbers) */ static int usb_host_find_device(int *pbus_num, int *paddr, + char *product_name, int product_name_size, const char *devname) { const char *p; @@ -369,6 +387,11 @@ static int usb_host_find_device(int *pbus_num, int *paddr, if (p) { *pbus_num = strtoul(devname, NULL, 0); *paddr = strtoul(p + 1, NULL, 0); + fs.bus_num = *pbus_num; + fs.addr = *paddr; + ret = usb_host_scan(&fs, usb_host_find_device_scan); + if (ret) + pstrcpy(product_name, product_name_size, fs.product_name); return 0; } p = strchr(devname, ':'); @@ -379,6 +402,7 @@ static int usb_host_find_device(int *pbus_num, int *paddr, if (ret) { *pbus_num = fs.bus_num; *paddr = fs.addr; + pstrcpy(product_name, product_name_size, fs.product_name); return 0; } } diff --git a/vl.c b/vl.c index b01c9b31b..d5a0f7b12 100644 --- a/vl.c +++ b/vl.c @@ -3785,8 +3785,8 @@ void usb_info(void) speed_str = "?"; break; } - term_printf(" Device %d.%d, speed %s Mb/s\n", - 0, dev->addr, speed_str); + term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n", + 0, dev->addr, speed_str, dev->devname); } } -- cgit v1.2.3 From 951f13516a50383cd462c9150e643cc9f9566267 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 Jun 2006 21:02:43 +0000 Subject: telnet protocol and more consistent syntax (Jason Wessel) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2030 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 65 +++++++++++------- vl.c | 208 ++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 191 insertions(+), 82 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 02bfc2150..ed5850108 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -525,43 +525,60 @@ Write output to filename. No character can be read. name pipe @var{filename} @item COMn [Windows only] Use host serial port @var{n} -@item udp:remote_port -UDP Net Console sent to locahost at remote_port -@item udp:remote_host:remote_port -UDP Net Console sent to remote_host at remote_port -@item udp:src_port:remote_host:remote_port -UDP Net Console sent from src_port to remote_host at the remote_port. - -The udp:* sub options are primary intended for netconsole. If you -just want a simple readonly console you can use @code{netcat} or -@code{nc}, by starting qemu with: @code{-serial udp:4555} and nc as: -@code{nc -u -l -p 4555}. Any time qemu writes something to that port -it will appear in the netconsole session. +@item udp:[remote_host]:remote_port[@@[src_ip]:src_port] +This implements UDP Net Console. When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}. When not using a specifed @var{src_port} a random port is automatically chosen. + +If you just want a simple readonly console you can use @code{netcat} or +@code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as: +@code{nc -u -l -p 4555}. Any time qemu writes something to that port it +will appear in the netconsole session. If you plan to send characters back via netconsole or you want to stop and start qemu a lot of times, you should have qemu use the same source port each time by using something like @code{-serial -udp:4556:localhost:4555} to qemu. Another approach is to use a patched +udp::4555@@:4556} to qemu. Another approach is to use a patched version of netcat which can listen to a TCP port and send and receive characters via udp. If you have a patched version of netcat which activates telnet remote echo and single char transfer, then you can use the following options to step up a netcat redirector to allow telnet on port 5555 to access the qemu port. @table @code -@item Qemu Options --serial udp:4556:localhost:4555 -@item netcat options --u -P 4555 -L localhost:4556 -t -p 5555 -I -T +@item Qemu Options: +-serial udp::4555@@:4556 +@item netcat options: +-u -P 4555 -L 0.0.0.0:4556 -t -p 5555 -I -T +@item telnet options: +localhost 5555 +@end table + + +@item tcp:[host]:port[,server][,nowait] +The TCP Net Console has two modes of operation. It can send the serial +I/O to a location or wait for a connection from a location. By default +the TCP Net Console is sent to @var{host} at the @var{port}. If you use +the @var{,server} option QEMU will wait for a client socket application +to connect to the port before continuing, unless the @code{,nowait} +option was specified. If @var{host} is omitted, 0.0.0.0 is assumed. Only +one TCP connection at a time is accepted. You can use @code{telnet} to +connect to the corresponding character device. +@table @code +@item Example to send tcp console to 192.168.0.2 port 4444 +-serial tcp:192.168.0.2:4444 +@item Example to listen and wait on port 4444 for connection +-serial tcp::4444,server +@item Example to not wait and listen on ip 192.168.0.100 port 4444 +-serial tcp:192.168.0.100:4444,server,nowait @end table +@item telnet:host:port[,server][,nowait] +The telnet protocol is used instead of raw tcp sockets. The options +work the same as if you had specified @code{-serial tcp}. The +difference is that the port acts like a telnet server or client using +telnet option negotiation. This will also allow you to send the +MAGIC_SYSRQ sequence if you use a telnet that supports sending the break +sequence. Typically in unix telnet you do it with Control-] and then +type "send break" followed by pressing the enter key. -@item tcp:remote_host:remote_port -TCP Net Console sent to remote_host at the remote_port -@item tcpl:host:port -TCP Net Console: wait for connection on @var{host} on the local port -@var{port}. If host is omitted, 0.0.0.0 is assumed. Only one TCP -connection at a time is accepted. You can use @code{telnet} to connect -to the corresponding character device. @end table @item -parallel dev diff --git a/vl.c b/vl.c index d5a0f7b12..e8780dd08 100644 --- a/vl.c +++ b/vl.c @@ -2203,16 +2203,16 @@ static void udp_chr_add_read_handler(CharDriverState *chr, } int parse_host_port(struct sockaddr_in *saddr, const char *str); +int parse_host_src_port(struct sockaddr_in *haddr, + struct sockaddr_in *saddr, + const char *str); CharDriverState *qemu_chr_open_udp(const char *def) { CharDriverState *chr = NULL; NetCharDriver *s = NULL; int fd = -1; - int con_type; - struct sockaddr_in addr; - const char *p, *r; - int port; + struct sockaddr_in saddr; chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) @@ -2227,58 +2227,12 @@ CharDriverState *qemu_chr_open_udp(const char *def) goto return_err; } - /* There are three types of port definitions - * 1) udp:remote_port - * Juse use 0.0.0.0 for the IP and send to remote - * 2) udp:remote_host:port - * Use a IP and send traffic to remote - * 3) udp:local_port:remote_host:remote_port - * Use local_port as the originator + #2 - */ - con_type = 0; - p = def; - while ((p = strchr(p, ':'))) { - p++; - con_type++; - } - - p = def; - memset(&addr,0,sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - s->daddr.sin_family = AF_INET; - s->daddr.sin_addr.s_addr = htonl(INADDR_ANY); - - switch (con_type) { - case 0: - port = strtol(p, (char **)&r, 0); - if (r == p) { - fprintf(stderr, "Error parsing port number\n"); - goto return_err; - } - s->daddr.sin_port = htons((short)port); - break; - case 2: - port = strtol(p, (char **)&r, 0); - if (r == p) { - fprintf(stderr, "Error parsing port number\n"); - goto return_err; - } - addr.sin_port = htons((short)port); - p = r + 1; - /* Fall through to case 1 now that we have the local port */ - case 1: - if (parse_host_port(&s->daddr, p) < 0) { - fprintf(stderr, "Error parsing host name and port\n"); - goto return_err; - } - break; - default: - fprintf(stderr, "Too many ':' characters\n"); - goto return_err; + if (parse_host_src_port(&s->daddr, &saddr, def) < 0) { + printf("Could not parse: %s\n", def); + goto return_err; } - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("bind"); goto return_err; @@ -2312,6 +2266,7 @@ typedef struct { int fd, listen_fd; int connected; int max_size; + int do_telnetopt; } TCPCharDriver; static void tcp_chr_accept(void *opaque); @@ -2337,6 +2292,56 @@ static int tcp_chr_read_poll(void *opaque) return s->max_size; } +#define IAC 255 +#define IAC_BREAK 243 +static void tcp_chr_process_IAC_bytes(CharDriverState *chr, + TCPCharDriver *s, + char *buf, int *size) +{ + /* Handle any telnet client's basic IAC options to satisfy char by + * char mode with no echo. All IAC options will be removed from + * the buf and the do_telnetopt variable will be used to track the + * state of the width of the IAC information. + * + * IAC commands come in sets of 3 bytes with the exception of the + * "IAC BREAK" command and the double IAC. + */ + + int i; + int j = 0; + + for (i = 0; i < *size; i++) { + if (s->do_telnetopt > 1) { + if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) { + /* Double IAC means send an IAC */ + if (j != i) + buf[j] = buf[i]; + j++; + s->do_telnetopt = 1; + } else { + if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { + /* Handle IAC break commands by sending a serial break */ + chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK); + s->do_telnetopt++; + } + s->do_telnetopt++; + } + if (s->do_telnetopt >= 4) { + s->do_telnetopt = 1; + } + } else { + if ((unsigned char)buf[i] == IAC) { + s->do_telnetopt = 2; + } else { + if (j != i) + buf[j] = buf[i]; + j++; + } + } + } + *size = j; +} + static void tcp_chr_read(void *opaque) { CharDriverState *chr = opaque; @@ -2360,7 +2365,10 @@ static void tcp_chr_read(void *opaque) closesocket(s->fd); s->fd = -1; } else if (size > 0) { - s->fd_read(s->fd_opaque, buf, size); + if (s->do_telnetopt) + tcp_chr_process_IAC_bytes(chr, s, buf, &size); + if (size > 0) + s->fd_read(s->fd_opaque, buf, size); } } @@ -2385,6 +2393,21 @@ static void tcp_chr_connect(void *opaque) tcp_chr_read, NULL, chr); } +#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; +static void tcp_chr_telnet_init(int fd) +{ + char buf[3]; + /* Send the telnet negotion to put telnet in binary, no echo, single char mode */ + IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */ + send(fd, (char *)buf, 3, 0); + IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */ + send(fd, (char *)buf, 3, 0); +} + static void tcp_chr_accept(void *opaque) { CharDriverState *chr = opaque; @@ -2399,6 +2422,8 @@ static void tcp_chr_accept(void *opaque) if (fd < 0 && errno != EINTR) { return; } else if (fd >= 0) { + if (s->do_telnetopt) + tcp_chr_telnet_init(fd); break; } } @@ -2419,16 +2444,34 @@ static void tcp_chr_close(CharDriverState *chr) } static CharDriverState *qemu_chr_open_tcp(const char *host_str, - int is_listen) + int is_telnet) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; int fd = -1, ret, err, val; + int is_listen = 0; + int is_waitconnect = 1; + const char *ptr; struct sockaddr_in saddr; if (parse_host_port(&saddr, host_str) < 0) goto fail; + ptr = host_str; + while((ptr = strchr(ptr,','))) { + ptr++; + if (!strncmp(ptr,"server",6)) { + is_listen = 1; + } else if (!strncmp(ptr,"nowait",6)) { + is_waitconnect = 0; + } else { + printf("Unknown option: %s\n", ptr); + goto fail; + } + } + if (!is_listen) + is_waitconnect = 0; + chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) goto fail; @@ -2439,7 +2482,9 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) goto fail; - socket_set_nonblock(fd); + + if (!is_waitconnect) + socket_set_nonblock(fd); s->connected = 0; s->fd = -1; @@ -2457,6 +2502,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, goto fail; s->listen_fd = fd; qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); + if (is_telnet) + s->do_telnetopt = 1; } else { for(;;) { ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); @@ -2484,6 +2531,12 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, chr->chr_write = tcp_chr_write; chr->chr_add_read_handler = tcp_chr_add_read_handler; chr->chr_close = tcp_chr_close; + if (is_listen && is_waitconnect) { + printf("QEMU waiting for connection on: %s\n", host_str); + tcp_chr_accept(chr); + socket_set_nonblock(s->listen_fd); + } + return chr; fail: if (fd >= 0) @@ -2505,7 +2558,7 @@ CharDriverState *qemu_chr_open(const char *filename) if (strstart(filename, "tcp:", &p)) { return qemu_chr_open_tcp(p, 0); } else - if (strstart(filename, "tcpl:", &p)) { + if (strstart(filename, "telnet:", &p)) { return qemu_chr_open_tcp(p, 1); } else if (strstart(filename, "udp:", &p)) { @@ -2618,6 +2671,45 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) return 0; } +int parse_host_src_port(struct sockaddr_in *haddr, + struct sockaddr_in *saddr, + const char *input_str) +{ + char *str = strdup(input_str); + char *host_str = str; + char *src_str; + char *ptr; + + /* + * Chop off any extra arguments at the end of the string which + * would start with a comma, then fill in the src port information + * if it was provided else use the "any address" and "any port". + */ + if ((ptr = strchr(str,','))) + *ptr = '\0'; + + if ((src_str = strchr(input_str,'@'))) { + *src_str = '\0'; + src_str++; + } + + if (parse_host_port(haddr, host_str) < 0) + goto fail; + + if (!src_str || *src_str == '\0') + src_str = ":0"; + + if (parse_host_port(saddr, src_str) < 0) + goto fail; + + free(str); + return(0); + +fail: + free(str); + return -1; +} + int parse_host_port(struct sockaddr_in *saddr, const char *str) { char buf[512]; -- cgit v1.2.3 From 106ec87921a41752777781f073092301d4477567 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 27 Jun 2006 21:08:10 +0000 Subject: initial MIPS signal handling (initial patch by Raphael Rigo) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2031 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 5 +- linux-user/signal.c | 336 +++++++++++++++++++++++++++++++++++++++++++++- linux-user/syscall.c | 28 ++++ linux-user/syscall_defs.h | 10 ++ 4 files changed, 376 insertions(+), 3 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 6b8337fc7..2250b127a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1302,6 +1302,7 @@ void cpu_loop(CPUMIPSState *env) case EXCP_SYSCALL: { syscall_num = env->gpr[2] - 4000; + env->PC += 4; if (syscall_num >= sizeof(mips_syscall_args)) { ret = -ENOSYS; } else { @@ -1328,7 +1329,6 @@ void cpu_loop(CPUMIPSState *env) arg5, arg6); } - env->PC += 4; if ((unsigned int)ret >= (unsigned int)(-1133)) { env->gpr[7] = 1; /* error flag */ ret = -ret; @@ -1347,6 +1347,9 @@ void cpu_loop(CPUMIPSState *env) info.si_code = 0; queue_signal(info.si_signo, &info); break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; default: // error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", diff --git a/linux-user/signal.c b/linux-user/signal.c index ac4b2897f..1e0308b9e 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -432,13 +432,17 @@ int do_sigaction(int sig, const struct target_sigaction *act, if (oact) { oact->_sa_handler = tswapl(k->sa._sa_handler); oact->sa_flags = tswapl(k->sa.sa_flags); - oact->sa_restorer = tswapl(k->sa.sa_restorer); + #if !defined(TARGET_MIPS) + oact->sa_restorer = tswapl(k->sa.sa_restorer); + #endif oact->sa_mask = k->sa.sa_mask; } if (act) { k->sa._sa_handler = tswapl(act->_sa_handler); k->sa.sa_flags = tswapl(act->sa_flags); - k->sa.sa_restorer = tswapl(act->sa_restorer); + #if !defined(TARGET_MIPS) + k->sa.sa_restorer = tswapl(act->sa_restorer); + #endif k->sa.sa_mask = act->sa_mask; /* we update the host linux signal state */ @@ -1618,6 +1622,334 @@ long do_rt_sigreturn(CPUState *env) return -ENOSYS; } +#elif defined(TARGET_MIPS) + +struct target_sigcontext { + uint32_t sc_regmask; /* Unused */ + uint32_t sc_status; + uint64_t sc_pc; + uint64_t sc_regs[32]; + uint64_t sc_fpregs[32]; + uint32_t sc_ownedfp; /* Unused */ + uint32_t sc_fpc_csr; + uint32_t sc_fpc_eir; /* Unused */ + uint32_t sc_used_math; + uint32_t sc_dsp; /* dsp status, was sc_ssflags */ + uint64_t sc_mdhi; + uint64_t sc_mdlo; + target_ulong sc_hi1; /* Was sc_cause */ + target_ulong sc_lo1; /* Was sc_badvaddr */ + target_ulong sc_hi2; /* Was sc_sigset[4] */ + target_ulong sc_lo2; + target_ulong sc_hi3; + target_ulong sc_lo3; +}; + +struct sigframe { + uint32_t sf_ass[4]; /* argument save space for o32 */ + uint32_t sf_code[2]; /* signal trampoline */ + struct target_sigcontext sf_sc; + target_sigset_t sf_mask; +}; + +/* Install trampoline to jump back from signal handler */ +static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) +{ + int err; + + /* + * Set up the return code ... + * + * li v0, __NR__foo_sigreturn + * syscall + */ + + err = __put_user(0x24020000 + syscall, tramp + 0); + err |= __put_user(0x0000000c , tramp + 1); + /* flush_cache_sigtramp((unsigned long) tramp); */ + return err; +} + +static inline int +setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) +{ + int err = 0; + + err |= __put_user(regs->PC, &sc->sc_pc); + + #define save_gp_reg(i) do { \ + err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \ + } while(0) + __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); + save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); + save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); + save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); + save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); + save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); + save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); + save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); + save_gp_reg(31); + #undef save_gp_reg + + err |= __put_user(regs->HI, &sc->sc_mdhi); + err |= __put_user(regs->LO, &sc->sc_mdlo); + + /* Not used yet, but might be useful if we ever have DSP suppport */ +#if 0 + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } + /* same with 64 bit */ + #ifdef CONFIG_64BIT + err |= __put_user(regs->hi, &sc->sc_hi[0]); + err |= __put_user(regs->lo, &sc->sc_lo[0]); + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi[1]); + err |= __put_user(mflo1(), &sc->sc_lo[1]); + err |= __put_user(mfhi2(), &sc->sc_hi[2]); + err |= __put_user(mflo2(), &sc->sc_lo[2]); + err |= __put_user(mfhi3(), &sc->sc_hi[3]); + err |= __put_user(mflo3(), &sc->sc_lo[3]); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } + #endif + + + #endif + + + #if 0 + err |= __put_user(!!used_math(), &sc->sc_used_math); + + if (!used_math()) + goto out; + + /* + * Save FPU state to signal context. Signal handler will "inherit" + * current FPU state. + */ + preempt_disable(); + + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); + + preempt_enable(); + out: +#endif + return err; +} + +static inline int +restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) +{ + int err = 0; + + err |= __get_user(regs->CP0_EPC, &sc->sc_pc); + + err |= __get_user(regs->HI, &sc->sc_mdhi); + err |= __get_user(regs->LO, &sc->sc_mdlo); + + #define restore_gp_reg(i) do { \ + err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \ + } while(0) + restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); + restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); + restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); + restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); + restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); + restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); + restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); + restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); + restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); + restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); + restore_gp_reg(31); + #undef restore_gp_reg + +#if 0 + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + #ifdef CONFIG_64BIT + err |= __get_user(regs->hi, &sc->sc_hi[0]); + err |= __get_user(regs->lo, &sc->sc_lo[0]); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg); + err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg); + err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + #endif + + err |= __get_user(used_math, &sc->sc_used_math); + conditional_used_math(used_math); + + preempt_disable(); + + if (used_math()) { + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + + preempt_enable(); +#endif + return err; +} +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->gpr[29]; + + /* + * FPU emulator may have it's own trampoline active just + * above the user stack, 16-bytes before the next lowest + * 16 byte boundary. Try to avoid trashing it. + */ + sp -= 32; + +#if 0 + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) + sp = current->sas_ss_sp + current->sas_ss_size; +#endif + + return g2h((sp - frame_size) & ~7); +} + +static void setup_frame(int sig, struct emulated_sigaction * ka, + target_sigset_t *set, CPUState *regs) +{ + struct sigframe *frame; + int i; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); + + if(setup_sigcontext(regs, &frame->sf_sc)) + goto give_sigsegv; + + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if(__put_user(set->sig[i], &frame->sf_mask.sig[i])) + goto give_sigsegv; + } + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to struct sigcontext + * + * $25 and PC point to the signal handler, $29 points to the + * struct sigframe. + */ + regs->gpr[ 4] = sig; + regs->gpr[ 5] = 0; + regs->gpr[ 6] = h2g(&frame->sf_sc); + regs->gpr[29] = h2g(frame); + regs->gpr[31] = h2g(frame->sf_code); + /* The original kernel code sets CP0_EPC to the handler + * since it returns to userland using eret + * we cannot do this here, and we must set PC directly */ + regs->PC = regs->gpr[25] = ka->sa._sa_handler; + return; + +give_sigsegv: + force_sig(TARGET_SIGSEGV/*, current*/); + return; +} + +long do_sigreturn(CPUState *regs) +{ + struct sigframe *frame; + sigset_t blocked; + target_sigset_t target_set; + int i; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "do_sigreturn\n"); +#endif + frame = (struct sigframe *) regs->gpr[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i])) + goto badframe; + } + + target_to_host_sigset_internal(&blocked, &target_set); + sigprocmask(SIG_SETMASK, &blocked, NULL); + + if (restore_sigcontext(regs, &frame->sf_sc)) + goto badframe; + +#if 0 + /* + * Don't let your children do this ... + */ + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\tsyscall_exit" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ +#endif + + regs->PC = regs->CP0_EPC; + /* I am not sure this is right, but it seems to work + * maybe a problem with nested signals ? */ + regs->CP0_EPC = 0; + return 0; + +badframe: + force_sig(TARGET_SIGSEGV/*, current*/); + return 0; + +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} #else diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 229b08935..60ed9a607 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2246,6 +2246,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_sigaction: { + #if !defined(TARGET_MIPS) struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; if (arg2) { @@ -2268,6 +2269,33 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, old_act->sa_restorer = oact.sa_restorer; unlock_user_struct(old_act, arg3, 1); } + #else + struct target_sigaction act, oact, *pact, *old_act; + + if (arg2) { + lock_user_struct(old_act, arg2, 1); + act._sa_handler = old_act->_sa_handler; + target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]); + act.sa_flags = old_act->sa_flags; + unlock_user_struct(old_act, arg2, 0); + pact = &act; + } else { + pact = NULL; + } + + ret = get_errno(do_sigaction(arg1, pact, &oact)); + + if (!is_error(ret) && arg3) { + lock_user_struct(old_act, arg3, 0); + old_act->_sa_handler = oact._sa_handler; + old_act->sa_flags = oact.sa_flags; + old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; + old_act->sa_mask.sig[1] = 0; + old_act->sa_mask.sig[2] = 0; + old_act->sa_mask.sig[3] = 0; + unlock_user_struct(old_act, arg3, 1); + } + #endif } break; case TARGET_NR_rt_sigaction: diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index b5fafcc5a..73a5c4250 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -448,6 +448,15 @@ int do_sigaction(int sig, const struct target_sigaction *act, #endif +#if defined(TARGET_MIPS) + +struct target_sigaction { + target_ulong sa_flags; + target_ulong _sa_handler; + target_sigset_t sa_mask; +}; + +#else struct target_old_sigaction { target_ulong _sa_handler; target_ulong sa_mask; @@ -461,6 +470,7 @@ struct target_sigaction { target_ulong sa_restorer; target_sigset_t sa_mask; }; +#endif typedef union target_sigval { int sival_int; -- cgit v1.2.3 From 0510224e89506a0c463df491338a5b3c778cd20a Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 1 Jul 2006 21:41:18 +0000 Subject: disable unimplemented C+ mode (aka windows xp 64 fix) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2032 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/rtl8139.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 49c4c916b..72939b45c 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -2833,7 +2833,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) pci_conf[0x02] = 0x39; pci_conf[0x03] = 0x81; pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */ - pci_conf[0x08] = 0x20; /* 0x10 */ /* PCI revision ID; >=0x20 is for 8139C+ */ + pci_conf[0x08] = 0x10; /* 0x10 */ /* PCI revision ID; >=0x20 is for 8139C+ */ pci_conf[0x0a] = 0x00; /* ethernet network controller */ pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; /* header_type */ -- cgit v1.2.3 From 99ba31b4fe905e6781e2c99c1e686370acc40ec6 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 09:46:31 +0000 Subject: flash device fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2033 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pflash_cfi02.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 1f0cbe2f9..ee2f63a1a 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -42,9 +42,6 @@ #ifdef PFLASH_DEBUG #define DPRINTF(fmt, args...) \ do { \ - if (loglevel) \ - fprintf(logfile, "PFLASH: " fmt , ##args); \ - else \ printf("PFLASH: " fmt , ##args); \ } while (0) #else @@ -213,7 +210,7 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, /* WARNING: when the memory area is in ROMD mode, the offset is a ram offset, not a physical address */ if (pfl->wcycle == 0) - offset -= pfl->off; + offset -= (target_ulong)(long)pfl->storage; else offset -= pfl->base; -- cgit v1.2.3 From 856074ec70ffba4f1b8d73be88f3cfc782532156 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 09:47:34 +0000 Subject: fix for IO_MEM_ROMD support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2034 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/exec.c b/exec.c index dd42f77d8..88acff091 100644 --- a/exec.c +++ b/exec.c @@ -1513,9 +1513,11 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, te->addr_code = -1; } if (prot & PAGE_WRITE) { - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { - /* ROM: access is ignored (same as unassigned) */ - te->addr_write = vaddr | IO_MEM_ROM; + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + (pd & IO_MEM_ROMD)) { + /* write access calls the I/O callback */ + te->addr_write = vaddr | + (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD)); } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd)) { te->addr_write = vaddr | IO_MEM_NOTDIRTY; -- cgit v1.2.3 From 6cadb320c70cdcbfa38afe9ac864eb77ae6012a3 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 10:08:36 +0000 Subject: rtl8139 fixes (Igor Kovalenko) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2035 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/rtl8139.c | 1279 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 837 insertions(+), 442 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 72939b45c..c41b9d649 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -23,15 +23,28 @@ * Modifications: * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver) - * + * + * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver + * HW revision ID changes for FreeBSD driver + * + * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver + * Corrected packet transfer reassembly routine for 8139C+ mode + * Rearranged debugging print statements + * Implemented PCI timer interrupt (disabled by default) + * Implemented Tally Counters, increased VM load/save version + * Implemented IP/TCP/UDP checksum task offloading */ #include "vl.h" +/* XXX: such dependency must be suppressed */ +#include /* debug RTL8139 card */ //#define DEBUG_RTL8139 1 +#define PCI_FREQUENCY 33000000L + /* debug RTL8139 card C+ mode only */ //#define DEBUG_RTL8139CP 1 @@ -39,6 +52,8 @@ ignored by most drivers, disabled by default */ //#define RTL8139_CALCULATE_RXCRC 1 +/* Uncomment to enable on-board timer interrupts */ +//#define RTL8139_ONBOARD_TIMER 1 #if defined(RTL8139_CALCULATE_RXCRC) /* For crc32 */ @@ -52,12 +67,19 @@ #define MOD2(input, size) \ ( ( input ) & ( size - 1 ) ) +#if defined (DEBUG_RTL8139) +# define DEBUG_PRINT(x) do { printf x ; } while (0) +#else +# define DEBUG_PRINT(x) +#endif + /* Symbolic offsets to registers. */ enum RTL8139_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ - TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ + TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */ + /* Dump Tally Conter control register(64bit). C+ mode only */ + TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ RxBuf = 0x30, ChipCmd = 0x37, RxBufPtr = 0x38, @@ -115,8 +137,10 @@ enum ChipCmdBits { /* C+ mode */ enum CplusCmdBits { - CPlusRxEnb = 0x0002, - CPlusTxEnb = 0x0001, + CPlusRxVLAN = 0x0040, /* enable receive VLAN detagging */ + CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */ + CPlusRxEnb = 0x0002, + CPlusTxEnb = 0x0001, }; /* Interrupt register bits, using my own meaningful names. */ @@ -315,6 +339,11 @@ enum chip_flags { (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22) #define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1) +#define RTL8139_PCI_REVID_8139 0x10 +#define RTL8139_PCI_REVID_8139CPLUS 0x20 + +#define RTL8139_PCI_REVID RTL8139_PCI_REVID_8139CPLUS + /* Size is 64 * 16bit words */ #define EEPROM_9346_ADDR_BITS 6 #define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS) @@ -356,11 +385,41 @@ typedef struct EEprom9346 uint8_t eedo; } EEprom9346; +typedef struct RTL8139TallyCounters +{ + /* Tally counters */ + uint64_t TxOk; + uint64_t RxOk; + uint64_t TxERR; + uint32_t RxERR; + uint16_t MissPkt; + uint16_t FAE; + uint32_t Tx1Col; + uint32_t TxMCol; + uint64_t RxOkPhy; + uint64_t RxOkBrd; + uint32_t RxOkMul; + uint16_t TxAbt; + uint16_t TxUndrn; +} RTL8139TallyCounters; + +/* Clears all tally counters */ +static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters); + +/* Writes tally counters to specified physical memory address */ +static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters); + +/* Loads values of tally counters from VM state file */ +static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters); + +/* Saves values of tally counters to VM state file */ +static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters); + typedef struct RTL8139State { uint8_t phys[8]; /* mac address */ uint8_t mult[8]; /* multicast mask array */ - uint32_t TxStatus[4]; /* TxStatus0 */ + uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */ uint32_t TxAddr[4]; /* TxAddr0 */ uint32_t RxBuf; /* Receive buffer */ uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */ @@ -414,14 +473,27 @@ typedef struct RTL8139State { uint32_t RxRingAddrHI; EEprom9346 eeprom; - + + uint32_t TCTR; + uint32_t TimerInt; + int64_t TCTR_base; + + /* Tally counters */ + RTL8139TallyCounters tally_counters; + + /* Non-persistent data */ + uint8_t *cplus_txbuffer; + int cplus_txbuffer_len; + int cplus_txbuffer_offset; + + /* PCI interrupt timer */ + QEMUTimer *timer; + } RTL8139State; void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom command 0x%02x\n", command); -#endif + DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command)); switch (command & Chip9346_op_mask) { @@ -432,10 +504,8 @@ void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) eeprom->eedo = 0; eeprom->tick = 0; eeprom->mode = Chip9346_data_read; -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output); -#endif + DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output)); } break; @@ -445,10 +515,8 @@ void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) eeprom->input = 0; eeprom->tick = 0; eeprom->mode = Chip9346_none; /* Chip9346_data_write */ -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom begin write to address 0x%02x\n", - eeprom->address); -#endif + DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n", + eeprom->address)); } break; default: @@ -456,19 +524,13 @@ void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) switch (command & Chip9346_op_ext_mask) { case Chip9346_op_write_enable: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write enabled\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom write enabled\n")); break; case Chip9346_op_write_all: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom begin write all\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom begin write all\n")); break; case Chip9346_op_write_disable: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom write disabled\n")); break; } break; @@ -481,9 +543,7 @@ void prom9346_shift_clock(EEprom9346 *eeprom) ++ eeprom->tick; -#if defined(DEBUG_RTL8139) - printf("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo); -#endif + DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo)); switch (eeprom->mode) { @@ -493,9 +553,7 @@ void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->mode = Chip9346_read_command; eeprom->tick = 0; eeprom->input = 0; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ synchronized, begin command read\n"); -#endif + DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n")); } break; @@ -512,14 +570,24 @@ void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->output <<= 1; if (eeprom->tick == 16) { +#if 1 + // the FreeBSD drivers (rl and re) don't explicitly toggle + // CS between reads (or does setting Cfg9346 to 0 count too?), + // so we need to enter wait-for-command state here + eeprom->mode = Chip9346_enter_command_mode; + eeprom->input = 0; + eeprom->tick = 0; + + DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n")); +#else + // original behaviour ++eeprom->address; eeprom->address &= EEPROM_9346_ADDR_MASK; eeprom->output = eeprom->contents[eeprom->address]; eeprom->tick = 0; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ read next address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output); + DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output)); #endif } break; @@ -528,10 +596,9 @@ void prom9346_shift_clock(EEprom9346 *eeprom) eeprom->input = (eeprom->input << 1) | (bit & 1); if (eeprom->tick == 16) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->input); -#endif + DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->input)); + eeprom->contents[eeprom->address] = eeprom->input; eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */ eeprom->tick = 0; @@ -548,10 +615,9 @@ void prom9346_shift_clock(EEprom9346 *eeprom) { eeprom->contents[i] = eeprom->input; } -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom filled with data=0x%04x\n", - eeprom->input); -#endif + DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n", + eeprom->input)); + eeprom->mode = Chip9346_enter_command_mode; eeprom->tick = 0; eeprom->input = 0; @@ -582,9 +648,8 @@ void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) eeprom->eesk = eesk; eeprom->eedi = eedi; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo); -#endif + DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", + eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo)); if (!old_eecs && eecs) { @@ -594,17 +659,12 @@ void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) eeprom->output = 0; eeprom->mode = Chip9346_enter_command_mode; -#if defined(DEBUG_RTL8139) - printf("=== eeprom: begin access, enter command mode\n"); -#endif - + DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n")); } if (!eecs) { -#if defined(DEBUG_RTL8139) - printf("=== eeprom: end access\n"); -#endif + DEBUG_PRINT(("=== eeprom: end access\n")); return; } @@ -619,10 +679,10 @@ static void rtl8139_update_irq(RTL8139State *s) { int isr; isr = (s->IntrStatus & s->IntrMask) & 0xffff; -#if defined(DEBUG_RTL8139) - printf("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", - s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask); -#endif + + DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", + s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask)); + if (s->irq == 16) { /* PCI irq */ pci_set_irq(s->pci_dev, 0, (isr != 0)); @@ -691,9 +751,7 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) /* write packet data */ if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s)) { - #if defined(DEBUG_RTL8139) - printf(">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped); - #endif + DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped)); if (size > wrapped) { @@ -751,7 +809,7 @@ static int rtl8139_can_receive(void *opaque) } } -static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt) { RTL8139State *s = opaque; @@ -761,16 +819,12 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: received len=%d\n", size); -#endif + DEBUG_PRINT((">>> RTL8139: received len=%d\n", size)); /* test if board clock is stopped */ if (!s->clock_enabled) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: stopped ==========================\n"); -#endif + DEBUG_PRINT(("RTL8139: stopped ==========================\n")); return; } @@ -778,42 +832,44 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) if (!rtl8139_receiver_enabled(s)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: receiver disabled ================\n"); -#endif + DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); return; } /* XXX: check this */ if (s->RxConfig & AcceptAllPhys) { /* promiscuous: receive all */ -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: packet received in promiscuous mode\n"); -#endif + DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n")); } else { if (!memcmp(buf, broadcast_macaddr, 6)) { /* broadcast address */ if (!(s->RxConfig & AcceptBroadcast)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: broadcast packet rejected\n"); -#endif + DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxBroadcast; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: broadcast packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: broadcast packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkBrd; + } else if (buf[0] & 0x01) { /* multicast */ if (!(s->RxConfig & AcceptMulticast)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast packet rejected\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } @@ -821,17 +877,21 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast address mismatch\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxMulticast; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkMul; + } else if (s->phys[0] == buf[0] && s->phys[1] == buf[1] && s->phys[2] == buf[2] && @@ -841,23 +901,28 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) /* match */ if (!(s->RxConfig & AcceptMyPhys)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: rejecting physical address matching packet\n"); -#endif + DEBUG_PRINT((">>> RTL8139: rejecting physical address matching packet\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxPhysical; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: physical address matching packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: physical address matching packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkPhy; } else { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: unknown packet\n"); -#endif + DEBUG_PRINT((">>> RTL8139: unknown packet\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } } @@ -872,9 +937,7 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) if (rtl8139_cp_receiver_enabled(s)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: in C+ Rx mode ================\n"); -#endif + DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n")); /* begin C+ receiver mode */ @@ -897,10 +960,8 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); cplus_rx_ring_desc += 16 * descriptor; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = 0x%8lx\n", - descriptor, s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = %016" PRIx64 "\n", + descriptor, s->RxRingAddrHI, s->RxRingAddrLO, (uint64_t)cplus_rx_ring_desc)); uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; @@ -913,33 +974,41 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4); rxbufHI = le32_to_cpu(val); -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", + DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", descriptor, - rxdw0, rxdw1, rxbufLO, rxbufHI); -#endif + rxdw0, rxdw1, rxbufLO, rxbufHI)); if (!(rxdw0 & CP_RX_OWN)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; + + /* update tally counter */ + ++s->tally_counters.RxERR; + ++s->tally_counters.MissPkt; + rtl8139_update_irq(s); return; } uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; + /* TODO: scatter the packet over available receive ring descriptors space */ + if (size+4 > rx_space) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", - descriptor, rx_space, size); -#endif + DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", + descriptor, rx_space, size)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; + + /* update tally counter */ + ++s->tally_counters.RxERR; + ++s->tally_counters.MissPkt; + rtl8139_update_irq(s); return; } @@ -949,6 +1018,11 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) /* receive/copy to target memory */ cpu_physical_memory_write( rx_addr, buf, size ); + if (s->CpCmd & CPlusRxChkSum) + { + /* do some packet checksumming */ + } + /* write checksum */ #if defined (RTL8139_CALCULATE_RXCRC) val = cpu_to_le32(crc32(~0, buf, size)); @@ -1008,6 +1082,9 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) val = cpu_to_le32(rxdw1); cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); + /* update tally counter */ + ++s->tally_counters.RxOk; + /* seek to next Rx descriptor */ if (rxdw0 & CP_RX_EOR) { @@ -1018,16 +1095,13 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) ++s->currCPlusRxDesc; } -#if defined(DEBUG_RTL8139) - printf("RTL8139: done C+ Rx mode ----------------\n"); -#endif + DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n")); } else { -#if defined(DEBUG_RTL8139) - printf("RTL8139: in ring Rx mode ================\n"); -#endif + DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n")); + /* begin ring receiver mode */ int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize); @@ -1035,10 +1109,9 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) if (avail != 0 && size + 8 >= avail) { -#if defined(DEBUG_RTL8139) - printf("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8); -#endif + DEBUG_PRINT(("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; rtl8139_update_irq(s); @@ -1070,15 +1143,21 @@ static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) /* now we can signal we have received something */ -#if defined(DEBUG_RTL8139) - printf(" received: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); -#endif - + DEBUG_PRINT((" received: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); } s->IntrStatus |= RxOK; - rtl8139_update_irq(s); + + if (do_interrupt) + { + rtl8139_update_irq(s); + } +} + +static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +{ + rtl8139_do_receive(opaque, buf, size, 1); } static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) @@ -1103,6 +1182,11 @@ static void rtl8139_reset(RTL8139State *s) /* prepare eeprom */ s->eeprom.contents[0] = 0x8129; +#if 1 + // PCI vendor and device ID should be mirrored here + s->eeprom.contents[1] = 0x10ec; + s->eeprom.contents[2] = 0x8139; +#endif memcpy(&s->eeprom.contents[7], s->macaddr, 6); /* mark all status registers as owned by host */ @@ -1129,7 +1213,7 @@ static void rtl8139_reset(RTL8139State *s) // s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk s->clock_enabled = 0; #else - s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 0, 0); // RTL-8139C HasLWake + s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake s->clock_enabled = 1; #endif @@ -1157,34 +1241,133 @@ static void rtl8139_reset(RTL8139State *s) s->NWayAdvert = 0x05e1; /* all modes, full duplex */ s->NWayLPAR = 0x05e1; /* all modes, full duplex */ s->NWayExpansion = 0x0001; /* autonegotiation supported */ + + /* also reset timer and disable timer interrupt */ + s->TCTR = 0; + s->TimerInt = 0; + s->TCTR_base = 0; + + /* reset tally counters */ + RTL8139TallyCounters_clear(&s->tally_counters); +} + +void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters) +{ + counters->TxOk = 0; + counters->RxOk = 0; + counters->TxERR = 0; + counters->RxERR = 0; + counters->MissPkt = 0; + counters->FAE = 0; + counters->Tx1Col = 0; + counters->TxMCol = 0; + counters->RxOkPhy = 0; + counters->RxOkBrd = 0; + counters->RxOkMul = 0; + counters->TxAbt = 0; + counters->TxUndrn = 0; +} + +static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters) +{ + uint16_t val16; + uint32_t val32; + uint64_t val64; + + val64 = cpu_to_le64(tally_counters->TxOk); + cpu_physical_memory_write(tc_addr + 0, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->RxOk); + cpu_physical_memory_write(tc_addr + 8, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->TxERR); + cpu_physical_memory_write(tc_addr + 16, (uint8_t *)&val64, 8); + + val32 = cpu_to_le32(tally_counters->RxERR); + cpu_physical_memory_write(tc_addr + 24, (uint8_t *)&val32, 4); + + val16 = cpu_to_le16(tally_counters->MissPkt); + cpu_physical_memory_write(tc_addr + 28, (uint8_t *)&val16, 2); + + val16 = cpu_to_le16(tally_counters->FAE); + cpu_physical_memory_write(tc_addr + 30, (uint8_t *)&val16, 2); + + val32 = cpu_to_le32(tally_counters->Tx1Col); + cpu_physical_memory_write(tc_addr + 32, (uint8_t *)&val32, 4); + + val32 = cpu_to_le32(tally_counters->TxMCol); + cpu_physical_memory_write(tc_addr + 36, (uint8_t *)&val32, 4); + + val64 = cpu_to_le64(tally_counters->RxOkPhy); + cpu_physical_memory_write(tc_addr + 40, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->RxOkBrd); + cpu_physical_memory_write(tc_addr + 48, (uint8_t *)&val64, 8); + + val32 = cpu_to_le32(tally_counters->RxOkMul); + cpu_physical_memory_write(tc_addr + 56, (uint8_t *)&val32, 4); + + val16 = cpu_to_le16(tally_counters->TxAbt); + cpu_physical_memory_write(tc_addr + 60, (uint8_t *)&val16, 2); + + val16 = cpu_to_le16(tally_counters->TxUndrn); + cpu_physical_memory_write(tc_addr + 62, (uint8_t *)&val16, 2); +} + +/* Loads values of tally counters from VM state file */ +static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters) +{ + qemu_get_be64s(f, &tally_counters->TxOk); + qemu_get_be64s(f, &tally_counters->RxOk); + qemu_get_be64s(f, &tally_counters->TxERR); + qemu_get_be32s(f, &tally_counters->RxERR); + qemu_get_be16s(f, &tally_counters->MissPkt); + qemu_get_be16s(f, &tally_counters->FAE); + qemu_get_be32s(f, &tally_counters->Tx1Col); + qemu_get_be32s(f, &tally_counters->TxMCol); + qemu_get_be64s(f, &tally_counters->RxOkPhy); + qemu_get_be64s(f, &tally_counters->RxOkBrd); + qemu_get_be32s(f, &tally_counters->RxOkMul); + qemu_get_be16s(f, &tally_counters->TxAbt); + qemu_get_be16s(f, &tally_counters->TxUndrn); +} + +/* Saves values of tally counters to VM state file */ +static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters) +{ + qemu_put_be64s(f, &tally_counters->TxOk); + qemu_put_be64s(f, &tally_counters->RxOk); + qemu_put_be64s(f, &tally_counters->TxERR); + qemu_put_be32s(f, &tally_counters->RxERR); + qemu_put_be16s(f, &tally_counters->MissPkt); + qemu_put_be16s(f, &tally_counters->FAE); + qemu_put_be32s(f, &tally_counters->Tx1Col); + qemu_put_be32s(f, &tally_counters->TxMCol); + qemu_put_be64s(f, &tally_counters->RxOkPhy); + qemu_put_be64s(f, &tally_counters->RxOkBrd); + qemu_put_be32s(f, &tally_counters->RxOkMul); + qemu_put_be16s(f, &tally_counters->TxAbt); + qemu_put_be16s(f, &tally_counters->TxUndrn); } static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val)); if (val & CmdReset) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd reset\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd reset\n")); rtl8139_reset(s); } if (val & CmdRxEnb) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd enable receiver\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n")); } if (val & CmdTxEnb) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd enable transmitter\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n")); } /* mask unwriteable bits */ @@ -1202,15 +1385,11 @@ static int rtl8139_RxBufferEmpty(RTL8139State *s) if (unread != 0) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: receiver buffer data available 0x%04x\n", unread); -#endif + DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", unread)); return 0; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: receiver buffer is empty\n"); -#endif + DEBUG_PRINT(("RTL8139: receiver buffer is empty\n")); return 1; } @@ -1222,9 +1401,7 @@ static uint32_t rtl8139_ChipCmd_read(RTL8139State *s) if (rtl8139_RxBufferEmpty(s)) ret |= RxBufEmpty; -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret)); return ret; } @@ -1233,9 +1410,7 @@ static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val) { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ command register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xff84, s->CpCmd); @@ -1247,9 +1422,21 @@ static uint32_t rtl8139_CpCmd_read(RTL8139State *s) { uint32_t ret = s->CpCmd; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ command register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret)); + + return ret; +} + +static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val) +{ + DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", val)); +} + +static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s) +{ + uint32_t ret = 0; + + DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret)); return ret; } @@ -1261,9 +1448,7 @@ int rtl8139_config_writeable(RTL8139State *s) return 1; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: Configuration registers are write-protected\n"); -#endif + DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n")); return 0; } @@ -1272,9 +1457,7 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ uint32 mask = 0x4cff; @@ -1296,9 +1479,7 @@ static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s) { uint32_t ret = s->BasicModeCtrl; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret)); return ret; } @@ -1307,9 +1488,7 @@ static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val) { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xff3f, s->BasicModeStatus); @@ -1321,9 +1500,7 @@ static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s) { uint32_t ret = s->BasicModeStatus; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret)); return ret; } @@ -1332,9 +1509,7 @@ static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Cfg9346 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x31, s->Cfg9346); @@ -1377,9 +1552,7 @@ static uint32_t rtl8139_Cfg9346_read(RTL8139State *s) } } -#ifdef DEBUG_RTL8139 - printf("RTL8139: Cfg9346 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret)); return ret; } @@ -1388,9 +1561,7 @@ static void rtl8139_Config0_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config0 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1405,9 +1576,7 @@ static uint32_t rtl8139_Config0_read(RTL8139State *s) { uint32_t ret = s->Config0; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config0 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret)); return ret; } @@ -1416,9 +1585,7 @@ static void rtl8139_Config1_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config1 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1433,9 +1600,7 @@ static uint32_t rtl8139_Config1_read(RTL8139State *s) { uint32_t ret = s->Config1; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config1 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret)); return ret; } @@ -1444,9 +1609,7 @@ static void rtl8139_Config3_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config3 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1461,9 +1624,7 @@ static uint32_t rtl8139_Config3_read(RTL8139State *s) { uint32_t ret = s->Config3; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config3 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret)); return ret; } @@ -1472,9 +1633,7 @@ static void rtl8139_Config4_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config4 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1489,9 +1648,7 @@ static uint32_t rtl8139_Config4_read(RTL8139State *s) { uint32_t ret = s->Config4; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config4 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret)); return ret; } @@ -1500,9 +1657,7 @@ static void rtl8139_Config5_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config5 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x80, s->Config5); @@ -1514,9 +1669,7 @@ static uint32_t rtl8139_Config5_read(RTL8139State *s) { uint32_t ret = s->Config5; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config5 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret)); return ret; } @@ -1525,15 +1678,11 @@ static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val) { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val)); return; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val)); val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig); @@ -1542,31 +1691,26 @@ static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val) static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C TxConfig via write(b) val=0x%02x\n", val); -#endif - uint32_t tc = s->TxConfig; - tc &= 0xFFFFFF00; - tc |= (val & 0x000000FF); - rtl8139_TxConfig_write(s, tc); + DEBUG_PRINT(("RTL8139C TxConfig via write(b) val=0x%02x\n", val)); + + uint32_t tc = s->TxConfig; + tc &= 0xFFFFFF00; + tc |= (val & 0x000000FF); + rtl8139_TxConfig_write(s, tc); } static uint32_t rtl8139_TxConfig_read(RTL8139State *s) { uint32_t ret = s->TxConfig; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxConfig read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret)); return ret; } static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xf0fc0040, s->RxConfig); @@ -1576,18 +1720,14 @@ static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) /* reset buffer size and read/write pointers */ rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3)); -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize); -#endif + DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize)); } static uint32_t rtl8139_RxConfig_read(RTL8139State *s) { uint32_t ret = s->RxConfig; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret)); return ret; } @@ -1596,41 +1736,43 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", + descriptor)); return 0; } if (s->TxStatus[descriptor] & TxHostOwns) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", descriptor, s->TxStatus[descriptor]); -#endif + DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", + descriptor, s->TxStatus[descriptor])); return 0; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmitting from descriptor %d\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", descriptor)); int txsize = s->TxStatus[descriptor] & 0x1fff; uint8_t txbuffer[0x2000]; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", txsize, s->TxAddr[descriptor]); -#endif - cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); + DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", + txsize, s->TxAddr[descriptor])); - qemu_send_packet(s->vc, txbuffer, txsize); + cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); /* Mark descriptor as transferred */ s->TxStatus[descriptor] |= TxHostOwns; s->TxStatus[descriptor] |= TxStatOK; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor); -#endif + if (TxLoopBack == (s->TxConfig & TxLoopBack)) + { + DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); + rtl8139_do_receive(s, txbuffer, txsize, 0); + } + else + { + qemu_send_packet(s->vc, txbuffer, txsize); + } + + DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor)); /* update interrupt */ s->IntrStatus |= TxOK; @@ -1643,17 +1785,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode: transmitter disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n")); return 0; } if (!rtl8139_cp_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode: C+ transmitter disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n")); return 0 ; } @@ -1665,10 +1803,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) /* Normal priority ring */ cplus_tx_ring_desc += 16 * descriptor; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", - descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", + descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc)); uint32_t val, txdw0,txdw1,txbufLO,txbufHI; @@ -1681,11 +1817,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4); txbufHI = le32_to_cpu(val); -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", + DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor, - txdw0, txdw1, txbufLO, txbufHI); -#endif + txdw0, txdw1, txbufLO, txbufHI)); /* w0 ownership flag */ #define CP_TX_OWN (1<<31) @@ -1728,28 +1862,71 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) if (!(txdw0 & CP_TX_OWN)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor)); return 0 ; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor)); + + if (txdw0 & CP_TX_FS) + { + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is first segment descriptor\n", descriptor)); + + /* reset internal buffer offset */ + s->cplus_txbuffer_offset = 0; + } int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK; target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI); - uint8_t txbuffer[CP_TX_BUFFER_SIZE]; + /* make sure we have enough space to assemble the packet */ + if (!s->cplus_txbuffer) + { + s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE; + s->cplus_txbuffer = malloc(s->cplus_txbuffer_len); + s->cplus_txbuffer_offset = 0; + } + + while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) + { + s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE; + s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len); -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at 0x%08x\n", txsize, tx_addr); -#endif - cpu_physical_memory_read(tx_addr, txbuffer, txsize); + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len)); + } + + if (!s->cplus_txbuffer) + { + /* out of memory */ - /* transmit the packet */ - qemu_send_packet(s->vc, txbuffer, txsize); + DEBUG_PRINT(("RTL8139: +++ C+ mode transmiter failed to reallocate %d bytes\n", s->cplus_txbuffer_len)); + + /* update tally counter */ + ++s->tally_counters.TxERR; + ++s->tally_counters.TxAbt; + + return 0; + } + + /* append more data to the packet */ + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at %016" PRIx64 " to offset %d\n", + txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset)); + + cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); + s->cplus_txbuffer_offset += txsize; + + /* seek to next Rx descriptor */ + if (txdw0 & CP_TX_EOR) + { + s->currCPlusTxDesc = 0; + } + else + { + ++s->currCPlusTxDesc; + if (s->currCPlusTxDesc >= 64) + s->currCPlusTxDesc = 0; + } /* transfer ownership to target */ txdw0 &= ~CP_RX_OWN; @@ -1767,19 +1944,175 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) // val = cpu_to_le32(txdw1); // cpu_physical_memory_write(cplus_tx_ring_desc+4, &val, 4); - /* seek to next Rx descriptor */ - if (txdw0 & CP_TX_EOR) + /* Now decide if descriptor being processed is holding the last segment of packet */ + if (txdw0 & CP_TX_LS) { - s->currCPlusTxDesc = 0; + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor)); + + /* can transfer fully assembled packet */ + + uint8_t *saved_buffer = s->cplus_txbuffer; + int saved_size = s->cplus_txbuffer_offset; + int saved_buffer_len = s->cplus_txbuffer_len; + + /* reset the card space to protect from recursive call */ + s->cplus_txbuffer = NULL; + s->cplus_txbuffer_offset = 0; + s->cplus_txbuffer_len = 0; + + if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS)) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); + + #define ETH_P_IP 0x0800 /* Internet Protocol packet */ + #define ETH_HLEN 14 + + /* ip packet header */ + register struct ip *ip = 0; + int hlen = 0; + + struct mbuf local_m; + + int proto = ntohs(*(uint16_t *)(saved_buffer + 12)); + if (proto == ETH_P_IP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n")); + + /* not aligned */ + local_m.m_data = saved_buffer + ETH_HLEN; + local_m.m_len = saved_size - ETH_HLEN; + + ip = mtod(&local_m, struct ip *); + + if (ip->ip_v != IPVERSION) { + DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", ip->ip_v, IPVERSION)); + ip = NULL; + } else { + hlen = ip->ip_hl << 2; + } + } + + if (ip) + { + if (txdw0 & CP_TX_IPCS) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); + + if (hlenlocal_m.m_len) {/* min header length */ + /* bad packet header len */ + /* or packet too short */ + } + else + { + ip->ip_sum = 0; + ip->ip_sum = cksum(&local_m, hlen); + DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + } + } + + if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); + + u_int8_t ip_protocol = ip->ip_p; + u_int16_t ip_data_len = ntohs(ip->ip_len) - hlen; + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + memcpy(saved_ip_header, local_m.m_data, hlen); + + struct mbuf local_checksum_m; + + local_checksum_m.m_data = local_m.m_data + hlen - 12; + local_checksum_m.m_len = local_m.m_len - hlen + 12; + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(local_checksum_m.m_data, saved_ip_header + 12, 8); + + if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IPPROTO_TCP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); + + struct tcpiphdr * p_tcpip_hdr = (struct tcpiphdr *)local_checksum_m.m_data; + p_tcpip_hdr->ti_x1 = 0; + p_tcpip_hdr->ti_pr = IPPROTO_TCP; + p_tcpip_hdr->ti_len = htons(ip_data_len); + + struct tcphdr* p_tcp_hdr = (struct tcphdr*) (local_checksum_m.m_data+12); + + p_tcp_hdr->th_sum = 0; + + int tcp_checksum = cksum(&local_checksum_m, ip_data_len + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); + + p_tcp_hdr->th_sum = tcp_checksum; + } + else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IPPROTO_UDP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); + + struct udpiphdr * p_udpip_hdr = (struct udpiphdr *)local_checksum_m.m_data; + p_udpip_hdr->ui_x1 = 0; + p_udpip_hdr->ui_pr = IPPROTO_UDP; + p_udpip_hdr->ui_len = htons(ip_data_len); + + struct udphdr* p_udp_hdr = (struct udphdr*) (local_checksum_m.m_data+12); + + int old_csum = p_udp_hdr->uh_sum; + p_udp_hdr->uh_sum = 0; + + int udp_checksum = cksum(&local_checksum_m, ip_data_len + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); + + if (old_csum != udp_checksum) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum mismatch old=%04x new=%04x\n", + old_csum, udp_checksum)); + } + + p_udp_hdr->uh_sum = udp_checksum; + } + + /* restore IP header */ + memcpy(local_m.m_data, saved_ip_header, hlen); + } + } + } + + /* update tally counter */ + ++s->tally_counters.TxOk; + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size)); + + if (TxLoopBack == (s->TxConfig & TxLoopBack)) + { + DEBUG_PRINT(("RTL8139: +++ C+ transmit loopback mode\n")); + rtl8139_receive(s, saved_buffer, saved_size); + } + else + { + /* transmit the packet */ + qemu_send_packet(s->vc, saved_buffer, saved_size); + } + + /* restore card space if there was no recursion and reset offset */ + if (!s->cplus_txbuffer) + { + s->cplus_txbuffer = saved_buffer; + s->cplus_txbuffer_len = saved_buffer_len; + s->cplus_txbuffer_offset = 0; + } + else + { + free(saved_buffer); + } } else { - ++s->currCPlusTxDesc; + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n")); } -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode transmitted %d bytes from descriptor %d\n", txsize, descriptor); -#endif return 1; } @@ -1795,9 +2128,8 @@ static void rtl8139_cplus_transmit(RTL8139State *s) /* Mark transfer completed */ if (!txcount) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", s->currCPlusTxDesc); -#endif + DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", + s->currCPlusTxDesc)); } else { @@ -1822,9 +2154,7 @@ static void rtl8139_transmit(RTL8139State *s) /* Mark transfer completed */ if (!txcount) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc); -#endif + DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc)); } } @@ -1832,9 +2162,31 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32 { int descriptor = txRegOffset/4; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor); -#endif + + /* handle C+ transmit mode register configuration */ + + if (rtl8139_cp_transmitter_enabled(s)) + { + DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); + + /* handle Dump Tally Counters command */ + s->TxStatus[descriptor] = val; + + if (descriptor == 0 && (val & 0x8)) + { + target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]); + + /* dump tally counters to specified memory location */ + RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters); + + /* mark dump completed */ + s->TxStatus[0] &= ~0x8; + } + + return; + } + + DEBUG_PRINT(("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); /* mask only reserved bits */ val &= ~0xff00c000; /* these bits are reset on write */ @@ -1850,9 +2202,7 @@ static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset) { uint32_t ret = s->TxStatus[txRegOffset/4]; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret); -#endif + DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret)); return ret; } @@ -1884,9 +2234,7 @@ static uint16_t rtl8139_TSAD_read(RTL8139State *s) |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TSAD read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret)); return ret; } @@ -1895,46 +2243,38 @@ static uint16_t rtl8139_CSCR_read(RTL8139State *s) { uint16_t ret = s->CSCR; -#ifdef DEBUG_RTL8139 - printf("RTL8139: CSCR read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret)); return ret; } static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val); -#endif + DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); + + s->currCPlusTxDesc = 0; } static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) { uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]); -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret); -#endif + DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret)); return ret; } static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBufPtr write val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val)); /* this value is off by 16 */ s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize); -#if defined(DEBUG_RTL8139) - printf(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); -#endif + DEBUG_PRINT((" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); } static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) @@ -1942,18 +2282,24 @@ static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) /* this value is off by 16 */ uint32_t ret = s->RxBufPtr - 0x10; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBufPtr read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxBufPtr read val=0x%04x\n", ret)); + + return ret; +} + +static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s) +{ + /* this value is NOT off by 16 */ + uint32_t ret = s->RxBufAddr; + + DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret)); return ret; } static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBuf write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val)); s->RxBuf = val; @@ -1964,18 +2310,14 @@ static uint32_t rtl8139_RxBuf_read(RTL8139State *s) { uint32_t ret = s->RxBuf; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBuf read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret)); return ret; } static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrMask write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x1e00, s->IntrMask); @@ -1989,18 +2331,14 @@ static uint32_t rtl8139_IntrMask_read(RTL8139State *s) { uint32_t ret = s->IntrMask; -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrMask read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret)); return ret; } static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrStatus write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val)); #if 0 @@ -2027,9 +2365,7 @@ static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) { uint32_t ret = s->IntrStatus; -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrStatus read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret)); #if 0 @@ -2045,9 +2381,7 @@ static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: MultiIntr write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xf000, s->MultiIntr); @@ -2059,9 +2393,7 @@ static uint32_t rtl8139_MultiIntr_read(RTL8139State *s) { uint32_t ret = s->MultiIntr; -#ifdef DEBUG_RTL8139 - printf("RTL8139: MultiIntr read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret)); return ret; } @@ -2109,15 +2441,11 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) break; case MediaStatus: /* ignore */ -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val)); break; case HltClk: -#ifdef DEBUG_RTL8139 - printf("RTL8139: HltClk write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val)); if (val == 'R') { s->clock_enabled = 1; @@ -2129,37 +2457,27 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) break; case TxThresh: -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxThresh write(b) val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val)); s->TxThresh = val; break; case TxPoll: -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll write(b) val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val)); if (val & (1 << 7)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll high priority transmission (not implemented)\n"); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not implemented)\n")); //rtl8139_cplus_transmit(s); } if (val & (1 << 6)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll normal priority transmission\n"); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll normal priority transmission\n")); rtl8139_cplus_transmit(s); } break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val)); break; } } @@ -2195,20 +2513,14 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) rtl8139_BasicModeStatus_write(s, val); break; case NWayAdvert: -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayAdvert write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val)); s->NWayAdvert = val; break; case NWayLPAR: -#ifdef DEBUG_RTL8139 - printf("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val)); break; case NWayExpansion: -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayExpansion write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val)); s->NWayExpansion = val; break; @@ -2216,10 +2528,12 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) rtl8139_CpCmd_write(s, val); break; + case IntrMitigate: + rtl8139_IntrMitigate_write(s, val); + break; + default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val)); #ifdef TARGET_WORDS_BIGENDIAN rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff); @@ -2241,9 +2555,7 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) switch (addr) { case RxMissed: -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxMissed clearing on write\n"); -#endif + DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n")); s->RxMissed = 0; break; @@ -2268,23 +2580,28 @@ static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) break; case RxRingAddrLO: -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing low bits write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", val)); s->RxRingAddrLO = val; break; case RxRingAddrHI: -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing high bits write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", val)); s->RxRingAddrHI = val; break; + case Timer: + DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n")); + s->TCTR = 0; + s->TCTR_base = qemu_get_clock(vm_clock); + break; + + case FlashReg: + DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val)); + s->TimerInt = val; + break; + default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val)); #ifdef TARGET_WORDS_BIGENDIAN rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff); rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff); @@ -2342,43 +2659,31 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) case MediaStatus: ret = 0xd0; -#ifdef DEBUG_RTL8139 - printf("RTL8139: MediaStatus read 0x%x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret)); break; case HltClk: ret = s->clock_enabled; -#ifdef DEBUG_RTL8139 - printf("RTL8139: HltClk read 0x%x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret)); break; case PCIRevisionID: - ret = 0x10; -#ifdef DEBUG_RTL8139 - printf("RTL8139: PCI Revision ID read 0x%x\n", ret); -#endif + ret = RTL8139_PCI_REVID; + DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret)); break; case TxThresh: ret = s->TxThresh; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret)); break; case 0x43: /* Part of TxConfig register. Windows driver tries to read it */ ret = s->TxConfig >> 24; -#ifdef DEBUG_RTL8139 - printf("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret)); break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented read(b) addr=0x%x\n", addr); -#endif + DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", addr)); ret = 0; break; } @@ -2411,6 +2716,10 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) ret = rtl8139_RxBufPtr_read(s); break; + case RxBufAddr: + ret = rtl8139_RxBufAddr_read(s); + break; + case BasicModeCtrl: ret = rtl8139_BasicModeCtrl_read(s); break; @@ -2419,27 +2728,25 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) break; case NWayAdvert: ret = s->NWayAdvert; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret)); break; case NWayLPAR: ret = s->NWayLPAR; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret)); break; case NWayExpansion: ret = s->NWayExpansion; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret)); break; case CpCmd: ret = rtl8139_CpCmd_read(s); break; + case IntrMitigate: + ret = rtl8139_IntrMitigate_read(s); + break; + case TxSummary: ret = rtl8139_TSAD_read(s); break; @@ -2449,9 +2756,7 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr); -#endif + DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr)); #ifdef TARGET_WORDS_BIGENDIAN ret = rtl8139_io_readb(opaque, addr) << 8; @@ -2461,9 +2766,7 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) ret |= rtl8139_io_readb(opaque, addr + 1) << 8; #endif -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret); -#endif + DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret)); break; } @@ -2482,9 +2785,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) case RxMissed: ret = s->RxMissed; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxMissed read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret)); break; case TxConfig: @@ -2509,22 +2810,26 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) case RxRingAddrLO: ret = s->RxRingAddrLO; -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret)); break; case RxRingAddrHI: ret = s->RxRingAddrHI; -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret)); + break; + + case Timer: + ret = s->TCTR; + DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret)); + break; + + case FlashReg: + ret = s->TimerInt; + DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret)); break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr); -#endif + DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr)); #ifdef TARGET_WORDS_BIGENDIAN ret = rtl8139_io_readb(opaque, addr) << 24; @@ -2538,9 +2843,7 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) ret |= rtl8139_io_readb(opaque, addr + 3) << 24; #endif -#ifdef DEBUG_RTL8139 - printf("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret); -#endif + DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret)); break; } @@ -2688,6 +2991,12 @@ static void rtl8139_save(QEMUFile* f,void* opaque) qemu_put_8s(f, &s->eeprom.eesk); qemu_put_8s(f, &s->eeprom.eedi); qemu_put_8s(f, &s->eeprom.eedo); + + qemu_put_be32s(f, &s->TCTR); + qemu_put_be32s(f, &s->TimerInt); + qemu_put_be64s(f, &s->TCTR_base); + + RTL8139TallyCounters_save(f, &s->tally_counters); } static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) @@ -2695,9 +3004,11 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) RTL8139State* s=(RTL8139State*)opaque; int i; - if (version_id != 1) + /* just 2 versions for now */ + if (version_id > 2) return -EINVAL; + /* saved since version 1 */ qemu_get_buffer(f, s->phys, 6); qemu_get_buffer(f, s->mult, 8); @@ -2769,6 +3080,25 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) qemu_get_8s(f, &s->eeprom.eedi); qemu_get_8s(f, &s->eeprom.eedo); + /* saved since version 2 */ + if (version_id >= 2) + { + qemu_get_be32s(f, &s->TCTR); + qemu_get_be32s(f, &s->TimerInt); + qemu_get_be64s(f, &s->TCTR_base); + + RTL8139TallyCounters_load(f, &s->tally_counters); + } + else + { + /* not saved, use default */ + s->TCTR = 0; + s->TimerInt = 0; + s->TCTR_base = 0; + + RTL8139TallyCounters_clear(&s->tally_counters); + } + return 0; } @@ -2817,6 +3147,59 @@ static CPUWriteMemoryFunc *rtl8139_mmio_write[3] = { rtl8139_mmio_writel, }; +static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time) +{ + int64_t next_time = current_time + + muldiv64(1, ticks_per_sec, PCI_FREQUENCY); + if (next_time <= current_time) + next_time = current_time + 1; + return next_time; +} + +#if RTL8139_ONBOARD_TIMER +static void rtl8139_timer(void *opaque) +{ + RTL8139State *s = opaque; + + int is_timeout = 0; + + int64_t curr_time; + uint32_t curr_tick; + + if (!s->clock_enabled) + { + DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n")); + return; + } + + curr_time = qemu_get_clock(vm_clock); + + curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, ticks_per_sec); + + if (s->TimerInt && curr_tick >= s->TimerInt) + { + if (s->TCTR < s->TimerInt || curr_tick < s->TCTR) + { + is_timeout = 1; + } + } + + s->TCTR = curr_tick; + +// DEBUG_PRINT(("RTL8139: >>> timer: tick=%08u\n", s->TCTR)); + + if (is_timeout) + { + DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u\n", s->TCTR)); + s->IntrStatus |= PCSTimeout; + rtl8139_update_irq(s); + } + + qemu_mod_timer(s->timer, + rtl8139_get_next_tctr_time(s,curr_time)); +} +#endif /* RTL8139_ONBOARD_TIMER */ + void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) { PCIRTL8139State *d; @@ -2833,7 +3216,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) pci_conf[0x02] = 0x39; pci_conf[0x03] = 0x81; pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */ - pci_conf[0x08] = 0x10; /* 0x10 */ /* PCI revision ID; >=0x20 is for 8139C+ */ + pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 8139C+ */ pci_conf[0x0a] = 0x00; /* ethernet network controller */ pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; /* header_type */ @@ -2867,9 +3250,21 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) s->macaddr[3], s->macaddr[4], s->macaddr[5]); + + s->cplus_txbuffer = NULL; + s->cplus_txbuffer_len = 0; + s->cplus_txbuffer_offset = 0; /* XXX: instance number ? */ - register_savevm("rtl8139", 0, 1, rtl8139_save, rtl8139_load, s); + register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s); register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load, &d->dev); + +#if RTL8139_ONBOARD_TIMER + s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); + + qemu_mod_timer(s->timer, + rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock))); +#endif /* RTL8139_ONBOARD_TIMER */ } + -- cgit v1.2.3 From e3c2613f918ed1e302ec6c3d3a35bb176e154aa5 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 11:33:00 +0000 Subject: pcnet nic support (Antony T Curtis) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2036 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/pci.c | 2 + hw/pcnet.c | 1771 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 4 + 4 files changed, 1778 insertions(+), 1 deletion(-) create mode 100644 hw/pcnet.c diff --git a/Makefile.target b/Makefile.target index 169ab775a..d60e6b832 100644 --- a/Makefile.target +++ b/Makefile.target @@ -329,7 +329,7 @@ VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o # PCI network cards -VL_OBJS+= ne2000.o rtl8139.o +VL_OBJS+= ne2000.o rtl8139.o pcnet.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support diff --git a/hw/pci.c b/hw/pci.c index ebe606814..f58f6fd60 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -493,6 +493,8 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd) pci_ne2000_init(bus, nd); } else if (strcmp(nd->model, "rtl8139") == 0) { pci_rtl8139_init(bus, nd); + } else if (strcmp(nd->model, "pcnet") == 0) { + pci_pcnet_init(bus, nd); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit (1); diff --git a/hw/pcnet.c b/hw/pcnet.c new file mode 100644 index 000000000..120058162 --- /dev/null +++ b/hw/pcnet.c @@ -0,0 +1,1771 @@ +/* + * QEMU AMD PC-Net II (Am79C970A) emulation + * + * Copyright (c) 2004 Antony T Curtis + * + * 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. + */ + +/* This software was written to be compatible with the specification: + * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet + * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 + */ + +#include "vl.h" + +/* XXX: suppress those headers */ +#include +#include +#include + +//#define PCNET_DEBUG +//#define PCNET_DEBUG_IO +//#define PCNET_DEBUG_BCR +//#define PCNET_DEBUG_CSR +//#define PCNET_DEBUG_RMD +//#define PCNET_DEBUG_TMD +//#define PCNET_DEBUG_MATCH + + +#define PCNET_IOPORT_SIZE 0x20 +#define PCNET_PNPMMIO_SIZE 0x20 + + +typedef struct PCNetState_st PCNetState; + +struct PCNetState_st { + PCIDevice dev; + VLANClientState *vc; + NICInfo *nd; + QEMUTimer *poll_timer; + int mmio_io_addr, rap, isr, lnkst; + target_phys_addr_t rdra, tdra; + uint8_t prom[16]; + uint16_t csr[128]; + uint16_t bcr[32]; + uint64_t timer; + int xmit_pos, recv_pos; + uint8_t buffer[4096]; +}; + +#ifdef __GNUC__ +#define PACKED(A) A __attribute__ ((packed)) +#else +#error FixMe +#endif + +/* BUS CONFIGURATION REGISTERS */ +#define BCR_MSRDA 0 +#define BCR_MSWRA 1 +#define BCR_MC 2 +#define BCR_LNKST 4 +#define BCR_LED1 5 +#define BCR_LED2 6 +#define BCR_LED3 7 +#define BCR_FDC 9 +#define BCR_BSBC 18 +#define BCR_EECAS 19 +#define BCR_SWS 20 +#define BCR_PLAT 22 + +#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) +#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) +#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF) + +#define CSR_INIT(S) !!(((S)->csr[0])&0x0001) +#define CSR_STRT(S) !!(((S)->csr[0])&0x0002) +#define CSR_STOP(S) !!(((S)->csr[0])&0x0004) +#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008) +#define CSR_TXON(S) !!(((S)->csr[0])&0x0010) +#define CSR_RXON(S) !!(((S)->csr[0])&0x0020) +#define CSR_INEA(S) !!(((S)->csr[0])&0x0040) +#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020) +#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040) +#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800) +#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000) +#define CSR_SPND(S) !!(((S)->csr[5])&0x0001) +#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000) +#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000) +#define CSR_DRX(S) !!(((S)->csr[15])&0x0001) +#define CSR_DTX(S) !!(((S)->csr[15])&0x0002) +#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) +#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) +#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) +#define CSR_PROM(S) !!(((S)->csr[15])&0x8000) + +#define CSR_CRBC(S) ((S)->csr[40]) +#define CSR_CRST(S) ((S)->csr[41]) +#define CSR_CXBC(S) ((S)->csr[42]) +#define CSR_CXST(S) ((S)->csr[43]) +#define CSR_NRBC(S) ((S)->csr[44]) +#define CSR_NRST(S) ((S)->csr[45]) +#define CSR_POLL(S) ((S)->csr[46]) +#define CSR_PINT(S) ((S)->csr[47]) +#define CSR_RCVRC(S) ((S)->csr[72]) +#define CSR_XMTRC(S) ((S)->csr[74]) +#define CSR_RCVRL(S) ((S)->csr[76]) +#define CSR_XMTRL(S) ((S)->csr[78]) +#define CSR_MISSC(S) ((S)->csr[112]) + +#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16)) +#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16)) +#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16)) +#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16)) +#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16)) +#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16)) +#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) +#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16)) +#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16)) +#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16)) +#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16)) +#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16)) +#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16)) +#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16)) + +#define PHYSADDR(S,A) \ + (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16)) + +struct pcnet_initblk16 { + uint16_t mode; + uint16_t padr1; + uint16_t padr2; + uint16_t padr3; + uint16_t ladrf1; + uint16_t ladrf2; + uint16_t ladrf3; + uint16_t ladrf4; + unsigned PACKED(rdra:24); + unsigned PACKED(res1:5); + unsigned PACKED(rlen:3); + unsigned PACKED(tdra:24); + unsigned PACKED(res2:5); + unsigned PACKED(tlen:3); +}; + +struct pcnet_initblk32 { + uint16_t mode; + unsigned PACKED(res1:4); + unsigned PACKED(rlen:4); + unsigned PACKED(res2:4); + unsigned PACKED(tlen:4); + uint16_t padr1; + uint16_t padr2; + uint16_t padr3; + uint16_t _res; + uint16_t ladrf1; + uint16_t ladrf2; + uint16_t ladrf3; + uint16_t ladrf4; + uint32_t rdra; + uint32_t tdra; +}; + +struct pcnet_TMD { + struct { + unsigned tbadr:32; + } tmd0; + struct { + unsigned PACKED(bcnt:12), PACKED(ones:4), PACKED(res:7), PACKED(bpe:1); + unsigned PACKED(enp:1), PACKED(stp:1), PACKED(def:1), PACKED(one:1); + unsigned PACKED(ltint:1), PACKED(nofcs:1), PACKED(err:1), PACKED(own:1); + } tmd1; + struct { + unsigned PACKED(trc:4), PACKED(res:12); + unsigned PACKED(tdr:10), PACKED(rtry:1), PACKED(lcar:1); + unsigned PACKED(lcol:1), PACKED(exdef:1), PACKED(uflo:1), PACKED(buff:1); + } tmd2; + struct { + unsigned res:32; + } tmd3; +}; + +struct pcnet_RMD { + struct { + unsigned rbadr:32; + } rmd0; + struct { + unsigned PACKED(bcnt:12), PACKED(ones:4), PACKED(res:4); + unsigned PACKED(bam:1), PACKED(lafm:1), PACKED(pam:1), PACKED(bpe:1); + unsigned PACKED(enp:1), PACKED(stp:1), PACKED(buff:1), PACKED(crc:1); + unsigned PACKED(oflo:1), PACKED(fram:1), PACKED(err:1), PACKED(own:1); + } rmd1; + struct { + unsigned PACKED(mcnt:12), PACKED(zeros:4); + unsigned PACKED(rpc:8), PACKED(rcc:8); + } rmd2; + struct { + unsigned res:32; + } rmd3; +}; + + +#define PRINT_TMD(T) printf( \ + "TMD0 : TBADR=0x%08x\n" \ + "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \ + "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \ + " BPE=%d, BCNT=%d\n" \ + "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \ + "LCA=%d, RTR=%d,\n" \ + " TDR=%d, TRC=%d\n", \ + (T)->tmd0.tbadr, \ + (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \ + (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \ + (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \ + 4096-(T)->tmd1.bcnt, \ + (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\ + (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \ + (T)->tmd2.tdr, (T)->tmd2.trc) + +#define PRINT_RMD(R) printf( \ + "RMD0 : RBADR=0x%08x\n" \ + "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \ + "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \ + "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ + "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \ + (R)->rmd0.rbadr, \ + (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \ + (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \ + (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \ + (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \ + (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \ + (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \ + (R)->rmd2.zeros) + +static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) +{ + if (!BCR_SWSTYLE(s)) { + uint16_t xda[4]; + cpu_physical_memory_read(addr, + (void *)&xda[0], sizeof(xda)); + ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | + ((xda[1]&0x00ff) << 16); + ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| + ((xda[1] & 0xff00) << 16); + ((uint32_t *)tmd)[2] = + (xda[3] & 0xffff) << 16; + ((uint32_t *)tmd)[3] = 0; + } + else + if (BCR_SWSTYLE(s) != 3) + cpu_physical_memory_read(addr, (void *)tmd, 16); + else { + uint32_t xda[4]; + cpu_physical_memory_read(addr, + (void *)&xda[0], sizeof(xda)); + ((uint32_t *)tmd)[0] = xda[2]; + ((uint32_t *)tmd)[1] = xda[1]; + ((uint32_t *)tmd)[2] = xda[0]; + ((uint32_t *)tmd)[3] = xda[3]; + } +} + +static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) +{ + if (!BCR_SWSTYLE(s)) { + uint16_t xda[4]; + xda[0] = ((uint32_t *)tmd)[0] & 0xffff; + xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | + ((((uint32_t *)tmd)[1]>>16)&0xff00); + xda[2] = ((uint32_t *)tmd)[1] & 0xffff; + xda[3] = ((uint32_t *)tmd)[2] >> 16; + cpu_physical_memory_write(addr, + (void *)&xda[0], sizeof(xda)); + } + else { + if (BCR_SWSTYLE(s) != 3) + cpu_physical_memory_write(addr, (void *)tmd, 16); + else { + uint32_t xda[4]; + xda[0] = ((uint32_t *)tmd)[2]; + xda[1] = ((uint32_t *)tmd)[1]; + xda[2] = ((uint32_t *)tmd)[0]; + xda[3] = ((uint32_t *)tmd)[3]; + cpu_physical_memory_write(addr, + (void *)&xda[0], sizeof(xda)); + } + } +} + +static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) +{ + if (!BCR_SWSTYLE(s)) { + uint16_t rda[4]; + cpu_physical_memory_read(addr, + (void *)&rda[0], sizeof(rda)); + ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| + ((rda[1] & 0x00ff) << 16); + ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| + ((rda[1] & 0xff00) << 16); + ((uint32_t *)rmd)[2] = rda[3] & 0xffff; + ((uint32_t *)rmd)[3] = 0; + } + else + if (BCR_SWSTYLE(s) != 3) + cpu_physical_memory_read(addr, (void *)rmd, 16); + else { + uint32_t rda[4]; + cpu_physical_memory_read(addr, + (void *)&rda[0], sizeof(rda)); + ((uint32_t *)rmd)[0] = rda[2]; + ((uint32_t *)rmd)[1] = rda[1]; + ((uint32_t *)rmd)[2] = rda[0]; + ((uint32_t *)rmd)[3] = rda[3]; + } +} + +static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) +{ + if (!BCR_SWSTYLE(s)) { + uint16_t rda[4]; \ + rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \ + rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\ + ((((uint32_t *)rmd)[1]>>16)&0xff00);\ + rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \ + rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \ + cpu_physical_memory_write(addr, \ + (void *)&rda[0], sizeof(rda)); \ + } + else { + if (BCR_SWSTYLE(s) != 3) + cpu_physical_memory_write(addr, (void *)rmd, 16); + else { + uint32_t rda[4]; + rda[0] = ((uint32_t *)rmd)[2]; + rda[1] = ((uint32_t *)rmd)[1]; + rda[2] = ((uint32_t *)rmd)[0]; + rda[3] = ((uint32_t *)rmd)[3]; + cpu_physical_memory_write(addr, + (void *)&rda[0], sizeof(rda)); + } + } +} + + +#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR) + +#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR) + +#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR) + +#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR) + +#if 1 + +#define CHECK_RMD(ADDR,RES) do { \ + struct pcnet_RMD rmd; \ + RMDLOAD(&rmd,(ADDR)); \ + (RES) |= (rmd.rmd1.ones != 15) \ + || (rmd.rmd2.zeros != 0); \ +} while (0) + +#define CHECK_TMD(ADDR,RES) do { \ + struct pcnet_TMD tmd; \ + TMDLOAD(&tmd,(ADDR)); \ + (RES) |= (tmd.tmd1.ones != 15); \ +} while (0) + +#else + +#define CHECK_RMD(ADDR,RES) do { \ + switch (BCR_SWSTYLE(s)) { \ + case 0x00: \ + do { \ + uint16_t rda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&rda[0], sizeof(rda)); \ + (RES) |= (rda[2] & 0xf000)!=0xf000; \ + (RES) |= (rda[3] & 0xf000)!=0x0000; \ + } while (0); \ + break; \ + case 0x01: \ + case 0x02: \ + do { \ + uint32_t rda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&rda[0], sizeof(rda)); \ + (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ + (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ + } while (0); \ + break; \ + case 0x03: \ + do { \ + uint32_t rda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&rda[0], sizeof(rda)); \ + (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ + (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ + } while (0); \ + break; \ + } \ +} while (0) + +#define CHECK_TMD(ADDR,RES) do { \ + switch (BCR_SWSTYLE(s)) { \ + case 0x00: \ + do { \ + uint16_t xda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&xda[0], sizeof(xda)); \ + (RES) |= (xda[2] & 0xf000)!=0xf000;\ + } while (0); \ + break; \ + case 0x01: \ + case 0x02: \ + case 0x03: \ + do { \ + uint32_t xda[4]; \ + cpu_physical_memory_read((ADDR), \ + (void *)&xda[0], sizeof(xda)); \ + (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ + } while (0); \ + break; \ + } \ +} while (0) + +#endif + +#define PRINT_PKTHDR(BUF) do { \ + struct ether_header *hdr = (void *)(BUF); \ + printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ + "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ + "type=0x%04x (bcast=%d)\n", \ + hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \ + hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ + hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ + hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ + htons(hdr->ether_type), \ + !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \ +} while (0) + +#define MULTICAST_FILTER_LEN 8 + +static inline uint32_t lnc_mchash(const uint8_t *ether_addr) +{ +#define LNC_POLYNOMIAL 0xEDB88320UL + uint32_t crc = 0xFFFFFFFF; + int idx, bit; + uint8_t data; + + for (idx = 0; idx < ETHER_ADDR_LEN; idx++) { + for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) { + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); + data >>= 1; + } + } + return crc; +#undef LNC_POLYNOMIAL +} + +#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) + +/* generated using the AUTODIN II polynomial + * x^32 + x^26 + x^23 + x^22 + x^16 + + * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 + */ +static const uint32_t crctab[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) +{ + struct ether_header *hdr = (void *)buf; + uint8_t padr[6] = { + s->csr[12] & 0xff, s->csr[12] >> 8, + s->csr[13] & 0xff, s->csr[13] >> 8, + s->csr[14] & 0xff, s->csr[14] >> 8 + }; + int result = (!CSR_DRCVPA(s)) && !bcmp(hdr->ether_dhost, padr, 6); +#ifdef PCNET_DEBUG_MATCH + printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " + "padr=%02x:%02x:%02x:%02x:%02x:%02x\n", + hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], + hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], + padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]); + printf("padr_match result=%d\n", result); +#endif + return result; +} + +static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) +{ + static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct ether_header *hdr = (void *)buf; + int result = !CSR_DRCVBC(s) && !bcmp(hdr->ether_dhost, BCAST, 6); +#ifdef PCNET_DEBUG_MATCH + printf("padr_bcast result=%d\n", result); +#endif + return result; +} + +static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) +{ + struct ether_header *hdr = (void *)buf; + if ((*(hdr->ether_dhost)&0x01) && + ((uint64_t *)&s->csr[8])[0] != 0LL) { + uint8_t ladr[8] = { + s->csr[8] & 0xff, s->csr[8] >> 8, + s->csr[9] & 0xff, s->csr[9] >> 8, + s->csr[10] & 0xff, s->csr[10] >> 8, + s->csr[11] & 0xff, s->csr[11] >> 8 + }; + int index = lnc_mchash(hdr->ether_dhost) >> 26; + return !!(ladr[index >> 3] & (1 << (index & 7))); + } + return 0; +} + +static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) +{ + while (idx < 1) idx += CSR_RCVRL(s); + return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8)); +} + +static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time) +{ + int64_t next_time = current_time + + muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), + ticks_per_sec, 33000000L); + if (next_time <= current_time) + next_time = current_time + 1; + return next_time; +} + +static void pcnet_poll(PCNetState *s); +static void pcnet_poll_timer(void *opaque); + +static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap); +static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value); +static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val); +static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); + +static void pcnet_s_reset(PCNetState *s) +{ +#ifdef PCNET_DEBUG + printf("pcnet_s_reset\n"); +#endif + + s->lnkst = 0x40; + s->rdra = 0; + s->tdra = 0; + s->rap = 0; + + s->bcr[BCR_BSBC] &= ~0x0080; + + s->csr[0] = 0x0004; + s->csr[3] = 0x0000; + s->csr[4] = 0x0115; + s->csr[5] = 0x0000; + s->csr[6] = 0x0000; + s->csr[8] = 0; + s->csr[9] = 0; + s->csr[10] = 0; + s->csr[11] = 0; + s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]); + s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]); + s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]); + s->csr[15] &= 0x21c4; + s->csr[72] = 1; + s->csr[74] = 1; + s->csr[76] = 1; + s->csr[78] = 1; + s->csr[80] = 0x1410; + s->csr[88] = 0x1003; + s->csr[89] = 0x0262; + s->csr[94] = 0x0000; + s->csr[100] = 0x0200; + s->csr[103] = 0x0105; + s->csr[103] = 0x0105; + s->csr[112] = 0x0000; + s->csr[114] = 0x0000; + s->csr[122] = 0x0000; + s->csr[124] = 0x0000; +} + +static void pcnet_update_irq(PCNetState *s) +{ + int isr = 0; + s->csr[0] &= ~0x0080; + +#if 1 + if (((s->csr[0] & ~s->csr[3]) & 0x5f00) || + (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) || + (((s->csr[5]>>1) & s->csr[5]) & 0x0048)) +#else + if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ || + (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ || + (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ || + (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ || + (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ || + (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ || + (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ || + (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ || + (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ || + (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ || + (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ || + (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */) +#endif + { + + isr = CSR_INEA(s); + s->csr[0] |= 0x0080; + } + + if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */ + s->csr[4] &= ~0x0080; + s->csr[4] |= 0x0040; + s->csr[0] |= 0x0080; + isr = 1; +#ifdef PCNET_DEBUG + printf("pcnet user int\n"); +#endif + } + +#if 1 + if (((s->csr[5]>>1) & s->csr[5]) & 0x0500) +#else + if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ || + (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ ) +#endif + { + isr = 1; + s->csr[0] |= 0x0080; + } + + if (isr != s->isr) { +#ifdef PCNET_DEBUG + printf("pcnet: INTA=%d\n", isr); +#endif + } + pci_set_irq(&s->dev, 0, isr); + s->isr = isr; +} + +static void pcnet_init(PCNetState *s) +{ +#ifdef PCNET_DEBUG + printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); +#endif + +#define PCNET_INIT() do { \ + cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \ + (uint8_t *)&initblk, sizeof(initblk)); \ + s->csr[15] = le16_to_cpu(initblk.mode); \ + CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \ + CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \ + s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \ + s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \ + s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \ + s->csr[10] = le16_to_cpu(initblk.ladrf3); \ + s->csr[11] = le16_to_cpu(initblk.ladrf4); \ + s->csr[12] = le16_to_cpu(initblk.padr1); \ + s->csr[13] = le16_to_cpu(initblk.padr2); \ + s->csr[14] = le16_to_cpu(initblk.padr3); \ + s->rdra = PHYSADDR(s,initblk.rdra); \ + s->tdra = PHYSADDR(s,initblk.tdra); \ +} while (0) + + if (BCR_SSIZE32(s)) { + struct pcnet_initblk32 initblk; + PCNET_INIT(); +#ifdef PCNET_DEBUG + printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", + initblk.rlen, initblk.tlen); +#endif + } else { + struct pcnet_initblk16 initblk; + PCNET_INIT(); +#ifdef PCNET_DEBUG + printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", + initblk.rlen, initblk.tlen); +#endif + } + +#undef PCNET_INIT + + CSR_RCVRC(s) = CSR_RCVRL(s); + CSR_XMTRC(s) = CSR_XMTRL(s); + +#ifdef PCNET_DEBUG + printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", + BCR_SSIZE32(s), + s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s)); +#endif + + s->csr[0] |= 0x0101; + s->csr[0] &= ~0x0004; /* clear STOP bit */ +} + +static void pcnet_start(PCNetState *s) +{ +#ifdef PCNET_DEBUG + printf("pcnet_start\n"); +#endif + + if (!CSR_DTX(s)) + s->csr[0] |= 0x0010; /* set TXON */ + + if (!CSR_DRX(s)) + s->csr[0] |= 0x0020; /* set RXON */ + + s->csr[0] &= ~0x0004; /* clear STOP bit */ + s->csr[0] |= 0x0002; +} + +static void pcnet_stop(PCNetState *s) +{ +#ifdef PCNET_DEBUG + printf("pcnet_stop\n"); +#endif + s->csr[0] &= ~0x7feb; + s->csr[0] |= 0x0014; + s->csr[4] &= ~0x02c2; + s->csr[5] &= ~0x0011; + pcnet_poll_timer(s); +} + +static void pcnet_rdte_poll(PCNetState *s) +{ + s->csr[28] = s->csr[29] = 0; + if (s->rdra) { + int bad = 0; +#if 1 + target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); + target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); + target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); +#else + target_phys_addr_t crda = s->rdra + + (CSR_RCVRL(s) - CSR_RCVRC(s)) * + (BCR_SWSTYLE(s) ? 16 : 8 ); + int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; + target_phys_addr_t nrda = s->rdra + + (CSR_RCVRL(s) - nrdc) * + (BCR_SWSTYLE(s) ? 16 : 8 ); + int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; + target_phys_addr_t nnrd = s->rdra + + (CSR_RCVRL(s) - nnrc) * + (BCR_SWSTYLE(s) ? 16 : 8 ); +#endif + + CHECK_RMD(PHYSADDR(s,crda), bad); + if (!bad) { + CHECK_RMD(PHYSADDR(s,nrda), bad); + if (bad || (nrda == crda)) nrda = 0; + CHECK_RMD(PHYSADDR(s,nnrd), bad); + if (bad || (nnrd == crda)) nnrd = 0; + + s->csr[28] = crda & 0xffff; + s->csr[29] = crda >> 16; + s->csr[26] = nrda & 0xffff; + s->csr[27] = nrda >> 16; + s->csr[36] = nnrd & 0xffff; + s->csr[37] = nnrd >> 16; +#ifdef PCNET_DEBUG + if (bad) { + printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n", + PHYSADDR(s,crda)); + } + } else { + printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda)); +#endif + } + } + + if (CSR_CRDA(s)) { + struct pcnet_RMD rmd; + RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); + CSR_CRBC(s) = rmd.rmd1.bcnt; + CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16; +#ifdef PCNET_DEBUG_RMD_X + printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n", + PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), + ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]); + PRINT_RMD(&rmd); +#endif + } else { + CSR_CRBC(s) = CSR_CRST(s) = 0; + } + + if (CSR_NRDA(s)) { + struct pcnet_RMD rmd; + RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); + CSR_NRBC(s) = rmd.rmd1.bcnt; + CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16; + } else { + CSR_NRBC(s) = CSR_NRST(s) = 0; + } + +} + +static int pcnet_tdte_poll(PCNetState *s) +{ + s->csr[34] = s->csr[35] = 0; + if (s->tdra) { + target_phys_addr_t cxda = s->tdra + + (CSR_XMTRL(s) - CSR_XMTRC(s)) * + (BCR_SWSTYLE(s) ? 16 : 8 ); + int bad = 0; + CHECK_TMD(PHYSADDR(s, cxda),bad); + if (!bad) { + if (CSR_CXDA(s) != cxda) { + s->csr[60] = s->csr[34]; + s->csr[61] = s->csr[35]; + s->csr[62] = CSR_CXBC(s); + s->csr[63] = CSR_CXST(s); + } + s->csr[34] = cxda & 0xffff; + s->csr[35] = cxda >> 16; +#ifdef PCNET_DEBUG + } else { + printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda)); +#endif + } + } + + if (CSR_CXDA(s)) { + struct pcnet_TMD tmd; + + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); + + CSR_CXBC(s) = tmd.tmd1.bcnt; + CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16; + } else { + CSR_CXBC(s) = CSR_CXST(s) = 0; + } + + return !!(CSR_CXST(s) & 0x8000); +} + +static int pcnet_can_receive(void *opaque) +{ + PCNetState *s = opaque; + if (CSR_STOP(s) || CSR_SPND(s)) + return 0; + + if (s->recv_pos > 0) + return 0; + + return sizeof(s->buffer)-16; +} + +#define MIN_BUF_SIZE 60 + +static void pcnet_receive(void *opaque, const uint8_t *buf, int size) +{ + PCNetState *s = opaque; + int is_padr = 0, is_bcast = 0, is_ladr = 0; + uint8_t buf1[60]; + + if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) + return; + +#ifdef PCNET_DEBUG + printf("pcnet_receive size=%d\n", size); +#endif + + /* if too small buffer, then expand it */ + if (size < MIN_BUF_SIZE) { + memcpy(buf1, buf, size); + memset(buf1 + size, 0, MIN_BUF_SIZE - size); + buf = buf1; + size = MIN_BUF_SIZE; + } + + if (CSR_PROM(s) + || (is_padr=padr_match(s, buf, size)) + || (is_bcast=padr_bcast(s, buf, size)) + || (is_ladr=ladr_match(s, buf, size))) { + + pcnet_rdte_poll(s); + + if (!(CSR_CRST(s) & 0x8000) && s->rdra) { + struct pcnet_RMD rmd; + int rcvrc = CSR_RCVRC(s)-1,i; + target_phys_addr_t nrda; + for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { + if (rcvrc <= 1) + rcvrc = CSR_RCVRL(s); + nrda = s->rdra + + (CSR_RCVRL(s) - rcvrc) * + (BCR_SWSTYLE(s) ? 16 : 8 ); + RMDLOAD(&rmd, PHYSADDR(s,nrda)); + if (rmd.rmd1.own) { +#ifdef PCNET_DEBUG_RMD + printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", + rcvrc, CSR_RCVRC(s)); +#endif + CSR_RCVRC(s) = rcvrc; + pcnet_rdte_poll(s); + break; + } + } + } + + if (!(CSR_CRST(s) & 0x8000)) { +#ifdef PCNET_DEBUG_RMD + printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s)); +#endif + s->csr[0] |= 0x1000; /* Set MISS flag */ + CSR_MISSC(s)++; + } else { + uint8_t *src = &s->buffer[8]; + target_phys_addr_t crda = CSR_CRDA(s); + struct pcnet_RMD rmd; + int pktcount = 0; + + memcpy(src, buf, size); + + /* XXX: avoid CRC generation */ + if (!CSR_ASTRP_RCV(s)) { + uint32_t fcs = ~0; +#if 0 + uint8_t *p = s->buffer; + + ((uint32_t *)p)[0] = ((uint32_t *)p)[1] = 0xaaaaaaaa; + p[7] = 0xab; +#else + uint8_t *p = src; +#endif + + while (size < 46) { + src[size++] = 0; + } + + while (p != &src[size]) { + CRC(fcs, *p++); + } + ((uint32_t *)&src[size])[0] = htonl(fcs); + size += 4; /* FCS at end of packet */ + } else size += 4; + +#ifdef PCNET_DEBUG_MATCH + PRINT_PKTHDR(buf); +#endif + + RMDLOAD(&rmd, PHYSADDR(s,crda)); + /*if (!CSR_LAPPEN(s))*/ + rmd.rmd1.stp = 1; + +#define PCNET_RECV_STORE() do { \ + int count = MIN(4096 - rmd.rmd1.bcnt,size); \ + target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ + cpu_physical_memory_write(rbadr, src, count); \ + src += count; size -= count; \ + rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ + RMDSTORE(&rmd, PHYSADDR(s,crda)); \ + pktcount++; \ +} while (0) + + PCNET_RECV_STORE(); + if ((size > 0) && CSR_NRDA(s)) { + target_phys_addr_t nrda = CSR_NRDA(s); + RMDLOAD(&rmd, PHYSADDR(s,nrda)); + if (rmd.rmd1.own) { + crda = nrda; + PCNET_RECV_STORE(); + if ((size > 0) && (nrda=CSR_NNRD(s))) { + RMDLOAD(&rmd, PHYSADDR(s,nrda)); + if (rmd.rmd1.own) { + crda = nrda; + PCNET_RECV_STORE(); + } + } + } + } + +#undef PCNET_RECV_STORE + + RMDLOAD(&rmd, PHYSADDR(s,crda)); + if (size == 0) { + rmd.rmd1.enp = 1; + rmd.rmd1.pam = !CSR_PROM(s) && is_padr; + rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; + rmd.rmd1.bam = !CSR_PROM(s) && is_bcast; + } else { + rmd.rmd1.oflo = 1; + rmd.rmd1.buff = 1; + rmd.rmd1.err = 1; + } + RMDSTORE(&rmd, PHYSADDR(s,crda)); + s->csr[0] |= 0x0400; + +#ifdef PCNET_DEBUG + printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", + CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount); +#endif +#ifdef PCNET_DEBUG_RMD + PRINT_RMD(&rmd); +#endif + + while (pktcount--) { + if (CSR_RCVRC(s) <= 1) + CSR_RCVRC(s) = CSR_RCVRL(s); + else + CSR_RCVRC(s)--; + } + + pcnet_rdte_poll(s); + + } + } + + pcnet_poll(s); + pcnet_update_irq(s); +} + +static void pcnet_transmit(PCNetState *s) +{ + target_phys_addr_t xmit_cxda = 0; + int count = CSR_XMTRL(s)-1; + s->xmit_pos = -1; + + if (!CSR_TXON(s)) { + s->csr[0] &= ~0x0008; + return; + } + + txagain: + if (pcnet_tdte_poll(s)) { + struct pcnet_TMD tmd; + + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); + +#ifdef PCNET_DEBUG_TMD + printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); + PRINT_TMD(&tmd); +#endif + if (tmd.tmd1.stp) { + s->xmit_pos = 0; + if (!tmd.tmd1.enp) { + cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), + s->buffer, 4096 - tmd.tmd1.bcnt); + s->xmit_pos += 4096 - tmd.tmd1.bcnt; + } + xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); + } + if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { + cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), + s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); + s->xmit_pos += 4096 - tmd.tmd1.bcnt; +#ifdef PCNET_DEBUG + printf("pcnet_transmit size=%d\n", s->xmit_pos); +#endif + if (CSR_LOOP(s)) + pcnet_receive(s, s->buffer, s->xmit_pos); + else + qemu_send_packet(s->vc, s->buffer, s->xmit_pos); + + s->csr[0] &= ~0x0008; /* clear TDMD */ + s->csr[4] |= 0x0004; /* set TXSTRT */ + s->xmit_pos = -1; + } + + tmd.tmd1.own = 0; + TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); + if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) + s->csr[0] |= 0x0200; /* set TINT */ + + if (CSR_XMTRC(s)<=1) + CSR_XMTRC(s) = CSR_XMTRL(s); + else + CSR_XMTRC(s)--; + if (count--) + goto txagain; + + } else + if (s->xmit_pos >= 0) { + struct pcnet_TMD tmd; + TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); + tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; + tmd.tmd1.own = 0; + TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); + s->csr[0] |= 0x0200; /* set TINT */ + if (!CSR_DXSUFLO(s)) { + s->csr[0] &= ~0x0010; + } else + if (count--) + goto txagain; + } +} + +static void pcnet_poll(PCNetState *s) +{ + if (CSR_RXON(s)) { + pcnet_rdte_poll(s); + } + + if (CSR_TDMD(s) || + (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) + pcnet_transmit(s); +} + +static void pcnet_poll_timer(void *opaque) +{ + PCNetState *s = opaque; + + qemu_del_timer(s->poll_timer); + + if (CSR_TDMD(s)) { + pcnet_transmit(s); + } + + pcnet_update_irq(s); + + if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { + uint64_t now = qemu_get_clock(vm_clock) * 33; + if (!s->timer || !now) + s->timer = now; + else { + uint64_t t = now - s->timer + CSR_POLL(s); + if (t > 0xffffLL) { + pcnet_poll(s); + CSR_POLL(s) = CSR_PINT(s); + } else + CSR_POLL(s) = t; + } + qemu_mod_timer(s->poll_timer, + pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock))); + } +} + + +static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value) +{ + uint16_t val = new_value; +#ifdef PCNET_DEBUG_CSR + printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val); +#endif + switch (rap) { + case 0: + s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */ + + s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048); + + val = (val & 0x007f) | (s->csr[0] & 0x7f00); + + /* IFF STOP, STRT and INIT are set, clear STRT and INIT */ + if ((val&7) == 7) + val &= ~3; + + if (!CSR_STOP(s) && (val & 4)) + pcnet_stop(s); + + if (!CSR_INIT(s) && (val & 1)) + pcnet_init(s); + + if (!CSR_STRT(s) && (val & 2)) + pcnet_start(s); + + if (CSR_TDMD(s)) + pcnet_transmit(s); + + return; + case 1: + case 2: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 18: /* CRBAL */ + case 19: /* CRBAU */ + case 20: /* CXBAL */ + case 21: /* CXBAU */ + case 22: /* NRBAU */ + case 23: /* NRBAU */ + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: /* CRBC */ + case 41: + case 42: /* CXBC */ + case 43: + case 44: + case 45: + case 46: /* POLL */ + case 47: /* POLLINT */ + case 72: + case 74: + case 76: /* RCVRL */ + case 78: /* XMTRL */ + case 112: + if (CSR_STOP(s) || CSR_SPND(s)) + break; + return; + case 3: + break; + case 4: + s->csr[4] &= ~(val & 0x026a); + val &= ~0x026a; val |= s->csr[4] & 0x026a; + break; + case 5: + s->csr[5] &= ~(val & 0x0a90); + val &= ~0x0a90; val |= s->csr[5] & 0x0a90; + break; + case 16: + pcnet_csr_writew(s,1,val); + return; + case 17: + pcnet_csr_writew(s,2,val); + return; + case 58: + pcnet_bcr_writew(s,BCR_SWS,val); + break; + default: + return; + } + s->csr[rap] = val; +} + +static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap) +{ + uint32_t val; + switch (rap) { + case 0: + pcnet_update_irq(s); + val = s->csr[0]; + val |= (val & 0x7800) ? 0x8000 : 0; + break; + case 16: + return pcnet_csr_readw(s,1); + case 17: + return pcnet_csr_readw(s,2); + case 58: + return pcnet_bcr_readw(s,BCR_SWS); + case 88: + val = s->csr[89]; + val <<= 16; + val |= s->csr[88]; + break; + default: + val = s->csr[rap]; + } +#ifdef PCNET_DEBUG_CSR + printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val); +#endif + return val; +} + +static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val) +{ + rap &= 127; +#ifdef PCNET_DEBUG_BCR + printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val); +#endif + switch (rap) { + case BCR_SWS: + if (!(CSR_STOP(s) || CSR_SPND(s))) + return; + val &= ~0x0300; + switch (val & 0x00ff) { + case 0: + val |= 0x0200; + break; + case 1: + val |= 0x0100; + break; + case 2: + case 3: + val |= 0x0300; + break; + default: + printf("Bad SWSTYLE=0x%02x\n", val & 0xff); + val = 0x0200; + break; + } +#ifdef PCNET_DEBUG + printf("BCR_SWS=0x%04x\n", val); +#endif + case BCR_LNKST: + case BCR_LED1: + case BCR_LED2: + case BCR_LED3: + case BCR_MC: + case BCR_FDC: + case BCR_BSBC: + case BCR_EECAS: + case BCR_PLAT: + s->bcr[rap] = val; + break; + default: + break; + } +} + +static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) +{ + uint32_t val; + rap &= 127; + switch (rap) { + case BCR_LNKST: + case BCR_LED1: + case BCR_LED2: + case BCR_LED3: + val = s->bcr[rap] & ~0x8000; + val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0; + break; + default: + val = rap < 32 ? s->bcr[rap] : 0; + break; + } +#ifdef PCNET_DEBUG_BCR + printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val); +#endif + return val; +} + +static void pcnet_h_reset(PCNetState *s) +{ + int i; + uint16_t checksum; + + /* Initialize the PROM */ + + memcpy(s->prom, s->nd->macaddr, 6); + s->prom[12] = s->prom[13] = 0x00; + s->prom[14] = s->prom[15] = 0x57; + + for (i = 0,checksum = 0; i < 16; i++) + checksum += s->prom[i]; + *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); + + + s->bcr[BCR_MSRDA] = 0x0005; + s->bcr[BCR_MSWRA] = 0x0005; + s->bcr[BCR_MC ] = 0x0002; + s->bcr[BCR_LNKST] = 0x00c0; + s->bcr[BCR_LED1 ] = 0x0084; + s->bcr[BCR_LED2 ] = 0x0088; + s->bcr[BCR_LED3 ] = 0x0090; + s->bcr[BCR_FDC ] = 0x0000; + s->bcr[BCR_BSBC ] = 0x9001; + s->bcr[BCR_EECAS] = 0x0002; + s->bcr[BCR_SWS ] = 0x0200; + s->bcr[BCR_PLAT ] = 0xff06; + + pcnet_s_reset(s); +} + +static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PCNetState *s = opaque; +#ifdef PCNET_DEBUG + printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); +#endif + /* Check APROMWE bit to enable write access */ + if (pcnet_bcr_readw(s,2) & 0x80) + s->prom[addr & 15] = val; +} + +static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) +{ + PCNetState *s = opaque; + uint32_t val = s->prom[addr &= 15]; +#ifdef PCNET_DEBUG + printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); +#endif + return val; +} + +static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +{ + PCNetState *s = opaque; + pcnet_poll_timer(s); +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val); +#endif + if (!BCR_DWIO(s)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + pcnet_csr_writew(s, s->rap, val); + break; + case 0x02: + s->rap = val & 0x7f; + break; + case 0x06: + pcnet_bcr_writew(s, s->rap, val); + break; + } + } + pcnet_update_irq(s); +} + +static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) +{ + PCNetState *s = opaque; + uint32_t val = -1; + pcnet_poll_timer(s); + if (!BCR_DWIO(s)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + val = pcnet_csr_readw(s, s->rap); + break; + case 0x02: + val = s->rap; + break; + case 0x04: + pcnet_s_reset(s); + val = 0; + break; + case 0x06: + val = pcnet_bcr_readw(s, s->rap); + break; + } + } + pcnet_update_irq(s); +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff); +#endif + return val; +} + +static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +{ + PCNetState *s = opaque; + pcnet_poll_timer(s); +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val); +#endif + if (BCR_DWIO(s)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + pcnet_csr_writew(s, s->rap, val & 0xffff); + break; + case 0x04: + s->rap = val & 0x7f; + break; + case 0x0c: + pcnet_bcr_writew(s, s->rap, val & 0xffff); + break; + } + } else + if ((addr & 0x0f) == 0) { + /* switch device to dword i/o mode */ + pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080); +#ifdef PCNET_DEBUG_IO + printf("device switched into dword i/o mode\n"); +#endif + } + pcnet_update_irq(s); +} + +static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) +{ + PCNetState *s = opaque; + uint32_t val = -1; + pcnet_poll_timer(s); + if (BCR_DWIO(s)) { + switch (addr & 0x0f) { + case 0x00: /* RDP */ + val = pcnet_csr_readw(s, s->rap); + break; + case 0x04: + val = s->rap; + break; + case 0x08: + pcnet_s_reset(s); + val = 0; + break; + case 0x0c: + val = pcnet_bcr_readw(s, s->rap); + break; + } + } + pcnet_update_irq(s); +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val); +#endif + return val; +} + +static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCNetState *d = (PCNetState *)pci_dev; + +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size); +#endif + + register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); + register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); + + register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); + register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); + register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); + register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); +} + +static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val); +#endif + if (!(addr & 0x10)) + pcnet_aprom_writeb(d, addr & 0x0f, val); +} + +static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val = -1; + if (!(addr & 0x10)) + val = pcnet_aprom_readb(d, addr & 0x0f); +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff); +#endif + return val; +} + +static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val); +#endif + if (addr & 0x10) + pcnet_ioport_writew(d, addr & 0x0f, val); + else { + addr &= 0x0f; + pcnet_aprom_writeb(d, addr, val & 0xff); + pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); + } +} + +static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val = -1; + if (addr & 0x10) + val = pcnet_ioport_readw(d, addr & 0x0f); + else { + addr &= 0x0f; + val = pcnet_aprom_readb(d, addr+1); + val <<= 8; + val |= pcnet_aprom_readb(d, addr); + } +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff); +#endif + return val; +} + +static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val); +#endif + if (addr & 0x10) + pcnet_ioport_writel(d, addr & 0x0f, val); + else { + addr &= 0x0f; + pcnet_aprom_writeb(d, addr, val & 0xff); + pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); + pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); + pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); + } +} + +static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val; + if (addr & 0x10) + val = pcnet_ioport_readl(d, addr & 0x0f); + else { + addr &= 0x0f; + val = pcnet_aprom_readb(d, addr+3); + val <<= 8; + val |= pcnet_aprom_readb(d, addr+2); + val <<= 8; + val |= pcnet_aprom_readb(d, addr+1); + val <<= 8; + val |= pcnet_aprom_readb(d, addr); + } +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val); +#endif + return val; +} + + +static CPUWriteMemoryFunc *pcnet_mmio_write[] = { + (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, + (CPUWriteMemoryFunc *)&pcnet_mmio_writew, + (CPUWriteMemoryFunc *)&pcnet_mmio_writel +}; + +static CPUReadMemoryFunc *pcnet_mmio_read[] = { + (CPUReadMemoryFunc *)&pcnet_mmio_readb, + (CPUReadMemoryFunc *)&pcnet_mmio_readw, + (CPUReadMemoryFunc *)&pcnet_mmio_readl +}; + +static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCNetState *d = (PCNetState *)pci_dev; + +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size); +#endif + + cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr); +} + +void pci_pcnet_init(PCIBus *bus, NICInfo *nd) +{ + PCNetState *d; + uint8_t *pci_conf; + +#if 0 + printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", + sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); +#endif + + d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), + -1, NULL, NULL); + + pci_conf = d->dev.config; + + *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022); + *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); + *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); + *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); + pci_conf[0x08] = 0x10; + pci_conf[0x09] = 0x00; + pci_conf[0x0a] = 0x00; // ethernet network controller + pci_conf[0x0b] = 0x02; + pci_conf[0x0e] = 0x00; // header_type + + *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); + *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); + + pci_conf[0x3d] = 1; // interrupt pin 0 + pci_conf[0x3e] = 0x06; + pci_conf[0x3f] = 0xff; + + /* Handler for memory-mapped I/O */ + d->mmio_io_addr = + cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); + + pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, + PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); + + pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, + PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); + + d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); + + d->nd = nd; + + d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, + pcnet_can_receive, d); + + snprintf(d->vc->info_str, sizeof(d->vc->info_str), + "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + d->nd->macaddr[0], + d->nd->macaddr[1], + d->nd->macaddr[2], + d->nd->macaddr[3], + d->nd->macaddr[4], + d->nd->macaddr[5]); + + pcnet_h_reset(d); +} diff --git a/vl.h b/vl.h index 244310fee..661e4fd5e 100644 --- a/vl.h +++ b/vl.h @@ -828,6 +828,10 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd); void pci_rtl8139_init(PCIBus *bus, NICInfo *nd); +/* pcnet.c */ + +void pci_pcnet_init(PCIBus *bus, NICInfo *nd); + /* pckbd.c */ void kbd_init(void); -- cgit v1.2.3 From 47378eb1ca3730d3c22ca741f8e72d74fd48f493 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 16:33:33 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2037 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index 8cc9aa55f..516ea87bf 100644 --- a/TODO +++ b/TODO @@ -1,24 +1,20 @@ short term: ---------- -- support variable tsc freq +- 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 -- merge Solaris patch - warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?) - config file (at least for windows/Mac OS X) -- commit message if execution of code in IO memory - update doc: PCI infos. -- VNC patch + Synaptic patch. - basic VGA optimizations -- physical memory cache (reduce qemu-fast address space size to about 32 MB) - better code fetch (different exception handling + CS.limit support) - do not resize vga if invalid size. - avoid looping if only exceptions -- cycle counter for all archs - TLB code protection support for PPC - see openMosix Doc - disable SMC handling for ARM/SPARC/PPC (not finished) @@ -31,12 +27,10 @@ short term: - fix CCOP optimisation - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). -- fix arm fpu rounding (at least for float->integer conversions) ppc specific: ------------ - TLB invalidate not needed if msr_pr changes -- SPR_ENCODE() not useful - enable shift optimizations ? linux-user specific: -- cgit v1.2.3 From 6c270db74181e313bdbd602e1273e0ebd090366b Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 16:47:58 +0000 Subject: rate converter fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2038 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/rate_template.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/audio/rate_template.h b/audio/rate_template.h index 3e0e77c94..398d305e9 100644 --- a/audio/rate_template.h +++ b/audio/rate_template.h @@ -51,7 +51,7 @@ void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, if (rate->opos_inc == (1ULL + UINT_MAX)) { int i, n = *isamp > *osamp ? *osamp : *isamp; for (i = 0; i < n; i++) { - OP (obuf[i].l, ibuf[i].r); + OP (obuf[i].l, ibuf[i].l); OP (obuf[i].r, ibuf[i].r); } *isamp = n; -- cgit v1.2.3 From feea13e186a902179fcd79e3ce5318b5eb73c0d2 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 16:49:00 +0000 Subject: sb16 fixes (WfW 3 appears to work with shipped drivers) (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2039 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sb16.c | 84 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/hw/sb16.c b/hw/sb16.c index f5eb7fe80..6443a90d0 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -193,6 +193,31 @@ static void aux_timer (void *opaque) #define DMA8_AUTO 1 #define DMA8_HIGH 2 +static void continue_dma8 (SB16State *s) +{ + if (s->freq > 0) { + audsettings_t as; + + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + + s->voice = AUD_open_out ( + &s->card, + s->voice, + "sb16", + s, + SB_audio_callback, + &as, + 0 /* little endian */ + ); + } + + control (s, 1); +} + static void dma_cmd8 (SB16State *s, int mask, int dma_len) { s->fmt = AUD_FMT_U8; @@ -201,7 +226,8 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->fmt_signed = 0; s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0; if (-1 == s->time_const) { - s->freq = 11025; + if (s->freq <= 0) + s->freq = 11025; } else { int tmp = (256 - s->time_const); @@ -239,27 +265,7 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, s->block_size, s->dma_auto, s->fifo, s->highspeed); - if (s->freq) { - audsettings_t as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as, - 0 /* little endian */ - ); - } - - control (s, 1); + continue_dma8 (s); speaker (s, 1); } @@ -437,7 +443,7 @@ static void command (SB16State *s, uint8_t cmd) break; case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */ - control (s, 1); + dma_cmd8 (s, DMA8_AUTO, -1); break; case 0x20: /* Direct ADC, Juice/PL */ @@ -531,7 +537,9 @@ static void command (SB16State *s, uint8_t cmd) break; case 0xd4: /* continue DMA operation. 8bit */ - control (s, 1); + /* KQ6 (or maybe Sierras audblst.drv in general) resets + the frequency between halt/continue */ + continue_dma8 (s); break; case 0xd5: /* halt DMA operation. 16bit */ @@ -818,6 +826,33 @@ static void complete (SB16State *s) return; } +static void legacy_reset (SB16State *s) +{ + audsettings_t as; + + s->freq = 11025; + s->fmt_signed = 0; + s->fmt_bits = 8; + s->fmt_stereo = 0; + + as.freq = s->freq; + as.nchannels = 1; + as.fmt = AUD_FMT_U8; + + s->voice = AUD_open_out ( + &s->card, + s->voice, + "sb16", + s, + SB_audio_callback, + &as, + 0 /* little endian */ + ); + + /* Not sure about that... */ + /* AUD_set_active_out (s->voice, 1); */ +} + static void reset (SB16State *s) { pic_set_irq (s->irq, 0); @@ -841,6 +876,7 @@ static void reset (SB16State *s) dsp_out_data(s, 0xaa); speaker (s, 0); control (s, 0); + legacy_reset (s); } static IO_WRITE_PROTO (dsp_write) -- cgit v1.2.3 From 8ead62cfc21f61a32677892c721674e06e9f6153 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 16:51:32 +0000 Subject: audio fixes + initial audio capture support (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2040 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 5 +- audio/audio.c | 327 ++++++++++++++++++++++++++++++++++++++++++++++-- audio/audio.h | 14 ++- audio/audio_int.h | 18 ++- audio/audio_template.h | 12 +- audio/coreaudio.c | 2 - audio/dsound_template.h | 14 +-- audio/dsoundaudio.c | 8 +- audio/fmodaudio.c | 2 - audio/noaudio.c | 34 ++--- audio/ossaudio.c | 26 ++-- audio/sdlaudio.c | 1 - audio/wavaudio.c | 1 - audio/wavcapture.c | 101 +++++++++++++++ hw/es1370.c | 3 +- 15 files changed, 514 insertions(+), 54 deletions(-) create mode 100644 audio/wavcapture.c diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 30f1e5076..2cac396b2 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -61,8 +61,8 @@ static struct { .size_in_usec_in = 1, .size_in_usec_out = 1, #endif - .pcm_name_out = "hw:0,0", - .pcm_name_in = "hw:0,0", + .pcm_name_out = "default", + .pcm_name_in = "default", #ifdef HIGH_LATENCY .buffer_size_in = 400000, .period_size_in = 400000 / 4, @@ -606,7 +606,6 @@ static int alsa_run_out (HWVoiceOut *hw) } } - mixeng_clear (src, written); rpos = (rpos + written) % hw->samples; samples -= written; len -= written; diff --git a/audio/audio.c b/audio/audio.c index f10025bf4..0de728cc5 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -29,6 +29,7 @@ /* #define DEBUG_PLIVE */ /* #define DEBUG_LIVE */ /* #define DEBUG_OUT */ +/* #define DEBUG_CAPTURE */ #define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" @@ -137,7 +138,7 @@ int audio_bug (const char *funcname, int cond) if (cond) { static int shown; - AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname); + AUD_log (NULL, "A bug was just triggered in %s\n", funcname); if (!shown) { shown = 1; AUD_log (NULL, "Save all your work and restart without audio\n"); @@ -620,6 +621,121 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) } } +/* + * Capture + */ +static void noop_conv (st_sample_t *dst, const void *src, + int samples, volume_t *vol) +{ + (void) src; + (void) dst; + (void) samples; + (void) vol; +} + +static CaptureVoiceOut *audio_pcm_capture_find_specific ( + AudioState *s, + audsettings_t *as, + int endian + ) +{ + CaptureVoiceOut *cap; + int swap_endian = audio_need_to_swap_endian (endian); + + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + if ((cap->hw.info.swap_endian == swap_endian) + && audio_pcm_info_eq (&cap->hw.info, as)) { + return cap; + } + } + return NULL; +} + +static void audio_notify_capture (CaptureVoiceOut *cap, int enabled) +{ + if (cap->hw.enabled != enabled) { + struct capture_callback *cb; + + cap->hw.enabled = enabled; + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.state (cb->opaque, enabled); + } + } +} + +static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap) +{ + HWVoiceOut *hw = &cap->hw; + SWVoiceOut *sw; + int enabled = 0; + + for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) { + if (sw->active) { + enabled = 1; + break; + } + } + audio_notify_capture (cap, enabled); +} + +static void audio_detach_capture (HWVoiceOut *hw) +{ + SWVoiceOut *sw; + + for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) { + if (sw->rate) { + st_rate_stop (sw->rate); + sw->rate = NULL; + } + + LIST_REMOVE (sw, entries); + LIST_REMOVE (sw, cap_entries); + qemu_free (sw); + audio_recalc_and_notify_capture ((CaptureVoiceOut *) sw->hw); + } +} + +static int audio_attach_capture (AudioState *s, HWVoiceOut *hw) +{ + CaptureVoiceOut *cap; + + audio_detach_capture (hw); + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + SWVoiceOut *sw; + HWVoiceOut *hw_cap; + + hw_cap = &cap->hw; + sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); + if (!sw) { + dolog ("Could not allocate soft capture voice (%zu bytes)\n", + sizeof (*sw)); + return -1; + } + + sw->info = hw->info; + sw->hw = hw_cap; + sw->empty = 1; + sw->active = hw->enabled; + sw->conv = noop_conv; + sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq; + sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq); + if (!sw->rate) { + dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw)); + qemu_free (sw); + return -1; + } + LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries); + LIST_INSERT_HEAD (&hw->sw_cap_head, sw, cap_entries); + if (sw->active) { + audio_notify_capture (cap, 1); + } + else { + audio_recalc_and_notify_capture (cap); + } + } + return 0; +} + /* * Hard voice (capture) */ @@ -916,17 +1032,11 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) SWVoiceOut *temp_sw; if (on) { - int total; - hw->pending_disable = 0; if (!hw->enabled) { hw->enabled = 1; hw->pcm_ops->ctl_out (hw, VOICE_ENABLE); } - - if (sw->empty) { - total = 0; - } } else { if (hw->enabled) { @@ -940,6 +1050,13 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) hw->pending_disable = nb_active == 1; } } + for (temp_sw = hw->sw_cap_head.lh_first; temp_sw; + temp_sw = temp_sw->entries.le_next) { + temp_sw->active = hw->enabled; + if (hw->enabled) { + audio_notify_capture ((CaptureVoiceOut *) temp_sw->hw, 1); + } + } sw->active = on; } } @@ -1031,6 +1148,41 @@ static int audio_get_free (SWVoiceOut *sw) return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; } +static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples) +{ + int n; + + if (hw->enabled) { + SWVoiceOut *sw; + + for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) { + int rpos2 = rpos; + + n = samples; + while (n) { + int till_end_of_hw = hw->samples - rpos2; + int to_write = audio_MIN (till_end_of_hw, n); + int bytes = to_write << hw->info.shift; + int written; + + sw->buf = hw->mix_buf + rpos2; + written = audio_pcm_sw_write (sw, NULL, bytes); + if (written - bytes) { + dolog ("Could not mix %d bytes into a capture buffer", + bytes); + break; + } + n -= to_write; + rpos2 = (rpos2 + to_write) % hw->samples; + } + } + } + + n = audio_MIN (samples, hw->samples - rpos); + mixeng_clear (hw->mix_buf + rpos, n); + mixeng_clear (hw->mix_buf, samples - n); +} + static void audio_run_out (AudioState *s) { HWVoiceOut *hw = NULL; @@ -1038,7 +1190,7 @@ static void audio_run_out (AudioState *s) while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) { int played; - int live, free, nb_live, cleanup_required; + int live, free, nb_live, cleanup_required, prev_rpos; live = audio_pcm_hw_get_live_out2 (hw, &nb_live); if (!nb_live) { @@ -1057,6 +1209,11 @@ static void audio_run_out (AudioState *s) hw->enabled = 0; hw->pending_disable = 0; hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); + for (sw = hw->sw_cap_head.lh_first; sw; + sw = sw->cap_entries.le_next) { + sw->active = 0; + audio_recalc_and_notify_capture ((CaptureVoiceOut *) sw->hw); + } continue; } @@ -1072,6 +1229,7 @@ static void audio_run_out (AudioState *s) continue; } + prev_rpos = hw->rpos; played = hw->pcm_ops->run_out (hw); if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { dolog ("hw->rpos=%d hw->samples=%d played=%d\n", @@ -1085,6 +1243,7 @@ static void audio_run_out (AudioState *s) if (played) { hw->ts_helper += played; + audio_capture_mix_and_clear (hw, prev_rpos, played); } cleanup_required = 0; @@ -1158,12 +1317,60 @@ static void audio_run_in (AudioState *s) } } +static void audio_run_capture (AudioState *s) +{ + CaptureVoiceOut *cap; + + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + int live, rpos, captured; + HWVoiceOut *hw = &cap->hw; + SWVoiceOut *sw; + + captured = live = audio_pcm_hw_get_live_out (hw); + rpos = hw->rpos; + while (live) { + int left = hw->samples - rpos; + int to_capture = audio_MIN (live, left); + st_sample_t *src; + struct capture_callback *cb; + + src = hw->mix_buf + rpos; + hw->clip (cap->buf, src, to_capture); + mixeng_clear (src, to_capture); + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.capture (cb->opaque, cap->buf, + to_capture << hw->info.shift); + } + rpos = (rpos + to_capture) % hw->samples; + live -= to_capture; + } + hw->rpos = rpos; + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (!sw->active && sw->empty) { + continue; + } + + if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) { + dolog ("captured=%d sw->total_hw_samples_mixed=%d\n", + captured, sw->total_hw_samples_mixed); + captured = sw->total_hw_samples_mixed; + } + + sw->total_hw_samples_mixed -= captured; + sw->empty = sw->total_hw_samples_mixed == 0; + } + } +} + static void audio_timer (void *opaque) { AudioState *s = opaque; audio_run_out (s); audio_run_in (s); + audio_run_capture (s); qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); } @@ -1327,8 +1534,14 @@ static void audio_atexit (void) HWVoiceIn *hwi = NULL; while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { + SWVoiceOut *sw; + hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); hwo->pcm_ops->fini_out (hwo); + + for (sw = hwo->sw_cap_head.lh_first; sw; sw = sw->entries.le_next) { + audio_notify_capture ((CaptureVoiceOut *) sw->hw, 0); + } } while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) { @@ -1383,6 +1596,7 @@ AudioState *AUD_init (void) LIST_INIT (&s->hw_head_out); LIST_INIT (&s->hw_head_in); + LIST_INIT (&s->cap_head); atexit (audio_atexit); s->ts = qemu_new_timer (vm_clock, audio_timer, s); @@ -1479,3 +1693,100 @@ AudioState *AUD_init (void) qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); return s; } + +int AUD_add_capture ( + AudioState *s, + audsettings_t *as, + int endian, + struct audio_capture_ops *ops, + void *cb_opaque + ) +{ + CaptureVoiceOut *cap; + struct capture_callback *cb; + + if (!s) { + /* XXX suppress */ + s = &glob_audio_state; + } + + if (audio_validate_settigs (as)) { + dolog ("Invalid settings were passed when trying to add capture\n"); + audio_print_settings (as); + return -1; + } + + cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb)); + if (!cb) { + dolog ("Could not allocate capture callback information, size %zu\n", + sizeof (*cb)); + goto err0; + } + cb->ops = *ops; + cb->opaque = cb_opaque; + + cap = audio_pcm_capture_find_specific (s, as, endian); + if (cap) { + LIST_INSERT_HEAD (&cap->cb_head, cb, entries); + return 0; + } + else { + HWVoiceOut *hw; + CaptureVoiceOut *cap; + + cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap)); + if (!cap) { + dolog ("Could not allocate capture voice, size %zu\n", + sizeof (*cap)); + goto err1; + } + + hw = &cap->hw; + LIST_INIT (&hw->sw_head); + LIST_INIT (&cap->cb_head); + + /* XXX find a more elegant way */ + hw->samples = 4096 * 4; + hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, + sizeof (st_sample_t)); + if (!hw->mix_buf) { + dolog ("Could not allocate capture mix buffer (%d samples)\n", + hw->samples); + goto err2; + } + + audio_pcm_init_info (&hw->info, as, endian); + + cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + if (!cap->buf) { + dolog ("Could not allocate capture buffer " + "(%d samples, each %d bytes)\n", + hw->samples, 1 << hw->info.shift); + goto err3; + } + + hw->clip = mixeng_clip + [hw->info.nchannels == 2] + [hw->info.sign] + [hw->info.swap_endian] + [hw->info.bits == 16]; + + LIST_INSERT_HEAD (&s->cap_head, cap, entries); + LIST_INSERT_HEAD (&cap->cb_head, cb, entries); + + hw = NULL; + while ((hw = audio_pcm_hw_find_any_out (s, hw))) { + audio_attach_capture (s, hw); + } + return 0; + + err3: + qemu_free (cap->hw.mix_buf); + err2: + qemu_free (cap); + err1: + qemu_free (cb); + err0: + return -1; + } +} diff --git a/audio/audio.h b/audio/audio.h index 169b5f636..4e1a694d0 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -41,6 +41,11 @@ typedef struct { audfmt_e fmt; } audsettings_t; +struct audio_capture_ops { + void (*state) (void *opaque, int enabled); + void (*capture) (void *opaque, void *buf, int size); +}; + typedef struct AudioState AudioState; typedef struct SWVoiceOut SWVoiceOut; typedef struct SWVoiceIn SWVoiceIn; @@ -66,6 +71,13 @@ AudioState *AUD_init (void); void AUD_help (void); void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card); void AUD_remove_card (QEMUSoundCard *card); +int AUD_add_capture ( + AudioState *s, + audsettings_t *as, + int endian, + struct audio_capture_ops *ops, + void *opaque + ); SWVoiceOut *AUD_open_out ( QEMUSoundCard *card, @@ -111,7 +123,7 @@ static inline void *advance (void *p, int incr) } uint32_t popcount (uint32_t u); -inline uint32_t lsbindex (uint32_t u); +uint32_t lsbindex (uint32_t u); #ifdef __GNUC__ #define audio_MIN(a, b) ( __extension__ ({ \ diff --git a/audio/audio_int.h b/audio/audio_int.h index ca240ccc7..c01c16add 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -79,6 +79,7 @@ typedef struct HWVoiceOut { int samples; LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; + LIST_HEAD (sw_cap_listhead, SWVoiceOut) sw_cap_head; struct audio_pcm_ops *pcm_ops; LIST_ENTRY (HWVoiceOut) entries; } HWVoiceOut; @@ -115,6 +116,7 @@ struct SWVoiceOut { volume_t vol; struct audio_callback callback; LIST_ENTRY (SWVoiceOut) entries; + LIST_ENTRY (SWVoiceOut) cap_entries; }; struct SWVoiceIn { @@ -160,14 +162,28 @@ struct audio_pcm_ops { int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); }; +struct capture_callback { + struct audio_capture_ops ops; + void *opaque; + LIST_ENTRY (capture_callback) entries; +}; + +typedef struct CaptureVoiceOut { + HWVoiceOut hw; + void *buf; + LIST_HEAD (cb_listhead, capture_callback) cb_head; + LIST_ENTRY (CaptureVoiceOut) entries; +} CaptureVoiceOut; + struct AudioState { struct audio_driver *drv; void *drv_opaque; QEMUTimer *ts; - LIST_HEAD (card_head, QEMUSoundCard) card_head; + LIST_HEAD (card_listhead, QEMUSoundCard) card_head; LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; + LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head; int nb_hw_voices_out; int nb_hw_voices_in; }; diff --git a/audio/audio_template.h b/audio/audio_template.h index 419a4aa46..04b30239d 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -200,6 +200,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp) HW *hw = *hwp; if (!hw->sw_head.lh_first) { +#ifdef DAC + audio_detach_capture (hw); +#endif LIST_REMOVE (hw, entries); glue (s->nb_hw_voices_, TYPE) += 1; glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); @@ -266,7 +269,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) hw->pcm_ops = drv->pcm_ops; LIST_INIT (&hw->sw_head); - +#ifdef DAC + LIST_INIT (&hw->sw_cap_head); +#endif if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { goto err0; } @@ -292,6 +297,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); glue (s->nb_hw_voices_, TYPE) -= 1; +#ifdef DAC + audio_attach_capture (s, hw); +#endif return hw; err1: @@ -542,7 +550,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) cur_ts = sw->hw->ts_helper; old_ts = ts->old_ts; - /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */ + /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */ if (cur_ts >= old_ts) { delta = cur_ts - old_ts; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 534fb3ef7..34e416d93 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -275,8 +275,6 @@ static OSStatus audioDeviceIOProc( #endif } - /* cleanup */ - mixeng_clear (src, frameCount); rpos = (rpos + frameCount) % hw->samples; core->decr += frameCount; core->rpos = rpos; diff --git a/audio/dsound_template.h b/audio/dsound_template.h index 38ba5b9ca..96f7cc7fa 100644 --- a/audio/dsound_template.h +++ b/audio/dsound_template.h @@ -70,7 +70,13 @@ static int glue (dsound_lock_, TYPE) ( int i; LPVOID p1 = NULL, p2 = NULL; DWORD blen1 = 0, blen2 = 0; + DWORD flag; +#ifdef DSBTYPE_IN + flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; +#else + flag = entire ? DSBLOCK_ENTIREBUFFER : 0; +#endif for (i = 0; i < conf.lock_retries; ++i) { hr = glue (IFACE, _Lock) ( buf, @@ -80,13 +86,7 @@ static int glue (dsound_lock_, TYPE) ( &blen1, &p2, &blen2, - (entire -#ifdef DSBTYPE_IN - ? DSCBLOCK_ENTIREBUFFER -#else - ? DSBLOCK_ENTIREBUFFER -#endif - : 0) + flag ); if (FAILED (hr)) { diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index 63c5a5057..90a0333f1 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -453,13 +453,11 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len) if (src_len1) { hw->clip (dst, src1, src_len1); - mixeng_clear (src1, src_len1); } if (src_len2) { dst = advance (dst, src_len1 << hw->info.shift); hw->clip (dst, src2, src_len2); - mixeng_clear (src2, src_len2); } hw->rpos = pos % hw->samples; @@ -987,6 +985,12 @@ static void *dsound_audio_init (void) hr = IDirectSound_Initialize (s->dsound, NULL); if (FAILED (hr)) { dsound_logerr (hr, "Could not initialize DirectSound\n"); + + hr = IDirectSound_Release (s->dsound); + if (FAILED (hr)) { + dsound_logerr (hr, "Could not release DirectSound\n"); + } + s->dsound = NULL; return NULL; } diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index 072d8a830..23f267753 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -153,13 +153,11 @@ static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len) if (src_len1) { hw->clip (dst, src1, src_len1); - mixeng_clear (src1, src_len1); } if (src_len2) { dst = advance (dst, src_len1 << hw->info.shift); hw->clip (dst, src2, src_len2); - mixeng_clear (src2, src_len2); } hw->rpos = pos % hw->samples; diff --git a/audio/noaudio.c b/audio/noaudio.c index aa3581168..314f6177a 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -40,22 +40,21 @@ static int no_run_out (HWVoiceOut *hw) { NoVoiceOut *no = (NoVoiceOut *) hw; int live, decr, samples; - int64_t now = qemu_get_clock (vm_clock); - int64_t ticks = now - no->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - - if (bytes > INT_MAX) { - samples = INT_MAX >> hw->info.shift; - } - else { - samples = bytes >> hw->info.shift; - } + int64_t now; + int64_t ticks; + int64_t bytes; live = audio_pcm_hw_get_live_out (&no->hw); if (!live) { return 0; } + now = qemu_get_clock (vm_clock); + ticks = now - no->old_ticks; + bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; + bytes = audio_MIN (bytes, INT_MAX); + samples = bytes >> hw->info.shift; + no->old_ticks = now; decr = audio_MIN (live, samples); hw->rpos = (hw->rpos + decr) % hw->samples; @@ -101,17 +100,20 @@ static void no_fini_in (HWVoiceIn *hw) static int no_run_in (HWVoiceIn *hw) { NoVoiceIn *no = (NoVoiceIn *) hw; - int64_t now = qemu_get_clock (vm_clock); - int64_t ticks = now - no->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; int live = audio_pcm_hw_get_live_in (hw); int dead = hw->samples - live; int samples; - bytes = audio_MIN (bytes, INT_MAX); - samples = bytes >> hw->info.shift; - samples = audio_MIN (samples, dead); + if (dead) { + int64_t now = qemu_get_clock (vm_clock); + int64_t ticks = now - no->old_ticks; + int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; + no->old_ticks = now; + bytes = audio_MIN (bytes, INT_MAX); + samples = bytes >> hw->info.shift; + samples = audio_MIN (samples, dead); + } return samples; } diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 7d12f9e34..0bdc8eaab 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -55,12 +55,14 @@ static struct { int fragsize; const char *devpath_out; const char *devpath_in; + int debug; } conf = { .try_mmap = 0, .nfrags = 4, .fragsize = 4096, .devpath_out = "/dev/dsp", - .devpath_in = "/dev/dsp" + .devpath_in = "/dev/dsp", + .debug = 0 }; struct oss_params { @@ -324,9 +326,20 @@ static int oss_run_out (HWVoiceOut *hw) return 0; } - if (abinfo.bytes < 0 || abinfo.bytes > bufsize) { - ldebug ("warning: Invalid available size, size=%d bufsize=%d\n", - abinfo.bytes, bufsize); + if (abinfo.bytes > bufsize) { + if (conf.debug) { + dolog ("warning: Invalid available size, size=%d bufsize=%d\n" + "please report your OS/audio hw to malc@pulsesoft.com\n", + abinfo.bytes, bufsize); + } + abinfo.bytes = bufsize; + } + + if (abinfo.bytes < 0) { + if (conf.debug) { + dolog ("warning: Invalid available size, size=%d bufsize=%d\n", + abinfo.bytes, bufsize); + } return 0; } @@ -369,15 +382,12 @@ static int oss_run_out (HWVoiceOut *hw) "alignment %d\n", wbytes, written, hw->info.align + 1); } - mixeng_clear (src, wsamples); decr -= wsamples; rpos = (rpos + wsamples) % hw->samples; break; } } - mixeng_clear (src, convert_samples); - rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; } @@ -730,6 +740,8 @@ static struct audio_option oss_options[] = { "Path to DAC device", NULL, 0}, {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in, "Path to ADC device", NULL, 0}, + {"DEBUG", AUD_OPT_BOOL, &conf.debug, + "Turn on some debugging messages", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} }; diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 713c7849d..9fe212833 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -240,7 +240,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len) /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ hw->clip (buf, src, chunk); - mixeng_clear (src, chunk); sdl->rpos = (sdl->rpos + chunk) % hw->samples; to_mix -= chunk; buf += chunk << hw->info.shift; diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 18d2bb0c7..ca1e99f4c 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -81,7 +81,6 @@ static int wav_run_out (HWVoiceOut *hw) hw->clip (dst, src, convert_samples); qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift); - mixeng_clear (src, convert_samples); rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; diff --git a/audio/wavcapture.c b/audio/wavcapture.c new file mode 100644 index 000000000..33f04c50b --- /dev/null +++ b/audio/wavcapture.c @@ -0,0 +1,101 @@ +#include "vl.h" + +typedef struct { + QEMUFile *f; + int bytes; +} WAVState; + +/* VICE code: Store number as little endian. */ +static void le_store (uint8_t *buf, uint32_t val, int len) +{ + int i; + for (i = 0; i < len; i++) { + buf[i] = (uint8_t) (val & 0xff); + val >>= 8; + } +} + +static void wav_state_cb (void *opaque, int enabled) +{ + WAVState *wav = opaque; + + if (!enabled) { + uint8_t rlen[4]; + uint8_t dlen[4]; + uint32_t datalen = wav->bytes; + uint32_t rifflen = datalen + 36; + + if (!wav->f) { + return; + } + + le_store (rlen, rifflen, 4); + le_store (dlen, datalen, 4); + + qemu_fseek (wav->f, 4, SEEK_SET); + qemu_put_buffer (wav->f, rlen, 4); + + qemu_fseek (wav->f, 32, SEEK_CUR); + qemu_put_buffer (wav->f, dlen, 4); + } + else { + qemu_fseek (wav->f, 0, SEEK_END); + } +} + +static void wav_capture_cb (void *opaque, void *buf, int size) +{ + WAVState *wav = opaque; + + qemu_put_buffer (wav->f, buf, size); + wav->bytes += size; +} + +void wav_capture (const char *path, int freq, int bits16, int stereo) +{ + WAVState *wav; + uint8_t hdr[] = { + 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, + 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, + 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 + }; + audsettings_t as; + struct audio_capture_ops ops; + int shift; + + stereo = !!stereo; + bits16 = !!bits16; + + as.freq = freq; + as.nchannels = 1 << stereo; + as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; + + ops.state = wav_state_cb; + ops.capture = wav_capture_cb; + + wav = qemu_mallocz (sizeof (*wav)); + if (!wav) { + AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav)); + return; + } + + shift = bits16 + stereo; + hdr[34] = bits16 ? 0x10 : 0x08; + + le_store (hdr + 22, as.nchannels, 2); + le_store (hdr + 24, freq, 4); + le_store (hdr + 28, freq << shift, 4); + le_store (hdr + 32, 1 << shift, 2); + + wav->f = fopen (path, "wb"); + if (!wav->f) { + AUD_log ("wav", "Failed to open wave file `%s'\nReason: %s\n", + path, strerror (errno)); + qemu_free (wav); + return; + } + + qemu_put_buffer (wav->f, hdr, sizeof (hdr)); + AUD_add_capture (NULL, &as, 0, &ops, wav); +} diff --git a/hw/es1370.c b/hw/es1370.c index 9fddd9d8b..2aa2db9eb 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -479,9 +479,10 @@ static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr) IO_WRITE_PROTO (es1370_writeb) { ES1370State *s = opaque; - addr = es1370_fixup (s, addr); uint32_t shift, mask; + addr = es1370_fixup (s, addr); + switch (addr) { case ES1370_REG_CONTROL: case ES1370_REG_CONTROL + 1: -- cgit v1.2.3 From 219fb125039e175a92aa14684ac688305b5143bd Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 21:42:10 +0000 Subject: avoid unneeded dependencies git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2041 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index 120058162..a375f27d9 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -29,11 +29,6 @@ #include "vl.h" -/* XXX: suppress those headers */ -#include -#include -#include - //#define PCNET_DEBUG //#define PCNET_DEBUG_IO //#define PCNET_DEBUG_BCR @@ -70,6 +65,12 @@ struct PCNetState_st { #error FixMe #endif +struct qemu_ether_header { + uint8_t ether_dhost[6]; + uint8_t ether_shost[6]; + uint16_t ether_type; +}; + /* BUS CONFIGURATION REGISTERS */ #define BCR_MSRDA 0 #define BCR_MSWRA 1 @@ -441,7 +442,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ #endif #define PRINT_PKTHDR(BUF) do { \ - struct ether_header *hdr = (void *)(BUF); \ + struct qemu_ether_header *hdr = (void *)(BUF); \ printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ "type=0x%04x (bcast=%d)\n", \ @@ -449,7 +450,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ - htons(hdr->ether_type), \ + be16_to_cpu(hdr->ether_type), \ !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \ } while (0) @@ -462,7 +463,7 @@ static inline uint32_t lnc_mchash(const uint8_t *ether_addr) int idx, bit; uint8_t data; - for (idx = 0; idx < ETHER_ADDR_LEN; idx++) { + for (idx = 0; idx < 6; idx++) { for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) { crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); data >>= 1; @@ -547,7 +548,7 @@ static const uint32_t crctab[256] = { static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) { - struct ether_header *hdr = (void *)buf; + struct qemu_ether_header *hdr = (void *)buf; uint8_t padr[6] = { s->csr[12] & 0xff, s->csr[12] >> 8, s->csr[13] & 0xff, s->csr[13] >> 8, @@ -568,7 +569,7 @@ static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) { static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct ether_header *hdr = (void *)buf; + struct qemu_ether_header *hdr = (void *)buf; int result = !CSR_DRCVBC(s) && !bcmp(hdr->ether_dhost, BCAST, 6); #ifdef PCNET_DEBUG_MATCH printf("padr_bcast result=%d\n", result); @@ -578,7 +579,7 @@ static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) { - struct ether_header *hdr = (void *)buf; + struct qemu_ether_header *hdr = (void *)buf; if ((*(hdr->ether_dhost)&0x01) && ((uint64_t *)&s->csr[8])[0] != 0LL) { uint8_t ladr[8] = { @@ -993,17 +994,18 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) memcpy(src, buf, size); +#if 1 + /* no need to compute the CRC */ + src[size] = 0; + src[size + 1] = 0; + src[size + 2] = 0; + src[size + 3] = 0; + size += 4; +#else /* XXX: avoid CRC generation */ if (!CSR_ASTRP_RCV(s)) { uint32_t fcs = ~0; -#if 0 - uint8_t *p = s->buffer; - - ((uint32_t *)p)[0] = ((uint32_t *)p)[1] = 0xaaaaaaaa; - p[7] = 0xab; -#else uint8_t *p = src; -#endif while (size < 46) { src[size++] = 0; @@ -1015,6 +1017,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) ((uint32_t *)&src[size])[0] = htonl(fcs); size += 4; /* FCS at end of packet */ } else size += 4; +#endif #ifdef PCNET_DEBUG_MATCH PRINT_PKTHDR(buf); -- cgit v1.2.3 From d929eba5d47f097302779d55427712c3ceb931ad Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 4 Jul 2006 21:47:22 +0000 Subject: audio endianness API changes (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2042 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 14 ++++---------- audio/audio.c | 46 ++++++++++++++++++++++++---------------------- audio/audio.h | 15 ++++++++++----- audio/audio_int.h | 14 ++------------ audio/audio_template.h | 21 +++++++++------------ audio/coreaudio.c | 10 +--------- audio/dsound_template.h | 4 ++-- audio/fmodaudio.c | 8 ++++++-- audio/noaudio.c | 4 ++-- audio/ossaudio.c | 14 ++++---------- audio/sdlaudio.c | 7 ++----- audio/wavaudio.c | 3 ++- audio/wavcapture.c | 3 ++- hw/adlib.c | 4 ++-- hw/es1370.c | 7 +++---- hw/pcspk.c | 4 ++-- hw/sb16.c | 16 ++++++++-------- 17 files changed, 85 insertions(+), 109 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 2cac396b2..71e523566 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -662,12 +662,9 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianness; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift); @@ -751,12 +748,9 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianness; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); diff --git a/audio/audio.c b/audio/audio.c index 0de728cc5..dd86c4d7a 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -510,6 +510,18 @@ static void audio_print_settings (audsettings_t *as) AUD_log (NULL, "invalid(%d)", as->fmt); break; } + AUD_log (NULL, "endianness="); + switch (as->endianness) { + case 0: + AUD_log (NULL, "little"); + break; + case 1: + AUD_log (NULL, "big"); + break; + default: + AUD_log (NULL, "invalid"); + break; + } AUD_log (NULL, "\n"); } @@ -518,6 +530,7 @@ static int audio_validate_settigs (audsettings_t *as) int invalid; invalid = as->nchannels != 1 && as->nchannels != 2; + invalid |= as->endianness != 0 && as->endianness != 1; switch (as->fmt) { case AUD_FMT_S8: @@ -531,11 +544,7 @@ static int audio_validate_settigs (audsettings_t *as) } invalid |= as->freq <= 0; - - if (invalid) { - return -1; - } - return 0; + return invalid ? -1 : 0; } static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) @@ -557,14 +566,11 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) return info->freq == as->freq && info->nchannels == as->nchannels && info->sign == sign - && info->bits == bits; + && info->bits == bits + && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS); } -void audio_pcm_init_info ( - struct audio_pcm_info *info, - audsettings_t *as, - int swap_endian - ) +void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) { int bits = 8, sign = 0; @@ -588,7 +594,7 @@ void audio_pcm_init_info ( info->shift = (as->nchannels == 2) + (bits == 16); info->align = (1 << info->shift) - 1; info->bytes_per_second = info->freq << info->shift; - info->swap_endian = swap_endian; + info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); } void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) @@ -610,7 +616,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) int shift = info->nchannels - 1; short s = INT16_MAX; - if (info->swap_endian) { + if (info->swap_endianness) { s = bswap16 (s); } @@ -635,16 +641,13 @@ static void noop_conv (st_sample_t *dst, const void *src, static CaptureVoiceOut *audio_pcm_capture_find_specific ( AudioState *s, - audsettings_t *as, - int endian + audsettings_t *as ) { CaptureVoiceOut *cap; - int swap_endian = audio_need_to_swap_endian (endian); for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { - if ((cap->hw.info.swap_endian == swap_endian) - && audio_pcm_info_eq (&cap->hw.info, as)) { + if (audio_pcm_info_eq (&cap->hw.info, as)) { return cap; } } @@ -1697,7 +1700,6 @@ AudioState *AUD_init (void) int AUD_add_capture ( AudioState *s, audsettings_t *as, - int endian, struct audio_capture_ops *ops, void *cb_opaque ) @@ -1725,7 +1727,7 @@ int AUD_add_capture ( cb->ops = *ops; cb->opaque = cb_opaque; - cap = audio_pcm_capture_find_specific (s, as, endian); + cap = audio_pcm_capture_find_specific (s, as); if (cap) { LIST_INSERT_HEAD (&cap->cb_head, cb, entries); return 0; @@ -1755,7 +1757,7 @@ int AUD_add_capture ( goto err2; } - audio_pcm_init_info (&hw->info, as, endian); + audio_pcm_init_info (&hw->info, as); cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); if (!cap->buf) { @@ -1768,7 +1770,7 @@ int AUD_add_capture ( hw->clip = mixeng_clip [hw->info.nchannels == 2] [hw->info.sign] - [hw->info.swap_endian] + [hw->info.swap_endianness] [hw->info.bits == 16]; LIST_INSERT_HEAD (&s->cap_head, cap, entries); diff --git a/audio/audio.h b/audio/audio.h index 4e1a694d0..14fa3bce9 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -24,6 +24,7 @@ #ifndef QEMU_AUDIO_H #define QEMU_AUDIO_H +#include "config.h" #include "sys-queue.h" typedef void (*audio_callback_fn_t) (void *opaque, int avail); @@ -35,10 +36,17 @@ typedef enum { AUD_FMT_S16 } audfmt_e; +#ifdef WORDS_BIGENDIAN +#define AUDIO_HOST_ENDIANNESS 1 +#else +#define AUDIO_HOST_ENDIANNESS 0 +#endif + typedef struct { int freq; int nchannels; audfmt_e fmt; + int endianness; } audsettings_t; struct audio_capture_ops { @@ -74,7 +82,6 @@ void AUD_remove_card (QEMUSoundCard *card); int AUD_add_capture ( AudioState *s, audsettings_t *as, - int endian, struct audio_capture_ops *ops, void *opaque ); @@ -85,8 +92,7 @@ SWVoiceOut *AUD_open_out ( const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - audsettings_t *settings, - int sw_endian + audsettings_t *settings ); void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw); @@ -104,8 +110,7 @@ SWVoiceIn *AUD_open_in ( const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - audsettings_t *settings, - int sw_endian + audsettings_t *settings ); void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw); diff --git a/audio/audio_int.h b/audio/audio_int.h index c01c16add..f5dcb2c70 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -61,7 +61,7 @@ struct audio_pcm_info { int align; int shift; int bytes_per_second; - int swap_endian; + int swap_endianness; }; typedef struct HWVoiceOut { @@ -198,8 +198,7 @@ extern struct audio_driver coreaudio_audio_driver; extern struct audio_driver dsound_audio_driver; extern volume_t nominal_volume; -void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as, - int swap_endian); +void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as); void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len); @@ -220,15 +219,6 @@ static inline int audio_ring_dist (int dst, int src, int len) return (dst >= src) ? (dst - src) : (len - src + dst); } -static inline int audio_need_to_swap_endian (int endianness) -{ -#ifdef WORDS_BIGENDIAN - return endianness != 1; -#else - return endianness != 0; -#endif -} - #if defined __GNUC__ #define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2))) #define INIT_FIELD(f) . f diff --git a/audio/audio_template.h b/audio/audio_template.h index 04b30239d..04b47befe 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -140,13 +140,12 @@ static int glue (audio_pcm_sw_init_, TYPE) ( SW *sw, HW *hw, const char *name, - audsettings_t *as, - int endian + audsettings_t *as ) { int err; - audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian)); + audio_pcm_init_info (&sw->info, as); sw->hw = hw; sw->active = 0; #ifdef DAC @@ -164,7 +163,7 @@ static int glue (audio_pcm_sw_init_, TYPE) ( #endif [sw->info.nchannels == 2] [sw->info.sign] - [sw->info.swap_endian] + [sw->info.swap_endianness] [sw->info.bits == 16]; sw->name = qemu_strdup (name); @@ -288,7 +287,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) #endif [hw->info.nchannels == 2] [hw->info.sign] - [hw->info.swap_endian] + [hw->info.swap_endianness] [hw->info.bits == 16]; if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { @@ -336,8 +335,7 @@ static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as) static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( AudioState *s, const char *sw_name, - audsettings_t *as, - int sw_endian + audsettings_t *as ) { SW *sw; @@ -365,7 +363,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) { goto err3; } @@ -407,8 +405,7 @@ SW *glue (AUD_open_, TYPE) ( const char *name, void *callback_opaque , audio_callback_fn_t callback_fn, - audsettings_t *as, - int sw_endian + audsettings_t *as ) { AudioState *s; @@ -481,12 +478,12 @@ SW *glue (AUD_open_, TYPE) ( } glue (audio_pcm_sw_fini_, TYPE) (sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) { goto fail; } } else { - sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian); + sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as); if (!sw) { dolog ("Failed to create voice `%s'\n", name); return NULL; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 34e416d93..8512f122b 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -295,7 +295,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) UInt32 propertySize; int err; int bits = 8; - int endianess = 0; const char *typ = "playback"; AudioValueRange frameRange; @@ -308,16 +307,9 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { bits = 16; - endianess = 1; } - audio_pcm_init_info ( - &hw->info, - as, - /* Following is irrelevant actually since we do not use - mixengs clipping routines */ - audio_need_to_swap_endian (endianess) - ); + audio_pcm_init_info (&hw->info, as); /* open default output device */ propertySize = sizeof(core->outputDeviceID); diff --git a/audio/dsound_template.h b/audio/dsound_template.h index 96f7cc7fa..0896b04a0 100644 --- a/audio/dsound_template.h +++ b/audio/dsound_template.h @@ -250,8 +250,8 @@ static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as) } ds->first_time = 1; - - audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); if (bc.dwBufferBytes & hw->info.align) { dolog ( diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index 23f267753..5875ba15e 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -358,6 +358,7 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as) { int bits16, mode, channel; FMODVoiceOut *fmd = (FMODVoiceOut *) hw; + audsettings_t obt_as = *as; mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); fmd->fmod_sample = FSOUND_Sample_Alloc ( @@ -384,7 +385,8 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as) fmd->channel = channel; /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); bits16 = (mode & FSOUND_16BITS) != 0; hw->samples = conf.nb_samples; return 0; @@ -418,6 +420,7 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as) { int bits16, mode; FMODVoiceIn *fmd = (FMODVoiceIn *) hw; + audsettings_t obt_as = *as; if (conf.broken_adc) { return -1; @@ -440,7 +443,8 @@ static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as) } /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); bits16 = (mode & FSOUND_16BITS) != 0; hw->samples = conf.nb_samples; return 0; diff --git a/audio/noaudio.c b/audio/noaudio.c index 314f6177a..8fb15a224 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -68,7 +68,7 @@ static int no_write (SWVoiceOut *sw, void *buf, int len) static int no_init_out (HWVoiceOut *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, as, 0); + audio_pcm_init_info (&hw->info, as); hw->samples = 1024; return 0; } @@ -87,7 +87,7 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...) static int no_init_in (HWVoiceIn *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, as, 0); + audio_pcm_init_info (&hw->info, as); hw->samples = 1024; return 0; } diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 0bdc8eaab..125e4c8ff 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -453,12 +453,9 @@ static int oss_init_out (HWVoiceOut *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianness; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + audio_pcm_init_info (&hw->info, &obt_as); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; @@ -597,12 +594,9 @@ static int oss_init_in (HWVoiceIn *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianness; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + audio_pcm_init_info (&hw->info, &obt_as); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 9fe212833..f2a6896a5 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -335,12 +335,9 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as) obt_as.freq = obt.freq; obt_as.nchannels = obt.channels; obt_as.fmt = effective_fmt; + obt_as.endianness = endianess; - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianess) - ); + audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; s->initialized = 1; diff --git a/audio/wavaudio.c b/audio/wavaudio.c index ca1e99f4c..c359fc4f2 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -135,7 +135,8 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) hdr[34] = bits16 ? 0x10 : 0x08; - audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0)); + wav_as.endianness = 0; + audio_pcm_init_info (&hw->info, &wav_as); hw->samples = 1024; wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); diff --git a/audio/wavcapture.c b/audio/wavcapture.c index 33f04c50b..7458a5e3e 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -70,6 +70,7 @@ void wav_capture (const char *path, int freq, int bits16, int stereo) as.freq = freq; as.nchannels = 1 << stereo; as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; + as.endianness = 0; ops.state = wav_state_cb; ops.capture = wav_capture_cb; @@ -97,5 +98,5 @@ void wav_capture (const char *path, int freq, int bits16, int stereo) } qemu_put_buffer (wav->f, hdr, sizeof (hdr)); - AUD_add_capture (NULL, &as, 0, &ops, wav); + AUD_add_capture (NULL, &as, &ops, wav); } diff --git a/hw/adlib.c b/hw/adlib.c index f482d1fa8..b47bc3eec 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -301,6 +301,7 @@ int Adlib_init (AudioState *audio) as.freq = conf.freq; as.nchannels = SHIFT; as.fmt = AUD_FMT_S16; + as.endianness = AUDIO_HOST_ENDIANNESS; AUD_register_card (audio, "adlib", &s->card); @@ -310,8 +311,7 @@ int Adlib_init (AudioState *audio) "adlib", s, adlib_callback, - &as, - 0 /* XXX: little endian? */ + &as ); if (!s->voice) { Adlib_fini (s); diff --git a/hw/es1370.c b/hw/es1370.c index 2aa2db9eb..0d2d86116 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -423,6 +423,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) as.freq = new_freq; as.nchannels = 1 << (new_fmt & 1); as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8; + as.endianness = 0; if (i == ADC_CHANNEL) { s->adc_voice = @@ -432,8 +433,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) "es1370.adc", s, es1370_adc_callback, - &as, - 0 /* little endian */ + &as ); } else { @@ -444,8 +444,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) i ? "es1370.dac2" : "es1370.dac1", s, i ? es1370_dac2_callback : es1370_dac1_callback, - &as, - 0 /* litle endian */ + &as ); } } diff --git a/hw/pcspk.c b/hw/pcspk.c index 2e30662a2..0d52b31b4 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -95,7 +95,7 @@ static void pcspk_callback(void *opaque, int free) int pcspk_audio_init(AudioState *audio) { PCSpkState *s = &pcspk_state; - audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8}; + audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0}; if (!audio) { AUD_log(s_spk, "No audio state\n"); @@ -103,7 +103,7 @@ int pcspk_audio_init(AudioState *audio) } AUD_register_card(audio, s_spk, &s->card); - s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as, 0); + s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as); if (!s->voice) { AUD_log(s_spk, "Could not open voice\n"); return -1; diff --git a/hw/sb16.c b/hw/sb16.c index 6443a90d0..04325ac03 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -203,6 +203,7 @@ static void continue_dma8 (SB16State *s) as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; + as.endianness = 0; s->voice = AUD_open_out ( &s->card, @@ -210,8 +211,7 @@ static void continue_dma8 (SB16State *s) "sb16", s, SB_audio_callback, - &as, - 0 /* little endian */ + &as ); } @@ -348,6 +348,7 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; + as.endianness = 0; s->voice = AUD_open_out ( &s->card, @@ -355,8 +356,7 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) "sb16", s, SB_audio_callback, - &as, - 0 /* little endian */ + &as ); } @@ -838,6 +838,7 @@ static void legacy_reset (SB16State *s) as.freq = s->freq; as.nchannels = 1; as.fmt = AUD_FMT_U8; + as.endianness = 0; s->voice = AUD_open_out ( &s->card, @@ -845,8 +846,7 @@ static void legacy_reset (SB16State *s) "sb16", s, SB_audio_callback, - &as, - 0 /* little endian */ + &as ); /* Not sure about that... */ @@ -1371,6 +1371,7 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; + as.endianness = 0; s->voice = AUD_open_out ( &s->card, @@ -1378,8 +1379,7 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) "sb16", s, SB_audio_callback, - &as, - 0 /* little endian */ + &as ); } -- cgit v1.2.3 From 4f2092904d80257dfc9be7569cdf58ffbe0182a8 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 5 Jul 2006 14:39:57 +0000 Subject: Don't include audio.h when building tools. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2043 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.h b/vl.h index 661e4fd5e..8d6a4d95a 100644 --- a/vl.h +++ b/vl.h @@ -37,7 +37,6 @@ #include #include #include -#include "audio/audio.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 @@ -78,6 +77,7 @@ static inline char *realpath(const char *path, char *resolved_path) #else +#include "audio/audio.h" #include "cpu.h" #include "gdbstub.h" -- cgit v1.2.3 From 3d7374c5dab5670891e34d6f5752d6c3e23259dc Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jul 2006 19:53:04 +0000 Subject: monitor/mwait support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2044 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 3 +++ target-i386/helper.c | 28 +++++++++++++++++++++ target-i386/op.c | 15 +++++++++--- target-i386/translate.c | 65 +++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 97 insertions(+), 14 deletions(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index 4ff527f84..609a5869a 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -496,6 +496,9 @@ void save_native_fp_state(CPUState *env); float approx_rsqrt(float a); float approx_rcp(float a); void update_fp_status(void); +void helper_hlt(void); +void helper_monitor(void); +void helper_mwait(void); extern const uint8_t parity_table[256]; extern const uint8_t rclw_table[32]; diff --git a/target-i386/helper.c b/target-i386/helper.c index d7b41ea0b..70e9fae3b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3408,6 +3408,34 @@ void helper_bswapq_T0(void) } #endif +void helper_hlt(void) +{ + env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ + env->hflags |= HF_HALTED_MASK; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); +} + +void helper_monitor(void) +{ + if (ECX != 0) + raise_exception(EXCP0D_GPF); + /* XXX: store address ? */ +} + +void helper_mwait(void) +{ + if (ECX != 0) + raise_exception(EXCP0D_GPF); + /* XXX: not complete but not completely erroneous */ + if (env->cpu_index != 0 || env->next_cpu != NULL) { + /* more than one CPU: do not sleep because another CPU may + wake this one */ + } else { + helper_hlt(); + } +} + float approx_rsqrt(float a) { return 1.0 / sqrt(a); diff --git a/target-i386/op.c b/target-i386/op.c index a9a8665a1..7a3aa7727 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -614,10 +614,17 @@ void OPPROTO op_movq_eip_im64(void) void OPPROTO op_hlt(void) { - env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ - env->hflags |= HF_HALTED_MASK; - env->exception_index = EXCP_HLT; - cpu_loop_exit(); + helper_hlt(); +} + +void OPPROTO op_monitor(void) +{ + helper_monitor(); +} + +void OPPROTO op_mwait(void) +{ + helper_mwait(); } void OPPROTO op_debug(void) diff --git a/target-i386/translate.c b/target-i386/translate.c index c61f964c0..f905f323d 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -100,6 +100,7 @@ typedef struct DisasContext { int popl_esp_hack; /* for correct popl with esp base handling */ int rip_offset; /* only used in x86_64, but left for simplicity */ int cpuid_features; + int cpuid_ext_features; } DisasContext; static void gen_eob(DisasContext *s); @@ -5567,26 +5568,69 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; + rm = modrm & 7; switch(op) { case 0: /* sgdt */ - case 1: /* sidt */ if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (op == 0) - gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); - else - gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); + gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit)); gen_op_st_T0_A0[OT_WORD + s->mem_index](); gen_add_A0_im(s, 2); - if (op == 0) - gen_op_movtl_T0_env(offsetof(CPUX86State,gdt.base)); - else - gen_op_movtl_T0_env(offsetof(CPUX86State,idt.base)); + gen_op_movtl_T0_env(offsetof(CPUX86State, gdt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); break; + case 1: + if (mod == 3) { + switch (rm) { + case 0: /* monitor */ + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || + s->cpl != 0) + goto illegal_op; + gen_jmp_im(pc_start - s->cs_base); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_movq_A0_reg[R_EBX](); + gen_op_addq_A0_AL(); + } else +#endif + { + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_AL(); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + } + gen_add_A0_ds_seg(s); + gen_op_monitor(); + break; + case 1: /* mwait */ + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || + s->cpl != 0) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(s->pc - s->cs_base); + gen_op_mwait(); + gen_eob(s); + break; + default: + goto illegal_op; + } + } else { /* sidt */ + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit)); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + gen_add_A0_im(s, 2); + gen_op_movtl_T0_env(offsetof(CPUX86State, idt.base)); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); + } + break; case 2: /* lgdt */ case 3: /* lidt */ if (mod == 3) @@ -5629,7 +5673,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } else { if (mod == 3) { #ifdef TARGET_X86_64 - if (CODE64(s) && (modrm & 7) == 0) { + if (CODE64(s) && rm == 0) { /* swapgs */ gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base)); gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase)); @@ -6348,6 +6392,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->mem_index = 1 * 4; } dc->cpuid_features = env->cpuid_features; + dc->cpuid_ext_features = env->cpuid_ext_features; #ifdef TARGET_X86_64 dc->lma = (flags >> HF_LMA_SHIFT) & 1; dc->code64 = (flags >> HF_CS64_SHIFT) & 1; -- cgit v1.2.3 From 0de6bb73fd213db5a9d703e10c284c5c0321d82e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jul 2006 19:53:43 +0000 Subject: monitor/mwait workaround git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2045 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kqemu.c b/kqemu.c index 61983d01d..b7a93b0be 100644 --- a/kqemu.c +++ b/kqemu.c @@ -119,7 +119,7 @@ static int is_cpuid_supported(void) static void kqemu_update_cpuid(CPUState *env) { - int critical_features_mask, features; + int critical_features_mask, features, ext_features, ext_features_mask; uint32_t eax, ebx, ecx, edx; /* the following features are kept identical on the host and @@ -130,11 +130,14 @@ static void kqemu_update_cpuid(CPUState *env) CPUID_CMOV | CPUID_CX8 | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_SEP; + ext_features_mask = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR; if (!is_cpuid_supported()) { features = 0; + ext_features = 0; } else { cpuid(1, eax, ebx, ecx, edx); features = edx; + ext_features = ecx; } #ifdef __x86_64__ /* NOTE: on x86_64 CPUs, SYSENTER is not supported in @@ -144,6 +147,8 @@ static void kqemu_update_cpuid(CPUState *env) #endif env->cpuid_features = (env->cpuid_features & ~critical_features_mask) | (features & critical_features_mask); + env->cpuid_ext_features = (env->cpuid_ext_features & ~ext_features_mask) | + (ext_features & ext_features_mask); /* XXX: we could update more of the target CPUID state so that the non accelerated code sees exactly the same CPU features as the accelerated code */ -- cgit v1.2.3 From 718da2b9b0243bd180db9079b98d7d88ee96aa7a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 10 Jul 2006 21:38:17 +0000 Subject: fixed for TCP segmentation offloading - removed dependency on slirp.h (Igor Kovalenko) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2046 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/rtl8139.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 268 insertions(+), 67 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index c41b9d649..9c613a8f9 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -33,13 +33,18 @@ * Implemented PCI timer interrupt (disabled by default) * Implemented Tally Counters, increased VM load/save version * Implemented IP/TCP/UDP checksum task offloading + * + * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading + * Fixed MTU=1500 for produced ethernet frames + * + * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing + * segmentation offloading + * Removed slirp.h dependency + * Added rx/tx buffer reset when enabling rx/tx operation */ #include "vl.h" -/* XXX: such dependency must be suppressed */ -#include - /* debug RTL8139 card */ //#define DEBUG_RTL8139 1 @@ -1364,10 +1369,14 @@ static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) if (val & CmdRxEnb) { DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n")); + + s->currCPlusRxDesc = 0; } if (val & CmdTxEnb) { DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n")); + + s->currCPlusTxDesc = 0; } /* mask unwriteable bits */ @@ -1732,6 +1741,25 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s) return ret; } +static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt) +{ + if (!size) + { + DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n")); + return; + } + + if (TxLoopBack == (s->TxConfig & TxLoopBack)) + { + DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); + rtl8139_do_receive(s, buf, size, do_interrupt); + } + else + { + qemu_send_packet(s->vc, buf, size); + } +} + static int rtl8139_transmit_one(RTL8139State *s, int descriptor) { if (!rtl8139_transmitter_enabled(s)) @@ -1762,15 +1790,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) s->TxStatus[descriptor] |= TxHostOwns; s->TxStatus[descriptor] |= TxStatOK; - if (TxLoopBack == (s->TxConfig & TxLoopBack)) - { - DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); - rtl8139_do_receive(s, txbuffer, txsize, 0); - } - else - { - qemu_send_packet(s->vc, txbuffer, txsize); - } + rtl8139_transfer_frame(s, txbuffer, txsize, 0); DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor)); @@ -1781,6 +1801,93 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) return 1; } +/* structures and macros for task offloading */ +typedef struct ip_header +{ + uint8_t ip_ver_len; /* version and header length */ + uint8_t ip_tos; /* type of service */ + uint16_t ip_len; /* total length */ + uint16_t ip_id; /* identification */ + uint16_t ip_off; /* fragment offset field */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + uint32_t ip_src,ip_dst; /* source and dest address */ +} ip_header; + +#define IP_HEADER_VERSION_4 4 +#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf) +#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2) + +typedef struct tcp_header +{ + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + uint32_t th_seq; /* sequence number */ + uint32_t th_ack; /* acknowledgement number */ + uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */ + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ +} tcp_header; + +typedef struct udp_header +{ + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length */ + uint16_t uh_sum; /* udp checksum */ +} udp_header; + +typedef struct ip_pseudo_header +{ + uint32_t ip_src; + uint32_t ip_dst; + uint8_t zeros; + uint8_t ip_proto; + uint16_t ip_payload; +} ip_pseudo_header; + +#define IP_PROTO_TCP 6 +#define IP_PROTO_UDP 17 + +#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2) +#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f) +#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags)) + +#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off))) + +#define TCP_FLAG_FIN 0x01 +#define TCP_FLAG_PUSH 0x08 + +/* produces ones' complement sum of data */ +static uint16_t ones_complement_sum(uint8_t *data, size_t len) +{ + uint32_t result = 0; + + for (; len > 1; data+=2, len-=2) + { + result += *(uint16_t*)data; + } + + /* add the remainder byte */ + if (len) + { + uint8_t odd[2] = {*data, 0}; + result += *(uint16_t*)odd; + } + + while (result>>16) + result = (result & 0xffff) + (result >> 16); + + return result; +} + +static uint16_t ip_checksum(void *data, size_t len) +{ + return ~ones_complement_sum((uint8_t*)data, len); +} + static int rtl8139_cplus_transmit_one(RTL8139State *s) { if (!rtl8139_transmitter_enabled(s)) @@ -1831,6 +1938,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) #define CP_TX_LS (1<<28) /* large send packet flag */ #define CP_TX_LGSEN (1<<27) +/* large send MSS mask, bits 16...25 */ +#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1) + /* IP checksum offload flag */ #define CP_TX_IPCS (1<<18) /* UDP checksum offload flag */ @@ -1885,6 +1995,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE; s->cplus_txbuffer = malloc(s->cplus_txbuffer_len); s->cplus_txbuffer_offset = 0; + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len)); } while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) @@ -1960,35 +2072,41 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) s->cplus_txbuffer_offset = 0; s->cplus_txbuffer_len = 0; - if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS)) + if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN)) { DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_HLEN 14 + #define ETH_MTU 1500 /* ip packet header */ - register struct ip *ip = 0; + ip_header *ip = 0; int hlen = 0; + uint8_t ip_protocol = 0; + uint16_t ip_data_len = 0; - struct mbuf local_m; + uint8_t *eth_payload_data = 0; + size_t eth_payload_len = 0; - int proto = ntohs(*(uint16_t *)(saved_buffer + 12)); + int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); if (proto == ETH_P_IP) { DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n")); /* not aligned */ - local_m.m_data = saved_buffer + ETH_HLEN; - local_m.m_len = saved_size - ETH_HLEN; + eth_payload_data = saved_buffer + ETH_HLEN; + eth_payload_len = saved_size - ETH_HLEN; - ip = mtod(&local_m, struct ip *); + ip = (ip_header*)eth_payload_data; - if (ip->ip_v != IPVERSION) { - DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", ip->ip_v, IPVERSION)); + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { + DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4)); ip = NULL; } else { - hlen = ip->ip_hl << 2; + hlen = IP_HEADER_LENGTH(ip); + ip_protocol = ip->ip_p; + ip_data_len = be16_to_cpu(ip->ip_len) - hlen; } } @@ -1998,84 +2116,178 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) { DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); - if (hlenlocal_m.m_len) {/* min header length */ + if (hleneth_payload_len) {/* min header length */ /* bad packet header len */ /* or packet too short */ } else { ip->ip_sum = 0; - ip->ip_sum = cksum(&local_m, hlen); + ip->ip_sum = ip_checksum(ip, hlen); DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); } } - if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) { - DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); +#if defined (DEBUG_RTL8139) + int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; +#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n", + ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss)); - u_int8_t ip_protocol = ip->ip_p; - u_int16_t ip_data_len = ntohs(ip->ip_len) - hlen; + int tcp_send_offset = 0; + int send_count = 0; /* maximum IP header length is 60 bytes */ uint8_t saved_ip_header[60]; - memcpy(saved_ip_header, local_m.m_data, hlen); - struct mbuf local_checksum_m; + /* save IP header template; data area is used in tcp checksum calculation */ + memcpy(saved_ip_header, eth_payload_data, hlen); + + /* a placeholder for checksum calculation routine in tcp case */ + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + + /* pointer to TCP header */ + tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + + /* ETH_MTU = ip header len + tcp header len + payload */ + int tcp_data_len = ip_data_len - tcp_hlen; + int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n", + ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size)); + + /* note the cycle below overwrites IP header data, + but restores it from saved_ip_header before sending packet */ + + int is_last_frame = 0; + + for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) + { + uint16_t chunk_size = tcp_chunk_size; + + /* check if this is the last frame */ + if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) + { + is_last_frame = 1; + chunk_size = tcp_data_len - tcp_send_offset; + } + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq))); + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size)); + + if (tcp_send_offset) + { + memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); + } + + /* keep PUSH and FIN flags only for the last frame */ + if (!is_last_frame) + { + TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); + } - local_checksum_m.m_data = local_m.m_data + hlen - 12; - local_checksum_m.m_len = local_m.m_len - hlen + 12; + /* recalculate TCP checksum */ + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); + + p_tcp_hdr->th_sum = 0; + + int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum)); + + p_tcp_hdr->th_sum = tcp_checksum; + + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); + + /* set IP data length and recalculate IP checksum */ + ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); + + /* increment IP id for subsequent frames */ + ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); + + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(eth_payload_data, hlen); + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + + int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size)); + rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0); + + /* add transferred count to TCP sequence number */ + p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); + ++send_count; + } + + /* Stop sending this frame */ + saved_size = 0; + } + else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + memcpy(saved_ip_header, eth_payload_data, hlen); + + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; /* add 4 TCP pseudoheader fields */ /* copy IP source and destination fields */ - memcpy(local_checksum_m.m_data, saved_ip_header + 12, 8); + memcpy(data_to_checksum, saved_ip_header + 12, 8); - if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IPPROTO_TCP) + if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) { DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); - struct tcpiphdr * p_tcpip_hdr = (struct tcpiphdr *)local_checksum_m.m_data; - p_tcpip_hdr->ti_x1 = 0; - p_tcpip_hdr->ti_pr = IPPROTO_TCP; - p_tcpip_hdr->ti_len = htons(ip_data_len); + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); - struct tcphdr* p_tcp_hdr = (struct tcphdr*) (local_checksum_m.m_data+12); + tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); p_tcp_hdr->th_sum = 0; - int tcp_checksum = cksum(&local_checksum_m, ip_data_len + 12); + int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); p_tcp_hdr->th_sum = tcp_checksum; } - else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IPPROTO_UDP) + else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) { DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); - struct udpiphdr * p_udpip_hdr = (struct udpiphdr *)local_checksum_m.m_data; - p_udpip_hdr->ui_x1 = 0; - p_udpip_hdr->ui_pr = IPPROTO_UDP; - p_udpip_hdr->ui_len = htons(ip_data_len); + ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_udpip_hdr->zeros = 0; + p_udpip_hdr->ip_proto = IP_PROTO_UDP; + p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); - struct udphdr* p_udp_hdr = (struct udphdr*) (local_checksum_m.m_data+12); + udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); - int old_csum = p_udp_hdr->uh_sum; p_udp_hdr->uh_sum = 0; - int udp_checksum = cksum(&local_checksum_m, ip_data_len + 12); + int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); - if (old_csum != udp_checksum) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum mismatch old=%04x new=%04x\n", - old_csum, udp_checksum)); - } - p_udp_hdr->uh_sum = udp_checksum; } /* restore IP header */ - memcpy(local_m.m_data, saved_ip_header, hlen); + memcpy(eth_payload_data, saved_ip_header, hlen); } } } @@ -2085,16 +2297,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size)); - if (TxLoopBack == (s->TxConfig & TxLoopBack)) - { - DEBUG_PRINT(("RTL8139: +++ C+ transmit loopback mode\n")); - rtl8139_receive(s, saved_buffer, saved_size); - } - else - { - /* transmit the packet */ - qemu_send_packet(s->vc, saved_buffer, saved_size); - } + rtl8139_transfer_frame(s, saved_buffer, saved_size, 1); /* restore card space if there was no recursion and reset offset */ if (!s->cplus_txbuffer) @@ -2253,8 +2456,6 @@ static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_ DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); - - s->currCPlusTxDesc = 0; } static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) -- cgit v1.2.3 From 9f909fefd52ad9f6a1f1e1b9b0a895cca04b858c Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Jul 2006 23:00:26 +0000 Subject: use posix timers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2047 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index d60e6b832..eadd85c40 100644 --- a/Makefile.target +++ b/Makefile.target @@ -401,7 +401,7 @@ endif ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 ifndef CONFIG_SOLARIS -VL_LIBS=-lutil +VL_LIBS=-lutil -lrt endif endif endif -- cgit v1.2.3 From effedbc915c51bf2f65818960671fef2bf8c54cf Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Jul 2006 23:00:40 +0000 Subject: export cpu_get_real_ticks() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2048 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 3 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 6d6eb1a4c..e21bd543f 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -900,15 +900,107 @@ void cpu_tlb_update_dirty(CPUState *env); void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -/* profiling */ -#ifdef CONFIG_PROFILER -static inline int64_t profile_getclock(void) +/*******************************************/ +/* 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__) && defined(HOST_SOLARIS) + +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 +} +#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; -- cgit v1.2.3 From 1dce7c3c2244a6f149e7afd7b1d84963ed57b7fd Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Jul 2006 23:20:22 +0000 Subject: new clock logic: cpu ticks and virtual clocks are no longer proportional - added timestamps on the stdio console git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2049 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 13 ++- linux-user/main.c | 24 +---- vl.c | 302 +++++++++++++++++++++++++----------------------------- vl.h | 1 + 4 files changed, 153 insertions(+), 187 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 361f4bb93..898d0681e 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -58,10 +58,19 @@ static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) } /* TSC handling */ - uint64_t cpu_get_tsc(CPUX86State *env) { - return qemu_get_clock(vm_clock); + /* Note: when using kqemu, it is more logical to return the host TSC + because kqemu does not trap the RDTSC instruction for + performance reasons */ +#if USE_KQEMU + if (env->kqemu_enabled) { + return cpu_get_real_ticks(); + } else +#endif + { + return cpu_get_ticks(); + } } /* IRQ handling */ diff --git a/linux-user/main.c b/linux-user/main.c index 2250b127a..6c3d5db7e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -107,29 +107,7 @@ int cpu_get_pic_interrupt(CPUState *env) /* timers for rdtsc */ -#if defined(__i386__) - -int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile ("rdtsc" : "=A" (val)); - return val; -} - -#elif defined(__x86_64__) - -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; -} - -#else +#if 0 static uint64_t emu_time; diff --git a/vl.c b/vl.c index e8780dd08..c9992d815 100644 --- a/vl.c +++ b/vl.c @@ -482,114 +482,103 @@ int kbd_mouse_is_absolute(void) return qemu_put_mouse_event_absolute; } -/***********************************************************/ -/* timers */ - -#if defined(__powerpc__) - -static inline uint32_t get_tbl(void) +/* compute with 96 bit intermediate result: (a*b)/c */ +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) { - uint32_t tbl; - asm volatile("mftb %0" : "=r" (tbl)); - return tbl; -} + union { + uint64_t ll; + struct { +#ifdef WORDS_BIGENDIAN + uint32_t high, low; +#else + uint32_t low, high; +#endif + } l; + } u, res; + uint64_t rl, rh; -static inline uint32_t get_tbu(void) -{ - uint32_t tbl; - asm volatile("mftbu %0" : "=r" (tbl)); - return tbl; + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; } -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; -} +/***********************************************************/ +/* real time host monotonic timer */ -#elif defined(__i386__) +#define QEMU_TIMER_BASE 1000000000LL -int64_t cpu_get_real_ticks(void) -{ -#ifdef _WIN32 - LARGE_INTEGER ti; - QueryPerformanceCounter(&ti); - return ti.QuadPart; -#else - int64_t val; - asm volatile ("rdtsc" : "=A" (val)); - return val; -#endif -} +#ifdef WIN32 -#elif defined(__x86_64__) +static int64_t clock_freq; -int64_t cpu_get_real_ticks(void) +static void init_get_clock(void) { - uint32_t low,high; - int64_t val; - asm volatile("rdtsc" : "=a" (low), "=d" (high)); - val = high; - val <<= 32; - val |= low; - return val; + ret = QueryPerformanceFrequency(&freq); + if (ret == 0) { + fprintf(stderr, "Could not calibrate ticks\n"); + exit(1); + } + clock_freq = freq.QuadPart; } -#elif defined(__ia64) - -int64_t cpu_get_real_ticks(void) +static int64_t get_clock(void) { - int64_t val; - asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); - return val; + LARGE_INTEGER ti; + QueryPerformanceCounter(&ti); + return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq); } -#elif defined(__s390__) +#else -int64_t cpu_get_real_ticks(void) +static int use_rt_clock; + +static void init_get_clock(void) { - int64_t val; - asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); - return val; + use_rt_clock = 0; +#if defined(__linux__) + { + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + use_rt_clock = 1; + } + } +#endif } -#elif defined(__sparc__) && defined(HOST_SOLARIS) - -uint64_t cpu_get_real_ticks (void) +static int64_t get_clock(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; +#if defined(__linux__) + if (use_rt_clock) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000LL + ts.tv_nsec; + } else #endif + { + /* XXX: using gettimeofday leads to problems if the date + changes, so it should be avoided. */ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); + } } -#else -#error unsupported CPU #endif +/***********************************************************/ +/* guest cycle counter */ + static int64_t cpu_ticks_prev; static int64_t cpu_ticks_offset; +static int64_t cpu_clock_offset; static int cpu_ticks_enabled; -static inline int64_t cpu_get_ticks(void) +/* return the host CPU cycle counter and handle stop/restart */ +int64_t cpu_get_ticks(void) { if (!cpu_ticks_enabled) { return cpu_ticks_offset; @@ -606,11 +595,24 @@ static inline int64_t cpu_get_ticks(void) } } +/* return the host CPU monotonic timer and handle stop/restart */ +static int64_t cpu_get_clock(void) +{ + int64_t ti; + if (!cpu_ticks_enabled) { + return cpu_clock_offset; + } else { + ti = get_clock(); + return ti + cpu_clock_offset; + } +} + /* enable cpu_get_ticks() */ void cpu_enable_ticks(void) { if (!cpu_ticks_enabled) { cpu_ticks_offset -= cpu_get_real_ticks(); + cpu_clock_offset -= get_clock(); cpu_ticks_enabled = 1; } } @@ -621,69 +623,14 @@ void cpu_disable_ticks(void) { if (cpu_ticks_enabled) { cpu_ticks_offset = cpu_get_ticks(); + cpu_clock_offset = cpu_get_clock(); cpu_ticks_enabled = 0; } } -#ifdef _WIN32 -void cpu_calibrate_ticks(void) -{ - LARGE_INTEGER freq; - int ret; - - ret = QueryPerformanceFrequency(&freq); - if (ret == 0) { - fprintf(stderr, "Could not calibrate ticks\n"); - exit(1); - } - ticks_per_sec = freq.QuadPart; -} - -#else -static int64_t get_clock(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000LL + tv.tv_usec; -} - -void cpu_calibrate_ticks(void) -{ - int64_t usec, ticks; - - usec = get_clock(); - ticks = cpu_get_real_ticks(); - usleep(50 * 1000); - usec = get_clock() - usec; - ticks = cpu_get_real_ticks() - ticks; - ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; -} -#endif /* !_WIN32 */ - -/* compute with 96 bit intermediate result: (a*b)/c */ -uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) -{ - union { - uint64_t ll; - struct { -#ifdef WORDS_BIGENDIAN - uint32_t high, low; -#else - uint32_t low, high; -#endif - } l; - } u, res; - uint64_t rl, rh; - - u.ll = a; - rl = (uint64_t)u.l.low * (uint64_t)b; - rh = (uint64_t)u.l.high * (uint64_t)b; - rh += (rl >> 32); - res.l.high = rh / c; - res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; - return res.ll; -} - +/***********************************************************/ +/* timers */ + #define QEMU_TIMER_REALTIME 0 #define QEMU_TIMER_VIRTUAL 1 @@ -822,28 +769,21 @@ int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { case QEMU_TIMER_REALTIME: -#ifdef _WIN32 - return GetTickCount(); -#else - { - struct tms tp; - - /* Note that using gettimeofday() is not a good solution - for timers because its value change when the date is - modified. */ - if (timer_freq == 100) { - return times(&tp) * 10; - } else { - return ((int64_t)times(&tp) * 1000) / timer_freq; - } - } -#endif + return get_clock() / 1000000; default: case QEMU_TIMER_VIRTUAL: - return cpu_get_ticks(); + return cpu_get_clock(); } } +static void init_timers(void) +{ + init_get_clock(); + ticks_per_sec = QEMU_TIMER_BASE; + rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); + vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL); +} + /* save a timer */ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) { @@ -985,11 +925,8 @@ static int start_rtc_timer(void) #endif /* !defined(_WIN32) */ -static void init_timers(void) +static void init_timer_alarm(void) { - rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); - vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL); - #ifdef _WIN32 { int count=0; @@ -1354,7 +1291,9 @@ CharDriverState *qemu_chr_open_pipe(const char *filename) static int term_got_escape, client_index; static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; -int term_fifo_size; +static int term_fifo_size; +static int term_timestamps; +static int64_t term_timestamps_start; void term_print_help(void) { @@ -1363,6 +1302,7 @@ void term_print_help(void) "C-a x exit emulator\n" "C-a s save disk data back to file (if -snapshot)\n" "C-a b send break (magic sysrq)\n" + "C-a t toggle console timestamps\n" "C-a c switch between console and monitor\n" "C-a C-a send C-a\n" ); @@ -1409,6 +1349,10 @@ static void stdio_received_byte(int ch) goto send_char; } break; + case 't': + term_timestamps = !term_timestamps; + term_timestamps_start = -1; + break; case TERM_ESCAPE: goto send_char; } @@ -1466,6 +1410,39 @@ static void stdio_read(void *opaque) stdio_received_byte(buf[0]); } +static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + FDCharDriver *s = chr->opaque; + if (!term_timestamps) { + return unix_write(s->fd_out, buf, len); + } else { + int i; + char buf1[64]; + + for(i = 0; i < len; i++) { + unix_write(s->fd_out, buf + i, 1); + if (buf[i] == '\n') { + int64_t ti; + int secs; + + ti = get_clock(); + if (term_timestamps_start == -1) + term_timestamps_start = ti; + ti -= term_timestamps_start; + secs = ti / 1000000000; + snprintf(buf1, sizeof(buf1), + "[%02d:%02d:%02d.%03d] ", + secs / 3600, + (secs / 60) % 60, + secs % 60, + (int)((ti / 1000000) % 1000)); + unix_write(s->fd_out, buf1, strlen(buf1)); + } + } + return len; + } +} + /* init terminal so that we can grab keys */ static struct termios oldtty; static int old_fd0_flags; @@ -1511,6 +1488,7 @@ CharDriverState *qemu_chr_open_stdio(void) if (stdio_nb_clients >= STDIO_MAX_CLIENTS) return NULL; chr = qemu_chr_open_fd(0, 1); + chr->chr_write = stdio_write; if (stdio_nb_clients == 0) qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL); client_index = stdio_nb_clients; @@ -5638,6 +5616,7 @@ int main(int argc, char **argv) SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE); #endif init_timers(); + init_timer_alarm(); register_machines(); machine = first_machine; @@ -6128,7 +6107,6 @@ int main(int argc, char **argv) register_savevm("ram", 0, 1, ram_save, ram_load, NULL); init_ioports(); - cpu_calibrate_ticks(); /* terminal init */ if (nographic) { diff --git a/vl.h b/vl.h index 8d6a4d95a..d97f485f3 100644 --- a/vl.h +++ b/vl.h @@ -390,6 +390,7 @@ int qemu_timer_pending(QEMUTimer *ts); extern int64_t ticks_per_sec; extern int pit_min_timer_count; +int64_t cpu_get_ticks(void); void cpu_enable_ticks(void); void cpu_disable_ticks(void); -- cgit v1.2.3 From ec607da7c2f2199a486f8df243f23f509f6ab5c0 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 13 Jul 2006 23:25:11 +0000 Subject: avoid recursive tx git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2050 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index a375f27d9..0826cee16 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -57,6 +57,7 @@ struct PCNetState_st { uint64_t timer; int xmit_pos, recv_pos; uint8_t buffer[4096]; + int tx_busy; }; #ifdef __GNUC__ @@ -659,6 +660,8 @@ static void pcnet_s_reset(PCNetState *s) s->csr[114] = 0x0000; s->csr[122] = 0x0000; s->csr[124] = 0x0000; + + s->tx_busy = 0; } static void pcnet_update_irq(PCNetState *s) @@ -1104,7 +1107,9 @@ static void pcnet_transmit(PCNetState *s) s->csr[0] &= ~0x0008; return; } - + + s->tx_busy = 1; + txagain: if (pcnet_tdte_poll(s)) { struct pcnet_TMD tmd; @@ -1167,6 +1172,8 @@ static void pcnet_transmit(PCNetState *s) if (count--) goto txagain; } + + s->tx_busy = 0; } static void pcnet_poll(PCNetState *s) @@ -1177,7 +1184,13 @@ static void pcnet_poll(PCNetState *s) if (CSR_TDMD(s) || (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) + { + /* prevent recursion */ + if (s->tx_busy) + return; + pcnet_transmit(s); + } } static void pcnet_poll_timer(void *opaque) -- cgit v1.2.3 From a8e5ac33d22c335b792389a5b153bfc02b04fcdc Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 14 Jul 2006 09:36:13 +0000 Subject: win32 compilation - force process affinity on win32 as a workaround for SMP issues git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2051 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/vl.c b/vl.c index c9992d815..77ebd3557 100644 --- a/vl.c +++ b/vl.c @@ -517,6 +517,8 @@ static int64_t clock_freq; static void init_get_clock(void) { + LARGE_INTEGER freq; + int ret; ret = QueryPerformanceFrequency(&freq); if (ret == 0) { fprintf(stderr, "Could not calibrate ticks\n"); @@ -5614,6 +5616,24 @@ int main(int argc, char **argv) } #else SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE); + /* Note: cpu_interrupt() is currently not SMP safe, so we force + QEMU to run on a single CPU */ + { + HANDLE h; + DWORD mask, smask; + int i; + h = GetCurrentProcess(); + if (GetProcessAffinityMask(h, &mask, &smask)) { + for(i = 0; i < 32; i++) { + if (mask & (1 << i)) + break; + } + if (i != 32) { + mask = 1 << i; + SetProcessAffinityMask(h, mask); + } + } + } #endif init_timers(); init_timer_alarm(); -- cgit v1.2.3 From 29b9a3456fdb98a33f48360437d8826415f7c40b Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 14 Jul 2006 09:40:02 +0000 Subject: win32 compilation fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2052 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index 0826cee16..0845cdc3e 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -60,8 +60,10 @@ struct PCNetState_st { int tx_busy; }; +/* XXX: using bitfields for target memory structures is almost surely + not portable, so it should be suppressed ASAP */ #ifdef __GNUC__ -#define PACKED(A) A __attribute__ ((packed)) +#define PACKED_FIELD(A) A __attribute__ ((packed)) #else #error FixMe #endif @@ -152,20 +154,20 @@ struct pcnet_initblk16 { uint16_t ladrf2; uint16_t ladrf3; uint16_t ladrf4; - unsigned PACKED(rdra:24); - unsigned PACKED(res1:5); - unsigned PACKED(rlen:3); - unsigned PACKED(tdra:24); - unsigned PACKED(res2:5); - unsigned PACKED(tlen:3); + unsigned PACKED_FIELD(rdra:24); + unsigned PACKED_FIELD(res1:5); + unsigned PACKED_FIELD(rlen:3); + unsigned PACKED_FIELD(tdra:24); + unsigned PACKED_FIELD(res2:5); + unsigned PACKED_FIELD(tlen:3); }; struct pcnet_initblk32 { uint16_t mode; - unsigned PACKED(res1:4); - unsigned PACKED(rlen:4); - unsigned PACKED(res2:4); - unsigned PACKED(tlen:4); + unsigned PACKED_FIELD(res1:4); + unsigned PACKED_FIELD(rlen:4); + unsigned PACKED_FIELD(res2:4); + unsigned PACKED_FIELD(tlen:4); uint16_t padr1; uint16_t padr2; uint16_t padr3; @@ -183,14 +185,14 @@ struct pcnet_TMD { unsigned tbadr:32; } tmd0; struct { - unsigned PACKED(bcnt:12), PACKED(ones:4), PACKED(res:7), PACKED(bpe:1); - unsigned PACKED(enp:1), PACKED(stp:1), PACKED(def:1), PACKED(one:1); - unsigned PACKED(ltint:1), PACKED(nofcs:1), PACKED(err:1), PACKED(own:1); + unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1); + unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1); + unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); } tmd1; struct { - unsigned PACKED(trc:4), PACKED(res:12); - unsigned PACKED(tdr:10), PACKED(rtry:1), PACKED(lcar:1); - unsigned PACKED(lcol:1), PACKED(exdef:1), PACKED(uflo:1), PACKED(buff:1); + unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12); + unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1); + unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1); } tmd2; struct { unsigned res:32; @@ -202,14 +204,14 @@ struct pcnet_RMD { unsigned rbadr:32; } rmd0; struct { - unsigned PACKED(bcnt:12), PACKED(ones:4), PACKED(res:4); - unsigned PACKED(bam:1), PACKED(lafm:1), PACKED(pam:1), PACKED(bpe:1); - unsigned PACKED(enp:1), PACKED(stp:1), PACKED(buff:1), PACKED(crc:1); - unsigned PACKED(oflo:1), PACKED(fram:1), PACKED(err:1), PACKED(own:1); + unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4); + unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1); + unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1); + unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); } rmd1; struct { - unsigned PACKED(mcnt:12), PACKED(zeros:4); - unsigned PACKED(rpc:8), PACKED(rcc:8); + unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4); + unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8); } rmd2; struct { unsigned res:32; @@ -555,7 +557,7 @@ static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) s->csr[13] & 0xff, s->csr[13] >> 8, s->csr[14] & 0xff, s->csr[14] >> 8 }; - int result = (!CSR_DRCVPA(s)) && !bcmp(hdr->ether_dhost, padr, 6); + int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6); #ifdef PCNET_DEBUG_MATCH printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " "padr=%02x:%02x:%02x:%02x:%02x:%02x\n", @@ -571,7 +573,7 @@ static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) { static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; struct qemu_ether_header *hdr = (void *)buf; - int result = !CSR_DRCVBC(s) && !bcmp(hdr->ether_dhost, BCAST, 6); + int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6); #ifdef PCNET_DEBUG_MATCH printf("padr_bcast result=%d\n", result); #endif -- cgit v1.2.3 From 3c656346c91448f2a42b67e169a9fd4f62e4552e Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 14 Jul 2006 13:13:51 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2053 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- qemu-doc.texi | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index c18d72be3..53a48a1e8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.1 \ No newline at end of file +0.8.2 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index ed5850108..f7da0b37a 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -250,16 +250,19 @@ with a serial console. @item -vnc d Normally, QEMU uses SDL to display the VGA output. With this option, -you can have QEMU listen on VNC display d and redirect the VGA display -over the VNC session. It is very useful to enable the usb tablet device -when using this option (option @option{-usbdevice tablet}). +you can have QEMU listen on VNC display @var{d} and redirect the VGA +display over the VNC session. It is very useful to enable the usb +tablet device when using this option (option @option{-usbdevice +tablet}). When using the VNC display, you must use the @option{-k} +option to set the keyboard layout. @item -k language Use keyboard layout @var{language} (for example @code{fr} for French). This option is only needed where it is not easy to get raw PC -keycodes (e.g. on Macs or with some X11 servers). You don't need to -use it on PC/Linux or PC/Windows hosts. +keycodes (e.g. on Macs, with some X11 servers or with a VNC +display). You don't normally need to use it on PC/Linux or PC/Windows +hosts. The available layouts are: @example @@ -617,6 +620,11 @@ Cirrus Logic GD5446 PCI VGA). If your guest OS supports the VESA 2.0 VBE extensions (e.g. Windows XP) and if you want to use high resolution modes (>= 1280x1024x16) then you should use this option. +@item -no-acpi +Disable ACPI (Advanced Configuration and Power Interface) support. Use +it if your guest OS complains about ACPI problems (PC target machine +only). + @item -loadvm file Start right away with a saved state (@code{loadvm} in monitor) @end table -- cgit v1.2.3 From bd468840d4db56198a3d7ce4692711ddc2217771 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 14 Jul 2006 20:24:31 +0000 Subject: fixed LF interpretation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2054 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/console.c b/console.c index 0dfed7129..f039dfcb3 100644 --- a/console.c +++ b/console.c @@ -619,7 +619,6 @@ static void console_put_lf(TextConsole *s) TextCell *c; int x, y1; - s->x = 0; s->y++; if (s->y >= s->height) { s->y = s->height - 1; @@ -773,6 +772,7 @@ static void console_putchar(TextConsole *s, int ch) 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)); @@ -791,8 +791,10 @@ static void console_putchar(TextConsole *s, int ch) c->t_attrib = s->t_attrib; update_xy(s, s->x, s->y); s->x++; - if (s->x >= s->width) + if (s->x >= s->width) { + s->x = 0; console_put_lf(s); + } break; } break; -- cgit v1.2.3 From 7ba1260ac1637f5d9e3af619e74de3cb39f10ba6 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 14 Jul 2006 20:26:42 +0000 Subject: generate CRLF instead of LF git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2055 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 4 +++- vl.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index 9a18639c4..5edd39e92 100644 --- a/monitor.c +++ b/monitor.c @@ -82,8 +82,10 @@ void term_puts(const char *str) c = *str++; if (c == '\0') break; + if (c == '\n') + term_outbuf[term_outbuf_index++] = '\r'; term_outbuf[term_outbuf_index++] = c; - if (term_outbuf_index >= sizeof(term_outbuf) || + if (term_outbuf_index >= (sizeof(term_outbuf) - 1) || c == '\n') term_flush(); } diff --git a/vl.c b/vl.c index 77ebd3557..6787332ba 100644 --- a/vl.c +++ b/vl.c @@ -6159,7 +6159,7 @@ int main(int argc, char **argv) exit(1); } if (!strcmp(serial_devices[i], "vc")) - qemu_chr_printf(serial_hds[i], "serial%d console\n", i); + qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i); } } @@ -6172,7 +6172,7 @@ int main(int argc, char **argv) exit(1); } if (!strcmp(parallel_devices[i], "vc")) - qemu_chr_printf(parallel_hds[i], "parallel%d console\n", i); + qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); } } -- cgit v1.2.3 From 13224a87fb27a5d029388aa61a1347aa89dd3788 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 14 Jul 2006 22:03:35 +0000 Subject: added mouse event generation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2056 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index 5edd39e92..763acb7ce 100644 --- a/monitor.c +++ b/monitor.c @@ -821,6 +821,26 @@ static void do_send_key(const char *string) } } +static int mouse_button_state; + +static void do_mouse_move(const char *dx_str, const char *dy_str, + const char *dz_str) +{ + int dx, dy, dz; + dx = strtol(dx_str, NULL, 0); + dy = strtol(dy_str, NULL, 0); + dz = 0; + if (dz_str) + dz = strtol(dz_str, NULL, 0); + kbd_mouse_event(dx, dy, dz, mouse_button_state); +} + +static void do_mouse_button(int button_state) +{ + mouse_button_state = button_state; + kbd_mouse_event(0, 0, 0, mouse_button_state); +} + static void do_ioport_read(int count, int format, int size, int addr, int has_index, int index) { uint32_t val; @@ -1109,6 +1129,10 @@ static term_cmd_t term_cmds[] = { "device", "remove USB device 'bus.addr'" }, { "cpu", "i", do_cpu_set, "index", "set the default CPU" }, + { "mouse_move", "sss?", do_mouse_move, + "dx dy [dz]", "send mouse move events" }, + { "mouse_button", "i", do_mouse_button, + "state", "change mouse button state (1=L, 2=M, 4=R)" }, { NULL, NULL, }, }; @@ -1949,7 +1973,6 @@ static void monitor_handle_command(const char *cmdline) while (isspace(*p)) p++; if (*typestr == '?' || *typestr == '.') { - typestr++; if (*typestr == '?') { if (*p == '\0') has_arg = 0; @@ -1965,6 +1988,7 @@ static void monitor_handle_command(const char *cmdline) has_arg = 0; } } + typestr++; if (nb_args >= MAX_ARGS) goto error_args; args[nb_args++] = (void *)has_arg; -- cgit v1.2.3 From 634fce96eba8f332929025dd173a2f14e14a8f90 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 15 Jul 2006 17:40:09 +0000 Subject: Defer timer initialization until after commandline processing. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2057 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 6787332ba..042e12180 100644 --- a/vl.c +++ b/vl.c @@ -5635,8 +5635,6 @@ int main(int argc, char **argv) } } #endif - init_timers(); - init_timer_alarm(); register_machines(); machine = first_machine; @@ -6046,6 +6044,9 @@ int main(int argc, char **argv) setvbuf(stdout, NULL, _IOLBF, 0); + init_timers(); + init_timer_alarm(); + #ifdef _WIN32 socket_init(); #endif -- cgit v1.2.3 From 6330126439a1f08d2a586bb1357622d944a44ec4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Jul 2006 18:56:50 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2058 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index df487a54e..58f3e5e74 100644 --- a/Changelog +++ b/Changelog @@ -8,9 +8,14 @@ version 0.8.2: - Solaris/SPARC host support (Ben Taylor) - PPC breakpoints and single stepping (Jason Wessel) - USB updates (Paul Brook) - - UDP character devices (Jason Wessel) - - TCP character devices + - 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: -- cgit v1.2.3 From ec36b695b0bd054e673854fd1f02fa83e4bebea2 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Jul 2006 18:57:03 +0000 Subject: audio capture to wab files (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2059 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + audio/audio.c | 172 +++++++++++++++++++++++++++++++++++-------------- audio/audio.h | 23 ++++++- audio/audio_int.h | 16 +++-- audio/audio_template.h | 4 +- audio/noaudio.c | 2 +- audio/wavcapture.c | 122 ++++++++++++++++++++++++++--------- monitor.c | 70 ++++++++++++++++++++ 8 files changed, 319 insertions(+), 91 deletions(-) diff --git a/Makefile.target b/Makefile.target index eadd85c40..912a83ee4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -321,6 +321,7 @@ 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 diff --git a/audio/audio.c b/audio/audio.c index dd86c4d7a..9be77c09d 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -510,7 +510,8 @@ static void audio_print_settings (audsettings_t *as) AUD_log (NULL, "invalid(%d)", as->fmt); break; } - AUD_log (NULL, "endianness="); + + AUD_log (NULL, " endianness="); switch (as->endianness) { case 0: AUD_log (NULL, "little"); @@ -525,7 +526,7 @@ static void audio_print_settings (audsettings_t *as) AUD_log (NULL, "\n"); } -static int audio_validate_settigs (audsettings_t *as) +static int audio_validate_settings (audsettings_t *as) { int invalid; @@ -654,15 +655,25 @@ static CaptureVoiceOut *audio_pcm_capture_find_specific ( return NULL; } -static void audio_notify_capture (CaptureVoiceOut *cap, int enabled) +static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd) { - if (cap->hw.enabled != enabled) { - struct capture_callback *cb; + struct capture_callback *cb; + +#ifdef DEBUG_CAPTURE + dolog ("notification %d sent\n", cmd); +#endif + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.notify (cb->opaque, cmd); + } +} +static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled) +{ + if (cap->hw.enabled != enabled) { + audcnotification_e cmd; cap->hw.enabled = enabled; - for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { - cb->ops.state (cb->opaque, enabled); - } + cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE; + audio_notify_capture (cap, cmd); } } @@ -672,29 +683,40 @@ static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap) SWVoiceOut *sw; int enabled = 0; - for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) { + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { if (sw->active) { enabled = 1; break; } } - audio_notify_capture (cap, enabled); + audio_capture_maybe_changed (cap, enabled); } static void audio_detach_capture (HWVoiceOut *hw) { - SWVoiceOut *sw; + SWVoiceCap *sc = hw->cap_head.lh_first; + + while (sc) { + SWVoiceCap *sc1 = sc->entries.le_next; + SWVoiceOut *sw = &sc->sw; + CaptureVoiceOut *cap = sc->cap; + int was_active = sw->active; - for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) { if (sw->rate) { st_rate_stop (sw->rate); sw->rate = NULL; } LIST_REMOVE (sw, entries); - LIST_REMOVE (sw, cap_entries); - qemu_free (sw); - audio_recalc_and_notify_capture ((CaptureVoiceOut *) sw->hw); + LIST_REMOVE (sc, entries); + qemu_free (sc); + if (was_active) { + /* We have removed soft voice from the capture: + this might have changed the overall status of the capture + since this might have been the only active voice */ + audio_recalc_and_notify_capture (cap); + } + sc = sc1; } } @@ -704,19 +726,21 @@ static int audio_attach_capture (AudioState *s, HWVoiceOut *hw) audio_detach_capture (hw); for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + SWVoiceCap *sc; SWVoiceOut *sw; - HWVoiceOut *hw_cap; + HWVoiceOut *hw_cap = &cap->hw; - hw_cap = &cap->hw; - sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); - if (!sw) { + sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc)); + if (!sc) { dolog ("Could not allocate soft capture voice (%zu bytes)\n", - sizeof (*sw)); + sizeof (*sc)); return -1; } - sw->info = hw->info; + sc->cap = cap; + sw = &sc->sw; sw->hw = hw_cap; + sw->info = hw->info; sw->empty = 1; sw->active = hw->enabled; sw->conv = noop_conv; @@ -728,12 +752,14 @@ static int audio_attach_capture (AudioState *s, HWVoiceOut *hw) return -1; } LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries); - LIST_INSERT_HEAD (&hw->sw_cap_head, sw, cap_entries); + LIST_INSERT_HEAD (&hw->cap_head, sc, entries); +#ifdef DEBUG_CAPTURE + asprintf (&sw->name, "for %p %d,%d,%d", + hw, sw->info.freq, sw->info.bits, sw->info.nchannels); + dolog ("Added %s active = %d\n", sw->name, sw->active); +#endif if (sw->active) { - audio_notify_capture (cap, 1); - } - else { - audio_recalc_and_notify_capture (cap); + audio_capture_maybe_changed (cap, 1); } } return 0; @@ -915,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) } if (live == hwsamples) { +#ifdef DEBUG_OUT + dolog ("%s is full %d\n", sw->name, live); +#endif return 0; } @@ -1033,6 +1062,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) hw = sw->hw; if (sw->active != on) { SWVoiceOut *temp_sw; + SWVoiceCap *sc; if (on) { hw->pending_disable = 0; @@ -1053,11 +1083,11 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) hw->pending_disable = nb_active == 1; } } - for (temp_sw = hw->sw_cap_head.lh_first; temp_sw; - temp_sw = temp_sw->entries.le_next) { - temp_sw->active = hw->enabled; + + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + sc->sw.active = hw->enabled; if (hw->enabled) { - audio_notify_capture ((CaptureVoiceOut *) temp_sw->hw, 1); + audio_capture_maybe_changed (sc->cap, 1); } } sw->active = on; @@ -1156,9 +1186,10 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples) int n; if (hw->enabled) { - SWVoiceOut *sw; + SWVoiceCap *sc; - for (sw = hw->sw_cap_head.lh_first; sw; sw = sw->cap_entries.le_next) { + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + SWVoiceOut *sw = &sc->sw; int rpos2 = rpos; n = samples; @@ -1171,8 +1202,9 @@ static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples) sw->buf = hw->mix_buf + rpos2; written = audio_pcm_sw_write (sw, NULL, bytes); if (written - bytes) { - dolog ("Could not mix %d bytes into a capture buffer", - bytes); + dolog ("Could not mix %d bytes into a capture " + "buffer, mixed %d\n", + bytes, written); break; } n -= to_write; @@ -1206,16 +1238,16 @@ static void audio_run_out (AudioState *s) } if (hw->pending_disable && !nb_live) { + SWVoiceCap *sc; #ifdef DEBUG_OUT dolog ("Disabling voice\n"); #endif hw->enabled = 0; hw->pending_disable = 0; hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); - for (sw = hw->sw_cap_head.lh_first; sw; - sw = sw->cap_entries.le_next) { - sw->active = 0; - audio_recalc_and_notify_capture ((CaptureVoiceOut *) sw->hw); + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + sc->sw.active = 0; + audio_recalc_and_notify_capture (sc->cap); } continue; } @@ -1277,15 +1309,18 @@ static void audio_run_out (AudioState *s) } if (cleanup_required) { - restart: - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + SWVoiceOut *sw1; + + sw = hw->sw_head.lh_first; + while (sw) { + sw1 = sw->entries.le_next; if (!sw->active && !sw->callback.fn) { #ifdef DEBUG_PLIVE dolog ("Finishing with old voice\n"); #endif audio_close_out (s, sw); - goto restart; /* play it safe */ } + sw = sw1; } } } @@ -1537,13 +1572,18 @@ static void audio_atexit (void) HWVoiceIn *hwi = NULL; while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { - SWVoiceOut *sw; + SWVoiceCap *sc; hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); hwo->pcm_ops->fini_out (hwo); - for (sw = hwo->sw_cap_head.lh_first; sw; sw = sw->entries.le_next) { - audio_notify_capture ((CaptureVoiceOut *) sw->hw, 0); + for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) { + CaptureVoiceOut *cap = sc->cap; + struct capture_callback *cb; + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.destroy (cb->opaque); + } } } @@ -1697,7 +1737,7 @@ AudioState *AUD_init (void) return s; } -int AUD_add_capture ( +CaptureVoiceOut *AUD_add_capture ( AudioState *s, audsettings_t *as, struct audio_capture_ops *ops, @@ -1712,10 +1752,10 @@ int AUD_add_capture ( s = &glob_audio_state; } - if (audio_validate_settigs (as)) { + if (audio_validate_settings (as)) { dolog ("Invalid settings were passed when trying to add capture\n"); audio_print_settings (as); - return -1; + goto err0; } cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb)); @@ -1730,7 +1770,7 @@ int AUD_add_capture ( cap = audio_pcm_capture_find_specific (s, as); if (cap) { LIST_INSERT_HEAD (&cap->cb_head, cb, entries); - return 0; + return cap; } else { HWVoiceOut *hw; @@ -1780,7 +1820,7 @@ int AUD_add_capture ( while ((hw = audio_pcm_hw_find_any_out (s, hw))) { audio_attach_capture (s, hw); } - return 0; + return cap; err3: qemu_free (cap->hw.mix_buf); @@ -1789,6 +1829,38 @@ int AUD_add_capture ( err1: qemu_free (cb); err0: - return -1; + return NULL; + } +} + +void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) +{ + struct capture_callback *cb; + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + if (cb->opaque == cb_opaque) { + cb->ops.destroy (cb_opaque); + LIST_REMOVE (cb, entries); + qemu_free (cb); + + if (!cap->cb_head.lh_first) { + SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1; + while (sw) { +#ifdef DEBUG_CAPTURE + dolog ("freeing %s\n", sw->name); +#endif + sw1 = sw->entries.le_next; + if (sw->rate) { + st_rate_stop (sw->rate); + sw->rate = NULL; + } + LIST_REMOVE (sw, entries); + sw = sw1; + } + LIST_REMOVE (cap, entries); + qemu_free (cap); + } + return; + } } } diff --git a/audio/audio.h b/audio/audio.h index 14fa3bce9..c097f391b 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -49,13 +49,31 @@ typedef struct { int endianness; } audsettings_t; +typedef enum { + AUD_CNOTIFY_ENABLE, + AUD_CNOTIFY_DISABLE +} audcnotification_e; + struct audio_capture_ops { - void (*state) (void *opaque, int enabled); + void (*notify) (void *opaque, audcnotification_e cmd); void (*capture) (void *opaque, void *buf, int size); + void (*destroy) (void *opaque); }; +struct capture_ops { + void (*info) (void *opaque); + void (*destroy) (void *opaque); +}; + +typedef struct CaptureState { + void *opaque; + struct capture_ops ops; + LIST_ENTRY (CaptureState) entries; +} CaptureState; + typedef struct AudioState AudioState; typedef struct SWVoiceOut SWVoiceOut; +typedef struct CaptureVoiceOut CaptureVoiceOut; typedef struct SWVoiceIn SWVoiceIn; typedef struct QEMUSoundCard { @@ -79,12 +97,13 @@ AudioState *AUD_init (void); void AUD_help (void); void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card); void AUD_remove_card (QEMUSoundCard *card); -int AUD_add_capture ( +CaptureVoiceOut *AUD_add_capture ( AudioState *s, audsettings_t *as, struct audio_capture_ops *ops, void *opaque ); +void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque); SWVoiceOut *AUD_open_out ( QEMUSoundCard *card, diff --git a/audio/audio_int.h b/audio/audio_int.h index f5dcb2c70..1a15d4ced 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -64,10 +64,11 @@ struct audio_pcm_info { int swap_endianness; }; +typedef struct SWVoiceCap SWVoiceCap; + typedef struct HWVoiceOut { int enabled; int pending_disable; - int valid; struct audio_pcm_info info; f_sample *clip; @@ -79,7 +80,7 @@ typedef struct HWVoiceOut { int samples; LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; - LIST_HEAD (sw_cap_listhead, SWVoiceOut) sw_cap_head; + LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; struct audio_pcm_ops *pcm_ops; LIST_ENTRY (HWVoiceOut) entries; } HWVoiceOut; @@ -116,7 +117,6 @@ struct SWVoiceOut { volume_t vol; struct audio_callback callback; LIST_ENTRY (SWVoiceOut) entries; - LIST_ENTRY (SWVoiceOut) cap_entries; }; struct SWVoiceIn { @@ -168,12 +168,18 @@ struct capture_callback { LIST_ENTRY (capture_callback) entries; }; -typedef struct CaptureVoiceOut { +struct CaptureVoiceOut { HWVoiceOut hw; void *buf; LIST_HEAD (cb_listhead, capture_callback) cb_head; LIST_ENTRY (CaptureVoiceOut) entries; -} CaptureVoiceOut; +}; + +struct SWVoiceCap { + SWVoiceOut sw; + CaptureVoiceOut *cap; + LIST_ENTRY (SWVoiceCap) entries; +}; struct AudioState { struct audio_driver *drv; diff --git a/audio/audio_template.h b/audio/audio_template.h index 04b47befe..13e1c3efb 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -269,7 +269,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) hw->pcm_ops = drv->pcm_ops; LIST_INIT (&hw->sw_head); #ifdef DAC - LIST_INIT (&hw->sw_cap_head); + LIST_INIT (&hw->cap_head); #endif if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) { goto err0; @@ -426,7 +426,7 @@ SW *glue (AUD_open_, TYPE) ( s = card->audio; - if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) { + if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) { audio_print_settings (as); goto fail; } diff --git a/audio/noaudio.c b/audio/noaudio.c index 8fb15a224..a3423e5eb 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -102,7 +102,7 @@ static int no_run_in (HWVoiceIn *hw) NoVoiceIn *no = (NoVoiceIn *) hw; int live = audio_pcm_hw_get_live_in (hw); int dead = hw->samples - live; - int samples; + int samples = 0; if (dead) { int64_t now = qemu_get_clock (vm_clock); diff --git a/audio/wavcapture.c b/audio/wavcapture.c index 7458a5e3e..748b58006 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -3,6 +3,11 @@ typedef struct { QEMUFile *f; int bytes; + char *path; + int freq; + int bits; + int nchannels; + CaptureVoiceOut *cap; } WAVState; /* VICE code: Store number as little endian. */ @@ -15,35 +20,39 @@ static void le_store (uint8_t *buf, uint32_t val, int len) } } -static void wav_state_cb (void *opaque, int enabled) +static void wav_notify (void *opaque, audcnotification_e cmd) { - WAVState *wav = opaque; + (void) opaque; + (void) cmd; +} - if (!enabled) { - uint8_t rlen[4]; - uint8_t dlen[4]; - uint32_t datalen = wav->bytes; - uint32_t rifflen = datalen + 36; +static void wav_destroy (void *opaque) +{ + WAVState *wav = opaque; + uint8_t rlen[4]; + uint8_t dlen[4]; + uint32_t datalen = wav->bytes; + uint32_t rifflen = datalen + 36; - if (!wav->f) { - return; - } + if (!wav->f) { + return; + } - le_store (rlen, rifflen, 4); - le_store (dlen, datalen, 4); + le_store (rlen, rifflen, 4); + le_store (dlen, datalen, 4); - qemu_fseek (wav->f, 4, SEEK_SET); - qemu_put_buffer (wav->f, rlen, 4); + qemu_fseek (wav->f, 4, SEEK_SET); + qemu_put_buffer (wav->f, rlen, 4); - qemu_fseek (wav->f, 32, SEEK_CUR); - qemu_put_buffer (wav->f, dlen, 4); - } - else { - qemu_fseek (wav->f, 0, SEEK_END); + qemu_fseek (wav->f, 32, SEEK_CUR); + qemu_put_buffer (wav->f, dlen, 4); + fclose (wav->f); + if (wav->path) { + qemu_free (wav->path); } } -static void wav_capture_cb (void *opaque, void *buf, int size) +static void wav_capture (void *opaque, void *buf, int size) { WAVState *wav = opaque; @@ -51,7 +60,30 @@ static void wav_capture_cb (void *opaque, void *buf, int size) wav->bytes += size; } -void wav_capture (const char *path, int freq, int bits16, int stereo) +static void wav_capture_destroy (void *opaque) +{ + WAVState *wav = opaque; + + AUD_del_capture (wav->cap, wav); +} + +static void wav_capture_info (void *opaque) +{ + WAVState *wav = opaque; + char *path = wav->path; + + term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n", + wav->freq, wav->bits, wav->nchannels, + path ? path : "", wav->bytes); +} + +static struct capture_ops wav_capture_ops = { + .destroy = wav_capture_destroy, + .info = wav_capture_info +}; + +int wav_start_capture (CaptureState *s, const char *path, int freq, + int bits, int nchannels) { WAVState *wav; uint8_t hdr[] = { @@ -62,23 +94,35 @@ void wav_capture (const char *path, int freq, int bits16, int stereo) }; audsettings_t as; struct audio_capture_ops ops; - int shift; + int stereo, bits16, shift; + CaptureVoiceOut *cap; + + if (bits != 8 && bits != 16) { + term_printf ("incorrect bit count %d, must be 8 or 16\n", bits); + return -1; + } + + if (nchannels != 1 && nchannels != 2) { + term_printf ("incorrect channel count %d, must be 1 or 2\n", bits); + return -1; + } - stereo = !!stereo; - bits16 = !!bits16; + stereo = nchannels == 2; + bits16 = bits == 16; as.freq = freq; as.nchannels = 1 << stereo; as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; as.endianness = 0; - ops.state = wav_state_cb; - ops.capture = wav_capture_cb; + ops.notify = wav_notify; + ops.capture = wav_capture; + ops.destroy = wav_destroy; wav = qemu_mallocz (sizeof (*wav)); if (!wav) { AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav)); - return; + return -1; } shift = bits16 + stereo; @@ -91,12 +135,28 @@ void wav_capture (const char *path, int freq, int bits16, int stereo) wav->f = fopen (path, "wb"); if (!wav->f) { - AUD_log ("wav", "Failed to open wave file `%s'\nReason: %s\n", - path, strerror (errno)); + term_printf ("Failed to open wave file `%s'\nReason: %s\n", + path, strerror (errno)); qemu_free (wav); - return; + return -1; } + wav->path = qemu_strdup (path); + wav->bits = bits; + wav->nchannels = nchannels; + wav->freq = freq; + qemu_put_buffer (wav->f, hdr, sizeof (hdr)); - AUD_add_capture (NULL, &as, &ops, wav); + + cap = AUD_add_capture (NULL, &as, &ops, wav); + if (!cap) { + term_printf ("Failed to add audio capture\n"); + qemu_free (wav); + return -1; + } + + wav->cap = cap; + s->opaque = wav; + s->ops = wav_capture_ops; + return 0; } diff --git a/monitor.c b/monitor.c index 763acb7ce..09a0299fc 100644 --- a/monitor.c +++ b/monitor.c @@ -1077,6 +1077,64 @@ static void do_info_profile(void) } #endif +/* Capture support */ +static LIST_HEAD (capture_list_head, CaptureState) capture_head; + +static void do_info_capture (void) +{ + int i; + CaptureState *s; + + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { + term_printf ("[%d]: ", i); + s->ops.info (s->opaque); + } +} + +static void do_stop_capture (int n) +{ + int i; + CaptureState *s; + + for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) { + if (i == n) { + s->ops.destroy (s->opaque); + LIST_REMOVE (s, entries); + qemu_free (s); + return; + } + } +} + +#ifdef HAS_AUDIO +int wav_start_capture (CaptureState *s, const char *path, int freq, + int bits, int nchannels); + +static void do_wav_capture (const char *path, + int has_freq, int freq, + int has_bits, int bits, + int has_channels, int nchannels) +{ + CaptureState *s; + + s = qemu_mallocz (sizeof (*s)); + if (!s) { + term_printf ("Not enough memory to add wave capture\n"); + return; + } + + freq = has_freq ? freq : 44100; + bits = has_bits ? bits : 16; + nchannels = has_channels ? nchannels : 2; + + if (wav_start_capture (s, path, freq, bits, nchannels)) { + term_printf ("Faied to add wave capture\n"); + qemu_free (s); + } + LIST_INSERT_HEAD (&capture_head, s, entries); +} +#endif + static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, @@ -1133,6 +1191,13 @@ static term_cmd_t term_cmds[] = { "dx dy [dz]", "send mouse move events" }, { "mouse_button", "i", do_mouse_button, "state", "change mouse button state (1=L, 2=M, 4=R)" }, +#ifdef HAS_AUDIO + { "wavcapture", "si?i?i?", do_wav_capture, + "path [frequency bits channels]", + "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" }, +#endif + { "stopcapture", "i", do_stop_capture, + "capture index", "stop capture" }, { NULL, NULL, }, }; @@ -1171,6 +1236,8 @@ static term_cmd_t info_cmds[] = { "", "show host USB devices", }, { "profile", "", do_info_profile, "", "show profiling information", }, + { "capture", "", do_info_capture, + "show capture information" }, { NULL, NULL, }, }; @@ -2081,6 +2148,9 @@ static void monitor_handle_command(const char *cmdline) case 6: cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]); break; + case 7: + cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + break; default: term_printf("unsupported number of arguments: %d\n", nb_args); goto fail; -- cgit v1.2.3 From 69db0ac75a07a8a8957bbe72ab93a6e66ecee067 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 17 Jul 2006 18:45:34 +0000 Subject: Fix comment typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2060 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl050.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pl050.c b/hw/pl050.c index a71ccf614..20451e532 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -1,5 +1,5 @@ /* - * Arm PrimeCell PL050 Kyeboard / Mouse Interface + * Arm PrimeCell PL050 Keyboard / Mouse Interface * * Copyright (c) 2006 CodeSourcery. * Written by Paul Brook -- cgit v1.2.3 From a3c259974ea93b160112a9c61101e667664443c3 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Jul 2006 21:09:59 +0000 Subject: audio capture fixes (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2061 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/audio.c | 5 +++++ audio/wavcapture.c | 3 ++- qemu-doc.texi | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/audio/audio.c b/audio/audio.c index 9be77c09d..8e7af1aca 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1845,16 +1845,21 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) if (!cap->cb_head.lh_first) { SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1; + while (sw) { + SWVoiceCap *sc = (SWVoiceCap *) sw; #ifdef DEBUG_CAPTURE dolog ("freeing %s\n", sw->name); #endif + sw1 = sw->entries.le_next; if (sw->rate) { st_rate_stop (sw->rate); sw->rate = NULL; } LIST_REMOVE (sw, entries); + LIST_REMOVE (sc, entries); + qemu_free (sc); sw = sw1; } LIST_REMOVE (cap, entries); diff --git a/audio/wavcapture.c b/audio/wavcapture.c index 748b58006..f55d59cac 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -121,7 +121,8 @@ int wav_start_capture (CaptureState *s, const char *path, int freq, wav = qemu_mallocz (sizeof (*wav)); if (!wav) { - AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav)); + term_printf ("Could not allocate memory for wav capture (%zu bytes)", + sizeof (*wav)); return -1; } diff --git a/qemu-doc.texi b/qemu-doc.texi index f7da0b37a..1e49ccfab 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -741,6 +741,8 @@ show emulated PCI device show USB devices plugged on the virtual USB hub @item info usbhost show all USB host devices +@item info capture +show information about active capturing @end table @item q or quit @@ -755,6 +757,23 @@ Change a removable media. @item screendump filename Save screen into PPM image @var{filename}. +@item wavcapture filename [frequency [bits [channels]]] +Capture audio into @var{filename}. Using sample rate @var{frequency} +bits per sample @var{bits} and number of channels @var{channels}. + +Defaults: +@itemize @minus +@item Sample rate = 44100 Hz - CD quality +@item Bits = 16 +@item Number of channels = 2 - Stereo +@end itemize + +@item stopcapture index +Stop capture with a given @var{index}, index can be obtained with +@example +info capture +@end example + @item log item1[,...] Activate logging of the specified items to @file{/tmp/qemu.log}. -- cgit v1.2.3 From 725cb90bf7e2487fe5aa5621cc10afe6d169e310 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Jul 2006 21:12:17 +0000 Subject: sparc64 fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2062 c046a42c-6fe2-441c-8c8c-71466251a162 --- sparc-dis.c | 4 +++- target-sparc/cpu.h | 1 + target-sparc/op.c | 24 ++++++++++++++++++++++++ target-sparc/translate.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/sparc-dis.c b/sparc-dis.c index 597dc8a70..2be874ac9 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -2887,7 +2887,9 @@ print_insn_sparc (memaddr, info) { const char *name; - if (info->mach == bfd_mach_sparc_v9) + if ((info->mach == bfd_mach_sparc_v8plusa) || + ((info->mach >= bfd_mach_sparc_v9) && + (info->mach <= bfd_mach_sparc_v9b))) name = sparc_decode_asi_v9 (X_ASI (insn)); else name = sparc_decode_asi_v8 (X_ASI (insn)); diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index d0bcd4067..8cbf0b2e3 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -210,6 +210,7 @@ typedef struct CPUSPARCState { uint64_t version; uint64_t fprs; uint64_t tick_cmpr, stick_cmpr; + uint64_t gsr; #endif #if !defined(TARGET_SPARC64) && !defined(reg_T2) target_ulong t2; diff --git a/target-sparc/op.c b/target-sparc/op.c index f6d417f47..7ea209ea8 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1514,6 +1514,9 @@ void OPPROTO op_saved(void) env->cansave++; if (env->otherwin == 0) env->canrestore--; + else + env->otherwin--; + FORCE_RET(); } void OPPROTO op_restored(void) @@ -1525,6 +1528,7 @@ void OPPROTO op_restored(void) env->cansave--; else env->otherwin--; + FORCE_RET(); } void OPPROTO op_popc(void) @@ -1571,3 +1575,23 @@ void OPPROTO op_st_asi() helper_st_asi(PARAM1, PARAM2, PARAM3); } +#ifdef TARGET_SPARC64 +void OPPROTO op_alignaddr() +{ + uint64_t tmp; + + tmp = T0 + T1; + env->gsr &= ~7ULL; + env->gsr |= tmp & 7ULL; + T0 = tmp & ~7ULL; +} + +void OPPROTO op_faligndata() +{ + uint64_t tmp; + + tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8); + tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8); + (*((uint64_t *)&DT0)) = tmp; +} +#endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 26c81454a..4a8ad7061 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -364,6 +364,9 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); case 0x80: /* Primary address space */ \ gen_op_##width##_raw(); \ break; \ + case 0x82: /* Primary address space, non-faulting load */ \ + gen_op_##width##_raw(); \ + break; \ default: \ break; \ } \ @@ -1151,6 +1154,12 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs)); gen_movl_T0_reg(rd); break; + case 0x13: /* Graphics Status */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_movtl_T0_env(offsetof(CPUSPARCState, gsr)); + gen_movl_T0_reg(rd); + break; case 0x17: /* Tick compare */ gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr)); gen_movl_T0_reg(rd); @@ -1166,7 +1175,6 @@ static void disas_sparc_insn(DisasContext * dc) case 0x10: /* Performance Control */ case 0x11: /* Performance Instrumentation Counter */ case 0x12: /* Dispatch Control */ - case 0x13: /* Graphics Status */ case 0x14: /* Softint set, WO */ case 0x15: /* Softint clear, WO */ case 0x16: /* Softint write */ @@ -1870,6 +1878,11 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_sir(); #endif break; + case 0x13: /* Graphics Status */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr)); + break; case 0x17: /* Tick compare */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) @@ -1895,7 +1908,6 @@ static void disas_sparc_insn(DisasContext * dc) case 0x10: /* Performance Control */ case 0x11: /* Performance Instrumentation Counter */ case 0x12: /* Dispatch Control */ - case 0x13: /* Graphics Status */ case 0x14: /* Softint set */ case 0x15: /* Softint clear */ case 0x16: /* Softint write */ @@ -2077,7 +2089,36 @@ static void disas_sparc_insn(DisasContext * dc) } case 0x36: /* UltraSparc shutdown, VIS */ { - // XXX + int opf = GET_FIELD_SP(insn, 5, 13); + rs1 = GET_FIELD(insn, 13, 17); + rs2 = GET_FIELD(insn, 27, 31); + + switch (opf) { + case 0x018: /* VIS I alignaddr */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_movl_reg_T0(rs1); + gen_movl_reg_T1(rs2); + gen_op_alignaddr(); + gen_movl_T0_reg(rd); + break; + case 0x01a: /* VIS I alignaddrl */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + // XXX + break; + case 0x048: /* VIS I faligndata */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_faligndata(); + gen_op_store_DT0_fpr(rd); + break; + default: + goto illegal_insn; + } + break; } #endif default: -- cgit v1.2.3 From 5ef54116ea1c576995f0074b71400bf7bda08cf1 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Jul 2006 21:14:09 +0000 Subject: Sparc64 user emulator fixes (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2063 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 8 +++++--- linux-user/main.c | 22 ++++++++++++++++++++++ target-sparc/translate.c | 4 ++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 687ff77b4..57b5ed27d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -135,11 +135,13 @@ enum #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SPARC ) +#define elf_check_arch(x) ( (x) == EM_SPARCV9 ) #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB -#define ELF_ARCH EM_SPARC +#define ELF_ARCH EM_SPARCV9 + +#define STACK_BIAS 2047 static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { @@ -147,7 +149,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; - regs->u_regs[14] = infop->start_stack - 16 * 4; + regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; } #else diff --git a/linux-user/main.c b/linux-user/main.c index 6c3d5db7e..d1693110f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -473,11 +473,17 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1) static void save_window(CPUSPARCState *env) { +#ifndef TARGET_SPARC64 unsigned int new_wim; new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & ((1LL << NWINDOWS) - 1); save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1)); env->wim = new_wim; +#else + save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1)); + env->cansave++; + env->canrestore--; +#endif } static void restore_window(CPUSPARCState *env) @@ -500,6 +506,12 @@ static void restore_window(CPUSPARCState *env) sp_ptr += sizeof(target_ulong); } env->wim = new_wim; +#ifdef TARGET_SPARC64 + env->canrestore++; + if (env->cleanwin < NWINDOWS - 1) + env->cleanwin++; + env->cansave--; +#endif } static void flush_windows(CPUSPARCState *env) @@ -532,8 +544,12 @@ void cpu_loop (CPUSPARCState *env) trapnr = cpu_sparc_exec (env); switch (trapnr) { +#ifndef TARGET_SPARC64 case 0x88: case 0x90: +#else + case 0x16d: +#endif ret = do_syscall (env, env->gregs[1], env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], @@ -574,6 +590,12 @@ void cpu_loop (CPUSPARCState *env) } break; #else + case TT_SPILL: /* window overflow */ + save_window(env); + break; + case TT_FILL: /* window underflow */ + restore_window(env); + break; // XXX #endif case EXCP_INTERRUPT: diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 4a8ad7061..a522d778b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2731,6 +2731,10 @@ void cpu_reset(CPUSPARCState *env) env->regwptr = env->regbase + (env->cwp * 16); #if defined(CONFIG_USER_ONLY) env->user_mode_only = 1; +#ifdef TARGET_SPARC64 + env->cleanwin = NWINDOWS - 1; + env->cansave = NWINDOWS - 1; +#endif #else env->psrs = 1; env->psrps = 1; -- cgit v1.2.3 From 74ccb34e6b52d06d577b5e3695d86d7f440431df Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 18 Jul 2006 21:23:34 +0000 Subject: Sparc64 host support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2064 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 10 +++++++-- cpu-all.h | 2 +- dyngen-exec.h | 13 +++++++++++ dyngen.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-------- elf.h | 2 ++ linux-user/signal.c | 12 +++++----- 6 files changed, 84 insertions(+), 18 deletions(-) diff --git a/Makefile.target b/Makefile.target index 912a83ee4..91516edf4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -112,7 +112,7 @@ CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3 LDFLAGS+=-m32 OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0 else -CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 LDFLAGS+=-m32 OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat @@ -122,8 +122,9 @@ endif endif ifeq ($(ARCH),sparc64) -CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 LDFLAGS+=-m64 +LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 endif @@ -415,6 +416,11 @@ 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 diff --git a/cpu-all.h b/cpu-all.h index e21bd543f..145d84beb 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -971,7 +971,7 @@ static inline int64_t cpu_get_real_ticks(void) return val; } -#elif defined(__sparc__) && defined(HOST_SOLARIS) +#elif defined(__sparc_v9__) static inline int64_t cpu_get_real_ticks (void) { diff --git a/dyngen-exec.h b/dyngen-exec.h index 0478ade88..0c392283d 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -35,12 +35,15 @@ 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 @@ -50,11 +53,14 @@ 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) @@ -128,6 +134,12 @@ extern int printf(const char *, ...); #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" @@ -141,6 +153,7 @@ extern int printf(const char *, ...); #define AREG10 "l6" #define AREG11 "l7" #endif +#endif #define USE_FP_CONVERT #endif #ifdef __s390__ diff --git a/dyngen.c b/dyngen.c index a8e2958e8..5fb921e28 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1442,9 +1442,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { #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; @@ -1454,18 +1457,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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) { + if (((start_insn & ~0x1fff) == INSN_SAVE) || + (start_insn & ~0x1fff) == INSN_ADD_SP) { p_start += 0x4; start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -128) - error("Found bogus save at the start of %s", name); if (end_insn1 == 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); } @@ -1481,21 +1487,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #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) == 0x9de3a000) { + if (((start_insn & ~0x1fff) == INSN_SAVE) || + (start_insn & ~0x1fff) == INSN_ADD_SP) { p_start += 0x4; start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -256) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + 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); } @@ -2191,7 +2217,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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 = ELF64_R_TYPE(rel->r_info); + type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; reloc_offset = rel->r_offset - start_offset; switch(type) { @@ -2215,6 +2241,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " | ((%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) = " @@ -2225,8 +2260,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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)", type); + error("unsupported sparc64 relocation (%d) for symbol %s", type, name); } } } diff --git a/elf.h b/elf.h index 0dc82e7ca..8ceb94976 100644 --- a/elf.h +++ b/elf.h @@ -227,6 +227,7 @@ typedef struct { #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000) #define R_386_NONE 0 #define R_386_32 1 @@ -326,6 +327,7 @@ typedef struct { #define R_SPARC_10 30 #define R_SPARC_11 31 #define R_SPARC_64 32 +#define R_SPARC_OLO10 33 #define R_SPARC_WDISP16 40 #define R_SPARC_WDISP19 41 #define R_SPARC_7 43 diff --git a/linux-user/signal.c b/linux-user/signal.c index 1e0308b9e..60f9eb767 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1334,28 +1334,28 @@ typedef struct { unsigned long *insn_addr; unsigned long insn; } si_fpqueue [16]; -} __siginfo_fpu_t; +} qemu_siginfo_fpu_t; struct target_signal_frame { struct sparc_stackf ss; __siginfo_t info; - __siginfo_fpu_t *fpu_save; + qemu_siginfo_fpu_t *fpu_save; target_ulong insns[2] __attribute__ ((aligned (8))); target_ulong extramask[TARGET_NSIG_WORDS - 1]; target_ulong extra_size; /* Should be 0 */ - __siginfo_fpu_t fpu_state; + qemu_siginfo_fpu_t fpu_state; }; struct target_rt_signal_frame { struct sparc_stackf ss; siginfo_t info; target_ulong regs[20]; sigset_t mask; - __siginfo_fpu_t *fpu_save; + qemu_siginfo_fpu_t *fpu_save; unsigned int insns[2]; stack_t stack; unsigned int extra_size; /* Should be 0 */ - __siginfo_fpu_t fpu_state; + qemu_siginfo_fpu_t fpu_state; }; #define UREG_O0 16 @@ -1500,7 +1500,7 @@ sigsegv: force_sig(TARGET_SIGSEGV); } static inline int -restore_fpu_state(CPUState *env, __siginfo_fpu_t *fpu) +restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu) { int err; #if 0 -- cgit v1.2.3 From 3b2ccc57c74a3a7405dabd36f7abacd3eff46b46 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Jul 2006 17:54:57 +0000 Subject: Linux compilation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2065 c046a42c-6fe2-441c-8c8c-71466251a162 --- usb-linux.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/usb-linux.c b/usb-linux.c index aa1ded23d..420382be9 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -26,6 +26,7 @@ #if defined(__linux__) #include #include +#include #include #include @@ -59,6 +60,14 @@ typedef struct USBHostDevice { static void usb_host_handle_reset(USBDevice *dev, int destroy) { + USBHostDevice *s = (USBHostDevice *)dev; + + if (destroy) { + if (s->fd >= 0) + close(s->fd); + qemu_free(s); + return; + } #if 0 USBHostDevice *s = (USBHostDevice *)dev; /* USBDEVFS_RESET, but not the first time as it has already be -- cgit v1.2.3 From 059809e45160fda714edf645902db95e262886e9 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 19 Jul 2006 18:06:15 +0000 Subject: usb destroy API change (Lonnie Mendez) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2066 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hid.c | 18 +++++++++++------- hw/usb-hub.c | 12 +++++++++--- hw/usb-msd.c | 16 ++++++++++------ hw/usb.c | 5 +---- hw/usb.h | 5 +++-- usb-linux.c | 20 +++++++++++--------- vl.c | 3 +++ 7 files changed, 48 insertions(+), 31 deletions(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 93f46dbf9..8fc0b744b 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -323,16 +323,10 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) return l; } -static void usb_mouse_handle_reset(USBDevice *dev, int destroy) +static void usb_mouse_handle_reset(USBDevice *dev) { USBMouseState *s = (USBMouseState *)dev; - if (destroy) { - qemu_add_mouse_event_handler(NULL, NULL, 0); - qemu_free(s); - return; - } - s->dx = 0; s->dy = 0; s->dz = 0; @@ -506,6 +500,14 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, return ret; } +static void usb_mouse_handle_destroy(USBDevice *dev) +{ + USBMouseState *s = (USBMouseState *)dev; + + qemu_add_mouse_event_handler(NULL, NULL, 0); + qemu_free(s); +} + USBDevice *usb_tablet_init(void) { USBMouseState *s; @@ -519,6 +521,7 @@ USBDevice *usb_tablet_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_TABLET; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); @@ -539,6 +542,7 @@ USBDevice *usb_mouse_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_MOUSE; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 2eba905ff..8350931be 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -199,11 +199,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) } } -static void usb_hub_handle_reset(USBDevice *dev, int destroy) +static void usb_hub_handle_reset(USBDevice *dev) { /* XXX: do it */ - if (destroy) - qemu_free(dev); } static int usb_hub_handle_control(USBDevice *dev, int request, int value, @@ -525,6 +523,13 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); } +static void usb_hub_handle_destroy(USBDevice *dev) +{ + USBHubState *s = (USBHubState *)dev; + + qemu_free(s); +} + USBDevice *usb_hub_init(int nb_ports) { USBHubState *s; @@ -543,6 +548,7 @@ USBDevice *usb_hub_init(int nb_ports) s->dev.handle_reset = usb_hub_handle_reset; s->dev.handle_control = usb_hub_handle_control; s->dev.handle_data = usb_hub_handle_data; + s->dev.handle_destroy = usb_hub_handle_destroy; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub"); diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 3dccfb955..ff2047d4b 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -112,16 +112,12 @@ static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail) s->mode = USB_MSDM_CSW; } -static void usb_msd_handle_reset(USBDevice *dev, int destroy) +static void usb_msd_handle_reset(USBDevice *dev) { MSDState *s = (MSDState *)dev; DPRINTF("Reset\n"); s->mode = USB_MSDM_CBW; - if (destroy) { - scsi_disk_destroy(s->scsi_dev); - qemu_free(s); - } } static int usb_msd_handle_control(USBDevice *dev, int request, int value, @@ -369,6 +365,13 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, return ret; } +static void usb_msd_handle_destroy(USBDevice *dev) +{ + MSDState *s = (MSDState *)dev; + + scsi_disk_destroy(s->scsi_dev); + qemu_free(s); +} USBDevice *usb_msd_init(const char *filename) { @@ -388,11 +391,12 @@ USBDevice *usb_msd_init(const char *filename) s->dev.handle_reset = usb_msd_handle_reset; s->dev.handle_control = usb_msd_handle_control; s->dev.handle_data = usb_msd_handle_data; + s->dev.handle_destroy = usb_msd_handle_destroy; snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", filename); s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); - usb_msd_handle_reset((USBDevice *)s, 0); + usb_msd_handle_reset((USBDevice *)s); return (USBDevice *)s; } diff --git a/hw/usb.c b/hw/usb.c index a00d94532..34aac5fa9 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -55,10 +55,7 @@ int usb_generic_handle_packet(USBDevice *s, int pid, s->remote_wakeup = 0; s->addr = 0; s->state = USB_STATE_DEFAULT; - s->handle_reset(s, 0); - break; - case USB_MSG_DESTROY: - s->handle_reset(s, 1); + s->handle_reset(s); break; case USB_TOKEN_SETUP: if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) diff --git a/hw/usb.h b/hw/usb.h index b0887d680..98fde0656 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -29,7 +29,6 @@ #define USB_MSG_ATTACH 0x100 #define USB_MSG_DETACH 0x101 #define USB_MSG_RESET 0x102 -#define USB_MSG_DESTROY 0x103 #define USB_RET_NODEV (-1) #define USB_RET_NAK (-2) @@ -117,12 +116,14 @@ struct USBDevice { int (*handle_packet)(USBDevice *dev, int pid, uint8_t devaddr, uint8_t devep, uint8_t *data, int len); + void (*handle_destroy)(USBDevice *dev); + int speed; /* The following fields are used by the generic USB device layer. They are here just to avoid creating a new structure for them. */ - void (*handle_reset)(USBDevice *dev, int destroy); + void (*handle_reset)(USBDevice *dev); int (*handle_control)(USBDevice *dev, int request, int value, int index, int length, uint8_t *data); int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, diff --git a/usb-linux.c b/usb-linux.c index 420382be9..0a13753d4 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -58,16 +58,8 @@ typedef struct USBHostDevice { int fd; } USBHostDevice; -static void usb_host_handle_reset(USBDevice *dev, int destroy) +static void usb_host_handle_reset(USBDevice *dev) { - USBHostDevice *s = (USBHostDevice *)dev; - - if (destroy) { - if (s->fd >= 0) - close(s->fd); - qemu_free(s); - return; - } #if 0 USBHostDevice *s = (USBHostDevice *)dev; /* USBDEVFS_RESET, but not the first time as it has already be @@ -76,6 +68,15 @@ static void usb_host_handle_reset(USBDevice *dev, int destroy) #endif } +static void usb_host_handle_destroy(USBDevice *dev) +{ + USBHostDevice *s = (USBHostDevice *)dev; + + if (s->fd >= 0) + close(s->fd); + qemu_free(s); +} + static int usb_host_handle_control(USBDevice *dev, int request, int value, @@ -244,6 +245,7 @@ USBDevice *usb_host_device_open(const char *devname) dev->dev.handle_reset = usb_host_handle_reset; dev->dev.handle_control = usb_host_handle_control; dev->dev.handle_data = usb_host_handle_data; + dev->dev.handle_destroy = usb_host_handle_destroy; if (product_name[0] == '\0') snprintf(dev->dev.devname, sizeof(dev->dev.devname), diff --git a/vl.c b/vl.c index 042e12180..657116b00 100644 --- a/vl.c +++ b/vl.c @@ -3781,6 +3781,7 @@ static int usb_device_del(const char *devname) { USBPort *port; USBPort **lastp; + USBDevice *dev; int bus_num, addr; const char *p; @@ -3805,8 +3806,10 @@ static int usb_device_del(const char *devname) if (!port) return -1; + dev = port->dev; *lastp = port->next; usb_attach(port, NULL); + dev->handle_destroy(dev); port->next = free_usb_ports; free_usb_ports = port; return 0; -- cgit v1.2.3 From d07edbfa0022c86567f3460378008a654e532820 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 21 Jul 2006 22:39:57 +0000 Subject: Fix Arm cp15 c13 (Process ID) register writes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2067 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 60eee5c2c..2ed46a29b 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -494,10 +494,18 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 13: /* Process ID. */ switch (op2) { case 0: - env->cp15.c9_data = val; + /* Unlike real hardware the qemu TLB uses virtual addresses, + not modified virtual addresses, so this causes a TLB flush. + */ + if (env->cp15.c13_fcse != val) + tlb_flush(env, 1); + env->cp15.c13_fcse = val; break; case 1: - env->cp15.c9_insn = val; + /* This changes the ASID, so do a TLB flush. */ + if (env->cp15.c13_context != val) + tlb_flush(env, 0); + env->cp15.c13_context = val; break; default: goto bad_reg; -- cgit v1.2.3 From 47dbd1f32d24648b7e8c7291ae3c88d4639cecf1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 22 Jul 2006 17:06:44 +0000 Subject: error display fix (malc) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2068 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/wavcapture.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/audio/wavcapture.c b/audio/wavcapture.c index f55d59cac..0f6f7bf01 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -103,7 +103,8 @@ int wav_start_capture (CaptureState *s, const char *path, int freq, } if (nchannels != 1 && nchannels != 2) { - term_printf ("incorrect channel count %d, must be 1 or 2\n", bits); + term_printf ("incorrect channel count %d, must be 1 or 2\n", + nchannels); return -1; } -- cgit v1.2.3 From f3a9676a6038dbfc717f2225eb9d9416de4ea159 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 29 Jul 2006 19:09:31 +0000 Subject: Arm host build fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2070 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 60239d4b9..eeeeb8f5d 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1404,7 +1404,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, is_write = 0; return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, - &uc->uc_sigmask); + &uc->uc_sigmask, puc); } #elif defined(__mc68000) -- cgit v1.2.3 From 46152182100e68f7f8aa4954af1bf91160bb3d15 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 30 Jul 2006 19:16:29 +0000 Subject: Rewrite Arm host support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2071 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm.ld | 25 ++++++ cpu-all.h | 9 +++ disas.c | 6 +- dyngen.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++-------------- dyngen.h | 60 ++++++++++---- elf.h | 2 + 6 files changed, 295 insertions(+), 78 deletions(-) diff --git a/arm.ld b/arm.ld index 61f4c3486..e216cbfa7 100644 --- a/arm.ld +++ b/arm.ld @@ -53,6 +53,10 @@ SECTIONS .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. */ @@ -63,7 +67,28 @@ SECTIONS *(.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) diff --git a/cpu-all.h b/cpu-all.h index 145d84beb..996289eaf 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -992,6 +992,15 @@ static inline int64_t cpu_get_real_ticks (void) 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 */ diff --git a/disas.c b/disas.c index fd91b9220..27b677792 100644 --- a/disas.c +++ b/disas.c @@ -271,11 +271,9 @@ void disas(FILE *out, void *code, unsigned long size) for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) { fprintf(out, "0x%08lx: ", pc); #ifdef __arm__ - /* since data are included in the code, it is better to + /* since data is included in the code, it is better to display code data too */ - if (is_host) { - fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); - } + fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); #endif count = print_insn(pc, &disasm_info); fprintf(out, "\n"); diff --git a/dyngen.c b/dyngen.c index 5fb921e28..2d93283d6 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1255,90 +1255,149 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, { uint8_t *p; uint32_t insn; - int offset, min_offset, pc_offset, data_size; + 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; + 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: ldr pc offset must be 32 bit aligned", + 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: ldr pc offset must point inside the function code", + 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) { - /* ldr position */ + /* The intruction position */ fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", p - p_start); - /* ldr data index */ - data_index = ((p_end - p_start) - pc_offset - 4) >> 2; - fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", + /* 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"); - if (data_index >= sizeof(data_allocated)) - error("%s: too many data", name); - if (!data_allocated[data_index]) { - ELF_RELOC *rel; - int i, addend, type; - const char *sym_name, *p; - char relname[1024]; - - data_allocated[data_index] = 1; - - /* 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"); - } } } p += 4; } + + /* Copy and relocate the constant pool data. */ data_size = (p_end - p_start) - min_offset; if (data_size > 0 && outfile) { - fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2); + 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++; + } } - /* the last instruction must be a mov pc, lr */ if (p == p_start) goto arm_ret_error; p -= 4; insn = get32((uint32_t *)p); - if ((insn & 0xffff0000) != 0xe91b0000) { + /* 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; + return p - p_start; } #endif @@ -1537,6 +1596,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #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 || @@ -1545,6 +1606,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); } @@ -2282,7 +2349,37 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); @@ -2303,6 +2400,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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; @@ -2407,6 +2506,28 @@ int gen_file(FILE *outfile, int out_type) } 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" @@ -2417,10 +2538,36 @@ fprintf(outfile, " 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;\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 { @@ -2489,9 +2636,23 @@ fprintf(outfile, /* Generate prologue, if needed. */ fprintf(outfile, -" for(;;) {\n" -" switch(*opc_ptr++) {\n" -); +" 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; @@ -2525,17 +2686,6 @@ fprintf(outfile, " goto the_end;\n" " }\n"); -#ifdef HOST_ARM -/* generate constant table if needed */ -fprintf(outfile, -" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n" -" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n" -" last_gen_code_ptr = gen_code_ptr;\n" -" arm_ldr_ptr = arm_ldr_table;\n" -" arm_data_ptr = arm_data_table;\n" -" }\n"); -#endif - fprintf(outfile, " }\n" @@ -2553,7 +2703,10 @@ fprintf(outfile, /* generate some code patching */ #ifdef HOST_ARM -fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n"); +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"); diff --git a/dyngen.h b/dyngen.h index fe0a9364e..2a87c448f 100644 --- a/dyngen.h +++ b/dyngen.h @@ -19,7 +19,7 @@ */ int __op_param1, __op_param2, __op_param3; -#ifdef __sparc__ +#if defined(__sparc__) || defined(__arm__) void __op_gen_label1(){} void __op_gen_label2(){} void __op_gen_label3(){} @@ -145,18 +145,16 @@ void fix_bsr(void *p, int offset) { #ifdef __arm__ -#define MAX_OP_SIZE (128 * 4) /* in bytes */ -/* max size of the code that can be generated without calling arm_flush_ldr */ -#define MAX_FRAG_SIZE (1024 * 4) -//#define MAX_FRAG_SIZE (135 * 4) /* for testing */ +#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[1024]; +static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE]; extern char exec_loop; @@ -175,8 +173,9 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, int offset, data_size, target; uint8_t *data_ptr; uint32_t insn; + uint32_t mask; - data_size = (uint8_t *)data_end - (uint8_t *)data_start; + data_size = (data_end - data_start) << 2; if (gen_jmp) { /* generate branch to skip the data */ @@ -198,17 +197,48 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + (unsigned long)data_ptr - (unsigned long)ptr - 8; - insn = *ptr & ~(0xfff | 0x00800000); if (offset < 0) { - offset = - offset; - } else { - insn |= 0x00800000; - } - if (offset > 0xfff) { - fprintf(stderr, "Error ldr offset\n"); + fprintf(stderr, "Negative constant pool offset\n"); abort(); } - insn |= offset; + 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; diff --git a/elf.h b/elf.h index 8ceb94976..1825d50e8 100644 --- a/elf.h +++ b/elf.h @@ -502,6 +502,8 @@ typedef struct { #define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ #define R_ARM_GOT32 26 /* 32 bit GOT entry */ #define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 #define R_ARM_GNU_VTENTRY 100 #define R_ARM_GNU_VTINHERIT 101 #define R_ARM_THM_PC11 102 /* thumb unconditional branch */ -- cgit v1.2.3 From d62ca2bb9be6d6af2c0cbda47a6d7e51548060bf Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Aug 2006 15:50:14 +0000 Subject: removed unused code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2072 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 195 ---------------------------------------------------------------- osdep.h | 4 +- 2 files changed, 1 insertion(+), 198 deletions(-) diff --git a/osdep.c b/osdep.c index ffa29fe8e..c1dd294e6 100644 --- a/osdep.c +++ b/osdep.c @@ -112,13 +112,6 @@ __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; p return __res; \ } -int qemu_write(int fd, const void *buf, size_t n) -{ - QEMU_SYSCALL3(write, fd, buf, n); -} - - - /****************************************************************/ /* shmat replacement */ @@ -284,16 +277,6 @@ void *get_mmap_addr(unsigned long size) #include #endif -int qemu_write(int fd, const void *buf, size_t n) -{ - int ret; - ret = write(fd, buf, n); - if (ret < 0) - return -errno; - else - return ret; -} - void *get_mmap_addr(unsigned long size) { return NULL; @@ -462,181 +445,3 @@ char *qemu_strdup(const char *str) strcpy(ptr, str); return ptr; } - -/****************************************************************/ -/* printf support */ - -static inline int qemu_isdigit(int c) -{ - return c >= '0' && c <= '9'; -} - -#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) - -/* from BSD ppp sources */ -int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args) -{ - int c, i, n; - int width, prec, fillch; - int base, len, neg; - unsigned long val = 0; - const char *f; - char *str, *buf0; - char num[32]; - static const char hexchars[] = "0123456789abcdef"; - - buf0 = buf; - --buflen; - while (buflen > 0) { - for (f = fmt; *f != '%' && *f != 0; ++f) - ; - if (f > fmt) { - len = f - fmt; - if (len > buflen) - len = buflen; - memcpy(buf, fmt, len); - buf += len; - buflen -= len; - fmt = f; - } - if (*fmt == 0) - break; - c = *++fmt; - width = prec = 0; - fillch = ' '; - if (c == '0') { - fillch = '0'; - c = *++fmt; - } - if (c == '*') { - width = va_arg(args, int); - c = *++fmt; - } else { - while (qemu_isdigit(c)) { - width = width * 10 + c - '0'; - c = *++fmt; - } - } - if (c == '.') { - c = *++fmt; - if (c == '*') { - prec = va_arg(args, int); - c = *++fmt; - } else { - while (qemu_isdigit(c)) { - prec = prec * 10 + c - '0'; - c = *++fmt; - } - } - } - /* modifiers */ - switch(c) { - case 'l': - c = *++fmt; - break; - default: - break; - } - str = 0; - base = 0; - neg = 0; - ++fmt; - switch (c) { - case 'd': - i = va_arg(args, int); - if (i < 0) { - neg = 1; - val = -i; - } else - val = i; - base = 10; - break; - case 'o': - val = va_arg(args, unsigned int); - base = 8; - break; - case 'x': - case 'X': - val = va_arg(args, unsigned int); - base = 16; - break; - case 'p': - val = (unsigned long) va_arg(args, void *); - base = 16; - neg = 2; - break; - case 's': - str = va_arg(args, char *); - break; - case 'c': - num[0] = va_arg(args, int); - num[1] = 0; - str = num; - break; - default: - *buf++ = '%'; - if (c != '%') - --fmt; /* so %z outputs %z etc. */ - --buflen; - continue; - } - if (base != 0) { - str = num + sizeof(num); - *--str = 0; - while (str > num + neg) { - *--str = hexchars[val % base]; - val = val / base; - if (--prec <= 0 && val == 0) - break; - } - switch (neg) { - case 1: - *--str = '-'; - break; - case 2: - *--str = 'x'; - *--str = '0'; - break; - } - len = num + sizeof(num) - 1 - str; - } else { - len = strlen(str); - if (prec > 0 && len > prec) - len = prec; - } - if (width > 0) { - if (width > buflen) - width = buflen; - if ((n = width - len) > 0) { - buflen -= n; - for (; n > 0; --n) - *buf++ = fillch; - } - } - if (len > buflen) - len = buflen; - memcpy(buf, str, len); - buf += len; - buflen -= len; - } - *buf = 0; - return buf - buf0; -} - -void qemu_vprintf(const char *fmt, va_list ap) -{ - char buf[1024]; - int len; - - len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap); - qemu_write(1, buf, len); -} - -void qemu_printf(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - qemu_vprintf(fmt, ap); - va_end(ap); -} - diff --git a/osdep.h b/osdep.h index 29a261cbd..661e6e86a 100644 --- a/osdep.h +++ b/osdep.h @@ -3,9 +3,7 @@ #include -int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args); -void qemu_vprintf(const char *fmt, va_list ap); -void qemu_printf(const char *fmt, ...); +#define qemu_printf printf void *qemu_malloc(size_t size); void *qemu_mallocz(size_t size); -- cgit v1.2.3 From 93b6b2a3cd2bf7844dd2a9000cb4feefe7b0f597 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Aug 2006 15:51:11 +0000 Subject: show backing file name git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2073 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qemu-img.c b/qemu-img.c index c5a8e1a61..8b2acad14 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -638,6 +638,8 @@ static int img_info(int argc, char **argv) BlockDriverState *bs; char fmt_name[128], size_buf[128], dsize_buf[128]; int64_t total_sectors, allocated_size; + char backing_filename[1024]; + char backing_filename2[1024]; fmt = NULL; for(;;) { @@ -688,6 +690,13 @@ static int img_info(int argc, char **argv) dsize_buf); if (bdrv_is_encrypted(bs)) printf("encrypted: yes\n"); + bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); + if (backing_filename[0] != '\0') + path_combine(backing_filename2, sizeof(backing_filename2), + filename, backing_filename); + printf("backing file: %s (actual path: %s)\n", + backing_filename, + backing_filename2); bdrv_delete(bs); return 0; } -- cgit v1.2.3 From 7954c73498b7e782ba5db2993637daef456b6310 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Aug 2006 15:52:40 +0000 Subject: commit to specific devices git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2074 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/monitor.c b/monitor.c index 09a0299fc..b48e8cc70 100644 --- a/monitor.c +++ b/monitor.c @@ -167,13 +167,16 @@ static void do_help(const char *name) help_cmd(name); } -static void do_commit(void) +static void do_commit(const char *device) { - int i; - + int i, all_devices; + + all_devices = !strcmp(device, "all"); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { - bdrv_commit(bs_table[i]); + if (all_devices || + !strcmp(bdrv_get_device_name(bs_table[i]), device)) + bdrv_commit(bs_table[i]); } } } @@ -1138,8 +1141,8 @@ static void do_wav_capture (const char *path, static term_cmd_t term_cmds[] = { { "help|?", "s?", do_help, "[cmd]", "show the help" }, - { "commit", "", do_commit, - "", "commit changes to the disk images (if -snapshot is used)" }, + { "commit", "s", do_commit, + "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" }, { "info", "s?", do_info, "subcommand", "show various information about the system state" }, { "q|quit", "", do_quit, -- cgit v1.2.3 From 83f6409109acd7cd13ff8a603f29c46033c4fb00 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 1 Aug 2006 16:21:11 +0000 Subject: async file I/O API git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2075 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 5 + Makefile | 12 +- Makefile.target | 3 +- block-bochs.c | 6 +- block-cloop.c | 6 +- block-cow.c | 38 ++- block-dmg.c | 8 +- block-qcow.c | 368 ++++++++++++++++++----- block-raw.c | 817 +++++++++++++++++++++++++++++++++++++++++++++++++++ block-vmdk.c | 2 +- block-vpc.c | 13 +- block-vvfat.c | 22 +- block.c | 885 ++++++++++++++++++++++++++++++++++++-------------------- block_int.h | 32 +- vl.c | 79 ++++- vl.h | 58 +++- 16 files changed, 1898 insertions(+), 456 deletions(-) create mode 100644 block-raw.c diff --git a/Changelog b/Changelog index 58f3e5e74..693ce4ed3 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,8 @@ +version 0.8.3: + + - Support for relative paths in backing files for disk images + - Async file I/O API + version 0.8.2: - ACPI support diff --git a/Makefile b/Makefile index d6e6f61eb..28a4f861b 100644 --- a/Makefile +++ b/Makefile @@ -25,14 +25,22 @@ else DOCS= endif +ifndef CONFIG_DARWIN +ifndef CONFIG_WIN32 +ifndef CONFIG_SOLARIS +LIBS+=-lrt +endif +endif +endif + 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 block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c + +qemu-img$(EXESUF): qemu-img.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 $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c diff --git a/Makefile.target b/Makefile.target index 91516edf4..04cdb21af 100644 --- a/Makefile.target +++ b/Makefile.target @@ -289,7 +289,8 @@ ifeq ($(ARCH),alpha) endif # must use static linking to avoid leaving stuff in virtual address space -VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.o +VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.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 ifdef CONFIG_WIN32 VL_OBJS+=tap-win32.o diff --git a/block-bochs.c b/block-bochs.c index 62317aff3..febb4d3fd 100644 --- a/block-bochs.c +++ b/block-bochs.c @@ -85,15 +85,15 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int bochs_open(BlockDriverState *bs, const char *filename) +static int bochs_open(BlockDriverState *bs, const char *filename, int flags) { BDRVBochsState *s = bs->opaque; int fd, i; struct bochs_header bochs; - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + fd = open(filename, O_RDWR | O_BINARY); if (fd < 0) { - fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; } diff --git a/block-cloop.c b/block-cloop.c index c617e1b64..f51c32d1b 100644 --- a/block-cloop.c +++ b/block-cloop.c @@ -50,14 +50,14 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int cloop_open(BlockDriverState *bs, const char *filename) +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 | O_LARGEFILE); + s->fd = open(filename, O_RDONLY | O_BINARY); if (s->fd < 0) - return -1; + return -errno; bs->read_only = 1; /* read header */ diff --git a/block-cow.c b/block-cow.c index 6af8b7497..07c8a7bf1 100644 --- a/block-cow.c +++ b/block-cow.c @@ -62,7 +62,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int cow_open(BlockDriverState *bs, const char *filename) +static int cow_open(BlockDriverState *bs, const char *filename, int flags) { BDRVCowState *s = bs->opaque; int fd; @@ -93,22 +93,6 @@ static int cow_open(BlockDriverState *bs, const char *filename) pstrcpy(bs->backing_file, sizeof(bs->backing_file), cow_header.backing_file); -#if 0 - if (cow_header.backing_file[0] != '\0') { - if (stat(cow_header.backing_file, &st) != 0) { - fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); - goto fail; - } - if (st.st_mtime != be32_to_cpu(cow_header.mtime)) { - fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); - goto fail; - } - fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); - if (fd < 0) - goto fail; - bs->fd = fd; - } -#endif /* mmap the bitmap */ s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size), @@ -179,8 +163,15 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num, 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; @@ -220,7 +211,7 @@ static int cow_create(const char *filename, int64_t image_sectors, if (flags) return -ENOTSUP; - cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, + cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); if (cow_fd < 0) return -1; @@ -228,18 +219,23 @@ static int cow_create(const char *filename, int64_t image_sectors, 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); - return -1; + goto mtime_fail; } if (fstat(fd, &st) != 0) { close(fd); - return -1; + goto mtime_fail; } close(fd); cow_header.mtime = cpu_to_be32(st.st_mtime); - realpath(image_filename, cow_header.backing_file); + 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); diff --git a/block-dmg.c b/block-dmg.c index a16ab926b..a883a23f8 100644 --- a/block-dmg.c +++ b/block-dmg.c @@ -73,16 +73,16 @@ static off_t read_uint32(int fd) return be32_to_cpu(buffer); } -static int dmg_open(BlockDriverState *bs, const char *filename) +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 | O_LARGEFILE); + s->fd = open(filename, O_RDONLY | O_BINARY); if (s->fd < 0) - return -1; + return -errno; bs->read_only = 1; s->n_chunks = 0; s->offsets = s->lengths = s->sectors = s->sectorcounts = 0; @@ -93,7 +93,7 @@ dmg_close: close(s->fd); /* open raw instead */ bs->drv=&bdrv_raw; - return bs->drv->bdrv_open(bs,filename); + return bs->drv->bdrv_open(bs, filename, flags); } info_begin=read_off(s->fd); if(info_begin==0) diff --git a/block-qcow.c b/block-qcow.c index e5b52fb86..65e74e778 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -1,7 +1,7 @@ /* * Block driver for the QCOW format * - * Copyright (c) 2004 Fabrice Bellard + * 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 @@ -53,7 +53,7 @@ typedef struct QCowHeader { #define L2_CACHE_SIZE 16 typedef struct BDRVQcowState { - int fd; + BlockDriverState *hd; int cluster_bits; int cluster_size; int cluster_sectors; @@ -89,20 +89,16 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int qcow_open(BlockDriverState *bs, const char *filename) +static int qcow_open(BlockDriverState *bs, const char *filename, int flags) { BDRVQcowState *s = bs->opaque; - int fd, len, i, shift; + int len, i, shift, ret; QCowHeader header; - - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); - if (fd < 0) { - fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) - return -1; - } - s->fd = fd; - if (read(fd, &header, sizeof(header)) != sizeof(header)) + + 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); @@ -138,8 +134,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename) s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); if (!s->l1_table) goto fail; - lseek(fd, s->l1_table_offset, SEEK_SET); - if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) != + 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++) { @@ -162,8 +157,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename) len = header.backing_file_size; if (len > 1023) len = 1023; - lseek(fd, header.backing_file_offset, SEEK_SET); - if (read(fd, bs->backing_file, len) != len) + if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len) goto fail; bs->backing_file[len] = '\0'; } @@ -174,7 +168,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename) qemu_free(s->l2_cache); qemu_free(s->cluster_cache); qemu_free(s->cluster_data); - close(fd); + bdrv_delete(s->hd); return -1; } @@ -276,14 +270,14 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, if (!allocate) return 0; /* allocate a new l2 entry */ - l2_offset = lseek(s->fd, 0, SEEK_END); + 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); - lseek(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET); - if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp)) + if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), + &tmp, sizeof(tmp)) != sizeof(tmp)) return 0; new_l2_table = 1; } @@ -309,14 +303,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, } } l2_table = s->l2_cache + (min_index << s->l2_bits); - lseek(s->fd, l2_offset, SEEK_SET); if (new_l2_table) { memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); - if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != + 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 (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != + if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != s->l2_size * sizeof(uint64_t)) return 0; } @@ -337,21 +330,20 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, overwritten */ if (decompress_cluster(s, cluster_offset) < 0) return 0; - cluster_offset = lseek(s->fd, 0, SEEK_END); + cluster_offset = bdrv_getlength(s->hd); cluster_offset = (cluster_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); /* write the cluster content */ - lseek(s->fd, cluster_offset, SEEK_SET); - if (write(s->fd, s->cluster_cache, s->cluster_size) != + if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) != s->cluster_size) return -1; } else { - cluster_offset = lseek(s->fd, 0, SEEK_END); + 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); - ftruncate(s->fd, cluster_offset + s->cluster_size); + 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 && @@ -365,8 +357,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, s->cluster_data, s->cluster_data + 512, 1, 1, &s->aes_encrypt_key); - lseek(s->fd, cluster_offset + i * 512, SEEK_SET); - if (write(s->fd, s->cluster_data, 512) != 512) + if (bdrv_pwrite(s->hd, cluster_offset + i * 512, + s->cluster_data, 512) != 512) return -1; } } @@ -379,8 +371,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* update L2 table */ tmp = cpu_to_be64(cluster_offset); l2_table[l2_index] = tmp; - lseek(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET); - if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp)) + if (bdrv_pwrite(s->hd, + l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp)) return 0; } return cluster_offset; @@ -438,8 +430,7 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) if (s->cluster_cache_offset != coffset) { csize = cluster_offset >> (63 - s->cluster_bits); csize &= (s->cluster_size - 1); - lseek(s->fd, coffset, SEEK_SET); - ret = read(s->fd, s->cluster_data, csize); + ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize); if (ret != csize) return -1; if (decompress_buffer(s->cluster_cache, s->cluster_size, @@ -451,6 +442,8 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) return 0; } +#if 0 + static int qcow_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { @@ -465,14 +458,20 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, if (n > nb_sectors) n = nb_sectors; if (!cluster_offset) { - memset(buf, 0, 512 * n); + 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 { - lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); - ret = read(s->fd, buf, n * 512); + ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); if (ret != n * 512) return -1; if (s->crypt_method) { @@ -486,6 +485,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, } return 0; } +#endif static int qcow_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) @@ -504,13 +504,13 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, index_in_cluster + n); if (!cluster_offset) return -1; - lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); if (s->crypt_method) { encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1, &s->aes_encrypt_key); - ret = write(s->fd, s->cluster_data, n * 512); + ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, + s->cluster_data, n * 512); } else { - ret = write(s->fd, buf, n * 512); + ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); } if (ret != n * 512) return -1; @@ -522,6 +522,231 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, return 0; } +typedef struct { + int64_t sector_num; + uint8_t *buf; + int nb_sectors; + int n; + uint64_t cluster_offset; + uint8_t *cluster_data; + BlockDriverAIOCB *hd_aiocb; + BlockDriverAIOCB *backing_hd_aiocb; +} QCowAIOCB; + +static void qcow_aio_delete(BlockDriverAIOCB *acb); + +static int qcow_aio_new(BlockDriverAIOCB *acb) +{ + BlockDriverState *bs = acb->bs; + BDRVQcowState *s = bs->opaque; + QCowAIOCB *acb1; + acb1 = qemu_mallocz(sizeof(QCowAIOCB)); + if (!acb1) + return -1; + acb->opaque = acb1; + acb1->hd_aiocb = bdrv_aio_new(s->hd); + if (!acb1->hd_aiocb) + goto fail; + if (bs->backing_hd) { + acb1->backing_hd_aiocb = bdrv_aio_new(bs->backing_hd); + if (!acb1->backing_hd_aiocb) + goto fail; + } + return 0; + fail: + qcow_aio_delete(acb); + return -1; +} + +static void qcow_aio_read_cb(void *opaque, int ret) +{ + BlockDriverAIOCB *acb = opaque; + BlockDriverState *bs = acb->bs; + BDRVQcowState *s = bs->opaque; + QCowAIOCB *acb1 = acb->opaque; + int index_in_cluster; + + if (ret < 0) { + fail: + acb->cb(acb->cb_opaque, ret); + return; + } + + redo: + /* post process the read buffer */ + if (!acb1->cluster_offset) { + /* nothing to do */ + } else if (acb1->cluster_offset & QCOW_OFLAG_COMPRESSED) { + /* nothing to do */ + } else { + if (s->crypt_method) { + encrypt_sectors(s, acb1->sector_num, acb1->buf, acb1->buf, + acb1->n, 0, + &s->aes_decrypt_key); + } + } + + acb1->nb_sectors -= acb1->n; + acb1->sector_num += acb1->n; + acb1->buf += acb1->n * 512; + + if (acb1->nb_sectors == 0) { + /* request completed */ + acb->cb(acb->cb_opaque, 0); + return; + } + + /* prepare next AIO request */ + acb1->cluster_offset = get_cluster_offset(bs, + acb1->sector_num << 9, + 0, 0, 0, 0); + index_in_cluster = acb1->sector_num & (s->cluster_sectors - 1); + acb1->n = s->cluster_sectors - index_in_cluster; + if (acb1->n > acb1->nb_sectors) + acb1->n = acb1->nb_sectors; + + if (!acb1->cluster_offset) { + if (bs->backing_hd) { + /* read from the base image */ + ret = bdrv_aio_read(acb1->backing_hd_aiocb, acb1->sector_num, + acb1->buf, acb1->n, qcow_aio_read_cb, acb); + if (ret < 0) + goto fail; + } else { + /* Note: in this case, no need to wait */ + memset(acb1->buf, 0, 512 * acb1->n); + goto redo; + } + } else if (acb1->cluster_offset & QCOW_OFLAG_COMPRESSED) { + /* add AIO support for compressed blocks ? */ + if (decompress_cluster(s, acb1->cluster_offset) < 0) + goto fail; + memcpy(acb1->buf, + s->cluster_cache + index_in_cluster * 512, 512 * acb1->n); + goto redo; + } else { + if ((acb1->cluster_offset & 511) != 0) { + ret = -EIO; + goto fail; + } + ret = bdrv_aio_read(acb1->hd_aiocb, + (acb1->cluster_offset >> 9) + index_in_cluster, + acb1->buf, acb1->n, qcow_aio_read_cb, acb); + if (ret < 0) + goto fail; + } +} + +static int qcow_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + QCowAIOCB *acb1 = acb->opaque; + + acb1->sector_num = sector_num; + acb1->buf = buf; + acb1->nb_sectors = nb_sectors; + acb1->n = 0; + acb1->cluster_offset = 0; + + qcow_aio_read_cb(acb, 0); +} + +static void qcow_aio_write_cb(void *opaque, int ret) +{ + BlockDriverAIOCB *acb = opaque; + BlockDriverState *bs = acb->bs; + BDRVQcowState *s = bs->opaque; + QCowAIOCB *acb1 = acb->opaque; + int index_in_cluster; + uint64_t cluster_offset; + const uint8_t *src_buf; + + if (ret < 0) { + fail: + acb->cb(acb->cb_opaque, ret); + return; + } + + acb1->nb_sectors -= acb1->n; + acb1->sector_num += acb1->n; + acb1->buf += acb1->n * 512; + + if (acb1->nb_sectors == 0) { + /* request completed */ + acb->cb(acb->cb_opaque, 0); + return; + } + + index_in_cluster = acb1->sector_num & (s->cluster_sectors - 1); + acb1->n = s->cluster_sectors - index_in_cluster; + if (acb1->n > acb1->nb_sectors) + acb1->n = acb1->nb_sectors; + cluster_offset = get_cluster_offset(bs, acb1->sector_num << 9, 1, 0, + index_in_cluster, + index_in_cluster + acb1->n); + if (!cluster_offset || (cluster_offset & 511) != 0) { + ret = -EIO; + goto fail; + } + if (s->crypt_method) { + if (!acb1->cluster_data) { + acb1->cluster_data = qemu_mallocz(s->cluster_size); + if (!acb1->cluster_data) { + ret = -ENOMEM; + goto fail; + } + } + encrypt_sectors(s, acb1->sector_num, acb1->cluster_data, acb1->buf, + acb1->n, 1, &s->aes_encrypt_key); + src_buf = acb1->cluster_data; + } else { + src_buf = acb1->buf; + } + ret = bdrv_aio_write(acb1->hd_aiocb, + (cluster_offset >> 9) + index_in_cluster, + src_buf, acb1->n, + qcow_aio_write_cb, acb); + if (ret < 0) + goto fail; +} + +static int qcow_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + QCowAIOCB *acb1 = acb->opaque; + BlockDriverState *bs = acb->bs; + BDRVQcowState *s = bs->opaque; + + s->cluster_cache_offset = -1; /* disable compressed cache */ + + acb1->sector_num = sector_num; + acb1->buf = (uint8_t *)buf; + acb1->nb_sectors = nb_sectors; + acb1->n = 0; + + qcow_aio_write_cb(acb, 0); +} + +static void qcow_aio_cancel(BlockDriverAIOCB *acb) +{ + QCowAIOCB *acb1 = acb->opaque; + if (acb1->hd_aiocb) + bdrv_aio_cancel(acb1->hd_aiocb); + if (acb1->backing_hd_aiocb) + bdrv_aio_cancel(acb1->backing_hd_aiocb); +} + +static void qcow_aio_delete(BlockDriverAIOCB *acb) +{ + QCowAIOCB *acb1 = acb->opaque; + if (acb1->hd_aiocb) + bdrv_aio_delete(acb1->hd_aiocb); + if (acb1->backing_hd_aiocb) + bdrv_aio_delete(acb1->backing_hd_aiocb); + qemu_free(acb1->cluster_data); + qemu_free(acb1); +} + static void qcow_close(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; @@ -529,7 +754,7 @@ static void qcow_close(BlockDriverState *bs) qemu_free(s->l2_cache); qemu_free(s->cluster_cache); qemu_free(s->cluster_data); - close(s->fd); + bdrv_delete(s->hd); } static int qcow_create(const char *filename, int64_t total_size, @@ -537,12 +762,9 @@ static int qcow_create(const char *filename, int64_t total_size, { int fd, header_size, backing_filename_len, l1_size, i, shift; QCowHeader header; - char backing_filename[1024]; uint64_t tmp; - struct stat st; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, - 0644); + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); if (fd < 0) return -1; memset(&header, 0, sizeof(header)); @@ -552,28 +774,11 @@ static int qcow_create(const char *filename, int64_t total_size, header_size = sizeof(header); backing_filename_len = 0; if (backing_file) { - if (strcmp(backing_file, "fat:")) { - const char *p; - /* XXX: this is a hack: we do not attempt to check for URL - like syntax */ - p = strchr(backing_file, ':'); - if (p && (p - backing_file) >= 2) { - /* URL like but exclude "c:" like filenames */ - pstrcpy(backing_filename, sizeof(backing_filename), - backing_file); - } else { - realpath(backing_file, backing_filename); - if (stat(backing_filename, &st) != 0) { - return -1; - } - } - header.backing_file_offset = cpu_to_be64(header_size); - backing_filename_len = strlen(backing_filename); - header.backing_file_size = cpu_to_be32(backing_filename_len); - header_size += backing_filename_len; - } else - backing_file = NULL; - header.mtime = cpu_to_be32(st.st_mtime); + 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 */ @@ -595,7 +800,7 @@ static int qcow_create(const char *filename, int64_t total_size, /* write all the data */ write(fd, &header, sizeof(header)); if (backing_file) { - write(fd, backing_filename, backing_filename_len); + write(fd, backing_file, backing_filename_len); } lseek(fd, header_size, SEEK_SET); tmp = 0; @@ -610,12 +815,14 @@ 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); - lseek(s->fd, s->l1_table_offset, SEEK_SET); - if (write(s->fd, s->l1_table, l1_length) < 0) + if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0) return -1; - ftruncate(s->fd, s->l1_table_offset + l1_length); + 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)); @@ -682,8 +889,7 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, out_len, 0, 0); cluster_offset &= s->cluster_offset_mask; - lseek(s->fd, cluster_offset, SEEK_SET); - if (write(s->fd, out_buf, out_len) != out_len) { + if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { qemu_free(out_buf); return -1; } @@ -696,7 +902,7 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, static void qcow_flush(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; - fsync(s->fd); + bdrv_flush(s->hd); } BlockDriver bdrv_qcow = { @@ -704,14 +910,20 @@ BlockDriver bdrv_qcow = { sizeof(BDRVQcowState), qcow_probe, qcow_open, - qcow_read, - qcow_write, + NULL, + NULL, qcow_close, qcow_create, qcow_flush, qcow_is_allocated, qcow_set_key, - qcow_make_empty + qcow_make_empty, + + .bdrv_aio_new = qcow_aio_new, + .bdrv_aio_read = qcow_aio_read, + .bdrv_aio_write = qcow_aio_write, + .bdrv_aio_cancel = qcow_aio_cancel, + .bdrv_aio_delete = qcow_aio_delete, }; diff --git a/block-raw.c b/block-raw.c new file mode 100644 index 000000000..77502b097 --- /dev/null +++ b/block-raw.c @@ -0,0 +1,817 @@ +/* + * 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 +#ifndef _WIN32 +#include + +#ifndef QEMU_TOOL +#include "exec-all.h" +#endif + +#ifdef CONFIG_COCOA +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#endif + +#ifdef __sun__ +#include +#endif + +typedef struct BDRVRawState { + int fd; +} BDRVRawState; + +#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 raw_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVRawState *s = bs->opaque; + int fd, open_flags; + +#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; + } + if (flags & BDRV_O_CREAT) + open_flags |= O_CREAT | O_TRUNC; + + fd = open(filename, open_flags, 0644); + if (fd < 0) + return -errno; + 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; + + 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; + + lseek(s->fd, offset, SEEK_SET); + ret = write(s->fd, buf, count); + return ret; +} + +/***********************************************************/ +/* Unix AOP using POSIX AIO */ + +typedef struct RawAIOCB { + struct aiocb aiocb; + int busy; /* only used for debugging */ + BlockDriverAIOCB *next; +} RawAIOCB; + +static int aio_sig_num = SIGUSR2; +static BlockDriverAIOCB *first_aio; /* AIO issued */ + +#ifndef QEMU_TOOL +static void aio_signal_handler(int signum) +{ + 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 + } +} + +void qemu_aio_init(void) +{ + struct sigaction act; + + 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); + + { + /* XXX: aio thread exit seems to hang on RH 9 */ + struct aioinit ai; + memset(&ai, 0, sizeof(ai)); + ai.aio_threads = 2; + ai.aio_num = 1; + ai.aio_idle_time = 365 * 100000; + aio_init(&ai); + } +} +#endif /* !QEMU_TOOL */ + +void qemu_aio_poll(void) +{ + BlockDriverAIOCB *acb, **pacb; + RawAIOCB *acb1; + int ret; + + for(;;) { + pacb = &first_aio; + for(;;) { + acb = *pacb; + if (!acb) + goto the_end; + acb1 = acb->opaque; + ret = aio_error(&acb1->aiocb); + if (ret == ECANCELED) { + /* remove the request */ + acb1->busy = 0; + *pacb = acb1->next; + } else if (ret != EINPROGRESS) { + /* end of aio */ + if (ret == 0) { + ret = aio_return(&acb1->aiocb); + if (ret == acb1->aiocb.aio_nbytes) + ret = 0; + else + ret = -1; + } else { + ret = -ret; + } + /* remove the request */ + acb1->busy = 0; + *pacb = acb1->next; + /* call the callback */ + acb->cb(acb->cb_opaque, ret); + break; + } else { + pacb = &acb1->next; + } + } + } + the_end: ; +} + +/* wait until at least one AIO was handled */ +static sigset_t wait_oset; + +void qemu_aio_wait_start(void) +{ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, aio_sig_num); + sigprocmask(SIG_BLOCK, &set, &wait_oset); +} + +void qemu_aio_wait(void) +{ + sigset_t set; + int nb_sigs; + 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 int raw_aio_new(BlockDriverAIOCB *acb) +{ + RawAIOCB *acb1; + BDRVRawState *s = acb->bs->opaque; + + acb1 = qemu_mallocz(sizeof(RawAIOCB)); + if (!acb1) + return -1; + acb->opaque = acb1; + acb1->aiocb.aio_fildes = s->fd; + acb1->aiocb.aio_sigevent.sigev_signo = aio_sig_num; + acb1->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; + return 0; +} + +static int raw_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + RawAIOCB *acb1 = acb->opaque; + + assert(acb1->busy == 0); + acb1->busy = 1; + acb1->aiocb.aio_buf = buf; + acb1->aiocb.aio_nbytes = nb_sectors * 512; + acb1->aiocb.aio_offset = sector_num * 512; + acb1->next = first_aio; + first_aio = acb; + if (aio_read(&acb1->aiocb) < 0) { + acb1->busy = 0; + return -errno; + } + return 0; +} + +static int raw_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + RawAIOCB *acb1 = acb->opaque; + + assert(acb1->busy == 0); + acb1->busy = 1; + acb1->aiocb.aio_buf = (uint8_t *)buf; + acb1->aiocb.aio_nbytes = nb_sectors * 512; + acb1->aiocb.aio_offset = sector_num * 512; + acb1->next = first_aio; + first_aio = acb; + if (aio_write(&acb1->aiocb) < 0) { + acb1->busy = 0; + return -errno; + } + return 0; +} + +static void raw_aio_cancel(BlockDriverAIOCB *acb) +{ + RawAIOCB *acb1 = acb->opaque; + int ret; + BlockDriverAIOCB **pacb; + + ret = aio_cancel(acb1->aiocb.aio_fildes, &acb1->aiocb); + if (ret == AIO_NOTCANCELED) { + /* fail safe: if the aio could not be canceled, we wait for + it */ + while (aio_error(&acb1->aiocb) == EINPROGRESS); + } + + /* remove the callback from the queue */ + pacb = &first_aio; + for(;;) { + if (*pacb == NULL) { + break; + } else if (*pacb == acb) { + acb1->busy = 0; + *pacb = acb1->next; + break; + } + acb1 = (*pacb)->opaque; + pacb = &acb1->next; + } +} + +static void raw_aio_delete(BlockDriverAIOCB *acb) +{ + RawAIOCB *acb1 = acb->opaque; + raw_aio_cancel(acb); + qemu_free(acb1); +} + +static void raw_close(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + close(s->fd); +} + +static int raw_truncate(BlockDriverState *bs, int64_t offset) +{ + BDRVRawState *s = bs->opaque; + 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 + +#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); + } +#ifdef _WIN32 + /* On Windows hosts it can happen that we're unable to get file size + for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ + if (size == -1) + size = LONG_LONG_MAX; +#endif + 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 | O_LARGEFILE, + 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_new = raw_aio_new, + .bdrv_aio_read = raw_aio_read, + .bdrv_aio_write = raw_aio_write, + .bdrv_aio_cancel = raw_aio_cancel, + .bdrv_aio_delete = raw_aio_delete, + .protocol_name = "file", + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, + .bdrv_truncate = raw_truncate, + .bdrv_getlength = raw_getlength, +}; + +#else /* _WIN32 */ + +/* XXX: use another file ? */ +#include +#include + +typedef struct BDRVRawState { + HANDLE hfile; +} BDRVRawState; + +typedef struct RawAIOCB { + 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; + + if ((flags & BDRV_O_ACCESS) == O_RDWR) { + access_flags = GENERIC_READ | GENERIC_WRITE; + } else { + access_flags = GENERIC_READ; + } + if (flags & BDRV_O_CREATE) { + create_flags = CREATE_ALWAYS; + } else { + create_flags = OPEN_EXISTING; + } + s->hfile = CreateFile(filename, access_flags, + FILE_SHARE_READ, NULL, + create_flags, FILE_FLAG_OVERLAPPED, 0); + 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, NULL, &ov); + if (!ret) + return -EIO; + ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE); + if (!ret) + return -EIO; + 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, NULL, &ov); + if (!ret) + return -EIO; + ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE); + if (!ret) + return -EIO; + return ret_count; +} + +static int raw_aio_new(BlockDriverAIOCB *acb) +{ + RawAIOCB *acb1; + BDRVRawState *s = acb->bs->opaque; + + acb1 = qemu_mallocz(sizeof(RawAIOCB)); + if (!acb1) + return -ENOMEM; + acb->opaque = acb1; + s->hevent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hevent) + return -ENOMEM; + return 0; +} + +static void raw_aio_cb(void *opaque) +{ + BlockDriverAIOCB *acb = acb1; + RawAIOCB *acb1 = acb->opaque; + DWORD ret_count; + int ret; + + ret = GetOverlappedResult(s->hfile, &acb1->ov, &ret_count, TRUE); + if (!ret || ret_count != acb1->count) { + acb->cb(acb->cb_opaque, -EIO); + } else { + acb->cb(acb->cb_opaque, 0); + } +} + +static int raw_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BlockDriverState *bs = acb->bs; + BDRVRawState *s = bs->opaque; + RawAIOCB *acb1 = acb->opaque; + DWORD ret_count; + int ret; + int64_t offset; + + memset(&acb1->ov, 0, sizeof(acb1->ov)); + offset = sector_num * 512; + acb1->ov.Offset = offset; + acb1->ov.OffsetHigh = offset >> 32; + acb1->ov.hEvent = acb1->hEvent; + acb1->count = nb_sectors * 512; + qemu_add_wait_object(acb1->ov.hEvent, raw_aio_cb, acb); + ret = ReadFile(s->hfile, buf, acb1->count, NULL, &acb1->ov); + if (!ret) + return -EIO; + return 0; +} + +static int raw_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BlockDriverState *bs = acb->bs; + BDRVRawState *s = bs->opaque; + RawAIOCB *acb1 = acb->opaque; + DWORD ret_count; + int ret; + int64_t offset; + + memset(&acb1->ov, 0, sizeof(acb1->ov)); + offset = sector_num * 512; + acb1->ov.Offset = offset; + acb1->ov.OffsetHigh = offset >> 32; + acb1->ov.hEvent = acb1->hEvent; + acb1->count = nb_sectors * 512; + qemu_add_wait_object(acb1->ov.hEvent, raw_aio_cb, acb); + ret = ReadFile(s->hfile, buf, acb1->count, NULL, &acb1->ov); + if (!ret) + return -EIO; + return 0; +} + +static void raw_aio_cancel(BlockDriverAIOCB *acb) +{ + BlockDriverState *bs = acb->bs; + BDRVRawState *s = bs->opaque; + RawAIOCB *acb1 = acb->opaque; + + qemu_del_wait_object(acb1->ov.hEvent, raw_aio_cb, acb); + /* XXX: if more than one async I/O it is not correct */ + CancelIo(s->hfile); +} + +static void raw_aio_delete(BlockDriverAIOCB *acb) +{ + RawAIOCB *acb1 = acb->opaque; + raw_aio_cancel(acb); + CloseHandle(acb1->hEvent); + qemu_free(acb1); +} + +static void raw_flush(BlockDriverState *bs) +{ + /* XXX: add it */ +} + +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 = length; + high = length >> 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; + if (!GetFileSizeEx(s->hfile, &l)) + 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_wait_start(void) +{ +} + +void qemu_aio_wait(void) +{ +} + +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_new = raw_aio_new, + .bdrv_aio_read = raw_aio_read, + .bdrv_aio_write = raw_aio_write, + .bdrv_aio_cancel = raw_aio_cancel, + .bdrv_aio_delete = raw_aio_delete, +#endif + .protocol_name = "file", + .bdrv_pread = raw_pread, + .bdrv_pwrite = raw_pwrite, + .bdrv_truncate = raw_truncate, + .bdrv_getlength = raw_getlength, +}; +#endif /* _WIN32 */ diff --git a/block-vmdk.c b/block-vmdk.c index 4cc3db84a..8279d6696 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -89,7 +89,7 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int vmdk_open(BlockDriverState *bs, const char *filename) +static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) { BDRVVmdkState *s = bs->opaque; int fd, i; diff --git a/block-vpc.c b/block-vpc.c index bdc3b8891..4d228c5b6 100644 --- a/block-vpc.c +++ b/block-vpc.c @@ -86,19 +86,16 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int vpc_open(BlockDriverState *bs, const char *filename) +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_RDWR | O_BINARY | O_LARGEFILE); - if (fd < 0) { - fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) - return -1; - } - + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return -1; + bs->read_only = 1; // no write support yet s->fd = fd; diff --git a/block-vvfat.c b/block-vvfat.c index 9dedf9115..ad6b7d29e 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -351,13 +351,6 @@ typedef struct BDRVVVFATState { } BDRVVVFATState; -static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename) -{ - if (strstart(filename, "fat:", NULL)) - return 100; - return 0; -} - static void init_mbr(BDRVVVFATState* s) { /* TODO: if the files mbr.img and bootsect.img exist, use them */ @@ -954,18 +947,22 @@ static int init_directories(BDRVVVFATState* s, 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) +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"); @@ -1040,7 +1037,6 @@ DLOG(if (stderr == NULL) { bs->heads = bs->cyls = bs->secs = 0; // assert(is_consistent(s)); - return 0; } @@ -2732,8 +2728,7 @@ static int enable_write_target(BDRVVVFATState *s) array_init(&(s->commits), sizeof(commit_t)); s->qcow_filename = malloc(1024); - strcpy(s->qcow_filename, "/tmp/vl.XXXXXX"); - get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1); + get_tmp_filename(s->qcow_filename, 1024); if (bdrv_create(&bdrv_qcow, s->qcow_filename, s->sector_count, "fat:", 0) < 0) return -1; @@ -2767,14 +2762,15 @@ static void vvfat_close(BlockDriverState *bs) BlockDriver bdrv_vvfat = { "vvfat", sizeof(BDRVVVFATState), - vvfat_probe, + 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 + vvfat_is_allocated, + .protocol_name = "fat", }; #ifdef DEBUG diff --git a/block.c b/block.c index ceb0532bd..3cf8b7b12 100644 --- a/block.c +++ b/block.c @@ -32,85 +32,92 @@ #include #endif -#ifdef CONFIG_COCOA -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#endif - -#ifdef __sun__ -#include -#endif +#define SECTOR_BITS 9 +#define SECTOR_SIZE (1 << SECTOR_BITS) + +static int bdrv_aio_new_em(BlockDriverAIOCB *acb); +static int bdrv_aio_read_em(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors); +static int bdrv_aio_write_em(BlockDriverAIOCB *acb, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb); +static void bdrv_aio_delete_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; -#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 ); +#ifdef _WIN32 +#define PATH_SEP '\\' +#else +#define PATH_SEP '/' +#endif -kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) +int path_is_absolute(const char *path) { - 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; + const char *p; + p = strchr(path, ':'); + if (p) + p++; + else + p = path; + return (*p == PATH_SEP); } -kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ) +/* 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) { - 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 ); + 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, PATH_SEP); + 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); } - - return kernResult; } -#endif void bdrv_register(BlockDriver *bdrv) { + if (!bdrv->bdrv_aio_new) { + /* add AIO emulation layer */ + bdrv->bdrv_aio_new = bdrv_aio_new_em; + 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->bdrv_aio_delete = bdrv_aio_delete_em; + } 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; } @@ -156,14 +163,7 @@ int bdrv_create(BlockDriver *drv, #ifdef _WIN32 void get_tmp_filename(char *filename, int size) { - char* p = strrchr(filename, '/'); - - if (p == NULL) - return; - - /* XXX: find a better function */ - tmpnam(p); - *p = '/'; + tmpnam(filename); } #else void get_tmp_filename(char *filename, int size) @@ -176,101 +176,107 @@ void get_tmp_filename(char *filename, int size) } #endif +static BlockDriver *find_protocol(const char *filename) +{ + BlockDriver *drv1; + char protocol[128]; + int len; + const char *p; + p = strchr(filename, ':'); + if (!p) + return &bdrv_raw; + len = p - filename; + if (len > sizeof(protocol) - 1) + len = sizeof(protocol) - 1; +#ifdef _WIN32 + if (len == 1) { + /* specific win32 case for driver letters */ + return &bdrv_raw; + } +#endif + 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 fd, ret, score, score_max; + int ret, score, score_max; BlockDriver *drv1, *drv; - uint8_t *buf; - size_t bufsize = 1024; - - fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) { - buf = NULL; - ret = 0; - } else { -#ifdef DIOCGSECTORSIZE - { - unsigned int sectorsize = 512; - if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && - sectorsize > bufsize) - bufsize = sectorsize; - } -#endif -#ifdef CONFIG_COCOA - u_int32_t blockSize = 512; - if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { - bufsize = blockSize; - } -#endif - buf = qemu_malloc(bufsize); - if (!buf) - return NULL; - ret = read(fd, buf, bufsize); - if (ret < 0) { - close(fd); - qemu_free(buf); - return NULL; - } - close(fd); - } + uint8_t buf[2048]; + BlockDriverState *bs; - drv = NULL; + drv = find_protocol(filename); + /* no need to test disk image formats for vvfat or host specific + devices */ + if (drv == &bdrv_vvfat) + return drv; + if (strstart(filename, "/dev/", NULL)) + return &bdrv_raw; + + 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) { - score = drv1->bdrv_probe(buf, ret, filename); - if (score > score_max) { - score_max = score; - drv = drv1; + if (drv1->bdrv_probe) { + score = drv1->bdrv_probe(buf, ret, filename); + if (score > score_max) { + score_max = score; + drv = drv1; + } } } - qemu_free(buf); return drv; } -int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) +int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) { -#ifdef CONFIG_COCOA - if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) { - 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 ); + 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; } -#endif - return bdrv_open2(bs, filename, snapshot, NULL); + *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 snapshot, +int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, BlockDriver *drv) { - int ret; + int ret, open_flags; char tmp_filename[1024]; + char backing_filename[1024]; bs->read_only = 0; bs->is_temporary = 0; bs->encrypted = 0; - if (snapshot) { + if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; int64_t total_size; @@ -280,17 +286,16 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, /* if there is a backing file, use it */ bs1 = bdrv_new(""); if (!bs1) { - return -1; + return -ENOMEM; } if (bdrv_open(bs1, filename, 0) < 0) { bdrv_delete(bs1); return -1; } - total_size = bs1->total_sectors; + total_size = bdrv_getlength(bs1) >> SECTOR_BITS; bdrv_delete(bs1); get_tmp_filename(tmp_filename, sizeof(tmp_filename)); - /* XXX: use cow for linux as it is more efficient ? */ if (bdrv_create(&bdrv_qcow, tmp_filename, total_size, filename, 0) < 0) { return -1; @@ -300,27 +305,43 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, } pstrcpy(bs->filename, sizeof(bs->filename), filename); - if (!drv) { - drv = find_image_format(filename); + if (flags & BDRV_O_FILE) { + drv = find_protocol(filename); if (!drv) - return -1; + 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; - - ret = drv->bdrv_open(bs, filename); + /* 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); - return -1; + return ret; } + #ifndef _WIN32 if (bs->is_temporary) { unlink(filename); } #endif - if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { + if (bs->backing_file[0] != '\0') { /* if there is a backing file, use it */ bs->backing_hd = bdrv_new(""); if (!bs->backing_hd) { @@ -328,7 +349,9 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, bdrv_close(bs); return -1; } - if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) + path_combine(backing_filename, sizeof(backing_filename), + filename, bs->backing_file); + if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0) goto fail; } @@ -373,7 +396,7 @@ void bdrv_delete(BlockDriverState *bs) /* commit COW file into the raw image */ int bdrv_commit(BlockDriverState *bs) { - int64_t i; + int64_t i, total_sectors; int n, j; unsigned char sector[512]; @@ -388,7 +411,8 @@ int bdrv_commit(BlockDriverState *bs) return -ENOTSUP; } - for (i = 0; i < bs->total_sectors;) { + total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; + for (i = 0; i < total_sectors;) { if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { for(j = 0; j < n; j++) { if (bdrv_read(bs, i, sector, 1) != 0) { @@ -411,49 +435,43 @@ int bdrv_commit(BlockDriverState *bs) return 0; } -/* return -1 if error */ +/* return < 0 if error */ int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { - int ret, n; BlockDriver *drv = bs->drv; if (!bs->inserted) return -1; - while (nb_sectors > 0) { - if (sector_num == 0 && bs->boot_sector_enabled) { + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { memcpy(buf, bs->boot_sector_data, 512); - n = 1; - } else if (bs->backing_hd) { - if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { - ret = drv->bdrv_read(bs, sector_num, buf, n); - if (ret < 0) - return -1; - } else { - /* read from the base image */ - ret = bdrv_read(bs->backing_hd, sector_num, buf, n); - if (ret < 0) - return -1; - } - } else { - ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); - if (ret < 0) - return -1; - /* no need to loop */ - break; - } - nb_sectors -= n; - sector_num += n; - buf += n * 512; + 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 -EIO; + else + return 0; + } else { + return drv->bdrv_read(bs, sector_num, buf, nb_sectors); } - return 0; } -/* return -1 if error */ +/* return < 0 if error */ int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { + BlockDriver *drv = bs->drv; if (!bs->inserted) return -1; if (bs->read_only) @@ -461,12 +479,183 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { memcpy(bs->boot_sector_data, buf, 512); } - return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); + 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); + } +} + +#if 0 +/* not necessary now */ +static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, + void *buf1, int count1) +{ + uint8_t *buf = buf1; + 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 void *buf1, int count1) +{ + const uint8_t *buf = buf1; + 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; +} +#endif + +/** + * 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 -ENOENT; + if (!drv->bdrv_pread) + return -ENOTSUP; + 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 -ENOENT; + if (!drv->bdrv_pwrite) + return -ENOTSUP; + 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 -ENOENT; + 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 -ENOENT; + if (!drv->bdrv_getlength) { + /* legacy mode */ + return bs->total_sectors * SECTOR_SIZE; + } + return drv->bdrv_getlength(bs); } void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) { - *nb_sectors_ptr = bs->total_sectors; + int64_t size; + size = bdrv_getlength(bs); + if (size < 0) + size = 0; + *nb_sectors_ptr = size >> SECTOR_BITS; } /* force a given boot sector. */ @@ -660,187 +849,251 @@ void bdrv_info(void) } } +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); + } +} + + /**************************************************************/ -/* RAW block driver */ +/* async I/Os */ -typedef struct BDRVRawState { - int fd; -} BDRVRawState; +BlockDriverAIOCB *bdrv_aio_new(BlockDriverState *bs) +{ + BlockDriver *drv = bs->drv; + BlockDriverAIOCB *acb; + acb = qemu_mallocz(sizeof(BlockDriverAIOCB)); + if (!acb) + return NULL; + + acb->bs = bs; + if (drv->bdrv_aio_new(acb) < 0) { + qemu_free(acb); + return NULL; + } + return acb; +} -static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) +int bdrv_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - return 1; /* maybe */ + BlockDriverState *bs = acb->bs; + BlockDriver *drv = bs->drv; + + if (!bs->inserted) + return -1; + + /* 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; + } + + acb->cb = cb; + acb->cb_opaque = opaque; + return drv->bdrv_aio_read(acb, sector_num, buf, nb_sectors); } -static int raw_open(BlockDriverState *bs, const char *filename) +int bdrv_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, + const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - BDRVRawState *s = bs->opaque; - int fd; - int64_t size; -#ifdef _BSD - struct stat sb; -#endif -#ifdef __sun__ - struct dk_minfo minfo; - int rv; -#endif + BlockDriverState *bs = acb->bs; + BlockDriver *drv = bs->drv; - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); - if (fd < 0) { - fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) + if (!bs->inserted) return -1; - bs->read_only = 1; + if (bs->read_only) + return -1; + if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { + memcpy(bs->boot_sector_data, buf, 512); } -#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 + + acb->cb = cb; + acb->cb_opaque = opaque; + return drv->bdrv_aio_write(acb, sector_num, buf, nb_sectors); +} + +void bdrv_aio_cancel(BlockDriverAIOCB *acb) { - size = lseek(fd, 0, SEEK_END); + BlockDriverState *bs = acb->bs; + BlockDriver *drv = bs->drv; + + drv->bdrv_aio_cancel(acb); } -#ifdef _WIN32 - /* On Windows hosts it can happen that we're unable to get file size - for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ - if (size == -1) - size = LONG_LONG_MAX; -#endif - bs->total_sectors = size / 512; - s->fd = fd; + +void bdrv_aio_delete(BlockDriverAIOCB *acb) +{ + BlockDriverState *bs = acb->bs; + BlockDriver *drv = bs->drv; + + drv->bdrv_aio_delete(acb); + qemu_free(acb); +} + +/**************************************************************/ +/* async block device emulation */ + +#ifdef QEMU_TOOL +static int bdrv_aio_new_em(BlockDriverAIOCB *acb) +{ return 0; } -static int raw_read(BlockDriverState *bs, int64_t sector_num, +static int bdrv_aio_read_em(BlockDriverAIOCB *acb, int64_t sector_num, uint8_t *buf, int nb_sectors) { - BDRVRawState *s = bs->opaque; int ret; - - lseek(s->fd, sector_num * 512, SEEK_SET); - ret = read(s->fd, buf, nb_sectors * 512); - if (ret != nb_sectors * 512) - return -1; + ret = bdrv_read(acb->bs, sector_num, buf, nb_sectors); + acb->cb(acb->cb_opaque, ret); return 0; } -static int raw_write(BlockDriverState *bs, int64_t sector_num, +static int bdrv_aio_write_em(BlockDriverAIOCB *acb, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - BDRVRawState *s = bs->opaque; int ret; - - lseek(s->fd, sector_num * 512, SEEK_SET); - ret = write(s->fd, buf, nb_sectors * 512); - if (ret != nb_sectors * 512) - return -1; + ret = bdrv_write(acb->bs, sector_num, buf, nb_sectors); + acb->cb(acb->cb_opaque, ret); return 0; } -static void raw_close(BlockDriverState *bs) +static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb) { - BDRVRawState *s = bs->opaque; - close(s->fd); } -#ifdef _WIN32 -#include -#include - -int qemu_ftruncate64(int fd, int64_t length) +static void bdrv_aio_delete_em(BlockDriverAIOCB *acb) { - LARGE_INTEGER li; - LONG high; - HANDLE h; - BOOL res; - - if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) - return -1; +} +#else +typedef struct BlockDriverAIOCBSync { + QEMUBH *bh; + int ret; +} BlockDriverAIOCBSync; - h = (HANDLE)_get_osfhandle(fd); +static void bdrv_aio_bh_cb(void *opaque) +{ + BlockDriverAIOCB *acb = opaque; + BlockDriverAIOCBSync *acb1 = acb->opaque; + acb->cb(acb->cb_opaque, acb1->ret); +} - /* 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; +static int bdrv_aio_new_em(BlockDriverAIOCB *acb) +{ + BlockDriverAIOCBSync *acb1; - high = length >> 32; - if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN)) - return -1; - res = SetEndOfFile(h); + acb1 = qemu_mallocz(sizeof(BlockDriverAIOCBSync)); + if (!acb1) + return -1; + acb->opaque = acb1; + acb1->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); + return 0; +} - /* back to old position */ - SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); - return res ? 0 : -1; +static int bdrv_aio_read_em(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BlockDriverAIOCBSync *acb1 = acb->opaque; + int ret; + + ret = bdrv_read(acb->bs, sector_num, buf, nb_sectors); + acb1->ret = ret; + qemu_bh_schedule(acb1->bh); + return 0; } -static int set_sparse(int fd) +static int bdrv_aio_write_em(BlockDriverAIOCB *acb, int64_t sector_num, + const uint8_t *buf, int nb_sectors) { - DWORD returned; - return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, - NULL, 0, NULL, 0, &returned, NULL); + BlockDriverAIOCBSync *acb1 = acb->opaque; + int ret; + + ret = bdrv_write(acb->bs, sector_num, buf, nb_sectors); + acb1->ret = ret; + qemu_bh_schedule(acb1->bh); + return 0; } -#else -static inline int set_sparse(int fd) + +static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb) { - return 1; + BlockDriverAIOCBSync *acb1 = acb->opaque; + qemu_bh_cancel(acb1->bh); } -#endif -static int raw_create(const char *filename, int64_t total_size, - const char *backing_file, int flags) +static void bdrv_aio_delete_em(BlockDriverAIOCB *acb) { - int fd; + BlockDriverAIOCBSync *acb1 = acb->opaque; + qemu_bh_delete(acb1->bh); +} +#endif /* !QEMU_TOOL */ - if (flags || backing_file) - return -ENOTSUP; +/**************************************************************/ +/* sync block device emulation */ - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, - 0644); - if (fd < 0) - return -EIO; - set_sparse(fd); - ftruncate(fd, total_size * 512); - close(fd); - return 0; +static void bdrv_rw_em_cb(void *opaque, int ret) +{ + *(int *)opaque = ret; } -static void raw_flush(BlockDriverState *bs) +#define NOT_DONE 0x7fffffff + +static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) { - BDRVRawState *s = bs->opaque; - fsync(s->fd); + int async_ret, ret; + + if (!bs->sync_aiocb) { + bs->sync_aiocb = bdrv_aio_new(bs); + if (!bs->sync_aiocb) + return -1; + } + async_ret = NOT_DONE; + qemu_aio_wait_start(); + ret = bdrv_aio_read(bs->sync_aiocb, sector_num, buf, nb_sectors, + bdrv_rw_em_cb, &async_ret); + if (ret < 0) { + qemu_aio_wait_end(); + return ret; + } + while (async_ret == NOT_DONE) { + qemu_aio_wait(); + } + qemu_aio_wait_end(); + return async_ret; } -BlockDriver bdrv_raw = { - "raw", - sizeof(BDRVRawState), - raw_probe, - raw_open, - raw_read, - raw_write, - raw_close, - raw_create, - raw_flush, -}; +static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + int async_ret, ret; + + if (!bs->sync_aiocb) { + bs->sync_aiocb = bdrv_aio_new(bs); + if (!bs->sync_aiocb) + return -1; + } + async_ret = NOT_DONE; + qemu_aio_wait_start(); + ret = bdrv_aio_write(bs->sync_aiocb, sector_num, buf, nb_sectors, + bdrv_rw_em_cb, &async_ret); + if (ret < 0) { + qemu_aio_wait_end(); + return ret; + } + while (async_ret == NOT_DONE) { + qemu_aio_wait(); + } + qemu_aio_wait_end(); + return async_ret; +} void bdrv_init(void) { diff --git a/block_int.h b/block_int.h index c2a2e30a9..e40503ea3 100644 --- a/block_int.h +++ b/block_int.h @@ -28,7 +28,7 @@ struct BlockDriver { const char *format_name; int instance_size; int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); - int (*bdrv_open)(BlockDriverState *bs, const char *filename); + int (*bdrv_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, @@ -41,11 +41,28 @@ struct BlockDriver { int nb_sectors, int *pnum); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_make_empty)(BlockDriverState *bs); + /* aio */ + int (*bdrv_aio_new)(BlockDriverAIOCB *acb); + int (*bdrv_aio_read)(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors); + int (*bdrv_aio_write)(BlockDriverAIOCB *acb, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb); + void (*bdrv_aio_delete)(BlockDriverAIOCB *acb); + + 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); + struct BlockDriver *next; }; struct BlockDriverState { - int64_t total_sectors; + int64_t total_sectors; /* XXX: will be suppressed */ int read_only; /* if true, the media is read only */ int inserted; /* if true, the media is present */ int removable; /* if true, the media can be removed */ @@ -67,6 +84,9 @@ struct BlockDriverState { int is_temporary; BlockDriverState *backing_hd; + /* sync read/write emulation */ + + BlockDriverAIOCB *sync_aiocb; /* NOTE: the following infos are only hints for real hardware drivers. They are not used by the block driver */ @@ -76,6 +96,14 @@ struct BlockDriverState { BlockDriverState *next; }; +struct BlockDriverAIOCB { + BlockDriverState *bs; + BlockDriverCompletionFunc *cb; + void *cb_opaque; + + void *opaque; /* driver opaque */ +}; + void get_tmp_filename(char *filename, int size); #endif /* BLOCK_INT_H */ diff --git a/vl.c b/vl.c index 657116b00..b31b2398a 100644 --- a/vl.c +++ b/vl.c @@ -4771,6 +4771,77 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) return 0; } +/***********************************************************/ +/* bottom halves (can be seen as timers which expire ASAP) */ + +struct QEMUBH { + QEMUBHFunc *cb; + void *opaque; + int scheduled; + QEMUBH *next; +}; + +static QEMUBH *first_bh = NULL; + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) +{ + QEMUBH *bh; + bh = qemu_mallocz(sizeof(QEMUBH)); + if (!bh) + return NULL; + bh->cb = cb; + bh->opaque = opaque; + return bh; +} + +void qemu_bh_poll(void) +{ + QEMUBH *bh, **pbh; + + for(;;) { + pbh = &first_bh; + bh = *pbh; + if (!bh) + break; + *pbh = bh->next; + bh->scheduled = 0; + bh->cb(bh->opaque); + } +} + +void qemu_bh_schedule(QEMUBH *bh) +{ + CPUState *env = cpu_single_env; + if (bh->scheduled) + return; + bh->scheduled = 1; + bh->next = first_bh; + first_bh = bh; + + /* stop the currently executing CPU to execute the BH ASAP */ + if (env) { + cpu_interrupt(env, CPU_INTERRUPT_EXIT); + } +} + +void qemu_bh_cancel(QEMUBH *bh) +{ + QEMUBH **pbh; + if (bh->scheduled) { + pbh = &first_bh; + while (*pbh != bh) + pbh = &(*pbh)->next; + *pbh = bh->next; + bh->scheduled = 0; + } +} + +void qemu_bh_delete(QEMUBH *bh) +{ + qemu_bh_cancel(bh); + qemu_free(bh); +} + /***********************************************************/ /* machine registration */ @@ -5030,6 +5101,8 @@ void main_loop_wait(int timeout) #ifdef _WIN32 tap_win32_poll(); #endif + qemu_aio_poll(); + qemu_bh_poll(); if (vm_running) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], @@ -6049,6 +6122,7 @@ int main(int argc, char **argv) init_timers(); init_timer_alarm(); + qemu_aio_init(); #ifdef _WIN32 socket_init(); @@ -6093,7 +6167,7 @@ int main(int argc, char **argv) snprintf(buf, sizeof(buf), "hd%c", i + 'a'); bs_table[i] = bdrv_new(buf); } - if (bdrv_open(bs_table[i], hd_filename[i], snapshot) < 0) { + if (bdrv_open(bs_table[i], hd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { fprintf(stderr, "qemu: could not open hard disk image '%s'\n", hd_filename[i]); exit(1); @@ -6118,7 +6192,8 @@ int main(int argc, char **argv) bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY); } if (fd_filename[i] != '\0') { - if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) { + if (bdrv_open(fd_table[i], fd_filename[i], + snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { fprintf(stderr, "qemu: could not open floppy disk image '%s'\n", fd_filename[i]); exit(1); diff --git a/vl.h b/vl.h index d97f485f3..d653f4683 100644 --- a/vl.h +++ b/vl.h @@ -481,6 +481,16 @@ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); void cpu_save(QEMUFile *f, void *opaque); int cpu_load(QEMUFile *f, void *opaque, int version_id); +/* bottom halves */ +typedef struct QEMUBH QEMUBH; +typedef void QEMUBHFunc(void *opaque); + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); +void qemu_bh_schedule(QEMUBH *bh); +void qemu_bh_cancel(QEMUBH *bh); +void qemu_bh_delete(QEMUBH *bh); +void qemu_bh_poll(void); + /* block.c */ typedef struct BlockDriverState BlockDriverState; typedef struct BlockDriver BlockDriver; @@ -495,6 +505,16 @@ extern BlockDriver bdrv_bochs; extern BlockDriver bdrv_vpc; extern BlockDriver bdrv_vvfat; +#define BDRV_O_RDONLY 0x0000 +#define BDRV_O_RDWR 0x0002 +#define BDRV_O_ACCESS 0x0003 +#define BDRV_O_CREAT 0x0004 /* create an empty file */ +#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */ +#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to + use a disk image format on top of + it (default for + bdrv_file_open()) */ + void bdrv_init(void); BlockDriver *bdrv_find_format(const char *format_name); int bdrv_create(BlockDriver *drv, @@ -502,17 +522,44 @@ int bdrv_create(BlockDriver *drv, const char *backing_file, int flags); BlockDriverState *bdrv_new(const char *device_name); void bdrv_delete(BlockDriverState *bs); -int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot); -int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, +int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); +int bdrv_open(BlockDriverState *bs, const char *filename, int flags); +int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, BlockDriver *drv); void bdrv_close(BlockDriverState *bs); int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); +int bdrv_pread(BlockDriverState *bs, int64_t offset, + void *buf, int count); +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, + const void *buf, int count); +int bdrv_truncate(BlockDriverState *bs, int64_t offset); +int64_t bdrv_getlength(BlockDriverState *bs); void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); +/* async block I/O */ +typedef struct BlockDriverAIOCB BlockDriverAIOCB; +typedef void BlockDriverCompletionFunc(void *opaque, int ret); + +BlockDriverAIOCB *bdrv_aio_new(BlockDriverState *bs); +int bdrv_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); +int bdrv_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, + const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); +void bdrv_aio_cancel(BlockDriverAIOCB *acb); +void bdrv_aio_delete(BlockDriverAIOCB *acb); + +void qemu_aio_init(void); +void qemu_aio_poll(void); +void qemu_aio_wait_start(void); +void qemu_aio_wait(void); +void qemu_aio_wait_end(void); + /* Ensure contents are flushed to disk. */ void bdrv_flush(BlockDriverState *bs); @@ -551,6 +598,13 @@ const char *bdrv_get_device_name(BlockDriverState *bs); int qcow_get_cluster_size(BlockDriverState *bs); int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf); +void bdrv_get_backing_filename(BlockDriverState *bs, + char *filename, int filename_size); + +int path_is_absolute(const char *path); +void path_combine(char *dest, int dest_size, + const char *base_path, + const char *filename); #ifndef QEMU_TOOL -- cgit v1.2.3 From 979b67ad863aaa11172f5de781f53c77a392d64c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 2 Aug 2006 22:02:08 +0000 Subject: some compilation fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2076 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/block-raw.c b/block-raw.c index 77502b097..413a8c473 100644 --- a/block-raw.c +++ b/block-raw.c @@ -207,10 +207,11 @@ typedef struct RawAIOCB { static int aio_sig_num = SIGUSR2; static BlockDriverAIOCB *first_aio; /* AIO issued */ +static int aio_initialized = 0; -#ifndef QEMU_TOOL 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 */ @@ -221,11 +222,14 @@ static void aio_signal_handler(int signum) } #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() */ @@ -242,7 +246,6 @@ void qemu_aio_init(void) aio_init(&ai); } } -#endif /* !QEMU_TOOL */ void qemu_aio_poll(void) { @@ -293,6 +296,9 @@ 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); @@ -570,7 +576,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) } else { access_flags = GENERIC_READ; } - if (flags & BDRV_O_CREATE) { + if (flags & BDRV_O_CREAT) { create_flags = CREATE_ALWAYS; } else { create_flags = OPEN_EXISTING; @@ -632,15 +638,17 @@ static int raw_aio_new(BlockDriverAIOCB *acb) if (!acb1) return -ENOMEM; acb->opaque = acb1; - s->hevent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!s->hevent) + s->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!s->hEvent) return -ENOMEM; return 0; } static void raw_aio_cb(void *opaque) { - BlockDriverAIOCB *acb = acb1; + BlockDriverAIOCB *acb = opaque; + BlockDriverState *bs = acb->bs; + BDRVRawState *s = bs->opaque; RawAIOCB *acb1 = acb->opaque; DWORD ret_count; int ret; @@ -659,7 +667,6 @@ static int raw_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, BlockDriverState *bs = acb->bs; BDRVRawState *s = bs->opaque; RawAIOCB *acb1 = acb->opaque; - DWORD ret_count; int ret; int64_t offset; @@ -682,7 +689,6 @@ static int raw_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, BlockDriverState *bs = acb->bs; BDRVRawState *s = bs->opaque; RawAIOCB *acb1 = acb->opaque; - DWORD ret_count; int ret; int64_t offset; @@ -734,8 +740,8 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset) BDRVRawState *s = bs->opaque; DWORD low, high; - low = length; - high = length >> 32; + low = offset; + high = offset >> 32; if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN)) return -EIO; if (!SetEndOfFile(s->hfile)) -- cgit v1.2.3 From 550be12730cfe3c2374deed6189bad281f476ec7 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 2 Aug 2006 22:19:33 +0000 Subject: fixed refresh logic (initial patch by Igor Kovalenko) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2077 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/tcx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/tcx.c b/hw/tcx.c index a3a2114e8..ed32c9424 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -31,7 +31,7 @@ typedef struct TCXState { uint32_t addr; DisplayState *ds; uint8_t *vram; - unsigned long vram_offset; + ram_addr_t vram_offset; uint16_t width, height; uint8_t r[256], g[256], b[256]; uint8_t dac_index, dac_state; @@ -86,8 +86,8 @@ static void tcx_draw_line8(TCXState *s1, uint8_t *d, static void tcx_update_display(void *opaque) { TCXState *ts = opaque; - uint32_t page; - int y, page_min, page_max, y_start, dd, ds; + ram_addr_t page, page_min, page_max; + int y, y_start, dd, ds; uint8_t *d, *s; void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width); @@ -95,8 +95,8 @@ static void tcx_update_display(void *opaque) return; page = ts->vram_offset; y_start = -1; - page_min = 0x7fffffff; - page_max = -1; + page_min = 0xffffffff; + page_max = 0; d = ts->ds->data; s = ts->vram; dd = ts->ds->linesize; @@ -154,7 +154,7 @@ static void tcx_update_display(void *opaque) ts->width, y - y_start); } /* reset modified pages */ - if (page_max != -1) { + if (page_min <= page_max) { cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, VGA_DIRTY_FLAG); } -- cgit v1.2.3 From 436e15b827be64cf29b2154863af39f71e5ea7d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Aug 2006 09:07:19 +0000 Subject: win32 fixes (initial patch by kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2078 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/block-raw.c b/block-raw.c index 413a8c473..33ad64741 100644 --- a/block-raw.c +++ b/block-raw.c @@ -518,7 +518,6 @@ BlockDriver bdrv_raw = { #else /* _WIN32 */ /* XXX: use another file ? */ -#include #include typedef struct BDRVRawState { @@ -600,12 +599,14 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, memset(&ov, 0, sizeof(ov)); ov.Offset = offset; ov.OffsetHigh = offset >> 32; - ret = ReadFile(s->hfile, buf, count, NULL, &ov); - if (!ret) - return -EIO; - ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE); - if (!ret) - return -EIO; + 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; } @@ -620,30 +621,31 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, memset(&ov, 0, sizeof(ov)); ov.Offset = offset; ov.OffsetHigh = offset >> 32; - ret = WriteFile(s->hfile, buf, count, NULL, &ov); - if (!ret) - return -EIO; - ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE); - if (!ret) - return -EIO; + 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; } static int raw_aio_new(BlockDriverAIOCB *acb) { RawAIOCB *acb1; - BDRVRawState *s = acb->bs->opaque; acb1 = qemu_mallocz(sizeof(RawAIOCB)); if (!acb1) return -ENOMEM; acb->opaque = acb1; - s->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!s->hEvent) + acb1->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!acb1->hEvent) return -ENOMEM; return 0; } - +#ifndef QEMU_TOOL static void raw_aio_cb(void *opaque) { BlockDriverAIOCB *acb = opaque; @@ -660,7 +662,7 @@ static void raw_aio_cb(void *opaque) acb->cb(acb->cb_opaque, 0); } } - +#endif static int raw_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, uint8_t *buf, int nb_sectors) { @@ -676,7 +678,9 @@ static int raw_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, acb1->ov.OffsetHigh = offset >> 32; acb1->ov.hEvent = acb1->hEvent; acb1->count = nb_sectors * 512; +#ifndef QEMU_TOOL qemu_add_wait_object(acb1->ov.hEvent, raw_aio_cb, acb); +#endif ret = ReadFile(s->hfile, buf, acb1->count, NULL, &acb1->ov); if (!ret) return -EIO; @@ -698,7 +702,9 @@ static int raw_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, acb1->ov.OffsetHigh = offset >> 32; acb1->ov.hEvent = acb1->hEvent; acb1->count = nb_sectors * 512; +#ifndef QEMU_TOOL qemu_add_wait_object(acb1->ov.hEvent, raw_aio_cb, acb); +#endif ret = ReadFile(s->hfile, buf, acb1->count, NULL, &acb1->ov); if (!ret) return -EIO; @@ -709,9 +715,11 @@ static void raw_aio_cancel(BlockDriverAIOCB *acb) { BlockDriverState *bs = acb->bs; BDRVRawState *s = bs->opaque; +#ifndef QEMU_TOOL RawAIOCB *acb1 = acb->opaque; qemu_del_wait_object(acb1->ov.hEvent, raw_aio_cb, acb); +#endif /* XXX: if more than one async I/O it is not correct */ CancelIo(s->hfile); } @@ -753,8 +761,10 @@ static int64_t raw_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; LARGE_INTEGER l; - if (!GetFileSizeEx(s->hfile, &l)) - return -EIO; + + l.LowPart = GetFileSize(s->hfile, &l.HighPart); + if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) + return -EIO; return l.QuadPart; } -- cgit v1.2.3 From e7b81015e5b8d03c13670940a80c9be0eeb816f6 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Aug 2006 17:52:41 +0000 Subject: added missing returns git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2079 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/block-qcow.c b/block-qcow.c index 65e74e778..9ad7061d3 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -649,6 +649,7 @@ static int qcow_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, acb1->cluster_offset = 0; qcow_aio_read_cb(acb, 0); + return 0; } static void qcow_aio_write_cb(void *opaque, int ret) @@ -725,6 +726,7 @@ static int qcow_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, acb1->n = 0; qcow_aio_write_cb(acb, 0); + return 0; } static void qcow_aio_cancel(BlockDriverAIOCB *acb) -- cgit v1.2.3 From 7f1a8398ab447c9ba2cc0e73935d7c97d6075053 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Aug 2006 17:53:19 +0000 Subject: removed unused code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2080 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 238 ---------------------------------------------------------------- osdep.h | 35 ---------- 2 files changed, 273 deletions(-) diff --git a/osdep.c b/osdep.c index c1dd294e6..348fcf2ca 100644 --- a/osdep.c +++ b/osdep.c @@ -33,242 +33,6 @@ #include "vl.h" #endif -#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) - -#include -#include - -/* When not using soft mmu, libc independant functions are needed for - the CPU core because it needs to use alternates stacks and - libc/thread incompatibles settings */ - -#include - -#define QEMU_SYSCALL0(name) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name)); \ -return __res; \ -} - -#define QEMU_SYSCALL1(name,arg1) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1))); \ -return __res; \ -} - -#define QEMU_SYSCALL2(name,arg1,arg2) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \ -return __res; \ -} - -#define QEMU_SYSCALL3(name,arg1,arg2,arg3) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3))); \ -return __res; \ -} - -#define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4))); \ -return __res; \ -} - -#define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \ -return __res; \ -} - -#define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \ -{ \ -long __res; \ -__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \ - : "=a" (__res) \ - : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \ - "0" ((long)(arg6))); \ -return __res; \ -} - -/****************************************************************/ -/* shmat replacement */ - -int qemu_ipc(int call, unsigned long first, - unsigned long second, unsigned long third, - void *ptr, unsigned long fifth) -{ - QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth); -} - -#define SHMAT 21 - -/* we must define shmat so that a specific address will be used when - mapping the X11 ximage */ -void *shmat(int shmid, const void *shmaddr, int shmflg) -{ - void *ptr; - int ret; - /* we give an address in the right memory area */ - if (!shmaddr) - shmaddr = get_mmap_addr(8192 * 1024); - ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0); - if (ret < 0) - return NULL; - return ptr; -} - -/****************************************************************/ -/* sigaction bypassing the threads */ - -static int kernel_sigaction(int signum, const struct qemu_sigaction *act, - struct qemu_sigaction *oldact, - int sigsetsize) -{ - QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize); -} - -int qemu_sigaction(int signum, const struct qemu_sigaction *act, - struct qemu_sigaction *oldact) -{ - return kernel_sigaction(signum, act, oldact, 8); -} - -/****************************************************************/ -/* memory allocation */ - -//#define DEBUG_MALLOC - -#define MALLOC_BASE 0xab000000 -#define PHYS_RAM_BASE 0xac000000 - -#define MALLOC_ALIGN 16 -#define BLOCK_HEADER_SIZE 16 - -typedef struct MemoryBlock { - struct MemoryBlock *next; - unsigned long size; /* size of block, including header */ -} MemoryBlock; - -static MemoryBlock *first_free_block; -static unsigned long malloc_addr = MALLOC_BASE; - -static void *malloc_get_space(size_t size) -{ - void *ptr; - size = TARGET_PAGE_ALIGN(size); - ptr = mmap((void *)malloc_addr, size, - PROT_WRITE | PROT_READ, - MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0); - if (ptr == MAP_FAILED) - return NULL; - malloc_addr += size; - return ptr; -} - -void *qemu_malloc(size_t size) -{ - MemoryBlock *mb, *mb1, **pmb; - void *ptr; - size_t size1, area_size; - - if (size == 0) - return NULL; - - size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1); - pmb = &first_free_block; - for(;;) { - mb = *pmb; - if (mb == NULL) - break; - if (size <= mb->size) - goto found; - pmb = &mb->next; - } - /* no big enough blocks found: get new space */ - area_size = TARGET_PAGE_ALIGN(size); - mb = malloc_get_space(area_size); - if (!mb) - return NULL; - size1 = area_size - size; - if (size1 > 0) { - /* create a new free block */ - mb1 = (MemoryBlock *)((uint8_t *)mb + size); - mb1->next = NULL; - mb1->size = size1; - *pmb = mb1; - } - goto the_end; - found: - /* a free block was found: use it */ - size1 = mb->size - size; - if (size1 > 0) { - /* create a new free block */ - mb1 = (MemoryBlock *)((uint8_t *)mb + size); - mb1->next = mb->next; - mb1->size = size1; - *pmb = mb1; - } else { - /* suppress the first block */ - *pmb = mb->next; - } - the_end: - mb->size = size; - mb->next = NULL; - ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE); -#ifdef DEBUG_MALLOC - qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr); -#endif - return ptr; -} - -void qemu_free(void *ptr) -{ - MemoryBlock *mb; - - if (!ptr) - return; - mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE); - mb->next = first_free_block; - first_free_block = mb; -} - -/****************************************************************/ -/* virtual memory allocation */ - -unsigned long mmap_addr = PHYS_RAM_BASE; - -void *get_mmap_addr(unsigned long size) -{ - unsigned long addr; - addr = mmap_addr; - mmap_addr += ((size + 4095) & ~4095) + 4096; - return (void *)addr; -} - -#else - #ifdef _WIN32 #include #elif defined(_BSD) @@ -424,8 +188,6 @@ void qemu_vfree(void *ptr) #endif -#endif - void *qemu_mallocz(size_t size) { void *ptr; diff --git a/osdep.h b/osdep.h index 661e6e86a..325baf14e 100644 --- a/osdep.h +++ b/osdep.h @@ -15,39 +15,4 @@ void qemu_vfree(void *ptr); void *get_mmap_addr(unsigned long size); -/* specific kludges for OS compatibility (should be moved elsewhere) */ -#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY) - -/* disabled pthread version of longjmp which prevent us from using an - alternative signal stack */ -extern void __longjmp(jmp_buf env, int val); -#define longjmp __longjmp - -#include - -struct siginfo; - -/* NOTE: it works only because the glibc sigset_t is >= kernel sigset_t */ -struct qemu_sigaction { - union { - void (*_sa_handler)(int); - void (*_sa_sigaction)(int, struct siginfo *, void *); - } _u; - unsigned long sa_flags; - void (*sa_restorer)(void); - sigset_t sa_mask; /* mask last for extensibility */ -}; - -int qemu_sigaction(int signum, const struct qemu_sigaction *act, - struct qemu_sigaction *oldact); - -#undef sigaction -#undef sa_handler -#undef sa_sigaction -#define sigaction qemu_sigaction -#define sa_handler _u._sa_handler -#define sa_sigaction _u._sa_sigaction - -#endif - #endif -- cgit v1.2.3 From e2f909bef950fa5aae9939fd917e7bd0c3b63042 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 3 Aug 2006 20:39:40 +0000 Subject: swapped memset args (Charles Coffing) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2081 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 8e7af1aca..556e6fdbc 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -605,11 +605,11 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) } if (info->sign) { - memset (buf, len << info->shift, 0x00); + memset (buf, 0x00, len << info->shift); } else { if (info->bits == 8) { - memset (buf, len << info->shift, 0x80); + memset (buf, 0x80, len << info->shift); } else { int i; -- cgit v1.2.3 From 9e46cfa4c69a9720080d11aa68ef24cf9dddeb4d Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 4 Aug 2006 21:55:15 +0000 Subject: sparc64.ld file (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2082 c046a42c-6fe2-441c-8c8c-71466251a162 --- sparc64.ld | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 sparc64.ld diff --git a/sparc64.ld b/sparc64.ld new file mode 100644 index 000000000..19853ff68 --- /dev/null +++ b/sparc64.ld @@ -0,0 +1,138 @@ +OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", + "elf64-sparc") +OUTPUT_ARCH(sparc:v9) +SEARCH_DIR(/lib64); SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib64); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib64); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x60000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x47ff041f + .text : + { + *(.text) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x47ff041f + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x47ff041f + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + . = ALIGN(64 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + .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 . */ +} -- cgit v1.2.3 From 585f8587ad3619cf070fdc19d2d0b8e7a2398d91 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Aug 2006 21:14:20 +0000 Subject: new qcow2 disk image format git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2083 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow2.c | 2236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2236 insertions(+) create mode 100644 block-qcow2.c diff --git a/block-qcow2.c b/block-qcow2.c new file mode 100644 index 000000000..f499b13be --- /dev/null +++ b/block-qcow2.c @@ -0,0 +1,2236 @@ +/* + * 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 +#include "aes.h" +#include + +/* + 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; +} + +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; +} + +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 { + int64_t sector_num; + uint8_t *buf; + int nb_sectors; + int n; + uint64_t cluster_offset; + uint8_t *cluster_data; + BlockDriverAIOCB *hd_aiocb; + BlockDriverAIOCB *backing_hd_aiocb; +} QCowAIOCB; + +static void qcow_aio_delete(BlockDriverAIOCB *acb); + +static int qcow_aio_new(BlockDriverAIOCB *acb) +{ + BlockDriverState *bs = acb->bs; + BDRVQcowState *s = bs->opaque; + QCowAIOCB *acb1; + acb1 = qemu_mallocz(sizeof(QCowAIOCB)); + if (!acb1) + return -1; + acb->opaque = acb1; + acb1->hd_aiocb = bdrv_aio_new(s->hd); + if (!acb1->hd_aiocb) + goto fail; + if (bs->backing_hd) { + acb1->backing_hd_aiocb = bdrv_aio_new(bs->backing_hd); + if (!acb1->backing_hd_aiocb) + goto fail; + } + return 0; + fail: + qcow_aio_delete(acb); + return -1; +} + +static void qcow_aio_read_cb(void *opaque, int ret) +{ + BlockDriverAIOCB *acb = opaque; + BlockDriverState *bs = acb->bs; + BDRVQcowState *s = bs->opaque; + QCowAIOCB *acb1 = acb->opaque; + int index_in_cluster; + + if (ret < 0) { + fail: + acb->cb(acb->cb_opaque, ret); + return; + } + + redo: + /* post process the read buffer */ + if (!acb1->cluster_offset) { + /* nothing to do */ + } else if (acb1->cluster_offset & QCOW_OFLAG_COMPRESSED) { + /* nothing to do */ + } else { + if (s->crypt_method) { + encrypt_sectors(s, acb1->sector_num, acb1->buf, acb1->buf, + acb1->n, 0, + &s->aes_decrypt_key); + } + } + + acb1->nb_sectors -= acb1->n; + acb1->sector_num += acb1->n; + acb1->buf += acb1->n * 512; + + if (acb1->nb_sectors == 0) { + /* request completed */ + acb->cb(acb->cb_opaque, 0); + return; + } + + /* prepare next AIO request */ + acb1->cluster_offset = get_cluster_offset(bs, + acb1->sector_num << 9, + 0, 0, 0, 0); + index_in_cluster = acb1->sector_num & (s->cluster_sectors - 1); + acb1->n = s->cluster_sectors - index_in_cluster; + if (acb1->n > acb1->nb_sectors) + acb1->n = acb1->nb_sectors; + + if (!acb1->cluster_offset) { + if (bs->backing_hd) { + /* read from the base image */ + ret = bdrv_aio_read(acb1->backing_hd_aiocb, acb1->sector_num, + acb1->buf, acb1->n, qcow_aio_read_cb, acb); + if (ret < 0) + goto fail; + } else { + /* Note: in this case, no need to wait */ + memset(acb1->buf, 0, 512 * acb1->n); + goto redo; + } + } else if (acb1->cluster_offset & QCOW_OFLAG_COMPRESSED) { + /* add AIO support for compressed blocks ? */ + if (decompress_cluster(s, acb1->cluster_offset) < 0) + goto fail; + memcpy(acb1->buf, + s->cluster_cache + index_in_cluster * 512, 512 * acb1->n); + goto redo; + } else { + if ((acb1->cluster_offset & 511) != 0) { + ret = -EIO; + goto fail; + } + ret = bdrv_aio_read(acb1->hd_aiocb, + (acb1->cluster_offset >> 9) + index_in_cluster, + acb1->buf, acb1->n, qcow_aio_read_cb, acb); + if (ret < 0) + goto fail; + } +} + +static int qcow_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + QCowAIOCB *acb1 = acb->opaque; + + acb1->sector_num = sector_num; + acb1->buf = buf; + acb1->nb_sectors = nb_sectors; + acb1->n = 0; + acb1->cluster_offset = 0; + + qcow_aio_read_cb(acb, 0); + return 0; +} + +static void qcow_aio_write_cb(void *opaque, int ret) +{ + BlockDriverAIOCB *acb = opaque; + BlockDriverState *bs = acb->bs; + BDRVQcowState *s = bs->opaque; + QCowAIOCB *acb1 = acb->opaque; + int index_in_cluster; + uint64_t cluster_offset; + const uint8_t *src_buf; + + if (ret < 0) { + fail: + acb->cb(acb->cb_opaque, ret); + return; + } + + acb1->nb_sectors -= acb1->n; + acb1->sector_num += acb1->n; + acb1->buf += acb1->n * 512; + + if (acb1->nb_sectors == 0) { + /* request completed */ + acb->cb(acb->cb_opaque, 0); + return; + } + + index_in_cluster = acb1->sector_num & (s->cluster_sectors - 1); + acb1->n = s->cluster_sectors - index_in_cluster; + if (acb1->n > acb1->nb_sectors) + acb1->n = acb1->nb_sectors; + cluster_offset = get_cluster_offset(bs, acb1->sector_num << 9, 1, 0, + index_in_cluster, + index_in_cluster + acb1->n); + if (!cluster_offset || (cluster_offset & 511) != 0) { + ret = -EIO; + goto fail; + } + if (s->crypt_method) { + if (!acb1->cluster_data) { + acb1->cluster_data = qemu_mallocz(s->cluster_size); + if (!acb1->cluster_data) { + ret = -ENOMEM; + goto fail; + } + } + encrypt_sectors(s, acb1->sector_num, acb1->cluster_data, acb1->buf, + acb1->n, 1, &s->aes_encrypt_key); + src_buf = acb1->cluster_data; + } else { + src_buf = acb1->buf; + } + ret = bdrv_aio_write(acb1->hd_aiocb, + (cluster_offset >> 9) + index_in_cluster, + src_buf, acb1->n, + qcow_aio_write_cb, acb); + if (ret < 0) + goto fail; +} + +static int qcow_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + QCowAIOCB *acb1 = acb->opaque; + BlockDriverState *bs = acb->bs; + BDRVQcowState *s = bs->opaque; + + s->cluster_cache_offset = -1; /* disable compressed cache */ + + acb1->sector_num = sector_num; + acb1->buf = (uint8_t *)buf; + acb1->nb_sectors = nb_sectors; + acb1->n = 0; + + qcow_aio_write_cb(acb, 0); + return 0; +} + +static void qcow_aio_cancel(BlockDriverAIOCB *acb) +{ + QCowAIOCB *acb1 = acb->opaque; + if (acb1->hd_aiocb) + bdrv_aio_cancel(acb1->hd_aiocb); + if (acb1->backing_hd_aiocb) + bdrv_aio_cancel(acb1->backing_hd_aiocb); +} + +static void qcow_aio_delete(BlockDriverAIOCB *acb) +{ + QCowAIOCB *acb1 = acb->opaque; + if (acb1->hd_aiocb) + bdrv_aio_delete(acb1->hd_aiocb); + if (acb1->backing_hd_aiocb) + bdrv_aio_delete(acb1->backing_hd_aiocb); + qemu_free(acb1->cluster_data); + qemu_free(acb1); +} + +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, 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); + 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; + } + + 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_new = qcow_aio_new, + .bdrv_aio_read = qcow_aio_read, + .bdrv_aio_write = qcow_aio_write, + .bdrv_aio_cancel = qcow_aio_cancel, + .bdrv_aio_delete = qcow_aio_delete, + .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, +}; -- cgit v1.2.3 From 9ab8a34a183b7f7c37fb4e8e6d33fa82b4840005 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Aug 2006 21:27:55 +0000 Subject: O_LARGEFILE is not needed git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2084 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-raw.c b/block-raw.c index 33ad64741..14f4bd5b3 100644 --- a/block-raw.c +++ b/block-raw.c @@ -477,7 +477,7 @@ static int raw_create(const char *filename, int64_t total_size, if (flags || backing_file) return -ENOTSUP; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); if (fd < 0) return -EIO; -- cgit v1.2.3 From 42ca638823ad463d5eb0301d160887883fad9efd Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Aug 2006 21:29:27 +0000 Subject: enable qcow2 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2085 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- Makefile.target | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 28a4f861b..f0a8199f9 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ subdir-%: dyngen$(EXESUF) recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) -qemu-img$(EXESUF): qemu-img.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 +qemu-img$(EXESUF): qemu-img.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) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c diff --git a/Makefile.target b/Makefile.target index 04cdb21af..7ace0a83b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -291,7 +291,7 @@ 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 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 +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 -- cgit v1.2.3 From faea38e7863a6e29f110063388eb93840fcd475c Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Aug 2006 21:31:00 +0000 Subject: multiple snapshot support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2086 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 144 +++++++++++++++- block_int.h | 11 ++ monitor.c | 24 +-- qemu-img.c | 71 ++++---- vl.c | 550 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- vl.h | 50 +++++- 6 files changed, 711 insertions(+), 139 deletions(-) diff --git a/block.c b/block.c index 3cf8b7b12..529dd4e25 100644 --- a/block.c +++ b/block.c @@ -494,12 +494,10 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, } } -#if 0 /* not necessary now */ static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, - void *buf1, int count1) + uint8_t *buf, int count1) { - uint8_t *buf = buf1; uint8_t tmp_buf[SECTOR_SIZE]; int len, nb_sectors, count; int64_t sector_num; @@ -542,9 +540,8 @@ static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, } static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, - const void *buf1, int count1) + const uint8_t *buf, int count1) { - const uint8_t *buf = buf1; uint8_t tmp_buf[SECTOR_SIZE]; int len, nb_sectors, count; int64_t sector_num; @@ -589,7 +586,6 @@ static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, } return count1; } -#endif /** * Read with byte offsets (needed only for file protocols) @@ -602,7 +598,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, if (!drv) return -ENOENT; if (!drv->bdrv_pread) - return -ENOTSUP; + return bdrv_pread_em(bs, offset, buf1, count1); return drv->bdrv_pread(bs, offset, buf1, count1); } @@ -617,7 +613,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, if (!drv) return -ENOENT; if (!drv->bdrv_pwrite) - return -ENOTSUP; + return bdrv_pwrite_em(bs, offset, buf1, count1); return drv->bdrv_pwrite(bs, offset, buf1, count1); } @@ -859,6 +855,137 @@ void bdrv_get_backing_filename(BlockDriverState *bs, } } +int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + BlockDriver *drv = bs->drv; + if (!drv) + return -ENOENT; + 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 -ENOENT; + 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 -ENOENT; + 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 -ENOENT; + 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 -ENOENT; + 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 -ENOENT; + 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]; + struct tm tm; + 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; + localtime_r(&ti, &tm); + strftime(date_buf, sizeof(date_buf), + "%Y-%m-%d %H:%M:%S", &tm); + 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 */ @@ -1108,4 +1235,5 @@ void bdrv_init(void) bdrv_register(&bdrv_bochs); bdrv_register(&bdrv_vpc); bdrv_register(&bdrv_vvfat); + bdrv_register(&bdrv_qcow2); } diff --git a/block_int.h b/block_int.h index e40503ea3..b3bc5b387 100644 --- a/block_int.h +++ b/block_int.h @@ -57,6 +57,17 @@ struct BlockDriver { 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); struct BlockDriver *next; }; diff --git a/monitor.c b/monitor.c index b48e8cc70..b40eac4c4 100644 --- a/monitor.c +++ b/monitor.c @@ -380,18 +380,6 @@ static void do_log(const char *items) cpu_set_log(mask); } -static void do_savevm(const char *filename) -{ - if (qemu_savevm(filename) < 0) - term_printf("I/O error when saving VM to '%s'\n", filename); -} - -static void do_loadvm(const char *filename) -{ - if (qemu_loadvm(filename) < 0) - term_printf("I/O error when loading VM from '%s'\n", filename); -} - static void do_stop(void) { vm_stop(EXCP_INTERRUPT); @@ -1155,10 +1143,12 @@ static term_cmd_t term_cmds[] = { "filename", "save screen into PPM image 'filename'" }, { "log", "s", do_log, "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, - { "savevm", "F", do_savevm, - "filename", "save the whole virtual machine state to 'filename'" }, - { "loadvm", "F", do_loadvm, - "filename", "restore the whole virtual machine state from 'filename'" }, + { "savevm", "s?", do_savevm, + "tag|id", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" }, + { "loadvm", "s", do_loadvm, + "tag|id", "restore a VM snapshot from its tag or id" }, + { "delvm", "s", do_delvm, + "tag|id", "delete a VM snapshot from its tag or id" }, { "stop", "", do_stop, "", "stop emulation", }, { "c|cont", "", do_cont, @@ -1241,6 +1231,8 @@ static term_cmd_t info_cmds[] = { "", "show profiling information", }, { "capture", "", do_info_capture, "show capture information" }, + { "snapshots", "", do_info_snapshots, + "show the currently saved VM snapshots" }, { NULL, NULL, }, }; diff --git a/qemu-img.c b/qemu-img.c index 8b2acad14..06687bc1f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -159,36 +159,6 @@ void help(void) exit(1); } - -#define NB_SUFFIXES 4 - -static void 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; - } - } -} - #if defined(WIN32) /* XXX: put correct support for win32 */ static int read_password(char *buf, int buf_size) @@ -486,6 +456,7 @@ static int img_convert(int argc, char **argv) int64_t total_sectors, nb_sectors, sector_num; uint8_t buf[IO_BUF_SIZE]; const uint8_t *buf1; + BlockDriverInfo bdi; fmt = NULL; out_fmt = "raw"; @@ -525,9 +496,9 @@ static int img_convert(int argc, char **argv) drv = bdrv_find_format(out_fmt); if (!drv) error("Unknown file format '%s'", fmt); - if (compress && drv != &bdrv_qcow) + if (compress && drv != &bdrv_qcow && drv != &bdrv_qcow2) error("Compression not supported for this file format"); - if (encrypt && drv != &bdrv_qcow) + if (encrypt && drv != &bdrv_qcow && drv != &bdrv_qcow2) error("Encryption not supported for this file format"); if (compress && encrypt) error("Compression and encryption not supported at the same time"); @@ -544,7 +515,9 @@ static int img_convert(int argc, char **argv) out_bs = bdrv_new_open(out_filename, out_fmt); if (compress) { - cluster_size = qcow_get_cluster_size(out_bs); + if (bdrv_get_info(out_bs, &bdi) < 0) + error("could not get block driver info"); + cluster_size = bdi.cluster_size; if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) error("invalid cluster size"); cluster_sectors = cluster_size >> 9; @@ -562,12 +535,15 @@ static int img_convert(int argc, char **argv) if (n < cluster_sectors) memset(buf + n * 512, 0, cluster_size - n * 512); if (is_not_zero(buf, cluster_size)) { - if (qcow_compress_cluster(out_bs, sector_num, buf) != 0) + if (bdrv_write_compressed(out_bs, sector_num, buf, + cluster_sectors) != 0) error("error while compressing sector %" PRId64, sector_num); } sector_num += n; } + /* signal EOF to align */ + bdrv_write_compressed(out_bs, 0, NULL, 0); } else { sector_num = 0; for(;;) { @@ -630,6 +606,24 @@ static int64_t get_allocated_file_size(const char *filename) } #endif +static void dump_snapshots(BlockDriverState *bs) +{ + QEMUSnapshotInfo *sn_tab, *sn; + int nb_sns, i; + char buf[256]; + + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + if (nb_sns <= 0) + return; + printf("Snapshot list:\n"); + printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); + for(i = 0; i < nb_sns; i++) { + sn = &sn_tab[i]; + printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); + } + qemu_free(sn_tab); +} + static int img_info(int argc, char **argv) { int c; @@ -640,6 +634,7 @@ static int img_info(int argc, char **argv) int64_t total_sectors, allocated_size; char backing_filename[1024]; char backing_filename2[1024]; + BlockDriverInfo bdi; fmt = NULL; for(;;) { @@ -690,13 +685,19 @@ static int img_info(int argc, char **argv) dsize_buf); if (bdrv_is_encrypted(bs)) printf("encrypted: yes\n"); + if (bdrv_get_info(bs, &bdi) >= 0) { + if (bdi.cluster_size != 0) + printf("cluster_size: %d\n", bdi.cluster_size); + } bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); - if (backing_filename[0] != '\0') + if (backing_filename[0] != '\0') { path_combine(backing_filename2, sizeof(backing_filename2), filename, backing_filename); printf("backing file: %s (actual path: %s)\n", backing_filename, backing_filename2); + } + dump_snapshots(bs); bdrv_delete(bs); return 0; } diff --git a/vl.c b/vl.c index b31b2398a..6daed966b 100644 --- a/vl.c +++ b/vl.c @@ -113,7 +113,11 @@ char phys_ram_file[1024]; void *ioport_opaque[MAX_IOPORTS]; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; -BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD]; +/* Note: bs_table[MAX_DISKS] is a dummy block driver if none available + to store the VM snapshots */ +BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; +/* point to the block driver where the snapshots are managed */ +BlockDriverState *bs_snapshots; int vga_ram_size; int bios_size; static DisplayState display_state; @@ -4085,14 +4089,190 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) /***********************************************************/ /* savevm/loadvm support */ +#define IO_BUF_SIZE 32768 + +struct QEMUFile { + FILE *outfile; + BlockDriverState *bs; + int is_file; + int is_writable; + int64_t base_offset; + int64_t buf_offset; /* start of buffer when writing, end of buffer + when reading */ + int buf_index; + int buf_size; /* 0 when writing */ + uint8_t buf[IO_BUF_SIZE]; +}; + +QEMUFile *qemu_fopen(const char *filename, const char *mode) +{ + QEMUFile *f; + + f = qemu_mallocz(sizeof(QEMUFile)); + if (!f) + return NULL; + if (!strcmp(mode, "wb")) { + f->is_writable = 1; + } else if (!strcmp(mode, "rb")) { + f->is_writable = 0; + } else { + goto fail; + } + f->outfile = fopen(filename, mode); + if (!f->outfile) + goto fail; + f->is_file = 1; + return f; + fail: + if (f->outfile) + fclose(f->outfile); + qemu_free(f); + return NULL; +} + +QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) +{ + QEMUFile *f; + + f = qemu_mallocz(sizeof(QEMUFile)); + if (!f) + return NULL; + f->is_file = 0; + f->bs = bs; + f->is_writable = is_writable; + f->base_offset = offset; + return f; +} + +void qemu_fflush(QEMUFile *f) +{ + if (!f->is_writable) + return; + if (f->buf_index > 0) { + if (f->is_file) { + fseek(f->outfile, f->buf_offset, SEEK_SET); + fwrite(f->buf, 1, f->buf_index, f->outfile); + } else { + bdrv_pwrite(f->bs, f->base_offset + f->buf_offset, + f->buf, f->buf_index); + } + f->buf_offset += f->buf_index; + f->buf_index = 0; + } +} + +static void qemu_fill_buffer(QEMUFile *f) +{ + int len; + + if (f->is_writable) + return; + if (f->is_file) { + fseek(f->outfile, f->buf_offset, SEEK_SET); + len = fread(f->buf, 1, IO_BUF_SIZE, f->outfile); + if (len < 0) + len = 0; + } else { + len = bdrv_pread(f->bs, f->base_offset + f->buf_offset, + f->buf, IO_BUF_SIZE); + if (len < 0) + len = 0; + } + f->buf_index = 0; + f->buf_size = len; + f->buf_offset += len; +} + +void qemu_fclose(QEMUFile *f) +{ + if (f->is_writable) + qemu_fflush(f); + if (f->is_file) { + fclose(f->outfile); + } + qemu_free(f); +} + void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) { - fwrite(buf, 1, size, f); + int l; + while (size > 0) { + l = IO_BUF_SIZE - f->buf_index; + if (l > size) + l = size; + memcpy(f->buf + f->buf_index, buf, l); + f->buf_index += l; + buf += l; + size -= l; + if (f->buf_index >= IO_BUF_SIZE) + qemu_fflush(f); + } } void qemu_put_byte(QEMUFile *f, int v) { - fputc(v, f); + f->buf[f->buf_index++] = v; + if (f->buf_index >= IO_BUF_SIZE) + qemu_fflush(f); +} + +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1) +{ + int size, l; + + size = size1; + while (size > 0) { + l = f->buf_size - f->buf_index; + if (l == 0) { + qemu_fill_buffer(f); + l = f->buf_size - f->buf_index; + if (l == 0) + break; + } + if (l > size) + l = size; + memcpy(buf, f->buf + f->buf_index, l); + f->buf_index += l; + buf += l; + size -= l; + } + return size1 - size; +} + +int qemu_get_byte(QEMUFile *f) +{ + if (f->buf_index >= f->buf_size) { + qemu_fill_buffer(f); + if (f->buf_index >= f->buf_size) + return 0; + } + return f->buf[f->buf_index++]; +} + +int64_t qemu_ftell(QEMUFile *f) +{ + return f->buf_offset - f->buf_size + f->buf_index; +} + +int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) +{ + if (whence == SEEK_SET) { + /* nothing to do */ + } else if (whence == SEEK_CUR) { + pos += qemu_ftell(f); + } else { + /* SEEK_END not supported */ + return -1; + } + if (f->is_writable) { + qemu_fflush(f); + f->buf_offset = pos; + } else { + f->buf_offset = pos; + f->buf_index = 0; + f->buf_size = 0; + } + return pos; } void qemu_put_be16(QEMUFile *f, unsigned int v) @@ -4115,21 +4295,6 @@ void qemu_put_be64(QEMUFile *f, uint64_t v) qemu_put_be32(f, v); } -int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) -{ - return fread(buf, 1, size, f); -} - -int qemu_get_byte(QEMUFile *f) -{ - int v; - v = fgetc(f); - if (v == EOF) - return 0; - else - return v; -} - unsigned int qemu_get_be16(QEMUFile *f) { unsigned int v; @@ -4156,18 +4321,6 @@ uint64_t qemu_get_be64(QEMUFile *f) return v; } -int64_t qemu_ftell(QEMUFile *f) -{ - return ftell(f); -} - -int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) -{ - if (fseek(f, pos, whence) < 0) - return -1; - return ftell(f); -} - typedef struct SaveStateEntry { char idstr[256]; int instance_id; @@ -4209,25 +4362,18 @@ int register_savevm(const char *idstr, } #define QEMU_VM_FILE_MAGIC 0x5145564d -#define QEMU_VM_FILE_VERSION 0x00000001 +#define QEMU_VM_FILE_VERSION 0x00000002 -int qemu_savevm(const char *filename) +int qemu_savevm_state(QEMUFile *f) { SaveStateEntry *se; - QEMUFile *f; - int len, len_pos, cur_pos, saved_vm_running, ret; - - saved_vm_running = vm_running; - vm_stop(0); - - f = fopen(filename, "wb"); - if (!f) { - ret = -1; - goto the_end; - } + int len, ret; + int64_t cur_pos, len_pos, total_len_pos; qemu_put_be32(f, QEMU_VM_FILE_MAGIC); qemu_put_be32(f, QEMU_VM_FILE_VERSION); + total_len_pos = qemu_ftell(f); + qemu_put_be64(f, 0); /* total size */ for(se = first_se; se != NULL; se = se->next) { /* ID string */ @@ -4239,24 +4385,24 @@ int qemu_savevm(const char *filename) qemu_put_be32(f, se->version_id); /* record size: filled later */ - len_pos = ftell(f); + len_pos = qemu_ftell(f); qemu_put_be32(f, 0); se->save_state(f, se->opaque); /* fill record size */ - cur_pos = ftell(f); - len = ftell(f) - len_pos - 4; - fseek(f, len_pos, SEEK_SET); + cur_pos = qemu_ftell(f); + len = cur_pos - len_pos - 4; + qemu_fseek(f, len_pos, SEEK_SET); qemu_put_be32(f, len); - fseek(f, cur_pos, SEEK_SET); + qemu_fseek(f, cur_pos, SEEK_SET); } + cur_pos = qemu_ftell(f); + qemu_fseek(f, total_len_pos, SEEK_SET); + qemu_put_be64(f, cur_pos - total_len_pos - 8); + qemu_fseek(f, cur_pos, SEEK_SET); - fclose(f); ret = 0; - the_end: - if (saved_vm_running) - vm_start(); return ret; } @@ -4272,38 +4418,29 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id) return NULL; } -int qemu_loadvm(const char *filename) +int qemu_loadvm_state(QEMUFile *f) { SaveStateEntry *se; - QEMUFile *f; - int len, cur_pos, ret, instance_id, record_len, version_id; - int saved_vm_running; + int len, ret, instance_id, record_len, version_id; + int64_t total_len, end_pos, cur_pos; unsigned int v; char idstr[256]; - saved_vm_running = vm_running; - vm_stop(0); - - f = fopen(filename, "rb"); - if (!f) { - ret = -1; - goto the_end; - } - v = qemu_get_be32(f); if (v != QEMU_VM_FILE_MAGIC) goto fail; v = qemu_get_be32(f); if (v != QEMU_VM_FILE_VERSION) { fail: - fclose(f); ret = -1; goto the_end; } + total_len = qemu_get_be64(f); + end_pos = total_len + qemu_ftell(f); for(;;) { - len = qemu_get_byte(f); - if (feof(f)) + if (qemu_ftell(f) >= end_pos) break; + len = qemu_get_byte(f); qemu_get_buffer(f, idstr, len); idstr[len] = '\0'; instance_id = qemu_get_be32(f); @@ -4313,7 +4450,7 @@ int qemu_loadvm(const char *filename) printf("idstr=%s instance=0x%x version=%d len=%d\n", idstr, instance_id, version_id, record_len); #endif - cur_pos = ftell(f); + cur_pos = qemu_ftell(f); se = find_se(idstr, instance_id); if (!se) { fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", @@ -4328,12 +4465,281 @@ int qemu_loadvm(const char *filename) /* always seek to exact end of record */ qemu_fseek(f, cur_pos + record_len, SEEK_SET); } - fclose(f); ret = 0; + the_end: + return ret; +} + +/* device can contain snapshots */ +static int bdrv_can_snapshot(BlockDriverState *bs) +{ + return (bs && + !bdrv_is_removable(bs) && + !bdrv_is_read_only(bs)); +} + +/* device must be snapshots in order to have a reliable snapshot */ +static int bdrv_has_snapshot(BlockDriverState *bs) +{ + return (bs && + !bdrv_is_removable(bs) && + !bdrv_is_read_only(bs)); +} + +static BlockDriverState *get_bs_snapshots(void) +{ + BlockDriverState *bs; + int i; + + if (bs_snapshots) + return bs_snapshots; + for(i = 0; i <= MAX_DISKS; i++) { + bs = bs_table[i]; + if (bdrv_can_snapshot(bs)) + goto ok; + } + return NULL; + ok: + bs_snapshots = bs; + return bs; +} + +static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, + const char *name) +{ + QEMUSnapshotInfo *sn_tab, *sn; + int nb_sns, i, ret; + + ret = -ENOENT; + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + if (nb_sns < 0) + return ret; + for(i = 0; i < nb_sns; i++) { + sn = &sn_tab[i]; + if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { + *sn_info = *sn; + ret = 0; + break; + } + } + qemu_free(sn_tab); + return ret; +} + +void do_savevm(const char *name) +{ + BlockDriverState *bs, *bs1; + QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; + int must_delete, ret, i; + BlockDriverInfo bdi1, *bdi = &bdi1; + QEMUFile *f; + int saved_vm_running; + struct timeval tv; + + bs = get_bs_snapshots(); + if (!bs) { + term_printf("No block device can accept snapshots\n"); + return; + } + + saved_vm_running = vm_running; + vm_stop(0); + + must_delete = 0; + if (name) { + ret = bdrv_snapshot_find(bs, old_sn, name); + if (ret >= 0) { + must_delete = 1; + } + } + memset(sn, 0, sizeof(*sn)); + if (must_delete) { + pstrcpy(sn->name, sizeof(sn->name), old_sn->name); + pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); + } else { + if (name) + pstrcpy(sn->name, sizeof(sn->name), name); + } + + /* fill auxiliary fields */ + gettimeofday(&tv, NULL); + sn->date_sec = tv.tv_sec; + sn->date_nsec = tv.tv_usec * 1000; + sn->vm_clock_nsec = qemu_get_clock(vm_clock); + + if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { + term_printf("Device %s does not support VM state snapshots\n", + bdrv_get_device_name(bs)); + goto the_end; + } + + /* save the VM state */ + f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1); + if (!f) { + term_printf("Could not open VM state file\n"); + goto the_end; + } + ret = qemu_savevm_state(f); + sn->vm_state_size = qemu_ftell(f); + qemu_fclose(f); + if (ret < 0) { + term_printf("Error %d while writing VM\n", ret); + goto the_end; + } + + /* create the snapshots */ + + for(i = 0; i < MAX_DISKS; i++) { + bs1 = bs_table[i]; + if (bdrv_has_snapshot(bs1)) { + if (must_delete) { + ret = bdrv_snapshot_delete(bs1, old_sn->id_str); + if (ret < 0) { + term_printf("Error while deleting snapshot on '%s'\n", + bdrv_get_device_name(bs1)); + } + } + ret = bdrv_snapshot_create(bs1, sn); + if (ret < 0) { + term_printf("Error while creating snapshot on '%s'\n", + bdrv_get_device_name(bs1)); + } + } + } + the_end: if (saved_vm_running) vm_start(); - return ret; +} + +void do_loadvm(const char *name) +{ + BlockDriverState *bs, *bs1; + BlockDriverInfo bdi1, *bdi = &bdi1; + QEMUFile *f; + int i, ret; + int saved_vm_running; + + bs = get_bs_snapshots(); + if (!bs) { + term_printf("No block device supports snapshots\n"); + return; + } + + saved_vm_running = vm_running; + vm_stop(0); + + for(i = 0; i <= MAX_DISKS; i++) { + bs1 = bs_table[i]; + if (bdrv_has_snapshot(bs1)) { + ret = bdrv_snapshot_goto(bs1, name); + if (ret < 0) { + if (bs != bs1) + term_printf("Warning: "); + switch(ret) { + case -ENOTSUP: + term_printf("Snapshots not supported on device '%s'\n", + bdrv_get_device_name(bs1)); + break; + case -ENOENT: + term_printf("Could not find snapshot '%s' on device '%s'\n", + name, bdrv_get_device_name(bs1)); + break; + default: + term_printf("Error %d while activating snapshot on '%s'\n", + ret, bdrv_get_device_name(bs1)); + break; + } + /* fatal on snapshot block device */ + if (bs == bs1) + goto the_end; + } + } + } + + if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { + term_printf("Device %s does not support VM state snapshots\n", + bdrv_get_device_name(bs)); + return; + } + + /* restore the VM state */ + f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0); + if (!f) { + term_printf("Could not open VM state file\n"); + goto the_end; + } + ret = qemu_loadvm_state(f); + qemu_fclose(f); + if (ret < 0) { + term_printf("Error %d while loading VM state\n", ret); + } + the_end: + if (saved_vm_running) + vm_start(); +} + +void do_delvm(const char *name) +{ + BlockDriverState *bs, *bs1; + int i, ret; + + bs = get_bs_snapshots(); + if (!bs) { + term_printf("No block device supports snapshots\n"); + return; + } + + for(i = 0; i <= MAX_DISKS; i++) { + bs1 = bs_table[i]; + if (bdrv_has_snapshot(bs1)) { + ret = bdrv_snapshot_delete(bs1, name); + if (ret < 0) { + if (ret == -ENOTSUP) + term_printf("Snapshots not supported on device '%s'\n", + bdrv_get_device_name(bs1)); + else + term_printf("Error %d while deleting snapshot on '%s'\n", + ret, bdrv_get_device_name(bs1)); + } + } + } +} + +void do_info_snapshots(void) +{ + BlockDriverState *bs, *bs1; + QEMUSnapshotInfo *sn_tab, *sn; + int nb_sns, i; + char buf[256]; + + bs = get_bs_snapshots(); + if (!bs) { + term_printf("No available block device supports snapshots\n"); + return; + } + term_printf("Snapshot devices:"); + for(i = 0; i <= MAX_DISKS; i++) { + bs1 = bs_table[i]; + if (bdrv_has_snapshot(bs1)) { + if (bs == bs1) + term_printf(" %s", bdrv_get_device_name(bs1)); + } + } + term_printf("\n"); + + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + if (nb_sns < 0) { + term_printf("bdrv_snapshot_list: error %d\n", nb_sns); + return; + } + term_printf("Snapshot list (from %s):\n", bdrv_get_device_name(bs)); + term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); + for(i = 0; i < nb_sns; i++) { + sn = &sn_tab[i]; + term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); + } + qemu_free(sn_tab); } /***********************************************************/ @@ -6284,7 +6690,7 @@ int main(int argc, char **argv) } else #endif if (loadvm) - qemu_loadvm(loadvm); + do_loadvm(loadvm); { /* XXX: simplify init */ diff --git a/vl.h b/vl.h index d653f4683..f71742463 100644 --- a/vl.h +++ b/vl.h @@ -396,8 +396,11 @@ void cpu_disable_ticks(void); /* VM Load/Save */ -typedef FILE QEMUFile; +typedef struct QEMUFile QEMUFile; +QEMUFile *qemu_fopen(const char *filename, const char *mode); +void qemu_fflush(QEMUFile *f); +void qemu_fclose(QEMUFile *f); void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); void qemu_put_byte(QEMUFile *f, int v); void qemu_put_be16(QEMUFile *f, unsigned int v); @@ -467,8 +470,6 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); typedef void SaveStateHandler(QEMUFile *f, void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); -int qemu_loadvm(const char *filename); -int qemu_savevm(const char *filename); int register_savevm(const char *idstr, int instance_id, int version_id, @@ -481,6 +482,11 @@ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); void cpu_save(QEMUFile *f, void *opaque); int cpu_load(QEMUFile *f, void *opaque, int version_id); +void do_savevm(const char *name); +void do_loadvm(const char *name); +void do_delvm(const char *name); +void do_info_snapshots(void); + /* bottom halves */ typedef struct QEMUBH QEMUBH; typedef void QEMUBHFunc(void *opaque); @@ -504,6 +510,25 @@ extern BlockDriver bdrv_dmg; extern BlockDriver bdrv_bochs; extern BlockDriver bdrv_vpc; extern BlockDriver bdrv_vvfat; +extern BlockDriver bdrv_qcow2; + +typedef struct BlockDriverInfo { + /* in bytes, 0 if irrelevant */ + int cluster_size; + /* offset at which the VM state can be saved (0 if not possible) */ + int64_t vm_state_offset; +} BlockDriverInfo; + +typedef struct QEMUSnapshotInfo { + char id_str[128]; /* unique snapshot id */ + /* the following fields are informative. They are not needed for + the consistency of the snapshot */ + char name[256]; /* user choosen name */ + uint32_t vm_state_size; /* VM state info size */ + uint32_t date_sec; /* UTC date of the snapshot */ + uint32_t date_nsec; + uint64_t vm_clock_nsec; /* VM clock relative to boot */ +} QEMUSnapshotInfo; #define BDRV_O_RDONLY 0x0000 #define BDRV_O_RDWR 0x0002 @@ -594,13 +619,22 @@ int bdrv_set_key(BlockDriverState *bs, const char *key); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque); const char *bdrv_get_device_name(BlockDriverState *bs); +int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); -int qcow_get_cluster_size(BlockDriverState *bs); -int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf); void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size); - +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); +char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); + +char *get_human_readable_size(char *buf, int buf_size, int64_t size); int path_is_absolute(const char *path); void path_combine(char *dest, int dest_size, const char *base_path, @@ -824,7 +858,7 @@ void vnc_display_init(DisplayState *ds, int display); /* ide.c */ #define MAX_DISKS 4 -extern BlockDriverState *bs_table[MAX_DISKS]; +extern BlockDriverState *bs_table[MAX_DISKS + 1]; void isa_ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1); -- cgit v1.2.3 From e70332b376ca6e7ca3357d8ce32b12c9a90da545 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Aug 2006 21:31:46 +0000 Subject: use QEMUFile API git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2087 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/wavaudio.c | 4 ++-- audio/wavcapture.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/audio/wavaudio.c b/audio/wavaudio.c index c359fc4f2..a552b7e97 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -151,7 +151,7 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); le_store (hdr + 32, 1 << (bits16 + stereo), 2); - wav->f = fopen (conf.wav_path, "wb"); + wav->f = qemu_fopen (conf.wav_path, "wb"); if (!wav->f) { dolog ("Failed to open wave file `%s'\nReason: %s\n", conf.wav_path, strerror (errno)); @@ -185,7 +185,7 @@ static void wav_fini_out (HWVoiceOut *hw) qemu_fseek (wav->f, 32, SEEK_CUR); qemu_put_buffer (wav->f, dlen, 4); - fclose (wav->f); + qemu_fclose (wav->f); wav->f = NULL; qemu_free (wav->pcm_buf); diff --git a/audio/wavcapture.c b/audio/wavcapture.c index 0f6f7bf01..d1a6f7ba7 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -46,7 +46,7 @@ static void wav_destroy (void *opaque) qemu_fseek (wav->f, 32, SEEK_CUR); qemu_put_buffer (wav->f, dlen, 4); - fclose (wav->f); + qemu_fclose (wav->f); if (wav->path) { qemu_free (wav->path); } @@ -135,7 +135,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq, le_store (hdr + 28, freq << shift, 4); le_store (hdr + 32, 1 << shift, 2); - wav->f = fopen (path, "wb"); + wav->f = qemu_fopen (path, "wb"); if (!wav->f) { term_printf ("Failed to open wave file `%s'\nReason: %s\n", path, strerror (errno)); -- cgit v1.2.3 From c47c33b098302d2c94db22e76ef5745aab05a7c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Aug 2006 21:32:10 +0000 Subject: block API change git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2088 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/block-qcow.c b/block-qcow.c index 9ad7061d3..151ec85d2 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -350,7 +350,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, (n_end - n_start) < s->cluster_sectors) { uint64_t start_sect; start_sect = (offset & ~(s->cluster_size - 1)) >> 9; - memset(s->cluster_data + 512, 0xaa, 512); + 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, @@ -813,7 +813,7 @@ static int qcow_create(const char *filename, int64_t total_size, return 0; } -int qcow_make_empty(BlockDriverState *bs) +static int qcow_make_empty(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; uint32_t l1_length = s->l1_size * sizeof(uint64_t); @@ -833,18 +833,10 @@ int qcow_make_empty(BlockDriverState *bs) return 0; } -int qcow_get_cluster_size(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - if (bs->drv != &bdrv_qcow) - return -1; - return s->cluster_size; -} - /* XXX: put compressed sectors first, then all the cluster aligned tables to avoid losing bytes in alignment */ -int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf) +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; @@ -852,8 +844,8 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, uint8_t *out_buf; uint64_t cluster_offset; - if (bs->drv != &bdrv_qcow) - return -1; + if (nb_sectors != s->cluster_sectors) + return -EINVAL; out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128); if (!out_buf) @@ -907,6 +899,13 @@ static void qcow_flush(BlockDriverState *bs) 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), @@ -926,6 +925,6 @@ BlockDriver bdrv_qcow = { .bdrv_aio_write = qcow_aio_write, .bdrv_aio_cancel = qcow_aio_cancel, .bdrv_aio_delete = qcow_aio_delete, + .bdrv_write_compressed = qcow_write_compressed, + .bdrv_get_info = qcow_get_info, }; - - -- cgit v1.2.3 From 15e6690aca348a7dc8772b8f1197cf13c8764335 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 5 Aug 2006 22:24:28 +0000 Subject: fixed disk image creation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2089 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow2.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index f499b13be..7d92ca962 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -1081,7 +1081,7 @@ static int qcow_create(const char *filename, int64_t total_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, s->cluster_size); + offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size); s->refcount_table = qemu_mallocz(s->cluster_size); if (!s->refcount_table) @@ -1089,7 +1089,7 @@ static int qcow_create(const char *filename, int64_t total_size, 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); @@ -1101,7 +1101,7 @@ static int qcow_create(const char *filename, int64_t total_size, /* update refcounts */ create_refcount_update(s, 0, header_size); - create_refcount_update(s, s->l1_table_offset, l1_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); @@ -1894,7 +1894,11 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) 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) @@ -2144,7 +2148,7 @@ static void check_refcounts(BlockDriverState *bs) 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); -- cgit v1.2.3 From 6eb5733a3cad93b00043d48fa22b9df7d1f5ab33 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Aug 2006 09:51:25 +0000 Subject: fixed blocking io emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2090 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 5 +++++ vl.c | 6 +++++- vl.h | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/block-raw.c b/block-raw.c index 14f4bd5b3..adb3d39ad 100644 --- a/block-raw.c +++ b/block-raw.c @@ -308,6 +308,11 @@ 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); diff --git a/vl.c b/vl.c index 6daed966b..0504c6f19 100644 --- a/vl.c +++ b/vl.c @@ -5200,19 +5200,23 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) return bh; } -void qemu_bh_poll(void) +int qemu_bh_poll(void) { QEMUBH *bh, **pbh; + int ret; + ret = 0; for(;;) { pbh = &first_bh; bh = *pbh; if (!bh) break; + ret = 1; *pbh = bh->next; bh->scheduled = 0; bh->cb(bh->opaque); } + return ret; } void qemu_bh_schedule(QEMUBH *bh) diff --git a/vl.h b/vl.h index f71742463..ce52fb826 100644 --- a/vl.h +++ b/vl.h @@ -495,7 +495,7 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); void qemu_bh_schedule(QEMUBH *bh); void qemu_bh_cancel(QEMUBH *bh); void qemu_bh_delete(QEMUBH *bh); -void qemu_bh_poll(void); +int qemu_bh_poll(void); /* block.c */ typedef struct BlockDriverState BlockDriverState; -- cgit v1.2.3 From 51c1ebb1bc2642296379a8db1ba9dfb4f78a2f80 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 6 Aug 2006 11:31:06 +0000 Subject: Fix SCSI off-by-one device size. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2091 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/scsi-disk.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index decab1f42..f545c89c2 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -348,15 +348,21 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) /* The normal LEN field for this command is zero. */ memset(s->buf, 0, 8); bdrv_get_geometry(s->bdrv, &nb_sectors); - s->buf[0] = (nb_sectors >> 24) & 0xff; - s->buf[1] = (nb_sectors >> 16) & 0xff; - s->buf[2] = (nb_sectors >> 8) & 0xff; - s->buf[3] = nb_sectors & 0xff; - s->buf[4] = 0; - s->buf[5] = 0; - s->buf[6] = s->cluster_size * 2; - s->buf[7] = 0; - s->buf_len = 8; + /* Returned value is the address of the last sector. */ + if (nb_sectors) { + nb_sectors--; + s->buf[0] = (nb_sectors >> 24) & 0xff; + s->buf[1] = (nb_sectors >> 16) & 0xff; + s->buf[2] = (nb_sectors >> 8) & 0xff; + s->buf[3] = nb_sectors & 0xff; + s->buf[4] = 0; + s->buf[5] = 0; + s->buf[6] = s->cluster_size * 2; + s->buf[7] = 0; + s->buf_len = 8; + } else { + scsi_command_complete(s, SENSE_NOT_READY); + } break; case 0x08: case 0x28: -- cgit v1.2.3 From 1aacf3489b67a907fa1b316a81e8991782f57199 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 6 Aug 2006 13:27:39 +0000 Subject: Add missing #define. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2092 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/scsi-disk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index f545c89c2..3419c8e2d 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -24,6 +24,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) #include "vl.h" #define SENSE_NO_SENSE 0 +#define SENSE_NOT_READY 2 #define SENSE_ILLEGAL_REQUEST 5 struct SCSIDevice -- cgit v1.2.3 From a946592212874f1e214e0db365c29e8de1179847 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Aug 2006 13:34:04 +0000 Subject: handle read outside the backing file git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2093 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow2.c | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index 7d92ca962..bc2aa14bb 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -696,11 +696,26 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) 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; + int ret, index_in_cluster, n, n1; uint64_t cluster_offset; while (nb_sectors > 0) { @@ -712,9 +727,12 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, 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; + 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); } @@ -815,7 +833,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) BlockDriverState *bs = acb->bs; BDRVQcowState *s = bs->opaque; QCowAIOCB *acb1 = acb->opaque; - int index_in_cluster; + int index_in_cluster, n1; if (ret < 0) { fail: @@ -859,10 +877,16 @@ static void qcow_aio_read_cb(void *opaque, int ret) if (!acb1->cluster_offset) { if (bs->backing_hd) { /* read from the base image */ - ret = bdrv_aio_read(acb1->backing_hd_aiocb, acb1->sector_num, - acb1->buf, acb1->n, qcow_aio_read_cb, acb); - if (ret < 0) - goto fail; + n1 = backing_read1(bs->backing_hd, acb1->sector_num, + acb1->buf, acb1->n); + if (n1 > 0) { + ret = bdrv_aio_read(acb1->backing_hd_aiocb, acb1->sector_num, + acb1->buf, n1, qcow_aio_read_cb, acb); + if (ret < 0) + goto fail; + } else { + goto redo; + } } else { /* Note: in this case, no need to wait */ memset(acb1->buf, 0, 512 * acb1->n); -- cgit v1.2.3 From d15a771da15513560371443bd361abbcf51f70b8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Aug 2006 13:35:09 +0000 Subject: qcow2 is now used for '-snapshot' - keep BlockDriverState.total_sectors git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2094 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 12 +++++------- block_int.h | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index 529dd4e25..dacee2f7f 100644 --- a/block.c +++ b/block.c @@ -296,7 +296,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bdrv_delete(bs1); get_tmp_filename(tmp_filename, sizeof(tmp_filename)); - if (bdrv_create(&bdrv_qcow, tmp_filename, + if (bdrv_create(&bdrv_qcow2, tmp_filename, total_size, filename, 0) < 0) { return -1; } @@ -335,7 +335,9 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, qemu_free(bs->opaque); return ret; } - + if (drv->bdrv_getlength) { + bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; + } #ifndef _WIN32 if (bs->is_temporary) { unlink(filename); @@ -647,11 +649,7 @@ int64_t bdrv_getlength(BlockDriverState *bs) void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) { - int64_t size; - size = bdrv_getlength(bs); - if (size < 0) - size = 0; - *nb_sectors_ptr = size >> SECTOR_BITS; + *nb_sectors_ptr = bs->total_sectors; } /* force a given boot sector. */ diff --git a/block_int.h b/block_int.h index b3bc5b387..26cc4ffba 100644 --- a/block_int.h +++ b/block_int.h @@ -73,7 +73,8 @@ struct BlockDriver { }; struct BlockDriverState { - int64_t total_sectors; /* XXX: will be suppressed */ + 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 inserted; /* if true, the media is present */ int removable; /* if true, the media can be removed */ -- cgit v1.2.3 From c88676f89c3e2b4eefdfe2ef647e1ea07fe052ae Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Aug 2006 13:36:11 +0000 Subject: use zlib to compress ram snapshots - correctly save qemu clock git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2095 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 226 insertions(+), 29 deletions(-) diff --git a/vl.c b/vl.c index 0504c6f19..7ef5f52cb 100644 --- a/vl.c +++ b/vl.c @@ -29,6 +29,7 @@ #include #include #include +#include #ifndef _WIN32 #include @@ -822,17 +823,21 @@ static void timer_save(QEMUFile *f, void *opaque) } qemu_put_be64s(f, &cpu_ticks_offset); qemu_put_be64s(f, &ticks_per_sec); + qemu_put_be64s(f, &cpu_clock_offset); } static int timer_load(QEMUFile *f, void *opaque, int version_id) { - if (version_id != 1) + if (version_id != 1 && version_id != 2) return -EINVAL; if (cpu_ticks_enabled) { return -EINVAL; } qemu_get_be64s(f, &cpu_ticks_offset); qemu_get_be64s(f, &ticks_per_sec); + if (version_id == 2) { + qemu_get_be64s(f, &cpu_clock_offset); + } return 0; } @@ -5114,24 +5119,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) /***********************************************************/ /* ram save/restore */ -/* we just avoid storing empty pages */ -static void ram_put_page(QEMUFile *f, const uint8_t *buf, int len) -{ - int i, v; - - v = buf[0]; - for(i = 1; i < len; i++) { - if (buf[i] != v) - goto normal_save; - } - qemu_put_byte(f, 1); - qemu_put_byte(f, v); - return; - normal_save: - qemu_put_byte(f, 0); - qemu_put_buffer(f, buf, len); -} - static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) { int v; @@ -5152,28 +5139,238 @@ static int ram_get_page(QEMUFile *f, uint8_t *buf, int len) return 0; } +static int ram_load_v1(QEMUFile *f, void *opaque) +{ + int i, ret; + + if (qemu_get_be32(f) != phys_ram_size) + return -EINVAL; + for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) { + ret = ram_get_page(f, phys_ram_base + i, TARGET_PAGE_SIZE); + if (ret) + return ret; + } + return 0; +} + +#define BDRV_HASH_BLOCK_SIZE 1024 +#define IOBUF_SIZE 4096 +#define RAM_CBLOCK_MAGIC 0xfabe + +typedef struct RamCompressState { + z_stream zstream; + QEMUFile *f; + uint8_t buf[IOBUF_SIZE]; +} RamCompressState; + +static int ram_compress_open(RamCompressState *s, QEMUFile *f) +{ + int ret; + memset(s, 0, sizeof(*s)); + s->f = f; + ret = deflateInit2(&s->zstream, 1, + Z_DEFLATED, 15, + 9, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) + return -1; + s->zstream.avail_out = IOBUF_SIZE; + s->zstream.next_out = s->buf; + return 0; +} + +static void ram_put_cblock(RamCompressState *s, const uint8_t *buf, int len) +{ + qemu_put_be16(s->f, RAM_CBLOCK_MAGIC); + qemu_put_be16(s->f, len); + qemu_put_buffer(s->f, buf, len); +} + +static int ram_compress_buf(RamCompressState *s, const uint8_t *buf, int len) +{ + int ret; + + s->zstream.avail_in = len; + s->zstream.next_in = (uint8_t *)buf; + while (s->zstream.avail_in > 0) { + ret = deflate(&s->zstream, Z_NO_FLUSH); + if (ret != Z_OK) + return -1; + if (s->zstream.avail_out == 0) { + ram_put_cblock(s, s->buf, IOBUF_SIZE); + s->zstream.avail_out = IOBUF_SIZE; + s->zstream.next_out = s->buf; + } + } + return 0; +} + +static void ram_compress_close(RamCompressState *s) +{ + int len, ret; + + /* compress last bytes */ + for(;;) { + ret = deflate(&s->zstream, Z_FINISH); + if (ret == Z_OK || ret == Z_STREAM_END) { + len = IOBUF_SIZE - s->zstream.avail_out; + if (len > 0) { + ram_put_cblock(s, s->buf, len); + } + s->zstream.avail_out = IOBUF_SIZE; + s->zstream.next_out = s->buf; + if (ret == Z_STREAM_END) + break; + } else { + goto fail; + } + } +fail: + deflateEnd(&s->zstream); +} + +typedef struct RamDecompressState { + z_stream zstream; + QEMUFile *f; + uint8_t buf[IOBUF_SIZE]; +} RamDecompressState; + +static int ram_decompress_open(RamDecompressState *s, QEMUFile *f) +{ + int ret; + memset(s, 0, sizeof(*s)); + s->f = f; + ret = inflateInit(&s->zstream); + if (ret != Z_OK) + return -1; + return 0; +} + +static int ram_decompress_buf(RamDecompressState *s, uint8_t *buf, int len) +{ + int ret, clen; + + s->zstream.avail_out = len; + s->zstream.next_out = buf; + while (s->zstream.avail_out > 0) { + if (s->zstream.avail_in == 0) { + if (qemu_get_be16(s->f) != RAM_CBLOCK_MAGIC) + return -1; + clen = qemu_get_be16(s->f); + if (clen > IOBUF_SIZE) + return -1; + qemu_get_buffer(s->f, s->buf, clen); + s->zstream.avail_in = clen; + s->zstream.next_in = s->buf; + } + ret = inflate(&s->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) { + return -1; + } + } + return 0; +} + +static void ram_decompress_close(RamDecompressState *s) +{ + inflateEnd(&s->zstream); +} + static void ram_save(QEMUFile *f, void *opaque) { int i; + RamCompressState s1, *s = &s1; + uint8_t buf[10]; + qemu_put_be32(f, phys_ram_size); - for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) { - ram_put_page(f, phys_ram_base + i, TARGET_PAGE_SIZE); + if (ram_compress_open(s, f) < 0) + return; + for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) { +#if 0 + if (tight_savevm_enabled) { + int64_t sector_num; + int j; + + /* find if the memory block is available on a virtual + block device */ + sector_num = -1; + for(j = 0; j < MAX_DISKS; j++) { + if (bs_table[j]) { + sector_num = bdrv_hash_find(bs_table[j], + phys_ram_base + i, BDRV_HASH_BLOCK_SIZE); + if (sector_num >= 0) + break; + } + } + if (j == MAX_DISKS) + goto normal_compress; + buf[0] = 1; + buf[1] = j; + cpu_to_be64wu((uint64_t *)(buf + 2), sector_num); + ram_compress_buf(s, buf, 10); + } else +#endif + { + // normal_compress: + buf[0] = 0; + ram_compress_buf(s, buf, 1); + ram_compress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE); + } } + ram_compress_close(s); } static int ram_load(QEMUFile *f, void *opaque, int version_id) { - int i, ret; + RamDecompressState s1, *s = &s1; + uint8_t buf[10]; + int i; - if (version_id != 1) + if (version_id == 1) + return ram_load_v1(f, opaque); + if (version_id != 2) return -EINVAL; if (qemu_get_be32(f) != phys_ram_size) return -EINVAL; - for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) { - ret = ram_get_page(f, phys_ram_base + i, TARGET_PAGE_SIZE); - if (ret) - return ret; + if (ram_decompress_open(s, f) < 0) + return -EINVAL; + for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) { + if (ram_decompress_buf(s, buf, 1) < 0) { + fprintf(stderr, "Error while reading ram block header\n"); + goto error; + } + if (buf[0] == 0) { + if (ram_decompress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE) < 0) { + fprintf(stderr, "Error while reading ram block address=0x%08x", i); + goto error; + } + } else +#if 0 + if (buf[0] == 1) { + int bs_index; + int64_t sector_num; + + ram_decompress_buf(s, buf + 1, 9); + bs_index = buf[1]; + sector_num = be64_to_cpupu((const uint64_t *)(buf + 2)); + if (bs_index >= MAX_DISKS || bs_table[bs_index] == NULL) { + fprintf(stderr, "Invalid block device index %d\n", bs_index); + goto error; + } + if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i, + BDRV_HASH_BLOCK_SIZE / 512) < 0) { + fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n", + bs_index, sector_num); + goto error; + } + } else +#endif + { + error: + printf("Error block header\n"); + return -EINVAL; + } } + ram_decompress_close(s); return 0; } @@ -6612,8 +6809,8 @@ int main(int argc, char **argv) } } - register_savevm("timer", 0, 1, timer_save, timer_load, NULL); - register_savevm("ram", 0, 1, ram_save, ram_load, NULL); + register_savevm("timer", 0, 2, timer_save, timer_load, NULL); + register_savevm("ram", 0, 2, ram_save, ram_load, NULL); init_ioports(); -- cgit v1.2.3 From 13a2e80f04a24b5466ff22328f5374a461181c0a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Aug 2006 14:50:31 +0000 Subject: info about VM snapshots git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2096 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ qemu-doc.texi | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Changelog b/Changelog index 693ce4ed3..8d36cbbe4 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,8 @@ 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 version 0.8.2: diff --git a/qemu-doc.texi b/qemu-doc.texi index 1e49ccfab..9f0b4f68b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -743,6 +743,8 @@ show USB devices plugged on the virtual USB hub show all USB host devices @item info capture show information about active capturing +@item info snapshots +show list of VM snapshots @end table @item q or quit @@ -777,11 +779,18 @@ info capture @item log item1[,...] Activate logging of the specified items to @file{/tmp/qemu.log}. -@item savevm filename -Save the whole virtual machine state to @var{filename}. +@item savevm [tag|id] +Create a snapshot of the whole virtual machine. If @var{tag} is +provided, it is used as human readable identifier. If there is already +a snapshot with the same tag or ID, it is replaced. More info at +@ref{vm_snapshots}. -@item loadvm filename -Restore the whole virtual machine state from @var{filename}. +@item loadvm tag|id +Set the whole virtual machine to the snapshot identified by the tag +@var{tag} or the unique snapshot ID @var{id}. + +@item delvm tag|id +Delete the snapshot identified by @var{tag} or @var{id}. @item stop Stop emulation. @@ -895,11 +904,14 @@ CPU registers by prefixing them with @emph{$}. Since version 0.6.1, QEMU supports many disk image formats, including growable disk images (their size increase as non empty sectors are -written), compressed and encrypted disk images. +written), compressed and encrypted disk images. Version 0.8.3 added +the new qcow2 disk image format which is essential to support VM +snapshots. @menu * disk_images_quickstart:: Quick start for disk image creation * disk_images_snapshot_mode:: Snapshot mode +* vm_snapshots:: VM snapshots * qemu_img_invocation:: qemu-img Invocation * disk_images_fat_images:: Virtual FAT disk images @end menu @@ -926,6 +938,57 @@ a temporary file created in @file{/tmp}. You can however force the write back to the raw disk images by using the @code{commit} monitor command (or @key{C-a s} in the serial console). +@node vm_snapshots +@subsection VM snapshots + +VM snapshots are snapshots of the complete virtual machine including +CPU state, RAM, device state and the content of all the writable +disks. In order to use VM snapshots, you must have at least one non +removable and writable block device using the @code{qcow2} disk image +format. Normally this device is the first virtual hard drive. + +Use the monitor command @code{savevm} to create a new VM snapshot or +replace an existing one. A human readable name can be assigned to each +snapshots in addition to its numerical ID. + +Use @code{loadvm} to restore a VM snapshot and @code{delvm} to remove +a VM snapshot. @code{info snapshots} lists the available snapshots +with their associated information: + +@example +(qemu) info snapshots +Snapshot devices: hda +Snapshot list (from hda): +ID TAG VM SIZE DATE VM CLOCK +1 start 41M 2006-08-06 12:38:02 00:00:14.954 +2 40M 2006-08-06 12:43:29 00:00:18.633 +3 msys 40M 2006-08-06 12:44:04 00:00:23.514 +@end example + +A VM snapshot is made of a VM state info (its size is shown in +@code{info snapshots}) and a snapshot of every writable disk image. +The VM state info is stored in the first @code{qcow2} non removable +and writable block device. The disk image snapshots are stored in +every disk image. The size of a snapshot in a disk image is difficult +to evaluate and is not shown by @code{info snapshots} because the +associated disk sectors are shared among all the snapshots to save +disk space (otherwise each snapshot would have to copy the full disk +images). + +When using the (unrelated) @code{-snapshot} option +(@ref{disk_images_snapshot_mode}), you can always make VM snapshots, +but they are deleted as soon as you exit QEMU. + +VM snapshots currently have the following known limitations: +@itemize +@item +They cannot cope with removable devices if they are removed or +inserted after a snapshot is done. +@item +A few device drivers still have incomplete snapshot support so their +state is not saved or restored properly (in particular USB). +@end itemize + @node qemu_img_invocation @subsection @code{qemu-img} Invocation -- cgit v1.2.3 From 51d6bae7a8d7a359d79004c586be352cd924d75f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 6 Aug 2006 21:13:56 +0000 Subject: removed duplicated line git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2097 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pflash_cfi02.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index ee2f63a1a..0db8b5645 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -135,7 +135,6 @@ static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width) #else ret = p[offset]; ret |= p[offset + 1] << 8; - ret |= p[offset + 1] << 8; ret |= p[offset + 2] << 16; ret |= p[offset + 3] << 24; #endif -- cgit v1.2.3 From ce1a14dc0d94cf85393356f56f197c5e8b6a7f60 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 7 Aug 2006 02:38:06 +0000 Subject: Dynamically allocate AIO Completion Blocks. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2098 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow.c | 231 +++++++++++++++++++++--------------------------- block-qcow2.c | 242 +++++++++++++++++++++++--------------------------- block-raw.c | 280 +++++++++++++++++++++++++++++----------------------------- block.c | 237 ++++++++++++++++++++++--------------------------- block_int.h | 27 +++--- vl.h | 14 ++- 6 files changed, 483 insertions(+), 548 deletions(-) diff --git a/block-qcow.c b/block-qcow.c index 151ec85d2..d5333b379 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -522,7 +522,8 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, return 0; } -typedef struct { +typedef struct QCowAIOCB { + BlockDriverAIOCB common; int64_t sector_num; uint8_t *buf; int nb_sectors; @@ -530,223 +531,198 @@ typedef struct { uint64_t cluster_offset; uint8_t *cluster_data; BlockDriverAIOCB *hd_aiocb; - BlockDriverAIOCB *backing_hd_aiocb; } QCowAIOCB; -static void qcow_aio_delete(BlockDriverAIOCB *acb); - -static int qcow_aio_new(BlockDriverAIOCB *acb) -{ - BlockDriverState *bs = acb->bs; - BDRVQcowState *s = bs->opaque; - QCowAIOCB *acb1; - acb1 = qemu_mallocz(sizeof(QCowAIOCB)); - if (!acb1) - return -1; - acb->opaque = acb1; - acb1->hd_aiocb = bdrv_aio_new(s->hd); - if (!acb1->hd_aiocb) - goto fail; - if (bs->backing_hd) { - acb1->backing_hd_aiocb = bdrv_aio_new(bs->backing_hd); - if (!acb1->backing_hd_aiocb) - goto fail; - } - return 0; - fail: - qcow_aio_delete(acb); - return -1; -} - static void qcow_aio_read_cb(void *opaque, int ret) { - BlockDriverAIOCB *acb = opaque; - BlockDriverState *bs = acb->bs; + QCowAIOCB *acb = opaque; + BlockDriverState *bs = acb->common.bs; BDRVQcowState *s = bs->opaque; - QCowAIOCB *acb1 = acb->opaque; int index_in_cluster; + acb->hd_aiocb = NULL; if (ret < 0) { fail: - acb->cb(acb->cb_opaque, ret); + acb->common.cb(acb->common.opaque, ret); + qemu_aio_release(acb); return; } redo: /* post process the read buffer */ - if (!acb1->cluster_offset) { + if (!acb->cluster_offset) { /* nothing to do */ - } else if (acb1->cluster_offset & QCOW_OFLAG_COMPRESSED) { + } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* nothing to do */ } else { if (s->crypt_method) { - encrypt_sectors(s, acb1->sector_num, acb1->buf, acb1->buf, - acb1->n, 0, + encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, + acb->n, 0, &s->aes_decrypt_key); } } - acb1->nb_sectors -= acb1->n; - acb1->sector_num += acb1->n; - acb1->buf += acb1->n * 512; + acb->nb_sectors -= acb->n; + acb->sector_num += acb->n; + acb->buf += acb->n * 512; - if (acb1->nb_sectors == 0) { + if (acb->nb_sectors == 0) { /* request completed */ - acb->cb(acb->cb_opaque, 0); + acb->common.cb(acb->common.opaque, 0); + qemu_aio_release(acb); return; } /* prepare next AIO request */ - acb1->cluster_offset = get_cluster_offset(bs, - acb1->sector_num << 9, - 0, 0, 0, 0); - index_in_cluster = acb1->sector_num & (s->cluster_sectors - 1); - acb1->n = s->cluster_sectors - index_in_cluster; - if (acb1->n > acb1->nb_sectors) - acb1->n = acb1->nb_sectors; - - if (!acb1->cluster_offset) { + 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 */ - ret = bdrv_aio_read(acb1->backing_hd_aiocb, acb1->sector_num, - acb1->buf, acb1->n, qcow_aio_read_cb, acb); - if (ret < 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 { /* Note: in this case, no need to wait */ - memset(acb1->buf, 0, 512 * acb1->n); + memset(acb->buf, 0, 512 * acb->n); goto redo; } - } else if (acb1->cluster_offset & QCOW_OFLAG_COMPRESSED) { + } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ - if (decompress_cluster(s, acb1->cluster_offset) < 0) + if (decompress_cluster(s, acb->cluster_offset) < 0) goto fail; - memcpy(acb1->buf, - s->cluster_cache + index_in_cluster * 512, 512 * acb1->n); + memcpy(acb->buf, + s->cluster_cache + index_in_cluster * 512, 512 * acb->n); goto redo; } else { - if ((acb1->cluster_offset & 511) != 0) { + if ((acb->cluster_offset & 511) != 0) { ret = -EIO; goto fail; } - ret = bdrv_aio_read(acb1->hd_aiocb, - (acb1->cluster_offset >> 9) + index_in_cluster, - acb1->buf, acb1->n, qcow_aio_read_cb, acb); - if (ret < 0) + 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 int qcow_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors) +static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - QCowAIOCB *acb1 = acb->opaque; - - acb1->sector_num = sector_num; - acb1->buf = buf; - acb1->nb_sectors = nb_sectors; - acb1->n = 0; - acb1->cluster_offset = 0; + 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 0; + return &acb->common; } static void qcow_aio_write_cb(void *opaque, int ret) { - BlockDriverAIOCB *acb = opaque; - BlockDriverState *bs = acb->bs; + QCowAIOCB *acb = opaque; + BlockDriverState *bs = acb->common.bs; BDRVQcowState *s = bs->opaque; - QCowAIOCB *acb1 = acb->opaque; int index_in_cluster; uint64_t cluster_offset; const uint8_t *src_buf; - + + acb->hd_aiocb = NULL; + if (ret < 0) { fail: - acb->cb(acb->cb_opaque, ret); + acb->common.cb(acb->common.opaque, ret); + qemu_aio_release(acb); return; } - acb1->nb_sectors -= acb1->n; - acb1->sector_num += acb1->n; - acb1->buf += acb1->n * 512; + acb->nb_sectors -= acb->n; + acb->sector_num += acb->n; + acb->buf += acb->n * 512; - if (acb1->nb_sectors == 0) { + if (acb->nb_sectors == 0) { /* request completed */ - acb->cb(acb->cb_opaque, 0); + acb->common.cb(acb->common.opaque, 0); + qemu_aio_release(acb); return; } - index_in_cluster = acb1->sector_num & (s->cluster_sectors - 1); - acb1->n = s->cluster_sectors - index_in_cluster; - if (acb1->n > acb1->nb_sectors) - acb1->n = acb1->nb_sectors; - cluster_offset = get_cluster_offset(bs, acb1->sector_num << 9, 1, 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; + cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, index_in_cluster, - index_in_cluster + acb1->n); + index_in_cluster + acb->n); if (!cluster_offset || (cluster_offset & 511) != 0) { ret = -EIO; goto fail; } if (s->crypt_method) { - if (!acb1->cluster_data) { - acb1->cluster_data = qemu_mallocz(s->cluster_size); - if (!acb1->cluster_data) { + if (!acb->cluster_data) { + acb->cluster_data = qemu_mallocz(s->cluster_size); + if (!acb->cluster_data) { ret = -ENOMEM; goto fail; } } - encrypt_sectors(s, acb1->sector_num, acb1->cluster_data, acb1->buf, - acb1->n, 1, &s->aes_encrypt_key); - src_buf = acb1->cluster_data; + 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 = acb1->buf; + src_buf = acb->buf; } - ret = bdrv_aio_write(acb1->hd_aiocb, - (cluster_offset >> 9) + index_in_cluster, - src_buf, acb1->n, - qcow_aio_write_cb, acb); - if (ret < 0) + 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 int qcow_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, - const uint8_t *buf, int nb_sectors) +static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - QCowAIOCB *acb1 = acb->opaque; - BlockDriverState *bs = acb->bs; BDRVQcowState *s = bs->opaque; + QCowAIOCB *acb; s->cluster_cache_offset = -1; /* disable compressed cache */ - acb1->sector_num = sector_num; - acb1->buf = (uint8_t *)buf; - acb1->nb_sectors = nb_sectors; - acb1->n = 0; + 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 0; -} - -static void qcow_aio_cancel(BlockDriverAIOCB *acb) -{ - QCowAIOCB *acb1 = acb->opaque; - if (acb1->hd_aiocb) - bdrv_aio_cancel(acb1->hd_aiocb); - if (acb1->backing_hd_aiocb) - bdrv_aio_cancel(acb1->backing_hd_aiocb); + return &acb->common; } -static void qcow_aio_delete(BlockDriverAIOCB *acb) +static void qcow_aio_cancel(BlockDriverAIOCB *blockacb) { - QCowAIOCB *acb1 = acb->opaque; - if (acb1->hd_aiocb) - bdrv_aio_delete(acb1->hd_aiocb); - if (acb1->backing_hd_aiocb) - bdrv_aio_delete(acb1->backing_hd_aiocb); - qemu_free(acb1->cluster_data); - qemu_free(acb1); + QCowAIOCB *acb = (QCowAIOCB *)blockacb; + if (acb->hd_aiocb) + bdrv_aio_cancel(acb->hd_aiocb); + qemu_aio_release(acb); } static void qcow_close(BlockDriverState *bs) @@ -920,11 +896,10 @@ BlockDriver bdrv_qcow = { qcow_set_key, qcow_make_empty, - .bdrv_aio_new = qcow_aio_new, .bdrv_aio_read = qcow_aio_read, .bdrv_aio_write = qcow_aio_write, .bdrv_aio_cancel = qcow_aio_cancel, - .bdrv_aio_delete = qcow_aio_delete, + .aiocb_size = sizeof(QCowAIOCB), .bdrv_write_compressed = qcow_write_compressed, .bdrv_get_info = qcow_get_info, }; diff --git a/block-qcow2.c b/block-qcow2.c index bc2aa14bb..a876ea2e2 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -791,7 +791,8 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, return 0; } -typedef struct { +typedef struct QCowAIOCB { + BlockDriverAIOCB common; int64_t sector_num; uint8_t *buf; int nb_sectors; @@ -799,229 +800,211 @@ typedef struct { uint64_t cluster_offset; uint8_t *cluster_data; BlockDriverAIOCB *hd_aiocb; - BlockDriverAIOCB *backing_hd_aiocb; } QCowAIOCB; -static void qcow_aio_delete(BlockDriverAIOCB *acb); - -static int qcow_aio_new(BlockDriverAIOCB *acb) -{ - BlockDriverState *bs = acb->bs; - BDRVQcowState *s = bs->opaque; - QCowAIOCB *acb1; - acb1 = qemu_mallocz(sizeof(QCowAIOCB)); - if (!acb1) - return -1; - acb->opaque = acb1; - acb1->hd_aiocb = bdrv_aio_new(s->hd); - if (!acb1->hd_aiocb) - goto fail; - if (bs->backing_hd) { - acb1->backing_hd_aiocb = bdrv_aio_new(bs->backing_hd); - if (!acb1->backing_hd_aiocb) - goto fail; - } - return 0; - fail: - qcow_aio_delete(acb); - return -1; -} - static void qcow_aio_read_cb(void *opaque, int ret) { - BlockDriverAIOCB *acb = opaque; - BlockDriverState *bs = acb->bs; + QCowAIOCB *acb = opaque; + BlockDriverState *bs = acb->common.bs; BDRVQcowState *s = bs->opaque; - QCowAIOCB *acb1 = acb->opaque; int index_in_cluster, n1; + acb->hd_aiocb = NULL; if (ret < 0) { fail: - acb->cb(acb->cb_opaque, ret); + acb->common.cb(acb->common.opaque, ret); + qemu_aio_release(acb); return; } redo: /* post process the read buffer */ - if (!acb1->cluster_offset) { + if (!acb->cluster_offset) { /* nothing to do */ - } else if (acb1->cluster_offset & QCOW_OFLAG_COMPRESSED) { + } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* nothing to do */ } else { if (s->crypt_method) { - encrypt_sectors(s, acb1->sector_num, acb1->buf, acb1->buf, - acb1->n, 0, + encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, + acb->n, 0, &s->aes_decrypt_key); } } - acb1->nb_sectors -= acb1->n; - acb1->sector_num += acb1->n; - acb1->buf += acb1->n * 512; + acb->nb_sectors -= acb->n; + acb->sector_num += acb->n; + acb->buf += acb->n * 512; - if (acb1->nb_sectors == 0) { + if (acb->nb_sectors == 0) { /* request completed */ - acb->cb(acb->cb_opaque, 0); + acb->common.cb(acb->common.opaque, 0); + qemu_aio_release(acb); return; } /* prepare next AIO request */ - acb1->cluster_offset = get_cluster_offset(bs, - acb1->sector_num << 9, - 0, 0, 0, 0); - index_in_cluster = acb1->sector_num & (s->cluster_sectors - 1); - acb1->n = s->cluster_sectors - index_in_cluster; - if (acb1->n > acb1->nb_sectors) - acb1->n = acb1->nb_sectors; - - if (!acb1->cluster_offset) { + 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, acb1->sector_num, - acb1->buf, acb1->n); + n1 = backing_read1(bs->backing_hd, acb->sector_num, + acb->buf, acb->n); if (n1 > 0) { - ret = bdrv_aio_read(acb1->backing_hd_aiocb, acb1->sector_num, - acb1->buf, n1, qcow_aio_read_cb, acb); - if (ret < 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(acb1->buf, 0, 512 * acb1->n); + memset(acb->buf, 0, 512 * acb->n); goto redo; } - } else if (acb1->cluster_offset & QCOW_OFLAG_COMPRESSED) { + } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ - if (decompress_cluster(s, acb1->cluster_offset) < 0) + if (decompress_cluster(s, acb->cluster_offset) < 0) goto fail; - memcpy(acb1->buf, - s->cluster_cache + index_in_cluster * 512, 512 * acb1->n); + memcpy(acb->buf, + s->cluster_cache + index_in_cluster * 512, 512 * acb->n); goto redo; } else { - if ((acb1->cluster_offset & 511) != 0) { + if ((acb->cluster_offset & 511) != 0) { ret = -EIO; goto fail; } - ret = bdrv_aio_read(acb1->hd_aiocb, - (acb1->cluster_offset >> 9) + index_in_cluster, - acb1->buf, acb1->n, qcow_aio_read_cb, acb); - if (ret < 0) + 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 int qcow_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors) +static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - QCowAIOCB *acb1 = acb->opaque; - - acb1->sector_num = sector_num; - acb1->buf = buf; - acb1->nb_sectors = nb_sectors; - acb1->n = 0; - acb1->cluster_offset = 0; + 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 0; + return &acb->common; } static void qcow_aio_write_cb(void *opaque, int ret) { - BlockDriverAIOCB *acb = opaque; - BlockDriverState *bs = acb->bs; + QCowAIOCB *acb = opaque; + BlockDriverState *bs = acb->common.bs; BDRVQcowState *s = bs->opaque; - QCowAIOCB *acb1 = acb->opaque; int index_in_cluster; uint64_t cluster_offset; const uint8_t *src_buf; - + + acb->hd_aiocb = NULL; + if (ret < 0) { fail: - acb->cb(acb->cb_opaque, ret); + acb->common.cb(acb->common.opaque, ret); + qemu_aio_release(acb); return; } - acb1->nb_sectors -= acb1->n; - acb1->sector_num += acb1->n; - acb1->buf += acb1->n * 512; + acb->nb_sectors -= acb->n; + acb->sector_num += acb->n; + acb->buf += acb->n * 512; - if (acb1->nb_sectors == 0) { + if (acb->nb_sectors == 0) { /* request completed */ - acb->cb(acb->cb_opaque, 0); + acb->common.cb(acb->common.opaque, 0); + qemu_aio_release(acb); return; } - index_in_cluster = acb1->sector_num & (s->cluster_sectors - 1); - acb1->n = s->cluster_sectors - index_in_cluster; - if (acb1->n > acb1->nb_sectors) - acb1->n = acb1->nb_sectors; - cluster_offset = get_cluster_offset(bs, acb1->sector_num << 9, 1, 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; + cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, index_in_cluster, - index_in_cluster + acb1->n); + index_in_cluster + acb->n); if (!cluster_offset || (cluster_offset & 511) != 0) { ret = -EIO; goto fail; } if (s->crypt_method) { - if (!acb1->cluster_data) { - acb1->cluster_data = qemu_mallocz(s->cluster_size); - if (!acb1->cluster_data) { + if (!acb->cluster_data) { + acb->cluster_data = qemu_mallocz(s->cluster_size); + if (!acb->cluster_data) { ret = -ENOMEM; goto fail; } } - encrypt_sectors(s, acb1->sector_num, acb1->cluster_data, acb1->buf, - acb1->n, 1, &s->aes_encrypt_key); - src_buf = acb1->cluster_data; + 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 = acb1->buf; + src_buf = acb->buf; } - ret = bdrv_aio_write(acb1->hd_aiocb, - (cluster_offset >> 9) + index_in_cluster, - src_buf, acb1->n, - qcow_aio_write_cb, acb); - if (ret < 0) + 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 int qcow_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, - const uint8_t *buf, int nb_sectors) +static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - QCowAIOCB *acb1 = acb->opaque; - BlockDriverState *bs = acb->bs; BDRVQcowState *s = bs->opaque; + QCowAIOCB *acb; s->cluster_cache_offset = -1; /* disable compressed cache */ - acb1->sector_num = sector_num; - acb1->buf = (uint8_t *)buf; - acb1->nb_sectors = nb_sectors; - acb1->n = 0; + 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 0; -} - -static void qcow_aio_cancel(BlockDriverAIOCB *acb) -{ - QCowAIOCB *acb1 = acb->opaque; - if (acb1->hd_aiocb) - bdrv_aio_cancel(acb1->hd_aiocb); - if (acb1->backing_hd_aiocb) - bdrv_aio_cancel(acb1->backing_hd_aiocb); + return &acb->common; } -static void qcow_aio_delete(BlockDriverAIOCB *acb) +static void qcow_aio_cancel(BlockDriverAIOCB *blockacb) { - QCowAIOCB *acb1 = acb->opaque; - if (acb1->hd_aiocb) - bdrv_aio_delete(acb1->hd_aiocb); - if (acb1->backing_hd_aiocb) - bdrv_aio_delete(acb1->backing_hd_aiocb); - qemu_free(acb1->cluster_data); - qemu_free(acb1); + QCowAIOCB *acb = (QCowAIOCB *)blockacb; + if (acb->hd_aiocb) + bdrv_aio_cancel(acb->hd_aiocb); + qemu_aio_release(acb); } static void qcow_close(BlockDriverState *bs) @@ -2249,11 +2232,10 @@ BlockDriver bdrv_qcow2 = { qcow_set_key, qcow_make_empty, - .bdrv_aio_new = qcow_aio_new, .bdrv_aio_read = qcow_aio_read, .bdrv_aio_write = qcow_aio_write, .bdrv_aio_cancel = qcow_aio_cancel, - .bdrv_aio_delete = qcow_aio_delete, + .aiocb_size = sizeof(QCowAIOCB), .bdrv_write_compressed = qcow_write_compressed, .bdrv_snapshot_create = qcow_snapshot_create, diff --git a/block-raw.c b/block-raw.c index adb3d39ad..a64564dc7 100644 --- a/block-raw.c +++ b/block-raw.c @@ -200,13 +200,13 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, /* Unix AOP using POSIX AIO */ typedef struct RawAIOCB { + BlockDriverAIOCB common; struct aiocb aiocb; - int busy; /* only used for debugging */ - BlockDriverAIOCB *next; + struct RawAIOCB *next; } RawAIOCB; static int aio_sig_num = SIGUSR2; -static BlockDriverAIOCB *first_aio; /* AIO issued */ +static RawAIOCB *first_aio; /* AIO issued */ static int aio_initialized = 0; static void aio_signal_handler(int signum) @@ -249,8 +249,7 @@ void qemu_aio_init(void) void qemu_aio_poll(void) { - BlockDriverAIOCB *acb, **pacb; - RawAIOCB *acb1; + RawAIOCB *acb, **pacb; int ret; for(;;) { @@ -259,17 +258,16 @@ void qemu_aio_poll(void) acb = *pacb; if (!acb) goto the_end; - acb1 = acb->opaque; - ret = aio_error(&acb1->aiocb); + ret = aio_error(&acb->aiocb); if (ret == ECANCELED) { /* remove the request */ - acb1->busy = 0; - *pacb = acb1->next; + *pacb = acb->next; + qemu_aio_release(acb); } else if (ret != EINPROGRESS) { /* end of aio */ if (ret == 0) { - ret = aio_return(&acb1->aiocb); - if (ret == acb1->aiocb.aio_nbytes) + ret = aio_return(&acb->aiocb); + if (ret == acb->aiocb.aio_nbytes) ret = 0; else ret = -1; @@ -277,13 +275,13 @@ void qemu_aio_poll(void) ret = -ret; } /* remove the request */ - acb1->busy = 0; - *pacb = acb1->next; + *pacb = acb->next; /* call the callback */ - acb->cb(acb->cb_opaque, ret); + acb->common.cb(acb->common.opaque, ret); + qemu_aio_release(acb); break; } else { - pacb = &acb1->next; + pacb = &acb->next; } } } @@ -324,70 +322,70 @@ void qemu_aio_wait_end(void) sigprocmask(SIG_SETMASK, &wait_oset, NULL); } -static int raw_aio_new(BlockDriverAIOCB *acb) +static RawAIOCB *raw_aio_setup(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - RawAIOCB *acb1; - BDRVRawState *s = acb->bs->opaque; - - acb1 = qemu_mallocz(sizeof(RawAIOCB)); - if (!acb1) - return -1; - acb->opaque = acb1; - acb1->aiocb.aio_fildes = s->fd; - acb1->aiocb.aio_sigevent.sigev_signo = aio_sig_num; - acb1->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; - return 0; + BDRVRawState *s = bs->opaque; + RawAIOCB *acb; + + 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 int raw_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors) +static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - RawAIOCB *acb1 = acb->opaque; + RawAIOCB *acb; - assert(acb1->busy == 0); - acb1->busy = 1; - acb1->aiocb.aio_buf = buf; - acb1->aiocb.aio_nbytes = nb_sectors * 512; - acb1->aiocb.aio_offset = sector_num * 512; - acb1->next = first_aio; - first_aio = acb; - if (aio_read(&acb1->aiocb) < 0) { - acb1->busy = 0; - return -errno; + 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 0; + return &acb->common; } -static int raw_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, - const uint8_t *buf, int nb_sectors) +static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - RawAIOCB *acb1 = acb->opaque; + RawAIOCB *acb; - assert(acb1->busy == 0); - acb1->busy = 1; - acb1->aiocb.aio_buf = (uint8_t *)buf; - acb1->aiocb.aio_nbytes = nb_sectors * 512; - acb1->aiocb.aio_offset = sector_num * 512; - acb1->next = first_aio; - first_aio = acb; - if (aio_write(&acb1->aiocb) < 0) { - acb1->busy = 0; - return -errno; + 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 0; + return &acb->common; } -static void raw_aio_cancel(BlockDriverAIOCB *acb) +static void raw_aio_cancel(BlockDriverAIOCB *blockacb) { - RawAIOCB *acb1 = acb->opaque; int ret; - BlockDriverAIOCB **pacb; + RawAIOCB *acb = (RawAIOCB *)blockacb; + RawAIOCB **pacb; - ret = aio_cancel(acb1->aiocb.aio_fildes, &acb1->aiocb); + 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(&acb1->aiocb) == EINPROGRESS); + while (aio_error(&acb->aiocb) == EINPROGRESS); } /* remove the callback from the queue */ @@ -396,22 +394,14 @@ static void raw_aio_cancel(BlockDriverAIOCB *acb) if (*pacb == NULL) { break; } else if (*pacb == acb) { - acb1->busy = 0; - *pacb = acb1->next; + *pacb = acb->next; + qemu_aio_release(acb); break; } - acb1 = (*pacb)->opaque; - pacb = &acb1->next; + pacb = &acb->next; } } -static void raw_aio_delete(BlockDriverAIOCB *acb) -{ - RawAIOCB *acb1 = acb->opaque; - raw_aio_cancel(acb); - qemu_free(acb1); -} - static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -508,11 +498,10 @@ BlockDriver bdrv_raw = { raw_create, raw_flush, - .bdrv_aio_new = raw_aio_new, .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, - .bdrv_aio_delete = raw_aio_delete, + .aiocb_size = sizeof(RawAIOCB), .protocol_name = "file", .bdrv_pread = raw_pread, .bdrv_pwrite = raw_pwrite, @@ -530,6 +519,7 @@ typedef struct BDRVRawState { } BDRVRawState; typedef struct RawAIOCB { + BlockDriverAIOCB common; HANDLE hEvent; OVERLAPPED ov; int count; @@ -574,6 +564,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRawState *s = bs->opaque; int access_flags, create_flags; + DWORD overlapped; if ((flags & BDRV_O_ACCESS) == O_RDWR) { access_flags = GENERIC_READ | GENERIC_WRITE; @@ -585,9 +576,14 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) } else { create_flags = OPEN_EXISTING; } +#ifdef QEMU_TOOL + overlapped = 0; +#else + overlapped = FILE_FLAG_OVERLAPPED; +#endif s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, - create_flags, FILE_FLAG_OVERLAPPED, 0); + create_flags, overlapped, 0); if (s->hfile == INVALID_HANDLE_VALUE) return -1; return 0; @@ -637,104 +633,107 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, return ret_count; } -static int raw_aio_new(BlockDriverAIOCB *acb) -{ - RawAIOCB *acb1; - - acb1 = qemu_mallocz(sizeof(RawAIOCB)); - if (!acb1) - return -ENOMEM; - acb->opaque = acb1; - acb1->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!acb1->hEvent) - return -ENOMEM; - return 0; -} #ifndef QEMU_TOOL static void raw_aio_cb(void *opaque) { - BlockDriverAIOCB *acb = opaque; - BlockDriverState *bs = acb->bs; + RawAIOCB *acb = opaque; + BlockDriverState *bs = acb->common.bs; BDRVRawState *s = bs->opaque; - RawAIOCB *acb1 = acb->opaque; DWORD ret_count; int ret; - ret = GetOverlappedResult(s->hfile, &acb1->ov, &ret_count, TRUE); - if (!ret || ret_count != acb1->count) { - acb->cb(acb->cb_opaque, -EIO); + ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE); + if (!ret || ret_count != acb->count) { + acb->common.cb(acb->common.opaque, -EIO); } else { - acb->cb(acb->cb_opaque, 0); + acb->common.cb(acb->common.opaque, 0); } } #endif -static int raw_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors) + +static RawAIOCB *raw_aio_setup(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriverState *bs = acb->bs; - BDRVRawState *s = bs->opaque; - RawAIOCB *acb1 = acb->opaque; - int ret; + RawAIOCB *acb; int64_t offset; - memset(&acb1->ov, 0, sizeof(acb1->ov)); + 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; - acb1->ov.Offset = offset; - acb1->ov.OffsetHigh = offset >> 32; - acb1->ov.hEvent = acb1->hEvent; - acb1->count = nb_sectors * 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(acb1->ov.hEvent, raw_aio_cb, acb); + qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb); #endif - ret = ReadFile(s->hfile, buf, acb1->count, NULL, &acb1->ov); - if (!ret) - return -EIO; - return 0; + return acb; } -static int raw_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors) +static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriverState *bs = acb->bs; BDRVRawState *s = bs->opaque; - RawAIOCB *acb1 = acb->opaque; + RawAIOCB *acb; int ret; - int64_t offset; - memset(&acb1->ov, 0, sizeof(acb1->ov)); - offset = sector_num * 512; - acb1->ov.Offset = offset; - acb1->ov.OffsetHigh = offset >> 32; - acb1->ov.hEvent = acb1->hEvent; - acb1->count = nb_sectors * 512; -#ifndef QEMU_TOOL - qemu_add_wait_object(acb1->ov.hEvent, raw_aio_cb, acb); + 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 - ret = ReadFile(s->hfile, buf, acb1->count, NULL, &acb1->ov); - if (!ret) - return -EIO; - return 0; + return (BlockDriverAIOCB *)acb; } -static void raw_aio_cancel(BlockDriverAIOCB *acb) +static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriverState *bs = acb->bs; BDRVRawState *s = bs->opaque; -#ifndef QEMU_TOOL - RawAIOCB *acb1 = acb->opaque; + RawAIOCB *acb; + int ret; - qemu_del_wait_object(acb1->ov.hEvent, raw_aio_cb, acb); + 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 - /* XXX: if more than one async I/O it is not correct */ - CancelIo(s->hfile); + return (BlockDriverAIOCB *)acb; } -static void raw_aio_delete(BlockDriverAIOCB *acb) +static void raw_aio_cancel(BlockDriverAIOCB *blockacb) { - RawAIOCB *acb1 = acb->opaque; - raw_aio_cancel(acb); - CloseHandle(acb1->hEvent); - qemu_free(acb1); +#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 } static void raw_flush(BlockDriverState *bs) @@ -823,11 +822,10 @@ BlockDriver bdrv_raw = { raw_flush, #if 0 - .bdrv_aio_new = raw_aio_new, .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, - .bdrv_aio_delete = raw_aio_delete, + .aiocb_size = sizeof(RawAIOCB); #endif .protocol_name = "file", .bdrv_pread = raw_pread, diff --git a/block.c b/block.c index dacee2f7f..0c2fc6ea8 100644 --- a/block.c +++ b/block.c @@ -35,13 +35,13 @@ #define SECTOR_BITS 9 #define SECTOR_SIZE (1 << SECTOR_BITS) -static int bdrv_aio_new_em(BlockDriverAIOCB *acb); -static int bdrv_aio_read_em(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors); -static int bdrv_aio_write_em(BlockDriverAIOCB *acb, int64_t sector_num, - const uint8_t *buf, int nb_sectors); +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 void bdrv_aio_delete_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, @@ -106,13 +106,11 @@ void path_combine(char *dest, int dest_size, void bdrv_register(BlockDriver *bdrv) { - if (!bdrv->bdrv_aio_new) { + if (!bdrv->bdrv_aio_read) { /* add AIO emulation layer */ - bdrv->bdrv_aio_new = bdrv_aio_new_em; 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->bdrv_aio_delete = bdrv_aio_delete_em; } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) { /* add synchronous IO emulation layer */ bdrv->bdrv_read = bdrv_read_em; @@ -964,7 +962,9 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); } else { ti = sn->date_sec; +#ifndef _WIN32 localtime_r(&ti, &tm); +#endif strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm); secs = sn->vm_clock_nsec / 1000000000; @@ -988,31 +988,14 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) /**************************************************************/ /* async I/Os */ -BlockDriverAIOCB *bdrv_aio_new(BlockDriverState *bs) +BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { BlockDriver *drv = bs->drv; - BlockDriverAIOCB *acb; - acb = qemu_mallocz(sizeof(BlockDriverAIOCB)); - if (!acb) - return NULL; - - acb->bs = bs; - if (drv->bdrv_aio_new(acb) < 0) { - qemu_free(acb); - return NULL; - } - return acb; -} - -int bdrv_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) -{ - BlockDriverState *bs = acb->bs; - BlockDriver *drv = bs->drv; if (!bs->inserted) - return -1; + 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) { @@ -1022,141 +1005,114 @@ int bdrv_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, buf += 512; } - acb->cb = cb; - acb->cb_opaque = opaque; - return drv->bdrv_aio_read(acb, sector_num, buf, nb_sectors); + return drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque); } -int bdrv_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, - const 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) { - BlockDriverState *bs = acb->bs; BlockDriver *drv = bs->drv; if (!bs->inserted) - return -1; + return NULL; if (bs->read_only) - return -1; + return NULL; if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { memcpy(bs->boot_sector_data, buf, 512); } - acb->cb = cb; - acb->cb_opaque = opaque; - return drv->bdrv_aio_write(acb, sector_num, buf, nb_sectors); + return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); } void bdrv_aio_cancel(BlockDriverAIOCB *acb) - { - BlockDriverState *bs = acb->bs; - BlockDriver *drv = bs->drv; - - drv->bdrv_aio_cancel(acb); - } - -void bdrv_aio_delete(BlockDriverAIOCB *acb) { - BlockDriverState *bs = acb->bs; - BlockDriver *drv = bs->drv; + BlockDriver *drv = acb->bs->drv; - drv->bdrv_aio_delete(acb); - qemu_free(acb); + drv->bdrv_aio_cancel(acb); } + /**************************************************************/ /* async block device emulation */ #ifdef QEMU_TOOL -static int bdrv_aio_new_em(BlockDriverAIOCB *acb) -{ - return 0; -} - -static int bdrv_aio_read_em(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors) +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(acb->bs, sector_num, buf, nb_sectors); - acb->cb(acb->cb_opaque, ret); - return 0; + ret = bdrv_read(bs, sector_num, buf, nb_sectors); + cb(opaque, ret); + return NULL; } -static int bdrv_aio_write_em(BlockDriverAIOCB *acb, int64_t sector_num, - const uint8_t *buf, int nb_sectors) +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(acb->bs, sector_num, buf, nb_sectors); - acb->cb(acb->cb_opaque, ret); - return 0; + ret = bdrv_write(bs, sector_num, buf, nb_sectors); + cb(opaque, ret); + return NULL; } static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb) { } - -static void bdrv_aio_delete_em(BlockDriverAIOCB *acb) -{ -} #else typedef struct BlockDriverAIOCBSync { + BlockDriverAIOCB common; QEMUBH *bh; int ret; } BlockDriverAIOCBSync; -static void bdrv_aio_bh_cb(void *opaque) -{ - BlockDriverAIOCB *acb = opaque; - BlockDriverAIOCBSync *acb1 = acb->opaque; - acb->cb(acb->cb_opaque, acb1->ret); -} +static BlockDriverAIOCBSync *free_acb = NULL; -static int bdrv_aio_new_em(BlockDriverAIOCB *acb) +static void bdrv_aio_bh_cb(void *opaque) { - BlockDriverAIOCBSync *acb1; - - acb1 = qemu_mallocz(sizeof(BlockDriverAIOCBSync)); - if (!acb1) - return -1; - acb->opaque = acb1; - acb1->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); - return 0; + BlockDriverAIOCBSync *acb = opaque; + acb->common.cb(acb->common.opaque, acb->ret); + qemu_aio_release(acb); } -static int bdrv_aio_read_em(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors) +static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriverAIOCBSync *acb1 = acb->opaque; + BlockDriverAIOCBSync *acb; int ret; - - ret = bdrv_read(acb->bs, sector_num, buf, nb_sectors); - acb1->ret = ret; - qemu_bh_schedule(acb1->bh); - return 0; + + 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 int bdrv_aio_write_em(BlockDriverAIOCB *acb, int64_t sector_num, - const uint8_t *buf, int nb_sectors) +static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, + int64_t sector_num, const uint8_t *buf, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - BlockDriverAIOCBSync *acb1 = acb->opaque; + BlockDriverAIOCBSync *acb; int ret; - - ret = bdrv_write(acb->bs, sector_num, buf, nb_sectors); - acb1->ret = ret; - qemu_bh_schedule(acb1->bh); - return 0; -} -static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb) -{ - BlockDriverAIOCBSync *acb1 = acb->opaque; - qemu_bh_cancel(acb1->bh); + 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_delete_em(BlockDriverAIOCB *acb) +static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb) { - BlockDriverAIOCBSync *acb1 = acb->opaque; - qemu_bh_delete(acb1->bh); + BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb; + qemu_bh_cancel(acb->bh); + qemu_aio_release(acb); } #endif /* !QEMU_TOOL */ @@ -1173,20 +1129,16 @@ static void bdrv_rw_em_cb(void *opaque, int ret) static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { - int async_ret, ret; + int async_ret; + BlockDriverAIOCB *acb; - if (!bs->sync_aiocb) { - bs->sync_aiocb = bdrv_aio_new(bs); - if (!bs->sync_aiocb) - return -1; - } async_ret = NOT_DONE; qemu_aio_wait_start(); - ret = bdrv_aio_read(bs->sync_aiocb, sector_num, buf, nb_sectors, + acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, bdrv_rw_em_cb, &async_ret); - if (ret < 0) { + if (acb == NULL) { qemu_aio_wait_end(); - return ret; + return -1; } while (async_ret == NOT_DONE) { qemu_aio_wait(); @@ -1198,20 +1150,16 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - int async_ret, ret; + int async_ret; + BlockDriverAIOCB *acb; - if (!bs->sync_aiocb) { - bs->sync_aiocb = bdrv_aio_new(bs); - if (!bs->sync_aiocb) - return -1; - } async_ret = NOT_DONE; qemu_aio_wait_start(); - ret = bdrv_aio_write(bs->sync_aiocb, sector_num, buf, nb_sectors, + acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, bdrv_rw_em_cb, &async_ret); - if (ret < 0) { + if (acb == NULL) { qemu_aio_wait_end(); - return ret; + return -1; } while (async_ret == NOT_DONE) { qemu_aio_wait(); @@ -1235,3 +1183,32 @@ void bdrv_init(void) 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; +} diff --git a/block_int.h b/block_int.h index 26cc4ffba..8fd241f2a 100644 --- a/block_int.h +++ b/block_int.h @@ -42,13 +42,14 @@ struct BlockDriver { int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_make_empty)(BlockDriverState *bs); /* aio */ - int (*bdrv_aio_new)(BlockDriverAIOCB *acb); - int (*bdrv_aio_read)(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors); - int (*bdrv_aio_write)(BlockDriverAIOCB *acb, int64_t sector_num, - const uint8_t *buf, int nb_sectors); + 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); - void (*bdrv_aio_delete)(BlockDriverAIOCB *acb); + int aiocb_size; const char *protocol_name; int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, @@ -69,6 +70,7 @@ struct BlockDriver { QEMUSnapshotInfo **psn_info); int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + BlockDriverAIOCB *free_aiocb; struct BlockDriver *next; }; @@ -96,9 +98,9 @@ struct BlockDriverState { int is_temporary; BlockDriverState *backing_hd; - /* sync read/write emulation */ + /* async read/write emulation */ - BlockDriverAIOCB *sync_aiocb; + void *sync_aiocb; /* NOTE: the following infos are only hints for real hardware drivers. They are not used by the block driver */ @@ -111,11 +113,14 @@ struct BlockDriverState { struct BlockDriverAIOCB { BlockDriverState *bs; BlockDriverCompletionFunc *cb; - void *cb_opaque; - - void *opaque; /* driver opaque */ + 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 */ diff --git a/vl.h b/vl.h index ce52fb826..1632e3571 100644 --- a/vl.h +++ b/vl.h @@ -569,15 +569,13 @@ void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); -BlockDriverAIOCB *bdrv_aio_new(BlockDriverState *bs); -int bdrv_aio_read(BlockDriverAIOCB *acb, int64_t sector_num, - uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque); -int bdrv_aio_write(BlockDriverAIOCB *acb, int64_t sector_num, - const uint8_t *buf, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque); +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); -void bdrv_aio_delete(BlockDriverAIOCB *acb); void qemu_aio_init(void); void qemu_aio_poll(void); -- cgit v1.2.3 From 90765429aab64478e4dd9de3bbb21e5eafb5ead5 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Aug 2006 19:10:16 +0000 Subject: fixed aio emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2099 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index 0c2fc6ea8..d81451058 100644 --- a/block.c +++ b/block.c @@ -35,6 +35,12 @@ #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); @@ -111,6 +117,7 @@ void bdrv_register(BlockDriver *bdrv) 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; @@ -1061,14 +1068,6 @@ static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb) { } #else -typedef struct BlockDriverAIOCBSync { - BlockDriverAIOCB common; - QEMUBH *bh; - int ret; -} BlockDriverAIOCBSync; - -static BlockDriverAIOCBSync *free_acb = NULL; - static void bdrv_aio_bh_cb(void *opaque) { BlockDriverAIOCBSync *acb = opaque; -- cgit v1.2.3 From 19d36792c02e09941d9f3ef19b9461306cc54d76 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Aug 2006 21:34:34 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2100 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 6 +++--- qemu-img.texi | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 9f0b4f68b..8ff329a72 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -949,7 +949,7 @@ format. Normally this device is the first virtual hard drive. Use the monitor command @code{savevm} to create a new VM snapshot or replace an existing one. A human readable name can be assigned to each -snapshots in addition to its numerical ID. +snapshot in addition to its numerical ID. Use @code{loadvm} to restore a VM snapshot and @code{delvm} to remove a VM snapshot. @code{info snapshots} lists the available snapshots @@ -972,8 +972,8 @@ and writable block device. The disk image snapshots are stored in every disk image. The size of a snapshot in a disk image is difficult to evaluate and is not shown by @code{info snapshots} because the associated disk sectors are shared among all the snapshots to save -disk space (otherwise each snapshot would have to copy the full disk -images). +disk space (otherwise each snapshot would need a full copy of all the +disk images). When using the (unrelated) @code{-snapshot} option (@ref{disk_images_snapshot_mode}), you can always make VM snapshots, diff --git a/qemu-img.texi b/qemu-img.texi index ac7923ffd..1f01dce16 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -29,16 +29,19 @@ is the disk image format. It is guessed automatically in most cases. The followi @item raw Raw disk image format (default). This format has the advantage of -being simple and easily exportable to all other emulators. If your file -system supports @emph{holes} (for example in ext2 or ext3 on Linux), -then only the written sectors will reserve space. Use @code{qemu-img -info} to know the real size used by the image or @code{ls -ls} on -Unix/Linux. +being simple and easily exportable to all other emulators. If your +file system supports @emph{holes} (for example in ext2 or ext3 on +Linux or NTFS on Windows), then only the written sectors will reserve +space. Use @code{qemu-img info} to know the real size used by the +image or @code{ls -ls} on Unix/Linux. -@item qcow +@item qcow2 QEMU image format, the most versatile format. Use it to have smaller images (useful if your filesystem does not supports holes, for example -on Windows), optional AES encryption and zlib based compression. +on Windows), optional AES encryption, zlib based compression and +support of multiple VM snapshots. +@item qcow +Old QEMU image format. Left for compatibility. @item cow User Mode Linux Copy On Write image format. Used to be the only growable image format in QEMU. It is supported only for compatibility with @@ -104,7 +107,8 @@ are detected and suppressed from the destination image. Give information about the disk image @var{filename}. Use it in particular to know the size reserved on disk which can be different -from the displayed size. +from the displayed size. If VM snapshots are stored in the disk image, +they are displayed too. @end table @c man end -- cgit v1.2.3 From fb43f4dddc1512e6429c526871b48c99292a4861 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Aug 2006 21:34:46 +0000 Subject: copyright update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2101 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 6 +++--- vl.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 06687bc1f..8b8da0565 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1,7 +1,7 @@ /* - * create a COW disk image + * QEMU disk image utility * - * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003-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 @@ -131,7 +131,7 @@ static void format_print(void *opaque, const char *name) void help(void) { - printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2005 Fabrice Bellard\n" + printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2006 Fabrice Bellard\n" "usage: qemu-img command [command options]\n" "QEMU disk image utility\n" "\n" diff --git a/vl.c b/vl.c index 7ef5f52cb..1bef09c9c 100644 --- a/vl.c +++ b/vl.c @@ -1,7 +1,7 @@ /* * QEMU System Emulator * - * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2003-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 @@ -5800,7 +5800,7 @@ int main_loop(void) void help(void) { - printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n" + printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2006 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" "\n" "'disk_image' is a raw hard image image for IDE hard disk 0\n" -- cgit v1.2.3 From e84a4fedf74983ad0517b4754f927a96a2eea7ce Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Aug 2006 21:35:12 +0000 Subject: mem leak fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2102 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/wavcapture.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/audio/wavcapture.c b/audio/wavcapture.c index d1a6f7ba7..d915fa02b 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -34,22 +34,19 @@ static void wav_destroy (void *opaque) uint32_t datalen = wav->bytes; uint32_t rifflen = datalen + 36; - if (!wav->f) { - return; - } - - le_store (rlen, rifflen, 4); - le_store (dlen, datalen, 4); - - qemu_fseek (wav->f, 4, SEEK_SET); - qemu_put_buffer (wav->f, rlen, 4); - - qemu_fseek (wav->f, 32, SEEK_CUR); - qemu_put_buffer (wav->f, dlen, 4); - qemu_fclose (wav->f); - if (wav->path) { - qemu_free (wav->path); + if (wav->f) { + le_store (rlen, rifflen, 4); + le_store (dlen, datalen, 4); + + qemu_fseek (wav->f, 4, SEEK_SET); + qemu_put_buffer (wav->f, rlen, 4); + + qemu_fseek (wav->f, 32, SEEK_CUR); + qemu_put_buffer (wav->f, dlen, 4); + qemu_fclose (wav->f); } + + qemu_free (wav->path); } static void wav_capture (void *opaque, void *buf, int size) @@ -153,6 +150,8 @@ int wav_start_capture (CaptureState *s, const char *path, int freq, cap = AUD_add_capture (NULL, &as, &ops, wav); if (!cap) { term_printf ("Failed to add audio capture\n"); + qemu_free (wav->path); + qemu_fclose (wav->f); qemu_free (wav); return -1; } -- cgit v1.2.3 From 8ccad811e6c138102072d6ad10fea384538755f2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 7 Aug 2006 21:36:34 +0000 Subject: use AIO for DMA transfers - enabled DMA for CDROMs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2103 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 435 ++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 236 insertions(+), 199 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index debbc0f41..40e7b42c6 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -26,6 +26,8 @@ /* debug IDE devices */ //#define DEBUG_IDE //#define DEBUG_IDE_ATAPI +//#define DEBUG_AIO +#define USE_DMA_CDROM /* Bits of HD_STATUS */ #define ERR_STAT 0x01 @@ -368,19 +370,20 @@ typedef struct IDEState { #define UDIDETCR0 0x73 #define UDIDETCR1 0x7B -typedef int IDEDMAFunc(IDEState *s, - target_phys_addr_t phys_addr, - int transfer_size1); - typedef struct BMDMAState { uint8_t cmd; uint8_t status; uint32_t addr; - + struct PCIIDEState *pci_dev; /* current transfer state */ + uint32_t cur_addr; + uint32_t cur_prd_last; + uint32_t cur_prd_addr; + uint32_t cur_prd_len; IDEState *ide_if; - IDEDMAFunc *dma_cb; + BlockDriverCompletionFunc *dma_cb; + BlockDriverAIOCB *aiocb; } BMDMAState; typedef struct PCIIDEState { @@ -390,7 +393,7 @@ typedef struct PCIIDEState { int type; /* see IDE_TYPE_xxx */ } PCIIDEState; -static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb); +static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb); static void padstr(char *str, const char *src, int len) { @@ -513,10 +516,17 @@ static void ide_atapi_identify(IDEState *s) padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ +#ifdef USE_DMA_CDROM + put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ + put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */ + put_le16(p + 63, 7); /* mdma0-2 supported */ + put_le16(p + 64, 0x3f); /* PIO modes supported */ +#else put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */ put_le16(p + 53, 3); /* words 64-70, 54-58 valid */ put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ put_le16(p + 64, 1); /* PIO modes */ +#endif put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ @@ -526,7 +536,9 @@ static void ide_atapi_identify(IDEState *s) put_le16(p + 72, 30); /* in ns */ put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ - +#ifdef USE_DMA_CDROM + put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ +#endif memcpy(s->identify_data, p, sizeof(s->identify_data)); s->identify_set = 1; } @@ -659,54 +671,101 @@ static void ide_sector_read(IDEState *s) } } -static int ide_read_dma_cb(IDEState *s, - target_phys_addr_t phys_addr, - int transfer_size1) +/* return 0 if buffer completed */ +static int dma_buf_rw(BMDMAState *bm, int is_write) { - int len, transfer_size, n; - int64_t sector_num; + IDEState *s = bm->ide_if; + struct { + uint32_t addr; + uint32_t size; + } prd; + int l, len; - transfer_size = transfer_size1; - while (transfer_size > 0) { - len = s->io_buffer_size - s->io_buffer_index; - if (len <= 0) { - /* transfert next data */ - n = s->nsector; - if (n == 0) - break; - if (n > MAX_MULT_SECTORS) - n = MAX_MULT_SECTORS; - sector_num = ide_get_sector(s); - bdrv_read(s->bs, sector_num, s->io_buffer, n); - s->io_buffer_index = 0; - s->io_buffer_size = n * 512; - len = s->io_buffer_size; - sector_num += n; - ide_set_sector(s, sector_num); - s->nsector -= n; + for(;;) { + l = s->io_buffer_size - s->io_buffer_index; + if (l <= 0) + break; + if (bm->cur_prd_len == 0) { + /* end of table (with a fail safe of one page) */ + if (bm->cur_prd_last || + (bm->cur_addr - bm->addr) >= 4096) + return 0; + cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8); + bm->cur_addr += 8; + prd.addr = le32_to_cpu(prd.addr); + prd.size = le32_to_cpu(prd.size); + len = prd.size & 0xfffe; + if (len == 0) + len = 0x10000; + bm->cur_prd_len = len; + bm->cur_prd_addr = prd.addr; + bm->cur_prd_last = (prd.size & 0x80000000); + } + if (l > bm->cur_prd_len) + l = bm->cur_prd_len; + if (l > 0) { + if (is_write) { + cpu_physical_memory_write(bm->cur_prd_addr, + s->io_buffer + s->io_buffer_index, l); + } else { + cpu_physical_memory_read(bm->cur_prd_addr, + s->io_buffer + s->io_buffer_index, l); + } + bm->cur_prd_addr += l; + bm->cur_prd_len -= l; + s->io_buffer_index += l; } - if (len > transfer_size) - len = transfer_size; - cpu_physical_memory_write(phys_addr, - s->io_buffer + s->io_buffer_index, len); - s->io_buffer_index += len; - transfer_size -= len; - phys_addr += len; } - if (s->io_buffer_index >= s->io_buffer_size && s->nsector == 0) { + return 1; +} + +/* XXX: handle errors */ +static void ide_read_dma_cb(void *opaque, int ret) +{ + BMDMAState *bm = opaque; + IDEState *s = bm->ide_if; + int n; + int64_t sector_num; + + n = s->io_buffer_size >> 9; + sector_num = ide_get_sector(s); + if (n > 0) { + sector_num += n; + ide_set_sector(s, sector_num); + s->nsector -= n; + if (dma_buf_rw(bm, 1) == 0) + goto eot; + } + + /* end of transfer ? */ + if (s->nsector == 0) { s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); -#ifdef DEBUG_IDE_ATAPI - printf("dma status=0x%x\n", s->status); -#endif - return 0; + eot: + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + bm->dma_cb = NULL; + bm->ide_if = NULL; + bm->aiocb = NULL; + return; } - return transfer_size1 - transfer_size; + + /* launch next transfer */ + n = s->nsector; + if (n > MAX_MULT_SECTORS) + n = MAX_MULT_SECTORS; + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; +#ifdef DEBUG_AIO + printf("aio_read: sector_num=%lld n=%d\n", sector_num, n); +#endif + bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n, + ide_read_dma_cb, bm); } static void ide_sector_read_dma(IDEState *s) { - s->status = READY_STAT | SEEK_STAT | DRQ_STAT; + s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; s->io_buffer_index = 0; s->io_buffer_size = 0; ide_dma_start(s, ide_read_dma_cb); @@ -761,71 +820,56 @@ static void ide_sector_write(IDEState *s) } } -static int ide_write_dma_cb(IDEState *s, - target_phys_addr_t phys_addr, - int transfer_size1) +/* XXX: handle errors */ +static void ide_write_dma_cb(void *opaque, int ret) { - int len, transfer_size, n; + BMDMAState *bm = opaque; + IDEState *s = bm->ide_if; + int n; int64_t sector_num; - transfer_size = transfer_size1; - for(;;) { - len = s->io_buffer_size - s->io_buffer_index; - if (len == 0) { - n = s->io_buffer_size >> 9; - sector_num = ide_get_sector(s); - bdrv_write(s->bs, sector_num, s->io_buffer, - s->io_buffer_size >> 9); - sector_num += n; - ide_set_sector(s, sector_num); - s->nsector -= n; - n = s->nsector; - if (n == 0) { - /* end of transfer */ - s->status = READY_STAT | SEEK_STAT; -#ifdef TARGET_I386 - if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { - /* It seems there is a bug in the Windows 2000 installer - HDD IDE driver which fills the disk with empty logs - when the IDE write IRQ comes too early. This hack tries - to correct that at the expense of slower write - performances. Use this option _only_ to install Windows - 2000. You must disable it for normal use. */ - qemu_mod_timer(s->sector_write_timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); - } else -#endif - ide_set_irq(s); - return 0; - } - if (n > MAX_MULT_SECTORS) - n = MAX_MULT_SECTORS; - s->io_buffer_index = 0; - s->io_buffer_size = n * 512; - len = s->io_buffer_size; - } - if (transfer_size <= 0) - break; - if (len > transfer_size) - len = transfer_size; - cpu_physical_memory_read(phys_addr, - s->io_buffer + s->io_buffer_index, len); - s->io_buffer_index += len; - transfer_size -= len; - phys_addr += len; + n = s->io_buffer_size >> 9; + sector_num = ide_get_sector(s); + if (n > 0) { + sector_num += n; + ide_set_sector(s, sector_num); + s->nsector -= n; } - return transfer_size1 - transfer_size; -} -static void ide_sector_write_dma(IDEState *s) -{ - int n; - s->status = READY_STAT | SEEK_STAT | DRQ_STAT; + /* end of transfer ? */ + if (s->nsector == 0) { + s->status = READY_STAT | SEEK_STAT; + ide_set_irq(s); + eot: + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + bm->dma_cb = NULL; + bm->ide_if = NULL; + bm->aiocb = NULL; + return; + } + + /* launch next transfer */ n = s->nsector; if (n > MAX_MULT_SECTORS) n = MAX_MULT_SECTORS; s->io_buffer_index = 0; s->io_buffer_size = n * 512; + + if (dma_buf_rw(bm, 0) == 0) + goto eot; +#ifdef DEBUG_AIO + printf("aio_write: sector_num=%lld n=%d\n", sector_num, n); +#endif + bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, + ide_write_dma_cb, bm); +} + +static void ide_sector_write_dma(IDEState *s) +{ + s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT; + s->io_buffer_index = 0; + s->io_buffer_size = 0; ide_dma_start(s, ide_write_dma_cb); } @@ -882,6 +926,23 @@ static void lba_to_msf(uint8_t *buf, int lba) buf[2] = lba % 75; } +static void cd_data_to_raw(uint8_t *buf, int lba) +{ + /* sync bytes */ + buf[0] = 0x00; + memset(buf + 1, 0xff, 10); + buf[11] = 0x00; + buf += 12; + /* MSF */ + lba_to_msf(buf, lba); + buf[3] = 0x01; /* mode 1 data */ + buf += 4; + /* data */ + buf += 2048; + /* XXX: ECC not computed */ + memset(buf, 0, 288); +} + static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, int sector_size) { @@ -890,20 +951,8 @@ static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, bdrv_read(bs, (int64_t)lba << 2, buf, 4); break; case 2352: - /* sync bytes */ - buf[0] = 0x00; - memset(buf + 1, 0xff, 10); - buf[11] = 0x00; - buf += 12; - /* MSF */ - lba_to_msf(buf, lba); - buf[3] = 0x01; /* mode 1 data */ - buf += 4; - /* data */ - bdrv_read(bs, (int64_t)lba << 2, buf, 4); - buf += 2048; - /* ECC */ - memset(buf, 0, 288); + bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); + cd_data_to_raw(buf, lba); break; default: break; @@ -1013,46 +1062,58 @@ static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, } /* ATAPI DMA support */ -static int ide_atapi_cmd_read_dma_cb(IDEState *s, - target_phys_addr_t phys_addr, - int transfer_size1) + +/* XXX: handle read errors */ +static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) { - int len, transfer_size; - - transfer_size = transfer_size1; - while (transfer_size > 0) { -#ifdef DEBUG_IDE_ATAPI - printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr); -#endif - if (s->packet_transfer_size <= 0) - break; - len = s->cd_sector_size - s->io_buffer_index; - if (len <= 0) { - /* transfert next data */ - cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); - s->lba++; - s->io_buffer_index = 0; - len = s->cd_sector_size; + BMDMAState *bm = opaque; + IDEState *s = bm->ide_if; + int data_offset, n; + + if (s->io_buffer_size > 0) { + if (s->cd_sector_size == 2352) { + n = 1; + cd_data_to_raw(s->io_buffer, s->lba); + } else { + n = s->io_buffer_size >> 11; } - if (len > transfer_size) - len = transfer_size; - cpu_physical_memory_write(phys_addr, - s->io_buffer + s->io_buffer_index, len); - s->packet_transfer_size -= len; - s->io_buffer_index += len; - transfer_size -= len; - phys_addr += len; + s->packet_transfer_size -= s->io_buffer_size; + s->lba += n; + if (dma_buf_rw(bm, 1) == 0) + goto eot; } + if (s->packet_transfer_size <= 0) { s->status = READY_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s); -#ifdef DEBUG_IDE_ATAPI - printf("dma status=0x%x\n", s->status); -#endif - return 0; + eot: + bm->status &= ~BM_STATUS_DMAING; + bm->status |= BM_STATUS_INT; + bm->dma_cb = NULL; + bm->ide_if = NULL; + bm->aiocb = NULL; + return; + } + + s->io_buffer_index = 0; + if (s->cd_sector_size == 2352) { + n = 1; + s->io_buffer_size = s->cd_sector_size; + data_offset = 16; + } else { + n = s->packet_transfer_size >> 11; + if (n > (MAX_MULT_SECTORS / 4)) + n = (MAX_MULT_SECTORS / 4); + s->io_buffer_size = n * 2048; + data_offset = 0; } - return transfer_size1 - transfer_size; +#ifdef DEBUG_AIO + printf("aio_read_cd: lba=%u n=%d\n", s->lba, n); +#endif + bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, + s->io_buffer + data_offset, n * 4, + ide_atapi_cmd_read_dma_cb, bm); } /* start a CD-CDROM read command with DMA */ @@ -1062,10 +1123,12 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, { s->lba = lba; s->packet_transfer_size = nb_sectors * sector_size; - s->io_buffer_index = sector_size; + s->io_buffer_index = 0; + s->io_buffer_size = 0; s->cd_sector_size = sector_size; - s->status = READY_STAT | DRQ_STAT; + /* XXX: check if BUSY_STAT should be set */ + s->status = READY_STAT | DRQ_STAT | BUSY_STAT; ide_dma_start(s, ide_atapi_cmd_read_dma_cb); } @@ -2103,59 +2166,19 @@ static void ide_map(PCIDevice *pci_dev, int region_num, } } -/* XXX: full callback usage to prepare non blocking I/Os support - - error handling */ -static void ide_dma_loop(BMDMAState *bm) -{ - struct { - uint32_t addr; - uint32_t size; - } prd; - target_phys_addr_t cur_addr; - int len, i, len1; - - cur_addr = bm->addr; - /* at most one page to avoid hanging if erroneous parameters */ - for(i = 0; i < 512; i++) { - cpu_physical_memory_read(cur_addr, (uint8_t *)&prd, 8); - prd.addr = le32_to_cpu(prd.addr); - prd.size = le32_to_cpu(prd.size); -#ifdef DEBUG_IDE - printf("ide: dma: prd: %08x: addr=0x%08x size=0x%08x\n", - (int)cur_addr, prd.addr, prd.size); -#endif - len = prd.size & 0xfffe; - if (len == 0) - len = 0x10000; - while (len > 0) { - len1 = bm->dma_cb(bm->ide_if, prd.addr, len); - if (len1 == 0) - goto the_end; - prd.addr += len1; - len -= len1; - } - /* end of transfer */ - if (prd.size & 0x80000000) - break; - cur_addr += 8; - } - /* end of transfer */ - the_end: - bm->status &= ~BM_STATUS_DMAING; - bm->status |= BM_STATUS_INT; - bm->dma_cb = NULL; - bm->ide_if = NULL; -} - -static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb) +static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb) { BMDMAState *bm = s->bmdma; if(!bm) return; bm->ide_if = s; bm->dma_cb = dma_cb; + bm->cur_addr = bm->addr; + bm->cur_prd_last = 0; + bm->cur_prd_addr = 0; + bm->cur_prd_len = 0; if (bm->status & BM_STATUS_DMAING) { - ide_dma_loop(bm); + bm->dma_cb(bm, 0); } } @@ -2167,14 +2190,28 @@ static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) #endif if (!(val & BM_CMD_START)) { /* XXX: do it better */ - bm->status &= ~BM_STATUS_DMAING; + if (bm->status & BM_STATUS_DMAING) { + bm->status &= ~BM_STATUS_DMAING; + /* cancel DMA request */ + bm->ide_if = NULL; + bm->dma_cb = NULL; + if (bm->aiocb) { +#ifdef DEBUG_AIO + printf("aio_cancel\n"); +#endif + bdrv_aio_cancel(bm->aiocb); + bm->aiocb = NULL; + } + } bm->cmd = val & 0x09; } else { - bm->status |= BM_STATUS_DMAING; + if (!(bm->status & BM_STATUS_DMAING)) { + bm->status |= BM_STATUS_DMAING; + /* start dma transfer if possible */ + if (bm->dma_cb) + bm->dma_cb(bm, 0); + } bm->cmd = val & 0x09; - /* start dma transfer if possible */ - if (bm->dma_cb) - ide_dma_loop(bm); } } -- cgit v1.2.3 From 35b961cf8d8a38e51a05dd9e540d1ddc6e66ffc3 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Aug 2006 21:55:55 +0000 Subject: indent git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2104 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lance.c | 208 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 110 insertions(+), 98 deletions(-) diff --git a/hw/lance.c b/hw/lance.c index d1679375d..cf02333dd 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -48,7 +48,7 @@ do { printf("LANCE: " fmt , ##args); } while (0) #define LE_RDP 0 #define LE_RAP 1 -#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ +#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ #define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ #define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ @@ -67,36 +67,36 @@ do { printf("LANCE: " fmt , ##args); } while (0) #define LE_C0_STRT 0x0002 /* Start the card */ #define LE_C0_INIT 0x0001 /* Init the card */ -#define LE_C3_BSWP 0x4 /* SWAP */ +#define LE_C3_BSWP 0x4 /* SWAP */ #define LE_C3_ACON 0x2 /* ALE Control */ #define LE_C3_BCON 0x1 /* Byte control */ /* Receive message descriptor 1 */ -#define LE_R1_OWN 0x80 /* Who owns the entry */ -#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ -#define LE_R1_FRA 0x20 /* FRA: Frame error */ -#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ -#define LE_R1_CRC 0x08 /* CRC error */ -#define LE_R1_BUF 0x04 /* BUF: Buffer error */ -#define LE_R1_SOP 0x02 /* Start of packet */ -#define LE_R1_EOP 0x01 /* End of packet */ -#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ - -#define LE_T1_OWN 0x80 /* Lance owns the packet */ -#define LE_T1_ERR 0x40 /* Error summary */ -#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ -#define LE_T1_EONE 0x08 /* Error: one retry needed */ -#define LE_T1_EDEF 0x04 /* Error: deferred */ -#define LE_T1_SOP 0x02 /* Start of packet */ -#define LE_T1_EOP 0x01 /* End of packet */ +#define LE_R1_OWN 0x80 /* Who owns the entry */ +#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ +#define LE_R1_FRA 0x20 /* FRA: Frame error */ +#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUF 0x04 /* BUF: Buffer error */ +#define LE_R1_SOP 0x02 /* Start of packet */ +#define LE_R1_EOP 0x01 /* End of packet */ +#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ + +#define LE_T1_OWN 0x80 /* Lance owns the packet */ +#define LE_T1_ERR 0x40 /* Error summary */ +#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ +#define LE_T1_EONE 0x08 /* Error: one retry needed */ +#define LE_T1_EDEF 0x04 /* Error: deferred */ +#define LE_T1_SOP 0x02 /* Start of packet */ +#define LE_T1_EOP 0x01 /* End of packet */ #define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ -#define LE_T3_BUF 0x8000 /* Buffer error */ -#define LE_T3_UFL 0x4000 /* Error underflow */ -#define LE_T3_LCOL 0x1000 /* Error late collision */ -#define LE_T3_CLOS 0x0800 /* Error carrier loss */ -#define LE_T3_RTY 0x0400 /* Error retry */ -#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ +#define LE_T3_BUF 0x8000 /* Buffer error */ +#define LE_T3_UFL 0x4000 /* Error underflow */ +#define LE_T3_LCOL 0x1000 /* Error late collision */ +#define LE_T3_CLOS 0x0800 /* Error carrier loss */ +#define LE_T3_RTY 0x0400 /* Error retry */ +#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ #define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) #define TX_RING_MOD_MASK (TX_RING_SIZE - 1) @@ -111,43 +111,43 @@ do { printf("LANCE: " fmt , ##args); } while (0) #define TX_BUFF_SIZE PKT_BUF_SZ struct lance_rx_desc { - unsigned short rmd0; /* low address of packet */ - unsigned char rmd1_bits; /* descriptor bits */ - unsigned char rmd1_hadr; /* high address of packet */ - short length; /* This length is 2s complement (negative)! - * Buffer length - */ - unsigned short mblength; /* This is the actual number of bytes received */ + unsigned short rmd0; /* low address of packet */ + unsigned char rmd1_bits; /* descriptor bits */ + unsigned char rmd1_hadr; /* high address of packet */ + short length; /* This length is 2s complement (negative)! + * Buffer length + */ + unsigned short mblength; /* This is the actual number of bytes received */ }; struct lance_tx_desc { - unsigned short tmd0; /* low address of packet */ - unsigned char tmd1_bits; /* descriptor bits */ - unsigned char tmd1_hadr; /* high address of packet */ - short length; /* Length is 2s complement (negative)! */ - unsigned short misc; + unsigned short tmd0; /* low address of packet */ + unsigned char tmd1_bits; /* descriptor bits */ + unsigned char tmd1_hadr; /* high address of packet */ + short length; /* Length is 2s complement (negative)! */ + unsigned short misc; }; /* The LANCE initialization block, described in databook. */ /* On the Sparc, this block should be on a DMA region */ struct lance_init_block { - unsigned short mode; /* Pre-set mode (reg. 15) */ - unsigned char phys_addr[6]; /* Physical ethernet address */ - unsigned filter[2]; /* Multicast filter. */ - - /* Receive and transmit ring base, along with extra bits. */ - unsigned short rx_ptr; /* receive descriptor addr */ - unsigned short rx_len; /* receive len and high addr */ - unsigned short tx_ptr; /* transmit descriptor addr */ - unsigned short tx_len; /* transmit len and high addr */ - - /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ - struct lance_rx_desc brx_ring[RX_RING_SIZE]; - struct lance_tx_desc btx_ring[TX_RING_SIZE]; - - char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE]; - char pad[2]; /* align rx_buf for copy_and_sum(). */ - char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE]; + unsigned short mode; /* Pre-set mode (reg. 15) */ + unsigned char phys_addr[6]; /* Physical ethernet address */ + unsigned filter[2]; /* Multicast filter. */ + + /* Receive and transmit ring base, along with extra bits. */ + unsigned short rx_ptr; /* receive descriptor addr */ + unsigned short rx_len; /* receive len and high addr */ + unsigned short tx_ptr; /* transmit descriptor addr */ + unsigned short tx_len; /* transmit len and high addr */ + + /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ + struct lance_rx_desc brx_ring[RX_RING_SIZE]; + struct lance_tx_desc btx_ring[TX_RING_SIZE]; + + char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE]; + char pad[2]; /* align rx_buf for copy_and_sum(). */ + char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE]; }; #define LEDMA_REGS 4 @@ -155,11 +155,11 @@ struct lance_init_block { typedef struct LANCEState { VLANClientState *vc; - uint8_t macaddr[6]; /* init mac address */ + uint8_t macaddr[6]; /* init mac address */ uint32_t leptr; uint16_t addr; uint16_t regs[LE_NREGS]; - uint8_t phys[6]; /* mac address */ + uint8_t phys[6]; /* mac address */ int irq; unsigned int rxptr, txptr; uint32_t ledmaregs[LEDMA_REGS]; @@ -192,13 +192,14 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) DPRINTF("read areg = %4.4x\n", s->addr); return s->addr; default: - DPRINTF("read unknown(%d)\n", saddr>>1); + DPRINTF("read unknown(%d)\n", saddr >> 1); break; } return 0; } -static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void lance_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) { LANCEState *s = opaque; uint32_t saddr; @@ -208,7 +209,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val switch (saddr >> 1) { case LE_RDP: DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val); - switch(s->addr) { + switch (s->addr) { case LE_CSR0: if (val & LE_C0_STOP) { s->regs[LE_CSR0] = LE_C0_STOP; @@ -235,8 +236,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val if (val & LE_C0_INIT) { reg |= LE_C0_IDON | LE_C0_INIT; reg &= ~LE_C0_STOP; - } - else if (val & LE_C0_STRT) { + } else if (val & LE_C0_STRT) { reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; reg &= ~LE_C0_STOP; } @@ -262,7 +262,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val s->addr = val; break; default: - DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val); + DPRINTF("write unknown(%d) = %4.4x\n", saddr >> 1, val); break; } lance_send(s); @@ -288,7 +288,7 @@ static int lance_can_receive(void *opaque) return 1; } -static void lance_receive(void *opaque, const uint8_t *buf, int size) +static void lance_receive(void *opaque, const uint8_t * buf, int size) { LANCEState *s = opaque; uint32_t dmaptr = s->leptr + s->ledmaregs[3]; @@ -304,16 +304,21 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size) ib = (void *) iommu_translate(dmaptr); old_rxptr = s->rxptr; - for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); + for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); + i = (i + 1) & RX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t) & ib->brx_ring[i].rmd1_bits, + (void *) &temp8, 1); if (temp8 == (LE_R1_OWN)) { s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; temp16 = size + 4; bswap16s(&temp16); - cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2); - cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size); + cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. + mblength, (void *) &temp16, 2); + cpu_physical_memory_write((uint32_t) & ib->rx_buf[i], buf, + size); temp8 = LE_R1_POK; - cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); + cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. + rmd1_bits, (void *) &temp8, 1); s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; if (s->regs[LE_CSR0] & LE_C0_INEA) pic_set_irq(s->irq, 1); @@ -339,19 +344,25 @@ static void lance_send(void *opaque) ib = (void *) iommu_translate(dmaptr); - DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring); + DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", + dmaptr, ib, &ib->btx_ring); old_txptr = s->txptr; - for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); - if (temp8 == (LE_T1_POK|LE_T1_OWN)) { - cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2); + for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); + i = (i + 1) & TX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].tmd1_bits, + (void *) &temp8, 1); + if (temp8 == (LE_T1_POK | LE_T1_OWN)) { + cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].length, + (void *) &temp16, 2); bswap16s(&temp16); temp16 = (~temp16) + 1; - cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16); + cpu_physical_memory_read((uint32_t) & ib->tx_buf[i], pkt_buf, + temp16); DPRINTF("sending packet, len %d\n", temp16); qemu_send_packet(s->vc, pkt_buf, temp16); temp8 = LE_T1_POK; - cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); + cpu_physical_memory_write((uint32_t) & ib->btx_ring[i]. + tmd1_bits, (void *) &temp8, 1); s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; } @@ -369,7 +380,8 @@ static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) return s->ledmaregs[saddr]; } -static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) { LANCEState *s = opaque; uint32_t saddr; @@ -390,73 +402,73 @@ static CPUWriteMemoryFunc *ledma_mem_write[3] = { ledma_mem_writel, }; -static void lance_save(QEMUFile *f, void *opaque) +static void lance_save(QEMUFile * f, void *opaque) { LANCEState *s = opaque; int i; - + qemu_put_be32s(f, &s->leptr); qemu_put_be16s(f, &s->addr); - for (i = 0; i < LE_NREGS; i ++) + for (i = 0; i < LE_NREGS; i++) qemu_put_be16s(f, &s->regs[i]); qemu_put_buffer(f, s->phys, 6); qemu_put_be32s(f, &s->irq); - for (i = 0; i < LEDMA_REGS; i ++) + for (i = 0; i < LEDMA_REGS; i++) qemu_put_be32s(f, &s->ledmaregs[i]); } -static int lance_load(QEMUFile *f, void *opaque, int version_id) +static int lance_load(QEMUFile * f, void *opaque, int version_id) { LANCEState *s = opaque; int i; - + if (version_id != 1) - return -EINVAL; + return -EINVAL; qemu_get_be32s(f, &s->leptr); qemu_get_be16s(f, &s->addr); - for (i = 0; i < LE_NREGS; i ++) + for (i = 0; i < LE_NREGS; i++) qemu_get_be16s(f, &s->regs[i]); qemu_get_buffer(f, s->phys, 6); qemu_get_be32s(f, &s->irq); - for (i = 0; i < LEDMA_REGS; i ++) + for (i = 0; i < LEDMA_REGS; i++) qemu_get_be32s(f, &s->ledmaregs[i]); return 0; } -void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr) +void lance_init(NICInfo * nd, int irq, uint32_t leaddr, uint32_t ledaddr) { LANCEState *s; int lance_io_memory, ledma_io_memory; s = qemu_mallocz(sizeof(LANCEState)); if (!s) - return; + return; s->irq = irq; - lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); + lance_io_memory = + cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); cpu_register_physical_memory(leaddr, 4, lance_io_memory); - ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); + ledma_io_memory = + cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); memcpy(s->macaddr, nd->macaddr, 6); lance_reset(s); - s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s); + s->vc = + qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, + s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - s->macaddr[0], - s->macaddr[1], - s->macaddr[2], - s->macaddr[3], - s->macaddr[4], - s->macaddr[5]); + "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->macaddr[0], + s->macaddr[1], + s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); register_savevm("lance", leaddr, 1, lance_save, lance_load, s); qemu_register_reset(lance_reset, s); } - -- cgit v1.2.3 From 2a98c1981f643086be6cb2383cd90223ae42c852 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 9 Aug 2006 22:38:19 +0000 Subject: removed tabs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2105 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lance.c | 372 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 186 insertions(+), 186 deletions(-) diff --git a/hw/lance.c b/hw/lance.c index cf02333dd..400cce5fb 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -48,55 +48,55 @@ do { printf("LANCE: " fmt , ##args); } while (0) #define LE_RDP 0 #define LE_RAP 1 -#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ - -#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ -#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ -#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ -#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ -#define LE_C0_MERR 0x0800 /* ME: Memory error */ -#define LE_C0_RINT 0x0400 /* Received interrupt */ -#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ -#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ -#define LE_C0_INTR 0x0080 /* Interrupt or error */ -#define LE_C0_INEA 0x0040 /* Interrupt enable */ -#define LE_C0_RXON 0x0020 /* Receiver on */ -#define LE_C0_TXON 0x0010 /* Transmitter on */ -#define LE_C0_TDMD 0x0008 /* Transmitter demand */ -#define LE_C0_STOP 0x0004 /* Stop the card */ -#define LE_C0_STRT 0x0002 /* Start the card */ -#define LE_C0_INIT 0x0001 /* Init the card */ - -#define LE_C3_BSWP 0x4 /* SWAP */ -#define LE_C3_ACON 0x2 /* ALE Control */ -#define LE_C3_BCON 0x1 /* Byte control */ +#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ + +#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ +#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ +#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ +#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ +#define LE_C0_MERR 0x0800 /* ME: Memory error */ +#define LE_C0_RINT 0x0400 /* Received interrupt */ +#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ +#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ +#define LE_C0_INTR 0x0080 /* Interrupt or error */ +#define LE_C0_INEA 0x0040 /* Interrupt enable */ +#define LE_C0_RXON 0x0020 /* Receiver on */ +#define LE_C0_TXON 0x0010 /* Transmitter on */ +#define LE_C0_TDMD 0x0008 /* Transmitter demand */ +#define LE_C0_STOP 0x0004 /* Stop the card */ +#define LE_C0_STRT 0x0002 /* Start the card */ +#define LE_C0_INIT 0x0001 /* Init the card */ + +#define LE_C3_BSWP 0x4 /* SWAP */ +#define LE_C3_ACON 0x2 /* ALE Control */ +#define LE_C3_BCON 0x1 /* Byte control */ /* Receive message descriptor 1 */ -#define LE_R1_OWN 0x80 /* Who owns the entry */ -#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ -#define LE_R1_FRA 0x20 /* FRA: Frame error */ -#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ -#define LE_R1_CRC 0x08 /* CRC error */ -#define LE_R1_BUF 0x04 /* BUF: Buffer error */ -#define LE_R1_SOP 0x02 /* Start of packet */ -#define LE_R1_EOP 0x01 /* End of packet */ -#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ - -#define LE_T1_OWN 0x80 /* Lance owns the packet */ -#define LE_T1_ERR 0x40 /* Error summary */ -#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ -#define LE_T1_EONE 0x08 /* Error: one retry needed */ -#define LE_T1_EDEF 0x04 /* Error: deferred */ -#define LE_T1_SOP 0x02 /* Start of packet */ -#define LE_T1_EOP 0x01 /* End of packet */ -#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ - -#define LE_T3_BUF 0x8000 /* Buffer error */ -#define LE_T3_UFL 0x4000 /* Error underflow */ -#define LE_T3_LCOL 0x1000 /* Error late collision */ -#define LE_T3_CLOS 0x0800 /* Error carrier loss */ -#define LE_T3_RTY 0x0400 /* Error retry */ -#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ +#define LE_R1_OWN 0x80 /* Who owns the entry */ +#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ +#define LE_R1_FRA 0x20 /* FRA: Frame error */ +#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUF 0x04 /* BUF: Buffer error */ +#define LE_R1_SOP 0x02 /* Start of packet */ +#define LE_R1_EOP 0x01 /* End of packet */ +#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ + +#define LE_T1_OWN 0x80 /* Lance owns the packet */ +#define LE_T1_ERR 0x40 /* Error summary */ +#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ +#define LE_T1_EONE 0x08 /* Error: one retry needed */ +#define LE_T1_EDEF 0x04 /* Error: deferred */ +#define LE_T1_SOP 0x02 /* Start of packet */ +#define LE_T1_EOP 0x01 /* End of packet */ +#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ + +#define LE_T3_BUF 0x8000 /* Buffer error */ +#define LE_T3_UFL 0x4000 /* Error underflow */ +#define LE_T3_LCOL 0x1000 /* Error late collision */ +#define LE_T3_CLOS 0x0800 /* Error carrier loss */ +#define LE_T3_RTY 0x0400 /* Error retry */ +#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ #define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) #define TX_RING_MOD_MASK (TX_RING_SIZE - 1) @@ -111,42 +111,42 @@ do { printf("LANCE: " fmt , ##args); } while (0) #define TX_BUFF_SIZE PKT_BUF_SZ struct lance_rx_desc { - unsigned short rmd0; /* low address of packet */ - unsigned char rmd1_bits; /* descriptor bits */ - unsigned char rmd1_hadr; /* high address of packet */ - short length; /* This length is 2s complement (negative)! - * Buffer length - */ - unsigned short mblength; /* This is the actual number of bytes received */ + unsigned short rmd0; /* low address of packet */ + unsigned char rmd1_bits; /* descriptor bits */ + unsigned char rmd1_hadr; /* high address of packet */ + short length; /* This length is 2s complement (negative)! + * Buffer length + */ + unsigned short mblength; /* This is the actual number of bytes received */ }; struct lance_tx_desc { - unsigned short tmd0; /* low address of packet */ - unsigned char tmd1_bits; /* descriptor bits */ - unsigned char tmd1_hadr; /* high address of packet */ - short length; /* Length is 2s complement (negative)! */ + unsigned short tmd0; /* low address of packet */ + unsigned char tmd1_bits; /* descriptor bits */ + unsigned char tmd1_hadr; /* high address of packet */ + short length; /* Length is 2s complement (negative)! */ unsigned short misc; }; /* The LANCE initialization block, described in databook. */ /* On the Sparc, this block should be on a DMA region */ struct lance_init_block { - unsigned short mode; /* Pre-set mode (reg. 15) */ - unsigned char phys_addr[6]; /* Physical ethernet address */ - unsigned filter[2]; /* Multicast filter. */ + unsigned short mode; /* Pre-set mode (reg. 15) */ + unsigned char phys_addr[6]; /* Physical ethernet address */ + unsigned filter[2]; /* Multicast filter. */ /* Receive and transmit ring base, along with extra bits. */ - unsigned short rx_ptr; /* receive descriptor addr */ - unsigned short rx_len; /* receive len and high addr */ - unsigned short tx_ptr; /* transmit descriptor addr */ - unsigned short tx_len; /* transmit len and high addr */ + unsigned short rx_ptr; /* receive descriptor addr */ + unsigned short rx_len; /* receive len and high addr */ + unsigned short tx_ptr; /* transmit descriptor addr */ + unsigned short tx_len; /* transmit len and high addr */ /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ struct lance_rx_desc brx_ring[RX_RING_SIZE]; struct lance_tx_desc btx_ring[TX_RING_SIZE]; char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE]; - char pad[2]; /* align rx_buf for copy_and_sum(). */ + char pad[2]; /* align rx_buf for copy_and_sum(). */ char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE]; }; @@ -155,11 +155,11 @@ struct lance_init_block { typedef struct LANCEState { VLANClientState *vc; - uint8_t macaddr[6]; /* init mac address */ + uint8_t macaddr[6]; /* init mac address */ uint32_t leptr; uint16_t addr; uint16_t regs[LE_NREGS]; - uint8_t phys[6]; /* mac address */ + uint8_t phys[6]; /* mac address */ int irq; unsigned int rxptr, txptr; uint32_t ledmaregs[LEDMA_REGS]; @@ -186,20 +186,20 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: - DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]); - return s->regs[s->addr]; + DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]); + return s->regs[s->addr]; case LE_RAP: - DPRINTF("read areg = %4.4x\n", s->addr); - return s->addr; + DPRINTF("read areg = %4.4x\n", s->addr); + return s->addr; default: - DPRINTF("read unknown(%d)\n", saddr >> 1); - break; + DPRINTF("read unknown(%d)\n", saddr >> 1); + break; } return 0; } static void lance_mem_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) + uint32_t val) { LANCEState *s = opaque; uint32_t saddr; @@ -208,62 +208,62 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, saddr = addr & LE_MAXREG; switch (saddr >> 1) { case LE_RDP: - DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val); - switch (s->addr) { - case LE_CSR0: - if (val & LE_C0_STOP) { - s->regs[LE_CSR0] = LE_C0_STOP; - break; - } - - reg = s->regs[LE_CSR0]; - - // 1 = clear for some bits - reg &= ~(val & 0x7f00); - - // generated bits - reg &= ~(LE_C0_ERR | LE_C0_INTR); - if (reg & 0x7100) - reg |= LE_C0_ERR; - if (reg & 0x7f00) - reg |= LE_C0_INTR; - - // direct bit - reg &= ~LE_C0_INEA; - reg |= val & LE_C0_INEA; - - // exclusive bits - if (val & LE_C0_INIT) { - reg |= LE_C0_IDON | LE_C0_INIT; - reg &= ~LE_C0_STOP; - } else if (val & LE_C0_STRT) { - reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; - reg &= ~LE_C0_STOP; - } - - s->regs[LE_CSR0] = reg; - break; - case LE_CSR1: - s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); - s->regs[s->addr] = val; - break; - case LE_CSR2: - s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); - s->regs[s->addr] = val; - break; - case LE_CSR3: - s->regs[s->addr] = val; - break; - } - break; + DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val); + switch (s->addr) { + case LE_CSR0: + if (val & LE_C0_STOP) { + s->regs[LE_CSR0] = LE_C0_STOP; + break; + } + + reg = s->regs[LE_CSR0]; + + // 1 = clear for some bits + reg &= ~(val & 0x7f00); + + // generated bits + reg &= ~(LE_C0_ERR | LE_C0_INTR); + if (reg & 0x7100) + reg |= LE_C0_ERR; + if (reg & 0x7f00) + reg |= LE_C0_INTR; + + // direct bit + reg &= ~LE_C0_INEA; + reg |= val & LE_C0_INEA; + + // exclusive bits + if (val & LE_C0_INIT) { + reg |= LE_C0_IDON | LE_C0_INIT; + reg &= ~LE_C0_STOP; + } else if (val & LE_C0_STRT) { + reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; + reg &= ~LE_C0_STOP; + } + + s->regs[LE_CSR0] = reg; + break; + case LE_CSR1: + s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); + s->regs[s->addr] = val; + break; + case LE_CSR2: + s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); + s->regs[s->addr] = val; + break; + case LE_CSR3: + s->regs[s->addr] = val; + break; + } + break; case LE_RAP: - DPRINTF("write areg = %4.4x\n", val); - if (val < LE_NREGS) - s->addr = val; - break; + DPRINTF("write areg = %4.4x\n", val); + if (val < LE_NREGS) + s->addr = val; + break; default: - DPRINTF("write unknown(%d) = %4.4x\n", saddr >> 1, val); - break; + DPRINTF("write unknown(%d) = %4.4x\n", saddr >> 1, val); + break; } lance_send(s); } @@ -299,32 +299,32 @@ static void lance_receive(void *opaque, const uint8_t * buf, int size) DPRINTF("receive size %d\n", size); if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) - return; + return; ib = (void *) iommu_translate(dmaptr); old_rxptr = s->rxptr; for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); - i = (i + 1) & RX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t) & ib->brx_ring[i].rmd1_bits, - (void *) &temp8, 1); - if (temp8 == (LE_R1_OWN)) { - s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; - temp16 = size + 4; - bswap16s(&temp16); - cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. - mblength, (void *) &temp16, 2); - cpu_physical_memory_write((uint32_t) & ib->rx_buf[i], buf, - size); - temp8 = LE_R1_POK; - cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. - rmd1_bits, (void *) &temp8, 1); - s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; - if (s->regs[LE_CSR0] & LE_C0_INEA) - pic_set_irq(s->irq, 1); - DPRINTF("got packet, len %d\n", size); - return; - } + i = (i + 1) & RX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t) & ib->brx_ring[i].rmd1_bits, + (void *) &temp8, 1); + if (temp8 == (LE_R1_OWN)) { + s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; + temp16 = size + 4; + bswap16s(&temp16); + cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. + mblength, (void *) &temp16, 2); + cpu_physical_memory_write((uint32_t) & ib->rx_buf[i], buf, + size); + temp8 = LE_R1_POK; + cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. + rmd1_bits, (void *) &temp8, 1); + s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; + if (s->regs[LE_CSR0] & LE_C0_INEA) + pic_set_irq(s->irq, 1); + DPRINTF("got packet, len %d\n", size); + return; + } } } @@ -340,35 +340,35 @@ static void lance_send(void *opaque) DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]); if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) - return; + return; ib = (void *) iommu_translate(dmaptr); DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", - dmaptr, ib, &ib->btx_ring); + dmaptr, ib, &ib->btx_ring); old_txptr = s->txptr; for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); - i = (i + 1) & TX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].tmd1_bits, - (void *) &temp8, 1); - if (temp8 == (LE_T1_POK | LE_T1_OWN)) { - cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].length, - (void *) &temp16, 2); - bswap16s(&temp16); - temp16 = (~temp16) + 1; - cpu_physical_memory_read((uint32_t) & ib->tx_buf[i], pkt_buf, - temp16); - DPRINTF("sending packet, len %d\n", temp16); - qemu_send_packet(s->vc, pkt_buf, temp16); - temp8 = LE_T1_POK; - cpu_physical_memory_write((uint32_t) & ib->btx_ring[i]. - tmd1_bits, (void *) &temp8, 1); - s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; - s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; - } + i = (i + 1) & TX_RING_MOD_MASK) { + cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].tmd1_bits, + (void *) &temp8, 1); + if (temp8 == (LE_T1_POK | LE_T1_OWN)) { + cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].length, + (void *) &temp16, 2); + bswap16s(&temp16); + temp16 = (~temp16) + 1; + cpu_physical_memory_read((uint32_t) & ib->tx_buf[i], pkt_buf, + temp16); + DPRINTF("sending packet, len %d\n", temp16); + qemu_send_packet(s->vc, pkt_buf, temp16); + temp8 = LE_T1_POK; + cpu_physical_memory_write((uint32_t) & ib->btx_ring[i]. + tmd1_bits, (void *) &temp8, 1); + s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; + s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; + } } if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) - pic_set_irq(s->irq, 1); + pic_set_irq(s->irq, 1); } static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) @@ -381,7 +381,7 @@ static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) } static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) + uint32_t val) { LANCEState *s = opaque; uint32_t saddr; @@ -410,11 +410,11 @@ static void lance_save(QEMUFile * f, void *opaque) qemu_put_be32s(f, &s->leptr); qemu_put_be16s(f, &s->addr); for (i = 0; i < LE_NREGS; i++) - qemu_put_be16s(f, &s->regs[i]); + qemu_put_be16s(f, &s->regs[i]); qemu_put_buffer(f, s->phys, 6); qemu_put_be32s(f, &s->irq); for (i = 0; i < LEDMA_REGS; i++) - qemu_put_be32s(f, &s->ledmaregs[i]); + qemu_put_be32s(f, &s->ledmaregs[i]); } static int lance_load(QEMUFile * f, void *opaque, int version_id) @@ -423,16 +423,16 @@ static int lance_load(QEMUFile * f, void *opaque, int version_id) int i; if (version_id != 1) - return -EINVAL; + return -EINVAL; qemu_get_be32s(f, &s->leptr); qemu_get_be16s(f, &s->addr); for (i = 0; i < LE_NREGS; i++) - qemu_get_be16s(f, &s->regs[i]); + qemu_get_be16s(f, &s->regs[i]); qemu_get_buffer(f, s->phys, 6); qemu_get_be32s(f, &s->irq); for (i = 0; i < LEDMA_REGS; i++) - qemu_get_be32s(f, &s->ledmaregs[i]); + qemu_get_be32s(f, &s->ledmaregs[i]); return 0; } @@ -443,16 +443,16 @@ void lance_init(NICInfo * nd, int irq, uint32_t leaddr, uint32_t ledaddr) s = qemu_mallocz(sizeof(LANCEState)); if (!s) - return; + return; s->irq = irq; lance_io_memory = - cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); + cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); cpu_register_physical_memory(leaddr, 4, lance_io_memory); ledma_io_memory = - cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); + cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); memcpy(s->macaddr, nd->macaddr, 6); @@ -460,14 +460,14 @@ void lance_init(NICInfo * nd, int irq, uint32_t leaddr, uint32_t ledaddr) lance_reset(s); s->vc = - qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, - s); + qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, + s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - s->macaddr[0], - s->macaddr[1], - s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); + "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->macaddr[0], + s->macaddr[1], + s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); register_savevm("lance", leaddr, 1, lance_save, lance_load, s); qemu_register_reset(lance_reset, s); -- cgit v1.2.3 From 4ca9c76f3620dc20e56d9b7027a6f1115ea48eea Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 10 Aug 2006 01:03:35 +0000 Subject: Add SCSI controller class. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2106 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/pci.c b/hw/pci.c index f58f6fd60..85531f72e 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -416,6 +416,7 @@ typedef struct { static pci_class_desc pci_class_descriptions[] = { + { 0x0100, "SCSI controller"}, { 0x0101, "IDE controller"}, { 0x0200, "Ethernet controller"}, { 0x0300, "VGA controller"}, -- cgit v1.2.3 From 4d611c9a2f4c5d9080d8b6a6f0d7431233cd56f9 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 12 Aug 2006 01:04:27 +0000 Subject: SCSI and USB async IO support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2107 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 142 ++++++++++++++++----------- hw/lsi53c895a.c | 80 +++++++++------ hw/scsi-disk.c | 152 ++++++++++++++++++++++------- hw/usb-hid.c | 11 +-- hw/usb-hub.c | 46 ++++----- hw/usb-msd.c | 68 ++++++++++--- hw/usb-ohci.c | 156 +++++++++++++++++++++-------- hw/usb-uhci.c | 244 ++++++++++++++++++++++++++++++++++------------ hw/usb.c | 32 +++--- hw/usb.h | 58 +++++++++-- pc-bios/openbios-esp.diff | 30 ++++++ pc-bios/openbios-sparc32 | Bin 506966 -> 246036 bytes usb-linux.c | 11 +-- vl.h | 9 ++ 14 files changed, 746 insertions(+), 293 deletions(-) create mode 100644 pc-bios/openbios-esp.diff diff --git a/hw/esp.c b/hw/esp.c index cdd062f78..17e70dd03 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -62,6 +62,11 @@ struct ESPState { uint8_t cmdbuf[TI_BUFSZ]; int cmdlen; int do_cmd; + + uint32_t dma_left; + uint8_t async_buf[TARGET_PAGE_SIZE]; + uint32_t async_ptr; + uint32_t async_len; }; #define STAT_DO 0x00 @@ -72,6 +77,8 @@ struct ESPState { #define STAT_MO 0x07 #define STAT_TC 0x10 +#define STAT_PE 0x20 +#define STAT_GE 0x40 #define STAT_IN 0x80 #define INTR_FC 0x08 @@ -195,26 +202,85 @@ static void write_response(ESPState *s) } -static void esp_command_complete(void *opaque, uint32_t tag, int sense) +static void esp_do_dma(ESPState *s) +{ + uint32_t dmaptr, minlen, len, from, to; + int to_device; + dmaptr = iommu_translate(s->espdmaregs[1]); + to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; + from = s->espdmaregs[1]; + minlen = s->dma_left; + to = from + minlen; + dmaptr = iommu_translate(s->espdmaregs[1]); + if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { + len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); + } else { + len = to - from; + } + DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1], len, from, to); + s->espdmaregs[1] += len; + if (s->do_cmd) { + s->ti_size -= len; + DPRINTF("command len %d + %d\n", s->cmdlen, len); + cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); + s->ti_size = 0; + s->cmdlen = 0; + s->do_cmd = 0; + do_cmd(s, s->cmdbuf); + return; + } else { + s->async_len = len; + s->dma_left -= len; + if (to_device) { + s->async_ptr = -1; + cpu_physical_memory_read(dmaptr, s->async_buf, len); + scsi_write_data(s->current_dev, s->async_buf, len); + } else { + s->async_ptr = dmaptr; + scsi_read_data(s->current_dev, s->async_buf, len); + } + } +} + +static void esp_command_complete(void *opaque, uint32_t reason, int sense) { ESPState *s = (ESPState *)opaque; - DPRINTF("SCSI Command complete\n"); - if (s->ti_size != 0) - DPRINTF("SCSI command completed unexpectedly\n"); - s->ti_size = 0; - if (sense) - DPRINTF("Command failed\n"); - s->sense = sense; - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; + s->ti_size -= s->async_len; + s->espdmaregs[1] += s->async_len; + if (s->async_ptr != (uint32_t)-1) { + cpu_physical_memory_write(s->async_ptr, s->async_buf, s->async_len); + } + if (reason == SCSI_REASON_DONE) { + DPRINTF("SCSI Command complete\n"); + if (s->ti_size != 0) + DPRINTF("SCSI command completed unexpectedly\n"); + s->ti_size = 0; + if (sense) + DPRINTF("Command failed\n"); + s->sense = sense; + } else { + DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); + } + if (s->dma_left) { + esp_do_dma(s); + } else { + if (s->ti_size) { + s->rregs[4] |= STAT_IN | STAT_TC; + } else { + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; + } + s->rregs[5] = INTR_BS; + s->rregs[6] = 0; + s->rregs[7] = 0; + s->espdmaregs[0] |= DMA_INTR; + pic_set_irq(s->irq, 1); + } } static void handle_ti(ESPState *s) { - uint32_t dmaptr, dmalen, minlen, len, from, to; - unsigned int i; - int to_device; - uint8_t buf[TARGET_PAGE_SIZE]; + uint32_t dmalen, minlen; dmalen = s->wregs[0] | (s->wregs[1] << 8); if (dmalen==0) { @@ -227,47 +293,9 @@ static void handle_ti(ESPState *s) minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; DPRINTF("Transfer Information len %d\n", minlen); if (s->dma) { - dmaptr = iommu_translate(s->espdmaregs[1]); - /* Check if the transfer writes to to reads from the device. */ - to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; - DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n", - to_device ? 'r': 'w', dmaptr, s->ti_size); - from = s->espdmaregs[1]; - to = from + minlen; - for (i = 0; i < minlen; i += len, from += len) { - dmaptr = iommu_translate(s->espdmaregs[1] + i); - if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { - len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); - } else { - len = to - from; - } - DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); - s->ti_size -= len; - if (s->do_cmd) { - DPRINTF("command len %d + %d\n", s->cmdlen, len); - cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); - s->ti_size = 0; - s->cmdlen = 0; - s->do_cmd = 0; - do_cmd(s, s->cmdbuf); - return; - } else { - if (to_device) { - cpu_physical_memory_read(dmaptr, buf, len); - scsi_write_data(s->current_dev, buf, len); - } else { - scsi_read_data(s->current_dev, buf, len); - cpu_physical_memory_write(dmaptr, buf, len); - } - } - } - if (s->ti_size) { - s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); - } - s->rregs[5] = INTR_BS; - s->rregs[6] = 0; - s->rregs[7] = 0; - s->espdmaregs[0] |= DMA_INTR; + s->dma_left = minlen; + s->rregs[4] &= ~STAT_TC; + esp_do_dma(s); } else if (s->do_cmd) { DPRINTF("command len %d\n", s->cmdlen); s->ti_size = 0; @@ -276,7 +304,6 @@ static void handle_ti(ESPState *s) do_cmd(s, s->cmdbuf); return; } - pic_set_irq(s->irq, 1); } static void esp_reset(void *opaque) @@ -320,8 +347,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) break; case 5: // interrupt - // Clear status bits except TC - s->rregs[4] &= STAT_TC; + // Clear interrupt/error status bits + s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE); pic_set_irq(s->irq, 0); s->espdmaregs[0] &= ~DMA_INTR; break; @@ -342,6 +369,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) case 0: case 1: s->rregs[saddr] = val; + s->rregs[4] &= ~STAT_TC; break; case 2: // FIFO diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 24dff0eff..8f5672534 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -152,6 +152,9 @@ do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) /* The HBA is ID 7, so for simplicitly limit to 7 devices. */ #define LSI_MAX_DEVS 7 +/* Size of internal DMA buffer for async IO requests. */ +#define LSI_DMA_BLOCK_SIZE 0x10000 + typedef struct { PCIDevice pci_dev; int mmio_io_addr; @@ -162,7 +165,9 @@ typedef struct { int carry; /* ??? Should this be an a visible register somewhere? */ int sense; uint8_t msg; - /* Nonzero if a Wait Reselect instruction has been issued. */ + /* 0 if SCRIPTS are running or stopped. + * 1 if a Wait Reselect instruction has been issued. + * 2 if a DMA operation is in progress. */ int waiting; SCSIDevice *scsi_dev[LSI_MAX_DEVS]; SCSIDevice *current_dev; @@ -226,6 +231,7 @@ typedef struct { uint32_t csbc; uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ + uint8_t dma_buf[LSI_DMA_BLOCK_SIZE]; /* Script ram is stored as 32-bit words in host byteorder. */ uint32_t script_ram[2048]; } LSIState; @@ -295,6 +301,7 @@ static void lsi_soft_reset(LSIState *s) static uint8_t lsi_reg_readb(LSIState *s, int offset); static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); +static void lsi_execute_script(LSIState *s); static inline uint32_t read_dword(LSIState *s, uint32_t addr) { @@ -402,21 +409,20 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase) lsi_set_phase(s, new_phase); } +/* Initiate a SCSI layer data transfer. */ static void lsi_do_dma(LSIState *s, int out) { - uint8_t buf[TARGET_PAGE_SIZE]; - uint32_t addr; uint32_t count; - int n; count = s->dbc; - addr = s->dnad; - DPRINTF("DMA %s addr=0x%08x len=%d avail=%d\n", out ? "out" : "in", + if (count > LSI_DMA_BLOCK_SIZE) + count = LSI_DMA_BLOCK_SIZE; + DPRINTF("DMA addr=0x%08x len=%d avail=%d\n", addr, count, s->data_len); /* ??? Too long transfers are truncated. Don't know if this is the correct behavior. */ if (count > s->data_len) { - /* If the DMA length is greater then the device data length then + /* If the DMA length is greater than the device data length then a phase mismatch will occur. */ count = s->data_len; s->dbc = count; @@ -426,20 +432,47 @@ static void lsi_do_dma(LSIState *s, int out) s->csbc += count; /* ??? Set SFBR to first data byte. */ - while (count) { - n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count; - if (out) { - cpu_physical_memory_read(addr, buf, n); - scsi_write_data(s->current_dev, buf, n); - } else { - scsi_read_data(s->current_dev, buf, n); - cpu_physical_memory_write(addr, buf, n); - } - addr += n; - count -= n; + if ((s->sstat1 & PHASE_MASK) == PHASE_DO) { + cpu_physical_memory_read(s->dnad, s->dma_buf, count); + scsi_write_data(s->current_dev, s->dma_buf, count); + } else { + scsi_read_data(s->current_dev, s->dma_buf, count); } + /* If the DMA did not complete then suspend execution. */ + if (s->dbc) + s->waiting = 2; } +/* Callback to indicate that the SCSI layer has completed a transfer. */ +static void lsi_command_complete(void *opaque, uint32_t reason, int sense) +{ + LSIState *s = (LSIState *)opaque; + uint32_t count; + int out; + + out = ((s->sstat1 & PHASE_MASK) == PHASE_DO); + count = s->dbc; + if (count > LSI_DMA_BLOCK_SIZE) + count = LSI_DMA_BLOCK_SIZE; + if (!out) + cpu_physical_memory_write(s->dnad, s->dma_buf, count); + s->dnad += count; + s->dbc -= count; + + if (reason == SCSI_REASON_DONE) { + DPRINTF("Command complete sense=%d\n", sense); + s->sense = sense; + lsi_set_phase(s, PHASE_ST); + } + + if (s->dbc) { + lsi_do_dma(s, out); + } else if (s->waiting == 2) { + /* Restart SCRIPTS execution. */ + s->waiting = 0; + lsi_execute_script(s); + } +} static void lsi_do_command(LSIState *s) { @@ -461,15 +494,6 @@ static void lsi_do_command(LSIState *s) } } -static void lsi_command_complete(void *opaque, uint32_t tag, int sense) -{ - LSIState *s = (LSIState *)opaque; - - DPRINTF("Command complete sense=%d\n", sense); - s->sense = sense; - lsi_set_phase(s, PHASE_ST); -} - static void lsi_do_status(LSIState *s) { DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); @@ -1134,7 +1158,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) s->istat0 &= ~LSI_ISTAT0_INTF; lsi_update_irq(s); } - if (s->waiting && val & LSI_ISTAT0_SIGP) { + if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) { DPRINTF("Woken by SIGP\n"); s->waiting = 0; s->dsp = s->dnad; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 3419c8e2d..a2f299e95 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -25,6 +25,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) #define SENSE_NO_SENSE 0 #define SENSE_NOT_READY 2 +#define SENSE_HARDWARE_ERROR 4 #define SENSE_ILLEGAL_REQUEST 5 struct SCSIDevice @@ -46,7 +47,13 @@ struct SCSIDevice int buf_pos; int buf_len; int sense; + BlockDriverAIOCB *aiocb; + /* Data still to be transfered after this request completes. */ + uint8_t *aiodata; + uint32_t aiolen; char buf[512]; + /* Completion functions may be called from either scsi_{read,write}_data + or from the AIO completion routines. */ scsi_completionfn completion; void *opaque; }; @@ -54,10 +61,49 @@ struct SCSIDevice static void scsi_command_complete(SCSIDevice *s, int sense) { s->sense = sense; - s->completion(s->opaque, s->tag, sense); + s->completion(s->opaque, SCSI_REASON_DONE, sense); } -/* Read data from a scsi device. Returns nonzero on failure. */ +static void scsi_transfer_complete(SCSIDevice *s) +{ + s->completion(s->opaque, SCSI_REASON_DATA, 0); + s->aiocb = NULL; +} + +static void scsi_read_complete(void * opaque, int ret) +{ + SCSIDevice *s = (SCSIDevice *)opaque; + + if (ret) { + DPRINTF("IO error\n"); + scsi_command_complete(s, SENSE_HARDWARE_ERROR); + } + + if (s->aiolen) { + /* Read the remaining data. Full and partial sectors are transferred + separately. */ + scsi_read_data(s, s->aiodata, s->aiolen); + } else { + if (s->buf_len == 0 && s->sector_count == 0) + scsi_command_complete(s, SENSE_NO_SENSE); + else + scsi_transfer_complete(s); + } +} + +/* Cancel a pending data transfer. */ +void scsi_cancel_io(SCSIDevice *s) +{ + if (!s->aiocb) { + BADF("Cancel with no pending IO\n"); + return; + } + bdrv_aio_cancel(s->aiocb); + s->aiocb = NULL; +} + +/* Read data from a scsi device. Returns nonzero on failure. + The transfer may complete asynchronously. */ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) { uint32_t n; @@ -84,14 +130,19 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) n = s->sector_count; if (n != 0) { - bdrv_read(s->bdrv, s->sector, data, n); - data += n * 512; - len -= n * 512; + s->aiolen = len - n * 512; + s->aiodata = data + n * 512; + s->aiocb = bdrv_aio_read(s->bdrv, s->sector, data, n, + scsi_read_complete, s); + if (s->aiocb == NULL) + scsi_command_complete(s, SENSE_HARDWARE_ERROR); s->sector += n; s->sector_count -= n; + return 0; } if (len && s->sector_count) { + /* TODO: Make this use AIO. */ bdrv_read(s->bdrv, s->sector, s->buf, 1); s->sector++; s->sector_count--; @@ -106,11 +157,53 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) if (s->buf_len == 0 && s->sector_count == 0) scsi_command_complete(s, SENSE_NO_SENSE); + else + scsi_transfer_complete(s); return 0; } -/* Read data to a scsi device. Returns nonzero on failure. */ +static void scsi_write_complete(void * opaque, int ret) +{ + SCSIDevice *s = (SCSIDevice *)opaque; + + if (ret) { + fprintf(stderr, "scsi-disc: IO write error\n"); + exit(1); + } + + if (s->sector_count == 0) + scsi_command_complete(s, SENSE_NO_SENSE); + else + scsi_transfer_complete(s); +} + +static uint32_t scsi_write_partial_sector(SCSIDevice *s, uint8_t *data, + uint32_t len) +{ + int n; + + n = 512 - s->buf_len; + if (n > len) + n = len; + + memcpy(s->buf + s->buf_len, data, n); + data += n; + s->buf_len += n; + len -= n; + if (s->buf_len == 512) { + /* A full sector has been accumulated. Write it to disk. */ + /* TODO: Make this use async IO. */ + bdrv_write(s->bdrv, s->sector, s->buf, 1); + s->buf_len = 0; + s->sector++; + s->sector_count--; + } + return n; +} + +/* Write data to a scsi device. Returns nonzero on failure. + The transfer may complete asynchronously. */ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) { uint32_t n; @@ -125,48 +218,39 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) return 1; if (s->buf_len != 0 || len < 512) { - n = 512 - s->buf_len; - if (n > len) - n = len; - - memcpy(s->buf + s->buf_len, data, n); - data += n; - s->buf_len += n; + n = scsi_write_partial_sector(s, data, len); len -= n; - if (s->buf_len == 512) { - /* A full sector has been accumulated. Write it to disk. */ - bdrv_write(s->bdrv, s->sector, s->buf, 1); - s->buf_len = 0; - s->sector++; - s->sector_count--; - } + data += n; } n = len / 512; if (n > s->sector_count) - n = s->sector_count; + return 1; if (n != 0) { - bdrv_write(s->bdrv, s->sector, data, n); + s->aiocb = bdrv_aio_write(s->bdrv, s->sector, data, n, + scsi_write_complete, s); + if (s->aiocb == NULL) + scsi_command_complete(s, SENSE_HARDWARE_ERROR); data += n * 512; len -= n * 512; s->sector += n; s->sector_count -= n; } - if (len >= 512) - return 1; - - if (len && s->sector_count) { - /* Recurse to complete the partial write. */ - return scsi_write_data(s, data, len); + if (len) { + if (s->sector_count == 0) + return 1; + /* Complete a partial write. */ + scsi_write_partial_sector(s, data, len); + } + if (n == 0) { + /* Transfer completes immediately. */ + if (s->sector_count == 0) + scsi_command_complete(s, SENSE_NO_SENSE); + else + scsi_transfer_complete(s); } - - if (len != 0) - return 1; - - if (s->sector_count == 0) - scsi_command_complete(s, SENSE_NO_SENSE); return 0; } diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 8fc0b744b..095fcb3e6 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -474,19 +474,18 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, return ret; } -static int usb_mouse_handle_data(USBDevice *dev, int pid, - uint8_t devep, uint8_t *data, int len) +static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) { USBMouseState *s = (USBMouseState *)dev; int ret = 0; - switch(pid) { + switch(p->pid) { case USB_TOKEN_IN: - if (devep == 1) { + if (p->devep == 1) { if (s->kind == USB_MOUSE) - ret = usb_mouse_poll(s, data, len); + ret = usb_mouse_poll(s, p->data, p->len); else if (s->kind == USB_TABLET) - ret = usb_tablet_poll(s, data, len); + ret = usb_tablet_poll(s, p->data, p->len); } else { goto fail; } diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 8350931be..651dac210 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -180,8 +180,7 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) port->wPortStatus &= ~PORT_STAT_LOW_SPEED; port->port.dev = dev; /* send the attach message */ - dev->handle_packet(dev, - USB_MSG_ATTACH, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_ATTACH); } else { dev = port->port.dev; if (dev) { @@ -192,8 +191,7 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) port->wPortChange |= PORT_STAT_C_ENABLE; } /* send the detach message */ - dev->handle_packet(dev, - USB_MSG_DETACH, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_DETACH); port->port.dev = NULL; } } @@ -349,8 +347,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, break; case PORT_RESET: if (dev) { - dev->handle_packet(dev, - USB_MSG_RESET, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_RESET); port->wPortChange |= PORT_STAT_C_RESET; /* set enable bit */ port->wPortStatus |= PORT_STAT_ENABLE; @@ -434,22 +431,21 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, return ret; } -static int usb_hub_handle_data(USBDevice *dev, int pid, - uint8_t devep, uint8_t *data, int len) +static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) { USBHubState *s = (USBHubState *)dev; int ret; - switch(pid) { + switch(p->pid) { case USB_TOKEN_IN: - if (devep == 1) { + if (p->devep == 1) { USBHubPort *port; unsigned int status; int i, n; n = (s->nb_ports + 1 + 7) / 8; - if (len == 1) { /* FreeBSD workaround */ + if (p->len == 1) { /* FreeBSD workaround */ n = 1; - } else if (n > len) { + } else if (n > p->len) { return USB_RET_BABBLE; } status = 0; @@ -460,7 +456,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, } if (status != 0) { for(i = 0; i < n; i++) { - data[i] = status >> (8 * i); + p->data[i] = status >> (8 * i); } ret = n; } else { @@ -479,9 +475,7 @@ static int usb_hub_handle_data(USBDevice *dev, int pid, return ret; } -static int usb_hub_broadcast_packet(USBHubState *s, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len) +static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p) { USBHubPort *port; USBDevice *dev; @@ -491,9 +485,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, int pid, port = &s->ports[i]; dev = port->port.dev; if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { - ret = dev->handle_packet(dev, pid, - devaddr, devep, - data, len); + ret = dev->handle_packet(dev, p); if (ret != USB_RET_NODEV) { return ret; } @@ -502,9 +494,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, int pid, return USB_RET_NODEV; } -static int usb_hub_handle_packet(USBDevice *dev, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len) +static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p) { USBHubState *s = (USBHubState *)dev; @@ -513,14 +503,14 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, #endif if (dev->state == USB_STATE_DEFAULT && dev->addr != 0 && - devaddr != dev->addr && - (pid == USB_TOKEN_SETUP || - pid == USB_TOKEN_OUT || - pid == USB_TOKEN_IN)) { + p->devaddr != dev->addr && + (p->pid == USB_TOKEN_SETUP || + p->pid == USB_TOKEN_OUT || + p->pid == USB_TOKEN_IN)) { /* broadcast the packet to the devices */ - return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len); + return usb_hub_broadcast_packet(s, p); } - return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); + return usb_generic_handle_packet(dev, p); } static void usb_hub_handle_destroy(USBDevice *dev) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index ff2047d4b..7d1f35d06 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -33,9 +33,12 @@ typedef struct { USBDevice dev; enum USBMSDMode mode; uint32_t data_len; + uint32_t transfer_len; uint32_t tag; SCSIDevice *scsi_dev; int result; + /* For async completion. */ + USBPacket *packet; } MSDState; static const uint8_t qemu_msd_dev_descriptor[] = { @@ -103,13 +106,27 @@ static const uint8_t qemu_msd_config_descriptor[] = { 0x00 /* u8 ep_bInterval; */ }; -static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail) +static void usb_msd_command_complete(void *opaque, uint32_t reason, int fail) { MSDState *s = (MSDState *)opaque; - - DPRINTF("Command complete\n"); - s->result = fail; - s->mode = USB_MSDM_CSW; + USBPacket *p; + + s->data_len -= s->transfer_len; + s->transfer_len = 0; + if (reason == SCSI_REASON_DONE) { + DPRINTF("Command complete %d\n", fail); + s->result = fail; + s->mode = USB_MSDM_CSW; + } + if (s->packet) { + /* Set s->packet to NULL before calling usb_packet_complete because + annother request may be issues before usb_packet_complete returns. + */ + DPRINTF("Packet complete %p\n", p); + p = s->packet; + s->packet = NULL; + usb_packet_complete(p); + } } static void usb_msd_handle_reset(USBDevice *dev) @@ -250,15 +267,24 @@ struct usb_msd_csw { uint8_t status; }; -static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, - uint8_t *data, int len) +static void usb_msd_cancel_io(USBPacket *p, void *opaque) +{ + MSDState *s = opaque; + scsi_cancel_io(s->scsi_dev); + s->packet = NULL; +} + +static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) { MSDState *s = (MSDState *)dev; int ret = 0; struct usb_msd_cbw cbw; struct usb_msd_csw csw; + uint8_t devep = p->devep; + uint8_t *data = p->data; + int len = p->len; - switch (pid) { + switch (p->pid) { case USB_TOKEN_OUT: if (devep != 2) goto fail; @@ -300,13 +326,18 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, if (len > s->data_len) goto fail; + s->transfer_len = len; if (scsi_write_data(s->scsi_dev, data, len)) goto fail; - s->data_len -= len; - if (s->data_len == 0) - s->mode = USB_MSDM_CSW; - ret = len; + if (s->transfer_len == 0) { + ret = len; + } else { + DPRINTF("Deferring packet %p\n", p); + usb_defer_packet(p, usb_msd_cancel_io, s); + s->packet = p; + ret = USB_RET_ASYNC; + } break; default: @@ -340,13 +371,18 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, if (len > s->data_len) len = s->data_len; + s->transfer_len = len; if (scsi_read_data(s->scsi_dev, data, len)) goto fail; - s->data_len -= len; - if (s->data_len == 0) - s->mode = USB_MSDM_CSW; - ret = len; + if (s->transfer_len == 0) { + ret = len; + } else { + DPRINTF("Deferring packet %p\n", p); + usb_defer_packet(p, usb_msd_cancel_io, s); + s->packet = p; + ret = USB_RET_ASYNC; + } break; default: diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index e87d9da70..de113e9a3 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -89,6 +89,14 @@ typedef struct { uint32_t rhdesc_a, rhdesc_b; uint32_t rhstatus; OHCIPort rhport[OHCI_MAX_PORTS]; + + /* Active packets. */ + uint32_t old_ctl; + USBPacket usb_packet; + uint8_t usb_buf[8192]; + uint32_t async_td; + int async_complete; + } OHCIState; /* Host Controller Communications Area */ @@ -288,8 +296,7 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) port->ctrl &= ~OHCI_PORT_LSDA; port->port.dev = dev; /* send the attach message */ - dev->handle_packet(dev, - USB_MSG_ATTACH, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_ATTACH); dprintf("usb-ohci: Attached port %d\n", port1->index); } else { /* set connect status */ @@ -305,8 +312,7 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) dev = port->port.dev; if (dev) { /* send the detach message */ - dev->handle_packet(dev, - USB_MSG_DETACH, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_DETACH); } port->port.dev = NULL; dprintf("usb-ohci: Detached port %d\n", port1->index); @@ -323,6 +329,7 @@ static void ohci_reset(OHCIState *ohci) int i; ohci->ctl = 0; + ohci->old_ctl = 0; ohci->status = 0; ohci->intr_status = 0; ohci->intr = OHCI_INTR_MIE; @@ -356,6 +363,10 @@ static void ohci_reset(OHCIState *ohci) if (port->port.dev) ohci_attach(&port->port, port->port.dev); } + if (ohci->async_td) { + usb_cancel_packet(&ohci->usb_packet); + ohci->async_td = 0; + } dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); } @@ -423,6 +434,18 @@ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) cpu_physical_memory_rw(ptr, buf, len - n, write); } +static void ohci_process_lists(OHCIState *ohci); + +static void ohci_async_complete_packet(USBPacket * packet, void *opaque) +{ + OHCIState *ohci = opaque; +#ifdef DEBUG_PACKET + dprintf("Async packet complete\n"); +#endif + ohci->async_complete = 1; + ohci_process_lists(ohci); +} + /* Service a transport descriptor. Returns nonzero to terminate processing of this endpoint. */ @@ -430,7 +453,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) { int dir; size_t len = 0; - uint8_t buf[8192]; char *str = NULL; int pid; int ret; @@ -439,8 +461,17 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) struct ohci_td td; uint32_t addr; int flag_r; + int completion; addr = ed->head & OHCI_DPTR_MASK; + /* See if this TD has already been submitted to the device. */ + completion = (addr == ohci->async_td); + if (completion && !ohci->async_complete) { +#ifdef DEBUG_PACKET + dprintf("Skipping async TD\n"); +#endif + return 1; + } if (!ohci_read_td(addr, &td)) { fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); return 0; @@ -481,8 +512,8 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) len = (td.be - td.cbp) + 1; } - if (len && dir != OHCI_TD_DIR_IN) { - ohci_copy_td(&td, buf, len, 0); + if (len && dir != OHCI_TD_DIR_IN && !completion) { + ohci_copy_td(&td, ohci->usb_buf, len, 0); } } @@ -494,31 +525,58 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) if (len >= 0 && dir != OHCI_TD_DIR_IN) { dprintf(" data:"); for (i = 0; i < len; i++) - printf(" %.2x", buf[i]); + printf(" %.2x", ohci->usb_buf[i]); dprintf("\n"); } #endif - ret = USB_RET_NODEV; - for (i = 0; i < ohci->num_ports; i++) { - dev = ohci->rhport[i].port.dev; - if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) - continue; - - ret = dev->handle_packet(dev, pid, OHCI_BM(ed->flags, ED_FA), - OHCI_BM(ed->flags, ED_EN), buf, len); - if (ret != USB_RET_NODEV) - break; - } + if (completion) { + ret = ohci->usb_packet.len; + ohci->async_td = 0; + ohci->async_complete = 0; + } else { + ret = USB_RET_NODEV; + for (i = 0; i < ohci->num_ports; i++) { + dev = ohci->rhport[i].port.dev; + if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) + continue; + + if (ohci->async_td) { + /* ??? The hardware should allow one active packet per + endpoint. We only allow one active packet per controller. + This should be sufficient as long as devices respond in a + timely manner. + */ #ifdef DEBUG_PACKET - dprintf("ret=%d\n", ret); + dprintf("Too many pending packets\n"); #endif + return 1; + } + ohci->usb_packet.pid = pid; + ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA); + ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN); + ohci->usb_packet.data = ohci->usb_buf; + ohci->usb_packet.len = len; + ohci->usb_packet.complete_cb = ohci_async_complete_packet; + ohci->usb_packet.complete_opaque = ohci; + ret = dev->handle_packet(dev, &ohci->usb_packet); + if (ret != USB_RET_NODEV) + break; + } +#ifdef DEBUG_PACKET + dprintf("ret=%d\n", ret); +#endif + if (ret == USB_RET_ASYNC) { + ohci->async_td = addr; + return 1; + } + } if (ret >= 0) { if (dir == OHCI_TD_DIR_IN) { - ohci_copy_td(&td, buf, ret, 1); + ohci_copy_td(&td, ohci->usb_buf, ret, 1); #ifdef DEBUG_PACKET dprintf(" data:"); for (i = 0; i < ret; i++) - printf(" %.2x", buf[i]); + printf(" %.2x", ohci->usb_buf[i]); dprintf("\n"); #endif } else { @@ -608,8 +666,16 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) next_ed = ed.next & OHCI_DPTR_MASK; - if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) + if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) { + uint32_t addr; + /* Cancel pending packets for ED that have been paused. */ + addr = ed.head & OHCI_DPTR_MASK; + if (ohci->async_td && addr == ohci->async_td) { + usb_cancel_packet(&ohci->usb_packet); + ohci->async_td = 0; + } continue; + } /* Skip isochronous endpoints. */ if (ed.flags & OHCI_ED_F) @@ -646,6 +712,26 @@ static void ohci_sof(OHCIState *ohci) ohci_set_interrupt(ohci, OHCI_INTR_SF); } +/* Process Control and Bulk lists. */ +static void ohci_process_lists(OHCIState *ohci) +{ + if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { + if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) + dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); + if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { + ohci->ctrl_cur = 0; + ohci->status &= ~OHCI_STATUS_CLF; + } + } + + if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { + if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { + ohci->bulk_cur = 0; + ohci->status &= ~OHCI_STATUS_BLF; + } + } +} + /* Do frame processing on frame boundary */ static void ohci_frame_boundary(void *opaque) { @@ -661,21 +747,15 @@ static void ohci_frame_boundary(void *opaque) n = ohci->frame_number & 0x1f; ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n])); } - if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { - if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) - dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); - if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { - ohci->ctrl_cur = 0; - ohci->status &= ~OHCI_STATUS_CLF; - } - } - if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { - if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { - ohci->bulk_cur = 0; - ohci->status &= ~OHCI_STATUS_BLF; - } + /* Cancel all pending packets if either of the lists has been disabled. */ + if (ohci->async_td && + ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { + usb_cancel_packet(&ohci->usb_packet); + ohci->async_td = 0; } + ohci->old_ctl = ohci->ctl; + ohci_process_lists(ohci); /* Frame boundary, so do EOF stuf here */ ohci->frt = ohci->fit; @@ -907,8 +987,7 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { dprintf("usb-ohci: port %d: RESET\n", portnum); - port->port.dev->handle_packet(port->port.dev, USB_MSG_RESET, - 0, 0, NULL, 0); + usb_send_msg(port->port.dev, USB_MSG_RESET); port->ctrl &= ~OHCI_PORT_PRS; /* ??? Should this also set OHCI_PORT_PESC. */ port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; @@ -1186,5 +1265,6 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); } + ohci->async_td = 0; ohci_reset(ohci); } diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 1a6e0130f..29809f96b 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -76,6 +76,18 @@ typedef struct UHCIState { uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ QEMUTimer *frame_timer; UHCIPort ports[NB_PORTS]; + + /* Interrupts that should be raised at the end of the current frame. */ + uint32_t pending_int_mask; + /* For simplicity of implementation we only allow a single pending USB + request. This means all usb traffic on this controller is effectively + suspended until that transfer completes. When the transfer completes + the next transfer from that queue will be processed. However + other queues will not be processed until the next frame. The solution + is to allow multiple pending requests. */ + uint32_t async_qh; + USBPacket usb_packet; + uint8_t usb_buf[1280]; } UHCIState; typedef struct UHCI_TD { @@ -188,8 +200,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) port = &s->ports[i]; dev = port->port.dev; if (dev) { - dev->handle_packet(dev, - USB_MSG_RESET, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_RESET); } } uhci_reset(s); @@ -232,8 +243,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) /* port reset */ if ( (val & UHCI_PORT_RESET) && !(port->ctrl & UHCI_PORT_RESET) ) { - dev->handle_packet(dev, - USB_MSG_RESET, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_RESET); } } port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb); @@ -336,8 +346,7 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) port->ctrl &= ~UHCI_PORT_LSDA; port->port.dev = dev; /* send the attach message */ - dev->handle_packet(dev, - USB_MSG_ATTACH, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_ATTACH); } else { /* set connect status */ if (port->ctrl & UHCI_PORT_CCS) { @@ -352,16 +361,13 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) dev = port->port.dev; if (dev) { /* send the detach message */ - dev->handle_packet(dev, - USB_MSG_DETACH, 0, 0, NULL, 0); + usb_send_msg(dev, USB_MSG_DETACH); } port->port.dev = NULL; } } -static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len) +static int uhci_broadcast_packet(UHCIState *s, USBPacket *p) { UHCIPort *port; USBDevice *dev; @@ -370,18 +376,18 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, #ifdef DEBUG_PACKET { const char *pidstr; - switch(pid) { + switch(p->pid) { case USB_TOKEN_SETUP: pidstr = "SETUP"; break; case USB_TOKEN_IN: pidstr = "IN"; break; case USB_TOKEN_OUT: pidstr = "OUT"; break; default: pidstr = "?"; break; } printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n", - s->frnum, pidstr, devaddr, devep, len); - if (pid != USB_TOKEN_IN) { + s->frnum, pidstr, p->devaddr, p->devep, p->len); + if (p->pid != USB_TOKEN_IN) { printf(" data_out="); - for(i = 0; i < len; i++) { - printf(" %02x", data[i]); + for(i = 0; i < p->len; i++) { + printf(" %02x", p->data[i]); } printf("\n"); } @@ -391,17 +397,17 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, port = &s->ports[i]; dev = port->port.dev; if (dev && (port->ctrl & UHCI_PORT_EN)) { - ret = dev->handle_packet(dev, pid, - devaddr, devep, - data, len); + ret = dev->handle_packet(dev, p); if (ret != USB_RET_NODEV) { #ifdef DEBUG_PACKET - { + if (ret == USB_RET_ASYNC) { + printf("usb-uhci: Async packet\n"); + } else { printf(" ret=%d ", ret); - if (pid == USB_TOKEN_IN && ret > 0) { + if (p->pid == USB_TOKEN_IN && ret > 0) { printf("data_in="); for(i = 0; i < ret; i++) { - printf(" %02x", data[i]); + printf(" %02x", p->data[i]); } } printf("\n"); @@ -414,6 +420,8 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, return USB_RET_NODEV; } +static void uhci_async_complete_packet(USBPacket * packet, void *opaque); + /* return -1 if fatal error (frame must be stopped) 0 if TD successful 1 if TD unsuccessful or inactive @@ -421,9 +429,9 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) { uint8_t pid; - uint8_t buf[1280]; int len, max_len, err, ret; + /* ??? This is wrong for async completion. */ if (td->ctrl & TD_CTRL_IOC) { *int_mask |= 0x01; } @@ -434,21 +442,8 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) /* TD is active */ max_len = ((td->token >> 21) + 1) & 0x7ff; pid = td->token & 0xff; - switch(pid) { - case USB_TOKEN_OUT: - case USB_TOKEN_SETUP: - cpu_physical_memory_read(td->buffer, buf, max_len); - ret = uhci_broadcast_packet(s, pid, - (td->token >> 8) & 0x7f, - (td->token >> 15) & 0xf, - buf, max_len); - len = max_len; - break; - case USB_TOKEN_IN: - ret = uhci_broadcast_packet(s, pid, - (td->token >> 8) & 0x7f, - (td->token >> 15) & 0xf, - buf, max_len); + if (s->async_qh) { + ret = s->usb_packet.len; if (ret >= 0) { len = ret; if (len > max_len) { @@ -457,17 +452,52 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) } if (len > 0) { /* write the data back */ - cpu_physical_memory_write(td->buffer, buf, len); + cpu_physical_memory_write(td->buffer, s->usb_buf, len); } } else { len = 0; } - break; - default: - /* invalid pid : frame interrupted */ - s->status |= UHCI_STS_HCPERR; - uhci_update_irq(s); - return -1; + s->async_qh = 0; + } else { + s->usb_packet.pid = pid; + s->usb_packet.devaddr = (td->token >> 8) & 0x7f; + s->usb_packet.devep = (td->token >> 15) & 0xf; + s->usb_packet.data = s->usb_buf; + s->usb_packet.len = max_len; + s->usb_packet.complete_cb = uhci_async_complete_packet; + s->usb_packet.complete_opaque = s; + switch(pid) { + case USB_TOKEN_OUT: + case USB_TOKEN_SETUP: + cpu_physical_memory_read(td->buffer, s->usb_buf, max_len); + ret = uhci_broadcast_packet(s, &s->usb_packet); + len = max_len; + break; + case USB_TOKEN_IN: + ret = uhci_broadcast_packet(s, &s->usb_packet); + if (ret >= 0) { + len = ret; + if (len > max_len) { + len = max_len; + ret = USB_RET_BABBLE; + } + if (len > 0) { + /* write the data back */ + cpu_physical_memory_write(td->buffer, s->usb_buf, len); + } + } else { + len = 0; + } + break; + default: + /* invalid pid : frame interrupted */ + s->status |= UHCI_STS_HCPERR; + uhci_update_irq(s); + return -1; + } + } + if (ret == USB_RET_ASYNC) { + return 2; } if (td->ctrl & TD_CTRL_IOS) td->ctrl &= ~TD_CTRL_ACTIVE; @@ -520,6 +550,61 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) } } +static void uhci_async_complete_packet(USBPacket * packet, void *opaque) +{ + UHCIState *s = opaque; + UHCI_QH qh; + UHCI_TD td; + uint32_t link; + uint32_t old_td_ctrl; + uint32_t val; + int ret; + + link = s->async_qh; + if (!link) { + /* This should never happen. It means a TD somehow got removed + without cancelling the associated async IO request. */ + return; + } + cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); + le32_to_cpus(&qh.link); + le32_to_cpus(&qh.el_link); + /* Re-process the queue containing the async packet. */ + while (1) { + cpu_physical_memory_read(qh.el_link & ~0xf, + (uint8_t *)&td, sizeof(td)); + le32_to_cpus(&td.link); + le32_to_cpus(&td.ctrl); + le32_to_cpus(&td.token); + le32_to_cpus(&td.buffer); + old_td_ctrl = td.ctrl; + ret = uhci_handle_td(s, &td, &s->pending_int_mask); + /* update the status bits of the TD */ + if (old_td_ctrl != td.ctrl) { + val = cpu_to_le32(td.ctrl); + cpu_physical_memory_write((qh.el_link & ~0xf) + 4, + (const uint8_t *)&val, + sizeof(val)); + } + if (ret < 0) + break; /* interrupted frame */ + if (ret == 2) { + s->async_qh = link; + break; + } else if (ret == 0) { + /* update qh element link */ + qh.el_link = td.link; + val = cpu_to_le32(qh.el_link); + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, + sizeof(val)); + if (!(qh.el_link & 4)) + break; + } + break; + } +} + static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; @@ -528,6 +613,7 @@ static void uhci_frame_timer(void *opaque) int int_mask, cnt, ret; UHCI_TD td; UHCI_QH qh; + uint32_t old_async_qh; if (!(s->cmd & UHCI_CMD_RS)) { qemu_del_timer(s->frame_timer); @@ -535,6 +621,14 @@ static void uhci_frame_timer(void *opaque) s->status |= UHCI_STS_HCHALTED; return; } + /* Complete the previous frame. */ + s->frnum = (s->frnum + 1) & 0x7ff; + if (s->pending_int_mask) { + s->status2 |= s->pending_int_mask; + s->status |= UHCI_STS_USBINT; + uhci_update_irq(s); + } + old_async_qh = s->async_qh; frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); le32_to_cpus(&link); @@ -546,6 +640,12 @@ static void uhci_frame_timer(void *opaque) /* valid frame */ if (link & 2) { /* QH */ + if (link == s->async_qh) { + /* We've found a previously issues packet. + Nothing else to do. */ + old_async_qh = 0; + break; + } cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); le32_to_cpus(&qh.link); le32_to_cpus(&qh.el_link); @@ -556,6 +656,10 @@ static void uhci_frame_timer(void *opaque) } else if (qh.el_link & 2) { /* QH */ link = qh.el_link; + } else if (s->async_qh) { + /* We can only cope with one pending packet. Keep looking + for the previously issued packet. */ + link = qh.link; } else { /* TD */ if (--cnt == 0) @@ -577,7 +681,9 @@ static void uhci_frame_timer(void *opaque) } if (ret < 0) break; /* interrupted frame */ - if (ret == 0) { + if (ret == 2) { + s->async_qh = link; + } else if (ret == 0) { /* update qh element link */ qh.el_link = td.link; val = cpu_to_le32(qh.el_link); @@ -599,25 +705,41 @@ static void uhci_frame_timer(void *opaque) le32_to_cpus(&td.ctrl); le32_to_cpus(&td.token); le32_to_cpus(&td.buffer); - old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &int_mask); - /* update the status bits of the TD */ - if (old_td_ctrl != td.ctrl) { - val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); + /* Ignore isochonous transfers while there is an async packet + pending. This is wrong, but we don't implement isochronous + transfers anyway. */ + if (s->async_qh == 0) { + old_td_ctrl = td.ctrl; + ret = uhci_handle_td(s, &td, &int_mask); + /* update the status bits of the TD */ + if (old_td_ctrl != td.ctrl) { + val = cpu_to_le32(td.ctrl); + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, + sizeof(val)); + } + if (ret < 0) + break; /* interrupted frame */ + if (ret == 2) { + /* We can't handle async isochronous transfers. + Cancel The packet. */ + fprintf(stderr, "usb-uhci: Unimplemented async packet\n"); + usb_cancel_packet(&s->usb_packet); + } } - if (ret < 0) - break; /* interrupted frame */ link = td.link; } } - s->frnum = (s->frnum + 1) & 0x7ff; - if (int_mask) { - s->status2 |= int_mask; - s->status |= UHCI_STS_USBINT; - uhci_update_irq(s); + s->pending_int_mask = int_mask; + if (old_async_qh) { + /* A previously started transfer has disappeared from the transfer + list. There's nothing useful we can do with it now, so just + discard the packet and hope it wasn't too important. */ +#ifdef DEBUG + printf("Discarding USB packet\n"); +#endif + usb_cancel_packet(&s->usb_packet); + s->async_qh = 0; } /* prepare the timer for the next frame */ expire_time = qemu_get_clock(vm_clock) + diff --git a/hw/usb.c b/hw/usb.c index 34aac5fa9..efbc6dbe9 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -38,13 +38,13 @@ void usb_attach(USBPort *port, USBDevice *dev) #define SETUP_STATE_DATA 1 #define SETUP_STATE_ACK 2 -int usb_generic_handle_packet(USBDevice *s, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len) +int usb_generic_handle_packet(USBDevice *s, USBPacket *p) { int l, ret = 0; + int len = p->len; + uint8_t *data = p->data; - switch(pid) { + switch(p->pid) { case USB_MSG_ATTACH: s->state = USB_STATE_ATTACHED; break; @@ -58,7 +58,7 @@ int usb_generic_handle_packet(USBDevice *s, int pid, s->handle_reset(s); break; case USB_TOKEN_SETUP: - if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) return USB_RET_NODEV; if (len != 8) goto fail; @@ -85,9 +85,9 @@ int usb_generic_handle_packet(USBDevice *s, int pid, } break; case USB_TOKEN_IN: - if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) return USB_RET_NODEV; - switch(devep) { + switch(p->devep) { case 0: switch(s->setup_state) { case SETUP_STATE_ACK: @@ -125,14 +125,14 @@ int usb_generic_handle_packet(USBDevice *s, int pid, } break; default: - ret = s->handle_data(s, pid, devep, data, len); + ret = s->handle_data(s, p); break; } break; case USB_TOKEN_OUT: - if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) + if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) return USB_RET_NODEV; - switch(devep) { + switch(p->devep) { case 0: switch(s->setup_state) { case SETUP_STATE_ACK: @@ -163,7 +163,7 @@ int usb_generic_handle_packet(USBDevice *s, int pid, } break; default: - ret = s->handle_data(s, pid, devep, data, len); + ret = s->handle_data(s, p); break; } break; @@ -191,3 +191,13 @@ int set_usb_string(uint8_t *buf, const char *str) } return q - buf; } + +/* Send an internal message to a USB device. */ +void usb_send_msg(USBDevice *dev, int msg) +{ + USBPacket p; + memset(&p, 0, sizeof(p)); + p.pid = msg; + dev->handle_packet(dev, &p); +} + diff --git a/hw/usb.h b/hw/usb.h index 98fde0656..ed8890e39 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -34,6 +34,7 @@ #define USB_RET_NAK (-2) #define USB_RET_STALL (-3) #define USB_RET_BABBLE (-4) +#define USB_RET_ASYNC (-5) #define USB_SPEED_LOW 0 #define USB_SPEED_FULL 1 @@ -109,13 +110,12 @@ typedef struct USBPort USBPort; typedef struct USBDevice USBDevice; +typedef struct USBPacket USBPacket; /* definition of a USB device */ struct USBDevice { void *opaque; - int (*handle_packet)(USBDevice *dev, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len); + int (*handle_packet)(USBDevice *dev, USBPacket *p); void (*handle_destroy)(USBDevice *dev); int speed; @@ -126,8 +126,7 @@ struct USBDevice { void (*handle_reset)(USBDevice *dev); int (*handle_control)(USBDevice *dev, int request, int value, int index, int length, uint8_t *data); - int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, - uint8_t *data, int len); + int (*handle_data)(USBDevice *dev, USBPacket *p); uint8_t addr; char devname[32]; @@ -151,11 +150,54 @@ struct USBPort { struct USBPort *next; /* Used internally by qemu. */ }; +typedef void USBCallback(USBPacket * packet, void *opaque); + +/* Structure used to hold information about an active USB packet. */ +struct USBPacket { + /* Data fields for use by the driver. */ + int pid; + uint8_t devaddr; + uint8_t devep; + uint8_t *data; + int len; + /* Internal use by the USB layer. */ + USBCallback *complete_cb; + void *complete_opaque; + USBCallback *cancel_cb; + void * *cancel_opaque; +}; + +/* Defer completion of a USB packet. The hadle_packet routine should then + return USB_RET_ASYNC. Packets that complete immediately (before + handle_packet returns) should not call this method. */ +static inline void usb_defer_packet(USBPacket *p, USBCallback *cancel, + void * opaque) +{ + p->cancel_cb = cancel; + p->cancel_opaque = opaque; +} + +/* Notify the controller that an async packet is complete. This should only + be called for packets previously deferred with usb_defer_packet, and + should never be called from within handle_packet. */ +static inline void usb_packet_complete(USBPacket *p) +{ + p->complete_cb(p, p->complete_opaque); +} + +/* Cancel an active packet. The packed must have been deferred with + usb_defer_packet, and not yet completed. */ +static inline void usb_cancel_packet(USBPacket * p) +{ + p->cancel_cb(p, p->cancel_opaque); +} + void usb_attach(USBPort *port, USBDevice *dev); -int usb_generic_handle_packet(USBDevice *s, int pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len); +int usb_generic_handle_packet(USBDevice *s, USBPacket *p); int set_usb_string(uint8_t *buf, const char *str); +void usb_send_msg(USBDevice *dev, int msg); + +void usb_packet_complete(USBPacket *p); /* usb hub */ USBDevice *usb_hub_init(int nb_ports); diff --git a/pc-bios/openbios-esp.diff b/pc-bios/openbios-esp.diff new file mode 100644 index 000000000..5d4f836f1 --- /dev/null +++ b/pc-bios/openbios-esp.diff @@ -0,0 +1,30 @@ +The ESP SCSI driver currently doesn't check whether a DMA requests has +completed before checking its status. On older qemu versions this works ok +because DMA happens instantly. On never qemu DMA can take an indeterminate +amount of time ooto complete, just like on real hardware. + +The patch below waits for the controller to raise the DMA interrupt after +initiating a DMA request. + +Index: drivers/esp.c +=================================================================== +--- drivers/esp.c (revision 61) ++++ drivers/esp.c (working copy) +@@ -113,6 +113,8 @@ do_command(esp_private_t *esp, sd_privat + esp->espdma.regs->cond_reg = 0; + // Set ATN, issue command + esp->ll->regs[ESP_CMD] = ESP_CMD_SELA | ESP_CMD_DMA; ++ // Wait for DMA to complete ++ while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */; + // Check status + status = esp->ll->regs[ESP_STATUS]; + +@@ -129,6 +131,8 @@ do_command(esp_private_t *esp, sd_privat + esp->espdma.regs->cond_reg = DMA_ST_WRITE; + // Transfer + esp->ll->regs[ESP_CMD] = ESP_CMD_TI | ESP_CMD_DMA; ++ // Wait for DMA to complete ++ while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */; + // Check status + status = esp->ll->regs[ESP_STATUS]; + diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 7a729aa81..04b60776d 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/usb-linux.c b/usb-linux.c index 0a13753d4..77436927c 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -114,22 +114,21 @@ static int usb_host_handle_control(USBDevice *dev, } } -static int usb_host_handle_data(USBDevice *dev, int pid, - uint8_t devep, - uint8_t *data, int len) +static int usb_host_handle_data(USBDevice *dev, USBPacket *p) { USBHostDevice *s = (USBHostDevice *)dev; struct usbdevfs_bulktransfer bt; int ret; + uint8_t devep = p->devep; /* XXX: optimize and handle all data types by looking at the config descriptor */ - if (pid == USB_TOKEN_IN) + if (p->pid == USB_TOKEN_IN) devep |= 0x80; bt.ep = devep; - bt.len = len; + bt.len = p->len; bt.timeout = 50; - bt.data = data; + bt.data = p->data; ret = ioctl(s->fd, USBDEVFS_BULK, &bt); if (ret < 0) { switch(errno) { diff --git a/vl.h b/vl.h index 1632e3571..5a1032681 100644 --- a/vl.h +++ b/vl.h @@ -1146,6 +1146,11 @@ void do_usb_del(const char *devname); void usb_info(void); /* scsi-disk.c */ +enum scsi_reason { + SCSI_REASON_DONE, /* Command complete. */ + SCSI_REASON_DATA /* Transfer complete, more data required. */ +}; + typedef struct SCSIDevice SCSIDevice; typedef void (*scsi_completionfn)(void *, uint32_t, int); @@ -1155,8 +1160,12 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, void scsi_disk_destroy(SCSIDevice *s); int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); +/* SCSI data transfers are asynchrnonous. However, unlike the block IO + layer the completion routine may be called directly by + scsi_{read,write}_data. */ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); +void scsi_cancel_io(SCSIDevice *s); /* lsi53c895a.c */ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); -- cgit v1.2.3 From 69fba4a51edb69fb983ca887d985c1d9a1c62e5e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 13 Aug 2006 14:20:43 +0000 Subject: Remove OpenBIOS ESP patch. Merged upstream. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2108 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/openbios-esp.diff | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 pc-bios/openbios-esp.diff diff --git a/pc-bios/openbios-esp.diff b/pc-bios/openbios-esp.diff deleted file mode 100644 index 5d4f836f1..000000000 --- a/pc-bios/openbios-esp.diff +++ /dev/null @@ -1,30 +0,0 @@ -The ESP SCSI driver currently doesn't check whether a DMA requests has -completed before checking its status. On older qemu versions this works ok -because DMA happens instantly. On never qemu DMA can take an indeterminate -amount of time ooto complete, just like on real hardware. - -The patch below waits for the controller to raise the DMA interrupt after -initiating a DMA request. - -Index: drivers/esp.c -=================================================================== ---- drivers/esp.c (revision 61) -+++ drivers/esp.c (working copy) -@@ -113,6 +113,8 @@ do_command(esp_private_t *esp, sd_privat - esp->espdma.regs->cond_reg = 0; - // Set ATN, issue command - esp->ll->regs[ESP_CMD] = ESP_CMD_SELA | ESP_CMD_DMA; -+ // Wait for DMA to complete -+ while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */; - // Check status - status = esp->ll->regs[ESP_STATUS]; - -@@ -129,6 +131,8 @@ do_command(esp_private_t *esp, sd_privat - esp->espdma.regs->cond_reg = DMA_ST_WRITE; - // Transfer - esp->ll->regs[ESP_CMD] = ESP_CMD_TI | ESP_CMD_DMA; -+ // Wait for DMA to complete -+ while ((esp->espdma.regs->cond_reg & DMA_HNDL_INTR) == 0) /* no-op */; - // Check status - status = esp->ll->regs[ESP_STATUS]; - -- cgit v1.2.3 From 35f1df84b6a9d4462764b833e915100f91e4f257 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 14 Aug 2006 15:08:12 +0000 Subject: scsi empty drive fix (Blue Swirl). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2109 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/scsi-disk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a2f299e95..55a26239d 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -447,6 +447,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) s->buf_len = 8; } else { scsi_command_complete(s, SENSE_NOT_READY); + return 0; } break; case 0x08: -- cgit v1.2.3 From 3dc1cb3428f8661f99e03cfac6f5aedf3d614927 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 15 Aug 2006 22:57:33 +0000 Subject: ESP DMA fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2110 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 17e70dd03..d67dbf3f3 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -206,7 +206,6 @@ static void esp_do_dma(ESPState *s) { uint32_t dmaptr, minlen, len, from, to; int to_device; - dmaptr = iommu_translate(s->espdmaregs[1]); to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; from = s->espdmaregs[1]; minlen = s->dma_left; @@ -218,8 +217,8 @@ static void esp_do_dma(ESPState *s) len = to - from; } DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1], len, from, to); - s->espdmaregs[1] += len; if (s->do_cmd) { + s->espdmaregs[1] += len; s->ti_size -= len; DPRINTF("command len %d + %d\n", s->cmdlen, len); cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); -- cgit v1.2.3 From 4c279bdf3ae80ab194c2f8b9d27680fb4e6841a8 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 09:43:50 +0000 Subject: win32 compilation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2111 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/vl.c b/vl.c index 1bef09c9c..af42379a8 100644 --- a/vl.c +++ b/vl.c @@ -4539,7 +4539,11 @@ void do_savevm(const char *name) BlockDriverInfo bdi1, *bdi = &bdi1; QEMUFile *f; int saved_vm_running; +#ifdef _WIN32 + struct _timeb tb; +#else struct timeval tv; +#endif bs = get_bs_snapshots(); if (!bs) { @@ -4567,9 +4571,15 @@ void do_savevm(const char *name) } /* fill auxiliary fields */ +#ifdef _WIN32 + _ftime(&tb); + sn->date_sec = tb.time; + sn->date_nsec = tb.millitm * 1000000; +#else gettimeofday(&tv, NULL); sn->date_sec = tv.tv_sec; sn->date_nsec = tv.tv_usec * 1000; +#endif sn->vm_clock_nsec = qemu_get_clock(vm_clock); if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { -- cgit v1.2.3 From dfd92d3a46c31b17fcdbd735c6f88de54bc6bd3f Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 10:42:46 +0000 Subject: reset key modifiers when switching console (aka savevm keyboard bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2112 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdl.c b/sdl.c index 38d75536d..00f574640 100644 --- a/sdl.c +++ b/sdl.c @@ -394,6 +394,8 @@ static void sdl_refresh(DisplayState *ds) gui_keysym = 1; break; case 0x02 ... 0x0a: /* '1' to '9' keys */ + /* Reset the modifiers sent to the current console */ + reset_keys(); console_select(keycode - 0x02); if (!is_graphic_console()) { /* display grab if going to a text console */ @@ -468,7 +470,7 @@ static void sdl_refresh(DisplayState *ds) } } } - if (is_graphic_console()) + if (is_graphic_console() && !gui_keysym) sdl_process_key(&ev->key); break; case SDL_QUIT: -- cgit v1.2.3 From d2269f6f64e1b707fc8ea5d43102589c03dd090e Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 10:44:00 +0000 Subject: save VGA PCI state git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2113 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 15 ++++++- hw/vga.c | 136 ++++++++++++++++++++++++++++++++++---------------------- hw/vga_int.h | 1 + 3 files changed, 96 insertions(+), 56 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index d186d797a..94163e598 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2905,6 +2905,9 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque) { CirrusVGAState *s = opaque; + if (s->pci_dev) + pci_device_save(s->pci_dev, f); + qemu_put_be32s(f, &s->latch); qemu_put_8s(f, &s->sr_index); qemu_put_buffer(f, s->sr, 256); @@ -2943,10 +2946,17 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque) static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) { CirrusVGAState *s = opaque; + int ret; - if (version_id != 1) + if (version_id > 2) return -EINVAL; + if (s->pci_dev && version_id >= 2) { + ret = pci_device_load(s->pci_dev, f); + if (ret < 0) + return ret; + } + qemu_get_be32s(f, &s->latch); qemu_get_8s(f, &s->sr_index); qemu_get_buffer(f, s->sr, 256); @@ -3100,7 +3110,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) s->cursor_invalidate = cirrus_cursor_invalidate; s->cursor_draw_line = cirrus_cursor_draw_line; - register_savevm("cirrus_vga", 0, 1, cirrus_vga_save, cirrus_vga_load, s); + register_savevm("cirrus_vga", 0, 2, cirrus_vga_save, cirrus_vga_load, s); } /*************************************** @@ -3178,6 +3188,7 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, device_id, 1); + s->pci_dev = (PCIDevice *)d; /* setup memory space */ /* memory #0 LFB */ diff --git a/hw/vga.c b/hw/vga.c index 8f748b371..c77b9f9ff 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -143,9 +143,6 @@ static uint32_t expand4[256]; static uint16_t expand2[256]; static uint8_t expand4to8[16]; -VGAState *vga_state; -int vga_io_memory; - static void vga_screen_dump(void *opaque, const char *filename); static uint32_t vga_ioport_read(void *opaque, uint32_t addr) @@ -1624,6 +1621,9 @@ static void vga_save(QEMUFile *f, void *opaque) VGAState *s = opaque; int i; + if (s->pci_dev) + pci_device_save(s->pci_dev, f); + qemu_put_be32s(f, &s->latch); qemu_put_8s(f, &s->sr_index); qemu_put_buffer(f, s->sr, 8); @@ -1663,11 +1663,17 @@ static void vga_save(QEMUFile *f, void *opaque) static int vga_load(QEMUFile *f, void *opaque, int version_id) { VGAState *s = opaque; - int is_vbe, i; + int is_vbe, i, ret; - if (version_id != 1) + if (version_id > 2) return -EINVAL; + if (s->pci_dev && version_id >= 2) { + ret = pci_device_load(s->pci_dev, f); + if (ret < 0) + return ret; + } + qemu_get_be32s(f, &s->latch); qemu_get_8s(f, &s->sr_index); qemu_get_buffer(f, s->sr, 8); @@ -1711,10 +1717,16 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) return 0; } +typedef struct PCIVGAState { + PCIDevice dev; + VGAState vga_state; +} PCIVGAState; + static void vga_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { - VGAState *s = vga_state; + PCIVGAState *d = (PCIVGAState *)pci_dev; + VGAState *s = &d->vga_state; if (region_num == PCI_ROM_SLOT) { cpu_register_physical_memory(addr, s->bios_size, s->bios_offset); } else { @@ -1761,24 +1773,14 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, s->get_resolution = vga_get_resolution; graphic_console_init(s->ds, vga_update_display, vga_invalidate_display, vga_screen_dump, s); - /* XXX: currently needed for display */ - vga_state = s; } - -int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size, - unsigned long vga_bios_offset, int vga_bios_size) +/* used by both ISA and PCI */ +static void vga_init(VGAState *s) { - VGAState *s; + int vga_io_memory; - s = qemu_mallocz(sizeof(VGAState)); - if (!s) - return -1; - - vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - - register_savevm("vga", 0, 1, vga_save, vga_load, s); + register_savevm("vga", 0, 2, vga_save, vga_load, s); register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); @@ -1823,43 +1825,69 @@ int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, vga_io_memory); +} + +int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size) +{ + VGAState *s; + + s = qemu_mallocz(sizeof(VGAState)); + if (!s) + return -1; + + vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); + vga_init(s); - if (bus) { - PCIDevice *d; - uint8_t *pci_conf; - - d = pci_register_device(bus, "VGA", - sizeof(PCIDevice), - -1, NULL, NULL); - pci_conf = d->config; - pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID) - pci_conf[0x01] = 0x12; - pci_conf[0x02] = 0x11; - pci_conf[0x03] = 0x11; - pci_conf[0x0a] = 0x00; // VGA controller - pci_conf[0x0b] = 0x03; - pci_conf[0x0e] = 0x00; // header_type - - /* XXX: vga_ram_size must be a power of two */ - pci_register_io_region(d, 0, vga_ram_size, - PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); - if (vga_bios_size != 0) { - unsigned int bios_total_size; - s->bios_offset = vga_bios_offset; - s->bios_size = vga_bios_size; - /* must be a power of two */ - bios_total_size = 1; - while (bios_total_size < vga_bios_size) - bios_total_size <<= 1; - pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size, - PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); - } - } else { #ifdef CONFIG_BOCHS_VBE - /* XXX: use optimized standard vga accesses */ - cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, - vga_ram_size, vga_ram_offset); + /* XXX: use optimized standard vga accesses */ + cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, + vga_ram_size, vga_ram_offset); #endif + return 0; +} + +int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size, + unsigned long vga_bios_offset, int vga_bios_size) +{ + PCIVGAState *d; + VGAState *s; + uint8_t *pci_conf; + + d = (PCIVGAState *)pci_register_device(bus, "VGA", + sizeof(PCIVGAState), + -1, NULL, NULL); + if (!d) + return -1; + s = &d->vga_state; + + vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); + vga_init(s); + s->pci_dev = &d->dev; + + pci_conf = d->dev.config; + pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID) + pci_conf[0x01] = 0x12; + pci_conf[0x02] = 0x11; + pci_conf[0x03] = 0x11; + pci_conf[0x0a] = 0x00; // VGA controller + pci_conf[0x0b] = 0x03; + pci_conf[0x0e] = 0x00; // header_type + + /* XXX: vga_ram_size must be a power of two */ + pci_register_io_region(&d->dev, 0, vga_ram_size, + PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); + if (vga_bios_size != 0) { + unsigned int bios_total_size; + s->bios_offset = vga_bios_offset; + s->bios_size = vga_bios_size; + /* must be a power of two */ + bios_total_size = 1; + while (bios_total_size < vga_bios_size) + bios_total_size <<= 1; + pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size, + PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); } return 0; } diff --git a/hw/vga_int.h b/hw/vga_int.h index b33ab575d..e4a4a46cd 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -83,6 +83,7 @@ unsigned int vram_size; \ unsigned long bios_offset; \ unsigned int bios_size; \ + PCIDevice *pci_dev; \ uint32_t latch; \ uint8_t sr_index; \ uint8_t sr[256]; \ -- cgit v1.2.3 From 89b6b508929d63b2a3dda18692fcb724afb43336 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 10:45:20 +0000 Subject: vga init changes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2114 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 4 ++-- hw/pc.c | 9 +++++++-- hw/ppc_chrp.c | 12 ++++++------ hw/ppc_prep.c | 4 ++-- vl.h | 12 +++++++----- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 22d742a2e..bad916319 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -270,8 +270,8 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, isa_pic = pic_init(pic_irq_request, env); pit = pit_init(0x40, 0); serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); - vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); + isa_vga_init(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); if (nd_table[0].vlan) { if (nd_table[0].model == NULL diff --git a/hw/pc.c b/hw/pc.c index 898d0681e..b233d8cd0 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -768,8 +768,13 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, vga_ram_size); } } else { - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); + if (pci_enabled) { + pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size, 0, 0); + } else { + isa_vga_init(ds, phys_ram_base + ram_size, ram_size, + vga_ram_size); + } } rtc_state = rtc_init(0x70, 8); diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 42d599588..94707690e 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -424,9 +424,9 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, pic = heathrow_pic_init(&heathrow_pic_mem_index); set_irq = heathrow_pic_set_irq; pci_bus = pci_grackle_init(0xfec00000, pic); - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, - ram_size, vga_ram_size, - vga_bios_offset, vga_bios_size); + pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, + ram_size, vga_ram_size, + vga_bios_offset, vga_bios_size); /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); @@ -474,9 +474,9 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, set_irq = openpic_set_irq; pci_bus = pci_pmac_init(pic); /* init basic PC hardware */ - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, - ram_size, vga_ram_size, - vga_bios_offset, vga_bios_size); + pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, + ram_size, vga_ram_size, + vga_bios_offset, vga_bios_size); /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index a4d7ddfe7..d75c27c3e 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -612,8 +612,8 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); /* init basic PC hardware */ - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); + pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, + vga_ram_size, 0, 0); rtc_init(0x70, 8); // openpic = openpic_init(0x00000000, 0xF0000000, 1); isa_pic = pic_init(pic_irq_request, first_cpu); diff --git a/vl.h b/vl.h index 5a1032681..8a87a0a0d 100644 --- a/vl.h +++ b/vl.h @@ -744,8 +744,8 @@ uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len); void pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len); -void generic_pci_save(QEMUFile* f, void *opaque); -int generic_pci_load(QEMUFile* f, void *opaque, int version_id); +void pci_device_save(PCIDevice *s, QEMUFile *f); +int pci_device_load(PCIDevice *s, QEMUFile *f); typedef void (*pci_set_irq_fn)(PCIDevice *pci_dev, void *pic, int irq_num, int level); @@ -834,9 +834,11 @@ static inline void dpy_resize(DisplayState *s, int w, int h) s->dpy_resize(s, w, h); } -int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size, - unsigned long vga_bios_offset, int vga_bios_size); +int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); +int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size, + unsigned long vga_bios_offset, int vga_bios_size); /* cirrus_vga.c */ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, -- cgit v1.2.3 From 1941d19c657a8084603e88d7860786baa40c0e80 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 10:46:34 +0000 Subject: PCI save/restore changes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2115 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 23 ++++++++++++++++------- hw/pci.c | 15 ++++++++------- hw/piix_pci.c | 16 +++++++++++++++- hw/rtl8139.c | 16 +++++++++++----- 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index e23c6df06..14d48ee95 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -648,6 +648,9 @@ static void ne2000_save(QEMUFile* f,void* opaque) { NE2000State* s=(NE2000State*)opaque; + if (s->pci_dev) + pci_device_save(s->pci_dev, f); + qemu_put_8s(f, &s->rxcr); qemu_put_8s(f, &s->cmd); @@ -673,13 +676,21 @@ static void ne2000_save(QEMUFile* f,void* opaque) static int ne2000_load(QEMUFile* f,void* opaque,int version_id) { NE2000State* s=(NE2000State*)opaque; + int ret; + + if (version_id > 3) + return -EINVAL; + + if (s->pci_dev && version_id >= 3) { + ret = pci_device_load(s->pci_dev, f); + if (ret < 0) + return ret; + } - if (version_id == 2) { + if (version_id >= 2) { qemu_get_8s(f, &s->rxcr); - } else if (version_id == 1) { - s->rxcr = 0x0c; } else { - return -EINVAL; + s->rxcr = 0x0c; } qemu_get_8s(f, &s->cmd); @@ -810,7 +821,5 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd) s->macaddr[5]); /* XXX: instance number ? */ - register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); - register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, - &d->dev); + register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s); } diff --git a/hw/pci.c b/hw/pci.c index 85531f72e..75bd98110 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -36,6 +36,8 @@ struct PCIBus { PCIDevice *devices[256]; }; +static void pci_update_mappings(PCIDevice *d); + target_phys_addr_t pci_mem_base; static int pci_irq_index; static PCIBus *first_bus; @@ -56,21 +58,20 @@ int pci_bus_num(PCIBus *s) return s->bus_num; } -void generic_pci_save(QEMUFile* f, void *opaque) +void pci_device_save(PCIDevice *s, QEMUFile *f) { - PCIDevice* s=(PCIDevice*)opaque; - + qemu_put_be32(f, 1); /* PCI device version */ qemu_put_buffer(f, s->config, 256); } -int generic_pci_load(QEMUFile* f, void *opaque, int version_id) +int pci_device_load(PCIDevice *s, QEMUFile *f) { - PCIDevice* s=(PCIDevice*)opaque; - + uint32_t version_id; + version_id = qemu_get_be32(f); if (version_id != 1) return -EINVAL; - qemu_get_buffer(f, s->config, 256); + pci_update_mappings(s); return 0; } diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 1f7ad94c6..672b736ad 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -181,6 +181,20 @@ static void piix3_reset(PCIDevice *d) pci_conf[0xae] = 0x00; } +static void piix_save(QEMUFile* f, void *opaque) +{ + PCIDevice *d = opaque; + pci_device_save(d, f); +} + +static int piix_load(QEMUFile* f, void *opaque, int version_id) +{ + PCIDevice *d = opaque; + if (version_id != 2) + return -EINVAL; + return pci_device_load(d, f); +} + int piix3_init(PCIBus *bus) { PCIDevice *d; @@ -188,7 +202,7 @@ int piix3_init(PCIBus *bus) d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice), -1, NULL, NULL); - register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); + register_savevm("PIIX3", 0, 2, piix_save, piix_load, d); piix3_dev = d; pci_conf = d->config; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 9c613a8f9..db6353a7e 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3122,6 +3122,8 @@ static void rtl8139_save(QEMUFile* f,void* opaque) RTL8139State* s=(RTL8139State*)opaque; int i; + pci_device_save(s->pci_dev, f); + qemu_put_buffer(f, s->phys, 6); qemu_put_buffer(f, s->mult, 8); @@ -3203,12 +3205,18 @@ static void rtl8139_save(QEMUFile* f,void* opaque) static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) { RTL8139State* s=(RTL8139State*)opaque; - int i; + int i, ret; /* just 2 versions for now */ - if (version_id > 2) + if (version_id > 3) return -EINVAL; + if (version_id >= 3) { + ret = pci_device_load(s->pci_dev, f); + if (ret < 0) + return ret; + } + /* saved since version 1 */ qemu_get_buffer(f, s->phys, 6); qemu_get_buffer(f, s->mult, 8); @@ -3457,9 +3465,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) s->cplus_txbuffer_offset = 0; /* XXX: instance number ? */ - register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s); - register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load, - &d->dev); + register_savevm("rtl8139", 0, 3, rtl8139_save, rtl8139_load, s); #if RTL8139_ONBOARD_TIMER s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); -- cgit v1.2.3 From e6cf6a8c7d1d01b1b3a293ba420d39c61435a9b9 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 10:48:06 +0000 Subject: save apic timer git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2116 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/apic.c b/hw/apic.c index 8f88cce01..aa6f2ef38 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -745,6 +745,8 @@ static void apic_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->initial_count); qemu_put_be64s(f, &s->initial_count_load_time); qemu_put_be64s(f, &s->next_time); + + qemu_put_timer(f, s->timer); } static int apic_load(QEMUFile *f, void *opaque, int version_id) @@ -752,7 +754,7 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id) APICState *s = opaque; int i; - if (version_id != 1) + if (version_id > 2) return -EINVAL; /* XXX: what if the base changes? (registered memory regions) */ @@ -779,6 +781,9 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->initial_count); qemu_get_be64s(f, &s->initial_count_load_time); qemu_get_be64s(f, &s->next_time); + + if (version_id >= 2) + qemu_get_timer(f, s->timer); return 0; } -- cgit v1.2.3 From c3d78997a3235b2bb500c9eae4f0389550d77a35 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 10:48:35 +0000 Subject: minimal PCI IDE save/restore git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2117 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index 40e7b42c6..b9bd607a4 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2409,6 +2409,117 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, cmd646_set_irq, d, 1); } +static void pci_ide_save(QEMUFile* f, void *opaque) +{ + PCIIDEState *d = opaque; + int i; + + pci_device_save(&d->dev, f); + + for(i = 0; i < 2; i++) { + BMDMAState *bm = &d->bmdma[i]; + qemu_put_8s(f, &bm->cmd); + qemu_put_8s(f, &bm->status); + qemu_put_be32s(f, &bm->addr); + /* XXX: if a transfer is pending, we do not save it yet */ + } + + /* per IDE interface data */ + for(i = 0; i < 2; i++) { + IDEState *s = &d->ide_if[i * 2]; + uint8_t drive1_selected; + qemu_put_8s(f, &s->cmd); + drive1_selected = (s->cur_drive != s); + qemu_put_8s(f, &drive1_selected); + } + + /* per IDE drive data */ + for(i = 0; i < 4; i++) { + IDEState *s = &d->ide_if[i]; + qemu_put_be32s(f, &s->mult_sectors); + qemu_put_be32s(f, &s->identify_set); + if (s->identify_set) { + qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512); + } + qemu_put_8s(f, &s->feature); + qemu_put_8s(f, &s->error); + qemu_put_be32s(f, &s->nsector); + qemu_put_8s(f, &s->sector); + qemu_put_8s(f, &s->lcyl); + qemu_put_8s(f, &s->hcyl); + qemu_put_8s(f, &s->hob_feature); + qemu_put_8s(f, &s->hob_nsector); + qemu_put_8s(f, &s->hob_sector); + qemu_put_8s(f, &s->hob_lcyl); + qemu_put_8s(f, &s->hob_hcyl); + qemu_put_8s(f, &s->select); + qemu_put_8s(f, &s->status); + qemu_put_8s(f, &s->lba48); + + qemu_put_8s(f, &s->sense_key); + qemu_put_8s(f, &s->asc); + /* XXX: if a transfer is pending, we do not save it yet */ + } +} + +static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) +{ + PCIIDEState *d = opaque; + int ret, i; + + if (version_id != 1) + return -EINVAL; + ret = pci_device_load(&d->dev, f); + if (ret < 0) + return ret; + + for(i = 0; i < 2; i++) { + BMDMAState *bm = &d->bmdma[i]; + qemu_get_8s(f, &bm->cmd); + qemu_get_8s(f, &bm->status); + qemu_get_be32s(f, &bm->addr); + /* XXX: if a transfer is pending, we do not save it yet */ + } + + /* per IDE interface data */ + for(i = 0; i < 2; i++) { + IDEState *s = &d->ide_if[i * 2]; + uint8_t drive1_selected; + qemu_get_8s(f, &s->cmd); + qemu_get_8s(f, &drive1_selected); + s->cur_drive = &d->ide_if[i * 2 + (drive1_selected != 0)]; + } + + /* per IDE drive data */ + for(i = 0; i < 4; i++) { + IDEState *s = &d->ide_if[i]; + qemu_get_be32s(f, &s->mult_sectors); + qemu_get_be32s(f, &s->identify_set); + if (s->identify_set) { + qemu_get_buffer(f, (uint8_t *)s->identify_data, 512); + } + qemu_get_8s(f, &s->feature); + qemu_get_8s(f, &s->error); + qemu_get_be32s(f, &s->nsector); + qemu_get_8s(f, &s->sector); + qemu_get_8s(f, &s->lcyl); + qemu_get_8s(f, &s->hcyl); + qemu_get_8s(f, &s->hob_feature); + qemu_get_8s(f, &s->hob_nsector); + qemu_get_8s(f, &s->hob_sector); + qemu_get_8s(f, &s->hob_lcyl); + qemu_get_8s(f, &s->hob_hcyl); + qemu_get_8s(f, &s->select); + qemu_get_8s(f, &s->status); + qemu_get_8s(f, &s->lba48); + + qemu_get_8s(f, &s->sense_key); + qemu_get_8s(f, &s->asc); + /* XXX: if a transfer is pending, we do not save it yet */ + } + return 0; +} + /* hd_table must contain 4 block drivers */ /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) @@ -2442,6 +2553,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) pic_set_irq_new, isa_pic, 15); ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); ide_init_ioport(&d->ide_if[2], 0x170, 0x376); + + register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); } /***********************************************************/ -- cgit v1.2.3 From 243a273ee0168fc373f342479ae92fe3028b45c1 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 16:19:07 +0000 Subject: fd leak fix (Igor Kovalenko) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2118 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/osdep.c b/osdep.c index 348fcf2ca..1a4c03688 100644 --- a/osdep.c +++ b/osdep.c @@ -120,7 +120,8 @@ void *kqemu_vmalloc(size_t size) } snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", tmpdir); - if (mkstemp(phys_ram_file) < 0) { + phys_ram_fd = mkstemp(phys_ram_file); + if (phys_ram_fd < 0) { fprintf(stderr, "warning: could not create temporary file in '%s'.\n" "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n" @@ -128,18 +129,13 @@ void *kqemu_vmalloc(size_t size) tmpdir); snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", "/tmp"); - if (mkstemp(phys_ram_file) < 0) { + phys_ram_fd = mkstemp(phys_ram_file); + if (phys_ram_fd < 0) { fprintf(stderr, "Could not create temporary memory file '%s'\n", phys_ram_file); exit(1); } } - phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600); - if (phys_ram_fd < 0) { - fprintf(stderr, "Could not open temporary memory file '%s'\n", - phys_ram_file); - exit(1); - } unlink(phys_ram_file); } size = (size + 4095) & ~4095; -- cgit v1.2.3 From 87b47350eddb859f870046a56b457d3e748deab7 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 17:22:54 +0000 Subject: -L help git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2119 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 3 +++ vl.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 8ff329a72..a9d9747b1 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -614,6 +614,9 @@ translation mode (@var{t}=none, lba or auto). Usually QEMU can guess all thoses parameters. This option is useful for old MS-DOS disk images. +@item -L path +Set the directory for the BIOS, VGA BIOS and keymaps. + @item -std-vga Simulate a standard VGA card with Bochs VBE extensions (default is Cirrus Logic GD5446 PCI VGA). If your guest OS supports the VESA 2.0 diff --git a/vl.c b/vl.c index af42379a8..29142e1f6 100644 --- a/vl.c +++ b/vl.c @@ -5899,7 +5899,7 @@ void help(void) "-d item1,... output log to %s (use -d ? for a list of log items)\n" "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n" " translation (t=none or lba) (usually qemu can guess them)\n" - "-L path set the directory for the BIOS and VGA BIOS\n" + "-L path set the directory for the BIOS, VGA BIOS and keymaps\n" #ifdef USE_KQEMU "-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n" "-no-kqemu disable KQEMU kernel module usage\n" -- cgit v1.2.3 From 6e1b3e4da4de3720c8bd29cf22933a87e801b0d5 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 17 Aug 2006 17:41:26 +0000 Subject: disable -fomit-frame-pointer git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2120 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index 7ace0a83b..9ce7e7f5b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -66,8 +66,8 @@ LDFLAGS+=-static endif ifeq ($(ARCH),i386) -CFLAGS+=-fomit-frame-pointer -OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2 +HELPER_CFLAGS:=$(CFLAGS) -fomit-frame-pointer +OP_CFLAGS:=$(CFLAGS) -mpreferred-stack-boundary=2 -fomit-frame-pointer ifeq ($(HAVE_GCC3_OPTIONS),yes) OP_CFLAGS+= -falign-functions=0 -fno-gcse else @@ -471,8 +471,19 @@ gen-op.h: op.o $(DYNGEN) op.o: op.c $(CC) $(OP_CFLAGS) $(DEFINES) -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) $(DEFINES) -c -o $@ $< +else +op_helper.o: op_helper.c + $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< +endif + +cpu-exec.o: cpu-exec.c + $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< ifeq ($(TARGET_BASE_ARCH), i386) op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h -- cgit v1.2.3 From 83acc96b235753f089fadd7f755a9856a31165f2 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 18 Aug 2006 09:32:04 +0000 Subject: fixed VGA resolutions with height > 1024 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2121 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 13 +++++++++---- hw/vga.c | 18 +++++++++++------- hw/vga_int.h | 3 ++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 94163e598..d8fb37a89 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -1000,12 +1000,12 @@ static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value) ***************************************/ static void cirrus_get_offsets(VGAState *s1, - uint32_t *pline_offset, - uint32_t *pstart_addr) + uint32_t *pline_offset, + uint32_t *pstart_addr, + uint32_t *pline_compare) { CirrusVGAState * s = (CirrusVGAState *)s1; - uint32_t start_addr; - uint32_t line_offset; + uint32_t start_addr, line_offset, line_compare; line_offset = s->cr[0x13] | ((s->cr[0x1b] & 0x10) << 4); @@ -1018,6 +1018,11 @@ static void cirrus_get_offsets(VGAState *s1, | ((s->cr[0x1b] & 0x0c) << 15) | ((s->cr[0x1d] & 0x80) << 12); *pstart_addr = start_addr; + + line_compare = s->cr[0x18] | + ((s->cr[0x07] & 0x10) << 4) | + ((s->cr[0x09] & 0x40) << 3); + *pline_compare = line_compare; } static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s) diff --git a/hw/vga.c b/hw/vga.c index c77b9f9ff..4ecb7a95c 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -935,13 +935,15 @@ static int update_palette256(VGAState *s) static void vga_get_offsets(VGAState *s, uint32_t *pline_offset, - uint32_t *pstart_addr) + uint32_t *pstart_addr, + uint32_t *pline_compare) { - uint32_t start_addr, line_offset; + uint32_t start_addr, line_offset, line_compare; #ifdef CONFIG_BOCHS_VBE if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { line_offset = s->vbe_line_offset; start_addr = s->vbe_start_addr; + line_compare = 65535; } else #endif { @@ -951,9 +953,15 @@ static void vga_get_offsets(VGAState *s, /* starting address */ start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); + + /* line compare */ + line_compare = s->cr[0x18] | + ((s->cr[0x07] & 0x10) << 4) | + ((s->cr[0x09] & 0x40) << 3); } *pline_offset = line_offset; *pstart_addr = start_addr; + *pline_compare = line_compare; } /* update start_addr and line_offset. Return TRUE if modified */ @@ -964,11 +972,7 @@ static int update_basic_params(VGAState *s) full_update = 0; - s->get_offsets(s, &line_offset, &start_addr); - /* line compare */ - line_compare = s->cr[0x18] | - ((s->cr[0x07] & 0x10) << 4) | - ((s->cr[0x09] & 0x40) << 3); + s->get_offsets(s, &line_offset, &start_addr, &line_compare); if (line_offset != s->line_offset || start_addr != s->start_addr || diff --git a/hw/vga_int.h b/hw/vga_int.h index e4a4a46cd..70127768a 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -108,7 +108,8 @@ int (*get_bpp)(struct VGAState *s); \ void (*get_offsets)(struct VGAState *s, \ uint32_t *pline_offset, \ - uint32_t *pstart_addr); \ + uint32_t *pstart_addr, \ + uint32_t *pline_compare); \ void (*get_resolution)(struct VGAState *s, \ int *pwidth, \ int *pheight); \ -- cgit v1.2.3 From ea185bbda732dae6b6a5a44699f90c83e21f1494 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 11:43:22 +0000 Subject: use bdrv_media_changed() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2122 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index 3890ace12..930c0e21b 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -66,7 +66,6 @@ typedef enum fdrive_type_t { typedef enum fdrive_flags_t { FDRIVE_MOTOR_ON = 0x01, /* motor on/off */ - FDRIVE_REVALIDATE = 0x02, /* Revalidated */ } fdrive_flags_t; typedef enum fdisk_flags_t { @@ -236,7 +235,6 @@ static void fd_revalidate (fdrive_t *drv) int nb_heads, max_track, last_sect, ro; FLOPPY_DPRINTF("revalidate\n"); - drv->drflags &= ~FDRIVE_REVALIDATE; if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { ro = bdrv_is_read_only(drv->bs); bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect); @@ -291,7 +289,6 @@ static void fd_revalidate (fdrive_t *drv) drv->max_track = 0; drv->flags &= ~FDISK_DBL_SIDES; } - drv->drflags |= FDRIVE_REVALIDATE; } /* Motor control */ @@ -488,19 +485,6 @@ static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { fdctrl_write_mem, }; -static void fd_change_cb (void *opaque) -{ - fdrive_t *drv = opaque; - - FLOPPY_DPRINTF("disk change\n"); - fd_revalidate(drv); -#if 0 - fd_recalibrate(drv); - fdctrl_reset_fifo(drv->fdctrl); - fdctrl_raise_irq(drv->fdctrl, 0x20); -#endif -} - fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t io_base, BlockDriverState **fds) @@ -529,10 +513,6 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, } for (i = 0; i < 2; i++) { fd_init(&fdctrl->drives[i], fds[i]); - if (fds[i]) { - bdrv_set_change_cb(fds[i], - &fd_change_cb, &fdctrl->drives[i]); - } } fdctrl_reset(fdctrl, 0); fdctrl->state = FD_CTRL_ACTIVE; @@ -760,18 +740,28 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) // fdctrl.precomp = (value >> 2) & 0x07; } +static int fdctrl_media_changed(fdrive_t *drv) +{ + int ret; + if (!drv->bs) + return 0; + ret = bdrv_media_changed(drv->bs); + if (ret) { + fd_revalidate(drv); + } + return ret; +} + /* Digital input register : 0x07 (read-only) */ static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl) { uint32_t retval = 0; - if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE || - drv1(fdctrl)->drflags & FDRIVE_REVALIDATE) + if (fdctrl_media_changed(drv0(fdctrl)) || + fdctrl_media_changed(drv1(fdctrl))) retval |= 0x80; if (retval != 0) FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval); - drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE; - drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE; return retval; } -- cgit v1.2.3 From 66c6ef7678939f2119eb649074babf5d5b2666f6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 11:44:21 +0000 Subject: better support of removable media git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2123 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 120 ++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index b9bd607a4..6741cac1f 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -943,26 +943,44 @@ static void cd_data_to_raw(uint8_t *buf, int lba) memset(buf, 0, 288); } -static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, +static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, int sector_size) { + int ret; + switch(sector_size) { case 2048: - bdrv_read(bs, (int64_t)lba << 2, buf, 4); + ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4); break; case 2352: - bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); + ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); + if (ret < 0) + return ret; cd_data_to_raw(buf, lba); break; default: + ret = -EIO; break; } + return ret; +} + +static void ide_atapi_io_error(IDEState *s, int ret) +{ + /* XXX: handle more errors */ + if (ret == -ENOMEDIUM) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } else { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + } } /* The whole ATAPI transfer logic is handled in this function */ static void ide_atapi_cmd_reply_end(IDEState *s) { - int byte_count_limit, size; + int byte_count_limit, size, ret; #ifdef DEBUG_IDE_ATAPI printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", s->packet_transfer_size, @@ -981,7 +999,12 @@ static void ide_atapi_cmd_reply_end(IDEState *s) } else { /* see if a new sector must be read */ if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { - cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); + ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); + if (ret < 0) { + ide_transfer_stop(s); + ide_atapi_io_error(s, ret); + return; + } s->lba++; s->io_buffer_index = 0; } @@ -1070,6 +1093,11 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) IDEState *s = bm->ide_if; int data_offset, n; + if (ret < 0) { + ide_atapi_io_error(s, ret); + goto eot; + } + if (s->io_buffer_size > 0) { if (s->cd_sector_size == 2352) { n = 1; @@ -1114,6 +1142,12 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, s->io_buffer + data_offset, n * 4, ide_atapi_cmd_read_dma_cb, bm); + if (!bm->aiocb) { + /* Note: media not present is the most likely case */ + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + goto eot; + } } /* start a CD-CDROM read command with DMA */ @@ -1270,11 +1304,6 @@ static void ide_atapi_cmd(IDEState *s) { int nb_sectors, lba; - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } if (packet[0] == GPCMD_READ_10) nb_sectors = ube16_to_cpu(packet + 7); else @@ -1284,11 +1313,6 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_ok(s); break; } - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } ide_atapi_cmd_read(s, lba, nb_sectors, 2048); } break; @@ -1296,22 +1320,12 @@ static void ide_atapi_cmd(IDEState *s) { int nb_sectors, lba, transfer_request; - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; lba = ube32_to_cpu(packet + 2); if (nb_sectors == 0) { ide_atapi_cmd_ok(s); break; } - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } transfer_request = packet[9]; switch(transfer_request & 0xf8) { case 0x00: @@ -1336,13 +1350,17 @@ static void ide_atapi_cmd(IDEState *s) case GPCMD_SEEK: { int lba; - if (!bdrv_is_inserted(s->bs)) { + int64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } lba = ube32_to_cpu(packet + 2); - if (((int64_t)lba << 2) > s->nb_sectors) { + if (lba >= total_sectors) { ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); break; @@ -1358,7 +1376,10 @@ static void ide_atapi_cmd(IDEState *s) if (eject && !start) { /* eject the disk */ - bdrv_close(s->bs); + bdrv_eject(s->bs, 1); + } else if (eject && start) { + /* close the tray */ + bdrv_eject(s->bs, 0); } ide_atapi_cmd_ok(s); } @@ -1379,8 +1400,11 @@ static void ide_atapi_cmd(IDEState *s) case GPCMD_READ_TOC_PMA_ATIP: { int format, msf, start_track, len; + int64_t total_sectors; - if (!bdrv_is_inserted(s->bs)) { + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; @@ -1391,7 +1415,7 @@ static void ide_atapi_cmd(IDEState *s) start_track = packet[6]; switch(format) { case 0: - len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track); + len = cdrom_read_toc(total_sectors, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1405,7 +1429,7 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 12, max_len); break; case 2: - len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track); + len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1419,15 +1443,21 @@ static void ide_atapi_cmd(IDEState *s) } break; case GPCMD_READ_CDVD_CAPACITY: - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; + { + int64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + /* NOTE: it is really the number of sectors minus 1 */ + cpu_to_ube32(buf, total_sectors - 1); + cpu_to_ube32(buf + 4, 2048); + ide_atapi_cmd_reply(s, 8, 8); } - /* NOTE: it is really the number of sectors minus 1 */ - cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); - cpu_to_ube32(buf + 4, 2048); - ide_atapi_cmd_reply(s, 8, 8); break; case GPCMD_INQUIRY: max_len = packet[4]; @@ -1451,17 +1481,6 @@ static void ide_atapi_cmd(IDEState *s) } } -/* called when the inserted state of the media has changed */ -static void cdrom_change_cb(void *opaque) -{ - IDEState *s = opaque; - int64_t nb_sectors; - - /* XXX: send interrupt too */ - bdrv_get_geometry(s->bs, &nb_sectors); - s->nb_sectors = nb_sectors; -} - static void ide_cmd_lba48_transform(IDEState *s, int lba48) { s->lba48 = lba48; @@ -2092,7 +2111,6 @@ static void ide_init2(IDEState *ide_state, } if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { s->is_cdrom = 1; - bdrv_set_change_cb(s->bs, cdrom_change_cb, s); } } s->drive_serial = drive_serial++; -- cgit v1.2.3 From 19cb37389f4641d48803f0c5d72708749cbcf318 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 11:45:59 +0000 Subject: better support of host drives git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2124 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 682 +++++++++++++++++++++++++++++++++++++++++++++++++--------- block.c | 218 ++++++++++++++----- block_int.h | 12 +- qemu-doc.texi | 56 ++++- vl.h | 4 + 5 files changed, 808 insertions(+), 164 deletions(-) diff --git a/block-raw.c b/block-raw.c index a64564dc7..4dc0b9a74 100644 --- a/block-raw.c +++ b/block-raw.c @@ -46,100 +46,42 @@ #ifdef __sun__ #include #endif +#ifdef __linux__ +#include +#include +#include +#endif -typedef struct BDRVRawState { - int fd; -} BDRVRawState; +//#define DEBUG_FLOPPY -#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; -} +#define FTYPE_FILE 0 +#define FTYPE_CD 1 +#define FTYPE_FD 2 -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; -} +/* 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; + 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; @@ -150,9 +92,15 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) if (flags & BDRV_O_CREAT) open_flags |= O_CREAT | O_TRUNC; + s->type = FTYPE_FILE; + fd = open(filename, open_flags, 0644); - if (fd < 0) - return -errno; + if (fd < 0) { + ret = -errno; + if (ret == -EROFS) + ret = -EACCES; + return ret; + } s->fd = fd; return 0; } @@ -180,6 +128,10 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, 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; @@ -191,13 +143,17 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, 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 AOP using POSIX AIO */ +/* Unix AIO using POSIX AIO */ typedef struct RawAIOCB { BlockDriverAIOCB common; @@ -236,15 +192,18 @@ void qemu_aio_init(void) 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 RH 9 */ + /* 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 = 2; + ai.aio_threads = 1; ai.aio_num = 1; ai.aio_idle_time = 365 * 100000; aio_init(&ai); } +#endif } void qemu_aio_poll(void) @@ -270,7 +229,7 @@ void qemu_aio_poll(void) if (ret == acb->aiocb.aio_nbytes) ret = 0; else - ret = -1; + ret = -EINVAL; } else { ret = -ret; } @@ -329,6 +288,9 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs, BDRVRawState *s = bs->opaque; RawAIOCB *acb; + if (fd_open(bs) < 0) + return NULL; + acb = qemu_aio_get(bs, cb, opaque); if (!acb) return NULL; @@ -405,12 +367,17 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb) static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; - close(s->fd); + 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; @@ -428,6 +395,11 @@ static int64_t raw_getlength(BlockDriverState *bs) 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)) { @@ -455,12 +427,6 @@ static int64_t raw_getlength(BlockDriverState *bs) { size = lseek(fd, 0, SEEK_END); } -#ifdef _WIN32 - /* On Windows hosts it can happen that we're unable to get file size - for CD-ROM raw device (it's inherent limitation of the CDFS driver). */ - if (size == -1) - size = LONG_LONG_MAX; -#endif return size; } @@ -509,13 +475,358 @@ BlockDriver bdrv_raw = { .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 +#define FTYPE_FILE 0 +#define FTYPE_CD 1 + typedef struct BDRVRawState { HANDLE hfile; + int type; + char drive_letter[2]; } BDRVRawState; typedef struct RawAIOCB { @@ -565,6 +876,23 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) BDRVRawState *s = bs->opaque; int access_flags, create_flags; DWORD overlapped; + char device_name[64]; + const char *p; + + 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(filename); if ((flags & BDRV_O_ACCESS) == O_RDWR) { access_flags = GENERIC_READ | GENERIC_WRITE; @@ -765,10 +1093,22 @@ static int64_t raw_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; LARGE_INTEGER l; + ULARGE_INTEGER available, total, total_free; - l.LowPart = GetFileSize(s->hfile, &l.HighPart); - if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) - return -EIO; + switch(s->ftype) { + 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_letter, &available, &total, &total_free)) + return -EIO; + l = total; + break; + default: + return -EIO; + } return l.QuadPart; } @@ -833,4 +1173,146 @@ BlockDriver bdrv_raw = { .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(drivers)); + 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(const char *filename) +{ + UINT type; + const char *p; + + if (strstart(filename, "\\\\.\\", &p) || + strstart(filename, "//./", &p)) { + s->drive_letter[0] = p[0]; + s->drive_letter[1] = '\0'; + type = GetDriveType(s->drive_letter); + 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]; + const char *p; + + 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(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 = 0; +#else + overlapped = FILE_FLAG_OVERLAPPED; +#endif + s->hfile = CreateFile(filename, access_flags, + FILE_SHARE_READ, NULL, + create_flags, overlapped, 0); + 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 */ diff --git a/block.c b/block.c index d81451058..885b70023 100644 --- a/block.c +++ b/block.c @@ -181,24 +181,37 @@ void get_tmp_filename(char *filename, int size) } #endif +#ifdef _WIN32 +static int is_windows_drive(const char *filename) +{ + if (((filename[0] >= 'a' && filename[0] <= 'z') || + (filename[0] >= 'A' && filename[0] <= 'Z')) && + filename[1] == ':' && 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)) + return &bdrv_raw; +#endif p = strchr(filename, ':'); if (!p) return &bdrv_raw; len = p - filename; if (len > sizeof(protocol) - 1) len = sizeof(protocol) - 1; -#ifdef _WIN32 - if (len == 1) { - /* specific win32 case for driver letters */ - return &bdrv_raw; - } -#endif memcpy(protocol, filename, len); protocol[len] = '\0'; for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { @@ -218,14 +231,28 @@ static BlockDriver *find_image_format(const char *filename) 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 or host specific - devices */ + /* no need to test disk image formats for vvfat */ if (drv == &bdrv_vvfat) return drv; - if (strstart(filename, "/dev/", NULL)) - return &bdrv_raw; - + ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY); if (ret < 0) return NULL; @@ -362,9 +389,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, goto fail; } - bs->inserted = 1; - /* call the change callback */ + bs->media_changed = 1; if (bs->change_cb) bs->change_cb(bs->change_opaque); @@ -373,7 +399,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, void bdrv_close(BlockDriverState *bs) { - if (bs->inserted) { + if (bs->drv) { if (bs->backing_hd) bdrv_delete(bs->backing_hd); bs->drv->bdrv_close(bs); @@ -385,9 +411,9 @@ void bdrv_close(BlockDriverState *bs) #endif bs->opaque = NULL; bs->drv = NULL; - bs->inserted = 0; /* call the change callback */ + bs->media_changed = 1; if (bs->change_cb) bs->change_cb(bs->change_opaque); } @@ -403,12 +429,13 @@ void bdrv_delete(BlockDriverState *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 (!bs->inserted) - return -ENOENT; + if (!drv) + return -ENOMEDIUM; if (bs->read_only) { return -EACCES; @@ -420,7 +447,7 @@ int bdrv_commit(BlockDriverState *bs) total_sectors = bdrv_getlength(bs) >> SECTOR_BITS; for (i = 0; i < total_sectors;) { - if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { + 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; @@ -436,20 +463,20 @@ int bdrv_commit(BlockDriverState *bs) } } - if (bs->drv->bdrv_make_empty) - return bs->drv->bdrv_make_empty(bs); + if (drv->bdrv_make_empty) + return drv->bdrv_make_empty(bs); return 0; } -/* return < 0 if error */ +/* 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 (!bs->inserted) - return -1; + if (!drv) + return -ENOMEDIUM; if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { memcpy(buf, bs->boot_sector_data, 512); @@ -466,7 +493,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, if (ret < 0) return ret; else if (ret != len) - return -EIO; + return -EINVAL; else return 0; } else { @@ -474,15 +501,20 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, } } -/* return < 0 if error */ +/* 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->inserted) - return -1; + if (!bs->drv) + return -ENOMEDIUM; if (bs->read_only) - return -1; + return -EACCES; if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { memcpy(bs->boot_sector_data, buf, 512); } @@ -501,7 +533,6 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, } } -/* not necessary now */ static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, uint8_t *buf, int count1) { @@ -603,7 +634,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_pread) return bdrv_pread_em(bs, offset, buf1, count1); return drv->bdrv_pread(bs, offset, buf1, count1); @@ -618,7 +649,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_pwrite) return bdrv_pwrite_em(bs, offset, buf1, count1); return drv->bdrv_pwrite(bs, offset, buf1, count1); @@ -631,7 +662,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) { BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_truncate) return -ENOTSUP; return drv->bdrv_truncate(bs, offset); @@ -644,7 +675,7 @@ int64_t bdrv_getlength(BlockDriverState *bs) { BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_getlength) { /* legacy mode */ return bs->total_sectors * SECTOR_SIZE; @@ -652,9 +683,16 @@ int64_t bdrv_getlength(BlockDriverState *bs) 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) { - *nb_sectors_ptr = bs->total_sectors; + 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. */ @@ -715,21 +753,7 @@ int bdrv_is_read_only(BlockDriverState *bs) return bs->read_only; } -int bdrv_is_inserted(BlockDriverState *bs) -{ - return bs->inserted; -} - -int bdrv_is_locked(BlockDriverState *bs) -{ - return bs->locked; -} - -void bdrv_set_locked(BlockDriverState *bs, int locked) -{ - bs->locked = locked; -} - +/* XXX: no longer used */ void bdrv_set_change_cb(BlockDriverState *bs, void (*change_cb)(void *opaque), void *opaque) { @@ -761,7 +785,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key) void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) { - if (!bs->inserted || !bs->drv) { + if (!bs->drv) { buf[0] = '\0'; } else { pstrcpy(buf, buf_size, bs->drv->format_name); @@ -833,7 +857,7 @@ void bdrv_info(void) if (bs->removable) { term_printf(" locked=%d", bs->locked); } - if (bs->inserted) { + if (bs->drv) { term_printf(" file=%s", bs->filename); if (bs->backing_file[0] != '\0') term_printf(" backing_file=%s", bs->backing_file); @@ -863,7 +887,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, { BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_write_compressed) return -ENOTSUP; return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors); @@ -873,7 +897,7 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_get_info) return -ENOTSUP; memset(bdi, 0, sizeof(*bdi)); @@ -888,7 +912,7 @@ int bdrv_snapshot_create(BlockDriverState *bs, { BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_snapshot_create) return -ENOTSUP; return drv->bdrv_snapshot_create(bs, sn_info); @@ -899,7 +923,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, { BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_snapshot_goto) return -ENOTSUP; return drv->bdrv_snapshot_goto(bs, snapshot_id); @@ -909,7 +933,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) { BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_snapshot_delete) return -ENOTSUP; return drv->bdrv_snapshot_delete(bs, snapshot_id); @@ -920,7 +944,7 @@ int bdrv_snapshot_list(BlockDriverState *bs, { BlockDriver *drv = bs->drv; if (!drv) - return -ENOENT; + return -ENOMEDIUM; if (!drv->bdrv_snapshot_list) return -ENOTSUP; return drv->bdrv_snapshot_list(bs, psn_info); @@ -1001,7 +1025,7 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, { BlockDriver *drv = bs->drv; - if (!bs->inserted) + if (!drv) return NULL; /* XXX: we assume that nb_sectors == 0 is suppored by the async read */ @@ -1021,7 +1045,7 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, { BlockDriver *drv = bs->drv; - if (!bs->inserted) + if (!drv) return NULL; if (bs->read_only) return NULL; @@ -1170,6 +1194,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, void bdrv_init(void) { bdrv_register(&bdrv_raw); + bdrv_register(&bdrv_host_device); #ifndef _WIN32 bdrv_register(&bdrv_cow); #endif @@ -1211,3 +1236,78 @@ void qemu_aio_release(void *p) 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); + } +} diff --git a/block_int.h b/block_int.h index 8fd241f2a..25f6717b5 100644 --- a/block_int.h +++ b/block_int.h @@ -70,6 +70,12 @@ struct BlockDriver { 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; }; @@ -78,7 +84,6 @@ 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 inserted; /* if true, the media is present */ int removable; /* if true, the media can be removed */ int locked; /* if true, the media cannot temporarily be ejected */ int encrypted; /* if true, the media is encrypted */ @@ -86,7 +91,7 @@ struct BlockDriverState { void (*change_cb)(void *opaque); void *change_opaque; - BlockDriver *drv; + BlockDriver *drv; /* NULL means no media */ void *opaque; int boot_sector_enabled; @@ -96,7 +101,8 @@ struct BlockDriverState { 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 */ diff --git a/qemu-doc.texi b/qemu-doc.texi index a9d9747b1..40667e3f4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -206,7 +206,7 @@ Select the emulated machine (@code{-M ?} for list) @item -fda file @item -fdb file Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can -use the host floppy by using @file{/dev/fd0} as filename. +use the host floppy by using @file{/dev/fd0} as filename (@pxref{host_drives}). @item -hda file @item -hdb file @@ -217,7 +217,7 @@ Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}). @item -cdrom file Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and @option{-cdrom} at the same time). You can use the host CD-ROM by -using @file{/dev/cdrom} as filename. +using @file{/dev/cdrom} as filename (@pxref{host_drives}). @item -boot [a|c|d] Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is @@ -916,6 +916,7 @@ snapshots. * disk_images_snapshot_mode:: Snapshot mode * vm_snapshots:: VM snapshots * qemu_img_invocation:: qemu-img Invocation +* host_drives:: Using host drives * disk_images_fat_images:: Virtual FAT disk images @end menu @@ -997,6 +998,57 @@ state is not saved or restored properly (in particular USB). @include qemu-img.texi +@node host_drives +@subsection Using host drives + +In addition to disk image files, QEMU can directly access host +devices. We describe here the usage for QEMU version >= 0.8.3. + +@subsubsection Linux + +On Linux, you can directly use the host device filename instead of a +disk image filename provided you have enough proviledge to access +it. For example, use @file{/dev/cdrom} to access to the CDROM or +@file{/dev/fd0} for the floppy. + +@table +@item CD +You can specify a CDROM device even if no CDROM is loaded. QEMU has +specific code to detect CDROM insertion or removal. CDROM ejection by +the guest OS is supported. Currently only data CDs are supported. +@item Floppy +You can specify a floppy device even if no floppy is loaded. Floppy +removal is currently not detected accurately (if you change floppy +without doing floppy access while the floppy is not loaded, the guest +OS will think that the same floppy is loaded). +@item Hard disks +Hard disks can be used. Normally you must specify the whole disk +(@file{/dev/hdb} instead of @file{/dev/hdb1}) so that the guest OS can +see it as a partitioned disk. WARNING: unless you know what you do, it +is better to only make READ-ONLY accesses to the hard disk otherwise +you may corrupt your host data (use the @option{-snapshot} command +line option or modify the device permissions accordingly). +@end table + +@subsubsection Windows + +On Windows you can use any host drives as QEMU drive. The prefered +syntax is the driver letter (e.g. @file{d:}). The alternate syntax +@file{\\.\d:} is supported. @file{/dev/cdrom} is supported as an alias +to the first CDROM drive. + +Currently there is no specific code to handle removable medias, so it +is better to use the @code{change} or @code{eject} monitor commands to +change or eject media. + +@subsubsection Mac OS X + +@file{/dev/cdrom} is an alias to the first CDROM. + +Currently there is no specific code to handle removable medias, so it +is better to use the @code{change} or @code{eject} monitor commands to +change or eject media. + @node disk_images_fat_images @subsection Virtual FAT disk images diff --git a/vl.h b/vl.h index 8a87a0a0d..4bef80192 100644 --- a/vl.h +++ b/vl.h @@ -50,6 +50,7 @@ #define fsync _commit #define lseek _lseeki64 #define ENOTSUP 4096 +#define ENOMEDIUM 4097 extern int qemu_ftruncate64(int, int64_t); #define ftruncate qemu_ftruncate64 @@ -502,6 +503,7 @@ typedef struct BlockDriverState BlockDriverState; typedef struct BlockDriver BlockDriver; extern BlockDriver bdrv_raw; +extern BlockDriver bdrv_host_device; extern BlockDriver bdrv_cow; extern BlockDriver bdrv_qcow; extern BlockDriver bdrv_vmdk; @@ -604,8 +606,10 @@ int bdrv_get_translation_hint(BlockDriverState *bs); int bdrv_is_removable(BlockDriverState *bs); int bdrv_is_read_only(BlockDriverState *bs); int bdrv_is_inserted(BlockDriverState *bs); +int bdrv_media_changed(BlockDriverState *bs); int bdrv_is_locked(BlockDriverState *bs); void bdrv_set_locked(BlockDriverState *bs, int locked); +void bdrv_eject(BlockDriverState *bs, int eject_flag); void bdrv_set_change_cb(BlockDriverState *bs, void (*change_cb)(void *opaque), void *opaque); void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); -- cgit v1.2.3 From a9f277ba8f9490fc01b9d518ed6932c816fa4604 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 11:58:10 +0000 Subject: no need for bdrv_close() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2125 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/scsi-disk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 55a26239d..213e8d293 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -545,7 +545,6 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) void scsi_disk_destroy(SCSIDevice *s) { - bdrv_close(s->bdrv); qemu_free(s); } -- cgit v1.2.3 From b56bdb328a9abae5035488e885c8e5fbaa5ce980 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 11:58:59 +0000 Subject: delete block device git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2126 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-msd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 7d1f35d06..e4cfca0fe 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -35,6 +35,7 @@ typedef struct { uint32_t data_len; uint32_t transfer_len; uint32_t tag; + BlockDriverState *bs; SCSIDevice *scsi_dev; int result; /* For async completion. */ @@ -406,6 +407,7 @@ static void usb_msd_handle_destroy(USBDevice *dev) MSDState *s = (MSDState *)dev; scsi_disk_destroy(s->scsi_dev); + bdrv_delete(s->bs); qemu_free(s); } @@ -419,7 +421,9 @@ USBDevice *usb_msd_init(const char *filename) return NULL; bdrv = bdrv_new("usb"); - bdrv_open(bdrv, filename, 0); + if (bdrv_open(bdrv, filename, 0) < 0) + goto fail; + s->bs = bdrv; s->dev.speed = USB_SPEED_FULL; s->dev.handle_packet = usb_generic_handle_packet; @@ -435,4 +439,7 @@ USBDevice *usb_msd_init(const char *filename) s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); usb_msd_handle_reset((USBDevice *)s); return (USBDevice *)s; + fail: + qemu_free(s); + return NULL; } -- cgit v1.2.3 From e6cda8e299318e0e54fabea4c74c0bd839547ea7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 12:37:52 +0000 Subject: win32 tap poll suppression (kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2127 c046a42c-6fe2-441c-8c8c-71466251a162 --- tap-win32.c | 27 +++++++++------------------ vl.c | 3 --- vl.h | 1 - 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/tap-win32.c b/tap-win32.c index af5e25e68..d84a622d3 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -97,6 +97,7 @@ typedef struct tap_win32_overlapped { HANDLE write_event; HANDLE output_queue_semaphore; HANDLE free_list_semaphore; + HANDLE tap_semaphore; CRITICAL_SECTION output_queue_cs; CRITICAL_SECTION free_list_cs; OVERLAPPED read_overlapped; @@ -445,6 +446,10 @@ static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, overlapped->free_list = element; } } + /* To count buffers, initially no-signal. */ + overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL); + if(!overlapped->tap_semaphore) + fprintf(stderr, "error creating tap_semaphore.\n"); } static int tap_win32_write(tap_win32_overlapped_t *overlapped, @@ -526,6 +531,7 @@ static DWORD WINAPI tap_win32_thread_entry(LPVOID param) if(read_size > 0) { buffer->read_size = read_size; put_buffer_on_output_queue(overlapped, buffer); + ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL); buffer = get_buffer_from_free_list(overlapped); } } @@ -620,8 +626,6 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, hThread = CreateThread(NULL, 0, tap_win32_thread_entry, (LPVOID)&tap_overlapped, 0, &idThread); - SetThreadPriority(hThread,THREAD_PRIORITY_TIME_CRITICAL); - return 0; } @@ -630,11 +634,8 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, typedef struct TAPState { VLANClientState *vc; tap_win32_overlapped_t *handle; - HANDLE tap_event; } TAPState; -static TAPState *tap_win32_state = NULL; - static void tap_receive(void *opaque, const uint8_t *buf, int size) { TAPState *s = opaque; @@ -642,22 +643,17 @@ static void tap_receive(void *opaque, const uint8_t *buf, int size) tap_win32_write(s->handle, buf, size); } -/* XXX: horrible, suppress this by using proper thread signaling */ -void tap_win32_poll(void) +static void tap_win32_send(void *opaque) { - TAPState *s = tap_win32_state; + TAPState *s = opaque; uint8_t *buf; int max_size = 4096; int size; - if (!s) - return; - size = tap_win32_read(s->handle, &buf, max_size); if (size > 0) { qemu_send_packet(s->vc, buf, size); tap_win32_free_buffer(s->handle, buf); - SetEvent(s->tap_event); } } @@ -677,12 +673,7 @@ int tap_win32_init(VLANState *vlan, const char *ifname) snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s", ifname); - tap_win32_state = s; - s->tap_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!s->tap_event) { - fprintf(stderr, "tap-win32: Failed CreateEvent\n"); - } - qemu_add_wait_object(s->tap_event, NULL, NULL); + qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s); return 0; } diff --git a/vl.c b/vl.c index 29142e1f6..771903099 100644 --- a/vl.c +++ b/vl.c @@ -5714,9 +5714,6 @@ void main_loop_wait(int timeout) } slirp_select_poll(&rfds, &wfds, &xfds); } -#endif -#ifdef _WIN32 - tap_win32_poll(); #endif qemu_aio_poll(); qemu_bh_poll(); diff --git a/vl.h b/vl.h index 4bef80192..461caea02 100644 --- a/vl.h +++ b/vl.h @@ -348,7 +348,6 @@ void do_info_network(void); /* TAP win32 */ int tap_win32_init(VLANState *vlan, const char *ifname); -void tap_win32_poll(void); /* NIC info */ -- cgit v1.2.3 From f0e421721302eec09bb085a6b5002d040521b9b8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 12:38:38 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2128 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 8d36cbbe4..0ce7372a3 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ version 0.8.3: - Async file I/O API - New qcow2 disk image format - Support of multiple VM snapshots + - Linux: specific host CDROM and floppy support version 0.8.2: -- cgit v1.2.3 From 60659e3b4488a6947a4ee2835f669b5d5463e34e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 14:27:31 +0000 Subject: Japanese keyboard fixes (kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2129 c046a42c-6fe2-441c-8c8c-71466251a162 --- keymaps/ja | 1 + sdl.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/keymaps/ja b/keymaps/ja index 8fd0b9ef1..ae513c7ee 100644 --- a/keymaps/ja +++ b/keymaps/ja @@ -97,6 +97,7 @@ Eisu_toggle 0x3a shift Execute 0x54 shift Kanji 0x70 backslash 0x73 +yen 0x7d bar 0x7d shift underscore 0x73 shift Henkan_Mode 0x79 diff --git a/sdl.c b/sdl.c index 00f574640..e65dcac9c 100644 --- a/sdl.c +++ b/sdl.c @@ -104,6 +104,10 @@ static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev) keysym = ev->keysym.sym; if (keysym == 0 && ev->keysym.scancode == 113) keysym = SDLK_MODE; + /* For Japanese key '\' and '|' */ + if (keysym == 92 && ev->keysym.scancode == 133) { + keysym = 0xa5; + } return keysym2scancode(kbd_layout, keysym); } @@ -118,7 +122,7 @@ static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) #else -static const uint8_t x_keycode_to_pc_keycode[61] = { +static const uint8_t x_keycode_to_pc_keycode[115] = { 0xc7, /* 97 Home */ 0xc8, /* 98 Up */ 0xc9, /* 99 PgUp */ @@ -142,10 +146,10 @@ static const uint8_t x_keycode_to_pc_keycode[61] = { 0x0, /* 117 */ 0x0, /* 118 */ 0x0, /* 119 */ - 0x70, /* 120 Hiragana_Katakana */ + 0x0, /* 120 */ 0x0, /* 121 */ 0x0, /* 122 */ - 0x73, /* 123 backslash */ + 0x0, /* 123 */ 0x0, /* 124 */ 0x0, /* 125 */ 0x0, /* 126 */ @@ -180,6 +184,24 @@ static const uint8_t x_keycode_to_pc_keycode[61] = { 0x51, /* 155 KP_PgDn */ 0x52, /* 156 KP_Ins */ 0x53, /* 157 KP_Del */ + 0x0, /* 158 */ + 0x0, /* 159 */ + 0x0, /* 160 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 170 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 180 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 190 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 200 */ + 0x0, /* 201 */ + 0x0, /* 202 */ + 0x0, /* 203 */ + 0x0, /* 204 */ + 0x0, /* 205 */ + 0x0, /* 206 */ + 0x0, /* 207 */ + 0x70, /* 208 Hiragana_Katakana */ + 0x0, /* 209 */ + 0x0, /* 210 */ + 0x73, /* 211 backslash */ }; static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) @@ -192,7 +214,7 @@ static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) keycode = 0; } else if (keycode < 97) { keycode -= 8; /* just an offset */ - } else if (keycode < 158) { + } else if (keycode < 212) { /* use conversion table */ keycode = x_keycode_to_pc_keycode[keycode - 97]; } else { -- cgit v1.2.3 From ee0f47514ce64070b942125bf90bb93a48f112eb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 16:56:18 +0000 Subject: removed outdated info git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2130 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 152 +++++++--------------------------------------------------- 1 file changed, 18 insertions(+), 134 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 40667e3f4..a9ffe7f2f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1115,9 +1115,8 @@ contained in @file{qemu-ifup} can be executed as root. You must verify that your host kernel supports the TAP network interfaces: the device @file{/dev/net/tun} must be present. -See @ref{direct_linux_boot} to have an example of network use with a -Linux distribution and @ref{sec_invocation} to have examples of -command lines using the TAP network interfaces. +See @ref{sec_invocation} to have examples of command lines using the +TAP network interfaces. @subsection Using the user mode network stack @@ -1167,146 +1166,31 @@ basic example. This section explains how to launch a Linux kernel inside QEMU without having to make a full bootable image. It is very useful for fast Linux -kernel testing. The QEMU network configuration is also explained. +kernel testing. -@enumerate -@item -Download the archive @file{linux-test-xxx.tar.gz} containing a Linux -kernel and a disk image. - -@item Optional: If you want network support (for example to launch X11 examples), you -must copy the script @file{qemu-ifup} in @file{/etc} and configure -properly @code{sudo} so that the command @code{ifconfig} contained in -@file{qemu-ifup} can be executed as root. You must verify that your host -kernel supports the TUN/TAP network interfaces: the device -@file{/dev/net/tun} must be present. - -When network is enabled, there is a virtual network connection between -the host kernel and the emulated kernel. The emulated kernel is seen -from the host kernel at IP address 172.20.0.2 and the host kernel is -seen from the emulated kernel at IP address 172.20.0.1. - -@item Launch @code{qemu.sh}. You should have the following output: - -@smallexample -> ./qemu.sh -Connected to host network interface: tun0 -Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 @/(Red Hat @/Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 -BIOS-provided physical RAM map: - BIOS-e801: 0000000000000000 - 000000000009f000 (usable) - BIOS-e801: 0000000000100000 - 0000000002000000 (usable) -32MB LOWMEM available. -On node 0 totalpages: 8192 -zone(0): 4096 pages. -zone(1): 4096 pages. -zone(2): 0 pages. -Kernel command line: root=/dev/hda sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe @/ide5=noprobe console=ttyS0 -ide_setup: ide2=noprobe -ide_setup: ide3=noprobe -ide_setup: ide4=noprobe -ide_setup: ide5=noprobe -Initializing CPU#0 -Detected 2399.621 MHz processor. -Console: colour EGA 80x25 -Calibrating delay loop... 4744.80 BogoMIPS -Memory: 28872k/32768k available (1210k kernel code, 3508k reserved, 266k data, 64k init, @/0k highmem) -Dentry cache hash table entries: 4096 (order: 3, 32768 bytes) -Inode cache hash table entries: 2048 (order: 2, 16384 bytes) -Mount cache hash table entries: 512 (order: 0, 4096 bytes) -Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes) -Page-cache hash table entries: 8192 (order: 3, 32768 bytes) -CPU: Intel Pentium Pro stepping 03 -Checking 'hlt' instruction... OK. -POSIX conformance testing by UNIFIX -Linux NET4.0 for Linux 2.4 -Based upon Swansea University Computer Society NET3.039 -Initializing RT netlink socket -apm: BIOS not found. -Starting kswapd -Journalled Block Device driver loaded -Detected PS/2 Mouse Port. -pty: 256 Unix98 ptys configured -Serial driver version 5.05c (2001-07-08) with no serial options enabled -ttyS00 at 0x03f8 (irq = 4) is a 16450 -ne.c:v1.10 9/23/94 Donald Becker (becker@@scyld.com) -Last modified Nov 1, 2000 by Paul Gortmaker -NE*000 ethercard probe at 0x300: 52 54 00 12 34 56 -eth0: NE2000 found at 0x300, using IRQ 9. -RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize -Uniform Multi-Platform E-IDE driver Revision: 7.00beta4-2.4 -ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx -hda: QEMU HARDDISK, ATA DISK drive -ide0 at 0x1f0-0x1f7,0x3f6 on irq 14 -hda: attached ide-disk driver. -hda: 20480 sectors (10 MB) w/256KiB Cache, CHS=20/16/63 -Partition check: - hda: -Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996 -NET4: Linux TCP/IP 1.0 for NET4.0 -IP Protocols: ICMP, UDP, TCP, IGMP -IP: routing cache hash table of 512 buckets, 4Kbytes -TCP: Hash tables configured (established 2048 bind 4096) -NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. -EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended -VFS: Mounted root (ext2 filesystem). -Freeing unused kernel memory: 64k freed - -Linux version 2.4.21 (bellard@@voyager.localdomain) (gcc version 3.2.2 20030222 @/(Red Hat @/Linux 3.2.2-5)) #5 Tue Nov 11 18:18:53 CET 2003 - -QEMU Linux test distribution (based on Redhat 9) - -Type 'exit' to halt the system - -sh-2.05b# -@end smallexample - -@item -Then you can play with the kernel inside the virtual serial console. You -can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help -about the keys you can type inside the virtual serial console. In -particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as -the Magic SysRq key. - -@item -If the network is enabled, launch the script @file{/etc/linuxrc} in the -emulator (don't forget the leading dot): +The syntax is: @example -. /etc/linuxrc +qemu -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda" @end example -Then enable X11 connections on your PC from the emulated Linux: -@example -xhost +172.20.0.2 -@end example - -You can now launch @file{xterm} or @file{xlogo} and verify that you have -a real Virtual Linux system ! - -@end enumerate +Use @option{-kernel} to provide the Linux kernel image and +@option{-append} to give the kernel command line arguments. The +@option{-initrd} option can be used to provide an INITRD image. -NOTES: -@enumerate -@item -A 2.5.74 kernel is also included in the archive. Just -replace the bzImage in qemu.sh to try it. - -@item -In order to exit cleanly from qemu, you can do a @emph{shutdown} inside -qemu. qemu will automatically exit when the Linux shutdown is done. +When using the direct Linux boot, a disk image for the first hard disk +@file{hda} is required because its boot sector is used to launch the +Linux kernel. -@item -You can boot slightly faster by disabling the probe of non present IDE -interfaces. To do so, add the following options on the kernel command -line: +If you do not need graphical output, you can disable it and redirect +the virtual serial port and the QEMU monitor to the console with the +@option{-nographic} option. The typical command line is: @example -ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe +qemu -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \ + -append "root=/dev/hda console=ttyS0" -nographic @end example -@item -The example disk image is a modified version of the one made by Kevin -Lawton for the plex86 Project (@url{www.plex86.org}). - -@end enumerate +Use @key{Ctrl-a c} to switch between the serial console and the +monitor (@pxref{pcsys_keys}). @node pcsys_usb @section USB emulation -- cgit v1.2.3 From f542086dd4a37e08a429183181fd249c30660d96 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Aug 2006 20:26:44 +0000 Subject: spelling fixes (Stefan Weil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2131 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index a9ffe7f2f..61796bfd9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -559,8 +559,8 @@ localhost 5555 The TCP Net Console has two modes of operation. It can send the serial I/O to a location or wait for a connection from a location. By default the TCP Net Console is sent to @var{host} at the @var{port}. If you use -the @var{,server} option QEMU will wait for a client socket application -to connect to the port before continuing, unless the @code{,nowait} +the @var{server} option QEMU will wait for a client socket application +to connect to the port before continuing, unless the @code{nowait} option was specified. If @var{host} is omitted, 0.0.0.0 is assumed. Only one TCP connection at a time is accepted. You can use @code{telnet} to connect to the corresponding character device. @@ -1011,7 +1011,7 @@ disk image filename provided you have enough proviledge to access it. For example, use @file{/dev/cdrom} to access to the CDROM or @file{/dev/fd0} for the floppy. -@table +@table @code @item CD You can specify a CDROM device even if no CDROM is loaded. QEMU has specific code to detect CDROM insertion or removal. CDROM ejection by @@ -1198,7 +1198,7 @@ monitor (@pxref{pcsys_keys}). QEMU emulates a PCI UHCI USB controller. You can virtually plug virtual USB devices or real host USB devices (experimental, works only on Linux hosts). Qemu will automatically create and connect virtual USB hubs -as neccessary to connect multiple USB devices. +as necessary to connect multiple USB devices. @menu * usb_devices:: -- cgit v1.2.3 From 2192c33250878c6e9c78820766afe42b73fd1c2f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 21 Aug 2006 20:28:18 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2132 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 61796bfd9..3bf3b5cd9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1387,7 +1387,7 @@ correctly instructs QEMU to shutdown at the appropriate moment. See @ref{sec_invocation} about the help of the option @option{-smb}. -@subsubsection Windows XP security problems +@subsubsection Windows XP security problem Some releases of Windows XP install correctly but give a security error when booting: @@ -1395,10 +1395,12 @@ error when booting: A problem is preventing Windows from accurately checking the license for this computer. Error code: 0x800703e6. @end example -The only known workaround is to boot in Safe mode -without networking support. -Future QEMU releases are likely to correct this bug. +The workaround is to install a service pack for XP after a boot in safe +mode. Then reboot, and the problem should go away. Since there is no +network while in safe mode, its recommended to download the full +installation of SP1 or SP2 and transfer that via an ISO or using the +vvfat block device ("-hdb fat:directory_which_holds_the_SP"). @subsection MS-DOS and FreeDOS -- cgit v1.2.3 From 6b21b973ab9aa2bfc3ebfe1df4474466ceb4d88b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Aug 2006 21:14:37 +0000 Subject: fixed error handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2133 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 885b70023..3b35500b7 100644 --- a/block.c +++ b/block.c @@ -365,6 +365,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, } if (ret < 0) { qemu_free(bs->opaque); + bs->opaque = NULL; + bs->drv = NULL; return ret; } if (drv->bdrv_getlength) { @@ -381,7 +383,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, if (!bs->backing_hd) { fail: bdrv_close(bs); - return -1; + return -ENOMEM; } path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); -- cgit v1.2.3 From f45512feac6622615e08cca33d172abb87b01921 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 23 Aug 2006 21:40:13 +0000 Subject: win32 compilation fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2134 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 40 ++++++++++++---------------------------- block.c | 15 +++++++++++---- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/block-raw.c b/block-raw.c index 4dc0b9a74..84fdff787 100644 --- a/block-raw.c +++ b/block-raw.c @@ -826,7 +826,7 @@ BlockDriver bdrv_host_device = { typedef struct BDRVRawState { HANDLE hfile; int type; - char drive_letter[2]; + char drive_path[16]; /* format: "d:\" */ } BDRVRawState; typedef struct RawAIOCB { @@ -876,23 +876,8 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) BDRVRawState *s = bs->opaque; int access_flags, create_flags; DWORD overlapped; - char device_name[64]; - const char *p; - 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(filename); + s->type = FTYPE_FILE; if ((flags & BDRV_O_ACCESS) == O_RDWR) { access_flags = GENERIC_READ | GENERIC_WRITE; @@ -1089,22 +1074,22 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset) return 0; } -static int64_t raw_getlength(BlockDriverState *bs) +static int64_t raw_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; LARGE_INTEGER l; ULARGE_INTEGER available, total, total_free; - switch(s->ftype) { + 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_letter, &available, &total, &total_free)) + if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free)) return -EIO; - l = total; + l.QuadPart = total.QuadPart; break; default: return -EIO; @@ -1182,7 +1167,7 @@ static int find_cdrom(char *cdrom_name, int cdrom_name_size) char drives[256], *pdrv = drives; UINT type; - memset(drives, 0, sizeof(drivers)); + memset(drives, 0, sizeof(drives)); GetLogicalDriveStrings(sizeof(drives), drives); while(pdrv[0] != '\0') { type = GetDriveType(pdrv); @@ -1197,16 +1182,16 @@ static int find_cdrom(char *cdrom_name, int cdrom_name_size) return -1; } -static int find_device_type(const char *filename) +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)) { - s->drive_letter[0] = p[0]; - s->drive_letter[1] = '\0'; - type = GetDriveType(s->drive_letter); + snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]); + type = GetDriveType(s->drive_path); if (type == DRIVE_CDROM) return FTYPE_CD; else @@ -1222,7 +1207,6 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) int access_flags, create_flags; DWORD overlapped; char device_name[64]; - const char *p; if (strstart(filename, "/dev/cdrom", NULL)) { if (find_cdrom(device_name, sizeof(device_name)) < 0) @@ -1237,7 +1221,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) filename = device_name; } } - s->type = find_device_type(filename); + s->type = find_device_type(bs, filename); if ((flags & BDRV_O_ACCESS) == O_RDWR) { access_flags = GENERIC_READ | GENERIC_WRITE; diff --git a/block.c b/block.c index 3b35500b7..12fc2ef45 100644 --- a/block.c +++ b/block.c @@ -182,11 +182,17 @@ void get_tmp_filename(char *filename, int size) #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 (((filename[0] >= 'a' && filename[0] <= 'z') || - (filename[0] >= 'A' && filename[0] <= 'Z')) && - filename[1] == ':' && filename[2] == '\0') + if (is_windows_drive_prefix(filename) && + filename[2] == '\0') return 1; if (strstart(filename, "\\\\.\\", NULL) || strstart(filename, "//./", NULL)) @@ -203,7 +209,8 @@ static BlockDriver *find_protocol(const char *filename) const char *p; #ifdef _WIN32 - if (is_windows_drive(filename)) + if (is_windows_drive(filename) || + is_windows_drive_prefix(filename)) return &bdrv_raw; #endif p = strchr(filename, ':'); -- cgit v1.2.3 From fd44d818219dc62f14d3f22d4d5cff5595a729e9 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 24 Aug 2006 18:58:29 +0000 Subject: win32 aio emulation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2135 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block-raw.c b/block-raw.c index 84fdff787..3ed4b32de 100644 --- a/block-raw.c +++ b/block-raw.c @@ -1129,6 +1129,9 @@ void qemu_aio_wait_start(void) void qemu_aio_wait(void) { +#ifndef QEMU_TOOL + qemu_bh_poll(); +#endif } void qemu_aio_wait_end(void) -- cgit v1.2.3 From a817d93656eb534cdbaaea68e44e5325169ad697 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 24 Aug 2006 19:53:37 +0000 Subject: fixed handling of relative filenames with -snapshot git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2136 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 12fc2ef45..fdaba4bca 100644 --- a/block.c +++ b/block.c @@ -335,8 +335,9 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bdrv_delete(bs1); get_tmp_filename(tmp_filename, sizeof(tmp_filename)); + realpath(filename, backing_filename); if (bdrv_create(&bdrv_qcow2, tmp_filename, - total_size, filename, 0) < 0) { + total_size, backing_filename, 0) < 0) { return -1; } filename = tmp_filename; -- cgit v1.2.3 From 64f5a135a7fee4e95efa08861698373b30a23bb0 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 24 Aug 2006 20:36:44 +0000 Subject: signed fixes - VNC console switch (initial patch by Andrzej Zaborowski) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2137 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 11 deletions(-) diff --git a/vnc.c b/vnc.c index 1bea9661d..19aa4b746 100644 --- a/vnc.c +++ b/vnc.c @@ -81,6 +81,8 @@ struct VncState VncReadEvent *read_handler; size_t read_handler_expect; + /* input */ + uint8_t modifiers_state[256]; }; /* TODO @@ -622,7 +624,7 @@ static void vnc_write_u32(VncState *vs, uint32_t value) static void vnc_write_u16(VncState *vs, uint16_t value) { - char buf[2]; + uint8_t buf[2]; buf[0] = (value >> 8) & 0xFF; buf[1] = value & 0xFF; @@ -641,23 +643,23 @@ static void vnc_flush(VncState *vs) vnc_client_write(vs); } -static uint8_t read_u8(char *data, size_t offset) +static uint8_t read_u8(uint8_t *data, size_t offset) { return data[offset]; } -static uint16_t read_u16(char *data, size_t offset) +static uint16_t read_u16(uint8_t *data, size_t offset) { return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); } -static int32_t read_s32(char *data, size_t offset) +static int32_t read_s32(uint8_t *data, size_t offset) { return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); } -static uint32_t read_u32(char *data, size_t offset) +static uint32_t read_u32(uint8_t *data, size_t offset) { return ((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]); @@ -699,18 +701,99 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) } } +static void reset_keys(VncState *vs) +{ + int i; + for(i = 0; i < 256; i++) { + if (vs->modifiers_state[i]) { + if (i & 0x80) + kbd_put_keycode(0xe0); + kbd_put_keycode(i | 0x80); + vs->modifiers_state[i] = 0; + } + } +} + static void do_key_event(VncState *vs, int down, uint32_t sym) { int keycode; keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); + + /* QEMU console switch */ + switch(keycode) { + case 0x2a: /* Left Shift */ + case 0x36: /* Right Shift */ + case 0x1d: /* Left CTRL */ + case 0x9d: /* Right CTRL */ + case 0x38: /* Left ALT */ + case 0xb8: /* Right ALT */ + if (down) + vs->modifiers_state[keycode] = 1; + else + vs->modifiers_state[keycode] = 0; + break; + case 0x02 ... 0x0a: /* '1' to '9' keys */ + if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) { + /* Reset the modifiers sent to the current console */ + reset_keys(vs); + console_select(keycode - 0x02); + return; + } + break; + } - if (keycode & 0x80) - kbd_put_keycode(0xe0); - if (down) - kbd_put_keycode(keycode & 0x7f); - else - kbd_put_keycode(keycode | 0x80); + if (is_graphic_console()) { + if (keycode & 0x80) + kbd_put_keycode(0xe0); + if (down) + kbd_put_keycode(keycode & 0x7f); + else + kbd_put_keycode(keycode | 0x80); + } else { + /* QEMU console emulation */ + if (down) { + switch (keycode) { + case 0x2a: /* Left Shift */ + case 0x36: /* Right Shift */ + case 0x1d: /* Left CTRL */ + case 0x9d: /* Right CTRL */ + case 0x38: /* Left ALT */ + case 0xb8: /* Right ALT */ + break; + case 0xc8: + kbd_put_keysym(QEMU_KEY_UP); + break; + case 0xd0: + kbd_put_keysym(QEMU_KEY_DOWN); + break; + case 0xcb: + kbd_put_keysym(QEMU_KEY_LEFT); + break; + case 0xcd: + kbd_put_keysym(QEMU_KEY_RIGHT); + break; + case 0xd3: + kbd_put_keysym(QEMU_KEY_DELETE); + break; + case 0xc7: + kbd_put_keysym(QEMU_KEY_HOME); + break; + case 0xcf: + kbd_put_keysym(QEMU_KEY_END); + break; + case 0xc9: + kbd_put_keysym(QEMU_KEY_PAGEUP); + break; + case 0xd1: + kbd_put_keysym(QEMU_KEY_PAGEDOWN); + break; + default: + kbd_put_keysym(sym); + break; + } + } + } } static void key_event(VncState *vs, int down, uint32_t sym) -- cgit v1.2.3 From 508d92d0573319d7dbd827f6216aec44c1421832 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 26 Aug 2006 18:00:36 +0000 Subject: 16 bit divider git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2138 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/serial.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index f36beb209..16dbc65c3 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -71,7 +71,7 @@ #define UART_LSR_DR 0x01 /* Receiver data ready */ struct SerialState { - uint8_t divider; + uint16_t divider; uint8_t rbr; /* receive register */ uint8_t ier; uint8_t iir; /* read only */ @@ -310,7 +310,7 @@ static void serial_save(QEMUFile *f, void *opaque) { SerialState *s = opaque; - qemu_put_8s(f,&s->divider); + qemu_put_be16s(f,&s->divider); qemu_put_8s(f,&s->rbr); qemu_put_8s(f,&s->ier); qemu_put_8s(f,&s->iir); @@ -325,10 +325,13 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id) { SerialState *s = opaque; - if(version_id != 1) + if(version_id > 2) return -EINVAL; - qemu_get_8s(f,&s->divider); + if (version_id >= 2) + qemu_get_be16s(f, &s->divider); + else + s->divider = qemu_get_byte(f); qemu_get_8s(f,&s->rbr); qemu_get_8s(f,&s->ier); qemu_get_8s(f,&s->iir); @@ -357,7 +360,7 @@ SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, s->iir = UART_IIR_NO_INT; s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; - register_savevm("serial", base, 1, serial_save, serial_load, s); + register_savevm("serial", base, 2, serial_save, serial_load, s); register_ioport_write(base, 8, 1, serial_ioport_write, s); register_ioport_read(base, 8, 1, serial_ioport_read, s); @@ -444,7 +447,7 @@ SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, s->base = base; s->it_shift = it_shift; - register_savevm("serial", base, 1, serial_save, serial_load, s); + register_savevm("serial", base, 2, serial_save, serial_load, s); s_io_memory = cpu_register_io_memory(0, serial_mm_read, serial_mm_write, s); -- cgit v1.2.3 From a917d384ac0d09cd68266a6f2ca5c94212c8f81e Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 29 Aug 2006 04:52:16 +0000 Subject: SCSI TCQ support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2139 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 125 +++++++------- hw/iommu.c | 51 +++++- hw/lsi53c895a.c | 467 ++++++++++++++++++++++++++++++++++++++++------------ hw/scsi-disk.c | 494 ++++++++++++++++++++++++++++++-------------------------- hw/sun4m.c | 12 ++ hw/usb-msd.c | 213 +++++++++++++++++------- vl.h | 21 ++- 7 files changed, 932 insertions(+), 451 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index d67dbf3f3..991e5151f 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -64,8 +64,7 @@ struct ESPState { int do_cmd; uint32_t dma_left; - uint8_t async_buf[TARGET_PAGE_SIZE]; - uint32_t async_ptr; + uint8_t *async_buf; uint32_t async_len; }; @@ -91,17 +90,16 @@ struct ESPState { static int get_cmd(ESPState *s, uint8_t *buf) { - uint32_t dmaptr, dmalen; + uint32_t dmalen; int target; dmalen = s->wregs[0] | (s->wregs[1] << 8); target = s->wregs[4] & 7; DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { - dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr); - cpu_physical_memory_read(dmaptr, buf, dmalen); + s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->espdmaregs[1]); + sparc_iommu_memory_read(s->espdmaregs[1], buf, dmalen); } else { buf[0] = 0; memcpy(&buf[1], s->ti_buf, dmalen); @@ -112,6 +110,12 @@ static int get_cmd(ESPState *s, uint8_t *buf) s->ti_rptr = 0; s->ti_wptr = 0; + if (s->current_dev) { + /* Started a new command before the old one finished. Cancel it. */ + scsi_cancel_io(s->current_dev, 0); + s->async_len = 0; + } + if (target >= 4 || !s->scsi_dev[target]) { // No such drive s->rregs[4] = STAT_IN; @@ -137,12 +141,15 @@ static void do_cmd(ESPState *s, uint8_t *buf) s->ti_size = 0; } else { s->rregs[4] = STAT_IN | STAT_TC; + s->dma_left = 0; if (datalen > 0) { s->rregs[4] |= STAT_DI; s->ti_size = datalen; + scsi_read_data(s->current_dev, 0); } else { s->rregs[4] |= STAT_DO; s->ti_size = -datalen; + scsi_write_data(s->current_dev, 0); } } s->rregs[5] = INTR_BS | INTR_FC; @@ -178,16 +185,13 @@ static void handle_satn_stop(ESPState *s) static void write_response(ESPState *s) { - uint32_t dmaptr; - DPRINTF("Transfer status (sense=%d)\n", s->sense); s->ti_buf[0] = s->sense; s->ti_buf[1] = 0; if (s->dma) { - dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); - cpu_physical_memory_write(dmaptr, s->ti_buf, 2); + sparc_iommu_memory_write(s->espdmaregs[1], s->ti_buf, 2); s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; @@ -202,78 +206,89 @@ static void write_response(ESPState *s) } +static void esp_dma_done(ESPState *s) +{ + s->rregs[4] |= STAT_IN | STAT_TC; + s->rregs[5] = INTR_BS; + s->rregs[6] = 0; + s->rregs[7] = 0; + s->espdmaregs[0] |= DMA_INTR; + pic_set_irq(s->irq, 1); +} + static void esp_do_dma(ESPState *s) { - uint32_t dmaptr, minlen, len, from, to; + uint32_t addr, len; int to_device; + to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; - from = s->espdmaregs[1]; - minlen = s->dma_left; - to = from + minlen; - dmaptr = iommu_translate(s->espdmaregs[1]); - if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { - len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); - } else { - len = to - from; - } - DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1], len, from, to); + addr = s->espdmaregs[1]; + len = s->dma_left; + DPRINTF("DMA address %08x len %08x\n", addr, len); if (s->do_cmd) { s->espdmaregs[1] += len; s->ti_size -= len; DPRINTF("command len %d + %d\n", s->cmdlen, len); - cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); + sparc_iommu_memory_read(addr, &s->cmdbuf[s->cmdlen], len); s->ti_size = 0; s->cmdlen = 0; s->do_cmd = 0; do_cmd(s, s->cmdbuf); return; + } + if (s->async_len == 0) { + /* Defer until data is available. */ + return; + } + if (len > s->async_len) { + len = s->async_len; + } + if (to_device) { + sparc_iommu_memory_read(addr, s->async_buf, len); } else { - s->async_len = len; - s->dma_left -= len; + sparc_iommu_memory_write(addr, s->async_buf, len); + } + s->ti_size -= len; + s->dma_left -= len; + s->async_buf += len; + s->async_len -= len; + s->espdmaregs[1] += len; + if (s->async_len == 0) { if (to_device) { - s->async_ptr = -1; - cpu_physical_memory_read(dmaptr, s->async_buf, len); - scsi_write_data(s->current_dev, s->async_buf, len); + scsi_write_data(s->current_dev, 0); } else { - s->async_ptr = dmaptr; - scsi_read_data(s->current_dev, s->async_buf, len); + scsi_read_data(s->current_dev, 0); } } + if (s->dma_left == 0) { + esp_dma_done(s); + } } -static void esp_command_complete(void *opaque, uint32_t reason, int sense) +static void esp_command_complete(void *opaque, int reason, uint32_t tag, + uint32_t arg) { ESPState *s = (ESPState *)opaque; - s->ti_size -= s->async_len; - s->espdmaregs[1] += s->async_len; - if (s->async_ptr != (uint32_t)-1) { - cpu_physical_memory_write(s->async_ptr, s->async_buf, s->async_len); - } if (reason == SCSI_REASON_DONE) { DPRINTF("SCSI Command complete\n"); if (s->ti_size != 0) DPRINTF("SCSI command completed unexpectedly\n"); s->ti_size = 0; - if (sense) + s->dma_left = 0; + s->async_len = 0; + if (arg) DPRINTF("Command failed\n"); - s->sense = sense; + s->sense = arg; + s->rregs[4] = STAT_ST; + esp_dma_done(s); + s->current_dev = NULL; } else { DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); - } - if (s->dma_left) { - esp_do_dma(s); - } else { - if (s->ti_size) { - s->rregs[4] |= STAT_IN | STAT_TC; - } else { - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - } - s->rregs[5] = INTR_BS; - s->rregs[6] = 0; - s->rregs[7] = 0; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + s->async_len = arg; + s->async_buf = scsi_get_buf(s->current_dev, 0); + if (s->dma_left) + esp_do_dma(s); } } @@ -333,7 +348,8 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) s->ti_size--; if ((s->rregs[4] & 6) == 0) { /* Data in/out. */ - scsi_read_data(s->current_dev, &s->rregs[2], 0); + fprintf(stderr, "esp: PIO data read not implemented\n"); + s->rregs[2] = 0; } else { s->rregs[2] = s->ti_buf[s->ti_rptr++]; } @@ -378,7 +394,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) uint8_t buf; buf = val & 0xff; s->ti_size--; - scsi_write_data(s->current_dev, &buf, 0); + fprintf(stderr, "esp: PIO data write not implemented\n"); } else { s->ti_size++; s->ti_buf[s->ti_wptr++] = val & 0xff; @@ -590,8 +606,9 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd qemu_register_reset(esp_reset, s); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { + /* Command queueing is not implemented. */ s->scsi_dev[i] = - scsi_disk_init(bs_table[i], esp_command_complete, s); + scsi_disk_init(bs_table[i], 0, esp_command_complete, s); } } } diff --git a/hw/iommu.c b/hw/iommu.c index e7d96c81c..83001bd7f 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -186,21 +186,62 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { iommu_mem_writew, }; -uint32_t iommu_translate_local(void *opaque, uint32_t addr) +static uint32_t iommu_page_get_flags(IOMMUState *s, uint32_t addr) { - IOMMUState *s = opaque; - uint32_t iopte, pa, tmppte; + uint32_t iopte; iopte = s->regs[1] << 4; addr &= ~s->iostart; iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; - pa = ldl_phys(iopte); + return ldl_phys(iopte); +} + +static uint32_t iommu_translate_pa(IOMMUState *s, uint32_t addr, uint32_t pa) +{ + uint32_t tmppte; + tmppte = pa; pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); - DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte); + DPRINTF("xlate dva %x => pa %x (iopte = %x)\n", addr, pa, tmppte); return pa; } +uint32_t iommu_translate_local(void *opaque, uint32_t addr) +{ + uint32_t flags; + flags = iommu_page_get_flags(opaque, addr); + return iommu_translate_pa(opaque, addr, flags); +} + +void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int is_write) +{ + int l, flags; + target_ulong page, phys_addr; + void * p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + flags = iommu_page_get_flags(opaque, page); + if (!(flags & IOPTE_VALID)) + return; + phys_addr = iommu_translate_pa(opaque, addr, flags); + if (is_write) { + if (!(flags & IOPTE_WRITE)) + return; + cpu_physical_memory_write(phys_addr, buf, len); + } else { + cpu_physical_memory_read(phys_addr, buf, len); + } + len -= l; + buf += l; + addr += l; + } +} + static void iommu_save(QEMUFile *f, void *opaque) { IOMMUState *s = opaque; diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 8f5672534..41c1ff22d 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -19,11 +19,11 @@ #define DPRINTF(fmt, args...) \ do { printf("lsi_scsi: " fmt , ##args); } while (0) #define BADF(fmt, args...) \ -do { fprintf(stderr, "lsi_scsi: " fmt , ##args); exit(1);} while (0) +do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args); exit(1);} while (0) #else #define DPRINTF(fmt, args...) do {} while(0) #define BADF(fmt, args...) \ -do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) +do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args);} while (0) #endif #define LSI_SCNTL0_TRG 0x01 @@ -152,26 +152,46 @@ do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) /* The HBA is ID 7, so for simplicitly limit to 7 devices. */ #define LSI_MAX_DEVS 7 -/* Size of internal DMA buffer for async IO requests. */ -#define LSI_DMA_BLOCK_SIZE 0x10000 +/* Maximum length of MSG IN data. */ +#define LSI_MAX_MSGIN_LEN 8 + +/* Flag set if this is a tagged command. */ +#define LSI_TAG_VALID (1 << 16) + +typedef struct { + uint32_t tag; + uint32_t pending; + int out; +} lsi_queue; typedef struct { PCIDevice pci_dev; int mmio_io_addr; int ram_io_addr; uint32_t script_ram_base; - uint32_t data_len; int carry; /* ??? Should this be an a visible register somewhere? */ int sense; - uint8_t msg; + /* Action to take at the end of a MSG IN phase. + 0 = COMMAND, 1 = disconect, 2 = DATA OUT, 3 = DATA IN. */ + int msg_action; + int msg_len; + uint8_t msg[LSI_MAX_MSGIN_LEN]; /* 0 if SCRIPTS are running or stopped. * 1 if a Wait Reselect instruction has been issued. - * 2 if a DMA operation is in progress. */ + * 2 if processing DMA from lsi_execute_script. + * 3 if a DMA operation is in progress. */ int waiting; SCSIDevice *scsi_dev[LSI_MAX_DEVS]; SCSIDevice *current_dev; int current_lun; + /* The tag is a combination of the device ID and the SCSI tag. */ + uint32_t current_tag; + uint32_t current_dma_len; + uint8_t *dma_buf; + lsi_queue *queue; + int queue_len; + int active_commands; uint32_t dsa; uint32_t temp; @@ -208,10 +228,12 @@ typedef struct { uint8_t sxfer; uint8_t socl; uint8_t sdid; + uint8_t ssid; uint8_t sfbr; uint8_t stest1; uint8_t stest2; uint8_t stest3; + uint8_t sidl; uint8_t stime0; uint8_t respid0; uint8_t respid1; @@ -231,7 +253,6 @@ typedef struct { uint32_t csbc; uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ - uint8_t dma_buf[LSI_DMA_BLOCK_SIZE]; /* Script ram is stored as 32-bit words in host byteorder. */ uint32_t script_ram[2048]; } LSIState; @@ -280,6 +301,7 @@ static void lsi_soft_reset(LSIState *s) s->stest1 = 0; s->stest2 = 0; s->stest3 = 0; + s->sidl = 0; s->stime0 = 0; s->respid0 = 0x80; s->respid1 = 0; @@ -409,68 +431,194 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase) lsi_set_phase(s, new_phase); } + +/* Resume SCRIPTS execution after a DMA operation. */ +static void lsi_resume_script(LSIState *s) +{ + if (s->waiting != 2) { + s->waiting = 0; + lsi_execute_script(s); + } else { + s->waiting = 0; + } +} + /* Initiate a SCSI layer data transfer. */ static void lsi_do_dma(LSIState *s, int out) { uint32_t count; + uint32_t addr; - count = s->dbc; - if (count > LSI_DMA_BLOCK_SIZE) - count = LSI_DMA_BLOCK_SIZE; - DPRINTF("DMA addr=0x%08x len=%d avail=%d\n", - addr, count, s->data_len); - /* ??? Too long transfers are truncated. Don't know if this is the - correct behavior. */ - if (count > s->data_len) { - /* If the DMA length is greater than the device data length then - a phase mismatch will occur. */ - count = s->data_len; - s->dbc = count; - lsi_bad_phase(s, out, PHASE_ST); + if (!s->current_dma_len) { + /* Wait until data is available. */ + DPRINTF("DMA no data available\n"); + return; } + count = s->dbc; + if (count > s->current_dma_len) + count = s->current_dma_len; + DPRINTF("DMA addr=0x%08x len=%d\n", s->dnad, count); + + addr = s->dnad; s->csbc += count; + s->dnad += count; + s->dbc -= count; + + if (s->dma_buf == NULL) { + s->dma_buf = scsi_get_buf(s->current_dev, s->current_tag); + } /* ??? Set SFBR to first data byte. */ - if ((s->sstat1 & PHASE_MASK) == PHASE_DO) { - cpu_physical_memory_read(s->dnad, s->dma_buf, count); - scsi_write_data(s->current_dev, s->dma_buf, count); + if (out) { + cpu_physical_memory_read(addr, s->dma_buf, count); + } else { + cpu_physical_memory_write(addr, s->dma_buf, count); + } + s->current_dma_len -= count; + if (s->current_dma_len == 0) { + s->dma_buf = NULL; + if (out) { + /* Write the data. */ + scsi_write_data(s->current_dev, s->current_tag); + } else { + /* Request any remaining data. */ + scsi_read_data(s->current_dev, s->current_tag); + } + } else { + s->dma_buf += count; + lsi_resume_script(s); + } +} + + +/* Add a command to the queue. */ +static void lsi_queue_command(LSIState *s) +{ + lsi_queue *p; + + DPRINTF("Queueing tag=0x%x\n", s->current_tag); + if (s->queue_len == s->active_commands) { + s->queue_len++; + s->queue = realloc(s->queue, s->queue_len * sizeof(lsi_queue)); + } + p = &s->queue[s->active_commands++]; + p->tag = s->current_tag; + p->pending = 0; + p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO; +} + +/* Queue a byte for a MSG IN phase. */ +static void lsi_add_msg_byte(LSIState *s, uint8_t data) +{ + if (s->msg_len >= LSI_MAX_MSGIN_LEN) { + BADF("MSG IN data too long\n"); } else { - scsi_read_data(s->current_dev, s->dma_buf, count); + DPRINTF("MSG IN 0x%02x\n", data); + s->msg[s->msg_len++] = data; } - /* If the DMA did not complete then suspend execution. */ - if (s->dbc) - s->waiting = 2; +} + +/* Perform reselection to continue a command. */ +static void lsi_reselect(LSIState *s, uint32_t tag) +{ + lsi_queue *p; + int n; + int id; + + p = NULL; + for (n = 0; n < s->active_commands; n++) { + p = &s->queue[n]; + if (p->tag == tag) + break; + } + if (n == s->active_commands) { + BADF("Reselected non-existant command tag=0x%x\n", tag); + return; + } + id = (tag >> 8) & 0xf; + s->ssid = id | 0x80; + DPRINTF("Reselected target %d\n", id); + s->current_dev = s->scsi_dev[id]; + s->current_tag = tag; + s->scntl1 |= LSI_SCNTL1_CON; + lsi_set_phase(s, PHASE_MI); + s->msg_action = p->out ? 2 : 3; + s->current_dma_len = p->pending; + s->dma_buf = NULL; + lsi_add_msg_byte(s, 0x80); + if (s->current_tag & LSI_TAG_VALID) { + lsi_add_msg_byte(s, 0x20); + lsi_add_msg_byte(s, tag & 0xff); + } + + s->active_commands--; + if (n != s->active_commands) { + s->queue[n] = s->queue[s->active_commands]; + } +} + +/* Record that data is available for a queued command. Returns zero if + the device was reselected, nonzero if the IO is deferred. */ +static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) +{ + lsi_queue *p; + int i; + for (i = 0; i < s->active_commands; i++) { + p = &s->queue[i]; + if (p->tag == tag) { + if (p->pending) { + BADF("Multiple IO pending for tag %d\n", tag); + } + p->pending = arg; + if (s->waiting == 1) { + /* Reselect device. */ + lsi_reselect(s, tag); + return 0; + } else { + DPRINTF("Queueing IO tag=0x%x\n", tag); + p->pending = arg; + return 1; + } + } + } + BADF("IO with unknown tag %d\n", tag); + return 1; } /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void lsi_command_complete(void *opaque, uint32_t reason, int sense) +static void lsi_command_complete(void *opaque, int reason, uint32_t tag, + uint32_t arg) { LSIState *s = (LSIState *)opaque; - uint32_t count; int out; - out = ((s->sstat1 & PHASE_MASK) == PHASE_DO); - count = s->dbc; - if (count > LSI_DMA_BLOCK_SIZE) - count = LSI_DMA_BLOCK_SIZE; - if (!out) - cpu_physical_memory_write(s->dnad, s->dma_buf, count); - s->dnad += count; - s->dbc -= count; - + out = (s->sstat1 & PHASE_MASK) == PHASE_DO; if (reason == SCSI_REASON_DONE) { - DPRINTF("Command complete sense=%d\n", sense); - s->sense = sense; - lsi_set_phase(s, PHASE_ST); + DPRINTF("Command complete sense=%d\n", (int)arg); + s->sense = arg; + if (s->waiting && s->dbc != 0) { + /* Raise phase mismatch for short transfers. */ + lsi_bad_phase(s, out, PHASE_ST); + } else { + lsi_set_phase(s, PHASE_ST); + } + lsi_resume_script(s); + return; } - if (s->dbc) { + if (s->waiting == 1 || tag != s->current_tag) { + if (lsi_queue_tag(s, tag, arg)) + return; + } + DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); + s->current_dma_len = arg; + if (!s->waiting) + return; + if (s->waiting == 1 || s->dbc == 0) { + lsi_resume_script(s); + } else { lsi_do_dma(s, out); - } else if (s->waiting == 2) { - /* Restart SCRIPTS execution. */ - s->waiting = 0; - lsi_execute_script(s); } } @@ -484,27 +632,37 @@ static void lsi_do_command(LSIState *s) s->dbc = 16; cpu_physical_memory_read(s->dnad, buf, s->dbc); s->sfbr = buf[0]; - n = scsi_send_command(s->current_dev, 0, buf, s->current_lun); + n = scsi_send_command(s->current_dev, s->current_tag, buf, s->current_lun); if (n > 0) { - s->data_len = n; lsi_set_phase(s, PHASE_DI); + scsi_read_data(s->current_dev, s->current_tag); } else if (n < 0) { - s->data_len = -n; lsi_set_phase(s, PHASE_DO); + scsi_write_data(s->current_dev, s->current_tag); + } + if (n && s->current_dma_len == 0) { + /* Command did not complete immediately so disconnect. */ + lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */ + lsi_add_msg_byte(s, 4); /* DISCONNECT */ + lsi_set_phase(s, PHASE_MI); + s->msg_action = 1; + lsi_queue_command(s); } } static void lsi_do_status(LSIState *s) { + uint8_t sense; DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); if (s->dbc != 1) BADF("Bad Status move\n"); s->dbc = 1; - s->msg = s->sense; - cpu_physical_memory_write(s->dnad, &s->msg, 1); - s->sfbr = s->msg; + sense = s->sense; + s->sfbr = sense; + cpu_physical_memory_write(s->dnad, &sense, 1); lsi_set_phase(s, PHASE_MI); - s->msg = 0; /* COMMAND COMPLETE */ + s->msg_action = 1; + lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */ } static void lsi_disconnect(LSIState *s) @@ -515,55 +673,114 @@ static void lsi_disconnect(LSIState *s) static void lsi_do_msgin(LSIState *s) { - DPRINTF("Message in len=%d\n", s->dbc); - s->dbc = 1; - s->sfbr = s->msg; - cpu_physical_memory_write(s->dnad, &s->msg, 1); - if (s->msg == 0) { - lsi_disconnect(s); + int len; + DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len); + s->sfbr = s->msg[0]; + len = s->msg_len; + if (len > s->dbc) + len = s->dbc; + cpu_physical_memory_write(s->dnad, s->msg, len); + /* Linux drivers rely on the last byte being in the SIDL. */ + s->sidl = s->msg[len - 1]; + s->msg_len -= len; + if (s->msg_len) { + memmove(s->msg, s->msg + len, s->msg_len); } else { /* ??? Check if ATN (not yet implemented) is asserted and maybe switch to PHASE_MO. */ - lsi_set_phase(s, PHASE_CMD); + switch (s->msg_action) { + case 0: + lsi_set_phase(s, PHASE_CMD); + break; + case 1: + lsi_disconnect(s); + break; + case 2: + lsi_set_phase(s, PHASE_DO); + break; + case 3: + lsi_set_phase(s, PHASE_DI); + break; + default: + abort(); + } } } +/* Read the next byte during a MSGOUT phase. */ +static uint8_t lsi_get_msgbyte(LSIState *s) +{ + uint8_t data; + cpu_physical_memory_read(s->dnad, &data, 1); + s->dnad++; + s->dbc--; + return data; +} + static void lsi_do_msgout(LSIState *s) { uint8_t msg; + int len; DPRINTF("MSG out len=%d\n", s->dbc); - if (s->dbc != 1) { - /* Multibyte messages not implemented. */ - s->msg = 7; /* MESSAGE REJECT */ - //s->dbc = 1; - //lsi_bad_phase(s, 1, PHASE_MI); - lsi_set_phase(s, PHASE_MI); - return; - } - cpu_physical_memory_read(s->dnad, &msg, 1); - s->sfbr = msg; - s->dnad++; - - switch (msg) { - case 0x00: - DPRINTF("Got Disconnect\n"); - lsi_disconnect(s); - return; - case 0x08: - DPRINTF("Got No Operation\n"); - lsi_set_phase(s, PHASE_CMD); - return; - } - if ((msg & 0x80) == 0) { - DPRINTF("Unimplemented message 0x%d\n", msg); - s->msg = 7; /* MESSAGE REJECT */ - lsi_bad_phase(s, 1, PHASE_MI); - return; + while (s->dbc) { + msg = lsi_get_msgbyte(s); + s->sfbr = msg; + + switch (msg) { + case 0x00: + DPRINTF("MSG: Disconnect\n"); + lsi_disconnect(s); + break; + case 0x08: + DPRINTF("MSG: No Operation\n"); + lsi_set_phase(s, PHASE_CMD); + break; + case 0x01: + len = lsi_get_msgbyte(s); + msg = lsi_get_msgbyte(s); + DPRINTF("Extended message 0x%x (len %d)\n", msg, len); + switch (msg) { + case 1: + DPRINTF("SDTR (ignored)\n"); + s->dbc -= 2; + break; + case 3: + DPRINTF("WDTR (ignored)\n"); + s->dbc -= 1; + break; + default: + goto bad; + } + break; + case 0x20: /* SIMPLE queue */ + s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; + DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff); + break; + case 0x21: /* HEAD of queue */ + BADF("HEAD queue not implemented\n"); + s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; + break; + case 0x22: /* ORDERED queue */ + BADF("ORDERED queue not implemented\n"); + s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; + break; + default: + if ((msg & 0x80) == 0) { + goto bad; + } + s->current_lun = msg & 7; + DPRINTF("Select LUN %d\n", s->current_lun); + lsi_set_phase(s, PHASE_CMD); + break; + } } - s->current_lun = msg & 7; - DPRINTF("Select LUN %d\n", s->current_lun); - lsi_set_phase(s, PHASE_CMD); + return; +bad: + BADF("Unimplemented message 0x%02x\n", msg); + lsi_set_phase(s, PHASE_MI); + lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */ + s->msg_action = 0; } /* Sign extend a 24-bit value. */ @@ -588,6 +805,23 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) } } +static void lsi_wait_reselect(LSIState *s) +{ + int i; + DPRINTF("Wait Reselect\n"); + if (s->current_dma_len) + BADF("Reselect with pending DMA\n"); + for (i = 0; i < s->active_commands; i++) { + if (s->queue[i].pending) { + lsi_reselect(s, s->queue[i].tag); + break; + } + } + if (s->current_dma_len == 0) { + s->waiting = 1; + } +} + static void lsi_execute_script(LSIState *s) { uint32_t insn; @@ -632,10 +866,16 @@ again: s->dnad = addr; switch (s->sstat1 & 0x7) { case PHASE_DO: + s->waiting = 2; lsi_do_dma(s, 1); + if (s->waiting) + s->waiting = 3; break; case PHASE_DI: + s->waiting = 2; lsi_do_dma(s, 0); + if (s->waiting) + s->waiting = 3; break; case PHASE_CMD: lsi_do_command(s); @@ -679,9 +919,13 @@ again: s->dnad = addr; switch (opcode) { case 0: /* Select */ + s->sdid = id; + if (s->current_dma_len && (s->ssid & 0xf) == id) { + DPRINTF("Already reselected by target %d\n", id); + break; + } s->sstat0 |= LSI_SSTAT0_WOA; s->scntl1 &= ~LSI_SCNTL1_IARB; - s->sdid = id; if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) { DPRINTF("Selected absent target %d\n", id); lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO); @@ -694,6 +938,7 @@ again: it only applies in low-level mode (unimplemented). lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ s->current_dev = s->scsi_dev[id]; + s->current_tag = id << 8; s->scntl1 |= LSI_SCNTL1_CON; if (insn & (1 << 3)) { s->socl |= LSI_SOCL_ATN; @@ -705,8 +950,7 @@ again: s->scntl1 &= ~LSI_SCNTL1_CON; break; case 2: /* Wait Reselect */ - DPRINTF("Wait Reselect\n"); - s->waiting = 1; + lsi_wait_reselect(s); break; case 3: /* Set */ DPRINTF("Set%s%s%s%s\n", @@ -755,9 +999,9 @@ again: data8 = (insn >> 8) & 0xff; opcode = (insn >> 27) & 7; operator = (insn >> 24) & 7; - DPRINTF("%s reg 0x%x %s data8 %d%s\n", + DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n", opcode_names[opcode - 5], reg, - operator_names[operator], data8, + operator_names[operator], data8, s->sfbr, (insn & (1 << 23)) ? " SFBR" : ""); op0 = op1 = 0; switch (opcode) { @@ -923,8 +1167,9 @@ again: n = (insn & 7); reg = (insn >> 16) & 0xff; if (insn & (1 << 24)) { - DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr); cpu_physical_memory_read(addr, data, n); + DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, + addr, *(int *)data); for (i = 0; i < n; i++) { lsi_reg_writeb(s, reg + i, data[i]); } @@ -977,6 +1222,8 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) return s->sdid; case 0x07: /* GPREG0 */ return 0x7f; + case 0xa: /* SSID */ + return s->ssid; case 0xb: /* SBCL */ /* ??? This is not correct. However it's (hopefully) only used for diagnostics, so should be ok. */ @@ -1065,13 +1312,22 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) return s->stest2; case 0x4f: /* STEST3 */ return s->stest3; + case 0x50: /* SIDL */ + /* This is needed by the linux drivers. We currently only update it + during the MSG IN phase. */ + return s->sidl; case 0x52: /* STEST4 */ return 0xe0; case 0x56: /* CCNTL0 */ return s->ccntl0; case 0x57: /* CCNTL1 */ return s->ccntl1; - case 0x58: case 0x59: /* SBDL */ + case 0x58: /* SBDL */ + /* Some drivers peek at the data bus during the MSG IN phase. */ + if ((s->sstat1 & PHASE_MASK) == PHASE_MI) + return s->msg[0]; + return 0; + case 0x59: /* SBDL high */ return 0; CASE_GET_REG32(mmrs, 0xa0) CASE_GET_REG32(mmws, 0xa4) @@ -1143,8 +1399,18 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) case 0x05: /* SXFER */ s->sxfer = val; break; + case 0x06: /* SDID */ + if ((val & 0xf) != (s->ssid & 0xf)) + BADF("Destination ID does not match SSID\n"); + s->sdid = val & 0xf; + break; case 0x07: /* GPREG0 */ break; + case 0x08: /* SFBR */ + /* The CPU is not allowed to write to this register. However the + SCRIPTS register move instructions are. */ + s->sfbr = val; + break; case 0x0c: case 0x0d: case 0x0e: case 0x0f: /* Linux writes to these readonly registers on startup. */ return; @@ -1555,7 +1821,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id) scsi_disk_destroy(s->scsi_dev[id]); } DPRINTF("Attaching block device %d\n", id); - s->scsi_dev[id] = scsi_disk_init(bd, lsi_command_complete, s); + s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s); } void *lsi_scsi_init(PCIBus *bus, int devfn) @@ -1587,6 +1853,9 @@ void *lsi_scsi_init(PCIBus *bus, int devfn) PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc); pci_register_io_region((struct PCIDevice *)s, 2, 0x2000, PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc); + s->queue = qemu_malloc(sizeof(lsi_queue)); + s->queue_len = 1; + s->active_commands = 0; lsi_soft_reset(s); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 213e8d293..c6280fd55 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -7,6 +7,10 @@ * Written by Paul Brook * * This code is licenced under the LGPL. + * + * Note that this file only handles the SCSI architecture model and device + * commands. Emultion of interface/link layer protocols is handled by + * the host adapter emulation. */ //#define DEBUG_SCSI @@ -28,231 +32,241 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) #define SENSE_HARDWARE_ERROR 4 #define SENSE_ILLEGAL_REQUEST 5 -struct SCSIDevice -{ - int command; +#define SCSI_DMA_BUF_SIZE 65536 + +typedef struct SCSIRequest { + SCSIDevice *dev; uint32_t tag; - BlockDriverState *bdrv; - /* The qemu block layer uses a fixed 512 byte sector size. - This is the number of 512 byte blocks in a single scsi sector. */ - int cluster_size; - /* When transfering data buf_pos and buf_len contain a partially - transferred block of data (or response to a command), and - sector/sector_count identify any remaining sectors. - Both sector and sector_count are in terms of qemu 512 byte blocks. */ /* ??? We should probably keep track of whether the data trasfer is a read or a write. Currently we rely on the host getting it right. */ + /* Both sector and sector_count are in terms of qemu 512 byte blocks. */ int sector; int sector_count; - int buf_pos; + /* The amounnt of data in the buffer. */ int buf_len; - int sense; + uint8_t dma_buf[SCSI_DMA_BUF_SIZE]; BlockDriverAIOCB *aiocb; - /* Data still to be transfered after this request completes. */ - uint8_t *aiodata; - uint32_t aiolen; - char buf[512]; + struct SCSIRequest *next; +} SCSIRequest; + +struct SCSIDevice +{ + BlockDriverState *bdrv; + SCSIRequest *requests; + /* The qemu block layer uses a fixed 512 byte sector size. + This is the number of 512 byte blocks in a single scsi sector. */ + int cluster_size; + int sense; + int tcq; /* Completion functions may be called from either scsi_{read,write}_data or from the AIO completion routines. */ scsi_completionfn completion; void *opaque; }; -static void scsi_command_complete(SCSIDevice *s, int sense) +/* Global pool of SCSIRequest structures. */ +static SCSIRequest *free_requests = NULL; + +static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag) { - s->sense = sense; - s->completion(s->opaque, SCSI_REASON_DONE, sense); + SCSIRequest *r; + + if (free_requests) { + r = free_requests; + free_requests = r->next; + } else { + r = qemu_malloc(sizeof(SCSIRequest)); + } + r->dev = s; + r->tag = tag; + r->sector_count = 0; + r->buf_len = 0; + r->aiocb = NULL; + + r->next = s->requests; + s->requests = r; + return r; } -static void scsi_transfer_complete(SCSIDevice *s) +static void scsi_remove_request(SCSIRequest *r) { - s->completion(s->opaque, SCSI_REASON_DATA, 0); - s->aiocb = NULL; + SCSIRequest *last; + SCSIDevice *s = r->dev; + + if (s->requests == r) { + s->requests = r->next; + } else { + last = s->requests; + while (last && last->next != r) + last = last->next; + if (last) { + last->next = r->next; + } else { + BADF("Orphaned request\n"); + } + } + r->next = free_requests; + free_requests = r; } -static void scsi_read_complete(void * opaque, int ret) +static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag) { - SCSIDevice *s = (SCSIDevice *)opaque; + SCSIRequest *r; - if (ret) { - DPRINTF("IO error\n"); - scsi_command_complete(s, SENSE_HARDWARE_ERROR); - } + r = s->requests; + while (r && r->tag != tag) + r = r->next; - if (s->aiolen) { - /* Read the remaining data. Full and partial sectors are transferred - separately. */ - scsi_read_data(s, s->aiodata, s->aiolen); - } else { - if (s->buf_len == 0 && s->sector_count == 0) - scsi_command_complete(s, SENSE_NO_SENSE); - else - scsi_transfer_complete(s); - } + return r; +} + +/* Helper function for command completion. */ +static void scsi_command_complete(SCSIRequest *r, int sense) +{ + SCSIDevice *s = r->dev; + uint32_t tag; + DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense); + s->sense = sense; + tag = r->tag; + scsi_remove_request(r); + s->completion(s->opaque, SCSI_REASON_DONE, tag, sense); } /* Cancel a pending data transfer. */ -void scsi_cancel_io(SCSIDevice *s) +void scsi_cancel_io(SCSIDevice *s, uint32_t tag) { - if (!s->aiocb) { - BADF("Cancel with no pending IO\n"); + SCSIRequest *r; + DPRINTF("Cancel tag=0x%x\n", tag); + r = scsi_find_request(s, tag); + if (r) { + if (r->aiocb) + bdrv_aio_cancel(r->aiocb); + r->aiocb = NULL; + scsi_remove_request(r); + } +} + +static void scsi_read_complete(void * opaque, int ret) +{ + SCSIRequest *r = (SCSIRequest *)opaque; + SCSIDevice *s = r->dev; + + if (ret) { + DPRINTF("IO error\n"); + scsi_command_complete(r, SENSE_HARDWARE_ERROR); return; } - bdrv_aio_cancel(s->aiocb); - s->aiocb = NULL; + DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->buf_len); + + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len); } -/* Read data from a scsi device. Returns nonzero on failure. - The transfer may complete asynchronously. */ -int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len) +/* Read more data from scsi device into buffer. */ +void scsi_read_data(SCSIDevice *s, uint32_t tag) { + SCSIRequest *r; uint32_t n; - DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count); - if (s->buf_len == 0 && s->sector_count == 0) - return 1; - - if (s->buf_len) { - n = s->buf_len; - if (n > len) - n = len; - memcpy(data, s->buf + s->buf_pos, n); - s->buf_pos += n; - s->buf_len -= n; - data += n; - len -= n; - if (s->buf_len == 0) - s->buf_pos = 0; + r = scsi_find_request(s, tag); + if (!r) { + BADF("Bad read tag 0x%x\n", tag); + /* ??? This is the wrong error. */ + scsi_command_complete(r, SENSE_HARDWARE_ERROR); + return; } - - n = len / 512; - if (n > s->sector_count) - n = s->sector_count; - - if (n != 0) { - s->aiolen = len - n * 512; - s->aiodata = data + n * 512; - s->aiocb = bdrv_aio_read(s->bdrv, s->sector, data, n, - scsi_read_complete, s); - if (s->aiocb == NULL) - scsi_command_complete(s, SENSE_HARDWARE_ERROR); - s->sector += n; - s->sector_count -= n; - return 0; + if (r->sector_count == (uint32_t)-1) { + DPRINTF("Read buf_len=%d\n", r->buf_len); + r->sector_count = 0; + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len); + return; } - - if (len && s->sector_count) { - /* TODO: Make this use AIO. */ - bdrv_read(s->bdrv, s->sector, s->buf, 1); - s->sector++; - s->sector_count--; - s->buf_pos = 0; - s->buf_len = 512; - /* Recurse to complete the partial read. */ - return scsi_read_data(s, data, len); + DPRINTF("Read sector_count=%d\n", r->sector_count); + if (r->sector_count == 0) { + scsi_command_complete(r, SENSE_NO_SENSE); + return; } - if (len != 0) - return 1; - - if (s->buf_len == 0 && s->sector_count == 0) - scsi_command_complete(s, SENSE_NO_SENSE); - else - scsi_transfer_complete(s); - - return 0; + n = r->sector_count; + if (n > SCSI_DMA_BUF_SIZE / 512) + n = SCSI_DMA_BUF_SIZE / 512; + + r->buf_len = n * 512; + r->aiocb = bdrv_aio_read(s->bdrv, r->sector, r->dma_buf, n, + scsi_read_complete, r); + if (r->aiocb == NULL) + scsi_command_complete(r, SENSE_HARDWARE_ERROR); + r->sector += n; + r->sector_count -= n; } static void scsi_write_complete(void * opaque, int ret) { - SCSIDevice *s = (SCSIDevice *)opaque; + SCSIRequest *r = (SCSIRequest *)opaque; + SCSIDevice *s = r->dev; + uint32_t len; if (ret) { fprintf(stderr, "scsi-disc: IO write error\n"); exit(1); } - if (s->sector_count == 0) - scsi_command_complete(s, SENSE_NO_SENSE); - else - scsi_transfer_complete(s); -} - -static uint32_t scsi_write_partial_sector(SCSIDevice *s, uint8_t *data, - uint32_t len) -{ - int n; - - n = 512 - s->buf_len; - if (n > len) - n = len; - - memcpy(s->buf + s->buf_len, data, n); - data += n; - s->buf_len += n; - len -= n; - if (s->buf_len == 512) { - /* A full sector has been accumulated. Write it to disk. */ - /* TODO: Make this use async IO. */ - bdrv_write(s->bdrv, s->sector, s->buf, 1); - s->buf_len = 0; - s->sector++; - s->sector_count--; + r->aiocb = NULL; + if (r->sector_count == 0) { + scsi_command_complete(r, SENSE_NO_SENSE); + } else { + len = r->sector_count * 512; + if (len > SCSI_DMA_BUF_SIZE) { + len = SCSI_DMA_BUF_SIZE; + } + r->buf_len = len; + DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len); + s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); } - return n; } /* Write data to a scsi device. Returns nonzero on failure. The transfer may complete asynchronously. */ -int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len) +int scsi_write_data(SCSIDevice *s, uint32_t tag) { + SCSIRequest *r; uint32_t n; - DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count); - if (s->buf_pos != 0) { - BADF("Bad state on write\n"); + DPRINTF("Write data tag=0x%x\n", tag); + r = scsi_find_request(s, tag); + if (!r) { + BADF("Bad write tag 0x%x\n", tag); + scsi_command_complete(r, SENSE_HARDWARE_ERROR); return 1; } - - if (s->sector_count == 0) - return 1; - - if (s->buf_len != 0 || len < 512) { - n = scsi_write_partial_sector(s, data, len); - len -= n; - data += n; + if (r->aiocb) + BADF("Data transfer already in progress\n"); + n = r->buf_len / 512; + if (n) { + r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n, + scsi_write_complete, r); + if (r->aiocb == NULL) + scsi_command_complete(r, SENSE_HARDWARE_ERROR); + r->sector += n; + r->sector_count -= n; + } else { + /* Invoke completion routine to fetch data from host. */ + scsi_write_complete(r, 0); } - n = len / 512; - if (n > s->sector_count) - return 1; + return 0; +} - if (n != 0) { - s->aiocb = bdrv_aio_write(s->bdrv, s->sector, data, n, - scsi_write_complete, s); - if (s->aiocb == NULL) - scsi_command_complete(s, SENSE_HARDWARE_ERROR); - data += n * 512; - len -= n * 512; - s->sector += n; - s->sector_count -= n; - } +/* Return a pointer to the data buffer. */ +uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag) +{ + SCSIRequest *r; - if (len) { - if (s->sector_count == 0) - return 1; - /* Complete a partial write. */ - scsi_write_partial_sector(s, data, len); + r = scsi_find_request(s, tag); + if (!r) { + BADF("Bad buffer tag 0x%x\n", tag); + return NULL; } - if (n == 0) { - /* Transfer completes immediately. */ - if (s->sector_count == 0) - scsi_command_complete(s, SENSE_NO_SENSE); - else - scsi_transfer_complete(s); - } - - return 0; + return r->dma_buf; } /* Execute a scsi command. Returns the length of the data expected by the @@ -267,15 +281,23 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) uint32_t len; int cmdlen; int is_write; - - s->command = buf[0]; - s->tag = tag; - s->sector_count = 0; - s->buf_pos = 0; - s->buf_len = 0; + uint8_t command; + uint8_t *outbuf; + SCSIRequest *r; + + command = buf[0]; + r = scsi_find_request(s, tag); + if (r) { + BADF("Tag 0x%x already in use\n", tag); + scsi_cancel_io(s, tag); + } + /* ??? Tags are not unique for different luns. We only implement a + single lun, so this should not matter. */ + r = scsi_new_request(s, tag); + outbuf = r->dma_buf; is_write = 0; - DPRINTF("Command: 0x%02x", buf[0]); - switch (s->command >> 5) { + DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); + switch (command >> 5) { case 0: lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16); len = buf[4]; @@ -298,7 +320,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) cmdlen = 12; break; default: - BADF("Unsupported command length, command %x\n", s->command); + BADF("Unsupported command length, command %x\n", command); goto fail; } #ifdef DEBUG_SCSI @@ -315,7 +337,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); goto fail; } - switch (s->command) { + switch (command) { case 0x0: DPRINTF("Test Unit Ready\n"); break; @@ -324,33 +346,35 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) if (len < 4) goto fail; memset(buf, 0, 4); - s->buf[0] = 0xf0; - s->buf[1] = 0; - s->buf[2] = s->sense; - s->buf_len = 4; + outbuf[0] = 0xf0; + outbuf[1] = 0; + outbuf[2] = s->sense; + r->buf_len = 4; break; case 0x12: DPRINTF("Inquiry (len %d)\n", len); if (len < 36) { BADF("Inquiry buffer too small (%d)\n", len); } - memset(s->buf, 0, 36); + memset(outbuf, 0, 36); if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { - s->buf[0] = 5; - s->buf[1] = 0x80; - memcpy(&s->buf[16], "QEMU CD-ROM ", 16); + outbuf[0] = 5; + outbuf[1] = 0x80; + memcpy(&outbuf[16], "QEMU CD-ROM ", 16); } else { - s->buf[0] = 0; - memcpy(&s->buf[16], "QEMU HARDDISK ", 16); + outbuf[0] = 0; + memcpy(&outbuf[16], "QEMU HARDDISK ", 16); } - memcpy(&s->buf[8], "QEMU ", 8); - memcpy(&s->buf[32], QEMU_VERSION, 4); + memcpy(&outbuf[8], "QEMU ", 8); + memcpy(&outbuf[32], QEMU_VERSION, 4); /* Identify device as SCSI-3 rev 1. Some later commands are also implemented. */ - s->buf[2] = 3; - s->buf[3] = 2; /* Format 2 */ - s->buf[4] = 32; - s->buf_len = 36; + outbuf[2] = 3; + outbuf[3] = 2; /* Format 2 */ + outbuf[4] = 32; + /* Sync data transfer and TCQ. */ + outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0); + r->buf_len = 36; break; case 0x16: DPRINTF("Reserve(6)\n"); @@ -365,17 +389,17 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) case 0x1a: case 0x5a: { - char *p; + uint8_t *p; int page; page = buf[2] & 0x3f; DPRINTF("Mode Sense (page %d, len %d)\n", page, len); - p = s->buf; + p = outbuf; memset(p, 0, 4); - s->buf[1] = 0; /* Default media type. */ - s->buf[3] = 0; /* Block descriptor length. */ + outbuf[1] = 0; /* Default media type. */ + outbuf[3] = 0; /* Block descriptor length. */ if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { - s->buf[2] = 0x80; /* Readonly. */ + outbuf[2] = 0x80; /* Readonly. */ } p += 4; if ((page == 8 || page == 0x3f)) { @@ -415,10 +439,10 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) p[21] = (16 * 176) & 0xff; p += 21; } - s->buf_len = p - s->buf; - s->buf[0] = s->buf_len - 4; - if (s->buf_len > len) - s->buf_len = len; + r->buf_len = p - outbuf; + outbuf[0] = r->buf_len - 4; + if (r->buf_len > len) + r->buf_len = len; } break; case 0x1b: @@ -431,36 +455,36 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) case 0x25: DPRINTF("Read Capacity\n"); /* The normal LEN field for this command is zero. */ - memset(s->buf, 0, 8); + memset(outbuf, 0, 8); bdrv_get_geometry(s->bdrv, &nb_sectors); /* Returned value is the address of the last sector. */ if (nb_sectors) { nb_sectors--; - s->buf[0] = (nb_sectors >> 24) & 0xff; - s->buf[1] = (nb_sectors >> 16) & 0xff; - s->buf[2] = (nb_sectors >> 8) & 0xff; - s->buf[3] = nb_sectors & 0xff; - s->buf[4] = 0; - s->buf[5] = 0; - s->buf[6] = s->cluster_size * 2; - s->buf[7] = 0; - s->buf_len = 8; + outbuf[0] = (nb_sectors >> 24) & 0xff; + outbuf[1] = (nb_sectors >> 16) & 0xff; + outbuf[2] = (nb_sectors >> 8) & 0xff; + outbuf[3] = nb_sectors & 0xff; + outbuf[4] = 0; + outbuf[5] = 0; + outbuf[6] = s->cluster_size * 2; + outbuf[7] = 0; + r->buf_len = 8; } else { - scsi_command_complete(s, SENSE_NOT_READY); + scsi_command_complete(r, SENSE_NOT_READY); return 0; } break; case 0x08: case 0x28: DPRINTF("Read (sector %d, count %d)\n", lba, len); - s->sector = lba * s->cluster_size; - s->sector_count = len * s->cluster_size; + r->sector = lba * s->cluster_size; + r->sector_count = len * s->cluster_size; break; case 0x0a: case 0x2a: DPRINTF("Write (sector %d, count %d)\n", lba, len); - s->sector = lba * s->cluster_size; - s->sector_count = len * s->cluster_size; + r->sector = lba * s->cluster_size; + r->sector_count = len * s->cluster_size; is_write = 1; break; case 0x35: @@ -478,18 +502,18 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); switch(format) { case 0: - toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track); + toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track); break; case 1: /* multi session : only a single session defined */ toclen = 12; - memset(s->buf, 0, 12); - s->buf[1] = 0x0a; - s->buf[2] = 0x01; - s->buf[3] = 0x01; + memset(outbuf, 0, 12); + outbuf[1] = 0x0a; + outbuf[2] = 0x01; + outbuf[3] = 0x01; break; case 2: - toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track); + toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track); break; default: goto error_cmd; @@ -497,7 +521,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) if (toclen > 0) { if (len > toclen) len = toclen; - s->buf_len = len; + r->buf_len = len; break; } error_cmd: @@ -506,11 +530,11 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) } case 0x46: DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len); - memset(s->buf, 0, 8); + memset(outbuf, 0, 8); /* ??? This shoud probably return much more information. For now just return the basic header indicating the CD-ROM profile. */ - s->buf[7] = 8; // CD-ROM - s->buf_len = 8; + outbuf[7] = 8; // CD-ROM + r->buf_len = 8; break; case 0x56: DPRINTF("Reserve(10)\n"); @@ -526,21 +550,27 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) DPRINTF("Report LUNs (len %d)\n", len); if (len < 16) goto fail; - memset(s->buf, 0, 16); - s->buf[3] = 8; - s->buf_len = 16; + memset(outbuf, 0, 16); + outbuf[3] = 8; + r->buf_len = 16; break; default: DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); fail: - scsi_command_complete(s, SENSE_ILLEGAL_REQUEST); + scsi_command_complete(r, SENSE_ILLEGAL_REQUEST); return 0; } - if (s->sector_count == 0 && s->buf_len == 0) { - scsi_command_complete(s, SENSE_NO_SENSE); + if (r->sector_count == 0 && r->buf_len == 0) { + scsi_command_complete(r, SENSE_NO_SENSE); + } + len = r->sector_count * 512 + r->buf_len; + if (is_write) { + return -len; + } else { + if (!r->sector_count) + r->sector_count = -1; + return len; } - len = s->sector_count * 512 + s->buf_len; - return is_write ? -len : len; } void scsi_disk_destroy(SCSIDevice *s) @@ -549,6 +579,7 @@ void scsi_disk_destroy(SCSIDevice *s) } SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, + int tcq, scsi_completionfn completion, void *opaque) { @@ -556,6 +587,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); s->bdrv = bdrv; + s->tcq = tcq; s->completion = completion; s->opaque = opaque; if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { diff --git a/hw/sun4m.c b/hw/sun4m.c index 203732f21..09a157c0a 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -199,6 +199,18 @@ uint32_t iommu_translate(uint32_t addr) return iommu_translate_local(iommu, addr); } +void sparc_iommu_memory_read(target_phys_addr_t addr, + uint8_t *buf, int len) +{ + return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 0); +} + +void sparc_iommu_memory_write(target_phys_addr_t addr, + uint8_t *buf, int len) +{ + return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 1); +} + static void *slavio_misc; void qemu_system_powerdown(void) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index e4cfca0fe..4530a1cea 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -32,8 +32,12 @@ enum USBMSDMode { typedef struct { USBDevice dev; enum USBMSDMode mode; + uint32_t scsi_len; + uint8_t *scsi_buf; + uint32_t usb_len; + uint8_t *usb_buf; uint32_t data_len; - uint32_t transfer_len; + uint32_t residue; uint32_t tag; BlockDriverState *bs; SCSIDevice *scsi_dev; @@ -42,6 +46,23 @@ typedef struct { USBPacket *packet; } MSDState; +struct usb_msd_cbw { + uint32_t sig; + uint32_t tag; + uint32_t data_len; + uint8_t flags; + uint8_t lun; + uint8_t cmd_len; + uint8_t cmd[16]; +}; + +struct usb_msd_csw { + uint32_t sig; + uint32_t tag; + uint32_t residue; + uint8_t status; +}; + static const uint8_t qemu_msd_dev_descriptor[] = { 0x12, /* u8 bLength; */ 0x01, /* u8 bDescriptorType; Device */ @@ -107,26 +128,90 @@ static const uint8_t qemu_msd_config_descriptor[] = { 0x00 /* u8 ep_bInterval; */ }; -static void usb_msd_command_complete(void *opaque, uint32_t reason, int fail) +static void usb_msd_copy_data(MSDState *s) +{ + uint32_t len; + len = s->usb_len; + if (len > s->scsi_len) + len = s->scsi_len; + if (s->mode == USB_MSDM_DATAIN) { + memcpy(s->usb_buf, s->scsi_buf, len); + } else { + memcpy(s->scsi_buf, s->usb_buf, len); + } + s->usb_len -= len; + s->scsi_len -= len; + s->usb_buf += len; + s->scsi_buf += len; + s->data_len -= len; + if (s->scsi_len == 0) { + if (s->mode == USB_MSDM_DATAIN) { + scsi_read_data(s->scsi_dev, s->tag); + } else if (s->mode == USB_MSDM_DATAOUT) { + scsi_write_data(s->scsi_dev, s->tag); + } + } +} + +static void usb_msd_send_status(MSDState *s) +{ + struct usb_msd_csw csw; + + csw.sig = cpu_to_le32(0x53425355); + csw.tag = cpu_to_le32(s->tag); + csw.residue = s->residue; + csw.status = s->result; + memcpy(s->usb_buf, &csw, 13); +} + +static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag, + uint32_t arg) { MSDState *s = (MSDState *)opaque; - USBPacket *p; + USBPacket *p = s->packet; - s->data_len -= s->transfer_len; - s->transfer_len = 0; + if (tag != s->tag) { + fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", tag); + } if (reason == SCSI_REASON_DONE) { - DPRINTF("Command complete %d\n", fail); - s->result = fail; - s->mode = USB_MSDM_CSW; + DPRINTF("Command complete %d\n", arg); + s->residue = s->data_len; + s->result = arg != 0; + if (s->packet) { + if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) { + /* A deferred packet with no write data remaining must be + the status read packet. */ + usb_msd_send_status(s); + s->mode = USB_MSDM_CBW; + } else { + if (s->data_len) { + s->data_len -= s->usb_len; + if (s->mode == USB_MSDM_DATAIN) + memset(s->usb_buf, 0, s->usb_len); + s->usb_len = 0; + } + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + } + s->packet = NULL; + usb_packet_complete(p); + } else if (s->data_len == 0) { + s->mode = USB_MSDM_CSW; + } + return; } - if (s->packet) { - /* Set s->packet to NULL before calling usb_packet_complete because - annother request may be issues before usb_packet_complete returns. - */ - DPRINTF("Packet complete %p\n", p); - p = s->packet; - s->packet = NULL; - usb_packet_complete(p); + s->scsi_len = arg; + s->scsi_buf = scsi_get_buf(s->scsi_dev, tag); + if (p) { + usb_msd_copy_data(s); + if (s->usb_len == 0) { + /* Set s->packet to NULL before calling usb_packet_complete + because annother request may be issued before + usb_packet_complete returns. */ + DPRINTF("Packet complete %p\n", p); + s->packet = NULL; + usb_packet_complete(p); + } } } @@ -251,28 +336,12 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, return ret; } -struct usb_msd_cbw { - uint32_t sig; - uint32_t tag; - uint32_t data_len; - uint8_t flags; - uint8_t lun; - uint8_t cmd_len; - uint8_t cmd[16]; -}; - -struct usb_msd_csw { - uint32_t sig; - uint32_t tag; - uint32_t residue; - uint8_t status; -}; - static void usb_msd_cancel_io(USBPacket *p, void *opaque) { MSDState *s = opaque; - scsi_cancel_io(s->scsi_dev); + scsi_cancel_io(s->scsi_dev, s->tag); s->packet = NULL; + s->scsi_len = 0; } static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) @@ -280,7 +349,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) MSDState *s = (MSDState *)dev; int ret = 0; struct usb_msd_cbw cbw; - struct usb_msd_csw csw; uint8_t devep = p->devep; uint8_t *data = p->data; int len = p->len; @@ -318,7 +386,17 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", s->tag, cbw.flags, cbw.cmd_len, s->data_len); + s->residue = 0; scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); + /* ??? Should check that USB and SCSI data transfer + directions match. */ + if (s->residue == 0) { + if (s->mode == USB_MSDM_DATAIN) { + scsi_read_data(s->scsi_dev, s->tag); + } else if (s->mode == USB_MSDM_DATAOUT) { + scsi_write_data(s->scsi_dev, s->tag); + } + } ret = len; break; @@ -327,17 +405,24 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (len > s->data_len) goto fail; - s->transfer_len = len; - if (scsi_write_data(s->scsi_dev, data, len)) - goto fail; - - if (s->transfer_len == 0) { - ret = len; - } else { + s->usb_buf = data; + s->usb_len = len; + if (s->scsi_len) { + usb_msd_copy_data(s); + } + if (s->residue && s->usb_len) { + s->data_len -= s->usb_len; + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + s->usb_len = 0; + } + if (s->usb_len) { DPRINTF("Deferring packet %p\n", p); usb_defer_packet(p, usb_msd_cancel_io, s); s->packet = p; ret = USB_RET_ASYNC; + } else { + ret = len; } break; @@ -352,37 +437,51 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) goto fail; switch (s->mode) { + case USB_MSDM_DATAOUT: + if (s->data_len != 0 || len < 13) + goto fail; + /* Waiting for SCSI write to complete. */ + usb_defer_packet(p, usb_msd_cancel_io, s); + s->packet = p; + ret = USB_RET_ASYNC; + break; + case USB_MSDM_CSW: DPRINTF("Command status %d tag 0x%x, len %d\n", s->result, s->tag, len); if (len < 13) goto fail; - csw.sig = cpu_to_le32(0x53425355); - csw.tag = cpu_to_le32(s->tag); - csw.residue = 0; - csw.status = s->result; - memcpy(data, &csw, 13); - ret = 13; + s->usb_len = len; + s->usb_buf = data; + usb_msd_send_status(s); s->mode = USB_MSDM_CBW; + ret = 13; break; case USB_MSDM_DATAIN: DPRINTF("Data in %d/%d\n", len, s->data_len); if (len > s->data_len) len = s->data_len; - - s->transfer_len = len; - if (scsi_read_data(s->scsi_dev, data, len)) - goto fail; - - if (s->transfer_len == 0) { - ret = len; - } else { + s->usb_buf = data; + s->usb_len = len; + if (s->scsi_len) { + usb_msd_copy_data(s); + } + if (s->residue && s->usb_len) { + s->data_len -= s->usb_len; + memset(s->usb_buf, 0, s->usb_len); + if (s->data_len == 0) + s->mode = USB_MSDM_CSW; + s->usb_len = 0; + } + if (s->usb_len) { DPRINTF("Deferring packet %p\n", p); usb_defer_packet(p, usb_msd_cancel_io, s); s->packet = p; ret = USB_RET_ASYNC; + } else { + ret = len; } break; @@ -436,7 +535,7 @@ USBDevice *usb_msd_init(const char *filename) snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", filename); - s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); + s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s); usb_msd_handle_reset((USBDevice *)s); return (USBDevice *)s; fail: diff --git a/vl.h b/vl.h index 461caea02..bd1e6673f 100644 --- a/vl.h +++ b/vl.h @@ -1025,12 +1025,20 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ extern QEMUMachine sun4m_machine; -uint32_t iommu_translate(uint32_t addr); void pic_set_irq_cpu(int irq, int level, unsigned int cpu); +/* ??? Remove iommu_translate once lance emulation has been converted. */ +uint32_t iommu_translate(uint32_t addr); +void sparc_iommu_memory_read(target_phys_addr_t addr, + uint8_t *buf, int len); +void sparc_iommu_memory_write(target_phys_addr_t addr, + uint8_t *buf, int len); /* iommu.c */ void *iommu_init(uint32_t addr); +/* ??? Remove iommu_translate_local. */ uint32_t iommu_translate_local(void *opaque, uint32_t addr); +void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int is_write); /* lance.c */ void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr); @@ -1157,9 +1165,11 @@ enum scsi_reason { }; typedef struct SCSIDevice SCSIDevice; -typedef void (*scsi_completionfn)(void *, uint32_t, int); +typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag, + uint32_t arg); SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, + int tcq, scsi_completionfn completion, void *opaque); void scsi_disk_destroy(SCSIDevice *s); @@ -1168,9 +1178,10 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); /* SCSI data transfers are asynchrnonous. However, unlike the block IO layer the completion routine may be called directly by scsi_{read,write}_data. */ -int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len); -int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len); -void scsi_cancel_io(SCSIDevice *s); +void scsi_read_data(SCSIDevice *s, uint32_t tag); +int scsi_write_data(SCSIDevice *s, uint32_t tag); +void scsi_cancel_io(SCSIDevice *s, uint32_t tag); +uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); /* lsi53c895a.c */ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); -- cgit v1.2.3 From 6192bc374ff3fb8d7dfc8723dee28559488dfff5 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 3 Sep 2006 12:08:37 +0000 Subject: Flush IO requests before savevm (original patch by Blue Swirl). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2140 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 11 +++++++++++ vl.c | 6 ++++++ vl.h | 1 + 3 files changed, 18 insertions(+) diff --git a/block-raw.c b/block-raw.c index 3ed4b32de..3a2843c5d 100644 --- a/block-raw.c +++ b/block-raw.c @@ -247,6 +247,17 @@ void qemu_aio_poll(void) 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; diff --git a/vl.c b/vl.c index 771903099..32c994366 100644 --- a/vl.c +++ b/vl.c @@ -4551,6 +4551,9 @@ void do_savevm(const char *name) return; } + /* ??? Should this occur after vm_stop? */ + qemu_aio_flush(); + saved_vm_running = vm_running; vm_stop(0); @@ -4641,6 +4644,9 @@ void do_loadvm(const char *name) return; } + /* Flush all IO requests so they don't interfere with the new state. */ + qemu_aio_flush(); + saved_vm_running = vm_running; vm_stop(0); diff --git a/vl.h b/vl.h index bd1e6673f..14116fa75 100644 --- a/vl.h +++ b/vl.h @@ -580,6 +580,7 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb); 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); void qemu_aio_wait_end(void); -- cgit v1.2.3 From c03b0f0fd86d0d8883528754b24de49b63935c7f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Sep 2006 14:10:53 +0000 Subject: allow disabling of serial or parallel devices (Stefan Weil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2141 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 6 ++++++ vl.c | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 3bf3b5cd9..144381ff9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -506,12 +506,16 @@ Redirect the virtual serial port to host character device This option can be used several times to simulate up to 4 serials ports. +Use @code{-serial none} to disable all serial ports. + Available character devices are: @table @code @item vc Virtual console @item pty [Linux only] Pseudo TTY (a new PTY is automatically allocated) +@item none +No device is allocated. @item null void device @item /dev/XXX @@ -593,6 +597,8 @@ parallel port. This option can be used several times to simulate up to 3 parallel ports. +Use @code{-parallel none} to disable all parallel ports. + @item -monitor dev Redirect the monitor to host device @var{dev} (same devices as the serial port). diff --git a/vl.c b/vl.c index 32c994366..cdfd98c55 100644 --- a/vl.c +++ b/vl.c @@ -6850,27 +6850,29 @@ int main(int argc, char **argv) monitor_init(monitor_hd, !nographic); for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_devices[i][0] != '\0') { - serial_hds[i] = qemu_chr_open(serial_devices[i]); + const char *devname = serial_devices[i]; + if (devname[0] != '\0' && strcmp(devname, "none")) { + serial_hds[i] = qemu_chr_open(devname); if (!serial_hds[i]) { fprintf(stderr, "qemu: could not open serial device '%s'\n", - serial_devices[i]); + devname); exit(1); } - if (!strcmp(serial_devices[i], "vc")) + if (!strcmp(devname, "vc")) qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i); } } for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - if (parallel_devices[i][0] != '\0') { - parallel_hds[i] = qemu_chr_open(parallel_devices[i]); + const char *devname = parallel_devices[i]; + if (devname[0] != '\0' && strcmp(devname, "none")) { + parallel_hds[i] = qemu_chr_open(devname); if (!parallel_hds[i]) { fprintf(stderr, "qemu: could not open parallel device '%s'\n", - parallel_devices[i]); + devname); exit(1); } - if (!strcmp(parallel_devices[i], "vc")) + if (!strcmp(devname, "vc")) qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); } } -- cgit v1.2.3 From 91cc029598b7cd37c726175e05df7e45e9df6ffb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Sep 2006 16:07:02 +0000 Subject: initial sparc32 lance and pcnet merge git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2142 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lance.c | 474 ------------------------------------------------------------- hw/pcnet.c | 441 +++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 327 insertions(+), 588 deletions(-) delete mode 100644 hw/lance.c diff --git a/hw/lance.c b/hw/lance.c deleted file mode 100644 index 400cce5fb..000000000 --- a/hw/lance.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * QEMU Lance emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug LANCE card */ -//#define DEBUG_LANCE - -#ifdef DEBUG_LANCE -#define DPRINTF(fmt, args...) \ -do { printf("LANCE: " fmt , ##args); } while (0) -#else -#define DPRINTF(fmt, args...) -#endif - -#ifndef LANCE_LOG_TX_BUFFERS -#define LANCE_LOG_TX_BUFFERS 4 -#define LANCE_LOG_RX_BUFFERS 4 -#endif - -#define LE_CSR0 0 -#define LE_CSR1 1 -#define LE_CSR2 2 -#define LE_CSR3 3 -#define LE_NREGS (LE_CSR3 + 1) -#define LE_MAXREG LE_CSR3 - -#define LE_RDP 0 -#define LE_RAP 1 - -#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ - -#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ -#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ -#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ -#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ -#define LE_C0_MERR 0x0800 /* ME: Memory error */ -#define LE_C0_RINT 0x0400 /* Received interrupt */ -#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ -#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ -#define LE_C0_INTR 0x0080 /* Interrupt or error */ -#define LE_C0_INEA 0x0040 /* Interrupt enable */ -#define LE_C0_RXON 0x0020 /* Receiver on */ -#define LE_C0_TXON 0x0010 /* Transmitter on */ -#define LE_C0_TDMD 0x0008 /* Transmitter demand */ -#define LE_C0_STOP 0x0004 /* Stop the card */ -#define LE_C0_STRT 0x0002 /* Start the card */ -#define LE_C0_INIT 0x0001 /* Init the card */ - -#define LE_C3_BSWP 0x4 /* SWAP */ -#define LE_C3_ACON 0x2 /* ALE Control */ -#define LE_C3_BCON 0x1 /* Byte control */ - -/* Receive message descriptor 1 */ -#define LE_R1_OWN 0x80 /* Who owns the entry */ -#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ -#define LE_R1_FRA 0x20 /* FRA: Frame error */ -#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ -#define LE_R1_CRC 0x08 /* CRC error */ -#define LE_R1_BUF 0x04 /* BUF: Buffer error */ -#define LE_R1_SOP 0x02 /* Start of packet */ -#define LE_R1_EOP 0x01 /* End of packet */ -#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ - -#define LE_T1_OWN 0x80 /* Lance owns the packet */ -#define LE_T1_ERR 0x40 /* Error summary */ -#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ -#define LE_T1_EONE 0x08 /* Error: one retry needed */ -#define LE_T1_EDEF 0x04 /* Error: deferred */ -#define LE_T1_SOP 0x02 /* Start of packet */ -#define LE_T1_EOP 0x01 /* End of packet */ -#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ - -#define LE_T3_BUF 0x8000 /* Buffer error */ -#define LE_T3_UFL 0x4000 /* Error underflow */ -#define LE_T3_LCOL 0x1000 /* Error late collision */ -#define LE_T3_CLOS 0x0800 /* Error carrier loss */ -#define LE_T3_RTY 0x0400 /* Error retry */ -#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ - -#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) - -#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) - -#define PKT_BUF_SZ 1544 -#define RX_BUFF_SIZE PKT_BUF_SZ -#define TX_BUFF_SIZE PKT_BUF_SZ - -struct lance_rx_desc { - unsigned short rmd0; /* low address of packet */ - unsigned char rmd1_bits; /* descriptor bits */ - unsigned char rmd1_hadr; /* high address of packet */ - short length; /* This length is 2s complement (negative)! - * Buffer length - */ - unsigned short mblength; /* This is the actual number of bytes received */ -}; - -struct lance_tx_desc { - unsigned short tmd0; /* low address of packet */ - unsigned char tmd1_bits; /* descriptor bits */ - unsigned char tmd1_hadr; /* high address of packet */ - short length; /* Length is 2s complement (negative)! */ - unsigned short misc; -}; - -/* The LANCE initialization block, described in databook. */ -/* On the Sparc, this block should be on a DMA region */ -struct lance_init_block { - unsigned short mode; /* Pre-set mode (reg. 15) */ - unsigned char phys_addr[6]; /* Physical ethernet address */ - unsigned filter[2]; /* Multicast filter. */ - - /* Receive and transmit ring base, along with extra bits. */ - unsigned short rx_ptr; /* receive descriptor addr */ - unsigned short rx_len; /* receive len and high addr */ - unsigned short tx_ptr; /* transmit descriptor addr */ - unsigned short tx_len; /* transmit len and high addr */ - - /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ - struct lance_rx_desc brx_ring[RX_RING_SIZE]; - struct lance_tx_desc btx_ring[TX_RING_SIZE]; - - char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE]; - char pad[2]; /* align rx_buf for copy_and_sum(). */ - char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE]; -}; - -#define LEDMA_REGS 4 -#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) - -typedef struct LANCEState { - VLANClientState *vc; - uint8_t macaddr[6]; /* init mac address */ - uint32_t leptr; - uint16_t addr; - uint16_t regs[LE_NREGS]; - uint8_t phys[6]; /* mac address */ - int irq; - unsigned int rxptr, txptr; - uint32_t ledmaregs[LEDMA_REGS]; -} LANCEState; - -static void lance_send(void *opaque); - -static void lance_reset(void *opaque) -{ - LANCEState *s = opaque; - memcpy(s->phys, s->macaddr, 6); - s->rxptr = 0; - s->txptr = 0; - memset(s->regs, 0, LE_NREGS * 2); - s->regs[LE_CSR0] = LE_C0_STOP; - memset(s->ledmaregs, 0, LEDMA_REGS * 4); -} - -static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) -{ - LANCEState *s = opaque; - uint32_t saddr; - - saddr = addr & LE_MAXREG; - switch (saddr >> 1) { - case LE_RDP: - DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]); - return s->regs[s->addr]; - case LE_RAP: - DPRINTF("read areg = %4.4x\n", s->addr); - return s->addr; - default: - DPRINTF("read unknown(%d)\n", saddr >> 1); - break; - } - return 0; -} - -static void lance_mem_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - LANCEState *s = opaque; - uint32_t saddr; - uint16_t reg; - - saddr = addr & LE_MAXREG; - switch (saddr >> 1) { - case LE_RDP: - DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val); - switch (s->addr) { - case LE_CSR0: - if (val & LE_C0_STOP) { - s->regs[LE_CSR0] = LE_C0_STOP; - break; - } - - reg = s->regs[LE_CSR0]; - - // 1 = clear for some bits - reg &= ~(val & 0x7f00); - - // generated bits - reg &= ~(LE_C0_ERR | LE_C0_INTR); - if (reg & 0x7100) - reg |= LE_C0_ERR; - if (reg & 0x7f00) - reg |= LE_C0_INTR; - - // direct bit - reg &= ~LE_C0_INEA; - reg |= val & LE_C0_INEA; - - // exclusive bits - if (val & LE_C0_INIT) { - reg |= LE_C0_IDON | LE_C0_INIT; - reg &= ~LE_C0_STOP; - } else if (val & LE_C0_STRT) { - reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; - reg &= ~LE_C0_STOP; - } - - s->regs[LE_CSR0] = reg; - break; - case LE_CSR1: - s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); - s->regs[s->addr] = val; - break; - case LE_CSR2: - s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); - s->regs[s->addr] = val; - break; - case LE_CSR3: - s->regs[s->addr] = val; - break; - } - break; - case LE_RAP: - DPRINTF("write areg = %4.4x\n", val); - if (val < LE_NREGS) - s->addr = val; - break; - default: - DPRINTF("write unknown(%d) = %4.4x\n", saddr >> 1, val); - break; - } - lance_send(s); -} - -static CPUReadMemoryFunc *lance_mem_read[3] = { - lance_mem_readw, - lance_mem_readw, - lance_mem_readw, -}; - -static CPUWriteMemoryFunc *lance_mem_write[3] = { - lance_mem_writew, - lance_mem_writew, - lance_mem_writew, -}; - - -#define MIN_BUF_SIZE 60 - -static int lance_can_receive(void *opaque) -{ - return 1; -} - -static void lance_receive(void *opaque, const uint8_t * buf, int size) -{ - LANCEState *s = opaque; - uint32_t dmaptr = s->leptr + s->ledmaregs[3]; - struct lance_init_block *ib; - unsigned int i, old_rxptr; - uint16_t temp16; - uint8_t temp8; - - DPRINTF("receive size %d\n", size); - if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) - return; - - ib = (void *) iommu_translate(dmaptr); - - old_rxptr = s->rxptr; - for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); - i = (i + 1) & RX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t) & ib->brx_ring[i].rmd1_bits, - (void *) &temp8, 1); - if (temp8 == (LE_R1_OWN)) { - s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; - temp16 = size + 4; - bswap16s(&temp16); - cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. - mblength, (void *) &temp16, 2); - cpu_physical_memory_write((uint32_t) & ib->rx_buf[i], buf, - size); - temp8 = LE_R1_POK; - cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. - rmd1_bits, (void *) &temp8, 1); - s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; - if (s->regs[LE_CSR0] & LE_C0_INEA) - pic_set_irq(s->irq, 1); - DPRINTF("got packet, len %d\n", size); - return; - } - } -} - -static void lance_send(void *opaque) -{ - LANCEState *s = opaque; - uint32_t dmaptr = s->leptr + s->ledmaregs[3]; - struct lance_init_block *ib; - unsigned int i, old_txptr; - uint16_t temp16; - uint8_t temp8; - char pkt_buf[PKT_BUF_SZ]; - - DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]); - if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) - return; - - ib = (void *) iommu_translate(dmaptr); - - DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", - dmaptr, ib, &ib->btx_ring); - old_txptr = s->txptr; - for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); - i = (i + 1) & TX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].tmd1_bits, - (void *) &temp8, 1); - if (temp8 == (LE_T1_POK | LE_T1_OWN)) { - cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].length, - (void *) &temp16, 2); - bswap16s(&temp16); - temp16 = (~temp16) + 1; - cpu_physical_memory_read((uint32_t) & ib->tx_buf[i], pkt_buf, - temp16); - DPRINTF("sending packet, len %d\n", temp16); - qemu_send_packet(s->vc, pkt_buf, temp16); - temp8 = LE_T1_POK; - cpu_physical_memory_write((uint32_t) & ib->btx_ring[i]. - tmd1_bits, (void *) &temp8, 1); - s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; - s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; - } - } - if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) - pic_set_irq(s->irq, 1); -} - -static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) -{ - LANCEState *s = opaque; - uint32_t saddr; - - saddr = (addr & LEDMA_MAXADDR) >> 2; - return s->ledmaregs[saddr]; -} - -static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - LANCEState *s = opaque; - uint32_t saddr; - - saddr = (addr & LEDMA_MAXADDR) >> 2; - s->ledmaregs[saddr] = val; -} - -static CPUReadMemoryFunc *ledma_mem_read[3] = { - ledma_mem_readl, - ledma_mem_readl, - ledma_mem_readl, -}; - -static CPUWriteMemoryFunc *ledma_mem_write[3] = { - ledma_mem_writel, - ledma_mem_writel, - ledma_mem_writel, -}; - -static void lance_save(QEMUFile * f, void *opaque) -{ - LANCEState *s = opaque; - int i; - - qemu_put_be32s(f, &s->leptr); - qemu_put_be16s(f, &s->addr); - for (i = 0; i < LE_NREGS; i++) - qemu_put_be16s(f, &s->regs[i]); - qemu_put_buffer(f, s->phys, 6); - qemu_put_be32s(f, &s->irq); - for (i = 0; i < LEDMA_REGS; i++) - qemu_put_be32s(f, &s->ledmaregs[i]); -} - -static int lance_load(QEMUFile * f, void *opaque, int version_id) -{ - LANCEState *s = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, &s->leptr); - qemu_get_be16s(f, &s->addr); - for (i = 0; i < LE_NREGS; i++) - qemu_get_be16s(f, &s->regs[i]); - qemu_get_buffer(f, s->phys, 6); - qemu_get_be32s(f, &s->irq); - for (i = 0; i < LEDMA_REGS; i++) - qemu_get_be32s(f, &s->ledmaregs[i]); - return 0; -} - -void lance_init(NICInfo * nd, int irq, uint32_t leaddr, uint32_t ledaddr) -{ - LANCEState *s; - int lance_io_memory, ledma_io_memory; - - s = qemu_mallocz(sizeof(LANCEState)); - if (!s) - return; - - s->irq = irq; - - lance_io_memory = - cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); - cpu_register_physical_memory(leaddr, 4, lance_io_memory); - - ledma_io_memory = - cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); - cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); - - memcpy(s->macaddr, nd->macaddr, 6); - - lance_reset(s); - - s->vc = - qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, - s); - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - s->macaddr[0], - s->macaddr[1], - s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); - - register_savevm("lance", leaddr, 1, lance_save, lance_load, s); - qemu_register_reset(lance_reset, s); -} diff --git a/hw/pcnet.c b/hw/pcnet.c index 0845cdc3e..6b78408d6 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -27,6 +27,16 @@ * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 */ +/* + * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also + * produced as NCR89C100. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt + * and + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt + */ + +/* TODO: remove little endian host assumptions */ + #include "vl.h" //#define PCNET_DEBUG @@ -46,11 +56,12 @@ typedef struct PCNetState_st PCNetState; struct PCNetState_st { PCIDevice dev; + PCIDevice *pci_dev; VLANClientState *vc; NICInfo *nd; QEMUTimer *poll_timer; - int mmio_io_addr, rap, isr, lnkst; - target_phys_addr_t rdra, tdra; + int mmio_index, rap, isr, lnkst; + uint32_t rdra, tdra; uint8_t prom[16]; uint16_t csr[128]; uint16_t bcr[32]; @@ -58,6 +69,12 @@ struct PCNetState_st { int xmit_pos, recv_pos; uint8_t buffer[4096]; int tx_busy; + void (*set_irq_cb)(void *s, int isr); + void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, + uint8_t *buf, int len); + void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, + uint8_t *buf, int len); + void *dma_opaque; }; /* XXX: using bitfields for target memory structures is almost surely @@ -99,6 +116,7 @@ struct qemu_ether_header { #define CSR_TXON(S) !!(((S)->csr[0])&0x0010) #define CSR_RXON(S) !!(((S)->csr[0])&0x0020) #define CSR_INEA(S) !!(((S)->csr[0])&0x0040) +#define CSR_BIGENDIAN(S) !!(((S)->csr[3])&0x0004) #define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020) #define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040) #define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800) @@ -147,35 +165,19 @@ struct qemu_ether_header { struct pcnet_initblk16 { uint16_t mode; - uint16_t padr1; - uint16_t padr2; - uint16_t padr3; - uint16_t ladrf1; - uint16_t ladrf2; - uint16_t ladrf3; - uint16_t ladrf4; - unsigned PACKED_FIELD(rdra:24); - unsigned PACKED_FIELD(res1:5); - unsigned PACKED_FIELD(rlen:3); - unsigned PACKED_FIELD(tdra:24); - unsigned PACKED_FIELD(res2:5); - unsigned PACKED_FIELD(tlen:3); + uint16_t padr[3]; + uint16_t ladrf[4]; + uint32_t rdra; + uint32_t tdra; }; struct pcnet_initblk32 { uint16_t mode; - unsigned PACKED_FIELD(res1:4); - unsigned PACKED_FIELD(rlen:4); - unsigned PACKED_FIELD(res2:4); - unsigned PACKED_FIELD(tlen:4); - uint16_t padr1; - uint16_t padr2; - uint16_t padr3; + uint8_t rlen; + uint8_t tlen; + uint16_t padr[3]; uint16_t _res; - uint16_t ladrf1; - uint16_t ladrf2; - uint16_t ladrf3; - uint16_t ladrf4; + uint16_t ladrf[4]; uint32_t rdra; uint32_t tdra; }; @@ -255,22 +257,32 @@ static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_p { if (!BCR_SWSTYLE(s)) { uint16_t xda[4]; - cpu_physical_memory_read(addr, + s->phys_mem_read(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda)); - ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | + if (CSR_BIGENDIAN(s)) { + ((uint32_t *)tmd)[0] = be16_to_cpu(xda[0]) | + ((be16_to_cpu(xda[1]) & 0x00ff) << 16); + ((uint32_t *)tmd)[1] = be16_to_cpu(xda[2]) | + ((be16_to_cpu(xda[1]) & 0xff00) << 16); + ((uint32_t *)tmd)[2] = + (be16_to_cpu(xda[3]) & 0xffff) << 16; + ((uint32_t *)tmd)[3] = 0; + } else { + ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | ((xda[1]&0x00ff) << 16); - ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| + ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| ((xda[1] & 0xff00) << 16); - ((uint32_t *)tmd)[2] = + ((uint32_t *)tmd)[2] = (xda[3] & 0xffff) << 16; - ((uint32_t *)tmd)[3] = 0; + ((uint32_t *)tmd)[3] = 0; + } } else if (BCR_SWSTYLE(s) != 3) - cpu_physical_memory_read(addr, (void *)tmd, 16); + s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, 16); else { uint32_t xda[4]; - cpu_physical_memory_read(addr, + s->phys_mem_read(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda)); ((uint32_t *)tmd)[0] = xda[2]; ((uint32_t *)tmd)[1] = xda[1]; @@ -283,24 +295,32 @@ static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_ { if (!BCR_SWSTYLE(s)) { uint16_t xda[4]; - xda[0] = ((uint32_t *)tmd)[0] & 0xffff; - xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | - ((((uint32_t *)tmd)[1]>>16)&0xff00); - xda[2] = ((uint32_t *)tmd)[1] & 0xffff; - xda[3] = ((uint32_t *)tmd)[2] >> 16; - cpu_physical_memory_write(addr, + if (CSR_BIGENDIAN(s)) { + xda[0] = cpu_to_be16(((uint32_t *)tmd)[0] & 0xffff); + xda[1] = cpu_to_be16(((((uint32_t *)tmd)[0] >> 16) & 0x00ff) | + ((((uint32_t *)tmd)[1] >> 16) & 0xff00)); + xda[2] = cpu_to_be16(((uint32_t *)tmd)[1] & 0xffff); + xda[3] = cpu_to_be16(((uint32_t *)tmd)[2] >> 16); + } else { + xda[0] = ((uint32_t *)tmd)[0] & 0xffff; + xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | + ((((uint32_t *)tmd)[1]>>16)&0xff00); + xda[2] = ((uint32_t *)tmd)[1] & 0xffff; + xda[3] = ((uint32_t *)tmd)[2] >> 16; + } + s->phys_mem_write(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda)); } else { if (BCR_SWSTYLE(s) != 3) - cpu_physical_memory_write(addr, (void *)tmd, 16); + s->phys_mem_write(s->dma_opaque, addr, (void *)tmd, 16); else { uint32_t xda[4]; xda[0] = ((uint32_t *)tmd)[2]; xda[1] = ((uint32_t *)tmd)[1]; xda[2] = ((uint32_t *)tmd)[0]; xda[3] = ((uint32_t *)tmd)[3]; - cpu_physical_memory_write(addr, + s->phys_mem_write(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda)); } } @@ -310,21 +330,30 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_p { if (!BCR_SWSTYLE(s)) { uint16_t rda[4]; - cpu_physical_memory_read(addr, + s->phys_mem_read(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda)); - ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| + if (CSR_BIGENDIAN(s)) { + ((uint32_t *)rmd)[0] = (be16_to_cpu(rda[0]) & 0xffff) | + ((be16_to_cpu(rda[1]) & 0x00ff) << 16); + ((uint32_t *)rmd)[1] = (be16_to_cpu(rda[2]) & 0xffff) | + ((be16_to_cpu(rda[1]) & 0xff00) << 16); + ((uint32_t *)rmd)[2] = be16_to_cpu(rda[3]) & 0xffff; + ((uint32_t *)rmd)[3] = 0; + } else { + ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| ((rda[1] & 0x00ff) << 16); - ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| + ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| ((rda[1] & 0xff00) << 16); - ((uint32_t *)rmd)[2] = rda[3] & 0xffff; - ((uint32_t *)rmd)[3] = 0; + ((uint32_t *)rmd)[2] = rda[3] & 0xffff; + ((uint32_t *)rmd)[3] = 0; + } } else if (BCR_SWSTYLE(s) != 3) - cpu_physical_memory_read(addr, (void *)rmd, 16); + s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, 16); else { uint32_t rda[4]; - cpu_physical_memory_read(addr, + s->phys_mem_read(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda)); ((uint32_t *)rmd)[0] = rda[2]; ((uint32_t *)rmd)[1] = rda[1]; @@ -336,25 +365,33 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_p static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) { if (!BCR_SWSTYLE(s)) { - uint16_t rda[4]; \ - rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \ - rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\ - ((((uint32_t *)rmd)[1]>>16)&0xff00);\ - rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \ - rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \ - cpu_physical_memory_write(addr, \ - (void *)&rda[0], sizeof(rda)); \ + uint16_t rda[4]; + if (CSR_BIGENDIAN(s)) { + rda[0] = cpu_to_be16(((uint32_t *)rmd)[0] & 0xffff); + rda[1] = cpu_to_be16(((((uint32_t *)rmd)[0] >> 16) & 0xff) | + ((((uint32_t *)rmd)[1] >> 16) & 0xff00)); + rda[2] = cpu_to_be16(((uint32_t *)rmd)[1] & 0xffff); + rda[3] = cpu_to_be16(((uint32_t *)rmd)[2] & 0xffff); + } else { + rda[0] = ((uint32_t *)rmd)[0] & 0xffff; + rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)| + ((((uint32_t *)rmd)[1]>>16)&0xff00); + rda[2] = ((uint32_t *)rmd)[1] & 0xffff; + rda[3] = ((uint32_t *)rmd)[2] & 0xffff; + } + s->phys_mem_write(s->dma_opaque, addr, + (void *)&rda[0], sizeof(rda)); } else { if (BCR_SWSTYLE(s) != 3) - cpu_physical_memory_write(addr, (void *)rmd, 16); + s->phys_mem_write(s->dma_opaque, addr, (void *)rmd, 16); else { uint32_t rda[4]; rda[0] = ((uint32_t *)rmd)[2]; rda[1] = ((uint32_t *)rmd)[1]; rda[2] = ((uint32_t *)rmd)[0]; rda[3] = ((uint32_t *)rmd)[3]; - cpu_physical_memory_write(addr, + s->phys_mem_write(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda)); } } @@ -391,7 +428,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ case 0x00: \ do { \ uint16_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&rda[0], sizeof(rda)); \ (RES) |= (rda[2] & 0xf000)!=0xf000; \ (RES) |= (rda[3] & 0xf000)!=0x0000; \ @@ -401,7 +438,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ case 0x02: \ do { \ uint32_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&rda[0], sizeof(rda)); \ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ @@ -410,7 +447,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ case 0x03: \ do { \ uint32_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&rda[0], sizeof(rda)); \ (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ @@ -424,7 +461,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ case 0x00: \ do { \ uint16_t xda[4]; \ - cpu_physical_memory_read((ADDR), \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&xda[0], sizeof(xda)); \ (RES) |= (xda[2] & 0xf000)!=0xf000;\ } while (0); \ @@ -434,7 +471,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ case 0x03: \ do { \ uint32_t xda[4]; \ - cpu_physical_memory_read((ADDR), \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&xda[0], sizeof(xda)); \ (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ } while (0); \ @@ -721,51 +758,86 @@ static void pcnet_update_irq(PCNetState *s) printf("pcnet: INTA=%d\n", isr); #endif } - pci_set_irq(&s->dev, 0, isr); - s->isr = isr; + s->set_irq_cb(s, isr); + s->isr = isr; } static void pcnet_init(PCNetState *s) { + int rlen, tlen; + uint16_t *padr, *ladrf, mode; + uint32_t rdra, tdra; + #ifdef PCNET_DEBUG printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); #endif -#define PCNET_INIT() do { \ - cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \ - (uint8_t *)&initblk, sizeof(initblk)); \ - s->csr[15] = le16_to_cpu(initblk.mode); \ - CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \ - CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \ - s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \ - s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \ - s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \ - s->csr[10] = le16_to_cpu(initblk.ladrf3); \ - s->csr[11] = le16_to_cpu(initblk.ladrf4); \ - s->csr[12] = le16_to_cpu(initblk.padr1); \ - s->csr[13] = le16_to_cpu(initblk.padr2); \ - s->csr[14] = le16_to_cpu(initblk.padr3); \ - s->rdra = PHYSADDR(s,initblk.rdra); \ - s->tdra = PHYSADDR(s,initblk.tdra); \ -} while (0) - if (BCR_SSIZE32(s)) { struct pcnet_initblk32 initblk; - PCNET_INIT(); -#ifdef PCNET_DEBUG - printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", - initblk.rlen, initblk.tlen); -#endif + s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), + (uint8_t *)&initblk, sizeof(initblk)); + mode = initblk.mode; + rlen = initblk.rlen >> 4; + tlen = initblk.tlen >> 4; + ladrf = initblk.ladrf; + padr = initblk.padr; + if (CSR_BIGENDIAN(s)) { + rdra = be32_to_cpu(initblk.rdra); + tdra = be32_to_cpu(initblk.tdra); + } else { + rdra = le32_to_cpu(initblk.rdra); + tdra = le32_to_cpu(initblk.tdra); + } + s->rdra = PHYSADDR(s,initblk.rdra); + s->tdra = PHYSADDR(s,initblk.tdra); } else { struct pcnet_initblk16 initblk; - PCNET_INIT(); -#ifdef PCNET_DEBUG - printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", - initblk.rlen, initblk.tlen); + s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), + (uint8_t *)&initblk, sizeof(initblk)); + mode = initblk.mode; + ladrf = initblk.ladrf; + padr = initblk.padr; + if (CSR_BIGENDIAN(s)) { + rdra = be32_to_cpu(initblk.rdra); + tdra = be32_to_cpu(initblk.tdra); + } else { + rdra = le32_to_cpu(initblk.rdra); + tdra = le32_to_cpu(initblk.tdra); + } + rlen = rdra >> 29; + tlen = tdra >> 29; + rdra &= 0x00ffffff; + tdra &= 0x00ffffff; + } + +#if defined(PCNET_DEBUG) + printf("rlen=%d tlen=%d\n", + rlen, tlen); #endif + CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512; + CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512; + s->csr[ 6] = (tlen << 12) | (rlen << 8); + if (CSR_BIGENDIAN(s)) { + s->csr[15] = be16_to_cpu(mode); + s->csr[ 8] = be16_to_cpu(ladrf[0]); + s->csr[ 9] = be16_to_cpu(ladrf[1]); + s->csr[10] = be16_to_cpu(ladrf[2]); + s->csr[11] = be16_to_cpu(ladrf[3]); + s->csr[12] = be16_to_cpu(padr[0]); + s->csr[13] = be16_to_cpu(padr[1]); + s->csr[14] = be16_to_cpu(padr[2]); + } else { + s->csr[15] = le16_to_cpu(mode); + s->csr[ 8] = le16_to_cpu(ladrf[0]); + s->csr[ 9] = le16_to_cpu(ladrf[1]); + s->csr[10] = le16_to_cpu(ladrf[2]); + s->csr[11] = le16_to_cpu(ladrf[3]); + s->csr[12] = le16_to_cpu(padr[0]); + s->csr[13] = le16_to_cpu(padr[1]); + s->csr[14] = le16_to_cpu(padr[2]); } - -#undef PCNET_INIT + s->rdra = PHYSADDR(s, rdra); + s->tdra = PHYSADDR(s, tdra); CSR_RCVRC(s) = CSR_RCVRL(s); CSR_XMTRC(s) = CSR_XMTRL(s); @@ -1035,7 +1107,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) #define PCNET_RECV_STORE() do { \ int count = MIN(4096 - rmd.rmd1.bcnt,size); \ target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ - cpu_physical_memory_write(rbadr, src, count); \ + s->phys_mem_write(s->dma_opaque, rbadr, src, count); \ src += count; size -= count; \ rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ RMDSTORE(&rmd, PHYSADDR(s,crda)); \ @@ -1125,14 +1197,14 @@ static void pcnet_transmit(PCNetState *s) if (tmd.tmd1.stp) { s->xmit_pos = 0; if (!tmd.tmd1.enp) { - cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), + s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), s->buffer, 4096 - tmd.tmd1.bcnt); s->xmit_pos += 4096 - tmd.tmd1.bcnt; } xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); } if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { - cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), + s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); s->xmit_pos += 4096 - tmd.tmd1.bcnt; #ifdef PCNET_DEBUG @@ -1426,8 +1498,9 @@ static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) return val; } -static void pcnet_h_reset(PCNetState *s) +void pcnet_h_reset(void *opaque) { + PCNetState *s = opaque; int i; uint16_t checksum; @@ -1703,6 +1776,90 @@ static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) } +static void pcnet_save(QEMUFile *f, void *opaque) +{ + PCNetState *s = opaque; + unsigned int i; + + if (s->pci_dev) + pci_device_save(s->pci_dev, f); + + qemu_put_be32s(f, &s->rap); + qemu_put_be32s(f, &s->isr); + qemu_put_be32s(f, &s->lnkst); + qemu_put_be32s(f, &s->rdra); + qemu_put_be32s(f, &s->tdra); + qemu_put_buffer(f, s->prom, 16); + for (i = 0; i < 128; i++) + qemu_put_be16s(f, &s->csr[i]); + for (i = 0; i < 32; i++) + qemu_put_be16s(f, &s->bcr[i]); + qemu_put_be64s(f, &s->timer); + qemu_put_be32s(f, &s->xmit_pos); + qemu_put_be32s(f, &s->recv_pos); + qemu_put_buffer(f, s->buffer, 4096); + qemu_put_be32s(f, &s->tx_busy); + qemu_put_timer(f, s->poll_timer); +} + +static int pcnet_load(QEMUFile *f, void *opaque, int version_id) +{ + PCNetState *s = opaque; + int i, ret; + + if (version_id != 2) + return -EINVAL; + + if (s->pci_dev) { + ret = pci_device_load(s->pci_dev, f); + if (ret < 0) + return ret; + } + + qemu_get_be32s(f, &s->rap); + qemu_get_be32s(f, &s->isr); + qemu_get_be32s(f, &s->lnkst); + qemu_get_be32s(f, &s->rdra); + qemu_get_be32s(f, &s->tdra); + qemu_get_buffer(f, s->prom, 16); + for (i = 0; i < 128; i++) + qemu_get_be16s(f, &s->csr[i]); + for (i = 0; i < 32; i++) + qemu_get_be16s(f, &s->bcr[i]); + qemu_get_be64s(f, &s->timer); + qemu_get_be32s(f, &s->xmit_pos); + qemu_get_be32s(f, &s->recv_pos); + qemu_get_buffer(f, s->buffer, 4096); + qemu_get_be32s(f, &s->tx_busy); + qemu_get_timer(f, s->poll_timer); + + return 0; +} + +static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char *info_str) +{ + d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); + + d->nd = nd; + + d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, + pcnet_can_receive, d); + + snprintf(d->vc->info_str, sizeof(d->vc->info_str), + "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + d->nd->macaddr[0], + d->nd->macaddr[1], + d->nd->macaddr[2], + d->nd->macaddr[3], + d->nd->macaddr[4], + d->nd->macaddr[5]); + + pcnet_h_reset(d); + register_savevm("pcnet", 0, 2, pcnet_save, pcnet_load, d); +} + +/* PCI interface */ + static CPUWriteMemoryFunc *pcnet_mmio_write[] = { (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, (CPUWriteMemoryFunc *)&pcnet_mmio_writew, @@ -1724,7 +1881,26 @@ static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size); #endif - cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr); + cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index); +} + +static void pcnet_pci_set_irq_cb(void *opaque, int isr) +{ + PCNetState *s = opaque; + + pci_set_irq(&s->dev, 0, isr); +} + +static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, + uint8_t *buf, int len) +{ + cpu_physical_memory_write(addr, buf, len); +} + +static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, + uint8_t *buf, int len) +{ + cpu_physical_memory_read(addr, buf, len); } void pci_pcnet_init(PCIBus *bus, NICInfo *nd) @@ -1760,7 +1936,7 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd) pci_conf[0x3f] = 0xff; /* Handler for memory-mapped I/O */ - d->mmio_io_addr = + d->mmio_index = cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, @@ -1769,21 +1945,58 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd) pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); - d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); + d->set_irq_cb = pcnet_pci_set_irq_cb; + d->phys_mem_read = pci_physical_memory_read; + d->phys_mem_write = pci_physical_memory_write; + d->pci_dev = &d->dev; - d->nd = nd; + pcnet_common_init(d, nd, "pcnet"); +} - d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, - pcnet_can_receive, d); - - snprintf(d->vc->info_str, sizeof(d->vc->info_str), - "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - d->nd->macaddr[0], - d->nd->macaddr[1], - d->nd->macaddr[2], - d->nd->macaddr[3], - d->nd->macaddr[4], - d->nd->macaddr[5]); +/* SPARC32 interface */ - pcnet_h_reset(d); +#if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure + +static CPUReadMemoryFunc *lance_mem_read[3] = { + (CPUReadMemoryFunc *)&pcnet_ioport_readw, + (CPUReadMemoryFunc *)&pcnet_ioport_readw, + (CPUReadMemoryFunc *)&pcnet_ioport_readw, +}; + +static CPUWriteMemoryFunc *lance_mem_write[3] = { + (CPUWriteMemoryFunc *)&pcnet_ioport_writew, + (CPUWriteMemoryFunc *)&pcnet_ioport_writew, + (CPUWriteMemoryFunc *)&pcnet_ioport_writew, +}; + +static void pcnet_sparc_set_irq_cb(void *opaque, int isr) +{ + PCNetState *s = opaque; + + ledma_set_irq(s->dma_opaque, isr); +} + +void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque) +{ + PCNetState *d; + int lance_io_memory; + + d = qemu_mallocz(sizeof(PCNetState)); + if (!d) + return NULL; + + lance_io_memory = + cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); + + d->dma_opaque = dma_opaque; + cpu_register_physical_memory(leaddr, 4, lance_io_memory); + + d->set_irq_cb = pcnet_sparc_set_irq_cb; + d->phys_mem_read = ledma_memory_read; + d->phys_mem_write = ledma_memory_write; + + pcnet_common_init(d, nd, "lance"); + + return d; } +#endif /* TARGET_SPARC */ -- cgit v1.2.3 From 67e999be93410b9eb7024d879d8e4cf6ce124eed Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Sep 2006 16:09:07 +0000 Subject: Separate the DMA controllers - Convert ESP to new DMA methods (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2143 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/esp.c | 172 ++++++++++---------------------------- hw/iommu.c | 12 +-- hw/sparc32_dma.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/sun4m.c | 29 ++----- vl.h | 45 +++++++--- 6 files changed, 338 insertions(+), 173 deletions(-) create mode 100644 hw/sparc32_dma.c diff --git a/Makefile.target b/Makefile.target index 9ce7e7f5b..65c336298 100644 --- a/Makefile.target +++ b/Makefile.target @@ -359,8 +359,8 @@ 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 lance.o iommu.o m48t59.o slavio_intctl.o -VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o +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 endif endif ifeq ($(TARGET_BASE_ARCH), arm) diff --git a/hw/esp.c b/hw/esp.c index 991e5151f..be5600183 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -1,5 +1,5 @@ /* - * QEMU ESP emulation + * QEMU ESP/NCR53C9x emulation * * Copyright (c) 2005-2006 Fabrice Bellard * @@ -26,33 +26,31 @@ /* debug ESP card */ //#define DEBUG_ESP +/* + * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), also + * produced as NCR89C100. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt + * and + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt + */ + #ifdef DEBUG_ESP #define DPRINTF(fmt, args...) \ do { printf("ESP: " fmt , ##args); } while (0) -#define pic_set_irq(irq, level) \ -do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0) #else #define DPRINTF(fmt, args...) #endif -#define ESPDMA_REGS 4 -#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) #define ESP_MAXREG 0x3f #define TI_BUFSZ 32 -#define DMA_VER 0xa0000000 -#define DMA_INTR 1 -#define DMA_INTREN 0x10 -#define DMA_WRITE_MEM 0x100 -#define DMA_LOADED 0x04000000 + typedef struct ESPState ESPState; struct ESPState { BlockDriverState **bd; uint8_t rregs[ESP_MAXREG]; uint8_t wregs[ESP_MAXREG]; - int irq; - uint32_t espdmaregs[ESPDMA_REGS]; - uint32_t ti_size; + int32_t ti_size; uint32_t ti_rptr, ti_wptr; uint8_t ti_buf[TI_BUFSZ]; int sense; @@ -66,6 +64,7 @@ struct ESPState { uint32_t dma_left; uint8_t *async_buf; uint32_t async_len; + void *dma_opaque; }; #define STAT_DO 0x00 @@ -97,9 +96,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) target = s->wregs[4] & 7; DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->espdmaregs[1]); - sparc_iommu_memory_read(s->espdmaregs[1], buf, dmalen); + espdma_memory_read(s->dma_opaque, buf, dmalen); } else { buf[0] = 0; memcpy(&buf[1], s->ti_buf, dmalen); @@ -116,13 +113,12 @@ static int get_cmd(ESPState *s, uint8_t *buf) s->async_len = 0; } - if (target >= 4 || !s->scsi_dev[target]) { + if (target >= MAX_DISKS || !s->scsi_dev[target]) { // No such drive s->rregs[4] = STAT_IN; s->rregs[5] = INTR_DC; s->rregs[6] = SEQ_0; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); return 0; } s->current_dev = s->scsi_dev[target]; @@ -137,25 +133,21 @@ static void do_cmd(ESPState *s, uint8_t *buf) DPRINTF("do_cmd: busid 0x%x\n", buf[0]); lun = buf[0] & 7; datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); - if (datalen == 0) { - s->ti_size = 0; - } else { + s->ti_size = datalen; + if (datalen != 0) { s->rregs[4] = STAT_IN | STAT_TC; s->dma_left = 0; if (datalen > 0) { s->rregs[4] |= STAT_DI; - s->ti_size = datalen; scsi_read_data(s->current_dev, 0); } else { s->rregs[4] |= STAT_DO; - s->ti_size = -datalen; scsi_write_data(s->current_dev, 0); } } s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } static void handle_satn(ESPState *s) @@ -174,12 +166,10 @@ static void handle_satn_stop(ESPState *s) if (s->cmdlen) { DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); s->do_cmd = 1; - s->espdmaregs[1] += s->cmdlen; s->rregs[4] = STAT_IN | STAT_TC | STAT_CD; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } } @@ -189,9 +179,7 @@ static void write_response(ESPState *s) s->ti_buf[0] = s->sense; s->ti_buf[1] = 0; if (s->dma) { - DPRINTF("DMA Direction: %c\n", - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); - sparc_iommu_memory_write(s->espdmaregs[1], s->ti_buf, 2); + espdma_memory_write(s->dma_opaque, s->ti_buf, 2); s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; @@ -201,9 +189,7 @@ static void write_response(ESPState *s) s->ti_wptr = 0; s->rregs[7] = 2; } - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); - + espdma_raise_irq(s->dma_opaque); } static void esp_dma_done(ESPState *s) @@ -212,24 +198,19 @@ static void esp_dma_done(ESPState *s) s->rregs[5] = INTR_BS; s->rregs[6] = 0; s->rregs[7] = 0; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } static void esp_do_dma(ESPState *s) { - uint32_t addr, len; + uint32_t len; int to_device; - to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; - addr = s->espdmaregs[1]; + to_device = (s->ti_size < 0); len = s->dma_left; - DPRINTF("DMA address %08x len %08x\n", addr, len); if (s->do_cmd) { - s->espdmaregs[1] += len; - s->ti_size -= len; DPRINTF("command len %d + %d\n", s->cmdlen, len); - sparc_iommu_memory_read(addr, &s->cmdbuf[s->cmdlen], len); + espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); s->ti_size = 0; s->cmdlen = 0; s->do_cmd = 0; @@ -244,19 +225,20 @@ static void esp_do_dma(ESPState *s) len = s->async_len; } if (to_device) { - sparc_iommu_memory_read(addr, s->async_buf, len); + espdma_memory_read(s->dma_opaque, s->async_buf, len); } else { - sparc_iommu_memory_write(addr, s->async_buf, len); + espdma_memory_write(s->dma_opaque, s->async_buf, len); } - s->ti_size -= len; s->dma_left -= len; s->async_buf += len; s->async_len -= len; - s->espdmaregs[1] += len; if (s->async_len == 0) { if (to_device) { + // ti_size is negative + s->ti_size += len; scsi_write_data(s->current_dev, 0); } else { + s->ti_size -= len; scsi_read_data(s->current_dev, 0); } } @@ -303,6 +285,8 @@ static void handle_ti(ESPState *s) if (s->do_cmd) minlen = (dmalen < 32) ? dmalen : 32; + else if (s->ti_size < 0) + minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size; else minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; DPRINTF("Transfer Information len %d\n", minlen); @@ -320,13 +304,13 @@ static void handle_ti(ESPState *s) } } -static void esp_reset(void *opaque) +void esp_reset(void *opaque) { ESPState *s = opaque; + memset(s->rregs, 0, ESP_MAXREG); memset(s->wregs, 0, ESP_MAXREG); s->rregs[0x0e] = 0x4; // Indicate fas100a - memset(s->espdmaregs, 0, ESPDMA_REGS * 4); s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; @@ -353,7 +337,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) } else { s->rregs[2] = s->ti_buf[s->ti_rptr++]; } - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } if (s->ti_size == 0) { s->ti_rptr = 0; @@ -364,8 +348,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) // interrupt // Clear interrupt/error status bits s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE); - pic_set_irq(s->irq, 0); - s->espdmaregs[0] &= ~DMA_INTR; + espdma_clear_irq(s->dma_opaque); break; default: break; @@ -426,8 +409,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) DPRINTF("Bus reset (%2.2x)\n", val); s->rregs[5] = INTR_RST; if (!(s->wregs[8] & 0x40)) { - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } break; case 0x10: @@ -490,68 +472,12 @@ static CPUWriteMemoryFunc *esp_mem_write[3] = { esp_mem_writeb, }; -static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) -{ - ESPState *s = opaque; - uint32_t saddr; - - saddr = (addr & ESPDMA_MAXADDR) >> 2; - DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]); - - return s->espdmaregs[saddr]; -} - -static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - ESPState *s = opaque; - uint32_t saddr; - - saddr = (addr & ESPDMA_MAXADDR) >> 2; - DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val); - switch (saddr) { - case 0: - if (!(val & DMA_INTREN)) - pic_set_irq(s->irq, 0); - if (val & 0x80) { - esp_reset(s); - } else if (val & 0x40) { - val &= ~0x40; - } else if (val == 0) - val = 0x40; - val &= 0x0fffffff; - val |= DMA_VER; - break; - case 1: - s->espdmaregs[0] |= DMA_LOADED; - break; - default: - break; - } - s->espdmaregs[saddr] = val; -} - -static CPUReadMemoryFunc *espdma_mem_read[3] = { - espdma_mem_readl, - espdma_mem_readl, - espdma_mem_readl, -}; - -static CPUWriteMemoryFunc *espdma_mem_write[3] = { - espdma_mem_writel, - espdma_mem_writel, - espdma_mem_writel, -}; - static void esp_save(QEMUFile *f, void *opaque) { ESPState *s = opaque; - unsigned int i; qemu_put_buffer(f, s->rregs, ESP_MAXREG); qemu_put_buffer(f, s->wregs, ESP_MAXREG); - qemu_put_be32s(f, &s->irq); - for (i = 0; i < ESPDMA_REGS; i++) - qemu_put_be32s(f, &s->espdmaregs[i]); qemu_put_be32s(f, &s->ti_size); qemu_put_be32s(f, &s->ti_rptr); qemu_put_be32s(f, &s->ti_wptr); @@ -562,16 +488,12 @@ static void esp_save(QEMUFile *f, void *opaque) static int esp_load(QEMUFile *f, void *opaque, int version_id) { ESPState *s = opaque; - unsigned int i; - if (version_id != 1) - return -EINVAL; + if (version_id != 2) + return -EINVAL; // Cannot emulate 1 qemu_get_buffer(f, s->rregs, ESP_MAXREG); qemu_get_buffer(f, s->wregs, ESP_MAXREG); - qemu_get_be32s(f, &s->irq); - for (i = 0; i < ESPDMA_REGS; i++) - qemu_get_be32s(f, &s->espdmaregs[i]); qemu_get_be32s(f, &s->ti_size); qemu_get_be32s(f, &s->ti_rptr); qemu_get_be32s(f, &s->ti_wptr); @@ -581,28 +503,25 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr) +void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque) { ESPState *s; - int esp_io_memory, espdma_io_memory; + int esp_io_memory; int i; s = qemu_mallocz(sizeof(ESPState)); if (!s) - return; + return NULL; s->bd = bd; - s->irq = irq; + s->dma_opaque = dma_opaque; esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory); - espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s); - cpu_register_physical_memory(espdaddr, 16, espdma_io_memory); - esp_reset(s); - register_savevm("esp", espaddr, 1, esp_save, esp_load, s); + register_savevm("esp", espaddr, 2, esp_save, esp_load, s); qemu_register_reset(esp_reset, s); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { @@ -611,5 +530,6 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd scsi_disk_init(bs_table[i], 0, esp_command_complete, s); } } -} + return s; +} diff --git a/hw/iommu.c b/hw/iommu.c index 83001bd7f..5c2768cee 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -206,19 +206,11 @@ static uint32_t iommu_translate_pa(IOMMUState *s, uint32_t addr, uint32_t pa) return pa; } -uint32_t iommu_translate_local(void *opaque, uint32_t addr) -{ - uint32_t flags; - flags = iommu_page_get_flags(opaque, addr); - return iommu_translate_pa(opaque, addr, flags); -} - -void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int is_write) +void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int is_write) { int l, flags; target_ulong page, phys_addr; - void * p; while (len > 0) { page = addr & TARGET_PAGE_MASK; diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c new file mode 100644 index 000000000..d8d7e6a83 --- /dev/null +++ b/hw/sparc32_dma.c @@ -0,0 +1,249 @@ +/* + * QEMU Sparc32 DMA controller emulation + * + * 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" + +/* debug DMA */ +//#define DEBUG_DMA + +/* + * This is the DMA controller part of chip STP2000 (Master I/O), also + * produced as NCR89C100. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt + * and + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt + */ + +#ifdef DEBUG_DMA +#define DPRINTF(fmt, args...) \ +do { printf("DMA: " fmt , ##args); } while (0) +#define pic_set_irq_new(ctl, irq, level) \ + do { printf("DMA: set_irq(%d): %d\n", (irq), (level)); \ + pic_set_irq_new((ctl), (irq),(level));} while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +#define DMA_REGS 8 +#define DMA_MAXADDR (DMA_REGS * 4 - 1) + +#define DMA_VER 0xa0000000 +#define DMA_INTR 1 +#define DMA_INTREN 0x10 +#define DMA_WRITE_MEM 0x100 +#define DMA_LOADED 0x04000000 +#define DMA_RESET 0x80 + +typedef struct DMAState DMAState; + +struct DMAState { + uint32_t dmaregs[DMA_REGS]; + int espirq, leirq; + void *iommu, *esp_opaque, *lance_opaque, *intctl; +}; + +void ledma_set_irq(void *opaque, int isr) +{ + DMAState *s = opaque; + + pic_set_irq_new(s->intctl, s->leirq, isr); +} + +void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len) +{ + DMAState *s = opaque; + + DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n", + s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + sparc_iommu_memory_read(s->iommu, addr | s->dmaregs[7], buf, len); +} + +void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len) +{ + DMAState *s = opaque; + + DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n", + s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + sparc_iommu_memory_write(s->iommu, addr | s->dmaregs[7], buf, len); +} + +void espdma_raise_irq(void *opaque) +{ + DMAState *s = opaque; + + s->dmaregs[0] |= DMA_INTR; + pic_set_irq_new(s->intctl, s->espirq, 1); +} + +void espdma_clear_irq(void *opaque) +{ + DMAState *s = opaque; + + s->dmaregs[0] &= ~DMA_INTR; + pic_set_irq_new(s->intctl, s->espirq, 0); +} + +void espdma_memory_read(void *opaque, uint8_t *buf, int len) +{ + DMAState *s = opaque; + + DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n", + s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len); + s->dmaregs[0] |= DMA_INTR; + s->dmaregs[1] += len; +} + +void espdma_memory_write(void *opaque, uint8_t *buf, int len) +{ + DMAState *s = opaque; + + DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n", + s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len); + s->dmaregs[0] |= DMA_INTR; + s->dmaregs[1] += len; +} + +static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr) +{ + DMAState *s = opaque; + uint32_t saddr; + + saddr = (addr & DMA_MAXADDR) >> 2; + DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->dmaregs[saddr]); + + return s->dmaregs[saddr]; +} + +static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + DMAState *s = opaque; + uint32_t saddr; + + saddr = (addr & DMA_MAXADDR) >> 2; + DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->dmaregs[saddr], val); + switch (saddr) { + case 0: + if (!(val & DMA_INTREN)) + pic_set_irq_new(s->intctl, s->espirq, 0); + if (val & DMA_RESET) { + esp_reset(s->esp_opaque); + } else if (val & 0x40) { + val &= ~0x40; + } else if (val == 0) + val = 0x40; + val &= 0x0fffffff; + val |= DMA_VER; + break; + case 1: + s->dmaregs[0] |= DMA_LOADED; + break; + case 4: + if (!(val & DMA_INTREN)) + pic_set_irq_new(s->intctl, s->leirq, 0); + if (val & DMA_RESET) + pcnet_h_reset(s->lance_opaque); + val &= 0x0fffffff; + val |= DMA_VER; + break; + default: + break; + } + s->dmaregs[saddr] = val; +} + +static CPUReadMemoryFunc *dma_mem_read[3] = { + dma_mem_readl, + dma_mem_readl, + dma_mem_readl, +}; + +static CPUWriteMemoryFunc *dma_mem_write[3] = { + dma_mem_writel, + dma_mem_writel, + dma_mem_writel, +}; + +static void dma_reset(void *opaque) +{ + DMAState *s = opaque; + + memset(s->dmaregs, 0, DMA_REGS * 4); + s->dmaregs[0] = DMA_VER; + s->dmaregs[4] = DMA_VER; +} + +static void dma_save(QEMUFile *f, void *opaque) +{ + DMAState *s = opaque; + unsigned int i; + + for (i = 0; i < DMA_REGS; i++) + qemu_put_be32s(f, &s->dmaregs[i]); +} + +static int dma_load(QEMUFile *f, void *opaque, int version_id) +{ + DMAState *s = opaque; + unsigned int i; + + if (version_id != 1) + return -EINVAL; + for (i = 0; i < DMA_REGS; i++) + qemu_get_be32s(f, &s->dmaregs[i]); + + return 0; +} + +void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, void *intctl) +{ + DMAState *s; + int dma_io_memory; + + s = qemu_mallocz(sizeof(DMAState)); + if (!s) + return NULL; + + s->espirq = espirq; + s->leirq = leirq; + s->iommu = iommu; + s->intctl = intctl; + + dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s); + cpu_register_physical_memory(daddr, 16 * 2, dma_io_memory); + + register_savevm("sparc32_dma", daddr, 1, dma_save, dma_load, s); + qemu_register_reset(dma_reset, s); + + return s; +} + +void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque, + void *lance_opaque) +{ + DMAState *s = opaque; + + s->esp_opaque = esp_opaque; + s->lance_opaque = lance_opaque; +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 09a157c0a..94629364d 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -37,10 +37,9 @@ #define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ #define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */ #define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */ -#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */ +#define PHYS_JJ_DMA 0x78400000 /* DMA controller */ #define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ #define PHYS_JJ_ESP_IRQ 18 -#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */ #define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */ #define PHYS_JJ_LE_IRQ 16 #define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */ @@ -192,25 +191,6 @@ void pic_set_irq_cpu(int irq, int level, unsigned int cpu) slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); } -static void *iommu; - -uint32_t iommu_translate(uint32_t addr) -{ - return iommu_translate_local(iommu, addr); -} - -void sparc_iommu_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len) -{ - return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 0); -} - -void sparc_iommu_memory_write(target_phys_addr_t addr, - uint8_t *buf, int len) -{ - return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 1); -} - static void *slavio_misc; void qemu_system_powerdown(void) @@ -235,6 +215,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, int ret, linux_boot; unsigned int i; long vram_size = 0x100000, prom_offset, initrd_size, kernel_size; + void *iommu, *dma, *main_esp, *main_lance = NULL; linux_boot = (kernel_filename != NULL); @@ -255,12 +236,13 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < smp_cpus; i++) { slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } + dma = sparc32_dma_init(PHYS_JJ_DMA, PHYS_JJ_ESP_IRQ, PHYS_JJ_LE_IRQ, iommu, slavio_intctl); tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); + main_lance = lance_init(&nd_table[0], PHYS_JJ_LE, dma); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); @@ -276,8 +258,9 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); - esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA); + main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma); slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); + sparc32_dma_set_reset_data(dma, main_esp, main_lance); prom_offset = ram_size + vram_size; cpu_register_physical_memory(PROM_ADDR, diff --git a/vl.h b/vl.h index 14116fa75..9612c6c6c 100644 --- a/vl.h +++ b/vl.h @@ -924,6 +924,9 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd); /* pcnet.c */ void pci_pcnet_init(PCIBus *bus, NICInfo *nd); +void pcnet_h_reset(void *opaque); +void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque); + /* pckbd.c */ @@ -1027,22 +1030,24 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ extern QEMUMachine sun4m_machine; void pic_set_irq_cpu(int irq, int level, unsigned int cpu); -/* ??? Remove iommu_translate once lance emulation has been converted. */ -uint32_t iommu_translate(uint32_t addr); -void sparc_iommu_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len); -void sparc_iommu_memory_write(target_phys_addr_t addr, - uint8_t *buf, int len); /* iommu.c */ void *iommu_init(uint32_t addr); -/* ??? Remove iommu_translate_local. */ -uint32_t iommu_translate_local(void *opaque, uint32_t addr); -void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, +void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write); +static inline void sparc_iommu_memory_read(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, int len) +{ + sparc_iommu_memory_rw(opaque, addr, buf, len, 0); +} -/* lance.c */ -void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr); +static inline void sparc_iommu_memory_write(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, int len) +{ + sparc_iommu_memory_rw(opaque, addr, buf, len, 1); +} /* tcx.c */ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, @@ -1074,7 +1079,23 @@ void *slavio_misc_init(uint32_t base, int irq); void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ -void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr); +void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque); +void esp_reset(void *opaque); + +/* sparc32_dma.c */ +void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, + void *intctl); +void ledma_set_irq(void *opaque, int isr); +void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, + int len); +void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, + int len); +void espdma_raise_irq(void *opaque); +void espdma_clear_irq(void *opaque); +void espdma_memory_read(void *opaque, uint8_t *buf, int len); +void espdma_memory_write(void *opaque, uint8_t *buf, int len); +void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque, + void *lance_opaque); /* sun4u.c */ extern QEMUMachine sun4u_machine; -- cgit v1.2.3 From 03c1847584dad4c766bea465c4febcf5892f31d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Sep 2006 16:40:12 +0000 Subject: endianness fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2144 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 253 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 157 insertions(+), 96 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index 6b78408d6..04cf9d590 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -253,147 +253,208 @@ struct pcnet_RMD { (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \ (R)->rmd2.zeros) -static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) +static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd1, + target_phys_addr_t addr) { + uint32_t *tmd = (uint32_t *)tmd1; + if (!BCR_SWSTYLE(s)) { uint16_t xda[4]; s->phys_mem_read(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda)); if (CSR_BIGENDIAN(s)) { - ((uint32_t *)tmd)[0] = be16_to_cpu(xda[0]) | - ((be16_to_cpu(xda[1]) & 0x00ff) << 16); - ((uint32_t *)tmd)[1] = be16_to_cpu(xda[2]) | - ((be16_to_cpu(xda[1]) & 0xff00) << 16); - ((uint32_t *)tmd)[2] = - (be16_to_cpu(xda[3]) & 0xffff) << 16; - ((uint32_t *)tmd)[3] = 0; + be16_to_cpus(&xda[0]); + be16_to_cpus(&xda[1]); + be16_to_cpus(&xda[2]); + be16_to_cpus(&xda[3]); } else { - ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | - ((xda[1]&0x00ff) << 16); - ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| - ((xda[1] & 0xff00) << 16); - ((uint32_t *)tmd)[2] = - (xda[3] & 0xffff) << 16; - ((uint32_t *)tmd)[3] = 0; + le16_to_cpus(&xda[0]); + le16_to_cpus(&xda[1]); + le16_to_cpus(&xda[2]); + le16_to_cpus(&xda[3]); } - } - else - if (BCR_SWSTYLE(s) != 3) - s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, 16); - else { + + tmd[0] = (xda[0]&0xffff) | + ((xda[1]&0x00ff) << 16); + tmd[1] = (xda[2]&0xffff)| + ((xda[1] & 0xff00) << 16); + tmd[2] = + (xda[3] & 0xffff) << 16; + tmd[3] = 0; + } else { uint32_t xda[4]; s->phys_mem_read(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda)); - ((uint32_t *)tmd)[0] = xda[2]; - ((uint32_t *)tmd)[1] = xda[1]; - ((uint32_t *)tmd)[2] = xda[0]; - ((uint32_t *)tmd)[3] = xda[3]; + if (CSR_BIGENDIAN(s)) { + be32_to_cpus(&xda[0]); + be32_to_cpus(&xda[1]); + be32_to_cpus(&xda[2]); + be32_to_cpus(&xda[3]); + } else { + le32_to_cpus(&xda[0]); + le32_to_cpus(&xda[1]); + le32_to_cpus(&xda[2]); + le32_to_cpus(&xda[3]); + } + if (BCR_SWSTYLE(s) != 3) { + memcpy(tmd, xda, sizeof(xda)); + } else { + tmd[0] = xda[2]; + tmd[1] = xda[1]; + tmd[2] = xda[0]; + tmd[3] = xda[3]; + } } } -static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) +static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd1, + target_phys_addr_t addr) { + const uint32_t *tmd = (const uint32_t *)tmd1; if (!BCR_SWSTYLE(s)) { uint16_t xda[4]; + xda[0] = tmd[0] & 0xffff; + xda[1] = ((tmd[0]>>16)&0x00ff) | + ((tmd[1]>>16)&0xff00); + xda[2] = tmd[1] & 0xffff; + xda[3] = tmd[2] >> 16; if (CSR_BIGENDIAN(s)) { - xda[0] = cpu_to_be16(((uint32_t *)tmd)[0] & 0xffff); - xda[1] = cpu_to_be16(((((uint32_t *)tmd)[0] >> 16) & 0x00ff) | - ((((uint32_t *)tmd)[1] >> 16) & 0xff00)); - xda[2] = cpu_to_be16(((uint32_t *)tmd)[1] & 0xffff); - xda[3] = cpu_to_be16(((uint32_t *)tmd)[2] >> 16); + cpu_to_be16s(&xda[0]); + cpu_to_be16s(&xda[1]); + cpu_to_be16s(&xda[2]); + cpu_to_be16s(&xda[3]); } else { - xda[0] = ((uint32_t *)tmd)[0] & 0xffff; - xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | - ((((uint32_t *)tmd)[1]>>16)&0xff00); - xda[2] = ((uint32_t *)tmd)[1] & 0xffff; - xda[3] = ((uint32_t *)tmd)[2] >> 16; + cpu_to_le16s(&xda[0]); + cpu_to_le16s(&xda[1]); + cpu_to_le16s(&xda[2]); + cpu_to_le16s(&xda[3]); } s->phys_mem_write(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda)); - } - else { - if (BCR_SWSTYLE(s) != 3) - s->phys_mem_write(s->dma_opaque, addr, (void *)tmd, 16); - else { - uint32_t xda[4]; - xda[0] = ((uint32_t *)tmd)[2]; - xda[1] = ((uint32_t *)tmd)[1]; - xda[2] = ((uint32_t *)tmd)[0]; - xda[3] = ((uint32_t *)tmd)[3]; - s->phys_mem_write(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda)); + } else { + uint32_t xda[4]; + if (BCR_SWSTYLE(s) != 3) { + memcpy(xda, tmd, sizeof(xda)); + } else { + xda[0] = tmd[2]; + xda[1] = tmd[1]; + xda[2] = tmd[0]; + xda[3] = tmd[3]; } + if (CSR_BIGENDIAN(s)) { + cpu_to_be32s(&xda[0]); + cpu_to_be32s(&xda[1]); + cpu_to_be32s(&xda[2]); + cpu_to_be32s(&xda[3]); + } else { + cpu_to_le32s(&xda[0]); + cpu_to_le32s(&xda[1]); + cpu_to_le32s(&xda[2]); + cpu_to_le32s(&xda[3]); + } + s->phys_mem_write(s->dma_opaque, addr, + (void *)&xda[0], sizeof(xda)); } } -static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) +static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd1, + target_phys_addr_t addr) { + uint32_t *rmd = (uint32_t *)rmd1; + if (!BCR_SWSTYLE(s)) { uint16_t rda[4]; - s->phys_mem_read(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda)); + s->phys_mem_read(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda)); if (CSR_BIGENDIAN(s)) { - ((uint32_t *)rmd)[0] = (be16_to_cpu(rda[0]) & 0xffff) | - ((be16_to_cpu(rda[1]) & 0x00ff) << 16); - ((uint32_t *)rmd)[1] = (be16_to_cpu(rda[2]) & 0xffff) | - ((be16_to_cpu(rda[1]) & 0xff00) << 16); - ((uint32_t *)rmd)[2] = be16_to_cpu(rda[3]) & 0xffff; - ((uint32_t *)rmd)[3] = 0; + be16_to_cpus(&rda[0]); + be16_to_cpus(&rda[1]); + be16_to_cpus(&rda[2]); + be16_to_cpus(&rda[3]); } else { - ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| - ((rda[1] & 0x00ff) << 16); - ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| - ((rda[1] & 0xff00) << 16); - ((uint32_t *)rmd)[2] = rda[3] & 0xffff; - ((uint32_t *)rmd)[3] = 0; + le16_to_cpus(&rda[0]); + le16_to_cpus(&rda[1]); + le16_to_cpus(&rda[2]); + le16_to_cpus(&rda[3]); } - } - else - if (BCR_SWSTYLE(s) != 3) - s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, 16); - else { + rmd[0] = (rda[0]&0xffff)| + ((rda[1] & 0x00ff) << 16); + rmd[1] = (rda[2]&0xffff)| + ((rda[1] & 0xff00) << 16); + rmd[2] = rda[3] & 0xffff; + rmd[3] = 0; + } else { uint32_t rda[4]; - s->phys_mem_read(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda)); - ((uint32_t *)rmd)[0] = rda[2]; - ((uint32_t *)rmd)[1] = rda[1]; - ((uint32_t *)rmd)[2] = rda[0]; - ((uint32_t *)rmd)[3] = rda[3]; + s->phys_mem_read(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda)); + if (CSR_BIGENDIAN(s)) { + be32_to_cpus(&rda[0]); + be32_to_cpus(&rda[1]); + be32_to_cpus(&rda[2]); + be32_to_cpus(&rda[3]); + } else { + le32_to_cpus(&rda[0]); + le32_to_cpus(&rda[1]); + le32_to_cpus(&rda[2]); + le32_to_cpus(&rda[3]); + } + if (BCR_SWSTYLE(s) != 3) { + memcpy(rmd, rda, sizeof(rda)); + } else { + rmd[0] = rda[2]; + rmd[1] = rda[1]; + rmd[2] = rda[0]; + rmd[3] = rda[3]; + } } } -static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) +static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, + target_phys_addr_t addr) { + const uint32_t *rmd = (const uint32_t *)rmd1; + if (!BCR_SWSTYLE(s)) { uint16_t rda[4]; + rda[0] = rmd[0] & 0xffff; + rda[1] = ((rmd[0]>>16)&0xff)| + ((rmd[1]>>16)&0xff00); + rda[2] = rmd[1] & 0xffff; + rda[3] = rmd[2] & 0xffff; if (CSR_BIGENDIAN(s)) { - rda[0] = cpu_to_be16(((uint32_t *)rmd)[0] & 0xffff); - rda[1] = cpu_to_be16(((((uint32_t *)rmd)[0] >> 16) & 0xff) | - ((((uint32_t *)rmd)[1] >> 16) & 0xff00)); - rda[2] = cpu_to_be16(((uint32_t *)rmd)[1] & 0xffff); - rda[3] = cpu_to_be16(((uint32_t *)rmd)[2] & 0xffff); + cpu_to_be16s(&rda[0]); + cpu_to_be16s(&rda[1]); + cpu_to_be16s(&rda[2]); + cpu_to_be16s(&rda[3]); } else { - rda[0] = ((uint32_t *)rmd)[0] & 0xffff; - rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)| - ((((uint32_t *)rmd)[1]>>16)&0xff00); - rda[2] = ((uint32_t *)rmd)[1] & 0xffff; - rda[3] = ((uint32_t *)rmd)[2] & 0xffff; + cpu_to_le16s(&rda[0]); + cpu_to_le16s(&rda[1]); + cpu_to_le16s(&rda[2]); + cpu_to_le16s(&rda[3]); } s->phys_mem_write(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda)); - } - else { - if (BCR_SWSTYLE(s) != 3) - s->phys_mem_write(s->dma_opaque, addr, (void *)rmd, 16); - else { - uint32_t rda[4]; - rda[0] = ((uint32_t *)rmd)[2]; - rda[1] = ((uint32_t *)rmd)[1]; - rda[2] = ((uint32_t *)rmd)[0]; - rda[3] = ((uint32_t *)rmd)[3]; - s->phys_mem_write(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda)); + } else { + uint32_t rda[4]; + if (BCR_SWSTYLE(s) != 3) { + memcpy(rda, rmd, sizeof(rda)); + } else { + rda[0] = rmd[2]; + rda[1] = rmd[1]; + rda[2] = rmd[0]; + rda[3] = rmd[3]; } + if (CSR_BIGENDIAN(s)) { + cpu_to_be32s(&rda[0]); + cpu_to_be32s(&rda[1]); + cpu_to_be32s(&rda[2]); + cpu_to_be32s(&rda[3]); + } else { + cpu_to_le32s(&rda[0]); + cpu_to_le32s(&rda[1]); + cpu_to_le32s(&rda[2]); + cpu_to_le32s(&rda[3]); + } + s->phys_mem_write(s->dma_opaque, addr, + (void *)&rda[0], sizeof(rda)); } } -- cgit v1.2.3 From e17a36ce41bc76abecebb434850ba619f5182ba8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Sep 2006 17:09:02 +0000 Subject: multi byte nop support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2145 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index f905f323d..5c6453d4f 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1615,6 +1615,56 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ *offset_ptr = disp; } +static void gen_nop_modrm(DisasContext *s, int modrm) +{ + int mod, rm, base, code; + + mod = (modrm >> 6) & 3; + if (mod == 3) + return; + rm = modrm & 7; + + if (s->aflag) { + + base = rm; + + if (base == 4) { + code = ldub_code(s->pc++); + base = (code & 7); + } + + switch (mod) { + case 0: + if (base == 5) { + s->pc += 4; + } + break; + case 1: + s->pc++; + break; + default: + case 2: + s->pc += 4; + break; + } + } else { + switch (mod) { + case 0: + if (rm == 6) { + s->pc += 2; + } + break; + case 1: + s->pc++; + break; + default: + case 2: + s->pc += 2; + break; + } + } +} + /* used for LEA and MOV AX, mem */ static void gen_add_A0_ds_seg(DisasContext *s) { @@ -5791,10 +5841,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_lea_modrm(s, modrm, ®_addr, &offset_addr); /* nothing more to do */ break; - default: - goto illegal_op; + default: /* nop (multi byte) */ + gen_nop_modrm(s, modrm); + break; } break; + case 0x119 ... 0x11f: /* nop (multi byte) */ + modrm = ldub_code(s->pc++); + gen_nop_modrm(s, modrm); + break; case 0x120: /* mov reg, crN */ case 0x122: /* mov crN, reg */ if (s->cpl != 0) { -- cgit v1.2.3 From c6d46c200f72be7b9fba3e0f29fa8d6128aea4c9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Sep 2006 17:10:41 +0000 Subject: typo git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2146 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 144381ff9..cc73dcddc 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1220,7 +1220,7 @@ or the @code{usb_add} monitor command. Available devices are: @item @code{mouse} Virtual Mouse. This will override the PS/2 mouse emulation when activated. @item @code{tablet} -Pointer device that uses abolsute coordinates (like a touchscreen). +Pointer device that uses absolute coordinates (like a touchscreen). This means qemu is able to report the mouse position without having to grab the mouse. Also overrides the PS/2 mouse emulation when activated. @item @code{disk:file} -- cgit v1.2.3 From 9b94dc325b1ab7de421a0419f324d8f8db55aeb4 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 3 Sep 2006 19:48:17 +0000 Subject: better PCNET endianness support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2147 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 223 ++++++++++++++++++------------------------------------- hw/sparc32_dma.c | 42 ++++++++++- vl.h | 8 +- 3 files changed, 116 insertions(+), 157 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index 04cf9d590..f242cd1e9 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -71,9 +71,9 @@ struct PCNetState_st { int tx_busy; void (*set_irq_cb)(void *s, int isr); void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len); + uint8_t *buf, int len, int do_bswap); void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len); + uint8_t *buf, int len, int do_bswap); void *dma_opaque; }; @@ -116,7 +116,7 @@ struct qemu_ether_header { #define CSR_TXON(S) !!(((S)->csr[0])&0x0010) #define CSR_RXON(S) !!(((S)->csr[0])&0x0020) #define CSR_INEA(S) !!(((S)->csr[0])&0x0040) -#define CSR_BIGENDIAN(S) !!(((S)->csr[3])&0x0004) +#define CSR_BSWP(S) !!(((S)->csr[3])&0x0004) #define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020) #define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040) #define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800) @@ -261,19 +261,11 @@ static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd1, if (!BCR_SWSTYLE(s)) { uint16_t xda[4]; s->phys_mem_read(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda)); - if (CSR_BIGENDIAN(s)) { - be16_to_cpus(&xda[0]); - be16_to_cpus(&xda[1]); - be16_to_cpus(&xda[2]); - be16_to_cpus(&xda[3]); - } else { - le16_to_cpus(&xda[0]); - le16_to_cpus(&xda[1]); - le16_to_cpus(&xda[2]); - le16_to_cpus(&xda[3]); - } - + (void *)&xda[0], sizeof(xda), 0); + le16_to_cpus(&xda[0]); + le16_to_cpus(&xda[1]); + le16_to_cpus(&xda[2]); + le16_to_cpus(&xda[3]); tmd[0] = (xda[0]&0xffff) | ((xda[1]&0x00ff) << 16); tmd[1] = (xda[2]&0xffff)| @@ -284,18 +276,11 @@ static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd1, } else { uint32_t xda[4]; s->phys_mem_read(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda)); - if (CSR_BIGENDIAN(s)) { - be32_to_cpus(&xda[0]); - be32_to_cpus(&xda[1]); - be32_to_cpus(&xda[2]); - be32_to_cpus(&xda[3]); - } else { - le32_to_cpus(&xda[0]); - le32_to_cpus(&xda[1]); - le32_to_cpus(&xda[2]); - le32_to_cpus(&xda[3]); - } + (void *)&xda[0], sizeof(xda), 0); + le32_to_cpus(&xda[0]); + le32_to_cpus(&xda[1]); + le32_to_cpus(&xda[2]); + le32_to_cpus(&xda[3]); if (BCR_SWSTYLE(s) != 3) { memcpy(tmd, xda, sizeof(xda)); } else { @@ -318,19 +303,12 @@ static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd1, ((tmd[1]>>16)&0xff00); xda[2] = tmd[1] & 0xffff; xda[3] = tmd[2] >> 16; - if (CSR_BIGENDIAN(s)) { - cpu_to_be16s(&xda[0]); - cpu_to_be16s(&xda[1]); - cpu_to_be16s(&xda[2]); - cpu_to_be16s(&xda[3]); - } else { - cpu_to_le16s(&xda[0]); - cpu_to_le16s(&xda[1]); - cpu_to_le16s(&xda[2]); - cpu_to_le16s(&xda[3]); - } + cpu_to_le16s(&xda[0]); + cpu_to_le16s(&xda[1]); + cpu_to_le16s(&xda[2]); + cpu_to_le16s(&xda[3]); s->phys_mem_write(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda)); + (void *)&xda[0], sizeof(xda), 0); } else { uint32_t xda[4]; if (BCR_SWSTYLE(s) != 3) { @@ -341,19 +319,12 @@ static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd1, xda[2] = tmd[0]; xda[3] = tmd[3]; } - if (CSR_BIGENDIAN(s)) { - cpu_to_be32s(&xda[0]); - cpu_to_be32s(&xda[1]); - cpu_to_be32s(&xda[2]); - cpu_to_be32s(&xda[3]); - } else { - cpu_to_le32s(&xda[0]); - cpu_to_le32s(&xda[1]); - cpu_to_le32s(&xda[2]); - cpu_to_le32s(&xda[3]); - } + cpu_to_le32s(&xda[0]); + cpu_to_le32s(&xda[1]); + cpu_to_le32s(&xda[2]); + cpu_to_le32s(&xda[3]); s->phys_mem_write(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda)); + (void *)&xda[0], sizeof(xda), 0); } } @@ -364,18 +335,12 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd1, if (!BCR_SWSTYLE(s)) { uint16_t rda[4]; - s->phys_mem_read(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda)); - if (CSR_BIGENDIAN(s)) { - be16_to_cpus(&rda[0]); - be16_to_cpus(&rda[1]); - be16_to_cpus(&rda[2]); - be16_to_cpus(&rda[3]); - } else { - le16_to_cpus(&rda[0]); - le16_to_cpus(&rda[1]); - le16_to_cpus(&rda[2]); - le16_to_cpus(&rda[3]); - } + s->phys_mem_read(s->dma_opaque, addr, + (void *)&rda[0], sizeof(rda), 0); + le16_to_cpus(&rda[0]); + le16_to_cpus(&rda[1]); + le16_to_cpus(&rda[2]); + le16_to_cpus(&rda[3]); rmd[0] = (rda[0]&0xffff)| ((rda[1] & 0x00ff) << 16); rmd[1] = (rda[2]&0xffff)| @@ -384,18 +349,12 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd1, rmd[3] = 0; } else { uint32_t rda[4]; - s->phys_mem_read(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda)); - if (CSR_BIGENDIAN(s)) { - be32_to_cpus(&rda[0]); - be32_to_cpus(&rda[1]); - be32_to_cpus(&rda[2]); - be32_to_cpus(&rda[3]); - } else { - le32_to_cpus(&rda[0]); - le32_to_cpus(&rda[1]); - le32_to_cpus(&rda[2]); - le32_to_cpus(&rda[3]); - } + s->phys_mem_read(s->dma_opaque, addr, + (void *)&rda[0], sizeof(rda), 0); + le32_to_cpus(&rda[0]); + le32_to_cpus(&rda[1]); + le32_to_cpus(&rda[2]); + le32_to_cpus(&rda[3]); if (BCR_SWSTYLE(s) != 3) { memcpy(rmd, rda, sizeof(rda)); } else { @@ -419,19 +378,12 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, ((rmd[1]>>16)&0xff00); rda[2] = rmd[1] & 0xffff; rda[3] = rmd[2] & 0xffff; - if (CSR_BIGENDIAN(s)) { - cpu_to_be16s(&rda[0]); - cpu_to_be16s(&rda[1]); - cpu_to_be16s(&rda[2]); - cpu_to_be16s(&rda[3]); - } else { - cpu_to_le16s(&rda[0]); - cpu_to_le16s(&rda[1]); - cpu_to_le16s(&rda[2]); - cpu_to_le16s(&rda[3]); - } + cpu_to_le16s(&rda[0]); + cpu_to_le16s(&rda[1]); + cpu_to_le16s(&rda[2]); + cpu_to_le16s(&rda[3]); s->phys_mem_write(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda)); + (void *)&rda[0], sizeof(rda), 0); } else { uint32_t rda[4]; if (BCR_SWSTYLE(s) != 3) { @@ -442,19 +394,12 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, rda[2] = rmd[0]; rda[3] = rmd[3]; } - if (CSR_BIGENDIAN(s)) { - cpu_to_be32s(&rda[0]); - cpu_to_be32s(&rda[1]); - cpu_to_be32s(&rda[2]); - cpu_to_be32s(&rda[3]); - } else { - cpu_to_le32s(&rda[0]); - cpu_to_le32s(&rda[1]); - cpu_to_le32s(&rda[2]); - cpu_to_le32s(&rda[3]); - } + cpu_to_le32s(&rda[0]); + cpu_to_le32s(&rda[1]); + cpu_to_le32s(&rda[2]); + cpu_to_le32s(&rda[3]); s->phys_mem_write(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda)); + (void *)&rda[0], sizeof(rda), 0); } } @@ -490,7 +435,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, do { \ uint16_t rda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ - (void *)&rda[0], sizeof(rda)); \ + (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[2] & 0xf000)!=0xf000; \ (RES) |= (rda[3] & 0xf000)!=0x0000; \ } while (0); \ @@ -500,7 +445,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, do { \ uint32_t rda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ - (void *)&rda[0], sizeof(rda)); \ + (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ } while (0); \ @@ -509,7 +454,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, do { \ uint32_t rda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ - (void *)&rda[0], sizeof(rda)); \ + (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ } while (0); \ @@ -523,7 +468,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, do { \ uint16_t xda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ - (void *)&xda[0], sizeof(xda)); \ + (void *)&xda[0], sizeof(xda), 0); \ (RES) |= (xda[2] & 0xf000)!=0xf000;\ } while (0); \ break; \ @@ -533,7 +478,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, do { \ uint32_t xda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ - (void *)&xda[0], sizeof(xda)); \ + (void *)&xda[0], sizeof(xda), 0); \ (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ } while (0); \ break; \ @@ -546,13 +491,12 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, struct qemu_ether_header *hdr = (void *)(BUF); \ printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ - "type=0x%04x (bcast=%d)\n", \ + "type=0x%04x\n", \ hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \ hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ - be16_to_cpu(hdr->ether_type), \ - !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \ + be16_to_cpu(hdr->ether_type)); \ } while (0) #define MULTICAST_FILTER_LEN 8 @@ -669,7 +613,7 @@ static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) { - static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; struct qemu_ether_header *hdr = (void *)buf; int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6); #ifdef PCNET_DEBUG_MATCH @@ -836,35 +780,25 @@ static void pcnet_init(PCNetState *s) if (BCR_SSIZE32(s)) { struct pcnet_initblk32 initblk; s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), - (uint8_t *)&initblk, sizeof(initblk)); + (uint8_t *)&initblk, sizeof(initblk), 0); mode = initblk.mode; rlen = initblk.rlen >> 4; tlen = initblk.tlen >> 4; ladrf = initblk.ladrf; padr = initblk.padr; - if (CSR_BIGENDIAN(s)) { - rdra = be32_to_cpu(initblk.rdra); - tdra = be32_to_cpu(initblk.tdra); - } else { - rdra = le32_to_cpu(initblk.rdra); - tdra = le32_to_cpu(initblk.tdra); - } + rdra = le32_to_cpu(initblk.rdra); + tdra = le32_to_cpu(initblk.tdra); s->rdra = PHYSADDR(s,initblk.rdra); s->tdra = PHYSADDR(s,initblk.tdra); } else { struct pcnet_initblk16 initblk; s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), - (uint8_t *)&initblk, sizeof(initblk)); + (uint8_t *)&initblk, sizeof(initblk), 0); mode = initblk.mode; ladrf = initblk.ladrf; padr = initblk.padr; - if (CSR_BIGENDIAN(s)) { - rdra = be32_to_cpu(initblk.rdra); - tdra = be32_to_cpu(initblk.tdra); - } else { - rdra = le32_to_cpu(initblk.rdra); - tdra = le32_to_cpu(initblk.tdra); - } + rdra = le32_to_cpu(initblk.rdra); + tdra = le32_to_cpu(initblk.tdra); rlen = rdra >> 29; tlen = tdra >> 29; rdra &= 0x00ffffff; @@ -878,25 +812,14 @@ static void pcnet_init(PCNetState *s) CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512; CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512; s->csr[ 6] = (tlen << 12) | (rlen << 8); - if (CSR_BIGENDIAN(s)) { - s->csr[15] = be16_to_cpu(mode); - s->csr[ 8] = be16_to_cpu(ladrf[0]); - s->csr[ 9] = be16_to_cpu(ladrf[1]); - s->csr[10] = be16_to_cpu(ladrf[2]); - s->csr[11] = be16_to_cpu(ladrf[3]); - s->csr[12] = be16_to_cpu(padr[0]); - s->csr[13] = be16_to_cpu(padr[1]); - s->csr[14] = be16_to_cpu(padr[2]); - } else { - s->csr[15] = le16_to_cpu(mode); - s->csr[ 8] = le16_to_cpu(ladrf[0]); - s->csr[ 9] = le16_to_cpu(ladrf[1]); - s->csr[10] = le16_to_cpu(ladrf[2]); - s->csr[11] = le16_to_cpu(ladrf[3]); - s->csr[12] = le16_to_cpu(padr[0]); - s->csr[13] = le16_to_cpu(padr[1]); - s->csr[14] = le16_to_cpu(padr[2]); - } + s->csr[15] = le16_to_cpu(mode); + s->csr[ 8] = le16_to_cpu(ladrf[0]); + s->csr[ 9] = le16_to_cpu(ladrf[1]); + s->csr[10] = le16_to_cpu(ladrf[2]); + s->csr[11] = le16_to_cpu(ladrf[3]); + s->csr[12] = le16_to_cpu(padr[0]); + s->csr[13] = le16_to_cpu(padr[1]); + s->csr[14] = le16_to_cpu(padr[2]); s->rdra = PHYSADDR(s, rdra); s->tdra = PHYSADDR(s, tdra); @@ -1168,7 +1091,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) #define PCNET_RECV_STORE() do { \ int count = MIN(4096 - rmd.rmd1.bcnt,size); \ target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ - s->phys_mem_write(s->dma_opaque, rbadr, src, count); \ + s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ src += count; size -= count; \ rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ RMDSTORE(&rmd, PHYSADDR(s,crda)); \ @@ -1259,14 +1182,16 @@ static void pcnet_transmit(PCNetState *s) s->xmit_pos = 0; if (!tmd.tmd1.enp) { s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), - s->buffer, 4096 - tmd.tmd1.bcnt); + s->buffer, 4096 - tmd.tmd1.bcnt, + CSR_BSWP(s)); s->xmit_pos += 4096 - tmd.tmd1.bcnt; } xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); } if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), - s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); + s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt, + CSR_BSWP(s)); s->xmit_pos += 4096 - tmd.tmd1.bcnt; #ifdef PCNET_DEBUG printf("pcnet_transmit size=%d\n", s->xmit_pos); @@ -1953,13 +1878,13 @@ static void pcnet_pci_set_irq_cb(void *opaque, int isr) } static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len) + uint8_t *buf, int len, int do_bswap) { cpu_physical_memory_write(addr, buf, len); } static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len) + uint8_t *buf, int len, int do_bswap) { cpu_physical_memory_read(addr, buf, len); } diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index d8d7e6a83..b17a12b9e 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -69,22 +69,56 @@ void ledma_set_irq(void *opaque, int isr) pic_set_irq_new(s->intctl, s->leirq, isr); } -void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len) +/* Note: on sparc, the lance 16 bit bus is swapped */ +void ledma_memory_read(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap) { DMAState *s = opaque; + int i; DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n", s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); - sparc_iommu_memory_read(s->iommu, addr | s->dmaregs[7], buf, len); + addr |= s->dmaregs[7]; + if (do_bswap) { + sparc_iommu_memory_read(s->iommu, addr, buf, len); + } else { + addr &= ~1; + len &= ~1; + sparc_iommu_memory_read(s->iommu, addr, buf, len); + for(i = 0; i < len; i += 2) { + bswap16s((uint16_t *)(buf + i)); + } + } } -void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len) +void ledma_memory_write(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap) { DMAState *s = opaque; + int l, i; + uint16_t tmp_buf[32]; DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n", s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); - sparc_iommu_memory_write(s->iommu, addr | s->dmaregs[7], buf, len); + addr |= s->dmaregs[7]; + if (do_bswap) { + sparc_iommu_memory_write(s->iommu, addr, buf, len); + } else { + addr &= ~1; + len &= ~1; + while (len > 0) { + l = len; + if (l > sizeof(tmp_buf)) + l = sizeof(tmp_buf); + for(i = 0; i < l; i += 2) { + tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i)); + } + sparc_iommu_memory_write(s->iommu, addr, (uint8_t *)tmp_buf, l); + len -= l; + buf += l; + addr += l; + } + } } void espdma_raise_irq(void *opaque) diff --git a/vl.h b/vl.h index 9612c6c6c..f831e0ff9 100644 --- a/vl.h +++ b/vl.h @@ -1086,10 +1086,10 @@ void esp_reset(void *opaque); void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, void *intctl); void ledma_set_irq(void *opaque, int isr); -void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, - int len); -void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, - int len); +void ledma_memory_read(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap); +void ledma_memory_write(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap); void espdma_raise_irq(void *opaque); void espdma_clear_irq(void *opaque); void espdma_memory_read(void *opaque, uint8_t *buf, int len); -- cgit v1.2.3 From 094eed6ca5ce69cb85ac9b778e27da6bf0355173 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Sep 2006 11:10:18 +0000 Subject: two stop bits support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2148 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index cdfd98c55..45e9417f2 100644 --- a/vl.c +++ b/vl.c @@ -1598,7 +1598,7 @@ static void tty_serial_init(int fd, int speed, |INLCR|IGNCR|ICRNL|IXON); tty.c_oflag |= OPOST; tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); - tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS); + tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB); switch(data_bits) { default: case 8: @@ -1625,6 +1625,8 @@ static void tty_serial_init(int fd, int speed, tty.c_cflag |= PARENB | PARODD; break; } + if (stop_bits == 2) + tty.c_cflag |= CSTOPB; tcsetattr (fd, TCSANOW, &tty); } -- cgit v1.2.3 From 21206a104f86a27c69ed95cead1f69f6da33e77e Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Sep 2006 11:31:34 +0000 Subject: more correct display functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2149 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/tcx.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/hw/tcx.c b/hw/tcx.c index ed32c9424..1df7d24f9 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -34,11 +34,55 @@ typedef struct TCXState { ram_addr_t vram_offset; uint16_t width, height; uint8_t r[256], g[256], b[256]; + uint32_t palette[256]; uint8_t dac_index, dac_state; } TCXState; static void tcx_screen_dump(void *opaque, const char *filename); +/* XXX: unify with vga draw line functions */ +static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); +} + +static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); +} + +static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); +} + +static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) +{ + return (r << 16) | (g << 8) | b; +} + +static void update_palette_entries(TCXState *s, int start, int end) +{ + int i; + for(i = start; i < end; i++) { + switch(s->ds->depth) { + default: + case 8: + s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]); + break; + case 15: + s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]); + break; + case 16: + s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); + break; + case 32: + s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); + break; + } + } +} + static void tcx_draw_line32(TCXState *s1, uint8_t *d, const uint8_t *s, int width) { @@ -47,14 +91,11 @@ static void tcx_draw_line32(TCXState *s1, uint8_t *d, for(x = 0; x < width; x++) { val = *s++; - *d++ = s1->b[val]; - *d++ = s1->g[val]; - *d++ = s1->r[val]; - d++; + *((uint32_t *)d)++ = s1->palette[val]; } } -static void tcx_draw_line24(TCXState *s1, uint8_t *d, +static void tcx_draw_line16(TCXState *s1, uint8_t *d, const uint8_t *s, int width) { int x; @@ -62,9 +103,7 @@ static void tcx_draw_line24(TCXState *s1, uint8_t *d, for(x = 0; x < width; x++) { val = *s++; - *d++ = s1->b[val]; - *d++ = s1->g[val]; - *d++ = s1->r[val]; + *((uint16_t *)d)++ = s1->palette[val]; } } @@ -76,8 +115,7 @@ static void tcx_draw_line8(TCXState *s1, uint8_t *d, for(x = 0; x < width; x++) { val = *s++; - /* XXX translate between palettes? */ - *d++ = val; + *d++ = s1->palette[val]; } } @@ -106,8 +144,9 @@ static void tcx_update_display(void *opaque) case 32: f = tcx_draw_line32; break; - case 24: - f = tcx_draw_line24; + case 15: + case 16: + f = tcx_draw_line16; break; default: case 8: @@ -201,6 +240,7 @@ static int tcx_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, s->b, 256); qemu_get_8s(f, &s->dac_index); qemu_get_8s(f, &s->dac_state); + update_palette_entries(s, 0, 256); return 0; } @@ -213,6 +253,7 @@ static void tcx_reset(void *opaque) memset(s->g, 0, 256); memset(s->b, 0, 256); s->r[255] = s->g[255] = s->b[255] = 255; + update_palette_entries(s, 0, 256); memset(s->vram, 0, MAXX*MAXY); cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY, VGA_DIRTY_FLAG); @@ -240,14 +281,17 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val) switch (s->dac_state) { case 0: s->r[s->dac_index] = val >> 24; + update_palette_entries(s, s->dac_index, s->dac_index + 1); s->dac_state++; break; case 1: s->g[s->dac_index] = val >> 24; + update_palette_entries(s, s->dac_index, s->dac_index + 1); s->dac_state++; break; case 2: s->b[s->dac_index] = val >> 24; + update_palette_entries(s, s->dac_index, s->dac_index + 1); default: s->dac_state = 0; break; -- cgit v1.2.3 From 715748fa08b35690b15c0557ad1e92cd73c8fbb3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Sep 2006 11:35:47 +0000 Subject: added mouse protocol (Igor Kovalenko) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2150 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 69 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index b13e7c46f..0439a8461 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -42,6 +42,13 @@ * */ +/* + * Modifications: + * 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented + * serial mouse queue. + * Implemented serial mouse protocol. + */ + #ifdef DEBUG_SERIAL #define SER_DPRINTF(fmt, args...) \ do { printf("SER: " fmt , ##args); } while (0) @@ -58,7 +65,7 @@ do { printf("KBD: " fmt , ##args); } while (0) #endif #ifdef DEBUG_MOUSE #define MS_DPRINTF(fmt, args...) \ -do { printf("SER: " fmt , ##args); } while (0) +do { printf("MSC: " fmt , ##args); } while (0) #else #define MS_DPRINTF(fmt, args...) #endif @@ -71,12 +78,12 @@ typedef enum { ser, kbd, mouse, } chn_type_t; -#define KBD_QUEUE_SIZE 256 +#define SERIO_QUEUE_SIZE 256 typedef struct { - uint8_t data[KBD_QUEUE_SIZE]; + uint8_t data[SERIO_QUEUE_SIZE]; int rptr, wptr, count; -} KBDQueue; +} SERIOQueue; typedef struct ChannelState { int irq; @@ -86,7 +93,7 @@ typedef struct ChannelState { chn_type_t type; struct ChannelState *otherchn; uint8_t rx, tx, wregs[16], rregs[16]; - KBDQueue queue; + SERIOQueue queue; CharDriverState *chr; } ChannelState; @@ -103,13 +110,13 @@ static void serial_receive_byte(ChannelState *s, int ch); static void put_queue(void *opaque, int b) { ChannelState *s = opaque; - KBDQueue *q = &s->queue; + SERIOQueue *q = &s->queue; - KBD_DPRINTF("put: 0x%02x\n", b); - if (q->count >= KBD_QUEUE_SIZE) + SER_DPRINTF("put: 0x%02x\n", b); + if (q->count >= SERIO_QUEUE_SIZE) return; q->data[q->wptr] = b; - if (++q->wptr == KBD_QUEUE_SIZE) + if (++q->wptr == SERIO_QUEUE_SIZE) q->wptr = 0; q->count++; serial_receive_byte(s, 0); @@ -118,14 +125,14 @@ static void put_queue(void *opaque, int b) static uint32_t get_queue(void *opaque) { ChannelState *s = opaque; - KBDQueue *q = &s->queue; + SERIOQueue *q = &s->queue; int val; if (q->count == 0) { return 0; } else { val = q->data[q->rptr]; - if (++q->rptr == KBD_QUEUE_SIZE) + if (++q->rptr == SERIO_QUEUE_SIZE) q->rptr = 0; q->count--; } @@ -326,7 +333,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) case 1: s->rregs[0] &= ~1; clr_rxint(s); - if (s->type == kbd) + if (s->type == kbd || s->type == mouse) ret = get_queue(s); else ret = s->rx; @@ -512,9 +519,41 @@ static void sunmouse_event(void *opaque, ChannelState *s = opaque; int ch; - // XXX - ch = 0x42; - serial_receive_byte(s, ch); + MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state); + + ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */ + + if (buttons_state & MOUSE_EVENT_LBUTTON) + ch ^= 0x4; + if (buttons_state & MOUSE_EVENT_MBUTTON) + ch ^= 0x2; + if (buttons_state & MOUSE_EVENT_RBUTTON) + ch ^= 0x1; + + put_queue(s, ch); + + ch = dx; + + if (ch > 127) + ch=127; + else if (ch < -127) + ch=-127; + + put_queue(s, ch & 0xff); + + ch = -dy; + + if (ch > 127) + ch=127; + else if (ch < -127) + ch=-127; + + put_queue(s, ch & 0xff); + + // MSC protocol specify two extra motion bytes + + put_queue(s, 0); + put_queue(s, 0); } void slavio_serial_ms_kbd_init(int base, int irq) -- cgit v1.2.3 From e4a89056df2c6fc38f860db172460f4df37cd2ca Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Sep 2006 11:38:11 +0000 Subject: fix serial irq logic (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2151 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 91 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 0439a8461..7112bec84 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -88,7 +88,7 @@ typedef struct { typedef struct ChannelState { int irq; int reg; - int rxint, txint; + int rxint, txint, rxint_under_svc, txint_under_svc; chn_id_t chn; // this channel, A (base+4) or B (base+0) chn_type_t type; struct ChannelState *otherchn; @@ -106,6 +106,7 @@ struct SerialState { static void handle_kbd_command(ChannelState *s, int val); static int serial_can_receive(void *opaque); static void serial_receive_byte(ChannelState *s, int ch); +static inline void set_txint(ChannelState *s); static void put_queue(void *opaque, int b) { @@ -142,17 +143,26 @@ static uint32_t get_queue(void *opaque) return val; } -static void slavio_serial_update_irq(ChannelState *s) +static int slavio_serial_update_irq_chn(ChannelState *s) { if ((s->wregs[1] & 1) && // interrupts enabled (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && s->rxint == 1) || // rx ints enabled, pending ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p - pic_set_irq(s->irq, 1); - } else { - pic_set_irq(s->irq, 0); + return 1; } + return 0; +} + +static void slavio_serial_update_irq(ChannelState *s) +{ + int irq; + + irq = slavio_serial_update_irq_chn(s); + irq |= slavio_serial_update_irq_chn(s->otherchn); + + pic_set_irq(s->irq, irq); } static void slavio_serial_reset_chn(ChannelState *s) @@ -174,6 +184,7 @@ static void slavio_serial_reset_chn(ChannelState *s) s->rx = s->tx = 0; s->rxint = s->txint = 0; + s->rxint_under_svc = s->txint_under_svc = 0; } static void slavio_serial_reset(void *opaque) @@ -186,45 +197,63 @@ static void slavio_serial_reset(void *opaque) static inline void clr_rxint(ChannelState *s) { s->rxint = 0; + s->rxint_under_svc = 0; if (s->chn == 0) s->rregs[3] &= ~0x20; else { s->otherchn->rregs[3] &= ~4; } + if (s->txint) + set_txint(s); + else + s->rregs[2] = 6; slavio_serial_update_irq(s); } static inline void set_rxint(ChannelState *s) { s->rxint = 1; - if (s->chn == 0) - s->rregs[3] |= 0x20; - else { - s->otherchn->rregs[3] |= 4; + if (!s->txint_under_svc) { + s->rxint_under_svc = 1; + if (s->chn == 0) + s->rregs[3] |= 0x20; + else { + s->otherchn->rregs[3] |= 4; + } + s->rregs[2] = 4; + slavio_serial_update_irq(s); } - slavio_serial_update_irq(s); } static inline void clr_txint(ChannelState *s) { s->txint = 0; + s->txint_under_svc = 0; if (s->chn == 0) s->rregs[3] &= ~0x10; else { s->otherchn->rregs[3] &= ~2; } + if (s->rxint) + set_rxint(s); + else + s->rregs[2] = 6; slavio_serial_update_irq(s); } static inline void set_txint(ChannelState *s) { s->txint = 1; - if (s->chn == 0) - s->rregs[3] |= 0x10; - else { - s->otherchn->rregs[3] |= 2; + if (!s->rxint_under_svc) { + s->txint_under_svc = 1; + if (s->chn == 0) + s->rregs[3] |= 0x10; + else { + s->otherchn->rregs[3] |= 2; + } + s->rregs[2] = 0; + slavio_serial_update_irq(s); } - slavio_serial_update_irq(s); } static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -250,15 +279,14 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint case 8: newreg |= 0x8; break; - case 0x20: - clr_rxint(s); - break; case 0x28: clr_txint(s); break; case 0x38: - clr_rxint(s); - clr_txint(s); + if (s->rxint_under_svc) + clr_rxint(s); + else if (s->txint_under_svc) + clr_txint(s); break; default: break; @@ -301,11 +329,9 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint else if (s->type == kbd) { handle_kbd_command(s, val); } - s->txint = 1; s->rregs[0] |= 4; // Tx buffer empty s->rregs[1] |= 1; // All sent set_txint(s); - slavio_serial_update_irq(s); } break; default: @@ -348,11 +374,15 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) static int serial_can_receive(void *opaque) { ChannelState *s = opaque; + int ret; + if (((s->wregs[3] & 1) == 0) // Rx not enabled || ((s->rregs[0] & 1) == 1)) // char already available - return 0; + ret = 0; else - return 1; + ret = 1; + SER_DPRINTF("can receive %d\n", ret); + return ret; } static void serial_receive_byte(ChannelState *s, int ch) @@ -400,6 +430,8 @@ static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) qemu_put_be32s(f, &s->reg); qemu_put_be32s(f, &s->rxint); qemu_put_be32s(f, &s->txint); + qemu_put_be32s(f, &s->rxint_under_svc); + qemu_put_be32s(f, &s->txint_under_svc); qemu_put_8s(f, &s->rx); qemu_put_8s(f, &s->tx); qemu_put_buffer(f, s->wregs, 16); @@ -416,13 +448,17 @@ static void slavio_serial_save(QEMUFile *f, void *opaque) static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) { - if (version_id != 1) + if (version_id > 2) return -EINVAL; qemu_get_be32s(f, &s->irq); qemu_get_be32s(f, &s->reg); qemu_get_be32s(f, &s->rxint); qemu_get_be32s(f, &s->txint); + if (version_id >= 2) { + qemu_get_be32s(f, &s->rxint_under_svc); + qemu_get_be32s(f, &s->txint_under_svc); + } qemu_get_8s(f, &s->rx); qemu_get_8s(f, &s->tx); qemu_get_buffer(f, s->wregs, 16); @@ -469,7 +505,7 @@ SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDr } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; - register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s); + register_savevm("slavio_serial", base, 2, slavio_serial_save, slavio_serial_load, s); qemu_register_reset(slavio_serial_reset, s); slavio_serial_reset(s); return s; @@ -519,6 +555,9 @@ static void sunmouse_event(void *opaque, ChannelState *s = opaque; int ch; + /* XXX: SDL sometimes generates nul events: we delete them */ + if (dx == 0 && dy == 0 && dz == 0 && buttons_state == 0) + return; MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state); ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */ -- cgit v1.2.3 From 6bcb76c3b62195820daed29d621cda3fbe4256f3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Sep 2006 12:03:20 +0000 Subject: vvfat fixes (Roger Lathrop) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2152 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vvfat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block-vvfat.c b/block-vvfat.c index ad6b7d29e..48a52e311 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -61,7 +61,7 @@ void nonono(const char* file, int line, const char* msg) { exit(-5); } #undef assert -#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a) +#define assert(a) do {if (!(a)) nonono(__FILE__, __LINE__, #a);}while(0) #endif #else @@ -2174,7 +2174,7 @@ static int commit_one_file(BDRVVVFATState* s, 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, 0666); + 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); -- cgit v1.2.3 From 35db099ddb95c9761f665782b2f2cbe73f44e336 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 9 Sep 2006 12:17:15 +0000 Subject: allow host serial port usage (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2153 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 110 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 22 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 7112bec84..404138d4b 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -74,6 +74,8 @@ typedef enum { chn_a, chn_b, } chn_id_t; +#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a') + typedef enum { ser, kbd, mouse, } chn_type_t; @@ -113,7 +115,7 @@ static void put_queue(void *opaque, int b) ChannelState *s = opaque; SERIOQueue *q = &s->queue; - SER_DPRINTF("put: 0x%02x\n", b); + SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b); if (q->count >= SERIO_QUEUE_SIZE) return; q->data[q->wptr] = b; @@ -137,7 +139,7 @@ static uint32_t get_queue(void *opaque) q->rptr = 0; q->count--; } - KBD_DPRINTF("get 0x%02x\n", val); + KBD_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val); if (q->count > 0) serial_receive_byte(s, 0); return val; @@ -198,11 +200,10 @@ static inline void clr_rxint(ChannelState *s) { s->rxint = 0; s->rxint_under_svc = 0; - if (s->chn == 0) + if (s->chn == chn_a) s->rregs[3] &= ~0x20; - else { + else s->otherchn->rregs[3] &= ~4; - } if (s->txint) set_txint(s); else @@ -215,11 +216,10 @@ static inline void set_rxint(ChannelState *s) s->rxint = 1; if (!s->txint_under_svc) { s->rxint_under_svc = 1; - if (s->chn == 0) + if (s->chn == chn_a) s->rregs[3] |= 0x20; - else { + else s->otherchn->rregs[3] |= 4; - } s->rregs[2] = 4; slavio_serial_update_irq(s); } @@ -229,11 +229,10 @@ static inline void clr_txint(ChannelState *s) { s->txint = 0; s->txint_under_svc = 0; - if (s->chn == 0) + if (s->chn == chn_a) s->rregs[3] &= ~0x10; - else { + else s->otherchn->rregs[3] &= ~2; - } if (s->rxint) set_rxint(s); else @@ -246,16 +245,74 @@ static inline void set_txint(ChannelState *s) s->txint = 1; if (!s->rxint_under_svc) { s->txint_under_svc = 1; - if (s->chn == 0) + if (s->chn == chn_a) s->rregs[3] |= 0x10; - else { + else s->otherchn->rregs[3] |= 2; - } s->rregs[2] = 0; slavio_serial_update_irq(s); } } +static void slavio_serial_update_parameters(ChannelState *s) +{ + int speed, parity, data_bits, stop_bits; + QEMUSerialSetParams ssp; + + if (!s->chr || s->type != ser) + return; + + if (s->wregs[4] & 1) { + if (s->wregs[4] & 2) + parity = 'E'; + else + parity = 'O'; + } else { + parity = 'N'; + } + if ((s->wregs[4] & 0x0c) == 0x0c) + stop_bits = 2; + else + stop_bits = 1; + switch (s->wregs[5] & 0x60) { + case 0x00: + data_bits = 5; + break; + case 0x20: + data_bits = 7; + break; + case 0x40: + data_bits = 6; + break; + default: + case 0x60: + data_bits = 8; + break; + } + speed = 2457600 / ((s->wregs[12] | (s->wregs[13] << 8)) + 2); + switch (s->wregs[4] & 0xc0) { + case 0x00: + break; + case 0x40: + speed /= 16; + break; + case 0x80: + speed /= 32; + break; + default: + case 0xc0: + speed /= 64; + break; + } + ssp.speed = speed; + ssp.parity = parity; + ssp.data_bits = data_bits; + ssp.stop_bits = stop_bits; + SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s), + speed, parity, data_bits, stop_bits); + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); +} + static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { SerialState *ser = opaque; @@ -269,7 +326,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint s = &ser->chn[channel]; switch (saddr) { case 0: - SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff); + SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff); newreg = 0; switch (s->reg) { case 0: @@ -292,9 +349,18 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint break; } break; - case 1 ... 8: - case 10 ... 15: + case 1 ... 3: + case 6 ... 8: + case 10 ... 11: + case 14 ... 15: + s->wregs[s->reg] = val; + break; + case 4: + case 5: + case 12: + case 13: s->wregs[s->reg] = val; + slavio_serial_update_parameters(s); break; case 9: switch (val & 0xc0) { @@ -321,7 +387,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint s->reg = 0; break; case 1: - SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val); + SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val); if (s->wregs[5] & 8) { // tx enabled s->tx = val; if (s->chr) @@ -352,7 +418,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) s = &ser->chn[channel]; switch (saddr) { case 0: - SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]); + SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]); ret = s->rregs[s->reg]; s->reg = 0; return ret; @@ -363,7 +429,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) ret = get_queue(s); else ret = s->rx; - SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret); + SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret); return ret; default: break; @@ -381,13 +447,13 @@ static int serial_can_receive(void *opaque) ret = 0; else ret = 1; - SER_DPRINTF("can receive %d\n", ret); + //SER_DPRINTF("channel %c can receive %d\n", CHN_C(s), ret); return ret; } static void serial_receive_byte(ChannelState *s, int ch) { - SER_DPRINTF("put ch %d\n", ch); + SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch); s->rregs[0] |= 1; s->rx = ch; set_rxint(s); -- cgit v1.2.3 From 78600320a8571f4b065a7ea9331e1290d319acbb Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 9 Sep 2006 14:36:26 +0000 Subject: Arm MMU fix (Justin Fletcher). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2154 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 2ed46a29b..04d3b5254 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -239,7 +239,7 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type, switch (ap) { case 0: - if (access_type != 1) + if (access_type == 1) return 0; switch ((env->cp15.c1_sys >> 8) & 3) { case 1: -- cgit v1.2.3 From 707b3ee068a1324b708f6dd707cc156a0b8de371 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 9 Sep 2006 23:35:22 +0000 Subject: ARM 64-bit host fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2155 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall_defs.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 73a5c4250..015f3ba24 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -938,29 +938,29 @@ struct target_stat64 { struct target_eabi_stat64 { unsigned long long st_dev; unsigned int __pad1; - unsigned long __st_ino; + target_ulong __st_ino; unsigned int st_mode; unsigned int st_nlink; - unsigned long st_uid; - unsigned long st_gid; + target_ulong st_uid; + target_ulong st_gid; unsigned long long st_rdev; unsigned int __pad2[2]; long long st_size; - unsigned long st_blksize; + target_ulong st_blksize; unsigned int __pad3; unsigned long long st_blocks; - unsigned long target_st_atime; - unsigned long target_st_atime_nsec; + target_ulong target_st_atime; + target_ulong target_st_atime_nsec; - unsigned long target_st_mtime; - unsigned long target_st_mtime_nsec; + target_ulong target_st_mtime; + target_ulong target_st_mtime_nsec; - unsigned long target_st_ctime; - unsigned long target_st_ctime_nsec; + target_ulong target_st_ctime; + target_ulong target_st_ctime_nsec; unsigned long long st_ino; } __attribute__ ((packed)); -- cgit v1.2.3 From 519945dfbe270059cf012863b97343c752f634cf Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 10 Sep 2006 14:39:54 +0000 Subject: Avoid (repeatedly) trying to read stdin after it has closed. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2156 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vl.c b/vl.c index 45e9417f2..d422fedcf 100644 --- a/vl.c +++ b/vl.c @@ -1417,6 +1417,11 @@ static void stdio_read(void *opaque) uint8_t buf[1]; size = read(0, buf, 1); + if (size == 0) { + /* stdin has been closed. Remove it from the active list. */ + qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); + return; + } if (size > 0) stdio_received_byte(buf[0]); } -- cgit v1.2.3 From b8174937ed2c885aca5b9b08773a34397d802717 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 10 Sep 2006 19:25:12 +0000 Subject: dummy cs4231 audio driver for sun4m (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2157 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + hw/cs4231.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/sun4m.c | 4 ++ vl.h | 3 + 4 files changed, 191 insertions(+) create mode 100644 hw/cs4231.c diff --git a/Makefile.target b/Makefile.target index 65c336298..89b44144d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -361,6 +361,7 @@ 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) diff --git a/hw/cs4231.c b/hw/cs4231.c new file mode 100644 index 000000000..a15468556 --- /dev/null +++ b/hw/cs4231.c @@ -0,0 +1,183 @@ +/* + * QEMU Crystal CS4231 audio chip emulation + * + * 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" + +/* debug CS4231 */ +//#define DEBUG_CS + +/* + * In addition to Crystal CS4231 there is a DMA controller on Sparc. + */ +#define CS_MAXADDR 0x3f +#define CS_REGS 16 +#define CS_DREGS 32 +#define CS_MAXDREG (CS_DREGS - 1) + +typedef struct CSState { + uint32_t regs[CS_REGS]; + uint8_t dregs[CS_DREGS]; + void *intctl; +} CSState; + +#define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG) +#define CS_VER 0xa0 +#define CS_CDC_VER 0x8a + +#ifdef DEBUG_CS +#define DPRINTF(fmt, args...) \ + do { printf("CS: " fmt , ##args); } while (0) +#define pic_set_irq_new(intctl, irq, level) \ + do { printf("CS: set_irq(%d): %d\n", (irq), (level)); \ + pic_set_irq_new((intctl), (irq),(level));} while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +static void cs_reset(void *opaque) +{ + CSState *s = opaque; + + memset(s->regs, 0, CS_REGS * 4); + memset(s->dregs, 0, CS_DREGS); + s->dregs[12] = CS_CDC_VER; + s->dregs[25] = CS_VER; +} + +static uint32_t cs_mem_readl(void *opaque, target_phys_addr_t addr) +{ + CSState *s = opaque; + uint32_t saddr, ret; + + saddr = (addr & CS_MAXADDR) >> 2; + switch (saddr) { + case 1: + switch (CS_RAP(s)) { + case 3: // Write only + ret = 0; + break; + default: + ret = s->dregs[CS_RAP(s)]; + break; + } + DPRINTF("read dreg[%d]: 0x%8.8x\n", CS_RAP(s), ret); + break; + default: + ret = s->regs[saddr]; + DPRINTF("read reg[%d]: 0x%8.8x\n", saddr, ret); + break; + } + return ret; +} + +static void cs_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + CSState *s = opaque; + uint32_t saddr; + + saddr = (addr & CS_MAXADDR) >> 2; + DPRINTF("write reg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->regs[saddr], val); + switch (saddr) { + case 1: + DPRINTF("write dreg[%d]: 0x%2.2x -> 0x%2.2x\n", CS_RAP(s), s->dregs[CS_RAP(s)], val); + switch(CS_RAP(s)) { + case 11: + case 25: // Read only + break; + case 12: + val &= 0x40; + val |= CS_CDC_VER; // Codec version + s->dregs[CS_RAP(s)] = val; + break; + default: + s->dregs[CS_RAP(s)] = val; + break; + } + break; + case 2: // Read only + break; + case 4: + if (val & 1) + cs_reset(s); + val &= 0x7f; + s->regs[saddr] = val; + break; + default: + s->regs[saddr] = val; + break; + } +} + +static CPUReadMemoryFunc *cs_mem_read[3] = { + cs_mem_readl, + cs_mem_readl, + cs_mem_readl, +}; + +static CPUWriteMemoryFunc *cs_mem_write[3] = { + cs_mem_writel, + cs_mem_writel, + cs_mem_writel, +}; + +static void cs_save(QEMUFile *f, void *opaque) +{ + CSState *s = opaque; + unsigned int i; + + for (i = 0; i < CS_REGS; i++) + qemu_put_be32s(f, &s->regs[i]); + + qemu_put_buffer(f, s->dregs, CS_DREGS); +} + +static int cs_load(QEMUFile *f, void *opaque, int version_id) +{ + CSState *s = opaque; + unsigned int i; + + if (version_id > 1) + return -EINVAL; + + for (i = 0; i < CS_REGS; i++) + qemu_get_be32s(f, &s->regs[i]); + + qemu_get_buffer(f, s->dregs, CS_DREGS); + return 0; +} + +void cs_init(target_phys_addr_t base, int irq, void *intctl) +{ + int cs_io_memory; + CSState *s; + + s = qemu_mallocz(sizeof(CSState)); + if (!s) + return; + + cs_io_memory = cpu_register_io_memory(0, cs_mem_read, cs_mem_write, s); + cpu_register_physical_memory(base, CS_MAXADDR, cs_io_memory); + register_savevm("cs4231", base, 1, cs_save, cs_load, s); + qemu_register_reset(cs_reset, s); + cs_reset(s); +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 94629364d..a636638b5 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -55,6 +55,9 @@ #define PHYS_JJ_FDC 0x71400000 /* Floppy */ #define PHYS_JJ_FLOPPY_IRQ 22 #define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */ +#define PHYS_JJ_CS 0x6c000000 /* Crystal CS4231 */ +#define PHYS_JJ_CS_IRQ 5 + #define MAX_CPUS 16 /* TSC handling */ @@ -260,6 +263,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma); slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); + cs_init(PHYS_JJ_CS, PHYS_JJ_CS_IRQ, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); prom_offset = ram_size + vram_size; diff --git a/vl.h b/vl.h index f831e0ff9..26191cae5 100644 --- a/vl.h +++ b/vl.h @@ -1097,6 +1097,9 @@ void espdma_memory_write(void *opaque, uint8_t *buf, int len); void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque, void *lance_opaque); +/* cs4231.c */ +void cs_init(target_phys_addr_t base, int irq, void *intctl); + /* sun4u.c */ extern QEMUMachine sun4u_machine; -- cgit v1.2.3 From 6787f5fae0fb9e3923b8c316780645c3e1d81df2 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 17 Sep 2006 03:20:58 +0000 Subject: SPARC SCSI fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2158 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index be5600183..4587502e2 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -61,7 +61,11 @@ struct ESPState { int cmdlen; int do_cmd; + /* The amount of data left in the current DMA transfer. */ uint32_t dma_left; + /* The size of the current DMA transfer. Zero if no transfer is in + progress. */ + uint32_t dma_counter; uint8_t *async_buf; uint32_t async_len; void *dma_opaque; @@ -92,7 +96,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) uint32_t dmalen; int target; - dmalen = s->wregs[0] | (s->wregs[1] << 8); + dmalen = s->rregs[0] | (s->rregs[1] << 8); target = s->wregs[4] & 7; DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { @@ -137,6 +141,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) if (datalen != 0) { s->rregs[4] = STAT_IN | STAT_TC; s->dma_left = 0; + s->dma_counter = 0; if (datalen > 0) { s->rregs[4] |= STAT_DI; scsi_read_data(s->current_dev, 0); @@ -198,6 +203,8 @@ static void esp_dma_done(ESPState *s) s->rregs[5] = INTR_BS; s->rregs[6] = 0; s->rregs[7] = 0; + s->rregs[0] = 0; + s->rregs[1] = 0; espdma_raise_irq(s->dma_opaque); } @@ -232,17 +239,25 @@ static void esp_do_dma(ESPState *s) s->dma_left -= len; s->async_buf += len; s->async_len -= len; + if (to_device) + s->ti_size += len; + else + s->ti_size -= len; if (s->async_len == 0) { if (to_device) { // ti_size is negative - s->ti_size += len; scsi_write_data(s->current_dev, 0); } else { - s->ti_size -= len; scsi_read_data(s->current_dev, 0); + /* If there is still data to be read from the device then + complete the DMA operation immeriately. Otherwise defer + until the scsi layer has completed. */ + if (s->dma_left == 0 && s->ti_size > 0) { + esp_dma_done(s); + } } - } - if (s->dma_left == 0) { + } else { + /* Partially filled a scsi buffer. Complete immediately. */ esp_dma_done(s); } } @@ -269,8 +284,13 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag, DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); s->async_len = arg; s->async_buf = scsi_get_buf(s->current_dev, 0); - if (s->dma_left) + if (s->dma_left) { esp_do_dma(s); + } else if (s->dma_counter != 0 && s->ti_size <= 0) { + /* If this was the last part of a DMA transfer then the + completion interrupt is deferred to here. */ + esp_dma_done(s); + } } } @@ -278,10 +298,11 @@ static void handle_ti(ESPState *s) { uint32_t dmalen, minlen; - dmalen = s->wregs[0] | (s->wregs[1] << 8); + dmalen = s->rregs[0] | (s->rregs[1] << 8); if (dmalen==0) { dmalen=0x10000; } + s->dma_counter = dmalen; if (s->do_cmd) minlen = (dmalen < 32) ? dmalen : 32; @@ -366,7 +387,6 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) switch (saddr) { case 0: case 1: - s->rregs[saddr] = val; s->rregs[4] &= ~STAT_TC; break; case 2: @@ -388,6 +408,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) // Command if (val & 0x80) { s->dma = 1; + /* Reload DMA counter. */ + s->rregs[0] = s->wregs[0]; + s->rregs[1] = s->wregs[1]; } else { s->dma = 0; } -- cgit v1.2.3 From aef445bd7e46d2d47701a03c5478da34b3d53c4c Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 18 Sep 2006 01:15:29 +0000 Subject: Merge common ISA access routines. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2159 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/isa_mmio.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/mips_r4k.c | 86 +---------------------------------------------- hw/ppc.c | 58 -------------------------------- hw/ppc_chrp.c | 10 +++--- vl.h | 2 ++ 6 files changed, 110 insertions(+), 150 deletions(-) create mode 100644 hw/isa_mmio.c diff --git a/Makefile.target b/Makefile.target index 89b44144d..d61b8e5d0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -289,7 +289,7 @@ ifeq ($(ARCH),alpha) 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 +VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.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 diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c new file mode 100644 index 000000000..070f6f587 --- /dev/null +++ b/hw/isa_mmio.c @@ -0,0 +1,102 @@ +/* + * Memory mapped access to ISA IO space. + * + * 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" + +static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outb(NULL, addr & 0xffff, val); +} + +static void isa_mmio_writew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + cpu_outw(NULL, addr & 0xffff, val); +} + +static void isa_mmio_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + cpu_outl(NULL, addr & 0xffff, val); +} + +static uint32_t isa_mmio_readb (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inb(NULL, addr & 0xffff); + return val; +} + +static uint32_t isa_mmio_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inw(NULL, addr & 0xffff); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t isa_mmio_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inl(NULL, addr & 0xffff); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *isa_mmio_write[] = { + &isa_mmio_writeb, + &isa_mmio_writew, + &isa_mmio_writel, +}; + +static CPUReadMemoryFunc *isa_mmio_read[] = { + &isa_mmio_readb, + &isa_mmio_readw, + &isa_mmio_readl, +}; + +static int isa_mmio_iomemtype = 0; + +void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size) +{ + if (!isa_mmio_iomemtype) { + isa_mmio_iomemtype = cpu_register_io_memory(0, isa_mmio_read, + isa_mmio_write, NULL); + } + cpu_register_physical_memory(base, size, isa_mmio_iomemtype); +} diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index bad916319..075b16cb4 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -107,88 +107,6 @@ void cpu_mips_clock_init (CPUState *env) } -static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); -#endif - cpu_outb(NULL, addr & 0xffff, value); -} - -static uint32_t io_readb (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inb(NULL, addr & 0xffff); -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); -#endif - return ret; -} - -static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); -#endif -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap16(value); -#endif - cpu_outw(NULL, addr & 0xffff, value); -} - -static uint32_t io_readw (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inw(NULL, addr & 0xffff); -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap16(ret); -#endif -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); -#endif - return ret; -} - -static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); -#endif -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap32(value); -#endif - cpu_outl(NULL, addr & 0xffff, value); -} - -static uint32_t io_readl (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inl(NULL, addr & 0xffff); - -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap32(ret); -#endif -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); -#endif - return ret; -} - -CPUWriteMemoryFunc *io_write[] = { - &io_writeb, - &io_writew, - &io_writel, -}; - -CPUReadMemoryFunc *io_read[] = { - &io_readb, - &io_readw, - &io_readl, -}; - void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -197,7 +115,6 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, char buf[1024]; int64_t entry = 0; unsigned long bios_offset; - int io_memory; int ret; CPUState *env; long kernel_size; @@ -263,8 +180,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, cpu_mips_irqctrl_init(); /* Register 64 KB of ISA IO space at 0x14000000 */ - io_memory = cpu_register_io_memory(0, io_read, io_write, NULL); - cpu_register_physical_memory(0x14000000, 0x00010000, io_memory); + isa_mmio_init(0x14000000, 0x00010000); isa_mem_base = 0x10000000; isa_pic = pic_init(pic_irq_request, env); diff --git a/hw/ppc.c b/hw/ppc.c index 3743ad786..b0865c164 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -201,64 +201,6 @@ void cpu_ppc_reset (CPUState *env) } #endif -static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - cpu_outb(NULL, addr & 0xffff, value); -} - -static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inb(NULL, addr & 0xffff); - return ret; -} - -static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap16(value); -#endif - cpu_outw(NULL, addr & 0xffff, value); -} - -static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inw(NULL, addr & 0xffff); -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap16(ret); -#endif - return ret; -} - -static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap32(value); -#endif - cpu_outl(NULL, addr & 0xffff, value); -} - -static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inl(NULL, addr & 0xffff); - -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap32(ret); -#endif - return ret; -} - -CPUWriteMemoryFunc *PPC_io_write[] = { - &PPC_io_writeb, - &PPC_io_writew, - &PPC_io_writel, -}; - -CPUReadMemoryFunc *PPC_io_read[] = { - &PPC_io_readb, - &PPC_io_readw, - &PPC_io_readl, -}; - /*****************************************************************************/ /* Debug port */ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 94707690e..7599eab91 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -305,7 +305,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, SetIRQFunc *set_irq; void *pic; m48t59_t *nvram; - int PPC_io_memory, unin_memory; + int unin_memory; int linux_boot, i; unsigned long bios_offset, vga_bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; @@ -417,9 +417,8 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, isa_mem_base = 0x80000000; /* Register 2 MB of ISA IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); - cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory); - + isa_mmio_init(0xfe000000, 0x00200000); + /* init basic PC hardware */ pic = heathrow_pic_init(&heathrow_pic_mem_index); set_irq = heathrow_pic_set_irq; @@ -463,8 +462,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, isa_mem_base = 0x80000000; /* Register 8 MB of ISA IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); - cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory); + isa_mmio_init(0xf2000000, 0x00800000); /* UniN init */ unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); diff --git a/vl.h b/vl.h index 26191cae5..e16fd9285 100644 --- a/vl.h +++ b/vl.h @@ -675,6 +675,8 @@ int register_ioport_write(int start, int length, int size, IOPortWriteFunc *func, void *opaque); void isa_unassign_ioport(int start, int length); +void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size); + /* PCI bus */ extern target_phys_addr_t pci_mem_base; -- cgit v1.2.3 From 8f40c388ef0b1ce79c08d20b2a4b2a4a4f56a6f0 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 20 Sep 2006 20:28:05 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2160 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index cc73dcddc..060c42c08 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1,7 +1,7 @@ \input texinfo @c -*- texinfo -*- @c %**start of header @setfilename qemu-doc.info -@settitle QEMU CPU Emulator User Documentation +@settitle QEMU Emulator User Documentation @exampleindent 0 @paragraphindent 0 @c %**end of header @@ -9,7 +9,7 @@ @iftex @titlepage @sp 7 -@center @titlefont{QEMU CPU Emulator} +@center @titlefont{QEMU Emulator} @sp 1 @center @titlefont{User Documentation} @sp 3 @@ -1114,6 +1114,8 @@ This is the standard way to connect QEMU to a real network. QEMU adds a virtual network device on your host (called @code{tapN}), and you can then configure it as if it was a real ethernet card. +@subsubsection Linux host + As an example, you can download the @file{linux-test-xxx.tar.gz} archive and copy the script @file{qemu-ifup} in @file{/etc} and configure properly @code{sudo} so that the command @code{ifconfig} @@ -1124,6 +1126,13 @@ device @file{/dev/net/tun} must be present. See @ref{sec_invocation} to have examples of command lines using the TAP network interfaces. +@subsubsection Windows host + +There is a virtual ethernet driver for Windows 2000/XP systems, called +TAP-Win32. But it is not included in standard QEMU for Windows, +so you will need to get it separately. It is part of OpenVPN package, +so download OpenVPN from : @url{http://openvpn.net/}. + @subsection Using the user mode network stack By using the option @option{-net user} (default configuration if no -- cgit v1.2.3 From df52b0009bcd7cb10e52f37cb669c3b46a4b36b0 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 20 Sep 2006 20:30:57 +0000 Subject: sun4m halt support (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2161 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 6 ++++-- hw/slavio_misc.c | 3 --- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index eeeeb8f5d..6385639f4 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -548,8 +548,10 @@ int cpu_exec(CPUState *env1) //do_interrupt(0, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; } else if (interrupt_request & CPU_INTERRUPT_HALT) { - env1->halted = 1; - return EXCP_HALTED; + 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 diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 904f44e51..a48a7af5c 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -123,10 +123,7 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32 break; case 0xa000000: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); -#if 0 - // XXX almost works cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); -#endif break; } } -- cgit v1.2.3 From 05f83f0f950fa1ae412d05670bf8c05adaaccb6b Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 21 Sep 2006 20:34:50 +0000 Subject: Update sparc bios image (Blue Swirl). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2162 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/openbios-sparc32 | Bin 246036 -> 241940 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 04b60776d..b3f2c5238 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ -- cgit v1.2.3 From 37dd208d38ab9f65f9e15fd7fe2f0b75bc83220a Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 21 Sep 2006 21:46:53 +0000 Subject: VBE: 8 bit DACs + support for VBE BIOS IDs (Volker Ruppert) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2163 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 17 +++++++++++++---- hw/vga_int.h | 3 +++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 4ecb7a95c..0609f84cc 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -422,7 +422,9 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) case VBE_DISPI_INDEX_ID: if (val == VBE_DISPI_ID0 || val == VBE_DISPI_ID1 || - val == VBE_DISPI_ID2) { + val == VBE_DISPI_ID2 || + val == VBE_DISPI_ID3 || + val == VBE_DISPI_ID4) { s->vbe_regs[s->vbe_index] = val; } break; @@ -505,6 +507,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) /* XXX: the bios should do that */ s->bank_offset = 0; } + s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0; s->vbe_regs[s->vbe_index] = val; break; case VBE_DISPI_INDEX_VIRT_WIDTH: @@ -921,9 +924,15 @@ static int update_palette256(VGAState *s) palette = s->last_palette; v = 0; for(i = 0; i < 256; i++) { - col = s->rgb_to_pixel(c6_to_8(s->palette[v]), - c6_to_8(s->palette[v + 1]), - c6_to_8(s->palette[v + 2])); + if (s->dac_8bit) { + col = s->rgb_to_pixel(s->palette[v], + s->palette[v + 1], + s->palette[v + 2]); + } else { + col = s->rgb_to_pixel(c6_to_8(s->palette[v]), + c6_to_8(s->palette[v + 1]), + c6_to_8(s->palette[v + 2])); + } if (col != palette[i]) { full_update = 1; palette[i] = col; diff --git a/hw/vga_int.h b/hw/vga_int.h index 70127768a..633f344c7 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -49,6 +49,8 @@ #define VBE_DISPI_ID0 0xB0C0 #define VBE_DISPI_ID1 0xB0C1 #define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 #define VBE_DISPI_DISABLED 0x00 #define VBE_DISPI_ENABLED 0x01 @@ -103,6 +105,7 @@ uint8_t dac_read_index; \ uint8_t dac_write_index; \ uint8_t dac_cache[3]; /* used when writing */ \ + int dac_8bit; \ uint8_t palette[768]; \ int32_t bank_offset; \ int (*get_bpp)(struct VGAState *s); \ -- cgit v1.2.3 From e69954b9fc698996c8416a2fb26c6b50ad9f49a9 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 23 Sep 2006 17:40:58 +0000 Subject: Add ARM RealView Emulation Baseboard. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2164 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + hw/arm_gic.c | 544 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/arm_sysctl.c | 208 ++++++++++++++++++++ hw/pl080.c | 32 +++- hw/realview.c | 138 ++++++++++++++ hw/versatile_pci.c | 32 +++- hw/versatilepb.c | 194 +------------------ vl.c | 1 + vl.h | 13 +- 9 files changed, 957 insertions(+), 206 deletions(-) create mode 100644 hw/arm_gic.c create mode 100644 hw/arm_sysctl.c create mode 100644 hw/realview.c diff --git a/Makefile.target b/Makefile.target index d61b8e5d0..3d6fdc1c2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -368,6 +368,7 @@ 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 endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o diff --git a/hw/arm_gic.c b/hw/arm_gic.c new file mode 100644 index 000000000..c7cc38088 --- /dev/null +++ b/hw/arm_gic.c @@ -0,0 +1,544 @@ +/* + * ARM AMBA Generic/Distributed Interrupt Controller + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +/* TODO: Some variants of this controller can handle multiple CPUs. + Currently only single CPU operation is implemented. */ + +#include "vl.h" +#include "arm_pic.h" + +//#define DEBUG_GIC + +#ifdef DEBUG_GIC +#define DPRINTF(fmt, args...) \ +do { printf("arm_gic: " fmt , (int)s->base, ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +/* Distributed interrupt controller. */ + +static const uint8_t gic_id[] = +{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; + +#define GIC_NIRQ 96 + +typedef struct gic_irq_state +{ + unsigned enabled:1; + unsigned pending:1; + unsigned active:1; + unsigned level:1; + unsigned model:1; /* 0 = 1:N, 1 = N:N */ + unsigned trigger:1; /* nonzero = edge triggered. */ +} gic_irq_state; + +#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1 +#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0 +#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled +#define GIC_SET_PENDING(irq) s->irq_state[irq].pending = 1 +#define GIC_CLEAR_PENDING(irq) s->irq_state[irq].pending = 0 +#define GIC_TEST_PENDING(irq) s->irq_state[irq].pending +#define GIC_SET_ACTIVE(irq) s->irq_state[irq].active = 1 +#define GIC_CLEAR_ACTIVE(irq) s->irq_state[irq].active = 0 +#define GIC_TEST_ACTIVE(irq) s->irq_state[irq].active +#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1 +#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0 +#define GIC_TEST_MODEL(irq) s->irq_state[irq].model +#define GIC_SET_LEVEL(irq) s->irq_state[irq].level = 1 +#define GIC_CLEAR_LEVEL(irq) s->irq_state[irq].level = 0 +#define GIC_TEST_LEVEL(irq) s->irq_state[irq].level +#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1 +#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0 +#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger + +typedef struct gic_state +{ + arm_pic_handler handler; + uint32_t base; + void *parent; + int parent_irq; + int enabled; + int cpu_enabled; + + gic_irq_state irq_state[GIC_NIRQ]; + int irq_target[GIC_NIRQ]; + int priority[GIC_NIRQ]; + int last_active[GIC_NIRQ]; + + int priority_mask; + int running_irq; + int running_priority; + int current_pending; +} gic_state; + +/* TODO: Many places that call this routine could be optimized. */ +/* Update interrupt status after enabled or pending bits have been changed. */ +static void gic_update(gic_state *s) +{ + int best_irq; + int best_prio; + int irq; + + s->current_pending = 1023; + if (!s->enabled || !s->cpu_enabled) { + pic_set_irq_new(s->parent, s->parent_irq, 0); + return; + } + best_prio = 0x100; + best_irq = 1023; + for (irq = 0; irq < 96; irq++) { + if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq)) { + if (s->priority[irq] < best_prio) { + best_prio = s->priority[irq]; + best_irq = irq; + } + } + } + if (best_prio > s->priority_mask) { + pic_set_irq_new(s->parent, s->parent_irq, 0); + } else { + s->current_pending = best_irq; + if (best_prio < s->running_priority) { + DPRINTF("Raised pending IRQ %d\n", best_irq); + pic_set_irq_new(s->parent, s->parent_irq, 1); + } + } +} + +static void gic_set_irq(void *opaque, int irq, int level) +{ + gic_state *s = (gic_state *)opaque; + /* The first external input line is internal interrupt 32. */ + irq += 32; + if (level == GIC_TEST_LEVEL(irq)) + return; + + if (level) { + GIC_SET_LEVEL(irq); + if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) { + DPRINTF("Set %d pending\n", irq); + GIC_SET_PENDING(irq); + } + } else { + GIC_CLEAR_LEVEL(irq); + } + gic_update(s); +} + +static void gic_set_running_irq(gic_state *s, int irq) +{ + s->running_irq = irq; + s->running_priority = s->priority[irq]; + gic_update(s); +} + +static uint32_t gic_acknowledge_irq(gic_state *s) +{ + int new_irq; + new_irq = s->current_pending; + if (new_irq == 1023 || s->priority[new_irq] >= s->running_priority) { + DPRINTF("ACK no pending IRQ\n"); + return 1023; + } + pic_set_irq_new(s->parent, s->parent_irq, 0); + s->last_active[new_irq] = s->running_irq; + /* For level triggered interrupts we clear the pending bit while + the interrupt is active. */ + GIC_CLEAR_PENDING(new_irq); + gic_set_running_irq(s, new_irq); + DPRINTF("ACK %d\n", new_irq); + return new_irq; +} + +static void gic_complete_irq(gic_state * s, int irq) +{ + int update = 0; + DPRINTF("EIO %d\n", irq); + if (s->running_irq == 1023) + return; /* No active IRQ. */ + if (irq != 1023) { + /* Mark level triggered interrupts as pending if they are still + raised. */ + if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq) + && GIC_TEST_LEVEL(irq)) { + GIC_SET_PENDING(irq); + update = 1; + } + } + if (irq != s->running_irq) { + /* Complete an IRQ that is not currently running. */ + int tmp = s->running_irq; + while (s->last_active[tmp] != 1023) { + if (s->last_active[tmp] == irq) { + s->last_active[tmp] = s->last_active[irq]; + break; + } + tmp = s->last_active[tmp]; + } + if (update) { + gic_update(s); + } + } else { + /* Complete the current running IRQ. */ + gic_set_running_irq(s, s->last_active[s->running_irq]); + } +} + +static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) +{ + gic_state *s = (gic_state *)opaque; + uint32_t res; + int irq; + int i; + + offset -= s->base + 0x1000; + if (offset < 0x100) { + if (offset == 0) + return s->enabled; + if (offset == 4) + return (GIC_NIRQ / 32) - 1; + if (offset < 0x08) + return 0; + goto bad_reg; + } else if (offset < 0x200) { + /* Interrupt Set/Clear Enable. */ + if (offset < 0x180) + irq = (offset - 0x100) * 8; + else + irq = (offset - 0x180) * 8; + if (irq >= GIC_NIRQ) + goto bad_reg; + res = 0; + for (i = 0; i < 8; i++) { + if (GIC_TEST_ENABLED(irq + i)) { + res |= (1 << i); + } + } + } else if (offset < 0x300) { + /* Interrupt Set/Clear Pending. */ + if (offset < 0x280) + irq = (offset - 0x200) * 8; + else + irq = (offset - 0x280) * 8; + if (irq >= GIC_NIRQ) + goto bad_reg; + res = 0; + for (i = 0; i < 8; i++) { + if (GIC_TEST_PENDING(irq + i)) { + res |= (1 << i); + } + } + } else if (offset < 0x400) { + /* Interrupt Active. */ + irq = (offset - 0x300) * 8; + if (irq >= GIC_NIRQ) + goto bad_reg; + res = 0; + for (i = 0; i < 8; i++) { + if (GIC_TEST_ACTIVE(irq + i)) { + res |= (1 << i); + } + } + } else if (offset < 0x800) { + /* Interrupt Priority. */ + irq = offset - 0x400; + if (irq >= GIC_NIRQ) + goto bad_reg; + res = s->priority[irq]; + } else if (offset < 0xc00) { + /* Interrupt CPU Target. */ + irq = offset - 0x800; + if (irq >= GIC_NIRQ) + goto bad_reg; + res = s->irq_target[irq]; + } else if (offset < 0xf00) { + /* Interrupt Configuration. */ + irq = (offset - 0xc00) * 2; + if (irq >= GIC_NIRQ) + goto bad_reg; + res = 0; + for (i = 0; i < 4; i++) { + if (GIC_TEST_MODEL(irq + i)) + res |= (1 << (i * 2)); + if (GIC_TEST_TRIGGER(irq + i)) + res |= (2 << (i * 2)); + } + } else if (offset < 0xfe0) { + goto bad_reg; + } else /* offset >= 0xfe0 */ { + if (offset & 3) { + res = 0; + } else { + res = gic_id[(offset - 0xfe0) >> 2]; + } + } + return res; +bad_reg: + cpu_abort (cpu_single_env, "gic_dist_readb: Bad offset %x\n", offset); + return 0; +} + +static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset) +{ + uint32_t val; + val = gic_dist_readb(opaque, offset); + val |= gic_dist_readb(opaque, offset + 1) << 8; + return val; +} + +static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) +{ + uint32_t val; + val = gic_dist_readw(opaque, offset); + val |= gic_dist_readw(opaque, offset + 2) << 16; + return val; +} + +static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + gic_state *s = (gic_state *)opaque; + int irq; + int i; + + offset -= s->base + 0x1000; + if (offset < 0x100) { + if (offset == 0) { + s->enabled = (value & 1); + DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); + } else if (offset < 4) { + /* ignored. */ + } else { + goto bad_reg; + } + } else if (offset < 0x180) { + /* Interrupt Set Enable. */ + irq = (offset - 0x100) * 8; + if (irq >= GIC_NIRQ) + goto bad_reg; + for (i = 0; i < 8; i++) { + if (value & (1 << i)) { + if (!GIC_TEST_ENABLED(irq + i)) + DPRINTF("Enabled IRQ %d\n", irq + i); + GIC_SET_ENABLED(irq + i); + /* If a raised level triggered IRQ enabled then mark + is as pending. */ + if (GIC_TEST_LEVEL(irq + i) && !GIC_TEST_TRIGGER(irq + i)) + GIC_SET_PENDING(irq + i); + } + } + } else if (offset < 0x200) { + /* Interrupt Clear Enable. */ + irq = (offset - 0x180) * 8; + if (irq >= GIC_NIRQ) + goto bad_reg; + for (i = 0; i < 8; i++) { + if (value & (1 << i)) { + if (GIC_TEST_ENABLED(irq + i)) + DPRINTF("Disabled IRQ %d\n", irq + i); + GIC_CLEAR_ENABLED(irq + i); + } + } + } else if (offset < 0x280) { + /* Interrupt Set Pending. */ + irq = (offset - 0x200) * 8; + if (irq >= GIC_NIRQ) + goto bad_reg; + for (i = 0; i < 8; i++) { + if (value & (1 << i)) { + GIC_SET_PENDING(irq + i); + } + } + } else if (offset < 0x300) { + /* Interrupt Clear Pending. */ + irq = (offset - 0x280) * 8; + if (irq >= GIC_NIRQ) + goto bad_reg; + for (i = 0; i < 8; i++) { + if (value & (1 << i)) { + GIC_CLEAR_PENDING(irq + i); + } + } + } else if (offset < 0x400) { + /* Interrupt Active. */ + goto bad_reg; + } else if (offset < 0x800) { + /* Interrupt Priority. */ + irq = offset - 0x400; + if (irq >= GIC_NIRQ) + goto bad_reg; + s->priority[irq] = value; + } else if (offset < 0xc00) { + /* Interrupt CPU Target. */ + irq = offset - 0x800; + if (irq >= GIC_NIRQ) + goto bad_reg; + s->irq_target[irq] = value; + } else if (offset < 0xf00) { + /* Interrupt Configuration. */ + irq = (offset - 0xc00) * 2; + if (irq >= GIC_NIRQ) + goto bad_reg; + for (i = 0; i < 4; i++) { + if (value & (1 << (i * 2))) { + GIC_SET_MODEL(irq + i); + } else { + GIC_CLEAR_MODEL(irq + i); + } + if (value & (2 << (i * 2))) { + GIC_SET_TRIGGER(irq + i); + } else { + GIC_CLEAR_TRIGGER(irq + i); + } + } + } else { + /* 0xf00 is only handled for word writes. */ + goto bad_reg; + } + gic_update(s); + return; +bad_reg: + cpu_abort (cpu_single_env, "gic_dist_writeb: Bad offset %x\n", offset); +} + +static void gic_dist_writew(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + gic_state *s = (gic_state *)opaque; + if (offset - s->base == 0xf00) { + GIC_SET_PENDING(value & 0x3ff); + gic_update(s); + return; + } + gic_dist_writeb(opaque, offset, value & 0xff); + gic_dist_writeb(opaque, offset + 1, value >> 8); +} + +static void gic_dist_writel(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + gic_dist_writew(opaque, offset, value & 0xffff); + gic_dist_writew(opaque, offset + 2, value >> 16); +} + +static CPUReadMemoryFunc *gic_dist_readfn[] = { + gic_dist_readb, + gic_dist_readw, + gic_dist_readl +}; + +static CPUWriteMemoryFunc *gic_dist_writefn[] = { + gic_dist_writeb, + gic_dist_writew, + gic_dist_writel +}; + +static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset) +{ + gic_state *s = (gic_state *)opaque; + offset -= s->base; + switch (offset) { + case 0x00: /* Control */ + return s->cpu_enabled; + case 0x04: /* Priority mask */ + return s->priority_mask; + case 0x08: /* Binary Point */ + /* ??? Not implemented. */ + return 0; + case 0x0c: /* Acknowledge */ + return gic_acknowledge_irq(s); + case 0x14: /* Runing Priority */ + return s->running_priority; + case 0x18: /* Highest Pending Interrupt */ + return s->current_pending; + default: + cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset); + return 0; + } +} + +static void gic_cpu_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + gic_state *s = (gic_state *)opaque; + offset -= s->base; + switch (offset) { + case 0x00: /* Control */ + s->cpu_enabled = (value & 1); + DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis"); + break; + case 0x04: /* Priority mask */ + s->priority_mask = (value & 0x3ff); + break; + case 0x08: /* Binary Point */ + /* ??? Not implemented. */ + break; + case 0x10: /* End Of Interrupt */ + return gic_complete_irq(s, value & 0x3ff); + default: + cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset); + return; + } + gic_update(s); +} + +static CPUReadMemoryFunc *gic_cpu_readfn[] = { + gic_cpu_read, + gic_cpu_read, + gic_cpu_read +}; + +static CPUWriteMemoryFunc *gic_cpu_writefn[] = { + gic_cpu_write, + gic_cpu_write, + gic_cpu_write +}; + +static void gic_reset(gic_state *s) +{ + int i; + memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state)); + s->priority_mask = 0xf0; + s->current_pending = 1023; + s->running_irq = 1023; + s->running_priority = 0x100; + for (i = 0; i < 15; i++) { + GIC_SET_ENABLED(i); + GIC_SET_TRIGGER(i); + } + s->enabled = 0; + s->cpu_enabled = 0; +} + +void *arm_gic_init(uint32_t base, void *parent, int parent_irq) +{ + gic_state *s; + int iomemtype; + + s = (gic_state *)qemu_mallocz(sizeof(gic_state)); + if (!s) + return NULL; + s->handler = gic_set_irq; + s->parent = parent; + s->parent_irq = parent_irq; + if (base != 0xffffffff) { + iomemtype = cpu_register_io_memory(0, gic_cpu_readfn, + gic_cpu_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + iomemtype = cpu_register_io_memory(0, gic_dist_readfn, + gic_dist_writefn, s); + cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype); + s->base = base; + } else { + s->base = 0; + } + gic_reset(s); + return s; +} diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c new file mode 100644 index 000000000..e9de998a2 --- /dev/null +++ b/hw/arm_sysctl.c @@ -0,0 +1,208 @@ +/* + * Status and system control registers for ARM RealView/Versatile boards. + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "arm_pic.h" + +#define LOCK_VALUE 0xa05f + +typedef struct { + uint32_t base; + uint32_t sys_id; + uint32_t leds; + uint16_t lockval; + uint32_t cfgdata1; + uint32_t cfgdata2; + uint32_t flags; + uint32_t nvflags; + uint32_t resetlevel; +} arm_sysctl_state; + +static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset) +{ + arm_sysctl_state *s = (arm_sysctl_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* ID */ + return s->sys_id; + case 0x04: /* SW */ + /* General purpose hardware switches. + We don't have a useful way of exposing these to the user. */ + return 0; + case 0x08: /* LED */ + return s->leds; + case 0x20: /* LOCK */ + return s->lockval; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + case 0x24: /* 100HZ */ + /* ??? Implement these. */ + return 0; + case 0x28: /* CFGDATA1 */ + return s->cfgdata1; + case 0x2c: /* CFGDATA2 */ + return s->cfgdata2; + case 0x30: /* FLAGS */ + return s->flags; + case 0x38: /* NVFLAGS */ + return s->nvflags; + case 0x40: /* RESETCTL */ + return s->resetlevel; + case 0x44: /* PCICTL */ + return 1; + case 0x48: /* MCI */ + return 0; + case 0x4c: /* FLASH */ + return 0; + case 0x50: /* CLCD */ + return 0x1000; + case 0x54: /* CLCDSER */ + return 0; + case 0x58: /* BOOTCS */ + return 0; + case 0x5c: /* 24MHz */ + /* ??? not implemented. */ + return 0; + case 0x60: /* MISC */ + return 0; + case 0x84: /* PROCID0 */ + /* ??? Don't know what the proper value for the core tile ID is. */ + return 0x02000000; + case 0x88: /* PROCID1 */ + return 0xff000000; + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x70: /* IOSEL */ + case 0x74: /* PLDCTL */ + case 0x80: /* BUSID */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + case 0xc0: /* SYS_TEST_OSC0 */ + case 0xc4: /* SYS_TEST_OSC1 */ + case 0xc8: /* SYS_TEST_OSC2 */ + case 0xcc: /* SYS_TEST_OSC3 */ + case 0xd0: /* SYS_TEST_OSC4 */ + return 0; + default: + printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset); + return 0; + } +} + +static void arm_sysctl_write(void *opaque, target_phys_addr_t offset, + uint32_t val) +{ + arm_sysctl_state *s = (arm_sysctl_state *)opaque; + offset -= s->base; + + switch (offset) { + case 0x08: /* LED */ + s->leds = val; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + /* ??? */ + break; + case 0x20: /* LOCK */ + if (val == LOCK_VALUE) + s->lockval = val; + else + s->lockval = val & 0x7fff; + break; + case 0x28: /* CFGDATA1 */ + /* ??? Need to implement this. */ + s->cfgdata1 = val; + break; + case 0x2c: /* CFGDATA2 */ + /* ??? Need to implement this. */ + s->cfgdata2 = val; + break; + case 0x30: /* FLAGSSET */ + s->flags |= val; + break; + case 0x34: /* FLAGSCLR */ + s->flags &= ~val; + break; + case 0x38: /* NVFLAGSSET */ + s->nvflags |= val; + break; + case 0x3c: /* NVFLAGSCLR */ + s->nvflags &= ~val; + break; + case 0x40: /* RESETCTL */ + if (s->lockval == LOCK_VALUE) { + s->resetlevel = val; + if (val & 0x100) + cpu_abort(cpu_single_env, "Board reset\n"); + } + break; + case 0x44: /* PCICTL */ + /* nothing to do. */ + break; + case 0x4c: /* FLASH */ + case 0x50: /* CLCD */ + case 0x54: /* CLCDSER */ + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x70: /* IOSEL */ + case 0x74: /* PLDCTL */ + case 0x80: /* BUSID */ + case 0x84: /* PROCID0 */ + case 0x88: /* PROCID1 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + break; + default: + printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset); + return; + } +} + +static CPUReadMemoryFunc *arm_sysctl_readfn[] = { + arm_sysctl_read, + arm_sysctl_read, + arm_sysctl_read +}; + +static CPUWriteMemoryFunc *arm_sysctl_writefn[] = { + arm_sysctl_write, + arm_sysctl_write, + arm_sysctl_write +}; + +void arm_sysctl_init(uint32_t base, uint32_t sys_id) +{ + arm_sysctl_state *s; + int iomemtype; + + s = (arm_sysctl_state *)qemu_mallocz(sizeof(arm_sysctl_state)); + if (!s) + return; + s->base = base; + s->sys_id = sys_id; + iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn, + arm_sysctl_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + /* ??? Save/restore. */ +} + diff --git a/hw/pl080.c b/hw/pl080.c index 49996ca91..549b3bfd1 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -1,5 +1,5 @@ /* - * Arm PrimeCell PL080 DMA controller + * Arm PrimeCell PL080/PL081 DMA controller * * Copyright (c) 2006 CodeSourcery. * Written by Paul Brook @@ -9,7 +9,7 @@ #include "vl.h" -#define PL080_NUM_CHANNELS 8 +#define PL080_MAX_CHANNELS 8 #define PL080_CONF_E 0x1 #define PL080_CONF_M1 0x2 #define PL080_CONF_M2 0x4 @@ -45,7 +45,8 @@ typedef struct { uint32_t sync; uint32_t req_single; uint32_t req_burst; - pl080_channel chan[PL080_NUM_CHANNELS]; + pl080_channel chan[PL080_MAX_CHANNELS]; + int nchannels; /* Flag to avoid recursive DMA invocations. */ int running; void *pic; @@ -55,6 +56,9 @@ typedef struct { static const unsigned char pl080_id[] = { 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; +static const unsigned char pl081_id[] = +{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; + static void pl080_update(pl080_state *s) { if ((s->tc_int & s->tc_mask) @@ -80,7 +84,7 @@ static void pl080_run(pl080_state *s) uint32_t req; s->tc_mask = 0; - for (c = 0; c < PL080_NUM_CHANNELS; c++) { + for (c = 0; c < s->nchannels; c++) { if (s->chan[c].conf & PL080_CCONF_ITC) s->tc_mask |= 1 << c; if (s->chan[c].conf & PL080_CCONF_IE) @@ -99,7 +103,7 @@ cpu_abort(cpu_single_env, "DMA active\n"); } s->running = 1; while (s->running) { - for (c = 0; c < PL080_NUM_CHANNELS; c++) { + for (c = 0; c < s->nchannels; c++) { ch = &s->chan[c]; again: /* Test if thiws channel has any pending DMA requests. */ @@ -185,10 +189,16 @@ static uint32_t pl080_read(void *opaque, target_phys_addr_t offset) offset -= s->base; if (offset >= 0xfe0 && offset < 0x1000) { - return pl080_id[(offset - 0xfe0) >> 2]; + if (s->nchannels == 8) { + return pl080_id[(offset - 0xfe0) >> 2]; + } else { + return pl081_id[(offset - 0xfe0) >> 2]; + } } if (offset >= 0x100 && offset < 0x200) { i = (offset & 0xe0) >> 5; + if (i >= s->nchannels) + goto bad_offset; switch (offset >> 2) { case 0: /* SrcAddr */ return s->chan[i].src; @@ -217,7 +227,7 @@ static uint32_t pl080_read(void *opaque, target_phys_addr_t offset) return s->err_int; case 7: /* EnbldChns */ mask = 0; - for (i = 0; i < PL080_NUM_CHANNELS; i++) { + for (i = 0; i < s->nchannels; i++) { if (s->chan[i].conf & PL080_CCONF_E) mask |= 1 << i; } @@ -248,6 +258,8 @@ static void pl080_write(void *opaque, target_phys_addr_t offset, offset -= s->base; if (offset >= 0x100 && offset < 0x200) { i = (offset & 0xe0) >> 5; + if (i >= s->nchannels) + goto bad_offset; switch (offset >> 2) { case 0: /* SrcAddr */ s->chan[i].src = value; @@ -293,6 +305,7 @@ static void pl080_write(void *opaque, target_phys_addr_t offset, s->sync = value; break; default: + bad_offset: cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset); } pl080_update(s); @@ -310,7 +323,9 @@ static CPUWriteMemoryFunc *pl080_writefn[] = { pl080_write }; -void *pl080_init(uint32_t base, void *pic, int irq) +/* The PL080 and PL081 are the same except for the number of channels + they implement (8 and 2 respectively). */ +void *pl080_init(uint32_t base, void *pic, int irq, int nchannels) { int iomemtype; pl080_state *s; @@ -322,6 +337,7 @@ void *pl080_init(uint32_t base, void *pic, int irq) s->base = base; s->pic = pic; s->irq = irq; + s->nchannels = nchannels; /* ??? Save/restore. */ return s; } diff --git a/hw/realview.c b/hw/realview.c new file mode 100644 index 000000000..11b091608 --- /dev/null +++ b/hw/realview.c @@ -0,0 +1,138 @@ +/* + * ARM RealView Baseboard System emulation. + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "arm_pic.h" + +/* Board init. */ + +static void realview_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + CPUState *env; + void *pic; + void *scsi_hba; + PCIBus *pci_bus; + NICInfo *nd; + int n; + int done_smc = 0; + + env = cpu_init(); + cpu_arm_set_model(env, ARM_CPUID_ARM926); + //cpu_arm_set_model(env, ARM_CPUID_ARM11MPCORE); + /* ??? RAM shoud repeat to fill physical memory space. */ + /* SDRAM at address zero. */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + arm_sysctl_init(0x10000000, 0xc1400400); + pic = arm_pic_init_cpu(env); + /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3 + is nIRQ (there are inconsistencies). However Linux 2.6.17 expects + GIC1 to be nIRQ and ignores all the others, so do that for now. */ + pic = arm_gic_init(0x10040000, pic, ARM_PIC_CPU_IRQ); + pl050_init(0x10006000, pic, 20, 0); + pl050_init(0x10007000, pic, 21, 1); + + pl011_init(0x10009000, pic, 12, serial_hds[0]); + pl011_init(0x1000a000, pic, 13, serial_hds[1]); + pl011_init(0x1000b000, pic, 14, serial_hds[2]); + pl011_init(0x1000c000, pic, 15, serial_hds[3]); + + /* DMA controller is optional, apparently. */ + pl080_init(0x10030000, pic, 24, 2); + + sp804_init(0x10011000, pic, 4); + sp804_init(0x10012000, pic, 5); + + pl110_init(ds, 0x10020000, pic, 23, 1); + + pci_bus = pci_vpb_init(pic, 48, 1); + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + scsi_hba = lsi_scsi_init(pci_bus, -1); + for (n = 0; n < MAX_DISKS; n++) { + if (bs_table[n]) { + lsi_scsi_attach(scsi_hba, bs_table[n], n); + } + } + for(n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + if (!nd->model) + nd->model = done_smc ? "rtl8139" : "smc91c111"; + if (strcmp(nd->model, "smc91c111") == 0) { + smc91c111_init(nd, 0x4e000000, pic, 28); + } else { + pci_nic_init(pci_bus, nd); + } + } + + /* Memory map for RealView Emulation Baseboard: */ + /* 0x10000000 System registers. */ + /* 0x10001000 System controller. */ + /* 0x10002000 Two-Wire Serial Bus. */ + /* 0x10003000 Reserved. */ + /* 0x10004000 AACI. */ + /* 0x10005000 MCI. */ + /* 0x10006000 KMI0. */ + /* 0x10007000 KMI1. */ + /* 0x10008000 Character LCD. */ + /* 0x10009000 UART0. */ + /* 0x1000a000 UART1. */ + /* 0x1000b000 UART2. */ + /* 0x1000c000 UART3. */ + /* 0x1000d000 SSPI. */ + /* 0x1000e000 SCI. */ + /* 0x1000f000 Reserved. */ + /* 0x10010000 Watchdog. */ + /* 0x10011000 Timer 0+1. */ + /* 0x10012000 Timer 2+3. */ + /* 0x10013000 GPIO 0. */ + /* 0x10014000 GPIO 1. */ + /* 0x10015000 GPIO 2. */ + /* 0x10016000 Reserved. */ + /* 0x10017000 RTC. */ + /* 0x10018000 DMC. */ + /* 0x10019000 PCI controller config. */ + /* 0x10020000 CLCD. */ + /* 0x10030000 DMA Controller. */ + /* 0x10040000 GIC1 (FIQ1). */ + /* 0x10050000 GIC2 (IRQ1). */ + /* 0x10060000 GIC3 (FIQ2). */ + /* 0x10070000 GIC4 (IRQ2). */ + /* 0x10080000 SMC. */ + /* 0x40000000 NOR flash. */ + /* 0x44000000 DoC flash. */ + /* 0x48000000 SRAM. */ + /* 0x4c000000 Configuration flash. */ + /* 0x4e000000 Ethernet. */ + /* 0x4f000000 USB. */ + /* 0x50000000 PISMO. */ + /* 0x54000000 PISMO. */ + /* 0x58000000 PISMO. */ + /* 0x5c000000 PISMO. */ + /* 0x60000000 PCI. */ + /* 0x61000000 PCI Self Config. */ + /* 0x62000000 PCI Config. */ + /* 0x63000000 PCI IO. */ + /* 0x64000000 PCI mem 0. */ + /* 0x68000000 PCI mem 1. */ + /* 0x6c000000 PCI mem 2. */ + + arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, + initrd_filename, 0x33b); +} + +QEMUMachine realview_machine = { + "realview", + "ARM RealView Emulation Baseboard (ARM926EJ-S)", + realview_init +}; diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 34a4bc6c5..aac61c7b5 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -77,31 +77,49 @@ static CPUReadMemoryFunc *pci_vpb_config_read[] = { &pci_vpb_config_readl, }; +static int pci_vpb_irq; + static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) { - pic_set_irq_new(pic, 27 + irq_num, level); + pic_set_irq_new(pic, pci_vpb_irq + irq_num, level); } -PCIBus *pci_vpb_init(void *pic) +PCIBus *pci_vpb_init(void *pic, int irq, int realview) { PCIBus *s; PCIDevice *d; int mem_config; - + uint32_t base; + const char * name; + + pci_vpb_irq = irq; + if (realview) { + base = 0x60000000; + name = "RealView EB PCI Controller"; + } else { + base = 0x40000000; + name = "Versatile/PB PCI Controller"; + } s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3); /* ??? Register memory space. */ mem_config = cpu_register_io_memory(0, pci_vpb_config_read, pci_vpb_config_write, s); /* Selfconfig area. */ - cpu_register_physical_memory(0x41000000, 0x10000, mem_config); + cpu_register_physical_memory(base + 0x01000000, 0x10000, mem_config); /* Normal config area. */ - cpu_register_physical_memory(0x42000000, 0x10000, mem_config); + cpu_register_physical_memory(base + 0x02000000, 0x10000, mem_config); + + d = pci_register_device(s, name, sizeof(PCIDevice), -1, NULL, NULL); + + if (realview) { + /* IO memory area. */ + isa_mmio_init(base + 0x03000000, 0x00100000); + } - d = pci_register_device(s, "Versatile/PB PCI Controller", - sizeof(PCIDevice), -1, NULL, NULL); d->config[0x00] = 0xee; // vendor_id d->config[0x01] = 0x10; + /* Both boards have the same device ID. Oh well. */ d->config[0x02] = 0x00; // device_id d->config[0x03] = 0x03; d->config[0x04] = 0x00; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 28ec1374b..475cb4892 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -10,8 +10,6 @@ #include "vl.h" #include "arm_pic.h" -#define LOCK_VALUE 0xa05f - /* Primary interrupt controller. */ typedef struct vpb_sic_state @@ -75,7 +73,7 @@ static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset) case 8: /* PICENABLE */ return s->pic_enable; default: - printf ("vpb_sic_read: Bad register offset 0x%x\n", offset); + printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset); return 0; } } @@ -110,7 +108,7 @@ static void vpb_sic_write(void *opaque, target_phys_addr_t offset, vpb_sic_update_pic(s); break; default: - printf ("vpb_sic_write: Bad register offset 0x%x\n", offset); + printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset); return; } vpb_sic_update(s); @@ -147,188 +145,6 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) return s; } -/* System controller. */ - -typedef struct { - uint32_t base; - uint32_t leds; - uint16_t lockval; - uint32_t cfgdata1; - uint32_t cfgdata2; - uint32_t flags; - uint32_t nvflags; - uint32_t resetlevel; -} vpb_sys_state; - -static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset) -{ - vpb_sys_state *s = (vpb_sys_state *)opaque; - - offset -= s->base; - switch (offset) { - case 0x00: /* ID */ - return 0x41007004; - case 0x04: /* SW */ - /* General purpose hardware switches. - We don't have a useful way of exposing these to the user. */ - return 0; - case 0x08: /* LED */ - return s->leds; - case 0x20: /* LOCK */ - return s->lockval; - case 0x0c: /* OSC0 */ - case 0x10: /* OSC1 */ - case 0x14: /* OSC2 */ - case 0x18: /* OSC3 */ - case 0x1c: /* OSC4 */ - case 0x24: /* 100HZ */ - /* ??? Implement these. */ - return 0; - case 0x28: /* CFGDATA1 */ - return s->cfgdata1; - case 0x2c: /* CFGDATA2 */ - return s->cfgdata2; - case 0x30: /* FLAGS */ - return s->flags; - case 0x38: /* NVFLAGS */ - return s->nvflags; - case 0x40: /* RESETCTL */ - return s->resetlevel; - case 0x44: /* PCICTL */ - return 1; - case 0x48: /* MCI */ - return 0; - case 0x4c: /* FLASH */ - return 0; - case 0x50: /* CLCD */ - return 0x1000; - case 0x54: /* CLCDSER */ - return 0; - case 0x58: /* BOOTCS */ - return 0; - case 0x5c: /* 24MHz */ - /* ??? not implemented. */ - return 0; - case 0x60: /* MISC */ - return 0; - case 0x64: /* DMAPSR0 */ - case 0x68: /* DMAPSR1 */ - case 0x6c: /* DMAPSR2 */ - case 0x8c: /* OSCRESET0 */ - case 0x90: /* OSCRESET1 */ - case 0x94: /* OSCRESET2 */ - case 0x98: /* OSCRESET3 */ - case 0x9c: /* OSCRESET4 */ - case 0xc0: /* SYS_TEST_OSC0 */ - case 0xc4: /* SYS_TEST_OSC1 */ - case 0xc8: /* SYS_TEST_OSC2 */ - case 0xcc: /* SYS_TEST_OSC3 */ - case 0xd0: /* SYS_TEST_OSC4 */ - return 0; - default: - printf ("vpb_sys_read: Bad register offset 0x%x\n", offset); - return 0; - } -} - -static void vpb_sys_write(void *opaque, target_phys_addr_t offset, - uint32_t val) -{ - vpb_sys_state *s = (vpb_sys_state *)opaque; - offset -= s->base; - - switch (offset) { - case 0x08: /* LED */ - s->leds = val; - case 0x0c: /* OSC0 */ - case 0x10: /* OSC1 */ - case 0x14: /* OSC2 */ - case 0x18: /* OSC3 */ - case 0x1c: /* OSC4 */ - /* ??? */ - break; - case 0x20: /* LOCK */ - if (val == LOCK_VALUE) - s->lockval = val; - else - s->lockval = val & 0x7fff; - break; - case 0x28: /* CFGDATA1 */ - /* ??? Need to implement this. */ - s->cfgdata1 = val; - break; - case 0x2c: /* CFGDATA2 */ - /* ??? Need to implement this. */ - s->cfgdata2 = val; - break; - case 0x30: /* FLAGSSET */ - s->flags |= val; - break; - case 0x34: /* FLAGSCLR */ - s->flags &= ~val; - break; - case 0x38: /* NVFLAGSSET */ - s->nvflags |= val; - break; - case 0x3c: /* NVFLAGSCLR */ - s->nvflags &= ~val; - break; - case 0x40: /* RESETCTL */ - if (s->lockval == LOCK_VALUE) { - s->resetlevel = val; - if (val & 0x100) - cpu_abort(cpu_single_env, "Board reset\n"); - } - break; - case 0x44: /* PCICTL */ - /* nothing to do. */ - break; - case 0x4c: /* FLASH */ - case 0x50: /* CLCD */ - case 0x54: /* CLCDSER */ - case 0x64: /* DMAPSR0 */ - case 0x68: /* DMAPSR1 */ - case 0x6c: /* DMAPSR2 */ - case 0x8c: /* OSCRESET0 */ - case 0x90: /* OSCRESET1 */ - case 0x94: /* OSCRESET2 */ - case 0x98: /* OSCRESET3 */ - case 0x9c: /* OSCRESET4 */ - break; - default: - printf ("vpb_sys_write: Bad register offset 0x%x\n", offset); - return; - } -} - -static CPUReadMemoryFunc *vpb_sys_readfn[] = { - vpb_sys_read, - vpb_sys_read, - vpb_sys_read -}; - -static CPUWriteMemoryFunc *vpb_sys_writefn[] = { - vpb_sys_write, - vpb_sys_write, - vpb_sys_write -}; - -static vpb_sys_state *vpb_sys_init(uint32_t base) -{ - vpb_sys_state *s; - int iomemtype; - - s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state)); - if (!s) - return NULL; - s->base = base; - iomemtype = cpu_register_io_memory(0, vpb_sys_readfn, - vpb_sys_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - /* ??? Save/restore. */ - return s; -} - /* Board init. */ /* The AB and PB boards both use the same core, just with different @@ -355,14 +171,14 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); - vpb_sys_init(0x10000000); + arm_sysctl_init(0x10000000, 0x41007004); pic = arm_pic_init_cpu(env); pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); sic = vpb_sic_init(0x10003000, pic, 31); pl050_init(0x10006000, sic, 3, 0); pl050_init(0x10007000, sic, 4, 1); - pci_bus = pci_vpb_init(sic); + pci_bus = pci_vpb_init(sic, 27, 0); /* The Versatile PCI bridge does not provide access to PCI IO space, so many of the qemu PCI devices are not useable. */ for(n = 0; n < nb_nics; n++) { @@ -390,7 +206,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, pl011_init(0x101f3000, pic, 14, serial_hds[2]); pl011_init(0x10009000, sic, 6, serial_hds[3]); - pl080_init(0x10130000, pic, 17); + pl080_init(0x10130000, pic, 17, 8); sp804_init(0x101e2000, pic, 4); sp804_init(0x101e3000, pic, 5); diff --git a/vl.c b/vl.c index d422fedcf..d3efbbd4b 100644 --- a/vl.c +++ b/vl.c @@ -6150,6 +6150,7 @@ void register_machines(void) qemu_register_machine(&integratorcp1026_machine); qemu_register_machine(&versatilepb_machine); qemu_register_machine(&versatileab_machine); + qemu_register_machine(&realview_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); #else diff --git a/vl.h b/vl.h index e16fd9285..fef2ef8c2 100644 --- a/vl.h +++ b/vl.h @@ -778,7 +778,7 @@ PCIBus *pci_pmac_init(void *pic); PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, void *pic); -PCIBus *pci_vpb_init(void *pic); +PCIBus *pci_vpb_init(void *pic, int irq, int realview); /* piix_pci.c */ PCIBus *i440fx_init(void); @@ -1222,6 +1222,9 @@ extern QEMUMachine integratorcp1026_machine; extern QEMUMachine versatilepb_machine; extern QEMUMachine versatileab_machine; +/* realview.c */ +extern QEMUMachine realview_machine; + /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); @@ -1244,7 +1247,7 @@ void pl011_init(uint32_t base, void *pic, int irq, CharDriverState *chr); void pl050_init(uint32_t base, void *pic, int irq, int is_mouse); /* pl080.c */ -void *pl080_init(uint32_t base, void *pic, int irq); +void *pl080_init(uint32_t base, void *pic, int irq, int nchannels); /* pl190.c */ void *pl190_init(uint32_t base, void *parent, int irq, int fiq); @@ -1253,6 +1256,12 @@ void *pl190_init(uint32_t base, void *parent, int irq, int fiq); void sp804_init(uint32_t base, void *pic, int irq); void icp_pit_init(uint32_t base, void *pic, int irq); +/* arm_sysctl.c */ +void arm_sysctl_init(uint32_t base, uint32_t sys_id); + +/* arm_gic.c */ +void *arm_gic_init(uint32_t base, void *parent, int parent_irq); + /* arm_boot.c */ void arm_load_kernel(int ram_size, const char *kernel_filename, -- cgit v1.2.3 From d2b5931756fdb9f839180e33898cd1e3e4fbdc90 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 24 Sep 2006 00:16:34 +0000 Subject: PCI shared IRQ fix (original patch by andrzej zaborowski). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2165 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apb_pci.c | 16 +++++++++--- hw/grackle_pci.c | 14 +++++++---- hw/pci.c | 16 ++++++++++-- hw/piix_pci.c | 72 ++++++++++++++++-------------------------------------- hw/prep_pci.c | 20 +++++++++++---- hw/unin_pci.c | 13 +++++++--- hw/versatile_pci.c | 9 +++++-- vl.h | 10 +++++--- 8 files changed, 95 insertions(+), 75 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 02e9824b3..6fa885e9e 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -179,10 +179,18 @@ static CPUReadMemoryFunc *pci_apb_ioread[] = { &pci_apb_ioreadl, }; -/* ??? This is probably wrong. */ -static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num) { - pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level); + /* ??? As mentioned below this is probably wrong. */ + return irq_num; +} + +static void pci_apb_set_irq(void *pic, int irq_num, int level) +{ + /* ??? This is almost certainly wrong. However the rest of the sun4u + IRQ handling is missing, as is OpenBIOS support, so it wouldn't work + anyway. */ + pic_set_irq_new(pic, irq_num, level); } PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, @@ -194,7 +202,7 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, s = qemu_mallocz(sizeof(APBState)); /* Ultrasparc APB main bus */ - s->bus = pci_register_bus(pci_apb_set_irq, pic, 0); + s->bus = pci_register_bus(pci_apb_set_irq, pci_apb_map_irq, pic, 0); pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, pci_apb_config_write, s); diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index e3cbceb49..8f8e5c063 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -74,11 +74,15 @@ static CPUReadMemoryFunc *pci_grackle_read[] = { &pci_host_data_readl, }; -/* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ -static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +/* Don't know if this matches real hardware, but it agrees with OHW. */ +static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num) { - heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); + return (irq_num + (pci_dev->devfn >> 3)) & 3; +} + +static void pci_grackle_set_irq(void *pic, int irq_num, int level) +{ + heathrow_pic_set_irq(pic, irq_num + 8, level); } PCIBus *pci_grackle_init(uint32_t base, void *pic) @@ -88,7 +92,7 @@ PCIBus *pci_grackle_init(uint32_t base, void *pic) int pci_mem_config, pci_mem_data; s = qemu_mallocz(sizeof(GrackleState)); - s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0); + s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq, pic, 0); pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, pci_grackle_config_write, s); diff --git a/hw/pci.c b/hw/pci.c index 75bd98110..78f05cd90 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -29,11 +29,15 @@ struct PCIBus { int bus_num; int devfn_min; pci_set_irq_fn set_irq; + pci_map_irq_fn map_irq; uint32_t config_reg; /* XXX: suppress */ /* low level pic */ SetIRQFunc *low_set_irq; void *irq_opaque; PCIDevice *devices[256]; + /* The bus IRQ state is the logical OR of the connected devices. + Keep a count of the number of devices with raised IRQs. */ + int irq_count[4]; }; static void pci_update_mappings(PCIDevice *d); @@ -42,13 +46,16 @@ target_phys_addr_t pci_mem_base; static int pci_irq_index; static PCIBus *first_bus; -PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min) +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + void *pic, int devfn_min) { PCIBus *bus; bus = qemu_mallocz(sizeof(PCIBus)); bus->set_irq = set_irq; + bus->map_irq = map_irq; bus->irq_opaque = pic; bus->devfn_min = devfn_min; + memset(bus->irq_count, 0, sizeof(bus->irq_count)); first_bus = bus; return bus; } @@ -100,6 +107,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, pci_dev->bus = bus; pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); + memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state)); if (!config_read) config_read = pci_default_read_config; @@ -404,7 +412,11 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len) void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) { PCIBus *bus = pci_dev->bus; - bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level); + + irq_num = bus->map_irq(pci_dev, irq_num); + bus->irq_count[irq_num] += level - pci_dev->irq_state[irq_num]; + pci_dev->irq_state[irq_num] = level; + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); } /***********************************************************/ diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 672b736ad..939521c7b 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -40,7 +40,17 @@ static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr) return s->config_reg; } -static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level); +static void piix3_set_irq(void *pic, int irq_num, int level); + +/* return the global irq number corresponding to a given device irq + pin. We could also use the bus number to have a more precise + mapping. */ +static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + int slot_addend; + slot_addend = (pci_dev->devfn >> 3) - 1; + return (irq_num + slot_addend) & 3; +} PCIBus *i440fx_init(void) { @@ -49,7 +59,7 @@ PCIBus *i440fx_init(void) I440FXState *s; s = qemu_mallocz(sizeof(I440FXState)); - b = pci_register_bus(piix3_set_irq, NULL, 0); + b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0); s->bus = b; register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); @@ -83,65 +93,25 @@ static PCIDevice *piix3_dev; /* just used for simpler irq handling. */ #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) -static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; - -/* return the global irq number corresponding to a given device irq - pin. We could also use the bus number to have a more precise - mapping. */ -static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) -{ - int slot_addend; - slot_addend = (pci_dev->devfn >> 3) - 1; - return (irq_num + slot_addend) & 3; -} - -static inline int get_pci_irq_level(int irq_num) -{ - int pic_level; -#if (PCI_IRQ_WORDS == 2) - pic_level = ((pci_irq_levels[irq_num][0] | - pci_irq_levels[irq_num][1]) != 0); -#else - { - int i; - pic_level = 0; - for(i = 0; i < PCI_IRQ_WORDS; i++) { - if (pci_irq_levels[irq_num][i]) { - pic_level = 1; - break; - } - } - } -#endif - return pic_level; -} +static int pci_irq_levels[4]; -static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level) +static void piix3_set_irq(void *pic, int irq_num, int level) { - int irq_index, shift, pic_irq, pic_level; - uint32_t *p; + int i, pic_irq, pic_level; - irq_num = pci_slot_get_pirq(pci_dev, irq_num); - irq_index = pci_dev->irq_index; - p = &pci_irq_levels[irq_num][irq_index >> 5]; - shift = (irq_index & 0x1f); - *p = (*p & ~(1 << shift)) | (level << shift); + pci_irq_levels[irq_num] = level; /* now we change the pic irq level according to the piix irq mappings */ /* XXX: optimize */ pic_irq = piix3_dev->config[0x60 + irq_num]; if (pic_irq < 16) { - /* the pic level is the logical OR of all the PCI irqs mapped + /* The pic level is the logical OR of all the PCI irqs mapped to it */ pic_level = 0; - if (pic_irq == piix3_dev->config[0x60]) - pic_level |= get_pci_irq_level(0); - if (pic_irq == piix3_dev->config[0x61]) - pic_level |= get_pci_irq_level(1); - if (pic_irq == piix3_dev->config[0x62]) - pic_level |= get_pci_irq_level(2); - if (pic_irq == piix3_dev->config[0x63]) - pic_level |= get_pci_irq_level(3); + for (i = 0; i < 4; i++) { + if (pic_irq == piix3_dev->config[0x60 + i]) + pic_level |= pci_irq_levels[i]; + } pic_set_irq(pic_irq, pic_level); } } diff --git a/hw/prep_pci.c b/hw/prep_pci.c index a31b74c80..b5ff8eb0f 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -117,11 +117,21 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = { &PPC_PCIIO_readl, }; -static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +/* Don't know if this matches real hardware, but it agrees with OHW. */ +static int prep_map_irq(PCIDevice *pci_dev, int irq_num) { - /* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ - pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); + return (irq_num + (pci_dev->devfn >> 3)) & 3; +} + +static int prep_irq_levels[4]; + +static void prep_set_irq(void *pic, int irq_num, int level) +{ + int pic_irq_num; + prep_irq_levels[irq_num] = level; + level |= prep_irq_levels[irq_num ^ 2]; + pic_irq_num = (irq_num == 0 || irq_num == 2) ? 9 : 11; + pic_set_irq(pic_irq_num, level); } PCIBus *pci_prep_init(void) @@ -131,7 +141,7 @@ PCIBus *pci_prep_init(void) int PPC_io_memory; s = qemu_mallocz(sizeof(PREPPCIState)); - s->bus = pci_register_bus(prep_set_irq, NULL, 0); + s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0); register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); diff --git a/hw/unin_pci.c b/hw/unin_pci.c index a7e360004..d132d6ec2 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -140,9 +140,15 @@ static CPUReadMemoryFunc *pci_unin_read[] = { }; #endif -static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +/* Don't know if this matches real hardware, but it agrees with OHW. */ +static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num) { - openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); + return (irq_num + (pci_dev->devfn >> 3)) & 3; +} + +static void pci_unin_set_irq(void *pic, int irq_num, int level) +{ + openpic_set_irq(pic, irq_num + 8, level); } PCIBus *pci_pmac_init(void *pic) @@ -154,7 +160,8 @@ PCIBus *pci_pmac_init(void *pic) /* Use values found on a real PowerMac */ /* Uninorth main bus */ s = qemu_mallocz(sizeof(UNINState)); - s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3); + s->bus = pci_register_bus(pci_unin_set_irq, pci_unin_map_irq, + pic, 11 << 3); pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, pci_unin_main_config_write, s); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index aac61c7b5..9addda8f0 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -79,7 +79,12 @@ static CPUReadMemoryFunc *pci_vpb_config_read[] = { static int pci_vpb_irq; -static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) +static int pci_vpb_map_irq(PCIDevice *d, int irq_num) +{ + return irq_num; +} + +static void pci_vpb_set_irq(void *pic, int irq_num, int level) { pic_set_irq_new(pic, pci_vpb_irq + irq_num, level); } @@ -100,7 +105,7 @@ PCIBus *pci_vpb_init(void *pic, int irq, int realview) base = 0x40000000; name = "Versatile/PB PCI Controller"; } - s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3); + s = pci_register_bus(pci_vpb_set_irq, pci_vpb_map_irq, pic, 11 << 3); /* ??? Register memory space. */ mem_config = cpu_register_io_memory(0, pci_vpb_config_read, diff --git a/vl.h b/vl.h index fef2ef8c2..3f654f2f4 100644 --- a/vl.h +++ b/vl.h @@ -733,6 +733,9 @@ struct PCIDevice { PCIConfigWriteFunc *config_write; /* ??? This is a PC-specific hack, and should be removed. */ int irq_index; + + /* Current IRQ levels. Used internally by the generic PCI code. */ + int irq_state[4]; }; PCIDevice *pci_register_device(PCIBus *bus, const char *name, @@ -753,9 +756,10 @@ void pci_default_write_config(PCIDevice *d, void pci_device_save(PCIDevice *s, QEMUFile *f); int pci_device_load(PCIDevice *s, QEMUFile *f); -typedef void (*pci_set_irq_fn)(PCIDevice *pci_dev, void *pic, - int irq_num, int level); -PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min); +typedef void (*pci_set_irq_fn)(void *pic, int irq_num, int level); +typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + void *pic, int devfn_min); void pci_nic_init(PCIBus *bus, NICInfo *nd); void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); -- cgit v1.2.3 From 80b3ada7dd56088613a446934d144a747e740fa1 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 24 Sep 2006 17:01:44 +0000 Subject: Implement sun4u PCI IRQ routing. Allow multiple PCI busses and PCI-PCI bridges. Fix bugs in Versatile PCI implementation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2166 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apb_pci.c | 37 ++++++++++++++----- hw/grackle_pci.c | 3 +- hw/pci.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++------ hw/piix_pci.c | 14 ++++++-- hw/prep_pci.c | 12 ++----- hw/unin_pci.c | 2 +- hw/versatile_pci.c | 8 ++--- vl.h | 6 ++-- 8 files changed, 146 insertions(+), 39 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 6fa885e9e..3ebe3207f 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -21,6 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + +/* XXX This file and most of its contests are somewhat misnamed. The + Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is + the secondary PCI bridge. */ + #include "vl.h" typedef target_phys_addr_t pci_addr_t; #include "pci_host.h" @@ -179,17 +184,25 @@ static CPUReadMemoryFunc *pci_apb_ioread[] = { &pci_apb_ioreadl, }; +/* The APB host has an IRQ line for each IRQ line of each slot. */ static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num) { - /* ??? As mentioned below this is probably wrong. */ - return irq_num; + return ((pci_dev->devfn & 0x18) >> 1) + irq_num; +} + +static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num) +{ + int bus_offset; + if (pci_dev->devfn & 1) + bus_offset = 16; + else + bus_offset = 0; + return bus_offset + irq_num; } static void pci_apb_set_irq(void *pic, int irq_num, int level) { - /* ??? This is almost certainly wrong. However the rest of the sun4u - IRQ handling is missing, as is OpenBIOS support, so it wouldn't work - anyway. */ + /* PCI IRQ map onto the first 32 INO. */ pic_set_irq_new(pic, irq_num, level); } @@ -199,10 +212,12 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, APBState *s; PCIDevice *d; int pci_mem_config, pci_mem_data, apb_config, pci_ioport; + PCIDevice *apb; + PCIBus *secondary; s = qemu_mallocz(sizeof(APBState)); - /* Ultrasparc APB main bus */ - s->bus = pci_register_bus(pci_apb_set_irq, pci_apb_map_irq, pic, 0); + /* Ultrasparc PBM main bus */ + s->bus = pci_register_bus(pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32); pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, pci_apb_config_write, s); @@ -219,7 +234,7 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice), - -1, NULL, NULL); + 0, NULL, NULL); d->config[0x00] = 0x8e; // vendor_id : Sun d->config[0x01] = 0x10; d->config[0x02] = 0x00; // device_id @@ -234,7 +249,11 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, d->config[0x0B] = 0x06; // class_base = PCI_bridge d->config[0x0D] = 0x10; // latency_timer d->config[0x0E] = 0x00; // header_type - return s->bus; + + /* APB secondary busses */ + secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq); + pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq); + return secondary; } diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 8f8e5c063..4004f9942 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -92,7 +92,8 @@ PCIBus *pci_grackle_init(uint32_t base, void *pic) int pci_mem_config, pci_mem_data; s = qemu_mallocz(sizeof(GrackleState)); - s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq, pic, 0); + s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq, + pic, 0, 0); pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, pci_grackle_config_write, s); diff --git a/hw/pci.c b/hw/pci.c index 78f05cd90..7c9db0e8d 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -35,9 +35,11 @@ struct PCIBus { SetIRQFunc *low_set_irq; void *irq_opaque; PCIDevice *devices[256]; + PCIDevice *parent_dev; + PCIBus *next; /* The bus IRQ state is the logical OR of the connected devices. Keep a count of the number of devices with raised IRQs. */ - int irq_count[4]; + int irq_count[]; }; static void pci_update_mappings(PCIDevice *d); @@ -47,19 +49,29 @@ static int pci_irq_index; static PCIBus *first_bus; PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *pic, int devfn_min) + void *pic, int devfn_min, int nirq) { PCIBus *bus; - bus = qemu_mallocz(sizeof(PCIBus)); + bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int))); bus->set_irq = set_irq; bus->map_irq = map_irq; bus->irq_opaque = pic; bus->devfn_min = devfn_min; - memset(bus->irq_count, 0, sizeof(bus->irq_count)); first_bus = bus; return bus; } +PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq) +{ + PCIBus *bus; + bus = qemu_mallocz(sizeof(PCIBus)); + bus->map_irq = map_irq; + bus->parent_dev = dev; + bus->next = dev->bus->next; + dev->bus->next = bus; + return bus; +} + int pci_bus_num(PCIBus *s) { return s->bus_num; @@ -351,7 +363,9 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) addr, val, len); #endif bus_num = (addr >> 16) & 0xff; - if (bus_num != 0) + while (s && s->bus_num != bus_num) + s = s->next; + if (!s) return; pci_dev = s->devices[(addr >> 8) & 0xff]; if (!pci_dev) @@ -372,7 +386,9 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len) uint32_t val; bus_num = (addr >> 16) & 0xff; - if (bus_num != 0) + while (s && s->bus_num != bus_num) + s= s->next; + if (!s) goto fail; pci_dev = s->devices[(addr >> 8) & 0xff]; if (!pci_dev) { @@ -411,11 +427,21 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len) /* 0 <= irq_num <= 3. level must be 0 or 1 */ void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) { - PCIBus *bus = pci_dev->bus; + PCIBus *bus; + int change; + + change = level - pci_dev->irq_state[irq_num]; + if (!change) + return; - irq_num = bus->map_irq(pci_dev, irq_num); - bus->irq_count[irq_num] += level - pci_dev->irq_state[irq_num]; pci_dev->irq_state[irq_num] = level; + bus = pci_dev->bus; + while (!bus->set_irq) { + irq_num = bus->map_irq(pci_dev, irq_num); + pci_dev = bus->parent_dev; + bus = pci_dev->bus; + } + bus->irq_count[irq_num] += change; bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); } @@ -465,6 +491,9 @@ static void pci_info_device(PCIDevice *d) if (d->config[PCI_INTERRUPT_PIN] != 0) { term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); } + if (class == 0x0604) { + term_printf(" BUS %d.\n", d->config[0x19]); + } for(i = 0;i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; if (r->size != 0) { @@ -478,14 +507,19 @@ static void pci_info_device(PCIDevice *d) } } } + if (class == 0x0604 && d->config[0x19] != 0) { + pci_for_each_device(d->config[0x19], pci_info_device); + } } -void pci_for_each_device(void (*fn)(PCIDevice *d)) +void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d)) { PCIBus *bus = first_bus; PCIDevice *d; int devfn; + while (bus && bus->bus_num != bus_num) + bus = bus->next; if (bus) { for(devfn = 0; devfn < 256; devfn++) { d = bus->devices[devfn]; @@ -497,7 +531,7 @@ void pci_for_each_device(void (*fn)(PCIDevice *d)) void pci_info(void) { - pci_for_each_device(pci_info_device); + pci_for_each_device(0, pci_info_device); } /* Initialize a PCI NIC. */ @@ -515,3 +549,50 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd) } } +typedef struct { + PCIDevice dev; + PCIBus *bus; +} PCIBridge; + +void pci_bridge_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + PCIBridge *s = (PCIBridge *)d; + + if (address == 0x19 || (address == 0x18 && len > 1)) { + if (address == 0x19) + s->bus->bus_num = val & 0xff; + else + s->bus->bus_num = (val >> 8) & 0xff; +#if defined(DEBUG_PCI) + printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num); +#endif + } + pci_default_write_config(d, address, val, len); +} + +PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, + pci_map_irq_fn map_irq, const char *name) +{ + PCIBridge *s; + s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge), + devfn, NULL, pci_bridge_write_config); + s->dev.config[0x00] = id >> 16; + s->dev.config[0x01] = id > 24; + s->dev.config[0x02] = id; // device_id + s->dev.config[0x03] = id >> 8; + s->dev.config[0x04] = 0x06; // command = bus master, pci mem + s->dev.config[0x05] = 0x00; + s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error + s->dev.config[0x07] = 0x00; // status = fast devsel + s->dev.config[0x08] = 0x00; // revision + s->dev.config[0x09] = 0x00; // programming i/f + s->dev.config[0x0A] = 0x04; // class_sub = PCI to PCI bridge + s->dev.config[0x0B] = 0x06; // class_base = PCI_bridge + s->dev.config[0x0D] = 0x10; // latency_timer + s->dev.config[0x0E] = 0x81; // header_type + s->dev.config[0x1E] = 0xa0; // secondary status + + s->bus = pci_register_secondary_bus(&s->dev, map_irq); + return s->bus; +} diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 939521c7b..d618f0062 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -59,7 +59,7 @@ PCIBus *i440fx_init(void) I440FXState *s; s = qemu_mallocz(sizeof(I440FXState)); - b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0); + b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0, 4); s->bus = b; register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); @@ -226,6 +226,7 @@ static uint32_t pci_bios_io_addr; static uint32_t pci_bios_mem_addr; /* host irqs corresponding to PCI irqs A-D */ static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; +static int pci_bios_next_bus; static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) { @@ -320,6 +321,14 @@ static void pci_bios_init_device(PCIDevice *d) pci_set_io_region_addr(d, 3, 0x374); } break; + case 0x0604: + /* PCI to PCI bridge. Assign bus ID and recurse to configure + devices on the secondary bus. */ + i = pci_bios_next_bus++; + pci_config_writeb(d, 0x18, pci_bus_num(d->bus)); + pci_config_writeb(d, 0x19, i); + pci_for_each_device(i, pci_bios_init_device); + break; case 0x0300: if (vendor_id != 0x1234) goto default_map; @@ -398,6 +407,7 @@ void pci_bios_init(void) isa_outb(elcr[0], 0x4d0); isa_outb(elcr[1], 0x4d1); - pci_for_each_device(pci_bios_init_device); + pci_bios_next_bus = 1; + pci_for_each_device(0, pci_bios_init_device); } diff --git a/hw/prep_pci.c b/hw/prep_pci.c index b5ff8eb0f..3d93c065f 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -120,18 +120,12 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = { /* Don't know if this matches real hardware, but it agrees with OHW. */ static int prep_map_irq(PCIDevice *pci_dev, int irq_num) { - return (irq_num + (pci_dev->devfn >> 3)) & 3; + return (irq_num + (pci_dev->devfn >> 3)) & 1; } -static int prep_irq_levels[4]; - static void prep_set_irq(void *pic, int irq_num, int level) { - int pic_irq_num; - prep_irq_levels[irq_num] = level; - level |= prep_irq_levels[irq_num ^ 2]; - pic_irq_num = (irq_num == 0 || irq_num == 2) ? 9 : 11; - pic_set_irq(pic_irq_num, level); + pic_set_irq(irq_num ? 11 : 9, level); } PCIBus *pci_prep_init(void) @@ -141,7 +135,7 @@ PCIBus *pci_prep_init(void) int PPC_io_memory; s = qemu_mallocz(sizeof(PREPPCIState)); - s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0); + s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0, 2); register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); diff --git a/hw/unin_pci.c b/hw/unin_pci.c index d132d6ec2..e47f4b3ac 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -161,7 +161,7 @@ PCIBus *pci_pmac_init(void *pic) /* Uninorth main bus */ s = qemu_mallocz(sizeof(UNINState)); s->bus = pci_register_bus(pci_unin_set_irq, pci_unin_map_irq, - pic, 11 << 3); + pic, 11 << 3, 4); pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, pci_unin_main_config_write, s); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 9addda8f0..32854c2f9 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -11,7 +11,7 @@ static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr) { - return addr & 0xf8ff; + return addr & 0xffffff; } static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr, @@ -105,15 +105,15 @@ PCIBus *pci_vpb_init(void *pic, int irq, int realview) base = 0x40000000; name = "Versatile/PB PCI Controller"; } - s = pci_register_bus(pci_vpb_set_irq, pci_vpb_map_irq, pic, 11 << 3); + s = pci_register_bus(pci_vpb_set_irq, pci_vpb_map_irq, pic, 11 << 3, 4); /* ??? Register memory space. */ mem_config = cpu_register_io_memory(0, pci_vpb_config_read, pci_vpb_config_write, s); /* Selfconfig area. */ - cpu_register_physical_memory(base + 0x01000000, 0x10000, mem_config); + cpu_register_physical_memory(base + 0x01000000, 0x1000000, mem_config); /* Normal config area. */ - cpu_register_physical_memory(base + 0x02000000, 0x10000, mem_config); + cpu_register_physical_memory(base + 0x02000000, 0x1000000, mem_config); d = pci_register_device(s, name, sizeof(PCIDevice), -1, NULL, NULL); diff --git a/vl.h b/vl.h index 3f654f2f4..124e7d776 100644 --- a/vl.h +++ b/vl.h @@ -759,15 +759,17 @@ int pci_device_load(PCIDevice *s, QEMUFile *f); typedef void (*pci_set_irq_fn)(void *pic, int irq_num, int level); typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *pic, int devfn_min); + void *pic, int devfn_min, int nirq); void pci_nic_init(PCIBus *bus, NICInfo *nd); void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); uint32_t pci_data_read(void *opaque, uint32_t addr, int len); int pci_bus_num(PCIBus *s); -void pci_for_each_device(void (*fn)(PCIDevice *d)); +void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d)); void pci_info(void); +PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, + pci_map_irq_fn map_irq, const char *name); /* prep_pci.c */ PCIBus *pci_prep_init(void); -- cgit v1.2.3 From d4afc623ae3ca529ff16cc2cf5de9293310de3e6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:38:12 +0000 Subject: moved PCI, MP and ACPI init to bios git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2167 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 65536 -> 131072 bytes pc-bios/bios.diff | 3050 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 2826 insertions(+), 224 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 64be517b2..051fdbb14 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index e87592784..e70499017 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,270 +1,2872 @@ -Index: apmbios.S -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/apmbios.S,v -retrieving revision 1.4 -diff -u -w -r1.4 apmbios.S ---- apmbios.S 26 Dec 2005 10:35:51 -0000 1.4 -+++ apmbios.S 3 May 2006 21:22:46 -0000 -@@ -225,6 +225,7 @@ - APMSYM(05): - cmp al, #0x05 - jne APMSYM(07) -+ sti - hlt - jmp APMSYM(ok) +diff -ruN --exclude Makefile bios/acpi-dsdt.dsl bios.new/acpi-dsdt.dsl +--- bios/acpi-dsdt.dsl 1970-01-01 01:00:00.000000000 +0100 ++++ bios.new/acpi-dsdt.dsl 2006-09-24 20:27:54.000000000 +0200 +@@ -0,0 +1,559 @@ ++/* ++ * QEMU ACPI DSDT ASL definition ++ * ++ * Copyright (c) 2006 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 version 2 as published by the Free Software Foundation. ++ * ++ * 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 ++ */ ++DefinitionBlock ( ++ "acpi-dsdt.aml", // Output Filename ++ "DSDT", // Signature ++ 0x01, // DSDT Compliance Revision ++ "QEMU", // OEMID ++ "QEMUDSDT", // TABLE ID ++ 0x1 // OEM Revision ++ ) ++{ ++ Scope (\) ++ { ++ /* CMOS memory access */ ++ OperationRegion (CMS, SystemIO, 0x70, 0x02) ++ Field (CMS, ByteAcc, NoLock, Preserve) ++ { ++ CMSI, 8, ++ CMSD, 8 ++ } ++ Method (CMRD, 1, NotSerialized) ++ { ++ Store (Arg0, CMSI) ++ Store (CMSD, Local0) ++ Return (Local0) ++ } ++ ++ /* Debug Output */ ++ OperationRegion (DBG, SystemIO, 0xb044, 0x04) ++ Field (DBG, DWordAcc, NoLock, Preserve) ++ { ++ DBGL, 32, ++ } ++ } ++ ++ ++ /* PCI Bus definition */ ++ Scope(\_SB) { ++ Device(PCI0) { ++ Name (_HID, EisaId ("PNP0A03")) ++ Name (_ADR, 0x00) ++ Name (_UID, 1) ++ Name(_PRT, Package() { ++ /* PCI IRQ routing table, example from ACPI 2.0a specification, ++ section 6.2.8.1 */ ++ /* Note: we provide the same info as the PCI routing ++ table of the Bochs BIOS */ ++ ++ // PCI Slot 0 ++ Package() {0x0000ffff, 0, LNKD, 0}, ++ Package() {0x0000ffff, 1, LNKA, 0}, ++ Package() {0x0000ffff, 2, LNKB, 0}, ++ Package() {0x0000ffff, 3, LNKC, 0}, ++ ++ // PCI Slot 1 ++ Package() {0x0001ffff, 0, LNKA, 0}, ++ Package() {0x0001ffff, 1, LNKB, 0}, ++ Package() {0x0001ffff, 2, LNKC, 0}, ++ Package() {0x0001ffff, 3, LNKD, 0}, ++ ++ // PCI Slot 2 ++ Package() {0x0002ffff, 0, LNKB, 0}, ++ Package() {0x0002ffff, 1, LNKC, 0}, ++ Package() {0x0002ffff, 2, LNKD, 0}, ++ Package() {0x0002ffff, 3, LNKA, 0}, ++ ++ // PCI Slot 3 ++ Package() {0x0003ffff, 0, LNKC, 0}, ++ Package() {0x0003ffff, 1, LNKD, 0}, ++ Package() {0x0003ffff, 2, LNKA, 0}, ++ Package() {0x0003ffff, 3, LNKB, 0}, ++ ++ // PCI Slot 4 ++ Package() {0x0004ffff, 0, LNKD, 0}, ++ Package() {0x0004ffff, 1, LNKA, 0}, ++ Package() {0x0004ffff, 2, LNKB, 0}, ++ Package() {0x0004ffff, 3, LNKC, 0}, ++ ++ // PCI Slot 5 ++ Package() {0x0005ffff, 0, LNKA, 0}, ++ Package() {0x0005ffff, 1, LNKB, 0}, ++ Package() {0x0005ffff, 2, LNKC, 0}, ++ Package() {0x0005ffff, 3, LNKD, 0}, ++ }) ++ ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (MEMP, ResourceTemplate () ++ { ++ WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, ++ 0x0000, // Address Space Granularity ++ 0x0000, // Address Range Minimum ++ 0x00FF, // Address Range Maximum ++ 0x0000, // Address Translation Offset ++ 0x0100, // Address Length ++ ,, ) ++ IO (Decode16, ++ 0x0CF8, // Address Range Minimum ++ 0x0CF8, // Address Range Maximum ++ 0x01, // Address Alignment ++ 0x08, // Address Length ++ ) ++ WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, ++ 0x0000, // Address Space Granularity ++ 0x0000, // Address Range Minimum ++ 0x0CF7, // Address Range Maximum ++ 0x0000, // Address Translation Offset ++ 0x0CF8, // Address Length ++ ,, , TypeStatic) ++ WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, ++ 0x0000, // Address Space Granularity ++ 0x0D00, // Address Range Minimum ++ 0xFFFF, // Address Range Maximum ++ 0x0000, // Address Translation Offset ++ 0xF300, // Address Length ++ ,, , TypeStatic) ++ DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, ++ 0x00000000, // Address Space Granularity ++ 0x000A0000, // Address Range Minimum ++ 0x000BFFFF, // Address Range Maximum ++ 0x00000000, // Address Translation Offset ++ 0x00020000, // Address Length ++ ,, , AddressRangeMemory, TypeStatic) ++ DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite, ++ 0x00000000, // Address Space Granularity ++ 0x00000000, // Address Range Minimum ++ 0xFEBFFFFF, // Address Range Maximum ++ 0x00000000, // Address Translation Offset ++ 0x00000000, // Address Length ++ ,, MEMF, AddressRangeMemory, TypeStatic) ++ }) ++ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN) ++ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX) ++ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN) ++ /* compute available RAM */ ++ Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0) ++ ShiftLeft(Local0, 16, Local0) ++ Add(Local0, 0x1000000, Local0) ++ /* update field of last region */ ++ Store(Local0, PMIN) ++ Subtract (PMAX, PMIN, PLEN) ++ Increment (PLEN) ++ Return (MEMP) ++ } ++ } ++ } ++ ++ Scope(\_SB.PCI0) { ++ ++ /* PIIX3 ISA bridge */ ++ Device (ISA) { ++ Name (_ADR, 0x00010000) ++ ++ /* PIIX PCI to ISA irq remapping */ ++ OperationRegion (P40C, PCI_Config, 0x60, 0x04) ++ ++ ++ /* Keyboard seems to be important for WinXP install */ ++ Device (KBD) ++ { ++ Name (_HID, EisaId ("PNP0303")) ++ Method (_STA, 0, NotSerialized) ++ { ++ Return (0x0f) ++ } ++ ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (TMP, ResourceTemplate () ++ { ++ IO (Decode16, ++ 0x0060, // Address Range Minimum ++ 0x0060, // Address Range Maximum ++ 0x01, // Address Alignment ++ 0x01, // Address Length ++ ) ++ IO (Decode16, ++ 0x0064, // Address Range Minimum ++ 0x0064, // Address Range Maximum ++ 0x01, // Address Alignment ++ 0x01, // Address Length ++ ) ++ IRQNoFlags () ++ {1} ++ }) ++ Return (TMP) ++ } ++ } ++ ++ /* PS/2 mouse */ ++ Device (MOU) ++ { ++ Name (_HID, EisaId ("PNP0F13")) ++ Method (_STA, 0, NotSerialized) ++ { ++ Return (0x0f) ++ } ++ ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (TMP, ResourceTemplate () ++ { ++ IRQNoFlags () {12} ++ }) ++ Return (TMP) ++ } ++ } ++ ++ /* PS/2 floppy controller */ ++ Device (FDC0) ++ { ++ Name (_HID, EisaId ("PNP0700")) ++ Method (_STA, 0, NotSerialized) ++ { ++ Return (0x0F) ++ } ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (BUF0, ResourceTemplate () ++ { ++ IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04) ++ IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01) ++ IRQNoFlags () {6} ++ DMA (Compatibility, NotBusMaster, Transfer8) {2} ++ }) ++ Return (BUF0) ++ } ++ } ++ ++ /* Parallel port */ ++ Device (LPT) ++ { ++ Name (_HID, EisaId ("PNP0400")) ++ Method (_STA, 0, NotSerialized) ++ { ++ Store (\_SB.PCI0.PX13.DRSA, Local0) ++ And (Local0, 0x80000000, Local0) ++ If (LEqual (Local0, 0)) ++ { ++ Return (0x00) ++ } ++ Else ++ { ++ Return (0x0F) ++ } ++ } ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (BUF0, ResourceTemplate () ++ { ++ IO (Decode16, 0x0378, 0x0378, 0x08, 0x08) ++ IRQNoFlags () {7} ++ }) ++ Return (BUF0) ++ } ++ } ++ ++ /* Serial Ports */ ++ Device (COM1) ++ { ++ Name (_HID, EisaId ("PNP0501")) ++ Name (_UID, 0x01) ++ Method (_STA, 0, NotSerialized) ++ { ++ Store (\_SB.PCI0.PX13.DRSC, Local0) ++ And (Local0, 0x08000000, Local0) ++ If (LEqual (Local0, 0)) ++ { ++ Return (0x00) ++ } ++ Else ++ { ++ Return (0x0F) ++ } ++ } ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (BUF0, ResourceTemplate () ++ { ++ IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08) ++ IRQNoFlags () {4} ++ }) ++ Return (BUF0) ++ } ++ } ++ ++ Device (COM2) ++ { ++ Name (_HID, EisaId ("PNP0501")) ++ Name (_UID, 0x02) ++ Method (_STA, 0, NotSerialized) ++ { ++ Store (\_SB.PCI0.PX13.DRSC, Local0) ++ And (Local0, 0x80000000, Local0) ++ If (LEqual (Local0, 0)) ++ { ++ Return (0x00) ++ } ++ Else ++ { ++ Return (0x0F) ++ } ++ } ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (BUF0, ResourceTemplate () ++ { ++ IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08) ++ IRQNoFlags () {3} ++ }) ++ Return (BUF0) ++ } ++ } ++ } ++ ++ /* PIIX4 PM */ ++ Device (PX13) { ++ Name (_ADR, 0x00010003) ++ ++ OperationRegion (P13C, PCI_Config, 0x5c, 0x24) ++ Field (P13C, DWordAcc, NoLock, Preserve) ++ { ++ DRSA, 32, ++ DRSB, 32, ++ DRSC, 32, ++ DRSE, 32, ++ DRSF, 32, ++ DRSG, 32, ++ DRSH, 32, ++ DRSI, 32, ++ DRSJ, 32 ++ } ++ } ++ } ++ ++ /* PCI IRQs */ ++ Scope(\_SB) { ++ Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) ++ { ++ PRQ0, 8, ++ PRQ1, 8, ++ PRQ2, 8, ++ PRQ3, 8 ++ } ++ ++ Device(LNKA){ ++ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link ++ Name(_UID, 1) ++ Name(_PRS, ResourceTemplate(){ ++ IRQ (Level, ActiveLow, Shared) ++ {3,4,5,6,7,9,10,11,12} ++ }) ++ Method (_STA, 0, NotSerialized) ++ { ++ Store (0x0B, Local0) ++ If (And (0x80, PRQ0, Local1)) ++ { ++ Store (0x09, Local0) ++ } ++ Return (Local0) ++ } ++ Method (_DIS, 0, NotSerialized) ++ { ++ Or (PRQ0, 0x80, PRQ0) ++ } ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (PRR0, ResourceTemplate () ++ { ++ IRQ (Level, ActiveLow, Shared) ++ {1} ++ }) ++ CreateWordField (PRR0, 0x01, TMP) ++ Store (PRQ0, Local0) ++ If (LLess (Local0, 0x80)) ++ { ++ ShiftLeft (One, Local0, TMP) ++ } ++ Else ++ { ++ Store (Zero, TMP) ++ } ++ Return (PRR0) ++ } ++ Method (_SRS, 1, NotSerialized) ++ { ++ CreateWordField (Arg0, 0x01, TMP) ++ FindSetRightBit (TMP, Local0) ++ Decrement (Local0) ++ Store (Local0, PRQ0) ++ } ++ } ++ Device(LNKB){ ++ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link ++ Name(_UID, 2) ++ Name(_PRS, ResourceTemplate(){ ++ IRQ (Level, ActiveLow, Shared) ++ {3,4,5,6,7,9,10,11,12} ++ }) ++ Method (_STA, 0, NotSerialized) ++ { ++ Store (0x0B, Local0) ++ If (And (0x80, PRQ1, Local1)) ++ { ++ Store (0x09, Local0) ++ } ++ Return (Local0) ++ } ++ Method (_DIS, 0, NotSerialized) ++ { ++ Or (PRQ1, 0x80, PRQ1) ++ } ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (PRR0, ResourceTemplate () ++ { ++ IRQ (Level, ActiveLow, Shared) ++ {1} ++ }) ++ CreateWordField (PRR0, 0x01, TMP) ++ Store (PRQ1, Local0) ++ If (LLess (Local0, 0x80)) ++ { ++ ShiftLeft (One, Local0, TMP) ++ } ++ Else ++ { ++ Store (Zero, TMP) ++ } ++ Return (PRR0) ++ } ++ Method (_SRS, 1, NotSerialized) ++ { ++ CreateWordField (Arg0, 0x01, TMP) ++ FindSetRightBit (TMP, Local0) ++ Decrement (Local0) ++ Store (Local0, PRQ1) ++ } ++ } ++ Device(LNKC){ ++ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link ++ Name(_UID, 3) ++ Name(_PRS, ResourceTemplate(){ ++ IRQ (Level, ActiveLow, Shared) ++ {3,4,5,6,7,9,10,11,12} ++ }) ++ Method (_STA, 0, NotSerialized) ++ { ++ Store (0x0B, Local0) ++ If (And (0x80, PRQ2, Local1)) ++ { ++ Store (0x09, Local0) ++ } ++ Return (Local0) ++ } ++ Method (_DIS, 0, NotSerialized) ++ { ++ Or (PRQ2, 0x80, PRQ2) ++ } ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (PRR0, ResourceTemplate () ++ { ++ IRQ (Level, ActiveLow, Shared) ++ {1} ++ }) ++ CreateWordField (PRR0, 0x01, TMP) ++ Store (PRQ2, Local0) ++ If (LLess (Local0, 0x80)) ++ { ++ ShiftLeft (One, Local0, TMP) ++ } ++ Else ++ { ++ Store (Zero, TMP) ++ } ++ Return (PRR0) ++ } ++ Method (_SRS, 1, NotSerialized) ++ { ++ CreateWordField (Arg0, 0x01, TMP) ++ FindSetRightBit (TMP, Local0) ++ Decrement (Local0) ++ Store (Local0, PRQ2) ++ } ++ } ++ Device(LNKD){ ++ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link ++ Name(_UID, 4) ++ Name(_PRS, ResourceTemplate(){ ++ IRQ (Level, ActiveLow, Shared) ++ {3,4,5,6,7,9,10,11,12} ++ }) ++ Method (_STA, 0, NotSerialized) ++ { ++ Store (0x0B, Local0) ++ If (And (0x80, PRQ3, Local1)) ++ { ++ Store (0x09, Local0) ++ } ++ Return (Local0) ++ } ++ Method (_DIS, 0, NotSerialized) ++ { ++ Or (PRQ3, 0x80, PRQ3) ++ } ++ Method (_CRS, 0, NotSerialized) ++ { ++ Name (PRR0, ResourceTemplate () ++ { ++ IRQ (Level, ActiveLow, Shared) ++ {1} ++ }) ++ CreateWordField (PRR0, 0x01, TMP) ++ Store (PRQ3, Local0) ++ If (LLess (Local0, 0x80)) ++ { ++ ShiftLeft (One, Local0, TMP) ++ } ++ Else ++ { ++ Store (Zero, TMP) ++ } ++ Return (PRR0) ++ } ++ Method (_SRS, 1, NotSerialized) ++ { ++ CreateWordField (Arg0, 0x01, TMP) ++ FindSetRightBit (TMP, Local0) ++ Decrement (Local0) ++ Store (Local0, PRQ3) ++ } ++ } ++ } ++ ++ /* S5 = power off state */ ++ Name (_S5, Package (4) { ++ 0x00, // PM1a_CNT.SLP_TYP ++ 0x00, // PM2a_CNT.SLP_TYP ++ 0x00, // reserved ++ 0x00, // reserved ++ }) ++} +diff -ruN --exclude Makefile bios/acpi-dsdt.hex bios.new/acpi-dsdt.hex +--- bios/acpi-dsdt.hex 1970-01-01 01:00:00.000000000 +0100 ++++ bios.new/acpi-dsdt.hex 2006-09-24 20:27:54.000000000 +0200 +@@ -0,0 +1,278 @@ ++/* ++ * ++ * Intel ACPI Component Architecture ++ * ASL Optimizing Compiler version 20060421 [Apr 29 2006] ++ * Copyright (C) 2000 - 2006 Intel Corporation ++ * Supports ACPI Specification Revision 3.0a ++ * ++ * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006 ++ * ++ * C source code output ++ * ++ */ ++unsigned char AmlCode[] = ++{ ++ 0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */ ++ 0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */ ++ 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */ ++ 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ ++ 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */ ++ 0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */ ++ 0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */ ++ 0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */ ++ 0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */ ++ 0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */ ++ 0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */ ++ 0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */ ++ 0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */ ++ 0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */ ++ 0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */ ++ 0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */ ++ 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */ ++ 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */ ++ 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */ ++ 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */ ++ 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */ ++ 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */ ++ 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */ ++ 0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */ ++ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */ ++ 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */ ++ 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */ ++ 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */ ++ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */ ++ 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */ ++ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */ ++ 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */ ++ 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */ ++ 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */ ++ 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */ ++ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */ ++ 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */ ++ 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */ ++ 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */ ++ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */ ++ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */ ++ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */ ++ 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */ ++ 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */ ++ 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */ ++ 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */ ++ 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */ ++ 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */ ++ 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */ ++ 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */ ++ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */ ++ 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */ ++ 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */ ++ 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */ ++ 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */ ++ 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */ ++ 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */ ++ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */ ++ 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */ ++ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */ ++ 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */ ++ 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */ ++ 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */ ++ 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */ ++ 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */ ++ 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */ ++ 0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */ ++ 0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */ ++ 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */ ++ 0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */ ++ 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */ ++ 0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */ ++ 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */ ++ 0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */ ++ 0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */ ++ 0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */ ++ 0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */ ++ 0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */ ++ 0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */ ++ 0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */ ++ 0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */ ++ 0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */ ++ 0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */ ++ 0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */ ++ 0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */ ++ 0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */ ++ 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */ ++ 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */ ++ 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */ ++ 0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */ ++ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */ ++ 0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */ ++ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */ ++ 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */ ++ 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */ ++ 0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */ ++ 0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */ ++ 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */ ++ 0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */ ++ 0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */ ++ 0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */ ++ 0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */ ++ 0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */ ++ 0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */ ++ 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */ ++ 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */ ++ 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */ ++ 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */ ++ 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */ ++ 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */ ++ 0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */ ++ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */ ++ 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */ ++ 0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */ ++ 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */ ++ 0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */ ++ 0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */ ++ 0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */ ++ 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */ ++ 0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */ ++ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */ ++ 0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */ ++ 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */ ++ 0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */ ++ 0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */ ++ 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */ ++ 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */ ++ 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */ ++ 0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */ ++ 0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */ ++ 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */ ++ 0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */ ++ 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */ ++ 0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */ ++ 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */ ++ 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */ ++ 0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */ ++ 0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */ ++ 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */ ++ 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */ ++ 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */ ++ 0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */ ++ 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */ ++ 0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */ ++ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */ ++ 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */ ++ 0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */ ++ 0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */ ++ 0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */ ++ 0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */ ++ 0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */ ++ 0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */ ++ 0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */ ++ 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */ ++ 0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */ ++ 0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */ ++ 0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */ ++ 0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */ ++ 0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */ ++ 0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */ ++ 0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */ ++ 0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */ ++ 0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */ ++ 0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */ ++ 0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */ ++ 0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */ ++ 0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */ ++ 0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */ ++ 0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */ ++ 0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */ ++ 0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */ ++ 0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */ ++ 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */ ++ 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */ ++ 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */ ++ 0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */ ++ 0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */ ++ 0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */ ++ 0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */ ++ 0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */ ++ 0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */ ++ 0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */ ++ 0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */ ++ 0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */ ++ 0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */ ++ 0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */ ++ 0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */ ++ 0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */ ++ 0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */ ++ 0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */ ++ 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */ ++ 0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */ ++ 0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */ ++ 0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */ ++ 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */ ++ 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */ ++ 0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */ ++ 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */ ++ 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */ ++ 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */ ++ 0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */ ++ 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */ ++ 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */ ++ 0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */ ++ 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */ ++ 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */ ++ 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */ ++ 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */ ++ 0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */ ++ 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */ ++ 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */ ++ 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */ ++ 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */ ++ 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */ ++ 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */ ++ 0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */ ++ 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */ ++ 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */ ++ 0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */ ++ 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */ ++ 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */ ++ 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */ ++ 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */ ++ 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */ ++ 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */ ++ 0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */ ++ 0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */ ++ 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */ ++ 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */ ++ 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */ ++ 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */ ++ 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */ ++ 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */ ++ 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */ ++ 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */ ++ 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */ ++ 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */ ++ 0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */ ++ 0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */ ++ 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */ ++ 0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */ ++ 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */ ++ 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */ ++ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */ ++ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */ ++ 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */ ++ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */ ++ 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */ ++ 0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */ ++ 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */ ++ 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */ ++ 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */ ++ 0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */ ++ 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */ ++ 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */ ++ 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */ ++ 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */ ++ 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */ ++ 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */ ++ 0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */ ++ 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */ ++ 0x00,0x00, ++}; +Binary files bios/BIOS-bochs-latest and bios.new/BIOS-bochs-latest differ +diff -ruN --exclude Makefile bios/Makefile.in bios.new/Makefile.in +--- bios/Makefile.in 2006-01-13 18:36:27.000000000 +0100 ++++ bios.new/Makefile.in 2006-09-24 20:26:39.000000000 +0200 +@@ -61,7 +61,8 @@ -Index: rombios.c -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v -retrieving revision 1.160 -diff -u -w -r1.160 rombios.c ---- rombios.c 25 Jan 2006 17:51:49 -0000 1.160 -+++ rombios.c 3 May 2006 21:22:48 -0000 -@@ -1816,6 +1816,7 @@ - { - printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ", - BIOS_BUILD_DATE, bios_cvs_version_string); + clean: + @RMCOMMAND@ *.o *.a *.s _rombios*_.c rombios*.txt rombios*.sym +- @RMCOMMAND@ usage biossums ++ @RMCOMMAND@ usage biossums rombios16.bin ++ @RMCOMMAND@ rombios32.bin rombios32.out pad tmp32.bin + + dist-clean: clean + @RMCOMMAND@ Makefile +@@ -69,15 +70,35 @@ + bios-clean: + @RMCOMMAND@ BIOS-bochs-* + +-BIOS-bochs-latest: rombios.c apmbios.S biossums ++rombios16.bin: rombios.c apmbios.S biossums + $(GCC) $(BIOS_BUILD_DATE) -E -P $< > _rombios_.c + $(BCC) -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c + sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s + $(AS86) _rombios_.s -b tmp.bin -u- -w- -g -0 -j -O -l rombios.txt + -perl ${srcdir}/makesym.perl < rombios.txt > rombios.sym +- mv tmp.bin BIOS-bochs-latest +- ./biossums BIOS-bochs-latest ++ mv tmp.bin rombios16.bin ++ ./biossums rombios16.bin + rm -f _rombios_.s + ++ ++rombios32.bin: rombios32.out pad ++ objcopy -O binary $< tmp32.bin ++ ./pad < tmp32.bin > $@ 65536 0xff ++ ++rombios32.out: rombios32start.o rombios32.o rombios32.ld ++ ld -o $@ -T rombios32.ld rombios32start.o rombios32.o ++ ++rombios32.o: rombios32.c ++ $(GCC) -O2 -Wall -c -o $@ $< ++ ++rombios32start.o: rombios32start.S ++ $(GCC) -c -o $@ $< ++ ++BIOS-bochs-latest: rombios16.bin rombios32.bin ++ cat rombios32.bin rombios16.bin > $@ ++ ++pad: pad.c ++ $(GCC) -o $@ $< ++ + biossums: biossums.c + $(GCC) -o biossums biossums.c +diff -ruN --exclude Makefile bios/pad.c bios.new/pad.c +--- bios/pad.c 1970-01-01 01:00:00.000000000 +0100 ++++ bios.new/pad.c 2006-09-24 20:22:58.000000000 +0200 +@@ -0,0 +1,20 @@ ++#include ++#include ++ ++int main(int argc, char **argv) ++{ ++ int len, val, i, c; ++ ++ len = strtol(argv[1], NULL, 0); ++ val = strtol(argv[2], NULL, 0); ++ for(i = 0 ; i < len; i++) { ++ c = getchar(); ++ if (c == EOF) ++ break; ++ putchar(c); ++ } ++ for( ; i < len; i++) { ++ putchar(val); ++ } ++ return 0; ++} +diff -ruN --exclude Makefile bios/rombios32.c bios.new/rombios32.c +--- bios/rombios32.c 1970-01-01 01:00:00.000000000 +0100 ++++ bios.new/rombios32.c 2006-09-24 20:22:58.000000000 +0200 +@@ -0,0 +1,1324 @@ ++// 32 bit Bochs BIOS init code ++// Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++#include ++#include ++ ++typedef signed char int8_t; ++typedef short int16_t; ++typedef int int32_t; ++typedef long long int64_t; ++typedef unsigned char uint8_t; ++typedef unsigned short uint16_t; ++typedef unsigned int uint32_t; ++typedef unsigned long long uint64_t; ++ ++/* if true, put the MP float table and ACPI RSDT in EBDA and the MP ++ table in RAM. Unfortunately, Linux has bugs with that, so we prefer ++ to modify the BIOS in shadow RAM */ ++//#define BX_USE_EBDA_TABLES ++ ++/* define it if the (emulated) hardware supports SMM mode */ ++#define BX_USE_SMM ++ ++#define BX_INFO(fmt, args...) bios_printf(0, fmt, ## args); ++ ++#define INFO_PORT 0x402 ++ ++#define cpuid(index, eax, ebx, ecx, edx) \ ++ asm volatile ("cpuid" \ ++ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \ ++ : "0" (index)) ++ ++#define CPUID_APIC (1 << 9) ++ ++#define APIC_BASE ((uint8_t *)0xfee00000) ++#define APIC_ICR_LOW 0x300 ++#define APIC_SVR 0x0F0 ++#define APIC_ID 0x020 ++#define APIC_LVT3 0x370 ++ ++#define APIC_ENABLED 0x0100 ++ ++#define CPU_COUNT_ADDR 0xf000 ++#define AP_BOOT_ADDR 0x10000 ++ ++#define MPTABLE_MAX_SIZE 0x00002000 ++#define ACPI_DATA_SIZE 0x00010000 ++#define SMI_CMD_IO_ADDR 0xb2 ++#define PM_IO_BASE 0xb000 ++ ++#define BIOS_TMP_STORAGE 0x00030000 /* 64 KB used to copy the BIOS to shadow RAM */ ++ ++static inline void outl(int addr, int val) ++{ ++ asm volatile ("outl %1, %w0" : : "d" (addr), "a" (val)); ++} ++ ++static inline void outw(int addr, int val) ++{ ++ asm volatile ("outw %w1, %w0" : : "d" (addr), "a" (val)); ++} ++ ++static inline void outb(int addr, int val) ++{ ++ asm volatile ("outb %b1, %w0" : : "d" (addr), "a" (val)); ++} ++ ++static inline uint32_t inl(int addr) ++{ ++ uint32_t val; ++ asm volatile ("inl %w1, %0" : "=a" (val) : "d" (addr)); ++ return val; ++} ++ ++static inline uint16_t inw(int addr) ++{ ++ uint16_t val; ++ asm volatile ("inw %w1, %w0" : "=a" (val) : "d" (addr)); ++ return val; ++} ++ ++static inline uint8_t inb(int addr) ++{ ++ uint8_t val; ++ asm volatile ("inb %w1, %b0" : "=a" (val) : "d" (addr)); ++ return val; ++} ++ ++static inline void writel(void *addr, uint32_t val) ++{ ++ *(volatile uint32_t *)addr = val; ++} ++ ++static inline void writew(void *addr, uint16_t val) ++{ ++ *(volatile uint16_t *)addr = val; ++} ++ ++static inline void writeb(void *addr, uint8_t val) ++{ ++ *(volatile uint8_t *)addr = val; ++} ++ ++static inline uint32_t readl(const void *addr) ++{ ++ return *(volatile const uint32_t *)addr; ++} ++ ++static inline uint16_t readw(const void *addr) ++{ ++ return *(volatile const uint16_t *)addr; ++} ++ ++static inline uint8_t readb(const void *addr) ++{ ++ return *(volatile const uint8_t *)addr; ++} ++ ++static inline void putc(int c) ++{ ++ outb(INFO_PORT, c); ++} ++ ++static inline int isdigit(int c) ++{ ++ return c >= '0' && c <= '9'; ++} ++ ++void *memset(void *d1, int val, size_t len) ++{ ++ uint8_t *d = d1; ++ ++ while (len--) { ++ *d++ = val; ++ } ++ return d1; ++} ++ ++void *memcpy(void *d1, const void *s1, size_t len) ++{ ++ uint8_t *d = d1; ++ const uint8_t *s = s1; ++ ++ while (len--) { ++ *d++ = *s++; ++ } ++ return d1; ++} ++ ++void *memmove(void *d1, const void *s1, size_t len) ++{ ++ uint8_t *d = d1; ++ const uint8_t *s = s1; ++ ++ if (d <= s) { ++ while (len--) { ++ *d++ = *s++; ++ } ++ } else { ++ d += len; ++ s += len; ++ while (len--) { ++ *--d = *--s; ++ } ++ } ++ return d1; ++} ++ ++size_t strlen(const char *s) ++{ ++ const char *s1; ++ for(s1 = s; *s1 != '\0'; s1++); ++ return s1 - s; ++} ++ ++/* from BSD ppp sources */ ++int vsnprintf(char *buf, int buflen, const char *fmt, va_list args) ++{ ++ int c, i, n; ++ int width, prec, fillch; ++ int base, len, neg; ++ unsigned long val = 0; ++ const char *f; ++ char *str, *buf0; ++ char num[32]; ++ static const char hexchars[] = "0123456789abcdef"; ++ ++ buf0 = buf; ++ --buflen; ++ while (buflen > 0) { ++ for (f = fmt; *f != '%' && *f != 0; ++f) ++ ; ++ if (f > fmt) { ++ len = f - fmt; ++ if (len > buflen) ++ len = buflen; ++ memcpy(buf, fmt, len); ++ buf += len; ++ buflen -= len; ++ fmt = f; ++ } ++ if (*fmt == 0) ++ break; ++ c = *++fmt; ++ width = prec = 0; ++ fillch = ' '; ++ if (c == '0') { ++ fillch = '0'; ++ c = *++fmt; ++ } ++ if (c == '*') { ++ width = va_arg(args, int); ++ c = *++fmt; ++ } else { ++ while (isdigit(c)) { ++ width = width * 10 + c - '0'; ++ c = *++fmt; ++ } ++ } ++ if (c == '.') { ++ c = *++fmt; ++ if (c == '*') { ++ prec = va_arg(args, int); ++ c = *++fmt; ++ } else { ++ while (isdigit(c)) { ++ prec = prec * 10 + c - '0'; ++ c = *++fmt; ++ } ++ } ++ } ++ /* modifiers */ ++ switch(c) { ++ case 'l': ++ c = *++fmt; ++ break; ++ default: ++ break; ++ } ++ str = 0; ++ base = 0; ++ neg = 0; ++ ++fmt; ++ switch (c) { ++ case 'd': ++ i = va_arg(args, int); ++ if (i < 0) { ++ neg = 1; ++ val = -i; ++ } else ++ val = i; ++ base = 10; ++ break; ++ case 'o': ++ val = va_arg(args, unsigned int); ++ base = 8; ++ break; ++ case 'x': ++ case 'X': ++ val = va_arg(args, unsigned int); ++ base = 16; ++ break; ++ case 'p': ++ val = (unsigned long) va_arg(args, void *); ++ base = 16; ++ neg = 2; ++ break; ++ case 's': ++ str = va_arg(args, char *); ++ break; ++ case 'c': ++ num[0] = va_arg(args, int); ++ num[1] = 0; ++ str = num; ++ break; ++ default: ++ *buf++ = '%'; ++ if (c != '%') ++ --fmt; /* so %z outputs %z etc. */ ++ --buflen; ++ continue; ++ } ++ if (base != 0) { ++ str = num + sizeof(num); ++ *--str = 0; ++ while (str > num + neg) { ++ *--str = hexchars[val % base]; ++ val = val / base; ++ if (--prec <= 0 && val == 0) ++ break; ++ } ++ switch (neg) { ++ case 1: ++ *--str = '-'; ++ break; ++ case 2: ++ *--str = 'x'; ++ *--str = '0'; ++ break; ++ } ++ len = num + sizeof(num) - 1 - str; ++ } else { ++ len = strlen(str); ++ if (prec > 0 && len > prec) ++ len = prec; ++ } ++ if (width > 0) { ++ if (width > buflen) ++ width = buflen; ++ if ((n = width - len) > 0) { ++ buflen -= n; ++ for (; n > 0; --n) ++ *buf++ = fillch; ++ } ++ } ++ if (len > buflen) ++ len = buflen; ++ memcpy(buf, str, len); ++ buf += len; ++ buflen -= len; ++ } ++ *buf = 0; ++ return buf - buf0; ++} ++ ++void bios_printf(int flags, const char *fmt, ...) ++{ ++ va_list ap; ++ char buf[1024]; ++ const char *s; ++ ++ va_start(ap, fmt); ++ vsnprintf(buf, sizeof(buf), fmt, ap); ++ s = buf; ++ while (*s) ++ putc(*s++); ++ va_end(ap); ++} ++ ++/* approximative ! */ ++void delay_ms(int n) ++{ ++ int i, j; ++ for(i = 0; i < n; i++) { ++ for(j = 0; j < 1000000; j++); ++ } ++} ++ ++int smp_cpus; ++uint32_t cpuid_features; ++uint32_t cpuid_ext_features; ++unsigned long ram_size; ++#ifdef BX_USE_EBDA_TABLES ++unsigned long ebda_cur_addr; ++#endif ++int acpi_enabled; ++uint32_t pm_io_base; ++int pm_sci_int; ++unsigned long bios_table_cur_addr; ++unsigned long bios_table_end_addr; ++ ++void cpu_probe(void) ++{ ++ uint32_t eax, ebx, ecx, edx; ++ cpuid(1, eax, ebx, ecx, edx); ++ cpuid_features = edx; ++ cpuid_ext_features = ecx; ++} ++ ++static int cmos_readb(int addr) ++{ ++ outb(0x70, addr); ++ return inb(0x71); ++} ++ ++void ram_probe(void) ++{ ++ ram_size = (cmos_readb(0x34) | (cmos_readb(0x35) << 8)) * 65536 + ++ 16 * 1024 * 1024; ++#ifdef BX_USE_EBDA_TABLES ++ ebda_cur_addr = ((*(uint16_t *)(0x40e)) << 4) + 0x380; ++#endif ++ BX_INFO("ram_size=0x%08lx\n"); ++} ++ ++/****************************************************/ ++/* SMP probe */ ++ ++extern uint8_t smp_ap_boot_code_start; ++extern uint8_t smp_ap_boot_code_end; ++ ++/* find the number of CPUs by launching a SIPI to them */ ++void smp_probe(void) ++{ ++ uint32_t val, sipi_vector; ++ ++ smp_cpus = 1; ++ if (cpuid_features & CPUID_APIC) { ++ ++ /* enable local APIC */ ++ val = readl(APIC_BASE + APIC_SVR); ++ val |= APIC_ENABLED; ++ writel(APIC_BASE + APIC_SVR, val); ++ ++ writew((void *)CPU_COUNT_ADDR, 1); ++ /* copy AP boot code */ ++ memcpy((void *)AP_BOOT_ADDR, &smp_ap_boot_code_start, ++ &smp_ap_boot_code_end - &smp_ap_boot_code_start); ++ ++ /* broadcast SIPI */ ++ writel(APIC_BASE + APIC_ICR_LOW, 0x000C4500); ++ sipi_vector = AP_BOOT_ADDR >> 12; ++ writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector); ++ ++ delay_ms(10); ++ ++ smp_cpus = readw((void *)CPU_COUNT_ADDR); ++ } ++ BX_INFO("Found %d cpus\n", smp_cpus); ++} ++ ++/****************************************************/ ++/* PCI init */ ++ ++#define PCI_ADDRESS_SPACE_MEM 0x00 ++#define PCI_ADDRESS_SPACE_IO 0x01 ++#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08 ++ ++#define PCI_ROM_SLOT 6 ++#define PCI_NUM_REGIONS 7 ++ ++#define PCI_DEVICES_MAX 64 ++ ++#define PCI_VENDOR_ID 0x00 /* 16 bits */ ++#define PCI_DEVICE_ID 0x02 /* 16 bits */ ++#define PCI_COMMAND 0x04 /* 16 bits */ ++#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ ++#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ ++#define PCI_CLASS_DEVICE 0x0a /* Device class */ ++#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ ++#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ ++#define PCI_MIN_GNT 0x3e /* 8 bits */ ++#define PCI_MAX_LAT 0x3f /* 8 bits */ ++ ++typedef struct PCIDevice { ++ int bus; ++ int devfn; ++} PCIDevice; ++ ++static uint32_t pci_bios_io_addr; ++static uint32_t pci_bios_mem_addr; ++/* host irqs corresponding to PCI irqs A-D */ ++static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; ++static PCIDevice i440_pcidev; ++ ++static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) ++{ ++ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); ++ outl(0xcfc, val); ++} ++ ++static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) ++{ ++ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); ++ outw(0xcfc + (addr & 2), val); ++} ++ ++static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) ++{ ++ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); ++ outb(0xcfc + (addr & 3), val); ++} ++ ++static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) ++{ ++ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); ++ return inl(0xcfc); ++} ++ ++static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) ++{ ++ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); ++ return inw(0xcfc + (addr & 2)); ++} ++ ++static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) ++{ ++ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); ++ return inb(0xcfc + (addr & 3)); ++} ++ ++static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) ++{ ++ uint16_t cmd; ++ uint32_t ofs, old_addr; ++ ++ if ( region_num == PCI_ROM_SLOT ) { ++ ofs = 0x30; ++ }else{ ++ ofs = 0x10 + region_num * 4; ++ } ++ ++ old_addr = pci_config_readl(d, ofs); ++ ++ pci_config_writel(d, ofs, addr); ++ BX_INFO("region %d: 0x%08x\n", region_num, addr); ++ ++ /* enable memory mappings */ ++ cmd = pci_config_readw(d, PCI_COMMAND); ++ if ( region_num == PCI_ROM_SLOT ) ++ cmd |= 2; ++ else if (old_addr & PCI_ADDRESS_SPACE_IO) ++ cmd |= 1; ++ else ++ cmd |= 2; ++ pci_config_writew(d, PCI_COMMAND, cmd); ++} ++ ++/* return the global irq number corresponding to a given device irq ++ pin. We could also use the bus number to have a more precise ++ mapping. */ ++static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) ++{ ++ int slot_addend; ++ slot_addend = (pci_dev->devfn >> 3) - 1; ++ return (irq_num + slot_addend) & 3; ++} ++ ++static int find_bios_table_area(void) ++{ ++ unsigned long addr; ++ for(addr = 0xf0000; addr < 0x100000; addr += 16) { ++ if (*(uint32_t *)addr == 0xaafb4442) { ++ bios_table_cur_addr = addr + 8; ++ bios_table_end_addr = bios_table_cur_addr + *(uint32_t *)(addr + 4); ++ BX_INFO("bios_table_addr: 0x%08lx end=0x%08lx\n", ++ bios_table_cur_addr, bios_table_end_addr); ++ return 0; ++ } ++ } ++ return -1; ++} ++ ++static void bios_shadow_init(PCIDevice *d) ++{ ++ int v; ++ ++ if (find_bios_table_area() < 0) ++ return; ++ ++ /* remap the BIOS to shadow RAM an keep it read/write while we ++ are writing tables */ ++ memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000); ++ v = pci_config_readb(d, 0x67); ++ v = (v & 0x0f) | (0x30); ++ pci_config_writeb(d, 0x67, v); ++ memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000); ++ ++ i440_pcidev = *d; ++} ++ ++static void bios_lock_shadow_ram(void) ++{ ++ PCIDevice *d = &i440_pcidev; ++ int v; ++ ++ v = pci_config_readb(d, 0x67); ++ v = (v & 0x0f) | (0x20); ++ pci_config_writeb(d, 0x67, v); ++} ++ ++static void pci_bios_init_bridges(PCIDevice *d) ++{ ++ uint16_t vendor_id, device_id; ++ ++ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); ++ device_id = pci_config_readw(d, PCI_DEVICE_ID); ++ ++ if (vendor_id == 0x8086 && device_id == 0x7000) { ++ int i, irq; ++ uint8_t elcr[2]; ++ ++ /* PIIX3 bridge */ ++ ++ elcr[0] = 0x00; ++ elcr[1] = 0x00; ++ for(i = 0; i < 4; i++) { ++ irq = pci_irqs[i]; ++ /* set to trigger level */ ++ elcr[irq >> 3] |= (1 << (irq & 7)); ++ /* activate irq remapping in PIIX */ ++ pci_config_writeb(d, 0x60 + i, irq); ++ } ++ outb(0x4d0, elcr[0]); ++ outb(0x4d1, elcr[1]); ++ BX_INFO("PIIX3 init: elcr=%02x %02x\n", ++ elcr[0], elcr[1]); ++ } else if (vendor_id == 0x8086 && device_id == 0x1237) { ++ /* i440 PCI bridge */ ++ bios_shadow_init(d); ++ } ++} ++ ++extern uint8_t smm_relocation_start, smm_relocation_end; ++extern uint8_t smm_code_start, smm_code_end; ++ ++#ifdef BX_USE_SMM ++static void smm_init(void) ++{ ++ /* copy the SMM relocation code */ ++ memcpy((void *)0x38000, &smm_relocation_start, ++ &smm_relocation_end - &smm_relocation_start); ++ /* raise an SMI interrupt */ ++ outb(0xb2, 00); ++ ++ /* enable the SMM memory window */ ++ pci_config_writel(&i440_pcidev, 0x6c, (1 << 26) | 0x000a); ++ ++ /* copy the SMM code */ ++ memcpy((void *)0xa8000, &smm_code_start, ++ &smm_code_end - &smm_code_start); ++ ++ /* close the SMM memory window and enable normal SMM */ ++ pci_config_writel(&i440_pcidev, 0x6c, (1 << 31) | 0x000a); ++} ++#endif ++ ++static void pci_bios_init_device(PCIDevice *d) ++{ ++ int class; ++ uint32_t *paddr; ++ int i, pin, pic_irq, vendor_id, device_id; ++ ++ class = pci_config_readw(d, PCI_CLASS_DEVICE); ++ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); ++ device_id = pci_config_readw(d, PCI_DEVICE_ID); ++ BX_INFO("PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n", ++ d->bus, d->devfn, vendor_id, device_id); ++ switch(class) { ++ case 0x0101: ++ if (vendor_id == 0x8086 && device_id == 0x7010) { ++ /* PIIX3 IDE */ ++ pci_config_writew(d, 0x40, 0x8000); // enable IDE0 ++ pci_config_writew(d, 0x42, 0x8000); // enable IDE1 ++ goto default_map; ++ } else { ++ /* IDE: we map it as in ISA mode */ ++ pci_set_io_region_addr(d, 0, 0x1f0); ++ pci_set_io_region_addr(d, 1, 0x3f4); ++ pci_set_io_region_addr(d, 2, 0x170); ++ pci_set_io_region_addr(d, 3, 0x374); ++ } ++ break; ++ case 0x0300: ++ if (vendor_id != 0x1234) ++ goto default_map; ++ /* VGA: map frame buffer to default Bochs VBE address */ ++ pci_set_io_region_addr(d, 0, 0xE0000000); ++ break; ++ case 0x0800: ++ /* PIC */ ++ if (vendor_id == 0x1014) { ++ /* IBM */ ++ if (device_id == 0x0046 || device_id == 0xFFFF) { ++ /* MPIC & MPIC2 */ ++ pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); ++ } ++ } ++ break; ++ case 0xff00: ++ if (vendor_id == 0x0106b && ++ (device_id == 0x0017 || device_id == 0x0022)) { ++ /* macio bridge */ ++ pci_set_io_region_addr(d, 0, 0x80800000); ++ } ++ break; ++ default: ++ default_map: ++ /* default memory mappings */ ++ for(i = 0; i < PCI_NUM_REGIONS; i++) { ++ int ofs; ++ uint32_t val, size ; ++ ++ if (i == PCI_ROM_SLOT) ++ ofs = 0x30; ++ else ++ ofs = 0x10 + i * 4; ++ pci_config_writel(d, ofs, 0xffffffff); ++ val = pci_config_readl(d, ofs); ++ if (val != 0) { ++ size = (~(val & ~0xf)) + 1; ++ if (val & PCI_ADDRESS_SPACE_IO) ++ paddr = &pci_bios_io_addr; ++ else ++ paddr = &pci_bios_mem_addr; ++ *paddr = (*paddr + size - 1) & ~(size - 1); ++ pci_set_io_region_addr(d, i, *paddr); ++ *paddr += size; ++ } ++ } ++ break; ++ } ++ ++ /* map the interrupt */ ++ pin = pci_config_readb(d, PCI_INTERRUPT_PIN); ++ if (pin != 0) { ++ pin = pci_slot_get_pirq(d, pin - 1); ++ pic_irq = pci_irqs[pin]; ++ pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); ++ } ++ ++ if (vendor_id == 0x8086 && device_id == 0x7113) { ++ /* PIIX4 Power Management device (for ACPI) */ ++ pm_io_base = PM_IO_BASE; ++ pci_config_writel(d, 0x40, pm_io_base | 1); ++ pci_config_writeb(d, 0x80, 0x01); /* enable PM io space */ ++ pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE); ++#ifdef BX_USE_SMM ++ smm_init(); ++#endif ++ acpi_enabled = 1; ++ } ++} ++ ++void pci_for_each_device(void (*init_func)(PCIDevice *d)) ++{ ++ PCIDevice d1, *d = &d1; ++ int bus, devfn; ++ uint16_t vendor_id, device_id; ++ ++ for(bus = 0; bus < 1; bus++) { ++ for(devfn = 0; devfn < 256; devfn++) { ++ d->bus = bus; ++ d->devfn = devfn; ++ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); ++ device_id = pci_config_readw(d, PCI_DEVICE_ID); ++ if (vendor_id != 0xffff || device_id != 0xffff) { ++ init_func(d); ++ } ++ } ++ } ++} ++ ++void pci_bios_init(void) ++{ ++ pci_bios_io_addr = 0xc000; ++ pci_bios_mem_addr = 0xf0000000; ++ ++ pci_for_each_device(pci_bios_init_bridges); ++ ++ pci_for_each_device(pci_bios_init_device); ++} ++ ++/****************************************************/ ++/* Multi Processor table init */ ++ ++static void putb(uint8_t **pp, int val) ++{ ++ uint8_t *q; ++ q = *pp; ++ *q++ = val; ++ *pp = q; ++} ++ ++static void putstr(uint8_t **pp, const char *str) ++{ ++ uint8_t *q; ++ q = *pp; ++ while (*str) ++ *q++ = *str++; ++ *pp = q; ++} ++ ++static void putle16(uint8_t **pp, int val) ++{ ++ uint8_t *q; ++ q = *pp; ++ *q++ = val; ++ *q++ = val >> 8; ++ *pp = q; ++} ++ ++static void putle32(uint8_t **pp, int val) ++{ ++ uint8_t *q; ++ q = *pp; ++ *q++ = val; ++ *q++ = val >> 8; ++ *q++ = val >> 16; ++ *q++ = val >> 24; ++ *pp = q; ++} ++ ++static int mpf_checksum(const uint8_t *data, int len) ++{ ++ int sum, i; ++ sum = 0; ++ for(i = 0; i < len; i++) ++ sum += data[i]; ++ return sum & 0xff; ++} ++ ++static unsigned long align(unsigned long addr, unsigned long v) ++{ ++ return (addr + v - 1) & ~(v - 1); ++} ++ ++static void mptable_init(void) ++{ ++ uint8_t *mp_config_table, *q, *float_pointer_struct; ++ int ioapic_id, i, len; ++ int mp_config_table_size; ++ ++ if (smp_cpus <= 1) ++ return; ++ ++#ifdef BX_USE_EBDA_TABLES ++ mp_config_table = (uint8_t *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE); ++#else ++ bios_table_cur_addr = align(bios_table_cur_addr, 16); ++ mp_config_table = (uint8_t *)bios_table_cur_addr; ++#endif ++ q = mp_config_table; ++ putstr(&q, "PCMP"); /* "PCMP signature */ ++ putle16(&q, 0); /* table length (patched later) */ ++ putb(&q, 4); /* spec rev */ ++ putb(&q, 0); /* checksum (patched later) */ ++ putstr(&q, "QEMUCPU "); /* OEM id */ ++ putstr(&q, "0.1 "); /* vendor id */ ++ putle32(&q, 0); /* OEM table ptr */ ++ putle16(&q, 0); /* OEM table size */ ++ putle16(&q, 20); /* entry count */ ++ putle32(&q, 0xfee00000); /* local APIC addr */ ++ putle16(&q, 0); /* ext table length */ ++ putb(&q, 0); /* ext table checksum */ ++ putb(&q, 0); /* reserved */ ++ ++ for(i = 0; i < smp_cpus; i++) { ++ putb(&q, 0); /* entry type = processor */ ++ putb(&q, i); /* APIC id */ ++ putb(&q, 0x11); /* local APIC version number */ ++ if (i == 0) ++ putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */ ++ else ++ putb(&q, 1); /* cpu flags: enabled */ ++ putb(&q, 0); /* cpu signature */ ++ putb(&q, 6); ++ putb(&q, 0); ++ putb(&q, 0); ++ putle16(&q, 0x201); /* feature flags */ ++ putle16(&q, 0); ++ ++ putle16(&q, 0); /* reserved */ ++ putle16(&q, 0); ++ putle16(&q, 0); ++ putle16(&q, 0); ++ } ++ ++ /* isa bus */ ++ putb(&q, 1); /* entry type = bus */ ++ putb(&q, 0); /* bus ID */ ++ putstr(&q, "ISA "); ++ ++ /* ioapic */ ++ ioapic_id = smp_cpus; ++ putb(&q, 2); /* entry type = I/O APIC */ ++ putb(&q, ioapic_id); /* apic ID */ ++ putb(&q, 0x11); /* I/O APIC version number */ ++ putb(&q, 1); /* enable */ ++ putle32(&q, 0xfec00000); /* I/O APIC addr */ ++ ++ /* irqs */ ++ for(i = 0; i < 16; i++) { ++ putb(&q, 3); /* entry type = I/O interrupt */ ++ putb(&q, 0); /* interrupt type = vectored interrupt */ ++ putb(&q, 0); /* flags: po=0, el=0 */ ++ putb(&q, 0); ++ putb(&q, 0); /* source bus ID = ISA */ ++ putb(&q, i); /* source bus IRQ */ ++ putb(&q, ioapic_id); /* dest I/O APIC ID */ ++ putb(&q, i); /* dest I/O APIC interrupt in */ ++ } ++ /* patch length */ ++ len = q - mp_config_table; ++ mp_config_table[4] = len; ++ mp_config_table[5] = len >> 8; ++ ++ mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table); ++ ++ mp_config_table_size = q - mp_config_table; ++ ++#ifndef BX_USE_EBDA_TABLES ++ bios_table_cur_addr += mp_config_table_size; ++#endif ++ ++ /* floating pointer structure */ ++#ifdef BX_USE_EBDA_TABLES ++ ebda_cur_addr = align(ebda_cur_addr, 16); ++ float_pointer_struct = (uint8_t *)ebda_cur_addr; ++#else ++ bios_table_cur_addr = align(bios_table_cur_addr, 16); ++ float_pointer_struct = (uint8_t *)bios_table_cur_addr; ++#endif ++ q = float_pointer_struct; ++ putstr(&q, "_MP_"); ++ /* pointer to MP config table */ ++ putle32(&q, (unsigned long)mp_config_table); ++ ++ putb(&q, 1); /* length in 16 byte units */ ++ putb(&q, 4); /* MP spec revision */ ++ putb(&q, 0); /* checksum (patched later) */ ++ putb(&q, 0); /* MP feature byte 1 */ ++ ++ putb(&q, 0); ++ putb(&q, 0); ++ putb(&q, 0); ++ putb(&q, 0); ++ float_pointer_struct[10] = ++ -mpf_checksum(float_pointer_struct, q - float_pointer_struct); ++#ifdef BX_USE_EBDA_TABLES ++ ebda_cur_addr += (q - float_pointer_struct); ++#else ++ bios_table_cur_addr += (q - float_pointer_struct); ++#endif ++ BX_INFO("MP table addr=0x%08lx MPC table addr=0x%08lx size=0x%x\n", ++ (unsigned long)float_pointer_struct, ++ (unsigned long)mp_config_table, ++ mp_config_table_size); ++} ++ ++/****************************************************/ ++/* ACPI tables init */ ++ ++/* Table structure from Linux kernel (the ACPI tables are under the ++ BSD license) */ ++ ++#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ ++ uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\ ++ uint32_t length; /* Length of table, in bytes, including header */\ ++ uint8_t revision; /* ACPI Specification minor version # */\ ++ uint8_t checksum; /* To make sum of entire table == 0 */\ ++ uint8_t oem_id [6]; /* OEM identification */\ ++ uint8_t oem_table_id [8]; /* OEM table identification */\ ++ uint32_t oem_revision; /* OEM revision number */\ ++ uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\ ++ uint32_t asl_compiler_revision; /* ASL compiler revision number */ ++ ++ ++struct acpi_table_header /* ACPI common table header */ ++{ ++ ACPI_TABLE_HEADER_DEF ++}; ++ ++struct rsdp_descriptor /* Root System Descriptor Pointer */ ++{ ++ uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */ ++ uint8_t checksum; /* To make sum of struct == 0 */ ++ uint8_t oem_id [6]; /* OEM identification */ ++ uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ ++ uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */ ++ uint32_t length; /* XSDT Length in bytes including hdr */ ++ uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */ ++ uint8_t extended_checksum; /* Checksum of entire table */ ++ uint8_t reserved [3]; /* Reserved field must be 0 */ ++}; ++ ++/* ++ * ACPI 1.0 Root System Description Table (RSDT) ++ */ ++struct rsdt_descriptor_rev1 ++{ ++ ACPI_TABLE_HEADER_DEF /* ACPI common table header */ ++ uint32_t table_offset_entry [2]; /* Array of pointers to other */ ++ /* ACPI tables */ ++}; ++ ++/* ++ * ACPI 1.0 Firmware ACPI Control Structure (FACS) ++ */ ++struct facs_descriptor_rev1 ++{ ++ uint8_t signature[4]; /* ACPI Signature */ ++ uint32_t length; /* Length of structure, in bytes */ ++ uint32_t hardware_signature; /* Hardware configuration signature */ ++ uint32_t firmware_waking_vector; /* ACPI OS waking vector */ ++ uint32_t global_lock; /* Global Lock */ ++ uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */ ++ uint32_t reserved1 : 31; /* Must be 0 */ ++ uint8_t resverved3 [40]; /* Reserved - must be zero */ ++}; ++ ++ ++/* ++ * ACPI 1.0 Fixed ACPI Description Table (FADT) ++ */ ++struct fadt_descriptor_rev1 ++{ ++ ACPI_TABLE_HEADER_DEF /* ACPI common table header */ ++ uint32_t firmware_ctrl; /* Physical address of FACS */ ++ uint32_t dsdt; /* Physical address of DSDT */ ++ uint8_t model; /* System Interrupt Model */ ++ uint8_t reserved1; /* Reserved */ ++ uint16_t sci_int; /* System vector of SCI interrupt */ ++ uint32_t smi_cmd; /* Port address of SMI command port */ ++ uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */ ++ uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */ ++ uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ ++ uint8_t reserved2; /* Reserved - must be zero */ ++ uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ ++ uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ ++ uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ ++ uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ ++ uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ ++ uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ ++ uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ ++ uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ ++ uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ ++ uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ ++ uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ ++ uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ ++ uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ ++ uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ ++ uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */ ++ uint8_t reserved3; /* Reserved */ ++ uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ ++ uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ ++ uint16_t flush_size; /* Size of area read to flush caches */ ++ uint16_t flush_stride; /* Stride used in flushing caches */ ++ uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */ ++ uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */ ++ uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ ++ uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ ++ uint8_t century; /* Index to century in RTC CMOS RAM */ ++ uint8_t reserved4; /* Reserved */ ++ uint8_t reserved4a; /* Reserved */ ++ uint8_t reserved4b; /* Reserved */ +#if 0 - printf( - #ifdef BX_APM - "apmbios " -@@ -1827,6 +1828,9 @@ - "eltorito " - #endif - "\n\n"); ++ uint32_t wb_invd : 1; /* The wbinvd instruction works properly */ ++ uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ ++ uint32_t proc_c1 : 1; /* All processors support C1 state */ ++ uint32_t plvl2_up : 1; /* C2 state works on MP system */ ++ uint32_t pwr_button : 1; /* Power button is handled as a generic feature */ ++ uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ ++ uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ ++ uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ ++ uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */ ++ uint32_t reserved5 : 23; /* Reserved - must be zero */ +#else -+ printf("apmbios pcibios eltorito \n\n"); ++ uint32_t flags; +#endif - } - - //-------------------------------------------------------------------------- -@@ -3999,6 +4003,29 @@ - } - #endif - ++}; ++ ++/* ++ * MADT values and structures ++ */ ++ ++/* Values for MADT PCATCompat */ ++ ++#define DUAL_PIC 0 ++#define MULTIPLE_APIC 1 ++ ++ ++/* Master MADT */ ++ ++struct multiple_apic_table ++{ ++ ACPI_TABLE_HEADER_DEF /* ACPI common table header */ ++ uint32_t local_apic_address; /* Physical address of local APIC */ ++#if 0 ++ uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */ ++ uint32_t reserved1 : 31; ++#else ++ uint32_t flags; ++#endif ++}; ++ ++ ++/* Values for Type in APIC_HEADER_DEF */ ++ ++#define APIC_PROCESSOR 0 ++#define APIC_IO 1 ++#define APIC_XRUPT_OVERRIDE 2 ++#define APIC_NMI 3 ++#define APIC_LOCAL_NMI 4 ++#define APIC_ADDRESS_OVERRIDE 5 ++#define APIC_IO_SAPIC 6 ++#define APIC_LOCAL_SAPIC 7 ++#define APIC_XRUPT_SOURCE 8 ++#define APIC_RESERVED 9 /* 9 and greater are reserved */ ++ ++/* ++ * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) ++ */ ++#define APIC_HEADER_DEF /* Common APIC sub-structure header */\ ++ uint8_t type; \ ++ uint8_t length; ++ ++/* Sub-structures for MADT */ ++ ++struct madt_processor_apic ++{ ++ APIC_HEADER_DEF ++ uint8_t processor_id; /* ACPI processor id */ ++ uint8_t local_apic_id; /* Processor's local APIC id */ ++#if 0 ++ uint32_t processor_enabled: 1; /* Processor is usable if set */ ++ uint32_t reserved2 : 31; /* Reserved, must be zero */ ++#else ++ uint32_t flags; ++#endif ++}; ++ ++struct madt_io_apic ++{ ++ APIC_HEADER_DEF ++ uint8_t io_apic_id; /* I/O APIC ID */ ++ uint8_t reserved; /* Reserved - must be zero */ ++ uint32_t address; /* APIC physical address */ ++ uint32_t interrupt; /* Global system interrupt where INTI ++ * lines start */ ++}; ++ ++#include "acpi-dsdt.hex" + -+void set_e820_range(ES, DI, start, end, type) -+ Bit16u ES; -+ Bit16u DI; -+ Bit32u start; -+ Bit32u end; -+ Bit16u type; -+{ -+ write_word(ES, DI, start); -+ write_word(ES, DI+2, start >> 16); -+ write_word(ES, DI+4, 0x00); -+ write_word(ES, DI+6, 0x00); ++static inline uint16_t cpu_to_le16(uint16_t x) ++{ ++ return x; ++} ++ ++static inline uint32_t cpu_to_le32(uint32_t x) ++{ ++ return x; ++} ++ ++static int acpi_checksum(const uint8_t *data, int len) ++{ ++ int sum, i; ++ sum = 0; ++ for(i = 0; i < len; i++) ++ sum += data[i]; ++ return (-sum) & 0xff; ++} ++ ++static void acpi_build_table_header(struct acpi_table_header *h, ++ char *sig, int len) ++{ ++ memcpy(h->signature, sig, 4); ++ h->length = cpu_to_le32(len); ++ h->revision = 0; ++ memcpy(h->oem_id, "QEMU ", 6); ++ memcpy(h->oem_table_id, "QEMU", 4); ++ memcpy(h->oem_table_id + 4, sig, 4); ++ h->oem_revision = cpu_to_le32(1); ++ memcpy(h->asl_compiler_id, "QEMU", 4); ++ h->asl_compiler_revision = cpu_to_le32(1); ++ h->checksum = acpi_checksum((void *)h, len); ++} ++ ++/* base_addr must be a multiple of 4KB */ ++void acpi_bios_init(void) ++{ ++ struct rsdp_descriptor *rsdp; ++ struct rsdt_descriptor_rev1 *rsdt; ++ struct fadt_descriptor_rev1 *fadt; ++ struct facs_descriptor_rev1 *facs; ++ struct multiple_apic_table *madt; ++ uint8_t *dsdt; ++ uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr; ++ uint32_t acpi_tables_size, madt_addr, madt_size; ++ int i; ++ ++ /* reserve memory space for tables */ ++#ifdef BX_USE_EBDA_TABLES ++ ebda_cur_addr = align(ebda_cur_addr, 16); ++ rsdp = (void *)(ebda_cur_addr); ++ ebda_cur_addr += sizeof(*rsdp); ++#else ++ bios_table_cur_addr = align(bios_table_cur_addr, 16); ++ rsdp = (void *)(bios_table_cur_addr); ++ bios_table_cur_addr += sizeof(*rsdp); ++#endif ++ ++ addr = base_addr = ram_size - ACPI_DATA_SIZE; ++ rsdt_addr = addr; ++ rsdt = (void *)(addr); ++ addr += sizeof(*rsdt); ++ ++ fadt_addr = addr; ++ fadt = (void *)(addr); ++ addr += sizeof(*fadt); ++ ++ /* XXX: FACS should be in RAM */ ++ addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */ ++ facs_addr = addr; ++ facs = (void *)(addr); ++ addr += sizeof(*facs); ++ ++ dsdt_addr = addr; ++ dsdt = (void *)(addr); ++ addr += sizeof(AmlCode); ++ ++ addr = (addr + 7) & ~7; ++ madt_addr = addr; ++ madt_size = sizeof(*madt) + ++ sizeof(struct madt_processor_apic) * smp_cpus + ++ sizeof(struct madt_io_apic); ++ madt = (void *)(addr); ++ addr += madt_size; ++ ++ acpi_tables_size = addr - base_addr; ++ ++ BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n", ++ (unsigned long)rsdp, ++ (unsigned long)rsdt, acpi_tables_size); ++ ++ /* RSDP */ ++ memset(rsdp, 0, sizeof(*rsdp)); ++ memcpy(rsdp->signature, "RSD PTR ", 8); ++ memcpy(rsdp->oem_id, "QEMU ", 6); ++ rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr); ++ rsdp->checksum = acpi_checksum((void *)rsdp, 20); + -+ end -= start; -+ write_word(ES, DI+8, end); -+ write_word(ES, DI+10, end >> 16); -+ write_word(ES, DI+12, 0x0000); -+ write_word(ES, DI+14, 0x0000); ++ /* RSDT */ ++ rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr); ++ rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr); ++ acpi_build_table_header((struct acpi_table_header *)rsdt, ++ "RSDT", sizeof(*rsdt)); + -+ write_word(ES, DI+16, type); -+ write_word(ES, DI+18, 0x0); ++ /* FADT */ ++ memset(fadt, 0, sizeof(*fadt)); ++ fadt->firmware_ctrl = cpu_to_le32(facs_addr); ++ fadt->dsdt = cpu_to_le32(dsdt_addr); ++ fadt->model = 1; ++ fadt->reserved1 = 0; ++ fadt->sci_int = cpu_to_le16(pm_sci_int); ++ fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR); ++ fadt->acpi_enable = 0xf1; ++ fadt->acpi_disable = 0xf0; ++ fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base); ++ fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04); ++ fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08); ++ fadt->pm1_evt_len = 4; ++ fadt->pm1_cnt_len = 2; ++ fadt->pm_tmr_len = 4; ++ fadt->plvl2_lat = cpu_to_le16(50); ++ fadt->plvl3_lat = cpu_to_le16(50); ++ fadt->plvl3_lat = cpu_to_le16(50); ++ /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */ ++ fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6)); ++ acpi_build_table_header((struct acpi_table_header *)fadt, "FACP", ++ sizeof(*fadt)); ++ ++ /* FACS */ ++ memset(facs, 0, sizeof(*facs)); ++ memcpy(facs->signature, "FACS", 4); ++ facs->length = cpu_to_le32(sizeof(*facs)); ++ ++ /* DSDT */ ++ memcpy(dsdt, AmlCode, sizeof(AmlCode)); ++ ++ /* MADT */ ++ { ++ struct madt_processor_apic *apic; ++ struct madt_io_apic *io_apic; ++ ++ memset(madt, 0, madt_size); ++ madt->local_apic_address = cpu_to_le32(0xfee00000); ++ madt->flags = cpu_to_le32(1); ++ apic = (void *)(madt + 1); ++ for(i=0;itype = APIC_PROCESSOR; ++ apic->length = sizeof(*apic); ++ apic->processor_id = i; ++ apic->local_apic_id = i; ++ apic->flags = cpu_to_le32(1); ++ apic++; ++ } ++ io_apic = (void *)apic; ++ io_apic->type = APIC_IO; ++ io_apic->length = sizeof(*io_apic); ++ io_apic->io_apic_id = smp_cpus; ++ io_apic->address = cpu_to_le32(0xfec00000); ++ io_apic->interrupt = cpu_to_le32(0); ++ ++ acpi_build_table_header((struct acpi_table_header *)madt, ++ "APIC", madt_size); ++ } ++} ++ ++void rombios32_init(void) ++{ ++ BX_INFO("Starting rombios32\n"); ++ ++ ram_probe(); ++ ++ cpu_probe(); ++ ++ smp_probe(); ++ ++ pci_bios_init(); ++ ++ if (bios_table_cur_addr != 0) { ++ ++ mptable_init(); ++ ++ if (acpi_enabled) ++ acpi_bios_init(); ++ ++ bios_lock_shadow_ram(); ++ } ++} +diff -ruN --exclude Makefile bios/rombios32.ld bios.new/rombios32.ld +--- bios/rombios32.ld 1970-01-01 01:00:00.000000000 +0100 ++++ bios.new/rombios32.ld 2006-09-24 20:28:05.000000000 +0200 +@@ -0,0 +1,19 @@ ++OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") ++OUTPUT_ARCH(i386) ++ENTRY(_start); ++SECTIONS ++{ ++ . = 0x00040000; ++ .text : { *(.text) } ++ .rodata : { *(.rodata) } ++ . = ALIGN(4096); ++ .data : { *(.data) } ++ __bss_start = . ; ++ .bss : { *(.bss) *(COMMON) } ++ _end = . ; ++ /DISCARD/ : { *(.stab) ++ *(.stabstr) ++ *(.comment) ++ *(.note) ++ } +} +diff -ruN --exclude Makefile bios/rombios32start.S bios.new/rombios32start.S +--- bios/rombios32start.S 1970-01-01 01:00:00.000000000 +0100 ++++ bios.new/rombios32start.S 2006-09-24 20:22:58.000000000 +0200 +@@ -0,0 +1,76 @@ ++.globl _start ++.globl smp_ap_boot_code_start ++.globl smp_ap_boot_code_end ++.global smm_relocation_start ++.global smm_relocation_end ++.global smm_code_start ++.global smm_code_end ++ ++#define PM_IO_BASE 0xb000 ++ ++_start: ++ /* clear bss section */ ++ xor %eax, %eax ++ mov $__bss_start, %edi ++ mov $_end, %ecx ++ sub %edi, %ecx ++ rep stosb ++ ++ jmp rombios32_init ++ ++#define CPU_COUNT 0xf000 ++ ++ .code16 ++smp_ap_boot_code_start: ++ xor %ax, %ax ++ mov %ax, %ds ++ incw CPU_COUNT ++1: ++ hlt ++ jmp 1b ++smp_ap_boot_code_end: ++ ++/* code to relocate SMBASE to 0xa0000 */ ++smm_relocation_start: ++ mov $0x38000 + 0x7efc, %ebx ++ mov (%ebx), %al /* revision ID to see if x86_64 or x86 */ ++ cmp $0x64, %al ++ je 1f ++ mov $0x38000 + 0x7ef8, %ebx ++ jmp 2f ++1: ++ mov $0x38000 + 0x7f00, %ebx ++2: ++ movl $0xa0000, %eax ++ movl %eax, (%ebx) ++ rsm ++smm_relocation_end: ++ ++/* minimal SMM code to enable or disable ACPI */ ++smm_code_start: ++ movw $0xb2, %dx ++ inb %dx, %al ++ cmp $0xf0, %al ++ jne 1f ++ ++ /* ACPI disable */ ++ mov $PM_IO_BASE + 0x04, %dx /* PMCNTRL */ ++ inw %dx, %ax ++ andw $~1, %ax ++ outw %ax, %dx ++ ++ jmp 2f ++ ++1: ++ cmp $0xf1, %al ++ jne 2f ++ ++ /* ACPI enable */ ++ mov $PM_IO_BASE + 0x04, %dx /* PMCNTRL */ ++ inw %dx, %ax ++ orw $1, %ax ++ outw %ax, %dx ++ ++2: ++ rsm ++smm_code_end: +diff -ruN --exclude Makefile bios/rombios.c bios.new/rombios.c +--- bios/rombios.c 2006-08-11 19:34:12.000000000 +0200 ++++ bios.new/rombios.c 2006-09-24 20:35:47.000000000 +0200 +@@ -24,7 +24,7 @@ + // License along with this library; if not, write to the Free Software + // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-// ROM BIOS for use with Bochs/Plex x86 emulation environment ++// ROM BIOS for use with Bochs/Plex x86/QEMU emulation environment + + + // ROM BIOS compatability entry points: +@@ -143,6 +143,7 @@ + #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */ + #define BX_PCIBIOS 1 + #define BX_APM 1 ++#define BX_ROMBIOS32 1 + + #define BX_USE_ATADRV 1 + #define BX_ELTORITO_BOOT 1 +@@ -159,6 +160,9 @@ + #define BIOS_REVISION 1 + #define BIOS_CONFIG_TABLE 0xe6f5 + ++/* define it to include QEMU specific code */ ++#define BX_QEMU ++ + #ifndef BIOS_BUILD_DATE + # define BIOS_BUILD_DATE "06/23/99" + #endif +@@ -170,7 +174,9 @@ + #define BASE_MEM_IN_K (640 - EBDA_SIZE) + + // Define the application NAME +-#ifdef PLEX86 ++#if defined(BX_QEMU) ++# define BX_APPNAME "QEMU" ++#elif defined(PLEX86) + # define BX_APPNAME "Plex86" + #else + # define BX_APPNAME "Bochs" +@@ -1826,6 +1832,9 @@ + #ifdef BX_ELTORITO_BOOT + "eltorito " + #endif ++#ifdef BX_ROMBIOS32 ++ "rombios32 " ++#endif + "\n\n"); + } + +@@ -4085,6 +4094,24 @@ + case 0x20: // coded by osmaker aka K.J. + if(regs.u.r32.edx == 0x534D4150) + { ++ extended_memory_size = inb_cmos(0x35); ++ extended_memory_size <<= 8; ++ extended_memory_size |= inb_cmos(0x34); ++ extended_memory_size *= 64; ++ // greater than EFF00000??? ++ if(extended_memory_size > 0x3bc000) { ++ extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 ++ } ++ extended_memory_size *= 1024; ++ extended_memory_size += (16L * 1024 * 1024); ++ ++ if(extended_memory_size <= (16L * 1024 * 1024)) { ++ extended_memory_size = inb_cmos(0x31); ++ extended_memory_size <<= 8; ++ extended_memory_size |= inb_cmos(0x30); ++ extended_memory_size *= 1024; ++ } + - void - int15_function32(regs, ES, DS, FLAGS) - pushad_regs_t regs; // REGS pushed via pushad -@@ -4063,19 +4090,8 @@ switch(regs.u.r16.bx) { case 0: -- write_word(ES, regs.u.r16.di, 0x00); -- write_word(ES, regs.u.r16.di+2, 0x00); -- write_word(ES, regs.u.r16.di+4, 0x00); -- write_word(ES, regs.u.r16.di+6, 0x00); -- -- write_word(ES, regs.u.r16.di+8, 0xFC00); -- write_word(ES, regs.u.r16.di+10, 0x0009); -- write_word(ES, regs.u.r16.di+12, 0x0000); -- write_word(ES, regs.u.r16.di+14, 0x0000); -- -- write_word(ES, regs.u.r16.di+16, 0x1); -- write_word(ES, regs.u.r16.di+18, 0x0); -- -+ set_e820_range(ES, regs.u.r16.di, -+ 0x0000000L, 0x0009fc00L, 1); - regs.u.r32.ebx = 1; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; -@@ -4083,6 +4099,24 @@ +@@ -4115,27 +4142,9 @@ return; break; - case 1: -+ set_e820_range(ES, regs.u.r16.di, -+ 0x0009fc00L, 0x000a0000L, 2); -+ regs.u.r32.ebx = 2; -+ regs.u.r32.eax = 0x534D4150; -+ regs.u.r32.ecx = 0x14; -+ CLEAR_CF(); -+ return; -+ break; -+ case 2: -+ set_e820_range(ES, regs.u.r16.di, -+ 0x000e8000L, 0x00100000L, 2); -+ regs.u.r32.ebx = 3; -+ regs.u.r32.eax = 0x534D4150; -+ regs.u.r32.ecx = 0x14; -+ CLEAR_CF(); -+ return; -+ break; -+ case 3: - extended_memory_size = inb_cmos(0x35); - extended_memory_size <<= 8; - extended_memory_size |= inb_cmos(0x34); -@@ -4092,9 +4126,9 @@ - extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 - } - extended_memory_size *= 1024; -- extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off -+ extended_memory_size += (16L * 1024 * 1024); - -- if(extended_memory_size <= 15728640) -+ if(extended_memory_size <= (16L * 1024 * 1024)) - { - extended_memory_size = inb_cmos(0x31); - extended_memory_size <<= 8; -@@ -4102,28 +4136,23 @@ - extended_memory_size *= 1024; - } - -- write_word(ES, regs.u.r16.di, 0x0000); -- write_word(ES, regs.u.r16.di+2, 0x0010); -- write_word(ES, regs.u.r16.di+4, 0x0000); -- write_word(ES, regs.u.r16.di+6, 0x0000); -- -- write_word(ES, regs.u.r16.di+8, extended_memory_size); -- extended_memory_size >>= 16; -- write_word(ES, regs.u.r16.di+10, extended_memory_size); -- extended_memory_size >>= 16; -- write_word(ES, regs.u.r16.di+12, extended_memory_size); -- extended_memory_size >>= 16; -- write_word(ES, regs.u.r16.di+14, extended_memory_size); + case 3: +- extended_memory_size = inb_cmos(0x35); +- extended_memory_size <<= 8; +- extended_memory_size |= inb_cmos(0x34); +- extended_memory_size *= 64; +- if(extended_memory_size > 0x3bc000) // greater than EFF00000??? +- { +- extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 +- } +- extended_memory_size *= 1024; +- extended_memory_size += (16L * 1024 * 1024); - -- write_word(ES, regs.u.r16.di+16, 0x1); -- write_word(ES, regs.u.r16.di+18, 0x0); +- if(extended_memory_size <= (16L * 1024 * 1024)) +- { +- extended_memory_size = inb_cmos(0x31); +- extended_memory_size <<= 8; +- extended_memory_size |= inb_cmos(0x30); +- extended_memory_size *= 1024; +- } - -- regs.u.r32.ebx = 0; -+ set_e820_range(ES, regs.u.r16.di, -+ 0x00100000L, extended_memory_size, 1); -+ regs.u.r32.ebx = 4; + set_e820_range(ES, regs.u.r16.di, +- 0x00100000L, extended_memory_size, 1); ++ 0x00100000L, ++ extended_memory_size - 0x10000L, 1); + regs.u.r32.ebx = 4; regs.u.r32.eax = 0x534D4150; regs.u.r32.ecx = 0x14; - CLEAR_CF(); +@@ -4143,6 +4152,16 @@ return; break; -+ case 4: -+ /* 256KB BIOS area at the end of 4 GB */ + case 4: + set_e820_range(ES, regs.u.r16.di, -+ 0xfffc0000L, 0x00000000L, 2); -+ regs.u.r32.ebx = 0; ++ extended_memory_size - 0x10000L, ++ extended_memory_size, 3); // ACPI RAM ++ regs.u.r32.ebx = 5; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; - default: /* AX=E820, DX=534D4150, BX unrecognized */ - goto int15_unimplemented; - break; -@@ -8713,6 +8742,7 @@ ++ break; ++ case 5: + /* 256KB BIOS area at the end of 4 GB */ + set_e820_range(ES, regs.u.r16.di, + 0xfffc0000L, 0x00000000L, 2); +@@ -8757,6 +8776,9 @@ + unknown_service: mov al, #0x80 bios32_end: ++#ifdef BX_QEMU ++ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu ++#endif popf -+ and dword ptr[esp+4],0xfffffffc ;; reset CS.RPL for kqemu retf - .align 16 -@@ -8823,17 +8853,17 @@ +@@ -8868,6 +8890,9 @@ pci_pro_fail: pop edi pop esi -- sti ++#ifdef BX_QEMU ++ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu ++#endif popf stc -+ and dword ptr[esp+4],0xfffffffc ;; reset CS.RPL for kqemu retf - pci_pro_ok: +@@ -8875,6 +8900,9 @@ xor ah, ah pop edi pop esi -- sti ++#ifdef BX_QEMU ++ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu ++#endif popf clc -+ and dword ptr[esp+4],0xfffffffc ;; reset CS.RPL for kqemu retf +@@ -9183,227 +9211,118 @@ + db 0 ;; reserved + pci_routing_table_structure_end: + +-pci_irq_list: +- db 11, 10, 9, 5; ++#endif // BX_PCIBIOS + +-pcibios_init_sel_reg: +- push eax +- mov eax, #0x800000 +- mov ax, bx +- shl eax, #8 +- and dl, #0xfc +- or al, dl +- mov dx, #0x0cf8 +- out dx, eax +- pop eax +- ret +- +-pcibios_init_iomem_bases: +- push bp +- mov bp, sp +- mov eax, #0xe0000000 ;; base for memory init +- push eax +- mov ax, #0xc000 ;; base for i/o init +- push ax +- mov ax, #0x0010 ;; start at base address #0 ++#if BX_ROMBIOS32 ++rombios32_init: ++ ;; save a20 and enable it ++ in al, 0x92 + push ax +- mov bx, #0x0008 +-pci_init_io_loop1: +- mov dl, #0x00 +- call pcibios_init_sel_reg +- mov dx, #0x0cfc +- in ax, dx +- cmp ax, #0xffff +- jz next_pci_dev +- mov dl, #0x04 ;; disable i/o and memory space access +- call pcibios_init_sel_reg +- mov dx, #0x0cfc +- in al, dx +- and al, #0xfc +- out dx, al +-pci_init_io_loop2: +- mov dl, [bp-8] +- call pcibios_init_sel_reg +- mov dx, #0x0cfc +- in eax, dx +- test al, #0x01 +- jnz init_io_base +- mov ecx, eax +- mov eax, #0xffffffff +- out dx, eax +- in eax, dx +- cmp eax, ecx +- je next_pci_base +- xor eax, #0xffffffff +- mov ecx, eax +- mov eax, [bp-4] +- out dx, eax +- add eax, ecx ;; calculate next free mem base +- add eax, #0x01000000 +- and eax, #0xff000000 +- mov [bp-4], eax +- jmp next_pci_base +-init_io_base: +- mov cx, ax +- mov ax, #0xffff +- out dx, ax +- in ax, dx +- cmp ax, cx +- je next_pci_base +- xor ax, #0xfffe +- mov cx, ax +- mov ax, [bp-6] +- out dx, ax +- add ax, cx ;; calculate next free i/o base +- add ax, #0x0100 +- and ax, #0xff00 +- mov [bp-6], ax +-next_pci_base: +- mov al, [bp-8] +- add al, #0x04 +- cmp al, #0x28 +- je enable_iomem_space +- mov byte ptr[bp-8], al +- jmp pci_init_io_loop2 +-enable_iomem_space: +- mov dl, #0x04 ;; enable i/o and memory space access if available +- call pcibios_init_sel_reg +- mov dx, #0x0cfc +- in al, dx +- or al, #0x07 +- out dx, al +-next_pci_dev: +- mov byte ptr[bp-8], #0x10 +- inc bx +- cmp bx, #0x0100 +- jne pci_init_io_loop1 +- mov sp, bp +- pop bp +- ret ++ or al, #0x02 ++ out 0x92, al - pci_pro_select_reg: -@@ -8971,7 +9001,7 @@ - jmp pci_real_ok - pci_real_f0d: ;; write configuration dword - cmp al, #0x0d -- jne pci_real_unknown -+ jne pci_real_f0e - call pci_real_select_reg - push dx - mov dx, #0x0cfc -@@ -8979,6 +9009,46 @@ - out dx, eax - pop dx - jmp pci_real_ok -+pci_real_f0e: ;; get irq routing options -+ cmp al, #0x0e -+ jne pci_real_unknown -+ SEG ES -+ cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start -+ jb pci_real_too_small -+ SEG ES -+ mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start -+ pushf -+ push ds -+ push es -+ push cx -+ push si -+ push di +-pcibios_init_set_elcr: +- push ax +- push cx +- mov dx, #0x04d0 +- test al, #0x08 +- jz is_master_pic +- inc dx +- and al, #0x07 +-is_master_pic: +- mov cl, al +- mov bl, #0x01 +- shl bl, cl +- in al, dx +- or al, bl +- out dx, al +- pop cx +- pop ax +- ret ++ ;; save SS:SP to the BDA ++ xor ax, ax ++ mov ds, ax ++ mov 0x0469, ss ++ mov 0x0467, sp + +-pcibios_init_irqs: +- push ds +- push bp +- mov ax, #0xf000 +- mov ds, ax +- mov dx, #0x04d0 ;; reset ELCR1 + ELCR2 +- mov al, #0x00 +- out dx, al +- inc dx +- out dx, al +- mov si, #pci_routing_table_structure +- mov bh, [si+8] +- mov bl, [si+9] +- mov dl, #0x00 +- call pcibios_init_sel_reg +- mov dx, #0x0cfc +- in eax, dx +- cmp eax, [si+12] ;; check irq router +- jne pci_init_end +- mov dl, [si+34] +- call pcibios_init_sel_reg +- push bx ;; save irq router bus + devfunc +- mov dx, #0x0cfc +- mov ax, #0x8080 +- out dx, ax ;; reset PIRQ route control +- inc dx +- inc dx +- out dx, ax +- mov ax, [si+6] +- sub ax, #0x20 +- shr ax, #4 +- mov cx, ax +- add si, #0x20 ;; set pointer to 1st entry +- mov bp, sp +- mov ax, #pci_irq_list +- push ax +- xor ax, ax +- push ax +-pci_init_irq_loop1: +- mov bh, [si] +- mov bl, [si+1] +-pci_init_irq_loop2: +- mov dl, #0x00 +- call pcibios_init_sel_reg +- mov dx, #0x0cfc +- in ax, dx +- cmp ax, #0xffff +- jnz pci_test_int_pin +- test bl, #0x07 +- jz next_pir_entry +- jmp next_pci_func +-pci_test_int_pin: +- mov dl, #0x3c +- call pcibios_init_sel_reg +- mov dx, #0x0cfd +- in al, dx +- and al, #0x07 +- jz next_pci_func +- dec al ;; determine pirq reg +- mov dl, #0x03 +- mul al, dl +- add al, #0x02 +- xor ah, ah +- mov bx, ax +- mov al, [si+bx] +- mov dl, al +- mov bx, [bp] +- call pcibios_init_sel_reg +- mov dx, #0x0cfc +- and al, #0x03 +- add dl, al +- in al, dx +- cmp al, #0x80 +- jb pirq_found +- mov bx, [bp-2] ;; pci irq list pointer +- mov al, [bx] +- out dx, al +- inc bx +- mov [bp-2], bx +- call pcibios_init_set_elcr +-pirq_found: +- mov bh, [si] +- mov bl, [si+1] +- add bl, [bp-3] ;; pci function number +- mov dl, #0x3c +- call pcibios_init_sel_reg +- mov dx, #0x0cfc +- out dx, al +-next_pci_func: +- inc byte ptr[bp-3] +- inc bl +- test bl, #0x07 +- jnz pci_init_irq_loop2 +-next_pir_entry: +- add si, #0x10 +- mov byte ptr[bp-3], #0x00 +- loop pci_init_irq_loop1 +- mov sp, bp +- pop bx +-pci_init_end: +- pop bp +- pop ds ++ SEG CS ++ lidt [pmode_IDT_info] ++ SEG CS ++ lgdt [rombios32_gdt_48] ++ ;; set PE bit in CR0 ++ mov eax, cr0 ++ or al, #0x01 ++ mov cr0, eax ++ ;; start protected mode code: ljmpl 0x10:rombios32_init1 ++ db 0x66, 0xea ++ dw rombios32_05 ++ dw 0x000f ;; high 16 bit address ++ dw 0x0010 ++ ++use32 386 ++rombios32_05: ++ ;; init data segments ++ mov eax, #0x18 ++ mov ds, ax ++ mov es, ax ++ mov ss, ax ++ xor eax, eax ++ mov fs, ax ++ mov gs, ax + cld -+ mov si, #pci_routing_table_structure_start -+ push cs -+ pop ds -+ SEG ES -+ mov cx, [di+2] -+ SEG ES -+ mov es, [di+4] -+ mov di, cx -+ mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start ++ ++ ;; copy rombios32 code to ram (ram offset = 1MB) ++ mov esi, #0xfffe0000 ++ mov edi, #0x00040000 ++ mov ecx, #0x10000 / 4 + rep -+ movsb -+ pop di -+ pop si -+ pop cx -+ pop es -+ pop ds -+ popf -+ mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used -+ jmp pci_real_ok -+pci_real_too_small: -+ SEG ES -+ mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start -+ mov ah, #0x89 -+ jmp pci_real_fail -+ - pci_real_unknown: - mov ah, #0x81 - pci_real_fail: -@@ -9019,6 +9089,7 @@ - dw 0,0 ;; Miniport data - db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved - db 0x07 ;; checksum -+pci_routing_table_structure_start: - ;; first slot entry PCI-to-ISA (embedded) - db 0 ;; pci bus number - db 0x08 ;; pci device number (bit 7-3) -@@ -9097,6 +9168,7 @@ - dw 0xdef8 ;; IRQ bitmap INTD# - db 5 ;; physical slot (0 = embedded) - db 0 ;; reserved -+pci_routing_table_structure_end: ++ movsd ++ ++ ;; init the stack pointer ++ mov esp, #0x00080000 ++ ++ ;; call rombios32 code ++ mov eax, #0x00040000 ++ call eax ++ ++ ;; return to 16 bit protected mode first ++ db 0xea ++ dd rombios32_10 ++ dw 0x20 ++ ++use16 386 ++rombios32_10: ++ ;; restore data segment limits to 0xffff ++ mov ax, #0x28 ++ mov ds, ax ++ mov es, ax ++ mov ss, ax ++ mov fs, ax ++ mov gs, ax ++ ++ ;; reset PE bit in CR0 ++ mov eax, cr0 ++ and al, #0xFE ++ mov cr0, eax ++ ++ ;; far jump to flush CPU queue after transition to real mode ++ JMP_AP(0xf000, rombios32_real_mode) ++ ++rombios32_real_mode: ++ ;; restore IDT to normal real-mode defaults ++ SEG CS ++ lidt [rmode_IDT_info] ++ ++ xor ax, ax ++ mov ds, ax ++ mov es, ax ++ mov fs, ax ++ mov gs, ax ++ ++ ;; restore SS:SP from the BDA ++ mov ss, 0x0469 ++ mov sp, 0x0467 ++ ;; restore a20 ++ pop ax ++ out 0x92, al + ret +-#endif // BX_PCIBIOS ++ ++rombios32_gdt_48: ++ dw 0x30 ++ dw rombios32_gdt ++ dw 0x000f ++ ++rombios32_gdt: ++ dw 0, 0, 0, 0 ++ dw 0, 0, 0, 0 ++ dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10) ++ dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18) ++ dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff ++ dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff ++#endif ++ + + ; parallel port detection: base address in DX, index in BX, timeout in CL + detect_parport: +@@ -9535,10 +9454,17 @@ + ;; DATA_SEG_DEFS_HERE + + ++;; the following area can be used to write dynamically generated tables ++ .align 16 ++bios_table_area_start: ++ dd 0xaafb4442 ++ dd bios_table_area_end - bios_table_area_start - 8; ++ + ;-------- + ;- POST - + ;-------- + .org 0xe05b ; POST Entry Point ++bios_table_area_end: + post: + + xor ax, ax +@@ -9802,9 +9728,9 @@ + #endif + out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14 + +- call pcibios_init_iomem_bases +- call pcibios_init_irqs +- ++#if BX_ROMBIOS32 ++ call rombios32_init ++#endif + call rom_scan - pci_irq_list: - db 11, 10, 9, 5; + call _print_bios_banner -- cgit v1.2.3 From ba86345802fcede0b0f50393c97c128aa7a3f40c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:41:10 +0000 Subject: added cpu_get_physical_page_desc() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2168 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/exec.c b/exec.c index 88acff091..20870ad02 100644 --- a/exec.c +++ b/exec.c @@ -1801,6 +1801,17 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, } } +/* XXX: temporary until new memory mapping API */ +uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr) +{ + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) + return IO_MEM_UNASSIGNED; + return p->phys_offset; +} + static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) { return 0; -- cgit v1.2.3 From 3b21e03e043236a0569383ff5d677c336e3d8b3a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:41:56 +0000 Subject: added SMM support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2169 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 2 + cpu-exec.c | 12 ++- target-i386/cpu.h | 4 + target-i386/exec.h | 2 + target-i386/helper.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/helper2.c | 9 +- target-i386/op.c | 5 + target-i386/translate.c | 11 ++ vl.c | 5 +- 9 files changed, 307 insertions(+), 6 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 996289eaf..a8628b502 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -762,6 +762,7 @@ extern int code_copy_enabled; #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); @@ -839,6 +840,7 @@ 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, diff --git a/cpu-exec.c b/cpu-exec.c index 6385639f4..0b5f7f3d8 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -458,8 +458,16 @@ int cpu_exec(CPUState *env1) interrupt_request = env->interrupt_request; if (__builtin_expect(interrupt_request, 0)) { #if defined(TARGET_I386) - /* if hardware interrupt pending, we execute it */ - if ((interrupt_request & CPU_INTERRUPT_HARD) && + 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; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2f2361730..55e7a98c5 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -142,6 +142,7 @@ #define HF_OSFXSR_SHIFT 16 /* CR4.OSFXSR */ #define HF_VM_SHIFT 17 /* must be same as eflags */ #define HF_HALTED_SHIFT 18 /* CPU halted */ +#define HF_SMM_SHIFT 19 /* CPU in SMM mode */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) @@ -158,6 +159,7 @@ #define HF_CS64_MASK (1 << HF_CS64_SHIFT) #define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT) #define HF_HALTED_MASK (1 << HF_HALTED_SHIFT) +#define HF_SMM_MASK (1 << HF_SMM_SHIFT) #define CR0_PE_MASK (1 << 0) #define CR0_MP_MASK (1 << 1) @@ -503,6 +505,7 @@ typedef struct CPUX86State { int exception_is_int; target_ulong exception_next_eip; target_ulong dr[8]; /* debug registers */ + uint32_t smbase; int interrupt_request; int user_mode_only; /* user mode only simulation */ @@ -630,6 +633,7 @@ void cpu_set_apic_tpr(CPUX86State *env, uint8_t val); #ifndef NO_CPU_IO_DEFS uint8_t cpu_get_apic_tpr(CPUX86State *env); #endif +void cpu_smm_update(CPUX86State *env); /* will be suppressed */ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); diff --git a/target-i386/exec.h b/target-i386/exec.h index 609a5869a..377f7bd28 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -176,6 +176,7 @@ void raise_interrupt(int intno, int is_int, int error_code, int next_eip_addend); void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); +void do_smm_enter(void); void __hidden cpu_loop_exit(void); void OPPROTO op_movl_eflags_T0(void); @@ -203,6 +204,7 @@ void helper_lsl(void); void helper_lar(void); void helper_verr(void); void helper_verw(void); +void helper_rsm(void); void check_iob_T0(void); void check_iow_T0(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 70e9fae3b..d990c07ed 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1215,6 +1215,269 @@ void raise_exception(int exception_index) raise_interrupt(exception_index, 0, 0, 0); } +/* SMM support */ + +#ifdef TARGET_X86_64 +#define SMM_REVISION_ID 0x00020064 +#else +#define SMM_REVISION_ID 0x00020000 +#endif + +void do_smm_enter(void) +{ + target_ulong sm_state; + SegmentCache *dt; + int i, offset; + + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "SMM: enter\n"); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); + } + + env->hflags |= HF_SMM_MASK; + cpu_smm_update(env); + + sm_state = env->smbase + 0x8000; + +#ifdef TARGET_X86_64 + for(i = 0; i < 6; i++) { + dt = &env->segs[i]; + offset = 0x7e00 + i * 16; + stw_phys(sm_state + offset, dt->selector); + stw_phys(sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff); + stl_phys(sm_state + offset + 4, dt->limit); + stq_phys(sm_state + offset + 8, dt->base); + } + + stq_phys(sm_state + 0x7e68, env->gdt.base); + stl_phys(sm_state + 0x7e64, env->gdt.limit); + + stw_phys(sm_state + 0x7e70, env->ldt.selector); + stq_phys(sm_state + 0x7e78, env->ldt.base); + stl_phys(sm_state + 0x7e74, env->ldt.limit); + stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); + + stq_phys(sm_state + 0x7e88, env->idt.base); + stl_phys(sm_state + 0x7e84, env->idt.limit); + + stw_phys(sm_state + 0x7e90, env->tr.selector); + stq_phys(sm_state + 0x7e98, env->tr.base); + stl_phys(sm_state + 0x7e94, env->tr.limit); + stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); + + stq_phys(sm_state + 0x7ed0, env->efer); + + stq_phys(sm_state + 0x7ff8, EAX); + stq_phys(sm_state + 0x7ff0, ECX); + stq_phys(sm_state + 0x7fe8, EDX); + stq_phys(sm_state + 0x7fe0, EBX); + stq_phys(sm_state + 0x7fd8, ESP); + stq_phys(sm_state + 0x7fd0, EBP); + stq_phys(sm_state + 0x7fc8, ESI); + stq_phys(sm_state + 0x7fc0, EDI); + for(i = 8; i < 16; i++) + stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]); + stq_phys(sm_state + 0x7f78, env->eip); + stl_phys(sm_state + 0x7f70, compute_eflags()); + stl_phys(sm_state + 0x7f68, env->dr[6]); + stl_phys(sm_state + 0x7f60, env->dr[7]); + + stl_phys(sm_state + 0x7f48, env->cr[4]); + stl_phys(sm_state + 0x7f50, env->cr[3]); + stl_phys(sm_state + 0x7f58, env->cr[0]); + + stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); + stl_phys(sm_state + 0x7f00, env->smbase); +#else + stl_phys(sm_state + 0x7ffc, env->cr[0]); + stl_phys(sm_state + 0x7ff8, env->cr[3]); + stl_phys(sm_state + 0x7ff4, compute_eflags()); + stl_phys(sm_state + 0x7ff0, env->eip); + stl_phys(sm_state + 0x7fec, EDI); + stl_phys(sm_state + 0x7fe8, ESI); + stl_phys(sm_state + 0x7fe4, EBP); + stl_phys(sm_state + 0x7fe0, ESP); + stl_phys(sm_state + 0x7fdc, EBX); + stl_phys(sm_state + 0x7fd8, EDX); + stl_phys(sm_state + 0x7fd4, ECX); + stl_phys(sm_state + 0x7fd0, EAX); + stl_phys(sm_state + 0x7fcc, env->dr[6]); + stl_phys(sm_state + 0x7fc8, env->dr[7]); + + stl_phys(sm_state + 0x7fc4, env->tr.selector); + stl_phys(sm_state + 0x7f64, env->tr.base); + stl_phys(sm_state + 0x7f60, env->tr.limit); + stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); + + stl_phys(sm_state + 0x7fc0, env->ldt.selector); + stl_phys(sm_state + 0x7f80, env->ldt.base); + stl_phys(sm_state + 0x7f7c, env->ldt.limit); + stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); + + stl_phys(sm_state + 0x7f74, env->gdt.base); + stl_phys(sm_state + 0x7f70, env->gdt.limit); + + stl_phys(sm_state + 0x7f58, env->idt.base); + stl_phys(sm_state + 0x7f54, env->idt.limit); + + for(i = 0; i < 6; i++) { + dt = &env->segs[i]; + if (i < 3) + offset = 0x7f84 + i * 12; + else + offset = 0x7f2c + (i - 3) * 12; + stl_phys(sm_state + 0x7fa8 + i * 4, dt->selector); + stl_phys(sm_state + offset + 8, dt->base); + stl_phys(sm_state + offset + 4, dt->limit); + stl_phys(sm_state + offset, (dt->flags >> 8) & 0xf0ff); + } + stl_phys(sm_state + 0x7f14, env->cr[4]); + + stl_phys(sm_state + 0x7efc, SMM_REVISION_ID); + stl_phys(sm_state + 0x7ef8, env->smbase); +#endif + /* init SMM cpu state */ + + load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + env->eip = 0x00008000; + cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, + 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0); + cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); + + cpu_x86_update_cr0(env, + env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); + cpu_x86_update_cr4(env, 0); + env->dr[7] = 0x00000400; +#ifdef TARGET_X86_64 + env->efer = 0; +#endif + CC_OP = CC_OP_EFLAGS; +} + +void helper_rsm(void) +{ + target_ulong sm_state; + int i, offset; + uint32_t val; + + sm_state = env->smbase + 0x8000; +#ifdef TARGET_X86_64 + for(i = 0; i < 6; i++) { + offset = 0x7e00 + i * 16; + cpu_x86_load_seg_cache(env, i, + lduw_phys(sm_state + offset), + ldq_phys(sm_state + offset + 8), + ldl_phys(sm_state + offset + 4), + (lduw_phys(sm_state + offset + 2) & 0xf0ff) << 8); + } + + env->gdt.base = ldq_phys(sm_state + 0x7e68); + env->gdt.limit = ldl_phys(sm_state + 0x7e64); + + env->ldt.selector = lduw_phys(sm_state + 0x7e70); + env->ldt.base = ldq_phys(sm_state + 0x7e78); + env->ldt.limit = ldl_phys(sm_state + 0x7e74); + env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8; + + env->idt.base = ldq_phys(sm_state + 0x7e88); + env->idt.limit = ldl_phys(sm_state + 0x7e84); + + env->tr.selector = lduw_phys(sm_state + 0x7e90); + env->tr.base = ldq_phys(sm_state + 0x7e98); + env->tr.limit = ldl_phys(sm_state + 0x7e94); + env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8; + + env->efer = ldq_phys(sm_state + 0x7ed0); + + EAX = ldq_phys(sm_state + 0x7ff8); + ECX = ldq_phys(sm_state + 0x7ff0); + EDX = ldq_phys(sm_state + 0x7fe8); + EBX = ldq_phys(sm_state + 0x7fe0); + ESP = ldq_phys(sm_state + 0x7fd8); + EBP = ldq_phys(sm_state + 0x7fd0); + ESI = ldq_phys(sm_state + 0x7fc8); + EDI = ldq_phys(sm_state + 0x7fc0); + for(i = 8; i < 16; i++) + env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8); + env->eip = ldq_phys(sm_state + 0x7f78); + load_eflags(ldl_phys(sm_state + 0x7f70), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + env->dr[6] = ldl_phys(sm_state + 0x7f68); + env->dr[7] = ldl_phys(sm_state + 0x7f60); + + cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f48)); + cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7f50)); + cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7f58)); + + val = ldl_phys(sm_state + 0x7efc); /* revision ID */ + if (val & 0x20000) { + env->smbase = ldl_phys(sm_state + 0x7f00) & ~0x7fff; + } +#else + cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc)); + cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8)); + load_eflags(ldl_phys(sm_state + 0x7ff4), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + env->eip = ldl_phys(sm_state + 0x7ff0); + EDI = ldl_phys(sm_state + 0x7fec); + ESI = ldl_phys(sm_state + 0x7fe8); + EBP = ldl_phys(sm_state + 0x7fe4); + ESP = ldl_phys(sm_state + 0x7fe0); + EBX = ldl_phys(sm_state + 0x7fdc); + EDX = ldl_phys(sm_state + 0x7fd8); + ECX = ldl_phys(sm_state + 0x7fd4); + EAX = ldl_phys(sm_state + 0x7fd0); + env->dr[6] = ldl_phys(sm_state + 0x7fcc); + env->dr[7] = ldl_phys(sm_state + 0x7fc8); + + env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff; + env->tr.base = ldl_phys(sm_state + 0x7f64); + env->tr.limit = ldl_phys(sm_state + 0x7f60); + env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8; + + env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff; + env->ldt.base = ldl_phys(sm_state + 0x7f80); + env->ldt.limit = ldl_phys(sm_state + 0x7f7c); + env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8; + + env->gdt.base = ldl_phys(sm_state + 0x7f74); + env->gdt.limit = ldl_phys(sm_state + 0x7f70); + + env->idt.base = ldl_phys(sm_state + 0x7f58); + env->idt.limit = ldl_phys(sm_state + 0x7f54); + + for(i = 0; i < 6; i++) { + if (i < 3) + offset = 0x7f84 + i * 12; + else + offset = 0x7f2c + (i - 3) * 12; + cpu_x86_load_seg_cache(env, i, + ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff, + ldl_phys(sm_state + offset + 8), + ldl_phys(sm_state + offset + 4), + (ldl_phys(sm_state + offset) & 0xf0ff) << 8); + } + cpu_x86_update_cr4(env, ldl_phys(sm_state + 0x7f14)); + + val = ldl_phys(sm_state + 0x7efc); /* revision ID */ + if (val & 0x20000) { + env->smbase = ldl_phys(sm_state + 0x7ef8) & ~0x7fff; + } +#endif + CC_OP = CC_OP_EFLAGS; + env->hflags &= ~HF_SMM_MASK; + cpu_smm_update(env); + + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "SMM: after RSM\n"); + cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); + } +} + #ifdef BUGGY_GCC_DIV64 /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we call it from another function */ diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 19af159f9..f05ae4a69 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -161,7 +161,8 @@ void cpu_reset(CPUX86State *env) cpu_x86_update_cr0(env, 0x60000010); env->a20_mask = 0xffffffff; - + env->smbase = 0x30000; + env->idt.limit = 0xffff; env->gdt.limit = 0xffff; env->ldt.limit = 0xffff; @@ -268,7 +269,7 @@ void cpu_dump_state(CPUState *env, FILE *f, "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" - "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n", + "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], @@ -296,13 +297,14 @@ void cpu_dump_state(CPUState *env, FILE *f, env->hflags & HF_CPL_MASK, (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, (env->a20_mask >> 20) & 1, + (env->hflags >> HF_SMM_SHIFT) & 1, (env->hflags >> HF_HALTED_SHIFT) & 1); } else #endif { cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n", + "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_EBX], (uint32_t)env->regs[R_ECX], @@ -322,6 +324,7 @@ void cpu_dump_state(CPUState *env, FILE *f, env->hflags & HF_CPL_MASK, (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, (env->a20_mask >> 20) & 1, + (env->hflags >> HF_SMM_SHIFT) & 1, (env->hflags >> HF_HALTED_SHIFT) & 1); } diff --git a/target-i386/op.c b/target-i386/op.c index 7a3aa7727..7c20f524f 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -678,6 +678,11 @@ void OPPROTO op_reset_inhibit_irq(void) env->hflags &= ~HF_INHIBIT_IRQ_MASK; } +void OPPROTO op_rsm(void) +{ + helper_rsm(); +} + #if 0 /* vm86plus instructions */ void OPPROTO op_cli_vm(void) diff --git a/target-i386/translate.c b/target-i386/translate.c index 5c6453d4f..ad18af975 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6012,6 +6012,17 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_lea_modrm(s, modrm, ®_addr, &offset_addr); /* ignore for now */ break; + case 0x1aa: /* rsm */ + if (!(s->flags & HF_SMM_MASK)) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(s->pc - s->cs_base); + gen_op_rsm(); + gen_eob(s); + break; case 0x110 ... 0x117: case 0x128 ... 0x12f: case 0x150 ... 0x177: diff --git a/vl.c b/vl.c index d3efbbd4b..c30bb6b4d 100644 --- a/vl.c +++ b/vl.c @@ -4881,6 +4881,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be64s(f, &env->fmask); qemu_put_be64s(f, &env->kernelgsbase); #endif + qemu_put_be32s(f, &env->smbase); } #ifdef USE_X86LDOUBLE @@ -4914,7 +4915,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) uint32_t hflags; uint16_t fpus, fpuc, fptag, fpregs_format; - if (version_id != 3) + if (version_id != 3 && version_id != 4) return -EINVAL; for(i = 0; i < CPU_NB_REGS; i++) qemu_get_betls(f, &env->regs[i]); @@ -5017,6 +5018,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be64s(f, &env->fmask); qemu_get_be64s(f, &env->kernelgsbase); #endif + if (version_id >= 4) + qemu_get_be32s(f, &env->smbase); /* XXX: compute hflags from scratch, except for CPL and IIF */ env->hflags = hflags; -- cgit v1.2.3 From ab1e34add6735b5d2c1300426e8143399bc27dd8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:44:17 +0000 Subject: moved ACPI table init to BIOS - preliminary SMM support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2170 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi.c | 492 +++++++++++++++----------------------------------------------- 1 file changed, 113 insertions(+), 379 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 6c20a4e93..76a9ce587 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -19,13 +19,11 @@ #include "vl.h" //#define DEBUG +#define USE_SMM /* i82731AB (PIIX4) compatible power management function */ #define PM_FREQ 3579545 -/* XXX: make them variable */ -#define PM_IO_BASE 0xb000 -#define SMI_CMD_IO_ADDR 0xb040 #define ACPI_DBG_IO_ADDR 0xb044 typedef struct PIIX4PMState { @@ -33,6 +31,8 @@ typedef struct PIIX4PMState { uint16_t pmsts; uint16_t pmen; uint16_t pmcntrl; + uint8_t apmc; + uint8_t apms; QEMUTimer *tmr_timer; int64_t tmr_overflow_time; } PIIX4PMState; @@ -46,10 +46,6 @@ typedef struct PIIX4PMState { #define SUS_EN (1 << 13) -/* Note: only used for ACPI bios init. Could be deleted when ACPI init - is integrated in Bochs BIOS */ -static PIIX4PMState *piix4_pm_state; - static uint32_t get_pmtmr(PIIX4PMState *s) { uint32_t d; @@ -195,22 +191,50 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) return val; } -static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) +static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val) { PIIX4PMState *s = opaque; + addr &= 1; #ifdef DEBUG - printf("SMI cmd val=0x%02x\n", val); + printf("pm_smi_writeb addr=0x%x val=0x%02x\n", addr, val); #endif - switch(val) { - case 0xf0: /* ACPI disable */ - s->pmcntrl &= ~SCI_EN; - break; - case 0xf1: /* ACPI enable */ - s->pmcntrl |= SCI_EN; - break; + if (addr == 0) { + s->apmc = val; +#ifdef USE_SMM + cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); +#else + /* emulation of what the SMM BIOS should do */ + switch(val) { + case 0xf0: /* ACPI disable */ + s->pmcntrl &= ~SCI_EN; + break; + case 0xf1: /* ACPI enable */ + s->pmcntrl |= SCI_EN; + break; + } +#endif + } else { + s->apms = val; } } +static uint32_t pm_smi_readb(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val; + + addr &= 1; + if (addr == 0) { + val = s->apmc; + } else { + val = s->apms; + } +#ifdef DEBUG + printf("pm_smi_readb addr=0x%x val=0x%02x\n", addr, val); +#endif + return val; +} + static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) { #if defined(DEBUG) @@ -218,17 +242,81 @@ static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) #endif } -/* XXX: we still add it to the PIIX3 and we count on the fact that - OSes are smart enough to accept this strange configuration */ +static void pm_io_space_update(PIIX4PMState *s) +{ + uint32_t pm_io_base; + + if (s->dev.config[0x80] & 1) { + pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); + pm_io_base &= 0xfffe; + + /* XXX: need to improve memory and ioport allocation */ +#if defined(DEBUG) + printf("PM: mapping to 0x%x\n", pm_io_base); +#endif + register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); + register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); + register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); + register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); + } +} + +static void pm_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + pci_default_write_config(d, address, val, len); + if (address == 0x80) + pm_io_space_update((PIIX4PMState *)d); +} + +static void pm_save(QEMUFile* f,void *opaque) +{ + PIIX4PMState *s = opaque; + + pci_device_save(&s->dev, f); + + qemu_put_be16s(f, &s->pmsts); + qemu_put_be16s(f, &s->pmen); + qemu_put_be16s(f, &s->pmcntrl); + qemu_put_8s(f, &s->apmc); + qemu_put_8s(f, &s->apms); + qemu_put_timer(f, s->tmr_timer); + qemu_put_be64s(f, &s->tmr_overflow_time); +} + +static int pm_load(QEMUFile* f,void* opaque,int version_id) +{ + PIIX4PMState *s = opaque; + int ret; + + if (version_id > 1) + return -EINVAL; + + ret = pci_device_load(&s->dev, f); + if (ret < 0) + return ret; + + qemu_get_be16s(f, &s->pmsts); + qemu_get_be16s(f, &s->pmen); + qemu_get_be16s(f, &s->pmcntrl); + qemu_get_8s(f, &s->apmc); + qemu_get_8s(f, &s->apms); + qemu_get_timer(f, s->tmr_timer); + qemu_get_be64s(f, &s->tmr_overflow_time); + + pm_io_space_update(s); + + return 0; +} + void piix4_pm_init(PCIBus *bus, int devfn) { PIIX4PMState *s; uint8_t *pci_conf; - uint32_t pm_io_base; s = (PIIX4PMState *)pci_register_device(bus, "PM", sizeof(PIIX4PMState), - devfn, NULL, NULL); + devfn, NULL, pm_write_config); pci_conf = s->dev.config; pci_conf[0x00] = 0x86; pci_conf[0x01] = 0x80; @@ -241,15 +329,11 @@ void piix4_pm_init(PCIBus *bus, int devfn) pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 0x01; // interrupt pin 1 - pm_io_base = PM_IO_BASE; - pci_conf[0x40] = pm_io_base | 1; - pci_conf[0x41] = pm_io_base >> 8; - register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); - register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); - register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); - register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); + pci_conf[0x40] = 0x01; /* PM io base read only bit */ - register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s); + register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s); + register_ioport_read(0xb2, 2, 1, pm_smi_readb, s); + register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); /* XXX: which specification is used ? The i82731AB has different @@ -260,356 +344,6 @@ void piix4_pm_init(PCIBus *bus, int devfn) (serial_hds[1] != NULL ? 0x90 : 0); s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); - piix4_pm_state = s; -} - -/* ACPI tables */ -/* XXX: move them in the Bochs BIOS ? */ - -/*************************************************/ - -/* Table structure from Linux kernel (the ACPI tables are under the - BSD license) */ - -#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ - uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\ - uint32_t length; /* Length of table, in bytes, including header */\ - uint8_t revision; /* ACPI Specification minor version # */\ - uint8_t checksum; /* To make sum of entire table == 0 */\ - uint8_t oem_id [6]; /* OEM identification */\ - uint8_t oem_table_id [8]; /* OEM table identification */\ - uint32_t oem_revision; /* OEM revision number */\ - uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\ - uint32_t asl_compiler_revision; /* ASL compiler revision number */ - - -struct acpi_table_header /* ACPI common table header */ -{ - ACPI_TABLE_HEADER_DEF -}; - -struct rsdp_descriptor /* Root System Descriptor Pointer */ -{ - uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */ - uint8_t checksum; /* To make sum of struct == 0 */ - uint8_t oem_id [6]; /* OEM identification */ - uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ - uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */ - uint32_t length; /* XSDT Length in bytes including hdr */ - uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */ - uint8_t extended_checksum; /* Checksum of entire table */ - uint8_t reserved [3]; /* Reserved field must be 0 */ -}; -/* - * ACPI 1.0 Root System Description Table (RSDT) - */ -struct rsdt_descriptor_rev1 -{ - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - uint32_t table_offset_entry [2]; /* Array of pointers to other */ - /* ACPI tables */ -}; - -/* - * ACPI 1.0 Firmware ACPI Control Structure (FACS) - */ -struct facs_descriptor_rev1 -{ - uint8_t signature[4]; /* ACPI Signature */ - uint32_t length; /* Length of structure, in bytes */ - uint32_t hardware_signature; /* Hardware configuration signature */ - uint32_t firmware_waking_vector; /* ACPI OS waking vector */ - uint32_t global_lock; /* Global Lock */ - uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */ - uint32_t reserved1 : 31; /* Must be 0 */ - uint8_t resverved3 [40]; /* Reserved - must be zero */ -}; - - -/* - * ACPI 1.0 Fixed ACPI Description Table (FADT) - */ -struct fadt_descriptor_rev1 -{ - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - uint32_t firmware_ctrl; /* Physical address of FACS */ - uint32_t dsdt; /* Physical address of DSDT */ - uint8_t model; /* System Interrupt Model */ - uint8_t reserved1; /* Reserved */ - uint16_t sci_int; /* System vector of SCI interrupt */ - uint32_t smi_cmd; /* Port address of SMI command port */ - uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */ - uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */ - uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - uint8_t reserved2; /* Reserved - must be zero */ - uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ - uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ - uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ - uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ - uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ - uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ - uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ - uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ - uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ - uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ - uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ - uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ - uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */ - uint8_t reserved3; /* Reserved */ - uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ - uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ - uint16_t flush_size; /* Size of area read to flush caches */ - uint16_t flush_stride; /* Stride used in flushing caches */ - uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */ - uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */ - uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ - uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ - uint8_t century; /* Index to century in RTC CMOS RAM */ - uint8_t reserved4; /* Reserved */ - uint8_t reserved4a; /* Reserved */ - uint8_t reserved4b; /* Reserved */ -#if 0 - uint32_t wb_invd : 1; /* The wbinvd instruction works properly */ - uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ - uint32_t proc_c1 : 1; /* All processors support C1 state */ - uint32_t plvl2_up : 1; /* C2 state works on MP system */ - uint32_t pwr_button : 1; /* Power button is handled as a generic feature */ - uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ - uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ - uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ - uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */ - uint32_t reserved5 : 23; /* Reserved - must be zero */ -#else - uint32_t flags; -#endif -}; - -/* - * MADT values and structures - */ - -/* Values for MADT PCATCompat */ - -#define DUAL_PIC 0 -#define MULTIPLE_APIC 1 - - -/* Master MADT */ - -struct multiple_apic_table -{ - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - uint32_t local_apic_address; /* Physical address of local APIC */ -#if 0 - uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */ - uint32_t reserved1 : 31; -#else - uint32_t flags; -#endif -}; - - -/* Values for Type in APIC_HEADER_DEF */ - -#define APIC_PROCESSOR 0 -#define APIC_IO 1 -#define APIC_XRUPT_OVERRIDE 2 -#define APIC_NMI 3 -#define APIC_LOCAL_NMI 4 -#define APIC_ADDRESS_OVERRIDE 5 -#define APIC_IO_SAPIC 6 -#define APIC_LOCAL_SAPIC 7 -#define APIC_XRUPT_SOURCE 8 -#define APIC_RESERVED 9 /* 9 and greater are reserved */ - -/* - * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) - */ -#define APIC_HEADER_DEF /* Common APIC sub-structure header */\ - uint8_t type; \ - uint8_t length; - -/* Sub-structures for MADT */ - -struct madt_processor_apic -{ - APIC_HEADER_DEF - uint8_t processor_id; /* ACPI processor id */ - uint8_t local_apic_id; /* Processor's local APIC id */ -#if 0 - uint32_t processor_enabled: 1; /* Processor is usable if set */ - uint32_t reserved2 : 31; /* Reserved, must be zero */ -#else - uint32_t flags; -#endif -}; - -struct madt_io_apic -{ - APIC_HEADER_DEF - uint8_t io_apic_id; /* I/O APIC ID */ - uint8_t reserved; /* Reserved - must be zero */ - uint32_t address; /* APIC physical address */ - uint32_t interrupt; /* Global system interrupt where INTI - * lines start */ -}; - -#include "acpi-dsdt.hex" - -static int acpi_checksum(const uint8_t *data, int len) -{ - int sum, i; - sum = 0; - for(i = 0; i < len; i++) - sum += data[i]; - return (-sum) & 0xff; -} - -static void acpi_build_table_header(struct acpi_table_header *h, - char *sig, int len) -{ - memcpy(h->signature, sig, 4); - h->length = cpu_to_le32(len); - h->revision = 0; - memcpy(h->oem_id, "QEMU ", 6); - memcpy(h->oem_table_id, "QEMU", 4); - memcpy(h->oem_table_id + 4, sig, 4); - h->oem_revision = cpu_to_le32(1); - memcpy(h->asl_compiler_id, "QEMU", 4); - h->asl_compiler_revision = cpu_to_le32(1); - h->checksum = acpi_checksum((void *)h, len); -} - -#define ACPI_TABLES_BASE 0x000e8000 - -/* base_addr must be a multiple of 4KB */ -void acpi_bios_init(void) -{ - struct rsdp_descriptor *rsdp; - struct rsdt_descriptor_rev1 *rsdt; - struct fadt_descriptor_rev1 *fadt; - struct facs_descriptor_rev1 *facs; - struct multiple_apic_table *madt; - uint8_t *dsdt; - uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr; - uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size; - int i; - - /* compute PCI I/O addresses */ - pm_io_base = (piix4_pm_state->dev.config[0x40] | - (piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f; - - base_addr = ACPI_TABLES_BASE; - - /* reserve memory space for tables */ - addr = base_addr; - rsdp = (void *)(phys_ram_base + addr); - addr += sizeof(*rsdp); - - rsdt_addr = addr; - rsdt = (void *)(phys_ram_base + addr); - addr += sizeof(*rsdt); - - fadt_addr = addr; - fadt = (void *)(phys_ram_base + addr); - addr += sizeof(*fadt); - - /* XXX: FACS should be in RAM */ - addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */ - facs_addr = addr; - facs = (void *)(phys_ram_base + addr); - addr += sizeof(*facs); - - dsdt_addr = addr; - dsdt = (void *)(phys_ram_base + addr); - addr += sizeof(AmlCode); - - addr = (addr + 7) & ~7; - madt_addr = addr; - madt_size = sizeof(*madt) + - sizeof(struct madt_processor_apic) * smp_cpus + - sizeof(struct madt_io_apic); - madt = (void *)(phys_ram_base + addr); - addr += madt_size; - - acpi_tables_size = addr - base_addr; - - cpu_register_physical_memory(base_addr, acpi_tables_size, - base_addr | IO_MEM_ROM); - - /* RSDP */ - memset(rsdp, 0, sizeof(*rsdp)); - memcpy(rsdp->signature, "RSD PTR ", 8); - memcpy(rsdp->oem_id, "QEMU ", 6); - rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr); - rsdp->checksum = acpi_checksum((void *)rsdp, 20); - - /* RSDT */ - rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr); - rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr); - acpi_build_table_header((struct acpi_table_header *)rsdt, - "RSDT", sizeof(*rsdt)); - - /* FADT */ - memset(fadt, 0, sizeof(*fadt)); - fadt->firmware_ctrl = cpu_to_le32(facs_addr); - fadt->dsdt = cpu_to_le32(dsdt_addr); - fadt->model = 1; - fadt->reserved1 = 0; - fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]); - fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR); - fadt->acpi_enable = 0xf1; - fadt->acpi_disable = 0xf0; - fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base); - fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04); - fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08); - fadt->pm1_evt_len = 4; - fadt->pm1_cnt_len = 2; - fadt->pm_tmr_len = 4; - fadt->plvl2_lat = cpu_to_le16(50); - fadt->plvl3_lat = cpu_to_le16(50); - fadt->plvl3_lat = cpu_to_le16(50); - /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */ - fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6)); - acpi_build_table_header((struct acpi_table_header *)fadt, "FACP", - sizeof(*fadt)); - - /* FACS */ - memset(facs, 0, sizeof(*facs)); - memcpy(facs->signature, "FACS", 4); - facs->length = cpu_to_le32(sizeof(*facs)); - - /* DSDT */ - memcpy(dsdt, AmlCode, sizeof(AmlCode)); - - /* MADT */ - { - struct madt_processor_apic *apic; - struct madt_io_apic *io_apic; - - memset(madt, 0, madt_size); - madt->local_apic_address = cpu_to_le32(0xfee00000); - madt->flags = cpu_to_le32(1); - apic = (void *)(madt + 1); - for(i=0;itype = APIC_PROCESSOR; - apic->length = sizeof(*apic); - apic->processor_id = i; - apic->local_apic_id = i; - apic->flags = cpu_to_le32(1); - apic++; - } - io_apic = (void *)apic; - io_apic->type = APIC_IO; - io_apic->length = sizeof(*io_apic); - io_apic->io_apic_id = smp_cpus; - io_apic->address = cpu_to_le32(0xfec00000); - io_apic->interrupt = cpu_to_le32(0); - - acpi_build_table_header((struct acpi_table_header *)madt, - "APIC", madt_size); - } + register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s); } -- cgit v1.2.3 From f537a28c9747d5b8864dabf7dda4972a9ec4687c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:45:28 +0000 Subject: moved ACPI table init to BIOS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2171 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 7 - hw/acpi-dsdt.dsl | 559 ------------------------------------------------------- hw/acpi-dsdt.hex | 278 --------------------------- 3 files changed, 844 deletions(-) delete mode 100644 hw/acpi-dsdt.dsl delete mode 100644 hw/acpi-dsdt.hex diff --git a/Makefile.target b/Makefile.target index 3d6fdc1c2..aa2244b00 100644 --- a/Makefile.target +++ b/Makefile.target @@ -514,13 +514,6 @@ endif loader.o: loader.c elf_ops.h -acpi.o: acpi.c acpi-dsdt.hex - -ifdef BUILD_ACPI_TABLES -$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl - iasl -tc -p $@ $< -endif - ifeq ($(TARGET_ARCH), sh4) op.o: op.c op_mem.c cpu.h op_helper.o: op_helper.c exec.h cpu.h diff --git a/hw/acpi-dsdt.dsl b/hw/acpi-dsdt.dsl deleted file mode 100644 index fc4081fd8..000000000 --- a/hw/acpi-dsdt.dsl +++ /dev/null @@ -1,559 +0,0 @@ -/* - * QEMU ACPI DSDT ASL definition - * - * Copyright (c) 2006 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 version 2 as published by the Free Software Foundation. - * - * 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 - */ -DefinitionBlock ( - "acpi-dsdt.aml", // Output Filename - "DSDT", // Signature - 0x01, // DSDT Compliance Revision - "QEMU", // OEMID - "QEMUDSDT", // TABLE ID - 0x1 // OEM Revision - ) -{ - Scope (\) - { - /* CMOS memory access */ - OperationRegion (CMS, SystemIO, 0x70, 0x02) - Field (CMS, ByteAcc, NoLock, Preserve) - { - CMSI, 8, - CMSD, 8 - } - Method (CMRD, 1, NotSerialized) - { - Store (Arg0, CMSI) - Store (CMSD, Local0) - Return (Local0) - } - - /* Debug Output */ - OperationRegion (DBG, SystemIO, 0xb044, 0x04) - Field (DBG, DWordAcc, NoLock, Preserve) - { - DBGL, 32, - } - } - - - /* PCI Bus definition */ - Scope(\_SB) { - Device(PCI0) { - Name (_HID, EisaId ("PNP0A03")) - Name (_ADR, 0x00) - Name (_UID, 1) - Name(_PRT, Package() { - /* PCI IRQ routing table, example from ACPI 2.0a specification, - section 6.2.8.1 */ - /* Note: we provide the same info as the PCI routing - table of the Bochs BIOS */ - - // PCI Slot 0 - Package() {0x0000ffff, 0, LNKD, 0}, - Package() {0x0000ffff, 1, LNKA, 0}, - Package() {0x0000ffff, 2, LNKB, 0}, - Package() {0x0000ffff, 3, LNKC, 0}, - - // PCI Slot 1 - Package() {0x0001ffff, 0, LNKA, 0}, - Package() {0x0001ffff, 1, LNKB, 0}, - Package() {0x0001ffff, 2, LNKC, 0}, - Package() {0x0001ffff, 3, LNKD, 0}, - - // PCI Slot 2 - Package() {0x0002ffff, 0, LNKB, 0}, - Package() {0x0002ffff, 1, LNKC, 0}, - Package() {0x0002ffff, 2, LNKD, 0}, - Package() {0x0002ffff, 3, LNKA, 0}, - - // PCI Slot 3 - Package() {0x0003ffff, 0, LNKC, 0}, - Package() {0x0003ffff, 1, LNKD, 0}, - Package() {0x0003ffff, 2, LNKA, 0}, - Package() {0x0003ffff, 3, LNKB, 0}, - - // PCI Slot 4 - Package() {0x0004ffff, 0, LNKD, 0}, - Package() {0x0004ffff, 1, LNKA, 0}, - Package() {0x0004ffff, 2, LNKB, 0}, - Package() {0x0004ffff, 3, LNKC, 0}, - - // PCI Slot 5 - Package() {0x0005ffff, 0, LNKA, 0}, - Package() {0x0005ffff, 1, LNKB, 0}, - Package() {0x0005ffff, 2, LNKC, 0}, - Package() {0x0005ffff, 3, LNKD, 0}, - }) - - Method (_CRS, 0, NotSerialized) - { - Name (MEMP, ResourceTemplate () - { - WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, - 0x0000, // Address Space Granularity - 0x0000, // Address Range Minimum - 0x00FF, // Address Range Maximum - 0x0000, // Address Translation Offset - 0x0100, // Address Length - ,, ) - IO (Decode16, - 0x0CF8, // Address Range Minimum - 0x0CF8, // Address Range Maximum - 0x01, // Address Alignment - 0x08, // Address Length - ) - WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, - 0x0000, // Address Space Granularity - 0x0000, // Address Range Minimum - 0x0CF7, // Address Range Maximum - 0x0000, // Address Translation Offset - 0x0CF8, // Address Length - ,, , TypeStatic) - WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, - 0x0000, // Address Space Granularity - 0x0D00, // Address Range Minimum - 0xFFFF, // Address Range Maximum - 0x0000, // Address Translation Offset - 0xF300, // Address Length - ,, , TypeStatic) - DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, - 0x00000000, // Address Space Granularity - 0x000A0000, // Address Range Minimum - 0x000BFFFF, // Address Range Maximum - 0x00000000, // Address Translation Offset - 0x00020000, // Address Length - ,, , AddressRangeMemory, TypeStatic) - DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite, - 0x00000000, // Address Space Granularity - 0x00000000, // Address Range Minimum - 0xFEBFFFFF, // Address Range Maximum - 0x00000000, // Address Translation Offset - 0x00000000, // Address Length - ,, MEMF, AddressRangeMemory, TypeStatic) - }) - CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN) - CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX) - CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN) - /* compute available RAM */ - Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0) - ShiftLeft(Local0, 16, Local0) - Add(Local0, 0x1000000, Local0) - /* update field of last region */ - Store(Local0, PMIN) - Subtract (PMAX, PMIN, PLEN) - Increment (PLEN) - Return (MEMP) - } - } - } - - Scope(\_SB.PCI0) { - - /* PIIX3 ISA bridge */ - Device (ISA) { - Name (_ADR, 0x00010000) - - /* PIIX PCI to ISA irq remapping */ - OperationRegion (P40C, PCI_Config, 0x60, 0x04) - - - /* Keyboard seems to be important for WinXP install */ - Device (KBD) - { - Name (_HID, EisaId ("PNP0303")) - Method (_STA, 0, NotSerialized) - { - Return (0x0f) - } - - Method (_CRS, 0, NotSerialized) - { - Name (TMP, ResourceTemplate () - { - IO (Decode16, - 0x0060, // Address Range Minimum - 0x0060, // Address Range Maximum - 0x01, // Address Alignment - 0x01, // Address Length - ) - IO (Decode16, - 0x0064, // Address Range Minimum - 0x0064, // Address Range Maximum - 0x01, // Address Alignment - 0x01, // Address Length - ) - IRQNoFlags () - {1} - }) - Return (TMP) - } - } - - /* PS/2 mouse */ - Device (MOU) - { - Name (_HID, EisaId ("PNP0F13")) - Method (_STA, 0, NotSerialized) - { - Return (0x0f) - } - - Method (_CRS, 0, NotSerialized) - { - Name (TMP, ResourceTemplate () - { - IRQNoFlags () {12} - }) - Return (TMP) - } - } - - /* PS/2 floppy controller */ - Device (FDC0) - { - Name (_HID, EisaId ("PNP0700")) - Method (_STA, 0, NotSerialized) - { - Return (0x0F) - } - Method (_CRS, 0, NotSerialized) - { - Name (BUF0, ResourceTemplate () - { - IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04) - IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01) - IRQNoFlags () {6} - DMA (Compatibility, NotBusMaster, Transfer8) {2} - }) - Return (BUF0) - } - } - - /* Parallel port */ - Device (LPT) - { - Name (_HID, EisaId ("PNP0400")) - Method (_STA, 0, NotSerialized) - { - Store (\_SB.PCI0.PX13.DRSA, Local0) - And (Local0, 0x80000000, Local0) - If (LEqual (Local0, 0)) - { - Return (0x00) - } - Else - { - Return (0x0F) - } - } - Method (_CRS, 0, NotSerialized) - { - Name (BUF0, ResourceTemplate () - { - IO (Decode16, 0x0378, 0x0378, 0x08, 0x08) - IRQNoFlags () {7} - }) - Return (BUF0) - } - } - - /* Serial Ports */ - Device (COM1) - { - Name (_HID, EisaId ("PNP0501")) - Name (_UID, 0x01) - Method (_STA, 0, NotSerialized) - { - Store (\_SB.PCI0.PX13.DRSC, Local0) - And (Local0, 0x08000000, Local0) - If (LEqual (Local0, 0)) - { - Return (0x00) - } - Else - { - Return (0x0F) - } - } - Method (_CRS, 0, NotSerialized) - { - Name (BUF0, ResourceTemplate () - { - IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08) - IRQNoFlags () {4} - }) - Return (BUF0) - } - } - - Device (COM2) - { - Name (_HID, EisaId ("PNP0501")) - Name (_UID, 0x02) - Method (_STA, 0, NotSerialized) - { - Store (\_SB.PCI0.PX13.DRSC, Local0) - And (Local0, 0x80000000, Local0) - If (LEqual (Local0, 0)) - { - Return (0x00) - } - Else - { - Return (0x0F) - } - } - Method (_CRS, 0, NotSerialized) - { - Name (BUF0, ResourceTemplate () - { - IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08) - IRQNoFlags () {3} - }) - Return (BUF0) - } - } - } - - /* PIIX4 PM */ - Device (PX13) { - Name (_ADR, 0x00010003) - - OperationRegion (P13C, PCI_Config, 0x5c, 0x24) - Field (P13C, DWordAcc, NoLock, Preserve) - { - DRSA, 32, - DRSB, 32, - DRSC, 32, - DRSE, 32, - DRSF, 32, - DRSG, 32, - DRSH, 32, - DRSI, 32, - DRSJ, 32 - } - } - } - - /* PCI IRQs */ - Scope(\_SB) { - Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) - { - PRQ0, 8, - PRQ1, 8, - PRQ2, 8, - PRQ3, 8 - } - - Device(LNKA){ - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link - Name(_UID, 1) - Name(_PRS, ResourceTemplate(){ - IRQ (Level, ActiveLow, Shared) - {3,4,5,6,7,9,10,11,12} - }) - Method (_STA, 0, NotSerialized) - { - Store (0x0B, Local0) - If (And (0x80, PRQ0, Local1)) - { - Store (0x09, Local0) - } - Return (Local0) - } - Method (_DIS, 0, NotSerialized) - { - Or (PRQ0, 0x80, PRQ0) - } - Method (_CRS, 0, NotSerialized) - { - Name (PRR0, ResourceTemplate () - { - IRQ (Level, ActiveLow, Shared) - {1} - }) - CreateWordField (PRR0, 0x01, TMP) - Store (PRQ0, Local0) - If (LLess (Local0, 0x80)) - { - ShiftLeft (One, Local0, TMP) - } - Else - { - Store (Zero, TMP) - } - Return (PRR0) - } - Method (_SRS, 1, NotSerialized) - { - CreateWordField (Arg0, 0x01, TMP) - FindSetRightBit (TMP, Local0) - Decrement (Local0) - Store (Local0, PRQ0) - } - } - Device(LNKB){ - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link - Name(_UID, 2) - Name(_PRS, ResourceTemplate(){ - IRQ (Level, ActiveLow, Shared) - {3,4,5,6,7,9,10,11,12} - }) - Method (_STA, 0, NotSerialized) - { - Store (0x0B, Local0) - If (And (0x80, PRQ1, Local1)) - { - Store (0x09, Local0) - } - Return (Local0) - } - Method (_DIS, 0, NotSerialized) - { - Or (PRQ1, 0x80, PRQ1) - } - Method (_CRS, 0, NotSerialized) - { - Name (PRR0, ResourceTemplate () - { - IRQ (Level, ActiveLow, Shared) - {1} - }) - CreateWordField (PRR0, 0x01, TMP) - Store (PRQ1, Local0) - If (LLess (Local0, 0x80)) - { - ShiftLeft (One, Local0, TMP) - } - Else - { - Store (Zero, TMP) - } - Return (PRR0) - } - Method (_SRS, 1, NotSerialized) - { - CreateWordField (Arg0, 0x01, TMP) - FindSetRightBit (TMP, Local0) - Decrement (Local0) - Store (Local0, PRQ1) - } - } - Device(LNKC){ - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link - Name(_UID, 3) - Name(_PRS, ResourceTemplate(){ - IRQ (Level, ActiveLow, Shared) - {3,4,5,6,7,9,10,11,12} - }) - Method (_STA, 0, NotSerialized) - { - Store (0x0B, Local0) - If (And (0x80, PRQ2, Local1)) - { - Store (0x09, Local0) - } - Return (Local0) - } - Method (_DIS, 0, NotSerialized) - { - Or (PRQ2, 0x80, PRQ2) - } - Method (_CRS, 0, NotSerialized) - { - Name (PRR0, ResourceTemplate () - { - IRQ (Level, ActiveLow, Shared) - {1} - }) - CreateWordField (PRR0, 0x01, TMP) - Store (PRQ2, Local0) - If (LLess (Local0, 0x80)) - { - ShiftLeft (One, Local0, TMP) - } - Else - { - Store (Zero, TMP) - } - Return (PRR0) - } - Method (_SRS, 1, NotSerialized) - { - CreateWordField (Arg0, 0x01, TMP) - FindSetRightBit (TMP, Local0) - Decrement (Local0) - Store (Local0, PRQ2) - } - } - Device(LNKD){ - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link - Name(_UID, 4) - Name(_PRS, ResourceTemplate(){ - IRQ (Level, ActiveLow, Shared) - {3,4,5,6,7,9,10,11,12} - }) - Method (_STA, 0, NotSerialized) - { - Store (0x0B, Local0) - If (And (0x80, PRQ3, Local1)) - { - Store (0x09, Local0) - } - Return (Local0) - } - Method (_DIS, 0, NotSerialized) - { - Or (PRQ3, 0x80, PRQ3) - } - Method (_CRS, 0, NotSerialized) - { - Name (PRR0, ResourceTemplate () - { - IRQ (Level, ActiveLow, Shared) - {1} - }) - CreateWordField (PRR0, 0x01, TMP) - Store (PRQ3, Local0) - If (LLess (Local0, 0x80)) - { - ShiftLeft (One, Local0, TMP) - } - Else - { - Store (Zero, TMP) - } - Return (PRR0) - } - Method (_SRS, 1, NotSerialized) - { - CreateWordField (Arg0, 0x01, TMP) - FindSetRightBit (TMP, Local0) - Decrement (Local0) - Store (Local0, PRQ3) - } - } - } - - /* S5 = power off state */ - Name (_S5, Package (4) { - 0x00, // PM1a_CNT.SLP_TYP - 0x00, // PM2a_CNT.SLP_TYP - 0x00, // reserved - 0x00, // reserved - }) -} diff --git a/hw/acpi-dsdt.hex b/hw/acpi-dsdt.hex deleted file mode 100644 index f4f50bd65..000000000 --- a/hw/acpi-dsdt.hex +++ /dev/null @@ -1,278 +0,0 @@ -/* - * - * Intel ACPI Component Architecture - * ASL Optimizing Compiler version 20060421 [Apr 29 2006] - * Copyright (C) 2000 - 2006 Intel Corporation - * Supports ACPI Specification Revision 3.0a - * - * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006 - * - * C source code output - * - */ -unsigned char AmlCode[] = -{ - 0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */ - 0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */ - 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */ - 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ - 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */ - 0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */ - 0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */ - 0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */ - 0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */ - 0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */ - 0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */ - 0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */ - 0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */ - 0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */ - 0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */ - 0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */ - 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */ - 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */ - 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */ - 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */ - 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */ - 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */ - 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */ - 0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */ - 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */ - 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */ - 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */ - 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */ - 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */ - 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */ - 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */ - 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */ - 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */ - 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */ - 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */ - 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */ - 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */ - 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */ - 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */ - 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */ - 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */ - 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */ - 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */ - 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */ - 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */ - 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */ - 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */ - 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */ - 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */ - 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */ - 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */ - 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */ - 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */ - 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */ - 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */ - 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */ - 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */ - 0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */ - 0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */ - 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */ - 0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */ - 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */ - 0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */ - 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */ - 0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */ - 0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */ - 0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */ - 0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */ - 0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */ - 0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */ - 0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */ - 0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */ - 0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */ - 0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */ - 0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */ - 0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */ - 0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */ - 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */ - 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */ - 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */ - 0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */ - 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */ - 0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */ - 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */ - 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */ - 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */ - 0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */ - 0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */ - 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */ - 0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */ - 0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */ - 0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */ - 0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */ - 0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */ - 0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */ - 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */ - 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */ - 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */ - 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */ - 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */ - 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */ - 0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */ - 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */ - 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */ - 0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */ - 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */ - 0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */ - 0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */ - 0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */ - 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */ - 0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */ - 0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */ - 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */ - 0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */ - 0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */ - 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */ - 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */ - 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */ - 0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */ - 0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */ - 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */ - 0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */ - 0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */ - 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */ - 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */ - 0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */ - 0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */ - 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */ - 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */ - 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */ - 0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */ - 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */ - 0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */ - 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */ - 0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */ - 0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */ - 0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */ - 0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */ - 0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */ - 0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */ - 0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */ - 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */ - 0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */ - 0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */ - 0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */ - 0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */ - 0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */ - 0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */ - 0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */ - 0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */ - 0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */ - 0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */ - 0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */ - 0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */ - 0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */ - 0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */ - 0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */ - 0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */ - 0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */ - 0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */ - 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */ - 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */ - 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */ - 0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */ - 0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */ - 0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */ - 0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */ - 0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */ - 0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */ - 0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */ - 0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */ - 0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */ - 0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */ - 0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */ - 0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */ - 0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */ - 0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */ - 0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */ - 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */ - 0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */ - 0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */ - 0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */ - 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */ - 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */ - 0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */ - 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */ - 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */ - 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */ - 0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */ - 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */ - 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */ - 0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */ - 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */ - 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */ - 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */ - 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */ - 0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */ - 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */ - 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */ - 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */ - 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */ - 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */ - 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */ - 0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */ - 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */ - 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */ - 0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */ - 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */ - 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */ - 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */ - 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */ - 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */ - 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */ - 0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */ - 0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */ - 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */ - 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */ - 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */ - 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */ - 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */ - 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */ - 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */ - 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */ - 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */ - 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */ - 0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */ - 0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */ - 0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */ - 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */ - 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */ - 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */ - 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */ - 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */ - 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */ - 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */ - 0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */ - 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */ - 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */ - 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */ - 0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */ - 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */ - 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */ - 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */ - 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */ - 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */ - 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */ - 0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */ - 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */ - 0x00,0x00, -}; -- cgit v1.2.3 From a5954d5c34502ebeaae95b8719a734066f596f1e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:48:00 +0000 Subject: moved MP table init to BIOS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2172 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 178 ++++++---------------------------------------------------------- 1 file changed, 15 insertions(+), 163 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index b233d8cd0..ab235c7ee 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -40,6 +40,7 @@ static fdctrl_t *floppy_controller; static RTCState *rtc_state; static PITState *pit; static IOAPICState *ioapic; +static PCIDevice *i440fx_state; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -73,6 +74,14 @@ uint64_t cpu_get_tsc(CPUX86State *env) } } +/* SMM support */ +void cpu_smm_update(CPUState *env) +{ + if (i440fx_state && env == first_cpu) + i440fx_set_smm(i440fx_state, (env->hflags >> HF_SMM_SHIFT) & 1); +} + + /* IRQ handling */ int cpu_get_pic_interrupt(CPUState *env) { @@ -398,156 +407,6 @@ static void main_cpu_reset(void *opaque) cpu_reset(env); } -/*************************************************/ - -static void putb(uint8_t **pp, int val) -{ - uint8_t *q; - q = *pp; - *q++ = val; - *pp = q; -} - -static void putstr(uint8_t **pp, const char *str) -{ - uint8_t *q; - q = *pp; - while (*str) - *q++ = *str++; - *pp = q; -} - -static void putle16(uint8_t **pp, int val) -{ - uint8_t *q; - q = *pp; - *q++ = val; - *q++ = val >> 8; - *pp = q; -} - -static void putle32(uint8_t **pp, int val) -{ - uint8_t *q; - q = *pp; - *q++ = val; - *q++ = val >> 8; - *q++ = val >> 16; - *q++ = val >> 24; - *pp = q; -} - -static int mpf_checksum(const uint8_t *data, int len) -{ - int sum, i; - sum = 0; - for(i = 0; i < len; i++) - sum += data[i]; - return sum & 0xff; -} - -/* Build the Multi Processor table in the BIOS. Same values as Bochs. */ -static void bios_add_mptable(uint8_t *bios_data) -{ - uint8_t *mp_config_table, *q, *float_pointer_struct; - int ioapic_id, offset, i, len; - - if (smp_cpus <= 1) - return; - - mp_config_table = bios_data + 0xb000; - q = mp_config_table; - putstr(&q, "PCMP"); /* "PCMP signature */ - putle16(&q, 0); /* table length (patched later) */ - putb(&q, 4); /* spec rev */ - putb(&q, 0); /* checksum (patched later) */ - putstr(&q, "QEMUCPU "); /* OEM id */ - putstr(&q, "0.1 "); /* vendor id */ - putle32(&q, 0); /* OEM table ptr */ - putle16(&q, 0); /* OEM table size */ - putle16(&q, 20); /* entry count */ - putle32(&q, 0xfee00000); /* local APIC addr */ - putle16(&q, 0); /* ext table length */ - putb(&q, 0); /* ext table checksum */ - putb(&q, 0); /* reserved */ - - for(i = 0; i < smp_cpus; i++) { - putb(&q, 0); /* entry type = processor */ - putb(&q, i); /* APIC id */ - putb(&q, 0x11); /* local APIC version number */ - if (i == 0) - putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */ - else - putb(&q, 1); /* cpu flags: enabled */ - putb(&q, 0); /* cpu signature */ - putb(&q, 6); - putb(&q, 0); - putb(&q, 0); - putle16(&q, 0x201); /* feature flags */ - putle16(&q, 0); - - putle16(&q, 0); /* reserved */ - putle16(&q, 0); - putle16(&q, 0); - putle16(&q, 0); - } - - /* isa bus */ - putb(&q, 1); /* entry type = bus */ - putb(&q, 0); /* bus ID */ - putstr(&q, "ISA "); - - /* ioapic */ - ioapic_id = smp_cpus; - putb(&q, 2); /* entry type = I/O APIC */ - putb(&q, ioapic_id); /* apic ID */ - putb(&q, 0x11); /* I/O APIC version number */ - putb(&q, 1); /* enable */ - putle32(&q, 0xfec00000); /* I/O APIC addr */ - - /* irqs */ - for(i = 0; i < 16; i++) { - putb(&q, 3); /* entry type = I/O interrupt */ - putb(&q, 0); /* interrupt type = vectored interrupt */ - putb(&q, 0); /* flags: po=0, el=0 */ - putb(&q, 0); - putb(&q, 0); /* source bus ID = ISA */ - putb(&q, i); /* source bus IRQ */ - putb(&q, ioapic_id); /* dest I/O APIC ID */ - putb(&q, i); /* dest I/O APIC interrupt in */ - } - /* patch length */ - len = q - mp_config_table; - mp_config_table[4] = len; - mp_config_table[5] = len >> 8; - - mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table); - - /* align to 16 */ - offset = q - bios_data; - offset = (offset + 15) & ~15; - float_pointer_struct = bios_data + offset; - - /* floating pointer structure */ - q = float_pointer_struct; - putstr(&q, "_MP_"); - /* pointer to MP config table */ - putle32(&q, mp_config_table - bios_data + 0x000f0000); - - putb(&q, 1); /* length in 16 byte units */ - putb(&q, 4); /* MP spec revision */ - putb(&q, 0); /* checksum (patched later) */ - putb(&q, 0); /* MP feature byte 1 */ - - putb(&q, 0); - putb(&q, 0); - putb(&q, 0); - putb(&q, 0); - float_pointer_struct[10] = - -mpf_checksum(float_pointer_struct, q - float_pointer_struct); -} - - static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 14, 15 }; @@ -632,7 +491,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, /* XXX: enable it in all cases */ env->cpuid_features |= CPUID_APIC; } - register_savevm("cpu", i, 3, cpu_save, cpu_load, env); + register_savevm("cpu", i, 4, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); if (pci_enabled) { apic_init(env); @@ -659,9 +518,6 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); exit(1); } - if (bios_size == 65536) { - bios_add_mptable(phys_ram_base + bios_offset); - } /* VGA BIOS load */ if (cirrus_vga_enabled) { @@ -747,7 +603,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } if (pci_enabled) { - pci_bus = i440fx_init(); + pci_bus = i440fx_init(&i440fx_state); piix3_devfn = piix3_init(pci_bus); } else { pci_bus = NULL; @@ -850,7 +706,10 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled && acpi_enabled) { piix4_pm_init(pci_bus, piix3_devfn + 3); } - + + if (i440fx_state) { + i440fx_init_memory_mappings(i440fx_state); + } #if 0 /* ??? Need to figure out some way for the user to specify SCSI devices. */ @@ -868,13 +727,6 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, lsi_scsi_attach(scsi, bdrv, -1); } #endif - /* must be done after all PCI devices are instanciated */ - /* XXX: should be done in the Bochs BIOS */ - if (pci_enabled) { - pci_bios_init(); - if (acpi_enabled) - acpi_bios_init(); - } } static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, -- cgit v1.2.3 From 02a1602e62a7edc010130bc58f1be7ec1669af06 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:48:23 +0000 Subject: added cpu_smm_update() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2173 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index d1693110f..42f4a0350 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -122,6 +122,10 @@ int64_t cpu_get_real_ticks(void) /***********************************************************/ /* CPUX86 core interface */ +void cpu_smm_update(CPUState *env) +{ +} + uint64_t cpu_get_tsc(CPUX86State *env) { return cpu_get_real_ticks(); -- cgit v1.2.3 From ee0ea1d0dda935aa13e6562ee32d37d441b43490 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:49:13 +0000 Subject: moved PCI init to BIOS - added ISA memory mapping registers and SMM support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2174 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/piix_pci.c | 348 +++++++++++++++++++++------------------------------------- 1 file changed, 123 insertions(+), 225 deletions(-) diff --git a/hw/piix_pci.c b/hw/piix_pci.c index d618f0062..43f2da2c4 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -52,7 +52,123 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) return (irq_num + slot_addend) & 3; } -PCIBus *i440fx_init(void) +static uint32_t isa_page_descs[384 / 4]; +static uint8_t smm_enabled; + +static const uint32_t mar_addresses[15] = { + 0xa0000, + 0xc0000, + 0xc4000, + 0xc8000, + 0xcc000, + 0xd0000, + 0xd4000, + 0xd8000, + 0xdc000, + 0xe0000, + 0xe4000, + 0xe8000, + 0xec000, + 0xf0000, + 0x100000, +}; + +static void i440fx_update_memory_mappings(PCIDevice *d) +{ + int i, r; + uint32_t start, end, addr; + uint32_t smram, smbase, smsize; + + for(i = 0; i < 14; i++) { + r = (d->config[(i >> 1) + 0x61] >> ((i & 1) * 4)) & 3; + start = mar_addresses[i]; + end = mar_addresses[i + 1]; + // printf("ISA mapping %08x: %d\n", start, r); + switch(r) { + case 3: + /* RAM */ + cpu_register_physical_memory(start, end - start, + start); + break; + case 2: + /* ROM (XXX: not quite correct) */ + cpu_register_physical_memory(start, end - start, + start | IO_MEM_ROM); + break; + case 1: + case 0: + /* XXX: should distinguish read/write cases */ + for(addr = start; addr < end; addr += 4096) { + cpu_register_physical_memory(addr, 4096, + isa_page_descs[(addr - 0xa0000) >> 12]); + } + break; + } + } + smram = le32_to_cpu(*(uint32_t *)(d->config + 0x6c)); + if ((smm_enabled && (smram & 0x80000000)) || (smram & (1 << 26))) { + /* Note: we assume the SMM area is in the 0xa0000-0x100000 range */ + smbase = (smram & 0xffff) << 16; + smsize = (((smram >> 20) & 0xf) + 1) << 16; + if (smbase >= 0xa0000 && (smbase + smsize) <= 0x100000) { + cpu_register_physical_memory(smbase, smsize, smbase); + } + } +} + +void i440fx_set_smm(PCIDevice *d, int val) +{ + val = (val != 0); + if (smm_enabled != val) { + smm_enabled = val; + i440fx_update_memory_mappings(d); + } +} + + +/* XXX: suppress when better memory API. We make the assumption that + no device (in particular the VGA) changes the memory mappings in + the 0xa0000-0x100000 range */ +void i440fx_init_memory_mappings(PCIDevice *d) +{ + int i; + for(i = 0; i < 96; i++) { + isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000); + } +} + +static void i440fx_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + /* XXX: implement SMRAM.D_LOCK */ + pci_default_write_config(d, address, val, len); + if ((address >= 0x61 && address <= 0x67) || address == 0x6c) + i440fx_update_memory_mappings(d); +} + +static void i440fx_save(QEMUFile* f, void *opaque) +{ + PCIDevice *d = opaque; + pci_device_save(d, f); + qemu_put_8s(f, &smm_enabled); +} + +static int i440fx_load(QEMUFile* f, void *opaque, int version_id) +{ + PCIDevice *d = opaque; + int ret; + + if (version_id != 1) + return -EINVAL; + ret = pci_device_load(d, f); + if (ret < 0) + return ret; + i440fx_update_memory_mappings(d); + qemu_get_8s(f, &smm_enabled); + return 0; +} + +PCIBus *i440fx_init(PCIDevice **pi440fx_state) { PCIBus *b; PCIDevice *d; @@ -73,7 +189,7 @@ PCIBus *i440fx_init(void) register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, - NULL, NULL); + NULL, i440fx_write_config); d->config[0x00] = 0x86; // vendor_id d->config[0x01] = 0x80; @@ -83,6 +199,11 @@ PCIBus *i440fx_init(void) d->config[0x0a] = 0x00; // class_sub = host2pci d->config[0x0b] = 0x06; // class_base = PCI_bridge d->config[0x0e] = 0x00; // header_type + + d->config[0x6c] = 0x0a; /* SMRAM */ + + register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d); + *pi440fx_state = d; return b; } @@ -188,226 +309,3 @@ int piix3_init(PCIBus *bus) piix3_reset(d); return d->devfn; } - -/***********************************************************/ -/* XXX: the following should be moved to the PC BIOS */ - -static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) -{ - return cpu_inb(NULL, addr); -} - -static void isa_outb(uint32_t val, uint32_t addr) -{ - cpu_outb(NULL, addr, val); -} - -static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) -{ - return cpu_inw(NULL, addr); -} - -static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) -{ - cpu_outw(NULL, addr, val); -} - -static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) -{ - return cpu_inl(NULL, addr); -} - -static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) -{ - cpu_outl(NULL, addr, val); -} - -static uint32_t pci_bios_io_addr; -static uint32_t pci_bios_mem_addr; -/* host irqs corresponding to PCI irqs A-D */ -static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; -static int pci_bios_next_bus; - -static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - pci_data_write(s, addr, val, 4); -} - -static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - pci_data_write(s, addr, val, 2); -} - -static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - pci_data_write(s, addr, val, 1); -} - -static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - return pci_data_read(s, addr, 4); -} - -static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - return pci_data_read(s, addr, 2); -} - -static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - return pci_data_read(s, addr, 1); -} - -static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) -{ - PCIIORegion *r; - uint16_t cmd; - uint32_t ofs; - - if ( region_num == PCI_ROM_SLOT ) { - ofs = 0x30; - }else{ - ofs = 0x10 + region_num * 4; - } - - pci_config_writel(d, ofs, addr); - r = &d->io_regions[region_num]; - - /* enable memory mappings */ - cmd = pci_config_readw(d, PCI_COMMAND); - if ( region_num == PCI_ROM_SLOT ) - cmd |= 2; - else if (r->type & PCI_ADDRESS_SPACE_IO) - cmd |= 1; - else - cmd |= 2; - pci_config_writew(d, PCI_COMMAND, cmd); -} - -static void pci_bios_init_device(PCIDevice *d) -{ - int class; - PCIIORegion *r; - uint32_t *paddr; - int i, pin, pic_irq, vendor_id, device_id; - - class = pci_config_readw(d, PCI_CLASS_DEVICE); - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); - switch(class) { - case 0x0101: - if (vendor_id == 0x8086 && device_id == 0x7010) { - /* PIIX3 IDE */ - pci_config_writew(d, 0x40, 0x8000); // enable IDE0 - pci_config_writew(d, 0x42, 0x8000); // enable IDE1 - goto default_map; - } else { - /* IDE: we map it as in ISA mode */ - pci_set_io_region_addr(d, 0, 0x1f0); - pci_set_io_region_addr(d, 1, 0x3f4); - pci_set_io_region_addr(d, 2, 0x170); - pci_set_io_region_addr(d, 3, 0x374); - } - break; - case 0x0604: - /* PCI to PCI bridge. Assign bus ID and recurse to configure - devices on the secondary bus. */ - i = pci_bios_next_bus++; - pci_config_writeb(d, 0x18, pci_bus_num(d->bus)); - pci_config_writeb(d, 0x19, i); - pci_for_each_device(i, pci_bios_init_device); - break; - case 0x0300: - if (vendor_id != 0x1234) - goto default_map; - /* VGA: map frame buffer to default Bochs VBE address */ - pci_set_io_region_addr(d, 0, 0xE0000000); - break; - case 0x0800: - /* PIC */ - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); - if (vendor_id == 0x1014) { - /* IBM */ - if (device_id == 0x0046 || device_id == 0xFFFF) { - /* MPIC & MPIC2 */ - pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); - } - } - break; - case 0xff00: - if (vendor_id == 0x0106b && - (device_id == 0x0017 || device_id == 0x0022)) { - /* macio bridge */ - pci_set_io_region_addr(d, 0, 0x80800000); - } - break; - default: - default_map: - /* default memory mappings */ - for(i = 0; i < PCI_NUM_REGIONS; i++) { - r = &d->io_regions[i]; - if (r->size) { - if (r->type & PCI_ADDRESS_SPACE_IO) - paddr = &pci_bios_io_addr; - else - paddr = &pci_bios_mem_addr; - *paddr = (*paddr + r->size - 1) & ~(r->size - 1); - pci_set_io_region_addr(d, i, *paddr); - *paddr += r->size; - } - } - break; - } - - /* map the interrupt */ - pin = pci_config_readb(d, PCI_INTERRUPT_PIN); - if (pin != 0) { - pin = pci_slot_get_pirq(d, pin - 1); - pic_irq = pci_irqs[pin]; - pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); - } -} - -/* - * This function initializes the PCI devices as a normal PCI BIOS - * would do. It is provided just in case the BIOS has no support for - * PCI. - */ -void pci_bios_init(void) -{ - int i, irq; - uint8_t elcr[2]; - - pci_bios_io_addr = 0xc000; - pci_bios_mem_addr = 0xf0000000; - - /* activate IRQ mappings */ - elcr[0] = 0x00; - elcr[1] = 0x00; - for(i = 0; i < 4; i++) { - irq = pci_irqs[i]; - /* set to trigger level */ - elcr[irq >> 3] |= (1 << (irq & 7)); - /* activate irq remapping in PIIX */ - pci_config_writeb(piix3_dev, 0x60 + i, irq); - } - isa_outb(elcr[0], 0x4d0); - isa_outb(elcr[1], 0x4d1); - - pci_bios_next_bus = 1; - pci_for_each_device(0, pci_bios_init_device); -} - -- cgit v1.2.3 From f00fc47c15d1a88c1422973d2ac10c87f7af07cb Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:49:43 +0000 Subject: moved PCI init to BIOS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2175 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vl.h b/vl.h index 124e7d776..eedef51bd 100644 --- a/vl.h +++ b/vl.h @@ -787,9 +787,10 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, PCIBus *pci_vpb_init(void *pic, int irq, int realview); /* piix_pci.c */ -PCIBus *i440fx_init(void); +PCIBus *i440fx_init(PCIDevice **pi440fx_state); +void i440fx_set_smm(PCIDevice *d, int val); int piix3_init(PCIBus *bus); -void pci_bios_init(void); +void i440fx_init_memory_mappings(PCIDevice *d); /* openpic.c */ typedef struct openpic_t openpic_t; -- cgit v1.2.3 From 4f3baa4b3680255c88d30a2d0ad0f1fb50b1e373 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 18:49:55 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2176 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index 0ce7372a3..a2c9a007d 100644 --- a/Changelog +++ b/Changelog @@ -5,6 +5,8 @@ version 0.8.3: - 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: -- cgit v1.2.3 From 84631fd79cd9c1c5ed21b9a574dd6bb9309de64c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 19:31:43 +0000 Subject: implement i440 instead of i450 ISA memory mappings to be compatible with Bochs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2177 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/piix_pci.c | 95 ++++++++++++++++++++++++++--------------------------------- 1 file changed, 41 insertions(+), 54 deletions(-) diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 43f2da2c4..155769447 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -55,63 +55,50 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) static uint32_t isa_page_descs[384 / 4]; static uint8_t smm_enabled; -static const uint32_t mar_addresses[15] = { - 0xa0000, - 0xc0000, - 0xc4000, - 0xc8000, - 0xcc000, - 0xd0000, - 0xd4000, - 0xd8000, - 0xdc000, - 0xe0000, - 0xe4000, - 0xe8000, - 0xec000, - 0xf0000, - 0x100000, -}; +static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r) +{ + uint32_t addr; + + // printf("ISA mapping %08x-0x%08x: %d\n", start, end, r); + switch(r) { + case 3: + /* RAM */ + cpu_register_physical_memory(start, end - start, + start); + break; + case 1: + /* ROM (XXX: not quite correct) */ + cpu_register_physical_memory(start, end - start, + start | IO_MEM_ROM); + break; + case 2: + case 0: + /* XXX: should distinguish read/write cases */ + for(addr = start; addr < end; addr += 4096) { + cpu_register_physical_memory(addr, 4096, + isa_page_descs[(addr - 0xa0000) >> 12]); + } + break; + } +} static void i440fx_update_memory_mappings(PCIDevice *d) { int i, r; - uint32_t start, end, addr; - uint32_t smram, smbase, smsize; - - for(i = 0; i < 14; i++) { - r = (d->config[(i >> 1) + 0x61] >> ((i & 1) * 4)) & 3; - start = mar_addresses[i]; - end = mar_addresses[i + 1]; - // printf("ISA mapping %08x: %d\n", start, r); - switch(r) { - case 3: - /* RAM */ - cpu_register_physical_memory(start, end - start, - start); - break; - case 2: - /* ROM (XXX: not quite correct) */ - cpu_register_physical_memory(start, end - start, - start | IO_MEM_ROM); - break; - case 1: - case 0: - /* XXX: should distinguish read/write cases */ - for(addr = start; addr < end; addr += 4096) { - cpu_register_physical_memory(addr, 4096, - isa_page_descs[(addr - 0xa0000) >> 12]); - } - break; - } + uint32_t smram, addr; + + update_pam(d, 0xf0000, 0x100000, (d->config[0x59] >> 4) & 3); + for(i = 0; i < 12; i++) { + r = (d->config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3; + update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r); } - smram = le32_to_cpu(*(uint32_t *)(d->config + 0x6c)); - if ((smm_enabled && (smram & 0x80000000)) || (smram & (1 << 26))) { - /* Note: we assume the SMM area is in the 0xa0000-0x100000 range */ - smbase = (smram & 0xffff) << 16; - smsize = (((smram >> 20) & 0xf) + 1) << 16; - if (smbase >= 0xa0000 && (smbase + smsize) <= 0x100000) { - cpu_register_physical_memory(smbase, smsize, smbase); + smram = d->config[0x72]; + if ((smm_enabled && (smram & 0x08)) || (smram & 0x40)) { + cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000); + } else { + for(addr = 0xa0000; addr < 0xc0000; addr += 4096) { + cpu_register_physical_memory(addr, 4096, + isa_page_descs[(addr - 0xa0000) >> 12]); } } } @@ -142,7 +129,7 @@ static void i440fx_write_config(PCIDevice *d, { /* XXX: implement SMRAM.D_LOCK */ pci_default_write_config(d, address, val, len); - if ((address >= 0x61 && address <= 0x67) || address == 0x6c) + if ((address >= 0x59 && address <= 0x5f) || address == 0x72) i440fx_update_memory_mappings(d); } @@ -200,7 +187,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state) d->config[0x0b] = 0x06; // class_base = PCI_bridge d->config[0x0e] = 0x00; // header_type - d->config[0x6c] = 0x0a; /* SMRAM */ + d->config[0x72] = 0x02; /* SMRAM */ register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d); *pi440fx_state = d; -- cgit v1.2.3 From 79266dbd9ebb56ee20a72ce94d385388a689c71c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 24 Sep 2006 19:36:49 +0000 Subject: updated git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2178 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/bios.diff | 73 +++++++++++++++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 051fdbb14..8e6de368a 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index e70499017..f89c77ef6 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,6 +1,6 @@ -diff -ruN --exclude Makefile bios/acpi-dsdt.dsl bios.new/acpi-dsdt.dsl ---- bios/acpi-dsdt.dsl 1970-01-01 01:00:00.000000000 +0100 -+++ bios.new/acpi-dsdt.dsl 2006-09-24 20:27:54.000000000 +0200 +diff -ruN --exclude Makefile bios.org/acpi-dsdt.dsl bios/acpi-dsdt.dsl +--- bios.org/acpi-dsdt.dsl 1970-01-01 01:00:00.000000000 +0100 ++++ bios/acpi-dsdt.dsl 2006-09-24 20:27:54.000000000 +0200 @@ -0,0 +1,559 @@ +/* + * QEMU ACPI DSDT ASL definition @@ -561,9 +561,9 @@ diff -ruN --exclude Makefile bios/acpi-dsdt.dsl bios.new/acpi-dsdt.dsl + 0x00, // reserved + }) +} -diff -ruN --exclude Makefile bios/acpi-dsdt.hex bios.new/acpi-dsdt.hex ---- bios/acpi-dsdt.hex 1970-01-01 01:00:00.000000000 +0100 -+++ bios.new/acpi-dsdt.hex 2006-09-24 20:27:54.000000000 +0200 +diff -ruN --exclude Makefile bios.org/acpi-dsdt.hex bios/acpi-dsdt.hex +--- bios.org/acpi-dsdt.hex 1970-01-01 01:00:00.000000000 +0100 ++++ bios/acpi-dsdt.hex 2006-09-24 20:27:54.000000000 +0200 @@ -0,0 +1,278 @@ +/* + * @@ -843,10 +843,10 @@ diff -ruN --exclude Makefile bios/acpi-dsdt.hex bios.new/acpi-dsdt.hex + 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */ + 0x00,0x00, +}; -Binary files bios/BIOS-bochs-latest and bios.new/BIOS-bochs-latest differ -diff -ruN --exclude Makefile bios/Makefile.in bios.new/Makefile.in ---- bios/Makefile.in 2006-01-13 18:36:27.000000000 +0100 -+++ bios.new/Makefile.in 2006-09-24 20:26:39.000000000 +0200 +Binary files bios.org/BIOS-bochs-latest and bios/BIOS-bochs-latest differ +diff -ruN --exclude Makefile bios.org/Makefile.in bios/Makefile.in +--- bios.org/Makefile.in 2006-01-13 18:36:27.000000000 +0100 ++++ bios/Makefile.in 2006-09-24 21:37:05.000000000 +0200 @@ -61,7 +61,8 @@ clean: @@ -857,7 +857,7 @@ diff -ruN --exclude Makefile bios/Makefile.in bios.new/Makefile.in dist-clean: clean @RMCOMMAND@ Makefile -@@ -69,15 +70,35 @@ +@@ -69,15 +70,40 @@ bios-clean: @RMCOMMAND@ BIOS-bochs-* @@ -882,9 +882,14 @@ diff -ruN --exclude Makefile bios/Makefile.in bios.new/Makefile.in +rombios32.out: rombios32start.o rombios32.o rombios32.ld + ld -o $@ -T rombios32.ld rombios32start.o rombios32.o + -+rombios32.o: rombios32.c ++rombios32.o: rombios32.c acpi-dsdt.hex + $(GCC) -O2 -Wall -c -o $@ $< + ++ifeq ("1", "0") ++acpi-dsdt.hex: acpi-dsdt.dsl ++ iasl -tc -p $@ $< ++endif ++ +rombios32start.o: rombios32start.S + $(GCC) -c -o $@ $< + @@ -896,9 +901,9 @@ diff -ruN --exclude Makefile bios/Makefile.in bios.new/Makefile.in + biossums: biossums.c $(GCC) -o biossums biossums.c -diff -ruN --exclude Makefile bios/pad.c bios.new/pad.c ---- bios/pad.c 1970-01-01 01:00:00.000000000 +0100 -+++ bios.new/pad.c 2006-09-24 20:22:58.000000000 +0200 +diff -ruN --exclude Makefile bios.org/pad.c bios/pad.c +--- bios.org/pad.c 1970-01-01 01:00:00.000000000 +0100 ++++ bios/pad.c 2006-09-24 20:22:58.000000000 +0200 @@ -0,0 +1,20 @@ +#include +#include @@ -920,9 +925,9 @@ diff -ruN --exclude Makefile bios/pad.c bios.new/pad.c + } + return 0; +} -diff -ruN --exclude Makefile bios/rombios32.c bios.new/rombios32.c ---- bios/rombios32.c 1970-01-01 01:00:00.000000000 +0100 -+++ bios.new/rombios32.c 2006-09-24 20:22:58.000000000 +0200 +diff -ruN --exclude Makefile bios.org/rombios32.c bios/rombios32.c +--- bios.org/rombios32.c 1970-01-01 01:00:00.000000000 +0100 ++++ bios/rombios32.c 2006-09-24 21:29:27.000000000 +0200 @@ -0,0 +1,1324 @@ +// 32 bit Bochs BIOS init code +// Copyright (C) 2006 Fabrice Bellard @@ -1490,9 +1495,9 @@ diff -ruN --exclude Makefile bios/rombios32.c bios.new/rombios32.c + /* remap the BIOS to shadow RAM an keep it read/write while we + are writing tables */ + memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000); -+ v = pci_config_readb(d, 0x67); ++ v = pci_config_readb(d, 0x59); + v = (v & 0x0f) | (0x30); -+ pci_config_writeb(d, 0x67, v); ++ pci_config_writeb(d, 0x59, v); + memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000); + + i440_pcidev = *d; @@ -1503,9 +1508,9 @@ diff -ruN --exclude Makefile bios/rombios32.c bios.new/rombios32.c + PCIDevice *d = &i440_pcidev; + int v; + -+ v = pci_config_readb(d, 0x67); -+ v = (v & 0x0f) | (0x20); -+ pci_config_writeb(d, 0x67, v); ++ v = pci_config_readb(d, 0x59); ++ v = (v & 0x0f) | (0x10); ++ pci_config_writeb(d, 0x59, v); +} + +static void pci_bios_init_bridges(PCIDevice *d) @@ -1553,14 +1558,14 @@ diff -ruN --exclude Makefile bios/rombios32.c bios.new/rombios32.c + outb(0xb2, 00); + + /* enable the SMM memory window */ -+ pci_config_writel(&i440_pcidev, 0x6c, (1 << 26) | 0x000a); ++ pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x40); + + /* copy the SMM code */ + memcpy((void *)0xa8000, &smm_code_start, + &smm_code_end - &smm_code_start); + + /* close the SMM memory window and enable normal SMM */ -+ pci_config_writel(&i440_pcidev, 0x6c, (1 << 31) | 0x000a); ++ pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08); +} +#endif + @@ -2248,9 +2253,9 @@ diff -ruN --exclude Makefile bios/rombios32.c bios.new/rombios32.c + bios_lock_shadow_ram(); + } +} -diff -ruN --exclude Makefile bios/rombios32.ld bios.new/rombios32.ld ---- bios/rombios32.ld 1970-01-01 01:00:00.000000000 +0100 -+++ bios.new/rombios32.ld 2006-09-24 20:28:05.000000000 +0200 +diff -ruN --exclude Makefile bios.org/rombios32.ld bios/rombios32.ld +--- bios.org/rombios32.ld 1970-01-01 01:00:00.000000000 +0100 ++++ bios/rombios32.ld 2006-09-24 20:28:05.000000000 +0200 @@ -0,0 +1,19 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) @@ -2271,9 +2276,9 @@ diff -ruN --exclude Makefile bios/rombios32.ld bios.new/rombios32.ld + *(.note) + } +} -diff -ruN --exclude Makefile bios/rombios32start.S bios.new/rombios32start.S ---- bios/rombios32start.S 1970-01-01 01:00:00.000000000 +0100 -+++ bios.new/rombios32start.S 2006-09-24 20:22:58.000000000 +0200 +diff -ruN --exclude Makefile bios.org/rombios32start.S bios/rombios32start.S +--- bios.org/rombios32start.S 1970-01-01 01:00:00.000000000 +0100 ++++ bios/rombios32start.S 2006-09-24 20:22:58.000000000 +0200 @@ -0,0 +1,76 @@ +.globl _start +.globl smp_ap_boot_code_start @@ -2351,9 +2356,9 @@ diff -ruN --exclude Makefile bios/rombios32start.S bios.new/rombios32start.S +2: + rsm +smm_code_end: -diff -ruN --exclude Makefile bios/rombios.c bios.new/rombios.c ---- bios/rombios.c 2006-08-11 19:34:12.000000000 +0200 -+++ bios.new/rombios.c 2006-09-24 20:35:47.000000000 +0200 +diff -ruN --exclude Makefile bios.org/rombios.c bios/rombios.c +--- bios.org/rombios.c 2006-08-11 19:34:12.000000000 +0200 ++++ bios/rombios.c 2006-09-24 20:35:47.000000000 +0200 @@ -24,7 +24,7 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- cgit v1.2.3 From 17100159f159d7007fa8400fc00d71d5c822d08f Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 25 Sep 2006 21:33:49 +0000 Subject: fixed help info strings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2179 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monitor.c b/monitor.c index b40eac4c4..f2a2417dd 100644 --- a/monitor.c +++ b/monitor.c @@ -1230,9 +1230,9 @@ static term_cmd_t info_cmds[] = { { "profile", "", do_info_profile, "", "show profiling information", }, { "capture", "", do_info_capture, - "show capture information" }, + "", "show capture information" }, { "snapshots", "", do_info_snapshots, - "show the currently saved VM snapshots" }, + "", "show the currently saved VM snapshots" }, { NULL, NULL, }, }; -- cgit v1.2.3 From 6f15b608f2a1466de0dccc3e6d9cdee354a1e178 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 25 Sep 2006 21:34:25 +0000 Subject: removed unused code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2180 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/configure b/configure index e6c74e4ec..a2fde23ae 100755 --- a/configure +++ b/configure @@ -88,14 +88,12 @@ bsd="no" linux="no" kqemu="no" profiler="no" -kernel_path="" cocoa="no" check_gfx="yes" check_gcc="yes" softmmu="yes" user="no" build_docs="no" -build_acpi_tables="no" uname_release="" # OS specific @@ -223,8 +221,6 @@ for opt do ;; --enable-profiler) profiler="yes" ;; - --kernel-path=*) kernel_path="$optarg" - ;; --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" ;; --disable-gfx-check) check_gfx="no" @@ -241,8 +237,6 @@ for opt do ;; --enable-uname-release=*) uname_release="$optarg" ;; - --enable-iasl) build_acpi_tables="yes" - ;; esac done @@ -267,7 +261,6 @@ echo " --target-list=LIST set target list [$target_list]" echo "" echo "kqemu kernel acceleration support:" echo " --disable-kqemu disable kqemu support" -echo " --kernel-path=PATH set the kernel path (configure probes it)" echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]" @@ -291,7 +284,6 @@ 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 " --enable-iasl compilation of ACPI tables with the IASL compiler" echo "" echo "NOTE: The object files are build at the place where configure is launched" exit 1 @@ -712,9 +704,6 @@ echo "TARGET_DIRS=$target_list" >> $config_mak if [ "$build_docs" = "yes" ] ; then echo "BUILD_DOCS=yes" >> $config_mak fi -if [ "$build_acpi_tables" = "yes" ] ; then - echo "BUILD_ACPI_TABLES=yes" >> $config_mak -fi # XXX: suppress that if [ "$bsd" = "yes" ] ; then -- cgit v1.2.3 From 42fc925ec0df2cb8d924bec1c9fb782c12bd8364 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 25 Sep 2006 21:41:20 +0000 Subject: VBE 4 bit bank selection fix (Volker Rupper) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2181 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/vga.c b/hw/vga.c index 0609f84cc..5acacf9b3 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -447,7 +447,11 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) } break; case VBE_DISPI_INDEX_BANK: - val &= s->vbe_bank_mask; + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { + val &= (s->vbe_bank_mask >> 2); + } else { + val &= s->vbe_bank_mask; + } s->vbe_regs[s->vbe_index] = val; s->bank_offset = (val << 16); break; -- cgit v1.2.3 From 69c3bcb48f3dd61251bca66cba375b4147e4cfca Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Sep 2006 19:52:41 +0000 Subject: enabled PSE36 for x86_64 (fix for OpenSolaris as guest) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2182 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index f05ae4a69..dc6a5000e 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -135,6 +135,8 @@ CPUX86State *cpu_x86_init(void) /* these features are needed for Win64 and aren't fully implemented */ env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA; + /* this feature is needed for Solaris and isn't fully implemented */ + env->cpuid_features |= CPUID_PSE36; #endif } cpu_reset(env); -- cgit v1.2.3 From 8988ae8945f93049a0e416600d928a7b4ce8446f Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Sep 2006 19:54:02 +0000 Subject: SMM fix for x86_64 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2183 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 4 +++- target-i386/helper.c | 15 ++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 55e7a98c5..30507403e 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -260,6 +260,7 @@ #define CPUID_MCA (1 << 14) #define CPUID_CMOV (1 << 15) #define CPUID_PAT (1 << 16) +#define CPUID_PSE36 (1 << 17) #define CPUID_CLFLUSH (1 << 19) /* ... */ #define CPUID_MMX (1 << 23) @@ -543,7 +544,8 @@ void cpu_set_ferr(CPUX86State *s); cache: it synchronizes the hflags with the segment cache values */ static inline void cpu_x86_load_seg_cache(CPUX86State *env, int seg_reg, unsigned int selector, - uint32_t base, unsigned int limit, + target_ulong base, + unsigned int limit, unsigned int flags) { SegmentCache *sc; diff --git a/target-i386/helper.c b/target-i386/helper.c index d990c07ed..4017bee79 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1338,6 +1338,10 @@ void do_smm_enter(void) #endif /* init SMM cpu state */ +#ifdef TARGET_X86_64 + env->efer = 0; + env->hflags &= ~HF_LMA_MASK; +#endif load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); env->eip = 0x00008000; cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, @@ -1352,9 +1356,6 @@ void do_smm_enter(void) env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); cpu_x86_update_cr4(env, 0); env->dr[7] = 0x00000400; -#ifdef TARGET_X86_64 - env->efer = 0; -#endif CC_OP = CC_OP_EFLAGS; } @@ -1366,6 +1367,12 @@ void helper_rsm(void) sm_state = env->smbase + 0x8000; #ifdef TARGET_X86_64 + env->efer = ldq_phys(sm_state + 0x7ed0); + if (env->efer & MSR_EFER_LMA) + env->hflags |= HF_LMA_MASK; + else + env->hflags &= ~HF_LMA_MASK; + for(i = 0; i < 6; i++) { offset = 0x7e00 + i * 16; cpu_x86_load_seg_cache(env, i, @@ -1391,8 +1398,6 @@ void helper_rsm(void) env->tr.limit = ldl_phys(sm_state + 0x7e94); env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8; - env->efer = ldq_phys(sm_state + 0x7ed0); - EAX = ldq_phys(sm_state + 0x7ff8); ECX = ldq_phys(sm_state + 0x7ff0); EDX = ldq_phys(sm_state + 0x7fe8); -- cgit v1.2.3 From 74ce674fa856b37bf3ff46bff2c7a4a49810ed80 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 27 Sep 2006 21:31:59 +0000 Subject: fixed user mode emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2184 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/target-i386/helper.c b/target-i386/helper.c index 4017bee79..c2b5e1100 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1217,6 +1217,18 @@ void raise_exception(int exception_index) /* SMM support */ +#if defined(CONFIG_USER_ONLY) + +void do_smm_enter(void) +{ +} + +void helper_rsm(void) +{ +} + +#else + #ifdef TARGET_X86_64 #define SMM_REVISION_ID 0x00020064 #else @@ -1483,6 +1495,9 @@ void helper_rsm(void) } } +#endif /* !CONFIG_USER_ONLY */ + + #ifdef BUGGY_GCC_DIV64 /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we call it from another function */ -- cgit v1.2.3 From 5e966ce6f44c29c3b9d5349c25c75de145d8a0b1 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 28 Sep 2006 19:52:59 +0000 Subject: PCI IRC routing fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2185 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 7c9db0e8d..bc7c779e5 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -435,11 +435,12 @@ void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) return; pci_dev->irq_state[irq_num] = level; - bus = pci_dev->bus; - while (!bus->set_irq) { + for (;;) { + bus = pci_dev->bus; irq_num = bus->map_irq(pci_dev, irq_num); + if (bus->set_irq) + break; pci_dev = bus->parent_dev; - bus = pci_dev->bus; } bus->irq_count[irq_num] += change; bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); -- cgit v1.2.3 From 8d7b0fbb3f301e3cd9a018cc0650807e433c1ec5 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 29 Sep 2006 20:01:17 +0000 Subject: 32 bit RSP update fix (aka Open Solaris x86_64 bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2186 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index c2b5e1100..57777ff75 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -553,6 +553,20 @@ static inline unsigned int get_sp_mask(unsigned int e2) return 0xffff; } +#ifdef TARGET_X86_64 +#define SET_ESP(val, sp_mask)\ +do {\ + if ((sp_mask) == 0xffff)\ + ESP = (ESP & ~0xffff) | ((val) & 0xffff);\ + else if ((sp_mask) == 0xffffffffLL)\ + ESP = (uint32_t)(val);\ + else\ + ESP = (val);\ +} while (0) +#else +#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask)) +#endif + /* XXX: add a is_user flag to have proper security support */ #define PUSHW(ssp, sp, sp_mask, val)\ {\ @@ -584,10 +598,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, { SegmentCache *dt; target_ulong ptr, ssp; - int type, dpl, selector, ss_dpl, cpl, sp_mask; + int type, dpl, selector, ss_dpl, cpl; int has_error_code, new_stack, shift; uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; - uint32_t old_eip; + uint32_t old_eip, sp_mask; has_error_code = 0; if (!is_int && !is_hw) { @@ -623,7 +637,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip); if (has_error_code) { - int mask, type; + int type; + uint32_t mask; /* push the error code */ type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; shift = type >> 3; @@ -637,7 +652,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, stl_kernel(ssp, error_code); else stw_kernel(ssp, error_code); - ESP = (esp & mask) | (ESP & ~mask); + SET_ESP(esp, mask); } return; case 6: /* 286 interrupt gate */ @@ -765,7 +780,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, cpu_x86_load_seg_cache(env, R_SS, ss, ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); } - ESP = (ESP & ~sp_mask) | (esp & sp_mask); + SET_ESP(esp, sp_mask); selector = (selector & ~3) | dpl; cpu_x86_load_seg_cache(env, R_CS, selector, @@ -2015,7 +2030,7 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) PUSHW(ssp, esp, esp_mask, next_eip); } - ESP = (ESP & ~esp_mask) | (esp & esp_mask); + SET_ESP(esp, esp_mask); env->eip = new_eip; env->segs[R_CS].selector = new_cs; env->segs[R_CS].base = (new_cs << 4); @@ -2101,7 +2116,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) if (new_eip > limit) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); /* from this point, not restartable */ - ESP = (ESP & ~sp_mask) | (sp & sp_mask); + SET_ESP(sp, sp_mask); cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, get_seg_base(e1, e2), limit, e2); EIP = new_eip; @@ -2230,7 +2245,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) get_seg_limit(e1, e2), e2); cpu_x86_set_cpl(env, dpl); - ESP = (ESP & ~sp_mask) | (sp & sp_mask); + SET_ESP(sp, sp_mask); EIP = offset; } #ifdef USE_KQEMU @@ -2459,7 +2474,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) sp += addend; } - ESP = (ESP & ~sp_mask) | (sp & sp_mask); + SET_ESP(sp, sp_mask); env->eip = new_eip; if (is_iret) { /* NOTE: 'cpl' is the _old_ CPL */ -- cgit v1.2.3 From 326199c2707d45ecbbaa411f6640a152fc199d3e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 1 Oct 2006 13:03:52 +0000 Subject: ARM GIC bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2187 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm_gic.c b/hw/arm_gic.c index c7cc38088..94ce9aa34 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -383,7 +383,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, s->irq_target[irq] = value; } else if (offset < 0xf00) { /* Interrupt Configuration. */ - irq = (offset - 0xc00) * 2; + irq = (offset - 0xc00) * 4; if (irq >= GIC_NIRQ) goto bad_reg; for (i = 0; i < 4; i++) { -- cgit v1.2.3 From a7e6f8ba22f7406aa13048979c6573d80dac5605 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 1 Oct 2006 16:08:15 +0000 Subject: synced to Bochs BIOS - use 32 bit pushf/popf in 32 bit PCI bios - moved some useful defines in rombios.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2188 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/bios.diff | 3041 ++++------------------------------------------------- 2 files changed, 191 insertions(+), 2850 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 8e6de368a..1af4a4f0e 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index f89c77ef6..0bb1d345c 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,934 +1,158 @@ -diff -ruN --exclude Makefile bios.org/acpi-dsdt.dsl bios/acpi-dsdt.dsl ---- bios.org/acpi-dsdt.dsl 1970-01-01 01:00:00.000000000 +0100 -+++ bios/acpi-dsdt.dsl 2006-09-24 20:27:54.000000000 +0200 -@@ -0,0 +1,559 @@ -+/* -+ * QEMU ACPI DSDT ASL definition -+ * -+ * Copyright (c) 2006 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 version 2 as published by the Free Software Foundation. -+ * -+ * 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 -+ */ -+DefinitionBlock ( -+ "acpi-dsdt.aml", // Output Filename -+ "DSDT", // Signature -+ 0x01, // DSDT Compliance Revision -+ "QEMU", // OEMID -+ "QEMUDSDT", // TABLE ID -+ 0x1 // OEM Revision -+ ) -+{ -+ Scope (\) -+ { -+ /* CMOS memory access */ -+ OperationRegion (CMS, SystemIO, 0x70, 0x02) -+ Field (CMS, ByteAcc, NoLock, Preserve) -+ { -+ CMSI, 8, -+ CMSD, 8 -+ } -+ Method (CMRD, 1, NotSerialized) -+ { -+ Store (Arg0, CMSI) -+ Store (CMSD, Local0) -+ Return (Local0) -+ } -+ -+ /* Debug Output */ -+ OperationRegion (DBG, SystemIO, 0xb044, 0x04) -+ Field (DBG, DWordAcc, NoLock, Preserve) -+ { -+ DBGL, 32, -+ } -+ } -+ -+ -+ /* PCI Bus definition */ -+ Scope(\_SB) { -+ Device(PCI0) { -+ Name (_HID, EisaId ("PNP0A03")) -+ Name (_ADR, 0x00) -+ Name (_UID, 1) -+ Name(_PRT, Package() { -+ /* PCI IRQ routing table, example from ACPI 2.0a specification, -+ section 6.2.8.1 */ -+ /* Note: we provide the same info as the PCI routing -+ table of the Bochs BIOS */ -+ -+ // PCI Slot 0 -+ Package() {0x0000ffff, 0, LNKD, 0}, -+ Package() {0x0000ffff, 1, LNKA, 0}, -+ Package() {0x0000ffff, 2, LNKB, 0}, -+ Package() {0x0000ffff, 3, LNKC, 0}, -+ -+ // PCI Slot 1 -+ Package() {0x0001ffff, 0, LNKA, 0}, -+ Package() {0x0001ffff, 1, LNKB, 0}, -+ Package() {0x0001ffff, 2, LNKC, 0}, -+ Package() {0x0001ffff, 3, LNKD, 0}, -+ -+ // PCI Slot 2 -+ Package() {0x0002ffff, 0, LNKB, 0}, -+ Package() {0x0002ffff, 1, LNKC, 0}, -+ Package() {0x0002ffff, 2, LNKD, 0}, -+ Package() {0x0002ffff, 3, LNKA, 0}, -+ -+ // PCI Slot 3 -+ Package() {0x0003ffff, 0, LNKC, 0}, -+ Package() {0x0003ffff, 1, LNKD, 0}, -+ Package() {0x0003ffff, 2, LNKA, 0}, -+ Package() {0x0003ffff, 3, LNKB, 0}, -+ -+ // PCI Slot 4 -+ Package() {0x0004ffff, 0, LNKD, 0}, -+ Package() {0x0004ffff, 1, LNKA, 0}, -+ Package() {0x0004ffff, 2, LNKB, 0}, -+ Package() {0x0004ffff, 3, LNKC, 0}, -+ -+ // PCI Slot 5 -+ Package() {0x0005ffff, 0, LNKA, 0}, -+ Package() {0x0005ffff, 1, LNKB, 0}, -+ Package() {0x0005ffff, 2, LNKC, 0}, -+ Package() {0x0005ffff, 3, LNKD, 0}, -+ }) -+ -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (MEMP, ResourceTemplate () -+ { -+ WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, -+ 0x0000, // Address Space Granularity -+ 0x0000, // Address Range Minimum -+ 0x00FF, // Address Range Maximum -+ 0x0000, // Address Translation Offset -+ 0x0100, // Address Length -+ ,, ) -+ IO (Decode16, -+ 0x0CF8, // Address Range Minimum -+ 0x0CF8, // Address Range Maximum -+ 0x01, // Address Alignment -+ 0x08, // Address Length -+ ) -+ WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, -+ 0x0000, // Address Space Granularity -+ 0x0000, // Address Range Minimum -+ 0x0CF7, // Address Range Maximum -+ 0x0000, // Address Translation Offset -+ 0x0CF8, // Address Length -+ ,, , TypeStatic) -+ WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, -+ 0x0000, // Address Space Granularity -+ 0x0D00, // Address Range Minimum -+ 0xFFFF, // Address Range Maximum -+ 0x0000, // Address Translation Offset -+ 0xF300, // Address Length -+ ,, , TypeStatic) -+ DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, -+ 0x00000000, // Address Space Granularity -+ 0x000A0000, // Address Range Minimum -+ 0x000BFFFF, // Address Range Maximum -+ 0x00000000, // Address Translation Offset -+ 0x00020000, // Address Length -+ ,, , AddressRangeMemory, TypeStatic) -+ DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite, -+ 0x00000000, // Address Space Granularity -+ 0x00000000, // Address Range Minimum -+ 0xFEBFFFFF, // Address Range Maximum -+ 0x00000000, // Address Translation Offset -+ 0x00000000, // Address Length -+ ,, MEMF, AddressRangeMemory, TypeStatic) -+ }) -+ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN) -+ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX) -+ CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN) -+ /* compute available RAM */ -+ Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0) -+ ShiftLeft(Local0, 16, Local0) -+ Add(Local0, 0x1000000, Local0) -+ /* update field of last region */ -+ Store(Local0, PMIN) -+ Subtract (PMAX, PMIN, PLEN) -+ Increment (PLEN) -+ Return (MEMP) -+ } -+ } -+ } -+ -+ Scope(\_SB.PCI0) { -+ -+ /* PIIX3 ISA bridge */ -+ Device (ISA) { -+ Name (_ADR, 0x00010000) -+ -+ /* PIIX PCI to ISA irq remapping */ -+ OperationRegion (P40C, PCI_Config, 0x60, 0x04) -+ -+ -+ /* Keyboard seems to be important for WinXP install */ -+ Device (KBD) -+ { -+ Name (_HID, EisaId ("PNP0303")) -+ Method (_STA, 0, NotSerialized) -+ { -+ Return (0x0f) -+ } -+ -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (TMP, ResourceTemplate () -+ { -+ IO (Decode16, -+ 0x0060, // Address Range Minimum -+ 0x0060, // Address Range Maximum -+ 0x01, // Address Alignment -+ 0x01, // Address Length -+ ) -+ IO (Decode16, -+ 0x0064, // Address Range Minimum -+ 0x0064, // Address Range Maximum -+ 0x01, // Address Alignment -+ 0x01, // Address Length -+ ) -+ IRQNoFlags () -+ {1} -+ }) -+ Return (TMP) -+ } -+ } -+ -+ /* PS/2 mouse */ -+ Device (MOU) -+ { -+ Name (_HID, EisaId ("PNP0F13")) -+ Method (_STA, 0, NotSerialized) -+ { -+ Return (0x0f) -+ } -+ -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (TMP, ResourceTemplate () -+ { -+ IRQNoFlags () {12} -+ }) -+ Return (TMP) -+ } -+ } -+ -+ /* PS/2 floppy controller */ -+ Device (FDC0) -+ { -+ Name (_HID, EisaId ("PNP0700")) -+ Method (_STA, 0, NotSerialized) -+ { -+ Return (0x0F) -+ } -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (BUF0, ResourceTemplate () -+ { -+ IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04) -+ IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01) -+ IRQNoFlags () {6} -+ DMA (Compatibility, NotBusMaster, Transfer8) {2} -+ }) -+ Return (BUF0) -+ } -+ } -+ -+ /* Parallel port */ -+ Device (LPT) -+ { -+ Name (_HID, EisaId ("PNP0400")) -+ Method (_STA, 0, NotSerialized) -+ { -+ Store (\_SB.PCI0.PX13.DRSA, Local0) -+ And (Local0, 0x80000000, Local0) -+ If (LEqual (Local0, 0)) -+ { -+ Return (0x00) -+ } -+ Else -+ { -+ Return (0x0F) -+ } -+ } -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (BUF0, ResourceTemplate () -+ { -+ IO (Decode16, 0x0378, 0x0378, 0x08, 0x08) -+ IRQNoFlags () {7} -+ }) -+ Return (BUF0) -+ } -+ } -+ -+ /* Serial Ports */ -+ Device (COM1) -+ { -+ Name (_HID, EisaId ("PNP0501")) -+ Name (_UID, 0x01) -+ Method (_STA, 0, NotSerialized) -+ { -+ Store (\_SB.PCI0.PX13.DRSC, Local0) -+ And (Local0, 0x08000000, Local0) -+ If (LEqual (Local0, 0)) -+ { -+ Return (0x00) -+ } -+ Else -+ { -+ Return (0x0F) -+ } -+ } -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (BUF0, ResourceTemplate () -+ { -+ IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08) -+ IRQNoFlags () {4} -+ }) -+ Return (BUF0) -+ } -+ } -+ -+ Device (COM2) -+ { -+ Name (_HID, EisaId ("PNP0501")) -+ Name (_UID, 0x02) -+ Method (_STA, 0, NotSerialized) -+ { -+ Store (\_SB.PCI0.PX13.DRSC, Local0) -+ And (Local0, 0x80000000, Local0) -+ If (LEqual (Local0, 0)) -+ { -+ Return (0x00) -+ } -+ Else -+ { -+ Return (0x0F) -+ } -+ } -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (BUF0, ResourceTemplate () -+ { -+ IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08) -+ IRQNoFlags () {3} -+ }) -+ Return (BUF0) -+ } -+ } -+ } -+ -+ /* PIIX4 PM */ -+ Device (PX13) { -+ Name (_ADR, 0x00010003) -+ -+ OperationRegion (P13C, PCI_Config, 0x5c, 0x24) -+ Field (P13C, DWordAcc, NoLock, Preserve) -+ { -+ DRSA, 32, -+ DRSB, 32, -+ DRSC, 32, -+ DRSE, 32, -+ DRSF, 32, -+ DRSG, 32, -+ DRSH, 32, -+ DRSI, 32, -+ DRSJ, 32 -+ } -+ } -+ } -+ -+ /* PCI IRQs */ -+ Scope(\_SB) { -+ Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) -+ { -+ PRQ0, 8, -+ PRQ1, 8, -+ PRQ2, 8, -+ PRQ3, 8 -+ } -+ -+ Device(LNKA){ -+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link -+ Name(_UID, 1) -+ Name(_PRS, ResourceTemplate(){ -+ IRQ (Level, ActiveLow, Shared) -+ {3,4,5,6,7,9,10,11,12} -+ }) -+ Method (_STA, 0, NotSerialized) -+ { -+ Store (0x0B, Local0) -+ If (And (0x80, PRQ0, Local1)) -+ { -+ Store (0x09, Local0) -+ } -+ Return (Local0) -+ } -+ Method (_DIS, 0, NotSerialized) -+ { -+ Or (PRQ0, 0x80, PRQ0) -+ } -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (PRR0, ResourceTemplate () -+ { -+ IRQ (Level, ActiveLow, Shared) -+ {1} -+ }) -+ CreateWordField (PRR0, 0x01, TMP) -+ Store (PRQ0, Local0) -+ If (LLess (Local0, 0x80)) -+ { -+ ShiftLeft (One, Local0, TMP) -+ } -+ Else -+ { -+ Store (Zero, TMP) -+ } -+ Return (PRR0) -+ } -+ Method (_SRS, 1, NotSerialized) -+ { -+ CreateWordField (Arg0, 0x01, TMP) -+ FindSetRightBit (TMP, Local0) -+ Decrement (Local0) -+ Store (Local0, PRQ0) -+ } -+ } -+ Device(LNKB){ -+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link -+ Name(_UID, 2) -+ Name(_PRS, ResourceTemplate(){ -+ IRQ (Level, ActiveLow, Shared) -+ {3,4,5,6,7,9,10,11,12} -+ }) -+ Method (_STA, 0, NotSerialized) -+ { -+ Store (0x0B, Local0) -+ If (And (0x80, PRQ1, Local1)) -+ { -+ Store (0x09, Local0) -+ } -+ Return (Local0) -+ } -+ Method (_DIS, 0, NotSerialized) -+ { -+ Or (PRQ1, 0x80, PRQ1) -+ } -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (PRR0, ResourceTemplate () -+ { -+ IRQ (Level, ActiveLow, Shared) -+ {1} -+ }) -+ CreateWordField (PRR0, 0x01, TMP) -+ Store (PRQ1, Local0) -+ If (LLess (Local0, 0x80)) -+ { -+ ShiftLeft (One, Local0, TMP) -+ } -+ Else -+ { -+ Store (Zero, TMP) -+ } -+ Return (PRR0) -+ } -+ Method (_SRS, 1, NotSerialized) -+ { -+ CreateWordField (Arg0, 0x01, TMP) -+ FindSetRightBit (TMP, Local0) -+ Decrement (Local0) -+ Store (Local0, PRQ1) -+ } -+ } -+ Device(LNKC){ -+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link -+ Name(_UID, 3) -+ Name(_PRS, ResourceTemplate(){ -+ IRQ (Level, ActiveLow, Shared) -+ {3,4,5,6,7,9,10,11,12} -+ }) -+ Method (_STA, 0, NotSerialized) -+ { -+ Store (0x0B, Local0) -+ If (And (0x80, PRQ2, Local1)) -+ { -+ Store (0x09, Local0) -+ } -+ Return (Local0) -+ } -+ Method (_DIS, 0, NotSerialized) -+ { -+ Or (PRQ2, 0x80, PRQ2) -+ } -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (PRR0, ResourceTemplate () -+ { -+ IRQ (Level, ActiveLow, Shared) -+ {1} -+ }) -+ CreateWordField (PRR0, 0x01, TMP) -+ Store (PRQ2, Local0) -+ If (LLess (Local0, 0x80)) -+ { -+ ShiftLeft (One, Local0, TMP) -+ } -+ Else -+ { -+ Store (Zero, TMP) -+ } -+ Return (PRR0) -+ } -+ Method (_SRS, 1, NotSerialized) -+ { -+ CreateWordField (Arg0, 0x01, TMP) -+ FindSetRightBit (TMP, Local0) -+ Decrement (Local0) -+ Store (Local0, PRQ2) -+ } -+ } -+ Device(LNKD){ -+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link -+ Name(_UID, 4) -+ Name(_PRS, ResourceTemplate(){ -+ IRQ (Level, ActiveLow, Shared) -+ {3,4,5,6,7,9,10,11,12} -+ }) -+ Method (_STA, 0, NotSerialized) -+ { -+ Store (0x0B, Local0) -+ If (And (0x80, PRQ3, Local1)) -+ { -+ Store (0x09, Local0) -+ } -+ Return (Local0) -+ } -+ Method (_DIS, 0, NotSerialized) -+ { -+ Or (PRQ3, 0x80, PRQ3) -+ } -+ Method (_CRS, 0, NotSerialized) -+ { -+ Name (PRR0, ResourceTemplate () -+ { -+ IRQ (Level, ActiveLow, Shared) -+ {1} -+ }) -+ CreateWordField (PRR0, 0x01, TMP) -+ Store (PRQ3, Local0) -+ If (LLess (Local0, 0x80)) -+ { -+ ShiftLeft (One, Local0, TMP) -+ } -+ Else -+ { -+ Store (Zero, TMP) -+ } -+ Return (PRR0) -+ } -+ Method (_SRS, 1, NotSerialized) -+ { -+ CreateWordField (Arg0, 0x01, TMP) -+ FindSetRightBit (TMP, Local0) -+ Decrement (Local0) -+ Store (Local0, PRQ3) -+ } -+ } -+ } -+ -+ /* S5 = power off state */ -+ Name (_S5, Package (4) { -+ 0x00, // PM1a_CNT.SLP_TYP -+ 0x00, // PM2a_CNT.SLP_TYP -+ 0x00, // reserved -+ 0x00, // reserved -+ }) -+} -diff -ruN --exclude Makefile bios.org/acpi-dsdt.hex bios/acpi-dsdt.hex ---- bios.org/acpi-dsdt.hex 1970-01-01 01:00:00.000000000 +0100 -+++ bios/acpi-dsdt.hex 2006-09-24 20:27:54.000000000 +0200 -@@ -0,0 +1,278 @@ -+/* -+ * -+ * Intel ACPI Component Architecture -+ * ASL Optimizing Compiler version 20060421 [Apr 29 2006] -+ * Copyright (C) 2000 - 2006 Intel Corporation -+ * Supports ACPI Specification Revision 3.0a -+ * -+ * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006 -+ * -+ * C source code output -+ * -+ */ -+unsigned char AmlCode[] = -+{ -+ 0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */ -+ 0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */ -+ 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */ -+ 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ -+ 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */ -+ 0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */ -+ 0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */ -+ 0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */ -+ 0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */ -+ 0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */ -+ 0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */ -+ 0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */ -+ 0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */ -+ 0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */ -+ 0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */ -+ 0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */ -+ 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */ -+ 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */ -+ 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */ -+ 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */ -+ 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */ -+ 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */ -+ 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */ -+ 0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */ -+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */ -+ 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */ -+ 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */ -+ 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */ -+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */ -+ 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */ -+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */ -+ 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */ -+ 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */ -+ 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */ -+ 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */ -+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */ -+ 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */ -+ 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */ -+ 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */ -+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */ -+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */ -+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */ -+ 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */ -+ 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */ -+ 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */ -+ 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */ -+ 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */ -+ 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */ -+ 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */ -+ 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */ -+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */ -+ 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */ -+ 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */ -+ 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */ -+ 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */ -+ 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */ -+ 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */ -+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */ -+ 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */ -+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */ -+ 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */ -+ 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */ -+ 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */ -+ 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */ -+ 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */ -+ 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */ -+ 0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */ -+ 0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */ -+ 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */ -+ 0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */ -+ 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */ -+ 0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */ -+ 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */ -+ 0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */ -+ 0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */ -+ 0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */ -+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */ -+ 0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */ -+ 0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */ -+ 0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */ -+ 0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */ -+ 0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */ -+ 0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */ -+ 0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */ -+ 0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */ -+ 0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */ -+ 0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */ -+ 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */ -+ 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */ -+ 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */ -+ 0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */ -+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */ -+ 0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */ -+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */ -+ 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */ -+ 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */ -+ 0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */ -+ 0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */ -+ 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */ -+ 0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */ -+ 0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */ -+ 0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */ -+ 0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */ -+ 0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */ -+ 0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */ -+ 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */ -+ 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */ -+ 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */ -+ 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */ -+ 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */ -+ 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */ -+ 0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */ -+ 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */ -+ 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */ -+ 0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */ -+ 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */ -+ 0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */ -+ 0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */ -+ 0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */ -+ 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */ -+ 0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */ -+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */ -+ 0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */ -+ 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */ -+ 0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */ -+ 0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */ -+ 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */ -+ 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */ -+ 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */ -+ 0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */ -+ 0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */ -+ 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */ -+ 0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */ -+ 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */ -+ 0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */ -+ 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */ -+ 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */ -+ 0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */ -+ 0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */ -+ 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */ -+ 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */ -+ 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */ -+ 0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */ -+ 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */ -+ 0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */ -+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */ -+ 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */ -+ 0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */ -+ 0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */ -+ 0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */ -+ 0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */ -+ 0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */ -+ 0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */ -+ 0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */ -+ 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */ -+ 0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */ -+ 0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */ -+ 0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */ -+ 0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */ -+ 0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */ -+ 0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */ -+ 0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */ -+ 0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */ -+ 0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */ -+ 0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */ -+ 0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */ -+ 0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */ -+ 0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */ -+ 0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */ -+ 0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */ -+ 0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */ -+ 0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */ -+ 0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */ -+ 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */ -+ 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */ -+ 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */ -+ 0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */ -+ 0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */ -+ 0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */ -+ 0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */ -+ 0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */ -+ 0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */ -+ 0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */ -+ 0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */ -+ 0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */ -+ 0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */ -+ 0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */ -+ 0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */ -+ 0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */ -+ 0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */ -+ 0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */ -+ 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */ -+ 0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */ -+ 0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */ -+ 0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */ -+ 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */ -+ 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */ -+ 0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */ -+ 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */ -+ 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */ -+ 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */ -+ 0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */ -+ 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */ -+ 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */ -+ 0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */ -+ 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */ -+ 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */ -+ 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */ -+ 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */ -+ 0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */ -+ 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */ -+ 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */ -+ 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */ -+ 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */ -+ 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */ -+ 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */ -+ 0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */ -+ 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */ -+ 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */ -+ 0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */ -+ 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */ -+ 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */ -+ 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */ -+ 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */ -+ 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */ -+ 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */ -+ 0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */ -+ 0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */ -+ 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */ -+ 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */ -+ 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */ -+ 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */ -+ 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */ -+ 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */ -+ 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */ -+ 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */ -+ 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */ -+ 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */ -+ 0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */ -+ 0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */ -+ 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */ -+ 0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */ -+ 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */ -+ 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */ -+ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */ -+ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */ -+ 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */ -+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */ -+ 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */ -+ 0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */ -+ 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */ -+ 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */ -+ 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */ -+ 0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */ -+ 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */ -+ 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */ -+ 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */ -+ 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */ -+ 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */ -+ 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */ -+ 0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */ -+ 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */ -+ 0x00,0x00, -+}; -Binary files bios.org/BIOS-bochs-latest and bios/BIOS-bochs-latest differ -diff -ruN --exclude Makefile bios.org/Makefile.in bios/Makefile.in ---- bios.org/Makefile.in 2006-01-13 18:36:27.000000000 +0100 -+++ bios/Makefile.in 2006-09-24 21:37:05.000000000 +0200 -@@ -61,7 +61,8 @@ +Index: BIOS-bochs-latest +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/BIOS-bochs-latest,v +retrieving revision 1.133 +diff -u -w -r1.133 BIOS-bochs-latest +Binary files /tmp/cvsrjjP5I and BIOS-bochs-latest differ +Index: rombios.c +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v +retrieving revision 1.170 +diff -u -w -r1.170 rombios.c +--- rombios.c 30 Sep 2006 11:22:53 -0000 1.170 ++++ rombios.c 1 Oct 2006 16:03:53 -0000 +@@ -4115,7 +4115,7 @@ + case 3: + set_e820_range(ES, regs.u.r16.di, + 0x00100000L, +- extended_memory_size - 0x10000L, 1); ++ extended_memory_size - ACPI_DATA_SIZE, 1); + regs.u.r32.ebx = 4; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; +@@ -4124,7 +4124,7 @@ + break; + case 4: + set_e820_range(ES, regs.u.r16.di, +- extended_memory_size - 0x10000L, ++ extended_memory_size - ACPI_DATA_SIZE, + extended_memory_size, 3); // ACPI RAM + regs.u.r32.ebx = 5; + regs.u.r32.eax = 0x534D4150; +@@ -8723,7 +8723,7 @@ + + .align 16 + bios32_entry_point: +- pushf ++ pushfd + cmp eax, #0x49435024 ;; "$PCI" + jne unknown_service + mov eax, #0x80000000 +@@ -8750,12 +8750,12 @@ + #ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu + #endif +- popf ++ popfd + retf - clean: - @RMCOMMAND@ *.o *.a *.s _rombios*_.c rombios*.txt rombios*.sym -- @RMCOMMAND@ usage biossums -+ @RMCOMMAND@ usage biossums rombios16.bin -+ @RMCOMMAND@ rombios32.bin rombios32.out pad tmp32.bin + .align 16 + pcibios_protected: +- pushf ++ pushfd + cli + push esi + push edi +@@ -8864,7 +8864,7 @@ + #ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu + #endif +- popf ++ popfd + stc + retf + pci_pro_ok: +@@ -8874,7 +8874,7 @@ + #ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu + #endif +- popf ++ popfd + clc + retf - dist-clean: clean - @RMCOMMAND@ Makefile -@@ -69,15 +70,40 @@ - bios-clean: - @RMCOMMAND@ BIOS-bochs-* +Index: rombios.h +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/rombios.h,v +retrieving revision 1.1 +diff -u -w -r1.1 rombios.h +--- rombios.h 30 Sep 2006 11:22:53 -0000 1.1 ++++ rombios.h 1 Oct 2006 16:03:54 -0000 +@@ -19,7 +19,7 @@ + // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA --BIOS-bochs-latest: rombios.c apmbios.S biossums -+rombios16.bin: rombios.c apmbios.S biossums - $(GCC) $(BIOS_BUILD_DATE) -E -P $< > _rombios_.c - $(BCC) -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c - sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s - $(AS86) _rombios_.s -b tmp.bin -u- -w- -g -0 -j -O -l rombios.txt - -perl ${srcdir}/makesym.perl < rombios.txt > rombios.sym -- mv tmp.bin BIOS-bochs-latest -- ./biossums BIOS-bochs-latest -+ mv tmp.bin rombios16.bin -+ ./biossums rombios16.bin - rm -f _rombios_.s + /* define it to include QEMU specific code */ +-//#define BX_QEMU ++#define BX_QEMU + #define BX_ROMBIOS32 1 + #define DEBUG_ROMBIOS 0 +@@ -48,3 +48,7 @@ + #endif + #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) + #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p) + -+rombios32.bin: rombios32.out pad -+ objcopy -O binary $< tmp32.bin -+ ./pad < tmp32.bin > $@ 65536 0xff -+ -+rombios32.out: rombios32start.o rombios32.o rombios32.ld -+ ld -o $@ -T rombios32.ld rombios32start.o rombios32.o -+ -+rombios32.o: rombios32.c acpi-dsdt.hex -+ $(GCC) -O2 -Wall -c -o $@ $< -+ -+ifeq ("1", "0") -+acpi-dsdt.hex: acpi-dsdt.dsl -+ iasl -tc -p $@ $< -+endif -+ -+rombios32start.o: rombios32start.S -+ $(GCC) -c -o $@ $< -+ -+BIOS-bochs-latest: rombios16.bin rombios32.bin -+ cat rombios32.bin rombios16.bin > $@ -+ -+pad: pad.c -+ $(GCC) -o $@ $< -+ - biossums: biossums.c - $(GCC) -o biossums biossums.c -diff -ruN --exclude Makefile bios.org/pad.c bios/pad.c ---- bios.org/pad.c 1970-01-01 01:00:00.000000000 +0100 -+++ bios/pad.c 2006-09-24 20:22:58.000000000 +0200 -@@ -0,0 +1,20 @@ -+#include -+#include -+ -+int main(int argc, char **argv) -+{ -+ int len, val, i, c; -+ -+ len = strtol(argv[1], NULL, 0); -+ val = strtol(argv[2], NULL, 0); -+ for(i = 0 ; i < len; i++) { -+ c = getchar(); -+ if (c == EOF) -+ break; -+ putchar(c); -+ } -+ for( ; i < len; i++) { -+ putchar(val); -+ } -+ return 0; -+} -diff -ruN --exclude Makefile bios.org/rombios32.c bios/rombios32.c ---- bios.org/rombios32.c 1970-01-01 01:00:00.000000000 +0100 -+++ bios/rombios32.c 2006-09-24 21:29:27.000000000 +0200 -@@ -0,0 +1,1324 @@ ++#define ACPI_DATA_SIZE 0x00010000L ++#define PM_IO_BASE 0xb000 ++#define CPU_COUNT_ADDR 0xf000 +Index: rombios32.c +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/rombios32.c,v +retrieving revision 1.4 +diff -u -w -r1.4 rombios32.c +--- rombios32.c 30 Sep 2006 11:22:53 -0000 1.4 ++++ rombios32.c 1 Oct 2006 16:03:54 -0000 +@@ -55,13 +55,10 @@ + + #define APIC_ENABLED 0x0100 + +-#define CPU_COUNT_ADDR 0xf000 + #define AP_BOOT_ADDR 0x10000 + + #define MPTABLE_MAX_SIZE 0x00002000 +-#define ACPI_DATA_SIZE 0x00010000 + #define SMI_CMD_IO_ADDR 0xb2 +-#define PM_IO_BASE 0xb000 + + #define BIOS_TMP_STORAGE 0x00030000 /* 64 KB used to copy the BIOS to shadow RAM */ + +@@ -354,12 +351,14 @@ + + void delay_ms(int n) + { +- int i, j, r1, r2; ++ int i, j; + for(i = 0; i < n; i++) { +-#if BX_QEMU ++#ifdef BX_QEMU + /* approximative ! */ + for(j = 0; j < 1000000; j++); + #else ++ { ++ int r1, r2; + j = 66; + r1 = inb(0x61) & 0x10; + do { +@@ -369,6 +368,7 @@ + r1 = r2; + } + } while (j > 0); ++ } + #endif + } + } +Index: rombios32start.S +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/rombios32start.S,v +retrieving revision 1.1 +diff -u -w -r1.1 rombios32start.S +--- rombios32start.S 28 Sep 2006 18:56:20 -0000 1.1 ++++ rombios32start.S 1 Oct 2006 16:03:54 -0000 +@@ -1,3 +1,25 @@ ++///////////////////////////////////////////////////////////////////////// ++// $Id: bios.diff,v 1.15 2006-10-01 16:08:15 bellard Exp $ ++///////////////////////////////////////////////////////////////////////// ++// +// 32 bit Bochs BIOS init code +// Copyright (C) 2006 Fabrice Bellard +// @@ -945,1933 +169,50 @@ diff -ruN --exclude Makefile bios.org/rombios32.c bios/rombios32.c +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+#include -+#include -+ -+typedef signed char int8_t; -+typedef short int16_t; -+typedef int int32_t; -+typedef long long int64_t; -+typedef unsigned char uint8_t; -+typedef unsigned short uint16_t; -+typedef unsigned int uint32_t; -+typedef unsigned long long uint64_t; -+ -+/* if true, put the MP float table and ACPI RSDT in EBDA and the MP -+ table in RAM. Unfortunately, Linux has bugs with that, so we prefer -+ to modify the BIOS in shadow RAM */ -+//#define BX_USE_EBDA_TABLES -+ -+/* define it if the (emulated) hardware supports SMM mode */ -+#define BX_USE_SMM -+ -+#define BX_INFO(fmt, args...) bios_printf(0, fmt, ## args); -+ -+#define INFO_PORT 0x402 -+ -+#define cpuid(index, eax, ebx, ecx, edx) \ -+ asm volatile ("cpuid" \ -+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \ -+ : "0" (index)) -+ -+#define CPUID_APIC (1 << 9) -+ -+#define APIC_BASE ((uint8_t *)0xfee00000) -+#define APIC_ICR_LOW 0x300 -+#define APIC_SVR 0x0F0 -+#define APIC_ID 0x020 -+#define APIC_LVT3 0x370 -+ -+#define APIC_ENABLED 0x0100 -+ -+#define CPU_COUNT_ADDR 0xf000 -+#define AP_BOOT_ADDR 0x10000 -+ -+#define MPTABLE_MAX_SIZE 0x00002000 -+#define ACPI_DATA_SIZE 0x00010000 -+#define SMI_CMD_IO_ADDR 0xb2 -+#define PM_IO_BASE 0xb000 -+ -+#define BIOS_TMP_STORAGE 0x00030000 /* 64 KB used to copy the BIOS to shadow RAM */ -+ -+static inline void outl(int addr, int val) -+{ -+ asm volatile ("outl %1, %w0" : : "d" (addr), "a" (val)); -+} -+ -+static inline void outw(int addr, int val) -+{ -+ asm volatile ("outw %w1, %w0" : : "d" (addr), "a" (val)); -+} -+ -+static inline void outb(int addr, int val) -+{ -+ asm volatile ("outb %b1, %w0" : : "d" (addr), "a" (val)); -+} -+ -+static inline uint32_t inl(int addr) -+{ -+ uint32_t val; -+ asm volatile ("inl %w1, %0" : "=a" (val) : "d" (addr)); -+ return val; -+} -+ -+static inline uint16_t inw(int addr) -+{ -+ uint16_t val; -+ asm volatile ("inw %w1, %w0" : "=a" (val) : "d" (addr)); -+ return val; -+} -+ -+static inline uint8_t inb(int addr) -+{ -+ uint8_t val; -+ asm volatile ("inb %w1, %b0" : "=a" (val) : "d" (addr)); -+ return val; -+} -+ -+static inline void writel(void *addr, uint32_t val) -+{ -+ *(volatile uint32_t *)addr = val; -+} -+ -+static inline void writew(void *addr, uint16_t val) -+{ -+ *(volatile uint16_t *)addr = val; -+} -+ -+static inline void writeb(void *addr, uint8_t val) -+{ -+ *(volatile uint8_t *)addr = val; -+} -+ -+static inline uint32_t readl(const void *addr) -+{ -+ return *(volatile const uint32_t *)addr; -+} -+ -+static inline uint16_t readw(const void *addr) -+{ -+ return *(volatile const uint16_t *)addr; -+} -+ -+static inline uint8_t readb(const void *addr) -+{ -+ return *(volatile const uint8_t *)addr; -+} -+ -+static inline void putc(int c) -+{ -+ outb(INFO_PORT, c); -+} -+ -+static inline int isdigit(int c) -+{ -+ return c >= '0' && c <= '9'; -+} -+ -+void *memset(void *d1, int val, size_t len) -+{ -+ uint8_t *d = d1; -+ -+ while (len--) { -+ *d++ = val; -+ } -+ return d1; -+} -+ -+void *memcpy(void *d1, const void *s1, size_t len) -+{ -+ uint8_t *d = d1; -+ const uint8_t *s = s1; -+ -+ while (len--) { -+ *d++ = *s++; -+ } -+ return d1; -+} -+ -+void *memmove(void *d1, const void *s1, size_t len) -+{ -+ uint8_t *d = d1; -+ const uint8_t *s = s1; -+ -+ if (d <= s) { -+ while (len--) { -+ *d++ = *s++; -+ } -+ } else { -+ d += len; -+ s += len; -+ while (len--) { -+ *--d = *--s; -+ } -+ } -+ return d1; -+} -+ -+size_t strlen(const char *s) -+{ -+ const char *s1; -+ for(s1 = s; *s1 != '\0'; s1++); -+ return s1 - s; -+} -+ -+/* from BSD ppp sources */ -+int vsnprintf(char *buf, int buflen, const char *fmt, va_list args) -+{ -+ int c, i, n; -+ int width, prec, fillch; -+ int base, len, neg; -+ unsigned long val = 0; -+ const char *f; -+ char *str, *buf0; -+ char num[32]; -+ static const char hexchars[] = "0123456789abcdef"; -+ -+ buf0 = buf; -+ --buflen; -+ while (buflen > 0) { -+ for (f = fmt; *f != '%' && *f != 0; ++f) -+ ; -+ if (f > fmt) { -+ len = f - fmt; -+ if (len > buflen) -+ len = buflen; -+ memcpy(buf, fmt, len); -+ buf += len; -+ buflen -= len; -+ fmt = f; -+ } -+ if (*fmt == 0) -+ break; -+ c = *++fmt; -+ width = prec = 0; -+ fillch = ' '; -+ if (c == '0') { -+ fillch = '0'; -+ c = *++fmt; -+ } -+ if (c == '*') { -+ width = va_arg(args, int); -+ c = *++fmt; -+ } else { -+ while (isdigit(c)) { -+ width = width * 10 + c - '0'; -+ c = *++fmt; -+ } -+ } -+ if (c == '.') { -+ c = *++fmt; -+ if (c == '*') { -+ prec = va_arg(args, int); -+ c = *++fmt; -+ } else { -+ while (isdigit(c)) { -+ prec = prec * 10 + c - '0'; -+ c = *++fmt; -+ } -+ } -+ } -+ /* modifiers */ -+ switch(c) { -+ case 'l': -+ c = *++fmt; -+ break; -+ default: -+ break; -+ } -+ str = 0; -+ base = 0; -+ neg = 0; -+ ++fmt; -+ switch (c) { -+ case 'd': -+ i = va_arg(args, int); -+ if (i < 0) { -+ neg = 1; -+ val = -i; -+ } else -+ val = i; -+ base = 10; -+ break; -+ case 'o': -+ val = va_arg(args, unsigned int); -+ base = 8; -+ break; -+ case 'x': -+ case 'X': -+ val = va_arg(args, unsigned int); -+ base = 16; -+ break; -+ case 'p': -+ val = (unsigned long) va_arg(args, void *); -+ base = 16; -+ neg = 2; -+ break; -+ case 's': -+ str = va_arg(args, char *); -+ break; -+ case 'c': -+ num[0] = va_arg(args, int); -+ num[1] = 0; -+ str = num; -+ break; -+ default: -+ *buf++ = '%'; -+ if (c != '%') -+ --fmt; /* so %z outputs %z etc. */ -+ --buflen; -+ continue; -+ } -+ if (base != 0) { -+ str = num + sizeof(num); -+ *--str = 0; -+ while (str > num + neg) { -+ *--str = hexchars[val % base]; -+ val = val / base; -+ if (--prec <= 0 && val == 0) -+ break; -+ } -+ switch (neg) { -+ case 1: -+ *--str = '-'; -+ break; -+ case 2: -+ *--str = 'x'; -+ *--str = '0'; -+ break; -+ } -+ len = num + sizeof(num) - 1 - str; -+ } else { -+ len = strlen(str); -+ if (prec > 0 && len > prec) -+ len = prec; -+ } -+ if (width > 0) { -+ if (width > buflen) -+ width = buflen; -+ if ((n = width - len) > 0) { -+ buflen -= n; -+ for (; n > 0; --n) -+ *buf++ = fillch; -+ } -+ } -+ if (len > buflen) -+ len = buflen; -+ memcpy(buf, str, len); -+ buf += len; -+ buflen -= len; -+ } -+ *buf = 0; -+ return buf - buf0; -+} -+ -+void bios_printf(int flags, const char *fmt, ...) -+{ -+ va_list ap; -+ char buf[1024]; -+ const char *s; -+ -+ va_start(ap, fmt); -+ vsnprintf(buf, sizeof(buf), fmt, ap); -+ s = buf; -+ while (*s) -+ putc(*s++); -+ va_end(ap); -+} -+ -+/* approximative ! */ -+void delay_ms(int n) -+{ -+ int i, j; -+ for(i = 0; i < n; i++) { -+ for(j = 0; j < 1000000; j++); -+ } -+} -+ -+int smp_cpus; -+uint32_t cpuid_features; -+uint32_t cpuid_ext_features; -+unsigned long ram_size; -+#ifdef BX_USE_EBDA_TABLES -+unsigned long ebda_cur_addr; -+#endif -+int acpi_enabled; -+uint32_t pm_io_base; -+int pm_sci_int; -+unsigned long bios_table_cur_addr; -+unsigned long bios_table_end_addr; -+ -+void cpu_probe(void) -+{ -+ uint32_t eax, ebx, ecx, edx; -+ cpuid(1, eax, ebx, ecx, edx); -+ cpuid_features = edx; -+ cpuid_ext_features = ecx; -+} -+ -+static int cmos_readb(int addr) -+{ -+ outb(0x70, addr); -+ return inb(0x71); -+} -+ -+void ram_probe(void) -+{ -+ ram_size = (cmos_readb(0x34) | (cmos_readb(0x35) << 8)) * 65536 + -+ 16 * 1024 * 1024; -+#ifdef BX_USE_EBDA_TABLES -+ ebda_cur_addr = ((*(uint16_t *)(0x40e)) << 4) + 0x380; -+#endif -+ BX_INFO("ram_size=0x%08lx\n"); -+} -+ -+/****************************************************/ -+/* SMP probe */ -+ -+extern uint8_t smp_ap_boot_code_start; -+extern uint8_t smp_ap_boot_code_end; -+ -+/* find the number of CPUs by launching a SIPI to them */ -+void smp_probe(void) -+{ -+ uint32_t val, sipi_vector; -+ -+ smp_cpus = 1; -+ if (cpuid_features & CPUID_APIC) { -+ -+ /* enable local APIC */ -+ val = readl(APIC_BASE + APIC_SVR); -+ val |= APIC_ENABLED; -+ writel(APIC_BASE + APIC_SVR, val); -+ -+ writew((void *)CPU_COUNT_ADDR, 1); -+ /* copy AP boot code */ -+ memcpy((void *)AP_BOOT_ADDR, &smp_ap_boot_code_start, -+ &smp_ap_boot_code_end - &smp_ap_boot_code_start); -+ -+ /* broadcast SIPI */ -+ writel(APIC_BASE + APIC_ICR_LOW, 0x000C4500); -+ sipi_vector = AP_BOOT_ADDR >> 12; -+ writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector); -+ -+ delay_ms(10); -+ -+ smp_cpus = readw((void *)CPU_COUNT_ADDR); -+ } -+ BX_INFO("Found %d cpus\n", smp_cpus); -+} -+ -+/****************************************************/ -+/* PCI init */ -+ -+#define PCI_ADDRESS_SPACE_MEM 0x00 -+#define PCI_ADDRESS_SPACE_IO 0x01 -+#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08 -+ -+#define PCI_ROM_SLOT 6 -+#define PCI_NUM_REGIONS 7 -+ -+#define PCI_DEVICES_MAX 64 -+ -+#define PCI_VENDOR_ID 0x00 /* 16 bits */ -+#define PCI_DEVICE_ID 0x02 /* 16 bits */ -+#define PCI_COMMAND 0x04 /* 16 bits */ -+#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -+#define PCI_CLASS_DEVICE 0x0a /* Device class */ -+#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -+#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -+#define PCI_MIN_GNT 0x3e /* 8 bits */ -+#define PCI_MAX_LAT 0x3f /* 8 bits */ -+ -+typedef struct PCIDevice { -+ int bus; -+ int devfn; -+} PCIDevice; -+ -+static uint32_t pci_bios_io_addr; -+static uint32_t pci_bios_mem_addr; -+/* host irqs corresponding to PCI irqs A-D */ -+static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; -+static PCIDevice i440_pcidev; -+ -+static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) -+{ -+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); -+ outl(0xcfc, val); -+} -+ -+static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) -+{ -+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); -+ outw(0xcfc + (addr & 2), val); -+} -+ -+static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) -+{ -+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); -+ outb(0xcfc + (addr & 3), val); -+} -+ -+static uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) -+{ -+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); -+ return inl(0xcfc); -+} -+ -+static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) -+{ -+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); -+ return inw(0xcfc + (addr & 2)); -+} -+ -+static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) -+{ -+ outl(0xcf8, 0x80000000 | (d->bus << 16) | (d->devfn << 8) | (addr & 0xfc)); -+ return inb(0xcfc + (addr & 3)); -+} -+ -+static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) -+{ -+ uint16_t cmd; -+ uint32_t ofs, old_addr; -+ -+ if ( region_num == PCI_ROM_SLOT ) { -+ ofs = 0x30; -+ }else{ -+ ofs = 0x10 + region_num * 4; -+ } -+ -+ old_addr = pci_config_readl(d, ofs); -+ -+ pci_config_writel(d, ofs, addr); -+ BX_INFO("region %d: 0x%08x\n", region_num, addr); -+ -+ /* enable memory mappings */ -+ cmd = pci_config_readw(d, PCI_COMMAND); -+ if ( region_num == PCI_ROM_SLOT ) -+ cmd |= 2; -+ else if (old_addr & PCI_ADDRESS_SPACE_IO) -+ cmd |= 1; -+ else -+ cmd |= 2; -+ pci_config_writew(d, PCI_COMMAND, cmd); -+} -+ -+/* return the global irq number corresponding to a given device irq -+ pin. We could also use the bus number to have a more precise -+ mapping. */ -+static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) -+{ -+ int slot_addend; -+ slot_addend = (pci_dev->devfn >> 3) - 1; -+ return (irq_num + slot_addend) & 3; -+} -+ -+static int find_bios_table_area(void) -+{ -+ unsigned long addr; -+ for(addr = 0xf0000; addr < 0x100000; addr += 16) { -+ if (*(uint32_t *)addr == 0xaafb4442) { -+ bios_table_cur_addr = addr + 8; -+ bios_table_end_addr = bios_table_cur_addr + *(uint32_t *)(addr + 4); -+ BX_INFO("bios_table_addr: 0x%08lx end=0x%08lx\n", -+ bios_table_cur_addr, bios_table_end_addr); -+ return 0; -+ } -+ } -+ return -1; -+} -+ -+static void bios_shadow_init(PCIDevice *d) -+{ -+ int v; -+ -+ if (find_bios_table_area() < 0) -+ return; -+ -+ /* remap the BIOS to shadow RAM an keep it read/write while we -+ are writing tables */ -+ memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000); -+ v = pci_config_readb(d, 0x59); -+ v = (v & 0x0f) | (0x30); -+ pci_config_writeb(d, 0x59, v); -+ memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000); -+ -+ i440_pcidev = *d; -+} -+ -+static void bios_lock_shadow_ram(void) -+{ -+ PCIDevice *d = &i440_pcidev; -+ int v; -+ -+ v = pci_config_readb(d, 0x59); -+ v = (v & 0x0f) | (0x10); -+ pci_config_writeb(d, 0x59, v); -+} ++#include "rombios.h" + -+static void pci_bios_init_bridges(PCIDevice *d) -+{ -+ uint16_t vendor_id, device_id; -+ -+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); -+ device_id = pci_config_readw(d, PCI_DEVICE_ID); -+ -+ if (vendor_id == 0x8086 && device_id == 0x7000) { -+ int i, irq; -+ uint8_t elcr[2]; -+ -+ /* PIIX3 bridge */ -+ -+ elcr[0] = 0x00; -+ elcr[1] = 0x00; -+ for(i = 0; i < 4; i++) { -+ irq = pci_irqs[i]; -+ /* set to trigger level */ -+ elcr[irq >> 3] |= (1 << (irq & 7)); -+ /* activate irq remapping in PIIX */ -+ pci_config_writeb(d, 0x60 + i, irq); -+ } -+ outb(0x4d0, elcr[0]); -+ outb(0x4d1, elcr[1]); -+ BX_INFO("PIIX3 init: elcr=%02x %02x\n", -+ elcr[0], elcr[1]); -+ } else if (vendor_id == 0x8086 && device_id == 0x1237) { -+ /* i440 PCI bridge */ -+ bios_shadow_init(d); -+ } -+} -+ -+extern uint8_t smm_relocation_start, smm_relocation_end; -+extern uint8_t smm_code_start, smm_code_end; -+ -+#ifdef BX_USE_SMM -+static void smm_init(void) -+{ -+ /* copy the SMM relocation code */ -+ memcpy((void *)0x38000, &smm_relocation_start, -+ &smm_relocation_end - &smm_relocation_start); -+ /* raise an SMI interrupt */ -+ outb(0xb2, 00); -+ -+ /* enable the SMM memory window */ -+ pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x40); -+ -+ /* copy the SMM code */ -+ memcpy((void *)0xa8000, &smm_code_start, -+ &smm_code_end - &smm_code_start); -+ -+ /* close the SMM memory window and enable normal SMM */ -+ pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08); -+} -+#endif -+ -+static void pci_bios_init_device(PCIDevice *d) -+{ -+ int class; -+ uint32_t *paddr; -+ int i, pin, pic_irq, vendor_id, device_id; -+ -+ class = pci_config_readw(d, PCI_CLASS_DEVICE); -+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); -+ device_id = pci_config_readw(d, PCI_DEVICE_ID); -+ BX_INFO("PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n", -+ d->bus, d->devfn, vendor_id, device_id); -+ switch(class) { -+ case 0x0101: -+ if (vendor_id == 0x8086 && device_id == 0x7010) { -+ /* PIIX3 IDE */ -+ pci_config_writew(d, 0x40, 0x8000); // enable IDE0 -+ pci_config_writew(d, 0x42, 0x8000); // enable IDE1 -+ goto default_map; -+ } else { -+ /* IDE: we map it as in ISA mode */ -+ pci_set_io_region_addr(d, 0, 0x1f0); -+ pci_set_io_region_addr(d, 1, 0x3f4); -+ pci_set_io_region_addr(d, 2, 0x170); -+ pci_set_io_region_addr(d, 3, 0x374); -+ } -+ break; -+ case 0x0300: -+ if (vendor_id != 0x1234) -+ goto default_map; -+ /* VGA: map frame buffer to default Bochs VBE address */ -+ pci_set_io_region_addr(d, 0, 0xE0000000); -+ break; -+ case 0x0800: -+ /* PIC */ -+ if (vendor_id == 0x1014) { -+ /* IBM */ -+ if (device_id == 0x0046 || device_id == 0xFFFF) { -+ /* MPIC & MPIC2 */ -+ pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); -+ } -+ } -+ break; -+ case 0xff00: -+ if (vendor_id == 0x0106b && -+ (device_id == 0x0017 || device_id == 0x0022)) { -+ /* macio bridge */ -+ pci_set_io_region_addr(d, 0, 0x80800000); -+ } -+ break; -+ default: -+ default_map: -+ /* default memory mappings */ -+ for(i = 0; i < PCI_NUM_REGIONS; i++) { -+ int ofs; -+ uint32_t val, size ; -+ -+ if (i == PCI_ROM_SLOT) -+ ofs = 0x30; -+ else -+ ofs = 0x10 + i * 4; -+ pci_config_writel(d, ofs, 0xffffffff); -+ val = pci_config_readl(d, ofs); -+ if (val != 0) { -+ size = (~(val & ~0xf)) + 1; -+ if (val & PCI_ADDRESS_SPACE_IO) -+ paddr = &pci_bios_io_addr; -+ else -+ paddr = &pci_bios_mem_addr; -+ *paddr = (*paddr + size - 1) & ~(size - 1); -+ pci_set_io_region_addr(d, i, *paddr); -+ *paddr += size; -+ } -+ } -+ break; -+ } -+ -+ /* map the interrupt */ -+ pin = pci_config_readb(d, PCI_INTERRUPT_PIN); -+ if (pin != 0) { -+ pin = pci_slot_get_pirq(d, pin - 1); -+ pic_irq = pci_irqs[pin]; -+ pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); -+ } -+ -+ if (vendor_id == 0x8086 && device_id == 0x7113) { -+ /* PIIX4 Power Management device (for ACPI) */ -+ pm_io_base = PM_IO_BASE; -+ pci_config_writel(d, 0x40, pm_io_base | 1); -+ pci_config_writeb(d, 0x80, 0x01); /* enable PM io space */ -+ pm_sci_int = pci_config_readb(d, PCI_INTERRUPT_LINE); -+#ifdef BX_USE_SMM -+ smm_init(); -+#endif -+ acpi_enabled = 1; -+ } -+} -+ -+void pci_for_each_device(void (*init_func)(PCIDevice *d)) -+{ -+ PCIDevice d1, *d = &d1; -+ int bus, devfn; -+ uint16_t vendor_id, device_id; -+ -+ for(bus = 0; bus < 1; bus++) { -+ for(devfn = 0; devfn < 256; devfn++) { -+ d->bus = bus; -+ d->devfn = devfn; -+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); -+ device_id = pci_config_readw(d, PCI_DEVICE_ID); -+ if (vendor_id != 0xffff || device_id != 0xffff) { -+ init_func(d); -+ } -+ } -+ } -+} -+ -+void pci_bios_init(void) -+{ -+ pci_bios_io_addr = 0xc000; -+ pci_bios_mem_addr = 0xf0000000; -+ -+ pci_for_each_device(pci_bios_init_bridges); -+ -+ pci_for_each_device(pci_bios_init_device); -+} -+ -+/****************************************************/ -+/* Multi Processor table init */ -+ -+static void putb(uint8_t **pp, int val) -+{ -+ uint8_t *q; -+ q = *pp; -+ *q++ = val; -+ *pp = q; -+} -+ -+static void putstr(uint8_t **pp, const char *str) -+{ -+ uint8_t *q; -+ q = *pp; -+ while (*str) -+ *q++ = *str++; -+ *pp = q; -+} -+ -+static void putle16(uint8_t **pp, int val) -+{ -+ uint8_t *q; -+ q = *pp; -+ *q++ = val; -+ *q++ = val >> 8; -+ *pp = q; -+} -+ -+static void putle32(uint8_t **pp, int val) -+{ -+ uint8_t *q; -+ q = *pp; -+ *q++ = val; -+ *q++ = val >> 8; -+ *q++ = val >> 16; -+ *q++ = val >> 24; -+ *pp = q; -+} -+ -+static int mpf_checksum(const uint8_t *data, int len) -+{ -+ int sum, i; -+ sum = 0; -+ for(i = 0; i < len; i++) -+ sum += data[i]; -+ return sum & 0xff; -+} -+ -+static unsigned long align(unsigned long addr, unsigned long v) -+{ -+ return (addr + v - 1) & ~(v - 1); -+} -+ -+static void mptable_init(void) -+{ -+ uint8_t *mp_config_table, *q, *float_pointer_struct; -+ int ioapic_id, i, len; -+ int mp_config_table_size; -+ -+ if (smp_cpus <= 1) -+ return; -+ -+#ifdef BX_USE_EBDA_TABLES -+ mp_config_table = (uint8_t *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE); -+#else -+ bios_table_cur_addr = align(bios_table_cur_addr, 16); -+ mp_config_table = (uint8_t *)bios_table_cur_addr; -+#endif -+ q = mp_config_table; -+ putstr(&q, "PCMP"); /* "PCMP signature */ -+ putle16(&q, 0); /* table length (patched later) */ -+ putb(&q, 4); /* spec rev */ -+ putb(&q, 0); /* checksum (patched later) */ -+ putstr(&q, "QEMUCPU "); /* OEM id */ -+ putstr(&q, "0.1 "); /* vendor id */ -+ putle32(&q, 0); /* OEM table ptr */ -+ putle16(&q, 0); /* OEM table size */ -+ putle16(&q, 20); /* entry count */ -+ putle32(&q, 0xfee00000); /* local APIC addr */ -+ putle16(&q, 0); /* ext table length */ -+ putb(&q, 0); /* ext table checksum */ -+ putb(&q, 0); /* reserved */ -+ -+ for(i = 0; i < smp_cpus; i++) { -+ putb(&q, 0); /* entry type = processor */ -+ putb(&q, i); /* APIC id */ -+ putb(&q, 0x11); /* local APIC version number */ -+ if (i == 0) -+ putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */ -+ else -+ putb(&q, 1); /* cpu flags: enabled */ -+ putb(&q, 0); /* cpu signature */ -+ putb(&q, 6); -+ putb(&q, 0); -+ putb(&q, 0); -+ putle16(&q, 0x201); /* feature flags */ -+ putle16(&q, 0); -+ -+ putle16(&q, 0); /* reserved */ -+ putle16(&q, 0); -+ putle16(&q, 0); -+ putle16(&q, 0); -+ } -+ -+ /* isa bus */ -+ putb(&q, 1); /* entry type = bus */ -+ putb(&q, 0); /* bus ID */ -+ putstr(&q, "ISA "); -+ -+ /* ioapic */ -+ ioapic_id = smp_cpus; -+ putb(&q, 2); /* entry type = I/O APIC */ -+ putb(&q, ioapic_id); /* apic ID */ -+ putb(&q, 0x11); /* I/O APIC version number */ -+ putb(&q, 1); /* enable */ -+ putle32(&q, 0xfec00000); /* I/O APIC addr */ -+ -+ /* irqs */ -+ for(i = 0; i < 16; i++) { -+ putb(&q, 3); /* entry type = I/O interrupt */ -+ putb(&q, 0); /* interrupt type = vectored interrupt */ -+ putb(&q, 0); /* flags: po=0, el=0 */ -+ putb(&q, 0); -+ putb(&q, 0); /* source bus ID = ISA */ -+ putb(&q, i); /* source bus IRQ */ -+ putb(&q, ioapic_id); /* dest I/O APIC ID */ -+ putb(&q, i); /* dest I/O APIC interrupt in */ -+ } -+ /* patch length */ -+ len = q - mp_config_table; -+ mp_config_table[4] = len; -+ mp_config_table[5] = len >> 8; -+ -+ mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table); -+ -+ mp_config_table_size = q - mp_config_table; -+ -+#ifndef BX_USE_EBDA_TABLES -+ bios_table_cur_addr += mp_config_table_size; -+#endif -+ -+ /* floating pointer structure */ -+#ifdef BX_USE_EBDA_TABLES -+ ebda_cur_addr = align(ebda_cur_addr, 16); -+ float_pointer_struct = (uint8_t *)ebda_cur_addr; -+#else -+ bios_table_cur_addr = align(bios_table_cur_addr, 16); -+ float_pointer_struct = (uint8_t *)bios_table_cur_addr; -+#endif -+ q = float_pointer_struct; -+ putstr(&q, "_MP_"); -+ /* pointer to MP config table */ -+ putle32(&q, (unsigned long)mp_config_table); -+ -+ putb(&q, 1); /* length in 16 byte units */ -+ putb(&q, 4); /* MP spec revision */ -+ putb(&q, 0); /* checksum (patched later) */ -+ putb(&q, 0); /* MP feature byte 1 */ -+ -+ putb(&q, 0); -+ putb(&q, 0); -+ putb(&q, 0); -+ putb(&q, 0); -+ float_pointer_struct[10] = -+ -mpf_checksum(float_pointer_struct, q - float_pointer_struct); -+#ifdef BX_USE_EBDA_TABLES -+ ebda_cur_addr += (q - float_pointer_struct); -+#else -+ bios_table_cur_addr += (q - float_pointer_struct); -+#endif -+ BX_INFO("MP table addr=0x%08lx MPC table addr=0x%08lx size=0x%x\n", -+ (unsigned long)float_pointer_struct, -+ (unsigned long)mp_config_table, -+ mp_config_table_size); -+} -+ -+/****************************************************/ -+/* ACPI tables init */ -+ -+/* Table structure from Linux kernel (the ACPI tables are under the -+ BSD license) */ -+ -+#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ -+ uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\ -+ uint32_t length; /* Length of table, in bytes, including header */\ -+ uint8_t revision; /* ACPI Specification minor version # */\ -+ uint8_t checksum; /* To make sum of entire table == 0 */\ -+ uint8_t oem_id [6]; /* OEM identification */\ -+ uint8_t oem_table_id [8]; /* OEM table identification */\ -+ uint32_t oem_revision; /* OEM revision number */\ -+ uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\ -+ uint32_t asl_compiler_revision; /* ASL compiler revision number */ -+ -+ -+struct acpi_table_header /* ACPI common table header */ -+{ -+ ACPI_TABLE_HEADER_DEF -+}; -+ -+struct rsdp_descriptor /* Root System Descriptor Pointer */ -+{ -+ uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */ -+ uint8_t checksum; /* To make sum of struct == 0 */ -+ uint8_t oem_id [6]; /* OEM identification */ -+ uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ -+ uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */ -+ uint32_t length; /* XSDT Length in bytes including hdr */ -+ uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */ -+ uint8_t extended_checksum; /* Checksum of entire table */ -+ uint8_t reserved [3]; /* Reserved field must be 0 */ -+}; -+ -+/* -+ * ACPI 1.0 Root System Description Table (RSDT) -+ */ -+struct rsdt_descriptor_rev1 -+{ -+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */ -+ uint32_t table_offset_entry [2]; /* Array of pointers to other */ -+ /* ACPI tables */ -+}; -+ -+/* -+ * ACPI 1.0 Firmware ACPI Control Structure (FACS) -+ */ -+struct facs_descriptor_rev1 -+{ -+ uint8_t signature[4]; /* ACPI Signature */ -+ uint32_t length; /* Length of structure, in bytes */ -+ uint32_t hardware_signature; /* Hardware configuration signature */ -+ uint32_t firmware_waking_vector; /* ACPI OS waking vector */ -+ uint32_t global_lock; /* Global Lock */ -+ uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */ -+ uint32_t reserved1 : 31; /* Must be 0 */ -+ uint8_t resverved3 [40]; /* Reserved - must be zero */ -+}; -+ -+ -+/* -+ * ACPI 1.0 Fixed ACPI Description Table (FADT) -+ */ -+struct fadt_descriptor_rev1 -+{ -+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */ -+ uint32_t firmware_ctrl; /* Physical address of FACS */ -+ uint32_t dsdt; /* Physical address of DSDT */ -+ uint8_t model; /* System Interrupt Model */ -+ uint8_t reserved1; /* Reserved */ -+ uint16_t sci_int; /* System vector of SCI interrupt */ -+ uint32_t smi_cmd; /* Port address of SMI command port */ -+ uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */ -+ uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */ -+ uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ -+ uint8_t reserved2; /* Reserved - must be zero */ -+ uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ -+ uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ -+ uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ -+ uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ -+ uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ -+ uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ -+ uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ -+ uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ -+ uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ -+ uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ -+ uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ -+ uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ -+ uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ -+ uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ -+ uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */ -+ uint8_t reserved3; /* Reserved */ -+ uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ -+ uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ -+ uint16_t flush_size; /* Size of area read to flush caches */ -+ uint16_t flush_stride; /* Stride used in flushing caches */ -+ uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */ -+ uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */ -+ uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ -+ uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ -+ uint8_t century; /* Index to century in RTC CMOS RAM */ -+ uint8_t reserved4; /* Reserved */ -+ uint8_t reserved4a; /* Reserved */ -+ uint8_t reserved4b; /* Reserved */ -+#if 0 -+ uint32_t wb_invd : 1; /* The wbinvd instruction works properly */ -+ uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ -+ uint32_t proc_c1 : 1; /* All processors support C1 state */ -+ uint32_t plvl2_up : 1; /* C2 state works on MP system */ -+ uint32_t pwr_button : 1; /* Power button is handled as a generic feature */ -+ uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ -+ uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ -+ uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ -+ uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */ -+ uint32_t reserved5 : 23; /* Reserved - must be zero */ -+#else -+ uint32_t flags; -+#endif -+}; -+ -+/* -+ * MADT values and structures -+ */ -+ -+/* Values for MADT PCATCompat */ -+ -+#define DUAL_PIC 0 -+#define MULTIPLE_APIC 1 -+ -+ -+/* Master MADT */ -+ -+struct multiple_apic_table -+{ -+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */ -+ uint32_t local_apic_address; /* Physical address of local APIC */ -+#if 0 -+ uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */ -+ uint32_t reserved1 : 31; -+#else -+ uint32_t flags; -+#endif -+}; -+ -+ -+/* Values for Type in APIC_HEADER_DEF */ -+ -+#define APIC_PROCESSOR 0 -+#define APIC_IO 1 -+#define APIC_XRUPT_OVERRIDE 2 -+#define APIC_NMI 3 -+#define APIC_LOCAL_NMI 4 -+#define APIC_ADDRESS_OVERRIDE 5 -+#define APIC_IO_SAPIC 6 -+#define APIC_LOCAL_SAPIC 7 -+#define APIC_XRUPT_SOURCE 8 -+#define APIC_RESERVED 9 /* 9 and greater are reserved */ -+ -+/* -+ * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) -+ */ -+#define APIC_HEADER_DEF /* Common APIC sub-structure header */\ -+ uint8_t type; \ -+ uint8_t length; -+ -+/* Sub-structures for MADT */ -+ -+struct madt_processor_apic -+{ -+ APIC_HEADER_DEF -+ uint8_t processor_id; /* ACPI processor id */ -+ uint8_t local_apic_id; /* Processor's local APIC id */ -+#if 0 -+ uint32_t processor_enabled: 1; /* Processor is usable if set */ -+ uint32_t reserved2 : 31; /* Reserved, must be zero */ -+#else -+ uint32_t flags; -+#endif -+}; -+ -+struct madt_io_apic -+{ -+ APIC_HEADER_DEF -+ uint8_t io_apic_id; /* I/O APIC ID */ -+ uint8_t reserved; /* Reserved - must be zero */ -+ uint32_t address; /* APIC physical address */ -+ uint32_t interrupt; /* Global system interrupt where INTI -+ * lines start */ -+}; -+ -+#include "acpi-dsdt.hex" -+ -+static inline uint16_t cpu_to_le16(uint16_t x) -+{ -+ return x; -+} -+ -+static inline uint32_t cpu_to_le32(uint32_t x) -+{ -+ return x; -+} -+ -+static int acpi_checksum(const uint8_t *data, int len) -+{ -+ int sum, i; -+ sum = 0; -+ for(i = 0; i < len; i++) -+ sum += data[i]; -+ return (-sum) & 0xff; -+} -+ -+static void acpi_build_table_header(struct acpi_table_header *h, -+ char *sig, int len) -+{ -+ memcpy(h->signature, sig, 4); -+ h->length = cpu_to_le32(len); -+ h->revision = 0; -+ memcpy(h->oem_id, "QEMU ", 6); -+ memcpy(h->oem_table_id, "QEMU", 4); -+ memcpy(h->oem_table_id + 4, sig, 4); -+ h->oem_revision = cpu_to_le32(1); -+ memcpy(h->asl_compiler_id, "QEMU", 4); -+ h->asl_compiler_revision = cpu_to_le32(1); -+ h->checksum = acpi_checksum((void *)h, len); -+} -+ -+/* base_addr must be a multiple of 4KB */ -+void acpi_bios_init(void) -+{ -+ struct rsdp_descriptor *rsdp; -+ struct rsdt_descriptor_rev1 *rsdt; -+ struct fadt_descriptor_rev1 *fadt; -+ struct facs_descriptor_rev1 *facs; -+ struct multiple_apic_table *madt; -+ uint8_t *dsdt; -+ uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr; -+ uint32_t acpi_tables_size, madt_addr, madt_size; -+ int i; -+ -+ /* reserve memory space for tables */ -+#ifdef BX_USE_EBDA_TABLES -+ ebda_cur_addr = align(ebda_cur_addr, 16); -+ rsdp = (void *)(ebda_cur_addr); -+ ebda_cur_addr += sizeof(*rsdp); -+#else -+ bios_table_cur_addr = align(bios_table_cur_addr, 16); -+ rsdp = (void *)(bios_table_cur_addr); -+ bios_table_cur_addr += sizeof(*rsdp); -+#endif -+ -+ addr = base_addr = ram_size - ACPI_DATA_SIZE; -+ rsdt_addr = addr; -+ rsdt = (void *)(addr); -+ addr += sizeof(*rsdt); -+ -+ fadt_addr = addr; -+ fadt = (void *)(addr); -+ addr += sizeof(*fadt); -+ -+ /* XXX: FACS should be in RAM */ -+ addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */ -+ facs_addr = addr; -+ facs = (void *)(addr); -+ addr += sizeof(*facs); -+ -+ dsdt_addr = addr; -+ dsdt = (void *)(addr); -+ addr += sizeof(AmlCode); -+ -+ addr = (addr + 7) & ~7; -+ madt_addr = addr; -+ madt_size = sizeof(*madt) + -+ sizeof(struct madt_processor_apic) * smp_cpus + -+ sizeof(struct madt_io_apic); -+ madt = (void *)(addr); -+ addr += madt_size; -+ -+ acpi_tables_size = addr - base_addr; -+ -+ BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n", -+ (unsigned long)rsdp, -+ (unsigned long)rsdt, acpi_tables_size); -+ -+ /* RSDP */ -+ memset(rsdp, 0, sizeof(*rsdp)); -+ memcpy(rsdp->signature, "RSD PTR ", 8); -+ memcpy(rsdp->oem_id, "QEMU ", 6); -+ rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr); -+ rsdp->checksum = acpi_checksum((void *)rsdp, 20); -+ -+ /* RSDT */ -+ rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr); -+ rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr); -+ acpi_build_table_header((struct acpi_table_header *)rsdt, -+ "RSDT", sizeof(*rsdt)); -+ -+ /* FADT */ -+ memset(fadt, 0, sizeof(*fadt)); -+ fadt->firmware_ctrl = cpu_to_le32(facs_addr); -+ fadt->dsdt = cpu_to_le32(dsdt_addr); -+ fadt->model = 1; -+ fadt->reserved1 = 0; -+ fadt->sci_int = cpu_to_le16(pm_sci_int); -+ fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR); -+ fadt->acpi_enable = 0xf1; -+ fadt->acpi_disable = 0xf0; -+ fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base); -+ fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04); -+ fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08); -+ fadt->pm1_evt_len = 4; -+ fadt->pm1_cnt_len = 2; -+ fadt->pm_tmr_len = 4; -+ fadt->plvl2_lat = cpu_to_le16(50); -+ fadt->plvl3_lat = cpu_to_le16(50); -+ fadt->plvl3_lat = cpu_to_le16(50); -+ /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */ -+ fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6)); -+ acpi_build_table_header((struct acpi_table_header *)fadt, "FACP", -+ sizeof(*fadt)); -+ -+ /* FACS */ -+ memset(facs, 0, sizeof(*facs)); -+ memcpy(facs->signature, "FACS", 4); -+ facs->length = cpu_to_le32(sizeof(*facs)); -+ -+ /* DSDT */ -+ memcpy(dsdt, AmlCode, sizeof(AmlCode)); -+ -+ /* MADT */ -+ { -+ struct madt_processor_apic *apic; -+ struct madt_io_apic *io_apic; -+ -+ memset(madt, 0, madt_size); -+ madt->local_apic_address = cpu_to_le32(0xfee00000); -+ madt->flags = cpu_to_le32(1); -+ apic = (void *)(madt + 1); -+ for(i=0;itype = APIC_PROCESSOR; -+ apic->length = sizeof(*apic); -+ apic->processor_id = i; -+ apic->local_apic_id = i; -+ apic->flags = cpu_to_le32(1); -+ apic++; -+ } -+ io_apic = (void *)apic; -+ io_apic->type = APIC_IO; -+ io_apic->length = sizeof(*io_apic); -+ io_apic->io_apic_id = smp_cpus; -+ io_apic->address = cpu_to_le32(0xfec00000); -+ io_apic->interrupt = cpu_to_le32(0); -+ -+ acpi_build_table_header((struct acpi_table_header *)madt, -+ "APIC", madt_size); -+ } -+} -+ -+void rombios32_init(void) -+{ -+ BX_INFO("Starting rombios32\n"); -+ -+ ram_probe(); -+ -+ cpu_probe(); -+ -+ smp_probe(); -+ -+ pci_bios_init(); -+ -+ if (bios_table_cur_addr != 0) { -+ -+ mptable_init(); -+ -+ if (acpi_enabled) -+ acpi_bios_init(); -+ -+ bios_lock_shadow_ram(); -+ } -+} -diff -ruN --exclude Makefile bios.org/rombios32.ld bios/rombios32.ld ---- bios.org/rombios32.ld 1970-01-01 01:00:00.000000000 +0100 -+++ bios/rombios32.ld 2006-09-24 20:28:05.000000000 +0200 -@@ -0,0 +1,19 @@ -+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -+OUTPUT_ARCH(i386) -+ENTRY(_start); -+SECTIONS -+{ -+ . = 0x00040000; -+ .text : { *(.text) } -+ .rodata : { *(.rodata) } -+ . = ALIGN(4096); -+ .data : { *(.data) } -+ __bss_start = . ; -+ .bss : { *(.bss) *(COMMON) } -+ _end = . ; -+ /DISCARD/ : { *(.stab) -+ *(.stabstr) -+ *(.comment) -+ *(.note) -+ } -+} -diff -ruN --exclude Makefile bios.org/rombios32start.S bios/rombios32start.S ---- bios.org/rombios32start.S 1970-01-01 01:00:00.000000000 +0100 -+++ bios/rombios32start.S 2006-09-24 20:22:58.000000000 +0200 -@@ -0,0 +1,76 @@ -+.globl _start -+.globl smp_ap_boot_code_start -+.globl smp_ap_boot_code_end -+.global smm_relocation_start -+.global smm_relocation_end -+.global smm_code_start -+.global smm_code_end -+ -+#define PM_IO_BASE 0xb000 -+ -+_start: -+ /* clear bss section */ -+ xor %eax, %eax -+ mov $__bss_start, %edi -+ mov $_end, %ecx -+ sub %edi, %ecx -+ rep stosb -+ -+ jmp rombios32_init -+ -+#define CPU_COUNT 0xf000 -+ -+ .code16 -+smp_ap_boot_code_start: -+ xor %ax, %ax -+ mov %ax, %ds -+ incw CPU_COUNT -+1: -+ hlt -+ jmp 1b -+smp_ap_boot_code_end: -+ -+/* code to relocate SMBASE to 0xa0000 */ -+smm_relocation_start: -+ mov $0x38000 + 0x7efc, %ebx -+ mov (%ebx), %al /* revision ID to see if x86_64 or x86 */ -+ cmp $0x64, %al -+ je 1f -+ mov $0x38000 + 0x7ef8, %ebx -+ jmp 2f -+1: -+ mov $0x38000 + 0x7f00, %ebx -+2: -+ movl $0xa0000, %eax -+ movl %eax, (%ebx) -+ rsm -+smm_relocation_end: -+ -+/* minimal SMM code to enable or disable ACPI */ -+smm_code_start: -+ movw $0xb2, %dx -+ inb %dx, %al -+ cmp $0xf0, %al -+ jne 1f -+ -+ /* ACPI disable */ -+ mov $PM_IO_BASE + 0x04, %dx /* PMCNTRL */ -+ inw %dx, %ax -+ andw $~1, %ax -+ outw %ax, %dx -+ -+ jmp 2f -+ -+1: -+ cmp $0xf1, %al -+ jne 2f -+ -+ /* ACPI enable */ -+ mov $PM_IO_BASE + 0x04, %dx /* PMCNTRL */ -+ inw %dx, %ax -+ orw $1, %ax -+ outw %ax, %dx -+ -+2: -+ rsm -+smm_code_end: -diff -ruN --exclude Makefile bios.org/rombios.c bios/rombios.c ---- bios.org/rombios.c 2006-08-11 19:34:12.000000000 +0200 -+++ bios/rombios.c 2006-09-24 20:35:47.000000000 +0200 -@@ -24,7 +24,7 @@ - // License along with this library; if not, write to the Free Software - // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - --// ROM BIOS for use with Bochs/Plex x86 emulation environment -+// ROM BIOS for use with Bochs/Plex x86/QEMU emulation environment - - - // ROM BIOS compatability entry points: -@@ -143,6 +143,7 @@ - #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */ - #define BX_PCIBIOS 1 - #define BX_APM 1 -+#define BX_ROMBIOS32 1 - - #define BX_USE_ATADRV 1 - #define BX_ELTORITO_BOOT 1 -@@ -159,6 +160,9 @@ - #define BIOS_REVISION 1 - #define BIOS_CONFIG_TABLE 0xe6f5 - -+/* define it to include QEMU specific code */ -+#define BX_QEMU -+ - #ifndef BIOS_BUILD_DATE - # define BIOS_BUILD_DATE "06/23/99" - #endif -@@ -170,7 +174,9 @@ - #define BASE_MEM_IN_K (640 - EBDA_SIZE) - - // Define the application NAME --#ifdef PLEX86 -+#if defined(BX_QEMU) -+# define BX_APPNAME "QEMU" -+#elif defined(PLEX86) - # define BX_APPNAME "Plex86" - #else - # define BX_APPNAME "Bochs" -@@ -1826,6 +1832,9 @@ - #ifdef BX_ELTORITO_BOOT - "eltorito " - #endif -+#ifdef BX_ROMBIOS32 -+ "rombios32 " -+#endif - "\n\n"); - } + .globl _start + .globl smp_ap_boot_code_start + .globl smp_ap_boot_code_end +@@ -6,8 +28,6 @@ + .global smm_code_start + .global smm_code_end -@@ -4085,6 +4094,24 @@ - case 0x20: // coded by osmaker aka K.J. - if(regs.u.r32.edx == 0x534D4150) - { -+ extended_memory_size = inb_cmos(0x35); -+ extended_memory_size <<= 8; -+ extended_memory_size |= inb_cmos(0x34); -+ extended_memory_size *= 64; -+ // greater than EFF00000??? -+ if(extended_memory_size > 0x3bc000) { -+ extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 -+ } -+ extended_memory_size *= 1024; -+ extended_memory_size += (16L * 1024 * 1024); -+ -+ if(extended_memory_size <= (16L * 1024 * 1024)) { -+ extended_memory_size = inb_cmos(0x31); -+ extended_memory_size <<= 8; -+ extended_memory_size |= inb_cmos(0x30); -+ extended_memory_size *= 1024; -+ } -+ - switch(regs.u.r16.bx) - { - case 0: -@@ -4115,27 +4142,9 @@ - return; - break; - case 3: -- extended_memory_size = inb_cmos(0x35); -- extended_memory_size <<= 8; -- extended_memory_size |= inb_cmos(0x34); -- extended_memory_size *= 64; -- if(extended_memory_size > 0x3bc000) // greater than EFF00000??? -- { -- extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 -- } -- extended_memory_size *= 1024; -- extended_memory_size += (16L * 1024 * 1024); +-#define PM_IO_BASE 0xb000 - -- if(extended_memory_size <= (16L * 1024 * 1024)) -- { -- extended_memory_size = inb_cmos(0x31); -- extended_memory_size <<= 8; -- extended_memory_size |= inb_cmos(0x30); -- extended_memory_size *= 1024; -- } -- - set_e820_range(ES, regs.u.r16.di, -- 0x00100000L, extended_memory_size, 1); -+ 0x00100000L, -+ extended_memory_size - 0x10000L, 1); - regs.u.r32.ebx = 4; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; -@@ -4143,6 +4152,16 @@ - return; - break; - case 4: -+ set_e820_range(ES, regs.u.r16.di, -+ extended_memory_size - 0x10000L, -+ extended_memory_size, 3); // ACPI RAM -+ regs.u.r32.ebx = 5; -+ regs.u.r32.eax = 0x534D4150; -+ regs.u.r32.ecx = 0x14; -+ CLEAR_CF(); -+ return; -+ break; -+ case 5: - /* 256KB BIOS area at the end of 4 GB */ - set_e820_range(ES, regs.u.r16.di, - 0xfffc0000L, 0x00000000L, 2); -@@ -8757,6 +8776,9 @@ - unknown_service: - mov al, #0x80 - bios32_end: -+#ifdef BX_QEMU -+ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu -+#endif - popf - retf - -@@ -8868,6 +8890,9 @@ - pci_pro_fail: - pop edi - pop esi -+#ifdef BX_QEMU -+ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu -+#endif - popf - stc - retf -@@ -8875,6 +8900,9 @@ - xor ah, ah - pop edi - pop esi -+#ifdef BX_QEMU -+ and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu -+#endif - popf - clc - retf -@@ -9183,227 +9211,118 @@ - db 0 ;; reserved - pci_routing_table_structure_end: + _start: + /* clear bss section */ + xor %eax, %eax +@@ -18,13 +38,11 @@ --pci_irq_list: -- db 11, 10, 9, 5; -+#endif // BX_PCIBIOS + jmp rombios32_init --pcibios_init_sel_reg: -- push eax -- mov eax, #0x800000 -- mov ax, bx -- shl eax, #8 -- and dl, #0xfc -- or al, dl -- mov dx, #0x0cf8 -- out dx, eax -- pop eax -- ret -- --pcibios_init_iomem_bases: -- push bp -- mov bp, sp -- mov eax, #0xe0000000 ;; base for memory init -- push eax -- mov ax, #0xc000 ;; base for i/o init -- push ax -- mov ax, #0x0010 ;; start at base address #0 -+#if BX_ROMBIOS32 -+rombios32_init: -+ ;; save a20 and enable it -+ in al, 0x92 - push ax -- mov bx, #0x0008 --pci_init_io_loop1: -- mov dl, #0x00 -- call pcibios_init_sel_reg -- mov dx, #0x0cfc -- in ax, dx -- cmp ax, #0xffff -- jz next_pci_dev -- mov dl, #0x04 ;; disable i/o and memory space access -- call pcibios_init_sel_reg -- mov dx, #0x0cfc -- in al, dx -- and al, #0xfc -- out dx, al --pci_init_io_loop2: -- mov dl, [bp-8] -- call pcibios_init_sel_reg -- mov dx, #0x0cfc -- in eax, dx -- test al, #0x01 -- jnz init_io_base -- mov ecx, eax -- mov eax, #0xffffffff -- out dx, eax -- in eax, dx -- cmp eax, ecx -- je next_pci_base -- xor eax, #0xffffffff -- mov ecx, eax -- mov eax, [bp-4] -- out dx, eax -- add eax, ecx ;; calculate next free mem base -- add eax, #0x01000000 -- and eax, #0xff000000 -- mov [bp-4], eax -- jmp next_pci_base --init_io_base: -- mov cx, ax -- mov ax, #0xffff -- out dx, ax -- in ax, dx -- cmp ax, cx -- je next_pci_base -- xor ax, #0xfffe -- mov cx, ax -- mov ax, [bp-6] -- out dx, ax -- add ax, cx ;; calculate next free i/o base -- add ax, #0x0100 -- and ax, #0xff00 -- mov [bp-6], ax --next_pci_base: -- mov al, [bp-8] -- add al, #0x04 -- cmp al, #0x28 -- je enable_iomem_space -- mov byte ptr[bp-8], al -- jmp pci_init_io_loop2 --enable_iomem_space: -- mov dl, #0x04 ;; enable i/o and memory space access if available -- call pcibios_init_sel_reg -- mov dx, #0x0cfc -- in al, dx -- or al, #0x07 -- out dx, al --next_pci_dev: -- mov byte ptr[bp-8], #0x10 -- inc bx -- cmp bx, #0x0100 -- jne pci_init_io_loop1 -- mov sp, bp -- pop bp -- ret -+ or al, #0x02 -+ out 0x92, al - --pcibios_init_set_elcr: -- push ax -- push cx -- mov dx, #0x04d0 -- test al, #0x08 -- jz is_master_pic -- inc dx -- and al, #0x07 --is_master_pic: -- mov cl, al -- mov bl, #0x01 -- shl bl, cl -- in al, dx -- or al, bl -- out dx, al -- pop cx -- pop ax -- ret -+ ;; save SS:SP to the BDA -+ xor ax, ax -+ mov ds, ax -+ mov 0x0469, ss -+ mov 0x0467, sp - --pcibios_init_irqs: -- push ds -- push bp -- mov ax, #0xf000 -- mov ds, ax -- mov dx, #0x04d0 ;; reset ELCR1 + ELCR2 -- mov al, #0x00 -- out dx, al -- inc dx -- out dx, al -- mov si, #pci_routing_table_structure -- mov bh, [si+8] -- mov bl, [si+9] -- mov dl, #0x00 -- call pcibios_init_sel_reg -- mov dx, #0x0cfc -- in eax, dx -- cmp eax, [si+12] ;; check irq router -- jne pci_init_end -- mov dl, [si+34] -- call pcibios_init_sel_reg -- push bx ;; save irq router bus + devfunc -- mov dx, #0x0cfc -- mov ax, #0x8080 -- out dx, ax ;; reset PIRQ route control -- inc dx -- inc dx -- out dx, ax -- mov ax, [si+6] -- sub ax, #0x20 -- shr ax, #4 -- mov cx, ax -- add si, #0x20 ;; set pointer to 1st entry -- mov bp, sp -- mov ax, #pci_irq_list -- push ax -- xor ax, ax -- push ax --pci_init_irq_loop1: -- mov bh, [si] -- mov bl, [si+1] --pci_init_irq_loop2: -- mov dl, #0x00 -- call pcibios_init_sel_reg -- mov dx, #0x0cfc -- in ax, dx -- cmp ax, #0xffff -- jnz pci_test_int_pin -- test bl, #0x07 -- jz next_pir_entry -- jmp next_pci_func --pci_test_int_pin: -- mov dl, #0x3c -- call pcibios_init_sel_reg -- mov dx, #0x0cfd -- in al, dx -- and al, #0x07 -- jz next_pci_func -- dec al ;; determine pirq reg -- mov dl, #0x03 -- mul al, dl -- add al, #0x02 -- xor ah, ah -- mov bx, ax -- mov al, [si+bx] -- mov dl, al -- mov bx, [bp] -- call pcibios_init_sel_reg -- mov dx, #0x0cfc -- and al, #0x03 -- add dl, al -- in al, dx -- cmp al, #0x80 -- jb pirq_found -- mov bx, [bp-2] ;; pci irq list pointer -- mov al, [bx] -- out dx, al -- inc bx -- mov [bp-2], bx -- call pcibios_init_set_elcr --pirq_found: -- mov bh, [si] -- mov bl, [si+1] -- add bl, [bp-3] ;; pci function number -- mov dl, #0x3c -- call pcibios_init_sel_reg -- mov dx, #0x0cfc -- out dx, al --next_pci_func: -- inc byte ptr[bp-3] -- inc bl -- test bl, #0x07 -- jnz pci_init_irq_loop2 --next_pir_entry: -- add si, #0x10 -- mov byte ptr[bp-3], #0x00 -- loop pci_init_irq_loop1 -- mov sp, bp -- pop bx --pci_init_end: -- pop bp -- pop ds -+ SEG CS -+ lidt [pmode_IDT_info] -+ SEG CS -+ lgdt [rombios32_gdt_48] -+ ;; set PE bit in CR0 -+ mov eax, cr0 -+ or al, #0x01 -+ mov cr0, eax -+ ;; start protected mode code: ljmpl 0x10:rombios32_init1 -+ db 0x66, 0xea -+ dw rombios32_05 -+ dw 0x000f ;; high 16 bit address -+ dw 0x0010 -+ -+use32 386 -+rombios32_05: -+ ;; init data segments -+ mov eax, #0x18 -+ mov ds, ax -+ mov es, ax -+ mov ss, ax -+ xor eax, eax -+ mov fs, ax -+ mov gs, ax -+ cld -+ -+ ;; copy rombios32 code to ram (ram offset = 1MB) -+ mov esi, #0xfffe0000 -+ mov edi, #0x00040000 -+ mov ecx, #0x10000 / 4 -+ rep -+ movsd -+ -+ ;; init the stack pointer -+ mov esp, #0x00080000 -+ -+ ;; call rombios32 code -+ mov eax, #0x00040000 -+ call eax -+ -+ ;; return to 16 bit protected mode first -+ db 0xea -+ dd rombios32_10 -+ dw 0x20 -+ -+use16 386 -+rombios32_10: -+ ;; restore data segment limits to 0xffff -+ mov ax, #0x28 -+ mov ds, ax -+ mov es, ax -+ mov ss, ax -+ mov fs, ax -+ mov gs, ax -+ -+ ;; reset PE bit in CR0 -+ mov eax, cr0 -+ and al, #0xFE -+ mov cr0, eax -+ -+ ;; far jump to flush CPU queue after transition to real mode -+ JMP_AP(0xf000, rombios32_real_mode) -+ -+rombios32_real_mode: -+ ;; restore IDT to normal real-mode defaults -+ SEG CS -+ lidt [rmode_IDT_info] -+ -+ xor ax, ax -+ mov ds, ax -+ mov es, ax -+ mov fs, ax -+ mov gs, ax -+ -+ ;; restore SS:SP from the BDA -+ mov ss, 0x0469 -+ mov sp, 0x0467 -+ ;; restore a20 -+ pop ax -+ out 0x92, al - ret --#endif // BX_PCIBIOS -+ -+rombios32_gdt_48: -+ dw 0x30 -+ dw rombios32_gdt -+ dw 0x000f -+ -+rombios32_gdt: -+ dw 0, 0, 0, 0 -+ dw 0, 0, 0, 0 -+ dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10) -+ dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18) -+ dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff -+ dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff -+#endif -+ - - ; parallel port detection: base address in DX, index in BX, timeout in CL - detect_parport: -@@ -9535,10 +9454,17 @@ - ;; DATA_SEG_DEFS_HERE - - -+;; the following area can be used to write dynamically generated tables -+ .align 16 -+bios_table_area_start: -+ dd 0xaafb4442 -+ dd bios_table_area_end - bios_table_area_start - 8; -+ - ;-------- - ;- POST - - ;-------- - .org 0xe05b ; POST Entry Point -+bios_table_area_end: - post: - - xor ax, ax -@@ -9802,9 +9728,9 @@ - #endif - out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14 - -- call pcibios_init_iomem_bases -- call pcibios_init_irqs +-#define CPU_COUNT 0xf000 - -+#if BX_ROMBIOS32 -+ call rombios32_init -+#endif - call rom_scan - - call _print_bios_banner + .code16 + smp_ap_boot_code_start: + xor %ax, %ax + mov %ax, %ds +- incw CPU_COUNT ++ incw CPU_COUNT_ADDR + 1: + hlt + jmp 1b +@@ -33,7 +51,7 @@ + /* code to relocate SMBASE to 0xa0000 */ + smm_relocation_start: + mov $0x38000 + 0x7efc, %ebx +- mov (%ebx), %al /* revision ID to see if x86_64 or x86 */ ++ addr32 mov (%ebx), %al /* revision ID to see if x86_64 or x86 */ + cmp $0x64, %al + je 1f + mov $0x38000 + 0x7ef8, %ebx +@@ -42,7 +60,7 @@ + mov $0x38000 + 0x7f00, %ebx + 2: + movl $0xa0000, %eax +- movl %eax, (%ebx) ++ addr32 movl %eax, (%ebx) + rsm + smm_relocation_end: + -- cgit v1.2.3 From 93eac243d523b473dd33f6fc84ffa15ed2f018d9 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 2 Oct 2006 17:58:33 +0000 Subject: 32 bit syscall fix (Juergen Keil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2189 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kqemu.c b/kqemu.c index b7a93b0be..5ba314f42 100644 --- a/kqemu.c +++ b/kqemu.c @@ -470,9 +470,13 @@ static int do_syscall(CPUState *env, selector = (env->star >> 32) & 0xffff; #ifdef __x86_64__ if (env->hflags & HF_LMA_MASK) { + int code64; + env->regs[R_ECX] = kenv->next_eip; env->regs[11] = env->eflags; + code64 = env->hflags & HF_CS64_MASK; + cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, @@ -485,7 +489,7 @@ static int do_syscall(CPUState *env, DESC_S_MASK | DESC_W_MASK | DESC_A_MASK); env->eflags &= ~env->fmask; - if (env->hflags & HF_CS64_MASK) + if (code64) env->eip = env->lstar; else env->eip = env->cstar; -- cgit v1.2.3 From 47d02f6d5c25a3858bc9d895d14ccfb5e8e6c1b8 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 2 Oct 2006 18:25:40 +0000 Subject: SMI enable bit support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2190 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 76a9ce587..ce16531fb 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -19,7 +19,6 @@ #include "vl.h" //#define DEBUG -#define USE_SMM /* i82731AB (PIIX4) compatible power management function */ #define PM_FREQ 3579545 @@ -200,19 +199,9 @@ static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val) #endif if (addr == 0) { s->apmc = val; -#ifdef USE_SMM - cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); -#else - /* emulation of what the SMM BIOS should do */ - switch(val) { - case 0xf0: /* ACPI disable */ - s->pmcntrl &= ~SCI_EN; - break; - case 0xf1: /* ACPI enable */ - s->pmcntrl |= SCI_EN; - break; + if (s->dev.config[0x5b] & (1 << 1)) { + cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); } -#endif } else { s->apms = val; } -- cgit v1.2.3 From e3e97e7c90f4a40a56ea05f3a34f267edf41c9ed Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 2 Oct 2006 18:35:39 +0000 Subject: do not generate MP table if one CPU (no APIC in QEMU in this case) - added wbinvd (ignored in QEMU but useful on real hardware) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2191 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/bios.diff | 241 +++++++++++------------------------------------------- 2 files changed, 46 insertions(+), 195 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 1af4a4f0e..0161bde0f 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 0bb1d345c..c355befc9 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,83 +1,10 @@ -Index: BIOS-bochs-latest -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/BIOS-bochs-latest,v -retrieving revision 1.133 -diff -u -w -r1.133 BIOS-bochs-latest -Binary files /tmp/cvsrjjP5I and BIOS-bochs-latest differ -Index: rombios.c -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v -retrieving revision 1.170 -diff -u -w -r1.170 rombios.c ---- rombios.c 30 Sep 2006 11:22:53 -0000 1.170 -+++ rombios.c 1 Oct 2006 16:03:53 -0000 -@@ -4115,7 +4115,7 @@ - case 3: - set_e820_range(ES, regs.u.r16.di, - 0x00100000L, -- extended_memory_size - 0x10000L, 1); -+ extended_memory_size - ACPI_DATA_SIZE, 1); - regs.u.r32.ebx = 4; - regs.u.r32.eax = 0x534D4150; - regs.u.r32.ecx = 0x14; -@@ -4124,7 +4124,7 @@ - break; - case 4: - set_e820_range(ES, regs.u.r16.di, -- extended_memory_size - 0x10000L, -+ extended_memory_size - ACPI_DATA_SIZE, - extended_memory_size, 3); // ACPI RAM - regs.u.r32.ebx = 5; - regs.u.r32.eax = 0x534D4150; -@@ -8723,7 +8723,7 @@ - - .align 16 - bios32_entry_point: -- pushf -+ pushfd - cmp eax, #0x49435024 ;; "$PCI" - jne unknown_service - mov eax, #0x80000000 -@@ -8750,12 +8750,12 @@ - #ifdef BX_QEMU - and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu - #endif -- popf -+ popfd - retf - - .align 16 - pcibios_protected: -- pushf -+ pushfd - cli - push esi - push edi -@@ -8864,7 +8864,7 @@ - #ifdef BX_QEMU - and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu - #endif -- popf -+ popfd - stc - retf - pci_pro_ok: -@@ -8874,7 +8874,7 @@ - #ifdef BX_QEMU - and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu - #endif -- popf -+ popfd - clc - retf - Index: rombios.h =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios.h,v -retrieving revision 1.1 -diff -u -w -r1.1 rombios.h ---- rombios.h 30 Sep 2006 11:22:53 -0000 1.1 -+++ rombios.h 1 Oct 2006 16:03:54 -0000 +retrieving revision 1.2 +diff -u -w -r1.2 rombios.h +--- rombios.h 1 Oct 2006 16:39:18 -0000 1.2 ++++ rombios.h 2 Oct 2006 18:31:41 -0000 @@ -19,7 +19,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA @@ -87,132 +14,56 @@ diff -u -w -r1.1 rombios.h #define BX_ROMBIOS32 1 #define DEBUG_ROMBIOS 0 -@@ -48,3 +48,7 @@ - #endif - #define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) - #define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p) -+ -+#define ACPI_DATA_SIZE 0x00010000L -+#define PM_IO_BASE 0xb000 -+#define CPU_COUNT_ADDR 0xf000 Index: rombios32.c =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios32.c,v -retrieving revision 1.4 -diff -u -w -r1.4 rombios32.c ---- rombios32.c 30 Sep 2006 11:22:53 -0000 1.4 -+++ rombios32.c 1 Oct 2006 16:03:54 -0000 -@@ -55,13 +55,10 @@ +retrieving revision 1.6 +diff -u -w -r1.6 rombios32.c +--- rombios32.c 2 Oct 2006 06:29:37 -0000 1.6 ++++ rombios32.c 2 Oct 2006 18:31:41 -0000 +@@ -45,6 +45,8 @@ + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \ + : "0" (index)) - #define APIC_ENABLED 0x0100 ++#define wbinvd() asm volatile("wbinvd") ++ + #define CPUID_APIC (1 << 9) --#define CPU_COUNT_ADDR 0xf000 - #define AP_BOOT_ADDR 0x10000 + #define APIC_BASE ((uint8_t *)0xfee00000) +@@ -591,6 +593,7 @@ + PCIDevice *d = &i440_pcidev; + int v; - #define MPTABLE_MAX_SIZE 0x00002000 --#define ACPI_DATA_SIZE 0x00010000 - #define SMI_CMD_IO_ADDR 0xb2 --#define PM_IO_BASE 0xb000 ++ wbinvd(); + v = pci_config_readb(d, 0x59); + v = (v & 0x0f) | (0x10); + pci_config_writeb(d, 0x59, v); +@@ -645,7 +648,7 @@ + outb(0xb3, 0x01); - #define BIOS_TMP_STORAGE 0x00030000 /* 64 KB used to copy the BIOS to shadow RAM */ + /* raise an SMI interrupt */ +- outb(0xb2, 0x01); ++ outb(0xb2, 0x00); -@@ -354,12 +351,14 @@ + /* wait until SMM code executed */ + while (inb(0xb3) != 0x00); +@@ -656,6 +659,7 @@ + /* copy the SMM code */ + memcpy((void *)0xa8000, &smm_code_start, + &smm_code_end - &smm_code_start); ++ wbinvd(); + + /* close the SMM memory window and enable normal SMM */ + pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08); +@@ -848,6 +852,11 @@ + int ioapic_id, i, len; + int mp_config_table_size; - void delay_ms(int n) - { -- int i, j, r1, r2; -+ int i, j; - for(i = 0; i < n; i++) { --#if BX_QEMU +#ifdef BX_QEMU - /* approximative ! */ - for(j = 0; j < 1000000; j++); - #else -+ { -+ int r1, r2; - j = 66; - r1 = inb(0x61) & 0x10; - do { -@@ -369,6 +368,7 @@ - r1 = r2; - } - } while (j > 0); -+ } - #endif - } - } -Index: rombios32start.S -=================================================================== -RCS file: /cvsroot/bochs/bochs/bios/rombios32start.S,v -retrieving revision 1.1 -diff -u -w -r1.1 rombios32start.S ---- rombios32start.S 28 Sep 2006 18:56:20 -0000 1.1 -+++ rombios32start.S 1 Oct 2006 16:03:54 -0000 -@@ -1,3 +1,25 @@ -+///////////////////////////////////////////////////////////////////////// -+// $Id: bios.diff,v 1.15 2006-10-01 16:08:15 bellard Exp $ -+///////////////////////////////////////////////////////////////////////// -+// -+// 32 bit Bochs BIOS init code -+// Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+#include "rombios.h" ++ if (smp_cpus <= 1) ++ return; ++#endif + - .globl _start - .globl smp_ap_boot_code_start - .globl smp_ap_boot_code_end -@@ -6,8 +28,6 @@ - .global smm_code_start - .global smm_code_end - --#define PM_IO_BASE 0xb000 -- - _start: - /* clear bss section */ - xor %eax, %eax -@@ -18,13 +38,11 @@ - - jmp rombios32_init - --#define CPU_COUNT 0xf000 -- - .code16 - smp_ap_boot_code_start: - xor %ax, %ax - mov %ax, %ds -- incw CPU_COUNT -+ incw CPU_COUNT_ADDR - 1: - hlt - jmp 1b -@@ -33,7 +51,7 @@ - /* code to relocate SMBASE to 0xa0000 */ - smm_relocation_start: - mov $0x38000 + 0x7efc, %ebx -- mov (%ebx), %al /* revision ID to see if x86_64 or x86 */ -+ addr32 mov (%ebx), %al /* revision ID to see if x86_64 or x86 */ - cmp $0x64, %al - je 1f - mov $0x38000 + 0x7ef8, %ebx -@@ -42,7 +60,7 @@ - mov $0x38000 + 0x7f00, %ebx - 2: - movl $0xa0000, %eax -- movl %eax, (%ebx) -+ addr32 movl %eax, (%ebx) - rsm - smm_relocation_end: - + #ifdef BX_USE_EBDA_TABLES + mp_config_table = (uint8_t *)(ram_size - ACPI_DATA_SIZE - MPTABLE_MAX_SIZE); + #else -- cgit v1.2.3 From d1beab8220d1a7535bbaa44e3821922dbbad3677 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 2 Oct 2006 19:44:22 +0000 Subject: no-reboot option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2192 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 3 +++ vl.c | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 060c42c08..4634a220a 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -634,6 +634,9 @@ Disable ACPI (Advanced Configuration and Power Interface) support. Use it if your guest OS complains about ACPI problems (PC target machine only). +@item -no-reboot +Exit instead of rebooting. + @item -loadvm file Start right away with a saved state (@code{loadvm} in monitor) @end table diff --git a/vl.c b/vl.c index c30bb6b4d..d047eb420 100644 --- a/vl.c +++ b/vl.c @@ -161,6 +161,7 @@ int vnc_display = -1; #endif int acpi_enabled = 1; int fd_bootchk = 1; +int no_reboot = 0; /***********************************************************/ /* x86 ISA bus support */ @@ -5627,7 +5628,11 @@ void qemu_system_reset(void) void qemu_system_reset_request(void) { - reset_requested = 1; + if (no_reboot) { + shutdown_requested = 1; + } else { + reset_requested = 1; + } if (cpu_single_env) cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); } @@ -5925,6 +5930,7 @@ void help(void) " (default is CL-GD5446 PCI VGA)\n" "-no-acpi disable ACPI\n" #endif + "-no-reboot exit instead of rebooting\n" "-loadvm file start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" "\n" @@ -6005,6 +6011,7 @@ enum { QEMU_OPTION_smp, QEMU_OPTION_vnc, QEMU_OPTION_no_acpi, + QEMU_OPTION_no_reboot, }; typedef struct QEMUOption { @@ -6081,6 +6088,7 @@ const QEMUOption qemu_options[] = { { "usb", 0, QEMU_OPTION_usb }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, { "no-acpi", 0, QEMU_OPTION_no_acpi }, + { "no-reboot", 0, QEMU_OPTION_no_reboot }, { NULL }, }; @@ -6725,6 +6733,9 @@ int main(int argc, char **argv) case QEMU_OPTION_no_acpi: acpi_enabled = 0; break; + case QEMU_OPTION_no_reboot: + no_reboot = 1; + break; } } } -- cgit v1.2.3 From b4511723bdc0ead9b9b958ad20a4a8bf900d6243 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 8 Oct 2006 18:20:51 +0000 Subject: APIC init fix + APIC get_irq fix (Juergen Keil) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2193 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index aa6f2ef38..6e6673947 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -382,8 +382,6 @@ static void apic_init_ipi(APICState *s) { int i; - for(i = 0; i < APIC_LVT_NB; i++) - s->lvt[i] = 1 << 16; /* mask LVT */ s->tpr = 0; s->spurious_vec = 0xff; s->log_dest = 0; @@ -391,7 +389,8 @@ static void apic_init_ipi(APICState *s) memset(s->isr, 0, sizeof(s->isr)); memset(s->tmr, 0, sizeof(s->tmr)); memset(s->irr, 0, sizeof(s->irr)); - memset(s->lvt, 0, sizeof(s->lvt)); + for(i = 0; i < APIC_LVT_NB; i++) + s->lvt[i] = 1 << 16; /* mask LVT */ s->esr = 0; memset(s->icr, 0, sizeof(s->icr)); s->divide_conf = 0; @@ -477,9 +476,9 @@ int apic_get_interrupt(CPUState *env) intno = get_highest_priority_int(s->irr); if (intno < 0) return -1; - reset_bit(s->irr, intno); if (s->tpr && intno <= s->tpr) return s->spurious_vec & 0xff; + reset_bit(s->irr, intno); set_bit(s->isr, intno); apic_update_irq(s); return intno; -- cgit v1.2.3 From 1f9519c92decd438d04639bdceb34bde2a1de678 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 18 Oct 2006 21:16:44 +0000 Subject: Fix typo in pixel conversion templates. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2194 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl110_template.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pl110_template.h b/hw/pl110_template.h index db05035b0..ed533aca1 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -79,7 +79,7 @@ static drawfn glue(pl110_draw_fn_,BITS)[18] = #endif #define FN_2(x, y) FN(x, y) FN(x+1, y) -#define FN_4(x, y) FN_2(x, y) FN_2(x+1, y) +#define FN_4(x, y) FN_2(x, y) FN_2(x+2, y) #define FN_8(y) FN_4(0, y) FN_4(4, y) static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) -- cgit v1.2.3 From 223b8a40d13550ebc08216bd96d1f615597e0554 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 21 Oct 2006 23:43:02 +0000 Subject: bFLT 64-bit host fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2195 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/flat.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/linux-user/flat.h b/linux-user/flat.h index b057b140e..6d52b1ffe 100644 --- a/linux-user/flat.h +++ b/linux-user/flat.h @@ -22,25 +22,25 @@ struct flat_hdr { char magic[4]; - unsigned long rev; /* version (as above) */ - unsigned long entry; /* Offset of first executable instruction + target_ulong rev; /* version (as above) */ + target_ulong entry; /* Offset of first executable instruction with text segment from beginning of file */ - unsigned long data_start; /* Offset of data segment from beginning of + target_ulong data_start; /* Offset of data segment from beginning of file */ - unsigned long data_end; /* Offset of end of data segment + target_ulong data_end; /* Offset of end of data segment from beginning of file */ - unsigned long bss_end; /* Offset of end of bss segment from beginning + target_ulong bss_end; /* Offset of end of bss segment from beginning of file */ /* (It is assumed that data_end through bss_end forms the bss segment.) */ - unsigned long stack_size; /* Size of stack, in bytes */ - unsigned long reloc_start; /* Offset of relocation records from + target_ulong stack_size; /* Size of stack, in bytes */ + target_ulong reloc_start; /* Offset of relocation records from beginning of file */ - unsigned long reloc_count; /* Number of relocation records */ - unsigned long flags; - unsigned long build_date; /* When the program/library was built */ - unsigned long filler[5]; /* Reservered, set to zero */ + target_ulong reloc_count; /* Number of relocation records */ + target_ulong flags; + target_ulong build_date; /* When the program/library was built */ + target_ulong filler[5]; /* Reservered, set to zero */ }; #define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */ -- cgit v1.2.3 From e6e5906b6e0a81718066ca43aef57515026c6624 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 22 Oct 2006 00:18:54 +0000 Subject: ColdFire target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2196 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 7 + configure | 10 +- cpu-all.h | 7 + cpu-exec.c | 62 +- disas.c | 4 + fpu/softfloat-native.c | 16 + fpu/softfloat-native.h | 2 + fpu/softfloat.c | 11 + fpu/softfloat.h | 2 + gdbstub.c | 67 + hw/pl110.c | 5 +- linux-user/elfload.c | 25 + linux-user/m68k-semi.c | 216 ++++ linux-user/m68k-sim.c | 171 +++ linux-user/m68k/syscall.h | 22 + linux-user/m68k/syscall_nr.h | 283 +++++ linux-user/m68k/termbits.h | 215 ++++ linux-user/main.c | 121 ++ linux-user/mmap.c | 2 +- linux-user/qemu.h | 3 + linux-user/syscall.c | 11 +- linux-user/syscall_defs.h | 67 +- qemu-doc.texi | 6 +- target-m68k/cpu.h | 140 +++ target-m68k/exec.h | 47 + target-m68k/helper.c | 149 +++ target-m68k/m68k-qreg.h | 12 + target-m68k/op-hacks.h | 83 ++ target-m68k/op.c | 678 +++++++++++ target-m68k/qregs.def | 34 + target-m68k/translate.c | 2759 ++++++++++++++++++++++++++++++++++++++++++ translate-all.c | 2 + 32 files changed, 5227 insertions(+), 12 deletions(-) create mode 100644 linux-user/m68k-semi.c create mode 100644 linux-user/m68k-sim.c create mode 100644 linux-user/m68k/syscall.h create mode 100644 linux-user/m68k/syscall_nr.h create mode 100644 linux-user/m68k/termbits.h create mode 100644 target-m68k/cpu.h create mode 100644 target-m68k/exec.h create mode 100644 target-m68k/helper.c create mode 100644 target-m68k/m68k-qreg.h create mode 100644 target-m68k/op-hacks.h create mode 100644 target-m68k/op.c create mode 100644 target-m68k/qregs.def create mode 100644 target-m68k/translate.c diff --git a/Makefile.target b/Makefile.target index aa2244b00..773f331a9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -197,6 +197,9 @@ 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 @@ -241,6 +244,10 @@ 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) diff --git a/configure b/configure index a2fde23ae..84f8ee099 100755 --- a/configure +++ b/configure @@ -362,7 +362,7 @@ if test -z "$target_list" ; then 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 $target_list" + 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'` @@ -727,6 +727,7 @@ target_bigendian="no" [ "$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" @@ -822,6 +823,11 @@ elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then 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 @@ -839,7 +845,7 @@ if test "$target_user_only" = "yes" ; then 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"; then +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 diff --git a/cpu-all.h b/cpu-all.h index a8628b502..ed5355319 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -725,6 +725,13 @@ void page_unprotect_range(target_ulong data, target_ulong data_size); #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 diff --git a/cpu-exec.c b/cpu-exec.c index 0b5f7f3d8..5950625fb 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -40,14 +40,14 @@ int tb_invalidated_flag; //#define DEBUG_EXEC //#define DEBUG_SIGNAL -#if defined(TARGET_ARM) || defined(TARGET_SPARC) +#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)) +#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K)) #define reg_T2 #endif @@ -194,6 +194,10 @@ static inline TranslationBlock *tb_find_fast(void) 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 */ @@ -370,6 +374,10 @@ int cpu_exec(CPUState *env1) 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 */ @@ -632,6 +640,12 @@ int cpu_exec(CPUState *env1) 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) @@ -846,6 +860,11 @@ int cpu_exec(CPUState *env1) 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 */ @@ -1103,6 +1122,45 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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, diff --git a/disas.c b/disas.c index 27b677792..04ea65355 100644 --- a/disas.c +++ b/disas.c @@ -186,6 +186,8 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) 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; @@ -385,6 +387,8 @@ void monitor_disas(CPUState *env, 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; diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index bbdb3d66d..1ef7cf29a 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -221,6 +221,11 @@ float128 float64_to_float128( float64 a STATUS_PARAM) /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ +float64 float64_trunc_to_int( float64 a STATUS_PARAM ) +{ + return trunc(a); +} + float64 float64_round_to_int( float64 a STATUS_PARAM ) { #if defined(__arm__) @@ -289,6 +294,17 @@ char float64_is_signaling_nan( float64 a1) } +char float64_is_nan( float64 a1 ) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); + +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index e7c08b89f..05cf023f6 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -214,6 +214,7 @@ float128 float64_to_float128( float64 STATUS_PARAM ); | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_trunc_to_int( float64 STATUS_PARAM ); INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM) { return a + b; @@ -265,6 +266,7 @@ INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM) char float64_compare( float64, float64 STATUS_PARAM ); char float64_compare_quiet( float64, float64 STATUS_PARAM ); char float64_is_signaling_nan( float64 ); +flag float64_is_nan( float64 ); INLINE float64 float64_abs(float64 a) { diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5e846200a..f24913a13 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2483,6 +2483,17 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) } +float64 float64_trunc_to_int( float64 a STATUS_PARAM) +{ + int oldmode; + float64 res; + oldmode = STATUS(float_rounding_mode); + STATUS(float_rounding_mode) = float_round_to_zero; + res = float64_round_to_int(a STATUS_VAR); + STATUS(float_rounding_mode) = oldmode; + return res; +} + /*---------------------------------------------------------------------------- | Returns the result of adding the absolute values of the double-precision | floating-point values `a' and `b'. If `zSign' is 1, the sum is negated diff --git a/fpu/softfloat.h b/fpu/softfloat.h index fdc80f32d..3dec119e4 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -237,6 +237,7 @@ char float32_lt_quiet( float32, float32 STATUS_PARAM ); char float32_compare( float32, float32 STATUS_PARAM ); char float32_compare_quiet( float32, float32 STATUS_PARAM ); char float32_is_signaling_nan( float32 ); +flag float64_is_nan( float64 a ); INLINE float32 float32_abs(float32 a) { @@ -269,6 +270,7 @@ float128 float64_to_float128( float64 STATUS_PARAM ); | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ float64 float64_round_to_int( float64 STATUS_PARAM ); +float64 float64_trunc_to_int( float64 STATUS_PARAM ); float64 float64_add( float64, float64 STATUS_PARAM ); float64 float64_sub( float64, float64 STATUS_PARAM ); float64 float64_mul( float64, float64 STATUS_PARAM ); diff --git a/gdbstub.c b/gdbstub.c index 6ad393f79..9e10c0cdc 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -434,6 +434,73 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) ptr += 8 * 12 + 4; cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff); } +#elif defined (TARGET_M68K) +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + int i; + uint8_t *ptr; + CPU_DoubleU u; + + ptr = mem_buf; + /* D0-D7 */ + for (i = 0; i < 8; i++) { + *(uint32_t *)ptr = tswapl(env->dregs[i]); + ptr += 4; + } + /* A0-A7 */ + for (i = 0; i < 8; i++) { + *(uint32_t *)ptr = tswapl(env->aregs[i]); + ptr += 4; + } + *(uint32_t *)ptr = tswapl(env->sr); + ptr += 4; + *(uint32_t *)ptr = tswapl(env->pc); + ptr += 4; + /* F0-F7. The 68881/68040 have 12-bit extended precision registers. + ColdFire has 8-bit double precision registers. */ + for (i = 0; i < 8; i++) { + u.d = env->fregs[i]; + *(uint32_t *)ptr = tswap32(u.l.upper); + *(uint32_t *)ptr = tswap32(u.l.lower); + } + /* FP control regs (not implemented). */ + memset (ptr, 0, 3 * 4); + ptr += 3 * 4; + + return ptr - mem_buf; +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + int i; + uint8_t *ptr; + CPU_DoubleU u; + + ptr = mem_buf; + /* D0-D7 */ + for (i = 0; i < 8; i++) { + env->dregs[i] = tswapl(*(uint32_t *)ptr); + ptr += 4; + } + /* A0-A7 */ + for (i = 0; i < 8; i++) { + env->aregs[i] = tswapl(*(uint32_t *)ptr); + ptr += 4; + } + env->sr = tswapl(*(uint32_t *)ptr); + ptr += 4; + env->pc = tswapl(*(uint32_t *)ptr); + ptr += 4; + /* F0-F7. The 68881/68040 have 12-bit extended precision registers. + ColdFire has 8-bit double precision registers. */ + for (i = 0; i < 8; i++) { + u.l.upper = tswap32(*(uint32_t *)ptr); + u.l.lower = tswap32(*(uint32_t *)ptr); + env->fregs[i] = u.d; + } + /* FP control regs (not implemented). */ + ptr += 3 * 4; +} #elif defined (TARGET_MIPS) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { diff --git a/hw/pl110.c b/hw/pl110.c index ecebe35eb..16de16c0d 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -185,10 +185,11 @@ static void pl110_update_display(void *opaque) addr = base; dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); + new_dirty = dirty; for (i = 0; i < s->rows; i++) { - new_dirty = 0; - if ((addr & TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) { + if ((addr & ~TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) { uint32_t tmp; + new_dirty = 0; for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) { new_dirty |= cpu_physical_memory_get_dirty(addr + tmp, VGA_DIRTY_FLAG); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 57b5ed27d..042c65dc7 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -288,6 +288,31 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif +#ifdef TARGET_M68K + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_68K ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_68K + +/* ??? Does this need to do anything? +#define ELF_PLAT_INIT(_r) */ + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->usp = infop->start_stack; + regs->sr = 0; + regs->pc = infop->entry; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +#endif + #ifndef ELF_PLATFORM #define ELF_PLATFORM (NULL) #endif diff --git a/linux-user/m68k-semi.c b/linux-user/m68k-semi.c new file mode 100644 index 000000000..7f6dddaee --- /dev/null +++ b/linux-user/m68k-semi.c @@ -0,0 +1,216 @@ +/* + * m68k/ColdFire Semihosting ssycall interface + * + * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +#define HOSTED_EXIT 0 +#define HOSTED_PUTCHAR 1 /* Obsolete */ +#define HOSTED_OPEN 2 +#define HOSTED_CLOSE 3 +#define HOSTED_READ 4 +#define HOSTED_WRITE 5 +#define HOSTED_LSEEK 6 +#define HOSTED_RENAME 7 +#define HOSTED_UNLINK 8 +#define HOSTED_STAT 9 +#define HOSTED_FSTAT 10 +#define HOSTED_GETTIMEOFDAY 11 +#define HOSTED_ISATTY 12 +#define HOSTED_SYSTEM 13 + +typedef uint32_t gdb_mode_t; +typedef uint32_t gdb_time_t; + +struct m68k_gdb_stat { + uint32_t gdb_st_dev; /* device */ + uint32_t gdb_st_ino; /* inode */ + gdb_mode_t gdb_st_mode; /* protection */ + uint32_t gdb_st_nlink; /* number of hard links */ + uint32_t gdb_st_uid; /* user ID of owner */ + uint32_t gdb_st_gid; /* group ID of owner */ + uint32_t gdb_st_rdev; /* device type (if inode device) */ + uint64_t gdb_st_size; /* total size, in bytes */ + uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ + uint64_t gdb_st_blocks; /* number of blocks allocated */ + gdb_time_t gdb_st_atime; /* time of last access */ + gdb_time_t gdb_st_mtime; /* time of last modification */ + gdb_time_t gdb_st_ctime; /* time of last change */ +}; + +struct gdb_timeval { + gdb_time_t tv_sec; /* second */ + uint64_t tv_usec; /* microsecond */ +}; + +#define GDB_O_RDONLY 0x0 +#define GDB_O_WRONLY 0x1 +#define GDB_O_RDWR 0x2 +#define GDB_O_APPEND 0x8 +#define GDB_O_CREAT 0x200 +#define GDB_O_TRUNC 0x400 +#define GDB_O_EXCL 0x800 + +static int translate_openflags(int flags) +{ + int hf; + + if (flags & GDB_O_WRONLY) + hf = O_WRONLY; + else if (flags & GDB_O_RDWR) + hf = O_RDWR; + else + hf = O_RDONLY; + + if (flags & GDB_O_APPEND) hf |= O_APPEND; + if (flags & GDB_O_CREAT) hf |= O_CREAT; + if (flags & GDB_O_TRUNC) hf |= O_TRUNC; + if (flags & GDB_O_EXCL) hf |= O_EXCL; + + return hf; +} + +static void translate_stat(struct m68k_gdb_stat *p, struct stat *s) +{ + p->gdb_st_dev = tswap16(s->st_dev); + p->gdb_st_ino = tswap16(s->st_ino); + p->gdb_st_mode = tswap32(s->st_mode); + p->gdb_st_nlink = tswap16(s->st_nlink); + p->gdb_st_uid = tswap16(s->st_uid); + p->gdb_st_gid = tswap16(s->st_gid); + p->gdb_st_rdev = tswap16(s->st_rdev); + p->gdb_st_size = tswap32(s->st_size); + p->gdb_st_atime = tswap32(s->st_atime); + p->gdb_st_mtime = tswap32(s->st_mtime); + p->gdb_st_ctime = tswap32(s->st_ctime); + p->gdb_st_blksize = tswap32(s->st_blksize); + p->gdb_st_blocks = tswap32(s->st_blocks); +} + +static inline uint32_t check_err(CPUM68KState *env, uint32_t code) +{ + if (code == (uint32_t)-1) { + env->sr |= CCF_C; + } else { + env->sr &= ~CCF_C; + env->dregs[0] = code; + } + return code; +} + +#define ARG(x) tswap32(args[x]) +void do_m68k_semihosting(CPUM68KState *env, int nr) +{ + uint32_t *args; + + args = (uint32_t *)env->dregs[1]; + switch (nr) { + case HOSTED_EXIT: + exit(env->dregs[0]); + case HOSTED_OPEN: + /* Assume name is NULL terminated. */ + check_err(env, open((char *)ARG(0), translate_openflags(ARG(2)), + ARG(3))); + break; + case HOSTED_CLOSE: + { + /* Ignore attempts to close stdin/out/err. */ + int fd = ARG(0); + if (fd > 2) + check_err(env, close(fd)); + else + check_err(env, 0); + break; + } + case HOSTED_READ: + check_err(env, read(ARG(0), (void *)ARG(1), ARG(2))); + break; + case HOSTED_WRITE: + check_err(env, write(ARG(0), (void *)ARG(1), ARG(2))); + break; + case HOSTED_LSEEK: + { + uint64_t off; + off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32); + check_err(env, lseek(ARG(0), off, ARG(3))); + } + break; + case HOSTED_RENAME: + /* Assume names are NULL terminated. */ + check_err(env, rename((char *)ARG(0), (char *)ARG(2))); + break; + case HOSTED_UNLINK: + /* Assume name is NULL terminated. */ + check_err(env, unlink((char *)ARG(0))); + break; + case HOSTED_STAT: + /* Assume name is NULL terminated. */ + { + struct stat s; + int rc; + rc = check_err(env, stat((char *)ARG(0), &s)); + if (rc == 0) { + translate_stat((struct m68k_gdb_stat *)ARG(2), &s); + } + } + break; + case HOSTED_FSTAT: + { + struct stat s; + int rc; + rc = check_err(env, fstat(ARG(0), &s)); + if (rc == 0) { + translate_stat((struct m68k_gdb_stat *)ARG(1), &s); + } + } + break; + case HOSTED_GETTIMEOFDAY: + { + struct timeval tv; + struct gdb_timeval *p; + int rc; + rc = check_err(env, gettimeofday(&tv, NULL)); + if (rc != 0) { + p = (struct gdb_timeval *)ARG(0); + p->tv_sec = tswap32(tv.tv_sec); + p->tv_usec = tswap64(tv.tv_usec); + } + } + break; + case HOSTED_ISATTY: + check_err(env, isatty(ARG(0))); + break; + case HOSTED_SYSTEM: + /* Assume name is NULL terminated. */ + check_err(env, system((char *)ARG(0))); + break; + default: + cpu_abort(env, "Unsupported semihosting syscall %d\n", nr); + } +} diff --git a/linux-user/m68k-sim.c b/linux-user/m68k-sim.c new file mode 100644 index 000000000..667808e8c --- /dev/null +++ b/linux-user/m68k-sim.c @@ -0,0 +1,171 @@ +/* + * m68k simulator syscall interface + * + * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +#define SYS_EXIT 1 +#define SYS_READ 3 +#define SYS_WRITE 4 +#define SYS_OPEN 5 +#define SYS_CLOSE 6 +#define SYS_BRK 17 +#define SYS_FSTAT 28 +#define SYS_ISATTY 29 +#define SYS_LSEEK 199 + +struct m86k_sim_stat { + uint16_t sim_st_dev; + uint16_t sim_st_ino; + uint32_t sim_st_mode; + uint16_t sim_st_nlink; + uint16_t sim_st_uid; + uint16_t sim_st_gid; + uint16_t sim_st_rdev; + uint32_t sim_st_size; + uint32_t sim_st_atime; + uint32_t sim_st_mtime; + uint32_t sim_st_ctime; + uint32_t sim_st_blksize; + uint32_t sim_st_blocks; +}; + +static inline uint32_t check_err(CPUM68KState *env, uint32_t code) +{ + env->dregs[0] = code; + if (code == (uint32_t)-1) { + env->dregs[1] = errno; + } else { + env->dregs[1] = 0; + } + return code; +} + +#define SIM_O_APPEND 0x0008 +#define SIM_O_CREAT 0x0200 +#define SIM_O_TRUNC 0x0400 +#define SIM_O_EXCL 0x0800 +#define SIM_O_NONBLOCK 0x4000 +#define SIM_O_NOCTTY 0x8000 +#define SIM_O_SYNC 0x2000 + +static int translate_openflags(int flags) +{ + int hf; + + switch (flags & 3) { + case 0: hf = O_RDONLY; break; + case 1: hf = O_WRONLY; break; + case 2: hf = O_RDWR; break; + default: hf = O_RDWR; break; + } + + if (flags & SIM_O_APPEND) hf |= O_APPEND; + if (flags & SIM_O_CREAT) hf |= O_CREAT; + if (flags & SIM_O_TRUNC) hf |= O_TRUNC; + if (flags & SIM_O_EXCL) hf |= O_EXCL; + if (flags & SIM_O_NONBLOCK) hf |= O_NONBLOCK; + if (flags & SIM_O_NOCTTY) hf |= O_NOCTTY; + if (flags & SIM_O_SYNC) hf |= O_SYNC; + + return hf; +} + +#define ARG(x) tswap32(args[x]) +void do_m68k_simcall(CPUM68KState *env, int nr) +{ + uint32_t *args; + + args = (uint32_t *)(env->aregs[7] + 4); + switch (nr) { + case SYS_EXIT: + exit(ARG(0)); + case SYS_READ: + check_err(env, read(ARG(0), (void *)ARG(1), ARG(2))); + break; + case SYS_WRITE: + check_err(env, write(ARG(0), (void *)ARG(1), ARG(2))); + break; + case SYS_OPEN: + check_err(env, open((char *)ARG(0), translate_openflags(ARG(1)), + ARG(2))); + break; + case SYS_CLOSE: + { + /* Ignore attempts to close stdin/out/err. */ + int fd = ARG(0); + if (fd > 2) + check_err(env, close(fd)); + else + check_err(env, 0); + break; + } + case SYS_BRK: + { + int32_t ret; + + ret = do_brk((void *)ARG(0)); + if (ret == -ENOMEM) + ret = -1; + check_err(env, ret); + } + break; + case SYS_FSTAT: + { + struct stat s; + int rc; + struct m86k_sim_stat *p; + rc = check_err(env, fstat(ARG(0), &s)); + if (rc == 0) { + p = (struct m86k_sim_stat *)ARG(1); + p->sim_st_dev = tswap16(s.st_dev); + p->sim_st_ino = tswap16(s.st_ino); + p->sim_st_mode = tswap32(s.st_mode); + p->sim_st_nlink = tswap16(s.st_nlink); + p->sim_st_uid = tswap16(s.st_uid); + p->sim_st_gid = tswap16(s.st_gid); + p->sim_st_rdev = tswap16(s.st_rdev); + p->sim_st_size = tswap32(s.st_size); + p->sim_st_atime = tswap32(s.st_atime); + p->sim_st_mtime = tswap32(s.st_mtime); + p->sim_st_ctime = tswap32(s.st_ctime); + p->sim_st_blksize = tswap32(s.st_blksize); + p->sim_st_blocks = tswap32(s.st_blocks); + } + } + break; + case SYS_ISATTY: + check_err(env, isatty(ARG(0))); + break; + case SYS_LSEEK: + check_err(env, lseek(ARG(0), (int32_t)ARG(1), ARG(2))); + break; + default: + cpu_abort(env, "Unsupported m68k sim syscall %d\n", nr); + } +} diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/syscall.h new file mode 100644 index 000000000..c225567d2 --- /dev/null +++ b/linux-user/m68k/syscall.h @@ -0,0 +1,22 @@ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { + target_long d1, d2, d3, d4, d5, d6, d7; + target_long a0, a1, a2, a3, a4, a5, a6; + target_ulong d0; + target_ulong usp; + target_ulong orig_d0; + int16_t stkadj; + uint16_t sr; + target_ulong pc; + uint16_t fntvex; + uint16_t __fill; +}; + + +#define UNAME_MACHINE "m68k" + +void do_m68k_semihosting(CPUState *, int); +void do_m68k_simcall(CPUState *, int); diff --git a/linux-user/m68k/syscall_nr.h b/linux-user/m68k/syscall_nr.h new file mode 100644 index 000000000..a39535f5f --- /dev/null +++ b/linux-user/m68k/syscall_nr.h @@ -0,0 +1,283 @@ +/* + * This file contains the system call numbers. + */ + +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_chown 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +//#define TARGET_NR_iopl /* 110 */ not supported +#define TARGET_NR_vhangup 111 +//#define TARGET_NR_idle /* 112 */ Obsolete +//#define TARGET_NR_vm86 /* 113 */ not supported +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_cacheflush 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_getpagesize 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread64 180 +#define TARGET_NR_pwrite64 181 +#define TARGET_NR_lchown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 +#define TARGET_NR_getpmsg 188 /* some people actually want streams */ +#define TARGET_NR_putpmsg 189 /* some people actually want streams */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_chown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_lchown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_pivot_root 217 +#define TARGET_NR_getdents64 220 +#define TARGET_NR_gettid 221 +#define TARGET_NR_tkill 222 +#define TARGET_NR_setxattr 223 +#define TARGET_NR_lsetxattr 224 +#define TARGET_NR_fsetxattr 225 +#define TARGET_NR_getxattr 226 +#define TARGET_NR_lgetxattr 227 +#define TARGET_NR_fgetxattr 228 +#define TARGET_NR_listxattr 229 +#define TARGET_NR_llistxattr 230 +#define TARGET_NR_flistxattr 231 +#define TARGET_NR_removexattr 232 +#define TARGET_NR_lremovexattr 233 +#define TARGET_NR_fremovexattr 234 +#define TARGET_NR_futex 235 +#define TARGET_NR_sendfile64 236 +#define TARGET_NR_mincore 237 +#define TARGET_NR_madvise 238 +#define TARGET_NR_fcntl64 239 +#define TARGET_NR_readahead 240 +#define TARGET_NR_io_setup 241 +#define TARGET_NR_io_destroy 242 +#define TARGET_NR_io_getevents 243 +#define TARGET_NR_io_submit 244 +#define TARGET_NR_io_cancel 245 +#define TARGET_NR_fadvise64 246 +#define TARGET_NR_exit_group 247 +#define TARGET_NR_lookup_dcookie 248 +#define TARGET_NR_epoll_create 249 +#define TARGET_NR_epoll_ctl 250 +#define TARGET_NR_epoll_wait 251 +#define TARGET_NR_remap_file_pages 252 +#define TARGET_NR_set_tid_address 253 +#define TARGET_NR_timer_create 254 +#define TARGET_NR_timer_settime 255 +#define TARGET_NR_timer_gettime 256 +#define TARGET_NR_timer_getoverrun 257 +#define TARGET_NR_timer_delete 258 +#define TARGET_NR_clock_settime 259 +#define TARGET_NR_clock_gettime 260 +#define TARGET_NR_clock_getres 261 +#define TARGET_NR_clock_nanosleep 262 +#define TARGET_NR_statfs64 263 +#define TARGET_NR_fstatfs64 264 +#define TARGET_NR_tgkill 265 +#define TARGET_NR_utimes 266 +#define TARGET_NR_fadvise64_64 267 +#define TARGET_NR_mbind 268 +#define TARGET_NR_get_mempolicy 269 +#define TARGET_NR_set_mempolicy 270 +#define TARGET_NR_mq_open 271 +#define TARGET_NR_mq_unlink 272 +#define TARGET_NR_mq_timedsend 273 +#define TARGET_NR_mq_timedreceive 274 +#define TARGET_NR_mq_notify 275 +#define TARGET_NR_mq_getsetattr 276 +#define TARGET_NR_waitid 277 +#define TARGET_NR_vserver 278 +#define TARGET_NR_add_key 279 +#define TARGET_NR_request_key 280 +#define TARGET_NR_keyctl 281 diff --git a/linux-user/m68k/termbits.h b/linux-user/m68k/termbits.h new file mode 100644 index 000000000..36ead0895 --- /dev/null +++ b/linux-user/m68k/termbits.h @@ -0,0 +1,215 @@ +/* from asm/termbits.h */ +/* NOTE: exactly the same as i386 */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + diff --git a/linux-user/main.c b/linux-user/main.c index 42f4a0350..53bf1bb92 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1412,6 +1412,98 @@ void cpu_loop (CPUState *env) } #endif +#ifdef TARGET_M68K + +void cpu_loop(CPUM68KState *env) +{ + int trapnr; + unsigned int n; + target_siginfo_t info; + TaskState *ts = env->opaque; + + for(;;) { + trapnr = cpu_m68k_exec(env); + switch(trapnr) { + case EXCP_ILLEGAL: + { + if (ts->sim_syscalls) { + uint16_t nr; + nr = lduw(env->pc + 2); + env->pc += 4; + do_m68k_simcall(env, nr); + } else { + goto do_sigill; + } + } + break; + case EXCP_HALTED: + /* Semihosing syscall. */ + env->pc += 2; + do_m68k_semihosting(env, env->dregs[0]); + break; + case EXCP_LINEA: + case EXCP_LINEF: + case EXCP_UNSUPPORTED: + do_sigill: + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->pc; + queue_signal(info.si_signo, &info); + break; + case EXCP_TRAP0: + { + ts->sim_syscalls = 0; + n = env->dregs[0]; + env->pc += 2; + env->dregs[0] = do_syscall(env, + n, + env->dregs[1], + env->dregs[2], + env->dregs[3], + env->dregs[4], + env->dregs[5], + env->dregs[6]); + } + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_ACCESS: + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->mmu.ar; + queue_signal(info.si_signo, &info); + } + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); + } + process_pending_signals(env); + } +} +#endif /* TARGET_M68K */ + void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n" @@ -1685,6 +1777,35 @@ int main(int argc, char **argv) env->gpr[i] = regs->gpr[i]; } } +#elif defined(TARGET_M68K) + { + m68k_def_t *def; + def = m68k_find_by_name("cfv4e"); + if (def == NULL) { + cpu_abort(cpu_single_env, + "Unable to find m68k CPU definition\n"); + } + cpu_m68k_register(cpu_single_env, def); + env->pc = regs->pc; + env->dregs[0] = regs->d0; + env->dregs[1] = regs->d1; + env->dregs[2] = regs->d2; + env->dregs[3] = regs->d3; + env->dregs[4] = regs->d4; + env->dregs[5] = regs->d5; + env->dregs[6] = regs->d6; + env->dregs[7] = regs->d7; + env->aregs[0] = regs->a0; + env->aregs[1] = regs->a1; + env->aregs[2] = regs->a2; + env->aregs[3] = regs->a3; + env->aregs[4] = regs->a4; + env->aregs[5] = regs->a5; + env->aregs[6] = regs->a6; + env->aregs[7] = regs->usp; + env->sr = regs->sr; + ts->sim_syscalls = 1; + } #elif defined(TARGET_MIPS) { int i; diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 0c906257b..cbaa7ce2c 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -209,7 +209,7 @@ long target_mmap(target_ulong start, target_ulong len, int prot, last_start += HOST_PAGE_ALIGN(len); } #endif - if (qemu_host_page_size != qemu_real_host_page_size) { + if (0 && qemu_host_page_size != qemu_real_host_page_size) { /* NOTE: this code is only for debugging with '-p' option */ /* ??? Can also occur when TARGET_PAGE_SIZE > host page size. */ /* reserve a memory area */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 218e846a0..d35455de3 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -73,6 +73,9 @@ typedef struct TaskState { struct target_vm86plus_struct vm86plus; uint32_t v86flags; uint32_t v86mask; +#endif +#ifdef TARGET_M68K + int sim_syscalls; #endif int used; /* non zero if used */ struct image_info *info; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 60ed9a607..e5e4139fd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -69,7 +69,8 @@ //#define DEBUG -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ + || defined(TARGET_M68K) /* 16 bit uid wrappers emulation */ #define USE_UID16 #endif @@ -1645,6 +1646,12 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) new_env->regwptr[0] = 0; /* XXXXX */ printf ("HELPME: %s:%d\n", __FILE__, __LINE__); +#elif defined(TARGET_M68K) + if (!newsp) + newsp = env->aregs[7]; + new_env->aregs[7] = newsp; + new_env->dregs[0] = 0; + /* ??? is this sufficient? */ #elif defined(TARGET_MIPS) printf ("HELPME: %s:%d\n", __FILE__, __LINE__); #elif defined(TARGET_PPC) @@ -2604,7 +2611,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_readdir: goto unimplemented; case TARGET_NR_mmap: -#if defined(TARGET_I386) || defined(TARGET_ARM) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K) { target_ulong *v; target_ulong v1, v2, v3, v4, v5, v6; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 015f3ba24..e33c12beb 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -48,7 +48,8 @@ #define TARGET_IOC_NRBITS 8 #define TARGET_IOC_TYPEBITS 8 -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ + || defined(TARGET_M68K) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -293,7 +294,7 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) #if defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u @@ -1070,6 +1071,68 @@ struct target_stat64 { target_ulong __unused5; }; +#elif defined(TARGET_M68K) + +struct target_stat { + unsigned short st_dev; + unsigned short __pad1; + target_ulong st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + target_ulong st_size; + target_ulong st_blksize; + target_ulong st_blocks; + target_ulong target_st_atime; + target_ulong __unused1; + target_ulong target_st_mtime; + target_ulong __unused2; + target_ulong target_st_ctime; + target_ulong __unused3; + target_ulong __unused4; + target_ulong __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct target_stat64 { + unsigned long long st_dev; + unsigned char __pad1[2]; + +#define TARGET_STAT64_HAS_BROKEN_ST_INO 1 + target_ulong __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + target_ulong st_uid; + target_ulong st_gid; + + unsigned long long st_rdev; + unsigned char __pad3[2]; + + long long st_size; + target_ulong st_blksize; + + target_ulong __pad4; /* future possible st_blocks high bits */ + target_ulong st_blocks; /* Number 512-byte blocks allocated. */ + + target_ulong target_st_atime; + target_ulong target_st_atime_nsec; + + target_ulong target_st_mtime; + target_ulong target_st_mtime_nsec; + + target_ulong target_st_ctime; + target_ulong target_st_ctime_nsec; + + unsigned long long st_ino; +} __attribute__((packed)); + #elif defined(TARGET_MIPS) struct target_stat { diff --git a/qemu-doc.texi b/qemu-doc.texi index 4634a220a..c7fbe1d1d 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -81,7 +81,7 @@ For system emulation, the following hardware targets are supported: @item ARM Versatile baseboard (ARM926E) @end itemize -For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported. +For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported. @node Installation @chapter Installation @@ -1768,6 +1768,10 @@ Act as if the host page size was 'pagesize' bytes binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB configurations), and arm-uclinux bFLT format binaries. +@command{qemu-m68k} is capable of running semihosted binaries using the BDM +(m5xxx-ram-hosted.ld) or m68k-sim (sim.ld) syscall interfaces, and +coldfire uClinux bFLT format binaries. + The binary format is detected automatically. @node compilation diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h new file mode 100644 index 000000000..29e02e8bb --- /dev/null +++ b/target-m68k/cpu.h @@ -0,0 +1,140 @@ +/* + * m68k virtual CPU header + * + * Copyright (c) 2005-2006 CodeSourcery + * Written by Paul Brook + * + * 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 + * 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_M68K_H +#define CPU_M68K_H + +#define TARGET_LONG_BITS 32 + +#include "cpu-defs.h" + +#include "softfloat.h" + +#define MAX_QREGS 32 + +#define TARGET_HAS_ICE 1 + +#define EXCP_ACCESS 2 /* Access (MMU) error. */ +#define EXCP_ADDRESS 3 /* Address error. */ +#define EXCP_ILLEGAL 4 /* Illegal instruction. */ +#define EXCP_DIV0 5 /* Divide by zero */ +#define EXCP_PRIVILEGE 8 /* Privilege violation. */ +#define EXCP_TRACE 9 +#define EXCP_LINEA 10 /* Unimplemented line-A (MAC) opcode. */ +#define EXCP_LINEF 11 /* Unimplemented line-F (FPU) opcode. */ +#define EXCP_DEBUGNBP 12 /* Non-breakpoint debug interrupt. */ +#define EXCP_DEBEGBP 13 /* Breakpoint debug interrupt. */ +#define EXCP_FORMAT 14 /* RTE format error. */ +#define EXCP_UNINITIALIZED 15 +#define EXCP_TRAP0 32 /* User trap #0. */ +#define EXCP_TRAP15 47 /* User trap #15. */ +#define EXCP_UNSUPPORTED 61 +#define EXCP_ICE 13 + +typedef struct CPUM68KState { + uint32_t dregs[8]; + uint32_t aregs[8]; + uint32_t pc; + uint32_t sr; + + /* Condition flags. */ + uint32_t cc_op; + uint32_t cc_dest; + uint32_t cc_src; + uint32_t cc_x; + + float64 fregs[8]; + float64 fp_result; + uint32_t fpcr; + uint32_t fpsr; + float_status fp_status; + + /* Temporary storage for DIV helpers. */ + uint32_t div1; + uint32_t div2; + + /* MMU status. */ + struct { + uint32_t ar; + } mmu; + /* ??? remove this. */ + uint32_t t1; + + /* exception/interrupt handling */ + jmp_buf jmp_env; + int exception_index; + int interrupt_request; + int user_mode_only; + uint32_t address; + + uint32_t qregs[MAX_QREGS]; + + CPU_COMMON +} CPUM68KState; + +CPUM68KState *cpu_m68k_init(void); +int cpu_m68k_exec(CPUM68KState *s); +void cpu_m68k_close(CPUM68KState *s); +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +struct siginfo; +int cpu_m68k_signal_handler(int host_signum, struct siginfo *info, + void *puc); +void cpu_m68k_flush_flags(CPUM68KState *, int); + +enum { + CC_OP_DYNAMIC, /* Use env->cc_op */ + CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */ + CC_OP_LOGIC, /* CC_DEST = result, CC_SRC = unused */ + CC_OP_ADD, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_CMPB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_CMPW, /* CC_DEST = result, CC_SRC = source */ + CC_OP_ADDX, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBX, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SHL, /* CC_DEST = source, CC_SRC = shift */ + CC_OP_SHR, /* CC_DEST = source, CC_SRC = shift */ + CC_OP_SAR, /* CC_DEST = source, CC_SRC = shift */ +}; + +#define CCF_C 0x01 +#define CCF_V 0x02 +#define CCF_Z 0x04 +#define CCF_N 0x08 +#define CCF_X 0x01 + +typedef struct m68k_def_t m68k_def_t; + +m68k_def_t *m68k_find_by_name(const char *); +void cpu_m68k_register(CPUM68KState *, m68k_def_t *); + +#define M68K_FPCR_PREC (1 << 6) + +#ifdef CONFIG_USER_ONLY +/* Linux uses 8k pages. */ +#define TARGET_PAGE_BITS 13 +#else +/* Smallest TLB entry size is 1k. */ +#define TARGET_PAGE_BITS 10 +#endif +#include "cpu-all.h" + +#endif diff --git a/target-m68k/exec.h b/target-m68k/exec.h new file mode 100644 index 000000000..ef4adeb39 --- /dev/null +++ b/target-m68k/exec.h @@ -0,0 +1,47 @@ +/* + * m68k execution defines + * + * Copyright (c) 2005-2006 CodeSourcery + * Written by Paul Brook + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "dyngen-exec.h" + +register struct CPUM68KState *env asm(AREG0); +/* This is only used for tb lookup. */ +register uint32_t T0 asm(AREG1); +/* ??? We don't use T1, but common code expects it to exist */ +#define T1 env->t1 + +#include "cpu.h" +#include "exec-all.h" + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu); + + +void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op); +float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1); + +void cpu_loop_exit(void); diff --git a/target-m68k/helper.c b/target-m68k/helper.c new file mode 100644 index 000000000..6b8f18d15 --- /dev/null +++ b/target-m68k/helper.c @@ -0,0 +1,149 @@ +/* + * m68k op helpers + * + * Copyright (c) 2006 CodeSourcery + * Written by Paul Brook + * + * 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 + * 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 + +#include "config.h" +#include "cpu.h" +#include "exec-all.h" + +void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) +{ + int flags; + uint32_t src; + uint32_t dest; + uint32_t tmp; + +#define HIGHBIT 0x80000000u + +#define SET_NZ(x) do { \ + if ((x) == 0) \ + flags |= CCF_Z; \ + else if ((int32_t)(x) < 0) \ + flags |= CCF_N; \ + } while (0) + +#define SET_FLAGS_SUB(type, utype) do { \ + SET_NZ((type)dest); \ + tmp = dest + src; \ + if ((utype) tmp < (utype) src) \ + flags |= CCF_C; \ + if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \ + flags |= CCF_V; \ + } while (0) + + flags = 0; + src = env->cc_src; + dest = env->cc_dest; + switch (cc_op) { + case CC_OP_FLAGS: + flags = dest; + break; + case CC_OP_LOGIC: + SET_NZ(dest); + break; + case CC_OP_ADD: + SET_NZ(dest); + if (dest < src) + flags |= CCF_C; + tmp = dest - src; + if (HIGHBIT & (src ^ dest) & ~(tmp ^ src)) + flags |= CCF_V; + break; + case CC_OP_SUB: + SET_FLAGS_SUB(int32_t, uint32_t); + break; + case CC_OP_CMPB: + SET_FLAGS_SUB(int8_t, uint8_t); + break; + case CC_OP_CMPW: + SET_FLAGS_SUB(int16_t, uint16_t); + break; + case CC_OP_ADDX: + SET_NZ(dest); + if (dest <= src) + flags |= CCF_C; + tmp = dest - src - 1; + if (HIGHBIT & (src ^ dest) & ~(tmp ^ src)) + flags |= CCF_V; + break; + case CC_OP_SUBX: + SET_NZ(dest); + tmp = dest + src + 1; + if (tmp <= src) + flags |= CCF_C; + if (HIGHBIT & (tmp ^ dest) & (tmp ^ src)) + flags |= CCF_V; + break; + case CC_OP_SHL: + if (src >= 32) { + SET_NZ(0); + } else { + tmp = dest << src; + SET_NZ(tmp); + } + if (src && src <= 32 && (dest & (1 << (32 - src)))) + flags |= CCF_C; + break; + case CC_OP_SHR: + if (src >= 32) { + SET_NZ(0); + } else { + tmp = dest >> src; + SET_NZ(tmp); + } + if (src && src <= 32 && ((dest >> (src - 1)) & 1)) + flags |= CCF_C; + break; + case CC_OP_SAR: + if (src >= 32) { + SET_NZ(-1); + } else { + tmp = (int32_t)dest >> src; + SET_NZ(tmp); + } + if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1)) + flags |= CCF_C; + break; + default: + cpu_abort(env, "Bad CC_OP %d", cc_op); + } + env->cc_op = CC_OP_FLAGS; + env->cc_dest = flags; +} + +float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1) +{ + /* ??? This may incorrectly raise exceptions. */ + /* ??? Should flush denormals to zero. */ + float64 res; + res = float64_sub(src0, src1, &env->fp_status); + if (float64_is_nan(res)) { + /* +/-inf compares equal against itself, but sub returns nan. */ + if (!float64_is_nan(src0) + && !float64_is_nan(src1)) { + res = 0; + if (float64_lt_quiet(src0, res, &env->fp_status)) + res = float64_chs(res); + } + } + return res; +} diff --git a/target-m68k/m68k-qreg.h b/target-m68k/m68k-qreg.h new file mode 100644 index 000000000..34bcb02ec --- /dev/null +++ b/target-m68k/m68k-qreg.h @@ -0,0 +1,12 @@ +enum { +#define DEFO32(name, offset) QREG_##name, +#define DEFR(name, reg, mode) QREG_##name, +#define DEFF64(name, offset) QREG_##name, + QREG_NULL, +#include "qregs.def" + TARGET_NUM_QREGS = 0x100 +#undef DEFO32 +#undef DEFR +#undef DEFF64 +}; + diff --git a/target-m68k/op-hacks.h b/target-m68k/op-hacks.h new file mode 100644 index 000000000..c7865638e --- /dev/null +++ b/target-m68k/op-hacks.h @@ -0,0 +1,83 @@ +/* Various hacks to make code written for a dynamic code generator work + with regular QEMU. */ + +static int free_qreg; + +#define QMODE_I32 1 +#define QMODE_F32 1 +#define QMODE_F64 2 + +static inline int gen_new_qreg(int mode) +{ + int qreg; + + qreg = free_qreg; + free_qreg += mode; + if (free_qreg > MAX_QREGS) { + fprintf(stderr, "qreg overflow\n"); + abort(); + } + return qreg + TARGET_NUM_QREGS; +} + +static inline int gen_im32(uint32_t i) +{ + int qreg = gen_new_qreg(QMODE_I32); + gen_op_mov32_im(qreg, i); + return qreg; +} + +static inline void gen_op_ldf32(int dest, int addr) +{ + gen_op_ld32(dest, addr); +} + +static inline void gen_op_stf32(int addr, int dest) +{ + gen_op_st32(addr, dest); +} + +static inline void gen_op_pack_32_f32(int dest, int src) +{ + gen_op_mov32(dest, src); +} + +static inline void gen_op_pack_f32_32(int dest, int src) +{ + gen_op_mov32(dest, src); +} + +static inline void gen_op_flags_set(void) +{ + /* Dummy op. */ +} + +static inline void gen_op_shl_im_cc(int val, int shift) +{ + gen_op_shl_cc(val, gen_im32(shift)); +} + +static inline void gen_op_shr_im_cc(int val, int shift) +{ + gen_op_shr_cc(val, gen_im32(shift)); +} + +static inline void gen_op_sar_im_cc(int val, int shift) +{ + gen_op_sar_cc(val, gen_im32(shift)); +} + +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) (long)(x) +#endif + +static inline void gen_op_goto_tb(int dummy, int n, long tb) +{ + if (n == 0) { + gen_op_goto_tb0(TBPARAM(tb)); + } else { + gen_op_goto_tb1(TBPARAM(tb)); + } +} diff --git a/target-m68k/op.c b/target-m68k/op.c new file mode 100644 index 000000000..489eafeef --- /dev/null +++ b/target-m68k/op.c @@ -0,0 +1,678 @@ +/* + * m68k micro operations + * + * Copyright (c) 2006 CodeSourcery + * Written by Paul Brook + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "exec.h" +#include "m68k-qreg.h" + +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif + +static long qreg_offsets[] = { +#define DEFO32(name, offset) offsetof(CPUState, offset), +#define DEFR(name, reg, mode) -1, +#define DEFF64(name, offset) offsetof(CPUState, offset), + 0, +#include "qregs.def" +}; + +#define CPU_FP_STATUS env->fp_status + +#define RAISE_EXCEPTION(n) do { \ + env->exception_index = n; \ + cpu_loop_exit(); \ + } while(0) + +#define get_op helper_get_op +#define set_op helper_set_op +#define get_opf64 helper_get_opf64 +#define set_opf64 helper_set_opf64 +uint32_t +get_op(int qreg) +{ + if (qreg == QREG_T0) { + return T0; + } else if (qreg < TARGET_NUM_QREGS) { + return *(uint32_t *)(((long)env) + qreg_offsets[qreg]); + } else { + return env->qregs[qreg - TARGET_NUM_QREGS]; + } +} + +void set_op(int qreg, uint32_t val) +{ + if (qreg == QREG_T0) { + T0 = val; + } else if (qreg < TARGET_NUM_QREGS) { + *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val; + } else { + env->qregs[qreg - TARGET_NUM_QREGS] = val; + } +} + +float64 get_opf64(int qreg) +{ + if (qreg < TARGET_NUM_QREGS) { + return *(float64 *)(((long)env) + qreg_offsets[qreg]); + } else { + return *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS]; + } +} + +void set_opf64(int qreg, float64 val) +{ + if (qreg < TARGET_NUM_QREGS) { + *(float64 *)(((long)env) + qreg_offsets[qreg]) = val; + } else { + *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS] = val; + } +} + +#define OP(name) void OPPROTO op_##name (void) + +OP(mov32) +{ + set_op(PARAM1, get_op(PARAM2)); + FORCE_RET(); +} + +OP(mov32_im) +{ + set_op(PARAM1, PARAM2); + FORCE_RET(); +} + +OP(movf64) +{ + set_opf64(PARAM1, get_opf64(PARAM2)); + FORCE_RET(); +} + +OP(zerof64) +{ + set_opf64(PARAM1, 0); + FORCE_RET(); +} + +OP(add32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + set_op(PARAM1, op2 + op3); + FORCE_RET(); +} + +OP(sub32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + set_op(PARAM1, op2 - op3); + FORCE_RET(); +} + +OP(mul32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + set_op(PARAM1, op2 * op3); + FORCE_RET(); +} + +OP(not32) +{ + uint32_t arg = get_op(PARAM2); + set_op(PARAM1, ~arg); + FORCE_RET(); +} + +OP(neg32) +{ + uint32_t arg = get_op(PARAM2); + set_op(PARAM1, -arg); + FORCE_RET(); +} + +OP(bswap32) +{ + uint32_t arg = get_op(PARAM2); + arg = (arg >> 24) | (arg << 24) + | ((arg >> 16) & 0xff00) | ((arg << 16) & 0xff0000); + set_op(PARAM1, arg); + FORCE_RET(); +} + +OP(btest) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + if (op1 & op2) + env->cc_dest &= ~CCF_Z; + else + env->cc_dest |= CCF_Z; + FORCE_RET(); +} + +OP(addx_cc) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + uint32_t res; + if (env->cc_x) { + env->cc_x = (op1 <= op2); + env->cc_op = CC_OP_SUBX; + res = op1 - (op2 + 1); + } else { + env->cc_x = (op1 < op2); + env->cc_op = CC_OP_SUB; + res = op1 - op2; + } + set_op(PARAM1, res); + FORCE_RET(); +} + +OP(subx_cc) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + uint32_t res; + if (env->cc_x) { + res = op1 + op2 + 1; + env->cc_x = (res <= op2); + env->cc_op = CC_OP_ADDX; + } else { + res = op1 + op2; + env->cc_x = (res < op2); + env->cc_op = CC_OP_ADD; + } + set_op(PARAM1, res); + FORCE_RET(); +} + +/* Logic ops. */ + +OP(and32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + set_op(PARAM1, op2 & op3); + FORCE_RET(); +} + +OP(or32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + set_op(PARAM1, op2 | op3); + FORCE_RET(); +} + +OP(xor32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + set_op(PARAM1, op2 ^ op3); + FORCE_RET(); +} + +/* Shifts. */ +OP(shl32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + uint32_t result; + result = op2 << op3; + set_op(PARAM1, result); + FORCE_RET(); +} + +OP(shl_cc) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + uint32_t result; + result = op1 << op2; + set_op(PARAM1, result); + env->cc_x = (op1 << (op2 - 1)) & 1; + FORCE_RET(); +} + +OP(shr32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + uint32_t result; + result = op2 >> op3; + set_op(PARAM1, result); + FORCE_RET(); +} + +OP(shr_cc) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + uint32_t result; + result = op1 >> op2; + set_op(PARAM1, result); + env->cc_x = (op1 >> (op2 - 1)) & 1; + FORCE_RET(); +} + +OP(sar_cc) +{ + int32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + uint32_t result; + result = op1 >> op2; + set_op(PARAM1, result); + env->cc_x = (op1 >> (op2 - 1)) & 1; + FORCE_RET(); +} + +/* Value extend. */ + +OP(ext8u32) +{ + uint32_t op2 = get_op(PARAM2); + set_op(PARAM1, (uint8_t)op2); + FORCE_RET(); +} + +OP(ext8s32) +{ + uint32_t op2 = get_op(PARAM2); + set_op(PARAM1, (int8_t)op2); + FORCE_RET(); +} + +OP(ext16u32) +{ + uint32_t op2 = get_op(PARAM2); + set_op(PARAM1, (uint16_t)op2); + FORCE_RET(); +} + +OP(ext16s32) +{ + uint32_t op2 = get_op(PARAM2); + set_op(PARAM1, (int16_t)op2); + FORCE_RET(); +} + +/* Load/store ops. */ +OP(ld8u32) +{ + uint32_t addr = get_op(PARAM2); + set_op(PARAM1, ldub(addr)); + FORCE_RET(); +} + +OP(ld8s32) +{ + uint32_t addr = get_op(PARAM2); + set_op(PARAM1, ldsb(addr)); + FORCE_RET(); +} + +OP(ld16u32) +{ + uint32_t addr = get_op(PARAM2); + set_op(PARAM1, lduw(addr)); + FORCE_RET(); +} + +OP(ld16s32) +{ + uint32_t addr = get_op(PARAM2); + set_op(PARAM1, ldsw(addr)); + FORCE_RET(); +} + +OP(ld32) +{ + uint32_t addr = get_op(PARAM2); + set_op(PARAM1, ldl(addr)); + FORCE_RET(); +} + +OP(st8) +{ + uint32_t addr = get_op(PARAM1); + stb(addr, get_op(PARAM2)); + FORCE_RET(); +} + +OP(st16) +{ + uint32_t addr = get_op(PARAM1); + stw(addr, get_op(PARAM2)); + FORCE_RET(); +} + +OP(st32) +{ + uint32_t addr = get_op(PARAM1); + stl(addr, get_op(PARAM2)); + FORCE_RET(); +} + +OP(ldf64) +{ + uint32_t addr = get_op(PARAM2); + set_opf64(PARAM1, ldfq(addr)); + FORCE_RET(); +} + +OP(stf64) +{ + uint32_t addr = get_op(PARAM1); + stfq(addr, get_opf64(PARAM2)); + FORCE_RET(); +} + +OP(flush_flags) +{ + int cc_op = PARAM1; + if (cc_op == CC_OP_DYNAMIC) + cc_op = env->cc_op; + cpu_m68k_flush_flags(env, cc_op); + FORCE_RET(); +} + +OP(divu) +{ + uint32_t num; + uint32_t den; + uint32_t quot; + uint32_t rem; + uint32_t flags; + + num = env->div1; + den = env->div2; + /* ??? This needs to make sure the throwing location is accurate. */ + if (den == 0) + RAISE_EXCEPTION(EXCP_DIV0); + quot = num / den; + rem = num % den; + flags = 0; + if (PARAM1 && quot > 0xffff) + flags |= CCF_V; + if (quot == 0) + flags |= CCF_Z; + else if ((int32_t)quot < 0) + flags |= CCF_N; + env->div1 = quot; + env->div2 = rem; + env->cc_dest = flags; + FORCE_RET(); +} + +OP(divs) +{ + int32_t num; + int32_t den; + int32_t quot; + int32_t rem; + int32_t flags; + + num = env->div1; + den = env->div2; + if (den == 0) + RAISE_EXCEPTION(EXCP_DIV0); + quot = num / den; + rem = num % den; + flags = 0; + if (PARAM1 && quot != (int16_t)quot) + flags |= CCF_V; + if (quot == 0) + flags |= CCF_Z; + else if (quot < 0) + flags |= CCF_N; + env->div1 = quot; + env->div2 = rem; + env->cc_dest = flags; + FORCE_RET(); +} + +OP(raise_exception) +{ + RAISE_EXCEPTION(PARAM1); + FORCE_RET(); +} + +/* Floating point comparison sets flags differently to other instructions. */ + +OP(sub_cmpf64) +{ + float64 src0; + float64 src1; + src0 = get_opf64(PARAM2); + src1 = get_opf64(PARAM3); + set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1)); + FORCE_RET(); +} + +OP(update_xflag_tst) +{ + uint32_t op1 = get_op(PARAM1); + env->cc_x = op1; + FORCE_RET(); +} + +OP(update_xflag_lt) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + env->cc_x = (op1 < op2); + FORCE_RET(); +} + +OP(get_xflag) +{ + set_op(PARAM1, env->cc_x); + FORCE_RET(); +} + +OP(logic_cc) +{ + uint32_t op1 = get_op(PARAM1); + env->cc_dest = op1; + FORCE_RET(); +} + +OP(update_cc_add) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + env->cc_dest = op1; + env->cc_src = op2; + FORCE_RET(); +} + +OP(fp_result) +{ + env->fp_result = get_opf64(PARAM1); + FORCE_RET(); +} + +OP(jmp) +{ + GOTO_LABEL_PARAM(1); +} + +/* These ops involve a function call, which probably requires a stack frame + and breaks things on some hosts. */ +OP(jmp_z32) +{ + uint32_t arg = get_op(PARAM1); + if (arg == 0) + GOTO_LABEL_PARAM(2); + FORCE_RET(); +} + +OP(jmp_nz32) +{ + uint32_t arg = get_op(PARAM1); + if (arg != 0) + GOTO_LABEL_PARAM(2); + FORCE_RET(); +} + +OP(jmp_s32) +{ + int32_t arg = get_op(PARAM1); + if (arg < 0) + GOTO_LABEL_PARAM(2); + FORCE_RET(); +} + +OP(jmp_ns32) +{ + int32_t arg = get_op(PARAM1); + if (arg >= 0) + GOTO_LABEL_PARAM(2); + FORCE_RET(); +} + +void OPPROTO op_goto_tb0(void) +{ + GOTO_TB(op_goto_tb0, PARAM1, 0); +} + +void OPPROTO op_goto_tb1(void) +{ + GOTO_TB(op_goto_tb1, PARAM1, 1); +} + +OP(exit_tb) +{ + EXIT_TB(); +} + + +/* Floating point. */ +OP(f64_to_i32) +{ + set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(f64_to_f32) +{ + union { + float32 f; + uint32_t i; + } u; + u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS); + set_op(PARAM1, u.i); + FORCE_RET(); +} + +OP(i32_to_f64) +{ + set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(f32_to_f64) +{ + union { + float32 f; + uint32_t i; + } u; + u.i = get_op(PARAM2); + set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(absf64) +{ + float64 op0 = get_opf64(PARAM2); + set_opf64(PARAM1, float64_abs(op0)); + FORCE_RET(); +} + +OP(chsf64) +{ + float64 op0 = get_opf64(PARAM2); + set_opf64(PARAM1, float64_chs(op0)); + FORCE_RET(); +} + +OP(sqrtf64) +{ + float64 op0 = get_opf64(PARAM2); + set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(addf64) +{ + float64 op0 = get_opf64(PARAM2); + float64 op1 = get_opf64(PARAM3); + set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(subf64) +{ + float64 op0 = get_opf64(PARAM2); + float64 op1 = get_opf64(PARAM3); + set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(mulf64) +{ + float64 op0 = get_opf64(PARAM2); + float64 op1 = get_opf64(PARAM3); + set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(divf64) +{ + float64 op0 = get_opf64(PARAM2); + float64 op1 = get_opf64(PARAM3); + set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(iround_f64) +{ + float64 op0 = get_opf64(PARAM2); + set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(itrunc_f64) +{ + float64 op0 = get_opf64(PARAM2); + set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS)); + FORCE_RET(); +} + +OP(compare_quietf64) +{ + float64 op0 = get_opf64(PARAM2); + float64 op1 = get_opf64(PARAM3); + set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS)); + FORCE_RET(); +} diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def new file mode 100644 index 000000000..d8c194408 --- /dev/null +++ b/target-m68k/qregs.def @@ -0,0 +1,34 @@ +DEFO32(D0, dregs[0]) +DEFO32(D1, dregs[1]) +DEFO32(D2, dregs[2]) +DEFO32(D3, dregs[3]) +DEFO32(D4, dregs[4]) +DEFO32(D5, dregs[5]) +DEFO32(D6, dregs[6]) +DEFO32(D7, dregs[7]) +DEFO32(A0, aregs[0]) +DEFO32(A1, aregs[1]) +DEFO32(A2, aregs[2]) +DEFO32(A3, aregs[3]) +DEFO32(A4, aregs[4]) +DEFO32(A5, aregs[5]) +DEFO32(A6, aregs[6]) +DEFO32(SP, aregs[7]) /* A7 */ +DEFF64(F0, fregs[0]) +DEFF64(F1, fregs[1]) +DEFF64(F2, fregs[2]) +DEFF64(F3, fregs[3]) +DEFF64(F4, fregs[4]) +DEFF64(F5, fregs[5]) +DEFF64(F6, fregs[6]) +DEFF64(F7, fregs[7]) +DEFF64(FP_RESULT, fp_result) +DEFO32(PC, pc) +DEFO32(CC_OP, cc_op) +DEFR(T0, AREG1, QMODE_I32) +DEFO32(CC_DEST, cc_dest) +DEFO32(CC_SRC, cc_src) +DEFO32(CC_X, cc_x) +DEFO32(DIV1, div1) +DEFO32(DIV2, div2) +DEFO32(EXCEPTION, exception_index) diff --git a/target-m68k/translate.c b/target-m68k/translate.c new file mode 100644 index 000000000..10728f97d --- /dev/null +++ b/target-m68k/translate.c @@ -0,0 +1,2759 @@ +/* + * m68k translation + * + * Copyright (c) 2005-2006 CodeSourcery + * Written by Paul Brook + * + * 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 + * 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 +#include +#include +#include +#include + +#include "config.h" +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "m68k-qreg.h" + +static inline void qemu_assert(int cond, const char *msg) +{ + if (!cond) { + fprintf (stderr, "badness: %s\n", msg); + abort(); + } +} + +/* internal defines */ +typedef struct DisasContext { + target_ulong pc; + int is_jmp; + int cc_op; + uint32_t fpcr; + struct TranslationBlock *tb; + int singlestep_enabled; +} DisasContext; + +#define DISAS_JUMP_NEXT 4 + +/* XXX: move that elsewhere */ +/* ??? Fix exceptions. */ +static void *gen_throws_exception; +#define gen_last_qop NULL + +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; +extern FILE *logfile; +extern int loglevel; + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +#include "gen-op.h" +#include "op-hacks.h" + +#define OS_BYTE 0 +#define OS_WORD 1 +#define OS_LONG 2 +#define OS_SINGLE 4 +#define OS_DOUBLE 5 + +#define DREG(insn, pos) (((insn >> pos) & 7) + QREG_D0) +#define AREG(insn, pos) (((insn >> pos) & 7) + QREG_A0) +#define FREG(insn, pos) (((insn >> pos) & 7) + QREG_F0) + +#define M68K_INSN_CF_A (1 << 0) +#define M68K_INSN_CF_B (1 << 1) +#define M68K_INSN_CF_C (1 << 2) +#define M68K_INSN_CF_MAC (1 << 3) +#define M68K_INSN_CF_EMAC (1 << 4) +#define M68K_INSN_CF_FPU (1 << 5) + +struct m68k_def_t { + const char * name; + uint32_t insns; +}; + +static m68k_def_t m68k_cpu_defs[] = { + {"m5206", M68K_INSN_CF_A}, + {"cfv4e", M68K_INSN_CF_A | M68K_INSN_CF_B | M68K_INSN_CF_C + | M68K_INSN_CF_MAC | M68K_INSN_CF_EMAC | M68K_INSN_CF_FPU}, + {NULL, 0}, +}; + +typedef void (*disas_proc)(DisasContext *, uint16_t); + +#define DISAS_INSN(name) \ + static void disas_##name (DisasContext *s, uint16_t insn) + +/* Generate a load from the specified address. Narrow values are + sign extended to full register width. */ +static inline int gen_load(int opsize, int addr, int sign) +{ + int tmp; + switch(opsize) { + case OS_BYTE: + tmp = gen_new_qreg(QMODE_I32); + if (sign) + gen_op_ld8s32(tmp, addr); + else + gen_op_ld8u32(tmp, addr); + break; + case OS_WORD: + tmp = gen_new_qreg(QMODE_I32); + if (sign) + gen_op_ld16s32(tmp, addr); + else + gen_op_ld16u32(tmp, addr); + break; + case OS_LONG: + tmp = gen_new_qreg(QMODE_I32); + gen_op_ld32(tmp, addr); + break; + case OS_SINGLE: + tmp = gen_new_qreg(QMODE_F32); + gen_op_ldf32(tmp, addr); + break; + case OS_DOUBLE: + tmp = gen_new_qreg(QMODE_F64); + gen_op_ldf64(tmp, addr); + break; + default: + qemu_assert(0, "bad load size"); + } + gen_throws_exception = gen_last_qop; + return tmp; +} + +/* Generate a store. */ +static inline void gen_store(int opsize, int addr, int val) +{ + switch(opsize) { + case OS_BYTE: + gen_op_st8(addr, val); + break; + case OS_WORD: + gen_op_st16(addr, val); + break; + case OS_LONG: + gen_op_st32(addr, val); + break; + case OS_SINGLE: + gen_op_stf32(addr, val); + break; + case OS_DOUBLE: + gen_op_stf64(addr, val); + break; + default: + qemu_assert(0, "bad store size"); + } + gen_throws_exception = gen_last_qop; +} + +/* Generate an unsigned load if VAL is 0 a signed load if val is -1, + otherwise generate a store. */ +static int gen_ldst(int opsize, int addr, int val) +{ + if (val > 0) { + gen_store(opsize, addr, val); + return 0; + } else { + return gen_load(opsize, addr, val != 0); + } +} + +/* Handle a base + index + displacement effective addresss. A base of + -1 means pc-relative. */ +static int gen_lea_indexed(DisasContext *s, int opsize, int base) +{ + int scale; + uint32_t offset; + uint16_t ext; + int add; + int tmp; + + offset = s->pc; + ext = lduw(s->pc); + s->pc += 2; + tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0); + /* ??? Check W/L bit. */ + scale = (ext >> 9) & 3; + if (scale == 0) { + add = tmp; + } else { + add = gen_new_qreg(QMODE_I32); + gen_op_shl32(add, tmp, gen_im32(scale)); + } + tmp = gen_new_qreg(QMODE_I32); + if (base != -1) { + gen_op_add32(tmp, base, gen_im32((int8_t)ext)); + gen_op_add32(tmp, tmp, add); + } else { + gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext)); + } + return tmp; +} + +/* Read a 32-bit immediate constant. */ +static inline uint32_t read_im32(DisasContext *s) +{ + uint32_t im; + im = ((uint32_t)lduw(s->pc)) << 16; + s->pc += 2; + im |= lduw(s->pc); + s->pc += 2; + return im; +} + + +/* Update the CPU env CC_OP state. */ +static inline void gen_flush_cc_op(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_mov32(QREG_CC_OP, gen_im32(s->cc_op)); +} + +/* Evaluate all the CC flags. */ +static inline void gen_flush_flags(DisasContext *s) +{ + if (s->cc_op == CC_OP_FLAGS) + return; + gen_op_flush_flags(s->cc_op); + s->cc_op = CC_OP_FLAGS; +} + +static inline int opsize_bytes(int opsize) +{ + switch (opsize) { + case OS_BYTE: return 1; + case OS_WORD: return 2; + case OS_LONG: return 4; + case OS_SINGLE: return 4; + case OS_DOUBLE: return 8; + default: + qemu_assert(0, "bad operand size"); + } +} + +/* Assign value to a register. If the width is less than the register width + only the low part of the register is set. */ +static void gen_partset_reg(int opsize, int reg, int val) +{ + int tmp; + switch (opsize) { + case OS_BYTE: + gen_op_and32(reg, reg, gen_im32(0xffffff00)); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, val, gen_im32(0xff)); + gen_op_or32(reg, reg, tmp); + break; + case OS_WORD: + gen_op_and32(reg, reg, gen_im32(0xffff0000)); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, val, gen_im32(0xffff)); + gen_op_or32(reg, reg, tmp); + break; + case OS_LONG: + gen_op_mov32(reg, val); + break; + case OS_SINGLE: + gen_op_pack_32_f32(reg, val); + break; + default: + qemu_assert(0, "Bad operand size"); + break; + } +} + +/* Sign or zero extend a value. */ +static inline int gen_extend(int val, int opsize, int sign) +{ + int tmp; + + switch (opsize) { + case OS_BYTE: + tmp = gen_new_qreg(QMODE_I32); + if (sign) + gen_op_ext8s32(tmp, val); + else + gen_op_ext8u32(tmp, val); + break; + case OS_WORD: + tmp = gen_new_qreg(QMODE_I32); + if (sign) + gen_op_ext16s32(tmp, val); + else + gen_op_ext16u32(tmp, val); + break; + case OS_LONG: + tmp = val; + break; + case OS_SINGLE: + tmp = gen_new_qreg(QMODE_F32); + gen_op_pack_f32_32(tmp, val); + break; + default: + qemu_assert(0, "Bad operand size"); + } + return tmp; +} + +/* Generate code for an "effective address". Does not adjust the base + register for autoincrememnt addressing modes. */ +static int gen_lea(DisasContext *s, uint16_t insn, int opsize) +{ + int reg; + int tmp; + uint16_t ext; + uint32_t offset; + + reg = insn & 7; + switch ((insn >> 3) & 7) { + case 0: /* Data register direct. */ + case 1: /* Address register direct. */ + /* ??? generate bad addressing mode fault. */ + qemu_assert(0, "invalid addressing mode"); + case 2: /* Indirect register */ + case 3: /* Indirect postincrement. */ + reg += QREG_A0; + return reg; + case 4: /* Indirect predecrememnt. */ + reg += QREG_A0; + tmp = gen_new_qreg(QMODE_I32); + gen_op_sub32(tmp, reg, gen_im32(opsize_bytes(opsize))); + return tmp; + case 5: /* Indirect displacement. */ + reg += QREG_A0; + tmp = gen_new_qreg(QMODE_I32); + ext = lduw(s->pc); + s->pc += 2; + gen_op_add32(tmp, reg, gen_im32((int16_t)ext)); + return tmp; + case 6: /* Indirect index + displacement. */ + reg += QREG_A0; + return gen_lea_indexed(s, opsize, reg); + case 7: /* Other */ + switch (reg) { + case 0: /* Absolute short. */ + offset = ldsw(s->pc); + s->pc += 2; + return gen_im32(offset); + case 1: /* Absolute long. */ + offset = read_im32(s); + return gen_im32(offset); + case 2: /* pc displacement */ + tmp = gen_new_qreg(QMODE_I32); + offset = s->pc; + offset += ldsw(s->pc); + s->pc += 2; + return gen_im32(offset); + case 3: /* pc index+displacement. */ + return gen_lea_indexed(s, opsize, -1); + case 4: /* Immediate. */ + default: + /* ??? generate bad addressing mode fault. */ + qemu_assert(0, "invalid addressing mode"); + } + } + /* Should never happen. */ + return -1; +} + +/* Helper function for gen_ea. Reuse the computed address between the + for read/write operands. */ +static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize, + int val, int *addrp) +{ + int tmp; + + if (addrp && val > 0) { + tmp = *addrp; + } else { + tmp = gen_lea(s, insn, opsize); + if (addrp) + *addrp = tmp; + } + return gen_ldst(opsize, tmp, val); +} + +/* Generate code to load/store a value ito/from an EA. If VAL > 0 this is + a write otherwise it is a read (0 == sign extend, -1 == zero extend). + ADDRP is non-null for readwrite operands. */ +static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, + int *addrp) +{ + int reg; + int result; + uint32_t offset; + + reg = insn & 7; + switch ((insn >> 3) & 7) { + case 0: /* Data register direct. */ + reg += QREG_D0; + if (val > 0) { + gen_partset_reg(opsize, reg, val); + return 0; + } else { + return gen_extend(reg, opsize, val); + } + case 1: /* Address register direct. */ + reg += QREG_A0; + if (val > 0) { + gen_op_mov32(reg, val); + return 0; + } else { + return gen_extend(reg, opsize, val); + } + case 2: /* Indirect register */ + reg += QREG_A0; + return gen_ldst(opsize, reg, val); + case 3: /* Indirect postincrement. */ + reg += QREG_A0; + result = gen_ldst(opsize, reg, val); + /* ??? This is not exception safe. The instruction may still + fault after this point. */ + if (val > 0 || !addrp) + gen_op_add32(reg, reg, gen_im32(opsize_bytes(opsize))); + return result; + case 4: /* Indirect predecrememnt. */ + { + int tmp; + if (addrp && val > 0) { + tmp = *addrp; + } else { + tmp = gen_lea(s, insn, opsize); + if (addrp) + *addrp = tmp; + } + result = gen_ldst(opsize, tmp, val); + /* ??? This is not exception safe. The instruction may still + fault after this point. */ + if (val > 0 || !addrp) { + reg += QREG_A0; + gen_op_mov32(reg, tmp); + } + } + return result; + case 5: /* Indirect displacement. */ + case 6: /* Indirect index + displacement. */ + return gen_ea_once(s, insn, opsize, val, addrp); + case 7: /* Other */ + switch (reg) { + case 0: /* Absolute short. */ + case 1: /* Absolute long. */ + case 2: /* pc displacement */ + case 3: /* pc index+displacement. */ + return gen_ea_once(s, insn, opsize, val, addrp); + case 4: /* Immediate. */ + /* Sign extend values for consistency. */ + switch (opsize) { + case OS_BYTE: + if (val) + offset = ldsb(s->pc + 1); + else + offset = ldub(s->pc + 1); + s->pc += 2; + break; + case OS_WORD: + if (val) + offset = ldsw(s->pc); + else + offset = lduw(s->pc); + s->pc += 2; + break; + case OS_LONG: + offset = read_im32(s); + break; + default: + qemu_assert(0, "Bad immediate operand"); + } + return gen_im32(offset); + default: + qemu_assert(0, "invalid addressing mode"); + } + } + /* Should never happen. */ + return -1; +} + +static void gen_logic_cc(DisasContext *s, int val) +{ + gen_op_logic_cc(val); + s->cc_op = CC_OP_LOGIC; +} + +static void gen_jmpcc(DisasContext *s, int cond, int l1) +{ + int tmp; + + gen_flush_flags(s); + switch (cond) { + case 0: /* T */ + gen_op_jmp(l1); + break; + case 1: /* F */ + break; + case 2: /* HI (!C && !Z) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z)); + gen_op_jmp_z32(tmp, l1); + break; + case 3: /* LS (C || Z) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z)); + gen_op_jmp_nz32(tmp, l1); + break; + case 4: /* CC (!C) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C)); + gen_op_jmp_z32(tmp, l1); + break; + case 5: /* CS (C) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C)); + gen_op_jmp_nz32(tmp, l1); + break; + case 6: /* NE (!Z) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z)); + gen_op_jmp_z32(tmp, l1); + break; + case 7: /* EQ (Z) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z)); + gen_op_jmp_nz32(tmp, l1); + break; + case 8: /* VC (!V) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V)); + gen_op_jmp_z32(tmp, l1); + break; + case 9: /* VS (V) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V)); + gen_op_jmp_nz32(tmp, l1); + break; + case 10: /* PL (!N) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N)); + gen_op_jmp_z32(tmp, l1); + break; + case 11: /* MI (N) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N)); + gen_op_jmp_nz32(tmp, l1); + break; + case 12: /* GE (!(N ^ V)) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2)); + gen_op_xor32(tmp, tmp, QREG_CC_DEST); + gen_op_and32(tmp, tmp, gen_im32(CCF_V)); + gen_op_jmp_z32(tmp, l1); + break; + case 13: /* LT (N ^ V) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2)); + gen_op_xor32(tmp, tmp, QREG_CC_DEST); + gen_op_and32(tmp, tmp, gen_im32(CCF_V)); + gen_op_jmp_nz32(tmp, l1); + break; + case 14: /* GT (!(Z || (N ^ V))) */ + { + int l2; + l2 = gen_new_label(); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z)); + gen_op_jmp_nz32(tmp, l2); + tmp = gen_new_qreg(QMODE_I32); + gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2)); + gen_op_xor32(tmp, tmp, QREG_CC_DEST); + gen_op_and32(tmp, tmp, gen_im32(CCF_V)); + gen_op_jmp_nz32(tmp, l2); + gen_op_jmp(l1); + gen_set_label(l2); + } + break; + case 15: /* LE (Z || (N ^ V)) */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z)); + gen_op_jmp_nz32(tmp, l1); + tmp = gen_new_qreg(QMODE_I32); + gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2)); + gen_op_xor32(tmp, tmp, QREG_CC_DEST); + gen_op_and32(tmp, tmp, gen_im32(CCF_V)); + gen_op_jmp_nz32(tmp, l1); + break; + default: + /* Should ever happen. */ + abort(); + } +} + +DISAS_INSN(scc) +{ + int l1; + int cond; + int reg; + + l1 = gen_new_label(); + cond = (insn >> 8) & 0xf; + reg = DREG(insn, 0); + gen_op_and32(reg, reg, gen_im32(0xffffff00)); + gen_jmpcc(s, cond ^ 1, l1); + gen_op_or32(reg, reg, gen_im32(0xff)); + gen_set_label(l1); +} + +/* Generate a jump to to the address in qreg DEST. */ +static void gen_jmp(DisasContext *s, int dest) +{ + gen_flush_cc_op(s); + gen_op_mov32(QREG_PC, dest); + s->is_jmp = DISAS_JUMP; +} + +static void gen_exception(DisasContext *s, uint32_t where, int nr) +{ + gen_flush_cc_op(s); + gen_jmp(s, gen_im32(where)); + gen_op_raise_exception(nr); +} + +/* Generate a jump to an immediate address. */ +static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) +{ + TranslationBlock *tb; + + tb = s->tb; + if (__builtin_expect (s->singlestep_enabled, 0)) { + gen_exception(s, dest, EXCP_DEBUG); + } else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || + (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + gen_op_goto_tb(0, n, (long)tb); + gen_op_mov32(QREG_PC, gen_im32(dest)); + gen_op_mov32(QREG_T0, gen_im32((long)tb + n)); + gen_op_exit_tb(); + } else { + gen_jmp(s, gen_im32(dest)); + gen_op_mov32(QREG_T0, gen_im32(0)); + gen_op_exit_tb(); + } + s->is_jmp = DISAS_TB_JUMP; +} + +DISAS_INSN(undef_mac) +{ + gen_exception(s, s->pc - 2, EXCP_LINEA); +} + +DISAS_INSN(undef_fpu) +{ + gen_exception(s, s->pc - 2, EXCP_LINEF); +} + +DISAS_INSN(undef) +{ + gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED); + cpu_abort(cpu_single_env, "Illegal instruction: %04x @ %08x", + insn, s->pc - 2); +} + +DISAS_INSN(mulw) +{ + int reg; + int tmp; + int src; + int sign; + + sign = (insn & 0x100) != 0; + reg = DREG(insn, 9); + tmp = gen_new_qreg(QMODE_I32); + if (sign) + gen_op_ext16s32(tmp, reg); + else + gen_op_ext16u32(tmp, reg); + src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL); + gen_op_mul32(tmp, tmp, src); + gen_op_mov32(reg, tmp); + /* Unlike m68k, coldfire always clears the overflow bit. */ + gen_logic_cc(s, tmp); +} + +DISAS_INSN(divw) +{ + int reg; + int tmp; + int src; + int sign; + + sign = (insn & 0x100) != 0; + reg = DREG(insn, 9); + if (sign) { + gen_op_ext16s32(QREG_DIV1, reg); + } else { + gen_op_ext16u32(QREG_DIV1, reg); + } + src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL); + gen_op_mov32(QREG_DIV2, src); + if (sign) { + gen_op_divs(1); + } else { + gen_op_divu(1); + } + + tmp = gen_new_qreg(QMODE_I32); + src = gen_new_qreg(QMODE_I32); + gen_op_ext16u32(tmp, QREG_DIV1); + gen_op_shl32(src, QREG_DIV2, gen_im32(16)); + gen_op_or32(reg, tmp, src); + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; +} + +DISAS_INSN(divl) +{ + int num; + int den; + int reg; + uint16_t ext; + + ext = lduw(s->pc); + s->pc += 2; + if (ext & 0x87f8) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + return; + } + num = DREG(ext, 12); + reg = DREG(ext, 0); + gen_op_mov32(QREG_DIV1, num); + den = gen_ea(s, insn, OS_LONG, 0, NULL); + gen_op_mov32(QREG_DIV2, den); + if (ext & 0x0800) { + gen_op_divs(0); + } else { + gen_op_divu(0); + } + if (num == reg) { + /* div */ + gen_op_mov32 (reg, QREG_DIV1); + } else { + /* rem */ + gen_op_mov32 (reg, QREG_DIV2); + } + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; +} + +DISAS_INSN(addsub) +{ + int reg; + int dest; + int src; + int tmp; + int addr; + int add; + + add = (insn & 0x4000) != 0; + reg = DREG(insn, 9); + dest = gen_new_qreg(QMODE_I32); + if (insn & 0x100) { + tmp = gen_ea(s, insn, OS_LONG, 0, &addr); + src = reg; + } else { + tmp = reg; + src = gen_ea(s, insn, OS_LONG, 0, NULL); + } + if (add) { + gen_op_add32(dest, tmp, src); + gen_op_update_xflag_lt(dest, src); + s->cc_op = CC_OP_ADD; + } else { + gen_op_update_xflag_lt(tmp, src); + gen_op_sub32(dest, tmp, src); + s->cc_op = CC_OP_SUB; + } + gen_op_update_cc_add(dest, src); + if (insn & 0x100) { + gen_ea(s, insn, OS_LONG, dest, &addr); + } else { + gen_op_mov32(reg, dest); + } +} + + +/* Reverse the order of the bits in REG. */ +DISAS_INSN(bitrev) +{ + int val; + int tmp1; + int tmp2; + int reg; + + val = gen_new_qreg(QMODE_I32); + tmp1 = gen_new_qreg(QMODE_I32); + tmp2 = gen_new_qreg(QMODE_I32); + reg = DREG(insn, 0); + gen_op_mov32(val, reg); + /* Reverse bits within each nibble. */ + gen_op_shl32(tmp1, val, gen_im32(3)); + gen_op_and32(tmp1, tmp1, gen_im32(0x88888888)); + gen_op_shl32(tmp2, val, gen_im32(1)); + gen_op_and32(tmp2, tmp2, gen_im32(0x44444444)); + gen_op_or32(tmp1, tmp1, tmp2); + gen_op_shr32(tmp2, val, gen_im32(1)); + gen_op_and32(tmp2, tmp2, gen_im32(0x22222222)); + gen_op_or32(tmp1, tmp1, tmp2); + gen_op_shr32(tmp2, val, gen_im32(3)); + gen_op_and32(tmp2, tmp2, gen_im32(0x11111111)); + gen_op_or32(tmp1, tmp1, tmp2); + /* Reverse nibbles withing bytes. */ + gen_op_shl32(val, tmp1, gen_im32(4)); + gen_op_and32(val, val, gen_im32(0xf0f0f0f0)); + gen_op_shr32(tmp2, tmp1, gen_im32(4)); + gen_op_and32(tmp2, tmp2, gen_im32(0x0f0f0f0f)); + gen_op_or32(val, val, tmp2); + /* Reverse bytes. */ + gen_op_bswap32(reg, val); + gen_op_mov32(reg, val); +} + +DISAS_INSN(bitop_reg) +{ + int opsize; + int op; + int src1; + int src2; + int tmp; + int addr; + int dest; + + if ((insn & 0x38) != 0) + opsize = OS_BYTE; + else + opsize = OS_LONG; + op = (insn >> 6) & 3; + src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL); + src2 = DREG(insn, 9); + dest = gen_new_qreg(QMODE_I32); + + gen_flush_flags(s); + tmp = gen_new_qreg(QMODE_I32); + if (opsize == OS_BYTE) + gen_op_and32(tmp, src2, gen_im32(7)); + else + gen_op_and32(tmp, src2, gen_im32(31)); + src2 = tmp; + tmp = gen_new_qreg(QMODE_I32); + gen_op_shl32(tmp, gen_im32(1), src2); + + gen_op_btest(src1, tmp); + switch (op) { + case 1: /* bchg */ + gen_op_xor32(dest, src1, tmp); + break; + case 2: /* bclr */ + gen_op_not32(tmp, tmp); + gen_op_and32(dest, src1, tmp); + break; + case 3: /* bset */ + gen_op_or32(dest, src1, tmp); + break; + default: /* btst */ + break; + } + if (op) + gen_ea(s, insn, opsize, dest, &addr); +} + +DISAS_INSN(sats) +{ + int reg; + int tmp; + int l1; + + reg = DREG(insn, 0); + tmp = gen_new_qreg(QMODE_I32); + gen_flush_flags(s); + gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V)); + l1 = gen_new_label(); + gen_op_jmp_z32(tmp, l1); + tmp = gen_new_qreg(QMODE_I32); + gen_op_shr32(tmp, reg, gen_im32(31)); + gen_op_xor32(tmp, tmp, gen_im32(0x80000000)); + gen_op_mov32(reg, tmp); + gen_set_label(l1); + gen_logic_cc(s, tmp); +} + +static void gen_push(int val) +{ + int tmp; + + tmp = gen_new_qreg(QMODE_I32); + gen_op_sub32(tmp, QREG_SP, gen_im32(4)); + gen_store(OS_LONG, tmp, val); + gen_op_mov32(QREG_SP, tmp); +} + +DISAS_INSN(movem) +{ + int addr; + int i; + uint16_t mask; + int reg; + int tmp; + int is_load; + + mask = lduw(s->pc); + s->pc += 2; + tmp = gen_lea(s, insn, OS_LONG); + addr = gen_new_qreg(QMODE_I32); + gen_op_mov32(addr, tmp); + is_load = ((insn & 0x0400) != 0); + for (i = 0; i < 16; i++, mask >>= 1) { + if (mask & 1) { + if (i < 8) + reg = DREG(i, 0); + else + reg = AREG(i, 0); + if (is_load) { + tmp = gen_load(OS_LONG, addr, 0); + gen_op_mov32(reg, tmp); + } else { + gen_store(OS_LONG, addr, reg); + } + if (mask != 1) + gen_op_add32(addr, addr, gen_im32(4)); + } + } +} + +DISAS_INSN(bitop_im) +{ + int opsize; + int op; + int src1; + uint32_t mask; + int bitnum; + int tmp; + int addr; + int dest; + + if ((insn & 0x38) != 0) + opsize = OS_BYTE; + else + opsize = OS_LONG; + op = (insn >> 6) & 3; + + bitnum = lduw(s->pc); + s->pc += 2; + if (bitnum & 0xff00) { + disas_undef(s, insn); + return; + } + + src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL); + + gen_flush_flags(s); + tmp = gen_new_qreg(QMODE_I32); + if (opsize == OS_BYTE) + bitnum &= 7; + else + bitnum &= 31; + mask = 1 << bitnum; + + gen_op_btest(src1, gen_im32(mask)); + if (op) + dest = gen_new_qreg(QMODE_I32); + else + dest = -1; + + switch (op) { + case 1: /* bchg */ + gen_op_xor32(dest, src1, gen_im32(mask)); + break; + case 2: /* bclr */ + gen_op_and32(dest, src1, gen_im32(~mask)); + break; + case 3: /* bset */ + gen_op_or32(dest, src1, gen_im32(mask)); + break; + default: /* btst */ + break; + } + if (op) + gen_ea(s, insn, opsize, dest, &addr); +} + +DISAS_INSN(arith_im) +{ + int op; + int src1; + int dest; + int src2; + int addr; + + op = (insn >> 9) & 7; + src1 = gen_ea(s, insn, OS_LONG, 0, (op == 6) ? NULL : &addr); + src2 = gen_im32(read_im32(s)); + dest = gen_new_qreg(QMODE_I32); + switch (op) { + case 0: /* ori */ + gen_op_or32(dest, src1, src2); + gen_logic_cc(s, dest); + break; + case 1: /* andi */ + gen_op_and32(dest, src1, src2); + gen_logic_cc(s, dest); + break; + case 2: /* subi */ + gen_op_mov32(dest, src1); + gen_op_update_xflag_lt(dest, src2); + gen_op_sub32(dest, dest, src2); + gen_op_update_cc_add(dest, src2); + s->cc_op = CC_OP_SUB; + break; + case 3: /* addi */ + gen_op_mov32(dest, src1); + gen_op_add32(dest, dest, src2); + gen_op_update_cc_add(dest, src2); + gen_op_update_xflag_lt(dest, src2); + s->cc_op = CC_OP_ADD; + break; + case 5: /* eori */ + gen_op_xor32(dest, src1, src2); + gen_logic_cc(s, dest); + break; + case 6: /* cmpi */ + gen_op_mov32(dest, src1); + gen_op_sub32(dest, dest, src2); + gen_op_update_cc_add(dest, src2); + s->cc_op = CC_OP_SUB; + break; + default: + abort(); + } + if (op != 6) { + gen_ea(s, insn, OS_LONG, dest, &addr); + } +} + +DISAS_INSN(byterev) +{ + int reg; + + reg = DREG(insn, 0); + gen_op_bswap32(reg, reg); +} + +DISAS_INSN(move) +{ + int src; + int dest; + int op; + int opsize; + + switch (insn >> 12) { + case 1: /* move.b */ + opsize = OS_BYTE; + break; + case 2: /* move.l */ + opsize = OS_LONG; + break; + case 3: /* move.w */ + opsize = OS_WORD; + break; + default: + abort(); + } + src = gen_ea(s, insn, opsize, -1, NULL); + op = (insn >> 6) & 7; + if (op == 1) { + /* movea */ + /* The value will already have been sign extended. */ + dest = AREG(insn, 9); + gen_op_mov32(dest, src); + } else { + /* normal move */ + uint16_t dest_ea; + dest_ea = ((insn >> 9) & 7) | (op << 3); + gen_ea(s, dest_ea, opsize, src, NULL); + /* This will be correct because loads sign extend. */ + gen_logic_cc(s, src); + } +} + +DISAS_INSN(negx) +{ + int reg; + int dest; + int tmp; + + gen_flush_flags(s); + reg = DREG(insn, 0); + dest = gen_new_qreg(QMODE_I32); + gen_op_mov32 (dest, gen_im32(0)); + gen_op_subx_cc(dest, reg); + /* !Z is sticky. */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_mov32 (tmp, QREG_CC_DEST); + gen_op_update_cc_add(dest, reg); + gen_op_mov32(reg, dest); + s->cc_op = CC_OP_DYNAMIC; + gen_flush_flags(s); + gen_op_or32(tmp, tmp, gen_im32(~CCF_Z)); + gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp); + s->cc_op = CC_OP_FLAGS; +} + +DISAS_INSN(lea) +{ + int reg; + int tmp; + + reg = AREG(insn, 9); + tmp = gen_lea(s, insn, OS_LONG); + gen_op_mov32(reg, tmp); +} + +DISAS_INSN(clr) +{ + int opsize; + + switch ((insn >> 6) & 3) { + case 0: /* clr.b */ + opsize = OS_BYTE; + break; + case 1: /* clr.w */ + opsize = OS_WORD; + break; + case 2: /* clr.l */ + opsize = OS_LONG; + break; + default: + abort(); + } + gen_ea (s, insn, opsize, gen_im32(0), NULL); + gen_logic_cc(s, gen_im32(0)); +} + +DISAS_INSN(move_from_ccr) +{ + int reg; + int dest; + + gen_flush_flags(s); + dest = gen_new_qreg(QMODE_I32); + gen_op_get_xflag(dest); + gen_op_shl32(dest, dest, gen_im32(4)); + gen_op_or32(dest, dest, QREG_CC_DEST); + reg = DREG(insn, 0); + gen_partset_reg(OS_WORD, reg, dest); +} + +DISAS_INSN(neg) +{ + int reg; + int src1; + + reg = DREG(insn, 0); + src1 = gen_new_qreg(QMODE_I32); + gen_op_mov32(src1, reg); + gen_op_neg32(reg, src1); + s->cc_op = CC_OP_SUB; + gen_op_update_cc_add(reg, src1); + gen_op_update_xflag_lt(gen_im32(0), src1); + s->cc_op = CC_OP_SUB; +} + +DISAS_INSN(move_to_ccr) +{ + int src1; + int reg; + + s->cc_op = CC_OP_FLAGS; + if ((insn & 0x38) == 0) + { + src1 = gen_new_qreg(QMODE_I32); + reg = DREG(insn, 0); + gen_op_and32(src1, reg, gen_im32(0xf)); + gen_op_logic_cc(src1); + gen_op_shr32(src1, reg, gen_im32(4)); + gen_op_and32(src1, src1, gen_im32(1)); + gen_op_update_xflag_tst(src1); + } + else if ((insn & 0x3f) != 0x3c) + { + uint8_t val; + val = ldsb(s->pc); + s->pc += 2; + gen_op_logic_cc(gen_im32(val & 0xf)); + gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4)); + } + else + disas_undef(s, insn); +} + +DISAS_INSN(not) +{ + int reg; + + reg = DREG(insn, 0); + gen_op_not32(reg, reg); + gen_logic_cc(s, reg); +} + +DISAS_INSN(swap) +{ + int dest; + int src1; + int src2; + int reg; + + dest = gen_new_qreg(QMODE_I32); + src1 = gen_new_qreg(QMODE_I32); + src2 = gen_new_qreg(QMODE_I32); + reg = DREG(insn, 0); + gen_op_shl32(src1, reg, gen_im32(16)); + gen_op_shr32(src2, reg, gen_im32(16)); + gen_op_or32(dest, src1, src2); + gen_op_mov32(reg, dest); + gen_logic_cc(s, dest); +} + +DISAS_INSN(pea) +{ + int tmp; + + tmp = gen_lea(s, insn, OS_LONG); + gen_push(tmp); +} + +DISAS_INSN(ext) +{ + int reg; + int op; + int tmp; + + reg = DREG(insn, 0); + op = (insn >> 6) & 7; + tmp = gen_new_qreg(QMODE_I32); + if (op == 3) + gen_op_ext16s32(tmp, reg); + else + gen_op_ext8s32(tmp, reg); + if (op == 2) + gen_partset_reg(OS_WORD, reg, tmp); + else + gen_op_mov32(reg, tmp); + gen_logic_cc(s, tmp); +} + +DISAS_INSN(tst) +{ + int opsize; + int tmp; + + switch ((insn >> 6) & 3) { + case 0: /* tst.b */ + opsize = OS_BYTE; + break; + case 1: /* tst.w */ + opsize = OS_WORD; + break; + case 2: /* tst.l */ + opsize = OS_LONG; + break; + default: + abort(); + } + tmp = gen_ea(s, insn, opsize, -1, NULL); + gen_logic_cc(s, tmp); +} + +DISAS_INSN(pulse) +{ + /* Implemented as a NOP. */ +} + +DISAS_INSN(illegal) +{ + gen_exception(s, s->pc - 2, EXCP_ILLEGAL); +} + +/* ??? This should be atomic. */ +DISAS_INSN(tas) +{ + int dest; + int src1; + int addr; + + dest = gen_new_qreg(QMODE_I32); + src1 = gen_ea(s, insn, OS_BYTE, -1, &addr); + gen_logic_cc(s, src1); + gen_op_or32(dest, src1, gen_im32(0x80)); + gen_ea(s, insn, OS_BYTE, dest, &addr); +} + +DISAS_INSN(mull) +{ + uint16_t ext; + int reg; + int src1; + int dest; + + /* The upper 32 bits of the product are discarded, so + muls.l and mulu.l are functionally equivalent. */ + ext = lduw(s->pc); + s->pc += 2; + if (ext & 0x87ff) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + return; + } + reg = DREG(ext, 12); + src1 = gen_ea(s, insn, OS_LONG, 0, NULL); + dest = gen_new_qreg(QMODE_I32); + gen_op_mul32(dest, src1, reg); + gen_op_mov32(reg, dest); + /* Unlike m68k, coldfire always clears the overflow bit. */ + gen_logic_cc(s, dest); +} + +DISAS_INSN(link) +{ + int16_t offset; + int reg; + int tmp; + + offset = ldsw(s->pc); + s->pc += 2; + reg = AREG(insn, 0); + tmp = gen_new_qreg(QMODE_I32); + gen_op_sub32(tmp, QREG_SP, gen_im32(4)); + gen_store(OS_LONG, tmp, reg); + if (reg != QREG_SP) + gen_op_mov32(reg, tmp); + gen_op_add32(QREG_SP, tmp, gen_im32(offset)); +} + +DISAS_INSN(unlk) +{ + int src; + int reg; + int tmp; + + src = gen_new_qreg(QMODE_I32); + reg = AREG(insn, 0); + gen_op_mov32(src, reg); + tmp = gen_load(OS_LONG, src, 0); + gen_op_mov32(reg, tmp); + gen_op_add32(QREG_SP, src, gen_im32(4)); +} + +DISAS_INSN(nop) +{ +} + +DISAS_INSN(rts) +{ + int tmp; + + tmp = gen_load(OS_LONG, QREG_SP, 0); + gen_op_add32(QREG_SP, QREG_SP, gen_im32(4)); + gen_jmp(s, tmp); +} + +DISAS_INSN(jump) +{ + int tmp; + + /* Load the target address first to ensure correct exception + behavior. */ + tmp = gen_lea(s, insn, OS_LONG); + if ((insn & 0x40) == 0) { + /* jsr */ + gen_push(gen_im32(s->pc)); + } + gen_jmp(s, tmp); +} + +DISAS_INSN(addsubq) +{ + int src1; + int src2; + int dest; + int val; + int addr; + + src1 = gen_ea(s, insn, OS_LONG, 0, &addr); + val = (insn >> 9) & 7; + if (val == 0) + val = 8; + src2 = gen_im32(val); + dest = gen_new_qreg(QMODE_I32); + gen_op_mov32(dest, src1); + if ((insn & 0x38) == 0x08) { + /* Don't update condition codes if the destination is an + address register. */ + if (insn & 0x0100) { + gen_op_sub32(dest, dest, src2); + } else { + gen_op_add32(dest, dest, src2); + } + } else { + if (insn & 0x0100) { + gen_op_update_xflag_lt(dest, src2); + gen_op_sub32(dest, dest, src2); + s->cc_op = CC_OP_SUB; + } else { + gen_op_add32(dest, dest, src2); + gen_op_update_xflag_lt(dest, src2); + s->cc_op = CC_OP_ADD; + } + gen_op_update_cc_add(dest, src2); + } + gen_ea(s, insn, OS_LONG, dest, &addr); +} + +DISAS_INSN(tpf) +{ + switch (insn & 7) { + case 2: /* One extension word. */ + s->pc += 2; + break; + case 3: /* Two extension words. */ + s->pc += 4; + break; + case 4: /* No extension words. */ + break; + default: + disas_undef(s, insn); + } +} + +DISAS_INSN(branch) +{ + int32_t offset; + uint32_t base; + int op; + int l1; + + base = s->pc; + op = (insn >> 8) & 0xf; + offset = (int8_t)insn; + if (offset == 0) { + offset = ldsw(s->pc); + s->pc += 2; + } else if (offset == -1) { + offset = read_im32(s); + } + if (op == 1) { + /* bsr */ + gen_push(gen_im32(s->pc)); + } + gen_flush_cc_op(s); + if (op > 1) { + /* Bcc */ + l1 = gen_new_label(); + gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1); + gen_jmp_tb(s, 1, base + offset); + gen_set_label(l1); + gen_jmp_tb(s, 0, s->pc); + } else { + /* Unconditional branch. */ + gen_jmp_tb(s, 0, base + offset); + } +} + +DISAS_INSN(moveq) +{ + int tmp; + + tmp = gen_im32((int8_t)insn); + gen_op_mov32(DREG(insn, 9), tmp); + gen_logic_cc(s, tmp); +} + +DISAS_INSN(mvzs) +{ + int opsize; + int src; + int reg; + + if (insn & 0x40) + opsize = OS_WORD; + else + opsize = OS_BYTE; + src = gen_ea(s, insn, opsize, (insn & 0x80) ? 0 : -1, NULL); + reg = DREG(insn, 9); + gen_op_mov32(reg, src); + gen_logic_cc(s, src); +} + +DISAS_INSN(or) +{ + int reg; + int dest; + int src; + int addr; + + reg = DREG(insn, 9); + dest = gen_new_qreg(QMODE_I32); + if (insn & 0x100) { + src = gen_ea(s, insn, OS_LONG, 0, &addr); + gen_op_or32(dest, src, reg); + gen_ea(s, insn, OS_LONG, dest, &addr); + } else { + src = gen_ea(s, insn, OS_LONG, 0, NULL); + gen_op_or32(dest, src, reg); + gen_op_mov32(reg, dest); + } + gen_logic_cc(s, dest); +} + +DISAS_INSN(suba) +{ + int src; + int reg; + + src = gen_ea(s, insn, OS_LONG, 0, NULL); + reg = AREG(insn, 9); + gen_op_sub32(reg, reg, src); +} + +DISAS_INSN(subx) +{ + int reg; + int src; + int dest; + int tmp; + + gen_flush_flags(s); + reg = DREG(insn, 9); + src = DREG(insn, 0); + dest = gen_new_qreg(QMODE_I32); + gen_op_mov32 (dest, reg); + gen_op_subx_cc(dest, src); + /* !Z is sticky. */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_mov32 (tmp, QREG_CC_DEST); + gen_op_update_cc_add(dest, src); + gen_op_mov32(reg, dest); + s->cc_op = CC_OP_DYNAMIC; + gen_flush_flags(s); + gen_op_or32(tmp, tmp, gen_im32(~CCF_Z)); + gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp); + s->cc_op = CC_OP_FLAGS; +} + +DISAS_INSN(mov3q) +{ + int src; + int val; + + val = (insn >> 9) & 7; + if (val == 0) + val = -1; + src = gen_im32(val); + gen_logic_cc(s, src); + gen_ea(s, insn, OS_LONG, src, NULL); +} + +DISAS_INSN(cmp) +{ + int op; + int src; + int reg; + int dest; + int opsize; + + op = (insn >> 6) & 3; + switch (op) { + case 0: /* cmp.b */ + opsize = OS_BYTE; + s->cc_op = CC_OP_CMPB; + break; + case 1: /* cmp.w */ + opsize = OS_WORD; + s->cc_op = CC_OP_CMPW; + break; + case 2: /* cmp.l */ + opsize = OS_LONG; + s->cc_op = CC_OP_SUB; + break; + default: + abort(); + } + src = gen_ea(s, insn, opsize, -1, NULL); + reg = DREG(insn, 9); + dest = gen_new_qreg(QMODE_I32); + gen_op_sub32(dest, reg, src); + gen_op_update_cc_add(dest, src); +} + +DISAS_INSN(cmpa) +{ + int opsize; + int src; + int reg; + int dest; + + if (insn & 0x100) { + opsize = OS_LONG; + } else { + opsize = OS_WORD; + } + src = gen_ea(s, insn, opsize, -1, NULL); + reg = AREG(insn, 9); + dest = gen_new_qreg(QMODE_I32); + gen_op_sub32(dest, reg, src); + gen_op_update_cc_add(dest, src); + s->cc_op = CC_OP_SUB; +} + +DISAS_INSN(eor) +{ + int src; + int reg; + int dest; + int addr; + + src = gen_ea(s, insn, OS_LONG, 0, &addr); + reg = DREG(insn, 9); + dest = gen_new_qreg(QMODE_I32); + gen_op_xor32(dest, src, reg); + gen_logic_cc(s, dest); + gen_ea(s, insn, OS_LONG, dest, &addr); +} + +DISAS_INSN(and) +{ + int src; + int reg; + int dest; + int addr; + + reg = DREG(insn, 9); + dest = gen_new_qreg(QMODE_I32); + if (insn & 0x100) { + src = gen_ea(s, insn, OS_LONG, 0, &addr); + gen_op_and32(dest, src, reg); + gen_ea(s, insn, OS_LONG, dest, &addr); + } else { + src = gen_ea(s, insn, OS_LONG, 0, NULL); + gen_op_and32(dest, src, reg); + gen_op_mov32(reg, dest); + } + gen_logic_cc(s, dest); +} + +DISAS_INSN(adda) +{ + int src; + int reg; + + src = gen_ea(s, insn, OS_LONG, 0, NULL); + reg = AREG(insn, 9); + gen_op_add32(reg, reg, src); +} + +DISAS_INSN(addx) +{ + int reg; + int src; + int dest; + int tmp; + + gen_flush_flags(s); + reg = DREG(insn, 9); + src = DREG(insn, 0); + dest = gen_new_qreg(QMODE_I32); + gen_op_mov32 (dest, reg); + gen_op_addx_cc(dest, src); + /* !Z is sticky. */ + tmp = gen_new_qreg(QMODE_I32); + gen_op_mov32 (tmp, QREG_CC_DEST); + gen_op_update_cc_add(dest, src); + gen_op_mov32(reg, dest); + s->cc_op = CC_OP_DYNAMIC; + gen_flush_flags(s); + gen_op_or32(tmp, tmp, gen_im32(~CCF_Z)); + gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp); + s->cc_op = CC_OP_FLAGS; +} + +DISAS_INSN(shift_im) +{ + int reg; + int tmp; + + reg = DREG(insn, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) + tmp = 8; + if (insn & 0x100) { + gen_op_shl_im_cc(reg, tmp); + s->cc_op = CC_OP_SHL; + } else { + if (insn & 8) { + gen_op_shr_im_cc(reg, tmp); + s->cc_op = CC_OP_SHR; + } else { + gen_op_sar_im_cc(reg, tmp); + s->cc_op = CC_OP_SAR; + } + } +} + +DISAS_INSN(shift_reg) +{ + int reg; + int src; + int tmp; + + reg = DREG(insn, 0); + src = DREG(insn, 9); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, src, gen_im32(63)); + if (insn & 0x100) { + gen_op_shl_cc(reg, tmp); + s->cc_op = CC_OP_SHL; + } else { + if (insn & 8) { + gen_op_shr_cc(reg, tmp); + s->cc_op = CC_OP_SHR; + } else { + gen_op_sar_cc(reg, tmp); + s->cc_op = CC_OP_SAR; + } + } +} + +DISAS_INSN(ff1) +{ + cpu_abort(NULL, "Unimplemented insn: ff1"); +} + +DISAS_INSN(strldsr) +{ + uint16_t ext; + uint32_t addr; + + addr = s->pc - 2; + ext = lduw(s->pc); + s->pc += 2; + if (ext != 0x46FC) + gen_exception(s, addr, EXCP_UNSUPPORTED); + else + gen_exception(s, addr, EXCP_PRIVILEGE); +} + +DISAS_INSN(move_from_sr) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(move_to_sr) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(move_from_usp) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(move_to_usp) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(halt) +{ + gen_exception(s, s->pc, EXCP_HLT); +} + +DISAS_INSN(stop) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(rte) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(movec) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(intouch) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(cpushl) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(wddata) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(wdebug) +{ + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); +} + +DISAS_INSN(trap) +{ + gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf)); +} + +/* ??? FP exceptions are not implemented. Most exceptions are deferred until + immediately before the next FP instruction is executed. */ +DISAS_INSN(fpu) +{ + uint16_t ext; + int opmode; + int src; + int dest; + int res; + int round; + int opsize; + + ext = lduw(s->pc); + s->pc += 2; + opmode = ext & 0x7f; + switch ((ext >> 13) & 7) { + case 0: case 2: + break; + case 1: + goto undef; + case 3: /* fmove out */ + src = FREG(ext, 7); + /* fmove */ + /* ??? TODO: Proper behavior on overflow. */ + switch ((ext >> 10) & 7) { + case 0: + opsize = OS_LONG; + res = gen_new_qreg(QMODE_I32); + gen_op_f64_to_i32(res, src); + break; + case 1: + opsize = OS_SINGLE; + res = gen_new_qreg(QMODE_F32); + gen_op_f64_to_f32(res, src); + break; + case 4: + opsize = OS_WORD; + res = gen_new_qreg(QMODE_I32); + gen_op_f64_to_i32(res, src); + break; + case 5: + opsize = OS_DOUBLE; + res = src; + break; + case 6: + opsize = OS_BYTE; + res = gen_new_qreg(QMODE_I32); + gen_op_f64_to_i32(res, src); + break; + default: + goto undef; + } + gen_ea(s, insn, opsize, res, NULL); + return; + case 4: /* fmove to control register. */ + switch ((ext >> 10) & 7) { + case 4: /* FPCR */ + /* Not implemented. Ignore writes. */ + break; + case 1: /* FPIAR */ + case 2: /* FPSR */ + default: + cpu_abort(NULL, "Unimplemented: fmove to control %d", + (ext >> 10) & 7); + } + break; + case 5: /* fmove from control register. */ + switch ((ext >> 10) & 7) { + case 4: /* FPCR */ + /* Not implemented. Always return zero. */ + res = gen_im32(0); + break; + case 1: /* FPIAR */ + case 2: /* FPSR */ + default: + cpu_abort(NULL, "Unimplemented: fmove from control %d", + (ext >> 10) & 7); + goto undef; + } + gen_ea(s, insn, OS_LONG, res, NULL); + break; + case 6: /* fmovem */ + case 7: + { + int addr; + uint16_t mask; + if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) + goto undef; + src = gen_lea(s, insn, OS_LONG); + addr = gen_new_qreg(QMODE_I32); + gen_op_mov32(addr, src); + mask = 0x80; + dest = QREG_F0; + while (mask) { + if (ext & mask) { + if (ext & (1 << 13)) { + /* store */ + gen_op_stf64(addr, dest); + } else { + /* load */ + gen_op_ldf64(dest, addr); + } + if (ext & (mask - 1)) + gen_op_add32(addr, addr, gen_im32(8)); + } + mask >>= 1; + dest++; + } + } + return; + } + if (ext & (1 << 14)) { + int tmp; + + /* Source effective address. */ + switch ((ext >> 10) & 7) { + case 0: opsize = OS_LONG; break; + case 1: opsize = OS_SINGLE; break; + case 4: opsize = OS_WORD; break; + case 5: opsize = OS_DOUBLE; break; + case 6: opsize = OS_BYTE; break; + default: + goto undef; + } + tmp = gen_ea(s, insn, opsize, -1, NULL); + if (opsize == OS_DOUBLE) { + src = tmp; + } else { + src = gen_new_qreg(QMODE_F64); + switch (opsize) { + case OS_LONG: + case OS_WORD: + case OS_BYTE: + gen_op_i32_to_f64(src, tmp); + break; + case OS_SINGLE: + gen_op_f32_to_f64(src, tmp); + break; + } + } + } else { + /* Source register. */ + src = FREG(ext, 10); + } + dest = FREG(ext, 7); + res = gen_new_qreg(QMODE_F64); + if (opmode != 0x3a) + gen_op_movf64(res, dest); + round = 1; + switch (opmode) { + case 0: case 0x40: case 0x44: /* fmove */ + gen_op_movf64(res, src); + break; + case 1: /* fint */ + gen_op_iround_f64(res, src); + round = 0; + break; + case 3: /* fintrz */ + gen_op_itrunc_f64(res, src); + round = 0; + break; + case 4: case 0x41: case 0x45: /* fsqrt */ + gen_op_sqrtf64(res, src); + break; + case 0x18: case 0x58: case 0x5c: /* fabs */ + gen_op_absf64(res, src); + break; + case 0x1a: case 0x5a: case 0x5e: /* fneg */ + gen_op_chsf64(res, src); + break; + case 0x20: case 0x60: case 0x64: /* fdiv */ + gen_op_divf64(res, res, src); + break; + case 0x22: case 0x62: case 0x66: /* fadd */ + gen_op_addf64(res, res, src); + break; + case 0x23: case 0x63: case 0x67: /* fmul */ + gen_op_mulf64(res, res, src); + break; + case 0x28: case 0x68: case 0x6c: /* fsub */ + gen_op_subf64(res, res, src); + break; + case 0x38: /* fcmp */ + gen_op_sub_cmpf64(res, res, src); + dest = 0; + round = 0; + break; + case 0x3a: /* ftst */ + gen_op_movf64(res, src); + dest = 0; + round = 0; + break; + default: + goto undef; + } + if (round) { + if (opmode & 0x40) { + if ((opmode & 0x4) != 0) + round = 0; + } else if ((s->fpcr & M68K_FPCR_PREC) == 0) { + round = 0; + } + } + if (round) { + int tmp; + + tmp = gen_new_qreg(QMODE_F32); + gen_op_f64_to_f32(tmp, res); + gen_op_f32_to_f64(res, tmp); + } + gen_op_fp_result(res); + if (dest) { + gen_op_movf64(dest, res); + } + return; +undef: + s->pc -= 2; + disas_undef_fpu(s, insn); +} + +DISAS_INSN(fbcc) +{ + uint32_t offset; + uint32_t addr; + int flag; + int zero; + int l1; + + addr = s->pc; + offset = ldsw(s->pc); + s->pc += 2; + if (insn & (1 << 6)) { + offset = (offset << 16) | lduw(s->pc); + s->pc += 2; + } + + l1 = gen_new_label(); + /* TODO: Raise BSUN exception. */ + flag = gen_new_qreg(QMODE_I32); + zero = gen_new_qreg(QMODE_F64); + gen_op_zerof64(zero); + gen_op_compare_quietf64(flag, QREG_FP_RESULT, zero); + /* Jump to l1 if condition is true. */ + switch (insn & 0xf) { + case 0: /* f */ + break; + case 1: /* eq (=0) */ + gen_op_jmp_z32(flag, l1); + break; + case 2: /* ogt (=1) */ + gen_op_sub32(flag, flag, gen_im32(1)); + gen_op_jmp_z32(flag, l1); + break; + case 3: /* oge (=0 or =1) */ + gen_op_jmp_z32(flag, l1); + gen_op_sub32(flag, flag, gen_im32(1)); + gen_op_jmp_z32(flag, l1); + break; + case 4: /* olt (=-1) */ + gen_op_jmp_s32(flag, l1); + break; + case 5: /* ole (=-1 or =0) */ + gen_op_jmp_s32(flag, l1); + gen_op_jmp_z32(flag, l1); + break; + case 6: /* ogl (=-1 or =1) */ + gen_op_jmp_s32(flag, l1); + gen_op_sub32(flag, flag, gen_im32(1)); + gen_op_jmp_z32(flag, l1); + break; + case 7: /* or (=2) */ + gen_op_sub32(flag, flag, gen_im32(2)); + gen_op_jmp_z32(flag, l1); + break; + case 8: /* un (<2) */ + gen_op_sub32(flag, flag, gen_im32(2)); + gen_op_jmp_s32(flag, l1); + break; + case 9: /* ueq (=0 or =2) */ + gen_op_jmp_z32(flag, l1); + gen_op_sub32(flag, flag, gen_im32(2)); + gen_op_jmp_z32(flag, l1); + break; + case 10: /* ugt (>0) */ + /* ??? Add jmp_gtu. */ + gen_op_sub32(flag, flag, gen_im32(1)); + gen_op_jmp_ns32(flag, l1); + break; + case 11: /* uge (>=0) */ + gen_op_jmp_ns32(flag, l1); + break; + case 12: /* ult (=-1 or =2) */ + gen_op_jmp_s32(flag, l1); + gen_op_sub32(flag, flag, gen_im32(2)); + gen_op_jmp_z32(flag, l1); + break; + case 13: /* ule (!=1) */ + gen_op_sub32(flag, flag, gen_im32(1)); + gen_op_jmp_nz32(flag, l1); + break; + case 14: /* ne (!=0) */ + gen_op_jmp_nz32(flag, l1); + break; + case 15: /* t */ + gen_op_mov32(flag, gen_im32(1)); + break; + } + gen_jmp_tb(s, 0, s->pc); + gen_set_label(l1); + gen_jmp_tb(s, 1, addr + offset); +} + +static disas_proc opcode_table[65536]; + +static void +register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) +{ + int i; + int from; + int to; + + /* Sanity check. All set bits must be included in the mask. */ + if (opcode & ~mask) + abort(); + /* This could probably be cleverer. For now just optimize the case where + the top bits are known. */ + /* Find the first zero bit in the mask. */ + i = 0x8000; + while ((i & mask) != 0) + i >>= 1; + /* Iterate over all combinations of this and lower bits. */ + if (i == 0) + i = 1; + else + i <<= 1; + from = opcode & ~(i - 1); + to = from + i; + for (i = from; i < to; i++) + { + if ((i & mask) == opcode) + opcode_table[i] = proc; + } +} + +/* Register m68k opcode handlers. Order is important. + Later insn override earlier ones. */ +static void +register_m68k_insns (m68k_def_t *def) +{ + uint32_t iflags; + + iflags = def->insns; +#define INSN(name, opcode, mask, isa) \ + if (iflags & M68K_INSN_##isa) \ + register_opcode(disas_##name, 0x##opcode, 0x##mask) + INSN(undef, 0000, 0000, CF_A); + INSN(arith_im, 0080, fff8, CF_A); + INSN(bitrev, 00c0, fff8, CF_C); + INSN(bitop_reg, 0100, f1c0, CF_A); + INSN(bitop_reg, 0140, f1c0, CF_A); + INSN(bitop_reg, 0180, f1c0, CF_A); + INSN(bitop_reg, 01c0, f1c0, CF_A); + INSN(arith_im, 0280, fff8, CF_A); + INSN(byterev, 02c0, fff8, CF_A); + INSN(arith_im, 0480, fff8, CF_A); + INSN(ff1, 04c0, fff8, CF_C); + INSN(arith_im, 0680, fff8, CF_A); + INSN(bitop_im, 0800, ffc0, CF_A); + INSN(bitop_im, 0840, ffc0, CF_A); + INSN(bitop_im, 0880, ffc0, CF_A); + INSN(bitop_im, 08c0, ffc0, CF_A); + INSN(arith_im, 0a80, fff8, CF_A); + INSN(arith_im, 0c00, ff38, CF_A); + INSN(move, 1000, f000, CF_A); + INSN(move, 2000, f000, CF_A); + INSN(move, 3000, f000, CF_A); + INSN(strldsr, 40e7, ffff, CF_A); + INSN(negx, 4080, fff8, CF_A); + INSN(move_from_sr, 40c0, fff8, CF_A); + INSN(lea, 41c0, f1c0, CF_A); + INSN(clr, 4200, ff00, CF_A); + INSN(undef, 42c0, ffc0, CF_A); + INSN(move_from_ccr, 42c0, fff8, CF_A); + INSN(neg, 4480, fff8, CF_A); + INSN(move_to_ccr, 44c0, ffc0, CF_A); + INSN(not, 4680, fff8, CF_A); + INSN(move_to_sr, 46c0, ffc0, CF_A); + INSN(pea, 4840, ffc0, CF_A); + INSN(swap, 4840, fff8, CF_A); + INSN(movem, 48c0, fbc0, CF_A); + INSN(ext, 4880, fff8, CF_A); + INSN(ext, 48c0, fff8, CF_A); + INSN(ext, 49c0, fff8, CF_A); + INSN(tst, 4a00, ff00, CF_A); + INSN(tas, 4ac0, ffc0, CF_B); + INSN(halt, 4ac8, ffff, CF_A); + INSN(pulse, 4acc, ffff, CF_A); + INSN(illegal, 4afc, ffff, CF_A); + INSN(mull, 4c00, ffc0, CF_A); + INSN(divl, 4c40, ffc0, CF_A); + INSN(sats, 4c80, fff8, CF_B); + INSN(trap, 4e40, fff0, CF_A); + INSN(link, 4e50, fff8, CF_A); + INSN(unlk, 4e58, fff8, CF_A); + INSN(move_to_usp, 4e60, fff8, CF_B); + INSN(move_from_usp, 4e68, fff8, CF_B); + INSN(nop, 4e71, ffff, CF_A); + INSN(stop, 4e72, ffff, CF_A); + INSN(rte, 4e73, ffff, CF_A); + INSN(rts, 4e75, ffff, CF_A); + INSN(movec, 4e7b, ffff, CF_A); + INSN(jump, 4e80, ffc0, CF_A); + INSN(jump, 4ec0, ffc0, CF_A); + INSN(addsubq, 5180, f1c0, CF_A); + INSN(scc, 50c0, f0f8, CF_A); + INSN(addsubq, 5080, f1c0, CF_A); + INSN(tpf, 51f8, fff8, CF_A); + INSN(branch, 6000, f000, CF_A); + INSN(moveq, 7000, f100, CF_A); + INSN(mvzs, 7100, f100, CF_B); + INSN(or, 8000, f000, CF_A); + INSN(divw, 80c0, f0c0, CF_A); + INSN(addsub, 9000, f000, CF_A); + INSN(subx, 9180, f1f8, CF_A); + INSN(suba, 91c0, f1c0, CF_A); + INSN(undef_mac, a000, f000, CF_A); + INSN(mov3q, a140, f1c0, CF_B); + INSN(cmp, b000, f1c0, CF_B); /* cmp.b */ + INSN(cmp, b040, f1c0, CF_B); /* cmp.w */ + INSN(cmpa, b0c0, f1c0, CF_B); /* cmpa.w */ + INSN(cmp, b080, f1c0, CF_A); + INSN(cmpa, b1c0, f1c0, CF_A); + INSN(eor, b180, f1c0, CF_A); + INSN(and, c000, f000, CF_A); + INSN(mulw, c0c0, f0c0, CF_A); + INSN(addsub, d000, f000, CF_A); + INSN(addx, d180, f1f8, CF_A); + INSN(adda, d1c0, f1c0, CF_A); + INSN(shift_im, e080, f0f0, CF_A); + INSN(shift_reg, e0a0, f0f0, CF_A); + INSN(undef_fpu, f000, f000, CF_A); + INSN(fpu, f200, ffc0, CF_FPU); + INSN(fbcc, f280, ffc0, CF_FPU); + INSN(intouch, f340, ffc0, CF_A); + INSN(cpushl, f428, ff38, CF_A); + INSN(wddata, fb00, ff00, CF_A); + INSN(wdebug, fbc0, ffc0, CF_A); +#undef INSN +} + +/* ??? Some of this implementation is not exception safe. We should always + write back the result to memory before setting the condition codes. */ +static void disas_m68k_insn(CPUState * env, DisasContext *s) +{ + uint16_t insn; + + insn = lduw(s->pc); + s->pc += 2; + + opcode_table[insn](s, insn); +} + +#if 0 +/* Save the result of a floating point operation. */ +static void expand_op_fp_result(qOP *qop) +{ + gen_op_movf64(QREG_FP_RESULT, qop->args[0]); +} + +/* Dummy op to indicate that the flags have been set. */ +static void expand_op_flags_set(qOP *qop) +{ +} + +/* Convert the confition codes into CC_OP_FLAGS format. */ +static void expand_op_flush_flags(qOP *qop) +{ + int cc_opreg; + + if (qop->args[0] == CC_OP_DYNAMIC) + cc_opreg = QREG_CC_OP; + else + cc_opreg = gen_im32(qop->args[0]); + gen_op_helper32(QREG_NULL, cc_opreg, HELPER_flush_flags); +} + +/* Set CC_DEST after a logical or direct flag setting operation. */ +static void expand_op_logic_cc(qOP *qop) +{ + gen_op_mov32(QREG_CC_DEST, qop->args[0]); +} + +/* Set CC_SRC and CC_DEST after an arithmetic operation. */ +static void expand_op_update_cc_add(qOP *qop) +{ + gen_op_mov32(QREG_CC_DEST, qop->args[0]); + gen_op_mov32(QREG_CC_SRC, qop->args[1]); +} + +/* Update the X flag. */ +static void expand_op_update_xflag(qOP *qop) +{ + int arg0; + int arg1; + + arg0 = qop->args[0]; + arg1 = qop->args[1]; + if (arg1 == QREG_NULL) { + /* CC_X = arg0. */ + gen_op_mov32(QREG_CC_X, arg0); + } else { + /* CC_X = arg0 < (unsigned)arg1. */ + gen_op_set_ltu32(QREG_CC_X, arg0, arg1); + } +} + +/* Set arg0 to the contents of the X flag. */ +static void expand_op_get_xflag(qOP *qop) +{ + gen_op_mov32(qop->args[0], QREG_CC_X); +} + +/* Expand a shift by immediate. The ISA only allows shifts by 1-8, so we + already know the shift is within range. */ +static inline void expand_shift_im(qOP *qop, int right, int arith) +{ + int val; + int reg; + int tmp; + int im; + + reg = qop->args[0]; + im = qop->args[1]; + tmp = gen_im32(im); + val = gen_new_qreg(QMODE_I32); + gen_op_mov32(val, reg); + gen_op_mov32(QREG_CC_DEST, val); + gen_op_mov32(QREG_CC_SRC, tmp); + if (right) { + if (arith) { + gen_op_sar32(reg, val, tmp); + } else { + gen_op_shr32(reg, val, tmp); + } + if (im == 1) + tmp = QREG_NULL; + else + tmp = gen_im32(im - 1); + } else { + gen_op_shl32(reg, val, tmp); + tmp = gen_im32(32 - im); + } + if (tmp != QREG_NULL) + gen_op_shr32(val, val, tmp); + gen_op_and32(QREG_CC_X, val, gen_im32(1)); +} + +static void expand_op_shl_im_cc(qOP *qop) +{ + expand_shift_im(qop, 0, 0); +} + +static void expand_op_shr_im_cc(qOP *qop) +{ + expand_shift_im(qop, 1, 0); +} + +static void expand_op_sar_im_cc(qOP *qop) +{ + expand_shift_im(qop, 1, 1); +} + +/* Expand a shift by register. */ +/* ??? This gives incorrect answers for shifts by 0 or >= 32 */ +static inline void expand_shift_reg(qOP *qop, int right, int arith) +{ + int val; + int reg; + int shift; + int tmp; + + reg = qop->args[0]; + shift = qop->args[1]; + val = gen_new_qreg(QMODE_I32); + gen_op_mov32(val, reg); + gen_op_mov32(QREG_CC_DEST, val); + gen_op_mov32(QREG_CC_SRC, shift); + tmp = gen_new_qreg(QMODE_I32); + if (right) { + if (arith) { + gen_op_sar32(reg, val, shift); + } else { + gen_op_shr32(reg, val, shift); + } + gen_op_sub32(tmp, shift, gen_im32(1)); + } else { + gen_op_shl32(reg, val, shift); + gen_op_sub32(tmp, gen_im32(31), shift); + } + gen_op_shl32(val, val, tmp); + gen_op_and32(QREG_CC_X, val, gen_im32(1)); +} + +static void expand_op_shl_cc(qOP *qop) +{ + expand_shift_reg(qop, 0, 0); +} + +static void expand_op_shr_cc(qOP *qop) +{ + expand_shift_reg(qop, 1, 0); +} + +static void expand_op_sar_cc(qOP *qop) +{ + expand_shift_reg(qop, 1, 1); +} + +/* Set the Z flag to (arg0 & arg1) == 0. */ +static void expand_op_btest(qOP *qop) +{ + int tmp; + int l1; + + l1 = gen_new_label(); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, qop->args[0], qop->args[1]); + gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(~(uint32_t)CCF_Z)); + gen_op_jmp_nz32(tmp, l1); + gen_op_or32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(CCF_Z)); + gen_op_label(l1); +} + +/* arg0 += arg1 + CC_X */ +static void expand_op_addx_cc(qOP *qop) +{ + int arg0 = qop->args[0]; + int arg1 = qop->args[1]; + int l1, l2; + + gen_op_add32 (arg0, arg0, arg1); + l1 = gen_new_label(); + l2 = gen_new_label(); + gen_op_jmp_z32(QREG_CC_X, l1); + gen_op_add32(arg0, arg0, gen_im32(1)); + gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADDX)); + gen_op_set_leu32(QREG_CC_X, arg0, arg1); + gen_op_jmp(l2); + gen_set_label(l1); + gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADD)); + gen_op_set_ltu32(QREG_CC_X, arg0, arg1); + gen_set_label(l2); +} + +/* arg0 -= arg1 + CC_X */ +static void expand_op_subx_cc(qOP *qop) +{ + int arg0 = qop->args[0]; + int arg1 = qop->args[1]; + int l1, l2; + + l1 = gen_new_label(); + l2 = gen_new_label(); + gen_op_jmp_z32(QREG_CC_X, l1); + gen_op_set_leu32(QREG_CC_X, arg0, arg1); + gen_op_sub32(arg0, arg0, gen_im32(1)); + gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUBX)); + gen_op_jmp(l2); + gen_set_label(l1); + gen_op_set_ltu32(QREG_CC_X, arg0, arg1); + gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUB)); + gen_set_label(l2); + gen_op_sub32 (arg0, arg0, arg1); +} + +/* Expand target specific ops to generic qops. */ +static void expand_target_qops(void) +{ + qOP *qop; + qOP *next; + int c; + + /* Copy the list of qops, expanding target specific ops as we go. */ + qop = gen_first_qop; + gen_first_qop = NULL; + gen_last_qop = NULL; + for (; qop; qop = next) { + c = qop->opcode; + next = qop->next; + if (c < FIRST_TARGET_OP) { + qop->prev = gen_last_qop; + qop->next = NULL; + if (gen_last_qop) + gen_last_qop->next = qop; + else + gen_first_qop = qop; + gen_last_qop = qop; + continue; + } + switch (c) { +#define DEF(name, nargs, barrier) \ + case INDEX_op_##name: \ + expand_op_##name(qop); \ + break; +#include "qop-target.def" +#undef DEF + default: + cpu_abort(NULL, "Unexpanded target qop"); + } + } +} + +/* ??? Implement this. */ +static void +optimize_flags(void) +{ +} +#endif + +/* generate intermediate code for basic block 'tb'. */ +int gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, + int search_pc) +{ + DisasContext dc1, *dc = &dc1; + uint16_t *gen_opc_end; + int j, lj; + target_ulong pc_start; + int pc_offset; + int last_cc_op; + + /* generate intermediate code */ + pc_start = tb->pc; + + dc->tb = tb; + + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + + dc->is_jmp = DISAS_NEXT; + dc->pc = pc_start; + dc->cc_op = CC_OP_DYNAMIC; + dc->singlestep_enabled = env->singlestep_enabled; + dc->fpcr = env->fpcr; + nb_gen_labels = 0; + lj = -1; + do { + free_qreg = 0; + pc_offset = dc->pc - pc_start; + gen_throws_exception = NULL; + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == dc->pc) { + gen_exception(dc, dc->pc, EXCP_DEBUG); + dc->is_jmp = DISAS_JUMP; + break; + } + } + if (dc->is_jmp) + break; + } + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = dc->pc; + gen_opc_instr_start[lj] = 1; + } + last_cc_op = dc->cc_op; + disas_m68k_insn(env, dc); + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + !env->singlestep_enabled && + (pc_offset) < (TARGET_PAGE_SIZE - 32)); + + if (__builtin_expect(env->singlestep_enabled, 0)) { + /* Make sure the pc is updated, and raise a debug exception. */ + if (!dc->is_jmp) { + gen_flush_cc_op(dc); + gen_op_mov32(QREG_PC, gen_im32((long)dc->pc)); + } + gen_op_raise_exception(EXCP_DEBUG); + } else { + switch(dc->is_jmp) { + case DISAS_NEXT: + gen_flush_cc_op(dc); + gen_jmp_tb(dc, 0, dc->pc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + gen_flush_cc_op(dc); + /* indicate that the hash table must be used to find the next TB */ + gen_op_mov32(QREG_T0, gen_im32(0)); + gen_op_exit_tb(); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + } + } + *gen_opc_ptr = INDEX_op_end; + +#ifdef DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "----------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + target_disas(logfile, pc_start, dc->pc - pc_start, 0); + fprintf(logfile, "\n"); + if (loglevel & (CPU_LOG_TB_OP)) { + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } + } +#endif + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + tb->size = 0; + } else { + tb->size = dc->pc - pc_start; + } + + //optimize_flags(); + //expand_target_qops(); + return 0; +} + +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 1); +} + +CPUM68KState *cpu_m68k_init(void) +{ + CPUM68KState *env; + + env = malloc(sizeof(CPUM68KState)); + if (!env) + return NULL; + cpu_exec_init(env); + + memset(env, 0, sizeof(CPUM68KState)); + /* ??? FP regs should be initialized to NaN. */ + cpu_single_env = env; + env->cc_op = CC_OP_FLAGS; + return env; +} + +void cpu_m68k_close(CPUM68KState *env) +{ + free(env); +} + +m68k_def_t *m68k_find_by_name(const char *name) +{ + m68k_def_t *def; + + def = m68k_cpu_defs; + while (def->name) + { + if (strcmp(def->name, name) == 0) + return def; + def++; + } + return NULL; +} + +void cpu_m68k_register(CPUM68KState *env, m68k_def_t *def) +{ + register_m68k_insns(def); +} + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; + uint16_t sr; + CPU_DoubleU u; + for (i = 0; i < 8; i++) + { + u.d = env->fregs[i]; + cpu_fprintf (f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n", + i, env->dregs[i], i, env->aregs[i], + i, u.l.upper, u.l.lower, u.d); + } + cpu_fprintf (f, "PC = %08x ", env->pc); + sr = env->sr; + cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & 0x10) ? 'X' : '-', + (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-', + (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-'); + cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result); +} + +/* ??? */ +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} + +#if defined(CONFIG_USER_ONLY) + +int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + env->exception_index = EXCP_ACCESS; + env->mmu.ar = address; + return 1; +} + +#else + +#error not implemented + +#endif diff --git a/translate-all.c b/translate-all.c index 0de429f5b..43365478b 100644 --- a/translate-all.c +++ b/translate-all.c @@ -302,6 +302,8 @@ int cpu_restore_state(TranslationBlock *tb, } env->access_type = type; } +#elif defined(TARGET_M68K) + env->pc = gen_opc_pc[j]; #elif defined(TARGET_MIPS) env->PC = gen_opc_pc[j]; env->hflags &= ~MIPS_HFLAG_BMASK; -- cgit v1.2.3 From d37aca662561a54a5ea177c6c05280633fa41cb8 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 22 Oct 2006 11:54:30 +0000 Subject: Fix comment typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2197 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 75a1f1314..b994bdd29 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -48,7 +48,7 @@ typedef struct CPUARMState { /* Regs for current mode. */ uint32_t regs[16]; /* Frequently accessed CPSR bits are stored separately for efficiently. - This contains all the other bits. Use cpsr_{read,write} to accless + This contains all the other bits. Use cpsr_{read,write} to access the whole CPSR. */ uint32_t uncached_cpsr; uint32_t spsr; -- cgit v1.2.3 From dd016883fb560f0dc541d4da829caa33830fd30d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 23 Oct 2006 21:25:11 +0000 Subject: add support for cvt.s.d and cvt.d.s (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2198 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 12 ++++++++++++ target-mips/translate.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/target-mips/op.c b/target-mips/op.c index 457551725..39db3ce95 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -785,12 +785,24 @@ void op_mtc1 (void) #define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) +FLOAT_OP(cvtd, s) +{ + FDT2 = float32_to_float64(WT0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} FLOAT_OP(cvtd, w) { FDT2 = int32_to_float64(WT0, &env->fp_status); DEBUG_FPU_STATE(); RETURN(); } +FLOAT_OP(cvts, d) +{ + FST2 = float64_to_float32(WT0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} FLOAT_OP(cvts, w) { FST2 = int32_to_float32(WT0, &env->fp_status); diff --git a/target-mips/translate.c b/target-mips/translate.c index 7ad8ebddf..c0de12b0f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1675,6 +1675,13 @@ static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int GEN_STORE_FTN_FREG(fd, WT2); opn = "ceil.w.d"; break; + case FOP(33, 16): /* cvt.d.s */ + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvtd_s(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "cvt.d.s"; + break; case FOP(33, 20): /* cvt.d.w */ CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); @@ -1782,6 +1789,13 @@ static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int GEN_STORE_FTN_FREG(fd, WT2); opn = "trunc.w.s"; break; + case FOP(32, 17): /* cvt.s.d */ + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvts_d(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "cvt.s.d"; + break; case FOP(32, 20): /* cvt.s.w */ CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); -- cgit v1.2.3 From 27908725b9e2ccabc5089eb6f8975c6b277de14b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 23 Oct 2006 21:31:01 +0000 Subject: sparc64 syscall fix (Blue Swirl) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2199 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 53bf1bb92..38e94d27b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -559,10 +559,18 @@ void cpu_loop (CPUSPARCState *env) env->regwptr[2], env->regwptr[3], env->regwptr[4], env->regwptr[5]); if ((unsigned int)ret >= (unsigned int)(-515)) { +#ifdef TARGET_SPARC64 + env->xcc |= PSR_CARRY; +#else env->psr |= PSR_CARRY; +#endif ret = -ret; } else { +#ifdef TARGET_SPARC64 + env->xcc &= ~PSR_CARRY; +#else env->psr &= ~PSR_CARRY; +#endif } env->regwptr[0] = ret; /* next instruction */ -- cgit v1.2.3 From c688a6eb185544444a50e07cade5166b2e23270e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 23 Oct 2006 21:37:34 +0000 Subject: wrwim insn fix (Paul Robinson) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2200 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 9 +++++++++ target-sparc/translate.c | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 7ea209ea8..1ec15d28b 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -844,6 +844,15 @@ void OPPROTO op_wrpsr(void) FORCE_RET(); } +void OPPROTO op_wrwim(void) +{ +#if NWINDOWS == 32 + env->wim = T0; +#else + env->wim = T0 & ((1 << NWINDOWS) - 1); +#endif +} + void OPPROTO op_rett(void) { helper_rett(); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index a522d778b..455dd171e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2005,7 +2005,7 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; } #else - gen_op_movl_env_T0(offsetof(CPUSPARCState, wim)); + gen_op_wrwim(); #endif } break; -- cgit v1.2.3 From a94a6abff47685e33caf332b55f45e02ab2d8a55 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 25 Oct 2006 17:43:33 +0000 Subject: Fix ARM VFP debugging dumps. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2201 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index fa7ad6086..cd91bdce8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2542,6 +2542,12 @@ void cpu_dump_state(CPUState *env, FILE *f, float s; } s0, s1; CPU_DoubleU d; + /* ??? This assumes float64 and double have the same layout. + Oh well, it's only debug dumps. */ + union { + float64 f64; + double d; + } d0; uint32_t psr; for(i=0;i<16;i++) { @@ -2565,11 +2571,12 @@ void cpu_dump_state(CPUState *env, FILE *f, d.d = env->vfp.regs[i]; s0.i = d.l.lower; s1.i = d.l.upper; - cpu_fprintf(f, "s%02d=%08x(%8f) s%02d=%08x(%8f) d%02d=%08x%08x(%8f)\n", + d0.f64 = d.d; + cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n", i * 2, (int)s0.i, s0.s, - i * 2 + 1, (int)s0.i, s0.s, + i * 2 + 1, (int)s1.i, s1.s, i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower, - d.d); + d0.d); } cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); } -- cgit v1.2.3 From fafffaef4f09958c2b12ee4b09ffba59847eba44 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 28 Oct 2006 12:09:16 +0000 Subject: removed invalid code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2202 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/signal.c b/linux-user/signal.c index 60f9eb767..8ee5c4b2f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1521,8 +1521,11 @@ restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu) return -EFAULT; #endif +#if 0 + /* XXX: incorrect */ err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0], (sizeof(unsigned long) * 32)); +#endif err |= __get_user(env->fsr, &fpu->si_fsr); #if 0 err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth); -- cgit v1.2.3 From 00a67ba19a41e26fc24758c6bfb9bbcda430a83b Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 28 Oct 2006 12:19:07 +0000 Subject: avoid regression on sparc-user and ppc-user git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2203 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile.target b/Makefile.target index 773f331a9..57f949891 100644 --- a/Makefile.target +++ b/Makefile.target @@ -494,6 +494,11 @@ endif cpu-exec.o: cpu-exec.c $(CC) $(HELPER_CFLAGS) $(DEFINES) -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) $(DEFINES) -c -o $@ $< + ifeq ($(TARGET_BASE_ARCH), i386) op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h endif -- cgit v1.2.3 From 750afe93fd15fafc20b6c34d30f339547d15c2d1 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 28 Oct 2006 19:27:11 +0000 Subject: avoid using char when it is not necessary git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2204 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.c | 20 +++++++------- fpu/softfloat-native.h | 62 +++++++++++++++++++++--------------------- fpu/softfloat-specialize.h | 16 +++++------ fpu/softfloat.c | 54 ++++++++++++++++++------------------ fpu/softfloat.h | 68 +++++++++++++++++++++++----------------------- 5 files changed, 110 insertions(+), 110 deletions(-) diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 1ef7cf29a..f20d5c45f 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -149,7 +149,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM) { return sqrtf(a); } -char float32_compare( float32 a, float32 b STATUS_PARAM ) +int float32_compare( float32 a, float32 b STATUS_PARAM ) { if (a < b) { return -1; @@ -161,7 +161,7 @@ char float32_compare( float32 a, float32 b STATUS_PARAM ) return 2; } } -char float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) +int float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) { if (isless(a, b)) { return -1; @@ -173,7 +173,7 @@ char float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) return 2; } } -char float32_is_signaling_nan( float32 a1) +int float32_is_signaling_nan( float32 a1) { float32u u; uint32_t a; @@ -258,7 +258,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM) { return sqrt(a); } -char float64_compare( float64 a, float64 b STATUS_PARAM ) +int float64_compare( float64 a, float64 b STATUS_PARAM ) { if (a < b) { return -1; @@ -270,7 +270,7 @@ char float64_compare( float64 a, float64 b STATUS_PARAM ) return 2; } } -char float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) +int float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) { if (isless(a, b)) { return -1; @@ -282,7 +282,7 @@ char float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) return 2; } } -char float64_is_signaling_nan( float64 a1) +int float64_is_signaling_nan( float64 a1) { float64u u; uint64_t a; @@ -294,7 +294,7 @@ char float64_is_signaling_nan( float64 a1) } -char float64_is_nan( float64 a1 ) +int float64_is_nan( float64 a1 ) { float64u u; uint64_t a; @@ -350,7 +350,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM) { return sqrtl(a); } -char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) { if (a < b) { return -1; @@ -362,7 +362,7 @@ char floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) return 2; } } -char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { if (isless(a, b)) { return -1; @@ -374,7 +374,7 @@ char floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) return 2; } } -char floatx80_is_signaling_nan( floatx80 a1) +int floatx80_is_signaling_nan( floatx80 a1) { floatx80u u; u.f = a1; diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 05cf023f6..8c2770877 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -152,38 +152,38 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM) } float32 float32_rem( float32, float32 STATUS_PARAM); float32 float32_sqrt( float32 STATUS_PARAM); -INLINE char float32_eq( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) { return a == b; } -INLINE char float32_le( float32 a, float32 b STATUS_PARAM) +INLINE int float32_le( float32 a, float32 b STATUS_PARAM) { return a <= b; } -INLINE char float32_lt( float32 a, float32 b STATUS_PARAM) +INLINE int float32_lt( float32 a, float32 b STATUS_PARAM) { return a < b; } -INLINE char float32_eq_signaling( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM) { return a <= b && a >= b; } -INLINE char float32_le_quiet( float32 a, float32 b STATUS_PARAM) +INLINE int float32_le_quiet( float32 a, float32 b STATUS_PARAM) { return islessequal(a, b); } -INLINE char float32_lt_quiet( float32 a, float32 b STATUS_PARAM) +INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM) { return isless(a, b); } -INLINE char float32_unordered( float32 a, float32 b STATUS_PARAM) +INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) { return isunordered(a, b); } -char float32_compare( float32, float32 STATUS_PARAM ); -char float32_compare_quiet( float32, float32 STATUS_PARAM ); -char float32_is_signaling_nan( float32 ); +int float32_compare( float32, float32 STATUS_PARAM ); +int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_signaling_nan( float32 ); INLINE float32 float32_abs(float32 a) { @@ -233,40 +233,40 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM) } float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); -INLINE char float64_eq( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) { return a == b; } -INLINE char float64_le( float64 a, float64 b STATUS_PARAM) +INLINE int float64_le( float64 a, float64 b STATUS_PARAM) { return a <= b; } -INLINE char float64_lt( float64 a, float64 b STATUS_PARAM) +INLINE int float64_lt( float64 a, float64 b STATUS_PARAM) { return a < b; } -INLINE char float64_eq_signaling( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM) { return a <= b && a >= b; } -INLINE char float64_le_quiet( float64 a, float64 b STATUS_PARAM) +INLINE int float64_le_quiet( float64 a, float64 b STATUS_PARAM) { return islessequal(a, b); } -INLINE char float64_lt_quiet( float64 a, float64 b STATUS_PARAM) +INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM) { return isless(a, b); } -INLINE char float64_unordered( float64 a, float64 b STATUS_PARAM) +INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM) { return isunordered(a, b); } -char float64_compare( float64, float64 STATUS_PARAM ); -char float64_compare_quiet( float64, float64 STATUS_PARAM ); -char float64_is_signaling_nan( float64 ); -flag float64_is_nan( float64 ); +int float64_compare( float64, float64 STATUS_PARAM ); +int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_signaling_nan( float64 ); +int float64_is_nan( float64 ); INLINE float64 float64_abs(float64 a) { @@ -315,39 +315,39 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM) } floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); -INLINE char floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) { return a == b; } -INLINE char floatx80_le( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM) { return a <= b; } -INLINE char floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) { return a < b; } -INLINE char floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) { return a <= b && a >= b; } -INLINE char floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM) { return islessequal(a, b); } -INLINE char floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) { return isless(a, b); } -INLINE char floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) { return isunordered(a, b); } -char floatx80_compare( floatx80, floatx80 STATUS_PARAM ); -char floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); -char floatx80_is_signaling_nan( floatx80 ); +int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_signaling_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) { diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index d430f58a7..f9b6f0cbc 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -68,7 +68,7 @@ typedef struct { | otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float32_is_nan( float32 a ) +int float32_is_nan( float32 a ) { return ( 0xFF000000 < (bits32) ( a<<1 ) ); @@ -80,7 +80,7 @@ flag float32_is_nan( float32 a ) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float32_is_signaling_nan( float32 a ) +int float32_is_signaling_nan( float32 a ) { return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); @@ -161,7 +161,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) | otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float64_is_nan( float64 a ) +int float64_is_nan( float64 a ) { return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); @@ -173,7 +173,7 @@ flag float64_is_nan( float64 a ) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float64_is_signaling_nan( float64 a ) +int float64_is_signaling_nan( float64 a ) { return @@ -264,7 +264,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag floatx80_is_nan( floatx80 a ) +int floatx80_is_nan( floatx80 a ) { return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); @@ -276,7 +276,7 @@ flag floatx80_is_nan( floatx80 a ) | signaling NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag floatx80_is_signaling_nan( floatx80 a ) +int floatx80_is_signaling_nan( floatx80 a ) { bits64 aLow; @@ -371,7 +371,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) | otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float128_is_nan( float128 a ) +int float128_is_nan( float128 a ) { return @@ -385,7 +385,7 @@ flag float128_is_nan( float128 a ) | signaling NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -flag float128_is_signaling_nan( float128 a ) +int float128_is_signaling_nan( float128 a ) { return diff --git a/fpu/softfloat.c b/fpu/softfloat.c index f24913a13..5dbfa81e4 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2023,7 +2023,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_eq( float32 a, float32 b STATUS_PARAM ) +int float32_eq( float32 a, float32 b STATUS_PARAM ) { if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) @@ -2045,7 +2045,7 @@ flag float32_eq( float32 a, float32 b STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_le( float32 a, float32 b STATUS_PARAM ) +int float32_le( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; @@ -2068,7 +2068,7 @@ flag float32_le( float32 a, float32 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_lt( float32 a, float32 b STATUS_PARAM ) +int float32_lt( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; @@ -2092,7 +2092,7 @@ flag float32_lt( float32 a, float32 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) +int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) { if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) @@ -2112,7 +2112,7 @@ flag float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_le_quiet( float32 a, float32 b STATUS_PARAM ) +int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; @@ -2138,7 +2138,7 @@ flag float32_le_quiet( float32 a, float32 b STATUS_PARAM ) | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) +int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; @@ -2952,7 +2952,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_eq( float64 a, float64 b STATUS_PARAM ) +int float64_eq( float64 a, float64 b STATUS_PARAM ) { if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) @@ -2974,7 +2974,7 @@ flag float64_eq( float64 a, float64 b STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_le( float64 a, float64 b STATUS_PARAM ) +int float64_le( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; @@ -2997,7 +2997,7 @@ flag float64_le( float64 a, float64 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_lt( float64 a, float64 b STATUS_PARAM ) +int float64_lt( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; @@ -3021,7 +3021,7 @@ flag float64_lt( float64 a, float64 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) +int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) { if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) @@ -3041,7 +3041,7 @@ flag float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_le_quiet( float64 a, float64 b STATUS_PARAM ) +int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; @@ -3067,7 +3067,7 @@ flag float64_le_quiet( float64 a, float64 b STATUS_PARAM ) | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) +int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; @@ -3890,7 +3890,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -3920,7 +3920,7 @@ flag floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) | Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; @@ -3953,7 +3953,7 @@ flag floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; @@ -3986,7 +3986,7 @@ flag floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) @@ -4013,7 +4013,7 @@ flag floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) | to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; @@ -4049,7 +4049,7 @@ flag floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; @@ -5010,7 +5010,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_eq( float128 a, float128 b STATUS_PARAM ) +int float128_eq( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) @@ -5040,7 +5040,7 @@ flag float128_eq( float128 a, float128 b STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_le( float128 a, float128 b STATUS_PARAM ) +int float128_le( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign; @@ -5072,7 +5072,7 @@ flag float128_le( float128 a, float128 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_lt( float128 a, float128 b STATUS_PARAM ) +int float128_lt( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign; @@ -5105,7 +5105,7 @@ flag float128_lt( float128 a, float128 b STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) +int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) @@ -5132,7 +5132,7 @@ flag float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) | IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_le_quiet( float128 a, float128 b STATUS_PARAM ) +int float128_le_quiet( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign; @@ -5168,7 +5168,7 @@ flag float128_le_quiet( float128 a, float128 b STATUS_PARAM ) | Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -flag float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) +int float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign; @@ -5283,7 +5283,7 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) } #define COMPARE(s, nan_exp) \ -INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \ +INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ int is_quiet STATUS_PARAM ) \ { \ flag aSign, bSign; \ @@ -5317,12 +5317,12 @@ INLINE char float ## s ## _compare_internal( float ## s a, float ## s b, \ } \ } \ \ -char float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \ +int float ## s ## _compare( float ## s a, float ## s b STATUS_PARAM ) \ { \ return float ## s ## _compare_internal(a, b, 0 STATUS_VAR); \ } \ \ -char float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ +int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ { \ return float ## s ## _compare_internal(a, b, 1 STATUS_VAR); \ } diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 3dec119e4..a326af832 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -43,7 +43,7 @@ these four paragraphs for those parts of this code that are retained. | implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed | to the same as `int'. *----------------------------------------------------------------------------*/ -typedef char flag; +typedef uint8_t flag; typedef uint8_t uint8; typedef int8_t int8; typedef int uint16; @@ -228,16 +228,16 @@ float32 float32_mul( float32, float32 STATUS_PARAM ); float32 float32_div( float32, float32 STATUS_PARAM ); float32 float32_rem( float32, float32 STATUS_PARAM ); float32 float32_sqrt( float32 STATUS_PARAM ); -char float32_eq( float32, float32 STATUS_PARAM ); -char float32_le( float32, float32 STATUS_PARAM ); -char float32_lt( float32, float32 STATUS_PARAM ); -char float32_eq_signaling( float32, float32 STATUS_PARAM ); -char float32_le_quiet( float32, float32 STATUS_PARAM ); -char float32_lt_quiet( float32, float32 STATUS_PARAM ); -char float32_compare( float32, float32 STATUS_PARAM ); -char float32_compare_quiet( float32, float32 STATUS_PARAM ); -char float32_is_signaling_nan( float32 ); -flag float64_is_nan( float64 a ); +int float32_eq( float32, float32 STATUS_PARAM ); +int float32_le( float32, float32 STATUS_PARAM ); +int float32_lt( float32, float32 STATUS_PARAM ); +int float32_eq_signaling( float32, float32 STATUS_PARAM ); +int float32_le_quiet( float32, float32 STATUS_PARAM ); +int float32_lt_quiet( float32, float32 STATUS_PARAM ); +int float32_compare( float32, float32 STATUS_PARAM ); +int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_signaling_nan( float32 ); +int float64_is_nan( float64 a ); INLINE float32 float32_abs(float32 a) { @@ -277,15 +277,15 @@ float64 float64_mul( float64, float64 STATUS_PARAM ); float64 float64_div( float64, float64 STATUS_PARAM ); float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); -char float64_eq( float64, float64 STATUS_PARAM ); -char float64_le( float64, float64 STATUS_PARAM ); -char float64_lt( float64, float64 STATUS_PARAM ); -char float64_eq_signaling( float64, float64 STATUS_PARAM ); -char float64_le_quiet( float64, float64 STATUS_PARAM ); -char float64_lt_quiet( float64, float64 STATUS_PARAM ); -char float64_compare( float64, float64 STATUS_PARAM ); -char float64_compare_quiet( float64, float64 STATUS_PARAM ); -char float64_is_signaling_nan( float64 ); +int float64_eq( float64, float64 STATUS_PARAM ); +int float64_le( float64, float64 STATUS_PARAM ); +int float64_lt( float64, float64 STATUS_PARAM ); +int float64_eq_signaling( float64, float64 STATUS_PARAM ); +int float64_le_quiet( float64, float64 STATUS_PARAM ); +int float64_lt_quiet( float64, float64 STATUS_PARAM ); +int float64_compare( float64, float64 STATUS_PARAM ); +int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_signaling_nan( float64 ); INLINE float64 float64_abs(float64 a) { @@ -322,13 +322,13 @@ floatx80 floatx80_mul( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_div( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); -char floatx80_eq( floatx80, floatx80 STATUS_PARAM ); -char floatx80_le( floatx80, floatx80 STATUS_PARAM ); -char floatx80_lt( floatx80, floatx80 STATUS_PARAM ); -char floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); -char floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); -char floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); -char floatx80_is_signaling_nan( floatx80 ); +int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); +int floatx80_le( floatx80, floatx80 STATUS_PARAM ); +int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); +int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_signaling_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) { @@ -369,13 +369,13 @@ float128 float128_mul( float128, float128 STATUS_PARAM ); float128 float128_div( float128, float128 STATUS_PARAM ); float128 float128_rem( float128, float128 STATUS_PARAM ); float128 float128_sqrt( float128 STATUS_PARAM ); -char float128_eq( float128, float128 STATUS_PARAM ); -char float128_le( float128, float128 STATUS_PARAM ); -char float128_lt( float128, float128 STATUS_PARAM ); -char float128_eq_signaling( float128, float128 STATUS_PARAM ); -char float128_le_quiet( float128, float128 STATUS_PARAM ); -char float128_lt_quiet( float128, float128 STATUS_PARAM ); -char float128_is_signaling_nan( float128 ); +int float128_eq( float128, float128 STATUS_PARAM ); +int float128_le( float128, float128 STATUS_PARAM ); +int float128_lt( float128, float128 STATUS_PARAM ); +int float128_eq_signaling( float128, float128 STATUS_PARAM ); +int float128_le_quiet( float128, float128 STATUS_PARAM ); +int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_is_signaling_nan( float128 ); INLINE float128 float128_abs(float128 a) { -- cgit v1.2.3 From 569f5d668c071487a31bdc51b27bbedaa46cb01a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 29 Oct 2006 15:10:09 +0000 Subject: compilation fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2205 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/nwfpe/fpa11_cprt.c | 4 ---- target-mips/op.c | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/target-arm/nwfpe/fpa11_cprt.c b/target-arm/nwfpe/fpa11_cprt.c index 91f2d8001..3be9b42a9 100644 --- a/target-arm/nwfpe/fpa11_cprt.c +++ b/target-arm/nwfpe/fpa11_cprt.c @@ -27,10 +27,6 @@ //#include "fpmodule.h" //#include "fpmodule.inl" -extern flag floatx80_is_nan(floatx80); -extern flag float64_is_nan( float64); -extern flag float32_is_nan( float32); - void SetRoundingMode(const unsigned int opcode); unsigned int PerformFLT(const unsigned int opcode); diff --git a/target-mips/op.c b/target-mips/op.c index 39db3ce95..638fd3b33 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -977,9 +977,8 @@ void op_cmp_ ## fmt ## _ ## op (void) \ RETURN(); \ } -flag float64_is_unordered(float64 a, float64 b STATUS_PARAM) +int float64_is_unordered(float64 a, float64 b STATUS_PARAM) { - extern flag float64_is_nan( float64 a ); if (float64_is_nan(a) || float64_is_nan(b)) { float_raise(float_flag_invalid, status); return 1; -- cgit v1.2.3 From 58126404f5d8ccb53ab7a385ad0230dd7c4cc130 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 29 Oct 2006 15:38:28 +0000 Subject: Mips IDE support. (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2206 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++-- hw/mips_r4k.c | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index 57f949891..bdc365908 100644 --- a/Makefile.target +++ b/Makefile.target @@ -357,8 +357,8 @@ VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) -VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o -#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o +VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o ide.o +#VL_OBJS+= #pckbd.o fdc.o m48t59.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 075b16cb4..6c838ac31 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -7,6 +7,10 @@ #define VIRT_TO_PHYS_ADDEND (-0x80000000LL) +static const int ide_iobase[2] = { 0x1f0, 0x170 }; +static const int ide_iobase2[2] = { 0x3f6, 0x376 }; +static const int ide_irq[2] = { 14, 15 }; + extern FILE *logfile; static PITState *pit; @@ -118,6 +122,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, int ret; CPUState *env; long kernel_size; + int i; env = cpu_init(); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); @@ -198,6 +203,10 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, exit (1); } } + + for(i = 0; i < 2; i++) + isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + bs_table[2 * i], bs_table[2 * i + 1]); } QEMUMachine mips_machine = { -- cgit v1.2.3 From 188157fe87f24fc4200deba17bb258ec5ddb6ca1 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 1 Nov 2006 01:44:16 +0000 Subject: Remove FD on close. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2207 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vl.c b/vl.c index d047eb420..447da38a9 100644 --- a/vl.c +++ b/vl.c @@ -1228,6 +1228,11 @@ static void fd_chr_read(void *opaque) if (len == 0) return; size = read(s->fd_in, buf, len); + if (size == 0) { + /* FD has been closed. Remove it from the active list. */ + qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); + return; + } if (size > 0) { s->fd_read(s->fd_opaque, buf, size); } -- cgit v1.2.3 From 597a0559fd7fd0f2151276f25d9e97dff468ea23 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 1 Nov 2006 19:19:17 +0000 Subject: update from latest Bochs BIOS git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2208 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/bios.diff | 56 +++++++++++------------------------------------------- 2 files changed, 11 insertions(+), 45 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 0161bde0f..14ea6a606 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index c355befc9..86c36c11d 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,10 +1,10 @@ Index: rombios.h =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios.h,v -retrieving revision 1.2 -diff -u -w -r1.2 rombios.h ---- rombios.h 1 Oct 2006 16:39:18 -0000 1.2 -+++ rombios.h 2 Oct 2006 18:31:41 -0000 +retrieving revision 1.3 +diff -u -w -r1.3 rombios.h +--- rombios.h 3 Oct 2006 20:27:30 -0000 1.3 ++++ rombios.h 1 Nov 2006 19:16:34 -0000 @@ -19,7 +19,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA @@ -12,50 +12,16 @@ diff -u -w -r1.2 rombios.h -//#define BX_QEMU +#define BX_QEMU - #define BX_ROMBIOS32 1 - #define DEBUG_ROMBIOS 0 + #ifndef LEGACY + # define BX_ROMBIOS32 1 Index: rombios32.c =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios32.c,v -retrieving revision 1.6 -diff -u -w -r1.6 rombios32.c ---- rombios32.c 2 Oct 2006 06:29:37 -0000 1.6 -+++ rombios32.c 2 Oct 2006 18:31:41 -0000 -@@ -45,6 +45,8 @@ - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \ - : "0" (index)) - -+#define wbinvd() asm volatile("wbinvd") -+ - #define CPUID_APIC (1 << 9) - - #define APIC_BASE ((uint8_t *)0xfee00000) -@@ -591,6 +593,7 @@ - PCIDevice *d = &i440_pcidev; - int v; - -+ wbinvd(); - v = pci_config_readb(d, 0x59); - v = (v & 0x0f) | (0x10); - pci_config_writeb(d, 0x59, v); -@@ -645,7 +648,7 @@ - outb(0xb3, 0x01); - - /* raise an SMI interrupt */ -- outb(0xb2, 0x01); -+ outb(0xb2, 0x00); - - /* wait until SMM code executed */ - while (inb(0xb3) != 0x00); -@@ -656,6 +659,7 @@ - /* copy the SMM code */ - memcpy((void *)0xa8000, &smm_code_start, - &smm_code_end - &smm_code_start); -+ wbinvd(); - - /* close the SMM memory window and enable normal SMM */ - pci_config_writeb(&i440_pcidev, 0x72, 0x02 | 0x08); -@@ -848,6 +852,11 @@ +retrieving revision 1.8 +diff -u -w -r1.8 rombios32.c +--- rombios32.c 3 Oct 2006 20:27:30 -0000 1.8 ++++ rombios32.c 1 Nov 2006 19:16:34 -0000 +@@ -852,6 +852,11 @@ int ioapic_id, i, len; int mp_config_table_size; -- cgit v1.2.3 From d08b2a28e6d71c561b84878b84e52159a63a27cc Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 4 Nov 2006 16:46:29 +0000 Subject: MIPS usermode debug exceptions (Dave Denholm). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2209 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 38e94d27b..6dd08022f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1362,6 +1362,20 @@ void cpu_loop(CPUMIPSState *env) case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; default: // error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", -- cgit v1.2.3 From b362e5e067835d04ddde5fb1277272d4b498b970 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 12 Nov 2006 20:40:55 +0000 Subject: Speed up tlb_flush_page (Daniel Jacobowitz). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2210 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 8 ++++++++ exec-all.h | 12 +++++++++++- exec.c | 15 +++++++-------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 674c0bd3f..0b49c8991 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -80,6 +80,14 @@ typedef unsigned long ram_addr_t; #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) diff --git a/exec-all.h b/exec-all.h index b598948e3..82ef3acdc 100644 --- a/exec-all.h +++ b/exec-all.h @@ -196,9 +196,19 @@ typedef struct TranslationBlock { struct TranslationBlock *jmp_first; } TranslationBlock; +static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) +{ + target_ulong tmp; + tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); + return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK; +} + static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) { - return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1); + target_ulong tmp; + tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); + return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) | + (tmp & TB_JMP_ADDR_MASK)); } static inline unsigned int tb_phys_hash_func(unsigned long pc) diff --git a/exec.c b/exec.c index 20870ad02..762d6dc4d 100644 --- a/exec.c +++ b/exec.c @@ -1288,14 +1288,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr) tlb_flush_entry(&env->tlb_table[0][i], addr); tlb_flush_entry(&env->tlb_table[1][i], addr); - for(i = 0; i < TB_JMP_CACHE_SIZE; i++) { - tb = env->tb_jmp_cache[i]; - if (tb && - ((tb->pc & TARGET_PAGE_MASK) == addr || - ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) { - env->tb_jmp_cache[i] = NULL; - } - } + /* Discard jump cache entries for any tb which might potentially + overlap the flushed page. */ + i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE); + memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb)); + + i = tb_jmp_cache_hash_page(addr); + memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb)); #if !defined(CONFIG_SOFTMMU) if (addr < MMAP_AREA_END) -- cgit v1.2.3 From 483dcf538ea2ac86914bf7deef1d07f3b48d8878 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 12 Nov 2006 20:55:05 +0000 Subject: Avoid redundant TLB flushes (Daniel Jacobowitz). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2211 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index bf397c9b4..6e31436f5 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -572,8 +572,17 @@ static void invalidate_tlb (int idx) { tlb_t *tlb; target_ulong addr; + uint8_t ASID; + + ASID = env->CP0_EntryHi & 0xFF; tlb = &env->tlb[idx]; + /* The qemu TLB is flushed then the ASID changes, so no need to + flush these entries again. */ + if (tlb->G == 0 && tlb->ASID != ASID) { + return; + } + if (tlb->V0) { tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN); addr = tlb->VPN; -- cgit v1.2.3 From 2d37be61e3a377843f4e8b8fcc837838294b8b3f Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 12 Nov 2006 21:31:18 +0000 Subject: M68k build fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2212 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/op.c | 7 +++++-- target-m68k/translate.c | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/target-m68k/op.c b/target-m68k/op.c index 489eafeef..8ea7589c3 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -412,7 +412,10 @@ OP(divu) quot = num / den; rem = num % den; flags = 0; - if (PARAM1 && quot > 0xffff) + /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses + the address of a symbol, and gcc knows symbols can't have address + zero. */ + if (PARAM1 == 2 && quot > 0xffff) flags |= CCF_V; if (quot == 0) flags |= CCF_Z; @@ -439,7 +442,7 @@ OP(divs) quot = num / den; rem = num % den; flags = 0; - if (PARAM1 && quot != (int16_t)quot) + if (PARAM1 == 2 && quot != (int16_t)quot) flags |= CCF_V; if (quot == 0) flags |= CCF_Z; diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 10728f97d..9c34c626b 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -747,9 +747,9 @@ DISAS_INSN(divl) den = gen_ea(s, insn, OS_LONG, 0, NULL); gen_op_mov32(QREG_DIV2, den); if (ext & 0x0800) { - gen_op_divs(0); + gen_op_divs(2); } else { - gen_op_divu(0); + gen_op_divu(2); } if (num == reg) { /* div */ -- cgit v1.2.3 From 417f38f066e21cf69f85d78eecbf6268c53a80bc Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 12 Nov 2006 23:54:39 +0000 Subject: MIPS FPU fixes (Daniel Jacobowitz). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2213 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 +- target-mips/translate.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 638fd3b33..534c90e51 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -799,7 +799,7 @@ FLOAT_OP(cvtd, w) } FLOAT_OP(cvts, d) { - FST2 = float64_to_float32(WT0, &env->fp_status); + FST2 = float64_to_float32(FDT0, &env->fp_status); DEBUG_FPU_STATE(); RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index c0de12b0f..f5c3afdce 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1791,7 +1791,7 @@ static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int break; case FOP(32, 17): /* cvt.s.d */ CHECK_FR(ctx, fs | fd); - GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.d"; @@ -1812,7 +1812,7 @@ static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int break; case FOP(36, 17): /* cvt.w.d */ CHECK_FR(ctx, fs | fd); - GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.w.d"; @@ -2089,6 +2089,7 @@ static void decode_opc (DisasContext *ctx) case 0x39: /* SWC1 */ case 0x3D: /* SDC1 */ #if defined(MIPS_USES_FPU) + save_cpu_state(ctx, 1); gen_op_cp1_enabled(); gen_flt_ldst(ctx, op, rt, rs, imm); #else @@ -2098,6 +2099,7 @@ static void decode_opc (DisasContext *ctx) case 0x11: /* CP1 opcode */ #if defined(MIPS_USES_FPU) + save_cpu_state(ctx, 1); gen_op_cp1_enabled(); op1 = ((ctx->opcode >> 21) & 0x1F); switch (op1) { -- cgit v1.2.3 From ec2db7de7a280ce8d943e1a14463609d44b2b3e8 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 14 Nov 2006 21:13:53 +0000 Subject: ARM timer counts down, not up. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2214 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_timer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/arm_timer.c b/hw/arm_timer.c index a97d73e44..c8864f13c 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -107,29 +107,29 @@ static void arm_timer_update(arm_timer_state *s, int64_t now) /* Return the current value of the timer. */ static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now) { - int64_t elapsed; + int64_t left; int64_t period; if (s->count == 0) return 0; if ((s->control & TIMER_CTRL_ENABLE) == 0) return s->count; - elapsed = now - s->loaded; + left = s->expires - now; period = s->expires - s->loaded; /* If the timer should have expired then return 0. This can happen when the host timer signal doesnt occur immediately. It's better to have a timer appear to sit at zero for a while than have it wrap around before the guest interrupt is raised. */ /* ??? Could we trigger the interrupt here? */ - if (elapsed > period) + if (left < 0) return 0; /* We need to calculate count * elapsed / period without overfowing. Scale both elapsed and period so they fit in a 32-bit int. */ while (period != (int32_t)period) { period >>= 1; - elapsed >>= 1; + left >>= 1; } - return ((uint64_t)s->count * (uint64_t)(int32_t)elapsed) + return ((uint64_t)s->count * (uint64_t)(int32_t)left) / (int32_t)period; } -- cgit v1.2.3 From 1be9e1dc569eb3817441baf60d26648c5dcef12d Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 19 Nov 2006 15:26:04 +0000 Subject: Remove do_socketcallwrapper. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2215 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 221 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 129 insertions(+), 92 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e5e4139fd..e95212894 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -837,6 +837,113 @@ static long do_sendrecvmsg(int fd, target_ulong target_msg, return ret; } +static long do_accept(int fd, target_ulong target_addr, + target_ulong target_addrlen) +{ + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(target_addrlen); + long ret; + + ret = get_errno(accept(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + return ret; +} + +static long do_getpeername(int fd, target_ulong target_addr, + target_ulong target_addrlen) +{ + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(target_addrlen); + long ret; + + ret = get_errno(getpeername(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + return ret; +} + +static long do_getsockname(int fd, target_ulong target_addr, + target_ulong target_addrlen) +{ + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(target_addrlen); + long ret; + + ret = get_errno(getsockname(fd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + return ret; +} + +static long do_socketpair(int domain, int type, int protocol, + target_ulong target_tab) +{ + int tab[2]; + long ret; + + ret = get_errno(socketpair(domain, type, protocol, tab)); + if (!is_error(ret)) { + tput32(target_tab, tab[0]); + tput32(target_tab + 4, tab[1]); + } + return ret; +} + +static long do_sendto(int fd, target_ulong msg, size_t len, int flags, + target_ulong target_addr, socklen_t addrlen) +{ + void *addr; + void *host_msg; + long ret; + + host_msg = lock_user(msg, len, 1); + if (target_addr) { + addr = alloca(addrlen); + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(sendto(fd, host_msg, len, flags, addr, addrlen)); + } else { + ret = get_errno(send(fd, host_msg, len, flags)); + } + unlock_user(host_msg, msg, 0); + return ret; +} + +static long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, + target_ulong target_addr, target_ulong target_addrlen) +{ + socklen_t addrlen; + void *addr; + void *host_msg; + long ret; + + host_msg = lock_user(msg, len, 0); + if (target_addr) { + addrlen = tget32(target_addrlen); + addr = alloca(addrlen); + ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen)); + } else { + addr = NULL; /* To keep compiler quiet. */ + ret = get_errno(recv(fd, host_msg, len, flags)); + } + if (!is_error(ret)) { + if (target_addr) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + unlock_user(host_msg, msg, len); + } else { + unlock_user(host_msg, msg, 0); + } + return ret; +} + static long do_socketcall(int num, target_ulong vptr) { long ret; @@ -879,14 +986,7 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); target_ulong target_addrlen = tgetl(vptr + 2 * n); - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); - - ret = get_errno(accept(sockfd, addr, &addrlen)); - if (!is_error(ret)) { - host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); - } + ret = do_accept(sockfd, target_addr, target_addrlen); } break; case SOCKOP_getsockname: @@ -894,14 +994,7 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); target_ulong target_addrlen = tgetl(vptr + 2 * n); - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); - - ret = get_errno(getsockname(sockfd, addr, &addrlen)); - if (!is_error(ret)) { - host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); - } + ret = do_getsockname(sockfd, target_addr, target_addrlen); } break; case SOCKOP_getpeername: @@ -909,14 +1002,7 @@ static long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); target_ulong target_addr = tgetl(vptr + n); target_ulong target_addrlen = tgetl(vptr + 2 * n); - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); - - ret = get_errno(getpeername(sockfd, addr, &addrlen)); - if (!is_error(ret)) { - host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); - } + ret = do_getpeername(sockfd, target_addr, target_addrlen); } break; case SOCKOP_socketpair: @@ -924,14 +1010,8 @@ static long do_socketcall(int num, target_ulong vptr) int domain = tgetl(vptr); int type = tgetl(vptr + n); int protocol = tgetl(vptr + 2 * n); - target_ulong target_tab = tgetl(vptr + 3 * n); - int tab[2]; - - ret = get_errno(socketpair(domain, type, protocol, tab)); - if (!is_error(ret)) { - tput32(target_tab, tab[0]); - tput32(target_tab + 4, tab[1]); - } + target_ulong tab = tgetl(vptr + 3 * n); + ret = do_socketpair(domain, type, protocol, tab); } break; case SOCKOP_send: @@ -940,11 +1020,7 @@ static long do_socketcall(int num, target_ulong vptr) target_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - void *host_msg; - - host_msg = lock_user(msg, len, 1); - ret = get_errno(send(sockfd, host_msg, len, flags)); - unlock_user(host_msg, msg, 0); + ret = do_sendto(sockfd, msg, len, flags, 0, 0); } break; case SOCKOP_recv: @@ -953,11 +1029,7 @@ static long do_socketcall(int num, target_ulong vptr) target_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - void *host_msg; - - host_msg = lock_user(msg, len, 0); - ret = get_errno(recv(sockfd, host_msg, len, flags)); - unlock_user(host_msg, msg, ret); + ret = do_recvfrom(sockfd, msg, len, flags, 0, 0); } break; case SOCKOP_sendto: @@ -966,15 +1038,9 @@ static long do_socketcall(int num, target_ulong vptr) target_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - target_ulong target_addr = tgetl(vptr + 4 * n); + target_ulong addr = tgetl(vptr + 4 * n); socklen_t addrlen = tgetl(vptr + 5 * n); - void *addr = alloca(addrlen); - void *host_msg; - - host_msg = lock_user(msg, len, 1); - target_to_host_sockaddr(addr, target_addr, addrlen); - ret = get_errno(sendto(sockfd, host_msg, len, flags, addr, addrlen)); - unlock_user(host_msg, msg, 0); + ret = do_sendto(sockfd, msg, len, flags, addr, addrlen); } break; case SOCKOP_recvfrom: @@ -983,21 +1049,9 @@ static long do_socketcall(int num, target_ulong vptr) target_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - target_ulong target_addr = tgetl(vptr + 4 * n); - target_ulong target_addrlen = tgetl(vptr + 5 * n); - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); - void *host_msg; - - host_msg = lock_user(msg, len, 0); - ret = get_errno(recvfrom(sockfd, host_msg, len, flags, addr, &addrlen)); - if (!is_error(ret)) { - host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); - unlock_user(host_msg, msg, len); - } else { - unlock_user(host_msg, msg, 0); - } + target_ulong addr = tgetl(vptr + 4 * n); + target_ulong addrlen = tgetl(vptr + 5 * n); + ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen); } break; case SOCKOP_shutdown: @@ -1053,23 +1107,6 @@ static long do_socketcall(int num, target_ulong vptr) return ret; } -/* XXX: suppress this function and call directly the related socket - functions */ -static long do_socketcallwrapper(int num, long arg1, long arg2, long arg3, - long arg4, long arg5, long arg6) -{ - target_long args[6]; - - tputl(args, arg1); - tputl(args+1, arg2); - tputl(args+2, arg3); - tputl(args+3, arg4); - tputl(args+4, arg5); - tputl(args+5, arg6); - - return do_socketcall(num, (target_ulong) args); -} - #define N_SHM_REGIONS 32 static struct shm_region { @@ -2755,7 +2792,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_accept case TARGET_NR_accept: - ret = do_socketcallwrapper(SOCKOP_accept, arg1, arg2, arg3, arg4, arg5, arg6); + ret = do_accept(arg1, arg2, arg3); break; #endif #ifdef TARGET_NR_bind @@ -2770,12 +2807,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_getpeername case TARGET_NR_getpeername: - ret = do_socketcallwrapper(SOCKOP_getpeername, arg1, arg2, arg3, arg4, arg5, arg6); + ret = do_getpeername(arg1, arg2, arg3); break; #endif #ifdef TARGET_NR_getsockname case TARGET_NR_getsockname: - ret = do_socketcallwrapper(SOCKOP_getsockname, arg1, arg2, arg3, arg4, arg5, arg6); + ret = do_getsockname(arg1, arg2, arg3); break; #endif #ifdef TARGET_NR_getsockopt @@ -2785,17 +2822,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_listen case TARGET_NR_listen: - ret = do_socketcallwrapper(SOCKOP_listen, arg1, arg2, arg3, arg4, arg5, arg6); + ret = get_errno(listen(arg1, arg2)); break; #endif #ifdef TARGET_NR_recv case TARGET_NR_recv: - ret = do_socketcallwrapper(SOCKOP_recv, arg1, arg2, arg3, arg4, arg5, arg6); + ret = do_recvfrom(arg1, arg1, arg3, arg4, 0, 0); break; #endif #ifdef TARGET_NR_recvfrom case TARGET_NR_recvfrom: - ret = do_socketcallwrapper(SOCKOP_recvfrom, arg1, arg2, arg3, arg4, arg5, arg6); + ret = do_recvfrom(arg1, arg1, arg3, arg4, arg5, arg6); break; #endif #ifdef TARGET_NR_recvmsg @@ -2805,7 +2842,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_send case TARGET_NR_send: - ret = do_socketcallwrapper(SOCKOP_send, arg1, arg2, arg3, arg4, arg5, arg6); + ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0); break; #endif #ifdef TARGET_NR_sendmsg @@ -2815,12 +2852,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_sendto case TARGET_NR_sendto: - ret = do_socketcallwrapper(SOCKOP_sendto, arg1, arg2, arg3, arg4, arg5, arg6); + ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6); break; #endif #ifdef TARGET_NR_shutdown case TARGET_NR_shutdown: - ret = do_socketcallwrapper(SOCKOP_shutdown, arg1, arg2, arg3, arg4, arg5, arg6); + ret = get_errno(shutdown(arg1, arg2)); break; #endif #ifdef TARGET_NR_socket @@ -2830,7 +2867,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_socketpair case TARGET_NR_socketpair: - ret = do_socketcallwrapper(SOCKOP_socketpair, arg1, arg2, arg3, arg4, arg5, arg6); + ret = do_socketpair(arg1, arg2, arg3, arg4); break; #endif #ifdef TARGET_NR_setsockopt -- cgit v1.2.3 From 38d0662a4cf196cc059c9e27f634b13fb24fce2d Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 19 Nov 2006 20:29:35 +0000 Subject: Arm semihosted commandline support (Wolfgang Schildbach). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2216 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm-semi.c | 42 +++++++++++++++++++++++++++++++++++++----- linux-user/linuxload.c | 2 ++ linux-user/qemu.h | 1 + 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c index 250d5b75c..b182eb408 100644 --- a/linux-user/arm-semi.c +++ b/linux-user/arm-semi.c @@ -77,7 +77,8 @@ static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code) return code; } -#define ARG(n) tget32(args + n * 4) +#define ARG(n) tget32(args + (n) * 4) +#define SET_ARG(n, val) tput32(args + (n) * 4,val) uint32_t do_arm_semihosting(CPUState *env) { target_ulong args; @@ -158,10 +159,41 @@ uint32_t do_arm_semihosting(CPUState *env) case SYS_ERRNO: return ts->swi_errno; case SYS_GET_CMDLINE: - /* XXX: Not implemented. */ - s = (char *)g2h(ARG(0)); - *s = 0; - return -1; + /* Build a commandline from the original argv. */ + { + char **arg = ts->info->host_argv; + int len = ARG(1); + /* lock the buffer on the ARM side */ + char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0); + + s = cmdline_buffer; + while (*arg && len > 2) { + int n = strlen(*arg); + + if (s != cmdline_buffer) { + *(s++) = ' '; + len--; + } + if (n >= len) + n = len - 1; + memcpy(s, *arg, n); + s += n; + len -= n; + arg++; + } + /* Null terminate the string. */ + *s = 0; + len = s - cmdline_buffer; + + /* Unlock the buffer on the ARM side. */ + unlock_user(cmdline_buffer, ARG(0), len); + + /* Adjust the commandline length argument. */ + SET_ARG(1, len); + + /* Return success if commandline fit into buffer. */ + return *arg ? -1 : 0; + } case SYS_HEAPINFO: { uint32_t *ptr; diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index ef5409b95..2d20c000d 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -162,6 +162,8 @@ int loader_exec(const char * filename, char ** argv, char ** envp, retval = prepare_binprm(&bprm); + infop->host_argv = argv; + if(retval>=0) { if (bprm.buf[0] == 0x7f && bprm.buf[1] == 'E' diff --git a/linux-user/qemu.h b/linux-user/qemu.h index d35455de3..f894dde08 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -29,6 +29,7 @@ struct image_info { unsigned long entry; target_ulong code_offset; target_ulong data_offset; + char **host_argv; int personality; }; -- cgit v1.2.3 From 08f396d720d5dd9adf1520cea00ff5fcf776c1f3 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 19 Nov 2006 21:51:51 +0000 Subject: Add missing ARM syscall numbers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2217 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/syscall_nr.h | 67 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index 195e459ec..c48be982f 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -259,4 +259,69 @@ /* 254 for set_thread_area */ /* 255 for get_thread_area */ /* 256 for set_tid_address */ -#define TARGET_NR_utimes (269) +#define TARGET_NR_set_tid_address 256 +#define TARGET_NR_timer_create 257 +#define TARGET_NR_timer_settime 258 +#define TARGET_NR_timer_gettime 259 +#define TARGET_NR_timer_getoverrun 260 +#define TARGET_NR_timer_delete 261 +#define TARGET_NR_clock_settime 262 +#define TARGET_NR_clock_gettime 263 +#define TARGET_NR_clock_getres 264 +#define TARGET_NR_clock_nanosleep 265 +#define TARGET_NR_statfs64 266 +#define TARGET_NR_fstatfs64 267 +#define TARGET_NR_tgkill 268 +#define TARGET_NR_utimes 269 +#define TARGET_NR_arm_fadvise64_64 270 +#define TARGET_NR_pciconfig_iobase 271 +#define TARGET_NR_pciconfig_read 272 +#define TARGET_NR_pciconfig_write 273 +#define TARGET_NR_mq_open 274 +#define TARGET_NR_mq_unlink 275 +#define TARGET_NR_mq_timedsend 276 +#define TARGET_NR_mq_timedreceive 277 +#define TARGET_NR_mq_notify 278 +#define TARGET_NR_mq_getsetattr 279 +#define TARGET_NR_waitid 280 +#define TARGET_NR_socket 281 +#define TARGET_NR_bind 282 +#define TARGET_NR_connect 283 +#define TARGET_NR_listen 284 +#define TARGET_NR_accept 285 +#define TARGET_NR_getsockname 286 +#define TARGET_NR_getpeername 287 +#define TARGET_NR_socketpair 288 +#define TARGET_NR_send 289 +#define TARGET_NR_sendto 290 +#define TARGET_NR_recv 291 +#define TARGET_NR_recvfrom 292 +#define TARGET_NR_shutdown 293 +#define TARGET_NR_setsockopt 294 +#define TARGET_NR_getsockopt 295 +#define TARGET_NR_sendmsg 296 +#define TARGET_NR_recvmsg 297 +#define TARGET_NR_semop 298 +#define TARGET_NR_semget 299 +#define TARGET_NR_semctl 300 +#define TARGET_NR_msgsnd 301 +#define TARGET_NR_msgrcv 302 +#define TARGET_NR_msgget 303 +#define TARGET_NR_msgctl 304 +#define TARGET_NR_shmat 305 +#define TARGET_NR_shmdt 306 +#define TARGET_NR_shmget 307 +#define TARGET_NR_shmctl 308 +#define TARGET_NR_add_key 309 +#define TARGET_NR_request_key 310 +#define TARGET_NR_keyctl 311 +#define TARGET_NR_semtimedop 312 +#define TARGET_NR_vserver 313 +#define TARGET_NR_ioprio_set 314 +#define TARGET_NR_ioprio_get 315 +#define TARGET_NR_inotify_init 316 +#define TARGET_NR_inotify_add_watch 317 +#define TARGET_NR_inotify_rm_watch 318 +#define TARGET_NR_mbind 319 +#define TARGET_NR_get_mempolicy 320 +#define TARGET_NR_set_mempolicy 321 -- cgit v1.2.3 From 29bfb117251c96034bb9f9144bc61799137690c3 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 19 Nov 2006 23:07:17 +0000 Subject: Add casts for 64-bit hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2218 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/integratorcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index f438af733..17dca2859 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -325,7 +325,7 @@ static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset) case 5: /* INT_SOFTCLR */ case 11: /* FRQ_ENABLECLR */ default: - printf ("icp_pic_read: Bad register offset 0x%x\n", offset); + printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); return 0; } } @@ -362,7 +362,7 @@ static void icp_pic_write(void *opaque, target_phys_addr_t offset, case 8: /* FRQ_STATUS */ case 9: /* FRQ_RAWSTAT */ default: - printf ("icp_pic_write: Bad register offset 0x%x\n", offset); + printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); return; } icp_pic_update(s); -- cgit v1.2.3 From ec2309289d39dcdfd1a766b945b46d8a0e0be3a4 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Dec 2006 15:51:39 +0000 Subject: sparc-softmmu build fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2219 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index f4f725d6c..0b1d5669a 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -12,12 +12,12 @@ void raise_exception(int tt) #ifdef USE_INT_TO_FLOAT_HELPERS void do_fitos(void) { - FT0 = int32_to_float32(*((int32_t *)&FT1)); + FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status); } void do_fitod(void) { - DT0 = int32_to_float64(*((int32_t *)&FT1)); + DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); } #endif -- cgit v1.2.3 From 814b9a47490c4500fd105b524b8354764e6655e5 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Dec 2006 17:42:40 +0000 Subject: MIPS TLB performance improvements, by Daniel Jacobowitz. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2220 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 3 ++- target-mips/exec.h | 1 + target-mips/helper.c | 2 +- target-mips/mips-defs.h | 1 + target-mips/op_helper.c | 54 +++++++++++++++++++++++++++++++++++++++++++------ target-mips/translate.c | 1 + 6 files changed, 54 insertions(+), 8 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 330f9eb19..3ade7bce6 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -94,7 +94,8 @@ struct CPUMIPSState { #endif #if defined(MIPS_USES_R4K_TLB) - tlb_t tlb[MIPS_TLB_NB]; + tlb_t tlb[MIPS_TLB_MAX]; + uint32_t tlb_in_use; #endif uint32_t CP0_index; uint32_t CP0_random; diff --git a/target-mips/exec.h b/target-mips/exec.h index 93014d6df..a1cf685a1 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -115,5 +115,6 @@ uint32_t cpu_mips_get_count (CPUState *env); void cpu_mips_store_count (CPUState *env, uint32_t value); void cpu_mips_store_compare (CPUState *env, uint32_t value); void cpu_mips_clock_init (CPUState *env); +void cpu_mips_tlb_flush (CPUState *env, int flush_global); #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ diff --git a/target-mips/helper.c b/target-mips/helper.c index 9c8e4f68d..57318a5a3 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -46,7 +46,7 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, tlb_t *tlb; int i, n; - for (i = 0; i < MIPS_TLB_NB; i++) { + for (i = 0; i < env->tlb_in_use; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index c6f9e9cbe..63e64bbdc 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -22,6 +22,7 @@ /* Uses MIPS R4Kc TLB model */ #define MIPS_USES_R4K_TLB #define MIPS_TLB_NB 16 +#define MIPS_TLB_MAX 128 /* basic FPU register support */ #define MIPS_USES_FPU 1 /* Define a implementation number of 1. diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 6e31436f5..c7d86d016 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -367,7 +367,7 @@ void do_mtc0 (int reg, int sel) env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ if ((old & 0xFF) != (val & 0xFF)) - tlb_flush (env, 1); + cpu_mips_tlb_flush (env, 1); rn = "EntryHi"; break; case 11: @@ -568,7 +568,14 @@ void fpu_handle_exception(void) /* TLB management */ #if defined(MIPS_USES_R4K_TLB) -static void invalidate_tlb (int idx) +void cpu_mips_tlb_flush (CPUState *env, int flush_global) +{ + /* Flush qemu's TLB and discard all shadowed entries. */ + tlb_flush (env, flush_global); + env->tlb_in_use = MIPS_TLB_NB; +} + +static void invalidate_tlb (int idx, int use_extra) { tlb_t *tlb; target_ulong addr; @@ -583,6 +590,15 @@ static void invalidate_tlb (int idx) return; } + if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) { + /* For tlbwr, we can shadow the discarded entry into + a new (fake) TLB entry, as long as the guest can not + tell that it's there. */ + env->tlb[env->tlb_in_use] = *tlb; + env->tlb_in_use++; + return; + } + if (tlb->V0) { tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN); addr = tlb->VPN; @@ -601,6 +617,14 @@ static void invalidate_tlb (int idx) } } +static void mips_tlb_flush_extra (CPUState *env, int first) +{ + /* Discard entries from env->tlb[first] onwards. */ + while (env->tlb_in_use > first) { + invalidate_tlb(--env->tlb_in_use, 0); + } +} + static void fill_tlb (int idx) { tlb_t *tlb; @@ -627,9 +651,14 @@ static void fill_tlb (int idx) void do_tlbwi (void) { + /* Discard cached TLB entries. We could avoid doing this if the + tlbwi is just upgrading access permissions on the current entry; + that might be a further win. */ + mips_tlb_flush_extra (env, MIPS_TLB_NB); + /* Wildly undefined effects for CP0_index containing a too high value and MIPS_TLB_NB not being a power of two. But so does real silicon. */ - invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); + invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1), 0); fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); } @@ -637,7 +666,7 @@ void do_tlbwr (void) { int r = cpu_mips_get_random(env); - invalidate_tlb(r); + invalidate_tlb(r, 1); fill_tlb(r); } @@ -660,6 +689,17 @@ void do_tlbp (void) } } if (i == MIPS_TLB_NB) { + /* No match. Discard any shadow entries, if any of them match. */ + for (i = MIPS_TLB_NB; i < env->tlb_in_use; i++) { + tlb = &env->tlb[i]; + + /* Check ASID, virtual page number & size */ + if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { + mips_tlb_flush_extra (env, i); + break; + } + } + env->CP0_index |= 0x80000000; } } @@ -674,8 +714,10 @@ void do_tlbr (void) tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; /* If this will change the current ASID, flush qemu's TLB. */ - if (ASID != tlb->ASID && tlb->G != 1) - tlb_flush (env, 1); + if (ASID != tlb->ASID) + cpu_mips_tlb_flush (env, 1); + + mips_tlb_flush_extra(env, MIPS_TLB_NB); env->CP0_EntryHi = tlb->VPN | tlb->ASID; size = (tlb->end - tlb->VPN) >> 12; diff --git a/target-mips/translate.c b/target-mips/translate.c index f5c3afdce..0d624185f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2430,6 +2430,7 @@ CPUMIPSState *cpu_mips_init (void) env->PC = 0xBFC00000; #if defined (MIPS_USES_R4K_TLB) env->CP0_random = MIPS_TLB_NB - 1; + env->tlb_in_use = MIPS_TLB_NB; #endif env->CP0_Wired = 0; env->CP0_Config0 = MIPS_CONFIG0; -- cgit v1.2.3 From 6ae817752b72a7c9c3bb031afa7e7cc0e4d10eaf Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Dec 2006 17:48:52 +0000 Subject: Halt/reboot support for Linux, by Daniel Jacobowitz. This is a band-aid until we emulate real MIPS hardware with real firmware. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2221 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 133 ++++++++++++++++++++++++++++++++++++------------ target-mips/cpu.h | 8 ++- target-mips/translate.c | 10 +++- 3 files changed, 116 insertions(+), 35 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 6c838ac31..60eb191bd 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -110,6 +110,93 @@ void cpu_mips_clock_init (CPUState *env) cpu_mips_update_count(env, 1, 0); } +static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + if ((addr & 0xffff) == 0 && val == 42) + qemu_system_reset_request (); + else if ((addr & 0xffff) == 4 && val == 42) + qemu_system_shutdown_request (); +} + +static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static CPUWriteMemoryFunc *mips_qemu_write[] = { + &mips_qemu_writel, + &mips_qemu_writel, + &mips_qemu_writel, +}; + +static CPUReadMemoryFunc *mips_qemu_read[] = { + &mips_qemu_readl, + &mips_qemu_readl, + &mips_qemu_readl, +}; + +static int mips_qemu_iomemtype = 0; + +void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + int64_t entry = 0; + long kernel_size, initrd_size; + + kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); + if (kernel_size >= 0) + env->PC = entry; + else { + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + env->PC = KERNEL_LOAD_ADDR; + } + + /* load initrd */ + initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image(initrd_filename, + phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); + if (initrd_size == (target_ulong) -1) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + + /* Store command line. */ + if (initrd_size > 0) { + int ret; + ret = sprintf(phys_ram_base + (16 << 20) - 256, + "rd_start=0x%08x rd_size=%li ", + INITRD_LOAD_ADDR, + initrd_size); + strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline); + } + else { + strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); + } + + *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); + *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); +} + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); + + if (env->kernel_filename) + load_kernel (env, env->ram_size, env->kernel_filename, + env->kernel_cmdline, env->initrd_filename); +} void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -117,19 +204,24 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename) { char buf[1024]; - int64_t entry = 0; unsigned long bios_offset; int ret; CPUState *env; - long kernel_size; int i; env = cpu_init(); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + qemu_register_reset(main_cpu_reset, env); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + if (!mips_qemu_iomemtype) { + mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read, + mips_qemu_write, NULL); + } + cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype); + /* Try to load a BIOS image. If this fails, we continue regardless, but initialize the hardware ourselves. When a kernel gets preloaded we also initialize the hardware, since the BIOS wasn't @@ -146,38 +238,13 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, buf); } - kernel_size = 0; if (kernel_filename) { - kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); - if (kernel_size >= 0) - env->PC = entry; - else { - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - env->PC = KERNEL_LOAD_ADDR; - } - - /* load initrd */ - if (initrd_filename) { - if (load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND) - == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - - /* Store command line. */ - strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); - /* FIXME: little endian support */ - *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); - *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); + load_kernel (env, ram_size, kernel_filename, kernel_cmdline, + initrd_filename); + env->ram_size = ram_size; + env->kernel_filename = kernel_filename; + env->kernel_cmdline = kernel_cmdline; + env->initrd_filename = initrd_filename; } /* Init internal devices */ diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 3ade7bce6..3ac2131a5 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -182,7 +182,6 @@ struct CPUMIPSState { uint32_t CP0_ErrorEPC; uint32_t CP0_DESAVE; /* Qemu */ - struct QEMUTimer *timer; /* Internal timer */ int interrupt_request; jmp_buf jmp_env; int exception_index; @@ -213,6 +212,13 @@ struct CPUMIPSState { int halted; /* TRUE if the CPU is in suspend state */ CPU_COMMON + + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; + + struct QEMUTimer *timer; /* Internal timer */ }; #include "cpu-all.h" diff --git a/target-mips/translate.c b/target-mips/translate.c index 0d624185f..07725b344 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2425,7 +2425,16 @@ CPUMIPSState *cpu_mips_init (void) if (!env) return NULL; cpu_exec_init(env); + cpu_reset(env); + return env; +} + +void cpu_reset (CPUMIPSState *env) +{ + memset(env, 0, offsetof(CPUMIPSState, breakpoints)); + tlb_flush(env, 1); + /* Minimal init */ env->PC = 0xBFC00000; #if defined (MIPS_USES_R4K_TLB) @@ -2456,5 +2465,4 @@ CPUMIPSState *cpu_mips_init (void) #ifdef MIPS_USES_FPU env->fcr0 = MIPS_FCR0; #endif - return env; } -- cgit v1.2.3 From 873eb01234e67d27f3719310f7a89892e4727546 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Dec 2006 17:59:07 +0000 Subject: Dynamically translate MIPS mfc0 instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2222 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 3 +- target-mips/op.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++- target-mips/op_helper.c | 158 +++++----------------------------------------- target-mips/translate.c | 151 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 327 insertions(+), 147 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index a1cf685a1..bc330c029 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -66,7 +66,8 @@ void do_maddu (void); void do_msub (void); void do_msubu (void); #endif -void do_mfc0(int reg, int sel); +void do_mfc0_random(void); +void do_mfc0_count(void); void do_mtc0(int reg, int sel); void do_tlbwi (void); void do_tlbwr (void); diff --git a/target-mips/op.c b/target-mips/op.c index 534c90e51..2597e2e3d 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -688,9 +688,167 @@ void op_jnz_T2 (void) } /* CP0 functions */ -void op_mfc0 (void) +void op_mfc0_index (void) { - CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2); + T0 = env->CP0_index; + RETURN(); +} + +void op_mfc0_random (void) +{ + CALL_FROM_TB0(do_mfc0_random); + RETURN(); +} + +void op_mfc0_entrylo0 (void) +{ + T0 = env->CP0_EntryLo0; + RETURN(); +} + +void op_mfc0_entrylo1 (void) +{ + T0 = env->CP0_EntryLo1; + RETURN(); +} + +void op_mfc0_context (void) +{ + T0 = env->CP0_Context; + RETURN(); +} + +void op_mfc0_pagemask (void) +{ + T0 = env->CP0_PageMask; + RETURN(); +} + +void op_mfc0_wired (void) +{ + T0 = env->CP0_Wired; + RETURN(); +} + +void op_mfc0_badvaddr (void) +{ + T0 = env->CP0_BadVAddr; + RETURN(); +} + +void op_mfc0_count (void) +{ + CALL_FROM_TB0(do_mfc0_count); + RETURN(); +} + +void op_mfc0_entryhi (void) +{ + T0 = env->CP0_EntryHi; + RETURN(); +} + +void op_mfc0_compare (void) +{ + T0 = env->CP0_Compare; + RETURN(); +} + +void op_mfc0_status (void) +{ + T0 = env->CP0_Status; + if (env->hflags & MIPS_HFLAG_UM) + T0 |= (1 << CP0St_UM); + if (env->hflags & MIPS_HFLAG_ERL) + T0 |= (1 << CP0St_ERL); + if (env->hflags & MIPS_HFLAG_EXL) + T0 |= (1 << CP0St_EXL); + RETURN(); +} + +void op_mfc0_cause (void) +{ + T0 = env->CP0_Cause; + RETURN(); +} + +void op_mfc0_epc (void) +{ + T0 = env->CP0_EPC; + RETURN(); +} + +void op_mfc0_prid (void) +{ + T0 = env->CP0_PRid; + RETURN(); +} + +void op_mfc0_config0 (void) +{ + T0 = env->CP0_Config0; + RETURN(); +} + +void op_mfc0_config1 (void) +{ + T0 = env->CP0_Config1; + RETURN(); +} + +void op_mfc0_lladdr (void) +{ + T0 = env->CP0_LLAddr >> 4; + RETURN(); +} + +void op_mfc0_watchlo (void) +{ + T0 = env->CP0_WatchLo; + RETURN(); +} + +void op_mfc0_watchhi (void) +{ + T0 = env->CP0_WatchHi; + RETURN(); +} + +void op_mfc0_debug (void) +{ + T0 = env->CP0_Debug; + if (env->hflags & MIPS_HFLAG_DM) + T0 |= 1 << CP0DB_DM; + RETURN(); +} + +void op_mfc0_depc (void) +{ + T0 = env->CP0_DEPC; + RETURN(); +} + +void op_mfc0_taglo (void) +{ + T0 = env->CP0_TagLo; + RETURN(); +} + +void op_mfc0_datalo (void) +{ + T0 = env->CP0_DataLo; + RETURN(); +} + +void op_mfc0_errorepc (void) +{ + T0 = env->CP0_ErrorEPC; + RETURN(); +} + +void op_mfc0_desave (void) +{ + T0 = env->CP0_DESAVE; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index c7d86d016..d3959f380 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -131,10 +131,16 @@ void do_msubu (void) #endif #if defined(CONFIG_USER_ONLY) -void do_mfc0 (int reg, int sel) +void do_mfc0_random (void) { - cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel); + cpu_abort(env, "mfc0 random\n"); } + +void do_mfc0_count (void) +{ + cpu_abort(env, "mfc0 count\n"); +} + void do_mtc0 (int reg, int sel) { cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel); @@ -159,152 +165,18 @@ void do_tlbr (void) { cpu_abort(env, "tlbr\n"); } + #else /* CP0 helpers */ -void do_mfc0 (int reg, int sel) +void do_mfc0_random (void) { - const unsigned char *rn; + T0 = cpu_mips_get_random(env); +} - if (sel != 0 && reg != 16 && reg != 28) { - rn = "invalid"; - goto print; - } - switch (reg) { - case 0: - T0 = env->CP0_index; - rn = "Index"; - break; - case 1: - T0 = cpu_mips_get_random(env); - rn = "Random"; - break; - case 2: - T0 = env->CP0_EntryLo0; - rn = "EntryLo0"; - break; - case 3: - T0 = env->CP0_EntryLo1; - rn = "EntryLo1"; - break; - case 4: - T0 = env->CP0_Context; - rn = "Context"; - break; - case 5: - T0 = env->CP0_PageMask; - rn = "PageMask"; - break; - case 6: - T0 = env->CP0_Wired; - rn = "Wired"; - break; - case 8: - T0 = env->CP0_BadVAddr; - rn = "BadVaddr"; - break; - case 9: - T0 = cpu_mips_get_count(env); - rn = "Count"; - break; - case 10: - T0 = env->CP0_EntryHi; - rn = "EntryHi"; - break; - case 11: - T0 = env->CP0_Compare; - rn = "Compare"; - break; - case 12: - T0 = env->CP0_Status; - if (env->hflags & MIPS_HFLAG_UM) - T0 |= (1 << CP0St_UM); - rn = "Status"; - break; - case 13: - T0 = env->CP0_Cause; - rn = "Cause"; - break; - case 14: - T0 = env->CP0_EPC; - rn = "EPC"; - break; - case 15: - T0 = env->CP0_PRid; - rn = "PRid"; - break; - case 16: - switch (sel) { - case 0: - T0 = env->CP0_Config0; - rn = "Config"; - break; - case 1: - T0 = env->CP0_Config1; - rn = "Config1"; - break; - default: - rn = "Unknown config register"; - break; - } - break; - case 17: - T0 = env->CP0_LLAddr >> 4; - rn = "LLAddr"; - break; - case 18: - T0 = env->CP0_WatchLo; - rn = "WatchLo"; - break; - case 19: - T0 = env->CP0_WatchHi; - rn = "WatchHi"; - break; - case 23: - T0 = env->CP0_Debug; - if (env->hflags & MIPS_HFLAG_DM) - T0 |= 1 << CP0DB_DM; - rn = "Debug"; - break; - case 24: - T0 = env->CP0_DEPC; - rn = "DEPC"; - break; - case 28: - switch (sel) { - case 0: - T0 = env->CP0_TagLo; - rn = "TagLo"; - break; - case 1: - T0 = env->CP0_DataLo; - rn = "DataLo"; - break; - default: - rn = "unknown sel"; - break; - } - break; - case 30: - T0 = env->CP0_ErrorEPC; - rn = "ErrorEPC"; - break; - case 31: - T0 = env->CP0_DESAVE; - rn = "DESAVE"; - break; - default: - rn = "unknown"; - break; - } - print: -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n", - env->PC, rn, T0, reg, sel); - } -#endif - return; +void do_mfc0_count (void) +{ + T0 = cpu_mips_get_count(env); } void do_mtc0 (int reg, int sel) diff --git a/target-mips/translate.c b/target-mips/translate.c index 07725b344..e1c8bd4c7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1349,6 +1349,155 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, } /* CP0 (MMU and control) */ +static void gen_mfc0 (DisasContext *ctx, int reg, int sel) +{ + const unsigned char *rn; + + if (sel != 0 && reg != 16 && reg != 28) { + rn = "invalid"; + goto die; + } + switch (reg) { + case 0: + gen_op_mfc0_index(); + rn = "Index"; + break; + case 1: + gen_op_mfc0_random(); + rn = "Random"; + break; + case 2: + gen_op_mfc0_entrylo0(); + rn = "EntryLo0"; + break; + case 3: + gen_op_mfc0_entrylo1(); + rn = "EntryLo1"; + break; + case 4: + gen_op_mfc0_context(); + rn = "Context"; + break; + case 5: + gen_op_mfc0_pagemask(); + rn = "PageMask"; + break; + case 6: + gen_op_mfc0_wired(); + rn = "Wired"; + break; + case 8: + gen_op_mfc0_badvaddr(); + rn = "BadVaddr"; + break; + case 9: + gen_op_mfc0_count(); + rn = "Count"; + break; + case 10: + gen_op_mfc0_entryhi(); + rn = "EntryHi"; + break; + case 11: + gen_op_mfc0_compare(); + rn = "Compare"; + break; + case 12: + gen_op_mfc0_status(); + rn = "Status"; + break; + case 13: + gen_op_mfc0_cause(); + rn = "Cause"; + break; + case 14: + gen_op_mfc0_epc(); + rn = "EPC"; + break; + case 15: + gen_op_mfc0_prid(); + rn = "PRid"; + break; + case 16: + switch (sel) { + case 0: + gen_op_mfc0_config0(); + rn = "Config"; + break; + case 1: + gen_op_mfc0_config1(); + rn = "Config1"; + break; + default: + rn = "Unknown config register"; + goto die; + } + break; + case 17: + gen_op_mfc0_lladdr(); + rn = "LLAddr"; + break; + case 18: + gen_op_mfc0_watchlo(); + rn = "WatchLo"; + break; + case 19: + gen_op_mfc0_watchhi(); + rn = "WatchHi"; + break; + case 23: + gen_op_mfc0_debug(); + rn = "Debug"; + break; + case 24: + gen_op_mfc0_depc(); + rn = "DEPC"; + break; + case 28: + switch (sel) { + case 0: + gen_op_mfc0_taglo(); + rn = "TagLo"; + break; + case 1: + gen_op_mfc0_datalo(); + rn = "DataLo"; + break; + default: + rn = "unknown sel"; + goto die; + } + break; + case 30: + gen_op_mfc0_errorepc(); + rn = "ErrorEPC"; + break; + case 31: + gen_op_mfc0_desave(); + rn = "DESAVE"; + break; + default: + rn = "unknown"; + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n", + env->PC, rn, T0, reg, sel); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n", + env->PC, rn, T0, reg, sel); + } +#endif + generate_exception(ctx, EXCP_RI); +} + static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) { const unsigned char *opn = "unk"; @@ -1370,7 +1519,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) /* Treat as NOP */ return; } - gen_op_mfc0(rd, ctx->opcode & 0x7); + gen_mfc0(ctx, rd, ctx->opcode & 0x7); gen_op_store_T0_gpr(rt); opn = "mfc0"; break; -- cgit v1.2.3 From 8c0fdd856c63eb11ec5ef955731b1b0cda51f967 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Dec 2006 18:19:33 +0000 Subject: Dynamically translate MIPS mtc0 instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2223 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 3 +- target-mips/op.c | 180 ++++++++++++++++++++++++++++++++++- target-mips/op_helper.c | 247 ++++++------------------------------------------ target-mips/translate.c | 213 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 423 insertions(+), 220 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index bc330c029..e39f70f87 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -68,7 +68,8 @@ void do_msubu (void); #endif void do_mfc0_random(void); void do_mfc0_count(void); -void do_mtc0(int reg, int sel); +void do_mtc0_status_debug(uint32_t old, uint32_t val); +void do_mtc0_status_irqraise_debug(void); void do_tlbwi (void); void do_tlbwr (void); void do_tlbp (void); diff --git a/target-mips/op.c b/target-mips/op.c index 2597e2e3d..7a5772834 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -852,9 +852,185 @@ void op_mfc0_desave (void) RETURN(); } -void op_mtc0 (void) +void op_mtc0_index (void) { - CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2); + env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F); + RETURN(); +} + +void op_mtc0_entrylo0 (void) +{ + env->CP0_EntryLo0 = T0 & 0x3FFFFFFF; + RETURN(); +} + +void op_mtc0_entrylo1 (void) +{ + env->CP0_EntryLo1 = T0 & 0x3FFFFFFF; + RETURN(); +} + +void op_mtc0_context (void) +{ + env->CP0_Context = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0); + RETURN(); +} + +void op_mtc0_pagemask (void) +{ + env->CP0_PageMask = T0 & 0x01FFE000; + RETURN(); +} + +void op_mtc0_wired (void) +{ + env->CP0_Wired = T0 & 0x0000000F; + RETURN(); +} + +void op_mtc0_count (void) +{ + CALL_FROM_TB2(cpu_mips_store_count, env, T0); + RETURN(); +} + +void op_mtc0_entryhi (void) +{ + uint32_t old, val; + + val = T0 & 0xFFFFE0FF; + old = env->CP0_EntryHi; + env->CP0_EntryHi = val; + /* If the ASID changes, flush qemu's TLB. */ + if ((old & 0xFF) != (val & 0xFF)) + CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1); + RETURN(); +} + +void op_mtc0_compare (void) +{ + CALL_FROM_TB2(cpu_mips_store_compare, env, T0); + RETURN(); +} + +void op_mtc0_status (void) +{ + uint32_t val, old, mask; + + val = T0 & 0xFA78FF01; + old = env->CP0_Status; + if (T0 & (1 << CP0St_UM)) + env->hflags |= MIPS_HFLAG_UM; + else + env->hflags &= ~MIPS_HFLAG_UM; + if (T0 & (1 << CP0St_ERL)) + env->hflags |= MIPS_HFLAG_ERL; + else + env->hflags &= ~MIPS_HFLAG_ERL; + if (T0 & (1 << CP0St_EXL)) + env->hflags |= MIPS_HFLAG_EXL; + else + env->hflags &= ~MIPS_HFLAG_EXL; + env->CP0_Status = val; + /* If we unmasked an asserted IRQ, raise it */ + mask = 0x0000FF00; + if (loglevel & CPU_LOG_TB_IN_ASM) + CALL_FROM_TB2(do_mtc0_status_debug, old, val); + if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) && + !(env->hflags & MIPS_HFLAG_EXL) && + !(env->hflags & MIPS_HFLAG_ERL) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & env->CP0_Cause & mask)) { + env->interrupt_request |= CPU_INTERRUPT_HARD; + if (logfile) + CALL_FROM_TB0(do_mtc0_status_irqraise_debug); + } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) { + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + } + RETURN(); +} + +void op_mtc0_cause (void) +{ + uint32_t val, old; + + val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300); + old = env->CP0_Cause; + env->CP0_Cause = val; +#if 0 + { + int i, mask; + + /* Check if we ever asserted a software IRQ */ + for (i = 0; i < 2; i++) { + mask = 0x100 << i; + if ((val & mask) & !(old & mask)) + CALL_FROM_TB1(mips_set_irq, i); + } + } +#endif + RETURN(); +} + +void op_mtc0_epc (void) +{ + env->CP0_EPC = T0; + RETURN(); +} + +void op_mtc0_config0 (void) +{ +#if defined(MIPS_USES_R4K_TLB) + env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001); +#else + env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001); +#endif + RETURN(); +} + +void op_mtc0_watchlo (void) +{ + env->CP0_WatchLo = T0; + RETURN(); +} + +void op_mtc0_watchhi (void) +{ + env->CP0_WatchHi = T0 & 0x40FF0FF8; + RETURN(); +} + +void op_mtc0_debug (void) +{ + env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120); + if (T0 & (1 << CP0DB_DM)) + env->hflags |= MIPS_HFLAG_DM; + else + env->hflags &= ~MIPS_HFLAG_DM; + RETURN(); +} + +void op_mtc0_depc (void) +{ + env->CP0_DEPC = T0; + RETURN(); +} + +void op_mtc0_taglo (void) +{ + env->CP0_TagLo = T0 & 0xFFFFFCF6; + RETURN(); +} + +void op_mtc0_errorepc (void) +{ + env->CP0_ErrorEPC = T0; + RETURN(); +} + +void op_mtc0_desave (void) +{ + env->CP0_DESAVE = T0; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d3959f380..11e12c0d8 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -141,9 +141,24 @@ void do_mfc0_count (void) cpu_abort(env, "mfc0 count\n"); } -void do_mtc0 (int reg, int sel) +void cpu_mips_store_count(CPUState *env, uint32_t value) { - cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel); + cpu_abort(env, "mtc0 count\n"); +} + +void cpu_mips_store_compare(CPUState *env, uint32_t value) +{ + cpu_abort(env, "mtc0 compare\n"); +} + +void do_mtc0_status_debug(uint32_t old, uint32_t val) +{ + cpu_abort(env, "mtc0 status\n"); +} + +void do_mtc0_status_irqraise_debug(void) +{ + cpu_abort(env, "mtc0 status\n"); } void do_tlbwi (void) @@ -166,6 +181,11 @@ void do_tlbr (void) cpu_abort(env, "tlbr\n"); } +void cpu_mips_tlb_flush (CPUState *env, int flush_global) +{ + cpu_abort(env, "mips_tlb_flush\n"); +} + #else /* CP0 helpers */ @@ -179,222 +199,17 @@ void do_mfc0_count (void) T0 = cpu_mips_get_count(env); } -void do_mtc0 (int reg, int sel) +void do_mtc0_status_debug(uint32_t old, uint32_t val) { - const unsigned char *rn; - uint32_t val, old, mask; + const uint32_t mask = 0x0000FF00; + fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n", + old, val, env->CP0_Cause, old & mask, val & mask, + env->CP0_Cause & mask); +} - if (sel != 0 && reg != 16 && reg != 28) { - val = -1; - old = -1; - rn = "invalid"; - goto print; - } - switch (reg) { - case 0: - val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F); - old = env->CP0_index; - env->CP0_index = val; - rn = "Index"; - break; - case 2: - val = T0 & 0x3FFFFFFF; - old = env->CP0_EntryLo0; - env->CP0_EntryLo0 = val; - rn = "EntryLo0"; - break; - case 3: - val = T0 & 0x3FFFFFFF; - old = env->CP0_EntryLo1; - env->CP0_EntryLo1 = val; - rn = "EntryLo1"; - break; - case 4: - val = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0); - old = env->CP0_Context; - env->CP0_Context = val; - rn = "Context"; - break; - case 5: - val = T0 & 0x01FFE000; - old = env->CP0_PageMask; - env->CP0_PageMask = val; - rn = "PageMask"; - break; - case 6: - val = T0 & 0x0000000F; - old = env->CP0_Wired; - env->CP0_Wired = val; - rn = "Wired"; - break; - case 9: - val = T0; - old = cpu_mips_get_count(env); - cpu_mips_store_count(env, val); - rn = "Count"; - break; - case 10: - val = T0 & 0xFFFFE0FF; - old = env->CP0_EntryHi; - env->CP0_EntryHi = val; - /* If the ASID changes, flush qemu's TLB. */ - if ((old & 0xFF) != (val & 0xFF)) - cpu_mips_tlb_flush (env, 1); - rn = "EntryHi"; - break; - case 11: - val = T0; - old = env->CP0_Compare; - cpu_mips_store_compare(env, val); - rn = "Compare"; - break; - case 12: - val = T0 & 0xFA78FF01; - if (T0 & (1 << CP0St_UM)) - env->hflags |= MIPS_HFLAG_UM; - else - env->hflags &= ~MIPS_HFLAG_UM; - if (T0 & (1 << CP0St_ERL)) - env->hflags |= MIPS_HFLAG_ERL; - else - env->hflags &= ~MIPS_HFLAG_ERL; - if (T0 & (1 << CP0St_EXL)) - env->hflags |= MIPS_HFLAG_EXL; - else - env->hflags &= ~MIPS_HFLAG_EXL; - old = env->CP0_Status; - env->CP0_Status = val; - /* If we unmasked an asserted IRQ, raise it */ - mask = 0x0000FF00; - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n", - old, val, env->CP0_Cause, old & mask, val & mask, - env->CP0_Cause & mask); - } - if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) && - !(env->hflags & MIPS_HFLAG_EXL) && - !(env->hflags & MIPS_HFLAG_ERL) && - !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Status & env->CP0_Cause & mask)) { - if (logfile) - fprintf(logfile, "Raise pending IRQs\n"); - env->interrupt_request |= CPU_INTERRUPT_HARD; - } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) { - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - } - rn = "Status"; - break; - case 13: - val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300); - old = env->CP0_Cause; - env->CP0_Cause = val; -#if 0 - { - int i; - /* Check if we ever asserted a software IRQ */ - for (i = 0; i < 2; i++) { - mask = 0x100 << i; - if ((val & mask) & !(old & mask)) - mips_set_irq(i); - } - } -#endif - rn = "Cause"; - break; - case 14: - val = T0; - old = env->CP0_EPC; - env->CP0_EPC = val; - rn = "EPC"; - break; - case 16: - switch (sel) { - case 0: -#if defined(MIPS_USES_R4K_TLB) - val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001); -#else - val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001); -#endif - old = env->CP0_Config0; - env->CP0_Config0 = val; - rn = "Config0"; - break; - default: - val = -1; - old = -1; - rn = "bad config selector"; - break; - } - break; - case 18: - val = T0; - old = env->CP0_WatchLo; - env->CP0_WatchLo = val; - rn = "WatchLo"; - break; - case 19: - val = T0 & 0x40FF0FF8; - old = env->CP0_WatchHi; - env->CP0_WatchHi = val; - rn = "WatchHi"; - break; - case 23: - val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120); - if (T0 & (1 << CP0DB_DM)) - env->hflags |= MIPS_HFLAG_DM; - else - env->hflags &= ~MIPS_HFLAG_DM; - old = env->CP0_Debug; - env->CP0_Debug = val; - rn = "Debug"; - break; - case 24: - val = T0; - old = env->CP0_DEPC; - env->CP0_DEPC = val; - rn = "DEPC"; - break; - case 28: - switch (sel) { - case 0: - val = T0 & 0xFFFFFCF6; - old = env->CP0_TagLo; - env->CP0_TagLo = val; - rn = "TagLo"; - break; - default: - val = -1; - old = -1; - rn = "invalid sel"; - break; - } - break; - case 30: - val = T0; - old = env->CP0_ErrorEPC; - env->CP0_ErrorEPC = val; - rn = "EPC"; - break; - case 31: - val = T0; - old = env->CP0_DESAVE; - env->CP0_DESAVE = val; - rn = "DESAVE"; - break; - default: - val = -1; - old = -1; - rn = "unknown"; - break; - } - print: -#if defined MIPS_DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n", - env->PC, rn, T0, val, reg, sel, old); - } -#endif - return; +void do_mtc0_status_irqraise_debug(void) +{ + fprintf(logfile, "Raise pending IRQs\n"); } #ifdef MIPS_USES_FPU diff --git a/target-mips/translate.c b/target-mips/translate.c index e1c8bd4c7..688066710 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1371,6 +1371,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 3: + /* also CONF */ gen_op_mfc0_entrylo1(); rn = "EntryLo1"; break; @@ -1386,6 +1387,10 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) gen_op_mfc0_wired(); rn = "Wired"; break; + case 7: +// gen_op_mfc0_info(); + rn = "Info"; + break; case 8: gen_op_mfc0_badvaddr(); rn = "BadVaddr"; @@ -1445,6 +1450,19 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) gen_op_mfc0_watchhi(); rn = "WatchHi"; break; + case 20: + /* 64 bit only */ +// gen_op_mfc0_xcontext(); + rn = "XContext"; + break; + case 21: +// gen_op_mfc0_framemask(); + rn = "Framemask"; + break; + case 22: +// gen_op_mfc0_diagnostic(); + rn = "'Diagnostic"; + break; case 23: gen_op_mfc0_debug(); rn = "Debug"; @@ -1453,6 +1471,18 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) gen_op_mfc0_depc(); rn = "DEPC"; break; + case 25: +// gen_op_mfc0_performance(); + rn = "Performance"; + break; + case 26: +// gen_op_mfc0_ecc(); + rn = "ECC"; + break; + case 27: +// gen_op_mfc0_cacheerr(); + rn = "CacheErr"; + break; case 28: switch (sel) { case 0: @@ -1468,6 +1498,10 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) goto die; } break; + case 29: +// gen_op_mfc0_taghi(); + rn = "TagHi"; + break; case 30: gen_op_mfc0_errorepc(); rn = "ErrorEPC"; @@ -1498,6 +1532,183 @@ die: generate_exception(ctx, EXCP_RI); } +static void gen_mtc0 (DisasContext *ctx, int reg, int sel) +{ + const unsigned char *rn; + uint32_t val, old; + + if (sel != 0 && reg != 16 && reg != 28) { + val = -1; + old = -1; + rn = "invalid"; + goto die; + } + switch (reg) { + case 0: + gen_op_mtc0_index(); + rn = "Index"; + break; + case 1: +// ignore or except? + rn = "Random"; + break; + case 2: + gen_op_mtc0_entrylo0(); + rn = "EntryLo0"; + break; + case 3: + gen_op_mtc0_entrylo1(); + rn = "EntryLo1"; + break; + case 4: + gen_op_mtc0_context(); + rn = "Context"; + break; + case 5: + gen_op_mtc0_pagemask(); + rn = "PageMask"; + break; + case 6: + gen_op_mtc0_wired(); + rn = "Wired"; + break; + case 7: +// ignore or except? + rn = "Info"; + break; + case 8: +// ignore or except? + rn = "BadVaddr"; + break; + case 9: + gen_op_mtc0_count(); + rn = "Count"; + break; + case 10: + gen_op_mtc0_entryhi(); + rn = "EntryHi"; + break; + case 11: + gen_op_mtc0_compare(); + rn = "Compare"; + break; + case 12: + gen_op_mtc0_status(); + rn = "Status"; + break; + case 13: + gen_op_mtc0_cause(); + rn = "Cause"; + break; + case 14: + gen_op_mtc0_epc(); + rn = "EPC"; + break; + case 15: +// ignore or except? + rn = "PRid"; + break; + case 16: + switch (sel) { + case 0: + gen_op_mtc0_config0(); + rn = "Config0"; + break; + default: + rn = "Invalid config selector"; + goto die; + } + break; + case 17: +// ignore or except? + rn = "LLaddr"; + break; + case 18: + gen_op_mtc0_watchlo(); + rn = "WatchLo"; + break; + case 19: + gen_op_mtc0_watchhi(); + rn = "WatchHi"; + break; + case 20: + /* 64 bit only */ +// gen_op_mtc0_xcontext(); + rn = "XContext"; + break; + case 21: +// gen_op_mtc0_framemask(); + rn = "Framemask"; + break; + case 22: +// ignore or except? + rn = "Diagnostic"; + break; + case 23: + gen_op_mtc0_debug(); + rn = "Debug"; + break; + case 24: + gen_op_mtc0_depc(); + rn = "DEPC"; + break; + case 25: +// ignore or except? + rn = "Performance"; + break; + case 26: +// ignore or except? + rn = "ECC"; + break; + case 27: +// ignore or except? + rn = "CacheErr"; + break; + case 28: + switch (sel) { + case 0: + gen_op_mtc0_taglo(); + rn = "TagLo"; + break; + default: + rn = "invalid sel"; + goto die; + } + break; + case 29: +// gen_op_mtc0_taghi(); + rn = "TagHi"; + break; + case 30: + gen_op_mtc0_errorepc(); + rn = "ErrorEPC"; + break; + case 31: + gen_op_mtc0_desave(); + rn = "DESAVE"; + break; + default: + rn = "unknown"; + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n", + env->PC, rn, T0, reg, sel); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n", + env->PC, rn, T0, reg, sel); + } +#endif + generate_exception(ctx, EXCP_RI); +} + static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) { const unsigned char *opn = "unk"; @@ -1529,7 +1740,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) save_cpu_state(ctx, 1); ctx->pc -= 4; GEN_LOAD_REG_TN(T0, rt); - gen_op_mtc0(rd, ctx->opcode & 0x7); + gen_mtc0(ctx, rd, ctx->opcode & 0x7); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; opn = "mtc0"; -- cgit v1.2.3 From 7a387fffce508fedae82e3e81b90d1f20c02c783 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Dec 2006 20:17:30 +0000 Subject: Add MIPS32R2 instructions, and generally straighten out the instruction decoding. This is also the first percent towards MIPS64 support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2224 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 59 +- target-mips/exec.h | 1 + target-mips/helper.c | 6 - target-mips/mips-defs.h | 50 +- target-mips/op.c | 360 +++++++- target-mips/op_helper.c | 6 +- target-mips/translate.c | 2344 ++++++++++++++++++++++++++++++++++++----------- 7 files changed, 2235 insertions(+), 591 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 3ac2131a5..46436cde3 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -99,14 +99,16 @@ struct CPUMIPSState { #endif uint32_t CP0_index; uint32_t CP0_random; - uint32_t CP0_EntryLo0; - uint32_t CP0_EntryLo1; - uint32_t CP0_Context; + uint64_t CP0_EntryLo0; + uint64_t CP0_EntryLo1; + uint64_t CP0_Context; uint32_t CP0_PageMask; + uint32_t CP0_PageGrain; uint32_t CP0_Wired; + uint32_t CP0_HWREna; uint32_t CP0_BadVAddr; uint32_t CP0_Count; - uint32_t CP0_EntryHi; + uint64_t CP0_EntryHi; uint32_t CP0_Compare; uint32_t CP0_Status; #define CP0St_CU3 31 @@ -116,19 +118,36 @@ struct CPUMIPSState { #define CP0St_RP 27 #define CP0St_FR 26 #define CP0St_RE 25 +#define CP0St_MX 24 +#define CP0St_PX 23 #define CP0St_BEV 22 #define CP0St_TS 21 #define CP0St_SR 20 #define CP0St_NMI 19 #define CP0St_IM 8 +#define CP0St_KX 7 +#define CP0St_SX 6 +#define CP0St_UX 5 #define CP0St_UM 4 +#define CP0St_R0 3 #define CP0St_ERL 2 #define CP0St_EXL 1 #define CP0St_IE 0 + uint32_t CP0_IntCtl; + uint32_t CP0_SRSCtl; uint32_t CP0_Cause; +#define CP0Ca_BD 31 +#define CP0Ca_TI 30 +#define CP0Ca_CE 28 +#define CP0Ca_DC 27 +#define CP0Ca_PCI 26 #define CP0Ca_IV 23 +#define CP0Ca_WP 22 +#define CP0Ca_IP 8 +#define CP0Ca_EC 2 uint32_t CP0_EPC; uint32_t CP0_PRid; + uint32_t CP0_EBase; uint32_t CP0_Config0; #define CP0C0_M 31 #define CP0C0_K23 28 @@ -140,8 +159,10 @@ struct CPUMIPSState { #define CP0C0_AT 13 #define CP0C0_AR 10 #define CP0C0_MT 7 +#define CP0C0_VI 3 #define CP0C0_K0 0 uint32_t CP0_Config1; +#define CP0C1_M 31 #define CP0C1_MMU 25 #define CP0C1_IS 22 #define CP0C1_IL 19 @@ -149,14 +170,38 @@ struct CPUMIPSState { #define CP0C1_DS 13 #define CP0C1_DL 10 #define CP0C1_DA 7 +#define CP0C1_C2 6 +#define CP0C1_MD 5 #define CP0C1_PC 4 #define CP0C1_WR 3 #define CP0C1_CA 2 #define CP0C1_EP 1 #define CP0C1_FP 0 + uint32_t CP0_Config2; +#define CP0C2_M 31 +#define CP0C2_TU 28 +#define CP0C2_TS 24 +#define CP0C2_TL 20 +#define CP0C2_TA 16 +#define CP0C2_SU 12 +#define CP0C2_SS 8 +#define CP0C2_SL 4 +#define CP0C2_SA 0 + uint32_t CP0_Config3; +#define CP0C3_M 31 +#define CP0C3_DSPP 10 +#define CP0C3_LPA 7 +#define CP0C3_VEIC 6 +#define CP0C3_VInt 5 +#define CP0C3_SP 4 +#define CP0C3_MT 2 +#define CP0C3_SM 1 +#define CP0C3_TL 0 uint32_t CP0_LLAddr; uint32_t CP0_WatchLo; uint32_t CP0_WatchHi; + uint32_t CP0_XContext; + uint32_t CP0_Framemask; uint32_t CP0_Debug; #define CPDB_DBD 31 #define CP0DB_DM 30 @@ -177,8 +222,11 @@ struct CPUMIPSState { #define CP0DB_DBp 1 #define CP0DB_DSS 0 uint32_t CP0_DEPC; + uint32_t CP0_Performance0; uint32_t CP0_TagLo; uint32_t CP0_DataLo; + uint32_t CP0_TagHi; + uint32_t CP0_DataHi; uint32_t CP0_ErrorEPC; uint32_t CP0_DESAVE; /* Qemu */ @@ -211,6 +259,9 @@ struct CPUMIPSState { int halted; /* TRUE if the CPU is in suspend state */ + int SYNCI_Step; /* Address step size for SYNCI */ + int CCRes; /* Cycle count resolution/divisor */ + CPU_COMMON int ram_size; diff --git a/target-mips/exec.h b/target-mips/exec.h index e39f70f87..817ef0346 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -68,6 +68,7 @@ void do_msubu (void); #endif void do_mfc0_random(void); void do_mfc0_count(void); +void do_mtc0_entryhi(uint32_t in); void do_mtc0_status_debug(uint32_t old, uint32_t val); void do_mtc0_status_irqraise_debug(void); void do_tlbwi (void); diff --git a/target-mips/helper.c b/target-mips/helper.c index 57318a5a3..6b73cb821 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -302,15 +302,9 @@ void do_interrupt (CPUState *env) #endif env->CP0_Wired = 0; env->CP0_Config0 = MIPS_CONFIG0; -#if defined (MIPS_CONFIG1) env->CP0_Config1 = MIPS_CONFIG1; -#endif -#if defined (MIPS_CONFIG2) env->CP0_Config2 = MIPS_CONFIG2; -#endif -#if defined (MIPS_CONFIG3) env->CP0_Config3 = MIPS_CONFIG3; -#endif env->CP0_WatchLo = 0; env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV); goto set_error_EPC; diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 63e64bbdc..14d1438bc 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -29,26 +29,44 @@ * Define a major version 1, minor version 0. */ #define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0) -/* Have config1, uses TLB */ -#define MIPS_CONFIG0_1 \ -((1 << CP0C0_M) | (0 << CP0C0_K23) | (0 << CP0C0_KU) | \ - (1 << CP0C0_MT) | (2 << CP0C0_K0)) + /* Have config1, is MIPS32R1, uses TLB, no virtual icache, + uncached coherency */ +#define MIPS_CONFIG0_1 \ + ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) | \ + (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) | \ + (0x2 << CP0C0_K0)) #ifdef TARGET_WORDS_BIGENDIAN #define MIPS_CONFIG0 (MIPS_CONFIG0_1 | (1 << CP0C0_BE)) #else #define MIPS_CONFIG0 MIPS_CONFIG0_1 #endif -/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache, - * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, - * no performance counters, watch registers present, no code compression, - * EJTAG present, FPU enable bit depending on MIPS_USES_FPU - */ -#define MIPS_CONFIG1 \ -((15 << CP0C1_MMU) | \ - (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \ - (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \ - (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \ - (1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP)) +/* Have config2, 16 TLB entries, 64 sets Icache, 16 bytes Icache line, + 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, + no coprocessor2 attached, no MDMX support attached, + no performance counters, watch registers present, + no code compression, EJTAG present, FPU enable bit depending on + MIPS_USES_FPU */ +#define MIPS_CONFIG1_1 \ +((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) | \ + (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \ + (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \ + (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \ + (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP)) +#ifdef MIPS_USES_FPU +#define MIPS_CONFIG1 (MIPS_CONFIG1_1 | (1 << CP0C1_FP)) +#else +#define MIPS_CONFIG1 (MIPS_CONFIG1_1 | (0 << CP0C1_FP)) +#endif +/* Have config3, no tertiary/secondary caches implemented */ +#define MIPS_CONFIG2 \ +((1 << CP0C2_M)) +/* No config4, no DSP ASE, no large physaddr, + no external interrupt controller, no vectored interupts, + no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */ +#define MIPS_CONFIG3 \ +((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \ + (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \ + (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL)) #elif (MIPS_CPU == MIPS_R4Kp) /* 32 bits target */ #define TARGET_LONG_BITS 32 @@ -60,7 +78,7 @@ #define MIPS_USES_R4K_FPM #else #error "MIPS CPU not defined" -/* Remainder for other flags */ +/* Reminder for other flags */ //#define TARGET_MIPS64 //#define MIPS_USES_FPU #endif diff --git a/target-mips/op.c b/target-mips/op.c index 7a5772834..84fcbd9e0 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -437,6 +437,18 @@ void op_srl (void) RETURN(); } +void op_rotr (void) +{ + target_ulong tmp; + + if (T1) { + tmp = T0 << (0x20 - T1); + T0 = (T0 >> T1) | tmp; + } else + T0 = T1; + RETURN(); +} + void op_sllv (void) { T0 = T1 << (T0 & 0x1F); @@ -455,6 +467,19 @@ void op_srlv (void) RETURN(); } +void op_rotrv (void) +{ + target_ulong tmp; + + T0 &= 0x1F; + if (T0) { + tmp = T1 << (0x20 - T0); + T0 = (T1 >> T0) | tmp; + } else + T0 = T1; + RETURN(); +} + void op_clo (void) { int n; @@ -602,6 +627,20 @@ void op_movz (void) RETURN(); } +void op_movf (void) +{ + if (!(env->fcr31 & PARAM1)) + env->gpr[PARAM2] = env->gpr[PARAM3]; + RETURN(); +} + +void op_movt (void) +{ + if (env->fcr31 & PARAM1) + env->gpr[PARAM2] = env->gpr[PARAM3]; + RETURN(); +} + /* Tests */ #define OP_COND(name, cond) \ void glue(op_, name) (void) \ @@ -625,28 +664,32 @@ OP_COND(gtz, (int32_t)T0 > 0); OP_COND(lez, (int32_t)T0 <= 0); OP_COND(ltz, (int32_t)T0 < 0); -/* Branchs */ +/* Branches */ //#undef USE_DIRECT_JUMP void OPPROTO op_goto_tb0(void) { GOTO_TB(op_goto_tb0, PARAM1, 0); + RETURN(); } void OPPROTO op_goto_tb1(void) { GOTO_TB(op_goto_tb1, PARAM1, 1); + RETURN(); } /* Branch to register */ void op_save_breg_target (void) { env->btarget = T2; + RETURN(); } void op_restore_breg_target (void) { T2 = env->btarget; + RETURN(); } void op_breg (void) @@ -724,12 +767,24 @@ void op_mfc0_pagemask (void) RETURN(); } +void op_mfc0_pagegrain (void) +{ + T0 = env->CP0_PageGrain; + RETURN(); +} + void op_mfc0_wired (void) { T0 = env->CP0_Wired; RETURN(); } +void op_mfc0_hwrena (void) +{ + T0 = env->CP0_HWREna; + RETURN(); +} + void op_mfc0_badvaddr (void) { T0 = env->CP0_BadVAddr; @@ -766,6 +821,18 @@ void op_mfc0_status (void) RETURN(); } +void op_mfc0_intctl (void) +{ + T0 = env->CP0_IntCtl; + RETURN(); +} + +void op_mfc0_srsctl (void) +{ + T0 = env->CP0_SRSCtl; + RETURN(); +} + void op_mfc0_cause (void) { T0 = env->CP0_Cause; @@ -784,6 +851,12 @@ void op_mfc0_prid (void) RETURN(); } +void op_mfc0_ebase (void) +{ + T0 = env->CP0_EBase; + RETURN(); +} + void op_mfc0_config0 (void) { T0 = env->CP0_Config0; @@ -796,24 +869,48 @@ void op_mfc0_config1 (void) RETURN(); } +void op_mfc0_config2 (void) +{ + T0 = env->CP0_Config2; + RETURN(); +} + +void op_mfc0_config3 (void) +{ + T0 = env->CP0_Config3; + RETURN(); +} + void op_mfc0_lladdr (void) { T0 = env->CP0_LLAddr >> 4; RETURN(); } -void op_mfc0_watchlo (void) +void op_mfc0_watchlo0 (void) { T0 = env->CP0_WatchLo; RETURN(); } -void op_mfc0_watchhi (void) +void op_mfc0_watchhi0 (void) { T0 = env->CP0_WatchHi; RETURN(); } +void op_mfc0_xcontext (void) +{ + T0 = env->CP0_XContext; + RETURN(); +} + +void op_mfc0_framemask (void) +{ + T0 = env->CP0_Framemask; + RETURN(); +} + void op_mfc0_debug (void) { T0 = env->CP0_Debug; @@ -828,6 +925,12 @@ void op_mfc0_depc (void) RETURN(); } +void op_mfc0_performance0 (void) +{ + T0 = env->CP0_Performance0; + RETURN(); +} + void op_mfc0_taglo (void) { T0 = env->CP0_TagLo; @@ -840,6 +943,18 @@ void op_mfc0_datalo (void) RETURN(); } +void op_mfc0_taghi (void) +{ + T0 = env->CP0_TagHi; + RETURN(); +} + +void op_mfc0_datahi (void) +{ + T0 = env->CP0_DataHi; + RETURN(); +} + void op_mfc0_errorepc (void) { T0 = env->CP0_ErrorEPC; @@ -854,37 +969,57 @@ void op_mfc0_desave (void) void op_mtc0_index (void) { - env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F); + env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & (MIPS_TLB_NB - 1)); RETURN(); } void op_mtc0_entrylo0 (void) { - env->CP0_EntryLo0 = T0 & 0x3FFFFFFF; + /* Large physaddr not implemented */ + /* 1k pages not implemented */ + env->CP0_EntryLo0 = T0 & 0x3FFFFFFFUL; RETURN(); } void op_mtc0_entrylo1 (void) { - env->CP0_EntryLo1 = T0 & 0x3FFFFFFF; + /* Large physaddr not implemented */ + /* 1k pages not implemented */ + env->CP0_EntryLo1 = T0 & 0x3FFFFFFFUL; RETURN(); } void op_mtc0_context (void) { - env->CP0_Context = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0); + env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0); RETURN(); } void op_mtc0_pagemask (void) { - env->CP0_PageMask = T0 & 0x01FFE000; + /* 1k pages not implemented */ + env->CP0_PageMask = T0 & 0x1FFFE000; + RETURN(); +} + +void op_mtc0_pagegrain (void) +{ + /* SmartMIPS not implemented */ + /* Large physaddr not implemented */ + /* 1k pages not implemented */ + env->CP0_PageGrain = 0; RETURN(); } void op_mtc0_wired (void) { - env->CP0_Wired = T0 & 0x0000000F; + env->CP0_Wired = T0 & (MIPS_TLB_NB - 1); + RETURN(); +} + +void op_mtc0_hwrena (void) +{ + env->CP0_HWREna = T0 & 0x0000000F; RETURN(); } @@ -898,6 +1033,8 @@ void op_mtc0_entryhi (void) { uint32_t old, val; + /* 1k pages not implemented */ + /* Ignore MIPS64 TLB for now */ val = T0 & 0xFFFFE0FF; old = env->CP0_EntryHi; env->CP0_EntryHi = val; @@ -950,6 +1087,20 @@ void op_mtc0_status (void) RETURN(); } +void op_mtc0_intctl (void) +{ + /* vectored interrupts not implemented */ + env->CP0_IntCtl = 0; + RETURN(); +} + +void op_mtc0_srsctl (void) +{ + /* shadow registers not implemented */ + env->CP0_SRSCtl = 0; + RETURN(); +} + void op_mtc0_cause (void) { uint32_t val, old; @@ -960,7 +1111,6 @@ void op_mtc0_cause (void) #if 0 { int i, mask; - /* Check if we ever asserted a software IRQ */ for (i = 0; i < 2; i++) { mask = 0x100 << i; @@ -978,28 +1128,56 @@ void op_mtc0_epc (void) RETURN(); } +void op_mtc0_ebase (void) +{ + /* vectored interrupts not implemented */ + /* Multi-CPU not implemented */ + env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000); + RETURN(); +} + void op_mtc0_config0 (void) { #if defined(MIPS_USES_R4K_TLB) - env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001); + /* Fixed mapping MMU not implemented */ + env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF88) | (T0 & 0x00000001); #else - env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001); + env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF88) | (T0 & 0x00000001); #endif RETURN(); } -void op_mtc0_watchlo (void) +void op_mtc0_config2 (void) +{ + /* tertiary/secondary caches not implemented */ + env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); + RETURN(); +} + +void op_mtc0_watchlo0 (void) { env->CP0_WatchLo = T0; RETURN(); } -void op_mtc0_watchhi (void) +void op_mtc0_watchhi0 (void) { env->CP0_WatchHi = T0 & 0x40FF0FF8; RETURN(); } +void op_mtc0_xcontext (void) +{ + env->CP0_XContext = T0; /* XXX */ + RETURN(); +} + +void op_mtc0_framemask (void) +{ + env->CP0_Framemask = T0; /* XXX */ + RETURN(); +} + void op_mtc0_debug (void) { env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120); @@ -1016,12 +1194,36 @@ void op_mtc0_depc (void) RETURN(); } +void op_mtc0_performance0 (void) +{ + env->CP0_Performance0 = T0; /* XXX */ + RETURN(); +} + void op_mtc0_taglo (void) { env->CP0_TagLo = T0 & 0xFFFFFCF6; RETURN(); } +void op_mtc0_datalo (void) +{ + env->CP0_DataLo = T0; /* XXX */ + RETURN(); +} + +void op_mtc0_taghi (void) +{ + env->CP0_TagHi = T0; /* XXX */ + RETURN(); +} + +void op_mtc0_datahi (void) +{ + env->CP0_DataHi = T0; /* XXX */ + RETURN(); +} + void op_mtc0_errorepc (void) { env->CP0_ErrorEPC = T0; @@ -1422,6 +1624,42 @@ void op_tlbr (void) void op_pmon (void) { CALL_FROM_TB1(do_pmon, PARAM1); + RETURN(); +} + +void op_di (void) +{ + uint32_t val; + + T0 = env->CP0_Status; + val = T0 & ~(1 << CP0St_IE); + if (val != T0) { + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + env->CP0_Status = val; + } + RETURN(); +} + +void op_ei (void) +{ + uint32_t val; + + T0 = env->CP0_Status; + val = T0 | (1 << CP0St_IE); + if (val != T0) { + const uint32_t mask = 0x0000FF00; + + env->CP0_Status = val; + if (!(env->hflags & MIPS_HFLAG_EXL) && + !(env->hflags & MIPS_HFLAG_ERL) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & env->CP0_Cause & mask)) { + env->interrupt_request |= CPU_INTERRUPT_HARD; + if (logfile) + CALL_FROM_TB0(do_mtc0_status_irqraise_debug); + } + } + RETURN(); } void op_trap (void) @@ -1434,12 +1672,14 @@ void op_trap (void) void op_debug (void) { - CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG); + CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG); + RETURN(); } void op_set_lladdr (void) { env->CP0_LLAddr = T2; + RETURN(); } void debug_eret (void); @@ -1456,12 +1696,50 @@ void op_eret (void) env->CP0_Status &= ~(1 << CP0St_EXL); } env->CP0_LLAddr = 1; + RETURN(); } void op_deret (void) { CALL_FROM_TB0(debug_eret); env->PC = env->CP0_DEPC; + RETURN(); +} + +void op_rdhwr_cpunum(void) +{ + if (env->CP0_HWREna & (1 << 0)) + T0 = env->CP0_EBase & 0x2ff; + else + CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI); + RETURN(); +} + +void op_rdhwr_synci_step(void) +{ + if (env->CP0_HWREna & (1 << 1)) + T0 = env->SYNCI_Step; + else + CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI); + RETURN(); +} + +void op_rdhwr_cc(void) +{ + if (env->CP0_HWREna & (1 << 2)) + T0 = env->CP0_Count; + else + CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI); + RETURN(); +} + +void op_rdhwr_ccres(void) +{ + if (env->CP0_HWREna & (1 << 3)) + T0 = env->CCRes; + else + CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI); + RETURN(); } void op_save_state (void) @@ -1491,10 +1769,62 @@ void op_raise_exception_err (void) void op_exit_tb (void) { EXIT_TB(); + RETURN(); } void op_wait (void) { env->halted = 1; CALL_FROM_TB1(do_raise_exception, EXCP_HLT); + RETURN(); +} + +/* Bitfield operations. */ +void op_ext(void) +{ + unsigned int pos = PARAM1; + unsigned int size = PARAM2; + + T0 = (T1 >> pos) & ((1 << size) - 1); + RETURN(); +} + +void op_ins(void) +{ + unsigned int pos = PARAM1; + unsigned int size = PARAM2; + target_ulong mask = ((1 << size) - 1) << pos; + + T0 = (T2 & ~mask) | ((T1 << pos) & mask); + RETURN(); +} + +void op_wsbh(void) +{ + T0 = ((T1 << 8) & ~0x00FF00FF) | ((T1 >> 8) & 0x00FF00FF); + RETURN(); +} + +void op_dsbh(void) +{ + T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL); + RETURN(); +} + +void op_dshd(void) +{ + T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL); + RETURN(); +} + +void op_seb(void) +{ + T0 = ((T1 & 0xFF) ^ 0x80) - 0x80; + RETURN(); +} + +void op_seh(void) +{ + T0 = ((T1 & 0xFFFF) ^ 0x8000) - 0x8000; + RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 11e12c0d8..87a043dc2 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -153,12 +153,12 @@ void cpu_mips_store_compare(CPUState *env, uint32_t value) void do_mtc0_status_debug(uint32_t old, uint32_t val) { - cpu_abort(env, "mtc0 status\n"); + cpu_abort(env, "mtc0 status debug\n"); } -void do_mtc0_status_irqraise_debug(void) +void do_mtc0_status_irqraise_debug (void) { - cpu_abort(env, "mtc0 status\n"); + cpu_abort(env, "mtc0 status irqraise debug\n"); } void do_tlbwi (void) diff --git a/target-mips/translate.c b/target-mips/translate.c index 688066710..d54c63336 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -50,184 +50,313 @@ static uint32_t *gen_opparam_ptr; #include "gen-op.h" -/* MIPS opcodes */ -#define EXT_SPECIAL 0x100 -#define EXT_SPECIAL2 0x200 -#define EXT_REGIMM 0x300 -#define EXT_CP0 0x400 -#define EXT_CP1 0x500 -#define EXT_CP2 0x600 -#define EXT_CP3 0x700 +/* MIPS major opcodes */ +#define MASK_OP_MAJOR(op) (op & (0x3F << 26)) enum { /* indirect opcode tables */ - OPC_SPECIAL = 0x00, - OPC_BREGIMM = 0x01, - OPC_CP0 = 0x10, - OPC_CP1 = 0x11, - OPC_CP2 = 0x12, - OPC_CP3 = 0x13, - OPC_SPECIAL2 = 0x1C, + OPC_SPECIAL = (0x00 << 26), + OPC_REGIMM = (0x01 << 26), + OPC_CP0 = (0x10 << 26), + OPC_CP1 = (0x11 << 26), + OPC_CP2 = (0x12 << 26), + OPC_CP3 = (0x13 << 26), + OPC_SPECIAL2 = (0x1C << 26), + OPC_SPECIAL3 = (0x1F << 26), /* arithmetic with immediate */ - OPC_ADDI = 0x08, - OPC_ADDIU = 0x09, - OPC_SLTI = 0x0A, - OPC_SLTIU = 0x0B, - OPC_ANDI = 0x0C, - OPC_ORI = 0x0D, - OPC_XORI = 0x0E, - OPC_LUI = 0x0F, + OPC_ADDI = (0x08 << 26), + OPC_ADDIU = (0x09 << 26), + OPC_SLTI = (0x0A << 26), + OPC_SLTIU = (0x0B << 26), + OPC_ANDI = (0x0C << 26), + OPC_ORI = (0x0D << 26), + OPC_XORI = (0x0E << 26), + OPC_LUI = (0x0F << 26), + OPC_DADDI = (0x18 << 26), + OPC_DADDIU = (0x19 << 26), /* Jump and branches */ - OPC_J = 0x02, - OPC_JAL = 0x03, - OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */ - OPC_BEQL = 0x14, - OPC_BNE = 0x05, - OPC_BNEL = 0x15, - OPC_BLEZ = 0x06, - OPC_BLEZL = 0x16, - OPC_BGTZ = 0x07, - OPC_BGTZL = 0x17, - OPC_JALX = 0x1D, /* MIPS 16 only */ + OPC_J = (0x02 << 26), + OPC_JAL = (0x03 << 26), + OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ + OPC_BEQL = (0x14 << 26), + OPC_BNE = (0x05 << 26), + OPC_BNEL = (0x15 << 26), + OPC_BLEZ = (0x06 << 26), + OPC_BLEZL = (0x16 << 26), + OPC_BGTZ = (0x07 << 26), + OPC_BGTZL = (0x17 << 26), + OPC_JALX = (0x1D << 26), /* MIPS 16 only */ /* Load and stores */ - OPC_LB = 0x20, - OPC_LH = 0x21, - OPC_LWL = 0x22, - OPC_LW = 0x23, - OPC_LBU = 0x24, - OPC_LHU = 0x25, - OPC_LWR = 0x26, - OPC_LWU = 0x27, - OPC_SB = 0x28, - OPC_SH = 0x29, - OPC_SWL = 0x2A, - OPC_SW = 0x2B, - OPC_SWR = 0x2E, - OPC_LL = 0x30, - OPC_SC = 0x38, + OPC_LDL = (0x1A << 26), + OPC_LDR = (0x1B << 26), + OPC_LB = (0x20 << 26), + OPC_LH = (0x21 << 26), + OPC_LWL = (0x22 << 26), + OPC_LW = (0x23 << 26), + OPC_LBU = (0x24 << 26), + OPC_LHU = (0x25 << 26), + OPC_LWR = (0x26 << 26), + OPC_LWU = (0x27 << 26), + OPC_SB = (0x28 << 26), + OPC_SH = (0x29 << 26), + OPC_SWL = (0x2A << 26), + OPC_SW = (0x2B << 26), + OPC_SDL = (0x2C << 26), + OPC_SDR = (0x2D << 26), + OPC_SWR = (0x2E << 26), + OPC_LL = (0x30 << 26), + OPC_LLD = (0x34 << 26), + OPC_LD = (0x37 << 26), + OPC_SC = (0x38 << 26), + OPC_SCD = (0x3C << 26), + OPC_SD = (0x3F << 26), /* Floating point load/store */ - OPC_LWC1 = 0x31, - OPC_LWC2 = 0x32, - OPC_LDC1 = 0x35, - OPC_LDC2 = 0x36, - OPC_SWC1 = 0x39, - OPC_SWC2 = 0x3A, - OPC_SDC1 = 0x3D, - OPC_SDC2 = 0x3E, + OPC_LWC1 = (0x31 << 26), + OPC_LWC2 = (0x32 << 26), + OPC_LDC1 = (0x35 << 26), + OPC_LDC2 = (0x36 << 26), + OPC_SWC1 = (0x39 << 26), + OPC_SWC2 = (0x3A << 26), + OPC_SDC1 = (0x3D << 26), + OPC_SDC2 = (0x3E << 26), + /* MDMX ASE specific */ + OPC_MDMX = (0x1E << 26), /* Cache and prefetch */ - OPC_CACHE = 0x2F, - OPC_PREF = 0x33, + OPC_CACHE = (0x2F << 26), + OPC_PREF = (0x33 << 26), + /* Reserved major opcode */ + OPC_MAJOR3B_RESERVED = (0x3B << 26), }; /* MIPS special opcodes */ +#define MASK_SPECIAL(op) MASK_OP_MAJOR(op) | (op & 0x3F) + enum { /* Shifts */ - OPC_SLL = 0x00 | EXT_SPECIAL, + OPC_SLL = 0x00 | OPC_SPECIAL, /* NOP is SLL r0, r0, 0 */ /* SSNOP is SLL r0, r0, 1 */ - OPC_SRL = 0x02 | EXT_SPECIAL, - OPC_SRA = 0x03 | EXT_SPECIAL, - OPC_SLLV = 0x04 | EXT_SPECIAL, - OPC_SRLV = 0x06 | EXT_SPECIAL, - OPC_SRAV = 0x07 | EXT_SPECIAL, + /* EHB is SLL r0, r0, 3 */ + OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */ + OPC_SRA = 0x03 | OPC_SPECIAL, + OPC_SLLV = 0x04 | OPC_SPECIAL, + OPC_SRLV = 0x06 | OPC_SPECIAL, + OPC_SRAV = 0x07 | OPC_SPECIAL, + OPC_DSLLV = 0x14 | OPC_SPECIAL, + OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */ + OPC_DSRAV = 0x17 | OPC_SPECIAL, + OPC_DSLL = 0x38 | OPC_SPECIAL, + OPC_DSRL = 0x3A | OPC_SPECIAL, /* also DROTR */ + OPC_DSRA = 0x3B | OPC_SPECIAL, + OPC_DSLL32 = 0x3C | OPC_SPECIAL, + OPC_DSRL32 = 0x3E | OPC_SPECIAL, /* also DROTR32 */ + OPC_DSRA32 = 0x3F | OPC_SPECIAL, /* Multiplication / division */ - OPC_MULT = 0x18 | EXT_SPECIAL, - OPC_MULTU = 0x19 | EXT_SPECIAL, - OPC_DIV = 0x1A | EXT_SPECIAL, - OPC_DIVU = 0x1B | EXT_SPECIAL, + OPC_MULT = 0x18 | OPC_SPECIAL, + OPC_MULTU = 0x19 | OPC_SPECIAL, + OPC_DIV = 0x1A | OPC_SPECIAL, + OPC_DIVU = 0x1B | OPC_SPECIAL, + OPC_DMULT = 0x1C | OPC_SPECIAL, + OPC_DMULTU = 0x1D | OPC_SPECIAL, + OPC_DDIV = 0x1E | OPC_SPECIAL, + OPC_DDIVU = 0x1F | OPC_SPECIAL, /* 2 registers arithmetic / logic */ - OPC_ADD = 0x20 | EXT_SPECIAL, - OPC_ADDU = 0x21 | EXT_SPECIAL, - OPC_SUB = 0x22 | EXT_SPECIAL, - OPC_SUBU = 0x23 | EXT_SPECIAL, - OPC_AND = 0x24 | EXT_SPECIAL, - OPC_OR = 0x25 | EXT_SPECIAL, - OPC_XOR = 0x26 | EXT_SPECIAL, - OPC_NOR = 0x27 | EXT_SPECIAL, - OPC_SLT = 0x2A | EXT_SPECIAL, - OPC_SLTU = 0x2B | EXT_SPECIAL, + OPC_ADD = 0x20 | OPC_SPECIAL, + OPC_ADDU = 0x21 | OPC_SPECIAL, + OPC_SUB = 0x22 | OPC_SPECIAL, + OPC_SUBU = 0x23 | OPC_SPECIAL, + OPC_AND = 0x24 | OPC_SPECIAL, + OPC_OR = 0x25 | OPC_SPECIAL, + OPC_XOR = 0x26 | OPC_SPECIAL, + OPC_NOR = 0x27 | OPC_SPECIAL, + OPC_SLT = 0x2A | OPC_SPECIAL, + OPC_SLTU = 0x2B | OPC_SPECIAL, + OPC_DADD = 0x2C | OPC_SPECIAL, + OPC_DADDU = 0x2D | OPC_SPECIAL, + OPC_DSUB = 0x2E | OPC_SPECIAL, + OPC_DSUBU = 0x2F | OPC_SPECIAL, /* Jumps */ - OPC_JR = 0x08 | EXT_SPECIAL, - OPC_JALR = 0x09 | EXT_SPECIAL, + OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */ + OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */ /* Traps */ - OPC_TGE = 0x30 | EXT_SPECIAL, - OPC_TGEU = 0x31 | EXT_SPECIAL, - OPC_TLT = 0x32 | EXT_SPECIAL, - OPC_TLTU = 0x33 | EXT_SPECIAL, - OPC_TEQ = 0x34 | EXT_SPECIAL, - OPC_TNE = 0x36 | EXT_SPECIAL, + OPC_TGE = 0x30 | OPC_SPECIAL, + OPC_TGEU = 0x31 | OPC_SPECIAL, + OPC_TLT = 0x32 | OPC_SPECIAL, + OPC_TLTU = 0x33 | OPC_SPECIAL, + OPC_TEQ = 0x34 | OPC_SPECIAL, + OPC_TNE = 0x36 | OPC_SPECIAL, /* HI / LO registers load & stores */ - OPC_MFHI = 0x10 | EXT_SPECIAL, - OPC_MTHI = 0x11 | EXT_SPECIAL, - OPC_MFLO = 0x12 | EXT_SPECIAL, - OPC_MTLO = 0x13 | EXT_SPECIAL, + OPC_MFHI = 0x10 | OPC_SPECIAL, + OPC_MTHI = 0x11 | OPC_SPECIAL, + OPC_MFLO = 0x12 | OPC_SPECIAL, + OPC_MTLO = 0x13 | OPC_SPECIAL, /* Conditional moves */ - OPC_MOVZ = 0x0A | EXT_SPECIAL, - OPC_MOVN = 0x0B | EXT_SPECIAL, + OPC_MOVZ = 0x0A | OPC_SPECIAL, + OPC_MOVN = 0x0B | OPC_SPECIAL, - OPC_MOVCI = 0x01 | EXT_SPECIAL, + OPC_MOVCI = 0x01 | OPC_SPECIAL, /* Special */ - OPC_PMON = 0x05 | EXT_SPECIAL, - OPC_SYSCALL = 0x0C | EXT_SPECIAL, - OPC_BREAK = 0x0D | EXT_SPECIAL, - OPC_SYNC = 0x0F | EXT_SPECIAL, + OPC_PMON = 0x05 | OPC_SPECIAL, /* inofficial */ + OPC_SYSCALL = 0x0C | OPC_SPECIAL, + OPC_BREAK = 0x0D | OPC_SPECIAL, + OPC_SPIM = 0x0E | OPC_SPECIAL, /* inofficial */ + OPC_SYNC = 0x0F | OPC_SPECIAL, + + OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL, + OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL, + OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL, + OPC_SPECIAL35_RESERVED = 0x35 | OPC_SPECIAL, + OPC_SPECIAL37_RESERVED = 0x37 | OPC_SPECIAL, + OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL, + OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL, +}; + +/* REGIMM (rt field) opcodes */ +#define MASK_REGIMM(op) MASK_OP_MAJOR(op) | (op & (0x1F << 16)) + +enum { + OPC_BLTZ = (0x00 << 16) | OPC_REGIMM, + OPC_BLTZL = (0x02 << 16) | OPC_REGIMM, + OPC_BGEZ = (0x01 << 16) | OPC_REGIMM, + OPC_BGEZL = (0x03 << 16) | OPC_REGIMM, + OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM, + OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM, + OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM, + OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM, + OPC_TGEI = (0x08 << 16) | OPC_REGIMM, + OPC_TGEIU = (0x09 << 16) | OPC_REGIMM, + OPC_TLTI = (0x0A << 16) | OPC_REGIMM, + OPC_TLTIU = (0x0B << 16) | OPC_REGIMM, + OPC_TEQI = (0x0C << 16) | OPC_REGIMM, + OPC_TNEI = (0x0E << 16) | OPC_REGIMM, + OPC_SYNCI = (0x1F << 16) | OPC_REGIMM, }; +/* Special2 opcodes */ +#define MASK_SPECIAL2(op) MASK_OP_MAJOR(op) | (op & 0x3F) + enum { - /* Mutiply & xxx operations */ - OPC_MADD = 0x00 | EXT_SPECIAL2, - OPC_MADDU = 0x01 | EXT_SPECIAL2, - OPC_MUL = 0x02 | EXT_SPECIAL2, - OPC_MSUB = 0x04 | EXT_SPECIAL2, - OPC_MSUBU = 0x05 | EXT_SPECIAL2, + /* Multiply & xxx operations */ + OPC_MADD = 0x00 | OPC_SPECIAL2, + OPC_MADDU = 0x01 | OPC_SPECIAL2, + OPC_MUL = 0x02 | OPC_SPECIAL2, + OPC_MSUB = 0x04 | OPC_SPECIAL2, + OPC_MSUBU = 0x05 | OPC_SPECIAL2, /* Misc */ - OPC_CLZ = 0x20 | EXT_SPECIAL2, - OPC_CLO = 0x21 | EXT_SPECIAL2, + OPC_CLZ = 0x20 | OPC_SPECIAL2, + OPC_CLO = 0x21 | OPC_SPECIAL2, + OPC_DCLZ = 0x24 | OPC_SPECIAL2, + OPC_DCLO = 0x25 | OPC_SPECIAL2, /* Special */ - OPC_SDBBP = 0x3F | EXT_SPECIAL2, + OPC_SDBBP = 0x3F | OPC_SPECIAL2, +}; + +/* Special3 opcodes */ +#define MASK_SPECIAL3(op) MASK_OP_MAJOR(op) | (op & 0x3F) + +enum { + OPC_EXT = 0x00 | OPC_SPECIAL3, + OPC_DEXTM = 0x01 | OPC_SPECIAL3, + OPC_DEXTU = 0x02 | OPC_SPECIAL3, + OPC_DEXT = 0x03 | OPC_SPECIAL3, + OPC_INS = 0x04 | OPC_SPECIAL3, + OPC_DINSM = 0x05 | OPC_SPECIAL3, + OPC_DINSU = 0x06 | OPC_SPECIAL3, + OPC_DINS = 0x07 | OPC_SPECIAL3, + OPC_BSHFL = 0x20 | OPC_SPECIAL3, + OPC_DBSHFL = 0x24 | OPC_SPECIAL3, + OPC_RDHWR = 0x3B | OPC_SPECIAL3, }; -/* Branch REGIMM */ +/* BSHFL opcodes */ +#define MASK_BSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6)) + enum { - OPC_BLTZ = 0x00 | EXT_REGIMM, - OPC_BLTZL = 0x02 | EXT_REGIMM, - OPC_BGEZ = 0x01 | EXT_REGIMM, - OPC_BGEZL = 0x03 | EXT_REGIMM, - OPC_BLTZAL = 0x10 | EXT_REGIMM, - OPC_BLTZALL = 0x12 | EXT_REGIMM, - OPC_BGEZAL = 0x11 | EXT_REGIMM, - OPC_BGEZALL = 0x13 | EXT_REGIMM, - OPC_TGEI = 0x08 | EXT_REGIMM, - OPC_TGEIU = 0x09 | EXT_REGIMM, - OPC_TLTI = 0x0A | EXT_REGIMM, - OPC_TLTIU = 0x0B | EXT_REGIMM, - OPC_TEQI = 0x0C | EXT_REGIMM, - OPC_TNEI = 0x0E | EXT_REGIMM, + OPC_WSBH = (0x02 << 6) | OPC_BSHFL, + OPC_SEB = (0x10 << 6) | OPC_BSHFL, + OPC_SEH = (0x18 << 6) | OPC_BSHFL, }; +/* DBSHFL opcodes */ +#define MASK_DBSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6)) + enum { - /* Coprocessor 0 (MMU) */ - OPC_MFC0 = 0x00 | EXT_CP0, - OPC_MTC0 = 0x04 | EXT_CP0, - OPC_TLBR = 0x01 | EXT_CP0, - OPC_TLBWI = 0x02 | EXT_CP0, - OPC_TLBWR = 0x06 | EXT_CP0, - OPC_TLBP = 0x08 | EXT_CP0, - OPC_ERET = 0x18 | EXT_CP0, - OPC_DERET = 0x1F | EXT_CP0, - OPC_WAIT = 0x20 | EXT_CP0, + OPC_DSBH = (0x02 << 6) | OPC_DBSHFL, + OPC_DSHD = (0x05 << 6) | OPC_DBSHFL, }; -#ifdef MIPS_USES_FPU +/* Coprocessor 0 (rs field) */ +#define MASK_CP0(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) + enum { - /* Coprocessor 1 (FPU) */ - OPC_MFC1 = 0x00 | EXT_CP1, - OPC_MTC1 = 0x04 | EXT_CP1, - OPC_CFC1 = 0x02 | EXT_CP1, - OPC_CTC1 = 0x06 | EXT_CP1, + OPC_MFC0 = (0x00 << 21) | OPC_CP0, + OPC_DMFC0 = (0x01 << 21) | OPC_CP0, + OPC_MTC0 = (0x04 << 21) | OPC_CP0, + OPC_DMTC0 = (0x05 << 21) | OPC_CP0, + OPC_RDPGPR = (0x0A << 21) | OPC_CP0, + OPC_MFMC0 = (0x0B << 21) | OPC_CP0, + OPC_WRPGPR = (0x0E << 21) | OPC_CP0, + OPC_C0 = (0x10 << 21) | OPC_CP0, + OPC_C0_FIRST = (0x10 << 21) | OPC_CP0, + OPC_C0_LAST = (0x1F << 21) | OPC_CP0, }; -#endif + +/* MFMC0 opcodes */ +#define MASK_MFMC0(op) MASK_CP0(op) | (op & ((0x0C << 11) | (1 << 5))) + +enum { + OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0, + OPC_EI = (1 << 5) | (0x0C << 11) | OPC_MFMC0, +}; + +/* Coprocessor 0 (with rs == C0) */ +#define MASK_C0(op) MASK_CP0(op) | (op & 0x3F) + +enum { + OPC_TLBR = 0x01 | OPC_C0, + OPC_TLBWI = 0x02 | OPC_C0, + OPC_TLBWR = 0x06 | OPC_C0, + OPC_TLBP = 0x08 | OPC_C0, + OPC_RFE = 0x10 | OPC_C0, + OPC_ERET = 0x18 | OPC_C0, + OPC_DERET = 0x1F | OPC_C0, + OPC_WAIT = 0x20 | OPC_C0, +}; + +/* Coprocessor 1 (rs field) */ +#define MASK_CP1(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) + +enum { + OPC_MFC1 = (0x00 << 21) | OPC_CP1, + OPC_DMFC1 = (0x01 << 21) | OPC_CP1, + OPC_CFC1 = (0x02 << 21) | OPC_CP1, + OPC_MFHCI = (0x03 << 21) | OPC_CP1, + OPC_MTC1 = (0x04 << 21) | OPC_CP1, + OPC_DMTC1 = (0x05 << 21) | OPC_CP1, + OPC_CTC1 = (0x06 << 21) | OPC_CP1, + OPC_MTHCI = (0x07 << 21) | OPC_CP1, + OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ + OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */ + OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */ + OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */ + OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */ + OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */ + OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */ +}; + +enum { + OPC_BC1F = (0x00 << 16) | OPC_BC1, + OPC_BC1T = (0x01 << 16) | OPC_BC1, + OPC_BC1FL = (0x02 << 16) | OPC_BC1, + OPC_BC1TL = (0x03 << 16) | OPC_BC1, +}; + +#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & ((0x1F << 21) | (0x3 << 16))) +#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & ((0x1F << 21) | 0x3F)) + +#define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) +#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) const unsigned char *regnames[] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", @@ -260,8 +389,7 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); -#ifdef MIPS_USES_FPU -const unsigned char *fregnames[] = +static const char *fregnames[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", @@ -344,8 +472,6 @@ static inline void gen_cmp_ ## fmt(int n) \ FOP_CONDS(d) FOP_CONDS(s) -#endif - typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; @@ -410,9 +536,7 @@ do { \ } \ } while (0) -#ifdef MIPS_USES_FPU - -# define GEN_LOAD_FREG_FTN(FTn, Fn) \ +#define GEN_LOAD_FREG_FTN(FTn, Fn) \ do { \ glue(gen_op_load_fpr_, FTn)(Fn); \ } while (0) @@ -422,8 +546,6 @@ do { \ glue(gen_op_store_fpr_, FTn)(Fn); \ } while (0) -#endif - static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) { #if defined MIPS_DEBUG_DISAS @@ -487,7 +609,7 @@ static GenOpFunc *gen_op_s##width[] = { \ } #endif -#ifdef TARGET_MIPS64 +#ifdef MIPS_HAS_MIPS64 OP_LD_TABLE(d); OP_LD_TABLE(dl); OP_LD_TABLE(dr); @@ -510,18 +632,16 @@ OP_LD_TABLE(bu); OP_ST_TABLE(b); OP_LD_TABLE(l); OP_ST_TABLE(c); -#ifdef MIPS_USES_FPU OP_LD_TABLE(wc1); OP_ST_TABLE(wc1); OP_LD_TABLE(dc1); OP_ST_TABLE(dc1); -#endif /* Load and store */ -static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, +static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, int base, int16_t offset) { - const unsigned char *opn = "unk"; + const char *opn = "unk"; if (base == 0) { GEN_LOAD_IMM_TN(T0, offset); @@ -536,23 +656,27 @@ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, * memory access */ switch (opc) { -#if defined(TARGET_MIPS64) +#ifdef MIPS_HAS_MIPS64 case OPC_LD: -#if defined (MIPS_HAS_UNALIGNED_LS) - case OPC_ULD: -#endif op_ldst(ld); GEN_STORE_TN_REG(rt, T0); opn = "ld"; break; + case OPC_LLD: + op_ldst(lld); + GEN_STORE_TN_REG(rt, T0); + opn = "lld"; + break; case OPC_SD: -#if defined (MIPS_HAS_UNALIGNED_LS) - case OPC_USD: -#endif GEN_LOAD_REG_TN(T1, rt); op_ldst(sd); opn = "sd"; break; + case OPC_SCD: + GEN_LOAD_REG_TN(T1, rt); + op_ldst(scd); + opn = "scd"; + break; case OPC_LDL: op_ldst(ldl); GEN_STORE_TN_REG(rt, T0); @@ -575,9 +699,6 @@ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, break; #endif case OPC_LW: -#if defined (MIPS_HAS_UNALIGNED_LS) - case OPC_ULW: -#endif op_ldst(lw); GEN_STORE_TN_REG(rt, T0); opn = "lw"; @@ -588,33 +709,21 @@ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, opn = "lwu"; break; case OPC_SW: -#if defined (MIPS_HAS_UNALIGNED_LS) - case OPC_USW: -#endif GEN_LOAD_REG_TN(T1, rt); op_ldst(sw); opn = "sw"; break; case OPC_LH: -#if defined (MIPS_HAS_UNALIGNED_LS) - case OPC_ULH: -#endif op_ldst(lh); GEN_STORE_TN_REG(rt, T0); opn = "lh"; break; case OPC_SH: -#if defined (MIPS_HAS_UNALIGNED_LS) - case OPC_USH: -#endif GEN_LOAD_REG_TN(T1, rt); op_ldst(sh); opn = "sh"; break; case OPC_LHU: -#if defined (MIPS_HAS_UNALIGNED_LS) - case OPC_ULHU: -#endif op_ldst(lhu); GEN_STORE_TN_REG(rt, T0); opn = "lhu"; @@ -675,13 +784,11 @@ static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt, MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); } -#ifdef MIPS_USES_FPU - /* Load and store */ -static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft, +static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, int base, int16_t offset) { - const unsigned char *opn = "unk"; + const char *opn = "unk"; if (base == 0) { GEN_LOAD_IMM_TN(T0, offset); @@ -718,21 +825,20 @@ static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft, break; default: MIPS_INVAL("float load/store"); - generate_exception(ctx, EXCP_CpU); + generate_exception_err(ctx, EXCP_CpU, 1); return; } MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); } -#endif /* Arithmetic with immediate operand */ -static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, +static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) { uint32_t uimm; - const unsigned char *opn = "unk"; + const char *opn = "unk"; - if (rt == 0 && opc != OPC_ADDI) { + if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { /* if no destination, treat it as a NOP * For addi, we must generate the overflow exception when needed. */ @@ -740,8 +846,9 @@ static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, return; } if (opc == OPC_ADDI || opc == OPC_ADDIU || + opc == OPC_DADDI || opc == OPC_DADDIU || opc == OPC_SLTI || opc == OPC_SLTIU) - uimm = (int32_t)imm; /* Sign extent to 32 bits */ + uimm = (int32_t)imm; /* Sign extend to 32 bits */ else uimm = (uint16_t)imm; if (opc != OPC_LUI) { @@ -761,6 +868,17 @@ static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, gen_op_add(); opn = "addiu"; break; +#ifdef MIPS_HAS_MIPS64 + case OPC_DADDI: + save_cpu_state(ctx, 1); + gen_op_daddo(); + opn = "daddi"; + break; + case OPC_DADDIU: + gen_op_dadd(); + opn = "daddiu"; + break; +#endif case OPC_SLTI: gen_op_lt(); opn = "slti"; @@ -793,9 +911,50 @@ static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, opn = "sra"; break; case OPC_SRL: - gen_op_srl(); - opn = "srl"; + if ((ctx->opcode >> 21) & 1) { + gen_op_rotr(); + opn = "rotr"; + } else { + gen_op_srl(); + opn = "srl"; + } + break; +#ifdef MIPS_HAS_MIPS64 + case OPC_DSLL: + gen_op_dsll(); + opn = "dsll"; + break; + case OPC_DSRA: + gen_op_dsra(); + opn = "dsra"; + break; + case OPC_DSRL: + if ((ctx->opcode >> 21) & 1) { + gen_op_drotr(); + opn = "drotr"; + } else { + gen_op_dsrl(); + opn = "dsrl"; + } + break; + case OPC_DSLL32: + gen_op_dsll32(); + opn = "dsll32"; + break; + case OPC_DSRA32: + gen_op_dsra32(); + opn = "dsra32"; + break; + case OPC_DSRL32: + if ((ctx->opcode >> 21) & 1) { + gen_op_drotr32(); + opn = "drotr32"; + } else { + gen_op_dsrl32(); + opn = "dsrl32"; + } break; +#endif default: MIPS_INVAL("imm arith"); generate_exception(ctx, EXCP_RI); @@ -806,12 +965,13 @@ static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt, } /* Arithmetic */ -static void gen_arith (DisasContext *ctx, uint16_t opc, +static void gen_arith (DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { - const unsigned char *opn = "unk"; + const char *opn = "unk"; - if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) { + if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB + && opc != OPC_DADD && opc != OPC_DSUB) { /* if no destination, treat it as a NOP * For add & sub, we must generate the overflow exception when needed. */ @@ -839,6 +999,26 @@ static void gen_arith (DisasContext *ctx, uint16_t opc, gen_op_sub(); opn = "subu"; break; +#ifdef MIPS_HAS_MIPS64 + case OPC_DADD: + save_cpu_state(ctx, 1); + gen_op_daddo(); + opn = "dadd"; + break; + case OPC_DADDU: + gen_op_dadd(); + opn = "daddu"; + break; + case OPC_DSUB: + save_cpu_state(ctx, 1); + gen_op_dsubo(); + opn = "dsub"; + break; + case OPC_DSUBU: + gen_op_dsub(); + opn = "dsubu"; + break; +#endif case OPC_SLT: gen_op_lt(); opn = "slt"; @@ -884,9 +1064,33 @@ static void gen_arith (DisasContext *ctx, uint16_t opc, opn = "srav"; break; case OPC_SRLV: - gen_op_srlv(); - opn = "srlv"; + if ((ctx->opcode >> 6) & 1) { + gen_op_rotrv(); + opn = "rotrv"; + } else { + gen_op_srlv(); + opn = "srlv"; + } + break; +#ifdef MIPS_HAS_MIPS64 + case OPC_DSLLV: + gen_op_dsllv(); + opn = "dsllv"; + break; + case OPC_DSRAV: + gen_op_dsrav(); + opn = "dsrav"; + break; + case OPC_DSRLV: + if ((ctx->opcode >> 6) & 1) { + gen_op_drotrv(); + opn = "drotrv"; + } else { + gen_op_dsrlv(); + opn = "dsrlv"; + } break; +#endif default: MIPS_INVAL("arith"); generate_exception(ctx, EXCP_RI); @@ -898,9 +1102,9 @@ static void gen_arith (DisasContext *ctx, uint16_t opc, } /* Arithmetic on HI/LO registers */ -static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg) +static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) { - const unsigned char *opn = "unk"; + const char *opn = "unk"; if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { /* Treat as a NOP */ @@ -936,10 +1140,10 @@ static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg) MIPS_DEBUG("%s %s", opn, regnames[reg]); } -static void gen_muldiv (DisasContext *ctx, uint16_t opc, +static void gen_muldiv (DisasContext *ctx, uint32_t opc, int rs, int rt) { - const unsigned char *opn = "unk"; + const char *opn = "unk"; GEN_LOAD_REG_TN(T0, rs); GEN_LOAD_REG_TN(T1, rt); @@ -960,6 +1164,24 @@ static void gen_muldiv (DisasContext *ctx, uint16_t opc, gen_op_multu(); opn = "multu"; break; +#ifdef MIPS_HAS_MIPS64 + case OPC_DDIV: + gen_op_ddiv(); + opn = "ddiv"; + break; + case OPC_DDIVU: + gen_op_ddivu(); + opn = "ddivu"; + break; + case OPC_DMULT: + gen_op_dmult(); + opn = "dmult"; + break; + case OPC_DMULTU: + gen_op_dmultu(); + opn = "dmultu"; + break; +#endif case OPC_MADD: gen_op_madd(); opn = "madd"; @@ -984,10 +1206,10 @@ static void gen_muldiv (DisasContext *ctx, uint16_t opc, MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]); } -static void gen_cl (DisasContext *ctx, uint16_t opc, +static void gen_cl (DisasContext *ctx, uint32_t opc, int rd, int rs) { - const unsigned char *opn = "unk"; + const char *opn = "unk"; if (rd == 0) { /* Treat as a NOP */ MIPS_DEBUG("NOP"); @@ -996,15 +1218,23 @@ static void gen_cl (DisasContext *ctx, uint16_t opc, GEN_LOAD_REG_TN(T0, rs); switch (opc) { case OPC_CLO: - /* CLO */ gen_op_clo(); opn = "clo"; break; case OPC_CLZ: - /* CLZ */ gen_op_clz(); opn = "clz"; break; +#ifdef MIPS_HAS_MIPS64 + case OPC_DCLO: + gen_op_dclo(); + opn = "dclo"; + break; + case OPC_DCLZ: + gen_op_dclz(); + opn = "dclz"; + break; +#endif default: MIPS_INVAL("CLx"); generate_exception(ctx, EXCP_RI); @@ -1015,7 +1245,7 @@ static void gen_cl (DisasContext *ctx, uint16_t opc, } /* Traps */ -static void gen_trap (DisasContext *ctx, uint16_t opc, +static void gen_trap (DisasContext *ctx, uint32_t opc, int rs, int rt, int16_t imm) { int cond; @@ -1130,7 +1360,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) } /* Branches (before delay slot) */ -static void gen_compute_branch (DisasContext *ctx, uint16_t opc, +static void gen_compute_branch (DisasContext *ctx, uint32_t opc, int rs, int rt, int32_t offset) { target_ulong btarget; @@ -1180,8 +1410,9 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, case OPC_JR: case OPC_JALR: /* Jump to register */ - if (offset != 0) { - /* Only hint = 0 is valid */ + if (offset != 0 && offset != 16) { + /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the + others are reserved. */ generate_exception(ctx, EXCP_RI); return; } @@ -1348,80 +1579,342 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc, return; } +/* special3 bitfield operations */ +static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, + int rs, int lsb, int msb) +{ + GEN_LOAD_REG_TN(T1, rs); + switch (opc) { + case OPC_EXT: + if (lsb + msb > 31) + goto fail; + gen_op_ext(lsb, msb + 1); + break; + case OPC_DEXTM: + if (lsb + msb > 63) + goto fail; + gen_op_ext(lsb, msb + 1 + 32); + break; + case OPC_DEXTU: + if (lsb + msb > 63) + goto fail; + gen_op_ext(lsb + 32, msb + 1); + break; + case OPC_DEXT: + gen_op_ext(lsb, msb + 1); + break; + case OPC_INS: + if (lsb > msb) + goto fail; + GEN_LOAD_REG_TN(T2, rt); + gen_op_ins(lsb, msb - lsb + 1); + break; + case OPC_DINSM: + if (lsb > msb) + goto fail; + GEN_LOAD_REG_TN(T2, rt); + gen_op_ins(lsb, msb - lsb + 1 + 32); + break; + case OPC_DINSU: + if (lsb > msb) + goto fail; + GEN_LOAD_REG_TN(T2, rt); + gen_op_ins(lsb + 32, msb - lsb + 1); + break; + case OPC_DINS: + if (lsb > msb) + goto fail; + GEN_LOAD_REG_TN(T2, rt); + gen_op_ins(lsb, msb - lsb + 1); + break; + default: +fail: + MIPS_INVAL("bitops"); + generate_exception(ctx, EXCP_RI); + return; + } + GEN_STORE_TN_REG(rt, T0); +} + /* CP0 (MMU and control) */ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) { - const unsigned char *rn; + const char *rn = "invalid"; - if (sel != 0 && reg != 16 && reg != 28) { - rn = "invalid"; - goto die; - } switch (reg) { case 0: - gen_op_mfc0_index(); - rn = "Index"; + switch (sel) { + case 0: + gen_op_mfc0_index(); + rn = "Index"; + break; + case 1: +// gen_op_mfc0_mvpcontrol(); /* MT ASE */ + rn = "MVPControl"; +// break; + case 2: +// gen_op_mfc0_mvpconf0(); /* MT ASE */ + rn = "MVPConf0"; +// break; + case 3: +// gen_op_mfc0_mvpconf1(); /* MT ASE */ + rn = "MVPConf1"; +// break; + default: + goto die; + } break; case 1: - gen_op_mfc0_random(); - rn = "Random"; + switch (sel) { + case 0: + gen_op_mfc0_random(); + rn = "Random"; + break; + case 1: +// gen_op_mfc0_vpecontrol(); /* MT ASE */ + rn = "VPEControl"; +// break; + case 2: +// gen_op_mfc0_vpeconf0(); /* MT ASE */ + rn = "VPEConf0"; +// break; + case 3: +// gen_op_mfc0_vpeconf1(); /* MT ASE */ + rn = "VPEConf1"; +// break; + case 4: +// gen_op_mfc0_YQMask(); /* MT ASE */ + rn = "YQMask"; +// break; + case 5: +// gen_op_mfc0_vpeschedule(); /* MT ASE */ + rn = "VPESchedule"; +// break; + case 6: +// gen_op_mfc0_vpeschefback(); /* MT ASE */ + rn = "VPEScheFBack"; +// break; + case 7: +// gen_op_mfc0_vpeopt(); /* MT ASE */ + rn = "VPEOpt"; +// break; + default: + goto die; + } break; case 2: - gen_op_mfc0_entrylo0(); - rn = "EntryLo0"; + switch (sel) { + case 0: + gen_op_mfc0_entrylo0(); + rn = "EntryLo0"; + break; + case 1: +// gen_op_mfc0_tcstatus(); /* MT ASE */ + rn = "TCStatus"; +// break; + case 2: +// gen_op_mfc0_tcbind(); /* MT ASE */ + rn = "TCBind"; +// break; + case 3: +// gen_op_mfc0_tcrestart(); /* MT ASE */ + rn = "TCRestart"; +// break; + case 4: +// gen_op_mfc0_tchalt(); /* MT ASE */ + rn = "TCHalt"; +// break; + case 5: +// gen_op_mfc0_tccontext(); /* MT ASE */ + rn = "TCContext"; +// break; + case 6: +// gen_op_mfc0_tcschedule(); /* MT ASE */ + rn = "TCSchedule"; +// break; + case 7: +// gen_op_mfc0_tcschefback(); /* MT ASE */ + rn = "TCScheFBack"; +// break; + default: + goto die; + } break; case 3: - /* also CONF */ - gen_op_mfc0_entrylo1(); - rn = "EntryLo1"; + switch (sel) { + case 0: + gen_op_mfc0_entrylo1(); + rn = "EntryLo1"; + break; + default: + goto die; + } break; case 4: - gen_op_mfc0_context(); - rn = "Context"; + switch (sel) { + case 0: + gen_op_mfc0_context(); + rn = "Context"; + break; + case 1: +// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */ + rn = "ContextConfig"; +// break; + default: + goto die; + } break; case 5: - gen_op_mfc0_pagemask(); - rn = "PageMask"; + switch (sel) { + case 0: + gen_op_mfc0_pagemask(); + rn = "PageMask"; + break; + case 1: + gen_op_mfc0_pagegrain(); + rn = "PageGrain"; + break; + default: + goto die; + } break; case 6: - gen_op_mfc0_wired(); - rn = "Wired"; + switch (sel) { + case 0: + gen_op_mfc0_wired(); + rn = "Wired"; + break; + case 1: +// gen_op_mfc0_srsconf0(); /* shadow registers */ + rn = "SRSConf0"; +// break; + case 2: +// gen_op_mfc0_srsconf1(); /* shadow registers */ + rn = "SRSConf1"; +// break; + case 3: +// gen_op_mfc0_srsconf2(); /* shadow registers */ + rn = "SRSConf2"; +// break; + case 4: +// gen_op_mfc0_srsconf3(); /* shadow registers */ + rn = "SRSConf3"; +// break; + case 5: +// gen_op_mfc0_srsconf4(); /* shadow registers */ + rn = "SRSConf4"; +// break; + default: + goto die; + } break; case 7: -// gen_op_mfc0_info(); - rn = "Info"; + switch (sel) { + case 0: + gen_op_mfc0_hwrena(); + rn = "HWREna"; + break; + default: + goto die; + } break; case 8: - gen_op_mfc0_badvaddr(); - rn = "BadVaddr"; + switch (sel) { + case 0: + gen_op_mfc0_badvaddr(); + rn = "BadVaddr"; + break; + default: + goto die; + } break; case 9: - gen_op_mfc0_count(); - rn = "Count"; + switch (sel) { + case 0: + gen_op_mfc0_count(); + rn = "Count"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } break; case 10: - gen_op_mfc0_entryhi(); - rn = "EntryHi"; + switch (sel) { + case 0: + gen_op_mfc0_entryhi(); + rn = "EntryHi"; + break; + default: + goto die; + } break; case 11: - gen_op_mfc0_compare(); - rn = "Compare"; + switch (sel) { + case 0: + gen_op_mfc0_compare(); + rn = "Compare"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } break; case 12: - gen_op_mfc0_status(); - rn = "Status"; + switch (sel) { + case 0: + gen_op_mfc0_status(); + rn = "Status"; + break; + case 1: + gen_op_mfc0_intctl(); + rn = "IntCtl"; + break; + case 2: + gen_op_mfc0_srsctl(); + rn = "SRSCtl"; + break; + case 3: +// gen_op_mfc0_srsmap(); /* shadow registers */ + rn = "SRSMap"; +// break; + default: + goto die; + } break; case 13: - gen_op_mfc0_cause(); - rn = "Cause"; + switch (sel) { + case 0: + gen_op_mfc0_cause(); + rn = "Cause"; + break; + default: + goto die; + } break; case 14: - gen_op_mfc0_epc(); - rn = "EPC"; + switch (sel) { + case 0: + gen_op_mfc0_epc(); + rn = "EPC"; + break; + default: + goto die; + } break; case 15: - gen_op_mfc0_prid(); - rn = "PRid"; + switch (sel) { + case 0: + gen_op_mfc0_prid(); + rn = "PRid"; + break; + case 1: + gen_op_mfc0_ebase(); + rn = "EBase"; + break; + default: + goto die; + } break; case 16: switch (sel) { @@ -1433,91 +1926,285 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) gen_op_mfc0_config1(); rn = "Config1"; break; + case 2: + gen_op_mfc0_config2(); + rn = "Config2"; + break; + case 3: + gen_op_mfc0_config3(); + rn = "Config3"; + break; + /* 6,7 are implementation dependent */ default: - rn = "Unknown config register"; goto die; } break; case 17: - gen_op_mfc0_lladdr(); - rn = "LLAddr"; + switch (sel) { + case 0: + gen_op_mfc0_lladdr(); + rn = "LLAddr"; + break; + default: + goto die; + } break; case 18: - gen_op_mfc0_watchlo(); - rn = "WatchLo"; + switch (sel) { + case 0: + gen_op_mfc0_watchlo0(); + rn = "WatchLo"; + break; + case 1: +// gen_op_mfc0_watchlo1(); + rn = "WatchLo1"; +// break; + case 2: +// gen_op_mfc0_watchlo2(); + rn = "WatchLo2"; +// break; + case 3: +// gen_op_mfc0_watchlo3(); + rn = "WatchLo3"; +// break; + case 4: +// gen_op_mfc0_watchlo4(); + rn = "WatchLo4"; +// break; + case 5: +// gen_op_mfc0_watchlo5(); + rn = "WatchLo5"; +// break; + case 6: +// gen_op_mfc0_watchlo6(); + rn = "WatchLo6"; +// break; + case 7: +// gen_op_mfc0_watchlo7(); + rn = "WatchLo7"; +// break; + default: + goto die; + } break; case 19: - gen_op_mfc0_watchhi(); - rn = "WatchHi"; + switch (sel) { + case 0: + gen_op_mfc0_watchhi0(); + rn = "WatchHi"; + break; + case 1: +// gen_op_mfc0_watchhi1(); + rn = "WatchHi1"; +// break; + case 2: +// gen_op_mfc0_watchhi2(); + rn = "WatchHi2"; +// break; + case 3: +// gen_op_mfc0_watchhi3(); + rn = "WatchHi3"; +// break; + case 4: +// gen_op_mfc0_watchhi4(); + rn = "WatchHi4"; +// break; + case 5: +// gen_op_mfc0_watchhi5(); + rn = "WatchHi5"; +// break; + case 6: +// gen_op_mfc0_watchhi6(); + rn = "WatchHi6"; +// break; + case 7: +// gen_op_mfc0_watchhi7(); + rn = "WatchHi7"; +// break; + default: + goto die; + } break; case 20: - /* 64 bit only */ -// gen_op_mfc0_xcontext(); - rn = "XContext"; + switch (sel) { + case 0: + /* 64 bit MMU only */ + gen_op_mfc0_xcontext(); + rn = "XContext"; + break; + default: + goto die; + } break; case 21: -// gen_op_mfc0_framemask(); - rn = "Framemask"; + /* Officially reserved, but sel 0 is used for R1x000 framemask */ + switch (sel) { + case 0: + gen_op_mfc0_framemask(); + rn = "Framemask"; + break; + default: + goto die; + } break; case 22: -// gen_op_mfc0_diagnostic(); - rn = "'Diagnostic"; - break; + /* ignored */ + rn = "'Diagnostic"; /* implementation dependent */ + break; case 23: - gen_op_mfc0_debug(); - rn = "Debug"; + switch (sel) { + case 0: + gen_op_mfc0_debug(); /* EJTAG support */ + rn = "Debug"; + break; + case 1: +// gen_op_mfc0_tracecontrol(); /* PDtrace support */ + rn = "TraceControl"; +// break; + case 2: +// gen_op_mfc0_tracecontrol2(); /* PDtrace support */ + rn = "TraceControl2"; +// break; + case 3: +// gen_op_mfc0_usertracedata(); /* PDtrace support */ + rn = "UserTraceData"; +// break; + case 4: +// gen_op_mfc0_debug(); /* PDtrace support */ + rn = "TraceBPC"; +// break; + default: + goto die; + } break; case 24: - gen_op_mfc0_depc(); - rn = "DEPC"; + switch (sel) { + case 0: + gen_op_mfc0_depc(); /* EJTAG support */ + rn = "DEPC"; + break; + default: + goto die; + } break; case 25: -// gen_op_mfc0_performance(); - rn = "Performance"; + switch (sel) { + case 0: + gen_op_mfc0_performance0(); + rn = "Performance0"; + break; + case 1: +// gen_op_mfc0_performance1(); + rn = "Performance1"; +// break; + case 2: +// gen_op_mfc0_performance2(); + rn = "Performance2"; +// break; + case 3: +// gen_op_mfc0_performance3(); + rn = "Performance3"; +// break; + case 4: +// gen_op_mfc0_performance4(); + rn = "Performance4"; +// break; + case 5: +// gen_op_mfc0_performance5(); + rn = "Performance5"; +// break; + case 6: +// gen_op_mfc0_performance6(); + rn = "Performance6"; +// break; + case 7: +// gen_op_mfc0_performance7(); + rn = "Performance7"; +// break; + default: + goto die; + } break; case 26: -// gen_op_mfc0_ecc(); - rn = "ECC"; - break; + rn = "ECC"; + break; case 27: -// gen_op_mfc0_cacheerr(); - rn = "CacheErr"; + switch (sel) { + /* ignored */ + case 0 ... 3: + rn = "CacheErr"; + break; + default: + goto die; + } break; case 28: switch (sel) { case 0: + case 2: + case 4: + case 6: gen_op_mfc0_taglo(); rn = "TagLo"; break; case 1: + case 3: + case 5: + case 7: gen_op_mfc0_datalo(); rn = "DataLo"; break; default: - rn = "unknown sel"; goto die; } break; case 29: -// gen_op_mfc0_taghi(); - rn = "TagHi"; + switch (sel) { + case 0: + case 2: + case 4: + case 6: + gen_op_mfc0_taghi(); + rn = "TagHi"; + break; + case 1: + case 3: + case 5: + case 7: + gen_op_mfc0_datahi(); + rn = "DataHi"; + break; + default: + goto die; + } break; case 30: - gen_op_mfc0_errorepc(); - rn = "ErrorEPC"; + switch (sel) { + case 0: + gen_op_mfc0_errorepc(); + rn = "ErrorEPC"; + break; + default: + goto die; + } break; case 31: - gen_op_mfc0_desave(); - rn = "DESAVE"; + switch (sel) { + case 0: + gen_op_mfc0_desave(); /* EJTAG support */ + rn = "DESAVE"; + break; + default: + goto die; + } break; default: - rn = "unknown"; goto die; } #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n", - env->PC, rn, T0, reg, sel); + fprintf(logfile, "mfc0 %s (reg %d sel %d)\n", + rn, reg, sel); } #endif return; @@ -1525,8 +2212,8 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) die: #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n", - env->PC, rn, T0, reg, sel); + fprintf(logfile, "mfc0 %s (reg %d sel %d)\n", + rn, reg, sel); } #endif generate_exception(ctx, EXCP_RI); @@ -1534,167 +2221,583 @@ die: static void gen_mtc0 (DisasContext *ctx, int reg, int sel) { - const unsigned char *rn; - uint32_t val, old; - - if (sel != 0 && reg != 16 && reg != 28) { - val = -1; - old = -1; - rn = "invalid"; - goto die; - } + const char *rn = "invalid"; + switch (reg) { case 0: - gen_op_mtc0_index(); - rn = "Index"; + switch (sel) { + case 0: + gen_op_mtc0_index(); + rn = "Index"; + break; + case 1: +// gen_op_mtc0_mvpcontrol(); /* MT ASE */ + rn = "MVPControl"; +// break; + case 2: +// gen_op_mtc0_mvpconf0(); /* MT ASE */ + rn = "MVPConf0"; +// break; + case 3: +// gen_op_mtc0_mvpconf1(); /* MT ASE */ + rn = "MVPConf1"; +// break; + default: + goto die; + } break; case 1: -// ignore or except? - rn = "Random"; + switch (sel) { + case 0: + /* ignored */ + rn = "Random"; + break; + case 1: +// gen_op_mtc0_vpecontrol(); /* MT ASE */ + rn = "VPEControl"; +// break; + case 2: +// gen_op_mtc0_vpeconf0(); /* MT ASE */ + rn = "VPEConf0"; +// break; + case 3: +// gen_op_mtc0_vpeconf1(); /* MT ASE */ + rn = "VPEConf1"; +// break; + case 4: +// gen_op_mtc0_YQMask(); /* MT ASE */ + rn = "YQMask"; +// break; + case 5: +// gen_op_mtc0_vpeschedule(); /* MT ASE */ + rn = "VPESchedule"; +// break; + case 6: +// gen_op_mtc0_vpeschefback(); /* MT ASE */ + rn = "VPEScheFBack"; +// break; + case 7: +// gen_op_mtc0_vpeopt(); /* MT ASE */ + rn = "VPEOpt"; +// break; + default: + goto die; + } break; case 2: - gen_op_mtc0_entrylo0(); - rn = "EntryLo0"; + switch (sel) { + case 0: + gen_op_mtc0_entrylo0(); + rn = "EntryLo0"; + break; + case 1: +// gen_op_mtc0_tcstatus(); /* MT ASE */ + rn = "TCStatus"; +// break; + case 2: +// gen_op_mtc0_tcbind(); /* MT ASE */ + rn = "TCBind"; +// break; + case 3: +// gen_op_mtc0_tcrestart(); /* MT ASE */ + rn = "TCRestart"; +// break; + case 4: +// gen_op_mtc0_tchalt(); /* MT ASE */ + rn = "TCHalt"; +// break; + case 5: +// gen_op_mtc0_tccontext(); /* MT ASE */ + rn = "TCContext"; +// break; + case 6: +// gen_op_mtc0_tcschedule(); /* MT ASE */ + rn = "TCSchedule"; +// break; + case 7: +// gen_op_mtc0_tcschefback(); /* MT ASE */ + rn = "TCScheFBack"; +// break; + default: + goto die; + } break; case 3: - gen_op_mtc0_entrylo1(); - rn = "EntryLo1"; + switch (sel) { + case 0: + gen_op_mtc0_entrylo1(); + rn = "EntryLo1"; + break; + default: + goto die; + } break; case 4: - gen_op_mtc0_context(); - rn = "Context"; + switch (sel) { + case 0: + gen_op_mtc0_context(); + rn = "Context"; + break; + case 1: +// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */ + rn = "ContextConfig"; +// break; + default: + goto die; + } break; case 5: - gen_op_mtc0_pagemask(); - rn = "PageMask"; + switch (sel) { + case 0: + gen_op_mtc0_pagemask(); + rn = "PageMask"; + break; + case 1: + gen_op_mtc0_pagegrain(); + rn = "PageGrain"; + break; + default: + goto die; + } break; case 6: - gen_op_mtc0_wired(); - rn = "Wired"; + switch (sel) { + case 0: + gen_op_mtc0_wired(); + rn = "Wired"; + break; + case 1: +// gen_op_mtc0_srsconf0(); /* shadow registers */ + rn = "SRSConf0"; +// break; + case 2: +// gen_op_mtc0_srsconf1(); /* shadow registers */ + rn = "SRSConf1"; +// break; + case 3: +// gen_op_mtc0_srsconf2(); /* shadow registers */ + rn = "SRSConf2"; +// break; + case 4: +// gen_op_mtc0_srsconf3(); /* shadow registers */ + rn = "SRSConf3"; +// break; + case 5: +// gen_op_mtc0_srsconf4(); /* shadow registers */ + rn = "SRSConf4"; +// break; + default: + goto die; + } break; case 7: -// ignore or except? - rn = "Info"; + switch (sel) { + case 0: + gen_op_mtc0_hwrena(); + rn = "HWREna"; + break; + default: + goto die; + } break; case 8: -// ignore or except? + /* ignored */ rn = "BadVaddr"; break; case 9: - gen_op_mtc0_count(); - rn = "Count"; + switch (sel) { + case 0: + gen_op_mtc0_count(); + rn = "Count"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 10: - gen_op_mtc0_entryhi(); - rn = "EntryHi"; + switch (sel) { + case 0: + gen_op_mtc0_entryhi(); + rn = "EntryHi"; + break; + default: + goto die; + } break; case 11: - gen_op_mtc0_compare(); - rn = "Compare"; + switch (sel) { + case 0: + gen_op_mtc0_compare(); + rn = "Compare"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 12: - gen_op_mtc0_status(); - rn = "Status"; + switch (sel) { + case 0: + gen_op_mtc0_status(); + rn = "Status"; + break; + case 1: + gen_op_mtc0_intctl(); + rn = "IntCtl"; + break; + case 2: + gen_op_mtc0_srsctl(); + rn = "SRSCtl"; + break; + case 3: +// gen_op_mtc0_srsmap(); /* shadow registers */ + rn = "SRSMap"; +// break; + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 13: - gen_op_mtc0_cause(); - rn = "Cause"; + switch (sel) { + case 0: + gen_op_mtc0_cause(); + rn = "Cause"; + break; + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 14: - gen_op_mtc0_epc(); - rn = "EPC"; + switch (sel) { + case 0: + gen_op_mtc0_epc(); + rn = "EPC"; + break; + default: + goto die; + } break; case 15: -// ignore or except? - rn = "PRid"; + switch (sel) { + case 0: + /* ignored */ + rn = "PRid"; + break; + case 1: + gen_op_mtc0_ebase(); + rn = "EBase"; + break; + default: + goto die; + } break; case 16: switch (sel) { case 0: gen_op_mtc0_config0(); - rn = "Config0"; + rn = "Config"; + break; + case 1: + /* ignored */ + rn = "Config1"; + break; + case 2: + gen_op_mtc0_config2(); + rn = "Config2"; break; + case 3: + /* ignored */ + rn = "Config3"; + break; + /* 6,7 are implementation dependent */ default: rn = "Invalid config selector"; goto die; } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 17: -// ignore or except? - rn = "LLaddr"; + switch (sel) { + case 0: + /* ignored */ + rn = "LLAddr"; + break; + default: + goto die; + } break; case 18: - gen_op_mtc0_watchlo(); - rn = "WatchLo"; + switch (sel) { + case 0: + gen_op_mtc0_watchlo0(); + rn = "WatchLo"; + break; + case 1: +// gen_op_mtc0_watchlo1(); + rn = "WatchLo1"; +// break; + case 2: +// gen_op_mtc0_watchlo2(); + rn = "WatchLo2"; +// break; + case 3: +// gen_op_mtc0_watchlo3(); + rn = "WatchLo3"; +// break; + case 4: +// gen_op_mtc0_watchlo4(); + rn = "WatchLo4"; +// break; + case 5: +// gen_op_mtc0_watchlo5(); + rn = "WatchLo5"; +// break; + case 6: +// gen_op_mtc0_watchlo6(); + rn = "WatchLo6"; +// break; + case 7: +// gen_op_mtc0_watchlo7(); + rn = "WatchLo7"; +// break; + default: + goto die; + } break; case 19: - gen_op_mtc0_watchhi(); - rn = "WatchHi"; + switch (sel) { + case 0: + gen_op_mtc0_watchhi0(); + rn = "WatchHi"; + break; + case 1: +// gen_op_mtc0_watchhi1(); + rn = "WatchHi1"; +// break; + case 2: +// gen_op_mtc0_watchhi2(); + rn = "WatchHi2"; +// break; + case 3: +// gen_op_mtc0_watchhi3(); + rn = "WatchHi3"; +// break; + case 4: +// gen_op_mtc0_watchhi4(); + rn = "WatchHi4"; +// break; + case 5: +// gen_op_mtc0_watchhi5(); + rn = "WatchHi5"; +// break; + case 6: +// gen_op_mtc0_watchhi6(); + rn = "WatchHi6"; +// break; + case 7: +// gen_op_mtc0_watchhi7(); + rn = "WatchHi7"; +// break; + default: + goto die; + } break; case 20: - /* 64 bit only */ -// gen_op_mtc0_xcontext(); - rn = "XContext"; + switch (sel) { + case 0: + /* 64 bit MMU only */ + gen_op_mtc0_xcontext(); + rn = "XContext"; + break; + default: + goto die; + } break; case 21: -// gen_op_mtc0_framemask(); - rn = "Framemask"; - break; + /* Officially reserved, but sel 0 is used for R1x000 framemask */ + switch (sel) { + case 0: + gen_op_mtc0_framemask(); + rn = "Framemask"; + break; + default: + goto die; + } + break; case 22: -// ignore or except? - rn = "Diagnostic"; + /* ignored */ + rn = "Diagnostic"; /* implementation dependent */ break; case 23: - gen_op_mtc0_debug(); - rn = "Debug"; + switch (sel) { + case 0: + gen_op_mtc0_debug(); /* EJTAG support */ + rn = "Debug"; + break; + case 1: +// gen_op_mtc0_tracecontrol(); /* PDtrace support */ + rn = "TraceControl"; +// break; + case 2: +// gen_op_mtc0_tracecontrol2(); /* PDtrace support */ + rn = "TraceControl2"; +// break; + case 3: +// gen_op_mtc0_usertracedata(); /* PDtrace support */ + rn = "UserTraceData"; +// break; + case 4: +// gen_op_mtc0_debug(); /* PDtrace support */ + rn = "TraceBPC"; +// break; + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 24: - gen_op_mtc0_depc(); - rn = "DEPC"; + switch (sel) { + case 0: + gen_op_mtc0_depc(); /* EJTAG support */ + rn = "DEPC"; + break; + default: + goto die; + } break; case 25: -// ignore or except? - rn = "Performance"; + switch (sel) { + case 0: + gen_op_mtc0_performance0(); + rn = "Performance0"; + break; + case 1: +// gen_op_mtc0_performance1(); + rn = "Performance1"; +// break; + case 2: +// gen_op_mtc0_performance2(); + rn = "Performance2"; +// break; + case 3: +// gen_op_mtc0_performance3(); + rn = "Performance3"; +// break; + case 4: +// gen_op_mtc0_performance4(); + rn = "Performance4"; +// break; + case 5: +// gen_op_mtc0_performance5(); + rn = "Performance5"; +// break; + case 6: +// gen_op_mtc0_performance6(); + rn = "Performance6"; +// break; + case 7: +// gen_op_mtc0_performance7(); + rn = "Performance7"; +// break; + default: + goto die; + } break; case 26: -// ignore or except? + /* ignored */ rn = "ECC"; break; case 27: -// ignore or except? - rn = "CacheErr"; + switch (sel) { + case 0 ... 3: + /* ignored */ + rn = "CacheErr"; + break; + default: + goto die; + } break; case 28: switch (sel) { case 0: + case 2: + case 4: + case 6: gen_op_mtc0_taglo(); rn = "TagLo"; break; + case 1: + case 3: + case 5: + case 7: + gen_op_mtc0_datalo(); + rn = "DataLo"; + break; default: - rn = "invalid sel"; goto die; } break; case 29: -// gen_op_mtc0_taghi(); - rn = "TagHi"; + switch (sel) { + case 0: + case 2: + case 4: + case 6: + gen_op_mtc0_taghi(); + rn = "TagHi"; + break; + case 1: + case 3: + case 5: + case 7: + gen_op_mtc0_datahi(); + rn = "DataHi"; + break; + default: + rn = "invalid sel"; + goto die; + } break; case 30: - gen_op_mtc0_errorepc(); - rn = "ErrorEPC"; + switch (sel) { + case 0: + gen_op_mtc0_errorepc(); + rn = "ErrorEPC"; + break; + default: + goto die; + } break; case 31: - gen_op_mtc0_desave(); - rn = "DESAVE"; + switch (sel) { + case 0: + gen_op_mtc0_desave(); /* EJTAG support */ + rn = "DESAVE"; + break; + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; default: - rn = "unknown"; goto die; } #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n", - env->PC, rn, T0, reg, sel); + fprintf(logfile, "mtc0 %s (reg %d sel %d)\n", + rn, reg, sel); } #endif return; @@ -1702,16 +2805,16 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) die: #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n", - env->PC, rn, T0, reg, sel); + fprintf(logfile, "mtc0 %s (reg %d sel %d)\n", + rn, reg, sel); } #endif generate_exception(ctx, EXCP_RI); } -static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) +static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) { - const unsigned char *opn = "unk"; + const char *opn = "unk"; if (!(ctx->CP0_Status & (1 << CP0St_CU0)) && (ctx->hflags & MIPS_HFLAG_UM) && @@ -1720,7 +2823,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "CP0 is not usable\n"); } - generate_exception_err (ctx, EXCP_CpU, 0); + generate_exception (ctx, EXCP_CpU); return; } @@ -1736,13 +2839,12 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) break; case OPC_MTC0: /* If we get an exception, we want to restart at next instruction */ + /* XXX: breaks for mtc in delay slot */ ctx->pc += 4; save_cpu_state(ctx, 1); ctx->pc -= 4; GEN_LOAD_REG_TN(T0, rt); gen_mtc0(ctx, rd, ctx->opcode & 0x7); - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; opn = "mtc0"; break; #if defined(MIPS_USES_R4K_TLB) @@ -1800,31 +2902,30 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd) MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); } -#ifdef MIPS_USES_FPU /* CP1 Branches (before delay slot) */ -static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond, +static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, int32_t offset) { target_ulong btarget; btarget = ctx->pc + 4 + offset; - switch (cond) { - case 0x0000: /* bc1f */ + switch (op) { + case OPC_BC1F: gen_op_bc1f(); MIPS_DEBUG("bc1f %08x", btarget); goto not_likely; - case 0x0002: /* bc1fl */ + case OPC_BC1FL: gen_op_bc1f(); MIPS_DEBUG("bc1fl %08x", btarget); goto likely; - case 0x0001: /* bc1t */ + case OPC_BC1T: gen_op_bc1t(); MIPS_DEBUG("bc1t %08x", btarget); not_likely: ctx->hflags |= MIPS_HFLAG_BC; break; - case 0x0003: /* bc1tl */ + case OPC_BC1TL: gen_op_bc1t(); MIPS_DEBUG("bc1tl %08x", btarget); likely: @@ -1832,7 +2933,7 @@ static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond, break; default: MIPS_INVAL("cp1 branch/jump"); - generate_exception(ctx, EXCP_RI); + generate_exception_err (ctx, EXCP_RI, 1); return; } gen_op_set_bcond(); @@ -1845,9 +2946,9 @@ static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond, } /* Coprocessor 1 (FPU) */ -static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) +static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) { - const unsigned char *opn = "unk"; + const char *opn = "unk"; switch (opc) { case OPC_MFC1: @@ -1865,7 +2966,7 @@ static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) case OPC_CFC1: if (fs != 0 && fs != 31) { MIPS_INVAL("cfc1 freg"); - generate_exception(ctx, EXCP_RI); + generate_exception_err (ctx, EXCP_RI, 1); return; } GEN_LOAD_IMM_TN(T1, fs); @@ -1874,9 +2975,9 @@ static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) opn = "cfc1"; break; case OPC_CTC1: - if (fs != 0 && fs != 31) { + if (fs != 0 && fs != 31) { MIPS_INVAL("ctc1 freg"); - generate_exception(ctx, EXCP_RI); + generate_exception_err (ctx, EXCP_RI, 1); return; } GEN_LOAD_IMM_TN(T1, fs); @@ -1890,7 +2991,7 @@ static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); } - generate_exception(ctx, EXCP_RI); + generate_exception_err (ctx, EXCP_RI, 1); return; } MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); @@ -1908,16 +3009,16 @@ static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs) */ #define CHECK_FR(ctx, freg) do { \ if (!((ctx)->CP0_Status & (1<opcode & 0x3f; + switch (ctx->opcode & FOP(0x3f, 0x1f)) { case FOP(0, 17): CHECK_FR(ctx, fs | ft | fd); @@ -2033,7 +3135,7 @@ static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorw_d(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "ceil.w.d"; + opn = "floor.w.d"; break; case FOP(33, 16): /* cvt.d.s */ CHECK_FR(ctx, fs | fd); @@ -2201,11 +3303,11 @@ static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int break; default: if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n", + fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n", ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); } - generate_exception(ctx, EXCP_RI); + generate_exception_err (ctx, EXCP_RI, 1); return; } if (binary) @@ -2213,14 +3315,27 @@ static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int else MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]); } -#endif -/* ISA extensions */ +static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) +{ + uint32_t ccbit; + + if (cc) + ccbit = 1 << (24 + cc); + else + ccbit = 1 << 23; + if (!tf) + gen_op_movf(ccbit, rd, rs); + else + gen_op_movt(ccbit, rd, rs); +} + +/* ISA extensions (ASEs) */ /* MIPS16 extension to MIPS32 */ /* SmartMIPS extension to MIPS32 */ -#ifdef TARGET_MIPS64 -static void gen_arith64 (DisasContext *ctx, uint16_t opc) +#ifdef MIPS_HAS_MIPS64 +static void gen_arith64 (DisasContext *ctx, uint32_t opc) { if (func == 0x02 && rd == 0) { /* NOP */ @@ -2265,7 +3380,7 @@ static void decode_opc (DisasContext *ctx) { int32_t offset; int rs, rt, rd, sa; - uint16_t op, op1; + uint32_t op, op1, op2; int16_t imm; /* make sure instructions are on a word boundary */ @@ -2279,76 +3394,86 @@ static void decode_opc (DisasContext *ctx) MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); gen_blikely(ctx); } - op = ctx->opcode >> 26; - rs = ((ctx->opcode >> 21) & 0x1F); - rt = ((ctx->opcode >> 16) & 0x1F); - rd = ((ctx->opcode >> 11) & 0x1F); - sa = ((ctx->opcode >> 6) & 0x1F); + op = MASK_OP_MAJOR(ctx->opcode); + rs = (ctx->opcode >> 21) & 0x1f; + rt = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 6) & 0x1f; imm = (int16_t)ctx->opcode; switch (op) { - case 0x00: /* Special opcode */ - op1 = ctx->opcode & 0x3F; + case OPC_SPECIAL: + op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { - case 0x00: /* Arithmetic with immediate */ - case 0x02 ... 0x03: - gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa); - break; - case 0x04: /* Arithmetic */ - case 0x06 ... 0x07: - case 0x0A ... 0x0B: - case 0x20 ... 0x27: - case 0x2A ... 0x2B: - gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt); - break; - case 0x18 ... 0x1B: /* MULT / DIV */ - gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt); - break; - case 0x08 ... 0x09: /* Jumps */ - gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa); + case OPC_SLL: /* Arithmetic with immediate */ + case OPC_SRL ... OPC_SRA: + gen_arith_imm(ctx, op1, rd, rt, sa); + break; + case OPC_SLLV: /* Arithmetic */ + case OPC_SRLV ... OPC_SRAV: + case OPC_MOVZ ... OPC_MOVN: + case OPC_ADD ... OPC_NOR: + case OPC_SLT ... OPC_SLTU: + gen_arith(ctx, op1, rd, rs, rt); + break; + case OPC_MULT ... OPC_DIVU: + gen_muldiv(ctx, op1, rs, rt); + break; + case OPC_JR ... OPC_JALR: + gen_compute_branch(ctx, op1, rs, rd, sa); return; - case 0x30 ... 0x34: /* Traps */ - case 0x36: - gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1); + case OPC_TGE ... OPC_TEQ: /* Traps */ + case OPC_TNE: + gen_trap(ctx, op1, rs, rt, -1); break; - case 0x10: /* Move from HI/LO */ - case 0x12: - gen_HILO(ctx, op1 | EXT_SPECIAL, rd); + case OPC_MFHI: /* Move from HI/LO */ + case OPC_MFLO: + gen_HILO(ctx, op1, rd); break; - case 0x11: - case 0x13: /* Move to HI/LO */ - gen_HILO(ctx, op1 | EXT_SPECIAL, rs); + case OPC_MTHI: + case OPC_MTLO: /* Move to HI/LO */ + gen_HILO(ctx, op1, rs); break; - case 0x0C: /* SYSCALL */ + case OPC_PMON: /* Pmon entry point */ + gen_op_pmon(sa); + break; + case OPC_SYSCALL: generate_exception(ctx, EXCP_SYSCALL); + ctx->bstate = BS_EXCP; break; - case 0x0D: /* BREAK */ + case OPC_BREAK: generate_exception(ctx, EXCP_BREAK); break; - case 0x0F: /* SYNC */ - /* Treat as a noop */ + case OPC_SPIM: /* SPIM ? */ + /* Implemented as RI exception for now. */ + MIPS_INVAL("spim (unofficial)"); + generate_exception(ctx, EXCP_RI); break; - case 0x05: /* Pmon entry point */ - gen_op_pmon((ctx->opcode >> 6) & 0x1F); + case OPC_SYNC: + /* Treat as a noop. */ break; - case 0x01: /* MOVCI */ -#if defined (MIPS_HAS_MOVCI) - /* XXX */ -#else - /* Not implemented */ - generate_exception_err (ctx, EXCP_CpU, 1); -#endif + case OPC_MOVCI: + gen_op_cp1_enabled(); + gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, + (ctx->opcode >> 16) & 1); break; -#if defined (TARGET_MIPS64) - case 0x14: /* MIPS64 specific opcodes */ - case 0x16: - case 0x17: - case 0x1C ... 0x1F: - case 0x2C ... 0x2F: - case 0x37: - case 0x39 ... 0x3B: - case 0x3E ... 0x3F: +#ifdef MIPS_HAS_MIPS64 + /* MIPS64 specific opcodes */ + case OPC_DSLL: + case OPC_DSRL ... OPC_DSRA: + case OPC_DSLL32: + case OPC_DSRL32 ... OPC_DSRA32: + gen_arith_imm(ctx, op1, rd, rt, sa); + break; + case OPC_DSLLV: + case OPC_DSRLV ... OPC_DSRAV: + case OPC_DADD ... OPC_DSUBU: + gen_arith(ctx, op1, rd, rs, rt); + break; + case OPC_DMULT ... OPC_DDIVU: + gen_muldiv(ctx, op1, rs, rt); + break; #endif default: /* Invalid */ MIPS_INVAL("special"); @@ -2356,23 +3481,20 @@ static void decode_opc (DisasContext *ctx) break; } break; - case 0x1C: /* Special2 opcode */ - op1 = ctx->opcode & 0x3F; + case OPC_SPECIAL2: + op1 = MASK_SPECIAL2(ctx->opcode); switch (op1) { -#if defined (MIPS_USES_R4K_EXT) - /* Those instructions are not part of MIPS32 core */ - case 0x00 ... 0x01: /* Multiply and add/sub */ - case 0x04 ... 0x05: - gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt); + case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ + case OPC_MSUB ... OPC_MSUBU: + gen_muldiv(ctx, op1, rs, rt); break; - case 0x02: /* MUL */ - gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt); + case OPC_MUL: + gen_arith(ctx, op1, rd, rs, rt); break; - case 0x20 ... 0x21: /* CLO / CLZ */ - gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs); + case OPC_CLZ ... OPC_CLO: + gen_cl(ctx, op1, rd, rs); break; -#endif - case 0x3F: /* SDBBP */ + case OPC_SDBBP: /* XXX: not clear which exception should be raised * when in debug mode... */ @@ -2383,22 +3505,109 @@ static void decode_opc (DisasContext *ctx) } /* Treat as a noop */ break; +#ifdef MIPS_HAS_MIPS64 + case OPC_DCLZ ... OPC_DCLO: + gen_cl(ctx, op1, rd, rs); + break; +#endif default: /* Invalid */ MIPS_INVAL("special2"); generate_exception(ctx, EXCP_RI); break; } break; - case 0x01: /* B REGIMM opcode */ - op1 = ((ctx->opcode >> 16) & 0x1F); + case OPC_SPECIAL3: + op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { - case 0x00 ... 0x03: /* REGIMM branches */ - case 0x10 ... 0x13: - gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2); + case OPC_EXT: + case OPC_INS: + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_BSHFL: + op2 = MASK_BSHFL(ctx->opcode); + switch (op2) { + case OPC_WSBH: + GEN_LOAD_REG_TN(T1, rt); + gen_op_wsbh(); + break; + case OPC_SEB: + GEN_LOAD_REG_TN(T1, rt); + gen_op_seb(); + break; + case OPC_SEH: + GEN_LOAD_REG_TN(T1, rt); + gen_op_seh(); + break; + default: /* Invalid */ + MIPS_INVAL("bshfl"); + generate_exception(ctx, EXCP_RI); + break; + } + GEN_STORE_TN_REG(rd, T0); + break; + case OPC_RDHWR: + switch (rd) { + case 0: + gen_op_rdhwr_cpunum(); + break; + case 1: + gen_op_rdhwr_synci_step(); + break; + case 2: + gen_op_rdhwr_cc(); + break; + case 3: + gen_op_rdhwr_ccres(); + break; + default: /* Invalid */ + MIPS_INVAL("rdhwr"); + generate_exception(ctx, EXCP_RI); + break; + } + GEN_STORE_TN_REG(rt, T0); + break; +#ifdef MIPS_HAS_MIPS64 + case OPC_DEXTM ... OPC_DEXT: + case OPC_DINSM ... OPC_DINS: + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_DBSHFL: + op2 = MASK_DBSHFL(ctx->opcode); + switch (op2) { + case OPC_DSBH: + GEN_LOAD_REG_TN(T1, rt); + gen_op_dsbh(); + break; + case OPC_DSHD: + GEN_LOAD_REG_TN(T1, rt); + gen_op_dshd(); + break; + default: /* Invalid */ + MIPS_INVAL("dbshfl"); + generate_exception(ctx, EXCP_RI); + break; + } + GEN_STORE_TN_REG(rd, T0); +#endif + default: /* Invalid */ + MIPS_INVAL("special3"); + generate_exception(ctx, EXCP_RI); + break; + } + break; + case OPC_REGIMM: + op1 = MASK_REGIMM(ctx->opcode); + switch (op1) { + case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */ + case OPC_BLTZAL ... OPC_BGEZALL: + gen_compute_branch(ctx, op1, rs, -1, imm << 2); return; - case 0x08 ... 0x0C: /* Traps */ - case 0x0E: - gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm); + case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ + case OPC_TNEI: + gen_trap(ctx, op1, rs, -1, imm); + break; + case OPC_SYNCI: + /* treat as noop */ break; default: /* Invalid */ MIPS_INVAL("REGIMM"); @@ -2406,48 +3615,78 @@ static void decode_opc (DisasContext *ctx) break; } break; - case 0x10: /* CP0 opcode */ - op1 = ((ctx->opcode >> 21) & 0x1F); + case OPC_CP0: + op1 = MASK_CP0(ctx->opcode); switch (op1) { - case 0x00: - case 0x04: - gen_cp0(ctx, op1 | EXT_CP0, rt, rd); + case OPC_MFC0: + case OPC_MTC0: +#ifdef MIPS_HAS_MIPS64 + case OPC_DMFC0: + case OPC_DMTC0: +#endif + gen_cp0(ctx, op1, rt, rd); + break; + case OPC_C0_FIRST ... OPC_C0_LAST: + gen_cp0(ctx, MASK_C0(ctx->opcode), rt, rd); + break; + case OPC_MFMC0: + op2 = MASK_MFMC0(ctx->opcode); + switch (op2) { + case OPC_DI: + gen_op_di(); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case OPC_EI: + gen_op_ei(); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + default: /* Invalid */ + MIPS_INVAL("MFMC0"); + generate_exception(ctx, EXCP_RI); + break; + } + GEN_STORE_TN_REG(rt, T0); break; + /* Shadow registers (not implemented). */ + case OPC_RDPGPR: + case OPC_WRPGPR: default: - gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd); + generate_exception(ctx, EXCP_RI); break; } break; - case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */ - gen_arith_imm(ctx, op, rt, rs, imm); - break; - case 0x02 ... 0x03: /* Jump */ - offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2; - gen_compute_branch(ctx, op, rs, rt, offset); - return; - case 0x04 ... 0x07: /* Branch */ - case 0x14 ... 0x17: - gen_compute_branch(ctx, op, rs, rt, imm << 2); - return; - case 0x20 ... 0x2E: /* Load and stores */ - case 0x30: - case 0x38: - gen_ldst(ctx, op, rt, rs, imm); - break; - case 0x2F: /* Cache operation */ - /* Treat as a noop */ - break; - case 0x33: /* Prefetch */ + case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */ + gen_arith_imm(ctx, op, rt, rs, imm); + break; + case OPC_J ... OPC_JAL: /* Jump */ + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; + gen_compute_branch(ctx, op, rs, rt, offset); + return; + case OPC_BEQ ... OPC_BGTZ: /* Branch */ + case OPC_BEQL ... OPC_BGTZL: + gen_compute_branch(ctx, op, rs, rt, imm << 2); + return; + case OPC_LB ... OPC_LWR: /* Load and stores */ + case OPC_SB ... OPC_SW: + case OPC_SWR: + case OPC_LL: + case OPC_SC: + gen_ldst(ctx, op, rt, rs, imm); + break; + case OPC_CACHE: + /* Treat as a noop */ + break; + case OPC_PREF: /* Treat as a noop */ break; - case 0x3F: /* HACK */ - break; /* Floating point. */ - case 0x31: /* LWC1 */ - case 0x35: /* LDC1 */ - case 0x39: /* SWC1 */ - case 0x3D: /* SDC1 */ + case OPC_LWC1: + case OPC_LDC1: + case OPC_SWC1: + case OPC_SDC1: #if defined(MIPS_USES_FPU) save_cpu_state(ctx, 1); gen_op_cp1_enabled(); @@ -2457,65 +3696,80 @@ static void decode_opc (DisasContext *ctx) #endif break; - case 0x11: /* CP1 opcode */ + case OPC_CP1: #if defined(MIPS_USES_FPU) save_cpu_state(ctx, 1); gen_op_cp1_enabled(); - op1 = ((ctx->opcode >> 21) & 0x1F); + op1 = MASK_CP1(ctx->opcode); switch (op1) { - case 0x00: /* mfc1 */ - case 0x02: /* cfc1 */ - case 0x04: /* mtc1 */ - case 0x06: /* ctc1 */ - gen_cp1(ctx, op1 | EXT_CP1, rt, rd); - break; - case 0x08: /* bc */ - gen_compute_branch1(ctx, rt, imm << 2); + case OPC_MFC1: + case OPC_CFC1: + case OPC_MTC1: + case OPC_CTC1: + gen_cp1(ctx, op1, rt, rd); + break; + case OPC_BC1: + gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2); return; - case 0x10: /* 16: fmt=single fp */ - case 0x11: /* 17: fmt=double fp */ - case 0x14: /* 20: fmt=32bit fixed */ - case 0x15: /* 21: fmt=64bit fixed */ - gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f); + case OPC_S_FMT: + case OPC_D_FMT: + case OPC_W_FMT: + case OPC_L_FMT: + gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa); break; default: generate_exception_err(ctx, EXCP_RI, 1); break; } - break; #else generate_exception_err(ctx, EXCP_CpU, 1); #endif break; /* COP2. */ - case 0x32: /* LWC2 */ - case 0x36: /* LDC2 */ - case 0x3A: /* SWC2 */ - case 0x3E: /* SDC2 */ - case 0x12: /* CP2 opcode */ - /* Not implemented */ + case OPC_LWC2: + case OPC_LDC2: + case OPC_SWC2: + case OPC_SDC2: + case OPC_CP2: + /* COP2: Not implemented. */ generate_exception_err(ctx, EXCP_CpU, 2); break; - case 0x13: /* CP3 opcode */ + case OPC_CP3: + gen_op_cp1_enabled(); + op1 = MASK_CP3(ctx->opcode); + switch (op1) { /* Not implemented */ - generate_exception_err(ctx, EXCP_CpU, 3); + default: + generate_exception_err(ctx, EXCP_RI, 1); + break; + } break; -#if defined (TARGET_MIPS64) - case 0x18 ... 0x1B: - case 0x27: - case 0x34: - case 0x37: - /* MIPS64 opcodes */ +#ifdef MIPS_HAS_MIPS64 + /* MIPS64 opcodes */ + case OPC_LWU: + case OPC_LDL ... OPC_LDR: + case OPC_SDL ... OPC_SDR: + case OPC_LLD: + case OPC_LD: + case OPC_SCD: + case OPC_SD: + gen_ldst(ctx, op, rt, rs, imm); + break; + case OPC_DADDI ... OPC_DADDIU: + gen_arith_imm(ctx, op, rt, rs, imm); + break; #endif -#if defined (MIPS_HAS_JALX) - case 0x1D: - /* JALX: not implemented */ +#ifdef MIPS_HAS_MIPS16 + case OPC_JALX: + /* MIPS16: Not implemented. */ +#endif +#ifdef MIPS_HAS_MDMX + case OPC_MDMX: + /* MDMX: Not implemented. */ #endif - case 0x1E: - /* ASE specific */ default: /* Invalid */ MIPS_INVAL(""); generate_exception(ctx, EXCP_RI); @@ -2707,7 +3961,6 @@ int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } -#ifdef MIPS_USES_FPU void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -2721,19 +3974,19 @@ void fpu_dump_state(CPUState *env, FILE *f, fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n", env->fcr0, env->fcr31, - (env->CP0_Status & (1<CP0_Status & (1 << CP0St_FR)) != 0); fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); - for(i=0; i < 32; i+=2) { - fpu_fprintf(f, "f%02d: ", i); + for(i = 0; i < 32; i += 2) { + fpu_fprintf(f, "%s: ", fregnames[i]); printfpr(FPR(env, i)); } #undef printfpr } -void dump_fpu(CPUState *env) +void dump_fpu (CPUState *env) { if (loglevel) { fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n", @@ -2741,7 +3994,6 @@ void dump_fpu(CPUState *env) fpu_dump_state(env, logfile, fprintf, 0); } } -#endif /* MIPS_USES_FPU */ void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), @@ -2772,9 +4024,8 @@ void cpu_dump_state (CPUState *env, FILE *f, c0_status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n", env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); -#ifdef MIPS_USES_FPU - fpu_dump_state(env, f, cpu_fprintf, flags); -#endif + if (c0_status & (1 << CP0St_CU1)) + fpu_dump_state(env, f, cpu_fprintf, flags); } CPUMIPSState *cpu_mips_init (void) @@ -2802,16 +4053,12 @@ void cpu_reset (CPUMIPSState *env) env->tlb_in_use = MIPS_TLB_NB; #endif env->CP0_Wired = 0; + /* SMP not implemented */ + env->CP0_EBase = 0x80000000; env->CP0_Config0 = MIPS_CONFIG0; -#if defined (MIPS_CONFIG1) - env->CP0_Config1 = MIPS_CONFIG1; -#endif -#if defined (MIPS_CONFIG2) - env->CP0_Config2 = MIPS_CONFIG2; -#endif -#if defined (MIPS_CONFIG3) - env->CP0_Config3 = MIPS_CONFIG3; -#endif + env->CP0_Config1 = MIPS_CONFIG1; + env->CP0_Config2 = MIPS_CONFIG2; + env->CP0_Config3 = MIPS_CONFIG3; env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV); env->CP0_WatchLo = 0; env->hflags = MIPS_HFLAG_ERL; @@ -2825,4 +4072,7 @@ void cpu_reset (CPUMIPSState *env) #ifdef MIPS_USES_FPU env->fcr0 = MIPS_FCR0; #endif + /* XXX some guesswork here, values are CPU specific */ + env->SYNCI_Step = 16; + env->CCRes = 2; } -- cgit v1.2.3 From e16fe40c87272f0bc081b5a915db54eab2dc74dc Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Dec 2006 21:38:37 +0000 Subject: Move the MIPS CPU timer in a seperate file, by Alec Voropay. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2225 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/mips_r4k.c | 98 ++++++++------------------------------------------------- hw/mips_timer.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 4 +++ 4 files changed, 103 insertions(+), 86 deletions(-) create mode 100644 hw/mips_timer.c diff --git a/Makefile.target b/Makefile.target index bdc365908..aa9a01306 100644 --- a/Makefile.target +++ b/Makefile.target @@ -357,7 +357,7 @@ VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) -VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o ide.o +VL_OBJS+= mips_r4k.o mips_timer.o dma.o vga.o serial.o i8254.o i8259.o ide.o #VL_OBJS+= #pckbd.o fdc.o m48t59.o endif ifeq ($(TARGET_BASE_ARCH), sparc) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 60eb191bd..0ddd91627 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -1,3 +1,12 @@ +/* + * QEMU/MIPS pseudo-board + * + * emulates a simple machine with ISA-like bus. + * ISA IO space mapped to the 0x14000000 (PHYS) and + * ISA memory at the 0x10000000 (PHYS, 16Mb in size). + * All peripherial devices are attached to this "bus" with + * the standard PC ISA addresses. +*/ #include "vl.h" #define BIOS_FILENAME "mips_bios.bin" @@ -13,8 +22,10 @@ static const int ide_irq[2] = { 14, 15 }; extern FILE *logfile; -static PITState *pit; +static PITState *pit; /* PIT i8254 */ +/*i8254 PIT is attached to the IRQ0 at PIC i8259 */ +/*The PIC is attached to the MIPS CPU INT0 pin */ static void pic_irq_request(void *opaque, int level) { CPUState *env = first_cpu; @@ -27,89 +38,6 @@ static void pic_irq_request(void *opaque, int level) } } -void cpu_mips_irqctrl_init (void) -{ -} - -/* XXX: do not use a global */ -uint32_t cpu_mips_get_random (CPUState *env) -{ - static uint32_t seed = 0; - uint32_t idx; - seed = seed * 314159 + 1; - idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired; - return idx; -} - -/* MIPS R4K timer */ -uint32_t cpu_mips_get_count (CPUState *env) -{ - return env->CP0_Count + - (uint32_t)muldiv64(qemu_get_clock(vm_clock), - 100 * 1000 * 1000, ticks_per_sec); -} - -static void cpu_mips_update_count (CPUState *env, uint32_t count, - uint32_t compare) -{ - uint64_t now, next; - uint32_t tmp; - - tmp = count; - if (count == compare) - tmp++; - now = qemu_get_clock(vm_clock); - next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); - if (next == now) - next++; -#if 0 - if (logfile) { - fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", - __func__, now, count, compare, next - now); - } -#endif - /* Store new count and compare registers */ - env->CP0_Compare = compare; - env->CP0_Count = - count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec); - /* Adjust timer */ - qemu_mod_timer(env->timer, next); -} - -void cpu_mips_store_count (CPUState *env, uint32_t value) -{ - cpu_mips_update_count(env, value, env->CP0_Compare); -} - -void cpu_mips_store_compare (CPUState *env, uint32_t value) -{ - cpu_mips_update_count(env, cpu_mips_get_count(env), value); - env->CP0_Cause &= ~0x00008000; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); -} - -static void mips_timer_cb (void *opaque) -{ - CPUState *env; - - env = opaque; -#if 0 - if (logfile) { - fprintf(logfile, "%s\n", __func__); - } -#endif - cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); - env->CP0_Cause |= 0x00008000; - cpu_interrupt(env, CPU_INTERRUPT_HARD); -} - -void cpu_mips_clock_init (CPUState *env) -{ - env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); - env->CP0_Compare = 0; - cpu_mips_update_count(env, 1, 0); -} - static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { @@ -247,7 +175,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, env->initrd_filename = initrd_filename; } - /* Init internal devices */ + /* Init CPU internal devices */ cpu_mips_clock_init(env); cpu_mips_irqctrl_init(); diff --git a/hw/mips_timer.c b/hw/mips_timer.c new file mode 100644 index 000000000..251324d7b --- /dev/null +++ b/hw/mips_timer.c @@ -0,0 +1,85 @@ +#include "vl.h" + +void cpu_mips_irqctrl_init (void) +{ +} + +/* XXX: do not use a global */ +uint32_t cpu_mips_get_random (CPUState *env) +{ + static uint32_t seed = 0; + uint32_t idx; + seed = seed * 314159 + 1; + idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired; + return idx; +} + +/* MIPS R4K timer */ +uint32_t cpu_mips_get_count (CPUState *env) +{ + return env->CP0_Count + + (uint32_t)muldiv64(qemu_get_clock(vm_clock), + 100 * 1000 * 1000, ticks_per_sec); +} + +static void cpu_mips_update_count (CPUState *env, uint32_t count, + uint32_t compare) +{ + uint64_t now, next; + uint32_t tmp; + + tmp = count; + if (count == compare) + tmp++; + now = qemu_get_clock(vm_clock); + next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); + if (next == now) + next++; +#if 0 + if (logfile) { + fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", + __func__, now, count, compare, next - now); + } +#endif + /* Store new count and compare registers */ + env->CP0_Compare = compare; + env->CP0_Count = + count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec); + /* Adjust timer */ + qemu_mod_timer(env->timer, next); +} + +void cpu_mips_store_count (CPUState *env, uint32_t value) +{ + cpu_mips_update_count(env, value, env->CP0_Compare); +} + +void cpu_mips_store_compare (CPUState *env, uint32_t value) +{ + cpu_mips_update_count(env, cpu_mips_get_count(env), value); + env->CP0_Cause &= ~0x00008000; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); +} + +static void mips_timer_cb (void *opaque) +{ + CPUState *env; + + env = opaque; +#if 0 + if (logfile) { + fprintf(logfile, "%s\n", __func__); + } +#endif + cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); + env->CP0_Cause |= 0x00008000; + cpu_interrupt(env, CPU_INTERRUPT_HARD); +} + +void cpu_mips_clock_init (CPUState *env) +{ + env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); + env->CP0_Compare = 0; + cpu_mips_update_count(env, 1, 0); +} + diff --git a/vl.h b/vl.h index eedef51bd..89b24cf91 100644 --- a/vl.h +++ b/vl.h @@ -1024,6 +1024,10 @@ extern QEMUMachine heathrow_machine; /* mips_r4k.c */ extern QEMUMachine mips_machine; +/* mips_timer.c */ +extern void cpu_mips_clock_init(CPUState *); +extern void cpu_mips_irqctrl_init (void); + /* shix.c */ extern QEMUMachine shix_machine; -- cgit v1.2.3 From bb8a53ad91e97389609fdda3f79536fcbe322930 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Dec 2006 23:12:49 +0000 Subject: Update copyright notice. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2226 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index d54c63336..cf625488e 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004-2005 Jocelyn Mayer * Copyright (c) 2006 Marius Groeger (FPU operations) + * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public -- cgit v1.2.3 From e1449664164bff3b549a3b8e07ecdd0984fef53d Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Dec 2006 00:30:19 +0000 Subject: Simplify mask construction. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2227 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index cf625488e..16b73a148 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -353,8 +353,8 @@ enum { OPC_BC1TL = (0x03 << 16) | OPC_BC1, }; -#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & ((0x1F << 21) | (0x3 << 16))) -#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & ((0x1F << 21) | 0x3F)) +#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & (0x3 << 16)) +#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) #define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) #define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) -- cgit v1.2.3 From aa328addc0ed51751baa758c1eeb978c6fb77c74 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Dec 2006 16:22:15 +0000 Subject: Fix reset handling, CP0 isn't enabled by default (a fact which doesn't matter when running in kernel space). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2228 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 55 ++++++++++++++++++------------------------------- target-mips/translate.c | 14 ++++++++++--- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 6b73cb821..a222d6b0e 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -245,7 +245,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, void do_interrupt (CPUState *env) { - target_ulong pc, offset; + target_ulong offset; int cause = -1; if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { @@ -284,8 +284,7 @@ void do_interrupt (CPUState *env) set_DEPC: if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, - * come back to the jump - */ + come back to the jump. */ env->CP0_DEPC = env->PC - 4; env->hflags &= ~MIPS_HFLAG_BMASK; } else { @@ -294,41 +293,29 @@ void do_interrupt (CPUState *env) enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; /* EJTAG probe trap enable is not implemented... */ - pc = 0xBFC00480; + env->PC = 0xBFC00480; break; case EXCP_RESET: -#ifdef MIPS_USES_R4K_TLB - env->CP0_random = MIPS_TLB_NB - 1; -#endif - env->CP0_Wired = 0; - env->CP0_Config0 = MIPS_CONFIG0; - env->CP0_Config1 = MIPS_CONFIG1; - env->CP0_Config2 = MIPS_CONFIG2; - env->CP0_Config3 = MIPS_CONFIG3; - env->CP0_WatchLo = 0; - env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV); - goto set_error_EPC; + cpu_reset(env); + break; case EXCP_SRESET: - env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) | - (1 << CP0St_SR); + env->CP0_Status = (1 << CP0St_SR); env->CP0_WatchLo = 0; goto set_error_EPC; case EXCP_NMI: - env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) | - (1 << CP0St_NMI); + env->CP0_Status = (1 << CP0St_NMI); set_error_EPC: if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, - * come back to the jump - */ + come back to the jump. */ env->CP0_ErrorEPC = env->PC - 4; env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_ErrorEPC = env->PC; } env->hflags |= MIPS_HFLAG_ERL; - env->CP0_Status |= (1 << CP0St_ERL); - pc = 0xBFC00000; + env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); + env->PC = 0xBFC00000; break; case EXCP_MCHECK: cause = 24; @@ -385,19 +372,9 @@ void do_interrupt (CPUState *env) offset = 0x000; goto set_EPC; set_EPC: - if (env->CP0_Status & (1 << CP0St_BEV)) { - pc = 0xBFC00200; - } else { - pc = 0x80000000; - } - env->hflags |= MIPS_HFLAG_EXL; - env->CP0_Status |= (1 << CP0St_EXL); - pc += offset; - env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, - * come back to the jump - */ + come back to the jump. */ env->CP0_EPC = env->PC - 4; env->CP0_Cause |= 0x80000000; env->hflags &= ~MIPS_HFLAG_BMASK; @@ -405,6 +382,15 @@ void do_interrupt (CPUState *env) env->CP0_EPC = env->PC; env->CP0_Cause &= ~0x80000000; } + if (env->CP0_Status & (1 << CP0St_BEV)) { + env->PC = 0xBFC00200; + } else { + env->PC = 0x80000000; + } + env->hflags |= MIPS_HFLAG_EXL; + env->CP0_Status |= (1 << CP0St_EXL); + env->PC += offset; + env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); break; default: if (logfile) { @@ -414,7 +400,6 @@ void do_interrupt (CPUState *env) printf("Invalid MIPS exception %d. Exiting\n", env->exception_index); exit(1); } - env->PC = pc; if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n" " S %08x C %08x A %08x D %08x\n", diff --git a/target-mips/translate.c b/target-mips/translate.c index 16b73a148..5b95c41bd 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2817,8 +2817,8 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) { const char *opn = "unk"; - if (!(ctx->CP0_Status & (1 << CP0St_CU0)) && - (ctx->hflags & MIPS_HFLAG_UM) && + if ((!ctx->CP0_Status & (1 << CP0St_CU0) && + (ctx->hflags & MIPS_HFLAG_UM)) && !(ctx->hflags & MIPS_HFLAG_ERL) && !(ctx->hflags & MIPS_HFLAG_EXL)) { if (loglevel & CPU_LOG_TB_IN_ASM) { @@ -4048,6 +4048,14 @@ void cpu_reset (CPUMIPSState *env) tlb_flush(env, 1); /* Minimal init */ + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + * come back to the jump. */ + env->CP0_ErrorEPC = env->PC - 4; + env->hflags &= ~MIPS_HFLAG_BMASK; + } else { + env->CP0_ErrorEPC = env->PC; + } env->PC = 0xBFC00000; #if defined (MIPS_USES_R4K_TLB) env->CP0_random = MIPS_TLB_NB - 1; @@ -4060,7 +4068,7 @@ void cpu_reset (CPUMIPSState *env) env->CP0_Config1 = MIPS_CONFIG1; env->CP0_Config2 = MIPS_CONFIG2; env->CP0_Config3 = MIPS_CONFIG3; - env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV); + env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); env->CP0_WatchLo = 0; env->hflags = MIPS_HFLAG_ERL; /* Count register increments in debug mode, EJTAG version 1 */ -- cgit v1.2.3 From ea55ffb37378dcb16972aef6ef898b3d0ba17fb0 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Dec 2006 17:16:55 +0000 Subject: Move date/time init to the RTC implementation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2229 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mc146818rtc.c | 25 +++++++++++++++++++++++++ hw/pc.c | 22 ---------------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 9d4cbed90..bad4cbd86 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -380,6 +380,29 @@ void rtc_set_date(RTCState *s, const struct tm *tm) rtc_copy_date(s); } +/* PC cmos mappings */ +#define REG_IBM_CENTURY_BYTE 0x32 +#define REG_IBM_PS2_CENTURY_BYTE 0x37 + +void rtc_set_date_from_host(RTCState *s) +{ + time_t ti; + struct tm *tm; + int val; + + /* set the CMOS date */ + time(&ti); + if (rtc_utc) + tm = gmtime(&ti); + else + tm = localtime(&ti); + rtc_set_date(s, tm); + + val = to_bcd(s, (tm->tm_year / 100) + 19); + rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); + rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); +} + static void rtc_save(QEMUFile *f, void *opaque) { RTCState *s = opaque; @@ -444,6 +467,8 @@ RTCState *rtc_init(int base, int irq) s->cmos_data[RTC_REG_C] = 0x00; s->cmos_data[RTC_REG_D] = 0x80; + rtc_set_date_from_host(s); + s->periodic_timer = qemu_new_timer(vm_clock, rtc_periodic_timer, s); s->second_timer = qemu_new_timer(vm_clock, diff --git a/hw/pc.c b/hw/pc.c index ab235c7ee..77a6467c7 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -111,14 +111,6 @@ static void pic_irq_request(void *opaque, int level) /* PC cmos mappings */ #define REG_EQUIPMENT_BYTE 0x14 -#define REG_IBM_CENTURY_BYTE 0x32 -#define REG_IBM_PS2_CENTURY_BYTE 0x37 - - -static inline int to_bcd(RTCState *s, int a) -{ - return ((a / 10) << 4) | (a % 10); -} static int cmos_get_fd_drive_type(int fd0) { @@ -167,22 +159,8 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table RTCState *s = rtc_state; int val; int fd0, fd1, nb; - time_t ti; - struct tm *tm; int i; - /* set the CMOS date */ - time(&ti); - if (rtc_utc) - tm = gmtime(&ti); - else - tm = localtime(&ti); - rtc_set_date(s, tm); - - val = to_bcd(s, (tm->tm_year / 100) + 19); - rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); - rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); - /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ -- cgit v1.2.3 From cd75cf10ca75ae2dbd8ea5a79d138cff900a9edf Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Dec 2006 17:18:01 +0000 Subject: .cvsignore m68k-user. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2230 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.cvsignore b/.cvsignore index 7be41c433..cd2812715 100644 --- a/.cvsignore +++ b/.cvsignore @@ -27,6 +27,7 @@ mips-softmmu mipsel-softmmu mips-user mipsel-user +m68k-user .gdbinit sh4-user sh4-softmmu -- cgit v1.2.3 From afdfa781e66b689c6c8ee37b7da66bda59df73d2 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Dec 2006 18:15:35 +0000 Subject: MIPS RTC emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2231 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/mips_r4k.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index aa9a01306..1efe348ae 100644 --- a/Makefile.target +++ b/Makefile.target @@ -358,7 +358,7 @@ DEFINES += -DHAS_AUDIO 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+= #pckbd.o fdc.o m48t59.o +VL_OBJS+= mc146818rtc.o #pckbd.o fdc.o m48t59.o endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 0ddd91627..61db814d9 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -135,6 +135,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, unsigned long bios_offset; int ret; CPUState *env; + static RTCState *rtc_state; int i; env = cpu_init(); @@ -179,12 +180,15 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, cpu_mips_clock_init(env); cpu_mips_irqctrl_init(); + rtc_state = rtc_init(0x70, 8); + /* Register 64 KB of ISA IO space at 0x14000000 */ isa_mmio_init(0x14000000, 0x00010000); isa_mem_base = 0x10000000; isa_pic = pic_init(pic_irq_request, env); pit = pit_init(0x40, 0); + serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); isa_vga_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); -- cgit v1.2.3 From 9f08349345dae1d67effb8494c8386dd74b94128 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Dec 2006 18:28:42 +0000 Subject: Spelling fixes, thanks to Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2232 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- hw/ne2000.c | 2 +- hw/smc91c111.c | 2 +- hw/unin_pci.c | 2 +- target-sh4/README.sh4 | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 5950625fb..f9a06e530 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -398,7 +398,7 @@ int cpu_exec(CPUState *env1) break; } else if (env->user_mode_only) { /* if user mode only, we simulate a fake exception - which will be hanlded outside the cpu execution + which will be handled outside the cpu execution loop */ #if defined(TARGET_I386) do_interrupt_user(env->exception_index, diff --git a/hw/ne2000.c b/hw/ne2000.c index 14d48ee95..94700c17b 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -312,7 +312,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) } s->curpag = next >> 8; - /* now we can signal we have receive something */ + /* now we can signal we have received something */ s->isr |= ENISR_RX; ne2000_update_irq(s); } diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 214e92efc..1ef5b5689 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -615,7 +615,7 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) return; - /* Short packets are padded with zeros. Recieveing a packet + /* Short packets are padded with zeros. Receiving a packet < 64 bytes long is considered an error condition. */ if (size < 64) packetsize = 64; diff --git a/hw/unin_pci.c b/hw/unin_pci.c index e47f4b3ac..6448a6f25 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -183,7 +183,7 @@ PCIBus *pci_pmac_init(void *pic) d->config[0x0E] = 0x00; // header_type d->config[0x34] = 0x00; // capabilities_pointer -#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly +#if 0 // XXX: not activated as PPC BIOS doesn't handle multiple buses properly /* pci-to-pci bridge */ d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, NULL, NULL); diff --git a/target-sh4/README.sh4 b/target-sh4/README.sh4 index b88717532..2edda9f04 100644 --- a/target-sh4/README.sh4 +++ b/target-sh4/README.sh4 @@ -113,7 +113,7 @@ GDB remote target support has been implemented and lightly tested. Files ----- -File names are harcoded at this time. The bootloader must be stored in +File names are hardcoded at this time. The bootloader must be stored in shix_bios.bin in the current directory. The initial Linux image must be stored in shix_linux_nand.bin in the current directory in NAND format. Test files can be obtained from -- cgit v1.2.3 From 71fb7241c65ef2de8b55e6907e674b8f766b3061 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Dec 2006 20:07:37 +0000 Subject: Fix build of MIPS target without FPU support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2233 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 ++ target-mips/translate.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/target-mips/op.c b/target-mips/op.c index 84fcbd9e0..35a13657e 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -627,6 +627,7 @@ void op_movz (void) RETURN(); } +#ifdef MIPS_USES_FPU void op_movf (void) { if (!(env->fcr31 & PARAM1)) @@ -640,6 +641,7 @@ void op_movt (void) env->gpr[PARAM2] = env->gpr[PARAM3]; RETURN(); } +#endif /* Tests */ #define OP_COND(name, cond) \ diff --git a/target-mips/translate.c b/target-mips/translate.c index 5b95c41bd..74fa11416 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -390,6 +390,8 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); +#ifdef MIPS_USES_FPU + static const char *fregnames[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", @@ -473,6 +475,8 @@ static inline void gen_cmp_ ## fmt(int n) \ FOP_CONDS(d) FOP_CONDS(s) +#endif /* MIPS_USES_FPU */ + typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; @@ -633,10 +637,12 @@ OP_LD_TABLE(bu); OP_ST_TABLE(b); OP_LD_TABLE(l); OP_ST_TABLE(c); +#ifdef MIPS_USES_FPU OP_LD_TABLE(wc1); OP_ST_TABLE(wc1); OP_LD_TABLE(dc1); OP_ST_TABLE(dc1); +#endif /* Load and store */ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, @@ -785,6 +791,8 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); } +#ifdef MIPS_USES_FPU + /* Load and store */ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, int base, int16_t offset) @@ -832,6 +840,8 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); } +#endif /* MIPS_USES_FPU */ + /* Arithmetic with immediate operand */ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) @@ -2903,6 +2913,8 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); } +#ifdef MIPS_USES_FPU + /* CP1 Branches (before delay slot) */ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, int32_t offset) @@ -3331,6 +3343,8 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) gen_op_movt(ccbit, rd, rs); } +#endif /* MIPS_USES_FPU */ + /* ISA extensions (ASEs) */ /* MIPS16 extension to MIPS32 */ /* SmartMIPS extension to MIPS32 */ @@ -3453,11 +3467,13 @@ static void decode_opc (DisasContext *ctx) /* Treat as a noop. */ break; +#ifdef MIPS_USES_FPU case OPC_MOVCI: gen_op_cp1_enabled(); gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, (ctx->opcode >> 16) & 1); break; +#endif #ifdef MIPS_HAS_MIPS64 /* MIPS64 specific opcodes */ @@ -3737,6 +3753,7 @@ static void decode_opc (DisasContext *ctx) generate_exception_err(ctx, EXCP_CpU, 2); break; +#ifdef MIPS_USES_FPU case OPC_CP3: gen_op_cp1_enabled(); op1 = MASK_CP3(ctx->opcode); @@ -3747,6 +3764,7 @@ static void decode_opc (DisasContext *ctx) break; } break; +#endif #ifdef MIPS_HAS_MIPS64 /* MIPS64 opcodes */ @@ -3962,6 +3980,8 @@ int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } +#ifdef MIPS_USES_FPU + void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -3996,6 +4016,8 @@ void dump_fpu (CPUState *env) } } +#endif /* MIPS_USES_FPU */ + void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -4025,8 +4047,10 @@ void cpu_dump_state (CPUState *env, FILE *f, c0_status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n", env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); +#ifdef MIPS_USES_FPU if (c0_status & (1 << CP0St_CU1)) fpu_dump_state(env, f, cpu_fprintf, flags); +#endif } CPUMIPSState *cpu_mips_init (void) -- cgit v1.2.3 From 7d600c804d79e21254a20b953d6bd175597d752d Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 8 Dec 2006 01:32:58 +0000 Subject: Fix fstat for MIPS userland emulation, and add support for a cacheflush syscall, thanks to Dave Denholm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2234 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e95212894..075460bae 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2933,7 +2933,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, lock_user_struct(target_st, arg2, 0); target_st->st_dev = tswap16(st.st_dev); target_st->st_ino = tswapl(st.st_ino); -#if defined(TARGET_PPC) +#if defined(TARGET_PPC) || defined(TARGET_MIPS) target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */ target_st->st_uid = tswap32(st.st_uid); target_st->st_gid = tswap32(st.st_gid); @@ -3829,6 +3829,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; } #endif +#ifdef TARGET_NR_cacheflush + case TARGET_NR_cacheflush: + /* self-modifying code is handled automatically, so nothing needed */ + ret = 0; + break; +#endif #ifdef TARGET_NR_security case TARGET_NR_security: goto unimplemented; -- cgit v1.2.3 From ca7c2b1b9f984f622c7495004483016fee61e489 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 10 Dec 2006 22:08:10 +0000 Subject: Handle invalid accesses as SIGILL for mips/mipsel userland emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2235 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 ++ target-mips/helper.c | 7 +++++++ target-mips/translate.c | 3 +++ 3 files changed, 12 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 6dd08022f..c423d299b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1352,6 +1352,8 @@ void cpu_loop(CPUMIPSState *env) } } break; + case EXCP_TLBL: + case EXCP_TLBS: case EXCP_CpU: case EXCP_RI: info.si_signo = TARGET_SIGILL; diff --git a/target-mips/helper.c b/target-mips/helper.c index a222d6b0e..a0a56d8f0 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -243,6 +243,12 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return ret; } +#if defined(CONFIG_USER_ONLY) +void do_interrupt (CPUState *env) +{ + env->exception_index = EXCP_NONE; +} +#else void do_interrupt (CPUState *env) { target_ulong offset; @@ -409,3 +415,4 @@ void do_interrupt (CPUState *env) } env->exception_index = EXCP_NONE; } +#endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 74fa11416..64f7d7565 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4072,6 +4072,7 @@ void cpu_reset (CPUMIPSState *env) tlb_flush(env, 1); /* Minimal init */ +#if !defined(CONFIG_USER_ONLY) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump. */ @@ -4098,9 +4099,11 @@ void cpu_reset (CPUMIPSState *env) /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); env->CP0_PRid = MIPS_CPU; +#endif env->exception_index = EXCP_NONE; #if defined(CONFIG_USER_ONLY) env->hflags |= MIPS_HFLAG_UM; + env->user_mode_only = 1; #endif #ifdef MIPS_USES_FPU env->fcr0 = MIPS_FCR0; -- cgit v1.2.3 From a42aa815715dc1db881f5480a50bd331bbd5e923 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 10 Dec 2006 22:11:04 +0000 Subject: Build fix for newer kernel headers, thanks Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2236 c046a42c-6fe2-441c-8c8c-71466251a162 --- usb-linux.c | 1 - 1 file changed, 1 deletion(-) diff --git a/usb-linux.c b/usb-linux.c index 77436927c..50386eaf6 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -26,7 +26,6 @@ #if defined(__linux__) #include #include -#include #include #include -- cgit v1.2.3 From 3bcb80f1af107c25bf8c255f3ca88ac467f27a1a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 10 Dec 2006 23:07:39 +0000 Subject: Fix sector size overflow, by Herbert Xu. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2237 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/fdc.c b/hw/fdc.c index 930c0e21b..073dafa4c 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -888,7 +888,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) fdctrl->data_len = fdctrl->fifo[8]; } else { int tmp; - fdctrl->data_len = 128 << fdctrl->fifo[5]; + fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); tmp = (cur_drv->last_sect - ks + 1); if (fdctrl->fifo[0] & 0x80) tmp += cur_drv->last_sect; -- cgit v1.2.3 From a2d4e44b485222a8972ea9e555b148148c655bb9 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 10 Dec 2006 23:20:45 +0000 Subject: Fix PCI config space overflow, by Herbert Xu. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2238 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index bc7c779e5..d8fcd7be5 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -242,16 +242,23 @@ uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len) { uint32_t val; + switch(len) { - case 1: - val = d->config[address]; - break; - case 2: - val = le16_to_cpu(*(uint16_t *)(d->config + address)); - break; default: case 4: - val = le32_to_cpu(*(uint32_t *)(d->config + address)); + if (address <= 0xfc) { + val = le32_to_cpu(*(uint32_t *)(d->config + address)); + break; + } + /* fall through */ + case 2: + if (address <= 0xfe) { + val = le16_to_cpu(*(uint16_t *)(d->config + address)); + break; + } + /* fall through */ + case 1: + val = d->config[address]; break; } return val; @@ -341,7 +348,8 @@ void pci_default_write_config(PCIDevice *d, if (can_write) { d->config[addr] = val; } - addr++; + if (++addr > 0xff) + break; val >>= 8; } -- cgit v1.2.3 From 667accab8e3cee23597e4a3af7b06c7efceb2a92 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 11 Dec 2006 02:08:05 +0000 Subject: Implement -no-quit option, by Xavier Gnata. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2239 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 4 +++- vl.c | 17 +++++++++++++++-- vl.h | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/sdl.c b/sdl.c index e65dcac9c..b58e9d679 100644 --- a/sdl.c +++ b/sdl.c @@ -496,7 +496,9 @@ static void sdl_refresh(DisplayState *ds) sdl_process_key(&ev->key); break; case SDL_QUIT: - qemu_system_shutdown_request(); + if (!no_quit) { + qemu_system_shutdown_request(); + } break; case SDL_MOUSEMOTION: if (gui_grab || kbd_mouse_is_absolute()) { diff --git a/vl.c b/vl.c index 447da38a9..5b5f25afd 100644 --- a/vl.c +++ b/vl.c @@ -143,6 +143,7 @@ int graphic_height = 600; #endif int graphic_depth = 15; int full_screen = 0; +int no_quit = 0; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; #ifdef TARGET_I386 @@ -5845,7 +5846,10 @@ void help(void) "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" - "-snapshot write to temporary files instead of disk image files\n" + "-snapshot write to temporary files instead of disk image files\n" +#ifdef CONFIG_SDL + "-no-quit disable SDL window close capability\n" +#endif #ifdef TARGET_I386 "-no-fd-bootchk disable boot signature checking for floppy disks\n" #endif @@ -5853,7 +5857,7 @@ void help(void) "-smp n set the number of CPUs to 'n' [default=1]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" #ifndef _WIN32 - "-k language use keyboard layout (for example \"fr\" for French)\n" + "-k language use keyboard layout (for example \"fr\" for French)\n" #endif #ifdef HAS_AUDIO "-audio-help print list of audio drivers and their options\n" @@ -6007,6 +6011,7 @@ enum { QEMU_OPTION_parallel, QEMU_OPTION_loadvm, QEMU_OPTION_full_screen, + QEMU_OPTION_no_quit, QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, QEMU_OPTION_kernel_kqemu, @@ -6083,6 +6088,9 @@ const QEMUOption qemu_options[] = { { "parallel", 1, QEMU_OPTION_parallel }, { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, { "full-screen", 0, QEMU_OPTION_full_screen }, +#ifdef CONFIG_SDL + { "no-quit", 0, QEMU_OPTION_no_quit }, +#endif { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, @@ -6691,6 +6699,11 @@ int main(int argc, char **argv) case QEMU_OPTION_full_screen: full_screen = 1; break; +#ifdef CONFIG_SDL + case QEMU_OPTION_no_quit: + no_quit = 1; + break; +#endif case QEMU_OPTION_pidfile: create_pidfile(optarg); break; diff --git a/vl.h b/vl.h index 89b24cf91..3847170d9 100644 --- a/vl.h +++ b/vl.h @@ -152,6 +152,7 @@ extern int kqemu_allowed; extern int win2k_install_hack; extern int usb_enabled; extern int smp_cpus; +extern int no_quit; /* XXX: make it dynamic */ #if defined (TARGET_PPC) || defined (TARGET_SPARC64) -- cgit v1.2.3 From 366dfc521e03c1d02c69cdb09b1565dbae97ebd0 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 11 Dec 2006 18:35:08 +0000 Subject: Spelling fixes, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2240 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index c7fbe1d1d..c3e6cb2eb 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -443,7 +443,7 @@ or @file{C:\WINNT\SYSTEM32\DRIVERS\ETC\LMHOSTS} (Windows NT/2000). Then @file{dir} can be accessed in @file{\\smbserver\qemu}. Note that a SAMBA server must be installed on the host OS in -@file{/usr/sbin/smbd}. QEMU was tested succesfully with smbd version +@file{/usr/sbin/smbd}. QEMU was tested successfully with smbd version 2.2.7a from the Red Hat 9 and version 3.0.10-1.fc3 from Fedora Core 3. @item -redir [tcp|udp]:host-port:[guest-host]:guest-port @@ -678,7 +678,7 @@ During emulation, if you are using the @option{-nographic} option, use @item Ctrl-a h Print this help @item Ctrl-a x -Exit emulatior +Exit emulator @item Ctrl-a s Save disk data back to file (if -snapshot) @item Ctrl-a b @@ -1810,7 +1810,7 @@ to install QEMU in @file{/usr/local}. @subsection Tested tool versions -In order to compile QEMU succesfully, it is very important that you +In order to compile QEMU successfully, it is very important that you have the right tools. The most important one is gcc. I cannot guaranty that QEMU works if you do not use a tested gcc version. Look at 'configure' and 'Makefile' if you want to make a different gcc -- cgit v1.2.3 From 197ea35ab2175f7faaee4cb416332dc28db5bbbe Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 11 Dec 2006 19:13:59 +0000 Subject: Fix addrlen size, by David Woodhouse. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2241 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 075460bae..155297966 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -841,7 +841,7 @@ static long do_accept(int fd, target_ulong target_addr, target_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(target_addrlen); + void *addr = alloca(addrlen); long ret; ret = get_errno(accept(fd, addr, &addrlen)); -- cgit v1.2.3 From 8e33c08c84b9f418dee69f79e7b579c59e77814b Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 11 Dec 2006 19:22:27 +0000 Subject: MIPS FPU support for the gdb stub, by Daniel Jacobowitz. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2242 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/gdbstub.c b/gdbstub.c index 9e10c0cdc..a5e68ae03 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -532,11 +532,37 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) *(uint32_t *)ptr = tswapl(env->PC); ptr += 4; +#ifdef MIPS_USES_FPU + for (i = 0; i < 32; i++) + { + *(uint32_t *)ptr = tswapl(FPR_W (env, i)); + ptr += 4; + } + + *(uint32_t *)ptr = tswapl(env->fcr31); + ptr += 4; + + *(uint32_t *)ptr = tswapl(env->fcr0); + ptr += 4; +#endif + /* 32 FP registers, fsr, fir, fp. Not yet implemented. */ + /* what's 'fp' mean here? */ return ptr - mem_buf; } +/* convert MIPS rounding mode in FCR31 to IEEE library */ +static unsigned int ieee_rm[] = + { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down + }; +#define RESTORE_ROUNDING_MODE \ + set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) + static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { int i; @@ -566,6 +592,28 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->PC = tswapl(*(uint32_t *)ptr); ptr += 4; + +#ifdef MIPS_USES_FPU + for (i = 0; i < 32; i++) + { + FPR_W (env, i) = tswapl(*(uint32_t *)ptr); + ptr += 4; + } + + env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF; + ptr += 4; + + env->fcr0 = tswapl(*(uint32_t *)ptr); + ptr += 4; + + /* set rounding mode */ + RESTORE_ROUNDING_MODE; + +#ifndef CONFIG_SOFTFLOAT + /* no floating point exception for native float */ + SET_FP_ENABLE(env->fcr31, 0); +#endif +#endif } #elif defined (TARGET_SH4) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) -- cgit v1.2.3 From 0d3267a728ee392bd5113b1d9ad3b135565012e3 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 11 Dec 2006 22:04:25 +0000 Subject: MIPS has also a fixed MMAP_SHIFT of 12. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2243 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 155297966..1c3121818 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2673,7 +2673,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #ifdef TARGET_NR_mmap2 case TARGET_NR_mmap2: -#if defined(TARGET_SPARC) +#if defined(TARGET_SPARC) || defined(TARGET_MIPS) #define MMAP_SHIFT 12 #else #define MMAP_SHIFT TARGET_PAGE_BITS -- cgit v1.2.3 From 768a4a36a444ef5aef1f103adf42553eadfe4614 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 14 Dec 2006 13:32:11 +0000 Subject: Fix userland ELF loader for zero sized BSS. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2244 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 042c65dc7..c0ea5a012 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -553,10 +553,13 @@ static void set_brk(unsigned long start, unsigned long end) /* We need to explicitly zero any fractional pages after the data section (i.e. bss). This would contain the junk from the file that should not be in memory. */ -static void padzero(unsigned long elf_bss) +static void padzero(unsigned long elf_bss, unsigned long last_bss) { unsigned long nbyte; + if (elf_bss >= last_bss) + return; + /* XXX: this is really a hack : if the real host page size is smaller than the target page size, some pages after the end of the file may not be mapped. A better fix would be to @@ -798,7 +801,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, * that there are zeromapped pages up to and including the last * bss page. */ - padzero(elf_bss); + padzero(elf_bss, last_bss); elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ @@ -1227,7 +1230,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, sections */ set_brk(elf_bss, elf_brk); - padzero(elf_bss); + padzero(elf_bss, elf_brk); #if 0 printf("(start_brk) %x\n" , info->start_brk); -- cgit v1.2.3 From 73e14b623fc960385f60f3eed06583c27fb5d9df Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 14 Dec 2006 13:36:01 +0000 Subject: Reduce VNC resize traffic, thanks Eduardo Felipe. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2245 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vnc.c b/vnc.c index 19aa4b746..92e48c56e 100644 --- a/vnc.c +++ b/vnc.c @@ -167,6 +167,7 @@ static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, static void vnc_dpy_resize(DisplayState *ds, int w, int h) { + int size_changed; VncState *vs = ds->opaque; ds->data = realloc(ds->data, w * h * vs->depth); @@ -178,10 +179,11 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h) } ds->depth = vs->depth * 8; + size_changed = ds->width != w || ds->height != h; ds->width = w; ds->height = h; ds->linesize = w * vs->depth; - if (vs->csock != -1 && vs->has_resize) { + if (vs->csock != -1 && vs->has_resize && size_changed) { vnc_write_u8(vs, 0); /* msg id */ vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ -- cgit v1.2.3 From e4630047e161ac1b23bfd37b2c52785fce49400a Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 14 Dec 2006 14:48:11 +0000 Subject: Simple test for mips/mipsel, based on a test by Alexander Voropay. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2246 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 7 ++++++ tests/hello-mips.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 tests/hello-mips.c diff --git a/tests/Makefile b/tests/Makefile index d7abae69e..f803f6a65 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -82,6 +82,13 @@ hello-arm: hello-arm.o hello-arm.o: hello-arm.c arm-linux-gcc -Wall -g -O2 -c -o $@ $< +# MIPS test +hello-mips: hello-mips.c + mips-linux-gnu-gcc -nostdlib -static -mno-abicalls -fno-PIC -mabi=32 -Wall -Wextra -g -O2 -o $@ $< + +hello-mipsel: hello-mips.c + mipsel-linux-gnu-gcc -nostdlib -static -mno-abicalls -fno-PIC -mabi=32 -Wall -Wextra -g -O2 -o $@ $< + # XXX: find a way to compile easily a test for each arch test2: @for arch in i386 arm armeb sparc ppc mips mipsel; do \ diff --git a/tests/hello-mips.c b/tests/hello-mips.c new file mode 100644 index 000000000..f8256730d --- /dev/null +++ b/tests/hello-mips.c @@ -0,0 +1,64 @@ +/* +* MIPS o32 Linux syscall example +* +* http://www.linux-mips.org/wiki/RISC/os +* http://www.linux-mips.org/wiki/MIPSABIHistory +* http://www.linux.com/howtos/Assembly-HOWTO/mips.shtml +* +* mipsel-linux-gcc -nostdlib -mno-abicalls -fno-PIC -mabi=32 \ +* -O2 -static -o hello-mips hello-mips.c +* +*/ +#define __NR_SYSCALL_BASE 4000 +#define __NR_exit (__NR_SYSCALL_BASE+ 1) +#define __NR_write (__NR_SYSCALL_BASE+ 4) + +static inline void exit1(int status) +{ + register unsigned long __a0 asm("$4") = (unsigned long) status; + + __asm__ __volatile__ ( + " .set push \n" + " .set noreorder \n" + " li $2, %0 \n" + " syscall \n" + " .set pop " + : + : "i" (__NR_exit), "r" (__a0) + : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", + "memory"); +} + +static inline int write(int fd, const char *buf, int len) +{ + register unsigned long __a0 asm("$4") = (unsigned long) fd; + register unsigned long __a1 asm("$5") = (unsigned long) buf; + register unsigned long __a2 asm("$6") = (unsigned long) len; + register unsigned long __a3 asm("$7"); + unsigned long __v0; + + __asm__ __volatile__ ( + " .set push \n" + " .set noreorder \n" + " li $2, %2 \n" + " syscall \n" + " move %0, $2 \n" + " .set pop " + : "=r" (__v0), "=r" (__a3) + : "i" (__NR_write), "r" (__a0), "r" (__a1), "r" (__a2) + : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", + "memory"); + +/* if (__a3 == 0) */ + return (int) __v0; +/* + errno = __v0; + return -1; + */ +} + +void __start(void) +{ + write (1, "Hello, World!\n", 14); + exit1 (42); +} -- cgit v1.2.3 From 179e32bbccd0b7ae2fa99e6612d1657c3b8205ae Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 16 Dec 2006 16:45:18 +0000 Subject: Fix erraneous fallthrough in MIPS trap implementation, thanks Atsushi Nemoto. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2247 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 64f7d7565..c9cbc9dad 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1276,6 +1276,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, GEN_LOAD_REG_TN(T1, rt); cond = 1; } + break; case OPC_TEQI: case OPC_TGEI: case OPC_TGEIU: -- cgit v1.2.3 From 67d3b957e69aeb9ab7bfc3d6e05f342cb452b1d7 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 18 Dec 2006 05:03:52 +0000 Subject: Add unassigned memory debugging code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2248 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/exec.c b/exec.c index 762d6dc4d..ae2d825da 100644 --- a/exec.c +++ b/exec.c @@ -41,6 +41,7 @@ //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH //#define DEBUG_TLB +//#define DEBUG_UNASSIGNED /* make various TB consistency checks */ //#define DEBUG_TB_CHECK @@ -1813,11 +1814,17 @@ uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr) static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) { +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read 0x%08x\n", (int)addr); +#endif return 0; } static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val); +#endif } static CPUReadMemoryFunc *unassigned_mem_read[3] = { -- cgit v1.2.3 From 328a42406d1da2044e2918918ac744f95a1eeb36 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 19 Dec 2006 03:31:34 +0000 Subject: Look for gcc3 (Anthony Liguori). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2249 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 59 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/configure b/configure index 84f8ee099..ab8595613 100755 --- a/configure +++ b/configure @@ -22,6 +22,8 @@ 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" @@ -178,6 +180,7 @@ for opt do --cross-prefix=*) cross_prefix="$optarg" ;; --cc=*) cc="$optarg" + gcc3_search="no" ;; --host-cc=*) host_cc="$optarg" ;; @@ -314,6 +317,45 @@ if test "$mingw32" = "yes" ; then fi fi +# Check for gcc4, error if pre-gcc4 +if test "$check_gcc" = "yes" ; then + cat > $TMPC <&/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 # @@ -416,23 +458,6 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu have_gcc3_options="yes" fi -# Check for gcc4, error if pre-gcc4 -if test "$check_gcc" = "yes" ; then - cat > $TMPC </dev/null ; then - echo "ERROR: \"$cc\" looks like gcc 4.x" - 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 - ########################################## # SDL probe -- cgit v1.2.3 From c570fd169c16f110781f31e0e963542a15229ee9 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 01:19:56 +0000 Subject: Preliminiary MIPS64 support, disabled by default due to performance impact. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2250 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 14 +- target-mips/cpu.h | 29 ++- target-mips/exec.h | 48 ++++- target-mips/fop_template.c | 1 + target-mips/helper.c | 34 +-- target-mips/mips-defs.h | 13 +- target-mips/op.c | 496 ++++++++++++++++++++++++++++++++++++-------- target-mips/op_helper.c | 146 +++++++++++-- target-mips/op_helper_mem.c | 198 ++++++++++++++++-- target-mips/op_mem.c | 67 ++++++ target-mips/op_template.c | 26 ++- target-mips/translate.c | 93 +++++---- 12 files changed, 957 insertions(+), 208 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 61db814d9..ca3a4ffce 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -11,10 +11,10 @@ #define BIOS_FILENAME "mips_bios.bin" //#define BIOS_FILENAME "system.bin" -#define KERNEL_LOAD_ADDR 0x80010000 -#define INITRD_LOAD_ADDR 0x80800000 +#define KERNEL_LOAD_ADDR SIGN_EXTEND32(0x80010000) +#define INITRD_LOAD_ADDR SIGN_EXTEND32(0x80800000) -#define VIRT_TO_PHYS_ADDEND (-0x80000000LL) +#define VIRT_TO_PHYS_ADDEND (-SIGN_EXTEND32(0x80000000LL)) static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; @@ -74,9 +74,11 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, long kernel_size, initrd_size; kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); - if (kernel_size >= 0) + if (kernel_size >= 0) { + if ((entry & ~0x7fffffffULL) == 0x80000000) + entry = SIGN_EXTEND32(entry); env->PC = entry; - else { + } else { kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); if (kernel_size < 0) { @@ -103,7 +105,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, if (initrd_size > 0) { int ret; ret = sprintf(phys_ram_base + (16 << 20) - 256, - "rd_start=0x%08x rd_size=%li ", + "rd_start=0x" TLSZ " rd_size=%li ", INITRD_LOAD_ADDR, initrd_size); strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 46436cde3..710748c69 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -15,6 +15,16 @@ typedef unsigned char uint_fast8_t; typedef unsigned int uint_fast16_t; #endif +#ifdef MIPS_HAS_MIPS64 +#define SIGN_EXTEND32(val) (((((uint64_t)(val)) & 0xFFFFFFFF) ^ 0x80000000) - 0x80000000) +/* target_ulong size spec */ +#define TLSZ "%016llx" +#else +#define SIGN_EXTEND32(val) (val) +/* target_ulong size spec */ +#define TLSZ "%08x" +#endif + typedef union fpr_t fpr_t; union fpr_t { float64 fd; /* ieee double precision */ @@ -55,7 +65,12 @@ struct CPUMIPSState { target_ulong gpr[32]; /* Special registers */ target_ulong PC; - uint32_t HI, LO; +#if TARGET_LONG_BITS > HOST_LONG_BITS + target_ulong t0; + target_ulong t1; + target_ulong t2; +#endif + target_ulong HI, LO; uint32_t DCR; /* ? */ #if defined(MIPS_USES_FPU) /* Floating point registers */ @@ -106,7 +121,7 @@ struct CPUMIPSState { uint32_t CP0_PageGrain; uint32_t CP0_Wired; uint32_t CP0_HWREna; - uint32_t CP0_BadVAddr; + target_ulong CP0_BadVAddr; uint32_t CP0_Count; uint64_t CP0_EntryHi; uint32_t CP0_Compare; @@ -145,9 +160,9 @@ struct CPUMIPSState { #define CP0Ca_WP 22 #define CP0Ca_IP 8 #define CP0Ca_EC 2 - uint32_t CP0_EPC; + target_ulong CP0_EPC; uint32_t CP0_PRid; - uint32_t CP0_EBase; + target_ulong CP0_EBase; uint32_t CP0_Config0; #define CP0C0_M 31 #define CP0C0_K23 28 @@ -197,7 +212,7 @@ struct CPUMIPSState { #define CP0C3_MT 2 #define CP0C3_SM 1 #define CP0C3_TL 0 - uint32_t CP0_LLAddr; + target_ulong CP0_LLAddr; uint32_t CP0_WatchLo; uint32_t CP0_WatchHi; uint32_t CP0_XContext; @@ -221,13 +236,13 @@ struct CPUMIPSState { #define CP0DB_DDBL 2 #define CP0DB_DBp 1 #define CP0DB_DSS 0 - uint32_t CP0_DEPC; + target_ulong CP0_DEPC; uint32_t CP0_Performance0; uint32_t CP0_TagLo; uint32_t CP0_DataLo; uint32_t CP0_TagHi; uint32_t CP0_DataHi; - uint32_t CP0_ErrorEPC; + target_ulong CP0_ErrorEPC; uint32_t CP0_DESAVE; /* Qemu */ int interrupt_request; diff --git a/target-mips/exec.h b/target-mips/exec.h index 817ef0346..9e1fcdc00 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -3,6 +3,7 @@ //#define DEBUG_OP +#include "config.h" #include "mips-defs.h" #include "dyngen-exec.h" @@ -16,9 +17,15 @@ typedef int32_t host_int_t; typedef uint32_t host_uint_t; #endif +#if TARGET_LONG_BITS > HOST_LONG_BITS +#define T0 (env->t0) +#define T1 (env->t1) +#define T2 (env->t2) +#else register host_uint_t T0 asm(AREG1); register host_uint_t T1 asm(AREG2); register host_uint_t T2 asm(AREG3); +#endif #if defined (USE_HOST_FLOAT_REGS) #error "implement me." @@ -58,13 +65,36 @@ static inline void regs_to_env(void) { } -#if (HOST_LONG_BITS == 32) +#ifdef MIPS_HAS_MIPS64 +#if TARGET_LONG_BITS > HOST_LONG_BITS +void do_dsll (void); +void do_dsll32 (void); +void do_dsra (void); +void do_dsra32 (void); +void do_dsrl (void); +void do_dsrl32 (void); +void do_drotr (void); +void do_drotr32 (void); +void do_dsllv (void); +void do_dsrav (void); +void do_dsrlv (void); +void do_drotrv (void); +#endif +#endif + +#if TARGET_LONG_BITS > HOST_LONG_BITS void do_mult (void); void do_multu (void); void do_madd (void); void do_maddu (void); void do_msub (void); void do_msubu (void); +void do_ddiv (void); +void do_ddivu (void); +#endif +#ifdef MIPS_HAS_MIPS64 +void do_dmult (void); +void do_dmultu (void); #endif void do_mfc0_random(void); void do_mfc0_count(void); @@ -86,6 +116,12 @@ void do_lwl_raw (uint32_t); void do_lwr_raw (uint32_t); uint32_t do_swl_raw (uint32_t); uint32_t do_swr_raw (uint32_t); +#ifdef MIPS_HAS_MIPS64 +void do_ldl_raw (uint64_t); +void do_ldr_raw (uint64_t); +uint64_t do_sdl_raw (uint64_t); +uint64_t do_sdr_raw (uint64_t); +#endif #if !defined(CONFIG_USER_ONLY) void do_lwl_user (uint32_t); void do_lwl_kernel (uint32_t); @@ -95,6 +131,16 @@ uint32_t do_swl_user (uint32_t); uint32_t do_swl_kernel (uint32_t); uint32_t do_swr_user (uint32_t); uint32_t do_swr_kernel (uint32_t); +#ifdef MIPS_HAS_MIPS64 +void do_ldl_user (uint64_t); +void do_ldl_kernel (uint64_t); +void do_ldr_user (uint64_t); +void do_ldr_kernel (uint64_t); +uint64_t do_sdl_user (uint64_t); +uint64_t do_sdl_kernel (uint64_t); +uint64_t do_sdr_user (uint64_t); +uint64_t do_sdr_kernel (uint64_t); +#endif #endif void do_pmon (int function); diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index bc0a6e03e..4ebb46bff 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -96,4 +96,5 @@ SET_RESET(DT0, _DT0) SET_RESET(DT1, _DT1) SET_RESET(DT2, _DT2) +#undef SET_RESET #endif diff --git a/target-mips/helper.c b/target-mips/helper.c index a0a56d8f0..0e3eb6c7c 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -86,7 +86,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, #endif if (user_mode && address > 0x7FFFFFFFUL) return TLBRET_BADADDR; - if (address < 0x80000000UL) { + if (address < SIGN_EXTEND32(0x80000000UL)) { if (!(env->hflags & MIPS_HFLAG_ERL)) { #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); @@ -98,17 +98,17 @@ static int get_physical_address (CPUState *env, target_ulong *physical, *physical = address; *prot = PAGE_READ | PAGE_WRITE; } - } else if (address < 0xA0000000UL) { + } else if (address < SIGN_EXTEND32(0xA0000000UL)) { /* kseg0 */ /* XXX: check supervisor mode */ - *physical = address - 0x80000000UL; + *physical = address - SIGN_EXTEND32(0x80000000UL); *prot = PAGE_READ | PAGE_WRITE; - } else if (address < 0xC0000000UL) { + } else if (address < SIGN_EXTEND32(0xC0000000UL)) { /* kseg1 */ /* XXX: check supervisor mode */ - *physical = address - 0xA0000000UL; + *physical = address - SIGN_EXTEND32(0xA0000000UL); *prot = PAGE_READ | PAGE_WRITE; - } else if (address < 0xE0000000UL) { + } else if (address < SIGN_EXTEND32(0xE0000000UL)) { /* kseg2 */ #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); @@ -129,8 +129,8 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } #if 0 if (logfile) { - fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw, - access_type, *physical, *prot, ret); + fprintf(logfile, TLSZ " %d %d => " TLSZ " %d (%d)\n", + address, rw, access_type, *physical, *prot, ret); } #endif @@ -171,7 +171,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if 0 cpu_dump_state(env, logfile, fprintf, 0); #endif - fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n", + fprintf(logfile, "%s pc " TLSZ " ad " TLSZ " rw %d is_user %d smmu %d\n", __func__, env->PC, address, rw, is_user, is_softmmu); } @@ -189,7 +189,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ret = get_physical_address(env, &physical, &prot, address, rw, access_type); if (logfile) { - fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n", + fprintf(logfile, "%s address=" TLSZ " ret %d physical " TLSZ " prot %d\n", __func__, address, ret, physical, prot); } if (ret == TLBRET_MATCH) { @@ -255,7 +255,7 @@ void do_interrupt (CPUState *env) int cause = -1; if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { - fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n", + fprintf(logfile, "%s enter: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n", __func__, env->PC, env->CP0_EPC, cause, env->exception_index); } if (env->exception_index == EXCP_EXT_INTERRUPT && @@ -299,7 +299,7 @@ void do_interrupt (CPUState *env) enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; /* EJTAG probe trap enable is not implemented... */ - env->PC = 0xBFC00480; + env->PC = SIGN_EXTEND32(0xBFC00480); break; case EXCP_RESET: cpu_reset(env); @@ -321,7 +321,7 @@ void do_interrupt (CPUState *env) } env->hflags |= MIPS_HFLAG_ERL; env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - env->PC = 0xBFC00000; + env->PC = SIGN_EXTEND32(0xBFC00000); break; case EXCP_MCHECK: cause = 24; @@ -389,9 +389,9 @@ void do_interrupt (CPUState *env) env->CP0_Cause &= ~0x80000000; } if (env->CP0_Status & (1 << CP0St_BEV)) { - env->PC = 0xBFC00200; + env->PC = SIGN_EXTEND32(0xBFC00200); } else { - env->PC = 0x80000000; + env->PC = SIGN_EXTEND32(0x80000000); } env->hflags |= MIPS_HFLAG_EXL; env->CP0_Status |= (1 << CP0St_EXL); @@ -407,8 +407,8 @@ void do_interrupt (CPUState *env) exit(1); } if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { - fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n" - " S %08x C %08x A %08x D %08x\n", + fprintf(logfile, "%s: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n" + " S %08x C %08x A " TLSZ " D " TLSZ "\n", __func__, env->PC, env->CP0_EPC, cause, env->exception_index, env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, env->CP0_DEPC); diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 14d1438bc..83480c6ab 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -14,7 +14,8 @@ #if (MIPS_CPU == MIPS_R4Kc) /* 32 bits target */ -#define TARGET_LONG_BITS 32 +#undef MIPS_HAS_MIPS64 +//#define MIPS_HAS_MIPS64 1 /* real pages are variable size... */ #define TARGET_PAGE_BITS 12 /* Uses MIPS R4Kx enhancements to MIPS32 architecture */ @@ -69,7 +70,7 @@ (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL)) #elif (MIPS_CPU == MIPS_R4Kp) /* 32 bits target */ -#define TARGET_LONG_BITS 32 +#undef MIPS_HAS_MIPS64 /* real pages are variable size... */ #define TARGET_PAGE_BITS 12 /* Uses MIPS R4Kx enhancements to MIPS32 architecture */ @@ -79,8 +80,14 @@ #else #error "MIPS CPU not defined" /* Reminder for other flags */ -//#define TARGET_MIPS64 +//#undef MIPS_HAS_MIPS64 //#define MIPS_USES_FPU #endif +#ifdef MIPS_HAS_MIPS64 +#define TARGET_LONG_BITS 64 +#else +#define TARGET_LONG_BITS 32 +#endif + #endif /* !defined (__QEMU_MIPS_DEFS_H__) */ diff --git a/target-mips/op.c b/target-mips/op.c index 35a13657e..4b6c20c49 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -140,13 +140,7 @@ CALL_FROM_TB2(func, arg0, arg1); #include "op_template.c" #undef REG -#define TN T0 -#include "op_template.c" -#undef TN -#define TN T1 -#include "op_template.c" -#undef TN -#define TN T2 +#define TN #include "op_template.c" #undef TN @@ -334,7 +328,7 @@ void op_store_LO (void) /* Arithmetic */ void op_add (void) { - T0 += T1; + T0 = SIGN_EXTEND32((int32_t)T0 + (int32_t)T1); RETURN(); } @@ -342,18 +336,19 @@ void op_addo (void) { target_ulong tmp; - tmp = T0; - T0 += T1; + tmp = (int32_t)T0; + T0 = (int32_t)T0 + (int32_t)T1; if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) { - /* operands of same sign, result different sign */ + /* operands of same sign, result different sign */ CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } + T0 = SIGN_EXTEND32(T0); RETURN(); } void op_sub (void) { - T0 -= T1; + T0 = SIGN_EXTEND32((int32_t)T0 - (int32_t)T1); RETURN(); } @@ -361,31 +356,110 @@ void op_subo (void) { target_ulong tmp; - tmp = T0; + tmp = (int32_t)T0; T0 = (int32_t)T0 - (int32_t)T1; if (((tmp ^ T1) & (tmp ^ T0)) >> 31) { - /* operands of different sign, first operand and result different sign */ + /* operands of different sign, first operand and result different sign */ CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } + T0 = SIGN_EXTEND32(T0); RETURN(); } void op_mul (void) { - T0 = (int32_t)T0 * (int32_t)T1; + T0 = SIGN_EXTEND32((int32_t)T0 * (int32_t)T1); RETURN(); } void op_div (void) { if (T1 != 0) { - env->LO = (int32_t)T0 / (int32_t)T1; - env->HI = (int32_t)T0 % (int32_t)T1; + env->LO = SIGN_EXTEND32((int32_t)T0 / (int32_t)T1); + env->HI = SIGN_EXTEND32((int32_t)T0 % (int32_t)T1); } RETURN(); } void op_divu (void) +{ + if (T1 != 0) { + env->LO = SIGN_EXTEND32((uint32_t)T0 / (uint32_t)T1); + env->HI = SIGN_EXTEND32((uint32_t)T0 % (uint32_t)T1); + } + RETURN(); +} + +#ifdef MIPS_HAS_MIPS64 +/* Arithmetic */ +void op_dadd (void) +{ + T0 += T1; + RETURN(); +} + +void op_daddo (void) +{ + target_long tmp; + + tmp = T0; + T0 += T1; + if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 63) { + /* operands of same sign, result different sign */ + CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); + } + RETURN(); +} + +void op_dsub (void) +{ + T0 -= T1; + RETURN(); +} + +void op_dsubo (void) +{ + target_long tmp; + + tmp = T0; + T0 = (int64_t)T0 - (int64_t)T1; + if (((tmp ^ T1) & (tmp ^ T0)) >> 63) { + /* operands of different sign, first operand and result different sign */ + CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); + } + RETURN(); +} + +void op_dmul (void) +{ + T0 = (int64_t)T0 * (int64_t)T1; + RETURN(); +} + +#if TARGET_LONG_BITS > HOST_LONG_BITS +/* Those might call libgcc functions. */ +void op_ddiv (void) +{ + do_ddiv(); + RETURN(); +} + +void op_ddivu (void) +{ + do_ddivu(); + RETURN(); +} +#else +void op_ddiv (void) +{ + if (T1 != 0) { + env->LO = (int64_t)T0 / (int64_t)T1; + env->HI = (int64_t)T0 % (int64_t)T1; + } + RETURN(); +} + +void op_ddivu (void) { if (T1 != 0) { env->LO = T0 / T1; @@ -393,6 +467,8 @@ void op_divu (void) } RETURN(); } +#endif +#endif /* MIPS_HAS_MIPS64 */ /* Logical */ void op_and (void) @@ -421,19 +497,19 @@ void op_xor (void) void op_sll (void) { - T0 = T0 << T1; + T0 = SIGN_EXTEND32((uint32_t)T0 << (uint32_t)T1); RETURN(); } void op_sra (void) { - T0 = (int32_t)T0 >> T1; + T0 = SIGN_EXTEND32((int32_t)T0 >> (uint32_t)T1); RETURN(); } void op_srl (void) { - T0 = T0 >> T1; + T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1); RETURN(); } @@ -442,8 +518,8 @@ void op_rotr (void) target_ulong tmp; if (T1) { - tmp = T0 << (0x20 - T1); - T0 = (T0 >> T1) | tmp; + tmp = SIGN_EXTEND32((uint32_t)T0 << (0x20 - (uint32_t)T1)); + T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1) | tmp; } else T0 = T1; RETURN(); @@ -451,19 +527,19 @@ void op_rotr (void) void op_sllv (void) { - T0 = T1 << (T0 & 0x1F); + T0 = SIGN_EXTEND32((uint32_t)T1 << ((uint32_t)T0 & 0x1F)); RETURN(); } void op_srav (void) { - T0 = (int32_t)T1 >> (T0 & 0x1F); + T0 = SIGN_EXTEND32((int32_t)T1 >> (T0 & 0x1F)); RETURN(); } void op_srlv (void) { - T0 = T1 >> (T0 & 0x1F); + T0 = SIGN_EXTEND32((uint32_t)T1 >> (T0 & 0x1F)); RETURN(); } @@ -473,8 +549,8 @@ void op_rotrv (void) T0 &= 0x1F; if (T0) { - tmp = T1 << (0x20 - T0); - T0 = (T1 >> T0) | tmp; + tmp = SIGN_EXTEND32((uint32_t)T1 << (0x20 - T0)); + T0 = SIGN_EXTEND32((uint32_t)T1 >> T0) | tmp; } else T0 = T1; RETURN(); @@ -484,7 +560,7 @@ void op_clo (void) { int n; - if (T0 == (target_ulong)-1) { + if (T0 == ~((target_ulong)0)) { T0 = 32; } else { for (n = 0; n < 32; n++) { @@ -514,67 +590,213 @@ void op_clz (void) RETURN(); } -/* 64 bits arithmetic */ -#if (HOST_LONG_BITS == 64) -static inline uint64_t get_HILO (void) +#ifdef MIPS_HAS_MIPS64 + +#if TARGET_LONG_BITS > HOST_LONG_BITS +/* Those might call libgcc functions. */ +void op_dsll (void) { - return ((uint64_t)env->HI << 32) | (uint64_t)env->LO; + CALL_FROM_TB0(do_dsll); + RETURN(); } -static inline void set_HILO (uint64_t HILO) +void op_dsll32 (void) { - env->LO = HILO & 0xFFFFFFFF; - env->HI = HILO >> 32; + CALL_FROM_TB0(do_dsll32); + RETURN(); } -void op_mult (void) +void op_dsra (void) { - set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); + CALL_FROM_TB0(do_dsra); RETURN(); } -void op_multu (void) +void op_dsra32 (void) { - set_HILO((uint64_t)T0 * (uint64_t)T1); + CALL_FROM_TB0(do_dsra32); RETURN(); } -void op_madd (void) +void op_dsrl (void) { - int64_t tmp; + CALL_FROM_TB0(do_dsrl); + RETURN(); +} - tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - set_HILO((int64_t)get_HILO() + tmp); +void op_dsrl32 (void) +{ + CALL_FROM_TB0(do_dsrl32); RETURN(); } -void op_maddu (void) +void op_drotr (void) { - uint64_t tmp; + CALL_FROM_TB0(do_drotr); + RETURN(); +} - tmp = ((uint64_t)T0 * (uint64_t)T1); - set_HILO(get_HILO() + tmp); +void op_drotr32 (void) +{ + CALL_FROM_TB0(do_drotr32); RETURN(); } -void op_msub (void) +void op_dsllv (void) { - int64_t tmp; + CALL_FROM_TB0(do_dsllv); + RETURN(); +} - tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - set_HILO((int64_t)get_HILO() - tmp); +void op_dsrav (void) +{ + CALL_FROM_TB0(do_dsrav); RETURN(); } -void op_msubu (void) +void op_dsrlv (void) { - uint64_t tmp; + CALL_FROM_TB0(do_dsrlv); + RETURN(); +} - tmp = ((uint64_t)T0 * (uint64_t)T1); - set_HILO(get_HILO() - tmp); +void op_drotrv (void) +{ + CALL_FROM_TB0(do_drotrv); RETURN(); } -#else + +#else /* TARGET_LONG_BITS > HOST_LONG_BITS */ + +void op_dsll (void) +{ + T0 = T0 << T1; + RETURN(); +} + +void op_dsll32 (void) +{ + T0 = T0 << (T1 + 32); + RETURN(); +} + +void op_dsra (void) +{ + T0 = (int64_t)T0 >> T1; + RETURN(); +} + +void op_dsra32 (void) +{ + T0 = (int64_t)T0 >> (T1 + 32); + RETURN(); +} + +void op_dsrl (void) +{ + T0 = T0 >> T1; + RETURN(); +} + +void op_dsrl32 (void) +{ + T0 = T0 >> (T1 + 32); + RETURN(); +} + +void op_drotr (void) +{ + target_ulong tmp; + + if (T1) { + tmp = T0 << (0x40 - T1); + T0 = (T0 >> T1) | tmp; + } else + T0 = T1; + RETURN(); +} + +void op_drotr32 (void) +{ + target_ulong tmp; + + if (T1) { + tmp = T0 << (0x40 - (32 + T1)); + T0 = (T0 >> (32 + T1)) | tmp; + } else + T0 = T1; + RETURN(); +} + +void op_dsllv (void) +{ + T0 = T1 << (T0 & 0x3F); + RETURN(); +} + +void op_dsrav (void) +{ + T0 = (int64_t)T1 >> (T0 & 0x3F); + RETURN(); +} + +void op_dsrlv (void) +{ + T0 = T1 >> (T0 & 0x3F); + RETURN(); +} + +void op_drotrv (void) +{ + target_ulong tmp; + + T0 &= 0x3F; + if (T0) { + tmp = T1 << (0x40 - T0); + T0 = (T1 >> T0) | tmp; + } else + T0 = T1; + RETURN(); +} +#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ + +void op_dclo (void) +{ + int n; + + if (T0 == ~((target_ulong)0)) { + T0 = 64; + } else { + for (n = 0; n < 64; n++) { + if (!(T0 & (1ULL << 63))) + break; + T0 = T0 << 1; + } + T0 = n; + } + RETURN(); +} + +void op_dclz (void) +{ + int n; + + if (T0 == 0) { + T0 = 64; + } else { + for (n = 0; n < 64; n++) { + if (T0 & (1ULL << 63)) + break; + T0 = T0 << 1; + } + T0 = n; + } + RETURN(); +} +#endif + +/* 64 bits arithmetic */ +#if TARGET_LONG_BITS > HOST_LONG_BITS void op_mult (void) { CALL_FROM_TB0(do_mult); @@ -610,6 +832,81 @@ void op_msubu (void) CALL_FROM_TB0(do_msubu); RETURN(); } + +#else /* TARGET_LONG_BITS > HOST_LONG_BITS */ + +static inline uint64_t get_HILO (void) +{ + return ((uint64_t)env->HI << 32) | ((uint64_t)(uint32_t)env->LO); +} + +static inline void set_HILO (uint64_t HILO) +{ + env->LO = SIGN_EXTEND32(HILO & 0xFFFFFFFF); + env->HI = SIGN_EXTEND32(HILO >> 32); +} + +void op_mult (void) +{ + set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); + RETURN(); +} + +void op_multu (void) +{ + set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); + RETURN(); +} + +void op_madd (void) +{ + int64_t tmp; + + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); + set_HILO((int64_t)get_HILO() + tmp); + RETURN(); +} + +void op_maddu (void) +{ + uint64_t tmp; + + tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); + set_HILO(get_HILO() + tmp); + RETURN(); +} + +void op_msub (void) +{ + int64_t tmp; + + tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); + set_HILO((int64_t)get_HILO() - tmp); + RETURN(); +} + +void op_msubu (void) +{ + uint64_t tmp; + + tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); + set_HILO(get_HILO() - tmp); + RETURN(); +} +#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ + +#ifdef MIPS_HAS_MIPS64 +void op_dmult (void) +{ + CALL_FROM_TB0(do_dmult); + RETURN(); +} + +void op_dmultu (void) +{ + CALL_FROM_TB0(do_dmultu); + RETURN(); +} #endif /* Conditional moves */ @@ -735,7 +1032,7 @@ void op_jnz_T2 (void) /* CP0 functions */ void op_mfc0_index (void) { - T0 = env->CP0_index; + T0 = SIGN_EXTEND32(env->CP0_index); RETURN(); } @@ -765,25 +1062,25 @@ void op_mfc0_context (void) void op_mfc0_pagemask (void) { - T0 = env->CP0_PageMask; + T0 = SIGN_EXTEND32(env->CP0_PageMask); RETURN(); } void op_mfc0_pagegrain (void) { - T0 = env->CP0_PageGrain; + T0 = SIGN_EXTEND32(env->CP0_PageGrain); RETURN(); } void op_mfc0_wired (void) { - T0 = env->CP0_Wired; + T0 = SIGN_EXTEND32(env->CP0_Wired); RETURN(); } void op_mfc0_hwrena (void) { - T0 = env->CP0_HWREna; + T0 = SIGN_EXTEND32(env->CP0_HWREna); RETURN(); } @@ -807,13 +1104,13 @@ void op_mfc0_entryhi (void) void op_mfc0_compare (void) { - T0 = env->CP0_Compare; + T0 = SIGN_EXTEND32(env->CP0_Compare); RETURN(); } void op_mfc0_status (void) { - T0 = env->CP0_Status; + T0 = SIGN_EXTEND32(env->CP0_Status); if (env->hflags & MIPS_HFLAG_UM) T0 |= (1 << CP0St_UM); if (env->hflags & MIPS_HFLAG_ERL) @@ -825,19 +1122,19 @@ void op_mfc0_status (void) void op_mfc0_intctl (void) { - T0 = env->CP0_IntCtl; + T0 = SIGN_EXTEND32(env->CP0_IntCtl); RETURN(); } void op_mfc0_srsctl (void) { - T0 = env->CP0_SRSCtl; + T0 = SIGN_EXTEND32(env->CP0_SRSCtl); RETURN(); } void op_mfc0_cause (void) { - T0 = env->CP0_Cause; + T0 = SIGN_EXTEND32(env->CP0_Cause); RETURN(); } @@ -849,7 +1146,7 @@ void op_mfc0_epc (void) void op_mfc0_prid (void) { - T0 = env->CP0_PRid; + T0 = SIGN_EXTEND32(env->CP0_PRid); RETURN(); } @@ -861,25 +1158,25 @@ void op_mfc0_ebase (void) void op_mfc0_config0 (void) { - T0 = env->CP0_Config0; + T0 = SIGN_EXTEND32(env->CP0_Config0); RETURN(); } void op_mfc0_config1 (void) { - T0 = env->CP0_Config1; + T0 = SIGN_EXTEND32(env->CP0_Config1); RETURN(); } void op_mfc0_config2 (void) { - T0 = env->CP0_Config2; + T0 = SIGN_EXTEND32(env->CP0_Config2); RETURN(); } void op_mfc0_config3 (void) { - T0 = env->CP0_Config3; + T0 = SIGN_EXTEND32(env->CP0_Config3); RETURN(); } @@ -891,13 +1188,13 @@ void op_mfc0_lladdr (void) void op_mfc0_watchlo0 (void) { - T0 = env->CP0_WatchLo; + T0 = SIGN_EXTEND32(env->CP0_WatchLo); RETURN(); } void op_mfc0_watchhi0 (void) { - T0 = env->CP0_WatchHi; + T0 = SIGN_EXTEND32(env->CP0_WatchHi); RETURN(); } @@ -915,7 +1212,7 @@ void op_mfc0_framemask (void) void op_mfc0_debug (void) { - T0 = env->CP0_Debug; + T0 = SIGN_EXTEND32(env->CP0_Debug); if (env->hflags & MIPS_HFLAG_DM) T0 |= 1 << CP0DB_DM; RETURN(); @@ -929,31 +1226,31 @@ void op_mfc0_depc (void) void op_mfc0_performance0 (void) { - T0 = env->CP0_Performance0; + T0 = SIGN_EXTEND32(env->CP0_Performance0); RETURN(); } void op_mfc0_taglo (void) { - T0 = env->CP0_TagLo; + T0 = SIGN_EXTEND32(env->CP0_TagLo); RETURN(); } void op_mfc0_datalo (void) { - T0 = env->CP0_DataLo; + T0 = SIGN_EXTEND32(env->CP0_DataLo); RETURN(); } void op_mfc0_taghi (void) { - T0 = env->CP0_TagHi; + T0 = SIGN_EXTEND32(env->CP0_TagHi); RETURN(); } void op_mfc0_datahi (void) { - T0 = env->CP0_DataHi; + T0 = SIGN_EXTEND32(env->CP0_DataHi); RETURN(); } @@ -965,7 +1262,7 @@ void op_mfc0_errorepc (void) void op_mfc0_desave (void) { - T0 = env->CP0_DESAVE; + T0 = SIGN_EXTEND32(env->CP0_DESAVE); RETURN(); } @@ -979,7 +1276,7 @@ void op_mtc0_entrylo0 (void) { /* Large physaddr not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo0 = T0 & 0x3FFFFFFFUL; + env->CP0_EntryLo0 = T0 & SIGN_EXTEND32(0x3FFFFFFFUL); RETURN(); } @@ -987,7 +1284,7 @@ void op_mtc0_entrylo1 (void) { /* Large physaddr not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo1 = T0 & 0x3FFFFFFFUL; + env->CP0_EntryLo1 = T0 & SIGN_EXTEND32(0x3FFFFFFFUL); RETURN(); } @@ -1037,7 +1334,7 @@ void op_mtc0_entryhi (void) /* 1k pages not implemented */ /* Ignore MIPS64 TLB for now */ - val = T0 & 0xFFFFE0FF; + val = T0 & SIGN_EXTEND32(0xFFFFE0FF); old = env->CP0_EntryHi; env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ @@ -1056,7 +1353,7 @@ void op_mtc0_status (void) { uint32_t val, old, mask; - val = T0 & 0xFA78FF01; + val = T0 & SIGN_EXTEND32(0xFA78FF01); old = env->CP0_Status; if (T0 & (1 << CP0St_UM)) env->hflags |= MIPS_HFLAG_UM; @@ -1107,7 +1404,7 @@ void op_mtc0_cause (void) { uint32_t val, old; - val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300); + val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300); old = env->CP0_Cause; env->CP0_Cause = val; #if 0 @@ -1134,7 +1431,7 @@ void op_mtc0_ebase (void) { /* vectored interrupts not implemented */ /* Multi-CPU not implemented */ - env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000); + env->CP0_EBase = SIGN_EXTEND32(0x80000000) | (T0 & 0x3FFFF000); RETURN(); } @@ -1204,7 +1501,7 @@ void op_mtc0_performance0 (void) void op_mtc0_taglo (void) { - env->CP0_TagLo = T0 & 0xFFFFFCF6; + env->CP0_TagLo = T0 & SIGN_EXTEND32(0xFFFFFCF6); RETURN(); } @@ -1787,7 +2084,7 @@ void op_ext(void) unsigned int pos = PARAM1; unsigned int size = PARAM2; - T0 = (T1 >> pos) & ((1 << size) - 1); + T0 = ((uint32_t)T1 >> pos) & ((1 << size) - 1); RETURN(); } @@ -1797,7 +2094,7 @@ void op_ins(void) unsigned int size = PARAM2; target_ulong mask = ((1 << size) - 1) << pos; - T0 = (T2 & ~mask) | ((T1 << pos) & mask); + T0 = (T2 & ~mask) | (((uint32_t)T1 << pos) & mask); RETURN(); } @@ -1807,6 +2104,26 @@ void op_wsbh(void) RETURN(); } +#ifdef MIPS_HAS_MIPS64 +void op_dext(void) +{ + unsigned int pos = PARAM1; + unsigned int size = PARAM2; + + T0 = (T1 >> pos) & ((1 << size) - 1); + RETURN(); +} + +void op_dins(void) +{ + unsigned int pos = PARAM1; + unsigned int size = PARAM2; + target_ulong mask = ((1 << size) - 1) << pos; + + T0 = (T2 & ~mask) | ((T1 << pos) & mask); + RETURN(); +} + void op_dsbh(void) { T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL); @@ -1818,6 +2135,7 @@ void op_dshd(void) T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL); RETURN(); } +#endif void op_seb(void) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 87a043dc2..b719f036a 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -74,8 +74,92 @@ void do_raise_exception_direct (uint32_t exception) #undef MEMSUFFIX #endif +#ifdef MIPS_HAS_MIPS64 +#if TARGET_LONG_BITS > HOST_LONG_BITS +/* Those might call libgcc functions. */ +void do_dsll (void) +{ + T0 = T0 << T1; +} + +void do_dsll32 (void) +{ + T0 = T0 << (T1 + 32); +} + +void do_dsra (void) +{ + T0 = (int64_t)T0 >> T1; +} + +void do_dsra32 (void) +{ + T0 = (int64_t)T0 >> (T1 + 32); +} + +void do_dsrl (void) +{ + T0 = T0 >> T1; +} + +void do_dsrl32 (void) +{ + T0 = T0 >> (T1 + 32); +} + +void do_drotr (void) +{ + target_ulong tmp; + + if (T1) { + tmp = T0 << (0x40 - T1); + T0 = (T0 >> T1) | tmp; + } else + T0 = T1; +} + +void do_drotr32 (void) +{ + target_ulong tmp; + + if (T1) { + tmp = T0 << (0x40 - (32 + T1)); + T0 = (T0 >> (32 + T1)) | tmp; + } else + T0 = T1; +} + +void do_dsllv (void) +{ + T0 = T1 << (T0 & 0x3F); +} + +void do_dsrav (void) +{ + T0 = (int64_t)T1 >> (T0 & 0x3F); +} + +void do_dsrlv (void) +{ + T0 = T1 >> (T0 & 0x3F); +} + +void do_drotrv (void) +{ + target_ulong tmp; + + T0 &= 0x3F; + if (T0) { + tmp = T1 << (0x40 - T0); + T0 = (T1 >> T0) | tmp; + } else + T0 = T1; +} +#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ +#endif /* MIPS_HAS_MIPS64 */ + /* 64 bits arithmetic for 32 bits hosts */ -#if (HOST_LONG_BITS == 32) +#if TARGET_LONG_BITS > HOST_LONG_BITS static inline uint64_t get_HILO (void) { return ((uint64_t)env->HI << 32) | (uint64_t)env->LO; @@ -83,8 +167,8 @@ static inline uint64_t get_HILO (void) static inline void set_HILO (uint64_t HILO) { - env->LO = HILO & 0xFFFFFFFF; - env->HI = HILO >> 32; + env->LO = SIGN_EXTEND32(HILO & 0xFFFFFFFF); + env->HI = SIGN_EXTEND32(HILO >> 32); } void do_mult (void) @@ -94,7 +178,7 @@ void do_mult (void) void do_multu (void) { - set_HILO((uint64_t)T0 * (uint64_t)T1); + set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); } void do_madd (void) @@ -109,7 +193,7 @@ void do_maddu (void) { uint64_t tmp; - tmp = ((uint64_t)T0 * (uint64_t)T1); + tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); set_HILO(get_HILO() + tmp); } @@ -125,11 +209,41 @@ void do_msubu (void) { uint64_t tmp; - tmp = ((uint64_t)T0 * (uint64_t)T1); + tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); set_HILO(get_HILO() - tmp); } #endif +#ifdef MIPS_HAS_MIPS64 +void do_dmult (void) +{ + /* XXX */ + set_HILO((int64_t)T0 * (int64_t)T1); +} + +void do_dmultu (void) +{ + /* XXX */ + set_HILO((uint64_t)T0 * (uint64_t)T1); +} + +void do_ddiv (void) +{ + if (T1 != 0) { + env->LO = (int64_t)T0 / (int64_t)T1; + env->HI = (int64_t)T0 % (int64_t)T1; + } +} + +void do_ddivu (void) +{ + if (T1 != 0) { + env->LO = T0 / T1; + env->HI = T0 % T1; + } +} +#endif + #if defined(CONFIG_USER_ONLY) void do_mfc0_random (void) { @@ -191,12 +305,12 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) /* CP0 helpers */ void do_mfc0_random (void) { - T0 = cpu_mips_get_random(env); + T0 = SIGN_EXTEND32(cpu_mips_get_random(env)); } void do_mfc0_count (void) { - T0 = cpu_mips_get_count(env); + T0 = SIGN_EXTEND32(cpu_mips_get_count(env)); } void do_mtc0_status_debug(uint32_t old, uint32_t val) @@ -319,7 +433,7 @@ static void fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb[idx]; - tlb->VPN = env->CP0_EntryHi & 0xFFFFE000; + tlb->VPN = env->CP0_EntryHi & SIGN_EXTEND32(0xFFFFE000); tlb->ASID = env->CP0_EntryHi & 0xFF; size = env->CP0_PageMask >> 13; size = 4 * (size + 1); @@ -364,7 +478,7 @@ void do_tlbp (void) uint8_t ASID; int i; - tag = env->CP0_EntryHi & 0xFFFFE000; + tag = env->CP0_EntryHi & SIGN_EXTEND32(0xFFFFE000); ASID = env->CP0_EntryHi & 0xFF; for (i = 0; i < MIPS_TLB_NB; i++) { tlb = &env->tlb[i]; @@ -418,16 +532,16 @@ void do_tlbr (void) #endif /* !CONFIG_USER_ONLY */ -void op_dump_ldst (const unsigned char *func) +void dump_ldst (const unsigned char *func) { if (loglevel) - fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1); + fprintf(logfile, "%s => " TLSZ " " TLSZ "\n", __func__, T0, T1); } void dump_sc (void) { if (loglevel) { - fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__, + fprintf(logfile, "%s " TLSZ " at " TLSZ " (" TLSZ ")\n", __func__, T1, T0, env->CP0_LLAddr); } } @@ -435,7 +549,7 @@ void dump_sc (void) void debug_eret (void) { if (loglevel) { - fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n", + fprintf(logfile, "ERET: pc " TLSZ " EPC " TLSZ " ErrorEPC " TLSZ " (%d)\n", env->PC, env->CP0_EPC, env->CP0_ErrorEPC, env->hflags & MIPS_HFLAG_ERL ? 1 : 0); } @@ -454,13 +568,13 @@ void do_pmon (int function) break; case 3: case 12: - printf("%c", env->gpr[4] & 0xFF); + printf("%c", (char)(env->gpr[4] & 0xFF)); break; case 17: break; case 158: { - unsigned char *fmt = (void *)env->gpr[4]; + unsigned char *fmt = (void *)(unsigned long)env->gpr[4]; printf("%s", fmt); } break; diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index 4711f7a6c..e8ec22b15 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -10,9 +10,6 @@ void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) target_ulong sav = T0; #endif - /* XXX: this is valid only in big-endian mode - * should be reverted for little-endian... - */ switch (GET_LMASK(T0)) { case 0: T0 = tmp; @@ -42,9 +39,6 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) target_ulong sav = T0; #endif - /* XXX: this is valid only in big-endian mode - * should be reverted for little-endian... - */ switch (GET_LMASK(T0)) { case 0: T0 = (tmp >> 24) | (T1 & 0xFFFFFF00); @@ -71,15 +65,9 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) - target_ulong sav; + target_ulong sav = tmp; #endif -#if defined (DEBUG_OP) - sav = tmp; -#endif - /* XXX: this is valid only in big-endian mode - * should be reverted for little-endian... - */ switch (GET_LMASK(T0)) { case 0: tmp = T1; @@ -107,15 +95,9 @@ uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) { #if defined (DEBUG_OP) - target_ulong sav; + target_ulong sav = tmp; #endif -#if defined (DEBUG_OP) - sav = tmp; -#endif - /* XXX: this is valid only in big-endian mode - * should be reverted for little-endian... - */ switch (GET_LMASK(T0)) { case 0: tmp = (tmp & 0x00FFFFFF) | (T1 << 24); @@ -139,3 +121,179 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) RETURN(); return tmp; } + +#ifdef MIPS_HAS_MIPS64 + +# ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK64(v) ((v) & 4) +#else +#define GET_LMASK64(v) (((v) & 4) ^ 4) +#endif + +void glue(do_ldl, MEMSUFFIX) (uint64_t tmp) +{ +#if defined (DEBUG_OP) + target_ulong sav = T0; +#endif + + switch (GET_LMASK64(T0)) { + case 0: + T0 = tmp; + break; + case 1: + T0 = (tmp << 8) | (T1 & 0x00000000000000FFULL); + break; + case 2: + T0 = (tmp << 16) | (T1 & 0x000000000000FFFFULL); + break; + case 3: + T0 = (tmp << 24) | (T1 & 0x0000000000FFFFFFULL); + break; + case 4: + T0 = (tmp << 32) | (T1 & 0x00000000FFFFFFFFULL); + break; + case 5: + T0 = (tmp << 40) | (T1 & 0x000000FFFFFFFFFFULL); + break; + case 6: + T0 = (tmp << 48) | (T1 & 0x0000FFFFFFFFFFFFULL); + break; + case 7: + T0 = (tmp << 56) | (T1 & 0x00FFFFFFFFFFFFFFULL); + break; + } +#if defined (DEBUG_OP) + if (logfile) { + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + __func__, sav, tmp, T1, T0); + } +#endif + RETURN(); +} + +void glue(do_ldr, MEMSUFFIX) (uint64_t tmp) +{ +#if defined (DEBUG_OP) + target_ulong sav = T0; +#endif + + switch (GET_LMASK64(T0)) { + case 0: + T0 = (tmp >> 56) | (T1 & 0xFFFFFFFFFFFFFF00ULL); + break; + case 1: + T0 = (tmp >> 48) | (T1 & 0xFFFFFFFFFFFF0000ULL); + break; + case 2: + T0 = (tmp >> 40) | (T1 & 0xFFFFFFFFFF000000ULL); + break; + case 3: + T0 = (tmp >> 32) | (T1 & 0xFFFFFFFF00000000ULL); + break; + case 4: + T0 = (tmp >> 24) | (T1 & 0xFFFFFF0000000000ULL); + break; + case 5: + T0 = (tmp >> 16) | (T1 & 0xFFFF000000000000ULL); + break; + case 6: + T0 = (tmp >> 8) | (T1 & 0xFF00000000000000ULL); + break; + case 7: + T0 = tmp; + break; + } +#if defined (DEBUG_OP) + if (logfile) { + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + __func__, sav, tmp, T1, T0); + } +#endif + RETURN(); +} + +uint64_t glue(do_sdl, MEMSUFFIX) (uint64_t tmp) +{ +#if defined (DEBUG_OP) + target_ulong sav = tmp; +#endif + + switch (GET_LMASK64(T0)) { + case 0: + tmp = T1; + break; + case 1: + tmp = (tmp & 0xFF00000000000000ULL) | (T1 >> 8); + break; + case 2: + tmp = (tmp & 0xFFFF000000000000ULL) | (T1 >> 16); + break; + case 3: + tmp = (tmp & 0xFFFFFF0000000000ULL) | (T1 >> 24); + break; + case 4: + tmp = (tmp & 0xFFFFFFFF00000000ULL) | (T1 >> 32); + break; + case 5: + tmp = (tmp & 0xFFFFFFFFFF000000ULL) | (T1 >> 40); + break; + case 6: + tmp = (tmp & 0xFFFFFFFFFFFF0000ULL) | (T1 >> 48); + break; + case 7: + tmp = (tmp & 0xFFFFFFFFFFFFFF00ULL) | (T1 >> 56); + break; + } +#if defined (DEBUG_OP) + if (logfile) { + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + __func__, T0, sav, T1, tmp); + } +#endif + RETURN(); + return tmp; +} + +uint64_t glue(do_sdr, MEMSUFFIX) (uint64_t tmp) +{ +#if defined (DEBUG_OP) + target_ulong sav = tmp; +#endif + + switch (GET_LMASK64(T0)) { + case 0: + tmp = (tmp & 0x00FFFFFFFFFFFFFFULL) | (T1 << 56); + break; + case 1: + tmp = (tmp & 0x0000FFFFFFFFFFFFULL) | (T1 << 48); + break; + case 2: + tmp = (tmp & 0x000000FFFFFFFFFFULL) | (T1 << 40); + break; + case 3: + tmp = (tmp & 0x00000000FFFFFFFFULL) | (T1 << 32); + break; + case 4: + tmp = (tmp & 0x0000000000FFFFFFULL) | (T1 << 24); + break; + case 5: + tmp = (tmp & 0x000000000000FFFFULL) | (T1 << 16); + break; + case 6: + tmp = (tmp & 0x00000000000000FFULL) | (T1 << 8); + break; + case 7: + tmp = T1; + break; + } +#if defined (DEBUG_OP) + if (logfile) { + fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + __func__, T0, sav, T1, tmp); + } +#endif + RETURN(); + return tmp; +} + +#endif /* MIPS_HAS_MIPS64 */ diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 35ccd44c6..a3289793b 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -75,6 +75,7 @@ void glue(op_sw, MEMSUFFIX) (void) /* "half" load and stores. We must do the memory access inline, or fault handling won't work. */ +/* XXX: This is broken, CP0_BADVADDR has the wrong (aligned) value. */ void glue(op_lwl, MEMSUFFIX) (void) { uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); @@ -125,6 +126,72 @@ void glue(op_sc, MEMSUFFIX) (void) RETURN(); } +#ifdef MIPS_HAS_MIPS64 +void glue(op_ld, MEMSUFFIX) (void) +{ + T0 = glue(ldq, MEMSUFFIX)(T0); + RETURN(); +} + +void glue(op_sd, MEMSUFFIX) (void) +{ + glue(stq, MEMSUFFIX)(T0, T1); + RETURN(); +} + +/* "half" load and stores. We must do the memory access inline, + or fault handling won't work. */ +void glue(op_ldl, MEMSUFFIX) (void) +{ + target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7); + CALL_FROM_TB1(glue(do_ldl, MEMSUFFIX), tmp); + RETURN(); +} + +void glue(op_ldr, MEMSUFFIX) (void) +{ + target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7); + CALL_FROM_TB1(glue(do_ldr, MEMSUFFIX), tmp); + RETURN(); +} + +void glue(op_sdl, MEMSUFFIX) (void) +{ + target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7); + tmp = CALL_FROM_TB1(glue(do_sdl, MEMSUFFIX), tmp); + glue(stq, MEMSUFFIX)(T0 & ~7, tmp); + RETURN(); +} + +void glue(op_sdr, MEMSUFFIX) (void) +{ + target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7); + tmp = CALL_FROM_TB1(glue(do_sdr, MEMSUFFIX), tmp); + glue(stq, MEMSUFFIX)(T0 & ~7, tmp); + RETURN(); +} + +void glue(op_lld, MEMSUFFIX) (void) +{ + T1 = T0; + T0 = glue(ldq, MEMSUFFIX)(T0); + env->CP0_LLAddr = T1; + RETURN(); +} + +void glue(op_scd, MEMSUFFIX) (void) +{ + CALL_FROM_TB0(dump_sc); + if (T0 == env->CP0_LLAddr) { + glue(stq, MEMSUFFIX)(T0, T1); + T0 = 1; + } else { + T0 = 0; + } + RETURN(); +} +#endif /* MIPS_HAS_MIPS64 */ + #ifdef MIPS_USES_FPU void glue(op_lwc1, MEMSUFFIX) (void) { diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 9314c95e2..8d4c4e404 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -51,15 +51,21 @@ void glue(op_load_gpr_T2_gpr, REG) (void) #endif #if defined (TN) -void glue(op_set_, TN) (void) -{ - TN = PARAM1; - RETURN(); -} +#define SET_RESET(treg, tregname) \ + void glue(op_set, tregname)(void) \ + { \ + treg = PARAM1; \ + RETURN(); \ + } \ + void glue(op_reset, tregname)(void) \ + { \ + treg = 0; \ + RETURN(); \ + } \ -void glue (op_reset_, TN) (void) -{ - TN = 0; - RETURN(); -} +SET_RESET(T0, _T0) +SET_RESET(T1, _T1) +SET_RESET(T2, _T2) + +#undef SET_RESET #endif diff --git a/target-mips/translate.c b/target-mips/translate.c index c9cbc9dad..1252e81a9 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -31,6 +31,7 @@ #include "disas.h" //#define MIPS_DEBUG_DISAS +//#define MIPS_DEBUG_SIGN_EXTENSIONS //#define MIPS_SINGLE_STEP #ifdef USE_DIRECT_JUMP @@ -502,7 +503,7 @@ enum { #define MIPS_DEBUG(fmt, args...) \ do { \ if (loglevel & CPU_LOG_TB_IN_ASM) { \ - fprintf(logfile, "%08x: %08x " fmt "\n", \ + fprintf(logfile, TLSZ ": %08x " fmt "\n", \ ctx->pc, ctx->opcode , ##args); \ } \ } while (0) @@ -621,6 +622,8 @@ OP_LD_TABLE(dr); OP_ST_TABLE(d); OP_ST_TABLE(dl); OP_ST_TABLE(dr); +OP_LD_TABLE(ld); +OP_ST_TABLE(cd); #endif OP_LD_TABLE(w); OP_LD_TABLE(wu); @@ -1417,7 +1420,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_J: case OPC_JAL: /* Jump to immediate */ - btarget = ((ctx->pc + 4) & 0xF0000000) | offset; + btarget = ((ctx->pc + 4) & SIGN_EXTEND32(0xF0000000)) | offset; break; case OPC_JR: case OPC_JALR: @@ -2927,21 +2930,21 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, switch (op) { case OPC_BC1F: gen_op_bc1f(); - MIPS_DEBUG("bc1f %08x", btarget); + MIPS_DEBUG("bc1f " TLSZ, btarget); goto not_likely; case OPC_BC1FL: gen_op_bc1f(); - MIPS_DEBUG("bc1fl %08x", btarget); + MIPS_DEBUG("bc1fl " TLSZ, btarget); goto likely; case OPC_BC1T: gen_op_bc1t(); - MIPS_DEBUG("bc1t %08x", btarget); + MIPS_DEBUG("bc1t " TLSZ, btarget); not_likely: ctx->hflags |= MIPS_HFLAG_BC; break; case OPC_BC1TL: gen_op_bc1t(); - MIPS_DEBUG("bc1tl %08x", btarget); + MIPS_DEBUG("bc1tl " TLSZ, btarget); likely: ctx->hflags |= MIPS_HFLAG_BL; break; @@ -2952,7 +2955,7 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, } gen_op_set_bcond(); - MIPS_DEBUG("enter ds: cond %02x target %08x", + MIPS_DEBUG("enter ds: cond %02x target " TLSZ, ctx->hflags, btarget); ctx->btarget = btarget; @@ -3351,30 +3354,6 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) /* SmartMIPS extension to MIPS32 */ #ifdef MIPS_HAS_MIPS64 -static void gen_arith64 (DisasContext *ctx, uint32_t opc) -{ - if (func == 0x02 && rd == 0) { - /* NOP */ - return; - } - if (rs == 0 || rt == 0) { - gen_op_reset_T0(); - gen_op_save64(); - } else { - gen_op_load_gpr_T0(rs); - gen_op_load_gpr_T1(rt); - gen_op_save64(); - if (func & 0x01) - gen_op_mul64u(); - else - gen_op_mul64s(); - } - if (func & 0x02) - gen_op_add64(); - else - gen_op_sub64(); -} - /* Coprocessor 3 (FPU) */ /* MDMX extension to MIPS64 */ @@ -3407,7 +3386,7 @@ static void decode_opc (DisasContext *ctx) if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { /* Handle blikely not taken case */ - MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4); + MIPS_DEBUG("blikely condition (" TLSZ ")", ctx->pc + 4); gen_blikely(ctx); } op = MASK_OP_MAJOR(ctx->opcode); @@ -4011,7 +3990,7 @@ void fpu_dump_state(CPUState *env, FILE *f, void dump_fpu (CPUState *env) { if (loglevel) { - fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n", + fprintf(logfile, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n", env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); fpu_dump_state(env, logfile, fprintf, 0); } @@ -4019,6 +3998,39 @@ void dump_fpu (CPUState *env) #endif /* MIPS_USES_FPU */ +#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) +/* Debug help: The architecture requires 32bit code to maintain proper + sign-extened values on 64bit machines. */ + +#define SIGN_EXT_P(val) ((((val) & ~0x7fffffff) == 0) || (((val) & ~0x7fffffff) == ~0x7fffffff)) + +void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; + + if (!SIGN_EXT_P(env->PC)) + cpu_fprintf(f, "BROKEN: pc=0x" TLSZ "\n", env->PC); + if (!SIGN_EXT_P(env->HI)) + cpu_fprintf(f, "BROKEN: HI=0x" TLSZ "\n", env->HI); + if (!SIGN_EXT_P(env->LO)) + cpu_fprintf(f, "BROKEN: LO=0x" TLSZ "\n", env->LO); + if (!SIGN_EXT_P(env->btarget)) + cpu_fprintf(f, "BROKEN: btarget=0x" TLSZ "\n", env->btarget); + + for (i = 0; i < 32; i++) { + if (!SIGN_EXT_P(env->gpr[i])) + cpu_fprintf(f, "BROKEN: %s=0x" TLSZ "\n", regnames[i], env->gpr[i]); + } + + if (!SIGN_EXT_P(env->CP0_EPC)) + cpu_fprintf(f, "BROKEN: EPC=0x" TLSZ "\n", env->CP0_EPC); + if (!SIGN_EXT_P(env->CP0_LLAddr)) + cpu_fprintf(f, "BROKEN: LLAddr=0x" TLSZ "\n", env->CP0_LLAddr); +} +#endif + void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -4026,12 +4038,12 @@ void cpu_dump_state (CPUState *env, FILE *f, uint32_t c0_status; int i; - cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n", + cpu_fprintf(f, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n", env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { if ((i & 3) == 0) cpu_fprintf(f, "GPR%02d:", i); - cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]); + cpu_fprintf(f, " %s " TLSZ, regnames[i], env->gpr[i]); if ((i & 3) == 3) cpu_fprintf(f, "\n"); } @@ -4044,14 +4056,17 @@ void cpu_dump_state (CPUState *env, FILE *f, if (env->hflags & MIPS_HFLAG_EXL) c0_status |= (1 << CP0St_EXL); - cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n", + cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TLSZ "\n", c0_status, env->CP0_Cause, env->CP0_EPC); - cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n", + cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TLSZ "\n", env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); #ifdef MIPS_USES_FPU if (c0_status & (1 << CP0St_CU1)) fpu_dump_state(env, f, cpu_fprintf, flags); #endif +#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) + cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags); +#endif } CPUMIPSState *cpu_mips_init (void) @@ -4082,14 +4097,14 @@ void cpu_reset (CPUMIPSState *env) } else { env->CP0_ErrorEPC = env->PC; } - env->PC = 0xBFC00000; + env->PC = SIGN_EXTEND32(0xBFC00000); #if defined (MIPS_USES_R4K_TLB) env->CP0_random = MIPS_TLB_NB - 1; env->tlb_in_use = MIPS_TLB_NB; #endif env->CP0_Wired = 0; /* SMP not implemented */ - env->CP0_EBase = 0x80000000; + env->CP0_EBase = SIGN_EXTEND32(0x80000000); env->CP0_Config0 = MIPS_CONFIG0; env->CP0_Config1 = MIPS_CONFIG1; env->CP0_Config2 = MIPS_CONFIG2; -- cgit v1.2.3 From 5dc4b744806b5f7487989e42a84322fbd5810877 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 13:48:28 +0000 Subject: Scrap SIGN_EXTEND32. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2251 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 12 ++++-- target-mips/cpu.h | 5 +-- target-mips/helper.c | 20 +++++----- target-mips/op.c | 102 ++++++++++++++++++++++++------------------------ target-mips/op_helper.c | 12 +++--- target-mips/translate.c | 6 +-- 6 files changed, 79 insertions(+), 78 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index ca3a4ffce..1f779b2ff 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -11,10 +11,14 @@ #define BIOS_FILENAME "mips_bios.bin" //#define BIOS_FILENAME "system.bin" -#define KERNEL_LOAD_ADDR SIGN_EXTEND32(0x80010000) -#define INITRD_LOAD_ADDR SIGN_EXTEND32(0x80800000) +#define KERNEL_LOAD_ADDR (int32_t)0x80010000 +#ifdef MIPS_HAS_MIPS64 +#define INITRD_LOAD_ADDR (int64_t)0x80800000 +#else +#define INITRD_LOAD_ADDR (int32_t)0x80800000 +#endif -#define VIRT_TO_PHYS_ADDEND (-SIGN_EXTEND32(0x80000000LL)) +#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; @@ -76,7 +80,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) - entry = SIGN_EXTEND32(entry); + entry = (int32_t)entry; env->PC = entry; } else { kernel_size = load_image(kernel_filename, diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 710748c69..8f0f598b6 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -15,13 +15,10 @@ typedef unsigned char uint_fast8_t; typedef unsigned int uint_fast16_t; #endif -#ifdef MIPS_HAS_MIPS64 -#define SIGN_EXTEND32(val) (((((uint64_t)(val)) & 0xFFFFFFFF) ^ 0x80000000) - 0x80000000) /* target_ulong size spec */ +#ifdef MIPS_HAS_MIPS64 #define TLSZ "%016llx" #else -#define SIGN_EXTEND32(val) (val) -/* target_ulong size spec */ #define TLSZ "%08x" #endif diff --git a/target-mips/helper.c b/target-mips/helper.c index 0e3eb6c7c..e70dc1a99 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -86,7 +86,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, #endif if (user_mode && address > 0x7FFFFFFFUL) return TLBRET_BADADDR; - if (address < SIGN_EXTEND32(0x80000000UL)) { + if (address < (int32_t)0x80000000UL) { if (!(env->hflags & MIPS_HFLAG_ERL)) { #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); @@ -98,17 +98,17 @@ static int get_physical_address (CPUState *env, target_ulong *physical, *physical = address; *prot = PAGE_READ | PAGE_WRITE; } - } else if (address < SIGN_EXTEND32(0xA0000000UL)) { + } else if (address < (int32_t)0xA0000000UL) { /* kseg0 */ /* XXX: check supervisor mode */ - *physical = address - SIGN_EXTEND32(0x80000000UL); + *physical = address - (int32_t)0x80000000UL; *prot = PAGE_READ | PAGE_WRITE; - } else if (address < SIGN_EXTEND32(0xC0000000UL)) { + } else if (address < (int32_t)0xC0000000UL) { /* kseg1 */ /* XXX: check supervisor mode */ - *physical = address - SIGN_EXTEND32(0xA0000000UL); + *physical = address - (int32_t)0xA0000000UL; *prot = PAGE_READ | PAGE_WRITE; - } else if (address < SIGN_EXTEND32(0xE0000000UL)) { + } else if (address < (int32_t)0xE0000000UL) { /* kseg2 */ #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); @@ -299,7 +299,7 @@ void do_interrupt (CPUState *env) enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; /* EJTAG probe trap enable is not implemented... */ - env->PC = SIGN_EXTEND32(0xBFC00480); + env->PC = (int32_t)0xBFC00480; break; case EXCP_RESET: cpu_reset(env); @@ -321,7 +321,7 @@ void do_interrupt (CPUState *env) } env->hflags |= MIPS_HFLAG_ERL; env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - env->PC = SIGN_EXTEND32(0xBFC00000); + env->PC = (int32_t)0xBFC00000; break; case EXCP_MCHECK: cause = 24; @@ -389,9 +389,9 @@ void do_interrupt (CPUState *env) env->CP0_Cause &= ~0x80000000; } if (env->CP0_Status & (1 << CP0St_BEV)) { - env->PC = SIGN_EXTEND32(0xBFC00200); + env->PC = (int32_t)0xBFC00200; } else { - env->PC = SIGN_EXTEND32(0x80000000); + env->PC = (int32_t)0x80000000; } env->hflags |= MIPS_HFLAG_EXL; env->CP0_Status |= (1 << CP0St_EXL); diff --git a/target-mips/op.c b/target-mips/op.c index 4b6c20c49..27fb3ef59 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -328,7 +328,7 @@ void op_store_LO (void) /* Arithmetic */ void op_add (void) { - T0 = SIGN_EXTEND32((int32_t)T0 + (int32_t)T1); + T0 = (int32_t)((int32_t)T0 + (int32_t)T1); RETURN(); } @@ -342,13 +342,13 @@ void op_addo (void) /* operands of same sign, result different sign */ CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } - T0 = SIGN_EXTEND32(T0); + T0 = (int32_t)T0; RETURN(); } void op_sub (void) { - T0 = SIGN_EXTEND32((int32_t)T0 - (int32_t)T1); + T0 = (int32_t)((int32_t)T0 - (int32_t)T1); RETURN(); } @@ -362,21 +362,21 @@ void op_subo (void) /* operands of different sign, first operand and result different sign */ CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); } - T0 = SIGN_EXTEND32(T0); + T0 = (int32_t)T0; RETURN(); } void op_mul (void) { - T0 = SIGN_EXTEND32((int32_t)T0 * (int32_t)T1); + T0 = (int32_t)((int32_t)T0 * (int32_t)T1); RETURN(); } void op_div (void) { if (T1 != 0) { - env->LO = SIGN_EXTEND32((int32_t)T0 / (int32_t)T1); - env->HI = SIGN_EXTEND32((int32_t)T0 % (int32_t)T1); + env->LO = (int32_t)((int32_t)T0 / (int32_t)T1); + env->HI = (int32_t)((int32_t)T0 % (int32_t)T1); } RETURN(); } @@ -384,8 +384,8 @@ void op_div (void) void op_divu (void) { if (T1 != 0) { - env->LO = SIGN_EXTEND32((uint32_t)T0 / (uint32_t)T1); - env->HI = SIGN_EXTEND32((uint32_t)T0 % (uint32_t)T1); + env->LO = (int32_t)((uint32_t)T0 / (uint32_t)T1); + env->HI = (int32_t)((uint32_t)T0 % (uint32_t)T1); } RETURN(); } @@ -497,19 +497,19 @@ void op_xor (void) void op_sll (void) { - T0 = SIGN_EXTEND32((uint32_t)T0 << (uint32_t)T1); + T0 = (int32_t)((uint32_t)T0 << (uint32_t)T1); RETURN(); } void op_sra (void) { - T0 = SIGN_EXTEND32((int32_t)T0 >> (uint32_t)T1); + T0 = (int32_t)((int32_t)T0 >> (uint32_t)T1); RETURN(); } void op_srl (void) { - T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1); + T0 = (int32_t)((uint32_t)T0 >> (uint32_t)T1); RETURN(); } @@ -518,8 +518,8 @@ void op_rotr (void) target_ulong tmp; if (T1) { - tmp = SIGN_EXTEND32((uint32_t)T0 << (0x20 - (uint32_t)T1)); - T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1) | tmp; + tmp = (int32_t)((uint32_t)T0 << (0x20 - (uint32_t)T1)); + T0 = (int32_t)((uint32_t)T0 >> (uint32_t)T1) | tmp; } else T0 = T1; RETURN(); @@ -527,19 +527,19 @@ void op_rotr (void) void op_sllv (void) { - T0 = SIGN_EXTEND32((uint32_t)T1 << ((uint32_t)T0 & 0x1F)); + T0 = (int32_t)((uint32_t)T1 << ((uint32_t)T0 & 0x1F)); RETURN(); } void op_srav (void) { - T0 = SIGN_EXTEND32((int32_t)T1 >> (T0 & 0x1F)); + T0 = (int32_t)((int32_t)T1 >> (T0 & 0x1F)); RETURN(); } void op_srlv (void) { - T0 = SIGN_EXTEND32((uint32_t)T1 >> (T0 & 0x1F)); + T0 = (int32_t)((uint32_t)T1 >> (T0 & 0x1F)); RETURN(); } @@ -549,8 +549,8 @@ void op_rotrv (void) T0 &= 0x1F; if (T0) { - tmp = SIGN_EXTEND32((uint32_t)T1 << (0x20 - T0)); - T0 = SIGN_EXTEND32((uint32_t)T1 >> T0) | tmp; + tmp = (int32_t)((uint32_t)T1 << (0x20 - T0)); + T0 = (int32_t)((uint32_t)T1 >> T0) | tmp; } else T0 = T1; RETURN(); @@ -842,8 +842,8 @@ static inline uint64_t get_HILO (void) static inline void set_HILO (uint64_t HILO) { - env->LO = SIGN_EXTEND32(HILO & 0xFFFFFFFF); - env->HI = SIGN_EXTEND32(HILO >> 32); + env->LO = (int32_t)(HILO & 0xFFFFFFFF); + env->HI = (int32_t)(HILO >> 32); } void op_mult (void) @@ -1032,7 +1032,7 @@ void op_jnz_T2 (void) /* CP0 functions */ void op_mfc0_index (void) { - T0 = SIGN_EXTEND32(env->CP0_index); + T0 = (int32_t)(env->CP0_index); RETURN(); } @@ -1062,25 +1062,25 @@ void op_mfc0_context (void) void op_mfc0_pagemask (void) { - T0 = SIGN_EXTEND32(env->CP0_PageMask); + T0 = (int32_t)env->CP0_PageMask; RETURN(); } void op_mfc0_pagegrain (void) { - T0 = SIGN_EXTEND32(env->CP0_PageGrain); + T0 = (int32_t)env->CP0_PageGrain; RETURN(); } void op_mfc0_wired (void) { - T0 = SIGN_EXTEND32(env->CP0_Wired); + T0 = (int32_t)env->CP0_Wired; RETURN(); } void op_mfc0_hwrena (void) { - T0 = SIGN_EXTEND32(env->CP0_HWREna); + T0 = (int32_t)env->CP0_HWREna; RETURN(); } @@ -1104,13 +1104,13 @@ void op_mfc0_entryhi (void) void op_mfc0_compare (void) { - T0 = SIGN_EXTEND32(env->CP0_Compare); + T0 = (int32_t)env->CP0_Compare; RETURN(); } void op_mfc0_status (void) { - T0 = SIGN_EXTEND32(env->CP0_Status); + T0 = (int32_t)env->CP0_Status; if (env->hflags & MIPS_HFLAG_UM) T0 |= (1 << CP0St_UM); if (env->hflags & MIPS_HFLAG_ERL) @@ -1122,19 +1122,19 @@ void op_mfc0_status (void) void op_mfc0_intctl (void) { - T0 = SIGN_EXTEND32(env->CP0_IntCtl); + T0 = (int32_t)env->CP0_IntCtl; RETURN(); } void op_mfc0_srsctl (void) { - T0 = SIGN_EXTEND32(env->CP0_SRSCtl); + T0 = (int32_t)env->CP0_SRSCtl; RETURN(); } void op_mfc0_cause (void) { - T0 = SIGN_EXTEND32(env->CP0_Cause); + T0 = (int32_t)env->CP0_Cause; RETURN(); } @@ -1146,7 +1146,7 @@ void op_mfc0_epc (void) void op_mfc0_prid (void) { - T0 = SIGN_EXTEND32(env->CP0_PRid); + T0 = (int32_t)env->CP0_PRid; RETURN(); } @@ -1158,25 +1158,25 @@ void op_mfc0_ebase (void) void op_mfc0_config0 (void) { - T0 = SIGN_EXTEND32(env->CP0_Config0); + T0 = (int32_t)env->CP0_Config0; RETURN(); } void op_mfc0_config1 (void) { - T0 = SIGN_EXTEND32(env->CP0_Config1); + T0 = (int32_t)env->CP0_Config1; RETURN(); } void op_mfc0_config2 (void) { - T0 = SIGN_EXTEND32(env->CP0_Config2); + T0 = (int32_t)env->CP0_Config2; RETURN(); } void op_mfc0_config3 (void) { - T0 = SIGN_EXTEND32(env->CP0_Config3); + T0 = (int32_t)env->CP0_Config3; RETURN(); } @@ -1188,13 +1188,13 @@ void op_mfc0_lladdr (void) void op_mfc0_watchlo0 (void) { - T0 = SIGN_EXTEND32(env->CP0_WatchLo); + T0 = (int32_t)env->CP0_WatchLo; RETURN(); } void op_mfc0_watchhi0 (void) { - T0 = SIGN_EXTEND32(env->CP0_WatchHi); + T0 = (int32_t)env->CP0_WatchHi; RETURN(); } @@ -1212,7 +1212,7 @@ void op_mfc0_framemask (void) void op_mfc0_debug (void) { - T0 = SIGN_EXTEND32(env->CP0_Debug); + T0 = (int32_t)env->CP0_Debug; if (env->hflags & MIPS_HFLAG_DM) T0 |= 1 << CP0DB_DM; RETURN(); @@ -1226,31 +1226,31 @@ void op_mfc0_depc (void) void op_mfc0_performance0 (void) { - T0 = SIGN_EXTEND32(env->CP0_Performance0); + T0 = (int32_t)env->CP0_Performance0; RETURN(); } void op_mfc0_taglo (void) { - T0 = SIGN_EXTEND32(env->CP0_TagLo); + T0 = (int32_t)env->CP0_TagLo; RETURN(); } void op_mfc0_datalo (void) { - T0 = SIGN_EXTEND32(env->CP0_DataLo); + T0 = (int32_t)env->CP0_DataLo; RETURN(); } void op_mfc0_taghi (void) { - T0 = SIGN_EXTEND32(env->CP0_TagHi); + T0 = (int32_t)env->CP0_TagHi; RETURN(); } void op_mfc0_datahi (void) { - T0 = SIGN_EXTEND32(env->CP0_DataHi); + T0 = (int32_t)env->CP0_DataHi; RETURN(); } @@ -1262,7 +1262,7 @@ void op_mfc0_errorepc (void) void op_mfc0_desave (void) { - T0 = SIGN_EXTEND32(env->CP0_DESAVE); + T0 = (int32_t)env->CP0_DESAVE; RETURN(); } @@ -1276,7 +1276,7 @@ void op_mtc0_entrylo0 (void) { /* Large physaddr not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo0 = T0 & SIGN_EXTEND32(0x3FFFFFFFUL); + env->CP0_EntryLo0 = T0 & (int32_t)0x3FFFFFFF; RETURN(); } @@ -1284,7 +1284,7 @@ void op_mtc0_entrylo1 (void) { /* Large physaddr not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo1 = T0 & SIGN_EXTEND32(0x3FFFFFFFUL); + env->CP0_EntryLo1 = T0 & (int32_t)0x3FFFFFFF; RETURN(); } @@ -1334,7 +1334,7 @@ void op_mtc0_entryhi (void) /* 1k pages not implemented */ /* Ignore MIPS64 TLB for now */ - val = T0 & SIGN_EXTEND32(0xFFFFE0FF); + val = T0 & (int32_t)0xFFFFE0FF; old = env->CP0_EntryHi; env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ @@ -1353,7 +1353,7 @@ void op_mtc0_status (void) { uint32_t val, old, mask; - val = T0 & SIGN_EXTEND32(0xFA78FF01); + val = T0 & (int32_t)0xFA78FF01; old = env->CP0_Status; if (T0 & (1 << CP0St_UM)) env->hflags |= MIPS_HFLAG_UM; @@ -1431,7 +1431,7 @@ void op_mtc0_ebase (void) { /* vectored interrupts not implemented */ /* Multi-CPU not implemented */ - env->CP0_EBase = SIGN_EXTEND32(0x80000000) | (T0 & 0x3FFFF000); + env->CP0_EBase = (int32_t)0x80000000 | (T0 & 0x3FFFF000); RETURN(); } @@ -1501,7 +1501,7 @@ void op_mtc0_performance0 (void) void op_mtc0_taglo (void) { - env->CP0_TagLo = T0 & SIGN_EXTEND32(0xFFFFFCF6); + env->CP0_TagLo = T0 & (int32_t)0xFFFFFCF6; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index b719f036a..a518e5ca4 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -167,8 +167,8 @@ static inline uint64_t get_HILO (void) static inline void set_HILO (uint64_t HILO) { - env->LO = SIGN_EXTEND32(HILO & 0xFFFFFFFF); - env->HI = SIGN_EXTEND32(HILO >> 32); + env->LO = (int32_t)(HILO & 0xFFFFFFFF); + env->HI = (int32_t)(HILO >> 32); } void do_mult (void) @@ -305,12 +305,12 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) /* CP0 helpers */ void do_mfc0_random (void) { - T0 = SIGN_EXTEND32(cpu_mips_get_random(env)); + T0 = (int32_t)cpu_mips_get_random(env); } void do_mfc0_count (void) { - T0 = SIGN_EXTEND32(cpu_mips_get_count(env)); + T0 = (int32_t)cpu_mips_get_count(env); } void do_mtc0_status_debug(uint32_t old, uint32_t val) @@ -433,7 +433,7 @@ static void fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb[idx]; - tlb->VPN = env->CP0_EntryHi & SIGN_EXTEND32(0xFFFFE000); + tlb->VPN = env->CP0_EntryHi & (int32_t)0xFFFFE000; tlb->ASID = env->CP0_EntryHi & 0xFF; size = env->CP0_PageMask >> 13; size = 4 * (size + 1); @@ -478,7 +478,7 @@ void do_tlbp (void) uint8_t ASID; int i; - tag = env->CP0_EntryHi & SIGN_EXTEND32(0xFFFFE000); + tag = env->CP0_EntryHi & (int32_t)0xFFFFE000; ASID = env->CP0_EntryHi & 0xFF; for (i = 0; i < MIPS_TLB_NB; i++) { tlb = &env->tlb[i]; diff --git a/target-mips/translate.c b/target-mips/translate.c index 1252e81a9..a501a178f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1420,7 +1420,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_J: case OPC_JAL: /* Jump to immediate */ - btarget = ((ctx->pc + 4) & SIGN_EXTEND32(0xF0000000)) | offset; + btarget = ((ctx->pc + 4) & (int32_t)0xF0000000) | offset; break; case OPC_JR: case OPC_JALR: @@ -4097,14 +4097,14 @@ void cpu_reset (CPUMIPSState *env) } else { env->CP0_ErrorEPC = env->PC; } - env->PC = SIGN_EXTEND32(0xBFC00000); + env->PC = (int32_t)0xBFC00000; #if defined (MIPS_USES_R4K_TLB) env->CP0_random = MIPS_TLB_NB - 1; env->tlb_in_use = MIPS_TLB_NB; #endif env->CP0_Wired = 0; /* SMP not implemented */ - env->CP0_EBase = SIGN_EXTEND32(0x80000000); + env->CP0_EBase = (int32_t)0x80000000; env->CP0_Config0 = MIPS_CONFIG0; env->CP0_Config1 = MIPS_CONFIG1; env->CP0_Config2 = MIPS_CONFIG2; -- cgit v1.2.3 From a86c8f29de76536db368714297ed13beb05ef771 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 16:49:27 +0000 Subject: Fix compiler warnings, add signed versions of some swab functions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2252 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dyngen.c b/dyngen.c index 2d93283d6..bcfb86ea0 100644 --- a/dyngen.c +++ b/dyngen.c @@ -127,10 +127,12 @@ 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 @@ -284,11 +286,21 @@ 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; @@ -397,7 +409,7 @@ void elf_swap_rel(ELF_RELOC *rel) swabls(&rel->r_offset); swabls(&rel->r_info); #ifdef ELF_USES_RELOCA - swabls(&rel->r_addend); + swablss(&rel->r_addend); #endif } @@ -505,7 +517,7 @@ int load_object(const char *filename) } sec = &shdr[ehdr.e_shstrndx]; - shstr = sdata[ehdr.e_shstrndx]; + shstr = (char *)sdata[ehdr.e_shstrndx]; /* swap relocations */ for(i = 0; i < ehdr.e_shnum; i++) { @@ -541,7 +553,7 @@ int load_object(const char *filename) strtab_sec = &shdr[symtab_sec->sh_link]; symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr]; - strtab = sdata[symtab_sec->sh_link]; + strtab = (char *)sdata[symtab_sec->sh_link]; nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); if (do_swap) { -- cgit v1.2.3 From 92190c648a0b34a46061dce5cf056a125ede731b Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 16:50:09 +0000 Subject: Silence a spurious gcc warning. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2253 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnchextile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vnchextile.h b/vnchextile.h index 16a354d60..aa575b7df 100644 --- a/vnchextile.h +++ b/vnchextile.h @@ -119,7 +119,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, for (j = 0; j < h; j++) { int has_color = 0; int min_x = -1; - pixel_t color; + pixel_t color = 0; /* shut up gcc */ for (i = 0; i < w; i++) { if (!has_color) { -- cgit v1.2.3 From d8b20157fc3054b7bc4db7bcd8530e5c7ca9a06e Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 16:50:54 +0000 Subject: Remove unused variable. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2254 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index d75c27c3e..c4b7ff5ba 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -525,7 +525,6 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, { CPUState *env; char buf[1024]; - SetIRQFunc *set_irq; m48t59_t *nvram; int PPC_io_memory; int linux_boot, i, nb_nics1, bios_size; -- cgit v1.2.3 From 416b5d366d79431d07d2dff693f4b70d679ffc42 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 17:23:49 +0000 Subject: Avoid "unused variable" compiler warning. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2255 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/smc91c111.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 1ef5b5689..0249cfe98 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -159,7 +159,6 @@ static void smc91c111_do_tx(smc91c111_state *s) int len; int control; int add_crc; - uint32_t crc; int packetnum; uint8_t *p; @@ -192,6 +191,8 @@ static void smc91c111_do_tx(smc91c111_state *s) about. */ add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0; if (add_crc) { + uint32_t crc; + crc = crc32(~0, p, len); memcpy(p + len, &crc, 4); len += 4; -- cgit v1.2.3 From 8bdc2159db1dc9eec69652a74fb503c0a1953bc2 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 17:24:45 +0000 Subject: Don't cast lvalues, fixes compiler warning. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2256 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/tcx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/tcx.c b/hw/tcx.c index 1df7d24f9..a1a6b6855 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -88,10 +88,11 @@ static void tcx_draw_line32(TCXState *s1, uint8_t *d, { int x; uint8_t val; + uint32_t *p = (uint32_t *)d; for(x = 0; x < width; x++) { val = *s++; - *((uint32_t *)d)++ = s1->palette[val]; + *p++ = s1->palette[val]; } } @@ -100,10 +101,11 @@ static void tcx_draw_line16(TCXState *s1, uint8_t *d, { int x; uint8_t val; + uint16_t *p = (uint16_t *)d; for(x = 0; x < width; x++) { val = *s++; - *((uint16_t *)d)++ = s1->palette[val]; + *p++ = s1->palette[val]; } } -- cgit v1.2.3 From eaf7e70b014464294ce9622dc47b0f17a099fbb7 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 19:10:59 +0000 Subject: Enable TCP_NODELAY, by Daniel Jacobowitz. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2257 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/tcp.h | 2 +- slirp/tcp_subr.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/slirp/tcp.h b/slirp/tcp.h index cd7e89110..0cd3ab3a4 100644 --- a/slirp/tcp.h +++ b/slirp/tcp.h @@ -112,7 +112,7 @@ struct tcphdr { /* * User-settable options (used with setsockopt). */ -/* #define TCP_NODELAY 0x01 */ /* don't delay send to coalesce packets */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ /* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ /* diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index e66987eea..2526bffc6 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -499,6 +499,8 @@ tcp_connect(inso) setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); opt = 1; setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int)); so->so_fport = addr.sin_port; so->so_faddr = addr.sin_addr; -- cgit v1.2.3 From 1cb6c3fd3815c4a5aa3ec1fb6ff291e64b8baf8e Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 19:14:11 +0000 Subject: Fix "inaccessible boot device" on FreeBSD, by Juergen Lock. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2258 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block-raw.c b/block-raw.c index 3a2843c5d..e6cc31aff 100644 --- a/block-raw.c +++ b/block-raw.c @@ -51,6 +51,9 @@ #include #include #endif +#ifdef __FreeBSD__ +#include +#endif //#define DEBUG_FLOPPY -- cgit v1.2.3 From ffd843bcdc46768f26507f0889c92f4bda287986 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Dec 2006 19:46:43 +0000 Subject: Run monitor over unix domain sockets, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2259 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 5 +++ qemu_socket.h | 1 + vl.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 102 insertions(+), 19 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index c3e6cb2eb..89b79d83d 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -586,6 +586,11 @@ MAGIC_SYSRQ sequence if you use a telnet that supports sending the break sequence. Typically in unix telnet you do it with Control-] and then type "send break" followed by pressing the enter key. +@item unix:path[,server][,nowait] +A unix domain socket is used instead of a tcp socket. The option works the +same as if you had specified @code{-serial tcp} except the unix domain socket +@var{path} is used for connections. + @end table @item -parallel dev diff --git a/qemu_socket.h b/qemu_socket.h index 64b7d4e5e..6e8bcce6c 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -19,6 +19,7 @@ #include #include #include +#include #define socket_error() errno #define closesocket(s) close(s) diff --git a/vl.c b/vl.c index 5b5f25afd..5c379c290 100644 --- a/vl.c +++ b/vl.c @@ -2206,6 +2206,7 @@ static void udp_chr_add_read_handler(CharDriverState *chr, } int parse_host_port(struct sockaddr_in *saddr, const char *str); +int parse_unix_path(struct sockaddr_un *uaddr, const char *str); int parse_host_src_port(struct sockaddr_in *haddr, struct sockaddr_in *saddr, const char *str); @@ -2270,6 +2271,7 @@ typedef struct { int connected; int max_size; int do_telnetopt; + int is_unix; } TCPCharDriver; static void tcp_chr_accept(void *opaque); @@ -2291,6 +2293,8 @@ static int tcp_chr_read_poll(void *opaque) TCPCharDriver *s = chr->opaque; if (!s->connected) return 0; + if (!s->fd_can_read) + return 0; s->max_size = s->fd_can_read(s->fd_opaque); return s->max_size; } @@ -2416,12 +2420,25 @@ static void tcp_chr_accept(void *opaque) CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; struct sockaddr_in saddr; +#ifndef _WIN32 + struct sockaddr_un uaddr; +#endif + struct sockaddr *addr; socklen_t len; int fd; for(;;) { - len = sizeof(saddr); - fd = accept(s->listen_fd, (struct sockaddr *)&saddr, &len); +#ifndef _WIN32 + if (s->is_unix) { + len = sizeof(uaddr); + addr = (struct sockaddr *)&uaddr; + } else +#endif + { + len = sizeof(saddr); + addr = (struct sockaddr *)&saddr; + } + fd = accept(s->listen_fd, addr, &len); if (fd < 0 && errno != EINTR) { return; } else if (fd >= 0) { @@ -2447,7 +2464,8 @@ static void tcp_chr_close(CharDriverState *chr) } static CharDriverState *qemu_chr_open_tcp(const char *host_str, - int is_telnet) + int is_telnet, + int is_unix) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; @@ -2456,9 +2474,26 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, int is_waitconnect = 1; const char *ptr; struct sockaddr_in saddr; +#ifndef _WIN32 + struct sockaddr_un uaddr; +#endif + struct sockaddr *addr; + socklen_t addrlen; - if (parse_host_port(&saddr, host_str) < 0) - goto fail; +#ifndef _WIN32 + if (is_unix) { + addr = (struct sockaddr *)&uaddr; + addrlen = sizeof(uaddr); + if (parse_unix_path(&uaddr, host_str) < 0) + goto fail; + } else +#endif + { + addr = (struct sockaddr *)&saddr; + addrlen = sizeof(saddr); + if (parse_host_port(&saddr, host_str) < 0) + goto fail; + } ptr = host_str; while((ptr = strchr(ptr,','))) { @@ -2481,8 +2516,14 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, s = qemu_mallocz(sizeof(TCPCharDriver)); if (!s) goto fail; - - fd = socket(PF_INET, SOCK_STREAM, 0); + +#ifndef _WIN32 + if (is_unix) + fd = socket(PF_UNIX, SOCK_STREAM, 0); + else +#endif + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) goto fail; @@ -2492,24 +2533,43 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, s->connected = 0; s->fd = -1; s->listen_fd = -1; + s->is_unix = is_unix; + + chr->opaque = s; + chr->chr_write = tcp_chr_write; + chr->chr_add_read_handler = tcp_chr_add_read_handler; + chr->chr_close = tcp_chr_close; + if (is_listen) { /* allow fast reuse */ - val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); +#ifndef _WIN32 + if (is_unix) { + char path[109]; + strncpy(path, uaddr.sun_path, 108); + path[108] = 0; + unlink(path); + } else +#endif + { + val = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); + } - ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) + ret = bind(fd, addr, addrlen); + if (ret < 0) goto fail; + ret = listen(fd, 0); if (ret < 0) goto fail; + s->listen_fd = fd; qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); if (is_telnet) s->do_telnetopt = 1; } else { for(;;) { - ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + ret = connect(fd, addr, addrlen); if (ret < 0) { err = socket_error(); if (err == EINTR || err == EWOULDBLOCK) { @@ -2530,10 +2590,6 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr); } - chr->opaque = s; - chr->chr_write = tcp_chr_write; - chr->chr_add_read_handler = tcp_chr_add_read_handler; - chr->chr_close = tcp_chr_close; if (is_listen && is_waitconnect) { printf("QEMU waiting for connection on: %s\n", host_str); tcp_chr_accept(chr); @@ -2559,16 +2615,18 @@ CharDriverState *qemu_chr_open(const char *filename) return qemu_chr_open_null(); } else if (strstart(filename, "tcp:", &p)) { - return qemu_chr_open_tcp(p, 0); + return qemu_chr_open_tcp(p, 0, 0); } else if (strstart(filename, "telnet:", &p)) { - return qemu_chr_open_tcp(p, 1); + return qemu_chr_open_tcp(p, 1, 0); } else if (strstart(filename, "udp:", &p)) { return qemu_chr_open_udp(p); } else #ifndef _WIN32 - if (strstart(filename, "file:", &p)) { + if (strstart(filename, "unix:", &p)) { + return qemu_chr_open_tcp(p, 0, 1); + } else if (strstart(filename, "file:", &p)) { return qemu_chr_open_file_out(p); } else if (strstart(filename, "pipe:", &p)) { return qemu_chr_open_pipe(p); @@ -2743,6 +2801,24 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str) return 0; } +int parse_unix_path(struct sockaddr_un *uaddr, const char *str) +{ + const char *p; + int len; + + len = MIN(108, strlen(str)); + p = strchr(str, ','); + if (p) + len = MIN(len, p - str); + + memset(uaddr, 0, sizeof(*uaddr)); + + uaddr->sun_family = AF_UNIX; + memcpy(uaddr->sun_path, str, len); + + return 0; +} + /* find or alloc a new VLAN */ VLANState *qemu_find_vlan(int id) { @@ -6955,6 +7031,7 @@ int main(int argc, char **argv) vm_start(); } } + main_loop(); quit_timers(); return 0; -- cgit v1.2.3 From 73fc97427b6410b9ebd38b8d88831be050ce189b Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 02:09:07 +0000 Subject: Unix domain socket support for VNC, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2260 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 13 ++++++--- vl.c | 10 +++---- vl.h | 2 +- vnc.c | 86 +++++++++++++++++++++++++++++++++++++++++------------------ 4 files changed, 74 insertions(+), 37 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 89b79d83d..ea4d2e63a 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -247,14 +247,21 @@ command line application. The emulated serial port is redirected on the console. Therefore, you can still use QEMU to debug a Linux kernel with a serial console. -@item -vnc d +@item -vnc display Normally, QEMU uses SDL to display the VGA output. With this option, -you can have QEMU listen on VNC display @var{d} and redirect the VGA +you can have QEMU listen on VNC display @var{display} and redirect the VGA display over the VNC session. It is very useful to enable the usb tablet device when using this option (option @option{-usbdevice tablet}). When using the VNC display, you must use the @option{-k} -option to set the keyboard layout. +option to set the keyboard layout if you are not using en-us. + +@var{display} may be in the form @var{interface:d}, in which case connections +will only be allowed from @var{interface} on display @var{d}. Optionally, +@var{interface} can be omitted. @var{display} can also be in the form +@var{unix:path} where @var{path} is the location of a unix socket to listen for +connections on. + @item -k language diff --git a/vl.c b/vl.c index 5c379c290..929d2a938 100644 --- a/vl.c +++ b/vl.c @@ -152,7 +152,7 @@ int win2k_install_hack = 0; int usb_enabled = 0; static VLANState *first_vlan; int smp_cpus = 1; -int vnc_display = -1; +const char *vnc_display; #if defined(TARGET_SPARC) #define MAX_CPUS 16 #elif defined(TARGET_I386) @@ -6818,11 +6818,7 @@ int main(int argc, char **argv) } break; case QEMU_OPTION_vnc: - vnc_display = atoi(optarg); - if (vnc_display < 0) { - fprintf(stderr, "Invalid VNC display\n"); - exit(1); - } + vnc_display = optarg; break; case QEMU_OPTION_no_acpi: acpi_enabled = 0; @@ -6946,7 +6942,7 @@ int main(int argc, char **argv) /* terminal init */ if (nographic) { dumb_display_init(ds); - } else if (vnc_display != -1) { + } else if (vnc_display != NULL) { vnc_display_init(ds, vnc_display); } else { #if defined(CONFIG_SDL) diff --git a/vl.h b/vl.h index 3847170d9..52957f624 100644 --- a/vl.h +++ b/vl.h @@ -867,7 +867,7 @@ void sdl_display_init(DisplayState *ds, int full_screen); void cocoa_display_init(DisplayState *ds, int full_screen); /* vnc.c */ -void vnc_display_init(DisplayState *ds, int display); +void vnc_display_init(DisplayState *ds, const char *display); /* ide.c */ #define MAX_DISKS 4 diff --git a/vnc.c b/vnc.c index 92e48c56e..d3371671f 100644 --- a/vnc.c +++ b/vnc.c @@ -1101,10 +1101,18 @@ static void vnc_listen_read(void *opaque) } } -void vnc_display_init(DisplayState *ds, int display) +extern int parse_host_port(struct sockaddr_in *saddr, const char *str); + +void vnc_display_init(DisplayState *ds, const char *arg) { - struct sockaddr_in addr; + struct sockaddr *addr; + struct sockaddr_in iaddr; +#ifndef _WIN32 + struct sockaddr_un uaddr; +#endif int reuse_addr, ret; + socklen_t addrlen; + const char *p; VncState *vs; vs = qemu_mallocz(sizeof(VncState)); @@ -1126,25 +1134,60 @@ void vnc_display_init(DisplayState *ds, int display) if (!vs->kbd_layout) exit(1); - vs->lsock = socket(PF_INET, SOCK_STREAM, 0); - if (vs->lsock == -1) { - fprintf(stderr, "Could not create socket\n"); - exit(1); - } + vs->ds->data = NULL; + vs->ds->dpy_update = vnc_dpy_update; + vs->ds->dpy_resize = vnc_dpy_resize; + vs->ds->dpy_refresh = vnc_dpy_refresh; + + memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); - addr.sin_family = AF_INET; - addr.sin_port = htons(5900 + display); - memset(&addr.sin_addr, 0, sizeof(addr.sin_addr)); + vnc_dpy_resize(vs->ds, 640, 400); - reuse_addr = 1; - ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, - (const char *)&reuse_addr, sizeof(reuse_addr)); - if (ret == -1) { - fprintf(stderr, "setsockopt() failed\n"); - exit(1); +#ifndef _WIN32 + if (strstart(arg, "unix:", &p)) { + addr = (struct sockaddr *)&uaddr; + addrlen = sizeof(uaddr); + + vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0); + if (vs->lsock == -1) { + fprintf(stderr, "Could not create socket\n"); + exit(1); + } + + uaddr.sun_family = AF_UNIX; + memset(uaddr.sun_path, 0, 108); + snprintf(uaddr.sun_path, 108, "%s", p); + + unlink(uaddr.sun_path); + } else +#endif + { + addr = (struct sockaddr *)&iaddr; + addrlen = sizeof(iaddr); + + vs->lsock = socket(PF_INET, SOCK_STREAM, 0); + if (vs->lsock == -1) { + fprintf(stderr, "Could not create socket\n"); + exit(1); + } + + if (parse_host_port(&iaddr, arg) < 0) { + fprintf(stderr, "Could not parse VNC address\n"); + exit(1); + } + + iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); + + reuse_addr = 1; + ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, + (const char *)&reuse_addr, sizeof(reuse_addr)); + if (ret == -1) { + fprintf(stderr, "setsockopt() failed\n"); + exit(1); + } } - if (bind(vs->lsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + if (bind(vs->lsock, addr, addrlen) == -1) { fprintf(stderr, "bind() failed\n"); exit(1); } @@ -1158,13 +1201,4 @@ void vnc_display_init(DisplayState *ds, int display) if (ret == -1) { exit(1); } - - vs->ds->data = NULL; - vs->ds->dpy_update = vnc_dpy_update; - vs->ds->dpy_resize = vnc_dpy_resize; - vs->ds->dpy_refresh = vnc_dpy_refresh; - - memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); - - vnc_dpy_resize(vs->ds, 640, 400); } -- cgit v1.2.3 From 71e3ceb800ec212acd78f613245bbb82278348d0 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 02:11:31 +0000 Subject: Daemonize option, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2261 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 6 +++++ vl.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index ea4d2e63a..6796aeb6d 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -309,6 +309,12 @@ Start in full screen. Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. +@item -daemonize +Daemonize the QEMU process after initialization. QEMU will not detach from +standard IO until it is ready to receive connections on any of its devices. +This option is a useful way for external programs to launch QEMU without having +to cope with initialization race conditions. + @item -win2k-hack Use it when installing Windows 2000 to avoid a disk full bug. After Windows 2000 is installed, you no longer need this option (this option diff --git a/vl.c b/vl.c index 929d2a938..c56c87cfe 100644 --- a/vl.c +++ b/vl.c @@ -163,6 +163,7 @@ const char *vnc_display; int acpi_enabled = 1; int fd_bootchk = 1; int no_reboot = 0; +int daemonize = 0; /***********************************************************/ /* x86 ISA bus support */ @@ -6018,6 +6019,9 @@ void help(void) "-no-reboot exit instead of rebooting\n" "-loadvm file start right away with a saved state (loadvm in monitor)\n" "-vnc display start a VNC server on display\n" +#ifndef _WIN32 + "-daemonize daemonize QEMU after initializing\n" +#endif "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -6098,6 +6102,7 @@ enum { QEMU_OPTION_vnc, QEMU_OPTION_no_acpi, QEMU_OPTION_no_reboot, + QEMU_OPTION_daemonize, }; typedef struct QEMUOption { @@ -6178,6 +6183,7 @@ const QEMUOption qemu_options[] = { { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "no-reboot", 0, QEMU_OPTION_no_reboot }, + { "daemonize", 0, QEMU_OPTION_daemonize }, { NULL }, }; @@ -6408,6 +6414,7 @@ int main(int argc, char **argv) QEMUMachine *machine; char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; + int fds[2]; LIST_INIT (&vm_change_state_head); #ifndef _WIN32 @@ -6826,10 +6833,61 @@ int main(int argc, char **argv) case QEMU_OPTION_no_reboot: no_reboot = 1; break; + case QEMU_OPTION_daemonize: + daemonize = 1; + break; } } } +#ifndef _WIN32 + if (daemonize && !nographic && vnc_display == NULL) { + fprintf(stderr, "Can only daemonize if using -nographic or -vnc\n"); + daemonize = 0; + } + + if (daemonize) { + pid_t pid; + + if (pipe(fds) == -1) + exit(1); + + pid = fork(); + if (pid > 0) { + uint8_t status; + ssize_t len; + + close(fds[1]); + + again: + len = read(fds[0], &status, 1); + if (len == -1 && (errno == EINTR)) + goto again; + + if (len != 1 || status != 0) + exit(1); + else + exit(0); + } else if (pid < 0) + exit(1); + + setsid(); + + pid = fork(); + if (pid > 0) + exit(0); + else if (pid < 0) + exit(1); + + umask(027); + chdir("/"); + + signal(SIGTSTP, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + } +#endif + #ifdef USE_KQEMU if (smp_cpus > 1) kqemu_allowed = 0; @@ -7028,6 +7086,30 @@ int main(int argc, char **argv) } } + if (daemonize) { + uint8_t status = 0; + ssize_t len; + int fd; + + again1: + len = write(fds[1], &status, 1); + if (len == -1 && (errno == EINTR)) + goto again1; + + if (len != 1) + exit(1); + + fd = open("/dev/null", O_RDWR); + if (fd == -1) + exit(1); + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + close(fd); + } + main_loop(); quit_timers(); return 0; -- cgit v1.2.3 From bd491d6a4ecc57144ffa55c0daf97b43bc1648ce Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 02:14:49 +0000 Subject: Fix CDROM change, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2262 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index 6741cac1f..68ad718d0 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1481,6 +1481,17 @@ static void ide_atapi_cmd(IDEState *s) } } +/* called when the inserted state of the media has changed */ +static void cdrom_change_cb(void *opaque) +{ + IDEState *s = opaque; + int64_t nb_sectors; + + /* XXX: send interrupt too */ + bdrv_get_geometry(s->bs, &nb_sectors); + s->nb_sectors = nb_sectors; +} + static void ide_cmd_lba48_transform(IDEState *s, int lba48) { s->lba48 = lba48; @@ -2111,6 +2122,7 @@ static void ide_init2(IDEState *ide_state, } if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { s->is_cdrom = 1; + bdrv_set_change_cb(s->bs, cdrom_change_cb, s); } } s->drive_serial = drive_serial++; -- cgit v1.2.3 From fef3074347c02ed0c2fd9d1918402c966b909466 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 14:11:32 +0000 Subject: Escape filname printout properly, by Anthony Liguori and Julian Seward. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2263 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 9 ++++++--- monitor.c | 27 +++++++++++++++++++++++++++ qemu-img.c | 5 +++++ vl.h | 1 + 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index fdaba4bca..9aebaa0a4 100644 --- a/block.c +++ b/block.c @@ -868,9 +868,12 @@ void bdrv_info(void) term_printf(" locked=%d", bs->locked); } if (bs->drv) { - term_printf(" file=%s", bs->filename); - if (bs->backing_file[0] != '\0') - term_printf(" backing_file=%s", bs->backing_file); + 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) diff --git a/monitor.c b/monitor.c index f2a2417dd..d553ce607 100644 --- a/monitor.c +++ b/monitor.c @@ -106,6 +106,33 @@ void term_printf(const char *fmt, ...) va_end(ap); } +void term_print_filename(const char *filename) +{ + int i; + + for (i = 0; filename[i]; i++) { + switch (filename[i]) { + case ' ': + case '"': + case '\\': + term_printf("\\%c", filename[i]); + break; + case '\t': + term_printf("\\t"); + break; + case '\r': + term_printf("\\r"); + break; + case '\n': + term_printf("\\n"); + break; + default: + term_printf("%c", filename[i]); + break; + } + } +} + static int monitor_fprintf(FILE *stream, const char *fmt, ...) { va_list ap; diff --git a/qemu-img.c b/qemu-img.c index 8b8da0565..23a698db7 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -113,6 +113,11 @@ void term_printf(const char *fmt, ...) va_end(ap); } +void term_print_filename(const char *filename) +{ + term_printf(filename); +} + void __attribute__((noreturn)) error(const char *fmt, ...) { va_list ap; diff --git a/vl.h b/vl.h index 52957f624..5f13dcd7d 100644 --- a/vl.h +++ b/vl.h @@ -1318,6 +1318,7 @@ void monitor_init(CharDriverState *hd, int show_banner); void term_puts(const char *str); void term_vprintf(const char *fmt, va_list ap); void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +void term_print_filename(const char *filename); void term_flush(void); void term_print_help(void); void monitor_readline(const char *prompt, int is_password, -- cgit v1.2.3 From 62ee021121dea0b08b7e2f7c741cb417fc392bb2 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 14:19:53 +0000 Subject: Build fix for AIO (-dummy) on Windows, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2264 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block-raw.c b/block-raw.c index e6cc31aff..9f4a0a1d2 100644 --- a/block-raw.c +++ b/block-raw.c @@ -1137,6 +1137,10 @@ void qemu_aio_poll(void) { } +void qemu_aio_flush(void) +{ +} + void qemu_aio_wait_start(void) { } -- cgit v1.2.3 From 42550fde7e16ac040fbd391bb2c65c3f5fa08d60 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 16:34:12 +0000 Subject: SCSI emulation improvements, by Chuck Brazie. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2265 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 26 ++--- qemu-doc.texi | 8 +- vl.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- vl.h | 21 ++++ 4 files changed, 343 insertions(+), 59 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 77a6467c7..70be34624 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -688,23 +688,21 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); } -#if 0 - /* ??? Need to figure out some way for the user to - specify SCSI devices. */ if (pci_enabled) { void *scsi; - BlockDriverState *bdrv; - - scsi = lsi_scsi_init(pci_bus, -1); - bdrv = bdrv_new("scsidisk"); - bdrv_open(bdrv, "scsi_disk.img", 0); - lsi_scsi_attach(scsi, bdrv, -1); - bdrv = bdrv_new("scsicd"); - bdrv_open(bdrv, "scsi_cd.iso", 0); - bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); - lsi_scsi_attach(scsi, bdrv, -1); + + if (scsi_hba_lsi > 0) { + if (!(scsi = lsi_scsi_init(pci_bus, -1))) { + exit(1); + } + for(i = 0; i < MAX_SCSI_DISKS; i++) { + if (scsi_disks_info[i].adapter == SCSI_LSI_53C895A && + scsi_disks_info[i].device_type != SCSI_NONE) { + lsi_scsi_attach(scsi, bs_scsi_table[i], scsi_disks_info[i].id); + } + } + } } -#endif } static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, diff --git a/qemu-doc.texi b/qemu-doc.texi index 6796aeb6d..9b9df3305 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -223,10 +223,16 @@ using @file{/dev/cdrom} as filename (@pxref{host_drives}). Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is the default. +@item -disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] +Use @var{file} as the IDE disk/CD-ROM image. The defaults are: hdx=a,type=disk + +@item -disk scsi,img=file[,sdx=a..g][,type=disk|cdrom][,id=n] +Use @var{file} as the SCSI disk/CD-ROM image. The defaults are: sdx=a,type=disk,id='auto assign' + @item -snapshot Write to temporary files instead of disk image files. In this case, the raw disk image you use is not written back. You can however force -the write back by pressing @key{C-a s} (@pxref{disk_images}). +the write back by pressing @key{C-a s} (@pxref{disk_images}). @item -no-fd-bootchk Disable boot signature checking for floppy disks in Bochs BIOS. It may diff --git a/vl.c b/vl.c index c56c87cfe..bdd46c328 100644 --- a/vl.c +++ b/vl.c @@ -109,6 +109,8 @@ /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 +#define DISK_OPTIONS_SIZE 256 + const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; void *ioport_opaque[MAX_IOPORTS]; @@ -119,6 +121,9 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; +BlockDriverState *bs_scsi_table[MAX_SCSI_DISKS]; +SCSIDiskInfo scsi_disks_info[MAX_SCSI_DISKS]; +int scsi_hba_lsi; /* Count of scsi disks/cdrom using this lsi adapter */ int vga_ram_size; int bios_size; static DisplayState display_state; @@ -3814,7 +3819,172 @@ void do_info_network(void) term_printf(" %s\n", vc->info_str); } } - + +/* Parse IDE and SCSI disk options */ +static int disk_options_init(int num_ide_disks, + char ide_disk_options[][DISK_OPTIONS_SIZE], + int snapshot, + int num_scsi_disks, + char scsi_disk_options[][DISK_OPTIONS_SIZE], + int cdrom_index, + int cyls, + int heads, + int secs, + int translation) +{ + char buf[256]; + char dev_name[64]; + int id, i, j; + int cdrom_device; + int ide_cdrom_created = 0; + int scsi_index; + scsi_host_adapters temp_adapter; + + /* Process any IDE disks/cdroms */ + for (i=0; i< num_ide_disks; i++) { + for (j=0; j= 0 && (!ide_cdrom_created)) { + bs_table[cdrom_index] = bdrv_new("cdrom"); + bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); + } + + for(i = 0; i < num_scsi_disks; i++) { + + temp_adapter = SCSI_LSI_53C895A; + scsi_hba_lsi++; + + /*Check for sdx= parameter */ + if (get_param_value(buf, sizeof(buf), "sdx", scsi_disk_options[i])) { + if (buf[0] >= 'a' && buf[0] <= 'g') { + scsi_index = buf[0] - 'a'; + } else{ + fprintf(stderr, "qemu: sdx= option for SCSI must be one letter from a-g. %s \n",buf); + exit(1); + } + } else { + scsi_index = 0; + } + + /* Check for SCSI id specified. */ + if (get_param_value(buf, sizeof(buf),"id",scsi_disk_options[i])) { + id = strtol(buf, NULL, 0); + if (id < 0 || id > 6) { + fprintf(stderr, "qemu: SCSI id must be from 0-6: %d\n", id); + return -1; + } + /* Check if id already used */ + for(j = 0; j < MAX_SCSI_DISKS; j++) { + if (scsi_disks_info[j].device_type != SCSI_NONE && + j != i && + scsi_disks_info[j].adapter == temp_adapter && + scsi_disks_info[j].id == id ) { + fprintf(stderr, "qemu: SCSI id already used: %u\n", id); + return -1; + } + } + } else { + id = -1; + } + scsi_disks_info[i].adapter = temp_adapter; + scsi_disks_info[i].id = id; + + if (get_param_value(buf, sizeof(buf),"type",scsi_disk_options[i])) { + if (!strcmp(buf, "disk")) { + cdrom_device = 0; + } else if (!strcmp(buf, "cdrom")) { + cdrom_device = 1; + } else { + fprintf(stderr, "qemu: invalid SCSI disk type= value: %s\n", buf); + return -1; + } + } else { + cdrom_device = 0; + } + + if (cdrom_device) { + snprintf(dev_name, sizeof(buf), "cdrom%c", scsi_index); + scsi_disks_info[scsi_index].device_type = SCSI_CDROM; + } else { + snprintf(dev_name, sizeof(buf), "sd%c", scsi_index + 'a'); + scsi_disks_info[scsi_index].device_type = SCSI_DISK; + } + + if (!(bs_scsi_table[scsi_index] = bdrv_new(dev_name))) { + fprintf(stderr, "qemu: unable to create new block device for:%s\n",dev_name); + return -1; + } + + /* Get image filename from options and then try to open it */ + if (get_param_value(buf, sizeof(buf),"img",scsi_disk_options[i])) { + if (bdrv_open(bs_scsi_table[scsi_index], buf, 0) < 0) { + fprintf(stderr, "qemu: could not open SCSI disk image img='%s'\n",buf); + return -1; + } + } else { + fprintf(stderr, "qemu: SCSI disk image not specified for sd%c \n", i + 'a'); + return -1; + } + } + + return 0; +} + + /***********************************************************/ /* USB devices */ @@ -5923,6 +6093,10 @@ void help(void) "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" + "-disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] \n" + " defaults are: hdx=a,type=disk \n" + "-disk scsi,img=file[,sdx=a..g][,type=disk|cdrom][,id=n] \n" + " defaults are: sdx=a,type=disk,id='auto assign' \n" "-snapshot write to temporary files instead of disk image files\n" #ifdef CONFIG_SDL "-no-quit disable SDL window close capability\n" @@ -6103,6 +6277,7 @@ enum { QEMU_OPTION_no_acpi, QEMU_OPTION_no_reboot, QEMU_OPTION_daemonize, + QEMU_OPTION_disk, }; typedef struct QEMUOption { @@ -6177,6 +6352,7 @@ const QEMUOption qemu_options[] = { { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, { "vnc", HAS_ARG, QEMU_OPTION_vnc }, + { "disk", HAS_ARG, QEMU_OPTION_disk }, /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, @@ -6395,7 +6571,11 @@ int main(int argc, char **argv) int i, cdrom_index; int snapshot, linux_boot; const char *initrd_filename; - const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; + const char *fd_filename[MAX_FD]; + char scsi_options[MAX_SCSI_DISKS] [DISK_OPTIONS_SIZE]; + char ide_options[MAX_DISKS] [DISK_OPTIONS_SIZE]; + int num_ide_disks; + int num_scsi_disks; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; @@ -6450,10 +6630,19 @@ int main(int argc, char **argv) register_machines(); machine = first_machine; initrd_filename = NULL; + for(i = 0; i < MAX_SCSI_DISKS; i++) { + scsi_disks_info[i].device_type = SCSI_NONE; + bs_scsi_table[i] = NULL; + } + + num_ide_disks = 0; + num_scsi_disks = 0; + for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; - for(i = 0; i < MAX_DISKS; i++) - hd_filename[i] = NULL; + for(i = 0; i < MAX_DISKS; i++) { + ide_options[i][0] = '\0'; + } ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; @@ -6497,7 +6686,16 @@ int main(int argc, char **argv) break; r = argv[optind]; if (r[0] != '-') { - hd_filename[0] = argv[optind++]; + + /* Build new disk IDE syntax string */ + pstrcpy(ide_options[0], + 14, + "hdx=a,img="); + /*Add on image filename */ + pstrcpy(&(ide_options[0][13]), + sizeof(ide_options[0])-13, + argv[optind++]); + num_ide_disks++; } else { const QEMUOption *popt; @@ -6547,10 +6745,75 @@ int main(int argc, char **argv) case QEMU_OPTION_hdd: { int hd_index; + const char newIDE_DiskSyntax [][10] = { + "hdx=a,img=", "hdx=b,img=", "hdx=c,img=", "hdx=d,img=" }; + hd_index = popt->index - QEMU_OPTION_hda; - hd_filename[hd_index] = optarg; - if (hd_index == cdrom_index) - cdrom_index = -1; + if (num_ide_disks >= MAX_DISKS){ + fprintf(stderr, "qemu: too many IDE disks defined.\n"); + exit(1); + } + /* Build new disk IDE syntax string */ + pstrcpy(ide_options[hd_index], + 11, + newIDE_DiskSyntax[hd_index]); + /* Add on image filename */ + pstrcpy(&(ide_options[hd_index][10]), + sizeof(ide_options[0])-10, + optarg); + num_ide_disks++; + } + break; + case QEMU_OPTION_disk: /*Combined IDE and SCSI, for disk and CDROM */ + { + const char *p_input_char; + char *p_output_string; + char device[64]; + int disk_index; + + p_input_char = optarg; + p_output_string = device; + while (*p_input_char != '\0' && *p_input_char != ',') { + if ((p_output_string - device) < sizeof(device) - 1) + *p_output_string++ = *p_input_char; + p_input_char++; + } + *p_output_string = '\0'; + if (*p_input_char == ',') + p_input_char++; + + if (!strcmp(device, "scsi")) { + if (num_scsi_disks >= MAX_SCSI_DISKS) { + fprintf(stderr, "qemu: too many SCSI disks defined.\n"); + exit(1); + } + pstrcpy(scsi_options[num_scsi_disks], + sizeof(scsi_options[0]), + p_input_char); + num_scsi_disks++; + } else if (!strcmp(device,"ide")) { + if (num_ide_disks >= MAX_DISKS) { + fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); + exit(1); + } + disk_index = 0; /* default is hda */ + if (get_param_value(device, sizeof(device),"hdx",p_input_char)) { + if (device[0] >= 'a' && device[0] <= 'd') { + disk_index = device[0] - 'a'; + } else { + fprintf(stderr, "qemu: invalid IDE disk hdx= value: %s\n", device); + return -1; + } + } + else disk_index=0; + pstrcpy(ide_options[disk_index], + sizeof(ide_options[0]), + p_input_char); + num_ide_disks++; + } else { + fprintf(stderr, "qemu: -disk option must specify IDE or SCSI: %s \n",device); + exit(1); + } } break; case QEMU_OPTION_snapshot: @@ -6604,8 +6867,22 @@ int main(int argc, char **argv) kernel_cmdline = optarg; break; case QEMU_OPTION_cdrom: - if (cdrom_index >= 0) { - hd_filename[cdrom_index] = optarg; + { + char buf[24]; + if (num_ide_disks >= MAX_DISKS) { + fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); + exit(1); + } + snprintf(buf, sizeof(buf), "type=cdrom,hdx=%c,img=", cdrom_index + 'a'); + /* Build new disk IDE syntax string */ + pstrcpy(ide_options[cdrom_index], + 25, + buf); + /* Add on image filename */ + pstrcpy(&(ide_options[cdrom_index][24]), + sizeof(ide_options[0])-24, + optarg); + num_ide_disks++; } break; case QEMU_OPTION_boot: @@ -6893,20 +7170,11 @@ int main(int argc, char **argv) kqemu_allowed = 0; #endif linux_boot = (kernel_filename != NULL); - - if (!linux_boot && - hd_filename[0] == '\0' && - (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && + + if (!linux_boot && + num_ide_disks == 0 && fd_filename[0] == '\0') help(); - - /* boot to cd by default if no hard disk */ - if (hd_filename[0] == '\0' && boot_device == 'c') { - if (fd_filename[0] != '\0') - boot_device = 'a'; - else - boot_device = 'd'; - } setvbuf(stdout, NULL, _IOLBF, 0); @@ -6942,31 +7210,22 @@ int main(int argc, char **argv) exit(1); } - /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); - if (cdrom_index >= 0) { - bs_table[cdrom_index] = bdrv_new("cdrom"); - bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); + + /* open the virtual block devices, disks or CDRoms */ + if (disk_options_init(num_ide_disks,ide_options,snapshot, + num_scsi_disks,scsi_options, + cdrom_index, + cyls, heads, secs, translation)){ + exit(1); } - /* open the virtual block devices */ - for(i = 0; i < MAX_DISKS; i++) { - if (hd_filename[i]) { - if (!bs_table[i]) { - char buf[64]; - snprintf(buf, sizeof(buf), "hd%c", i + 'a'); - bs_table[i] = bdrv_new(buf); - } - if (bdrv_open(bs_table[i], hd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { - fprintf(stderr, "qemu: could not open hard disk image '%s'\n", - hd_filename[i]); - exit(1); - } - if (i == 0 && cyls != 0) { - bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); - bdrv_set_translation_hint(bs_table[i], translation); - } - } + /* boot to floppy or default cd if no hard disk */ + if (num_ide_disks == 0 && boot_device == 'c') { + if (fd_filename[0] != '\0') + boot_device = 'a'; + else + boot_device = 'd'; } /* we always create at least one floppy disk */ diff --git a/vl.h b/vl.h index 5f13dcd7d..d3c56d4ce 100644 --- a/vl.h +++ b/vl.h @@ -1222,9 +1222,30 @@ int scsi_write_data(SCSIDevice *s, uint32_t tag); void scsi_cancel_io(SCSIDevice *s, uint32_t tag); uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); +enum scsi_host_adapters { + SCSI_LSI_53C895A +}; +enum scsi_devices { + SCSI_CDROM, + SCSI_DISK, + SCSI_NONE +}; +typedef enum scsi_host_adapters scsi_host_adapters; +typedef enum scsi_devices scsi_devices; +typedef struct SCSIDiskInfo { + scsi_host_adapters adapter; + int id; + scsi_devices device_type; +} SCSIDiskInfo; + +#define MAX_SCSI_DISKS 7 +extern BlockDriverState *bs_scsi_table[MAX_SCSI_DISKS]; +extern SCSIDiskInfo scsi_disks_info[MAX_SCSI_DISKS]; + /* lsi53c895a.c */ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *lsi_scsi_init(PCIBus *bus, int devfn); +extern int scsi_hba_lsi; // Count of scsi disks/cdrom using this lsi adapter /* integratorcp.c */ extern QEMUMachine integratorcp926_machine; -- cgit v1.2.3 From c032e2a98c1c23bdd281ebf0aa4593e87813e1e0 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 17:29:05 +0000 Subject: Fix -cdrom breakage. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2266 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index bdd46c328..7e161c69c 100644 --- a/vl.c +++ b/vl.c @@ -6749,7 +6749,7 @@ int main(int argc, char **argv) "hdx=a,img=", "hdx=b,img=", "hdx=c,img=", "hdx=d,img=" }; hd_index = popt->index - QEMU_OPTION_hda; - if (num_ide_disks >= MAX_DISKS){ + if (num_ide_disks >= MAX_DISKS) { fprintf(stderr, "qemu: too many IDE disks defined.\n"); exit(1); } @@ -6868,7 +6868,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_cdrom: { - char buf[24]; + char buf[22]; if (num_ide_disks >= MAX_DISKS) { fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); exit(1); @@ -6876,11 +6876,11 @@ int main(int argc, char **argv) snprintf(buf, sizeof(buf), "type=cdrom,hdx=%c,img=", cdrom_index + 'a'); /* Build new disk IDE syntax string */ pstrcpy(ide_options[cdrom_index], - 25, + 22, buf); /* Add on image filename */ - pstrcpy(&(ide_options[cdrom_index][24]), - sizeof(ide_options[0])-24, + pstrcpy(&(ide_options[cdrom_index][21]), + sizeof(ide_options[0])-21, optarg); num_ide_disks++; } -- cgit v1.2.3 From c26c1c4b3d5d4b7bd9f986ab67608419e7abefe1 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 19:25:31 +0000 Subject: Support for unidirectional pipes, by Ed Swierk. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2267 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/vl.c b/vl.c index 7e161c69c..b3e07acc5 100644 --- a/vl.c +++ b/vl.c @@ -1297,12 +1297,23 @@ CharDriverState *qemu_chr_open_file_out(const char *file_out) CharDriverState *qemu_chr_open_pipe(const char *filename) { - int fd; - - fd = open(filename, O_RDWR | O_BINARY); - if (fd < 0) - return NULL; - return qemu_chr_open_fd(fd, fd); + int fd_in, fd_out; + char filename_in[256], filename_out[256]; + + snprintf(filename_in, 256, "%s.in", filename); + snprintf(filename_out, 256, "%s.out", filename); + fd_in = open(filename_in, O_RDWR | O_BINARY); + fd_out = open(filename_out, O_RDWR | O_BINARY); + if (fd_in < 0 || fd_out < 0) { + if (fd_in >= 0) + close(fd_in); + if (fd_out >= 0) + close(fd_out); + fd_in = fd_out = open(filename, O_RDWR | O_BINARY); + if (fd_in < 0) + return NULL; + } + return qemu_chr_open_fd(fd_in, fd_out); } -- cgit v1.2.3 From 52f61fdeec9debd499776f58ef485df76e4b38a5 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Dec 2006 21:20:52 +0000 Subject: Windows build fix, namespace cleanup, fix error message, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2268 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/vl.c b/vl.c index b3e07acc5..b4a03fdae 100644 --- a/vl.c +++ b/vl.c @@ -281,7 +281,7 @@ int register_ioport_write(int start, int length, int size, for(i = start; i < start + length; i += size) { ioport_write_table[bsize][i] = func; if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque) - hw_error("register_ioport_read: invalid opaque"); + hw_error("register_ioport_write: invalid opaque"); ioport_opaque[i] = opaque; } return 0; @@ -1096,7 +1096,7 @@ static void null_chr_add_read_handler(CharDriverState *chr, { } -CharDriverState *qemu_chr_open_null(void) +static CharDriverState *qemu_chr_open_null(void) { CharDriverState *chr; @@ -1264,7 +1264,7 @@ static void fd_chr_add_read_handler(CharDriverState *chr, } /* open a character device to a unix fd */ -CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) +static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) { CharDriverState *chr; FDCharDriver *s; @@ -1285,7 +1285,7 @@ CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) return chr; } -CharDriverState *qemu_chr_open_file_out(const char *file_out) +static CharDriverState *qemu_chr_open_file_out(const char *file_out) { int fd_out; @@ -1295,7 +1295,7 @@ CharDriverState *qemu_chr_open_file_out(const char *file_out) return qemu_chr_open_fd(-1, fd_out); } -CharDriverState *qemu_chr_open_pipe(const char *filename) +static CharDriverState *qemu_chr_open_pipe(const char *filename) { int fd_in, fd_out; char filename_in[256], filename_out[256]; @@ -1520,7 +1520,7 @@ static void term_init(void) fcntl(0, F_SETFL, O_NONBLOCK); } -CharDriverState *qemu_chr_open_stdio(void) +static CharDriverState *qemu_chr_open_stdio(void) { CharDriverState *chr; @@ -1546,7 +1546,7 @@ CharDriverState *qemu_chr_open_stdio(void) } #if defined(__linux__) -CharDriverState *qemu_chr_open_pty(void) +static CharDriverState *qemu_chr_open_pty(void) { struct termios tty; char slave_name[1024]; @@ -1685,7 +1685,7 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -CharDriverState *qemu_chr_open_tty(const char *filename) +static CharDriverState *qemu_chr_open_tty(const char *filename) { CharDriverState *chr; int fd; @@ -1739,7 +1739,7 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -CharDriverState *qemu_chr_open_pp(const char *filename) +static CharDriverState *qemu_chr_open_pp(const char *filename) { CharDriverState *chr; int fd; @@ -1766,7 +1766,7 @@ CharDriverState *qemu_chr_open_pp(const char *filename) } #else -CharDriverState *qemu_chr_open_pty(void) +static CharDriverState *qemu_chr_open_pty(void) { return NULL; } @@ -1984,7 +1984,7 @@ static void win_chr_add_read_handler(CharDriverState *chr, s->win_opaque = opaque; } -CharDriverState *qemu_chr_open_win(const char *filename) +static CharDriverState *qemu_chr_open_win(const char *filename) { CharDriverState *chr; WinCharState *s; @@ -2087,7 +2087,7 @@ static int win_chr_pipe_init(WinCharState *s, const char *filename) } -CharDriverState *qemu_chr_open_win_pipe(const char *filename) +static CharDriverState *qemu_chr_open_win_pipe(const char *filename) { CharDriverState *chr; WinCharState *s; @@ -2113,7 +2113,7 @@ CharDriverState *qemu_chr_open_win_pipe(const char *filename) return chr; } -CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) +static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) { CharDriverState *chr; WinCharState *s; @@ -2133,7 +2133,7 @@ CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) return chr; } -CharDriverState *qemu_chr_open_win_file_out(const char *file_out) +static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) { HANDLE fd_out; @@ -2223,12 +2223,14 @@ static void udp_chr_add_read_handler(CharDriverState *chr, } int parse_host_port(struct sockaddr_in *saddr, const char *str); -int parse_unix_path(struct sockaddr_un *uaddr, const char *str); +#ifndef _WIN32 +static int parse_unix_path(struct sockaddr_un *uaddr, const char *str); +#endif int parse_host_src_port(struct sockaddr_in *haddr, struct sockaddr_in *saddr, const char *str); -CharDriverState *qemu_chr_open_udp(const char *def) +static CharDriverState *qemu_chr_open_udp(const char *def) { CharDriverState *chr = NULL; NetCharDriver *s = NULL; @@ -2818,7 +2820,8 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str) return 0; } -int parse_unix_path(struct sockaddr_un *uaddr, const char *str) +#ifndef _WIN32 +static int parse_unix_path(struct sockaddr_un *uaddr, const char *str) { const char *p; int len; @@ -2835,6 +2838,7 @@ int parse_unix_path(struct sockaddr_un *uaddr, const char *str) return 0; } +#endif /* find or alloc a new VLAN */ VLANState *qemu_find_vlan(int id) @@ -3691,7 +3695,7 @@ static int get_param_value(char *buf, int buf_size, return 0; } -int net_client_init(const char *str) +static int net_client_init(const char *str) { const char *p; char *q; @@ -5880,7 +5884,7 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque) *pre = re; } -void qemu_system_reset(void) +static void qemu_system_reset(void) { QEMUResetEntry *re; -- cgit v1.2.3 From 4258b780afaa7251d9a7e363fe69e5672464fb56 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 22 Dec 2006 22:35:25 +0000 Subject: Sparc64 build fix (Igor Kovalenko). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2269 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apb_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 3ebe3207f..a5fe9b989 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -251,8 +251,8 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, d->config[0x0E] = 0x00; // header_type /* APB secondary busses */ - secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq); - pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq); + secondary = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 1"); + pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq, "Advanced PCI Bus secondary bridge 2"); return secondary; } -- cgit v1.2.3 From 28d657fc0b790e7b338ba624074624e3ce1f457b Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Dec 2006 00:03:15 +0000 Subject: Fix build warning on Windows. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2270 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/tcp.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/slirp/tcp.h b/slirp/tcp.h index 0cd3ab3a4..229293c49 100644 --- a/slirp/tcp.h +++ b/slirp/tcp.h @@ -111,8 +111,14 @@ struct tcphdr { /* * User-settable options (used with setsockopt). + * + * We don't use the system headers on unix because we have conflicting + * local structures. We can't avoid the system definitions on Windows, + * so we undefine them. */ +#undef TCP_NODELAY #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#undef TCP_MAXSEG /* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ /* -- cgit v1.2.3 From eddbd288a04d26852a9b5e3598eb90cd8ff5505f Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Dec 2006 00:23:19 +0000 Subject: More serial ports for the mips machine. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2271 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 1f779b2ff..cf52a0358 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -24,6 +24,9 @@ static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 14, 15 }; +static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; +static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; + extern FILE *logfile; static PITState *pit; /* PIT i8254 */ @@ -195,7 +198,13 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, isa_pic = pic_init(pic_irq_request, env); pit = pit_init(0x40, 0); - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); + for(i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + serial_init(&pic_set_irq_new, isa_pic, + serial_io[i], serial_irq[i], serial_hds[i]); + } + } + isa_vga_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); -- cgit v1.2.3 From 5bf089345be113089881163914a4d448f5365480 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Dec 2006 00:33:26 +0000 Subject: Fix spelling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2272 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index ab8595613..cc4bd3fa9 100755 --- a/configure +++ b/configure @@ -288,7 +288,7 @@ 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 build at the place where configure is launched" +echo "NOTE: The object files are built at the place where configure is launched" exit 1 fi -- cgit v1.2.3 From 70ead4341212ecb3181d5c780284cef0fc7b51fc Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Dec 2006 00:49:32 +0000 Subject: Use memory barriers in FORCE_RET / RETURN. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2273 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 2 +- target-mips/exec.h | 4 ++-- target-ppc/exec.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 0c392283d..2f3878561 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -188,7 +188,7 @@ extern int printf(const char *, ...); #endif /* force GCC to generate only one epilog at the end of the function */ -#define FORCE_RET() asm volatile (""); +#define FORCE_RET() __asm__ __volatile__("" : : : "memory"); #ifndef OPPROTO #define OPPROTO diff --git a/target-mips/exec.h b/target-mips/exec.h index 9e1fcdc00..e364d8a6f 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -45,9 +45,9 @@ register host_uint_t T2 asm(AREG3); #endif #if defined (DEBUG_OP) -#define RETURN() __asm__ __volatile__("nop"); +# define RETURN() __asm__ __volatile__("nop" : : : "memory"); #else -#define RETURN() __asm__ __volatile__(""); +# define RETURN() __asm__ __volatile__("" : : : "memory"); #endif #include "cpu.h" diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 3ef0968bc..89171f9d3 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -38,9 +38,9 @@ register uint32_t T2 asm(AREG3); #define FT2 (env->ft2) #if defined (DEBUG_OP) -#define RETURN() __asm__ __volatile__("nop"); +# define RETURN() __asm__ __volatile__("nop" : : : "memory"); #else -#define RETURN() __asm__ __volatile__(""); +# define RETURN() __asm__ __volatile__("" : : : "memory"); #endif #include "cpu.h" -- cgit v1.2.3 From 9042c0e20de166542b603621fd30dc8be95dfd4d Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Dec 2006 14:18:40 +0000 Subject: Check ELF binaries for machine type and endianness. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2274 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf_ops.h | 13 +++++++++---- hw/mips_r4k.c | 12 +++--------- loader.c | 12 ++++++++++-- target-arm/cpu.h | 2 ++ target-i386/cpu.h | 6 ++++++ target-m68k/cpu.h | 2 ++ target-mips/cpu.h | 2 ++ target-ppc/cpu.h | 2 ++ target-sh4/cpu.h | 2 ++ target-sparc/cpu.h | 6 ++++++ 10 files changed, 44 insertions(+), 15 deletions(-) diff --git a/elf_ops.h b/elf_ops.h index 122bf10c1..1cd4f2b3d 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -153,6 +153,9 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, glue(bswap_ehdr, SZ)(&ehdr); } + if (ELF_MACHINE != ehdr.e_machine) + goto fail; + if (pentry) *pentry = (uint64_t)ehdr.e_entry; @@ -164,7 +167,7 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, if (!phdr) goto fail; if (read(fd, phdr, size) != size) - goto fail; + goto fail1; if (must_swab) { for(i = 0; i < ehdr.e_phnum; i++) { ph = &phdr[i]; @@ -181,9 +184,9 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, data = qemu_mallocz(mem_size); if (ph->p_filesz > 0) { if (lseek(fd, ph->p_offset, SEEK_SET) < 0) - goto fail; + goto fail2; if (read(fd, data, ph->p_filesz) != ph->p_filesz) - goto fail; + goto fail2; } addr = ph->p_vaddr + virt_to_phys_addend; @@ -197,9 +200,11 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, } qemu_free(phdr); return total_size; - fail: +fail2: qemu_free(data); +fail1: qemu_free(phdr); +fail: return -1; } diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index cf52a0358..d72d768a0 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -11,7 +11,6 @@ #define BIOS_FILENAME "mips_bios.bin" //#define BIOS_FILENAME "system.bin" -#define KERNEL_LOAD_ADDR (int32_t)0x80010000 #ifdef MIPS_HAS_MIPS64 #define INITRD_LOAD_ADDR (int64_t)0x80800000 #else @@ -86,14 +85,9 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, entry = (int32_t)entry; env->PC = entry; } else { - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - env->PC = KERNEL_LOAD_ADDR; + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); } /* load initrd */ diff --git a/loader.c b/loader.c index 3fa681dbb..7823add91 100644 --- a/loader.c +++ b/loader.c @@ -197,7 +197,7 @@ static void *load_at(int fd, int offset, int size) int load_elf(const char *filename, int64_t virt_to_phys_addend, uint64_t *pentry) { - int fd, data_order, must_swab, ret; + int fd, data_order, host_data_order, must_swab, ret; uint8_t e_ident[EI_NIDENT]; fd = open(filename, O_RDONLY | O_BINARY); @@ -218,7 +218,15 @@ int load_elf(const char *filename, int64_t virt_to_phys_addend, data_order = ELFDATA2LSB; #endif must_swab = data_order != e_ident[EI_DATA]; - + +#ifdef TARGET_WORDS_BIGENDIAN + host_data_order = ELFDATA2MSB; +#else + host_data_order = ELFDATA2LSB; +#endif + if (host_data_order != e_ident[EI_DATA]) + return -1; + lseek(fd, 0, SEEK_SET); if (e_ident[EI_CLASS] == ELFCLASS64) { ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index b994bdd29..359d5cbdc 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -22,6 +22,8 @@ #define TARGET_LONG_BITS 32 +#define ELF_MACHINE EM_ARM + #include "cpu-defs.h" #include "softfloat.h" diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 30507403e..429609315 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -36,6 +36,12 @@ #define TARGET_HAS_ICE 1 +#ifdef TARGET_X86_64 +#define ELF_MACHINE EM_X86_64 +#else +#define ELF_MACHINE EM_386 +#endif + #include "cpu-defs.h" #include "softfloat.h" diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 29e02e8bb..a30bf962d 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -31,6 +31,8 @@ #define TARGET_HAS_ICE 1 +#define ELF_MACHINE EM_68K + #define EXCP_ACCESS 2 /* Access (MMU) error. */ #define EXCP_ADDRESS 3 /* Address error. */ #define EXCP_ILLEGAL 4 /* Illegal instruction. */ diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 8f0f598b6..c1b13d902 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -3,6 +3,8 @@ #define TARGET_HAS_ICE 1 +#define ELF_MACHINE EM_MIPS + #include "config.h" #include "mips-defs.h" #include "cpu-defs.h" diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 88d91358e..f05fb280b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -32,6 +32,8 @@ #define TARGET_HAS_ICE 1 +#define ELF_MACHINE EM_PPC + /* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC * have different cache line sizes */ diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index ef818fdf2..7296d9eef 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -25,6 +25,8 @@ #define TARGET_LONG_BITS 32 #define TARGET_HAS_ICE 1 +#define ELF_MACHINE EM_SH + #include "cpu-defs.h" #include "softfloat.h" diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 8cbf0b2e3..86c232004 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -19,6 +19,12 @@ #define TARGET_HAS_ICE 1 +#if !defined(TARGET_SPARC64) +#define ELF_MACHINE EM_SPARC +#else +#define ELF_MACHINE EM_SPARCV9 +#endif + /*#define EXCP_INTERRUPT 0x100*/ /* trap definitions */ -- cgit v1.2.3 From 04d4b0c33f92e8431095af4c8ab1dc8098b70ae6 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Dec 2006 15:18:47 +0000 Subject: Simplify error handling again. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2275 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf_ops.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/elf_ops.h b/elf_ops.h index 1cd4f2b3d..abcce093e 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -167,7 +167,7 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, if (!phdr) goto fail; if (read(fd, phdr, size) != size) - goto fail1; + goto fail; if (must_swab) { for(i = 0; i < ehdr.e_phnum; i++) { ph = &phdr[i]; @@ -184,9 +184,9 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, data = qemu_mallocz(mem_size); if (ph->p_filesz > 0) { if (lseek(fd, ph->p_offset, SEEK_SET) < 0) - goto fail2; + goto fail; if (read(fd, data, ph->p_filesz) != ph->p_filesz) - goto fail2; + goto fail; } addr = ph->p_vaddr + virt_to_phys_addend; @@ -200,11 +200,8 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, } qemu_free(phdr); return total_size; -fail2: + fail: qemu_free(data); -fail1: qemu_free(phdr); -fail: return -1; } - -- cgit v1.2.3 From a14d6c8c65f4caa6f61030fcfd3df6f108919d44 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 23 Dec 2006 15:37:33 +0000 Subject: Solaris SMBD hacks (Ben Taylor). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2276 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index b4a03fdae..3799c8a58 100644 --- a/vl.c +++ b/vl.c @@ -89,6 +89,11 @@ #include "exec-all.h" #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" +#ifdef __sun__ +#define SMBD_COMMAND "/usr/sfw/sbin/smbd" +#else +#define SMBD_COMMAND "/usr/sbin/smbd" +#endif //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IOPORT @@ -3084,8 +3089,8 @@ void net_slirp_smb(const char *exported_dir) fclose(f); atexit(smb_exit); - snprintf(smb_cmdline, sizeof(smb_cmdline), "/usr/sbin/smbd -s %s", - smb_conf); + snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", + SMBD_COMMAND, smb_conf); slirp_add_exec(0, smb_cmdline, 4, 139); } -- cgit v1.2.3 From 1f9584496747480020bb93ee1582d104f877ce0a Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Dec 2006 22:51:27 +0000 Subject: Null character instead of numeric null. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2277 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 3799c8a58..ed3109e21 100644 --- a/vl.c +++ b/vl.c @@ -3881,7 +3881,7 @@ static int disk_options_init(int num_ide_disks, } if (cdrom_device) { - snprintf(dev_name, sizeof(dev_name), "cdrom%c", i); + snprintf(dev_name, sizeof(dev_name), "cdrom%c", i + '0'); } else { snprintf(dev_name, sizeof(dev_name), "hd%c", i + 'a'); } @@ -3977,7 +3977,7 @@ static int disk_options_init(int num_ide_disks, } if (cdrom_device) { - snprintf(dev_name, sizeof(buf), "cdrom%c", scsi_index); + snprintf(dev_name, sizeof(buf), "cdrom%c", scsi_index + '0'); scsi_disks_info[scsi_index].device_type = SCSI_CDROM; } else { snprintf(dev_name, sizeof(buf), "sd%c", scsi_index + 'a'); -- cgit v1.2.3 From fa1fb14cd2f4f24e158b1bb284bd193e79899575 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 24 Dec 2006 17:12:43 +0000 Subject: Fix SCSI cdrom boot, thanks Blue Swirl. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2278 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 33 +++++++++++++++++++++++++-------- hw/sun4m.c | 6 ++++++ vl.c | 31 +++++++++++++++++++++++++++++++ vl.h | 4 +++- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 4587502e2..fea08d878 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -43,6 +43,8 @@ do { printf("ESP: " fmt , ##args); } while (0) #define ESP_MAXREG 0x3f #define TI_BUFSZ 32 +/* The HBA is ID 7, so for simplicitly limit to 7 devices. */ +#define ESP_MAX_DEVS 7 typedef struct ESPState ESPState; @@ -526,11 +528,33 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id) return 0; } +void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id) +{ + ESPState *s = (ESPState *)opaque; + + if (id < 0) { + for (id = 0; id < ESP_MAX_DEVS; id++) { + if (s->scsi_dev[id] == NULL) + break; + } + } + if (id >= ESP_MAX_DEVS) { + DPRINTF("Bad Device ID %d\n", id); + return; + } + if (s->scsi_dev[id]) { + DPRINTF("Destroying device %d\n", id); + scsi_disk_destroy(s->scsi_dev[id]); + } + DPRINTF("Attaching block device %d\n", id); + /* Command queueing is not implemented. */ + s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s); +} + void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque) { ESPState *s; int esp_io_memory; - int i; s = qemu_mallocz(sizeof(ESPState)); if (!s) @@ -546,13 +570,6 @@ void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque) register_savevm("esp", espaddr, 2, esp_save, esp_load, s); qemu_register_reset(esp_reset, s); - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) { - /* Command queueing is not implemented. */ - s->scsi_dev[i] = - scsi_disk_init(bs_table[i], 0, esp_command_complete, s); - } - } return s; } diff --git a/hw/sun4m.c b/hw/sun4m.c index a636638b5..c6765d9e1 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -262,6 +262,12 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma); + for (i = 0; i < MAX_SCSI_DISKS; i++) { + if (scsi_disks_info[i].adapter == SCSI_ESP && + scsi_disks_info[i].device_type != SCSI_NONE) { + esp_scsi_attach(main_esp, bs_scsi_table[i], scsi_disks_info[i].id); + } + } slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); cs_init(PHYS_JJ_CS, PHYS_JJ_CS_IRQ, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); diff --git a/vl.c b/vl.c index ed3109e21..aea96387d 100644 --- a/vl.c +++ b/vl.c @@ -3925,8 +3925,12 @@ static int disk_options_init(int num_ide_disks, for(i = 0; i < num_scsi_disks; i++) { +#if !defined(TARGET_SPARC) || defined(TARGET_SPARC64) temp_adapter = SCSI_LSI_53C895A; scsi_hba_lsi++; +#else + temp_adapter = SCSI_ESP; +#endif /*Check for sdx= parameter */ if (get_param_value(buf, sizeof(buf), "sdx", scsi_disk_options[i])) { @@ -3999,6 +4003,9 @@ static int disk_options_init(int num_ide_disks, fprintf(stderr, "qemu: SCSI disk image not specified for sd%c \n", i + 'a'); return -1; } + if (cdrom_device) { + bdrv_set_type_hint(bs_scsi_table[scsi_index], BDRV_TYPE_CDROM); + } } return 0; @@ -6887,6 +6894,8 @@ int main(int argc, char **argv) kernel_cmdline = optarg; break; case QEMU_OPTION_cdrom: +#if !defined(TARGET_SPARC) || defined(TARGET_SPARC64) + /* Assume boot cdrom is IDE */ { char buf[22]; if (num_ide_disks >= MAX_DISKS) { @@ -6904,6 +6913,27 @@ int main(int argc, char **argv) optarg); num_ide_disks++; } +#else + /* Assume boot cdrom is SCSI */ + { + char buf[27]; + if (num_scsi_disks >= MAX_SCSI_DISKS) { + fprintf(stderr, "qemu: too many SCSI disks/cdroms defined.\n"); + exit(1); + } + snprintf(buf, sizeof(buf), "type=cdrom,sdx=%c,id=%d,img=", + num_scsi_disks + 'a', num_scsi_disks + 2); + /* Build new disk SCSI syntax string */ + pstrcpy(scsi_options[num_scsi_disks], + 27, + buf); + /* Add on image filename */ + pstrcpy(&(scsi_options[num_scsi_disks][26]), + sizeof(scsi_options[0])-26, + optarg); + num_scsi_disks++; + } +#endif break; case QEMU_OPTION_boot: boot_device = optarg[0]; @@ -7193,6 +7223,7 @@ int main(int argc, char **argv) if (!linux_boot && num_ide_disks == 0 && + num_scsi_disks == 0 && fd_filename[0] == '\0') help(); diff --git a/vl.h b/vl.h index d3c56d4ce..6d0e7a769 100644 --- a/vl.h +++ b/vl.h @@ -1093,6 +1093,7 @@ void *slavio_misc_init(uint32_t base, int irq); void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ +void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque); void esp_reset(void *opaque); @@ -1223,7 +1224,8 @@ void scsi_cancel_io(SCSIDevice *s, uint32_t tag); uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); enum scsi_host_adapters { - SCSI_LSI_53C895A + SCSI_LSI_53C895A, + SCSI_ESP }; enum scsi_devices { SCSI_CDROM, -- cgit v1.2.3 From 388c45084d54ced21822ab29c76583a446ad410f Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 26 Dec 2006 18:27:07 +0000 Subject: bFLT loader commandline fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2279 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/flatload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/flatload.c b/linux-user/flatload.c index bf55be2b7..7e3296e5a 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -752,8 +752,8 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, DBG_FLT("p=%x\n", (int)p); /* Copy argv/envp. */ - p = copy_strings(p, bprm->argc, bprm->argv); p = copy_strings(p, bprm->envc, bprm->envp); + p = copy_strings(p, bprm->argc, bprm->argv); /* Align stack. */ sp = p & ~(target_ulong)(sizeof(target_ulong) - 1); sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1); -- cgit v1.2.3 From 04e897efdde24155237f228ea341ddaf2bce9dc7 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 1 Jan 2007 14:14:34 +0000 Subject: Remove duplicate TARGET_M68K case. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2280 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/disas.c b/disas.c index 04ea65355..297992798 100644 --- a/disas.c +++ b/disas.c @@ -194,8 +194,6 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #else print_insn = print_insn_little_mips; #endif -#elif defined(TARGET_M68K) - print_insn = print_insn_m68k; #elif defined(TARGET_SH4) disasm_info.mach = bfd_mach_sh4; print_insn = print_insn_sh; @@ -395,8 +393,6 @@ void monitor_disas(CPUState *env, #else print_insn = print_insn_little_mips; #endif -#elif defined(TARGET_M68K) - print_insn = print_insn_m68k; #else term_printf("0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", pc); -- cgit v1.2.3 From f8c6ff6c3cede2414da9be3e270218cdf3f8fc2c Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 1 Jan 2007 20:31:07 +0000 Subject: Fix initrd load address. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2281 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index d72d768a0..eee297018 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -12,7 +12,7 @@ #define BIOS_FILENAME "mips_bios.bin" //#define BIOS_FILENAME "system.bin" #ifdef MIPS_HAS_MIPS64 -#define INITRD_LOAD_ADDR (int64_t)0x80800000 +#define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000 #else #define INITRD_LOAD_ADDR (int32_t)0x80800000 #endif -- cgit v1.2.3 From 7495fd0f4a7b0b017f56d8f0a4fc4c3c5c3aa085 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 1 Jan 2007 20:32:08 +0000 Subject: Simplify code and fix formatting. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2282 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index a518e5ca4..b7defc9e5 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -162,12 +162,12 @@ void do_drotrv (void) #if TARGET_LONG_BITS > HOST_LONG_BITS static inline uint64_t get_HILO (void) { - return ((uint64_t)env->HI << 32) | (uint64_t)env->LO; + return (env->HI << 32) | (uint32_t)env->LO; } static inline void set_HILO (uint64_t HILO) { - env->LO = (int32_t)(HILO & 0xFFFFFFFF); + env->LO = (int32_t)HILO; env->HI = (int32_t)(HILO >> 32); } @@ -523,10 +523,10 @@ void do_tlbr (void) env->CP0_EntryHi = tlb->VPN | tlb->ASID; size = (tlb->end - tlb->VPN) >> 12; env->CP0_PageMask = (size - 1) << 13; - env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) - | (tlb->C0 << 3) | (tlb->PFN[0] >> 6); - env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) - | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); + env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | + (tlb->C0 << 3) | (tlb->PFN[0] >> 6); + env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | + (tlb->C1 << 3) | (tlb->PFN[1] >> 6); } #endif -- cgit v1.2.3 From 3a3f24fce80c1516fe03e0d4c73505ef6dbaa21c Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 1 Jan 2007 20:34:37 +0000 Subject: Fix lwl/lwr for 64bit emulation, also debug output spec for 64bit emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2283 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper_mem.c | 50 +++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index e8ec22b15..6af78ce05 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -1,3 +1,5 @@ +#undef DEBUG_OP + #ifdef TARGET_WORDS_BIGENDIAN #define GET_LMASK(v) ((v) & 3) #else @@ -12,21 +14,21 @@ void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) switch (GET_LMASK(T0)) { case 0: - T0 = tmp; + T0 = (int32_t)tmp; break; case 1: - T0 = (tmp << 8) | (T1 & 0x000000FF); + T0 = (int32_t)((tmp << 8) | (T1 & 0x000000FF)); break; case 2: - T0 = (tmp << 16) | (T1 & 0x0000FFFF); + T0 = (int32_t)((tmp << 16) | (T1 & 0x0000FFFF)); break; case 3: - T0 = (tmp << 24) | (T1 & 0x00FFFFFF); + T0 = (int32_t)((tmp << 24) | (T1 & 0x00FFFFFF)); break; } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + fprintf(logfile, "%s: " TLSZ " - %08x " TLSZ " => " TLSZ "\n", __func__, sav, tmp, T1, T0); } #endif @@ -41,21 +43,21 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) switch (GET_LMASK(T0)) { case 0: - T0 = (tmp >> 24) | (T1 & 0xFFFFFF00); + T0 = (int32_t)((tmp >> 24) | (T1 & 0xFFFFFF00)); break; case 1: - T0 = (tmp >> 16) | (T1 & 0xFFFF0000); + T0 = (int32_t)((tmp >> 16) | (T1 & 0xFFFF0000)); break; case 2: - T0 = (tmp >> 8) | (T1 & 0xFF000000); + T0 = (int32_t)((tmp >> 8) | (T1 & 0xFF000000)); break; case 3: - T0 = tmp; + T0 = (int32_t)tmp; break; } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + fprintf(logfile, "%s: " TLSZ " - %08x " TLSZ " => " TLSZ "\n", __func__, sav, tmp, T1, T0); } #endif @@ -70,21 +72,21 @@ uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) switch (GET_LMASK(T0)) { case 0: - tmp = T1; + tmp = (int32_t)T1; break; case 1: - tmp = (tmp & 0xFF000000) | (T1 >> 8); + tmp = (int32_t)((tmp & 0xFF000000) | ((uint32_t)T1 >> 8)); break; case 2: - tmp = (tmp & 0xFFFF0000) | (T1 >> 16); + tmp = (int32_t)((tmp & 0xFFFF0000) | ((uint32_t)T1 >> 16)); break; case 3: - tmp = (tmp & 0xFFFFFF00) | (T1 >> 24); + tmp = (int32_t)((tmp & 0xFFFFFF00) | ((uint32_t)T1 >> 24)); break; } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => %08x\n", __func__, T0, sav, T1, tmp); } #endif @@ -100,21 +102,21 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) switch (GET_LMASK(T0)) { case 0: - tmp = (tmp & 0x00FFFFFF) | (T1 << 24); + tmp = (int32_t)((tmp & 0x00FFFFFF) | (T1 << 24)); break; case 1: - tmp = (tmp & 0x0000FFFF) | (T1 << 16); + tmp = (int32_t)((tmp & 0x0000FFFF) | (T1 << 16)); break; case 2: - tmp = (tmp & 0x000000FF) | (T1 << 8); + tmp = (int32_t)((tmp & 0x000000FF) | (T1 << 8)); break; case 3: - tmp = T1; + tmp = (int32_t)T1; break; } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => %08x\n", __func__, T0, sav, T1, tmp); } #endif @@ -164,7 +166,7 @@ void glue(do_ldl, MEMSUFFIX) (uint64_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n", __func__, sav, tmp, T1, T0); } #endif @@ -205,7 +207,7 @@ void glue(do_ldr, MEMSUFFIX) (uint64_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n", __func__, sav, tmp, T1, T0); } #endif @@ -246,7 +248,7 @@ uint64_t glue(do_sdl, MEMSUFFIX) (uint64_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n", __func__, T0, sav, T1, tmp); } #endif @@ -288,7 +290,7 @@ uint64_t glue(do_sdr, MEMSUFFIX) (uint64_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: %08x - %08x %08x => %08x\n", + fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n", __func__, T0, sav, T1, tmp); } #endif -- cgit v1.2.3 From 0feef828e182f5b644d1d33a9ff3c54fc326b740 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 1 Jan 2007 20:35:21 +0000 Subject: Fix bad data type. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2284 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op.c b/target-mips/op.c index 27fb3ef59..0550d2786 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1330,7 +1330,7 @@ void op_mtc0_count (void) void op_mtc0_entryhi (void) { - uint32_t old, val; + target_ulong old, val; /* 1k pages not implemented */ /* Ignore MIPS64 TLB for now */ -- cgit v1.2.3 From 240f24e01372201d44115e945edb39d91a6cc1be Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 1 Jan 2007 21:31:01 +0000 Subject: Fix Makefile weirdness. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2285 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- configure | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index f0a8199f9..52ec957a2 100644 --- a/Makefile +++ b/Makefile @@ -5,14 +5,14 @@ include config-host.mak .PHONY: all clean distclean dvi info install install-doc tar tarbin \ speed test test2 html dvi info -CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I. +CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I. ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic endif ifeq ($(ARCH),sparc) CFLAGS+=-mcpu=ultrasparc endif -LDFLAGS=-g +LDFLAGS+=-g LIBS= DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE TOOLS=qemu-img$(EXESUF) diff --git a/configure b/configure index cc4bd3fa9..70d557a5d 100755 --- a/configure +++ b/configure @@ -243,11 +243,6 @@ for opt do esac done -# Checking for CFLAGS -if test -z "$CFLAGS"; then - CFLAGS="-O2" -fi - if test x"$show_help" = x"yes" ; then cat << EOF -- cgit v1.2.3 From df628ff14eeb825eafbf820ea71b09b8d9434029 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 2 Jan 2007 19:33:15 +0000 Subject: Arm GIC stuck interrupt fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2286 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_gic.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 94ce9aa34..2901f3466 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -17,7 +17,7 @@ #ifdef DEBUG_GIC #define DPRINTF(fmt, args...) \ -do { printf("arm_gic: " fmt , (int)s->base, ##args); } while (0) +do { printf("arm_gic: " fmt , ##args); } while (0) #else #define DPRINTF(fmt, args...) do {} while(0) #endif @@ -135,7 +135,10 @@ static void gic_set_irq(void *opaque, int irq, int level) static void gic_set_running_irq(gic_state *s, int irq) { s->running_irq = irq; - s->running_priority = s->priority[irq]; + if (irq == 1023) + s->running_priority = 0x100; + else + s->running_priority = s->priority[irq]; gic_update(s); } @@ -160,7 +163,7 @@ static uint32_t gic_acknowledge_irq(gic_state *s) static void gic_complete_irq(gic_state * s, int irq) { int update = 0; - DPRINTF("EIO %d\n", irq); + DPRINTF("EOI %d\n", irq); if (s->running_irq == 1023) return; /* No active IRQ. */ if (irq != 1023) { -- cgit v1.2.3 From 2ee4aed86ff2ba38a0e1846de18a9aec38d73015 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 Jan 2007 15:18:08 +0000 Subject: moved invalidate_tlb() to helper.c as a work around for gcc 3.2.2 bug - suppressed invalid tb_invalidate_page_range() calls git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2287 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 1 + target-mips/helper.c | 41 +++++++++++++++++++++++++++++++++++++++++ target-mips/op_helper.c | 48 +++--------------------------------------------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index e364d8a6f..3d6bb7d60 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -149,6 +149,7 @@ void dump_sc (void); int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); void do_interrupt (CPUState *env); +void invalidate_tlb (CPUState *env, int idx, int use_extra); void cpu_loop_exit(void); void do_raise_exception_err (uint32_t exception, int error_code); diff --git a/target-mips/helper.c b/target-mips/helper.c index e70dc1a99..43038c2d7 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -416,3 +416,44 @@ void do_interrupt (CPUState *env) env->exception_index = EXCP_NONE; } #endif /* !defined(CONFIG_USER_ONLY) */ + +void invalidate_tlb (CPUState *env, int idx, int use_extra) +{ + tlb_t *tlb; + target_ulong addr; + uint8_t ASID; + + ASID = env->CP0_EntryHi & 0xFF; + + tlb = &env->tlb[idx]; + /* The qemu TLB is flushed then the ASID changes, so no need to + flush these entries again. */ + if (tlb->G == 0 && tlb->ASID != ASID) { + return; + } + + if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) { + /* For tlbwr, we can shadow the discarded entry into + a new (fake) TLB entry, as long as the guest can not + tell that it's there. */ + env->tlb[env->tlb_in_use] = *tlb; + env->tlb_in_use++; + return; + } + + if (tlb->V0) { + addr = tlb->VPN; + while (addr < tlb->end) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } + } + if (tlb->V1) { + addr = tlb->end; + while (addr < tlb->end2) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } + } +} + diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index b7defc9e5..f4eb6e6a0 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -376,53 +376,11 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) env->tlb_in_use = MIPS_TLB_NB; } -static void invalidate_tlb (int idx, int use_extra) -{ - tlb_t *tlb; - target_ulong addr; - uint8_t ASID; - - ASID = env->CP0_EntryHi & 0xFF; - - tlb = &env->tlb[idx]; - /* The qemu TLB is flushed then the ASID changes, so no need to - flush these entries again. */ - if (tlb->G == 0 && tlb->ASID != ASID) { - return; - } - - if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) { - /* For tlbwr, we can shadow the discarded entry into - a new (fake) TLB entry, as long as the guest can not - tell that it's there. */ - env->tlb[env->tlb_in_use] = *tlb; - env->tlb_in_use++; - return; - } - - if (tlb->V0) { - tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN); - addr = tlb->VPN; - while (addr < tlb->end) { - tlb_flush_page (env, addr); - addr += TARGET_PAGE_SIZE; - } - } - if (tlb->V1) { - tb_invalidate_page_range(tlb->PFN[1], tlb->end2 - tlb->end); - addr = tlb->end; - while (addr < tlb->end2) { - tlb_flush_page (env, addr); - addr += TARGET_PAGE_SIZE; - } - } -} - static void mips_tlb_flush_extra (CPUState *env, int first) { /* Discard entries from env->tlb[first] onwards. */ while (env->tlb_in_use > first) { - invalidate_tlb(--env->tlb_in_use, 0); + invalidate_tlb(env, --env->tlb_in_use, 0); } } @@ -459,7 +417,7 @@ void do_tlbwi (void) /* Wildly undefined effects for CP0_index containing a too high value and MIPS_TLB_NB not being a power of two. But so does real silicon. */ - invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1), 0); + invalidate_tlb(env, env->CP0_index & (MIPS_TLB_NB - 1), 0); fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); } @@ -467,7 +425,7 @@ void do_tlbwr (void) { int r = cpu_mips_get_random(env); - invalidate_tlb(r, 1); + invalidate_tlb(env, r, 1); fill_tlb(r); } -- cgit v1.2.3 From b371dc594b75d739aa5b6bcf48423b401265dc68 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 3 Jan 2007 15:20:39 +0000 Subject: memsave monitor command git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2288 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/monitor.c b/monitor.c index d553ce607..127c0c5e1 100644 --- a/monitor.c +++ b/monitor.c @@ -642,6 +642,36 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne term_printf("\n"); } +static void do_memory_save(unsigned int valh, unsigned int vall, + uint32_t size, const char *filename) +{ + FILE *f; + target_long addr = GET_TLONG(valh, vall); + uint32_t l; + CPUState *env; + uint8_t buf[1024]; + + env = mon_get_cpu(); + if (!env) + return; + + f = fopen(filename, "wb"); + if (!f) { + term_printf("could not open '%s'\n", filename); + return; + } + while (size != 0) { + l = sizeof(buf); + if (l > size) + l = size; + cpu_memory_rw_debug(env, addr, buf, l, 0); + fwrite(buf, 1, l, f); + addr += l; + size -= l; + } + fclose(f); +} + static void do_sum(uint32_t start, uint32_t size) { uint32_t addr; @@ -1218,6 +1248,8 @@ static term_cmd_t term_cmds[] = { #endif { "stopcapture", "i", do_stop_capture, "capture index", "stop capture" }, + { "memsave", "lis", do_memory_save, + "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", }, { NULL, NULL, }, }; -- cgit v1.2.3 From 6f30fa853b78203c3a03c91470b7d2d12f46955a Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 01:00:47 +0000 Subject: Untangle the various CFLAGS/LDFLAGS flavours. Allow overriding the optional flags at make time. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2289 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 19 ++++---- Makefile.target | 131 +++++++++++++++++++++++++++++--------------------------- configure | 8 +++- 3 files changed, 83 insertions(+), 75 deletions(-) diff --git a/Makefile b/Makefile index 52ec957a2..4aa7510e4 100644 --- a/Makefile +++ b/Makefile @@ -5,19 +5,18 @@ include config-host.mak .PHONY: all clean distclean dvi info install install-doc tar tarbin \ speed test test2 html dvi info -CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I. -ifdef CONFIG_DARWIN -CFLAGS+= -mdynamic-no-pic -endif +BASE_CFLAGS= +BASE_LDFLAGS= + +BASE_CFLAGS += $(OS_CFLAGS) ifeq ($(ARCH),sparc) -CFLAGS+=-mcpu=ultrasparc +BASE_CFLAGS += -mcpu=ultrasparc endif -LDFLAGS+=-g +CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS= -DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE TOOLS=qemu-img$(EXESUF) ifdef CONFIG_STATIC -LDFLAGS+=-static +BASE_LDFLAGS += -static endif ifdef BUILD_DOCS DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 @@ -41,10 +40,10 @@ subdir-%: dyngen$(EXESUF) recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) qemu-img$(EXESUF): qemu-img.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) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS) + $(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c - $(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^ + $(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^ clean: # avoid old build problems by removing potentially incorrect old files diff --git a/Makefile.target b/Makefile.target index 1efe348ae..7c664922c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -12,14 +12,14 @@ TARGET_BASE_ARCH:=sparc endif TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio -DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) +CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) ifdef CONFIG_USER_ONLY VPATH+=:$(SRC_PATH)/linux-user -DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) +CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) endif -CFLAGS=-Wall -O2 -g -fno-strict-aliasing +BASE_CFLAGS= +BASE_LDFLAGS= #CFLAGS+=-Werror -LDFLAGS=-g LIBS= HELPER_CFLAGS=$(CFLAGS) DYNGEN=../dyngen$(EXESUF) @@ -62,18 +62,20 @@ endif endif # !CONFIG_USER_ONLY ifdef CONFIG_STATIC -LDFLAGS+=-static +BASE_LDFLAGS+=-static endif +# 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:=$(CFLAGS) -fomit-frame-pointer -OP_CFLAGS:=$(CFLAGS) -mpreferred-stack-boundary=2 -fomit-frame-pointer +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 @@ -81,76 +83,76 @@ ifdef CONFIG_STATIC USE_I386_LD=y endif ifdef USE_I386_LD -LDFLAGS+=-Wl,-T,$(SRC_PATH)/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! -LDFLAGS+=-Wl,-shared +BASE_LDFLAGS+=-Wl,-shared endif endif ifeq ($(ARCH),x86_64) -OP_CFLAGS=$(CFLAGS) -falign-functions=0 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/x86_64.ld +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),ppc) -CFLAGS+= -D__powerpc__ -OP_CFLAGS=$(CFLAGS) -LDFLAGS+=-Wl,-T,$(SRC_PATH)/ppc.ld +CPPFLAGS+= -D__powerpc__ +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),s390) -OP_CFLAGS=$(CFLAGS) -LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),sparc) ifeq ($(CONFIG_SOLARIS),yes) -CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3 -LDFLAGS+=-m32 -OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0 +BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3 +BASE_LDFLAGS+=-m32 +OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0 else -CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 -LDFLAGS+=-m32 -OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 +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 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static endif endif ifeq ($(ARCH),sparc64) -CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 -LDFLAGS+=-m64 -LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld -OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 +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 because we want two-instruction relocations -# for the constant constructions -OP_CFLAGS=-Wall -O2 -g +# -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 -CFLAGS += -msmall-data -LDFLAGS+=-Wl,-T,$(SRC_PATH)/alpha.ld +BASE_CFLAGS+=-msmall-data +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),ia64) -CFLAGS += -mno-sdata -OP_CFLAGS=$(CFLAGS) -LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld +BASE_CFLAGS+=-mno-sdata +OP_CFLAGS+=-mno-sdata +BASE_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),arm) -OP_CFLAGS=$(CFLAGS) -mno-sched-prolog -fno-omit-frame-pointer -LDFLAGS+=-Wl,-T,$(SRC_PATH)/arm.ld +OP_CFLAGS+=-mno-sched-prolog -fno-omit-frame-pointer +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),m68k) -OP_CFLAGS=$(CFLAGS) -fomit-frame-pointer -LDFLAGS+=-Wl,-T,m68k.ld +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) @@ -159,13 +161,14 @@ OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls endif ifeq ($(CONFIG_DARWIN),yes) -OP_CFLAGS+= -mdynamic-no-pic LIBS+=-lmx endif +OP_CFLAGS+=$(OS_CFLAGS) + ######################################################### -DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE +CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS+=-lm ifndef CONFIG_USER_ONLY LIBS+=-lz @@ -179,8 +182,8 @@ endif # profiling code ifdef TARGET_GPROF -LDFLAGS+=-p -main.o: CFLAGS+=-p +BASE_LDFLAGS+=-p +main.o: BASE_CFLAGS+=-p endif OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ @@ -211,7 +214,7 @@ LIBOBJS+=fpu/softfloat.o else LIBOBJS+=fpu/softfloat-native.o endif -DEFINES+=-I$(SRC_PATH)/fpu +CPPFLAGS+=-I$(SRC_PATH)/fpu ifeq ($(TARGET_ARCH), i386) LIBOBJS+=helper.o helper2.o @@ -288,7 +291,7 @@ endif all: $(PROGS) $(QEMU_USER): $(OBJS) - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + $(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) @@ -324,7 +327,7 @@ LIBS += -lole32 -ldxguid endif ifdef CONFIG_FMOD AUDIODRV += fmodaudio.o -audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES) +audio.o fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS) LIBS += $(CONFIG_FMOD_LIB) endif ifdef CONFIG_ADLIB @@ -347,14 +350,14 @@ 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 mixeng.o apic.o parallel.o acpi.o piix_pci.o VL_OBJS+= usb-uhci.o -DEFINES += -DHAS_AUDIO +CPPFLAGS += -DHAS_AUDIO 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 mixeng.o VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o -DEFINES += -DHAS_AUDIO +CPPFLAGS += -DHAS_AUDIO 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 @@ -395,7 +398,7 @@ COCOA_LIBS+=-framework CoreAudio endif endif ifdef CONFIG_SLIRP -DEFINES+=-I$(SRC_PATH)/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 @@ -418,7 +421,7 @@ endif endif endif ifdef TARGET_GPROF -vl.o: CFLAGS+=-p +vl.o: BASE_CFLAGS+=-p VL_LDFLAGS+=-p endif @@ -439,22 +442,22 @@ $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) cocoa.o: cocoa.m - $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< sdl.o: sdl.c keymaps.c sdl_keysym.h - $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h - $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< sdlaudio.o: sdlaudio.c - $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< depend: $(SRCS) - $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend + $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend vldepend: $(VL_OBJS:.o=.c) - $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend + $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend # libqemu @@ -478,26 +481,26 @@ gen-op.h: op.o $(DYNGEN) $(DYNGEN) -g -o $@ $< op.o: op.c - $(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $< + $(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) $(DEFINES) -c -o $@ $< + $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< else op_helper.o: op_helper.c - $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< + $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< endif cpu-exec.o: cpu-exec.c - $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $< + $(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) $(DEFINES) -c -o $@ $< + $(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 @@ -539,10 +542,10 @@ endif $(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h %.o: %.c - $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< %.o: %.S - $(CC) $(DEFINES) -c -o $@ $< + $(CC) $(CPPFLAGS) -c -o $@ $< clean: rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o diff --git a/configure b/configure index 70d557a5d..f03edd16c 100755 --- a/configure +++ b/configure @@ -103,7 +103,7 @@ targetos=`uname -s` case $targetos in CYGWIN*) mingw32="yes" -CFLAGS="-O2 -mno-cygwin" +OS_CFLAGS="-mno-cygwin" ;; MINGW32*) mingw32="yes" @@ -126,6 +126,7 @@ oss="yes" Darwin) bsd="yes" darwin="yes" +OS_CFLAGS="-mdynamic-no-pic" ;; SunOS) solaris="yes" @@ -243,6 +244,10 @@ for opt do 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 @@ -605,6 +610,7 @@ 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 -- cgit v1.2.3 From 455204eb1a0880a5e4474acf07d4641f51123a1d Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 16:42:13 +0000 Subject: Dynamic handling of guest mice, by Lonnie Mendez. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2290 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adb.c | 2 +- hw/ps2.c | 2 +- hw/slavio_serial.c | 2 +- hw/usb-hid.c | 9 ++-- monitor.c | 4 ++ qemu-doc.texi | 16 +++++++ sdl.c | 7 ++- vl.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++----- vl.h | 18 ++++++- 9 files changed, 176 insertions(+), 19 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index 8e08cb143..3f664a9c5 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -406,5 +406,5 @@ void adb_mouse_init(ADBBusState *bus) d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, adb_mouse_reset, s); adb_mouse_reset(d); - qemu_add_mouse_event_handler(adb_mouse_event, d, 0); + qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse"); } diff --git a/hw/ps2.c b/hw/ps2.c index 8438a5e85..3794c6036 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -560,7 +560,7 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_arg = update_arg; ps2_reset(&s->common); register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s); - qemu_add_mouse_event_handler(ps2_mouse_event, s, 0); + qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse"); qemu_register_reset(ps2_reset, &s->common); return s; } diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 404138d4b..928ff4c91 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -682,7 +682,7 @@ void slavio_serial_ms_kbd_init(int base, int irq) slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); - qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0); + qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, "QEMU Sun Mouse"); qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); qemu_register_reset(slavio_serial_reset, s); slavio_serial_reset(s); diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 095fcb3e6..bde3a7c67 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -39,6 +39,7 @@ typedef struct USBMouseState { int x, y; int kind; int mouse_grabbed; + QEMUPutMouseEntry *eh_entry; } USBMouseState; /* mostly the same values as the Bochs USB Mouse device */ @@ -259,7 +260,8 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) int dx, dy, dz, b, l; if (!s->mouse_grabbed) { - qemu_add_mouse_event_handler(usb_mouse_event, s, 0); + s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, + 0, "QEMU USB Mouse"); s->mouse_grabbed = 1; } @@ -295,7 +297,8 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) int dz, b, l; if (!s->mouse_grabbed) { - qemu_add_mouse_event_handler(usb_tablet_event, s, 1); + s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, s, + 1, "QEMU USB Tablet"); s->mouse_grabbed = 1; } @@ -503,7 +506,7 @@ static void usb_mouse_handle_destroy(USBDevice *dev) { USBMouseState *s = (USBMouseState *)dev; - qemu_add_mouse_event_handler(NULL, NULL, 0); + qemu_remove_mouse_event_handler(s->eh_entry); qemu_free(s); } diff --git a/monitor.c b/monitor.c index 127c0c5e1..da9b49239 100644 --- a/monitor.c +++ b/monitor.c @@ -1241,6 +1241,8 @@ static term_cmd_t term_cmds[] = { "dx dy [dz]", "send mouse move events" }, { "mouse_button", "i", do_mouse_button, "state", "change mouse button state (1=L, 2=M, 4=R)" }, + { "mouse_set", "i", do_mouse_set, + "index", "set which mouse device receives events" }, #ifdef HAS_AUDIO { "wavcapture", "si?i?i?", do_wav_capture, "path [frequency bits channels]", @@ -1292,6 +1294,8 @@ static term_cmd_t info_cmds[] = { "", "show capture information" }, { "snapshots", "", do_info_snapshots, "", "show the currently saved VM snapshots" }, + { "mice", "", do_info_mice, + "", "show which guest mouse is receiving events" }, { NULL, NULL, }, }; diff --git a/qemu-doc.texi b/qemu-doc.texi index 9b9df3305..f76ffd003 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -781,6 +781,8 @@ show all USB host devices show information about active capturing @item info snapshots show list of VM snapshots +@item info mice +show which guest mouse is receiving events @end table @item q or quit @@ -795,6 +797,20 @@ Change a removable media. @item screendump filename Save screen into PPM image @var{filename}. +@item mouse_move dx dy [dz] +Move the active mouse to the specified coordinates @var{dx} @var{dy} +with optional scroll axis @var{dz}. + +@item mouse_button val +Change the active mouse button state @var{val} (1=L, 2=M, 4=R). + +@item mouse_set index +Set which mouse device receives events at given @var{index}, index +can be obtained with +@example +info mice +@end example + @item wavcapture filename [frequency [bits [channels]]] Capture audio into @var{filename}. Using sample rate @var{frequency} bits per sample @var{bits} and number of channels @var{channels}. diff --git a/sdl.c b/sdl.c index b58e9d679..5ec0f67ef 100644 --- a/sdl.c +++ b/sdl.c @@ -319,6 +319,7 @@ static void sdl_show_cursor(void) { if (!kbd_mouse_is_absolute()) { SDL_ShowCursor(1); + SDL_SetCursor(sdl_cursor_normal); } } @@ -364,6 +365,9 @@ static void sdl_send_mouse_event(int dz) SDL_GetMouseState(&dx, &dy); dx = dx * 0x7FFF / width; dy = dy * 0x7FFF / height; + } else if (absolute_enabled) { + sdl_show_cursor(); + absolute_enabled = 0; } kbd_mouse_event(dx, dy, dz, buttons); @@ -501,7 +505,8 @@ static void sdl_refresh(DisplayState *ds) } break; case SDL_MOUSEMOTION: - if (gui_grab || kbd_mouse_is_absolute()) { + if (gui_grab || kbd_mouse_is_absolute() || + absolute_enabled) { sdl_send_mouse_event(0); } break; diff --git a/vl.c b/vl.c index aea96387d..5e06b0d77 100644 --- a/vl.c +++ b/vl.c @@ -463,9 +463,8 @@ void hw_error(const char *fmt, ...) static QEMUPutKBDEvent *qemu_put_kbd_event; static void *qemu_put_kbd_event_opaque; -static QEMUPutMouseEvent *qemu_put_mouse_event; -static void *qemu_put_mouse_event_opaque; -static int qemu_put_mouse_event_absolute; +static QEMUPutMouseEntry *qemu_put_mouse_event_head; +static QEMUPutMouseEntry *qemu_put_mouse_event_current; void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { @@ -473,11 +472,68 @@ void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) qemu_put_kbd_event = func; } -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute) +QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, + void *opaque, int absolute, + const char *name) { - qemu_put_mouse_event_opaque = opaque; - qemu_put_mouse_event = func; - qemu_put_mouse_event_absolute = absolute; + QEMUPutMouseEntry *s, *cursor; + + s = qemu_mallocz(sizeof(QEMUPutMouseEntry)); + if (!s) + return NULL; + + s->qemu_put_mouse_event = func; + s->qemu_put_mouse_event_opaque = opaque; + s->qemu_put_mouse_event_absolute = absolute; + s->qemu_put_mouse_event_name = qemu_strdup(name); + s->next = NULL; + + if (!qemu_put_mouse_event_head) { + qemu_put_mouse_event_head = qemu_put_mouse_event_current = s; + return s; + } + + cursor = qemu_put_mouse_event_head; + while (cursor->next != NULL) + cursor = cursor->next; + + cursor->next = s; + qemu_put_mouse_event_current = s; + + return s; +} + +void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) +{ + QEMUPutMouseEntry *prev = NULL, *cursor; + + if (!qemu_put_mouse_event_head || entry == NULL) + return; + + cursor = qemu_put_mouse_event_head; + while (cursor != NULL && cursor != entry) { + prev = cursor; + cursor = cursor->next; + } + + if (cursor == NULL) // does not exist or list empty + return; + else if (prev == NULL) { // entry is head + qemu_put_mouse_event_head = cursor->next; + if (qemu_put_mouse_event_current == entry) + qemu_put_mouse_event_current = cursor->next; + qemu_free(entry->qemu_put_mouse_event_name); + qemu_free(entry); + return; + } + + prev->next = entry->next; + + if (qemu_put_mouse_event_current == entry) + qemu_put_mouse_event_current = prev; + + qemu_free(entry->qemu_put_mouse_event_name); + qemu_free(entry); } void kbd_put_keycode(int keycode) @@ -489,15 +545,72 @@ void kbd_put_keycode(int keycode) void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) { - if (qemu_put_mouse_event) { - qemu_put_mouse_event(qemu_put_mouse_event_opaque, - dx, dy, dz, buttons_state); + QEMUPutMouseEvent *mouse_event; + void *mouse_event_opaque; + + if (!qemu_put_mouse_event_current) { + return; + } + + mouse_event = + qemu_put_mouse_event_current->qemu_put_mouse_event; + mouse_event_opaque = + qemu_put_mouse_event_current->qemu_put_mouse_event_opaque; + + if (mouse_event) { + mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state); } } int kbd_mouse_is_absolute(void) { - return qemu_put_mouse_event_absolute; + if (!qemu_put_mouse_event_current) + return 0; + + return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute; +} + +void do_info_mice(void) +{ + QEMUPutMouseEntry *cursor; + int index = 0; + + if (!qemu_put_mouse_event_head) { + term_printf("No mouse devices connected\n"); + return; + } + + term_printf("Mouse devices available:\n"); + cursor = qemu_put_mouse_event_head; + while (cursor != NULL) { + term_printf("%c Mouse #%d: %s\n", + (cursor == qemu_put_mouse_event_current ? '*' : ' '), + index, cursor->qemu_put_mouse_event_name); + index++; + cursor = cursor->next; + } +} + +void do_mouse_set(int index) +{ + QEMUPutMouseEntry *cursor; + int i = 0; + + if (!qemu_put_mouse_event_head) { + term_printf("No mouse devices connected\n"); + return; + } + + cursor = qemu_put_mouse_event_head; + while (cursor != NULL && index != i) { + i++; + cursor = cursor->next; + } + + if (cursor != NULL) + qemu_put_mouse_event_current = cursor; + else + term_printf("Mouse at given index not found\n"); } /* compute with 96 bit intermediate result: (a*b)/c */ diff --git a/vl.h b/vl.h index 6d0e7a769..5561a27c9 100644 --- a/vl.h +++ b/vl.h @@ -172,13 +172,29 @@ extern int no_quit; typedef void QEMUPutKBDEvent(void *opaque, int keycode); typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); +typedef struct QEMUPutMouseEntry { + QEMUPutMouseEvent *qemu_put_mouse_event; + void *qemu_put_mouse_event_opaque; + int qemu_put_mouse_event_absolute; + char *qemu_put_mouse_event_name; + + /* used internally by qemu for handling mice */ + struct QEMUPutMouseEntry *next; +} QEMUPutMouseEntry; + void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute); +QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, + void *opaque, int absolute, + const char *name); +void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry); void kbd_put_keycode(int keycode); void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); int kbd_mouse_is_absolute(void); +void do_info_mice(void); +void do_mouse_set(int index); + /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx constants) */ #define QEMU_KEY_ESC1(c) ((c) | 0xe100) -- cgit v1.2.3 From a0ae05aa6390fe363e70355c9375a9b9149dab14 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 16:54:16 +0000 Subject: PPC32 Trace Exception and Trap instruction, by Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2291 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 2 -- target-ppc/translate.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 3f7a70871..70b0a4915 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1113,8 +1113,6 @@ void do_interrupt (CPUState *env) } goto store_next; case EXCP_TRACE: /* 0x0D00 */ - /* XXX: TODO */ - cpu_abort(env, "Trace exception is not implemented yet !\n"); goto store_next; case EXCP_PERF: /* 0x0F00 */ /* XXX: TODO */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 046f168bf..41737d4a8 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1956,6 +1956,8 @@ GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW) { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); + /* Update the nip since this might generate a trap exception */ + gen_op_update_nip(ctx->nip); gen_op_tw(TO(ctx->opcode)); } -- cgit v1.2.3 From 9ae0255520fb37d9972bef9bf58d6f342ea7128a Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 17:39:04 +0000 Subject: Add -option-rom option to allow loading of PCI option ROMs, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2292 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 19 ++++++++++++++++++- qemu-doc.texi | 4 ++++ vl.c | 22 ++++++++++++++++++++++ vl.h | 4 ++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index 70be34624..917d9724a 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -451,7 +451,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; int ret, linux_boot, initrd_size, i; - unsigned long bios_offset, vga_bios_offset; + unsigned long bios_offset, vga_bios_offset, option_rom_offset; int bios_size, isa_bios_size; PCIBus *pci_bus; int piix3_devfn = -1; @@ -518,6 +518,23 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x100000 - isa_bios_size, isa_bios_size, (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); + + option_rom_offset = 0; + for (i = 0; i < nb_option_roms; i++) { + int offset = bios_offset + bios_size + option_rom_offset; + int size; + + size = load_image(option_rom[i], phys_ram_base + offset); + if ((size + option_rom_offset) > 0x10000) { + fprintf(stderr, "Too many option ROMS\n"); + exit(1); + } + cpu_register_physical_memory(0xd0000 + option_rom_offset, + size, offset | IO_MEM_ROM); + option_rom_offset += size + 2047; + option_rom_offset -= (option_rom_offset % 2048); + } + /* map all the bios at the top of memory */ cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); diff --git a/qemu-doc.texi b/qemu-doc.texi index f76ffd003..1dd33fe9b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -326,6 +326,10 @@ Use it when installing Windows 2000 to avoid a disk full bug. After Windows 2000 is installed, you no longer need this option (this option slows down the IDE transfers). +@item -option-rom file +Load the contents of file as an option ROM. This option is useful to load +things like EtherBoot. + @end table USB options: diff --git a/vl.c b/vl.c index 5e06b0d77..cfe94c816 100644 --- a/vl.c +++ b/vl.c @@ -174,6 +174,8 @@ int acpi_enabled = 1; int fd_bootchk = 1; int no_reboot = 0; int daemonize = 0; +const char *option_rom[MAX_OPTION_ROMS]; +int nb_option_roms; /***********************************************************/ /* x86 ISA bus support */ @@ -6336,6 +6338,7 @@ void help(void) #ifndef _WIN32 "-daemonize daemonize QEMU after initializing\n" #endif + "-option-rom rom load a file, rom, into the option ROM space\n" "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -6418,6 +6421,7 @@ enum { QEMU_OPTION_no_reboot, QEMU_OPTION_daemonize, QEMU_OPTION_disk, + QEMU_OPTION_option_rom, }; typedef struct QEMUOption { @@ -6500,6 +6504,7 @@ const QEMUOption qemu_options[] = { { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "no-reboot", 0, QEMU_OPTION_no_reboot }, { "daemonize", 0, QEMU_OPTION_daemonize }, + { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, { NULL }, }; @@ -7276,6 +7281,14 @@ int main(int argc, char **argv) case QEMU_OPTION_daemonize: daemonize = 1; break; + case QEMU_OPTION_option_rom: + if (nb_option_roms >= MAX_OPTION_ROMS) { + fprintf(stderr, "Too many option ROMs\n"); + exit(1); + } + option_rom[nb_option_roms] = optarg; + nb_option_roms++; + break; } } } @@ -7368,6 +7381,15 @@ int main(int argc, char **argv) /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; + for (i = 0; i < nb_option_roms; i++) { + int ret = get_image_size(option_rom[i]); + if (ret == -1) { + fprintf(stderr, "Could not load option rom '%s'\n", option_rom[i]); + exit(1); + } + phys_ram_size += ret; + } + phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { fprintf(stderr, "Could not allocate physical memory\n"); diff --git a/vl.h b/vl.h index 5561a27c9..b63145e35 100644 --- a/vl.h +++ b/vl.h @@ -154,6 +154,10 @@ extern int usb_enabled; extern int smp_cpus; extern int no_quit; +#define MAX_OPTION_ROMS 16 +extern const char *option_rom[MAX_OPTION_ROMS]; +extern int nb_option_roms; + /* XXX: make it dynamic */ #if defined (TARGET_PPC) || defined (TARGET_SPARC64) #define BIOS_SIZE ((512 + 32) * 1024) -- cgit v1.2.3 From eec85c2a0d18523f535785d15b046f427481cf5f Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 17:41:07 +0000 Subject: Add -boot n option for x86 using PXE, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2293 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 ++- pc-bios/README | 6 ++++++ qemu-doc.texi | 6 +++--- vl.c | 26 ++++++++++++++++++++++++-- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 4aa7510e4..b88f50101 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,8 @@ install: all $(if $(BUILD_DOCS),install-doc) $(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; do \ + 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 diff --git a/pc-bios/README b/pc-bios/README index fc85eb429..45e4b7cba 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,3 +14,9 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. + +- The PXE roms come from Rom-o-Matic etherboot 5.4.2. + pcnet32:pcnet32 -- [0x1022,0x2000] + ns8390:winbond940 -- [0x1050,0x0940] + rtl8139:rtl8139 -- [0x10ec,0x8139] + http://rom-o-matic.net/ diff --git a/qemu-doc.texi b/qemu-doc.texi index 1dd33fe9b..45f5ea412 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -219,9 +219,9 @@ Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and @option{-cdrom} at the same time). You can use the host CD-ROM by using @file{/dev/cdrom} as filename (@pxref{host_drives}). -@item -boot [a|c|d] -Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is -the default. +@item -boot [a|c|d|n] +Boot on floppy (a), hard disk (c), CD-ROM (d), or Etherboot (n). Hard disk boot +is the default. @item -disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] Use @var{file} as the IDE disk/CD-ROM image. The defaults are: hdx=a,type=disk diff --git a/vl.c b/vl.c index cfe94c816..7b3d880b4 100644 --- a/vl.c +++ b/vl.c @@ -6234,7 +6234,7 @@ void help(void) "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" - "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" + "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" "-disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] \n" " defaults are: hdx=a,type=disk \n" "-disk scsi,img=file[,sdx=a..g][,type=disk|cdrom][,id=n] \n" @@ -7056,7 +7056,7 @@ int main(int argc, char **argv) case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && -#ifdef TARGET_SPARC +#if defined(TARGET_SPARC) || defined(TARGET_I386) // Network boot boot_device != 'n' && #endif @@ -7378,6 +7378,28 @@ int main(int argc, char **argv) exit(1); } +#ifdef TARGET_I386 + if (boot_device == 'n') { + for (i = 0; i < nb_nics; i++) { + const char *model = nd_table[i].model; + char buf[1024]; + if (model == NULL) + model = "ne2k_pci"; + snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model); + if (get_image_size(buf) > 0) { + option_rom[nb_option_roms] = strdup(buf); + nb_option_roms++; + break; + } + } + if (i == nb_nics) { + fprintf(stderr, "No valid PXE rom found for network device\n"); + exit(1); + } + boot_device = 'c'; /* to prevent confusion by the BIOS */ + } +#endif + /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; -- cgit v1.2.3 From 2e9671daee6f575e2eca8893ec64cd0655d672bc Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 17:44:41 +0000 Subject: patch for block-raw.c for Solaris, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2294 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 2 ++ vl.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/block-raw.c b/block-raw.c index 9f4a0a1d2..9fe953c30 100644 --- a/block-raw.c +++ b/block-raw.c @@ -44,6 +44,8 @@ #endif #ifdef __sun__ +#define _POSIX_PTHREAD_SEMANTICS 1 +#include #include #endif #ifdef __linux__ diff --git a/vl.h b/vl.h index b63145e35..9d95494a0 100644 --- a/vl.h +++ b/vl.h @@ -45,6 +45,10 @@ #define O_BINARY 0 #endif +#ifdef __sun__ +#define ENOMEDIUM 4097 +#endif + #ifdef _WIN32 #include #define fsync _commit -- cgit v1.2.3 From b92090309e5ff7154e4c131438ee2d540e233955 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 18:52:57 +0000 Subject: Fix comment, by Volker Ruppert. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2295 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index 073dafa4c..0012834f4 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1673,8 +1673,9 @@ enqueue: #else cur_drv->last_sect = fdctrl->fifo[3]; #endif - /* Bochs BIOS is buggy and don't send format informations - * for each sector. So, pretend all's done right now... + /* TODO: implement format using DMA expected by the Bochs BIOS + * and Linux fdformat (read 3 bytes per sector via DMA and fill + * the sector with the specified fill byte */ fdctrl->data_state &= ~FD_STATE_FORMAT; fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); -- cgit v1.2.3 From 6850dd945ea7eb0beedb25435bf2bc16741aec38 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 18:56:04 +0000 Subject: Support for Bochs "growing" images, by Volker Ruppert. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2296 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-bochs.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/block-bochs.c b/block-bochs.c index febb4d3fd..35e2a6cf0 100644 --- a/block-bochs.c +++ b/block-bochs.c @@ -28,7 +28,8 @@ /**************************************************************/ #define HEADER_MAGIC "Bochs Virtual HD Image" -#define HEADER_VERSION 0x00010000 +#define HEADER_VERSION 0x00020000 +#define HEADER_V1 0x00010000 #define HEADER_SIZE 512 #define REDOLOG_TYPE "Redolog" @@ -37,7 +38,7 @@ // not allocated: 0xffffffff // always little-endian -struct bochs_header { +struct bochs_header_v1 { char magic[32]; // "Bochs Virtual HD Image" char type[16]; // "Redolog" char subtype[16]; // "Undoable" / "Volatile" / "Growing" @@ -56,6 +57,27 @@ struct bochs_header { } 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; @@ -79,7 +101,8 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename) 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_VERSION) || + (le32_to_cpu(bochs->version) == HEADER_V1))) return 100; return 0; @@ -90,6 +113,7 @@ 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) { @@ -109,11 +133,17 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) 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_VERSION) && + (le32_to_cpu(bochs.version) != HEADER_V1))) { goto fail; } - bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512; + 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); -- cgit v1.2.3 From 4dbb0f5006c7a729e20199f08a9d338b11f61fef Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 18:58:34 +0000 Subject: Fix for hard disk translation hints, by Volker Ruppert. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2297 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 14 ++++++++++++-- vl.h | 8 +++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 68ad718d0..a1aabf05e 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2069,7 +2069,7 @@ static void ide_init2(IDEState *ide_state, { IDEState *s; static int drive_serial = 1; - int i, cylinders, heads, secs, translation; + int i, cylinders, heads, secs, translation, lba_detected = 0; int64_t nb_sectors; for(i = 0; i < 2; i++) { @@ -2083,6 +2083,7 @@ static void ide_init2(IDEState *ide_state, s->nb_sectors = nb_sectors; /* if a geometry hint is available, use it */ bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); + translation = bdrv_get_translation_hint(s->bs); if (cylinders != 0) { s->cylinders = cylinders; s->heads = heads; @@ -2093,6 +2094,7 @@ static void ide_init2(IDEState *ide_state, /* if heads > 16, it means that a BIOS LBA translation was active, so the default hardware geometry is OK */ + lba_detected = 1; goto default_geometry; } else { s->cylinders = cylinders; @@ -2100,7 +2102,6 @@ static void ide_init2(IDEState *ide_state, s->sectors = secs; /* disable any translation to be in sync with the logical geometry */ - translation = bdrv_get_translation_hint(s->bs); if (translation == BIOS_ATA_TRANSLATION_AUTO) { bdrv_set_translation_hint(s->bs, BIOS_ATA_TRANSLATION_NONE); @@ -2117,6 +2118,15 @@ static void ide_init2(IDEState *ide_state, s->cylinders = cylinders; s->heads = 16; s->sectors = 63; + if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) { + if ((s->cylinders * s->heads) <= 131072) { + bdrv_set_translation_hint(s->bs, + BIOS_ATA_TRANSLATION_LARGE); + } else { + bdrv_set_translation_hint(s->bs, + BIOS_ATA_TRANSLATION_LBA); + } + } } bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, s->sectors); } diff --git a/vl.h b/vl.h index 9d95494a0..1c584063e 100644 --- a/vl.h +++ b/vl.h @@ -616,9 +616,11 @@ void bdrv_flush(BlockDriverState *bs); #define BDRV_TYPE_HD 0 #define BDRV_TYPE_CDROM 1 #define BDRV_TYPE_FLOPPY 2 -#define BIOS_ATA_TRANSLATION_AUTO 0 -#define BIOS_ATA_TRANSLATION_NONE 1 -#define BIOS_ATA_TRANSLATION_LBA 2 +#define BIOS_ATA_TRANSLATION_AUTO 0 +#define BIOS_ATA_TRANSLATION_NONE 1 +#define BIOS_ATA_TRANSLATION_LBA 2 +#define BIOS_ATA_TRANSLATION_LARGE 3 +#define BIOS_ATA_TRANSLATION_RECHS 4 void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs); -- cgit v1.2.3 From 43f238d7b6f75244b8c47409896a9725655e52ab Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 20:55:49 +0000 Subject: Support fcntl F_GETLK64, F_SETLK64, F_SETLKW64, by Kirill A. Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2298 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1c3121818..21f559ebc 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1727,6 +1727,8 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) { struct flock fl; struct target_flock *target_fl; + struct flock64 fl64; + struct target_flock64 *target_fl64; long ret; switch(cmd) { @@ -1756,10 +1758,27 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) break; case TARGET_F_GETLK64: + ret = fcntl(fd, cmd >> 1, &fl64); + if (ret == 0) { + lock_user_struct(target_fl64, arg, 0); + target_fl64->l_type = tswap16(fl64.l_type) >> 1; + target_fl64->l_whence = tswap16(fl64.l_whence); + target_fl64->l_start = tswapl(fl64.l_start); + target_fl64->l_len = tswapl(fl64.l_len); + target_fl64->l_pid = tswapl(fl64.l_pid); + unlock_user_struct(target_fl64, arg, 1); + } + break; case TARGET_F_SETLK64: case TARGET_F_SETLKW64: - ret = -1; - errno = EINVAL; + lock_user_struct(target_fl64, arg, 1); + fl64.l_type = tswap16(target_fl64->l_type) >> 1; + fl64.l_whence = tswap16(target_fl64->l_whence); + fl64.l_start = tswapl(target_fl64->l_start); + fl64.l_len = tswapl(target_fl64->l_len); + fl64.l_pid = tswap16(target_fl64->l_pid); + unlock_user_struct(target_fl64, arg, 0); + ret = fcntl(fd, cmd >> 1, &fl64); break; case F_GETFL: -- cgit v1.2.3 From 8f28f3fbbe1116c5f4f11ebf4167a770032e2606 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 21:25:54 +0000 Subject: Configure check for alsa, by Bernhard Fischer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2299 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/configure b/configure index f03edd16c..93bbe7b78 100755 --- a/configure +++ b/configure @@ -509,6 +509,25 @@ fi # sdl compile test fi # cross compilation fi # -z $sdl +########################################## +# alsa sound support libraries + +if test "$alsa" = "yes" ; then + cat > $TMPC << EOF +#include +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" -- cgit v1.2.3 From 86e94dea5b740dad65446c857f6959eae43e0ba6 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 22:01:59 +0000 Subject: Reinitialize monitor upon reconnect, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2300 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 2 ++ monitor.c | 20 +++++++++++++++----- vl.c | 28 ++++++++++++++++++++++++++++ vl.h | 7 +++++-- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/console.c b/console.c index f039dfcb3..cd30235b3 100644 --- a/console.c +++ b/console.c @@ -1086,5 +1086,7 @@ CharDriverState *text_console_init(DisplayState *ds) s->t_attrib = s->t_attrib_default; text_console_resize(s); + qemu_chr_reset(chr); + return chr; } diff --git a/monitor.c b/monitor.c index da9b49239..6cb1c38fb 100644 --- a/monitor.c +++ b/monitor.c @@ -55,6 +55,7 @@ typedef struct term_cmd_t { } term_cmd_t; static CharDriverState *monitor_hd; +static int hide_banner; static term_cmd_t term_cmds[]; static term_cmd_t info_cmds[]; @@ -2438,15 +2439,24 @@ static void monitor_start_input(void) readline_start("(qemu) ", 0, monitor_handle_command1, NULL); } +static void term_event(void *opaque, int event) +{ + if (event != CHR_EVENT_RESET) + return; + + if (!hide_banner) + term_printf("QEMU %s monitor - type 'help' for more information\n", + QEMU_VERSION); + monitor_start_input(); +} + void monitor_init(CharDriverState *hd, int show_banner) { monitor_hd = hd; - if (show_banner) { - term_printf("QEMU %s monitor - type 'help' for more information\n", - QEMU_VERSION); - } + hide_banner = !show_banner; + qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL); - monitor_start_input(); + qemu_chr_add_event_handler(hd, term_event); } /* XXX: use threads ? */ diff --git a/vl.c b/vl.c index 7b3d880b4..e5399c730 100644 --- a/vl.c +++ b/vl.c @@ -1165,6 +1165,23 @@ void quit_timers(void) /***********************************************************/ /* character device */ +static void qemu_chr_reset_bh(void *opaque) +{ + CharDriverState *s = opaque; + if (s->chr_event) + s->chr_event(s, CHR_EVENT_RESET); + qemu_bh_delete(s->bh); + s->bh = NULL; +} + +void qemu_chr_reset(CharDriverState *s) +{ + if (s->bh == NULL) { + s->bh = qemu_bh_new(qemu_chr_reset_bh, s); + qemu_bh_schedule(s->bh); + } +} + int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) { return s->chr_write(s, buf, len); @@ -1402,6 +1419,9 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) chr->opaque = s; chr->chr_write = fd_chr_write; chr->chr_add_read_handler = fd_chr_add_read_handler; + + qemu_chr_reset(chr); + return chr; } @@ -1819,6 +1839,7 @@ static CharDriverState *qemu_chr_open_tty(const char *filename) if (!chr) return NULL; chr->chr_ioctl = tty_serial_ioctl; + qemu_chr_reset(chr); return chr; } @@ -1882,6 +1903,9 @@ static CharDriverState *qemu_chr_open_pp(const char *filename) chr->chr_write = null_chr_write; chr->chr_add_read_handler = null_chr_add_read_handler; chr->chr_ioctl = pp_ioctl; + + qemu_chr_reset(chr); + return chr; } @@ -2127,6 +2151,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename) free(chr); return NULL; } + qemu_chr_reset(chr); return chr; } @@ -2230,6 +2255,7 @@ static CharDriverState *qemu_chr_open_win_pipe(const char *filename) free(chr); return NULL; } + qemu_chr_reset(chr); return chr; } @@ -2250,6 +2276,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) chr->opaque = s; chr->chr_write = win_chr_write; chr->chr_add_read_handler = win_chr_add_read_handler; + qemu_chr_reset(chr); return chr; } @@ -2537,6 +2564,7 @@ static void tcp_chr_connect(void *opaque) s->connected = 1; qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, tcp_chr_read, NULL, chr); + qemu_chr_reset(chr); } #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; diff --git a/vl.h b/vl.h index 1c584063e..8eef56de3 100644 --- a/vl.h +++ b/vl.h @@ -260,11 +260,13 @@ int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); #endif +typedef struct QEMUBH QEMUBH; + /* character device */ #define CHR_EVENT_BREAK 0 /* serial break char */ #define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */ - +#define CHR_EVENT_RESET 2 /* new connection established */ #define CHR_IOCTL_SERIAL_SET_PARAMS 1 @@ -295,6 +297,7 @@ typedef struct CharDriverState { void (*chr_send_event)(struct CharDriverState *chr, int event); void (*chr_close)(struct CharDriverState *chr); void *opaque; + QEMUBH *bh; } CharDriverState; void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); @@ -305,6 +308,7 @@ void qemu_chr_add_read_handler(CharDriverState *s, IOReadHandler *fd_read, void *opaque); void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); +void qemu_chr_reset(CharDriverState *s); /* consoles */ @@ -513,7 +517,6 @@ void do_delvm(const char *name); void do_info_snapshots(void); /* bottom halves */ -typedef struct QEMUBH QEMUBH; typedef void QEMUBHFunc(void *opaque); QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); -- cgit v1.2.3 From 43c1b7e4c35f1dc7ee073733ddb16339c216183b Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 5 Jan 2007 23:48:51 +0000 Subject: Add new Etherboot ROMs for PXE boot. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2301 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/pxe-ne2k_pci.bin | Bin 0 -> 32768 bytes pc-bios/pxe-pcnet.bin | Bin 0 -> 32768 bytes pc-bios/pxe-rtl8139.bin | Bin 0 -> 32768 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 pc-bios/pxe-ne2k_pci.bin create mode 100644 pc-bios/pxe-pcnet.bin create mode 100644 pc-bios/pxe-rtl8139.bin diff --git a/pc-bios/pxe-ne2k_pci.bin b/pc-bios/pxe-ne2k_pci.bin new file mode 100644 index 000000000..8d8fc02af Binary files /dev/null and b/pc-bios/pxe-ne2k_pci.bin differ diff --git a/pc-bios/pxe-pcnet.bin b/pc-bios/pxe-pcnet.bin new file mode 100644 index 000000000..d127d3378 Binary files /dev/null and b/pc-bios/pxe-pcnet.bin differ diff --git a/pc-bios/pxe-rtl8139.bin b/pc-bios/pxe-rtl8139.bin new file mode 100644 index 000000000..2b5cacbbb Binary files /dev/null and b/pc-bios/pxe-rtl8139.bin differ -- cgit v1.2.3 From f7bcd4e373193fd3d78d7ee24c0a1bcca9dcc3a3 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 6 Jan 2007 01:37:51 +0000 Subject: Different MIPS BIOS binary names per endianness, and more relaxed size rules for the binaries, by Alec Voropay. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2302 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index eee297018..5f5b799d7 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -9,7 +9,11 @@ */ #include "vl.h" +#ifdef TARGET_BIG_ENDIAN #define BIOS_FILENAME "mips_bios.bin" +#else +#define BIOS_FILENAME "mipsel_bios.bin" +#endif //#define BIOS_FILENAME "system.bin" #ifdef MIPS_HAS_MIPS64 #define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000 @@ -136,7 +140,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; unsigned long bios_offset; - int ret; + int bios_size; CPUState *env; static RTCState *rtc_state; int i; @@ -160,8 +164,8 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, run. */ bios_offset = ram_size + vga_ram_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - ret = load_image(buf, phys_ram_base + bios_offset); - if (ret == BIOS_SIZE) { + bios_size = load_image(buf, phys_ram_base + bios_offset); + if (bios_size > 0 & bios_size <= BIOS_SIZE) { cpu_register_physical_memory((uint32_t)(0x1fc00000), BIOS_SIZE, bios_offset | IO_MEM_ROM); } else { -- cgit v1.2.3 From 2909b29aeea50fc25ea342a39db4c8ef5fd6a716 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 6 Jan 2007 02:24:15 +0000 Subject: Unbreak the last patch. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2303 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 5f5b799d7..ffed67c2a 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -9,7 +9,7 @@ */ #include "vl.h" -#ifdef TARGET_BIG_ENDIAN +#ifdef TARGET_WORDS_BIGENDIAN #define BIOS_FILENAME "mips_bios.bin" #else #define BIOS_FILENAME "mipsel_bios.bin" @@ -165,7 +165,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, bios_offset = ram_size + vga_ram_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); bios_size = load_image(buf, phys_ram_base + bios_offset); - if (bios_size > 0 & bios_size <= BIOS_SIZE) { + if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) { cpu_register_physical_memory((uint32_t)(0x1fc00000), BIOS_SIZE, bios_offset | IO_MEM_ROM); } else { -- cgit v1.2.3 From f5e25d7007544415dbfd3fdf0778604c9b7c68b7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Jan 2007 17:12:41 +0000 Subject: Japanese keyboard patch (kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2304 c046a42c-6fe2-441c-8c8c-71466251a162 --- keymaps/ja | 3 +++ vnc_keysym.h | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/keymaps/ja b/keymaps/ja index ae513c7ee..6947cb124 100644 --- a/keymaps/ja +++ b/keymaps/ja @@ -103,3 +103,6 @@ underscore 0x73 shift Henkan_Mode 0x79 Katakana 0x70 Muhenkan 0x7b +Henkan_Mode_Real 0x79 +Henkan_Mode_Ultra 0x79 +backslash_ja 0x73 diff --git a/vnc_keysym.h b/vnc_keysym.h index a4ac6885b..14fe47f9e 100644 --- a/vnc_keysym.h +++ b/vnc_keysym.h @@ -271,5 +271,15 @@ static name2keysym_t name2keysym[]={ {"Num_Lock", 0xff7f}, /* XK_Num_Lock */ {"Pause", 0xff13}, /* XK_Pause */ {"Escape", 0xff1b}, /* XK_Escape */ + + /* localized keys */ +{"BackApostrophe", 0xff21}, +{"Muhenkan", 0xff22}, +{"Katakana", 0xff25}, +{"Zenkaku_Hankaku", 0xff29}, +{"Henkan_Mode_Real", 0xff23}, +{"Henkan_Mode_Ultra", 0xff3e}, +{"backslash_ja", 0xffa5}, + {0,0}, }; -- cgit v1.2.3 From 3b9f94e1a8757ac223a51c662e4278aab738f0cd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Jan 2007 17:27:07 +0000 Subject: win32 block device fixes (initial patch by kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2305 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 17 ++++++++++++----- block.c | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/block-raw.c b/block-raw.c index 9fe953c30..1401e8215 100644 --- a/block-raw.c +++ b/block-raw.c @@ -906,13 +906,13 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) create_flags = OPEN_EXISTING; } #ifdef QEMU_TOOL - overlapped = 0; + overlapped = FILE_ATTRIBUTE_NORMAL; #else overlapped = FILE_FLAG_OVERLAPPED; #endif s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, - create_flags, overlapped, 0); + create_flags, overlapped, NULL); if (s->hfile == INVALID_HANDLE_VALUE) return -1; return 0; @@ -962,6 +962,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, return ret_count; } +#if 0 #ifndef QEMU_TOOL static void raw_aio_cb(void *opaque) { @@ -1064,10 +1065,12 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb) qemu_aio_release(acb); #endif } +#endif /* #if 0 */ static void raw_flush(BlockDriverState *bs) { - /* XXX: add it */ + BDRVRawState *s = bs->opaque; + FlushFileBuffers(s->hfile); } static void raw_close(BlockDriverState *bs) @@ -1143,6 +1146,10 @@ void qemu_aio_flush(void) { } +void qemu_aio_flush(void) +{ +} + void qemu_aio_wait_start(void) { } @@ -1254,13 +1261,13 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) create_flags = OPEN_EXISTING; #ifdef QEMU_TOOL - overlapped = 0; + overlapped = FILE_ATTRIBUTE_NORMAL; #else overlapped = FILE_FLAG_OVERLAPPED; #endif s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, - create_flags, overlapped, 0); + create_flags, overlapped, NULL); if (s->hfile == INVALID_HANDLE_VALUE) return -1; return 0; diff --git a/block.c b/block.c index 9aebaa0a4..bbece2d24 100644 --- a/block.c +++ b/block.c @@ -56,12 +56,6 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, static BlockDriverState *bdrv_first; static BlockDriver *first_drv; -#ifdef _WIN32 -#define PATH_SEP '\\' -#else -#define PATH_SEP '/' -#endif - int path_is_absolute(const char *path) { const char *p; @@ -70,7 +64,11 @@ int path_is_absolute(const char *path) p++; else p = path; - return (*p == PATH_SEP); +#ifdef _WIN32 + return (*p == '/' || *p == '\\'); +#else + return (*p == '/'); +#endif } /* if filename is absolute, just copy it to dest. Otherwise, build a @@ -93,7 +91,15 @@ void path_combine(char *dest, int dest_size, p++; else p = base_path; - p1 = strrchr(base_path, PATH_SEP); + p1 = strrchr(base_path, '/'); +#ifdef _WIN32 + { + const char *p2; + p2 = strrchr(base_path, '\\'); + if (!p1 || p2 > p1) + p1 = p2; + } +#endif if (p1) p1++; else @@ -168,7 +174,10 @@ int bdrv_create(BlockDriver *drv, #ifdef _WIN32 void get_tmp_filename(char *filename, int size) { - tmpnam(filename); + 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) @@ -996,7 +1005,11 @@ char *get_human_readable_size(char *buf, int buf_size, int64_t size) 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; @@ -1006,11 +1019,15 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); } else { ti = sn->date_sec; -#ifndef _WIN32 +#ifdef _WIN32 + ptm = localtime(&ti); + strftime(date_buf, sizeof(date_buf), + "%Y-%m-%d %H:%M:%S", ptm); +#else localtime_r(&ti, &tm); -#endif 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", -- cgit v1.2.3 From 3b39528c156638be50b713a5cc5a398a443a65c0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Jan 2007 17:33:20 +0000 Subject: removed redundant qemu_aio_flush() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2306 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/block-raw.c b/block-raw.c index 1401e8215..8cf198854 100644 --- a/block-raw.c +++ b/block-raw.c @@ -1146,10 +1146,6 @@ void qemu_aio_flush(void) { } -void qemu_aio_flush(void) -{ -} - void qemu_aio_wait_start(void) { } -- cgit v1.2.3 From 21664424ede70eebaaddae1168261e73fa46bc33 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Jan 2007 18:22:37 +0000 Subject: path_is_absolute() fix for win32 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2307 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/block.c b/block.c index bbece2d24..9264e42a6 100644 --- a/block.c +++ b/block.c @@ -59,6 +59,11 @@ 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++; -- cgit v1.2.3 From 2f67a0d55aea184ec31f81df87ba4aa07c378fdb Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 7 Jan 2007 19:38:08 +0000 Subject: Script to check for missing FORCE_RET. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2308 c046a42c-6fe2-441c-8c8c-71466251a162 --- check_ops.sh | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100755 check_ops.sh diff --git a/check_ops.sh b/check_ops.sh new file mode 100755 index 000000000..b1f2f8500 --- /dev/null +++ b/check_ops.sh @@ -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_.*!!' -- cgit v1.2.3 From 96d30e4801dd31b0fbbee4ac8977937ce0ec116f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 7 Jan 2007 20:42:14 +0000 Subject: Revert -disk patch, as requested by Fabrice. The general idea of this patch is sound, but the implementation is just too ugly. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2309 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 26 ++-- hw/sun4m.c | 6 - qemu-doc.texi | 6 - vl.c | 374 +++++++--------------------------------------------------- vl.h | 22 ---- 5 files changed, 56 insertions(+), 378 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 917d9724a..1c141ae6a 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -705,21 +705,23 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); } +#if 0 + /* ??? Need to figure out some way for the user to + specify SCSI devices. */ if (pci_enabled) { void *scsi; - - if (scsi_hba_lsi > 0) { - if (!(scsi = lsi_scsi_init(pci_bus, -1))) { - exit(1); - } - for(i = 0; i < MAX_SCSI_DISKS; i++) { - if (scsi_disks_info[i].adapter == SCSI_LSI_53C895A && - scsi_disks_info[i].device_type != SCSI_NONE) { - lsi_scsi_attach(scsi, bs_scsi_table[i], scsi_disks_info[i].id); - } - } - } + BlockDriverState *bdrv; + + scsi = lsi_scsi_init(pci_bus, -1); + bdrv = bdrv_new("scsidisk"); + bdrv_open(bdrv, "scsi_disk.img", 0); + lsi_scsi_attach(scsi, bdrv, -1); + bdrv = bdrv_new("scsicd"); + bdrv_open(bdrv, "scsi_cd.iso", 0); + bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); + lsi_scsi_attach(scsi, bdrv, -1); } +#endif } static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, diff --git a/hw/sun4m.c b/hw/sun4m.c index c6765d9e1..a636638b5 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -262,12 +262,6 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma); - for (i = 0; i < MAX_SCSI_DISKS; i++) { - if (scsi_disks_info[i].adapter == SCSI_ESP && - scsi_disks_info[i].device_type != SCSI_NONE) { - esp_scsi_attach(main_esp, bs_scsi_table[i], scsi_disks_info[i].id); - } - } slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); cs_init(PHYS_JJ_CS, PHYS_JJ_CS_IRQ, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); diff --git a/qemu-doc.texi b/qemu-doc.texi index 45f5ea412..655e15149 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -223,12 +223,6 @@ using @file{/dev/cdrom} as filename (@pxref{host_drives}). Boot on floppy (a), hard disk (c), CD-ROM (d), or Etherboot (n). Hard disk boot is the default. -@item -disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] -Use @var{file} as the IDE disk/CD-ROM image. The defaults are: hdx=a,type=disk - -@item -disk scsi,img=file[,sdx=a..g][,type=disk|cdrom][,id=n] -Use @var{file} as the SCSI disk/CD-ROM image. The defaults are: sdx=a,type=disk,id='auto assign' - @item -snapshot Write to temporary files instead of disk image files. In this case, the raw disk image you use is not written back. You can however force diff --git a/vl.c b/vl.c index e5399c730..5afa986c0 100644 --- a/vl.c +++ b/vl.c @@ -114,8 +114,6 @@ /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 -#define DISK_OPTIONS_SIZE 256 - const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; void *ioport_opaque[MAX_IOPORTS]; @@ -126,9 +124,6 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; -BlockDriverState *bs_scsi_table[MAX_SCSI_DISKS]; -SCSIDiskInfo scsi_disks_info[MAX_SCSI_DISKS]; -int scsi_hba_lsi; /* Count of scsi disks/cdrom using this lsi adapter */ int vga_ram_size; int bios_size; static DisplayState display_state; @@ -3983,178 +3978,6 @@ void do_info_network(void) } } -/* Parse IDE and SCSI disk options */ -static int disk_options_init(int num_ide_disks, - char ide_disk_options[][DISK_OPTIONS_SIZE], - int snapshot, - int num_scsi_disks, - char scsi_disk_options[][DISK_OPTIONS_SIZE], - int cdrom_index, - int cyls, - int heads, - int secs, - int translation) -{ - char buf[256]; - char dev_name[64]; - int id, i, j; - int cdrom_device; - int ide_cdrom_created = 0; - int scsi_index; - scsi_host_adapters temp_adapter; - - /* Process any IDE disks/cdroms */ - for (i=0; i< num_ide_disks; i++) { - for (j=0; j= 0 && (!ide_cdrom_created)) { - bs_table[cdrom_index] = bdrv_new("cdrom"); - bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); - } - - for(i = 0; i < num_scsi_disks; i++) { - -#if !defined(TARGET_SPARC) || defined(TARGET_SPARC64) - temp_adapter = SCSI_LSI_53C895A; - scsi_hba_lsi++; -#else - temp_adapter = SCSI_ESP; -#endif - - /*Check for sdx= parameter */ - if (get_param_value(buf, sizeof(buf), "sdx", scsi_disk_options[i])) { - if (buf[0] >= 'a' && buf[0] <= 'g') { - scsi_index = buf[0] - 'a'; - } else{ - fprintf(stderr, "qemu: sdx= option for SCSI must be one letter from a-g. %s \n",buf); - exit(1); - } - } else { - scsi_index = 0; - } - - /* Check for SCSI id specified. */ - if (get_param_value(buf, sizeof(buf),"id",scsi_disk_options[i])) { - id = strtol(buf, NULL, 0); - if (id < 0 || id > 6) { - fprintf(stderr, "qemu: SCSI id must be from 0-6: %d\n", id); - return -1; - } - /* Check if id already used */ - for(j = 0; j < MAX_SCSI_DISKS; j++) { - if (scsi_disks_info[j].device_type != SCSI_NONE && - j != i && - scsi_disks_info[j].adapter == temp_adapter && - scsi_disks_info[j].id == id ) { - fprintf(stderr, "qemu: SCSI id already used: %u\n", id); - return -1; - } - } - } else { - id = -1; - } - scsi_disks_info[i].adapter = temp_adapter; - scsi_disks_info[i].id = id; - - if (get_param_value(buf, sizeof(buf),"type",scsi_disk_options[i])) { - if (!strcmp(buf, "disk")) { - cdrom_device = 0; - } else if (!strcmp(buf, "cdrom")) { - cdrom_device = 1; - } else { - fprintf(stderr, "qemu: invalid SCSI disk type= value: %s\n", buf); - return -1; - } - } else { - cdrom_device = 0; - } - - if (cdrom_device) { - snprintf(dev_name, sizeof(buf), "cdrom%c", scsi_index + '0'); - scsi_disks_info[scsi_index].device_type = SCSI_CDROM; - } else { - snprintf(dev_name, sizeof(buf), "sd%c", scsi_index + 'a'); - scsi_disks_info[scsi_index].device_type = SCSI_DISK; - } - - if (!(bs_scsi_table[scsi_index] = bdrv_new(dev_name))) { - fprintf(stderr, "qemu: unable to create new block device for:%s\n",dev_name); - return -1; - } - - /* Get image filename from options and then try to open it */ - if (get_param_value(buf, sizeof(buf),"img",scsi_disk_options[i])) { - if (bdrv_open(bs_scsi_table[scsi_index], buf, 0) < 0) { - fprintf(stderr, "qemu: could not open SCSI disk image img='%s'\n",buf); - return -1; - } - } else { - fprintf(stderr, "qemu: SCSI disk image not specified for sd%c \n", i + 'a'); - return -1; - } - if (cdrom_device) { - bdrv_set_type_hint(bs_scsi_table[scsi_index], BDRV_TYPE_CDROM); - } - } - - return 0; -} - - /***********************************************************/ /* USB devices */ @@ -6263,10 +6086,6 @@ void help(void) "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" - "-disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] \n" - " defaults are: hdx=a,type=disk \n" - "-disk scsi,img=file[,sdx=a..g][,type=disk|cdrom][,id=n] \n" - " defaults are: sdx=a,type=disk,id='auto assign' \n" "-snapshot write to temporary files instead of disk image files\n" #ifdef CONFIG_SDL "-no-quit disable SDL window close capability\n" @@ -6448,7 +6267,6 @@ enum { QEMU_OPTION_no_acpi, QEMU_OPTION_no_reboot, QEMU_OPTION_daemonize, - QEMU_OPTION_disk, QEMU_OPTION_option_rom, }; @@ -6524,8 +6342,7 @@ const QEMUOption qemu_options[] = { { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, { "vnc", HAS_ARG, QEMU_OPTION_vnc }, - { "disk", HAS_ARG, QEMU_OPTION_disk }, - + /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, @@ -6744,11 +6561,7 @@ int main(int argc, char **argv) int i, cdrom_index; int snapshot, linux_boot; const char *initrd_filename; - const char *fd_filename[MAX_FD]; - char scsi_options[MAX_SCSI_DISKS] [DISK_OPTIONS_SIZE]; - char ide_options[MAX_DISKS] [DISK_OPTIONS_SIZE]; - int num_ide_disks; - int num_scsi_disks; + const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; @@ -6803,19 +6616,10 @@ int main(int argc, char **argv) register_machines(); machine = first_machine; initrd_filename = NULL; - for(i = 0; i < MAX_SCSI_DISKS; i++) { - scsi_disks_info[i].device_type = SCSI_NONE; - bs_scsi_table[i] = NULL; - } - - num_ide_disks = 0; - num_scsi_disks = 0; - for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; - for(i = 0; i < MAX_DISKS; i++) { - ide_options[i][0] = '\0'; - } + for(i = 0; i < MAX_DISKS; i++) + hd_filename[i] = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; @@ -6859,16 +6663,7 @@ int main(int argc, char **argv) break; r = argv[optind]; if (r[0] != '-') { - - /* Build new disk IDE syntax string */ - pstrcpy(ide_options[0], - 14, - "hdx=a,img="); - /*Add on image filename */ - pstrcpy(&(ide_options[0][13]), - sizeof(ide_options[0])-13, - argv[optind++]); - num_ide_disks++; + hd_filename[0] = argv[optind++]; } else { const QEMUOption *popt; @@ -6918,75 +6713,10 @@ int main(int argc, char **argv) case QEMU_OPTION_hdd: { int hd_index; - const char newIDE_DiskSyntax [][10] = { - "hdx=a,img=", "hdx=b,img=", "hdx=c,img=", "hdx=d,img=" }; - hd_index = popt->index - QEMU_OPTION_hda; - if (num_ide_disks >= MAX_DISKS) { - fprintf(stderr, "qemu: too many IDE disks defined.\n"); - exit(1); - } - /* Build new disk IDE syntax string */ - pstrcpy(ide_options[hd_index], - 11, - newIDE_DiskSyntax[hd_index]); - /* Add on image filename */ - pstrcpy(&(ide_options[hd_index][10]), - sizeof(ide_options[0])-10, - optarg); - num_ide_disks++; - } - break; - case QEMU_OPTION_disk: /*Combined IDE and SCSI, for disk and CDROM */ - { - const char *p_input_char; - char *p_output_string; - char device[64]; - int disk_index; - - p_input_char = optarg; - p_output_string = device; - while (*p_input_char != '\0' && *p_input_char != ',') { - if ((p_output_string - device) < sizeof(device) - 1) - *p_output_string++ = *p_input_char; - p_input_char++; - } - *p_output_string = '\0'; - if (*p_input_char == ',') - p_input_char++; - - if (!strcmp(device, "scsi")) { - if (num_scsi_disks >= MAX_SCSI_DISKS) { - fprintf(stderr, "qemu: too many SCSI disks defined.\n"); - exit(1); - } - pstrcpy(scsi_options[num_scsi_disks], - sizeof(scsi_options[0]), - p_input_char); - num_scsi_disks++; - } else if (!strcmp(device,"ide")) { - if (num_ide_disks >= MAX_DISKS) { - fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); - exit(1); - } - disk_index = 0; /* default is hda */ - if (get_param_value(device, sizeof(device),"hdx",p_input_char)) { - if (device[0] >= 'a' && device[0] <= 'd') { - disk_index = device[0] - 'a'; - } else { - fprintf(stderr, "qemu: invalid IDE disk hdx= value: %s\n", device); - return -1; - } - } - else disk_index=0; - pstrcpy(ide_options[disk_index], - sizeof(ide_options[0]), - p_input_char); - num_ide_disks++; - } else { - fprintf(stderr, "qemu: -disk option must specify IDE or SCSI: %s \n",device); - exit(1); - } + hd_filename[hd_index] = optarg; + if (hd_index == cdrom_index) + cdrom_index = -1; } break; case QEMU_OPTION_snapshot: @@ -7040,46 +6770,9 @@ int main(int argc, char **argv) kernel_cmdline = optarg; break; case QEMU_OPTION_cdrom: -#if !defined(TARGET_SPARC) || defined(TARGET_SPARC64) - /* Assume boot cdrom is IDE */ - { - char buf[22]; - if (num_ide_disks >= MAX_DISKS) { - fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); - exit(1); - } - snprintf(buf, sizeof(buf), "type=cdrom,hdx=%c,img=", cdrom_index + 'a'); - /* Build new disk IDE syntax string */ - pstrcpy(ide_options[cdrom_index], - 22, - buf); - /* Add on image filename */ - pstrcpy(&(ide_options[cdrom_index][21]), - sizeof(ide_options[0])-21, - optarg); - num_ide_disks++; - } -#else - /* Assume boot cdrom is SCSI */ - { - char buf[27]; - if (num_scsi_disks >= MAX_SCSI_DISKS) { - fprintf(stderr, "qemu: too many SCSI disks/cdroms defined.\n"); - exit(1); - } - snprintf(buf, sizeof(buf), "type=cdrom,sdx=%c,id=%d,img=", - num_scsi_disks + 'a', num_scsi_disks + 2); - /* Build new disk SCSI syntax string */ - pstrcpy(scsi_options[num_scsi_disks], - 27, - buf); - /* Add on image filename */ - pstrcpy(&(scsi_options[num_scsi_disks][26]), - sizeof(scsi_options[0])-26, - optarg); - num_scsi_disks++; + if (cdrom_index >= 0) { + hd_filename[cdrom_index] = optarg; } -#endif break; case QEMU_OPTION_boot: boot_device = optarg[0]; @@ -7376,11 +7069,19 @@ int main(int argc, char **argv) linux_boot = (kernel_filename != NULL); if (!linux_boot && - num_ide_disks == 0 && - num_scsi_disks == 0 && + hd_filename[0] == '\0' && + (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') help(); + /* boot to floppy or the default cd if no hard disk defined yet */ + if (hd_filename[0] == '\0' && boot_device == 'c') { + if (fd_filename[0] != '\0') + boot_device = 'a'; + else + boot_device = 'd'; + } + setvbuf(stdout, NULL, _IOLBF, 0); init_timers(); @@ -7446,22 +7147,31 @@ int main(int argc, char **argv) exit(1); } + /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); - - /* open the virtual block devices, disks or CDRoms */ - if (disk_options_init(num_ide_disks,ide_options,snapshot, - num_scsi_disks,scsi_options, - cdrom_index, - cyls, heads, secs, translation)){ - exit(1); + if (cdrom_index >= 0) { + bs_table[cdrom_index] = bdrv_new("cdrom"); + bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); } - /* boot to floppy or default cd if no hard disk */ - if (num_ide_disks == 0 && boot_device == 'c') { - if (fd_filename[0] != '\0') - boot_device = 'a'; - else - boot_device = 'd'; + /* open the virtual block devices */ + for(i = 0; i < MAX_DISKS; i++) { + if (hd_filename[i]) { + if (!bs_table[i]) { + char buf[64]; + snprintf(buf, sizeof(buf), "hd%c", i + 'a'); + bs_table[i] = bdrv_new(buf); + } + if (bdrv_open(bs_table[i], hd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { + fprintf(stderr, "qemu: could not open hard disk image '%s'\n", + hd_filename[i]); + exit(1); + } + if (i == 0 && cyls != 0) { + bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); + bdrv_set_translation_hint(bs_table[i], translation); + } + } } /* we always create at least one floppy disk */ diff --git a/vl.h b/vl.h index 8eef56de3..35222dc34 100644 --- a/vl.h +++ b/vl.h @@ -1252,31 +1252,9 @@ int scsi_write_data(SCSIDevice *s, uint32_t tag); void scsi_cancel_io(SCSIDevice *s, uint32_t tag); uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); -enum scsi_host_adapters { - SCSI_LSI_53C895A, - SCSI_ESP -}; -enum scsi_devices { - SCSI_CDROM, - SCSI_DISK, - SCSI_NONE -}; -typedef enum scsi_host_adapters scsi_host_adapters; -typedef enum scsi_devices scsi_devices; -typedef struct SCSIDiskInfo { - scsi_host_adapters adapter; - int id; - scsi_devices device_type; -} SCSIDiskInfo; - -#define MAX_SCSI_DISKS 7 -extern BlockDriverState *bs_scsi_table[MAX_SCSI_DISKS]; -extern SCSIDiskInfo scsi_disks_info[MAX_SCSI_DISKS]; - /* lsi53c895a.c */ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *lsi_scsi_init(PCIBus *bus, int devfn); -extern int scsi_hba_lsi; // Count of scsi disks/cdrom using this lsi adapter /* integratorcp.c */ extern QEMUMachine integratorcp926_machine; -- cgit v1.2.3 From 18607dcb7ce42da3e36f1c9bf6c77f28ebf293c8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Jan 2007 22:04:40 +0000 Subject: added cutils.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2310 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- Makefile.target | 1 + cutils.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-img.c | 43 ------------------------------ vl.c | 43 ------------------------------ vl.h | 10 ++++--- 6 files changed, 91 insertions(+), 91 deletions(-) create mode 100644 cutils.c diff --git a/Makefile b/Makefile index b88f50101..77c523727 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ subdir-%: dyngen$(EXESUF) recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) -qemu-img$(EXESUF): qemu-img.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 +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 diff --git a/Makefile.target b/Makefile.target index 7c664922c..a9cde3cf9 100644 --- a/Makefile.target +++ b/Makefile.target @@ -300,6 +300,7 @@ 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 diff --git a/cutils.c b/cutils.c new file mode 100644 index 000000000..352c47e21 --- /dev/null +++ b/cutils.c @@ -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; +} diff --git a/qemu-img.c b/qemu-img.c index 23a698db7..4bb0a5161 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -62,49 +62,6 @@ char *qemu_strdup(const char *str) return ptr; } -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; -} - void term_printf(const char *fmt, ...) { va_list ap; diff --git a/vl.c b/vl.c index 5afa986c0..3edca0ecf 100644 --- a/vl.c +++ b/vl.c @@ -306,49 +306,6 @@ void isa_unassign_ioport(int start, int length) /***********************************************************/ -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; -} - void cpu_outb(CPUState *env, int addr, int val) { #ifdef DEBUG_IOPORT diff --git a/vl.h b/vl.h index 35222dc34..ef1205cce 100644 --- a/vl.h +++ b/vl.h @@ -102,6 +102,12 @@ static inline char *realpath(const char *path, char *resolved_path) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +/* cutils.c */ +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); + /* vl.c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); @@ -109,10 +115,6 @@ void hw_error(const char *fmt, ...); extern const char *bios_dir; -void pstrcpy(char *buf, int buf_size, const char *str); -char *pstrcat(char *buf, int buf_size, const char *s); -int strstart(const char *str, const char *val, const char **ptr); - extern int vm_running; typedef struct vm_change_state_entry VMChangeStateEntry; -- cgit v1.2.3 From 01781963983206feac8c6be5ded68c3ee244c4ad Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 7 Jan 2007 22:43:30 +0000 Subject: win32: physical drive support (initial patch by kazu) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2311 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 16 +++++++++++++++- qemu-doc.texi | 19 +++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/block-raw.c b/block-raw.c index 8cf198854..2b6f441ba 100644 --- a/block-raw.c +++ b/block-raw.c @@ -838,6 +838,7 @@ BlockDriver bdrv_host_device = { #define FTYPE_FILE 0 #define FTYPE_CD 1 +#define FTYPE_HARDDISK 2 typedef struct BDRVRawState { HANDLE hfile; @@ -1098,6 +1099,9 @@ 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: @@ -1110,6 +1114,14 @@ static int64_t raw_getlength(BlockDriverState *bs) 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; } @@ -1216,6 +1228,8 @@ static int find_device_type(BlockDriverState *bs, const char *filename) 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) @@ -1248,7 +1262,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) } } s->type = find_device_type(bs, filename); - + if ((flags & BDRV_O_ACCESS) == O_RDWR) { access_flags = GENERIC_READ | GENERIC_WRITE; } else { diff --git a/qemu-doc.texi b/qemu-doc.texi index 655e15149..0423ef065 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1079,14 +1079,25 @@ line option or modify the device permissions accordingly). @subsubsection Windows -On Windows you can use any host drives as QEMU drive. The prefered -syntax is the driver letter (e.g. @file{d:}). The alternate syntax -@file{\\.\d:} is supported. @file{/dev/cdrom} is supported as an alias -to the first CDROM drive. +@table @code +@item CD +The prefered syntax is the drive letter (e.g. @file{d:}). The +alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is +supported as an alias to the first CDROM drive. Currently there is no specific code to handle removable medias, so it is better to use the @code{change} or @code{eject} monitor commands to change or eject media. +@item Hard disks +Hard disks can be used with the syntax: @file{\\.\PhysicalDriveN} +where @var{N} is the drive number (0 is the first hard disk). + +WARNING: unless you know what you do, it is better to only make +READ-ONLY accesses to the hard disk otherwise you may corrupt your +host data (use the @option{-snapshot} command line so that the +modifications are written in a temporary file). +@end table + @subsubsection Mac OS X -- cgit v1.2.3 From bf8c534200b7e69e87725a0d49eb94c0da744f91 Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 9 Jan 2007 19:44:41 +0000 Subject: ifname arg fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2312 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 3edca0ecf..1ec78a747 100644 --- a/vl.c +++ b/vl.c @@ -3886,7 +3886,9 @@ static int net_client_init(const char *str) if (net_tap_fd_init(vlan, fd)) ret = 0; } else { - get_param_value(ifname, sizeof(ifname), "ifname", p); + if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { + ifname[0] = '\0'; + } if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); } -- cgit v1.2.3 From f158755072f368d539b31851b308bec985893abb Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 10 Jan 2007 11:46:13 +0000 Subject: Restore SCSI disk attaching, by Igor Kovalenko. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2313 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/sun4m.c b/hw/sun4m.c index a636638b5..9b6aae53c 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -262,6 +262,13 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma); + + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) { + esp_scsi_attach(main_esp, bs_table[i], i); + } + } + slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); cs_init(PHYS_JJ_CS, PHYS_JJ_CS_IRQ, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); -- cgit v1.2.3 From abcebc7e803f243ef244e06349a4b911daa738f4 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 10 Jan 2007 16:17:21 +0000 Subject: Devfn number for network PCI cards, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2314 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 4 ++-- hw/pc.c | 2 +- hw/pci.c | 8 ++++---- hw/pcnet.c | 4 ++-- hw/ppc_chrp.c | 4 ++-- hw/realview.c | 2 +- hw/rtl8139.c | 4 ++-- hw/sun4u.c | 2 +- hw/versatilepb.c | 2 +- vl.h | 8 ++++---- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 94700c17b..a045a2043 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -781,7 +781,7 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); } -void pci_ne2000_init(PCIBus *bus, NICInfo *nd) +void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) { PCINE2000State *d; NE2000State *s; @@ -789,7 +789,7 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd) d = (PCINE2000State *)pci_register_device(bus, "NE2000", sizeof(PCINE2000State), - -1, + devfn, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0xec; // Realtek 8029 diff --git a/hw/pc.c b/hw/pc.c index 1c141ae6a..408a9fb24 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -668,7 +668,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (strcmp(nd->model, "ne2k_isa") == 0) { pc_init_ne2k_isa(nd); } else if (pci_enabled) { - pci_nic_init(pci_bus, nd); + pci_nic_init(pci_bus, nd, -1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit(1); diff --git a/hw/pci.c b/hw/pci.c index d8fcd7be5..b895f98a0 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -544,14 +544,14 @@ void pci_info(void) } /* Initialize a PCI NIC. */ -void pci_nic_init(PCIBus *bus, NICInfo *nd) +void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn) { if (strcmp(nd->model, "ne2k_pci") == 0) { - pci_ne2000_init(bus, nd); + pci_ne2000_init(bus, nd, devfn); } else if (strcmp(nd->model, "rtl8139") == 0) { - pci_rtl8139_init(bus, nd); + pci_rtl8139_init(bus, nd, devfn); } else if (strcmp(nd->model, "pcnet") == 0) { - pci_pcnet_init(bus, nd); + pci_pcnet_init(bus, nd, devfn); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit (1); diff --git a/hw/pcnet.c b/hw/pcnet.c index f242cd1e9..3bdddeb38 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1889,7 +1889,7 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, cpu_physical_memory_read(addr, buf, len); } -void pci_pcnet_init(PCIBus *bus, NICInfo *nd) +void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) { PCNetState *d; uint8_t *pci_conf; @@ -1900,7 +1900,7 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd) #endif d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), - -1, NULL, NULL); + devfn, NULL, NULL); pci_conf = d->dev.config; diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 7599eab91..1e0fd2e9d 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -436,7 +436,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i]); + pci_nic_init(pci_bus, &nd_table[i], -1); } pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); @@ -483,7 +483,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(pci_bus, &nd_table[i]); + pci_ne2000_init(pci_bus, &nd_table[i], -1); } #if 1 diff --git a/hw/realview.c b/hw/realview.c index 11b091608..6d057cee0 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -71,7 +71,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, if (strcmp(nd->model, "smc91c111") == 0) { smc91c111_init(nd, 0x4e000000, pic, 28); } else { - pci_nic_init(pci_bus, nd); + pci_nic_init(pci_bus, nd, -1); } } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index db6353a7e..94fc2fca3 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3409,7 +3409,7 @@ static void rtl8139_timer(void *opaque) } #endif /* RTL8139_ONBOARD_TIMER */ -void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) +void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) { PCIRTL8139State *d; RTL8139State *s; @@ -3417,7 +3417,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) d = (PCIRTL8139State *)pci_register_device(bus, "RTL8139", sizeof(PCIRTL8139State), - -1, + devfn, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0xec; /* Realtek 8139 */ diff --git a/hw/sun4u.c b/hw/sun4u.c index 6d413691d..61069a652 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -344,7 +344,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i]); + pci_nic_init(pci_bus, &nd_table[i], -1); } pci_cmd646_ide_init(pci_bus, bs_table, 1); diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 475cb4892..12b73037e 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -188,7 +188,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, if (strcmp(nd->model, "smc91c111") == 0) { smc91c111_init(nd, 0x10010000, sic, 25); } else { - pci_nic_init(pci_bus, nd); + pci_nic_init(pci_bus, nd, -1); } } if (usb_enabled) { diff --git a/vl.h b/vl.h index ef1205cce..8667ba8f3 100644 --- a/vl.h +++ b/vl.h @@ -793,7 +793,7 @@ typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *pic, int devfn_min, int nirq); -void pci_nic_init(PCIBus *bus, NICInfo *nd); +void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn); void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); uint32_t pci_data_read(void *opaque, uint32_t addr, int len); int pci_bus_num(PCIBus *s); @@ -956,15 +956,15 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); /* ne2000.c */ void isa_ne2000_init(int base, int irq, NICInfo *nd); -void pci_ne2000_init(PCIBus *bus, NICInfo *nd); +void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn); /* rtl8139.c */ -void pci_rtl8139_init(PCIBus *bus, NICInfo *nd); +void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); /* pcnet.c */ -void pci_pcnet_init(PCIBus *bus, NICInfo *nd); +void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); void pcnet_h_reset(void *opaque); void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque); -- cgit v1.2.3 From 8f1c91d801b56fa68a0c297e0405edf6a22c0586 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 10 Jan 2007 16:23:41 +0000 Subject: Devfn number for the PIIX3 southbridge, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2315 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- hw/piix_pci.c | 6 +++--- vl.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 408a9fb24..73f7609ae 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -599,7 +599,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled) { pci_bus = i440fx_init(&i440fx_state); - piix3_devfn = piix3_init(pci_bus); + piix3_devfn = piix3_init(pci_bus, -1); } else { pci_bus = NULL; } diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 155769447..9b3e7533b 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -196,7 +196,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state) /* PIIX3 PCI to ISA bridge */ -static PCIDevice *piix3_dev; +PCIDevice *piix3_dev; /* just used for simpler irq handling. */ #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) @@ -273,13 +273,13 @@ static int piix_load(QEMUFile* f, void *opaque, int version_id) return pci_device_load(d, f); } -int piix3_init(PCIBus *bus) +int piix3_init(PCIBus *bus, int devfn) { PCIDevice *d; uint8_t *pci_conf; d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice), - -1, NULL, NULL); + devfn, NULL, NULL); register_savevm("PIIX3", 0, 2, piix_save, piix_load, d); piix3_dev = d; diff --git a/vl.h b/vl.h index 8667ba8f3..b1be8c23e 100644 --- a/vl.h +++ b/vl.h @@ -821,7 +821,7 @@ PCIBus *pci_vpb_init(void *pic, int irq, int realview); /* piix_pci.c */ PCIBus *i440fx_init(PCIDevice **pi440fx_state); void i440fx_set_smm(PCIDevice *d, int val); -int piix3_init(PCIBus *bus); +int piix3_init(PCIBus *bus, int devfn); void i440fx_init_memory_mappings(PCIDevice *d); /* openpic.c */ -- cgit v1.2.3 From 567daa491f5a155ccd64edd0f4044c5527b488b2 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 10 Jan 2007 16:25:04 +0000 Subject: Increase MIPS BIOS from 128kB to 4MB, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2316 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.h b/vl.h index b1be8c23e..db367c13b 100644 --- a/vl.h +++ b/vl.h @@ -168,7 +168,7 @@ extern int nb_option_roms; #if defined (TARGET_PPC) || defined (TARGET_SPARC64) #define BIOS_SIZE ((512 + 32) * 1024) #elif defined(TARGET_MIPS) -#define BIOS_SIZE (128 * 1024) +#define BIOS_SIZE (4 * 1024 * 1024) #else #define BIOS_SIZE ((256 + 64) * 1024) #endif -- cgit v1.2.3 From 5c2b87e34df1f00d8bb788b01a7506351421c10e Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 15 Jan 2007 17:08:08 +0000 Subject: PIIX4 support, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2317 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/piix_pci.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 9b3e7533b..b2b7bf0cc 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -197,6 +197,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state) /* PIIX3 PCI to ISA bridge */ PCIDevice *piix3_dev; +PCIDevice *piix4_dev; /* just used for simpler irq handling. */ #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) @@ -259,6 +260,44 @@ static void piix3_reset(PCIDevice *d) pci_conf[0xae] = 0x00; } +static void piix4_reset(PCIDevice *d) +{ + uint8_t *pci_conf = d->config; + + pci_conf[0x04] = 0x07; // master, memory and I/O + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x00; + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium + pci_conf[0x4c] = 0x4d; + pci_conf[0x4e] = 0x03; + pci_conf[0x4f] = 0x00; + pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10 + pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10 + pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11 + pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11 + pci_conf[0x69] = 0x02; + pci_conf[0x70] = 0x80; + pci_conf[0x76] = 0x0c; + pci_conf[0x77] = 0x0c; + pci_conf[0x78] = 0x02; + pci_conf[0x79] = 0x00; + pci_conf[0x80] = 0x00; + pci_conf[0x82] = 0x00; + pci_conf[0xa0] = 0x08; + pci_conf[0xa0] = 0x08; + pci_conf[0xa2] = 0x00; + pci_conf[0xa3] = 0x00; + pci_conf[0xa4] = 0x00; + pci_conf[0xa5] = 0x00; + pci_conf[0xa6] = 0x00; + pci_conf[0xa7] = 0x00; + pci_conf[0xa8] = 0x0f; + pci_conf[0xaa] = 0x00; + pci_conf[0xab] = 0x00; + pci_conf[0xac] = 0x00; + pci_conf[0xae] = 0x00; +} + static void piix_save(QEMUFile* f, void *opaque) { PCIDevice *d = opaque; @@ -296,3 +335,27 @@ int piix3_init(PCIBus *bus, int devfn) piix3_reset(d); return d->devfn; } + +int piix4_init(PCIBus *bus, int devfn) +{ + PCIDevice *d; + uint8_t *pci_conf; + + d = pci_register_device(bus, "PIIX4", sizeof(PCIDevice), + devfn, NULL, NULL); + register_savevm("PIIX4", 0, 2, piix_save, piix_load, d); + + piix4_dev = d; + pci_conf = d->config; + + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x10; // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge + pci_conf[0x03] = 0x71; + pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA + pci_conf[0x0b] = 0x06; // class_base = PCI_bridge + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic + + piix4_reset(d); + return d->devfn; +} -- cgit v1.2.3 From fde7d5bd733fd64bdbf9600d1d5d83c96d004a62 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 15 Jan 2007 18:32:02 +0000 Subject: Gallileo GT64xxx support, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2318 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 3 + 2 files changed, 585 insertions(+) create mode 100644 hw/gt64xxx.c diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c new file mode 100644 index 000000000..4354a1462 --- /dev/null +++ b/hw/gt64xxx.c @@ -0,0 +1,582 @@ +/* + * QEMU GT64120 PCI host + * + * Copyright (c) 2006 Aurelien Jarno + * + * 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" +typedef target_phys_addr_t pci_addr_t; +#include "pci_host.h" + +#define GT_REGS (0x1000 >> 2) + +/* CPU Configuration */ +#define GT_CPU (0x000 >> 2) +#define GT_MULTI (0x120 >> 2) + +/* CPU Address Decode */ +#define GT_SCS10LD (0x008 >> 2) +#define GT_SCS10HD (0x010 >> 2) +#define GT_SCS32LD (0x018 >> 2) +#define GT_SCS32HD (0x020 >> 2) +#define GT_CS20LD (0x028 >> 2) +#define GT_CS20HD (0x030 >> 2) +#define GT_CS3BOOTLD (0x038 >> 2) +#define GT_CS3BOOTHD (0x040 >> 2) +#define GT_PCI0IOLD (0x048 >> 2) +#define GT_PCI0IOHD (0x050 >> 2) +#define GT_PCI0M0LD (0x058 >> 2) +#define GT_PCI0M0HD (0x060 >> 2) +#define GT_ISD (0x068 >> 2) + +#define GT_PCI0M1LD (0x080 >> 2) +#define GT_PCI0M1HD (0x088 >> 2) +#define GT_PCI1IOLD (0x090 >> 2) +#define GT_PCI1IOHD (0x098 >> 2) +#define GT_PCI1M0LD (0x0a0 >> 2) +#define GT_PCI1M0HD (0x0a8 >> 2) +#define GT_PCI1M1LD (0x0b0 >> 2) +#define GT_PCI1M1HD (0x0b8 >> 2) +#define GT_PCI1M1LD (0x0b0 >> 2) +#define GT_PCI1M1HD (0x0b8 >> 2) + +#define GT_SCS10AR (0x0d0 >> 2) +#define GT_SCS32AR (0x0d8 >> 2) +#define GT_CS20R (0x0e0 >> 2) +#define GT_CS3BOOTR (0x0e8 >> 2) + +#define GT_PCI0IOREMAP (0x0f0 >> 2) +#define GT_PCI0M0REMAP (0x0f8 >> 2) +#define GT_PCI0M1REMAP (0x100 >> 2) +#define GT_PCI1IOREMAP (0x108 >> 2) +#define GT_PCI1M0REMAP (0x110 >> 2) +#define GT_PCI1M1REMAP (0x118 >> 2) + +/* CPU Error Report */ +#define GT_CPUERR_ADDRLO (0x070 >> 2) +#define GT_CPUERR_ADDRHI (0x078 >> 2) +#define GT_CPUERR_DATALO (0x128 >> 2) /* GT-64120A only */ +#define GT_CPUERR_DATAHI (0x130 >> 2) /* GT-64120A only */ +#define GT_CPUERR_PARITY (0x138 >> 2) /* GT-64120A only */ + +/* CPU Sync Barrier */ +#define GT_PCI0SYNC (0x0c0 >> 2) +#define GT_PCI1SYNC (0x0c8 >> 2) + +/* SDRAM and Device Address Decode */ +#define GT_SCS0LD (0x400 >> 2) +#define GT_SCS0HD (0x404 >> 2) +#define GT_SCS1LD (0x408 >> 2) +#define GT_SCS1HD (0x40c >> 2) +#define GT_SCS2LD (0x410 >> 2) +#define GT_SCS2HD (0x414 >> 2) +#define GT_SCS3LD (0x418 >> 2) +#define GT_SCS3HD (0x41c >> 2) +#define GT_CS0LD (0x420 >> 2) +#define GT_CS0HD (0x424 >> 2) +#define GT_CS1LD (0x428 >> 2) +#define GT_CS1HD (0x42c >> 2) +#define GT_CS2LD (0x430 >> 2) +#define GT_CS2HD (0x434 >> 2) +#define GT_CS3LD (0x438 >> 2) +#define GT_CS3HD (0x43c >> 2) +#define GT_BOOTLD (0x440 >> 2) +#define GT_BOOTHD (0x444 >> 2) +#define GT_ADERR (0x470 >> 2) + +/* SDRAM Configuration */ +#define GT_SDRAM_CFG (0x448 >> 2) +#define GT_SDRAM_OPMODE (0x474 >> 2) +#define GT_SDRAM_BM (0x478 >> 2) +#define GT_SDRAM_ADDRDECODE (0x47c >> 2) + +/* SDRAM Parameters */ +#define GT_SDRAM_B0 (0x44c >> 2) +#define GT_SDRAM_B1 (0x450 >> 2) +#define GT_SDRAM_B2 (0x454 >> 2) +#define GT_SDRAM_B3 (0x458 >> 2) + +/* Device Parameters */ +#define GT_DEV_B0 (0x45c >> 2) +#define GT_DEV_B1 (0x460 >> 2) +#define GT_DEV_B2 (0x464 >> 2) +#define GT_DEV_B3 (0x468 >> 2) +#define GT_DEV_BOOT (0x46c >> 2) + +/* ECC */ +#define GT_ECC_ERRDATALO (0x480 >> 2) /* GT-64120A only */ +#define GT_ECC_ERRDATAHI (0x484 >> 2) /* GT-64120A only */ +#define GT_ECC_MEM (0x488 >> 2) /* GT-64120A only */ +#define GT_ECC_CALC (0x48c >> 2) /* GT-64120A only */ +#define GT_ECC_ERRADDR (0x490 >> 2) /* GT-64120A only */ + +/* DMA Record */ +#define GT_DMA0_CNT (0x800 >> 2) +#define GT_DMA1_CNT (0x804 >> 2) +#define GT_DMA2_CNT (0x808 >> 2) +#define GT_DMA3_CNT (0x80c >> 2) +#define GT_DMA0_SA (0x810 >> 2) +#define GT_DMA1_SA (0x814 >> 2) +#define GT_DMA2_SA (0x818 >> 2) +#define GT_DMA3_SA (0x81c >> 2) +#define GT_DMA0_DA (0x820 >> 2) +#define GT_DMA1_DA (0x824 >> 2) +#define GT_DMA2_DA (0x828 >> 2) +#define GT_DMA3_DA (0x82c >> 2) +#define GT_DMA0_NEXT (0x830 >> 2) +#define GT_DMA1_NEXT (0x834 >> 2) +#define GT_DMA2_NEXT (0x838 >> 2) +#define GT_DMA3_NEXT (0x83c >> 2) +#define GT_DMA0_CUR (0x870 >> 2) +#define GT_DMA1_CUR (0x874 >> 2) +#define GT_DMA2_CUR (0x878 >> 2) +#define GT_DMA3_CUR (0x87c >> 2) + +/* DMA Channel Control */ +#define GT_DMA0_CTRL (0x840 >> 2) +#define GT_DMA1_CTRL (0x844 >> 2) +#define GT_DMA2_CTRL (0x848 >> 2) +#define GT_DMA3_CTRL (0x84c >> 2) + +/* DMA Arbiter */ +#define GT_DMA_ARB (0x860 >> 2) + +/* Timer/Counter */ +#define GT_TC0 (0x850 >> 2) +#define GT_TC1 (0x854 >> 2) +#define GT_TC2 (0x858 >> 2) +#define GT_TC3 (0x85c >> 2) +#define GT_TC_CONTROL (0x864 >> 2) + +/* PCI Internal */ +#define GT_PCI0_CMD (0xc00 >> 2) +#define GT_PCI0_TOR (0xc04 >> 2) +#define GT_PCI0_BS_SCS10 (0xc08 >> 2) +#define GT_PCI0_BS_SCS32 (0xc0c >> 2) +#define GT_PCI0_BS_CS20 (0xc10 >> 2) +#define GT_PCI0_BS_CS3BT (0xc14 >> 2) +#define GT_PCI1_IACK (0xc30 >> 2) +#define GT_PCI0_IACK (0xc34 >> 2) +#define GT_PCI0_BARE (0xc3c >> 2) +#define GT_PCI0_PREFMBR (0xc40 >> 2) +#define GT_PCI0_SCS10_BAR (0xc48 >> 2) +#define GT_PCI0_SCS32_BAR (0xc4c >> 2) +#define GT_PCI0_CS20_BAR (0xc50 >> 2) +#define GT_PCI0_CS3BT_BAR (0xc54 >> 2) +#define GT_PCI0_SSCS10_BAR (0xc58 >> 2) +#define GT_PCI0_SSCS32_BAR (0xc5c >> 2) +#define GT_PCI0_SCS3BT_BAR (0xc64 >> 2) +#define GT_PCI1_CMD (0xc80 >> 2) +#define GT_PCI1_TOR (0xc84 >> 2) +#define GT_PCI1_BS_SCS10 (0xc88 >> 2) +#define GT_PCI1_BS_SCS32 (0xc8c >> 2) +#define GT_PCI1_BS_CS20 (0xc90 >> 2) +#define GT_PCI1_BS_CS3BT (0xc94 >> 2) +#define GT_PCI1_BARE (0xcbc >> 2) +#define GT_PCI1_PREFMBR (0xcc0 >> 2) +#define GT_PCI1_SCS10_BAR (0xcc8 >> 2) +#define GT_PCI1_SCS32_BAR (0xccc >> 2) +#define GT_PCI1_CS20_BAR (0xcd0 >> 2) +#define GT_PCI1_CS3BT_BAR (0xcd4 >> 2) +#define GT_PCI1_SSCS10_BAR (0xcd8 >> 2) +#define GT_PCI1_SSCS32_BAR (0xcdc >> 2) +#define GT_PCI1_SCS3BT_BAR (0xce4 >> 2) +#define GT_PCI1_CFGADDR (0xcf0 >> 2) +#define GT_PCI1_CFGDATA (0xcf4 >> 2) +#define GT_PCI0_CFGADDR (0xcf8 >> 2) +#define GT_PCI0_CFGDATA (0xcfc >> 2) + +/* Interrupts */ +#define GT_INTRCAUSE (0xc18 >> 2) +#define GT_INTRMASK (0xc1c >> 2) +#define GT_PCI0_ICMASK (0xc24 >> 2) +#define GT_PCI0_SERR0MASK (0xc28 >> 2) +#define GT_CPU_INTSEL (0xc70 >> 2) +#define GT_PCI0_INTSEL (0xc74 >> 2) +#define GT_HINTRCAUSE (0xc98 >> 2) +#define GT_HINTRMASK (0xc9c >> 2) +#define GT_PCI0_HICMASK (0xca4 >> 2) +#define GT_PCI1_SERR1MASK (0xca8 >> 2) + + +typedef PCIHostState GT64120PCIState; + +typedef struct GT64120State { + GT64120PCIState *pci; + uint32_t regs[GT_REGS]; +} GT64120State; + +static void gt64120_pci_mapping(GT64120State *s) +{ + target_phys_addr_t start, length; + + /* Update IO mapping */ + start = s->regs[GT_PCI0IOLD] << 21; + length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; + isa_mmio_init(start, length); +} + +static void gt64120_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + GT64120State *s = opaque; + uint32_t saddr; + + saddr = (addr & 0xfff) >> 2; + switch (saddr) { + /* CPU Configuration Register */ + case GT_CPU: + s->regs[GT_CPU] = val; + gt64120_pci_mapping(s); + break; + case GT_MULTI: + break; + + /* CPU Address Decode */ + case GT_PCI0IOLD: + s->regs[GT_PCI0IOLD] = val & 0x00007fff; + s->regs[GT_PCI0IOREMAP] = val & 0x000007ff; + gt64120_pci_mapping(s); + break; + case GT_PCI0M0LD: + s->regs[GT_PCI0M0LD] = val & 0x00007fff; + s->regs[GT_PCI0M0REMAP] = val & 0x000007ff; + gt64120_pci_mapping(s); + break; + case GT_PCI0M1LD: + s->regs[GT_PCI0M1LD] = val & 0x00007fff; + s->regs[GT_PCI0M1REMAP] = val & 0x000007ff; + gt64120_pci_mapping(s); + break; + case GT_PCI1IOLD: + s->regs[GT_PCI1IOLD] = val & 0x00007fff; + s->regs[GT_PCI1IOREMAP] = val & 0x000007ff; + gt64120_pci_mapping(s); + break; + case GT_PCI1M0LD: + s->regs[GT_PCI1M0LD] = val & 0x00007fff; + s->regs[GT_PCI1M0REMAP] = val & 0x000007ff; + gt64120_pci_mapping(s); + break; + case GT_PCI1M1LD: + s->regs[GT_PCI1M1LD] = val & 0x00007fff; + s->regs[GT_PCI1M1REMAP] = val & 0x000007ff; + gt64120_pci_mapping(s); + break; + case GT_PCI0IOHD: + case GT_PCI0M0HD: + case GT_PCI0M1HD: + case GT_PCI1IOHD: + case GT_PCI1M0HD: + case GT_PCI1M1HD: + s->regs[saddr] = val & 0x0000007f; + gt64120_pci_mapping(s); + break; + case GT_PCI0IOREMAP: + case GT_PCI0M0REMAP: + case GT_PCI0M1REMAP: + case GT_PCI1IOREMAP: + case GT_PCI1M0REMAP: + case GT_PCI1M1REMAP: + s->regs[saddr] = val & 0x000007ff; + gt64120_pci_mapping(s); + break; + + /* CPU Error Report */ + case GT_CPUERR_ADDRLO: + case GT_CPUERR_ADDRHI: + case GT_CPUERR_DATALO: + case GT_CPUERR_DATAHI: + case GT_CPUERR_PARITY: + break; + + /* ECC */ + case GT_ECC_ERRDATALO: + case GT_ECC_ERRDATAHI: + case GT_ECC_MEM: + case GT_ECC_CALC: + case GT_ECC_ERRADDR: + break; + + /* PCI Internal */ + case GT_PCI0_CMD: + case GT_PCI1_CMD: + s->regs[saddr] = val & 0x0401fc0f; + break; + case GT_PCI0_CFGADDR: + s->pci->config_reg = val & 0x80fffffc; + break; + case GT_PCI0_CFGDATA: + pci_host_data_writel(s->pci, 0, val); + break; + + default: +#if 0 + printf ("gt64120_writel: Bad register offset 0x%x\n", (int)addr); +#endif + break; + } +} + +static uint32_t gt64120_readl (void *opaque, + target_phys_addr_t addr) +{ + GT64120State *s = opaque; + uint32_t val; + uint32_t saddr; + + val = 0; + saddr = (addr & 0xfff) >> 2; + + switch (saddr) { + + /* CPU Error Report */ + case GT_CPUERR_ADDRLO: + case GT_CPUERR_ADDRHI: + case GT_CPUERR_DATALO: + case GT_CPUERR_DATAHI: + case GT_CPUERR_PARITY: + return 0; + break; + + /* ECC */ + case GT_ECC_ERRDATALO: + case GT_ECC_ERRDATAHI: + case GT_ECC_MEM: + case GT_ECC_CALC: + case GT_ECC_ERRADDR: + return 0; + break; + + case GT_CPU: + case GT_MULTI: + case GT_PCI0IOLD: + case GT_PCI0M0LD: + case GT_PCI0M1LD: + case GT_PCI1IOLD: + case GT_PCI1M0LD: + case GT_PCI1M1LD: + case GT_PCI0IOHD: + case GT_PCI0M0HD: + case GT_PCI0M1HD: + case GT_PCI1IOHD: + case GT_PCI1M0HD: + case GT_PCI1M1HD: + case GT_PCI0_CMD: + case GT_PCI1_CMD: + case GT_PCI0IOREMAP: + case GT_PCI0M0REMAP: + case GT_PCI0M1REMAP: + case GT_PCI1IOREMAP: + case GT_PCI1M0REMAP: + case GT_PCI1M1REMAP: + val = s->regs[saddr]; + break; + case GT_PCI0_IACK: + val = pic_intack_read(isa_pic); + break; + + /* PCI Internal */ + case GT_PCI0_CFGADDR: + val = s->pci->config_reg; + break; + case GT_PCI0_CFGDATA: + val = pci_host_data_readl(s->pci, 0); + break; + + default: + val = s->regs[saddr]; +#if 0 + printf ("gt64120_readl: Bad register offset 0x%x\n", (int)addr); +#endif + break; + } + + return val; +} + +static CPUWriteMemoryFunc *gt64120_write[] = { + >64120_writel, + >64120_writel, + >64120_writel, +}; + +static CPUReadMemoryFunc *gt64120_read[] = { + >64120_readl, + >64120_readl, + >64120_readl, +}; + +static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num) +{ + int slot; + + slot = (pci_dev->devfn >> 3); + + switch (slot) { + /* PIIX4 USB */ + case 10: + return 3; + /* AMD 79C973 Ethernet */ + case 11: + return 0; + /* Crystal 4281 Sound */ + case 12: + return 0; + /* PCI slot 1 to 4 */ + case 18 ... 21: + return ((slot - 18) + irq_num) & 0x03; + /* Unknown device, don't do any translation */ + default: + return irq_num; + } +} + +extern PCIDevice *piix4_dev; +static int pci_irq_levels[4]; + +static void pci_gt64120_set_irq(void *pic, int irq_num, int level) +{ + int i, pic_irq, pic_level; + + pci_irq_levels[irq_num] = level; + + /* now we change the pic irq level according to the piix irq mappings */ + /* XXX: optimize */ + pic_irq = piix4_dev->config[0x60 + irq_num]; + if (pic_irq < 16) { + /* The pic level is the logical OR of all the PCI irqs mapped + to it */ + pic_level = 0; + for (i = 0; i < 4; i++) { + if (pic_irq == piix4_dev->config[0x60 + i]) + pic_level |= pci_irq_levels[i]; + } + pic_set_irq(pic_irq, pic_level); + } +} + + +void gt64120_reset(void *opaque) +{ + GT64120State *s = opaque; + + /* CPU Configuration */ +#ifdef TARGET_WORDS_BIGENDIAN + s->regs[GT_CPU] = 0x00000000; +#else + s->regs[GT_CPU] = 0x00000800; +#endif + s->regs[GT_MULTI] = 0x00000000; + + /* CPU Address decode FIXME: not complete*/ + s->regs[GT_PCI0IOLD] = 0x00000080; + s->regs[GT_PCI0IOHD] = 0x0000000f; + s->regs[GT_PCI0M0LD] = 0x00000090; + s->regs[GT_PCI0M0HD] = 0x0000001f; + s->regs[GT_PCI0M1LD] = 0x00000790; + s->regs[GT_PCI0M1HD] = 0x0000001f; + s->regs[GT_PCI1IOLD] = 0x00000100; + s->regs[GT_PCI1IOHD] = 0x0000000f; + s->regs[GT_PCI1M0LD] = 0x00000110; + s->regs[GT_PCI1M0HD] = 0x0000001f; + s->regs[GT_PCI1M1LD] = 0x00000120; + s->regs[GT_PCI1M1HD] = 0x0000002f; + s->regs[GT_PCI0IOREMAP] = 0x00000080; + s->regs[GT_PCI0M0REMAP] = 0x00000090; + s->regs[GT_PCI0M1REMAP] = 0x00000790; + s->regs[GT_PCI1IOREMAP] = 0x00000100; + s->regs[GT_PCI1M0REMAP] = 0x00000110; + s->regs[GT_PCI1M1REMAP] = 0x00000120; + + /* CPU Error Report */ + s->regs[GT_CPUERR_ADDRLO] = 0x00000000; + s->regs[GT_CPUERR_ADDRHI] = 0x00000000; + s->regs[GT_CPUERR_DATALO] = 0xffffffff; + s->regs[GT_CPUERR_DATAHI] = 0xffffffff; + s->regs[GT_CPUERR_PARITY] = 0x000000ff; + + /* ECC */ + s->regs[GT_ECC_ERRDATALO] = 0x00000000; + s->regs[GT_ECC_ERRDATAHI] = 0x00000000; + s->regs[GT_ECC_MEM] = 0x00000000; + s->regs[GT_ECC_CALC] = 0x00000000; + s->regs[GT_ECC_ERRADDR] = 0x00000000; + + /* PCI Internal FIXME: not complete*/ +#ifdef TARGET_WORDS_BIGENDIAN + s->regs[GT_PCI0_CMD] = 0x00000000; + s->regs[GT_PCI1_CMD] = 0x00000000; +#else + s->regs[GT_PCI0_CMD] = 0x00010001; + s->regs[GT_PCI1_CMD] = 0x00010001; +#endif + s->regs[GT_PCI0_IACK] = 0x00000000; + s->regs[GT_PCI1_IACK] = 0x00000000; + + gt64120_pci_mapping(s); +} + +PCIBus *pci_gt64120_init(void *pic) +{ + GT64120State *s; + PCIDevice *d; + int gt64120; + + s = qemu_mallocz(sizeof(GT64120State)); + s->pci = qemu_mallocz(sizeof(GT64120PCIState)); + gt64120_reset(s); + + s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq, + pic, 144, 4); + + gt64120 = cpu_register_io_memory(0, gt64120_read, + gt64120_write, s); + cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120); + + d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), + 0, NULL, NULL); + + d->config[0x00] = 0xab; // vendor_id + d->config[0x01] = 0x11; + d->config[0x02] = 0x46; // device_id + d->config[0x03] = 0x20; + d->config[0x04] = 0x06; + d->config[0x05] = 0x00; + d->config[0x06] = 0x80; + d->config[0x07] = 0xa2; + d->config[0x08] = 0x10; + d->config[0x09] = 0x00; + d->config[0x0A] = 0x80; + d->config[0x0B] = 0x05; + d->config[0x0C] = 0x08; + d->config[0x0D] = 0x40; + d->config[0x0E] = 0x00; + d->config[0x0F] = 0x00; + d->config[0x17] = 0x08; + d->config[0x1B] = 0x1c; + d->config[0x1F] = 0x1f; + d->config[0x23] = 0x14; + d->config[0x27] = 0x14; + d->config[0x3D] = 0x01; + + return s->pci->bus; +} diff --git a/vl.h b/vl.h index db367c13b..759d2d3d5 100644 --- a/vl.h +++ b/vl.h @@ -835,6 +835,9 @@ typedef struct HeathrowPICS HeathrowPICS; void heathrow_pic_set_irq(void *opaque, int num, int level); HeathrowPICS *heathrow_pic_init(int *pmem_index); +/* gt64xxx.c */ +PCIBus *pci_gt64120_init(void *pic); + #ifdef HAS_AUDIO struct soundhw { const char *name; -- cgit v1.2.3 From 5856de800df5789b8641c47be5399afff7773910 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 15 Jan 2007 23:58:11 +0000 Subject: MIPS Malta system and devices support, by Aurelien Jarno and Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2319 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 6 +- hw/mips_malta.c | 590 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 1 + vl.h | 6 + 4 files changed, 601 insertions(+), 2 deletions(-) create mode 100644 hw/mips_malta.c diff --git a/Makefile.target b/Makefile.target index a9cde3cf9..5973211c3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -361,8 +361,10 @@ VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o CPPFLAGS += -DHAS_AUDIO 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 +VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o dma.o vga.o serial.o i8254.o i8259.o +VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o +VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) +DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) diff --git a/hw/mips_malta.c b/hw/mips_malta.c new file mode 100644 index 000000000..cf26655d7 --- /dev/null +++ b/hw/mips_malta.c @@ -0,0 +1,590 @@ +/* + * QEMU Malta board support + * + * Copyright (c) 2006 Aurelien Jarno + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "vl.h" + +#define BIOS_FILENAME "mips_bios.bin" +#ifdef MIPS_HAS_MIPS64 +#define INITRD_LOAD_ADDR (uint64_t)0x80800000 +#define ENVP_ADDR (uint64_t)0x80002000 +#else +#define INITRD_LOAD_ADDR (uint32_t)0x80800000 +#define ENVP_ADDR (uint32_t)0x80002000 +#endif + +#define VIRT_TO_PHYS_ADDEND (-((uint64_t)(uint32_t)0x80000000)) + +#define ENVP_NB_ENTRIES 16 +#define ENVP_ENTRY_SIZE 256 + + +extern FILE *logfile; + +typedef struct { + uint32_t leds; + uint32_t brk; + uint32_t gpout; + uint32_t i2coe; + uint32_t i2cout; + uint32_t i2csel; + CharDriverState *display; + char display_text[9]; +} MaltaFPGAState; + +static PITState *pit; + +static void pic_irq_request(void *opaque, int level) +{ + CPUState *env = first_cpu; + if (level) { + env->CP0_Cause |= 0x00000400; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + env->CP0_Cause &= ~0x00000400; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +/* Malta FPGA */ +static void malta_fpga_update_display(void *opaque) +{ + char leds_text[9]; + int i; + MaltaFPGAState *s = opaque; + + for (i = 7 ; i >= 0 ; i--) { + if (s->leds & (1 << i)) + leds_text[i] = '#'; + else + leds_text[i] = ' '; + } + leds_text[8] = '\0'; + + qemu_chr_printf(s->display, "\e[H\n\n|\e[31m%-8.8s\e[00m|\r\n", leds_text); + qemu_chr_printf(s->display, "\n\n\n\n|\e[32m%-8.8s\e[00m|", s->display_text); +} + +static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) +{ + MaltaFPGAState *s = opaque; + uint32_t val = 0; + uint32_t saddr; + + saddr = (addr & 0xfffff); + + switch (saddr) { + + /* SWITCH Register */ + case 0x00200: + val = 0x00000000; /* All switches closed */ + break; + + /* STATUS Register */ + case 0x00208: +#ifdef TARGET_WORDS_BIGENDIAN + val = 0x00000012; +#else + val = 0x00000010; +#endif + break; + + /* JMPRS Register */ + case 0x00210: + val = 0x00; + break; + + /* LEDBAR Register */ + case 0x00408: + val = s->leds; + break; + + /* BRKRES Register */ + case 0x00508: + val = s->brk; + break; + + /* GPOUT Register */ + case 0x00a00: + val = s->gpout; + break; + + /* XXX: implement a real I2C controller */ + + /* GPINP Register */ + case 0x00a08: + /* IN = OUT until a real I2C control is implemented */ + if (s->i2csel) + val = s->i2cout; + else + val = 0x00; + break; + + /* I2CINP Register */ + case 0x00b00: + val = 0x00000003; + break; + + /* I2COE Register */ + case 0x00b08: + val = s->i2coe; + break; + + /* I2COUT Register */ + case 0x00b10: + val = s->i2cout; + break; + + /* I2CSEL Register */ + case 0x00b18: + val = s->i2cout; + break; + + default: +#if 0 + printf ("malta_fpga_read: Bad register offset 0x%x\n", (int)addr); +#endif + break; + } + return val; +} + +static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + MaltaFPGAState *s = opaque; + uint32_t saddr; + + saddr = (addr & 0xfffff); + + switch (saddr) { + + /* SWITCH Register */ + case 0x00200: + break; + + /* JMPRS Register */ + case 0x00210: + break; + + /* LEDBAR Register */ + /* XXX: implement a 8-LED array */ + case 0x00408: + s->leds = val & 0xff; + break; + + /* ASCIIWORD Register */ + case 0x00410: + snprintf(s->display_text, 9, "%08X", val); + malta_fpga_update_display(s); + break; + + /* ASCIIPOS0 to ASCIIPOS7 Registers */ + case 0x00418: + case 0x00420: + case 0x00428: + case 0x00430: + case 0x00438: + case 0x00440: + case 0x00448: + case 0x00450: + s->display_text[(saddr - 0x00418) >> 3] = (char) val; + malta_fpga_update_display(s); + break; + + /* SOFTRES Register */ + case 0x00500: + if (val == 0x42) + qemu_system_reset_request (); + break; + + /* BRKRES Register */ + case 0x00508: + s->brk = val & 0xff; + break; + + /* GPOUT Register */ + case 0x00a00: + s->gpout = val & 0xff; + break; + + /* I2COE Register */ + case 0x00b08: + s->i2coe = val & 0x03; + break; + + /* I2COUT Register */ + case 0x00b10: + s->i2cout = val & 0x03; + break; + + /* I2CSEL Register */ + case 0x00b18: + s->i2cout = val & 0x01; + break; + + default: +#if 0 + printf ("malta_fpga_write: Bad register offset 0x%x\n", (int)addr); +#endif + break; + } +} + +static CPUReadMemoryFunc *malta_fpga_read[] = { + malta_fpga_readl, + malta_fpga_readl, + malta_fpga_readl +}; + +static CPUWriteMemoryFunc *malta_fpga_write[] = { + malta_fpga_writel, + malta_fpga_writel, + malta_fpga_writel +}; + +void malta_fpga_reset(void *opaque) +{ + MaltaFPGAState *s = opaque; + + s->leds = 0x00; + s->brk = 0x0a; + s->gpout = 0x00; + s->i2coe = 0x0; + s->i2cout = 0x3; + s->i2csel = 0x1; + + s->display_text[8] = '\0'; + snprintf(s->display_text, 9, " "); + malta_fpga_update_display(s); +} + +MaltaFPGAState *malta_fpga_init(target_phys_addr_t base) +{ + MaltaFPGAState *s; + int malta; + + s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState)); + + malta = cpu_register_io_memory(0, malta_fpga_read, + malta_fpga_write, s); + cpu_register_physical_memory(base, 0x100000, malta); + + s->display = qemu_chr_open("vc"); + qemu_chr_printf(s->display, "\e[HMalta LEBDAR\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "+ +\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "\n"); + qemu_chr_printf(s->display, "Malta ASCII\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "+ +\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + + malta_fpga_reset(s); + qemu_register_reset(malta_fpga_reset, s); + + return s; +} + +/* Audio support */ +#ifdef HAS_AUDIO +static void audio_init (PCIBus *pci_bus) +{ + struct soundhw *c; + int audio_enabled = 0; + + for (c = soundhw; !audio_enabled && c->name; ++c) { + audio_enabled = c->enabled; + } + + if (audio_enabled) { + AudioState *s; + + s = AUD_init (); + if (s) { + for (c = soundhw; c->name; ++c) { + if (c->enabled) { + if (c->isa) { + fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name); + exit(1); + } + else { + if (pci_bus) { + c->init.init_pci (pci_bus, s); + } + } + } + } + } + } +} +#endif + +/* Network support */ +static void network_init (PCIBus *pci_bus) +{ + int i; + NICInfo *nd; + + for(i = 0; i < nb_nics; i++) { + nd = &nd_table[i]; + if (!nd->model) { + nd->model = "pcnet"; + } + if (i == 0 && strcmp(nd->model, "pcnet") == 0) { + /* The malta board has a PCNet card using PCI SLOT 11 */ + pci_nic_init(pci_bus, nd, 88); + } else { + pci_nic_init(pci_bus, nd, -1); + } + } +} + +/* ROM and pseudo bootloader + + The following code implements a very very simple bootloader. It first + loads the registers a0 to a3 to the values expected by the OS, and + then jump at the kernel address. + + The bootloader should pass the locations of the kernel arguments and + environment variables tables. Those tables contain the 32-bit address + of NULL terminated strings. The environment variables table should be + terminated by a NULL address. + + For a simpler implementation, the number of kernel arguments is fixed + to two (the name of the kernel and the command line), and the two + tables are actually the same one. + + The registers a0 to a3 should contain the following values: + a0 - number of kernel arguments + a1 - 32-bit address of the kernel arguments table + a2 - 32-bit address of the environment variables table + a3 - RAM size in bytes +*/ + +static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr) +{ + uint32_t *p; + + /* Small bootloader */ + p = (uint32_t *) (phys_ram_base + bios_offset); + stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */ + stl_raw(p++, 0x00000000); /* nop */ + + /* Second part of the bootloader */ + p = (uint32_t *) (phys_ram_base + bios_offset + 0x040); + stl_raw(p++, 0x3c040000); /* lui a0, 0 */ + stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */ + stl_raw(p++, 0x3c050000 | ((ENVP_ADDR) >> 16)); /* lui a1, high(ENVP_ADDR) */ + stl_raw(p++, 0x34a50000 | ((ENVP_ADDR) & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */ + stl_raw(p++, 0x3c060000 | ((ENVP_ADDR + 8) >> 16)); /* lui a2, high(ENVP_ADDR + 8) */ + stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ + stl_raw(p++, 0x3c070000 | ((env->ram_size) >> 16)); /* lui a3, high(env->ram_size) */ + stl_raw(p++, 0x34e70000 | ((env->ram_size) & 0xffff)); /* ori a3, a3, low(env->ram_size) */ + stl_raw(p++, 0x3c1f0000 | ((kernel_addr) >> 16)); /* lui ra, high(kernel_addr) */; + stl_raw(p++, 0x37ff0000 | ((kernel_addr) & 0xffff)); /* ori ra, ra, low(kernel_addr) */ + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0x00000000); /* nop */ +} + +static void prom_set(int index, const char *string, ...) +{ + va_list ap; + uint32_t *p; + uint32_t table_addr; + char *s; + + if (index >= ENVP_NB_ENTRIES) + return; + + p = (uint32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND); + p += index; + + if (string == NULL) { + stl_raw(p, 0); + return; + } + + table_addr = ENVP_ADDR + sizeof(uint32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE; + s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr); + + stl_raw(p, table_addr); + + va_start(ap, string); + vsnprintf (s, ENVP_ENTRY_SIZE, string, ap); + va_end(ap); +} + +/* Kernel */ +static int64_t load_kernel (CPUState *env) +{ + int64_t kernel_addr = 0; + int index = 0; + long initrd_size; + + if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + env->kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + if (env->initrd_filename) { + initrd_size = load_image(env->initrd_filename, + phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); + if (initrd_size == (target_ulong) -1) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + env->initrd_filename); + exit(1); + } + } + + /* Store command line. */ + prom_set(index++, env->kernel_filename); + if (initrd_size > 0) + prom_set(index++, "rd_start=0x%08x rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline); + else + prom_set(index++, env->kernel_cmdline); + + /* Setup minimum environment variables */ + prom_set(index++, "memsize"); + prom_set(index++, "%i", env->ram_size); + prom_set(index++, "modetty0"); + prom_set(index++, "38400n8r"); + prom_set(index++, NULL); + + return kernel_addr; +} + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); + + /* The bootload does not need to be rewritten as it is located in a + read only location. The kernel location and the arguments table + location does not change. */ + if (env->kernel_filename) + load_kernel (env); +} + +void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + char buf[1024]; + unsigned long bios_offset; + int64_t kernel_addr; + PCIBus *pci_bus; + CPUState *env; + RTCState *rtc_state; + fdctrl_t *floppy_controller; + MaltaFPGAState *malta_fpga; + int ret; + + env = cpu_init(); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + qemu_register_reset(main_cpu_reset, env); + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + /* Map the bios at two physical locations, as on the real board */ + bios_offset = ram_size + vga_ram_size; + cpu_register_physical_memory(0x1e000000LL, + BIOS_SIZE, bios_offset | IO_MEM_ROM); + cpu_register_physical_memory(0x1fc00000LL, + BIOS_SIZE, bios_offset | IO_MEM_ROM); + + /* Load a BIOS image except if a kernel image has been specified. In + the later case, just write a small bootloader to the flash + location. */ + if (kernel_filename) { + env->ram_size = ram_size; + env->kernel_filename = kernel_filename; + env->kernel_cmdline = kernel_cmdline; + env->initrd_filename = initrd_filename; + kernel_addr = load_kernel(env); + write_bootloader(env, bios_offset, kernel_addr); + } else { + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret != BIOS_SIZE) { + fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", + buf); + exit(1); + } + } + + /* Board ID = 0x420 (Malta Board with CoreLV) + XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should + map to the board ID. */ + stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420); + + /* Init internal devices */ + cpu_mips_clock_init(env); + cpu_mips_irqctrl_init(); + + /* FPGA */ + malta_fpga = malta_fpga_init(0x1f000000LL); + + /* Interrupt controller */ + isa_pic = pic_init(pic_irq_request, env); + + /* Northbridge */ + pci_bus = pci_gt64120_init(isa_pic); + + /* Southbridge */ + piix4_init(pci_bus, 80); + pci_piix3_ide_init(pci_bus, bs_table, 81); + usb_uhci_init(pci_bus, 82); + piix4_pm_init(pci_bus, 83); + pit = pit_init(0x40, 0); + DMA_init(0); + + /* Super I/O */ + kbd_init(); + rtc_state = rtc_init(0x70, 8); + serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); + parallel_init(0x378, 7, parallel_hds[0]); + /* XXX: The floppy controller does not work correctly, something is + probably wrong */ + floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); + + /* Sound card */ +#ifdef HAS_AUDIO + audio_init(pci_bus); +#endif + + /* Network card */ + network_init(pci_bus); +} + +QEMUMachine mips_malta_machine = { + "malta", + "MIPS Malta Core LV", + mips_malta_init, +}; diff --git a/vl.c b/vl.c index 1ec78a747..eb675078a 100644 --- a/vl.c +++ b/vl.c @@ -6370,6 +6370,7 @@ void register_machines(void) qemu_register_machine(&prep_machine); #elif defined(TARGET_MIPS) qemu_register_machine(&mips_machine); + qemu_register_machine(&mips_malta_machine); #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 qemu_register_machine(&sun4u_machine); diff --git a/vl.h b/vl.h index 759d2d3d5..8aac950a5 100644 --- a/vl.h +++ b/vl.h @@ -302,6 +302,7 @@ typedef struct CharDriverState { QEMUBH *bh; } CharDriverState; +CharDriverState *qemu_chr_open(const char *filename); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); void qemu_chr_send_event(CharDriverState *s, int event); @@ -824,6 +825,8 @@ void i440fx_set_smm(PCIDevice *d, int val); int piix3_init(PCIBus *bus, int devfn); void i440fx_init_memory_mappings(PCIDevice *d); +int piix4_init(PCIBus *bus, int devfn); + /* openpic.c */ typedef struct openpic_t openpic_t; void openpic_set_irq(void *opaque, int n_IRQ, int level); @@ -1059,6 +1062,9 @@ extern QEMUMachine heathrow_machine; /* mips_r4k.c */ extern QEMUMachine mips_machine; +/* mips_malta.c */ +extern QEMUMachine mips_malta_machine; + /* mips_timer.c */ extern void cpu_mips_clock_init(CPUState *); extern void cpu_mips_irqctrl_init (void); -- cgit v1.2.3 From daf90626beeb5f20504c593f01604a554f7ef232 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 16 Jan 2007 18:54:31 +0000 Subject: ARM ELF loader. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2320 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_boot.c | 54 ++++++++++++++++++++++++++++++++---------------------- hw/integratorcp.c | 2 +- hw/realview.c | 2 +- hw/versatilepb.c | 2 +- vl.h | 2 +- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 0e28d4a07..f62f0f6fa 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -64,42 +64,52 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size, stl_raw(p++, 0); } -void arm_load_kernel(int ram_size, const char *kernel_filename, +void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, int board_id) { int kernel_size; int initrd_size; int n; + uint64_t entry; /* Load the kernel. */ if (!kernel_filename) { fprintf(stderr, "Kernel image must be specified\n"); exit(1); } - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } - if (initrd_filename) { - initrd_size = load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", - initrd_filename); + + kernel_size = load_elf(kernel_filename, 0, &entry); + if (kernel_size) { + /* An ELF image. Jump to the entry point. */ + env->regs[15] = entry & 0xfffffffe; + env->thumb = entry & 1; + } else { + /* Raw binary image. Assume it is a Limux zImage. */ + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } - } else { - initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image(initrd_filename, + phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_size = 0; + } + bootloader[1] |= board_id & 0xff; + bootloader[2] |= (board_id >> 8) & 0xff; + bootloader[5] = KERNEL_ARGS_ADDR; + bootloader[6] = KERNEL_LOAD_ADDR; + for (n = 0; n < sizeof(bootloader) / 4; n++) + stl_raw(phys_ram_base + (n * 4), bootloader[n]); + set_kernel_args(ram_size, initrd_size, kernel_cmdline); } - bootloader[1] |= board_id & 0xff; - bootloader[2] |= (board_id >> 8) & 0xff; - bootloader[5] = KERNEL_ARGS_ADDR; - bootloader[6] = KERNEL_LOAD_ADDR; - for (n = 0; n < sizeof(bootloader) / 4; n++) - stl_raw(phys_ram_base + (n * 4), bootloader[n]); - set_kernel_args(ram_size, initrd_size, kernel_cmdline); } diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 17dca2859..4e5f4ac9f 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -509,7 +509,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, } pl110_init(ds, 0xc0000000, pic, 22, 0); - arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, + arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, initrd_filename, 0x113); } diff --git a/hw/realview.c b/hw/realview.c index 6d057cee0..ea42705ad 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -127,7 +127,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, /* 0x68000000 PCI mem 1. */ /* 0x6c000000 PCI mem 2. */ - arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, + arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, initrd_filename, 0x33b); } diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 12b73037e..bc42472ad 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -250,7 +250,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, /* 0x101f3000 UART2. */ /* 0x101f4000 SSPI. */ - arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, + arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, initrd_filename, board_id); } diff --git a/vl.h b/vl.h index 8aac950a5..5cbbc4fb8 100644 --- a/vl.h +++ b/vl.h @@ -1317,7 +1317,7 @@ void *arm_gic_init(uint32_t base, void *parent, int parent_irq); /* arm_boot.c */ -void arm_load_kernel(int ram_size, const char *kernel_filename, +void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, int board_id); -- cgit v1.2.3 From dabd98ddf501ab9e28905f64a28282be96840a2d Mon Sep 17 00:00:00 2001 From: bellard Date: Tue, 16 Jan 2007 19:28:58 +0000 Subject: fixed movd mmx/sse insn git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2321 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/ops_sse.h | 19 +++++++++++++++++++ target-i386/translate.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index cdc380120..df1527c55 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -558,6 +558,25 @@ void OPPROTO glue(op_movl_T0_mm, SUFFIX) (void) T0 = s->L(0); } +#ifdef TARGET_X86_64 +void OPPROTO glue(op_movq_mm_T0, SUFFIX) (void) +{ + Reg *d; + d = (Reg *)((char *)env + PARAM1); + d->Q(0) = T0; +#if SHIFT == 1 + d->Q(1) = 0; +#endif +} + +void OPPROTO glue(op_movq_T0_mm, SUFFIX) (void) +{ + Reg *s; + s = (Reg *)((char *)env + PARAM1); + T0 = s->Q(0); +} +#endif + #if SHIFT == 0 void OPPROTO glue(op_pshufw, SUFFIX) (void) { diff --git a/target-i386/translate.c b/target-i386/translate.c index ad18af975..735acb0e4 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2621,12 +2621,28 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); break; case 0x6e: /* movd mm, ea */ - gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); - gen_op_movl_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); +#ifdef TARGET_X86_64 + if (s->dflag == 2) { + gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0); + gen_op_movq_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + } else +#endif + { + gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); + gen_op_movl_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + } break; case 0x16e: /* movd xmm, ea */ - gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); - gen_op_movl_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg])); +#ifdef TARGET_X86_64 + if (s->dflag == 2) { + gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0); + gen_op_movq_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg])); + } else +#endif + { + gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); + gen_op_movl_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg])); + } break; case 0x6f: /* movq mm, ea */ if (mod != 3) { @@ -2750,12 +2766,28 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) offsetof(CPUX86State,xmm_regs[reg].XMM_L(3))); break; case 0x7e: /* movd ea, mm */ - gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); - gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1); +#ifdef TARGET_X86_64 + if (s->dflag == 2) { + gen_op_movq_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1); + } else +#endif + { + gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); + gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1); + } break; case 0x17e: /* movd ea, xmm */ - gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg])); - gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1); +#ifdef TARGET_X86_64 + if (s->dflag == 2) { + gen_op_movq_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg])); + gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1); + } else +#endif + { + gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg])); + gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1); + } break; case 0x27e: /* movq xmm, ea */ if (mod != 3) { -- cgit v1.2.3 From adb4796796a073d782d0be3566f91e2489dc7065 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 16 Jan 2007 23:02:36 +0000 Subject: Improved console handling, thanks Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2322 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 155 insertions(+), 18 deletions(-) diff --git a/console.c b/console.c index cd30235b3..b0e7f2e0d 100644 --- a/console.c +++ b/console.c @@ -121,6 +121,7 @@ struct TextConsole { int total_height; int backscroll_height; int x, y; + int x_saved, y_saved; int y_displayed; int y_base; TextAttributes t_attrib_default; /* default text attributes */ @@ -147,7 +148,7 @@ static int nb_consoles = 0; void vga_hw_update(void) { - if (active_console->hw_update) + if (active_console && active_console->hw_update) active_console->hw_update(active_console->hw); } @@ -659,10 +660,6 @@ 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; inb_esc_params; i++) { switch (s->esc_params[i]) { case 0: /* reset all console attributes to default */ @@ -752,10 +749,21 @@ static void console_handle_escape(TextConsole *s) } } +static void console_clear_xy(TextConsole *s, int x, int y) +{ + int y1 = (s->y_base + y) % s->total_height; + TextCell *c = &s->cells[y1 * s->width + x]; + c->ch = ' '; + c->t_attrib = s->t_attrib_default; + c++; + update_xy(s, x, y); +} + static void console_putchar(TextConsole *s, int ch) { TextCell *c; - int y1, i, x; + int y1, i; + int x, y; switch(s->state) { case TTY_STATE_NORM: @@ -781,20 +789,31 @@ static void console_putchar(TextConsole *s, int ch) case '\a': /* alert aka. bell */ /* TODO: has to be implemented */ break; + case 14: + /* SI (shift in), character set 0 (ignored) */ + break; + case 15: + /* SO (shift out), character set 1 (ignored) */ + break; case 27: /* esc (introducing an escape sequence) */ s->state = TTY_STATE_ESC; break; default: + if (s->x >= s->width - 1) { + break; + } 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 0 /* line wrap disabled */ if (s->x >= s->width) { s->x = 0; console_put_lf(s); } +#endif break; } break; @@ -818,32 +837,150 @@ static void console_putchar(TextConsole *s, int ch) s->nb_esc_params++; if (ch == ';') break; +#ifdef DEBUG_CONSOLE + fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n", + s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params); +#endif s->state = TTY_STATE_NORM; switch(ch) { - case 'D': - if (s->x > 0) - s->x--; + case 'A': + /* move cursor up */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } + s->y -= s->esc_params[0]; + if (s->y < 0) { + s->y = 0; + } + break; + case 'B': + /* move cursor down */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } + s->y += s->esc_params[0]; + if (s->y >= s->height) { + s->y = s->height - 1; + } break; case 'C': - if (s->x < (s->width - 1)) - s->x++; + /* move cursor right */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } + s->x += s->esc_params[0]; + if (s->x >= s->width) { + s->x = s->width - 1; + } break; + case 'D': + /* move cursor left */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } + s->x -= s->esc_params[0]; + if (s->x < 0) { + s->x = 0; + } + break; + case 'G': + /* move cursor to column */ + s->x = s->esc_params[0] - 1; + if (s->x < 0) { + s->x = 0; + } + break; + case 'f': + case 'H': + /* move cursor to row, column */ + s->x = s->esc_params[1] - 1; + if (s->x < 0) { + s->x = 0; + } + s->y = s->esc_params[0] - 1; + if (s->y < 0) { + s->y = 0; + } + break; + case 'J': + switch (s->esc_params[0]) { + case 0: + /* clear to end of screen */ + for (y = s->y; y < s->height; y++) { + for (x = 0; x < s->width; x++) { + if (y == s->y && x < s->x) { + continue; + } + console_clear_xy(s, x, y); + } + } + break; + case 1: + /* clear from beginning of screen */ + for (y = 0; y <= s->y; y++) { + for (x = 0; x < s->width; x++) { + if (y == s->y && x > s->x) { + break; + } + console_clear_xy(s, x, y); + } + } + break; + case 2: + /* clear entire screen */ + for (y = 0; y <= s->height; y++) { + for (x = 0; x < s->width; x++) { + console_clear_xy(s, x, y); + } + } + break; + } case 'K': + switch (s->esc_params[0]) { + case 0: /* 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); + console_clear_xy(s, x, s->y); } break; - default: + case 1: + /* clear from beginning of line */ + for (x = 0; x <= s->x; x++) { + console_clear_xy(s, x, s->y); + } + break; + case 2: + /* clear entire line */ + for(x = 0; x < s->width; x++) { + console_clear_xy(s, x, s->y); + } break; } + break; + case 'm': console_handle_escape(s); break; + case 'n': + /* report cursor position */ + /* TODO: send ESC[row;colR */ + break; + case 's': + /* save cursor position */ + s->x_saved = s->x; + s->y_saved = s->y; + break; + case 'u': + /* restore cursor position */ + s->x = s->x_saved; + s->y = s->y_saved; + break; + default: +#ifdef DEBUG_CONSOLE + fprintf(stderr, "unhandled escape character '%c'\n", ch); +#endif + break; + } + break; } } } -- cgit v1.2.3 From 72742c8626a9a25dd707a4c76583cd9c9faa5942 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 17 Jan 2007 08:59:26 +0000 Subject: ARM boot fix (Jason Wessel). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2323 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_boot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index f62f0f6fa..28f6a9262 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -80,12 +80,12 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, } kernel_size = load_elf(kernel_filename, 0, &entry); - if (kernel_size) { + if (kernel_size >= 0) { /* An ELF image. Jump to the entry point. */ env->regs[15] = entry & 0xfffffffe; env->thumb = entry & 1; } else { - /* Raw binary image. Assume it is a Limux zImage. */ + /* Raw binary image. Assume it is a Linux zImage. */ kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) { -- cgit v1.2.3 From f1770b3e1f0fa6d684cd5e306530491fbfa5e604 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Jan 2007 15:15:52 +0000 Subject: Disable Malta floppy controller for now, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2324 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index cf26655d7..2c838a5b0 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -501,7 +501,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, PCIBus *pci_bus; CPUState *env; RTCState *rtc_state; - fdctrl_t *floppy_controller; + /* fdctrl_t *floppy_controller; */ MaltaFPGAState *malta_fpga; int ret; @@ -571,8 +571,8 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); parallel_init(0x378, 7, parallel_hds[0]); /* XXX: The floppy controller does not work correctly, something is - probably wrong */ - floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); + probably wrong. + floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */ /* Sound card */ #ifdef HAS_AUDIO -- cgit v1.2.3 From 2c52c8169a35eb5d15f81fe456219da30cadfe83 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Jan 2007 20:03:15 +0000 Subject: Keep track of mips related issues. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2325 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 target-mips/TODO diff --git a/target-mips/TODO b/target-mips/TODO new file mode 100644 index 000000000..5dd1de39e --- /dev/null +++ b/target-mips/TODO @@ -0,0 +1,17 @@ +Unsolved issues/bugs in the mips/mipsel backend +----------------------------------------------- + +- MIPS64: + - No 64bit TLB support + - no 64bit wide registers for FPU + - 64bit mul/div handling broken + - DM[FT]C not implemented + +- TLB fails cornercase at address wrap around +- [ls][dw][lr] report broken (aligned) BadVAddr +- Missing per-CPU instruction decoding, currently all implemented + instructions are regarded as valid +- pcnet32 does not work for little endian emulation on big endian host + (probably not mips specific, but observable for mips-malta) + +- We fake firmware support instead of doing the real thing -- cgit v1.2.3 From 9dbd25e664955f3b936fa7f98818324d36b8b92b Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Jan 2007 21:32:49 +0000 Subject: Note newsworthy changes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2326 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index a2c9a007d..2cc6e329f 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,8 @@ version 0.8.3: - Linux: specific host CDROM and floppy support - SMM support - Moved PCI init, MP table init and ACPI table init to Bochs BIOS + - Support for MIPS32 Release 2 instruction set (Thiemo Seufer) + - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil) version 0.8.2: -- cgit v1.2.3 From 54fd9cdfb468c1d701ffff168b76a433b73a95c6 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Jan 2007 22:47:40 +0000 Subject: Slirp UDP fix, by Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2327 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/udp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/slirp/udp.c b/slirp/udp.c index 0d7097027..8cf4cbd31 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -205,8 +205,6 @@ udp_input(m, iphlen) /* udp_last_so = so; */ so->so_laddr = ip->ip_src; so->so_lport = uh->uh_sport; - so->so_faddr = ip->ip_dst; /* XXX */ - so->so_fport = uh->uh_dport; /* XXX */ if ((so->so_iptos = udp_tos(so)) == 0) so->so_iptos = ip->ip_tos; @@ -217,6 +215,9 @@ udp_input(m, iphlen) */ } + so->so_faddr = ip->ip_dst; /* XXX */ + so->so_fport = uh->uh_dport; /* XXX */ + iphlen += sizeof(struct udphdr); m->m_len -= iphlen; m->m_data += iphlen; -- cgit v1.2.3 From 8182266352df123bbe5661d14ded4ef06d866a60 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Jan 2007 23:08:17 +0000 Subject: Fix USB buffer size, by Herbert Xu. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2328 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 29809f96b..f0b1e2e44 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -87,7 +87,7 @@ typedef struct UHCIState { is to allow multiple pending requests. */ uint32_t async_qh; USBPacket usb_packet; - uint8_t usb_buf[1280]; + uint8_t usb_buf[2048]; } UHCIState; typedef struct UHCI_TD { -- cgit v1.2.3 From 605686cd7acdc37b87134c7eedf01b99db9213c1 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Jan 2007 23:31:19 +0000 Subject: Kqemu support for Solaris, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2329 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 5 +++++ kqemu.c | 3 +++ osdep.c | 13 +++++++++++++ 3 files changed, 21 insertions(+) diff --git a/configure b/configure index 93bbe7b78..68c3fcc7b 100755 --- a/configure +++ b/configure @@ -151,6 +151,11 @@ if [ "$solaris" = "yes" ] ; then make="gmake" install="ginstall" solarisrev=`uname -r | cut -f2 -d.` + if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then + if test "$solarisrev" -gt 10 ; then + kqemu="yes" + fi + fi fi # find source path diff --git a/kqemu.c b/kqemu.c index 5ba314f42..e01556adf 100644 --- a/kqemu.c +++ b/kqemu.c @@ -26,6 +26,9 @@ #include #include #endif +#ifdef HOST_SOLARIS +#include +#endif #include #include #include diff --git a/osdep.c b/osdep.c index 1a4c03688..d1eff8deb 100644 --- a/osdep.c +++ b/osdep.c @@ -27,6 +27,10 @@ #include #include #include +#ifdef HOST_SOLARIS +#include +#include +#endif #include "cpu.h" #if defined(USE_KQEMU) @@ -86,13 +90,22 @@ void *kqemu_vmalloc(size_t size) const char *tmpdir; char phys_ram_file[1024]; void *ptr; +#ifdef HOST_SOLARIS + struct statvfs stfs; +#else struct statfs stfs; +#endif if (phys_ram_fd < 0) { tmpdir = getenv("QEMU_TMPDIR"); if (!tmpdir) +#ifdef HOST_SOLARIS + tmpdir = "/tmp"; + if (statvfs(tmpdir, &stfs) == 0) { +#else tmpdir = "/dev/shm"; if (statfs(tmpdir, &stfs) == 0) { +#endif int64_t free_space; int ram_mb; -- cgit v1.2.3 From 0da75eb13524d5aa426486d015d63e1b6ce34aa2 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Jan 2007 23:35:01 +0000 Subject: Big endian support for Gallileo, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2330 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 4354a1462..f3ff61381 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -240,14 +240,19 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, GT64120State *s = opaque; uint32_t saddr; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + saddr = (addr & 0xfff) >> 2; switch (saddr) { - /* CPU Configuration Register */ + + /* CPU Configuration */ case GT_CPU: s->regs[GT_CPU] = val; - gt64120_pci_mapping(s); break; case GT_MULTI: + /* Read-only register as only one GT64xxx is present on the CPU bus */ break; /* CPU Address Decode */ @@ -306,6 +311,13 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, case GT_CPUERR_DATALO: case GT_CPUERR_DATAHI: case GT_CPUERR_PARITY: + /* Read-only registers, do nothing */ + break; + + /* CPU Sync Barrier */ + case GT_PCI0SYNC: + case GT_PCI1SYNC: + /* Read-only registers, do nothing */ break; /* ECC */ @@ -314,6 +326,7 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, case GT_ECC_MEM: case GT_ECC_CALC: case GT_ECC_ERRADDR: + /* Read-only registers, do nothing */ break; /* PCI Internal */ @@ -328,6 +341,16 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, pci_host_data_writel(s->pci, 0, val); break; + /* SDRAM Parameters */ + case GT_SDRAM_B0: + case GT_SDRAM_B1: + case GT_SDRAM_B2: + case GT_SDRAM_B3: + /* We don't simulate electrical parameters of the SDRAM. + Accept, but ignore the values. */ + s->regs[saddr] = val; + break; + default: #if 0 printf ("gt64120_writel: Bad register offset 0x%x\n", (int)addr); @@ -348,13 +371,31 @@ static uint32_t gt64120_readl (void *opaque, switch (saddr) { + /* CPU Configuration */ + case GT_MULTI: + /* Only one GT64xxx is present on the CPU bus, return + the initial value */ + val = s->regs[saddr]; + break; + /* CPU Error Report */ case GT_CPUERR_ADDRLO: case GT_CPUERR_ADDRHI: case GT_CPUERR_DATALO: case GT_CPUERR_DATAHI: case GT_CPUERR_PARITY: - return 0; + /* Emulated memory has no error, always return the initial + values */ + val = s->regs[saddr]; + break; + + /* CPU Sync Barrier */ + case GT_PCI0SYNC: + case GT_PCI1SYNC: + /* Reading those register should empty all FIFO on the PCI + bus, which are not emulated. The return value should be + a random value that should be ignored. */ + val = 0xc000ffee; break; /* ECC */ @@ -363,11 +404,12 @@ static uint32_t gt64120_readl (void *opaque, case GT_ECC_MEM: case GT_ECC_CALC: case GT_ECC_ERRADDR: - return 0; + /* Emulated memory has no error, always return the initial + values */ + val = s->regs[saddr]; break; case GT_CPU: - case GT_MULTI: case GT_PCI0IOLD: case GT_PCI0M0LD: case GT_PCI0M1LD: @@ -394,6 +436,16 @@ static uint32_t gt64120_readl (void *opaque, val = pic_intack_read(isa_pic); break; + /* SDRAM Parameters */ + case GT_SDRAM_B0: + case GT_SDRAM_B1: + case GT_SDRAM_B2: + case GT_SDRAM_B3: + /* We don't simulate electrical parameters of the SDRAM. + Just return the last written value. */ + val = s->regs[saddr]; + break; + /* PCI Internal */ case GT_PCI0_CFGADDR: val = s->pci->config_reg; @@ -410,7 +462,11 @@ static uint32_t gt64120_readl (void *opaque, break; } +#ifdef TARGET_WORDS_BIGENDIAN + return bswap32(val); +#else return val; +#endif } static CPUWriteMemoryFunc *gt64120_write[] = { @@ -521,6 +577,12 @@ void gt64120_reset(void *opaque) s->regs[GT_ECC_CALC] = 0x00000000; s->regs[GT_ECC_ERRADDR] = 0x00000000; + /* SDRAM Parameters */ + s->regs[GT_SDRAM_B0] = 0x00000005; + s->regs[GT_SDRAM_B1] = 0x00000005; + s->regs[GT_SDRAM_B2] = 0x00000005; + s->regs[GT_SDRAM_B3] = 0x00000005; + /* PCI Internal FIXME: not complete*/ #ifdef TARGET_WORDS_BIGENDIAN s->regs[GT_PCI0_CMD] = 0x00000000; -- cgit v1.2.3 From 54421cb17bc744bad15f2b1adb4adefdaea83c10 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 18 Jan 2007 00:22:11 +0000 Subject: Fix CDROM permission check, by Kazu . git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2331 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/block-raw.c b/block-raw.c index 2b6f441ba..29882e1f7 100644 --- a/block-raw.c +++ b/block-raw.c @@ -914,8 +914,13 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, create_flags, overlapped, NULL); - if (s->hfile == INVALID_HANDLE_VALUE) + if (s->hfile == INVALID_HANDLE_VALUE) { + int err = GetLastError(); + + if (err == ERROR_ACCESS_DENIED) + return -EACCES; return -1; + } return 0; } @@ -1278,8 +1283,13 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, create_flags, overlapped, NULL); - if (s->hfile == INVALID_HANDLE_VALUE) + if (s->hfile == INVALID_HANDLE_VALUE) { + int err = GetLastError(); + + if (err == ERROR_ACCESS_DENIED) + return -EACCES; return -1; + } return 0; } -- cgit v1.2.3 From 831b78254cfa752d5e6542542a663468e650bcb3 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 18 Jan 2007 20:06:33 +0000 Subject: Darwin userspace emulation, by Pierre d'Herbemont. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2332 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 17 +- configure | 48 +- darwin-user/commpage.c | 358 ++++++++++++ darwin-user/ioctls.h | 4 + darwin-user/ioctls_types.h | 1 + darwin-user/machload.c | 903 ++++++++++++++++++++++++++++++ darwin-user/main.c | 922 +++++++++++++++++++++++++++++++ darwin-user/mmap.c | 411 ++++++++++++++ darwin-user/qemu.h | 179 ++++++ darwin-user/signal.c | 463 ++++++++++++++++ darwin-user/syscall.c | 1315 ++++++++++++++++++++++++++++++++++++++++++++ darwin-user/syscalls.h | 384 +++++++++++++ gdbstub.c | 2 +- 13 files changed, 4996 insertions(+), 11 deletions(-) create mode 100644 darwin-user/commpage.c create mode 100644 darwin-user/ioctls.h create mode 100644 darwin-user/ioctls_types.h create mode 100644 darwin-user/machload.c create mode 100644 darwin-user/main.c create mode 100644 darwin-user/mmap.c create mode 100644 darwin-user/qemu.h create mode 100644 darwin-user/signal.c create mode 100644 darwin-user/syscall.c create mode 100644 darwin-user/syscalls.h diff --git a/Makefile.target b/Makefile.target index 5973211c3..af4a69a6e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -13,7 +13,11 @@ 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 +ifdef CONFIG_DARWIN_USER +VPATH+=:$(SRC_PATH)/darwin-user +CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH) +endif +ifdef CONFIG_LINUX_USER VPATH+=:$(SRC_PATH)/linux-user CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) endif @@ -85,12 +89,14 @@ endif ifdef USE_I386_LD BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld else +ifdef CONFIG_LINUX_USER # 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 +endif ifeq ($(ARCH),x86_64) BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld @@ -98,8 +104,10 @@ endif ifeq ($(ARCH),ppc) CPPFLAGS+= -D__powerpc__ +ifdef CONFIG_LINUX_USER BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif +endif ifeq ($(ARCH),s390) BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld @@ -186,6 +194,7 @@ BASE_LDFLAGS+=-p main.o: BASE_CFLAGS+=-p endif +ifdef CONFIG_LINUX_USER OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ elfload.o linuxload.o ifdef TARGET_HAS_BFLT @@ -203,6 +212,12 @@ endif ifeq ($(TARGET_ARCH), m68k) OBJS+= m68k-sim.o m68k-semi.o endif +endif #CONFIG_LINUX_USER + +ifdef CONFIG_DARWIN_USER +OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o +endif + SRCS:= $(OBJS:.o=.c) OBJS+= libqemu.a diff --git a/configure b/configure index 68c3fcc7b..eda1437fe 100755 --- a/configure +++ b/configure @@ -94,7 +94,8 @@ cocoa="no" check_gfx="yes" check_gcc="yes" softmmu="yes" -user="no" +linux_user="no" +darwin_user="no" build_docs="no" uname_release="" @@ -126,6 +127,7 @@ oss="yes" Darwin) bsd="yes" darwin="yes" +darwin_user="yes" OS_CFLAGS="-mdynamic-no-pic" ;; SunOS) @@ -134,7 +136,7 @@ solaris="yes" *) oss="yes" linux="yes" -user="yes" +linux_user="yes" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" fi @@ -240,9 +242,13 @@ for opt do ;; --enable-system) softmmu="yes" ;; - --disable-user) user="no" + --disable-linux-user) linux_user="no" ;; - --enable-user) user="yes" + --enable-linux-user) linux_user="yes" + ;; + --disable-darwin-user) darwin_user="no" + ;; + --enable-darwin-user) darwin_user="yes" ;; --enable-uname-release=*) uname_release="$optarg" ;; @@ -287,8 +293,10 @@ 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 " --enable-linux-user enable all linux usermode emulation targets" +echo " --disable-linux-user disable all linux usermode emulation targets" +echo " --enable-darwin-user enable all darwin usermode emulation targets" +echo " --disable-darwin-user disable all darwin 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" @@ -408,8 +416,12 @@ if test -z "$target_list" ; 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" + if [ "$linux_user" = "yes" ] ; then + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user $target_list" + fi +# the following are Darwin specific + if [ "$darwin_user" = "yes" ] ; then + target_list="i386-darwin-user ppc-darwin-user $target_list" fi else target_list=`echo "$target_list" | sed -e 's/,/ /g'` @@ -787,6 +799,16 @@ if expr $target : '.*-user' > /dev/null ; then target_user_only="yes" fi +target_linux_user="no" +if expr $target : '.*-linux-user' > /dev/null ; then + target_linux_user="yes" +fi + +target_darwin_user="no" +if expr $target : '.*-darwin-user' > /dev/null ; then + target_darwin_user="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" @@ -799,7 +821,7 @@ fi mkdir -p $target_dir mkdir -p $target_dir/fpu -if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then +if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then mkdir -p $target_dir/nwfpe fi if test "$target_user_only" = "no" ; then @@ -894,6 +916,14 @@ 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_linux_user" = "yes" ; then + echo "CONFIG_LINUX_USER=yes" >> $config_mak + echo "#define CONFIG_LINUX_USER 1" >> $config_h +fi +if test "$target_darwin_user" = "yes" ; then + echo "CONFIG_DARWIN_USER=yes" >> $config_mak + echo "#define CONFIG_DARWIN_USER 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 diff --git a/darwin-user/commpage.c b/darwin-user/commpage.c new file mode 100644 index 000000000..12ee1da02 --- /dev/null +++ b/darwin-user/commpage.c @@ -0,0 +1,358 @@ + /* + * Commpage syscalls + * + * Copyright (c) 2006 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +//#define DEBUG_COMMPAGE + +#ifdef DEBUG_COMMPAGE +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0) +#else +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) +#endif + +/******************************************************************** + * Commpage definitions + */ +#ifdef TARGET_I386 +/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */ +# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */ +# define COMMPAGE_SIZE (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */ +#elif defined(TARGET_PPC) +/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */ +# define COMMPAGE_START (-8*4096) +# define COMMPAGE_SIZE (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */ +#endif + +void do_compare_and_swap32(void *cpu_env, int num); +void do_compare_and_swap64(void *cpu_env, int num); +void do_add_atomic_word32(void *cpu_env, int num); +void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1); +void do_nanotime(void *cpu_env, int num); + +void unimpl_commpage(void *cpu_env, int num); + +typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, + uint32_t arg8); +typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1, + uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, + uint32_t arg6, uint32_t arg7, uint32_t arg8); + +#define HAS_PTR 0x10 +#define NO_PTR 0x20 +#define CALL_DIRECT 0x1 +#define CALL_INDIRECT 0x2 + +#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \ + { #name, offset, nargs, options, (commpage_8args_function_t)func } + +struct commpage_entry { + char * name; + int offset; + int nargs; + char options; + commpage_8args_function_t function; +}; + +static inline int commpage_code_num(struct commpage_entry *entry) +{ + if((entry->options & HAS_PTR)) + return entry->offset + 4; + else + return entry->offset; +} + +static inline int commpage_is_indirect(struct commpage_entry *entry) +{ + return !(entry->options & CALL_DIRECT); +} + +/******************************************************************** + * Commpage entry + */ +static struct commpage_entry commpage_entries[] = +{ + COMMPAGE_ENTRY(compare_and_swap32, 0, 0x080, do_compare_and_swap32, CALL_INDIRECT | HAS_PTR), + COMMPAGE_ENTRY(compare_and_swap64, 0, 0x0c0, do_compare_and_swap64, CALL_INDIRECT | HAS_PTR), + COMMPAGE_ENTRY(enqueue, 0, 0x100, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(dequeue, 0, 0x140, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(memory_barrier, 0, 0x180, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(add_atomic_word32, 0, 0x1a0, do_add_atomic_word32, CALL_INDIRECT | HAS_PTR), + COMMPAGE_ENTRY(add_atomic_word64, 0, 0x1c0, unimpl_commpage, CALL_INDIRECT | HAS_PTR), + + COMMPAGE_ENTRY(mach_absolute_time, 0, 0x200, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(spinlock_try, 1, 0x220, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT), + COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT), + COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(gettimeofday, 1, 0x2c0, do_cgettimeofday, CALL_INDIRECT), + COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(pthread_self, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + + COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT), + +#ifdef TARGET_I386 + COMMPAGE_ENTRY(bts, 0, 0x5e0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(btc, 0, 0x5f0, unimpl_commpage, CALL_INDIRECT), +#endif + + COMMPAGE_ENTRY(bzero, 2, 0x600, bzero, CALL_DIRECT), + COMMPAGE_ENTRY(bcopy, 3, 0x780, bcopy, CALL_DIRECT), + COMMPAGE_ENTRY(memcpy, 3, 0x7a0, memcpy, CALL_DIRECT), + +#ifdef TARGET_I386 + COMMPAGE_ENTRY(old_nanotime, 0, 0xf80, do_nanotime, CALL_INDIRECT), + COMMPAGE_ENTRY(memset_pattern, 0, 0xf80, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(long_copy, 0, 0x1200, unimpl_commpage, CALL_INDIRECT), + + COMMPAGE_ENTRY(sysintegrity, 0, 0x1600, unimpl_commpage, CALL_INDIRECT), + + COMMPAGE_ENTRY(nanotime, 0, 0x1700, do_nanotime, CALL_INDIRECT), +#elif TARGET_PPC + COMMPAGE_ENTRY(compare_and_swap32b, 0, 0xf80, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(compare_and_swap64b, 0, 0xfc0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(memset_pattern, 0, 0x1000, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(bigcopy, 0, 0x1140, unimpl_commpage, CALL_INDIRECT), +#endif +}; + + +/******************************************************************** + * Commpage backdoor + */ +static inline void print_commpage_entry(struct commpage_entry entry) +{ + printf("@0x%x %s\n", entry.offset, entry.name); +} + +static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry) +{ +#ifdef TARGET_I386 + char * commpage = (char*)(COMMPAGE_START+entry.offset); + int c = 0; + if(entry.options & HAS_PTR) + { + commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff; + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff; + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff; + commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff; + } + commpage[c++] = 0xcd; + commpage[c++] = 0x79; /* int 0x79 */ + commpage[c++] = 0xc3; /* ret */ +#else + qerror("can't install the commpage on this arch\n"); +#endif +} + +/******************************************************************** + * Commpage initialization + */ +void commpage_init(void) +{ +#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(__powerpc__) ^ defined(TARGET_PPC)) + int i; + void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE, + PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if((int)commpage != COMMPAGE_START) + qerror("can't allocate the commpage\n"); + + bzero(commpage, COMMPAGE_SIZE); + + /* XXX: commpage data not handled */ + + for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) + install_commpage_backdoor_for_entry(commpage_entries[i]); +#else + /* simply map our pages so they can be executed + XXX: we don't really want to do that since in the ppc on ppc situation we may + not able to run commpages host optimized instructions (like G5's on a G5), + hence this is sometimes a broken fix. */ + page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID); +#endif +} + +/******************************************************************** + * Commpage implementation + */ +void do_compare_and_swap32(void *cpu_env, int num) +{ +#ifdef TARGET_I386 + uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX]; + uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX]; + DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value); + + if(value && old == tswap32(*value)) + { + uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX]; + *value = tswap32(new); + /* set zf flag */ + ((CPUX86State*)cpu_env)->eflags |= 0x40; + } + else + { + ((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value); + /* unset zf flag */ + ((CPUX86State*)cpu_env)->eflags &= ~0x40; + } +#else + qerror("do_compare_and_swap32 unimplemented"); +#endif +} + +void do_compare_and_swap64(void *cpu_env, int num) +{ +#ifdef TARGET_I386 + /* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */ + uint64_t old, new, swapped_val; + uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI]; + old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX]; + + DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value); + swapped_val = tswap64(*value); + + if(old == swapped_val) + { + new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX]; + *value = tswap64(new); + /* set zf flag */ + ((CPUX86State*)cpu_env)->eflags |= 0x40; + } + else + { + ((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val); + ((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32); + /* unset zf flag */ + ((CPUX86State*)cpu_env)->eflags &= ~0x40; + } +#else + qerror("do_compare_and_swap64 unimplemented"); +#endif +} + +void do_add_atomic_word32(void *cpu_env, int num) +{ +#ifdef TARGET_I386 + uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX]; + uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX]; + uint32_t swapped_value = tswap32(*value); + + DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value); + + /* old value in EAX */ + ((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value; + *value = tswap32(swapped_value + amt); +#else + qerror("do_add_atomic_word32 unimplemented"); +#endif +} + +void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1) +{ +#ifdef TARGET_I386 + extern int __commpage_gettimeofday(struct timeval *); + DPRINTF("commpage: gettimeofday(0x%x)\n", arg1); + struct timeval *time = (struct timeval *)arg1; + int ret = __commpage_gettimeofday(time); + tswap32s((uint32_t*)&time->tv_sec); + tswap32s((uint32_t*)&time->tv_usec); + ((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */ +#else + qerror("do_gettimeofday unimplemented"); +#endif +} + +void do_nanotime(void *cpu_env, int num) +{ +#ifdef TARGET_I386 + uint64_t t = mach_absolute_time(); + ((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff); + ((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff); +#else + qerror("do_nanotime unimplemented"); +#endif +} + +void unimpl_commpage(void *cpu_env, int num) +{ + gemu_log("qemu: commpage function 0x%x not implemented\n", num); +} + +/******************************************************************** + * do_commpage - called by the main cpu loop + */ +void +do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, + uint32_t arg8) +{ + int i, found = 0; + + arg1 = tswap32(arg1); + arg2 = tswap32(arg2); + arg3 = tswap32(arg3); + arg4 = tswap32(arg4); + arg5 = tswap32(arg5); + arg6 = tswap32(arg6); + arg7 = tswap32(arg7); + arg8 = tswap32(arg8); + + num = num-COMMPAGE_START-2; + + for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) { + if( num == commpage_code_num(&commpage_entries[i]) ) + { + DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]"); + found = 1; + if(commpage_is_indirect(&commpage_entries[i])) + { + commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function; + function(cpu_env, num, arg1, arg2, arg3, + arg4, arg5, arg6, arg7, arg8); + } + else + { + commpage_entries[i].function(arg1, arg2, arg3, + arg4, arg5, arg6, arg7, arg8); + } + break; + } + } + + if(!found) + { + gemu_log("qemu: commpage function 0x%x not defined\n", num); + gdb_handlesig (cpu_env, SIGTRAP); + exit(-1); + } +} diff --git a/darwin-user/ioctls.h b/darwin-user/ioctls.h new file mode 100644 index 000000000..dc73af259 --- /dev/null +++ b/darwin-user/ioctls.h @@ -0,0 +1,4 @@ + /* emulated ioctl list */ + + IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) diff --git a/darwin-user/ioctls_types.h b/darwin-user/ioctls_types.h new file mode 100644 index 000000000..63e65f031 --- /dev/null +++ b/darwin-user/ioctls_types.h @@ -0,0 +1 @@ +STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT) \ No newline at end of file diff --git a/darwin-user/machload.c b/darwin-user/machload.c new file mode 100644 index 000000000..3ba417ed0 --- /dev/null +++ b/darwin-user/machload.c @@ -0,0 +1,903 @@ +/* + * Mach-O object file loading + * + * Copyright (c) 2006 Pierre d'Herbemont + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" +#include "disas.h" + +#include +#include +#include +#include +#include + +//#define DEBUG_MACHLOAD + +#ifdef DEBUG_MACHLOAD +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0) +#else +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) +#endif + +# define check_mach_header(x) (x.magic == MH_CIGAM) + +extern const char *interp_prefix; + +/* we don't have a good implementation for this */ +#define DONT_USE_DYLD_SHARED_MAP + +/* Pass extra arg to DYLD for debug */ +//#define ACTIVATE_DYLD_TRACE + +//#define OVERRIDE_DYLINKER + +#ifdef OVERRIDE_DYLINKER +# ifdef TARGET_I386 +# define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld" +# else +# define DYLINKER_NAME "/usr/lib/dyld" +# endif +#endif + +/* XXX: in an include */ +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; +}; + +/* Print symbols in gdb */ +void *macho_text_sect = 0; +int macho_offset = 0; + +int load_object(const char *filename, struct target_pt_regs * regs, void ** mh); +void qerror(const char *format, ...); +#ifdef TARGET_I386 +typedef struct mach_i386_thread_state { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + unsigned int edi; + unsigned int esi; + unsigned int ebp; + unsigned int esp; + unsigned int ss; + unsigned int eflags; + unsigned int eip; + unsigned int cs; + unsigned int ds; + unsigned int es; + unsigned int fs; + unsigned int gs; +} mach_i386_thread_state_t; + +void bswap_i386_thread_state(struct mach_i386_thread_state *ts) +{ + bswap32s((uint32_t*)&ts->eax); + bswap32s((uint32_t*)&ts->ebx); + bswap32s((uint32_t*)&ts->ecx); + bswap32s((uint32_t*)&ts->edx); + bswap32s((uint32_t*)&ts->edi); + bswap32s((uint32_t*)&ts->esi); + bswap32s((uint32_t*)&ts->ebp); + bswap32s((uint32_t*)&ts->esp); + bswap32s((uint32_t*)&ts->ss); + bswap32s((uint32_t*)&ts->eflags); + bswap32s((uint32_t*)&ts->eip); + bswap32s((uint32_t*)&ts->cs); + bswap32s((uint32_t*)&ts->ds); + bswap32s((uint32_t*)&ts->es); + bswap32s((uint32_t*)&ts->fs); + bswap32s((uint32_t*)&ts->gs); +} +#define target_thread_state mach_i386_thread_state +#define TARGET_CPU_TYPE CPU_TYPE_I386 +#define TARGET_CPU_NAME "i386" +#endif + +#ifdef TARGET_PPC +struct mach_ppc_thread_state { + unsigned int srr0; /* Instruction address register (PC) */ + unsigned int srr1; /* Machine state register (supervisor) */ + unsigned int r0; + unsigned int r1; + unsigned int r2; + unsigned int r3; + unsigned int r4; + unsigned int r5; + unsigned int r6; + unsigned int r7; + unsigned int r8; + unsigned int r9; + unsigned int r10; + unsigned int r11; + unsigned int r12; + unsigned int r13; + unsigned int r14; + unsigned int r15; + unsigned int r16; + unsigned int r17; + unsigned int r18; + unsigned int r19; + unsigned int r20; + unsigned int r21; + unsigned int r22; + unsigned int r23; + unsigned int r24; + unsigned int r25; + unsigned int r26; + unsigned int r27; + unsigned int r28; + unsigned int r29; + unsigned int r30; + unsigned int r31; + + unsigned int cr; /* Condition register */ + unsigned int xer; /* User's integer exception register */ + unsigned int lr; /* Link register */ + unsigned int ctr; /* Count register */ + unsigned int mq; /* MQ register (601 only) */ + + unsigned int vrsave; /* Vector Save Register */ +}; + +void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts) +{ + bswap32s((uint32_t*)&ts->srr0); + bswap32s((uint32_t*)&ts->srr1); + bswap32s((uint32_t*)&ts->r0); + bswap32s((uint32_t*)&ts->r1); + bswap32s((uint32_t*)&ts->r2); + bswap32s((uint32_t*)&ts->r3); + bswap32s((uint32_t*)&ts->r4); + bswap32s((uint32_t*)&ts->r5); + bswap32s((uint32_t*)&ts->r6); + bswap32s((uint32_t*)&ts->r7); + bswap32s((uint32_t*)&ts->r8); + bswap32s((uint32_t*)&ts->r9); + bswap32s((uint32_t*)&ts->r10); + bswap32s((uint32_t*)&ts->r11); + bswap32s((uint32_t*)&ts->r12); + bswap32s((uint32_t*)&ts->r13); + bswap32s((uint32_t*)&ts->r14); + bswap32s((uint32_t*)&ts->r15); + bswap32s((uint32_t*)&ts->r16); + bswap32s((uint32_t*)&ts->r17); + bswap32s((uint32_t*)&ts->r18); + bswap32s((uint32_t*)&ts->r19); + bswap32s((uint32_t*)&ts->r20); + bswap32s((uint32_t*)&ts->r21); + bswap32s((uint32_t*)&ts->r22); + bswap32s((uint32_t*)&ts->r23); + bswap32s((uint32_t*)&ts->r24); + bswap32s((uint32_t*)&ts->r25); + bswap32s((uint32_t*)&ts->r26); + bswap32s((uint32_t*)&ts->r27); + bswap32s((uint32_t*)&ts->r28); + bswap32s((uint32_t*)&ts->r29); + bswap32s((uint32_t*)&ts->r30); + bswap32s((uint32_t*)&ts->r31); + + bswap32s((uint32_t*)&ts->cr); + bswap32s((uint32_t*)&ts->xer); + bswap32s((uint32_t*)&ts->lr); + bswap32s((uint32_t*)&ts->ctr); + bswap32s((uint32_t*)&ts->mq); + + bswap32s((uint32_t*)&ts->vrsave); +} + +#define target_thread_state mach_ppc_thread_state +#define TARGET_CPU_TYPE CPU_TYPE_POWERPC +#define TARGET_CPU_NAME "PowerPC" +#endif + +struct target_thread_command { + unsigned long cmd; /* LC_THREAD or LC_UNIXTHREAD */ + unsigned long cmdsize; /* total size of this command */ + unsigned long flavor; /* flavor of thread state */ + unsigned long count; /* count of longs in thread state */ + struct target_thread_state state; /* thread state for this flavor */ +}; + +void bswap_tc(struct target_thread_command *tc) +{ + bswap32s((uint32_t*)(&tc->flavor)); + bswap32s((uint32_t*)&tc->count); +#if defined(TARGET_I386) + bswap_i386_thread_state(&tc->state); +#elif defined(TARGET_PPC) + bswap_ppc_thread_state(&tc->state); +#else +# error unknown TARGET_CPU_TYPE +#endif +} + +void bswap_mh(struct mach_header *mh) +{ + bswap32s((uint32_t*)(&mh->magic)); + bswap32s((uint32_t*)&mh->cputype); + bswap32s((uint32_t*)&mh->cpusubtype); + bswap32s((uint32_t*)&mh->filetype); + bswap32s((uint32_t*)&mh->ncmds); + bswap32s((uint32_t*)&mh->sizeofcmds); + bswap32s((uint32_t*)&mh->flags); +} + +void bswap_lc(struct load_command *lc) +{ + bswap32s((uint32_t*)&lc->cmd); + bswap32s((uint32_t*)&lc->cmdsize); +} + + +void bswap_fh(struct fat_header *fh) +{ + bswap32s((uint32_t*)&fh->magic); + bswap32s((uint32_t*)&fh->nfat_arch); +} + +void bswap_fa(struct fat_arch *fa) +{ + bswap32s((uint32_t*)&fa->cputype); + bswap32s((uint32_t*)&fa->cpusubtype); + bswap32s((uint32_t*)&fa->offset); + bswap32s((uint32_t*)&fa->size); + bswap32s((uint32_t*)&fa->align); +} + +void bswap_segcmd(struct segment_command *sc) +{ + bswap32s((uint32_t*)&sc->vmaddr); + bswap32s((uint32_t*)&sc->vmsize); + bswap32s((uint32_t*)&sc->fileoff); + bswap32s((uint32_t*)&sc->filesize); + bswap32s((uint32_t*)&sc->maxprot); + bswap32s((uint32_t*)&sc->initprot); + bswap32s((uint32_t*)&sc->nsects); + bswap32s((uint32_t*)&sc->flags); +} + +void bswap_symtabcmd(struct symtab_command *stc) +{ + bswap32s((uint32_t*)&stc->cmd); + bswap32s((uint32_t*)&stc->cmdsize); + bswap32s((uint32_t*)&stc->symoff); + bswap32s((uint32_t*)&stc->nsyms); + bswap32s((uint32_t*)&stc->stroff); + bswap32s((uint32_t*)&stc->strsize); +} + +void bswap_sym(struct nlist *n) +{ + bswap32s((uint32_t*)&n->n_un.n_strx); + bswap16s((uint16_t*)&n->n_desc); + bswap32s((uint32_t*)&n->n_value); +} + +int load_thread(struct mach_header *mh, struct target_thread_command *tc, struct target_pt_regs * regs, int fd, int mh_pos, int need_bswap) +{ + int entry; + if(need_bswap) + bswap_tc(tc); +#if defined(TARGET_I386) + entry = tc->state.eip; + DPRINTF(" eax 0x%.8x\n ebx 0x%.8x\n ecx 0x%.8x\n edx 0x%.8x\n edi 0x%.8x\n esi 0x%.8x\n ebp 0x%.8x\n esp 0x%.8x\n ss 0x%.8x\n eflags 0x%.8x\n eip 0x%.8x\n cs 0x%.8x\n ds 0x%.8x\n es 0x%.8x\n fs 0x%.8x\n gs 0x%.8x\n", + tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp, + tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es, + tc->state.fs, tc->state.gs ); +#define reg_copy(reg) regs->reg = tc->state.reg + if(regs) + { + reg_copy(eax); + reg_copy(ebx); + reg_copy(ecx); + reg_copy(edx); + + reg_copy(edi); + reg_copy(esi); + + reg_copy(ebp); + reg_copy(esp); + + reg_copy(eflags); + reg_copy(eip); + /* + reg_copy(ss); + reg_copy(cs); + reg_copy(ds); + reg_copy(es); + reg_copy(fs); + reg_copy(gs);*/ + } +#undef reg_copy +#elif defined(TARGET_PPC) + entry = tc->state.srr0; +#endif + DPRINTF("load_thread: entry 0x%x\n", entry); + return entry; +} + +int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap) +{ + int size; + char * dylinker_name; + size = dc->cmdsize - sizeof(struct dylinker_command); + + if(need_bswap) + dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc); + else + dylinker_name = (char*)((dc->name.offset)+(int)dc); + +#ifdef OVERRIDE_DYLINKER + dylinker_name = DYLINKER_NAME; +#else + if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1) + qerror("can't allocate the new dylinker name\n"); +#endif + + DPRINTF("dylinker_name %s\n", dylinker_name); + return load_object(dylinker_name, NULL, NULL); +} + +int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide) +{ + unsigned long addr = sc->vmaddr; + unsigned long size = sc->filesize; + unsigned long error = 0; + + if(need_bswap) + bswap_segcmd(sc); + + if(sc->vmaddr == 0) + { + DPRINTF("load_segment: sc->vmaddr == 0 returning\n"); + return -1; + } + + if (strcmp(sc->segname, "__PAGEZERO") == 0) + { + DPRINTF("load_segment: __PAGEZERO returning\n"); + return -1; + } + + /* Right now mmap memory */ + /* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */ + DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide); + + if(sc->filesize > 0) + { + int opt = 0; + + if(fixed) + opt |= MAP_FIXED; + + DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide); + + addr = target_mmap(sc->vmaddr+slide, sc->filesize, sc->initprot, opt, fd, mh_pos + sc->fileoff); + + if(addr==-1) + qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide); + + error = addr-sc->vmaddr; + } + else + { + addr = sc->vmaddr+slide; + error = slide; + } + + if(sc->vmsize > sc->filesize) + { + addr += sc->filesize; + size = sc->vmsize-sc->filesize; + addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if(addr==-1) + qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide); + } + + return error; +} + +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; +} + +/* load a mach-o object file */ +int load_object(const char *filename, struct target_pt_regs * regs, void ** mh) +{ + int need_bswap = 0; + int entry_point = 0; + int dyld_entry_point = 0; + int slide, mmapfixed; + int fd; + struct load_command *lcmds, *lc; + int is_fat = 0; + unsigned int i, magic; + int mach_hdr_pos = 0; + struct mach_header mach_hdr; + + /* for symbol lookup whith -d flag. */ + struct symtab_command * symtabcmd = 0; + struct nlist_extended *symtab, *sym; + struct nlist *symtab_std, *syment; + char *strtab; + + fd = open(filename, O_RDONLY); + if (fd < 0) + qerror("can't open file '%s'", filename); + + /* Read magic header. */ + if (read(fd, &magic, sizeof (magic)) != sizeof (magic)) + qerror("unable to read Magic of '%s'", filename); + + /* Check Mach identification. */ + if(magic == MH_MAGIC) + { + is_fat = 0; + need_bswap = 0; + } else if (magic == MH_CIGAM) + { + is_fat = 0; + need_bswap = 1; + } else if (magic == FAT_MAGIC) + { + is_fat = 1; + need_bswap = 0; + } else if (magic == FAT_CIGAM) + { + is_fat = 1; + need_bswap = 1; + } + else + qerror("Not a Mach-O file.", filename); + + DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]"); + if(is_fat) + { + int found = 0; + struct fat_header fh; + struct fat_arch *fa; + + lseek(fd, 0, SEEK_SET); + + /* Read Fat header. */ + if (read(fd, &fh, sizeof (fh)) != sizeof (fh)) + qerror("unable to read file header"); + + if(need_bswap) + bswap_fh(&fh); + + /* Read Fat Arch. */ + fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch); + + if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch) + qerror("unable to read file header"); + + for( i = 0; i < fh.nfat_arch; i++, fa++) + { + if(need_bswap) + bswap_fa(fa); + if(fa->cputype == TARGET_CPU_TYPE) + { + mach_hdr_pos = fa->offset; + lseek(fd, mach_hdr_pos, SEEK_SET); + + /* Read Mach header. */ + + if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header)) + qerror("unable to read file header"); + + if(mach_hdr.magic == MH_MAGIC) + need_bswap = 0; + else if (mach_hdr.magic == MH_CIGAM) + need_bswap = 1; + else + qerror("Invalid mach header in Fat Mach-O File"); + found = 1; + break; + } + } + if(!found) + qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME); + } + else + { + lseek(fd, 0, SEEK_SET); + /* Read Mach header */ + if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr)) + qerror("%s: unable to read file header", filename); + } + + if(need_bswap) + bswap_mh(&mach_hdr); + + if ((mach_hdr.cputype) != TARGET_CPU_TYPE) + qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME); + + + switch(mach_hdr.filetype) + { + case MH_EXECUTE: break; + case MH_FVMLIB: + case MH_DYLIB: + case MH_DYLINKER: break; + default: + qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype); + } + + /* read segment headers */ + lcmds = malloc(mach_hdr.sizeofcmds); + + if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds) + qerror("%s: unable to read load_command", filename); + slide = 0; + mmapfixed = 0; + for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++) + { + + if(need_bswap) + bswap_lc(lc); + switch(lc->cmd) + { + case LC_SEGMENT: + /* The main_exe can't be relocated */ + if(mach_hdr.filetype == MH_EXECUTE) + mmapfixed = 1; + + slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide); + + /* other segment must be mapped according to slide exactly, if load_segment did something */ + if(slide != -1) + mmapfixed = 1; + else + slide = 0; /* load_segment didn't map the segment */ + + if(mach_hdr.filetype == MH_EXECUTE && slide != 0) + qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide); + + if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0) + { + /* Text section */ + if(mach_hdr.filetype == MH_EXECUTE) + { + /* return the mach_header */ + *mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide); + } + else + { + /* it is dyld save the section for gdb, we will be interested in dyld symbol + while debuging */ + macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide); + macho_offset = slide; + } + } + break; + case LC_LOAD_DYLINKER: + dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap ); + break; + case LC_LOAD_DYLIB: + /* dyld will do that for us */ + break; + case LC_THREAD: + case LC_UNIXTHREAD: + { + struct target_pt_regs * _regs; + if(mach_hdr.filetype == MH_DYLINKER) + _regs = regs; + else + _regs = 0; + entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap ); + } + break; + case LC_SYMTAB: + /* Save the symtab and strtab */ + symtabcmd = (struct symtab_command *)lc; + break; + case LC_ID_DYLINKER: + case LC_ID_DYLIB: + case LC_UUID: + case LC_DYSYMTAB: + case LC_TWOLEVEL_HINTS: + case LC_PREBIND_CKSUM: + case LC_SUB_LIBRARY: + break; + default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename); + } + lc = (struct load_command*)((int)(lc)+(lc->cmdsize)); + } + + if(symtabcmd) + { + if(need_bswap) + bswap_symtabcmd(symtabcmd); + + symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist)); + strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize); + + symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms); + + if(need_bswap) + { + for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++) + bswap_sym(syment); + } + + for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++) + { + struct nlist *sym_follow, *sym_next = 0; + unsigned int j; + memset(sym, 0, sizeof(*sym)); + + sym->n_type = syment->n_type; + 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 < symtabcmd->nsyms; j++, sym_follow++) { + if ( 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 = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */ + + sym->st_value += slide; + } + + free((void*)symtab_std); + + { + DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms); + struct syminfo *s; + s = malloc(sizeof(*s)); + s->disas_symtab = symtab; + s->disas_strtab = strtab; + s->disas_num_syms = symtabcmd->nsyms; + s->next = syminfos; + syminfos = s; + } + } + close(fd); + if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point) + return dyld_entry_point; + else + return entry_point+slide; +} + +extern unsigned long stack_size; + +unsigned long setup_arg_pages(void * mh, char ** argv, char ** env) +{ + unsigned long stack_base, error, size; + int i; + int * stack; + int argc, envc; + + /* Create enough stack to hold everything. If we don't use + * it for args, we'll use it for something else... + */ + size = stack_size; + + error = target_mmap(0, + size + qemu_host_page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (error == -1) + qerror("stk mmap"); + + /* we reserve one extra page at the top of the stack as guard */ + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); + + stack_base = error + size; + stack = (void*)stack_base; +/* + * | STRING AREA | + * +-------------+ + * | 0 | +* +-------------+ + * | apple[n] | + * +-------------+ + * : + * +-------------+ + * | apple[0] | + * +-------------+ + * | 0 | + * +-------------+ + * | env[n] | + * +-------------+ + * : + * : + * +-------------+ + * | env[0] | + * +-------------+ + * | 0 | + * +-------------+ + * | arg[argc-1] | + * +-------------+ + * : + * : + * +-------------+ + * | arg[0] | + * +-------------+ + * | argc | + * +-------------+ + * sp-> | mh | address of where the a.out's file offset 0 is in memory + * +-------------+ +*/ + /* Construct the stack Stack grows down */ + stack--; + + /* XXX: string should go up there */ + + *stack = 0; + stack--; + + /* Push the absolute path of our executable */ + DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]); + stl(stack, (int) argv[0]); + + stack--; + + stl(stack, 0); + stack--; + + /* Get envc */ + for(envc = 0; env[envc]; envc++); + + for(i = envc-1; i >= 0; i--) + { + DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]); + stl(stack, (int)env[i]); + stack--; + + /* XXX: remove that when string will be on top of the stack */ + page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID); + } + + /* Add on the stack the interp_prefix choosen if so */ + if(interp_prefix[0]) + { + char *dyld_root; + asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix); + page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID); + + stl(stack, (int)dyld_root); + stack--; + } + +#ifdef DONT_USE_DYLD_SHARED_MAP + { + char *shared_map_mode; + asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid"); + page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID); + + stl(stack, (int)shared_map_mode); + stack--; + } +#endif + +#ifdef ACTIVATE_DYLD_TRACE + char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes", + "DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes", + "DYLD_PRINT_INITIALIZERS=yes", + "DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" }; + + char ** extra_env = malloc(sizeof(extra_env_static)); + bcopy(extra_env_static, extra_env, sizeof(extra_env_static)); + page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID); + + for(i = 0; i<9; i++) + { + DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]); + stl(stack, (int) extra_env[i]); + stack--; + } +#endif + + stl(stack, 0); + stack--; + + /* Get argc */ + for(argc = 0; argv[argc]; argc++); + + for(i = argc-1; i >= 0; i--) + { + DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]); + stl(stack, (int) argv[i]); + stack--; + + /* XXX: remove that when string will be on top of the stack */ + page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID); + } + + DPRINTF("pushing argc %d \n", argc); + stl(stack, argc); + stack--; + + DPRINTF("pushing mh 0x%x \n", (int)mh); + stl(stack, (int) mh); + + /* Stack points on the mh */ + return (unsigned long)stack; +} + +int mach_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs) +{ + int entrypoint, stack; + void * mh; /* the Mach Header that will be used by dyld */ + + DPRINTF("mach_exec at 0x%x\n", (int)mach_exec); + + entrypoint = load_object(filename, regs, &mh); + stack = setup_arg_pages(mh, argv, envp); +#if defined(TARGET_I386) + regs->eip = entrypoint; + regs->esp = stack; +#elif defined(TARGET_PPC) + regs->nip = entrypoint; + regs->gpr[1] = stack; +#endif + DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh); + + if(!entrypoint) + qerror("%s: no entry point!\n", filename); + + return 0; +} diff --git a/darwin-user/main.c b/darwin-user/main.c new file mode 100644 index 000000000..259aab324 --- /dev/null +++ b/darwin-user/main.c @@ -0,0 +1,922 @@ +/* + * qemu user main + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2006 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 +#include +#include +#include +#include +#include + +#include +#include + +#include "qemu.h" + +#define DEBUG_LOGFILE "/tmp/qemu.log" + +#ifdef __APPLE__ +#include +# define environ (*_NSGetEnviron()) +#endif + +#include +#include + +const char *interp_prefix = ""; + +asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000"); + +/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so + we allocate a bigger stack. Need a better solution, for example + by remapping the process stack directly at the right place */ +unsigned long stack_size = 512 * 1024; + +void qerror(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(1); +} + +void gemu_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void cpu_outb(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); +} + +void cpu_outw(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); +} + +void cpu_outl(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); +} + +int cpu_inb(CPUState *env, int addr) +{ + fprintf(stderr, "inb: port=0x%04x\n", addr); + return 0; +} + +int cpu_inw(CPUState *env, int addr) +{ + fprintf(stderr, "inw: port=0x%04x\n", addr); + return 0; +} + +int cpu_inl(CPUState *env, int addr) +{ + fprintf(stderr, "inl: port=0x%04x\n", addr); + return 0; +} + +int cpu_get_pic_interrupt(CPUState *env) +{ + return -1; +} +#ifdef TARGET_PPC + +static inline uint64_t cpu_ppc_get_tb (CPUState *env) +{ + /* TO FIX */ + return 0; +} + +uint32_t cpu_ppc_load_tbl (CPUState *env) +{ + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; +} + +uint32_t cpu_ppc_load_tbu (CPUState *env) +{ + return cpu_ppc_get_tb(env) >> 32; +} + +static void cpu_ppc_store_tb (CPUState *env, uint64_t value) +{ + /* TO FIX */ +} + +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); +} + +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); +} + +uint32_t cpu_ppc_load_decr (CPUState *env) +{ + /* TO FIX */ + return -1; +} + +void cpu_ppc_store_decr (CPUState *env, uint32_t value) +{ + /* TO FIX */ +} + +void cpu_loop(CPUPPCState *env) +{ + int trapnr; + uint32_t ret; + target_siginfo_t info; + + for(;;) { + trapnr = cpu_ppc_exec(env); + if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && + trapnr != EXCP_TRACE) { + if (loglevel > 0) { + cpu_dump_state(env, logfile, fprintf, 0); + } + } + switch(trapnr) { + case EXCP_NONE: + break; + case EXCP_SYSCALL_USER: + /* system call */ + if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) + ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]*/); + else if(((int)env->gpr[0])<0) + ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]); + else + ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]); + + /* Unix syscall error signaling */ + if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) + { + if( (int)ret < 0 ) + env->nip += 0; + else + env->nip += 4; + } + + /* Return value */ + env->gpr[3] = ret; + break; + case EXCP_RESET: + /* Should not happen ! */ + fprintf(stderr, "RESET asked... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "RESET asked... Stop emulation\n"); + abort(); + case EXCP_MACHINE_CHECK: + fprintf(stderr, "Machine check exeption... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "RESET asked... Stop emulation\n"); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_OBJERR; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + case EXCP_DSI: +#ifndef DAR +/* To deal with multiple qemu header version as host for the darwin-user code */ +# define DAR SPR_DAR +#endif + fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]); + if (loglevel) { + fprintf(logfile, "Invalid data memory access: 0x%08x\n", + env->spr[DAR]); + } + /* Handle this via the gdb */ + gdb_handlesig (env, SIGSEGV); + + info.si_addr = (void*)env->nip; + queue_signal(info.si_signo, &info); + break; + case EXCP_ISI: + fprintf(stderr, "Invalid instruction fetch\n"); + if (loglevel) + fprintf(logfile, "Invalid instruction fetch\n"); + /* Handle this via the gdb */ + gdb_handlesig (env, SIGSEGV); + + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case EXCP_EXTERNAL: + /* Should not happen ! */ + fprintf(stderr, "External interruption... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "External interruption... Stop emulation\n"); + abort(); + case EXCP_ALIGN: + fprintf(stderr, "Invalid unaligned memory access\n"); + if (loglevel) + fprintf(logfile, "Invalid unaligned memory access\n"); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRALN; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case EXCP_PROGRAM: + switch (env->error_code & ~0xF) { + case EXCP_FP: + fprintf(stderr, "Program exception\n"); + if (loglevel) + fprintf(logfile, "Program exception\n"); + /* Set FX */ + env->fpscr[7] |= 0x8; + /* Finally, update FEX */ + if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & + ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) + env->fpscr[7] |= 0x4; + info.si_signo = SIGFPE; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_FP_OX: + info.si_code = FPE_FLTOVF; + break; + case EXCP_FP_UX: + info.si_code = FPE_FLTUND; + break; + case EXCP_FP_ZX: + case EXCP_FP_VXZDZ: + info.si_code = FPE_FLTDIV; + break; + case EXCP_FP_XX: + info.si_code = FPE_FLTRES; + break; + case EXCP_FP_VXSOFT: + info.si_code = FPE_FLTINV; + break; + case EXCP_FP_VXNAN: + case EXCP_FP_VXISI: + case EXCP_FP_VXIDI: + case EXCP_FP_VXIMZ: + case EXCP_FP_VXVC: + case EXCP_FP_VXSQRT: + case EXCP_FP_VXCVI: + info.si_code = FPE_FLTSUB; + break; + default: + fprintf(stderr, "Unknown floating point exception " + "(%02x)\n", env->error_code); + if (loglevel) { + fprintf(logfile, "Unknown floating point exception " + "(%02x)\n", env->error_code & 0xF); + } + } + break; + case EXCP_INVAL: + fprintf(stderr, "Invalid instruction\n"); + if (loglevel) + fprintf(logfile, "Invalid instruction\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_INVAL_INVAL: + info.si_code = ILL_ILLOPC; + break; + case EXCP_INVAL_LSWX: + info.si_code = ILL_ILLOPN; + break; + case EXCP_INVAL_SPR: + info.si_code = ILL_PRVREG; + break; + case EXCP_INVAL_FP: + info.si_code = ILL_COPROC; + break; + default: + fprintf(stderr, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + if (loglevel) { + fprintf(logfile, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + } + info.si_code = ILL_ILLADR; + break; + } + /* Handle this via the gdb */ + gdb_handlesig (env, SIGSEGV); + break; + case EXCP_PRIV: + fprintf(stderr, "Privilege violation\n"); + if (loglevel) + fprintf(logfile, "Privilege violation\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_PRIV_OPC: + info.si_code = ILL_PRVOPC; + break; + case EXCP_PRIV_REG: + info.si_code = ILL_PRVREG; + break; + default: + fprintf(stderr, "Unknown privilege violation (%02x)\n", + env->error_code & 0xF); + info.si_code = ILL_PRVOPC; + break; + } + break; + case EXCP_TRAP: + fprintf(stderr, "Tried to call a TRAP\n"); + if (loglevel) + fprintf(logfile, "Tried to call a TRAP\n"); + abort(); + default: + /* Should not happen ! */ + fprintf(stderr, "Unknown program exception (%02x)\n", + env->error_code); + if (loglevel) { + fprintf(logfile, "Unknwon program exception (%02x)\n", + env->error_code); + } + abort(); + } + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case EXCP_NO_FP: + fprintf(stderr, "No floating point allowed\n"); + if (loglevel) + fprintf(logfile, "No floating point allowed\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_COPROC; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case EXCP_DECR: + /* Should not happen ! */ + fprintf(stderr, "Decrementer exception\n"); + if (loglevel) + fprintf(logfile, "Decrementer exception\n"); + abort(); + case EXCP_TRACE: + /* Pass to gdb: we use this to trace execution */ + gdb_handlesig (env, SIGTRAP); + break; + case EXCP_FP_ASSIST: + /* Should not happen ! */ + fprintf(stderr, "Floating point assist exception\n"); + if (loglevel) + fprintf(logfile, "Floating point assist exception\n"); + abort(); + case EXCP_MTMSR: + /* We reloaded the msr, just go on */ + if (msr_pr == 0) { + fprintf(stderr, "Tried to go into supervisor mode !\n"); + if (loglevel) + fprintf(logfile, "Tried to go into supervisor mode !\n"); + abort(); + } + break; + case EXCP_BRANCH: + /* We stopped because of a jump... */ + break; + case EXCP_INTERRUPT: + /* Don't know why this should ever happen... */ + fprintf(stderr, "EXCP_INTERRUPT\n"); + break; + case EXCP_DEBUG: + gdb_handlesig (env, SIGTRAP); + break; + default: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + if (loglevel) { + fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " + "0x%02x - aborting\n", trapnr, env->error_code); + } + abort(); + } + process_pending_signals(env); + } +} +#endif + + +#ifdef TARGET_I386 + +/***********************************************************/ +/* CPUX86 core interface */ + +uint64_t cpu_get_tsc(CPUX86State *env) +{ + return cpu_get_real_ticks(); +} + +void +write_dt(void *ptr, unsigned long addr, unsigned long limit, + int flags) +{ + unsigned int e1, e2; + e1 = (addr << 16) | (limit & 0xffff); + e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); + e2 |= flags; + stl((uint8_t *)ptr, e1); + stl((uint8_t *)ptr + 4, e2); +} + +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, + unsigned long addr, unsigned int sel) +{ + unsigned int e1, e2; + e1 = (addr & 0xffff) | (sel << 16); + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); + stl((uint8_t *)ptr, e1); + stl((uint8_t *)ptr + 4, e2); +} + +#define GDT_TABLE_SIZE 14 +#define LDT_TABLE_SIZE 15 +#define IDT_TABLE_SIZE 256 +#define TSS_SIZE 104 +uint64_t gdt_table[GDT_TABLE_SIZE]; +uint64_t ldt_table[LDT_TABLE_SIZE]; +uint64_t idt_table[IDT_TABLE_SIZE]; +uint32_t tss[TSS_SIZE]; + +/* only dpl matters as we do only user space emulation */ +static void set_idt(int n, unsigned int dpl) +{ + set_gate(idt_table + n, 0, dpl, 0, 0); +} + +/* ABI convention: after a syscall if there was an error the CF flag is set */ +static inline set_error(CPUX86State *env, int ret) +{ + if(ret<0) + env->eflags = env->eflags | 0x1; + else + env->eflags &= ~0x1; + env->regs[R_EAX] = ret; +} + +void cpu_loop(CPUX86State *env) +{ + int trapnr; + int ret; + uint8_t *pc; + target_siginfo_t info; + + for(;;) { + trapnr = cpu_x86_exec(env); + uint32_t *params = (uint32_t *)env->regs[R_ESP]; + switch(trapnr) { + case 0x79: /* Our commpage hack back door exit is here */ + do_commpage(env, env->eip, *(params + 1), *(params + 2), + *(params + 3), *(params + 4), + *(params + 5), *(params + 6), + *(params + 7), *(params + 8)); + break; + case 0x81: /* mach syscall */ + { + ret = do_mach_syscall(env, env->regs[R_EAX], + *(params + 1), *(params + 2), + *(params + 3), *(params + 4), + *(params + 5), *(params + 6), + *(params + 7), *(params + 8)); + set_error(env, ret); + break; + } + case 0x90: /* unix backdoor */ + { + /* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/ + int saved_stack = env->regs[R_ESP]; + env->regs[R_ESP] = env->regs[R_ECX]; + + ret = do_unix_syscall(env, env->regs[R_EAX]); + + env->regs[R_ECX] = env->regs[R_ESP]; + env->regs[R_ESP] = saved_stack; + + set_error(env, ret); + break; + } + case 0x80: /* unix syscall */ + { + ret = do_unix_syscall(env, env->regs[R_EAX]/*, + *(params + 1), *(params + 2), + *(params + 3), *(params + 4), + *(params + 5), *(params + 6), + *(params + 7), *(params + 8)*/); + set_error(env, ret); + break; + } + case 0x82: /* thread syscall */ + { + ret = do_thread_syscall(env, env->regs[R_EAX], + *(params + 1), *(params + 2), + *(params + 3), *(params + 4), + *(params + 5), *(params + 6), + *(params + 7), *(params + 8)); + set_error(env, ret); + break; + } + case EXCP0B_NOSEG: + case EXCP0C_STACK: + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_NOOP; + info.si_addr = 0; + gdb_handlesig (env, SIGBUS); + queue_signal(info.si_signo, &info); + break; + case EXCP0D_GPF: + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_NOOP; + info.si_addr = 0; + gdb_handlesig (env, SIGSEGV); + queue_signal(info.si_signo, &info); + break; + case EXCP0E_PAGE: + info.si_signo = SIGSEGV; + info.si_errno = 0; + if (!(env->error_code & 1)) + info.si_code = SEGV_MAPERR; + else + info.si_code = SEGV_ACCERR; + info.si_addr = (void*)env->cr[2]; + gdb_handlesig (env, SIGSEGV); + queue_signal(info.si_signo, &info); + break; + case EXCP00_DIVZ: + /* division by zero */ + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = FPE_INTDIV; + info.si_addr = (void*)env->eip; + gdb_handlesig (env, SIGFPE); + queue_signal(info.si_signo, &info); + break; + case EXCP01_SSTP: + case EXCP03_INT3: + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void*)env->eip; + gdb_handlesig (env, SIGTRAP); + queue_signal(info.si_signo, &info); + break; + case EXCP04_INTO: + case EXCP05_BOUND: + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_NOOP; + info.si_addr = 0; + gdb_handlesig (env, SIGSEGV); + queue_signal(info.si_signo, &info); + break; + case EXCP06_ILLOP: + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPN; + info.si_addr = (void*)env->eip; + gdb_handlesig (env, SIGILL); + queue_signal(info.si_signo, &info); + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + pc = (void*)(env->segs[R_CS].base + env->eip); + fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", + (long)pc, trapnr); + abort(); + } + process_pending_signals(env); + } +} +#endif + +void usage(void) +{ + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" + "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n" + "Darwin CPU emulator (compiled for %s emulation)\n" + "\n" + "-h print this help\n" + "-L path set the elf interpreter prefix (default=%s)\n" + "-s size set the stack size in bytes (default=%ld)\n" + "\n" + "debug options:\n" +#ifdef USE_CODE_COPY + "-no-code-copy disable code copy acceleration\n" +#endif + "-d options activate log (logfile=%s)\n" + "-g wait for gdb on port 1234\n" + "-p pagesize set the host page size to 'pagesize'\n", + TARGET_ARCH, + interp_prefix, + stack_size, + DEBUG_LOGFILE); + _exit(1); +} + +/* XXX: currently only used for async signals (see signal.c) */ +CPUState *global_env; +/* used only if single thread */ +CPUState *cpu_single_env = NULL; + +/* used to free thread contexts */ +TaskState *first_task_state; + +int main(int argc, char **argv) +{ + const char *filename; + struct target_pt_regs regs1, *regs = ®s1; + TaskState ts1, *ts = &ts1; + CPUState *env; + int optind; + short use_gdbstub = 0; + const char *r; + + if (argc <= 1) + usage(); + + /* init debug */ + cpu_set_log_filename(DEBUG_LOGFILE); + + optind = 1; + for(;;) { + if (optind >= argc) + break; + r = argv[optind]; + if (r[0] != '-') + break; + optind++; + r++; + if (!strcmp(r, "-")) { + break; + } else if (!strcmp(r, "d")) { + int mask; + CPULogItem *item; + + if (optind >= argc) + break; + + r = argv[optind++]; + mask = cpu_str_to_log_mask(r); + if (!mask) { + printf("Log items (comma separated):\n"); + for(item = cpu_log_items; item->mask != 0; item++) { + printf("%-10s %s\n", item->name, item->help); + } + exit(1); + } + cpu_set_log(mask); + } else if (!strcmp(r, "s")) { + r = argv[optind++]; + stack_size = strtol(r, (char **)&r, 0); + if (stack_size <= 0) + usage(); + if (*r == 'M') + stack_size *= 1024 * 1024; + else if (*r == 'k' || *r == 'K') + stack_size *= 1024; + } else if (!strcmp(r, "L")) { + interp_prefix = argv[optind++]; + } else if (!strcmp(r, "p")) { + qemu_host_page_size = atoi(argv[optind++]); + if (qemu_host_page_size == 0 || + (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { + fprintf(stderr, "page size must be a power of two\n"); + exit(1); + } + } else + if (!strcmp(r, "g")) { + use_gdbstub = 1; + } else +#ifdef USE_CODE_COPY + if (!strcmp(r, "no-code-copy")) { + code_copy_enabled = 0; + } else +#endif + { + usage(); + } + } + if (optind >= argc) + usage(); + filename = argv[optind]; + + /* Zero out regs */ + memset(regs, 0, sizeof(struct target_pt_regs)); + +#if 0 + /* Scan interp_prefix dir for replacement files. */ + init_paths(interp_prefix); +#endif + + /* NOTE: we need to init the CPU at this stage to get + qemu_host_page_size */ + env = cpu_init(); + + printf("Starting %s with qemu\n----------------\n", filename); + + commpage_init(); + + if (mach_exec(filename, argv+optind, environ, regs) != 0) { + printf("Error loading %s\n", filename); + _exit(1); + } + + syscall_init(); + signal_init(); + global_env = env; + + /* build Task State */ + memset(ts, 0, sizeof(TaskState)); + env->opaque = ts; + ts->used = 1; + env->user_mode_only = 1; + +#if defined(TARGET_I386) + cpu_x86_set_cpl(env, 3); + + env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; + env->hflags |= HF_PE_MASK; + + if (env->cpuid_features & CPUID_SSE) { + env->cr[4] |= CR4_OSFXSR_MASK; + env->hflags |= HF_OSFXSR_MASK; + } + + /* flags setup : we activate the IRQs by default as in user mode */ + env->eflags |= IF_MASK; + + /* darwin register setup */ + env->regs[R_EAX] = regs->eax; + env->regs[R_EBX] = regs->ebx; + env->regs[R_ECX] = regs->ecx; + env->regs[R_EDX] = regs->edx; + env->regs[R_ESI] = regs->esi; + env->regs[R_EDI] = regs->edi; + env->regs[R_EBP] = regs->ebp; + env->regs[R_ESP] = regs->esp; + env->eip = regs->eip; + + /* Darwin LDT setup */ + /* 2 - User code segment + 3 - User data segment + 4 - User cthread */ + bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0])); + env->ldt.base = (uint32_t) ldt_table; + env->ldt.limit = sizeof(ldt_table) - 1; + + write_dt(ldt_table + 2, 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); + write_dt(ldt_table + 3, 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + write_dt(ldt_table + 4, 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + + /* Darwin GDT setup. + * has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86, + now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */ + bzero(gdt_table, sizeof(gdt_table)); + env->gdt.base = (uint32_t)gdt_table; + env->gdt.limit = sizeof(gdt_table) - 1; + + /* Set up a back door to handle sysenter syscalls (unix) */ + char * syscallbackdoor = malloc(64); + page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID); + + int i = 0; + syscallbackdoor[i++] = 0xcd; + syscallbackdoor[i++] = 0x90; /* int 0x90 */ + syscallbackdoor[i++] = 0x0F; + syscallbackdoor[i++] = 0x35; /* sysexit */ + + /* Darwin sysenter/sysexit setup */ + env->sysenter_cs = 0x1; //XXX + env->sysenter_eip = (int)syscallbackdoor; + env->sysenter_esp = (int)malloc(64); + + /* Darwin TSS setup + This must match up with GDT[4] */ + env->tr.base = (uint32_t) tss; + env->tr.limit = sizeof(tss) - 1; + env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT); + stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment + + /* Darwin interrupt setup */ + bzero(idt_table, sizeof(idt_table)); + env->idt.base = (uint32_t) idt_table; + env->idt.limit = sizeof(idt_table) - 1; + set_idt(0, 0); + set_idt(1, 0); + set_idt(2, 0); + set_idt(3, 3); + set_idt(4, 3); + set_idt(5, 3); + set_idt(6, 0); + set_idt(7, 0); + set_idt(8, 0); + set_idt(9, 0); + set_idt(10, 0); + set_idt(11, 0); + set_idt(12, 0); + set_idt(13, 0); + set_idt(14, 0); + set_idt(15, 0); + set_idt(16, 0); + set_idt(17, 0); + set_idt(18, 0); + set_idt(19, 0); + /* Syscalls are done via + int 0x80 (unix) (rarely used) + int 0x81 (mach) + int 0x82 (thread) + int 0x83 (diag) (not handled here) + sysenter/sysexit (unix) -> we redirect that to int 0x90 */ + set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */ + set_idt(0x80, 3); /* Unix Syscall */ + set_idt(0x81, 3); /* Mach Syscalls */ + set_idt(0x82, 3); /* thread Syscalls */ + + set_idt(0x90, 3); /* Unix Syscall backdoor */ + + + cpu_x86_load_seg(env, R_CS, __USER_CS); + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_FS, __USER_DS); + cpu_x86_load_seg(env, R_GS, __USER_DS); + +#elif defined(TARGET_PPC) + { + int i; + env->nip = regs->nip; + for(i = 0; i < 32; i++) { + env->gpr[i] = regs->gpr[i]; + } + } +#else +#error unsupported target CPU +#endif + + if (use_gdbstub) { + printf("Waiting for gdb Connection on port 1234...\n"); + gdbserver_start (1234); + gdb_handlesig(env, 0); + } + + cpu_loop(env); + /* never exits */ + return 0; +} diff --git a/darwin-user/mmap.c b/darwin-user/mmap.c new file mode 100644 index 000000000..ada613d36 --- /dev/null +++ b/darwin-user/mmap.c @@ -0,0 +1,411 @@ +/* + * mmap support for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "qemu.h" + +//#define DEBUG_MMAP + +/* NOTE: all the constants are the HOST ones */ +int target_mprotect(unsigned long start, unsigned long len, int prot) +{ + unsigned long end, host_start, host_end, addr; + int prot1, ret; + +#ifdef DEBUG_MMAP + printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); +#endif + + if ((start & ~TARGET_PAGE_MASK) != 0) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return -EINVAL; + if (len == 0) + return 0; + + host_start = start & qemu_host_page_mask; + host_end = HOST_PAGE_ALIGN(end); + if (start > host_start) { + /* handle host page containing start */ + prot1 = prot; + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + if (host_end == host_start + qemu_host_page_size) { + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + end = host_end; + } + ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS); + if (ret != 0) + return ret; + host_start += qemu_host_page_size; + } + if (end < host_end) { + prot1 = prot; + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size, + prot1 & PAGE_BITS); + if (ret != 0) + return ret; + host_end -= qemu_host_page_size; + } + + /* handle the pages in the middle */ + if (host_start < host_end) { + ret = mprotect((void *)host_start, host_end - host_start, prot); + if (ret != 0) + return ret; + } + page_set_flags(start, start + len, prot | PAGE_VALID); + return 0; +} + +/* map an incomplete host page */ +int mmap_frag(unsigned long host_start, + unsigned long start, unsigned long end, + int prot, int flags, int fd, unsigned long offset) +{ + unsigned long host_end, ret, addr; + int prot1, prot_new; + + host_end = host_start + qemu_host_page_size; + + /* get the protection of the target pages outside the mapping */ + prot1 = 0; + for(addr = host_start; addr < host_end; addr++) { + if (addr < start || addr >= end) + prot1 |= page_get_flags(addr); + } + + if (prot1 == 0) { + /* no page was there, so we allocate one */ + ret = (long)mmap((void *)host_start, qemu_host_page_size, prot, + flags | MAP_ANONYMOUS, -1, 0); + if (ret == -1) + return ret; + } + prot1 &= PAGE_BITS; + + prot_new = prot | prot1; + if (!(flags & MAP_ANONYMOUS)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ +#ifndef __APPLE__ + if ((flags & MAP_TYPE) == MAP_SHARED && +#else + if ((flags & MAP_SHARED) && +#endif + (prot & PROT_WRITE)) + return -EINVAL; + + /* adjust protection to be able to read */ + if (!(prot1 & PROT_WRITE)) + mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE); + + /* read the corresponding file data */ + pread(fd, (void *)start, end - start, offset); + + /* put final protection */ + if (prot_new != (prot1 | PROT_WRITE)) + mprotect((void *)host_start, qemu_host_page_size, prot_new); + } else { + /* just update the protection */ + if (prot_new != prot1) { + mprotect((void *)host_start, qemu_host_page_size, prot_new); + } + } + return 0; +} + +/* NOTE: all the constants are the HOST ones */ +long target_mmap(unsigned long start, unsigned long len, int prot, + int flags, int fd, unsigned long offset) +{ + unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len; +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) + static unsigned long last_start = 0x40000000; +#endif + +#ifdef DEBUG_MMAP + { + printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", + start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); + if (flags & MAP_FIXED) + printf("MAP_FIXED "); + if (flags & MAP_ANONYMOUS) + printf("MAP_ANON "); +#ifndef MAP_TYPE +# define MAP_TYPE 0x3 +#endif + switch(flags & MAP_TYPE) { + case MAP_PRIVATE: + printf("MAP_PRIVATE "); + break; + case MAP_SHARED: + printf("MAP_SHARED "); + break; + default: + printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); + break; + } + printf("fd=%d offset=%lx\n", fd, offset); + } +#endif + + if (offset & ~TARGET_PAGE_MASK) + return -EINVAL; + + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return start; + host_start = start & qemu_host_page_mask; + + if (!(flags & MAP_FIXED)) { +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) + /* tell the kenel to search at the same place as i386 */ + if (host_start == 0) { + host_start = last_start; + last_start += HOST_PAGE_ALIGN(len); + } +#endif + if (qemu_host_page_size != qemu_real_host_page_size) { + /* NOTE: this code is only for debugging with '-p' option */ + /* reserve a memory area */ + host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; + host_start = (long)mmap((void *)host_start, host_len, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (host_start == -1) + return host_start; + host_end = host_start + host_len; + start = HOST_PAGE_ALIGN(host_start); + end = start + HOST_PAGE_ALIGN(len); + if (start > host_start) + munmap((void *)host_start, start - host_start); + if (end < host_end) + munmap((void *)end, host_end - end); + /* use it as a fixed mapping */ + flags |= MAP_FIXED; + } else { + /* if not fixed, no need to do anything */ + host_offset = offset & qemu_host_page_mask; + host_len = len + offset - host_offset; + start = (long)mmap((void *)host_start, host_len, + prot, flags, fd, host_offset); + if (start == -1) + return start; + /* update start so that it points to the file position at 'offset' */ + if (!(flags & MAP_ANONYMOUS)) + start += offset - host_offset; + goto the_end1; + } + } + + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + end = start + len; + host_end = HOST_PAGE_ALIGN(end); + + /* worst case: we cannot map the file because the offset is not + aligned, so we read it */ + if (!(flags & MAP_ANONYMOUS) && + (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ +#ifndef __APPLE__ + if ((flags & MAP_TYPE) == MAP_SHARED && +#else + if ((flags & MAP_SHARED) && +#endif + (prot & PROT_WRITE)) + return -EINVAL; + retaddr = target_mmap(start, len, prot | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (retaddr == -1) + return retaddr; + pread(fd, (void *)start, len, offset); + if (!(prot & PROT_WRITE)) { + ret = target_mprotect(start, len, prot); + if (ret != 0) + return ret; + } + goto the_end; + } + + /* handle the start of the mapping */ + if (start > host_start) { + if (host_end == host_start + qemu_host_page_size) { + /* one single host page */ + ret = mmap_frag(host_start, start, end, + prot, flags, fd, offset); + if (ret == -1) + return ret; + goto the_end1; + } + ret = mmap_frag(host_start, start, host_start + qemu_host_page_size, + prot, flags, fd, offset); + if (ret == -1) + return ret; + host_start += qemu_host_page_size; + } + /* handle the end of the mapping */ + if (end < host_end) { + ret = mmap_frag(host_end - qemu_host_page_size, + host_end - qemu_host_page_size, host_end, + prot, flags, fd, + offset + host_end - qemu_host_page_size - start); + if (ret == -1) + return ret; + host_end -= qemu_host_page_size; + } + + /* map the middle (easier) */ + if (host_start < host_end) { + unsigned long offset1; + if (flags & MAP_ANONYMOUS) + offset1 = 0; + else + offset1 = offset + host_start - start; + ret = (long)mmap((void *)host_start, host_end - host_start, + prot, flags, fd, offset1); + if (ret == -1) + return ret; + } + the_end1: + page_set_flags(start, start + len, prot | PAGE_VALID); + the_end: +#ifdef DEBUG_MMAP + printf("target_mmap: ret=0x%lx\n", (long)start); + page_dump(stdout); + printf("\n"); +#endif + return start; +} + +int target_munmap(unsigned long start, unsigned long len) +{ + unsigned long end, host_start, host_end, addr; + int prot, ret; + +#ifdef DEBUG_MMAP + printf("munmap: start=0x%lx len=0x%lx\n", start, len); +#endif + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return -EINVAL; + end = start + len; + host_start = start & qemu_host_page_mask; + host_end = HOST_PAGE_ALIGN(end); + + if (start > host_start) { + /* handle host page containing start */ + prot = 0; + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (host_end == host_start + qemu_host_page_size) { + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + end = host_end; + } + if (prot != 0) + host_start += qemu_host_page_size; + } + if (end < host_end) { + prot = 0; + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (prot != 0) + host_end -= qemu_host_page_size; + } + + /* unmap what we can */ + if (host_start < host_end) { + ret = munmap((void *)host_start, host_end - host_start); + if (ret != 0) + return ret; + } + + page_set_flags(start, start + len, 0); + return 0; +} + +/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED + blocks which have been allocated starting on a host page */ +long target_mremap(unsigned long old_addr, unsigned long old_size, + unsigned long new_size, unsigned long flags, + unsigned long new_addr) +{ +#ifndef __APPLE__ + /* XXX: use 5 args syscall */ + new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags); + if (new_addr == -1) + return new_addr; + prot = page_get_flags(old_addr); + page_set_flags(old_addr, old_addr + old_size, 0); + page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); + return new_addr; +#else + qerror("target_mremap: unsupported\n"); +#endif + +} + +int target_msync(unsigned long start, unsigned long len, int flags) +{ + unsigned long end; + + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + if (end == start) + return 0; + + start &= qemu_host_page_mask; + return msync((void *)start, end - start, flags); +} + diff --git a/darwin-user/qemu.h b/darwin-user/qemu.h new file mode 100644 index 000000000..4d7713b50 --- /dev/null +++ b/darwin-user/qemu.h @@ -0,0 +1,179 @@ +#ifndef GEMU_H +#define GEMU_H + +#include "thunk.h" + +#include +#include + +#include "cpu.h" + +#include "gdbstub.h" + +typedef siginfo_t target_siginfo_t; +#define target_sigaction sigaction +#ifdef TARGET_I386 +struct target_pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + int xds; + int xes; + long orig_eax; + long eip; + int xcs; + long eflags; + long esp; + int xss; +}; +struct target_sigcontext { + int sc_onstack; + int sc_mask; + int sc_eax; + int sc_ebx; + int sc_ecx; + int sc_edx; + int sc_edi; + int sc_esi; + int sc_ebp; + int sc_esp; + int sc_ss; + int sc_eflags; + int sc_eip; + int sc_cs; + int sc_ds; + int sc_es; + int sc_fs; + int sc_gs; +}; + +#define __USER_CS (0x17) +#define __USER_DS (0x1F) + +#elif defined(TARGET_PPC) +struct target_pt_regs { + unsigned long gpr[32]; + unsigned long nip; + unsigned long msr; + unsigned long orig_gpr3; /* Used for restarting system calls */ + unsigned long ctr; + unsigned long link; + unsigned long xer; + unsigned long ccr; + unsigned long mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + unsigned long trap; /* Reason for being here */ + unsigned long dar; /* Fault registers */ + unsigned long dsisr; + unsigned long result; /* Result of a system call */ +}; + +struct target_sigcontext { + int sc_onstack; /* sigstack state to restore */ + int sc_mask; /* signal mask to restore */ + int sc_ir; /* pc */ + int sc_psw; /* processor status word */ + int sc_sp; /* stack pointer if sc_regs == NULL */ + void *sc_regs; /* (kernel private) saved state */ +}; + +#endif + +typedef struct TaskState { + struct TaskState *next; + int used; /* non zero if used */ + uint8_t stack[0]; +} __attribute__((aligned(16))) TaskState; + +void syscall_init(void); +long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); +long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); +long do_unix_syscall(void *cpu_env, int num); +int do_sigaction(int sig, const struct sigaction *act, + struct sigaction *oact); +int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss); + +void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); +void qerror(const char *fmt, ...); + +void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags); + +extern CPUState *global_env; +void cpu_loop(CPUState *env); +void init_paths(const char *prefix); +const char *path(const char *pathname); + +extern int loglevel; +extern FILE *logfile; + +/* commpage.c */ +void commpage_init(); +void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8); + +/* signal.c */ +void process_pending_signals(void *cpu_env); +void signal_init(void); +int queue_signal(int sig, target_siginfo_t *info); +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +long do_sigreturn(CPUState *env, int num); + +/* machload.c */ +int mach_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs); + +/* mmap.c */ +int target_mprotect(unsigned long start, unsigned long len, int prot); +long target_mmap(unsigned long start, unsigned long len, int prot, + int flags, int fd, unsigned long offset); +int target_munmap(unsigned long start, unsigned long len); +long target_mremap(unsigned long old_addr, unsigned long old_size, + unsigned long new_size, unsigned long flags, + unsigned long new_addr); +int target_msync(unsigned long start, unsigned long len, int flags); + +/* user access */ + +/* XXX: todo protect every memory access */ +#define lock_user(x,y,z) (void*)(x) +#define unlock_user(x,y,z) + +/* Mac OS X ABI arguments processing */ +#ifdef TARGET_I386 +static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env) +{ + uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i); + *i+=4; + return tswap32(*args); +} +static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env) +{ + uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i); + *i+=8; + return tswap64(*args); +} +#elif defined(TARGET_PPC) +static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env) +{ + /* XXX: won't work when args goes on stack after gpr10 */ + uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]); + *i+=4; + return tswap32(args); +} +static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env) +{ + /* XXX: won't work when args goes on stack after gpr10 */ + uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]); + *i+=(8 << 8) + 8; + return tswap64(args); +} +#endif + +#endif diff --git a/darwin-user/signal.c b/darwin-user/signal.c new file mode 100644 index 000000000..a0b9f89dc --- /dev/null +++ b/darwin-user/signal.c @@ -0,0 +1,463 @@ +/* + * Emulation of Linux signals + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __ia64__ +#undef uc_mcontext +#undef uc_sigmask +#undef uc_stack +#undef uc_link +#endif + +#include + +#include "qemu.h" + +#define DEBUG_SIGNAL + +#define MAX_SIGQUEUE_SIZE 1024 + +struct sigqueue { + struct sigqueue *next; + target_siginfo_t info; +}; + +struct emulated_sigaction { + struct target_sigaction sa; + int pending; /* true if signal is pending */ + struct sigqueue *first; + struct sigqueue info; /* in order to always have memory for the + first signal, we put it here */ +}; + +struct sigaltstack target_sigaltstack_used = { + 0, 0, SA_DISABLE +}; + +static struct emulated_sigaction sigact_table[NSIG]; +static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ +static struct sigqueue *first_free; /* first free siginfo queue entry */ +static int signal_pending; /* non zero if a signal may be pending */ + +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc); + + +static inline int host_to_target_signal(int sig) +{ + return sig; +} + +static inline int target_to_host_signal(int sig) +{ + return sig; +} + +/* siginfo conversion */ + + + +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) +{ + +} + +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) +{ + +} + +void signal_init(void) +{ + struct sigaction act; + int i; + + /* set all host signal handlers. ALL signals are blocked during + the handlers to serialize them. */ + sigfillset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = host_signal_handler; + for(i = 1; i < NSIG; i++) { + sigaction(i, &act, NULL); + } + + memset(sigact_table, 0, sizeof(sigact_table)); + + first_free = &sigqueue_table[0]; + for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) + sigqueue_table[i].next = &sigqueue_table[i + 1]; + sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; +} + +/* signal queue handling */ + +static inline struct sigqueue *alloc_sigqueue(void) +{ + struct sigqueue *q = first_free; + if (!q) + return NULL; + first_free = q->next; + return q; +} + +static inline void free_sigqueue(struct sigqueue *q) +{ + q->next = first_free; + first_free = q; +} + +/* abort execution with signal */ +void __attribute((noreturn)) force_sig(int sig) +{ + int host_sig; + host_sig = target_to_host_signal(sig); + fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", + sig, strsignal(host_sig)); + _exit(-host_sig); +} + +/* queue a signal so that it will be send to the virtual CPU as soon + as possible */ +int queue_signal(int sig, target_siginfo_t *info) +{ + struct emulated_sigaction *k; + struct sigqueue *q, **pq; + target_ulong handler; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "queue_signal: sig=%d\n", + sig); +#endif + k = &sigact_table[sig - 1]; + handler = (target_ulong)k->sa.sa_handler; + if (handler == SIG_DFL) { + /* default handler : ignore some signal. The other are fatal */ + if (sig != SIGCHLD && + sig != SIGURG && + sig != SIGWINCH) { + force_sig(sig); + } else { + return 0; /* indicate ignored */ + } + } else if (handler == host_to_target_signal(SIG_IGN)) { + /* ignore signal */ + return 0; + } else if (handler == host_to_target_signal(SIG_ERR)) { + force_sig(sig); + } else { + pq = &k->first; + if (!k->pending) { + /* first signal */ + q = &k->info; + } else { + q = alloc_sigqueue(); + if (!q) + return -EAGAIN; + while (*pq != NULL) + pq = &(*pq)->next; + } + *pq = q; + q->info = *info; + q->next = NULL; + k->pending = 1; + /* signal that a new signal is pending */ + signal_pending = 1; + return 1; /* indicates that the signal was queued */ + } +} + +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc) +{ + int sig; + target_siginfo_t tinfo; + + /* the CPU emulator uses some host signals to detect exceptions, + we we forward to it some signals */ + if (host_signum == SIGSEGV || host_signum == SIGBUS +#if defined(TARGET_I386) && defined(USE_CODE_COPY) + || host_signum == SIGFPE +#endif + ) { + if (cpu_signal_handler(host_signum, (void*)info, puc)) + return; + } + + /* get target signal number */ + sig = host_to_target_signal(host_signum); + if (sig < 1 || sig > NSIG) + return; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "qemu: got signal %d\n", sig); +#endif + if (queue_signal(sig, &tinfo) == 1) { + /* interrupt the virtual CPU as soon as possible */ + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); + } +} + +int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss) +{ + /* XXX: test errors */ + if(oss) + { + oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp); + oss->ss_size = tswap32(target_sigaltstack_used.ss_size); + oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags); + } + if(ss) + { + target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp); + target_sigaltstack_used.ss_size = tswap32(ss->ss_size); + target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags); + } + return 0; +} + +int do_sigaction(int sig, const struct sigaction *act, + struct sigaction *oact) +{ + struct emulated_sigaction *k; + struct sigaction act1; + int host_sig; + + if (sig < 1 || sig > NSIG) + return -EINVAL; + + k = &sigact_table[sig - 1]; +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n", + sig, (int)act, (int)oact); +#endif + if (oact) { +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n", + sig, (int)act, (int)oact); +#endif + + oact->sa_handler = tswapl(k->sa.sa_handler); + oact->sa_flags = tswapl(k->sa.sa_flags); + oact->sa_mask = tswapl(k->sa.sa_mask); + } + if (act) { +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n", + act->sa_handler, act->sa_flags, act->sa_mask); +#endif + + k->sa.sa_handler = tswapl(act->sa_handler); + k->sa.sa_flags = tswapl(act->sa_flags); + k->sa.sa_mask = tswapl(act->sa_mask); + /* we update the host signal state */ + host_sig = target_to_host_signal(sig); + if (host_sig != SIGSEGV && host_sig != SIGBUS) { +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction handler going to call sigaction\n", + act->sa_handler, act->sa_flags, act->sa_mask); +#endif + + sigfillset(&act1.sa_mask); + act1.sa_flags = SA_SIGINFO; + if (k->sa.sa_flags & SA_RESTART) + act1.sa_flags |= SA_RESTART; + /* NOTE: it is important to update the host kernel signal + ignore state to avoid getting unexpected interrupted + syscalls */ + if (k->sa.sa_handler == SIG_IGN) { + act1.sa_sigaction = (void *)SIG_IGN; + } else if (k->sa.sa_handler == SIG_DFL) { + act1.sa_sigaction = (void *)SIG_DFL; + } else { + act1.sa_sigaction = host_signal_handler; + } + sigaction(host_sig, &act1, NULL); + } + } + return 0; +} + + +#ifdef TARGET_I386 + +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) +{ + /* XXX Fix that */ + if(target_sigaltstack_used.ss_flags & SA_DISABLE) + { + int esp; + /* Default to using normal stack */ + esp = env->regs[R_ESP]; + + return (void *)((esp - frame_size) & -8ul); + } + else + { + return target_sigaltstack_used.ss_sp; + } +} + +static void setup_frame(int sig, struct emulated_sigaction *ka, + void *set, CPUState *env) +{ + void *frame; + int i, err = 0; + + fprintf(stderr, "setup_frame %d\n", sig); + frame = get_sigframe(ka, env, sizeof(*frame)); + + /* Set up registers for signal handler */ + env->regs[R_ESP] = (unsigned long) frame; + env->eip = (unsigned long) ka->sa.sa_handler; + + env->eflags &= ~TF_MASK; + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV /* , current */); +} + +long do_sigreturn(CPUState *env, int num) +{ + int i = 0; + struct target_sigcontext *scp = get_int_arg(&i, env); + /* XXX Get current signal number */ + /* XXX Adjust accordin to sc_onstack, sc_mask */ + if(tswapl(scp->sc_onstack) & 0x1) + target_sigaltstack_used.ss_flags |= ~SA_DISABLE; + else + target_sigaltstack_used.ss_flags &= SA_DISABLE; + int set = tswapl(scp->sc_eax); + sigprocmask(SIG_SETMASK, &set, NULL); + + fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx)); + fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi)); + fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip)); + + env->regs[R_EAX] = tswapl(scp->sc_eax); + env->regs[R_EBX] = tswapl(scp->sc_ebx); + env->regs[R_ECX] = tswapl(scp->sc_ecx); + env->regs[R_EDX] = tswapl(scp->sc_edx); + env->regs[R_EDI] = tswapl(scp->sc_edi); + env->regs[R_ESI] = tswapl(scp->sc_esi); + env->regs[R_EBP] = tswapl(scp->sc_ebp); + env->regs[R_ESP] = tswapl(scp->sc_esp); + env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss); + env->eflags = tswapl(scp->sc_eflags); + env->eip = tswapl(scp->sc_eip); + env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs); + env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds); + env->segs[R_ES].selector = (void*)tswapl(scp->sc_es); + env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs); + env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs); + + /* Again, because our caller's caller will reset EAX */ + return env->regs[R_EAX]; +} + +#else + +static void setup_frame(int sig, struct emulated_sigaction *ka, + void *set, CPUState *env) +{ + fprintf(stderr, "setup_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env, int num) +{ + int i = 0; + struct target_sigcontext *scp = get_int_arg(&i, env); + fprintf(stderr, "do_sigreturn: not implemented\n"); + return -ENOSYS; +} + +#endif + +void process_pending_signals(void *cpu_env) +{ + struct emulated_sigaction *k; + struct sigqueue *q; + target_ulong handler; + int sig; + + if (!signal_pending) + return; + + k = sigact_table; + + for(sig = 1; sig <= NSIG; sig++) { + if (k->pending) + goto handle_signal; + k++; + } + + /* if no signal is pending, just return */ + signal_pending = 0; + return; +handle_signal: + #ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: process signal %d\n", sig); + #endif + /* dequeue signal */ + q = k->first; + k->first = q->next; + if (!k->first) + k->pending = 0; + + sig = gdb_handlesig (cpu_env, sig); + if (!sig) { + fprintf (stderr, "Lost signal\n"); + abort(); + } + + handler = k->sa.sa_handler; + if (handler == SIG_DFL) { + /* default handler : ignore some signal. The other are fatal */ + if (sig != SIGCHLD && + sig != SIGURG && + sig != SIGWINCH) { + force_sig(sig); + } + } else if (handler == SIG_IGN) { + /* ignore sig */ + } else if (handler == SIG_ERR) { + force_sig(sig); + } else { + + setup_frame(sig, k, 0, cpu_env); + if (k->sa.sa_flags & SA_RESETHAND) + k->sa.sa_handler = SIG_DFL; + } + if (q != &k->info) + free_sigqueue(q); +} + + diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c new file mode 100644 index 000000000..50725e633 --- /dev/null +++ b/darwin-user/syscall.c @@ -0,0 +1,1315 @@ +/* + * Darwin syscalls + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2006 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 +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "qemu.h" + +//#define DEBUG_SYSCALL + +#ifdef DEBUG_SYSCALL +# define DEBUG_FORCE_ENABLE_LOCAL() int __DEBUG_qemu_user_force_enable = 1 +# define DEBUG_BEGIN_ENABLE __DEBUG_qemu_user_force_enable = 1; +# define DEBUG_END_ENABLE __DEBUG_qemu_user_force_enable = 0; + +# define DEBUG_DISABLE_ALL() static int __DEBUG_qemu_user_force_enable = 0 +# define DEBUG_ENABLE_ALL() static int __DEBUG_qemu_user_force_enable = 1 + DEBUG_ENABLE_ALL(); + +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); \ + if(__DEBUG_qemu_user_force_enable) fprintf(stderr, __VA_ARGS__); \ + } while(0) +#else +# define DEBUG_FORCE_ENABLE_LOCAL() +# define DEBUG_BEGIN_ENABLE +# define DEBUG_END_ENABLE + +# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0) +#endif + +enum { + bswap_out = 0, + bswap_in = 1 +}; + +extern const char *interp_prefix; + +static inline long get_errno(long ret) +{ + if (ret == -1) + return -errno; + else + return ret; +} + +static inline int is_error(long ret) +{ + return (unsigned long)ret >= (unsigned long)(-4096); +} + +/* ------------------------------------------------------------ + Mach syscall handling +*/ + +void static inline print_description_msg_header(mach_msg_header_t *hdr) +{ + char *name = NULL; + int i; + struct { int number; char *name; } msg_name[] = + { + /* see http://fxr.watson.org/fxr/source/compat/mach/mach_namemap.c?v=NETBSD */ + { 200, "host_info" }, + { 202, "host_page_size" }, + { 206, "host_get_clock_service" }, + { 206, "host_get_clock_service" }, + { 206, "host_get_clock_service" }, + { 306, "host_get_clock_service" }, + { 3204, "mach_port_allocate" }, + { 3206, "mach_port_deallocate" }, + { 3404, "mach_ports_lookup" }, + { 3409, "mach_task_get_special_port" }, + { 3414, "mach_task_get_exception_ports" }, + { 3418, "mach_semaphore_create" }, + { 3504, "mach_semaphore_create" }, + { 3509, "mach_semaphore_create" }, + { 3518, "semaphore_create" }, + { 3616, "thread_policy" }, + { 3801, "vm_allocate" }, + { 3802, "vm_deallocate" }, + { 3802, "vm_deallocate" }, + { 3803, "vm_protect" }, + { 3812, "vm_map" }, + { 4241776, "lu_message_send_id" }, /* lookupd */ + { 4241876, "lu_message_reply_id" }, /* lookupd */ + }; + + for(i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) { + if(msg_name[i].number == hdr->msgh_id) + { + name = msg_name[i].name; + break; + } + } + if(!name) + DPRINTF("unknown mach msg %d 0x%x\n", hdr->msgh_id, hdr->msgh_id); + else + DPRINTF("%s\n", name); +#if 0 + DPRINTF("Bits: %8x\n", hdr->msgh_bits); + DPRINTF("Size: %8x\n", hdr->msgh_size); + DPRINTF("Rmte: %8x\n", hdr->msgh_remote_port); + DPRINTF("Locl: %8x\n", hdr->msgh_local_port); + DPRINTF("Rsrv: %8x\n", hdr->msgh_reserved); + + DPRINTF("Id : %8x\n", hdr->msgh_id); + + NDR_record_t *ndr = (NDR_record_t *)(hdr + 1); + DPRINTF("hdr = %p, sizeof(hdr) = %x, NDR = %p\n", hdr, (unsigned int)sizeof(mach_msg_header_t), ndr); + DPRINTF("%d %d %d %d %d %d %d %d\n", + ndr->mig_vers, ndr->if_vers, ndr->reserved1, ndr->mig_encoding, + ndr->int_rep, ndr->char_rep, ndr->float_rep, ndr->reserved2); +#endif +} + +static inline void print_mach_msg_return(mach_msg_return_t ret) +{ + int i, found = 0; +#define MACH_MSG_RET(msg) { msg, #msg } + struct { int code; char *name; } msg_name[] = + { + /* ref: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/osfmk/man/mach_msg.html */ + /* send message */ + MACH_MSG_RET(MACH_SEND_MSG_TOO_SMALL), + MACH_MSG_RET(MACH_SEND_NO_BUFFER), + MACH_MSG_RET(MACH_SEND_INVALID_DATA), + MACH_MSG_RET(MACH_SEND_INVALID_HEADER), + MACH_MSG_RET(MACH_SEND_INVALID_DEST), + MACH_MSG_RET(MACH_SEND_INVALID_NOTIFY), + MACH_MSG_RET(MACH_SEND_INVALID_REPLY), + MACH_MSG_RET(MACH_SEND_INVALID_TRAILER), + MACH_MSG_RET(MACH_SEND_INVALID_MEMORY), + MACH_MSG_RET(MACH_SEND_INVALID_RIGHT), + MACH_MSG_RET(MACH_SEND_INVALID_TYPE), + MACH_MSG_RET(MACH_SEND_INTERRUPTED), + MACH_MSG_RET(MACH_SEND_TIMED_OUT), + + MACH_MSG_RET(MACH_RCV_BODY_ERROR), + MACH_MSG_RET(MACH_RCV_HEADER_ERROR), + + MACH_MSG_RET(MACH_RCV_IN_SET), + MACH_MSG_RET(MACH_RCV_INTERRUPTED), + + MACH_MSG_RET(MACH_RCV_INVALID_DATA), + MACH_MSG_RET(MACH_RCV_INVALID_NAME), + MACH_MSG_RET(MACH_RCV_INVALID_NOTIFY), + MACH_MSG_RET(MACH_RCV_INVALID_TRAILER), + MACH_MSG_RET(MACH_RCV_INVALID_TYPE), + + MACH_MSG_RET(MACH_RCV_PORT_CHANGED), + MACH_MSG_RET(MACH_RCV_PORT_DIED), + + MACH_MSG_RET(MACH_RCV_SCATTER_SMALL), + MACH_MSG_RET(MACH_RCV_TIMED_OUT), + MACH_MSG_RET(MACH_RCV_TOO_LARGE) + }; +#undef MACH_MSG_RET + + if( ret == MACH_MSG_SUCCESS) + DPRINTF("MACH_MSG_SUCCESS\n"); + else + { + for( i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) { + if(msg_name[0].code & ret) { + DPRINTF("%s ", msg_name[0].name); + found = 1; + } + } + if(!found) + qerror("unknow mach message ret code %d\n", ret); + else + DPRINTF("\n"); + } +} + +static inline void swap_mach_msg_header(mach_msg_header_t *hdr) +{ + hdr->msgh_bits = tswap32(hdr->msgh_bits); + hdr->msgh_size = tswap32(hdr->msgh_size); + hdr->msgh_remote_port = tswap32(hdr->msgh_remote_port); + hdr->msgh_local_port = tswap32(hdr->msgh_local_port); + hdr->msgh_reserved = tswap32(hdr->msgh_reserved); + hdr->msgh_id = tswap32(hdr->msgh_id); +} + +struct complex_msg { + mach_msg_header_t hdr; + mach_msg_body_t body; +}; + +static inline void * swap_mach_msg_body(struct complex_msg *complex_msg, int bswap) +{ + mach_msg_port_descriptor_t *descr = (mach_msg_port_descriptor_t *)(complex_msg+1); + int i,j; + void *additional_data; + + if(bswap == bswap_in) + tswap32s(&complex_msg->body.msgh_descriptor_count); + + DPRINTF("body.msgh_descriptor_count %d\n", complex_msg->body.msgh_descriptor_count); + + for(i = 0; i < complex_msg->body.msgh_descriptor_count; i++) { + switch(descr->type) + { + case MACH_MSG_PORT_DESCRIPTOR: + tswap32s(&descr->name); + descr++; + break; + case MACH_MSG_OOL_DESCRIPTOR: + { + mach_msg_ool_descriptor_t *ool = (void *)descr; + tswap32s((uint32_t *)&ool->address); + tswap32s(&ool->size); + + descr = (mach_msg_port_descriptor_t *)(ool+1); + break; + } + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + { + mach_msg_ool_ports_descriptor_t *ool_ports = (void *)descr; + mach_port_name_t * port_names; + + if(bswap == bswap_in) + { + tswap32s((uint32_t *)&ool_ports->address); + tswap32s(&ool_ports->count); + } + + port_names = ool_ports->address; + + for(j = 0; j < ool_ports->count; j++) + tswap32s(&port_names[j]); + + if(bswap == bswap_out) + { + tswap32s((uint32_t *)&ool_ports->address); + tswap32s(&ool_ports->count); + } + + descr = (mach_msg_port_descriptor_t *)(ool_ports+1); + break; + } + default: qerror("unknow mach msg descriptor type %x\n", descr->type); + } + } + if(bswap == bswap_out) + tswap32s(&complex_msg->body.msgh_descriptor_count); + additional_data = descr; + return additional_data; +} + +static inline uint32_t target_mach_msg_trap( + mach_msg_header_t *hdr, uint32_t options, uint32_t send_size, + uint32_t rcv_size, uint32_t rcv_name, uint32_t time_out, uint32_t notify ) +{ + extern int mach_msg_trap(mach_msg_header_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + mach_msg_audit_trailer_t *trailer; + mach_msg_id_t msg_id; + uint32_t ret = 0; + char *additional_data; + int i; + + swap_mach_msg_header(hdr); + + print_description_msg_header(hdr); + + msg_id = hdr->msgh_id; + + if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) + additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_in); + else + additional_data = (void*)(hdr+1); + + ret = mach_msg_trap(hdr, options, send_size, rcv_size, rcv_name, time_out, notify); + + print_mach_msg_return(ret); + + if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) + additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_out); + else + additional_data = (void*)(hdr+1); + + if( (options & MACH_RCV_MSG) && (REQUESTED_TRAILER_SIZE(options) > 0) ) + { + /* XXX: the kernel always return the full trailer with MACH_SEND_MSG, so we should + probably always bswap it */ + /* warning: according to Mac OS X Internals (the book) msg_size might be expressed in + natural_t units but according to xnu/osfmk/mach/message.h: "The size of + the message must be specified in bytes" */ + trailer = (mach_msg_audit_trailer_t *)((uint8_t *)hdr + hdr->msgh_size); + /* XXX: Should probably do that based on the option asked by the sender, but dealing + with kernel answer seems more sound */ + switch(trailer->msgh_trailer_size) + { + case sizeof(mach_msg_audit_trailer_t): + for(i = 0; i < 8; i++) + tswap32s(&trailer->msgh_audit.val[i]); + /* Fall in mach_msg_security_trailer_t case */ + case sizeof(mach_msg_security_trailer_t): + tswap32s(&trailer->msgh_sender.val[0]); + tswap32s(&trailer->msgh_sender.val[1]); + /* Fall in mach_msg_seqno_trailer_t case */ + case sizeof(mach_msg_seqno_trailer_t): + tswap32s(&trailer->msgh_seqno); + /* Fall in mach_msg_trailer_t case */ + case sizeof(mach_msg_trailer_t): + tswap32s(&trailer->msgh_trailer_type); + tswap32s(&trailer->msgh_trailer_size); + break; + case 0: + /* Safer not to byteswap, but probably wrong */ + break; + default: + qerror("unknow trailer type given its size %d\n", trailer->msgh_trailer_size); + break; + } + } + + /* Special message handling */ + switch (msg_id) { + case 200: /* host_info */ + { + mig_reply_error_t *err = (mig_reply_error_t *)hdr; + struct { + uint32_t unknow1; + uint32_t maxcpu; + uint32_t numcpu; + uint32_t memsize; + uint32_t cpu_type; + uint32_t cpu_subtype; + } *data = (void *)(err+1); + + DPRINTF("maxcpu = 0x%x\n", data->maxcpu); + DPRINTF("numcpu = 0x%x\n", data->maxcpu); + DPRINTF("memsize = 0x%x\n", data->memsize); + +#if defined(TARGET_I386) + data->cpu_type = CPU_TYPE_I386; + DPRINTF("cpu_type changed to 0x%x(i386)\n", data->cpu_type); +#elif defined(TARGET_PPC) + data->cpu_type = CPU_TYPE_POWERPC; + DPRINTF("cpu_type changed to 0x%x(ppc)\n", data->cpu_type); +#else +# error target not supported +#endif + +#if defined(TARGET_I386) + data->cpu_subtype = CPU_SUBTYPE_PENT; + DPRINTF("cpu_subtype changed to 0x%x(i386_pent)\n", data->cpu_subtype); +#elif defined(TARGET_PPC) + data->cpu_subtype = CPU_SUBTYPE_POWERPC_750; + DPRINTF("cpu_subtype changed to 0x%x(ppc_all)\n", data->cpu_subtype); +#else +# error target not supported +#endif + break; + } + case 202: /* host_page_size */ + { + mig_reply_error_t *err = (mig_reply_error_t *)hdr; + uint32_t *pagesize = (uint32_t *)(err+1); + + DPRINTF("pagesize = %d\n", *pagesize); + break; + } + default: break; + } + + swap_mach_msg_header(hdr); + + return ret; +} + +long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, + uint32_t arg8) +{ + extern uint32_t mach_reply_port(); + + long ret = 0; + + arg1 = tswap32(arg1); + arg2 = tswap32(arg2); + arg3 = tswap32(arg3); + arg4 = tswap32(arg4); + arg5 = tswap32(arg5); + arg6 = tswap32(arg6); + arg7 = tswap32(arg7); + arg8 = tswap32(arg8); + + DPRINTF("mach syscall %d : " , num); + + switch(num) { + /* see xnu/osfmk/mach/syscall_sw.h */ + case -26: + DPRINTF("mach_reply_port()\n"); + ret = mach_reply_port(); + break; + case -27: + DPRINTF("mach_thread_self()\n"); + ret = mach_thread_self(); + break; + case -28: + DPRINTF("mach_task_self()\n"); + ret = mach_task_self(); + break; + case -29: + DPRINTF("mach_host_self()\n"); + ret = mach_host_self(); + break; + case -31: + DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", + arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + break; + case -36: + DPRINTF("semaphore_wait_trap(0x%x)\n", arg1); + extern int semaphore_wait_trap(int); // XXX: is there any header for that? + ret = semaphore_wait_trap(arg1); + break; + case -43: + DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", + arg1, arg2, arg3, arg4, arg5); + ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5); + tswap32s((uint32_t*)arg3); + break; + case -89: + DPRINTF("mach_timebase_info(0x%x)\n", arg1); + struct mach_timebase_info info; + ret = mach_timebase_info(&info); + if(!is_error(ret)) + { + struct mach_timebase_info *outInfo = (void*)arg1; + outInfo->numer = tswap32(info.numer); + outInfo->denom = tswap32(info.denom); + } + break; + case -90: + DPRINTF("mach_wait_until()\n"); + extern int mach_wait_until(uint64_t); // XXX: is there any header for that? + ret = mach_wait_until(((uint64_t)arg2<<32) | (uint64_t)arg1); + break; + case -91: + DPRINTF("mk_timer_create()\n"); + extern int mk_timer_create(); // XXX: is there any header for that? + ret = mk_timer_create(); + break; + case -92: + DPRINTF("mk_timer_destroy()\n"); + extern int mk_timer_destroy(int); // XXX: is there any header for that? + ret = mk_timer_destroy(arg1); + break; + case -93: + DPRINTF("mk_timer_create()\n"); + extern int mk_timer_arm(int, uint64_t); // XXX: is there any header for that? + ret = mk_timer_arm(arg1, ((uint64_t)arg3<<32) | (uint64_t)arg2); + break; + case -94: + DPRINTF("mk_timer_cancel()\n"); + extern int mk_timer_cancel(int, uint64_t *); // XXX: is there any header for that? + ret = mk_timer_cancel(arg1, (uint64_t *)arg2); + if((!is_error(ret)) && arg2) + tswap64s((uint64_t *)arg2); + break; + default: + gemu_log("qemu: Unsupported mach syscall: %d(0x%x)\n", num, num); + gdb_handlesig (cpu_env, SIGTRAP); + exit(0); + break; + } + return ret; +} + +/* ------------------------------------------------------------ + thread type syscall handling +*/ +long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, + uint32_t arg8) +{ + extern uint32_t cthread_set_self(uint32_t); + extern uint32_t processor_facilities_used(); + long ret = 0; + + arg1 = tswap32(arg1); + arg2 = tswap32(arg2); + arg3 = tswap32(arg3); + arg4 = tswap32(arg4); + arg5 = tswap32(arg5); + arg6 = tswap32(arg6); + arg7 = tswap32(arg7); + arg8 = tswap32(arg8); + + DPRINTF("thread syscall %d : " , num); + + switch(num) { +#ifdef TARGET_I386 + case 0x3: +#endif + case 0x7FF1: /* cthread_set_self */ + DPRINTF("cthread_set_self(0x%x)\n", (unsigned int)arg1); + ret = cthread_set_self(arg1); +#ifdef TARGET_I386 + /* we need to update the LDT with the address of the thread */ + write_dt((void *)(((CPUX86State *) cpu_env)->ldt.base + (4 * sizeof(uint64_t))), arg1, 1, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + /* New i386 convention, %gs should be set to our this LDT entry */ + cpu_x86_load_seg(cpu_env, R_GS, 0x27); + /* Old i386 convention, the kernel returns the selector for the cthread (pre-10.4.8?)*/ + ret = 0x27; +#endif + break; + case 0x7FF2: /* Called the super-fast pthread_self handler by the apple guys */ + DPRINTF("pthread_self()\n"); + ret = (uint32_t)pthread_self(); + break; + case 0x7FF3: + DPRINTF("processor_facilities_used()\n"); +#ifdef __i386__ + qerror("processor_facilities_used: not implemented!\n"); +#else + ret = (uint32_t)processor_facilities_used(); +#endif + break; + default: + gemu_log("qemu: Unsupported thread syscall: %d(0x%x)\n", num, num); + gdb_handlesig (cpu_env, SIGTRAP); + exit(0); + break; + } + return ret; +} + +/* ------------------------------------------------------------ + ioctl handling +*/ +static inline void byteswap_termios(struct termios *t) +{ + tswap32s((uint32_t*)&t->c_iflag); + tswap32s((uint32_t*)&t->c_oflag); + tswap32s((uint32_t*)&t->c_cflag); + tswap32s((uint32_t*)&t->c_lflag); + /* 20 (char) bytes then */ + tswap32s((uint32_t*)&t->c_ispeed); + tswap32s((uint32_t*)&t->c_ospeed); +} + +static inline void byteswap_winsize(struct winsize *w) +{ + tswap16s(&w->ws_row); + tswap16s(&w->ws_col); + tswap16s(&w->ws_xpixel); + tswap16s(&w->ws_ypixel); +} + +#define STRUCT(name, list...) STRUCT_ ## name, +#define STRUCT_SPECIAL(name) STRUCT_ ## name, +enum { +#include "ioctls_types.h" +}; +#undef STRUCT +#undef STRUCT_SPECIAL + +#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL }; +#define STRUCT_SPECIAL(name) +#include "ioctls_types.h" +#undef STRUCT +#undef STRUCT_SPECIAL + +typedef struct IOCTLEntry { + unsigned int target_cmd; + unsigned int host_cmd; + const char *name; + int access; + const argtype arg_type[5]; +} IOCTLEntry; + +#define IOC_R 0x0001 +#define IOC_W 0x0002 +#define IOC_RW (IOC_R | IOC_W) + +#define MAX_STRUCT_SIZE 4096 + +IOCTLEntry ioctl_entries[] = { +#define IOCTL(cmd, access, types...) \ + { cmd, cmd, #cmd, access, { types } }, +#include "ioctls.h" + { 0, 0, }, +}; + +/* ??? Implement proper locking for ioctls. */ +static long do_ioctl(long fd, long cmd, long arg) +{ + const IOCTLEntry *ie; + const argtype *arg_type; + int ret; + uint8_t buf_temp[MAX_STRUCT_SIZE]; + int target_size; + void *argptr; + + ie = ioctl_entries; + for(;;) { + if (ie->target_cmd == 0) { + gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd); + return -ENOSYS; + } + if (ie->target_cmd == cmd) + break; + ie++; + } + arg_type = ie->arg_type; +#if defined(DEBUG) + gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); +#endif + switch(arg_type[0]) { + case TYPE_NULL: + /* no argument */ + ret = get_errno(ioctl(fd, ie->host_cmd)); + break; + case TYPE_PTRVOID: + case TYPE_INT: + /* int argment */ + ret = get_errno(ioctl(fd, ie->host_cmd, arg)); + break; + case TYPE_PTR: + arg_type++; + target_size = thunk_type_size(arg_type, 0); + switch(ie->access) { + case IOC_R: + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + argptr = lock_user(arg, target_size, 0); + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); + } + break; + case IOC_W: + argptr = lock_user(arg, target_size, 1); + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + break; + default: + case IOC_RW: + argptr = lock_user(arg, target_size, 1); + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + argptr = lock_user(arg, target_size, 0); + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); + } + break; + } + break; + default: + gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]); + ret = -ENOSYS; + break; + } + return ret; +} + +/* ------------------------------------------------------------ + Unix syscall handling +*/ + +static inline void byteswap_attrlist(struct attrlist *a) +{ + tswap16s(&a->bitmapcount); + tswap16s(&a->reserved); + tswap32s(&a->commonattr); + tswap32s(&a->volattr); + tswap32s(&a->dirattr); + tswap32s(&a->fileattr); + tswap32s(&a->forkattr); +} + +struct attrbuf_header { + unsigned long length; +}; + +static inline void byteswap_attrbuf(struct attrbuf_header *attrbuf, struct attrlist *attrlist) +{ + DPRINTF("attrBuf.lenght %lx\n", attrbuf->length); +} + +static inline void byteswap_statfs(struct statfs *s) +{ + tswap16s((uint16_t*)&s->f_otype); + tswap16s((uint16_t*)&s->f_oflags); + tswap32s((uint32_t*)&s->f_bsize); + tswap32s((uint32_t*)&s->f_iosize); + tswap32s((uint32_t*)&s->f_blocks); + tswap32s((uint32_t*)&s->f_bfree); + tswap32s((uint32_t*)&s->f_bavail); + tswap32s((uint32_t*)&s->f_files); + tswap32s((uint32_t*)&s->f_ffree); + tswap32s((uint32_t*)&s->f_fsid.val[0]); + tswap32s((uint32_t*)&s->f_fsid.val[1]); + tswap16s((uint16_t*)&s->f_reserved1); + tswap16s((uint16_t*)&s->f_type); + tswap32s((uint32_t*)&s->f_flags); +} + +static inline void byteswap_stat(struct stat *s) +{ + tswap32s((uint32_t*)&s->st_dev); + tswap32s(&s->st_ino); + tswap16s(&s->st_mode); + tswap16s(&s->st_nlink); + tswap32s(&s->st_uid); + tswap32s(&s->st_gid); + tswap32s((uint32_t*)&s->st_rdev); + tswap32s((uint32_t*)&s->st_atimespec.tv_sec); + tswap32s((uint32_t*)&s->st_atimespec.tv_nsec); + tswap32s((uint32_t*)&s->st_mtimespec.tv_sec); + tswap32s((uint32_t*)&s->st_mtimespec.tv_nsec); + tswap32s((uint32_t*)&s->st_ctimespec.tv_sec); + tswap32s((uint32_t*)&s->st_ctimespec.tv_nsec); + tswap64s((uint64_t*)&s->st_size); + tswap64s((uint64_t*)&s->st_blocks); + tswap32s((uint32_t*)&s->st_blksize); + tswap32s(&s->st_flags); + tswap32s(&s->st_gen); +} + +static inline void byteswap_dirents(struct dirent *d, int bytes) +{ + char *b; + for( b = (char*)d; (int)b < (int)d+bytes; ) + { + unsigned short s = ((struct dirent *)b)->d_reclen; + tswap32s(&((struct dirent *)b)->d_ino); + tswap16s(&((struct dirent *)b)->d_reclen); + if(s<=0) + break; + b += s; + } +} + +static inline void byteswap_iovec(struct iovec *v, int n) +{ + int i; + for(i = 0; i < n; i++) + { + tswap32s((uint32_t*)&v[i].iov_base); + tswap32s((uint32_t*)&v[i].iov_len); + } +} + +static inline void byteswap_timeval(struct timeval *t) +{ + tswap32s((uint32_t*)&t->tv_sec); + tswap32s((uint32_t*)&t->tv_usec); +} + +long do_unix_syscall_indirect(void *cpu_env, int num); +long do_sync(); +long do_exit(uint32_t arg1); +long do_getlogin(char *out, uint32_t size); +long do_open(char * arg1, uint32_t arg2, uint32_t arg3); +long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3); +long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3); +long do_execve(char* arg1, char ** arg2, char ** arg3); +long do_getgroups(uint32_t arg1, gid_t * arg2); +long do_gettimeofday(struct timeval * arg1, void * arg2); +long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3); +long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3); +long do_utimes(char * arg1, struct timeval * arg2); +long do_futimes(uint32_t arg1, struct timeval * arg2); +long do_statfs(char * arg1, struct statfs * arg2); +long do_fstatfs(uint32_t arg1, struct statfs * arg2); +long do_stat(char * arg1, struct stat * arg2); +long do_fstat(uint32_t arg1, struct stat * arg2); +long do_lstat(char * arg1, struct stat * arg2); +long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4); +long do_lseek(void *cpu_env, int num); +long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6); +long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5); +long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8); + +long no_syscall(void *cpu_env, int num); + +long do_pread(uint32_t arg1, void * arg2, size_t arg3, off_t arg4) +{ + //DPRINTF("0x%x, 0x%x, 0x%x, 0x%llx\n", arg1, arg2, arg3, arg4); + long ret = (pread(arg1, arg2, arg3, arg4)); + DPRINTF("0x%x\n", *(int*)arg2); + return ret; +} +long unimpl_unix_syscall(void *cpu_env, int num); + +typedef long (*syscall_function_t)(void *cpu_env, int num); + + +/* define a table that will handle the syscall number->function association */ +#define VOID void +#define INT (uint32_t)get_int_arg(&i, cpu_env) +#define INT64 (uint64_t)get_int64_arg(&i, cpu_env) +#define UINT (unsigned int)INT +#define PTR (void*)INT + +#define SIZE INT +#define OFFSET INT64 + +#define WRAPPER_CALL_DIRECT_0(function, args) long __qemu_##function(void *cpu_env) { return (long)function(); } +#define WRAPPER_CALL_DIRECT_1(function, _arg1) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; return (long)function(arg1); } +#define WRAPPER_CALL_DIRECT_2(function, _arg1, _arg2) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; return (long)function(arg1, arg2); } +#define WRAPPER_CALL_DIRECT_3(function, _arg1, _arg2, _arg3) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; return (long)function(arg1, arg2, arg3); } +#define WRAPPER_CALL_DIRECT_4(function, _arg1, _arg2, _arg3, _arg4) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; return (long)function(arg1, arg2, arg3, arg4); } +#define WRAPPER_CALL_DIRECT_5(function, _arg1, _arg2, _arg3, _arg4, _arg5) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; return (long)function(arg1, arg2, arg3, arg4, arg5); } +#define WRAPPER_CALL_DIRECT_6(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6); } +#define WRAPPER_CALL_DIRECT_7(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } +#define WRAPPER_CALL_DIRECT_8(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; typeof(_arg8) arg8 = _arg8; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } +#define WRAPPER_CALL_DIRECT(function, nargs, args...) WRAPPER_CALL_DIRECT_##nargs(function, args) +#define WRAPPER_CALL_NOERRNO(function, nargs, args...) WRAPPER_CALL_DIRECT(function, nargs, args) +#define WRAPPER_CALL_INDIRECT(function, nargs, args...) +#define ENTRY(name, number, function, nargs, call_type, args...) WRAPPER_##call_type(function, nargs, args) + +#include "syscalls.h" + +#undef ENTRY +#undef WRAPPER_CALL_DIRECT +#undef WRAPPER_CALL_NOERRNO +#undef WRAPPER_CALL_INDIRECT +#undef OFFSET +#undef SIZE +#undef INT +#undef PTR +#undef INT64 + +#define _ENTRY(name, number, function, nargs, call_type) [number] = {\ + name, \ + number, \ + (syscall_function_t)function, \ + nargs, \ + call_type \ + }, + +#define ENTRY_CALL_DIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, __qemu_##function, nargs, call_type) +#define ENTRY_CALL_NOERRNO(name, number, function, nargs, call_type) ENTRY_CALL_DIRECT(name, number, function, nargs, call_type) +#define ENTRY_CALL_INDIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, function, nargs, call_type) +#define ENTRY(name, number, function, nargs, call_type, args...) ENTRY_##call_type(name, number, function, nargs, call_type) + +#define CALL_DIRECT 1 +#define CALL_INDIRECT 2 +#define CALL_NOERRNO (CALL_DIRECT | 4 /* = 5 */) + +struct unix_syscall { + char * name; + int number; + syscall_function_t function; + int nargs; + int call_type; +} unix_syscall_table[SYS_MAXSYSCALL] = { +#include "syscalls.h" +}; + +#undef ENTRY +#undef _ENTRY +#undef ENTRY_CALL_DIRECT +#undef ENTRY_CALL_INDIRECT +#undef ENTRY_CALL_NOERRNO + +/* Actual syscalls implementation */ + +long do_unix_syscall_indirect(void *cpu_env, int num) +{ + long ret; + int new_num; + int i = 0; + + new_num = get_int_arg(&i, cpu_env); +#ifdef TARGET_I386 + ((CPUX86State*)cpu_env)->regs[R_ESP] += 4; + /* XXX: not necessary */ + ((CPUX86State*)cpu_env)->regs[R_EAX] = new_num; +#elif TARGET_PPC + { + int i; + uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr; + for(i = 3; i < 11; i++) + *regs[i] = *regs[i+1]; + /* XXX: not necessary */ + *regs[0] = new_num; + } +#endif + ret = do_unix_syscall(cpu_env, new_num); +#ifdef TARGET_I386 + ((CPUX86State*)cpu_env)->regs[R_ESP] -= 4; + /* XXX: not necessary */ + ((CPUX86State*)cpu_env)->regs[R_EAX] = num; +#elif TARGET_PPC + { + int i; + /* XXX: not really needed those regs are volatile accross calls */ + uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr; + for(i = 11; i > 3; i--) + *regs[i] = *regs[i-1]; + regs[3] = new_num; + *regs[0] = num; + } +#endif + return ret; +} + +long do_exit(uint32_t arg1) +{ + exit(arg1); + /* not reached */ + return -1; +} + +long do_sync() +{ + sync(); + return 0; +} + +long do_getlogin(char *out, uint32_t size) +{ + char *login = getlogin(); + if(!login) + return -1; + memcpy(out, login, size); + return 0; +} +long do_open(char * arg1, uint32_t arg2, uint32_t arg3) +{ + /* XXX: don't let the %s stay in there */ + DPRINTF("open(%s, 0x%x, 0x%x)\n", arg1, arg2, arg3); + return get_errno(open(arg1, arg2, arg3)); +} + +long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3) +{ + long ret; + DPRINTF("getfsstat(%p, 0x%x, 0x%x)\n", arg1, arg2, arg3); + ret = get_errno(getfsstat(arg1, arg2, arg3)); + if((!is_error(ret)) && arg1) + byteswap_statfs(arg1); + return ret; +} + +long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3) +{ + long ret; + DPRINTF("sigprocmask(%d, %p, %p)\n", arg1, arg2, arg3); + gemu_log("XXX: sigprocmask not tested (%d, %p, %p)\n", arg1, arg2, arg3); + if(arg2) + tswap32s(arg2); + ret = get_errno(sigprocmask(arg1, (void *)arg2, (void *)arg3)); + if((!is_error(ret)) && arg3) + tswap32s(arg3); + if(arg2) + tswap32s(arg2); + return ret; +} + +long do_execve(char* arg1, char ** arg2, char ** arg3) +{ + long ret; + char **argv = arg2; + char **envp = arg3; + int argc; + int envc; + + /* XXX: don't let the %s stay in here */ + DPRINTF("execve(%s, %p, %p)\n", arg1, arg2, arg3); + + for(argc = 0; argv[argc]; argc++); + for(envc = 0; envp[envc]; envc++); + + argv = (char**)malloc(sizeof(char*)*argc); + envp = (char**)malloc(sizeof(char*)*envc); + + for(; argc >= 0; argc--) + argv[argc] = (char*)tswap32((uint32_t)(arg2)[argc]); + + for(; envc >= 0; envc--) + envp[envc] = (char*)tswap32((uint32_t)(arg3)[envc]); + + ret = get_errno(execve(arg1, argv, envp)); + free(argv); + free(envp); + return ret; +} + +long do_getgroups(uint32_t arg1, gid_t * arg2) +{ + long ret; + int i; + DPRINTF("getgroups(0x%x, %p)\n", arg1, arg2); + ret = get_errno(getgroups(arg1, arg2)); + if(ret > 0) + for(i = 0; i < arg1; i++) + tswap32s(&arg2[i]); + return ret; +} + +long do_gettimeofday(struct timeval * arg1, void * arg2) +{ + long ret; + DPRINTF("gettimeofday(%p, %p)\n", + arg1, arg2); + ret = get_errno(gettimeofday(arg1, arg2)); + if(!is_error(ret)) + { + /* timezone no longer used according to the manpage, so don't bother with it */ + byteswap_timeval(arg1); + } + return ret; +} + +long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3) +{ + long ret; + DPRINTF("readv(0x%x, %p, 0x%x)\n", arg1, arg2, arg3); + if(arg2) + byteswap_iovec(arg2, arg3); + ret = get_errno(readv(arg1, arg2, arg3)); + if((!is_error(ret)) && arg2) + byteswap_iovec(arg2, arg3); + return ret; +} + +long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3) +{ + long ret; + DPRINTF("writev(0x%x, %p, 0x%x)\n", arg1, arg2, arg3); + if(arg2) + byteswap_iovec(arg2, arg3); + ret = get_errno(writev(arg1, arg2, arg3)); + if((!is_error(ret)) && arg2) + byteswap_iovec(arg2, arg3); + return ret; +} + +long do_utimes(char * arg1, struct timeval * arg2) +{ + DPRINTF("utimes(%p, %p)\n", arg1, arg2); + if(arg2) + { + byteswap_timeval(arg2); + byteswap_timeval(arg2+1); + } + return get_errno(utimes(arg1, arg2)); +} + +long do_futimes(uint32_t arg1, struct timeval * arg2) +{ + DPRINTF("futimes(0x%x, %p)\n", arg1, arg2); + if(arg2) + { + byteswap_timeval(arg2); + byteswap_timeval(arg2+1); + } + return get_errno(futimes(arg1, arg2)); +} + +long do_statfs(char * arg1, struct statfs * arg2) +{ + long ret; + DPRINTF("statfs(%p, %p)\n", arg1, arg2); + ret = get_errno(statfs(arg1, arg2)); + if(!is_error(ret)) + byteswap_statfs(arg2); + return ret; +} + +long do_fstatfs(uint32_t arg1, struct statfs* arg2) +{ + long ret; + DPRINTF("fstatfs(0x%x, %p)\n", + arg1, arg2); + ret = get_errno(fstatfs(arg1, arg2)); + if(!is_error(ret)) + byteswap_statfs(arg2); + + return ret; +} + +long do_stat(char * arg1, struct stat * arg2) +{ + long ret; + /* XXX: don't let the %s stay in there */ + DPRINTF("stat(%s, %p)\n", arg1, arg2); + ret = get_errno(stat(arg1, arg2)); + if(!is_error(ret)) + byteswap_stat(arg2); + return ret; +} + +long do_fstat(uint32_t arg1, struct stat * arg2) +{ + long ret; + DPRINTF("fstat(0x%x, %p)\n", arg1, arg2); + ret = get_errno(fstat(arg1, arg2)); + if(!is_error(ret)) + byteswap_stat(arg2); + return ret; +} + +long do_lstat(char * arg1, struct stat * arg2) +{ + long ret; + /* XXX: don't let the %s stay in there */ + DPRINTF("lstat(%s, %p)\n", (const char *)arg1, arg2); + ret = get_errno(lstat(arg1, arg2)); + if(!is_error(ret)) + byteswap_stat(arg2); + return ret; +} + +long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4) +{ + long ret; + DPRINTF("getdirentries(0x%x, %p, 0x%x, %p)\n", arg1, arg2, arg3, arg4); + if(arg4) + tswap32s((uint32_t *)arg4); + ret = get_errno(getdirentries(arg1, arg2, arg3, arg4)); + if(arg4) + tswap32s((uint32_t *)arg4); + if(!is_error(ret)) + byteswap_dirents(arg2, ret); + return ret; +} + +long do_lseek(void *cpu_env, int num) +{ + long ret; + int i = 0; + uint32_t arg1 = get_int_arg(&i, cpu_env); + uint64_t offset = get_int64_arg(&i, cpu_env); + uint32_t arg3 = get_int_arg(&i, cpu_env); + uint64_t r = lseek(arg1, offset, arg3); +#ifdef TARGET_I386 + /* lowest word in eax, highest in edx */ + ret = r & 0xffffffff; /* will be set to eax after do_unix_syscall exit */ + ((CPUX86State *)cpu_env)->regs[R_EDX] = (uint32_t)((r >> 32) & 0xffffffff) ; +#elif defined TARGET_PPC + ret = r & 0xffffffff; /* will be set to r3 after do_unix_syscall exit */ + ((CPUPPCState *)cpu_env)->gpr[4] = (uint32_t)((r >> 32) & 0xffffffff) ; +#else + qerror("64 bit ret value on your arch?"); +#endif + return get_errno(ret); +} + +long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6) +{ + long ret = 0; + int i; + DPRINTF("sysctl(%p, 0x%x, %p, %p, %p, 0x%lx)\n", + arg1, arg2, arg3, arg4, arg5, arg6); + if(arg1) { + i = 0; + do { *((int *) arg1 + i) = tswap32(*((int *) arg1 + i)); } while (++i < arg2); + } + + if(arg4) + *(int *) arg4 = tswap32(*(int *) arg4); + if(arg1) + ret = get_errno(sysctl((void *)arg1, arg2, (void *)arg3, (void *)arg4, (void *)arg5, arg6)); + + if ((ret == 0) && (arg2 == 2) && (*((int *) arg1) == 0) && (*((int *) arg1 + 1) == 3)) { + /* The output here is the new id - we need to swap it so it can be passed + back in (and then unswapped) */ + int count = (*(int *) arg4) / sizeof(int); + i = 0; + do { + *((int *) arg3 + i) = tswap32(*((int *) arg3 + i)); + } while (++i < count); + } + *(int *) arg4 = tswap32(*(int *) arg4); + + return ret; +} + +long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5) +{ + struct attrlist * attrlist = (void *)arg2; + long ret; + +#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) + qerror("SYS_getdirentriesattr unimplemented\n"); +#endif + /* XXX: don't let the %s stay in there */ + DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n", + (char *)arg1, arg2, arg3, arg4, arg5); + + if(arg2) /* XXX: We should handle that in a copy especially + if the structure is not writable */ + byteswap_attrlist(attrlist); + + ret = get_errno(getattrlist((const char* )arg1, attrlist, (void *)arg3, arg4, arg5)); + + if(!is_error(ret)) + { + byteswap_attrbuf((void *)arg3, attrlist); + byteswap_attrlist(attrlist); + } + return ret; +} + +long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8) +{ + DPRINTF("getdirentriesattr(0x%x, %p, %p, 0x%lx, %p, %p, %p, 0x%x)\n", + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); +#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) + qerror("SYS_getdirentriesattr unimplemented\n"); +#endif + + return get_errno(getdirentriesattr( arg1, (struct attrlist * )arg2, (void *)arg3, arg4, + (unsigned long *)arg5, (unsigned long *)arg6, + (unsigned long *)arg7, arg8)); +} + + +long no_syscall(void *cpu_env, int num) +{ + /* XXX: We should probably fordward it to the host kernel */ + qerror("no unix syscall %d\n", num); + /* not reached */ + return -1; +} + +long unimpl_unix_syscall(void *cpu_env, int num) +{ + if( (num < 0) || (num > SYS_MAXSYSCALL-1) ) + qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1); + + gemu_log("qemu: Unsupported unix syscall %s %d\n", unix_syscall_table[num].name , num); + gdb_handlesig (cpu_env, SIGTRAP); + exit(-1); +} + +long do_unix_syscall(void *cpu_env, int num) +{ + long ret = 0; + + DPRINTF("unix syscall %d: " , num); + + if( (num < 0) || (num > SYS_MAXSYSCALL-1) ) + qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1); + + DPRINTF("%s [%s]", unix_syscall_table[num].name, unix_syscall_table[num].call_type & CALL_DIRECT ? "direct" : "indirect" ); + ret = unix_syscall_table[num].function(cpu_env, num); + + if(!(unix_syscall_table[num].call_type & CALL_NOERRNO)) + ret = get_errno(ret); + + DPRINTF("[returned 0x%x(%d)]\n", (int)ret, (int)ret); + return ret; +} + +/* ------------------------------------------------------------ + syscall_init +*/ +void syscall_init(void) +{ + /* Nothing yet */ +} diff --git a/darwin-user/syscalls.h b/darwin-user/syscalls.h new file mode 100644 index 000000000..d04295bed --- /dev/null +++ b/darwin-user/syscalls.h @@ -0,0 +1,384 @@ +/* generated from xnu/bsd/kern/syscalls.master */ + + ENTRY("syscall", SYS_syscall, do_unix_syscall_indirect, 0, CALL_INDIRECT, VOID) /* 0 indirect syscall */ + ENTRY("exit", SYS_exit, do_exit, 1, CALL_DIRECT, INT) /* 1 */ + ENTRY("fork", SYS_fork, fork, 0, CALL_NOERRNO, VOID) /* 2 */ + ENTRY("read", SYS_read, read, 3, CALL_DIRECT, INT, PTR, SIZE) /* 3 */ + ENTRY("write", SYS_write, write, 3, CALL_DIRECT, INT, PTR, SIZE) /* 4 */ + ENTRY("open", SYS_open, do_open, 3, CALL_DIRECT, PTR, INT, INT) /* 5 */ + ENTRY("close", SYS_close, close, 1, CALL_DIRECT, INT) /* 6 */ + ENTRY("wait4", SYS_wait4, wait4, 4, CALL_DIRECT, INT, PTR, INT, PTR) /* 7 */ + ENTRY("", 8, no_syscall, 0, CALL_INDIRECT, VOID) /* 8 old creat */ + ENTRY("link", SYS_link, link, 2, CALL_DIRECT, PTR, PTR) /* 9 */ + ENTRY("unlink", SYS_unlink, unlink, 1, CALL_DIRECT, PTR) /* 10 */ + ENTRY("", 11, no_syscall, 0, CALL_INDIRECT, VOID) /* 11 old execv */ + ENTRY("chdir", SYS_chdir, chdir, 1, CALL_DIRECT, PTR) /* 12 */ + ENTRY("fchdir", SYS_fchdir, fchdir, 1, CALL_DIRECT, INT) /* 13 */ + ENTRY("mknod", SYS_mknod, mknod, 3, CALL_DIRECT, PTR, INT, INT) /* 14 */ + ENTRY("chmod", SYS_chmod, chmod, 2, CALL_DIRECT, PTR, INT) /* 15 */ + ENTRY("chown", SYS_chown, chown, 3, CALL_DIRECT, PTR, INT, INT) /* 16 */ + ENTRY("obreak", SYS_obreak, no_syscall, 1, CALL_INDIRECT, VOID) /* 17 old break */ + ENTRY("ogetfsstat", 18, unimpl_unix_syscall, 3, CALL_INDIRECT, PTR, INT, INT) /* 18 */ + ENTRY("", 19, no_syscall, 0, CALL_INDIRECT, VOID) /* 19 old lseek */ + ENTRY("getpid", SYS_getpid, getpid, 0, CALL_NOERRNO, VOID) /* 20 */ + ENTRY("", 21, no_syscall, 0, CALL_INDIRECT, VOID) /* 21 old mount */ + ENTRY("", 22, no_syscall, 0, CALL_INDIRECT, VOID) /* 22 old umount */ + ENTRY("setuid", SYS_setuid, setuid, 1, CALL_DIRECT, INT) /* 23 */ + ENTRY("getuid", SYS_getuid, getuid, 0, CALL_NOERRNO, VOID) /* 24 */ + ENTRY("geteuid", SYS_geteuid, geteuid, 0, CALL_NOERRNO, VOID) /* 25 */ + ENTRY("ptrace", SYS_ptrace, ptrace, 4, CALL_DIRECT, INT, INT, PTR, INT) /* 26 */ + ENTRY("recvmsg", SYS_recvmsg, recvmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 27 */ + ENTRY("sendmsg", SYS_sendmsg, sendmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 28 */ + ENTRY("recvfrom", SYS_recvfrom, recvfrom, 6, CALL_DIRECT, INT, PTR, INT, INT, PTR, PTR) /* 29 */ + ENTRY("accept", SYS_accept, accept, 3, CALL_DIRECT, INT, PTR, PTR) /* 30 */ + ENTRY("getpeername", SYS_getpeername, getpeername, 3, CALL_DIRECT, INT, PTR, PTR) /* 31 */ + ENTRY("getsockname", SYS_getsockname, getsockname, 3, CALL_DIRECT, INT, PTR, PTR) /* 32 */ + ENTRY("access", SYS_access, access, 2, CALL_DIRECT, PTR, INT) /* 33 */ + ENTRY("chflags", SYS_chflags, chflags, 2, CALL_DIRECT, PTR, INT) /* 34 */ + ENTRY("fchflags", SYS_fchflags, fchflags, 2, CALL_DIRECT, INT, INT) /* 35 */ + ENTRY("sync", SYS_sync, do_sync, 0, CALL_INDIRECT, VOID) /* 36 */ + ENTRY("kill", SYS_kill, kill, 2, CALL_DIRECT, INT, INT) /* 37 */ + ENTRY("", 38, no_syscall, 0, CALL_INDIRECT, VOID) /* 38 old stat */ + ENTRY("getppid", SYS_getppid, getppid, 0, CALL_DIRECT, VOID) /* 39 */ + ENTRY("", 40, no_syscall, 0, CALL_INDIRECT, VOID) /* 40 old lstat */ + ENTRY("dup", SYS_dup, dup, 1, CALL_DIRECT, INT) /* 41 */ + ENTRY("pipe", SYS_pipe, unimpl_unix_syscall, 0, CALL_INDIRECT, PTR) /* 42 */ + ENTRY("getegid", SYS_getegid, getegid, 0, CALL_NOERRNO, VOID) /* 43 */ + ENTRY("profil", SYS_profil, profil, 4, CALL_DIRECT, PTR, SIZE, INT, INT) /* 44 */ + ENTRY("ktrace", SYS_ktrace, no_syscall, 4, CALL_INDIRECT, VOID) /* 45 */ + ENTRY("sigaction", SYS_sigaction, do_sigaction, 3, CALL_DIRECT, INT, PTR, PTR) /* 46 */ + ENTRY("getgid", SYS_getgid, getgid, 0, CALL_NOERRNO, VOID) /* 47 */ + ENTRY("sigprocmask", SYS_sigprocmask, do_sigprocmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 48 */ + ENTRY("getlogin", SYS_getlogin, do_getlogin, 2, CALL_DIRECT, PTR, UINT) /* 49 XXX */ + ENTRY("setlogin", SYS_setlogin, setlogin, 1, CALL_DIRECT, PTR) /* 50 */ + ENTRY("acct", SYS_acct, acct, 1, CALL_DIRECT, PTR) /* 51 */ + ENTRY("sigpending", SYS_sigpending, sigpending, 1, CALL_DIRECT, PTR) /* 52 */ + ENTRY("sigaltstack", SYS_sigaltstack, do_sigaltstack, 2, CALL_DIRECT, PTR, PTR) /* 53 */ + ENTRY("ioctl", SYS_ioctl, do_ioctl, 3, CALL_DIRECT, INT, INT, INT) /* 54 */ + ENTRY("reboot", SYS_reboot, unimpl_unix_syscall, 2, CALL_INDIRECT, INT, PTR) /* 55 */ + ENTRY("revoke", SYS_revoke, revoke, 1, CALL_DIRECT, PTR) /* 56 */ + ENTRY("symlink", SYS_symlink, symlink, 2, CALL_DIRECT, PTR, PTR) /* 57 */ + ENTRY("readlink", SYS_readlink, readlink, 3, CALL_DIRECT, PTR, PTR, INT) /* 58 */ + ENTRY("execve", SYS_execve, do_execve, 3, CALL_DIRECT, PTR, PTR, PTR) /* 59 */ + ENTRY("umask", SYS_umask, umask, 1, CALL_DIRECT, INT) /* 60 */ + ENTRY("chroot", SYS_chroot, chroot, 1, CALL_DIRECT, PTR) /* 61 */ + ENTRY("", 62, no_syscall, 0, CALL_INDIRECT, VOID) /* 62 old fstat */ + ENTRY("", 63, no_syscall, 0, CALL_INDIRECT, VOID) /* 63 used internally , reserved */ + ENTRY("", 64, no_syscall, 0, CALL_INDIRECT, VOID) /* 64 old getpagesize */ + ENTRY("msync", SYS_msync, target_msync, 3, CALL_DIRECT, UINT /*PTR*/, SIZE, INT) /* 65 */ + ENTRY("vfork", SYS_vfork, vfork, 0, CALL_DIRECT, VOID) /* 66 */ + ENTRY("", 67, no_syscall, 0, CALL_INDIRECT, VOID) /* 67 old vread */ + ENTRY("", 68, no_syscall, 0, CALL_INDIRECT, VOID) /* 68 old vwrite */ + ENTRY("sbrk", SYS_sbrk, sbrk, 1, CALL_DIRECT, INT) /* 69 */ + ENTRY("sstk", SYS_sstk, no_syscall, 1, CALL_INDIRECT, VOID) /* 70 */ + ENTRY("", 71, no_syscall, 0, CALL_INDIRECT, VOID) /* 71 old mmap */ + ENTRY("ovadvise", SYS_ovadvise, no_syscall, 0, CALL_INDIRECT, VOID) /* 72 old vadvise */ + ENTRY("munmap", SYS_munmap, target_munmap, 2, CALL_DIRECT, UINT /* PTR */, SIZE) /* 73 */ + ENTRY("mprotect", SYS_mprotect, mprotect, 3, CALL_DIRECT, PTR, SIZE, INT) /* 74 */ + ENTRY("madvise", SYS_madvise, madvise, 3, CALL_DIRECT, PTR, SIZE, INT) /* 75 */ + ENTRY("", 76, no_syscall, 0, CALL_INDIRECT, VOID) /* 76 old vhangup */ + ENTRY("", 77, no_syscall, 0, CALL_INDIRECT, VOID) /* 77 old vlimit */ + ENTRY("mincore", SYS_mincore, mincore, 3, CALL_DIRECT, PTR, SIZE, PTR) /* 78 */ + ENTRY("getgroups", SYS_getgroups, do_getgroups, 2, CALL_DIRECT, UINT, PTR) /* 79 */ + ENTRY("setgroups", SYS_setgroups, setgroups, 2, CALL_DIRECT, UINT, PTR) /* 80 */ + ENTRY("getpgrp", SYS_getpgrp, getpgrp, 0, CALL_DIRECT, VOID) /* 81 */ + ENTRY("setpgid", SYS_setpgid, setpgid, 2, CALL_DIRECT, INT, INT) /* 82 */ + ENTRY("setitimer", SYS_setitimer, setitimer, 3, CALL_DIRECT, INT, PTR, PTR) /* 83 */ + ENTRY("", 84, no_syscall, 0, CALL_INDIRECT, VOID) /* 84 old wait */ + ENTRY("swapon", SYS_swapon, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 85 */ + ENTRY("getitimer", SYS_getitimer, getitimer, 2, CALL_DIRECT, INT, PTR) /* 86 */ + ENTRY("", 87, no_syscall, 0, CALL_INDIRECT, VOID) /* 87 old gethostname */ + ENTRY("", 88, no_syscall, 0, CALL_INDIRECT, VOID) /* 88 old sethostname */ + ENTRY("getdtablesize", SYS_getdtablesize, getdtablesize, 0, CALL_DIRECT, VOID) /* 89 */ + ENTRY("dup2", SYS_dup2, dup2, 2, CALL_DIRECT, INT, INT) /* 90 */ + ENTRY("", 91, no_syscall, 0, CALL_INDIRECT, VOID) /* 91 old getdopt */ + ENTRY("fcntl", SYS_fcntl, fcntl, 3, CALL_DIRECT, INT, INT, INT) /* 92 */ + ENTRY("select", SYS_select, select, 5, CALL_DIRECT, INT, PTR, PTR, PTR, PTR) /* 93 */ + ENTRY("", 94, no_syscall, 0, CALL_INDIRECT, VOID) /* 94 old setdopt */ + ENTRY("fsync", SYS_fsync, fsync, 1, CALL_DIRECT, INT) /* 95 */ + ENTRY("setpriority", SYS_setpriority, setpriority, 3, CALL_DIRECT, INT, INT, INT) /* 96 */ + ENTRY("socket", SYS_socket, socket, 3, CALL_DIRECT, INT, INT, INT) /* 97 */ + ENTRY("connect", SYS_connect, connect, 3, CALL_DIRECT, INT, PTR, INT) /* 98 */ + ENTRY("", 99, no_syscall, 0, CALL_INDIRECT, VOID) /* 99 old accept */ + ENTRY("getpriority", SYS_getpriority, getpriority, 2, CALL_DIRECT, INT, INT) /* 100 */ + ENTRY("", 101, no_syscall, 0, CALL_INDIRECT, VOID) /* 101 old send */ + ENTRY("", 102, no_syscall, 0, CALL_INDIRECT, VOID) /* 102 old recv */ + ENTRY("", 103, no_syscall, 0, CALL_INDIRECT, VOID) /* 103 old sigreturn */ + ENTRY("bind", SYS_bind, bind, 3, CALL_DIRECT, INT, PTR, INT) /* 104 */ + ENTRY("setsockopt", SYS_setsockopt, setsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, INT) /* 105 */ + ENTRY("listen", SYS_listen, listen, 2, CALL_DIRECT, INT, INT) /* 106 */ + ENTRY("", 107, no_syscall, 0, CALL_INDIRECT, VOID) /* 107 old vtimes */ + ENTRY("", 108, no_syscall, 0, CALL_INDIRECT, VOID) /* 108 old sigvec */ + ENTRY("", 109, no_syscall, 0, CALL_INDIRECT, VOID) /* 109 old sigblock */ + ENTRY("", 110, no_syscall, 0, CALL_INDIRECT, VOID) /* 110 old sigsetmask */ + ENTRY("sigsuspend", SYS_sigsuspend, unimpl_unix_syscall, 1, CALL_INDIRECT, INT) /* 111 */ + ENTRY("", 112, no_syscall, 0, CALL_INDIRECT, VOID) /* 112 old sigstack */ + ENTRY("", 113, no_syscall, 0, CALL_INDIRECT, VOID) /* 113 old recvmsg */ + ENTRY("", 114, no_syscall, 0, CALL_INDIRECT, VOID) /* 114 old sendmsg */ + ENTRY("", 115, no_syscall, 0, CALL_INDIRECT, VOID) /* 115 old vtrace */ + ENTRY("gettimeofday", SYS_gettimeofday, do_gettimeofday, 2, CALL_DIRECT, PTR, PTR) /* 116 */ + ENTRY("getrusage", SYS_getrusage, getrusage, 2, CALL_DIRECT, INT, PTR) /* 117 */ + ENTRY("getsockopt", SYS_getsockopt, getsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, PTR) /* 118 */ + ENTRY("", 119, no_syscall, 0, CALL_INDIRECT, VOID) /* 119 old resuba */ + ENTRY("readv", SYS_readv, do_readv, 3, CALL_DIRECT, INT, PTR, UINT) /* 120 */ + ENTRY("writev", SYS_writev, do_writev, 3, CALL_DIRECT, INT, PTR, UINT) /* 121 */ + ENTRY("settimeofday", SYS_settimeofday, settimeofday, 2, CALL_DIRECT, PTR, PTR) /* 122 */ + ENTRY("fchown", SYS_fchown, fchown, 3, CALL_DIRECT, INT, INT, INT) /* 123 */ + ENTRY("fchmod", SYS_fchmod, fchmod, 2, CALL_DIRECT, INT, INT) /* 124 */ + ENTRY("", 125, no_syscall, 0, CALL_INDIRECT, VOID) /* 125 old recvfrom */ + ENTRY("", 126, no_syscall, 0, CALL_INDIRECT, VOID) /* 126 old setreuid */ + ENTRY("", 127, no_syscall, 0, CALL_INDIRECT, VOID) /* 127 old setregid */ + ENTRY("rename", SYS_rename, rename, 2, CALL_DIRECT, PTR, PTR) /* 128 */ + ENTRY("", 129, no_syscall, 0, CALL_INDIRECT, VOID) /* 129 old truncate */ + ENTRY("", 130, no_syscall, 0, CALL_INDIRECT, VOID) /* 130 old ftruncate */ + ENTRY("flock", SYS_flock, flock, 2, CALL_DIRECT, INT, INT) /* 131 */ + ENTRY("mkfifo", SYS_mkfifo, mkfifo, 2, CALL_DIRECT, PTR, INT) /* 132 */ + ENTRY("sendto", SYS_sendto, sendto, 6, CALL_DIRECT, INT, PTR, SIZE, INT, PTR, INT) /* 133 */ + ENTRY("shutdown", SYS_shutdown, shutdown, 2, CALL_DIRECT, INT, INT) /* 134 */ + ENTRY("socketpair", SYS_socketpair, socketpair, 4, CALL_DIRECT, INT, INT, INT, PTR) /* 135 */ + ENTRY("mkdir", SYS_mkdir, mkdir, 2, CALL_DIRECT, PTR, INT) /* 136 */ + ENTRY("rmdir", SYS_rmdir, rmdir, 1, CALL_DIRECT, PTR) /* 137 */ + ENTRY("utimes", SYS_utimes, do_utimes, 2, CALL_DIRECT, PTR, PTR) /* 138 */ + ENTRY("futimes", SYS_futimes, do_futimes, 2, CALL_DIRECT, INT, PTR) /* 139 */ + ENTRY("adjtime", SYS_adjtime, adjtime, 2, CALL_DIRECT, PTR, PTR) /* 140 */ + ENTRY("", 141, no_syscall, 0, CALL_INDIRECT, VOID) /* 141 old getpeername */ + ENTRY("", 142, no_syscall, 0, CALL_INDIRECT, VOID) /* 142 old gethostid */ + ENTRY("", 143, no_syscall, 0, CALL_INDIRECT, VOID) /* 143 old sethostid */ + ENTRY("", 144, no_syscall, 0, CALL_INDIRECT, VOID) /* 144 old getrlimit */ + ENTRY("", 145, no_syscall, 0, CALL_INDIRECT, VOID) /* 145 old setrlimit */ + ENTRY("", 146, no_syscall, 0, CALL_INDIRECT, VOID) /* 146 old killpg */ + ENTRY("setsid", SYS_setsid, setsid, 0, CALL_DIRECT, VOID) /* 147 */ + ENTRY("", 148, no_syscall, 0, CALL_INDIRECT, VOID) /* 148 old setquota */ + ENTRY("", 149, no_syscall, 0, CALL_INDIRECT, VOID) /* 149 old qquota */ + ENTRY("", 150, no_syscall, 0, CALL_INDIRECT, VOID) /* 150 old getsockname */ + ENTRY("getpgid", SYS_getpgid, getpgid, 1, CALL_DIRECT, INT) /* 151 */ + ENTRY("setprivexec", SYS_setprivexec, no_syscall, 1, CALL_INDIRECT, VOID) /* 152 */ + ENTRY("pread", SYS_pread, do_pread, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 153 */ + ENTRY("pwrite", SYS_pwrite, pwrite, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 154 */ +#ifdef SYS_nfssvc + ENTRY("nfssvc", SYS_nfssvc, nfssvc, 2, CALL_DIRECT, INT, PTR) /* 155 */ +#else + ENTRY("nfssvc", 155, no_syscall, 2, CALL_INDIRECT, VOID) /* 155 */ +#endif + ENTRY("", 155, no_syscall, 0, CALL_INDIRECT, VOID) /* 155 */ + ENTRY("", 156, no_syscall, 0, CALL_INDIRECT, VOID) /* 156 old getdirentries */ + ENTRY("statfs", SYS_statfs, do_statfs, 2, CALL_DIRECT, PTR, PTR) /* 157 */ + ENTRY("fstatfs", SYS_fstatfs, do_fstatfs, 2, CALL_DIRECT, INT, PTR) /* 158 */ + ENTRY("unmount", SYS_unmount, unmount, 2, CALL_DIRECT, PTR, INT) /* 159 */ + ENTRY("", 160, no_syscall, 0, CALL_INDIRECT, VOID) /* 160 old async_daemon */ + ENTRY("", 161, no_syscall, 0, CALL_INDIRECT, VOID) /* 161 */ + ENTRY("", 162, no_syscall, 0, CALL_INDIRECT, VOID) /* 162 old getdomainname */ + ENTRY("", 163, no_syscall, 0, CALL_INDIRECT, VOID) /* 163 old setdomainname */ + ENTRY("", 164, no_syscall, 0, CALL_INDIRECT, VOID) /* 164 */ + ENTRY("quotactl", SYS_quotactl, no_syscall, 4, CALL_INDIRECT, VOID) /* 165 */ + ENTRY("", 166, no_syscall, 0, CALL_INDIRECT, VOID) /* 166 old exportfs */ + ENTRY("mount", SYS_mount, mount, 4, CALL_DIRECT, PTR, PTR, INT, PTR) /* 167 */ + ENTRY("", 168, no_syscall, 0, CALL_INDIRECT, VOID) /* 168 old ustat */ + ENTRY("", 169, no_syscall, 0, CALL_INDIRECT, VOID) /* 169 */ + ENTRY("table", SYS_table, no_syscall, 0, CALL_INDIRECT, VOID) /* 170 old table */ + ENTRY("", 171, no_syscall, 0, CALL_INDIRECT, VOID) /* 171 old wait3 */ + ENTRY("", 172, no_syscall, 0, CALL_INDIRECT, VOID) /* 172 old rpause */ + ENTRY("waitid", SYS_waitid, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 173 */ + ENTRY("", 174, no_syscall, 0, CALL_INDIRECT, VOID) /* 174 old getdents */ + ENTRY("", 175, no_syscall, 0, CALL_INDIRECT, VOID) /* 175 old gc_control */ + ENTRY("add_profil", SYS_add_profil, add_profil, 4, CALL_DIRECT, PTR, SIZE, UINT, UINT) /* 176 */ + ENTRY("", 177, no_syscall, 0, CALL_INDIRECT, VOID) /* 177 */ + ENTRY("", 178, no_syscall, 0, CALL_INDIRECT, VOID) /* 178 */ + ENTRY("", 179, no_syscall, 0, CALL_INDIRECT, VOID) /* 179 */ + ENTRY("kdebug_trace", SYS_kdebug_trace, no_syscall, 6, CALL_INDIRECT, VOID) /* 180 */ + ENTRY("setgid", SYS_setgid, setgid, 1, CALL_DIRECT, INT) /* 181 */ + ENTRY("setegid", SYS_setegid, setegid, 1, CALL_DIRECT, INT) /* 182 */ + ENTRY("seteuid", SYS_seteuid, seteuid, 1, CALL_DIRECT, INT) /* 183 */ + ENTRY("sigreturn", SYS_sigreturn, do_sigreturn, 2, CALL_INDIRECT, PTR, INT) /* 184 */ + ENTRY("chud", SYS_chud, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 185 */ + ENTRY("", 186, no_syscall, 0, CALL_INDIRECT, VOID) /* 186 */ + ENTRY("", 187, no_syscall, 0, CALL_INDIRECT, VOID) /* 187 */ + ENTRY("stat", SYS_stat, do_stat, 2, CALL_DIRECT, PTR, PTR) /* 188 */ + ENTRY("fstat", SYS_fstat, do_fstat, 2, CALL_DIRECT, INT, PTR) /* 189 */ + ENTRY("lstat", SYS_lstat, do_lstat, 2, CALL_DIRECT, PTR, PTR) /* 190 */ + ENTRY("pathconf", SYS_pathconf, pathconf, 2, CALL_DIRECT, PTR, INT) /* 191 */ + ENTRY("fpathconf", SYS_fpathconf, fpathconf, 2, CALL_DIRECT, INT, INT) /* 192 */ + ENTRY("getfsstat", SYS_getfsstat, do_getfsstat, 3, CALL_DIRECT, PTR, INT, INT) /* 193 */ + ENTRY("", 193, no_syscall, 0, CALL_INDIRECT, VOID) /* 193 */ + ENTRY("getrlimit", SYS_getrlimit, getrlimit, 2, CALL_DIRECT, UINT, PTR) /* 194 */ + ENTRY("setrlimit", SYS_setrlimit, setrlimit, 2, CALL_DIRECT, UINT, PTR) /* 195 */ + ENTRY("getdirentries", SYS_getdirentries, do_getdirentries, 4, CALL_DIRECT, INT, PTR, UINT, PTR) /* 196 */ + ENTRY("mmap", SYS_mmap, target_mmap, 6, CALL_DIRECT, UINT /*PTR*/, SIZE, INT, INT, INT, OFFSET) /* 197 */ + ENTRY("", 198, no_syscall, 0, CALL_INDIRECT, VOID) /* 198 __syscall */ + ENTRY("lseek", SYS_lseek, do_lseek, 3, CALL_INDIRECT, INT, OFFSET, INT) /* 199 */ + ENTRY("truncate", SYS_truncate, truncate, 2, CALL_DIRECT, PTR, OFFSET) /* 200 */ + ENTRY("ftruncate", SYS_ftruncate, ftruncate, 2, CALL_DIRECT, INT, OFFSET) /* 201 */ + ENTRY("__sysctl", SYS___sysctl, do___sysctl, 6, CALL_DIRECT, PTR, INT, PTR, PTR, PTR, SIZE) /* 202 */ + ENTRY("mlock", SYS_mlock, mlock, 2, CALL_DIRECT, PTR, SIZE) /* 203 */ + ENTRY("munlock", SYS_munlock, munlock, 2, CALL_DIRECT, PTR, SIZE) /* 204 */ + ENTRY("undelete", SYS_undelete, undelete, 1, CALL_DIRECT, PTR) /* 205 */ + ENTRY("ATsocket", SYS_ATsocket, no_syscall, 1, CALL_INDIRECT, VOID) /* 206 */ + ENTRY("ATgetmsg", SYS_ATgetmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 207 */ + ENTRY("ATputmsg", SYS_ATputmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 208 */ + ENTRY("ATPsndreq", SYS_ATPsndreq, no_syscall, 4, CALL_INDIRECT, VOID) /* 209 */ + ENTRY("ATPsndrsp", SYS_ATPsndrsp, no_syscall, 4, CALL_INDIRECT, VOID) /* 210 */ + ENTRY("ATPgetreq", SYS_ATPgetreq, no_syscall, 3, CALL_INDIRECT, VOID) /* 211 */ + ENTRY("ATPgetrsp", SYS_ATPgetrsp, no_syscall, 2, CALL_INDIRECT, VOID) /* 212 */ + ENTRY("", 213, no_syscall, 0, CALL_INDIRECT, VOID) /* 213 Reserved for AppleTalk */ + ENTRY("kqueue_from_portset_np", SYS_kqueue_from_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 214 */ + ENTRY("kqueue_portset_np", SYS_kqueue_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 215 */ + ENTRY("mkcomplex", SYS_mkcomplex, no_syscall, 3, CALL_INDIRECT, VOID) /* 216 soon to be obsolete */ + ENTRY("statv", SYS_statv, no_syscall, 2, CALL_INDIRECT, VOID) /* 217 soon to be obsolete */ + ENTRY("lstatv", SYS_lstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 218 soon to be obsolete */ + ENTRY("fstatv", SYS_fstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 219 soon to be obsolete */ + ENTRY("getattrlist", SYS_getattrlist, do_getattrlist, 5, CALL_DIRECT, PTR, PTR, PTR, SIZE, UINT) /* 220 */ + ENTRY("setattrlist", SYS_setattrlist, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 221 */ + ENTRY("getdirentriesattr", SYS_getdirentriesattr, do_getdirentriesattr, 8, CALL_DIRECT, INT, PTR, PTR, SIZE, PTR, PTR, PTR, UINT) /* 222 */ + ENTRY("exchangedata", SYS_exchangedata, exchangedata, 3, CALL_DIRECT, PTR, PTR, UINT) /* 223 */ + ENTRY("checkuseraccess", SYS_checkuseraccess, checkuseraccess, 6, CALL_DIRECT, PTR, INT, PTR, INT, INT, UINT) /* 224 */ + ENTRY("", 224, no_syscall, 0, CALL_INDIRECT, VOID) /* 224 HFS checkuseraccess check access to a file */ + ENTRY("searchfs", SYS_searchfs, searchfs, 6, CALL_DIRECT, PTR, PTR, PTR, UINT, UINT, PTR) /* 225 */ + ENTRY("delete", SYS_delete, no_syscall, 1, CALL_INDIRECT, VOID) /* 226 private delete ( Carbon semantics ) */ + ENTRY("copyfile", SYS_copyfile, no_syscall, 4, CALL_INDIRECT, VOID) /* 227 */ + ENTRY("", 228, no_syscall, 0, CALL_INDIRECT, VOID) /* 228 */ + ENTRY("", 229, no_syscall, 0, CALL_INDIRECT, VOID) /* 229 */ + ENTRY("poll", SYS_poll, no_syscall, 3, CALL_INDIRECT, VOID) /* 230 */ + ENTRY("watchevent", SYS_watchevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 231 */ + ENTRY("waitevent", SYS_waitevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 232 */ + ENTRY("modwatch", SYS_modwatch, no_syscall, 2, CALL_INDIRECT, VOID) /* 233 */ + ENTRY("getxattr", SYS_getxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 234 */ + ENTRY("fgetxattr", SYS_fgetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 235 */ + ENTRY("setxattr", SYS_setxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 236 */ + ENTRY("fsetxattr", SYS_fsetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 237 */ + ENTRY("removexattr", SYS_removexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 238 */ + ENTRY("fremovexattr", SYS_fremovexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 239 */ + ENTRY("listxattr", SYS_listxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 240 */ + ENTRY("flistxattr", SYS_flistxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 241 */ + ENTRY("fsctl", SYS_fsctl, fsctl, 4, CALL_DIRECT, PTR, UINT, PTR, UINT) /* 242 */ + ENTRY("initgroups", SYS_initgroups, unimpl_unix_syscall, 3, CALL_INDIRECT, UINT, PTR, INT) /* 243 */ + ENTRY("", 244, no_syscall, 0, CALL_INDIRECT, VOID) /* 244 */ + ENTRY("", 245, no_syscall, 0, CALL_INDIRECT, VOID) /* 245 */ + ENTRY("", 246, no_syscall, 0, CALL_INDIRECT, VOID) /* 246 */ +#ifdef SYS_nfsclnt + ENTRY("nfsclnt", SYS_nfsclnt, nfsclnt, 2, CALL_DIRECT, INT, PTR) /* 247 */ +#else + ENTRY("nfsclnt", 247, no_syscall, 2, CALL_INDIRECT, VOID) /* 247 */ +#endif + ENTRY("", 247, no_syscall, 0, CALL_INDIRECT, VOID) /* 247 */ + ENTRY("", 248, no_syscall, 0, CALL_INDIRECT, VOID) /* 248 */ + ENTRY("", 249, no_syscall, 0, CALL_INDIRECT, VOID) /* 249 */ + ENTRY("minherit", SYS_minherit, minherit, 3, CALL_DIRECT, PTR, INT, INT) /* 250 */ + ENTRY("semsys", SYS_semsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 251 */ + ENTRY("msgsys", SYS_msgsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 252 */ + ENTRY("shmsys", SYS_shmsys, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 253 */ + ENTRY("semctl", SYS_semctl, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 254 */ + ENTRY("semget", SYS_semget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 255 */ + ENTRY("semop", SYS_semop, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 256 */ + ENTRY("", 257, no_syscall, 0, CALL_INDIRECT, VOID) /* 257 */ + ENTRY("msgctl", SYS_msgctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 258 */ + ENTRY("msgget", SYS_msgget, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 259 */ + ENTRY("msgsnd", SYS_msgsnd, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 260 */ + ENTRY("msgrcv", SYS_msgrcv, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 261 */ + ENTRY("shmat", SYS_shmat, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 262 */ + ENTRY("shmctl", SYS_shmctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 263 */ + ENTRY("shmdt", SYS_shmdt, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 264 */ + ENTRY("shmget", SYS_shmget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 265 */ + ENTRY("shm_open", SYS_shm_open, shm_open, 3, CALL_DIRECT, PTR, INT, INT) /* 266 */ + ENTRY("shm_unlink", SYS_shm_unlink, shm_unlink, 1, CALL_DIRECT, PTR) /* 267 */ + ENTRY("sem_open", SYS_sem_open, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 268 */ + ENTRY("sem_close", SYS_sem_close, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 269 */ + ENTRY("sem_unlink", SYS_sem_unlink, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 270 */ + ENTRY("sem_wait", SYS_sem_wait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 271 */ + ENTRY("sem_trywait", SYS_sem_trywait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 272 */ + ENTRY("sem_post", SYS_sem_post, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 273 */ + ENTRY("sem_getvalue", SYS_sem_getvalue, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 274 */ + ENTRY("sem_init", SYS_sem_init, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 275 */ + ENTRY("sem_destroy", SYS_sem_destroy, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 276 */ + ENTRY("open_extended", SYS_open_extended, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 277 */ + ENTRY("umask_extended", SYS_umask_extended, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 278 */ + ENTRY("stat_extended", SYS_stat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 279 */ + ENTRY("lstat_extended", SYS_lstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 280 */ + ENTRY("fstat_extended", SYS_fstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 281 */ + ENTRY("chmod_extended", SYS_chmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 282 */ + ENTRY("fchmod_extended", SYS_fchmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 283 */ + ENTRY("access_extended", SYS_access_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 284 */ + ENTRY("settid", SYS_settid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 285 */ + ENTRY("gettid", SYS_gettid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 286 */ + ENTRY("setsgroups", SYS_setsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 287 */ + ENTRY("getsgroups", SYS_getsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 288 */ + ENTRY("setwgroups", SYS_setwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 289 */ + ENTRY("getwgroups", SYS_getwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 290 */ + ENTRY("mkfifo_extended", SYS_mkfifo_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 291 */ + ENTRY("mkdir_extended", SYS_mkdir_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 292 */ + ENTRY("identitysvc", SYS_identitysvc, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 293 */ + ENTRY("", 294, no_syscall, 0, CALL_INDIRECT, VOID) /* 294 */ + ENTRY("", 295, no_syscall, 0, CALL_INDIRECT, VOID) /* 295 */ + ENTRY("load_shared_file", SYS_load_shared_file, unimpl_unix_syscall, 7, CALL_INDIRECT, VOID) /* 296 */ + ENTRY("reset_shared_file", SYS_reset_shared_file, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 297 */ + ENTRY("new_system_shared_regions", SYS_new_system_shared_regions, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 298 */ + ENTRY("shared_region_map_file_np", SYS_shared_region_map_file_np, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 299 */ + ENTRY("shared_region_make_private_np", SYS_shared_region_make_private_np, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 300 */ + ENTRY("", 301, no_syscall, 0, CALL_INDIRECT, VOID) /* 301 */ + ENTRY("", 302, no_syscall, 0, CALL_INDIRECT, VOID) /* 302 */ + ENTRY("", 303, no_syscall, 0, CALL_INDIRECT, VOID) /* 303 */ + ENTRY("", 304, no_syscall, 0, CALL_INDIRECT, VOID) /* 304 */ + ENTRY("", 305, no_syscall, 0, CALL_INDIRECT, VOID) /* 305 */ + ENTRY("", 306, no_syscall, 0, CALL_INDIRECT, VOID) /* 306 */ + ENTRY("", 307, no_syscall, 0, CALL_INDIRECT, VOID) /* 307 */ + ENTRY("", 308, no_syscall, 0, CALL_INDIRECT, VOID) /* 308 */ + ENTRY("", 309, no_syscall, 0, CALL_INDIRECT, VOID) /* 309 */ + ENTRY("getsid", SYS_getsid, getsid, 1, CALL_DIRECT, INT) /* 310 */ + ENTRY("settid_with_pid", SYS_settid_with_pid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 311 */ + ENTRY("", 312, no_syscall, 0, CALL_INDIRECT, VOID) /* 312 */ + ENTRY("aio_fsync", SYS_aio_fsync, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 313 */ + ENTRY("aio_return", SYS_aio_return, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 314 */ + ENTRY("aio_suspend", SYS_aio_suspend, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 315 */ + ENTRY("aio_cancel", SYS_aio_cancel, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 316 */ + ENTRY("aio_error", SYS_aio_error, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 317 */ + ENTRY("aio_read", SYS_aio_read, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 318 */ + ENTRY("aio_write", SYS_aio_write, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 319 */ + ENTRY("lio_listio", SYS_lio_listio, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 320 */ + ENTRY("", 321, no_syscall, 0, CALL_INDIRECT, VOID) /* 321 */ + ENTRY("", 322, no_syscall, 0, CALL_INDIRECT, VOID) /* 322 */ + ENTRY("", 323, no_syscall, 0, CALL_INDIRECT, VOID) /* 323 */ + ENTRY("mlockall", SYS_mlockall, mlockall, 1, CALL_DIRECT, INT) /* 324 */ + ENTRY("munlockall", SYS_munlockall, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 325 */ + ENTRY("", 326, no_syscall, 0, CALL_INDIRECT, VOID) /* 326 */ + ENTRY("issetugid", SYS_issetugid, issetugid, 0, CALL_DIRECT, VOID) /* 327 */ + ENTRY("__pthread_kill", SYS___pthread_kill, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 328 */ + ENTRY("pthread_sigmask", SYS_pthread_sigmask, pthread_sigmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 329 */ + ENTRY("sigwait", SYS_sigwait, sigwait, 2, CALL_DIRECT, PTR, PTR) /* 330 */ + ENTRY("__disable_threadsignal", SYS___disable_threadsignal, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 331 */ + ENTRY("__pthread_markcancel", SYS___pthread_markcancel, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 332 */ + ENTRY("__pthread_canceled", SYS___pthread_canceled, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 333 */ + ENTRY("__semwait_signal", SYS___semwait_signal, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 334 */ + ENTRY("utrace", SYS_utrace, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 335 */ + ENTRY("proc_info", SYS_proc_info, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 336 */ + ENTRY("", 337, no_syscall, 0, CALL_INDIRECT, VOID) /* 337 */ + ENTRY("", 338, no_syscall, 0, CALL_INDIRECT, VOID) /* 338 */ + ENTRY("", 339, no_syscall, 0, CALL_INDIRECT, VOID) /* 339 */ + ENTRY("", 340, no_syscall, 0, CALL_INDIRECT, VOID) /* 340 */ + ENTRY("", 341, no_syscall, 0, CALL_INDIRECT, VOID) /* 341 */ + ENTRY("", 342, no_syscall, 0, CALL_INDIRECT, VOID) /* 342 */ + ENTRY("", 343, no_syscall, 0, CALL_INDIRECT, VOID) /* 343 */ + ENTRY("", 344, no_syscall, 0, CALL_INDIRECT, VOID) /* 344 */ + ENTRY("", 345, no_syscall, 0, CALL_INDIRECT, VOID) /* 345 */ + ENTRY("", 346, no_syscall, 0, CALL_INDIRECT, VOID) /* 346 */ + ENTRY("", 347, no_syscall, 0, CALL_INDIRECT, VOID) /* 347 */ + ENTRY("", 348, no_syscall, 0, CALL_INDIRECT, VOID) /* 348 */ + ENTRY("", 349, no_syscall, 0, CALL_INDIRECT, VOID) /* 349 */ + ENTRY("audit", SYS_audit, audit, 2, CALL_DIRECT, PTR, INT) /* 350 */ + ENTRY("auditon", SYS_auditon, auditon, 3, CALL_DIRECT, INT, PTR, INT) /* 351 */ + ENTRY("", 352, no_syscall, 0, CALL_INDIRECT, VOID) /* 352 */ + ENTRY("getauid", SYS_getauid, getauid, 1, CALL_DIRECT, PTR) /* 353 */ + ENTRY("setauid", SYS_setauid, setauid, 1, CALL_DIRECT, PTR) /* 354 */ + ENTRY("getaudit", SYS_getaudit, getaudit, 1, CALL_DIRECT, PTR) /* 355 */ + ENTRY("setaudit", SYS_setaudit, setaudit, 1, CALL_DIRECT, PTR) /* 356 */ + ENTRY("getaudit_addr", SYS_getaudit_addr, getaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 357 */ + ENTRY("setaudit_addr", SYS_setaudit_addr, setaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 358 */ + ENTRY("auditctl", SYS_auditctl, auditctl, 1, CALL_DIRECT, PTR) /* 359 */ + ENTRY("", 360, no_syscall, 0, CALL_INDIRECT, VOID) /* 360 */ + ENTRY("", 361, no_syscall, 0, CALL_INDIRECT, VOID) /* 361 */ + ENTRY("kqueue", SYS_kqueue, kqueue, 0, CALL_DIRECT, VOID) /* 362 */ + ENTRY("kevent", SYS_kevent, kevent, 6, CALL_DIRECT, INT, PTR, INT, PTR, INT, PTR) /* 363 */ + ENTRY("lchown", SYS_lchown, lchown, 3, CALL_DIRECT, PTR, INT , INT) /* 364 */ + ENTRY("stack_snapshot", SYS_stack_snapshot, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 365 */ + ENTRY("", 366, no_syscall, 0, CALL_INDIRECT, VOID) /* 366 */ + ENTRY("", 367, no_syscall, 0, CALL_INDIRECT, VOID) /* 367 */ + ENTRY("", 368, no_syscall, 0, CALL_INDIRECT, VOID) /* 368 */ + ENTRY("", 369, no_syscall, 0, CALL_INDIRECT, VOID) /* 369 */ diff --git a/gdbstub.c b/gdbstub.c index a5e68ae03..9015d625c 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -810,7 +810,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) goto breakpoint_error; } break; -#ifdef CONFIG_USER_ONLY +#ifdef CONFIG_LINUX_USER case 'q': if (strncmp(p, "Offsets", 7) == 0) { TaskState *ts = env->opaque; -- cgit v1.2.3 From 284ec167e75d24aec95a7d0eec4837449ad83fb3 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 18 Jan 2007 22:14:53 +0000 Subject: Add Darwin userspace emulation to Changelog. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2333 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 2cc6e329f..8123c3a9c 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,7 @@ version 0.8.3: - Moved PCI init, MP table init and ACPI table init to Bochs BIOS - Support for MIPS32 Release 2 instruction set (Thiemo Seufer) - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil) + - Darwin userspace emulation (Pierre d'Herbemont) version 0.8.2: -- cgit v1.2.3 From 7f1c9da99804235212888abda7ba7f06ee3afc70 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 18 Jan 2007 22:43:16 +0000 Subject: Darwin build fix, by Pierre d'Herbemont. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2334 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block.c b/block.c index 9264e42a6..dfa1edc3c 100644 --- a/block.c +++ b/block.c @@ -35,6 +35,10 @@ #define SECTOR_BITS 9 #define SECTOR_SIZE (1 << SECTOR_BITS) +#ifndef ENOMEDIUM +#define ENOMEDIUM ENODEV +#endif + typedef struct BlockDriverAIOCBSync { BlockDriverAIOCB common; QEMUBH *bh; -- cgit v1.2.3 From 15dcf5aa86656cea05847f6c9163ab884a161d12 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 19 Jan 2007 17:56:23 +0000 Subject: Note more issues. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2335 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index 5dd1de39e..e162ea529 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -1,12 +1,8 @@ Unsolved issues/bugs in the mips/mipsel backend ----------------------------------------------- -- MIPS64: - - No 64bit TLB support - - no 64bit wide registers for FPU - - 64bit mul/div handling broken - - DM[FT]C not implemented - +General +------- - TLB fails cornercase at address wrap around - [ls][dw][lr] report broken (aligned) BadVAddr - Missing per-CPU instruction decoding, currently all implemented @@ -14,4 +10,19 @@ Unsolved issues/bugs in the mips/mipsel backend - pcnet32 does not work for little endian emulation on big endian host (probably not mips specific, but observable for mips-malta) +MIPS64 +------ +- No 64bit TLB support +- no 64bit wide registers for FPU +- 64bit mul/div handling broken +- DM[FT]C not implemented + +"Generic" 4Kc system emulation +------------------------------ +- Doesn't correspond to any real hardware. + +MALTA system emulation +---------------------- - We fake firmware support instead of doing the real thing +- 2.4 Kernels receive spurious PIIX4 interrupts, indicates some + divergence from actual hardware. -- cgit v1.2.3 From 472c5273e255f97131e2f75d1e19c93b788ddefd Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Jan 2007 00:27:42 +0000 Subject: Change display colors, the LED bar is green and the text display is red. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2336 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2c838a5b0..bee29db0d 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -81,8 +81,8 @@ static void malta_fpga_update_display(void *opaque) } leds_text[8] = '\0'; - qemu_chr_printf(s->display, "\e[H\n\n|\e[31m%-8.8s\e[00m|\r\n", leds_text); - qemu_chr_printf(s->display, "\n\n\n\n|\e[32m%-8.8s\e[00m|", s->display_text); + qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); + qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); } static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) -- cgit v1.2.3 From af23902bd941eae86ce8cfd7c0074e4f30b69446 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Jan 2007 00:29:01 +0000 Subject: Fix typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2337 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index bee29db0d..12343e0ad 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -291,7 +291,7 @@ MaltaFPGAState *malta_fpga_init(target_phys_addr_t base) cpu_register_physical_memory(base, 0x100000, malta); s->display = qemu_chr_open("vc"); - qemu_chr_printf(s->display, "\e[HMalta LEBDAR\r\n"); + qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n"); qemu_chr_printf(s->display, "+--------+\r\n"); qemu_chr_printf(s->display, "+ +\r\n"); qemu_chr_printf(s->display, "+--------+\r\n"); -- cgit v1.2.3 From 5f12ab4b10075e5ae87e95cdef305172e0de17c0 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Jan 2007 01:12:17 +0000 Subject: Add more ATAPI CDROM DMA support, by Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2338 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index a1aabf05e..afa06f804 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -394,6 +394,7 @@ typedef struct PCIIDEState { } PCIIDEState; static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb); +static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); static void padstr(char *str, const char *src, int len) { @@ -1063,11 +1064,17 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) size = max_size; s->lba = -1; /* no sector read */ s->packet_transfer_size = size; + s->io_buffer_size = size; /* dma: send the reply data as one chunk */ s->elementary_transfer_size = 0; s->io_buffer_index = 0; - s->status = READY_STAT; - ide_atapi_cmd_reply_end(s); + if (s->atapi_dma) { + s->status = READY_STAT | DRQ_STAT; + ide_dma_start(s, ide_atapi_cmd_read_dma_cb); + } else { + s->status = READY_STAT; + ide_atapi_cmd_reply_end(s); + } } /* start a CD-CDROM read command */ @@ -1099,14 +1106,23 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) } if (s->io_buffer_size > 0) { - if (s->cd_sector_size == 2352) { - n = 1; - cd_data_to_raw(s->io_buffer, s->lba); - } else { - n = s->io_buffer_size >> 11; - } + /* + * For a cdrom read sector command (s->lba != -1), + * adjust the lba for the next s->io_buffer_size chunk + * and dma the current chunk. + * For a command != read (s->lba == -1), just transfer + * the reply data. + */ + if (s->lba != -1) { + if (s->cd_sector_size == 2352) { + n = 1; + cd_data_to_raw(s->io_buffer, s->lba); + } else { + n = s->io_buffer_size >> 11; + } + s->lba += n; + } s->packet_transfer_size -= s->io_buffer_size; - s->lba += n; if (dma_buf_rw(bm, 1) == 0) goto eot; } @@ -1170,7 +1186,8 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, int sector_size) { #ifdef DEBUG_IDE_ATAPI - printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); + printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio", + lba, nb_sectors); #endif if (s->atapi_dma) { ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); -- cgit v1.2.3 From 57be54bb3e0114824eafd0c3cb7d75ffffffa897 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 20 Jan 2007 16:52:55 +0000 Subject: Fix "make test2". git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2339 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index f803f6a65..f535dfaf1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -92,7 +92,7 @@ hello-mipsel: hello-mips.c # XXX: find a way to compile easily a test for each arch test2: @for arch in i386 arm armeb sparc ppc mips mipsel; do \ - ../$${arch}-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \ + ../$${arch}-linux-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \ done clean: -- cgit v1.2.3 From 8e71621f784b27ac06c3b6301df161e445132b88 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 20 Jan 2007 17:12:09 +0000 Subject: Add ARM Angel semihosting to system emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2340 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + arm-semi.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/arm-semi.c | 235 ---------------------------------- qemu-doc.texi | 5 + target-arm/helper.c | 18 +++ vl.c | 8 ++ vl.h | 1 + 7 files changed, 378 insertions(+), 235 deletions(-) create mode 100644 arm-semi.c delete mode 100644 linux-user/arm-semi.c diff --git a/Makefile.target b/Makefile.target index af4a69a6e..d8b2be2a2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -397,6 +397,7 @@ 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+= arm-semi.o endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o diff --git a/arm-semi.c b/arm-semi.c new file mode 100644 index 000000000..4254cba84 --- /dev/null +++ b/arm-semi.c @@ -0,0 +1,345 @@ +/* + * Arm "Angel" semihosting syscalls + * + * Copyright (c) 2005, 2007 CodeSourcery. + * Written by Paul Brook. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#ifdef CONFIG_USER_ONLY +#include "qemu.h" + +#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024) +#else +#include "vl.h" +#endif + +#define SYS_OPEN 0x01 +#define SYS_CLOSE 0x02 +#define SYS_WRITEC 0x03 +#define SYS_WRITE0 0x04 +#define SYS_WRITE 0x05 +#define SYS_READ 0x06 +#define SYS_READC 0x07 +#define SYS_ISTTY 0x09 +#define SYS_SEEK 0x0a +#define SYS_FLEN 0x0c +#define SYS_TMPNAM 0x0d +#define SYS_REMOVE 0x0e +#define SYS_RENAME 0x0f +#define SYS_CLOCK 0x10 +#define SYS_TIME 0x11 +#define SYS_SYSTEM 0x12 +#define SYS_ERRNO 0x13 +#define SYS_GET_CMDLINE 0x15 +#define SYS_HEAPINFO 0x16 +#define SYS_EXIT 0x18 + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +int open_modeflags[12] = { + O_RDONLY, + O_RDONLY | O_BINARY, + O_RDWR, + O_RDWR | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_APPEND, + O_WRONLY | O_CREAT | O_APPEND | O_BINARY, + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY +}; + +#ifdef CONFIG_USER_ONLY +static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code) +{ + if (code == (uint32_t)-1) + ts->swi_errno = errno; + return code; +} +#else +static inline uint32_t set_swi_errno(CPUState *env, uint32_t code) +{ + return code; +} + +static uint32_t softmmu_tget32(CPUState *env, uint32_t addr) +{ + uint32_t val; + + cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0); + return tswap32(val); +} +static uint32_t softmmu_tget8(CPUState *env, uint32_t addr) +{ + uint8_t val; + + cpu_memory_rw_debug(env, addr, &val, 1, 0); + return val; +} +#define tget32(p) softmmu_tget32(env, p) +#define tget8(p) softmmu_tget8(env, p) + +static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len, + int copy) +{ + char *p; + /* TODO: Make this something that isn't fixed size. */ + p = malloc(len); + if (copy) + cpu_memory_rw_debug(env, addr, p, len, 0); + return p; +} +#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy) +static char *softmmu_lock_user_string(CPUState *env, uint32_t addr) +{ + char *p; + char *s; + uint8_t c; + /* TODO: Make this something that isn't fixed size. */ + s = p = malloc(1024); + do { + cpu_memory_rw_debug(env, addr, &c, 1, 0); + addr++; + *(p++) = c; + } while (c); + return s; +} +#define lock_user_string(p) softmmu_lock_user_string(env, p) +static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr, + target_ulong len) +{ + if (len) + cpu_memory_rw_debug(env, addr, p, len, 1); + free(p); +} +#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) +#endif + +#define ARG(n) tget32(args + (n) * 4) +#define SET_ARG(n, val) tput32(args + (n) * 4,val) +uint32_t do_arm_semihosting(CPUState *env) +{ + target_ulong args; + char * s; + int nr; + uint32_t ret; + uint32_t len; +#ifdef CONFIG_USER_ONLY + TaskState *ts = env->opaque; +#else + CPUState *ts = env; +#endif + + nr = env->regs[0]; + args = env->regs[1]; + switch (nr) { + case SYS_OPEN: + s = lock_user_string(ARG(0)); + if (ARG(1) >= 12) + return (uint32_t)-1; + if (strcmp(s, ":tt") == 0) { + if (ARG(1) < 4) + return STDIN_FILENO; + else + return STDOUT_FILENO; + } + ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); + unlock_user(s, ARG(0), 0); + return ret; + case SYS_CLOSE: + return set_swi_errno(ts, close(ARG(0))); + case SYS_WRITEC: + { + char c = tget8(args); + /* Write to debug console. stderr is near enough. */ + return write(STDERR_FILENO, &c, 1); + } + case SYS_WRITE0: + s = lock_user_string(args); + ret = write(STDERR_FILENO, s, strlen(s)); + unlock_user(s, args, 0); + return ret; + case SYS_WRITE: + len = ARG(2); + s = lock_user(ARG(1), len, 1); + ret = set_swi_errno(ts, write(ARG(0), s, len)); + unlock_user(s, ARG(1), 0); + if (ret == (uint32_t)-1) + return -1; + return ARG(2) - ret; + case SYS_READ: + len = ARG(2); + s = lock_user(ARG(1), len, 0); + do + ret = set_swi_errno(ts, read(ARG(0), s, len)); + while (ret == -1 && errno == EINTR); + unlock_user(s, ARG(1), len); + if (ret == (uint32_t)-1) + return -1; + return ARG(2) - ret; + case SYS_READC: + /* XXX: Read from debug cosole. Not implemented. */ + return 0; + case SYS_ISTTY: + return isatty(ARG(0)); + case SYS_SEEK: + ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); + if (ret == (uint32_t)-1) + return -1; + return 0; + case SYS_FLEN: + { + struct stat buf; + ret = set_swi_errno(ts, fstat(ARG(0), &buf)); + if (ret == (uint32_t)-1) + return -1; + return buf.st_size; + } + case SYS_TMPNAM: + /* XXX: Not implemented. */ + return -1; + case SYS_REMOVE: + s = lock_user_string(ARG(0)); + ret = set_swi_errno(ts, remove(s)); + unlock_user(s, ARG(0), 0); + return ret; + case SYS_RENAME: + { + char *s2; + s = lock_user_string(ARG(0)); + s2 = lock_user_string(ARG(2)); + ret = set_swi_errno(ts, rename(s, s2)); + unlock_user(s2, ARG(2), 0); + unlock_user(s, ARG(0), 0); + return ret; + } + case SYS_CLOCK: + return clock() / (CLOCKS_PER_SEC / 100); + case SYS_TIME: + return set_swi_errno(ts, time(NULL)); + case SYS_SYSTEM: + s = lock_user_string(ARG(0)); + ret = set_swi_errno(ts, system(s)); + unlock_user(s, ARG(0), 0); + case SYS_ERRNO: +#ifdef CONFIG_USER_ONLY + return ts->swi_errno; +#else + return 0; +#endif + case SYS_GET_CMDLINE: +#ifdef CONFIG_USER_ONLY + /* Build a commandline from the original argv. */ + { + char **arg = ts->info->host_argv; + int len = ARG(1); + /* lock the buffer on the ARM side */ + char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0); + + s = cmdline_buffer; + while (*arg && len > 2) { + int n = strlen(*arg); + + if (s != cmdline_buffer) { + *(s++) = ' '; + len--; + } + if (n >= len) + n = len - 1; + memcpy(s, *arg, n); + s += n; + len -= n; + arg++; + } + /* Null terminate the string. */ + *s = 0; + len = s - cmdline_buffer; + + /* Unlock the buffer on the ARM side. */ + unlock_user(cmdline_buffer, ARG(0), len); + + /* Adjust the commandline length argument. */ + SET_ARG(1, len); + + /* Return success if commandline fit into buffer. */ + return *arg ? -1 : 0; + } +#else + return -1; +#endif + case SYS_HEAPINFO: + { + uint32_t *ptr; + uint32_t limit; + +#ifdef CONFIG_USER_ONLY + /* Some C libraries assume the heap immediately follows .bss, so + allocate it using sbrk. */ + if (!ts->heap_limit) { + long ret; + + ts->heap_base = do_brk(0); + limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE; + /* Try a big heap, and reduce the size if that fails. */ + for (;;) { + ret = do_brk(limit); + if (ret != -1) + break; + limit = (ts->heap_base >> 1) + (limit >> 1); + } + ts->heap_limit = limit; + } + + ptr = lock_user(ARG(0), 16, 0); + ptr[0] = tswap32(ts->heap_base); + ptr[1] = tswap32(ts->heap_limit); + ptr[2] = tswap32(ts->stack_base); + ptr[3] = tswap32(0); /* Stack limit. */ + unlock_user(ptr, ARG(0), 16); +#else + limit = ram_size; + ptr = lock_user(ARG(0), 16, 0); + /* TODO: Make this use the limit of the loaded application. */ + ptr[0] = tswap32(limit / 2); + ptr[1] = tswap32(limit); + ptr[2] = tswap32(limit); /* Stack base */ + ptr[3] = tswap32(0); /* Stack limit. */ + unlock_user(ptr, ARG(0), 16); +#endif + return 0; + } + case SYS_EXIT: + exit(0); + default: + fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); + } +} diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c deleted file mode 100644 index b182eb408..000000000 --- a/linux-user/arm-semi.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Arm "Angel" semihosting syscalls - * - * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook. - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "qemu.h" - -#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024) - -#define SYS_OPEN 0x01 -#define SYS_CLOSE 0x02 -#define SYS_WRITEC 0x03 -#define SYS_WRITE0 0x04 -#define SYS_WRITE 0x05 -#define SYS_READ 0x06 -#define SYS_READC 0x07 -#define SYS_ISTTY 0x09 -#define SYS_SEEK 0x0a -#define SYS_FLEN 0x0c -#define SYS_TMPNAM 0x0d -#define SYS_REMOVE 0x0e -#define SYS_RENAME 0x0f -#define SYS_CLOCK 0x10 -#define SYS_TIME 0x11 -#define SYS_SYSTEM 0x12 -#define SYS_ERRNO 0x13 -#define SYS_GET_CMDLINE 0x15 -#define SYS_HEAPINFO 0x16 -#define SYS_EXIT 0x18 - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -int open_modeflags[12] = { - O_RDONLY, - O_RDONLY | O_BINARY, - O_RDWR, - O_RDWR | O_BINARY, - O_WRONLY | O_CREAT | O_TRUNC, - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - O_RDWR | O_CREAT | O_TRUNC, - O_RDWR | O_CREAT | O_TRUNC | O_BINARY, - O_WRONLY | O_CREAT | O_APPEND, - O_WRONLY | O_CREAT | O_APPEND | O_BINARY, - O_RDWR | O_CREAT | O_APPEND, - O_RDWR | O_CREAT | O_APPEND | O_BINARY -}; - -static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code) -{ - if (code == (uint32_t)-1) - ts->swi_errno = errno; - return code; -} - -#define ARG(n) tget32(args + (n) * 4) -#define SET_ARG(n, val) tput32(args + (n) * 4,val) -uint32_t do_arm_semihosting(CPUState *env) -{ - target_ulong args; - char * s; - int nr; - uint32_t ret; - TaskState *ts = env->opaque; - - nr = env->regs[0]; - args = env->regs[1]; - switch (nr) { - case SYS_OPEN: - s = (char *)g2h(ARG(0)); - if (ARG(1) >= 12) - return (uint32_t)-1; - if (strcmp(s, ":tt") == 0) { - if (ARG(1) < 4) - return STDIN_FILENO; - else - return STDOUT_FILENO; - } - return set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); - case SYS_CLOSE: - return set_swi_errno(ts, close(ARG(0))); - case SYS_WRITEC: - { - char c = tget8(args); - /* Write to debug console. stderr is near enough. */ - return write(STDERR_FILENO, &c, 1); - } - case SYS_WRITE0: - s = lock_user_string(args); - ret = write(STDERR_FILENO, s, strlen(s)); - unlock_user(s, args, 0); - return ret; - case SYS_WRITE: - ret = set_swi_errno(ts, write(ARG(0), g2h(ARG(1)), ARG(2))); - if (ret == (uint32_t)-1) - return -1; - return ARG(2) - ret; - case SYS_READ: - ret = set_swi_errno(ts, read(ARG(0), g2h(ARG(1)), ARG(2))); - if (ret == (uint32_t)-1) - return -1; - return ARG(2) - ret; - case SYS_READC: - /* XXX: Read from debug cosole. Not implemented. */ - return 0; - case SYS_ISTTY: - return isatty(ARG(0)); - case SYS_SEEK: - ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); - if (ret == (uint32_t)-1) - return -1; - return 0; - case SYS_FLEN: - { - struct stat buf; - ret = set_swi_errno(ts, fstat(ARG(0), &buf)); - if (ret == (uint32_t)-1) - return -1; - return buf.st_size; - } - case SYS_TMPNAM: - /* XXX: Not implemented. */ - return -1; - case SYS_REMOVE: - return set_swi_errno(ts, remove((char *)g2h(ARG(0)))); - case SYS_RENAME: - return set_swi_errno(ts, rename((char *)g2h(ARG(0)), - (char *)g2h(ARG(2)))); - case SYS_CLOCK: - return clock() / (CLOCKS_PER_SEC / 100); - case SYS_TIME: - return set_swi_errno(ts, time(NULL)); - case SYS_SYSTEM: - return set_swi_errno(ts, system((char *)g2h(ARG(0)))); - case SYS_ERRNO: - return ts->swi_errno; - case SYS_GET_CMDLINE: - /* Build a commandline from the original argv. */ - { - char **arg = ts->info->host_argv; - int len = ARG(1); - /* lock the buffer on the ARM side */ - char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0); - - s = cmdline_buffer; - while (*arg && len > 2) { - int n = strlen(*arg); - - if (s != cmdline_buffer) { - *(s++) = ' '; - len--; - } - if (n >= len) - n = len - 1; - memcpy(s, *arg, n); - s += n; - len -= n; - arg++; - } - /* Null terminate the string. */ - *s = 0; - len = s - cmdline_buffer; - - /* Unlock the buffer on the ARM side. */ - unlock_user(cmdline_buffer, ARG(0), len); - - /* Adjust the commandline length argument. */ - SET_ARG(1, len); - - /* Return success if commandline fit into buffer. */ - return *arg ? -1 : 0; - } - case SYS_HEAPINFO: - { - uint32_t *ptr; - uint32_t limit; - - /* Some C llibraries assume the heap immediately follows .bss, so - allocate it using sbrk. */ - if (!ts->heap_limit) { - long ret; - - ts->heap_base = do_brk(0); - limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE; - /* Try a big heap, and reduce the size if that fails. */ - for (;;) { - ret = do_brk(limit); - if (ret != -1) - break; - limit = (ts->heap_base >> 1) + (limit >> 1); - } - ts->heap_limit = limit; - } - - page_unprotect_range (ARG(0), 32); - ptr = (uint32_t *)g2h(ARG(0)); - ptr[0] = tswap32(ts->heap_base); - ptr[1] = tswap32(ts->heap_limit); - ptr[2] = tswap32(ts->stack_base); - ptr[3] = tswap32(0); /* Stack limit. */ - return 0; - } - case SYS_EXIT: - exit(0); - default: - fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); - cpu_dump_state(env, stderr, fprintf, 0); - abort(); - } -} - diff --git a/qemu-doc.texi b/qemu-doc.texi index 0423ef065..11cd82ceb 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -661,6 +661,11 @@ Exit instead of rebooting. @item -loadvm file Start right away with a saved state (@code{loadvm} in monitor) + +@item -semihosting +Enable "Angel" semihosting interface (ARM target machines only). +Note that this allows guest direct access to the host filesystem, +so should only be used with trusted guest OS. @end table @c man end diff --git a/target-arm/helper.c b/target-arm/helper.c index 04d3b5254..5b4cd1393 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -105,6 +105,8 @@ void switch_mode(CPUState *env, int mode) #else +extern int semihosting_enabled; + /* Map CPU modes onto saved register banks. */ static inline int bank_number (int mode) { @@ -175,6 +177,22 @@ void do_interrupt(CPUARMState *env) offset = 4; break; case EXCP_SWI: + if (semihosting_enabled) { + /* Check for semihosting interrupt. */ + if (env->thumb) { + mask = lduw_code(env->regs[15] - 2) & 0xff; + } else { + mask = ldl_code(env->regs[15] - 4) & 0xffffff; + } + /* Only intercept calls from privileged modes, to provide some + semblance of security. */ + if (((mask == 0x123456 && !env->thumb) + || (mask == 0xab && env->thumb)) + && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { + env->regs[0] = do_arm_semihosting(env); + return; + } + } new_mode = ARM_CPU_MODE_SVC; addr = 0x08; mask = CPSR_I; diff --git a/vl.c b/vl.c index eb675078a..9f620cb1d 100644 --- a/vl.c +++ b/vl.c @@ -171,6 +171,7 @@ int no_reboot = 0; int daemonize = 0; const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; +int semihosting_enabled = 0; /***********************************************************/ /* x86 ISA bus support */ @@ -6227,6 +6228,7 @@ enum { QEMU_OPTION_no_reboot, QEMU_OPTION_daemonize, QEMU_OPTION_option_rom, + QEMU_OPTION_semihosting }; typedef struct QEMUOption { @@ -6309,6 +6311,9 @@ const QEMUOption qemu_options[] = { { "no-reboot", 0, QEMU_OPTION_no_reboot }, { "daemonize", 0, QEMU_OPTION_daemonize }, { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, +#if defined(TARGET_ARM) + { "semihosting", 0, QEMU_OPTION_semihosting }, +#endif { NULL }, }; @@ -6970,6 +6975,9 @@ int main(int argc, char **argv) option_rom[nb_option_roms] = optarg; nb_option_roms++; break; + case QEMU_OPTION_semihosting: + semihosting_enabled = 1; + break; } } } diff --git a/vl.h b/vl.h index 5cbbc4fb8..6bc2d73f6 100644 --- a/vl.h +++ b/vl.h @@ -159,6 +159,7 @@ extern int win2k_install_hack; extern int usb_enabled; extern int smp_cpus; extern int no_quit; +extern int semihosting_enabled; #define MAX_OPTION_ROMS 16 extern const char *option_rom[MAX_OPTION_ROMS]; -- cgit v1.2.3 From bc814401c2061f0d362f0fb709397a890df47e7c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 21 Jan 2007 03:12:25 +0000 Subject: Bring TLB / PageSize handling in line with real hardware behaviour. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2341 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 22 +++++----------------- target-mips/op_helper.c | 8 -------- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 43038c2d7..091dbffb7 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -50,7 +50,7 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && - tlb->VPN == tag && address < tlb->end2) { + tlb->VPN == tag) { /* TLB match */ n = (address >> TARGET_PAGE_BITS) & 1; /* Check access rights */ @@ -420,7 +420,6 @@ void do_interrupt (CPUState *env) void invalidate_tlb (CPUState *env, int idx, int use_extra) { tlb_t *tlb; - target_ulong addr; uint8_t ASID; ASID = env->CP0_EntryHi & 0xFF; @@ -441,19 +440,8 @@ void invalidate_tlb (CPUState *env, int idx, int use_extra) return; } - if (tlb->V0) { - addr = tlb->VPN; - while (addr < tlb->end) { - tlb_flush_page (env, addr); - addr += TARGET_PAGE_SIZE; - } - } - if (tlb->V1) { - addr = tlb->end; - while (addr < tlb->end2) { - tlb_flush_page (env, addr); - addr += TARGET_PAGE_SIZE; - } - } + if (tlb->V0) + tlb_flush_page (env, tlb->VPN); + if (tlb->V1) + tlb_flush_page (env, tlb->VPN + TARGET_PAGE_SIZE); } - diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index f4eb6e6a0..849482478 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -387,16 +387,11 @@ static void mips_tlb_flush_extra (CPUState *env, int first) static void fill_tlb (int idx) { tlb_t *tlb; - int size; /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb[idx]; tlb->VPN = env->CP0_EntryHi & (int32_t)0xFFFFE000; tlb->ASID = env->CP0_EntryHi & 0xFF; - size = env->CP0_PageMask >> 13; - size = 4 * (size + 1); - tlb->end = tlb->VPN + (1 << (8 + size)); - tlb->end2 = tlb->end + (1 << (8 + size)); tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; @@ -467,7 +462,6 @@ void do_tlbr (void) { tlb_t *tlb; uint8_t ASID; - int size; ASID = env->CP0_EntryHi & 0xFF; tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; @@ -479,8 +473,6 @@ void do_tlbr (void) mips_tlb_flush_extra(env, MIPS_TLB_NB); env->CP0_EntryHi = tlb->VPN | tlb->ASID; - size = (tlb->end - tlb->VPN) >> 12; - env->CP0_PageMask = (size - 1) << 13; env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | (tlb->C0 << 3) | (tlb->PFN[0] >> 6); env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | -- cgit v1.2.3 From 72f341ed1ef52607070120a7bbdc350edf52da47 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 21 Jan 2007 03:13:58 +0000 Subject: TLB address wraparound hopefully fixed now. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2342 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 1 - 1 file changed, 1 deletion(-) diff --git a/target-mips/TODO b/target-mips/TODO index e162ea529..13ae2a93d 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -3,7 +3,6 @@ Unsolved issues/bugs in the mips/mipsel backend General ------- -- TLB fails cornercase at address wrap around - [ls][dw][lr] report broken (aligned) BadVAddr - Missing per-CPU instruction decoding, currently all implemented instructions are regarded as valid -- cgit v1.2.3 From 3c07f8e89488c208391863cc7e26d106d7c0e46e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 21 Jan 2007 16:47:01 +0000 Subject: Don't resume guest when gdb connection terminates and -S specified. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2343 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 3 ++- vl.c | 6 +++--- vl.h | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 9015d625c..2311a6c01 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -987,7 +987,8 @@ static void gdb_read(void *opaque) qemu_del_vm_stop_handler(gdb_vm_stopped, s); qemu_set_fd_handler(s->fd, NULL, NULL, NULL); qemu_free(s); - vm_start(); + if (autostart) + vm_start(); } else { for(i = 0; i < size; i++) gdb_read_byte(s, buf[i]); diff --git a/vl.c b/vl.c index 9f620cb1d..f92c989d4 100644 --- a/vl.c +++ b/vl.c @@ -172,6 +172,7 @@ int daemonize = 0; const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; +int autostart = 1; /***********************************************************/ /* x86 ISA bus support */ @@ -6530,7 +6531,6 @@ int main(int argc, char **argv) const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; - int start_emulation = 1; char net_clients[MAX_NET_CLIENTS][256]; int nb_net_clients; int optind; @@ -6838,7 +6838,7 @@ int main(int argc, char **argv) bios_dir = optarg; break; case QEMU_OPTION_S: - start_emulation = 0; + autostart = 0; break; case QEMU_OPTION_k: keyboard_layout = optarg; @@ -7254,7 +7254,7 @@ int main(int argc, char **argv) { /* XXX: simplify init */ read_passwords(); - if (start_emulation) { + if (autostart) { vm_start(); } } diff --git a/vl.h b/vl.h index 6bc2d73f6..543eb722c 100644 --- a/vl.h +++ b/vl.h @@ -160,6 +160,7 @@ extern int usb_enabled; extern int smp_cpus; extern int no_quit; extern int semihosting_enabled; +extern int autostart; #define MAX_OPTION_ROMS 16 extern const char *option_rom[MAX_OPTION_ROMS]; -- cgit v1.2.3 From c281868e2675efc737fd99961ab083456bcdab35 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 21 Jan 2007 22:40:04 +0000 Subject: Add dependency for fop_template.c. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2344 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index d8b2be2a2..ba8d5e99b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -542,7 +542,7 @@ translate.o: translate.c translate_init.c endif ifeq ($(TARGET_ARCH), mips) -op.o: op.c op_template.c op_mem.c +op.o: op.c op_template.c fop_template.c op_mem.c op_helper.o: op_helper_mem.c endif -- cgit v1.2.3 From 3b1c8be4f4f1b5d4114320aaf41ec4872ab4598c Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 22 Jan 2007 20:50:42 +0000 Subject: Fix PageMask handling, second part. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2345 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 3 +-- target-mips/helper.c | 47 +++++++++++++++++++++++++++++++++-------------- target-mips/op_helper.c | 2 ++ 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c1b13d902..c1001c7fc 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -44,8 +44,7 @@ union fpr_t { typedef struct tlb_t tlb_t; struct tlb_t { target_ulong VPN; - target_ulong end; - target_ulong end2; + uint_fast32_t PageMask; uint_fast8_t ASID; uint_fast16_t G:1; uint_fast16_t C0:3; diff --git a/target-mips/helper.c b/target-mips/helper.c index 091dbffb7..d2d7a9f87 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -41,23 +41,26 @@ enum { static int map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) { - target_ulong tag = address & (TARGET_PAGE_MASK << 1); - uint8_t ASID = env->CP0_EntryHi & 0xFF; - tlb_t *tlb; - int i, n; + int i; for (i = 0; i < env->tlb_in_use; i++) { - tlb = &env->tlb[i]; + tlb_t *tlb = &env->tlb[i]; + /* 1k pages are not supported. */ + uint8_t ASID = env->CP0_EntryHi & 0xFF; + target_ulong mask = tlb->PageMask | 0x1FFF; + target_ulong tag = address & ~mask; + int n; + /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { /* TLB match */ - n = (address >> TARGET_PAGE_BITS) & 1; + n = !!(address & mask & ~(mask >> 1)); /* Check access rights */ if (!(n ? tlb->V1 : tlb->V0)) return TLBRET_INVALID; if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { - *physical = tlb->PFN[n] | (address & ~TARGET_PAGE_MASK); + *physical = tlb->PFN[n] | (address & (mask >> 1)); *prot = PAGE_READ; if (n ? tlb->D1 : tlb->D0) *prot |= PAGE_WRITE; @@ -420,9 +423,10 @@ void do_interrupt (CPUState *env) void invalidate_tlb (CPUState *env, int idx, int use_extra) { tlb_t *tlb; - uint8_t ASID; - - ASID = env->CP0_EntryHi & 0xFF; + target_ulong addr; + target_ulong end; + uint8_t ASID = env->CP0_EntryHi & 0xFF; + target_ulong mask; tlb = &env->tlb[idx]; /* The qemu TLB is flushed then the ASID changes, so no need to @@ -440,8 +444,23 @@ void invalidate_tlb (CPUState *env, int idx, int use_extra) return; } - if (tlb->V0) - tlb_flush_page (env, tlb->VPN); - if (tlb->V1) - tlb_flush_page (env, tlb->VPN + TARGET_PAGE_SIZE); + /* 1k pages are not supported. */ + mask = tlb->PageMask | 0x1FFF; + if (tlb->V0) { + addr = tlb->VPN; + end = addr | (mask >> 1); + while (addr < end) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } + } + if (tlb->V1) { + addr = tlb->VPN | ((mask >> 1) + 1); + addr = tlb->VPN + TARGET_PAGE_SIZE; + end = addr | mask; + while (addr < end) { + tlb_flush_page (env, addr); + addr += TARGET_PAGE_SIZE; + } + } } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 849482478..4326b6621 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -392,6 +392,7 @@ static void fill_tlb (int idx) tlb = &env->tlb[idx]; tlb->VPN = env->CP0_EntryHi & (int32_t)0xFFFFE000; tlb->ASID = env->CP0_EntryHi & 0xFF; + tlb->PageMask = env->CP0_PageMask; tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; @@ -473,6 +474,7 @@ void do_tlbr (void) mips_tlb_flush_extra(env, MIPS_TLB_NB); env->CP0_EntryHi = tlb->VPN | tlb->ASID; + env->CP0_PageMask = tlb->PageMask; env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | (tlb->C0 << 3) | (tlb->PFN[0] >> 6); env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | -- cgit v1.2.3 From 81e1e20979c9b09202277e125373e40bf2fb9e24 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 22 Jan 2007 20:57:17 +0000 Subject: Update TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2346 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index 13ae2a93d..a7ab2cf16 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -14,7 +14,8 @@ MIPS64 - No 64bit TLB support - no 64bit wide registers for FPU - 64bit mul/div handling broken -- DM[FT]C not implemented +- DM[FT]C not implemented, M[FT]C does not cut sign extensions in all + cases. "Generic" 4Kc system emulation ------------------------------ @@ -23,5 +24,5 @@ MIPS64 MALTA system emulation ---------------------- - We fake firmware support instead of doing the real thing -- 2.4 Kernels receive spurious PIIX4 interrupts, indicates some - divergence from actual hardware. +- Linux 2.4/2.6 Kernels receive spurious PIIX4 interrupts, noisy on 2.4, + silent on 2.6, indicates some divergence from actual hardware. -- cgit v1.2.3 From 17c275d9ceb1921c43a4255adf6bd768c90c9992 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 23 Jan 2007 01:47:46 +0000 Subject: Update .cvsignore. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2347 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.cvsignore b/.cvsignore index cd2812715..ae68e450c 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,14 +1,16 @@ -arm-user +arm-linux-user arm-softmmu -armeb-user +armeb-linux-user config-host.* dyngen i386 i386-softmmu -i386-user +i386-darwin-user +i386-linux-user ppc-softmmu ppc64-softmmu -ppc-user +ppc-darwin-user +ppc-linux-user qemu-doc.html qemu-tech.html qemu-doc.info @@ -17,19 +19,19 @@ qemu.1 qemu.pod qemu-img.1 qemu-img.pod -sparc-user +sparc-linux-user qemu-img sparc-softmmu x86_64-softmmu -sparc64-user +sparc64-linux-user sparc64-softmmu mips-softmmu mipsel-softmmu -mips-user -mipsel-user -m68k-user +mips-linux-user +mipsel-linux-user +m68k-linux-user .gdbinit -sh4-user +sh4-linux-user sh4-softmmu *.aux *.cp -- cgit v1.2.3 From 9c2149c8e06cf6fbf1bd5096a50486abc3b71f17 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 23 Jan 2007 22:45:22 +0000 Subject: Implementing dmfc/dmtc. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2348 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 67 +-- target-mips/op.c | 236 ++++++++-- target-mips/op_helper.c | 12 +- target-mips/translate.c | 1205 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 1434 insertions(+), 86 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c1001c7fc..8781e3098 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -44,7 +44,7 @@ union fpr_t { typedef struct tlb_t tlb_t; struct tlb_t { target_ulong VPN; - uint_fast32_t PageMask; + uint32_t PageMask; uint_fast8_t ASID; uint_fast16_t G:1; uint_fast16_t C0:3; @@ -110,20 +110,20 @@ struct CPUMIPSState { tlb_t tlb[MIPS_TLB_MAX]; uint32_t tlb_in_use; #endif - uint32_t CP0_index; - uint32_t CP0_random; - uint64_t CP0_EntryLo0; - uint64_t CP0_EntryLo1; - uint64_t CP0_Context; - uint32_t CP0_PageMask; - uint32_t CP0_PageGrain; - uint32_t CP0_Wired; - uint32_t CP0_HWREna; + int32_t CP0_Index; + int32_t CP0_Random; + target_ulong CP0_EntryLo0; + target_ulong CP0_EntryLo1; + target_ulong CP0_Context; + int32_t CP0_PageMask; + int32_t CP0_PageGrain; + int32_t CP0_Wired; + int32_t CP0_HWREna; target_ulong CP0_BadVAddr; - uint32_t CP0_Count; - uint64_t CP0_EntryHi; - uint32_t CP0_Compare; - uint32_t CP0_Status; + int32_t CP0_Count; + target_ulong CP0_EntryHi; + int32_t CP0_Compare; + int32_t CP0_Status; #define CP0St_CU3 31 #define CP0St_CU2 30 #define CP0St_CU1 29 @@ -146,9 +146,10 @@ struct CPUMIPSState { #define CP0St_ERL 2 #define CP0St_EXL 1 #define CP0St_IE 0 - uint32_t CP0_IntCtl; - uint32_t CP0_SRSCtl; - uint32_t CP0_Cause; + int32_t CP0_IntCtl; + int32_t CP0_SRSCtl; + int32_t CP0_SRSMap; + int32_t CP0_Cause; #define CP0Ca_BD 31 #define CP0Ca_TI 30 #define CP0Ca_CE 28 @@ -159,9 +160,9 @@ struct CPUMIPSState { #define CP0Ca_IP 8 #define CP0Ca_EC 2 target_ulong CP0_EPC; - uint32_t CP0_PRid; + int32_t CP0_PRid; target_ulong CP0_EBase; - uint32_t CP0_Config0; + int32_t CP0_Config0; #define CP0C0_M 31 #define CP0C0_K23 28 #define CP0C0_KU 25 @@ -174,7 +175,7 @@ struct CPUMIPSState { #define CP0C0_MT 7 #define CP0C0_VI 3 #define CP0C0_K0 0 - uint32_t CP0_Config1; + int32_t CP0_Config1; #define CP0C1_M 31 #define CP0C1_MMU 25 #define CP0C1_IS 22 @@ -190,7 +191,7 @@ struct CPUMIPSState { #define CP0C1_CA 2 #define CP0C1_EP 1 #define CP0C1_FP 0 - uint32_t CP0_Config2; + int32_t CP0_Config2; #define CP0C2_M 31 #define CP0C2_TU 28 #define CP0C2_TS 24 @@ -200,7 +201,7 @@ struct CPUMIPSState { #define CP0C2_SS 8 #define CP0C2_SL 4 #define CP0C2_SA 0 - uint32_t CP0_Config3; + int32_t CP0_Config3; #define CP0C3_M 31 #define CP0C3_DSPP 10 #define CP0C3_LPA 7 @@ -211,11 +212,11 @@ struct CPUMIPSState { #define CP0C3_SM 1 #define CP0C3_TL 0 target_ulong CP0_LLAddr; - uint32_t CP0_WatchLo; - uint32_t CP0_WatchHi; - uint32_t CP0_XContext; - uint32_t CP0_Framemask; - uint32_t CP0_Debug; + target_ulong CP0_WatchLo; + int32_t CP0_WatchHi; + target_ulong CP0_XContext; + int32_t CP0_Framemask; + int32_t CP0_Debug; #define CPDB_DBD 31 #define CP0DB_DM 30 #define CP0DB_LSNM 28 @@ -235,13 +236,13 @@ struct CPUMIPSState { #define CP0DB_DBp 1 #define CP0DB_DSS 0 target_ulong CP0_DEPC; - uint32_t CP0_Performance0; - uint32_t CP0_TagLo; - uint32_t CP0_DataLo; - uint32_t CP0_TagHi; - uint32_t CP0_DataHi; + int32_t CP0_Performance0; + int32_t CP0_TagLo; + int32_t CP0_DataLo; + int32_t CP0_TagHi; + int32_t CP0_DataHi; target_ulong CP0_ErrorEPC; - uint32_t CP0_DESAVE; + int32_t CP0_DESAVE; /* Qemu */ int interrupt_request; jmp_buf jmp_env; diff --git a/target-mips/op.c b/target-mips/op.c index 0550d2786..dec9f31ad 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1032,7 +1032,7 @@ void op_jnz_T2 (void) /* CP0 functions */ void op_mfc0_index (void) { - T0 = (int32_t)(env->CP0_index); + T0 = env->CP0_Index; RETURN(); } @@ -1044,49 +1044,49 @@ void op_mfc0_random (void) void op_mfc0_entrylo0 (void) { - T0 = env->CP0_EntryLo0; + T0 = (int32_t)env->CP0_EntryLo0; RETURN(); } void op_mfc0_entrylo1 (void) { - T0 = env->CP0_EntryLo1; + T0 = (int32_t)env->CP0_EntryLo1; RETURN(); } void op_mfc0_context (void) { - T0 = env->CP0_Context; + T0 = (int32_t)env->CP0_Context; RETURN(); } void op_mfc0_pagemask (void) { - T0 = (int32_t)env->CP0_PageMask; + T0 = env->CP0_PageMask; RETURN(); } void op_mfc0_pagegrain (void) { - T0 = (int32_t)env->CP0_PageGrain; + T0 = env->CP0_PageGrain; RETURN(); } void op_mfc0_wired (void) { - T0 = (int32_t)env->CP0_Wired; + T0 = env->CP0_Wired; RETURN(); } void op_mfc0_hwrena (void) { - T0 = (int32_t)env->CP0_HWREna; + T0 = env->CP0_HWREna; RETURN(); } void op_mfc0_badvaddr (void) { - T0 = env->CP0_BadVAddr; + T0 = (int32_t)env->CP0_BadVAddr; RETURN(); } @@ -1098,19 +1098,19 @@ void op_mfc0_count (void) void op_mfc0_entryhi (void) { - T0 = env->CP0_EntryHi; + T0 = (int32_t)env->CP0_EntryHi; RETURN(); } void op_mfc0_compare (void) { - T0 = (int32_t)env->CP0_Compare; + T0 = env->CP0_Compare; RETURN(); } void op_mfc0_status (void) { - T0 = (int32_t)env->CP0_Status; + T0 = env->CP0_Status; if (env->hflags & MIPS_HFLAG_UM) T0 |= (1 << CP0St_UM); if (env->hflags & MIPS_HFLAG_ERL) @@ -1122,67 +1122,73 @@ void op_mfc0_status (void) void op_mfc0_intctl (void) { - T0 = (int32_t)env->CP0_IntCtl; + T0 = env->CP0_IntCtl; RETURN(); } void op_mfc0_srsctl (void) { - T0 = (int32_t)env->CP0_SRSCtl; + T0 = env->CP0_SRSCtl; + RETURN(); +} + +void op_mfc0_srsmap (void) +{ + T0 = env->CP0_SRSMap; RETURN(); } void op_mfc0_cause (void) { - T0 = (int32_t)env->CP0_Cause; + T0 = env->CP0_Cause; RETURN(); } void op_mfc0_epc (void) { - T0 = env->CP0_EPC; + T0 = (int32_t)env->CP0_EPC; RETURN(); } void op_mfc0_prid (void) { - T0 = (int32_t)env->CP0_PRid; + T0 = env->CP0_PRid; RETURN(); } void op_mfc0_ebase (void) { - T0 = env->CP0_EBase; + T0 = (int32_t)env->CP0_EBase; RETURN(); } void op_mfc0_config0 (void) { - T0 = (int32_t)env->CP0_Config0; + T0 = env->CP0_Config0; RETURN(); } void op_mfc0_config1 (void) { - T0 = (int32_t)env->CP0_Config1; + T0 = env->CP0_Config1; RETURN(); } void op_mfc0_config2 (void) { - T0 = (int32_t)env->CP0_Config2; + T0 = env->CP0_Config2; RETURN(); } void op_mfc0_config3 (void) { - T0 = (int32_t)env->CP0_Config3; + T0 = env->CP0_Config3; RETURN(); } void op_mfc0_lladdr (void) { - T0 = env->CP0_LLAddr >> 4; + T0 = (int32_t)env->CP0_LLAddr >> 4; RETURN(); } @@ -1194,13 +1200,13 @@ void op_mfc0_watchlo0 (void) void op_mfc0_watchhi0 (void) { - T0 = (int32_t)env->CP0_WatchHi; + T0 = env->CP0_WatchHi; RETURN(); } void op_mfc0_xcontext (void) { - T0 = env->CP0_XContext; + T0 = (int32_t)env->CP0_XContext; RETURN(); } @@ -1212,7 +1218,7 @@ void op_mfc0_framemask (void) void op_mfc0_debug (void) { - T0 = (int32_t)env->CP0_Debug; + T0 = env->CP0_Debug; if (env->hflags & MIPS_HFLAG_DM) T0 |= 1 << CP0DB_DM; RETURN(); @@ -1220,55 +1226,55 @@ void op_mfc0_debug (void) void op_mfc0_depc (void) { - T0 = env->CP0_DEPC; + T0 = (int32_t)env->CP0_DEPC; RETURN(); } void op_mfc0_performance0 (void) { - T0 = (int32_t)env->CP0_Performance0; + T0 = env->CP0_Performance0; RETURN(); } void op_mfc0_taglo (void) { - T0 = (int32_t)env->CP0_TagLo; + T0 = env->CP0_TagLo; RETURN(); } void op_mfc0_datalo (void) { - T0 = (int32_t)env->CP0_DataLo; + T0 = env->CP0_DataLo; RETURN(); } void op_mfc0_taghi (void) { - T0 = (int32_t)env->CP0_TagHi; + T0 = env->CP0_TagHi; RETURN(); } void op_mfc0_datahi (void) { - T0 = (int32_t)env->CP0_DataHi; + T0 = env->CP0_DataHi; RETURN(); } void op_mfc0_errorepc (void) { - T0 = env->CP0_ErrorEPC; + T0 = (int32_t)env->CP0_ErrorEPC; RETURN(); } void op_mfc0_desave (void) { - T0 = (int32_t)env->CP0_DESAVE; + T0 = env->CP0_DESAVE; RETURN(); } void op_mtc0_index (void) { - env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & (MIPS_TLB_NB - 1)); + env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 & (MIPS_TLB_NB - 1)); RETURN(); } @@ -1276,7 +1282,7 @@ void op_mtc0_entrylo0 (void) { /* Large physaddr not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo0 = T0 & (int32_t)0x3FFFFFFF; + env->CP0_EntryLo0 = (int32_t)T0 & 0x3FFFFFFF; RETURN(); } @@ -1284,7 +1290,7 @@ void op_mtc0_entrylo1 (void) { /* Large physaddr not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo1 = T0 & (int32_t)0x3FFFFFFF; + env->CP0_EntryLo1 = (int32_t)T0 & 0x3FFFFFFF; RETURN(); } @@ -1334,7 +1340,7 @@ void op_mtc0_entryhi (void) /* 1k pages not implemented */ /* Ignore MIPS64 TLB for now */ - val = T0 & (int32_t)0xFFFFE0FF; + val = (int32_t)T0 & 0xFFFFE0FF; old = env->CP0_EntryHi; env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ @@ -1353,7 +1359,7 @@ void op_mtc0_status (void) { uint32_t val, old, mask; - val = T0 & (int32_t)0xFA78FF01; + val = (int32_t)T0 & 0xFA78FF01; old = env->CP0_Status; if (T0 & (1 << CP0St_UM)) env->hflags |= MIPS_HFLAG_UM; @@ -1400,6 +1406,13 @@ void op_mtc0_srsctl (void) RETURN(); } +void op_mtc0_srsmap (void) +{ + /* shadow registers not implemented */ + env->CP0_SRSMap = 0; + RETURN(); +} + void op_mtc0_cause (void) { uint32_t val, old; @@ -1423,7 +1436,7 @@ void op_mtc0_cause (void) void op_mtc0_epc (void) { - env->CP0_EPC = T0; + env->CP0_EPC = (int32_t)T0; RETURN(); } @@ -1455,7 +1468,7 @@ void op_mtc0_config2 (void) void op_mtc0_watchlo0 (void) { - env->CP0_WatchLo = T0; + env->CP0_WatchLo = (int32_t)T0; RETURN(); } @@ -1467,7 +1480,7 @@ void op_mtc0_watchhi0 (void) void op_mtc0_xcontext (void) { - env->CP0_XContext = T0; /* XXX */ + env->CP0_XContext = (int32_t)T0; /* XXX */ RETURN(); } @@ -1489,7 +1502,7 @@ void op_mtc0_debug (void) void op_mtc0_depc (void) { - env->CP0_DEPC = T0; + env->CP0_DEPC = (int32_t)T0; RETURN(); } @@ -1501,7 +1514,7 @@ void op_mtc0_performance0 (void) void op_mtc0_taglo (void) { - env->CP0_TagLo = T0 & (int32_t)0xFFFFFCF6; + env->CP0_TagLo = T0 & 0xFFFFFCF6; RETURN(); } @@ -1525,7 +1538,7 @@ void op_mtc0_datahi (void) void op_mtc0_errorepc (void) { - env->CP0_ErrorEPC = T0; + env->CP0_ErrorEPC = (int32_t)T0; RETURN(); } @@ -1535,6 +1548,139 @@ void op_mtc0_desave (void) RETURN(); } +void op_dmfc0_entrylo0 (void) +{ + T0 = env->CP0_EntryLo0; + RETURN(); +} + +void op_dmfc0_entrylo1 (void) +{ + T0 = env->CP0_EntryLo1; + RETURN(); +} + +void op_dmfc0_context (void) +{ + T0 = env->CP0_Context; + RETURN(); +} + +void op_dmfc0_badvaddr (void) +{ + T0 = env->CP0_BadVAddr; + RETURN(); +} + +void op_dmfc0_entryhi (void) +{ + T0 = env->CP0_EntryHi; + RETURN(); +} + +void op_dmfc0_epc (void) +{ + T0 = env->CP0_EPC; + RETURN(); +} + +void op_dmfc0_ebase (void) +{ + T0 = env->CP0_EBase; + RETURN(); +} + +void op_dmfc0_lladdr (void) +{ + T0 = env->CP0_LLAddr >> 4; + RETURN(); +} + +void op_dmfc0_watchlo0 (void) +{ + T0 = env->CP0_WatchLo; + RETURN(); +} + +void op_dmfc0_xcontext (void) +{ + T0 = env->CP0_XContext; + RETURN(); +} + +void op_dmfc0_depc (void) +{ + T0 = env->CP0_DEPC; + RETURN(); +} + +void op_dmfc0_errorepc (void) +{ + T0 = env->CP0_ErrorEPC; + RETURN(); +} + +void op_dmtc0_entrylo0 (void) +{ + /* Large physaddr not implemented */ + /* 1k pages not implemented */ + env->CP0_EntryLo0 = T0 & 0x3FFFFFFF; + RETURN(); +} + +void op_dmtc0_entrylo1 (void) +{ + /* Large physaddr not implemented */ + /* 1k pages not implemented */ + env->CP0_EntryLo1 = T0 & 0x3FFFFFFF; + RETURN(); +} + +void op_dmtc0_context (void) +{ + env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0); + RETURN(); +} + +void op_dmtc0_epc (void) +{ + env->CP0_EPC = T0; + RETURN(); +} + +void op_dmtc0_ebase (void) +{ + /* vectored interrupts not implemented */ + /* Multi-CPU not implemented */ + /* XXX: 64bit addressing broken */ + env->CP0_EBase = (int32_t)0x80000000 | (T0 & 0x3FFFF000); + RETURN(); +} + +void op_dmtc0_watchlo0 (void) +{ + env->CP0_WatchLo = T0; + RETURN(); +} + +void op_dmtc0_xcontext (void) +{ + env->CP0_XContext = T0; /* XXX */ + RETURN(); +} + +void op_dmtc0_depc (void) +{ + env->CP0_DEPC = T0; + RETURN(); +} + +void op_dmtc0_errorepc (void) +{ + env->CP0_ErrorEPC = T0; + RETURN(); +} + #ifdef MIPS_USES_FPU #if 0 diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 4326b6621..bea5a905e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -411,10 +411,10 @@ void do_tlbwi (void) that might be a further win. */ mips_tlb_flush_extra (env, MIPS_TLB_NB); - /* Wildly undefined effects for CP0_index containing a too high value and + /* Wildly undefined effects for CP0_Index containing a too high value and MIPS_TLB_NB not being a power of two. But so does real silicon. */ - invalidate_tlb(env, env->CP0_index & (MIPS_TLB_NB - 1), 0); - fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1)); + invalidate_tlb(env, env->CP0_Index & (MIPS_TLB_NB - 1), 0); + fill_tlb(env->CP0_Index & (MIPS_TLB_NB - 1)); } void do_tlbwr (void) @@ -439,7 +439,7 @@ void do_tlbp (void) /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { /* TLB match */ - env->CP0_index = i; + env->CP0_Index = i; break; } } @@ -455,7 +455,7 @@ void do_tlbp (void) } } - env->CP0_index |= 0x80000000; + env->CP0_Index |= 0x80000000; } } @@ -465,7 +465,7 @@ void do_tlbr (void) uint8_t ASID; ASID = env->CP0_EntryHi & 0xFF; - tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; + tlb = &env->tlb[env->CP0_Index & (MIPS_TLB_NB - 1)]; /* If this will change the current ASID, flush qemu's TLB. */ if (ASID != tlb->ASID) diff --git a/target-mips/translate.c b/target-mips/translate.c index a501a178f..3cc8a55d4 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2827,6 +2827,1181 @@ die: generate_exception(ctx, EXCP_RI); } +static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) +{ + const char *rn = "invalid"; + + switch (reg) { + case 0: + switch (sel) { + case 0: + gen_op_mfc0_index(); + rn = "Index"; + break; + case 1: +// gen_op_dmfc0_mvpcontrol(); /* MT ASE */ + rn = "MVPControl"; +// break; + case 2: +// gen_op_dmfc0_mvpconf0(); /* MT ASE */ + rn = "MVPConf0"; +// break; + case 3: +// gen_op_dmfc0_mvpconf1(); /* MT ASE */ + rn = "MVPConf1"; +// break; + default: + goto die; + } + break; + case 1: + switch (sel) { + case 0: + gen_op_mfc0_random(); + rn = "Random"; + break; + case 1: +// gen_op_dmfc0_vpecontrol(); /* MT ASE */ + rn = "VPEControl"; +// break; + case 2: +// gen_op_dmfc0_vpeconf0(); /* MT ASE */ + rn = "VPEConf0"; +// break; + case 3: +// gen_op_dmfc0_vpeconf1(); /* MT ASE */ + rn = "VPEConf1"; +// break; + case 4: +// gen_op_dmfc0_YQMask(); /* MT ASE */ + rn = "YQMask"; +// break; + case 5: +// gen_op_dmfc0_vpeschedule(); /* MT ASE */ + rn = "VPESchedule"; +// break; + case 6: +// gen_op_dmfc0_vpeschefback(); /* MT ASE */ + rn = "VPEScheFBack"; +// break; + case 7: +// gen_op_dmfc0_vpeopt(); /* MT ASE */ + rn = "VPEOpt"; +// break; + default: + goto die; + } + break; + case 2: + switch (sel) { + case 0: + gen_op_dmfc0_entrylo0(); + rn = "EntryLo0"; + break; + case 1: +// gen_op_dmfc0_tcstatus(); /* MT ASE */ + rn = "TCStatus"; +// break; + case 2: +// gen_op_dmfc0_tcbind(); /* MT ASE */ + rn = "TCBind"; +// break; + case 3: +// gen_op_dmfc0_tcrestart(); /* MT ASE */ + rn = "TCRestart"; +// break; + case 4: +// gen_op_dmfc0_tchalt(); /* MT ASE */ + rn = "TCHalt"; +// break; + case 5: +// gen_op_dmfc0_tccontext(); /* MT ASE */ + rn = "TCContext"; +// break; + case 6: +// gen_op_dmfc0_tcschedule(); /* MT ASE */ + rn = "TCSchedule"; +// break; + case 7: +// gen_op_dmfc0_tcschefback(); /* MT ASE */ + rn = "TCScheFBack"; +// break; + default: + goto die; + } + break; + case 3: + switch (sel) { + case 0: + gen_op_dmfc0_entrylo1(); + rn = "EntryLo1"; + break; + default: + goto die; + } + break; + case 4: + switch (sel) { + case 0: + gen_op_dmfc0_context(); + rn = "Context"; + break; + case 1: +// gen_op_dmfc0_contextconfig(); /* SmartMIPS ASE */ + rn = "ContextConfig"; +// break; + default: + goto die; + } + break; + case 5: + switch (sel) { + case 0: + gen_op_mfc0_pagemask(); + rn = "PageMask"; + break; + case 1: + gen_op_mfc0_pagegrain(); + rn = "PageGrain"; + break; + default: + goto die; + } + break; + case 6: + switch (sel) { + case 0: + gen_op_mfc0_wired(); + rn = "Wired"; + break; + case 1: +// gen_op_dmfc0_srsconf0(); /* shadow registers */ + rn = "SRSConf0"; +// break; + case 2: +// gen_op_dmfc0_srsconf1(); /* shadow registers */ + rn = "SRSConf1"; +// break; + case 3: +// gen_op_dmfc0_srsconf2(); /* shadow registers */ + rn = "SRSConf2"; +// break; + case 4: +// gen_op_dmfc0_srsconf3(); /* shadow registers */ + rn = "SRSConf3"; +// break; + case 5: +// gen_op_dmfc0_srsconf4(); /* shadow registers */ + rn = "SRSConf4"; +// break; + default: + goto die; + } + break; + case 7: + switch (sel) { + case 0: + gen_op_mfc0_hwrena(); + rn = "HWREna"; + break; + default: + goto die; + } + break; + case 8: + switch (sel) { + case 0: + gen_op_dmfc0_badvaddr(); + rn = "BadVaddr"; + break; + default: + goto die; + } + break; + case 9: + switch (sel) { + case 0: + gen_op_mfc0_count(); + rn = "Count"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } + break; + case 10: + switch (sel) { + case 0: + gen_op_dmfc0_entryhi(); + rn = "EntryHi"; + break; + default: + goto die; + } + break; + case 11: + switch (sel) { + case 0: + gen_op_mfc0_compare(); + rn = "Compare"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } + break; + case 12: + switch (sel) { + case 0: + gen_op_mfc0_status(); + rn = "Status"; + break; + case 1: + gen_op_mfc0_intctl(); + rn = "IntCtl"; + break; + case 2: + gen_op_mfc0_srsctl(); + rn = "SRSCtl"; + break; + case 3: + gen_op_mfc0_srsmap(); /* shadow registers */ + rn = "SRSMap"; + break; + default: + goto die; + } + break; + case 13: + switch (sel) { + case 0: + gen_op_mfc0_cause(); + rn = "Cause"; + break; + default: + goto die; + } + break; + case 14: + switch (sel) { + case 0: + gen_op_dmfc0_epc(); + rn = "EPC"; + break; + default: + goto die; + } + break; + case 15: + switch (sel) { + case 0: + gen_op_mfc0_prid(); + rn = "PRid"; + break; + case 1: + gen_op_dmfc0_ebase(); + rn = "EBase"; + break; + default: + goto die; + } + break; + case 16: + switch (sel) { + case 0: + gen_op_mfc0_config0(); + rn = "Config"; + break; + case 1: + gen_op_mfc0_config1(); + rn = "Config1"; + break; + case 2: + gen_op_mfc0_config2(); + rn = "Config2"; + break; + case 3: + gen_op_mfc0_config3(); + rn = "Config3"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } + break; + case 17: + switch (sel) { + case 0: + gen_op_dmfc0_lladdr(); + rn = "LLAddr"; + break; + default: + goto die; + } + break; + case 18: + switch (sel) { + case 0: + gen_op_dmfc0_watchlo0(); + rn = "WatchLo"; + break; + case 1: +// gen_op_dmfc0_watchlo1(); + rn = "WatchLo1"; +// break; + case 2: +// gen_op_dmfc0_watchlo2(); + rn = "WatchLo2"; +// break; + case 3: +// gen_op_dmfc0_watchlo3(); + rn = "WatchLo3"; +// break; + case 4: +// gen_op_dmfc0_watchlo4(); + rn = "WatchLo4"; +// break; + case 5: +// gen_op_dmfc0_watchlo5(); + rn = "WatchLo5"; +// break; + case 6: +// gen_op_dmfc0_watchlo6(); + rn = "WatchLo6"; +// break; + case 7: +// gen_op_dmfc0_watchlo7(); + rn = "WatchLo7"; +// break; + default: + goto die; + } + break; + case 19: + switch (sel) { + case 0: + gen_op_mfc0_watchhi0(); + rn = "WatchHi"; + break; + case 1: +// gen_op_mfc0_watchhi1(); + rn = "WatchHi1"; +// break; + case 2: +// gen_op_mfc0_watchhi2(); + rn = "WatchHi2"; +// break; + case 3: +// gen_op_mfc0_watchhi3(); + rn = "WatchHi3"; +// break; + case 4: +// gen_op_mfc0_watchhi4(); + rn = "WatchHi4"; +// break; + case 5: +// gen_op_mfc0_watchhi5(); + rn = "WatchHi5"; +// break; + case 6: +// gen_op_mfc0_watchhi6(); + rn = "WatchHi6"; +// break; + case 7: +// gen_op_mfc0_watchhi7(); + rn = "WatchHi7"; +// break; + default: + goto die; + } + break; + case 20: + switch (sel) { + case 0: + /* 64 bit MMU only */ + gen_op_dmfc0_xcontext(); + rn = "XContext"; + break; + default: + goto die; + } + break; + case 21: + /* Officially reserved, but sel 0 is used for R1x000 framemask */ + switch (sel) { + case 0: + gen_op_mfc0_framemask(); + rn = "Framemask"; + break; + default: + goto die; + } + break; + case 22: + /* ignored */ + rn = "'Diagnostic"; /* implementation dependent */ + break; + case 23: + switch (sel) { + case 0: + gen_op_mfc0_debug(); /* EJTAG support */ + rn = "Debug"; + break; + case 1: +// gen_op_dmfc0_tracecontrol(); /* PDtrace support */ + rn = "TraceControl"; +// break; + case 2: +// gen_op_dmfc0_tracecontrol2(); /* PDtrace support */ + rn = "TraceControl2"; +// break; + case 3: +// gen_op_dmfc0_usertracedata(); /* PDtrace support */ + rn = "UserTraceData"; +// break; + case 4: +// gen_op_dmfc0_debug(); /* PDtrace support */ + rn = "TraceBPC"; +// break; + default: + goto die; + } + break; + case 24: + switch (sel) { + case 0: + gen_op_dmfc0_depc(); /* EJTAG support */ + rn = "DEPC"; + break; + default: + goto die; + } + break; + case 25: + switch (sel) { + case 0: + gen_op_mfc0_performance0(); + rn = "Performance0"; + break; + case 1: +// gen_op_dmfc0_performance1(); + rn = "Performance1"; +// break; + case 2: +// gen_op_dmfc0_performance2(); + rn = "Performance2"; +// break; + case 3: +// gen_op_dmfc0_performance3(); + rn = "Performance3"; +// break; + case 4: +// gen_op_dmfc0_performance4(); + rn = "Performance4"; +// break; + case 5: +// gen_op_dmfc0_performance5(); + rn = "Performance5"; +// break; + case 6: +// gen_op_dmfc0_performance6(); + rn = "Performance6"; +// break; + case 7: +// gen_op_dmfc0_performance7(); + rn = "Performance7"; +// break; + default: + goto die; + } + break; + case 26: + rn = "ECC"; + break; + case 27: + switch (sel) { + /* ignored */ + case 0 ... 3: + rn = "CacheErr"; + break; + default: + goto die; + } + break; + case 28: + switch (sel) { + case 0: + case 2: + case 4: + case 6: + gen_op_mfc0_taglo(); + rn = "TagLo"; + break; + case 1: + case 3: + case 5: + case 7: + gen_op_mfc0_datalo(); + rn = "DataLo"; + break; + default: + goto die; + } + break; + case 29: + switch (sel) { + case 0: + case 2: + case 4: + case 6: + gen_op_mfc0_taghi(); + rn = "TagHi"; + break; + case 1: + case 3: + case 5: + case 7: + gen_op_mfc0_datahi(); + rn = "DataHi"; + break; + default: + goto die; + } + break; + case 30: + switch (sel) { + case 0: + gen_op_dmfc0_errorepc(); + rn = "ErrorEPC"; + break; + default: + goto die; + } + break; + case 31: + switch (sel) { + case 0: + gen_op_mfc0_desave(); /* EJTAG support */ + rn = "DESAVE"; + break; + default: + goto die; + } + break; + default: + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "dmfc0 %s (reg %d sel %d)\n", + rn, reg, sel); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "dmfc0 %s (reg %d sel %d)\n", + rn, reg, sel); + } +#endif + generate_exception(ctx, EXCP_RI); +} + +static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) +{ + const char *rn = "invalid"; + + switch (reg) { + case 0: + switch (sel) { + case 0: + gen_op_mtc0_index(); + rn = "Index"; + break; + case 1: +// gen_op_dmtc0_mvpcontrol(); /* MT ASE */ + rn = "MVPControl"; +// break; + case 2: +// gen_op_dmtc0_mvpconf0(); /* MT ASE */ + rn = "MVPConf0"; +// break; + case 3: +// gen_op_dmtc0_mvpconf1(); /* MT ASE */ + rn = "MVPConf1"; +// break; + default: + goto die; + } + break; + case 1: + switch (sel) { + case 0: + /* ignored */ + rn = "Random"; + break; + case 1: +// gen_op_dmtc0_vpecontrol(); /* MT ASE */ + rn = "VPEControl"; +// break; + case 2: +// gen_op_dmtc0_vpeconf0(); /* MT ASE */ + rn = "VPEConf0"; +// break; + case 3: +// gen_op_dmtc0_vpeconf1(); /* MT ASE */ + rn = "VPEConf1"; +// break; + case 4: +// gen_op_dmtc0_YQMask(); /* MT ASE */ + rn = "YQMask"; +// break; + case 5: +// gen_op_dmtc0_vpeschedule(); /* MT ASE */ + rn = "VPESchedule"; +// break; + case 6: +// gen_op_dmtc0_vpeschefback(); /* MT ASE */ + rn = "VPEScheFBack"; +// break; + case 7: +// gen_op_dmtc0_vpeopt(); /* MT ASE */ + rn = "VPEOpt"; +// break; + default: + goto die; + } + break; + case 2: + switch (sel) { + case 0: + gen_op_dmtc0_entrylo0(); + rn = "EntryLo0"; + break; + case 1: +// gen_op_dmtc0_tcstatus(); /* MT ASE */ + rn = "TCStatus"; +// break; + case 2: +// gen_op_dmtc0_tcbind(); /* MT ASE */ + rn = "TCBind"; +// break; + case 3: +// gen_op_dmtc0_tcrestart(); /* MT ASE */ + rn = "TCRestart"; +// break; + case 4: +// gen_op_dmtc0_tchalt(); /* MT ASE */ + rn = "TCHalt"; +// break; + case 5: +// gen_op_dmtc0_tccontext(); /* MT ASE */ + rn = "TCContext"; +// break; + case 6: +// gen_op_dmtc0_tcschedule(); /* MT ASE */ + rn = "TCSchedule"; +// break; + case 7: +// gen_op_dmtc0_tcschefback(); /* MT ASE */ + rn = "TCScheFBack"; +// break; + default: + goto die; + } + break; + case 3: + switch (sel) { + case 0: + gen_op_dmtc0_entrylo1(); + rn = "EntryLo1"; + break; + default: + goto die; + } + break; + case 4: + switch (sel) { + case 0: + gen_op_dmtc0_context(); + rn = "Context"; + break; + case 1: +// gen_op_dmtc0_contextconfig(); /* SmartMIPS ASE */ + rn = "ContextConfig"; +// break; + default: + goto die; + } + break; + case 5: + switch (sel) { + case 0: + gen_op_mtc0_pagemask(); + rn = "PageMask"; + break; + case 1: + gen_op_mtc0_pagegrain(); + rn = "PageGrain"; + break; + default: + goto die; + } + break; + case 6: + switch (sel) { + case 0: + gen_op_mtc0_wired(); + rn = "Wired"; + break; + case 1: +// gen_op_dmtc0_srsconf0(); /* shadow registers */ + rn = "SRSConf0"; +// break; + case 2: +// gen_op_dmtc0_srsconf1(); /* shadow registers */ + rn = "SRSConf1"; +// break; + case 3: +// gen_op_dmtc0_srsconf2(); /* shadow registers */ + rn = "SRSConf2"; +// break; + case 4: +// gen_op_dmtc0_srsconf3(); /* shadow registers */ + rn = "SRSConf3"; +// break; + case 5: +// gen_op_dmtc0_srsconf4(); /* shadow registers */ + rn = "SRSConf4"; +// break; + default: + goto die; + } + break; + case 7: + switch (sel) { + case 0: + gen_op_mtc0_hwrena(); + rn = "HWREna"; + break; + default: + goto die; + } + break; + case 8: + /* ignored */ + rn = "BadVaddr"; + break; + case 9: + switch (sel) { + case 0: + gen_op_mtc0_count(); + rn = "Count"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case 10: + switch (sel) { + case 0: + gen_op_mtc0_entryhi(); + rn = "EntryHi"; + break; + default: + goto die; + } + break; + case 11: + switch (sel) { + case 0: + gen_op_mtc0_compare(); + rn = "Compare"; + break; + /* 6,7 are implementation dependent */ + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case 12: + switch (sel) { + case 0: + gen_op_mtc0_status(); + rn = "Status"; + break; + case 1: + gen_op_mtc0_intctl(); + rn = "IntCtl"; + break; + case 2: + gen_op_mtc0_srsctl(); + rn = "SRSCtl"; + break; + case 3: + gen_op_mtc0_srsmap(); /* shadow registers */ + rn = "SRSMap"; + break; + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case 13: + switch (sel) { + case 0: + gen_op_mtc0_cause(); + rn = "Cause"; + break; + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case 14: + switch (sel) { + case 0: + gen_op_dmtc0_epc(); + rn = "EPC"; + break; + default: + goto die; + } + break; + case 15: + switch (sel) { + case 0: + /* ignored */ + rn = "PRid"; + break; + case 1: + gen_op_dmtc0_ebase(); + rn = "EBase"; + break; + default: + goto die; + } + break; + case 16: + switch (sel) { + case 0: + gen_op_mtc0_config0(); + rn = "Config"; + break; + case 1: + /* ignored */ + rn = "Config1"; + break; + case 2: + gen_op_mtc0_config2(); + rn = "Config2"; + break; + case 3: + /* ignored */ + rn = "Config3"; + break; + /* 6,7 are implementation dependent */ + default: + rn = "Invalid config selector"; + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case 17: + switch (sel) { + case 0: + /* ignored */ + rn = "LLAddr"; + break; + default: + goto die; + } + break; + case 18: + switch (sel) { + case 0: + gen_op_dmtc0_watchlo0(); + rn = "WatchLo"; + break; + case 1: +// gen_op_dmtc0_watchlo1(); + rn = "WatchLo1"; +// break; + case 2: +// gen_op_dmtc0_watchlo2(); + rn = "WatchLo2"; +// break; + case 3: +// gen_op_dmtc0_watchlo3(); + rn = "WatchLo3"; +// break; + case 4: +// gen_op_dmtc0_watchlo4(); + rn = "WatchLo4"; +// break; + case 5: +// gen_op_dmtc0_watchlo5(); + rn = "WatchLo5"; +// break; + case 6: +// gen_op_dmtc0_watchlo6(); + rn = "WatchLo6"; +// break; + case 7: +// gen_op_dmtc0_watchlo7(); + rn = "WatchLo7"; +// break; + default: + goto die; + } + break; + case 19: + switch (sel) { + case 0: + gen_op_mtc0_watchhi0(); + rn = "WatchHi"; + break; + case 1: +// gen_op_dmtc0_watchhi1(); + rn = "WatchHi1"; +// break; + case 2: +// gen_op_dmtc0_watchhi2(); + rn = "WatchHi2"; +// break; + case 3: +// gen_op_dmtc0_watchhi3(); + rn = "WatchHi3"; +// break; + case 4: +// gen_op_dmtc0_watchhi4(); + rn = "WatchHi4"; +// break; + case 5: +// gen_op_dmtc0_watchhi5(); + rn = "WatchHi5"; +// break; + case 6: +// gen_op_dmtc0_watchhi6(); + rn = "WatchHi6"; +// break; + case 7: +// gen_op_dmtc0_watchhi7(); + rn = "WatchHi7"; +// break; + default: + goto die; + } + break; + case 20: + switch (sel) { + case 0: + /* 64 bit MMU only */ + gen_op_dmtc0_xcontext(); + rn = "XContext"; + break; + default: + goto die; + } + break; + case 21: + /* Officially reserved, but sel 0 is used for R1x000 framemask */ + switch (sel) { + case 0: + gen_op_mtc0_framemask(); + rn = "Framemask"; + break; + default: + goto die; + } + break; + case 22: + /* ignored */ + rn = "Diagnostic"; /* implementation dependent */ + break; + case 23: + switch (sel) { + case 0: + gen_op_mtc0_debug(); /* EJTAG support */ + rn = "Debug"; + break; + case 1: +// gen_op_dmtc0_tracecontrol(); /* PDtrace support */ + rn = "TraceControl"; +// break; + case 2: +// gen_op_dmtc0_tracecontrol2(); /* PDtrace support */ + rn = "TraceControl2"; +// break; + case 3: +// gen_op_dmtc0_usertracedata(); /* PDtrace support */ + rn = "UserTraceData"; +// break; + case 4: +// gen_op_dmtc0_debug(); /* PDtrace support */ + rn = "TraceBPC"; +// break; + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + case 24: + switch (sel) { + case 0: + gen_op_dmtc0_depc(); /* EJTAG support */ + rn = "DEPC"; + break; + default: + goto die; + } + break; + case 25: + switch (sel) { + case 0: + gen_op_mtc0_performance0(); + rn = "Performance0"; + break; + case 1: +// gen_op_dmtc0_performance1(); + rn = "Performance1"; +// break; + case 2: +// gen_op_dmtc0_performance2(); + rn = "Performance2"; +// break; + case 3: +// gen_op_dmtc0_performance3(); + rn = "Performance3"; +// break; + case 4: +// gen_op_dmtc0_performance4(); + rn = "Performance4"; +// break; + case 5: +// gen_op_dmtc0_performance5(); + rn = "Performance5"; +// break; + case 6: +// gen_op_dmtc0_performance6(); + rn = "Performance6"; +// break; + case 7: +// gen_op_dmtc0_performance7(); + rn = "Performance7"; +// break; + default: + goto die; + } + break; + case 26: + /* ignored */ + rn = "ECC"; + break; + case 27: + switch (sel) { + case 0 ... 3: + /* ignored */ + rn = "CacheErr"; + break; + default: + goto die; + } + break; + case 28: + switch (sel) { + case 0: + case 2: + case 4: + case 6: + gen_op_mtc0_taglo(); + rn = "TagLo"; + break; + case 1: + case 3: + case 5: + case 7: + gen_op_mtc0_datalo(); + rn = "DataLo"; + break; + default: + goto die; + } + break; + case 29: + switch (sel) { + case 0: + case 2: + case 4: + case 6: + gen_op_mtc0_taghi(); + rn = "TagHi"; + break; + case 1: + case 3: + case 5: + case 7: + gen_op_mtc0_datahi(); + rn = "DataHi"; + break; + default: + rn = "invalid sel"; + goto die; + } + break; + case 30: + switch (sel) { + case 0: + gen_op_dmtc0_errorepc(); + rn = "ErrorEPC"; + break; + default: + goto die; + } + break; + case 31: + switch (sel) { + case 0: + gen_op_mtc0_desave(); /* EJTAG support */ + rn = "DESAVE"; + break; + default: + goto die; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + break; + default: + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "dmtc0 %s (reg %d sel %d)\n", + rn, reg, sel); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "dmtc0 %s (reg %d sel %d)\n", + rn, reg, sel); + } +#endif + generate_exception(ctx, EXCP_RI); +} + static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) { const char *opn = "unk"; @@ -2854,7 +4029,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) break; case OPC_MTC0: /* If we get an exception, we want to restart at next instruction */ - /* XXX: breaks for mtc in delay slot */ + /* XXX: breaks for mtc in delay slot */ ctx->pc += 4; save_cpu_state(ctx, 1); ctx->pc -= 4; @@ -2862,6 +4037,25 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) gen_mtc0(ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; break; + case OPC_DMFC0: + if (rt == 0) { + /* Treat as NOP */ + return; + } + gen_dmfc0(ctx, rd, ctx->opcode & 0x7); + gen_op_store_T0_gpr(rt); + opn = "dmfc0"; + break; + case OPC_DMTC0: + /* If we get an exception, we want to restart at next instruction */ + /* XXX: breaks for dmtc in delay slot */ + ctx->pc += 4; + save_cpu_state(ctx, 1); + ctx->pc -= 4; + GEN_LOAD_REG_TN(T0, rt); + gen_dmtc0(ctx, rd, ctx->opcode & 0x7); + opn = "dmtc0"; + break; #if defined(MIPS_USES_R4K_TLB) case OPC_TLBWI: gen_op_tlbwi(); @@ -3002,6 +4196,9 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) gen_op_ctc1(); opn = "ctc1"; break; + case OPC_DMFC1: + case OPC_DMTC1: + /* Not implemented, fallthrough. */ default: if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", @@ -3703,6 +4900,10 @@ static void decode_opc (DisasContext *ctx) case OPC_CFC1: case OPC_MTC1: case OPC_CTC1: +#ifdef MIPS_HAS_MIPS64 + case OPC_DMFC1: + case OPC_DMTC1: +#endif gen_cp1(ctx, op1, rt, rd); break; case OPC_BC1: @@ -4099,7 +5300,7 @@ void cpu_reset (CPUMIPSState *env) } env->PC = (int32_t)0xBFC00000; #if defined (MIPS_USES_R4K_TLB) - env->CP0_random = MIPS_TLB_NB - 1; + env->CP0_Random = MIPS_TLB_NB - 1; env->tlb_in_use = MIPS_TLB_NB; #endif env->CP0_Wired = 0; -- cgit v1.2.3 From 30c4bbace19e802979009cc5c16fb4e14dc6bda6 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Jan 2007 01:12:42 +0000 Subject: Fix DMA timeouts on FreeBSD, by Carlo Marcelo Arenas Belon. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2349 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index afa06f804..8c9b6e6dd 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2230,7 +2230,6 @@ static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb) return; bm->ide_if = s; bm->dma_cb = dma_cb; - bm->cur_addr = bm->addr; bm->cur_prd_last = 0; bm->cur_prd_addr = 0; bm->cur_prd_len = 0; @@ -2363,6 +2362,7 @@ static void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val) printf("%s: 0x%08x\n", __func__, val); #endif bm->addr = val & ~3; + bm->cur_addr = bm->addr; } static void bmdma_map(PCIDevice *pci_dev, int region_num, -- cgit v1.2.3 From 4de9b249d37c1b382cc3e5a21fad1b4a11cec2fa Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Jan 2007 01:47:51 +0000 Subject: Reworking MIPS interrupt handling, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2350 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- cpu-exec.c | 1 - hw/gt64xxx.c | 5 ++-- hw/i8259.c | 7 ++++++ hw/mips_int.c | 39 +++++++++++++++++++++++++++++++ hw/mips_malta.c | 10 ++------ hw/mips_r4k.c | 9 +------ hw/mips_timer.c | 6 ++--- target-mips/cpu.h | 1 + target-mips/exec.h | 1 + target-mips/op.c | 62 +++++++++---------------------------------------- target-mips/op_helper.c | 5 ++++ vl.h | 3 +++ 13 files changed, 76 insertions(+), 75 deletions(-) create mode 100644 hw/mips_int.c diff --git a/Makefile.target b/Makefile.target index ba8d5e99b..0deef0112 100644 --- a/Makefile.target +++ b/Makefile.target @@ -376,7 +376,7 @@ VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) -VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o dma.o vga.o serial.o i8254.o i8259.o +VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) DEFINES += -DHAS_AUDIO diff --git a/cpu-exec.c b/cpu-exec.c index f9a06e530..6662b3974 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -535,7 +535,6 @@ int cpu_exec(CPUState *env1) 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 diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index f3ff61381..84e041fcf 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -1,7 +1,7 @@ /* * QEMU GT64120 PCI host * - * Copyright (c) 2006 Aurelien Jarno + * Copyright (c) 2006,2007 Aurelien Jarno * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -433,7 +433,8 @@ static uint32_t gt64120_readl (void *opaque, val = s->regs[saddr]; break; case GT_PCI0_IACK: - val = pic_intack_read(isa_pic); + /* Read the IRQ number */ + val = pic_read_irq(isa_pic); break; /* SDRAM Parameters */ diff --git a/hw/i8259.c b/hw/i8259.c index c747f106e..f8b5a984b 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -161,6 +161,13 @@ void pic_update_irq(PicState2 *s) #endif s->irq_request(s->irq_request_opaque, 1); } + +/* all targets should do this rather than acking the IRQ in the cpu */ +#if defined(TARGET_MIPS) + else { + s->irq_request(s->irq_request_opaque, 0); + } +#endif } #ifdef DEBUG_IRQ_LATENCY diff --git a/hw/mips_int.c b/hw/mips_int.c new file mode 100644 index 000000000..93d599fc6 --- /dev/null +++ b/hw/mips_int.c @@ -0,0 +1,39 @@ +#include "vl.h" +#include "cpu.h" + +/* Raise IRQ to CPU if necessary. It must be called every time the active + IRQ may change */ +void cpu_mips_update_irq(CPUState *env) +{ + if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && + (env->CP0_Status & (1 << CP0St_IE)) && + !(env->hflags & MIPS_HFLAG_EXL) && + !(env->hflags & MIPS_HFLAG_ERL) && + !(env->hflags & MIPS_HFLAG_DM)) { + if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) { + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } + } else { + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + +void cpu_mips_irq_request(void *opaque, int irq, int level) +{ + CPUState *env = first_cpu; + + uint32_t mask; + + if (irq >= 16) + return; + + mask = 1 << (irq + CP0Ca_IP); + + if (level) { + env->CP0_Cause |= mask; + } else { + env->CP0_Cause &= ~mask; + } + cpu_mips_update_irq(env); +} + diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 12343e0ad..7ddf2fd17 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -54,16 +54,10 @@ typedef struct { static PITState *pit; +/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ static void pic_irq_request(void *opaque, int level) { - CPUState *env = first_cpu; - if (level) { - env->CP0_Cause |= 0x00000400; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - env->CP0_Cause &= ~0x00000400; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } + cpu_mips_irq_request(opaque, 2, level); } /* Malta FPGA */ diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index ffed67c2a..5fa5b76a6 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -38,14 +38,7 @@ static PITState *pit; /* PIT i8254 */ /*The PIC is attached to the MIPS CPU INT0 pin */ static void pic_irq_request(void *opaque, int level) { - CPUState *env = first_cpu; - if (level) { - env->CP0_Cause |= 0x00000400; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - env->CP0_Cause &= ~0x00000400; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } + cpu_mips_irq_request(opaque, 2, level); } static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 251324d7b..bc83036b3 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -57,8 +57,7 @@ void cpu_mips_store_count (CPUState *env, uint32_t value) void cpu_mips_store_compare (CPUState *env, uint32_t value) { cpu_mips_update_count(env, cpu_mips_get_count(env), value); - env->CP0_Cause &= ~0x00008000; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_mips_irq_request(env, 7, 0); } static void mips_timer_cb (void *opaque) @@ -72,8 +71,7 @@ static void mips_timer_cb (void *opaque) } #endif cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); - env->CP0_Cause |= 0x00008000; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_mips_irq_request(env, 7, 1); } void cpu_mips_clock_init (CPUState *env) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 8781e3098..3c99054d6 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -158,6 +158,7 @@ struct CPUMIPSState { #define CP0Ca_IV 23 #define CP0Ca_WP 22 #define CP0Ca_IP 8 +#define CP0Ca_IP_mask 0x0000FF00 #define CP0Ca_EC 2 target_ulong CP0_EPC; int32_t CP0_PRid; diff --git a/target-mips/exec.h b/target-mips/exec.h index 3d6bb7d60..15397b692 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -164,6 +164,7 @@ uint32_t cpu_mips_get_random (CPUState *env); uint32_t cpu_mips_get_count (CPUState *env); void cpu_mips_store_count (CPUState *env, uint32_t value); void cpu_mips_store_compare (CPUState *env, uint32_t value); +void cpu_mips_update_irq(CPUState *env); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); diff --git a/target-mips/op.c b/target-mips/op.c index dec9f31ad..9d30d03cd 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1357,7 +1357,7 @@ void op_mtc0_compare (void) void op_mtc0_status (void) { - uint32_t val, old, mask; + uint32_t val, old; val = (int32_t)T0 & 0xFA78FF01; old = env->CP0_Status; @@ -1374,21 +1374,9 @@ void op_mtc0_status (void) else env->hflags &= ~MIPS_HFLAG_EXL; env->CP0_Status = val; - /* If we unmasked an asserted IRQ, raise it */ - mask = 0x0000FF00; if (loglevel & CPU_LOG_TB_IN_ASM) CALL_FROM_TB2(do_mtc0_status_debug, old, val); - if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) && - !(env->hflags & MIPS_HFLAG_EXL) && - !(env->hflags & MIPS_HFLAG_ERL) && - !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Status & env->CP0_Cause & mask)) { - env->interrupt_request |= CPU_INTERRUPT_HARD; - if (logfile) - CALL_FROM_TB0(do_mtc0_status_irqraise_debug); - } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) { - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - } + CALL_FROM_TB1(cpu_mips_update_irq, env); RETURN(); } @@ -1415,22 +1403,13 @@ void op_mtc0_srsmap (void) void op_mtc0_cause (void) { - uint32_t val, old; + env->CP0_Cause = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300); - val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300); - old = env->CP0_Cause; - env->CP0_Cause = val; -#if 0 - { - int i, mask; - /* Check if we ever asserted a software IRQ */ - for (i = 0; i < 2; i++) { - mask = 0x100 << i; - if ((val & mask) & !(old & mask)) - CALL_FROM_TB1(mips_set_irq, i); - } + /* Handle the software interrupt as an hardware one, as they + are very similar */ + if (T0 & CP0Ca_IP_mask) { + CALL_FROM_TB1(cpu_mips_update_irq, env); } -#endif RETURN(); } @@ -2074,36 +2053,17 @@ void op_pmon (void) void op_di (void) { - uint32_t val; - T0 = env->CP0_Status; - val = T0 & ~(1 << CP0St_IE); - if (val != T0) { - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - env->CP0_Status = val; - } + env->CP0_Status = T0 & ~(1 << CP0St_IE); + CALL_FROM_TB1(cpu_mips_update_irq, env); RETURN(); } void op_ei (void) { - uint32_t val; - T0 = env->CP0_Status; - val = T0 | (1 << CP0St_IE); - if (val != T0) { - const uint32_t mask = 0x0000FF00; - - env->CP0_Status = val; - if (!(env->hflags & MIPS_HFLAG_EXL) && - !(env->hflags & MIPS_HFLAG_ERL) && - !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Status & env->CP0_Cause & mask)) { - env->interrupt_request |= CPU_INTERRUPT_HARD; - if (logfile) - CALL_FROM_TB0(do_mtc0_status_irqraise_debug); - } - } + env->CP0_Status = T0 | (1 << CP0St_IE); + CALL_FROM_TB1(cpu_mips_update_irq, env); RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index bea5a905e..9596d04fb 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -265,6 +265,11 @@ void cpu_mips_store_compare(CPUState *env, uint32_t value) cpu_abort(env, "mtc0 compare\n"); } +void cpu_mips_update_irq(CPUState *env) +{ + cpu_abort(env, "mtc0 status / mtc0 cause\n"); +} + void do_mtc0_status_debug(uint32_t old, uint32_t val) { cpu_abort(env, "mtc0 status debug\n"); diff --git a/vl.h b/vl.h index 543eb722c..92b1d253a 100644 --- a/vl.h +++ b/vl.h @@ -1067,6 +1067,9 @@ extern QEMUMachine mips_machine; /* mips_malta.c */ extern QEMUMachine mips_malta_machine; +/* mips_int */ +extern void cpu_mips_irq_request(void *opaque, int irq, int level); + /* mips_timer.c */ extern void cpu_mips_clock_init(CPUState *); extern void cpu_mips_irqctrl_init (void); -- cgit v1.2.3 From b29a0341d7ed7e7df4bf77a41db8e614f1ddb645 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Jan 2007 18:01:23 +0000 Subject: EBase is limited to KSEG0/KSEG1 even on 64bit CPUs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2351 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 2 +- target-mips/op.c | 19 ++----------------- target-mips/translate.c | 6 +++--- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 3c99054d6..fb5a3fef3 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -162,7 +162,7 @@ struct CPUMIPSState { #define CP0Ca_EC 2 target_ulong CP0_EPC; int32_t CP0_PRid; - target_ulong CP0_EBase; + int32_t CP0_EBase; int32_t CP0_Config0; #define CP0C0_M 31 #define CP0C0_K23 28 diff --git a/target-mips/op.c b/target-mips/op.c index 9d30d03cd..cd5c69ca4 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1158,7 +1158,7 @@ void op_mfc0_prid (void) void op_mfc0_ebase (void) { - T0 = (int32_t)env->CP0_EBase; + T0 = env->CP0_EBase; RETURN(); } @@ -1423,7 +1423,7 @@ void op_mtc0_ebase (void) { /* vectored interrupts not implemented */ /* Multi-CPU not implemented */ - env->CP0_EBase = (int32_t)0x80000000 | (T0 & 0x3FFFF000); + env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000); RETURN(); } @@ -1563,12 +1563,6 @@ void op_dmfc0_epc (void) RETURN(); } -void op_dmfc0_ebase (void) -{ - T0 = env->CP0_EBase; - RETURN(); -} - void op_dmfc0_lladdr (void) { T0 = env->CP0_LLAddr >> 4; @@ -1627,15 +1621,6 @@ void op_dmtc0_epc (void) RETURN(); } -void op_dmtc0_ebase (void) -{ - /* vectored interrupts not implemented */ - /* Multi-CPU not implemented */ - /* XXX: 64bit addressing broken */ - env->CP0_EBase = (int32_t)0x80000000 | (T0 & 0x3FFFF000); - RETURN(); -} - void op_dmtc0_watchlo0 (void) { env->CP0_WatchLo = T0; diff --git a/target-mips/translate.c b/target-mips/translate.c index 3cc8a55d4..ce56bb083 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -3099,7 +3099,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: - gen_op_dmfc0_ebase(); + gen_op_mfc0_ebase(); rn = "EBase"; break; default: @@ -3683,7 +3683,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: - gen_op_dmtc0_ebase(); + gen_op_mtc0_ebase(); rn = "EBase"; break; default: @@ -5305,7 +5305,7 @@ void cpu_reset (CPUMIPSState *env) #endif env->CP0_Wired = 0; /* SMP not implemented */ - env->CP0_EBase = (int32_t)0x80000000; + env->CP0_EBase = 0x80000000; env->CP0_Config0 = MIPS_CONFIG0; env->CP0_Config1 = MIPS_CONFIG1; env->CP0_Config2 = MIPS_CONFIG2; -- cgit v1.2.3 From 5f4da8c0f3736b23744c27bf327d012480293b02 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Jan 2007 21:05:24 +0000 Subject: New multiple snapshot support for VMDK, by Igor Lvovsky. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2352 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vmdk.c | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 353 insertions(+), 45 deletions(-) diff --git a/block-vmdk.c b/block-vmdk.c index 8279d6696..28df8ae46 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -22,6 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include "vl.h" #include "block_int.h" @@ -59,7 +60,7 @@ typedef struct { #define L2_CACHE_SIZE 16 typedef struct BDRVVmdkState { - int fd; + BlockDriverState *hd; int64_t l1_table_offset; int64_t l1_backup_table_offset; uint32_t *l1_table; @@ -73,6 +74,7 @@ typedef struct BDRVVmdkState { uint32_t l2_cache_counts[L2_CACHE_SIZE]; unsigned int cluster_sectors; + uint32_t parent_cid; } BDRVVmdkState; static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) @@ -89,27 +91,278 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) +#define CHECK_CID 1 + +#define SECTOR_SIZE 512 +#define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each +#define HEADER_SIZE 512 // first sector of 512 bytes + +static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) { BDRVVmdkState *s = bs->opaque; - int fd, i; - uint32_t magic; - int l1_size; + char desc[DESC_SIZE]; + uint32_t cid; + char *p_name, *cid_str; + size_t cid_str_size; + + /* the descriptor offset = 0x200 */ + if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) + return 0; + + if (parent) { + cid_str = "parentCID"; + cid_str_size = sizeof("parentCID"); + } else { + cid_str = "CID"; + cid_str_size = sizeof("CID"); + } + + if ((p_name = strstr(desc,cid_str)) != 0) { + p_name += cid_str_size; + sscanf(p_name,"%x",&cid); + } + + return cid; +} + +static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) +{ + BDRVVmdkState *s = bs->opaque; + char desc[DESC_SIZE], tmp_desc[DESC_SIZE]; + char *p_name, *tmp_str; + + /* the descriptor offset = 0x200 */ + if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) + return -1; + + tmp_str = strstr(desc,"parentCID"); + strcpy(tmp_desc, tmp_str); + if ((p_name = strstr(desc,"CID")) != 0) { + p_name += sizeof("CID"); + sprintf(p_name,"%x\n",cid); + strcat(desc,tmp_desc); + } + + if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) + return -1; + return 0; +} + +static int vmdk_is_cid_valid(BlockDriverState *bs) +{ +#ifdef CHECK_CID + BDRVVmdkState *s = bs->opaque; + BlockDriverState *p_bs = s->hd->backing_hd; + uint32_t cur_pcid; + + if (p_bs) { + cur_pcid = vmdk_read_cid(p_bs,0); + if (s->parent_cid != cur_pcid) + // CID not valid + return 0; + } +#endif + // CID valid + return 1; +} + +static int vmdk_snapshot_create(const char *filename, const char *backing_file) +{ + int snp_fd, p_fd; + uint32_t p_cid; + char *p_name, *gd_buf, *rgd_buf; + const char *real_filename, *temp_str; + VMDK4Header header; + uint32_t gde_entries, gd_size; + int64_t gd_offset, rgd_offset, capacity, gt_size; + char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE]; + char *desc_template = + "# Disk DescriptorFile\n" + "version=1\n" + "CID=%x\n" + "parentCID=%x\n" + "createType=\"monolithicSparse\"\n" + "parentFileNameHint=\"%s\"\n" + "\n" + "# Extent description\n" + "RW %lu SPARSE \"%s\"\n" + "\n" + "# The Disk Data Base \n" + "#DDB\n" + "\n"; + + snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644); + if (snp_fd < 0) + return -1; + p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE); + if (p_fd < 0) { + close(snp_fd); + return -1; + } + + /* read the header */ + if (lseek(p_fd, 0x0, SEEK_SET) == -1) + goto fail; + if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) + goto fail; + + /* write the header */ + if (lseek(snp_fd, 0x0, SEEK_SET) == -1) + goto fail; + if (write(snp_fd, hdr, HEADER_SIZE) == -1) + goto fail; + + memset(&header, 0, sizeof(header)); + memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC + + ftruncate(snp_fd, header.grain_offset << 9); + /* the descriptor offset = 0x200 */ + if (lseek(p_fd, 0x200, SEEK_SET) == -1) + goto fail; + if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) + goto fail; + + if ((p_name = strstr(p_desc,"CID")) != 0) { + p_name += sizeof("CID"); + sscanf(p_name,"%x",&p_cid); + } + + 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(s_desc, desc_template, p_cid, p_cid, backing_file + , (uint32_t)header.capacity, real_filename); + + /* write the descriptor */ + if (lseek(snp_fd, 0x200, SEEK_SET) == -1) + goto fail; + if (write(snp_fd, s_desc, strlen(s_desc)) == -1) + goto fail; - fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); - if (fd < 0) { - fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) + gd_offset = header.gd_offset * SECTOR_SIZE; // offset of GD table + rgd_offset = header.rgd_offset * SECTOR_SIZE; // offset of RGD table + capacity = header.capacity * SECTOR_SIZE; // Extent size + /* + * Each GDE span 32M disk, means: + * 512 GTE per GT, each GTE points to grain + */ + gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE; + if (!gt_size) + goto fail; + gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde + gd_size = gde_entries * sizeof(uint32_t); + + /* write RGD */ + rgd_buf = qemu_malloc(gd_size); + if (!rgd_buf) + goto fail; + if (lseek(p_fd, rgd_offset, SEEK_SET) == -1) + goto fail_rgd; + if (read(p_fd, rgd_buf, gd_size) != gd_size) + goto fail_rgd; + if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) + goto fail_rgd; + if (write(snp_fd, rgd_buf, gd_size) == -1) + goto fail_rgd; + qemu_free(rgd_buf); + + /* write GD */ + gd_buf = qemu_malloc(gd_size); + if (!gd_buf) + goto fail_rgd; + if (lseek(p_fd, gd_offset, SEEK_SET) == -1) + goto fail_gd; + if (read(p_fd, gd_buf, gd_size) != gd_size) + goto fail_gd; + if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) + goto fail_gd; + if (write(snp_fd, gd_buf, gd_size) == -1) + goto fail_gd; + qemu_free(gd_buf); + + close(p_fd); + close(snp_fd); + return 0; + + fail_gd: + qemu_free(gd_buf); + fail_rgd: + qemu_free(rgd_buf); + fail: + close(p_fd); + close(snp_fd); + return -1; +} + +static void vmdk_parent_close(BlockDriverState *bs) +{ + if (bs->backing_hd) + bdrv_close(bs->backing_hd); +} + + +static int vmdk_parent_open(BlockDriverState *bs, const char * filename) +{ + BDRVVmdkState *s = bs->opaque; + char *p_name; + char desc[DESC_SIZE]; + char parent_img_name[1024]; + + /* the descriptor offset = 0x200 */ + if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) + return -1; + + if ((p_name = strstr(desc,"parentFileNameHint")) != 0) { + char *end_name; + struct stat file_buf; + + p_name += sizeof("parentFileNameHint") + 1; + if ((end_name = strchr(p_name,'\"')) == 0) + return -1; + + strncpy(s->hd->backing_file, p_name, end_name - p_name); + if (stat(s->hd->backing_file, &file_buf) != 0) { + path_combine(parent_img_name, sizeof(parent_img_name), + filename, s->hd->backing_file); + } else { + strcpy(parent_img_name, s->hd->backing_file); + } + + s->hd->backing_hd = bdrv_new(""); + if (!s->hd->backing_hd) { + failure: + bdrv_close(s->hd); return -1; - bs->read_only = 1; + } + if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0) + goto failure; } - if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) + + return 0; +} + +static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVVmdkState *s = bs->opaque; + uint32_t magic; + int l1_size, i, ret; + + ret = bdrv_file_open(&s->hd, filename, flags); + if (ret < 0) + return ret; + if (bdrv_pread(s->hd, 0, &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)) + + if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header)) goto fail; s->cluster_sectors = le32_to_cpu(header.granularity); s->l2_size = 1 << 9; @@ -120,8 +373,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) 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)) + + if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header)) goto fail; bs->total_sectors = le64_to_cpu(header.capacity); s->cluster_sectors = le64_to_cpu(header.granularity); @@ -133,17 +386,22 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) / 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; + + // try to open parent images, if exist + if (vmdk_parent_open(bs, filename) != 0) + goto fail; + // write the CID once after the image creation + s->parent_cid = vmdk_read_cid(bs,1); } 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) + if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size) goto fail; for(i = 0; i < s->l1_size; i++) { le32_to_cpus(&s->l1_table[i]); @@ -153,9 +411,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) 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) + if (bdrv_pread(s->hd, s->l1_backup_table_offset, 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]); @@ -165,16 +421,43 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) 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); + bdrv_delete(s->hd); return -1; } +static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate); + +static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, + uint64_t offset, int allocate) +{ + uint64_t parent_cluster_offset; + BDRVVmdkState *s = bs->opaque; + uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB + + // we will be here if it's first write on non-exist grain(cluster). + // try to read from parent image, if exist + if (s->hd->backing_hd) { + BDRVVmdkState *ps = s->hd->backing_hd->opaque; + + if (!vmdk_is_cid_valid(bs)) + return -1; + parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, allocate); + if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != + ps->cluster_sectors*512) + return -1; + + if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, sizeof(whole_grain)) != + sizeof(whole_grain)) + return -1; + } + return 0; +} + static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate) { @@ -212,34 +495,41 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, } } 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)) + if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, 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) { + struct stat file_buf; + if (!allocate) return 0; - cluster_offset = lseek(s->fd, 0, SEEK_END); - ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9)); + stat(s->hd->filename, &file_buf); + cluster_offset = file_buf.st_size; + bdrv_truncate(s->hd, 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)) + if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), + &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)) + if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), + &tmp, sizeof(tmp)) != sizeof(tmp)) return 0; } + + if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1) + return 0; } cluster_offset <<= 9; return cluster_offset; @@ -265,9 +555,9 @@ 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; + int index_in_cluster, n, ret; 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; @@ -275,11 +565,18 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, if (n > nb_sectors) n = nb_sectors; if (!cluster_offset) { - memset(buf, 0, 512 * n); + // try to read from parent image, if exist + if (s->hd->backing_hd) { + if (!vmdk_is_cid_valid(bs)) + return -1; + ret = bdrv_read(s->hd->backing_hd, sector_num, buf, n); + if (ret < 0) + return -1; + } else { + 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) + if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) return -1; } nb_sectors -= n; @@ -293,8 +590,9 @@ 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; + int index_in_cluster, n; uint64_t cluster_offset; + static int cid_update = 0; while (nb_sectors > 0) { index_in_cluster = sector_num & (s->cluster_sectors - 1); @@ -304,13 +602,17 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, 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) + if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) return -1; nb_sectors -= n; sector_num += n; buf += n * 512; + + // update CID on the first write every time the virtual disk is opened + if (!cid_update) { + vmdk_write_cid(bs, time(NULL)); + cid_update++; + } } return 0; } @@ -334,7 +636,7 @@ static int vmdk_create(const char *filename, int64_t total_size, "# The Disk Data Base \n" "#DDB\n" "\n" - "ddb.virtualHWVersion = \"3\"\n" + "ddb.virtualHWVersion = \"4\"\n" "ddb.geometry.cylinders = \"%lu\"\n" "ddb.geometry.heads = \"16\"\n" "ddb.geometry.sectors = \"63\"\n" @@ -343,6 +645,9 @@ static int vmdk_create(const char *filename, int64_t total_size, const char *real_filename, *temp_str; /* XXX: add support for backing file */ + if (backing_file) { + return vmdk_snapshot_create(filename, backing_file); + } fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644); @@ -421,15 +726,18 @@ static int vmdk_create(const char *filename, int64_t total_size, static void vmdk_close(BlockDriverState *bs) { BDRVVmdkState *s = bs->opaque; + qemu_free(s->l1_table); qemu_free(s->l2_cache); - close(s->fd); + bdrv_delete(s->hd); + // try to close parent image, if exist + vmdk_parent_close(s->hd); } static void vmdk_flush(BlockDriverState *bs) { BDRVVmdkState *s = bs->opaque; - fsync(s->fd); + bdrv_flush(s->hd); } BlockDriver bdrv_vmdk = { -- cgit v1.2.3 From e6a71ae327a388723182a504bb253777ec36869b Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Jan 2007 21:35:22 +0000 Subject: Add support for 82371FB (Step A1) and Improved support for 82371SB (Function 1), by Carlo Marcelo Arenas Belon. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2353 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/piix_pci.c | 27 +++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 8c9b6e6dd..190f07493 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2577,6 +2577,55 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) return 0; } +static void piix3_reset(PCIIDEState *d) +{ + uint8_t *pci_conf = d->dev.config; + + pci_conf[0x04] = 0x00; + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x80; /* FBC */ + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium + pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */ +} + +void pci_piix_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) +{ + PCIIDEState *d; + uint8_t *pci_conf; + + /* register a function 1 of PIIX */ + d = (PCIIDEState *)pci_register_device(bus, "PIIX IDE", + sizeof(PCIIDEState), + devfn, + NULL, NULL); + d->type = IDE_TYPE_PIIX3; + + pci_conf = d->dev.config; + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x30; + pci_conf[0x03] = 0x12; + pci_conf[0x08] = 0x02; // Step A1 + pci_conf[0x09] = 0x80; // legacy ATA mode + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE + pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage + pci_conf[0x0e] = 0x00; // header_type + + piix3_reset(d); + + pci_register_io_region((PCIDevice *)d, 4, 0x10, + PCI_ADDRESS_SPACE_IO, bmdma_map); + + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], + pic_set_irq_new, isa_pic, 14); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], + pic_set_irq_new, isa_pic, 15); + ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); + ide_init_ioport(&d->ide_if[2], 0x170, 0x376); + + register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); +} + /* hd_table must contain 4 block drivers */ /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) @@ -2601,6 +2650,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage pci_conf[0x0e] = 0x00; // header_type + piix3_reset(d); + pci_register_io_region((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, bmdma_map); diff --git a/hw/piix_pci.c b/hw/piix_pci.c index b2b7bf0cc..1b16652bc 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -246,7 +246,6 @@ static void piix3_reset(PCIDevice *d) pci_conf[0x80] = 0x00; pci_conf[0x82] = 0x00; pci_conf[0xa0] = 0x08; - pci_conf[0xa0] = 0x08; pci_conf[0xa2] = 0x00; pci_conf[0xa3] = 0x00; pci_conf[0xa4] = 0x00; @@ -284,7 +283,6 @@ static void piix4_reset(PCIDevice *d) pci_conf[0x80] = 0x00; pci_conf[0x82] = 0x00; pci_conf[0xa0] = 0x08; - pci_conf[0xa0] = 0x08; pci_conf[0xa2] = 0x00; pci_conf[0xa3] = 0x00; pci_conf[0xa4] = 0x00; @@ -312,6 +310,31 @@ static int piix_load(QEMUFile* f, void *opaque, int version_id) return pci_device_load(d, f); } +int piix_init(PCIBus *bus, int devfn) +{ + PCIDevice *d; + uint8_t *pci_conf; + + d = pci_register_device(bus, "PIIX", sizeof(PCIDevice), + devfn, NULL, NULL); + register_savevm("PIIX", 0, 2, piix_save, piix_load, d); + + piix3_dev = d; + pci_conf = d->config; + + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x2E; // 82371FB PIIX PCI-to-ISA bridge + pci_conf[0x03] = 0x12; + pci_conf[0x08] = 0x02; // Step A1 + pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA + pci_conf[0x0b] = 0x06; // class_base = PCI_bridge + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic + + piix3_reset(d); + return d->devfn; +} + int piix3_init(PCIBus *bus, int devfn) { PCIDevice *d; -- cgit v1.2.3 From 6070dd07e91bc8621e506e80057bd07b5c76c970 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Jan 2007 21:40:21 +0000 Subject: Split out SDL X keymap, by Bernhard Fischer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2354 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- sdl.c | 84 +------------------------------------------ vl.h | 3 ++ x_keymap.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 84 deletions(-) create mode 100644 x_keymap.c diff --git a/Makefile.target b/Makefile.target index 0deef0112..ca6cd9600 100644 --- a/Makefile.target +++ b/Makefile.target @@ -406,7 +406,7 @@ ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o endif ifdef CONFIG_SDL -VL_OBJS+=sdl.o +VL_OBJS+=sdl.o x_keymap.o endif VL_OBJS+=vnc.o ifdef CONFIG_COCOA diff --git a/sdl.c b/sdl.c index 5ec0f67ef..87ad3903c 100644 --- a/sdl.c +++ b/sdl.c @@ -122,88 +122,6 @@ static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) #else -static const uint8_t x_keycode_to_pc_keycode[115] = { - 0xc7, /* 97 Home */ - 0xc8, /* 98 Up */ - 0xc9, /* 99 PgUp */ - 0xcb, /* 100 Left */ - 0x4c, /* 101 KP-5 */ - 0xcd, /* 102 Right */ - 0xcf, /* 103 End */ - 0xd0, /* 104 Down */ - 0xd1, /* 105 PgDn */ - 0xd2, /* 106 Ins */ - 0xd3, /* 107 Del */ - 0x9c, /* 108 Enter */ - 0x9d, /* 109 Ctrl-R */ - 0x0, /* 110 Pause */ - 0xb7, /* 111 Print */ - 0xb5, /* 112 Divide */ - 0xb8, /* 113 Alt-R */ - 0xc6, /* 114 Break */ - 0x0, /* 115 */ - 0x0, /* 116 */ - 0x0, /* 117 */ - 0x0, /* 118 */ - 0x0, /* 119 */ - 0x0, /* 120 */ - 0x0, /* 121 */ - 0x0, /* 122 */ - 0x0, /* 123 */ - 0x0, /* 124 */ - 0x0, /* 125 */ - 0x0, /* 126 */ - 0x0, /* 127 */ - 0x0, /* 128 */ - 0x79, /* 129 Henkan */ - 0x0, /* 130 */ - 0x7b, /* 131 Muhenkan */ - 0x0, /* 132 */ - 0x7d, /* 133 Yen */ - 0x0, /* 134 */ - 0x0, /* 135 */ - 0x47, /* 136 KP_7 */ - 0x48, /* 137 KP_8 */ - 0x49, /* 138 KP_9 */ - 0x4b, /* 139 KP_4 */ - 0x4c, /* 140 KP_5 */ - 0x4d, /* 141 KP_6 */ - 0x4f, /* 142 KP_1 */ - 0x50, /* 143 KP_2 */ - 0x51, /* 144 KP_3 */ - 0x52, /* 145 KP_0 */ - 0x53, /* 146 KP_. */ - 0x47, /* 147 KP_HOME */ - 0x48, /* 148 KP_UP */ - 0x49, /* 149 KP_PgUp */ - 0x4b, /* 150 KP_Left */ - 0x4c, /* 151 KP_ */ - 0x4d, /* 152 KP_Right */ - 0x4f, /* 153 KP_End */ - 0x50, /* 154 KP_Down */ - 0x51, /* 155 KP_PgDn */ - 0x52, /* 156 KP_Ins */ - 0x53, /* 157 KP_Del */ - 0x0, /* 158 */ - 0x0, /* 159 */ - 0x0, /* 160 */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 170 */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 180 */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 190 */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 200 */ - 0x0, /* 201 */ - 0x0, /* 202 */ - 0x0, /* 203 */ - 0x0, /* 204 */ - 0x0, /* 205 */ - 0x0, /* 206 */ - 0x0, /* 207 */ - 0x70, /* 208 Hiragana_Katakana */ - 0x0, /* 209 */ - 0x0, /* 210 */ - 0x73, /* 211 backslash */ -}; - static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) { int keycode; @@ -216,7 +134,7 @@ static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) keycode -= 8; /* just an offset */ } else if (keycode < 212) { /* use conversion table */ - keycode = x_keycode_to_pc_keycode[keycode - 97]; + keycode = _translate_keycode(keycode - 97); } else { keycode = 0; } diff --git a/vl.h b/vl.h index 92b1d253a..5a99ed53b 100644 --- a/vl.h +++ b/vl.h @@ -908,6 +908,9 @@ void cocoa_display_init(DisplayState *ds, int full_screen); /* vnc.c */ void vnc_display_init(DisplayState *ds, const char *display); +/* x_keymap.c */ +extern uint8_t _translate_keycode(const int key); + /* ide.c */ #define MAX_DISKS 4 diff --git a/x_keymap.c b/x_keymap.c new file mode 100644 index 000000000..9f72fc3eb --- /dev/null +++ b/x_keymap.c @@ -0,0 +1,110 @@ +/* + * QEMU SDL display 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" +static const uint8_t x_keycode_to_pc_keycode[115] = { + 0xc7, /* 97 Home */ + 0xc8, /* 98 Up */ + 0xc9, /* 99 PgUp */ + 0xcb, /* 100 Left */ + 0x4c, /* 101 KP-5 */ + 0xcd, /* 102 Right */ + 0xcf, /* 103 End */ + 0xd0, /* 104 Down */ + 0xd1, /* 105 PgDn */ + 0xd2, /* 106 Ins */ + 0xd3, /* 107 Del */ + 0x9c, /* 108 Enter */ + 0x9d, /* 109 Ctrl-R */ + 0x0, /* 110 Pause */ + 0xb7, /* 111 Print */ + 0xb5, /* 112 Divide */ + 0xb8, /* 113 Alt-R */ + 0xc6, /* 114 Break */ + 0x0, /* 115 */ + 0x0, /* 116 */ + 0x0, /* 117 */ + 0x0, /* 118 */ + 0x0, /* 119 */ + 0x0, /* 120 */ + 0x0, /* 121 */ + 0x0, /* 122 */ + 0x0, /* 123 */ + 0x0, /* 124 */ + 0x0, /* 125 */ + 0x0, /* 126 */ + 0x0, /* 127 */ + 0x0, /* 128 */ + 0x79, /* 129 Henkan */ + 0x0, /* 130 */ + 0x7b, /* 131 Muhenkan */ + 0x0, /* 132 */ + 0x7d, /* 133 Yen */ + 0x0, /* 134 */ + 0x0, /* 135 */ + 0x47, /* 136 KP_7 */ + 0x48, /* 137 KP_8 */ + 0x49, /* 138 KP_9 */ + 0x4b, /* 139 KP_4 */ + 0x4c, /* 140 KP_5 */ + 0x4d, /* 141 KP_6 */ + 0x4f, /* 142 KP_1 */ + 0x50, /* 143 KP_2 */ + 0x51, /* 144 KP_3 */ + 0x52, /* 145 KP_0 */ + 0x53, /* 146 KP_. */ + 0x47, /* 147 KP_HOME */ + 0x48, /* 148 KP_UP */ + 0x49, /* 149 KP_PgUp */ + 0x4b, /* 150 KP_Left */ + 0x4c, /* 151 KP_ */ + 0x4d, /* 152 KP_Right */ + 0x4f, /* 153 KP_End */ + 0x50, /* 154 KP_Down */ + 0x51, /* 155 KP_PgDn */ + 0x52, /* 156 KP_Ins */ + 0x53, /* 157 KP_Del */ + 0x0, /* 158 */ + 0x0, /* 159 */ + 0x0, /* 160 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 170 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 180 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 190 */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 200 */ + 0x0, /* 201 */ + 0x0, /* 202 */ + 0x0, /* 203 */ + 0x0, /* 204 */ + 0x0, /* 205 */ + 0x0, /* 206 */ + 0x0, /* 207 */ + 0x70, /* 208 Hiragana_Katakana */ + 0x0, /* 209 */ + 0x0, /* 210 */ + 0x73, /* 211 backslash */ +}; + +uint8_t _translate_keycode(const int key) +{ + return x_keycode_to_pc_keycode[key]; +} -- cgit v1.2.3 From 44cbbf18b946030d7445a324aa42f624031b0639 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Jan 2007 22:00:13 +0000 Subject: Fix malta emulation for 64bit qemu. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2355 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 25 ++++++++++++++++--------- hw/mips_r4k.c | 8 ++++---- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 7ddf2fd17..c37c36084 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -24,16 +24,21 @@ #include "vl.h" -#define BIOS_FILENAME "mips_bios.bin" +#ifdef TARGET_WORDS_BIGENDIAN +#define BIOS_FILENAME "mips_bios.bin" +#else +#define BIOS_FILENAME "mipsel_bios.bin" +#endif + #ifdef MIPS_HAS_MIPS64 -#define INITRD_LOAD_ADDR (uint64_t)0x80800000 -#define ENVP_ADDR (uint64_t)0x80002000 +#define INITRD_LOAD_ADDR (int64_t)0x80800000 +#define ENVP_ADDR (int64_t)0x80002000 #else -#define INITRD_LOAD_ADDR (uint32_t)0x80800000 -#define ENVP_ADDR (uint32_t)0x80002000 +#define INITRD_LOAD_ADDR (int32_t)0x80800000 +#define ENVP_ADDR (int32_t)0x80002000 #endif -#define VIRT_TO_PHYS_ADDEND (-((uint64_t)(uint32_t)0x80000000)) +#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) #define ENVP_NB_ENTRIES 16 #define ENVP_ENTRY_SIZE 256 @@ -156,7 +161,8 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) default: #if 0 - printf ("malta_fpga_read: Bad register offset 0x%x\n", (int)addr); + printf ("malta_fpga_read: Bad register offset 0x" TLSZ "\n", + addr); #endif break; } @@ -239,7 +245,8 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, default: #if 0 - printf ("malta_fpga_write: Bad register offset 0x%x\n", (int)addr); + printf ("malta_fpga_write: Bad register offset 0x" TLSZ "\n", + addr); #endif break; } @@ -458,7 +465,7 @@ static int64_t load_kernel (CPUState *env) /* Store command line. */ prom_set(index++, env->kernel_filename); if (initrd_size > 0) - prom_set(index++, "rd_start=0x%08x rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline); + prom_set(index++, "rd_start=0x" TLSZ " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline); else prom_set(index++, env->kernel_cmdline); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 5fa5b76a6..8d1cac939 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -14,7 +14,7 @@ #else #define BIOS_FILENAME "mipsel_bios.bin" #endif -//#define BIOS_FILENAME "system.bin" + #ifdef MIPS_HAS_MIPS64 #define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000 #else @@ -112,8 +112,8 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); } - *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); - *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); + *(int32_t *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); + *(int32_t *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); } static void main_cpu_reset(void *opaque) @@ -159,7 +159,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); bios_size = load_image(buf, phys_ram_base + bios_offset); if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) { - cpu_register_physical_memory((uint32_t)(0x1fc00000), + cpu_register_physical_memory(0x1fc00000, BIOS_SIZE, bios_offset | IO_MEM_ROM); } else { /* not fatal */ -- cgit v1.2.3 From df5cf721605327427e4c033f75fd0875486c109f Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Jan 2007 22:56:36 +0000 Subject: Make the tarball's VERSION part overridable from make invocation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2356 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 77c523727..0f608111b 100644 --- a/Makefile +++ b/Makefile @@ -128,7 +128,8 @@ dvi: qemu-doc.dvi qemu-tech.dvi html: qemu-doc.html qemu-tech.html -FILE=qemu-$(shell cat VERSION) +VERSION ?= $(shell cat VERSION) +FILE = qemu-$(VERSION) # tar release (use 'make -k tar' on a checkouted tree) tar: -- cgit v1.2.3 From 71c2fd5cdfa1106e109c2554d511bdb3bcdccb05 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 26 Jan 2007 15:37:46 +0000 Subject: Define ENOMEDIUM to match ENODEV if it isn't available. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2357 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 4 ---- vl.h | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index dfa1edc3c..9264e42a6 100644 --- a/block.c +++ b/block.c @@ -35,10 +35,6 @@ #define SECTOR_BITS 9 #define SECTOR_SIZE (1 << SECTOR_BITS) -#ifndef ENOMEDIUM -#define ENOMEDIUM ENODEV -#endif - typedef struct BlockDriverAIOCBSync { BlockDriverAIOCB common; QEMUBH *bh; diff --git a/vl.h b/vl.h index 5a99ed53b..c0df57955 100644 --- a/vl.h +++ b/vl.h @@ -48,6 +48,9 @@ #ifdef __sun__ #define ENOMEDIUM 4097 #endif +#ifndef ENOMEDIUM +#define ENOMEDIUM ENODEV +#endif #ifdef _WIN32 #include -- cgit v1.2.3 From 6c3675cac3934e79145fd025b8489c38ede588d3 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 26 Jan 2007 17:18:49 +0000 Subject: ENODEV works also for __sun__, the magic number 4097 stemmed from the windows support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2358 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/vl.h b/vl.h index c0df57955..41b546de3 100644 --- a/vl.h +++ b/vl.h @@ -45,9 +45,6 @@ #define O_BINARY 0 #endif -#ifdef __sun__ -#define ENOMEDIUM 4097 -#endif #ifndef ENOMEDIUM #define ENOMEDIUM ENODEV #endif -- cgit v1.2.3 From 64423fb206a9278d65b9f5601d0202bd9b5e6d84 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 27 Jan 2007 17:11:41 +0000 Subject: Accept -help. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2359 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.c b/vl.c index f92c989d4..9c6be0bb7 100644 --- a/vl.c +++ b/vl.c @@ -6240,6 +6240,7 @@ typedef struct QEMUOption { const QEMUOption qemu_options[] = { { "h", 0, QEMU_OPTION_h }, + { "help", 0, QEMU_OPTION_h }, { "M", HAS_ARG, QEMU_OPTION_M }, { "fda", HAS_ARG, QEMU_OPTION_fda }, -- cgit v1.2.3 From dff5efc848f5fe3fd8a9a67129a5234fe46ec3bb Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 27 Jan 2007 17:19:39 +0000 Subject: Accept --foo as an alias for -foo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2360 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vl.c b/vl.c index 9c6be0bb7..1a8d51c65 100644 --- a/vl.c +++ b/vl.c @@ -6634,6 +6634,9 @@ int main(int argc, char **argv) const QEMUOption *popt; optind++; + /* Treat --foo the same as -foo. */ + if (r[1] == '-') + r++; popt = qemu_options; for(;;) { if (!popt->name) { -- cgit v1.2.3 From e5b0bc445ed7edb1738aabb982a387ee38da1655 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 27 Jan 2007 23:46:43 +0000 Subject: Rearrange char event handlers to fix CHR_EVENT_RESET. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2361 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 23 ++------ hw/pl011.c | 4 +- hw/serial.c | 8 +-- hw/sh7750.c | 10 ++-- hw/slavio_serial.c | 4 +- monitor.c | 3 +- vl.c | 150 ++++++++++++++++++++--------------------------------- vl.h | 18 ++++--- 8 files changed, 84 insertions(+), 136 deletions(-) diff --git a/console.c b/console.c index b0e7f2e0d..2b3cd669d 100644 --- a/console.c +++ b/console.c @@ -132,10 +132,7 @@ struct TextConsole { int esc_params[MAX_ESC_PARAMS]; int nb_esc_params; - /* kbd read handler */ - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; + CharDriverState *chr; /* fifo for key pressed */ QEMUFIFO out_fifo; uint8_t out_fifo_buf[16]; @@ -1021,16 +1018,6 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len) 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; @@ -1052,14 +1039,14 @@ static void kbd_send_chars(void *opaque) int len; uint8_t buf[16]; - len = s->fd_can_read(s->fd_opaque); + len = qemu_chr_can_read(s->chr); 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); + qemu_chr_read(s->chr, buf, len); } /* characters are pending: we send them a bit later (XXX: horrible, should change char device API) */ @@ -1110,7 +1097,7 @@ void kbd_put_keysym(int keysym) } else { *q++ = keysym; } - if (s->fd_read) { + if (s->chr->chr_read) { qemu_fifo_write(&s->out_fifo, buf, q - buf); kbd_send_chars(s); } @@ -1186,9 +1173,9 @@ CharDriverState *text_console_init(DisplayState *ds) } 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->chr = chr; 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); diff --git a/hw/pl011.c b/hw/pl011.c index 657f03bbe..fb7ab7b53 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -243,8 +243,8 @@ void pl011_init(uint32_t base, void *pic, int irq, s->cr = 0x300; s->flags = 0x90; if (chr){ - qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s); - qemu_chr_add_event_handler(chr, pl011_event); + qemu_chr_add_handlers(chr, pl011_can_recieve, pl011_recieve, + pl011_event, s); } /* ??? Save/restore. */ } diff --git a/hw/serial.c b/hw/serial.c index 16dbc65c3..a88aec17d 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -365,8 +365,8 @@ SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, register_ioport_write(base, 8, 1, serial_ioport_write, s); register_ioport_read(base, 8, 1, serial_ioport_read, s); s->chr = chr; - qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s); - qemu_chr_add_event_handler(chr, serial_event); + qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1, + serial_event, s); return s; } @@ -453,7 +453,7 @@ SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, serial_mm_write, s); cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); s->chr = chr; - qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s); - qemu_chr_add_event_handler(chr, serial_event); + qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1, + serial_event, s); return s; } diff --git a/hw/sh7750.c b/hw/sh7750.c index 21f9bc0ae..164ce7162 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -299,9 +299,8 @@ static void init_serial1(SH7750State * s, int serial_nb) } s->serial1 = chr; - qemu_chr_add_read_handler(chr, serial1_can_receive, - serial1_receive, s); - qemu_chr_add_event_handler(chr, serial1_event); + qemu_chr_add_handlers(chr, serial1_can_receive, + serial1_receive, serial1_event, s); } /********************************************************************** @@ -415,9 +414,8 @@ static void init_serial2(SH7750State * s, int serial_nb) } s->serial2 = chr; - qemu_chr_add_read_handler(chr, serial2_can_receive, - serial2_receive, s); - qemu_chr_add_event_handler(chr, serial2_event); + qemu_chr_add_handlers(chr, serial2_can_receive, + serial2_receive, serial1_event, s); } static void init_serial_ports(SH7750State * s) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 928ff4c91..e72bb70e0 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -565,8 +565,8 @@ SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDr s->chn[i].chn = 1 - i; s->chn[i].type = ser; if (s->chn[i].chr) { - qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]); - qemu_chr_add_event_handler(s->chn[i].chr, serial_event); + qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, + serial_receive1, serial_event, &s->chn[i]); } } s->chn[0].otherchn = &s->chn[1]; diff --git a/monitor.c b/monitor.c index 6cb1c38fb..893040a17 100644 --- a/monitor.c +++ b/monitor.c @@ -2455,8 +2455,7 @@ void monitor_init(CharDriverState *hd, int show_banner) monitor_hd = hd; hide_banner = !show_banner; - qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL); - qemu_chr_add_event_handler(hd, term_event); + qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL); } /* XXX: use threads ? */ diff --git a/vl.c b/vl.c index 1a8d51c65..0bacd0480 100644 --- a/vl.c +++ b/vl.c @@ -1119,11 +1119,17 @@ void quit_timers(void) /***********************************************************/ /* character device */ +static void qemu_chr_event(CharDriverState *s, int event) +{ + if (!s->chr_event) + return; + s->chr_event(s->handler_opaque, event); +} + static void qemu_chr_reset_bh(void *opaque) { CharDriverState *s = opaque; - if (s->chr_event) - s->chr_event(s, CHR_EVENT_RESET); + qemu_chr_event(s, CHR_EVENT_RESET); qemu_bh_delete(s->bh); s->bh = NULL; } @@ -1148,6 +1154,19 @@ int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) return s->chr_ioctl(s, cmd, arg); } +int qemu_chr_can_read(CharDriverState *s) +{ + if (!s->chr_can_read) + return 0; + return s->chr_can_read(s->handler_opaque); +} + +void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) +{ + s->chr_read(s->handler_opaque, buf, len); +} + + void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) { char buf[4096]; @@ -1164,29 +1183,25 @@ void qemu_chr_send_event(CharDriverState *s, int event) s->chr_send_event(s, event); } -void qemu_chr_add_read_handler(CharDriverState *s, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +void qemu_chr_add_handlers(CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque) { - s->chr_add_read_handler(s, fd_can_read, fd_read, opaque); + s->chr_can_read = fd_can_read; + s->chr_read = fd_read; + s->chr_event = fd_event; + s->handler_opaque = opaque; + if (s->chr_update_read_handler) + s->chr_update_read_handler(s); } -void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event) -{ - s->chr_event = chr_event; -} - static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { return len; } -static void null_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) -{ -} - static CharDriverState *qemu_chr_open_null(void) { CharDriverState *chr; @@ -1195,7 +1210,6 @@ static CharDriverState *qemu_chr_open_null(void) if (!chr) return NULL; chr->chr_write = null_chr_write; - chr->chr_add_read_handler = null_chr_add_read_handler; return chr; } @@ -1287,9 +1301,6 @@ void socket_set_nonblock(int fd) typedef struct { int fd_in, fd_out; - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; int max_size; } FDCharDriver; @@ -1309,7 +1320,7 @@ static int fd_chr_read_poll(void *opaque) CharDriverState *chr = opaque; FDCharDriver *s = chr->opaque; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); return s->max_size; } @@ -1332,20 +1343,15 @@ static void fd_chr_read(void *opaque) return; } if (size > 0) { - s->fd_read(s->fd_opaque, buf, size); + qemu_chr_read(chr, buf, size); } } -static void fd_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +static void fd_chr_update_read_handler(CharDriverState *chr) { FDCharDriver *s = chr->opaque; if (s->fd_in >= 0) { - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; if (nographic && s->fd_in == 0) { } else { qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, @@ -1372,7 +1378,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) s->fd_out = fd_out; chr->opaque = s; chr->chr_write = fd_chr_write; - chr->chr_add_read_handler = fd_chr_add_read_handler; + chr->chr_update_read_handler = fd_chr_update_read_handler; qemu_chr_reset(chr); @@ -1465,7 +1471,7 @@ static void stdio_received_byte(int ch) chr = stdio_clients[client_index]; s = chr->opaque; - chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK); + qemu_chr_event(chr, CHR_EVENT_BREAK); } break; case 'c': @@ -1492,13 +1498,11 @@ static void stdio_received_byte(int ch) if (client_index < stdio_nb_clients) { uint8_t buf[1]; CharDriverState *chr; - FDCharDriver *s; chr = stdio_clients[client_index]; - s = chr->opaque; - if (s->fd_can_read(s->fd_opaque) > 0) { + if (qemu_chr_can_read(chr) > 0) { buf[0] = ch; - s->fd_read(s->fd_opaque, buf, 1); + qemu_chr_read(chr, buf, 1); } else if (term_fifo_size == 0) { term_fifo[term_fifo_size++] = ch; } @@ -1509,14 +1513,12 @@ static void stdio_received_byte(int ch) static int stdio_read_poll(void *opaque) { CharDriverState *chr; - FDCharDriver *s; if (client_index < stdio_nb_clients) { chr = stdio_clients[client_index]; - s = chr->opaque; /* try to flush the queue if needed */ - if (term_fifo_size != 0 && s->fd_can_read(s->fd_opaque) > 0) { - s->fd_read(s->fd_opaque, term_fifo, 1); + if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { + qemu_chr_read(chr, term_fifo, 1); term_fifo_size = 0; } /* see if we can absorb more chars */ @@ -1855,7 +1857,6 @@ static CharDriverState *qemu_chr_open_pp(const char *filename) } chr->opaque = (void *)fd; chr->chr_write = null_chr_write; - chr->chr_add_read_handler = null_chr_add_read_handler; chr->chr_ioctl = pp_ioctl; qemu_chr_reset(chr); @@ -1874,9 +1875,6 @@ static CharDriverState *qemu_chr_open_pty(void) #ifdef _WIN32 typedef struct { - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *win_opaque; int max_size; HANDLE hcom, hrecv, hsend; OVERLAPPED orecv, osend; @@ -2020,10 +2018,10 @@ static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1) static int win_chr_read_poll(WinCharState *s) { - s->max_size = s->fd_can_read(s->win_opaque); + s->max_size = qemu_chr_can_read(s->chr); return s->max_size; } - + static void win_chr_readfile(WinCharState *s) { int ret, err; @@ -2041,7 +2039,7 @@ static void win_chr_readfile(WinCharState *s) } if (size > 0) { - s->fd_read(s->win_opaque, buf, size); + qemu_chr_read(s->chr, buf, size); } } @@ -2071,17 +2069,6 @@ static int win_chr_poll(void *opaque) return 0; } -static void win_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) -{ - WinCharState *s = chr->opaque; - - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->win_opaque = opaque; -} - static CharDriverState *qemu_chr_open_win(const char *filename) { CharDriverState *chr; @@ -2097,7 +2084,6 @@ static CharDriverState *qemu_chr_open_win(const char *filename) } chr->opaque = s; chr->chr_write = win_chr_write; - chr->chr_add_read_handler = win_chr_add_read_handler; chr->chr_close = win_chr_close; if (win_chr_init(s, filename) < 0) { @@ -2201,7 +2187,6 @@ static CharDriverState *qemu_chr_open_win_pipe(const char *filename) } chr->opaque = s; chr->chr_write = win_chr_write; - chr->chr_add_read_handler = win_chr_add_read_handler; chr->chr_close = win_chr_close; if (win_chr_pipe_init(s, filename) < 0) { @@ -2229,7 +2214,6 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) s->hcom = fd_out; chr->opaque = s; chr->chr_write = win_chr_write; - chr->chr_add_read_handler = win_chr_add_read_handler; qemu_chr_reset(chr); return chr; } @@ -2251,9 +2235,6 @@ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) /* UDP Net console */ typedef struct { - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; int fd; struct sockaddr_in daddr; char buf[1024]; @@ -2275,15 +2256,15 @@ static int udp_chr_read_poll(void *opaque) CharDriverState *chr = opaque; NetCharDriver *s = chr->opaque; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); /* If there were any stray characters in the queue process them * first */ while (s->max_size > 0 && s->bufptr < s->bufcnt) { - s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1); + qemu_chr_read(chr, &s->buf[s->bufptr], 1); s->bufptr++; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); } return s->max_size; } @@ -2302,22 +2283,17 @@ static void udp_chr_read(void *opaque) s->bufptr = 0; while (s->max_size > 0 && s->bufptr < s->bufcnt) { - s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1); + qemu_chr_read(chr, &s->buf[s->bufptr], 1); s->bufptr++; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); } } -static void udp_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +static void udp_chr_update_read_handler(CharDriverState *chr) { NetCharDriver *s = chr->opaque; if (s->fd >= 0) { - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; qemu_set_fd_handler2(s->fd, udp_chr_read_poll, udp_chr_read, NULL, chr); } @@ -2367,7 +2343,7 @@ static CharDriverState *qemu_chr_open_udp(const char *def) s->bufptr = 0; chr->opaque = s; chr->chr_write = udp_chr_write; - chr->chr_add_read_handler = udp_chr_add_read_handler; + chr->chr_update_read_handler = udp_chr_update_read_handler; return chr; return_err: @@ -2384,13 +2360,11 @@ return_err: /* TCP Net console */ typedef struct { - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; int fd, listen_fd; int connected; int max_size; int do_telnetopt; + int do_nodelay; int is_unix; } TCPCharDriver; @@ -2413,9 +2387,7 @@ static int tcp_chr_read_poll(void *opaque) TCPCharDriver *s = chr->opaque; if (!s->connected) return 0; - if (!s->fd_can_read) - return 0; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); return s->max_size; } @@ -2448,7 +2420,7 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr, } else { if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { /* Handle IAC break commands by sending a serial break */ - chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK); + qemu_chr_event(chr, CHR_EVENT_BREAK); s->do_telnetopt++; } s->do_telnetopt++; @@ -2495,21 +2467,10 @@ static void tcp_chr_read(void *opaque) if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); if (size > 0) - s->fd_read(s->fd_opaque, buf, size); + qemu_chr_read(chr, buf, size); } } -static void tcp_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) -{ - TCPCharDriver *s = chr->opaque; - - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; -} - static void tcp_chr_connect(void *opaque) { CharDriverState *chr = opaque; @@ -2658,7 +2619,6 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, chr->opaque = s; chr->chr_write = tcp_chr_write; - chr->chr_add_read_handler = tcp_chr_add_read_handler; chr->chr_close = tcp_chr_close; if (is_listen) { diff --git a/vl.h b/vl.h index 41b546de3..b43ae9b6d 100644 --- a/vl.h +++ b/vl.h @@ -293,11 +293,12 @@ typedef void IOEventHandler(void *opaque, int event); typedef struct CharDriverState { int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); - void (*chr_add_read_handler)(struct CharDriverState *s, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque); + void (*chr_update_read_handler)(struct CharDriverState *s); int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); IOEventHandler *chr_event; + IOCanRWHandler *chr_can_read; + IOReadHandler *chr_read; + void *handler_opaque; void (*chr_send_event)(struct CharDriverState *chr, int event); void (*chr_close)(struct CharDriverState *chr); void *opaque; @@ -308,12 +309,15 @@ CharDriverState *qemu_chr_open(const char *filename); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); void qemu_chr_send_event(CharDriverState *s, int event); -void qemu_chr_add_read_handler(CharDriverState *s, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque); -void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event); +void qemu_chr_add_handlers(CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque); int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); void qemu_chr_reset(CharDriverState *s); +int qemu_chr_can_read(CharDriverState *s); +void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); /* consoles */ -- cgit v1.2.3 From f749998939e564d8b8363bd6148b7a067d6bc9e3 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 28 Jan 2007 00:10:01 +0000 Subject: Add nodelay option for TCP character devices. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2362 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 7 ++++--- vl.c | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 11cd82ceb..4b9c5f4cd 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -576,13 +576,14 @@ localhost 5555 @end table -@item tcp:[host]:port[,server][,nowait] +@item tcp:[host]:port[,server][,nowait][,nodelay] The TCP Net Console has two modes of operation. It can send the serial I/O to a location or wait for a connection from a location. By default the TCP Net Console is sent to @var{host} at the @var{port}. If you use the @var{server} option QEMU will wait for a client socket application to connect to the port before continuing, unless the @code{nowait} -option was specified. If @var{host} is omitted, 0.0.0.0 is assumed. Only +option was specified. The @code{nodelay} option disables the Nagle buffering +algoritm. If @var{host} is omitted, 0.0.0.0 is assumed. Only one TCP connection at a time is accepted. You can use @code{telnet} to connect to the corresponding character device. @table @code @@ -594,7 +595,7 @@ connect to the corresponding character device. -serial tcp:192.168.0.100:4444,server,nowait @end table -@item telnet:host:port[,server][,nowait] +@item telnet:host:port[,server][,nowait][,nodelay] The telnet protocol is used instead of raw tcp sockets. The options work the same as if you had specified @code{-serial tcp}. The difference is that the port acts like a telnet server or client using diff --git a/vl.c b/vl.c index 0bacd0480..afd478e27 100644 --- a/vl.c +++ b/vl.c @@ -2497,6 +2497,12 @@ static void tcp_chr_telnet_init(int fd) send(fd, (char *)buf, 3, 0); } +static void socket_set_nodelay(int fd) +{ + int val = 1; + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); +} + static void tcp_chr_accept(void *opaque) { CharDriverState *chr = opaque; @@ -2530,6 +2536,8 @@ static void tcp_chr_accept(void *opaque) } } socket_set_nonblock(fd); + if (s->do_nodelay) + socket_set_nodelay(fd); s->fd = fd; qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); tcp_chr_connect(chr); @@ -2554,6 +2562,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, int fd = -1, ret, err, val; int is_listen = 0; int is_waitconnect = 1; + int do_nodelay = 0; const char *ptr; struct sockaddr_in saddr; #ifndef _WIN32 @@ -2584,6 +2593,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, is_listen = 1; } else if (!strncmp(ptr,"nowait",6)) { is_waitconnect = 0; + } else if (!strncmp(ptr,"nodelay",6)) { + do_nodelay = 1; } else { printf("Unknown option: %s\n", ptr); goto fail; @@ -2616,6 +2627,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, s->fd = -1; s->listen_fd = -1; s->is_unix = is_unix; + s->do_nodelay = do_nodelay && !is_unix; chr->opaque = s; chr->chr_write = tcp_chr_write; @@ -2665,6 +2677,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, } } s->fd = fd; + socket_set_nodelay(fd); if (s->connected) tcp_chr_connect(chr); else -- cgit v1.2.3 From 4046d9130ebf3fb4dbb3fa49dfc7e23df7e59d87 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 28 Jan 2007 01:53:16 +0000 Subject: Use standard character device interface for gdbstub. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2363 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 163 ++++++++++++++++++++++++++++++++++------------------------ gdbstub.h | 4 +- qemu-doc.texi | 3 +- vl.c | 23 ++++++--- vl.h | 3 +- 5 files changed, 118 insertions(+), 78 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 2311a6c01..dd7fe42aa 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -53,25 +53,28 @@ enum RSState { RS_CHKSUM1, RS_CHKSUM2, }; -/* XXX: This is not thread safe. Do we care? */ -static int gdbserver_fd = -1; - typedef struct GDBState { CPUState *env; /* current CPU */ enum RSState state; /* parsing state */ - int fd; char line_buf[4096]; int line_buf_index; int line_csum; + char last_packet[4100]; + int last_packet_len; #ifdef CONFIG_USER_ONLY + int fd; int running_state; +#else + CharDriverState *chr; #endif } GDBState; #ifdef CONFIG_USER_ONLY +/* XXX: This is not thread safe. Do we care? */ +static int gdbserver_fd = -1; + /* XXX: remove this hack. */ static GDBState gdbserver_state; -#endif static int get_char(GDBState *s) { @@ -91,9 +94,11 @@ static int get_char(GDBState *s) } return ch; } +#endif static void put_buffer(GDBState *s, const uint8_t *buf, int len) { +#ifdef CONFIG_USER_ONLY int ret; while (len > 0) { @@ -106,6 +111,9 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len) len -= ret; } } +#else + qemu_chr_write(s->chr, buf, len); +#endif } static inline int fromhex(int v) @@ -154,33 +162,39 @@ static void hextomem(uint8_t *mem, const char *buf, int len) /* return -1 if error, 0 if OK */ static int put_packet(GDBState *s, char *buf) { - char buf1[3]; - int len, csum, ch, i; + int len, csum, i; + char *p; #ifdef DEBUG_GDB printf("reply='%s'\n", buf); #endif for(;;) { - buf1[0] = '$'; - put_buffer(s, buf1, 1); + p = s->last_packet; + *(p++) = '$'; len = strlen(buf); - put_buffer(s, buf, len); + memcpy(p, buf, len); + p += len; csum = 0; for(i = 0; i < len; i++) { csum += buf[i]; } - buf1[0] = '#'; - buf1[1] = tohex((csum >> 4) & 0xf); - buf1[2] = tohex((csum) & 0xf); + *(p++) = '#'; + *(p++) = tohex((csum >> 4) & 0xf); + *(p++) = tohex((csum) & 0xf); - put_buffer(s, buf1, 3); + s->last_packet_len = p - s->last_packet; + put_buffer(s, s->last_packet, s->last_packet_len); - ch = get_char(s); - if (ch < 0) +#ifdef CONFIG_USER_ONLY + i = get_char(s); + if (i < 0) return -1; - if (ch == '+') + if (i == '+') break; +#else + break; +#endif } return 0; } @@ -864,6 +878,26 @@ static void gdb_read_byte(GDBState *s, int ch) char reply[1]; #ifndef CONFIG_USER_ONLY + if (s->last_packet_len) { + /* Waiting for a response to the last packet. If we see the start + of a new command then abandon the previous response. */ + if (ch == '-') { +#ifdef DEBUG_GDB + printf("Got NACK, retransmitting\n"); +#endif + put_buffer(s, s->last_packet, s->last_packet_len); + } +#ifdef DEBUG_GDB + else if (ch == '+') + printf("Got ACK\n"); + else + printf("Got '%c' when expecting ACK/NACK\n", ch); +#endif + if (ch == '+' || ch == '$') + s->last_packet_len = 0; + if (ch != '$') + return; + } if (vm_running) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ @@ -972,30 +1006,6 @@ void gdb_exit(CPUState *env, int code) put_packet(s, buf); } -#else -static void gdb_read(void *opaque) -{ - GDBState *s = opaque; - int i, size; - uint8_t buf[4096]; - - size = recv(s->fd, buf, sizeof(buf), 0); - if (size < 0) - return; - if (size == 0) { - /* end of connection */ - qemu_del_vm_stop_handler(gdb_vm_stopped, s); - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); - qemu_free(s); - if (autostart) - vm_start(); - } else { - for(i = 0; i < size; i++) - gdb_read_byte(s, buf[i]); - } -} - -#endif static void gdb_accept(void *opaque) { @@ -1019,32 +1029,12 @@ static void gdb_accept(void *opaque) val = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); -#ifdef CONFIG_USER_ONLY s = &gdbserver_state; memset (s, 0, sizeof (GDBState)); -#else - s = qemu_mallocz(sizeof(GDBState)); - if (!s) { - close(fd); - return; - } -#endif s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; -#ifdef CONFIG_USER_ONLY fcntl(fd, F_SETFL, O_NONBLOCK); -#else - socket_set_nonblock(fd); - - /* stop the VM */ - vm_stop(EXCP_INTERRUPT); - - /* start handling I/O */ - qemu_set_fd_handler(s->fd, gdb_read, NULL, s); - /* when the VM is stopped, the following callback is called */ - qemu_add_vm_stop_handler(gdb_vm_stopped, s); -#endif } static int gdbserver_open(int port) @@ -1075,9 +1065,6 @@ static int gdbserver_open(int port) perror("listen"); return -1; } -#ifndef CONFIG_USER_ONLY - socket_set_nonblock(fd); -#endif return fd; } @@ -1087,10 +1074,52 @@ int gdbserver_start(int port) if (gdbserver_fd < 0) return -1; /* accept connections */ -#ifdef CONFIG_USER_ONLY gdb_accept (NULL); + return 0; +} #else - qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL); -#endif +static int gdb_chr_can_recieve(void *opaque) +{ + return 1; +} + +static void gdb_chr_recieve(void *opaque, const uint8_t *buf, int size) +{ + GDBState *s = opaque; + int i; + + for (i = 0; i < size; i++) { + gdb_read_byte(s, buf[i]); + } +} + +static void gdb_chr_event(void *opaque, int event) +{ + switch (event) { + case CHR_EVENT_RESET: + vm_stop(EXCP_INTERRUPT); + break; + default: + break; + } +} + +int gdbserver_start(CharDriverState *chr) +{ + GDBState *s; + + if (!chr) + return -1; + + s = qemu_mallocz(sizeof(GDBState)); + if (!s) { + return -1; + } + s->env = first_cpu; /* XXX: allow to change CPU */ + s->chr = chr; + qemu_chr_add_handlers(chr, gdb_chr_can_recieve, gdb_chr_recieve, + gdb_chr_event, s); + qemu_add_vm_stop_handler(gdb_vm_stopped, s); return 0; } +#endif diff --git a/gdbstub.h b/gdbstub.h index 7b42596f1..c9d5c6827 100644 --- a/gdbstub.h +++ b/gdbstub.h @@ -6,7 +6,9 @@ #ifdef CONFIG_USER_ONLY int gdb_handlesig (CPUState *, int); void gdb_exit(CPUState *, int); -#endif int gdbserver_start(int); +#else +int gdbserver_start(CharDriverState *chr); +#endif #endif diff --git a/qemu-doc.texi b/qemu-doc.texi index 4b9c5f4cd..0874f4c04 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -631,7 +631,8 @@ non graphical mode. @item -s Wait gdb connection to port 1234 (@pxref{gdb_usage}). @item -p port -Change gdb connection port. +Change gdb connection port. @var{port} can be either a decimal number +to specify a TCP port, or a host device (same devices as the serial port). @item -S Do not start CPU at startup (you must type 'c' in the monitor). @item -d diff --git a/vl.c b/vl.c index afd478e27..8ddd8ece2 100644 --- a/vl.c +++ b/vl.c @@ -6496,7 +6496,8 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB - int use_gdbstub, gdbstub_port; + int use_gdbstub; + char gdbstub_port_name[128]; #endif int i, cdrom_index; int snapshot, linux_boot; @@ -6564,7 +6565,7 @@ int main(int argc, char **argv) bios_size = BIOS_SIZE; #ifdef CONFIG_GDBSTUB use_gdbstub = 0; - gdbstub_port = DEFAULT_GDBSTUB_PORT; + sprintf(gdbstub_port_name, "%d", DEFAULT_GDBSTUB_PORT); #endif snapshot = 0; nographic = 0; @@ -6808,7 +6809,7 @@ int main(int argc, char **argv) use_gdbstub = 1; break; case QEMU_OPTION_p: - gdbstub_port = atoi(optarg); + pstrcpy(gdbstub_port_name, sizeof(gdbstub_port_name), optarg); break; #endif case QEMU_OPTION_L: @@ -7216,13 +7217,19 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB if (use_gdbstub) { - if (gdbserver_start(gdbstub_port) < 0) { - fprintf(stderr, "Could not open gdbserver socket on port %d\n", - gdbstub_port); + CharDriverState *chr; + int port; + + port = atoi(gdbstub_port_name); + if (port != 0) + sprintf(gdbstub_port_name, "tcp::%d,nowait,nodelay,server", port); + chr = qemu_chr_open(gdbstub_port_name); + if (!chr) { + fprintf(stderr, "qemu: could not open gdbstub device '%s'\n", + gdbstub_port_name); exit(1); - } else { - printf("Waiting gdb connection on port %d\n", gdbstub_port); } + gdbserver_start(chr); } else #endif if (loadvm) diff --git a/vl.h b/vl.h index b43ae9b6d..6f373cb81 100644 --- a/vl.h +++ b/vl.h @@ -84,7 +84,6 @@ static inline char *realpath(const char *path, char *resolved_path) #include "audio/audio.h" #include "cpu.h" -#include "gdbstub.h" #endif /* !defined(QEMU_TOOL) */ @@ -1364,6 +1363,8 @@ pflash_t *pflash_register (target_ulong base, ram_addr_t off, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); +#include "gdbstub.h" + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ -- cgit v1.2.3 From a2d1ebaf890da03de850812cc8dbec2d56efb4e8 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 28 Jan 2007 03:10:55 +0000 Subject: GDB hosted syscalls. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2364 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm-semi.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- gdbstub.c | 112 ++++++++++++++++++++++++++++++++++++++ gdbstub.h | 5 ++ 3 files changed, 262 insertions(+), 32 deletions(-) diff --git a/arm-semi.c b/arm-semi.c index 4254cba84..4ddbc73c2 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -61,7 +61,30 @@ #define O_BINARY 0 #endif -int open_modeflags[12] = { +#define GDB_O_RDONLY 0x000 +#define GDB_O_WRONLY 0x001 +#define GDB_O_RDWR 0x002 +#define GDB_O_APPEND 0x008 +#define GDB_O_CREAT 0x200 +#define GDB_O_TRUNC 0x400 +#define GDB_O_BINARY 0 + +static int gdb_open_modeflags[12] = { + GDB_O_RDONLY, + GDB_O_RDONLY | GDB_O_BINARY, + GDB_O_RDWR, + GDB_O_RDWR | GDB_O_BINARY, + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC, + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY, + GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC, + GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY, + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND, + GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY, + GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND, + GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY +}; + +static int open_modeflags[12] = { O_RDONLY, O_RDONLY | O_BINARY, O_RDWR, @@ -142,6 +165,35 @@ static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr, #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) #endif +static target_ulong arm_semi_syscall_len; + +static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err) +{ +#ifdef CONFIG_USER_ONLY + TaskState *ts = env->opaque; +#endif + if (ret == (target_ulong)-1) { +#ifdef CONFIG_USER_ONLY + ts->swi_errno = err; +#endif + env->regs[0] = ret; + } else { + /* Fixup syscalls that use nonstardard return conventions. */ + switch (env->regs[0]) { + case SYS_WRITE: + case SYS_READ: + env->regs[0] = arm_semi_syscall_len - ret; + break; + case SYS_SEEK: + env->regs[0] = 0; + break; + default: + env->regs[0] = ret; + break; + } + } +} + #define ARG(n) tget32(args + (n) * 4) #define SET_ARG(n, val) tput32(args + (n) * 4,val) uint32_t do_arm_semihosting(CPUState *env) @@ -170,52 +222,99 @@ uint32_t do_arm_semihosting(CPUState *env) else return STDOUT_FILENO; } - ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), (int)ARG(2), + gdb_open_modeflags[ARG(1)]); + return env->regs[0]; + } else { + ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); + } unlock_user(s, ARG(0), 0); return ret; case SYS_CLOSE: - return set_swi_errno(ts, close(ARG(0))); + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0)); + return env->regs[0]; + } else { + return set_swi_errno(ts, close(ARG(0))); + } case SYS_WRITEC: { char c = tget8(args); /* Write to debug console. stderr is near enough. */ - return write(STDERR_FILENO, &c, 1); + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args); + return env->regs[0]; + } else { + return write(STDERR_FILENO, &c, 1); + } } case SYS_WRITE0: s = lock_user_string(args); - ret = write(STDERR_FILENO, s, strlen(s)); + len = strlen(s); + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len); + ret = env->regs[0]; + } else { + ret = write(STDERR_FILENO, s, len); + } unlock_user(s, args, 0); return ret; case SYS_WRITE: len = ARG(2); - s = lock_user(ARG(1), len, 1); - ret = set_swi_errno(ts, write(ARG(0), s, len)); - unlock_user(s, ARG(1), 0); - if (ret == (uint32_t)-1) - return -1; - return ARG(2) - ret; + if (use_gdb_syscalls()) { + arm_semi_syscall_len = len; + gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len); + return env->regs[0]; + } else { + s = lock_user(ARG(1), len, 1); + ret = set_swi_errno(ts, write(ARG(0), s, len)); + unlock_user(s, ARG(1), 0); + if (ret == (uint32_t)-1) + return -1; + return len - ret; + } case SYS_READ: len = ARG(2); - s = lock_user(ARG(1), len, 0); - do - ret = set_swi_errno(ts, read(ARG(0), s, len)); - while (ret == -1 && errno == EINTR); - unlock_user(s, ARG(1), len); - if (ret == (uint32_t)-1) - return -1; - return ARG(2) - ret; + if (use_gdb_syscalls()) { + arm_semi_syscall_len = len; + gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len); + return env->regs[0]; + } else { + s = lock_user(ARG(1), len, 0); + do + ret = set_swi_errno(ts, read(ARG(0), s, len)); + while (ret == -1 && errno == EINTR); + unlock_user(s, ARG(1), len); + if (ret == (uint32_t)-1) + return -1; + return len - ret; + } case SYS_READC: /* XXX: Read from debug cosole. Not implemented. */ return 0; case SYS_ISTTY: - return isatty(ARG(0)); + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0)); + return env->regs[0]; + } else { + return isatty(ARG(0)); + } case SYS_SEEK: - ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); - if (ret == (uint32_t)-1) - return -1; - return 0; + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "fseek,%x,%x,0", ARG(0), ARG(1)); + return env->regs[0]; + } else { + ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); + if (ret == (uint32_t)-1) + return -1; + return 0; + } case SYS_FLEN: - { + if (use_gdb_syscalls()) { + /* TODO: Use stat syscall. */ + return -1; + } else { struct stat buf; ret = set_swi_errno(ts, fstat(ARG(0), &buf)); if (ret == (uint32_t)-1) @@ -226,12 +325,21 @@ uint32_t do_arm_semihosting(CPUState *env) /* XXX: Not implemented. */ return -1; case SYS_REMOVE: - s = lock_user_string(ARG(0)); - ret = set_swi_errno(ts, remove(s)); - unlock_user(s, ARG(0), 0); + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)); + ret = env->regs[0]; + } else { + s = lock_user_string(ARG(0)); + ret = set_swi_errno(ts, remove(s)); + unlock_user(s, ARG(0), 0); + } return ret; case SYS_RENAME: - { + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "rename,%s,%s", + ARG(0), (int)ARG(1), ARG(2), (int)ARG(3)); + return env->regs[0]; + } else { char *s2; s = lock_user_string(ARG(0)); s2 = lock_user_string(ARG(2)); @@ -245,9 +353,14 @@ uint32_t do_arm_semihosting(CPUState *env) case SYS_TIME: return set_swi_errno(ts, time(NULL)); case SYS_SYSTEM: - s = lock_user_string(ARG(0)); - ret = set_swi_errno(ts, system(s)); - unlock_user(s, ARG(0), 0); + if (use_gdb_syscalls()) { + gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)); + return env->regs[0]; + } else { + s = lock_user_string(ARG(0)); + ret = set_swi_errno(ts, system(s)); + unlock_user(s, ARG(0), 0); + } case SYS_ERRNO: #ifdef CONFIG_USER_ONLY return ts->swi_errno; diff --git a/gdbstub.c b/gdbstub.c index dd7fe42aa..a26c12ca6 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -52,6 +52,7 @@ enum RSState { RS_GETLINE, RS_CHKSUM1, RS_CHKSUM2, + RS_SYSCALL, }; typedef struct GDBState { CPUState *env; /* current CPU */ @@ -96,6 +97,27 @@ static int get_char(GDBState *s) } #endif +/* GDB stub state for use by semihosting syscalls. */ +static GDBState *gdb_syscall_state; +static gdb_syscall_complete_cb gdb_current_syscall_cb; + +enum { + GDB_SYS_UNKNOWN, + GDB_SYS_ENABLED, + GDB_SYS_DISABLED, +} gdb_syscall_mode; + +/* If gdb is connected when the first semihosting syscall occurs then use + remote gdb syscalls. Otherwise use native file IO. */ +int use_gdb_syscalls(void) +{ + if (gdb_syscall_mode == GDB_SYS_UNKNOWN) { + gdb_syscall_mode = (gdb_syscall_state ? GDB_SYS_ENABLED + : GDB_SYS_DISABLED); + } + return gdb_syscall_mode == GDB_SYS_ENABLED; +} + static void put_buffer(GDBState *s, const uint8_t *buf, int len) { #ifdef CONFIG_USER_ONLY @@ -755,6 +777,34 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) vm_start(); #endif return RS_IDLE; + case 'F': + { + target_ulong ret; + target_ulong err; + + ret = strtoull(p, (char **)&p, 16); + if (*p == ',') { + p++; + err = strtoull(p, (char **)&p, 16); + } else { + err = 0; + } + if (*p == ',') + p++; + type = *p; + if (gdb_current_syscall_cb) + gdb_current_syscall_cb(s->env, ret, err); + if (type == 'C') { + put_packet(s, "T02"); + } else { +#ifdef CONFIG_USER_ONLY + s->running_state = 1; +#else + vm_start(); +#endif + } + } + break; case 'g': reg_size = cpu_gdb_read_registers(env, mem_buf); memtohex(buf, mem_buf, reg_size); @@ -855,6 +905,9 @@ static void gdb_vm_stopped(void *opaque, int reason) char buf[256]; int ret; + if (s->state == RS_SYSCALL) + return; + /* disable single step if it was enable */ cpu_single_step(s->env, 0); @@ -871,6 +924,60 @@ static void gdb_vm_stopped(void *opaque, int reason) } #endif +/* Send a gdb syscall request. + This accepts limited printf-style format specifiers, specifically: + %x - target_ulong argument printed in hex. + %s - string pointer (target_ulong) and length (int) pair. */ +void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...) +{ + va_list va; + char buf[256]; + char *p; + target_ulong addr; + GDBState *s; + + s = gdb_syscall_state; + if (!s) + return; + gdb_current_syscall_cb = cb; + s->state = RS_SYSCALL; +#ifndef CONFIG_USER_ONLY + vm_stop(EXCP_DEBUG); +#endif + s->state = RS_IDLE; + va_start(va, fmt); + p = buf; + *(p++) = 'F'; + while (*fmt) { + if (*fmt == '%') { + fmt++; + switch (*fmt++) { + case 'x': + addr = va_arg(va, target_ulong); + p += sprintf(p, TARGET_FMT_lx, addr); + break; + case 's': + addr = va_arg(va, target_ulong); + p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int)); + break; + default: + fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n", + fmt - 1); + break; + } + } else { + *(p++) = *(fmt++); + } + } + va_end(va); + put_packet(s, buf); +#ifdef CONFIG_USER_ONLY + gdb_handlesig(s->env, 0); +#else + cpu_interrupt(s->env, CPU_INTERRUPT_EXIT); +#endif +} + static void gdb_read_byte(GDBState *s, int ch) { CPUState *env = s->env; @@ -942,6 +1049,8 @@ static void gdb_read_byte(GDBState *s, int ch) s->state = gdb_handle_packet(s, env, s->line_buf); } break; + default: + abort(); } } } @@ -1034,6 +1143,8 @@ static void gdb_accept(void *opaque) s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; + gdb_syscall_state = s; + fcntl(fd, F_SETFL, O_NONBLOCK); } @@ -1098,6 +1209,7 @@ static void gdb_chr_event(void *opaque, int event) switch (event) { case CHR_EVENT_RESET: vm_stop(EXCP_INTERRUPT); + gdb_syscall_state = opaque; break; default: break; diff --git a/gdbstub.h b/gdbstub.h index c9d5c6827..c5b52c2e2 100644 --- a/gdbstub.h +++ b/gdbstub.h @@ -3,6 +3,11 @@ #define DEFAULT_GDBSTUB_PORT 1234 +typedef void (*gdb_syscall_complete_cb)(CPUState *env, + target_ulong ret, target_ulong err); + +void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...); +int use_gdb_syscalls(void); #ifdef CONFIG_USER_ONLY int gdb_handlesig (CPUState *, int); void gdb_exit(CPUState *, int); -- cgit v1.2.3 From 3ddd00658edf6c1af0c22f9cdcf963efdeda91bb Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Jan 2007 11:48:27 +0000 Subject: Fix 64bit-induced MIPS Malta breakage, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2365 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index c37c36084..029e18e68 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -32,12 +32,11 @@ #ifdef MIPS_HAS_MIPS64 #define INITRD_LOAD_ADDR (int64_t)0x80800000 -#define ENVP_ADDR (int64_t)0x80002000 #else #define INITRD_LOAD_ADDR (int32_t)0x80800000 -#define ENVP_ADDR (int32_t)0x80002000 #endif +#define ENVP_ADDR (int32_t)0x80002000 #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) #define ENVP_NB_ENTRIES 16 @@ -390,36 +389,36 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t /* Small bootloader */ p = (uint32_t *) (phys_ram_base + bios_offset); - stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */ - stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */ + stl_raw(p++, 0x00000000); /* nop */ /* Second part of the bootloader */ p = (uint32_t *) (phys_ram_base + bios_offset + 0x040); - stl_raw(p++, 0x3c040000); /* lui a0, 0 */ - stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */ - stl_raw(p++, 0x3c050000 | ((ENVP_ADDR) >> 16)); /* lui a1, high(ENVP_ADDR) */ - stl_raw(p++, 0x34a50000 | ((ENVP_ADDR) & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */ - stl_raw(p++, 0x3c060000 | ((ENVP_ADDR + 8) >> 16)); /* lui a2, high(ENVP_ADDR + 8) */ - stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ - stl_raw(p++, 0x3c070000 | ((env->ram_size) >> 16)); /* lui a3, high(env->ram_size) */ - stl_raw(p++, 0x34e70000 | ((env->ram_size) & 0xffff)); /* ori a3, a3, low(env->ram_size) */ - stl_raw(p++, 0x3c1f0000 | ((kernel_addr) >> 16)); /* lui ra, high(kernel_addr) */; - stl_raw(p++, 0x37ff0000 | ((kernel_addr) & 0xffff)); /* ori ra, ra, low(kernel_addr) */ - stl_raw(p++, 0x03e00008); /* jr ra */ - stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x3c040000); /* lui a0, 0 */ + stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */ + stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ + stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */ + stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ + stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ + stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */ + stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ + stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */; + stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */ + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0x00000000); /* nop */ } static void prom_set(int index, const char *string, ...) { va_list ap; - uint32_t *p; - uint32_t table_addr; + int32_t *p; + int32_t table_addr; char *s; if (index >= ENVP_NB_ENTRIES) return; - p = (uint32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND); + p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND); p += index; if (string == NULL) { @@ -427,7 +426,7 @@ static void prom_set(int index, const char *string, ...) return; } - table_addr = ENVP_ADDR + sizeof(uint32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE; + table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE; s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr); stl_raw(p, table_addr); -- cgit v1.2.3 From 90e950d17fa8f6f6e5b10812a26dcb8bd893b6f2 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Jan 2007 12:02:12 +0000 Subject: Fix GT64120 mapping with REDBOOT, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2366 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 84e041fcf..ccb6a7c1a 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -229,9 +229,12 @@ static void gt64120_pci_mapping(GT64120State *s) target_phys_addr_t start, length; /* Update IO mapping */ - start = s->regs[GT_PCI0IOLD] << 21; - length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; - isa_mmio_init(start, length); + if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD]) + { + start = s->regs[GT_PCI0IOLD] << 21; + length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; + isa_mmio_init(start, length); + } } static void gt64120_writel (void *opaque, target_phys_addr_t addr, -- cgit v1.2.3 From 46ea33974d9637ac9f5338e897e9ed053a575a84 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Jan 2007 12:08:13 +0000 Subject: Fix set_error return value, by Pierre d'Herbemont. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2367 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/darwin-user/main.c b/darwin-user/main.c index 259aab324..5a2bc299e 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -478,7 +478,7 @@ static void set_idt(int n, unsigned int dpl) } /* ABI convention: after a syscall if there was an error the CF flag is set */ -static inline set_error(CPUX86State *env, int ret) +static inline void set_error(CPUX86State *env, int ret) { if(ret<0) env->eflags = env->eflags | 0x1; -- cgit v1.2.3 From fd6776422bb97e957f7771a84fd4f1399557b973 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Jan 2007 12:10:07 +0000 Subject: Use Cocoa and CoreAudio backend by default on Darwin systems, by Pierre d'Herbemont. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2368 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/configure b/configure index eda1437fe..bcff13e97 100755 --- a/configure +++ b/configure @@ -128,6 +128,8 @@ Darwin) bsd="yes" darwin="yes" darwin_user="yes" +cocoa="yes" +coreaudio="yes" OS_CFLAGS="-mdynamic-no-pic" ;; SunOS) @@ -503,7 +505,9 @@ _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` if test "$_sdlversion" -lt 121 ; then sdl_too_old=yes else -sdl=yes + if test "$cocoa" = "no" ; then + sdl=yes + fi fi # static link with sdl ? @@ -524,6 +528,13 @@ fi # static link fi # sdl compile test fi # cross compilation + +else + # Make sure to disable cocoa if sdl was set + if test "$sdl" = "yes" ; then + cocoa="no" + coreaudio="no" + fi fi # -z $sdl ########################################## -- cgit v1.2.3 From 5a7b542bbd6d79a049b4a1ab5fe3e284fac46e9a Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Jan 2007 12:16:51 +0000 Subject: siginfo fix for Darwin/Mac OS X, by Pierre d'Herbemont. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2369 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 27 ++++++++++++++++++--------- target-arm/cpu.h | 3 +-- target-i386/cpu.h | 3 +-- target-m68k/cpu.h | 3 +-- target-ppc/cpu.h | 3 +-- target-sh4/cpu.h | 5 ++--- target-sparc/cpu.h | 3 +-- 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 6662b3974..a2704e5f1 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1280,9 +1280,10 @@ static void cpu_send_trap(unsigned long pc, int trap, } #endif -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; int trapno; @@ -1310,9 +1311,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #elif defined(__x86_64__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; @@ -1374,9 +1376,10 @@ typedef struct ucontext SIGCONTEXT; # 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, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; int is_write; @@ -1397,9 +1400,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #elif defined(__alpha__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; uint32_t *pc = uc->uc_mcontext.sc_pc; uint32_t insn = *pc; @@ -1426,9 +1430,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, } #elif defined(__sparc__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; uint32_t *regs = (uint32_t *)(info + 1); void *sigmask = (regs + 20); unsigned long pc; @@ -1459,9 +1464,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #elif defined(__arm__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; int is_write; @@ -1476,9 +1482,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, #elif defined(__mc68000) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; int is_write; @@ -1498,8 +1505,9 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, # define __ISR_VALID 1 #endif -int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long ip; int is_write = 0; @@ -1526,9 +1534,10 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc) #elif defined(__s390__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; unsigned long pc; int is_write; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 359d5cbdc..3208c138b 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -133,8 +133,7 @@ void switch_mode(CPUARMState *, int); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -struct siginfo; -int cpu_arm_signal_handler(int host_signum, struct siginfo *info, +int cpu_arm_signal_handler(int host_signum, void *pinfo, void *puc); #define CPSR_M (0x1f) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 429609315..70a1caccd 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -628,8 +628,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -struct siginfo; -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, +int cpu_x86_signal_handler(int host_signum, void *pinfo, void *puc); void cpu_x86_set_a20(CPUX86State *env, int a20_state); diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index a30bf962d..de37baf9a 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -97,8 +97,7 @@ void cpu_m68k_close(CPUM68KState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -struct siginfo; -int cpu_m68k_signal_handler(int host_signum, struct siginfo *info, +int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); void cpu_m68k_flush_flags(CPUM68KState *, int); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f05fb280b..b294e3146 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -575,8 +575,7 @@ void cpu_ppc_close(CPUPPCState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -struct siginfo; -int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, +int cpu_ppc_signal_handler(int host_signum, void *pinfo, void *puc); void do_interrupt (CPUPPCState *env); diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 7296d9eef..e844d690e 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -121,9 +121,8 @@ typedef struct CPUSH4State { CPUSH4State *cpu_sh4_init(void); int cpu_sh4_exec(CPUSH4State * s); -struct siginfo; -int cpu_sh4_signal_handler(int hostsignum, struct siginfo *info, - void *puc); +int cpu_sh4_signal_handler(int host_signum, void *pinfo, + void *puc); #include "softfloat.h" diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 86c232004..5c4593ac6 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -275,8 +275,7 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); } while (0) #endif -struct siginfo; -int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc); +int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); #include "cpu-all.h" -- cgit v1.2.3 From bf53ca01900d093e75f0b85eb00ebf359fbee301 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Jan 2007 12:22:18 +0000 Subject: Upgrade the apic version_id, by Don Laor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2370 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/apic.c b/hw/apic.c index 6e6673947..8c9776195 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -831,7 +831,7 @@ int apic_init(CPUState *env) } s->timer = qemu_new_timer(vm_clock, apic_timer, s); - register_savevm("apic", 0, 1, apic_save, apic_load, s); + register_savevm("apic", 0, 2, apic_save, apic_load, s); qemu_register_reset(apic_reset, s); local_apics[s->id] = s; -- cgit v1.2.3 From 01feaa058ed41800ced5605859592de8028c0ee5 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Jan 2007 12:24:18 +0000 Subject: Save some vm space for the regular program loading zone, by Pierre d'Herbemont git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2371 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile.target b/Makefile.target index ca6cd9600..b840cc782 100644 --- a/Makefile.target +++ b/Makefile.target @@ -172,6 +172,11 @@ ifeq ($(CONFIG_DARWIN),yes) LIBS+=-lmx endif +ifdef CONFIG_DARWIN_USER +# Leave some space for the regular program loading zone +BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000 +endif + OP_CFLAGS+=$(OS_CFLAGS) ######################################################### -- cgit v1.2.3 From 0dcece76f0766d3be3f6e2023e91fb221bec20cc Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Jan 2007 13:34:07 +0000 Subject: Remove redundant ENOMEDIUM define. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2372 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/vl.h b/vl.h index 6f373cb81..a46e4050f 100644 --- a/vl.h +++ b/vl.h @@ -54,7 +54,6 @@ #define fsync _commit #define lseek _lseeki64 #define ENOTSUP 4096 -#define ENOMEDIUM 4097 extern int qemu_ftruncate64(int, int64_t); #define ftruncate qemu_ftruncate64 -- cgit v1.2.3 From 0499e4a02a5f7b53f48777de1e04b8440c740d85 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 1 Feb 2007 22:11:07 +0000 Subject: cwde and cdq fix in 64 bit mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2373 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/op.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/op.c b/target-i386/op.c index 7c20f524f..a8cfce271 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -788,7 +788,7 @@ void OPPROTO op_movzwl_T0_T0(void) void OPPROTO op_movswl_EAX_AX(void) { - EAX = (int16_t)EAX; + EAX = (uint32_t)((int16_t)EAX); } #ifdef TARGET_X86_64 @@ -810,7 +810,7 @@ void OPPROTO op_movsbw_AX_AL(void) void OPPROTO op_movslq_EDX_EAX(void) { - EDX = (int32_t)EAX >> 31; + EDX = (uint32_t)((int32_t)EAX >> 31); } void OPPROTO op_movswl_DX_AX(void) -- cgit v1.2.3 From d80c7d1c478ae75fd18cf48b5e319cda1f567553 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 1 Feb 2007 22:12:19 +0000 Subject: 64 bit syscall fixes - more logical mwait/monitor ECX test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2374 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 57777ff75..1d62f6b2e 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -977,7 +977,7 @@ void helper_syscall(int next_eip_addend) cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, @@ -1028,7 +1028,7 @@ void helper_sysret(int dflag) if (dflag == 2) { cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); @@ -2422,12 +2422,14 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) if ((new_ss & 0xfffc) == 0) { #ifdef TARGET_X86_64 /* NULL ss is allowed in long mode if cpl != 3*/ + /* XXX: test CS64 ? */ if ((env->hflags & HF_LMA_MASK) && rpl != 3) { cpu_x86_load_seg_cache(env, R_SS, new_ss, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); + ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */ } else #endif { @@ -3716,14 +3718,14 @@ void helper_hlt(void) void helper_monitor(void) { - if (ECX != 0) + if ((uint32_t)ECX != 0) raise_exception(EXCP0D_GPF); /* XXX: store address ? */ } void helper_mwait(void) { - if (ECX != 0) + if ((uint32_t)ECX != 0) raise_exception(EXCP0D_GPF); /* XXX: not complete but not completely erroneous */ if (env->cpu_index != 0 || env->next_cpu != NULL) { -- cgit v1.2.3 From c4e27dd441d0271d448043d0c326b995b1f3ed17 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 1 Feb 2007 22:12:43 +0000 Subject: 64 bit syscall fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2375 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kqemu.c b/kqemu.c index e01556adf..96ca5826c 100644 --- a/kqemu.c +++ b/kqemu.c @@ -483,7 +483,7 @@ static int do_syscall(CPUState *env, cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, -- cgit v1.2.3 From 6a1cbf68b7cbb6967f218a2cf65345518b49706a Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Feb 2007 00:37:56 +0000 Subject: script=no for the TUN/TAP net option, by Jean-Christian de Rivaz git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2376 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 3 ++- vl.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 0874f4c04..34f5a59d6 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -358,7 +358,8 @@ hostname reported by the builtin DHCP server. @item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file] Connect the host TAP network interface @var{name} to VLAN @var{n} and use the network script @var{file} to configure it. The default -network script is @file{/etc/qemu-ifup}. If @var{name} is not +network script is @file{/etc/qemu-ifup}. Use @option{script=no} to +disable script execution. If @var{name} is not provided, the OS automatically provides one. @option{fd=h} can be used to specify the handle of an already opened host TAP interface. Example: diff --git a/vl.c b/vl.c index 8ddd8ece2..daeec82e8 100644 --- a/vl.c +++ b/vl.c @@ -3289,7 +3289,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, if (fd < 0) return -1; - if (!setup_script) + if (!setup_script || !strcmp(setup_script, "no")) setup_script = ""; if (setup_script[0] != '\0') { /* try to launch network init script */ @@ -6066,6 +6066,7 @@ void help(void) "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n" " connect the host TAP network interface to VLAN 'n' and use\n" " the network script 'file' (default=%s);\n" + " use 'script=no' to disable script execution;\n" " use 'fd=h' to connect to an already opened TAP interface\n" #endif "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n" -- cgit v1.2.3 From 01d6a890b4dbfa63a6c2e23a768f0e6c9bee55e0 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Feb 2007 01:03:34 +0000 Subject: Sparc arm/mips/sparc register patch, by Martin Bochnig. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2377 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/exec.h | 7 +++++++ target-mips/exec.h | 10 ++++++++++ target-sparc/exec.h | 22 ++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/target-arm/exec.h b/target-arm/exec.h index 2d2b99aa3..deba89304 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -19,10 +19,17 @@ */ #include "dyngen-exec.h" +#if defined(__sparc__) +struct CPUARMState *env; +uint32_t T0; +uint32_t T1; +uint32_t T2; +#else register struct CPUARMState *env asm(AREG0); register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); register uint32_t T2 asm(AREG3); +#endif /* TODO: Put these in FP regs on targets that have such things. */ /* It is ok for FT0s and FT0d to overlap. Likewise FT1s and FT1d. */ diff --git a/target-mips/exec.h b/target-mips/exec.h index 15397b692..1e9fa8e69 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -7,7 +7,11 @@ #include "mips-defs.h" #include "dyngen-exec.h" +#if defined(__sparc__) +struct CPUMIPSState *env; +#else register struct CPUMIPSState *env asm(AREG0); +#endif #if defined (USE_64BITS_REGS) typedef int64_t host_int_t; @@ -17,6 +21,11 @@ typedef int32_t host_int_t; typedef uint32_t host_uint_t; #endif +#if defined(__sparc__) +host_uint_t T0; +host_uint_t T1; +host_uint_t T2; +#else #if TARGET_LONG_BITS > HOST_LONG_BITS #define T0 (env->t0) #define T1 (env->t1) @@ -26,6 +35,7 @@ register host_uint_t T0 asm(AREG1); register host_uint_t T1 asm(AREG2); register host_uint_t T2 asm(AREG3); #endif +#endif #if defined (USE_HOST_FLOAT_REGS) #error "implement me." diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 1b67ef4bf..6e0515f6e 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -3,23 +3,41 @@ #include "dyngen-exec.h" #include "config.h" +#if defined(__sparc__) +struct CPUSPARCState *env; +#else register struct CPUSPARCState *env asm(AREG0); +#endif + #ifdef TARGET_SPARC64 #define T0 (env->t0) #define T1 (env->t1) #define T2 (env->t2) #define REGWPTR env->regwptr #else +#if defined(__sparc__) +register uint32_t T0 asm(AREG3); +register uint32_t T1 asm(AREG2); +#else register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); +#endif #undef REG_REGWPTR // Broken #ifdef REG_REGWPTR +#if defined(__sparc__) +register uint32_t *REGWPTR asm(AREG4); +#else register uint32_t *REGWPTR asm(AREG3); +#endif #define reg_REGWPTR #ifdef AREG4 +#if defined(__sparc__) +register uint32_t T2 asm(AREG0); +#else register uint32_t T2 asm(AREG4); +#endif #define reg_T2 #else #define T2 (env->t2) @@ -27,7 +45,11 @@ register uint32_t T2 asm(AREG4); #else #define REGWPTR env->regwptr +#if defined(__sparc__) +register uint32_t T2 asm(AREG0); +#else register uint32_t T2 asm(AREG3); +#endif #define reg_T2 #endif #endif -- cgit v1.2.3 From 4a109bfbca86934141d857bc9ed1a43cf4b1a940 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Feb 2007 02:56:33 +0000 Subject: Update MIPS TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2378 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index a7ab2cf16..bd8d26d1f 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -14,8 +14,6 @@ MIPS64 - No 64bit TLB support - no 64bit wide registers for FPU - 64bit mul/div handling broken -- DM[FT]C not implemented, M[FT]C does not cut sign extensions in all - cases. "Generic" 4Kc system emulation ------------------------------ @@ -24,5 +22,5 @@ MIPS64 MALTA system emulation ---------------------- - We fake firmware support instead of doing the real thing -- Linux 2.4/2.6 Kernels receive spurious PIIX4 interrupts, noisy on 2.4, - silent on 2.6, indicates some divergence from actual hardware. +- Real firmware falls over when trying to init RAM, presumably due + to lacking I2C emulation. -- cgit v1.2.3 From 3fffc2234fc6551a78533fe544ba96106e58379a Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Feb 2007 03:13:18 +0000 Subject: PIIX4 SMBus host, EEPROM device emulation, by Ed Swierk. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2379 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/acpi.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.c | 6 ++ hw/smbus.h | 38 +++++++++++ hw/smbus_eeprom.c | 94 +++++++++++++++++++++++++++ vl.h | 6 ++ 6 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 hw/smbus.h create mode 100644 hw/smbus_eeprom.c diff --git a/Makefile.target b/Makefile.target index b840cc782..dc9a96575 100644 --- a/Makefile.target +++ b/Makefile.target @@ -370,7 +370,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) 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 mixeng.o apic.o parallel.o acpi.o piix_pci.o -VL_OBJS+= usb-uhci.o +VL_OBJS+= usb-uhci.o smbus_eeprom.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff --git a/hw/acpi.c b/hw/acpi.c index ce16531fb..78c4feabb 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -24,6 +24,7 @@ #define PM_FREQ 3579545 #define ACPI_DBG_IO_ADDR 0xb044 +#define SMB_IO_BASE 0xb100 typedef struct PIIX4PMState { PCIDevice dev; @@ -34,6 +35,15 @@ typedef struct PIIX4PMState { uint8_t apms; QEMUTimer *tmr_timer; int64_t tmr_overflow_time; + SMBusDevice *smb_dev[128]; + uint8_t smb_stat; + uint8_t smb_ctl; + uint8_t smb_cmd; + uint8_t smb_addr; + uint8_t smb_data0; + uint8_t smb_data1; + uint8_t smb_data[32]; + uint8_t smb_index; } PIIX4PMState; #define RTC_EN (1 << 10) @@ -45,6 +55,17 @@ typedef struct PIIX4PMState { #define SUS_EN (1 << 13) +#define SMBHSTSTS 0x00 +#define SMBHSTCNT 0x02 +#define SMBHSTCMD 0x03 +#define SMBHSTADD 0x04 +#define SMBHSTDAT0 0x05 +#define SMBHSTDAT1 0x06 +#define SMBBLKDAT 0x07 + +/* Note: only used for piix4_smbus_register_device */ +static PIIX4PMState *piix4_pm_state; + static uint32_t get_pmtmr(PIIX4PMState *s) { uint32_t d; @@ -231,6 +252,156 @@ static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) #endif } +static void smb_transaction(PIIX4PMState *s) +{ + uint8_t prot = (s->smb_ctl >> 2) & 0x07; + uint8_t read = s->smb_addr & 0x01; + uint8_t cmd = s->smb_cmd; + uint8_t addr = s->smb_addr >> 1; + SMBusDevice *dev = s->smb_dev[addr]; + +#ifdef DEBUG + printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); +#endif + if (!dev) goto error; + + switch(prot) { + case 0x0: + if (!dev->quick_cmd) goto error; + (*dev->quick_cmd)(dev, read); + break; + case 0x1: + if (read) { + if (!dev->receive_byte) goto error; + s->smb_data0 = (*dev->receive_byte)(dev); + } + else { + if (!dev->send_byte) goto error; + (*dev->send_byte)(dev, cmd); + } + break; + case 0x2: + if (read) { + if (!dev->read_byte) goto error; + s->smb_data0 = (*dev->read_byte)(dev, cmd); + } + else { + if (!dev->write_byte) goto error; + (*dev->write_byte)(dev, cmd, s->smb_data0); + } + break; + case 0x3: + if (read) { + uint16_t val; + if (!dev->read_word) goto error; + val = (*dev->read_word)(dev, cmd); + s->smb_data0 = val; + s->smb_data1 = val >> 8; + } + else { + if (!dev->write_word) goto error; + (*dev->write_word)(dev, cmd, (s->smb_data1 << 8) | s->smb_data0); + } + break; + case 0x5: + if (read) { + if (!dev->read_block) goto error; + s->smb_data0 = (*dev->read_block)(dev, cmd, s->smb_data); + } + else { + if (!dev->write_block) goto error; + (*dev->write_block)(dev, cmd, s->smb_data0, s->smb_data); + } + break; + default: + goto error; + } + return; + + error: + s->smb_stat |= 0x04; +} + +static void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PIIX4PMState *s = opaque; + addr &= 0x3f; +#ifdef DEBUG + printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val); +#endif + switch(addr) { + case SMBHSTSTS: + s->smb_stat = 0; + s->smb_index = 0; + break; + case SMBHSTCNT: + s->smb_ctl = val; + if (val & 0x40) + smb_transaction(s); + break; + case SMBHSTCMD: + s->smb_cmd = val; + break; + case SMBHSTADD: + s->smb_addr = val; + break; + case SMBHSTDAT0: + s->smb_data0 = val; + break; + case SMBHSTDAT1: + s->smb_data1 = val; + break; + case SMBBLKDAT: + s->smb_data[s->smb_index++] = val; + if (s->smb_index > 31) + s->smb_index = 0; + break; + default: + break; + } +} + +static uint32_t smb_ioport_readb(void *opaque, uint32_t addr) +{ + PIIX4PMState *s = opaque; + uint32_t val; + + addr &= 0x3f; + switch(addr) { + case SMBHSTSTS: + val = s->smb_stat; + break; + case SMBHSTCNT: + s->smb_index = 0; + val = s->smb_ctl & 0x1f; + break; + case SMBHSTCMD: + val = s->smb_cmd; + break; + case SMBHSTADD: + val = s->smb_addr; + break; + case SMBHSTDAT0: + val = s->smb_data0; + break; + case SMBHSTDAT1: + val = s->smb_data1; + break; + case SMBBLKDAT: + val = s->smb_data[s->smb_index++]; + if (s->smb_index > 31) + s->smb_index = 0; + break; + default: + val = 0; + break; + } +#ifdef DEBUG + printf("SMB readb port=0x%04x val=0x%02x\n", addr, val); +#endif + return val; +} + static void pm_io_space_update(PIIX4PMState *s) { uint32_t pm_io_base; @@ -302,6 +473,7 @@ void piix4_pm_init(PCIBus *bus, int devfn) { PIIX4PMState *s; uint8_t *pci_conf; + uint32_t pm_io_base, smb_io_base; s = (PIIX4PMState *)pci_register_device(bus, "PM", sizeof(PIIX4PMState), @@ -332,7 +504,20 @@ void piix4_pm_init(PCIBus *bus, int devfn) pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) | (serial_hds[1] != NULL ? 0x90 : 0); + smb_io_base = SMB_IO_BASE; + pci_conf[0x90] = smb_io_base | 1; + pci_conf[0x91] = smb_io_base >> 8; + pci_conf[0xd2] = 0x09; + register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, s); + register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s); + s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s); + piix4_pm_state = s; +} + +void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr) +{ + piix4_pm_state->smb_dev[addr] = dev; } diff --git a/hw/pc.c b/hw/pc.c index 73f7609ae..05802bca9 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -699,7 +699,13 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } if (pci_enabled && acpi_enabled) { + uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ piix4_pm_init(pci_bus, piix3_devfn + 3); + for (i = 0; i < 8; i++) { + SMBusDevice *eeprom = smbus_eeprom_device_init(0x50 + i, + eeprom_buf + (i * 256)); + piix4_smbus_register_device(eeprom, 0x50 + i); + } } if (i440fx_state) { diff --git a/hw/smbus.h b/hw/smbus.h new file mode 100644 index 000000000..76fc3c839 --- /dev/null +++ b/hw/smbus.h @@ -0,0 +1,38 @@ +/* + * QEMU SMBus API + * + * Copyright (c) 2007 Arastra, Inc. + * + * 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. + */ + +typedef struct SMBusDevice SMBusDevice; + +struct SMBusDevice { + uint8_t addr; + void (*quick_cmd)(SMBusDevice *dev, uint8_t read); + void (*send_byte)(SMBusDevice *dev, uint8_t val); + uint8_t (*receive_byte)(SMBusDevice *dev); + void (*write_byte)(SMBusDevice *dev, uint8_t cmd, uint8_t val); + uint8_t (*read_byte)(SMBusDevice *dev, uint8_t cmd); + void (*write_word)(SMBusDevice *dev, uint8_t cmd, uint16_t val); + uint16_t (*read_word)(SMBusDevice *dev, uint8_t cmd); + void (*write_block)(SMBusDevice *dev, uint8_t cmd, uint8_t len, uint8_t *buf); + uint8_t (*read_block)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf); +}; diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c new file mode 100644 index 000000000..d401b1756 --- /dev/null +++ b/hw/smbus_eeprom.c @@ -0,0 +1,94 @@ +/* + * QEMU SMBus EEPROM device + * + * Copyright (c) 2007 Arastra, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "vl.h" + +//#define DEBUG + +typedef struct SMBusEEPROMDevice { + SMBusDevice dev; + uint8_t *data; + uint8_t offset; +} SMBusEEPROMDevice; + +static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read) +{ +#ifdef DEBUG + printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->addr, read); +#endif +} + +static void eeprom_send_byte(SMBusDevice *dev, uint8_t val) +{ + SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; +#ifdef DEBUG + printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n", dev->addr, val); +#endif + eeprom->offset = val; +} + +static uint8_t eeprom_receive_byte(SMBusDevice *dev) +{ + SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; + uint8_t val = eeprom->data[eeprom->offset++]; +#ifdef DEBUG + printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n", dev->addr, val); +#endif + return val; +} + +static void eeprom_write_byte(SMBusDevice *dev, uint8_t cmd, uint8_t val) +{ + SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; +#ifdef DEBUG + printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", dev->addr, + cmd, val); +#endif + eeprom->data[cmd] = val; +} + +static uint8_t eeprom_read_byte(SMBusDevice *dev, uint8_t cmd) +{ + SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; + uint8_t val = eeprom->data[cmd]; +#ifdef DEBUG + printf("eeprom_read_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", dev->addr, + cmd, val); +#endif + return val; +} + +SMBusDevice *smbus_eeprom_device_init(uint8_t addr, uint8_t *buf) +{ + SMBusEEPROMDevice *eeprom = qemu_mallocz(sizeof(SMBusEEPROMDevice)); + eeprom->dev.addr = addr; + eeprom->dev.quick_cmd = eeprom_quick_cmd; + eeprom->dev.send_byte = eeprom_send_byte; + eeprom->dev.receive_byte = eeprom_receive_byte; + eeprom->dev.write_byte = eeprom_write_byte; + eeprom->dev.read_byte = eeprom_read_byte; + eeprom->data = buf; + eeprom->offset = 0; + return (SMBusDevice *) eeprom; +} diff --git a/vl.h b/vl.h index a46e4050f..d492f3e7b 100644 --- a/vl.h +++ b/vl.h @@ -1048,11 +1048,17 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); void pcspk_init(PITState *); int pcspk_audio_init(AudioState *); +#include "hw/smbus.h" + /* acpi.c */ extern int acpi_enabled; void piix4_pm_init(PCIBus *bus, int devfn); +void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); void acpi_bios_init(void); +/* smbus_eeprom.c */ +SMBusDevice *smbus_eeprom_device_init(uint8_t addr, uint8_t *buf); + /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; -- cgit v1.2.3 From 33ef55bd96d89b3259922438a7c45958438e364c Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Feb 2007 03:30:54 +0000 Subject: Mingw build fix, by Johannes Schindelin. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2380 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index daeec82e8..574452da8 100644 --- a/vl.c +++ b/vl.c @@ -1875,6 +1875,7 @@ static CharDriverState *qemu_chr_open_pty(void) #ifdef _WIN32 typedef struct { + CharDriverState *chr; int max_size; HANDLE hcom, hrecv, hsend; OVERLAPPED orecv, osend; @@ -1916,7 +1917,7 @@ static void win_chr_close(CharDriverState *chr) win_chr_close2(s); } -static int win_chr_init(WinCharState *s, const char *filename) +static int win_chr_init(WinCharState *s, CharDriverState *chr, const char *filename) { COMMCONFIG comcfg; COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; @@ -1974,6 +1975,7 @@ static int win_chr_init(WinCharState *s, const char *filename) fprintf(stderr, "Failed ClearCommError\n"); goto fail; } + s->chr = chr; qemu_add_polling_cb(win_chr_poll, s); return 0; @@ -2086,7 +2088,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename) chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; - if (win_chr_init(s, filename) < 0) { + if (win_chr_init(s, chr, filename) < 0) { free(s); free(chr); return NULL; -- cgit v1.2.3 From b49d07ba03bd727f198d92749147ec1a9bee6509 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Feb 2007 03:57:09 +0000 Subject: Use target_ulong type for emulator registers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2381 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index a2704e5f1..fcf0698aa 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -226,9 +226,9 @@ static inline TranslationBlock *tb_find_fast(void) int cpu_exec(CPUState *env1) { - int saved_T0, saved_T1; + target_ulong saved_T0, saved_T1; #if defined(reg_T2) - int saved_T2; + target_ulong saved_T2; #endif CPUState *saved_env; #if defined(TARGET_I386) @@ -262,7 +262,8 @@ int cpu_exec(CPUState *env1) #endif #endif #if defined(__sparc__) && !defined(HOST_SOLARIS) - int saved_i7, tmp_T0; + int saved_i7; + target_ulong tmp_T0; #endif int ret, interrupt_request; void (*gen_func)(void); -- cgit v1.2.3 From fa2948167f9dadfe9fd079f1e278742efae4d89f Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Feb 2007 22:05:00 +0000 Subject: sem* and msg* for qemu, part1, by Kirill Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2382 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 21f559ebc..2b37aa809 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1114,6 +1115,12 @@ static struct shm_region { uint32_t size; } shm_regions[N_SHM_REGIONS]; +union semun { + int val; + struct senid_ds *buf; + unsigned short *array; +}; + /* ??? This only works with linear mappings. */ static long do_ipc(long call, long first, long second, long third, long ptr, long fifth) @@ -1128,6 +1135,23 @@ static long do_ipc(long call, long first, long second, long third, call &= 0xffff; switch (call) { + case IPCOP_semop: + ret = get_errno(semop(first,(struct sembuf *) ptr, second)); + break; + + case IPCOP_semget: + ret = get_errno(semget(first, second, third)); + break; + + case IPCOP_semctl: + ret = get_errno(semctl(first, second, third, ((union semun*)ptr)->val)); + + break; + + case IPCOP_semtimedop: + gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version); + ret = -ENOSYS; + break; case IPCOP_shmat: /* SHM_* flags are the same on all linux platforms */ ret = get_errno((long) shmat(first, (void *) ptr, second)); -- cgit v1.2.3 From d96372efaaee2dffea3bd4367b8395f3743fcea5 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Feb 2007 22:05:44 +0000 Subject: sem* and msg* for qemu, part2, by Kirill Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2383 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2b37aa809..45c8f2939 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1152,6 +1152,35 @@ static long do_ipc(long call, long first, long second, long third, gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version); ret = -ENOSYS; break; + + case IPCOP_msgget: + ret = get_errno(msgget(first, second)); + break; + + case IPCOP_msgsnd: + ret = get_errno(msgsnd(first, (struct msgbuf *) ptr, second, third)); + break; + + case IPCOP_msgctl: + ret = get_errno(msgctl(first, second, (struct msqid_ds *) ptr)); + break; + + case IPCOP_msgrcv: + { + struct ipc_kludge + { + void *__unbounded msgp; + long int msgtyp; + }; + + struct ipc_kludge *foo = (struct ipc_kludge *) ptr; + struct msgbuf *msgp = (struct msgbuf *) foo->msgp; + + ret = get_errno(msgrcv(first, msgp, second, 0, third)); + + } + break; + case IPCOP_shmat: /* SHM_* flags are the same on all linux platforms */ ret = get_errno((long) shmat(first, (void *) ptr, second)); -- cgit v1.2.3 From 1057eaa709dba09d1c4f7a363877e635797e4623 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 4 Feb 2007 13:37:44 +0000 Subject: Fix 64-bit host register corruption. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2384 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 103 +++++------------------------------------------------- dyngen-exec.h | 3 ++ hostregs_helper.h | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 94 deletions(-) create mode 100644 hostregs_helper.h diff --git a/cpu-exec.c b/cpu-exec.c index fcf0698aa..0b57f0fdc 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -226,37 +226,9 @@ static inline TranslationBlock *tb_find_fast(void) int cpu_exec(CPUState *env1) { - target_ulong saved_T0, saved_T1; -#if defined(reg_T2) - target_ulong 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) +#define DECLARE_HOST_REGS 1 +#include "hostregs_helper.h" +#if defined(TARGET_SPARC) #if defined(reg_REGWPTR) uint32_t *saved_regwptr; #endif @@ -325,44 +297,15 @@ int cpu_exec(CPUState *env1) cpu_single_env = env1; /* first we save global registers */ - saved_env = env; +#define SAVE_HOST_REGS 1 +#include "hostregs_helper.h" 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); @@ -827,32 +770,6 @@ int cpu_exec(CPUState *env1) #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) @@ -871,15 +788,13 @@ int cpu_exec(CPUState *env1) #else #error unsupported target CPU #endif + + /* restore global registers */ #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; +#include "hostregs_helper.h" + /* fail safe : never use cpu_single_env outside cpu_exec() */ cpu_single_env = NULL; return ret; diff --git a/dyngen-exec.h b/dyngen-exec.h index 2f3878561..7b313d62c 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -62,6 +62,9 @@ typedef signed long long int64_t; #endif #endif +/* XXX: This may be wrong for 64-bit ILP32 hosts. */ +typedef void * host_reg_t; + #define INT8_MIN (-128) #define INT16_MIN (-32767-1) #define INT32_MIN (-2147483647-1) diff --git a/hostregs_helper.h b/hostregs_helper.h new file mode 100644 index 000000000..4fdf8ad96 --- /dev/null +++ b/hostregs_helper.h @@ -0,0 +1,98 @@ +/* + * Save/restore host registrs. + * + * Copyright (c) 2007 CodeSourcery + * + * 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 + */ + +/* The GCC global register vairable extension is used to reserve some + host registers for use by dyngen. However only the core parts of the + translation engine are compiled with these settings. We must manually + save/restore these registers when called from regular code. + It is not sufficient to save/restore T0 et. al. as these may be declared + with a datatype smaller than the actual register. */ + +#if defined(DECLARE_HOST_REGS) + +#define DO_REG(REG) \ + register host_reg_t reg_AREG##REG asm(AREG##REG); \ + volatile host_reg_t saved_AREG##REG; + +#elif defined(SAVE_HOST_REGS) + +#define DO_REG(REG) \ + __asm__ __volatile__ ("" : "=r" (reg_AREG##REG)); \ + saved_AREG##REG = reg_AREG##REG; + +#else + +#define DO_REG(REG) \ + reg_AREG##REG = saved_AREG##REG; \ + __asm__ __volatile__ ("" : : "r" (reg_AREG##REG)); + +#endif + +#ifdef AREG0 +DO_REG(0) +#endif + +#ifdef AREG1 +DO_REG(1) +#endif + +#ifdef AREG2 +DO_REG(2) +#endif + +#ifdef AREG3 +DO_REG(3) +#endif + +#ifdef AREG4 +DO_REG(4) +#endif + +#ifdef AREG5 +DO_REG(5) +#endif + +#ifdef AREG6 +DO_REG(6) +#endif + +#ifdef AREG7 +DO_REG(7) +#endif + +#ifdef AREG8 +DO_REG(8) +#endif + +#ifdef AREG9 +DO_REG(9) +#endif + +#ifdef AREG10 +DO_REG(10) +#endif + +#ifdef AREG11 +DO_REG(11) +#endif + +#undef SAVE_HOST_REGS +#undef DECLARE_HOST_REGS +#undef DO_REG -- cgit v1.2.3 From 4fe8b87a7c08275530f9ed29b1f7570b6feb559a Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 19:38:35 +0000 Subject: gcc version git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2385 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 34f5a59d6..17b03cefd 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1865,39 +1865,15 @@ make install @end example to install QEMU in @file{/usr/local}. -@subsection Tested tool versions +@subsection GCC version In order to compile QEMU successfully, it is very important that you -have the right tools. The most important one is gcc. I cannot guaranty -that QEMU works if you do not use a tested gcc version. Look at -'configure' and 'Makefile' if you want to make a different gcc -version work. - -@example -host gcc binutils glibc linux distribution ----------------------------------------------------------------------- -x86 3.2 2.13.2 2.1.3 2.4.18 - 2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3 - 3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9 - -PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq - 3.2 - -Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0 - -Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0 - -ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0 - -[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available - for gcc version >= 3.3. -[2] Linux >= 2.4.20 is necessary for precise exception support - (untested). -[3] 2.4.9-ac10-rmk2-np1-cerf2 - -[4] gcc 2.95.x generates invalid code when using too many register -variables. You must use gcc 3.x on PowerPC. -@end example +have the right tools. The most important one is gcc. On most hosts and +in particular on x86 ones, @emph{gcc 4.x is not supported}. If your +Linux distribution includes a gcc 4.x compiler, you can usually +install an older version (it is invoked by @code{gcc32} or +@code{gcc34}). The QEMU configure script automatically probes for +these older versions so that usally you don't have to do anything. @node Windows @section Windows -- cgit v1.2.3 From 831952376ebb4b18370048172c61159580f4b8dc Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 19:42:07 +0000 Subject: Darwin user help (Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2386 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 115 insertions(+), 9 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 17b03cefd..834c77855 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -25,7 +25,7 @@ * Installation:: * QEMU PC System emulator:: * QEMU System emulator for non PC targets:: -* QEMU Linux User space emulator:: +* QEMU User space emulator:: * compilation:: Compilation from the sources * Index:: @end menu @@ -57,8 +57,8 @@ peripherals. It can be used to launch different Operating Systems without rebooting the PC or to debug system code. @item -User mode emulation (Linux host only). In this mode, QEMU can launch -Linux processes compiled for one CPU on another CPU. It can be used to +User mode emulation. In this mode, QEMU can launch +processes compiled for one CPU on another CPU. It can be used to launch the Wine Windows API emulator (@url{http://www.winehq.org}) or to ease cross-compilation and cross-debugging. @@ -1704,8 +1704,29 @@ LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices. A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. -@node QEMU Linux User space emulator -@chapter QEMU Linux User space emulator +@node QEMU User space emulator +@chapter QEMU User space emulator + +@menu +* Supported Operating Systems :: +* Linux User space emulator:: +* Mac OS X/Darwin User space emulator :: +@end menu + +@node Supported Operating Systems +@section Supported Operating Systems + +The following OS are supported in user space emulation: + +@itemize @minus +@item +Linux (refered as qemu-linux-user) +@item +Mac OS X/Darwin (refered as qemu-darwin-user) +@end itemize + +@node Linux User space emulator +@section Linux User space emulator @menu * Quick Start:: @@ -1715,7 +1736,7 @@ information is available in the QEMU mailing-list archive. @end menu @node Quick Start -@section Quick Start +@subsection Quick Start In order to launch a Linux process, QEMU needs the process executable itself and all the target (x86) dynamic libraries used by it. @@ -1765,7 +1786,7 @@ qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 \ @end itemize @node Wine launch -@section Wine launch +@subsection Wine launch @itemize @@ -1794,7 +1815,7 @@ qemu-i386 /usr/local/qemu-i386/wine/bin/wine \ @end itemize @node Command line options -@section Command line options +@subsection Command line options @example usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] @@ -1819,7 +1840,7 @@ Act as if the host page size was 'pagesize' bytes @end table @node Other binaries -@section Other binaries +@subsection Other binaries @command{qemu-arm} is also capable of running ARM "Angel" semihosted ELF binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB @@ -1831,6 +1852,91 @@ coldfire uClinux bFLT format binaries. The binary format is detected automatically. +@node Mac OS X/Darwin User space emulator +@section Mac OS X/Darwin User space emulator + +@menu +* Mac OS X/Darwin Status:: +* Mac OS X/Darwin Quick Start:: +* Mac OS X/Darwin Command line options:: +@end menu + +@node Mac OS X/Darwin Status +@subsection Mac OS X/Darwin Status + +@itemize @minus +@item +target x86 on x86: Most apps (Cocoa and Carbon too) works. [1] +@item +target PowerPC on x86: Not working as the ppc commpage can't be mapped (yet!) +@item +target x86 on x86: Most apps (Cocoa and Carbon too) works. [1] +@item +target x86 on PowerPC: most utilities work. Cocoa and Carbon apps are not yet supported. +@end itemize + +[1] If you're host commpage can be executed by qemu. + +@node Mac OS X/Darwin Quick Start +@subsection Quick Start + +In order to launch a Mac OS X/Darwin process, QEMU needs the process executable +itself and all the target dynamic libraries used by it. If you don't have the FAT +libraries (you're running Mac OS X/ppc) you'll need to obtain it from a Mac OS X +CD or compile them by hand. + +@itemize + +@item On x86, you can just try to launch any process by using the native +libraries: + +@example +qemu-darwin-i386 /bin/ls +@end example + +or to run the ppc version of the executable: + +@example +qemu-darwin-ppc /bin/ls +@end example + +@item On ppc, you'll have to tell qemu where your x86 libraries (and dynamic linker) +are installed: + +@example +qemu-darwin-i386 -L /opt/x86_root/ /bin/ls +@end example + +@code{-L /opt/x86_root/} tells that the dynamic linker (dyld) path is in +@file{/opt/x86_root/usr/bin/dyld}. + +@end itemize + +@node Mac OS X/Darwin Command line options +@subsection Command line options + +@example +usage: qemu-darwin-i386 [-h] [-d] [-L path] [-s size] program [arguments...] +@end example + +@table @option +@item -h +Print the help +@item -L path +Set the library root path (default=/) +@item -s size +Set the stack size in bytes (default=524288) +@end table + +Debug options: + +@table @option +@item -d +Activate log (logfile=/tmp/qemu.log) +@item -p pagesize +Act as if the host page size was 'pagesize' bytes +@end table + @node compilation @chapter Compilation from the sources -- cgit v1.2.3 From 1e2bed4f7e08f2d1d3191cd03d66067e809659f7 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 19:43:27 +0000 Subject: Darwin cleanup usage (Pierre d'Herbemont) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2387 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/darwin-user/main.c b/darwin-user/main.c index 5a2bc299e..78cf864c1 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -646,17 +646,18 @@ void usage(void) "Darwin CPU emulator (compiled for %s emulation)\n" "\n" "-h print this help\n" - "-L path set the elf interpreter prefix (default=%s)\n" + "-L path set the %s library path (default='%s')\n" "-s size set the stack size in bytes (default=%ld)\n" "\n" "debug options:\n" #ifdef USE_CODE_COPY "-no-code-copy disable code copy acceleration\n" #endif - "-d options activate log (logfile=%s)\n" + "-d options activate log (logfile='%s')\n" "-g wait for gdb on port 1234\n" "-p pagesize set the host page size to 'pagesize'\n", TARGET_ARCH, + TARGET_ARCH, interp_prefix, stack_size, DEBUG_LOGFILE); @@ -753,11 +754,6 @@ int main(int argc, char **argv) /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); -#if 0 - /* Scan interp_prefix dir for replacement files. */ - init_paths(interp_prefix); -#endif - /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ env = cpu_init(); @@ -888,7 +884,7 @@ int main(int argc, char **argv) set_idt(0x81, 3); /* Mach Syscalls */ set_idt(0x82, 3); /* thread Syscalls */ - set_idt(0x90, 3); /* Unix Syscall backdoor */ + set_idt(0x90, 3); /* qemu-darwin-user's Unix syscalls backdoor */ cpu_x86_load_seg(env, R_CS, __USER_CS); -- cgit v1.2.3 From 263466f53aa70597b48b415a3a49d6f2e4511f77 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 19:47:42 +0000 Subject: This patch cleans up target_mach_msg_trap(), removes unuseful do_pread, begins sysctl implementation and implements fcntl (Pierre d'Herbemont). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2388 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/syscall.c | 348 +++++++++++++++++++++++++++++++++++++++---------- darwin-user/syscalls.h | 4 +- 2 files changed, 282 insertions(+), 70 deletions(-) diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c index 50725e633..f2543aa44 100644 --- a/darwin-user/syscall.c +++ b/darwin-user/syscall.c @@ -23,9 +23,10 @@ #include #include -#include +#include #include #include +#include #include #include @@ -208,15 +209,14 @@ static inline void print_mach_msg_return(mach_msg_return_t ret) else { for( i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) { - if(msg_name[0].code & ret) { - DPRINTF("%s ", msg_name[0].name); + if(msg_name[i].code == ret) { + DPRINTF("%s\n", msg_name[i].name); found = 1; + break; } } if(!found) qerror("unknow mach message ret code %d\n", ret); - else - DPRINTF("\n"); } } @@ -235,11 +235,10 @@ struct complex_msg { mach_msg_body_t body; }; -static inline void * swap_mach_msg_body(struct complex_msg *complex_msg, int bswap) +static inline void swap_mach_msg_body(struct complex_msg *complex_msg, int bswap) { mach_msg_port_descriptor_t *descr = (mach_msg_port_descriptor_t *)(complex_msg+1); int i,j; - void *additional_data; if(bswap == bswap_in) tswap32s(&complex_msg->body.msgh_descriptor_count); @@ -292,41 +291,41 @@ static inline void * swap_mach_msg_body(struct complex_msg *complex_msg, int bsw } if(bswap == bswap_out) tswap32s(&complex_msg->body.msgh_descriptor_count); - additional_data = descr; - return additional_data; +} + +static inline void swap_mach_msg(mach_msg_header_t *hdr, int bswap) +{ + if (bswap == bswap_out && hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) + swap_mach_msg_body((struct complex_msg *)hdr, bswap); + + swap_mach_msg_header(hdr); + + if (bswap == bswap_in && hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) + swap_mach_msg_body((struct complex_msg *)hdr, bswap); } static inline uint32_t target_mach_msg_trap( mach_msg_header_t *hdr, uint32_t options, uint32_t send_size, - uint32_t rcv_size, uint32_t rcv_name, uint32_t time_out, uint32_t notify ) + uint32_t rcv_size, uint32_t rcv_name, uint32_t time_out, uint32_t notify) { - extern int mach_msg_trap(mach_msg_header_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + extern int mach_msg_trap(mach_msg_header_t *, mach_msg_option_t, + mach_msg_size_t, mach_msg_size_t, mach_port_t, + mach_msg_timeout_t, mach_port_t); mach_msg_audit_trailer_t *trailer; mach_msg_id_t msg_id; uint32_t ret = 0; - char *additional_data; int i; - swap_mach_msg_header(hdr); - - print_description_msg_header(hdr); + swap_mach_msg(hdr, bswap_in); msg_id = hdr->msgh_id; - if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) - additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_in); - else - additional_data = (void*)(hdr+1); + print_description_msg_header(hdr); ret = mach_msg_trap(hdr, options, send_size, rcv_size, rcv_name, time_out, notify); print_mach_msg_return(ret); - if (hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX) - additional_data = swap_mach_msg_body((struct complex_msg *)hdr, bswap_out); - else - additional_data = (void*)(hdr+1); - if( (options & MACH_RCV_MSG) && (REQUESTED_TRAILER_SIZE(options) > 0) ) { /* XXX: the kernel always return the full trailer with MACH_SEND_MSG, so we should @@ -368,33 +367,20 @@ static inline uint32_t target_mach_msg_trap( case 200: /* host_info */ { mig_reply_error_t *err = (mig_reply_error_t *)hdr; - struct { - uint32_t unknow1; - uint32_t maxcpu; - uint32_t numcpu; - uint32_t memsize; - uint32_t cpu_type; - uint32_t cpu_subtype; - } *data = (void *)(err+1); - - DPRINTF("maxcpu = 0x%x\n", data->maxcpu); - DPRINTF("numcpu = 0x%x\n", data->maxcpu); - DPRINTF("memsize = 0x%x\n", data->memsize); + struct host_basic_info *data = (void *)(err+1); + + DPRINTF("maxcpu = 0x%x\n", data->max_cpus); + DPRINTF("numcpu = 0x%x\n", data->avail_cpus); + DPRINTF("memsize = 0x%x\n", data->memory_size); #if defined(TARGET_I386) data->cpu_type = CPU_TYPE_I386; DPRINTF("cpu_type changed to 0x%x(i386)\n", data->cpu_type); -#elif defined(TARGET_PPC) - data->cpu_type = CPU_TYPE_POWERPC; - DPRINTF("cpu_type changed to 0x%x(ppc)\n", data->cpu_type); -#else -# error target not supported -#endif - -#if defined(TARGET_I386) data->cpu_subtype = CPU_SUBTYPE_PENT; DPRINTF("cpu_subtype changed to 0x%x(i386_pent)\n", data->cpu_subtype); #elif defined(TARGET_PPC) + data->cpu_type = CPU_TYPE_POWERPC; + DPRINTF("cpu_type changed to 0x%x(ppc)\n", data->cpu_type); data->cpu_subtype = CPU_SUBTYPE_POWERPC_750; DPRINTF("cpu_subtype changed to 0x%x(ppc_all)\n", data->cpu_subtype); #else @@ -413,7 +399,7 @@ static inline uint32_t target_mach_msg_trap( default: break; } - swap_mach_msg_header(hdr); + swap_mach_msg(hdr, bswap_out); return ret; } @@ -827,19 +813,29 @@ long do_fstat(uint32_t arg1, struct stat * arg2); long do_lstat(char * arg1, struct stat * arg2); long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4); long do_lseek(void *cpu_env, int num); -long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6); +long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, void * newp, size_t newlen /* ignored */); long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5); long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8); +long do_fcntl(int fd, int cmd, int arg); long no_syscall(void *cpu_env, int num); long do_pread(uint32_t arg1, void * arg2, size_t arg3, off_t arg4) { - //DPRINTF("0x%x, 0x%x, 0x%x, 0x%llx\n", arg1, arg2, arg3, arg4); - long ret = (pread(arg1, arg2, arg3, arg4)); - DPRINTF("0x%x\n", *(int*)arg2); + DPRINTF("0x%x, %p, 0x%lx, 0x%llx\n", arg1, arg2, arg3, arg4); + long ret = pread(arg1, arg2, arg3, arg4); + return ret; +} + +long do_read(int d, void *buf, size_t nbytes) +{ + DPRINTF("0x%x, %p, 0x%lx\n", d, buf, nbytes); + long ret = get_errno(read(d, buf, nbytes)); + if(!is_error(ret)) + DPRINTF("%x\n", *(uint32_t*)buf); return ret; } + long unimpl_unix_syscall(void *cpu_env, int num); typedef long (*syscall_function_t)(void *cpu_env, int num); @@ -1199,33 +1195,163 @@ long do_lseek(void *cpu_env, int num) return get_errno(ret); } -long do___sysctl(void * arg1, uint32_t arg2, void * arg3, void * arg4, void * arg5, size_t arg6) +void no_swap(void * oldp, int size) +{ +} + +void sysctl_tswap32s(void * oldp, int size) +{ + tswap32s(oldp); +} + +void bswap_oid(uint32_t * oldp, int size) +{ + int count = size / sizeof(int); + int i = 0; + do { tswap32s(oldp + i); } while (++i < count); +} + +void sysctl_usrstack(uint32_t * oldp, int size) +{ + DPRINTF("sysctl_usrstack: 0x%x\n", *oldp); + tswap32s(oldp); +} + +void sysctl_ncpu(uint32_t * ncpu, int size) +{ + *ncpu = 0x1; + DPRINTF("sysctl_ncpu: 0x%x\n", *ncpu); + tswap32s(ncpu); +} + +void sysctl_exec(char * exec, int size) +{ + DPRINTF("sysctl_exec: %s\n", exec); +} + +void sysctl_translate(char * exec, int size) +{ + DPRINTF("sysctl_translate: %s\n", exec); +} + +struct sysctl_dir { + int num; + const char * name; + void (*swap_func)(void *, int); + struct sysctl_dir *childs; +}; + +#define ENTRYD(num, name, childs) { num, name, NULL, childs } +#define ENTRYE(num, name, func) { num, name, (void (*)(void *, int))func, NULL } +struct sysctl_dir sysctls_unspec[] = { + ENTRYE(3, "oip", bswap_oid), + { 0, NULL, NULL, NULL } +}; + +struct sysctl_dir sysctls_kern[] = { + ENTRYE(KERN_TRANSLATE, "translate", sysctl_translate), /* 44 */ + ENTRYE(KERN_EXEC, "exec", sysctl_exec), /* 45 */ + ENTRYE(KERN_USRSTACK32, "KERN_USRSTACK32", sysctl_usrstack), /* 35 */ + ENTRYE(KERN_SHREG_PRIVATIZABLE, "KERN_SHREG_PRIVATIZABLE", sysctl_tswap32s), /* 54 */ + { 0, NULL, NULL, NULL } +}; + +struct sysctl_dir sysctls_hw[] = { + ENTRYE(HW_NCPU, "ncpud", sysctl_tswap32s), + ENTRYE(104, "104", no_swap), + ENTRYE(105, "105", no_swap), + { 0, NULL, NULL, NULL } +}; + +struct sysctl_dir sysctls[] = { + ENTRYD(CTL_UNSPEC, "unspec", sysctls_unspec), + ENTRYD(CTL_KERN, "kern", sysctls_kern), + ENTRYD(CTL_HW, "hw", sysctls_hw ), + { 0, NULL, NULL, NULL } +}; + +#undef ENTRYE +#undef ENTRYD + +static inline struct sysctl_dir * get_sysctl_entry_for_mib(int mib, struct sysctl_dir * sysctl_elmt) +{ + if(!sysctl_elmt) + return NULL; + for(; sysctl_elmt->name != NULL ; sysctl_elmt++) { + if(sysctl_elmt->num == mib) + return sysctl_elmt; + } + return NULL; +} + +static inline long bswap_syctl(int * mib, int count, void *buf, int size) +{ + int i; + struct sysctl_dir * sysctl = sysctls; + struct sysctl_dir * ret = NULL; + + for(i = 0; i < count; i++) { + + if(!(ret = sysctl = get_sysctl_entry_for_mib(mib[i], sysctl))) { + gemu_log("bswap_syctl: can't find mib %d\n", mib[i]); + return -ENOTDIR; + } + if(!(sysctl = sysctl->childs)) + break; + } + + if(ret->childs) + qerror("we shouldn't have a directory element\n"); + + ret->swap_func(buf, size); + return 0; +} + +static inline void print_syctl(int * mib, int count) +{ + int i; + struct sysctl_dir * sysctl = sysctls; + struct sysctl_dir * ret = NULL; + + for(i = 0; i < count; i++) { + if(!(ret = sysctl = get_sysctl_entry_for_mib(mib[i], sysctl))){ + gemu_log("print_syctl: can't find mib %d\n", mib[i]); + return; + } + DPRINTF("%s.", sysctl->name); + if(!(sysctl = sysctl->childs)) + break; + } + DPRINTF("\n"); +} + +long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, void * newp, size_t newlen /* ignored */) { long ret = 0; int i; DPRINTF("sysctl(%p, 0x%x, %p, %p, %p, 0x%lx)\n", - arg1, arg2, arg3, arg4, arg5, arg6); - if(arg1) { + name, namelen, oldp, oldlenp, newp, newlen); + if(name) { i = 0; - do { *((int *) arg1 + i) = tswap32(*((int *) arg1 + i)); } while (++i < arg2); + do { tswap32s( name + i); } while (++i < namelen); + print_syctl(name, namelen); + //bswap_syctl(name, namelen, newp, newlen); + tswap32s((uint32_t*)oldlenp); } + + if(name) /* Sometimes sysctl is called with no arg1, ignore */ + ret = get_errno(sysctl(name, namelen, oldp, oldlenp, newp, newlen)); - if(arg4) - *(int *) arg4 = tswap32(*(int *) arg4); - if(arg1) - ret = get_errno(sysctl((void *)arg1, arg2, (void *)arg3, (void *)arg4, (void *)arg5, arg6)); - - if ((ret == 0) && (arg2 == 2) && (*((int *) arg1) == 0) && (*((int *) arg1 + 1) == 3)) { - /* The output here is the new id - we need to swap it so it can be passed - back in (and then unswapped) */ - int count = (*(int *) arg4) / sizeof(int); - i = 0; - do { - *((int *) arg3 + i) = tswap32(*((int *) arg3 + i)); - } while (++i < count); + if (!is_error(ret) && bswap_syctl(name, namelen, oldp, *oldlenp) != 0) { + return -ENOTDIR; } - *(int *) arg4 = tswap32(*(int *) arg4); + if(name) { + //bswap_syctl(name, namelen, newp, newlen); + tswap32s((uint32_t*)oldlenp); + i = 0; + do { tswap32s( name + i); } while (++i < namelen); + } return ret; } @@ -1235,7 +1361,8 @@ long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32 long ret; #if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) - qerror("SYS_getdirentriesattr unimplemented\n"); + gemu_log("SYS_getdirentriesattr unimplemented\n"); + return -ENOTSUP; #endif /* XXX: don't let the %s stay in there */ DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n", @@ -1268,6 +1395,91 @@ long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, (unsigned long *)arg7, arg8)); } +static inline void bswap_flock(struct flock *f) +{ + tswap64s(&f->l_start); + tswap64s(&f->l_len); + tswap32s(&f->l_pid); + tswap16s(&f->l_type); + tswap16s(&f->l_whence); +} + +static inline void bswap_fstore(struct fstore *f) +{ + tswap32s(&f->fst_flags); + tswap32s(&f->fst_posmode); + tswap64s(&f->fst_offset); + tswap64s(&f->fst_length); + tswap64s(&f->fst_bytesalloc); +} + +static inline void bswap_radvisory(struct radvisory *f) +{ + tswap64s(&f->ra_offset); + tswap32s(&f->ra_count); +} + +static inline void bswap_fbootstraptransfer(struct fbootstraptransfer *f) +{ + tswap64s(&f->fbt_offset); + tswap32s((uint32_t*)&f->fbt_length); + tswap32s((uint32_t*)&f->fbt_buffer); /* XXX: this is a ptr */ +} + +static inline void bswap_log2phys(struct log2phys *f) +{ + tswap32s(&f->l2p_flags); + tswap64s(&f->l2p_contigbytes); + tswap64s(&f->l2p_devoffset); +} + +static inline void bswap_fcntl_arg(int cmd, void * arg) +{ + switch(cmd) + { + case F_DUPFD: + case F_GETFD: + case F_SETFD: + case F_GETFL: + case F_SETFL: + case F_GETOWN: + case F_SETOWN: + case F_SETSIZE: + case F_RDAHEAD: + case F_FULLFSYNC: + break; + case F_GETLK: + case F_SETLK: + case F_SETLKW: + bswap_flock(arg); + break; + case F_PREALLOCATE: + bswap_fstore(arg); + break; + case F_RDADVISE: + bswap_radvisory(arg); + break; + case F_READBOOTSTRAP: + case F_WRITEBOOTSTRAP: + bswap_fbootstraptransfer(arg); + break; + case F_LOG2PHYS: + bswap_log2phys(arg); + break; + default: + gemu_log("unknow cmd in fcntl\n"); + } +} + +long do_fcntl(int fd, int cmd, int arg) +{ + long ret; + bswap_fcntl_arg(cmd, (void *)arg); + ret = get_errno(fcntl(fd, cmd, arg)); + if(!is_error(ret)) + bswap_fcntl_arg(cmd, (void *)arg); + return ret; +} long no_syscall(void *cpu_env, int num) { diff --git a/darwin-user/syscalls.h b/darwin-user/syscalls.h index d04295bed..7c361ce59 100644 --- a/darwin-user/syscalls.h +++ b/darwin-user/syscalls.h @@ -3,7 +3,7 @@ ENTRY("syscall", SYS_syscall, do_unix_syscall_indirect, 0, CALL_INDIRECT, VOID) /* 0 indirect syscall */ ENTRY("exit", SYS_exit, do_exit, 1, CALL_DIRECT, INT) /* 1 */ ENTRY("fork", SYS_fork, fork, 0, CALL_NOERRNO, VOID) /* 2 */ - ENTRY("read", SYS_read, read, 3, CALL_DIRECT, INT, PTR, SIZE) /* 3 */ + ENTRY("read", SYS_read, do_read, 3, CALL_DIRECT, INT, PTR, SIZE) /* 3 */ ENTRY("write", SYS_write, write, 3, CALL_DIRECT, INT, PTR, SIZE) /* 4 */ ENTRY("open", SYS_open, do_open, 3, CALL_DIRECT, PTR, INT, INT) /* 5 */ ENTRY("close", SYS_close, close, 1, CALL_DIRECT, INT) /* 6 */ @@ -92,7 +92,7 @@ ENTRY("getdtablesize", SYS_getdtablesize, getdtablesize, 0, CALL_DIRECT, VOID) /* 89 */ ENTRY("dup2", SYS_dup2, dup2, 2, CALL_DIRECT, INT, INT) /* 90 */ ENTRY("", 91, no_syscall, 0, CALL_INDIRECT, VOID) /* 91 old getdopt */ - ENTRY("fcntl", SYS_fcntl, fcntl, 3, CALL_DIRECT, INT, INT, INT) /* 92 */ + ENTRY("fcntl", SYS_fcntl, do_fcntl, 3, CALL_DIRECT, INT, INT, INT) /* 92 */ ENTRY("select", SYS_select, select, 5, CALL_DIRECT, INT, PTR, PTR, PTR, PTR) /* 93 */ ENTRY("", 94, no_syscall, 0, CALL_INDIRECT, VOID) /* 94 old setdopt */ ENTRY("fsync", SYS_fsync, fsync, 1, CALL_DIRECT, INT) /* 95 */ -- cgit v1.2.3 From 2a2528266e6834aa1dc8280ca91e334f52267365 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 19:50:01 +0000 Subject: This patch fixes typos in the commpage definition (Pierre d'Herbemont). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2389 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/commpage.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/darwin-user/commpage.c b/darwin-user/commpage.c index 12ee1da02..78a14130a 100644 --- a/darwin-user/commpage.c +++ b/darwin-user/commpage.c @@ -114,10 +114,10 @@ static struct commpage_entry commpage_entries[] = COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT), COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT), COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), - COMMPAGE_ENTRY(gettimeofday, 1, 0x2c0, do_cgettimeofday, CALL_INDIRECT), - COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), - COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), - COMMPAGE_ENTRY(pthread_self, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(gettimeofday, 1, 0x2e0, do_cgettimeofday, CALL_INDIRECT), + COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x4e0, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x520, unimpl_commpage, CALL_INDIRECT), + COMMPAGE_ENTRY(pthread_self, 0, 0x580, unimpl_commpage, CALL_INDIRECT), COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT), @@ -305,7 +305,7 @@ void do_nanotime(void *cpu_env, int num) void unimpl_commpage(void *cpu_env, int num) { - gemu_log("qemu: commpage function 0x%x not implemented\n", num); + qerror("qemu: commpage function 0x%x not implemented\n", num); } /******************************************************************** -- cgit v1.2.3 From 564c337efd415df3ab58c5bd080139e9f997d265 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 20:14:10 +0000 Subject: Mouse relative offset VNC extension (Anthony Liguori) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2390 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/vnc.c b/vnc.c index d3371671f..30dc51652 100644 --- a/vnc.c +++ b/vnc.c @@ -68,6 +68,11 @@ struct VncState int depth; /* internal VNC frame buffer byte per pixel */ int has_resize; int has_hextile; + int has_pointer_type_change; + int absolute; + int last_x; + int last_y; + Buffer output; Buffer input; kbd_layout_t *kbd_layout; @@ -671,6 +676,19 @@ static void client_cut_text(VncState *vs, size_t len, char *text) { } +static void check_pointer_type_change(VncState *vs, int absolute) +{ + if (vs->has_pointer_type_change && vs->absolute != absolute) { + vnc_write_u8(vs, 0); + vnc_write_u8(vs, 0); + vnc_write_u16(vs, 1); + vnc_framebuffer_update(vs, absolute, 0, + vs->ds->width, vs->ds->height, -257); + vnc_flush(vs); + } + vs->absolute = absolute; +} + static void pointer_event(VncState *vs, int button_mask, int x, int y) { int buttons = 0; @@ -686,21 +704,26 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) dz = -1; if (button_mask & 0x10) dz = 1; - - if (kbd_mouse_is_absolute()) { + + if (vs->absolute) { kbd_mouse_event(x * 0x7FFF / vs->ds->width, y * 0x7FFF / vs->ds->height, dz, buttons); - } else { - static int last_x = -1; - static int last_y = -1; - - if (last_x != -1) - kbd_mouse_event(x - last_x, y - last_y, dz, buttons); + } else if (vs->has_pointer_type_change) { + x -= 0x7FFF; + y -= 0x7FFF; - last_x = x; - last_y = y; + kbd_mouse_event(x, y, dz, buttons); + } else { + if (vs->last_x != -1) + kbd_mouse_event(x - vs->last_x, + y - vs->last_y, + dz, buttons); + vs->last_x = x; + vs->last_y = y; } + + check_pointer_type_change(vs, kbd_mouse_is_absolute()); } static void reset_keys(VncState *vs) @@ -829,6 +852,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) vs->has_hextile = 0; vs->has_resize = 0; + vs->has_pointer_type_change = 0; + vs->absolute = -1; vs->ds->dpy_copy = NULL; for (i = n_encodings - 1; i >= 0; i--) { @@ -845,10 +870,15 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) case -223: /* DesktopResize */ vs->has_resize = 1; break; + case -257: + vs->has_pointer_type_change = 1; + break; default: break; } } + + check_pointer_type_change(vs, kbd_mouse_is_absolute()); } static int compute_nbits(unsigned int val) @@ -1124,6 +1154,8 @@ void vnc_display_init(DisplayState *ds, const char *arg) vs->lsock = -1; vs->csock = -1; vs->depth = 4; + vs->last_x = -1; + vs->last_y = -1; vs->ds = ds; -- cgit v1.2.3 From a9ce859052ccb0d588173dfa11bc9cd6858ec6c3 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 20:20:30 +0000 Subject: info vnc command (Anthony Liguori) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2391 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 2 ++ vl.h | 1 + vnc.c | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/monitor.c b/monitor.c index 893040a17..33c482b09 100644 --- a/monitor.c +++ b/monitor.c @@ -1297,6 +1297,8 @@ static term_cmd_t info_cmds[] = { "", "show the currently saved VM snapshots" }, { "mice", "", do_info_mice, "", "show which guest mouse is receiving events" }, + { "vnc", "", do_info_vnc, + "", "show the vnc server status"}, { NULL, NULL, }, }; diff --git a/vl.h b/vl.h index d492f3e7b..ff717863f 100644 --- a/vl.h +++ b/vl.h @@ -909,6 +909,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen); /* vnc.c */ void vnc_display_init(DisplayState *ds, const char *display); +void do_info_vnc(void); /* x_keymap.c */ extern uint8_t _translate_keycode(const int key); diff --git a/vnc.c b/vnc.c index 30dc51652..f729e05d8 100644 --- a/vnc.c +++ b/vnc.c @@ -73,6 +73,8 @@ struct VncState int last_x; int last_y; + const char *display; + Buffer output; Buffer input; kbd_layout_t *kbd_layout; @@ -90,6 +92,24 @@ struct VncState uint8_t modifiers_state[256]; }; +static VncState *vnc_state; /* needed for info vnc */ + +void do_info_vnc(void) +{ + if (vnc_state == NULL) + term_printf("VNC server disabled\n"); + else { + term_printf("VNC server active on: "); + term_print_filename(vnc_state->display); + term_printf("\n"); + + if (vnc_state->csock == -1) + term_printf("No client connected\n"); + else + term_printf("Client connected\n"); + } +} + /* TODO 1) Get the queue working for IO. 2) there is some weirdness when using the -S option (the screen is grey @@ -1150,6 +1170,8 @@ void vnc_display_init(DisplayState *ds, const char *arg) exit(1); ds->opaque = vs; + vnc_state = vs; + vs->display = arg; vs->lsock = -1; vs->csock = -1; -- cgit v1.2.3 From 84f2e8ef058f5919f0e896d48edecc4c1282e092 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 20:21:32 +0000 Subject: copyright update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2392 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- qemu-img.c | 4 ++-- vl.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index c423d299b..7199372b3 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1530,7 +1530,7 @@ void cpu_loop(CPUM68KState *env) void usage(void) { - printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n" + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n" "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" diff --git a/qemu-img.c b/qemu-img.c index 4bb0a5161..a25954649 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1,7 +1,7 @@ /* * QEMU disk image utility * - * Copyright (c) 2003-2006 Fabrice Bellard + * Copyright (c) 2003-2007 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 @@ -93,7 +93,7 @@ static void format_print(void *opaque, const char *name) void help(void) { - printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2006 Fabrice Bellard\n" + printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2007 Fabrice Bellard\n" "usage: qemu-img command [command options]\n" "QEMU disk image utility\n" "\n" diff --git a/vl.c b/vl.c index 574452da8..c05def228 100644 --- a/vl.c +++ b/vl.c @@ -1,7 +1,7 @@ /* * QEMU System Emulator * - * Copyright (c) 2003-2006 Fabrice Bellard + * Copyright (c) 2003-2007 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 @@ -6010,7 +6010,7 @@ int main_loop(void) void help(void) { - printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2006 Fabrice Bellard\n" + printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" "\n" "'disk_image' is a raw hard image image for IDE hard disk 0\n" -- cgit v1.2.3 From c636bb66cc9043032caf20cb067bf9c818b7d17e Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 20:46:05 +0000 Subject: gdbserver fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2393 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 14 ++++++++++++++ gdbstub.h | 1 + monitor.c | 2 +- vl.c | 23 ++++++++--------------- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index a26c12ca6..aeddc3474 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1234,4 +1234,18 @@ int gdbserver_start(CharDriverState *chr) qemu_add_vm_stop_handler(gdb_vm_stopped, s); return 0; } + +int gdbserver_start_port(int port) +{ + CharDriverState *chr; + char gdbstub_port_name[128]; + + snprintf(gdbstub_port_name, sizeof(gdbstub_port_name), + "tcp::%d,nowait,nodelay,server", port); + chr = qemu_chr_open(gdbstub_port_name); + if (!chr) + return -EIO; + return gdbserver_start(chr); +} + #endif diff --git a/gdbstub.h b/gdbstub.h index c5b52c2e2..41ffc6d08 100644 --- a/gdbstub.h +++ b/gdbstub.h @@ -14,6 +14,7 @@ void gdb_exit(CPUState *, int); int gdbserver_start(int); #else int gdbserver_start(CharDriverState *chr); +int gdbserver_start_port(int port); #endif #endif diff --git a/monitor.c b/monitor.c index 33c482b09..1e9b904bf 100644 --- a/monitor.c +++ b/monitor.c @@ -423,7 +423,7 @@ static void do_gdbserver(int has_port, int port) { if (!has_port) port = DEFAULT_GDBSTUB_PORT; - if (gdbserver_start(port) < 0) { + if (gdbserver_start_port(port) < 0) { qemu_printf("Could not open gdbserver socket on port %d\n", port); } else { qemu_printf("Waiting gdb connection on port %d\n", port); diff --git a/vl.c b/vl.c index c05def228..1757036c0 100644 --- a/vl.c +++ b/vl.c @@ -6499,8 +6499,7 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB - int use_gdbstub; - char gdbstub_port_name[128]; + int use_gdbstub, gdbstub_port; #endif int i, cdrom_index; int snapshot, linux_boot; @@ -6568,7 +6567,7 @@ int main(int argc, char **argv) bios_size = BIOS_SIZE; #ifdef CONFIG_GDBSTUB use_gdbstub = 0; - sprintf(gdbstub_port_name, "%d", DEFAULT_GDBSTUB_PORT); + gdbstub_port = DEFAULT_GDBSTUB_PORT; #endif snapshot = 0; nographic = 0; @@ -6812,7 +6811,7 @@ int main(int argc, char **argv) use_gdbstub = 1; break; case QEMU_OPTION_p: - pstrcpy(gdbstub_port_name, sizeof(gdbstub_port_name), optarg); + gdbstub_port = atoi(optarg); break; #endif case QEMU_OPTION_L: @@ -7220,19 +7219,13 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB if (use_gdbstub) { - CharDriverState *chr; - int port; - - port = atoi(gdbstub_port_name); - if (port != 0) - sprintf(gdbstub_port_name, "tcp::%d,nowait,nodelay,server", port); - chr = qemu_chr_open(gdbstub_port_name); - if (!chr) { - fprintf(stderr, "qemu: could not open gdbstub device '%s'\n", - gdbstub_port_name); + /* XXX: use standard host:port notation and modify options + accordingly. */ + if (gdbserver_start_port(gdbstub_port) < 0) { + fprintf(stderr, "qemu: could not open gdbstub device on port '%d'\n", + gdbstub_port); exit(1); } - gdbserver_start(chr); } else #endif if (loadvm) -- cgit v1.2.3 From 7b9c30c5eecdbfc08ce18e4d386a5486289f0f78 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 20:46:55 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2394 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 7 ++++++- VERSION | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index 8123c3a9c..ea9ea7492 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -version 0.8.3: +version 0.9.0: - Support for relative paths in backing files for disk images - Async file I/O API @@ -10,6 +10,11 @@ version 0.8.3: - Support for MIPS32 Release 2 instruction set (Thiemo Seufer) - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil) - Darwin userspace emulation (Pierre d'Herbemont) + - m68k user support (Paul Brook) + - several x86 and x86_64 emulation fixes + - Mouse relative offset VNC extension (Anthony Liguori) + - PXE boot support (Anthony Liguori) + - '-daemonize' option (Anthony Liguori) version 0.8.2: diff --git a/VERSION b/VERSION index 53a48a1e8..899f24fc7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.2 \ No newline at end of file +0.9.0 \ No newline at end of file -- cgit v1.2.3 From 2afbeee757af01d74431df62a5216ae3f116e180 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 20:51:14 +0000 Subject: update path git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2395 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index f535dfaf1..79a3d55b5 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -13,7 +13,7 @@ endif TESTS+=sha1# test_path #TESTS+=test_path -QEMU=../i386-user/qemu-i386 +QEMU=../i386-linux-user/qemu-i386 all: $(TESTS) -- cgit v1.2.3 From df517cec519572613c235bd0319b7a59646e5622 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 20:52:39 +0000 Subject: int conversion test git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2396 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/test-i386.c b/tests/test-i386.c index 4a25d03b6..267391575 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -2583,6 +2583,41 @@ void test_sse(void) #endif +#define TEST_CONV_RAX(op)\ +{\ + unsigned long a, r;\ + a = i2l(0x8234a6f8);\ + r = a;\ + asm volatile(#op : "=a" (r) : "0" (r));\ + printf("%-10s A=" FMTLX " R=" FMTLX "\n", #op, a, r);\ +} + +#define TEST_CONV_RAX_RDX(op)\ +{\ + unsigned long a, d, r, rh; \ + a = i2l(0x8234a6f8);\ + d = i2l(0x8345a1f2);\ + r = a;\ + rh = d;\ + asm volatile(#op : "=a" (r), "=d" (rh) : "0" (r), "1" (rh)); \ + printf("%-10s A=" FMTLX " R=" FMTLX ":" FMTLX "\n", #op, a, r, rh); \ +} + +void test_conv(void) +{ + TEST_CONV_RAX(cbw); + TEST_CONV_RAX(cwde); +#if defined(__x86_64__) + TEST_CONV_RAX(cdqe); +#endif + + TEST_CONV_RAX_RDX(cwd); + TEST_CONV_RAX_RDX(cdq); +#if defined(__x86_64__) + TEST_CONV_RAX_RDX(cqo); +#endif +} + extern void *__start_initcall; extern void *__stop_initcall; @@ -2621,6 +2656,7 @@ int main(int argc, char **argv) test_single_step(); #endif test_enter(); + test_conv(); #ifdef TEST_SSE test_sse(); test_fxsave(); -- cgit v1.2.3 From b6aaab3b86005bf77d66724dbf53acf7da7af70b Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 21:06:29 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2397 c046a42c-6fe2-441c-8c8c-71466251a162 --- LICENSE | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/LICENSE b/LICENSE index bfc9a1f42..8bf5f94fa 100644 --- a/LICENSE +++ b/LICENSE @@ -1,11 +1,14 @@ -The following points clarify the QEMU licenses: +The following points clarify the QEMU license: -1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC - system emulator are released under the GNU Lesser General Public - License. +1) QEMU as a whole is released under the GNU General Public License -2) The Linux user mode QEMU emulator is released under the GNU General - Public License. +2) Parts of QEMU have specific licenses which are compatible with the +GNU General Public License. Hence each source file contains its own +licensing information. + +In particular, the QEMU virtual CPU core library (libqemu.a) is +released under the GNU Lesser General Public License. Many hardware +device emulation sources are released under the BSD license. 3) QEMU is a trademark of Fabrice Bellard. -- cgit v1.2.3 From a0f51eadc681d8525cbd40ec3283781d3e359c7d Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 21:09:14 +0000 Subject: removed git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2398 c046a42c-6fe2-441c-8c8c-71466251a162 --- README.distrib | 16 ----------- linux-2.6.9-qemu-fast.patch | 70 --------------------------------------------- 2 files changed, 86 deletions(-) delete mode 100644 README.distrib delete mode 100644 linux-2.6.9-qemu-fast.patch diff --git a/README.distrib b/README.distrib deleted file mode 100644 index a1598a299..000000000 --- a/README.distrib +++ /dev/null @@ -1,16 +0,0 @@ -Information about the various packages used to build the current qemu -x86 binary distribution: - -* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution - was used to get most of the binary packages. - -* wine-20020411 tarball - - ./configure --prefix=/usr/local/wine-i386 - - All exe and libs were stripped. Some compile time tools and the - includes were deleted. - -* ldconfig was launched to build the library links: - - qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache diff --git a/linux-2.6.9-qemu-fast.patch b/linux-2.6.9-qemu-fast.patch deleted file mode 100644 index f8ecd0b74..000000000 --- a/linux-2.6.9-qemu-fast.patch +++ /dev/null @@ -1,70 +0,0 @@ ---- linux-2.6.9/arch/i386/Kconfig 2004-10-18 23:53:22.000000000 +0200 -+++ linux-2.6.9-qemu/arch/i386/Kconfig 2004-12-07 21:56:49.000000000 +0100 -@@ -337,6 +337,14 @@ config X86_GENERIC - - endif - -+config QEMU -+ bool "Kernel to run under QEMU" -+ depends on EXPERIMENTAL -+ help -+ Select this if you want to boot the kernel inside qemu-fast, -+ the non-mmu version of the x86 emulator. See -+ . Say N. -+ - # - # Define implied options from the CPU selection here - # ---- linux-2.6.9/include/asm-i386/fixmap.h 2004-10-18 23:53:08.000000000 +0200 -+++ linux-2.6.9-qemu/include/asm-i386/fixmap.h 2004-12-07 23:16:11.000000000 +0100 -@@ -20,7 +20,11 @@ - * Leave one empty page between vmalloc'ed areas and - * the start of the fixmap. - */ -+#ifdef CONFIG_QEMU -+#define __FIXADDR_TOP 0xa7fff000 -+#else - #define __FIXADDR_TOP 0xfffff000 -+#endif - - #ifndef __ASSEMBLY__ - #include ---- linux-2.6.9/include/asm-i386/page.h 2004-10-18 23:53:22.000000000 +0200 -+++ linux-2.6.9-qemu/include/asm-i386/page.h 2004-12-07 21:56:49.000000000 +0100 -@@ -121,12 +121,19 @@ extern int sysctl_legacy_va_layout; - #endif /* __ASSEMBLY__ */ - - #ifdef __ASSEMBLY__ -+#ifdef CONFIG_QEMU -+#define __PAGE_OFFSET (0x90000000) -+#else - #define __PAGE_OFFSET (0xC0000000) -+#endif /* QEMU */ -+#else -+#ifdef CONFIG_QEMU -+#define __PAGE_OFFSET (0x90000000UL) - #else - #define __PAGE_OFFSET (0xC0000000UL) -+#endif /* QEMU */ - #endif - -- - #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) - #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) - #define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) ---- linux-2.6.9/include/asm-i386/param.h 2004-10-18 23:53:24.000000000 +0200 -+++ linux-2.6.9-qemu/include/asm-i386/param.h 2004-12-07 21:56:49.000000000 +0100 -@@ -2,7 +2,12 @@ - #define _ASMi386_PARAM_H - - #ifdef __KERNEL__ --# define HZ 1000 /* Internal kernel timer frequency */ -+# include -+# ifdef CONFIG_QEMU -+# define HZ 100 -+# else -+# define HZ 1000 /* Internal kernel timer frequency */ -+# endif - # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ - # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ - #endif -- cgit v1.2.3 From 19c80e50ee70ebaea78266a98334e4cd5f017678 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 21:22:42 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2399 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 0f608111b..db76c89d9 100644 --- a/Makefile +++ b/Makefile @@ -163,6 +163,9 @@ tarbin: $(datadir)/video.x \ $(datadir)/openbios-sparc32 \ $(datadir)/linux_boot.bin \ + $(datadir)/pxe-ne2k_pci.bin \ + $(datadir)/pxe-rtl8139.bin \ + $(datadir)/pxe-pcnet.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ $(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 ) -- cgit v1.2.3 From d8ecc0b9131a229ff6e8fbe5d3a0b284b1620452 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 21:41:46 +0000 Subject: Make cpu_signal_handler work on Mac OS X/Darwin x86 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2400 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 0b57f0fdc..058688fc7 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1176,6 +1176,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, #if defined(__i386__) +#if defined(__APPLE__) +# include + +# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip)) +# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) +# define ERROR_sig(context) ((context)->uc_mcontext->es.err) +#else +# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) +# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) +#endif + #if defined(USE_CODE_COPY) static void cpu_send_trap(unsigned long pc, int trap, struct ucontext *uc) @@ -1210,8 +1222,8 @@ int cpu_signal_handler(int host_signum, void *pinfo, #define REG_ERR ERR #define REG_TRAPNO TRAPNO #endif - pc = uc->uc_mcontext.gregs[REG_EIP]; - trapno = uc->uc_mcontext.gregs[REG_TRAPNO]; + pc = EIP_sig(uc); + trapno = TRAP_sig(uc); #if defined(TARGET_I386) && defined(USE_CODE_COPY) if (trapno == 0x00 || trapno == 0x05) { /* send division by zero or bound exception */ @@ -1221,7 +1233,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, #endif return handle_cpu_signal(pc, (unsigned long)info->si_addr, trapno == 0xe ? - (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, + (ERROR_sig(uc) >> 1) & 1 : 0, &uc->uc_sigmask, puc); } -- cgit v1.2.3 From 26a16623b8a86252dee95f2dcc85d6fe14191e20 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 5 Feb 2007 22:06:27 +0000 Subject: darwin fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2401 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 70a1caccd..1eb546e56 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -46,7 +46,7 @@ #include "softfloat.h" -#if defined(__i386__) && !defined(CONFIG_SOFTMMU) +#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(__APPLE__) #define USE_CODE_COPY #endif -- cgit v1.2.3 From 1193610e5df9eb88eaf7750f290fe8dd24ed620d Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Feb 2007 22:17:34 +0000 Subject: reset rombios32 area git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2403 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/bios.bin | Bin 131072 -> 131072 bytes pc-bios/bios.diff | 26 ++++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 14ea6a606..54e0bec80 100644 Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ diff --git a/pc-bios/bios.diff b/pc-bios/bios.diff index 86c36c11d..660d6d334 100644 --- a/pc-bios/bios.diff +++ b/pc-bios/bios.diff @@ -1,10 +1,32 @@ +Index: rombios.c +=================================================================== +RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v +retrieving revision 1.174 +diff -u -w -r1.174 rombios.c +--- rombios.c 17 Oct 2006 16:48:05 -0000 1.174 ++++ rombios.c 8 Feb 2007 21:57:48 -0000 +@@ -9472,6 +9472,14 @@ + mov eax, #0x00040000 + call eax + ++ ;; reset the memory (some boot loaders such as syslinux suppose ++ ;; that the memory is set to zero) ++ mov edi, #0x00040000 ++ mov ecx, #0x40000 / 4 ++ xor eax, eax ++ rep ++ stosd ++ + ;; return to 16 bit protected mode first + db 0xea + dd rombios32_10 Index: rombios.h =================================================================== RCS file: /cvsroot/bochs/bochs/bios/rombios.h,v retrieving revision 1.3 diff -u -w -r1.3 rombios.h --- rombios.h 3 Oct 2006 20:27:30 -0000 1.3 -+++ rombios.h 1 Nov 2006 19:16:34 -0000 ++++ rombios.h 8 Feb 2007 21:57:48 -0000 @@ -19,7 +19,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA @@ -20,7 +42,7 @@ RCS file: /cvsroot/bochs/bochs/bios/rombios32.c,v retrieving revision 1.8 diff -u -w -r1.8 rombios32.c --- rombios32.c 3 Oct 2006 20:27:30 -0000 1.8 -+++ rombios32.c 1 Nov 2006 19:16:34 -0000 ++++ rombios32.c 8 Feb 2007 21:57:48 -0000 @@ -852,6 +852,11 @@ int ioapic_id, i, len; int mp_config_table_size; -- cgit v1.2.3 From e9a1ab19d196aa50619fd8b77157bd11a5a8aa01 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Feb 2007 23:08:38 +0000 Subject: ram allocation functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2404 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 2 ++ exec.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index ed5355319..8a4730d32 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -848,6 +848,8 @@ 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); +ram_addr_t qemu_ram_alloc(unsigned int size); +void qemu_ram_free(ram_addr_t addr); int cpu_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, diff --git a/exec.c b/exec.c index ae2d825da..2e09b4bc3 100644 --- a/exec.c +++ b/exec.c @@ -82,6 +82,7 @@ int phys_ram_size; int phys_ram_fd; uint8_t *phys_ram_base; uint8_t *phys_ram_dirty; +static ram_addr_t phys_ram_alloc_offset = 0; CPUState *first_cpu; /* current CPU in the current thread. It is only valid inside @@ -1812,6 +1813,24 @@ uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr) return p->phys_offset; } +/* XXX: better than nothing */ +ram_addr_t qemu_ram_alloc(unsigned int size) +{ + ram_addr_t addr; + if ((phys_ram_alloc_offset + size) >= phys_ram_size) { + fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n", + size, phys_ram_size); + abort(); + } + addr = phys_ram_alloc_offset; + phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size); + return addr; +} + +void qemu_ram_free(ram_addr_t addr) +{ +} + static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) { #ifdef DEBUG_UNASSIGNED -- cgit v1.2.3 From 970ac5a3082428dca91171f270dcd95d6f4b2636 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Feb 2007 23:09:59 +0000 Subject: use ram allocation functions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2405 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 87 +++++++++++++++++++++++++++++++++++++++++------------------------ vl.c | 13 +--------- vl.h | 3 +-- 3 files changed, 57 insertions(+), 46 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 05802bca9..0560ff1f9 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -451,8 +451,8 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; int ret, linux_boot, initrd_size, i; - unsigned long bios_offset, vga_bios_offset, option_rom_offset; - int bios_size, isa_bios_size; + ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset; + int bios_size, isa_bios_size, vga_bios_size; PCIBus *pci_bus; int piix3_devfn = -1; CPUState *env; @@ -477,23 +477,24 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); + ram_addr = qemu_ram_alloc(ram_size); + cpu_register_physical_memory(0, ram_size, ram_addr); - /* BIOS load */ - bios_offset = ram_size + vga_ram_size; - vga_bios_offset = bios_offset + 256 * 1024; + /* allocate VGA RAM */ + vga_ram_addr = qemu_ram_alloc(vga_ram_size); + /* BIOS load */ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); bios_size = get_image_size(buf); if (bios_size <= 0 || - (bios_size % 65536) != 0 || - bios_size > (256 * 1024)) { + (bios_size % 65536) != 0) { goto bios_error; } + bios_offset = qemu_ram_alloc(bios_size); ret = load_image(buf, phys_ram_base + bios_offset); if (ret != bios_size) { bios_error: - fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); + fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", buf); exit(1); } @@ -503,8 +504,18 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } else { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); } + vga_bios_size = get_image_size(buf); + if (vga_bios_size <= 0 || vga_bios_size > 65536) + goto vga_bios_error; + vga_bios_offset = qemu_ram_alloc(65536); + ret = load_image(buf, phys_ram_base + vga_bios_offset); - + if (ret != vga_bios_size) { + vga_bios_error: + fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf); + exit(1); + } + /* setup basic memory access */ cpu_register_physical_memory(0xc0000, 0x10000, vga_bios_offset | IO_MEM_ROM); @@ -519,20 +530,32 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, isa_bios_size, (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); - option_rom_offset = 0; - for (i = 0; i < nb_option_roms; i++) { - int offset = bios_offset + bios_size + option_rom_offset; - int size; - - size = load_image(option_rom[i], phys_ram_base + offset); - if ((size + option_rom_offset) > 0x10000) { - fprintf(stderr, "Too many option ROMS\n"); - exit(1); - } - cpu_register_physical_memory(0xd0000 + option_rom_offset, - size, offset | IO_MEM_ROM); - option_rom_offset += size + 2047; - option_rom_offset -= (option_rom_offset % 2048); + { + ram_addr_t option_rom_offset; + int size, offset; + + offset = 0; + for (i = 0; i < nb_option_roms; i++) { + size = get_image_size(option_rom[i]); + if (size < 0) { + fprintf(stderr, "Could not load option rom '%s'\n", + option_rom[i]); + exit(1); + } + if (size > (0x10000 - offset)) + goto option_rom_error; + option_rom_offset = qemu_ram_alloc(size); + ret = load_image(option_rom[i], phys_ram_base + option_rom_offset); + if (ret != size) { + option_rom_error: + fprintf(stderr, "Too many option ROMS\n"); + exit(1); + } + size = (size + 4095) & ~4095; + cpu_register_physical_memory(0xd0000 + offset, + size, option_rom_offset | IO_MEM_ROM); + offset += size; + } } /* map all the bios at the top of memory */ @@ -612,19 +635,19 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (cirrus_vga_enabled) { if (pci_enabled) { pci_cirrus_vga_init(pci_bus, - ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + ds, phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); } else { - isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); } } else { if (pci_enabled) { - pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); + pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size, 0, 0); } else { - isa_vga_init(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); + isa_vga_init(ds, phys_ram_base + vga_ram_addr, + vga_ram_addr, vga_ram_size); } } diff --git a/vl.c b/vl.c index 1757036c0..a510df786 100644 --- a/vl.c +++ b/vl.c @@ -125,7 +125,6 @@ BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; int vga_ram_size; -int bios_size; static DisplayState display_state; int nographic; const char* keyboard_layout = NULL; @@ -6564,7 +6563,6 @@ int main(int argc, char **argv) hd_filename[i] = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; - bios_size = BIOS_SIZE; #ifdef CONFIG_GDBSTUB use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; @@ -7078,16 +7076,7 @@ int main(int argc, char **argv) #endif /* init the memory */ - phys_ram_size = ram_size + vga_ram_size + bios_size; - - for (i = 0; i < nb_option_roms; i++) { - int ret = get_image_size(option_rom[i]); - if (ret == -1) { - fprintf(stderr, "Could not load option rom '%s'\n", option_rom[i]); - exit(1); - } - phys_ram_size += ret; - } + phys_ram_size = ram_size + vga_ram_size + MAX_BIOS_SIZE; phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { diff --git a/vl.h b/vl.h index ff717863f..a06ce1834 100644 --- a/vl.h +++ b/vl.h @@ -165,12 +165,11 @@ extern const char *option_rom[MAX_OPTION_ROMS]; extern int nb_option_roms; /* XXX: make it dynamic */ +#define MAX_BIOS_SIZE (4 * 1024 * 1024) #if defined (TARGET_PPC) || defined (TARGET_SPARC64) #define BIOS_SIZE ((512 + 32) * 1024) #elif defined(TARGET_MIPS) #define BIOS_SIZE (4 * 1024 * 1024) -#else -#define BIOS_SIZE ((256 + 64) * 1024) #endif /* keyboard/mouse support */ -- cgit v1.2.3 From 43024c6a2b939ec865af3b96a4840a3db804141d Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 18:21:04 +0000 Subject: Fix for solaris register allocation issue on amd64, by Martin Bochnig. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2406 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 7b313d62c..bf40353b2 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -91,12 +91,12 @@ extern int printf(const char *, ...); #define AREG3 "edi" #endif #ifdef __x86_64__ -#define AREG0 "rbp" -#define AREG1 "rbx" +#define AREG0 "r14" +#define AREG1 "r15" #define AREG2 "r12" #define AREG3 "r13" -//#define AREG4 "r14" -//#define AREG5 "r15" +//#define AREG4 "rbp" +//#define AREG5 "rbx" #endif #ifdef __powerpc__ #define AREG0 "r27" -- cgit v1.2.3 From b80029cad1dad2caaaae61de334488a6847a087e Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 21:31:43 +0000 Subject: Support for more SPARC relocations, by Martin Bochnig. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2407 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 27 +++++++++++++++++++++++++++ elf.h | 3 +++ 2 files changed, 30 insertions(+) diff --git a/dyngen.c b/dyngen.c index bcfb86ea0..c6a878c6d 100644 --- a/dyngen.c +++ b/dyngen.c @@ -2349,6 +2349,33 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, reloc_offset, reloc_offset, name, addend, reloc_offset); break; + case R_SPARC_HH22: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x00000000) " + " | (((%s + %d) >> 42) & 0x00000000);\n", + reloc_offset, reloc_offset, name, addend); + break; + + case R_SPARC_LM22: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x00000000) " + " | (((%s + %d) >> 10) & 0x00000000);\n", + reloc_offset, reloc_offset, name, addend); + break; + + case R_SPARC_HM10: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x00000000) " + " | ((((%s + %d) >> 32 & 0x3ff)) & 0x00000000);\n", + reloc_offset, reloc_offset, name, addend); + break; + default: error("unsupported sparc64 relocation (%d) for symbol %s", type, name); } diff --git a/elf.h b/elf.h index 1825d50e8..e6ccfebed 100644 --- a/elf.h +++ b/elf.h @@ -328,6 +328,9 @@ typedef struct { #define R_SPARC_11 31 #define R_SPARC_64 32 #define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 #define R_SPARC_WDISP16 40 #define R_SPARC_WDISP19 41 #define R_SPARC_7 43 -- cgit v1.2.3 From b63891a08e16799842bae0ee341c1afa15a354b2 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 21:32:46 +0000 Subject: Fix typo, by Ed Swierk. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2408 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb.h b/hw/usb.h index ed8890e39..a6d0ae658 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -164,7 +164,7 @@ struct USBPacket { USBCallback *complete_cb; void *complete_opaque; USBCallback *cancel_cb; - void * *cancel_opaque; + void *cancel_opaque; }; /* Defer completion of a USB packet. The hadle_packet routine should then -- cgit v1.2.3 From 087f4ae0786948e83429f0a3dc062436da433c0f Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 21:50:42 +0000 Subject: Clean up serial code for Win 32, by Kazu. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2409 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 63 +++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/vl.c b/vl.c index a510df786..71e21be0d 100644 --- a/vl.c +++ b/vl.c @@ -1874,7 +1874,6 @@ static CharDriverState *qemu_chr_open_pty(void) #ifdef _WIN32 typedef struct { - CharDriverState *chr; int max_size; HANDLE hcom, hrecv, hsend; OVERLAPPED orecv, osend; @@ -1890,8 +1889,10 @@ typedef struct { static int win_chr_poll(void *opaque); static int win_chr_pipe_poll(void *opaque); -static void win_chr_close2(WinCharState *s) +static void win_chr_close(CharDriverState *chr) { + WinCharState *s = chr->opaque; + if (s->hsend) { CloseHandle(s->hsend); s->hsend = NULL; @@ -1905,19 +1906,14 @@ static void win_chr_close2(WinCharState *s) s->hcom = NULL; } if (s->fpipe) - qemu_del_polling_cb(win_chr_pipe_poll, s); + qemu_del_polling_cb(win_chr_pipe_poll, chr); else - qemu_del_polling_cb(win_chr_poll, s); + qemu_del_polling_cb(win_chr_poll, chr); } -static void win_chr_close(CharDriverState *chr) +static int win_chr_init(CharDriverState *chr, const char *filename) { WinCharState *s = chr->opaque; - win_chr_close2(s); -} - -static int win_chr_init(WinCharState *s, CharDriverState *chr, const char *filename) -{ COMMCONFIG comcfg; COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; COMSTAT comstat; @@ -1974,12 +1970,11 @@ static int win_chr_init(WinCharState *s, CharDriverState *chr, const char *filen fprintf(stderr, "Failed ClearCommError\n"); goto fail; } - s->chr = chr; - qemu_add_polling_cb(win_chr_poll, s); + qemu_add_polling_cb(win_chr_poll, chr); return 0; fail: - win_chr_close2(s); + win_chr_close(chr); return -1; } @@ -2017,14 +2012,17 @@ static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1) return len1 - len; } -static int win_chr_read_poll(WinCharState *s) +static int win_chr_read_poll(CharDriverState *chr) { - s->max_size = qemu_chr_can_read(s->chr); + WinCharState *s = chr->opaque; + + s->max_size = qemu_chr_can_read(chr); return s->max_size; } -static void win_chr_readfile(WinCharState *s) +static void win_chr_readfile(CharDriverState *chr) { + WinCharState *s = chr->opaque; int ret, err; uint8_t buf[1024]; DWORD size; @@ -2040,31 +2038,34 @@ static void win_chr_readfile(WinCharState *s) } if (size > 0) { - qemu_chr_read(s->chr, buf, size); + qemu_chr_read(chr, buf, size); } } -static void win_chr_read(WinCharState *s) +static void win_chr_read(CharDriverState *chr) { + WinCharState *s = chr->opaque; + if (s->len > s->max_size) s->len = s->max_size; if (s->len == 0) return; - win_chr_readfile(s); + win_chr_readfile(chr); } static int win_chr_poll(void *opaque) { - WinCharState *s = opaque; + CharDriverState *chr = opaque; + WinCharState *s = chr->opaque; COMSTAT status; DWORD comerr; ClearCommError(s->hcom, &comerr, &status); if (status.cbInQue > 0) { s->len = status.cbInQue; - win_chr_read_poll(s); - win_chr_read(s); + win_chr_read_poll(chr); + win_chr_read(chr); return 1; } return 0; @@ -2087,7 +2088,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename) chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; - if (win_chr_init(s, chr, filename) < 0) { + if (win_chr_init(chr, filename) < 0) { free(s); free(chr); return NULL; @@ -2098,21 +2099,23 @@ static CharDriverState *qemu_chr_open_win(const char *filename) static int win_chr_pipe_poll(void *opaque) { - WinCharState *s = opaque; + CharDriverState *chr = opaque; + WinCharState *s = chr->opaque; DWORD size; PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); if (size > 0) { s->len = size; - win_chr_read_poll(s); - win_chr_read(s); + win_chr_read_poll(chr); + win_chr_read(chr); return 1; } return 0; } -static int win_chr_pipe_init(WinCharState *s, const char *filename) +static int win_chr_pipe_init(CharDriverState *chr, const char *filename) { + WinCharState *s = chr->opaque; OVERLAPPED ov; int ret; DWORD size; @@ -2164,11 +2167,11 @@ static int win_chr_pipe_init(WinCharState *s, const char *filename) CloseHandle(ov.hEvent); ov.hEvent = NULL; } - qemu_add_polling_cb(win_chr_pipe_poll, s); + qemu_add_polling_cb(win_chr_pipe_poll, chr); return 0; fail: - win_chr_close2(s); + win_chr_close(chr); return -1; } @@ -2190,7 +2193,7 @@ static CharDriverState *qemu_chr_open_win_pipe(const char *filename) chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; - if (win_chr_pipe_init(s, filename) < 0) { + if (win_chr_pipe_init(chr, filename) < 0) { free(s); free(chr); return NULL; -- cgit v1.2.3 From ea785922f468971e876c27604cde3593d587a700 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 21:52:52 +0000 Subject: Build fix for mingw/Cygwin, by Kazu. It also looks like it does the right thing for Darwin. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2410 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.target b/Makefile.target index dc9a96575..2c8a873a2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -177,6 +177,7 @@ ifdef CONFIG_DARWIN_USER BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000 endif +BASE_CFLAGS+=$(OS_CFLAGS) OP_CFLAGS+=$(OS_CFLAGS) ######################################################### -- cgit v1.2.3 From dbcf5e82debb5d1901546705cb10a2fd34b59a99 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 22:14:55 +0000 Subject: Use the actual executable names in documentation, based on a patch by Pierre d'Herbemont. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2411 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 834c77855..9bc6b5a91 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1753,7 +1753,8 @@ qemu-i386 -L / /bin/ls @code{-L /} tells that the x86 dynamic linker must be searched with a @file{/} prefix. -@item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources): +@item Since QEMU is also a linux process, you can launch qemu with +qemu (NOTE: you can only do that if you compiled QEMU from the sources): @example qemu-i386 -L / qemu-i386 -L / /bin/ls @@ -1870,7 +1871,7 @@ target x86 on x86: Most apps (Cocoa and Carbon too) works. [1] @item target PowerPC on x86: Not working as the ppc commpage can't be mapped (yet!) @item -target x86 on x86: Most apps (Cocoa and Carbon too) works. [1] +target PowerPC on PowerPC: Most apps (Cocoa and Carbon too) works. [1] @item target x86 on PowerPC: most utilities work. Cocoa and Carbon apps are not yet supported. @end itemize @@ -1891,20 +1892,20 @@ CD or compile them by hand. libraries: @example -qemu-darwin-i386 /bin/ls +qemu-i386 /bin/ls @end example or to run the ppc version of the executable: @example -qemu-darwin-ppc /bin/ls +qemu-ppc /bin/ls @end example @item On ppc, you'll have to tell qemu where your x86 libraries (and dynamic linker) are installed: @example -qemu-darwin-i386 -L /opt/x86_root/ /bin/ls +qemu-i386 -L /opt/x86_root/ /bin/ls @end example @code{-L /opt/x86_root/} tells that the dynamic linker (dyld) path is in @@ -1916,7 +1917,7 @@ qemu-darwin-i386 -L /opt/x86_root/ /bin/ls @subsection Command line options @example -usage: qemu-darwin-i386 [-h] [-d] [-L path] [-s size] program [arguments...] +usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] @end example @table @option -- cgit v1.2.3 From ed8276ac7e7e4d18cbb37ee3069f3fc2f08ca1c7 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 22:37:56 +0000 Subject: Serial console improvements, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2412 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/console.c b/console.c index 2b3cd669d..a53b30177 100644 --- a/console.c +++ b/console.c @@ -533,21 +533,24 @@ static void console_show_cursor(TextConsole *s, int show) int y, y1; if (s == active_console) { + int x = s->x; + if (x >= s->width) { + x = s->width - 1; + } 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]; + c = &s->cells[y1 * s->width + 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); + vga_putcharxy(s->ds, x, y, c->ch, &t_attrib); } else { - vga_putcharxy(s->ds, s->x, y, c->ch, - &(c->t_attrib)); + vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib)); } - dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, + dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT, FONT_WIDTH, FONT_HEIGHT); } } @@ -796,8 +799,10 @@ static void console_putchar(TextConsole *s, int ch) s->state = TTY_STATE_ESC; break; default: - if (s->x >= s->width - 1) { - break; + if (s->x >= s->width) { + /* line wrap */ + s->x = 0; + console_put_lf(s); } y1 = (s->y_base + s->y) % s->total_height; c = &s->cells[y1 * s->width + s->x]; @@ -805,12 +810,6 @@ static void console_putchar(TextConsole *s, int ch) c->t_attrib = s->t_attrib; update_xy(s, s->x, s->y); s->x++; -#if 0 /* line wrap disabled */ - if (s->x >= s->width) { - s->x = 0; - console_put_lf(s); - } -#endif break; } break; -- cgit v1.2.3 From bd59780c46430dbb31e4232aa5191f0739ed70a7 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 22:58:02 +0000 Subject: Fix floating point to integer conversion, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2413 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 1ec15d28b..fd30e90e1 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1472,23 +1472,23 @@ void OPPROTO op_fstod(void) /* Float to integer conversion. */ void OPPROTO op_fstoi(void) { - *((int32_t *)&FT0) = float32_to_int32(FT1, &env->fp_status); + *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status); } void OPPROTO op_fdtoi(void) { - *((int32_t *)&FT0) = float64_to_int32(DT1, &env->fp_status); + *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status); } #ifdef TARGET_SPARC64 void OPPROTO op_fstox(void) { - *((int64_t *)&DT0) = float32_to_int64(FT1, &env->fp_status); + *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status); } void OPPROTO op_fdtox(void) { - *((int64_t *)&DT0) = float64_to_int64(DT1, &env->fp_status); + *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status); } void OPPROTO op_fmovs_cc(void) -- cgit v1.2.3 From d34dda5ea5cf1f74c4543679f33bc9ea56c90c24 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 22:59:40 +0000 Subject: qemu-img: fix incorrect error message, by Stuart Brady. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2414 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c index a25954649..6b470a150 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -457,7 +457,7 @@ static int img_convert(int argc, char **argv) drv = bdrv_find_format(out_fmt); if (!drv) - error("Unknown file format '%s'", fmt); + error("Unknown file format '%s'", out_fmt); if (compress && drv != &bdrv_qcow && drv != &bdrv_qcow2) error("Compression not supported for this file format"); if (encrypt && drv != &bdrv_qcow && drv != &bdrv_qcow2) -- cgit v1.2.3 From e9420c4f6e77f692398c895068347bbfaf81ef3b Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 23:00:33 +0000 Subject: Fix linking for qemu-img on Solaris, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2415 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index db76c89d9..b6d7b1f14 100644 --- a/Makefile +++ b/Makefile @@ -26,11 +26,9 @@ endif ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 -ifndef CONFIG_SOLARIS LIBS+=-lrt endif endif -endif all: $(TOOLS) $(DOCS) recurse-all -- cgit v1.2.3 From c2b84fabafd65765ee022da74f3e8ddc8f29a768 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 10 Feb 2007 23:21:21 +0000 Subject: Improve configure for Solaris, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2416 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/configure b/configure index bcff13e97..625541e14 100755 --- a/configure +++ b/configure @@ -133,8 +133,15 @@ coreaudio="yes" OS_CFLAGS="-mdynamic-no-pic" ;; SunOS) -solaris="yes" -;; + solaris="yes" + make="gmake" + install="ginstall" + solarisrev=`uname -r | cut -f2 -d.` + if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then + if test "$solarisrev" -ge 10 ; then + kqemu="yes" + fi + ;; *) oss="yes" linux="yes" @@ -151,17 +158,6 @@ if [ "$bsd" = "yes" ] ; then fi fi -if [ "$solaris" = "yes" ] ; then - make="gmake" - install="ginstall" - solarisrev=`uname -r | cut -f2 -d.` - if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then - if test "$solarisrev" -gt 10 ; then - kqemu="yes" - fi - fi -fi - # find source path source_path=`dirname "$0"` if [ -z "$source_path" ]; then -- cgit v1.2.3 From 86b2bd935d50651ddfead740fc68c9da56eb0cc5 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 11 Feb 2007 00:31:33 +0000 Subject: Fix syntax error. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2417 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 625541e14..9ec8df187 100755 --- a/configure +++ b/configure @@ -141,7 +141,8 @@ SunOS) if test "$solarisrev" -ge 10 ; then kqemu="yes" fi - ;; + fi +;; *) oss="yes" linux="yes" -- cgit v1.2.3 From cf257238ab9f14c9efc917efb70fb39a8e1fc736 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 11 Feb 2007 15:02:17 +0000 Subject: Fix typo, and some reformatting. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2418 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 9ec8df187..c217ac0bf 100755 --- a/configure +++ b/configure @@ -313,7 +313,7 @@ cat > $TMPC </dev/null ; then +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" @@ -338,11 +338,11 @@ if test "$check_gcc" = "yes" ; then int main(){return 0;} EOF check_cc() { - which "$1" >&/dev/null + which "$1" 2> /dev/null return $? } - if "$cc" -o $TMPE $TMPC 2>/dev/null ; then + 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 @@ -442,7 +442,7 @@ int main(int argc, char ** argv){ } EOF -if $cc -o $TMPE $TMPC 2>/dev/null ; then +if $cc -o $TMPE $TMPC 2> /dev/null ; then $TMPE && bigendian="yes" else echo big/little test failed -- cgit v1.2.3 From eb5c851f2dadab59c9de4132e00268219edb5a44 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 11 Feb 2007 15:06:09 +0000 Subject: Use PATH_MAX for name lengths, by Sergey Vlasov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2419 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 9264e42a6..82bbf60d2 100644 --- a/block.c +++ b/block.c @@ -322,8 +322,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, BlockDriver *drv) { int ret, open_flags; - char tmp_filename[1024]; - char backing_filename[1024]; + char tmp_filename[PATH_MAX]; + char backing_filename[PATH_MAX]; bs->read_only = 0; bs->is_temporary = 0; -- cgit v1.2.3 From 7494b0f94f8409e588b0b130da41d06a88ea3b03 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 11 Feb 2007 18:26:53 +0000 Subject: Linux userland emulation of syslog, from Debian patchset. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2420 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 45c8f2939..8196401ca 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -140,6 +140,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo +#define __NR_sys_syslog __NR_syslog #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek @@ -159,6 +160,7 @@ _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) +_syscall3(int,sys_syslog,int,type,char*,bufp,int,len) #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) #endif @@ -2947,9 +2949,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5); break; #endif - + case TARGET_NR_syslog: - goto unimplemented; + ret = get_errno(sys_syslog((int)arg1, (char*)arg2, (int)arg3)); + break; + case TARGET_NR_setitimer: { struct itimerval value, ovalue, *pvalue; -- cgit v1.2.3 From 39b9aae15b8766a9456dc12dd89b70ed6ed50c97 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 11 Feb 2007 18:36:44 +0000 Subject: Linux userland emulation of prctl, from Debian patchset. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2421 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8196401ca..5020f3fee 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -3422,7 +3423,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_nfsservctl: goto unimplemented; case TARGET_NR_prctl: - goto unimplemented; + ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5)); + break; #ifdef TARGET_NR_pread case TARGET_NR_pread: page_unprotect_range(arg2, arg3); -- cgit v1.2.3 From f2f1ac827d9867db4444498a64582595b001e40f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Feb 2007 19:01:48 +0000 Subject: increase USB table poll interval git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2422 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index bde3a7c67..1c2f4d231 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -170,7 +170,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = { 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* u8 ep_bmAttributes; Interrupt */ 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ - 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; static const uint8_t qemu_mouse_hid_report_descriptor[] = { -- cgit v1.2.3 From e55744879fa56bdd257beb05de3163c917470731 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 11 Feb 2007 20:03:13 +0000 Subject: Fix previous Linux userland emulation breakage. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2423 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5020f3fee..3506ece1e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2952,7 +2952,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif case TARGET_NR_syslog: - ret = get_errno(sys_syslog((int)arg1, (char*)arg2, (int)arg3)); + p = lock_user_string(arg2); + ret = get_errno(sys_syslog((int)arg1, p, (int)arg3)); + unlock_user(p, arg2, 0); break; case TARGET_NR_setitimer: @@ -3423,7 +3425,20 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_nfsservctl: goto unimplemented; case TARGET_NR_prctl: - ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5)); + switch (arg1) + { + case PR_GET_PDEATHSIG: + { + int deathsig; + ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5)); + if (!is_error(ret) && arg2) + tput32(arg2, deathsig); + } + break; + default: + ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5)); + break; + } break; #ifdef TARGET_NR_pread case TARGET_NR_pread: -- cgit v1.2.3 From 18acad9250068365340a74ea9e5201a06fb01ff4 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 14 Feb 2007 20:17:03 +0000 Subject: ARM doubleword post-modify fix (Daniel Jacobowitz). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2424 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index cd91bdce8..cf46e346e 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -391,9 +391,9 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, if (insn & (1 << 22)) { /* immediate */ val = (insn & 0xf) | ((insn >> 4) & 0xf0); - val += extra; if (!(insn & (1 << 23))) val = -val; + val += extra; if (val != 0) gen_op_addl_T1_im(val); } else { -- cgit v1.2.3 From 9529ebc2c5d44262f44f2e06ddeaedd03506e3a9 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 15 Feb 2007 22:49:45 +0000 Subject: update author git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2425 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index ea9ea7492..c8a68ca2f 100644 --- a/Changelog +++ b/Changelog @@ -23,7 +23,7 @@ version 0.8.2: - switch to OpenBios for SPARC targets (Blue Swirl) - VNC server fixes - MIPS FPU support (Marius Groeger) - - Solaris/SPARC host support (Ben Taylor) + - Solaris/SPARC host support (Juergen Keil) - PPC breakpoints and single stepping (Jason Wessel) - USB updates (Paul Brook) - UDP/TCP/telnet character devices (Jason Wessel) @@ -42,7 +42,7 @@ version 0.8.1: - PC speaker support (Joachim Henke) - IDE LBA48 support (Jens Axboe) - SSE3 support - - Solaris port (Ben Taylor) + - Solaris port (Juergen Keil) - Preliminary SH4 target (Samuel Tardieu) - VNC server (Anthony Liguori) - slirp fixes (Ed Swierk et al.) -- cgit v1.2.3 From b93aebecb0844b220c1652b79e698db2afe3bbab Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 15 Feb 2007 22:58:18 +0000 Subject: fixed cross win32 build git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2426 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index c217ac0bf..963111934 100755 --- a/configure +++ b/configure @@ -221,7 +221,7 @@ for opt do ;; --fmod-inc=*) fmod_inc="$optarg" ;; - --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no" + --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; linux_user="no" ;; --disable-slirp) slirp="no" ;; -- cgit v1.2.3 From f941aa256f2254c3f35f00fcf5d7f20dba55a5b7 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Feb 2007 22:19:29 +0000 Subject: Qemu support for S32 and U32 alsa output, by Vassili Karpov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2427 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 26 ++++++++++++ audio/audio.c | 110 ++++++++++++++++++++++++++++++++++++++++++------- audio/audio.h | 4 +- audio/audio_template.h | 4 +- audio/coreaudio.c | 5 --- audio/mixeng.c | 95 ++++++++++++++++++++++++++++++++++-------- audio/mixeng.h | 4 +- audio/wavaudio.c | 8 +++- audio/wavcapture.c | 6 +-- 9 files changed, 214 insertions(+), 48 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 71e523566..2e59dfa4c 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -157,6 +157,12 @@ static int aud_to_alsafmt (audfmt_e fmt) case AUD_FMT_U16: return SND_PCM_FORMAT_U16_LE; + case AUD_FMT_S32: + return SND_PCM_FORMAT_S32_LE; + + case AUD_FMT_U32: + return SND_PCM_FORMAT_U32_LE; + default: dolog ("Internal logic error: Bad audio format %d\n", fmt); #ifdef DEBUG_AUDIO @@ -199,6 +205,26 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness) *fmt = AUD_FMT_U16; break; + case SND_PCM_FORMAT_S32_LE: + *endianness = 0; + *fmt = AUD_FMT_S32; + break; + + case SND_PCM_FORMAT_U32_LE: + *endianness = 0; + *fmt = AUD_FMT_U32; + break; + + case SND_PCM_FORMAT_S32_BE: + *endianness = 1; + *fmt = AUD_FMT_S32; + break; + + case SND_PCM_FORMAT_U32_BE: + *endianness = 1; + *fmt = AUD_FMT_U32; + break; + default: dolog ("Unrecognized audio format %d\n", alsafmt); return -1; diff --git a/audio/audio.c b/audio/audio.c index 556e6fdbc..5d3c7f15f 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -80,7 +80,8 @@ static struct { { 44100, /* freq */ 2, /* nchannels */ - AUD_FMT_S16 /* fmt */ + AUD_FMT_S16, /* fmt */ + AUDIO_HOST_ENDIANNESS } }, @@ -91,7 +92,8 @@ static struct { { 44100, /* freq */ 2, /* nchannels */ - AUD_FMT_S16 /* fmt */ + AUD_FMT_S16, /* fmt */ + AUDIO_HOST_ENDIANNESS } }, @@ -166,6 +168,25 @@ int audio_bug (const char *funcname, int cond) } #endif +static inline int audio_bits_to_index (int bits) +{ + switch (bits) { + case 8: + return 0; + + case 16: + return 1; + + case 32: + return 2; + + default: + audio_bug ("bits_to_index", 1); + AUD_log (NULL, "invalid bits %d\n", bits); + return 0; + } +} + void *audio_calloc (const char *funcname, int nmemb, size_t size) { int cond; @@ -227,6 +248,12 @@ const char *audio_audfmt_to_string (audfmt_e fmt) case AUD_FMT_S16: return "S16"; + + case AUD_FMT_U32: + return "U32"; + + case AUD_FMT_S32: + return "S32"; } dolog ("Bogus audfmt %d returning S16\n", fmt); @@ -243,6 +270,10 @@ audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp) *defaultp = 0; return AUD_FMT_U16; } + else if (!strcasecmp (s, "u32")) { + *defaultp = 0; + return AUD_FMT_U32; + } else if (!strcasecmp (s, "s8")) { *defaultp = 0; return AUD_FMT_S8; @@ -251,6 +282,10 @@ audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp) *defaultp = 0; return AUD_FMT_S16; } + else if (!strcasecmp (s, "s32")) { + *defaultp = 0; + return AUD_FMT_S32; + } else { dolog ("Bogus audio format `%s' using %s\n", s, audio_audfmt_to_string (defval)); @@ -538,6 +573,8 @@ static int audio_validate_settings (audsettings_t *as) case AUD_FMT_U8: case AUD_FMT_S16: case AUD_FMT_U16: + case AUD_FMT_S32: + case AUD_FMT_U32: break; default: invalid = 1; @@ -563,6 +600,12 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) case AUD_FMT_U16: bits = 16; break; + + case AUD_FMT_S32: + sign = 1; + case AUD_FMT_U32: + bits = 32; + break; } return info->freq == as->freq && info->nchannels == as->nchannels @@ -573,7 +616,7 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) { - int bits = 8, sign = 0; + int bits = 8, sign = 0, shift = 0; switch (as->fmt) { case AUD_FMT_S8: @@ -585,6 +628,14 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) sign = 1; case AUD_FMT_U16: bits = 16; + shift = 1; + break; + + case AUD_FMT_S32: + sign = 1; + case AUD_FMT_U32: + bits = 32; + shift = 2; break; } @@ -592,7 +643,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) info->bits = bits; info->sign = sign; info->nchannels = as->nchannels; - info->shift = (as->nchannels == 2) + (bits == 16); + info->shift = (as->nchannels == 2) + shift; info->align = (1 << info->shift) - 1; info->bytes_per_second = info->freq << info->shift; info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); @@ -608,22 +659,49 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) memset (buf, 0x00, len << info->shift); } else { - if (info->bits == 8) { + switch (info->bits) { + case 8: memset (buf, 0x80, len << info->shift); - } - else { - int i; - uint16_t *p = buf; - int shift = info->nchannels - 1; - short s = INT16_MAX; + break; - if (info->swap_endianness) { - s = bswap16 (s); + case 16: + { + int i; + uint16_t *p = buf; + int shift = info->nchannels - 1; + short s = INT16_MAX; + + if (info->swap_endianness) { + s = bswap16 (s); + } + + for (i = 0; i < len << shift; i++) { + p[i] = s; + } } + break; + + case 32: + { + int i; + uint32_t *p = buf; + int shift = info->nchannels - 1; + int32_t s = INT32_MAX; + + if (info->swap_endianness) { + s = bswap32 (s); + } - for (i = 0; i < len << shift; i++) { - p[i] = s; + for (i = 0; i < len << shift; i++) { + p[i] = s; + } } + break; + + default: + AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n", + info->bits); + break; } } } @@ -1811,7 +1889,7 @@ CaptureVoiceOut *AUD_add_capture ( [hw->info.nchannels == 2] [hw->info.sign] [hw->info.swap_endianness] - [hw->info.bits == 16]; + [audio_bits_to_index (hw->info.bits)]; LIST_INSERT_HEAD (&s->cap_head, cap, entries); LIST_INSERT_HEAD (&cap->cb_head, cb, entries); diff --git a/audio/audio.h b/audio/audio.h index c097f391b..287cc5c73 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -33,7 +33,9 @@ typedef enum { AUD_FMT_U8, AUD_FMT_S8, AUD_FMT_U16, - AUD_FMT_S16 + AUD_FMT_S16, + AUD_FMT_U32, + AUD_FMT_S32 } audfmt_e; #ifdef WORDS_BIGENDIAN diff --git a/audio/audio_template.h b/audio/audio_template.h index 13e1c3efb..850e101d7 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -164,7 +164,7 @@ static int glue (audio_pcm_sw_init_, TYPE) ( [sw->info.nchannels == 2] [sw->info.sign] [sw->info.swap_endianness] - [sw->info.bits == 16]; + [audio_bits_to_index (sw->info.bits)]; sw->name = qemu_strdup (name); err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); @@ -288,7 +288,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) [hw->info.nchannels == 2] [hw->info.sign] [hw->info.swap_endianness] - [hw->info.bits == 16]; + [audio_bits_to_index (hw->info.bits)]; if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { goto err1; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 8512f122b..74d432f91 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -294,7 +294,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; UInt32 propertySize; int err; - int bits = 8; const char *typ = "playback"; AudioValueRange frameRange; @@ -305,10 +304,6 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as) return -1; } - if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { - bits = 16; - } - audio_pcm_init_info (&hw->info, as); /* open default output device */ diff --git a/audio/mixeng.c b/audio/mixeng.c index 6308d4100..34cc1aeee 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -82,6 +82,7 @@ #undef IN_T #undef SHIFT +/* Unsigned 16 bit */ #define IN_T uint16_t #define IN_MIN 0 #define IN_MAX USHRT_MAX @@ -101,26 +102,72 @@ #undef IN_T #undef SHIFT -t_sample *mixeng_conv[2][2][2][2] = { +/* Signed 32 bit */ +#define IN_T int32_t +#define IN_MIN INT32_MIN +#define IN_MAX INT32_MAX +#define SIGNED +#define SHIFT 32 +#define ENDIAN_CONVERSION natural +#define ENDIAN_CONVERT(v) (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#define ENDIAN_CONVERSION swap +#define ENDIAN_CONVERT(v) bswap32 (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#undef SIGNED +#undef IN_MAX +#undef IN_MIN +#undef IN_T +#undef SHIFT + +/* Unsigned 16 bit */ +#define IN_T uint32_t +#define IN_MIN 0 +#define IN_MAX UINT32_MAX +#define SHIFT 32 +#define ENDIAN_CONVERSION natural +#define ENDIAN_CONVERT(v) (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#define ENDIAN_CONVERSION swap +#define ENDIAN_CONVERT(v) bswap32 (v) +#include "mixeng_template.h" +#undef ENDIAN_CONVERT +#undef ENDIAN_CONVERSION +#undef IN_MAX +#undef IN_MIN +#undef IN_T +#undef SHIFT + +t_sample *mixeng_conv[2][2][2][3] = { { { { conv_natural_uint8_t_to_mono, - conv_natural_uint16_t_to_mono + conv_natural_uint16_t_to_mono, + conv_natural_uint32_t_to_mono }, { conv_natural_uint8_t_to_mono, - conv_swap_uint16_t_to_mono + conv_swap_uint16_t_to_mono, + conv_swap_uint32_t_to_mono, } }, { { conv_natural_int8_t_to_mono, - conv_natural_int16_t_to_mono + conv_natural_int16_t_to_mono, + conv_natural_int32_t_to_mono }, { conv_natural_int8_t_to_mono, - conv_swap_int16_t_to_mono + conv_swap_int16_t_to_mono, + conv_swap_int32_t_to_mono } } }, @@ -128,46 +175,54 @@ t_sample *mixeng_conv[2][2][2][2] = { { { conv_natural_uint8_t_to_stereo, - conv_natural_uint16_t_to_stereo + conv_natural_uint16_t_to_stereo, + conv_natural_uint32_t_to_stereo }, { conv_natural_uint8_t_to_stereo, - conv_swap_uint16_t_to_stereo + conv_swap_uint16_t_to_stereo, + conv_swap_uint32_t_to_stereo } }, { { conv_natural_int8_t_to_stereo, - conv_natural_int16_t_to_stereo + conv_natural_int16_t_to_stereo, + conv_natural_int32_t_to_stereo }, { conv_natural_int8_t_to_stereo, - conv_swap_int16_t_to_stereo + conv_swap_int16_t_to_stereo, + conv_swap_int32_t_to_stereo, } } } }; -f_sample *mixeng_clip[2][2][2][2] = { +f_sample *mixeng_clip[2][2][2][3] = { { { { clip_natural_uint8_t_from_mono, - clip_natural_uint16_t_from_mono + clip_natural_uint16_t_from_mono, + clip_natural_uint32_t_from_mono }, { clip_natural_uint8_t_from_mono, - clip_swap_uint16_t_from_mono + clip_swap_uint16_t_from_mono, + clip_swap_uint32_t_from_mono } }, { { clip_natural_int8_t_from_mono, - clip_natural_int16_t_from_mono + clip_natural_int16_t_from_mono, + clip_natural_int32_t_from_mono }, { clip_natural_int8_t_from_mono, - clip_swap_int16_t_from_mono + clip_swap_int16_t_from_mono, + clip_swap_int32_t_from_mono } } }, @@ -175,21 +230,25 @@ f_sample *mixeng_clip[2][2][2][2] = { { { clip_natural_uint8_t_from_stereo, - clip_natural_uint16_t_from_stereo + clip_natural_uint16_t_from_stereo, + clip_natural_uint32_t_from_stereo }, { clip_natural_uint8_t_from_stereo, - clip_swap_uint16_t_from_stereo + clip_swap_uint16_t_from_stereo, + clip_swap_uint32_t_from_stereo } }, { { clip_natural_int8_t_from_stereo, - clip_natural_int16_t_from_stereo + clip_natural_int16_t_from_stereo, + clip_natural_int32_t_from_stereo }, { clip_natural_int8_t_from_stereo, - clip_swap_int16_t_from_stereo + clip_swap_int16_t_from_stereo, + clip_swap_int32_t_from_stereo } } } diff --git a/audio/mixeng.h b/audio/mixeng.h index 9e3bac174..95b68df6a 100644 --- a/audio/mixeng.h +++ b/audio/mixeng.h @@ -37,8 +37,8 @@ typedef void (t_sample) (st_sample_t *dst, const void *src, int samples, volume_t *vol); typedef void (f_sample) (void *dst, const st_sample_t *src, int samples); -extern t_sample *mixeng_conv[2][2][2][2]; -extern f_sample *mixeng_clip[2][2][2][2]; +extern t_sample *mixeng_conv[2][2][2][3]; +extern f_sample *mixeng_clip[2][2][2][3]; void *st_rate_start (int inrate, int outrate); void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, diff --git a/audio/wavaudio.c b/audio/wavaudio.c index a552b7e97..2dbc58cbe 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -41,7 +41,8 @@ static struct { { 44100, 2, - AUD_FMT_S16 + AUD_FMT_S16, + AUDIO_HOST_ENDIANNESS }, "qemu.wav" }; @@ -131,6 +132,11 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as) case AUD_FMT_U16: bits16 = 1; break; + + case AUD_FMT_S32: + case AUD_FMT_U32: + dolog ("WAVE files can not handle 32bit formats\n"); + return -1; } hdr[34] = bits16 ? 0x10 : 0x08; diff --git a/audio/wavcapture.c b/audio/wavcapture.c index d915fa02b..4810fa30d 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -37,15 +37,15 @@ static void wav_destroy (void *opaque) if (wav->f) { le_store (rlen, rifflen, 4); le_store (dlen, datalen, 4); - + qemu_fseek (wav->f, 4, SEEK_SET); qemu_put_buffer (wav->f, rlen, 4); - + qemu_fseek (wav->f, 32, SEEK_CUR); qemu_put_buffer (wav->f, dlen, 4); qemu_fclose (wav->f); } - + qemu_free (wav->path); } -- cgit v1.2.3 From 802659181ef0caf82db06e355025e1bcfbfc4622 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Feb 2007 22:25:41 +0000 Subject: Userland mount syscall emulation, by Kirill A. Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2428 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3506ece1e..f3f97b0d5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2163,8 +2163,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(getpid()); break; case TARGET_NR_mount: - /* need to look at the data field */ - goto unimplemented; + { + /* need to look at the data field */ + void *p2, *p3; + p = lock_user_string(arg1); + p2 = lock_user_string(arg2); + p3 = lock_user_string(arg3); + ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, (const void *)arg5)); + unlock_user(p, arg1, 0); + unlock_user(p2, arg2, 0); + unlock_user(p3, arg3, 0); + break; + } case TARGET_NR_umount: p = lock_user_string(arg1); ret = get_errno(umount(p)); -- cgit v1.2.3 From d5d10bc3056646404f4b60517b851398c3a28986 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Feb 2007 22:54:49 +0000 Subject: Solaris tap device, by Sittichai Palingsong. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2429 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 71e21be0d..009febb4c 100644 --- a/vl.c +++ b/vl.c @@ -55,6 +55,21 @@ #include #include #include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include // must come after ip.h +#include +#include +#include +#include +#include #endif #endif #endif @@ -3199,7 +3214,15 @@ static void tap_send(void *opaque) uint8_t buf[4096]; int size; +#ifdef __sun__ + struct strbuf sbuf; + int f = 0; + sbuf.maxlen = sizeof(buf); + sbuf.buf = buf; + size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1; +#else size = read(s->fd, buf, sizeof(buf)); +#endif if (size > 0) { qemu_send_packet(s->vc, buf, size); } @@ -3242,10 +3265,135 @@ static int tap_open(char *ifname, int ifname_size) return fd; } #elif defined(__sun__) +#define TUNNEWPPA (('T'<<16) | 0x0001) +/* + * Allocate TAP device, returns opened fd. + * Stores dev name in the first arg(must be large enough). + */ +int tap_alloc(char *dev) +{ + int tap_fd, if_fd, ppa = -1; + static int ip_fd = 0; + char *ptr; + + static int arp_fd = 0; + int ip_muxid, arp_muxid; + struct strioctl strioc_if, strioc_ppa; + int link_type = I_PLINK;; + struct lifreq ifr; + char actual_name[32] = ""; + + memset(&ifr, 0x0, sizeof(ifr)); + + if( *dev ){ + ptr = dev; + while( *ptr && !isdigit((int)*ptr) ) ptr++; + ppa = atoi(ptr); + } + + /* Check if IP device was opened */ + if( ip_fd ) + close(ip_fd); + + if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){ + syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)"); + return -1; + } + + if( (tap_fd = open("/dev/tap", O_RDWR, 0)) < 0){ + syslog(LOG_ERR, "Can't open /dev/tap"); + return -1; + } + + /* Assign a new PPA and get its unit number. */ + strioc_ppa.ic_cmd = TUNNEWPPA; + strioc_ppa.ic_timout = 0; + strioc_ppa.ic_len = sizeof(ppa); + strioc_ppa.ic_dp = (char *)&ppa; + if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) + syslog (LOG_ERR, "Can't assign new interface"); + + if( (if_fd = open("/dev/tap", O_RDWR, 0)) < 0){ + syslog(LOG_ERR, "Can't open /dev/tap (2)"); + return -1; + } + if(ioctl(if_fd, I_PUSH, "ip") < 0){ + syslog(LOG_ERR, "Can't push IP module"); + return -1; + } + + if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) + syslog(LOG_ERR, "Can't get flags\n"); + + snprintf (actual_name, 32, "tap%d", ppa); + strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name)); + + ifr.lifr_ppa = ppa; + /* Assign ppa according to the unit number returned by tun device */ + + if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0) + syslog (LOG_ERR, "Can't set PPA %d", ppa); + if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) + syslog (LOG_ERR, "Can't get flags\n"); + /* Push arp module to if_fd */ + if (ioctl (if_fd, I_PUSH, "arp") < 0) + syslog (LOG_ERR, "Can't push ARP module (2)"); + + /* Push arp module to ip_fd */ + if (ioctl (ip_fd, I_POP, NULL) < 0) + syslog (LOG_ERR, "I_POP failed\n"); + if (ioctl (ip_fd, I_PUSH, "arp") < 0) + syslog (LOG_ERR, "Can't push ARP module (3)\n"); + /* Open arp_fd */ + if ((arp_fd = open ("/dev/tap", O_RDWR, 0)) < 0) + syslog (LOG_ERR, "Can't open %s\n", "/dev/tap"); + + /* Set ifname to arp */ + strioc_if.ic_cmd = SIOCSLIFNAME; + strioc_if.ic_timout = 0; + strioc_if.ic_len = sizeof(ifr); + strioc_if.ic_dp = (char *)𝔦 + if (ioctl(arp_fd, I_STR, &strioc_if) < 0){ + syslog (LOG_ERR, "Can't set ifname to arp\n"); + } + + if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){ + syslog(LOG_ERR, "Can't link TAP device to IP"); + return -1; + } + + if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0) + syslog (LOG_ERR, "Can't link TAP device to ARP"); + + close (if_fd); + + memset(&ifr, 0x0, sizeof(ifr)); + strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name)); + ifr.lifr_ip_muxid = ip_muxid; + ifr.lifr_arp_muxid = arp_muxid; + + if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0) + { + ioctl (ip_fd, I_PUNLINK , arp_muxid); + ioctl (ip_fd, I_PUNLINK, ip_muxid); + syslog (LOG_ERR, "Can't set multiplexor id"); + } + + sprintf(dev, "tap%d", ppa); + return tap_fd; +} + static int tap_open(char *ifname, int ifname_size) { - fprintf(stderr, "warning: tap_open not yet implemented\n"); - return -1; + char dev[10]=""; + int fd; + if( (fd = tap_alloc(dev)) < 0 ){ + fprintf(stderr, "Cannot allocate TAP device\n"); + return -1; + } + pstrcpy(ifname, ifname_size, dev); + fcntl(fd, F_SETFL, O_NONBLOCK); + return fd; } #else static int tap_open(char *ifname, int ifname_size) -- cgit v1.2.3 From 5867c88a8256c6501c382ba421c91464dd871e3b Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Feb 2007 23:44:43 +0000 Subject: Parport EPP support for Linux, by Marko Kohtala. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2430 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/parallel.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++----------- qemu-doc.texi | 2 +- vl.c | 85 +++++++++++- vl.h | 9 ++ 4 files changed, 436 insertions(+), 84 deletions(-) diff --git a/hw/parallel.c b/hw/parallel.c index cba95610e..d751d7a3a 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -2,6 +2,7 @@ * QEMU Parallel PORT emulation * * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2007 Marko Kohtala * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +26,18 @@ //#define DEBUG_PARALLEL +#ifdef DEBUG_PARALLEL +#define pdebug(fmt, arg...) printf("pp: " fmt, ##arg) +#else +#define pdebug(fmt, arg...) ((void)0) +#endif + +#define PARA_REG_DATA 0 +#define PARA_REG_STS 1 +#define PARA_REG_CTR 2 +#define PARA_REG_EPP_ADDR 3 +#define PARA_REG_EPP_DATA 4 + /* * These are the definitions for the Printer Status Register */ @@ -33,24 +46,31 @@ #define PARA_STS_PAPER 0x20 /* Out of paper */ #define PARA_STS_ONLINE 0x10 /* Online */ #define PARA_STS_ERROR 0x08 /* Error complement */ +#define PARA_STS_TMOUT 0x01 /* EPP timeout */ /* * These are the definitions for the Printer Control Register */ +#define PARA_CTR_DIR 0x20 /* Direction (1=read, 0=write) */ #define PARA_CTR_INTEN 0x10 /* IRQ Enable */ #define PARA_CTR_SELECT 0x08 /* Select In complement */ #define PARA_CTR_INIT 0x04 /* Initialize Printer complement */ #define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */ #define PARA_CTR_STROBE 0x01 /* Strobe complement */ +#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE) + struct ParallelState { - uint8_t data; - uint8_t status; /* read only register */ + uint8_t dataw; + uint8_t datar; + uint8_t status; uint8_t control; int irq; int irq_pending; CharDriverState *chr; int hw_driver; + int epp_timeout; + uint32_t last_read_offset; /* For debugging */ }; static void parallel_update_irq(ParallelState *s) @@ -61,96 +81,322 @@ static void parallel_update_irq(ParallelState *s) pic_set_irq(s->irq, 0); } -static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void +parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val) { ParallelState *s = opaque; + pdebug("write addr=0x%02x val=0x%02x\n", addr, val); + + addr &= 7; + switch(addr) { + case PARA_REG_DATA: + s->dataw = val; + parallel_update_irq(s); + break; + case PARA_REG_CTR: + if ((val & PARA_CTR_INIT) == 0 ) { + s->status = PARA_STS_BUSY; + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_ONLINE; + s->status |= PARA_STS_ERROR; + } + else if (val & PARA_CTR_SELECT) { + if (val & PARA_CTR_STROBE) { + s->status &= ~PARA_STS_BUSY; + if ((s->control & PARA_CTR_STROBE) == 0) + qemu_chr_write(s->chr, &s->dataw, 1); + } else { + if (s->control & PARA_CTR_INTEN) { + s->irq_pending = 1; + } + } + } + parallel_update_irq(s); + s->control = val; + break; + } +} + +static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val) +{ + ParallelState *s = opaque; + uint8_t parm = val; + + /* Sometimes programs do several writes for timing purposes on old + HW. Take care not to waste time on writes that do nothing. */ + + s->last_read_offset = ~0U; + addr &= 7; -#ifdef DEBUG_PARALLEL - printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val); -#endif switch(addr) { - case 0: - if (s->hw_driver) { - s->data = val; - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data); - } else { - s->data = val; - parallel_update_irq(s); - } + case PARA_REG_DATA: + if (s->dataw == val) + return; + pdebug("wd%02x\n", val); + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm); + s->dataw = val; break; - case 2: - if (s->hw_driver) { - s->control = val; - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control); - } else { - if ((val & PARA_CTR_INIT) == 0 ) { - s->status = PARA_STS_BUSY; - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_ONLINE; - s->status |= PARA_STS_ERROR; - } - else if (val & PARA_CTR_SELECT) { - if (val & PARA_CTR_STROBE) { - s->status &= ~PARA_STS_BUSY; - if ((s->control & PARA_CTR_STROBE) == 0) - qemu_chr_write(s->chr, &s->data, 1); - } else { - if (s->control & PARA_CTR_INTEN) { - s->irq_pending = 1; - } - } - } - parallel_update_irq(s); - s->control = val; - } + case PARA_REG_STS: + pdebug("ws%02x\n", val); + if (val & PARA_STS_TMOUT) + s->epp_timeout = 0; + break; + case PARA_REG_CTR: + val |= 0xc0; + if (s->control == val) + return; + pdebug("wc%02x\n", val); + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm); + s->control = val; break; + case PARA_REG_EPP_ADDR: + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) + /* Controls not correct for EPP address cycle, so do nothing */ + pdebug("wa%02x s\n", val); + else { + struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; + if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) { + s->epp_timeout = 1; + pdebug("wa%02x t\n", val); + } + else + pdebug("wa%02x\n", val); + } + break; + case PARA_REG_EPP_DATA: + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("we%02x s\n", val); + else { + struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; + if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) { + s->epp_timeout = 1; + pdebug("we%02x t\n", val); + } + else + pdebug("we%02x\n", val); + } + break; + } +} + +static void +parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val) +{ + ParallelState *s = opaque; + uint16_t eppdata = cpu_to_le16(val); + int err; + struct ParallelIOArg ioarg = { + .buffer = &eppdata, .count = sizeof(eppdata) + }; + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) { + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("we%04x s\n", val); + return; + } + err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); + if (err) { + s->epp_timeout = 1; + pdebug("we%04x t\n", val); + } + else + pdebug("we%04x\n", val); +} + +static void +parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val) +{ + ParallelState *s = opaque; + uint32_t eppdata = cpu_to_le32(val); + int err; + struct ParallelIOArg ioarg = { + .buffer = &eppdata, .count = sizeof(eppdata) + }; + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) { + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("we%08x s\n", val); + return; + } + err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); + if (err) { + s->epp_timeout = 1; + pdebug("we%08x t\n", val); } + else + pdebug("we%08x\n", val); } -static uint32_t parallel_ioport_read(void *opaque, uint32_t addr) +static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr) { ParallelState *s = opaque; uint32_t ret = 0xff; addr &= 7; switch(addr) { - case 0: - if (s->hw_driver) { - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data); - } - ret = s->data; + case PARA_REG_DATA: + if (s->control & PARA_CTR_DIR) + ret = s->datar; + else + ret = s->dataw; break; - case 1: - if (s->hw_driver) { - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status); - ret = s->status; - } else { - ret = s->status; - s->irq_pending = 0; - if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { - /* XXX Fixme: wait 5 microseconds */ - if (s->status & PARA_STS_ACK) - s->status &= ~PARA_STS_ACK; - else { - /* XXX Fixme: wait 5 microseconds */ - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_BUSY; - } - } - parallel_update_irq(s); - } + case PARA_REG_STS: + ret = s->status; + s->irq_pending = 0; + if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { + /* XXX Fixme: wait 5 microseconds */ + if (s->status & PARA_STS_ACK) + s->status &= ~PARA_STS_ACK; + else { + /* XXX Fixme: wait 5 microseconds */ + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_BUSY; + } + } + parallel_update_irq(s); break; - case 2: - if (s->hw_driver) { - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control); - } + case PARA_REG_CTR: ret = s->control; break; } -#ifdef DEBUG_PARALLEL - printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret); -#endif + pdebug("read addr=0x%02x val=0x%02x\n", addr, ret); + return ret; +} + +static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr) +{ + ParallelState *s = opaque; + uint8_t ret = 0xff; + addr &= 7; + switch(addr) { + case PARA_REG_DATA: + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret); + if (s->last_read_offset != addr || s->datar != ret) + pdebug("rd%02x\n", ret); + s->datar = ret; + break; + case PARA_REG_STS: + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret); + ret &= ~PARA_STS_TMOUT; + if (s->epp_timeout) + ret |= PARA_STS_TMOUT; + if (s->last_read_offset != addr || s->status != ret) + pdebug("rs%02x\n", ret); + s->status = ret; + break; + case PARA_REG_CTR: + /* s->control has some bits fixed to 1. It is zero only when + it has not been yet written to. */ + if (s->control == 0) { + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret); + if (s->last_read_offset != addr) + pdebug("rc%02x\n", ret); + s->control = ret; + } + else { + ret = s->control; + if (s->last_read_offset != addr) + pdebug("rc%02x\n", ret); + } + break; + case PARA_REG_EPP_ADDR: + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) + /* Controls not correct for EPP addr cycle, so do nothing */ + pdebug("ra%02x s\n", ret); + else { + struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; + if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) { + s->epp_timeout = 1; + pdebug("ra%02x t\n", ret); + } + else + pdebug("ra%02x\n", ret); + } + break; + case PARA_REG_EPP_DATA: + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("re%02x s\n", ret); + else { + struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; + if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) { + s->epp_timeout = 1; + pdebug("re%02x t\n", ret); + } + else + pdebug("re%02x\n", ret); + } + break; + } + s->last_read_offset = addr; + return ret; +} + +static uint32_t +parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr) +{ + ParallelState *s = opaque; + uint32_t ret; + uint16_t eppdata = ~0; + int err; + struct ParallelIOArg ioarg = { + .buffer = &eppdata, .count = sizeof(eppdata) + }; + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) { + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("re%04x s\n", eppdata); + return eppdata; + } + err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); + ret = le16_to_cpu(eppdata); + + if (err) { + s->epp_timeout = 1; + pdebug("re%04x t\n", ret); + } + else + pdebug("re%04x\n", ret); + return ret; +} + +static uint32_t +parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr) +{ + ParallelState *s = opaque; + uint32_t ret; + uint32_t eppdata = ~0U; + int err; + struct ParallelIOArg ioarg = { + .buffer = &eppdata, .count = sizeof(eppdata) + }; + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) { + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("re%08x s\n", eppdata); + return eppdata; + } + err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); + ret = le32_to_cpu(eppdata); + + if (err) { + s->epp_timeout = 1; + pdebug("re%08x t\n", ret); + } + else + pdebug("re%08x\n", ret); + return ret; +} + +static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val) +{ + addr &= 7; + pdebug("wecp%d=%02x\n", addr, val); +} + +static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr) +{ + uint8_t ret = 0xff; + addr &= 7; + pdebug("recp%d:%02x\n", addr, ret); return ret; } @@ -163,21 +409,39 @@ ParallelState *parallel_init(int base, int irq, CharDriverState *chr) s = qemu_mallocz(sizeof(ParallelState)); if (!s) return NULL; - s->chr = chr; - s->hw_driver = 0; - if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) - s->hw_driver = 1; - - s->irq = irq; - s->data = 0; + s->datar = ~0; + s->dataw = ~0; s->status = PARA_STS_BUSY; s->status |= PARA_STS_ACK; s->status |= PARA_STS_ONLINE; s->status |= PARA_STS_ERROR; s->control = PARA_CTR_SELECT; s->control |= PARA_CTR_INIT; + s->irq = irq; + s->irq_pending = 0; + s->chr = chr; + s->hw_driver = 0; + s->epp_timeout = 0; + s->last_read_offset = ~0U; - register_ioport_write(base, 8, 1, parallel_ioport_write, s); - register_ioport_read(base, 8, 1, parallel_ioport_read, s); + if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) { + s->hw_driver = 1; + s->status = dummy; + } + + if (s->hw_driver) { + register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s); + register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s); + register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s); + register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s); + register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s); + register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s); + register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s); + register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s); + } + else { + register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s); + register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s); + } return s; } diff --git a/qemu-doc.texi b/qemu-doc.texi index 9bc6b5a91..a4c99708e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -541,7 +541,7 @@ void device parameters are set according to the emulated ones. @item /dev/parportN [Linux only, parallel port only] Use host parallel port -@var{N}. Currently only SPP parallel port features can be used. +@var{N}. Currently SPP and EPP parallel port features can be used. @item file:filename Write output to filename. No character can be read. @item stdio diff --git a/vl.c b/vl.c index 009febb4c..0a527a77a 100644 --- a/vl.c +++ b/vl.c @@ -55,6 +55,7 @@ #include #include #include +#include #else #include #include @@ -1813,9 +1814,26 @@ static CharDriverState *qemu_chr_open_tty(const char *filename) return chr; } +typedef struct { + int fd; + int mode; +} ParallelCharDriver; + +static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode) +{ + if (s->mode != mode) { + int m = mode; + if (ioctl(s->fd, PPSETMODE, &m) < 0) + return 0; + s->mode = mode; + } + return 1; +} + static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) { - int fd = (int)chr->opaque; + ParallelCharDriver *drv = chr->opaque; + int fd = drv->fd; uint8_t b; switch(cmd) { @@ -1832,7 +1850,10 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) case CHR_IOCTL_PP_READ_CONTROL: if (ioctl(fd, PPRCONTROL, &b) < 0) return -ENOTSUP; - *(uint8_t *)arg = b; + /* Linux gives only the lowest bits, and no way to know data + direction! For better compatibility set the fixed upper + bits. */ + *(uint8_t *)arg = b | 0xc0; break; case CHR_IOCTL_PP_WRITE_CONTROL: b = *(uint8_t *)arg; @@ -1844,15 +1865,63 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) return -ENOTSUP; *(uint8_t *)arg = b; break; + case CHR_IOCTL_PP_EPP_READ_ADDR: + if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) { + struct ParallelIOArg *parg = arg; + int n = read(fd, parg->buffer, parg->count); + if (n != parg->count) { + return -EIO; + } + } + break; + case CHR_IOCTL_PP_EPP_READ: + if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) { + struct ParallelIOArg *parg = arg; + int n = read(fd, parg->buffer, parg->count); + if (n != parg->count) { + return -EIO; + } + } + break; + case CHR_IOCTL_PP_EPP_WRITE_ADDR: + if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) { + struct ParallelIOArg *parg = arg; + int n = write(fd, parg->buffer, parg->count); + if (n != parg->count) { + return -EIO; + } + } + break; + case CHR_IOCTL_PP_EPP_WRITE: + if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) { + struct ParallelIOArg *parg = arg; + int n = write(fd, parg->buffer, parg->count); + if (n != parg->count) { + return -EIO; + } + } + break; default: return -ENOTSUP; } return 0; } +static void pp_close(CharDriverState *chr) +{ + ParallelCharDriver *drv = chr->opaque; + int fd = drv->fd; + + pp_hw_mode(drv, IEEE1284_MODE_COMPAT); + ioctl(fd, PPRELEASE); + close(fd); + qemu_free(drv); +} + static CharDriverState *qemu_chr_open_pp(const char *filename) { CharDriverState *chr; + ParallelCharDriver *drv; int fd; fd = open(filename, O_RDWR); @@ -1864,14 +1933,24 @@ static CharDriverState *qemu_chr_open_pp(const char *filename) return NULL; } + drv = qemu_mallocz(sizeof(ParallelCharDriver)); + if (!drv) { + close(fd); + return NULL; + } + drv->fd = fd; + drv->mode = IEEE1284_MODE_COMPAT; + chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) { + qemu_free(drv); close(fd); return NULL; } - chr->opaque = (void *)fd; chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; + chr->chr_close = pp_close; + chr->opaque = drv; qemu_chr_reset(chr); diff --git a/vl.h b/vl.h index a06ce1834..79de55fa0 100644 --- a/vl.h +++ b/vl.h @@ -285,6 +285,10 @@ typedef struct { #define CHR_IOCTL_PP_READ_CONTROL 5 #define CHR_IOCTL_PP_WRITE_CONTROL 6 #define CHR_IOCTL_PP_READ_STATUS 7 +#define CHR_IOCTL_PP_EPP_READ_ADDR 8 +#define CHR_IOCTL_PP_EPP_READ 9 +#define CHR_IOCTL_PP_EPP_WRITE_ADDR 10 +#define CHR_IOCTL_PP_EPP_WRITE 11 typedef void IOEventHandler(void *opaque, int event); @@ -349,6 +353,11 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; +struct ParallelIOArg { + void *buffer; + int count; +}; + /* VLANs support */ typedef struct VLANClientState VLANClientState; -- cgit v1.2.3 From b7678d96c52b5e902283e538007e7b8e001dbc19 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Feb 2007 00:08:44 +0000 Subject: PS/2 interface - Allow custom IO ports + IRQ, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2431 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index 3c41e5f60..de40a09aa 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -121,6 +121,9 @@ typedef struct KBDState { uint8_t pending; void *kbd; void *mouse; + + int irq_kbd; + int irq_mouse; } KBDState; KBDState kbd_state; @@ -130,10 +133,10 @@ KBDState kbd_state; incorrect, but it avoids having to simulate exact delays */ static void kbd_update_irq(KBDState *s) { - int irq12_level, irq1_level; + int irq_kbd_level, irq_mouse_level; - irq1_level = 0; - irq12_level = 0; + irq_kbd_level = 0; + irq_mouse_level = 0; s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); if (s->pending) { s->status |= KBD_STAT_OBF; @@ -141,15 +144,15 @@ static void kbd_update_irq(KBDState *s) if (s->pending == KBD_PENDING_AUX) { s->status |= KBD_STAT_MOUSE_OBF; if (s->mode & KBD_MODE_MOUSE_INT) - irq12_level = 1; + irq_mouse_level = 1; } else { if ((s->mode & KBD_MODE_KBD_INT) && !(s->mode & KBD_MODE_DISABLE_KBD)) - irq1_level = 1; + irq_kbd_level = 1; } } - pic_set_irq(1, irq1_level); - pic_set_irq(12, irq12_level); + pic_set_irq(s->irq_kbd, irq_kbd_level); + pic_set_irq(s->irq_mouse, irq_mouse_level); } static void kbd_update_kbd_irq(void *opaque, int level) @@ -353,18 +356,26 @@ static int kbd_load(QEMUFile* f, void* opaque, int version_id) return 0; } -void kbd_init(void) +void i8042_init(int kbd_irq_lvl, int mouse_irq_lvl, uint32_t io_base) { KBDState *s = &kbd_state; + + s->irq_kbd = kbd_irq_lvl; + s->irq_mouse = mouse_irq_lvl; kbd_reset(s); register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); - register_ioport_read(0x60, 1, 1, kbd_read_data, s); - register_ioport_write(0x60, 1, 1, kbd_write_data, s); - register_ioport_read(0x64, 1, 1, kbd_read_status, s); - register_ioport_write(0x64, 1, 1, kbd_write_command, s); + register_ioport_read(io_base, 1, 1, kbd_read_data, s); + register_ioport_write(io_base, 1, 1, kbd_write_data, s); + register_ioport_read(io_base + 4, 1, 1, kbd_read_status, s); + register_ioport_write(io_base + 4, 1, 1, kbd_write_command, s); s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); qemu_register_reset(kbd_reset, s); } + +void kbd_init(void) +{ + return i8042_init(1, 12, 0x60); +} -- cgit v1.2.3 From 70705261e1c9762b149a2180e60b974ea9a5c2f0 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Feb 2007 00:10:59 +0000 Subject: Add PS/2 keyboard to MIPS R4K, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2432 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 1 + hw/mips_r4k.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 029e18e68..6df94dbaf 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -490,6 +490,7 @@ static void main_cpu_reset(void *opaque) load_kernel (env); } +static void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 8d1cac939..7d3ddd934 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -126,6 +126,7 @@ static void main_cpu_reset(void *opaque) env->kernel_cmdline, env->initrd_filename); } +static void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -212,6 +213,8 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < 2; i++) isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], bs_table[2 * i], bs_table[2 * i + 1]); + + kbd_init(); } QEMUMachine mips_machine = { -- cgit v1.2.3 From 925fd0f202e430fc18e1e4986cc066ea44504c9e Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Feb 2007 00:19:08 +0000 Subject: Fix sign-extension of VPN field in TLB, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2433 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 2 +- target-mips/op.c | 2 +- target-mips/op_helper.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index d2d7a9f87..51b8ca102 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -41,12 +41,12 @@ enum { static int map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) { + uint8_t ASID = env->CP0_EntryHi & 0xFF; int i; for (i = 0; i < env->tlb_in_use; i++) { tlb_t *tlb = &env->tlb[i]; /* 1k pages are not supported. */ - uint8_t ASID = env->CP0_EntryHi & 0xFF; target_ulong mask = tlb->PageMask | 0x1FFF; target_ulong tag = address & ~mask; int n; diff --git a/target-mips/op.c b/target-mips/op.c index cd5c69ca4..34c17c1ab 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1340,7 +1340,7 @@ void op_mtc0_entryhi (void) /* 1k pages not implemented */ /* Ignore MIPS64 TLB for now */ - val = (int32_t)T0 & 0xFFFFE0FF; + val = (target_ulong)(int32_t)T0 & ~(target_ulong)0x1F00; old = env->CP0_EntryHi; env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9596d04fb..1b8d9351a 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -395,7 +395,7 @@ static void fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb[idx]; - tlb->VPN = env->CP0_EntryHi & (int32_t)0xFFFFE000; + tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF; tlb->ASID = env->CP0_EntryHi & 0xFF; tlb->PageMask = env->CP0_PageMask; tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; -- cgit v1.2.3 From 20d8a3edb062c96f9a08ccf0637f76ae2563c5e1 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Feb 2007 17:04:49 +0000 Subject: Monitor multiplexing, by Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2434 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 32 ++++- qemu-doc.texi | 27 ++++ vl.c | 441 +++++++++++++++++++++++++++++++++++++--------------------- vl.h | 1 + 4 files changed, 335 insertions(+), 166 deletions(-) diff --git a/monitor.c b/monitor.c index 1e9b904bf..cd0663e93 100644 --- a/monitor.c +++ b/monitor.c @@ -54,7 +54,8 @@ typedef struct term_cmd_t { const char *help; } term_cmd_t; -static CharDriverState *monitor_hd; +#define MAX_MON 4 +static CharDriverState *monitor_hd[MAX_MON]; static int hide_banner; static term_cmd_t term_cmds[]; @@ -69,8 +70,11 @@ CPUState *mon_cpu = NULL; void term_flush(void) { + int i; if (term_outbuf_index > 0) { - qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); + for (i = 0; i < MAX_MON; i++) + if (monitor_hd[i] && monitor_hd[i]->focus == 0) + qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index); term_outbuf_index = 0; } } @@ -2452,9 +2456,25 @@ static void term_event(void *opaque, int event) monitor_start_input(); } +static int is_first_init = 1; + void monitor_init(CharDriverState *hd, int show_banner) { - monitor_hd = hd; + int i; + + if (is_first_init) { + for (i = 0; i < MAX_MON; i++) { + monitor_hd[i] = NULL; + } + is_first_init = 0; + } + for (i = 0; i < MAX_MON; i++) { + if (monitor_hd[i] == NULL) { + monitor_hd[i] = hd; + break; + } + } + hide_banner = !show_banner; qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL); @@ -2475,8 +2495,12 @@ static void monitor_readline_cb(void *opaque, const char *input) void monitor_readline(const char *prompt, int is_password, char *buf, int buf_size) { + int i; + if (is_password) { - qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS); + for (i = 0; i < MAX_MON; i++) + if (monitor_hd[i] && monitor_hd[i]->focus == 0) + qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS); } readline_start(prompt, is_password, monitor_readline_cb, NULL); monitor_readline_buf = buf; diff --git a/qemu-doc.texi b/qemu-doc.texi index a4c99708e..b539747df 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -610,6 +610,18 @@ A unix domain socket is used instead of a tcp socket. The option works the same as if you had specified @code{-serial tcp} except the unix domain socket @var{path} is used for connections. +@item mon:dev_string +This is a special option to allow the monitor to be multiplexed onto +another serial port. The monitor is accessed with key sequence of +@key{Control-a} and then pressing @key{c}. See monitor access +@ref{pcsys_keys} in the -nographic section for more keys. +@var{dev_string} should be any one of the serial devices specified +above. An example to multiplex the monitor onto a telnet server +listening on port 4444 would be: +@table @code +@item -serial mon:telnet::4444,server,nowait +@end table + @end table @item -parallel dev @@ -629,6 +641,19 @@ serial port). The default device is @code{vc} in graphical mode and @code{stdio} in non graphical mode. +@item -echr numeric_ascii_value +Change the escape character used for switching to the monitor when using +monitor and serial sharing. The default is @code{0x01} when using the +@code{-nographic} option. @code{0x01} is equal to pressing +@code{Control-a}. You can select a different character from the ascii +control keys where 1 through 26 map to Control-a through Control-z. For +instance you could use the either of the following to change the escape +character to Control-t. +@table @code +@item -echr 0x14 +@item -echr 20 +@end table + @item -s Wait gdb connection to port 1234 (@pxref{gdb_usage}). @item -p port @@ -711,6 +736,8 @@ Print this help Exit emulator @item Ctrl-a s Save disk data back to file (if -snapshot) +@item Ctrl-a t +toggle console timestamps @item Ctrl-a b Send break (magic sysrq in Linux) @item Ctrl-a c diff --git a/vl.c b/vl.c index 0a527a77a..de53b7219 100644 --- a/vl.c +++ b/vl.c @@ -1228,6 +1228,218 @@ static CharDriverState *qemu_chr_open_null(void) return chr; } +/* MUX driver for serial I/O splitting */ +static int term_timestamps; +static int64_t term_timestamps_start; +#define MAX_MUX 2 +typedef struct { + IOCanRWHandler *chr_can_read[MAX_MUX]; + IOReadHandler *chr_read[MAX_MUX]; + IOEventHandler *chr_event[MAX_MUX]; + void *ext_opaque[MAX_MUX]; + CharDriverState *drv; + int mux_cnt; + int term_got_escape; + int max_size; +} MuxDriver; + + +static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + MuxDriver *d = chr->opaque; + int ret; + if (!term_timestamps) { + ret = d->drv->chr_write(d->drv, buf, len); + } else { + int i; + + ret = 0; + for(i = 0; i < len; i++) { + ret += d->drv->chr_write(d->drv, buf+i, 1); + if (buf[i] == '\n') { + char buf1[64]; + int64_t ti; + int secs; + + ti = get_clock(); + if (term_timestamps_start == -1) + term_timestamps_start = ti; + ti -= term_timestamps_start; + secs = ti / 1000000000; + snprintf(buf1, sizeof(buf1), + "[%02d:%02d:%02d.%03d] ", + secs / 3600, + (secs / 60) % 60, + secs % 60, + (int)((ti / 1000000) % 1000)); + d->drv->chr_write(d->drv, buf1, strlen(buf1)); + } + } + } + return ret; +} + +static char *mux_help[] = { + "% h print this help\n\r", + "% x exit emulator\n\r", + "% s save disk data back to file (if -snapshot)\n\r", + "% t toggle console timestamps\n\r" + "% b send break (magic sysrq)\n\r", + "% c switch between console and monitor\n\r", + "% % sends %\n\r", + NULL +}; + +static int term_escape_char = 0x01; /* ctrl-a is used for escape */ +static void mux_print_help(CharDriverState *chr) +{ + int i, j; + char ebuf[15] = "Escape-Char"; + char cbuf[50] = "\n\r"; + + if (term_escape_char > 0 && term_escape_char < 26) { + sprintf(cbuf,"\n\r"); + sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a'); + } else { + sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", term_escape_char); + } + chr->chr_write(chr, cbuf, strlen(cbuf)); + for (i = 0; mux_help[i] != NULL; i++) { + for (j=0; mux_help[i][j] != '\0'; j++) { + if (mux_help[i][j] == '%') + chr->chr_write(chr, ebuf, strlen(ebuf)); + else + chr->chr_write(chr, &mux_help[i][j], 1); + } + } +} + +static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) +{ + if (d->term_got_escape) { + d->term_got_escape = 0; + if (ch == term_escape_char) + goto send_char; + switch(ch) { + case '?': + case 'h': + mux_print_help(chr); + break; + case 'x': + { + char *term = "QEMU: Terminated\n\r"; + chr->chr_write(chr,term,strlen(term)); + exit(0); + break; + } + case 's': + { + int i; + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) + bdrv_commit(bs_table[i]); + } + } + break; + case 'b': + if (chr->chr_event) + chr->chr_event(chr->opaque, CHR_EVENT_BREAK); + break; + case 'c': + /* Switch to the next registered device */ + chr->focus++; + if (chr->focus >= d->mux_cnt) + chr->focus = 0; + break; + case 't': + term_timestamps = !term_timestamps; + term_timestamps_start = -1; + break; + } + } else if (ch == term_escape_char) { + d->term_got_escape = 1; + } else { + send_char: + return 1; + } + return 0; +} + +static int mux_chr_can_read(void *opaque) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + if (d->chr_can_read[chr->focus]) + return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); + return 0; +} + +static void mux_chr_read(void *opaque, const uint8_t *buf, int size) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + int i; + for(i = 0; i < size; i++) + if (mux_proc_byte(chr, d, buf[i])) + d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1); +} + +static void mux_chr_event(void *opaque, int event) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + int i; + + /* Send the event to all registered listeners */ + for (i = 0; i < d->mux_cnt; i++) + if (d->chr_event[i]) + d->chr_event[i](d->ext_opaque[i], event); +} + +static void mux_chr_update_read_handler(CharDriverState *chr) +{ + MuxDriver *d = chr->opaque; + + if (d->mux_cnt >= MAX_MUX) { + fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); + return; + } + d->ext_opaque[d->mux_cnt] = chr->handler_opaque; + d->chr_can_read[d->mux_cnt] = chr->chr_can_read; + d->chr_read[d->mux_cnt] = chr->chr_read; + d->chr_event[d->mux_cnt] = chr->chr_event; + /* Fix up the real driver with mux routines */ + if (d->mux_cnt == 0) { + qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, + mux_chr_event, chr); + } + chr->focus = d->mux_cnt; + d->mux_cnt++; +} + +CharDriverState *qemu_chr_open_mux(CharDriverState *drv) +{ + CharDriverState *chr; + MuxDriver *d; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + d = qemu_mallocz(sizeof(MuxDriver)); + if (!d) { + free(chr); + return NULL; + } + + chr->opaque = d; + d->drv = drv; + chr->focus = -1; + chr->chr_write = mux_chr_write; + chr->chr_update_read_handler = mux_chr_update_read_handler; + return chr; +} + + #ifdef _WIN32 static void socket_cleanup(void) @@ -1319,10 +1531,8 @@ typedef struct { int max_size; } FDCharDriver; -#define STDIO_MAX_CLIENTS 2 - -static int stdio_nb_clients; -static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; +#define STDIO_MAX_CLIENTS 1 +static int stdio_nb_clients = 0; static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { @@ -1435,162 +1645,45 @@ static CharDriverState *qemu_chr_open_pipe(const char *filename) /* for STDIO, we handle the case where several clients use it (nographic mode) */ -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ - #define TERM_FIFO_MAX_SIZE 1 -static int term_got_escape, client_index; static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; static int term_fifo_size; -static int term_timestamps; -static int64_t term_timestamps_start; - -void term_print_help(void) -{ - printf("\n" - "C-a h print this help\n" - "C-a x exit emulator\n" - "C-a s save disk data back to file (if -snapshot)\n" - "C-a b send break (magic sysrq)\n" - "C-a t toggle console timestamps\n" - "C-a c switch between console and monitor\n" - "C-a C-a send C-a\n" - ); -} - -/* called when a char is received */ -static void stdio_received_byte(int ch) -{ - if (term_got_escape) { - term_got_escape = 0; - switch(ch) { - case 'h': - term_print_help(); - break; - case 'x': - exit(0); - break; - case 's': - { - int i; - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) - bdrv_commit(bs_table[i]); - } - } - break; - case 'b': - if (client_index < stdio_nb_clients) { - CharDriverState *chr; - FDCharDriver *s; - - chr = stdio_clients[client_index]; - s = chr->opaque; - qemu_chr_event(chr, CHR_EVENT_BREAK); - } - break; - case 'c': - client_index++; - if (client_index >= stdio_nb_clients) - client_index = 0; - if (client_index == 0) { - /* send a new line in the monitor to get the prompt */ - ch = '\r'; - goto send_char; - } - break; - case 't': - term_timestamps = !term_timestamps; - term_timestamps_start = -1; - break; - case TERM_ESCAPE: - goto send_char; - } - } else if (ch == TERM_ESCAPE) { - term_got_escape = 1; - } else { - send_char: - if (client_index < stdio_nb_clients) { - uint8_t buf[1]; - CharDriverState *chr; - - chr = stdio_clients[client_index]; - if (qemu_chr_can_read(chr) > 0) { - buf[0] = ch; - qemu_chr_read(chr, buf, 1); - } else if (term_fifo_size == 0) { - term_fifo[term_fifo_size++] = ch; - } - } - } -} static int stdio_read_poll(void *opaque) { - CharDriverState *chr; + CharDriverState *chr = opaque; - if (client_index < stdio_nb_clients) { - chr = stdio_clients[client_index]; - /* try to flush the queue if needed */ - if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { - qemu_chr_read(chr, term_fifo, 1); - term_fifo_size = 0; - } - /* see if we can absorb more chars */ - if (term_fifo_size == 0) - return 1; - else - return 0; - } else { - return 1; + /* try to flush the queue if needed */ + if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { + qemu_chr_read(chr, term_fifo, 1); + term_fifo_size = 0; } + /* see if we can absorb more chars */ + if (term_fifo_size == 0) + return 1; + else + return 0; } static void stdio_read(void *opaque) { int size; uint8_t buf[1]; - + CharDriverState *chr = opaque; + size = read(0, buf, 1); if (size == 0) { /* stdin has been closed. Remove it from the active list. */ qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); return; } - if (size > 0) - stdio_received_byte(buf[0]); -} - -static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len) -{ - FDCharDriver *s = chr->opaque; - if (!term_timestamps) { - return unix_write(s->fd_out, buf, len); - } else { - int i; - char buf1[64]; - - for(i = 0; i < len; i++) { - unix_write(s->fd_out, buf + i, 1); - if (buf[i] == '\n') { - int64_t ti; - int secs; - - ti = get_clock(); - if (term_timestamps_start == -1) - term_timestamps_start = ti; - ti -= term_timestamps_start; - secs = ti / 1000000000; - snprintf(buf1, sizeof(buf1), - "[%02d:%02d:%02d.%03d] ", - secs / 3600, - (secs / 60) % 60, - secs % 60, - (int)((ti / 1000000) % 1000)); - unix_write(s->fd_out, buf1, strlen(buf1)); - } + if (size > 0) { + if (qemu_chr_can_read(chr) > 0) { + qemu_chr_read(chr, buf, 1); + } else if (term_fifo_size == 0) { + term_fifo[term_fifo_size++] = buf[0]; } - return len; } } @@ -1635,24 +1728,13 @@ static CharDriverState *qemu_chr_open_stdio(void) { CharDriverState *chr; - if (nographic) { - if (stdio_nb_clients >= STDIO_MAX_CLIENTS) - return NULL; - chr = qemu_chr_open_fd(0, 1); - chr->chr_write = stdio_write; - if (stdio_nb_clients == 0) - qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL); - client_index = stdio_nb_clients; - } else { - if (stdio_nb_clients != 0) - return NULL; - chr = qemu_chr_open_fd(0, 1); - } - stdio_clients[stdio_nb_clients++] = chr; - if (stdio_nb_clients == 1) { - /* set the terminal in raw mode */ - term_init(); - } + if (stdio_nb_clients >= STDIO_MAX_CLIENTS) + return NULL; + chr = qemu_chr_open_fd(0, 1); + qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); + stdio_nb_clients++; + term_init(); + return chr; } @@ -2815,6 +2897,16 @@ CharDriverState *qemu_chr_open(const char *filename) if (strstart(filename, "udp:", &p)) { return qemu_chr_open_udp(p); } else + if (strstart(filename, "mon:", &p)) { + CharDriverState *drv = qemu_chr_open(p); + if (drv) { + drv = qemu_chr_open_mux(drv); + monitor_init(drv, !nographic); + return drv; + } + printf("Unable to open driver: %s\n", p); + return 0; + } else #ifndef _WIN32 if (strstart(filename, "unix:", &p)) { return qemu_chr_open_tcp(p, 0, 1); @@ -6416,6 +6508,7 @@ enum { QEMU_OPTION_cirrusvga, QEMU_OPTION_g, QEMU_OPTION_std_vga, + QEMU_OPTION_echr, QEMU_OPTION_monitor, QEMU_OPTION_serial, QEMU_OPTION_parallel, @@ -6497,6 +6590,7 @@ const QEMUOption qemu_options[] = { #endif { "localtime", 0, QEMU_OPTION_localtime }, { "std-vga", 0, QEMU_OPTION_std_vga }, + { "echr", 1, QEMU_OPTION_echr }, { "monitor", 1, QEMU_OPTION_monitor }, { "serial", 1, QEMU_OPTION_serial }, { "parallel", 1, QEMU_OPTION_parallel }, @@ -6932,8 +7026,8 @@ int main(int argc, char **argv) } break; case QEMU_OPTION_nographic: - pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); + pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); nographic = 1; break; case QEMU_OPTION_kernel: @@ -7094,6 +7188,14 @@ int main(int argc, char **argv) graphic_depth = depth; } break; + case QEMU_OPTION_echr: + { + char *r; + term_escape_char = strtol(optarg, &r, 0); + if (r == optarg) + printf("Bad argument to echr\n"); + break; + } case QEMU_OPTION_monitor: pstrcpy(monitor_device, sizeof(monitor_device), optarg); break; @@ -7384,12 +7486,27 @@ int main(int argc, char **argv) #endif } - monitor_hd = qemu_chr_open(monitor_device); - if (!monitor_hd) { - fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); - exit(1); + /* Maintain compatibility with multiple stdio monitors */ + if (!strcmp(monitor_device,"stdio")) { + for (i = 0; i < MAX_SERIAL_PORTS; i++) { + if (!strcmp(serial_devices[i],"mon:stdio")) { + monitor_device[0] = '\0'; + break; + } else if (!strcmp(serial_devices[i],"stdio")) { + monitor_device[0] = '\0'; + pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "mon:stdio"); + break; + } + } + } + if (monitor_device[0] != '\0') { + monitor_hd = qemu_chr_open(monitor_device); + if (!monitor_hd) { + fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); + exit(1); + } + monitor_init(monitor_hd, !nographic); } - monitor_init(monitor_hd, !nographic); for(i = 0; i < MAX_SERIAL_PORTS; i++) { const char *devname = serial_devices[i]; diff --git a/vl.h b/vl.h index 79de55fa0..bcaf004dd 100644 --- a/vl.h +++ b/vl.h @@ -303,6 +303,7 @@ typedef struct CharDriverState { void (*chr_send_event)(struct CharDriverState *chr, int event); void (*chr_close)(struct CharDriverState *chr); void *opaque; + int focus; QEMUBH *bh; } CharDriverState; -- cgit v1.2.3 From 43523e9332e79a8ecbcec8444f975b8a705aa9d3 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Feb 2007 18:19:32 +0000 Subject: -no-frame option for sdl, by Christian Laursen. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2435 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 8 +++++++- vl.c | 9 ++++++++- vl.h | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/sdl.c b/sdl.c index 87ad3903c..0cb22411d 100644 --- a/sdl.c +++ b/sdl.c @@ -34,6 +34,7 @@ static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static int last_vm_running; static int gui_saved_grab; static int gui_fullscreen; +static int gui_noframe; static int gui_key_modifier_pressed; static int gui_keysym; static int gui_fullscreen_initial_grab; @@ -59,6 +60,8 @@ static void sdl_resize(DisplayState *ds, int w, int h) flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; if (gui_fullscreen) flags |= SDL_FULLSCREEN; + if (gui_noframe) + flags |= SDL_NOFRAME; width = w; height = h; @@ -469,7 +472,7 @@ static void sdl_cleanup(void) SDL_Quit(); } -void sdl_display_init(DisplayState *ds, int full_screen) +void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) { int flags; uint8_t data = 0; @@ -485,6 +488,9 @@ void sdl_display_init(DisplayState *ds, int full_screen) exit(1); } + if (no_frame) + gui_noframe = 1; + flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; if (SDL_Init (flags)) { fprintf(stderr, "Could not initialize SDL - exiting\n"); diff --git a/vl.c b/vl.c index de53b7219..3dfa23c6f 100644 --- a/vl.c +++ b/vl.c @@ -163,6 +163,7 @@ int graphic_height = 600; #endif int graphic_depth = 15; int full_screen = 0; +int no_frame = 0; int no_quit = 0; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; @@ -6345,6 +6346,7 @@ void help(void) "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" "-snapshot write to temporary files instead of disk image files\n" #ifdef CONFIG_SDL + "-no-frame open SDL window without a frame and window decorations\n" "-no-quit disable SDL window close capability\n" #endif #ifdef TARGET_I386 @@ -6514,6 +6516,7 @@ enum { QEMU_OPTION_parallel, QEMU_OPTION_loadvm, QEMU_OPTION_full_screen, + QEMU_OPTION_no_frame, QEMU_OPTION_no_quit, QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, @@ -6597,6 +6600,7 @@ const QEMUOption qemu_options[] = { { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, { "full-screen", 0, QEMU_OPTION_full_screen }, #ifdef CONFIG_SDL + { "no-frame", 0, QEMU_OPTION_no_frame }, { "no-quit", 0, QEMU_OPTION_no_quit }, #endif { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, @@ -7224,6 +7228,9 @@ int main(int argc, char **argv) full_screen = 1; break; #ifdef CONFIG_SDL + case QEMU_OPTION_no_frame: + no_frame = 1; + break; case QEMU_OPTION_no_quit: no_quit = 1; break; @@ -7478,7 +7485,7 @@ int main(int argc, char **argv) vnc_display_init(ds, vnc_display); } else { #if defined(CONFIG_SDL) - sdl_display_init(ds, full_screen); + sdl_display_init(ds, full_screen, no_frame); #elif defined(CONFIG_COCOA) cocoa_display_init(ds, full_screen); #else diff --git a/vl.h b/vl.h index bcaf004dd..005ff1330 100644 --- a/vl.h +++ b/vl.h @@ -911,7 +911,7 @@ void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); /* sdl.c */ -void sdl_display_init(DisplayState *ds, int full_screen); +void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); /* cocoa.m */ void cocoa_display_init(DisplayState *ds, int full_screen); -- cgit v1.2.3 From 292eef5acb679a65c5f0fbdee65fb372263d50da Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Feb 2007 00:59:34 +0000 Subject: Ignore special flags in nsector variable. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2436 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 190f07493..9e5451fb9 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -794,7 +794,7 @@ static void ide_sector_write(IDEState *s) ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); s->nsector -= n; if (s->nsector == 0) { - /* no more sector to write */ + /* no more sectors to write */ ide_transfer_stop(s); } else { n1 = s->nsector; @@ -1631,12 +1631,12 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) ide_set_irq(s); break; case WIN_SETMULT: - if (s->nsector > MAX_MULT_SECTORS || + if ((s->nsector & 0xff) > MAX_MULT_SECTORS || s->nsector == 0 || (s->nsector & (s->nsector - 1)) != 0) { ide_abort_command(s); } else { - s->mult_sectors = s->nsector; + s->mult_sectors = s->nsector & 0xff; s->status = READY_STAT; } ide_set_irq(s); -- cgit v1.2.3 From d84fe7aef05a84349803ee49b07b002acee1f6e3 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Feb 2007 01:10:26 +0000 Subject: Don't require a disk image for network boot, by Ferenc Wagner. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2437 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.c b/vl.c index 3dfa23c6f..28d8eb34d 100644 --- a/vl.c +++ b/vl.c @@ -7354,6 +7354,7 @@ int main(int argc, char **argv) linux_boot = (kernel_filename != NULL); if (!linux_boot && + boot_device != 'n' && hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') -- cgit v1.2.3 From 5f189496c4a34e337d77680b0eebc1c0adc32caf Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Feb 2007 01:23:15 +0000 Subject: Document -no-frame option. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2438 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index b539747df..00b28a6d4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -247,6 +247,12 @@ command line application. The emulated serial port is redirected on the console. Therefore, you can still use QEMU to debug a Linux kernel with a serial console. +@item -no-frame + +Do not use decorations for SDL windows and start them using the whole +available screen space. This makes the using QEMU in a dedicated desktop +workspace more convenient. + @item -vnc display Normally, QEMU uses SDL to display the VGA output. With this option, -- cgit v1.2.3 From 47d5d01a45d64d231fb856a9cdfecf5d567371e6 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Feb 2007 00:05:08 +0000 Subject: Add -bootp option for slirp, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2439 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 10 ++++++++++ slirp/bootp.c | 6 ++++++ vl.c | 6 ++++++ vl.h | 1 + 4 files changed, 23 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 00b28a6d4..b23b03377 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -452,6 +452,16 @@ guest must be configured in binary mode (use the command @code{bin} of the Unix TFTP client). The host IP address on the guest is as usual 10.0.2.2. +@item -bootp file +When using the user mode network stack, broadcast @var{file} as the BOOTP +filename. In conjunction with @option{-tftp}, this can be used to network boot +a guest from a local directory. + +Example (using pxelinux): +@example +qemu -hda linux.img -boot n -tftp /path/to/tftp/files -bootp /pxelinux.0 +@end example + @item -smb dir When using the user mode network stack, activate a built-in SMB server so that Windows OSes can access to the host files in @file{dir} diff --git a/slirp/bootp.c b/slirp/bootp.c index 62cbcfd8f..9d243a705 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -38,6 +38,8 @@ typedef struct { BOOTPClient bootp_clients[NB_ADDR]; +const char *bootp_filename; + static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; #ifdef DEBUG @@ -168,6 +170,10 @@ static void bootp_reply(struct bootp_t *bp) goto new_addr; } } + + if (bootp_filename) + snprintf(rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename); + dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr)); saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); diff --git a/vl.c b/vl.c index 28d8eb34d..fd944e048 100644 --- a/vl.c +++ b/vl.c @@ -6403,6 +6403,7 @@ void help(void) "\n" #ifdef CONFIG_SLIRP "-tftp prefix allow tftp access to files starting with prefix [-net user]\n" + "-bootp file advertise file in BOOTP replies\n" #ifndef _WIN32 "-smb dir allow SMB access to files in 'dir' [-net user]\n" #endif @@ -6491,6 +6492,7 @@ enum { QEMU_OPTION_net, QEMU_OPTION_tftp, + QEMU_OPTION_bootp, QEMU_OPTION_smb, QEMU_OPTION_redir, @@ -6567,6 +6569,7 @@ const QEMUOption qemu_options[] = { { "net", HAS_ARG, QEMU_OPTION_net}, #ifdef CONFIG_SLIRP { "tftp", HAS_ARG, QEMU_OPTION_tftp }, + { "bootp", HAS_ARG, QEMU_OPTION_bootp }, #ifndef _WIN32 { "smb", HAS_ARG, QEMU_OPTION_smb }, #endif @@ -7085,6 +7088,9 @@ int main(int argc, char **argv) case QEMU_OPTION_tftp: tftp_prefix = optarg; break; + case QEMU_OPTION_bootp: + bootp_filename = optarg; + break; #ifndef _WIN32 case QEMU_OPTION_smb: net_slirp_smb(optarg); diff --git a/vl.h b/vl.h index 005ff1330..c6d305c1a 100644 --- a/vl.h +++ b/vl.h @@ -159,6 +159,7 @@ extern int smp_cpus; extern int no_quit; extern int semihosting_enabled; extern int autostart; +extern const char *bootp_filename; #define MAX_OPTION_ROMS 16 extern const char *option_rom[MAX_OPTION_ROMS]; -- cgit v1.2.3 From 1f697db9c3c22d3768175dbd70e7d5a68638e7b7 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Feb 2007 00:07:50 +0000 Subject: Add OACK support to slirp TFTP server, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2440 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/tftp.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ slirp/tftp.h | 1 + 2 files changed, 84 insertions(+) diff --git a/slirp/tftp.c b/slirp/tftp.c index c9946d6bf..b3947eb38 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -120,6 +120,45 @@ static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, return bytes_read; } +static int tftp_send_oack(struct tftp_session *spt, + const char *key, uint32_t value, + struct tftp_t *recv_tp) +{ + struct sockaddr_in saddr, daddr; + struct mbuf *m; + struct tftp_t *tp; + int n = 0; + + m = m_get(); + + if (!m) + return -1; + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_OACK); + n += sprintf(tp->x.tp_buf + n, "%s", key) + 1; + n += sprintf(tp->x.tp_buf + n, "%u", value) + 1; + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; + + daddr.sin_addr = spt->client_ip; + daddr.sin_port = spt->client_port; + + m->m_len = sizeof(struct tftp_t) - 514 + n - + sizeof(struct ip) - sizeof(struct udphdr); + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + return 0; +} + + + static int tftp_send_error(struct tftp_session *spt, u_int16_t errorcode, const char *msg, struct tftp_t *recv_tp) @@ -273,6 +312,8 @@ static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) return; } + k += 6; /* skipping octet */ + /* do sanity checks on the filename */ if ((spt->filename[0] != '/') @@ -297,6 +338,48 @@ static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) return; } + if (src[n - 1] != 0) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + while (k < n) { + const char *key, *value; + + key = src + k; + k += strlen(key) + 1; + + if (k >= n) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + value = src + k; + k += strlen(value) + 1; + + if (strcmp(key, "tsize") == 0) { + int tsize = atoi(value); + struct stat stat_p; + + if (tsize == 0 && tftp_prefix) { + char buffer[1024]; + int len; + + len = snprintf(buffer, sizeof(buffer), "%s/%s", + tftp_prefix, spt->filename); + + if (stat(buffer, &stat_p) == 0) + tsize = stat_p.st_size; + else { + tftp_send_error(spt, 1, "File not found", tp); + return; + } + } + + tftp_send_oack(spt, "tsize", tsize, tp); + } + } + tftp_send_data(spt, 1, tp); } diff --git a/slirp/tftp.h b/slirp/tftp.h index f0560b6ab..603f22bfd 100644 --- a/slirp/tftp.h +++ b/slirp/tftp.h @@ -9,6 +9,7 @@ #define TFTP_DATA 3 #define TFTP_ACK 4 #define TFTP_ERROR 5 +#define TFTP_OACK 6 #define TFTP_FILENAME_MAX 512 -- cgit v1.2.3 From 0db1137dbf5008d456b9cc80a5cf1222467fed9d Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Feb 2007 00:12:07 +0000 Subject: Change -tftp option to take a root directory, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2441 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 11 +++++------ slirp/tftp.c | 12 +++++++++--- vl.c | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index b23b03377..fe69e80b7 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -444,13 +444,12 @@ Indicate that no network devices should be configured. It is used to override the default configuration (@option{-net nic -net user}) which is activated if no @option{-net} options are provided. -@item -tftp prefix +@item -tftp dir When using the user mode network stack, activate a built-in TFTP -server. All filenames beginning with @var{prefix} can be downloaded -from the host to the guest using a TFTP client. The TFTP client on the -guest must be configured in binary mode (use the command @code{bin} of -the Unix TFTP client). The host IP address on the guest is as usual -10.0.2.2. +server. The files in @var{dir} will be exposed as the root of a TFTP server. +The TFTP client on the guest must be configured in binary mode (use the command +@code{bin} of the Unix TFTP client). The host IP address on the guest is as +usual 10.0.2.2. @item -bootp file When using the user mode network stack, broadcast @var{file} as the BOOTP diff --git a/slirp/tftp.c b/slirp/tftp.c index b3947eb38..96d00e62c 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -102,8 +102,15 @@ static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, { int fd; int bytes_read = 0; + char buffer[1024]; + int n; - fd = open(spt->filename, O_RDONLY | O_BINARY); + n = snprintf(buffer, sizeof(buffer), "%s/%s", + tftp_prefix, spt->filename); + if (n >= sizeof(buffer)) + return -1; + + fd = open(buffer, O_RDONLY | O_BINARY); if (fd < 0) { return -1; @@ -325,8 +332,7 @@ static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) /* only allow exported prefixes */ - if (!tftp_prefix - || (strncmp(spt->filename, tftp_prefix, strlen(tftp_prefix)) != 0)) { + if (!tftp_prefix) { tftp_send_error(spt, 2, "Access violation", tp); return; } diff --git a/vl.c b/vl.c index fd944e048..7a4058f7b 100644 --- a/vl.c +++ b/vl.c @@ -6402,7 +6402,7 @@ void help(void) " is provided, the default is '-net nic -net user'\n" "\n" #ifdef CONFIG_SLIRP - "-tftp prefix allow tftp access to files starting with prefix [-net user]\n" + "-tftp dir allow tftp access to files in dir [-net user]\n" "-bootp file advertise file in BOOTP replies\n" #ifndef _WIN32 "-smb dir allow SMB access to files in 'dir' [-net user]\n" -- cgit v1.2.3 From ad0504b5df46e745532a4e794810b749b487927e Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Feb 2007 00:18:37 +0000 Subject: Record important changes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2442 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changelog b/Changelog index c8a68ca2f..35709c3cd 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ + - TFTP booting from host directory (Anthony Liguori) + - Tap device emulation for Solaris (Sittichai Palanisong) + - Monitor multiplexing to several I/O channels (Jason Wessel) + version 0.9.0: - Support for relative paths in backing files for disk images -- cgit v1.2.3 From 32801d54654ecfc41ee7b86b90993c0b83c47f7e Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Feb 2007 13:39:32 +0000 Subject: 2nd serial port for Malta, by Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2443 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 6df94dbaf..155f5a818 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -570,6 +570,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, kbd_init(); rtc_state = rtc_init(0x70, 8); serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); + serial_init(&pic_set_irq_new, isa_pic, 0x2f8, 4, serial_hds[0]); parallel_init(0x378, 7, parallel_hds[0]); /* XXX: The floppy controller does not work correctly, something is probably wrong. -- cgit v1.2.3 From 3594c774873fb51fe119c214e78273f43e2556f8 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Feb 2007 23:37:21 +0000 Subject: Replace TLSZ with TARGET_FMT_lx. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2444 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 6 +++--- hw/mips_r4k.c | 2 +- target-mips/cpu.h | 7 ------- target-mips/helper.c | 12 ++++++------ target-mips/op_helper.c | 6 +++--- target-mips/op_helper_mem.c | 16 ++++++++-------- target-mips/translate.c | 38 +++++++++++++++++++------------------- 7 files changed, 40 insertions(+), 47 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 155f5a818..97431b1e6 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -160,7 +160,7 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) default: #if 0 - printf ("malta_fpga_read: Bad register offset 0x" TLSZ "\n", + printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n", addr); #endif break; @@ -244,7 +244,7 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, default: #if 0 - printf ("malta_fpga_write: Bad register offset 0x" TLSZ "\n", + printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n", addr); #endif break; @@ -464,7 +464,7 @@ static int64_t load_kernel (CPUState *env) /* Store command line. */ prom_set(index++, env->kernel_filename); if (initrd_size > 0) - prom_set(index++, "rd_start=0x" TLSZ " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline); + prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline); else prom_set(index++, env->kernel_cmdline); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 7d3ddd934..63ad36720 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -103,7 +103,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, if (initrd_size > 0) { int ret; ret = sprintf(phys_ram_base + (16 << 20) - 256, - "rd_start=0x" TLSZ " rd_size=%li ", + "rd_start=0x" TARGET_FMT_lx " rd_size=%li ", INITRD_LOAD_ADDR, initrd_size); strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index fb5a3fef3..6068813dc 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -17,13 +17,6 @@ typedef unsigned char uint_fast8_t; typedef unsigned int uint_fast16_t; #endif -/* target_ulong size spec */ -#ifdef MIPS_HAS_MIPS64 -#define TLSZ "%016llx" -#else -#define TLSZ "%08x" -#endif - typedef union fpr_t fpr_t; union fpr_t { float64 fd; /* ieee double precision */ diff --git a/target-mips/helper.c b/target-mips/helper.c index 51b8ca102..9ba401785 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -132,7 +132,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } #if 0 if (logfile) { - fprintf(logfile, TLSZ " %d %d => " TLSZ " %d (%d)\n", + fprintf(logfile, TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n", address, rw, access_type, *physical, *prot, ret); } #endif @@ -174,7 +174,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if 0 cpu_dump_state(env, logfile, fprintf, 0); #endif - fprintf(logfile, "%s pc " TLSZ " ad " TLSZ " rw %d is_user %d smmu %d\n", + fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d is_user %d smmu %d\n", __func__, env->PC, address, rw, is_user, is_softmmu); } @@ -192,7 +192,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ret = get_physical_address(env, &physical, &prot, address, rw, access_type); if (logfile) { - fprintf(logfile, "%s address=" TLSZ " ret %d physical " TLSZ " prot %d\n", + fprintf(logfile, "%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_lx " prot %d\n", __func__, address, ret, physical, prot); } if (ret == TLBRET_MATCH) { @@ -258,7 +258,7 @@ void do_interrupt (CPUState *env) int cause = -1; if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { - fprintf(logfile, "%s enter: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n", + fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n", __func__, env->PC, env->CP0_EPC, cause, env->exception_index); } if (env->exception_index == EXCP_EXT_INTERRUPT && @@ -410,8 +410,8 @@ void do_interrupt (CPUState *env) exit(1); } if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { - fprintf(logfile, "%s: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n" - " S %08x C %08x A " TLSZ " D " TLSZ "\n", + fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n" + " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", __func__, env->PC, env->CP0_EPC, cause, env->exception_index, env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, env->CP0_DEPC); diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 1b8d9351a..2e2df38a2 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -492,13 +492,13 @@ void do_tlbr (void) void dump_ldst (const unsigned char *func) { if (loglevel) - fprintf(logfile, "%s => " TLSZ " " TLSZ "\n", __func__, T0, T1); + fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1); } void dump_sc (void) { if (loglevel) { - fprintf(logfile, "%s " TLSZ " at " TLSZ " (" TLSZ ")\n", __func__, + fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__, T1, T0, env->CP0_LLAddr); } } @@ -506,7 +506,7 @@ void dump_sc (void) void debug_eret (void) { if (loglevel) { - fprintf(logfile, "ERET: pc " TLSZ " EPC " TLSZ " ErrorEPC " TLSZ " (%d)\n", + fprintf(logfile, "ERET: pc " TARGET_FMT_lx " EPC " TARGET_FMT_lx " ErrorEPC " TARGET_FMT_lx " (%d)\n", env->PC, env->CP0_EPC, env->CP0_ErrorEPC, env->hflags & MIPS_HFLAG_ERL ? 1 : 0); } diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index 6af78ce05..e0030e085 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -28,7 +28,7 @@ void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: " TLSZ " - %08x " TLSZ " => " TLSZ "\n", + fprintf(logfile, "%s: " TARGET_FMT_lx " - %08x " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__, sav, tmp, T1, T0); } #endif @@ -57,7 +57,7 @@ void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: " TLSZ " - %08x " TLSZ " => " TLSZ "\n", + fprintf(logfile, "%s: " TARGET_FMT_lx " - %08x " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__, sav, tmp, T1, T0); } #endif @@ -86,7 +86,7 @@ uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => %08x\n", + fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => %08x\n", __func__, T0, sav, T1, tmp); } #endif @@ -116,7 +116,7 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => %08x\n", + fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => %08x\n", __func__, T0, sav, T1, tmp); } #endif @@ -166,7 +166,7 @@ void glue(do_ldl, MEMSUFFIX) (uint64_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n", + fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__, sav, tmp, T1, T0); } #endif @@ -207,7 +207,7 @@ void glue(do_ldr, MEMSUFFIX) (uint64_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n", + fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__, sav, tmp, T1, T0); } #endif @@ -248,7 +248,7 @@ uint64_t glue(do_sdl, MEMSUFFIX) (uint64_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n", + fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__, T0, sav, T1, tmp); } #endif @@ -290,7 +290,7 @@ uint64_t glue(do_sdr, MEMSUFFIX) (uint64_t tmp) } #if defined (DEBUG_OP) if (logfile) { - fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n", + fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", __func__, T0, sav, T1, tmp); } #endif diff --git a/target-mips/translate.c b/target-mips/translate.c index ce56bb083..c049ad6e8 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -503,7 +503,7 @@ enum { #define MIPS_DEBUG(fmt, args...) \ do { \ if (loglevel & CPU_LOG_TB_IN_ASM) { \ - fprintf(logfile, TLSZ ": %08x " fmt "\n", \ + fprintf(logfile, TARGET_FMT_lx ": %08x " fmt "\n", \ ctx->pc, ctx->opcode , ##args); \ } \ } while (0) @@ -4124,21 +4124,21 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, switch (op) { case OPC_BC1F: gen_op_bc1f(); - MIPS_DEBUG("bc1f " TLSZ, btarget); + MIPS_DEBUG("bc1f " TARGET_FMT_lx, btarget); goto not_likely; case OPC_BC1FL: gen_op_bc1f(); - MIPS_DEBUG("bc1fl " TLSZ, btarget); + MIPS_DEBUG("bc1fl " TARGET_FMT_lx, btarget); goto likely; case OPC_BC1T: gen_op_bc1t(); - MIPS_DEBUG("bc1t " TLSZ, btarget); + MIPS_DEBUG("bc1t " TARGET_FMT_lx, btarget); not_likely: ctx->hflags |= MIPS_HFLAG_BC; break; case OPC_BC1TL: gen_op_bc1t(); - MIPS_DEBUG("bc1tl " TLSZ, btarget); + MIPS_DEBUG("bc1tl " TARGET_FMT_lx, btarget); likely: ctx->hflags |= MIPS_HFLAG_BL; break; @@ -4149,7 +4149,7 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, } gen_op_set_bcond(); - MIPS_DEBUG("enter ds: cond %02x target " TLSZ, + MIPS_DEBUG("enter ds: cond %02x target " TARGET_FMT_lx, ctx->hflags, btarget); ctx->btarget = btarget; @@ -4583,7 +4583,7 @@ static void decode_opc (DisasContext *ctx) if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { /* Handle blikely not taken case */ - MIPS_DEBUG("blikely condition (" TLSZ ")", ctx->pc + 4); + MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4); gen_blikely(ctx); } op = MASK_OP_MAJOR(ctx->opcode); @@ -5191,7 +5191,7 @@ void fpu_dump_state(CPUState *env, FILE *f, void dump_fpu (CPUState *env) { if (loglevel) { - fprintf(logfile, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n", + fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); fpu_dump_state(env, logfile, fprintf, 0); } @@ -5212,23 +5212,23 @@ void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, int i; if (!SIGN_EXT_P(env->PC)) - cpu_fprintf(f, "BROKEN: pc=0x" TLSZ "\n", env->PC); + cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC); if (!SIGN_EXT_P(env->HI)) - cpu_fprintf(f, "BROKEN: HI=0x" TLSZ "\n", env->HI); + cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI); if (!SIGN_EXT_P(env->LO)) - cpu_fprintf(f, "BROKEN: LO=0x" TLSZ "\n", env->LO); + cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO); if (!SIGN_EXT_P(env->btarget)) - cpu_fprintf(f, "BROKEN: btarget=0x" TLSZ "\n", env->btarget); + cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget); for (i = 0; i < 32; i++) { if (!SIGN_EXT_P(env->gpr[i])) - cpu_fprintf(f, "BROKEN: %s=0x" TLSZ "\n", regnames[i], env->gpr[i]); + cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i]); } if (!SIGN_EXT_P(env->CP0_EPC)) - cpu_fprintf(f, "BROKEN: EPC=0x" TLSZ "\n", env->CP0_EPC); + cpu_fprintf(f, "BROKEN: EPC=0x" TARGET_FMT_lx "\n", env->CP0_EPC); if (!SIGN_EXT_P(env->CP0_LLAddr)) - cpu_fprintf(f, "BROKEN: LLAddr=0x" TLSZ "\n", env->CP0_LLAddr); + cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->CP0_LLAddr); } #endif @@ -5239,12 +5239,12 @@ void cpu_dump_state (CPUState *env, FILE *f, uint32_t c0_status; int i; - cpu_fprintf(f, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n", + cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { if ((i & 3) == 0) cpu_fprintf(f, "GPR%02d:", i); - cpu_fprintf(f, " %s " TLSZ, regnames[i], env->gpr[i]); + cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i]); if ((i & 3) == 3) cpu_fprintf(f, "\n"); } @@ -5257,9 +5257,9 @@ void cpu_dump_state (CPUState *env, FILE *f, if (env->hflags & MIPS_HFLAG_EXL) c0_status |= (1 << CP0St_EXL); - cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TLSZ "\n", + cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", c0_status, env->CP0_Cause, env->CP0_EPC); - cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TLSZ "\n", + cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n", env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); #ifdef MIPS_USES_FPU if (c0_status & (1 << CP0St_CU1)) -- cgit v1.2.3 From 9c1de6125e49460aa1e508a837159a2087762d18 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 21 Feb 2007 17:25:30 +0000 Subject: Increase the number of multiplexed monitor devices. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2445 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 7a4058f7b..5bbbf40a1 100644 --- a/vl.c +++ b/vl.c @@ -1232,7 +1232,7 @@ static CharDriverState *qemu_chr_open_null(void) /* MUX driver for serial I/O splitting */ static int term_timestamps; static int64_t term_timestamps_start; -#define MAX_MUX 2 +#define MAX_MUX 4 typedef struct { IOCanRWHandler *chr_can_read[MAX_MUX]; IOReadHandler *chr_read[MAX_MUX]; -- cgit v1.2.3 From 331ad6f444f288093a174cfdbe23985f954cfad3 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 21 Feb 2007 22:32:19 +0000 Subject: Allow arbitrary MIPS BIOS sizes between 0 and 4 MB, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2446 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 97431b1e6..03db2f8a6 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -533,7 +533,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, } else { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); ret = load_image(buf, phys_ram_base + bios_offset); - if (ret != BIOS_SIZE) { + if (ret < 0 || ret > BIOS_SIZE) { fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", buf); exit(1); -- cgit v1.2.3 From 7bcc17dc020d49f0baf25010f3d2be41ebfe238f Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 21 Feb 2007 22:43:42 +0000 Subject: Fix initialisation of serial/parallel ports, spotted by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2447 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 03db2f8a6..eeb351387 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -569,9 +569,12 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, /* Super I/O */ kbd_init(); rtc_state = rtc_init(0x70, 8); - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); - serial_init(&pic_set_irq_new, isa_pic, 0x2f8, 4, serial_hds[0]); - parallel_init(0x378, 7, parallel_hds[0]); + if (serial_hds[0]) + serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); + if (serial_hds[1]) + serial_init(&pic_set_irq_new, isa_pic, 0x2f8, 4, serial_hds[1]); + if (parallel_hds[0]) + parallel_init(0x378, 7, parallel_hds[0]); /* XXX: The floppy controller does not work correctly, something is probably wrong. floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */ -- cgit v1.2.3 From cfc3475a8df6d03dfbffa813d7d919eda409c85b Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 22 Feb 2007 01:48:01 +0000 Subject: Allow gdbstub to connect over any serial device. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2448 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 32 +++++++++++++++++--------------- gdbstub.h | 5 ++--- monitor.c | 12 ++++++------ vl.c | 13 +++++++------ 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index aeddc3474..324af4d19 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1216,10 +1216,26 @@ static void gdb_chr_event(void *opaque, int event) } } -int gdbserver_start(CharDriverState *chr) +int gdbserver_start(const char *port) { GDBState *s; + char gdbstub_port_name[128]; + int port_num; + char *p; + CharDriverState *chr; + + if (!port || !*port) + return -1; + port_num = strtol(port, &p, 10); + if (*p == 0) { + /* A numeric value is interpreted as a port number. */ + snprintf(gdbstub_port_name, sizeof(gdbstub_port_name), + "tcp::%d,nowait,nodelay,server", port_num); + port = gdbstub_port_name; + } + + chr = qemu_chr_open(port); if (!chr) return -1; @@ -1234,18 +1250,4 @@ int gdbserver_start(CharDriverState *chr) qemu_add_vm_stop_handler(gdb_vm_stopped, s); return 0; } - -int gdbserver_start_port(int port) -{ - CharDriverState *chr; - char gdbstub_port_name[128]; - - snprintf(gdbstub_port_name, sizeof(gdbstub_port_name), - "tcp::%d,nowait,nodelay,server", port); - chr = qemu_chr_open(gdbstub_port_name); - if (!chr) - return -EIO; - return gdbserver_start(chr); -} - #endif diff --git a/gdbstub.h b/gdbstub.h index 41ffc6d08..e1c9efb80 100644 --- a/gdbstub.h +++ b/gdbstub.h @@ -1,7 +1,7 @@ #ifndef GDBSTUB_H #define GDBSTUB_H -#define DEFAULT_GDBSTUB_PORT 1234 +#define DEFAULT_GDBSTUB_PORT "1234" typedef void (*gdb_syscall_complete_cb)(CPUState *env, target_ulong ret, target_ulong err); @@ -13,8 +13,7 @@ int gdb_handlesig (CPUState *, int); void gdb_exit(CPUState *, int); int gdbserver_start(int); #else -int gdbserver_start(CharDriverState *chr); -int gdbserver_start_port(int port); +int gdbserver_start(const char *port); #endif #endif diff --git a/monitor.c b/monitor.c index cd0663e93..43ebe01f3 100644 --- a/monitor.c +++ b/monitor.c @@ -423,14 +423,14 @@ static void do_cont(void) } #ifdef CONFIG_GDBSTUB -static void do_gdbserver(int has_port, int port) +static void do_gdbserver(const char *port) { - if (!has_port) + if (!port) port = DEFAULT_GDBSTUB_PORT; - if (gdbserver_start_port(port) < 0) { - qemu_printf("Could not open gdbserver socket on port %d\n", port); + if (gdbserver_start(port) < 0) { + qemu_printf("Could not open gdbserver socket on port '%s'\n", port); } else { - qemu_printf("Waiting gdb connection on port %d\n", port); + qemu_printf("Waiting gdb connection on port '%s'\n", port); } } #endif @@ -1216,7 +1216,7 @@ static term_cmd_t term_cmds[] = { { "c|cont", "", do_cont, "", "resume emulation", }, #ifdef CONFIG_GDBSTUB - { "gdbserver", "i?", do_gdbserver, + { "gdbserver", "s?", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, #endif { "x", "/l", do_memory_dump, diff --git a/vl.c b/vl.c index 5bbbf40a1..efa0d6172 100644 --- a/vl.c +++ b/vl.c @@ -6422,8 +6422,8 @@ void help(void) "-parallel dev redirect the parallel port to char device 'dev'\n" "-pidfile file Write PID to 'file'\n" "-S freeze CPU at startup (use 'c' to start execution)\n" - "-s wait gdb connection to port %d\n" - "-p port change gdb connection port\n" + "-s wait gdb connection to port\n" + "-p port set gdb connection port [default=%s]\n" "-d item1,... output log to %s (use -d ? for a list of log items)\n" "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n" " translation (t=none or lba) (usually qemu can guess them)\n" @@ -6829,7 +6829,8 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB - int use_gdbstub, gdbstub_port; + int use_gdbstub; + const char *gdbstub_port; #endif int i, cdrom_index; int snapshot, linux_boot; @@ -7143,7 +7144,7 @@ int main(int argc, char **argv) use_gdbstub = 1; break; case QEMU_OPTION_p: - gdbstub_port = atoi(optarg); + gdbstub_port = optarg; break; #endif case QEMU_OPTION_L: @@ -7571,8 +7572,8 @@ int main(int argc, char **argv) if (use_gdbstub) { /* XXX: use standard host:port notation and modify options accordingly. */ - if (gdbserver_start_port(gdbstub_port) < 0) { - fprintf(stderr, "qemu: could not open gdbstub device on port '%d'\n", + if (gdbserver_start(gdbstub_port) < 0) { + fprintf(stderr, "qemu: could not open gdbstub device on port '%s'\n", gdbstub_port); exit(1); } -- cgit v1.2.3 From 96217e315d4ac38daf4a7b8cafa4a9cd13ad4126 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 22 Feb 2007 20:21:33 +0000 Subject: Basic USB device resume (root hub only), by Lonnie Mendez. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2449 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index f0b1e2e44..509c54f7c 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -26,6 +26,8 @@ //#define DEBUG //#define DEBUG_PACKET +#define UHCI_CMD_FGR (1 << 4) +#define UHCI_CMD_EGSM (1 << 3) #define UHCI_CMD_GRESET (1 << 2) #define UHCI_CMD_HCRESET (1 << 1) #define UHCI_CMD_RS (1 << 0) @@ -327,6 +329,21 @@ static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr) return val; } +/* signal resume if controller suspended */ +static void uhci_resume (void *opaque) +{ + UHCIState *s = (UHCIState *)opaque; + + if (!s) + return; + + if (s->cmd & UHCI_CMD_EGSM) { + s->cmd |= UHCI_CMD_FGR; + s->status |= UHCI_STS_RD; + uhci_update_irq(s); + } +} + static void uhci_attach(USBPort *port1, USBDevice *dev) { UHCIState *s = port1->opaque; @@ -344,6 +361,9 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) port->ctrl |= UHCI_PORT_LSDA; else port->ctrl &= ~UHCI_PORT_LSDA; + + uhci_resume(s); + port->port.dev = dev; /* send the attach message */ usb_send_msg(dev, USB_MSG_ATTACH); @@ -358,6 +378,9 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) port->ctrl &= ~UHCI_PORT_EN; port->ctrl |= UHCI_PORT_ENC; } + + uhci_resume(s); + dev = port->port.dev; if (dev) { /* send the detach message */ -- cgit v1.2.3 From 7ed40acfae7dc85da367b5b7fba4d56d53426530 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 22 Feb 2007 20:43:09 +0000 Subject: Revert host_info changes, and don't fail if sysctl is unknown when we are on the same host/target, by Pierre d'Herbemont. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2450 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/syscall.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c index f2543aa44..f69a5aacd 100644 --- a/darwin-user/syscall.c +++ b/darwin-user/syscall.c @@ -367,7 +367,14 @@ static inline uint32_t target_mach_msg_trap( case 200: /* host_info */ { mig_reply_error_t *err = (mig_reply_error_t *)hdr; - struct host_basic_info *data = (void *)(err+1); + struct { + uint32_t unknow1; + uint32_t max_cpus; + uint32_t avail_cpus; + uint32_t memory_size; + uint32_t cpu_type; + uint32_t cpu_subtype; + } *data = (void *)(err+1); DPRINTF("maxcpu = 0x%x\n", data->max_cpus); DPRINTF("numcpu = 0x%x\n", data->avail_cpus); @@ -1342,9 +1349,12 @@ long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, vo if(name) /* Sometimes sysctl is called with no arg1, ignore */ ret = get_errno(sysctl(name, namelen, oldp, oldlenp, newp, newlen)); +#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__) if (!is_error(ret) && bswap_syctl(name, namelen, oldp, *oldlenp) != 0) { return -ENOTDIR; } +#endif + if(name) { //bswap_syctl(name, namelen, newp, newlen); tswap32s((uint32_t*)oldlenp); -- cgit v1.2.3 From 430415f2b16b4b1e4d4168d989407f8167c668c9 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 23 Feb 2007 00:34:02 +0000 Subject: Add Erwan Velu as contributor for the tftp boot patches. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2451 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 35709c3cd..d13b849e6 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ - - TFTP booting from host directory (Anthony Liguori) + - TFTP booting from host directory (Anthony Liguori, Erwan Velu) - Tap device emulation for Solaris (Sittichai Palanisong) - Monitor multiplexing to several I/O channels (Jason Wessel) -- cgit v1.2.3 From 308c359325f24e776eaf1c42aeb9b8abfeef68e6 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 27 Feb 2007 00:52:01 +0000 Subject: Fix "make install prefix=/somewhere". git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2452 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/configure b/configure index 963111934..ceb9badb4 100755 --- a/configure +++ b/configure @@ -559,28 +559,28 @@ if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then 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" + if test -z "$prefix" ; then + prefix="/c/Program Files/Qemu" + fi + mansuffix="" + datasuffix="" + docsuffix="" + binsuffix="" 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" + if test -z "$prefix" ; then + prefix="/usr/local" + fi + mansuffix="/share/man" + datasuffix="/share/qemu" + docsuffix="/share/doc/qemu" + binsuffix="/bin" fi echo "Install prefix $prefix" -echo "BIOS directory $datadir" -echo "binary directory $bindir" +echo "BIOS directory $prefix$datasuffix" +echo "binary directory $prefix$binsuffix" if test "$mingw32" = "no" ; then -echo "Manual directory $mandir" +echo "Manual directory $prefix$mansuffix" echo "ELF interp prefix $interp_prefix" fi echo "Source path $source_path" @@ -640,11 +640,11 @@ 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 "bindir=\${prefix}$binsuffix" >> $config_mak +echo "mandir=\${prefix}$mansuffix" >> $config_mak +echo "datadir=\${prefix}$datasuffix" >> $config_mak +echo "docdir=\${prefix}$docsuffic" >> $config_mak +echo "#define CONFIG_QEMU_SHAREDIR \"$prefix$datasuffix\"" >> $config_h echo "MAKE=$make" >> $config_mak echo "INSTALL=$install" >> $config_mak echo "CC=$cc" >> $config_mak -- cgit v1.2.3 From 1124426a0940f50fe86c40ea89f0342a1f835312 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 27 Feb 2007 01:03:41 +0000 Subject: Honor $cross_prefix when searching for suitable gcc. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2453 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index ceb9badb4..093501625 100755 --- a/configure +++ b/configure @@ -348,9 +348,9 @@ EOF 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 + if check_cc "$cross_prefix$compat_cc" ; then echo "Found \"$compat_cc\"" - cc="$compat_cc" + cc="$cross_prefix$compat_cc" found_compat_cc="yes" break fi -- cgit v1.2.3 From 00a709c7b9f46fee5f2179e3e05adf5f8124f561 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 27 Feb 2007 19:27:51 +0000 Subject: Fix mips FPU emulation, 32 bit data types are allowed to use odd registers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2454 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 +- target-mips/translate.c | 45 ++++++++++++++++----------------------------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 34c17c1ab..9b8dd60d9 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1732,7 +1732,7 @@ void op_mtc1 (void) FLOAT_OP(cvtd, s) { - FDT2 = float32_to_float64(WT0, &env->fp_status); + FDT2 = float32_to_float64(FST0, &env->fp_status); DEBUG_FPU_STATE(); RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index c049ad6e8..7576fa3b3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4216,9 +4216,9 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) * Status register equals zero, since the register numbers specify an * even-odd pair of adjacent coprocessor general registers. When the FR bit * in the Status register equals one, both even and odd register numbers - * are valid. + * are valid. This limitation exists only for 64 bit wide (d,l) registers. * - * Multiple float registers can be checked by calling + * Multiple 64 bit wide registers can be checked by calling * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); */ #define CHECK_FR(ctx, freg) do { \ @@ -4324,42 +4324,42 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) /* 10 - ceil.l */ /* 11 - floor.l */ case FOP(12, 17): - CHECK_FR(ctx, fs | fd); + CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "round.w.d"; break; case FOP(13, 17): - CHECK_FR(ctx, fs | fd); + CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "trunc.w.d"; break; case FOP(14, 17): - CHECK_FR(ctx, fs | fd); + CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceilw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "ceil.w.d"; break; case FOP(15, 17): - CHECK_FR(ctx, fs | fd); + CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "floor.w.d"; break; - case FOP(33, 16): /* cvt.d.s */ - CHECK_FR(ctx, fs | fd); + case FOP(33, 16): + CHECK_FR(ctx, fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.d.s"; break; - case FOP(33, 20): /* cvt.d.w */ - CHECK_FR(ctx, fs | fd); + case FOP(33, 20): + CHECK_FR(ctx, fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_w(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4388,7 +4388,6 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) opn = condnames[func-48]; break; case FOP(0, 16): - CHECK_FR(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_add_s(); @@ -4397,7 +4396,6 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) binary = 1; break; case FOP(1, 16): - CHECK_FR(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_sub_s(); @@ -4406,7 +4404,6 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) binary = 1; break; case FOP(2, 16): - CHECK_FR(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_mul_s(); @@ -4415,7 +4412,6 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) binary = 1; break; case FOP(3, 16): - CHECK_FR(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_div_s(); @@ -4424,70 +4420,62 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) binary = 1; break; case FOP(4, 16): - CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_sqrt_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "sqrt.s"; break; case FOP(5, 16): - CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_abs_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "abs.s"; break; case FOP(6, 16): - CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_mov_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "mov.s"; break; case FOP(7, 16): - CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_chs_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "neg.s"; break; case FOP(12, 16): - CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_roundw_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "round.w.s"; break; case FOP(13, 16): - CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_truncw_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "trunc.w.s"; break; - case FOP(32, 17): /* cvt.s.d */ - CHECK_FR(ctx, fs | fd); + case FOP(32, 17): + CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.d"; break; - case FOP(32, 20): /* cvt.s.w */ - CHECK_FR(ctx, fs | fd); + case FOP(32, 20): GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvts_w(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.w"; break; - case FOP(36, 16): /* cvt.w.s */ - CHECK_FR(ctx, fs | fd); + case FOP(36, 16): GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtw_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.w.s"; break; - case FOP(36, 17): /* cvt.w.d */ - CHECK_FR(ctx, fs | fd); + case FOP(36, 17): + CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtw_d(); GEN_STORE_FTN_FREG(fd, WT2); @@ -4509,7 +4497,6 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) case FOP(61, 16): case FOP(62, 16): case FOP(63, 16): - CHECK_FR(ctx, fs | ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_cmp_s(func-48); -- cgit v1.2.3 From 3a11702b21a9bc2e23fd77e0dcad7f94bdfa48fe Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 27 Feb 2007 21:02:54 +0000 Subject: Include LDFLAGS when linking system emulator. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2455 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 2c8a873a2..b5cde5dc7 100644 --- a/Makefile.target +++ b/Makefile.target @@ -464,7 +464,7 @@ 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) + $(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) cocoa.o: cocoa.m $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< -- cgit v1.2.3 From 210fa55690d448bbdd89081c1c53840e795d4a8d Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 27 Feb 2007 21:04:49 +0000 Subject: Compiler check for byteswap.h instead of hardcoded path. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2456 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 093501625..11dd2e7a5 100755 --- a/configure +++ b/configure @@ -706,8 +706,14 @@ 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 +else + cat > $TMPC << EOF +#include +int main(void) { return bswap_32(0); } +EOF + if $cc -o $TMPE $TMPC 2> /dev/null ; then + echo "#define HAVE_BYTESWAP_H 1" >> $config_h + fi fi if test "$darwin" = "yes" ; then echo "CONFIG_DARWIN=yes" >> $config_mak -- cgit v1.2.3 From d7739d757094f998c97d4cbc759d726cfd224cca Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 28 Feb 2007 16:25:17 +0000 Subject: iDocument ARM RealView board (Andrzej Zaborowski). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2457 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index fe69e80b7..1acd7451a 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -79,6 +79,7 @@ For system emulation, the following hardware targets are supported: @item Malta board (32-bit MIPS processor) @item ARM Integrator/CP (ARM926E or 1026E processor) @item ARM Versatile baseboard (ARM926E) +@item ARM RealView Emulation baseboard (ARM926EJ-S) @end itemize For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported. @@ -1743,6 +1744,29 @@ PCI OHCI USB controller. LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices. @end itemize +The ARM RealView Emulation baseboard is emulated with the following devices: + +@itemize @minus +@item +ARM926E CPU +@item +ARM AMBA Generic/Distributed Interrupt Controller +@item +Four PL011 UARTs +@item +SMC 91c111 Ethernet adapter +@item +PL110 LCD controller +@item +PL050 KMI with PS/2 keyboard and mouse +@item +PCI host bridge +@item +PCI OHCI USB controller +@item +LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices +@end itemize + A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. -- cgit v1.2.3 From 130751ee24a5ec8d417fa063d3d956c54fea2033 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 28 Feb 2007 20:04:26 +0000 Subject: 24C01 / 24C02 EEPROM emulation for Malta, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2458 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 4 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index eeb351387..e73279835 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -49,6 +49,7 @@ typedef struct { uint32_t leds; uint32_t brk; uint32_t gpout; + uint32_t i2cin; uint32_t i2coe; uint32_t i2cout; uint32_t i2csel; @@ -83,6 +84,124 @@ static void malta_fpga_update_display(void *opaque) qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); } +/* + * EEPROM 24C01 / 24C02 emulation. + * + * Emulation for serial EEPROMs: + * 24C01 - 1024 bit (128 x 8) + * 24C02 - 2048 bit (256 x 8) + * + * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02. + */ + +//~ #define DEBUG + +#if defined(DEBUG) +# define logout(fmt, args...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ##args) +#else +# define logout(fmt, args...) ((void)0) +#endif + +struct _eeprom24c0x_t { + uint8_t tick; + uint8_t address; + uint8_t command; + uint8_t ack; + uint8_t scl; + uint8_t sda; + uint8_t data; + //~ uint16_t size; + uint8_t contents[256]; +}; + +typedef struct _eeprom24c0x_t eeprom24c0x_t; + +static eeprom24c0x_t eeprom = { + contents: { + /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00, + /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01, + /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00, + /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40, + /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00, + /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0, + /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4, + }, +}; + +static uint8_t eeprom24c0x_read() +{ + logout("%u: scl = %u, sda = %u, data = 0x%02x\n", + eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data); + return eeprom.sda; +} + +static void eeprom24c0x_write(int scl, int sda) +{ + if (eeprom.scl && scl && (eeprom.sda != sda)) { + logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n", + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start"); + if (!sda) { + eeprom.tick = 1; + eeprom.command = 0; + } + } else if (eeprom.tick == 0 && !eeprom.ack) { + /* Waiting for start. */ + logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n", + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); + } else if (!eeprom.scl && scl) { + logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n", + eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); + if (eeprom.ack) { + logout("\ti2c ack bit = 0\n"); + sda = 0; + eeprom.ack = 0; + } else if (eeprom.sda == sda) { + uint8_t bit = (sda != 0); + logout("\ti2c bit = %d\n", bit); + if (eeprom.tick < 9) { + eeprom.command <<= 1; + eeprom.command += bit; + eeprom.tick++; + if (eeprom.tick == 9) { + logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write"); + eeprom.ack = 1; + } + } else if (eeprom.tick < 17) { + if (eeprom.command & 1) { + sda = ((eeprom.data & 0x80) != 0); + } + eeprom.address <<= 1; + eeprom.address += bit; + eeprom.tick++; + eeprom.data <<= 1; + if (eeprom.tick == 17) { + eeprom.data = eeprom.contents[eeprom.address]; + logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data); + eeprom.ack = 1; + eeprom.tick = 0; + } + } else if (eeprom.tick >= 17) { + sda = 0; + } + } else { + logout("\tsda changed with raising scl\n"); + } + } else { + logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda); + } + eeprom.scl = scl; + eeprom.sda = sda; +} + static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) { MaltaFPGAState *s = opaque; @@ -140,7 +259,7 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) /* I2CINP Register */ case 0x00b00: - val = 0x00000003; + val = ((s->i2cin & ~1) | eeprom24c0x_read()); break; /* I2COE Register */ @@ -155,7 +274,7 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) /* I2CSEL Register */ case 0x00b18: - val = s->i2cout; + val = s->i2csel; break; default: @@ -234,12 +353,13 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, /* I2COUT Register */ case 0x00b10: - s->i2cout = val & 0x03; + eeprom24c0x_write(val & 0x02, val & 0x01); + s->i2cout = val; break; /* I2CSEL Register */ case 0x00b18: - s->i2cout = val & 0x01; + s->i2csel = val & 0x01; break; default: @@ -270,6 +390,7 @@ void malta_fpga_reset(void *opaque) s->leds = 0x00; s->brk = 0x0a; s->gpout = 0x00; + s->i2cin = 0x3; s->i2coe = 0x0; s->i2cout = 0x3; s->i2csel = 0x1; -- cgit v1.2.3 From c5be9f0898b92d0d6bfb458fd50fc170f4300361 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 28 Feb 2007 20:20:53 +0000 Subject: Fix CPU chaining in linux-user emulation, by Gwenole Beauchesne. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2459 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 2 ++ exec.c | 12 ++++++++++++ linux-user/syscall.c | 3 +-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 8a4730d32..0ad50e8bf 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -754,6 +754,8 @@ void page_unprotect_range(target_ulong data, target_ulong data_size); #endif /* SINGLE_CPU_DEFINES */ +CPUState *cpu_copy(CPUState *env); + void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags); diff --git a/exec.c b/exec.c index 2e09b4bc3..37d58a43e 100644 --- a/exec.c +++ b/exec.c @@ -1222,6 +1222,18 @@ void cpu_abort(CPUState *env, const char *fmt, ...) abort(); } +CPUState *cpu_copy(CPUState *env) +{ + CPUState *new_env = cpu_init(); + /* preserve chaining and index */ + CPUState *next_cpu = new_env->next_cpu; + int cpu_index = new_env->cpu_index; + memcpy(new_env, env, sizeof(CPUState)); + new_env->next_cpu = next_cpu; + new_env->cpu_index = cpu_index; + return new_env; +} + #if !defined(CONFIG_USER_ONLY) /* NOTE: if flush_global is true, also flush global entries (not diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f3f97b0d5..76b36524a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1720,8 +1720,7 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) ts->next = first_task_state; first_task_state = ts; /* we create a new CPU instance. */ - new_env = cpu_init(); - memcpy(new_env, env, sizeof(CPUState)); + new_env = cpu_copy(env); #if defined(TARGET_I386) if (!newsp) newsp = env->regs[R_ESP]; -- cgit v1.2.3 From 9542611a66227ceca062eec86d49e17aa79cbf90 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 28 Feb 2007 21:36:41 +0000 Subject: DS1225Y nvram device, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2460 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/ds1225y.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/mips_r4k.c | 1 + vl.h | 4 ++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 hw/ds1225y.c diff --git a/Makefile.target b/Makefile.target index b5cde5dc7..8eaa8dd78 100644 --- a/Makefile.target +++ b/Makefile.target @@ -383,7 +383,7 @@ CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o -VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o +VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) DEFINES += -DHAS_AUDIO endif diff --git a/hw/ds1225y.c b/hw/ds1225y.c new file mode 100644 index 000000000..48d6636b3 --- /dev/null +++ b/hw/ds1225y.c @@ -0,0 +1,121 @@ +/* + * QEMU NVRAM emulation for DS1225Y chip + * + * Copyright (c) 2007 Herv Poussineau + * + * 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" + +typedef enum +{ + none = 0, + readmode, + writemode, +} nvram_open_mode; + +struct ds1225y_t +{ + target_ulong mem_base; + uint32_t capacity; + const char *filename; + QEMUFile *file; + nvram_open_mode open_mode; +}; + +static int ds1225y_set_to_mode(ds1225y_t *NVRAM, nvram_open_mode mode, const char *filemode) +{ + if (NVRAM->open_mode != mode) + { + if (NVRAM->file) + qemu_fclose(NVRAM->file); + NVRAM->file = qemu_fopen(NVRAM->filename, filemode); + NVRAM->open_mode = mode; + } + return (NVRAM->file != NULL); +} + +static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) +{ + ds1225y_t *NVRAM = opaque; + int64_t pos; + + pos = addr - NVRAM->mem_base; + if (addr >= NVRAM->capacity) + addr -= NVRAM->capacity; + + if (!ds1225y_set_to_mode(NVRAM, readmode, "rb")) + return 0; + qemu_fseek(NVRAM->file, pos, SEEK_SET); + return (uint32_t)qemu_get_byte(NVRAM->file); +} + +static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + ds1225y_t *NVRAM = opaque; + int64_t pos; + + pos = addr - NVRAM->mem_base; + if (ds1225y_set_to_mode(NVRAM, writemode, "wb")) + { + qemu_fseek(NVRAM->file, pos, SEEK_SET); + qemu_put_byte(NVRAM->file, (int)value); + } +} + +static CPUReadMemoryFunc *nvram_read[] = { + &nvram_readb, + NULL, + NULL, +}; + +static CPUWriteMemoryFunc *nvram_write[] = { + &nvram_writeb, + NULL, + NULL, +}; + +static CPUWriteMemoryFunc *nvram_none[] = { + NULL, + NULL, + NULL, +}; + +/* Initialisation routine */ +ds1225y_t *ds1225y_init(target_ulong mem_base, const char *filename) +{ + ds1225y_t *s; + int mem_index1, mem_index2; + + s = qemu_mallocz(sizeof(ds1225y_t)); + if (!s) + return NULL; + s->mem_base = mem_base; + s->capacity = 0x2000; /* Fixed for ds1225y chip: 8K */ + s->filename = filename; + + /* Read/write memory */ + mem_index1 = cpu_register_io_memory(0, nvram_read, nvram_write, s); + cpu_register_physical_memory(mem_base, s->capacity, mem_index1); + /* Read-only memory */ + mem_index2 = cpu_register_io_memory(0, nvram_read, nvram_none, s); + cpu_register_physical_memory(mem_base + s->capacity, s->capacity, mem_index2); + return s; +} diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 63ad36720..b6054fd51 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -215,6 +215,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, bs_table[2 * i], bs_table[2 * i + 1]); kbd_init(); + ds1225y_init(0x9000, "nvram"); } QEMUMachine mips_machine = { diff --git a/vl.h b/vl.h index c6d305c1a..ae501e24b 100644 --- a/vl.h +++ b/vl.h @@ -941,6 +941,10 @@ int pmac_ide_init (BlockDriverState **hd_table, int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); +/* ds1225y.c */ +typedef struct ds1225y_t ds1225y_t; +ds1225y_t *ds1225y_init(target_ulong mem_base, const char *filename); + /* es1370.c */ int es1370_init (PCIBus *bus, AudioState *s); -- cgit v1.2.3 From cafffd4024b10ac1eae54b74a5a0f372d86eede7 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 28 Feb 2007 21:59:44 +0000 Subject: Make removing IOHandlers safe from within an IOHandler, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2461 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/vl.c b/vl.c index efa0d6172..cfe6a2a5d 100644 --- a/vl.c +++ b/vl.c @@ -4462,6 +4462,7 @@ typedef struct IOHandlerRecord { IOCanRWHandler *fd_read_poll; IOHandler *fd_read; IOHandler *fd_write; + int deleted; void *opaque; /* temporary data */ struct pollfd *ufd; @@ -4487,8 +4488,7 @@ int qemu_set_fd_handler2(int fd, if (ioh == NULL) break; if (ioh->fd == fd) { - *pioh = ioh->next; - qemu_free(ioh); + ioh->deleted = 1; break; } pioh = &ioh->next; @@ -4509,6 +4509,7 @@ int qemu_set_fd_handler2(int fd, ioh->fd_read = fd_read; ioh->fd_write = fd_write; ioh->opaque = opaque; + ioh->deleted = 0; } return 0; } @@ -6157,7 +6158,7 @@ void qemu_system_powerdown_request(void) void main_loop_wait(int timeout) { - IOHandlerRecord *ioh, *ioh_next; + IOHandlerRecord *ioh; fd_set rfds, wfds, xfds; int ret, nfds; struct timeval tv; @@ -6192,6 +6193,8 @@ void main_loop_wait(int timeout) FD_ZERO(&wfds); FD_ZERO(&xfds); for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { + if (ioh->deleted) + continue; if (ioh->fd_read && (!ioh->fd_read_poll || ioh->fd_read_poll(ioh->opaque) != 0)) { @@ -6219,9 +6222,11 @@ void main_loop_wait(int timeout) #endif ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); if (ret > 0) { - /* XXX: better handling of removal */ - for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { - ioh_next = ioh->next; + IOHandlerRecord **pioh; + + for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { + if (ioh->deleted) + continue; if (FD_ISSET(ioh->fd, &rfds)) { ioh->fd_read(ioh->opaque); } @@ -6229,6 +6234,17 @@ void main_loop_wait(int timeout) ioh->fd_write(ioh->opaque); } } + + /* remove deleted IO handlers */ + pioh = &first_io_handler; + while (*pioh) { + ioh = *pioh; + if (ioh->deleted) { + *pioh = ioh->next; + qemu_free(ioh); + } else + pioh = &ioh->next; + } } #if defined(CONFIG_SLIRP) if (slirp_inited) { -- cgit v1.2.3 From 54d43f70e3b003b5f24ef30ea361e034c2813d9f Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 28 Feb 2007 22:01:13 +0000 Subject: Mention ds1225y support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2462 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index d13b849e6..b0123e1d3 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,7 @@ - TFTP booting from host directory (Anthony Liguori, Erwan Velu) - Tap device emulation for Solaris (Sittichai Palanisong) - Monitor multiplexing to several I/O channels (Jason Wessel) + - ds1225y nvram support (Herve Poussineau) version 0.9.0: -- cgit v1.2.3 From 36d239587370c6ccfc53d7f6acc624ce5d61fe84 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 28 Feb 2007 22:37:42 +0000 Subject: MIPS FPU dynamic activation, part 1, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2463 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 3 +- gdbstub.c | 50 +++++++++--------- linux-user/main.c | 6 +-- target-mips/cpu.h | 4 +- target-mips/exec.h | 2 - target-mips/mips-defs.h | 13 ++--- target-mips/op.c | 9 ---- target-mips/op_helper.c | 2 - target-mips/op_mem.c | 2 - target-mips/translate.c | 134 ++++++++++++++++++++++-------------------------- 10 files changed, 95 insertions(+), 130 deletions(-) diff --git a/exec-all.h b/exec-all.h index 82ef3acdc..73b85436c 100644 --- a/exec-all.h +++ b/exec-all.h @@ -581,13 +581,12 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) } pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { - cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr); + cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); } return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; } #endif - #ifdef USE_KQEMU #define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG)) diff --git a/gdbstub.c b/gdbstub.c index 324af4d19..d1f104489 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -568,19 +568,20 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) *(uint32_t *)ptr = tswapl(env->PC); ptr += 4; -#ifdef MIPS_USES_FPU - for (i = 0; i < 32; i++) + if (env->CP0_Config1 & (1 << CP0C1_FP)) { - *(uint32_t *)ptr = tswapl(FPR_W (env, i)); - ptr += 4; - } + for (i = 0; i < 32; i++) + { + *(uint32_t *)ptr = tswapl(FPR_W (env, i)); + ptr += 4; + } - *(uint32_t *)ptr = tswapl(env->fcr31); - ptr += 4; + *(uint32_t *)ptr = tswapl(env->fcr31); + ptr += 4; - *(uint32_t *)ptr = tswapl(env->fcr0); - ptr += 4; -#endif + *(uint32_t *)ptr = tswapl(env->fcr0); + ptr += 4; + } /* 32 FP registers, fsr, fir, fp. Not yet implemented. */ /* what's 'fp' mean here? */ @@ -629,27 +630,28 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->PC = tswapl(*(uint32_t *)ptr); ptr += 4; -#ifdef MIPS_USES_FPU - for (i = 0; i < 32; i++) + if (env->CP0_Config1 & (1 << CP0C1_FP)) { - FPR_W (env, i) = tswapl(*(uint32_t *)ptr); - ptr += 4; - } + for (i = 0; i < 32; i++) + { + FPR_W (env, i) = tswapl(*(uint32_t *)ptr); + ptr += 4; + } - env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF; - ptr += 4; + env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF; + ptr += 4; - env->fcr0 = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->fcr0 = tswapl(*(uint32_t *)ptr); + ptr += 4; - /* set rounding mode */ - RESTORE_ROUNDING_MODE; + /* set rounding mode */ + RESTORE_ROUNDING_MODE; #ifndef CONFIG_SOFTFLOAT - /* no floating point exception for native float */ - SET_FP_ENABLE(env->fcr31, 0); -#endif + /* no floating point exception for native float */ + SET_FP_ENABLE(env->fcr31, 0); #endif + } } #elif defined (TARGET_SH4) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) diff --git a/linux-user/main.c b/linux-user/main.c index 7199372b3..3eb573db6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1838,9 +1838,9 @@ int main(int argc, char **argv) env->gpr[i] = regs->regs[i]; } env->PC = regs->cp0_epc; -#ifdef MIPS_USES_FPU - env->CP0_Status |= (1 << CP0St_CU1); -#endif + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + env->CP0_Status |= (1 << CP0St_CU1); + } } #elif defined(TARGET_SH4) { diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 6068813dc..21651beb0 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -63,7 +63,6 @@ struct CPUMIPSState { #endif target_ulong HI, LO; uint32_t DCR; /* ? */ -#if defined(MIPS_USES_FPU) /* Floating point registers */ fpr_t fpr[16]; #define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2]) @@ -97,8 +96,7 @@ struct CPUMIPSState { #define FP_DIV0 8 #define FP_INVALID 16 #define FP_UNIMPLEMENTED 32 - -#endif + #if defined(MIPS_USES_R4K_TLB) tlb_t tlb[MIPS_TLB_MAX]; uint32_t tlb_in_use; diff --git a/target-mips/exec.h b/target-mips/exec.h index 1e9fa8e69..3815a00c4 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -115,12 +115,10 @@ void do_tlbwi (void); void do_tlbwr (void); void do_tlbp (void); void do_tlbr (void); -#ifdef MIPS_USES_FPU void dump_fpu(CPUState *env); void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), int flags); -#endif void dump_sc (void); void do_lwl_raw (uint32_t); void do_lwr_raw (uint32_t); diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 83480c6ab..a78bef55e 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -45,19 +45,14 @@ 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, no coprocessor2 attached, no MDMX support attached, no performance counters, watch registers present, - no code compression, EJTAG present, FPU enable bit depending on - MIPS_USES_FPU */ -#define MIPS_CONFIG1_1 \ + no code compression, EJTAG present, no FPU */ +#define MIPS_CONFIG1 \ ((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) | \ (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \ (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \ - (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP)) -#ifdef MIPS_USES_FPU -#define MIPS_CONFIG1 (MIPS_CONFIG1_1 | (1 << CP0C1_FP)) -#else -#define MIPS_CONFIG1 (MIPS_CONFIG1_1 | (0 << CP0C1_FP)) -#endif + (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \ + (0 << CP0C1_FP)) /* Have config3, no tertiary/secondary caches implemented */ #define MIPS_CONFIG2 \ ((1 << CP0C2_M)) diff --git a/target-mips/op.c b/target-mips/op.c index 9b8dd60d9..21795ad37 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -144,8 +144,6 @@ CALL_FROM_TB2(func, arg0, arg1); #include "op_template.c" #undef TN -#ifdef MIPS_USES_FPU - #define SFREG 0 #define DFREG 0 #include "fop_template.c" @@ -279,8 +277,6 @@ CALL_FROM_TB2(func, arg0, arg1); #include "fop_template.c" #undef FTN -#endif - void op_dup_T0 (void) { T2 = T0; @@ -924,7 +920,6 @@ void op_movz (void) RETURN(); } -#ifdef MIPS_USES_FPU void op_movf (void) { if (!(env->fcr31 & PARAM1)) @@ -938,7 +933,6 @@ void op_movt (void) env->gpr[PARAM2] = env->gpr[PARAM3]; RETURN(); } -#endif /* Tests */ #define OP_COND(name, cond) \ @@ -1645,8 +1639,6 @@ void op_dmtc0_errorepc (void) RETURN(); } -#ifdef MIPS_USES_FPU - #if 0 # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) #else @@ -2001,7 +1993,6 @@ void op_bc1t (void) DEBUG_FPU_STATE(); RETURN(); } -#endif /* MIPS_USES_FPU */ #if defined(MIPS_USES_R4K_TLB) void op_tlbwi (void) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 2e2df38a2..a262ea668 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -331,7 +331,6 @@ void do_mtc0_status_irqraise_debug(void) fprintf(logfile, "Raise pending IRQs\n"); } -#ifdef MIPS_USES_FPU #include "softfloat.h" void fpu_handle_exception(void) @@ -370,7 +369,6 @@ void fpu_handle_exception(void) SET_FP_CAUSE(env->fcr31, 0); #endif } -#endif /* MIPS_USES_FPU */ /* TLB management */ #if defined(MIPS_USES_R4K_TLB) diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index a3289793b..823cfe809 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -192,7 +192,6 @@ void glue(op_scd, MEMSUFFIX) (void) } #endif /* MIPS_HAS_MIPS64 */ -#ifdef MIPS_USES_FPU void glue(op_lwc1, MEMSUFFIX) (void) { WT0 = glue(ldl, MEMSUFFIX)(T0); @@ -213,4 +212,3 @@ void glue(op_sdc1, MEMSUFFIX) (void) glue(stq, MEMSUFFIX)(T0, DT0); RETURN(); } -#endif diff --git a/target-mips/translate.c b/target-mips/translate.c index 7576fa3b3..5a77e906f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -391,8 +391,6 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); -#ifdef MIPS_USES_FPU - static const char *fregnames[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", @@ -476,8 +474,6 @@ static inline void gen_cmp_ ## fmt(int n) \ FOP_CONDS(d) FOP_CONDS(s) -#endif /* MIPS_USES_FPU */ - typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; @@ -640,12 +636,10 @@ OP_LD_TABLE(bu); OP_ST_TABLE(b); OP_LD_TABLE(l); OP_ST_TABLE(c); -#ifdef MIPS_USES_FPU OP_LD_TABLE(wc1); OP_ST_TABLE(wc1); OP_LD_TABLE(dc1); OP_ST_TABLE(dc1); -#endif /* Load and store */ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, @@ -794,8 +788,6 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]); } -#ifdef MIPS_USES_FPU - /* Load and store */ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, int base, int16_t offset) @@ -843,8 +835,6 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); } -#endif /* MIPS_USES_FPU */ - /* Arithmetic with immediate operand */ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) @@ -4111,8 +4101,6 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd); } -#ifdef MIPS_USES_FPU - /* CP1 Branches (before delay slot) */ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, int32_t offset) @@ -4531,8 +4519,6 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) gen_op_movt(ccbit, rd, rs); } -#endif /* MIPS_USES_FPU */ - /* ISA extensions (ASEs) */ /* MIPS16 extension to MIPS32 */ /* SmartMIPS extension to MIPS32 */ @@ -4555,7 +4541,7 @@ static void gen_blikely(DisasContext *ctx) gen_set_label(l1); } -static void decode_opc (DisasContext *ctx) +static void decode_opc (CPUState *env, DisasContext *ctx) { int32_t offset; int rs, rt, rd, sa; @@ -4631,13 +4617,15 @@ static void decode_opc (DisasContext *ctx) /* Treat as a noop. */ break; -#ifdef MIPS_USES_FPU case OPC_MOVCI: - gen_op_cp1_enabled(); - gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, - (ctx->opcode >> 16) & 1); + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + gen_op_cp1_enabled(); + gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, + (ctx->opcode >> 16) & 1); + } else { + generate_exception(ctx, EXCP_RI); + } break; -#endif #ifdef MIPS_HAS_MIPS64 /* MIPS64 specific opcodes */ @@ -4868,47 +4856,47 @@ static void decode_opc (DisasContext *ctx) case OPC_LDC1: case OPC_SWC1: case OPC_SDC1: -#if defined(MIPS_USES_FPU) - save_cpu_state(ctx, 1); - gen_op_cp1_enabled(); - gen_flt_ldst(ctx, op, rt, rs, imm); -#else - generate_exception_err(ctx, EXCP_CpU, 1); -#endif + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + save_cpu_state(ctx, 1); + gen_op_cp1_enabled(); + gen_flt_ldst(ctx, op, rt, rs, imm); + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } break; case OPC_CP1: -#if defined(MIPS_USES_FPU) - save_cpu_state(ctx, 1); - gen_op_cp1_enabled(); - op1 = MASK_CP1(ctx->opcode); - switch (op1) { - case OPC_MFC1: - case OPC_CFC1: - case OPC_MTC1: - case OPC_CTC1: + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + save_cpu_state(ctx, 1); + gen_op_cp1_enabled(); + op1 = MASK_CP1(ctx->opcode); + switch (op1) { + case OPC_MFC1: + case OPC_CFC1: + case OPC_MTC1: + case OPC_CTC1: #ifdef MIPS_HAS_MIPS64 - case OPC_DMFC1: - case OPC_DMTC1: + case OPC_DMFC1: + case OPC_DMTC1: #endif - gen_cp1(ctx, op1, rt, rd); - break; - case OPC_BC1: - gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2); - return; - case OPC_S_FMT: - case OPC_D_FMT: - case OPC_W_FMT: - case OPC_L_FMT: - gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa); - break; - default: - generate_exception_err(ctx, EXCP_RI, 1); - break; + gen_cp1(ctx, op1, rt, rd); + break; + case OPC_BC1: + gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2); + return; + case OPC_S_FMT: + case OPC_D_FMT: + case OPC_W_FMT: + case OPC_L_FMT: + gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa); + break; + default: + generate_exception_err(ctx, EXCP_RI, 1); + break; + } + } else { + generate_exception_err(ctx, EXCP_CpU, 1); } -#else - generate_exception_err(ctx, EXCP_CpU, 1); -#endif break; /* COP2. */ @@ -4921,18 +4909,20 @@ static void decode_opc (DisasContext *ctx) generate_exception_err(ctx, EXCP_CpU, 2); break; -#ifdef MIPS_USES_FPU case OPC_CP3: - gen_op_cp1_enabled(); - op1 = MASK_CP3(ctx->opcode); - switch (op1) { - /* Not implemented */ - default: - generate_exception_err(ctx, EXCP_RI, 1); - break; + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + gen_op_cp1_enabled(); + op1 = MASK_CP3(ctx->opcode); + switch (op1) { + /* Not implemented */ + default: + generate_exception_err(ctx, EXCP_RI, 1); + break; + } + } else { + generate_exception(ctx, EXCP_RI); } break; -#endif #ifdef MIPS_HAS_MIPS64 /* MIPS64 opcodes */ @@ -5079,7 +5069,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_instr_start[lj] = 1; } ctx.opcode = ldl_code(ctx.pc); - decode_opc(&ctx); + decode_opc(env, &ctx); ctx.pc += 4; if (env->singlestep_enabled) @@ -5148,8 +5138,6 @@ int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } -#ifdef MIPS_USES_FPU - void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -5184,8 +5172,6 @@ void dump_fpu (CPUState *env) } } -#endif /* MIPS_USES_FPU */ - #if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) /* Debug help: The architecture requires 32bit code to maintain proper sign-extened values on 64bit machines. */ @@ -5248,10 +5234,8 @@ void cpu_dump_state (CPUState *env, FILE *f, c0_status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n", env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); -#ifdef MIPS_USES_FPU if (c0_status & (1 << CP0St_CU1)) fpu_dump_state(env, f, cpu_fprintf, flags); -#endif #if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags); #endif @@ -5295,6 +5279,10 @@ void cpu_reset (CPUMIPSState *env) env->CP0_EBase = 0x80000000; env->CP0_Config0 = MIPS_CONFIG0; env->CP0_Config1 = MIPS_CONFIG1; +#ifdef MIPS_USES_FPU + /* basic FPU register support */ + env->CP0_Config1 |= (1 << CP0C1_FP); +#endif env->CP0_Config2 = MIPS_CONFIG2; env->CP0_Config3 = MIPS_CONFIG3; env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); @@ -5309,9 +5297,7 @@ void cpu_reset (CPUMIPSState *env) env->hflags |= MIPS_HFLAG_UM; env->user_mode_only = 1; #endif -#ifdef MIPS_USES_FPU - env->fcr0 = MIPS_FCR0; -#endif + env->fcr0 = MIPS_FCR0; /* XXX some guesswork here, values are CPU specific */ env->SYNCI_Step = 16; env->CCRes = 2; -- cgit v1.2.3 From c05ac0cdac0c4592876424f9c467484bb1eb2bb6 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Mar 2007 20:36:23 +0000 Subject: Fix wrong interrupt number for the second serial interface. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2464 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index e73279835..8d77b7800 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -693,7 +693,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, if (serial_hds[0]) serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); if (serial_hds[1]) - serial_init(&pic_set_irq_new, isa_pic, 0x2f8, 4, serial_hds[1]); + serial_init(&pic_set_irq_new, isa_pic, 0x2f8, 3, serial_hds[1]); if (parallel_hds[0]) parallel_init(0x378, 7, parallel_hds[0]); /* XXX: The floppy controller does not work correctly, something is -- cgit v1.2.3 From 6f5b89a07c90ebaa7caf744927f977d78d366326 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Mar 2007 20:48:00 +0000 Subject: MIPS Userland TLS register emulation, by Daniel Jacobowitz. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2465 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 1 + linux-user/mips/syscall_nr.h | 2 +- linux-user/syscall.c | 21 ++++++++++++++++++++- target-mips/cpu.h | 4 ++++ target-mips/op.c | 7 +++++++ target-mips/translate.c | 6 ++++++ 6 files changed, 39 insertions(+), 2 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 3eb573db6..367138448 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1297,6 +1297,7 @@ static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_add_key , 5) MIPS_SYS(sys_request_key , 4) MIPS_SYS(sys_keyctl , 5) + MIPS_SYS(sys_set_thread_area, 1) }; #undef MIPS_SYS diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h index 3593e65d0..e869bcdd6 100644 --- a/linux-user/mips/syscall_nr.h +++ b/linux-user/mips/syscall_nr.h @@ -285,4 +285,4 @@ #define TARGET_NR_add_key (TARGET_NR_Linux + 280) #define TARGET_NR_request_key (TARGET_NR_Linux + 281) #define TARGET_NR_keyctl (TARGET_NR_Linux + 282) - +#define TARGET_NR_set_thread_area (TARGET_NR_Linux + 283) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 76b36524a..acd098d87 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -165,6 +165,9 @@ _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) #endif +#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) +_syscall1(int,set_tid_address,int *,tidptr) +#endif extern int personality(int); extern int flock(int, int); @@ -3968,6 +3971,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_set_thread_area case TARGET_NR_set_thread_area: +#ifdef TARGET_MIPS + ((CPUMIPSState *) cpu_env)->tls_value = arg1; + ret = 0; + break; +#else + goto unimplemented_nowarn; +#endif +#endif +#ifdef TARGET_NR_get_thread_area case TARGET_NR_get_thread_area: goto unimplemented_nowarn; #endif @@ -3975,10 +3987,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getdomainname: goto unimplemented_nowarn; #endif + +#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) + case TARGET_NR_set_tid_address: + ret = get_errno(set_tid_address((int *) arg1)); + break; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) || defined(TARGET_NR_getdomainname) +#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) unimplemented_nowarn: #endif ret = -ENOSYS; diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 21651beb0..69335a018 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -268,6 +268,10 @@ struct CPUMIPSState { int SYNCI_Step; /* Address step size for SYNCI */ int CCRes; /* Cycle count resolution/divisor */ +#if defined(CONFIG_USER_ONLY) + target_ulong tls_value; +#endif + CPU_COMMON int ram_size; diff --git a/target-mips/op.c b/target-mips/op.c index 21795ad37..7c7ce3ba3 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -2021,6 +2021,13 @@ void op_tlbr (void) #endif /* Specials */ +#if defined (CONFIG_USER_ONLY) +void op_tls_value (void) +{ + T0 = env->tls_value; +} +#endif + void op_pmon (void) { CALL_FROM_TB1(do_pmon, PARAM1); diff --git a/target-mips/translate.c b/target-mips/translate.c index 5a77e906f..a9f7b75c4 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4728,6 +4728,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case 3: gen_op_rdhwr_ccres(); break; +#if defined (CONFIG_USER_ONLY) + case 29: + gen_op_tls_value (); + GEN_STORE_TN_REG(rt, T0); + break; +#endif default: /* Invalid */ MIPS_INVAL("rdhwr"); generate_exception(ctx, EXCP_RI); -- cgit v1.2.3 From 4ad5b06d6a655edd7b352581428ff3e37e7b8db1 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 3 Mar 2007 21:47:02 +0000 Subject: Fix configure typo, by Juergen Lock. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2466 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 11dd2e7a5..6415ebfd0 100755 --- a/configure +++ b/configure @@ -643,7 +643,7 @@ echo "prefix=$prefix" >> $config_mak echo "bindir=\${prefix}$binsuffix" >> $config_mak echo "mandir=\${prefix}$mansuffix" >> $config_mak echo "datadir=\${prefix}$datasuffix" >> $config_mak -echo "docdir=\${prefix}$docsuffic" >> $config_mak +echo "docdir=\${prefix}$docsuffix" >> $config_mak echo "#define CONFIG_QEMU_SHAREDIR \"$prefix$datasuffix\"" >> $config_h echo "MAKE=$make" >> $config_mak echo "INSTALL=$install" >> $config_mak -- cgit v1.2.3 From 7a2d6d9650ed16b2cdb0b4876fe9efce7ef8ea6d Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 4 Mar 2007 00:52:16 +0000 Subject: 64bit->win32 cross build fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2467 c046a42c-6fe2-441c-8c8c-71466251a162 --- a.out.h | 104 +++++++++++++++++++++++++++++++-------------------------------- dyngen.c | 8 ++--- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/a.out.h b/a.out.h index 1f978c1c0..2d35ebfd8 100644 --- a/a.out.h +++ b/a.out.h @@ -25,9 +25,9 @@ extern "C" { 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 */ + host_ulong f_timdat; /* time & date stamp */ + host_ulong f_symptr; /* file pointer to symtab */ + host_ulong f_nsyms; /* number of symtab entries */ short f_opthdr; /* sizeof(optional hdr) */ short f_flags; /* flags */ }; @@ -72,12 +72,12 @@ 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= + host_ulong tsize; /* text size in bytes, padded to FW bdry*/ + host_ulong dsize; /* initialized data " " */ + host_ulong bsize; /* uninitialized data " " */ + host_ulong entry; /* entry pt. */ + host_ulong text_start; /* base of text used for this file */ + host_ulong data_start; /* base of data used for this file= */ } AOUTHDR; @@ -103,16 +103,16 @@ AOUTHDR; struct external_scnhdr { char s_name[8]; /* section name */ - unsigned long s_paddr; /* physical address, offset + host_ulong 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 */ + host_ulong s_vaddr; /* virtual address */ + host_ulong s_size; /* section size */ + host_ulong s_scnptr; /* file ptr to raw data for section */ + host_ulong s_relptr; /* file ptr to relocation */ + host_ulong 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 */ + host_ulong s_flags; /* flags */ }; #define SCNHDR struct external_scnhdr @@ -136,8 +136,8 @@ struct external_scnhdr { */ 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 */ + host_ulong l_symndx; /* function name symbol index, iff l_lnno 0 */ + host_ulong l_paddr; /* (physical) address of line number */ } l_addr; unsigned short l_lnno; /* line number */ }; @@ -156,11 +156,11 @@ struct __attribute__((packed)) external_syment union { char e_name[E_SYMNMLEN]; struct { - unsigned long e_zeroes; - unsigned long e_offset; + host_ulong e_zeroes; + host_ulong e_offset; } e; } e; - unsigned long e_value; + host_ulong e_value; unsigned short e_scnum; unsigned short e_type; char e_sclass[1]; @@ -174,18 +174,18 @@ struct __attribute__((packed)) external_syment union external_auxent { struct { - unsigned long x_tagndx; /* str, un, or enum tag indx */ + host_ulong 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 */ + host_ulong 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 */ + host_ulong x_lnnoptr;/* ptr to fcn line # */ + host_ulong x_endndx; /* entry ndx past block end */ } x_fcn; struct { /* if ISARY, up to 4 dimen. */ char x_dimen[E_DIMNUM][2]; @@ -197,22 +197,22 @@ union external_auxent { union { char x_fname[E_FILNMLEN]; struct { - unsigned long x_zeroes; - unsigned long x_offset; + host_ulong x_zeroes; + host_ulong x_offset; } x_n; } x_file; struct { - unsigned long x_scnlen; /* section length */ + host_ulong x_scnlen; /* section length */ unsigned short x_nreloc; /* # relocation entries */ unsigned short x_nlinno; /* # line numbers */ - unsigned long x_checksum; /* section COMDAT checksum */ + host_ulong 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 */ + host_ulong 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)) */ @@ -344,7 +344,7 @@ struct external_PE_filehdr 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 */ + host_ulong 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 */ @@ -352,9 +352,9 @@ struct external_PE_filehdr 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 */ + host_ulong f_timdat; /* time & date stamp */ + host_ulong f_symptr; /* file pointer to symtab */ + host_ulong f_nsyms; /* number of symtab entries */ unsigned short f_opthdr; /* sizeof(optional hdr) */ unsigned short f_flags; /* flags */ }; @@ -370,17 +370,17 @@ 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 */ + host_ulong tsize; /* text size in bytes, padded to FW bdry*/ + host_ulong dsize; /* initialized data " " */ + host_ulong bsize; /* uninitialized data " " */ + host_ulong entry; /* entry pt. */ + host_ulong text_start; /* base of text used for this file */ + host_ulong 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; + host_ulong ImageBase; + host_ulong SectionAlignment; + host_ulong FileAlignment; unsigned short MajorOperatingSystemVersion; unsigned short MinorOperatingSystemVersion; unsigned short MajorImageVersion; @@ -388,17 +388,17 @@ typedef struct unsigned short MajorSubsystemVersion; unsigned short MinorSubsystemVersion; char Reserved1[4]; - unsigned long SizeOfImage; - unsigned long SizeOfHeaders; - unsigned long CheckSum; + host_ulong SizeOfImage; + host_ulong SizeOfHeaders; + host_ulong 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; + host_ulong SizeOfStackReserve; + host_ulong SizeOfStackCommit; + host_ulong SizeOfHeapReserve; + host_ulong SizeOfHeapCommit; + host_ulong LoaderFlags; + host_ulong NumberOfRvaAndSizes; /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */ diff --git a/dyngen.c b/dyngen.c index c6a878c6d..953b36c11 100644 --- a/dyngen.c +++ b/dyngen.c @@ -148,11 +148,11 @@ typedef uint64_t host_ulong; #ifdef CONFIG_FORMAT_COFF -#include "a.out.h" - typedef int32_t host_long; typedef uint32_t host_ulong; +#include "a.out.h" + #define FILENAMELEN 256 typedef struct coff_sym { @@ -1740,7 +1740,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { EXE_SYM *sym; const char *sym_name, *p; - unsigned long val; + host_ulong val; int n; for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { @@ -1772,7 +1772,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #ifdef CONFIG_FORMAT_MACH offset -= section_hdr[sym->n_sect-1].addr; #endif - val = *(unsigned long *)(ptr + offset); + val = *(host_ulong *)(ptr + offset); #ifdef ELF_USES_RELOCA { int reloc_shndx, nb_relocs1, j; -- cgit v1.2.3 From 94fc95cdb2e91826bd6a4c98cea4f4d9fa0fffb1 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 5 Mar 2007 19:44:02 +0000 Subject: New -cpu options: choose CPU model for emulated target. Only relevant on PowerPC targets, for now. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2468 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/integratorcp.c | 4 ++-- hw/mips_malta.c | 2 +- hw/mips_r4k.c | 2 +- hw/pc.c | 6 ++++-- hw/ppc_chrp.c | 59 ++++++++++++++++++++++++++----------------------------- hw/ppc_prep.c | 21 ++++++++++---------- hw/realview.c | 2 +- hw/shix.c | 2 +- hw/sun4m.c | 2 +- hw/sun4u.c | 2 +- hw/versatilepb.c | 4 ++-- vl.c | 18 ++++++++++++++++- vl.h | 6 +++++- 13 files changed, 75 insertions(+), 55 deletions(-) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 4e5f4ac9f..fd1675b40 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -516,7 +516,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, static void integratorcp926_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, @@ -526,7 +526,7 @@ static void integratorcp926_init(int ram_size, int vga_ram_size, static void integratorcp1026_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 8d77b7800..d137658fb 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -615,7 +615,7 @@ static void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { char buf[1024]; unsigned long bios_offset; diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index b6054fd51..91d8021dd 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -130,7 +130,7 @@ static void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { char buf[1024]; unsigned long bios_offset; diff --git a/hw/pc.c b/hw/pc.c index 0560ff1f9..ba9c2d947 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -758,7 +758,8 @@ static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, + const char *cpu_model) { pc_init1(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, @@ -771,7 +772,8 @@ static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, + const char *cpu_model) { pc_init1(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 1e0fd2e9d..937be150c 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -292,13 +292,14 @@ void pmac_format_nvram_partition(uint8_t *buf, int len) } /* PowerPC CHRP hardware initialisation */ -static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - int is_heathrow) +static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model, + int is_heathrow) { CPUState *env; char buf[1024]; @@ -320,22 +321,16 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, env = cpu_init(); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - /* Register CPU as a 74x/75x */ + /* Default CPU is a generic 74x/75x */ + if (cpu_model == NULL) + cpu_model = "750"; /* XXX: CPU model (or PVR) should be provided on command line */ // ppc_find_by_name("750gx", &def); // Linux boot OK // ppc_find_by_name("750fx", &def); // Linux boot OK /* Linux does not boot on 750cxe (and probably other 750cx based) * because it assumes it has 8 IBAT & DBAT pairs as it only have 4. */ - // ppc_find_by_name("750cxe", &def); - // ppc_find_by_name("750p", &def); - // ppc_find_by_name("740p", &def); - ppc_find_by_name("750", &def); - // ppc_find_by_name("740", &def); - // ppc_find_by_name("G3", &def); - // ppc_find_by_name("604r", &def); - // ppc_find_by_name("604e", &def); - // ppc_find_by_name("604", &def); + ppc_find_by_name(cpu_model, &def); if (def == NULL) { cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } @@ -525,30 +520,32 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); } -static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) +static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) { ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, - initrd_filename, 0); + initrd_filename, cpu_model, 0); } -static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) +static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) { ppc_chrp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, - initrd_filename, 1); + initrd_filename, cpu_model, 1); } QEMUMachine core99_machine = { diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index c4b7ff5ba..27d3d4848 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -518,10 +518,12 @@ CPUReadMemoryFunc *PPC_prep_io_read[] = { #define NVRAM_SIZE 0x2000 /* PowerPC PREP hardware initialisation */ -static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) +static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) { CPUState *env; char buf[1024]; @@ -543,12 +545,11 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, env = cpu_init(); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - - /* Register CPU as a 604 */ - /* XXX: CPU model (or PVR) should be provided on command line */ - // ppc_find_by_name("604r", &def); - // ppc_find_by_name("604e", &def); - ppc_find_by_name("604", &def); + + /* Default CPU is a 604 */ + if (cpu_model == NULL) + cpu_model = "604"; + ppc_find_by_name(cpu_model, &def); if (def == NULL) { cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } diff --git a/hw/realview.c b/hw/realview.c index ea42705ad..325b3d1ab 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -15,7 +15,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { CPUState *env; void *pic; diff --git a/hw/shix.c b/hw/shix.c index 9577c092c..5857d0e06 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -70,7 +70,7 @@ void vga_screen_dump(const char *filename) void shix_init(int ram_size, int vga_ram_size, int boot_device, DisplayState * ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { int ret; CPUState *env; diff --git a/hw/sun4m.c b/hw/sun4m.c index 9b6aae53c..c5f6ddda8 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -211,7 +211,7 @@ static void main_cpu_reset(void *opaque) static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { CPUState *env, *envs[MAX_CPUS]; char buf[1024]; diff --git a/hw/sun4u.c b/hw/sun4u.c index 61069a652..2357dc974 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -257,7 +257,7 @@ static fdctrl_t *floppy_controller; static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { CPUState *env; char buf[1024]; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index bc42472ad..1bcc160b3 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -257,7 +257,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, static void vpb_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { versatile_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, @@ -268,7 +268,7 @@ static void vpb_init(int ram_size, int vga_ram_size, int boot_device, static void vab_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) + const char *initrd_filename, const char *cpu_model) { versatile_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, diff --git a/vl.c b/vl.c index cfe6a2a5d..99d4766b9 100644 --- a/vl.c +++ b/vl.c @@ -6355,6 +6355,7 @@ void help(void) "\n" "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" + "-cpu cpu select CPU (-C ? for list)\n" "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" @@ -6487,6 +6488,7 @@ enum { QEMU_OPTION_h, QEMU_OPTION_M, + QEMU_OPTION_cpu, QEMU_OPTION_fda, QEMU_OPTION_fdb, QEMU_OPTION_hda, @@ -6562,6 +6564,7 @@ const QEMUOption qemu_options[] = { { "help", 0, QEMU_OPTION_h }, { "M", HAS_ARG, QEMU_OPTION_M }, + { "cpu", HAS_ARG, QEMU_OPTION_cpu }, { "fda", HAS_ARG, QEMU_OPTION_fda }, { "fdb", HAS_ARG, QEMU_OPTION_fdb }, { "hda", HAS_ARG, QEMU_OPTION_hda }, @@ -6867,6 +6870,7 @@ int main(int argc, char **argv) int parallel_device_index; const char *loadvm = NULL; QEMUMachine *machine; + const char *cpu_model; char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; int fds[2]; @@ -6904,6 +6908,7 @@ int main(int argc, char **argv) register_machines(); machine = first_machine; + cpu_model = NULL; initrd_filename = NULL; for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; @@ -6995,6 +7000,17 @@ int main(int argc, char **argv) exit(1); } break; + case QEMU_OPTION_cpu: + /* hw initialization will check this */ + if (optarg[0] == '?') { +#if defined(TARGET_PPC) + ppc_cpu_list(stdout, &fprintf); +#endif + exit(1); + } else { + cpu_model = optarg; + } + break; case QEMU_OPTION_initrd: initrd_filename = optarg; break; @@ -7569,7 +7585,7 @@ int main(int argc, char **argv) machine->init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, initrd_filename); + kernel_filename, kernel_cmdline, initrd_filename, cpu_model); /* init USB devices */ if (usb_enabled) { diff --git a/vl.h b/vl.h index ae501e24b..0f5ab9700 100644 --- a/vl.h +++ b/vl.h @@ -695,7 +695,7 @@ typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename); + const char *initrd_filename, const char *cpu_model); typedef struct QEMUMachine { const char *name; @@ -709,6 +709,10 @@ int qemu_register_machine(QEMUMachine *m); typedef void SetIRQFunc(void *opaque, int irq_num, int level); typedef void IRQRequestFunc(void *opaque, int level); +#if defined(TARGET_PPC) +void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +#endif + /* ISA bus */ extern target_phys_addr_t isa_mem_base; -- cgit v1.2.3 From 6d2980f515c005091de0b9f4fe526e749f62c380 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 6 Mar 2007 18:56:13 +0000 Subject: Fix unportable bitfields use which broke pcnet for big endian hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2469 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 608 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 339 insertions(+), 269 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index 3bdddeb38..71b8cf2a9 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -77,14 +77,6 @@ struct PCNetState_st { void *dma_opaque; }; -/* XXX: using bitfields for target memory structures is almost surely - not portable, so it should be suppressed ASAP */ -#ifdef __GNUC__ -#define PACKED_FIELD(A) A __attribute__ ((packed)) -#else -#error FixMe -#endif - struct qemu_ether_header { uint8_t ether_dhost[6]; uint8_t ether_shost[6]; @@ -183,223 +175,291 @@ struct pcnet_initblk32 { }; struct pcnet_TMD { - struct { - unsigned tbadr:32; - } tmd0; - struct { - unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1); - unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1); - unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); - } tmd1; - struct { - unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12); - unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1); - unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1); - } tmd2; - struct { - unsigned res:32; - } tmd3; + uint32_t tbadr; + int16_t length; + int16_t status; + uint32_t misc; + uint32_t res; }; +#define TMDL_BCNT_MASK 0x0fff +#define TMDL_BCNT_SH 0 +#define TMDL_ONES_MASK 0xf000 +#define TMDL_ONES_SH 12 + +#define TMDS_BPE_MASK 0x0080 +#define TMDS_BPE_SH 7 +#define TMDS_ENP_MASK 0x0100 +#define TMDS_ENP_SH 8 +#define TMDS_STP_MASK 0x0200 +#define TMDS_STP_SH 9 +#define TMDS_DEF_MASK 0x0400 +#define TMDS_DEF_SH 10 +#define TMDS_ONE_MASK 0x0800 +#define TMDS_ONE_SH 11 +#define TMDS_LTINT_MASK 0x1000 +#define TMDS_LTINT_SH 12 +#define TMDS_NOFCS_MASK 0x2000 +#define TMDS_NOFCS_SH 13 +#define TMDS_ERR_MASK 0x4000 +#define TMDS_ERR_SH 14 +#define TMDS_OWN_MASK 0x8000 +#define TMDS_OWN_SH 15 + +#define TMDM_TRC_MASK 0x0000000f +#define TMDM_TRC_SH 0 +#define TMDM_TDR_MASK 0x03ff0000 +#define TMDM_TDR_SH 16 +#define TMDM_RTRY_MASK 0x04000000 +#define TMDM_RTRY_SH 26 +#define TMDM_LCAR_MASK 0x08000000 +#define TMDM_LCAR_SH 27 +#define TMDM_LCOL_MASK 0x10000000 +#define TMDM_LCOL_SH 28 +#define TMDM_EXDEF_MASK 0x20000000 +#define TMDM_EXDEF_SH 29 +#define TMDM_UFLO_MASK 0x40000000 +#define TMDM_UFLO_SH 30 +#define TMDM_BUFF_MASK 0x80000000 +#define TMDM_BUFF_SH 31 + struct pcnet_RMD { - struct { - unsigned rbadr:32; - } rmd0; - struct { - unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4); - unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1); - unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1); - unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); - } rmd1; - struct { - unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4); - unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8); - } rmd2; - struct { - unsigned res:32; - } rmd3; + uint32_t rbadr; + int16_t buf_length; + int16_t status; + uint32_t msg_length; + uint32_t res; }; - -#define PRINT_TMD(T) printf( \ - "TMD0 : TBADR=0x%08x\n" \ +#define RMDL_BCNT_MASK 0x0fff +#define RMDL_BCNT_SH 0 +#define RMDL_ONES_MASK 0xf000 +#define RMDL_ONES_SH 12 + +#define RMDS_BAM_MASK 0x0010 +#define RMDS_BAM_SH 4 +#define RMDS_LFAM_MASK 0x0020 +#define RMDS_LFAM_SH 5 +#define RMDS_PAM_MASK 0x0040 +#define RMDS_PAM_SH 6 +#define RMDS_BPE_MASK 0x0080 +#define RMDS_BPE_SH 7 +#define RMDS_ENP_MASK 0x0100 +#define RMDS_ENP_SH 8 +#define RMDS_STP_MASK 0x0200 +#define RMDS_STP_SH 9 +#define RMDS_BUFF_MASK 0x0400 +#define RMDS_BUFF_SH 10 +#define RMDS_CRC_MASK 0x0800 +#define RMDS_CRC_SH 11 +#define RMDS_OFLO_MASK 0x1000 +#define RMDS_OFLO_SH 12 +#define RMDS_FRAM_MASK 0x2000 +#define RMDS_FRAM_SH 13 +#define RMDS_ERR_MASK 0x4000 +#define RMDS_ERR_SH 14 +#define RMDS_OWN_MASK 0x8000 +#define RMDS_OWN_SH 15 + +#define RMDM_MCNT_MASK 0x00000fff +#define RMDM_MCNT_SH 0 +#define RMDM_ZEROS_MASK 0x0000f000 +#define RMDM_ZEROS_SH 12 +#define RMDM_RPC_MASK 0x00ff0000 +#define RMDM_RPC_SH 16 +#define RMDM_RCC_MASK 0xff000000 +#define RMDM_RCC_SH 24 + +#define SET_FIELD(regp, name, field, value) \ + (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \ + | ((value) << name ## _ ## field ## _SH)) + +#define GET_FIELD(reg, name, field) \ + (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH) + +#define PRINT_TMD(T) printf( \ + "TMD0 : TBADR=0x%08x\n" \ "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \ "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \ " BPE=%d, BCNT=%d\n" \ "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \ "LCA=%d, RTR=%d,\n" \ " TDR=%d, TRC=%d\n", \ - (T)->tmd0.tbadr, \ - (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \ - (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \ - (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \ - 4096-(T)->tmd1.bcnt, \ - (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\ - (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \ - (T)->tmd2.tdr, (T)->tmd2.trc) - -#define PRINT_RMD(R) printf( \ - "RMD0 : RBADR=0x%08x\n" \ + (T)->tbadr, \ + GET_FIELD((T)->status, TMDS, OWN), \ + GET_FIELD((T)->status, TMDS, ERR), \ + GET_FIELD((T)->status, TMDS, NOFCS), \ + GET_FIELD((T)->status, TMDS, LTINT), \ + GET_FIELD((T)->status, TMDS, ONE), \ + GET_FIELD((T)->status, TMDS, DEF), \ + GET_FIELD((T)->status, TMDS, STP), \ + GET_FIELD((T)->status, TMDS, ENP), \ + GET_FIELD((T)->status, TMDS, BPE), \ + 4096-GET_FIELD((T)->length, TMDL, BCNT), \ + GET_FIELD((T)->misc, TMDM, BUFF), \ + GET_FIELD((T)->misc, TMDM, UFLO), \ + GET_FIELD((T)->misc, TMDM, EXDEF), \ + GET_FIELD((T)->misc, TMDM, LCOL), \ + GET_FIELD((T)->misc, TMDM, LCAR), \ + GET_FIELD((T)->misc, TMDM, RTRY), \ + GET_FIELD((T)->misc, TMDM, TDR), \ + GET_FIELD((T)->misc, TMDM, TRC)) + +#define PRINT_RMD(R) printf( \ + "RMD0 : RBADR=0x%08x\n" \ "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \ "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \ - "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ + "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \ - (R)->rmd0.rbadr, \ - (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \ - (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \ - (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \ - (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \ - (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \ - (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \ - (R)->rmd2.zeros) - -static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd1, + (R)->rbadr, \ + GET_FIELD((R)->status, RMDS, OWN), \ + GET_FIELD((R)->status, RMDS, ERR), \ + GET_FIELD((R)->status, RMDS, FRAM), \ + GET_FIELD((R)->status, RMDS, OFLO), \ + GET_FIELD((R)->status, RMDS, CRC), \ + GET_FIELD((R)->status, RMDS, BUFF), \ + GET_FIELD((R)->status, RMDS, STP), \ + GET_FIELD((R)->status, RMDS, ENP), \ + GET_FIELD((R)->status, RMDS, BPE), \ + GET_FIELD((R)->status, RMDS, PAM), \ + GET_FIELD((R)->status, RMDS, LFAM), \ + GET_FIELD((R)->status, RMDS, BAM), \ + GET_FIELD((R)->buf_length, RMDL, ONES), \ + 4096-GET_FIELD((R)->buf_length, RMDL, BCNT), \ + GET_FIELD((R)->msg_length, RMDM, RCC), \ + GET_FIELD((R)->msg_length, RMDM, RPC), \ + GET_FIELD((R)->msg_length, RMDM, MCNT), \ + GET_FIELD((R)->msg_length, RMDM, ZEROS)) + +static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) { - uint32_t *tmd = (uint32_t *)tmd1; - - if (!BCR_SWSTYLE(s)) { - uint16_t xda[4]; - s->phys_mem_read(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda), 0); - le16_to_cpus(&xda[0]); - le16_to_cpus(&xda[1]); - le16_to_cpus(&xda[2]); - le16_to_cpus(&xda[3]); - tmd[0] = (xda[0]&0xffff) | - ((xda[1]&0x00ff) << 16); - tmd[1] = (xda[2]&0xffff)| - ((xda[1] & 0xff00) << 16); - tmd[2] = - (xda[3] & 0xffff) << 16; - tmd[3] = 0; + if (!BCR_SSIZE32(s)) { + struct { + uint32_t tbadr; + int16_t length; + int16_t status; + } xda; + s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); + tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff; + tmd->length = le16_to_cpu(xda.length); + tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00; + tmd->misc = le16_to_cpu(xda.status) << 16; + tmd->res = 0; } else { - uint32_t xda[4]; - s->phys_mem_read(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda), 0); - le32_to_cpus(&xda[0]); - le32_to_cpus(&xda[1]); - le32_to_cpus(&xda[2]); - le32_to_cpus(&xda[3]); - if (BCR_SWSTYLE(s) != 3) { - memcpy(tmd, xda, sizeof(xda)); - } else { - tmd[0] = xda[2]; - tmd[1] = xda[1]; - tmd[2] = xda[0]; - tmd[3] = xda[3]; + s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0); + le32_to_cpus(&tmd->tbadr); + le16_to_cpus(&tmd->length); + le16_to_cpus(&tmd->status); + le32_to_cpus(&tmd->misc); + le32_to_cpus(&tmd->res); + if (BCR_SWSTYLE(s) == 3) { + uint32_t tmp = tmd->tbadr; + tmd->tbadr = tmd->misc; + tmd->misc = tmp; } } } -static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd1, +static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd, target_phys_addr_t addr) { - const uint32_t *tmd = (const uint32_t *)tmd1; - if (!BCR_SWSTYLE(s)) { - uint16_t xda[4]; - xda[0] = tmd[0] & 0xffff; - xda[1] = ((tmd[0]>>16)&0x00ff) | - ((tmd[1]>>16)&0xff00); - xda[2] = tmd[1] & 0xffff; - xda[3] = tmd[2] >> 16; - cpu_to_le16s(&xda[0]); - cpu_to_le16s(&xda[1]); - cpu_to_le16s(&xda[2]); - cpu_to_le16s(&xda[3]); - s->phys_mem_write(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda), 0); + if (!BCR_SSIZE32(s)) { + struct { + uint32_t tbadr; + int16_t length; + int16_t status; + } xda; + xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) | + ((tmd->status & 0xff00) << 16)); + xda.length = cpu_to_le16(tmd->length); + xda.status = cpu_to_le16(tmd->misc >> 16); + s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); } else { - uint32_t xda[4]; - if (BCR_SWSTYLE(s) != 3) { - memcpy(xda, tmd, sizeof(xda)); - } else { - xda[0] = tmd[2]; - xda[1] = tmd[1]; - xda[2] = tmd[0]; - xda[3] = tmd[3]; + struct { + uint32_t tbadr; + int16_t length; + int16_t status; + uint32_t misc; + uint32_t res; + } xda; + xda.tbadr = cpu_to_le32(tmd->tbadr); + xda.length = cpu_to_le16(tmd->length); + xda.status = cpu_to_le16(tmd->status); + xda.misc = cpu_to_le32(tmd->misc); + xda.res = cpu_to_le32(tmd->res); + if (BCR_SWSTYLE(s) == 3) { + uint32_t tmp = xda.tbadr; + xda.tbadr = xda.misc; + xda.misc = tmp; } - cpu_to_le32s(&xda[0]); - cpu_to_le32s(&xda[1]); - cpu_to_le32s(&xda[2]); - cpu_to_le32s(&xda[3]); - s->phys_mem_write(s->dma_opaque, addr, - (void *)&xda[0], sizeof(xda), 0); + s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0); } } -static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd1, +static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) { - uint32_t *rmd = (uint32_t *)rmd1; - - if (!BCR_SWSTYLE(s)) { - uint16_t rda[4]; - s->phys_mem_read(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda), 0); - le16_to_cpus(&rda[0]); - le16_to_cpus(&rda[1]); - le16_to_cpus(&rda[2]); - le16_to_cpus(&rda[3]); - rmd[0] = (rda[0]&0xffff)| - ((rda[1] & 0x00ff) << 16); - rmd[1] = (rda[2]&0xffff)| - ((rda[1] & 0xff00) << 16); - rmd[2] = rda[3] & 0xffff; - rmd[3] = 0; + if (!BCR_SSIZE32(s)) { + struct { + uint32_t rbadr; + int16_t buf_length; + int16_t msg_length; + } rda; + s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0); + rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff; + rmd->buf_length = le16_to_cpu(rda.buf_length); + rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00; + rmd->msg_length = le16_to_cpu(rda.msg_length); + rmd->res = 0; } else { - uint32_t rda[4]; - s->phys_mem_read(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda), 0); - le32_to_cpus(&rda[0]); - le32_to_cpus(&rda[1]); - le32_to_cpus(&rda[2]); - le32_to_cpus(&rda[3]); - if (BCR_SWSTYLE(s) != 3) { - memcpy(rmd, rda, sizeof(rda)); - } else { - rmd[0] = rda[2]; - rmd[1] = rda[1]; - rmd[2] = rda[0]; - rmd[3] = rda[3]; + s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0); + le32_to_cpus(&rmd->rbadr); + le16_to_cpus(&rmd->buf_length); + le16_to_cpus(&rmd->status); + le32_to_cpus(&rmd->msg_length); + le32_to_cpus(&rmd->res); + if (BCR_SWSTYLE(s) == 3) { + uint32_t tmp = rmd->rbadr; + rmd->rbadr = rmd->msg_length; + rmd->msg_length = tmp; } } } -static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, +static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) { - const uint32_t *rmd = (const uint32_t *)rmd1; - - if (!BCR_SWSTYLE(s)) { - uint16_t rda[4]; - rda[0] = rmd[0] & 0xffff; - rda[1] = ((rmd[0]>>16)&0xff)| - ((rmd[1]>>16)&0xff00); - rda[2] = rmd[1] & 0xffff; - rda[3] = rmd[2] & 0xffff; - cpu_to_le16s(&rda[0]); - cpu_to_le16s(&rda[1]); - cpu_to_le16s(&rda[2]); - cpu_to_le16s(&rda[3]); - s->phys_mem_write(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda), 0); + if (!BCR_SSIZE32(s)) { + struct { + uint32_t rbadr; + int16_t buf_length; + int16_t msg_length; + } rda; + rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) | + ((rmd->status & 0xff00) << 16)); + rda.buf_length = cpu_to_le16(rmd->buf_length); + rda.msg_length = cpu_to_le16(rmd->msg_length); + s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0); } else { - uint32_t rda[4]; - if (BCR_SWSTYLE(s) != 3) { - memcpy(rda, rmd, sizeof(rda)); - } else { - rda[0] = rmd[2]; - rda[1] = rmd[1]; - rda[2] = rmd[0]; - rda[3] = rmd[3]; + struct { + uint32_t rbadr; + int16_t buf_length; + int16_t status; + uint32_t msg_length; + uint32_t res; + } rda; + rda.rbadr = cpu_to_le32(rmd->rbadr); + rda.buf_length = cpu_to_le16(rmd->buf_length); + rda.status = cpu_to_le16(rmd->status); + rda.msg_length = cpu_to_le32(rmd->msg_length); + rda.res = cpu_to_le32(rmd->res); + if (BCR_SWSTYLE(s) == 3) { + uint32_t tmp = rda.rbadr; + rda.rbadr = rda.msg_length; + rda.msg_length = tmp; } - cpu_to_le32s(&rda[0]); - cpu_to_le32s(&rda[1]); - cpu_to_le32s(&rda[2]); - cpu_to_le32s(&rda[3]); - s->phys_mem_write(s->dma_opaque, addr, - (void *)&rda[0], sizeof(rda), 0); + s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0); } } @@ -417,14 +477,14 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, #define CHECK_RMD(ADDR,RES) do { \ struct pcnet_RMD rmd; \ RMDLOAD(&rmd,(ADDR)); \ - (RES) |= (rmd.rmd1.ones != 15) \ - || (rmd.rmd2.zeros != 0); \ + (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \ + || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \ } while (0) #define CHECK_TMD(ADDR,RES) do { \ struct pcnet_TMD tmd; \ TMDLOAD(&tmd,(ADDR)); \ - (RES) |= (tmd.tmd1.ones != 15); \ + (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \ } while (0) #else @@ -434,8 +494,8 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, case 0x00: \ do { \ uint16_t rda[4]; \ - s->phys_mem_read(s->dma_opaque, (ADDR), \ - (void *)&rda[0], sizeof(rda), 0); \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ + (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[2] & 0xf000)!=0xf000; \ (RES) |= (rda[3] & 0xf000)!=0x0000; \ } while (0); \ @@ -444,7 +504,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, case 0x02: \ do { \ uint32_t rda[4]; \ - s->phys_mem_read(s->dma_opaque, (ADDR), \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ @@ -453,7 +513,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, case 0x03: \ do { \ uint32_t rda[4]; \ - s->phys_mem_read(s->dma_opaque, (ADDR), \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ @@ -467,9 +527,9 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, case 0x00: \ do { \ uint16_t xda[4]; \ - s->phys_mem_read(s->dma_opaque, (ADDR), \ - (void *)&xda[0], sizeof(xda), 0); \ - (RES) |= (xda[2] & 0xf000)!=0xf000;\ + s->phys_mem_read(s->dma_opaque, (ADDR), \ + (void *)&xda[0], sizeof(xda), 0); \ + (RES) |= (xda[2] & 0xf000)!=0xf000; \ } while (0); \ break; \ case 0x01: \ @@ -477,8 +537,8 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, case 0x03: \ do { \ uint32_t xda[4]; \ - s->phys_mem_read(s->dma_opaque, (ADDR), \ - (void *)&xda[0], sizeof(xda), 0); \ + s->phys_mem_read(s->dma_opaque, (ADDR), \ + (void *)&xda[0], sizeof(xda), 0); \ (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ } while (0); \ break; \ @@ -488,15 +548,15 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, #endif #define PRINT_PKTHDR(BUF) do { \ - struct qemu_ether_header *hdr = (void *)(BUF); \ - printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ - "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ - "type=0x%04x\n", \ + struct qemu_ether_header *hdr = (void *)(BUF); \ + printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ + "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ + "type=0x%04x\n", \ hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \ hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ - be16_to_cpu(hdr->ether_type)); \ + be16_to_cpu(hdr->ether_type)); \ } while (0) #define MULTICAST_FILTER_LEN 8 @@ -770,7 +830,7 @@ static void pcnet_update_irq(PCNetState *s) static void pcnet_init(PCNetState *s) { int rlen, tlen; - uint16_t *padr, *ladrf, mode; + uint16_t padr[3], ladrf[4], mode; uint32_t rdra, tdra; #ifdef PCNET_DEBUG @@ -781,22 +841,30 @@ static void pcnet_init(PCNetState *s) struct pcnet_initblk32 initblk; s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), (uint8_t *)&initblk, sizeof(initblk), 0); - mode = initblk.mode; + mode = le16_to_cpu(initblk.mode); rlen = initblk.rlen >> 4; tlen = initblk.tlen >> 4; - ladrf = initblk.ladrf; - padr = initblk.padr; + ladrf[0] = le16_to_cpu(initblk.ladrf[0]); + ladrf[1] = le16_to_cpu(initblk.ladrf[1]); + ladrf[2] = le16_to_cpu(initblk.ladrf[2]); + ladrf[3] = le16_to_cpu(initblk.ladrf[3]); + padr[0] = le16_to_cpu(initblk.padr[0]); + padr[1] = le16_to_cpu(initblk.padr[1]); + padr[2] = le16_to_cpu(initblk.padr[2]); rdra = le32_to_cpu(initblk.rdra); tdra = le32_to_cpu(initblk.tdra); - s->rdra = PHYSADDR(s,initblk.rdra); - s->tdra = PHYSADDR(s,initblk.tdra); } else { struct pcnet_initblk16 initblk; s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), (uint8_t *)&initblk, sizeof(initblk), 0); - mode = initblk.mode; - ladrf = initblk.ladrf; - padr = initblk.padr; + mode = le16_to_cpu(initblk.mode); + ladrf[0] = le16_to_cpu(initblk.ladrf[0]); + ladrf[1] = le16_to_cpu(initblk.ladrf[1]); + ladrf[2] = le16_to_cpu(initblk.ladrf[2]); + ladrf[3] = le16_to_cpu(initblk.ladrf[3]); + padr[0] = le16_to_cpu(initblk.padr[0]); + padr[1] = le16_to_cpu(initblk.padr[1]); + padr[2] = le16_to_cpu(initblk.padr[2]); rdra = le32_to_cpu(initblk.rdra); tdra = le32_to_cpu(initblk.tdra); rlen = rdra >> 29; @@ -804,22 +872,22 @@ static void pcnet_init(PCNetState *s) rdra &= 0x00ffffff; tdra &= 0x00ffffff; } - + #if defined(PCNET_DEBUG) - printf("rlen=%d tlen=%d\n", - rlen, tlen); + printf("rlen=%d tlen=%d\n", rlen, tlen); #endif + CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512; CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512; s->csr[ 6] = (tlen << 12) | (rlen << 8); - s->csr[15] = le16_to_cpu(mode); - s->csr[ 8] = le16_to_cpu(ladrf[0]); - s->csr[ 9] = le16_to_cpu(ladrf[1]); - s->csr[10] = le16_to_cpu(ladrf[2]); - s->csr[11] = le16_to_cpu(ladrf[3]); - s->csr[12] = le16_to_cpu(padr[0]); - s->csr[13] = le16_to_cpu(padr[1]); - s->csr[14] = le16_to_cpu(padr[2]); + s->csr[15] = mode; + s->csr[ 8] = ladrf[0]; + s->csr[ 9] = ladrf[1]; + s->csr[10] = ladrf[2]; + s->csr[11] = ladrf[3]; + s->csr[12] = padr[0]; + s->csr[13] = padr[1]; + s->csr[14] = padr[2]; s->rdra = PHYSADDR(s, rdra); s->tdra = PHYSADDR(s, tdra); @@ -914,12 +982,12 @@ static void pcnet_rdte_poll(PCNetState *s) if (CSR_CRDA(s)) { struct pcnet_RMD rmd; RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); - CSR_CRBC(s) = rmd.rmd1.bcnt; - CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16; + CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT); + CSR_CRST(s) = rmd.status; #ifdef PCNET_DEBUG_RMD_X - printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n", + printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n", PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), - ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]); + rmd.buf_length, rmd.status, rmd.msg_length); PRINT_RMD(&rmd); #endif } else { @@ -929,8 +997,8 @@ static void pcnet_rdte_poll(PCNetState *s) if (CSR_NRDA(s)) { struct pcnet_RMD rmd; RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); - CSR_NRBC(s) = rmd.rmd1.bcnt; - CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16; + CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT); + CSR_NRST(s) = rmd.status; } else { CSR_NRBC(s) = CSR_NRST(s) = 0; } @@ -943,7 +1011,7 @@ static int pcnet_tdte_poll(PCNetState *s) if (s->tdra) { target_phys_addr_t cxda = s->tdra + (CSR_XMTRL(s) - CSR_XMTRC(s)) * - (BCR_SWSTYLE(s) ? 16 : 8 ); + (BCR_SWSTYLE(s) ? 16 : 8); int bad = 0; CHECK_TMD(PHYSADDR(s, cxda),bad); if (!bad) { @@ -955,8 +1023,7 @@ static int pcnet_tdte_poll(PCNetState *s) } s->csr[34] = cxda & 0xffff; s->csr[35] = cxda >> 16; -#ifdef PCNET_DEBUG - } else { +#ifdef PCNET_DEBUG_X printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda)); #endif } @@ -967,8 +1034,8 @@ static int pcnet_tdte_poll(PCNetState *s) TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); - CSR_CXBC(s) = tmd.tmd1.bcnt; - CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16; + CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT); + CSR_CXST(s) = tmd.status; } else { CSR_CXBC(s) = CSR_CXST(s) = 0; } @@ -1029,7 +1096,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) (CSR_RCVRL(s) - rcvrc) * (BCR_SWSTYLE(s) ? 16 : 8 ); RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { + if (GET_FIELD(rmd.status, RMDS, OWN)) { #ifdef PCNET_DEBUG_RMD printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", rcvrc, CSR_RCVRC(s)); @@ -1086,14 +1153,15 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) RMDLOAD(&rmd, PHYSADDR(s,crda)); /*if (!CSR_LAPPEN(s))*/ - rmd.rmd1.stp = 1; + SET_FIELD(&rmd.status, RMDS, STP, 1); #define PCNET_RECV_STORE() do { \ - int count = MIN(4096 - rmd.rmd1.bcnt,size); \ - target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ - s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ + int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),size); \ + target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \ + s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ src += count; size -= count; \ - rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ + SET_FIELD(&rmd.msg_length, RMDM, MCNT, count); \ + SET_FIELD(&rmd.status, RMDS, OWN, 0); \ RMDSTORE(&rmd, PHYSADDR(s,crda)); \ pktcount++; \ } while (0) @@ -1102,12 +1170,12 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) if ((size > 0) && CSR_NRDA(s)) { target_phys_addr_t nrda = CSR_NRDA(s); RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { + if (GET_FIELD(rmd.status, RMDS, OWN)) { crda = nrda; PCNET_RECV_STORE(); if ((size > 0) && (nrda=CSR_NNRD(s))) { RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { + if (GET_FIELD(rmd.status, RMDS, OWN)) { crda = nrda; PCNET_RECV_STORE(); } @@ -1119,14 +1187,14 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) RMDLOAD(&rmd, PHYSADDR(s,crda)); if (size == 0) { - rmd.rmd1.enp = 1; - rmd.rmd1.pam = !CSR_PROM(s) && is_padr; - rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; - rmd.rmd1.bam = !CSR_PROM(s) && is_bcast; + SET_FIELD(&rmd.status, RMDS, ENP, 1); + SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr); + SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr); + SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast); } else { - rmd.rmd1.oflo = 1; - rmd.rmd1.buff = 1; - rmd.rmd1.err = 1; + SET_FIELD(&rmd.status, RMDS, OFLO, 1); + SET_FIELD(&rmd.status, RMDS, BUFF, 1); + SET_FIELD(&rmd.status, RMDS, ERR, 1); } RMDSTORE(&rmd, PHYSADDR(s,crda)); s->csr[0] |= 0x0400; @@ -1172,30 +1240,30 @@ static void pcnet_transmit(PCNetState *s) if (pcnet_tdte_poll(s)) { struct pcnet_TMD tmd; - TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); #ifdef PCNET_DEBUG_TMD printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); PRINT_TMD(&tmd); #endif - if (tmd.tmd1.stp) { - s->xmit_pos = 0; - if (!tmd.tmd1.enp) { - s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), - s->buffer, 4096 - tmd.tmd1.bcnt, - CSR_BSWP(s)); - s->xmit_pos += 4096 - tmd.tmd1.bcnt; - } + if (GET_FIELD(tmd.status, TMDS, STP)) { + s->xmit_pos = 0; + if (!GET_FIELD(tmd.status, TMDS, ENP)) { + int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); + s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), + s->buffer, bcnt, CSR_BSWP(s)); + s->xmit_pos += bcnt; + } xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); } - if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { - s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), - s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt, - CSR_BSWP(s)); - s->xmit_pos += 4096 - tmd.tmd1.bcnt; + if (GET_FIELD(tmd.status, TMDS, ENP) && (s->xmit_pos >= 0)) { + int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); + s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), + s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s)); + s->xmit_pos += bcnt; #ifdef PCNET_DEBUG printf("pcnet_transmit size=%d\n", s->xmit_pos); -#endif +#endif if (CSR_LOOP(s)) pcnet_receive(s, s->buffer, s->xmit_pos); else @@ -1206,9 +1274,9 @@ static void pcnet_transmit(PCNetState *s) s->xmit_pos = -1; } - tmd.tmd1.own = 0; + SET_FIELD(&tmd.status, TMDS, OWN, 0); TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); - if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) + if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT))) s->csr[0] |= 0x0200; /* set TINT */ if (CSR_XMTRC(s)<=1) @@ -1221,9 +1289,11 @@ static void pcnet_transmit(PCNetState *s) } else if (s->xmit_pos >= 0) { struct pcnet_TMD tmd; - TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); - tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; - tmd.tmd1.own = 0; + TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); + SET_FIELD(&tmd.misc, TMDM, BUFF, 1); + SET_FIELD(&tmd.misc, TMDM, UFLO, 1); + SET_FIELD(&tmd.status, TMDS, ERR, 1); + SET_FIELD(&tmd.status, TMDS, OWN, 0); TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); s->csr[0] |= 0x0200; /* set TINT */ if (!CSR_DXSUFLO(s)) { -- cgit v1.2.3 From 451a42127ff27a499bed22e4eef1a5c452adc311 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 6 Mar 2007 19:36:53 +0000 Subject: Fix typo in PCI bridge code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2470 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci.c b/hw/pci.c index b895f98a0..eeaef9e83 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -587,7 +587,7 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge), devfn, NULL, pci_bridge_write_config); s->dev.config[0x00] = id >> 16; - s->dev.config[0x01] = id > 24; + s->dev.config[0x01] = id >> 24; s->dev.config[0x02] = id; // device_id s->dev.config[0x03] = id >> 8; s->dev.config[0x04] = 0x06; // command = bus master, pci mem -- cgit v1.2.3 From 35f1de319299f043132702c36ebaadfc4a15db69 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 6 Mar 2007 20:31:09 +0000 Subject: Fix GT-64xxx PCI mapping, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2471 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index ccb6a7c1a..2b01da70b 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -222,18 +222,24 @@ typedef PCIHostState GT64120PCIState; typedef struct GT64120State { GT64120PCIState *pci; uint32_t regs[GT_REGS]; + target_phys_addr_t PCI0IO_start; + target_phys_addr_t PCI0IO_length; } GT64120State; static void gt64120_pci_mapping(GT64120State *s) { - target_phys_addr_t start, length; - /* Update IO mapping */ if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD]) { - start = s->regs[GT_PCI0IOLD] << 21; - length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; - isa_mmio_init(start, length); + /* Unmap old IO address */ + if (s->PCI0IO_length) + { + cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED); + } + /* Map new IO address */ + s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21; + s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; + isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length); } } -- cgit v1.2.3 From 1c7b3754f68382941a1921e578ead25d97d116fb Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 6 Mar 2007 23:52:01 +0000 Subject: Simple u-boot image loading support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2472 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_boot.c | 34 ++++++++----- loader.c | 78 ++++++++++++++++++++++++++++ uboot_image.h | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 1 + 4 files changed, 261 insertions(+), 12 deletions(-) create mode 100644 uboot_image.h diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 28f6a9262..c313a9f9a 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -71,7 +71,9 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, int kernel_size; int initrd_size; int n; - uint64_t entry; + int is_linux = 0; + uint64_t elf_entry; + target_ulong entry; /* Load the kernel. */ if (!kernel_filename) { @@ -79,19 +81,27 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, exit(1); } - kernel_size = load_elf(kernel_filename, 0, &entry); - if (kernel_size >= 0) { - /* An ELF image. Jump to the entry point. */ + /* Assume that raw images are linux kernels, and ELF images are not. */ + kernel_size = load_elf(kernel_filename, 0, &elf_entry); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uboot(kernel_filename, &entry, &is_linux); + } + if (kernel_size < 0) { + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR); + entry = KERNEL_LOAD_ADDR; + is_linux = 1; + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + if (!is_linux) { + /* Jump to the entry point. */ env->regs[15] = entry & 0xfffffffe; env->thumb = entry & 1; } else { - /* Raw binary image. Assume it is a Linux zImage. */ - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); - } if (initrd_filename) { initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); @@ -106,7 +116,7 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, bootloader[1] |= board_id & 0xff; bootloader[2] |= (board_id >> 8) & 0xff; bootloader[5] = KERNEL_ARGS_ADDR; - bootloader[6] = KERNEL_LOAD_ADDR; + bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) stl_raw(phys_ram_base + (n * 4), bootloader[n]); set_kernel_args(ram_size, initrd_size, kernel_cmdline); diff --git a/loader.c b/loader.c index 7823add91..827d456d2 100644 --- a/loader.c +++ b/loader.c @@ -23,6 +23,7 @@ */ #include "vl.h" #include "disas.h" +#include "uboot_image.h" /* return the size or -1 if error */ int get_image_size(const char *filename) @@ -241,3 +242,80 @@ int load_elf(const char *filename, int64_t virt_to_phys_addend, close(fd); return -1; } + +static void bswap_uboot_header(uboot_image_header_t *hdr) +{ +#ifndef WORDS_BIGENDIAN + bswap32s(&hdr->ih_magic); + bswap32s(&hdr->ih_hcrc); + bswap32s(&hdr->ih_time); + bswap32s(&hdr->ih_size); + bswap32s(&hdr->ih_load); + bswap32s(&hdr->ih_ep); + bswap32s(&hdr->ih_dcrc); +#endif +} + +/* Load a U-Boot image. */ +int load_uboot(const char *filename, target_ulong *ep, int *is_linux) +{ + + int fd; + int size; + uboot_image_header_t h; + uboot_image_header_t *hdr = &h; + uint8_t *data = NULL; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return -1; + + size = read(fd, hdr, sizeof(uboot_image_header_t)); + if (size < 0) + goto fail; + + bswap_uboot_header(hdr); + + if (hdr->ih_magic != IH_MAGIC) + goto fail; + + /* TODO: Implement Multi-File images. */ + if (hdr->ih_type == IH_TYPE_MULTI) { + fprintf(stderr, "Unable to load multi-file u-boot images\n"); + goto fail; + } + + /* TODO: Implement compressed images. */ + if (hdr->ih_comp != IH_COMP_NONE) { + fprintf(stderr, "Unable to load compressed u-boot images\n"); + goto fail; + } + + /* TODO: Check CPU type. */ + if (is_linux) { + if (hdr->ih_type == IH_TYPE_KERNEL && hdr->ih_os == IH_OS_LINUX) + *is_linux = 1; + else + *is_linux = 0; + } + + *ep = hdr->ih_ep; + data = qemu_malloc(hdr->ih_size); + if (!data) + goto fail; + + if (read(fd, data, hdr->ih_size) != hdr->ih_size) { + fprintf(stderr, "Error reading file\n"); + goto fail; + } + + cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size); + + return hdr->ih_size; + +fail: + if (data) + qemu_free(data); + close(fd); + return -1; +} diff --git a/uboot_image.h b/uboot_image.h new file mode 100644 index 000000000..d5a5b3045 --- /dev/null +++ b/uboot_image.h @@ -0,0 +1,160 @@ +/* + * (C) Copyright 2000-2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + * + ******************************************************************** + * NOTE: This header file defines an interface to U-Boot. Including + * this (unmodified) header file in another file is considered normal + * use of U-Boot, and does *not* fall under the heading of "derived + * work". + ******************************************************************** + */ + +#ifndef __UBOOT_IMAGE_H__ +#define __UBOOT_IMAGE_H__ + +/* + * Operating System Codes + */ +#define IH_OS_INVALID 0 /* Invalid OS */ +#define IH_OS_OPENBSD 1 /* OpenBSD */ +#define IH_OS_NETBSD 2 /* NetBSD */ +#define IH_OS_FREEBSD 3 /* FreeBSD */ +#define IH_OS_4_4BSD 4 /* 4.4BSD */ +#define IH_OS_LINUX 5 /* Linux */ +#define IH_OS_SVR4 6 /* SVR4 */ +#define IH_OS_ESIX 7 /* Esix */ +#define IH_OS_SOLARIS 8 /* Solaris */ +#define IH_OS_IRIX 9 /* Irix */ +#define IH_OS_SCO 10 /* SCO */ +#define IH_OS_DELL 11 /* Dell */ +#define IH_OS_NCR 12 /* NCR */ +#define IH_OS_LYNXOS 13 /* LynxOS */ +#define IH_OS_VXWORKS 14 /* VxWorks */ +#define IH_OS_PSOS 15 /* pSOS */ +#define IH_OS_QNX 16 /* QNX */ +#define IH_OS_U_BOOT 17 /* Firmware */ +#define IH_OS_RTEMS 18 /* RTEMS */ +#define IH_OS_ARTOS 19 /* ARTOS */ +#define IH_OS_UNITY 20 /* Unity OS */ + +/* + * CPU Architecture Codes (supported by Linux) + */ +#define IH_CPU_INVALID 0 /* Invalid CPU */ +#define IH_CPU_ALPHA 1 /* Alpha */ +#define IH_CPU_ARM 2 /* ARM */ +#define IH_CPU_I386 3 /* Intel x86 */ +#define IH_CPU_IA64 4 /* IA64 */ +#define IH_CPU_MIPS 5 /* MIPS */ +#define IH_CPU_MIPS64 6 /* MIPS 64 Bit */ +#define IH_CPU_PPC 7 /* PowerPC */ +#define IH_CPU_S390 8 /* IBM S390 */ +#define IH_CPU_SH 9 /* SuperH */ +#define IH_CPU_SPARC 10 /* Sparc */ +#define IH_CPU_SPARC64 11 /* Sparc 64 Bit */ +#define IH_CPU_M68K 12 /* M68K */ +#define IH_CPU_NIOS 13 /* Nios-32 */ +#define IH_CPU_MICROBLAZE 14 /* MicroBlaze */ +#define IH_CPU_NIOS2 15 /* Nios-II */ +#define IH_CPU_BLACKFIN 16 /* Blackfin */ +#define IH_CPU_AVR32 17 /* AVR32 */ + +/* + * Image Types + * + * "Standalone Programs" are directly runnable in the environment + * provided by U-Boot; it is expected that (if they behave + * well) you can continue to work in U-Boot after return from + * the Standalone Program. + * "OS Kernel Images" are usually images of some Embedded OS which + * will take over control completely. Usually these programs + * will install their own set of exception handlers, device + * drivers, set up the MMU, etc. - this means, that you cannot + * expect to re-enter U-Boot except by resetting the CPU. + * "RAMDisk Images" are more or less just data blocks, and their + * parameters (address, size) are passed to an OS kernel that is + * being started. + * "Multi-File Images" contain several images, typically an OS + * (Linux) kernel image and one or more data images like + * RAMDisks. This construct is useful for instance when you want + * to boot over the network using BOOTP etc., where the boot + * server provides just a single image file, but you want to get + * for instance an OS kernel and a RAMDisk image. + * + * "Multi-File Images" start with a list of image sizes, each + * image size (in bytes) specified by an "uint32_t" in network + * byte order. This list is terminated by an "(uint32_t)0". + * Immediately after the terminating 0 follow the images, one by + * one, all aligned on "uint32_t" boundaries (size rounded up to + * a multiple of 4 bytes - except for the last file). + * + * "Firmware Images" are binary images containing firmware (like + * U-Boot or FPGA images) which usually will be programmed to + * flash memory. + * + * "Script files" are command sequences that will be executed by + * U-Boot's command interpreter; this feature is especially + * useful when you configure U-Boot to use a real shell (hush) + * as command interpreter (=> Shell Scripts). + */ + +#define IH_TYPE_INVALID 0 /* Invalid Image */ +#define IH_TYPE_STANDALONE 1 /* Standalone Program */ +#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ +#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ +#define IH_TYPE_MULTI 4 /* Multi-File Image */ +#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ +#define IH_TYPE_SCRIPT 6 /* Script file */ +#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ +#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ + +/* + * Compression Types + */ +#define IH_COMP_NONE 0 /* No Compression Used */ +#define IH_COMP_GZIP 1 /* gzip Compression Used */ +#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ + +#define IH_MAGIC 0x27051956 /* Image Magic Number */ +#define IH_NMLEN 32 /* Image Name Length */ + +/* + * all data in network byte order (aka natural aka bigendian) + */ + +typedef struct uboot_image_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +} uboot_image_header_t; + + +#endif /* __IMAGE_H__ */ diff --git a/vl.h b/vl.h index 0f5ab9700..26b274175 100644 --- a/vl.h +++ b/vl.h @@ -1155,6 +1155,7 @@ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); int load_elf(const char *filename, int64_t virt_to_phys_addend, uint64_t *pentry); int load_aout(const char *filename, uint8_t *addr); +int load_uboot(const char *filename, target_ulong *ep, int *is_linux); /* slavio_timer.c */ void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu); -- cgit v1.2.3 From 76a66253e5e48f1744f689041c1c21cedcaff630 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 7 Mar 2007 08:32:30 +0000 Subject: Great PowerPC emulation code resynchronisation and improvments: - Add status file to make regression tracking easier - Move all micro-operations helpers definitions into a separate header: should never be seen outside of op.c - Update copyrights - Add new / missing PowerPC CPU definitions - Add definitions for PowerPC BookE - Add support for PowerPC 6xx/7xx software driven TLBs Allow use of PowerPC 603 as an example - Add preliminary code for POWER, POWER2, PowerPC 403, 405, 440, 601, 602 and BookE support - Avoid compiling priviledged only resources support for user-mode emulation - Remove unused helpers / micro-ops / dead code - Add instructions usage statistics dump: useful to figure which instructions need strong optimizations. - Micro-operation fixes: * add missing RETURN in some micro-ops * fix prototypes * use softfloat routines for all floating-point operations * fix tlbie instruction * move some huge micro-operations into helpers - emulation fixes: * fix inverted opcodes for fcmpo / fcmpu * condition register update is always to be done after the whole instruction has completed * add missing NIP updates when calling helpers that may generate an exception - optimizations and improvments: * optimize very often used instructions (li, mr, rlwixx...) * remove specific micro-ops for rarely used instructions * add routines for addresses computations to avoid bugs due to multiple different implementations * fix TB linking: do not reset T0 at the end of every TB. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2473 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 3 + gdbstub.c | 4 +- hw/ppc.c | 91 +- linux-user/main.c | 21 +- monitor.c | 15 + target-ppc/STATUS | 91 ++ target-ppc/cpu.h | 926 ++++++----- target-ppc/exec.h | 76 +- target-ppc/helper.c | 1089 ++++++++----- target-ppc/mfrom_table.c | 79 + target-ppc/mfrom_table_gen.c | 33 + target-ppc/op.c | 896 +++++++++-- target-ppc/op_helper.c | 696 +++++++- target-ppc/op_helper.h | 132 ++ target-ppc/op_helper_mem.h | 206 ++- target-ppc/op_mem.h | 142 +- target-ppc/op_template.h | 73 +- target-ppc/translate.c | 2224 ++++++++++++++++++++------ target-ppc/translate_init.c | 3634 ++++++++++++++++++++++++++++++------------ 19 files changed, 7753 insertions(+), 2678 deletions(-) create mode 100644 target-ppc/STATUS create mode 100644 target-ppc/mfrom_table.c create mode 100644 target-ppc/mfrom_table_gen.c create mode 100644 target-ppc/op_helper.h diff --git a/cpu-all.h b/cpu-all.h index 0ad50e8bf..86acc36d6 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -759,6 +759,9 @@ CPUState *cpu_copy(CPUState *env); void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags); +void cpu_dump_statistics (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; diff --git a/gdbstub.c b/gdbstub.c index d1f104489..57d97e340 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -307,7 +307,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) registers[98] = tswapl(tmp); registers[99] = tswapl(env->lr); registers[100] = tswapl(env->ctr); - registers[101] = tswapl(do_load_xer(env)); + registers[101] = tswapl(ppc_load_xer(env)); registers[102] = 0; return 103 * 4; @@ -335,7 +335,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; env->lr = tswapl(registers[99]); env->ctr = tswapl(registers[100]); - do_store_xer(env, tswapl(registers[101])); + ppc_store_xer(env, tswapl(registers[101])); } #elif defined (TARGET_SPARC) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) diff --git a/hw/ppc.c b/hw/ppc.c index b0865c164..c910cb9f7 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -1,7 +1,7 @@ /* * QEMU generic PPC hardware System Emulator * - * Copyright (c) 2003-2004 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,7 +41,7 @@ static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env) { /* TB time in tb periods */ return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, - tb_env->tb_freq, ticks_per_sec); + tb_env->tb_freq, ticks_per_sec); } uint32_t cpu_ppc_load_tbl (CPUState *env) @@ -52,14 +52,14 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) tb = cpu_ppc_get_tb(tb_env); #ifdef DEBUG_TB { - static int last_time; - int now; - now = time(NULL); - if (last_time != now) { - last_time = now; - printf("%s: tb=0x%016lx %d %08lx\n", - __func__, tb, now, tb_env->tb_offset); - } + static int last_time; + int now; + now = time(NULL); + if (last_time != now) { + last_time = now; + printf("%s: tb=0x%016lx %d %08lx\n", + __func__, tb, now, tb_env->tb_offset); + } } #endif @@ -75,6 +75,7 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) #ifdef DEBUG_TB printf("%s: tb=0x%016lx\n", __func__, tb); #endif + return tb >> 32; } @@ -117,6 +118,7 @@ uint32_t cpu_ppc_load_decr (CPUState *env) #if defined(DEBUG_TB) printf("%s: 0x%08x\n", __func__, decr); #endif + return decr; } @@ -146,7 +148,7 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, if (is_excp) next += tb_env->decr_next - now; if (next == now) - next++; + next++; tb_env->decr_next = next; /* Adjust timer */ qemu_mod_timer(tb_env->decr_timer, next); @@ -154,7 +156,7 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, * raise an exception. */ if ((value & 0x80000000) && !(decr & 0x80000000)) - cpu_ppc_decr_excp(env); + cpu_ppc_decr_excp(env); } void cpu_ppc_store_decr (CPUState *env, uint32_t value) @@ -177,20 +179,64 @@ ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq) return NULL; env->tb_env = tb_env; if (tb_env->tb_freq == 0 || 1) { - tb_env->tb_freq = freq; - /* Create new timer */ - tb_env->decr_timer = + tb_env->tb_freq = freq; + /* Create new timer */ + tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); - /* There is a bug in 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee, - * it's not ready to handle it... - */ - _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); + /* There is a bug in Linux 2.4 kernels: + * if a decrementer exception is pending when it enables msr_ee, + * it's not ready to handle it... + */ + _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); } return tb_env; } +/* Specific helpers for POWER & PowerPC 601 RTC */ +ppc_tb_t *cpu_ppc601_rtc_init (CPUState *env) +{ + return cpu_ppc_tb_init(env, 7812500); +} + +void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value) +__attribute__ (( alias ("cpu_ppc_store_tbu") )); + +uint32_t cpu_ppc601_load_rtcu (CPUState *env) +__attribute__ (( alias ("cpu_ppc_load_tbu") )); + +void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tbl(env, value & 0x3FFFFF80); +} + +uint32_t cpu_ppc601_load_rtcl (CPUState *env) +{ + return cpu_ppc_load_tbl(env) & 0x3FFFFF80; +} + +/* Embedded PowerPC timers */ +target_ulong load_40x_pit (CPUState *env) +{ + /* XXX: TODO */ + return 0; +} + +void store_40x_pit (CPUState *env, target_ulong val) +{ + /* XXX: TODO */ +} + +void store_booke_tcr (CPUState *env, target_ulong val) +{ + /* XXX: TODO */ +} + +void store_booke_tsr (CPUState *env, target_ulong val) +{ + /* XXX: TODO */ +} + #if 0 /*****************************************************************************/ /* Handle system reset (for now, just stop emulation) */ @@ -264,6 +310,7 @@ uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) tmp |= m48t59_read(nvram, addr + 1) << 16; tmp |= m48t59_read(nvram, addr + 2) << 8; tmp |= m48t59_read(nvram, addr + 3); + return tmp; } @@ -316,10 +363,10 @@ uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) odd = count & 1; count &= ~1; for (i = 0; i != count; i++) { - crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); + crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); } if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); + crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); } return crc; diff --git a/linux-user/main.c b/linux-user/main.c index 367138448..702c3b955 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -670,18 +670,23 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) { cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); } - -uint32_t cpu_ppc_load_decr (CPUState *env) + +void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value) +__attribute__ (( alias ("cpu_ppc_store_tbu") )); + +uint32_t cpu_ppc601_load_rtcu (CPUState *env) +__attribute__ (( alias ("cpu_ppc_load_tbu") )); + +void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value) { - /* TO FIX */ - return -1; + cpu_ppc_store_tbl(env, value & 0x3FFFFF80); } - -void cpu_ppc_store_decr (CPUState *env, uint32_t value) + +uint32_t cpu_ppc601_load_rtcl (CPUState *env) { - /* TO FIX */ + return cpu_ppc_load_tbl(env) & 0x3FFFFF80; } - + void cpu_loop(CPUPPCState *env) { target_siginfo_t info; diff --git a/monitor.c b/monitor.c index 43ebe01f3..de0783bf9 100644 --- a/monitor.c +++ b/monitor.c @@ -331,6 +331,17 @@ static void do_info_history (void) } } +#if defined(TARGET_PPC) +/* XXX: not implemented in other targets */ +static void do_info_cpu_stats (void) +{ + CPUState *env; + + env = mon_get_cpu(); + cpu_dump_statistics(env, NULL, &monitor_fprintf, 0); +} +#endif + static void do_quit(void) { exit(0); @@ -1303,6 +1314,10 @@ static term_cmd_t info_cmds[] = { "", "show which guest mouse is receiving events" }, { "vnc", "", do_info_vnc, "", "show the vnc server status"}, +#if defined(TARGET_PPC) + { "cpustats", "", do_info_cpu_stats, + "", "show CPU statistics", }, +#endif { NULL, NULL, }, }; diff --git a/target-ppc/STATUS b/target-ppc/STATUS new file mode 100644 index 000000000..d5089f766 --- /dev/null +++ b/target-ppc/STATUS @@ -0,0 +1,91 @@ +PowerPC emulation status. +The goal of this file is to provide a reference status to avoid regressions. + +=============================================================================== +PowerPC core emulation status + +PowerPC CPU known to work (ie booting at least Linux 2.4): +* main stream PowerPC cores +- PowerPC 603 & derivatives +- PowerPC 604 & derivatives +- PowerPC 740 & derivatives +- PowerPC 750 & derivatives + +PowerPC that should work but are not supported by standard Linux kernel +(then remain mostly untested) +- PowerPC 745 +- PowerPC 755 + +Work in progress: +* embedded PowerPC cores +- PowerPC 405 +- BookE PowerPC +- e500 core (Freescale PowerQUICC) +* main stream PowerPC cores +- PowerPC 601 +- PowerPC 602 + +TODO: +* embedded PowerPC cores +- PowerPC 401 +- PowerPC 403 +- PowerPC 440 +- PowerPC 460 +* main stream PowerPC cores +- PowerPC 7400 (aka G4) +- PowerPC 7410 +- PowerPC 7450 +- PowerPC 7455 +- PowerPC 7457 +- PowerPC 7457A +* original POWER +- POWER +- POWER2 +* 64 bits PowerPC cores +- PowerPC 620 +- PowerPC 630 (aka POWER3) +- PowerPC 631 (aka POWER3+) +- POWER4 +- POWER4+ +- POWER5 +- POWER5+ +- PowerPC 970 +* RS64 series +- RS64 +- RS64-II +- RS64-III +- RS64-IV + +=============================================================================== +PowerPC microcontrollers emulation status + +TODO: +- PowerPC 40x microcontrollers emulation +- PowerQUICC microcontrollers emulation + +=============================================================================== +PowerPC based platforms emulation status + +* PREP platform (RS/6000 7043...) - TO BE CHECKED (broken) +- Gentoo Linux live CDROM 1.4 +- Debian Linux 3.0 +- Mandrake Linux 9 + +* heathrow PowerMac platform (beige PowerMac) - TO BE CHECKED (broken) +- Gentoo Linux live CDROM 1.4 +- Debian Linux 3.0 +- Mandrake Linux 9 + +* mac99 platform (white and blue PowerMac, ...) +- Gentoo Linux live CDROM 1.4 - boots, compiles linux kernel +- Debian Linux woody - boots from CDROM and HDD +- Mandrake Linux 9 - boots from CDROM, freezes during install + +TODO: +- MCA based RS/6000 emulation +- CHRP emulation (not PowerMac) +- PPAR emulation +- misc PowerPC reference boards emulation + +=============================================================================== +(to be completed) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b294e3146..8abb32492 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1,7 +1,7 @@ /* * PowerPC emulation cpu definitions for qemu. * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,8 +21,22 @@ #define __CPU_PPC_H__ #include "config.h" +#include +#if defined (TARGET_PPC64) +typedef uint64_t ppc_gpr_t; +#define TARGET_LONG_BITS 64 +#define REGX "%016" PRIx64 +#elif defined(TARGET_E500) +/* GPR are 64 bits: used by vector extension */ +typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 32 +#define REGX "%08" PRIx32 +#else +typedef uint32_t ppc_gpr_t; +#define TARGET_LONG_BITS 32 +#define REGX "%08" PRIx32 +#endif #include "cpu-defs.h" @@ -32,7 +46,11 @@ #define TARGET_HAS_ICE 1 -#define ELF_MACHINE EM_PPC +#if defined (TARGET_PPC64) +#define ELF_MACHINE EM_PPC64 +#else +#define ELF_MACHINE EM_PPC +#endif /* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC * have different cache line sizes @@ -42,6 +60,7 @@ /* XXX: put this in a common place */ #define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) /*****************************************************************************/ /* PVR definitions for most known PowerPC */ @@ -54,72 +73,155 @@ enum { CPU_PPC_401E2 = 0x00250000, CPU_PPC_401F2 = 0x00260000, CPU_PPC_401G2 = 0x00270000, - CPU_PPC_IOP480 = 0x40100000, +#define CPU_PPC_401 CPU_PPC_401G2 + CPU_PPC_IOP480 = 0x40100000, /* 401B2 ? */ + CPU_PPC_COBRA = 0x10100000, /* IBM Processor for Network Resources */ /* PowerPC 403 cores */ - CPU_PPC_403GA = 0x00200000, + CPU_PPC_403GA = 0x00200011, CPU_PPC_403GB = 0x00200100, CPU_PPC_403GC = 0x00200200, CPU_PPC_403GCX = 0x00201400, +#define CPU_PPC_403 CPU_PPC_403GCX /* PowerPC 405 cores */ - CPU_PPC_405 = 0x40110000, - CPU_PPC_405EP = 0x51210000, - CPU_PPC_405GPR = 0x50910000, + CPU_PPC_405CR = 0x40110145, +#define CPU_PPC_405GP CPU_PPC_405CR + CPU_PPC_405EP = 0x51210950, + CPU_PPC_405GPR = 0x50910951, CPU_PPC_405D2 = 0x20010000, CPU_PPC_405D4 = 0x41810000, - CPU_PPC_NPE405H = 0x41410000, - CPU_PPC_NPE405L = 0x41610000, +#define CPU_PPC_405 CPU_PPC_405D4 + CPU_PPC_NPE405H = 0x414100C0, + CPU_PPC_NPE405H2 = 0x41410140, + CPU_PPC_NPE405L = 0x416100C0, + /* XXX: missing 405LP, LC77700 */ + /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */ +#if 0 + CPU_PPC_STB01000 = xxx, +#endif #if 0 - CPU_PPC_STB02 = xxx, + CPU_PPC_STB01010 = xxx, +#endif +#if 0 + CPU_PPC_STB0210 = xxx, #endif CPU_PPC_STB03 = 0x40310000, #if 0 - CPU_PPC_STB04 = xxx, + CPU_PPC_STB043 = xxx, #endif - CPU_PPC_STB25 = 0x51510000, +#if 0 + CPU_PPC_STB045 = xxx, +#endif + CPU_PPC_STB25 = 0x51510950, #if 0 CPU_PPC_STB130 = xxx, #endif + /* Xilinx cores */ + CPU_PPC_X2VP4 = 0x20010820, +#define CPU_PPC_X2VP7 CPU_PPC_X2VP4 + CPU_PPC_X2VP20 = 0x20010860, +#define CPU_PPC_X2VP50 CPU_PPC_X2VP20 /* PowerPC 440 cores */ - CPU_PPC_440EP = 0x42220000, - CPU_PPC_440GP = 0x40120400, - CPU_PPC_440GX = 0x51B20000, - /* PowerPC MPC 8xx cores */ - CPU_PPC_8540 = 0x80200000, + CPU_PPC_440EP = 0x422218D3, +#define CPU_PPC_440GR CPU_PPC_440EP + CPU_PPC_440GP = 0x40120481, + CPU_PPC_440GX = 0x51B21850, + CPU_PPC_440GXc = 0x51B21892, + CPU_PPC_440GXf = 0x51B21894, + CPU_PPC_440SP = 0x53221850, + CPU_PPC_440SP2 = 0x53221891, + CPU_PPC_440SPE = 0x53421890, + /* XXX: missing 440GRX */ + /* PowerPC 460 cores - TODO */ + /* PowerPC MPC 5xx cores */ + CPU_PPC_5xx = 0x00020020, + /* PowerPC MPC 8xx cores (aka PowerQUICC) */ CPU_PPC_8xx = 0x00500000, - CPU_PPC_8240 = 0x00810100, - CPU_PPC_8245 = 0x00811014, + /* PowerPC MPC 8xxx cores (aka PowerQUICC-II) */ + CPU_PPC_82xx_HIP3 = 0x00810101, + CPU_PPC_82xx_HIP4 = 0x80811014, + CPU_PPC_827x = 0x80822013, + /* eCores */ + CPU_PPC_e200 = 0x81120000, + CPU_PPC_e500v110 = 0x80200010, + CPU_PPC_e500v120 = 0x80200020, + CPU_PPC_e500v210 = 0x80210010, + CPU_PPC_e500v220 = 0x80210020, +#define CPU_PPC_e500 CPU_PPC_e500v220 + CPU_PPC_e600 = 0x80040010, /* PowerPC 6xx cores */ - CPU_PPC_601 = 0x00010000, - CPU_PPC_602 = 0x00050000, - CPU_PPC_603 = 0x00030000, - CPU_PPC_603E = 0x00060000, - CPU_PPC_603EV = 0x00070000, - CPU_PPC_603R = 0x00071000, - CPU_PPC_G2 = 0x80810000, - CPU_PPC_G2LE = 0x80820000, + CPU_PPC_601 = 0x00010001, + CPU_PPC_602 = 0x00050100, + CPU_PPC_603 = 0x00030100, + CPU_PPC_603E = 0x00060101, + CPU_PPC_603P = 0x00070000, + CPU_PPC_603E7v = 0x00070100, + CPU_PPC_603E7v2 = 0x00070201, + CPU_PPC_603E7 = 0x00070200, + CPU_PPC_603R = 0x00071201, + CPU_PPC_G2 = 0x00810011, + CPU_PPC_G2H4 = 0x80811010, + CPU_PPC_G2gp = 0x80821010, + CPU_PPC_G2ls = 0x90810010, + CPU_PPC_G2LE = 0x80820010, + CPU_PPC_G2LEgp = 0x80822010, + CPU_PPC_G2LEls = 0xA0822010, CPU_PPC_604 = 0x00040000, - CPU_PPC_604E = 0x00090000, - CPU_PPC_604R = 0x000a0000, + CPU_PPC_604E = 0x00090100, /* Also 2110 & 2120 */ + CPU_PPC_604R = 0x000a0101, /* PowerPC 74x/75x cores (aka G3) */ CPU_PPC_74x = 0x00080000, - CPU_PPC_755 = 0x00083000, + CPU_PPC_740E = 0x00080100, + CPU_PPC_750E = 0x00080200, + CPU_PPC_755_10 = 0x00083100, + CPU_PPC_755_11 = 0x00083101, + CPU_PPC_755_20 = 0x00083200, + CPU_PPC_755D = 0x00083202, + CPU_PPC_755E = 0x00083203, +#define CPU_PPC_755 CPU_PPC_755E CPU_PPC_74xP = 0x10080000, - CPU_PPC_750CXE22 = 0x00082202, + CPU_PPC_750CXE21 = 0x00082201, + CPU_PPC_750CXE22 = 0x00082212, + CPU_PPC_750CXE23 = 0x00082203, CPU_PPC_750CXE24 = 0x00082214, CPU_PPC_750CXE24b = 0x00083214, CPU_PPC_750CXE31 = 0x00083211, CPU_PPC_750CXE31b = 0x00083311, #define CPU_PPC_750CXE CPU_PPC_750CXE31b - CPU_PPC_750FX = 0x70000000, - CPU_PPC_750GX = 0x70020000, + CPU_PPC_750CXR = 0x00083410, + CPU_PPC_750FX10 = 0x70000100, + CPU_PPC_750FX20 = 0x70000200, + CPU_PPC_750FX21 = 0x70000201, + CPU_PPC_750FX22 = 0x70000202, + CPU_PPC_750FX23 = 0x70000203, +#define CPU_PPC_750FX CPU_PPC_750FX23 + CPU_PPC_750FL = 0x700A0203, + CPU_PPC_750GX10 = 0x70020100, + CPU_PPC_750GX11 = 0x70020101, + CPU_PPC_750GX12 = 0x70020102, +#define CPU_PPC_750GX CPU_PPC_750GX12 + CPU_PPC_750GL = 0x70020102, + CPU_PPC_750L30 = 0x00088300, + CPU_PPC_750L32 = 0x00088302, + CPU_PPC_750CL = 0x00087200, /* PowerPC 74xx cores (aka G4) */ - CPU_PPC_7400 = 0x000C0000, - CPU_PPC_7410 = 0x800C0000, - CPU_PPC_7441 = 0x80000200, - CPU_PPC_7450 = 0x80000000, + CPU_PPC_7400 = 0x000C0100, + CPU_PPC_7410C = 0x800C1102, + CPU_PPC_7410D = 0x800C1103, + CPU_PPC_7410E = 0x800C1104, + CPU_PPC_7441 = 0x80000210, + CPU_PPC_7445 = 0x80010100, + CPU_PPC_7447 = 0x80020100, + CPU_PPC_7447A = 0x80030101, + CPU_PPC_7448 = 0x80040100, + CPU_PPC_7450 = 0x80000200, + CPU_PPC_7450b = 0x80000201, CPU_PPC_7451 = 0x80000203, - CPU_PPC_7455 = 0x80010000, - CPU_PPC_7457 = 0x80020000, + CPU_PPC_7451G = 0x80000210, + CPU_PPC_7455 = 0x80010201, + CPU_PPC_7455F = 0x80010303, + CPU_PPC_7455G = 0x80010304, + CPU_PPC_7457 = 0x80020101, + CPU_PPC_7457C = 0x80020102, CPU_PPC_7457A = 0x80030000, /* 64 bits PowerPC */ CPU_PPC_620 = 0x00140000, @@ -130,7 +232,21 @@ enum { CPU_PPC_POWER5 = 0x003A0000, CPU_PPC_POWER5P = 0x003B0000, CPU_PPC_970 = 0x00390000, - CPU_PPC_970FX = 0x003C0000, + CPU_PPC_970FX10 = 0x00391100, + CPU_PPC_970FX20 = 0x003C0200, + CPU_PPC_970FX21 = 0x003C0201, + CPU_PPC_970FX30 = 0x003C0300, + CPU_PPC_970FX31 = 0x003C0301, +#define CPU_PPC_970FX CPU_PPC_970FX31 + CPU_PPC_970MP10 = 0x00440100, + CPU_PPC_970MP11 = 0x00440101, +#define CPU_PPC_970MP CPU_PPC_970MP11 + CPU_PPC_CELL10 = 0x00700100, + CPU_PPC_CELL20 = 0x00700400, + CPU_PPC_CELL30 = 0x00700500, + CPU_PPC_CELL31 = 0x00700501, +#define CPU_PPC_CELL32 CPU_PPC_CELL31 +#define CPU_PPC_CELL CPU_PPC_CELL32 CPU_PPC_RS64 = 0x00330000, CPU_PPC_RS64II = 0x00340000, CPU_PPC_RS64III = 0x00360000, @@ -147,12 +263,28 @@ enum { #endif }; -/* System version register (used on MPC 8xx) */ +/* System version register (used on MPC 8xxx) */ enum { PPC_SVR_8540 = 0x80300000, - PPC_SVR_8541E = 0x807A0000, - PPC_SVR_8555E = 0x80790000, - PPC_SVR_8560 = 0x80700000, + PPC_SVR_8541E = 0x807A0010, + PPC_SVR_8543v10 = 0x80320010, + PPC_SVR_8543v11 = 0x80320011, + PPC_SVR_8543v20 = 0x80320020, + PPC_SVR_8543Ev10 = 0x803A0010, + PPC_SVR_8543Ev11 = 0x803A0011, + PPC_SVR_8543Ev20 = 0x803A0020, + PPC_SVR_8545 = 0x80310220, + PPC_SVR_8545E = 0x80390220, + PPC_SVR_8547E = 0x80390120, + PPC_SCR_8548v10 = 0x80310010, + PPC_SCR_8548v11 = 0x80310011, + PPC_SCR_8548v20 = 0x80310020, + PPC_SVR_8548Ev10 = 0x80390010, + PPC_SVR_8548Ev11 = 0x80390011, + PPC_SVR_8548Ev20 = 0x80390020, + PPC_SVR_8555E = 0x80790010, + PPC_SVR_8560v10 = 0x80700010, + PPC_SVR_8560v20 = 0x80700020, }; /*****************************************************************************/ @@ -197,7 +329,7 @@ enum { /* Time base support */ PPC_TB = 0x00002000, /* Embedded PowerPC dedicated instructions */ - PPC_4xx_COMMON = 0x00004000, + PPC_EMB_COMMON = 0x00004000, /* PowerPC 40x exception model */ PPC_40x_EXCP = 0x00008000, /* PowerPC 40x specific instructions */ @@ -225,12 +357,20 @@ enum { PPC_64H = 0x02000000, /* 64 bits PowerPC "bridge" features */ PPC_64_BRIDGE = 0x04000000, + /* BookE (embedded) PowerPC specification */ + PPC_BOOKE = 0x08000000, + /* eieio */ + PPC_MEM_EIEIO = 0x10000000, + /* e500 vector instructions */ + PPC_E500_VECTOR = 0x20000000, + /* PowerPC 4xx dedicated instructions */ + PPC_4xx_COMMON = 0x40000000, }; /* CPU run-time flags (MMU and exception model) */ enum { /* MMU model */ -#define PPC_FLAGS_MMU_MASK (0x0000000F) + PPC_FLAGS_MMU_MASK = 0x0000000F, /* Standard 32 bits PowerPC MMU */ PPC_FLAGS_MMU_32B = 0x00000000, /* Standard 64 bits PowerPC MMU */ @@ -243,8 +383,10 @@ enum { PPC_FLAGS_MMU_SOFT_4xx = 0x00000004, /* PowerPC 403 MMU */ PPC_FLAGS_MMU_403 = 0x00000005, + /* Freescale e500 MMU model */ + PPC_FLAGS_MMU_e500 = 0x00000006, /* Exception model */ -#define PPC_FLAGS_EXCP_MASK (0x000000F0) + PPC_FLAGS_EXCP_MASK = 0x000000F0, /* Standard PowerPC exception model */ PPC_FLAGS_EXCP_STD = 0x00000000, /* PowerPC 40x exception model */ @@ -277,32 +419,42 @@ enum { #define PPC_FLAGS_TODO (0x00000000) /* PowerPC 40x instruction set */ -#define PPC_INSNS_4xx (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_4xx_COMMON) +#define PPC_INSNS_EMB (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_EMB_COMMON) /* PowerPC 401 */ #define PPC_INSNS_401 (PPC_INSNS_TODO) #define PPC_FLAGS_401 (PPC_FLAGS_TODO) /* PowerPC 403 */ -#define PPC_INSNS_403 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_MEM_TLBIA | \ - PPC_40x_EXCP | PPC_40x_SPEC) +#define PPC_INSNS_403 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIA | PPC_4xx_COMMON | PPC_40x_EXCP | \ + PPC_40x_SPEC) #define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x) /* PowerPC 405 */ -#define PPC_INSNS_405 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_CACHE_OPT | \ - PPC_MEM_TLBIA | PPC_TB | PPC_40x_SPEC | PPC_40x_EXCP | \ +#define PPC_INSNS_405 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_CACHE_OPT | PPC_MEM_TLBIA | PPC_TB | \ + PPC_4xx_COMMON | PPC_40x_SPEC | PPC_40x_EXCP | \ PPC_405_MAC) #define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x) /* PowerPC 440 */ -#define PPC_INSNS_440 (PPC_INSNS_4xx | PPC_CACHE_OPT | PPC_405_MAC | \ - PPC_440_SPEC) +#define PPC_INSNS_440 (PPC_INSNS_EMB | PPC_CACHE_OPT | PPC_BOOKE | \ + PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) #define PPC_FLAGS_440 (PPC_FLAGS_TODO) +/* Generic BookE PowerPC */ +#define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \ + PPC_FLOAT | PPC_FLOAT_OPT | PPC_CACHE_OPT) +#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x) +/* e500 core */ +#define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \ + PPC_CACHE_OPT | PPC_E500_VECTOR) +#define PPC_FLAGS_E500 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x) /* Non-embedded PowerPC */ #define PPC_INSNS_COMMON (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \ - PPC_SEGMENT | PPC_MEM_TLBIE) + PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE) /* PowerPC 601 */ #define PPC_INSNS_601 (PPC_INSNS_COMMON | PPC_EXTERN | PPC_POWER_BR) #define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601) /* PowerPC 602 */ #define PPC_INSNS_602 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ - PPC_MEM_TLBSYNC | PPC_TB) + PPC_MEM_TLBSYNC | PPC_TB | PPC_602_SPEC) #define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602) /* PowerPC 603 */ #define PPC_INSNS_603 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ @@ -348,13 +500,17 @@ typedef struct ppc_tb_t ppc_tb_t; typedef struct ppc_spr_t ppc_spr_t; typedef struct ppc_dcr_t ppc_dcr_t; typedef struct ppc_avr_t ppc_avr_t; +typedef struct ppc_tlb_t ppc_tlb_t; + /* SPR access micro-ops generations callbacks */ struct ppc_spr_t { void (*uea_read)(void *opaque, int spr_num); void (*uea_write)(void *opaque, int spr_num); +#if !defined(CONFIG_USER_ONLY) void (*oea_read)(void *opaque, int spr_num); void (*oea_write)(void *opaque, int spr_num); +#endif const unsigned char *name; }; @@ -364,46 +520,42 @@ struct ppc_avr_t { }; /* Software TLB cache */ -typedef struct ppc_tlb_t ppc_tlb_t; struct ppc_tlb_t { - /* Physical page number */ - target_phys_addr_t RPN; - /* Virtual page number */ - target_ulong VPN; - /* Page size */ - target_ulong size; - /* Protection bits */ - int prot; - int is_user; - uint32_t private; - uint32_t flags; + target_ulong pte0; + target_ulong pte1; + target_ulong EPN; + target_ulong PID; + int size; }; /*****************************************************************************/ /* Machine state register bits definition */ -#define MSR_SF 63 /* Sixty-four-bit mode */ +#define MSR_SF 63 /* Sixty-four-bit mode hflags */ #define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */ -#define MSR_HV 60 /* hypervisor state */ -#define MSR_VR 25 /* altivec available */ -#define MSR_AP 23 /* Access privilege state on 602 */ -#define MSR_SA 22 /* Supervisor access mode on 602 */ +#define MSR_HV 60 /* hypervisor state hflags */ +#define MSR_UCLE 26 /* User-mode cache lock enable on e500 */ +#define MSR_VR 25 /* altivec available hflags */ +#define MSR_SPE 25 /* SPE enable on e500 hflags */ +#define MSR_AP 23 /* Access privilege state on 602 hflags */ +#define MSR_SA 22 /* Supervisor access mode on 602 hflags */ #define MSR_KEY 19 /* key bit on 603e */ #define MSR_POW 18 /* Power management */ #define MSR_WE 18 /* Wait state enable on embedded PowerPC */ #define MSR_TGPR 17 /* TGPR usage on 602/603 */ -#define MSR_TLB 17 /* TLB on ? */ +#define MSR_TLB 17 /* TLB update on ? */ #define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC */ #define MSR_ILE 16 /* Interrupt little-endian mode */ #define MSR_EE 15 /* External interrupt enable */ -#define MSR_PR 14 /* Problem state */ -#define MSR_FP 13 /* Floating point available */ +#define MSR_PR 14 /* Problem state hflags */ +#define MSR_FP 13 /* Floating point available hflags */ #define MSR_ME 12 /* Machine check interrupt enable */ -#define MSR_FE0 11 /* Floating point exception mode 0 */ -#define MSR_SE 10 /* Single-step trace enable */ +#define MSR_FE0 11 /* Floating point exception mode 0 hflags */ +#define MSR_SE 10 /* Single-step trace enable hflags */ #define MSR_DWE 10 /* Debug wait enable on 405 */ -#define MSR_BE 9 /* Branch trace enable */ +#define MSR_UBLE 10 /* User BTB lock enable on e500 */ +#define MSR_BE 9 /* Branch trace enable hflags */ #define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC */ -#define MSR_FE1 8 /* Floating point exception mode 1 */ +#define MSR_FE1 8 /* Floating point exception mode 1 hflags */ #define MSR_AL 7 /* AL bit on POWER */ #define MSR_IP 6 /* Interrupt prefix */ #define MSR_IR 5 /* Instruction relocate */ @@ -415,42 +567,45 @@ struct ppc_tlb_t { #define MSR_PX 2 /* Protection exclusive on 403 */ #define MSR_PMM 2 /* Performance monitor mark on POWER */ #define MSR_RI 1 /* Recoverable interrupt */ -#define MSR_LE 0 /* Little-endian mode */ +#define MSR_LE 0 /* Little-endian mode hflags */ #define msr_sf env->msr[MSR_SF] #define msr_isf env->msr[MSR_ISF] #define msr_hv env->msr[MSR_HV] +#define msr_ucle env->msr[MSR_UCLE] #define msr_vr env->msr[MSR_VR] +#define msr_spe env->msr[MSR_SPE] #define msr_ap env->msr[MSR_AP] #define msr_sa env->msr[MSR_SA] #define msr_key env->msr[MSR_KEY] -#define msr_pow env->msr[MSR_POW] +#define msr_pow env->msr[MSR_POW] #define msr_we env->msr[MSR_WE] #define msr_tgpr env->msr[MSR_TGPR] #define msr_tlb env->msr[MSR_TLB] #define msr_ce env->msr[MSR_CE] -#define msr_ile env->msr[MSR_ILE] -#define msr_ee env->msr[MSR_EE] -#define msr_pr env->msr[MSR_PR] -#define msr_fp env->msr[MSR_FP] -#define msr_me env->msr[MSR_ME] -#define msr_fe0 env->msr[MSR_FE0] -#define msr_se env->msr[MSR_SE] +#define msr_ile env->msr[MSR_ILE] +#define msr_ee env->msr[MSR_EE] +#define msr_pr env->msr[MSR_PR] +#define msr_fp env->msr[MSR_FP] +#define msr_me env->msr[MSR_ME] +#define msr_fe0 env->msr[MSR_FE0] +#define msr_se env->msr[MSR_SE] #define msr_dwe env->msr[MSR_DWE] -#define msr_be env->msr[MSR_BE] +#define msr_uble env->msr[MSR_UBLE] +#define msr_be env->msr[MSR_BE] #define msr_de env->msr[MSR_DE] -#define msr_fe1 env->msr[MSR_FE1] +#define msr_fe1 env->msr[MSR_FE1] #define msr_al env->msr[MSR_AL] -#define msr_ip env->msr[MSR_IP] -#define msr_ir env->msr[MSR_IR] +#define msr_ip env->msr[MSR_IP] +#define msr_ir env->msr[MSR_IR] #define msr_is env->msr[MSR_IS] -#define msr_dr env->msr[MSR_DR] +#define msr_dr env->msr[MSR_DR] #define msr_ds env->msr[MSR_DS] #define msr_pe env->msr[MSR_PE] #define msr_ep env->msr[MSR_EP] #define msr_px env->msr[MSR_PX] #define msr_pmm env->msr[MSR_PMM] -#define msr_ri env->msr[MSR_RI] -#define msr_le env->msr[MSR_LE] +#define msr_ri env->msr[MSR_RI] +#define msr_le env->msr[MSR_LE] /*****************************************************************************/ /* The whole PowerPC CPU context */ @@ -465,7 +620,7 @@ struct CPUPPCState { target_ulong t0, t1, t2; #endif /* general purpose registers */ - target_ulong gpr[32]; + ppc_gpr_t gpr[32]; /* LR */ target_ulong lr; /* CTR */ @@ -482,10 +637,10 @@ struct CPUPPCState { /* machine state register */ uint8_t msr[64]; /* temporary general purpose registers */ - target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */ + ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */ /* Floating point execution context */ - /* temporary float registers */ + /* temporary float registers */ float64 ft0; float64 ft1; float64 ft2; @@ -529,9 +684,12 @@ struct CPUPPCState { ppc_dcr_t *dcr_env; /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */ - int nb_tlb; - int nb_ways, last_way; - ppc_tlb_t tlb[128]; + int nb_tlb; /* Total number of TLB */ + int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */ + int nb_ways; /* Number of ways in the TLB set */ + int last_way; /* Last used way used to allocate TLB in a LRU way */ + int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ + ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ /* Callbacks for specific checks on some implementations */ int (*tlb_check_more)(CPUPPCState *env, struct ppc_tlb_t *tlb, int *prot, target_ulong vaddr, int rw, int acc_type, @@ -568,6 +726,16 @@ struct CPUPPCState { int (*osi_call)(struct CPUPPCState *env); }; +/* Context used internally during MMU translations */ +typedef struct mmu_ctx_t mmu_ctx_t; +struct mmu_ctx_t { + target_phys_addr_t raddr; /* Real address */ + int prot; /* Protection bits */ + target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */ + target_ulong ptem; /* Virtual segment ID | API */ + int key; /* Access key */ +}; + /*****************************************************************************/ CPUPPCState *cpu_ppc_init(void); int cpu_ppc_exec(CPUPPCState *s); @@ -583,6 +751,7 @@ void cpu_loop_exit(void); void dump_stack (CPUPPCState *env); +#if !defined(CONFIG_USER_ONLY) target_ulong do_load_ibatu (CPUPPCState *env, int nr); target_ulong do_load_ibatl (CPUPPCState *env, int nr); void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value); @@ -591,23 +760,17 @@ target_ulong do_load_dbatu (CPUPPCState *env, int nr); target_ulong do_load_dbatl (CPUPPCState *env, int nr); void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value); void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value); - -target_ulong do_load_nip (CPUPPCState *env); -void do_store_nip (CPUPPCState *env, target_ulong value); target_ulong do_load_sdr1 (CPUPPCState *env); void do_store_sdr1 (CPUPPCState *env, target_ulong value); target_ulong do_load_asr (CPUPPCState *env); void do_store_asr (CPUPPCState *env, target_ulong value); target_ulong do_load_sr (CPUPPCState *env, int srnum); void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); -uint32_t do_load_cr (CPUPPCState *env); -void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask); -uint32_t do_load_xer (CPUPPCState *env); -void do_store_xer (CPUPPCState *env, uint32_t value); +#endif +uint32_t ppc_load_xer (CPUPPCState *env); +void ppc_store_xer (CPUPPCState *env, uint32_t value); target_ulong do_load_msr (CPUPPCState *env); void do_store_msr (CPUPPCState *env, target_ulong value); -float64 do_load_fpscr (CPUPPCState *env); -void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask); void do_compute_hflags (CPUPPCState *env); @@ -645,261 +808,294 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); #define xer_bc env->xer[0] /* SPR definitions */ -#define SPR_MQ (0x000) -#define SPR_XER (0x001) -#define SPR_601_VRTCU (0x004) -#define SPR_601_VRTCL (0x005) -#define SPR_601_UDECR (0x006) -#define SPR_LR (0x008) -#define SPR_CTR (0x009) -#define SPR_DSISR (0x012) -#define SPR_DAR (0x013) -#define SPR_601_RTCU (0x014) -#define SPR_601_RTCL (0x015) -#define SPR_DECR (0x016) -#define SPR_SDR1 (0x019) -#define SPR_SRR0 (0x01A) -#define SPR_SRR1 (0x01B) -#define SPR_440_PID (0x030) -#define SPR_440_DECAR (0x036) -#define SPR_CSRR0 (0x03A) -#define SPR_CSRR1 (0x03B) -#define SPR_440_DEAR (0x03D) -#define SPR_440_ESR (0x03E) -#define SPR_440_IVPR (0x03F) -#define SPR_8xx_EIE (0x050) -#define SPR_8xx_EID (0x051) -#define SPR_8xx_NRE (0x052) -#define SPR_58x_CMPA (0x090) -#define SPR_58x_CMPB (0x091) -#define SPR_58x_CMPC (0x092) -#define SPR_58x_CMPD (0x093) -#define SPR_58x_ICR (0x094) -#define SPR_58x_DER (0x094) -#define SPR_58x_COUNTA (0x096) -#define SPR_58x_COUNTB (0x097) -#define SPR_58x_CMPE (0x098) -#define SPR_58x_CMPF (0x099) -#define SPR_58x_CMPG (0x09A) -#define SPR_58x_CMPH (0x09B) -#define SPR_58x_LCTRL1 (0x09C) -#define SPR_58x_LCTRL2 (0x09D) -#define SPR_58x_ICTRL (0x09E) -#define SPR_58x_BAR (0x09F) -#define SPR_VRSAVE (0x100) -#define SPR_USPRG0 (0x100) -#define SPR_USPRG4 (0x104) -#define SPR_USPRG5 (0x105) -#define SPR_USPRG6 (0x106) -#define SPR_USPRG7 (0x107) -#define SPR_VTBL (0x10C) -#define SPR_VTBU (0x10D) -#define SPR_SPRG0 (0x110) -#define SPR_SPRG1 (0x111) -#define SPR_SPRG2 (0x112) -#define SPR_SPRG3 (0x113) -#define SPR_SPRG4 (0x114) -#define SPR_SCOMC (0x114) -#define SPR_SPRG5 (0x115) -#define SPR_SCOMD (0x115) -#define SPR_SPRG6 (0x116) -#define SPR_SPRG7 (0x117) -#define SPR_ASR (0x118) -#define SPR_EAR (0x11A) -#define SPR_TBL (0x11C) -#define SPR_TBU (0x11D) -#define SPR_SVR (0x11E) -#define SPR_440_PIR (0x11E) -#define SPR_PVR (0x11F) -#define SPR_HSPRG0 (0x130) -#define SPR_440_DBSR (0x130) -#define SPR_HSPRG1 (0x131) -#define SPR_440_DBCR0 (0x134) -#define SPR_IBCR (0x135) -#define SPR_440_DBCR1 (0x135) -#define SPR_DBCR (0x136) -#define SPR_HDEC (0x136) -#define SPR_440_DBCR2 (0x136) -#define SPR_HIOR (0x137) -#define SPR_MBAR (0x137) -#define SPR_RMOR (0x138) -#define SPR_440_IAC1 (0x138) -#define SPR_HRMOR (0x139) -#define SPR_440_IAC2 (0x139) -#define SPR_HSSR0 (0x13A) -#define SPR_440_IAC3 (0x13A) -#define SPR_HSSR1 (0x13B) -#define SPR_440_IAC4 (0x13B) -#define SPR_LPCR (0x13C) -#define SPR_440_DAC1 (0x13C) -#define SPR_LPIDR (0x13D) -#define SPR_DABR2 (0x13D) -#define SPR_440_DAC2 (0x13D) -#define SPR_440_DVC1 (0x13E) -#define SPR_440_DVC2 (0x13F) -#define SPR_440_TSR (0x150) -#define SPR_440_TCR (0x154) -#define SPR_440_IVOR0 (0x190) -#define SPR_440_IVOR1 (0x191) -#define SPR_440_IVOR2 (0x192) -#define SPR_440_IVOR3 (0x193) -#define SPR_440_IVOR4 (0x194) -#define SPR_440_IVOR5 (0x195) -#define SPR_440_IVOR6 (0x196) -#define SPR_440_IVOR7 (0x197) -#define SPR_440_IVOR8 (0x198) -#define SPR_440_IVOR9 (0x199) -#define SPR_440_IVOR10 (0x19A) -#define SPR_440_IVOR11 (0x19B) -#define SPR_440_IVOR12 (0x19C) -#define SPR_440_IVOR13 (0x19D) -#define SPR_440_IVOR14 (0x19E) -#define SPR_440_IVOR15 (0x19F) -#define SPR_IBAT0U (0x210) -#define SPR_IBAT0L (0x211) -#define SPR_IBAT1U (0x212) -#define SPR_IBAT1L (0x213) -#define SPR_IBAT2U (0x214) -#define SPR_IBAT2L (0x215) -#define SPR_IBAT3U (0x216) -#define SPR_IBAT3L (0x217) -#define SPR_DBAT0U (0x218) -#define SPR_DBAT0L (0x219) -#define SPR_DBAT1U (0x21A) -#define SPR_DBAT1L (0x21B) -#define SPR_DBAT2U (0x21C) -#define SPR_DBAT2L (0x21D) -#define SPR_DBAT3U (0x21E) -#define SPR_DBAT3L (0x21F) -#define SPR_IBAT4U (0x230) -#define SPR_IBAT4L (0x231) -#define SPR_IBAT5U (0x232) -#define SPR_IBAT5L (0x233) -#define SPR_IBAT6U (0x234) -#define SPR_IBAT6L (0x235) -#define SPR_IBAT7U (0x236) -#define SPR_IBAT7L (0x237) -#define SPR_DBAT4U (0x238) -#define SPR_DBAT4L (0x239) -#define SPR_DBAT5U (0x23A) -#define SPR_DBAT5L (0x23B) -#define SPR_DBAT6U (0x23C) -#define SPR_DBAT6L (0x23D) -#define SPR_DBAT7U (0x23E) -#define SPR_DBAT7L (0x23F) -#define SPR_440_INV0 (0x370) -#define SPR_440_INV1 (0x371) -#define SPR_440_INV2 (0x372) -#define SPR_440_INV3 (0x373) -#define SPR_440_IVT0 (0x374) -#define SPR_440_IVT1 (0x375) -#define SPR_440_IVT2 (0x376) -#define SPR_440_IVT3 (0x377) -#define SPR_440_DNV0 (0x390) -#define SPR_440_DNV1 (0x391) -#define SPR_440_DNV2 (0x392) -#define SPR_440_DNV3 (0x393) -#define SPR_440_DVT0 (0x394) -#define SPR_440_DVT1 (0x395) -#define SPR_440_DVT2 (0x396) -#define SPR_440_DVT3 (0x397) -#define SPR_440_DVLIM (0x398) -#define SPR_440_IVLIM (0x399) -#define SPR_440_RSTCFG (0x39B) -#define SPR_440_DCBTRL (0x39C) -#define SPR_440_DCBTRH (0x39D) -#define SPR_440_ICBTRL (0x39E) -#define SPR_440_ICBTRH (0x39F) -#define SPR_UMMCR0 (0x3A8) -#define SPR_UPMC1 (0x3A9) -#define SPR_UPMC2 (0x3AA) -#define SPR_USIA (0x3AB) -#define SPR_UMMCR1 (0x3AC) -#define SPR_UPMC3 (0x3AD) -#define SPR_UPMC4 (0x3AE) -#define SPR_USDA (0x3AF) -#define SPR_40x_ZPR (0x3B0) -#define SPR_40x_PID (0x3B1) -#define SPR_440_MMUCR (0x3B2) -#define SPR_4xx_CCR0 (0x3B3) -#define SPR_405_IAC3 (0x3B4) -#define SPR_405_IAC4 (0x3B5) -#define SPR_405_DVC1 (0x3B6) -#define SPR_405_DVC2 (0x3B7) -#define SPR_MMCR0 (0x3B8) -#define SPR_PMC1 (0x3B9) -#define SPR_40x_SGR (0x3B9) -#define SPR_PMC2 (0x3BA) -#define SPR_40x_DCWR (0x3BA) -#define SPR_SIA (0x3BB) -#define SPR_405_SLER (0x3BB) -#define SPR_MMCR1 (0x3BC) -#define SPR_405_SU0R (0x3BC) -#define SPR_PMC3 (0x3BD) -#define SPR_405_DBCR1 (0x3BD) -#define SPR_PMC4 (0x3BE) -#define SPR_SDA (0x3BF) -#define SPR_403_VTBL (0x3CC) -#define SPR_403_VTBU (0x3CD) -#define SPR_DMISS (0x3D0) -#define SPR_DCMP (0x3D1) -#define SPR_DHASH1 (0x3D2) -#define SPR_DHASH2 (0x3D3) -#define SPR_4xx_ICDBDR (0x3D3) -#define SPR_IMISS (0x3D4) -#define SPR_40x_ESR (0x3D4) -#define SPR_ICMP (0x3D5) -#define SPR_40x_DEAR (0x3D5) -#define SPR_RPA (0x3D6) -#define SPR_40x_EVPR (0x3D6) -#define SPR_403_CDBCR (0x3D7) -#define SPR_TCR (0x3D8) -#define SPR_40x_TSR (0x3D8) -#define SPR_IBR (0x3DA) -#define SPR_40x_TCR (0x3DA) -#define SPR_ESASR (0x3DB) -#define SPR_40x_PIT (0x3DB) -#define SPR_403_TBL (0x3DC) -#define SPR_403_TBU (0x3DD) -#define SPR_SEBR (0x3DE) -#define SPR_40x_SRR2 (0x3DE) -#define SPR_SER (0x3DF) -#define SPR_40x_SRR3 (0x3DF) -#define SPR_HID0 (0x3F0) -#define SPR_40x_DBSR (0x3F0) -#define SPR_HID1 (0x3F1) -#define SPR_IABR (0x3F2) -#define SPR_40x_DBCR0 (0x3F2) -#define SPR_601_HID2 (0x3F2) -#define SPR_HID2 (0x3F3) -#define SPR_440_DBDR (0x3F3) -#define SPR_40x_IAC1 (0x3F4) -#define SPR_DABR (0x3F5) +#define SPR_MQ (0x000) +#define SPR_XER (0x001) +#define SPR_601_VRTCU (0x004) +#define SPR_601_VRTCL (0x005) +#define SPR_601_UDECR (0x006) +#define SPR_LR (0x008) +#define SPR_CTR (0x009) +#define SPR_DSISR (0x012) +#define SPR_DAR (0x013) +#define SPR_601_RTCU (0x014) +#define SPR_601_RTCL (0x015) +#define SPR_DECR (0x016) +#define SPR_SDR1 (0x019) +#define SPR_SRR0 (0x01A) +#define SPR_SRR1 (0x01B) +#define SPR_BOOKE_PID (0x030) +#define SPR_BOOKE_DECAR (0x036) +#define SPR_CSRR0 (0x03A) +#define SPR_CSRR1 (0x03B) +#define SPR_BOOKE_DEAR (0x03D) +#define SPR_BOOKE_ESR (0x03E) +#define SPR_BOOKE_EVPR (0x03F) +#define SPR_8xx_EIE (0x050) +#define SPR_8xx_EID (0x051) +#define SPR_8xx_NRE (0x052) +#define SPR_58x_CMPA (0x090) +#define SPR_58x_CMPB (0x091) +#define SPR_58x_CMPC (0x092) +#define SPR_58x_CMPD (0x093) +#define SPR_58x_ICR (0x094) +#define SPR_58x_DER (0x094) +#define SPR_58x_COUNTA (0x096) +#define SPR_58x_COUNTB (0x097) +#define SPR_58x_CMPE (0x098) +#define SPR_58x_CMPF (0x099) +#define SPR_58x_CMPG (0x09A) +#define SPR_58x_CMPH (0x09B) +#define SPR_58x_LCTRL1 (0x09C) +#define SPR_58x_LCTRL2 (0x09D) +#define SPR_58x_ICTRL (0x09E) +#define SPR_58x_BAR (0x09F) +#define SPR_VRSAVE (0x100) +#define SPR_USPRG0 (0x100) +#define SPR_USPRG4 (0x104) +#define SPR_USPRG5 (0x105) +#define SPR_USPRG6 (0x106) +#define SPR_USPRG7 (0x107) +#define SPR_VTBL (0x10C) +#define SPR_VTBU (0x10D) +#define SPR_SPRG0 (0x110) +#define SPR_SPRG1 (0x111) +#define SPR_SPRG2 (0x112) +#define SPR_SPRG3 (0x113) +#define SPR_SPRG4 (0x114) +#define SPR_SCOMC (0x114) +#define SPR_SPRG5 (0x115) +#define SPR_SCOMD (0x115) +#define SPR_SPRG6 (0x116) +#define SPR_SPRG7 (0x117) +#define SPR_ASR (0x118) +#define SPR_EAR (0x11A) +#define SPR_TBL (0x11C) +#define SPR_TBU (0x11D) +#define SPR_SVR (0x11E) +#define SPR_BOOKE_PIR (0x11E) +#define SPR_PVR (0x11F) +#define SPR_HSPRG0 (0x130) +#define SPR_BOOKE_DBSR (0x130) +#define SPR_HSPRG1 (0x131) +#define SPR_BOOKE_DBCR0 (0x134) +#define SPR_IBCR (0x135) +#define SPR_BOOKE_DBCR1 (0x135) +#define SPR_DBCR (0x136) +#define SPR_HDEC (0x136) +#define SPR_BOOKE_DBCR2 (0x136) +#define SPR_HIOR (0x137) +#define SPR_MBAR (0x137) +#define SPR_RMOR (0x138) +#define SPR_BOOKE_IAC1 (0x138) +#define SPR_HRMOR (0x139) +#define SPR_BOOKE_IAC2 (0x139) +#define SPR_HSSR0 (0x13A) +#define SPR_BOOKE_IAC3 (0x13A) +#define SPR_HSSR1 (0x13B) +#define SPR_BOOKE_IAC4 (0x13B) +#define SPR_LPCR (0x13C) +#define SPR_BOOKE_DAC1 (0x13C) +#define SPR_LPIDR (0x13D) +#define SPR_DABR2 (0x13D) +#define SPR_BOOKE_DAC2 (0x13D) +#define SPR_BOOKE_DVC1 (0x13E) +#define SPR_BOOKE_DVC2 (0x13F) +#define SPR_BOOKE_TSR (0x150) +#define SPR_BOOKE_TCR (0x154) +#define SPR_BOOKE_IVOR0 (0x190) +#define SPR_BOOKE_IVOR1 (0x191) +#define SPR_BOOKE_IVOR2 (0x192) +#define SPR_BOOKE_IVOR3 (0x193) +#define SPR_BOOKE_IVOR4 (0x194) +#define SPR_BOOKE_IVOR5 (0x195) +#define SPR_BOOKE_IVOR6 (0x196) +#define SPR_BOOKE_IVOR7 (0x197) +#define SPR_BOOKE_IVOR8 (0x198) +#define SPR_BOOKE_IVOR9 (0x199) +#define SPR_BOOKE_IVOR10 (0x19A) +#define SPR_BOOKE_IVOR11 (0x19B) +#define SPR_BOOKE_IVOR12 (0x19C) +#define SPR_BOOKE_IVOR13 (0x19D) +#define SPR_BOOKE_IVOR14 (0x19E) +#define SPR_BOOKE_IVOR15 (0x19F) +#define SPR_E500_SPEFSCR (0x200) +#define SPR_E500_BBEAR (0x201) +#define SPR_E500_BBTAR (0x202) +#define SPR_BOOKE_ATBL (0x20E) +#define SPR_BOOKE_ATBU (0x20F) +#define SPR_IBAT0U (0x210) +#define SPR_E500_IVOR32 (0x210) +#define SPR_IBAT0L (0x211) +#define SPR_E500_IVOR33 (0x211) +#define SPR_IBAT1U (0x212) +#define SPR_E500_IVOR34 (0x212) +#define SPR_IBAT1L (0x213) +#define SPR_E500_IVOR35 (0x213) +#define SPR_IBAT2U (0x214) +#define SPR_IBAT2L (0x215) +#define SPR_E500_L1CFG0 (0x215) +#define SPR_IBAT3U (0x216) +#define SPR_E500_L1CFG1 (0x216) +#define SPR_IBAT3L (0x217) +#define SPR_DBAT0U (0x218) +#define SPR_DBAT0L (0x219) +#define SPR_DBAT1U (0x21A) +#define SPR_DBAT1L (0x21B) +#define SPR_DBAT2U (0x21C) +#define SPR_DBAT2L (0x21D) +#define SPR_DBAT3U (0x21E) +#define SPR_DBAT3L (0x21F) +#define SPR_IBAT4U (0x230) +#define SPR_IBAT4L (0x231) +#define SPR_IBAT5U (0x232) +#define SPR_IBAT5L (0x233) +#define SPR_IBAT6U (0x234) +#define SPR_IBAT6L (0x235) +#define SPR_IBAT7U (0x236) +#define SPR_IBAT7L (0x237) +#define SPR_DBAT4U (0x238) +#define SPR_DBAT4L (0x239) +#define SPR_DBAT5U (0x23A) +#define SPR_E500_MCSRR0 (0x23A) +#define SPR_DBAT5L (0x23B) +#define SPR_E500_MCSRR1 (0x23B) +#define SPR_DBAT6U (0x23C) +#define SPR_E500_MCSR (0x23C) +#define SPR_DBAT6L (0x23D) +#define SPR_E500_MCAR (0x23D) +#define SPR_DBAT7U (0x23E) +#define SPR_DBAT7L (0x23F) +#define SPR_E500_MAS0 (0x270) +#define SPR_E500_MAS1 (0x271) +#define SPR_E500_MAS2 (0x272) +#define SPR_E500_MAS3 (0x273) +#define SPR_E500_MAS4 (0x274) +#define SPR_E500_MAS6 (0x276) +#define SPR_E500_PID1 (0x279) +#define SPR_E500_PID2 (0x27A) +#define SPR_E500_TLB0CFG (0x2B0) +#define SPR_E500_TLB1CFG (0x2B1) +#define SPR_440_INV0 (0x370) +#define SPR_440_INV1 (0x371) +#define SPR_440_INV2 (0x372) +#define SPR_440_INV3 (0x373) +#define SPR_440_IVT0 (0x374) +#define SPR_440_IVT1 (0x375) +#define SPR_440_IVT2 (0x376) +#define SPR_440_IVT3 (0x377) +#define SPR_440_DNV0 (0x390) +#define SPR_440_DNV1 (0x391) +#define SPR_440_DNV2 (0x392) +#define SPR_440_DNV3 (0x393) +#define SPR_440_DVT0 (0x394) +#define SPR_440_DVT1 (0x395) +#define SPR_440_DVT2 (0x396) +#define SPR_440_DVT3 (0x397) +#define SPR_440_DVLIM (0x398) +#define SPR_440_IVLIM (0x399) +#define SPR_440_RSTCFG (0x39B) +#define SPR_440_DCBTRL (0x39C) +#define SPR_440_DCBTRH (0x39D) +#define SPR_440_ICBTRL (0x39E) +#define SPR_440_ICBTRH (0x39F) +#define SPR_UMMCR0 (0x3A8) +#define SPR_UPMC1 (0x3A9) +#define SPR_UPMC2 (0x3AA) +#define SPR_USIA (0x3AB) +#define SPR_UMMCR1 (0x3AC) +#define SPR_UPMC3 (0x3AD) +#define SPR_UPMC4 (0x3AE) +#define SPR_USDA (0x3AF) +#define SPR_40x_ZPR (0x3B0) +#define SPR_E500_MAS7 (0x3B0) +#define SPR_40x_PID (0x3B1) +#define SPR_440_MMUCR (0x3B2) +#define SPR_4xx_CCR0 (0x3B3) +#define SPR_405_IAC3 (0x3B4) +#define SPR_405_IAC4 (0x3B5) +#define SPR_405_DVC1 (0x3B6) +#define SPR_405_DVC2 (0x3B7) +#define SPR_MMCR0 (0x3B8) +#define SPR_PMC1 (0x3B9) +#define SPR_40x_SGR (0x3B9) +#define SPR_PMC2 (0x3BA) +#define SPR_40x_DCWR (0x3BA) +#define SPR_SIA (0x3BB) +#define SPR_405_SLER (0x3BB) +#define SPR_MMCR1 (0x3BC) +#define SPR_405_SU0R (0x3BC) +#define SPR_PMC3 (0x3BD) +#define SPR_405_DBCR1 (0x3BD) +#define SPR_PMC4 (0x3BE) +#define SPR_SDA (0x3BF) +#define SPR_403_VTBL (0x3CC) +#define SPR_403_VTBU (0x3CD) +#define SPR_DMISS (0x3D0) +#define SPR_DCMP (0x3D1) +#define SPR_HASH1 (0x3D2) +#define SPR_HASH2 (0x3D3) +#define SPR_4xx_ICDBDR (0x3D3) +#define SPR_IMISS (0x3D4) +#define SPR_40x_ESR (0x3D4) +#define SPR_ICMP (0x3D5) +#define SPR_40x_DEAR (0x3D5) +#define SPR_RPA (0x3D6) +#define SPR_40x_EVPR (0x3D6) +#define SPR_403_CDBCR (0x3D7) +#define SPR_TCR (0x3D8) +#define SPR_40x_TSR (0x3D8) +#define SPR_IBR (0x3DA) +#define SPR_40x_TCR (0x3DA) +#define SPR_ESASR (0x3DB) +#define SPR_40x_PIT (0x3DB) +#define SPR_403_TBL (0x3DC) +#define SPR_403_TBU (0x3DD) +#define SPR_SEBR (0x3DE) +#define SPR_40x_SRR2 (0x3DE) +#define SPR_SER (0x3DF) +#define SPR_40x_SRR3 (0x3DF) +#define SPR_HID0 (0x3F0) +#define SPR_40x_DBSR (0x3F0) +#define SPR_HID1 (0x3F1) +#define SPR_IABR (0x3F2) +#define SPR_40x_DBCR0 (0x3F2) +#define SPR_601_HID2 (0x3F2) +#define SPR_E500_L1CSR0 (0x3F2) +#define SPR_HID2 (0x3F3) +#define SPR_E500_L1CSR1 (0x3F3) +#define SPR_440_DBDR (0x3F3) +#define SPR_40x_IAC1 (0x3F4) +#define SPR_E500_MMUCSR0 (0x3F4) +#define SPR_DABR (0x3F5) #define DABR_MASK (~(target_ulong)0x7) -#define SPR_40x_IAC2 (0x3F5) -#define SPR_601_HID5 (0x3F5) -#define SPR_40x_DAC1 (0x3F6) -#define SPR_40x_DAC2 (0x3F7) -#define SPR_L2PM (0x3F8) -#define SPR_750_HID2 (0x3F8) -#define SPR_L2CR (0x3F9) -#define SPR_IABR2 (0x3FA) -#define SPR_40x_DCCR (0x3FA) -#define SPR_ICTC (0x3FB) -#define SPR_40x_ICCR (0x3FB) -#define SPR_THRM1 (0x3FC) -#define SPR_403_PBL1 (0x3FC) -#define SPR_SP (0x3FD) -#define SPR_THRM2 (0x3FD) -#define SPR_403_PBU1 (0x3FD) -#define SPR_LT (0x3FE) -#define SPR_THRM3 (0x3FE) -#define SPR_FPECR (0x3FE) -#define SPR_403_PBL2 (0x3FE) -#define SPR_PIR (0x3FF) -#define SPR_403_PBU2 (0x3FF) -#define SPR_601_HID15 (0x3FF) +#define SPR_E500_BUCSR (0x3F5) +#define SPR_40x_IAC2 (0x3F5) +#define SPR_601_HID5 (0x3F5) +#define SPR_40x_DAC1 (0x3F6) +#define SPR_40x_DAC2 (0x3F7) +#define SPR_E500_MMUCFG (0x3F7) +#define SPR_L2PM (0x3F8) +#define SPR_750_HID2 (0x3F8) +#define SPR_L2CR (0x3F9) +#define SPR_IABR2 (0x3FA) +#define SPR_40x_DCCR (0x3FA) +#define SPR_ICTC (0x3FB) +#define SPR_40x_ICCR (0x3FB) +#define SPR_THRM1 (0x3FC) +#define SPR_403_PBL1 (0x3FC) +#define SPR_SP (0x3FD) +#define SPR_THRM2 (0x3FD) +#define SPR_403_PBU1 (0x3FD) +#define SPR_LT (0x3FE) +#define SPR_THRM3 (0x3FE) +#define SPR_FPECR (0x3FE) +#define SPR_403_PBL2 (0x3FE) +#define SPR_PIR (0x3FF) +#define SPR_403_PBU2 (0x3FF) +#define SPR_601_HID15 (0x3FF) +#define SPR_E500_SVR (0x3FF) +/*****************************************************************************/ /* Memory access type : * may be needed for precise access rights control and precise exceptions. */ @@ -977,7 +1173,7 @@ enum { #define EXCP_PPC_MAX 0x4000 /* Qemu exceptions: special cases we want to stop translation */ #define EXCP_MTMSR 0x11000 /* mtmsr instruction: */ - /* may change privilege level */ + /* may change privilege level */ #define EXCP_BRANCH 0x11001 /* branch instruction */ #define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */ #define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 89171f9d3..25e060fb6 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -1,7 +1,7 @@ /* * PowerPC emulation definitions for qemu. * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,15 +24,34 @@ #include "dyngen-exec.h" -#define TARGET_LONG_BITS 32 +#include "cpu.h" +#include "exec-all.h" register struct CPUPPCState *env asm(AREG0); -register uint32_t T0 asm(AREG1); -register uint32_t T1 asm(AREG2); -register uint32_t T2 asm(AREG3); +#if TARGET_LONG_BITS > HOST_LONG_BITS +/* no registers can be used */ +#define T0 (env->t0) +#define T1 (env->t1) +#define T2 (env->t2) +#else +/* This may be more efficient if HOST_LONG_BITS > TARGET_LONG_BITS + * To be set to one when we'll be sure it does not cause bugs.... + */ +#if 0 +register unsigned long T0 asm(AREG1); +register unsigned long T1 asm(AREG2); +register unsigned long T2 asm(AREG3); +#else +register target_ulong T0 asm(AREG1); +register target_ulong T1 asm(AREG2); +register target_ulong T2 asm(AREG3); +#endif +#endif +/* XXX: to clean: remove this mess */ #define PARAM(n) ((uint32_t)PARAM##n) #define SPARAM(n) ((int32_t)PARAM##n) + #define FT0 (env->ft0) #define FT1 (env->ft1) #define FT2 (env->ft2) @@ -43,14 +62,28 @@ register uint32_t T2 asm(AREG3); # define RETURN() __asm__ __volatile__("" : : : "memory"); #endif -#include "cpu.h" -#include "exec-all.h" +static inline target_ulong rotl8 (target_ulong i, int n) +{ + return (((uint8_t)i << n) | ((uint8_t)i >> (8 - n))); +} + +static inline target_ulong rotl16 (target_ulong i, int n) +{ + return (((uint16_t)i << n) | ((uint16_t)i >> (16 - n))); +} -static inline uint32_t rotl (uint32_t i, int n) +static inline target_ulong rotl32 (target_ulong i, int n) { - return ((i << n) | (i >> (32 - n))); + return (((uint32_t)i << n) | ((uint32_t)i >> (32 - n))); } +#if defined(TARGET_PPC64) +static inline target_ulong rotl64 (target_ulong i, int n) +{ + return (((uint64_t)i << n) | ((uint64_t)i >> (64 - n))); +} +#endif + #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ @@ -58,23 +91,14 @@ static inline uint32_t rotl (uint32_t i, int n) void do_raise_exception_err (uint32_t exception, int error_code); void do_raise_exception (uint32_t exception); -void do_sraw(void); - -void do_fctiw (void); -void do_fctiwz (void); -void do_fnmadd (void); -void do_fnmsub (void); -void do_fsqrt (void); -void do_fres (void); -void do_frsqrte (void); -void do_fsel (void); -void do_fcmpu (void); -void do_fcmpo (void); +int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr, + int rw, int access_type, int check_BATs); -void do_check_reservation (void); -void do_icbi (void); -void do_tlbia (void); -void do_tlbie (void); +void ppc6xx_tlb_invalidate_all (CPUState *env); +void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, + int is_code); +void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, + target_ulong pte0, target_ulong pte1); static inline void env_to_regs(void) { @@ -84,7 +108,7 @@ static inline void regs_to_env(void) { } -int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, +int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); #endif /* !defined (__PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 70b0a4915..f4f692d5e 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1,7 +1,7 @@ /* * PowerPC emulation helpers for qemu. * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,6 +30,7 @@ //#define DEBUG_MMU //#define DEBUG_BATS +//#define DEBUG_SOFTWARE_TLB //#define DEBUG_EXCEPTIONS //#define FLUSH_ALL_TLBS @@ -55,26 +56,307 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, } env->exception_index = exception; env->error_code = error_code; + return 1; } -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) + +target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { return addr; } #else +/* Common routines used by software and hardware TLBs emulation */ +static inline int pte_is_valid (target_ulong pte0) +{ + return pte0 & 0x80000000 ? 1 : 0; +} + +static inline void pte_invalidate (target_ulong *pte0) +{ + *pte0 &= ~0x80000000; +} + +#define PTE_PTEM_MASK 0x7FFFFFBF +#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) + +static int pte_check (mmu_ctx_t *ctx, + target_ulong pte0, target_ulong pte1, int h, int rw) +{ + int access, ret; + + access = 0; + ret = -1; + /* Check validity and table match */ + if (pte_is_valid(pte0) && (h == ((pte0 >> 6) & 1))) { + /* Check vsid & api */ + if ((pte0 & PTE_PTEM_MASK) == ctx->ptem) { + if (ctx->raddr != (target_ulong)-1) { + /* all matches should have equal RPN, WIMG & PP */ + if ((ctx->raddr & PTE_CHECK_MASK) != (pte1 & PTE_CHECK_MASK)) { + if (loglevel > 0) + fprintf(logfile, "Bad RPN/WIMG/PP\n"); + return -3; + } + } + /* Compute access rights */ + if (ctx->key == 0) { + access = PAGE_READ; + if ((pte1 & 0x00000003) != 0x3) + access |= PAGE_WRITE; + } else { + switch (pte1 & 0x00000003) { + case 0x0: + access = 0; + break; + case 0x1: + case 0x3: + access = PAGE_READ; + break; + case 0x2: + access = PAGE_READ | PAGE_WRITE; + break; + } + } + /* Keep the matching PTE informations */ + ctx->raddr = pte1; + ctx->prot = access; + if ((rw == 0 && (access & PAGE_READ)) || + (rw == 1 && (access & PAGE_WRITE))) { + /* Access granted */ +#if defined (DEBUG_MMU) + if (loglevel > 0) + fprintf(logfile, "PTE access granted !\n"); +#endif + ret = 0; + } else { + /* Access right violation */ +#if defined (DEBUG_MMU) + if (loglevel > 0) + fprintf(logfile, "PTE access rejected\n"); +#endif + ret = -2; + } + } + } + + return ret; +} + +static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p, + int ret, int rw) +{ + int store = 0; + + /* Update page flags */ + if (!(*pte1p & 0x00000100)) { + /* Update accessed flag */ + *pte1p |= 0x00000100; + store = 1; + } + if (!(*pte1p & 0x00000080)) { + if (rw == 1 && ret == 0) { + /* Update changed flag */ + *pte1p |= 0x00000080; + store = 1; + } else { + /* Force page fault for first write access */ + ctx->prot &= ~PAGE_WRITE; + } + } + + return store; +} + +/* Software driven TLB helpers */ +static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr, + int way, int is_code) +{ + int nr; + + /* Select TLB num in a way from address */ + nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1); + /* Select TLB way */ + nr += env->tlb_per_way * way; + /* 6xx have separate TLBs for instructions and data */ + if (is_code && env->id_tlbs == 1) + nr += env->nb_tlb; + + return nr; +} + +void ppc6xx_tlb_invalidate_all (CPUState *env) +{ + ppc_tlb_t *tlb; + int nr, max; + +#if defined (DEBUG_SOFTWARE_TLB) && 0 + if (loglevel != 0) { + fprintf(logfile, "Invalidate all TLBs\n"); + } +#endif + /* Invalidate all defined software TLB */ + max = env->nb_tlb; + if (env->id_tlbs == 1) + max *= 2; + for (nr = 0; nr < max; nr++) { + tlb = &env->tlb[nr]; +#if !defined(FLUSH_ALL_TLBS) + tlb_flush_page(env, tlb->EPN); +#endif + pte_invalidate(&tlb->pte0); + } +#if defined(FLUSH_ALL_TLBS) + tlb_flush(env, 1); +#endif +} + +static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, + target_ulong eaddr, + int is_code, int match_epn) +{ + ppc_tlb_t *tlb; + int way, nr; + +#if !defined(FLUSH_ALL_TLBS) + /* Invalidate ITLB + DTLB, all ways */ + for (way = 0; way < env->nb_ways; way++) { + nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); + tlb = &env->tlb[nr]; + if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) { +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "TLB invalidate %d/%d %08x\n", + nr, env->nb_tlb, eaddr); + } +#endif + pte_invalidate(&tlb->pte0); + tlb_flush_page(env, tlb->EPN); + } + } +#else + /* XXX: PowerPC specification say this is valid as well */ + ppc6xx_tlb_invalidate_all(env); +#endif +} + +void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, + int is_code) +{ + __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0); +} + +void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, + target_ulong pte0, target_ulong pte1) +{ + ppc_tlb_t *tlb; + int nr; + + nr = ppc6xx_tlb_getnum(env, EPN, way, is_code); + tlb = &env->tlb[nr]; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "Set TLB %d/%d EPN %08lx PTE0 %08lx PTE1 %08lx\n", + nr, env->nb_tlb, (unsigned long)EPN, + (unsigned long)pte0, (unsigned long)pte1); + } +#endif + /* Invalidate any pending reference in Qemu for this virtual address */ + __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1); + tlb->pte0 = pte0; + tlb->pte1 = pte1; + tlb->EPN = EPN; + tlb->PID = 0; + tlb->size = 1; + /* Store last way for LRU mechanism */ + env->last_way = way; +} + +static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int access_type) +{ + ppc_tlb_t *tlb; + int nr, best, way; + int ret; + + best = -1; + ret = -1; /* No TLB found */ + for (way = 0; way < env->nb_ways; way++) { + nr = ppc6xx_tlb_getnum(env, eaddr, way, + access_type == ACCESS_CODE ? 1 : 0); + tlb = &env->tlb[nr]; + /* This test "emulates" the PTE index match for hardware TLBs */ + if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "TLB %d/%d %s [%08x %08x] <> %08x\n", + nr, env->nb_tlb, + pte_is_valid(tlb->pte0) ? "valid" : "inval", + tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr); + } +#endif + continue; + } +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "TLB %d/%d %s %08x <> %08x %08x %c %c\n", + nr, env->nb_tlb, + pte_is_valid(tlb->pte0) ? "valid" : "inval", + tlb->EPN, eaddr, tlb->pte1, + rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); + } +#endif + switch (pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) { + case -3: + /* TLB inconsistency */ + return -1; + case -2: + /* Access violation */ + ret = -2; + best = nr; + break; + case -1: + default: + /* No match */ + break; + case 0: + /* access granted */ + /* XXX: we should go on looping to check all TLBs consistency + * but we can speed-up the whole thing as the + * result would be undefined if TLBs are not consistent. + */ + ret = 0; + best = nr; + goto done; + } + } + if (best != -1) { + done: +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel > 0) { + fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n", + ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); + } +#endif + /* Update page flags */ + pte_update_flags(ctx, &env->tlb[best].pte1, ret, rw); + } + + return ret; +} + /* Perform BAT hit & translation */ -static int get_bat (CPUState *env, uint32_t *real, int *prot, - uint32_t virtual, int rw, int type) +static int get_bat (CPUState *env, mmu_ctx_t *ctx, + target_ulong virtual, int rw, int type) { - uint32_t *BATlt, *BATut, *BATu, *BATl; - uint32_t base, BEPIl, BEPIu, bl; + target_ulong *BATlt, *BATut, *BATu, *BATl; + target_ulong base, BEPIl, BEPIu, bl; int i; int ret = -1; #if defined (DEBUG_BATS) if (loglevel > 0) { fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); + type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif switch (type) { @@ -90,7 +372,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, #if defined (DEBUG_BATS) if (loglevel > 0) { fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); + type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif base = virtual & 0xFFFC0000; @@ -113,18 +395,18 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, if ((msr_pr == 0 && (*BATu & 0x00000002)) || (msr_pr == 1 && (*BATu & 0x00000001))) { /* Get physical address */ - *real = (*BATl & 0xF0000000) | + ctx->raddr = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | (virtual & 0x0001F000); if (*BATl & 0x00000001) - *prot = PAGE_READ; + ctx->prot = PAGE_READ; if (*BATl & 0x00000002) - *prot = PAGE_WRITE | PAGE_READ; + ctx->prot = PAGE_WRITE | PAGE_READ; #if defined (DEBUG_BATS) if (loglevel > 0) { fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", - i, *real, *prot & PAGE_READ ? 'R' : '-', - *prot & PAGE_WRITE ? 'W' : '-'); + i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', + ctx->prot & PAGE_WRITE ? 'W' : '-'); } #endif ret = 0; @@ -153,189 +435,154 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, } /* PTE table lookup */ -static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, - int h, int key, int rw) +static int find_pte (mmu_ctx_t *ctx, int h, int rw) { - uint32_t pte0, pte1, keep = 0, access = 0; - int i, good = -1, store = 0; - int ret = -1; /* No entry found */ + target_ulong base, pte0, pte1; + int i, good = -1; + int ret; + ret = -1; /* No entry found */ + base = ctx->pg_addr[h]; for (i = 0; i < 8; i++) { pte0 = ldl_phys(base + (i * 8)); pte1 = ldl_phys(base + (i * 8) + 4); #if defined (DEBUG_MMU) if (loglevel > 0) { - fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " - "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, - pte0 >> 31, h, (pte0 >> 6) & 1, va); - } -#endif - /* Check validity and table match */ - if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) { - /* Check vsid & api */ - if ((pte0 & 0x7FFFFFBF) == va) { - if (good == -1) { - good = i; - keep = pte1; - } else { - /* All matches should have equal RPN, WIMG & PP */ - if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) { - if (loglevel > 0) - fprintf(logfile, "Bad RPN/WIMG/PP\n"); - return -1; - } - } - /* Check access rights */ - if (key == 0) { - access = PAGE_READ; - if ((pte1 & 0x00000003) != 0x3) - access |= PAGE_WRITE; - } else { - switch (pte1 & 0x00000003) { - case 0x0: - access = 0; - break; - case 0x1: - case 0x3: - access = PAGE_READ; - break; - case 0x2: - access = PAGE_READ | PAGE_WRITE; - break; - } - } - if (ret < 0) { - if ((rw == 0 && (access & PAGE_READ)) || - (rw == 1 && (access & PAGE_WRITE))) { -#if defined (DEBUG_MMU) - if (loglevel > 0) - fprintf(logfile, "PTE access granted !\n"); -#endif - good = i; - keep = pte1; - ret = 0; - } else { - /* Access right violation */ - ret = -2; -#if defined (DEBUG_MMU) - if (loglevel > 0) - fprintf(logfile, "PTE access rejected\n"); + fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " + "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, + pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem); + } #endif - } - *prot = access; - } - } + switch (pte_check(ctx, pte0, pte1, h, rw)) { + case -3: + /* PTE inconsistency */ + return -1; + case -2: + /* Access violation */ + ret = -2; + good = i; + break; + case -1: + default: + /* No PTE match */ + break; + case 0: + /* access granted */ + /* XXX: we should go on looping to check all PTEs consistency + * but if we can speed-up the whole thing as the + * result would be undefined if PTEs are not consistent. + */ + ret = 0; + good = i; + goto done; } } if (good != -1) { - *RPN = keep & 0xFFFFF000; + done: #if defined (DEBUG_MMU) if (loglevel > 0) { - fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", - *RPN, *prot, ret); - } + fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", + ctx->raddr, ctx->prot, ret); + } #endif /* Update page flags */ - if (!(keep & 0x00000100)) { - /* Access flag */ - keep |= 0x00000100; - store = 1; - } - if (!(keep & 0x00000080)) { - if (rw && ret == 0) { - /* Change flag */ - keep |= 0x00000080; - store = 1; - } else { - /* Force page fault for first write access */ - *prot &= ~PAGE_WRITE; - } - } - if (store) { - stl_phys_notdirty(base + (good * 8) + 4, keep); - } + pte1 = ctx->raddr; + if (pte_update_flags(ctx, &pte1, ret, rw) == 1) + stl_phys_notdirty(base + (good * 8) + 4, pte1); } return ret; } -static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask) +static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, + target_phys_addr_t hash, + target_phys_addr_t mask) { return (sdr1 & 0xFFFF0000) | (hash & mask); } /* Perform segment based translation */ -static int get_segment (CPUState *env, uint32_t *real, int *prot, - uint32_t virtual, int rw, int type) +static int get_segment (CPUState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int type) { - uint32_t pg_addr, sdr, ptem, vsid, pgidx; - uint32_t hash, mask; - uint32_t sr; - int key; + target_phys_addr_t sdr, hash, mask; + target_ulong sr, vsid, pgidx; int ret = -1, ret2; - sr = env->sr[virtual >> 28]; + sr = env->sr[eaddr >> 28]; #if defined (DEBUG_MMU) if (loglevel > 0) { - fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x " - "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n", - virtual, virtual >> 28, sr, env->nip, - env->lr, msr_ir, msr_dr, msr_pr, rw, type); + fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x " + "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n", + eaddr, eaddr >> 28, sr, env->nip, + env->lr, msr_ir, msr_dr, msr_pr, rw, type); } #endif - key = (((sr & 0x20000000) && msr_pr == 1) || - ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; + ctx->key = (((sr & 0x20000000) && msr_pr == 1) || + ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; if ((sr & 0x80000000) == 0) { #if defined (DEBUG_MMU) - if (loglevel > 0) - fprintf(logfile, "pte segment: key=%d n=0x%08x\n", - key, sr & 0x10000000); + if (loglevel > 0) + fprintf(logfile, "pte segment: key=%d n=0x%08x\n", + ctx->key, sr & 0x10000000); #endif /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { /* Page address translation */ + pgidx = (eaddr >> TARGET_PAGE_BITS) & 0xFFFF; vsid = sr & 0x00FFFFFF; - pgidx = (virtual >> 12) & 0xFFFF; - sdr = env->sdr1; hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6; + /* Primary table address */ + sdr = env->sdr1; mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; - pg_addr = get_pgaddr(sdr, hash, mask); - ptem = (vsid << 7) | (pgidx >> 10); + ctx->pg_addr[0] = get_pgaddr(sdr, hash, mask); + /* Secondary table address */ + hash = (~hash) & 0x01FFFFC0; + ctx->pg_addr[1] = get_pgaddr(sdr, hash, mask); + ctx->ptem = (vsid << 7) | (pgidx >> 10); + /* Initialize real address with an invalid value */ + ctx->raddr = (target_ulong)-1; + if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + /* Software TLB search */ + ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); + } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + /* XXX: TODO */ + } else { #if defined (DEBUG_MMU) - if (loglevel > 0) { - fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x " - "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, - pg_addr); - } + if (loglevel > 0) { + fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x " + "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, + hash, ctx->pg_addr[0]); + } #endif - /* Primary table lookup */ - ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw); - if (ret < 0) { - /* Secondary table lookup */ - hash = (~hash) & 0x01FFFFC0; - pg_addr = get_pgaddr(sdr, hash, mask); + /* Primary table lookup */ + ret = find_pte(ctx, 0, rw); + if (ret < 0) { + /* Secondary table lookup */ #if defined (DEBUG_MMU) - if (virtual != 0xEFFFFFFF && loglevel > 0) { - fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x " - "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx, - hash, pg_addr); - } + if (eaddr != 0xEFFFFFFF && loglevel > 0) { + fprintf(logfile, + "1 sdr1=0x%08x vsid=0x%06x api=0x%04x " + "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, + pgidx, hash, ctx->pg_addr[1]); + } #endif - ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw); - if (ret2 != -1) - ret = ret2; + ret2 = find_pte(ctx, 1, rw); + if (ret2 != -1) + ret = ret2; + } } } else { #if defined (DEBUG_MMU) - if (loglevel > 0) - fprintf(logfile, "No access allowed\n"); + if (loglevel > 0) + fprintf(logfile, "No access allowed\n"); #endif - ret = -3; + ret = -3; } } else { #if defined (DEBUG_MMU) if (loglevel > 0) - fprintf(logfile, "direct store...\n"); + fprintf(logfile, "direct store...\n"); #endif /* Direct-store segment : absolutely *BUGGY* for now */ switch (type) { @@ -356,7 +603,7 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, /* Should make the instruction do no-op. * As it already do no-op, it's quite easy :-) */ - *real = virtual; + ctx->raddr = eaddr; return 0; case ACCESS_EXT: /* eciwx or ecowx */ @@ -370,8 +617,8 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, "address translation\n"); return -4; } - if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) { - *real = virtual; + if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) { + ctx->raddr = eaddr; ret = 2; } else { ret = -2; @@ -381,8 +628,44 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, return ret; } -static int get_physical_address (CPUState *env, uint32_t *physical, int *prot, - uint32_t address, int rw, int access_type) +static int check_physical (CPUState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw) +{ + int in_plb, ret; + + ctx->raddr = eaddr; + ctx->prot = PAGE_READ; + ret = 0; + if (unlikely(msr_pe != 0 && PPC_MMU(env) == PPC_FLAGS_MMU_403)) { + /* 403 family add some particular protections, + * using PBL/PBU registers for accesses with no translation. + */ + in_plb = + /* Check PLB validity */ + (env->pb[0] < env->pb[1] && + /* and address in plb area */ + eaddr >= env->pb[0] && eaddr < env->pb[1]) || + (env->pb[2] < env->pb[3] && + eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0; + if (in_plb ^ msr_px) { + /* Access in protected area */ + if (rw == 1) { + /* Access is not allowed */ + ret = -2; + } + } else { + /* Read-write access is allowed */ + ctx->prot |= PAGE_WRITE; + } + } else { + ctx->prot |= PAGE_WRITE; + } + + return ret; +} + +int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, + int rw, int access_type, int check_BATs) { int ret; #if 0 @@ -393,46 +676,46 @@ static int get_physical_address (CPUState *env, uint32_t *physical, int *prot, if ((access_type == ACCESS_CODE && msr_ir == 0) || (access_type != ACCESS_CODE && msr_dr == 0)) { /* No address translation */ - *physical = address & ~0xFFF; - *prot = PAGE_READ | PAGE_WRITE; - ret = 0; + ret = check_physical(env, ctx, eaddr, rw); } else { /* Try to find a BAT */ - ret = get_bat(env, physical, prot, address, rw, access_type); + ret = -1; + if (check_BATs) + ret = get_bat(env, ctx, eaddr, rw, access_type); if (ret < 0) { /* We didn't match any BAT entry */ - ret = get_segment(env, physical, prot, address, rw, access_type); + ret = get_segment(env, ctx, eaddr, rw, access_type); } } #if 0 if (loglevel > 0) { - fprintf(logfile, "%s address %08x => %08x\n", - __func__, address, *physical); + fprintf(logfile, "%s address %08x => %08lx\n", + __func__, eaddr, ctx->raddr); } -#endif +#endif + return ret; } -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { - uint32_t phys_addr; - int prot; + mmu_ctx_t ctx; - if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0) + if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0)) return -1; - return phys_addr; + + return ctx.raddr & TARGET_PAGE_MASK; } /* Perform address translation */ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, int is_user, int is_softmmu) { - uint32_t physical; - int prot; + mmu_ctx_t ctx; int exception = 0, error_code = 0; int access_type; int ret = 0; - + if (rw == 2) { /* code access */ rw = 0; @@ -444,35 +727,39 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, access_type = ACCESS_INT; // access_type = env->access_type; } - if (env->user_mode_only) { - /* user mode only emulation */ - ret = -2; - goto do_fault; - } - ret = get_physical_address(env, &physical, &prot, - address, rw, access_type); + ret = get_physical_address(env, &ctx, address, rw, access_type, 1); if (ret == 0) { - ret = tlb_set_page(env, address & ~0xFFF, physical, prot, - is_user, is_softmmu); + ret = tlb_set_page(env, address & TARGET_PAGE_MASK, + ctx.raddr & TARGET_PAGE_MASK, ctx.prot, + is_user, is_softmmu); } else if (ret < 0) { - do_fault: #if defined (DEBUG_MMU) - if (loglevel > 0) - cpu_dump_state(env, logfile, fprintf, 0); + if (loglevel > 0) + cpu_dump_state(env, logfile, fprintf, 0); #endif if (access_type == ACCESS_CODE) { exception = EXCP_ISI; switch (ret) { case -1: - /* No matches in page tables */ - error_code = 0x40000000; + /* No matches in page tables or TLB */ + if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + exception = EXCP_I_TLBMISS; + env->spr[SPR_IMISS] = address; + env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; + error_code = 1 << 18; + goto tlb_miss; + } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + /* XXX: TODO */ + } else { + error_code = 0x40000000; + } break; case -2: /* Access rights violation */ error_code = 0x08000000; break; case -3: - /* No execute protection violation */ + /* No execute protection violation */ error_code = 0x10000000; break; case -4: @@ -490,8 +777,28 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, exception = EXCP_DSI; switch (ret) { case -1: - /* No matches in page tables */ - error_code = 0x40000000; + /* No matches in page tables or TLB */ + if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + if (rw == 1) { + exception = EXCP_DS_TLBMISS; + error_code = 1 << 16; + } else { + exception = EXCP_DL_TLBMISS; + error_code = 0; + } + env->spr[SPR_DMISS] = address; + env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem; + tlb_miss: + error_code |= ctx.key << 19; + env->spr[SPR_HASH1] = ctx.pg_addr[0]; + env->spr[SPR_HASH2] = ctx.pg_addr[1]; + /* Do not alter DAR nor DSISR */ + goto out; + } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + /* XXX: TODO */ + } else { + error_code = 0x40000000; + } break; case -2: /* Access rights violation */ @@ -514,7 +821,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, error_code = 0x04100000; break; default: - printf("DSI: invalid exception (%d)\n", ret); + printf("DSI: invalid exception (%d)\n", ret); exception = EXCP_PROGRAM; error_code = EXCP_INVAL | EXCP_INVAL_INVAL; break; @@ -528,10 +835,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, } if (exception == EXCP_DSI && rw == 1) error_code |= 0x02000000; - /* Store fault address */ - env->spr[SPR_DAR] = address; + /* Store fault address */ + env->spr[SPR_DAR] = address; env->spr[SPR_DSISR] = error_code; } + out: #if 0 printf("%s: set exception to %d %02x\n", __func__, exception, error_code); @@ -540,9 +848,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, env->error_code = error_code; ret = 1; } + return ret; } -#endif /*****************************************************************************/ /* BATs management */ @@ -551,11 +859,14 @@ static inline void do_invalidate_BAT (CPUPPCState *env, target_ulong BATu, target_ulong mask) { target_ulong base, end, page; + base = BATu & ~0x0001FFFF; end = base + mask + 0x00020000; #if defined (DEBUG_BATS) - if (loglevel != 0) - fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", base, end, mask); + if (loglevel != 0) { + fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", + base, end, mask); + } #endif for (page = base; page != end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); @@ -608,8 +919,7 @@ void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value) (env->IBAT[1][nr] & ~0x0001FFFF & ~mask); #if !defined(FLUSH_ALL_TLBS) do_invalidate_BAT(env, env->IBAT[0][nr], mask); -#endif -#if defined(FLUSH_ALL_TLBS) +#else tlb_flush(env, 1); #endif } @@ -663,24 +973,8 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) env->DBAT[1][nr] = value; } -static inline void invalidate_all_tlbs (CPUPPCState *env) -{ - /* XXX: this needs to be completed for sotware driven TLB support */ - tlb_flush(env, 1); -} - /*****************************************************************************/ /* Special registers manipulation */ -target_ulong do_load_nip (CPUPPCState *env) -{ - return env->nip; -} - -void do_store_nip (CPUPPCState *env, target_ulong value) -{ - env->nip = value; -} - target_ulong do_load_sdr1 (CPUPPCState *env) { return env->sdr1; @@ -695,7 +989,7 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value) #endif if (env->sdr1 != value) { env->sdr1 = value; - invalidate_all_tlbs(env); + tlb_flush(env, 1); } } @@ -724,34 +1018,13 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) tlb_flush_page(env, page); } #else - invalidate_all_tlbs(env); + tlb_flush(env, 1); #endif } } +#endif /* !defined (CONFIG_USER_ONLY) */ -uint32_t do_load_cr (CPUPPCState *env) -{ - return (env->crf[0] << 28) | - (env->crf[1] << 24) | - (env->crf[2] << 20) | - (env->crf[3] << 16) | - (env->crf[4] << 12) | - (env->crf[5] << 8) | - (env->crf[6] << 4) | - (env->crf[7] << 0); -} - -void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask) -{ - int i, sh; - - for (i = 0, sh = 7; i < 8; i++, sh --) { - if (mask & (1 << sh)) - env->crf[i] = (value >> (sh * 4)) & 0xFUL; - } -} - -uint32_t do_load_xer (CPUPPCState *env) +uint32_t ppc_load_xer (CPUPPCState *env) { return (xer_so << XER_SO) | (xer_ov << XER_OV) | @@ -760,7 +1033,7 @@ uint32_t do_load_xer (CPUPPCState *env) (xer_cmp << XER_CMP); } -void do_store_xer (CPUPPCState *env, uint32_t value) +void ppc_store_xer (CPUPPCState *env, uint32_t value) { xer_so = (value >> XER_SO) & 0x01; xer_ov = (value >> XER_OV) & 0x01; @@ -769,40 +1042,58 @@ void do_store_xer (CPUPPCState *env, uint32_t value) xer_bc = (value >> XER_BC) & 0x3F; } -target_ulong do_load_msr (CPUPPCState *env) +/* Swap temporary saved registers with GPRs */ +static inline void swap_gpr_tgpr (CPUPPCState *env) { - return (msr_vr << MSR_VR) | - (msr_ap << MSR_AP) | - (msr_sa << MSR_SA) | - (msr_key << MSR_KEY) | - (msr_pow << MSR_POW) | - (msr_tlb << MSR_TLB) | - (msr_ile << MSR_ILE) | - (msr_ee << MSR_EE) | - (msr_pr << MSR_PR) | - (msr_fp << MSR_FP) | - (msr_me << MSR_ME) | - (msr_fe0 << MSR_FE0) | - (msr_se << MSR_SE) | - (msr_be << MSR_BE) | - (msr_fe1 << MSR_FE1) | - (msr_al << MSR_AL) | - (msr_ip << MSR_IP) | - (msr_ir << MSR_IR) | - (msr_dr << MSR_DR) | - (msr_pe << MSR_PE) | - (msr_px << MSR_PX) | - (msr_ri << MSR_RI) | - (msr_le << MSR_LE); + ppc_gpr_t tmp; + + tmp = env->gpr[0]; + env->gpr[0] = env->tgpr[0]; + env->tgpr[0] = tmp; + tmp = env->gpr[1]; + env->gpr[1] = env->tgpr[1]; + env->tgpr[1] = tmp; + tmp = env->gpr[2]; + env->gpr[2] = env->tgpr[2]; + env->tgpr[2] = tmp; + tmp = env->gpr[3]; + env->gpr[3] = env->tgpr[3]; + env->tgpr[3] = tmp; } -void do_compute_hflags (CPUPPCState *env) +/* GDBstub can read and write MSR... */ +target_ulong do_load_msr (CPUPPCState *env) { - /* Compute current hflags */ - env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) | - (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) | - (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | - (msr_se << MSR_SE) | (msr_be << MSR_BE); + return +#if defined (TARGET_PPC64) + (msr_sf << MSR_SF) | + (msr_isf << MSR_ISF) | + (msr_hv << MSR_HV) | +#endif + (msr_ucle << MSR_UCLE) | + (msr_vr << MSR_VR) | /* VR / SPE */ + (msr_ap << MSR_AP) | + (msr_sa << MSR_SA) | + (msr_key << MSR_KEY) | + (msr_pow << MSR_POW) | /* POW / WE */ + (msr_tlb << MSR_TLB) | /* TLB / TGPE / CE */ + (msr_ile << MSR_ILE) | + (msr_ee << MSR_EE) | + (msr_pr << MSR_PR) | + (msr_fp << MSR_FP) | + (msr_me << MSR_ME) | + (msr_fe0 << MSR_FE0) | + (msr_se << MSR_SE) | /* SE / DWE / UBLE */ + (msr_be << MSR_BE) | /* BE / DE */ + (msr_fe1 << MSR_FE1) | + (msr_al << MSR_AL) | + (msr_ip << MSR_IP) | + (msr_ir << MSR_IR) | /* IR / IS */ + (msr_dr << MSR_DR) | /* DR / DS */ + (msr_pe << MSR_PE) | /* PE / EP */ + (msr_px << MSR_PX) | /* PX / PMM */ + (msr_ri << MSR_RI) | + (msr_le << MSR_LE); } void do_store_msr (CPUPPCState *env, target_ulong value) @@ -812,10 +1103,7 @@ void do_store_msr (CPUPPCState *env, target_ulong value) value &= env->msr_mask; if (((value >> MSR_IR) & 1) != msr_ir || ((value >> MSR_DR) & 1) != msr_dr) { - /* Flush all tlb when changing translation mode - * When using software driven TLB, we may also need to reload - * all defined TLBs - */ + /* Flush all tlb when changing translation mode */ tlb_flush(env, 1); env->interrupt_request |= CPU_INTERRUPT_EXITTB; } @@ -824,35 +1112,52 @@ void do_store_msr (CPUPPCState *env, target_ulong value) fprintf(logfile, "%s: T0 %08lx\n", __func__, value); } #endif - msr_vr = (value >> MSR_VR) & 1; - msr_ap = (value >> MSR_AP) & 1; - msr_sa = (value >> MSR_SA) & 1; - msr_key = (value >> MSR_KEY) & 1; - msr_pow = (value >> MSR_POW) & 1; - msr_tlb = (value >> MSR_TLB) & 1; - msr_ile = (value >> MSR_ILE) & 1; - msr_ee = (value >> MSR_EE) & 1; - msr_pr = (value >> MSR_PR) & 1; - msr_fp = (value >> MSR_FP) & 1; - msr_me = (value >> MSR_ME) & 1; - msr_fe0 = (value >> MSR_FE0) & 1; - msr_se = (value >> MSR_SE) & 1; - msr_be = (value >> MSR_BE) & 1; - msr_fe1 = (value >> MSR_FE1) & 1; - msr_al = (value >> MSR_AL) & 1; - msr_ip = (value >> MSR_IP) & 1; - msr_ir = (value >> MSR_IR) & 1; - msr_dr = (value >> MSR_DR) & 1; - msr_pe = (value >> MSR_PE) & 1; - msr_px = (value >> MSR_PX) & 1; - msr_ri = (value >> MSR_RI) & 1; - msr_le = (value >> MSR_LE) & 1; + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_602: + case PPC_FLAGS_EXCP_603: + if (((value >> MSR_TGPR) & 1) != msr_tgpr) { + /* Swap temporary saved registers with GPRs */ + swap_gpr_tgpr(env); + } + break; + default: + break; + } +#if defined (TARGET_PPC64) + msr_sf = (value >> MSR_SF) & 1; + msr_isf = (value >> MSR_ISF) & 1; + msr_hv = (value >> MSR_HV) & 1; +#endif + msr_ucle = (value >> MSR_UCLE) & 1; + msr_vr = (value >> MSR_VR) & 1; /* VR / SPE */ + msr_ap = (value >> MSR_AP) & 1; + msr_sa = (value >> MSR_SA) & 1; + msr_key = (value >> MSR_KEY) & 1; + msr_pow = (value >> MSR_POW) & 1; /* POW / WE */ + msr_tlb = (value >> MSR_TLB) & 1; /* TLB / TGPR / CE */ + msr_ile = (value >> MSR_ILE) & 1; + msr_ee = (value >> MSR_EE) & 1; + msr_pr = (value >> MSR_PR) & 1; + msr_fp = (value >> MSR_FP) & 1; + msr_me = (value >> MSR_ME) & 1; + msr_fe0 = (value >> MSR_FE0) & 1; + msr_se = (value >> MSR_SE) & 1; /* SE / DWE / UBLE */ + msr_be = (value >> MSR_BE) & 1; /* BE / DE */ + msr_fe1 = (value >> MSR_FE1) & 1; + msr_al = (value >> MSR_AL) & 1; + msr_ip = (value >> MSR_IP) & 1; + msr_ir = (value >> MSR_IR) & 1; /* IR / IS */ + msr_dr = (value >> MSR_DR) & 1; /* DR / DS */ + msr_pe = (value >> MSR_PE) & 1; /* PE / EP */ + msr_px = (value >> MSR_PX) & 1; /* PX / PMM */ + msr_ri = (value >> MSR_RI) & 1; + msr_le = (value >> MSR_LE) & 1; do_compute_hflags(env); enter_pm = 0; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_7x0: - if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0) + if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0) enter_pm = 1; break; default: @@ -866,75 +1171,16 @@ void do_store_msr (CPUPPCState *env, target_ulong value) } } -float64 do_load_fpscr (CPUPPCState *env) +void do_compute_hflags (CPUPPCState *env) { - /* The 32 MSB of the target fpr are undefined. - * They'll be zero... - */ - union { - float64 d; - struct { - uint32_t u[2]; - } s; - } u; - int i; - -#ifdef WORDS_BIGENDIAN -#define WORD0 0 -#define WORD1 1 -#else -#define WORD0 1 -#define WORD1 0 + /* Compute current hflags */ + env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) | + (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) | + (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | + (msr_se << MSR_SE) | (msr_be << MSR_BE); +#if defined (TARGET_PPC64) + env->hflags |= (msr_sf << MSR_SF) | (msr_hv << MSR_HV); #endif - u.s.u[WORD0] = 0; - u.s.u[WORD1] = 0; - for (i = 0; i < 8; i++) - u.s.u[WORD1] |= env->fpscr[i] << (4 * i); - return u.d; -} - -void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask) -{ - /* - * We use only the 32 LSB of the incoming fpr - */ - union { - double d; - struct { - uint32_t u[2]; - } s; - } u; - int i, rnd_type; - - u.d = f; - if (mask & 0x80) - env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9); - for (i = 1; i < 7; i++) { - if (mask & (1 << (7 - i))) - env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF; - } - /* TODO: update FEX & VX */ - /* Set rounding mode */ - switch (env->fpscr[0] & 0x3) { - case 0: - /* Best approximation (round to nearest) */ - rnd_type = float_round_nearest_even; - break; - case 1: - /* Smaller magnitude (round toward zero) */ - rnd_type = float_round_to_zero; - break; - case 2: - /* Round toward +infinite */ - rnd_type = float_round_up; - break; - default: - case 3: - /* Round toward -infinite */ - rnd_type = float_round_down; - break; - } - set_float_rounding_mode(rnd_type, &env->fp_status); } /*****************************************************************************/ @@ -944,17 +1190,18 @@ void do_interrupt (CPUState *env) { env->exception_index = -1; } -#else +#else /* defined (CONFIG_USER_ONLY) */ static void dump_syscall(CPUState *env) { - fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x r5=0x%08x r6=0x%08x nip=0x%08x\n", + fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x " + "r5=0x%08x r6=0x%08x nip=0x%08x\n", env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6], env->nip); } void do_interrupt (CPUState *env) { - target_ulong msr, *srr_0, *srr_1, tmp; + target_ulong msr, *srr_0, *srr_1; int excp; excp = env->exception_index; @@ -967,7 +1214,7 @@ void do_interrupt (CPUState *env) if (loglevel != 0) { fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n", (unsigned long)env->nip, excp, env->error_code); - cpu_dump_state(env, logfile, fprintf, 0); + cpu_dump_state(env, logfile, fprintf, 0); } } #endif @@ -978,7 +1225,7 @@ void do_interrupt (CPUState *env) msr_pow = 0; /* Generate informations in save/restore registers */ switch (excp) { - /* Generic PowerPC exceptions */ + /* Generic PowerPC exceptions */ case EXCP_RESET: /* 0x0100 */ if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) { if (msr_ip) @@ -993,7 +1240,7 @@ void do_interrupt (CPUState *env) if (msr_me == 0) { cpu_abort(env, "Machine check exception while not allowed\n"); } - if (PPC_EXCP(env) == PPC_FLAGS_EXCP_40x) { + if (unlikely(PPC_EXCP(env) == PPC_FLAGS_EXCP_40x)) { srr_0 = &env->spr[SPR_40x_SRR2]; srr_1 = &env->spr[SPR_40x_SRR3]; } @@ -1004,26 +1251,26 @@ void do_interrupt (CPUState *env) /* data location address has been stored * when the fault has been detected */ - msr &= ~0xFFFF0000; + msr &= ~0xFFFF0000; #if defined (DEBUG_EXCEPTIONS) - if (loglevel) { - fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", - env->spr[SPR_DSISR], env->spr[SPR_DAR]); - } else { - printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n", - env->spr[SPR_DSISR], env->spr[SPR_DAR]); - } + if (loglevel) { + fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", + env->spr[SPR_DSISR], env->spr[SPR_DAR]); + } else { + printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n", + env->spr[SPR_DSISR], env->spr[SPR_DAR]); + } #endif goto store_next; case EXCP_ISI: /* 0x0400 */ /* Store exception cause */ - msr &= ~0xFFFF0000; + msr &= ~0xFFFF0000; msr |= env->error_code; #if defined (DEBUG_EXCEPTIONS) - if (loglevel != 0) { - fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", - msr, env->nip); - } + if (loglevel != 0) { + fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", + msr, env->nip); + } #endif goto store_next; case EXCP_EXTERNAL: /* 0x0500 */ @@ -1039,7 +1286,7 @@ void do_interrupt (CPUState *env) } goto store_next; case EXCP_ALIGN: /* 0x0600 */ - if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) { + if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) { /* Store exception cause */ /* Get rS/rD and rA from faulting opcode */ env->spr[SPR_DSISR] |= @@ -1063,7 +1310,7 @@ void do_interrupt (CPUState *env) printf("Ignore floating point exception\n"); #endif return; - } + } msr |= 0x00100000; /* Set FX */ env->fpscr[7] |= 0x8; @@ -1071,21 +1318,21 @@ void do_interrupt (CPUState *env) if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) env->fpscr[7] |= 0x4; - break; + break; case EXCP_INVAL: - // printf("Invalid instruction at 0x%08x\n", env->nip); + // printf("Invalid instruction at 0x%08x\n", env->nip); msr |= 0x00080000; - break; + break; case EXCP_PRIV: msr |= 0x00040000; - break; + break; case EXCP_TRAP: msr |= 0x00020000; break; default: /* Should never occur */ - break; - } + break; + } msr |= 0x00010000; goto store_current; case EXCP_NO_FP: /* 0x0800 */ @@ -1125,7 +1372,7 @@ void do_interrupt (CPUState *env) cpu_abort(env, "Floating point assist exception " "is not implemented yet !\n"); goto store_next; - /* 64 bits PowerPC exceptions */ + /* 64 bits PowerPC exceptions */ case EXCP_DSEG: /* 0x0380 */ /* XXX: TODO */ cpu_abort(env, "Data segment exception is not implemented yet !\n"); @@ -1141,14 +1388,16 @@ void do_interrupt (CPUState *env) /* Requeue it */ env->interrupt_request |= CPU_INTERRUPT_TIMER; #endif - return; + return; } - cpu_abort(env, - "Hypervisor decrementer exception is not implemented yet !\n"); + /* XXX: TODO */ + cpu_abort(env, "Hypervisor decrementer exception is not implemented " + "yet !\n"); goto store_next; /* Implementation specific exceptions */ case 0x0A00: - if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) { + if (likely(env->spr[SPR_PVR] == CPU_PPC_G2 || + env->spr[SPR_PVR] == CPU_PPC_G2LE)) { /* Critical interrupt on G2 */ /* XXX: TODO */ cpu_abort(env, "G2 critical interrupt is not implemented yet !\n"); @@ -1186,9 +1435,10 @@ void do_interrupt (CPUState *env) case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: /* ITLBMISS on 602/603 */ - msr &= ~0xF00F0000; - msr_tgpr = 1; goto store_gprs; + case PPC_FLAGS_EXCP_7x5: + /* ITLBMISS on 745/755 */ + goto tlb_miss; default: cpu_abort(env, "Invalid exception 0x1000 !\n"); break; @@ -1198,8 +1448,8 @@ void do_interrupt (CPUState *env) switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* FIT on 4xx */ - cpu_abort(env, "40x FIT exception is not implemented yet !\n"); /* XXX: TODO */ + cpu_abort(env, "40x FIT exception is not implemented yet !\n"); goto store_next; default: cpu_abort(env, "Invalid exception 0x1010 !\n"); @@ -1230,9 +1480,10 @@ void do_interrupt (CPUState *env) case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: /* DLTLBMISS on 602/603 */ - msr &= ~0xF00F0000; - msr_tgpr = 1; goto store_gprs; + case PPC_FLAGS_EXCP_7x5: + /* DLTLBMISS on 745/755 */ + goto tlb_miss; default: cpu_abort(env, "Invalid exception 0x1100 !\n"); break; @@ -1249,37 +1500,44 @@ void do_interrupt (CPUState *env) case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: /* DSTLBMISS on 602/603 */ - msr &= ~0xF00F0000; - msr_tgpr = 1; store_gprs: + /* Swap temporary saved registers with GPRs */ + swap_gpr_tgpr(env); + msr_tgpr = 1; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "6xx %sTLB miss: IM %08x DM %08x IC %08x " - "DC %08x H1 %08x H2 %08x %08x\n", - excp == 0x1000 ? "I" : excp == 0x1100 ? "DL" : "DS", - env->spr[SPR_IMISS], env->spr[SPR_DMISS], - env->spr[SPR_ICMP], env->spr[SPR_DCMP], - env->spr[SPR_DHASH1], env->spr[SPR_DHASH2], + const unsigned char *es; + target_ulong *miss, *cmp; + int en; + if (excp == 0x1000) { + es = "I"; + en = 'I'; + miss = &env->spr[SPR_IMISS]; + cmp = &env->spr[SPR_ICMP]; + } else { + if (excp == 0x1100) + es = "DL"; + else + es = "DS"; + en = 'D'; + miss = &env->spr[SPR_DMISS]; + cmp = &env->spr[SPR_DCMP]; + } + fprintf(logfile, "6xx %sTLB miss: %cM %08x %cC %08x " + "H1 %08x H2 %08x %08x\n", es, en, *miss, en, *cmp, + env->spr[SPR_HASH1], env->spr[SPR_HASH2], env->error_code); } #endif - /* Swap temporary saved registers with GPRs */ - tmp = env->gpr[0]; - env->gpr[0] = env->tgpr[0]; - env->tgpr[0] = tmp; - tmp = env->gpr[1]; - env->gpr[1] = env->tgpr[1]; - env->tgpr[1] = tmp; - tmp = env->gpr[2]; - env->gpr[2] = env->tgpr[2]; - env->tgpr[2] = tmp; - tmp = env->gpr[3]; - env->gpr[3] = env->tgpr[3]; - env->tgpr[3] = tmp; + goto tlb_miss; + case PPC_FLAGS_EXCP_7x5: + /* DSTLBMISS on 745/755 */ + tlb_miss: + msr &= ~0xF83F0000; msr |= env->crf[0] << 28; msr |= env->error_code; /* key, D/I, S/L bits */ /* Set way using a LRU mechanism */ - msr |= (env->last_way ^ 1) << 17; + msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; goto store_next; default: cpu_abort(env, "Invalid exception 0x1200 !\n"); @@ -1324,6 +1582,7 @@ void do_interrupt (CPUState *env) switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_602: /* Watchdog on 602 */ + /* XXX: TODO */ cpu_abort(env, "602 watchdog exception is not implemented yet !\n"); goto store_next; diff --git a/target-ppc/mfrom_table.c b/target-ppc/mfrom_table.c new file mode 100644 index 000000000..4c2717318 --- /dev/null +++ b/target-ppc/mfrom_table.c @@ -0,0 +1,79 @@ +static const uint8_t mfrom_ROM_table[602] = +{ + 77, 77, 76, 76, 75, 75, 74, 74, + 73, 73, 72, 72, 71, 71, 70, 70, + 69, 69, 68, 68, 68, 67, 67, 66, + 66, 65, 65, 64, 64, 64, 63, 63, + 62, 62, 61, 61, 61, 60, 60, 59, + 59, 58, 58, 58, 57, 57, 56, 56, + 56, 55, 55, 54, 54, 54, 53, 53, + 53, 52, 52, 51, 51, 51, 50, 50, + 50, 49, 49, 49, 48, 48, 47, 47, + 47, 46, 46, 46, 45, 45, 45, 44, + 44, 44, 43, 43, 43, 42, 42, 42, + 42, 41, 41, 41, 40, 40, 40, 39, + 39, 39, 39, 38, 38, 38, 37, 37, + 37, 37, 36, 36, 36, 35, 35, 35, + 35, 34, 34, 34, 34, 33, 33, 33, + 33, 32, 32, 32, 32, 31, 31, 31, + 31, 30, 30, 30, 30, 29, 29, 29, + 29, 28, 28, 28, 28, 28, 27, 27, + 27, 27, 26, 26, 26, 26, 26, 25, + 25, 25, 25, 25, 24, 24, 24, 24, + 24, 23, 23, 23, 23, 23, 23, 22, + 22, 22, 22, 22, 21, 21, 21, 21, + 21, 21, 20, 20, 20, 20, 20, 20, + 19, 19, 19, 19, 19, 19, 19, 18, + 18, 18, 18, 18, 18, 17, 17, 17, + 17, 17, 17, 17, 16, 16, 16, 16, + 16, 16, 16, 16, 15, 15, 15, 15, + 15, 15, 15, 15, 14, 14, 14, 14, + 14, 14, 14, 14, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, +}; diff --git a/target-ppc/mfrom_table_gen.c b/target-ppc/mfrom_table_gen.c new file mode 100644 index 000000000..ab4b1cc0b --- /dev/null +++ b/target-ppc/mfrom_table_gen.c @@ -0,0 +1,33 @@ +#define _GNU_SOURCE +#include +#include +#include + +int main (void) +{ + double d; + uint8_t n; + int i; + + printf("static const uint8_t mfrom_ROM_table[602] =\n{\n "); + for (i = 0; i < 602; i++) { + /* Extremly decomposed: + * -T0 / 256 + * T0 = 256 * log10(10 + 1.0) + 0.5 + */ + d = -i; + d /= 256.0; + d = exp10(d); + d += 1.0; + d = log10(d); + d *= 256; + d += 0.5; + n = d; + printf("%3d, ", n); + if ((i & 7) == 7) + printf("\n "); + } + printf("\n};\n"); + + return 0; +} diff --git a/target-ppc/op.c b/target-ppc/op.c index ca1dbc5eb..1bad76811 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1,7 +1,7 @@ /* * PowerPC emulation micro-operations for qemu. * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,9 @@ #include "config.h" #include "exec.h" +#include "op_helper.h" +/* XXX: this is to be suppressed */ #define regs (env) #define Ts0 (int32_t)T0 #define Ts1 (int32_t)T1 @@ -32,7 +34,8 @@ #define FT1 (env->ft1) #define FT2 (env->ft2) -#define PPC_OP(name) void glue(op_, name)(void) +/* XXX: this is to be suppressed... */ +#define PPC_OP(name) void OPPROTO glue(op_, name)(void) #define REG 0 #include "op_template.h" @@ -134,31 +137,7 @@ /* set_Rc0 */ PPC_OP(set_Rc0) { - uint32_t tmp; - - if (Ts0 < 0) { - tmp = 0x08; - } else if (Ts0 > 0) { - tmp = 0x04; - } else { - tmp = 0x02; - } - tmp |= xer_ov; - env->crf[0] = tmp; - RETURN(); -} - -/* reset_Rc0 */ -PPC_OP(reset_Rc0) -{ - env->crf[0] = 0x02 | xer_ov; - RETURN(); -} - -/* set_Rc0_1 */ -PPC_OP(set_Rc0_1) -{ - env->crf[0] = 0x04 | xer_ov; + env->crf[0] = T0 | xer_ov; RETURN(); } @@ -170,6 +149,12 @@ PPC_OP(set_Rc1) } /* Constants load */ +void OPPROTO op_reset_T0 (void) +{ + T0 = 0; + RETURN(); +} + PPC_OP(set_T0) { T0 = PARAM(1); @@ -182,26 +167,30 @@ PPC_OP(set_T1) RETURN(); } +#if 0 // unused PPC_OP(set_T2) { T2 = PARAM(1); RETURN(); } +#endif -/* Generate exceptions */ -PPC_OP(raise_exception_err) +void OPPROTO op_move_T1_T0 (void) { - do_raise_exception_err(PARAM(1), PARAM(2)); + T1 = T0; + RETURN(); } -PPC_OP(raise_exception) +/* Generate exceptions */ +PPC_OP(raise_exception_err) { - do_raise_exception(PARAM(1)); + do_raise_exception_err(PARAM(1), PARAM(2)); } PPC_OP(update_nip) { env->nip = PARAM(1); + RETURN(); } PPC_OP(debug) @@ -209,46 +198,34 @@ PPC_OP(debug) do_raise_exception(EXCP_DEBUG); } -/* Segment registers load and store with immediate index */ -PPC_OP(load_srin) -{ - T0 = regs->sr[T1 >> 28]; - RETURN(); -} -PPC_OP(store_srin) +PPC_OP(exit_tb) { - do_store_sr(env, ((uint32_t)T1 >> 28), T0); - RETURN(); + EXIT_TB(); } -PPC_OP(load_sdr1) +/* Load/store special registers */ +PPC_OP(load_cr) { - T0 = regs->sdr1; + do_load_cr(); RETURN(); } -PPC_OP(store_sdr1) +PPC_OP(store_cr) { - do_store_sdr1(env, T0); + do_store_cr(PARAM(1)); RETURN(); } -PPC_OP(exit_tb) +void OPPROTO op_load_cro (void) { - EXIT_TB(); -} - -/* Load/store special registers */ -PPC_OP(load_cr) -{ - T0 = do_load_cr(env); + T0 = env->crf[PARAM1]; RETURN(); } -PPC_OP(store_cr) +void OPPROTO op_store_cro (void) { - do_store_cr(env, T0, PARAM(1)); + env->crf[PARAM1] = T0; RETURN(); } @@ -272,15 +249,47 @@ PPC_OP(load_xer_bc) RETURN(); } +void OPPROTO op_store_xer_bc (void) +{ + xer_bc = T0; + RETURN(); +} + PPC_OP(load_xer) { - T0 = do_load_xer(env); + do_load_xer(); RETURN(); } PPC_OP(store_xer) { - do_store_xer(env, T0); + do_store_xer(); + RETURN(); +} + +#if !defined(CONFIG_USER_ONLY) +/* Segment registers load and store */ +PPC_OP(load_sr) +{ + T0 = regs->sr[T1]; + RETURN(); +} + +PPC_OP(store_sr) +{ + do_store_sr(env, T1, T0); + RETURN(); +} + +PPC_OP(load_sdr1) +{ + T0 = regs->sdr1; + RETURN(); +} + +PPC_OP(store_sdr1) +{ + do_store_sdr1(env, T0); RETURN(); } @@ -295,6 +304,7 @@ PPC_OP(store_msr) do_store_msr(env, T0); RETURN(); } +#endif /* SPR */ PPC_OP(load_spr) @@ -345,6 +355,7 @@ PPC_OP(load_tbu) RETURN(); } +#if !defined(CONFIG_USER_ONLY) PPC_OP(store_tbl) { cpu_ppc_store_tbl(regs, T0); @@ -360,7 +371,8 @@ PPC_OP(store_tbu) PPC_OP(load_decr) { T0 = cpu_ppc_load_decr(regs); - } + RETURN(); +} PPC_OP(store_decr) { @@ -371,15 +383,16 @@ PPC_OP(store_decr) PPC_OP(load_ibat) { T0 = regs->IBAT[PARAM(1)][PARAM(2)]; + RETURN(); } -void op_store_ibatu (void) +void OPPROTO op_store_ibatu (void) { do_store_ibatu(env, PARAM1, T0); RETURN(); } -void op_store_ibatl (void) +void OPPROTO op_store_ibatl (void) { #if 1 env->IBAT[1][PARAM1] = T0; @@ -392,15 +405,16 @@ void op_store_ibatl (void) PPC_OP(load_dbat) { T0 = regs->DBAT[PARAM(1)][PARAM(2)]; + RETURN(); } -void op_store_dbatu (void) +void OPPROTO op_store_dbatu (void) { do_store_dbatu(env, PARAM1, T0); RETURN(); } -void op_store_dbatl (void) +void OPPROTO op_store_dbatl (void) { #if 1 env->DBAT[1][PARAM1] = T0; @@ -409,17 +423,18 @@ void op_store_dbatl (void) #endif RETURN(); } +#endif /* !defined(CONFIG_USER_ONLY) */ /* FPSCR */ PPC_OP(load_fpscr) { - FT0 = do_load_fpscr(env); + do_load_fpscr(); RETURN(); } PPC_OP(store_fpscr) { - do_store_fpscr(env, FT0, PARAM1); + do_store_fpscr(PARAM1); RETURN(); } @@ -454,6 +469,7 @@ PPC_OP(setcrfbit) PPC_OP(setlr) { regs->lr = PARAM1; + RETURN(); } PPC_OP(goto_tb0) @@ -469,6 +485,7 @@ PPC_OP(goto_tb1) PPC_OP(b_T1) { regs->nip = T1 & ~3; + RETURN(); } PPC_OP(jz_T0) @@ -491,11 +508,13 @@ PPC_OP(btest_T1) PPC_OP(movl_T1_ctr) { T1 = regs->ctr; + RETURN(); } PPC_OP(movl_T1_lr) { T1 = regs->lr; + RETURN(); } /* tests with result in T0 */ @@ -503,41 +522,49 @@ PPC_OP(movl_T1_lr) PPC_OP(test_ctr) { T0 = regs->ctr; + RETURN(); } PPC_OP(test_ctr_true) { T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0); + RETURN(); } PPC_OP(test_ctr_false) { T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0); + RETURN(); } PPC_OP(test_ctrz) { T0 = (regs->ctr == 0); + RETURN(); } PPC_OP(test_ctrz_true) { T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0); + RETURN(); } PPC_OP(test_ctrz_false) { T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0); + RETURN(); } PPC_OP(test_true) { T0 = (T0 & PARAM(1)); + RETURN(); } PPC_OP(test_false) { T0 = ((T0 & PARAM(1)) == 0); + RETURN(); } /* CTR maintenance */ @@ -555,8 +582,7 @@ PPC_OP(add) RETURN(); } -void do_addo (void); -void op_addo (void) +void OPPROTO op_addo (void) { do_addo(); RETURN(); @@ -575,21 +601,19 @@ PPC_OP(addc) RETURN(); } -void do_addco (void); -void op_addco (void) +void OPPROTO op_addco (void) { do_addco(); RETURN(); } /* add extended */ -void do_adde (void); -void op_adde (void) +void OPPROTO op_adde (void) { do_adde(); + RETURN(); } -void do_addeo (void); PPC_OP(addeo) { do_addeo(); @@ -626,8 +650,7 @@ PPC_OP(addme) RETURN(); } -void do_addmeo (void); -void op_addmeo (void) +void OPPROTO op_addmeo (void) { do_addmeo(); RETURN(); @@ -646,8 +669,7 @@ PPC_OP(addze) RETURN(); } -void do_addzeo (void); -void op_addzeo (void) +void OPPROTO op_addzeo (void) { do_addzeo(); RETURN(); @@ -664,8 +686,7 @@ PPC_OP(divw) RETURN(); } -void do_divwo (void); -void op_divwo (void) +void OPPROTO op_divwo (void) { do_divwo(); RETURN(); @@ -682,8 +703,7 @@ PPC_OP(divwu) RETURN(); } -void do_divwuo (void); -void op_divwuo (void) +void OPPROTO op_divwuo (void) { do_divwuo(); RETURN(); @@ -717,8 +737,7 @@ PPC_OP(mullw) RETURN(); } -void do_mullwo (void); -void op_mullwo (void) +void OPPROTO op_mullwo (void) { do_mullwo(); RETURN(); @@ -733,8 +752,7 @@ PPC_OP(neg) RETURN(); } -void do_nego (void); -void op_nego (void) +void OPPROTO op_nego (void) { do_nego(); RETURN(); @@ -747,8 +765,7 @@ PPC_OP(subf) RETURN(); } -void do_subfo (void); -void op_subfo (void) +void OPPROTO op_subfo (void) { do_subfo(); RETURN(); @@ -766,22 +783,19 @@ PPC_OP(subfc) RETURN(); } -void do_subfco (void); -void op_subfco (void) +void OPPROTO op_subfco (void) { do_subfco(); RETURN(); } /* substract from extended */ -void do_subfe (void); -void op_subfe (void) +void OPPROTO op_subfe (void) { do_subfe(); RETURN(); } -void do_subfeo (void); PPC_OP(subfeo) { do_subfeo(); @@ -810,8 +824,7 @@ PPC_OP(subfme) RETURN(); } -void do_subfmeo (void); -void op_subfmeo (void) +void OPPROTO op_subfmeo (void) { do_subfmeo(); RETURN(); @@ -830,8 +843,7 @@ PPC_OP(subfze) RETURN(); } -void do_subfzeo (void); -void op_subfzeo (void) +void OPPROTO op_subfzeo (void) { do_subfzeo(); RETURN(); @@ -906,18 +918,48 @@ PPC_OP(andc) } /* andi. */ -PPC_OP(andi_) +void OPPROTO op_andi_T0 (void) { T0 &= PARAM(1); RETURN(); } +void OPPROTO op_andi_T1 (void) +{ + T1 &= PARAM1; + RETURN(); +} + /* count leading zero */ -PPC_OP(cntlzw) +void OPPROTO op_cntlzw (void) { - T1 = T0; - for (T0 = 32; T1 > 0; T0--) - T1 = T1 >> 1; + int cnt; + + cnt = 0; + if (!(T0 & 0xFFFF0000UL)) { + cnt += 16; + T0 <<= 16; + } + if (!(T0 & 0xFF000000UL)) { + cnt += 8; + T0 <<= 8; + } + if (!(T0 & 0xF0000000UL)) { + cnt += 4; + T0 <<= 4; + } + if (!(T0 & 0xC0000000UL)) { + cnt += 2; + T0 <<= 2; + } + if (!(T0 & 0x80000000UL)) { + cnt++; + T0 <<= 1; + } + if (!(T0 & 0x80000000UL)) { + cnt++; + } + T0 = cnt; RETURN(); } @@ -992,48 +1034,15 @@ PPC_OP(xori) } /*** Integer rotate ***/ -/* rotate left word immediate then mask insert */ -PPC_OP(rlwimi) -{ - T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3)); - RETURN(); -} - -/* rotate left immediate then and with mask insert */ -PPC_OP(rotlwi) -{ - T0 = rotl(T0, PARAM(1)); - RETURN(); -} - -PPC_OP(slwi) -{ - T0 = T0 << PARAM(1); - RETURN(); -} - -PPC_OP(srwi) +void OPPROTO op_rotl32_T0_T1 (void) { - T0 = T0 >> PARAM(1); + T0 = rotl32(T0, T1 & 0x1F); RETURN(); } -/* rotate left word then and with mask insert */ -PPC_OP(rlwinm) +void OPPROTO op_rotli32_T0 (void) { - T0 = rotl(T0, PARAM(1)) & PARAM(2); - RETURN(); -} - -PPC_OP(rotl) -{ - T0 = rotl(T0, T1); - RETURN(); -} - -PPC_OP(rlwnm) -{ - T0 = rotl(T0, T1) & PARAM(1); + T0 = rotl32(T0, PARAM1); RETURN(); } @@ -1050,7 +1059,7 @@ PPC_OP(slw) } /* shift right algebraic word */ -void op_sraw (void) +void OPPROTO op_sraw (void) { do_sraw(); RETURN(); @@ -1080,25 +1089,55 @@ PPC_OP(srw) RETURN(); } +void OPPROTO op_sl_T0_T1 (void) +{ + T0 = T0 << T1; + RETURN(); +} + +void OPPROTO op_sli_T0 (void) +{ + T0 = T0 << PARAM1; + RETURN(); +} + +void OPPROTO op_srl_T0_T1 (void) +{ + T0 = T0 >> T1; + RETURN(); +} + +void OPPROTO op_srli_T0 (void) +{ + T0 = T0 >> PARAM1; + RETURN(); +} + +void OPPROTO op_srli_T1 (void) +{ + T1 = T1 >> PARAM1; + RETURN(); +} + /*** Floating-Point arithmetic ***/ /* fadd - fadd. */ PPC_OP(fadd) { - FT0 += FT1; + FT0 = float64_add(FT0, FT1, &env->fp_status); RETURN(); } /* fsub - fsub. */ PPC_OP(fsub) { - FT0 -= FT1; + FT0 = float64_sub(FT0, FT1, &env->fp_status); RETURN(); } /* fmul - fmul. */ PPC_OP(fmul) { - FT0 *= FT1; + FT0 = float64_mul(FT0, FT1, &env->fp_status); RETURN(); } @@ -1141,14 +1180,16 @@ PPC_OP(fsel) /* fmadd - fmadd. */ PPC_OP(fmadd) { - FT0 = (FT0 * FT1) + FT2; + FT0 = float64_mul(FT0, FT1, &env->fp_status); + FT0 = float64_add(FT0, FT2, &env->fp_status); RETURN(); } /* fmsub - fmsub. */ PPC_OP(fmsub) { - FT0 = (FT0 * FT1) - FT2; + FT0 = float64_mul(FT0, FT1, &env->fp_status); + FT0 = float64_sub(FT0, FT2, &env->fp_status); RETURN(); } @@ -1170,7 +1211,7 @@ PPC_OP(fnmsub) /* frsp - frsp. */ PPC_OP(frsp) { - FT0 = (float)FT0; + FT0 = float64_to_float32(FT0, &env->fp_status); RETURN(); } @@ -1188,7 +1229,6 @@ PPC_OP(fctiwz) RETURN(); } - /*** Floating-Point compare ***/ /* fcmpu */ PPC_OP(fcmpu) @@ -1229,12 +1269,14 @@ PPC_OP(fneg) /* Load and store */ #define MEMSUFFIX _raw +#include "op_helper.h" #include "op_mem.h" #if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user +#include "op_helper.h" #include "op_mem.h" - #define MEMSUFFIX _kernel +#include "op_helper.h" #include "op_mem.h" #endif @@ -1247,24 +1289,18 @@ PPC_OP(check_reservation) } /* Return from interrupt */ -void do_rfi (void); -void op_rfi (void) +#if !defined(CONFIG_USER_ONLY) +void OPPROTO op_rfi (void) { do_rfi(); RETURN(); } +#endif /* Trap word */ -void do_tw (uint32_t cmp, int flags); -void op_tw (void) -{ - do_tw(T1, PARAM(1)); - RETURN(); -} - -void op_twi (void) +void OPPROTO op_tw (void) { - do_tw(PARAM(1), PARAM(2)); + do_tw(PARAM1); RETURN(); } @@ -1275,6 +1311,7 @@ PPC_OP(icbi) RETURN(); } +#if !defined(CONFIG_USER_ONLY) /* tlbia */ PPC_OP(tlbia) { @@ -1288,9 +1325,554 @@ PPC_OP(tlbie) do_tlbie(); RETURN(); } +#endif -void op_store_pir (void) +/* PowerPC 602/603/755 software TLB load instructions */ +#if !defined(CONFIG_USER_ONLY) +void OPPROTO op_6xx_tlbld (void) +{ + do_load_6xx_tlb(0); + RETURN(); +} + +void OPPROTO op_6xx_tlbli (void) +{ + do_load_6xx_tlb(1); + RETURN(); +} +#endif + +/* 601 specific */ +uint32_t cpu_ppc601_load_rtcl (CPUState *env); +void OPPROTO op_load_601_rtcl (void) +{ + T0 = cpu_ppc601_load_rtcl(env); + RETURN(); +} + +uint32_t cpu_ppc601_load_rtcu (CPUState *env); +void OPPROTO op_load_601_rtcu (void) +{ + T0 = cpu_ppc601_load_rtcu(env); + RETURN(); +} + +#if !defined(CONFIG_USER_ONLY) +void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value); +void OPPROTO op_store_601_rtcl (void) +{ + cpu_ppc601_store_rtcl(env, T0); + RETURN(); +} + +void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value); +void OPPROTO op_store_601_rtcu (void) +{ + cpu_ppc601_store_rtcu(env, T0); + RETURN(); +} + +void OPPROTO op_load_601_bat (void) +{ + T0 = env->IBAT[PARAM1][PARAM2]; + RETURN(); +} +#endif /* !defined(CONFIG_USER_ONLY) */ + +/* 601 unified BATs store. + * To avoid using specific MMU code for 601, we store BATs in + * IBAT and DBAT simultaneously, then emulate unified BATs. + */ +#if !defined(CONFIG_USER_ONLY) +void OPPROTO op_store_601_batl (void) +{ + int nr = PARAM1; + + env->IBAT[1][nr] = T0; + env->DBAT[1][nr] = T0; + RETURN(); +} + +void OPPROTO op_store_601_batu (void) +{ + do_store_601_batu(PARAM1); + RETURN(); +} +#endif /* !defined(CONFIG_USER_ONLY) */ + +/* PowerPC 601 specific instructions (POWER bridge) */ +/* XXX: those micro-ops need tests ! */ +void OPPROTO op_POWER_abs (void) +{ + if (T0 == INT32_MIN) + T0 = INT32_MAX; + else if (T0 < 0) + T0 = -T0; + RETURN(); +} + +void OPPROTO op_POWER_abso (void) +{ + do_POWER_abso(); + RETURN(); +} + +void OPPROTO op_POWER_clcs (void) +{ + do_POWER_clcs(); + RETURN(); +} + +void OPPROTO op_POWER_div (void) +{ + do_POWER_div(); + RETURN(); +} + +void OPPROTO op_POWER_divo (void) +{ + do_POWER_divo(); + RETURN(); +} + +void OPPROTO op_POWER_divs (void) +{ + do_POWER_divs(); + RETURN(); +} + +void OPPROTO op_POWER_divso (void) +{ + do_POWER_divso(); + RETURN(); +} + +void OPPROTO op_POWER_doz (void) +{ + if (Ts1 > Ts0) + T0 = T1 - T0; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_POWER_dozo (void) +{ + do_POWER_dozo(); + RETURN(); +} + +void OPPROTO op_load_xer_cmp (void) +{ + T2 = xer_cmp; + RETURN(); +} + +void OPPROTO op_POWER_maskg (void) +{ + do_POWER_maskg(); + RETURN(); +} + +void OPPROTO op_POWER_maskir (void) +{ + T0 = (T0 & ~T2) | (T1 & T2); + RETURN(); +} + +void OPPROTO op_POWER_mul (void) +{ + uint64_t tmp; + + tmp = (uint64_t)T0 * (uint64_t)T1; + env->spr[SPR_MQ] = tmp >> 32; + T0 = tmp; + RETURN(); +} + +void OPPROTO op_POWER_mulo (void) +{ + do_POWER_mulo(); + RETURN(); +} + +void OPPROTO op_POWER_nabs (void) +{ + if (T0 > 0) + T0 = -T0; + RETURN(); +} + +void OPPROTO op_POWER_nabso (void) +{ + /* nabs never overflows */ + if (T0 > 0) + T0 = -T0; + xer_ov = 0; + RETURN(); +} + +/* XXX: factorise POWER rotates... */ +void OPPROTO op_POWER_rlmi (void) +{ + T0 = rotl32(T0, T2) & PARAM1; + T0 |= T1 & PARAM2; + RETURN(); +} + +void OPPROTO op_POWER_rrib (void) +{ + T2 &= 0x1FUL; + T0 = rotl32(T0 & INT32_MIN, T2); + T0 |= T1 & ~rotl32(INT32_MIN, T2); + RETURN(); +} + +void OPPROTO op_POWER_sle (void) +{ + T1 &= 0x1FUL; + env->spr[SPR_MQ] = rotl32(T0, T1); + T0 = T0 << T1; + RETURN(); +} + +void OPPROTO op_POWER_sleq (void) +{ + uint32_t tmp = env->spr[SPR_MQ]; + + T1 &= 0x1FUL; + env->spr[SPR_MQ] = rotl32(T0, T1); + T0 = T0 << T1; + T0 |= tmp >> (32 - T1); + RETURN(); +} + +void OPPROTO op_POWER_sllq (void) +{ + uint32_t msk = -1; + + msk = msk << (T1 & 0x1FUL); + if (T1 & 0x20UL) + msk = ~msk; + T1 &= 0x1FUL; + T0 = (T0 << T1) & msk; + T0 |= env->spr[SPR_MQ] & ~msk; + RETURN(); +} + +void OPPROTO op_POWER_slq (void) +{ + uint32_t msk = -1, tmp; + + msk = msk << (T1 & 0x1FUL); + if (T1 & 0x20UL) + msk = ~msk; + T1 &= 0x1FUL; + tmp = rotl32(T0, T1); + T0 = tmp & msk; + env->spr[SPR_MQ] = tmp; + RETURN(); +} + +void OPPROTO op_POWER_sraq (void) +{ + env->spr[SPR_MQ] = rotl32(T0, 32 - (T1 & 0x1FUL)); + if (T1 & 0x20UL) + T0 = -1L; + else + T0 = Ts0 >> T1; + RETURN(); +} + +void OPPROTO op_POWER_sre (void) +{ + T1 &= 0x1FUL; + env->spr[SPR_MQ] = rotl32(T0, 32 - T1); + T0 = Ts0 >> T1; + RETURN(); +} + +void OPPROTO op_POWER_srea (void) +{ + T1 &= 0x1FUL; + env->spr[SPR_MQ] = T0 >> T1; + T0 = Ts0 >> T1; + RETURN(); +} + +void OPPROTO op_POWER_sreq (void) +{ + uint32_t tmp; + int32_t msk; + + T1 &= 0x1FUL; + msk = INT32_MIN >> T1; + tmp = env->spr[SPR_MQ]; + env->spr[SPR_MQ] = rotl32(T0, 32 - T1); + T0 = T0 >> T1; + T0 |= tmp & msk; + RETURN(); +} + +void OPPROTO op_POWER_srlq (void) +{ + uint32_t tmp; + int32_t msk; + + msk = INT32_MIN >> (T1 & 0x1FUL); + if (T1 & 0x20UL) + msk = ~msk; + T1 &= 0x1FUL; + tmp = env->spr[SPR_MQ]; + env->spr[SPR_MQ] = rotl32(T0, 32 - T1); + T0 = T0 >> T1; + T0 &= msk; + T0 |= tmp & ~msk; + RETURN(); +} + +void OPPROTO op_POWER_srq (void) +{ + T1 &= 0x1FUL; + env->spr[SPR_MQ] = rotl32(T0, 32 - T1); + T0 = T0 >> T1; + RETURN(); +} + +/* POWER instructions not implemented in PowerPC 601 */ +#if !defined(CONFIG_USER_ONLY) +void OPPROTO op_POWER_mfsri (void) +{ + T1 = T0 >> 28; + T0 = env->sr[T1]; + RETURN(); +} + +void OPPROTO op_POWER_rac (void) +{ + do_POWER_rac(); + RETURN(); +} + +void OPPROTO op_POWER_rfsvc (void) +{ + do_POWER_rfsvc(); + RETURN(); +} +#endif + +/* PowerPC 602 specific instruction */ +#if !defined(CONFIG_USER_ONLY) +void OPPROTO op_602_mfrom (void) +{ + do_op_602_mfrom(); + RETURN(); +} +#endif + +/* PowerPC 4xx specific micro-ops */ +void OPPROTO op_405_add_T0_T2 (void) +{ + T0 = (int32_t)T0 + (int32_t)T2; + RETURN(); +} + +void OPPROTO op_405_mulchw (void) +{ + T0 = ((int16_t)T0) * ((int16_t)(T1 >> 16)); + RETURN(); +} + +void OPPROTO op_405_mulchwu (void) +{ + T0 = ((uint16_t)T0) * ((uint16_t)(T1 >> 16)); + RETURN(); +} + +void OPPROTO op_405_mulhhw (void) +{ + T0 = ((int16_t)(T0 >> 16)) * ((int16_t)(T1 >> 16)); + RETURN(); +} + +void OPPROTO op_405_mulhhwu (void) +{ + T0 = ((uint16_t)(T0 >> 16)) * ((uint16_t)(T1 >> 16)); + RETURN(); +} + +void OPPROTO op_405_mullhw (void) +{ + T0 = ((int16_t)T0) * ((int16_t)T1); + RETURN(); +} + +void OPPROTO op_405_mullhwu (void) +{ + T0 = ((uint16_t)T0) * ((uint16_t)T1); + RETURN(); +} + +void OPPROTO op_405_check_ov (void) +{ + do_405_check_ov(); + RETURN(); +} + +void OPPROTO op_405_check_sat (void) +{ + do_405_check_sat(); + RETURN(); +} + +void OPPROTO op_405_check_ovu (void) +{ + if (likely(T0 >= T2)) { + xer_ov = 0; + } else { + xer_ov = 1; + xer_so = 1; + } + RETURN(); +} + +void OPPROTO op_405_check_satu (void) +{ + if (unlikely(T0 < T2)) { + /* Saturate result */ + T0 = -1; + } + RETURN(); +} + +#if !defined(CONFIG_USER_ONLY) +void OPPROTO op_4xx_load_dcr (void) +{ + do_4xx_load_dcr(PARAM1); + RETURN(); +} + +void OPPROTO op_4xx_store_dcr (void) +{ + do_4xx_store_dcr(PARAM1); + RETURN(); +} + +/* Return from critical interrupt : + * same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1 + */ +void OPPROTO op_4xx_rfci (void) +{ + do_4xx_rfci(); + RETURN(); +} + +void OPPROTO op_4xx_wrte (void) +{ + msr_ee = T0 >> 16; + RETURN(); +} + +void OPPROTO op_4xx_tlbre_lo (void) +{ + do_4xx_tlbre_lo(); + RETURN(); +} + +void OPPROTO op_4xx_tlbre_hi (void) +{ + do_4xx_tlbre_hi(); + RETURN(); +} + +void OPPROTO op_4xx_tlbsx (void) +{ + do_4xx_tlbsx(); + RETURN(); +} + +void OPPROTO op_4xx_tlbsx_ (void) +{ + do_4xx_tlbsx_(); + RETURN(); +} + +void OPPROTO op_4xx_tlbwe_lo (void) +{ + do_4xx_tlbwe_lo(); + RETURN(); +} + +void OPPROTO op_4xx_tlbwe_hi (void) +{ + do_4xx_tlbwe_hi(); + RETURN(); +} +#endif + +/* SPR micro-ops */ +/* 440 specific */ +void OPPROTO op_440_dlmzb (void) +{ + do_440_dlmzb(); + RETURN(); +} + +void OPPROTO op_440_dlmzb_update_Rc (void) +{ + if (T0 == 8) + T0 = 0x2; + else if (T0 < 4) + T0 = 0x4; + else + T0 = 0x8; + RETURN(); +} + +#if !defined(CONFIG_USER_ONLY) +void OPPROTO op_store_pir (void) { env->spr[SPR_PIR] = T0 & 0x0000000FUL; RETURN(); } + +void OPPROTO op_load_403_pb (void) +{ + do_load_403_pb(PARAM1); + RETURN(); +} + +void OPPROTO op_store_403_pb (void) +{ + do_store_403_pb(PARAM1); + RETURN(); +} + +target_ulong load_40x_pit (CPUState *env); +void OPPROTO op_load_40x_pit (void) +{ + T0 = load_40x_pit(env); + RETURN(); +} + +void store_40x_pit (CPUState *env, target_ulong val); +void OPPROTO op_store_40x_pit (void) +{ + store_40x_pit(env, T0); + RETURN(); +} + +void store_booke_tcr (CPUState *env, target_ulong val); +void OPPROTO op_store_booke_tcr (void) +{ + store_booke_tcr(env, T0); + RETURN(); +} + +void store_booke_tsr (CPUState *env, target_ulong val); +void OPPROTO op_store_booke_tsr (void) +{ + store_booke_tsr(env, T0); + RETURN(); +} +#endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index e949eb42e..ea3849710 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1,7 +1,7 @@ /* * PowerPC emulation helpers for qemu. * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,6 +30,7 @@ //#define DEBUG_OP //#define DEBUG_EXCEPTIONS +//#define DEBUG_SOFTWARE_TLB //#define FLUSH_ALL_TLBS #define Ts0 (long)((target_long)T0) @@ -38,7 +39,7 @@ /*****************************************************************************/ /* Exceptions processing helpers */ -void cpu_loop_exit(void) +void cpu_loop_exit (void) { longjmp(env->jmp_env, 1); } @@ -50,22 +51,135 @@ void do_raise_exception_err (uint32_t exception, int error_code) #endif switch (exception) { case EXCP_PROGRAM: - if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) - return; - break; + if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) + return; + break; default: - break; -} + break; + } env->exception_index = exception; env->error_code = error_code; - cpu_loop_exit(); - } + cpu_loop_exit(); +} void do_raise_exception (uint32_t exception) { do_raise_exception_err(exception, 0); } +/*****************************************************************************/ +/* Registers load and stores */ +void do_load_cr (void) +{ + T0 = (env->crf[0] << 28) | + (env->crf[1] << 24) | + (env->crf[2] << 20) | + (env->crf[3] << 16) | + (env->crf[4] << 12) | + (env->crf[5] << 8) | + (env->crf[6] << 4) | + (env->crf[7] << 0); +} + +void do_store_cr (uint32_t mask) +{ + int i, sh; + + for (i = 0, sh = 7; i < 8; i++, sh --) { + if (mask & (1 << sh)) + env->crf[i] = (T0 >> (sh * 4)) & 0xFUL; + } +} + +void do_load_xer (void) +{ + T0 = (xer_so << XER_SO) | + (xer_ov << XER_OV) | + (xer_ca << XER_CA) | + (xer_bc << XER_BC) | + (xer_cmp << XER_CMP); +} + +void do_store_xer (void) +{ + xer_so = (T0 >> XER_SO) & 0x01; + xer_ov = (T0 >> XER_OV) & 0x01; + xer_ca = (T0 >> XER_CA) & 0x01; + xer_cmp = (T0 >> XER_CMP) & 0xFF; + xer_bc = (T0 >> XER_BC) & 0x3F; +} + +void do_load_fpscr (void) +{ + /* The 32 MSB of the target fpr are undefined. + * They'll be zero... + */ + union { + float64 d; + struct { + uint32_t u[2]; + } s; + } u; + int i; + +#ifdef WORDS_BIGENDIAN +#define WORD0 0 +#define WORD1 1 +#else +#define WORD0 1 +#define WORD1 0 +#endif + u.s.u[WORD0] = 0; + u.s.u[WORD1] = 0; + for (i = 0; i < 8; i++) + u.s.u[WORD1] |= env->fpscr[i] << (4 * i); + FT0 = u.d; +} + +void do_store_fpscr (uint32_t mask) +{ + /* + * We use only the 32 LSB of the incoming fpr + */ + union { + double d; + struct { + uint32_t u[2]; + } s; + } u; + int i, rnd_type; + + u.d = FT0; + if (mask & 0x80) + env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9); + for (i = 1; i < 7; i++) { + if (mask & (1 << (7 - i))) + env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF; + } + /* TODO: update FEX & VX */ + /* Set rounding mode */ + switch (env->fpscr[0] & 0x3) { + case 0: + /* Best approximation (round to nearest) */ + rnd_type = float_round_nearest_even; + break; + case 1: + /* Smaller magnitude (round toward zero) */ + rnd_type = float_round_to_zero; + break; + case 2: + /* Round toward +infinite */ + rnd_type = float_round_up; + break; + default: + case 3: + /* Round toward -infinite */ + rnd_type = float_round_down; + break; + } + set_float_rounding_mode(rnd_type, &env->fp_status); +} + /*****************************************************************************/ /* Fixed point operations helpers */ void do_addo (void) @@ -301,21 +415,21 @@ void do_sraw (void) if (likely(T1 != 0)) { ret = (int32_t)T0 >> (T1 & 0x1fUL); if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) { - xer_ca = 0; + xer_ca = 0; } else { - xer_ca = 1; + xer_ca = 1; } } else { - ret = T0; + ret = T0; xer_ca = 0; } } else { ret = (-1) * ((uint32_t)T0 >> 31); if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) { xer_ca = 0; - } else { + } else { xer_ca = 1; - } + } } T0 = ret; } @@ -330,7 +444,7 @@ void do_fctiw (void) } p; /* XXX: higher bits are not supposed to be significant. - * to make tests easier, return the same as a real PowerPC 750 (aka G3) + * to make tests easier, return the same as a real PowerPC 750 (aka G3) */ p.i = float64_to_int32(FT0, &env->fp_status); p.i |= 0xFFF80000ULL << 32; @@ -381,7 +495,7 @@ void do_fres (void) } p; if (likely(isnormal(FT0))) { - FT0 = (float)(1.0 / FT0); + FT0 = float32_div(1.0, FT0, &env->fp_status); } else { p.d = FT0; if (p.i == 0x8000000000000000ULL) { @@ -467,8 +581,8 @@ void do_fcmpo (void) } else { T0 = 0x01UL; env->fpscr[4] |= 0x1; - /* I don't know how to test "quiet" nan... */ - if (0 /* || ! quiet_nan(...) */) { + if (!float64_is_signaling_nan(FT0) || !float64_is_signaling_nan(FT1)) { + /* Quiet NaN case */ env->fpscr[6] |= 0x1; if (!(env->fpscr[1] & 0x8)) env->fpscr[4] |= 0x8; @@ -479,6 +593,7 @@ void do_fcmpo (void) env->fpscr[3] = T0; } +#if !defined (CONFIG_USER_ONLY) void do_rfi (void) { env->nip = env->spr[SPR_SRR0] & ~0x00000003; @@ -489,14 +604,15 @@ void do_rfi (void) #endif env->interrupt_request |= CPU_INTERRUPT_EXITTB; } +#endif -void do_tw (uint32_t cmp, int flags) +void do_tw (int flags) { - if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) || - (Ts0 > (int32_t)cmp && (flags & 0x08)) || - (Ts0 == (int32_t)cmp && (flags & 0x04)) || - (T0 < cmp && (flags & 0x02)) || - (T0 > cmp && (flags & 0x01))))) + if (!likely(!((Ts0 < Ts1 && (flags & 0x10)) || + (Ts0 > Ts1 && (flags & 0x08)) || + (Ts0 == Ts1 && (flags & 0x04)) || + (T0 < T1 && (flags & 0x02)) || + (T0 > T1 && (flags & 0x01))))) do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); } @@ -519,20 +635,311 @@ void do_icbi (void) } /*****************************************************************************/ -/* MMU related helpers */ -/* TLB invalidation helpers */ -void do_tlbia (void) +/* PowerPC 601 specific instructions (POWER bridge) */ +void do_POWER_abso (void) { - tlb_flush(env, 1); + if (T0 == INT32_MIN) { + T0 = INT32_MAX; + xer_ov = 1; + xer_so = 1; + } else { + T0 = -T0; + xer_ov = 0; + } } -void do_tlbie (void) +void do_POWER_clcs (void) { -#if !defined(FLUSH_ALL_TLBS) - tlb_flush_page(env, T0); + switch (T0) { + case 0x0CUL: + /* Instruction cache line size */ + T0 = ICACHE_LINE_SIZE; + break; + case 0x0DUL: + /* Data cache line size */ + T0 = DCACHE_LINE_SIZE; + break; + case 0x0EUL: + /* Minimum cache line size */ + T0 = ICACHE_LINE_SIZE < DCACHE_LINE_SIZE ? + ICACHE_LINE_SIZE : DCACHE_LINE_SIZE; + break; + case 0x0FUL: + /* Maximum cache line size */ + T0 = ICACHE_LINE_SIZE > DCACHE_LINE_SIZE ? + ICACHE_LINE_SIZE : DCACHE_LINE_SIZE; + break; + default: + /* Undefined */ + break; + } +} + +void do_POWER_div (void) +{ + uint64_t tmp; + + if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + T0 = (long)((-1) * (T0 >> 31)); + env->spr[SPR_MQ] = 0; + } else { + tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; + env->spr[SPR_MQ] = tmp % T1; + T0 = tmp / Ts1; + } +} + +void do_POWER_divo (void) +{ + int64_t tmp; + + if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + T0 = (long)((-1) * (T0 >> 31)); + env->spr[SPR_MQ] = 0; + xer_ov = 1; + xer_so = 1; + } else { + tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; + env->spr[SPR_MQ] = tmp % T1; + tmp /= Ts1; + if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) { + xer_ov = 1; + xer_so = 1; + } else { + xer_ov = 0; + } + T0 = tmp; + } +} + +void do_POWER_divs (void) +{ + if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + T0 = (long)((-1) * (T0 >> 31)); + env->spr[SPR_MQ] = 0; + } else { + env->spr[SPR_MQ] = T0 % T1; + T0 = Ts0 / Ts1; + } +} + +void do_POWER_divso (void) +{ + if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + T0 = (long)((-1) * (T0 >> 31)); + env->spr[SPR_MQ] = 0; + xer_ov = 1; + xer_so = 1; + } else { + T0 = Ts0 / Ts1; + env->spr[SPR_MQ] = Ts0 % Ts1; + xer_ov = 0; + } +} + +void do_POWER_dozo (void) +{ + if (Ts1 > Ts0) { + T2 = T0; + T0 = T1 - T0; + if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) { + xer_so = 1; + xer_ov = 1; + } else { + xer_ov = 0; + } + } else { + T0 = 0; + xer_ov = 0; + } +} + +void do_POWER_maskg (void) +{ + uint32_t ret; + + if (T0 == T1 + 1) { + ret = -1; + } else { + ret = (((uint32_t)(-1)) >> (T0)) ^ + (((uint32_t)(-1) >> (T1)) >> 1); + if (T0 > T1) + ret = ~ret; + } + T0 = ret; +} + +void do_POWER_mulo (void) +{ + uint64_t tmp; + + tmp = (uint64_t)T0 * (uint64_t)T1; + env->spr[SPR_MQ] = tmp >> 32; + T0 = tmp; + if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) { + xer_ov = 1; + xer_so = 1; + } else { + xer_ov = 0; + } +} + +#if !defined (CONFIG_USER_ONLY) +void do_POWER_rac (void) +{ +#if 0 + mmu_ctx_t ctx; + + /* We don't have to generate many instances of this instruction, + * as rac is supervisor only. + */ + if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT, 1) == 0) + T0 = ctx.raddr; +#endif +} + +void do_POWER_rfsvc (void) +{ + env->nip = env->lr & ~0x00000003UL; + T0 = env->ctr & 0x0000FFFFUL; + do_store_msr(env, T0); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request |= CPU_INTERRUPT_EXITTB; +} + +/* PowerPC 601 BAT management helper */ +void do_store_601_batu (int nr) +{ + do_store_ibatu(env, nr, T0); + env->DBAT[0][nr] = env->IBAT[0][nr]; + env->DBAT[1][nr] = env->IBAT[1][nr]; +} +#endif + +/*****************************************************************************/ +/* 602 specific instructions */ +/* mfrom is the most crazy instruction ever seen, imho ! */ +/* Real implementation uses a ROM table. Do the same */ +#define USE_MFROM_ROM_TABLE +void do_op_602_mfrom (void) +{ + if (likely(T0 < 602)) { +#ifdef USE_MFROM_ROM_TABLE +#include "mfrom_table.c" + T0 = mfrom_ROM_table[T0]; #else - do_tlbia(); + double d; + /* Extremly decomposed: + * -T0 / 256 + * T0 = 256 * log10(10 + 1.0) + 0.5 + */ + d = T0; + d = float64_div(d, 256, &env->fp_status); + d = float64_chs(d); + d = exp10(d); // XXX: use float emulation function + d = float64_add(d, 1.0, &env->fp_status); + d = log10(d); // XXX: use float emulation function + d = float64_mul(d, 256, &env->fp_status); + d = float64_add(d, 0.5, &env->fp_status); + T0 = float64_round_to_int(d, &env->fp_status); #endif + } else { + T0 = 0; + } +} + +/*****************************************************************************/ +/* Embedded PowerPC specific helpers */ +void do_405_check_ov (void) +{ + if (likely(((T1 ^ T2) >> 31) || !((T0 ^ T2) >> 31))) { + xer_ov = 0; + } else { + xer_ov = 1; + xer_so = 1; + } +} + +void do_405_check_sat (void) +{ + if (!likely(((T1 ^ T2) >> 31) || !((T0 ^ T2) >> 31))) { + /* Saturate result */ + if (T2 >> 31) { + T0 = INT32_MIN; + } else { + T0 = INT32_MAX; + } + } +} + +#if !defined(CONFIG_USER_ONLY) +void do_4xx_rfci (void) +{ + env->nip = env->spr[SPR_40x_SRR2]; + T0 = env->spr[SPR_40x_SRR3] & ~0xFFFF0000; + do_store_msr(env, T0); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request = CPU_INTERRUPT_EXITTB; +} + +void do_4xx_load_dcr (int dcrn) +{ + target_ulong val; + + if (unlikely(env->dcr_read == NULL)) + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); + else if (unlikely((*env->dcr_read)(env->dcr_env, dcrn, &val) != 0)) + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); + else + T0 = val; +} + +void do_4xx_store_dcr (int dcrn) +{ + if (unlikely(env->dcr_write == NULL)) + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); + else if (unlikely((*env->dcr_write)(env->dcr_env, dcrn, T0) != 0)) + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); +} + +void do_load_403_pb (int num) +{ + T0 = env->pb[num]; +} + +void do_store_403_pb (int num) +{ + if (likely(env->pb[num] != T0)) { + env->pb[num] = T0; + /* Should be optimized */ + tlb_flush(env, 1); + } +} +#endif + +/* 440 specific */ +void do_440_dlmzb (void) +{ + target_ulong mask; + int i; + + i = 1; + for (mask = 0xFF000000; mask != 0; mask = mask >> 8) { + if ((T0 & mask) == 0) + goto done; + i++; + } + for (mask = 0xFF000000; mask != 0; mask = mask >> 8) { + if ((T1 & mask) == 0) + break; + i++; + } + done: + T0 = i; } /*****************************************************************************/ @@ -570,7 +977,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) saved_env = env; env = cpu_single_env; ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); - if (!likely(ret == 0)) { + if (unlikely(ret != 0)) { if (likely(retaddr)) { /* now we have a real cpu fault */ pc = (target_phys_addr_t)retaddr; @@ -579,11 +986,230 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) /* the PC is inside the translated code. It means that we have a virtual CPU fault */ cpu_restore_state(tb, env, pc, NULL); -} + } } do_raise_exception_err(env->exception_index, env->error_code); } env = saved_env; } -#endif /* !CONFIG_USER_ONLY */ +/* TLB invalidation helpers */ +void do_tlbia (void) +{ + if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + ppc6xx_tlb_invalidate_all(env); + } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + /* XXX: TODO */ +#if 0 + ppcbooke_tlb_invalidate_all(env); +#endif + } else { + tlb_flush(env, 1); + } +} + +void do_tlbie (void) +{ +#if !defined(FLUSH_ALL_TLBS) + if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); + if (env->id_tlbs == 1) + ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1); + } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + /* XXX: TODO */ +#if 0 + ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, + env->spr[SPR_BOOKE_PID]); +#endif + } else { + /* tlbie invalidate TLBs for all segments */ + T0 &= TARGET_PAGE_MASK; + T0 &= ~((target_ulong)-1 << 28); + /* XXX: this case should be optimized, + * giving a mask to tlb_flush_page + */ + tlb_flush_page(env, T0 | (0x0 << 28)); + tlb_flush_page(env, T0 | (0x1 << 28)); + tlb_flush_page(env, T0 | (0x2 << 28)); + tlb_flush_page(env, T0 | (0x3 << 28)); + tlb_flush_page(env, T0 | (0x4 << 28)); + tlb_flush_page(env, T0 | (0x5 << 28)); + tlb_flush_page(env, T0 | (0x6 << 28)); + tlb_flush_page(env, T0 | (0x7 << 28)); + tlb_flush_page(env, T0 | (0x8 << 28)); + tlb_flush_page(env, T0 | (0x9 << 28)); + tlb_flush_page(env, T0 | (0xA << 28)); + tlb_flush_page(env, T0 | (0xB << 28)); + tlb_flush_page(env, T0 | (0xC << 28)); + tlb_flush_page(env, T0 | (0xD << 28)); + tlb_flush_page(env, T0 | (0xE << 28)); + tlb_flush_page(env, T0 | (0xF << 28)); + } +#else + do_tlbia(); +#endif +} + +/* Software driven TLBs management */ +/* PowerPC 602/603 software TLB load instructions helpers */ +void do_load_6xx_tlb (int is_code) +{ + target_ulong RPN, CMP, EPN; + int way; + + RPN = env->spr[SPR_RPA]; + if (is_code) { + CMP = env->spr[SPR_ICMP]; + EPN = env->spr[SPR_IMISS]; + } else { + CMP = env->spr[SPR_DCMP]; + EPN = env->spr[SPR_DMISS]; + } + way = (env->spr[SPR_SRR1] >> 17) & 1; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n", + __func__, (unsigned long)T0, (unsigned long)EPN, + (unsigned long)CMP, (unsigned long)RPN, way); + } +#endif + /* Store this TLB */ + ppc6xx_tlb_store(env, T0 & TARGET_PAGE_MASK, way, is_code, CMP, RPN); +} + +/* Helpers for 4xx TLB management */ +void do_4xx_tlbia (void) +{ +#if 0 + ppc_tlb_t *tlb; + target_ulong page, end; + int i; + + for (i = 0; i < 64; i++) { + tlb = &env->tlb[i]; + if (tlb->prot & PAGE_VALID) { + end = tlb->EPN + tlb->size; + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) + tlb_flush_page(env, page); + tlb->prot &= ~PAGE_VALID; + } + } +#endif +} + +void do_4xx_tlbre_lo (void) +{ +#if 0 + ppc_tlb_t *tlb; + + T0 &= 0x3F; + tlb = &env->tlb[T0]; + T0 = tlb->stor[0]; + env->spr[SPR_40x_PID] = tlb->pid; +#endif +} + +void do_4xx_tlbre_hi (void) +{ +#if 0 + ppc_tlb_t *tlb; + + T0 &= 0x3F; + tlb = &env->tlb[T0]; + T0 = tlb->stor[1]; +#endif +} + +static int tlb_4xx_search (target_ulong virtual) +{ +#if 0 + ppc_tlb_t *tlb; + target_ulong base, mask; + int i, ret; + + /* Default return value is no match */ + ret = -1; + for (i = 0; i < 64; i++) { + tlb = &env->tlb[i]; + /* Check TLB validity */ + if (!(tlb->prot & PAGE_VALID)) + continue; + /* Check TLB PID vs current PID */ + if (tlb->pid != 0 && tlb->pid != env->spr[SPR_40x_PID]) + continue; + /* Check TLB address vs virtual address */ + base = tlb->EPN; + mask = ~(tlb->size - 1); + if ((base & mask) != (virtual & mask)) + continue; + ret = i; + break; + } + + return ret; +#else + return -1; +#endif +} + +void do_4xx_tlbsx (void) +{ + T0 = tlb_4xx_search(T0); +} + +void do_4xx_tlbsx_ (void) +{ + int tmp = xer_ov; + + T0 = tlb_4xx_search(T0); + if (T0 != -1) + tmp |= 0x02; + env->crf[0] = tmp; +} + +void do_4xx_tlbwe_lo (void) +{ +#if 0 + ppc_tlb_t *tlb; + target_ulong page, end; + + T0 &= 0x3F; + tlb = &env->tlb[T0]; + /* Invalidate previous TLB (if it's valid) */ + if (tlb->prot & PAGE_VALID) { + end = tlb->EPN + tlb->size; + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) + tlb_flush_page(env, page); + } + tlb->size = 1024 << (2 * ((T1 >> 7) & 0x7)); + tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); + if (T1 & 0x400) + tlb->prot |= PAGE_VALID; + else + tlb->prot &= ~PAGE_VALID; + tlb->pid = env->spr[SPR_BOOKE_PID]; /* PID */ + /* Invalidate new TLB (if valid) */ + if (tlb->prot & PAGE_VALID) { + end = tlb->EPN + tlb->size; + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) + tlb_flush_page(env, page); + } +#endif +} + +void do_4xx_tlbwe_hi (void) +{ +#if 0 + ppc_tlb_t *tlb; + + T0 &= 0x3F; + tlb = &env->tlb[T0]; + tlb->RPN = T1 & 0xFFFFFC00; + tlb->prot = PAGE_READ; + if (T1 & 0x200) + tlb->prot |= PAGE_EXEC; + if (T1 & 0x100) + tlb->prot |= PAGE_WRITE; +#endif +} +#endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h new file mode 100644 index 000000000..0cba00204 --- /dev/null +++ b/target-ppc/op_helper.h @@ -0,0 +1,132 @@ +/* + * PowerPC emulation helpers header for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * 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(MEMSUFFIX) + +/* Memory load/store helpers */ +void glue(do_lsw, MEMSUFFIX) (int dst); +void glue(do_lsw_le, MEMSUFFIX) (int dst); +void glue(do_stsw, MEMSUFFIX) (int src); +void glue(do_stsw_le, MEMSUFFIX) (int src); +void glue(do_lmw, MEMSUFFIX) (int dst); +void glue(do_lmw_le, MEMSUFFIX) (int dst); +void glue(do_stmw, MEMSUFFIX) (int src); +void glue(do_stmw_le, MEMSUFFIX) (int src); +void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb); +void glue(do_POWER2_lfq, MEMSUFFIX) (void); +void glue(do_POWER2_lfq_le, MEMSUFFIX) (void); +void glue(do_POWER2_stfq, MEMSUFFIX) (void); +void glue(do_POWER2_stfq_le, MEMSUFFIX) (void); + +#else + +/* Registers load and stores */ +void do_load_cr (void); +void do_store_cr (uint32_t mask); +void do_load_xer (void); +void do_store_xer (void); +void do_load_fpscr (void); +void do_store_fpscr (uint32_t mask); + +/* Integer arithmetic helpers */ +void do_addo (void); +void do_addco (void); +void do_adde (void); +void do_addeo (void); +void do_addmeo (void); +void do_addzeo (void); +void do_divwo (void); +void do_divwuo (void); +void do_mullwo (void); +void do_nego (void); +void do_subfo (void); +void do_subfco (void); +void do_subfe (void); +void do_subfeo (void); +void do_subfmeo (void); +void do_subfzeo (void); +void do_sraw(void); + +/* Floating-point arithmetic helpers */ +void do_fsqrt (void); +void do_fres (void); +void do_frsqrte (void); +void do_fsel (void); +void do_fnmadd (void); +void do_fnmsub (void); +void do_fctiw (void); +void do_fctiwz (void); +void do_fcmpu (void); +void do_fcmpo (void); + +void do_tw (int flags); +void do_icbi (void); + +#if !defined(CONFIG_USER_ONLY) +void do_rfi (void); +void do_tlbia (void); +void do_tlbie (void); +void do_load_6xx_tlb (int is_code); +#endif + +/* POWER / PowerPC 601 specific helpers */ +void do_store_601_batu (int nr); +void do_POWER_abso (void); +void do_POWER_clcs (void); +void do_POWER_div (void); +void do_POWER_divo (void); +void do_POWER_divs (void); +void do_POWER_divso (void); +void do_POWER_dozo (void); +void do_POWER_maskg (void); +void do_POWER_mulo (void); +#if !defined(CONFIG_USER_ONLY) +void do_POWER_rac (void); +void do_POWER_rfsvc (void); +#endif + +/* PowerPC 602 specific helper */ +#if !defined(CONFIG_USER_ONLY) +void do_op_602_mfrom (void); +#endif + +/* PowerPC 4xx specific helpers */ +void do_405_check_ov (void); +void do_405_check_sat (void); +#if !defined(CONFIG_USER_ONLY) +void do_4xx_load_dcr (int dcrn); +void do_4xx_store_dcr (int dcrn); +void do_4xx_rfci (void); +void do_4xx_tlbre_lo (void); +void do_4xx_tlbre_hi (void); +void do_4xx_tlbsx (void); +void do_4xx_tlbsx_ (void); +void do_4xx_tlbwe_lo (void); +void do_4xx_tlbwe_hi (void); +#endif + +void do_440_dlmzb (void); + +#if !defined(CONFIG_USER_ONLY) +void do_load_403_pb (int num); +void do_store_403_pb (int num); +#endif + +#endif diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index fb90691f2..45bb90d8a 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -1,20 +1,78 @@ +/* + * PowerPC emulation micro-operations helpers for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * 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 + */ + +/* Multiple word / string load and store */ +static inline target_ulong glue(ld32r, MEMSUFFIX) (target_ulong EA) +{ + uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); + return ((tmp & 0xFF000000UL) >> 24) | ((tmp & 0x00FF0000UL) >> 8) | + ((tmp & 0x0000FF00UL) << 8) | ((tmp & 0x000000FFUL) << 24); +} + +static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, target_ulong data) +{ + uint32_t tmp = + ((data & 0xFF000000UL) >> 24) | ((data & 0x00FF0000UL) >> 8) | + ((data & 0x0000FF00UL) << 8) | ((data & 0x000000FFUL) << 24); + glue(stl, MEMSUFFIX)(EA, tmp); +} + +void glue(do_lmw, MEMSUFFIX) (int dst) +{ + for (; dst < 32; dst++, T0 += 4) { + ugpr(dst) = glue(ldl, MEMSUFFIX)(T0); + } +} + +void glue(do_stmw, MEMSUFFIX) (int src) +{ + for (; src < 32; src++, T0 += 4) { + glue(stl, MEMSUFFIX)(T0, ugpr(src)); + } +} + +void glue(do_lmw_le, MEMSUFFIX) (int dst) +{ + for (; dst < 32; dst++, T0 += 4) { + ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0); + } +} + +void glue(do_stmw_le, MEMSUFFIX) (int src) +{ + for (; src < 32; src++, T0 += 4) { + glue(st32r, MEMSUFFIX)(T0, ugpr(src)); + } +} + void glue(do_lsw, MEMSUFFIX) (int dst) { uint32_t tmp; int sh; -#if 0 - if (loglevel > 0) { - fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", - __func__, T0, T1, dst); - } -#endif for (; T1 > 3; T1 -= 4, T0 += 4) { ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0); - if (dst == 32) + if (unlikely(dst == 32)) dst = 0; } - if (T1 > 0) { + if (unlikely(T1 != 0)) { tmp = 0; for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { tmp |= glue(ldub, MEMSUFFIX)(T0) << sh; @@ -27,18 +85,12 @@ void glue(do_stsw, MEMSUFFIX) (int src) { int sh; -#if 0 - if (loglevel > 0) { - fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", - __func__, T0, T1, src); - } -#endif for (; T1 > 3; T1 -= 4, T0 += 4) { glue(stl, MEMSUFFIX)(T0, ugpr(src++)); - if (src == 32) + if (unlikely(src == 32)) src = 0; } - if (T1 > 0) { + if (unlikely(T1 != 0)) { for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF); } @@ -49,20 +101,12 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst) uint32_t tmp; int sh; -#if 0 - if (loglevel > 0) { - fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", - __func__, T0, T1, dst); - } -#endif for (; T1 > 3; T1 -= 4, T0 += 4) { - tmp = glue(ldl, MEMSUFFIX)(T0); - ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | - ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); - if (dst == 32) + ugpr(dst++) = glue(ld32r, MEMSUFFIX)(T0); + if (unlikely(dst == 32)) dst = 0; } - if (T1 > 0) { + if (unlikely(T1 != 0)) { tmp = 0; for (sh = 0; T1 > 0; T1--, T0++, sh += 8) { tmp |= glue(ldub, MEMSUFFIX)(T0) << sh; @@ -73,28 +117,108 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst) void glue(do_stsw_le, MEMSUFFIX) (int src) { - uint32_t tmp; int sh; -#if 0 - if (loglevel > 0) { - fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n", - __func__, T0, T1, src); - } -#endif for (; T1 > 3; T1 -= 4, T0 += 4) { - tmp = ((ugpr(src++) & 0xFF000000) >> 24); - tmp |= ((ugpr(src++) & 0x00FF0000) >> 8); - tmp |= ((ugpr(src++) & 0x0000FF00) << 8); - tmp |= ((ugpr(src++) & 0x000000FF) << 24); - glue(stl, MEMSUFFIX)(T0, tmp); - if (src == 32) + glue(st32r, MEMSUFFIX)(T0, ugpr(src++)); + if (unlikely(src == 32)) src = 0; } - if (T1 > 0) { + if (unlikely(T1 != 0)) { for (sh = 0; T1 > 0; T1--, T0++, sh += 8) glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF); } } +/* PPC 601 specific instructions (POWER bridge) */ +// XXX: to be tested +void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb) +{ + int i, c, d, reg; + + d = 24; + reg = dest; + for (i = 0; i < T1; i++) { + c = glue(ldub, MEMSUFFIX)(T0++); + /* ra (if not 0) and rb are never modified */ + if (likely(reg != rb && (ra == 0 || reg != ra))) { + ugpr(reg) = (ugpr(reg) & ~(0xFF << d)) | (c << d); + } + if (unlikely(c == T2)) + break; + if (likely(d != 0)) { + d -= 8; + } else { + d = 24; + reg++; + reg = reg & 0x1F; + } + } + T0 = i; +} + +/* XXX: TAGs are not managed */ +void glue(do_POWER2_lfq, MEMSUFFIX) (void) +{ + FT0 = glue(ldfq, MEMSUFFIX)(T0); + FT1 = glue(ldfq, MEMSUFFIX)(T0 + 4); +} + +static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) +{ + union { + double d; + uint64_t u; + } u; + + u.d = glue(ldfq, MEMSUFFIX)(EA); + u.u = ((u.u & 0xFF00000000000000ULL) >> 56) | + ((u.u & 0x00FF000000000000ULL) >> 40) | + ((u.u & 0x0000FF0000000000ULL) >> 24) | + ((u.u & 0x000000FF00000000ULL) >> 8) | + ((u.u & 0x00000000FF000000ULL) << 8) | + ((u.u & 0x0000000000FF0000ULL) << 24) | + ((u.u & 0x000000000000FF00ULL) << 40) | + ((u.u & 0x00000000000000FFULL) << 56); + + return u.d; +} + +void glue(do_POWER2_lfq_le, MEMSUFFIX) (void) +{ + FT0 = glue(ldfqr, MEMSUFFIX)(T0 + 4); + FT1 = glue(ldfqr, MEMSUFFIX)(T0); +} + +void glue(do_POWER2_stfq, MEMSUFFIX) (void) +{ + glue(stfq, MEMSUFFIX)(T0, FT0); + glue(stfq, MEMSUFFIX)(T0 + 4, FT1); +} + +static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) +{ + union { + double d; + uint64_t u; + } u; + + u.d = d; + u.u = ((u.u & 0xFF00000000000000ULL) >> 56) | + ((u.u & 0x00FF000000000000ULL) >> 40) | + ((u.u & 0x0000FF0000000000ULL) >> 24) | + ((u.u & 0x000000FF00000000ULL) >> 8) | + ((u.u & 0x00000000FF000000ULL) << 8) | + ((u.u & 0x0000000000FF0000ULL) << 24) | + ((u.u & 0x000000000000FF00ULL) << 40) | + ((u.u & 0x00000000000000FFULL) << 56); + glue(stfq, MEMSUFFIX)(EA, u.d); +} + +void glue(do_POWER2_stfq_le, MEMSUFFIX) (void) +{ + glue(stfqr, MEMSUFFIX)(T0 + 4, FT0); + glue(stfqr, MEMSUFFIX)(T0, FT1); +} + #undef MEMSUFFIX diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 9b3f721e5..a084b3194 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -1,6 +1,22 @@ -/* External helpers */ -void glue(do_lsw, MEMSUFFIX) (int dst); -void glue(do_stsw, MEMSUFFIX) (int src); +/* + * PowerPC emulation micro-operations for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * 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 + */ static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA) { @@ -11,7 +27,7 @@ static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA) static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA) { int16_t tmp = glue(lduw, MEMSUFFIX)(EA); - return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); + return (int16_t)((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); } static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) @@ -80,41 +96,25 @@ PPC_ST_OP(wbr_le, stl); /*** Integer load and store multiple ***/ PPC_OP(glue(lmw, MEMSUFFIX)) { - int dst = PARAM(1); - - for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ldl, MEMSUFFIX)(T0); - } + glue(do_lmw, MEMSUFFIX)(PARAM1); RETURN(); } -PPC_OP(glue(stmw, MEMSUFFIX)) +PPC_OP(glue(lmw_le, MEMSUFFIX)) { - int src = PARAM(1); - - for (; src < 32; src++, T0 += 4) { - glue(stl, MEMSUFFIX)(T0, ugpr(src)); - } + glue(do_lmw_le, MEMSUFFIX)(PARAM1); RETURN(); } -PPC_OP(glue(lmw_le, MEMSUFFIX)) +PPC_OP(glue(stmw, MEMSUFFIX)) { - int dst = PARAM(1); - - for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0); - } + glue(do_stmw, MEMSUFFIX)(PARAM1); RETURN(); } PPC_OP(glue(stmw_le, MEMSUFFIX)) { - int src = PARAM(1); - - for (; src < 32; src++, T0 += 4) { - glue(st32r, MEMSUFFIX)(T0, ugpr(src)); - } + glue(do_stmw_le, MEMSUFFIX)(PARAM1); RETURN(); } @@ -125,7 +125,6 @@ PPC_OP(glue(lswi, MEMSUFFIX)) RETURN(); } -void glue(do_lsw_le, MEMSUFFIX) (int dst); PPC_OP(glue(lswi_le, MEMSUFFIX)) { glue(do_lsw_le, MEMSUFFIX)(PARAM(1)); @@ -139,9 +138,9 @@ PPC_OP(glue(lswi_le, MEMSUFFIX)) */ PPC_OP(glue(lswx, MEMSUFFIX)) { - if (T1 > 0) { - if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) || - (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) { + if (unlikely(T1 > 0)) { + if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || + (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); } else { glue(do_lsw, MEMSUFFIX)(PARAM(1)); @@ -152,9 +151,9 @@ PPC_OP(glue(lswx, MEMSUFFIX)) PPC_OP(glue(lswx_le, MEMSUFFIX)) { - if (T1 > 0) { - if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) || - (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) { + if (unlikely(T1 > 0)) { + if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || + (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); } else { glue(do_lsw_le, MEMSUFFIX)(PARAM(1)); @@ -169,7 +168,6 @@ PPC_OP(glue(stsw, MEMSUFFIX)) RETURN(); } -void glue(do_stsw_le, MEMSUFFIX) (int src); PPC_OP(glue(stsw_le, MEMSUFFIX)) { glue(do_stsw_le, MEMSUFFIX)(PARAM(1)); @@ -180,7 +178,7 @@ PPC_OP(glue(stsw_le, MEMSUFFIX)) #define PPC_STF_OP(name, op) \ PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ { \ - glue(op, MEMSUFFIX)(T0, FT1); \ + glue(op, MEMSUFFIX)(T0, FT0); \ RETURN(); \ } @@ -228,7 +226,7 @@ PPC_STF_OP(fs_le, stflr); #define PPC_LDF_OP(name, op) \ PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ { \ - FT1 = glue(op, MEMSUFFIX)(T0); \ + FT0 = glue(op, MEMSUFFIX)(T0); \ RETURN(); \ } @@ -277,22 +275,22 @@ PPC_LDF_OP(fs_le, ldflr); /* Load and set reservation */ PPC_OP(glue(lwarx, MEMSUFFIX)) { - if (T0 & 0x03) { + if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - T1 = glue(ldl, MEMSUFFIX)(T0); - regs->reserve = T0; + T1 = glue(ldl, MEMSUFFIX)(T0); + regs->reserve = T0; } RETURN(); } PPC_OP(glue(lwarx_le, MEMSUFFIX)) { - if (T0 & 0x03) { + if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - T1 = glue(ld32r, MEMSUFFIX)(T0); - regs->reserve = T0; + T1 = glue(ld32r, MEMSUFFIX)(T0); + regs->reserve = T0; } RETURN(); } @@ -300,33 +298,33 @@ PPC_OP(glue(lwarx_le, MEMSUFFIX)) /* Store with reservation */ PPC_OP(glue(stwcx, MEMSUFFIX)) { - if (T0 & 0x03) { + if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (regs->reserve != T0) { + if (unlikely(regs->reserve != T0)) { env->crf[0] = xer_ov; } else { glue(stl, MEMSUFFIX)(T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = 0; + regs->reserve = -1; RETURN(); } PPC_OP(glue(stwcx_le, MEMSUFFIX)) { - if (T0 & 0x03) { + if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (regs->reserve != T0) { + if (unlikely(regs->reserve != T0)) { env->crf[0] = xer_ov; } else { glue(st32r, MEMSUFFIX)(T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = 0; + regs->reserve = -1; RETURN(); } @@ -340,6 +338,17 @@ PPC_OP(glue(dcbz, MEMSUFFIX)) glue(stl, MEMSUFFIX)(T0 + 0x14, 0); glue(stl, MEMSUFFIX)(T0 + 0x18, 0); glue(stl, MEMSUFFIX)(T0 + 0x1C, 0); +#if DCACHE_LINE_SIZE == 64 + /* XXX: cache line size should be 64 for POWER & PowerPC 601 */ + glue(stl, MEMSUFFIX)(T0 + 0x20UL, 0); + glue(stl, MEMSUFFIX)(T0 + 0x24UL, 0); + glue(stl, MEMSUFFIX)(T0 + 0x28UL, 0); + glue(stl, MEMSUFFIX)(T0 + 0x2CUL, 0); + glue(stl, MEMSUFFIX)(T0 + 0x30UL, 0); + glue(stl, MEMSUFFIX)(T0 + 0x34UL, 0); + glue(stl, MEMSUFFIX)(T0 + 0x38UL, 0); + glue(stl, MEMSUFFIX)(T0 + 0x3CUL, 0); +#endif RETURN(); } @@ -368,4 +377,41 @@ PPC_OP(glue(ecowx_le, MEMSUFFIX)) RETURN(); } +/* XXX: those micro-ops need tests ! */ +/* PowerPC 601 specific instructions (POWER bridge) */ +void OPPROTO glue(op_POWER_lscbx, MEMSUFFIX) (void) +{ + /* When byte count is 0, do nothing */ + if (likely(T1 > 0)) { + glue(do_POWER_lscbx, MEMSUFFIX)(PARAM1, PARAM2, PARAM3); + } + RETURN(); +} + +/* POWER2 quad load and store */ +/* XXX: TAGs are not managed */ +void OPPROTO glue(op_POWER2_lfq, MEMSUFFIX) (void) +{ + glue(do_POWER2_lfq, MEMSUFFIX)(); + RETURN(); +} + +void glue(op_POWER2_lfq_le, MEMSUFFIX) (void) +{ + glue(do_POWER2_lfq_le, MEMSUFFIX)(); + RETURN(); +} + +void OPPROTO glue(op_POWER2_stfq, MEMSUFFIX) (void) +{ + glue(do_POWER2_stfq, MEMSUFFIX)(); + RETURN(); +} + +void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void) +{ + glue(do_POWER2_stfq_le, MEMSUFFIX)(); + RETURN(); +} + #undef MEMSUFFIX diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 1be640d6d..511d065f6 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -1,7 +1,7 @@ /* * PowerPC emulation micro-operations for qemu. * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,107 +19,97 @@ */ /* General purpose registers moves */ -void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void) +void OPPROTO glue(op_load_gpr_T0_gpr, REG) (void) { T0 = regs->gpr[REG]; RETURN(); } -void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void) +void OPPROTO glue(op_load_gpr_T1_gpr, REG) (void) { T1 = regs->gpr[REG]; RETURN(); } -void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void) +void OPPROTO glue(op_load_gpr_T2_gpr, REG) (void) { T2 = regs->gpr[REG]; RETURN(); } -void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void) +void OPPROTO glue(op_store_T0_gpr_gpr, REG) (void) { regs->gpr[REG] = T0; RETURN(); } -void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void) +void OPPROTO glue(op_store_T1_gpr_gpr, REG) (void) { regs->gpr[REG] = T1; RETURN(); } -void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void) +#if 0 // unused +void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) { regs->gpr[REG] = T2; RETURN(); } +#endif #if REG <= 7 /* Condition register moves */ -void OPPROTO glue(op_load_crf_T0_crf, REG)(void) +void OPPROTO glue(op_load_crf_T0_crf, REG) (void) { T0 = regs->crf[REG]; RETURN(); } -void OPPROTO glue(op_load_crf_T1_crf, REG)(void) +void OPPROTO glue(op_load_crf_T1_crf, REG) (void) { T1 = regs->crf[REG]; RETURN(); } -void OPPROTO glue(op_store_T0_crf_crf, REG)(void) +void OPPROTO glue(op_store_T0_crf_crf, REG) (void) { regs->crf[REG] = T0; RETURN(); } -void OPPROTO glue(op_store_T1_crf_crf, REG)(void) +void OPPROTO glue(op_store_T1_crf_crf, REG) (void) { regs->crf[REG] = T1; RETURN(); } /* Floating point condition and status register moves */ -void OPPROTO glue(op_load_fpscr_T0_fpscr, REG)(void) +void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void) { T0 = regs->fpscr[REG]; RETURN(); } #if REG == 0 -void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void) +void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void) { regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9); RETURN(); } -void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void) -{ - regs->fpscr[REG] = (regs->fpscr[REG] & ~0x9) | (PARAM(1) & 0x9); - RETURN(); -} - -void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void) +void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void) { regs->fpscr[REG] = (regs->fpscr[REG] & 0x9); RETURN(); } #else -void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void) +void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void) { regs->fpscr[REG] = T0; RETURN(); } -void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void) -{ - regs->fpscr[REG] = PARAM(1); - RETURN(); -} - -void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void) +void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void) { regs->fpscr[REG] = 0x0; RETURN(); @@ -129,55 +119,42 @@ void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void) #endif /* REG <= 7 */ /* floating point registers moves */ -void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void) +void OPPROTO glue(op_load_fpr_FT0_fpr, REG) (void) { FT0 = env->fpr[REG]; RETURN(); } -void OPPROTO glue(op_store_FT0_fpr_fpr, REG)(void) +void OPPROTO glue(op_store_FT0_fpr_fpr, REG) (void) { env->fpr[REG] = FT0; RETURN(); } -void OPPROTO glue(op_load_fpr_FT1_fpr, REG)(void) +void OPPROTO glue(op_load_fpr_FT1_fpr, REG) (void) { FT1 = env->fpr[REG]; RETURN(); } -void OPPROTO glue(op_store_FT1_fpr_fpr, REG)(void) +void OPPROTO glue(op_store_FT1_fpr_fpr, REG) (void) { env->fpr[REG] = FT1; RETURN(); } -void OPPROTO glue(op_load_fpr_FT2_fpr, REG)(void) +void OPPROTO glue(op_load_fpr_FT2_fpr, REG) (void) { FT2 = env->fpr[REG]; RETURN(); } -void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void) +#if 0 // unused +void OPPROTO glue(op_store_FT2_fpr_fpr, REG) (void) { env->fpr[REG] = FT2; RETURN(); } - -#if REG <= 15 -/* Segment register moves */ -void OPPROTO glue(op_load_sr, REG)(void) -{ - T0 = env->sr[REG]; - RETURN(); -} - -void OPPROTO glue(op_store_sr, REG)(void) -{ - do_store_sr(env, REG, T0); - RETURN(); -} #endif #undef REG diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 41737d4a8..1e6c9cb8d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1,7 +1,7 @@ /* * PowerPC emulation for qemu: main translation routines. * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,6 +29,7 @@ //#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS +//#define DO_PPC_STATISTICS #ifdef USE_DIRECT_JUMP #define TBPARAM(x) @@ -96,25 +97,12 @@ GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf); GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr); GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr); GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr); -static GenOpFunc1 *gen_op_store_T0_fpscri_fpscr_table[8] = { - &gen_op_store_T0_fpscri_fpscr0, - &gen_op_store_T0_fpscri_fpscr1, - &gen_op_store_T0_fpscri_fpscr2, - &gen_op_store_T0_fpscri_fpscr3, - &gen_op_store_T0_fpscri_fpscr4, - &gen_op_store_T0_fpscri_fpscr5, - &gen_op_store_T0_fpscri_fpscr6, - &gen_op_store_T0_fpscri_fpscr7, -}; static inline void gen_op_store_T0_fpscri(int n, uint8_t param) { - (*gen_op_store_T0_fpscri_fpscr_table[n])(param); + gen_op_set_T0(param); + gen_op_store_T0_fpscr(n); } -/* Segment register moves */ -GEN16(gen_op_load_sr, gen_op_load_sr); -GEN16(gen_op_store_sr, gen_op_store_sr); - /* General purpose registers moves */ GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr); @@ -122,7 +110,9 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); +#if 0 // unused GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr); +#endif /* floating point registers moves */ GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr); @@ -130,9 +120,9 @@ GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr); GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr); GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr); GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr); +#if 0 // unused GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr); - -static uint8_t spr_access[1024 / 2]; +#endif /* internal defines */ typedef struct DisasContext { @@ -158,8 +148,18 @@ struct opc_handler_t { uint32_t type; /* handler */ void (*handler)(DisasContext *ctx); +#if defined(DO_PPC_STATISTICS) + const unsigned char *oname; + uint64_t count; +#endif }; +static inline void gen_set_Rc0 (DisasContext *ctx) +{ + gen_op_cmpi(0); + gen_op_set_Rc0(); +} + #define RET_EXCP(ctx, excp, error) \ do { \ if ((ctx)->exception == EXCP_NONE) { \ @@ -209,13 +209,13 @@ typedef struct opcode_t { /*** Instruction decoding ***/ #define EXTRACT_HELPER(name, shift, nb) \ -static inline uint32_t name (uint32_t opcode) \ +static inline target_ulong name (uint32_t opcode) \ { \ return (opcode >> (shift)) & ((1 << (nb)) - 1); \ } #define EXTRACT_SHELPER(name, shift, nb) \ -static inline int32_t name (uint32_t opcode) \ +static inline target_long name (uint32_t opcode) \ { \ return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \ } @@ -278,7 +278,7 @@ EXTRACT_HELPER(FPIMM, 20, 4); /* Displacement */ EXTRACT_SHELPER(d, 0, 16); /* Immediate address */ -static inline uint32_t LI (uint32_t opcode) +static inline target_ulong LI (uint32_t opcode) { return (opcode >> 0) & 0x03FFFFFC; } @@ -296,13 +296,29 @@ EXTRACT_HELPER(AA, 1, 1); EXTRACT_HELPER(LK, 0, 1); /* Create a mask between and bits */ -static inline uint32_t MASK (uint32_t start, uint32_t end) +static inline target_ulong MASK (uint32_t start, uint32_t end) { - uint32_t ret; + target_ulong ret; - ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1); - if (start > end) - return ~ret; +#if defined(TARGET_PPC64) + if (likely(start == 0)) { + ret = (uint64_t)(-1ULL) << (63 - end); + } else if (likely(end == 63)) { + ret = (uint64_t)(-1ULL) >> start; + } +#else + if (likely(start == 0)) { + ret = (uint32_t)(-1ULL) << (31 - end); + } else if (likely(end == 31)) { + ret = (uint32_t)(-1ULL) >> start; + } +#endif + else { + ret = (((target_ulong)(-1ULL)) >> (start)) ^ + (((target_ulong)(-1ULL) >> (end)) >> 1); + if (unlikely(start > end)) + return ~ret; + } return ret; } @@ -320,6 +336,7 @@ static inline uint32_t MASK (uint32_t start, uint32_t end) __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) )) #endif +#if defined(DO_PPC_STATISTICS) #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ OPCODES_SECTION opcode_t opc_##name = { \ .opc1 = op1, \ @@ -330,9 +347,25 @@ OPCODES_SECTION opcode_t opc_##name = { \ .inval = invl, \ .type = _typ, \ .handler = &gen_##name, \ + .oname = stringify(name), \ }, \ .oname = stringify(name), \ } +#else +#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ +OPCODES_SECTION opcode_t opc_##name = { \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval = invl, \ + .type = _typ, \ + .handler = &gen_##name, \ + }, \ + .oname = stringify(name), \ +} +#endif #define GEN_OPCODE_MARK(name) \ OPCODES_SECTION opcode_t opc_##name = { \ @@ -370,9 +403,9 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } #define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \ @@ -381,9 +414,9 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } #define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \ @@ -391,18 +424,18 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } #define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } /* Two operands arithmetic functions */ @@ -454,41 +487,51 @@ GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06); /* addi */ GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - int32_t simm = SIMM(ctx->opcode); + target_long simm = SIMM(ctx->opcode); if (rA(ctx->opcode) == 0) { + /* li case */ gen_op_set_T0(simm); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_addi(simm); + if (likely(simm != 0)) + gen_op_addi(simm); } gen_op_store_T0_gpr(rD(ctx->opcode)); } /* addic */ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { + target_long simm = SIMM(ctx->opcode); + gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_addic(SIMM(ctx->opcode)); + if (likely(simm != 0)) + gen_op_addic(SIMM(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); } /* addic. */ GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { + target_long simm = SIMM(ctx->opcode); + gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_addic(SIMM(ctx->opcode)); - gen_op_set_Rc0(); + if (likely(simm != 0)) + gen_op_addic(SIMM(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); + gen_set_Rc0(ctx); } /* addis */ GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - int32_t simm = SIMM(ctx->opcode); + target_long simm = SIMM(ctx->opcode); if (rA(ctx->opcode) == 0) { + /* lis case */ gen_op_set_T0(simm << 16); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_addi(simm << 16); + if (likely(simm != 0)) + gen_op_addi(simm << 16); } gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -543,9 +586,9 @@ GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \ gen_op_load_gpr_T0(rS(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } #define GEN_LOGICAL2(name, opc) \ __GEN_LOGICAL2(name, 0x1C, opc) @@ -555,9 +598,9 @@ GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \ { \ gen_op_load_gpr_T0(rS(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } /* and & and. */ @@ -568,17 +611,17 @@ GEN_LOGICAL2(andc, 0x01); GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_andi_(UIMM(ctx->opcode)); - gen_op_set_Rc0(); + gen_op_andi_T0(UIMM(ctx->opcode)); gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_set_Rc0(ctx); } /* andis. */ GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_andi_(UIMM(ctx->opcode) << 16); - gen_op_set_Rc0(); + gen_op_andi_T0(UIMM(ctx->opcode) << 16); gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_set_Rc0(ctx); } /* cntlzw */ @@ -597,15 +640,25 @@ GEN_LOGICAL2(nor, 0x03); /* or & or. */ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - /* Optimisation for mr case */ - if (rS(ctx->opcode) != rB(ctx->opcode)) { - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_or(); + int rs, ra, rb; + + rs = rS(ctx->opcode); + ra = rA(ctx->opcode); + rb = rB(ctx->opcode); + /* Optimisation for mr. ri case */ + if (rs != ra || rs != rb) { + gen_op_load_gpr_T0(rs); + if (rs != rb) { + gen_op_load_gpr_T1(rb); + gen_op_or(); + } + gen_op_store_T0_gpr(ra); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); + } else if (unlikely(Rc(ctx->opcode) != 0)) { + gen_op_load_gpr_T0(rs); + gen_set_Rc0(ctx); } - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); - gen_op_store_T0_gpr(rA(ctx->opcode)); } /* orc & orc. */ @@ -619,67 +672,68 @@ GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER) gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_xor(); } else { - gen_op_set_T0(0); + gen_op_reset_T0(); } - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /* ori */ GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t uimm = UIMM(ctx->opcode); + target_ulong uimm = UIMM(ctx->opcode); if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { /* NOP */ + /* XXX: should handle special NOPs for POWER series */ return; - } - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (uimm != 0) + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + if (likely(uimm != 0)) gen_op_ori(uimm); - gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_op_store_T0_gpr(rA(ctx->opcode)); } /* oris */ GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t uimm = UIMM(ctx->opcode); + target_ulong uimm = UIMM(ctx->opcode); if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { /* NOP */ return; - } - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (uimm != 0) + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + if (likely(uimm != 0)) gen_op_ori(uimm << 16); - gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_op_store_T0_gpr(rA(ctx->opcode)); } /* xori */ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t uimm = UIMM(ctx->opcode); + target_ulong uimm = UIMM(ctx->opcode); if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { /* NOP */ return; } gen_op_load_gpr_T0(rS(ctx->opcode)); - if (uimm != 0) - gen_op_xori(uimm); + if (likely(uimm != 0)) + gen_op_xori(uimm); gen_op_store_T0_gpr(rA(ctx->opcode)); } /* xoris */ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t uimm = UIMM(ctx->opcode); + target_ulong uimm = UIMM(ctx->opcode); if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { /* NOP */ return; } gen_op_load_gpr_T0(rS(ctx->opcode)); - if (uimm != 0) - gen_op_xori(uimm << 16); + if (likely(uimm != 0)) + gen_op_xori(uimm << 16); gen_op_store_T0_gpr(rA(ctx->opcode)); } @@ -687,16 +741,42 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) /* rlwimi & rlwimi. */ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t mb, me; + target_ulong mask; + uint32_t mb, me, sh; + int n; mb = MB(ctx->opcode); me = ME(ctx->opcode); + sh = SH(ctx->opcode); + n = me + 1 - mb; + if (likely(sh == 0)) { + if (likely(mb == 0 && me == 31)) { + gen_op_load_gpr_T0(rS(ctx->opcode)); + goto do_store; + } else if (likely(mb == 31 && me == 0)) { + gen_op_load_gpr_T0(rA(ctx->opcode)); + goto do_store; + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); + goto do_mask; + } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rA(ctx->opcode)); - gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me)); - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); + gen_op_rotli32_T0(SH(ctx->opcode)); + do_mask: +#if defined(TARGET_PPC64) + mb += 32; + me += 32; +#endif + mask = MASK(mb, me); + gen_op_andi_T0(mask); + gen_op_andi_T1(~mask); + gen_op_or(); + do_store: gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /* rlwinm & rlwinm. */ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -707,35 +787,34 @@ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) mb = MB(ctx->opcode); me = ME(ctx->opcode); gen_op_load_gpr_T0(rS(ctx->opcode)); -#if 1 // TRY - if (sh == 0) { - gen_op_andi_(MASK(mb, me)); - goto store; - } -#endif - if (mb == 0) { - if (me == 31) { - gen_op_rotlwi(sh); - goto store; -#if 0 - } else if (me == (31 - sh)) { - gen_op_slwi(sh); - goto store; -#endif + if (likely(sh == 0)) { + goto do_mask; + } + if (likely(mb == 0)) { + if (likely(me == 31)) { + gen_op_rotli32_T0(sh); + goto do_store; + } else if (likely(me == (31 - sh))) { + gen_op_sli_T0(sh); + goto do_store; } - } else if (me == 31) { -#if 0 - if (sh == (32 - mb)) { - gen_op_srwi(mb); - goto store; + } else if (likely(me == 31)) { + if (likely(sh == (32 - mb))) { + gen_op_srli_T0(mb); + goto do_store; } -#endif } - gen_op_rlwinm(sh, MASK(mb, me)); -store: - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); + gen_op_rotli32_T0(sh); + do_mask: +#if defined(TARGET_PPC64) + mb += 32; + me += 32; +#endif + gen_op_andi_T0(MASK(mb, me)); + do_store: gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /* rlwnm & rlwnm. */ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -746,15 +825,17 @@ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) me = ME(ctx->opcode); gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - if (mb == 0 && me == 31) { - gen_op_rotl(); - } else - { - gen_op_rlwnm(MASK(mb, me)); + gen_op_rotl32_T0_T1(); + if (unlikely(mb != 0 || me != 31)) { +#if defined(TARGET_PPC64) + mb += 32; + me += 32; +#endif + gen_op_andi_T0(MASK(mb, me)); } - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /*** Integer shift ***/ @@ -767,10 +848,10 @@ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); if (SH(ctx->opcode) != 0) - gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31)); - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); + gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31)); gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /* srw & srw. */ __GEN_LOGICAL2(srw, 0x18, 0x10); @@ -779,7 +860,7 @@ __GEN_LOGICAL2(srw, 0x18, 0x10); #define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -792,7 +873,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } @@ -803,7 +884,7 @@ _GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1); #define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -815,7 +896,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_AB(name, op2, inval) \ @@ -825,7 +906,7 @@ _GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1); #define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -837,7 +918,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_AC(name, op2, inval) \ @@ -847,7 +928,7 @@ _GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1); #define GEN_FLOAT_B(name, op2, op3) \ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -855,14 +936,14 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ gen_op_load_fpr_FT0(rB(ctx->opcode)); \ gen_op_f##name(); \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_BS(name, op1, op2) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -870,7 +951,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ gen_op_load_fpr_FT0(rB(ctx->opcode)); \ gen_op_f##name(); \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } @@ -881,13 +962,13 @@ GEN_FLOAT_AB(div, 0x12, 0x000007C0); /* fmul - fmuls */ GEN_FLOAT_AC(mul, 0x19, 0x0000F800); -/* fres */ +/* fres */ /* XXX: not in 601 */ GEN_FLOAT_BS(res, 0x3B, 0x18); -/* frsqrte */ +/* frsqrte */ /* XXX: not in 601 */ GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A); -/* fsel */ +/* fsel */ /* XXX: not in 601 */ _GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0); /* fsub - fsubs */ GEN_FLOAT_AB(sub, 0x14, 0x000007C0); @@ -895,7 +976,7 @@ GEN_FLOAT_AB(sub, 0x14, 0x000007C0); /* fsqrt */ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -903,13 +984,13 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_fsqrt(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -918,7 +999,7 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) gen_op_fsqrt(); gen_op_frsp(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } @@ -942,9 +1023,9 @@ GEN_FLOAT_B(rsp, 0x0C, 0x00); /*** Floating-Point compare ***/ /* fcmpo */ -GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) +GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -956,9 +1037,9 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) } /* fcmpu */ -GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) +GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -976,14 +1057,14 @@ GEN_FLOAT_B(abs, 0x08, 0x08); /* fmr - fmr. */ GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } @@ -996,7 +1077,7 @@ GEN_FLOAT_B(neg, 0x08, 0x01); /* mcrfs */ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -1008,13 +1089,13 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) /* mffs */ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } gen_op_load_fpscr(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } @@ -1023,15 +1104,15 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) { uint8_t crb; - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } crb = crbD(ctx->opcode) >> 2; gen_op_load_fpscr_T0(crb); - gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03))); + gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03))); gen_op_store_T0_fpscr(crb); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } @@ -1040,7 +1121,7 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) { uint8_t crb; - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -1048,35 +1129,70 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) gen_op_load_fpscr_T0(crb); gen_op_ori(1 << (crbD(ctx->opcode) & 0x03)); gen_op_store_T0_fpscr(crb); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } /* mtfsf */ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_store_fpscr(FM(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } /* mtfsfi */ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } +/*** Addressing modes ***/ +/* Register indirect with immediate index : EA = (rA|0) + SIMM */ +static inline void gen_addr_imm_index (DisasContext *ctx) +{ + target_long simm = SIMM(ctx->opcode); + + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(simm); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + if (likely(simm != 0)) + gen_op_addi(simm); + } +} + +static inline void gen_addr_reg_index (DisasContext *ctx) +{ + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } +} + +static inline void gen_addr_register (DisasContext *ctx) +{ + if (rA(ctx->opcode) == 0) { + gen_op_reset_T0(); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + } +} + /*** Integer load ***/ #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) @@ -1118,14 +1234,7 @@ static GenOpFunc *gen_op_st##width[] = { \ #define GEN_LD(width, opc) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (rA(ctx->opcode) == 0) { \ - gen_op_set_T0(simm); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - } \ + gen_addr_imm_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ } @@ -1133,15 +1242,12 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_LDU(width, opc) \ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) { \ + if (unlikely(rA(ctx->opcode) == 0 || \ + rA(ctx->opcode) == rD(ctx->opcode))) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ + gen_addr_imm_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1150,14 +1256,12 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_LDUX(width, opc) \ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) { \ + if (unlikely(rA(ctx->opcode) == 0 || \ + rA(ctx->opcode) == rD(ctx->opcode))) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ + gen_addr_reg_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1166,13 +1270,7 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ #define GEN_LDX(width, opc2, opc3) \ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rB(ctx->opcode)); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - } \ + gen_addr_reg_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ } @@ -1197,14 +1295,7 @@ GEN_LDS(wz, 0x00); #define GEN_ST(width, opc) \ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (rA(ctx->opcode) == 0) { \ - gen_op_set_T0(simm); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - } \ + gen_addr_imm_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ } @@ -1212,14 +1303,11 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_STU(width, opc) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (rA(ctx->opcode) == 0) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ + gen_addr_imm_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1228,13 +1316,11 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_STUX(width, opc) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ + gen_addr_reg_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1243,13 +1329,7 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ #define GEN_STX(width, opc2, opc3) \ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rB(ctx->opcode)); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - } \ + gen_addr_reg_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ } @@ -1311,30 +1391,18 @@ static GenOpFunc1 *gen_op_stmw[] = { /* lmw */ GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - int simm = SIMM(ctx->opcode); - - if (rA(ctx->opcode) == 0) { - gen_op_set_T0(simm); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (simm != 0) - gen_op_addi(simm); - } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); op_ldstm(lmw, rD(ctx->opcode)); } /* stmw */ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - int simm = SIMM(ctx->opcode); - - if (rA(ctx->opcode) == 0) { - gen_op_set_T0(simm); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (simm != 0) - gen_op_addi(simm); - } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); op_ldstm(stmw, rS(ctx->opcode)); } @@ -1391,19 +1459,16 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) if (nb == 0) nb = 32; nr = nb / 4; - if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) || - ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) { + if (unlikely(((start + nr) > 32 && + start <= ra && (start + nr - 32) > ra) || + ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) { RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); return; } - if (ra == 0) { - gen_op_set_T0(0); - } else { - gen_op_load_gpr_T0(ra); - } - gen_op_set_T1(nb); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip((ctx)->nip - 4); + gen_op_update_nip(ctx->nip - 4); + gen_addr_register(ctx); + gen_op_set_T1(nb); op_ldsts(lswi, start); } @@ -1413,17 +1478,13 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) int ra = rA(ctx->opcode); int rb = rB(ctx->opcode); + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); if (ra == 0) { - gen_op_load_gpr_T0(rb); ra = rb; - } else { - gen_op_load_gpr_T0(ra); - gen_op_load_gpr_T1(rb); - gen_op_add(); } gen_op_load_xer_bc(); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip((ctx)->nip - 4); op_ldstsx(lswx, rD(ctx->opcode), ra, rb); } @@ -1432,46 +1493,33 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) { int nb = NB(ctx->opcode); - if (rA(ctx->opcode) == 0) { - gen_op_set_T0(0); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_register(ctx); if (nb == 0) nb = 32; gen_op_set_T1(nb); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip((ctx)->nip - 4); op_ldsts(stsw, rS(ctx->opcode)); } /* stswx */ GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) { - int ra = rA(ctx->opcode); - - if (ra == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - ra = rB(ctx->opcode); - } else { - gen_op_load_gpr_T0(ra); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } - gen_op_load_xer_bc(); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip((ctx)->nip - 4); + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + gen_op_load_xer_bc(); op_ldsts(stsw, rS(ctx->opcode)); } /*** Memory synchronisation ***/ /* eieio */ -GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM) +GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO) { } /* isync */ -GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM) +GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM) { } @@ -1502,15 +1550,9 @@ static GenOpFunc *gen_op_stwcx[] = { #endif /* lwarx */ -GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES) +GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + gen_addr_reg_index(ctx); op_lwarx(); gen_op_store_T1_gpr(rD(ctx->opcode)); } @@ -1518,19 +1560,13 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES) /* stwcx. */ GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + gen_addr_reg_index(ctx); gen_op_load_gpr_T1(rS(ctx->opcode)); op_stwcx(); } /* sync */ -GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) +GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC) { } @@ -1538,79 +1574,59 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) #define GEN_LDF(width, opc) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ - gen_op_set_T0(simm); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - } \ + gen_addr_imm_index(ctx); \ op_ldst(l##width); \ - gen_op_store_FT1_fpr(rD(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ } #define GEN_LDUF(width, opc) \ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ + gen_addr_imm_index(ctx); \ op_ldst(l##width); \ - gen_op_store_FT1_fpr(rD(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } #define GEN_LDUXF(width, opc) \ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ + gen_addr_reg_index(ctx); \ op_ldst(l##width); \ - gen_op_store_FT1_fpr(rD(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } #define GEN_LDXF(width, opc2, opc3) \ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rB(ctx->opcode)); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - } \ + gen_addr_reg_index(ctx); \ op_ldst(l##width); \ - gen_op_store_FT1_fpr(rD(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ } #define GEN_LDFS(width, op) \ @@ -1629,38 +1645,28 @@ GEN_LDFS(fs, 0x10); #define GEN_STF(width, opc) \ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ - gen_op_set_T0(simm); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - } \ - gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + gen_addr_imm_index(ctx); \ + gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ } #define GEN_STUF(width, opc) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + gen_addr_imm_index(ctx); \ + gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } @@ -1668,18 +1674,16 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ #define GEN_STUXF(width, opc) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + gen_addr_reg_index(ctx); \ + gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } @@ -1687,18 +1691,12 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ #define GEN_STXF(width, opc2, opc3) \ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rB(ctx->opcode)); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - } \ - gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + gen_addr_reg_index(ctx); \ + gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ } @@ -1718,10 +1716,12 @@ GEN_STFS(fs, 0x14); /* stfiwx */ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } + gen_addr_reg_index(ctx); + /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */ RET_INVAL(ctx); } @@ -1745,9 +1745,9 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) } else { gen_op_set_T1(dest); gen_op_b_T1(); + gen_op_reset_T0(); if (ctx->singlestep_enabled) gen_op_debug(); - gen_op_set_T0(0); gen_op_exit_tb(); } } @@ -1755,12 +1755,15 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) /* b ba bl bla */ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { - uint32_t li, target; + target_ulong li, target; /* sign extend LI */ - li = ((int32_t)LI(ctx->opcode) << 6) >> 6; - - if (AA(ctx->opcode) == 0) +#if defined(TARGET_PPC64) + li = ((target_long)LI(ctx->opcode) << 38) >> 38; +#else + li = ((target_long)LI(ctx->opcode) << 6) >> 6; +#endif + if (likely(AA(ctx->opcode) == 0)) target = ctx->nip + li - 4; else target = li; @@ -1777,18 +1780,18 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) static inline void gen_bcond(DisasContext *ctx, int type) { - uint32_t target = 0; + target_ulong target = 0; + target_ulong li; uint32_t bo = BO(ctx->opcode); uint32_t bi = BI(ctx->opcode); uint32_t mask; - uint32_t li; if ((bo & 0x4) == 0) gen_op_dec_ctr(); switch(type) { case BCOND_IM: - li = (int32_t)((int16_t)(BD(ctx->opcode))); - if (AA(ctx->opcode) == 0) { + li = (target_long)((int16_t)(BD(ctx->opcode))); + if (likely(AA(ctx->opcode) == 0)) { target = ctx->nip + li - 4; } else { target = li; @@ -1821,6 +1824,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_goto_tb(ctx, 0, target); } else { gen_op_b_T1(); + gen_op_reset_T0(); } goto no_test; } @@ -1865,8 +1869,12 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_goto_tb(ctx, 1, ctx->nip); } else { gen_op_btest_T1(ctx->nip); + gen_op_reset_T0(); } no_test: + if (ctx->singlestep_enabled) + gen_op_debug(); + gen_op_exit_tb(); ctx->exception = EXCP_BRANCH; } @@ -1901,21 +1909,21 @@ GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \ } /* crand */ -GEN_CRLOGIC(and, 0x08) +GEN_CRLOGIC(and, 0x08); /* crandc */ -GEN_CRLOGIC(andc, 0x04) +GEN_CRLOGIC(andc, 0x04); /* creqv */ -GEN_CRLOGIC(eqv, 0x09) +GEN_CRLOGIC(eqv, 0x09); /* crnand */ -GEN_CRLOGIC(nand, 0x07) +GEN_CRLOGIC(nand, 0x07); /* crnor */ -GEN_CRLOGIC(nor, 0x01) +GEN_CRLOGIC(nor, 0x01); /* cror */ -GEN_CRLOGIC(or, 0x0E) +GEN_CRLOGIC(or, 0x0E); /* crorc */ -GEN_CRLOGIC(orc, 0x0D) +GEN_CRLOGIC(orc, 0x0D); /* crxor */ -GEN_CRLOGIC(xor, 0x06) +GEN_CRLOGIC(xor, 0x06); /* mcrf */ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) { @@ -1925,13 +1933,13 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) /*** System linkage ***/ /* rfi (supervisor only) */ -GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) +GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else /* Restore CPU state */ - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVOPC(ctx); return; } @@ -1952,7 +1960,7 @@ GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) /*** Trap ***/ /* tw */ -GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW) +GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW) { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); @@ -1965,39 +1973,11 @@ GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW) GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { gen_op_load_gpr_T0(rA(ctx->opcode)); -#if 0 - printf("%s: param=0x%04x T0=0x%04x\n", __func__, - SIMM(ctx->opcode), TO(ctx->opcode)); -#endif - gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode)); + gen_op_set_T1(SIMM(ctx->opcode)); + gen_op_tw(TO(ctx->opcode)); } /*** Processor control ***/ -static inline int check_spr_access (int spr, int rw, int supervisor) -{ - uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1)); - -#if 0 - if (spr != LR && spr != CTR) { - if (loglevel > 0) { - fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__, - SPR_ENCODE(spr), supervisor, rw, rights, - (rights >> ((2 * supervisor) + rw)) & 1); - } else { - printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__, - SPR_ENCODE(spr), supervisor, rw, rights, - (rights >> ((2 * supervisor) + rw)) & 1); - } - } -#endif - if (rights == 0) - return -1; - rights = rights >> (2 * supervisor); - rights = rights >> rw; - - return rights & 1; -} - /* mcrxr */ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) { @@ -2007,9 +1987,22 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) } /* mfcr */ -GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC) +GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC) { - gen_op_load_cr(); +#if 0 // XXX: to be tested + uint32_t crm, crn; + + if (likely(ctx->opcode & 0x00100000)) { + crm = CRM(ctx->opcode); + if (likely((crm ^ (crm - 1)) == 0)) { + crn = ffs(crm); + gen_op_load_cro(7 - crn); + } + } else +#endif + { + gen_op_load_cr(); + } gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -2019,7 +2012,7 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } @@ -2051,8 +2044,8 @@ static inline void gen_op_mfspr (DisasContext *ctx) else #endif read_cb = ctx->spr_cb[sprn].uea_read; - if (read_cb != NULL) { - if (read_cb != SPR_NOACCESS) { + if (likely(read_cb != NULL)) { + if (likely(read_cb != SPR_NOACCESS)) { (*read_cb)(ctx, sprn); gen_op_store_T0_gpr(rD(ctx->opcode)); } else { @@ -2062,7 +2055,7 @@ static inline void gen_op_mfspr (DisasContext *ctx) sprn, sprn); } printf("Trying to read priviledged spr %d %03x\n", sprn, sprn); - RET_PRIVREG(ctx); + RET_PRIVREG(ctx); } } else { /* Not defined */ @@ -2078,7 +2071,7 @@ static inline void gen_op_mfspr (DisasContext *ctx) GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) { gen_op_mfspr(ctx); - } +} /* mftb */ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB) @@ -2087,11 +2080,20 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB) } /* mtcrf */ -/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) { + uint32_t crm, crn; + gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_store_cr(CRM(ctx->opcode)); + crm = CRM(ctx->opcode); + if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) { + crn = ffs(crm); + gen_op_srli_T0(crn * 4); + gen_op_andi_T0(0xF); + gen_op_store_cro(7 - crn); + } else { + gen_op_store_cr(crm); + } } /* mtmsr */ @@ -2100,7 +2102,7 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } @@ -2124,8 +2126,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) else #endif write_cb = ctx->spr_cb[sprn].uea_write; - if (write_cb != NULL) { - if (write_cb != SPR_NOACCESS) { + if (likely(write_cb != NULL)) { + if (likely(write_cb != SPR_NOACCESS)) { gen_op_load_gpr_T0(rS(ctx->opcode)); (*write_cb)(ctx, sprn); } else { @@ -2135,8 +2137,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) sprn, sprn); } printf("Trying to write priviledged spr %d %03x\n", sprn, sprn); - RET_PRIVREG(ctx); - } + RET_PRIVREG(ctx); + } } else { /* Not defined */ if (loglevel) { @@ -2156,13 +2158,7 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) /* dcbf */ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + gen_addr_reg_index(ctx); op_ldst(lbz); } @@ -2172,18 +2168,13 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVOPC(ctx); return; } - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } - op_ldst(lbz); + gen_addr_reg_index(ctx); + /* XXX: specification says this should be treated as a store by the MMU */ + //op_ldst(lbz); op_ldst(stb); #endif } @@ -2191,31 +2182,35 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) /* dcdst */ GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + /* XXX: specification say this is treated as a load by the MMU */ + gen_addr_reg_index(ctx); op_ldst(lbz); } /* dcbt */ GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE) { + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ } /* dcbtst */ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE) { + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ } /* dcbz */ +#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) -#define op_dcbz() gen_op_dcbz_raw() +static GenOpFunc *gen_op_dcbz[] = { + &gen_op_dcbz_raw, + &gen_op_dcbz_raw, +}; #else -#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() static GenOpFunc *gen_op_dcbz[] = { &gen_op_dcbz_user, &gen_op_dcbz_user, @@ -2226,13 +2221,7 @@ static GenOpFunc *gen_op_dcbz[] = { GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + gen_addr_reg_index(ctx); op_dcbz(); gen_op_check_reservation(); } @@ -2240,14 +2229,11 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) /* icbi */ GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); gen_op_icbi(); + RET_STOP(ctx); } /* Optional: */ @@ -2264,11 +2250,12 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } - gen_op_load_sr(SR(ctx->opcode)); + gen_op_set_T1(SR(ctx->opcode)); + gen_op_load_sr(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } @@ -2279,12 +2266,13 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_load_srin(); + gen_op_srli_T1(28); + gen_op_load_sr(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } @@ -2295,12 +2283,13 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_store_sr(SR(ctx->opcode)); + gen_op_set_T1(SR(ctx->opcode)); + gen_op_store_sr(); RET_STOP(ctx); #endif } @@ -2311,13 +2300,14 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_store_srin(); + gen_op_srli_T1(28); + gen_op_store_sr(); RET_STOP(ctx); #endif } @@ -2330,7 +2320,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { if (loglevel) fprintf(logfile, "%s: ! supervisor\n", __func__); RET_PRIVOPC(ctx); @@ -2342,12 +2332,12 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) } /* tlbie */ -GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) +GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVOPC(ctx); return; } @@ -2358,12 +2348,12 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) } /* tlbsync */ -GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) +GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVOPC(ctx); return; } @@ -2406,30 +2396,1149 @@ static GenOpFunc *gen_op_ecowx[] = { GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN) { /* Should check EAR[E] & alignment ! */ - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { + gen_addr_reg_index(ctx); + op_eciwx(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +} + +/* ecowx */ +GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) +{ + /* Should check EAR[E] & alignment ! */ + gen_addr_reg_index(ctx); + gen_op_load_gpr_T1(rS(ctx->opcode)); + op_ecowx(); +} + +/* PowerPC 601 specific instructions */ +/* abs - abs. */ +GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_abs(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* abso - abso. */ +GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_abso(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* clcs */ +GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */ +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_clcs(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +} + +/* div - div. */ +GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_div(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* divo - divo. */ +GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_divo(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* divs - divs. */ +GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_divs(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* divso - divso. */ +GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_divso(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* doz - doz. */ +GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_doz(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* dozo - dozo. */ +GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_dozo(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* dozi */ +GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_set_T1(SIMM(ctx->opcode)); + gen_op_POWER_doz(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +} + +/* As lscbx load from memory byte after byte, it's always endian safe */ +#define op_POWER_lscbx(start, ra, rb) \ +(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb) +#if defined(CONFIG_USER_ONLY) +static GenOpFunc3 *gen_op_POWER_lscbx[] = { + &gen_op_POWER_lscbx_raw, + &gen_op_POWER_lscbx_raw, +}; +#else +static GenOpFunc3 *gen_op_POWER_lscbx[] = { + &gen_op_POWER_lscbx_user, + &gen_op_POWER_lscbx_user, + &gen_op_POWER_lscbx_kernel, + &gen_op_POWER_lscbx_kernel, +}; +#endif + +/* lscbx - lscbx. */ +GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR) +{ + int ra = rA(ctx->opcode); + int rb = rB(ctx->opcode); + + gen_addr_reg_index(ctx); + if (ra == 0) { + ra = rb; + } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_op_load_xer_bc(); + gen_op_load_xer_cmp(); + op_POWER_lscbx(rD(ctx->opcode), ra, rb); + gen_op_store_xer_bc(); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* maskg - maskg. */ +GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_maskg(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* maskir - maskir. */ +GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_load_gpr_T2(rB(ctx->opcode)); + gen_op_POWER_maskir(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* mul - mul. */ +GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_mul(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* mulo - mulo. */ +GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_mulo(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* nabs - nabs. */ +GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_nabs(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* nabso - nabso. */ +GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_nabso(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* rlmi - rlmi. */ +GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR) +{ + uint32_t mb, me; + + mb = MB(ctx->opcode); + me = ME(ctx->opcode); + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); + gen_op_load_gpr_T2(rB(ctx->opcode)); + gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me)); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* rrib - rrib. */ +GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); + gen_op_load_gpr_T2(rB(ctx->opcode)); + gen_op_POWER_rrib(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sle - sle. */ +GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sle(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sleq - sleq. */ +GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sleq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sliq - sliq. */ +GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_sle(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* slliq - slliq. */ +GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_sleq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sllq - sllq. */ +GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sllq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* slq - slq. */ +GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_slq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sraiq -sraiq. */ +GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_sraq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sraq - sraq. */ +GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sraq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sre - sre. */ +GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sre(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* srea - srea. */ +GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_srea(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sreq */ +GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sreq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sriq */ +GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_srq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* srliq */ +GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_srlq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* srlq */ +GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_srlq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* srq */ +GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_srq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* PowerPC 602 specific instructions */ +/* dsa */ +GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC) +{ + /* XXX: TODO */ + RET_INVAL(ctx); +} + +/* esa */ +GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC) +{ + /* XXX: TODO */ + RET_INVAL(ctx); +} + +/* mfrom */ +GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_602_mfrom(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* 602 - 603 - G2 TLB management */ +/* tlbld */ +GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_6xx_tlbld(); + RET_STOP(ctx); +#endif +} + +/* tlbli */ +GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_6xx_tlbli(); + RET_STOP(ctx); +#endif +} + +/* POWER instructions not in PowerPC 601 */ +/* clf */ +GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER) +{ + /* Cache line flush: implemented as no-op */ +} + +/* cli */ +GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER) +{ + /* Cache line invalidate: priviledged and treated as no-op */ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } +#endif +} + +/* dclst */ +GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER) +{ + /* Data cache line store: treated as no-op */ +} + +GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + int ra = rA(ctx->opcode); + int rd = rD(ctx->opcode); + + gen_addr_reg_index(ctx); + gen_op_POWER_mfsri(); + gen_op_store_T0_gpr(rd); + if (ra != 0 && ra != rd) + gen_op_store_T1_gpr(ra); +#endif +} + +GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + gen_op_POWER_rac(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_POWER_rfsvc(); + RET_CHG_FLOW(ctx); +#endif +} + +/* svc is not implemented for now */ + +/* POWER2 specific instructions */ +/* Quad manipulation (load/store two floats at a time) */ +#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])() +#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])() +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_POWER2_lfq[] = { + &gen_op_POWER2_lfq_le_raw, + &gen_op_POWER2_lfq_raw, +}; +static GenOpFunc *gen_op_POWER2_stfq[] = { + &gen_op_POWER2_stfq_le_raw, + &gen_op_POWER2_stfq_raw, +}; +#else +static GenOpFunc *gen_op_POWER2_lfq[] = { + &gen_op_POWER2_lfq_le_user, + &gen_op_POWER2_lfq_user, + &gen_op_POWER2_lfq_le_kernel, + &gen_op_POWER2_lfq_kernel, +}; +static GenOpFunc *gen_op_POWER2_stfq[] = { + &gen_op_POWER2_stfq_le_user, + &gen_op_POWER2_stfq_user, + &gen_op_POWER2_stfq_le_kernel, + &gen_op_POWER2_stfq_kernel, +}; +#endif + +/* lfq */ +GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2) +{ + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); + op_POWER2_lfq(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); +} + +/* lfqu */ +GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2) +{ + int ra = rA(ctx->opcode); + + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); + op_POWER2_lfq(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); + if (ra != 0) + gen_op_store_T0_gpr(ra); +} + +/* lfqux */ +GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2) +{ + int ra = rA(ctx->opcode); + + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + op_POWER2_lfq(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); + if (ra != 0) + gen_op_store_T0_gpr(ra); +} + +/* lfqx */ +GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2) +{ + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + op_POWER2_lfq(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); +} + +/* stfq */ +GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2) +{ + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); + gen_op_load_fpr_FT0(rS(ctx->opcode)); + gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + op_POWER2_stfq(); +} + +/* stfqu */ +GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2) +{ + int ra = rA(ctx->opcode); + + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); + gen_op_load_fpr_FT0(rS(ctx->opcode)); + gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + op_POWER2_stfq(); + if (ra != 0) + gen_op_store_T0_gpr(ra); +} + +/* stfqux */ +GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2) +{ + int ra = rA(ctx->opcode); + + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + gen_op_load_fpr_FT0(rS(ctx->opcode)); + gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + op_POWER2_stfq(); + if (ra != 0) + gen_op_store_T0_gpr(ra); +} + +/* stfqx */ +GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2) +{ + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + gen_op_load_fpr_FT0(rS(ctx->opcode)); + gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + op_POWER2_stfq(); +} + +/* BookE specific instructions */ +GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE) +{ + /* XXX: TODO */ + RET_INVAL(ctx); +} + +GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + /* Use the same micro-ops as for tlbie */ + gen_op_tlbie(); + RET_STOP(ctx); +#endif +} + +/* All 405 MAC instructions are translated here */ +static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3, + int ra, int rb, int rt, int Rc) +{ + gen_op_load_gpr_T0(ra); + gen_op_load_gpr_T1(rb); + switch (opc3 & 0x0D) { + case 0x05: + /* macchw - macchw. - macchwo - macchwo. */ + /* macchws - macchws. - macchwso - macchwso. */ + /* nmacchw - nmacchw. - nmacchwo - nmacchwo. */ + /* nmacchws - nmacchws. - nmacchwso - nmacchwso. */ + /* mulchw - mulchw. */ + gen_op_405_mulchw(); + break; + case 0x04: + /* macchwu - macchwu. - macchwuo - macchwuo. */ + /* macchwsu - macchwsu. - macchwsuo - macchwsuo. */ + /* mulchwu - mulchwu. */ + gen_op_405_mulchwu(); + break; + case 0x01: + /* machhw - machhw. - machhwo - machhwo. */ + /* machhws - machhws. - machhwso - machhwso. */ + /* nmachhw - nmachhw. - nmachhwo - nmachhwo. */ + /* nmachhws - nmachhws. - nmachhwso - nmachhwso. */ + /* mulhhw - mulhhw. */ + gen_op_405_mulhhw(); + break; + case 0x00: + /* machhwu - machhwu. - machhwuo - machhwuo. */ + /* machhwsu - machhwsu. - machhwsuo - machhwsuo. */ + /* mulhhwu - mulhhwu. */ + gen_op_405_mulhhwu(); + break; + case 0x0D: + /* maclhw - maclhw. - maclhwo - maclhwo. */ + /* maclhws - maclhws. - maclhwso - maclhwso. */ + /* nmaclhw - nmaclhw. - nmaclhwo - nmaclhwo. */ + /* nmaclhws - nmaclhws. - nmaclhwso - nmaclhwso. */ + /* mullhw - mullhw. */ + gen_op_405_mullhw(); + break; + case 0x0C: + /* maclhwu - maclhwu. - maclhwuo - maclhwuo. */ + /* maclhwsu - maclhwsu. - maclhwsuo - maclhwsuo. */ + /* mullhwu - mullhwu. */ + gen_op_405_mullhwu(); + break; + } + if (opc2 & 0x02) { + /* nmultiply-and-accumulate (0x0E) */ + gen_op_neg(); + } + if (opc2 & 0x04) { + /* (n)multiply-and-accumulate (0x0C - 0x0E) */ + gen_op_load_gpr_T2(rt); + gen_op_move_T1_T0(); + gen_op_405_add_T0_T2(); + } + if (opc3 & 0x10) { + /* Check overflow */ + if (opc3 & 0x01) + gen_op_405_check_ov(); + else + gen_op_405_check_ovu(); + } + if (opc3 & 0x02) { + /* Saturate */ + if (opc3 & 0x01) + gen_op_405_check_sat(); + else + gen_op_405_check_satu(); + } + gen_op_store_T0_gpr(rt); + if (unlikely(Rc) != 0) { + /* Update Rc0 */ + gen_set_Rc0(ctx); + } +} + +#define GEN_MAC_HANDLER(name, opc2, opc3) \ +GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC) \ +{ \ + gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode), \ + rD(ctx->opcode), Rc(ctx->opcode)); \ +} + +/* macchw - macchw. */ +GEN_MAC_HANDLER(macchw, 0x0C, 0x05); +/* macchwo - macchwo. */ +GEN_MAC_HANDLER(macchwo, 0x0C, 0x15); +/* macchws - macchws. */ +GEN_MAC_HANDLER(macchws, 0x0C, 0x07); +/* macchwso - macchwso. */ +GEN_MAC_HANDLER(macchwso, 0x0C, 0x17); +/* macchwsu - macchwsu. */ +GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06); +/* macchwsuo - macchwsuo. */ +GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16); +/* macchwu - macchwu. */ +GEN_MAC_HANDLER(macchwu, 0x0C, 0x04); +/* macchwuo - macchwuo. */ +GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14); +/* machhw - machhw. */ +GEN_MAC_HANDLER(machhw, 0x0C, 0x01); +/* machhwo - machhwo. */ +GEN_MAC_HANDLER(machhwo, 0x0C, 0x11); +/* machhws - machhws. */ +GEN_MAC_HANDLER(machhws, 0x0C, 0x03); +/* machhwso - machhwso. */ +GEN_MAC_HANDLER(machhwso, 0x0C, 0x13); +/* machhwsu - machhwsu. */ +GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02); +/* machhwsuo - machhwsuo. */ +GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12); +/* machhwu - machhwu. */ +GEN_MAC_HANDLER(machhwu, 0x0C, 0x00); +/* machhwuo - machhwuo. */ +GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10); +/* maclhw - maclhw. */ +GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D); +/* maclhwo - maclhwo. */ +GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D); +/* maclhws - maclhws. */ +GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F); +/* maclhwso - maclhwso. */ +GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F); +/* maclhwu - maclhwu. */ +GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C); +/* maclhwuo - maclhwuo. */ +GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C); +/* maclhwsu - maclhwsu. */ +GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E); +/* maclhwsuo - maclhwsuo. */ +GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E); +/* nmacchw - nmacchw. */ +GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05); +/* nmacchwo - nmacchwo. */ +GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15); +/* nmacchws - nmacchws. */ +GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07); +/* nmacchwso - nmacchwso. */ +GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17); +/* nmachhw - nmachhw. */ +GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01); +/* nmachhwo - nmachhwo. */ +GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11); +/* nmachhws - nmachhws. */ +GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03); +/* nmachhwso - nmachhwso. */ +GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13); +/* nmaclhw - nmaclhw. */ +GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D); +/* nmaclhwo - nmaclhwo. */ +GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D); +/* nmaclhws - nmaclhws. */ +GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F); +/* nmaclhwso - nmaclhwso. */ +GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F); + +/* mulchw - mulchw. */ +GEN_MAC_HANDLER(mulchw, 0x08, 0x05); +/* mulchwu - mulchwu. */ +GEN_MAC_HANDLER(mulchwu, 0x08, 0x04); +/* mulhhw - mulhhw. */ +GEN_MAC_HANDLER(mulhhw, 0x08, 0x01); +/* mulhhwu - mulhhwu. */ +GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00); +/* mullhw - mullhw. */ +GEN_MAC_HANDLER(mullhw, 0x08, 0x0D); +/* mullhwu - mullhwu. */ +GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C); + +/* mfdcr */ +GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + uint32_t dcrn = SPR(ctx->opcode); + + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_op_4xx_load_dcr(dcrn); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* mtdcr */ +GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + uint32_t dcrn = SPR(ctx->opcode); + + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_4xx_store_dcr(dcrn); +#endif +} + +/* dccci */ +GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* interpreted as no-op */ +#endif +} + +/* dcread */ +GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + op_ldst(lwz); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* icbt */ +GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC) +{ + /* interpreted as no-op */ + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ +} + +/* iccci */ +GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* interpreted as no-op */ +#endif +} + +/* icread */ +GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* interpreted as no-op */ +#endif +} + +/* rfci (supervisor only) */ +GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* Restore CPU state */ + gen_op_4xx_rfci(); + RET_CHG_FLOW(ctx); +#endif +} + +/* tlbre */ +GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + switch (rB(ctx->opcode)) { + case 0: gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); + gen_op_4xx_tlbre_hi(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + break; + case 1: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_4xx_tlbre_lo(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + break; + default: + RET_INVAL(ctx); + break; } - op_eciwx(); +#endif +} + +/* tlbsx - tlbsx. */ /* Named tlbs in BookE */ +GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + if (Rc(ctx->opcode)) + gen_op_4xx_tlbsx_(); + else + gen_op_4xx_tlbsx(); gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif } -/* ecowx */ -GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) +/* tlbwe */ +GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_EMB_COMMON) { - /* Should check EAR[E] & alignment ! */ - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + switch (rB(ctx->opcode)) { + case 0: gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_4xx_tlbwe_hi(); + break; + case 1: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_4xx_tlbwe_lo(); + break; + default: + RET_INVAL(ctx); + break; } - gen_op_load_gpr_T2(rS(ctx->opcode)); - op_ecowx(); +#endif +} + +/* wrtee */ +GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rD(ctx->opcode)); + gen_op_4xx_wrte(); + RET_EXCP(ctx, EXCP_MTMSR, 0); +#endif +} + +/* wrteei */ +GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_set_T0(ctx->opcode & 0x00010000); + gen_op_4xx_wrte(); + RET_EXCP(ctx, EXCP_MTMSR, 0); +#endif +} + +/* PPC 440 specific instructions */ +/* dlmzb */ +GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_440_dlmzb(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_op_store_xer_bc(); + if (Rc(ctx->opcode)) { + gen_op_440_dlmzb_update_Rc(); + gen_op_store_T0_crf(0); + } +} + +/* mbar replaces eieio on 440 */ +GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE) +{ + /* interpreted as no-op */ +} + +/* msync replaces sync on 440 */ +GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE) +{ + /* interpreted as no-op */ +} + +/* icbt */ +GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE) +{ + /* interpreted as no-op */ + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ } /* End opcode list */ @@ -2439,18 +3548,25 @@ GEN_OPCODE_MARK(end); /*****************************************************************************/ /* Misc PowerPC helpers */ +static inline uint32_t load_xer (CPUState *env) +{ + return (xer_so << XER_SO) | + (xer_ov << XER_OV) | + (xer_ca << XER_CA) | + (xer_bc << XER_BC) | + (xer_cmp << XER_CMP); +} + void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { #if defined(TARGET_PPC64) || 1 #define FILL "" -#define REGX "%016" PRIx64 #define RGPL 4 #define RFPL 4 #else #define FILL " " -#define REGX "%08" PRIx64 #define RGPL 8 #define RFPL 4 #endif @@ -2459,30 +3575,38 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n", env->nip, env->lr, env->ctr); - cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x DECR %08x\n", - do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env), - cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env)); - for (i = 0; i < 32; i++) { + cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x " +#if !defined(CONFIG_USER_ONLY) + "DECR %08x" +#endif + "\n", + do_load_msr(env), load_xer(env), cpu_ppc_load_tbu(env), + cpu_ppc_load_tbl(env) +#if !defined(CONFIG_USER_ONLY) + , cpu_ppc_load_decr(env) +#endif + ); + for (i = 0; i < 32; i++) { if ((i & (RGPL - 1)) == 0) cpu_fprintf(f, "GPR%02d", i); cpu_fprintf(f, " " REGX, env->gpr[i]); if ((i & (RGPL - 1)) == (RGPL - 1)) cpu_fprintf(f, "\n"); - } + } cpu_fprintf(f, "CR "); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) cpu_fprintf(f, "%01x", env->crf[i]); cpu_fprintf(f, " ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; + for (i = 0; i < 8; i++) { + char a = '-'; + if (env->crf[i] & 0x08) + a = 'L'; + else if (env->crf[i] & 0x04) + a = 'G'; + else if (env->crf[i] & 0x02) + a = 'E'; cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } + } cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve); for (i = 0; i < 32; i++) { if ((i & (RFPL - 1)) == 0) @@ -2501,6 +3625,53 @@ void cpu_dump_state(CPUState *env, FILE *f, #undef FILL } +void cpu_dump_statistics (CPUState *env, FILE*f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ +#if defined(DO_PPC_STATISTICS) + opc_handler_t **t1, **t2, **t3, *handler; + int op1, op2, op3; + + t1 = env->opcodes; + for (op1 = 0; op1 < 64; op1++) { + handler = t1[op1]; + if (is_indirect_opcode(handler)) { + t2 = ind_table(handler); + for (op2 = 0; op2 < 32; op2++) { + handler = t2[op2]; + if (is_indirect_opcode(handler)) { + t3 = ind_table(handler); + for (op3 = 0; op3 < 32; op3++) { + handler = t3[op3]; + if (handler->count == 0) + continue; + cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: " + "%016llx %lld\n", + op1, op2, op3, op1, (op3 << 5) | op2, + handler->oname, + handler->count, handler->count); + } + } else { + if (handler->count == 0) + continue; + cpu_fprintf(f, "%02x %02x (%02x %04d) %16s: " + "%016llx %lld\n", + op1, op2, op1, op2, handler->oname, + handler->count, handler->count); + } + } + } else { + if (handler->count == 0) + continue; + cpu_fprintf(f, "%02x (%02x ) %16s: %016llx %lld\n", + op1, op1, handler->oname, + handler->count, handler->count); + } + } +#endif +} + /*****************************************************************************/ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) @@ -2534,8 +3705,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #endif /* Set env in case of segfault during code fetch */ while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { + if (unlikely(env->nb_breakpoints > 0)) { + for (j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == ctx.nip) { gen_op_update_nip(ctx.nip); gen_op_debug(); @@ -2543,7 +3714,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } } } - if (search_pc) { + if (unlikely(search_pc)) { j = gen_opc_ptr - gen_opc_buf; if (lj < j) { lj++; @@ -2586,11 +3757,11 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } } /* Is opcode *REALLY* valid ? */ - if (handler->handler == &gen_invalid) { + if (unlikely(handler->handler == &gen_invalid)) { if (loglevel > 0) { - fprintf(logfile, "invalid/unsupported opcode: " + fprintf(logfile, "invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x%08x %d\n", - opc1(ctx.opcode), opc2(ctx.opcode), + opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); } else { printf("invalid/unsupported opcode: " @@ -2598,8 +3769,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); } - } else { - if ((ctx.opcode & handler->inval) != 0) { + } else { + if (unlikely((ctx.opcode & handler->inval) != 0)) { if (loglevel > 0) { fprintf(logfile, "invalid bits: %08x for opcode: " "%02x -%02x - %02x (0x%08x) (0x%08x)\n", @@ -2609,38 +3780,40 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { printf("invalid bits: %08x for opcode: " "%02x -%02x - %02x (0x%08x) (0x%08x)\n", - ctx.opcode & handler->inval, opc1(ctx.opcode), - opc2(ctx.opcode), opc3(ctx.opcode), + ctx.opcode & handler->inval, opc1(ctx.opcode), + opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); - } + } RET_INVAL(ctxp); break; } } (*(handler->handler))(&ctx); +#if defined(DO_PPC_STATISTICS) + handler->count++; +#endif /* Check trace mode exceptions */ - if ((msr_be && ctx.exception == EXCP_BRANCH) || - /* Check in single step trace mode - * we need to stop except if: - * - rfi, trap or syscall - * - first instruction of an exception handler - */ - (msr_se && (ctx.nip < 0x100 || - ctx.nip > 0xF00 || - (ctx.nip & 0xFC) != 0x04) && - ctx.exception != EXCP_SYSCALL && - ctx.exception != EXCP_SYSCALL_USER && - ctx.exception != EXCP_TRAP)) { + if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) || + /* Check in single step trace mode + * we need to stop except if: + * - rfi, trap or syscall + * - first instruction of an exception handler + */ + (msr_se && (ctx.nip < 0x100 || + ctx.nip > 0xF00 || + (ctx.nip & 0xFC) != 0x04) && + ctx.exception != EXCP_SYSCALL && + ctx.exception != EXCP_SYSCALL_USER && + ctx.exception != EXCP_TRAP))) { RET_EXCP(ctxp, EXCP_TRACE, 0); } - /* if we reach a page boundary or are single stepping, stop * generation */ - if (((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || - (env->singlestep_enabled)) { + if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || + (env->singlestep_enabled))) { break; - } + } #if defined (DO_SINGLE_STEP) break; #endif @@ -2648,28 +3821,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (ctx.exception == EXCP_NONE) { gen_goto_tb(&ctx, 0, ctx.nip); } else if (ctx.exception != EXCP_BRANCH) { - gen_op_set_T0(0); + gen_op_reset_T0(); + /* Generate the return instruction */ + gen_op_exit_tb(); } -#if 1 - /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump - * do bad business and then qemu crashes ! - */ - gen_op_set_T0(0); -#endif - /* Generate the return instruction */ - gen_op_exit_tb(); *gen_opc_ptr = INDEX_op_end; - if (search_pc) { + if (unlikely(search_pc)) { j = gen_opc_ptr - gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; tb->size = 0; -#if 0 - if (loglevel > 0) { - page_dump(logfile); - } -#endif } else { tb->size = ctx.nip - pc_start; } @@ -2679,8 +3841,10 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, cpu_dump_state(env, logfile, fprintf, 0); } if (loglevel & CPU_LOG_TB_IN_ASM) { + int flags; + flags = msr_le; fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le); + target_disas(logfile, pc_start, ctx.nip - pc_start, flags); fprintf(logfile, "\n"); } if (loglevel & CPU_LOG_TB_OP) { diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ddf0c9126..d4159fab4 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1,7 +1,7 @@ /* * PowerPC CPU initialization for qemu. * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -48,7 +48,7 @@ static void spr_write_generic (void *opaque, int sprn) gen_op_store_spr(sprn); } -/* SPR common to all PPC */ +/* SPR common to all PowerPC */ /* XER */ static void spr_read_xer (void *opaque, int sprn) { @@ -93,8 +93,9 @@ static void spr_read_ureg (void *opaque, int sprn) gen_op_load_spr(sprn + 0x10); } -/* SPR common to all non-embedded PPC (ie not 4xx) */ +/* SPR common to all non-embedded PowerPC */ /* DECR */ +#if !defined(CONFIG_USER_ONLY) static void spr_read_decr (void *opaque, int sprn) { gen_op_load_decr(); @@ -104,29 +105,33 @@ static void spr_write_decr (void *opaque, int sprn) { gen_op_store_decr(); } +#endif -/* SPR common to all non-embedded PPC, except 601 */ +/* SPR common to all non-embedded PowerPC, except 601 */ /* Time base */ static void spr_read_tbl (void *opaque, int sprn) { gen_op_load_tbl(); } -static void spr_write_tbl (void *opaque, int sprn) +static void spr_read_tbu (void *opaque, int sprn) { - gen_op_store_tbl(); + gen_op_load_tbu(); } -static void spr_read_tbu (void *opaque, int sprn) +#if !defined(CONFIG_USER_ONLY) +static void spr_write_tbl (void *opaque, int sprn) { - gen_op_load_tbu(); + gen_op_store_tbl(); } static void spr_write_tbu (void *opaque, int sprn) { gen_op_store_tbu(); } +#endif +#if !defined(CONFIG_USER_ONLY) /* IBAT0U...IBAT0U */ /* IBAT0L...IBAT7L */ static void spr_read_ibat (void *opaque, int sprn) @@ -229,11 +234,129 @@ static void spr_write_sdr1 (void *opaque, int sprn) RET_STOP(ctx); } +/* 64 bits PowerPC specific SPRs */ +/* ASR */ +#if defined(TARGET_PPC64) +static void spr_read_asr (void *opaque, int sprn) +{ + gen_op_load_asr(); +} + +static void spr_write_asr (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_asr(); + RET_STOP(ctx); +} +#endif +#endif /* !defined(CONFIG_USER_ONLY) */ + +/* PowerPC 601 specific registers */ +/* RTC */ +static void spr_read_601_rtcl (void *opaque, int sprn) +{ + gen_op_load_601_rtcl(); +} + +static void spr_read_601_rtcu (void *opaque, int sprn) +{ + gen_op_load_601_rtcu(); +} + +#if !defined(CONFIG_USER_ONLY) +static void spr_write_601_rtcu (void *opaque, int sprn) +{ + gen_op_store_601_rtcu(); +} + +static void spr_write_601_rtcl (void *opaque, int sprn) +{ + gen_op_store_601_rtcl(); +} +#endif + +/* Unified bats */ +#if !defined(CONFIG_USER_ONLY) +static void spr_read_601_ubat (void *opaque, int sprn) +{ + gen_op_load_601_bat(sprn & 1, (sprn - SPR_IBAT0U) / 2); +} + +static void spr_write_601_ubatu (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_601_batu((sprn - SPR_IBAT0U) / 2); + RET_STOP(ctx); +} + +static void spr_write_601_ubatl (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_601_batl((sprn - SPR_IBAT0L) / 2); + RET_STOP(ctx); +} +#endif + +/* PowerPC 40x specific registers */ +#if !defined(CONFIG_USER_ONLY) +static void spr_read_40x_pit (void *opaque, int sprn) +{ + gen_op_load_40x_pit(); +} + +static void spr_write_40x_pit (void *opaque, int sprn) +{ + gen_op_store_40x_pit(); +} + +static void spr_write_booke_tcr (void *opaque, int sprn) +{ + gen_op_store_booke_tcr(); +} + +static void spr_write_booke_tsr (void *opaque, int sprn) +{ + gen_op_store_booke_tsr(); +} +#endif + +/* PowerPC 403 specific registers */ +/* PBL1 / PBU1 / PBL2 / PBU2 */ +#if !defined(CONFIG_USER_ONLY) +static void spr_read_403_pbr (void *opaque, int sprn) +{ + gen_op_load_403_pb(sprn - SPR_403_PBL1); +} + +static void spr_write_403_pbr (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_403_pb(sprn - SPR_403_PBL1); + RET_STOP(ctx); +} + static void spr_write_pir (void *opaque, int sprn) { gen_op_store_pir(); } +#endif +#if defined(CONFIG_USER_ONLY) +#define spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, initial_value) \ +do { \ + _spr_register(env, num, name, uea_read, uea_write, initial_value); \ +} while (0) +static inline void _spr_register (CPUPPCState *env, int num, + const unsigned char *name, + void (*uea_read)(void *opaque, int sprn), + void (*uea_write)(void *opaque, int sprn), + target_ulong initial_value) +#else static inline void spr_register (CPUPPCState *env, int num, const unsigned char *name, void (*uea_read)(void *opaque, int sprn), @@ -241,25 +364,30 @@ static inline void spr_register (CPUPPCState *env, int num, void (*oea_read)(void *opaque, int sprn), void (*oea_write)(void *opaque, int sprn), target_ulong initial_value) +#endif { ppc_spr_t *spr; spr = &env->spr_cb[num]; if (spr->name != NULL ||env-> spr[num] != 0x00000000 || - spr->uea_read != NULL || spr->uea_write != NULL || - spr->oea_read != NULL || spr->oea_write != NULL) { +#if !defined(CONFIG_USER_ONLY) + spr->oea_read != NULL || spr->oea_write != NULL || +#endif + spr->uea_read != NULL || spr->uea_write != NULL) { printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num); exit(1); } #if defined(PPC_DEBUG_SPR) - printf("*** register spr %d (%03x) %s val %08" PRIx64 "\n", num, num, name, - (unsigned long long)initial_value); + printf("*** register spr %d (%03x) %s val " REGX "\n", num, num, name, + initial_value); #endif spr->name = name; spr->uea_read = uea_read; spr->uea_write = uea_write; +#if !defined(CONFIG_USER_ONLY) spr->oea_read = oea_read; spr->oea_write = oea_write; +#endif env->spr[num] = initial_value; } @@ -493,6 +621,70 @@ static void gen_tbl (CPUPPCState *env) 0x00000000); } +/* Softare table search registers */ +static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) +{ + env->nb_tlb = nb_tlbs; + env->nb_ways = nb_ways; + env->id_tlbs = 1; + spr_register(env, SPR_DMISS, "DMISS", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_DCMP, "DCMP", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_HASH1, "HASH1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_HASH2, "HASH2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_IMISS, "IMISS", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_ICMP, "ICMP", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_RPA, "RPA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR common to MPC755 and G2 */ +static void gen_spr_G2_755 (CPUPPCState *env) +{ + /* SGPRs */ + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + /* SPR common to all 7xx PowerPC implementations */ static void gen_spr_7xx (CPUPPCState *env) { @@ -513,6 +705,11 @@ static void gen_spr_7xx (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Performance monitors */ /* XXX : not implemented */ spr_register(env, SPR_MMCR0, "MMCR0", @@ -669,151 +866,1366 @@ static void gen_spr_604 (CPUPPCState *env) 0x00000000); } -// XXX: TODO (64 bits PPC sprs) -/* - * ASR => SPR 280 (64 bits) - * FPECR => SPR 1022 (?) - * VRSAVE => SPR 256 (Altivec) - * SCOMC => SPR 276 (64 bits ?) - * SCOMD => SPR 277 (64 bits ?) - * HSPRG0 => SPR 304 (hypervisor) - * HSPRG1 => SPR 305 (hypervisor) - * HDEC => SPR 310 (hypervisor) - * HIOR => SPR 311 (hypervisor) - * RMOR => SPR 312 (970) - * HRMOR => SPR 313 (hypervisor) - * HSRR0 => SPR 314 (hypervisor) - * HSRR1 => SPR 315 (hypervisor) - * LPCR => SPR 316 (970) - * LPIDR => SPR 317 (970) - * ... and more (thermal management, performance counters, ...) - */ - -static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) +/* SPR specific to PowerPC 603 implementation */ +static void gen_spr_603 (CPUPPCState *env) { - /* Default MMU definitions */ - env->nb_BATs = -1; - env->nb_tlb = 0; - env->nb_ways = 0; - /* XXX: missing: - * 32 bits PPC: - * - MPC5xx(x) - * - MPC8xx(x) - * - RCPU (MPC5xx) - */ - spr_register(env, SPR_PVR, "PVR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - def->pvr); - switch (def->pvr & def->pvr_mask) { - case CPU_PPC_604: /* PPC 604 */ - case CPU_PPC_604E: /* PPC 604e */ - case CPU_PPC_604R: /* PPC 604r */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_604(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - break; - - case CPU_PPC_74x: /* PPC 740 / 750 */ - case CPU_PPC_74xP: /* PPC 740P / 750P */ - case CPU_PPC_750CXE: /* IBM PPC 750cxe */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_7xx(env); - /* XXX : not implemented */ - spr_register(env, SPR_L2CR, "L2CR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - break; - - case CPU_PPC_750FX: /* IBM PPC 750 FX */ - case CPU_PPC_750GX: /* IBM PPC 750 GX */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ - gen_high_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_7xx(env); - /* XXX : not implemented */ - spr_register(env, SPR_L2CR, "L2CR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - break; - - default: - gen_spr_generic(env); - break; - } - if (env->nb_BATs == -1) - env->nb_BATs = 4; + &spr_read_generic, &spr_write_generic, + 0x00000000); } -#if defined(PPC_DUMP_CPU) -static void dump_sprs (CPUPPCState *env) +/* SPR specific to PowerPC G2 implementation */ +static void gen_spr_G2 (CPUPPCState *env) { - ppc_spr_t *spr; - uint32_t pvr = env->spr[SPR_PVR]; - uint32_t sr, sw, ur, uw; - int i, j, n; - - printf("* SPRs for PVR=%08x\n", pvr); - for (i = 0; i < 32; i++) { - for (j = 0; j < 32; j++) { - n = (i << 5) | j; - spr = &env->spr_cb[n]; + /* Memory base address */ + /* MBAR */ + spr_register(env, SPR_MBAR, "MBAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* System version register */ + /* SVR */ + spr_register(env, SPR_SVR, "SVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* Exception processing */ + spr_register(env, SPR_CSRR0, "CSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_CSRR1, "CSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Breakpoints */ + /* XXX : not implemented */ + spr_register(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_DABR2, "DABR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IABR2, "IABR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IBCR, "IBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_DBCR, "DBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 602 implementation */ +static void gen_spr_602 (CPUPPCState *env) +{ + /* ESA registers */ + /* XXX : not implemented */ + spr_register(env, SPR_SER, "SER", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_SEBR, "SEBR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_ESASR, "ESASR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Floating point status */ + /* XXX : not implemented */ + spr_register(env, SPR_SP, "SP", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_LT, "LT", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Watchdog timer */ + /* XXX : not implemented */ + spr_register(env, SPR_TCR, "TCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Interrupt base */ + spr_register(env, SPR_IBR, "IBR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 601 implementation */ +static void gen_spr_601 (CPUPPCState *env) +{ + /* Multiplication/division register */ + /* MQ */ + spr_register(env, SPR_MQ, "MQ", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* RTC registers */ + spr_register(env, SPR_601_RTCU, "RTCU", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_601_rtcu, + 0x00000000); + spr_register(env, SPR_601_VRTCU, "RTCU", + &spr_read_601_rtcu, SPR_NOACCESS, + &spr_read_601_rtcu, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_601_RTCL, "RTCL", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_601_rtcl, + 0x00000000); + spr_register(env, SPR_601_VRTCL, "RTCL", + &spr_read_601_rtcl, SPR_NOACCESS, + &spr_read_601_rtcl, SPR_NOACCESS, + 0x00000000); + /* Timer */ +#if 0 /* ? */ + spr_register(env, SPR_601_UDECR, "UDECR", + &spr_read_decr, SPR_NOACCESS, + &spr_read_decr, SPR_NOACCESS, + 0x00000000); +#endif + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + spr_register(env, SPR_IBAT0U, "IBAT0U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatu, + 0x00000000); + spr_register(env, SPR_IBAT0L, "IBAT0L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatl, + 0x00000000); + spr_register(env, SPR_IBAT1U, "IBAT1U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatu, + 0x00000000); + spr_register(env, SPR_IBAT1L, "IBAT1L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatl, + 0x00000000); + spr_register(env, SPR_IBAT2U, "IBAT2U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatu, + 0x00000000); + spr_register(env, SPR_IBAT2L, "IBAT2L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatl, + 0x00000000); + spr_register(env, SPR_IBAT3U, "IBAT3U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatu, + 0x00000000); + spr_register(env, SPR_IBAT3L, "IBAT3L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatl, + 0x00000000); +} + +/* PowerPC BookE SPR */ +static void gen_spr_BookE (CPUPPCState *env) +{ + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* Interrupt processing */ + spr_register(env, SPR_CSRR0, "CSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_CSRR1, "CSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Debug */ + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC1, "IAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DAC1, "DAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR0, "DBCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR1, "DBCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR2, "DBCR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBSR, "DBSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_DEAR, "DEAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_ESR, "ESR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_EVPR, "EVPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR0, "IVOR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR1, "IVOR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR2, "IVOR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR3, "IVOR3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR4, "IVOR4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR5, "IVOR5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR6, "IVOR6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR7, "IVOR7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR8, "IVOR8", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR9, "IVOR9", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR10, "IVOR10", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR11, "IVOR11", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR12, "IVOR12", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR13, "IVOR13", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR14, "IVOR14", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR15, "IVOR15", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_PID, "PID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_TCR, "TCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tcr, + 0x00000000); + spr_register(env, SPR_BOOKE_TSR, "TSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tsr, + 0x00000000); + /* Timer */ + spr_register(env, SPR_DECR, "DECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_decr, &spr_write_decr, + 0x00000000); + spr_register(env, SPR_BOOKE_DECAR, "DECAR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + /* SPRGs */ + spr_register(env, SPR_USPRG0, "USPRG0", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); +} + +/* SPR specific to PowerPC 440 implementation */ +static void gen_spr_440 (CPUPPCState *env) +{ + /* Cache control */ + /* XXX : not implemented */ + spr_register(env, SPR_440_DNV0, "DNV0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DNV1, "DNV1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DNV2, "DNV2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DNV3, "DNV3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVT0, "DVT0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVT1, "DVT1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVT2, "DVT2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVT3, "DVT3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVLIM, "DVLIM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_INV0, "INV0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_INV1, "INV1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_INV2, "INV2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_INV3, "INV3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVT0, "IVT0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVT1, "IVT1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVT2, "IVT2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVT3, "IVT3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVLIM, "IVLIM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Cache debug */ + /* XXX : not implemented */ + spr_register(env, SPR_440_DCBTRH, "DCBTRH", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DCBTRL, "DCBTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_4xx_ICDBDR, "ICDBDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_ICBTRH, "ICBTRH", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_ICBTRL, "ICBTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DBDR, "DBDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Processor control */ + spr_register(env, SPR_4xx_CCR0, "CCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_440_RSTCFG, "RSTCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* Storage control */ + spr_register(env, SPR_440_MMUCR, "MMUCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR shared between PowerPC 40x implementations */ +static void gen_spr_40x (CPUPPCState *env) +{ + /* Cache */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCCR, "DCCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_ICCR, "ICCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_4xx_ICDBDR, "ICDBDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* Bus access control */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + spr_register(env, SPR_40x_ZPR, "ZPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* MMU */ + spr_register(env, SPR_40x_PID, "PID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Exception */ + spr_register(env, SPR_40x_DEAR, "DEAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_ESR, "ESR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_EVPR, "EVPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_SRR2, "SRR2", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_SRR3, "SRR3", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Timers */ + spr_register(env, SPR_40x_PIT, "PIT", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_40x_pit, &spr_write_40x_pit, + 0x00000000); + spr_register(env, SPR_40x_TCR, "TCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tcr, + 0x00000000); + spr_register(env, SPR_40x_TSR, "TSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tsr, + 0x00000000); + /* Debug interface */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC1, "DAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DBCR0, "DBCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DBSR, "DBSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + /* Last reset was system reset (system boot */ + 0x00000300); + /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC1, "IAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 405 implementation */ +static void gen_spr_405 (CPUPPCState *env) +{ + spr_register(env, SPR_4xx_CCR0, "CCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00700000); + /* Debug */ + /* XXX : not implemented */ + spr_register(env, SPR_405_DBCR1, "DBCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Storage control */ + /* XXX : not implemented */ + spr_register(env, SPR_405_SLER, "SLER", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_SU0R, "SU0R", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* SPRG */ + spr_register(env, SPR_USPRG0, "USPRG0", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Debug */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR shared between PowerPC 401 & 403 implementations */ +static void gen_spr_401_403 (CPUPPCState *env) +{ + /* Time base */ + spr_register(env, SPR_403_VTBL, "TBL", + &spr_read_tbl, SPR_NOACCESS, + &spr_read_tbl, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_403_TBL, "TBL", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_tbl, + 0x00000000); + spr_register(env, SPR_403_VTBU, "TBU", + &spr_read_tbu, SPR_NOACCESS, + &spr_read_tbu, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_403_TBU, "TBU", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_tbu, + 0x00000000); + /* Debug */ + /* XXX: not implemented */ + spr_register(env, SPR_403_CDBCR, "CDBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 403 implementation */ +static void gen_spr_403 (CPUPPCState *env) +{ + /* MMU */ + spr_register(env, SPR_403_PBL1, "PBL1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_403_pbr, &spr_write_403_pbr, + 0x00000000); + spr_register(env, SPR_403_PBU1, "PBU1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_403_pbr, &spr_write_403_pbr, + 0x00000000); + spr_register(env, SPR_403_PBL2, "PBL2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_403_pbr, &spr_write_403_pbr, + 0x00000000); + spr_register(env, SPR_403_PBU2, "PBU2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_403_pbr, &spr_write_403_pbr, + 0x00000000); + /* Debug */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC compression coprocessor extension */ +#if defined (TODO) +static void gen_spr_compress (CPUPPCState *env) +{ + spr_register(env, SPR_401_SKR, "SKR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} +#endif + +// XXX: TODO (64 bits PowerPC SPRs) +/* + * ASR => SPR 280 (64 bits) + * FPECR => SPR 1022 (?) + * VRSAVE => SPR 256 (Altivec) + * SCOMC => SPR 276 (64 bits ?) + * SCOMD => SPR 277 (64 bits ?) + * HSPRG0 => SPR 304 (hypervisor) + * HSPRG1 => SPR 305 (hypervisor) + * HDEC => SPR 310 (hypervisor) + * HIOR => SPR 311 (hypervisor) + * RMOR => SPR 312 (970) + * HRMOR => SPR 313 (hypervisor) + * HSRR0 => SPR 314 (hypervisor) + * HSRR1 => SPR 315 (hypervisor) + * LPCR => SPR 316 (970) + * LPIDR => SPR 317 (970) + * ... and more (thermal management, performance counters, ...) + */ + +static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) +{ + env->reserve = -1; + /* Default MMU definitions */ + env->nb_BATs = -1; + env->nb_tlb = 0; + env->nb_ways = 0; + /* XXX: missing: + * 32 bits PowerPC: + * - MPC5xx(x) + * - MPC8xx(x) + * - RCPU (same as MPC5xx ?) + */ + spr_register(env, SPR_PVR, "PVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + def->pvr); + printf("%s: PVR %08x mask %08x => %08x\n", __func__, + def->pvr, def->pvr_mask, def->pvr & def->pvr_mask); + switch (def->pvr & def->pvr_mask) { + /* Embedded PowerPC from IBM */ + case CPU_PPC_401A1: /* 401 A1 family */ + case CPU_PPC_401B2: /* 401 B2 family */ + case CPU_PPC_401C2: /* 401 C2 family */ + case CPU_PPC_401D2: /* 401 D2 family */ + case CPU_PPC_401E2: /* 401 E2 family */ + case CPU_PPC_401F2: /* 401 F2 family */ + case CPU_PPC_401G2: /* 401 G2 family */ + case CPU_PPC_IOP480: /* IOP 480 family */ + case CPU_PPC_COBRA: /* IBM Processor for Network Resources */ + gen_spr_generic(env); + gen_spr_40x(env); + gen_spr_401_403(env); +#if defined (TODO) + /* XXX: optional ? */ + gen_spr_compress(env); +#endif + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + case CPU_PPC_403GA: /* 403 GA family */ + case CPU_PPC_403GB: /* 403 GB family */ + case CPU_PPC_403GC: /* 403 GC family */ + case CPU_PPC_403GCX: /* 403 GCX family */ + gen_spr_generic(env); + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_403(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + case CPU_PPC_405CR: /* 405 GP/CR family */ + case CPU_PPC_405EP: /* 405 EP family */ + case CPU_PPC_405GPR: /* 405 GPR family */ + case CPU_PPC_405D2: /* 405 D2 family */ + case CPU_PPC_405D4: /* 405 D4 family */ + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_40x(env); + gen_spr_405(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + case CPU_PPC_NPE405H: /* NPe405 H family */ + case CPU_PPC_NPE405H2: + case CPU_PPC_NPE405L: /* Npe405 L family */ + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_40x(env); + gen_spr_405(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + +#if defined (TODO) + case CPU_PPC_STB01000: +#endif +#if defined (TODO) + case CPU_PPC_STB01010: +#endif +#if defined (TODO) + case CPU_PPC_STB0210: +#endif + case CPU_PPC_STB03: /* STB03 family */ +#if defined (TODO) + case CPU_PPC_STB043: /* STB043 family */ +#endif +#if defined (TODO) + case CPU_PPC_STB045: /* STB045 family */ +#endif + case CPU_PPC_STB25: /* STB25 family */ +#if defined (TODO) + case CPU_PPC_STB130: /* STB130 family */ +#endif + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_40x(env); + gen_spr_405(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + case CPU_PPC_440EP: /* 440 EP family */ + case CPU_PPC_440GP: /* 440 GP family */ + case CPU_PPC_440GX: /* 440 GX family */ + case CPU_PPC_440GXc: /* 440 GXc family */ + case CPU_PPC_440GXf: /* 440 GXf family */ + case CPU_PPC_440SP: /* 440 SP family */ + case CPU_PPC_440SP2: + case CPU_PPC_440SPE: /* 440 SPE family */ + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + gen_spr_440(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + /* Embedded PowerPC from Freescale */ +#if defined (TODO) + case CPU_PPC_5xx: + break; +#endif +#if defined (TODO) + case CPU_PPC_8xx: /* MPC821 / 823 / 850 / 860 */ + break; +#endif +#if defined (TODO) + case CPU_PPC_82xx_HIP3: /* MPC8240 / 8260 */ + case CPU_PPC_82xx_HIP4: /* MPC8240 / 8260 */ + break; +#endif +#if defined (TODO) + case CPU_PPC_827x: /* MPC 827x / 828x */ + break; +#endif + + /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */ + case CPU_PPC_e500v110: + case CPU_PPC_e500v120: + case CPU_PPC_e500v210: + case CPU_PPC_e500v220: + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + +#if defined (TODO) + case CPU_PPC_e600: + break; +#endif + + /* 32 bits PowerPC */ + case CPU_PPC_601: /* PowerPC 601 */ + gen_spr_generic(env); + gen_spr_ne_601(env); + gen_spr_601(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_601_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_601_HID5, "HID5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ +#if 0 /* ? */ + spr_register(env, SPR_601_HID15, "HID15", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +#endif + env->nb_tlb = 64; + env->nb_ways = 2; + env->id_tlbs = 0; + env->id_tlbs = 0; + break; + + case CPU_PPC_602: /* PowerPC 602 */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + gen_spr_602(env); + /* hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_603: /* PowerPC 603 */ + case CPU_PPC_603E: /* PowerPC 603e */ + case CPU_PPC_603E7v: + case CPU_PPC_603E7v2: + case CPU_PPC_603P: /* PowerPC 603p */ + case CPU_PPC_603R: /* PowerPC 603r */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + gen_spr_603(env); + /* hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_G2: /* PowerPC G2 family */ + case CPU_PPC_G2H4: + case CPU_PPC_G2gp: + case CPU_PPC_G2ls: + case CPU_PPC_G2LE: /* PowerPC G2LE family */ + case CPU_PPC_G2LEgp: + case CPU_PPC_G2LEls: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + /* Memory management */ + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + gen_spr_G2_755(env); + gen_spr_G2(env); + /* Hardware implementation register */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_604: /* PowerPC 604 */ + case CPU_PPC_604E: /* PowerPC 604e */ + case CPU_PPC_604R: /* PowerPC 604r */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_604(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_74x: /* PowerPC 740 / 750 */ + case CPU_PPC_740E: + case CPU_PPC_750E: + case CPU_PPC_74xP: /* PowerPC 740P / 750P */ + case CPU_PPC_750CXE21: /* IBM PowerPC 750cxe */ + case CPU_PPC_750CXE22: + case CPU_PPC_750CXE23: + case CPU_PPC_750CXE24: + case CPU_PPC_750CXE24b: + case CPU_PPC_750CXE31: + case CPU_PPC_750CXE31b: + case CPU_PPC_750CXR: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_7xx(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_750FX10: /* IBM PowerPC 750 FX */ + case CPU_PPC_750FX20: + case CPU_PPC_750FX21: + case CPU_PPC_750FX22: + case CPU_PPC_750FX23: + case CPU_PPC_750GX10: /* IBM PowerPC 750 GX */ + case CPU_PPC_750GX11: + case CPU_PPC_750GX12: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ + gen_high_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_7xx(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_755_10: /* PowerPC 755 */ + case CPU_PPC_755_11: + case CPU_PPC_755_20: + case CPU_PPC_755D: + case CPU_PPC_755E: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + /* Memory management */ + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + gen_spr_G2_755(env); + /* L2 cache control */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTC, "ICTC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_L2PM, "L2PM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + +#if defined (TODO) + /* G4 family */ + case CPU_PPC_7400: /* PowerPC 7400 */ + case CPU_PPC_7410C: /* PowerPC 7410 */ + case CPU_PPC_7410D: + case CPU_PPC_7410E: + case CPU_PPC_7441: /* PowerPC 7441 */ + case CPU_PPC_7445: /* PowerPC 7445 */ + case CPU_PPC_7447: /* PowerPC 7447 */ + case CPU_PPC_7447A: /* PowerPC 7447A */ + case CPU_PPC_7448: /* PowerPC 7448 */ + case CPU_PPC_7450: /* PowerPC 7450 */ + case CPU_PPC_7450b: + case CPU_PPC_7451: /* PowerPC 7451 */ + case CPU_PPC_7451G: + case CPU_PPC_7455: /* PowerPC 7455 */ + case CPU_PPC_7455F: + case CPU_PPC_7455G: + case CPU_PPC_7457: /* PowerPC 7457 */ + case CPU_PPC_7457C: + case CPU_PPC_7457A: /* PowerPC 7457A */ + break; +#endif + +#if defined (TODO) + /* 64 bits PowerPC */ + case CPU_PPC_620: /* PowerPC 620 */ + case CPU_PPC_630: /* PowerPC 630 (Power 3) */ + case CPU_PPC_631: /* PowerPC 631 (Power 3+) */ + case CPU_PPC_POWER4: /* Power 4 */ + case CPU_PPC_POWER4P: /* Power 4+ */ + case CPU_PPC_POWER5: /* Power 5 */ + case CPU_PPC_POWER5P: /* Power 5+ */ + case CPU_PPC_970: /* PowerPC 970 */ + case CPU_PPC_970FX10: /* PowerPC 970 FX */ + case CPU_PPC_970FX20: + case CPU_PPC_970FX21: + case CPU_PPC_970FX30: + case CPU_PPC_970FX31: + case CPU_PPC_970MP10: /* PowerPC 970 MP */ + case CPU_PPC_970MP11: + case CPU_PPC_CELL10: /* Cell family */ + case CPU_PPC_CELL20: + case CPU_PPC_CELL30: + case CPU_PPC_CELL31: + case CPU_PPC_RS64: /* Apache (RS64/A35) */ + case CPU_PPC_RS64II: /* NorthStar (RS64-II/A50) */ + case CPU_PPC_RS64III: /* Pulsar (RS64-III) */ + case CPU_PPC_RS64IV: /* IceStar/IStar/SStar (RS64-IV) */ + break; +#endif + +#if defined (TODO) + /* POWER */ + case CPU_POWER: /* POWER */ + case CPU_POWER2: /* POWER2 */ + break; +#endif + + default: + gen_spr_generic(env); + break; + } + if (env->nb_BATs == -1) + env->nb_BATs = 4; + /* Allocate TLBs buffer when needed */ + if (env->nb_tlb != 0) { + int nb_tlb = env->nb_tlb; + if (env->id_tlbs != 0) + nb_tlb *= 2; + env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t)); + /* Pre-compute some useful values */ + env->tlb_per_way = env->nb_tlb / env->nb_ways; + } +} + +#if defined(PPC_DUMP_CPU) +static void dump_sprs (CPUPPCState *env) +{ + ppc_spr_t *spr; + uint32_t pvr = env->spr[SPR_PVR]; + uint32_t sr, sw, ur, uw; + int i, j, n; + + printf("* SPRs for PVR=%08x\n", pvr); + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + n = (i << 5) | j; + spr = &env->spr_cb[n]; +#if !defined(CONFIG_USER_ONLY) sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS; sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS; +#else + sw = 0; + sr = 0; +#endif uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS; ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS; if (sw || sr || uw || ur) { @@ -889,7 +2301,7 @@ static int register_direct_insn (opc_handler_t **ppc_opcodes, { if (insert_in_table(ppc_opcodes, idx, handler) < 0) { printf("*** ERROR: opcode %02x already assigned in main " - "opcode table\n", idx); + "opcode table\n", idx); return -1; } @@ -903,20 +2315,20 @@ static int register_ind_in_table (opc_handler_t **table, if (table[idx1] == &invalid_handler) { if (create_new_table(table, idx1) < 0) { printf("*** ERROR: unable to create indirect table " - "idx=%02x\n", idx1); + "idx=%02x\n", idx1); return -1; } } else { if (!is_indirect_opcode(table[idx1])) { printf("*** ERROR: idx %02x already assigned to a direct " - "opcode\n", idx1); + "opcode\n", idx1); return -1; } } if (handler != NULL && insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { printf("*** ERROR: opcode %02x already assigned in " - "opcode table %02x\n", idx2, idx1); + "opcode table %02x\n", idx2, idx1); return -1; } @@ -925,7 +2337,7 @@ static int register_ind_in_table (opc_handler_t **table, static int register_ind_insn (opc_handler_t **ppc_opcodes, unsigned char idx1, unsigned char idx2, - opc_handler_t *handler) + opc_handler_t *handler) { int ret; @@ -936,17 +2348,17 @@ static int register_ind_insn (opc_handler_t **ppc_opcodes, static int register_dblind_insn (opc_handler_t **ppc_opcodes, unsigned char idx1, unsigned char idx2, - unsigned char idx3, opc_handler_t *handler) + unsigned char idx3, opc_handler_t *handler) { if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { printf("*** ERROR: unable to join indirect table idx " - "[%02x-%02x]\n", idx1, idx2); + "[%02x-%02x]\n", idx1, idx2); return -1; } if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, handler) < 0) { printf("*** ERROR: unable to insert opcode " - "[%02x-%02x-%02x]\n", idx1, idx2, idx3); + "[%02x-%02x-%02x]\n", idx1, idx2, idx3); return -1; } @@ -1012,21 +2424,22 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) fill_new_table(env->opcodes, 0x40); #if defined(PPC_DUMP_CPU) - printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name); + printf("* PowerPC instructions for PVR %08x: %s flags %08x %08x\n", + def->pvr, def->name, def->insns_flags, def->flags); #endif if (&opc_start < &opc_end) { - start = &opc_start; - end = &opc_end; + start = &opc_start; + end = &opc_end; } else { - start = &opc_end; - end = &opc_start; + start = &opc_end; + end = &opc_start; } for (opc = start + 1; opc != end; opc++) { if ((opc->handler.type & def->insns_flags) != 0) { if (register_insn(env->opcodes, opc) < 0) { - printf("*** ERROR initializing PPC instruction " - "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, - opc->opc3); + printf("*** ERROR initializing PowerPC instruction " + "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + opc->opc3); return -1; } #if defined(PPC_DUMP_CPU) @@ -1038,7 +2451,7 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) } else { printf(" %02x %02x -- (%2d %4d) : %s\n", opc->opc1, opc->opc2, opc->opc1, opc->opc2, - opc->oname); + opc->oname); } } else { printf(" %02x %02x %02x (%2d %4d) : %s\n", @@ -1061,23 +2474,22 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) { env->msr_mask = def->msr_mask; env->flags = def->flags; - if (create_ppc_opcodes(env, def) < 0) { - printf("Error creating opcodes table\n"); - fflush(stdout); - fflush(stderr); + if (create_ppc_opcodes(env, def) < 0) return -1; - } init_ppc_proc(env, def); #if defined(PPC_DUMP_CPU) dump_sprs(env); + if (env->tlb != NULL) { + printf("%d %s TLB in %d ways\n", env->nb_tlb, + env->id_tlbs ? "splitted" : "merged", env->nb_ways); + } #endif - fflush(stdout); - fflush(stderr); return 0; } -CPUPPCState *cpu_ppc_init(void) +void do_compute_hflags (CPUPPCState *env); +CPUPPCState *cpu_ppc_init (void) { CPUPPCState *env; @@ -1112,911 +2524,1171 @@ void cpu_ppc_close(CPUPPCState *env) /*****************************************************************************/ /* PowerPC CPU definitions */ static ppc_def_t ppc_defs[] = -{ - /* Embedded PPC */ -#if defined (TODO) - /* PPC 401 */ { - .name = "401", - .pvr = CPU_PPC_401, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = xxx, - }, + /* Embedded PowerPC */ +#if defined (TODO) + /* PowerPC 401 */ + { + .name = "401", + .pvr = CPU_PPC_401, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* IOP480 (401 microcontroler) */ - { - .name = "iop480", - .pvr = CPU_PPC_IOP480, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = xxx, - }, + /* IOP480 (401 microcontroler) */ + { + .name = "iop480", + .pvr = CPU_PPC_IOP480, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* PPC 403 GA */ - { - .name = "403ga", - .pvr = CPU_PPC_403GA, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, + /* IBM Processor for Network Resources */ + { + .name = "Cobra", + .pvr = CPU_PPC_COBRA, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* PPC 403 GB */ - { - .name = "403gb", - .pvr = CPU_PPC_403GB, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, + /* Generic PowerPC 403 */ + { + .name = "403", + .pvr = CPU_PPC_403, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 403 GC */ - { - .name = "403gc", - .pvr = CPU_PPC_403GC, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, + /* PowerPC 403 GA */ + { + .name = "403ga", + .pvr = CPU_PPC_403GA, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 403 GCX */ - { - .name = "403gcx", - .pvr = CPU_PPC_403GCX, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, + /* PowerPC 403 GB */ + { + .name = "403gb", + .pvr = CPU_PPC_403GB, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 405 CR */ - { - .name = "405cr", - .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 403 GC */ + { + .name = "403gc", + .pvr = CPU_PPC_403GC, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 405 GP */ - { - .name = "405gp", - .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 403 GCX */ + { + .name = "403gcx", + .pvr = CPU_PPC_403GCX, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 405 EP */ - { - .name = "405ep", - .pvr = CPU_PPC_405EP, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* Generic PowerPC 405 */ + { + .name = "405", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 405 GPR */ - { - .name = "405gpr", - .pvr = CPU_PPC_405GPR, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 CR */ + { + .name = "405cr", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 405 D2 */ - { - .name = "405d2", - .pvr = CPU_PPC_405D2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 GP */ + { + .name = "405gp", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 405 D4 */ - { - .name = "405d4", - .pvr = CPU_PPC_405D4, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 EP */ + { + .name = "405ep", + .pvr = CPU_PPC_405EP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* Npe405 H */ - { - .name = "Npe405H", - .pvr = CPU_PPC_NPE405H, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 GPR */ + { + .name = "405gpr", + .pvr = CPU_PPC_405GPR, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* Npe405 L */ - { - .name = "Npe405L", - .pvr = CPU_PPC_NPE405L, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 D2 */ + { + .name = "405d2", + .pvr = CPU_PPC_405D2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB03xx */ - { - .name = "STB03", - .pvr = CPU_PPC_STB03, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 D4 */ + { + .name = "405d4", + .pvr = CPU_PPC_405D4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB04xx */ - { - .name = "STB04", - .pvr = CPU_PPC_STB04, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* Npe405 H */ + { + .name = "Npe405H", + .pvr = CPU_PPC_NPE405H, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB25xx */ - { - .name = "STB25", - .pvr = CPU_PPC_STB25, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* Npe405 L */ + { + .name = "Npe405L", + .pvr = CPU_PPC_NPE405L, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 440 EP */ - { - .name = "440ep", - .pvr = CPU_PPC_440EP, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* STB010000 */ + { + .name = "STB01000", + .pvr = CPU_PPC_STB01000, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 440 GP */ - { - .name = "440gp", - .pvr = CPU_PPC_440GP, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* STB01010 */ + { + .name = "STB01010", + .pvr = CPU_PPC_STB01010, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 440 GX */ - { - .name = "440gx", - .pvr = CPU_PPC_440GX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* STB0210 */ + { + .name = "STB0210", + .pvr = CPU_PPC_STB0210, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif - - /* 32 bits "classic" powerpc */ #if defined (TODO) - /* PPC 601 */ - { - .name = "601", - .pvr = CPU_PPC_601, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_601, - .flags = PPC_FLAGS_601, - .msr_mask = 0x000000000000FD70, - }, + /* STB03xx */ + { + .name = "STB03", + .pvr = CPU_PPC_STB03, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 602 */ - { - .name = "602", - .pvr = CPU_PPC_602, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_602, - .flags = PPC_FLAGS_602, - .msr_mask = 0x0000000000C7FF73, - }, + /* STB043x */ + { + .name = "STB043", + .pvr = CPU_PPC_STB043, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 603 */ - { - .name = "603", - .pvr = CPU_PPC_603, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, + /* STB045x */ + { + .name = "STB045", + .pvr = CPU_PPC_STB045, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 603e */ - { - .name = "603e", - .pvr = CPU_PPC_603E, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - { - .name = "Stretch", - .pvr = CPU_PPC_603E, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, + /* STB25xx */ + { + .name = "STB25", + .pvr = CPU_PPC_STB25, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 603ev */ - { - .name = "603ev", - .pvr = CPU_PPC_603EV, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, + /* STB130 */ + { + .name = "STB130", + .pvr = CPU_PPC_STB130, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif + /* Xilinx PowerPC 405 cores */ #if defined (TODO) - /* PPC 603r */ - { - .name = "603r", - .pvr = CPU_PPC_603R, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - { - .name = "Goldeneye", - .pvr = CPU_PPC_603R, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, + { + .name = "x2vp4", + .pvr = CPU_PPC_X2VP4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp7", + .pvr = CPU_PPC_X2VP7, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp20", + .pvr = CPU_PPC_X2VP20, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp50", + .pvr = CPU_PPC_X2VP50, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ - { - .name = "G2", - .pvr = CPU_PPC_G2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, - }, - { /* Same as G2, with LE mode support */ - .name = "G2le", - .pvr = CPU_PPC_G2LE, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3, - }, -#endif - /* PPC 604 */ - { - .name = "604", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* PPC 604e */ - { - .name = "604e", - .pvr = CPU_PPC_604E, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* PPC 604r */ - { - .name = "604r", - .pvr = CPU_PPC_604R, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* generic G3 */ - { - .name = "G3", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC740 (G3) */ - { - .name = "740", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Arthur", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, + /* PowerPC 440 EP */ + { + .name = "440ep", + .pvr = CPU_PPC_440EP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* MPC745 (G3) */ - { - .name = "745", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Goldfinger", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* MPC750 (G3) */ - { - .name = "750", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC755 (G3) */ - { - .name = "755", - .pvr = CPU_PPC_755, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, + /* PowerPC 440 GR */ + { + .name = "440gr", + .pvr = CPU_PPC_440GR, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* MPC740P (G3) */ - { - .name = "740p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Conan/Doyle", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, + /* PowerPC 440 GP */ + { + .name = "440gp", + .pvr = CPU_PPC_440GP, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* MPC745P (G3) */ - { - .name = "745p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* MPC750P (G3) */ - { - .name = "750p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC755P (G3) */ - { - .name = "755p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* IBM 750CXe (G3 embedded) */ - { - .name = "750cxe", - .pvr = CPU_PPC_750CXE, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - /* IBM 750FX (G3 embedded) */ - { - .name = "750fx", - .pvr = CPU_PPC_750FX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - /* IBM 750GX (G3 embedded) */ - { - .name = "750gx", - .pvr = CPU_PPC_750GX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* generic G4 */ - { - .name = "G4", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 GX */ + { + .name = "440gx", + .pvr = CPU_PPC_440GX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PPC 7400 (G4) */ - { - .name = "7400", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Max", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 GXc */ + { + .name = "440gxc", + .pvr = CPU_PPC_440GXC, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PPC 7410 (G4) */ - { - .name = "7410", - .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Nitro", - .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif - /* XXX: 7441 */ - /* XXX: 7445 */ - /* XXX: 7447 */ - /* XXX: 7447A */ -#if defined (TODO) - /* PPC 7450 (G4) */ - { - .name = "7450", - .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Vger", - .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 GXf */ + { + .name = "440gxf", + .pvr = CPU_PPC_440GXF, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif - /* XXX: 7451 */ #if defined (TODO) - /* PPC 7455 (G4) */ - { - .name = "7455", - .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 6", - .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 SP */ + { + .name = "440sp", + .pvr = CPU_PPC_440SP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PPC 7457 (G4) */ - { - .name = "7457", - .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 7", - .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 SP2 */ + { + .name = "440sp2", + .pvr = CPU_PPC_440SP2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PPC 7457A (G4) */ - { - .name = "7457A", - .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 7 PM", - .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 SPE */ + { + .name = "440spe", + .pvr = CPU_PPC_440SPE, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif - /* 64 bits PPC */ + /* Fake generic BookE PowerPC */ + { + .name = "BookE", + .pvr = CPU_PPC_e500, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_BOOKE, + .flags = PPC_FLAGS_BOOKE, + .msr_mask = 0x000000000006D630, + }, + /* PowerPC 460 cores - TODO */ + /* PowerPC MPC 5xx cores - TODO */ + /* PowerPC MPC 8xx cores - TODO */ + /* PowerPC MPC 8xxx cores - TODO */ + /* e200 cores - TODO */ + /* e500 cores - TODO */ + /* e600 cores - TODO */ + + /* 32 bits "classic" PowerPC */ #if defined (TODO) - /* PPC 620 */ - { - .name = "620", - .pvr = CPU_PPC_620, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_620, - .flags = PPC_FLAGS_620, - .msr_mask = 0x800000000005FF73, - }, + /* PowerPC 601 */ + { + .name = "601", + .pvr = CPU_PPC_601, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_601, + .flags = PPC_FLAGS_601, + .msr_mask = 0x000000000000FD70, + }, #endif #if defined (TODO) - /* PPC 630 (POWER3) */ - { - .name = "630", - .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_630, - .flags = PPC_FLAGS_630, - .msr_mask = xxx, - } - { - .name = "POWER3", - .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_630, - .flags = PPC_FLAGS_630, - .msr_mask = xxx, - } + /* PowerPC 602 */ + { + .name = "602", + .pvr = CPU_PPC_602, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_602, + .flags = PPC_FLAGS_602, + .msr_mask = 0x0000000000C7FF73, + }, #endif + /* PowerPC 603 */ + { + .name = "603", + .pvr = CPU_PPC_603, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e */ + { + .name = "603e", + .pvr = CPU_PPC_603E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + { + .name = "Stretch", + .pvr = CPU_PPC_603E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603p */ + { + .name = "603p", + .pvr = CPU_PPC_603P, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7 */ + { + .name = "603e7", + .pvr = CPU_PPC_603E7, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7v */ + { + .name = "603e7v", + .pvr = CPU_PPC_603E7v, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7v2 */ + { + .name = "603e7v2", + .pvr = CPU_PPC_603E7v2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603r */ + { + .name = "603r", + .pvr = CPU_PPC_603R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + { + .name = "Goldeneye", + .pvr = CPU_PPC_603R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, #if defined (TODO) - /* PPC 631 (Power 3+)*/ - { - .name = "631", - .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_631, - .flags = PPC_FLAGS_631, - .msr_mask = xxx, - }, - { - .name = "POWER3+", - .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_631, - .flags = PPC_FLAGS_631, - .msr_mask = xxx, - }, + /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ + { + .name = "G2", + .pvr = CPU_PPC_G2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2h4", + .pvr = CPU_PPC_G2H4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2gp", + .pvr = CPU_PPC_G2gp, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2ls", + .pvr = CPU_PPC_G2ls, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { /* Same as G2, with LE mode support */ + .name = "G2le", + .pvr = CPU_PPC_G2LE, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, + { + .name = "G2legp", + .pvr = CPU_PPC_G2LEgp, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, + { + .name = "G2lels", + .pvr = CPU_PPC_G2LEls, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, #endif + /* PowerPC 604 */ + { + .name = "604", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* PowerPC 604e */ + { + .name = "604e", + .pvr = CPU_PPC_604E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* PowerPC 604r */ + { + .name = "604r", + .pvr = CPU_PPC_604R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* generic G3 */ + { + .name = "G3", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* MPC740 (G3) */ + { + .name = "740", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Arthur", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* POWER4 */ - { - .name = "POWER4", - .pvr = CPU_PPC_POWER4, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER4, - .flags = PPC_FLAGS_POWER4, - .msr_mask = xxx, - }, + /* MPC745 (G3) */ + { + .name = "745", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Goldfinger", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, #endif + /* MPC750 (G3) */ + { + .name = "750", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* POWER4p */ - { - .name = "POWER4+", - .pvr = CPU_PPC_POWER4P, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER4, - .flags = PPC_FLAGS_POWER4, - .msr_mask = xxx, - }, + /* MPC755 (G3) */ + { + .name = "755", + .pvr = CPU_PPC_755, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, #endif + /* MPC740P (G3) */ + { + .name = "740p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Conan/Doyle", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* POWER5 */ - { - .name = "POWER5", - .pvr = CPU_PPC_POWER5, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER5, - .flags = PPC_FLAGS_POWER5, - .msr_mask = xxx, - }, + /* MPC745P (G3) */ + { + .name = "745p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, #endif + /* MPC750P (G3) */ + { + .name = "750p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* POWER5+ */ - { - .name = "POWER5+", - .pvr = CPU_PPC_POWER5P, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER5, - .flags = PPC_FLAGS_POWER5, - .msr_mask = xxx, - }, + /* MPC755P (G3) */ + { + .name = "755p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, #endif + /* IBM 750CXe (G3 embedded) */ + { + .name = "750cxe", + .pvr = CPU_PPC_750CXE, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* IBM 750FX (G3 embedded) */ + { + .name = "750fx", + .pvr = CPU_PPC_750FX, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* IBM 750GX (G3 embedded) */ + { + .name = "750gx", + .pvr = CPU_PPC_750GX, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* PPC 970 */ - { - .name = "970", - .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_970, - .flags = PPC_FLAGS_970, - .msr_mask = 0x900000000204FF36, - }, + /* generic G4 */ + { + .name = "G4", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif #if defined (TODO) - /* PPC 970FX (G5) */ - { - .name = "970fx", - .pvr = CPU_PPC_970FX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_970FX, - .flags = PPC_FLAGS_970FX, - .msr_mask = 0x800000000204FF36, - }, -#endif -#if defined (TODO) - /* RS64 (Apache/A35) */ - /* This one seems to support the whole POWER2 instruction set - * and the PowerPC 64 one. - */ - { - .name = "RS64", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "Apache", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "A35", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, + /* PowerPC 7400 (G4) */ + { + .name = "7400", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Max", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif #if defined (TODO) - /* RS64-II (NorthStar/A50) */ - { - .name = "RS64-II", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "NortStar", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "A50", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, + /* PowerPC 7410 (G4) */ + { + .name = "7410", + .pvr = CPU_PPC_7410, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Nitro", + .pvr = CPU_PPC_7410, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif + /* XXX: 7441 */ + /* XXX: 7445 */ + /* XXX: 7447 */ + /* XXX: 7447A */ #if defined (TODO) - /* RS64-III (Pulsar) */ - { - .name = "RS64-III", - .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "Pulsar", - .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, + /* PowerPC 7450 (G4) */ + { + .name = "7450", + .pvr = CPU_PPC_7450, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Vger", + .pvr = CPU_PPC_7450, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif + /* XXX: 7451 */ #if defined (TODO) - /* RS64-IV (IceStar/IStar/SStar) */ - { - .name = "RS64-IV", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "IceStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "IStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "SStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, + /* PowerPC 7455 (G4) */ + { + .name = "7455", + .pvr = CPU_PPC_7455, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 6", + .pvr = CPU_PPC_7455, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif - /* POWER */ #if defined (TODO) - /* Original POWER */ - { - .name = "POWER", - .pvr = CPU_POWER, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER, - .flags = PPC_FLAGS_POWER, - .msr_mask = xxx, - }, + /* PowerPC 7457 (G4) */ + { + .name = "7457", + .pvr = CPU_PPC_7457, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 7", + .pvr = CPU_PPC_7457, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif #if defined (TODO) - /* POWER2 */ - { - .name = "POWER2", - .pvr = CPU_POWER2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER, - .flags = PPC_FLAGS_POWER, - .msr_mask = xxx, - }, + /* PowerPC 7457A (G4) */ + { + .name = "7457A", + .pvr = CPU_PPC_7457A, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 7 PM", + .pvr = CPU_PPC_7457A, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif - /* Generic PowerPCs */ + /* 64 bits PowerPC */ #if defined (TODO) - { - .name = "ppc64", - .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_PPC64, - .flags = PPC_FLAGS_PPC64, - .msr_mask = 0xA00000000204FF36, - }, + /* PowerPC 620 */ + { + .name = "620", + .pvr = CPU_PPC_620, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_620, + .flags = PPC_FLAGS_620, + .msr_mask = 0x800000000005FF73, + }, #endif - { - .name = "ppc32", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_PPC32, - .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77, - }, - /* Fallback */ - { - .name = "ppc", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_PPC32, - .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77, - }, -}; +#if defined (TODO) + /* PowerPC 630 (POWER3) */ + { + .name = "630", + .pvr = CPU_PPC_630, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_630, + .flags = PPC_FLAGS_630, + .msr_mask = xxx, + } + { + .name = "POWER3", + .pvr = CPU_PPC_630, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_630, + .flags = PPC_FLAGS_630, + .msr_mask = xxx, + } +#endif +#if defined (TODO) + /* PowerPC 631 (Power 3+)*/ + { + .name = "631", + .pvr = CPU_PPC_631, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_631, + .flags = PPC_FLAGS_631, + .msr_mask = xxx, + }, + { + .name = "POWER3+", + .pvr = CPU_PPC_631, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_631, + .flags = PPC_FLAGS_631, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER4 */ + { + .name = "POWER4", + .pvr = CPU_PPC_POWER4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER4, + .flags = PPC_FLAGS_POWER4, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER4p */ + { + .name = "POWER4+", + .pvr = CPU_PPC_POWER4P, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER4, + .flags = PPC_FLAGS_POWER4, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER5 */ + { + .name = "POWER5", + .pvr = CPU_PPC_POWER5, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER5, + .flags = PPC_FLAGS_POWER5, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER5+ */ + { + .name = "POWER5+", + .pvr = CPU_PPC_POWER5P, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER5, + .flags = PPC_FLAGS_POWER5, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* PowerPC 970 */ + { + .name = "970", + .pvr = CPU_PPC_970, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_970, + .flags = PPC_FLAGS_970, + .msr_mask = 0x900000000204FF36, + }, +#endif +#if defined (TODO) + /* PowerPC 970FX (G5) */ + { + .name = "970fx", + .pvr = CPU_PPC_970FX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_970FX, + .flags = PPC_FLAGS_970FX, + .msr_mask = 0x800000000204FF36, + }, +#endif +#if defined (TODO) + /* RS64 (Apache/A35) */ + /* This one seems to support the whole POWER2 instruction set + * and the PowerPC 64 one. + */ + { + .name = "RS64", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "Apache", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "A35", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-II (NorthStar/A50) */ + { + .name = "RS64-II", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "NortStar", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "A50", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-III (Pulsar) */ + { + .name = "RS64-III", + .pvr = CPU_PPC_RS64III, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "Pulsar", + .pvr = CPU_PPC_RS64III, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-IV (IceStar/IStar/SStar) */ + { + .name = "RS64-IV", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "IceStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "IStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "SStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif + /* POWER */ +#if defined (TODO) + /* Original POWER */ + { + .name = "POWER", + .pvr = CPU_POWER, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER, + .flags = PPC_FLAGS_POWER, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER2 */ + { + .name = "POWER2", + .pvr = CPU_POWER2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER, + .flags = PPC_FLAGS_POWER, + .msr_mask = xxx, + }, +#endif + /* Generic PowerPCs */ +#if defined (TODO) + { + .name = "ppc64", + .pvr = CPU_PPC_970, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_PPC64, + .flags = PPC_FLAGS_PPC64, + .msr_mask = 0xA00000000204FF36, + }, +#endif + { + .name = "ppc32", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_PPC32, + .flags = PPC_FLAGS_PPC32, + .msr_mask = 0x000000000005FF77, + }, + /* Fallback */ + { + .name = "ppc", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_PPC32, + .flags = PPC_FLAGS_PPC32, + .msr_mask = 0x000000000005FF77, + }, + }; int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) { @@ -2058,7 +3730,7 @@ void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) int i; for (i = 0; ; i++) { - (*cpu_fprintf)(f, "PowerPC '%s' PVR %08x mask %08x\n", + (*cpu_fprintf)(f, "PowerPC %16s PVR %08x mask %08x\n", ppc_defs[i].name, ppc_defs[i].pvr, ppc_defs[i].pvr_mask); if (strcmp(ppc_defs[i].name, "ppc") == 0) -- cgit v1.2.3 From 3371d27293dc40159069d6593da22ba77ac8513c Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 8 Mar 2007 03:04:12 +0000 Subject: Implement --cpu for ARM. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2474 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/integratorcp.c | 38 +++++++------------------------------- hw/realview.c | 5 +++-- hw/versatilepb.c | 11 +++++++---- linux-user/main.c | 2 +- target-arm/cpu.h | 2 +- target-arm/helper.c | 29 ++++++++++++++++++++++++++++- vl.c | 3 +-- vl.h | 3 +-- 8 files changed, 49 insertions(+), 44 deletions(-) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index fd1675b40..5e4c636f0 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -471,7 +471,7 @@ static void icp_control_init(uint32_t base) static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, uint32_t cpuid) + const char *initrd_filename, const char *cpu_model) { CPUState *env; uint32_t bios_offset; @@ -479,7 +479,9 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, void *cpu_pic; env = cpu_init(); - cpu_arm_set_model(env, cpuid); + if (!cpu_model) + cpu_model = "arm926"; + cpu_arm_set_model(env, cpu_model); bios_offset = ram_size + vga_ram_size; /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ /* ??? RAM shoud repeat to fill physical memory space. */ @@ -513,34 +515,8 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, initrd_filename, 0x113); } -static void integratorcp926_init(int ram_size, int vga_ram_size, - int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, - snapshot, kernel_filename, kernel_cmdline, - initrd_filename, ARM_CPUID_ARM926); -} - -static void integratorcp1026_init(int ram_size, int vga_ram_size, - int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, - snapshot, kernel_filename, kernel_cmdline, - initrd_filename, ARM_CPUID_ARM1026); -} - -QEMUMachine integratorcp926_machine = { - "integratorcp926", +QEMUMachine integratorcp_machine = { + "integratorcp", "ARM Integrator/CP (ARM926EJ-S)", - integratorcp926_init, -}; - -QEMUMachine integratorcp1026_machine = { - "integratorcp1026", - "ARM Integrator/CP (ARM1026EJ-S)", - integratorcp1026_init, + integratorcp_init, }; diff --git a/hw/realview.c b/hw/realview.c index 325b3d1ab..619739c11 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -26,8 +26,9 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, int done_smc = 0; env = cpu_init(); - cpu_arm_set_model(env, ARM_CPUID_ARM926); - //cpu_arm_set_model(env, ARM_CPUID_ARM11MPCORE); + if (!cpu_model) + cpu_model = "arm926"; + cpu_arm_set_model(env, cpu_model); /* ??? RAM shoud repeat to fill physical memory space. */ /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 1bcc160b3..050878d50 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -154,7 +154,8 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) static void versatile_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, int board_id) + const char *initrd_filename, const char *cpu_model, + int board_id) { CPUState *env; void *pic; @@ -166,7 +167,9 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, int done_smc = 0; env = cpu_init(); - cpu_arm_set_model(env, ARM_CPUID_ARM926); + if (!cpu_model) + cpu_model = "arm926"; + cpu_arm_set_model(env, cpu_model); /* ??? RAM shoud repeat to fill physical memory space. */ /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -262,7 +265,7 @@ static void vpb_init(int ram_size, int vga_ram_size, int boot_device, versatile_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, - initrd_filename, 0x183); + initrd_filename, cpu_model, 0x183); } static void vab_init(int ram_size, int vga_ram_size, int boot_device, @@ -273,7 +276,7 @@ static void vab_init(int ram_size, int vga_ram_size, int boot_device, versatile_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, - initrd_filename, 0x25e); + initrd_filename, cpu_model, 0x25e); } QEMUMachine versatilepb_machine = { diff --git a/linux-user/main.c b/linux-user/main.c index 702c3b955..f96f96f6a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1756,7 +1756,7 @@ int main(int argc, char **argv) #elif defined(TARGET_ARM) { int i; - cpu_arm_set_model(env, ARM_CPUID_ARM1026); + cpu_arm_set_model(env, "arm926"); cpsr_write(env, regs->uregs[16], 0xffffffff); for(i = 0; i < 16; i++) { env->regs[i] = regs->uregs[i]; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 3208c138b..b3b37ebbe 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -209,7 +209,7 @@ static inline int arm_feature(CPUARMState *env, int feature) return (env->features & (1u << feature)) != 0; } -void cpu_arm_set_model(CPUARMState *env, uint32_t id); +void cpu_arm_set_model(CPUARMState *env, const char *name); #define ARM_CPUID_ARM1026 0x4106a262 #define ARM_CPUID_ARM926 0x41069265 diff --git a/target-arm/helper.c b/target-arm/helper.c index 5b4cd1393..093acc9af 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -36,8 +36,35 @@ static inline void set_feature(CPUARMState *env, int feature) env->features |= 1u << feature; } -void cpu_arm_set_model(CPUARMState *env, uint32_t id) +struct arm_cpu_t { + uint32_t id; + const char *name; +}; + +static const struct arm_cpu_t arm_cpu_names[] = { + { ARM_CPUID_ARM926, "arm926"}, + { ARM_CPUID_ARM1026, "arm1026"}, + { 0, NULL} +}; + +void cpu_arm_set_model(CPUARMState *env, const char *name) { + int i; + uint32_t id; + + id = 0; + i = 0; + for (i = 0; arm_cpu_names[i].name; i++) { + if (strcmp(name, arm_cpu_names[i].name) == 0) { + id = arm_cpu_names[i].id; + break; + } + } + if (!id) { + cpu_abort(env, "Unknown CPU '%s'", name); + return; + } + env->cp15.c0_cpuid = id; switch (id) { case ARM_CPUID_ARM926: diff --git a/vl.c b/vl.c index 99d4766b9..09d7baf88 100644 --- a/vl.c +++ b/vl.c @@ -6710,8 +6710,7 @@ void register_machines(void) qemu_register_machine(&sun4m_machine); #endif #elif defined(TARGET_ARM) - qemu_register_machine(&integratorcp926_machine); - qemu_register_machine(&integratorcp1026_machine); + qemu_register_machine(&integratorcp_machine); qemu_register_machine(&versatilepb_machine); qemu_register_machine(&versatileab_machine); qemu_register_machine(&realview_machine); diff --git a/vl.h b/vl.h index 26b274175..c7c7d73a0 100644 --- a/vl.h +++ b/vl.h @@ -1304,8 +1304,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *lsi_scsi_init(PCIBus *bus, int devfn); /* integratorcp.c */ -extern QEMUMachine integratorcp926_machine; -extern QEMUMachine integratorcp1026_machine; +extern QEMUMachine integratorcp_machine; /* versatilepb.c */ extern QEMUMachine versatilepb_machine; -- cgit v1.2.3 From 5adb4839e3c35382832bedc7155b3317b7b7d560 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 8 Mar 2007 03:15:18 +0000 Subject: Fix typo in help output. List ARM cpus. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2475 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/cpu.h | 1 + target-arm/helper.c | 10 ++++++++++ vl.c | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index b3b37ebbe..891616ecb 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -209,6 +209,7 @@ static inline int arm_feature(CPUARMState *env, int feature) return (env->features & (1u << feature)) != 0; } +void arm_cpu_list(void); void cpu_arm_set_model(CPUARMState *env, const char *name); #define ARM_CPUID_ARM1026 0x4106a262 diff --git a/target-arm/helper.c b/target-arm/helper.c index 093acc9af..36f5fe073 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -47,6 +47,16 @@ static const struct arm_cpu_t arm_cpu_names[] = { { 0, NULL} }; +void arm_cpu_list(void) +{ + int i; + + printf ("Available CPUs:\n"); + for (i = 0; arm_cpu_names[i].name; i++) { + printf(" %s\n", arm_cpu_names[i].name); + } +} + void cpu_arm_set_model(CPUARMState *env, const char *name) { int i; diff --git a/vl.c b/vl.c index 09d7baf88..e871c8cea 100644 --- a/vl.c +++ b/vl.c @@ -6355,7 +6355,7 @@ void help(void) "\n" "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" - "-cpu cpu select CPU (-C ? for list)\n" + "-cpu cpu select CPU (-cpu ? for list)\n" "-fda/-fdb file use 'file' as floppy disk 0/1 image\n" "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" @@ -7004,6 +7004,8 @@ int main(int argc, char **argv) if (optarg[0] == '?') { #if defined(TARGET_PPC) ppc_cpu_list(stdout, &fprintf); +#elif defined(TARGET_ARM) + arm_cpu_list(); #endif exit(1); } else { -- cgit v1.2.3 From f3d6b95e835ba12e9cfdca76124897122c47cd1b Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Mar 2007 13:03:18 +0000 Subject: ARM reabbot support (orginal patch by Aurelien Jarno). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2476 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_boot.c | 19 +++++++++++++++++++ hw/arm_sysctl.c | 2 +- target-arm/cpu.h | 6 ++++++ target-arm/helper.c | 53 +++++++++++++++++++++++++++++++---------------------- 4 files changed, 57 insertions(+), 23 deletions(-) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index c313a9f9a..dfc00db28 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -24,6 +24,17 @@ static uint32_t bootloader[] = { 0 /* Kernel entry point. Set by integratorcp_init. */ }; +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + + cpu_reset(env); + if (env->kernel_filename) + arm_load_kernel(env, env->ram_size, env->kernel_filename, + env->kernel_cmdline, env->initrd_filename, + env->board_id); +} + static void set_kernel_args(uint32_t ram_size, int initrd_size, const char *kernel_cmdline) { @@ -81,6 +92,14 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, exit(1); } + if (!env->kernel_filename) { + env->ram_size = ram_size; + env->kernel_filename = kernel_filename; + env->kernel_cmdline = kernel_cmdline; + env->initrd_filename = initrd_filename; + env->board_id = board_id; + qemu_register_reset(main_cpu_reset, env); + } /* Assume that raw images are linux kernels, and ELF images are not. */ kernel_size = load_elf(kernel_filename, 0, &elf_entry); entry = elf_entry; diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index e9de998a2..90ea76e71 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -149,7 +149,7 @@ static void arm_sysctl_write(void *opaque, target_phys_addr_t offset, if (s->lockval == LOCK_VALUE) { s->resetlevel = val; if (val & 0x100) - cpu_abort(cpu_single_env, "Board reset\n"); + qemu_system_reset_request (); } break; case 0x44: /* PCICTL */ diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 891616ecb..68bf3fd0f 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -122,6 +122,12 @@ typedef struct CPUARMState { CPU_COMMON + /* These fields after the common ones so thes are preserved on reset. */ + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; + int board_id; } CPUARMState; CPUARMState *cpu_arm_init(void); diff --git a/target-arm/helper.c b/target-arm/helper.c index 36f5fe073..242dd28f7 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5,8 +5,37 @@ #include "cpu.h" #include "exec-all.h" +static inline void set_feature(CPUARMState *env, int feature) +{ + env->features |= 1u << feature; +} + +static void cpu_reset_model_id(CPUARMState *env, uint32_t id) +{ + env->cp15.c0_cpuid = id; + switch (id) { + case ARM_CPUID_ARM926: + set_feature(env, ARM_FEATURE_VFP); + env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; + break; + case ARM_CPUID_ARM1026: + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; + break; + default: + cpu_abort(env, "Bad CPU ID: %x\n", id); + break; + } +} + void cpu_reset(CPUARMState *env) { + uint32_t id; + id = env->cp15.c0_cpuid; + memset(env, 0, offsetof(CPUARMState, breakpoints)); + if (id) + cpu_reset_model_id(env, id); #if defined (CONFIG_USER_ONLY) env->uncached_cpsr = ARM_CPU_MODE_USR; env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30; @@ -16,6 +45,7 @@ void cpu_reset(CPUARMState *env) env->vfp.xregs[ARM_VFP_FPEXC] = 0; #endif env->regs[15] = 0; + tlb_flush(env, 1); } CPUARMState *cpu_arm_init(void) @@ -27,15 +57,9 @@ CPUARMState *cpu_arm_init(void) return NULL; cpu_exec_init(env); cpu_reset(env); - tlb_flush(env, 1); return env; } -static inline void set_feature(CPUARMState *env, int feature) -{ - env->features |= 1u << feature; -} - struct arm_cpu_t { uint32_t id; const char *name; @@ -74,22 +98,7 @@ void cpu_arm_set_model(CPUARMState *env, const char *name) cpu_abort(env, "Unknown CPU '%s'", name); return; } - - env->cp15.c0_cpuid = id; - switch (id) { - case ARM_CPUID_ARM926: - set_feature(env, ARM_FEATURE_VFP); - env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; - break; - case ARM_CPUID_ARM1026: - set_feature(env, ARM_FEATURE_VFP); - set_feature(env, ARM_FEATURE_AUXCR); - env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; - break; - default: - cpu_abort(env, "Bad CPU ID: %x\n", id); - break; - } + cpu_reset_model_id(env, id); } void cpu_arm_close(CPUARMState *env) -- cgit v1.2.3 From bd967e05da8cbb2c863b0c75632530966cafcc11 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Mar 2007 18:54:57 +0000 Subject: SMP half-idle fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2477 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index e871c8cea..742f9000f 100644 --- a/vl.c +++ b/vl.c @@ -6298,13 +6298,16 @@ int main_loop(void) #ifdef CONFIG_PROFILER qemu_time += profile_getclock() - ti; #endif + if (ret == EXCP_HLT) { + /* Give the next CPU a chance to run. */ + cur_cpu = env; + continue; + } if (ret != EXCP_HALTED) break; /* all CPUs are halted ? */ - if (env == cur_cpu) { - ret = EXCP_HLT; + if (env == cur_cpu) break; - } } cur_cpu = env; @@ -6325,9 +6328,9 @@ int main_loop(void) if (ret == EXCP_DEBUG) { vm_stop(EXCP_DEBUG); } - /* if hlt instruction, we wait until the next IRQ */ + /* If all cpus are halted then wait until the next IRQ */ /* XXX: use timeout computed from timers */ - if (ret == EXCP_HLT) + if (ret == EXCP_HALTED) timeout = 10; else timeout = 0; -- cgit v1.2.3 From b35d7448b1d27a77bc6f59acc697710d5bd3823c Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 15 Mar 2007 21:56:07 +0000 Subject: Align stack when loading bFLT binaries. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2478 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/flatload.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 7e3296e5a..c9f1acd55 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -756,6 +756,13 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, p = copy_strings(p, bprm->argc, bprm->argv); /* Align stack. */ sp = p & ~(target_ulong)(sizeof(target_ulong) - 1); + /* Enforce final stack alignment of 16 bytes. This is sufficient + for all current targets, and excess alignment is harmless. */ + stack_len = bprm->envc + bprm->argc + 2; + stack_len += 3; /* argc, arvg, argp */ + stack_len *= sizeof(target_ulong); + if ((sp + stack_len) & 15) + sp -= 16 - ((sp + stack_len) & 15); sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1); /* Fake some return addresses to ensure the call chain will -- cgit v1.2.3 From 6658ffb81ee56a510d7d77025872a508a9adce3a Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 16 Mar 2007 23:58:11 +0000 Subject: Watchpoint support (previous commit got eaten by Savannah server crash). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2479 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 3 ++ cpu-defs.h | 8 +++ cpu-exec.c | 5 ++ exec.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++ gdbstub.c | 18 +++++++ target-arm/translate.c | 10 ++++ 6 files changed, 186 insertions(+) diff --git a/cpu-all.h b/cpu-all.h index 86acc36d6..9b617fcc7 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -775,10 +775,13 @@ extern int code_copy_enabled; #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 */ +#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); +int cpu_watchpoint_insert(CPUState *env, target_ulong addr); +int cpu_watchpoint_remove(CPUState *env, target_ulong addr); 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); diff --git a/cpu-defs.h b/cpu-defs.h index 0b49c8991..04fde7e89 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -76,6 +76,7 @@ typedef unsigned long ram_addr_t; #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 MAX_WATCHPOINTS 32 #define TB_JMP_CACHE_BITS 12 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) @@ -125,6 +126,13 @@ typedef struct CPUTLBEntry { int nb_breakpoints; \ int singlestep_enabled; \ \ + struct { \ + target_ulong vaddr; \ + int is_ram; \ + } watchpoint[MAX_WATCHPOINTS]; \ + int nb_watchpoints; \ + int watchpoint_hit; \ + \ void *next_cpu; /* next CPU sharing TB cache */ \ int cpu_index; /* CPU index (informative) */ \ /* user data */ \ diff --git a/cpu-exec.c b/cpu-exec.c index 058688fc7..48c2a93a7 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -409,6 +409,11 @@ int cpu_exec(CPUState *env1) #endif interrupt_request = env->interrupt_request; if (__builtin_expect(interrupt_request, 0)) { + if (interrupt_request & CPU_INTERRUPT_DEBUG) { + env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); + } #if defined(TARGET_I386) if ((interrupt_request & CPU_INTERRUPT_SMI) && !(env->hflags & HF_SMM_MASK)) { diff --git a/exec.c b/exec.c index 37d58a43e..6deaf4927 100644 --- a/exec.c +++ b/exec.c @@ -128,6 +128,9 @@ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; void *io_mem_opaque[IO_MEM_NB_ENTRIES]; static int io_mem_nb; +#if defined(CONFIG_SOFTMMU) +static int io_mem_watch; +#endif /* log support */ char *logfilename = "/tmp/qemu.log"; @@ -274,6 +277,7 @@ void cpu_exec_init(CPUState *env) cpu_index++; } env->cpu_index = cpu_index; + env->nb_watchpoints = 0; *penv = env; } @@ -1029,6 +1033,44 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) } #endif +/* Add a watchpoint. */ +int cpu_watchpoint_insert(CPUState *env, target_ulong addr) +{ + int i; + + for (i = 0; i < env->nb_watchpoints; i++) { + if (addr == env->watchpoint[i].vaddr) + return 0; + } + if (env->nb_watchpoints >= MAX_WATCHPOINTS) + return -1; + + i = env->nb_watchpoints++; + env->watchpoint[i].vaddr = addr; + tlb_flush_page(env, addr); + /* FIXME: This flush is needed because of the hack to make memory ops + terminate the TB. It can be removed once the proper IO trap and + re-execute bits are in. */ + tb_flush(env); + return i; +} + +/* Remove a watchpoint. */ +int cpu_watchpoint_remove(CPUState *env, target_ulong addr) +{ + int i; + + for (i = 0; i < env->nb_watchpoints; i++) { + if (addr == env->watchpoint[i].vaddr) { + env->nb_watchpoints--; + env->watchpoint[i] = env->watchpoint[env->nb_watchpoints]; + tlb_flush_page(env, addr); + return 0; + } + } + return -1; +} + /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) @@ -1484,6 +1526,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, target_phys_addr_t addend; int ret; CPUTLBEntry *te; + int i; p = phys_page_find(paddr >> TARGET_PAGE_BITS); if (!p) { @@ -1510,6 +1553,22 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, address = vaddr; addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); } + + /* Make accesses to pages with watchpoints go via the + watchpoint trap routines. */ + for (i = 0; i < env->nb_watchpoints; i++) { + if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) { + if (address & ~TARGET_PAGE_MASK) { + env->watchpoint[i].is_ram = 0; + address = vaddr | io_mem_watch; + } else { + env->watchpoint[i].is_ram = 1; + /* TODO: Figure out how to make read watchpoints coexist + with code. */ + pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD; + } + } + } index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); addend -= vaddr; @@ -1960,6 +2019,85 @@ static CPUWriteMemoryFunc *notdirty_mem_write[3] = { notdirty_mem_writel, }; +#if defined(CONFIG_SOFTMMU) +/* Watchpoint access routines. Watchpoints are inserted using TLB tricks, + so these check for a hit then pass through to the normal out-of-line + phys routines. */ +static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr) +{ + return ldub_phys(addr); +} + +static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr) +{ + return lduw_phys(addr); +} + +static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr) +{ + return ldl_phys(addr); +} + +/* Generate a debug exception if a watchpoint has been hit. + Returns the real physical address of the access. addr will be a host + address in the is_ram case. */ +static target_ulong check_watchpoint(target_phys_addr_t addr) +{ + CPUState *env = cpu_single_env; + target_ulong watch; + target_ulong retaddr; + int i; + + retaddr = addr; + for (i = 0; i < env->nb_watchpoints; i++) { + watch = env->watchpoint[i].vaddr; + if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) { + if (env->watchpoint[i].is_ram) + retaddr = addr - (unsigned long)phys_ram_base; + if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) { + cpu_single_env->watchpoint_hit = i + 1; + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG); + break; + } + } + } + return retaddr; +} + +static void watch_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + addr = check_watchpoint(addr); + stb_phys(addr, val); +} + +static void watch_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + addr = check_watchpoint(addr); + stw_phys(addr, val); +} + +static void watch_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + addr = check_watchpoint(addr); + stl_phys(addr, val); +} + +static CPUReadMemoryFunc *watch_mem_read[3] = { + watch_mem_readb, + watch_mem_readw, + watch_mem_readl, +}; + +static CPUWriteMemoryFunc *watch_mem_write[3] = { + watch_mem_writeb, + watch_mem_writew, + watch_mem_writel, +}; +#endif + static void io_mem_init(void) { cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL); @@ -1967,6 +2105,10 @@ static void io_mem_init(void) cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL); io_mem_nb = 5; +#if defined(CONFIG_SOFTMMU) + io_mem_watch = cpu_register_io_memory(-1, watch_mem_read, + watch_mem_write, NULL); +#endif /* alloc dirty bits array */ phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); diff --git a/gdbstub.c b/gdbstub.c index 57d97e340..4d62a8891 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -856,6 +856,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; put_packet(s, "OK"); +#ifndef CONFIG_USER_ONLY + } else if (type == 2) { + if (cpu_watchpoint_insert(env, addr) < 0) + goto breakpoint_error; + put_packet(s, "OK"); +#endif } else { breakpoint_error: put_packet(s, "E22"); @@ -872,6 +878,11 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) if (type == 0 || type == 1) { cpu_breakpoint_remove(env, addr); put_packet(s, "OK"); +#ifndef CONFIG_USER_ONLY + } else if (type == 2) { + cpu_watchpoint_remove(env, addr); + put_packet(s, "OK"); +#endif } else { goto breakpoint_error; } @@ -914,6 +925,13 @@ static void gdb_vm_stopped(void *opaque, int reason) cpu_single_step(s->env, 0); if (reason == EXCP_DEBUG) { + if (s->env->watchpoint_hit) { + snprintf(buf, sizeof(buf), "T%02xwatch:%x;", SIGTRAP, + s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr); + put_packet(s, buf); + s->env->watchpoint_hit = 0; + return; + } tb_flush(s->env); ret = SIGTRAP; } else if (reason == EXCP_INTERRUPT) { diff --git a/target-arm/translate.c b/target-arm/translate.c index cf46e346e..055ccfaa0 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -45,6 +45,7 @@ typedef struct DisasContext { struct TranslationBlock *tb; int singlestep_enabled; int thumb; + int is_mem; #if !defined(CONFIG_USER_ONLY) int user; #endif @@ -290,6 +291,7 @@ static inline void gen_bx(DisasContext *s) #define gen_ldst(name, s) gen_op_##name##_raw() #else #define gen_ldst(name, s) do { \ + s->is_mem = 1; \ if (IS_USER(s)) \ gen_op_##name##_user(); \ else \ @@ -1612,6 +1614,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_add_data_offset(s, insn); if (insn & (1 << 20)) { /* load */ + s->is_mem = 1; #if defined(CONFIG_USER_ONLY) if (insn & (1 << 22)) gen_op_ldub_raw(); @@ -2409,6 +2412,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->singlestep_enabled = env->singlestep_enabled; dc->condjmp = 0; dc->thumb = env->thumb; + dc->is_mem = 0; #if !defined(CONFIG_USER_ONLY) dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; #endif @@ -2447,6 +2451,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, gen_set_label(dc->condlabel); dc->condjmp = 0; } + /* Terminate the TB on memory ops if watchpoints are present. */ + /* FIXME: This should be replacd by the deterministic execution + * IRQ raising bits. */ + if (dc->is_mem && env->nb_watchpoints) + break; + /* Translation stops when a conditional branch is enoutered. * Otherwise the subsequent code could get translated several times. * Also stop translation when a page boundary is reached. This -- cgit v1.2.3 From 214201bdd4e41ec9748a434a68fa8f6fcc57bd49 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Mar 2007 01:27:24 +0000 Subject: Usermode recv syscall fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2480 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index acd098d87..7e4b0594e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2914,12 +2914,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_recv case TARGET_NR_recv: - ret = do_recvfrom(arg1, arg1, arg3, arg4, 0, 0); + ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0); break; #endif #ifdef TARGET_NR_recvfrom case TARGET_NR_recvfrom: - ret = do_recvfrom(arg1, arg1, arg3, arg4, arg5, arg6); + ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6); break; #endif #ifdef TARGET_NR_recvmsg -- cgit v1.2.3 From 5fd46862e5232d1840a9353c99b163f11b49a035 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Mar 2007 01:43:01 +0000 Subject: ARM register index+writeback fix (Lauro Ramos Venancio). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2481 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 055ccfaa0..4cb9142f4 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1537,6 +1537,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } } else { int address_offset; + int load; /* Misc load/store */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; @@ -1558,7 +1559,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_ldst(ldsw, s); break; } - gen_movl_reg_T0(s, rd); + load = 1; } else if (sh & 2) { /* doubleword */ if (sh & 1) { @@ -1568,20 +1569,27 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_addl_T1_im(4); gen_movl_T0_reg(s, rd + 1); gen_ldst(stl, s); + load = 0; } else { /* load */ gen_ldst(ldl, s); gen_movl_reg_T0(s, rd); gen_op_addl_T1_im(4); gen_ldst(ldl, s); - gen_movl_reg_T0(s, rd + 1); + rd++; + load = 1; } address_offset = -4; } else { /* store */ gen_movl_T0_reg(s, rd); gen_ldst(stw, s); + load = 0; } + /* Perform base writeback before the loaded value to + ensure correct behavior with overlapping index registers. + ldrd with base writeback is is undefined if the + destination and index registers overlap. */ if (!(insn & (1 << 24))) { gen_add_datah_offset(s, insn, address_offset); gen_movl_reg_T1(s, rn); @@ -1590,6 +1598,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_addl_T1_im(address_offset); gen_movl_reg_T1(s, rn); } + if (load) { + /* Complete the load. */ + gen_movl_reg_T0(s, rd); + } } break; case 0x4: @@ -1633,10 +1645,6 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_ldl_kernel(); } #endif - if (rd == 15) - gen_bx(s); - else - gen_movl_reg_T0(s, rd); } else { /* store */ gen_movl_T0_reg(s, rd); @@ -1665,6 +1673,13 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } else if (insn & (1 << 21)) gen_movl_reg_T1(s, rn); { } + if (insn & (1 << 20)) { + /* Complete the load. */ + if (rd == 15) + gen_bx(s); + else + gen_movl_reg_T0(s, rd); + } break; case 0x08: case 0x09: -- cgit v1.2.3 From d9bce9d99f4656ae0b0127f7472db9067b8f84ab Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Mar 2007 14:02:15 +0000 Subject: Make it safe to use 64 bits GPR and/or 64 bits host registers. For "symetry", add 64 bits versions of all modified functions. As a side effect, add a lot of code provision for PowerPC 64 support. Move overflow and carry checks in common routines for simple cases. Add isel and popcntb instructions from PowerPC 2.03 specification. Remove remaining micro-operations helpers prototypes from op.c. Fix XER_BC field to be 7 bits long. Add power management support for PowerPC 603 & 604. Fix compilation warnings. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2482 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 33 +- target-ppc/exec.h | 22 +- target-ppc/helper.c | 109 ++-- target-ppc/op.c | 870 +++++++++++++++++++++++----- target-ppc/op_helper.c | 505 +++++++++++++---- target-ppc/op_helper.h | 54 +- target-ppc/op_helper_mem.h | 156 ++++- target-ppc/op_mem.h | 538 +++++++++++++++--- target-ppc/translate.c | 1345 +++++++++++++++++++++++++++++++++++++------- 9 files changed, 3019 insertions(+), 613 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8abb32492..5b1af4152 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -365,6 +365,8 @@ enum { PPC_E500_VECTOR = 0x20000000, /* PowerPC 4xx dedicated instructions */ PPC_4xx_COMMON = 0x40000000, + /* PowerPC 2.03 specification extensions */ + PPC_203 = 0x80000000, }; /* CPU run-time flags (MMU and exception model) */ @@ -385,6 +387,8 @@ enum { PPC_FLAGS_MMU_403 = 0x00000005, /* Freescale e500 MMU model */ PPC_FLAGS_MMU_e500 = 0x00000006, + /* BookE MMU model */ + PPC_FLAGS_MMU_BOOKE = 0x00000007, /* Exception model */ PPC_FLAGS_EXCP_MASK = 0x000000F0, /* Standard PowerPC exception model */ @@ -407,6 +411,8 @@ enum { PPC_FLAGS_EXCP_74xx = 0x00000080, /* PowerPC 970 exception model */ PPC_FLAGS_EXCP_970 = 0x00000090, + /* BookE exception model */ + PPC_FLAGS_EXCP_BOOKE = 0x000000A0, }; #define PPC_MMU(env) (env->flags & PPC_FLAGS_MMU_MASK) @@ -437,11 +443,11 @@ enum { /* PowerPC 440 */ #define PPC_INSNS_440 (PPC_INSNS_EMB | PPC_CACHE_OPT | PPC_BOOKE | \ PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) -#define PPC_FLAGS_440 (PPC_FLAGS_TODO) +#define PPC_FLAGS_440 (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE) /* Generic BookE PowerPC */ #define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \ PPC_FLOAT | PPC_FLOAT_OPT | PPC_CACHE_OPT) -#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x) +#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE) /* e500 core */ #define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \ PPC_CACHE_OPT | PPC_E500_VECTOR) @@ -502,7 +508,6 @@ typedef struct ppc_dcr_t ppc_dcr_t; typedef struct ppc_avr_t ppc_avr_t; typedef struct ppc_tlb_t ppc_tlb_t; - /* SPR access micro-ops generations callbacks */ struct ppc_spr_t { void (*uea_read)(void *opaque, int spr_num); @@ -619,6 +624,8 @@ struct CPUPPCState { */ target_ulong t0, t1, t2; #endif + ppc_avr_t t0_avr, t1_avr, t2_avr; + /* general purpose registers */ ppc_gpr_t gpr[32]; /* LR */ @@ -674,6 +681,9 @@ struct CPUPPCState { /* Altivec registers */ ppc_avr_t avr[32]; uint32_t vscr; + /* SPE registers */ + ppc_gpr_t spe_acc; + uint32_t spe_fscr; /* Internal devices resources */ /* Time base and decrementer */ @@ -762,8 +772,10 @@ void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value); void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value); target_ulong do_load_sdr1 (CPUPPCState *env); void do_store_sdr1 (CPUPPCState *env, target_ulong value); -target_ulong do_load_asr (CPUPPCState *env); -void do_store_asr (CPUPPCState *env, target_ulong value); +#if defined(TARGET_PPC64) +target_ulong ppc_load_asr (CPUPPCState *env); +void ppc_store_asr (CPUPPCState *env, target_ulong value); +#endif target_ulong do_load_sr (CPUPPCState *env, int srnum); void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif @@ -771,6 +783,7 @@ uint32_t ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, uint32_t value); target_ulong do_load_msr (CPUPPCState *env); void do_store_msr (CPUPPCState *env, target_ulong value); +void ppc_store_msr32 (CPUPPCState *env, uint32_t value); void do_compute_hflags (CPUPPCState *env); @@ -787,6 +800,16 @@ void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); uint32_t cpu_ppc_load_decr (CPUPPCState *env); void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); +uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env); +uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env); +#if !defined(CONFIG_USER_ONLY) +void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value); +void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value); +target_ulong load_40x_pit (CPUPPCState *env); +void store_40x_pit (CPUPPCState *env, target_ulong val); +void store_booke_tcr (CPUPPCState *env, target_ulong val); +void store_booke_tsr (CPUPPCState *env, target_ulong val); +#endif #endif #define TARGET_PAGE_BITS 12 diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 25e060fb6..f1dde82d4 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -34,19 +34,25 @@ register struct CPUPPCState *env asm(AREG0); #define T1 (env->t1) #define T2 (env->t2) #else -/* This may be more efficient if HOST_LONG_BITS > TARGET_LONG_BITS - * To be set to one when we'll be sure it does not cause bugs.... - */ -#if 0 register unsigned long T0 asm(AREG1); register unsigned long T1 asm(AREG2); register unsigned long T2 asm(AREG3); -#else -register target_ulong T0 asm(AREG1); -register target_ulong T1 asm(AREG2); -register target_ulong T2 asm(AREG3); #endif +/* We may, sometime, need 64 bits registers on 32 bits target */ +#if defined(TARGET_PPC64) || (HOST_LONG_BITS == 64) +#define T0_64 T0 +#define T1_64 T0 +#define T2_64 T0 +#else +/* no registers can be used */ +#define T0_64 (env->t0) +#define T1_64 (env->t1) +#define T2_64 (env->t2) #endif +/* Provision for Altivec */ +#define T0_avr (env->t0_avr) +#define T1_avr (env->t1_avr) +#define T2_avr (env->t2_avr) /* XXX: to clean: remove this mess */ #define PARAM(n) ((uint32_t)PARAM##n) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f4f692d5e..405c928e7 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -37,12 +37,12 @@ /*****************************************************************************/ /* PowerPC MMU emulation */ -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, int is_user, int is_softmmu) { int exception, error_code; - + if (rw == 2) { exception = EXCP_ISI; error_code = 0; @@ -277,7 +277,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, ppc_tlb_t *tlb; int nr, best, way; int ret; - + best = -1; ret = -1; /* No TLB found */ for (way = 0; way < env->nb_ways; way++) { @@ -672,7 +672,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, if (loglevel > 0) { fprintf(logfile, "%s\n", __func__); } -#endif +#endif if ((access_type == ACCESS_CODE && msr_ir == 0) || (access_type != ACCESS_CODE && msr_dr == 0)) { /* No address translation */ @@ -693,7 +693,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, __func__, eaddr, ctx->raddr); } #endif - + return ret; } @@ -715,7 +715,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, int exception = 0, error_code = 0; int access_type; int ret = 0; - + if (rw == 2) { /* code access */ rw = 0; @@ -975,6 +975,21 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) /*****************************************************************************/ /* Special registers manipulation */ +#if defined(TARGET_PPC64) +target_ulong ppc_load_asr (CPUPPCState *env) +{ + return env->asr; +} + +void ppc_store_asr (CPUPPCState *env, target_ulong value) +{ + if (env->asr != value) { + env->asr = value; + tlb_flush(env, 1); + } +} +#endif + target_ulong do_load_sdr1 (CPUPPCState *env) { return env->sdr1; @@ -1039,7 +1054,7 @@ void ppc_store_xer (CPUPPCState *env, uint32_t value) xer_ov = (value >> XER_OV) & 0x01; xer_ca = (value >> XER_CA) & 0x01; xer_cmp = (value >> XER_CMP) & 0xFF; - xer_bc = (value >> XER_BC) & 0x3F; + xer_bc = (value >> XER_BC) & 0x7F; } /* Swap temporary saved registers with GPRs */ @@ -1066,34 +1081,34 @@ target_ulong do_load_msr (CPUPPCState *env) { return #if defined (TARGET_PPC64) - (msr_sf << MSR_SF) | - (msr_isf << MSR_ISF) | - (msr_hv << MSR_HV) | + ((target_ulong)msr_sf << MSR_SF) | + ((target_ulong)msr_isf << MSR_ISF) | + ((target_ulong)msr_hv << MSR_HV) | #endif - (msr_ucle << MSR_UCLE) | - (msr_vr << MSR_VR) | /* VR / SPE */ - (msr_ap << MSR_AP) | - (msr_sa << MSR_SA) | - (msr_key << MSR_KEY) | - (msr_pow << MSR_POW) | /* POW / WE */ - (msr_tlb << MSR_TLB) | /* TLB / TGPE / CE */ - (msr_ile << MSR_ILE) | - (msr_ee << MSR_EE) | - (msr_pr << MSR_PR) | - (msr_fp << MSR_FP) | - (msr_me << MSR_ME) | - (msr_fe0 << MSR_FE0) | - (msr_se << MSR_SE) | /* SE / DWE / UBLE */ - (msr_be << MSR_BE) | /* BE / DE */ - (msr_fe1 << MSR_FE1) | - (msr_al << MSR_AL) | - (msr_ip << MSR_IP) | - (msr_ir << MSR_IR) | /* IR / IS */ - (msr_dr << MSR_DR) | /* DR / DS */ - (msr_pe << MSR_PE) | /* PE / EP */ - (msr_px << MSR_PX) | /* PX / PMM */ - (msr_ri << MSR_RI) | - (msr_le << MSR_LE); + ((target_ulong)msr_ucle << MSR_UCLE) | + ((target_ulong)msr_vr << MSR_VR) | /* VR / SPE */ + ((target_ulong)msr_ap << MSR_AP) | + ((target_ulong)msr_sa << MSR_SA) | + ((target_ulong)msr_key << MSR_KEY) | + ((target_ulong)msr_pow << MSR_POW) | /* POW / WE */ + ((target_ulong)msr_tlb << MSR_TLB) | /* TLB / TGPE / CE */ + ((target_ulong)msr_ile << MSR_ILE) | + ((target_ulong)msr_ee << MSR_EE) | + ((target_ulong)msr_pr << MSR_PR) | + ((target_ulong)msr_fp << MSR_FP) | + ((target_ulong)msr_me << MSR_ME) | + ((target_ulong)msr_fe0 << MSR_FE0) | + ((target_ulong)msr_se << MSR_SE) | /* SE / DWE / UBLE */ + ((target_ulong)msr_be << MSR_BE) | /* BE / DE */ + ((target_ulong)msr_fe1 << MSR_FE1) | + ((target_ulong)msr_al << MSR_AL) | + ((target_ulong)msr_ip << MSR_IP) | + ((target_ulong)msr_ir << MSR_IR) | /* IR / IS */ + ((target_ulong)msr_dr << MSR_DR) | /* DR / DS */ + ((target_ulong)msr_pe << MSR_PE) | /* PE / EP */ + ((target_ulong)msr_px << MSR_PX) | /* PX / PMM */ + ((target_ulong)msr_ri << MSR_RI) | + ((target_ulong)msr_le << MSR_LE); } void do_store_msr (CPUPPCState *env, target_ulong value) @@ -1156,6 +1171,17 @@ void do_store_msr (CPUPPCState *env, target_ulong value) enter_pm = 0; switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_603: + /* Don't handle SLEEP mode: we should disable all clocks... + * No dynamic power-management. + */ + if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00C00000) != 0) + enter_pm = 1; + break; + case PPC_FLAGS_EXCP_604: + if (msr_pow == 1) + enter_pm = 1; + break; case PPC_FLAGS_EXCP_7x0: if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0) enter_pm = 1; @@ -1171,15 +1197,22 @@ void do_store_msr (CPUPPCState *env, target_ulong value) } } +#if defined(TARGET_PPC64) +void ppc_store_msr_32 (CPUPPCState *env, target_ulong value) +{ + do_store_msr(env, (uint32_t)value); +} +#endif + void do_compute_hflags (CPUPPCState *env) { /* Compute current hflags */ env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) | (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) | - (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | + (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_se << MSR_SE) | (msr_be << MSR_BE); #if defined (TARGET_PPC64) - env->hflags |= (msr_sf << MSR_SF) | (msr_hv << MSR_HV); + env->hflags |= (msr_sf << (MSR_SF - 32)) | (msr_hv << (MSR_HV - 32)); #endif } @@ -1193,8 +1226,8 @@ void do_interrupt (CPUState *env) #else /* defined (CONFIG_USER_ONLY) */ static void dump_syscall(CPUState *env) { - fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x " - "r5=0x%08x r6=0x%08x nip=0x%08x\n", + fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX + " r5=0x" REGX " r6=0x" REGX " nip=0x" REGX "\n", env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6], env->nip); } diff --git a/target-ppc/op.c b/target-ppc/op.c index 1bad76811..be922c6ad 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -26,9 +26,6 @@ /* XXX: this is to be suppressed */ #define regs (env) -#define Ts0 (int32_t)T0 -#define Ts1 (int32_t)T1 -#define Ts2 (int32_t)T2 #define FT0 (env->ft0) #define FT1 (env->ft1) @@ -157,15 +154,31 @@ void OPPROTO op_reset_T0 (void) PPC_OP(set_T0) { - T0 = PARAM(1); + T0 = (uint32_t)PARAM1; RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_set_T0_64 (void) +{ + T0 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; + RETURN(); +} +#endif + PPC_OP(set_T1) { - T1 = PARAM(1); + T1 = (uint32_t)PARAM1; + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_set_T1_64 (void) +{ + T1 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; RETURN(); } +#endif #if 0 // unused PPC_OP(set_T2) @@ -181,6 +194,12 @@ void OPPROTO op_move_T1_T0 (void) RETURN(); } +void OPPROTO op_move_T2_T0 (void) +{ + T2 = T0; + RETURN(); +} + /* Generate exceptions */ PPC_OP(raise_exception_err) { @@ -189,16 +208,23 @@ PPC_OP(raise_exception_err) PPC_OP(update_nip) { - env->nip = PARAM(1); + env->nip = (uint32_t)PARAM1; RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_update_nip_64 (void) +{ + env->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; + RETURN(); +} +#endif + PPC_OP(debug) { do_raise_exception(EXCP_DEBUG); } - PPC_OP(exit_tb) { EXIT_TB(); @@ -293,6 +319,20 @@ PPC_OP(store_sdr1) RETURN(); } +#if defined (TARGET_PPC64) +void OPPROTO op_load_asr (void) +{ + T0 = env->asr; + RETURN(); +} + +void OPPROTO op_store_asr (void) +{ + ppc_store_asr(env, T0); + RETURN(); +} +#endif + PPC_OP(load_msr) { T0 = do_load_msr(env); @@ -304,6 +344,14 @@ PPC_OP(store_msr) do_store_msr(env, T0); RETURN(); } + +#if defined (TARGET_PPC64) +void OPPROTO op_store_msr_32 (void) +{ + ppc_store_msr_32(env, T0); + RETURN(); +} +#endif #endif /* SPR */ @@ -459,7 +507,7 @@ PPC_OP(getbit_T1) PPC_OP(setcrfbit) { - T1 = (T1 & PARAM(1)) | (T0 << PARAM(2)); + T1 = (T1 & PARAM(1)) | (T0 << PARAM(2)); RETURN(); } @@ -468,10 +516,18 @@ PPC_OP(setcrfbit) PPC_OP(setlr) { - regs->lr = PARAM1; + regs->lr = (uint32_t)PARAM1; RETURN(); } +#if defined (TARGET_PPC64) +void OPPROTO op_setlr_64 (void) +{ + regs->lr = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; + RETURN(); +} +#endif + PPC_OP(goto_tb0) { GOTO_TB(op_goto_tb0, PARAM1, 0); @@ -482,12 +538,20 @@ PPC_OP(goto_tb1) GOTO_TB(op_goto_tb1, PARAM1, 1); } -PPC_OP(b_T1) +void OPPROTO op_b_T1 (void) { - regs->nip = T1 & ~3; + regs->nip = (uint32_t)(T1 & ~3); RETURN(); } +#if defined (TARGET_PPC64) +void OPPROTO op_b_T1_64 (void) +{ + regs->nip = (uint64_t)(T1 & ~3); + RETURN(); +} +#endif + PPC_OP(jz_T0) { if (!T0) @@ -495,16 +559,28 @@ PPC_OP(jz_T0) RETURN(); } -PPC_OP(btest_T1) +void OPPROTO op_btest_T1 (void) { if (T0) { - regs->nip = T1 & ~3; + regs->nip = (uint32_t)(T1 & ~3); } else { - regs->nip = PARAM1; + regs->nip = (uint32_t)PARAM1; } RETURN(); } +#if defined (TARGET_PPC64) +void OPPROTO op_btest_T1_64 (void) +{ + if (T0) { + regs->nip = (uint64_t)(T1 & ~3); + } else { + regs->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; + } + RETURN(); +} +#endif + PPC_OP(movl_T1_ctr) { T1 = regs->ctr; @@ -518,42 +594,89 @@ PPC_OP(movl_T1_lr) } /* tests with result in T0 */ +void OPPROTO op_test_ctr (void) +{ + T0 = (uint32_t)regs->ctr; + RETURN(); +} -PPC_OP(test_ctr) +#if defined(TARGET_PPC64) +void OPPROTO op_test_ctr_64 (void) { - T0 = regs->ctr; + T0 = (uint64_t)regs->ctr; + RETURN(); +} +#endif + +void OPPROTO op_test_ctr_true (void) +{ + T0 = ((uint32_t)regs->ctr != 0 && (T0 & PARAM1) != 0); RETURN(); } -PPC_OP(test_ctr_true) +#if defined(TARGET_PPC64) +void OPPROTO op_test_ctr_true_64 (void) { - T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0); + T0 = ((uint64_t)regs->ctr != 0 && (T0 & PARAM1) != 0); RETURN(); } +#endif -PPC_OP(test_ctr_false) +void OPPROTO op_test_ctr_false (void) { - T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0); + T0 = ((uint32_t)regs->ctr != 0 && (T0 & PARAM1) == 0); RETURN(); } -PPC_OP(test_ctrz) +#if defined(TARGET_PPC64) +void OPPROTO op_test_ctr_false_64 (void) { - T0 = (regs->ctr == 0); + T0 = ((uint64_t)regs->ctr != 0 && (T0 & PARAM1) == 0); RETURN(); } +#endif + +void OPPROTO op_test_ctrz (void) +{ + T0 = ((uint32_t)regs->ctr == 0); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_test_ctrz_64 (void) +{ + T0 = ((uint64_t)regs->ctr == 0); + RETURN(); +} +#endif + +void OPPROTO op_test_ctrz_true (void) +{ + T0 = ((uint32_t)regs->ctr == 0 && (T0 & PARAM1) != 0); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_test_ctrz_true_64 (void) +{ + T0 = ((uint64_t)regs->ctr == 0 && (T0 & PARAM1) != 0); + RETURN(); +} +#endif -PPC_OP(test_ctrz_true) +void OPPROTO op_test_ctrz_false (void) { - T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0); + T0 = ((uint32_t)regs->ctr == 0 && (T0 & PARAM1) == 0); RETURN(); } -PPC_OP(test_ctrz_false) +#if defined(TARGET_PPC64) +void OPPROTO op_test_ctrz_false_64 (void) { - T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0); + T0 = ((uint64_t)regs->ctr == 0 && (T0 & PARAM1) == 0); RETURN(); } +#endif PPC_OP(test_true) { @@ -582,30 +705,52 @@ PPC_OP(add) RETURN(); } -void OPPROTO op_addo (void) +void OPPROTO op_check_addo (void) { - do_addo(); - RETURN(); + if (likely(!(((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) & + ((uint32_t)T2 ^ (uint32_t)T0) & (1UL << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } } -/* add carrying */ -PPC_OP(addc) +#if defined(TARGET_PPC64) +void OPPROTO op_check_addo_64 (void) { - T2 = T0; - T0 += T1; - if (T0 < T2) { - xer_ca = 1; + if (likely(!(((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) & + ((uint64_t)T2 ^ (uint64_t)T0) & (1UL << 63)))) { + xer_ov = 0; } else { + xer_so = 1; + xer_ov = 1; + } +} +#endif + +/* add carrying */ +void OPPROTO op_check_addc (void) +{ + if (likely((uint32_t)T0 >= (uint32_t)T2)) { xer_ca = 0; + } else { + xer_ca = 1; } RETURN(); } -void OPPROTO op_addco (void) +#if defined(TARGET_PPC64) +void OPPROTO op_check_addc_64 (void) { - do_addco(); + if (likely((uint64_t)T0 >= (uint64_t)T2)) { + xer_ca = 0; + } else { + xer_ca = 1; + } RETURN(); } +#endif /* add extended */ void OPPROTO op_adde (void) @@ -614,11 +759,13 @@ void OPPROTO op_adde (void) RETURN(); } -PPC_OP(addeo) +#if defined(TARGET_PPC64) +void OPPROTO op_adde_64 (void) { - do_addeo(); + do_adde_64(); RETURN(); } +#endif /* add immediate */ PPC_OP(addi) @@ -627,28 +774,24 @@ PPC_OP(addi) RETURN(); } -/* add immediate carrying */ -PPC_OP(addic) +/* add to minus one extended */ +void OPPROTO op_add_me (void) { - T1 = T0; - T0 += PARAM(1); - if (T0 < T1) { + T0 += xer_ca + (-1); + if (likely((uint32_t)T1 != 0)) xer_ca = 1; - } else { - xer_ca = 0; - } RETURN(); } -/* add to minus one extended */ -PPC_OP(addme) +#if defined(TARGET_PPC64) +void OPPROTO op_add_me_64 (void) { - T1 = T0; T0 += xer_ca + (-1); - if (T1 != 0) + if (likely((uint64_t)T1 != 0)) xer_ca = 1; RETURN(); } +#endif void OPPROTO op_addmeo (void) { @@ -656,35 +799,43 @@ void OPPROTO op_addmeo (void) RETURN(); } +void OPPROTO op_addmeo_64 (void) +{ + do_addmeo(); + RETURN(); +} + /* add to zero extended */ -PPC_OP(addze) +void OPPROTO op_add_ze (void) { - T1 = T0; T0 += xer_ca; - if (T0 < T1) { - xer_ca = 1; - } else { - xer_ca = 0; - } RETURN(); } -void OPPROTO op_addzeo (void) +/* divide word */ +void OPPROTO op_divw (void) { - do_addzeo(); + if (unlikely(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || + (int32_t)T1 == 0)) { + T0 = (int32_t)((-1) * ((uint32_t)T0 >> 31)); + } else { + T0 = (int32_t)T0 / (int32_t)T1; + } RETURN(); } -/* divide word */ -PPC_OP(divw) +#if defined(TARGET_PPC64) +void OPPROTO op_divd (void) { - if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { - T0 = (int32_t)((-1) * (T0 >> 31)); + if (unlikely(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1) || + (int64_t)T1 == 0)) { + T0 = (int64_t)((-1ULL) * ((uint64_t)T0 >> 63)); } else { - T0 = (Ts0 / Ts1); + T0 = (int64_t)T0 / (int64_t)T1; } RETURN(); } +#endif void OPPROTO op_divwo (void) { @@ -692,16 +843,36 @@ void OPPROTO op_divwo (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_divdo (void) +{ + do_divdo(); + RETURN(); +} +#endif + /* divide word unsigned */ -PPC_OP(divwu) +void OPPROTO op_divwu (void) +{ + if (unlikely(T1 == 0)) { + T0 = 0; + } else { + T0 = (uint32_t)T0 / (uint32_t)T1; + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_divdu (void) { - if (T1 == 0) { + if (unlikely(T1 == 0)) { T0 = 0; } else { T0 /= T1; } RETURN(); } +#endif void OPPROTO op_divwuo (void) { @@ -709,33 +880,71 @@ void OPPROTO op_divwuo (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_divduo (void) +{ + do_divduo(); + RETURN(); +} +#endif + /* multiply high word */ -PPC_OP(mulhw) +void OPPROTO op_mulhw (void) { - T0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32; + T0 = ((int64_t)((int32_t)T0) * (int64_t)((int32_t)T1)) >> 32; RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_mulhd (void) +{ + uint64_t tl, th; + + do_imul64(&tl, &th); + T0 = th; + RETURN(); +} +#endif + /* multiply high word unsigned */ -PPC_OP(mulhwu) +void OPPROTO op_mulhwu (void) { - T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32; + T0 = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1) >> 32; RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_mulhdu (void) +{ + uint64_t tl, th; + + do_mul64(&tl, &th); + T0 = th; + RETURN(); +} +#endif + /* multiply low immediate */ PPC_OP(mulli) { - T0 = (Ts0 * SPARAM(1)); + T0 = ((int32_t)T0 * (int32_t)PARAM1); RETURN(); } /* multiply low word */ PPC_OP(mullw) +{ + T0 = (int32_t)(T0 * T1); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_mulld (void) { T0 *= T1; RETURN(); } +#endif void OPPROTO op_mullwo (void) { @@ -743,21 +952,47 @@ void OPPROTO op_mullwo (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_mulldo (void) +{ + do_mulldo(); + RETURN(); +} +#endif + /* negate */ -PPC_OP(neg) +void OPPROTO op_neg (void) { - if (T0 != 0x80000000) { - T0 = -Ts0; + if (likely(T0 != INT32_MIN)) { + T0 = -(int32_t)T0; } RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_neg_64 (void) +{ + if (likely(T0 != INT64_MIN)) { + T0 = -(int64_t)T0; + } + RETURN(); +} +#endif + void OPPROTO op_nego (void) { do_nego(); RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_nego_64 (void) +{ + do_nego_64(); + RETURN(); +} +#endif + /* substract from */ PPC_OP(subf) { @@ -765,29 +1000,54 @@ PPC_OP(subf) RETURN(); } -void OPPROTO op_subfo (void) +void OPPROTO op_check_subfo (void) +{ + if (likely(!(((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) & + ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_check_subfo_64 (void) { - do_subfo(); + if (likely(!(((uint64_t)(~T2) ^ (uint64_t)T1 ^ UINT64_MAX) & + ((uint64_t)(~T2) ^ (uint64_t)T0) & (1ULL << 63)))) { + xer_ov = 0; + } else { + xer_so = 1; + xer_ov = 1; + } RETURN(); } +#endif /* substract from carrying */ -PPC_OP(subfc) +void OPPROTO op_check_subfc (void) { - T0 = T1 - T0; - if (T0 <= T1) { - xer_ca = 1; - } else { + if (likely((uint32_t)T0 > (uint32_t)T1)) { xer_ca = 0; + } else { + xer_ca = 1; } RETURN(); } -void OPPROTO op_subfco (void) +#if defined(TARGET_PPC64) +void OPPROTO op_check_subfc_64 (void) { - do_subfco(); + if (likely((uint64_t)T0 > (uint64_t)T1)) { + xer_ca = 0; + } else { + xer_ca = 1; + } RETURN(); } +#endif /* substract from extended */ void OPPROTO op_subfe (void) @@ -796,17 +1056,19 @@ void OPPROTO op_subfe (void) RETURN(); } -PPC_OP(subfeo) +#if defined(TARGET_PPC64) +void OPPROTO op_subfe_64 (void) { - do_subfeo(); + do_subfe_64(); RETURN(); } +#endif /* substract from immediate carrying */ -PPC_OP(subfic) +void OPPROTO op_subfic (void) { - T0 = PARAM(1) + ~T0 + 1; - if (T0 <= PARAM(1)) { + T0 = PARAM1 + ~T0 + 1; + if ((uint32_t)T0 <= (uint32_t)PARAM1) { xer_ca = 1; } else { xer_ca = 0; @@ -814,15 +1076,37 @@ PPC_OP(subfic) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_subfic_64 (void) +{ + T0 = PARAM1 + ~T0 + 1; + if ((uint64_t)T0 <= (uint64_t)PARAM1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} +#endif + /* substract from minus one extended */ -PPC_OP(subfme) +void OPPROTO op_subfme (void) { T0 = ~T0 + xer_ca - 1; + if (likely((uint32_t)T0 != (uint32_t)-1)) + xer_ca = 1; + RETURN(); +} - if (T0 != -1) +#if defined(TARGET_PPC64) +void OPPROTO op_subfme_64 (void) +{ + T0 = ~T0 + xer_ca - 1; + if (likely((uint64_t)T0 != (uint64_t)-1)) xer_ca = 1; RETURN(); } +#endif void OPPROTO op_subfmeo (void) { @@ -830,12 +1114,20 @@ void OPPROTO op_subfmeo (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_subfmeo_64 (void) +{ + do_subfmeo_64(); + RETURN(); +} +#endif + /* substract from zero extended */ -PPC_OP(subfze) +void OPPROTO op_subfze (void) { T1 = ~T0; T0 = T1 + xer_ca; - if (T0 < T1) { + if ((uint32_t)T0 < (uint32_t)T1) { xer_ca = 1; } else { xer_ca = 0; @@ -843,32 +1135,68 @@ PPC_OP(subfze) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_subfze_64 (void) +{ + T1 = ~T0; + T0 = T1 + xer_ca; + if ((uint64_t)T0 < (uint64_t)T1) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} +#endif + void OPPROTO op_subfzeo (void) { do_subfzeo(); RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_subfzeo_64 (void) +{ + do_subfzeo_64(); + RETURN(); +} +#endif + /*** Integer comparison ***/ /* compare */ -PPC_OP(cmp) +void OPPROTO op_cmp (void) +{ + if ((int32_t)T0 < (int32_t)T1) { + T0 = 0x08; + } else if ((int32_t)T0 > (int32_t)T1) { + T0 = 0x04; + } else { + T0 = 0x02; + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_cmp_64 (void) { - if (Ts0 < Ts1) { + if ((int64_t)T0 < (int64_t)T1) { T0 = 0x08; - } else if (Ts0 > Ts1) { + } else if ((int64_t)T0 > (int64_t)T1) { T0 = 0x04; } else { T0 = 0x02; } RETURN(); } +#endif /* compare immediate */ -PPC_OP(cmpi) +void OPPROTO op_cmpi (void) { - if (Ts0 < SPARAM(1)) { + if ((int32_t)T0 < (int32_t)PARAM1) { T0 = 0x08; - } else if (Ts0 > SPARAM(1)) { + } else if ((int32_t)T0 > (int32_t)PARAM1) { T0 = 0x04; } else { T0 = 0x02; @@ -876,12 +1204,26 @@ PPC_OP(cmpi) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_cmpi_64 (void) +{ + if ((int64_t)T0 < (int64_t)((int32_t)PARAM1)) { + T0 = 0x08; + } else if ((int64_t)T0 > (int64_t)((int32_t)PARAM1)) { + T0 = 0x04; + } else { + T0 = 0x02; + } + RETURN(); +} +#endif + /* compare logical */ -PPC_OP(cmpl) +void OPPROTO op_cmpl (void) { - if (T0 < T1) { + if ((uint32_t)T0 < (uint32_t)T1) { T0 = 0x08; - } else if (T0 > T1) { + } else if ((uint32_t)T0 > (uint32_t)T1) { T0 = 0x04; } else { T0 = 0x02; @@ -889,18 +1231,69 @@ PPC_OP(cmpl) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_cmpl_64 (void) +{ + if ((uint64_t)T0 < (uint64_t)T1) { + T0 = 0x08; + } else if ((uint64_t)T0 > (uint64_t)T1) { + T0 = 0x04; + } else { + T0 = 0x02; + } + RETURN(); +} +#endif + /* compare logical immediate */ -PPC_OP(cmpli) +void OPPROTO op_cmpli (void) +{ + if ((uint32_t)T0 < (uint32_t)PARAM1) { + T0 = 0x08; + } else if ((uint32_t)T0 > (uint32_t)PARAM1) { + T0 = 0x04; + } else { + T0 = 0x02; + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_cmpli_64 (void) { - if (T0 < PARAM(1)) { + if ((uint64_t)T0 < (uint64_t)PARAM1) { T0 = 0x08; - } else if (T0 > PARAM(1)) { + } else if ((uint64_t)T0 > (uint64_t)PARAM1) { T0 = 0x04; } else { T0 = 0x02; } RETURN(); } +#endif + +void OPPROTO op_isel (void) +{ + if (T0) + T0 = T1; + else + T0 = T2; + RETURN(); +} + +void OPPROTO op_popcntb (void) +{ + do_popcntb(); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_popcntb_64 (void) +{ + do_popcntb_64(); + RETURN(); +} +#endif /*** Integer logical ***/ /* and */ @@ -963,6 +1356,80 @@ void OPPROTO op_cntlzw (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_cntlzd (void) +{ +#if HOST_LONG_BITS == 64 + int cnt; + + cnt = 0; + if (!(T0 & 0xFFFFFFFF00000000ULL)) { + cnt += 32; + T0 <<= 32; + } + if (!(T0 & 0xFFFF000000000000ULL)) { + cnt += 16; + T0 <<= 16; + } + if (!(T0 & 0xFF00000000000000ULL)) { + cnt += 8; + T0 <<= 8; + } + if (!(T0 & 0xF000000000000000ULL)) { + cnt += 4; + T0 <<= 4; + } + if (!(T0 & 0xC000000000000000ULL)) { + cnt += 2; + T0 <<= 2; + } + if (!(T0 & 0x8000000000000000ULL)) { + cnt++; + T0 <<= 1; + } + if (!(T0 & 0x8000000000000000ULL)) { + cnt++; + } + T0 = cnt; +#else + uint32_t tmp; + + /* Make it easier on 32 bits host machines */ + if (!(T0 >> 32)) { + tmp = T0; + T0 = 32; + } else { + tmp = T0 >> 32; + T0 = 0; + } + if (!(tmp & 0xFFFF0000UL)) { + T0 += 16; + tmp <<= 16; + } + if (!(tmp & 0xFF000000UL)) { + T0 += 8; + tmp <<= 8; + } + if (!(tmp & 0xF0000000UL)) { + T0 += 4; + tmp <<= 4; + } + if (!(tmp & 0xC0000000UL)) { + T0 += 2; + tmp <<= 2; + } + if (!(tmp & 0x80000000UL)) { + T0++; + tmp <<= 1; + } + if (!(tmp & 0x80000000UL)) { + T0++; + } +#endif + RETURN(); +} +#endif + /* eqv */ PPC_OP(eqv) { @@ -971,19 +1438,35 @@ PPC_OP(eqv) } /* extend sign byte */ -PPC_OP(extsb) +void OPPROTO op_extsb (void) { - T0 = (int32_t)((int8_t)(Ts0)); +#if defined (TARGET_PPC64) + T0 = (int64_t)((int8_t)T0); +#else + T0 = (int32_t)((int8_t)T0); +#endif RETURN(); } /* extend sign half word */ -PPC_OP(extsh) +void OPPROTO op_extsh (void) { - T0 = (int32_t)((int16_t)(Ts0)); +#if defined (TARGET_PPC64) + T0 = (int64_t)((int16_t)T0); +#else + T0 = (int32_t)((int16_t)T0); +#endif RETURN(); } +#if defined (TARGET_PPC64) +void OPPROTO op_extsw (void) +{ + T0 = (int64_t)((int32_t)T0); + RETURN(); +} +#endif + /* nand */ PPC_OP(nand) { @@ -1048,15 +1531,27 @@ void OPPROTO op_rotli32_T0 (void) /*** Integer shift ***/ /* shift left word */ -PPC_OP(slw) +void OPPROTO op_slw (void) { if (T1 & 0x20) { T0 = 0; + } else { + T0 = (uint32_t)(T0 << T1); + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_sld (void) +{ + if (T1 & 0x40) { + T0 = 0; } else { T0 = T0 << T1; } RETURN(); } +#endif /* shift right algebraic word */ void OPPROTO op_sraw (void) @@ -1065,12 +1560,21 @@ void OPPROTO op_sraw (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_srad (void) +{ + do_srad(); + RETURN(); +} +#endif + /* shift right algebraic word immediate */ -PPC_OP(srawi) +void OPPROTO op_srawi (void) { - T1 = T0; - T0 = (Ts0 >> PARAM(1)); - if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) { + uint32_t mask = (uint32_t)PARAM2; + + T0 = (int32_t)T0 >> PARAM1; + if ((int32_t)T1 < 0 && (T1 & mask) != 0) { xer_ca = 1; } else { xer_ca = 0; @@ -1078,16 +1582,43 @@ PPC_OP(srawi) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_sradi (void) +{ + uint64_t mask = ((uint64_t)PARAM2 << 32) | (uint64_t)PARAM3; + + T0 = (int64_t)T0 >> PARAM1; + if ((int64_t)T1 < 0 && ((uint64_t)T1 & mask) != 0) { + xer_ca = 1; + } else { + xer_ca = 0; + } + RETURN(); +} +#endif + /* shift right word */ -PPC_OP(srw) +void OPPROTO op_srw (void) { if (T1 & 0x20) { T0 = 0; } else { - T0 = T0 >> T1; + T0 = (uint32_t)T0 >> T1; + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_srd (void) +{ + if (T1 & 0x40) { + T0 = 0; + } else { + T0 = (uint64_t)T0 >> T1; } RETURN(); } +#endif void OPPROTO op_sl_T0_T1 (void) { @@ -1103,22 +1634,46 @@ void OPPROTO op_sli_T0 (void) void OPPROTO op_srl_T0_T1 (void) { - T0 = T0 >> T1; + T0 = (uint32_t)T0 >> T1; + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO op_srl_T0_T1_64 (void) +{ + T0 = (uint32_t)T0 >> T1; RETURN(); } +#endif void OPPROTO op_srli_T0 (void) { - T0 = T0 >> PARAM1; + T0 = (uint32_t)T0 >> PARAM1; RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_srli_T0_64 (void) +{ + T0 = (uint64_t)T0 >> PARAM1; + RETURN(); +} +#endif + void OPPROTO op_srli_T1 (void) { - T1 = T1 >> PARAM1; + T1 = (uint32_t)T1 >> PARAM1; RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_srli_T1_64 (void) +{ + T1 = (uint64_t)T1 >> PARAM1; + RETURN(); +} +#endif + /*** Floating-Point arithmetic ***/ /* fadd - fadd. */ PPC_OP(fadd) @@ -1281,13 +1836,22 @@ PPC_OP(fneg) #endif /* Special op to check and maybe clear reservation */ -PPC_OP(check_reservation) +void OPPROTO op_check_reservation (void) { if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003)) env->reserve = -1; RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_check_reservation_64 (void) +{ + if ((uint64_t)env->reserve == (uint64_t)(T0 & ~0x00000003)) + env->reserve = -1; + RETURN(); +} +#endif + /* Return from interrupt */ #if !defined(CONFIG_USER_ONLY) void OPPROTO op_rfi (void) @@ -1295,6 +1859,14 @@ void OPPROTO op_rfi (void) do_rfi(); RETURN(); } + +#if defined(TARGET_PPC64) +void OPPROTO op_rfi_32 (void) +{ + do_rfi_32(); + RETURN(); +} +#endif #endif /* Trap word */ @@ -1304,13 +1876,29 @@ void OPPROTO op_tw (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_td (void) +{ + do_td(PARAM1); + RETURN(); +} +#endif + /* Instruction cache block invalidate */ -PPC_OP(icbi) +void OPPROTO op_icbi (void) { do_icbi(); RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_icbi_64 (void) +{ + do_icbi_64(); + RETURN(); +} +#endif + #if !defined(CONFIG_USER_ONLY) /* tlbia */ PPC_OP(tlbia) @@ -1320,11 +1908,33 @@ PPC_OP(tlbia) } /* tlbie */ -PPC_OP(tlbie) +void OPPROTO op_tlbie (void) { do_tlbie(); RETURN(); } + +#if defined(TARGET_PPC64) +void OPPROTO op_tlbie_64 (void) +{ + do_tlbie_64(); + RETURN(); +} +#endif + +#if defined(TARGET_PPC64) +void OPPROTO op_slbia (void) +{ + do_slbia(); + RETURN(); +} + +void OPPROTO op_slbie (void) +{ + do_slbie(); + RETURN(); +} +#endif #endif /* PowerPC 602/603/755 software TLB load instructions */ @@ -1343,14 +1953,12 @@ void OPPROTO op_6xx_tlbli (void) #endif /* 601 specific */ -uint32_t cpu_ppc601_load_rtcl (CPUState *env); void OPPROTO op_load_601_rtcl (void) { T0 = cpu_ppc601_load_rtcl(env); RETURN(); } -uint32_t cpu_ppc601_load_rtcu (CPUState *env); void OPPROTO op_load_601_rtcu (void) { T0 = cpu_ppc601_load_rtcu(env); @@ -1358,14 +1966,12 @@ void OPPROTO op_load_601_rtcu (void) } #if !defined(CONFIG_USER_ONLY) -void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value); void OPPROTO op_store_601_rtcl (void) { cpu_ppc601_store_rtcl(env, T0); RETURN(); } -void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value); void OPPROTO op_store_601_rtcu (void) { cpu_ppc601_store_rtcu(env, T0); @@ -1449,7 +2055,7 @@ void OPPROTO op_POWER_divso (void) void OPPROTO op_POWER_doz (void) { - if (Ts1 > Ts0) + if ((int32_t)T1 > (int32_t)T0) T0 = T1 - T0; else T0 = 0; @@ -1580,7 +2186,7 @@ void OPPROTO op_POWER_sraq (void) if (T1 & 0x20UL) T0 = -1L; else - T0 = Ts0 >> T1; + T0 = (int32_t)T0 >> T1; RETURN(); } @@ -1588,7 +2194,7 @@ void OPPROTO op_POWER_sre (void) { T1 &= 0x1FUL; env->spr[SPR_MQ] = rotl32(T0, 32 - T1); - T0 = Ts0 >> T1; + T0 = (int32_t)T0 >> T1; RETURN(); } @@ -1596,7 +2202,7 @@ void OPPROTO op_POWER_srea (void) { T1 &= 0x1FUL; env->spr[SPR_MQ] = T0 >> T1; - T0 = Ts0 >> T1; + T0 = (int32_t)T0 >> T1; RETURN(); } @@ -1848,28 +2454,24 @@ void OPPROTO op_store_403_pb (void) RETURN(); } -target_ulong load_40x_pit (CPUState *env); void OPPROTO op_load_40x_pit (void) { T0 = load_40x_pit(env); RETURN(); } -void store_40x_pit (CPUState *env, target_ulong val); void OPPROTO op_store_40x_pit (void) { store_40x_pit(env, T0); RETURN(); } -void store_booke_tcr (CPUState *env, target_ulong val); void OPPROTO op_store_booke_tcr (void) { store_booke_tcr(env, T0); RETURN(); } -void store_booke_tsr (CPUState *env, target_ulong val); void OPPROTO op_store_booke_tsr (void) { store_booke_tsr(env, T0); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index ea3849710..7bc59332d 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -33,10 +33,6 @@ //#define DEBUG_SOFTWARE_TLB //#define FLUSH_ALL_TLBS -#define Ts0 (long)((target_long)T0) -#define Ts1 (long)((target_long)T1) -#define Ts2 (long)((target_long)T2) - /*****************************************************************************/ /* Exceptions processing helpers */ void cpu_loop_exit (void) @@ -106,7 +102,7 @@ void do_store_xer (void) xer_ov = (T0 >> XER_OV) & 0x01; xer_ca = (T0 >> XER_CA) & 0x01; xer_cmp = (T0 >> XER_CMP) & 0xFF; - xer_bc = (T0 >> XER_BC) & 0x3F; + xer_bc = (T0 >> XER_BC) & 0x7F; } void do_load_fpscr (void) @@ -122,7 +118,7 @@ void do_load_fpscr (void) } u; int i; -#ifdef WORDS_BIGENDIAN +#if defined(WORDS_BIGENDIAN) #define WORD0 0 #define WORD1 1 #else @@ -182,68 +178,110 @@ void do_store_fpscr (uint32_t mask) /*****************************************************************************/ /* Fixed point operations helpers */ -void do_addo (void) +#if defined(TARGET_PPC64) +static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { - T2 = T0; - T0 += T1; - if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { - xer_ov = 0; - } else { - xer_so = 1; - xer_ov = 1; - } + *plow += a; + /* carry test */ + if (*plow < a) + (*phigh)++; + *phigh += b; } -void do_addco (void) +static void neg128 (uint64_t *plow, uint64_t *phigh) { - T2 = T0; - T0 += T1; - if (likely(T0 >= T2)) { - xer_ca = 0; - } else { - xer_ca = 1; - } - if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { - xer_ov = 0; - } else { - xer_so = 1; - xer_ov = 1; + *plow = ~ *plow; + *phigh = ~ *phigh; + add128(plow, phigh, 1, 0); +} + +static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + uint32_t a0, a1, b0, b1; + uint64_t v; + + a0 = a; + a1 = a >> 32; + + b0 = b; + b1 = b >> 32; + + v = (uint64_t)a0 * (uint64_t)b0; + *plow = v; + *phigh = 0; + + v = (uint64_t)a0 * (uint64_t)b1; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b0; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b1; + *phigh += v; +#if defined(DEBUG_MULDIV) + printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + a, b, *phigh, *plow); +#endif +} + +void do_mul64 (uint64_t *plow, uint64_t *phigh) +{ + mul64(plow, phigh, T0, T1); +} + +static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) +{ + int sa, sb; + sa = (a < 0); + if (sa) + a = -a; + sb = (b < 0); + if (sb) + b = -b; + mul64(plow, phigh, a, b); + if (sa ^ sb) { + neg128(plow, phigh); } } +void do_imul64 (uint64_t *plow, uint64_t *phigh) +{ + imul64(plow, phigh, T0, T1); +} +#endif + void do_adde (void) { T2 = T0; T0 += T1 + xer_ca; - if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) { + if (likely(!((uint32_t)T0 < (uint32_t)T2 || + (xer_ca == 1 && (uint32_t)T0 == (uint32_t)T2)))) { xer_ca = 0; } else { xer_ca = 1; } } -void do_addeo (void) +#if defined(TARGET_PPC64) +void do_adde_64 (void) { T2 = T0; T0 += T1 + xer_ca; - if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) { + if (likely(!((uint64_t)T0 < (uint64_t)T2 || + (xer_ca == 1 && (uint64_t)T0 == (uint64_t)T2)))) { xer_ca = 0; } else { xer_ca = 1; } - if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { - xer_ov = 0; - } else { - xer_so = 1; - xer_ov = 1; - } } +#endif void do_addmeo (void) { T1 = T0; T0 += xer_ca + (-1); - if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) { + if (likely(!((uint32_t)T1 & + ((uint32_t)T1 ^ (uint32_t)T0) & (1UL << 31)))) { xer_ov = 0; } else { xer_so = 1; @@ -253,28 +291,29 @@ void do_addmeo (void) xer_ca = 1; } -void do_addzeo (void) +#if defined(TARGET_PPC64) +void do_addmeo_64 (void) { T1 = T0; - T0 += xer_ca; - if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) { + T0 += xer_ca + (-1); + if (likely(!((uint64_t)T1 & + ((uint64_t)T1 ^ (uint64_t)T0) & (1ULL << 63)))) { xer_ov = 0; } else { xer_so = 1; xer_ov = 1; } - if (likely(T0 >= T1)) { - xer_ca = 0; - } else { + if (likely(T1 != 0)) xer_ca = 1; - } } +#endif void do_divwo (void) { - if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) { + if (likely(!(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || + (int32_t)T1 == 0))) { xer_ov = 0; - T0 = (Ts0 / Ts1); + T0 = (int32_t)T0 / (int32_t)T1; } else { xer_so = 1; xer_ov = 1; @@ -282,6 +321,21 @@ void do_divwo (void) } } +#if defined(TARGET_PPC64) +void do_divdo (void) +{ + if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1ULL) || + (int64_t)T1 == 0))) { + xer_ov = 0; + T0 = (int64_t)T0 / (int64_t)T1; + } else { + xer_so = 1; + xer_ov = 1; + T0 = (-1ULL) * ((uint64_t)T0 >> 63); + } +} +#endif + void do_divwuo (void) { if (likely((uint32_t)T1 != 0)) { @@ -294,9 +348,23 @@ void do_divwuo (void) } } +#if defined(TARGET_PPC64) +void do_divduo (void) +{ + if (likely((uint64_t)T1 != 0)) { + xer_ov = 0; + T0 = (uint64_t)T0 / (uint64_t)T1; + } else { + xer_so = 1; + xer_ov = 1; + T0 = 0; + } +} +#endif + void do_mullwo (void) { - int64_t res = (int64_t)Ts0 * (int64_t)Ts1; + int64_t res = (int64_t)T0 * (int64_t)T1; if (likely((int32_t)res == res)) { xer_ov = 0; @@ -307,112 +375,148 @@ void do_mullwo (void) T0 = (int32_t)res; } -void do_nego (void) +#if defined(TARGET_PPC64) +void do_mulldo (void) { - if (likely(T0 != INT32_MIN)) { + int64_t th; + uint64_t tl; + + do_imul64(&tl, &th); + if (likely(th == 0)) { xer_ov = 0; - T0 = -Ts0; } else { xer_ov = 1; xer_so = 1; } + T0 = (int64_t)tl; } +#endif -void do_subfo (void) +void do_nego (void) { - T2 = T0; - T0 = T1 - T0; - if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) { + if (likely((int32_t)T0 != INT32_MIN)) { xer_ov = 0; + T0 = -(int32_t)T0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } - RETURN(); } -void do_subfco (void) +#if defined(TARGET_PPC64) +void do_nego_64 (void) { - T2 = T0; - T0 = T1 - T0; - if (likely(T0 > T1)) { - xer_ca = 0; - } else { - xer_ca = 1; - } - if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) { + if (likely((int64_t)T0 != INT64_MIN)) { xer_ov = 0; + T0 = -(int64_t)T0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } } +#endif void do_subfe (void) { T0 = T1 + ~T0 + xer_ca; - if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) { + if (likely((uint32_t)T0 >= (uint32_t)T1 && + (xer_ca == 0 || (uint32_t)T0 != (uint32_t)T1))) { xer_ca = 0; } else { xer_ca = 1; } } -void do_subfeo (void) +#if defined(TARGET_PPC64) +void do_subfe_64 (void) { - T2 = T0; T0 = T1 + ~T0 + xer_ca; - if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) { + if (likely((uint64_t)T0 >= (uint64_t)T1 && + (xer_ca == 0 || (uint64_t)T0 != (uint64_t)T1))) { + xer_ca = 0; + } else { + xer_ca = 1; + } +} +#endif + +void do_subfmeo (void) +{ + T1 = T0; + T0 = ~T0 + xer_ca - 1; + if (likely(!((uint32_t)~T1 & ((uint32_t)~T1 ^ (uint32_t)T0) & + (1UL << 31)))) { xer_ov = 0; } else { xer_so = 1; xer_ov = 1; } - if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) { - xer_ca = 0; - } else { + if (likely((uint32_t)T1 != UINT32_MAX)) xer_ca = 1; - } } -void do_subfmeo (void) +#if defined(TARGET_PPC64) +void do_subfmeo_64 (void) { T1 = T0; T0 = ~T0 + xer_ca - 1; - if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) { + if (likely(!((uint64_t)~T1 & ((uint64_t)~T1 ^ (uint64_t)T0) & + (1ULL << 63)))) { xer_ov = 0; } else { xer_so = 1; xer_ov = 1; } - if (likely(T1 != -1)) + if (likely((uint64_t)T1 != UINT64_MAX)) xer_ca = 1; } +#endif void do_subfzeo (void) { T1 = T0; T0 = ~T0 + xer_ca; - if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) { + if (likely(!(((uint32_t)~T1 ^ UINT32_MAX) & + ((uint32_t)(~T1) ^ (uint32_t)T0) & (1UL << 31)))) { xer_ov = 0; } else { xer_ov = 1; xer_so = 1; } - if (likely(T0 >= ~T1)) { + if (likely((uint32_t)T0 >= (uint32_t)~T1)) { xer_ca = 0; } else { xer_ca = 1; } } +#if defined(TARGET_PPC64) +void do_subfzeo_64 (void) +{ + T1 = T0; + T0 = ~T0 + xer_ca; + if (likely(!(((uint64_t)~T1 ^ UINT64_MAX) & + ((uint64_t)(~T1) ^ (uint64_t)T0) & (1ULL << 63)))) { + xer_ov = 0; + } else { + xer_ov = 1; + xer_so = 1; + } + if (likely((uint64_t)T0 >= (uint64_t)~T1)) { + xer_ca = 0; + } else { + xer_ca = 1; + } +} +#endif + /* shift right arithmetic helper */ void do_sraw (void) { int32_t ret; if (likely(!(T1 & 0x20UL))) { - if (likely(T1 != 0)) { + if (likely((uint32_t)T1 != 0)) { ret = (int32_t)T0 >> (T1 & 0x1fUL); if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) { xer_ca = 0; @@ -434,6 +538,69 @@ void do_sraw (void) T0 = ret; } +#if defined(TARGET_PPC64) +void do_srad (void) +{ + int64_t ret; + + if (likely(!(T1 & 0x40UL))) { + if (likely((uint64_t)T1 != 0)) { + ret = (int64_t)T0 >> (T1 & 0x3FUL); + if (likely(ret >= 0 || ((int64_t)T0 & ((1 << T1) - 1)) == 0)) { + xer_ca = 0; + } else { + xer_ca = 1; + } + } else { + ret = T0; + xer_ca = 0; + } + } else { + ret = (-1) * ((uint64_t)T0 >> 63); + if (likely(ret >= 0 || ((uint64_t)T0 & ~0x8000000000000000ULL) == 0)) { + xer_ca = 0; + } else { + xer_ca = 1; + } + } + T0 = ret; +} +#endif + +static inline int popcnt (uint32_t val) +{ + int i; + + for (i = 0; val != 0;) + val = val ^ (val - 1); + + return i; +} + +void do_popcntb (void) +{ + uint32_t ret; + int i; + + ret = 0; + for (i = 0; i < 32; i += 8) + ret |= popcnt((T0 >> i) & 0xFF) << i; + T0 = ret; +} + +#if defined(TARGET_PPC64) +void do_popcntb_64 (void) +{ + uint64_t ret; + int i; + + ret = 0; + for (i = 0; i < 64; i += 8) + ret |= popcnt((T0 >> i) & 0xFF) << i; + T0 = ret; +} +#endif + /*****************************************************************************/ /* Floating point operations helpers */ void do_fctiw (void) @@ -459,7 +626,7 @@ void do_fctiwz (void) } p; /* XXX: higher bits are not supposed to be significant. - * to make tests easier, return the same as a real PowerPC 750 (aka G3) + * to make tests easier, return the same as a real PowerPC 750 (aka G3) */ p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); p.i |= 0xFFF80000ULL << 32; @@ -596,26 +763,51 @@ void do_fcmpo (void) #if !defined (CONFIG_USER_ONLY) void do_rfi (void) { - env->nip = env->spr[SPR_SRR0] & ~0x00000003; - T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL; + env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003); + T0 = (target_ulong)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); do_store_msr(env, T0); #if defined (DEBUG_OP) dump_rfi(); #endif env->interrupt_request |= CPU_INTERRUPT_EXITTB; } + +#if defined(TARGET_PPC64) +void do_rfi_32 (void) +{ + env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); + T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); + do_store_msr(env, T0); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request |= CPU_INTERRUPT_EXITTB; +} +#endif #endif void do_tw (int flags) { - if (!likely(!((Ts0 < Ts1 && (flags & 0x10)) || - (Ts0 > Ts1 && (flags & 0x08)) || - (Ts0 == Ts1 && (flags & 0x04)) || - (T0 < T1 && (flags & 0x02)) || - (T0 > T1 && (flags & 0x01))))) + if (!likely(!(((int32_t)T0 < (int32_t)T1 && (flags & 0x10)) || + ((int32_t)T0 > (int32_t)T1 && (flags & 0x08)) || + ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) || + ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) || + ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); } +#if defined(TARGET_PPC64) +void do_td (int flags) +{ + if (!likely(!(((int64_t)T0 < (int64_t)T1 && (flags & 0x10)) || + ((int64_t)T0 > (int64_t)T1 && (flags & 0x08)) || + ((int64_t)T0 == (int64_t)T1 && (flags & 0x04)) || + ((uint64_t)T0 < (uint64_t)T1 && (flags & 0x02)) || + ((uint64_t)T0 > (uint64_t)T1 && (flags & 0x01))))) + do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); +} +#endif + /* Instruction cache invalidation helper */ void do_icbi (void) { @@ -625,20 +817,31 @@ void do_icbi (void) * (not a fetch) by the MMU. To be sure it will be so, * do the load "by hand". */ + tmp = ldl_kernel((uint32_t)T0); + T0 &= ~(ICACHE_LINE_SIZE - 1); + tb_invalidate_page_range((uint32_t)T0, (uint32_t)(T0 + ICACHE_LINE_SIZE)); +} + #if defined(TARGET_PPC64) - if (!msr_sf) - T0 &= 0xFFFFFFFFULL; -#endif - tmp = ldl_kernel(T0); +void do_icbi_64 (void) +{ + uint64_t tmp; + /* Invalidate one cache line : + * PowerPC specification says this is to be treated like a load + * (not a fetch) by the MMU. To be sure it will be so, + * do the load "by hand". + */ + tmp = ldq_kernel((uint64_t)T0); T0 &= ~(ICACHE_LINE_SIZE - 1); - tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE); + tb_invalidate_page_range((uint64_t)T0, (uint64_t)(T0 + ICACHE_LINE_SIZE)); } +#endif /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ void do_POWER_abso (void) { - if (T0 == INT32_MIN) { + if ((uint32_t)T0 == INT32_MIN) { T0 = INT32_MAX; xer_ov = 1; xer_so = 1; @@ -679,13 +882,13 @@ void do_POWER_div (void) { uint64_t tmp; - if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) { T0 = (long)((-1) * (T0 >> 31)); env->spr[SPR_MQ] = 0; } else { tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; env->spr[SPR_MQ] = tmp % T1; - T0 = tmp / Ts1; + T0 = tmp / (int32_t)T1; } } @@ -693,7 +896,7 @@ void do_POWER_divo (void) { int64_t tmp; - if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) { T0 = (long)((-1) * (T0 >> 31)); env->spr[SPR_MQ] = 0; xer_ov = 1; @@ -701,7 +904,7 @@ void do_POWER_divo (void) } else { tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; env->spr[SPR_MQ] = tmp % T1; - tmp /= Ts1; + tmp /= (int32_t)T1; if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) { xer_ov = 1; xer_so = 1; @@ -714,35 +917,36 @@ void do_POWER_divo (void) void do_POWER_divs (void) { - if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) { T0 = (long)((-1) * (T0 >> 31)); env->spr[SPR_MQ] = 0; } else { env->spr[SPR_MQ] = T0 % T1; - T0 = Ts0 / Ts1; + T0 = (int32_t)T0 / (int32_t)T1; } } void do_POWER_divso (void) { - if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) { + if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) { T0 = (long)((-1) * (T0 >> 31)); env->spr[SPR_MQ] = 0; xer_ov = 1; xer_so = 1; } else { - T0 = Ts0 / Ts1; - env->spr[SPR_MQ] = Ts0 % Ts1; + T0 = (int32_t)T0 / (int32_t)T1; + env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1; xer_ov = 0; } } void do_POWER_dozo (void) { - if (Ts1 > Ts0) { + if ((int32_t)T1 > (int32_t)T0) { T2 = T0; T0 = T1 - T0; - if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) { + if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) & + ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) { xer_so = 1; xer_ov = 1; } else { @@ -758,12 +962,12 @@ void do_POWER_maskg (void) { uint32_t ret; - if (T0 == T1 + 1) { + if ((uint32_t)T0 == (uint32_t)(T1 + 1)) { ret = -1; } else { - ret = (((uint32_t)(-1)) >> (T0)) ^ - (((uint32_t)(-1) >> (T1)) >> 1); - if (T0 > T1) + ret = (((uint32_t)(-1)) >> ((uint32_t)T0)) ^ + (((uint32_t)(-1) >> ((uint32_t)T1)) >> 1); + if ((uint32_t)T0 > (uint32_t)T1) ret = ~ret; } T0 = ret; @@ -812,7 +1016,7 @@ void do_POWER_rfsvc (void) /* PowerPC 601 BAT management helper */ void do_store_601_batu (int nr) { - do_store_ibatu(env, nr, T0); + do_store_ibatu(env, nr, (uint32_t)T0); env->DBAT[0][nr] = env->IBAT[0][nr]; env->DBAT[1][nr] = env->IBAT[1][nr]; } @@ -826,7 +1030,7 @@ void do_store_601_batu (int nr) void do_op_602_mfrom (void) { if (likely(T0 < 602)) { -#ifdef USE_MFROM_ROM_TABLE +#if defined(USE_MFROM_ROM_TABLE) #include "mfrom_table.c" T0 = mfrom_ROM_table[T0]; #else @@ -854,7 +1058,8 @@ void do_op_602_mfrom (void) /* Embedded PowerPC specific helpers */ void do_405_check_ov (void) { - if (likely(((T1 ^ T2) >> 31) || !((T0 ^ T2) >> 31))) { + if (likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) || + !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) { xer_ov = 0; } else { xer_ov = 1; @@ -864,7 +1069,8 @@ void do_405_check_ov (void) void do_405_check_sat (void) { - if (!likely(((T1 ^ T2) >> 31) || !((T0 ^ T2) >> 31))) { + if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) || + !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) { /* Saturate result */ if (T2 >> 31) { T0 = INT32_MIN; @@ -1010,6 +1216,7 @@ void do_tlbia (void) void do_tlbie (void) { + T0 = (uint32_t)T0; #if !defined(FLUSH_ALL_TLBS) if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); @@ -1050,13 +1257,78 @@ void do_tlbie (void) #endif } +#if defined(TARGET_PPC64) +void do_tlbie_64 (void) +{ + T0 = (uint64_t)T0; +#if !defined(FLUSH_ALL_TLBS) + if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); + if (env->id_tlbs == 1) + ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1); + } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + /* XXX: TODO */ +#if 0 + ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, + env->spr[SPR_BOOKE_PID]); +#endif + } else { + /* tlbie invalidate TLBs for all segments + * As we have 2^36 segments, invalidate all qemu TLBs + */ +#if 0 + T0 &= TARGET_PAGE_MASK; + T0 &= ~((target_ulong)-1 << 28); + /* XXX: this case should be optimized, + * giving a mask to tlb_flush_page + */ + tlb_flush_page(env, T0 | (0x0 << 28)); + tlb_flush_page(env, T0 | (0x1 << 28)); + tlb_flush_page(env, T0 | (0x2 << 28)); + tlb_flush_page(env, T0 | (0x3 << 28)); + tlb_flush_page(env, T0 | (0x4 << 28)); + tlb_flush_page(env, T0 | (0x5 << 28)); + tlb_flush_page(env, T0 | (0x6 << 28)); + tlb_flush_page(env, T0 | (0x7 << 28)); + tlb_flush_page(env, T0 | (0x8 << 28)); + tlb_flush_page(env, T0 | (0x9 << 28)); + tlb_flush_page(env, T0 | (0xA << 28)); + tlb_flush_page(env, T0 | (0xB << 28)); + tlb_flush_page(env, T0 | (0xC << 28)); + tlb_flush_page(env, T0 | (0xD << 28)); + tlb_flush_page(env, T0 | (0xE << 28)); + tlb_flush_page(env, T0 | (0xF << 28)); +#else + tlb_flush(env, 1); +#endif + } +#else + do_tlbia(); +#endif +} +#endif + +#if defined(TARGET_PPC64) +void do_slbia (void) +{ + /* XXX: TODO */ + tlb_flush(env, 1); +} + +void do_slbie (void) +{ + /* XXX: TODO */ + tlb_flush(env, 1); +} +#endif + /* Software driven TLBs management */ /* PowerPC 602/603 software TLB load instructions helpers */ void do_load_6xx_tlb (int is_code) { target_ulong RPN, CMP, EPN; int way; - + RPN = env->spr[SPR_RPA]; if (is_code) { CMP = env->spr[SPR_ICMP]; @@ -1074,7 +1346,8 @@ void do_load_6xx_tlb (int is_code) } #endif /* Store this TLB */ - ppc6xx_tlb_store(env, T0 & TARGET_PAGE_MASK, way, is_code, CMP, RPN); + ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK), + way, is_code, CMP, RPN); } /* Helpers for 4xx TLB management */ diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 0cba00204..13ed7ab92 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -35,6 +35,17 @@ void glue(do_POWER2_lfq_le, MEMSUFFIX) (void); void glue(do_POWER2_stfq, MEMSUFFIX) (void); void glue(do_POWER2_stfq_le, MEMSUFFIX) (void); +#if defined(TARGET_PPC64) +void glue(do_lsw_64, MEMSUFFIX) (int dst); +void glue(do_lsw_le_64, MEMSUFFIX) (int dst); +void glue(do_stsw_64, MEMSUFFIX) (int src); +void glue(do_stsw_le_64, MEMSUFFIX) (int src); +void glue(do_lmw_64, MEMSUFFIX) (int dst); +void glue(do_lmw_le_64, MEMSUFFIX) (int dst); +void glue(do_stmw_64, MEMSUFFIX) (int src); +void glue(do_stmw_le_64, MEMSUFFIX) (int src); +#endif + #else /* Registers load and stores */ @@ -46,23 +57,34 @@ void do_load_fpscr (void); void do_store_fpscr (uint32_t mask); /* Integer arithmetic helpers */ -void do_addo (void); -void do_addco (void); void do_adde (void); -void do_addeo (void); void do_addmeo (void); -void do_addzeo (void); void do_divwo (void); void do_divwuo (void); void do_mullwo (void); void do_nego (void); -void do_subfo (void); -void do_subfco (void); void do_subfe (void); -void do_subfeo (void); void do_subfmeo (void); void do_subfzeo (void); -void do_sraw(void); +void do_sraw (void); +#if defined(TARGET_PPC64) +void do_adde_64 (void); +void do_addmeo_64 (void); +void do_imul64 (uint64_t *tl, uint64_t *th); +void do_mul64 (uint64_t *tl, uint64_t *th); +void do_divdo (void); +void do_divduo (void); +void do_mulldo (void); +void do_nego_64 (void); +void do_subfe_64 (void); +void do_subfmeo_64 (void); +void do_subfzeo_64 (void); +void do_srad (void); +#endif +void do_popcntb (void); +#if defined(TARGET_PPC64) +void do_popcntb_64 (void); +#endif /* Floating-point arithmetic helpers */ void do_fsqrt (void); @@ -77,13 +99,29 @@ void do_fcmpu (void); void do_fcmpo (void); void do_tw (int flags); +#if defined(TARGET_PPC64) +void do_td (int flags); +#endif void do_icbi (void); +#if defined(TARGET_PPC64) +void do_icbi_64 (void); +#endif #if !defined(CONFIG_USER_ONLY) void do_rfi (void); +#if defined(TARGET_PPC64) +void do_rfi_32 (void); +#endif void do_tlbia (void); void do_tlbie (void); +#if defined(TARGET_PPC64) +void do_tlbie_64 (void); +#endif void do_load_6xx_tlb (int is_code); +#if defined(TARGET_PPC64) +void do_slbia (void); +void do_slbie (void); +#endif #endif /* POWER / PowerPC 601 specific helpers */ diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index 45bb90d8a..ccee7142e 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -1,6 +1,6 @@ /* * PowerPC emulation micro-operations helpers for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -37,98 +37,210 @@ static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, target_ulong data) void glue(do_lmw, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ldl, MEMSUFFIX)(T0); + ugpr(dst) = glue(ldl, MEMSUFFIX)((uint32_t)T0); + } +} + +#if defined(TARGET_PPC64) +void glue(do_lmw_64, MEMSUFFIX) (int dst) +{ + for (; dst < 32; dst++, T0 += 4) { + ugpr(dst) = glue(ldl, MEMSUFFIX)((uint64_t)T0); } } +#endif void glue(do_stmw, MEMSUFFIX) (int src) { for (; src < 32; src++, T0 += 4) { - glue(stl, MEMSUFFIX)(T0, ugpr(src)); + glue(stl, MEMSUFFIX)((uint32_t)T0, ugpr(src)); + } +} + +#if defined(TARGET_PPC64) +void glue(do_stmw_64, MEMSUFFIX) (int src) +{ + for (; src < 32; src++, T0 += 4) { + glue(stl, MEMSUFFIX)((uint64_t)T0, ugpr(src)); } } +#endif void glue(do_lmw_le, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0); + ugpr(dst) = glue(ld32r, MEMSUFFIX)((uint32_t)T0); + } +} + +#if defined(TARGET_PPC64) +void glue(do_lmw_le_64, MEMSUFFIX) (int dst) +{ + for (; dst < 32; dst++, T0 += 4) { + ugpr(dst) = glue(ld32r, MEMSUFFIX)((uint64_t)T0); } } +#endif void glue(do_stmw_le, MEMSUFFIX) (int src) { for (; src < 32; src++, T0 += 4) { - glue(st32r, MEMSUFFIX)(T0, ugpr(src)); + glue(st32r, MEMSUFFIX)((uint32_t)T0, ugpr(src)); } } +#if defined(TARGET_PPC64) +void glue(do_stmw_le_64, MEMSUFFIX) (int src) +{ + for (; src < 32; src++, T0 += 4) { + glue(st32r, MEMSUFFIX)((uint64_t)T0, ugpr(src)); + } +} +#endif + void glue(do_lsw, MEMSUFFIX) (int dst) { uint32_t tmp; int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0); + ugpr(dst++) = glue(ldl, MEMSUFFIX)((uint32_t)T0); if (unlikely(dst == 32)) dst = 0; } if (unlikely(T1 != 0)) { tmp = 0; for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { - tmp |= glue(ldub, MEMSUFFIX)(T0) << sh; + tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh; } ugpr(dst) = tmp; } } +#if defined(TARGET_PPC64) +void glue(do_lsw_64, MEMSUFFIX) (int dst) +{ + uint32_t tmp; + int sh; + + for (; T1 > 3; T1 -= 4, T0 += 4) { + ugpr(dst++) = glue(ldl, MEMSUFFIX)((uint64_t)T0); + if (unlikely(dst == 32)) + dst = 0; + } + if (unlikely(T1 != 0)) { + tmp = 0; + for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { + tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh; + } + ugpr(dst) = tmp; + } +} +#endif + void glue(do_stsw, MEMSUFFIX) (int src) { int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(stl, MEMSUFFIX)(T0, ugpr(src++)); + glue(stl, MEMSUFFIX)((uint32_t)T0, ugpr(src++)); if (unlikely(src == 32)) src = 0; } if (unlikely(T1 != 0)) { for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) - glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF); + glue(stb, MEMSUFFIX)((uint32_t)T0, (ugpr(src) >> sh) & 0xFF); } } +#if defined(TARGET_PPC64) +void glue(do_stsw_64, MEMSUFFIX) (int src) +{ + int sh; + + for (; T1 > 3; T1 -= 4, T0 += 4) { + glue(stl, MEMSUFFIX)((uint64_t)T0, ugpr(src++)); + if (unlikely(src == 32)) + src = 0; + } + if (unlikely(T1 != 0)) { + for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) + glue(stb, MEMSUFFIX)((uint64_t)T0, (ugpr(src) >> sh) & 0xFF); + } +} +#endif + void glue(do_lsw_le, MEMSUFFIX) (int dst) { uint32_t tmp; int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - ugpr(dst++) = glue(ld32r, MEMSUFFIX)(T0); + ugpr(dst++) = glue(ld32r, MEMSUFFIX)((uint32_t)T0); + if (unlikely(dst == 32)) + dst = 0; + } + if (unlikely(T1 != 0)) { + tmp = 0; + for (sh = 0; T1 > 0; T1--, T0++, sh += 8) { + tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh; + } + ugpr(dst) = tmp; + } +} + +#if defined(TARGET_PPC64) +void glue(do_lsw_le_64, MEMSUFFIX) (int dst) +{ + uint32_t tmp; + int sh; + + for (; T1 > 3; T1 -= 4, T0 += 4) { + ugpr(dst++) = glue(ld32r, MEMSUFFIX)((uint64_t)T0); if (unlikely(dst == 32)) dst = 0; } if (unlikely(T1 != 0)) { tmp = 0; for (sh = 0; T1 > 0; T1--, T0++, sh += 8) { - tmp |= glue(ldub, MEMSUFFIX)(T0) << sh; + tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh; } ugpr(dst) = tmp; } } +#endif void glue(do_stsw_le, MEMSUFFIX) (int src) { int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(st32r, MEMSUFFIX)(T0, ugpr(src++)); + glue(st32r, MEMSUFFIX)((uint32_t)T0, ugpr(src++)); + if (unlikely(src == 32)) + src = 0; + } + if (unlikely(T1 != 0)) { + for (sh = 0; T1 > 0; T1--, T0++, sh += 8) + glue(stb, MEMSUFFIX)((uint32_t)T0, (ugpr(src) >> sh) & 0xFF); + } +} + +#if defined(TARGET_PPC64) +void glue(do_stsw_le_64, MEMSUFFIX) (int src) +{ + int sh; + + for (; T1 > 3; T1 -= 4, T0 += 4) { + glue(st32r, MEMSUFFIX)((uint64_t)T0, ugpr(src++)); if (unlikely(src == 32)) src = 0; } if (unlikely(T1 != 0)) { for (sh = 0; T1 > 0; T1--, T0++, sh += 8) - glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF); + glue(stb, MEMSUFFIX)((uint64_t)T0, (ugpr(src) >> sh) & 0xFF); } } +#endif /* PPC 601 specific instructions (POWER bridge) */ // XXX: to be tested @@ -139,7 +251,7 @@ void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb) d = 24; reg = dest; for (i = 0; i < T1; i++) { - c = glue(ldub, MEMSUFFIX)(T0++); + c = glue(ldub, MEMSUFFIX)((uint32_t)T0++); /* ra (if not 0) and rb are never modified */ if (likely(reg != rb && (ra == 0 || reg != ra))) { ugpr(reg) = (ugpr(reg) & ~(0xFF << d)) | (c << d); @@ -160,8 +272,8 @@ void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb) /* XXX: TAGs are not managed */ void glue(do_POWER2_lfq, MEMSUFFIX) (void) { - FT0 = glue(ldfq, MEMSUFFIX)(T0); - FT1 = glue(ldfq, MEMSUFFIX)(T0 + 4); + FT0 = glue(ldfq, MEMSUFFIX)((uint32_t)T0); + FT1 = glue(ldfq, MEMSUFFIX)((uint32_t)(T0 + 4)); } static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) @@ -186,14 +298,14 @@ static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) void glue(do_POWER2_lfq_le, MEMSUFFIX) (void) { - FT0 = glue(ldfqr, MEMSUFFIX)(T0 + 4); - FT1 = glue(ldfqr, MEMSUFFIX)(T0); + FT0 = glue(ldfqr, MEMSUFFIX)((uint32_t)(T0 + 4)); + FT1 = glue(ldfqr, MEMSUFFIX)((uint32_t)T0); } void glue(do_POWER2_stfq, MEMSUFFIX) (void) { - glue(stfq, MEMSUFFIX)(T0, FT0); - glue(stfq, MEMSUFFIX)(T0 + 4, FT1); + glue(stfq, MEMSUFFIX)((uint32_t)T0, FT0); + glue(stfq, MEMSUFFIX)((uint32_t)(T0 + 4), FT1); } static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) @@ -217,8 +329,8 @@ static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) void glue(do_POWER2_stfq_le, MEMSUFFIX) (void) { - glue(stfqr, MEMSUFFIX)(T0 + 4, FT0); - glue(stfqr, MEMSUFFIX)(T0, FT1); + glue(stfqr, MEMSUFFIX)((uint32_t)(T0 + 4), FT0); + glue(stfqr, MEMSUFFIX)((uint32_t)T0, FT1); } #undef MEMSUFFIX diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index a084b3194..8aa799f65 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -37,6 +37,33 @@ static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); } +#if defined(TARGET_PPC64) +static inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA) +{ + return (int32_t)glue(ldl, MEMSUFFIX)(EA); +} + +static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) +{ + uint64_t tmp = glue(ldq, MEMSUFFIX)(EA); + return ((tmp & 0xFF00000000000000ULL) >> 56) | + ((tmp & 0x00FF000000000000ULL) >> 40) | + ((tmp & 0x0000FF0000000000ULL) >> 24) | + ((tmp & 0x000000FF00000000ULL) >> 8) | + ((tmp & 0x00000000FF000000ULL) << 8) | + ((tmp & 0x0000000000FF0000ULL) << 24) | + ((tmp & 0x000000000000FF00ULL) << 40) | + ((tmp & 0x00000000000000FFULL) << 54); +} + +static inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA) +{ + uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); + return (int32_t)((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | + ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); +} +#endif + static inline void glue(st16r, MEMSUFFIX) (target_ulong EA, uint16_t data) { uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8); @@ -50,140 +77,328 @@ static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t data) glue(stl, MEMSUFFIX)(EA, tmp); } +#if defined(TARGET_PPC64) +static inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t data) +{ + uint64_t tmp = ((data & 0xFF00000000000000ULL) >> 56) | + ((data & 0x00FF000000000000ULL) >> 40) | + ((data & 0x0000FF0000000000ULL) >> 24) | + ((data & 0x000000FF00000000ULL) >> 8) | + ((data & 0x00000000FF000000ULL) << 8) | + ((data & 0x0000000000FF0000ULL) << 24) | + ((data & 0x000000000000FF00ULL) << 40) | + ((data & 0x00000000000000FFULL) << 56); + glue(stq, MEMSUFFIX)(EA, tmp); +} +#endif + /*** Integer load ***/ #define PPC_LD_OP(name, op) \ -PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ +void OPPROTO glue(glue(op_l, name), MEMSUFFIX) (void) \ { \ - T1 = glue(op, MEMSUFFIX)(T0); \ + T1 = glue(op, MEMSUFFIX)((uint32_t)T0); \ RETURN(); \ } +#if defined(TARGET_PPC64) +#define PPC_LD_OP_64(name, op) \ +void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void) \ +{ \ + T1 = glue(op, MEMSUFFIX)((uint64_t)T0); \ + RETURN(); \ +} +#endif + #define PPC_ST_OP(name, op) \ -PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ +void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \ { \ - glue(op, MEMSUFFIX)(T0, T1); \ + glue(op, MEMSUFFIX)((uint32_t)T0, T1); \ RETURN(); \ } +#if defined(TARGET_PPC64) +#define PPC_ST_OP_64(name, op) \ +void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void) \ +{ \ + glue(op, MEMSUFFIX)((uint64_t)T0, T1); \ + RETURN(); \ +} +#endif + PPC_LD_OP(bz, ldub); PPC_LD_OP(ha, ldsw); PPC_LD_OP(hz, lduw); PPC_LD_OP(wz, ldl); +#if defined(TARGET_PPC64) +PPC_LD_OP(d, ldq); +PPC_LD_OP(wa, ldsl); +PPC_LD_OP_64(d, ldq); +PPC_LD_OP_64(wa, ldsl); +PPC_LD_OP_64(bz, ldub); +PPC_LD_OP_64(ha, ldsw); +PPC_LD_OP_64(hz, lduw); +PPC_LD_OP_64(wz, ldl); +#endif PPC_LD_OP(ha_le, ld16rs); PPC_LD_OP(hz_le, ld16r); PPC_LD_OP(wz_le, ld32r); +#if defined(TARGET_PPC64) +PPC_LD_OP(d_le, ld64r); +PPC_LD_OP(wa_le, ld32rs); +PPC_LD_OP_64(d_le, ld64r); +PPC_LD_OP_64(wa_le, ld32rs); +PPC_LD_OP_64(ha_le, ld16rs); +PPC_LD_OP_64(hz_le, ld16r); +PPC_LD_OP_64(wz_le, ld32r); +#endif /*** Integer store ***/ PPC_ST_OP(b, stb); PPC_ST_OP(h, stw); PPC_ST_OP(w, stl); +#if defined(TARGET_PPC64) +PPC_ST_OP(d, stq); +PPC_ST_OP_64(d, stq); +PPC_ST_OP_64(b, stb); +PPC_ST_OP_64(h, stw); +PPC_ST_OP_64(w, stl); +#endif PPC_ST_OP(h_le, st16r); PPC_ST_OP(w_le, st32r); +#if defined(TARGET_PPC64) +PPC_ST_OP(d_le, st64r); +PPC_ST_OP_64(d_le, st64r); +PPC_ST_OP_64(h_le, st16r); +PPC_ST_OP_64(w_le, st32r); +#endif /*** Integer load and store with byte reverse ***/ PPC_LD_OP(hbr, ld16r); PPC_LD_OP(wbr, ld32r); PPC_ST_OP(hbr, st16r); PPC_ST_OP(wbr, st32r); +#if defined(TARGET_PPC64) +PPC_LD_OP_64(hbr, ld16r); +PPC_LD_OP_64(wbr, ld32r); +PPC_ST_OP_64(hbr, st16r); +PPC_ST_OP_64(wbr, st32r); +#endif PPC_LD_OP(hbr_le, lduw); PPC_LD_OP(wbr_le, ldl); PPC_ST_OP(hbr_le, stw); PPC_ST_OP(wbr_le, stl); +#if defined(TARGET_PPC64) +PPC_LD_OP_64(hbr_le, lduw); +PPC_LD_OP_64(wbr_le, ldl); +PPC_ST_OP_64(hbr_le, stw); +PPC_ST_OP_64(wbr_le, stl); +#endif /*** Integer load and store multiple ***/ -PPC_OP(glue(lmw, MEMSUFFIX)) +void OPPROTO glue(op_lmw, MEMSUFFIX) (void) { glue(do_lmw, MEMSUFFIX)(PARAM1); RETURN(); } -PPC_OP(glue(lmw_le, MEMSUFFIX)) +#if defined(TARGET_PPC64) +void OPPROTO glue(op_lmw_64, MEMSUFFIX) (void) +{ + glue(do_lmw_64, MEMSUFFIX)(PARAM1); + RETURN(); +} +#endif + +void OPPROTO glue(op_lmw_le, MEMSUFFIX) (void) { glue(do_lmw_le, MEMSUFFIX)(PARAM1); RETURN(); } -PPC_OP(glue(stmw, MEMSUFFIX)) +#if defined(TARGET_PPC64) +void OPPROTO glue(op_lmw_le_64, MEMSUFFIX) (void) +{ + glue(do_lmw_le_64, MEMSUFFIX)(PARAM1); + RETURN(); +} +#endif + +void OPPROTO glue(op_stmw, MEMSUFFIX) (void) { glue(do_stmw, MEMSUFFIX)(PARAM1); RETURN(); } -PPC_OP(glue(stmw_le, MEMSUFFIX)) +#if defined(TARGET_PPC64) +void OPPROTO glue(op_stmw_64, MEMSUFFIX) (void) +{ + glue(do_stmw_64, MEMSUFFIX)(PARAM1); + RETURN(); +} +#endif + +void OPPROTO glue(op_stmw_le, MEMSUFFIX) (void) { glue(do_stmw_le, MEMSUFFIX)(PARAM1); RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO glue(op_stmw_le_64, MEMSUFFIX) (void) +{ + glue(do_stmw_le_64, MEMSUFFIX)(PARAM1); + RETURN(); +} +#endif + /*** Integer load and store strings ***/ -PPC_OP(glue(lswi, MEMSUFFIX)) +void OPPROTO glue(op_lswi, MEMSUFFIX) (void) +{ + glue(do_lsw, MEMSUFFIX)(PARAM1); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_lswi_64, MEMSUFFIX) (void) { - glue(do_lsw, MEMSUFFIX)(PARAM(1)); + glue(do_lsw_64, MEMSUFFIX)(PARAM1); RETURN(); } +#endif -PPC_OP(glue(lswi_le, MEMSUFFIX)) +void OPPROTO glue(op_lswi_le, MEMSUFFIX) (void) { - glue(do_lsw_le, MEMSUFFIX)(PARAM(1)); + glue(do_lsw_le, MEMSUFFIX)(PARAM1); RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO glue(op_lswi_le_64, MEMSUFFIX) (void) +{ + glue(do_lsw_le_64, MEMSUFFIX)(PARAM1); + RETURN(); +} +#endif + /* PPC32 specification says we must generate an exception if * rA is in the range of registers to be loaded. * In an other hand, IBM says this is valid, but rA won't be loaded. * For now, I'll follow the spec... */ -PPC_OP(glue(lswx, MEMSUFFIX)) +void OPPROTO glue(op_lswx, MEMSUFFIX) (void) +{ + /* Note: T1 comes from xer_bc then no cast is needed */ + if (likely(T1 != 0)) { + if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || + (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + } else { + glue(do_lsw, MEMSUFFIX)(PARAM1); + } + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_lswx_64, MEMSUFFIX) (void) +{ + /* Note: T1 comes from xer_bc then no cast is needed */ + if (likely(T1 != 0)) { + if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || + (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + } else { + glue(do_lsw_64, MEMSUFFIX)(PARAM1); + } + } + RETURN(); +} +#endif + +void OPPROTO glue(op_lswx_le, MEMSUFFIX) (void) { - if (unlikely(T1 > 0)) { + /* Note: T1 comes from xer_bc then no cast is needed */ + if (likely(T1 != 0)) { if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); } else { - glue(do_lsw, MEMSUFFIX)(PARAM(1)); + glue(do_lsw_le, MEMSUFFIX)(PARAM1); } } RETURN(); } -PPC_OP(glue(lswx_le, MEMSUFFIX)) +#if defined(TARGET_PPC64) +void OPPROTO glue(op_lswx_le_64, MEMSUFFIX) (void) { - if (unlikely(T1 > 0)) { + /* Note: T1 comes from xer_bc then no cast is needed */ + if (likely(T1 != 0)) { if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); } else { - glue(do_lsw_le, MEMSUFFIX)(PARAM(1)); + glue(do_lsw_le_64, MEMSUFFIX)(PARAM1); } } RETURN(); } +#endif + +void OPPROTO glue(op_stsw, MEMSUFFIX) (void) +{ + glue(do_stsw, MEMSUFFIX)(PARAM1); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_stsw_64, MEMSUFFIX) (void) +{ + glue(do_stsw_64, MEMSUFFIX)(PARAM1); + RETURN(); +} +#endif -PPC_OP(glue(stsw, MEMSUFFIX)) +void OPPROTO glue(op_stsw_le, MEMSUFFIX) (void) { - glue(do_stsw, MEMSUFFIX)(PARAM(1)); + glue(do_stsw_le, MEMSUFFIX)(PARAM1); RETURN(); } -PPC_OP(glue(stsw_le, MEMSUFFIX)) +#if defined(TARGET_PPC64) +void OPPROTO glue(op_stsw_le_64, MEMSUFFIX) (void) { - glue(do_stsw_le, MEMSUFFIX)(PARAM(1)); + glue(do_stsw_le_64, MEMSUFFIX)(PARAM1); RETURN(); } +#endif /*** Floating-point store ***/ #define PPC_STF_OP(name, op) \ -PPC_OP(glue(glue(st, name), MEMSUFFIX)) \ +void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \ +{ \ + glue(op, MEMSUFFIX)((uint32_t)T0, FT0); \ + RETURN(); \ +} + +#if defined(TARGET_PPC64) +#define PPC_STF_OP_64(name, op) \ +void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void) \ { \ - glue(op, MEMSUFFIX)(T0, FT0); \ + glue(op, MEMSUFFIX)((uint64_t)T0, FT0); \ RETURN(); \ } +#endif PPC_STF_OP(fd, stfq); PPC_STF_OP(fs, stfl); +#if defined(TARGET_PPC64) +PPC_STF_OP_64(fd, stfq); +PPC_STF_OP_64(fs, stfl); +#endif static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) { @@ -221,17 +436,34 @@ static inline void glue(stflr, MEMSUFFIX) (target_ulong EA, float f) PPC_STF_OP(fd_le, stfqr); PPC_STF_OP(fs_le, stflr); +#if defined(TARGET_PPC64) +PPC_STF_OP_64(fd_le, stfqr); +PPC_STF_OP_64(fs_le, stflr); +#endif /*** Floating-point load ***/ #define PPC_LDF_OP(name, op) \ -PPC_OP(glue(glue(l, name), MEMSUFFIX)) \ +void OPPROTO glue(glue(op_l, name), MEMSUFFIX) (void) \ +{ \ + FT0 = glue(op, MEMSUFFIX)((uint32_t)T0); \ + RETURN(); \ +} + +#if defined(TARGET_PPC64) +#define PPC_LDF_OP_64(name, op) \ +void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void) \ { \ - FT0 = glue(op, MEMSUFFIX)(T0); \ + FT0 = glue(op, MEMSUFFIX)((uint64_t)T0); \ RETURN(); \ } +#endif PPC_LDF_OP(fd, ldfq); PPC_LDF_OP(fs, ldfl); +#if defined(TARGET_PPC64) +PPC_LDF_OP_64(fd, ldfq); +PPC_LDF_OP_64(fs, ldfl); +#endif static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) { @@ -271,40 +503,142 @@ static inline float glue(ldflr, MEMSUFFIX) (target_ulong EA) PPC_LDF_OP(fd_le, ldfqr); PPC_LDF_OP(fs_le, ldflr); +#if defined(TARGET_PPC64) +PPC_LDF_OP_64(fd_le, ldfqr); +PPC_LDF_OP_64(fs_le, ldflr); +#endif /* Load and set reservation */ -PPC_OP(glue(lwarx, MEMSUFFIX)) +void OPPROTO glue(op_lwarx, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0); + regs->reserve = (uint32_t)T0; + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0); + regs->reserve = (uint64_t)T0; + } + RETURN(); +} + +void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + T1 = glue(ldq, MEMSUFFIX)((uint64_t)T0); + regs->reserve = (uint64_t)T0; + } + RETURN(); +} +#endif + +void OPPROTO glue(op_lwarx_le, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0); + regs->reserve = (uint32_t)T0; + } + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - T1 = glue(ldl, MEMSUFFIX)(T0); - regs->reserve = T0; + T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0); + regs->reserve = (uint64_t)T0; } RETURN(); } -PPC_OP(glue(lwarx_le, MEMSUFFIX)) +void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - T1 = glue(ld32r, MEMSUFFIX)(T0); - regs->reserve = T0; + T1 = glue(ld64r, MEMSUFFIX)((uint64_t)T0); + regs->reserve = (uint64_t)T0; } RETURN(); } +#endif /* Store with reservation */ -PPC_OP(glue(stwcx, MEMSUFFIX)) +void OPPROTO glue(op_stwcx, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + if (unlikely(regs->reserve != (uint32_t)T0)) { + env->crf[0] = xer_ov; + } else { + glue(stl, MEMSUFFIX)((uint32_t)T0, T1); + env->crf[0] = xer_ov | 0x02; + } + } + regs->reserve = -1; + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + if (unlikely(regs->reserve != (uint64_t)T0)) { + env->crf[0] = xer_ov; + } else { + glue(stl, MEMSUFFIX)((uint64_t)T0, T1); + env->crf[0] = xer_ov | 0x02; + } + } + regs->reserve = -1; + RETURN(); +} + +void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != T0)) { + if (unlikely(regs->reserve != (uint64_t)T0)) { env->crf[0] = xer_ov; } else { - glue(stl, MEMSUFFIX)(T0, T1); + glue(stq, MEMSUFFIX)((uint64_t)T0, T1); + env->crf[0] = xer_ov | 0x02; + } + } + regs->reserve = -1; + RETURN(); +} +#endif + +void OPPROTO glue(op_stwcx_le, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + if (unlikely(regs->reserve != (uint32_t)T0)) { + env->crf[0] = xer_ov; + } else { + glue(st32r, MEMSUFFIX)((uint32_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } @@ -312,15 +646,16 @@ PPC_OP(glue(stwcx, MEMSUFFIX)) RETURN(); } -PPC_OP(glue(stwcx_le, MEMSUFFIX)) +#if defined(TARGET_PPC64) +void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != T0)) { + if (unlikely(regs->reserve != (uint64_t)T0)) { env->crf[0] = xer_ov; } else { - glue(st32r, MEMSUFFIX)(T0, T1); + glue(st32r, MEMSUFFIX)((uint64_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } @@ -328,61 +663,136 @@ PPC_OP(glue(stwcx_le, MEMSUFFIX)) RETURN(); } -PPC_OP(glue(dcbz, MEMSUFFIX)) +void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + if (unlikely(regs->reserve != (uint64_t)T0)) { + env->crf[0] = xer_ov; + } else { + glue(st64r, MEMSUFFIX)((uint64_t)T0, T1); + env->crf[0] = xer_ov | 0x02; + } + } + regs->reserve = -1; + RETURN(); +} +#endif + +void OPPROTO glue(op_dcbz, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); +#if DCACHE_LINE_SIZE == 64 + /* XXX: cache line size should be 64 for POWER & PowerPC 601 */ + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0); +#endif + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_dcbz_64, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)(T0 + 0x00, 0); - glue(stl, MEMSUFFIX)(T0 + 0x04, 0); - glue(stl, MEMSUFFIX)(T0 + 0x08, 0); - glue(stl, MEMSUFFIX)(T0 + 0x0C, 0); - glue(stl, MEMSUFFIX)(T0 + 0x10, 0); - glue(stl, MEMSUFFIX)(T0 + 0x14, 0); - glue(stl, MEMSUFFIX)(T0 + 0x18, 0); - glue(stl, MEMSUFFIX)(T0 + 0x1C, 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); #if DCACHE_LINE_SIZE == 64 /* XXX: cache line size should be 64 for POWER & PowerPC 601 */ - glue(stl, MEMSUFFIX)(T0 + 0x20UL, 0); - glue(stl, MEMSUFFIX)(T0 + 0x24UL, 0); - glue(stl, MEMSUFFIX)(T0 + 0x28UL, 0); - glue(stl, MEMSUFFIX)(T0 + 0x2CUL, 0); - glue(stl, MEMSUFFIX)(T0 + 0x30UL, 0); - glue(stl, MEMSUFFIX)(T0 + 0x34UL, 0); - glue(stl, MEMSUFFIX)(T0 + 0x38UL, 0); - glue(stl, MEMSUFFIX)(T0 + 0x3CUL, 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0); #endif RETURN(); } +#endif /* External access */ -PPC_OP(glue(eciwx, MEMSUFFIX)) +void OPPROTO glue(op_eciwx, MEMSUFFIX) (void) +{ + T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_eciwx_64, MEMSUFFIX) (void) +{ + T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0); + RETURN(); +} +#endif + +void OPPROTO glue(op_ecowx, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)((uint32_t)T0, T1); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_ecowx_64, MEMSUFFIX) (void) { - T1 = glue(ldl, MEMSUFFIX)(T0); + glue(stl, MEMSUFFIX)((uint64_t)T0, T1); RETURN(); } +#endif -PPC_OP(glue(ecowx, MEMSUFFIX)) +void OPPROTO glue(op_eciwx_le, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)(T0, T1); + T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0); RETURN(); } -PPC_OP(glue(eciwx_le, MEMSUFFIX)) +#if defined(TARGET_PPC64) +void OPPROTO glue(op_eciwx_le_64, MEMSUFFIX) (void) { - T1 = glue(ld32r, MEMSUFFIX)(T0); + T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0); RETURN(); } +#endif -PPC_OP(glue(ecowx_le, MEMSUFFIX)) +void OPPROTO glue(op_ecowx_le, MEMSUFFIX) (void) { - glue(st32r, MEMSUFFIX)(T0, T1); + glue(st32r, MEMSUFFIX)((uint32_t)T0, T1); RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO glue(op_ecowx_le_64, MEMSUFFIX) (void) +{ + glue(st32r, MEMSUFFIX)((uint64_t)T0, T1); + RETURN(); +} +#endif + /* XXX: those micro-ops need tests ! */ /* PowerPC 601 specific instructions (POWER bridge) */ void OPPROTO glue(op_POWER_lscbx, MEMSUFFIX) (void) { /* When byte count is 0, do nothing */ - if (likely(T1 > 0)) { + if (likely(T1 != 0)) { glue(do_POWER_lscbx, MEMSUFFIX)(PARAM1, PARAM2, PARAM3); } RETURN(); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1e6c9cb8d..e5c281293 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -31,7 +31,7 @@ //#define PPC_DEBUG_DISAS //#define DO_PPC_STATISTICS -#ifdef USE_DIRECT_JUMP +#if defined(USE_DIRECT_JUMP) #define TBPARAM(x) #else #define TBPARAM(x) (long)(x) @@ -49,7 +49,27 @@ static uint32_t *gen_opparam_ptr; #include "gen-op.h" -#define GEN8(func, NAME) \ +static inline void gen_set_T0 (target_ulong val) +{ +#if defined(TARGET_PPC64) + if (val >> 32) + gen_op_set_T0_64(val >> 32, val); + else +#endif + gen_op_set_T0(val); +} + +static inline void gen_set_T1 (target_ulong val) +{ +#if defined(TARGET_PPC64) + if (val >> 32) + gen_op_set_T1_64(val >> 32, val); + else +#endif + gen_op_set_T1(val); +} + +#define GEN8(func, NAME) \ static GenOpFunc *NAME ## _table [8] = { \ NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ @@ -71,7 +91,7 @@ static inline void func(int n) \ NAME ## _table[n](); \ } -#define GEN32(func, NAME) \ +#define GEN32(func, NAME) \ static GenOpFunc *NAME ## _table [32] = { \ NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ @@ -135,6 +155,9 @@ typedef struct DisasContext { /* Translation flags */ #if !defined(CONFIG_USER_ONLY) int supervisor; +#endif +#if defined(TARGET_PPC64) + int sf_mode; #endif int fpu_enabled; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ @@ -156,14 +179,29 @@ struct opc_handler_t { static inline void gen_set_Rc0 (DisasContext *ctx) { - gen_op_cmpi(0); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_cmpi_64(0); + else +#endif + gen_op_cmpi(0); gen_op_set_Rc0(); } +static inline void gen_update_nip (DisasContext *ctx, target_ulong nip) +{ +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_update_nip_64(nip >> 32, nip); + else +#endif + gen_op_update_nip(nip); +} + #define RET_EXCP(ctx, excp, error) \ do { \ if ((ctx)->exception == EXCP_NONE) { \ - gen_op_update_nip((ctx)->nip); \ + gen_update_nip(ctx, (ctx)->nip); \ } \ gen_op_raise_exception_err((excp), (error)); \ ctx->exception = (excp); \ @@ -181,7 +219,7 @@ RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) /* Stop translation */ static inline void RET_STOP (DisasContext *ctx) { - gen_op_update_nip((ctx)->nip); + gen_update_nip(ctx, ctx->nip); ctx->exception = EXCP_MTMSR; } @@ -209,13 +247,13 @@ typedef struct opcode_t { /*** Instruction decoding ***/ #define EXTRACT_HELPER(name, shift, nb) \ -static inline target_ulong name (uint32_t opcode) \ +static inline uint32_t name (uint32_t opcode) \ { \ return (opcode >> (shift)) & ((1 << (nb)) - 1); \ } #define EXTRACT_SHELPER(name, shift, nb) \ -static inline target_long name (uint32_t opcode) \ +static inline int32_t name (uint32_t opcode) \ { \ return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \ } @@ -329,10 +367,10 @@ static inline target_ulong MASK (uint32_t start, uint32_t end) #define OPC_ALIGN 4 #endif #if defined(__APPLE__) -#define OPCODES_SECTION \ +#define OPCODES_SECTION \ __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) )) #else -#define OPCODES_SECTION \ +#define OPCODES_SECTION \ __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) )) #endif @@ -397,8 +435,8 @@ static opc_handler_t invalid_handler = { }; /*** Integer arithmetic ***/ -#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval) \ -GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ +#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval, type) \ +GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -408,8 +446,8 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ gen_set_Rc0(ctx); \ } -#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \ -GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ +#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval, type) \ +GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -419,8 +457,8 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ gen_set_Rc0(ctx); \ } -#define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \ -GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ +#define __GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \ +GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_##name(); \ @@ -428,8 +466,8 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ if (unlikely(Rc(ctx->opcode) != 0)) \ gen_set_Rc0(ctx); \ } -#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \ -GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ +#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3, type) \ +GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_##name(); \ @@ -439,51 +477,277 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ } /* Two operands arithmetic functions */ -#define GEN_INT_ARITH2(name, opc1, opc2, opc3) \ -__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000) \ -__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000) +#define GEN_INT_ARITH2(name, opc1, opc2, opc3, type) \ +__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000, type) \ +__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type) + +/* Two operands arithmetic functions with no overflow allowed */ +#define GEN_INT_ARITHN(name, opc1, opc2, opc3, type) \ +__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400, type) + +/* One operand arithmetic functions */ +#define GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \ +__GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \ +__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10, type) + +#if defined(TARGET_PPC64) +#define __GEN_INT_ARITH2_64(name, opc1, opc2, opc3, inval, type) \ +GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + if (ctx->sf_mode) \ + gen_op_##name##_64(); \ + else \ + gen_op_##name(); \ + gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ +} + +#define __GEN_INT_ARITH2_O_64(name, opc1, opc2, opc3, inval, type) \ +GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + if (ctx->sf_mode) \ + gen_op_##name##_64(); \ + else \ + gen_op_##name(); \ + gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ +} + +#define __GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \ +GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + if (ctx->sf_mode) \ + gen_op_##name##_64(); \ + else \ + gen_op_##name(); \ + gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ +} +#define __GEN_INT_ARITH1_O_64(name, opc1, opc2, opc3, type) \ +GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + if (ctx->sf_mode) \ + gen_op_##name##_64(); \ + else \ + gen_op_##name(); \ + gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ +} + +/* Two operands arithmetic functions */ +#define GEN_INT_ARITH2_64(name, opc1, opc2, opc3, type) \ +__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000000, type) \ +__GEN_INT_ARITH2_O_64(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type) /* Two operands arithmetic functions with no overflow allowed */ -#define GEN_INT_ARITHN(name, opc1, opc2, opc3) \ -__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400) +#define GEN_INT_ARITHN_64(name, opc1, opc2, opc3, type) \ +__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000400, type) /* One operand arithmetic functions */ -#define GEN_INT_ARITH1(name, opc1, opc2, opc3) \ -__GEN_INT_ARITH1(name, opc1, opc2, opc3) \ -__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10) +#define GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \ +__GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \ +__GEN_INT_ARITH1_O_64(name##o, opc1, opc2, opc3 | 0x10, type) +#else +#define GEN_INT_ARITH2_64 GEN_INT_ARITH2 +#define GEN_INT_ARITHN_64 GEN_INT_ARITHN +#define GEN_INT_ARITH1_64 GEN_INT_ARITH1 +#endif /* add add. addo addo. */ -GEN_INT_ARITH2 (add, 0x1F, 0x0A, 0x08); +static inline void gen_op_addo (void) +{ + gen_op_move_T2_T0(); + gen_op_add(); + gen_op_check_addo(); +} +#if defined(TARGET_PPC64) +#define gen_op_add_64 gen_op_add +static inline void gen_op_addo_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_add(); + gen_op_check_addo_64(); +} +#endif +GEN_INT_ARITH2_64 (add, 0x1F, 0x0A, 0x08, PPC_INTEGER); /* addc addc. addco addco. */ -GEN_INT_ARITH2 (addc, 0x1F, 0x0A, 0x00); +static inline void gen_op_addc (void) +{ + gen_op_move_T2_T0(); + gen_op_add(); + gen_op_check_addc(); +} +static inline void gen_op_addco (void) +{ + gen_op_move_T2_T0(); + gen_op_add(); + gen_op_check_addc(); + gen_op_check_addo(); +} +#if defined(TARGET_PPC64) +static inline void gen_op_addc_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_add(); + gen_op_check_addc_64(); +} +static inline void gen_op_addco_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_add(); + gen_op_check_addc_64(); + gen_op_check_addo_64(); +} +#endif +GEN_INT_ARITH2_64 (addc, 0x1F, 0x0A, 0x00, PPC_INTEGER); /* adde adde. addeo addeo. */ -GEN_INT_ARITH2 (adde, 0x1F, 0x0A, 0x04); +static inline void gen_op_addeo (void) +{ + gen_op_move_T2_T0(); + gen_op_adde(); + gen_op_check_addo(); +} +#if defined(TARGET_PPC64) +static inline void gen_op_addeo_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_adde_64(); + gen_op_check_addo_64(); +} +#endif +GEN_INT_ARITH2_64 (adde, 0x1F, 0x0A, 0x04, PPC_INTEGER); /* addme addme. addmeo addmeo. */ -GEN_INT_ARITH1 (addme, 0x1F, 0x0A, 0x07); +static inline void gen_op_addme (void) +{ + gen_op_move_T1_T0(); + gen_op_add_me(); +} +#if defined(TARGET_PPC64) +static inline void gen_op_addme_64 (void) +{ + gen_op_move_T1_T0(); + gen_op_add_me_64(); +} +#endif +GEN_INT_ARITH1_64 (addme, 0x1F, 0x0A, 0x07, PPC_INTEGER); /* addze addze. addzeo addzeo. */ -GEN_INT_ARITH1 (addze, 0x1F, 0x0A, 0x06); +static inline void gen_op_addze (void) +{ + gen_op_move_T2_T0(); + gen_op_add_ze(); + gen_op_check_addc(); +} +static inline void gen_op_addzeo (void) +{ + gen_op_move_T2_T0(); + gen_op_add_ze(); + gen_op_check_addc(); + gen_op_check_addo(); +} +#if defined(TARGET_PPC64) +static inline void gen_op_addze_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_add_ze(); + gen_op_check_addc_64(); +} +static inline void gen_op_addzeo_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_add_ze(); + gen_op_check_addc_64(); + gen_op_check_addo_64(); +} +#endif +GEN_INT_ARITH1_64 (addze, 0x1F, 0x0A, 0x06, PPC_INTEGER); /* divw divw. divwo divwo. */ -GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F); +GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F, PPC_INTEGER); /* divwu divwu. divwuo divwuo. */ -GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E); +GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E, PPC_INTEGER); /* mulhw mulhw. */ -GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02); +GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02, PPC_INTEGER); /* mulhwu mulhwu. */ -GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00); +GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00, PPC_INTEGER); /* mullw mullw. mullwo mullwo. */ -GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07); +GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07, PPC_INTEGER); /* neg neg. nego nego. */ -GEN_INT_ARITH1 (neg, 0x1F, 0x08, 0x03); +GEN_INT_ARITH1_64 (neg, 0x1F, 0x08, 0x03, PPC_INTEGER); /* subf subf. subfo subfo. */ -GEN_INT_ARITH2 (subf, 0x1F, 0x08, 0x01); +static inline void gen_op_subfo (void) +{ + gen_op_move_T2_T0(); + gen_op_subf(); + gen_op_check_subfo(); +} +#if defined(TARGET_PPC64) +#define gen_op_subf_64 gen_op_subf +static inline void gen_op_subfo_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_subf(); + gen_op_check_subfo_64(); +} +#endif +GEN_INT_ARITH2_64 (subf, 0x1F, 0x08, 0x01, PPC_INTEGER); /* subfc subfc. subfco subfco. */ -GEN_INT_ARITH2 (subfc, 0x1F, 0x08, 0x00); +static inline void gen_op_subfc (void) +{ + gen_op_subf(); + gen_op_check_subfc(); +} +static inline void gen_op_subfco (void) +{ + gen_op_move_T2_T0(); + gen_op_subf(); + gen_op_check_subfc(); + gen_op_check_subfo(); +} +#if defined(TARGET_PPC64) +static inline void gen_op_subfc_64 (void) +{ + gen_op_subf(); + gen_op_check_subfc_64(); +} +static inline void gen_op_subfco_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_subf(); + gen_op_check_subfc_64(); + gen_op_check_subfo_64(); +} +#endif +GEN_INT_ARITH2_64 (subfc, 0x1F, 0x08, 0x00, PPC_INTEGER); /* subfe subfe. subfeo subfeo. */ -GEN_INT_ARITH2 (subfe, 0x1F, 0x08, 0x04); +static inline void gen_op_subfeo (void) +{ + gen_op_move_T2_T0(); + gen_op_subfe(); + gen_op_check_subfo(); +} +#if defined(TARGET_PPC64) +#define gen_op_subfe_64 gen_op_subfe +static inline void gen_op_subfeo_64 (void) +{ + gen_op_move_T2_T0(); + gen_op_subfe_64(); + gen_op_check_subfo_64(); +} +#endif +GEN_INT_ARITH2_64 (subfe, 0x1F, 0x08, 0x04, PPC_INTEGER); /* subfme subfme. subfmeo subfmeo. */ -GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07); +GEN_INT_ARITH1_64 (subfme, 0x1F, 0x08, 0x07, PPC_INTEGER); /* subfze subfze. subfzeo subfzeo. */ -GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06); +GEN_INT_ARITH1_64 (subfze, 0x1F, 0x08, 0x06, PPC_INTEGER); /* addi */ GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { @@ -491,7 +755,7 @@ GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) if (rA(ctx->opcode) == 0) { /* li case */ - gen_op_set_T0(simm); + gen_set_T0(simm); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); if (likely(simm != 0)) @@ -505,8 +769,16 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) target_long simm = SIMM(ctx->opcode); gen_op_load_gpr_T0(rA(ctx->opcode)); - if (likely(simm != 0)) - gen_op_addic(SIMM(ctx->opcode)); + if (likely(simm != 0)) { + gen_op_move_T2_T0(); + gen_op_addi(simm); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_check_addc_64(); + else +#endif + gen_op_check_addc(); + } gen_op_store_T0_gpr(rD(ctx->opcode)); } /* addic. */ @@ -515,8 +787,16 @@ GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) target_long simm = SIMM(ctx->opcode); gen_op_load_gpr_T0(rA(ctx->opcode)); - if (likely(simm != 0)) - gen_op_addic(SIMM(ctx->opcode)); + if (likely(simm != 0)) { + gen_op_move_T2_T0(); + gen_op_addi(simm); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_check_addc_64(); + else +#endif + gen_op_check_addc(); + } gen_op_store_T0_gpr(rD(ctx->opcode)); gen_set_Rc0(ctx); } @@ -527,7 +807,7 @@ GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) if (rA(ctx->opcode) == 0) { /* lis case */ - gen_op_set_T0(simm << 16); + gen_set_T0(simm << 16); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); if (likely(simm != 0)) @@ -546,42 +826,103 @@ GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_subfic(SIMM(ctx->opcode)); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_subfic_64(SIMM(ctx->opcode)); + else +#endif + gen_op_subfic(SIMM(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); } +#if defined(TARGET_PPC64) +/* mulhd mulhd. */ +GEN_INT_ARITHN (mulhd, 0x1F, 0x09, 0x02, PPC_INTEGER); +/* mulhdu mulhdu. */ +GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_INTEGER); +/* mulld mulld. mulldo mulldo. */ +GEN_INT_ARITH2 (mulld, 0x1F, 0x09, 0x07, PPC_INTEGER); +/* divd divd. divdo divdo. */ +GEN_INT_ARITH2 (divd, 0x1F, 0x09, 0x0F, PPC_INTEGER); +/* divdu divdu. divduo divduo. */ +GEN_INT_ARITH2 (divdu, 0x1F, 0x09, 0x0E, PPC_INTEGER); +#endif + /*** Integer comparison ***/ -#define GEN_CMP(name, opc) \ -GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \ +#if defined(TARGET_PPC64) +#define GEN_CMP(name, opc, type) \ +GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \ +{ \ + gen_op_load_gpr_T0(rA(ctx->opcode)); \ + gen_op_load_gpr_T1(rB(ctx->opcode)); \ + if (ctx->sf_mode) \ + gen_op_##name##_64(); \ + else \ + gen_op_##name(); \ + gen_op_store_T0_crf(crfD(ctx->opcode)); \ +} +#else +#define GEN_CMP(name, opc, type) \ +GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ gen_op_store_T0_crf(crfD(ctx->opcode)); \ } +#endif /* cmp */ -GEN_CMP(cmp, 0x00); +GEN_CMP(cmp, 0x00, PPC_INTEGER); /* cmpi */ GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) { gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_cmpi(SIMM(ctx->opcode)); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_cmpi_64(SIMM(ctx->opcode)); + else +#endif + gen_op_cmpi(SIMM(ctx->opcode)); gen_op_store_T0_crf(crfD(ctx->opcode)); } /* cmpl */ -GEN_CMP(cmpl, 0x01); +GEN_CMP(cmpl, 0x01, PPC_INTEGER); /* cmpli */ GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) { gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_cmpli(UIMM(ctx->opcode)); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_cmpli_64(UIMM(ctx->opcode)); + else +#endif + gen_op_cmpli(UIMM(ctx->opcode)); gen_op_store_T0_crf(crfD(ctx->opcode)); } +/* isel (PowerPC 2.03 specification) */ +GEN_HANDLER(isel, 0x1F, 0x0F, 0x00, 0x00000001, PPC_203) +{ + uint32_t bi = rC(ctx->opcode); + uint32_t mask; + + if (rA(ctx->opcode) == 0) { + gen_set_T0(0); + } else { + gen_op_load_gpr_T1(rA(ctx->opcode)); + } + gen_op_load_gpr_T2(rB(ctx->opcode)); + mask = 1 << (3 - (bi & 0x03)); + gen_op_load_crf_T0(bi >> 2); + gen_op_test_true(mask); + gen_op_isel(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +} + /*** Integer logical ***/ -#define __GEN_LOGICAL2(name, opc2, opc3) \ -GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \ +#define __GEN_LOGICAL2(name, opc2, opc3, type) \ +GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, type) \ { \ gen_op_load_gpr_T0(rS(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ @@ -590,11 +931,11 @@ GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \ if (unlikely(Rc(ctx->opcode) != 0)) \ gen_set_Rc0(ctx); \ } -#define GEN_LOGICAL2(name, opc) \ -__GEN_LOGICAL2(name, 0x1C, opc) +#define GEN_LOGICAL2(name, opc, type) \ +__GEN_LOGICAL2(name, 0x1C, opc, type) -#define GEN_LOGICAL1(name, opc) \ -GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \ +#define GEN_LOGICAL1(name, opc, type) \ +GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type) \ { \ gen_op_load_gpr_T0(rS(ctx->opcode)); \ gen_op_##name(); \ @@ -604,9 +945,9 @@ GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \ } /* and & and. */ -GEN_LOGICAL2(and, 0x00); +GEN_LOGICAL2(and, 0x00, PPC_INTEGER); /* andc & andc. */ -GEN_LOGICAL2(andc, 0x01); +GEN_LOGICAL2(andc, 0x01, PPC_INTEGER); /* andi. */ GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { @@ -625,17 +966,17 @@ GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) } /* cntlzw */ -GEN_LOGICAL1(cntlzw, 0x00); +GEN_LOGICAL1(cntlzw, 0x00, PPC_INTEGER); /* eqv & eqv. */ -GEN_LOGICAL2(eqv, 0x08); +GEN_LOGICAL2(eqv, 0x08, PPC_INTEGER); /* extsb & extsb. */ -GEN_LOGICAL1(extsb, 0x1D); +GEN_LOGICAL1(extsb, 0x1D, PPC_INTEGER); /* extsh & extsh. */ -GEN_LOGICAL1(extsh, 0x1C); +GEN_LOGICAL1(extsh, 0x1C, PPC_INTEGER); /* nand & nand. */ -GEN_LOGICAL2(nand, 0x0E); +GEN_LOGICAL2(nand, 0x0E, PPC_INTEGER); /* nor & nor. */ -GEN_LOGICAL2(nor, 0x03); +GEN_LOGICAL2(nor, 0x03, PPC_INTEGER); /* or & or. */ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) @@ -662,7 +1003,7 @@ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) } /* orc & orc. */ -GEN_LOGICAL2(orc, 0x0C); +GEN_LOGICAL2(orc, 0x0C, PPC_INTEGER); /* xor & xor. */ GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER) { @@ -737,6 +1078,26 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_store_T0_gpr(rA(ctx->opcode)); } +/* popcntb : PowerPC 2.03 specification */ +GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_203) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_popcntb_64(); + else +#endif + gen_op_popcntb(); + gen_op_store_T0_gpr(rA(ctx->opcode)); +} + +#if defined(TARGET_PPC64) +/* extsw & extsw. */ +GEN_LOGICAL1(extsw, 0x1E, PPC_64B); +/* cntlzd */ +GEN_LOGICAL1(cntlzd, 0x01, PPC_64B); +#endif + /*** Integer rotate ***/ /* rlwimi & rlwimi. */ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -838,23 +1199,161 @@ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_set_Rc0(ctx); } +#if defined(TARGET_PPC64) +#define GEN_PPC64_R2(name, opc1, opc2) \ +GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B) \ +{ \ + gen_##name(ctx, 0); \ +} \ +GEN_HANDLER(name##1, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B) \ +{ \ + gen_##name(ctx, 1); \ +} +#define GEN_PPC64_R4(name, opc1, opc2) \ +GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B) \ +{ \ + gen_##name(ctx, 0, 0); \ +} \ +GEN_HANDLER(name##1, opc1, opc2 | 0x01, 0xFF, 0x00000000, PPC_64B) \ +{ \ + gen_##name(ctx, 0, 1); \ +} \ +GEN_HANDLER(name##2, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B) \ +{ \ + gen_##name(ctx, 1, 0); \ +} \ +GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B) \ +{ \ + gen_##name(ctx, 1, 1); \ +} +/* rldicl - rldicl. */ +static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn) +{ + int sh, mb; + + sh = SH(ctx->opcode) | (1 << shn); + mb = (MB(ctx->opcode) << 1) | mbn; + /* XXX: TODO */ + RET_INVAL(ctx); +} +GEN_PPC64_R4(rldicl, 0x1E, 0x00) +/* rldicr - rldicr. */ +static inline void gen_rldicr (DisasContext *ctx, int men, int shn) +{ + int sh, me; + + sh = SH(ctx->opcode) | (1 << shn); + me = (MB(ctx->opcode) << 1) | men; + /* XXX: TODO */ + RET_INVAL(ctx); +} +GEN_PPC64_R4(rldicr, 0x1E, 0x02) +/* rldic - rldic. */ +static inline void gen_rldic (DisasContext *ctx, int mbn, int shn) +{ + int sh, mb; + + sh = SH(ctx->opcode) | (1 << shn); + mb = (MB(ctx->opcode) << 1) | mbn; + /* XXX: TODO */ + RET_INVAL(ctx); +} +GEN_PPC64_R4(rldic, 0x1E, 0x04) +/* rldcl - rldcl. */ +static inline void gen_rldcl (DisasContext *ctx, int mbn) +{ + int mb; + + mb = (MB(ctx->opcode) << 1) | mbn; + /* XXX: TODO */ + RET_INVAL(ctx); +} +GEN_PPC64_R2(rldcl, 0x1E, 0x08) +/* rldcr - rldcr. */ +static inline void gen_rldcr (DisasContext *ctx, int men) +{ + int me; + + me = (MB(ctx->opcode) << 1) | men; + /* XXX: TODO */ + RET_INVAL(ctx); +} +GEN_PPC64_R2(rldcr, 0x1E, 0x09) +/* rldimi - rldimi. */ +static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) +{ + int sh, mb; + + sh = SH(ctx->opcode) | (1 << shn); + mb = (MB(ctx->opcode) << 1) | mbn; + /* XXX: TODO */ + RET_INVAL(ctx); +} +GEN_PPC64_R4(rldimi, 0x1E, 0x06) +#endif + /*** Integer shift ***/ /* slw & slw. */ -__GEN_LOGICAL2(slw, 0x18, 0x00); +__GEN_LOGICAL2(slw, 0x18, 0x00, PPC_INTEGER); /* sraw & sraw. */ -__GEN_LOGICAL2(sraw, 0x18, 0x18); +__GEN_LOGICAL2(sraw, 0x18, 0x18, PPC_INTEGER); /* srawi & srawi. */ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) { + int mb, me; gen_op_load_gpr_T0(rS(ctx->opcode)); - if (SH(ctx->opcode) != 0) - gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31)); + if (SH(ctx->opcode) != 0) { + gen_op_move_T1_T0(); + mb = 32 - SH(ctx->opcode); + me = 31; +#if defined(TARGET_PPC64) + mb += 32; + me += 32; +#endif + gen_op_srawi(SH(ctx->opcode), MASK(mb, me)); + } gen_op_store_T0_gpr(rA(ctx->opcode)); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx); } /* srw & srw. */ -__GEN_LOGICAL2(srw, 0x18, 0x10); +__GEN_LOGICAL2(srw, 0x18, 0x10, PPC_INTEGER); + +#if defined(TARGET_PPC64) +/* sld & sld. */ +__GEN_LOGICAL2(sld, 0x1B, 0x00, PPC_64B); +/* srad & srad. */ +__GEN_LOGICAL2(srad, 0x1A, 0x18, PPC_64B); +/* sradi & sradi. */ +static inline void gen_sradi (DisasContext *ctx, int n) +{ + uint64_t mask; + int sh, mb, me; + + gen_op_load_gpr_T0(rS(ctx->opcode)); + sh = SH(ctx->opcode) + (n << 5); + if (sh != 0) { + gen_op_move_T1_T0(); + mb = 64 - SH(ctx->opcode); + me = 63; + mask = MASK(mb, me); + gen_op_sradi(sh, mask >> 32, mask); + } + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} +GEN_HANDLER(sradi0, 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B) +{ + gen_sradi(ctx, 0); +} +GEN_HANDLER(sradi1, 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B) +{ + gen_sradi(ctx, 1); +} +/* srd & srd. */ +__GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B); +#endif /*** Floating-Point arithmetic ***/ #define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \ @@ -1165,7 +1664,7 @@ static inline void gen_addr_imm_index (DisasContext *ctx) target_long simm = SIMM(ctx->opcode); if (rA(ctx->opcode) == 0) { - gen_op_set_T0(simm); + gen_set_T0(simm); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); if (likely(simm != 0)) @@ -1196,26 +1695,51 @@ static inline void gen_addr_register (DisasContext *ctx) /*** Integer load ***/ #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) +#if defined(TARGET_PPC64) #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_raw, \ &gen_op_l##width##_le_raw, \ + &gen_op_l##width##_64_raw, \ + &gen_op_l##width##_le_64_raw, \ }; #define OP_ST_TABLE(width) \ static GenOpFunc *gen_op_st##width[] = { \ &gen_op_st##width##_raw, \ &gen_op_st##width##_le_raw, \ + &gen_op_st##width##_64_raw, \ + &gen_op_st##width##_le_64_raw, \ }; /* Byte access routine are endian safe */ +#define gen_op_stb_le_64_raw gen_op_stb_64_raw +#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw +#else +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_l##width[] = { \ + &gen_op_l##width##_raw, \ + &gen_op_l##width##_le_raw, \ +}; +#define OP_ST_TABLE(width) \ +static GenOpFunc *gen_op_st##width[] = { \ + &gen_op_st##width##_raw, \ + &gen_op_st##width##_le_raw, \ +}; +#endif +/* Byte access routine are endian safe */ #define gen_op_stb_le_raw gen_op_stb_raw #define gen_op_lbz_le_raw gen_op_lbz_raw #else +#if defined(TARGET_PPC64) #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_user, \ &gen_op_l##width##_le_user, \ &gen_op_l##width##_kernel, \ &gen_op_l##width##_le_kernel, \ + &gen_op_l##width##_64_user, \ + &gen_op_l##width##_le_64_user, \ + &gen_op_l##width##_64_kernel, \ + &gen_op_l##width##_le_64_kernel, \ }; #define OP_ST_TABLE(width) \ static GenOpFunc *gen_op_st##width[] = { \ @@ -1223,24 +1747,49 @@ static GenOpFunc *gen_op_st##width[] = { \ &gen_op_st##width##_le_user, \ &gen_op_st##width##_kernel, \ &gen_op_st##width##_le_kernel, \ + &gen_op_st##width##_64_user, \ + &gen_op_st##width##_le_64_user, \ + &gen_op_st##width##_64_kernel, \ + &gen_op_st##width##_le_64_kernel, \ }; /* Byte access routine are endian safe */ +#define gen_op_stb_le_64_user gen_op_stb_64_user +#define gen_op_lbz_le_64_user gen_op_lbz_64_user +#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel +#define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel +#else +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_l##width[] = { \ + &gen_op_l##width##_user, \ + &gen_op_l##width##_le_user, \ + &gen_op_l##width##_kernel, \ + &gen_op_l##width##_le_kernel, \ +}; +#define OP_ST_TABLE(width) \ +static GenOpFunc *gen_op_st##width[] = { \ + &gen_op_st##width##_user, \ + &gen_op_st##width##_le_user, \ + &gen_op_st##width##_kernel, \ + &gen_op_st##width##_le_kernel, \ +}; +#endif +/* Byte access routine are endian safe */ #define gen_op_stb_le_user gen_op_stb_user #define gen_op_lbz_le_user gen_op_lbz_user #define gen_op_stb_le_kernel gen_op_stb_kernel #define gen_op_lbz_le_kernel gen_op_lbz_kernel #endif -#define GEN_LD(width, opc) \ -GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +#define GEN_LD(width, opc, type) \ +GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ gen_addr_imm_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ } -#define GEN_LDU(width, opc) \ -GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +#define GEN_LDU(width, opc, type) \ +GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ if (unlikely(rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode))) { \ @@ -1253,8 +1802,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } -#define GEN_LDUX(width, opc) \ -GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ +#define GEN_LDUX(width, opc2, opc3, type) \ +GEN_HANDLER(l##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \ { \ if (unlikely(rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode))) { \ @@ -1267,41 +1816,74 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } -#define GEN_LDX(width, opc2, opc3) \ -GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ +#define GEN_LDX(width, opc2, opc3, type) \ +GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, type) \ { \ gen_addr_reg_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ } -#define GEN_LDS(width, op) \ +#define GEN_LDS(width, op, type) \ OP_LD_TABLE(width); \ -GEN_LD(width, op | 0x20); \ -GEN_LDU(width, op | 0x21); \ -GEN_LDUX(width, op | 0x01); \ -GEN_LDX(width, 0x17, op | 0x00) +GEN_LD(width, op | 0x20, type); \ +GEN_LDU(width, op | 0x21, type); \ +GEN_LDUX(width, 0x17, op | 0x01, type); \ +GEN_LDX(width, 0x17, op | 0x00, type) /* lbz lbzu lbzux lbzx */ -GEN_LDS(bz, 0x02); +GEN_LDS(bz, 0x02, PPC_INTEGER); /* lha lhau lhaux lhax */ -GEN_LDS(ha, 0x0A); +GEN_LDS(ha, 0x0A, PPC_INTEGER); /* lhz lhzu lhzux lhzx */ -GEN_LDS(hz, 0x08); +GEN_LDS(hz, 0x08, PPC_INTEGER); /* lwz lwzu lwzux lwzx */ -GEN_LDS(wz, 0x00); +GEN_LDS(wz, 0x00, PPC_INTEGER); +#if defined(TARGET_PPC64) +OP_LD_TABLE(wa); +OP_LD_TABLE(d); +/* lwaux */ +GEN_LDUX(wa, 0x15, 0x0B, PPC_64B); +/* lwax */ +GEN_LDX(wa, 0x15, 0x0A, PPC_64B); +/* ldux */ +GEN_LDUX(d, 0x15, 0x01, PPC_64B); +/* ldx */ +GEN_LDX(d, 0x15, 0x00, PPC_64B); +GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B) +{ + if (Rc(ctx->opcode)) { + if (unlikely(rA(ctx->opcode) == 0 || + rA(ctx->opcode) == rD(ctx->opcode))) { + RET_INVAL(ctx); + return; + } + } + gen_addr_imm_index(ctx); + if (ctx->opcode & 0x02) { + /* lwa (lwau is undefined) */ + op_ldst(lwa); + } else { + /* ld - ldu */ + op_ldst(ld); + } + gen_op_store_T1_gpr(rD(ctx->opcode)); + if (Rc(ctx->opcode)) + gen_op_store_T0_gpr(rA(ctx->opcode)); +} +#endif /*** Integer store ***/ -#define GEN_ST(width, opc) \ -GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +#define GEN_ST(width, opc, type) \ +GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ gen_addr_imm_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ } -#define GEN_STU(width, opc) \ -GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ +#define GEN_STU(width, opc, type) \ +GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ @@ -1313,8 +1895,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } -#define GEN_STUX(width, opc) \ -GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ +#define GEN_STUX(width, opc2, opc3, type) \ +GEN_HANDLER(st##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \ { \ if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ @@ -1326,44 +1908,97 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } -#define GEN_STX(width, opc2, opc3) \ -GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ +#define GEN_STX(width, opc2, opc3, type) \ +GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, type) \ { \ gen_addr_reg_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ } -#define GEN_STS(width, op) \ +#define GEN_STS(width, op, type) \ OP_ST_TABLE(width); \ -GEN_ST(width, op | 0x20); \ -GEN_STU(width, op | 0x21); \ -GEN_STUX(width, op | 0x01); \ -GEN_STX(width, 0x17, op | 0x00) +GEN_ST(width, op | 0x20, type); \ +GEN_STU(width, op | 0x21, type); \ +GEN_STUX(width, 0x17, op | 0x01, type); \ +GEN_STX(width, 0x17, op | 0x00, type) /* stb stbu stbux stbx */ -GEN_STS(b, 0x06); +GEN_STS(b, 0x06, PPC_INTEGER); /* sth sthu sthux sthx */ -GEN_STS(h, 0x0C); +GEN_STS(h, 0x0C, PPC_INTEGER); /* stw stwu stwux stwx */ -GEN_STS(w, 0x04); - +GEN_STS(w, 0x04, PPC_INTEGER); +#if defined(TARGET_PPC64) +OP_ST_TABLE(d); +GEN_STUX(d, 0x15, 0x01, PPC_64B); +GEN_STX(d, 0x15, 0x00, PPC_64B); +GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B) +{ + if (Rc(ctx->opcode)) { + if (unlikely(rA(ctx->opcode) == 0)) { + RET_INVAL(ctx); + return; + } + } + gen_addr_imm_index(ctx); + gen_op_load_gpr_T1(rS(ctx->opcode)); + op_ldst(std); + if (Rc(ctx->opcode)) + gen_op_store_T0_gpr(rA(ctx->opcode)); +} +#endif /*** Integer load and store with byte reverse ***/ /* lhbrx */ OP_LD_TABLE(hbr); -GEN_LDX(hbr, 0x16, 0x18); +GEN_LDX(hbr, 0x16, 0x18, PPC_INTEGER); /* lwbrx */ OP_LD_TABLE(wbr); -GEN_LDX(wbr, 0x16, 0x10); +GEN_LDX(wbr, 0x16, 0x10, PPC_INTEGER); /* sthbrx */ OP_ST_TABLE(hbr); -GEN_STX(hbr, 0x16, 0x1C); +GEN_STX(hbr, 0x16, 0x1C, PPC_INTEGER); /* stwbrx */ OP_ST_TABLE(wbr); -GEN_STX(wbr, 0x16, 0x14); +GEN_STX(wbr, 0x16, 0x14, PPC_INTEGER); /*** Integer load and store multiple ***/ #define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg) +#if defined(TARGET_PPC64) +#if defined(CONFIG_USER_ONLY) +static GenOpFunc1 *gen_op_lmw[] = { + &gen_op_lmw_raw, + &gen_op_lmw_le_raw, + &gen_op_lmw_64_raw, + &gen_op_lmw_le_64_raw, +}; +static GenOpFunc1 *gen_op_stmw[] = { + &gen_op_stmw_64_raw, + &gen_op_stmw_le_64_raw, +}; +#else +static GenOpFunc1 *gen_op_lmw[] = { + &gen_op_lmw_user, + &gen_op_lmw_le_user, + &gen_op_lmw_kernel, + &gen_op_lmw_le_kernel, + &gen_op_lmw_64_user, + &gen_op_lmw_le_64_user, + &gen_op_lmw_64_kernel, + &gen_op_lmw_le_64_kernel, +}; +static GenOpFunc1 *gen_op_stmw[] = { + &gen_op_stmw_user, + &gen_op_stmw_le_user, + &gen_op_stmw_kernel, + &gen_op_stmw_le_kernel, + &gen_op_stmw_64_user, + &gen_op_stmw_le_64_user, + &gen_op_stmw_64_kernel, + &gen_op_stmw_le_64_kernel, +}; +#endif +#else #if defined(CONFIG_USER_ONLY) static GenOpFunc1 *gen_op_lmw[] = { &gen_op_lmw_raw, @@ -1387,12 +2022,13 @@ static GenOpFunc1 *gen_op_stmw[] = { &gen_op_stmw_le_kernel, }; #endif +#endif /* lmw */ GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_imm_index(ctx); op_ldstm(lmw, rD(ctx->opcode)); } @@ -1401,7 +2037,7 @@ GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_imm_index(ctx); op_ldstm(stmw, rS(ctx->opcode)); } @@ -1409,6 +2045,59 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) /*** Integer load and store strings ***/ #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start) #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb) +#if defined(TARGET_PPC64) +#if defined(CONFIG_USER_ONLY) +static GenOpFunc1 *gen_op_lswi[] = { + &gen_op_lswi_raw, + &gen_op_lswi_le_raw, + &gen_op_lswi_64_raw, + &gen_op_lswi_le_64_raw, +}; +static GenOpFunc3 *gen_op_lswx[] = { + &gen_op_lswx_raw, + &gen_op_lswx_le_raw, + &gen_op_lswx_64_raw, + &gen_op_lswx_le_64_raw, +}; +static GenOpFunc1 *gen_op_stsw[] = { + &gen_op_stsw_raw, + &gen_op_stsw_le_raw, + &gen_op_stsw_64_raw, + &gen_op_stsw_le_64_raw, +}; +#else +static GenOpFunc1 *gen_op_lswi[] = { + &gen_op_lswi_user, + &gen_op_lswi_le_user, + &gen_op_lswi_kernel, + &gen_op_lswi_le_kernel, + &gen_op_lswi_64_user, + &gen_op_lswi_le_64_user, + &gen_op_lswi_64_kernel, + &gen_op_lswi_le_64_kernel, +}; +static GenOpFunc3 *gen_op_lswx[] = { + &gen_op_lswx_user, + &gen_op_lswx_le_user, + &gen_op_lswx_kernel, + &gen_op_lswx_le_kernel, + &gen_op_lswx_64_user, + &gen_op_lswx_le_64_user, + &gen_op_lswx_64_kernel, + &gen_op_lswx_le_64_kernel, +}; +static GenOpFunc1 *gen_op_stsw[] = { + &gen_op_stsw_user, + &gen_op_stsw_le_user, + &gen_op_stsw_kernel, + &gen_op_stsw_le_kernel, + &gen_op_stsw_64_user, + &gen_op_stsw_le_64_user, + &gen_op_stsw_64_kernel, + &gen_op_stsw_le_64_kernel, +}; +#endif +#else #if defined(CONFIG_USER_ONLY) static GenOpFunc1 *gen_op_lswi[] = { &gen_op_lswi_raw, @@ -1442,6 +2131,7 @@ static GenOpFunc1 *gen_op_stsw[] = { &gen_op_stsw_le_kernel, }; #endif +#endif /* lswi */ /* PowerPC32 specification says we must generate an exception if @@ -1466,7 +2156,7 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) return; } /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_register(ctx); gen_op_set_T1(nb); op_ldsts(lswi, start); @@ -1479,7 +2169,7 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) int rb = rB(ctx->opcode); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); if (ra == 0) { ra = rb; @@ -1494,7 +2184,7 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) int nb = NB(ctx->opcode); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_register(ctx); if (nb == 0) nb = 32; @@ -1506,7 +2196,7 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); gen_op_load_xer_bc(); op_ldsts(stsw, rS(ctx->opcode)); @@ -1525,14 +2215,19 @@ GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM) #define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])() #define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])() +#if defined(TARGET_PPC64) #if defined(CONFIG_USER_ONLY) static GenOpFunc *gen_op_lwarx[] = { &gen_op_lwarx_raw, &gen_op_lwarx_le_raw, + &gen_op_lwarx_64_raw, + &gen_op_lwarx_le_64_raw, }; static GenOpFunc *gen_op_stwcx[] = { &gen_op_stwcx_raw, &gen_op_stwcx_le_raw, + &gen_op_stwcx_64_raw, + &gen_op_stwcx_le_64_raw, }; #else static GenOpFunc *gen_op_lwarx[] = { @@ -1540,14 +2235,47 @@ static GenOpFunc *gen_op_lwarx[] = { &gen_op_lwarx_le_user, &gen_op_lwarx_kernel, &gen_op_lwarx_le_kernel, + &gen_op_lwarx_64_user, + &gen_op_lwarx_le_64_user, + &gen_op_lwarx_64_kernel, + &gen_op_lwarx_le_64_kernel, }; static GenOpFunc *gen_op_stwcx[] = { &gen_op_stwcx_user, &gen_op_stwcx_le_user, &gen_op_stwcx_kernel, &gen_op_stwcx_le_kernel, + &gen_op_stwcx_64_user, + &gen_op_stwcx_le_64_user, + &gen_op_stwcx_64_kernel, + &gen_op_stwcx_le_64_kernel, }; #endif +#else +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_lwarx[] = { + &gen_op_lwarx_raw, + &gen_op_lwarx_le_raw, +}; +static GenOpFunc *gen_op_stwcx[] = { + &gen_op_stwcx_raw, + &gen_op_stwcx_le_raw, +}; +#else +static GenOpFunc *gen_op_lwarx[] = { + &gen_op_lwarx_user, + &gen_op_lwarx_le_user, + &gen_op_lwarx_kernel, + &gen_op_lwarx_le_kernel, +}; +static GenOpFunc *gen_op_stwcx[] = { + &gen_op_stwcx_user, + &gen_op_stwcx_le_user, + &gen_op_stwcx_kernel, + &gen_op_stwcx_le_kernel, +}; +#endif +#endif /* lwarx */ GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES) @@ -1736,15 +2464,25 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) gen_op_goto_tb0(TBPARAM(tb)); else gen_op_goto_tb1(TBPARAM(tb)); - gen_op_set_T1(dest); - gen_op_b_T1(); + gen_set_T1(dest); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_b_T1_64(); + else +#endif + gen_op_b_T1(); gen_op_set_T0((long)tb + n); if (ctx->singlestep_enabled) gen_op_debug(); gen_op_exit_tb(); } else { - gen_op_set_T1(dest); - gen_op_b_T1(); + gen_set_T1(dest); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_b_T1_64(); + else +#endif + gen_op_b_T1(); gen_op_reset_T0(); if (ctx->singlestep_enabled) gen_op_debug(); @@ -1759,16 +2497,22 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) /* sign extend LI */ #if defined(TARGET_PPC64) - li = ((target_long)LI(ctx->opcode) << 38) >> 38; -#else - li = ((target_long)LI(ctx->opcode) << 6) >> 6; + if (ctx->sf_mode) + li = ((int64_t)LI(ctx->opcode) << 38) >> 38; + else #endif + li = ((int32_t)LI(ctx->opcode) << 6) >> 6; if (likely(AA(ctx->opcode) == 0)) target = ctx->nip + li - 4; else target = li; if (LK(ctx->opcode)) { - gen_op_setlr(ctx->nip); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_setlr_64(ctx->nip >> 32, ctx->nip); + else +#endif + gen_op_setlr(ctx->nip); } gen_goto_tb(ctx, 0, target); ctx->exception = EXCP_BRANCH; @@ -1778,16 +2522,16 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) #define BCOND_LR 1 #define BCOND_CTR 2 -static inline void gen_bcond(DisasContext *ctx, int type) -{ +static inline void gen_bcond(DisasContext *ctx, int type) +{ target_ulong target = 0; target_ulong li; - uint32_t bo = BO(ctx->opcode); - uint32_t bi = BI(ctx->opcode); - uint32_t mask; + uint32_t bo = BO(ctx->opcode); + uint32_t bi = BI(ctx->opcode); + uint32_t mask; if ((bo & 0x4) == 0) - gen_op_dec_ctr(); + gen_op_dec_ctr(); switch(type) { case BCOND_IM: li = (target_long)((int16_t)(BD(ctx->opcode))); @@ -1805,62 +2549,102 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_op_movl_T1_lr(); break; } - if (LK(ctx->opcode)) { - gen_op_setlr(ctx->nip); + if (LK(ctx->opcode)) { +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_setlr_64(ctx->nip >> 32, ctx->nip); + else +#endif + gen_op_setlr(ctx->nip); } if (bo & 0x10) { - /* No CR condition */ - switch (bo & 0x6) { - case 0: - gen_op_test_ctr(); + /* No CR condition */ + switch (bo & 0x6) { + case 0: +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_test_ctr_64(); + else +#endif + gen_op_test_ctr(); + break; + case 2: +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_test_ctrz_64(); + else +#endif + gen_op_test_ctrz(); break; - case 2: - gen_op_test_ctrz(); - break; default: - case 4: - case 6: + case 4: + case 6: if (type == BCOND_IM) { gen_goto_tb(ctx, 0, target); } else { - gen_op_b_T1(); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_b_T1_64(); + else +#endif + gen_op_b_T1(); gen_op_reset_T0(); } goto no_test; } - } else { - mask = 1 << (3 - (bi & 0x03)); - gen_op_load_crf_T0(bi >> 2); - if (bo & 0x8) { - switch (bo & 0x6) { - case 0: - gen_op_test_ctr_true(mask); - break; - case 2: - gen_op_test_ctrz_true(mask); - break; - default: - case 4: - case 6: + } else { + mask = 1 << (3 - (bi & 0x03)); + gen_op_load_crf_T0(bi >> 2); + if (bo & 0x8) { + switch (bo & 0x6) { + case 0: +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_test_ctr_true_64(mask); + else +#endif + gen_op_test_ctr_true(mask); + break; + case 2: +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_test_ctrz_true_64(mask); + else +#endif + gen_op_test_ctrz_true(mask); + break; + default: + case 4: + case 6: gen_op_test_true(mask); - break; - } - } else { - switch (bo & 0x6) { - case 0: - gen_op_test_ctr_false(mask); - break; - case 2: - gen_op_test_ctrz_false(mask); - break; + break; + } + } else { + switch (bo & 0x6) { + case 0: +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_test_ctr_false_64(mask); + else +#endif + gen_op_test_ctr_false(mask); + break; + case 2: +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_test_ctrz_false_64(mask); + else +#endif + gen_op_test_ctrz_false(mask); + break; default: - case 4: - case 6: + case 4: + case 6: gen_op_test_false(mask); - break; - } - } - } + break; + } + } + } if (type == BCOND_IM) { int l1 = gen_new_label(); gen_op_jz_T0(l1); @@ -1868,28 +2652,33 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_set_label(l1); gen_goto_tb(ctx, 1, ctx->nip); } else { - gen_op_btest_T1(ctx->nip); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_btest_T1_64(ctx->nip >> 32, ctx->nip); + else +#endif + gen_op_btest_T1(ctx->nip); gen_op_reset_T0(); } no_test: if (ctx->singlestep_enabled) gen_op_debug(); gen_op_exit_tb(); - ctx->exception = EXCP_BRANCH; + ctx->exception = EXCP_BRANCH; } GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_IM); } GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_CTR); } GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_LR); } @@ -1943,7 +2732,12 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) RET_PRIVOPC(ctx); return; } - gen_op_rfi(); +#if defined(TARGET_PPC64) + if (!ctx->sf_mode) + gen_op_rfi_32(); + else +#endif + gen_op_rfi(); RET_CHG_FLOW(ctx); #endif } @@ -1965,7 +2759,7 @@ GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW) gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); /* Update the nip since this might generate a trap exception */ - gen_op_update_nip(ctx->nip); + gen_update_nip(ctx, ctx->nip); gen_op_tw(TO(ctx->opcode)); } @@ -1973,10 +2767,34 @@ GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW) GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_set_T1(SIMM(ctx->opcode)); + gen_set_T1(SIMM(ctx->opcode)); + /* Update the nip since this might generate a trap exception */ + gen_update_nip(ctx, ctx->nip); gen_op_tw(TO(ctx->opcode)); } +#if defined(TARGET_PPC64) +/* td */ +GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + /* Update the nip since this might generate a trap exception */ + gen_update_nip(ctx, ctx->nip); + gen_op_td(TO(ctx->opcode)); +} + +/* tdi */ +GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_set_T1(SIMM(ctx->opcode)); + /* Update the nip since this might generate a trap exception */ + gen_update_nip(ctx, ctx->nip); + gen_op_td(TO(ctx->opcode)); +} +#endif + /*** Processor control ***/ /* mcrxr */ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) @@ -1989,7 +2807,6 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) /* mfcr */ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC) { -#if 0 // XXX: to be tested uint32_t crm, crn; if (likely(ctx->opcode & 0x00100000)) { @@ -1998,11 +2815,9 @@ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC) crn = ffs(crm); gen_op_load_cro(7 - crn); } - } else -#endif - { - gen_op_load_cr(); - } + } else { + gen_op_load_cr(); + } gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -2106,9 +2921,14 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) RET_PRIVREG(ctx); return; } - gen_op_update_nip((ctx)->nip); + gen_update_nip(ctx, ctx->nip); gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_store_msr(); +#if defined(TARGET_PPC64) + if (!ctx->sf_mode) + gen_op_store_msr_32(); + else +#endif + gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ RET_CHG_FLOW(ctx); #endif @@ -2205,6 +3025,27 @@ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE) /* dcbz */ #define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() +#if defined(TARGET_PPC64) +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_dcbz[] = { + &gen_op_dcbz_raw, + &gen_op_dcbz_raw, + &gen_op_dcbz_64_raw, + &gen_op_dcbz_64_raw, +}; +#else +static GenOpFunc *gen_op_dcbz[] = { + &gen_op_dcbz_user, + &gen_op_dcbz_user, + &gen_op_dcbz_kernel, + &gen_op_dcbz_kernel, + &gen_op_dcbz_64_user, + &gen_op_dcbz_64_user, + &gen_op_dcbz_64_kernel, + &gen_op_dcbz_64_kernel, +}; +#endif +#else #if defined(CONFIG_USER_ONLY) static GenOpFunc *gen_op_dcbz[] = { &gen_op_dcbz_raw, @@ -2218,6 +3059,7 @@ static GenOpFunc *gen_op_dcbz[] = { &gen_op_dcbz_kernel, }; #endif +#endif GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) { @@ -2230,9 +3072,14 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); - gen_op_icbi(); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_icbi_64(); + else +#endif + gen_op_icbi(); RET_STOP(ctx); } @@ -2342,7 +3189,12 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE) return; } gen_op_load_gpr_T0(rB(ctx->opcode)); - gen_op_tlbie(); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_tlbie_64(); + else +#endif + gen_op_tlbie(); RET_STOP(ctx); #endif } @@ -2368,14 +3220,19 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC) /* Optional: */ #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])() #define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])() +#if defined(TARGET_PPC64) #if defined(CONFIG_USER_ONLY) static GenOpFunc *gen_op_eciwx[] = { &gen_op_eciwx_raw, &gen_op_eciwx_le_raw, + &gen_op_eciwx_64_raw, + &gen_op_eciwx_le_64_raw, }; static GenOpFunc *gen_op_ecowx[] = { &gen_op_ecowx_raw, &gen_op_ecowx_le_raw, + &gen_op_ecowx_64_raw, + &gen_op_ecowx_le_64_raw, }; #else static GenOpFunc *gen_op_eciwx[] = { @@ -2383,14 +3240,47 @@ static GenOpFunc *gen_op_eciwx[] = { &gen_op_eciwx_le_user, &gen_op_eciwx_kernel, &gen_op_eciwx_le_kernel, + &gen_op_eciwx_64_user, + &gen_op_eciwx_le_64_user, + &gen_op_eciwx_64_kernel, + &gen_op_eciwx_le_64_kernel, }; static GenOpFunc *gen_op_ecowx[] = { &gen_op_ecowx_user, &gen_op_ecowx_le_user, &gen_op_ecowx_kernel, &gen_op_ecowx_le_kernel, + &gen_op_ecowx_64_user, + &gen_op_ecowx_le_64_user, + &gen_op_ecowx_64_kernel, + &gen_op_ecowx_le_64_kernel, }; #endif +#else +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_eciwx[] = { + &gen_op_eciwx_raw, + &gen_op_eciwx_le_raw, +}; +static GenOpFunc *gen_op_ecowx[] = { + &gen_op_ecowx_raw, + &gen_op_ecowx_le_raw, +}; +#else +static GenOpFunc *gen_op_eciwx[] = { + &gen_op_eciwx_user, + &gen_op_eciwx_le_user, + &gen_op_eciwx_kernel, + &gen_op_eciwx_le_kernel, +}; +static GenOpFunc *gen_op_ecowx[] = { + &gen_op_ecowx_user, + &gen_op_ecowx_le_user, + &gen_op_ecowx_kernel, + &gen_op_ecowx_le_kernel, +}; +#endif +#endif /* eciwx */ GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN) @@ -2542,7 +3432,7 @@ GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR) ra = rb; } /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_op_load_xer_bc(); gen_op_load_xer_cmp(); op_POWER_lscbx(rD(ctx->opcode), ra, rb); @@ -2710,7 +3600,7 @@ GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR) gen_set_Rc0(ctx); } -/* sraiq -sraiq. */ +/* sraiq - sraiq. */ GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR) { gen_op_load_gpr_T0(rS(ctx->opcode)); @@ -2984,7 +3874,7 @@ static GenOpFunc *gen_op_POWER2_stfq[] = { GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_imm_index(ctx); op_POWER2_lfq(); gen_op_store_FT0_fpr(rD(ctx->opcode)); @@ -2997,7 +3887,7 @@ GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2) int ra = rA(ctx->opcode); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_imm_index(ctx); op_POWER2_lfq(); gen_op_store_FT0_fpr(rD(ctx->opcode)); @@ -3012,7 +3902,7 @@ GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2) int ra = rA(ctx->opcode); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); op_POWER2_lfq(); gen_op_store_FT0_fpr(rD(ctx->opcode)); @@ -3025,7 +3915,7 @@ GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2) GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); op_POWER2_lfq(); gen_op_store_FT0_fpr(rD(ctx->opcode)); @@ -3036,7 +3926,7 @@ GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2) GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_imm_index(ctx); gen_op_load_fpr_FT0(rS(ctx->opcode)); gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); @@ -3049,7 +3939,7 @@ GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2) int ra = rA(ctx->opcode); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_imm_index(ctx); gen_op_load_fpr_FT0(rS(ctx->opcode)); gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); @@ -3064,7 +3954,7 @@ GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2) int ra = rA(ctx->opcode); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); gen_op_load_fpr_FT0(rS(ctx->opcode)); gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); @@ -3077,7 +3967,7 @@ GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2) GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip(ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); gen_op_load_fpr_FT0(rS(ctx->opcode)); gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); @@ -3102,7 +3992,12 @@ GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE) } gen_addr_reg_index(ctx); /* Use the same micro-ops as for tlbie */ - gen_op_tlbie(); +#if defined(TARGET_PPC64) + if (ctx->sf_mode) + gen_op_tlbie_64(); + else +#endif + gen_op_tlbie(); RET_STOP(ctx); #endif } @@ -3398,6 +4293,7 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON) #endif } +/* TLB management - PowerPC 405 implementation */ /* tlbre */ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON) { @@ -3426,7 +4322,7 @@ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON) #endif } -/* tlbsx - tlbsx. */ /* Named tlbs in BookE */ +/* tlbsx - tlbsx. */ GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON) { #if defined(CONFIG_USER_ONLY) @@ -3446,7 +4342,7 @@ GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON) } /* tlbwe */ -GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_EMB_COMMON) +GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -3575,15 +4471,20 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n", env->nip, env->lr, env->ctr); - cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x " + cpu_fprintf(f, "MSR " REGX FILL " XER %08x " +#if !defined(NO_TIMER_DUMP) + "TB %08x %08x " #if !defined(CONFIG_USER_ONLY) "DECR %08x" +#endif #endif "\n", - do_load_msr(env), load_xer(env), cpu_ppc_load_tbu(env), - cpu_ppc_load_tbl(env) + do_load_msr(env), load_xer(env) +#if !defined(NO_TIMER_DUMP) + , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) #if !defined(CONFIG_USER_ONLY) , cpu_ppc_load_decr(env) +#endif #endif ); for (i = 0; i < 32; i++) { @@ -3619,7 +4520,6 @@ void cpu_dump_state(CPUState *env, FILE *f, "SDR1 " REGX "\n", env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1); -#undef REGX #undef RGPL #undef RFPL #undef FILL @@ -3693,9 +4593,18 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.spr_cb = env->spr_cb; #if defined(CONFIG_USER_ONLY) ctx.mem_idx = msr_le; +#if defined(TARGET_PPC64) + ctx.mem_idx |= msr_sf << 1; +#endif #else ctx.supervisor = 1 - msr_pr; ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le; +#if defined(TARGET_PPC64) + ctx.mem_idx |= msr_sf << 2; +#endif +#endif +#if defined(TARGET_PPC64) + ctx.sf_mode = msr_sf; #endif ctx.fpu_enabled = msr_fp; ctx.singlestep_enabled = env->singlestep_enabled; @@ -3708,7 +4617,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (unlikely(env->nb_breakpoints > 0)) { for (j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == ctx.nip) { - gen_op_update_nip(ctx.nip); + gen_update_nip(&ctx, ctx.nip); gen_op_debug(); break; } @@ -3760,12 +4669,12 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (unlikely(handler->handler == &gen_invalid)) { if (loglevel > 0) { fprintf(logfile, "invalid/unsupported opcode: " - "%02x - %02x - %02x (%08x) 0x%08x %d\n", + "%02x - %02x - %02x (%08x) 0x" REGX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); } else { printf("invalid/unsupported opcode: " - "%02x - %02x - %02x (%08x) 0x%08x %d\n", + "%02x - %02x - %02x (%08x) 0x" REGX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); } @@ -3773,13 +4682,13 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (unlikely((ctx.opcode & handler->inval) != 0)) { if (loglevel > 0) { fprintf(logfile, "invalid bits: %08x for opcode: " - "%02x -%02x - %02x (0x%08x) (0x%08x)\n", + "%02x -%02x - %02x (%08x) " REGX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } else { printf("invalid bits: %08x for opcode: " - "%02x -%02x - %02x (0x%08x) (0x%08x)\n", + "%02x -%02x - %02x (%08x) " REGX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); @@ -3835,7 +4744,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { tb->size = ctx.nip - pc_start; } -#ifdef DEBUG_DISAS +#if defined(DEBUG_DISAS) if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); cpu_dump_state(env, logfile, fprintf, 0); -- cgit v1.2.3 From 36bc0bc9d7cf1df5335cb633306f0eea2c231cb0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Mar 2007 14:04:57 +0000 Subject: Add PowerPC 64 target for tests. As no PowerPC 64 CPU is implemented, this target can just be used to check that there is no difference between PowerPC 32 & PowerPC 64 used in 32 bits mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2483 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 6415ebfd0..af4c29bc1 100755 --- a/configure +++ b/configure @@ -412,7 +412,7 @@ 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" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu ppc64-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then -- cgit v1.2.3 From 39dfc926df54cd3c85485edc89abba67b39ccb7f Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Mar 2007 14:54:15 +0000 Subject: Allow disabling IDE block mode, by Carlo Marcelo Arenas Belon. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2484 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 9e5451fb9..d9c02ab0f 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1631,9 +1631,9 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) ide_set_irq(s); break; case WIN_SETMULT: - if ((s->nsector & 0xff) > MAX_MULT_SECTORS || - s->nsector == 0 || - (s->nsector & (s->nsector - 1)) != 0) { + if ((s->nsector & 0xff) != 0 && + ((s->nsector & 0xff) > MAX_MULT_SECTORS || + (s->nsector & (s->nsector - 1)) != 0)) { ide_abort_command(s); } else { s->mult_sectors = s->nsector & 0xff; -- cgit v1.2.3 From e1f63470e96665b13d8a71ce8df520ab64fdcb12 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Mar 2007 14:55:30 +0000 Subject: Don't fail for "revert to poweron defaults" IDE command, by Carlo Marcelo Arenas Belon. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2485 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/ide.c b/hw/ide.c index d9c02ab0f..0cd252173 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1729,6 +1729,8 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) goto abort_cmd; /* XXX: valid for CDROM ? */ switch(s->feature) { + case 0xcc: /* reverting to power-on defaults enable */ + case 0x66: /* reverting to power-on defaults disable */ case 0x02: /* write cache enable */ case 0x82: /* write cache disable */ case 0xaa: /* read look-ahead enable */ -- cgit v1.2.3 From 70956b7719f37c207610b6cd6f29be123414d360 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Mar 2007 15:00:37 +0000 Subject: Better way to select -lrt, by Andrzei Zaborowski. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2486 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 6 +----- Makefile.target | 3 ++- configure | 7 +++++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index b6d7b1f14..9b9a32d0c 100644 --- a/Makefile +++ b/Makefile @@ -24,11 +24,7 @@ else DOCS= endif -ifndef CONFIG_DARWIN -ifndef CONFIG_WIN32 -LIBS+=-lrt -endif -endif +LIBS+=$(AIOLIBS) all: $(TOOLS) $(DOCS) recurse-all diff --git a/Makefile.target b/Makefile.target index 8eaa8dd78..9f7a804a4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -431,6 +431,7 @@ 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 @@ -441,7 +442,7 @@ endif ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 ifndef CONFIG_SOLARIS -VL_LIBS=-lutil -lrt +VL_LIBS+=-lutil endif endif endif diff --git a/configure b/configure index af4c29bc1..515d1f38e 100755 --- a/configure +++ b/configure @@ -159,6 +159,12 @@ if [ "$bsd" = "yes" ] ; then fi fi +if [ "$bsd" = "yes" -o "$darwin" = "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 @@ -658,6 +664,7 @@ 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 -- cgit v1.2.3 From 1196be3713ebd728359ada9ebf292f0059694a73 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Mar 2007 15:17:58 +0000 Subject: Better ioport debugging output. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2487 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 2 ++ vl.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/exec.c b/exec.c index 6deaf4927..c168abef4 100644 --- a/exec.c +++ b/exec.c @@ -47,6 +47,8 @@ //#define DEBUG_TB_CHECK //#define DEBUG_TLB_CHECK +//#define DEBUG_IOPORT + #if !defined(CONFIG_USER_ONLY) /* TB consistency checks only implemented for usermode emulation. */ #undef DEBUG_TB_CHECK diff --git a/vl.c b/vl.c index 742f9000f..cbf63167b 100644 --- a/vl.c +++ b/vl.c @@ -199,7 +199,7 @@ PicState2 *isa_pic; uint32_t default_ioport_readb(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT - fprintf(stderr, "inb: port=0x%04x\n", address); + fprintf(stderr, "unused inb: port=0x%04x\n", address); #endif return 0xff; } @@ -207,7 +207,7 @@ uint32_t default_ioport_readb(void *opaque, uint32_t address) void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data) { #ifdef DEBUG_UNUSED_IOPORT - fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data); + fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data); #endif } @@ -231,7 +231,7 @@ void default_ioport_writew(void *opaque, uint32_t address, uint32_t data) uint32_t default_ioport_readl(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT - fprintf(stderr, "inl: port=0x%04x\n", address); + fprintf(stderr, "unused inl: port=0x%04x\n", address); #endif return 0xffffffff; } @@ -239,7 +239,7 @@ uint32_t default_ioport_readl(void *opaque, uint32_t address) void default_ioport_writel(void *opaque, uint32_t address, uint32_t data) { #ifdef DEBUG_UNUSED_IOPORT - fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data); + fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data); #endif } -- cgit v1.2.3 From 153a08db4f059ac2b6d4bb24ebbbfcc314697bf5 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Mar 2007 15:21:30 +0000 Subject: Remove useless static specifier. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2488 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 91d8021dd..2a3b15af6 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -136,7 +136,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, unsigned long bios_offset; int bios_size; CPUState *env; - static RTCState *rtc_state; + RTCState *rtc_state; int i; env = cpu_init(); -- cgit v1.2.3 From 60a9f9ecd90ae4921e919323ecd9ab59e71e71f5 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 17 Mar 2007 15:39:48 +0000 Subject: Note FPU enable/disable issue. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2489 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-mips/TODO b/target-mips/TODO index bd8d26d1f..9faa041b2 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -8,6 +8,8 @@ General instructions are regarded as valid - pcnet32 does not work for little endian emulation on big endian host (probably not mips specific, but observable for mips-malta) +- CP1 enable/disable is checked at translation time, not at execution + time, so it will have delayed effect. MIPS64 ------ -- cgit v1.2.3 From e24ad6f140f23e1edc1646ea248819698b77f0e2 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Mar 2007 16:59:31 +0000 Subject: OHCI USB PXA support (Andrzej Zaborowski). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2490 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 2 +- hw/ppc_prep.c | 2 +- hw/realview.c | 2 +- hw/usb-ohci.c | 148 +++++++++++++++++++++++++++++++++++++++++++------------ hw/usb.h | 4 +- hw/versatilepb.c | 2 +- 6 files changed, 123 insertions(+), 37 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 937be150c..b1199e2cf 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -501,7 +501,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, } if (usb_enabled) { - usb_ohci_init(pci_bus, 3, -1); + usb_ohci_init_pci(pci_bus, 3, -1); } if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 27d3d4848..32a3e5230 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -666,7 +666,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, #endif if (usb_enabled) { - usb_ohci_init(pci_bus, 3, -1); + usb_ohci_init_pci(pci_bus, 3, -1); } nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); diff --git a/hw/realview.c b/hw/realview.c index 619739c11..a5607e79b 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -57,7 +57,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, pci_bus = pci_vpb_init(pic, 48, 1); if (usb_enabled) { - usb_ohci_init(pci_bus, 3, -1); + usb_ohci_init_pci(pci_bus, 3, -1); } scsi_hba = lsi_scsi_init(pci_bus, -1); for (n = 0; n < MAX_DISKS; n++) { diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index de113e9a3..a4f8aa6e3 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -2,6 +2,7 @@ * QEMU USB OHCI Emulation * Copyright (c) 2004 Gianni Tedesco * Copyright (c) 2006 CodeSourcery + * Copyright (c) 2006 Openedhand Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -52,11 +53,19 @@ typedef struct OHCIPort { uint32_t ctrl; } OHCIPort; +enum ohci_type { + OHCI_TYPE_PCI, + OHCI_TYPE_PXA +}; + typedef struct { - struct PCIDevice pci_dev; + void *pic; + int irq; + enum ohci_type type; target_phys_addr_t mem_base; int mem; int num_ports; + const char *name; QEMUTimer *eof_timer; int64_t sof_time; @@ -90,6 +99,12 @@ typedef struct { uint32_t rhstatus; OHCIPort rhport[OHCI_MAX_PORTS]; + /* PXA27x Non-OHCI events */ + uint32_t hstatus; + uint32_t hmask; + uint32_t hreset; + uint32_t htest; + /* Active packets. */ uint32_t old_ctl; USBPacket usb_packet; @@ -256,6 +271,8 @@ struct ohci_td { #define OHCI_CC_BUFFEROVERRUN 0xc #define OHCI_CC_BUFFERUNDERRUN 0xd +#define OHCI_HRESET_FSBIR (1 << 0) + /* Update IRQ levels */ static inline void ohci_intr_update(OHCIState *ohci) { @@ -265,7 +282,10 @@ static inline void ohci_intr_update(OHCIState *ohci) (ohci->intr_status & ohci->intr)) level = 1; - pci_set_irq(&ohci->pci_dev, 0, level); + if (ohci->type == OHCI_TYPE_PCI) + pci_set_irq((PCIDevice *)ohci->pic, ohci->irq, level); + else + pic_set_irq_new(ohci->pic, ohci->irq, level); } /* Set an interrupt */ @@ -295,6 +315,11 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) else port->ctrl &= ~OHCI_PORT_LSDA; port->port.dev = dev; + + /* notify of remote-wakeup */ + if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) + ohci_set_interrupt(s, OHCI_INTR_RD); + /* send the attach message */ usb_send_msg(dev, USB_MSG_ATTACH); dprintf("usb-ohci: Attached port %d\n", port1->index); @@ -367,7 +392,7 @@ static void ohci_reset(OHCIState *ohci) usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; } - dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); + dprintf("usb-ohci: Reset %s\n", ohci->name); } /* Get an array of dwords from main memory */ @@ -795,13 +820,12 @@ static int ohci_bus_start(OHCIState *ohci) ohci); if (ohci->eof_timer == NULL) { - fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", - ohci->pci_dev.name); + fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", ohci->name); /* TODO: Signal unrecoverable error */ return 0; } - dprintf("usb-ohci: %s: USB Operational\n", ohci->pci_dev.name); + dprintf("usb-ohci: %s: USB Operational\n", ohci->name); ohci_sof(ohci); @@ -854,7 +878,7 @@ static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) if (val != ohci->fi) { dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n", - ohci->pci_dev.name, ohci->fi, ohci->fi); + ohci->name, ohci->fi, ohci->fi); } ohci->fi = val; @@ -892,13 +916,13 @@ static void ohci_set_ctl(OHCIState *ohci, uint32_t val) break; case OHCI_USB_SUSPEND: ohci_bus_stop(ohci); - dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name); + dprintf("usb-ohci: %s: USB Suspended\n", ohci->name); break; case OHCI_USB_RESUME: - dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name); + dprintf("usb-ohci: %s: USB Resume\n", ohci->name); break; case OHCI_USB_RESET: - dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name); + dprintf("usb-ohci: %s: USB Reset\n", ohci->name); break; } } @@ -1086,6 +1110,19 @@ static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr) case 20: /* HcRhStatus */ return ohci->rhstatus; + /* PXA27x specific registers */ + case 24: /* HcStatus */ + return ohci->hstatus & ohci->hmask; + + case 25: /* HcHReset */ + return ohci->hreset; + + case 26: /* HcHInterruptEnable */ + return ohci->hmask; + + case 27: /* HcHInterruptTest */ + return ohci->htest; + default: fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr); return 0xffffffff; @@ -1187,6 +1224,24 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) ohci_set_hub_status(ohci, val); break; + /* PXA27x specific registers */ + case 24: /* HcStatus */ + ohci->hstatus &= ~(val & ohci->hmask); + + case 25: /* HcHReset */ + ohci->hreset = val & ~OHCI_HRESET_FSBIR; + if (val & OHCI_HRESET_FSBIR) + ohci_reset(ohci); + break; + + case 26: /* HcHInterruptEnable */ + ohci->hmask = val; + break; + + case 27: /* HcHInterruptTest */ + ohci->htest = val; + break; + default: fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr); break; @@ -1207,22 +1262,11 @@ static CPUWriteMemoryFunc *ohci_writefn[3]={ ohci_mem_write }; -static void ohci_mapfunc(PCIDevice *pci_dev, int i, - uint32_t addr, uint32_t size, int type) -{ - OHCIState *ohci = (OHCIState *)pci_dev; - ohci->mem_base = addr; - cpu_register_physical_memory(addr, size, ohci->mem); -} - -void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) +static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn, + void *pic, int irq, enum ohci_type type, const char *name) { - OHCIState *ohci; - int vid = 0x106b; - int did = 0x003f; int i; - if (usb_frame_time == 0) { #if OHCI_TIME_WARP usb_frame_time = ticks_per_sec; @@ -1239,8 +1283,43 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) usb_frame_time, usb_bit_time); } - ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci), - devfn, NULL, NULL); + ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); + ohci->name = name; + + ohci->pic = pic; + ohci->irq = irq; + ohci->type = type; + + ohci->num_ports = num_ports; + for (i = 0; i < num_ports; i++) { + qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); + } + + ohci->async_td = 0; + ohci_reset(ohci); +} + +typedef struct { + PCIDevice pci_dev; + OHCIState state; +} OHCIPCIState; + +static void ohci_mapfunc(PCIDevice *pci_dev, int i, + uint32_t addr, uint32_t size, int type) +{ + OHCIPCIState *ohci = (OHCIPCIState *)pci_dev; + ohci->state.mem_base = addr; + cpu_register_physical_memory(addr, size, ohci->state.mem); +} + +void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn) +{ + OHCIPCIState *ohci; + int vid = 0x106b; + int did = 0x003f; + + ohci = (OHCIPCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci), + devfn, NULL, NULL); if (ohci == NULL) { fprintf(stderr, "usb-ohci: Failed to register PCI device\n"); return; @@ -1255,16 +1334,21 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) ohci->pci_dev.config[0x0b] = 0xc; ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ - ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); + usb_ohci_init(&ohci->state, num_ports, devfn, &ohci->pci_dev, + 0, OHCI_TYPE_PCI, ohci->pci_dev.name); pci_register_io_region((struct PCIDevice *)ohci, 0, 256, PCI_ADDRESS_SPACE_MEM, ohci_mapfunc); +} - ohci->num_ports = num_ports; - for (i = 0; i < num_ports; i++) { - qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); - } +void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, + void *pic, int irq) +{ + OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState)); - ohci->async_td = 0; - ohci_reset(ohci); + usb_ohci_init(ohci, num_ports, devfn, pic, irq, + OHCI_TYPE_PXA, "OHCI USB"); + ohci->mem_base = base; + + cpu_register_physical_memory(ohci->mem_base, 0xfff, ohci->mem); } diff --git a/hw/usb.h b/hw/usb.h index a6d0ae658..bd77eea8b 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -206,7 +206,9 @@ USBDevice *usb_hub_init(int nb_ports); void usb_uhci_init(PCIBus *bus, int devfn); /* usb-ohci.c */ -void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn); +void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn); +void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, + void *pic, int irq); /* usb-linux.c */ USBDevice *usb_host_device_open(const char *devname); diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 050878d50..5d3e857ee 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -195,7 +195,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, } } if (usb_enabled) { - usb_ohci_init(pci_bus, 3, -1); + usb_ohci_init_pci(pci_bus, 3, -1); } scsi_hba = lsi_scsi_init(pci_bus, -1); for (n = 0; n < MAX_DISKS; n++) { -- cgit v1.2.3 From 33d68b5f00011c8101aec93ba1bb2b470e35151d Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Mar 2007 00:30:29 +0000 Subject: MIPS -cpu selection support, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2491 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 1 + hw/mips_malta.c | 12 ++++++ hw/mips_r4k.c | 14 ++++++- target-mips/cpu.h | 5 +++ target-mips/mips-defs.h | 26 ------------ target-mips/translate.c | 9 +--- target-mips/translate_init.c | 97 ++++++++++++++++++++++++++++++++++++++++++++ vl.c | 2 + vl.h | 4 ++ 10 files changed, 137 insertions(+), 34 deletions(-) create mode 100644 target-mips/translate_init.c diff --git a/Changelog b/Changelog index b0123e1d3..1ecf09b2d 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,7 @@ - Tap device emulation for Solaris (Sittichai Palanisong) - Monitor multiplexing to several I/O channels (Jason Wessel) - ds1225y nvram support (Herve Poussineau) + - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) version 0.9.0: diff --git a/Makefile.target b/Makefile.target index 9f7a804a4..c0a79f969 100644 --- a/Makefile.target +++ b/Makefile.target @@ -551,6 +551,7 @@ endif ifeq ($(TARGET_ARCH), mips) op.o: op.c op_template.c fop_template.c op_mem.c op_helper.o: op_helper_mem.c +translate.o: translate.c translate_init.c endif loader.o: loader.c elf_ops.h diff --git a/hw/mips_malta.c b/hw/mips_malta.c index d137658fb..b215cd58a 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -626,8 +626,20 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, /* fdctrl_t *floppy_controller; */ MaltaFPGAState *malta_fpga; int ret; + mips_def_t *def; + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef MIPS_HAS_MIPS64 + cpu_model = "R4000"; +#else + cpu_model = "4KEc"; +#endif + } + if (mips_find_by_name(cpu_model, &def) != 0) + def = NULL; env = cpu_init(); + cpu_mips_register(env, def); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 2a3b15af6..7709418c0 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -138,8 +138,20 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, CPUState *env; RTCState *rtc_state; int i; + mips_def_t *def; + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef MIPS_HAS_MIPS64 + cpu_model = "R4000"; +#else + cpu_model = "4KEc"; +#endif + } + if (mips_find_by_name(cpu_model, &def) != 0) + def = NULL; env = cpu_init(); + cpu_mips_register(env, def); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); @@ -148,7 +160,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, if (!mips_qemu_iomemtype) { mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read, - mips_qemu_write, NULL); + mips_qemu_write, NULL); } cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 69335a018..276910aae 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -282,6 +282,11 @@ struct CPUMIPSState { struct QEMUTimer *timer; /* Internal timer */ }; +typedef struct mips_def_t mips_def_t; +int mips_find_by_name (const unsigned char *name, mips_def_t **def); +void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +int cpu_mips_register (CPUMIPSState *env, mips_def_t *def); + #include "cpu-all.h" /* Memory access type : diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index a78bef55e..b0fc98396 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -6,26 +6,15 @@ /* If we want to use host float regs... */ //#define USE_HOST_FLOAT_REGS -#define MIPS_R4Kc 0x00018000 -#define MIPS_R4Kp 0x00018300 - -/* Emulate MIPS R4Kc for now */ -#define MIPS_CPU MIPS_R4Kc - -#if (MIPS_CPU == MIPS_R4Kc) /* 32 bits target */ #undef MIPS_HAS_MIPS64 //#define MIPS_HAS_MIPS64 1 /* real pages are variable size... */ #define TARGET_PAGE_BITS 12 -/* Uses MIPS R4Kx enhancements to MIPS32 architecture */ -#define MIPS_USES_R4K_EXT /* Uses MIPS R4Kc TLB model */ #define MIPS_USES_R4K_TLB #define MIPS_TLB_NB 16 #define MIPS_TLB_MAX 128 -/* basic FPU register support */ -#define MIPS_USES_FPU 1 /* Define a implementation number of 1. * Define a major version 1, minor version 0. */ @@ -63,21 +52,6 @@ ((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \ (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL)) -#elif (MIPS_CPU == MIPS_R4Kp) -/* 32 bits target */ -#undef MIPS_HAS_MIPS64 -/* real pages are variable size... */ -#define TARGET_PAGE_BITS 12 -/* Uses MIPS R4Kx enhancements to MIPS32 architecture */ -#define MIPS_USES_R4K_EXT -/* Uses MIPS R4Km FPM MMU model */ -#define MIPS_USES_R4K_FPM -#else -#error "MIPS CPU not defined" -/* Reminder for other flags */ -//#undef MIPS_HAS_MIPS64 -//#define MIPS_USES_FPU -#endif #ifdef MIPS_HAS_MIPS64 #define TARGET_LONG_BITS 64 diff --git a/target-mips/translate.c b/target-mips/translate.c index a9f7b75c4..75e30692a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5283,12 +5283,6 @@ void cpu_reset (CPUMIPSState *env) env->CP0_Wired = 0; /* SMP not implemented */ env->CP0_EBase = 0x80000000; - env->CP0_Config0 = MIPS_CONFIG0; - env->CP0_Config1 = MIPS_CONFIG1; -#ifdef MIPS_USES_FPU - /* basic FPU register support */ - env->CP0_Config1 |= (1 << CP0C1_FP); -#endif env->CP0_Config2 = MIPS_CONFIG2; env->CP0_Config3 = MIPS_CONFIG3; env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); @@ -5296,7 +5290,6 @@ void cpu_reset (CPUMIPSState *env) env->hflags = MIPS_HFLAG_ERL; /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); - env->CP0_PRid = MIPS_CPU; #endif env->exception_index = EXCP_NONE; #if defined(CONFIG_USER_ONLY) @@ -5308,3 +5301,5 @@ void cpu_reset (CPUMIPSState *env) env->SYNCI_Step = 16; env->CCRes = 2; } + +#include "translate_init.c" diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c new file mode 100644 index 000000000..b7baff187 --- /dev/null +++ b/target-mips/translate_init.c @@ -0,0 +1,97 @@ +/* + * MIPS emulation for qemu: CPU initialisation routines. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * Copyright (c) 2007 Herve Poussineau + * + * 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 + */ + +struct mips_def_t { + const unsigned char *name; + int32_t CP0_PRid; + int32_t CP0_Config0; + int32_t CP0_Config1; +}; + +/*****************************************************************************/ +/* MIPS CPU definitions */ +static mips_def_t mips_defs[] = +{ +#ifndef MIPS_HAS_MIPS64 + { + .name = "4Kc", + .CP0_PRid = 0x00018000, + .CP0_Config0 = MIPS_CONFIG0, + .CP0_Config1 = MIPS_CONFIG1, + }, + { + .name = "4KEc", + .CP0_PRid = 0x00018400, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), + .CP0_Config1 = MIPS_CONFIG1, + }, + { + .name = "24Kf", + .CP0_PRid = 0x00019300, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP), + }, +#else + { + .name = "R4000", + .CP0_PRid = 0x00000400, + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP), + }, +#endif +}; + +int mips_find_by_name (const unsigned char *name, mips_def_t **def) +{ + int i, ret; + + ret = -1; + *def = NULL; + for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) { + if (strcasecmp(name, mips_defs[i].name) == 0) { + *def = &mips_defs[i]; + ret = 0; + break; + } + } + + return ret; +} + +void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + int i; + + for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) { + (*cpu_fprintf)(f, "MIPS '%s'\n", + mips_defs[i].name); + } +} + +int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) +{ + if (!def) + cpu_abort(env, "Unable to find MIPS CPU definition\n"); + env->CP0_PRid = def->CP0_PRid; + env->CP0_Config0 = def->CP0_Config0; + env->CP0_Config1 = def->CP0_Config1; + return 0; +} diff --git a/vl.c b/vl.c index cbf63167b..fc0f8ff4c 100644 --- a/vl.c +++ b/vl.c @@ -7009,6 +7009,8 @@ int main(int argc, char **argv) ppc_cpu_list(stdout, &fprintf); #elif defined(TARGET_ARM) arm_cpu_list(); +#elif defined(TARGET_MIPS) + mips_cpu_list(stdout, &fprintf); #endif exit(1); } else { diff --git a/vl.h b/vl.h index c7c7d73a0..464bf899c 100644 --- a/vl.h +++ b/vl.h @@ -713,6 +713,10 @@ typedef void IRQRequestFunc(void *opaque, int level); void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); #endif +#if defined(TARGET_MIPS) +void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +#endif + /* ISA bus */ extern target_phys_addr_t isa_mem_base; -- cgit v1.2.3 From 36f696517b1723d627b79aa924bac7c678de01b0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 18 Mar 2007 08:47:10 +0000 Subject: As icbi is not a priviledge instruction and is treated as a load by the MMU it needs to be implemented for every MMU translation mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2492 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 15 --------------- target-ppc/op_helper.c | 29 ----------------------------- target-ppc/op_helper.h | 7 ++----- target-ppc/op_helper_mem.h | 29 +++++++++++++++++++++++++++++ target-ppc/op_mem.h | 15 +++++++++++++++ target-ppc/translate.c | 43 +++++++++++++++++++++++++++++++++++++------ 6 files changed, 83 insertions(+), 55 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index be922c6ad..9531595be 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1884,21 +1884,6 @@ void OPPROTO op_td (void) } #endif -/* Instruction cache block invalidate */ -void OPPROTO op_icbi (void) -{ - do_icbi(); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_icbi_64 (void) -{ - do_icbi_64(); - RETURN(); -} -#endif - #if !defined(CONFIG_USER_ONLY) /* tlbia */ PPC_OP(tlbia) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 7bc59332d..7ef06b20b 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -808,35 +808,6 @@ void do_td (int flags) } #endif -/* Instruction cache invalidation helper */ -void do_icbi (void) -{ - uint32_t tmp; - /* Invalidate one cache line : - * PowerPC specification says this is to be treated like a load - * (not a fetch) by the MMU. To be sure it will be so, - * do the load "by hand". - */ - tmp = ldl_kernel((uint32_t)T0); - T0 &= ~(ICACHE_LINE_SIZE - 1); - tb_invalidate_page_range((uint32_t)T0, (uint32_t)(T0 + ICACHE_LINE_SIZE)); -} - -#if defined(TARGET_PPC64) -void do_icbi_64 (void) -{ - uint64_t tmp; - /* Invalidate one cache line : - * PowerPC specification says this is to be treated like a load - * (not a fetch) by the MMU. To be sure it will be so, - * do the load "by hand". - */ - tmp = ldq_kernel((uint64_t)T0); - T0 &= ~(ICACHE_LINE_SIZE - 1); - tb_invalidate_page_range((uint64_t)T0, (uint64_t)(T0 + ICACHE_LINE_SIZE)); -} -#endif - /*****************************************************************************/ /* PowerPC 601 specific instructions (POWER bridge) */ void do_POWER_abso (void) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 13ed7ab92..6eaceb30e 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -29,6 +29,7 @@ void glue(do_lmw, MEMSUFFIX) (int dst); void glue(do_lmw_le, MEMSUFFIX) (int dst); void glue(do_stmw, MEMSUFFIX) (int src); void glue(do_stmw_le, MEMSUFFIX) (int src); +void glue(do_icbi, MEMSUFFIX) (void); void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb); void glue(do_POWER2_lfq, MEMSUFFIX) (void); void glue(do_POWER2_lfq_le, MEMSUFFIX) (void); @@ -44,6 +45,7 @@ void glue(do_lmw_64, MEMSUFFIX) (int dst); void glue(do_lmw_le_64, MEMSUFFIX) (int dst); void glue(do_stmw_64, MEMSUFFIX) (int src); void glue(do_stmw_le_64, MEMSUFFIX) (int src); +void glue(do_icbi_64, MEMSUFFIX) (void); #endif #else @@ -102,11 +104,6 @@ void do_tw (int flags); #if defined(TARGET_PPC64) void do_td (int flags); #endif -void do_icbi (void); -#if defined(TARGET_PPC64) -void do_icbi_64 (void); -#endif - #if !defined(CONFIG_USER_ONLY) void do_rfi (void); #if defined(TARGET_PPC64) diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index ccee7142e..49ec1c42f 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -242,6 +242,35 @@ void glue(do_stsw_le_64, MEMSUFFIX) (int src) } #endif +/* Instruction cache invalidation helper */ +void glue(do_icbi, MEMSUFFIX) (void) +{ + uint32_t tmp; + /* Invalidate one cache line : + * PowerPC specification says this is to be treated like a load + * (not a fetch) by the MMU. To be sure it will be so, + * do the load "by hand". + */ + tmp = glue(ldl, MEMSUFFIX)((uint32_t)T0); + T0 &= ~(ICACHE_LINE_SIZE - 1); + tb_invalidate_page_range((uint32_t)T0, (uint32_t)(T0 + ICACHE_LINE_SIZE)); +} + +#if defined(TARGET_PPC64) +void glue(do_icbi_64, MEMSUFFIX) (void) +{ + uint64_t tmp; + /* Invalidate one cache line : + * PowerPC specification says this is to be treated like a load + * (not a fetch) by the MMU. To be sure it will be so, + * do the load "by hand". + */ + tmp = glue(ldq, MEMSUFFIX)((uint64_t)T0); + T0 &= ~(ICACHE_LINE_SIZE - 1); + tb_invalidate_page_range((uint64_t)T0, (uint64_t)(T0 + ICACHE_LINE_SIZE)); +} +#endif + /* PPC 601 specific instructions (POWER bridge) */ // XXX: to be tested void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb) diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 8aa799f65..f5a8c4b64 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -730,6 +730,21 @@ void OPPROTO glue(op_dcbz_64, MEMSUFFIX) (void) } #endif +/* Instruction cache block invalidate */ +void OPPROTO glue(op_icbi, MEMSUFFIX) (void) +{ + glue(do_icbi, MEMSUFFIX)(); + RETURN(); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_icbi_64, MEMSUFFIX) (void) +{ + glue(do_icbi_64, MEMSUFFIX)(); + RETURN(); +} +#endif + /* External access */ void OPPROTO glue(op_eciwx, MEMSUFFIX) (void) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e5c281293..82919a587 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3069,17 +3069,48 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) } /* icbi */ +#define op_icbi() (*gen_op_icbi[ctx->mem_idx])() +#if defined(TARGET_PPC64) +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_icbi[] = { + &gen_op_icbi_raw, + &gen_op_icbi_raw, + &gen_op_icbi_64_raw, + &gen_op_icbi_64_raw, +}; +#else +static GenOpFunc *gen_op_icbi[] = { + &gen_op_icbi_user, + &gen_op_icbi_user, + &gen_op_icbi_kernel, + &gen_op_icbi_kernel, + &gen_op_icbi_64_user, + &gen_op_icbi_64_user, + &gen_op_icbi_64_kernel, + &gen_op_icbi_64_kernel, +}; +#endif +#else +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_icbi[] = { + &gen_op_icbi_raw, + &gen_op_icbi_raw, +}; +#else +static GenOpFunc *gen_op_icbi[] = { + &gen_op_icbi_user, + &gen_op_icbi_user, + &gen_op_icbi_kernel, + &gen_op_icbi_kernel, +}; +#endif +#endif GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_icbi_64(); - else -#endif - gen_op_icbi(); + op_icbi(); RET_STOP(ctx); } -- cgit v1.2.3 From 39d51eb8bcc603c02342d8f5e1f7a569e5f17e06 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Mar 2007 12:43:40 +0000 Subject: Fix BD flag handling, cause register contents, implement some more bits for R2 interrupt handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2493 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_int.c | 13 ++++--------- hw/mips_timer.c | 7 +++++++ target-mips/helper.c | 14 +++++++++++--- target-mips/op.c | 7 ++++++- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/hw/mips_int.c b/hw/mips_int.c index 93d599fc6..7f9f15305 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -20,20 +20,15 @@ void cpu_mips_update_irq(CPUState *env) void cpu_mips_irq_request(void *opaque, int irq, int level) { - CPUState *env = first_cpu; - - uint32_t mask; + CPUState *env = (CPUState *)opaque; - if (irq >= 16) + if (irq < 0 || irq > 7) return; - mask = 1 << (irq + CP0Ca_IP); - if (level) { - env->CP0_Cause |= mask; + env->CP0_Cause |= 1 << (irq + CP0Ca_IP); } else { - env->CP0_Cause &= ~mask; + env->CP0_Cause &= ~(1 << (irq +CP0Ca_IP)); } cpu_mips_update_irq(env); } - diff --git a/hw/mips_timer.c b/hw/mips_timer.c index bc83036b3..055ee5b89 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -28,6 +28,9 @@ static void cpu_mips_update_count (CPUState *env, uint32_t count, uint64_t now, next; uint32_t tmp; + if (env->CP0_Cause & (1 << CP0Ca_DC)) + return; + tmp = count; if (count == compare) tmp++; @@ -57,6 +60,8 @@ void cpu_mips_store_count (CPUState *env, uint32_t value) void cpu_mips_store_compare (CPUState *env, uint32_t value) { cpu_mips_update_count(env, cpu_mips_get_count(env), value); + if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) + env->CP0_Cause &= ~(1 << CP0Ca_TI); cpu_mips_irq_request(env, 7, 0); } @@ -71,6 +76,8 @@ static void mips_timer_cb (void *opaque) } #endif cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); + if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) + env->CP0_Cause |= 1 << CP0Ca_TI; cpu_mips_irq_request(env, 7, 1); } diff --git a/target-mips/helper.c b/target-mips/helper.c index 9ba401785..0b23f359f 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -295,9 +295,12 @@ void do_interrupt (CPUState *env) /* If the exception was raised from a delay slot, come back to the jump. */ env->CP0_DEPC = env->PC - 4; + if (!(env->hflags & MIPS_HFLAG_EXL)) + env->CP0_Cause |= (1 << CP0Ca_BD); env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_DEPC = env->PC; + env->CP0_Cause &= ~(1 << CP0Ca_BD); } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; @@ -318,9 +321,12 @@ void do_interrupt (CPUState *env) /* If the exception was raised from a delay slot, come back to the jump. */ env->CP0_ErrorEPC = env->PC - 4; + if (!(env->hflags & MIPS_HFLAG_EXL)) + env->CP0_Cause |= (1 << CP0Ca_BD); env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_ErrorEPC = env->PC; + env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->hflags |= MIPS_HFLAG_ERL; env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); @@ -364,7 +370,8 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_CpU: cause = 11; - env->CP0_Cause = (env->CP0_Cause & ~0x03000000) | (env->error_code << 28); + env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) | + (env->error_code << CP0Ca_CE); goto set_EPC; case EXCP_OVERFLOW: cause = 12; @@ -385,11 +392,12 @@ void do_interrupt (CPUState *env) /* If the exception was raised from a delay slot, come back to the jump. */ env->CP0_EPC = env->PC - 4; - env->CP0_Cause |= 0x80000000; + if (!(env->hflags & MIPS_HFLAG_EXL)) + env->CP0_Cause |= (1 << CP0Ca_BD); env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_EPC = env->PC; - env->CP0_Cause &= ~0x80000000; + env->CP0_Cause &= ~(1 << CP0Ca_BD); } if (env->CP0_Status & (1 << CP0St_BEV)) { env->PC = (int32_t)0xBFC00200; diff --git a/target-mips/op.c b/target-mips/op.c index 7c7ce3ba3..a286cefe5 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1397,7 +1397,12 @@ void op_mtc0_srsmap (void) void op_mtc0_cause (void) { - env->CP0_Cause = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300); + uint32_t mask = 0x00C00300; + + if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) + mask |= 1 << CP0Ca_DC; + + env->CP0_Cause = (env->CP0_Cause & 0xFCC0FF7C) | (T0 & mask); /* Handle the software interrupt as an hardware one, as they are very similar */ -- cgit v1.2.3 From 11f295118c5b78910b0b26c1a856944016895ec8 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Mar 2007 22:18:43 +0000 Subject: A VGA card for the Malta board. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2494 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 1 + hw/mips_malta.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 2b01da70b..9d6bb44eb 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -239,6 +239,7 @@ static void gt64120_pci_mapping(GT64120State *s) /* Map new IO address */ s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21; s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; + isa_mem_base = s->PCI0IO_start; isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length); } } diff --git a/hw/mips_malta.c b/hw/mips_malta.c index b215cd58a..54b813bdf 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -719,6 +719,10 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, /* Network card */ network_init(pci_bus); + + /* Optional PCI video card */ + pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, + ram_size, vga_ram_size); } QEMUMachine mips_malta_machine = { -- cgit v1.2.3 From 6c041c54bc710cf818afd630f31161ce0352ebcd Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Mar 2007 23:23:31 +0000 Subject: Disable compiler options dangerous for op compilation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2495 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 27 ++++++++++++++++----------- configure | 8 -------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/Makefile.target b/Makefile.target index c0a79f969..38899ff14 100644 --- a/Makefile.target +++ b/Makefile.target @@ -70,16 +70,26 @@ BASE_LDFLAGS+=-static endif # We require -O2 to avoid the stack setup prologue in EXIT_TB -OP_CFLAGS = -Wall -O2 -g -fno-strict-aliasing +OP_CFLAGS := -Wall -O2 -g -fno-strict-aliasing + +# cc-option +# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0) + +cc-option = $(shell if $(CC) $(OP_CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ + > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) + +OP_CFLAGS+=$(call cc-option, -fno-reorder-blocks, "") +OP_CFLAGS+=$(call cc-option, -fno-gcse, "") +OP_CFLAGS+=$(call cc-option, -fno-tree-ch, "") +OP_CFLAGS+=$(call cc-option, -fno-optimize-sibling-calls, "") +OP_CFLAGS+=$(call cc-option, -fno-crossjumping, "") +OP_CFLAGS+=$(call cc-option, -fno-align-labels, "") +OP_CFLAGS+=$(call cc-option, -fno-align-jumps, "") +OP_CFLAGS+=$(call cc-option, -fno-align-functions, $(call cc-option, -malign-functions=0, "")) 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 @@ -163,11 +173,6 @@ 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 diff --git a/configure b/configure index 515d1f38e..d64fd04be 100755 --- a/configure +++ b/configure @@ -475,11 +475,6 @@ 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 @@ -654,9 +649,6 @@ echo "#define CONFIG_QEMU_SHAREDIR \"$prefix$datasuffix\"" >> $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 -- cgit v1.2.3 From b1f9be3157368392b62d5c4213413d5adddd015b Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Mar 2007 08:08:28 +0000 Subject: Add -cpu option for linux user emulation. Only usable for PowerPC and ARM for now. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2496 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index f96f96f6a..b5a0247c4 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1537,13 +1537,14 @@ void cpu_loop(CPUM68KState *env) void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n" - "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n" + "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] [-cpu model] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" "-h print this help\n" "-g port wait gdb connection to port\n" "-L path set the elf interpreter prefix (default=%s)\n" "-s size set the stack size in bytes (default=%ld)\n" + "-cpu model select CPU (-cpu ? for list)\n" "\n" "debug options:\n" #ifdef USE_CODE_COPY @@ -1567,6 +1568,7 @@ TaskState *first_task_state; int main(int argc, char **argv) { const char *filename; + const char *cpu_model; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; TaskState ts1, *ts = &ts1; @@ -1581,6 +1583,7 @@ int main(int argc, char **argv) /* init debug */ cpu_set_log_filename(DEBUG_LOGFILE); + cpu_model = NULL; optind = 1; for(;;) { if (optind >= argc) @@ -1631,6 +1634,18 @@ int main(int argc, char **argv) gdbstub_port = atoi(argv[optind++]); } else if (!strcmp(r, "r")) { qemu_uname_release = argv[optind++]; + } else if (!strcmp(r, "cpu")) { + cpu_model = argv[optind++]; + if (strcmp(cpu_model, "?") == 0) { +#if defined(TARGET_PPC) + ppc_cpu_list(stdout, &fprintf); +#elif defined(TARGET_ARM) + arm_cpu_list(); +#elif defined(TARGET_MIPS) + mips_cpu_list(stdout, &fprintf); +#endif + exit(1); + } } else #ifdef USE_CODE_COPY if (!strcmp(r, "no-code-copy")) { @@ -1756,7 +1771,9 @@ int main(int argc, char **argv) #elif defined(TARGET_ARM) { int i; - cpu_arm_set_model(env, "arm926"); + if (cpu_model == NULL) + cpu_model = "arm926"; + cpu_arm_set_model(env, cpu_model); cpsr_write(env, regs->uregs[16], 0xffffffff); for(i = 0; i < 16; i++) { env->regs[i] = regs->uregs[i]; @@ -1783,15 +1800,9 @@ int main(int argc, char **argv) int i; /* Choose and initialise CPU */ - /* XXX: CPU model (or PVR) should be provided on command line */ - // ppc_find_by_name("750gx", &def); - // ppc_find_by_name("750fx", &def); - // ppc_find_by_name("750p", &def); - ppc_find_by_name("750", &def); - // ppc_find_by_name("G3", &def); - // ppc_find_by_name("604r", &def); - // ppc_find_by_name("604e", &def); - // ppc_find_by_name("604", &def); + if (cpu_model == NULL) + cpu_model = "750"; + ppc_find_by_name(cpu_model, &def); if (def == NULL) { cpu_abort(env, "Unable to find PowerPC CPU definition\n"); @@ -1840,6 +1851,7 @@ int main(int argc, char **argv) { int i; + /* XXX: set CPU model */ for(i = 0; i < 32; i++) { env->gpr[i] = regs->regs[i]; } -- cgit v1.2.3 From cff4cbedc3ae945442034970c828f4a631fedcab Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 12:16:29 +0000 Subject: Support -cpu selection for mips usermode emulation. Fix segfault when dispaying the -cpu list help. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2497 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index b5a0247c4..0c5e6b5b4 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1644,7 +1644,7 @@ int main(int argc, char **argv) #elif defined(TARGET_MIPS) mips_cpu_list(stdout, &fprintf); #endif - exit(1); + _exit(1); } } else #ifdef USE_CODE_COPY @@ -1849,9 +1849,17 @@ int main(int argc, char **argv) } #elif defined(TARGET_MIPS) { + mips_def_t *def; int i; - /* XXX: set CPU model */ + /* Choose and initialise CPU */ + if (cpu_model == NULL) + cpu_model = "24Kf"; + mips_find_by_name(cpu_model, &def); + if (def == NULL) + cpu_abort(env, "Unable to find MIPS CPU definition\n"); + cpu_mips_register(env, def); + for(i = 0; i < 32; i++) { env->gpr[i] = regs->regs[i]; } -- cgit v1.2.3 From 0fa1bcb79081e3cf006e705145a07c7fb135e1b3 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 12:22:40 +0000 Subject: Solaris needs -lrt, spotted by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2498 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index d64fd04be..354f11097 100755 --- a/configure +++ b/configure @@ -159,7 +159,7 @@ if [ "$bsd" = "yes" ] ; then fi fi -if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then +if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then AIOLIBS= else AIOLIBS="-lrt" -- cgit v1.2.3 From 01c227fba4f1cefd47caa0aec8c5f503f0e29dc6 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 13:05:13 +0000 Subject: Fix allocation sizes in getpeername/getsockname, spotted by Kirill A. Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2499 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7e4b0594e..85f275cb7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -863,7 +863,7 @@ static long do_getpeername(int fd, target_ulong target_addr, target_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(target_addrlen); + void *addr = alloca(addrlen); long ret; ret = get_errno(getpeername(fd, addr, &addrlen)); @@ -878,7 +878,7 @@ static long do_getsockname(int fd, target_ulong target_addr, target_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(target_addrlen); + void *addr = alloca(addrlen); long ret; ret = get_errno(getsockname(fd, addr, &addrlen)); -- cgit v1.2.3 From d08d3bb8511c05b95042bbd5d5c8462a6a25a934 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 13:09:22 +0000 Subject: Add missing header includes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2500 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 85f275cb7..71788a8f1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include -- cgit v1.2.3 From b5906f958974df6f0fef821268bd1593ebefc143 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 13:32:45 +0000 Subject: Linux usermode clock_gettime/clock_getres emulation, by Kirill A. Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2501 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + linux-user/syscall.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/Makefile.target b/Makefile.target index 38899ff14..8be283577 100644 --- a/Makefile.target +++ b/Makefile.target @@ -208,6 +208,7 @@ endif ifdef CONFIG_LINUX_USER OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ elfload.o linuxload.o +LIBS+= $(AIOLIBS) ifdef TARGET_HAS_BFLT OBJS+= flatload.o endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 71788a8f1..5eb5b3931 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3990,6 +3990,29 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented_nowarn; #endif +#ifdef TARGET_NR_clock_gettime + case TARGET_NR_clock_gettime: + { + struct timespec ts; + ret = get_errno(clock_gettime(arg1, &ts)); + if (!is_error(ret)) { + host_to_target_timespec(arg2, &ts); + } + break; + } +#endif +#ifdef TARGET_NR_clock_getres + case TARGET_NR_clock_getres: + { + struct timespec ts; + ret = get_errno(clock_getres(arg1, &ts)); + if (!is_error(ret)) { + host_to_target_timespec(arg2, &ts); + } + break; + } +#endif + #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) case TARGET_NR_set_tid_address: ret = get_errno(set_tid_address((int *) arg1)); -- cgit v1.2.3 From ee999a8899ba8c6326cda4e2e70bb52b284cf7bb Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 13:43:04 +0000 Subject: Handling more darwin-user syscalls, by Ilya Shar. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2502 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/syscall.c | 34 ++++++++++++++++++++++++++++++++-- darwin-user/syscalls.h | 4 ++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c index f69a5aacd..ab3a7c15d 100644 --- a/darwin-user/syscall.c +++ b/darwin-user/syscall.c @@ -53,6 +53,8 @@ #include #include +#include + #include "qemu.h" //#define DEBUG_SYSCALL @@ -451,21 +453,49 @@ long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint3 case -31: DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", arg1, arg2, arg3, arg4, arg5, arg6, arg7); - ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7); - break; +/* may need more translation if target arch is different from host */ +#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__)) + case -33: + DPRINTF("semaphore_signal_trap(0x%x)\n", arg1); + ret = semaphore_signal_trap(arg1); + break; + case -34: + DPRINTF("semaphore_signal_all_trap(0x%x)\n", arg1); + ret = semaphore_signal_all_trap(arg1); + break; + case -35: + DPRINTF("semaphore_signal_thread_trap(0x%x)\n", arg1, arg2); + ret = semaphore_signal_thread_trap(arg1,arg2); + break; +#endif case -36: DPRINTF("semaphore_wait_trap(0x%x)\n", arg1); extern int semaphore_wait_trap(int); // XXX: is there any header for that? ret = semaphore_wait_trap(arg1); break; +/* may need more translation if target arch is different from host */ +#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__)) + case -37: + DPRINTF("semaphore_wait_signal_trap(0x%x, 0x%x)\n", arg1, arg2); + ret = semaphore_wait_signal_trap(arg1,arg2); + break; +#endif case -43: DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", arg1, arg2, arg3, arg4, arg5); ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5); tswap32s((uint32_t*)arg3); break; +/* may need more translation if target arch is different from host */ +#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__)) + case -61: + DPRINTF("syscall_thread_switch(0x%x, 0x%x, 0x%x)\n", + arg1, arg2, arg3); + ret = syscall_thread_switch(arg1, arg2, arg3); // just a hint to the scheduler; can drop? + break; +#endif case -89: DPRINTF("mach_timebase_info(0x%x)\n", arg1); struct mach_timebase_info info; diff --git a/darwin-user/syscalls.h b/darwin-user/syscalls.h index 7c361ce59..34d95daa7 100644 --- a/darwin-user/syscalls.h +++ b/darwin-user/syscalls.h @@ -42,7 +42,7 @@ ENTRY("getppid", SYS_getppid, getppid, 0, CALL_DIRECT, VOID) /* 39 */ ENTRY("", 40, no_syscall, 0, CALL_INDIRECT, VOID) /* 40 old lstat */ ENTRY("dup", SYS_dup, dup, 1, CALL_DIRECT, INT) /* 41 */ - ENTRY("pipe", SYS_pipe, unimpl_unix_syscall, 0, CALL_INDIRECT, PTR) /* 42 */ + ENTRY("pipe", SYS_pipe, pipe, 0, CALL_INDIRECT, PTR) /* 42 */ ENTRY("getegid", SYS_getegid, getegid, 0, CALL_NOERRNO, VOID) /* 43 */ ENTRY("profil", SYS_profil, profil, 4, CALL_DIRECT, PTR, SIZE, INT, INT) /* 44 */ ENTRY("ktrace", SYS_ktrace, no_syscall, 4, CALL_INDIRECT, VOID) /* 45 */ @@ -247,7 +247,7 @@ ENTRY("fsetxattr", SYS_fsetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 237 */ ENTRY("removexattr", SYS_removexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 238 */ ENTRY("fremovexattr", SYS_fremovexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 239 */ - ENTRY("listxattr", SYS_listxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 240 */ + ENTRY("listxattr", SYS_listxattr, listxattr, 4, CALL_INDIRECT, VOID) /* 240 */ ENTRY("flistxattr", SYS_flistxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 241 */ ENTRY("fsctl", SYS_fsctl, fsctl, 4, CALL_DIRECT, PTR, UINT, PTR, UINT) /* 242 */ ENTRY("initgroups", SYS_initgroups, unimpl_unix_syscall, 3, CALL_INDIRECT, UINT, PTR, INT) /* 243 */ -- cgit v1.2.3 From 8294eba18726b897c6a497b36ecd74a793f90523 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 14:47:40 +0000 Subject: SPARC host fixes, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2503 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/exec.h | 8 +------- target-mips/exec.h | 10 ---------- target-sparc/exec.h | 19 +------------------ 3 files changed, 2 insertions(+), 35 deletions(-) diff --git a/target-arm/exec.h b/target-arm/exec.h index deba89304..e73e12dc5 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -17,19 +17,13 @@ * 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 "dyngen-exec.h" -#if defined(__sparc__) -struct CPUARMState *env; -uint32_t T0; -uint32_t T1; -uint32_t T2; -#else register struct CPUARMState *env asm(AREG0); register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); register uint32_t T2 asm(AREG3); -#endif /* TODO: Put these in FP regs on targets that have such things. */ /* It is ok for FT0s and FT0d to overlap. Likewise FT1s and FT1d. */ diff --git a/target-mips/exec.h b/target-mips/exec.h index 3815a00c4..877221e56 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -7,11 +7,7 @@ #include "mips-defs.h" #include "dyngen-exec.h" -#if defined(__sparc__) -struct CPUMIPSState *env; -#else register struct CPUMIPSState *env asm(AREG0); -#endif #if defined (USE_64BITS_REGS) typedef int64_t host_int_t; @@ -21,11 +17,6 @@ typedef int32_t host_int_t; typedef uint32_t host_uint_t; #endif -#if defined(__sparc__) -host_uint_t T0; -host_uint_t T1; -host_uint_t T2; -#else #if TARGET_LONG_BITS > HOST_LONG_BITS #define T0 (env->t0) #define T1 (env->t1) @@ -35,7 +26,6 @@ register host_uint_t T0 asm(AREG1); register host_uint_t T1 asm(AREG2); register host_uint_t T2 asm(AREG3); #endif -#endif #if defined (USE_HOST_FLOAT_REGS) #error "implement me." diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 6e0515f6e..934f5ce96 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -1,13 +1,9 @@ #ifndef EXEC_SPARC_H #define EXEC_SPARC_H 1 -#include "dyngen-exec.h" #include "config.h" +#include "dyngen-exec.h" -#if defined(__sparc__) -struct CPUSPARCState *env; -#else register struct CPUSPARCState *env asm(AREG0); -#endif #ifdef TARGET_SPARC64 #define T0 (env->t0) @@ -15,13 +11,8 @@ register struct CPUSPARCState *env asm(AREG0); #define T2 (env->t2) #define REGWPTR env->regwptr #else -#if defined(__sparc__) -register uint32_t T0 asm(AREG3); -register uint32_t T1 asm(AREG2); -#else register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); -#endif #undef REG_REGWPTR // Broken #ifdef REG_REGWPTR @@ -33,11 +24,7 @@ register uint32_t *REGWPTR asm(AREG3); #define reg_REGWPTR #ifdef AREG4 -#if defined(__sparc__) -register uint32_t T2 asm(AREG0); -#else register uint32_t T2 asm(AREG4); -#endif #define reg_T2 #else #define T2 (env->t2) @@ -45,14 +32,10 @@ register uint32_t T2 asm(AREG4); #else #define REGWPTR env->regwptr -#if defined(__sparc__) -register uint32_t T2 asm(AREG0); -#else register uint32_t T2 asm(AREG3); #endif #define reg_T2 #endif -#endif #define FT0 (env->ft0) #define FT1 (env->ft1) -- cgit v1.2.3 From dcfb90144bd83a13e24f214e0c4a1b0b55067289 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 14:49:29 +0000 Subject: SCSI fixes, by Wang Cheng Yeh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2504 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lsi53c895a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 41c1ff22d..07e09f3cc 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -251,7 +251,7 @@ typedef struct { uint32_t ia; uint32_t sbc; uint32_t csbc; - uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ + uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */ /* Script ram is stored as 32-bit words in host byteorder. */ uint32_t script_ram[2048]; @@ -1038,7 +1038,7 @@ again: op0 |= op1; break; case 3: /* XOR */ - op0 |= op1; + op0 ^= op1; break; case 4: /* AND */ op0 &= op1; @@ -1765,7 +1765,7 @@ static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val) lsi_reg_writeb(s, addr, val & 0xff); lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff); - lsi_reg_writeb(s, addr + 2, (val >> 24) & 0xff); + lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff); } static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num, -- cgit v1.2.3 From c35734b2a6f9b028edacd5813ff271728ce2a9e3 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 15:17:08 +0000 Subject: Add -name option, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2505 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 8 ++++++++ qemu-doc.texi | 4 ++++ sdl.c | 19 ++++++++++++------- vl.c | 9 ++++++++- vl.h | 1 + vnc.c | 11 +++++++++-- 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/monitor.c b/monitor.c index de0783bf9..379733333 100644 --- a/monitor.c +++ b/monitor.c @@ -235,6 +235,12 @@ static void do_info_version(void) term_printf("%s\n", QEMU_VERSION); } +static void do_info_name(void) +{ + if (qemu_name) + term_printf("%s\n", qemu_name); +} + static void do_info_block(void) { bdrv_info(); @@ -1314,6 +1320,8 @@ static term_cmd_t info_cmds[] = { "", "show which guest mouse is receiving events" }, { "vnc", "", do_info_vnc, "", "show the vnc server status"}, + { "name", "", do_info_name, + "", "show the current VM name" }, #if defined(TARGET_PPC) { "cpustats", "", do_info_cpu_stats, "", "show CPU statistics", }, diff --git a/qemu-doc.texi b/qemu-doc.texi index 1acd7451a..74d0edf05 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -331,6 +331,10 @@ slows down the IDE transfers). Load the contents of file as an option ROM. This option is useful to load things like EtherBoot. +@item -name string +Sets the name of the guest. This name will be display in the SDL window +caption. The name will also be used for the VNC server. + @end table USB options: diff --git a/sdl.c b/sdl.c index 0cb22411d..aa5c66992 100644 --- a/sdl.c +++ b/sdl.c @@ -216,13 +216,18 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) static void sdl_update_caption(void) { char buf[1024]; - strcpy(buf, "QEMU"); - if (!vm_running) { - strcat(buf, " [Stopped]"); - } - if (gui_grab) { - strcat(buf, " - Press Ctrl-Alt to exit grab"); - } + const char *status = ""; + + if (!vm_running) + status = " [Stopped]"; + else if (gui_grab) + status = " - Press Ctrl-Alt to exit grab"; + + if (qemu_name) + snprintf(buf, sizeof(buf), "QEMU (%s)%s", qemu_name, status); + else + snprintf(buf, sizeof(buf), "QEMU%s", status); + SDL_WM_SetCaption(buf, "QEMU"); } diff --git a/vl.c b/vl.c index fc0f8ff4c..86677854b 100644 --- a/vl.c +++ b/vl.c @@ -189,6 +189,7 @@ const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; int autostart = 1; +const char *qemu_name; /***********************************************************/ /* x86 ISA bus support */ @@ -6395,6 +6396,7 @@ void help(void) #if defined(TARGET_PPC) || defined(TARGET_SPARC) "-g WxH[xDEPTH] Set the initial graphical resolution and depth\n" #endif + "-name string set the name of the guest\n" "\n" "Network options:\n" "-net nic[,vlan=n][,macaddr=addr][,model=type]\n" @@ -6553,7 +6555,8 @@ enum { QEMU_OPTION_no_reboot, QEMU_OPTION_daemonize, QEMU_OPTION_option_rom, - QEMU_OPTION_semihosting + QEMU_OPTION_semihosting, + QEMU_OPTION_name, }; typedef struct QEMUOption { @@ -6644,6 +6647,7 @@ const QEMUOption qemu_options[] = { #if defined(TARGET_ARM) { "semihosting", 0, QEMU_OPTION_semihosting }, #endif + { "name", HAS_ARG, QEMU_OPTION_name }, { NULL }, }; @@ -7340,6 +7344,9 @@ int main(int argc, char **argv) case QEMU_OPTION_semihosting: semihosting_enabled = 1; break; + case QEMU_OPTION_name: + qemu_name = optarg; + break; } } } diff --git a/vl.h b/vl.h index 464bf899c..b911f92b4 100644 --- a/vl.h +++ b/vl.h @@ -114,6 +114,7 @@ void hw_error(const char *fmt, ...); extern const char *bios_dir; extern int vm_running; +extern const char *qemu_name; typedef struct vm_change_state_entry VMChangeStateEntry; typedef void VMChangeStateHandler(void *opaque, int running); diff --git a/vnc.c b/vnc.c index f729e05d8..aba60d4c2 100644 --- a/vnc.c +++ b/vnc.c @@ -1056,6 +1056,8 @@ static int protocol_client_msg(VncState *vs, char *data, size_t len) static int protocol_client_init(VncState *vs, char *data, size_t len) { char pad[3] = { 0, 0, 0 }; + char buf[1024]; + int size; vs->width = vs->ds->width; vs->height = vs->ds->height; @@ -1100,8 +1102,13 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) vnc_write(vs, pad, 3); /* padding */ - vnc_write_u32(vs, 4); - vnc_write(vs, "QEMU", 4); + if (qemu_name) + size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name); + else + size = snprintf(buf, sizeof(buf), "QEMU"); + + vnc_write_u32(vs, size); + vnc_write(vs, buf, size); vnc_flush(vs); vnc_read_when(vs, protocol_client_msg, 1); -- cgit v1.2.3 From 93815bc280744c05abab9501eeb53edd01190e1b Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 15:58:31 +0000 Subject: Improve -pidfile option, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2506 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 81 +++++++++++++++++++++++++++++++------------------------------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/vl.c b/vl.c index 86677854b..e77ed4124 100644 --- a/vl.c +++ b/vl.c @@ -4387,44 +4387,24 @@ void usb_info(void) } } -/***********************************************************/ -/* pid file */ - -static char *pid_filename; +static int create_pidfile(const char *filename) +{ + int fd; + char buffer[128]; + int len; -/* Remove PID file. Called on normal exit */ + fd = open(filename, O_RDWR | O_CREAT, 0600); + if (fd == -1) + return -1; -static void remove_pidfile(void) -{ - unlink (pid_filename); -} + if (lockf(fd, F_TLOCK, 0) == -1) + return -1; -static void create_pidfile(const char *filename) -{ - struct stat pidstat; - FILE *f; + len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); + if (write(fd, buffer, len) != len) + return -1; - /* Try to write our PID to the named file */ - if (stat(filename, &pidstat) < 0) { - if (errno == ENOENT) { - if ((f = fopen (filename, "w")) == NULL) { - perror("Opening pidfile"); - exit(1); - } - fprintf(f, "%d\n", getpid()); - fclose(f); - pid_filename = qemu_strdup(filename); - if (!pid_filename) { - fprintf(stderr, "Could not save PID filename"); - exit(1); - } - atexit(remove_pidfile); - } - } else { - fprintf(stderr, "%s already exists. Remove it and try again.\n", - filename); - exit(1); - } + return 0; } /***********************************************************/ @@ -6880,6 +6860,7 @@ int main(int argc, char **argv) char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; int fds[2]; + const char *pid_file = NULL; LIST_INIT (&vm_change_state_head); #ifndef _WIN32 @@ -7285,7 +7266,7 @@ int main(int argc, char **argv) break; #endif case QEMU_OPTION_pidfile: - create_pidfile(optarg); + pid_file = optarg; break; #ifdef TARGET_I386 case QEMU_OPTION_win2k_hack: @@ -7371,16 +7352,19 @@ int main(int argc, char **argv) close(fds[1]); again: - len = read(fds[0], &status, 1); - if (len == -1 && (errno == EINTR)) - goto again; - - if (len != 1 || status != 0) - exit(1); - else - exit(0); + len = read(fds[0], &status, 1); + if (len == -1 && (errno == EINTR)) + goto again; + + if (len != 1) + exit(1); + else if (status == 1) { + fprintf(stderr, "Could not acquire pidfile\n"); + exit(1); + } else + exit(0); } else if (pid < 0) - exit(1); + exit(1); setsid(); @@ -7399,6 +7383,15 @@ int main(int argc, char **argv) } #endif + if (pid_file && create_pidfile(pid_file) != 0) { + if (daemonize) { + uint8_t status = 1; + write(fds[1], &status, 1); + } else + fprintf(stderr, "Could not acquire pid file\n"); + exit(1); + } + #ifdef USE_KQEMU if (smp_cpus > 1) kqemu_allowed = 0; -- cgit v1.2.3 From 50d3eeae384382671952bc40e00a58f5ab00fed0 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 16:36:43 +0000 Subject: Close file descriptors when execing network tap setup script, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2507 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vl.c b/vl.c index e77ed4124..f368d9bba 100644 --- a/vl.c +++ b/vl.c @@ -3621,6 +3621,14 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, pid = fork(); if (pid >= 0) { if (pid == 0) { + int open_max = sysconf (_SC_OPEN_MAX), i; + for (i = 0; i < open_max; i++) + if (i != STDIN_FILENO && + i != STDOUT_FILENO && + i != STDERR_FILENO && + i != fd) + close(i); + parg = args; *parg++ = (char *)setup_script; *parg++ = ifname; -- cgit v1.2.3 From 63a654bb39bd6d154a535c535190b1f3a9d27699 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 16:46:07 +0000 Subject: trunc() for Solaris 9 / SPARC, by Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2508 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index f20d5c45f..7b28a4cfe 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -221,6 +221,12 @@ float128 float64_to_float128( float64 a STATUS_PARAM) /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ +#if ( defined(__sun__) && ( HOST_SOLARIS < 10 )) +static inline float64 trunc(float64 x) +{ + return x < 0 ? -floor(-x) : floor(x); +} +#endif float64 float64_trunc_to_int( float64 a STATUS_PARAM ) { return trunc(a); -- cgit v1.2.3 From 290a0933c0488a5072bed5458b1b9fe4dc84cba4 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 18:20:28 +0000 Subject: Fix big endian host operation, by Ben Taylor and Igor Kovalenko. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2509 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/rtl8139.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 94fc2fca3..6ca275a3d 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -1192,7 +1192,10 @@ static void rtl8139_reset(RTL8139State *s) s->eeprom.contents[1] = 0x10ec; s->eeprom.contents[2] = 0x8139; #endif - memcpy(&s->eeprom.contents[7], s->macaddr, 6); + + s->eeprom.contents[7] = s->macaddr[0] | s->macaddr[1] << 8; + s->eeprom.contents[8] = s->macaddr[2] | s->macaddr[3] << 8; + s->eeprom.contents[9] = s->macaddr[4] | s->macaddr[5] << 8; /* mark all status registers as owned by host */ for (i = 0; i < 4; ++i) @@ -2455,12 +2458,12 @@ static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_ { DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); - s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); + s->TxAddr[txAddrOffset/4] = val; } static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) { - uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]); + uint32_t ret = s->TxAddr[txAddrOffset/4]; DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret)); -- cgit v1.2.3 From 9bb234b3b170299c39c9e88cfe7da5434a92d99d Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 19:16:00 +0000 Subject: Fix qemu crash due to sparc division-by-zero, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2510 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target-sparc/op.c b/target-sparc/op.c index fd30e90e1..9e16a29a4 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -671,6 +671,11 @@ void OPPROTO op_udiv_T1_T0(void) x0 = T0 | ((uint64_t) (env->y) << 32); x1 = T1; + + if (x1 == 0) { + raise_exception(TT_DIV_ZERO); + } + x0 = x0 / x1; if (x0 > 0xffffffff) { T0 = 0xffffffff; @@ -689,6 +694,11 @@ void OPPROTO op_sdiv_T1_T0(void) x0 = T0 | ((int64_t) (env->y) << 32); x1 = T1; + + if (x1 == 0) { + raise_exception(TT_DIV_ZERO); + } + x0 = x0 / x1; if ((int32_t) x0 != x0) { T0 = x0 < 0? 0x80000000: 0x7fffffff; -- cgit v1.2.3 From faab7592c76ea67c970708c1cb64757bb178062e Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 20:39:49 +0000 Subject: Fix call to generated code on SPARC, by Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2511 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cpu-exec.c b/cpu-exec.c index 48c2a93a7..634f1ba87 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -648,6 +648,7 @@ int cpu_exec(CPUState *env1) : /* no outputs */ : "r" (gen_func) : "i0", "i1", "i2", "i3", "i4", "i5", + "o0", "o1", "o2", "o3", "o4", "o5", "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7"); #elif defined(__arm__) -- cgit v1.2.3 From 820e00f252239465e1df507b6fabcffd6b7b6983 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 21:46:06 +0000 Subject: Define gen_intermediate_code_internal as "static inline". git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2512 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/translate.c | 5 +++-- target-mips/translate.c | 5 +++-- target-ppc/translate.c | 5 +++-- target-sh4/translate.c | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 9c34c626b..5d47c5469 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2551,8 +2551,9 @@ optimize_flags(void) #endif /* generate intermediate code for basic block 'tb'. */ -int gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, - int search_pc) +static inline int +gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, + int search_pc) { DisasContext dc1, *dc = &dc1; uint16_t *gen_opc_end; diff --git a/target-mips/translate.c b/target-mips/translate.c index 75e30692a..6ae3c68ca 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4999,8 +4999,9 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } } -int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, - int search_pc) +static inline int +gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, + int search_pc) { DisasContext ctx, *ctxp = &ctx; target_ulong pc_start; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 82919a587..d9be35d6c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4604,8 +4604,9 @@ void cpu_dump_statistics (CPUState *env, FILE*f, } /*****************************************************************************/ -int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, - int search_pc) +static inline int +gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, + int search_pc) { DisasContext ctx, *ctxp = &ctx; opc_handler_t **table, *handler; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 358f975e0..1c9fe40f5 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1087,8 +1087,9 @@ void decode_opc(DisasContext * ctx) ctx->flags |= BRANCH_EXCEPTION; } -int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, - int search_pc) +static inline int +gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, + int search_pc) { DisasContext ctx; target_ulong pc_start; -- cgit v1.2.3 From 3ad4bb2d3d22f3be94db7bcabac8586cfb222efb Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Mar 2007 22:15:30 +0000 Subject: Barf on branches/jumps in branch delay slots. Spotted by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2513 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 6ae3c68ca..b39ec5f98 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1368,12 +1368,20 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) static void gen_compute_branch (DisasContext *ctx, uint32_t opc, int rs, int rt, int32_t offset) { - target_ulong btarget; - int blink, bcond; + target_ulong btarget = -1; + int blink = 0; + int bcond = 0; + + if (ctx->hflags & MIPS_HFLAG_BMASK) { + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, + "undefined branch in delay slot at pc 0x%08x\n", ctx->pc); + } + MIPS_INVAL("branch/jump in bdelay slot"); + generate_exception(ctx, EXCP_RI); + return; + } - btarget = -1; - blink = 0; - bcond = 0; /* Load needed operands */ switch (opc) { case OPC_BEQ: -- cgit v1.2.3 From 548df2acc6fcd12169583e7e7e25b33600cc20e7 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Mar 2007 16:45:27 +0000 Subject: VMMouse Emulation, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2514 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/pckbd.c | 3 + hw/ps2.c | 5 + hw/vmmouse.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 3 + 5 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 hw/vmmouse.c diff --git a/Makefile.target b/Makefile.target index 8be283577..b52656434 100644 --- a/Makefile.target +++ b/Makefile.target @@ -377,7 +377,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) 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 mixeng.o apic.o parallel.o acpi.o piix_pci.o -VL_OBJS+= usb-uhci.o smbus_eeprom.o +VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff --git a/hw/pckbd.c b/hw/pckbd.c index de40a09aa..0ace3c0c9 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -372,6 +372,9 @@ void i8042_init(int kbd_irq_lvl, int mouse_irq_lvl, uint32_t io_base) s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); +#ifdef TARGET_I386 + vmmouse_init(s->mouse); +#endif qemu_register_reset(kbd_reset, s); } diff --git a/hw/ps2.c b/hw/ps2.c index 3794c6036..2d87f1f12 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -324,6 +324,11 @@ static void ps2_mouse_event(void *opaque, } } +void ps2_mouse_fake_event(void *opaque) +{ + ps2_mouse_event(opaque, 1, 0, 0, 0); +} + void ps2_write_mouse(void *opaque, int val) { PS2MouseState *s = (PS2MouseState *)opaque; diff --git a/hw/vmmouse.c b/hw/vmmouse.c new file mode 100644 index 000000000..cc783008d --- /dev/null +++ b/hw/vmmouse.c @@ -0,0 +1,300 @@ +/* + * QEMU VMMouse emulation + * + * Copyright (C) 2007 Anthony Liguori + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* debug only vmmouse */ +//#define DEBUG_VMMOUSE + +/* VMMouse Commands */ +#define VMMOUSE_GETVERSION 10 +#define VMMOUSE_DATA 39 +#define VMMOUSE_STATUS 40 +#define VMMOUSE_COMMAND 41 + +#define VMMOUSE_READ_ID 0x45414552 +#define VMMOUSE_DISABLE 0x000000f5 +#define VMMOUSE_REQUEST_RELATIVE 0x4c455252 +#define VMMOUSE_REQUEST_ABSOLUTE 0x53424152 + +#define VMMOUSE_QUEUE_SIZE 1024 + +#define VMMOUSE_MAGIC 0x564D5868 +#define VMMOUSE_VERSION 0x3442554a + +#ifdef DEBUG_VMMOUSE +#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DPRINTF(fmt, ...) do { } while (0) +#endif + +typedef struct _VMMouseState +{ + uint32_t queue[VMMOUSE_QUEUE_SIZE]; + uint16_t nb_queue; + uint16_t status; + uint8_t absolute; + QEMUPutMouseEntry *entry; + void *ps2_mouse; +} VMMouseState; + +static uint32_t vmmouse_get_version(VMMouseState *s, uint32_t *magic) +{ + DPRINTF("vmmouse_get_version(%x)\n", *magic); + *magic = VMMOUSE_MAGIC; + return VMMOUSE_VERSION; +} + +static uint32_t vmmouse_get_status(VMMouseState *s) +{ + DPRINTF("vmmouse_get_status()\n"); + return (s->status << 16) | s->nb_queue; +} + +static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state) +{ + VMMouseState *s = opaque; + int buttons = 0; + + if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4)) + return; + + DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n", + x, y, dz, buttons_state); + + if ((buttons_state & MOUSE_EVENT_LBUTTON)) + buttons |= 0x20; + if ((buttons_state & MOUSE_EVENT_RBUTTON)) + buttons |= 0x10; + if ((buttons_state & MOUSE_EVENT_MBUTTON)) + buttons |= 0x08; + + if (s->absolute) { + x <<= 1; + y <<= 1; + } + + s->queue[s->nb_queue++] = buttons; + s->queue[s->nb_queue++] = x; + s->queue[s->nb_queue++] = y; + s->queue[s->nb_queue++] = dz; + + /* need to still generate PS2 events to notify driver to + read from queue */ + ps2_mouse_fake_event(s->ps2_mouse); +} + +static void vmmouse_update_handler(VMMouseState *s) +{ + if (s->entry) { + qemu_remove_mouse_event_handler(s->entry); + s->entry = NULL; + } + if (s->status == 0) + s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event, + s, s->absolute, + "vmmouse"); +} + +static void vmmouse_read_id(VMMouseState *s) +{ + DPRINTF("vmmouse_read_id()\n"); + + if (s->nb_queue == VMMOUSE_QUEUE_SIZE) + return; + + s->queue[s->nb_queue++] = VMMOUSE_VERSION; + s->status = 0; + vmmouse_update_handler(s); +} + +static void vmmouse_request_relative(VMMouseState *s) +{ + DPRINTF("vmmouse_request_relative()\n"); + s->absolute = 0; + vmmouse_update_handler(s); +} + +static void vmmouse_request_absolute(VMMouseState *s) +{ + DPRINTF("vmmouse_request_absolute()\n"); + s->absolute = 1; + vmmouse_update_handler(s); +} + +static void vmmouse_disable(VMMouseState *s) +{ + DPRINTF("vmmouse_disable()\n"); + s->status = 0xffff; + vmmouse_update_handler(s); +} + +static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size) +{ + int i; + + DPRINTF("vmmouse_data(%d)\n", size); + + if (size == 0 || size > 6 || size > s->nb_queue) { + printf("vmmouse: driver requested too much data %d\n", size); + s->status = 0xffff; + vmmouse_update_handler(s); + return; + } + + for (i = 0; i < size; i++) + data[i] = s->queue[i]; + + s->nb_queue -= size; + if (s->nb_queue) + memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue); +} + +static void vmmouse_get_data(uint32_t *data) +{ + CPUState *env = cpu_single_env; + + data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX]; + data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX]; + data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI]; + + DPRINTF("get_data = {%x, %x, %x, %x, %x, %x}\n", + data[0], data[1], data[2], data[3], data[4], data[5]); +} + +static void vmmouse_set_data(const uint32_t *data) +{ + CPUState *env = cpu_single_env; + + DPRINTF("set_data = {%x, %x, %x, %x, %x, %x}\n", + data[0], data[1], data[2], data[3], data[4], data[5]); + + env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1]; + env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3]; + env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; +} + +static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr) +{ + VMMouseState *s = opaque; + uint32_t data[6]; + uint16_t command; + + vmmouse_get_data(data); + if (data[0] != VMMOUSE_MAGIC) + goto error; + + command = data[2] & 0xFFFF; + + switch (command) { + case VMMOUSE_GETVERSION: + data[0] = vmmouse_get_version(s, &data[1]); + break; + case VMMOUSE_STATUS: + data[0] = vmmouse_get_status(s); + break; + case VMMOUSE_COMMAND: + switch (data[1]) { + case VMMOUSE_DISABLE: + vmmouse_disable(s); + break; + case VMMOUSE_READ_ID: + vmmouse_read_id(s); + break; + case VMMOUSE_REQUEST_RELATIVE: + vmmouse_request_relative(s); + break; + case VMMOUSE_REQUEST_ABSOLUTE: + vmmouse_request_absolute(s); + break; + default: + printf("vmmouse: unknown command %x\n", data[1]); + break; + } + break; + case VMMOUSE_DATA: + vmmouse_data(s, data, data[1]); + break; + default: + printf("vmmouse: unknown command %x\n", command); + break; + } + +error: + vmmouse_set_data(data); + return data[0]; +} + +static void vmmouse_save(QEMUFile *f, void *opaque) +{ + VMMouseState *s = opaque; + int i; + + qemu_put_be32(f, VMMOUSE_QUEUE_SIZE); + for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++) + qemu_put_be32s(f, &s->queue[i]); + qemu_put_be16s(f, &s->nb_queue); + qemu_put_be16s(f, &s->status); + qemu_put_8s(f, &s->absolute); +} + +static int vmmouse_load(QEMUFile *f, void *opaque, int version_id) +{ + VMMouseState *s = opaque; + int i; + + if (version_id != 0) + return -EINVAL; + + if (qemu_get_be32(f) != VMMOUSE_QUEUE_SIZE) + return -EINVAL; + for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++) + qemu_get_be32s(f, &s->queue[i]); + qemu_get_be16s(f, &s->nb_queue); + qemu_get_be16s(f, &s->status); + qemu_get_8s(f, &s->absolute); + + vmmouse_update_handler(s); + + return 0; +} + +void *vmmouse_init(void *m) +{ + VMMouseState *s = NULL; + + DPRINTF("vmmouse_init\n"); + + s = qemu_mallocz(sizeof(VMMouseState)); + if (!s) + return NULL; + + s->status = 0xffff; + s->ps2_mouse = m; + + register_ioport_read(0x5658, 1, 4, vmmouse_ioport_read, s); + register_savevm("vmmouse", 0, 0, vmmouse_save, vmmouse_load, s); + + return s; +} + diff --git a/vl.h b/vl.h index b911f92b4..61b5b80f7 100644 --- a/vl.h +++ b/vl.h @@ -1005,6 +1005,8 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); void pcnet_h_reset(void *opaque); void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque); +/* vmmouse.c */ +void *vmmouse_init(void *m); /* pckbd.c */ @@ -1326,6 +1328,7 @@ void ps2_write_keyboard(void *, int val); uint32_t ps2_read_data(void *); void ps2_queue(void *, int b); void ps2_keyboard_set_translation(void *opaque, int mode); +void ps2_mouse_fake_event(void *opaque); /* smc91c111.c */ void smc91c111_init(NICInfo *, uint32_t, void *, int); -- cgit v1.2.3 From 491730f3287a5dec9a8ff45a80ee80c6682d49e5 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Mar 2007 16:52:54 +0000 Subject: SlavIO interrupt controller fix, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2515 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 288fb50f0..456d9672e 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -293,6 +293,7 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) if (level) { s->intregm_pending |= mask; s->intreg_pending[s->target_cpu] |= 1 << pil; + slavio_check_interrupts(s); } else { s->intregm_pending &= ~mask; @@ -300,7 +301,6 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) } } } - slavio_check_interrupts(s); } void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu) -- cgit v1.2.3 From dc3c9d213d70d5ecb41ba4130c1f23b3e8c51e0b Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Mar 2007 16:54:50 +0000 Subject: SlavIO Counter-Timers fix, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2516 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_timer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 976f0d4db..828d340b3 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -131,7 +131,6 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) if (s->mode != 1) { // clear irq pic_set_irq_cpu(s->irq, 0, s->cpu); - s->count_load_time = qemu_get_clock(vm_clock); s->reached = 0; return s->limit; } -- cgit v1.2.3 From b1e341ebb7fc177434e2fda728174fc0e962578e Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Mar 2007 21:50:52 +0000 Subject: fcntl64 fix, by Kirill A. Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2517 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5eb5b3931..5ff364d16 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3872,15 +3872,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #if TARGET_LONG_BITS == 32 case TARGET_NR_fcntl64: { + int cmd; struct flock64 fl; struct target_flock64 *target_fl; #ifdef TARGET_ARM struct target_eabi_flock64 *target_efl; #endif + switch(arg2){ + case TARGET_F_GETLK64: + cmd = F_GETLK64; + case TARGET_F_SETLK64: + cmd = F_SETLK64; + case TARGET_F_SETLKW64: + cmd = F_SETLK64; + default: + cmd = arg2; + } + switch(arg2) { - case F_GETLK64: - ret = get_errno(fcntl(arg1, arg2, &fl)); + case TARGET_F_GETLK64: + ret = get_errno(fcntl(arg1, cmd, &fl)); if (ret == 0) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { @@ -3905,8 +3917,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; - case F_SETLK64: - case F_SETLKW64: + case TARGET_F_SETLK64: + case TARGET_F_SETLKW64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { lock_user_struct(target_efl, arg3, 1); @@ -3927,10 +3939,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, fl.l_pid = tswapl(target_fl->l_pid); unlock_user_struct(target_fl, arg3, 0); } - ret = get_errno(fcntl(arg1, arg2, &fl)); + ret = get_errno(fcntl(arg1, cmd, &fl)); break; default: - ret = get_errno(do_fcntl(arg1, arg2, arg3)); + ret = get_errno(do_fcntl(arg1, cmd, arg3)); break; } break; -- cgit v1.2.3 From 75d62a585629cdc1ae0d530189653cb1d8d9c53c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 20 Mar 2007 22:10:42 +0000 Subject: Add missing softfloat helpers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2518 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ fpu/softfloat-native.h | 10 ++++++ fpu/softfloat.c | 48 +++++++++++++++++++++++++ fpu/softfloat.h | 4 +++ 4 files changed, 158 insertions(+) diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 7b28a4cfe..c629926f8 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -59,11 +59,21 @@ float32 int32_to_float32(int v STATUS_PARAM) return (float32)v; } +float32 uint32_to_float32(unsigned int v STATUS_PARAM) +{ + return (float32)v; +} + float64 int32_to_float64(int v STATUS_PARAM) { return (float64)v; } +float64 uint32_to_float64(unsigned int v STATUS_PARAM) +{ + return (float64)v; +} + #ifdef FLOATX80 floatx80 int32_to_floatx80(int v STATUS_PARAM) { @@ -74,10 +84,18 @@ float32 int64_to_float32( int64_t v STATUS_PARAM) { return (float32)v; } +float32 uint64_to_float32( uint64_t v STATUS_PARAM) +{ + return (float32)v; +} float64 int64_to_float64( int64_t v STATUS_PARAM) { return (float64)v; } +float64 uint64_to_float64( uint64_t v STATUS_PARAM) +{ + return (float64)v; +} #ifdef FLOATX80 floatx80 int64_to_floatx80( int64_t v STATUS_PARAM) { @@ -132,6 +150,37 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM) } #endif +unsigned int float32_to_uint32( float32 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = llrintf(a); + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = (int64_t)a; + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision operations. *----------------------------------------------------------------------------*/ @@ -218,6 +267,53 @@ float128 float64_to_float128( float64 a STATUS_PARAM) } #endif +unsigned int float64_to_uint32( float64 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = llrint(a); + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM) +{ + int64_t v; + unsigned int res; + + v = (int64_t)a; + if (v < 0) { + res = 0; + } else if (v > 0xffffffff) { + res = 0xffffffff; + } else { + res = v; + } + return res; +} +uint64_t float64_to_uint64 (float64 a STATUS_PARAM) +{ + int64_t v; + + v = llrint(a + (float64)INT64_MIN); + + return v - INT64_MIN; +} +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) +{ + int64_t v; + + v = (int64_t)(a + (float64)INT64_MIN); + + return v - INT64_MIN; +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 8c2770877..8a0d1ad37 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -99,7 +99,9 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM); | Software IEC/IEEE integer-to-floating-point conversion routines. *----------------------------------------------------------------------------*/ float32 int32_to_float32( int STATUS_PARAM); +float32 uint32_to_float32( unsigned int STATUS_PARAM); float64 int32_to_float64( int STATUS_PARAM); +float64 uint32_to_float64( unsigned int STATUS_PARAM); #ifdef FLOATX80 floatx80 int32_to_floatx80( int STATUS_PARAM); #endif @@ -107,7 +109,9 @@ floatx80 int32_to_floatx80( int STATUS_PARAM); float128 int32_to_float128( int STATUS_PARAM); #endif float32 int64_to_float32( int64_t STATUS_PARAM); +float32 uint64_to_float32( uint64_t STATUS_PARAM); float64 int64_to_float64( int64_t STATUS_PARAM); +float64 uint64_to_float64( uint64_t v STATUS_PARAM); #ifdef FLOATX80 floatx80 int64_to_floatx80( int64_t STATUS_PARAM); #endif @@ -120,6 +124,8 @@ float128 int64_to_float128( int64_t STATUS_PARAM); *----------------------------------------------------------------------------*/ int float32_to_int32( float32 STATUS_PARAM); int float32_to_int32_round_to_zero( float32 STATUS_PARAM); +unsigned int float32_to_uint32( float32 a STATUS_PARAM); +unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM); int64_t float32_to_int64( float32 STATUS_PARAM); int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM); float64 float32_to_float64( float32 STATUS_PARAM); @@ -200,8 +206,12 @@ INLINE float32 float32_chs(float32 a) *----------------------------------------------------------------------------*/ int float64_to_int32( float64 STATUS_PARAM ); int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +unsigned int float64_to_uint32( float64 STATUS_PARAM ); +unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); int64_t float64_to_int64( float64 STATUS_PARAM ); int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +uint64_t float64_to_uint64( float64 STATUS_PARAM ); +uint64_t float64_to_uint64_round_to_zero( float64 STATUS_PARAM ); float32 float64_to_float32( float64 STATUS_PARAM ); #ifdef FLOATX80 floatx80 float64_to_floatx80( float64 STATUS_PARAM ); diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5dbfa81e4..52e2db121 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1164,6 +1164,27 @@ float32 int64_to_float32( int64 a STATUS_PARAM ) } +float64 uint64_to_float32( uint64 a STATUS_PARAM ) +{ + int8 shiftCount; + + if ( a == 0 ) return 0; + shiftCount = countLeadingZeros64( a ) - 40; + if ( 0 <= shiftCount ) { + return packFloat32( 1 > 0, 0x95 - shiftCount, a< 0, 0x9C - shiftCount, a STATUS_VAR ); + } +} + /*---------------------------------------------------------------------------- | Returns the result of converting the 64-bit two's complement integer `a' | to the double-precision floating-point format. The conversion is performed @@ -1183,6 +1204,13 @@ float64 int64_to_float64( int64 a STATUS_PARAM ) } +float64 uint64_to_float64( uint64 a STATUS_PARAM ) +{ + if ( a == 0 ) return 0; + return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR ); + +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -5282,6 +5310,26 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) return res; } +uint64_t float64_to_uint64 (float64 a STATUS_PARAM) +{ + int64_t v; + + v = int64_to_float64(INT64_MIN STATUS_VAR); + v = float64_to_int64((a + v) STATUS_VAR); + + return v - INT64_MIN; +} + +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) +{ + int64_t v; + + v = int64_to_float64(INT64_MIN STATUS_VAR); + v = float64_to_int64_round_to_zero((a + v) STATUS_VAR); + + return v - INT64_MIN; +} + #define COMPARE(s, nan_exp) \ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ int is_quiet STATUS_PARAM ) \ diff --git a/fpu/softfloat.h b/fpu/softfloat.h index a326af832..00ec56b05 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -193,7 +193,9 @@ floatx80 int32_to_floatx80( int STATUS_PARAM ); float128 int32_to_float128( int STATUS_PARAM ); #endif float32 int64_to_float32( int64_t STATUS_PARAM ); +float32 uint64_to_float32( uint64_t STATUS_PARAM ); float64 int64_to_float64( int64_t STATUS_PARAM ); +float64 uint64_to_float64( uint64_t STATUS_PARAM ); #ifdef FLOATX80 floatx80 int64_to_floatx80( int64_t STATUS_PARAM ); #endif @@ -258,6 +260,8 @@ unsigned int float64_to_uint32( float64 STATUS_PARAM ); unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); int64_t float64_to_int64( float64 STATUS_PARAM ); int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); +uint64_t float64_to_uint64 (float64 a STATUS_PARAM); +uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM); float32 float64_to_float32( float64 STATUS_PARAM ); #ifdef FLOATX80 floatx80 float64_to_floatx80( float64 STATUS_PARAM ); -- cgit v1.2.3 From 0487d6a8b4e15383d0651eea1e4e03ded44308b2 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 20 Mar 2007 22:11:31 +0000 Subject: PowerPC 2.03 SPE extension - first pass. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2519 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 82 +++-- target-ppc/exec.h | 6 +- target-ppc/op.c | 815 ++++++++++++++++++++++++++++++++++++----- target-ppc/op_helper.c | 869 +++++++++++++++++++++++++++++++++++++++++++- target-ppc/op_helper.h | 281 ++++++++++++++ target-ppc/op_mem.h | 274 +++++++++++++- target-ppc/op_template.h | 42 +++ target-ppc/translate.c | 822 ++++++++++++++++++++++++++++++++++++++++- target-ppc/translate_init.c | 5 +- 9 files changed, 3050 insertions(+), 146 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 5b1af4152..e2294134d 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -26,15 +26,20 @@ #if defined (TARGET_PPC64) typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 64 +#define TARGET_GPR_BITS 64 #define REGX "%016" PRIx64 -#elif defined(TARGET_E500) +/* We can safely use PowerPC SPE extension when compiling PowerPC 64 */ +#define TARGET_PPCSPE +#elif defined(TARGET_PPCSPE) /* GPR are 64 bits: used by vector extension */ typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 32 +#define TARGET_GPR_BITS 64 #define REGX "%08" PRIx32 #else typedef uint32_t ppc_gpr_t; #define TARGET_LONG_BITS 32 +#define TARGET_GPR_BITS 32 #define REGX "%08" PRIx32 #endif @@ -297,7 +302,7 @@ enum { /* ld/st with reservation instructions */ /* cache control instructions */ /* spr/msr access instructions */ - PPC_INSNS_BASE = 0x00000001, + PPC_INSNS_BASE = 0x0000000000000001ULL, #define PPC_INTEGER PPC_INSNS_BASE #define PPC_FLOW PPC_INSNS_BASE #define PPC_MEM PPC_INSNS_BASE @@ -305,68 +310,72 @@ enum { #define PPC_CACHE PPC_INSNS_BASE #define PPC_MISC PPC_INSNS_BASE /* floating point operations instructions */ - PPC_FLOAT = 0x00000002, + PPC_FLOAT = 0x0000000000000002ULL, /* more floating point operations instructions */ - PPC_FLOAT_EXT = 0x00000004, + PPC_FLOAT_EXT = 0x0000000000000004ULL, /* external control instructions */ - PPC_EXTERN = 0x00000008, + PPC_EXTERN = 0x0000000000000008ULL, /* segment register access instructions */ - PPC_SEGMENT = 0x00000010, + PPC_SEGMENT = 0x0000000000000010ULL, /* Optional cache control instructions */ - PPC_CACHE_OPT = 0x00000020, + PPC_CACHE_OPT = 0x0000000000000020ULL, /* Optional floating point op instructions */ - PPC_FLOAT_OPT = 0x00000040, + PPC_FLOAT_OPT = 0x0000000000000040ULL, /* Optional memory control instructions */ - PPC_MEM_TLBIA = 0x00000080, - PPC_MEM_TLBIE = 0x00000100, - PPC_MEM_TLBSYNC = 0x00000200, + PPC_MEM_TLBIA = 0x0000000000000080ULL, + PPC_MEM_TLBIE = 0x0000000000000100ULL, + PPC_MEM_TLBSYNC = 0x0000000000000200ULL, /* eieio & sync */ - PPC_MEM_SYNC = 0x00000400, + PPC_MEM_SYNC = 0x0000000000000400ULL, /* PowerPC 6xx TLB management instructions */ - PPC_6xx_TLB = 0x00000800, + PPC_6xx_TLB = 0x0000000000000800ULL, /* Altivec support */ - PPC_ALTIVEC = 0x00001000, + PPC_ALTIVEC = 0x0000000000001000ULL, /* Time base support */ - PPC_TB = 0x00002000, + PPC_TB = 0x0000000000002000ULL, /* Embedded PowerPC dedicated instructions */ - PPC_EMB_COMMON = 0x00004000, + PPC_EMB_COMMON = 0x0000000000004000ULL, /* PowerPC 40x exception model */ - PPC_40x_EXCP = 0x00008000, + PPC_40x_EXCP = 0x0000000000008000ULL, /* PowerPC 40x specific instructions */ - PPC_40x_SPEC = 0x00010000, + PPC_40x_SPEC = 0x0000000000010000ULL, /* PowerPC 405 Mac instructions */ - PPC_405_MAC = 0x00020000, + PPC_405_MAC = 0x0000000000020000ULL, /* PowerPC 440 specific instructions */ - PPC_440_SPEC = 0x00040000, + PPC_440_SPEC = 0x0000000000040000ULL, /* Specific extensions */ /* Power-to-PowerPC bridge (601) */ - PPC_POWER_BR = 0x00080000, + PPC_POWER_BR = 0x0000000000080000ULL, /* PowerPC 602 specific */ - PPC_602_SPEC = 0x00100000, + PPC_602_SPEC = 0x0000000000100000ULL, /* Deprecated instructions */ /* Original POWER instruction set */ - PPC_POWER = 0x00200000, + PPC_POWER = 0x0000000000200000ULL, /* POWER2 instruction set extension */ - PPC_POWER2 = 0x00400000, + PPC_POWER2 = 0x0000000000400000ULL, /* Power RTC support */ - PPC_POWER_RTC = 0x00800000, + PPC_POWER_RTC = 0x0000000000800000ULL, /* 64 bits PowerPC instructions */ /* 64 bits PowerPC instruction set */ - PPC_64B = 0x01000000, + PPC_64B = 0x0000000001000000ULL, /* 64 bits hypervisor extensions */ - PPC_64H = 0x02000000, + PPC_64H = 0x0000000002000000ULL, /* 64 bits PowerPC "bridge" features */ - PPC_64_BRIDGE = 0x04000000, + PPC_64_BRIDGE = 0x0000000004000000ULL, /* BookE (embedded) PowerPC specification */ - PPC_BOOKE = 0x08000000, + PPC_BOOKE = 0x0000000008000000ULL, /* eieio */ - PPC_MEM_EIEIO = 0x10000000, + PPC_MEM_EIEIO = 0x0000000010000000ULL, /* e500 vector instructions */ - PPC_E500_VECTOR = 0x20000000, + PPC_E500_VECTOR = 0x0000000020000000ULL, /* PowerPC 4xx dedicated instructions */ - PPC_4xx_COMMON = 0x40000000, + PPC_4xx_COMMON = 0x0000000040000000ULL, /* PowerPC 2.03 specification extensions */ - PPC_203 = 0x80000000, + PPC_203 = 0x0000000080000000ULL, + /* PowerPC 2.03 SPE extension */ + PPC_SPE = 0x0000000100000000ULL, + /* PowerPC 2.03 SPE floating-point extension */ + PPC_SPEFPU = 0x0000000200000000ULL, }; /* CPU run-time flags (MMU and exception model) */ @@ -618,10 +627,10 @@ struct CPUPPCState { /* First are the most commonly used resources * during translated code execution */ -#if TARGET_LONG_BITS > HOST_LONG_BITS +#if TARGET_GPR_BITS > HOST_LONG_BITS /* temporary fixed-point registers * used to emulate 64 bits target on 32 bits hosts - */ + */ target_ulong t0, t1, t2; #endif ppc_avr_t t0_avr, t1_avr, t2_avr; @@ -683,6 +692,7 @@ struct CPUPPCState { uint32_t vscr; /* SPE registers */ ppc_gpr_t spe_acc; + float_status spe_status; uint32_t spe_fscr; /* Internal devices resources */ @@ -1192,6 +1202,8 @@ enum { #define EXCP_970_MAINT 0x1600 /* Maintenance exception */ #define EXCP_970_THRM 0x1800 /* Thermal exception */ #define EXCP_970_VPUA 0x1700 /* VPU assist exception */ +/* SPE related exceptions */ +#define EXCP_NO_SPE 0x0F20 /* SPE unavailable exception */ /* End of exception vectors area */ #define EXCP_PPC_MAX 0x4000 /* Qemu exceptions: special cases we want to stop translation */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index f1dde82d4..a10b62d25 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -39,10 +39,10 @@ register unsigned long T1 asm(AREG2); register unsigned long T2 asm(AREG3); #endif /* We may, sometime, need 64 bits registers on 32 bits target */ -#if defined(TARGET_PPC64) || (HOST_LONG_BITS == 64) +#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE) || (HOST_LONG_BITS == 64) #define T0_64 T0 -#define T1_64 T0 -#define T2_64 T0 +#define T1_64 T1 +#define T2_64 T2 #else /* no registers can be used */ #define T0_64 (env->t0) diff --git a/target-ppc/op.c b/target-ppc/op.c index 9531595be..0b972c8e6 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1326,106 +1326,14 @@ void OPPROTO op_andi_T1 (void) /* count leading zero */ void OPPROTO op_cntlzw (void) { - int cnt; - - cnt = 0; - if (!(T0 & 0xFFFF0000UL)) { - cnt += 16; - T0 <<= 16; - } - if (!(T0 & 0xFF000000UL)) { - cnt += 8; - T0 <<= 8; - } - if (!(T0 & 0xF0000000UL)) { - cnt += 4; - T0 <<= 4; - } - if (!(T0 & 0xC0000000UL)) { - cnt += 2; - T0 <<= 2; - } - if (!(T0 & 0x80000000UL)) { - cnt++; - T0 <<= 1; - } - if (!(T0 & 0x80000000UL)) { - cnt++; - } - T0 = cnt; + T0 = _do_cntlzw(T0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_cntlzd (void) { -#if HOST_LONG_BITS == 64 - int cnt; - - cnt = 0; - if (!(T0 & 0xFFFFFFFF00000000ULL)) { - cnt += 32; - T0 <<= 32; - } - if (!(T0 & 0xFFFF000000000000ULL)) { - cnt += 16; - T0 <<= 16; - } - if (!(T0 & 0xFF00000000000000ULL)) { - cnt += 8; - T0 <<= 8; - } - if (!(T0 & 0xF000000000000000ULL)) { - cnt += 4; - T0 <<= 4; - } - if (!(T0 & 0xC000000000000000ULL)) { - cnt += 2; - T0 <<= 2; - } - if (!(T0 & 0x8000000000000000ULL)) { - cnt++; - T0 <<= 1; - } - if (!(T0 & 0x8000000000000000ULL)) { - cnt++; - } - T0 = cnt; -#else - uint32_t tmp; - - /* Make it easier on 32 bits host machines */ - if (!(T0 >> 32)) { - tmp = T0; - T0 = 32; - } else { - tmp = T0 >> 32; - T0 = 0; - } - if (!(tmp & 0xFFFF0000UL)) { - T0 += 16; - tmp <<= 16; - } - if (!(tmp & 0xFF000000UL)) { - T0 += 8; - tmp <<= 8; - } - if (!(tmp & 0xF0000000UL)) { - T0 += 4; - tmp <<= 4; - } - if (!(tmp & 0xC0000000UL)) { - T0 += 2; - tmp <<= 2; - } - if (!(tmp & 0x80000000UL)) { - T0++; - tmp <<= 1; - } - if (!(tmp & 0x80000000UL)) { - T0++; - } -#endif + T0 = _do_cntlzd(T0); RETURN(); } #endif @@ -2462,4 +2370,723 @@ void OPPROTO op_store_booke_tsr (void) store_booke_tsr(env, T0); RETURN(); } + #endif /* !defined(CONFIG_USER_ONLY) */ + +#if defined(TARGET_PPCSPE) +/* SPE extension */ +void OPPROTO op_splatw_T1_64 (void) +{ + T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL); +} + +void OPPROTO op_splatwi_T0_64 (void) +{ + uint64_t tmp = PARAM1; + + T0_64 = (tmp << 32) | tmp; +} + +void OPPROTO op_splatwi_T1_64 (void) +{ + uint64_t tmp = PARAM1; + + T1_64 = (tmp << 32) | tmp; +} + +void OPPROTO op_extsh_T1_64 (void) +{ + T1_64 = (int32_t)((int16_t)T1_64); + RETURN(); +} + +void OPPROTO op_sli16_T1_64 (void) +{ + T1_64 = T1_64 << 16; + RETURN(); +} + +void OPPROTO op_sli32_T1_64 (void) +{ + T1_64 = T1_64 << 32; + RETURN(); +} + +void OPPROTO op_srli32_T1_64 (void) +{ + T1_64 = T1_64 >> 32; + RETURN(); +} + +void OPPROTO op_evsel (void) +{ + do_evsel(); + RETURN(); +} + +void OPPROTO op_evaddw (void) +{ + do_evaddw(); + RETURN(); +} + +void OPPROTO op_evsubfw (void) +{ + do_evsubfw(); + RETURN(); +} + +void OPPROTO op_evneg (void) +{ + do_evneg(); + RETURN(); +} + +void OPPROTO op_evabs (void) +{ + do_evabs(); + RETURN(); +} + +void OPPROTO op_evextsh (void) +{ + T0_64 = ((uint64_t)((int32_t)(int16_t)(T0_64 >> 32)) << 32) | + (uint64_t)((int32_t)(int16_t)T0_64); + RETURN(); +} + +void OPPROTO op_evextsb (void) +{ + T0_64 = ((uint64_t)((int32_t)(int8_t)(T0_64 >> 32)) << 32) | + (uint64_t)((int32_t)(int8_t)T0_64); + RETURN(); +} + +void OPPROTO op_evcntlzw (void) +{ + do_evcntlzw(); + RETURN(); +} + +void OPPROTO op_evrndw (void) +{ + do_evrndw(); + RETURN(); +} + +void OPPROTO op_brinc (void) +{ + do_brinc(); + RETURN(); +} + +void OPPROTO op_evcntlsw (void) +{ + do_evcntlsw(); + RETURN(); +} + +void OPPROTO op_evand (void) +{ + T0_64 &= T1_64; + RETURN(); +} + +void OPPROTO op_evandc (void) +{ + T0_64 &= ~T1_64; + RETURN(); +} + +void OPPROTO op_evor (void) +{ + T0_64 |= T1_64; + RETURN(); +} + +void OPPROTO op_evxor (void) +{ + T0_64 ^= T1_64; + RETURN(); +} + +void OPPROTO op_eveqv (void) +{ + T0_64 = ~(T0_64 ^ T1_64); + RETURN(); +} + +void OPPROTO op_evnor (void) +{ + T0_64 = ~(T0_64 | T1_64); + RETURN(); +} + +void OPPROTO op_evorc (void) +{ + T0_64 |= ~T1_64; + RETURN(); +} + +void OPPROTO op_evnand (void) +{ + T0_64 = ~(T0_64 & T1_64); + RETURN(); +} + +void OPPROTO op_evsrws (void) +{ + do_evsrws(); + RETURN(); +} + +void OPPROTO op_evsrwu (void) +{ + do_evsrwu(); + RETURN(); +} + +void OPPROTO op_evslw (void) +{ + do_evslw(); + RETURN(); +} + +void OPPROTO op_evrlw (void) +{ + do_evrlw(); + RETURN(); +} + +void OPPROTO op_evmergelo (void) +{ + T0_64 = (T0_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL); + RETURN(); +} + +void OPPROTO op_evmergehi (void) +{ + T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 >> 32); + RETURN(); +} + +void OPPROTO op_evmergelohi (void) +{ + T0_64 = (T0_64 << 32) | (T1_64 >> 32); + RETURN(); +} + +void OPPROTO op_evmergehilo (void) +{ + T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 & 0x00000000FFFFFFFFULL); + RETURN(); +} + +void OPPROTO op_evcmpgts (void) +{ + do_evcmpgts(); + RETURN(); +} + +void OPPROTO op_evcmpgtu (void) +{ + do_evcmpgtu(); + RETURN(); +} + +void OPPROTO op_evcmplts (void) +{ + do_evcmplts(); + RETURN(); +} + +void OPPROTO op_evcmpltu (void) +{ + do_evcmpltu(); + RETURN(); +} + +void OPPROTO op_evcmpeq (void) +{ + do_evcmpeq(); + RETURN(); +} + +void OPPROTO op_evfssub (void) +{ + do_evfssub(); + RETURN(); +} + +void OPPROTO op_evfsadd (void) +{ + do_evfsadd(); + RETURN(); +} + +void OPPROTO op_evfsnabs (void) +{ + do_evfsnabs(); + RETURN(); +} + +void OPPROTO op_evfsabs (void) +{ + do_evfsabs(); + RETURN(); +} + +void OPPROTO op_evfsneg (void) +{ + do_evfsneg(); + RETURN(); +} + +void OPPROTO op_evfsdiv (void) +{ + do_evfsdiv(); + RETURN(); +} + +void OPPROTO op_evfsmul (void) +{ + do_evfsmul(); + RETURN(); +} + +void OPPROTO op_evfscmplt (void) +{ + do_evfscmplt(); + RETURN(); +} + +void OPPROTO op_evfscmpgt (void) +{ + do_evfscmpgt(); + RETURN(); +} + +void OPPROTO op_evfscmpeq (void) +{ + do_evfscmpeq(); + RETURN(); +} + +void OPPROTO op_evfscfsi (void) +{ + do_evfscfsi(); + RETURN(); +} + +void OPPROTO op_evfscfui (void) +{ + do_evfscfui(); + RETURN(); +} + +void OPPROTO op_evfscfsf (void) +{ + do_evfscfsf(); + RETURN(); +} + +void OPPROTO op_evfscfuf (void) +{ + do_evfscfuf(); + RETURN(); +} + +void OPPROTO op_evfsctsi (void) +{ + do_evfsctsi(); + RETURN(); +} + +void OPPROTO op_evfsctui (void) +{ + do_evfsctui(); + RETURN(); +} + +void OPPROTO op_evfsctsf (void) +{ + do_evfsctsf(); + RETURN(); +} + +void OPPROTO op_evfsctuf (void) +{ + do_evfsctuf(); + RETURN(); +} + +void OPPROTO op_evfsctuiz (void) +{ + do_evfsctuiz(); + RETURN(); +} + +void OPPROTO op_evfsctsiz (void) +{ + do_evfsctsiz(); + RETURN(); +} + +void OPPROTO op_evfststlt (void) +{ + do_evfststlt(); + RETURN(); +} + +void OPPROTO op_evfststgt (void) +{ + do_evfststgt(); + RETURN(); +} + +void OPPROTO op_evfststeq (void) +{ + do_evfststeq(); + RETURN(); +} + +void OPPROTO op_efssub (void) +{ + T0_64 = _do_efssub(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efsadd (void) +{ + T0_64 = _do_efsadd(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efsnabs (void) +{ + T0_64 = _do_efsnabs(T0_64); + RETURN(); +} + +void OPPROTO op_efsabs (void) +{ + T0_64 = _do_efsabs(T0_64); + RETURN(); +} + +void OPPROTO op_efsneg (void) +{ + T0_64 = _do_efsneg(T0_64); + RETURN(); +} + +void OPPROTO op_efsdiv (void) +{ + T0_64 = _do_efsdiv(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efsmul (void) +{ + T0_64 = _do_efsmul(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efscmplt (void) +{ + do_efscmplt(); + RETURN(); +} + +void OPPROTO op_efscmpgt (void) +{ + do_efscmpgt(); + RETURN(); +} + +void OPPROTO op_efscfd (void) +{ + do_efscfd(); + RETURN(); +} + +void OPPROTO op_efscmpeq (void) +{ + do_efscmpeq(); + RETURN(); +} + +void OPPROTO op_efscfsi (void) +{ + do_efscfsi(); + RETURN(); +} + +void OPPROTO op_efscfui (void) +{ + do_efscfui(); + RETURN(); +} + +void OPPROTO op_efscfsf (void) +{ + do_efscfsf(); + RETURN(); +} + +void OPPROTO op_efscfuf (void) +{ + do_efscfuf(); + RETURN(); +} + +void OPPROTO op_efsctsi (void) +{ + do_efsctsi(); + RETURN(); +} + +void OPPROTO op_efsctui (void) +{ + do_efsctui(); + RETURN(); +} + +void OPPROTO op_efsctsf (void) +{ + do_efsctsf(); + RETURN(); +} + +void OPPROTO op_efsctuf (void) +{ + do_efsctuf(); + RETURN(); +} + +void OPPROTO op_efsctsiz (void) +{ + do_efsctsiz(); + RETURN(); +} + +void OPPROTO op_efsctuiz (void) +{ + do_efsctuiz(); + RETURN(); +} + +void OPPROTO op_efststlt (void) +{ + T0 = _do_efststlt(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efststgt (void) +{ + T0 = _do_efststgt(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efststeq (void) +{ + T0 = _do_efststeq(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efdsub (void) +{ + union { + uint64_t u; + float64 f; + } u1, u2; + u1.u = T0_64; + u2.u = T1_64; + u1.f = float64_sub(u1.f, u2.f, &env->spe_status); + T0_64 = u1.u; + RETURN(); +} + +void OPPROTO op_efdadd (void) +{ + union { + uint64_t u; + float64 f; + } u1, u2; + u1.u = T0_64; + u2.u = T1_64; + u1.f = float64_add(u1.f, u2.f, &env->spe_status); + T0_64 = u1.u; + RETURN(); +} + +void OPPROTO op_efdcfsid (void) +{ + do_efdcfsi(); + RETURN(); +} + +void OPPROTO op_efdcfuid (void) +{ + do_efdcfui(); + RETURN(); +} + +void OPPROTO op_efdnabs (void) +{ + T0_64 |= 0x8000000000000000ULL; + RETURN(); +} + +void OPPROTO op_efdabs (void) +{ + T0_64 &= ~0x8000000000000000ULL; + RETURN(); +} + +void OPPROTO op_efdneg (void) +{ + T0_64 ^= 0x8000000000000000ULL; + RETURN(); +} + +void OPPROTO op_efddiv (void) +{ + union { + uint64_t u; + float64 f; + } u1, u2; + u1.u = T0_64; + u2.u = T1_64; + u1.f = float64_div(u1.f, u2.f, &env->spe_status); + T0_64 = u1.u; + RETURN(); +} + +void OPPROTO op_efdmul (void) +{ + union { + uint64_t u; + float64 f; + } u1, u2; + u1.u = T0_64; + u2.u = T1_64; + u1.f = float64_mul(u1.f, u2.f, &env->spe_status); + T0_64 = u1.u; + RETURN(); +} + +void OPPROTO op_efdctsidz (void) +{ + do_efdctsiz(); + RETURN(); +} + +void OPPROTO op_efdctuidz (void) +{ + do_efdctuiz(); + RETURN(); +} + +void OPPROTO op_efdcmplt (void) +{ + do_efdcmplt(); + RETURN(); +} + +void OPPROTO op_efdcmpgt (void) +{ + do_efdcmpgt(); + RETURN(); +} + +void OPPROTO op_efdcfs (void) +{ + do_efdcfs(); + RETURN(); +} + +void OPPROTO op_efdcmpeq (void) +{ + do_efdcmpeq(); + RETURN(); +} + +void OPPROTO op_efdcfsi (void) +{ + do_efdcfsi(); + RETURN(); +} + +void OPPROTO op_efdcfui (void) +{ + do_efdcfui(); + RETURN(); +} + +void OPPROTO op_efdcfsf (void) +{ + do_efdcfsf(); + RETURN(); +} + +void OPPROTO op_efdcfuf (void) +{ + do_efdcfuf(); + RETURN(); +} + +void OPPROTO op_efdctsi (void) +{ + do_efdctsi(); + RETURN(); +} + +void OPPROTO op_efdctui (void) +{ + do_efdctui(); + RETURN(); +} + +void OPPROTO op_efdctsf (void) +{ + do_efdctsf(); + RETURN(); +} + +void OPPROTO op_efdctuf (void) +{ + do_efdctuf(); + RETURN(); +} + +void OPPROTO op_efdctuiz (void) +{ + do_efdctuiz(); + RETURN(); +} + +void OPPROTO op_efdctsiz (void) +{ + do_efdctsiz(); + RETURN(); +} + +void OPPROTO op_efdtstlt (void) +{ + T0 = _do_efdtstlt(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efdtstgt (void) +{ + T0 = _do_efdtstgt(T0_64, T1_64); + RETURN(); +} + +void OPPROTO op_efdtsteq (void) +{ + T0 = _do_efdtsteq(T0_64, T1_64); + RETURN(); +} +#endif /* defined(TARGET_PPCSPE) */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 7ef06b20b..756d164da 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -19,12 +19,17 @@ */ #include "exec.h" +#include "op_helper.h" + #define MEMSUFFIX _raw +#include "op_helper.h" #include "op_helper_mem.h" #if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user +#include "op_helper.h" #include "op_helper_mem.h" #define MEMSUFFIX _kernel +#include "op_helper.h" #include "op_helper_mem.h" #endif @@ -229,7 +234,7 @@ void do_mul64 (uint64_t *plow, uint64_t *phigh) mul64(plow, phigh, T0, T1); } -static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) +static void imul64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) { int sa, sb; sa = (a < 0); @@ -1119,6 +1124,868 @@ void do_440_dlmzb (void) T0 = i; } +#if defined(TARGET_PPCSPE) +/* SPE extension helpers */ +/* Use a table to make this quicker */ +static uint8_t hbrev[16] = { + 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, + 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF, +}; + +static inline uint8_t byte_reverse (uint8_t val) +{ + return hbrev[val >> 4] | (hbrev[val & 0xF] << 4); +} + +static inline uint32_t word_reverse (uint32_t val) +{ + return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) | + (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24); +} + +#define MASKBITS 16 // Random value - to be fixed +void do_brinc (void) +{ + uint32_t a, b, d, mask; + + mask = (uint32_t)(-1UL) >> MASKBITS; + b = T1_64 & mask; + a = T0_64 & mask; + d = word_reverse(1 + word_reverse(a | ~mask)); + T0_64 = (T0_64 & ~mask) | (d & mask); +} + +#define DO_SPE_OP2(name) \ +void do_ev##name (void) \ +{ \ + T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) | \ + (uint64_t)_do_e##name(T0_64, T1_64); \ +} + +#define DO_SPE_OP1(name) \ +void do_ev##name (void) \ +{ \ + T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) | \ + (uint64_t)_do_e##name(T0_64); \ +} + +/* Fixed-point vector arithmetic */ +static inline uint32_t _do_eabs (uint32_t val) +{ + if (val != 0x80000000) + val &= ~0x80000000; + + return val; +} + +static inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2) +{ + return op1 + op2; +} + +static inline int _do_ecntlsw (uint32_t val) +{ + if (val & 0x80000000) + return _do_cntlzw(~val); + else + return _do_cntlzw(val); +} + +static inline int _do_ecntlzw (uint32_t val) +{ + return _do_cntlzw(val); +} + +static inline uint32_t _do_eneg (uint32_t val) +{ + if (val != 0x80000000) + val ^= 0x80000000; + + return val; +} + +static inline uint32_t _do_erlw (uint32_t op1, uint32_t op2) +{ + return rotl32(op1, op2); +} + +static inline uint32_t _do_erndw (uint32_t val) +{ + return (val + 0x000080000000) & 0xFFFF0000; +} + +static inline uint32_t _do_eslw (uint32_t op1, uint32_t op2) +{ + /* No error here: 6 bits are used */ + return op1 << (op2 & 0x3F); +} + +static inline int32_t _do_esrws (int32_t op1, uint32_t op2) +{ + /* No error here: 6 bits are used */ + return op1 >> (op2 & 0x3F); +} + +static inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2) +{ + /* No error here: 6 bits are used */ + return op1 >> (op2 & 0x3F); +} + +static inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2) +{ + return op2 - op1; +} + +/* evabs */ +DO_SPE_OP1(abs); +/* evaddw */ +DO_SPE_OP2(addw); +/* evcntlsw */ +DO_SPE_OP1(cntlsw); +/* evcntlzw */ +DO_SPE_OP1(cntlzw); +/* evneg */ +DO_SPE_OP1(neg); +/* evrlw */ +DO_SPE_OP2(rlw); +/* evrnd */ +DO_SPE_OP1(rndw); +/* evslw */ +DO_SPE_OP2(slw); +/* evsrws */ +DO_SPE_OP2(srws); +/* evsrwu */ +DO_SPE_OP2(srwu); +/* evsubfw */ +DO_SPE_OP2(subfw); + +/* evsel is a little bit more complicated... */ +static inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n) +{ + if (n) + return op1; + else + return op2; +} + +void do_evsel (void) +{ + T0_64 = ((uint64_t)_do_esel(T0_64 >> 32, T1_64 >> 32, T0 >> 3) << 32) | + (uint64_t)_do_esel(T0_64, T1_64, (T0 >> 2) & 1); +} + +/* Fixed-point vector comparisons */ +#define DO_SPE_CMP(name) \ +void do_ev##name (void) \ +{ \ + T0 = _do_evcmp_merge((uint64_t)_do_e##name(T0_64 >> 32, \ + T1_64 >> 32) << 32, \ + _do_e##name(T0_64, T1_64)); \ +} + +static inline uint32_t _do_evcmp_merge (int t0, int t1) +{ + return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); +} +static inline int _do_ecmpeq (uint32_t op1, uint32_t op2) +{ + return op1 == op2 ? 1 : 0; +} + +static inline int _do_ecmpgts (int32_t op1, int32_t op2) +{ + return op1 > op2 ? 1 : 0; +} + +static inline int _do_ecmpgtu (uint32_t op1, uint32_t op2) +{ + return op1 > op2 ? 1 : 0; +} + +static inline int _do_ecmplts (int32_t op1, int32_t op2) +{ + return op1 < op2 ? 1 : 0; +} + +static inline int _do_ecmpltu (uint32_t op1, uint32_t op2) +{ + return op1 < op2 ? 1 : 0; +} + +/* evcmpeq */ +DO_SPE_CMP(cmpeq); +/* evcmpgts */ +DO_SPE_CMP(cmpgts); +/* evcmpgtu */ +DO_SPE_CMP(cmpgtu); +/* evcmplts */ +DO_SPE_CMP(cmplts); +/* evcmpltu */ +DO_SPE_CMP(cmpltu); + +/* Single precision floating-point conversions from/to integer */ +static inline uint32_t _do_efscfsi (int32_t val) +{ + union { + uint32_t u; + float32 f; + } u; + + u.f = int32_to_float32(val, &env->spe_status); + + return u.u; +} + +static inline uint32_t _do_efscfui (uint32_t val) +{ + union { + uint32_t u; + float32 f; + } u; + + u.f = uint32_to_float32(val, &env->spe_status); + + return u.u; +} + +static inline int32_t _do_efsctsi (uint32_t val) +{ + union { + int32_t u; + float32 f; + } u; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + + return float32_to_int32(u.f, &env->spe_status); +} + +static inline uint32_t _do_efsctui (uint32_t val) +{ + union { + int32_t u; + float32 f; + } u; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + + return float32_to_uint32(u.f, &env->spe_status); +} + +static inline int32_t _do_efsctsiz (uint32_t val) +{ + union { + int32_t u; + float32 f; + } u; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + + return float32_to_int32_round_to_zero(u.f, &env->spe_status); +} + +static inline uint32_t _do_efsctuiz (uint32_t val) +{ + union { + int32_t u; + float32 f; + } u; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + + return float32_to_uint32_round_to_zero(u.f, &env->spe_status); +} + +void do_efscfsi (void) +{ + T0_64 = _do_efscfsi(T0_64); +} + +void do_efscfui (void) +{ + T0_64 = _do_efscfui(T0_64); +} + +void do_efsctsi (void) +{ + T0_64 = _do_efsctsi(T0_64); +} + +void do_efsctui (void) +{ + T0_64 = _do_efsctui(T0_64); +} + +void do_efsctsiz (void) +{ + T0_64 = _do_efsctsiz(T0_64); +} + +void do_efsctuiz (void) +{ + T0_64 = _do_efsctuiz(T0_64); +} + +/* Single precision floating-point conversion to/from fractional */ +static inline uint32_t _do_efscfsf (uint32_t val) +{ + union { + uint32_t u; + float32 f; + } u; + float32 tmp; + + u.f = int32_to_float32(val, &env->spe_status); + tmp = int64_to_float32(1ULL << 32, &env->spe_status); + u.f = float32_div(u.f, tmp, &env->spe_status); + + return u.u; +} + +static inline uint32_t _do_efscfuf (uint32_t val) +{ + union { + uint32_t u; + float32 f; + } u; + float32 tmp; + + u.f = uint32_to_float32(val, &env->spe_status); + tmp = uint64_to_float32(1ULL << 32, &env->spe_status); + u.f = float32_div(u.f, tmp, &env->spe_status); + + return u.u; +} + +static inline int32_t _do_efsctsf (uint32_t val) +{ + union { + int32_t u; + float32 f; + } u; + float32 tmp; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + tmp = uint64_to_float32(1ULL << 32, &env->spe_status); + u.f = float32_mul(u.f, tmp, &env->spe_status); + + return float32_to_int32(u.f, &env->spe_status); +} + +static inline uint32_t _do_efsctuf (uint32_t val) +{ + union { + int32_t u; + float32 f; + } u; + float32 tmp; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + tmp = uint64_to_float32(1ULL << 32, &env->spe_status); + u.f = float32_mul(u.f, tmp, &env->spe_status); + + return float32_to_uint32(u.f, &env->spe_status); +} + +static inline int32_t _do_efsctsfz (uint32_t val) +{ + union { + int32_t u; + float32 f; + } u; + float32 tmp; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + tmp = uint64_to_float32(1ULL << 32, &env->spe_status); + u.f = float32_mul(u.f, tmp, &env->spe_status); + + return float32_to_int32_round_to_zero(u.f, &env->spe_status); +} + +static inline uint32_t _do_efsctufz (uint32_t val) +{ + union { + int32_t u; + float32 f; + } u; + float32 tmp; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + tmp = uint64_to_float32(1ULL << 32, &env->spe_status); + u.f = float32_mul(u.f, tmp, &env->spe_status); + + return float32_to_uint32_round_to_zero(u.f, &env->spe_status); +} + +void do_efscfsf (void) +{ + T0_64 = _do_efscfsf(T0_64); +} + +void do_efscfuf (void) +{ + T0_64 = _do_efscfuf(T0_64); +} + +void do_efsctsf (void) +{ + T0_64 = _do_efsctsf(T0_64); +} + +void do_efsctuf (void) +{ + T0_64 = _do_efsctuf(T0_64); +} + +void do_efsctsfz (void) +{ + T0_64 = _do_efsctsfz(T0_64); +} + +void do_efsctufz (void) +{ + T0_64 = _do_efsctufz(T0_64); +} + +/* Double precision floating point helpers */ +static inline int _do_efdcmplt (uint64_t op1, uint64_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return _do_efdtstlt(op1, op2); +} + +static inline int _do_efdcmpgt (uint64_t op1, uint64_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return _do_efdtstgt(op1, op2); +} + +static inline int _do_efdcmpeq (uint64_t op1, uint64_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return _do_efdtsteq(op1, op2); +} + +void do_efdcmplt (void) +{ + T0 = _do_efdcmplt(T0_64, T1_64); +} + +void do_efdcmpgt (void) +{ + T0 = _do_efdcmpgt(T0_64, T1_64); +} + +void do_efdcmpeq (void) +{ + T0 = _do_efdcmpeq(T0_64, T1_64); +} + +/* Double precision floating-point conversion to/from integer */ +static inline uint64_t _do_efdcfsi (int64_t val) +{ + union { + uint64_t u; + float64 f; + } u; + + u.f = int64_to_float64(val, &env->spe_status); + + return u.u; +} + +static inline uint64_t _do_efdcfui (uint64_t val) +{ + union { + uint64_t u; + float64 f; + } u; + + u.f = uint64_to_float64(val, &env->spe_status); + + return u.u; +} + +static inline int64_t _do_efdctsi (uint64_t val) +{ + union { + int64_t u; + float64 f; + } u; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + + return float64_to_int64(u.f, &env->spe_status); +} + +static inline uint64_t _do_efdctui (uint64_t val) +{ + union { + int64_t u; + float64 f; + } u; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + + return float64_to_uint64(u.f, &env->spe_status); +} + +static inline int64_t _do_efdctsiz (uint64_t val) +{ + union { + int64_t u; + float64 f; + } u; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + + return float64_to_int64_round_to_zero(u.f, &env->spe_status); +} + +static inline uint64_t _do_efdctuiz (uint64_t val) +{ + union { + int64_t u; + float64 f; + } u; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + + return float64_to_uint64_round_to_zero(u.f, &env->spe_status); +} + +void do_efdcfsi (void) +{ + T0_64 = _do_efdcfsi(T0_64); +} + +void do_efdcfui (void) +{ + T0_64 = _do_efdcfui(T0_64); +} + +void do_efdctsi (void) +{ + T0_64 = _do_efdctsi(T0_64); +} + +void do_efdctui (void) +{ + T0_64 = _do_efdctui(T0_64); +} + +void do_efdctsiz (void) +{ + T0_64 = _do_efdctsiz(T0_64); +} + +void do_efdctuiz (void) +{ + T0_64 = _do_efdctuiz(T0_64); +} + +/* Double precision floating-point conversion to/from fractional */ +static inline uint64_t _do_efdcfsf (int64_t val) +{ + union { + uint64_t u; + float64 f; + } u; + float64 tmp; + + u.f = int32_to_float64(val, &env->spe_status); + tmp = int64_to_float64(1ULL << 32, &env->spe_status); + u.f = float64_div(u.f, tmp, &env->spe_status); + + return u.u; +} + +static inline uint64_t _do_efdcfuf (uint64_t val) +{ + union { + uint64_t u; + float64 f; + } u; + float64 tmp; + + u.f = uint32_to_float64(val, &env->spe_status); + tmp = int64_to_float64(1ULL << 32, &env->spe_status); + u.f = float64_div(u.f, tmp, &env->spe_status); + + return u.u; +} + +static inline int64_t _do_efdctsf (uint64_t val) +{ + union { + int64_t u; + float64 f; + } u; + float64 tmp; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + tmp = uint64_to_float64(1ULL << 32, &env->spe_status); + u.f = float64_mul(u.f, tmp, &env->spe_status); + + return float64_to_int32(u.f, &env->spe_status); +} + +static inline uint64_t _do_efdctuf (uint64_t val) +{ + union { + int64_t u; + float64 f; + } u; + float64 tmp; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + tmp = uint64_to_float64(1ULL << 32, &env->spe_status); + u.f = float64_mul(u.f, tmp, &env->spe_status); + + return float64_to_uint32(u.f, &env->spe_status); +} + +static inline int64_t _do_efdctsfz (uint64_t val) +{ + union { + int64_t u; + float64 f; + } u; + float64 tmp; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + tmp = uint64_to_float64(1ULL << 32, &env->spe_status); + u.f = float64_mul(u.f, tmp, &env->spe_status); + + return float64_to_int32_round_to_zero(u.f, &env->spe_status); +} + +static inline uint64_t _do_efdctufz (uint64_t val) +{ + union { + int64_t u; + float64 f; + } u; + float64 tmp; + + u.u = val; + /* NaN are not treated the same way IEEE 754 does */ + if (unlikely(isnan(u.f))) + return 0; + tmp = uint64_to_float64(1ULL << 32, &env->spe_status); + u.f = float64_mul(u.f, tmp, &env->spe_status); + + return float64_to_uint32_round_to_zero(u.f, &env->spe_status); +} + +void do_efdcfsf (void) +{ + T0_64 = _do_efdcfsf(T0_64); +} + +void do_efdcfuf (void) +{ + T0_64 = _do_efdcfuf(T0_64); +} + +void do_efdctsf (void) +{ + T0_64 = _do_efdctsf(T0_64); +} + +void do_efdctuf (void) +{ + T0_64 = _do_efdctuf(T0_64); +} + +void do_efdctsfz (void) +{ + T0_64 = _do_efdctsfz(T0_64); +} + +void do_efdctufz (void) +{ + T0_64 = _do_efdctufz(T0_64); +} + +/* Floating point conversion between single and double precision */ +static inline uint32_t _do_efscfd (uint64_t val) +{ + union { + uint64_t u; + float64 f; + } u1; + union { + uint32_t u; + float32 f; + } u2; + + u1.u = val; + u2.f = float64_to_float32(u1.f, &env->spe_status); + + return u2.u; +} + +static inline uint64_t _do_efdcfs (uint32_t val) +{ + union { + uint64_t u; + float64 f; + } u2; + union { + uint32_t u; + float32 f; + } u1; + + u1.u = val; + u2.f = float32_to_float64(u1.f, &env->spe_status); + + return u2.u; +} + +void do_efscfd (void) +{ + T0_64 = _do_efscfd(T0_64); +} + +void do_efdcfs (void) +{ + T0_64 = _do_efdcfs(T0_64); +} + +/* Single precision fixed-point vector arithmetic */ +/* evfsabs */ +DO_SPE_OP1(fsabs); +/* evfsnabs */ +DO_SPE_OP1(fsnabs); +/* evfsneg */ +DO_SPE_OP1(fsneg); +/* evfsadd */ +DO_SPE_OP2(fsadd); +/* evfssub */ +DO_SPE_OP2(fssub); +/* evfsmul */ +DO_SPE_OP2(fsmul); +/* evfsdiv */ +DO_SPE_OP2(fsdiv); + +/* Single-precision floating-point comparisons */ +static inline int _do_efscmplt (uint32_t op1, uint32_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return _do_efststlt(op1, op2); +} + +static inline int _do_efscmpgt (uint32_t op1, uint32_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return _do_efststgt(op1, op2); +} + +static inline int _do_efscmpeq (uint32_t op1, uint32_t op2) +{ + /* XXX: TODO: test special values (NaN, infinites, ...) */ + return _do_efststeq(op1, op2); +} + +void do_efscmplt (void) +{ + T0 = _do_efscmplt(T0_64, T1_64); +} + +void do_efscmpgt (void) +{ + T0 = _do_efscmpgt(T0_64, T1_64); +} + +void do_efscmpeq (void) +{ + T0 = _do_efscmpeq(T0_64, T1_64); +} + +/* Single-precision floating-point vector comparisons */ +/* evfscmplt */ +DO_SPE_CMP(fscmplt); +/* evfscmpgt */ +DO_SPE_CMP(fscmpgt); +/* evfscmpeq */ +DO_SPE_CMP(fscmpeq); +/* evfststlt */ +DO_SPE_CMP(fststlt); +/* evfststgt */ +DO_SPE_CMP(fststgt); +/* evfststeq */ +DO_SPE_CMP(fststeq); + +/* Single-precision floating-point vector conversions */ +/* evfscfsi */ +DO_SPE_OP1(fscfsi); +/* evfscfui */ +DO_SPE_OP1(fscfui); +/* evfscfuf */ +DO_SPE_OP1(fscfuf); +/* evfscfsf */ +DO_SPE_OP1(fscfsf); +/* evfsctsi */ +DO_SPE_OP1(fsctsi); +/* evfsctui */ +DO_SPE_OP1(fsctui); +/* evfsctsiz */ +DO_SPE_OP1(fsctsiz); +/* evfsctuiz */ +DO_SPE_OP1(fsctuiz); +/* evfsctsf */ +DO_SPE_OP1(fsctsf); +/* evfsctuf */ +DO_SPE_OP1(fsctuf); +#endif /* defined(TARGET_PPCSPE) */ + /*****************************************************************************/ /* Softmmu support */ #if !defined (CONFIG_USER_ONLY) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 6eaceb30e..8a735c1fd 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -100,6 +100,7 @@ void do_fctiwz (void); void do_fcmpu (void); void do_fcmpo (void); +/* Misc */ void do_tw (int flags); #if defined(TARGET_PPC64) void do_td (int flags); @@ -157,11 +158,291 @@ void do_4xx_tlbwe_lo (void); void do_4xx_tlbwe_hi (void); #endif +/* PowerPC 440 specific helpers */ void do_440_dlmzb (void); +/* PowerPC 403 specific helpers */ #if !defined(CONFIG_USER_ONLY) void do_load_403_pb (int num); void do_store_403_pb (int num); #endif +#if defined(TARGET_PPCSPE) +/* SPE extension helpers */ +void do_brinc (void); +/* Fixed-point vector helpers */ +void do_evabs (void); +void do_evaddw (void); +void do_evcntlsw (void); +void do_evcntlzw (void); +void do_evneg (void); +void do_evrlw (void); +void do_evsel (void); +void do_evrndw (void); +void do_evslw (void); +void do_evsrws (void); +void do_evsrwu (void); +void do_evsubfw (void); +void do_evcmpeq (void); +void do_evcmpgts (void); +void do_evcmpgtu (void); +void do_evcmplts (void); +void do_evcmpltu (void); + +/* Single precision floating-point helpers */ +void do_efscmplt (void); +void do_efscmpgt (void); +void do_efscmpeq (void); +void do_efscfsf (void); +void do_efscfuf (void); +void do_efsctsf (void); +void do_efsctuf (void); + +void do_efscfsi (void); +void do_efscfui (void); +void do_efsctsi (void); +void do_efsctui (void); +void do_efsctsiz (void); +void do_efsctuiz (void); + +/* Double precision floating-point helpers */ +void do_efdcmplt (void); +void do_efdcmpgt (void); +void do_efdcmpeq (void); +void do_efdcfsf (void); +void do_efdcfuf (void); +void do_efdctsf (void); +void do_efdctuf (void); + +void do_efdcfsi (void); +void do_efdcfui (void); +void do_efdctsi (void); +void do_efdctui (void); +void do_efdctsiz (void); +void do_efdctuiz (void); + +void do_efdcfs (void); +void do_efscfd (void); + +/* Floating-point vector helpers */ +void do_evfsabs (void); +void do_evfsnabs (void); +void do_evfsneg (void); +void do_evfsadd (void); +void do_evfssub (void); +void do_evfsmul (void); +void do_evfsdiv (void); +void do_evfscmplt (void); +void do_evfscmpgt (void); +void do_evfscmpeq (void); +void do_evfststlt (void); +void do_evfststgt (void); +void do_evfststeq (void); +void do_evfscfsi (void); +void do_evfscfui (void); +void do_evfscfsf (void); +void do_evfscfuf (void); +void do_evfsctsf (void); +void do_evfsctuf (void); +void do_evfsctsi (void); +void do_evfsctui (void); +void do_evfsctsiz (void); +void do_evfsctuiz (void); +#endif /* defined(TARGET_PPCSPE) */ + +/* Inlined helpers: used in micro-operation as well as helpers */ +/* Generic fixed-point helpers */ +static inline int _do_cntlzw (uint32_t val) +{ + int cnt = 0; + if (!(val & 0xFFFF0000UL)) { + cnt += 16; + val <<= 16; + } + if (!(val & 0xFF000000UL)) { + cnt += 8; + val <<= 8; + } + if (!(val & 0xF0000000UL)) { + cnt += 4; + val <<= 4; + } + if (!(val & 0xC0000000UL)) { + cnt += 2; + val <<= 2; + } + if (!(val & 0x80000000UL)) { + cnt++; + val <<= 1; + } + if (!(val & 0x80000000UL)) { + cnt++; + } + return cnt; +} + +static inline int _do_cntlzd (uint64_t val) +{ + int cnt = 0; +#if HOST_LONG_BITS == 64 + if (!(val & 0xFFFFFFFF00000000ULL)) { + cnt += 32; + val <<= 32; + } + if (!(val & 0xFFFF000000000000ULL)) { + cnt += 16; + val <<= 16; + } + if (!(val & 0xFF00000000000000ULL)) { + cnt += 8; + val <<= 8; + } + if (!(val & 0xF000000000000000ULL)) { + cnt += 4; + val <<= 4; + } + if (!(val & 0xC000000000000000ULL)) { + cnt += 2; + val <<= 2; + } + if (!(val & 0x8000000000000000ULL)) { + cnt++; + val <<= 1; + } + if (!(val & 0x8000000000000000ULL)) { + cnt++; + } +#else + uint32_t tmp; + /* Make it easier on 32 bits host machines */ + if (!(val >> 32)) + cnt = cntlzw(val) + 32; + else + cnt = cntlzw(val >> 32); +#endif + return cnt; +} + +#if defined(TARGET_PPCSPE) +/* SPE extension */ +/* Single precision floating-point helpers */ +static inline uint32_t _do_efsabs (uint32_t val) +{ + return val & ~0x80000000; +} +static inline uint32_t _do_efsnabs (uint32_t val) +{ + return val | 0x80000000; +} +static inline uint32_t _do_efsneg (uint32_t val) +{ + return val ^ 0x80000000; +} +static inline uint32_t _do_efsadd (uint32_t op1, uint32_t op2) +{ + union { + uint32_t u; + float32 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + u1.f = float32_add(u1.f, u2.f, &env->spe_status); + return u1.u; +} +static inline uint32_t _do_efssub (uint32_t op1, uint32_t op2) +{ + union { + uint32_t u; + float32 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + u1.f = float32_sub(u1.f, u2.f, &env->spe_status); + return u1.u; +} +static inline uint32_t _do_efsmul (uint32_t op1, uint32_t op2) +{ + union { + uint32_t u; + float32 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + u1.f = float32_mul(u1.f, u2.f, &env->spe_status); + return u1.u; +} +static inline uint32_t _do_efsdiv (uint32_t op1, uint32_t op2) +{ + union { + uint32_t u; + float32 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + u1.f = float32_div(u1.f, u2.f, &env->spe_status); + return u1.u; +} + +static inline int _do_efststlt (uint32_t op1, uint32_t op2) +{ + union { + uint32_t u; + float32 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + return float32_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0; +} +static inline int _do_efststgt (uint32_t op1, uint32_t op2) +{ + union { + uint32_t u; + float32 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 1; +} +static inline int _do_efststeq (uint32_t op1, uint32_t op2) +{ + union { + uint32_t u; + float32 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + return float32_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0; +} +/* Double precision floating-point helpers */ +static inline int _do_efdtstlt (uint64_t op1, uint64_t op2) +{ + union { + uint64_t u; + float64 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + return float64_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0; +} +static inline int _do_efdtstgt (uint64_t op1, uint64_t op2) +{ + union { + uint64_t u; + float64 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + return float64_le(u1.f, u2.f, &env->spe_status) ? 0 : 1; +} +static inline int _do_efdtsteq (uint64_t op1, uint64_t op2) +{ + union { + uint64_t u; + float64 f; + } u1, u2; + u1.u = op1; + u2.u = op2; + return float64_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0; +} +#endif /* defined(TARGET_PPCSPE) */ #endif diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index f5a8c4b64..f080abc41 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -37,12 +37,7 @@ static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); } -#if defined(TARGET_PPC64) -static inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA) -{ - return (int32_t)glue(ldl, MEMSUFFIX)(EA); -} - +#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE) static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) { uint64_t tmp = glue(ldq, MEMSUFFIX)(EA); @@ -55,6 +50,13 @@ static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) ((tmp & 0x000000000000FF00ULL) << 40) | ((tmp & 0x00000000000000FFULL) << 54); } +#endif + +#if defined(TARGET_PPC64) +static inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA) +{ + return (int32_t)glue(ldl, MEMSUFFIX)(EA); +} static inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA) { @@ -77,7 +79,7 @@ static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t data) glue(stl, MEMSUFFIX)(EA, tmp); } -#if defined(TARGET_PPC64) +#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE) static inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t data) { uint64_t tmp = ((data & 0xFF00000000000000ULL) >> 56) | @@ -839,4 +841,262 @@ void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void) RETURN(); } +#if defined(TARGET_PPCSPE) +/* SPE extension */ +#define _PPC_SPE_LD_OP(name, op) \ +void OPPROTO glue(glue(op_spe_l, name), MEMSUFFIX) (void) \ +{ \ + T1_64 = glue(op, MEMSUFFIX)((uint32_t)T0); \ + RETURN(); \ +} + +#if defined(TARGET_PPC64) +#define _PPC_SPE_LD_OP_64(name, op) \ +void OPPROTO glue(glue(glue(op_spe_l, name), _64), MEMSUFFIX) (void) \ +{ \ + T1_64 = glue(op, MEMSUFFIX)((uint64_t)T0); \ + RETURN(); \ +} +#define PPC_SPE_LD_OP(name, op) \ +_PPC_SPE_LD_OP(name, op); \ +_PPC_SPE_LD_OP_64(name, op) +#else +#define PPC_SPE_LD_OP(name, op) \ +_PPC_SPE_LD_OP(name, op) +#endif + + +#define _PPC_SPE_ST_OP(name, op) \ +void OPPROTO glue(glue(op_spe_st, name), MEMSUFFIX) (void) \ +{ \ + glue(op, MEMSUFFIX)((uint32_t)T0, T1_64); \ + RETURN(); \ +} + +#if defined(TARGET_PPC64) +#define _PPC_SPE_ST_OP_64(name, op) \ +void OPPROTO glue(glue(glue(op_spe_st, name), _64), MEMSUFFIX) (void) \ +{ \ + glue(op, MEMSUFFIX)((uint64_t)T0, T1_64); \ + RETURN(); \ +} +#define PPC_SPE_ST_OP(name, op) \ +_PPC_SPE_ST_OP(name, op); \ +_PPC_SPE_ST_OP_64(name, op) +#else +#define PPC_SPE_ST_OP(name, op) \ +_PPC_SPE_ST_OP(name, op) +#endif + +#if !defined(TARGET_PPC64) +PPC_SPE_LD_OP(dd, ldq); +PPC_SPE_ST_OP(dd, stq); +PPC_SPE_LD_OP(dd_le, ld64r); +PPC_SPE_ST_OP(dd_le, st64r); +#endif +static inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = (uint64_t)glue(ldl, MEMSUFFIX)(EA) << 32; + ret |= (uint64_t)glue(ldl, MEMSUFFIX)(EA + 4); + return ret; +} +PPC_SPE_LD_OP(dw, spe_ldw); +static inline void glue(spe_stdw, MEMSUFFIX) (target_ulong EA, uint64_t data) +{ + glue(stl, MEMSUFFIX)(EA, data >> 32); + glue(stl, MEMSUFFIX)(EA + 4, data); +} +PPC_SPE_ST_OP(dw, spe_stdw); +static inline uint64_t glue(spe_ldw_le, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = (uint64_t)glue(ld32r, MEMSUFFIX)(EA) << 32; + ret |= (uint64_t)glue(ld32r, MEMSUFFIX)(EA + 4); + return ret; +} +PPC_SPE_LD_OP(dw_le, spe_ldw_le); +static inline void glue(spe_stdw_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) +{ + glue(st32r, MEMSUFFIX)(EA, data >> 32); + glue(st32r, MEMSUFFIX)(EA + 4, data); +} +PPC_SPE_ST_OP(dw_le, spe_stdw_le); +static inline uint64_t glue(spe_ldh, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48; + ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 32; + ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 4) << 16; + ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 6); + return ret; +} +PPC_SPE_LD_OP(dh, spe_ldh); +static inline void glue(spe_stdh, MEMSUFFIX) (target_ulong EA, uint64_t data) +{ + glue(stw, MEMSUFFIX)(EA, data >> 48); + glue(stw, MEMSUFFIX)(EA + 2, data >> 32); + glue(stw, MEMSUFFIX)(EA + 4, data >> 16); + glue(stw, MEMSUFFIX)(EA + 6, data); +} +PPC_SPE_ST_OP(dh, spe_stdh); +static inline uint64_t glue(spe_ldh_le, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48; + ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 32; + ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 4) << 16; + ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 6); + return ret; +} +PPC_SPE_LD_OP(dh_le, spe_ldh_le); +static inline void glue(spe_stdh_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) +{ + glue(st16r, MEMSUFFIX)(EA, data >> 48); + glue(st16r, MEMSUFFIX)(EA + 2, data >> 32); + glue(st16r, MEMSUFFIX)(EA + 4, data >> 16); + glue(st16r, MEMSUFFIX)(EA + 6, data); +} +PPC_SPE_ST_OP(dh_le, spe_stdh_le); +static inline uint64_t glue(spe_lwhe, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48; + ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 16; + return ret; +} +PPC_SPE_LD_OP(whe, spe_lwhe); +static inline void glue(spe_stwhe, MEMSUFFIX) (target_ulong EA, uint64_t data) +{ + glue(stw, MEMSUFFIX)(EA, data >> 48); + glue(stw, MEMSUFFIX)(EA + 2, data >> 16); +} +PPC_SPE_ST_OP(whe, spe_stwhe); +static inline uint64_t glue(spe_lwhe_le, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48; + ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 16; + return ret; +} +PPC_SPE_LD_OP(whe_le, spe_lwhe_le); +static inline void glue(spe_stwhe_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) +{ + glue(st16r, MEMSUFFIX)(EA, data >> 48); + glue(st16r, MEMSUFFIX)(EA + 2, data >> 16); +} +PPC_SPE_ST_OP(whe_le, spe_stwhe_le); +static inline uint64_t glue(spe_lwhou, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 32; + ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2); + return ret; +} +PPC_SPE_LD_OP(whou, spe_lwhou); +static inline uint64_t glue(spe_lwhos, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = ((uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA))) << 32; + ret |= (uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA + 2)); + return ret; +} +PPC_SPE_LD_OP(whos, spe_lwhos); +static inline void glue(spe_stwho, MEMSUFFIX) (target_ulong EA, uint64_t data) +{ + glue(stw, MEMSUFFIX)(EA, data >> 32); + glue(stw, MEMSUFFIX)(EA + 2, data); +} +PPC_SPE_ST_OP(who, spe_stwho); +static inline uint64_t glue(spe_lwhou_le, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 32; + ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2); + return ret; +} +PPC_SPE_LD_OP(whou_le, spe_lwhou_le); +static inline uint64_t glue(spe_lwhos_le, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + ret = ((uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA))) << 32; + ret |= (uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA + 2)); + return ret; +} +PPC_SPE_LD_OP(whos_le, spe_lwhos_le); +static inline void glue(spe_stwho_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) +{ + glue(st16r, MEMSUFFIX)(EA, data >> 32); + glue(st16r, MEMSUFFIX)(EA + 2, data); +} +PPC_SPE_ST_OP(who_le, spe_stwho_le); +#if !defined(TARGET_PPC64) +static inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, uint64_t data) +{ + glue(stl, MEMSUFFIX)(EA, data); +} +PPC_SPE_ST_OP(wwo, spe_stwwo); +static inline void glue(spe_stwwo_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) +{ + glue(st32r, MEMSUFFIX)(EA, data); +} +PPC_SPE_ST_OP(wwo_le, spe_stwwo_le); +#endif +static inline uint64_t glue(spe_lh, MEMSUFFIX) (target_ulong EA) +{ + uint16_t tmp; + tmp = glue(lduw, MEMSUFFIX)(EA); + return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16); +} +PPC_SPE_LD_OP(h, spe_lh); +static inline uint64_t glue(spe_lh_le, MEMSUFFIX) (target_ulong EA) +{ + uint16_t tmp; + tmp = glue(ld16r, MEMSUFFIX)(EA); + return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16); +} +PPC_SPE_LD_OP(h_le, spe_lh_le); +static inline uint64_t glue(spe_lwwsplat, MEMSUFFIX) (target_ulong EA) +{ + uint32_t tmp; + tmp = glue(ldl, MEMSUFFIX)(EA); + return ((uint64_t)tmp << 32) | (uint64_t)tmp; +} +PPC_SPE_LD_OP(wwsplat, spe_lwwsplat); +static inline uint64_t glue(spe_lwwsplat_le, MEMSUFFIX) (target_ulong EA) +{ + uint32_t tmp; + tmp = glue(ld32r, MEMSUFFIX)(EA); + return ((uint64_t)tmp << 32) | (uint64_t)tmp; +} +PPC_SPE_LD_OP(wwsplat_le, spe_lwwsplat_le); +static inline uint64_t glue(spe_lwhsplat, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + uint16_t tmp; + tmp = glue(lduw, MEMSUFFIX)(EA); + ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32); + tmp = glue(lduw, MEMSUFFIX)(EA + 2); + ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp; + return ret; +} +PPC_SPE_LD_OP(whsplat, spe_lwhsplat); +static inline uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA) +{ + uint64_t ret; + uint16_t tmp; + tmp = glue(ld16r, MEMSUFFIX)(EA); + ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32); + tmp = glue(ld16r, MEMSUFFIX)(EA + 2); + ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp; + return ret; +} +PPC_SPE_LD_OP(whsplat_le, spe_lwhsplat_le); +#endif /* defined(TARGET_PPCSPE) */ + #undef MEMSUFFIX diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 511d065f6..bcef1a5cb 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -57,6 +57,48 @@ void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) } #endif +#if defined(TARGET_PPCSPE) +void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void) +{ + T0_64 = regs->gpr[REG]; + RETURN(); +} + +void OPPROTO glue(op_load_gpr64_T1_gpr, REG) (void) +{ + T1_64 = regs->gpr[REG]; + RETURN(); +} + +#if 0 // unused +void OPPROTO glue(op_load_gpr64_T2_gpr, REG) (void) +{ + T2_64 = regs->gpr[REG]; + RETURN(); +} +#endif + +void OPPROTO glue(op_store_T0_gpr64_gpr, REG) (void) +{ + regs->gpr[REG] = T0_64; + RETURN(); +} + +void OPPROTO glue(op_store_T1_gpr64_gpr, REG) (void) +{ + regs->gpr[REG] = T1_64; + RETURN(); +} + +#if 0 // unused +void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) +{ + regs->gpr[REG] = T2_64; + RETURN(); +} +#endif +#endif /* defined(TARGET_PPCSPE) */ + #if REG <= 7 /* Condition register moves */ void OPPROTO glue(op_load_crf_T0_crf, REG) (void) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d9be35d6c..90a9fc93c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -160,6 +160,9 @@ typedef struct DisasContext { int sf_mode; #endif int fpu_enabled; +#if defined(TARGET_PPCSPE) + int spe_enabled; +#endif ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; } DisasContext; @@ -168,7 +171,7 @@ struct opc_handler_t { /* invalid bits */ uint32_t inval; /* instruction type */ - uint32_t type; + uint64_t type; /* handler */ void (*handler)(DisasContext *ctx); #if defined(DO_PPC_STATISTICS) @@ -4468,6 +4471,814 @@ GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE) */ } +#if defined(TARGET_PPCSPE) +/*** SPE extension ***/ + +/* Register moves */ +GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr); +GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr); +#if 0 // unused +GEN32(gen_op_load_gpr64_T2, gen_op_load_gpr64_T2_gpr); +#endif + +GEN32(gen_op_store_T0_gpr64, gen_op_store_T0_gpr64_gpr); +GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr); +#if 0 // unused +GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr); +#endif + +#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ +GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) \ +{ \ + if (Rc(ctx->opcode)) \ + gen_##name1(ctx); \ + else \ + gen_##name0(ctx); \ +} + +/* Handler for undefined SPE opcodes */ +static inline void gen_speundef (DisasContext *ctx) +{ + RET_INVAL(ctx); +} + +/* SPE load and stores */ +static inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh) +{ + target_long simm = rB(ctx->opcode); + + if (rA(ctx->opcode) == 0) { + gen_set_T0(simm << sh); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + if (likely(simm != 0)) + gen_op_addi(simm << sh); + } +} + +#define op_spe_ldst(name) (*gen_op_##name[ctx->mem_idx])() +#if defined(CONFIG_USER_ONLY) +#if defined(TARGET_PPC64) +#define OP_SPE_LD_TABLE(name) \ +static GenOpFunc *gen_op_spe_l##name[] = { \ + &gen_op_spe_l##name##_raw, \ + &gen_op_spe_l##name##_le_raw, \ + &gen_op_spe_l##name##_64_raw, \ + &gen_op_spe_l##name##_le_64_raw, \ +}; +#define OP_SPE_ST_TABLE(name) \ +static GenOpFunc *gen_op_spe_st##name[] = { \ + &gen_op_spe_st##name##_raw, \ + &gen_op_spe_st##name##_le_raw, \ + &gen_op_spe_st##name##_64_raw, \ + &gen_op_spe_st##name##_le_64_raw, \ +}; +#else /* defined(TARGET_PPC64) */ +#define OP_SPE_LD_TABLE(name) \ +static GenOpFunc *gen_op_spe_l##name[] = { \ + &gen_op_spe_l##name##_raw, \ + &gen_op_spe_l##name##_le_raw, \ +}; +#define OP_SPE_ST_TABLE(name) \ +static GenOpFunc *gen_op_spe_st##name[] = { \ + &gen_op_spe_st##name##_raw, \ + &gen_op_spe_st##name##_le_raw, \ +}; +#endif /* defined(TARGET_PPC64) */ +#else /* defined(CONFIG_USER_ONLY) */ +#if defined(TARGET_PPC64) +#define OP_SPE_LD_TABLE(name) \ +static GenOpFunc *gen_op_spe_l##name[] = { \ + &gen_op_spe_l##name##_user, \ + &gen_op_spe_l##name##_le_user, \ + &gen_op_spe_l##name##_kernel, \ + &gen_op_spe_l##name##_le_kernel, \ + &gen_op_spe_l##name##_64_user, \ + &gen_op_spe_l##name##_le_64_user, \ + &gen_op_spe_l##name##_64_kernel, \ + &gen_op_spe_l##name##_le_64_kernel, \ +}; +#define OP_SPE_ST_TABLE(name) \ +static GenOpFunc *gen_op_spe_st##name[] = { \ + &gen_op_spe_st##name##_user, \ + &gen_op_spe_st##name##_le_user, \ + &gen_op_spe_st##name##_kernel, \ + &gen_op_spe_st##name##_le_kernel, \ + &gen_op_spe_st##name##_64_user, \ + &gen_op_spe_st##name##_le_64_user, \ + &gen_op_spe_st##name##_64_kernel, \ + &gen_op_spe_st##name##_le_64_kernel, \ +}; +#else /* defined(TARGET_PPC64) */ +#define OP_SPE_LD_TABLE(name) \ +static GenOpFunc *gen_op_spe_l##name[] = { \ + &gen_op_spe_l##name##_user, \ + &gen_op_spe_l##name##_le_user, \ + &gen_op_spe_l##name##_kernel, \ + &gen_op_spe_l##name##_le_kernel, \ +}; +#define OP_SPE_ST_TABLE(name) \ +static GenOpFunc *gen_op_spe_st##name[] = { \ + &gen_op_spe_st##name##_user, \ + &gen_op_spe_st##name##_le_user, \ + &gen_op_spe_st##name##_kernel, \ + &gen_op_spe_st##name##_le_kernel, \ +}; +#endif /* defined(TARGET_PPC64) */ +#endif /* defined(CONFIG_USER_ONLY) */ + +#define GEN_SPE_LD(name, sh) \ +static inline void gen_evl##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_addr_spe_imm_index(ctx, sh); \ + op_spe_ldst(spe_l##name); \ + gen_op_store_T1_gpr64(rD(ctx->opcode)); \ +} + +#define GEN_SPE_LDX(name) \ +static inline void gen_evl##name##x (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_addr_reg_index(ctx); \ + op_spe_ldst(spe_l##name); \ + gen_op_store_T1_gpr64(rD(ctx->opcode)); \ +} + +#define GEN_SPEOP_LD(name, sh) \ +OP_SPE_LD_TABLE(name); \ +GEN_SPE_LD(name, sh); \ +GEN_SPE_LDX(name) + +#define GEN_SPE_ST(name, sh) \ +static inline void gen_evst##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_addr_spe_imm_index(ctx, sh); \ + gen_op_load_gpr64_T1(rS(ctx->opcode)); \ + op_spe_ldst(spe_st##name); \ +} + +#define GEN_SPE_STX(name) \ +static inline void gen_evst##name##x (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_addr_reg_index(ctx); \ + gen_op_load_gpr64_T1(rS(ctx->opcode)); \ + op_spe_ldst(spe_st##name); \ +} + +#define GEN_SPEOP_ST(name, sh) \ +OP_SPE_ST_TABLE(name); \ +GEN_SPE_ST(name, sh); \ +GEN_SPE_STX(name) + +#define GEN_SPEOP_LDST(name, sh) \ +GEN_SPEOP_LD(name, sh); \ +GEN_SPEOP_ST(name, sh) + +/* SPE arithmetic and logic */ +#define GEN_SPEOP_ARITH2(name) \ +static inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_op_load_gpr64_T0(rA(ctx->opcode)); \ + gen_op_load_gpr64_T1(rB(ctx->opcode)); \ + gen_op_##name(); \ + gen_op_store_T0_gpr64(rD(ctx->opcode)); \ +} + +#define GEN_SPEOP_ARITH1(name) \ +static inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_op_load_gpr64_T0(rA(ctx->opcode)); \ + gen_op_##name(); \ + gen_op_store_T0_gpr64(rD(ctx->opcode)); \ +} + +#define GEN_SPEOP_COMP(name) \ +static inline void gen_##name (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_op_load_gpr64_T0(rA(ctx->opcode)); \ + gen_op_load_gpr64_T1(rB(ctx->opcode)); \ + gen_op_##name(); \ + gen_op_store_T0_crf(crfD(ctx->opcode)); \ +} + +/* Logical */ +GEN_SPEOP_ARITH2(evand); +GEN_SPEOP_ARITH2(evandc); +GEN_SPEOP_ARITH2(evxor); +GEN_SPEOP_ARITH2(evor); +GEN_SPEOP_ARITH2(evnor); +GEN_SPEOP_ARITH2(eveqv); +GEN_SPEOP_ARITH2(evorc); +GEN_SPEOP_ARITH2(evnand); +GEN_SPEOP_ARITH2(evsrwu); +GEN_SPEOP_ARITH2(evsrws); +GEN_SPEOP_ARITH2(evslw); +GEN_SPEOP_ARITH2(evrlw); +GEN_SPEOP_ARITH2(evmergehi); +GEN_SPEOP_ARITH2(evmergelo); +GEN_SPEOP_ARITH2(evmergehilo); +GEN_SPEOP_ARITH2(evmergelohi); + +/* Arithmetic */ +GEN_SPEOP_ARITH2(evaddw); +GEN_SPEOP_ARITH2(evsubfw); +GEN_SPEOP_ARITH1(evabs); +GEN_SPEOP_ARITH1(evneg); +GEN_SPEOP_ARITH1(evextsb); +GEN_SPEOP_ARITH1(evextsh); +GEN_SPEOP_ARITH1(evrndw); +GEN_SPEOP_ARITH1(evcntlzw); +GEN_SPEOP_ARITH1(evcntlsw); +static inline void gen_brinc (DisasContext *ctx) +{ + /* Note: brinc is usable even if SPE is disabled */ + gen_op_load_gpr64_T0(rA(ctx->opcode)); + gen_op_load_gpr64_T1(rB(ctx->opcode)); + gen_op_brinc(); + gen_op_store_T0_gpr64(rD(ctx->opcode)); +} + +#define GEN_SPEOP_ARITH_IMM2(name) \ +static inline void gen_##name##i (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_op_load_gpr64_T0(rB(ctx->opcode)); \ + gen_op_splatwi_T1_64(rA(ctx->opcode)); \ + gen_op_##name(); \ + gen_op_store_T0_gpr64(rD(ctx->opcode)); \ +} + +#define GEN_SPEOP_LOGIC_IMM2(name) \ +static inline void gen_##name##i (DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->spe_enabled)) { \ + RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + return; \ + } \ + gen_op_load_gpr64_T0(rA(ctx->opcode)); \ + gen_op_splatwi_T1_64(rB(ctx->opcode)); \ + gen_op_##name(); \ + gen_op_store_T0_gpr64(rD(ctx->opcode)); \ +} + +GEN_SPEOP_ARITH_IMM2(evaddw); +#define gen_evaddiw gen_evaddwi +GEN_SPEOP_ARITH_IMM2(evsubfw); +#define gen_evsubifw gen_evsubfwi +GEN_SPEOP_LOGIC_IMM2(evslw); +GEN_SPEOP_LOGIC_IMM2(evsrwu); +#define gen_evsrwis gen_evsrwsi +GEN_SPEOP_LOGIC_IMM2(evsrws); +#define gen_evsrwiu gen_evsrwui +GEN_SPEOP_LOGIC_IMM2(evrlw); + +static inline void gen_evsplati (DisasContext *ctx) +{ + int32_t imm = (int32_t)(rA(ctx->opcode) << 27) >> 27; + + gen_op_splatwi_T0_64(imm); + gen_op_store_T0_gpr64(rD(ctx->opcode)); +} + +static inline void gen_evsplatfi (DisasContext *ctx) +{ + uint32_t imm = rA(ctx->opcode) << 27; + + gen_op_splatwi_T0_64(imm); + gen_op_store_T0_gpr64(rD(ctx->opcode)); +} + +/* Comparison */ +GEN_SPEOP_COMP(evcmpgtu); +GEN_SPEOP_COMP(evcmpgts); +GEN_SPEOP_COMP(evcmpltu); +GEN_SPEOP_COMP(evcmplts); +GEN_SPEOP_COMP(evcmpeq); + +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, PPC_SPE); +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, PPC_SPE); +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, PPC_SPE); //// +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, PPC_SPE); //// +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, PPC_SPE); //// +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x00000000, PPC_SPE); // +GEN_SPE(speundef, evand, 0x08, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, PPC_SPE); +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, PPC_SPE); +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, PPC_SPE); // +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, PPC_SPE); +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, PPC_SPE); //// +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); //// + +static inline void gen_evsel (DisasContext *ctx) +{ + if (unlikely(!ctx->spe_enabled)) { + RET_EXCP(ctx, EXCP_NO_SPE, 0); + return; + } + gen_op_load_crf_T0(ctx->opcode & 0x7); + gen_op_load_gpr64_T0(rA(ctx->opcode)); + gen_op_load_gpr64_T1(rB(ctx->opcode)); + gen_op_evsel(); + gen_op_store_T0_gpr64(rD(ctx->opcode)); +} + +GEN_HANDLER(evsel0, 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE) +{ + gen_evsel(ctx); +} +GEN_HANDLER(evsel1, 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE) +{ + gen_evsel(ctx); +} +GEN_HANDLER(evsel2, 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE) +{ + gen_evsel(ctx); +} +GEN_HANDLER(evsel3, 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE) +{ + gen_evsel(ctx); +} + +/* Load and stores */ +#if defined(TARGET_PPC64) +/* In that case, we already have 64 bits load & stores + * so, spe_ldd is equivalent to ld and spe_std is equivalent to std + */ +#if defined(CONFIG_USER_ONLY) +#define gen_op_spe_ldd_raw gen_op_ld_raw +#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw +#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw +#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw +#define gen_op_spe_stdd_raw gen_op_ld_raw +#define gen_op_spe_stdd_64_raw gen_op_std_64_raw +#define gen_op_spe_stdd_le_raw gen_op_std_le_raw +#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw +#else /* defined(CONFIG_USER_ONLY) */ +#define gen_op_spe_ldd_kernel gen_op_ld_kernel +#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel +#define gen_op_spe_ldd_le_kernel gen_op_ld_kernel +#define gen_op_spe_ldd_le_64_kernel gen_op_ld_64_kernel +#define gen_op_spe_ldd_user gen_op_ld_user +#define gen_op_spe_ldd_64_user gen_op_ld_64_user +#define gen_op_spe_ldd_le_user gen_op_ld_le_user +#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user +#define gen_op_spe_stdd_kernel gen_op_std_kernel +#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel +#define gen_op_spe_stdd_le_kernel gen_op_std_kernel +#define gen_op_spe_stdd_le_64_kernel gen_op_std_64_kernel +#define gen_op_spe_stdd_user gen_op_std_user +#define gen_op_spe_stdd_64_user gen_op_std_64_user +#define gen_op_spe_stdd_le_user gen_op_std_le_user +#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user +#endif /* defined(CONFIG_USER_ONLY) */ +#endif /* defined(TARGET_PPC64) */ +GEN_SPEOP_LDST(dd, 3); +GEN_SPEOP_LDST(dw, 3); +GEN_SPEOP_LDST(dh, 3); +GEN_SPEOP_LDST(whe, 2); +GEN_SPEOP_LD(whou, 2); +GEN_SPEOP_LD(whos, 2); +GEN_SPEOP_ST(who, 2); + +#if defined(TARGET_PPC64) +/* In that case, spe_stwwo is equivalent to stw */ +#if defined(CONFIG_USER_ONLY) +#define gen_op_spe_stwwo_raw gen_op_stw_raw +#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw +#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw +#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw +#else +#define gen_op_spe_stwwo_user gen_op_stw_user +#define gen_op_spe_stwwo_le_user gen_op_stw_le_user +#define gen_op_spe_stwwo_64_user gen_op_stw_64_user +#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user +#define gen_op_spe_stwwo_kernel gen_op_stw_kernel +#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel +#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel +#define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel +#endif +#endif +#define _GEN_OP_SPE_STWWE(suffix) \ +static inline void gen_op_spe_stwwe_##suffix (void) \ +{ \ + gen_op_srli32_T1_64(); \ + gen_op_spe_stwwo_##suffix(); \ +} +#define _GEN_OP_SPE_STWWE_LE(suffix) \ +static inline void gen_op_spe_stwwe_le_##suffix (void) \ +{ \ + gen_op_srli32_T1_64(); \ + gen_op_spe_stwwo_le_##suffix(); \ +} +#if defined(TARGET_PPC64) +#define GEN_OP_SPE_STWWE(suffix) \ +_GEN_OP_SPE_STWWE(suffix); \ +_GEN_OP_SPE_STWWE_LE(suffix); \ +static inline void gen_op_spe_stwwe_64_##suffix (void) \ +{ \ + gen_op_srli32_T1_64(); \ + gen_op_spe_stwwo_64_##suffix(); \ +} \ +static inline void gen_op_spe_stwwe_le_64_##suffix (void) \ +{ \ + gen_op_srli32_T1_64(); \ + gen_op_spe_stwwo_le_64_##suffix(); \ +} +#else +#define GEN_OP_SPE_STWWE(suffix) \ +_GEN_OP_SPE_STWWE(suffix); \ +_GEN_OP_SPE_STWWE_LE(suffix) +#endif +#if defined(CONFIG_USER_ONLY) +GEN_OP_SPE_STWWE(raw); +#else /* defined(CONFIG_USER_ONLY) */ +GEN_OP_SPE_STWWE(kernel); +GEN_OP_SPE_STWWE(user); +#endif /* defined(CONFIG_USER_ONLY) */ +GEN_SPEOP_ST(wwe, 2); +GEN_SPEOP_ST(wwo, 2); + +#define GEN_SPE_LDSPLAT(name, op, suffix) \ +static inline void gen_op_spe_l##name##_##suffix (void) \ +{ \ + gen_op_##op##_##suffix(); \ + gen_op_splatw_T1_64(); \ +} + +#define GEN_OP_SPE_LHE(suffix) \ +static inline void gen_op_spe_lhe_##suffix (void) \ +{ \ + gen_op_spe_lh_##suffix(); \ + gen_op_sli16_T1_64(); \ +} + +#define GEN_OP_SPE_LHX(suffix) \ +static inline void gen_op_spe_lhx_##suffix (void) \ +{ \ + gen_op_spe_lh_##suffix(); \ + gen_op_extsh_T1_64(); \ +} + +#if defined(CONFIG_USER_ONLY) +GEN_OP_SPE_LHE(raw); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, raw); +GEN_OP_SPE_LHE(le_raw); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_raw); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, raw); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_raw); +GEN_OP_SPE_LHX(raw); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, raw); +GEN_OP_SPE_LHX(le_raw); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_raw); +#if defined(TARGET_PPC64) +GEN_OP_SPE_LHE(64_raw); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_raw); +GEN_OP_SPE_LHE(le_64_raw); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_raw); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_raw); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_raw); +GEN_OP_SPE_LHX(64_raw); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_raw); +GEN_OP_SPE_LHX(le_64_raw); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw); +#endif +#else +GEN_OP_SPE_LHE(kernel); +GEN_OP_SPE_LHE(user); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user); +GEN_OP_SPE_LHE(le_kernel); +GEN_OP_SPE_LHE(le_user); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, user); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user); +GEN_OP_SPE_LHX(kernel); +GEN_OP_SPE_LHX(user); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user); +GEN_OP_SPE_LHX(le_kernel); +GEN_OP_SPE_LHX(le_user); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user); +#if defined(TARGET_PPC64) +GEN_OP_SPE_LHE(64_kernel); +GEN_OP_SPE_LHE(64_user); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user); +GEN_OP_SPE_LHE(le_64_kernel); +GEN_OP_SPE_LHE(le_64_user); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user); +GEN_OP_SPE_LHX(64_kernel); +GEN_OP_SPE_LHX(64_user); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user); +GEN_OP_SPE_LHX(le_64_kernel); +GEN_OP_SPE_LHX(le_64_user); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user); +#endif +#endif +GEN_SPEOP_LD(hhesplat, 1); +GEN_SPEOP_LD(hhousplat, 1); +GEN_SPEOP_LD(hhossplat, 1); +GEN_SPEOP_LD(wwsplat, 2); +GEN_SPEOP_LD(whsplat, 2); + +GEN_SPE(evlddx, evldd, 0x00, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evldwx, evldw, 0x01, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evldhx, evldh, 0x02, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evlhhesplatx, evlhhesplat, 0x04, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evlhhousplatx, evlhhousplat, 0x06, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evlhhossplatx, evlhhossplat, 0x07, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evlwhex, evlwhe, 0x08, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evlwhoux, evlwhou, 0x0A, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evlwhosx, evlwhos, 0x0B, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evlwwsplatx, evlwwsplat, 0x0C, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evlwhsplatx, evlwhsplat, 0x0E, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evstddx, evstdd, 0x10, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evstdwx, evstdw, 0x11, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evstdhx, evstdh, 0x12, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evstwhex, evstwhe, 0x18, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evstwhox, evstwho, 0x1A, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evstwwex, evstwwe, 0x1C, 0x0C, 0x00000000, PPC_SPE); // +GEN_SPE(evstwwox, evstwwo, 0x1E, 0x0C, 0x00000000, PPC_SPE); // + +/* Multiply and add - TODO */ +#if 0 +GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0x00000000, PPC_SPE); + +GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0x00000000, PPC_SPE); + +GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, PPC_SPE); +GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, PPC_SPE); +GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, PPC_SPE); +GEN_SPE(evmra, speundef, 0x07, 0x13, 0x0000F800, PPC_SPE); + +GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0x00000000, PPC_SPE); + +GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0x00000000, PPC_SPE); +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0x00000000, PPC_SPE); + +GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0x00000000, PPC_SPE); + +GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0x00000000, PPC_SPE); +GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0x00000000, PPC_SPE); +#endif + +/*** SPE floating-point extension ***/ +#define GEN_SPEFPUOP_CONV(name) \ +static inline void gen_##name (DisasContext *ctx) \ +{ \ + gen_op_load_gpr64_T0(rB(ctx->opcode)); \ + gen_op_##name(); \ + gen_op_store_T0_gpr64(rD(ctx->opcode)); \ +} + +/* Single precision floating-point vectors operations */ +/* Arithmetic */ +GEN_SPEOP_ARITH2(evfsadd); +GEN_SPEOP_ARITH2(evfssub); +GEN_SPEOP_ARITH2(evfsmul); +GEN_SPEOP_ARITH2(evfsdiv); +GEN_SPEOP_ARITH1(evfsabs); +GEN_SPEOP_ARITH1(evfsnabs); +GEN_SPEOP_ARITH1(evfsneg); +/* Conversion */ +GEN_SPEFPUOP_CONV(evfscfui); +GEN_SPEFPUOP_CONV(evfscfsi); +GEN_SPEFPUOP_CONV(evfscfuf); +GEN_SPEFPUOP_CONV(evfscfsf); +GEN_SPEFPUOP_CONV(evfsctui); +GEN_SPEFPUOP_CONV(evfsctsi); +GEN_SPEFPUOP_CONV(evfsctuf); +GEN_SPEFPUOP_CONV(evfsctsf); +GEN_SPEFPUOP_CONV(evfsctuiz); +GEN_SPEFPUOP_CONV(evfsctsiz); +/* Comparison */ +GEN_SPEOP_COMP(evfscmpgt); +GEN_SPEOP_COMP(evfscmplt); +GEN_SPEOP_COMP(evfscmpeq); +GEN_SPEOP_COMP(evfststgt); +GEN_SPEOP_COMP(evfststlt); +GEN_SPEOP_COMP(evfststeq); + +/* Opcodes definitions */ +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPEFPU); // +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPEFPU); // +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPEFPU); // +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPEFPU); // +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPEFPU); // +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPEFPU); // +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPEFPU); // +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPEFPU); // +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPEFPU); // +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPEFPU); // +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPEFPU); // +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPEFPU); // +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPEFPU); // +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPEFPU); // + +/* Single precision floating-point operations */ +/* Arithmetic */ +GEN_SPEOP_ARITH2(efsadd); +GEN_SPEOP_ARITH2(efssub); +GEN_SPEOP_ARITH2(efsmul); +GEN_SPEOP_ARITH2(efsdiv); +GEN_SPEOP_ARITH1(efsabs); +GEN_SPEOP_ARITH1(efsnabs); +GEN_SPEOP_ARITH1(efsneg); +/* Conversion */ +GEN_SPEFPUOP_CONV(efscfui); +GEN_SPEFPUOP_CONV(efscfsi); +GEN_SPEFPUOP_CONV(efscfuf); +GEN_SPEFPUOP_CONV(efscfsf); +GEN_SPEFPUOP_CONV(efsctui); +GEN_SPEFPUOP_CONV(efsctsi); +GEN_SPEFPUOP_CONV(efsctuf); +GEN_SPEFPUOP_CONV(efsctsf); +GEN_SPEFPUOP_CONV(efsctuiz); +GEN_SPEFPUOP_CONV(efsctsiz); +GEN_SPEFPUOP_CONV(efscfd); +/* Comparison */ +GEN_SPEOP_COMP(efscmpgt); +GEN_SPEOP_COMP(efscmplt); +GEN_SPEOP_COMP(efscmpeq); +GEN_SPEOP_COMP(efststgt); +GEN_SPEOP_COMP(efststlt); +GEN_SPEOP_COMP(efststeq); + +/* Opcodes definitions */ +GEN_SPE(efsadd, efssub, 0x00, 0x0A, 0x00000000, PPC_SPEFPU); // +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPEFPU); // +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPEFPU); // +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPEFPU); // +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPEFPU); // +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPEFPU); // +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efsctuiz, efsctsiz, 0x0C, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPEFPU); // +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPEFPU); // + +/* Double precision floating-point operations */ +/* Arithmetic */ +GEN_SPEOP_ARITH2(efdadd); +GEN_SPEOP_ARITH2(efdsub); +GEN_SPEOP_ARITH2(efdmul); +GEN_SPEOP_ARITH2(efddiv); +GEN_SPEOP_ARITH1(efdabs); +GEN_SPEOP_ARITH1(efdnabs); +GEN_SPEOP_ARITH1(efdneg); +/* Conversion */ + +GEN_SPEFPUOP_CONV(efdcfui); +GEN_SPEFPUOP_CONV(efdcfsi); +GEN_SPEFPUOP_CONV(efdcfuf); +GEN_SPEFPUOP_CONV(efdcfsf); +GEN_SPEFPUOP_CONV(efdctui); +GEN_SPEFPUOP_CONV(efdctsi); +GEN_SPEFPUOP_CONV(efdctuf); +GEN_SPEFPUOP_CONV(efdctsf); +GEN_SPEFPUOP_CONV(efdctuiz); +GEN_SPEFPUOP_CONV(efdctsiz); +GEN_SPEFPUOP_CONV(efdcfs); +GEN_SPEFPUOP_CONV(efdcfuid); +GEN_SPEFPUOP_CONV(efdcfsid); +GEN_SPEFPUOP_CONV(efdctuidz); +GEN_SPEFPUOP_CONV(efdctsidz); +/* Comparison */ +GEN_SPEOP_COMP(efdcmpgt); +GEN_SPEOP_COMP(efdcmplt); +GEN_SPEOP_COMP(efdcmpeq); +GEN_SPEOP_COMP(efdtstgt); +GEN_SPEOP_COMP(efdtstlt); +GEN_SPEOP_COMP(efdtsteq); + +/* Opcodes definitions */ +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPEFPU); // +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPEFPU); // +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPEFPU); // +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPEFPU); // +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPEFPU); // +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPEFPU); // +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPEFPU); // +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPEFPU); // +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPEFPU); // +#endif + /* End opcode list */ GEN_OPCODE_MARK(end); @@ -4604,9 +5415,9 @@ void cpu_dump_statistics (CPUState *env, FILE*f, } /*****************************************************************************/ -static inline int -gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, - int search_pc) +static inline int gen_intermediate_code_internal (CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext ctx, *ctxp = &ctx; opc_handler_t **table, *handler; @@ -4639,6 +5450,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.sf_mode = msr_sf; #endif ctx.fpu_enabled = msr_fp; +#if defined(TARGET_PPCSPE) + ctx.spe_enabled = msr_spe; +#endif ctx.singlestep_enabled = env->singlestep_enabled; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d4159fab4..1778ef1a8 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -30,7 +30,7 @@ struct ppc_def_t { const unsigned char *name; uint32_t pvr; uint32_t pvr_mask; - uint32_t insns_flags; + uint64_t insns_flags; uint32_t flags; uint64_t msr_mask; }; @@ -2424,7 +2424,8 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) fill_new_table(env->opcodes, 0x40); #if defined(PPC_DUMP_CPU) - printf("* PowerPC instructions for PVR %08x: %s flags %08x %08x\n", + printf("* PowerPC instructions for PVR %08x: %s flags %016 " PRIx64 + " %08x\n", def->pvr, def->name, def->insns_flags, def->flags); #endif if (&opc_start < &opc_end) { -- cgit v1.2.3 From 3430b0be36fb7f8bd963333d32f0f61c8a130698 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 20 Mar 2007 22:25:37 +0000 Subject: Ooops... Typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2520 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 52e2db121..6db6cf132 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1164,7 +1164,7 @@ float32 int64_to_float32( int64 a STATUS_PARAM ) } -float64 uint64_to_float32( uint64 a STATUS_PARAM ) +float32 uint64_to_float32( uint64 a STATUS_PARAM ) { int8 shiftCount; -- cgit v1.2.3 From 1698b74161e9bbcf36c5075fe5b8357024c4b5bb Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 21 Mar 2007 08:21:02 +0000 Subject: Fix compilation on 32 bits hosts (pb reported by Thiemo Seufer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2521 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 2 +- target-ppc/op_helper.h | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 0b972c8e6..f13f6f567 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -720,7 +720,7 @@ void OPPROTO op_check_addo (void) void OPPROTO op_check_addo_64 (void) { if (likely(!(((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) & - ((uint64_t)T2 ^ (uint64_t)T0) & (1UL << 63)))) { + ((uint64_t)T2 ^ (uint64_t)T0) & (1ULL << 63)))) { xer_ov = 0; } else { xer_so = 1; diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 8a735c1fd..3aa604583 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -313,12 +313,11 @@ static inline int _do_cntlzd (uint64_t val) cnt++; } #else - uint32_t tmp; /* Make it easier on 32 bits host machines */ if (!(val >> 32)) - cnt = cntlzw(val) + 32; + cnt = _do_cntlzw(val) + 32; else - cnt = cntlzw(val >> 32); + cnt = _do_cntlzw(val >> 32); #endif return cnt; } -- cgit v1.2.3 From 3953d7868768c179440e8302e536b436171205cc Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 21 Mar 2007 11:04:42 +0000 Subject: Move mips CPU specific initialization to translate_init.c. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2522 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/mips-defs.h | 37 --------------------------- target-mips/translate.c | 3 --- target-mips/translate_init.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 40 deletions(-) diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index b0fc98396..b59af0fd7 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -15,43 +15,6 @@ #define MIPS_USES_R4K_TLB #define MIPS_TLB_NB 16 #define MIPS_TLB_MAX 128 -/* Define a implementation number of 1. - * Define a major version 1, minor version 0. - */ -#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0) - /* Have config1, is MIPS32R1, uses TLB, no virtual icache, - uncached coherency */ -#define MIPS_CONFIG0_1 \ - ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) | \ - (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) | \ - (0x2 << CP0C0_K0)) -#ifdef TARGET_WORDS_BIGENDIAN -#define MIPS_CONFIG0 (MIPS_CONFIG0_1 | (1 << CP0C0_BE)) -#else -#define MIPS_CONFIG0 MIPS_CONFIG0_1 -#endif -/* Have config2, 16 TLB entries, 64 sets Icache, 16 bytes Icache line, - 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, - no coprocessor2 attached, no MDMX support attached, - no performance counters, watch registers present, - no code compression, EJTAG present, no FPU */ -#define MIPS_CONFIG1 \ -((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) | \ - (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \ - (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \ - (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \ - (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \ - (0 << CP0C1_FP)) -/* Have config3, no tertiary/secondary caches implemented */ -#define MIPS_CONFIG2 \ -((1 << CP0C2_M)) -/* No config4, no DSP ASE, no large physaddr, - no external interrupt controller, no vectored interupts, - no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */ -#define MIPS_CONFIG3 \ -((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \ - (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \ - (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL)) #ifdef MIPS_HAS_MIPS64 #define TARGET_LONG_BITS 64 diff --git a/target-mips/translate.c b/target-mips/translate.c index b39ec5f98..89061db9a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5292,8 +5292,6 @@ void cpu_reset (CPUMIPSState *env) env->CP0_Wired = 0; /* SMP not implemented */ env->CP0_EBase = 0x80000000; - env->CP0_Config2 = MIPS_CONFIG2; - env->CP0_Config3 = MIPS_CONFIG3; env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); env->CP0_WatchLo = 0; env->hflags = MIPS_HFLAG_ERL; @@ -5305,7 +5303,6 @@ void cpu_reset (CPUMIPSState *env) env->hflags |= MIPS_HFLAG_UM; env->user_mode_only = 1; #endif - env->fcr0 = MIPS_FCR0; /* XXX some guesswork here, values are CPU specific */ env->SYNCI_Step = 16; env->CCRes = 2; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index b7baff187..b87d8f3b5 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -19,11 +19,53 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* CPU / CPU family specific config register values. */ + +/* Have config1, is MIPS32R1, uses TLB, no virtual icache, + uncached coherency */ +#define MIPS_CONFIG0 \ + ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) | \ + (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) | \ + (0x2 << CP0C0_K0)) + +/* Have config2, 16 TLB entries, 64 sets Icache, 16 bytes Icache line, + 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, + no coprocessor2 attached, no MDMX support attached, + no performance counters, watch registers present, + no code compression, EJTAG present, no FPU */ +#define MIPS_CONFIG1 \ +((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) | \ + (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \ + (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \ + (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \ + (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \ + (0 << CP0C1_FP)) + +/* Have config3, no tertiary/secondary caches implemented */ +#define MIPS_CONFIG2 \ +((1 << CP0C2_M)) + +/* No config4, no DSP ASE, no large physaddr, + no external interrupt controller, no vectored interupts, + no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */ +#define MIPS_CONFIG3 \ +((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \ + (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \ + (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL)) + +/* Define a implementation number of 1. + Define a major version 1, minor version 0. */ +#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0) + + struct mips_def_t { const unsigned char *name; int32_t CP0_PRid; int32_t CP0_Config0; int32_t CP0_Config1; + int32_t CP0_Config2; + int32_t CP0_Config3; + int32_t CP1_fcr0; }; /*****************************************************************************/ @@ -36,18 +78,27 @@ static mips_def_t mips_defs[] = .CP0_PRid = 0x00018000, .CP0_Config0 = MIPS_CONFIG0, .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP1_fcr0 = MIPS_FCR0, }, { .name = "4KEc", .CP0_PRid = 0x00018400, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP1_fcr0 = MIPS_FCR0, }, { .name = "24Kf", .CP0_PRid = 0x00019300, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP1_fcr0 = MIPS_FCR0, }, #else { @@ -55,6 +106,9 @@ static mips_def_t mips_defs[] = .CP0_PRid = 0x00000400, .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT), .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP1_fcr0 = MIPS_FCR0, }, #endif }; @@ -91,7 +145,14 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) if (!def) cpu_abort(env, "Unable to find MIPS CPU definition\n"); env->CP0_PRid = def->CP0_PRid; +#ifdef TARGET_WORDS_BIGENDIAN + env->CP0_Config0 = def->CP0_Config0 | (1 << CP0C0_BE); +#else env->CP0_Config0 = def->CP0_Config0; +#endif env->CP0_Config1 = def->CP0_Config1; + env->CP0_Config2 = def->CP0_Config2; + env->CP0_Config3 = def->CP0_Config3; + env->fcr0 = def->CP1_fcr0; return 0; } -- cgit v1.2.3 From 9bad0425a0792b868eecfb9edd9157891554aa51 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 21 Mar 2007 19:45:50 +0000 Subject: Fix Sparc branches, original patch by Aurelien Jarno git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2523 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 455dd171e..74a0a2cb8 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -681,7 +681,7 @@ static inline void gen_mov_pc_npc(DisasContext * dc) static GenOpFunc * const gen_cond[2][16] = { { - gen_op_eval_ba, + gen_op_eval_bn, gen_op_eval_be, gen_op_eval_ble, gen_op_eval_bl, @@ -689,7 +689,7 @@ static GenOpFunc * const gen_cond[2][16] = { gen_op_eval_bcs, gen_op_eval_bneg, gen_op_eval_bvs, - gen_op_eval_bn, + gen_op_eval_ba, gen_op_eval_bne, gen_op_eval_bg, gen_op_eval_bge, @@ -700,7 +700,7 @@ static GenOpFunc * const gen_cond[2][16] = { }, { #ifdef TARGET_SPARC64 - gen_op_eval_ba, + gen_op_eval_bn, gen_op_eval_xbe, gen_op_eval_xble, gen_op_eval_xbl, @@ -708,7 +708,7 @@ static GenOpFunc * const gen_cond[2][16] = { gen_op_eval_xbcs, gen_op_eval_xbneg, gen_op_eval_xbvs, - gen_op_eval_bn, + gen_op_eval_ba, gen_op_eval_xbne, gen_op_eval_xbg, gen_op_eval_xbge, @@ -722,7 +722,7 @@ static GenOpFunc * const gen_cond[2][16] = { static GenOpFunc * const gen_fcond[4][16] = { { - gen_op_eval_ba, + gen_op_eval_bn, gen_op_eval_fbne, gen_op_eval_fblg, gen_op_eval_fbul, @@ -730,7 +730,7 @@ static GenOpFunc * const gen_fcond[4][16] = { gen_op_eval_fbug, gen_op_eval_fbg, gen_op_eval_fbu, - gen_op_eval_bn, + gen_op_eval_ba, gen_op_eval_fbe, gen_op_eval_fbue, gen_op_eval_fbge, @@ -741,7 +741,7 @@ static GenOpFunc * const gen_fcond[4][16] = { }, #ifdef TARGET_SPARC64 { - gen_op_eval_ba, + gen_op_eval_bn, gen_op_eval_fbne_fcc1, gen_op_eval_fblg_fcc1, gen_op_eval_fbul_fcc1, @@ -749,7 +749,7 @@ static GenOpFunc * const gen_fcond[4][16] = { gen_op_eval_fbug_fcc1, gen_op_eval_fbg_fcc1, gen_op_eval_fbu_fcc1, - gen_op_eval_bn, + gen_op_eval_ba, gen_op_eval_fbe_fcc1, gen_op_eval_fbue_fcc1, gen_op_eval_fbge_fcc1, @@ -759,7 +759,7 @@ static GenOpFunc * const gen_fcond[4][16] = { gen_op_eval_fbo_fcc1, }, { - gen_op_eval_ba, + gen_op_eval_bn, gen_op_eval_fbne_fcc2, gen_op_eval_fblg_fcc2, gen_op_eval_fbul_fcc2, @@ -767,7 +767,7 @@ static GenOpFunc * const gen_fcond[4][16] = { gen_op_eval_fbug_fcc2, gen_op_eval_fbg_fcc2, gen_op_eval_fbu_fcc2, - gen_op_eval_bn, + gen_op_eval_ba, gen_op_eval_fbe_fcc2, gen_op_eval_fbue_fcc2, gen_op_eval_fbge_fcc2, @@ -777,7 +777,7 @@ static GenOpFunc * const gen_fcond[4][16] = { gen_op_eval_fbo_fcc2, }, { - gen_op_eval_ba, + gen_op_eval_bn, gen_op_eval_fbne_fcc3, gen_op_eval_fblg_fcc3, gen_op_eval_fbul_fcc3, @@ -785,7 +785,7 @@ static GenOpFunc * const gen_fcond[4][16] = { gen_op_eval_fbug_fcc3, gen_op_eval_fbg_fcc3, gen_op_eval_fbu_fcc3, - gen_op_eval_bn, + gen_op_eval_ba, gen_op_eval_fbe_fcc3, gen_op_eval_fbue_fcc3, gen_op_eval_fbge_fcc3, -- cgit v1.2.3 From 6e65a42ad383480b9765d02816c8ab486867073b Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 22 Mar 2007 12:36:53 +0000 Subject: Win32 build fix. FIXME: This disables locking of the pidfile, a Win32 replacement of lockf should be used here. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2524 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vl.c b/vl.c index f368d9bba..87bb1bcd5 100644 --- a/vl.c +++ b/vl.c @@ -4405,8 +4405,11 @@ static int create_pidfile(const char *filename) if (fd == -1) return -1; + /* XXX: No locking for Win32 implemented */ +#ifndef _WIN32 if (lockf(fd, F_TLOCK, 0) == -1) return -1; +#endif len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); if (write(fd, buffer, len) != len) -- cgit v1.2.3 From a7222580366605ec15f3ffd83ddb0e62451b353b Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 22 Mar 2007 15:08:55 +0000 Subject: Fix fcntl64 logic bug, by Kirill A. Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2525 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5ff364d16..f79b5e0c7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3882,12 +3882,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, switch(arg2){ case TARGET_F_GETLK64: cmd = F_GETLK64; + break; case TARGET_F_SETLK64: cmd = F_SETLK64; + break; case TARGET_F_SETLKW64: cmd = F_SETLK64; + break; default: cmd = arg2; + break; } switch(arg2) { -- cgit v1.2.3 From e864cabdc0a38bb598ddcf88b264896dc6f3e3b2 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 22 Mar 2007 22:17:08 +0000 Subject: PowerPC bugfixes: - must clear carry bit when doing addic with a zero immediate value - fix missing RETURN in micro-operation that would lead to random failures and crashes - add USE_PRECISE_EMULATION compilation-time option to choose between getting exact floating point results and fast but less accurate computation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2526 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/exec.h | 4 +++ target-ppc/op.c | 20 ++++++++++++- target-ppc/op_helper.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++-- target-ppc/op_helper.h | 4 +++ target-ppc/translate.c | 5 +++- 5 files changed, 110 insertions(+), 4 deletions(-) diff --git a/target-ppc/exec.h b/target-ppc/exec.h index a10b62d25..87e8c1836 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -27,6 +27,10 @@ #include "cpu.h" #include "exec-all.h" +/* For normal operations, precise emulation should not be needed */ +//#define USE_PRECISE_EMULATION 1 +#define USE_PRECISE_EMULATION 0 + register struct CPUPPCState *env asm(AREG0); #if TARGET_LONG_BITS > HOST_LONG_BITS /* no registers can be used */ diff --git a/target-ppc/op.c b/target-ppc/op.c index f13f6f567..068ccb53b 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -261,10 +261,15 @@ PPC_OP(load_xer_cr) RETURN(); } -PPC_OP(clear_xer_cr) +PPC_OP(clear_xer_ov) { xer_so = 0; xer_ov = 0; + RETURN(); +} + +PPC_OP(clear_xer_ca) +{ xer_ca = 0; RETURN(); } @@ -714,6 +719,7 @@ void OPPROTO op_check_addo (void) xer_so = 1; xer_ov = 1; } + RETURN(); } #if defined(TARGET_PPC64) @@ -726,6 +732,7 @@ void OPPROTO op_check_addo_64 (void) xer_so = 1; xer_ov = 1; } + RETURN(); } #endif @@ -1643,16 +1650,24 @@ PPC_OP(fsel) /* fmadd - fmadd. */ PPC_OP(fmadd) { +#if USE_PRECISE_EMULATION + do_fmadd(); +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); FT0 = float64_add(FT0, FT2, &env->fp_status); +#endif RETURN(); } /* fmsub - fmsub. */ PPC_OP(fmsub) { +#if USE_PRECISE_EMULATION + do_fmsub(); +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); FT0 = float64_sub(FT0, FT2, &env->fp_status); +#endif RETURN(); } @@ -2378,6 +2393,7 @@ void OPPROTO op_store_booke_tsr (void) void OPPROTO op_splatw_T1_64 (void) { T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL); + RETURN(); } void OPPROTO op_splatwi_T0_64 (void) @@ -2385,6 +2401,7 @@ void OPPROTO op_splatwi_T0_64 (void) uint64_t tmp = PARAM1; T0_64 = (tmp << 32) | tmp; + RETURN(); } void OPPROTO op_splatwi_T1_64 (void) @@ -2392,6 +2409,7 @@ void OPPROTO op_splatwi_T1_64 (void) uint64_t tmp = PARAM1; T1_64 = (tmp << 32) | tmp; + RETURN(); } void OPPROTO op_extsh_T1_64 (void) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 756d164da..45e4dde9d 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -615,11 +615,13 @@ void do_fctiw (void) uint64_t i; } p; + p.i = float64_to_int32(FT0, &env->fp_status); +#if USE_PRECISE_EMULATION /* XXX: higher bits are not supposed to be significant. * to make tests easier, return the same as a real PowerPC 750 (aka G3) */ - p.i = float64_to_int32(FT0, &env->fp_status); p.i |= 0xFFF80000ULL << 32; +#endif FT0 = p.d; } @@ -630,26 +632,96 @@ void do_fctiwz (void) uint64_t i; } p; + p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); +#if USE_PRECISE_EMULATION /* XXX: higher bits are not supposed to be significant. * to make tests easier, return the same as a real PowerPC 750 (aka G3) */ - p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); p.i |= 0xFFF80000ULL << 32; +#endif FT0 = p.d; } +#if USE_PRECISE_EMULATION +void do_fmadd (void) +{ +#ifdef FLOAT128 + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); +#else + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) + FT2; +#endif +} + +void do_fmsub (void) +{ +#ifdef FLOAT128 + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); +#else + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) - FT2; +#endif +} +#endif /* USE_PRECISE_EMULATION */ + void do_fnmadd (void) { +#if USE_PRECISE_EMULATION +#ifdef FLOAT128 + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); +#else + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) + FT2; +#endif +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); FT0 = float64_add(FT0, FT2, &env->fp_status); +#endif if (likely(!isnan(FT0))) FT0 = float64_chs(FT0); } void do_fnmsub (void) { +#if USE_PRECISE_EMULATION +#ifdef FLOAT128 + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); +#else + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) - FT2; +#endif +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); FT0 = float64_sub(FT0, FT2, &env->fp_status); +#endif if (likely(!isnan(FT0))) FT0 = float64_chs(FT0); } @@ -667,7 +739,12 @@ void do_fres (void) } p; if (likely(isnormal(FT0))) { +#if USE_PRECISE_EMULATION + FT0 = float64_div(1.0, FT0, &env->fp_status); + FT0 = float64_to_float32(FT0, &env->fp_status); +#else FT0 = float32_div(1.0, FT0, &env->fp_status); +#endif } else { p.d = FT0; if (p.i == 0x8000000000000000ULL) { diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 3aa604583..fc3d8af60 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -93,6 +93,10 @@ void do_fsqrt (void); void do_fres (void); void do_frsqrte (void); void do_fsel (void); +#if USE_PRECISE_EMULATION +void do_fmadd (void); +void do_fmsub (void); +#endif void do_fnmadd (void); void do_fnmsub (void); void do_fctiw (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 90a9fc93c..fb9b07591 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -781,6 +781,8 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) else #endif gen_op_check_addc(); + } else { + gen_op_clear_xer_ca(); } gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -2804,7 +2806,8 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) { gen_op_load_xer_cr(); gen_op_store_T0_crf(crfD(ctx->opcode)); - gen_op_clear_xer_cr(); + gen_op_clear_xer_ov(); + gen_op_clear_xer_ca(); } /* mfcr */ -- cgit v1.2.3 From 51789c410beb34423b1188a6b6e069fe8b68aebe Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 22 Mar 2007 22:41:50 +0000 Subject: PowerPC improvments: - add missing 64 bits rotate instructions - safely define TARGET_PPCSPE when 64 bits registers are used a separate target will be needed to use it in 32 bits mode on 32 bits hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2527 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 9 ++++- target-ppc/op.c | 14 +++++++ target-ppc/translate.c | 106 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 104 insertions(+), 25 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e2294134d..55b98bf5b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -23,13 +23,18 @@ #include "config.h" #include +#if defined(TARGET_PPC64) || (HOST_LONG_BITS >= 64) +/* When using 64 bits temporary registers, + * we can use 64 bits GPR with no extra cost + */ +#define TARGET_PPCSPE +#endif + #if defined (TARGET_PPC64) typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 64 #define TARGET_GPR_BITS 64 #define REGX "%016" PRIx64 -/* We can safely use PowerPC SPE extension when compiling PowerPC 64 */ -#define TARGET_PPCSPE #elif defined(TARGET_PPCSPE) /* GPR are 64 bits: used by vector extension */ typedef uint64_t ppc_gpr_t; diff --git a/target-ppc/op.c b/target-ppc/op.c index 068ccb53b..1e0584209 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1444,6 +1444,20 @@ void OPPROTO op_rotli32_T0 (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_rotl64_T0_T1 (void) +{ + T0 = rotl64(T0, T1 & 0x3F); + RETURN(); +} + +void OPPROTO op_rotli64_T0 (void) +{ + T0 = rotl64(T0, PARAM1); + RETURN(); +} +#endif + /*** Integer shift ***/ /* shift left word */ void OPPROTO op_slw (void) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index fb9b07591..cd5cdf6fa 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1109,12 +1109,10 @@ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { target_ulong mask; uint32_t mb, me, sh; - int n; mb = MB(ctx->opcode); me = ME(ctx->opcode); sh = SH(ctx->opcode); - n = me + 1 - mb; if (likely(sh == 0)) { if (likely(mb == 0 && me == 31)) { gen_op_load_gpr_T0(rS(ctx->opcode)); @@ -1231,68 +1229,130 @@ GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B) \ { \ gen_##name(ctx, 1, 1); \ } + +static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me, + uint32_t sh) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + if (likely(sh == 0)) { + goto do_mask; + } + if (likely(mb == 0)) { + if (likely(me == 63)) { + gen_op_rotli32_T0(sh); + goto do_store; + } else if (likely(me == (63 - sh))) { + gen_op_sli_T0(sh); + goto do_store; + } + } else if (likely(me == 63)) { + if (likely(sh == (64 - mb))) { + gen_op_srli_T0(mb); + goto do_store; + } + } + gen_op_rotli64_T0(sh); + do_mask: + gen_op_andi_T0(MASK(mb, me)); + do_store: + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} /* rldicl - rldicl. */ static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn) { - int sh, mb; + uint32_t sh, mb; sh = SH(ctx->opcode) | (1 << shn); mb = (MB(ctx->opcode) << 1) | mbn; - /* XXX: TODO */ - RET_INVAL(ctx); + gen_rldinm(ctx, mb, 63, sh); } -GEN_PPC64_R4(rldicl, 0x1E, 0x00) +GEN_PPC64_R4(rldicl, 0x1E, 0x00); /* rldicr - rldicr. */ static inline void gen_rldicr (DisasContext *ctx, int men, int shn) { - int sh, me; + uint32_t sh, me; sh = SH(ctx->opcode) | (1 << shn); me = (MB(ctx->opcode) << 1) | men; - /* XXX: TODO */ - RET_INVAL(ctx); + gen_rldinm(ctx, 0, me, sh); } -GEN_PPC64_R4(rldicr, 0x1E, 0x02) +GEN_PPC64_R4(rldicr, 0x1E, 0x02); /* rldic - rldic. */ static inline void gen_rldic (DisasContext *ctx, int mbn, int shn) { - int sh, mb; + uint32_t sh, mb; sh = SH(ctx->opcode) | (1 << shn); mb = (MB(ctx->opcode) << 1) | mbn; - /* XXX: TODO */ - RET_INVAL(ctx); + gen_rldinm(ctx, mb, 63 - sh, sh); } -GEN_PPC64_R4(rldic, 0x1E, 0x04) +GEN_PPC64_R4(rldic, 0x1E, 0x04); + +static inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_rotl64_T0_T1(); + if (unlikely(mb != 0 || me != 63)) { + gen_op_andi_T0(MASK(mb, me)); + } + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + /* rldcl - rldcl. */ static inline void gen_rldcl (DisasContext *ctx, int mbn) { - int mb; + uint32_t mb; mb = (MB(ctx->opcode) << 1) | mbn; - /* XXX: TODO */ - RET_INVAL(ctx); + gen_rldnm(ctx, mb, 63); } GEN_PPC64_R2(rldcl, 0x1E, 0x08) /* rldcr - rldcr. */ static inline void gen_rldcr (DisasContext *ctx, int men) { - int me; + uint32_t me; me = (MB(ctx->opcode) << 1) | men; - /* XXX: TODO */ - RET_INVAL(ctx); + gen_rldnm(ctx, 0, me); } GEN_PPC64_R2(rldcr, 0x1E, 0x09) /* rldimi - rldimi. */ static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) { - int sh, mb; + uint64_t mask; + uint32_t sh, mb; sh = SH(ctx->opcode) | (1 << shn); mb = (MB(ctx->opcode) << 1) | mbn; - /* XXX: TODO */ - RET_INVAL(ctx); + if (likely(sh == 0)) { + if (likely(mb == 0)) { + gen_op_load_gpr_T0(rS(ctx->opcode)); + goto do_store; + } else if (likely(mb == 63)) { + gen_op_load_gpr_T0(rA(ctx->opcode)); + goto do_store; + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); + goto do_mask; + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); + gen_op_rotli64_T0(SH(ctx->opcode)); + do_mask: + mask = MASK(mb, 63 - sh); + gen_op_andi_T0(mask); + gen_op_andi_T1(~mask); + gen_op_or(); + do_store: + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } GEN_PPC64_R4(rldimi, 0x1E, 0x06) #endif -- cgit v1.2.3 From e397ee3382a34c65b0fb93514c3eef5c31715d3c Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 23 Mar 2007 00:43:28 +0000 Subject: Fix enough FPU/R2 support to get 24Kf going. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2528 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 2 ++ target-mips/exec.h | 1 + target-mips/op.c | 14 ++++++++++- target-mips/op_helper.c | 9 +++++-- target-mips/translate.c | 66 ++++++++++++++++++++++++++++++++----------------- 5 files changed, 66 insertions(+), 26 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 276910aae..f0f3ab2d7 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -203,6 +203,8 @@ struct CPUMIPSState { #define CP0C3_MT 2 #define CP0C3_SM 1 #define CP0C3_TL 0 + int32_t CP0_Config6; + int32_t CP0_Config7; target_ulong CP0_LLAddr; target_ulong CP0_WatchLo; int32_t CP0_WatchHi; diff --git a/target-mips/exec.h b/target-mips/exec.h index 877221e56..9816d4246 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -152,6 +152,7 @@ void invalidate_tlb (CPUState *env, int idx, int use_extra); void cpu_loop_exit(void); void do_raise_exception_err (uint32_t exception, int error_code); void do_raise_exception (uint32_t exception); +void do_raise_exception_direct_err (uint32_t exception, int error_code); void do_raise_exception_direct (uint32_t exception); void cpu_dump_state(CPUState *env, FILE *f, diff --git a/target-mips/op.c b/target-mips/op.c index a286cefe5..f97ec4292 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1180,6 +1180,18 @@ void op_mfc0_config3 (void) RETURN(); } +void op_mfc0_config6 (void) +{ + T0 = env->CP0_Config6; + RETURN(); +} + +void op_mfc0_config7 (void) +{ + T0 = env->CP0_Config7; + RETURN(); +} + void op_mfc0_lladdr (void) { T0 = (int32_t)env->CP0_LLAddr >> 4; @@ -1653,7 +1665,7 @@ void op_dmtc0_errorepc (void) void op_cp1_enabled(void) { if (!(env->CP0_Status & (1 << CP0St_CU1))) { - CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1); + CALL_FROM_TB2(do_raise_exception_direct_err, EXCP_CpU, 1); } RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index a262ea668..8ab7bf57d 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -56,10 +56,15 @@ void do_restore_state (void *pc_ptr) cpu_restore_state (tb, env, pc, NULL); } -void do_raise_exception_direct (uint32_t exception) +void do_raise_exception_direct_err (uint32_t exception, int error_code) { do_restore_state (GETPC ()); - do_raise_exception_err (exception, 0); + do_raise_exception_err (exception, error_code); +} + +void do_raise_exception_direct (uint32_t exception) +{ + do_raise_exception_direct_err (exception, 0); } #define MEMSUFFIX _raw diff --git a/target-mips/translate.c b/target-mips/translate.c index 89061db9a..5cc922b57 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -829,7 +829,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, break; default: MIPS_INVAL("float load/store"); - generate_exception_err(ctx, EXCP_CpU, 1); + generate_exception(ctx, EXCP_RI); return; } MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]); @@ -1932,22 +1932,31 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 16: switch (sel) { case 0: - gen_op_mfc0_config0(); + gen_op_mfc0_config0(); rn = "Config"; break; case 1: - gen_op_mfc0_config1(); + gen_op_mfc0_config1(); rn = "Config1"; break; case 2: - gen_op_mfc0_config2(); + gen_op_mfc0_config2(); rn = "Config2"; break; case 3: - gen_op_mfc0_config3(); + gen_op_mfc0_config3(); rn = "Config3"; break; - /* 6,7 are implementation dependent */ + /* 4,5 are reserved */ + /* 6,7 are implementation dependent */ + case 6: + gen_op_mfc0_config6(); + rn = "Config6"; + break; + case 7: + gen_op_mfc0_config7(); + rn = "Config7"; + break; default: goto die; } @@ -2516,28 +2525,37 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 16: switch (sel) { case 0: - gen_op_mtc0_config0(); + gen_op_mtc0_config0(); rn = "Config"; break; case 1: - /* ignored */ + /* ignored, read only */ rn = "Config1"; break; case 2: - gen_op_mtc0_config2(); + gen_op_mtc0_config2(); rn = "Config2"; break; case 3: - /* ignored */ + /* ignored, read only */ rn = "Config3"; break; - /* 6,7 are implementation dependent */ + /* 4,5 are reserved */ + /* 6,7 are implementation dependent */ + case 6: + /* ignored */ + rn = "Config6"; + break; + case 7: + /* ignored */ + rn = "Config7"; + break; default: rn = "Invalid config selector"; goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 17: switch (sel) { @@ -4140,7 +4158,7 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, break; default: MIPS_INVAL("cp1 branch/jump"); - generate_exception_err (ctx, EXCP_RI, 1); + generate_exception (ctx, EXCP_RI); return; } gen_op_set_bcond(); @@ -4173,7 +4191,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) case OPC_CFC1: if (fs != 0 && fs != 31) { MIPS_INVAL("cfc1 freg"); - generate_exception_err (ctx, EXCP_RI, 1); + generate_exception (ctx, EXCP_RI); return; } GEN_LOAD_IMM_TN(T1, fs); @@ -4184,7 +4202,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) case OPC_CTC1: if (fs != 0 && fs != 31) { MIPS_INVAL("ctc1 freg"); - generate_exception_err (ctx, EXCP_RI, 1); + generate_exception (ctx, EXCP_RI); return; } GEN_LOAD_IMM_TN(T1, fs); @@ -4201,7 +4219,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); } - generate_exception_err (ctx, EXCP_RI, 1); + generate_exception (ctx, EXCP_RI); return; } MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); @@ -4219,7 +4237,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) */ #define CHECK_FR(ctx, freg) do { \ if (!((ctx)->CP0_Status & (1<opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); } - generate_exception_err (ctx, EXCP_RI, 1); + generate_exception (ctx, EXCP_RI); return; } if (binary) @@ -4627,11 +4645,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_MOVCI: if (env->CP0_Config1 & (1 << CP0C1_FP)) { + save_cpu_state(ctx, 1); gen_op_cp1_enabled(); gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, (ctx->opcode >> 16) & 1); } else { - generate_exception(ctx, EXCP_RI); + generate_exception_err(ctx, EXCP_CpU, 1); } break; @@ -4905,7 +4924,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa); break; default: - generate_exception_err(ctx, EXCP_RI, 1); + generate_exception (ctx, EXCP_RI); break; } } else { @@ -4925,16 +4944,17 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_CP3: if (env->CP0_Config1 & (1 << CP0C1_FP)) { + save_cpu_state(ctx, 1); gen_op_cp1_enabled(); op1 = MASK_CP3(ctx->opcode); switch (op1) { /* Not implemented */ default: - generate_exception_err(ctx, EXCP_RI, 1); + generate_exception (ctx, EXCP_RI); break; } } else { - generate_exception(ctx, EXCP_RI); + generate_exception_err(ctx, EXCP_CpU, 1); } break; -- cgit v1.2.3 From 1b9eb036b9cd2d8b671f59030e8522c64ccea703 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 23 Mar 2007 09:40:22 +0000 Subject: Fix debug printf: we need different macros for target_ulong prints and GPR ones, as the lengths can be different. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2529 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 5 ++- target-ppc/helper.c | 99 ++++++++++++++++++++++++--------------------- target-ppc/translate.c | 12 +++--- target-ppc/translate_init.c | 4 +- 4 files changed, 65 insertions(+), 55 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 55b98bf5b..44dddc6c0 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -35,17 +35,20 @@ typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 64 #define TARGET_GPR_BITS 64 #define REGX "%016" PRIx64 +#define ADDRX "%016" PRIx64 #elif defined(TARGET_PPCSPE) /* GPR are 64 bits: used by vector extension */ typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 32 #define TARGET_GPR_BITS 64 -#define REGX "%08" PRIx32 +#define REGX "%016" PRIx64 +#define ADDRX "%08" PRIx32 #else typedef uint32_t ppc_gpr_t; #define TARGET_LONG_BITS 32 #define TARGET_GPR_BITS 32 #define REGX "%08" PRIx32 +#define ADDRX "%08" PRIx32 #endif #include "cpu-defs.h" diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 405c928e7..4daef379f 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -225,7 +225,7 @@ static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) { #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "TLB invalidate %d/%d %08x\n", + fprintf(logfile, "TLB invalidate %d/%d " ADDRX "\n", nr, env->nb_tlb, eaddr); } #endif @@ -255,9 +255,8 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, tlb = &env->tlb[nr]; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "Set TLB %d/%d EPN %08lx PTE0 %08lx PTE1 %08lx\n", - nr, env->nb_tlb, (unsigned long)EPN, - (unsigned long)pte0, (unsigned long)pte1); + fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX + " PTE1 " ADDRX "\n", nr, env->nb_tlb, EPN, pte0, pte1); } #endif /* Invalidate any pending reference in Qemu for this virtual address */ @@ -288,7 +287,8 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "TLB %d/%d %s [%08x %08x] <> %08x\n", + fprintf(logfile, "TLB %d/%d %s [" ADDRX " " ADDRX + "] <> " ADDRX "\n", nr, env->nb_tlb, pte_is_valid(tlb->pte0) ? "valid" : "inval", tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr); @@ -298,7 +298,8 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, } #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "TLB %d/%d %s %08x <> %08x %08x %c %c\n", + fprintf(logfile, "TLB %d/%d %s " ADDRX " <> " ADDRX " " ADDRX + " %c %c\n", nr, env->nb_tlb, pte_is_valid(tlb->pte0) ? "valid" : "inval", tlb->EPN, eaddr, tlb->pte1, @@ -355,7 +356,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, #if defined (DEBUG_BATS) if (loglevel > 0) { - fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__, + fprintf(logfile, "%s: %cBAT v 0x" ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif @@ -371,7 +372,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, } #if defined (DEBUG_BATS) if (loglevel > 0) { - fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__, + fprintf(logfile, "%s...: %cBAT v 0x" ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif @@ -384,7 +385,8 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, bl = (*BATu & 0x00001FFC) << 15; #if defined (DEBUG_BATS) if (loglevel > 0) { - fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", + fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX + " BATl 0x" ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); } @@ -404,7 +406,8 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, ctx->prot = PAGE_WRITE | PAGE_READ; #if defined (DEBUG_BATS) if (loglevel > 0) { - fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", + fprintf(logfile, "BAT %d match: r 0x" ADDRX + " prot=%c%c\n", i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', ctx->prot & PAGE_WRITE ? 'W' : '-'); } @@ -416,15 +419,16 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, } if (ret < 0) { #if defined (DEBUG_BATS) - printf("no BAT match for 0x%08x:\n", virtual); + printf("no BAT match for 0x" ADDRX ":\n", virtual); for (i = 0; i < 4; i++) { BATu = &BATut[i]; BATl = &BATlt[i]; BEPIu = *BATu & 0xF0000000; BEPIl = *BATu & 0x0FFE0000; bl = (*BATu & 0x00001FFC) << 15; - printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x \n\t" - "0x%08x 0x%08x 0x%08x\n", + printf("%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX + " BATl 0x" ADDRX " \n\t" + "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl); } @@ -448,8 +452,9 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw) pte1 = ldl_phys(base + (i * 8) + 4); #if defined (DEBUG_MMU) if (loglevel > 0) { - fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " - "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, + fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX + " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", + base + (i * 8), pte0, pte1, pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem); } #endif @@ -481,7 +486,8 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw) done: #if defined (DEBUG_MMU) if (loglevel > 0) { - fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", + fprintf(logfile, "found PTE at addr 0x" ADDRX " prot=0x%01x " + "ret=%d\n", ctx->raddr, ctx->prot, ret); } #endif @@ -512,8 +518,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, sr = env->sr[eaddr >> 28]; #if defined (DEBUG_MMU) if (loglevel > 0) { - fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x " - "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n", + fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX " nip=0x" + ADDRX " lr=0x" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, eaddr >> 28, sr, env->nip, env->lr, msr_ir, msr_dr, msr_pr, rw, type); } @@ -523,7 +529,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, if ((sr & 0x80000000) == 0) { #if defined (DEBUG_MMU) if (loglevel > 0) - fprintf(logfile, "pte segment: key=%d n=0x%08x\n", + fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n", ctx->key, sr & 0x10000000); #endif /* Check if instruction fetch is allowed, if needed */ @@ -550,9 +556,9 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } else { #if defined (DEBUG_MMU) if (loglevel > 0) { - fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x " - "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, - hash, ctx->pg_addr[0]); + fprintf(logfile, "0 sdr1=0x" ADDRX " vsid=0x%06x " + "api=0x%04x hash=0x%07x pg_addr=0x" ADDRX "\n", + sdr, vsid, pgidx, hash, ctx->pg_addr[0]); } #endif /* Primary table lookup */ @@ -562,9 +568,9 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, #if defined (DEBUG_MMU) if (eaddr != 0xEFFFFFFF && loglevel > 0) { fprintf(logfile, - "1 sdr1=0x%08x vsid=0x%06x api=0x%04x " - "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, - pgidx, hash, ctx->pg_addr[1]); + "1 sdr1=0x" ADDRX " vsid=0x%06x api=0x%04x " + "hash=0x%05x pg_addr=0x" ADDRX "\n", + sdr, vsid, pgidx, hash, ctx->pg_addr[1]); } #endif ret2 = find_pte(ctx, 1, rw); @@ -689,7 +695,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, } #if 0 if (loglevel > 0) { - fprintf(logfile, "%s address %08x => %08lx\n", + fprintf(logfile, "%s address " ADDRX " => " ADDRX "\n", __func__, eaddr, ctx->raddr); } #endif @@ -864,7 +870,7 @@ static inline void do_invalidate_BAT (CPUPPCState *env, end = base + mask + 0x00020000; #if defined (DEBUG_BATS) if (loglevel != 0) { - fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", + fprintf(logfile, "Flush BAT from " ADDRX " to " ADDRX " (" ADDRX ")\n", base, end, mask); } #endif @@ -882,9 +888,8 @@ static inline void dump_store_bat (CPUPPCState *env, char ID, int ul, int nr, { #if defined (DEBUG_BATS) if (loglevel != 0) { - fprintf(logfile, "Set %cBAT%d%c to 0x%08lx (0x%08lx)\n", - ID, nr, ul == 0 ? 'u' : 'l', (unsigned long)value, - (unsigned long)env->nip); + fprintf(logfile, "Set %cBAT%d%c to 0x" ADDRX " (0x" ADDRX ")\n", + ID, nr, ul == 0 ? 'u' : 'l', value, env->nip); } #endif } @@ -999,7 +1004,7 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value) { #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "%s: 0x%08lx\n", __func__, (unsigned long)value); + fprintf(logfile, "%s: 0x" ADDRX "\n", __func__, value); } #endif if (env->sdr1 != value) { @@ -1017,8 +1022,8 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) { #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "%s: reg=%d 0x%08lx %08lx\n", - __func__, srnum, (unsigned long)value, env->sr[srnum]); + fprintf(logfile, "%s: reg=%d 0x" ADDRX " " ADDRX "\n", + __func__, srnum, value, env->sr[srnum]); } #endif if (env->sr[srnum] != value) { @@ -1227,7 +1232,7 @@ void do_interrupt (CPUState *env) static void dump_syscall(CPUState *env) { fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX - " r5=0x" REGX " r6=0x" REGX " nip=0x" REGX "\n", + " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n", env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6], env->nip); } @@ -1245,15 +1250,16 @@ void do_interrupt (CPUState *env) #if defined (DEBUG_EXCEPTIONS) if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { if (loglevel != 0) { - fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n", - (unsigned long)env->nip, excp, env->error_code); + fprintf(logfile, + "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", + env->nip, excp, env->error_code); cpu_dump_state(env, logfile, fprintf, 0); } } #endif if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n", - (unsigned long)env->nip, excp, env->error_code); + fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", + env->nip, excp, env->error_code); } msr_pow = 0; /* Generate informations in save/restore registers */ @@ -1287,10 +1293,10 @@ void do_interrupt (CPUState *env) msr &= ~0xFFFF0000; #if defined (DEBUG_EXCEPTIONS) if (loglevel) { - fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", - env->spr[SPR_DSISR], env->spr[SPR_DAR]); + fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX + "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } else { - printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n", + printf("DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } #endif @@ -1301,8 +1307,8 @@ void do_interrupt (CPUState *env) msr |= env->error_code; #if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) { - fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", - msr, env->nip); + fprintf(logfile, "ISI exception: msr=0x" ADDRX ", nip=0x" ADDRX + "\n", msr, env->nip); } #endif goto store_next; @@ -1353,7 +1359,7 @@ void do_interrupt (CPUState *env) env->fpscr[7] |= 0x4; break; case EXCP_INVAL: - // printf("Invalid instruction at 0x%08x\n", env->nip); + // printf("Invalid instruction at 0x" ADDRX "\n", env->nip); msr |= 0x00080000; break; case EXCP_PRIV: @@ -1556,8 +1562,9 @@ void do_interrupt (CPUState *env) miss = &env->spr[SPR_DMISS]; cmp = &env->spr[SPR_DCMP]; } - fprintf(logfile, "6xx %sTLB miss: %cM %08x %cC %08x " - "H1 %08x H2 %08x %08x\n", es, en, *miss, en, *cmp, + fprintf(logfile, "6xx %sTLB miss: %cM " ADDRX " %cC " ADDRX + " H1 " ADDRX " H2 " ADDRX " " ADDRX "\n", + es, en, *miss, en, *cmp, env->spr[SPR_HASH1], env->spr[SPR_HASH2], env->error_code); } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index cd5cdf6fa..198fbf681 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5374,7 +5374,7 @@ void cpu_dump_state(CPUState *env, FILE *f, int i; - cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n", + cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX "\n", env->nip, env->lr, env->ctr); cpu_fprintf(f, "MSR " REGX FILL " XER %08x " #if !defined(NO_TIMER_DUMP) @@ -5545,7 +5545,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, #if defined PPC_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); - fprintf(logfile, "nip=%08x super=%d ir=%d\n", + fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n", ctx.nip, 1 - msr_pr, msr_ir); } #endif @@ -5578,12 +5578,12 @@ static inline int gen_intermediate_code_internal (CPUState *env, if (unlikely(handler->handler == &gen_invalid)) { if (loglevel > 0) { fprintf(logfile, "invalid/unsupported opcode: " - "%02x - %02x - %02x (%08x) 0x" REGX " %d\n", + "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); } else { printf("invalid/unsupported opcode: " - "%02x - %02x - %02x (%08x) 0x" REGX " %d\n", + "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); } @@ -5591,13 +5591,13 @@ static inline int gen_intermediate_code_internal (CPUState *env, if (unlikely((ctx.opcode & handler->inval) != 0)) { if (loglevel > 0) { fprintf(logfile, "invalid bits: %08x for opcode: " - "%02x -%02x - %02x (%08x) " REGX "\n", + "%02x -%02x - %02x (%08x) 0x" ADDRX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } else { printf("invalid bits: %08x for opcode: " - "%02x -%02x - %02x (%08x) " REGX "\n", + "%02x -%02x - %02x (%08x) 0x" ADDRX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 1778ef1a8..cba597672 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -378,7 +378,7 @@ static inline void spr_register (CPUPPCState *env, int num, exit(1); } #if defined(PPC_DEBUG_SPR) - printf("*** register spr %d (%03x) %s val " REGX "\n", num, num, name, + printf("*** register spr %d (%03x) %s val " ADDRX "\n", num, num, name, initial_value); #endif spr->name = name; @@ -2424,7 +2424,7 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) fill_new_table(env->opcodes, 0x40); #if defined(PPC_DUMP_CPU) - printf("* PowerPC instructions for PVR %08x: %s flags %016 " PRIx64 + printf("* PowerPC instructions for PVR %08x: %s flags %016" PRIx64 " %08x\n", def->pvr, def->name, def->insns_flags, def->flags); #endif -- cgit v1.2.3 From 426613dbf8cd1120f9e47fb636c4c03bc1ef586c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 23 Mar 2007 09:45:27 +0000 Subject: Add missing PowerPC 64 instructions PowerPC 64 fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2530 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 11 +++- target-ppc/helper.c | 5 +- target-ppc/op.c | 35 +++++++++++ target-ppc/op_helper.c | 64 +++++++++++++++++++- target-ppc/op_helper.h | 7 +++ target-ppc/op_mem.h | 54 +++++++++++++++++ target-ppc/translate.c | 142 +++++++++++++++++++++++++++++++++++++++++++- target-ppc/translate_init.c | 22 ++++--- 8 files changed, 326 insertions(+), 14 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 44dddc6c0..b70862ad8 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -384,6 +384,8 @@ enum { PPC_SPE = 0x0000000100000000ULL, /* PowerPC 2.03 SPE floating-point extension */ PPC_SPEFPU = 0x0000000200000000ULL, + /* SLB management */ + PPC_SLBI = 0x0000000400000000ULL, }; /* CPU run-time flags (MMU and exception model) */ @@ -503,11 +505,16 @@ enum { #define PPC_INSNS_74xx (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_ALTIVEC | \ PPC_MEM_TLBSYNC | PPC_TB) #define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx) +/* PowerPC 970 (aka G5) */ +#define PPC_INSNS_970 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_FLOAT_OPT | \ + PPC_ALTIVEC | PPC_MEM_TLBSYNC | PPC_TB | \ + PPC_64B | PPC_64_BRIDGE | PPC_SLBI) +#define PPC_FLAGS_970 (PPC_FLAGS_MMU_64B | PPC_FLAGS_EXCP_970) /* Default PowerPC will be 604/970 */ #define PPC_INSNS_PPC32 PPC_INSNS_604 #define PPC_FLAGS_PPC32 PPC_FLAGS_604 -#if 0 +#if 1 #define PPC_INSNS_PPC64 PPC_INSNS_970 #define PPC_FLAGS_PPC64 PPC_FLAGS_970 #endif @@ -801,7 +808,7 @@ uint32_t ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, uint32_t value); target_ulong do_load_msr (CPUPPCState *env); void do_store_msr (CPUPPCState *env, target_ulong value); -void ppc_store_msr32 (CPUPPCState *env, uint32_t value); +void ppc_store_msr_32 (CPUPPCState *env, uint32_t value); void do_compute_hflags (CPUPPCState *env); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4daef379f..b86f8234e 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1203,9 +1203,10 @@ void do_store_msr (CPUPPCState *env, target_ulong value) } #if defined(TARGET_PPC64) -void ppc_store_msr_32 (CPUPPCState *env, target_ulong value) +void ppc_store_msr_32 (CPUPPCState *env, uint32_t value) { - do_store_msr(env, (uint32_t)value); + do_store_msr(env, + (do_load_msr(env) & ~0xFFFFFFFFULL) | (value & 0xFFFFFFFF)); } #endif diff --git a/target-ppc/op.c b/target-ppc/op.c index 1e0584209..8bbbd62d4 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1721,6 +1721,29 @@ PPC_OP(fctiwz) RETURN(); } +#if defined(TARGET_PPC64) +/* fcfid - fcfid. */ +PPC_OP(fcfid) +{ + do_fcfid(); + RETURN(); +} + +/* fctid - fctid. */ +PPC_OP(fctid) +{ + do_fctid(); + RETURN(); +} + +/* fctidz - fctidz. */ +PPC_OP(fctidz) +{ + do_fctidz(); + RETURN(); +} +#endif + /*** Floating-Point compare ***/ /* fcmpu */ PPC_OP(fcmpu) @@ -1803,6 +1826,18 @@ void OPPROTO op_rfi_32 (void) do_rfi_32(); RETURN(); } + +void OPPROTO op_rfid (void) +{ + do_rfid(); + RETURN(); +} + +void OPPROTO op_rfid_32 (void) +{ + do_rfid_32(); + RETURN(); +} #endif #endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 45e4dde9d..55b5ca565 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -642,6 +642,42 @@ void do_fctiwz (void) FT0 = p.d; } +#if defined(TARGET_PPC64) +void do_fcfid (void) +{ + union { + double d; + uint64_t i; + } p; + + p.d = FT0; + FT0 = int64_to_float64(p.i, &env->fp_status); +} + +void do_fctid (void) +{ + union { + double d; + uint64_t i; + } p; + + p.i = float64_to_int64(FT0, &env->fp_status); + FT0 = p.d; +} + +void do_fctidz (void) +{ + union { + double d; + uint64_t i; + } p; + + p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status); + FT0 = p.d; +} + +#endif + #if USE_PRECISE_EMULATION void do_fmadd (void) { @@ -846,8 +882,12 @@ void do_fcmpo (void) void do_rfi (void) { env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (target_ulong)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); + T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); +#if defined(TARGET_PPC64) + ppc_store_msr_32(env, T0); +#else do_store_msr(env, T0); +#endif #if defined (DEBUG_OP) dump_rfi(); #endif @@ -859,6 +899,28 @@ void do_rfi_32 (void) { env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); + ppc_store_msr_32(env, T0); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request |= CPU_INTERRUPT_EXITTB; +} + +void do_rfid (void) +{ + env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003); + T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); + do_store_msr(env, T0); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request |= CPU_INTERRUPT_EXITTB; +} + +void do_rfid_32 (void) +{ + env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); + T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); do_store_msr(env, T0); #if defined (DEBUG_OP) dump_rfi(); diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index fc3d8af60..f819a0d36 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -101,6 +101,11 @@ void do_fnmadd (void); void do_fnmsub (void); void do_fctiw (void); void do_fctiwz (void); +#if defined(TARGET_PPC64) +void do_fcfid (void); +void do_fctid (void); +void do_fctidz (void); +#endif void do_fcmpu (void); void do_fcmpo (void); @@ -113,6 +118,8 @@ void do_td (int flags); void do_rfi (void); #if defined(TARGET_PPC64) void do_rfi_32 (void); +void do_rfid (void); +void do_rfid_32 (void); #endif void do_tlbia (void); void do_tlbie (void); diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index f080abc41..a78aa62c4 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -534,6 +534,17 @@ void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void) RETURN(); } +void OPPROTO glue(op_ldarx, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + T1 = glue(ldq, MEMSUFFIX)((uint32_t)T0); + regs->reserve = (uint32_t)T0; + } + RETURN(); +} + void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { @@ -569,6 +580,17 @@ void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void) RETURN(); } +void OPPROTO glue(op_ldarx_le, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + T1 = glue(ld64r, MEMSUFFIX)((uint32_t)T0); + regs->reserve = (uint32_t)T0; + } + RETURN(); +} + void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { @@ -615,6 +637,22 @@ void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void) RETURN(); } +void OPPROTO glue(op_stdcx, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + if (unlikely(regs->reserve != (uint32_t)T0)) { + env->crf[0] = xer_ov; + } else { + glue(stq, MEMSUFFIX)((uint32_t)T0, T1); + env->crf[0] = xer_ov | 0x02; + } + } + regs->reserve = -1; + RETURN(); +} + void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { @@ -665,6 +703,22 @@ void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void) RETURN(); } +void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void) +{ + if (unlikely(T0 & 0x03)) { + do_raise_exception(EXCP_ALIGN); + } else { + if (unlikely(regs->reserve != (uint32_t)T0)) { + env->crf[0] = xer_ov; + } else { + glue(st64r, MEMSUFFIX)((uint32_t)T0, T1); + env->crf[0] = xer_ov | 0x02; + } + } + regs->reserve = -1; + RETURN(); +} + void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 198fbf681..7d382d6ca 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1584,6 +1584,14 @@ GEN_FLOAT_B(ctiw, 0x0E, 0x00); GEN_FLOAT_B(ctiwz, 0x0F, 0x00); /* frsp */ GEN_FLOAT_B(rsp, 0x0C, 0x00); +#if defined(TARGET_PPC64) +/* fcfid */ +GEN_FLOAT_B(cfid, 0x0E, 0x1A); +/* fctid */ +GEN_FLOAT_B(ctid, 0x0E, 0x19); +/* fctidz */ +GEN_FLOAT_B(ctidz, 0x0F, 0x19); +#endif /*** Floating-Point compare ***/ /* fcmpo */ @@ -1996,8 +2004,8 @@ GEN_STS(h, 0x0C, PPC_INTEGER); GEN_STS(w, 0x04, PPC_INTEGER); #if defined(TARGET_PPC64) OP_ST_TABLE(d); -GEN_STUX(d, 0x15, 0x01, PPC_64B); -GEN_STX(d, 0x15, 0x00, PPC_64B); +GEN_STUX(d, 0x15, 0x05, PPC_64B); +GEN_STX(d, 0x15, 0x04, PPC_64B); GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B) { if (Rc(ctx->opcode)) { @@ -2358,6 +2366,62 @@ GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) op_stwcx(); } +#if defined(TARGET_PPC64) +#define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])() +#define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])() +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_ldarx[] = { + &gen_op_ldarx_raw, + &gen_op_ldarx_le_raw, + &gen_op_ldarx_64_raw, + &gen_op_ldarx_le_64_raw, +}; +static GenOpFunc *gen_op_stdcx[] = { + &gen_op_stdcx_raw, + &gen_op_stdcx_le_raw, + &gen_op_stdcx_64_raw, + &gen_op_stdcx_le_64_raw, +}; +#else +static GenOpFunc *gen_op_ldarx[] = { + &gen_op_ldarx_user, + &gen_op_ldarx_le_user, + &gen_op_ldarx_kernel, + &gen_op_ldarx_le_kernel, + &gen_op_ldarx_64_user, + &gen_op_ldarx_le_64_user, + &gen_op_ldarx_64_kernel, + &gen_op_ldarx_le_64_kernel, +}; +static GenOpFunc *gen_op_stdcx[] = { + &gen_op_stdcx_user, + &gen_op_stdcx_le_user, + &gen_op_stdcx_kernel, + &gen_op_stdcx_le_kernel, + &gen_op_stdcx_64_user, + &gen_op_stdcx_le_64_user, + &gen_op_stdcx_64_kernel, + &gen_op_stdcx_le_64_kernel, +}; +#endif + +/* ldarx */ +GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_RES) +{ + gen_addr_reg_index(ctx); + op_ldarx(); + gen_op_store_T1_gpr(rD(ctx->opcode)); +} + +/* stdcx. */ +GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_RES) +{ + gen_addr_reg_index(ctx); + gen_op_load_gpr_T1(rS(ctx->opcode)); + op_stdcx(); +} +#endif /* defined(TARGET_PPC64) */ + /* sync */ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC) { @@ -2807,6 +2871,26 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) #endif } +#if defined(TARGET_PPC64) +GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + /* Restore CPU state */ + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + if (!ctx->sf_mode) + gen_op_rfid_32(); + else + gen_op_rfid(); + RET_CHG_FLOW(ctx); +#endif +} +#endif + /* sc */ GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) { @@ -2978,6 +3062,25 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) } /* mtmsr */ +#if defined(TARGET_PPC64) +GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_MISC) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_update_nip(ctx, ctx->nip); + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_store_msr(); + /* Must stop the translation as machine state (may have) changed */ + RET_CHG_FLOW(ctx); +#endif +} +#endif + GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) { #if defined(CONFIG_USER_ONLY) @@ -3313,6 +3416,41 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC) #endif } +#if defined(TARGET_PPC64) +/* slbia */ +GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + if (loglevel) + fprintf(logfile, "%s: ! supervisor\n", __func__); + RET_PRIVOPC(ctx); + return; + } + gen_op_slbia(); + RET_STOP(ctx); +#endif +} + +/* slbie */ +GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_slbie(); + RET_STOP(ctx); +#endif +} +#endif + /*** External control ***/ /* Optional: */ #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])() diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index cba597672..a8ebc0cb4 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1716,7 +1716,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) printf("%s: PVR %08x mask %08x => %08x\n", __func__, def->pvr, def->pvr_mask, def->pvr & def->pvr_mask); switch (def->pvr & def->pvr_mask) { - /* Embedded PowerPC from IBM */ + /* Embedded PowerPC from IBM */ case CPU_PPC_401A1: /* 401 A1 family */ case CPU_PPC_401B2: /* 401 B2 family */ case CPU_PPC_401C2: /* 401 C2 family */ @@ -1833,7 +1833,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->id_tlbs = 0; break; - /* Embedded PowerPC from Freescale */ + /* Embedded PowerPC from Freescale */ #if defined (TODO) case CPU_PPC_5xx: break; @@ -1852,7 +1852,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) break; #endif - /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */ + /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */ case CPU_PPC_e500v110: case CPU_PPC_e500v120: case CPU_PPC_e500v210: @@ -1872,7 +1872,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) break; #endif - /* 32 bits PowerPC */ + /* 32 bits PowerPC */ case CPU_PPC_601: /* PowerPC 601 */ gen_spr_generic(env); gen_spr_ne_601(env); @@ -2131,7 +2131,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) break; #if defined (TODO) - /* G4 family */ + /* G4 family */ case CPU_PPC_7400: /* PowerPC 7400 */ case CPU_PPC_7410C: /* PowerPC 7410 */ case CPU_PPC_7410D: @@ -2154,8 +2154,9 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) break; #endif + /* 64 bits PowerPC */ +#if defined (TARGET_PPC64) #if defined (TODO) - /* 64 bits PowerPC */ case CPU_PPC_620: /* PowerPC 620 */ case CPU_PPC_630: /* PowerPC 630 (Power 3) */ case CPU_PPC_631: /* PowerPC 631 (Power 3+) */ @@ -2163,6 +2164,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) case CPU_PPC_POWER4P: /* Power 4+ */ case CPU_PPC_POWER5: /* Power 5 */ case CPU_PPC_POWER5P: /* Power 5+ */ +#endif case CPU_PPC_970: /* PowerPC 970 */ case CPU_PPC_970FX10: /* PowerPC 970 FX */ case CPU_PPC_970FX20: @@ -2171,16 +2173,20 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) case CPU_PPC_970FX31: case CPU_PPC_970MP10: /* PowerPC 970 MP */ case CPU_PPC_970MP11: +#if defined (TODO) case CPU_PPC_CELL10: /* Cell family */ case CPU_PPC_CELL20: case CPU_PPC_CELL30: case CPU_PPC_CELL31: +#endif +#if defined (TODO) case CPU_PPC_RS64: /* Apache (RS64/A35) */ case CPU_PPC_RS64II: /* NorthStar (RS64-II/A50) */ case CPU_PPC_RS64III: /* Pulsar (RS64-III) */ case CPU_PPC_RS64IV: /* IceStar/IStar/SStar (RS64-IV) */ - break; #endif + break; +#endif /* defined (TARGET_PPC64) */ #if defined (TODO) /* POWER */ @@ -3412,6 +3418,7 @@ static ppc_def_t ppc_defs[] = }, #endif /* 64 bits PowerPC */ +#if defined (TARGET_PPC64) #if defined (TODO) /* PowerPC 620 */ { @@ -3650,6 +3657,7 @@ static ppc_def_t ppc_defs[] = .msr_mask = xxx, }, #endif +#endif /* defined (TARGET_PPC64) */ #if defined (TODO) /* POWER2 */ { -- cgit v1.2.3 From e32f879d1b5cbde3c996d6db5e15e487ae3064a5 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 23 Mar 2007 20:01:20 +0000 Subject: Sparc tagged operations (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2531 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-tech.texi | 3 - target-sparc/cpu.h | 2 + target-sparc/op.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++ target-sparc/translate.c | 14 +++- 4 files changed, 194 insertions(+), 5 deletions(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index 77bda8637..ca913caf6 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -181,9 +181,6 @@ Current QEMU limitations: @itemize -@item Tagged add/subtract instructions are not supported, but they are -probably not used. - @item IPC syscalls are missing. @item 128-bit floating point operations are not supported, though none of the diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 5c4593ac6..60189a609 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -37,6 +37,7 @@ #define TT_WIN_UNF 0x06 #define TT_FP_EXCP 0x08 #define TT_DFAULT 0x09 +#define TT_TOVF 0x0a #define TT_EXTINT 0x10 #define TT_DIV_ZERO 0x2a #define TT_TRAP 0x80 @@ -47,6 +48,7 @@ #define TT_PRIV_INSN 0x11 #define TT_NFPU_INSN 0x20 #define TT_FP_EXCP 0x21 +#define TT_TOVF 0x23 #define TT_CLRWIN 0x24 #define TT_DIV_ZERO 0x28 #define TT_DFAULT 0x30 diff --git a/target-sparc/op.c b/target-sparc/op.c index 9e16a29a4..5c6e5391d 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -472,6 +472,96 @@ void OPPROTO op_addx_T1_T0_cc(void) FORCE_RET(); } +void OPPROTO op_tadd_T1_T0_cc(void) +{ + target_ulong src1; + + src1 = T0; + T0 += T1; + env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; + if ((src1 & 0x03) || (T1 & 0x03)) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (T0 < src1) + env->xcc |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) + env->xcc |= PSR_OVF; +#else + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (T0 < src1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + if ((src1 & 0x03) || (T1 & 0x03)) + env->psr |= PSR_OVF; +#endif + FORCE_RET(); +} + +void OPPROTO op_tadd_T1_T0_ccTV(void) +{ + target_ulong src1; + + if ((T0 & 0x03) || (T1 & 0x03)) + raise_exception(TT_TOVF); + + src1 = T0; + T0 += T1; + +#ifdef TARGET_SPARC64 + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + raise_exception(TT_TOVF); +#else + if ((src1 & 0x03) || (T1 & 0x03)) + raise_exception(TT_TOVF); +#endif + + env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (T0 < src1) + env->xcc |= PSR_CARRY; +#else + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (T0 < src1) + env->psr |= PSR_CARRY; +#endif + FORCE_RET(); +} + void OPPROTO op_sub_T1_T0(void) { T0 -= T1; @@ -582,6 +672,96 @@ void OPPROTO op_subx_T1_T0_cc(void) FORCE_RET(); } +void OPPROTO op_tsub_T1_T0_cc(void) +{ + target_ulong src1; + + src1 = T0; + T0 -= T1; + env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) + env->psr |= PSR_CARRY; + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; + if ((src1 & 0x03) || (T1 & 0x03)) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (src1 < T1) + env->xcc |= PSR_CARRY; + if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) + env->xcc |= PSR_OVF; +#else + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (src1 < T1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + if ((src1 & 0x03) || (T1 & 0x03)) + env->psr |= PSR_OVF; +#endif + FORCE_RET(); +} + +void OPPROTO op_tsub_T1_T0_ccTV(void) +{ + target_ulong src1; + + if ((T0 & 0x03) || (T1 & 0x03)) + raise_exception(TT_TOVF); + + src1 = T0; + T0 -= T1; + +#ifdef TARGET_SPARC64 + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + raise_exception(TT_TOVF); +#else + if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) + raise_exception(TT_TOVF); +#endif + + env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) + env->psr |= PSR_CARRY; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (src1 < T1) + env->xcc |= PSR_CARRY; +#else + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (src1 < T1) + env->psr |= PSR_CARRY; +#endif + FORCE_RET(); +} + void OPPROTO op_and_T1_T0(void) { T0 &= T1; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 74a0a2cb8..7486c277b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -27,7 +27,6 @@ Optimize synthetic instructions Optional alignment check 128-bit float - Tagged add/sub */ #include @@ -1833,10 +1832,21 @@ static void disas_sparc_insn(DisasContext * dc) } else { switch (xop) { case 0x20: /* taddcc */ + gen_op_tadd_T1_T0_cc(); + gen_movl_T0_reg(rd); + break; case 0x21: /* tsubcc */ + gen_op_tsub_T1_T0_cc(); + gen_movl_T0_reg(rd); + break; case 0x22: /* taddcctv */ + gen_op_tadd_T1_T0_ccTV(); + gen_movl_T0_reg(rd); + break; case 0x23: /* tsubcctv */ - goto illegal_insn; + gen_op_tsub_T1_T0_ccTV(); + gen_movl_T0_reg(rd); + break; case 0x24: /* mulscc */ gen_op_mulscc_T1_T0(); gen_movl_T0_reg(rd); -- cgit v1.2.3 From 3e736bf4b42fdb19920d348dcd8a1e7c0a0233ca Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 24 Mar 2007 13:24:09 +0000 Subject: Upgrade Sparc FPU version (based on patch by Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2532 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 4 ++-- target-sparc/translate.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 60189a609..3e8d71c20 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -238,8 +238,8 @@ typedef struct CPUSPARCState { (0 << 24) | (MAXTL << 8) | (NWINDOWS - 1)) #else #define GET_FSR32(env) (env->fsr) -#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ - env->fsr = _tmp & 0xcfc1ffff; \ +#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ + env->fsr = (_tmp & 0xcfc1ffff) | (env->fsr & 0x000e0000); \ } while (0) #endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 7486c277b..d1de266f6 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2754,6 +2754,7 @@ void cpu_reset(CPUSPARCState *env) env->version = GET_VER(env); env->pc = 0x1fff0000000ULL; #else + env->fsr = 4 << 17; /* FPU version 4 (Meiko) */ env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ env->pc = 0xffd00000; #endif -- cgit v1.2.3 From 34ee2edebb992b5d3f7c383a3d0c34f3e75880c8 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 24 Mar 2007 23:36:18 +0000 Subject: One more bit of mips CPU configuration, and support for early 4KEc which implemented only MIPS32R1. Thanks to Stefan Weil to insist he's right on that. :-) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2533 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index b87d8f3b5..6aacfb7e0 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -65,6 +65,8 @@ struct mips_def_t { int32_t CP0_Config1; int32_t CP0_Config2; int32_t CP0_Config3; + int32_t CP0_Config6; + int32_t CP0_Config7; int32_t CP1_fcr0; }; @@ -83,8 +85,26 @@ static mips_def_t mips_defs[] = .CP1_fcr0 = MIPS_FCR0, }, { - .name = "4KEc", + .name = "4KEcR1", .CP0_PRid = 0x00018400, + .CP0_Config0 = MIPS_CONFIG0, + .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP1_fcr0 = MIPS_FCR0, + }, + { + .name = "4KEc", + .CP0_PRid = 0x00019000, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), + .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP1_fcr0 = MIPS_FCR0, + }, + { + .name = "24Kc", + .CP0_PRid = 0x00019300, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), .CP0_Config1 = MIPS_CONFIG1, .CP0_Config2 = MIPS_CONFIG2, @@ -153,6 +173,8 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_Config1 = def->CP0_Config1; env->CP0_Config2 = def->CP0_Config2; env->CP0_Config3 = def->CP0_Config3; + env->CP0_Config6 = def->CP0_Config6; + env->CP0_Config7 = def->CP0_Config7; env->fcr0 = def->CP1_fcr0; return 0; } -- cgit v1.2.3 From 62724a3773b5553a696ebc5cdd212908f7572c6a Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 25 Mar 2007 07:55:52 +0000 Subject: Sparc32/64 CPU selection git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2534 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 9 +++++++ hw/sun4u.c | 10 +++++++ target-sparc/cpu.h | 14 +++++----- target-sparc/translate.c | 70 +++++++++++++++++++++++++++++++++++++++++++++--- vl.c | 2 ++ 5 files changed, 96 insertions(+), 9 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index c5f6ddda8..bc49c73c6 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -219,12 +219,21 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, unsigned int i; long vram_size = 0x100000, prom_offset, initrd_size, kernel_size; void *iommu, *dma, *main_esp, *main_lance = NULL; + const sparc_def_t *def; linux_boot = (kernel_filename != NULL); /* init CPUs */ + if (cpu_model == NULL) + cpu_model = "Fujitsu MB86904"; + sparc_find_by_name(cpu_model, &def); + if (def == NULL) { + fprintf(stderr, "Unable to find Sparc CPU definition\n"); + exit(1); + } for(i = 0; i < smp_cpus; i++) { env = cpu_init(); + cpu_sparc_register(env, def); envs[i] = env; if (i != 0) env->halted = 1; diff --git a/hw/sun4u.c b/hw/sun4u.c index 2357dc974..906695690 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -266,10 +266,20 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, unsigned int i; long prom_offset, initrd_size, kernel_size; PCIBus *pci_bus; + const sparc_def_t *def; linux_boot = (kernel_filename != NULL); + /* init CPUs */ + if (cpu_model == NULL) + cpu_model = "TI UltraSparc II"; + sparc_find_by_name(cpu_model, &def); + if (def == NULL) { + fprintf(stderr, "Unable to find Sparc CPU definition\n"); + exit(1); + } env = cpu_init(); + cpu_sparc_register(env, def); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 3e8d71c20..499d5cd96 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -152,6 +152,8 @@ /* 2 <= NWINDOWS <= 32. In QEMU it must also be a power of two. */ #define NWINDOWS 8 +typedef struct sparc_def_t sparc_def_t; + typedef struct CPUSPARCState { target_ulong gregs[8]; /* general registers */ target_ulong *regwptr; /* pointer to current register window */ @@ -170,6 +172,7 @@ typedef struct CPUSPARCState { int psret; /* enable traps */ uint32_t psrpil; /* interrupt level */ int psref; /* enable fpu */ + target_ulong version; jmp_buf jmp_env; int user_mode_only; int exception_index; @@ -215,7 +218,6 @@ typedef struct CPUSPARCState { uint64_t bgregs[8]; /* backup for normal global registers */ uint64_t igregs[8]; /* interrupt general registers */ uint64_t mgregs[8]; /* mmu general registers */ - uint64_t version; uint64_t fprs; uint64_t tick_cmpr, stick_cmpr; uint64_t gsr; @@ -233,9 +235,6 @@ typedef struct CPUSPARCState { #define PUT_FSR64(env, val) do { uint64_t _tmp = val; \ env->fsr = _tmp & 0x3fcfc1c3ffULL; \ } while (0) -// Manuf 0x17, version 0x11, mask 0 (UltraSparc-II) -#define GET_VER(env) ((0x17ULL << 48) | (0x11ULL << 32) | \ - (0 << 24) | (MAXTL << 8) | (NWINDOWS - 1)) #else #define GET_FSR32(env) (env->fsr) #define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ @@ -246,9 +245,12 @@ typedef struct CPUSPARCState { CPUSPARCState *cpu_sparc_init(void); int cpu_sparc_exec(CPUSPARCState *s); int cpu_sparc_close(CPUSPARCState *s); +int sparc_find_by_name (const unsigned char *name, const sparc_def_t **def); +void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, + ...)); +int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def); -/* Fake impl 0, version 4 */ -#define GET_PSR(env) ((0 << 28) | (4 << 24) | (env->psr & PSR_ICC) | \ +#define GET_PSR(env) (env->version | (env->psr & PSR_ICC) | \ (env->psref? PSR_EF : 0) | \ (env->psrpil << 8) | \ (env->psrs? PSR_S : 0) | \ diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d1de266f6..03466ce87 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -55,6 +55,13 @@ typedef struct DisasContext { struct TranslationBlock *tb; } DisasContext; +struct sparc_def_t { + const unsigned char *name; + target_ulong iu_version; + uint32_t fpu_version; + uint32_t mmu_version; +}; + static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; extern FILE *logfile; @@ -2751,11 +2758,8 @@ void cpu_reset(CPUSPARCState *env) env->gregs[1] = ram_size; #ifdef TARGET_SPARC64 env->pstate = PS_PRIV; - env->version = GET_VER(env); env->pc = 0x1fff0000000ULL; #else - env->fsr = 4 << 17; /* FPU version 4 (Meiko) */ - env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ env->pc = 0xffd00000; #endif env->npc = env->pc + 4; @@ -2774,6 +2778,66 @@ CPUSPARCState *cpu_sparc_init(void) return (env); } +static const sparc_def_t sparc_defs[] = { +#ifdef TARGET_SPARC64 + { + .name = "TI UltraSparc II", + .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0 << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, +#else + { + .name = "Fujitsu MB86904", + .iu_version = 0x04 << 24, /* Impl 0, ver 4 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */ + }, +#endif +}; + +int sparc_find_by_name(const unsigned char *name, const sparc_def_t **def) +{ + int ret; + unsigned int i; + + ret = -1; + *def = NULL; + for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { + if (strcasecmp(name, sparc_defs[i].name) == 0) { + *def = &sparc_defs[i]; + ret = 0; + break; + } + } + + return ret; +} + +void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + unsigned int i; + + for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { + (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x\n", + sparc_defs[i].name, + sparc_defs[i].iu_version, + sparc_defs[i].fpu_version, + sparc_defs[i].mmu_version); + } +} + +int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def) +{ + env->version = def->iu_version; + env->fsr = def->fpu_version; +#if !defined(TARGET_SPARC64) + env->mmuregs[0] = def->mmu_version; +#endif + return 0; +} + #define GET_FLAG(a,b) ((env->psr & a)?b:'-') void cpu_dump_state(CPUState *env, FILE *f, diff --git a/vl.c b/vl.c index 87bb1bcd5..6c5dbc801 100644 --- a/vl.c +++ b/vl.c @@ -7007,6 +7007,8 @@ int main(int argc, char **argv) arm_cpu_list(); #elif defined(TARGET_MIPS) mips_cpu_list(stdout, &fprintf); +#elif defined(TARGET_SPARC) + sparc_cpu_list(stdout, &fprintf); #endif exit(1); } else { -- cgit v1.2.3 From f5b122688b8d7912e7094be60cca4d3a2ee5a3e7 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 25 Mar 2007 15:58:03 +0000 Subject: Windows sockets like to be different. Inspired by a patch from Alex Consul. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2535 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vl.c b/vl.c index 6c5dbc801..b2b49e73f 100644 --- a/vl.c +++ b/vl.c @@ -2850,6 +2850,10 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, if (err == EINTR || err == EWOULDBLOCK) { } else if (err == EINPROGRESS) { break; +#ifdef _WIN32 + } else if (err == WSAEALREADY) { + break; +#endif } else { goto fail; } @@ -4017,6 +4021,10 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str) if (err == EINTR || err == EWOULDBLOCK) { } else if (err == EINPROGRESS) { break; +#ifdef _WIN32 + } else if (err == WSAEALREADY) { + break; +#endif } else { perror("connect"); closesocket(fd); -- cgit v1.2.3 From 99c19686938a8c8df0256c62d26463ca881206aa Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 25 Mar 2007 16:14:07 +0000 Subject: Improved kqemu error message, by Robert Millan. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2536 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kqemu.c b/kqemu.c index 96ca5826c..baf3ebae7 100644 --- a/kqemu.c +++ b/kqemu.c @@ -177,7 +177,8 @@ int kqemu_init(CPUState *env) kqemu_fd = open(KQEMU_DEVICE, O_RDWR); #endif if (kqemu_fd == KQEMU_INVALID_FD) { - fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE); + fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated: %s\n", + KQEMU_DEVICE, strerror(errno)); return -1; } version = 0; -- cgit v1.2.3 From ed5065e16a4717414c9ca1f2286903de0e663b2c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 25 Mar 2007 16:15:21 +0000 Subject: Typo in configure, by Nicholas Sauzede. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2537 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 354f11097..92b1fdc23 100755 --- a/configure +++ b/configure @@ -295,7 +295,7 @@ 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-dsound enable DirectSound audio driver" echo " --enable-system enable all system emulation targets" echo " --disable-system disable all system emulation targets" echo " --enable-linux-user enable all linux usermode emulation targets" -- cgit v1.2.3 From a39437aa1dd5331c802294b9455503f9c8585180 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 25 Mar 2007 20:27:04 +0000 Subject: Fix segfault with -nographic, by Enache Adrian. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2538 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.c b/vl.c index b2b49e73f..eb5d70750 100644 --- a/vl.c +++ b/vl.c @@ -7079,6 +7079,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_nographic: pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "null"); pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); nographic = 1; break; -- cgit v1.2.3 From 209afb9e0dc4f4ed21ed696047d4c72f8a942810 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 25 Mar 2007 20:55:00 +0000 Subject: Move determination of AIOLIBS until after all configure options have been handled. By Carlos O'Donell. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2539 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 92b1fdc23..63f327e91 100755 --- a/configure +++ b/configure @@ -159,12 +159,6 @@ if [ "$bsd" = "yes" ] ; then fi fi -if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then - AIOLIBS= -else - AIOLIBS="-lrt" -fi - # find source path source_path=`dirname "$0"` if [ -z "$source_path" ]; then @@ -260,6 +254,12 @@ for opt do esac done +if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then + AIOLIBS= +else + AIOLIBS="-lrt" +fi + # default flags for all hosts CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing" LDFLAGS="$LDFLAGS -g" -- cgit v1.2.3 From aa26bb2dacdc32bac84e7c72c501b4691721679e Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 25 Mar 2007 21:33:06 +0000 Subject: qemu_create_pidfile implementation for Win32, based on a patch by Carlos O'Donell. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2540 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ osdep.h | 2 ++ vl.c | 25 +------------------------ 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/osdep.c b/osdep.c index d1eff8deb..ccc1d70bb 100644 --- a/osdep.c +++ b/osdep.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef HOST_SOLARIS #include #include @@ -216,3 +217,50 @@ char *qemu_strdup(const char *str) strcpy(ptr, str); return ptr; } + +int qemu_create_pidfile(const char *filename) +{ + char buffer[128]; + int len; +#ifndef _WIN32 + int fd; + + fd = open(filename, O_RDWR | O_CREAT, 0600); + if (fd == -1) + return -1; + + if (lockf(fd, F_TLOCK, 0) == -1) + return -1; + + len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); + if (write(fd, buffer, len) != len) + return -1; +#else + HANDLE file; + DWORD flags; + OVERLAPPED overlap; + BOOL ret; + + /* Open for writing with no sharing. */ + file = CreateFile(filename, GENERIC_WRITE, 0, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (file == INVALID_HANDLE_VALUE) + return -1; + + flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY; + overlap.hEvent = 0; + /* Lock 1 byte. */ + ret = LockFileEx(file, flags, 0, 0, 1, &overlap); + if (ret == 0) + return -1; + + /* Write PID to file. */ + len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); + ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len, + &overlap, NULL); + if (ret == 0) + return -1; +#endif + return 0; +} diff --git a/osdep.h b/osdep.h index 325baf14e..68d29d74e 100644 --- a/osdep.h +++ b/osdep.h @@ -15,4 +15,6 @@ void qemu_vfree(void *ptr); void *get_mmap_addr(unsigned long size); +int qemu_create_pidfile(const char *filename); + #endif diff --git a/vl.c b/vl.c index eb5d70750..af8558b79 100644 --- a/vl.c +++ b/vl.c @@ -4403,29 +4403,6 @@ void usb_info(void) } } -static int create_pidfile(const char *filename) -{ - int fd; - char buffer[128]; - int len; - - fd = open(filename, O_RDWR | O_CREAT, 0600); - if (fd == -1) - return -1; - - /* XXX: No locking for Win32 implemented */ -#ifndef _WIN32 - if (lockf(fd, F_TLOCK, 0) == -1) - return -1; -#endif - - len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); - if (write(fd, buffer, len) != len) - return -1; - - return 0; -} - /***********************************************************/ /* dumb display */ @@ -7405,7 +7382,7 @@ int main(int argc, char **argv) } #endif - if (pid_file && create_pidfile(pid_file) != 0) { + if (pid_file && qemu_create_pidfile(pid_file) != 0) { if (daemonize) { uint8_t status = 1; write(fds[1], &status, 1); -- cgit v1.2.3 From de270b3c7c0c9b15e6c2f3d5e7f5c96673711dad Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 28 Mar 2007 20:43:46 +0000 Subject: Solaris host compilation fix by Shaddy Baddah. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2541 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b70862ad8..b21d6b19f 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -21,7 +21,7 @@ #define __CPU_PPC_H__ #include "config.h" -#include +#include #if defined(TARGET_PPC64) || (HOST_LONG_BITS >= 64) /* When using 64 bits temporary registers, -- cgit v1.2.3 From 471035729088e3aa7f69140ac0ad0b248ff7ec07 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 30 Mar 2007 09:38:04 +0000 Subject: New model for PowerPC CPU hardware interrupt events: move all PowerPC specific code into target-ppc/helper.c to avoid polluting the common code in cpu-exec.c. This makes implementation of new features (ie embedded PowerPC timers, critical interrupts, ...) easier. This also avoid hardcoding the IRQ callback in the OpenPIC controller, making it more easily reusable and allowing cascading. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2542 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 26 ++++------------- hw/openpic.c | 15 +++++----- hw/ppc.c | 54 +++++++++++++++++++++++++++++++++- hw/ppc_chrp.c | 12 ++++---- hw/ppc_prep.c | 18 ++++++------ target-ppc/cpu.h | 16 +++++++++++ target-ppc/helper.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 15 ++++++++-- 8 files changed, 193 insertions(+), 46 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 634f1ba87..d124c4059 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -256,8 +256,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_PPC) if (env1->halted) { if (env1->msr[MSR_EE] && - (env1->interrupt_request & - (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) { + (env1->interrupt_request & CPU_INTERRUPT_HARD)) { env1->halted = 0; } else { return EXCP_HALTED; @@ -448,24 +447,11 @@ int cpu_exec(CPUState *env1) 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 (interrupt_request & CPU_INTERRUPT_HARD) { + if (ppc_hw_interrupt(env) == 1) { + /* Some exception was raised */ + if (env->pending_interrupts == 0) + env->interrupt_request &= ~CPU_INTERRUPT_HARD; #if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else diff --git a/hw/openpic.c b/hw/openpic.c index 31773373a..7565b1def 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -164,6 +164,7 @@ typedef struct IRQ_dst_t { struct openpic_t { PCIDevice pci_dev; + SetIRQFunc *set_irq; int mem_index; /* Global registers */ uint32_t frep; /* Feature reporting register */ @@ -264,8 +265,8 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) IRQ_setbit(&dst->raised, n_IRQ); if (priority > dst->raised.priority) { IRQ_get_next(opp, &dst->raised); - DPRINTF("Raise CPU IRQ\n"); - cpu_interrupt(dst->env, CPU_INTERRUPT_HARD); + DPRINTF("Raise CPU IRQ fn %p env %p\n", opp->set_irq, dst->env); + opp->set_irq(dst->env, OPENPIC_EVT_INT, 1); } } @@ -532,7 +533,7 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) /* XXX: Should be able to reset any CPU */ if (val & 1) { DPRINTF("Reset CPU IRQ\n"); - // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET); + // opp->set_irq(dst->env, OPENPIC_EVT_RESET, 1); } break; #if MAX_IPI > 0 @@ -781,7 +782,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) src = &opp->src[n_IRQ]; if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { DPRINTF("Raise CPU IRQ\n"); - cpu_interrupt(dst->env, CPU_INTERRUPT_HARD); + opp->set_irq(dst->env, OPENPIC_EVT_INT, 1); } } break; @@ -963,8 +964,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, #endif } -openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, - CPUPPCState **envp) +openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, + int *pmem_index, int nb_cpus, CPUPPCState **envp) { openpic_t *opp; uint8_t *pci_conf; @@ -994,7 +995,7 @@ openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, } else { opp = qemu_mallocz(sizeof(openpic_t)); } - + opp->set_irq = set_irq; opp->mem_index = cpu_register_io_memory(0, openpic_read, openpic_write, opp); diff --git a/hw/ppc.c b/hw/ppc.c index c910cb9f7..04242ac90 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -24,6 +24,57 @@ #include "vl.h" #include "m48t59.h" +extern FILE *logfile; +extern int loglevel; + +/*****************************************************************************/ +/* PowerPC internal fake IRQ controller + * used to manage multiple sources hardware events + */ +/* XXX: should be protected */ +void ppc_set_irq (void *opaque, int n_IRQ, int level) +{ + CPUState *env; + + env = opaque; + if (level) { + env->pending_interrupts |= 1 << n_IRQ; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + env->pending_interrupts &= ~(1 << n_IRQ); + if (env->pending_interrupts == 0) + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +#if 0 + printf("%s: %p n_IRQ %d level %d => pending %08x req %08x\n", __func__, + env, n_IRQ, level, env->pending_interrupts, env->interrupt_request); +#endif +} + +/* External IRQ callback from OpenPIC IRQ controller */ +void ppc_openpic_irq (void *opaque, int n_IRQ, int level) +{ + switch (n_IRQ) { + case OPENPIC_EVT_INT: + n_IRQ = PPC_INTERRUPT_EXT; + break; + case OPENPIC_EVT_CINT: + /* On PowerPC BookE, critical input use vector 0 */ + n_IRQ = PPC_INTERRUPT_RESET; + break; + case OPENPIC_EVT_MCK: + n_IRQ = PPC_INTERRUPT_MCK; + break; + case OPENPIC_EVT_DEBUG: + n_IRQ = PPC_INTERRUPT_DEBUG; + break; + case OPENPIC_EVT_RESET: + qemu_system_reset_request(); + return; + } + ppc_set_irq(opaque, n_IRQ, level); +} + /*****************************************************************************/ /* PPC time base and decrementer emulation */ //#define DEBUG_TB @@ -35,6 +86,7 @@ struct ppc_tb_t { /* Decrementer management */ uint64_t decr_next; /* Tick for next decr interrupt */ struct QEMUTimer *decr_timer; + void *opaque; }; static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env) @@ -131,7 +183,7 @@ static inline void cpu_ppc_decr_excp (CPUState *env) #ifdef DEBUG_TB printf("raise decrementer exception\n"); #endif - cpu_interrupt(env, CPU_INTERRUPT_TIMER); + ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); } static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index b1199e2cf..e9d6670e4 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -1,7 +1,7 @@ /* * QEMU PPC CHRP/PMAC hardware System Emulator * - * Copyright (c) 2004 Fabrice Bellard + * Copyright (c) 2004-2007 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 @@ -449,21 +449,21 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, } macio_init(pci_bus, 0x0017); - + nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59); - + arch_name = "HEATHROW"; } else { isa_mem_base = 0x80000000; - + /* Register 8 MB of ISA IO space */ isa_mmio_init(0xf2000000, 0x00800000); - + /* UniN init */ unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); - pic = openpic_init(NULL, &openpic_mem_index, 1, &env); + pic = openpic_init(NULL, &ppc_openpic_irq, &openpic_mem_index, 1, &env); set_irq = openpic_set_irq; pci_bus = pci_pmac_init(pic); /* init basic PC hardware */ diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 32a3e5230..d504b1c6d 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -1,7 +1,7 @@ /* * QEMU PPC PREP hardware System Emulator * - * Copyright (c) 2003-2004 Jocelyn Mayer + * Copyright (c) 2003-2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -84,29 +84,27 @@ static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) #endif } -static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) +static uint32_t speaker_ioport_read (void *opaque, uint32_t addr) { #if 0 int out; out = pit_get_out(pit, 2, qemu_get_clock(vm_clock)); dummy_refresh_clock ^= 1; return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | - (dummy_refresh_clock << 4); + (dummy_refresh_clock << 4); #endif return 0; } -static void pic_irq_request(void *opaque, int level) +static void pic_irq_request (void *opaque, int level) { - if (level) - cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); + ppc_set_irq(opaque, PPC_INTERRUPT_EXT, level); } /* PCI intack register */ /* Read-only register (?) */ -static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value) +static void _PPC_intack_write (void *opaque, + target_phys_addr_t addr, uint32_t value) { // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); } @@ -294,7 +292,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) /* Special port 92 */ /* Check soft reset asked */ if (val & 0x01) { - // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET); + // cpu_interrupt(first_cpu, PPC_INTERRUPT_RESET); } /* Check LE mode */ if (val & 0x02) { diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b21d6b19f..ef02f1096 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -740,6 +740,7 @@ struct CPUPPCState { int exception_index; int error_code; int interrupt_request; + uint32_t pending_interrupts; /* Those resources are used only during code translation */ /* Next instruction pointer */ @@ -1267,6 +1268,21 @@ enum { EXCP_TRAP = 0x40, }; +/* Hardware interruption sources: + * all those exception can be raised simulteaneously + */ +enum { + PPC_INTERRUPT_RESET = 0, /* Reset / critical input */ + PPC_INTERRUPT_MCK = 1, /* Machine check exception */ + PPC_INTERRUPT_EXT = 2, /* External interrupt */ + PPC_INTERRUPT_DECR = 3, /* Decrementer exception */ + PPC_INTERRUPT_HDECR = 4, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT = 5, /* Programmable inteval timer interrupt */ + PPC_INTERRUPT_FIT = 6, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT = 7, /* Watchdog timer interrupt */ + PPC_INTERRUPT_DEBUG = 8, /* External debug exception */ +}; + /*****************************************************************************/ #endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b86f8234e..4356edc36 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1229,6 +1229,13 @@ void do_interrupt (CPUState *env) { env->exception_index = -1; } + +int ppc_hw_interrupt (CPUState *env) +{ + env->exception_index = -1; + + return 0; +} #else /* defined (CONFIG_USER_ONLY) */ static void dump_syscall(CPUState *env) { @@ -1753,4 +1760,80 @@ void do_interrupt (CPUState *env) env->nip = excp; env->exception_index = EXCP_NONE; } + +int ppc_hw_interrupt (CPUState *env) +{ + int raised = 0; + +#if 0 + printf("%s: %p pending %08x req %08x %08x me %d ee %d\n", + __func__, env, env->pending_interrupts, + env->interrupt_request, interrupt_request, + msr_me, msr_ee); +#endif + /* Raise it */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { + /* External reset / critical input */ + env->exception_index = EXCP_RESET; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); + raised = 1; + } + if (raised == 0 && msr_me != 0) { + /* Machine check exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { + env->exception_index = EXCP_MACHINE_CHECK; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); + raised = 1; + } + } + if (raised == 0 && msr_ee != 0) { +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + /* Hypervisor decrementer exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { + env->exception_index = EXCP_HDECR; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); + raised = 1; + } else +#endif + /* Decrementer exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { + env->exception_index = EXCP_DECR; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); + raised = 1; + /* Programmable interval timer on embedded PowerPC */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { + env->exception_index = EXCP_40x_PIT; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); + raised = 1; + /* Fixed interval timer on embedded PowerPC */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { + env->exception_index = EXCP_40x_FIT; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); + raised = 1; + /* Watchdog timer on embedded PowerPC */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { + env->exception_index = EXCP_40x_WATCHDOG; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); + raised = 1; + /* External interrupt */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { + env->exception_index = EXCP_EXTERNAL; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); + raised = 1; + } +#if 0 // TODO + /* External debug exception */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { + env->exception_index = EXCP_xxx; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); + raised = 1; +#endif + } + if (raised != 0) { + env->error_code = 0; + do_interrupt(env); + } + + return raised; +} #endif /* !CONFIG_USER_ONLY */ diff --git a/vl.h b/vl.h index 61b5b80f7..2bcf81ada 100644 --- a/vl.h +++ b/vl.h @@ -852,9 +852,16 @@ int piix4_init(PCIBus *bus, int devfn); /* openpic.c */ typedef struct openpic_t openpic_t; +enum { + OPENPIC_EVT_INT = 0, /* IRQ */ + OPENPIC_EVT_CINT, /* critical IRQ */ + OPENPIC_EVT_MCK, /* Machine check event */ + OPENPIC_EVT_DEBUG, /* Inconditional debug event */ + OPENPIC_EVT_RESET, /* Core reset event */ +}; void openpic_set_irq(void *opaque, int n_IRQ, int level); -openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, - CPUState **envp); +openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, + int *pmem_index, int nb_cpus, CPUPPCState **envp); /* heathrow_pic.c */ typedef struct HeathrowPICS HeathrowPICS; @@ -1115,6 +1122,10 @@ extern void cpu_mips_irqctrl_init (void); extern QEMUMachine shix_machine; #ifdef TARGET_PPC +/* PowerPC hardware exceptions management helpers */ +void ppc_set_irq (void *opaque, int n_IRQ, int level); +void ppc_openpic_irq (void *opaque, int n_IRQ, int level); +int ppc_hw_interrupt (CPUState *env); ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); #endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); -- cgit v1.2.3 From 363be49c86af1ebe423df4087c7b021459ecd8cc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 30 Mar 2007 10:07:33 +0000 Subject: Fix / update PowerPC BookE definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2543 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 81 ++++++++++++++---------- target-ppc/translate_init.c | 151 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 189 insertions(+), 43 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index ef02f1096..8d2c3a956 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -514,10 +514,8 @@ enum { /* Default PowerPC will be 604/970 */ #define PPC_INSNS_PPC32 PPC_INSNS_604 #define PPC_FLAGS_PPC32 PPC_FLAGS_604 -#if 1 #define PPC_INSNS_PPC64 PPC_INSNS_970 #define PPC_FLAGS_PPC64 PPC_FLAGS_970 -#endif #define PPC_INSNS_DEFAULT PPC_INSNS_604 #define PPC_FLAGS_DEFAULT PPC_FLAGS_604 typedef struct ppc_def_t ppc_def_t; @@ -562,9 +560,11 @@ struct ppc_tlb_t { #define MSR_SF 63 /* Sixty-four-bit mode hflags */ #define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */ #define MSR_HV 60 /* hypervisor state hflags */ -#define MSR_UCLE 26 /* User-mode cache lock enable on e500 */ +#define MSR_CM 31 /* Computation mode for BookE hflags */ +#define MSR_ICM 30 /* Interrupt computation mode for BookE */ +#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */ #define MSR_VR 25 /* altivec available hflags */ -#define MSR_SPE 25 /* SPE enable on e500 hflags */ +#define MSR_SPE 25 /* SPE enable for BookE hflags */ #define MSR_AP 23 /* Access privilege state on 602 hflags */ #define MSR_SA 22 /* Supervisor access mode on 602 hflags */ #define MSR_KEY 19 /* key bit on 603e */ @@ -600,6 +600,8 @@ struct ppc_tlb_t { #define msr_sf env->msr[MSR_SF] #define msr_isf env->msr[MSR_ISF] #define msr_hv env->msr[MSR_HV] +#define msr_cm env->msr[MSR_CM] +#define msr_icm env->msr[MSR_ICM] #define msr_ucle env->msr[MSR_UCLE] #define msr_vr env->msr[MSR_VR] #define msr_spe env->msr[MSR_SPE] @@ -724,6 +726,7 @@ struct CPUPPCState { int nb_ways; /* Number of ways in the TLB set */ int last_way; /* Last used way used to allocate TLB in a LRU way */ int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ + int nb_pids; /* Number of available PID registers */ ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ /* Callbacks for specific checks on some implementations */ int (*tlb_check_more)(CPUPPCState *env, struct ppc_tlb_t *tlb, int *prot, @@ -874,11 +877,11 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_SRR1 (0x01B) #define SPR_BOOKE_PID (0x030) #define SPR_BOOKE_DECAR (0x036) -#define SPR_CSRR0 (0x03A) -#define SPR_CSRR1 (0x03B) +#define SPR_BOOKE_CSRR0 (0x03A) +#define SPR_BOOKE_CSRR1 (0x03B) #define SPR_BOOKE_DEAR (0x03D) #define SPR_BOOKE_ESR (0x03E) -#define SPR_BOOKE_EVPR (0x03F) +#define SPR_BOOKE_IVPR (0x03F) #define SPR_8xx_EIE (0x050) #define SPR_8xx_EID (0x051) #define SPR_8xx_NRE (0x052) @@ -900,6 +903,9 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_58x_BAR (0x09F) #define SPR_VRSAVE (0x100) #define SPR_USPRG0 (0x100) +#define SPR_USPRG1 (0x101) +#define SPR_USPRG2 (0x102) +#define SPR_USPRG3 (0x103) #define SPR_USPRG4 (0x104) #define SPR_USPRG5 (0x105) #define SPR_USPRG6 (0x106) @@ -973,16 +979,18 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_BOOKE_ATBL (0x20E) #define SPR_BOOKE_ATBU (0x20F) #define SPR_IBAT0U (0x210) -#define SPR_E500_IVOR32 (0x210) +#define SPR_BOOKE_IVOR32 (0x210) #define SPR_IBAT0L (0x211) -#define SPR_E500_IVOR33 (0x211) +#define SPR_BOOKE_IVOR33 (0x211) #define SPR_IBAT1U (0x212) -#define SPR_E500_IVOR34 (0x212) +#define SPR_BOOKE_IVOR34 (0x212) #define SPR_IBAT1L (0x213) -#define SPR_E500_IVOR35 (0x213) +#define SPR_BOOKE_IVOR35 (0x213) #define SPR_IBAT2U (0x214) +#define SPR_BOOKE_IVOR36 (0x214) #define SPR_IBAT2L (0x215) #define SPR_E500_L1CFG0 (0x215) +#define SPR_BOOKE_IVOR37 (0x215) #define SPR_IBAT3U (0x216) #define SPR_E500_L1CFG1 (0x216) #define SPR_IBAT3L (0x217) @@ -1005,25 +1013,32 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_DBAT4U (0x238) #define SPR_DBAT4L (0x239) #define SPR_DBAT5U (0x23A) -#define SPR_E500_MCSRR0 (0x23A) +#define SPR_BOOKE_MCSRR0 (0x23A) #define SPR_DBAT5L (0x23B) -#define SPR_E500_MCSRR1 (0x23B) +#define SPR_BOOKE_MCSRR1 (0x23B) #define SPR_DBAT6U (0x23C) -#define SPR_E500_MCSR (0x23C) +#define SPR_BOOKE_MCSR (0x23C) #define SPR_DBAT6L (0x23D) #define SPR_E500_MCAR (0x23D) #define SPR_DBAT7U (0x23E) +#define SPR_BOOKE_DSRR0 (0x23E) #define SPR_DBAT7L (0x23F) -#define SPR_E500_MAS0 (0x270) -#define SPR_E500_MAS1 (0x271) -#define SPR_E500_MAS2 (0x272) -#define SPR_E500_MAS3 (0x273) -#define SPR_E500_MAS4 (0x274) -#define SPR_E500_MAS6 (0x276) -#define SPR_E500_PID1 (0x279) -#define SPR_E500_PID2 (0x27A) -#define SPR_E500_TLB0CFG (0x2B0) -#define SPR_E500_TLB1CFG (0x2B1) +#define SPR_BOOKE_DSRR1 (0x23F) +#define SPR_BOOKE_SPRG8 (0x25C) +#define SPR_BOOKE_SPRG9 (0x25D) +#define SPR_BOOKE_MAS0 (0x270) +#define SPR_BOOKE_MAS1 (0x271) +#define SPR_BOOKE_MAS2 (0x272) +#define SPR_BOOKE_MAS3 (0x273) +#define SPR_BOOKE_MAS4 (0x274) +#define SPR_BOOKE_MAS6 (0x276) +#define SPR_BOOKE_PID1 (0x279) +#define SPR_BOOKE_PID2 (0x27A) +#define SPR_BOOKE_TLB0CFG (0x2B0) +#define SPR_BOOKE_TLB1CFG (0x2B1) +#define SPR_BOOKE_TLB2CFG (0x2B2) +#define SPR_BOOKE_TLB3CFG (0x2B3) +#define SPR_BOOKE_EPR (0x2BE) #define SPR_440_INV0 (0x370) #define SPR_440_INV1 (0x371) #define SPR_440_INV2 (0x372) @@ -1043,10 +1058,10 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_440_DVLIM (0x398) #define SPR_440_IVLIM (0x399) #define SPR_440_RSTCFG (0x39B) -#define SPR_440_DCBTRL (0x39C) -#define SPR_440_DCBTRH (0x39D) -#define SPR_440_ICBTRL (0x39E) -#define SPR_440_ICBTRH (0x39F) +#define SPR_BOOKE_DCBTRL (0x39C) +#define SPR_BOOKE_DCBTRH (0x39D) +#define SPR_BOOKE_ICBTRL (0x39E) +#define SPR_BOOKE_ICBTRH (0x39F) #define SPR_UMMCR0 (0x3A8) #define SPR_UPMC1 (0x3A9) #define SPR_UPMC2 (0x3AA) @@ -1056,11 +1071,13 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_UPMC4 (0x3AE) #define SPR_USDA (0x3AF) #define SPR_40x_ZPR (0x3B0) -#define SPR_E500_MAS7 (0x3B0) +#define SPR_BOOKE_MAS7 (0x3B0) #define SPR_40x_PID (0x3B1) #define SPR_440_MMUCR (0x3B2) #define SPR_4xx_CCR0 (0x3B3) +#define SPR_BOOKE_EPLC (0x3B3) #define SPR_405_IAC3 (0x3B4) +#define SPR_BOOKE_EPSC (0x3B4) #define SPR_405_IAC4 (0x3B5) #define SPR_405_DVC1 (0x3B6) #define SPR_405_DVC2 (0x3B7) @@ -1083,7 +1100,7 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_DCMP (0x3D1) #define SPR_HASH1 (0x3D2) #define SPR_HASH2 (0x3D3) -#define SPR_4xx_ICDBDR (0x3D3) +#define SPR_BOOKE_ICBDR (0x3D3) #define SPR_IMISS (0x3D4) #define SPR_40x_ESR (0x3D4) #define SPR_ICMP (0x3D5) @@ -1114,7 +1131,7 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_E500_L1CSR1 (0x3F3) #define SPR_440_DBDR (0x3F3) #define SPR_40x_IAC1 (0x3F4) -#define SPR_E500_MMUCSR0 (0x3F4) +#define SPR_BOOKE_MMUCSR0 (0x3F4) #define SPR_DABR (0x3F5) #define DABR_MASK (~(target_ulong)0x7) #define SPR_E500_BUCSR (0x3F5) @@ -1122,7 +1139,7 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #define SPR_601_HID5 (0x3F5) #define SPR_40x_DAC1 (0x3F6) #define SPR_40x_DAC2 (0x3F7) -#define SPR_E500_MMUCFG (0x3F7) +#define SPR_BOOKE_MMUCFG (0x3F7) #define SPR_L2PM (0x3F8) #define SPR_750_HID2 (0x3F8) #define SPR_L2CR (0x3F9) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index a8ebc0cb4..d5626316c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -893,11 +893,11 @@ static void gen_spr_G2 (CPUPPCState *env) &spr_read_generic, SPR_NOACCESS, 0x00000000); /* Exception processing */ - spr_register(env, SPR_CSRR0, "CSRR0", + spr_register(env, SPR_BOOKE_CSRR0, "CSRR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_CSRR1, "CSRR1", + spr_register(env, SPR_BOOKE_CSRR1, "CSRR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -1060,11 +1060,27 @@ static void gen_spr_BookE (CPUPPCState *env) &spr_read_generic, &spr_write_pir, 0x00000000); /* Interrupt processing */ - spr_register(env, SPR_CSRR0, "CSRR0", + spr_register(env, SPR_BOOKE_CSRR0, "CSRR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_CSRR1, "CSRR1", + spr_register(env, SPR_BOOKE_CSRR1, "CSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_DSRR0, "DSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_DSRR1, "DSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -1137,7 +1153,12 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_BOOKE_EVPR, "EVPR", + spr_register(env, SPR_BOOKE_IVPR, "IVPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Exception vectors */ + spr_register(env, SPR_BOOKE_IVPR, "IVPR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -1205,6 +1226,30 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + spr_register(env, SPR_BOOKE_IVOR32, "IVOR32", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR33, "IVOR33", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR34, "IVOR34", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR35, "IVOR35", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR36, "IVOR36", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR37, "IVOR37", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); spr_register(env, SPR_BOOKE_PID, "PID", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1265,6 +1310,89 @@ static void gen_spr_BookE (CPUPPCState *env) 0x00000000); } +/* FSL storage control registers */ +static void gen_spr_BookE_FSL (CPUPPCState *env) +{ + /* TLB assist registers */ + spr_register(env, SPR_BOOKE_MAS0, "MAS0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MAS1, "MAS2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MAS2, "MAS3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MAS3, "MAS4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MAS4, "MAS5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MAS6, "MAS6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MAS7, "MAS7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + if (env->nb_pids > 1) { + spr_register(env, SPR_BOOKE_PID1, "PID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + } + if (env->nb_pids > 2) { + spr_register(env, SPR_BOOKE_PID2, "PID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + } + spr_register(env, SPR_BOOKE_MMUCFG, "MMUCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + spr_register(env, SPR_BOOKE_MMUCSR0, "MMUCSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* TOFIX */ + switch (env->nb_ways) { + case 4: + spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* Fallthru */ + case 3: + spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* Fallthru */ + case 2: + spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* Fallthru */ + case 1: + spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* Fallthru */ + case 0: + default: + break; + } +} + /* SPR specific to PowerPC 440 implementation */ static void gen_spr_440 (CPUPPCState *env) { @@ -1361,27 +1489,27 @@ static void gen_spr_440 (CPUPPCState *env) 0x00000000); /* Cache debug */ /* XXX : not implemented */ - spr_register(env, SPR_440_DCBTRH, "DCBTRH", + spr_register(env, SPR_BOOKE_DCBTRH, "DCBTRH", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_DCBTRL, "DCBTRL", + spr_register(env, SPR_BOOKE_DCBTRL, "DCBTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_4xx_ICDBDR, "ICDBDR", + spr_register(env, SPR_BOOKE_ICBDR, "ICBDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_ICBTRH, "ICBTRH", + spr_register(env, SPR_BOOKE_ICBTRH, "ICBTRH", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_ICBTRL, "ICBTRL", + spr_register(env, SPR_BOOKE_ICBTRL, "ICBTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); @@ -1426,7 +1554,7 @@ static void gen_spr_40x (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_4xx_ICDBDR, "ICDBDR", + spr_register(env, SPR_BOOKE_ICBDR, "ICBDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); @@ -1861,6 +1989,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) /* Time base */ gen_tbl(env); gen_spr_BookE(env); + gen_spr_BookE_FSL(env); env->nb_BATs = 0; env->nb_tlb = 64; env->nb_ways = 1; -- cgit v1.2.3 From a42bd6ccdfefbadfc34d381c42d64a78f532df63 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 30 Mar 2007 10:22:46 +0000 Subject: Fix rfi instruction: do not depend on current execution mode but on the execution mode that will be effective after the return. Add rfci, rfdi and rfmci for BookE PowerPC. Extend mfdcr / mtdcr and implement mfdrcx / mtdcrx. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2544 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 44 ++++++++++--------- target-ppc/op_helper.c | 112 +++++++++++++++++++++++++++++++++---------------- target-ppc/op_helper.h | 11 ++--- target-ppc/translate.c | 109 ++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 196 insertions(+), 80 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 8bbbd62d4..b284798dc 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1821,23 +1821,11 @@ void OPPROTO op_rfi (void) } #if defined(TARGET_PPC64) -void OPPROTO op_rfi_32 (void) -{ - do_rfi_32(); - RETURN(); -} - void OPPROTO op_rfid (void) { do_rfid(); RETURN(); } - -void OPPROTO op_rfid_32 (void) -{ - do_rfid_32(); - RETURN(); -} #endif #endif @@ -2309,28 +2297,46 @@ void OPPROTO op_405_check_satu (void) } #if !defined(CONFIG_USER_ONLY) -void OPPROTO op_4xx_load_dcr (void) +void OPPROTO op_load_dcr (void) { - do_4xx_load_dcr(PARAM1); + do_load_dcr(); RETURN(); } -void OPPROTO op_4xx_store_dcr (void) +void OPPROTO op_store_dcr (void) { - do_4xx_store_dcr(PARAM1); + do_store_dcr(); RETURN(); } /* Return from critical interrupt : * same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1 */ -void OPPROTO op_4xx_rfci (void) +void OPPROTO op_40x_rfci (void) +{ + do_40x_rfci(); + RETURN(); +} + +void OPPROTO op_rfci (void) +{ + do_rfci(); + RETURN(); +} + +void OPPROTO op_rfdi (void) +{ + do_rfdi(); + RETURN(); +} + +void OPPROTO op_rfmci (void) { - do_4xx_rfci(); + do_rfmci(); RETURN(); } -void OPPROTO op_4xx_wrte (void) +void OPPROTO op_wrte (void) { msr_ee = T0 >> 16; RETURN(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 55b5ca565..c21a38aea 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -881,12 +881,17 @@ void do_fcmpo (void) #if !defined (CONFIG_USER_ONLY) void do_rfi (void) { - env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); #if defined(TARGET_PPC64) - ppc_store_msr_32(env, T0); + if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { + env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); + do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + } else { + env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); + ppc_store_msr_32(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + } #else - do_store_msr(env, T0); + env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); + do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); #endif #if defined (DEBUG_OP) dump_rfi(); @@ -895,33 +900,15 @@ void do_rfi (void) } #if defined(TARGET_PPC64) -void do_rfi_32 (void) -{ - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); - ppc_store_msr_32(env, T0); -#if defined (DEBUG_OP) - dump_rfi(); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; -} - void do_rfid (void) { - env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); - do_store_msr(env, T0); -#if defined (DEBUG_OP) - dump_rfi(); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; -} - -void do_rfid_32 (void) -{ - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); - do_store_msr(env, T0); + if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { + env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); + do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + } else { + env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); + do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + } #if defined (DEBUG_OP) dump_rfi(); #endif @@ -936,8 +923,9 @@ void do_tw (int flags) ((int32_t)T0 > (int32_t)T1 && (flags & 0x08)) || ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) || ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) || - ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) + ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) { do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); + } } #if defined(TARGET_PPC64) @@ -1196,34 +1184,84 @@ void do_405_check_sat (void) } #if !defined(CONFIG_USER_ONLY) -void do_4xx_rfci (void) +void do_40x_rfci (void) { env->nip = env->spr[SPR_40x_SRR2]; - T0 = env->spr[SPR_40x_SRR3] & ~0xFFFF0000; - do_store_msr(env, T0); + do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request = CPU_INTERRUPT_EXITTB; +} + +void do_rfci (void) +{ +#if defined(TARGET_PPC64) + if (env->spr[SPR_BOOKE_CSRR1] & (1 << MSR_CM)) { + env->nip = (uint64_t)env->spr[SPR_BOOKE_CSRR0]; + } else +#endif + { + env->nip = (uint32_t)env->spr[SPR_BOOKE_CSRR0]; + } + do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_CSRR1] & ~0x3FFF0000); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request = CPU_INTERRUPT_EXITTB; +} + +void do_rfdi (void) +{ +#if defined(TARGET_PPC64) + if (env->spr[SPR_BOOKE_DSRR1] & (1 << MSR_CM)) { + env->nip = (uint64_t)env->spr[SPR_BOOKE_DSRR0]; + } else +#endif + { + env->nip = (uint32_t)env->spr[SPR_BOOKE_DSRR0]; + } + do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_DSRR1] & ~0x3FFF0000); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request = CPU_INTERRUPT_EXITTB; +} + +void do_rfmci (void) +{ +#if defined(TARGET_PPC64) + if (env->spr[SPR_BOOKE_MCSRR1] & (1 << MSR_CM)) { + env->nip = (uint64_t)env->spr[SPR_BOOKE_MCSRR0]; + } else +#endif + { + env->nip = (uint32_t)env->spr[SPR_BOOKE_MCSRR0]; + } + do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_MCSRR1] & ~0x3FFF0000); #if defined (DEBUG_OP) dump_rfi(); #endif env->interrupt_request = CPU_INTERRUPT_EXITTB; } -void do_4xx_load_dcr (int dcrn) +void do_load_dcr (void) { target_ulong val; if (unlikely(env->dcr_read == NULL)) do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); - else if (unlikely((*env->dcr_read)(env->dcr_env, dcrn, &val) != 0)) + else if (unlikely((*env->dcr_read)(env->dcr_env, T0, &val) != 0)) do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); else T0 = val; } -void do_4xx_store_dcr (int dcrn) +void do_store_dcr (void) { if (unlikely(env->dcr_write == NULL)) do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); - else if (unlikely((*env->dcr_write)(env->dcr_env, dcrn, T0) != 0)) + else if (unlikely((*env->dcr_write)(env->dcr_env, T0, T1) != 0)) do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); } diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index f819a0d36..abc295a4d 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -117,9 +117,7 @@ void do_td (int flags); #if !defined(CONFIG_USER_ONLY) void do_rfi (void); #if defined(TARGET_PPC64) -void do_rfi_32 (void); void do_rfid (void); -void do_rfid_32 (void); #endif void do_tlbia (void); void do_tlbie (void); @@ -158,9 +156,12 @@ void do_op_602_mfrom (void); void do_405_check_ov (void); void do_405_check_sat (void); #if !defined(CONFIG_USER_ONLY) -void do_4xx_load_dcr (int dcrn); -void do_4xx_store_dcr (int dcrn); -void do_4xx_rfci (void); +void do_load_dcr (void); +void do_store_dcr (void); +void do_40x_rfci (void); +void do_rfci (void); +void do_rfdi (void); +void do_rfmci (void); void do_4xx_tlbre_lo (void); void do_4xx_tlbre_hi (void); void do_4xx_tlbsx (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 7d382d6ca..2d9a346ed 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2861,12 +2861,7 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) RET_PRIVOPC(ctx); return; } -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) - gen_op_rfi_32(); - else -#endif - gen_op_rfi(); + gen_op_rfi(); RET_CHG_FLOW(ctx); #endif } @@ -2882,10 +2877,7 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW) RET_PRIVOPC(ctx); return; } - if (!ctx->sf_mode) - gen_op_rfid_32(); - else - gen_op_rfid(); + gen_op_rfid(); RET_CHG_FLOW(ctx); #endif } @@ -4423,7 +4415,8 @@ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) RET_PRIVREG(ctx); return; } - gen_op_4xx_load_dcr(dcrn); + gen_op_set_T0(dcrn); + gen_op_load_dcr(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } @@ -4440,8 +4433,41 @@ GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) RET_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_4xx_store_dcr(dcrn); + gen_op_set_T0(dcrn); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_store_dcr(); +#endif +} + +/* mfdcrx */ +GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_dcr(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* mtdcrx */ +GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_store_dcr(); #endif } @@ -4513,7 +4539,38 @@ GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON) } /* rfci (supervisor only) */ -GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON) +GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* Restore CPU state */ + gen_op_40x_rfci(); + RET_CHG_FLOW(ctx); +#endif +} + +GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* Restore CPU state */ + gen_op_rfci(); + RET_CHG_FLOW(ctx); +#endif +} + +/* BookE specific */ +GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4523,14 +4580,28 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON) return; } /* Restore CPU state */ - gen_op_4xx_rfci(); + gen_op_rfdi(); RET_CHG_FLOW(ctx); #endif } +GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* Restore CPU state */ + gen_op_rfmci(); + RET_CHG_FLOW(ctx); +#endif +} /* TLB management - PowerPC 405 implementation */ /* tlbre */ -GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON) +GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4558,7 +4629,7 @@ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON) } /* tlbsx - tlbsx. */ -GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON) +GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4615,7 +4686,7 @@ GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) return; } gen_op_load_gpr_T0(rD(ctx->opcode)); - gen_op_4xx_wrte(); + gen_op_wrte(); RET_EXCP(ctx, EXCP_MTMSR, 0); #endif } @@ -4631,7 +4702,7 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON) return; } gen_op_set_T0(ctx->opcode & 0x00010000); - gen_op_4xx_wrte(); + gen_op_wrte(); RET_EXCP(ctx, EXCP_MTMSR, 0); #endif } -- cgit v1.2.3 From e69f67b6d58f366ffaa83a0973948edd1f74b370 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 30 Mar 2007 16:41:55 +0000 Subject: Fix build failure. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2545 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.h b/vl.h index 2bcf81ada..5e2d8e857 100644 --- a/vl.h +++ b/vl.h @@ -859,9 +859,11 @@ enum { OPENPIC_EVT_DEBUG, /* Inconditional debug event */ OPENPIC_EVT_RESET, /* Core reset event */ }; +struct CPUPPCState; void openpic_set_irq(void *opaque, int n_IRQ, int level); openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, - int *pmem_index, int nb_cpus, CPUPPCState **envp); + int *pmem_index, int nb_cpus, + struct CPUPPCState **envp); /* heathrow_pic.c */ typedef struct HeathrowPICS HeathrowPICS; -- cgit v1.2.3 From 24c7b0e330fdbfcfe87f515d79e67156c57cbc4f Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 30 Mar 2007 16:44:54 +0000 Subject: Sanitize mips exception handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2546 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 6 +++--- dyngen-exec.h | 1 + hw/mips_int.c | 15 +++++++-------- target-mips/cpu.h | 2 -- target-mips/helper.c | 45 +++++++++++++++++++------------------------ target-mips/op.c | 51 ++++++++++++++++++++++++++----------------------- target-mips/op_helper.c | 8 +++++--- target-mips/translate.c | 22 +++------------------ 8 files changed, 66 insertions(+), 84 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index d124c4059..d16888662 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -461,10 +461,10 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Status & env->CP0_Cause & 0x0000FF00) && - !(env->hflags & MIPS_HFLAG_EXL) && - !(env->hflags & MIPS_HFLAG_ERL) && + !(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { /* Raise it */ env->exception_index = EXCP_EXT_INTERRUPT; diff --git a/dyngen-exec.h b/dyngen-exec.h index bf40353b2..c63eb265d 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -80,6 +80,7 @@ typedef void * host_reg_t; typedef struct FILE FILE; extern int fprintf(FILE *, const char *, ...); +extern int fputs(const char *, FILE *); extern int printf(const char *, ...); #undef NULL #define NULL 0 diff --git a/hw/mips_int.c b/hw/mips_int.c index 7f9f15305..b384b64d2 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -5,17 +5,16 @@ IRQ may change */ void cpu_mips_update_irq(CPUState *env) { - if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && - (env->CP0_Status & (1 << CP0St_IE)) && - !(env->hflags & MIPS_HFLAG_EXL) && - !(env->hflags & MIPS_HFLAG_ERL) && - !(env->hflags & MIPS_HFLAG_DM)) { - if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) { + if ((env->CP0_Status & (1 << CP0St_IE)) && + !(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM)) { + if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && + !(env->interrupt_request & CPU_INTERRUPT_HARD)) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } - } else { + } else cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } } void cpu_mips_irq_request(void *opaque, int irq, int level) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f0f3ab2d7..4fec3cc88 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -248,8 +248,6 @@ struct CPUMIPSState { #define MIPS_HFLAG_TMASK 0x007F #define MIPS_HFLAG_MODE 0x001F /* execution modes */ #define MIPS_HFLAG_UM 0x0001 /* user mode */ -#define MIPS_HFLAG_ERL 0x0002 /* Error mode */ -#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */ #define MIPS_HFLAG_DM 0x0008 /* Debug mode */ #define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ #define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ diff --git a/target-mips/helper.c b/target-mips/helper.c index 0b23f359f..fe5b2ab67 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -90,7 +90,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, if (user_mode && address > 0x7FFFFFFFUL) return TLBRET_BADADDR; if (address < (int32_t)0x80000000UL) { - if (!(env->hflags & MIPS_HFLAG_ERL)) { + if (!(env->CP0_Status & (1 << CP0St_ERL))) { #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); #else @@ -289,21 +289,18 @@ void do_interrupt (CPUState *env) goto set_DEPC; case EXCP_DDBL: env->CP0_Debug |= 1 << CP0DB_DDBL; - goto set_DEPC; set_DEPC: if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ env->CP0_DEPC = env->PC - 4; - if (!(env->hflags & MIPS_HFLAG_EXL)) - env->CP0_Cause |= (1 << CP0Ca_BD); env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_DEPC = env->PC; - env->CP0_Cause &= ~(1 << CP0Ca_BD); } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; + env->hflags &= ~MIPS_HFLAG_UM; /* EJTAG probe trap enable is not implemented... */ env->PC = (int32_t)0xBFC00480; break; @@ -311,25 +308,22 @@ void do_interrupt (CPUState *env) cpu_reset(env); break; case EXCP_SRESET: - env->CP0_Status = (1 << CP0St_SR); + env->CP0_Status |= (1 << CP0St_SR); env->CP0_WatchLo = 0; goto set_error_EPC; case EXCP_NMI: - env->CP0_Status = (1 << CP0St_NMI); + env->CP0_Status |= (1 << CP0St_NMI); set_error_EPC: if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ env->CP0_ErrorEPC = env->PC - 4; - if (!(env->hflags & MIPS_HFLAG_EXL)) - env->CP0_Cause |= (1 << CP0Ca_BD); env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_ErrorEPC = env->PC; - env->CP0_Cause &= ~(1 << CP0Ca_BD); } - env->hflags |= MIPS_HFLAG_ERL; - env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); + env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); + env->hflags &= ~MIPS_HFLAG_UM; env->PC = (int32_t)0xBFC00000; break; case EXCP_MCHECK: @@ -350,7 +344,7 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBL: cause = 2; - if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) offset = 0x000; goto set_EPC; case EXCP_IBE: @@ -384,28 +378,29 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBS: cause = 3; - if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) offset = 0x000; - goto set_EPC; set_EPC: - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_EPC = env->PC - 4; - if (!(env->hflags & MIPS_HFLAG_EXL)) + if (!(env->CP0_Status & (1 << CP0St_EXL))) { + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_EPC = env->PC - 4; env->CP0_Cause |= (1 << CP0Ca_BD); - env->hflags &= ~MIPS_HFLAG_BMASK; + env->hflags &= ~MIPS_HFLAG_BMASK; + } else { + env->CP0_EPC = env->PC; + env->CP0_Cause &= ~(1 << CP0Ca_BD); + } } else { - env->CP0_EPC = env->PC; - env->CP0_Cause &= ~(1 << CP0Ca_BD); + env->CP0_Status |= (1 << CP0St_EXL); + env->hflags &= ~MIPS_HFLAG_UM; } if (env->CP0_Status & (1 << CP0St_BEV)) { env->PC = (int32_t)0xBFC00200; } else { env->PC = (int32_t)0x80000000; } - env->hflags |= MIPS_HFLAG_EXL; - env->CP0_Status |= (1 << CP0St_EXL); env->PC += offset; env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); break; diff --git a/target-mips/op.c b/target-mips/op.c index f97ec4292..fecf18cc6 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1105,12 +1105,6 @@ void op_mfc0_compare (void) void op_mfc0_status (void) { T0 = env->CP0_Status; - if (env->hflags & MIPS_HFLAG_UM) - T0 |= (1 << CP0St_UM); - if (env->hflags & MIPS_HFLAG_ERL) - T0 |= (1 << CP0St_ERL); - if (env->hflags & MIPS_HFLAG_EXL) - T0 |= (1 << CP0St_EXL); RETURN(); } @@ -1365,20 +1359,10 @@ void op_mtc0_status (void) { uint32_t val, old; - val = (int32_t)T0 & 0xFA78FF01; + /* No 64bit FPU, no reverse endianness, no MDMX/DSP, no 64bit ops, + no 64bit addressing implemented. */ + val = (int32_t)T0 & 0xF878FF17; old = env->CP0_Status; - if (T0 & (1 << CP0St_UM)) - env->hflags |= MIPS_HFLAG_UM; - else - env->hflags &= ~MIPS_HFLAG_UM; - if (T0 & (1 << CP0St_ERL)) - env->hflags |= MIPS_HFLAG_ERL; - else - env->hflags &= ~MIPS_HFLAG_ERL; - if (T0 & (1 << CP0St_EXL)) - env->hflags |= MIPS_HFLAG_EXL; - else - env->hflags &= ~MIPS_HFLAG_EXL; env->CP0_Status = val; if (loglevel & CPU_LOG_TB_IN_ASM) CALL_FROM_TB2(do_mtc0_status_debug, old, val); @@ -1662,6 +1646,15 @@ void op_dmtc0_errorepc (void) # define DEBUG_FPU_STATE() do { } while(0) #endif +void op_cp0_enabled(void) +{ + if (!(env->CP0_Status & (1 << CP0St_CU0)) && + (env->hflags & MIPS_HFLAG_UM)) { + CALL_FROM_TB2(do_raise_exception_direct_err, EXCP_CpU, 0); + } + RETURN(); +} + void op_cp1_enabled(void) { if (!(env->CP0_Status & (1 << CP0St_CU1))) { @@ -2091,15 +2084,18 @@ void debug_eret (void); void op_eret (void) { CALL_FROM_TB0(debug_eret); - if (env->hflags & MIPS_HFLAG_ERL) { + if (env->CP0_Status & (1 << CP0St_ERL)) { env->PC = env->CP0_ErrorEPC; - env->hflags &= ~MIPS_HFLAG_ERL; - env->CP0_Status &= ~(1 << CP0St_ERL); + env->CP0_Status &= ~(1 << CP0St_ERL); } else { env->PC = env->CP0_EPC; - env->hflags &= ~MIPS_HFLAG_EXL; - env->CP0_Status &= ~(1 << CP0St_EXL); + env->CP0_Status &= ~(1 << CP0St_EXL); } + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & (1 << CP0St_UM))) + env->hflags |= MIPS_HFLAG_UM; env->CP0_LLAddr = 1; RETURN(); } @@ -2108,6 +2104,13 @@ void op_deret (void) { CALL_FROM_TB0(debug_eret); env->PC = env->CP0_DEPC; + env->hflags |= MIPS_HFLAG_DM; + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & (1 << CP0St_UM))) + env->hflags |= MIPS_HFLAG_UM; + env->CP0_LLAddr = 1; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 8ab7bf57d..f9748fc16 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -509,9 +509,11 @@ void dump_sc (void) void debug_eret (void) { if (loglevel) { - fprintf(logfile, "ERET: pc " TARGET_FMT_lx " EPC " TARGET_FMT_lx " ErrorEPC " TARGET_FMT_lx " (%d)\n", - env->PC, env->CP0_EPC, env->CP0_ErrorEPC, - env->hflags & MIPS_HFLAG_ERL ? 1 : 0); + fprintf(logfile, "ERET: pc " TARGET_FMT_lx " EPC " TARGET_FMT_lx, + env->PC, env->CP0_EPC); + if (env->CP0_Status & (1 << CP0St_ERL)) + fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); + fputs("\n", logfile); } } diff --git a/target-mips/translate.c b/target-mips/translate.c index 5cc922b57..65821087b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4022,17 +4022,6 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) { const char *opn = "unk"; - if ((!ctx->CP0_Status & (1 << CP0St_CU0) && - (ctx->hflags & MIPS_HFLAG_UM)) && - !(ctx->hflags & MIPS_HFLAG_ERL) && - !(ctx->hflags & MIPS_HFLAG_EXL)) { - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "CP0 is not usable\n"); - } - generate_exception (ctx, EXCP_CpU); - return; - } - switch (opc) { case OPC_MFC0: if (rt == 0) { @@ -4809,7 +4798,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_trap(ctx, op1, rs, -1, imm); break; case OPC_SYNCI: - /* treat as noop */ + /* treat as noop */ break; default: /* Invalid */ MIPS_INVAL("REGIMM"); @@ -4818,6 +4807,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_CP0: + gen_op_cp0_enabled(); op1 = MASK_CP0(ctx->opcode); switch (op1) { case OPC_MFC0: @@ -5258,12 +5248,6 @@ void cpu_dump_state (CPUState *env, FILE *f, } c0_status = env->CP0_Status; - if (env->hflags & MIPS_HFLAG_UM) - c0_status |= (1 << CP0St_UM); - if (env->hflags & MIPS_HFLAG_ERL) - c0_status |= (1 << CP0St_ERL); - if (env->hflags & MIPS_HFLAG_EXL) - c0_status |= (1 << CP0St_EXL); cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", c0_status, env->CP0_Cause, env->CP0_EPC); @@ -5304,6 +5288,7 @@ void cpu_reset (CPUMIPSState *env) } else { env->CP0_ErrorEPC = env->PC; } + env->hflags = 0; env->PC = (int32_t)0xBFC00000; #if defined (MIPS_USES_R4K_TLB) env->CP0_Random = MIPS_TLB_NB - 1; @@ -5314,7 +5299,6 @@ void cpu_reset (CPUMIPSState *env) env->CP0_EBase = 0x80000000; env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); env->CP0_WatchLo = 0; - env->hflags = MIPS_HFLAG_ERL; /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); #endif -- cgit v1.2.3 From 5efbfeddac734680ecb00c4e38eb6c698ad7fa5a Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 30 Mar 2007 17:48:00 +0000 Subject: Squash logic bugs while they are fresh... git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2547 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index fe5b2ab67..2572050bb 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -392,7 +392,6 @@ void do_interrupt (CPUState *env) env->CP0_EPC = env->PC; env->CP0_Cause &= ~(1 << CP0Ca_BD); } - } else { env->CP0_Status |= (1 << CP0St_EXL); env->hflags &= ~MIPS_HFLAG_UM; } -- cgit v1.2.3 From 36bb244bd30faf7ea931bb0ac5ccd76f74f761e4 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 30 Mar 2007 18:42:21 +0000 Subject: Fix typo, suggested by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2548 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 4fec3cc88..3849e503c 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -12,7 +12,7 @@ // uint_fast8_t and uint_fast16_t not in // XXX: move that elsewhere -#if defined(HOST_SOLARIS) && SOLARISREV < 10 +#if defined(HOST_SOLARIS) && HOST_SOLARIS < 10 typedef unsigned char uint_fast8_t; typedef unsigned int uint_fast16_t; #endif -- cgit v1.2.3 From 7246bb21ba7321a0b741405836c24c303c13d268 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 30 Mar 2007 18:56:19 +0000 Subject: Update mips TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2549 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index 9faa041b2..c92cbaf97 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -6,10 +6,6 @@ General - [ls][dw][lr] report broken (aligned) BadVAddr - Missing per-CPU instruction decoding, currently all implemented instructions are regarded as valid -- pcnet32 does not work for little endian emulation on big endian host - (probably not mips specific, but observable for mips-malta) -- CP1 enable/disable is checked at translation time, not at execution - time, so it will have delayed effect. MIPS64 ------ @@ -25,4 +21,4 @@ MALTA system emulation ---------------------- - We fake firmware support instead of doing the real thing - Real firmware falls over when trying to init RAM, presumably due - to lacking I2C emulation. + to lacking system controller emulation. -- cgit v1.2.3 From e598752a63d65eb2ed97123363cb02632bd485c7 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 30 Mar 2007 18:58:01 +0000 Subject: Spelling fixes, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2550 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 4 ++-- qemu-doc.texi | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/monitor.c b/monitor.c index 379733333..86b1f389b 100644 --- a/monitor.c +++ b/monitor.c @@ -1215,9 +1215,9 @@ static term_cmd_t term_cmds[] = { { "q|quit", "", do_quit, "", "quit the emulator" }, { "eject", "-fB", do_eject, - "[-f] device", "eject a removable media (use -f to force it)" }, + "[-f] device", "eject a removable medium (use -f to force it)" }, { "change", "BF", do_change, - "device filename", "change a removable media" }, + "device filename", "change a removable medium" }, { "screendump", "F", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, { "log", "s", do_log, diff --git a/qemu-doc.texi b/qemu-doc.texi index 74d0edf05..5db875c56 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -789,7 +789,7 @@ emulator. You can use it to: @itemize @minus @item -Remove or insert removable medias images +Remove or insert removable media images (such as CD-ROM or floppies) @item @@ -842,10 +842,10 @@ show which guest mouse is receiving events Quit the emulator. @item eject [-f] device -Eject a removable media (use -f to force it). +Eject a removable medium (use -f to force it). @item change device filename -Change a removable media. +Change a removable medium. @item screendump filename Save screen into PPM image @var{filename}. @@ -1140,7 +1140,7 @@ The prefered syntax is the drive letter (e.g. @file{d:}). The alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is supported as an alias to the first CDROM drive. -Currently there is no specific code to handle removable medias, so it +Currently there is no specific code to handle removable media, so it is better to use the @code{change} or @code{eject} monitor commands to change or eject media. @item Hard disks @@ -1158,7 +1158,7 @@ modifications are written in a temporary file). @file{/dev/cdrom} is an alias to the first CDROM. -Currently there is no specific code to handle removable medias, so it +Currently there is no specific code to handle removable media, so it is better to use the @code{change} or @code{eject} monitor commands to change or eject media. -- cgit v1.2.3 From aafd8139ed3fd90f281bb3ffc8db57c2882a077e Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 30 Mar 2007 19:20:50 +0000 Subject: Switch include for Solaris to avoid namespace issues. By Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2551 c046a42c-6fe2-441c-8c8c-71466251a162 --- kqemu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kqemu.c b/kqemu.c index baf3ebae7..c6b2e6950 100644 --- a/kqemu.c +++ b/kqemu.c @@ -27,7 +27,7 @@ #include #endif #ifdef HOST_SOLARIS -#include +#include #endif #include #include -- cgit v1.2.3 From 05a8096f2dd33234cacb957d2694281efc85e74d Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 31 Mar 2007 09:59:47 +0000 Subject: Better fix for OpenPIC: should not depend on PowerPC. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2552 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/openpic.c | 2 +- vl.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 7565b1def..1d9166511 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -965,7 +965,7 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, } openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, - int *pmem_index, int nb_cpus, CPUPPCState **envp) + int *pmem_index, int nb_cpus, CPUState **envp) { openpic_t *opp; uint8_t *pci_conf; diff --git a/vl.h b/vl.h index 5e2d8e857..c216b68a6 100644 --- a/vl.h +++ b/vl.h @@ -859,11 +859,10 @@ enum { OPENPIC_EVT_DEBUG, /* Inconditional debug event */ OPENPIC_EVT_RESET, /* Core reset event */ }; -struct CPUPPCState; void openpic_set_irq(void *opaque, int n_IRQ, int level); openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, int *pmem_index, int nb_cpus, - struct CPUPPCState **envp); + struct CPUState **envp); /* heathrow_pic.c */ typedef struct HeathrowPICS HeathrowPICS; -- cgit v1.2.3 From 1d0a48fb920cdd038aa1238740032e27aa460677 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 31 Mar 2007 11:10:49 +0000 Subject: As embedded PowerPC TLB model is very different from PowerPC 6xx ones, define ppc_tlb_t as an union of the two. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2553 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 20 +++++++++++++++++--- target-ppc/helper.c | 20 +++++++++----------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8d2c3a956..7204abe02 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -528,7 +528,7 @@ typedef struct ppc_tb_t ppc_tb_t; typedef struct ppc_spr_t ppc_spr_t; typedef struct ppc_dcr_t ppc_dcr_t; typedef struct ppc_avr_t ppc_avr_t; -typedef struct ppc_tlb_t ppc_tlb_t; +typedef union ppc_tlb_t ppc_tlb_t; /* SPR access micro-ops generations callbacks */ struct ppc_spr_t { @@ -547,12 +547,26 @@ struct ppc_avr_t { }; /* Software TLB cache */ -struct ppc_tlb_t { +typedef struct ppc6xx_tlb_t ppc6xx_tlb_t; +struct ppc6xx_tlb_t { target_ulong pte0; target_ulong pte1; target_ulong EPN; +}; + +typedef struct ppcemb_tlb_t ppcemb_tlb_t; +struct ppcemb_tlb_t { + target_ulong RPN; + target_ulong EPN; target_ulong PID; int size; + int prot; + int attr; /* Storage attributes */ +}; + +union ppc_tlb_t { + ppc6xx_tlb_t tlb6; + ppcemb_tlb_t tlbe; }; /*****************************************************************************/ @@ -729,7 +743,7 @@ struct CPUPPCState { int nb_pids; /* Number of available PID registers */ ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ /* Callbacks for specific checks on some implementations */ - int (*tlb_check_more)(CPUPPCState *env, struct ppc_tlb_t *tlb, int *prot, + int (*tlb_check_more)(CPUPPCState *env, ppc_tlb_t *tlb, int *prot, target_ulong vaddr, int rw, int acc_type, int is_user); /* 403 dedicated access protection registers */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4356edc36..c835b1efe 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -186,7 +186,7 @@ static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr, void ppc6xx_tlb_invalidate_all (CPUState *env) { - ppc_tlb_t *tlb; + ppc6xx_tlb_t *tlb; int nr, max; #if defined (DEBUG_SOFTWARE_TLB) && 0 @@ -199,7 +199,7 @@ void ppc6xx_tlb_invalidate_all (CPUState *env) if (env->id_tlbs == 1) max *= 2; for (nr = 0; nr < max; nr++) { - tlb = &env->tlb[nr]; + tlb = &env->tlb[nr].tlb6; #if !defined(FLUSH_ALL_TLBS) tlb_flush_page(env, tlb->EPN); #endif @@ -214,14 +214,14 @@ static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, int is_code, int match_epn) { - ppc_tlb_t *tlb; + ppc6xx_tlb_t *tlb; int way, nr; #if !defined(FLUSH_ALL_TLBS) /* Invalidate ITLB + DTLB, all ways */ for (way = 0; way < env->nb_ways; way++) { nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); - tlb = &env->tlb[nr]; + tlb = &env->tlb[nr].tlb6; if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) { #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { @@ -248,11 +248,11 @@ void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1) { - ppc_tlb_t *tlb; + ppc6xx_tlb_t *tlb; int nr; nr = ppc6xx_tlb_getnum(env, EPN, way, is_code); - tlb = &env->tlb[nr]; + tlb = &env->tlb[nr].tlb6; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX @@ -264,8 +264,6 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, tlb->pte0 = pte0; tlb->pte1 = pte1; tlb->EPN = EPN; - tlb->PID = 0; - tlb->size = 1; /* Store last way for LRU mechanism */ env->last_way = way; } @@ -273,7 +271,7 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int access_type) { - ppc_tlb_t *tlb; + ppc6xx_tlb_t *tlb; int nr, best, way; int ret; @@ -282,7 +280,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, for (way = 0; way < env->nb_ways; way++) { nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == ACCESS_CODE ? 1 : 0); - tlb = &env->tlb[nr]; + tlb = &env->tlb[nr].tlb6; /* This test "emulates" the PTE index match for hardware TLBs */ if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { #if defined (DEBUG_SOFTWARE_TLB) @@ -339,7 +337,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, } #endif /* Update page flags */ - pte_update_flags(ctx, &env->tlb[best].pte1, ret, rw); + pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw); } return ret; -- cgit v1.2.3 From a8dea12f453851d68c968d23faff2f1b9205d811 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 31 Mar 2007 11:33:48 +0000 Subject: Merge PowerPC 405 MMU model. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2554 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 159 +++++++++++++++++++++++++++++++++++++++++++------ target-ppc/op_helper.c | 134 +++++++++++++++++++++++++++++++---------- 2 files changed, 243 insertions(+), 50 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c835b1efe..c541e7128 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -549,8 +549,6 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { /* Software TLB search */ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { - /* XXX: TODO */ } else { #if defined (DEBUG_MMU) if (loglevel > 0) { @@ -632,6 +630,115 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, return ret; } +int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, + uint32_t address, int rw, int access_type) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + target_ulong mask; + int i, ret, zsel, zpr; + + ret = -6; + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb[i].tlbe; + /* Check valid flag */ + if (!(tlb->prot & PAGE_VALID)) { + if (loglevel) + fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); + continue; + } + mask = ~(tlb->size - 1); + if (loglevel) { + fprintf(logfile, "%s: TLB %d address %08x PID %04x <=> " + "%08x %08x %04x\n", + __func__, i, address, env->spr[SPR_40x_PID], + tlb->EPN, mask, tlb->PID); + } + /* Check PID */ + if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) + continue; + /* Check effective address */ + if ((address & mask) != tlb->EPN) + continue; + raddr = (tlb->RPN & mask) | (address & ~mask); + zsel = (tlb->attr >> 4) & 0xF; + zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; + if (loglevel) { + fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", + __func__, i, zsel, zpr, rw, tlb->attr); + } + if (access_type == ACCESS_CODE) { + /* Check execute enable bit */ + switch (zpr) { + case 0x0: + if (msr_pr) { + ret = -3; + ctx->prot = 0; + break; + } + /* No break here */ + case 0x1: + case 0x2: + /* Check from TLB entry */ + if (!(tlb->prot & PAGE_EXEC)) { + ret = -3; + } else { + if (tlb->prot & PAGE_WRITE) + ctx->prot = PAGE_READ | PAGE_WRITE; + else + ctx->prot = PAGE_READ; + ret = 0; + } + break; + case 0x3: + /* All accesses granted */ + ret = 0; + ctx->prot = PAGE_READ | PAGE_WRITE; + break; + } + } else { + switch (zpr) { + case 0x0: + if (msr_pr) { + ret = -2; + ctx->prot = 0; + break; + } + /* No break here */ + case 0x1: + case 0x2: + /* Check from TLB entry */ + /* Check write protection bit */ + if (rw && !(tlb->prot & PAGE_WRITE)) { + ret = -2; + } else { + ret = 2; + if (tlb->prot & PAGE_WRITE) + ctx->prot = PAGE_READ | PAGE_WRITE; + else + ctx->prot = PAGE_READ; + } + break; + case 0x3: + /* All accesses granted */ + ret = 2; + ctx->prot = PAGE_READ | PAGE_WRITE; + break; + } + } + if (ret >= 0) { + ctx->raddr = raddr; + if (loglevel) { + fprintf(logfile, "%s: access granted " ADDRX " => " REGX + " %d\n", __func__, address, ctx->raddr, ctx->prot); + } + return i; + } + } + + return ret; +} + static int check_physical (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw) { @@ -682,13 +789,26 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, /* No address translation */ ret = check_physical(env, ctx, eaddr, rw); } else { - /* Try to find a BAT */ - ret = -1; - if (check_BATs) - ret = get_bat(env, ctx, eaddr, rw, access_type); - if (ret < 0) { - /* We didn't match any BAT entry */ - ret = get_segment(env, ctx, eaddr, rw, access_type); + switch (PPC_MMU(env)) { + case PPC_FLAGS_MMU_32B: + case PPC_FLAGS_MMU_SOFT_6xx: + /* Try to find a BAT */ + ret = -1; + if (check_BATs) + ret = get_bat(env, ctx, eaddr, rw, access_type); + if (ret < 0) { + /* We didn't match any BAT entry */ + ret = get_segment(env, ctx, eaddr, rw, access_type); + } + break; + case PPC_FLAGS_MMU_SOFT_4xx: + ret = mmu4xx_get_physical_address(env, ctx, eaddr, + rw, access_type); + break; + default: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; } } #if 0 @@ -753,7 +873,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, error_code = 1 << 18; goto tlb_miss; } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { - /* XXX: TODO */ + exception = EXCP_40x_ITLBMISS; + error_code = 0; + env->spr[SPR_40x_DEAR] = address; + env->spr[SPR_40x_ESR] = 0x00000000; } else { error_code = 0x40000000; } @@ -799,7 +922,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, /* Do not alter DAR nor DSISR */ goto out; } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { - /* XXX: TODO */ + exception = EXCP_40x_DTLBMISS; + error_code = 0; + env->spr[SPR_40x_DEAR] = address; + if (rw) + env->spr[SPR_40x_ESR] = 0x00800000; + else + env->spr[SPR_40x_ESR] = 0x00000000; } else { error_code = 0x40000000; } @@ -1518,9 +1647,7 @@ void do_interrupt (CPUState *env) switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* DTLBMISS on 4xx */ - /* XXX: TODO */ - cpu_abort(env, - "40x DTLBMISS exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; goto store_next; case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: @@ -1538,9 +1665,7 @@ void do_interrupt (CPUState *env) switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* ITLBMISS on 4xx */ - /* XXX: TODO */ - cpu_abort(env, - "40x ITLBMISS exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; goto store_next; case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index c21a38aea..e1fff7f49 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2365,65 +2365,139 @@ void do_load_6xx_tlb (int is_code) way, is_code, CMP, RPN); } +static target_ulong booke_tlb_to_page_size (int size) +{ + return 1024 << (2 * size); +} + +static int booke_page_size_to_tlb (target_ulong page_size) +{ + int size; + + switch (page_size) { + case 0x00000400UL: + size = 0x0; + break; + case 0x00001000UL: + size = 0x1; + break; + case 0x00004000UL: + size = 0x2; + break; + case 0x00010000UL: + size = 0x3; + break; + case 0x00040000UL: + size = 0x4; + break; + case 0x00100000UL: + size = 0x5; + break; + case 0x00400000UL: + size = 0x6; + break; + case 0x01000000UL: + size = 0x7; + break; + case 0x04000000UL: + size = 0x8; + break; + case 0x10000000UL: + size = 0x9; + break; + case 0x40000000UL: + size = 0xA; + break; +#if defined (TARGET_PPC64) + case 0x000100000000ULL: + size = 0xB; + break; + case 0x000400000000ULL: + size = 0xC; + break; + case 0x001000000000ULL: + size = 0xD; + break; + case 0x004000000000ULL: + size = 0xE; + break; + case 0x010000000000ULL: + size = 0xF; + break; +#endif + default: + size = -1; + break; + } + + return size; +} + /* Helpers for 4xx TLB management */ void do_4xx_tlbia (void) { -#if 0 - ppc_tlb_t *tlb; - target_ulong page, end; + ppcemb_tlb_t *tlb; int i; for (i = 0; i < 64; i++) { - tlb = &env->tlb[i]; + tlb = &env->tlb[i].tlbe; if (tlb->prot & PAGE_VALID) { +#if 0 end = tlb->EPN + tlb->size; for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); +#endif tlb->prot &= ~PAGE_VALID; } } -#endif + tlb_flush(env, 1); } void do_4xx_tlbre_lo (void) { -#if 0 - ppc_tlb_t *tlb; + ppcemb_tlb_t *tlb; + int size; T0 &= 0x3F; - tlb = &env->tlb[T0]; - T0 = tlb->stor[0]; - env->spr[SPR_40x_PID] = tlb->pid; -#endif + tlb = &env->tlb[T0].tlbe; + T0 = tlb->EPN; + if (tlb->prot & PAGE_VALID) + T0 |= 0x400; + size = booke_page_size_to_tlb(tlb->size); + if (size < 0 || size > 0x7) + size = 1; + T0 |= size << 7; + env->spr[SPR_40x_PID] = tlb->PID; } void do_4xx_tlbre_hi (void) { -#if 0 - ppc_tlb_t *tlb; + ppcemb_tlb_t *tlb; T0 &= 0x3F; - tlb = &env->tlb[T0]; - T0 = tlb->stor[1]; -#endif + tlb = &env->tlb[T0].tlbe; + T0 = tlb->RPN; + if (tlb->prot & PAGE_EXEC) + T0 |= 0x200; + if (tlb->prot & PAGE_WRITE) + T0 |= 0x100; } static int tlb_4xx_search (target_ulong virtual) { -#if 0 - ppc_tlb_t *tlb; + ppcemb_tlb_t *tlb; target_ulong base, mask; int i, ret; /* Default return value is no match */ ret = -1; for (i = 0; i < 64; i++) { - tlb = &env->tlb[i]; + tlb = &env->tlb[i].tlbe; /* Check TLB validity */ if (!(tlb->prot & PAGE_VALID)) continue; /* Check TLB PID vs current PID */ - if (tlb->pid != 0 && tlb->pid != env->spr[SPR_40x_PID]) + if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) continue; /* Check TLB address vs virtual address */ base = tlb->EPN; @@ -2435,9 +2509,6 @@ static int tlb_4xx_search (target_ulong virtual) } return ret; -#else - return -1; -#endif } void do_4xx_tlbsx (void) @@ -2457,47 +2528,44 @@ void do_4xx_tlbsx_ (void) void do_4xx_tlbwe_lo (void) { -#if 0 - ppc_tlb_t *tlb; + ppcemb_tlb_t *tlb; target_ulong page, end; T0 &= 0x3F; - tlb = &env->tlb[T0]; + tlb = &env->tlb[T0].tlbe; /* Invalidate previous TLB (if it's valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); } - tlb->size = 1024 << (2 * ((T1 >> 7) & 0x7)); + tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); if (T1 & 0x400) tlb->prot |= PAGE_VALID; else tlb->prot &= ~PAGE_VALID; - tlb->pid = env->spr[SPR_BOOKE_PID]; /* PID */ + tlb->PID = env->spr[SPR_BOOKE_PID]; /* PID */ + tlb->attr = T1 & 0xFF; /* Invalidate new TLB (if valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); } -#endif } void do_4xx_tlbwe_hi (void) { -#if 0 - ppc_tlb_t *tlb; + ppcemb_tlb_t *tlb; T0 &= 0x3F; - tlb = &env->tlb[T0]; + tlb = &env->tlb[T0].tlbe; tlb->RPN = T1 & 0xFFFFFC00; tlb->prot = PAGE_READ; if (T1 & 0x200) tlb->prot |= PAGE_EXEC; if (T1 & 0x100) tlb->prot |= PAGE_WRITE; -#endif } #endif /* !CONFIG_USER_ONLY */ -- cgit v1.2.3 From 636aaad7b5ab72c03451296412249352817167a9 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 31 Mar 2007 11:38:38 +0000 Subject: Embedded PowerPC timers support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2555 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 205 insertions(+), 7 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 04242ac90..273c75f02 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -267,26 +267,224 @@ uint32_t cpu_ppc601_load_rtcl (CPUState *env) return cpu_ppc_load_tbl(env) & 0x3FFFFF80; } +/*****************************************************************************/ /* Embedded PowerPC timers */ -target_ulong load_40x_pit (CPUState *env) + +/* PIT, FIT & WDT */ +typedef struct ppcemb_timer_t ppcemb_timer_t; +struct ppcemb_timer_t { + uint64_t pit_reload; /* PIT auto-reload value */ + uint64_t fit_next; /* Tick for next FIT interrupt */ + struct QEMUTimer *fit_timer; + uint64_t wdt_next; /* Tick for next WDT interrupt */ + struct QEMUTimer *wdt_timer; +}; + +/* Fixed interval timer */ +static void cpu_4xx_fit_cb (void *opaque) { - /* XXX: TODO */ - return 0; + CPUState *env; + ppc_tb_t *tb_env; + ppcemb_timer_t *ppcemb_timer; + uint64_t now, next; + + env = opaque; + tb_env = env->tb_env; + ppcemb_timer = tb_env->opaque; + now = qemu_get_clock(vm_clock); + switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) { + case 0: + next = 1 << 9; + break; + case 1: + next = 1 << 13; + break; + case 2: + next = 1 << 17; + break; + case 3: + next = 1 << 21; + break; + default: + /* Cannot occur, but makes gcc happy */ + return; + } + next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq); + if (next == now) + next++; + qemu_mod_timer(ppcemb_timer->fit_timer, next); + tb_env->decr_next = next; + env->spr[SPR_40x_TSR] |= 1 << 26; + if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) + ppc_set_irq(env, PPC_INTERRUPT_FIT, 1); + if (loglevel) { + fprintf(logfile, "%s: ir %d TCR %08x TSR %08x\n", __func__, + (env->spr[SPR_40x_TCR] >> 23) & 0x1, + env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); + } +} + +/* Programmable interval timer */ +static void cpu_4xx_pit_cb (void *opaque) +{ + CPUState *env; + ppc_tb_t *tb_env; + ppcemb_timer_t *ppcemb_timer; + uint64_t now, next; + + env = opaque; + tb_env = env->tb_env; + ppcemb_timer = tb_env->opaque; + now = qemu_get_clock(vm_clock); + if ((env->spr[SPR_40x_TCR] >> 22) & 0x1) { + /* Auto reload */ + next = now + muldiv64(ppcemb_timer->pit_reload, + ticks_per_sec, tb_env->tb_freq); + if (next == now) + next++; + qemu_mod_timer(tb_env->decr_timer, next); + tb_env->decr_next = next; + } + env->spr[SPR_40x_TSR] |= 1 << 27; + if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) + ppc_set_irq(env, PPC_INTERRUPT_PIT, 1); + if (loglevel) { + fprintf(logfile, "%s: ar %d ir %d TCR %08x TSR %08x %08lx\n", __func__, + (env->spr[SPR_40x_TCR] >> 22) & 0x1, + (env->spr[SPR_40x_TCR] >> 26) & 0x1, + env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], + ppcemb_timer->pit_reload); + } +} + +/* Watchdog timer */ +static void cpu_4xx_wdt_cb (void *opaque) +{ + CPUState *env; + ppc_tb_t *tb_env; + ppcemb_timer_t *ppcemb_timer; + uint64_t now, next; + + env = opaque; + tb_env = env->tb_env; + ppcemb_timer = tb_env->opaque; + now = qemu_get_clock(vm_clock); + switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) { + case 0: + next = 1 << 17; + break; + case 1: + next = 1 << 21; + break; + case 2: + next = 1 << 25; + break; + case 3: + next = 1 << 29; + break; + default: + /* Cannot occur, but makes gcc happy */ + return; + } + next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq); + if (next == now) + next++; + if (loglevel) { + fprintf(logfile, "%s: TCR %08x TSR %08x\n", __func__, + env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); + } + switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { + case 0x0: + case 0x1: + qemu_mod_timer(ppcemb_timer->wdt_timer, next); + ppcemb_timer->wdt_next = next; + env->spr[SPR_40x_TSR] |= 1 << 31; + break; + case 0x2: + qemu_mod_timer(ppcemb_timer->wdt_timer, next); + ppcemb_timer->wdt_next = next; + env->spr[SPR_40x_TSR] |= 1 << 30; + if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) + ppc_set_irq(env, PPC_INTERRUPT_WDT, 1); + break; + case 0x3: + env->spr[SPR_40x_TSR] &= ~0x30000000; + env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000; + switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) { + case 0x0: + /* No reset */ + break; + case 0x1: /* Core reset */ + case 0x2: /* Chip reset */ + case 0x3: /* System reset */ + qemu_system_reset_request(); + return; + } + } } void store_40x_pit (CPUState *env, target_ulong val) { - /* XXX: TODO */ + ppc_tb_t *tb_env; + ppcemb_timer_t *ppcemb_timer; + uint64_t now, next; + + tb_env = env->tb_env; + ppcemb_timer = tb_env->opaque; + if (loglevel) + fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); + ppcemb_timer->pit_reload = val; + if (val == 0) { + /* Stop PIT */ + if (loglevel) + fprintf(logfile, "%s: stop PIT\n", __func__); + qemu_del_timer(tb_env->decr_timer); + } else { + if (loglevel) + fprintf(logfile, "%s: start PIT 0x%08x\n", __func__, val); + now = qemu_get_clock(vm_clock); + next = now + muldiv64(val, ticks_per_sec, tb_env->tb_freq); + if (next == now) + next++; + qemu_mod_timer(tb_env->decr_timer, next); + tb_env->decr_next = next; + } } -void store_booke_tcr (CPUState *env, target_ulong val) +target_ulong load_40x_pit (CPUState *env) { - /* XXX: TODO */ + return cpu_ppc_load_decr(env); } void store_booke_tsr (CPUState *env, target_ulong val) { - /* XXX: TODO */ + env->spr[SPR_40x_TSR] = val & 0xFC000000; +} + +void store_booke_tcr (CPUState *env, target_ulong val) +{ + /* We don't update timers now. Maybe we should... */ + env->spr[SPR_40x_TCR] = val & 0xFF800000; +} + +void ppc_emb_timers_init (CPUState *env) +{ + ppc_tb_t *tb_env; + ppcemb_timer_t *ppcemb_timer; + + tb_env = env->tb_env; + ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t)); + tb_env->opaque = ppcemb_timer; + if (loglevel) + fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); + if (ppcemb_timer != NULL) { + /* We use decr timer for PIT */ + tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env); + ppcemb_timer->fit_timer = + qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env); + ppcemb_timer->wdt_timer = + qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env); + } } #if 0 -- cgit v1.2.3 From c62db10577295ed4dc26fa9acd6e6f30cea7ffd0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 31 Mar 2007 12:57:57 +0000 Subject: Support for PowerPC BookE exception model. No need to requeue timer exceptions. Fix nip saving for 64 bits PowerPC. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2556 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 141 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 92 insertions(+), 49 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c541e7128..1d973dc43 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1340,11 +1340,12 @@ void ppc_store_msr_32 (CPUPPCState *env, uint32_t value) void do_compute_hflags (CPUPPCState *env) { /* Compute current hflags */ - env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) | - (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) | - (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | - (msr_se << MSR_SE) | (msr_be << MSR_BE); + env->hflags = (msr_cm << MSR_CM) | (msr_vr << MSR_VR) | + (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) | + (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | + (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE); #if defined (TARGET_PPC64) + /* No care here: PowerPC 64 MSR_SF means the same as MSR_CM for BookE */ env->hflags |= (msr_sf << (MSR_SF - 32)) | (msr_hv << (MSR_HV - 32)); #endif } @@ -1374,14 +1375,16 @@ static void dump_syscall(CPUState *env) void do_interrupt (CPUState *env) { - target_ulong msr, *srr_0, *srr_1; - int excp; + target_ulong msr, *srr_0, *srr_1, *asrr_0, *asrr_1; + int excp, idx; excp = env->exception_index; msr = do_load_msr(env); /* The default is to use SRR0 & SRR1 to save the exception context */ srr_0 = &env->spr[SPR_SRR0]; srr_1 = &env->spr[SPR_SRR1]; + asrr_0 = NULL; + asrr_1 = NULL; #if defined (DEBUG_EXCEPTIONS) if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { if (loglevel != 0) { @@ -1397,26 +1400,44 @@ void do_interrupt (CPUState *env) env->nip, excp, env->error_code); } msr_pow = 0; + idx = -1; /* Generate informations in save/restore registers */ switch (excp) { /* Generic PowerPC exceptions */ case EXCP_RESET: /* 0x0100 */ - if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) { + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + srr_0 = &env->spr[SPR_40x_SRR2]; + srr_1 = &env->spr[SPR_40x_SRR3]; + break; + case PPC_FLAGS_EXCP_BOOKE: + idx = 0; + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; + break; + default: if (msr_ip) excp += 0xFFC00; excp |= 0xFFC00000; - } else { - srr_0 = &env->spr[SPR_40x_SRR2]; - srr_1 = &env->spr[SPR_40x_SRR3]; + break; } goto store_next; case EXCP_MACHINE_CHECK: /* 0x0200 */ - if (msr_me == 0) { - cpu_abort(env, "Machine check exception while not allowed\n"); - } - if (unlikely(PPC_EXCP(env) == PPC_FLAGS_EXCP_40x)) { + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: srr_0 = &env->spr[SPR_40x_SRR2]; srr_1 = &env->spr[SPR_40x_SRR3]; + break; + case PPC_FLAGS_EXCP_BOOKE: + idx = 1; + srr_0 = &env->spr[SPR_BOOKE_MCSRR0]; + srr_1 = &env->spr[SPR_BOOKE_MCSRR1]; + asrr_0 = &env->spr[SPR_BOOKE_CSRR0]; + asrr_1 = &env->spr[SPR_BOOKE_CSRR1]; + msr_ce = 0; + break; + default: + break; } msr_me = 0; break; @@ -1425,6 +1446,7 @@ void do_interrupt (CPUState *env) /* data location address has been stored * when the fault has been detected */ + idx = 2; msr &= ~0xFFFF0000; #if defined (DEBUG_EXCEPTIONS) if (loglevel) { @@ -1438,6 +1460,7 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_ISI: /* 0x0400 */ /* Store exception cause */ + idx = 3; msr &= ~0xFFFF0000; msr |= env->error_code; #if defined (DEBUG_EXCEPTIONS) @@ -1448,20 +1471,12 @@ void do_interrupt (CPUState *env) #endif goto store_next; case EXCP_EXTERNAL: /* 0x0500 */ - if (msr_ee == 0) { -#if defined (DEBUG_EXCEPTIONS) - if (loglevel > 0) { - fprintf(logfile, "Skipping hardware interrupt\n"); - } -#endif - /* Requeue it */ - env->interrupt_request |= CPU_INTERRUPT_HARD; - return; - } + idx = 4; goto store_next; case EXCP_ALIGN: /* 0x0600 */ if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) { /* Store exception cause */ + idx = 5; /* Get rS/rD and rA from faulting opcode */ env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; @@ -1476,6 +1491,7 @@ void do_interrupt (CPUState *env) } goto store_current; case EXCP_PROGRAM: /* 0x0700 */ + idx = 6; msr &= ~0xFFFF0000; switch (env->error_code & ~0xF) { case EXCP_FP: @@ -1501,6 +1517,7 @@ void do_interrupt (CPUState *env) msr |= 0x00040000; break; case EXCP_TRAP: + idx = 15; msr |= 0x00020000; break; default: @@ -1510,18 +1527,13 @@ void do_interrupt (CPUState *env) msr |= 0x00010000; goto store_current; case EXCP_NO_FP: /* 0x0800 */ + idx = 7; msr &= ~0xFFFF0000; goto store_current; case EXCP_DECR: - if (msr_ee == 0) { -#if 1 - /* Requeue it */ - env->interrupt_request |= CPU_INTERRUPT_TIMER; -#endif - return; - } goto store_next; case EXCP_SYSCALL: /* 0x0C00 */ + idx = 8; /* NOTE: this is a temporary hack to support graphics OSI calls from the MOL driver */ if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && @@ -1557,13 +1569,6 @@ void do_interrupt (CPUState *env) "Instruction segment exception is not implemented yet !\n"); goto store_next; case EXCP_HDECR: /* 0x0980 */ - if (msr_ee == 0) { -#if 1 - /* Requeue it */ - env->interrupt_request |= CPU_INTERRUPT_TIMER; -#endif - return; - } /* XXX: TODO */ cpu_abort(env, "Hypervisor decrementer exception is not implemented " "yet !\n"); @@ -1581,6 +1586,7 @@ void do_interrupt (CPUState *env) } return; case 0x0F20: + idx = 9; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* APU unavailable on 405 */ @@ -1600,11 +1606,13 @@ void do_interrupt (CPUState *env) } return; case 0x1000: + idx = 10; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* PIT on 4xx */ - /* XXX: TODO */ - cpu_abort(env, "40x PIT exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; + if (loglevel != 0) + fprintf(logfile, "PIT exception\n"); goto store_next; case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: @@ -1619,11 +1627,13 @@ void do_interrupt (CPUState *env) } return; case 0x1010: + idx = 11; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* FIT on 4xx */ - /* XXX: TODO */ - cpu_abort(env, "40x FIT exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; + if (loglevel != 0) + fprintf(logfile, "FIT exception\n"); goto store_next; default: cpu_abort(env, "Invalid exception 0x1010 !\n"); @@ -1631,19 +1641,25 @@ void do_interrupt (CPUState *env) } return; case 0x1020: + idx = 12; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* Watchdog on 4xx */ - /* XXX: TODO */ - cpu_abort(env, - "40x watchdog exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; + if (loglevel != 0) + fprintf(logfile, "WDT exception\n"); goto store_next; + case PPC_FLAGS_EXCP_BOOKE: + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; + break; default: cpu_abort(env, "Invalid exception 0x1020 !\n"); break; } return; case 0x1100: + idx = 13; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* DTLBMISS on 4xx */ @@ -1662,6 +1678,7 @@ void do_interrupt (CPUState *env) } return; case 0x1200: + idx = 14; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* ITLBMISS on 4xx */ @@ -1838,6 +1855,10 @@ void do_interrupt (CPUState *env) cpu_abort(env, "601 run mode exception is not implemented yet !\n"); goto store_next; + case PPC_FLAGS_EXCP_BOOKE: + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; + break; default: cpu_abort(env, "Invalid exception 0x1800 !\n"); break; @@ -1852,15 +1873,19 @@ void do_interrupt (CPUState *env) return; store_current: /* save current instruction location */ - *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL; + *srr_0 = env->nip - 4; break; store_next: /* save next instruction location */ - *srr_0 = env->nip & 0xFFFFFFFFULL; + *srr_0 = env->nip; break; } /* Save msr */ *srr_1 = msr; + if (asrr_0 != NULL) + *asrr_0 = *srr_0; + if (asrr_1 != NULL) + *asrr_1 = *srr_1; /* If we disactivated any translation, flush TLBs */ if (msr_ir || msr_dr) { tlb_flush(env, 1); @@ -1877,10 +1902,28 @@ void do_interrupt (CPUState *env) msr_dr = 0; msr_ri = 0; msr_le = msr_ile; - msr_sf = msr_isf; + if (PPC_EXCP(env) == PPC_FLAGS_EXCP_BOOKE) { + msr_cm = msr_icm; + if (idx == -1 || (idx >= 16 && idx < 32)) { + cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n", + excp, excp, idx); + } +#if defined(TARGET_PPC64) + if (msr_cm) + env->nip = (uint64_t)env->spr[SPR_BOOKE_IVPR]; + else +#endif + env->nip = (uint32_t)env->spr[SPR_BOOKE_IVPR]; + if (idx < 16) + env->nip |= env->spr[SPR_BOOKE_IVOR0 + idx]; + else if (idx < 38) + env->nip |= env->spr[SPR_BOOKE_IVOR32 + idx - 32]; + } else { + msr_sf = msr_isf; + env->nip = excp; + } do_compute_hflags(env); /* Jump to handler */ - env->nip = excp; env->exception_index = EXCP_NONE; } -- cgit v1.2.3 From a4bc3afc09b27cca4adfc1500551cc9a36219edf Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 31 Mar 2007 16:54:14 +0000 Subject: Malta CBUS UART support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2557 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_int.c | 2 +- hw/mips_malta.c | 36 ++++++++++++++++++++++++++++++++++-- hw/serial.c | 29 ++++++++++++++++------------- target-mips/exec.h | 2 +- vl.h | 9 ++++++++- 5 files changed, 60 insertions(+), 18 deletions(-) diff --git a/hw/mips_int.c b/hw/mips_int.c index b384b64d2..ed489f1a1 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -27,7 +27,7 @@ void cpu_mips_irq_request(void *opaque, int irq, int level) if (level) { env->CP0_Cause |= 1 << (irq + CP0Ca_IP); } else { - env->CP0_Cause &= ~(1 << (irq +CP0Ca_IP)); + env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP)); } cpu_mips_update_irq(env); } diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 54b813bdf..43592df52 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -55,6 +55,7 @@ typedef struct { uint32_t i2csel; CharDriverState *display; char display_text[9]; + SerialState *uart; } MaltaFPGAState; static PITState *pit; @@ -241,6 +242,18 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) val = s->brk; break; + /* UART Registers */ + case 0x00900: + case 0x00904: + case 0x00908: + case 0x0090c: + case 0x00910: + case 0x00914: + case 0x00918: + case 0x0091c: + val = serial_mm_readl(s->uart, addr); + break; + /* GPOUT Register */ case 0x00a00: val = s->gpout; @@ -341,6 +354,18 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, s->brk = val & 0xff; break; + /* UART Registers */ + case 0x00900: + case 0x00904: + case 0x00908: + case 0x0090c: + case 0x00910: + case 0x00914: + case 0x00918: + case 0x0091c: + serial_mm_writel(s->uart, addr, val); + break; + /* GPOUT Register */ case 0x00a00: s->gpout = val & 0xff; @@ -400,15 +425,17 @@ void malta_fpga_reset(void *opaque) malta_fpga_update_display(s); } -MaltaFPGAState *malta_fpga_init(target_phys_addr_t base) +MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env) { MaltaFPGAState *s; + CharDriverState *uart_chr; int malta; s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState)); malta = cpu_register_io_memory(0, malta_fpga_read, malta_fpga_write, s); + cpu_register_physical_memory(base, 0x100000, malta); s->display = qemu_chr_open("vc"); @@ -422,6 +449,11 @@ MaltaFPGAState *malta_fpga_init(target_phys_addr_t base) qemu_chr_printf(s->display, "+ +\r\n"); qemu_chr_printf(s->display, "+--------+\r\n"); + uart_chr = qemu_chr_open("vc"); + qemu_chr_printf(uart_chr, "CBUS UART\r\n"); + s->uart = serial_mm_init(&cpu_mips_irq_request, env, base, 3, 2, + uart_chr, 0); + malta_fpga_reset(s); qemu_register_reset(malta_fpga_reset, s); @@ -683,7 +715,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, cpu_mips_irqctrl_init(); /* FPGA */ - malta_fpga = malta_fpga_init(0x1f000000LL); + malta_fpga = malta_fpga_init(0x1f000000LL, env); /* Interrupt controller */ isa_pic = pic_init(pic_irq_request, env); diff --git a/hw/serial.c b/hw/serial.c index a88aec17d..ed2a85700 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -371,45 +371,45 @@ SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, } /* Memory mapped interface */ -static uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr) +uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr) { SerialState *s = opaque; return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF; } -static void serial_mm_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) +void serial_mm_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) { SerialState *s = opaque; serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF); } -static uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr) +uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr) { SerialState *s = opaque; return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF; } -static void serial_mm_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) +void serial_mm_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) { SerialState *s = opaque; serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF); } -static uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr) +uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr) { SerialState *s = opaque; return serial_ioport_read(s, (addr - s->base) >> s->it_shift); } -static void serial_mm_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) +void serial_mm_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) { SerialState *s = opaque; @@ -430,7 +430,8 @@ static CPUWriteMemoryFunc *serial_mm_write[] = { SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, target_ulong base, int it_shift, - int irq, CharDriverState *chr) + int irq, CharDriverState *chr, + int ioregister) { SerialState *s; int s_io_memory; @@ -449,9 +450,11 @@ SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, register_savevm("serial", base, 2, serial_save, serial_load, s); - s_io_memory = cpu_register_io_memory(0, serial_mm_read, - serial_mm_write, s); - cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); + if (ioregister) { + s_io_memory = cpu_register_io_memory(0, serial_mm_read, + serial_mm_write, s); + cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); + } s->chr = chr; qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1, serial_event, s); diff --git a/target-mips/exec.h b/target-mips/exec.h index 9816d4246..6b3202741 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -163,7 +163,7 @@ uint32_t cpu_mips_get_random (CPUState *env); uint32_t cpu_mips_get_count (CPUState *env); void cpu_mips_store_count (CPUState *env, uint32_t value); void cpu_mips_store_compare (CPUState *env, uint32_t value); -void cpu_mips_update_irq(CPUState *env); +void cpu_mips_update_irq (CPUState *env); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); diff --git a/vl.h b/vl.h index c216b68a6..061c0bc2d 100644 --- a/vl.h +++ b/vl.h @@ -1035,7 +1035,14 @@ SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, int base, int irq, CharDriverState *chr); SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, target_ulong base, int it_shift, - int irq, CharDriverState *chr); + int irq, CharDriverState *chr, + int ioregister); +uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr); +void serial_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value); +uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr); +void serial_mm_writew (void *opaque, target_phys_addr_t addr, uint32_t value); +uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr); +void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value); /* parallel.c */ -- cgit v1.2.3 From e126cf13ee2b88949409c1c93bcf27413e97b241 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 31 Mar 2007 18:23:26 +0000 Subject: Fix usb hid and mass-storage protocol revision, by Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2558 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hid.c | 2 +- hw/usb-msd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 1c2f4d231..720c4d280 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -46,7 +46,7 @@ typedef struct USBMouseState { static const uint8_t qemu_mouse_dev_descriptor[] = { 0x12, /* u8 bLength; */ 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + 0x00, 0x01, /* u16 bcdUSB; v1.0 */ 0x00, /* u8 bDeviceClass; */ 0x00, /* u8 bDeviceSubClass; */ diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 4530a1cea..251bd64b2 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -66,7 +66,7 @@ struct usb_msd_csw { static const uint8_t qemu_msd_dev_descriptor[] = { 0x12, /* u8 bLength; */ 0x01, /* u8 bDescriptorType; Device */ - 0x10, 0x00, /* u16 bcdUSB; v1.0 */ + 0x00, 0x01, /* u16 bcdUSB; v1.0 */ 0x00, /* u8 bDeviceClass; */ 0x00, /* u8 bDeviceSubClass; */ -- cgit v1.2.3 From 5813427b1ddcd74c39f49563c12f1f4a6dba5cea Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 31 Mar 2007 18:59:32 +0000 Subject: fcntl() remaining fix, by Stuart Anderson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2559 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f79b5e0c7..c3a172b11 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1793,6 +1793,13 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) switch(cmd) { case TARGET_F_GETLK: + lock_user_struct(target_fl, arg, 1); + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswapl(target_fl->l_start); + fl.l_len = tswapl(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + unlock_user_struct(target_fl, arg, 0); ret = fcntl(fd, cmd, &fl); if (ret == 0) { lock_user_struct(target_fl, arg, 0); @@ -1818,6 +1825,13 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) break; case TARGET_F_GETLK64: + lock_user_struct(target_fl64, arg, 1); + fl64.l_type = tswap16(target_fl64->l_type) >> 1; + fl64.l_whence = tswap16(target_fl64->l_whence); + fl64.l_start = tswapl(target_fl64->l_start); + fl64.l_len = tswapl(target_fl64->l_len); + fl64.l_pid = tswap16(target_fl64->l_pid); + unlock_user_struct(target_fl64, arg, 0); ret = fcntl(fd, cmd >> 1, &fl64); if (ret == 0) { lock_user_struct(target_fl64, arg, 0); @@ -3896,6 +3910,26 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, switch(arg2) { case TARGET_F_GETLK64: +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) { + lock_user_struct(target_efl, arg3, 1); + fl.l_type = tswap16(target_efl->l_type); + fl.l_whence = tswap16(target_efl->l_whence); + fl.l_start = tswap64(target_efl->l_start); + fl.l_len = tswap64(target_efl->l_len); + fl.l_pid = tswapl(target_efl->l_pid); + unlock_user_struct(target_efl, arg3, 0); + } else +#endif + { + lock_user_struct(target_fl, arg3, 1); + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswap64(target_fl->l_start); + fl.l_len = tswap64(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + unlock_user_struct(target_fl, arg3, 0); + } ret = get_errno(fcntl(arg1, cmd, &fl)); if (ret == 0) { #ifdef TARGET_ARM -- cgit v1.2.3 From 1e0e6d8be9114ac4f1b9abde5a8852949c242eb5 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 31 Mar 2007 19:10:01 +0000 Subject: Update for binfmt_misc handler, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2560 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-binfmt-conf.sh | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh index bd278d908..cf1445935 100644 --- a/qemu-binfmt-conf.sh +++ b/qemu-binfmt-conf.sh @@ -1,8 +1,13 @@ #!/bin/sh -# enable automatic i386/ARM/SPARC/PPC program execution by the kernel +# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC program execution by the kernel # load the binfmt_misc module -/sbin/modprobe binfmt_misc +if [ ! -d /proc/sys/fs/binfmt_misc ]; then + /sbin/modprobe binfmt_misc +fi +if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then + mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc +fi # probe cpu type cpu=`uname -m` @@ -10,6 +15,12 @@ case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="i386" ;; + m68k) + cpu="m68k" + ;; + mips*) + cpu="mips" + ;; "Power Macintosh"|ppc|ppc64) cpu="ppc" ;; @@ -33,7 +44,12 @@ fi if [ $cpu != "ppc" ] ; then echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register fi +if [ $cpu != "m68k" ] ; then + echo 'Please check cpu value and header information for m68k!' + echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register +fi if [ $cpu != "mips" ] ; then + # FIXME: We could use the other endianness on a MIPS host. echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register fi -- cgit v1.2.3 From 0aeaa8ce4f441fec211794e4380b1eb0948ac9c1 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 31 Mar 2007 19:29:06 +0000 Subject: Don't let sigaction handle SIGKILL/SIGSTOP, by Stuart Anderson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2561 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 8ee5c4b2f..1e29c2c50 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -422,7 +422,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, struct sigaction act1; int host_sig; - if (sig < 1 || sig > TARGET_NSIG) + if (sig < 1 || sig > TARGET_NSIG || sig == SIGKILL || sig == SIGSTOP) return -EINVAL; k = &sigact_table[sig - 1]; #if defined(DEBUG_SIGNAL) -- cgit v1.2.3 From a80274c31bd94f7a345934d2544075a6d183ebac Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 31 Mar 2007 19:41:22 +0000 Subject: Large kernel initrd fix (initial patch by Daniel Jacobowitz). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2562 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index ba9c2d947..7a156eb9f 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -32,9 +32,11 @@ #define LINUX_BOOT_FILENAME "linux_boot.bin" #define KERNEL_LOAD_ADDR 0x00100000 -#define INITRD_LOAD_ADDR 0x00600000 +#define MAX_INITRD_LOAD_ADDR 0x38000000 #define KERNEL_PARAMS_ADDR 0x00090000 #define KERNEL_CMDLINE_ADDR 0x00099000 +/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ +#define ACPI_DATA_SIZE 0x10000 static fdctrl_t *floppy_controller; static RTCState *rtc_state; @@ -452,6 +454,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, char buf[1024]; int ret, linux_boot, initrd_size, i; ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset; + ram_addr_t initrd_offset; int bios_size, isa_bios_size, vga_bios_size; PCIBus *pci_bus; int piix3_devfn = -1; @@ -599,8 +602,28 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, /* load initrd */ initrd_size = 0; + initrd_offset = 0; if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + initrd_size = get_image_size (initrd_filename); + if (initrd_size > 0) { + initrd_offset = (ram_size - initrd_size) & TARGET_PAGE_MASK; + /* Leave space for BIOS ACPI tables. */ + initrd_offset -= ACPI_DATA_SIZE; + /* Avoid the last 64k to avoid 2.2.x kernel bugs. */ + initrd_offset -= 0x10000; + if (initrd_offset > MAX_INITRD_LOAD_ADDR) + initrd_offset = MAX_INITRD_LOAD_ADDR; + + if (initrd_size > ram_size + || initrd_offset < KERNEL_LOAD_ADDR + ret) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_offset); + } if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); @@ -608,7 +631,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } } if (initrd_size > 0) { - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, initrd_offset); stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); } pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, -- cgit v1.2.3 From 678dde1323f864a46730c303223b40c4571c23bb Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 31 Mar 2007 20:28:52 +0000 Subject: Generate double and triple faults, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2563 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 ++ target-i386/cpu.h | 1 + target-i386/helper.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/cpu-exec.c b/cpu-exec.c index d16888662..4916b1af6 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -360,6 +360,8 @@ int cpu_exec(CPUState *env1) env->exception_is_int, env->error_code, env->exception_next_eip, 0); + /* successfully delivered */ + env->old_exception = -1; #elif defined(TARGET_PPC) do_interrupt(env); #elif defined(TARGET_MIPS) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1eb546e56..104f31e2c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -515,6 +515,7 @@ typedef struct CPUX86State { uint32_t smbase; int interrupt_request; int user_mode_only; /* user mode only simulation */ + int old_exception; /* exception in flight */ CPU_COMMON diff --git a/target-i386/helper.c b/target-i386/helper.c index 1d62f6b2e..70370fca2 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1192,6 +1192,40 @@ void do_interrupt(int intno, int is_int, int error_code, } } +/* + * Check nested exceptions and change to double or triple fault if + * needed. It should only be called, if this is not an interrupt. + * Returns the new exception number. + */ +int check_exception(int intno, int *error_code) +{ + char first_contributory = env->old_exception == 0 || + (env->old_exception >= 10 && + env->old_exception <= 13); + char second_contributory = intno == 0 || + (intno >= 10 && intno <= 13); + + if (loglevel & CPU_LOG_INT) + fprintf(logfile, "check_exception old: %x new %x\n", + env->old_exception, intno); + + if (env->old_exception == EXCP08_DBLE) + cpu_abort(env, "triple fault"); + + if ((first_contributory && second_contributory) + || (env->old_exception == EXCP0E_PAGE && + (second_contributory || (intno == EXCP0E_PAGE)))) { + intno = EXCP08_DBLE; + *error_code = 0; + } + + if (second_contributory || (intno == EXCP0E_PAGE) || + (intno == EXCP08_DBLE)) + env->old_exception = intno; + + return intno; +} + /* * Signal an interruption. It is executed in the main CPU loop. * is_int is TRUE if coming from the int instruction. next_eip is the @@ -1201,6 +1235,9 @@ void do_interrupt(int intno, int is_int, int error_code, void raise_interrupt(int intno, int is_int, int error_code, int next_eip_addend) { + if (!is_int) + intno = check_exception(intno, &error_code); + env->exception_index = intno; env->error_code = error_code; env->exception_is_int = is_int; @@ -1211,6 +1248,8 @@ void raise_interrupt(int intno, int is_int, int error_code, /* same as raise_exception_err, but do not restore global registers */ static void raise_exception_err_norestore(int exception_index, int error_code) { + exception_index = check_exception(exception_index, &error_code); + env->exception_index = exception_index; env->error_code = error_code; env->exception_is_int = 0; -- cgit v1.2.3 From fbe4f65b28aa24534afe7669eb3087c1b5657c08 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 1 Apr 2007 11:16:48 +0000 Subject: MIPS64 configurations. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2564 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 4 ++++ Makefile | 2 ++ Makefile.target | 35 ++++++++++++++++++++++++++++------- configure | 18 ++++++++++++++++-- target-mips/op_helper.c | 2 -- 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/.cvsignore b/.cvsignore index ae68e450c..5277a1d7d 100644 --- a/.cvsignore +++ b/.cvsignore @@ -29,6 +29,10 @@ mips-softmmu mipsel-softmmu mips-linux-user mipsel-linux-user +mips64-softmmu +mips64el-softmmu +mips64-linux-user +mips64el-linux-user m68k-linux-user .gdbinit sh4-linux-user diff --git a/Makefile b/Makefile index 9b9a32d0c..60e3ec197 100644 --- a/Makefile +++ b/Makefile @@ -141,6 +141,8 @@ tarbin: $(bindir)/qemu-system-x86_64 \ $(bindir)/qemu-system-mips \ $(bindir)/qemu-system-mipsel \ + $(bindir)/qemu-system-mips64 \ + $(bindir)/qemu-system-mips64el \ $(bindir)/qemu-system-arm \ $(bindir)/qemu-i386 \ $(bindir)/qemu-arm \ diff --git a/Makefile.target b/Makefile.target index b52656434..3d221babb 100644 --- a/Makefile.target +++ b/Makefile.target @@ -4,6 +4,9 @@ TARGET_BASE_ARCH:=$(TARGET_ARCH) ifeq ($(TARGET_ARCH), x86_64) TARGET_BASE_ARCH:=i386 endif +ifeq ($(TARGET_ARCH), mips64) +TARGET_BASE_ARCH:=mips +endif ifeq ($(TARGET_ARCH), ppc64) TARGET_BASE_ARCH:=ppc endif @@ -44,6 +47,11 @@ ifeq ($(TARGET_ARCH),mips) TARGET_ARCH2=mipsel endif endif +ifeq ($(TARGET_ARCH),mips64) + ifneq ($(TARGET_WORDS_BIGENDIAN),yes) + TARGET_ARCH2=mips64el + endif +endif QEMU_USER=qemu-$(TARGET_ARCH2) # system emulator name ifdef CONFIG_SOFTMMU @@ -170,7 +178,19 @@ BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),mips) +ifeq ($(WORDS_BIGENDIAN),yes) +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +else +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld +endif +endif + +ifeq ($(ARCH),mips64) +ifeq ($(WORDS_BIGENDIAN),yes) BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld +else +BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld +endif endif ifeq ($(CONFIG_DARWIN),yes) @@ -258,7 +278,7 @@ ifeq ($(TARGET_BASE_ARCH), ppc) LIBOBJS+= op_helper.o helper.o endif -ifeq ($(TARGET_ARCH), mips) +ifeq ($(TARGET_BASE_ARCH), mips) LIBOBJS+= op_helper.o helper.o endif @@ -295,7 +315,7 @@ endif ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc) LIBOBJS+=ppc-dis.o endif -ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips) +ifeq ($(findstring mips, $(TARGET_BASE_ARCH) $(ARCH)),mips) LIBOBJS+=mips-dis.o endif ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc) @@ -387,7 +407,7 @@ VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o CPPFLAGS += -DHAS_AUDIO endif -ifeq ($(TARGET_ARCH), mips) +ifeq ($(TARGET_BASE_ARCH), mips) VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) @@ -554,10 +574,11 @@ 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 fop_template.c op_mem.c -op_helper.o: op_helper_mem.c -translate.o: translate.c translate_init.c +ifeq ($(TARGET_BASE_ARCH), mips) +helper.o: cpu.h exec-all.h +op.o: op_template.c fop_template.c op_mem.c exec.h +op_helper.o: op_helper_mem.c exec.h softmmu_template.h +translate.o: translate_init.c exec-all.h disas.h endif loader.o: loader.c elf_ops.h diff --git a/configure b/configure index 63f327e91..7754774d6 100755 --- a/configure +++ b/configure @@ -50,6 +50,9 @@ case "$cpu" in mips) cpu="mips" ;; + mips64) + cpu="mips64" + ;; s390) cpu="s390" ;; @@ -418,7 +421,7 @@ 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 ppc64-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then @@ -457,7 +460,7 @@ fi else # if cross compiling, cannot launch a program, so make a static guess -if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then +if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "mips64" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then bigendian="yes" fi @@ -675,6 +678,9 @@ elif test "$cpu" = "powerpc" ; then elif test "$cpu" = "mips" ; then echo "ARCH=mips" >> $config_mak echo "#define HOST_MIPS 1" >> $config_h +elif test "$cpu" = "mips64" ; then + echo "ARCH=mips64" >> $config_mak + echo "#define HOST_MIPS64 1" >> $config_h elif test "$cpu" = "s390" ; then echo "ARCH=s390" >> $config_mak echo "#define HOST_S390 1" >> $config_h @@ -801,6 +807,7 @@ target_bigendian="no" [ "$target_cpu" = "ppc" ] && target_bigendian=yes [ "$target_cpu" = "ppc64" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes +[ "$target_cpu" = "mips64" ] && target_bigendian=yes [ "$target_cpu" = "sh4eb" ] && target_bigendian=yes [ "$target_cpu" = "m68k" ] && target_bigendian=yes target_softmmu="no" @@ -903,6 +910,13 @@ elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then echo "#define TARGET_MIPS 1" >> $config_h echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h +elif test "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el" ; then + echo "TARGET_ARCH=mips64" >> $config_mak + echo "#define TARGET_ARCH \"mips64\"" >> $config_h + echo "#define TARGET_MIPS 1" >> $config_h + echo "#define TARGET_MIPS64 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 diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index f9748fc16..fb70f51e8 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -336,8 +336,6 @@ void do_mtc0_status_irqraise_debug(void) fprintf(logfile, "Raise pending IRQs\n"); } -#include "softfloat.h" - void fpu_handle_exception(void) { #ifdef CONFIG_SOFTFLOAT -- cgit v1.2.3 From 60aa19abefe2dc4d67a273dd0fa3b81810cdf21c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 1 Apr 2007 12:36:18 +0000 Subject: Actually enable 64bit configuration. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2565 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 4 ++-- hw/mips_r4k.c | 4 ++-- target-mips/exec.h | 8 ++++---- target-mips/mips-defs.h | 5 +---- target-mips/op.c | 10 +++++----- target-mips/op_helper.c | 6 +++--- target-mips/op_helper_mem.c | 4 ++-- target-mips/op_mem.c | 4 ++-- target-mips/translate.c | 34 +++++++++++++++++----------------- target-mips/translate_init.c | 2 +- 10 files changed, 39 insertions(+), 42 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 43592df52..e4b43bea9 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -30,7 +30,7 @@ #define BIOS_FILENAME "mipsel_bios.bin" #endif -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 #define INITRD_LOAD_ADDR (int64_t)0x80800000 #else #define INITRD_LOAD_ADDR (int32_t)0x80800000 @@ -662,7 +662,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, /* init CPUs */ if (cpu_model == NULL) { -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 cpu_model = "R4000"; #else cpu_model = "4KEc"; diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 7709418c0..487983e46 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -15,7 +15,7 @@ #define BIOS_FILENAME "mipsel_bios.bin" #endif -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 #define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000 #else #define INITRD_LOAD_ADDR (int32_t)0x80800000 @@ -142,7 +142,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, /* init CPUs */ if (cpu_model == NULL) { -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 cpu_model = "R4000"; #else cpu_model = "4KEc"; diff --git a/target-mips/exec.h b/target-mips/exec.h index 6b3202741..54f4d5a75 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -65,7 +65,7 @@ static inline void regs_to_env(void) { } -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 #if TARGET_LONG_BITS > HOST_LONG_BITS void do_dsll (void); void do_dsll32 (void); @@ -92,7 +92,7 @@ void do_msubu (void); void do_ddiv (void); void do_ddivu (void); #endif -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 void do_dmult (void); void do_dmultu (void); #endif @@ -114,7 +114,7 @@ void do_lwl_raw (uint32_t); void do_lwr_raw (uint32_t); uint32_t do_swl_raw (uint32_t); uint32_t do_swr_raw (uint32_t); -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 void do_ldl_raw (uint64_t); void do_ldr_raw (uint64_t); uint64_t do_sdl_raw (uint64_t); @@ -129,7 +129,7 @@ uint32_t do_swl_user (uint32_t); uint32_t do_swl_kernel (uint32_t); uint32_t do_swr_user (uint32_t); uint32_t do_swr_kernel (uint32_t); -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 void do_ldl_user (uint64_t); void do_ldl_kernel (uint64_t); void do_ldr_user (uint64_t); diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index b59af0fd7..8b29e8b2d 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -6,9 +6,6 @@ /* If we want to use host float regs... */ //#define USE_HOST_FLOAT_REGS -/* 32 bits target */ -#undef MIPS_HAS_MIPS64 -//#define MIPS_HAS_MIPS64 1 /* real pages are variable size... */ #define TARGET_PAGE_BITS 12 /* Uses MIPS R4Kc TLB model */ @@ -16,7 +13,7 @@ #define MIPS_TLB_NB 16 #define MIPS_TLB_MAX 128 -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 #define TARGET_LONG_BITS 64 #else #define TARGET_LONG_BITS 32 diff --git a/target-mips/op.c b/target-mips/op.c index fecf18cc6..db430a7ee 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -386,7 +386,7 @@ void op_divu (void) RETURN(); } -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 /* Arithmetic */ void op_dadd (void) { @@ -464,7 +464,7 @@ void op_ddivu (void) RETURN(); } #endif -#endif /* MIPS_HAS_MIPS64 */ +#endif /* TARGET_MIPS64 */ /* Logical */ void op_and (void) @@ -586,7 +586,7 @@ void op_clz (void) RETURN(); } -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 #if TARGET_LONG_BITS > HOST_LONG_BITS /* Those might call libgcc functions. */ @@ -891,7 +891,7 @@ void op_msubu (void) } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 void op_dmult (void) { CALL_FROM_TB0(do_dmult); @@ -2213,7 +2213,7 @@ void op_wsbh(void) RETURN(); } -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 void op_dext(void) { unsigned int pos = PARAM1; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index fb70f51e8..af3938798 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -79,7 +79,7 @@ void do_raise_exception_direct (uint32_t exception) #undef MEMSUFFIX #endif -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 #if TARGET_LONG_BITS > HOST_LONG_BITS /* Those might call libgcc functions. */ void do_dsll (void) @@ -161,7 +161,7 @@ void do_drotrv (void) T0 = T1; } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#endif /* MIPS_HAS_MIPS64 */ +#endif /* TARGET_MIPS64 */ /* 64 bits arithmetic for 32 bits hosts */ #if TARGET_LONG_BITS > HOST_LONG_BITS @@ -219,7 +219,7 @@ void do_msubu (void) } #endif -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 void do_dmult (void) { /* XXX */ diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index e0030e085..56eeaadd0 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -124,7 +124,7 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) return tmp; } -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 # ifdef TARGET_WORDS_BIGENDIAN #define GET_LMASK64(v) ((v) & 4) @@ -298,4 +298,4 @@ uint64_t glue(do_sdr, MEMSUFFIX) (uint64_t tmp) return tmp; } -#endif /* MIPS_HAS_MIPS64 */ +#endif /* TARGET_MIPS64 */ diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 823cfe809..a1991721a 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -126,7 +126,7 @@ void glue(op_sc, MEMSUFFIX) (void) RETURN(); } -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 void glue(op_ld, MEMSUFFIX) (void) { T0 = glue(ldq, MEMSUFFIX)(T0); @@ -190,7 +190,7 @@ void glue(op_scd, MEMSUFFIX) (void) } RETURN(); } -#endif /* MIPS_HAS_MIPS64 */ +#endif /* TARGET_MIPS64 */ void glue(op_lwc1, MEMSUFFIX) (void) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 65821087b..469f2ec51 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -611,7 +611,7 @@ static GenOpFunc *gen_op_s##width[] = { \ } #endif -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 OP_LD_TABLE(d); OP_LD_TABLE(dl); OP_LD_TABLE(dr); @@ -660,7 +660,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, * memory access */ switch (opc) { -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_LD: op_ldst(ld); GEN_STORE_TN_REG(rt, T0); @@ -872,7 +872,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, gen_op_add(); opn = "addiu"; break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DADDI: save_cpu_state(ctx, 1); gen_op_daddo(); @@ -923,7 +923,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, opn = "srl"; } break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DSLL: gen_op_dsll(); opn = "dsll"; @@ -1003,7 +1003,7 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, gen_op_sub(); opn = "subu"; break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DADD: save_cpu_state(ctx, 1); gen_op_daddo(); @@ -1076,7 +1076,7 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, opn = "srlv"; } break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DSLLV: gen_op_dsllv(); opn = "dsllv"; @@ -1168,7 +1168,7 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, gen_op_multu(); opn = "multu"; break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DDIV: gen_op_ddiv(); opn = "ddiv"; @@ -1229,7 +1229,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, gen_op_clz(); opn = "clz"; break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DCLO: gen_op_dclo(); opn = "dclo"; @@ -4538,7 +4538,7 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) /* MIPS16 extension to MIPS32 */ /* SmartMIPS extension to MIPS32 */ -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 /* Coprocessor 3 (FPU) */ /* MDMX extension to MIPS64 */ @@ -4643,7 +4643,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 /* MIPS64 specific opcodes */ case OPC_DSLL: case OPC_DSRL ... OPC_DSRA: @@ -4690,7 +4690,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } /* Treat as a noop */ break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DCLZ ... OPC_DCLO: gen_cl(ctx, op1, rd, rs); break; @@ -4757,7 +4757,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } GEN_STORE_TN_REG(rt, T0); break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: gen_bitops(ctx, op1, rt, rs, sa, rd); @@ -4812,7 +4812,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) switch (op1) { case OPC_MFC0: case OPC_MTC0: -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DMFC0: case OPC_DMTC0: #endif @@ -4898,7 +4898,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_CFC1: case OPC_MTC1: case OPC_CTC1: -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 case OPC_DMFC1: case OPC_DMTC1: #endif @@ -4948,7 +4948,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; -#ifdef MIPS_HAS_MIPS64 +#ifdef TARGET_MIPS64 /* MIPS64 opcodes */ case OPC_LWU: case OPC_LDL ... OPC_LDR: @@ -5197,7 +5197,7 @@ void dump_fpu (CPUState *env) } } -#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) +#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) /* Debug help: The architecture requires 32bit code to maintain proper sign-extened values on 64bit machines. */ @@ -5255,7 +5255,7 @@ void cpu_dump_state (CPUState *env, FILE *f, env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); if (c0_status & (1 << CP0St_CU1)) fpu_dump_state(env, f, cpu_fprintf, flags); -#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) +#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags); #endif } diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 6aacfb7e0..456a6cd83 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -74,7 +74,7 @@ struct mips_def_t { /* MIPS CPU definitions */ static mips_def_t mips_defs[] = { -#ifndef MIPS_HAS_MIPS64 +#ifndef TARGET_MIPS64 { .name = "4Kc", .CP0_PRid = 0x00018000, -- cgit v1.2.3 From 65fe7b09a5e4018580ebbbcd9db790f1f2136428 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 1 Apr 2007 15:05:09 +0000 Subject: Fix Sparc ASR handling (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2566 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 03466ce87..0d768ce6b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1130,11 +1130,19 @@ static void disas_sparc_insn(DisasContext * dc) rs1 = GET_FIELD(insn, 13, 17); switch(rs1) { case 0: /* rdy */ - gen_op_movtl_T0_env(offsetof(CPUSPARCState, y)); +#ifndef TARGET_SPARC64 + case 0x01 ... 0x0e: /* undefined in the SPARCv8 + manual, rdy on the microSPARC + II */ + case 0x0f: /* stbar in the SPARCv8 manual, + rdy on the microSPARC II */ + case 0x10 ... 0x1f: /* implementation-dependent in the + SPARCv8 manual, rdy on the + microSPARC II */ +#endif + gen_op_movtl_T0_env(offsetof(CPUSPARCState, y)); gen_movl_T0_reg(rd); break; - case 15: /* stbar / V9 membar */ - break; /* no effect? */ #ifdef TARGET_SPARC64 case 0x2: /* V9 rdccr */ gen_op_rdccr(); @@ -1160,6 +1168,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs)); gen_movl_T0_reg(rd); break; + case 0xf: /* V9 membar */ + break; /* no effect */ case 0x13: /* Graphics Status */ if (gen_trap_ifnofpu(dc)) goto jmp_insn; @@ -1879,7 +1889,17 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_xor_T1_T0(); gen_op_movtl_env_T0(offsetof(CPUSPARCState, y)); break; -#ifdef TARGET_SPARC64 +#ifndef TARGET_SPARC64 + case 0x01 ... 0x0f: /* undefined in the + SPARCv8 manual, nop + on the microSPARC + II */ + case 0x10 ... 0x1f: /* implementation-dependent + in the SPARCv8 + manual, nop on the + microSPARC II */ + break; +#else case 0x2: /* V9 wrccr */ gen_op_wrccr(); break; -- cgit v1.2.3 From fcc72045e8f2494a78fc6afc3e51aaa9b5221f75 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 1 Apr 2007 15:08:21 +0000 Subject: Fix Sparc co-processor ops (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2567 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 1 + target-sparc/translate.c | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 499d5cd96..91b4a2608 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -40,6 +40,7 @@ #define TT_TOVF 0x0a #define TT_EXTINT 0x10 #define TT_DIV_ZERO 0x2a +#define TT_NCP_INSN 0x24 #define TT_TRAP 0x80 #else #define TT_TFAULT 0x08 diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 0d768ce6b..65d08147e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1746,7 +1746,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_sra(); gen_movl_T0_reg(rd); #endif - } else if (xop < 0x38) { + } else if (xop < 0x36) { rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ @@ -2162,6 +2162,14 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; } } + } else if (xop == 0x36 || xop == 0x37) { /* CPop1 & CPop2, + V9 impdep1 & + impdep2 */ +#ifdef TARGET_SPARC64 + goto illegal_insn; +#else + goto ncp_insn; +#endif #ifdef TARGET_SPARC64 } else if (xop == 0x39) { /* V9 return */ rs1 = GET_FIELD(insn, 13, 17); @@ -2410,6 +2418,15 @@ static void disas_sparc_insn(DisasContext * dc) break; #ifndef TARGET_SPARC64 + case 0x30: /* ldc */ + case 0x31: /* ldcsr */ + case 0x33: /* lddc */ + case 0x34: /* stc */ + case 0x35: /* stcsr */ + case 0x36: /* stdcq */ + case 0x37: /* stdc */ + goto ncp_insn; + break; /* avoid warnings */ (void) &gen_op_stfa; (void) &gen_op_stdfa; @@ -2618,6 +2635,14 @@ static void disas_sparc_insn(DisasContext * dc) save_state(dc); gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); dc->is_br = 1; + return; +#ifndef TARGET_SPARC64 + ncp_insn: + save_state(dc); + gen_op_exception(TT_NCP_INSN); + dc->is_br = 1; + return; +#endif } static inline int gen_intermediate_code_internal(TranslationBlock * tb, -- cgit v1.2.3 From d4218d996d2274f4136b8bd22e946bf56f050c9e Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 1 Apr 2007 15:15:36 +0000 Subject: Fix Sparc lda/ldda/sta/stda asi handling, fault on misaligned register ldd/std and illegal cwp on wrpsr (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2568 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 2 +- target-sparc/op_helper.c | 8 +++++++- target-sparc/translate.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 91b4a2608..3279cfdea 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -269,7 +269,7 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); env->psrs = (_tmp & PSR_S)? 1 : 0; \ env->psrps = (_tmp & PSR_PS)? 1 : 0; \ env->psret = (_tmp & PSR_ET)? 1 : 0; \ - cpu_set_cwp(env, _tmp & PSR_CWP & (NWINDOWS - 1)); \ + cpu_set_cwp(env, _tmp & PSR_CWP); \ } while (0) #ifdef TARGET_SPARC64 diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 0b1d5669a..8a9b7bb3c 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -615,6 +615,9 @@ void helper_rett() { unsigned int cwp; + if (env->psret == 1) + raise_exception(TT_ILL_INSN); + env->psret = 1; cwp = (env->cwp + 1) & (NWINDOWS - 1); if (env->wim & (1 << cwp)) { @@ -655,7 +658,10 @@ void helper_debug() #ifndef TARGET_SPARC64 void do_wrpsr() { - PUT_PSR(env, T0); + if ((T0 & PSR_CWP) >= NWINDOWS) + raise_exception(TT_ILL_INSN); + else + PUT_PSR(env, T0); } void do_rdpsr() diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 65d08147e..50d0875d1 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2341,6 +2341,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(lduh); break; case 0x3: /* load double word */ + if (rd & 1) + goto illegal_insn; gen_op_ldst(ldd); gen_movl_T0_reg(rd + 1); break; @@ -2360,6 +2362,8 @@ static void disas_sparc_insn(DisasContext * dc) #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) case 0x10: /* load word alternate */ #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2367,6 +2371,8 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x11: /* load unsigned byte alternate */ #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2374,6 +2380,8 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x12: /* load unsigned halfword alternate */ #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2381,14 +2389,20 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x13: /* load double word alternate */ #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif + if (rd & 1) + goto illegal_insn; gen_op_ldda(insn, 1, 8, 0); gen_movl_T0_reg(rd + 1); break; case 0x19: /* load signed byte alternate */ #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2396,6 +2410,8 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x1a: /* load signed halfword alternate */ #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2403,6 +2419,8 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x1d: /* ldstuba -- XXX: should be atomically */ #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2410,6 +2428,8 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x1f: /* swap reg with alt. memory. Also atomically */ #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2508,6 +2528,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(sth); break; case 0x7: + if (rd & 1) + goto illegal_insn; flush_T2(dc); gen_movl_reg_T2(rd + 1); gen_op_ldst(std); @@ -2515,6 +2537,8 @@ static void disas_sparc_insn(DisasContext * dc) #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) case 0x14: #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2522,6 +2546,8 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x15: #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2529,6 +2555,8 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x16: #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif @@ -2536,9 +2564,13 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x17: #ifndef TARGET_SPARC64 + if (IS_IMM) + goto illegal_insn; if (!supervisor(dc)) goto priv_insn; #endif + if (rd & 1) + goto illegal_insn; flush_T2(dc); gen_movl_reg_T2(rd + 1); gen_op_stda(insn, 0, 8, 0); -- cgit v1.2.3 From 8a08f9a809f8613bb7d6c3e9389812f1b043c846 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 1 Apr 2007 15:38:17 +0000 Subject: Fix Sparc shift ops (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2569 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 19 ++++++++++++------- target-sparc/translate.c | 7 +++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 5c6e5391d..2c8949048 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -965,38 +965,43 @@ void OPPROTO op_logic_T0_cc(void) void OPPROTO op_sll(void) { - T0 <<= T1; + T0 <<= (T1 & 0x1f); } #ifdef TARGET_SPARC64 +void OPPROTO op_sllx(void) +{ + T0 <<= (T1 & 0x3f); +} + void OPPROTO op_srl(void) { - T0 = (T0 & 0xffffffff) >> T1; + T0 = (T0 & 0xffffffff) >> (T1 & 0x1f); } void OPPROTO op_srlx(void) { - T0 >>= T1; + T0 >>= (T1 & 0x3f); } void OPPROTO op_sra(void) { - T0 = ((int32_t) (T0 & 0xffffffff)) >> T1; + T0 = ((int32_t) (T0 & 0xffffffff)) >> (T1 & 0x1f); } void OPPROTO op_srax(void) { - T0 = ((int64_t) T0) >> T1; + T0 = ((int64_t) T0) >> (T1 & 0x3f); } #else void OPPROTO op_srl(void) { - T0 >>= T1; + T0 >>= (T1 & 0x1f); } void OPPROTO op_sra(void) { - T0 = ((int32_t) T0) >> T1; + T0 = ((int32_t) T0) >> (T1 & 0x1f); } #endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 50d0875d1..70cf1bcdb 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1703,7 +1703,7 @@ static void disas_sparc_insn(DisasContext * dc) } #endif #ifdef TARGET_SPARC64 - } else if (xop == 0x25) { /* sll, V9 sllx ( == sll) */ + } else if (xop == 0x25) { /* sll, V9 sllx */ rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ @@ -1713,7 +1713,10 @@ static void disas_sparc_insn(DisasContext * dc) rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); } - gen_op_sll(); + if (insn & (1 << 12)) + gen_op_sllx(); + else + gen_op_sll(); gen_movl_T0_reg(rd); } else if (xop == 0x26) { /* srl, V9 srlx */ rs1 = GET_FIELD(insn, 13, 17); -- cgit v1.2.3 From 36cd921035c1469f8d953c47132925ac5da7f02e Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 1 Apr 2007 15:44:43 +0000 Subject: Reorganise Sun4m to allow other machine types git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2570 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 193 ++++++++++++++++++++++++++++++++++++++++++------------------- vl.c | 2 +- vl.h | 4 +- 3 files changed, 135 insertions(+), 64 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index bc49c73c6..a1091a21a 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -23,43 +23,44 @@ */ #include "vl.h" +/* + * Sun4m architecture was used in the following machines: + * + * SPARCserver 6xxMP/xx + * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), SPARCclassic X (4/10) + * SPARCstation LX/ZX (4/30) + * SPARCstation Voyager + * SPARCstation 10/xx, SPARCserver 10/xx + * SPARCstation 5, SPARCserver 5 + * SPARCstation 20/xx, SPARCserver 20 + * SPARCstation 4 + * + * See for example: http://www.sunhelp.org/faq/sunref1.html + */ + #define KERNEL_LOAD_ADDR 0x00004000 #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 #define PROM_SIZE_MAX (256 * 1024) #define PROM_ADDR 0xffd00000 #define PROM_FILENAME "openbios-sparc32" -#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ -#define PHYS_JJ_IDPROM_OFF 0x1FD8 -#define PHYS_JJ_EEPROM_SIZE 0x2000 -// IRQs are not PIL ones, but master interrupt controller register -// bits -#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ -#define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */ -#define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */ -#define PHYS_JJ_DMA 0x78400000 /* DMA controller */ -#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ -#define PHYS_JJ_ESP_IRQ 18 -#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */ -#define PHYS_JJ_LE_IRQ 16 -#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */ -#define PHYS_JJ_CLOCK_IRQ 7 -#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */ -#define PHYS_JJ_CLOCK1_IRQ 19 -#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */ -#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ -#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */ -#define PHYS_JJ_MS_KBD_IRQ 14 -#define PHYS_JJ_SER 0x71100000 /* Serial */ -#define PHYS_JJ_SER_IRQ 15 -#define PHYS_JJ_FDC 0x71400000 /* Floppy */ -#define PHYS_JJ_FLOPPY_IRQ 22 -#define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */ -#define PHYS_JJ_CS 0x6c000000 /* Crystal CS4231 */ -#define PHYS_JJ_CS_IRQ 5 #define MAX_CPUS 16 +struct hwdef { + target_ulong iommu_base, slavio_base; + target_ulong intctl_base, counter_base, nvram_base, ms_kb_base, serial_base; + target_ulong fd_base; + target_ulong dma_base, esp_base, le_base; + target_ulong tcx_base, cs_base; + long vram_size, nvram_size; + // IRQ numbers are not PIL ones, but master interrupt controller register + // bit numbers + int intctl_g_intr, esp_irq, le_irq, cpu_irq, clock_irq, clock1_irq; + int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq; + int machine_id; // For NVRAM +}; + /* TSC handling */ uint64_t cpu_get_tsc() @@ -122,7 +123,8 @@ extern int nographic; static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, int boot_device, uint32_t RAM_size, uint32_t kernel_size, - int width, int height, int depth) + int width, int height, int depth, + int machine_id) { unsigned char tmp = 0; int i, j; @@ -151,7 +153,7 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, // Sun4m specific use i = 0x1fd8; m48t59_write(nvram, i++, 0x01); - m48t59_write(nvram, i++, 0x80); /* Sun4m OBP */ + m48t59_write(nvram, i++, machine_id); j = 0; m48t59_write(nvram, i++, macaddr[j++]); m48t59_write(nvram, i++, macaddr[j++]); @@ -207,25 +209,16 @@ static void main_cpu_reset(void *opaque) cpu_reset(env); } -/* Sun4m hardware initialisation */ -static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, + DisplayState *ds, const char *cpu_model) + { CPUState *env, *envs[MAX_CPUS]; - char buf[1024]; - int ret, linux_boot; unsigned int i; - long vram_size = 0x100000, prom_offset, initrd_size, kernel_size; void *iommu, *dma, *main_esp, *main_lance = NULL; const sparc_def_t *def; - linux_boot = (kernel_filename != NULL); - /* init CPUs */ - if (cpu_model == NULL) - cpu_model = "Fujitsu MB86904"; sparc_find_by_name(cpu_model, &def); if (def == NULL) { fprintf(stderr, "Unable to find Sparc CPU definition\n"); @@ -243,34 +236,40 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); - iommu = iommu_init(PHYS_JJ_IOMMU); - slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); + iommu = iommu_init(hwdef->iommu_base); + slavio_intctl = slavio_intctl_init(hwdef->intctl_base, + hwdef->intctl_base + 0x10000); for(i = 0; i < smp_cpus; i++) { slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } - dma = sparc32_dma_init(PHYS_JJ_DMA, PHYS_JJ_ESP_IRQ, PHYS_JJ_LE_IRQ, iommu, slavio_intctl); + dma = sparc32_dma_init(hwdef->dma_base, hwdef->esp_irq, + hwdef->le_irq, iommu, slavio_intctl); - tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); + tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size, + hwdef->vram_size, graphic_width, graphic_height); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { - main_lance = lance_init(&nd_table[0], PHYS_JJ_LE, dma); + main_lance = lance_init(&nd_table[0], hwdef->le_base, dma); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); } } - nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8); + nvram = m48t59_init(0, hwdef->nvram_base, 0, hwdef->nvram_size, 8); for (i = 0; i < MAX_CPUS; i++) { - slavio_timer_init(PHYS_JJ_CLOCK + i * TARGET_PAGE_SIZE, PHYS_JJ_CLOCK_IRQ, 0, i); + slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE, + hwdef->clock_irq, 0, i); } - slavio_timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ, 2, (unsigned int)-1); - slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); + slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2, + (unsigned int)-1); + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, hwdef->ms_kb_irq); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device - slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); - fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); - main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma); + slavio_serial_init(hwdef->serial_base, hwdef->ser_irq, + serial_hds[1], serial_hds[0]); + fdctrl_init(hwdef->fd_irq, 0, 1, hwdef->fd_base, fd_table); + main_esp = esp_init(bs_table, hwdef->esp_base, dma); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { @@ -278,9 +277,23 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, } } - slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); - cs_init(PHYS_JJ_CS, PHYS_JJ_CS_IRQ, slavio_intctl); + slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->me_irq); + cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); +} + +static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + int machine_id) +{ + int ret, linux_boot; + char buf[1024]; + unsigned int i; + long prom_offset, initrd_size, kernel_size; + + linux_boot = (kernel_filename != NULL); prom_offset = ram_size + vram_size; cpu_register_physical_memory(PROM_ADDR, @@ -329,11 +342,69 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, } } } - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth); + nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, + boot_device, ram_size, kernel_size, graphic_width, + graphic_height, graphic_depth, machine_id); +} + +static const struct hwdef hwdefs[] = { + /* SS-5 */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, + .cs_base = 0x6c000000, + .slavio_base = 0x71000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .vram_size = 0x00100000, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, + .cs_irq = 5, + .machine_id = 0x80, + }, +}; + +static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model, + unsigned int machine) +{ + sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model); + + sun4m_load_kernel(hwdefs[machine].vram_size, ram_size, boot_device, + kernel_filename, kernel_cmdline, initrd_filename, + hwdefs[machine].machine_id); +} + +/* SPARCstation 5 hardware initialisation */ +static void ss5_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + if (cpu_model == NULL) + cpu_model = "Fujitsu MB86904"; + sun4m_common_init(ram_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, + 0); } -QEMUMachine sun4m_machine = { - "sun4m", - "Sun4m platform", - sun4m_init, +QEMUMachine ss5_machine = { + "SS-5", + "Sun4m platform, SPARCstation 5", + ss5_init, }; diff --git a/vl.c b/vl.c index af8558b79..9b071b1ac 100644 --- a/vl.c +++ b/vl.c @@ -6690,7 +6690,7 @@ void register_machines(void) #ifdef TARGET_SPARC64 qemu_register_machine(&sun4u_machine); #else - qemu_register_machine(&sun4m_machine); + qemu_register_machine(&ss5_machine); #endif #elif defined(TARGET_ARM) qemu_register_machine(&integratorcp_machine); diff --git a/vl.h b/vl.h index 061c0bc2d..336673624 100644 --- a/vl.h +++ b/vl.h @@ -1143,7 +1143,7 @@ extern CPUReadMemoryFunc *PPC_io_read[]; void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ -extern QEMUMachine sun4m_machine; +extern QEMUMachine ss5_machine; void pic_set_irq_cpu(int irq, int level, unsigned int cpu); /* iommu.c */ @@ -1169,7 +1169,7 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, unsigned long vram_offset, int vram_size, int width, int height); /* slavio_intctl.c */ -void *slavio_intctl_init(); +void *slavio_intctl_init(uint32_t addr, uint32_t addrg); void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); void slavio_pic_info(void *opaque); void slavio_irq_info(void *opaque); -- cgit v1.2.3 From e0353fe250eacac23104ff7fe466cd6533536509 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 1 Apr 2007 15:55:28 +0000 Subject: Add SparcStation-10 machine git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2571 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 18 +++++++-------- hw/sun4m.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++- target-sparc/translate.c | 7 ++++++ vl.c | 1 + vl.h | 5 ++-- 5 files changed, 78 insertions(+), 13 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 456d9672e..6a2986082 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -54,6 +54,7 @@ typedef struct SLAVIO_INTCTLState { uint64_t irq_count[32]; #endif CPUState *cpu_envs[MAX_CPUS]; + const uint32_t *intbit_to_level; } SLAVIO_INTCTLState; #define INTCTL_MAXADDR 0xf @@ -208,11 +209,6 @@ void slavio_irq_info(void *opaque) #endif } -static const uint32_t intbit_to_level[32] = { - 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, - 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, -}; - static void slavio_check_interrupts(void *opaque) { CPUState *env; @@ -225,8 +221,8 @@ static void slavio_check_interrupts(void *opaque) if (pending && !(s->intregm_disabled & 0x80000000)) { for (i = 0; i < 32; i++) { if (pending & (1 << i)) { - if (max < intbit_to_level[i]) - max = intbit_to_level[i]; + if (max < s->intbit_to_level[i]) + max = s->intbit_to_level[i]; } } env = s->cpu_envs[s->target_cpu]; @@ -288,7 +284,7 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level); if (irq < 32) { uint32_t mask = 1 << irq; - uint32_t pil = intbit_to_level[irq]; + uint32_t pil = s->intbit_to_level[irq]; if (pil > 0) { if (level) { s->intregm_pending |= mask; @@ -313,7 +309,7 @@ void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu) return; } if (irq < 32) { - uint32_t pil = intbit_to_level[irq]; + uint32_t pil = s->intbit_to_level[irq]; if (pil > 0) { if (level) { s->intreg_pending[cpu] |= 1 << pil; @@ -375,7 +371,8 @@ void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env) s->cpu_envs[cpu] = env; } -void *slavio_intctl_init(uint32_t addr, uint32_t addrg) +void *slavio_intctl_init(uint32_t addr, uint32_t addrg, + const uint32_t *intbit_to_level) { int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; SLAVIO_INTCTLState *s; @@ -384,6 +381,7 @@ void *slavio_intctl_init(uint32_t addr, uint32_t addrg) if (!s) return NULL; + s->intbit_to_level = intbit_to_level; for (i = 0; i < MAX_CPUS; i++) { slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory); diff --git a/hw/sun4m.c b/hw/sun4m.c index a1091a21a..5150af4ca 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -59,6 +59,7 @@ struct hwdef { int intctl_g_intr, esp_irq, le_irq, cpu_irq, clock_irq, clock1_irq; int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq; int machine_id; // For NVRAM + uint32_t intbit_to_level[32]; }; /* TSC handling */ @@ -238,7 +239,8 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, iommu = iommu_init(hwdef->iommu_base); slavio_intctl = slavio_intctl_init(hwdef->intctl_base, - hwdef->intctl_base + 0x10000); + hwdef->intctl_base + 0x10000, + &hwdef->intbit_to_level[0]); for(i = 0; i < smp_cpus; i++) { slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } @@ -375,6 +377,43 @@ static const struct hwdef hwdefs[] = { .me_irq = 30, .cs_irq = 5, .machine_id = 0x80, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, + }, + /* SS-10 */ + /* XXX: Replace with real values */ + { + .iommu_base = 0x10000000, + .tcx_base = 0x50000000, + .cs_base = 0x6c000000, + .slavio_base = 0x71000000, + .ms_kb_base = 0x71000000, + .serial_base = 0x71100000, + .nvram_base = 0x71200000, + .fd_base = 0x71400000, + .counter_base = 0x71d00000, + .intctl_base = 0x71e00000, + .dma_base = 0x78400000, + .esp_base = 0x78800000, + .le_base = 0x78c00000, + .vram_size = 0x00100000, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, + .cs_irq = 5, + .machine_id = 0x73, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, }, }; @@ -403,8 +442,27 @@ static void ss5_init(int ram_size, int vga_ram_size, int boot_device, 0); } +/* SPARCstation 10 hardware initialisation */ +static void ss10_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + if (cpu_model == NULL) + cpu_model = "TI SuperSparc II"; + sun4m_common_init(ram_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, + 1); +} + QEMUMachine ss5_machine = { "SS-5", "Sun4m platform, SPARCstation 5", ss5_init, }; + +QEMUMachine ss10_machine = { + "SS-10", + "Sun4m platform, SPARCstation 10", + ss10_init, +}; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 70cf1bcdb..c5cb2d0d4 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2874,6 +2874,13 @@ static const sparc_def_t sparc_defs[] = { .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */ }, + { + /* XXX: Replace with real values */ + .name = "TI SuperSparc II", + .iu_version = 0x40000000, + .fpu_version = 0x00000000, + .mmu_version = 0x00000000, + }, #endif }; diff --git a/vl.c b/vl.c index 9b071b1ac..eee74d6a8 100644 --- a/vl.c +++ b/vl.c @@ -6691,6 +6691,7 @@ void register_machines(void) qemu_register_machine(&sun4u_machine); #else qemu_register_machine(&ss5_machine); + qemu_register_machine(&ss10_machine); #endif #elif defined(TARGET_ARM) qemu_register_machine(&integratorcp_machine); diff --git a/vl.h b/vl.h index 336673624..76fbeee30 100644 --- a/vl.h +++ b/vl.h @@ -1143,7 +1143,7 @@ extern CPUReadMemoryFunc *PPC_io_read[]; void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ -extern QEMUMachine ss5_machine; +extern QEMUMachine ss5_machine, ss10_machine; void pic_set_irq_cpu(int irq, int level, unsigned int cpu); /* iommu.c */ @@ -1169,7 +1169,8 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, unsigned long vram_offset, int vram_size, int width, int height); /* slavio_intctl.c */ -void *slavio_intctl_init(uint32_t addr, uint32_t addrg); +void *slavio_intctl_init(uint32_t addr, uint32_t addrg, + const uint32_t *intbit_to_level); void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); void slavio_pic_info(void *opaque); void slavio_irq_info(void *opaque); -- cgit v1.2.3 From 52cc07d04774676c69e3998cdb5d10c8f5286072 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 1 Apr 2007 16:05:41 +0000 Subject: Change Sparc uses of pic_set_irq to pic_set_irq_new git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2572 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 6 +++--- hw/slavio_misc.c | 11 ++++++++--- hw/slavio_serial.c | 15 ++++++++++----- hw/slavio_timer.c | 12 +++++++++--- hw/sun4m.c | 24 ++++++++---------------- vl.h | 12 +++++++----- 6 files changed, 45 insertions(+), 35 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 6a2986082..ed145a3e1 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -277,7 +277,7 @@ static void slavio_check_interrupts(void *opaque) * "irq" here is the bit number in the system interrupt register to * separate serial and keyboard interrupts sharing a level. */ -void slavio_pic_set_irq(void *opaque, int irq, int level) +void pic_set_irq_new(void *opaque, int irq, int level) { SLAVIO_INTCTLState *s = opaque; @@ -299,13 +299,13 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) } } -void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu) +void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu) { SLAVIO_INTCTLState *s = opaque; DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level); if (cpu == (unsigned int)-1) { - slavio_pic_set_irq(opaque, irq, level); + pic_set_irq_new(opaque, irq, level); return; } if (irq < 32) { diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index a48a7af5c..1f4128e3f 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -36,6 +36,9 @@ #ifdef DEBUG_MISC #define MISC_DPRINTF(fmt, args...) \ do { printf("MISC: " fmt , ##args); } while (0) +#define pic_set_irq_new(intctl, irq, level) \ + do { printf("MISC: set_irq(%d): %d\n", (irq), (level)); \ + pic_set_irq_new((intctl), (irq),(level));} while (0) #else #define MISC_DPRINTF(fmt, args...) #endif @@ -45,6 +48,7 @@ typedef struct MiscState { uint8_t config; uint8_t aux1, aux2; uint8_t diag, mctrl, sysctrl; + void *intctl; } MiscState; #define MISC_MAXADDR 1 @@ -54,9 +58,9 @@ static void slavio_misc_update_irq(void *opaque) MiscState *s = opaque; if ((s->aux2 & 0x4) && (s->config & 0x8)) { - pic_set_irq(s->irq, 1); + pic_set_irq_new(s->intctl, s->irq, 1); } else { - pic_set_irq(s->irq, 0); + pic_set_irq_new(s->intctl, s->irq, 0); } } @@ -207,7 +211,7 @@ static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void *slavio_misc_init(uint32_t base, int irq) +void *slavio_misc_init(uint32_t base, int irq, void *intctl) { int slavio_misc_io_memory; MiscState *s; @@ -233,6 +237,7 @@ void *slavio_misc_init(uint32_t base, int irq) cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory); s->irq = irq; + s->intctl = intctl; register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s); qemu_register_reset(slavio_misc_reset, s); diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index e72bb70e0..847710e3d 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -52,8 +52,9 @@ #ifdef DEBUG_SERIAL #define SER_DPRINTF(fmt, args...) \ do { printf("SER: " fmt , ##args); } while (0) -#define pic_set_irq(irq, level) \ -do { printf("SER: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0) +#define pic_set_irq_new(intctl, irq, level) \ + do { printf("SER: set_irq(%d): %d\n", (irq), (level)); \ + pic_set_irq_new((intctl), (irq),(level));} while (0) #else #define SER_DPRINTF(fmt, args...) #endif @@ -97,6 +98,7 @@ typedef struct ChannelState { uint8_t rx, tx, wregs[16], rregs[16]; SERIOQueue queue; CharDriverState *chr; + void *intctl; } ChannelState; struct SerialState { @@ -164,7 +166,7 @@ static void slavio_serial_update_irq(ChannelState *s) irq = slavio_serial_update_irq_chn(s); irq |= slavio_serial_update_irq_chn(s->otherchn); - pic_set_irq(s->irq, irq); + pic_set_irq_new(s->intctl, s->irq, irq); } static void slavio_serial_reset_chn(ChannelState *s) @@ -545,7 +547,8 @@ static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) } -SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2) +SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, + CharDriverState *chr2, void *intctl) { int slavio_serial_io_memory, i; SerialState *s; @@ -564,6 +567,7 @@ SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDr s->chn[i].irq = irq; s->chn[i].chn = 1 - i; s->chn[i].type = ser; + s->chn[i].intctl = intctl; if (s->chn[i].chr) { qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, serial_receive1, serial_event, &s->chn[i]); @@ -661,7 +665,7 @@ static void sunmouse_event(void *opaque, put_queue(s, 0); } -void slavio_serial_ms_kbd_init(int base, int irq) +void slavio_serial_ms_kbd_init(int base, int irq, void *intctl) { int slavio_serial_io_memory, i; SerialState *s; @@ -673,6 +677,7 @@ void slavio_serial_ms_kbd_init(int base, int irq) s->chn[i].irq = irq; s->chn[i].chn = 1 - i; s->chn[i].chr = NULL; + s->chn[i].intctl = intctl; } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 828d340b3..59fe6832f 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -28,6 +28,9 @@ #ifdef DEBUG_TIMER #define DPRINTF(fmt, args...) \ do { printf("TIMER: " fmt , ##args); } while (0) +#define pic_set_irq_new(intctl, irq, level) \ + do { printf("TIMER: set_irq(%d): %d\n", (irq), (level)); \ + pic_set_irq_new((intctl), (irq),(level));} while (0) #else #define DPRINTF(fmt, args...) #endif @@ -57,6 +60,7 @@ typedef struct SLAVIO_TIMERState { int reached, stopped; int mode; // 0 = processor, 1 = user, 2 = system unsigned int cpu; + void *intctl; } SLAVIO_TIMERState; #define TIMER_MAXADDR 0x1f @@ -103,7 +107,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); if (s->mode != 1) - pic_set_irq_cpu(s->irq, out, s->cpu); + pic_set_irq_cpu(s->intctl, s->irq, out, s->cpu); } // timer callback @@ -130,7 +134,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) // part of counter (user mode) if (s->mode != 1) { // clear irq - pic_set_irq_cpu(s->irq, 0, s->cpu); + pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu); s->reached = 0; return s->limit; } @@ -265,7 +269,8 @@ static void slavio_timer_reset(void *opaque) slavio_timer_get_out(s); } -void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu) +void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu, + void *intctl) { int slavio_timer_io_memory; SLAVIO_TIMERState *s; @@ -277,6 +282,7 @@ void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu) s->mode = mode; s->cpu = cpu; s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); + s->intctl = intctl; slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, slavio_timer_mem_write, s); diff --git a/hw/sun4m.c b/hw/sun4m.c index 5150af4ca..a23baee17 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -184,17 +184,7 @@ void irq_info() void pic_set_irq(int irq, int level) { - slavio_pic_set_irq(slavio_intctl, irq, level); -} - -void pic_set_irq_new(void *opaque, int irq, int level) -{ - pic_set_irq(irq, level); -} - -void pic_set_irq_cpu(int irq, int level, unsigned int cpu) -{ - slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); + pic_set_irq_new(slavio_intctl, irq, level); } static void *slavio_misc; @@ -261,15 +251,16 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, nvram = m48t59_init(0, hwdef->nvram_base, 0, hwdef->nvram_size, 8); for (i = 0; i < MAX_CPUS; i++) { slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE, - hwdef->clock_irq, 0, i); + hwdef->clock_irq, 0, i, slavio_intctl); } slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2, - (unsigned int)-1); - slavio_serial_ms_kbd_init(hwdef->ms_kb_base, hwdef->ms_kb_irq); + (unsigned int)-1, slavio_intctl); + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, hwdef->ms_kb_irq, + slavio_intctl); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device slavio_serial_init(hwdef->serial_base, hwdef->ser_irq, - serial_hds[1], serial_hds[0]); + serial_hds[1], serial_hds[0], slavio_intctl); fdctrl_init(hwdef->fd_irq, 0, 1, hwdef->fd_base, fd_table); main_esp = esp_init(bs_table, hwdef->esp_base, dma); @@ -279,7 +270,8 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, } } - slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->me_irq); + slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->me_irq, + slavio_intctl); cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); } diff --git a/vl.h b/vl.h index 76fbeee30..be24d72a4 100644 --- a/vl.h +++ b/vl.h @@ -1144,7 +1144,6 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ extern QEMUMachine ss5_machine, ss10_machine; -void pic_set_irq_cpu(int irq, int level, unsigned int cpu); /* iommu.c */ void *iommu_init(uint32_t addr); @@ -1169,6 +1168,7 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, unsigned long vram_offset, int vram_size, int width, int height); /* slavio_intctl.c */ +void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); void *slavio_intctl_init(uint32_t addr, uint32_t addrg, const uint32_t *intbit_to_level); void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); @@ -1185,14 +1185,16 @@ int load_aout(const char *filename, uint8_t *addr); int load_uboot(const char *filename, target_ulong *ep, int *is_linux); /* slavio_timer.c */ -void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu); +void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu, + void *intctl); /* slavio_serial.c */ -SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2); -void slavio_serial_ms_kbd_init(int base, int irq); +SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, + CharDriverState *chr2, void *intctl); +void slavio_serial_ms_kbd_init(int base, int irq, void *intctl); /* slavio_misc.c */ -void *slavio_misc_init(uint32_t base, int irq); +void *slavio_misc_init(uint32_t base, int irq, void *intctl); void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ -- cgit v1.2.3 From 4f14e88c5991877085b1090508ee222d6f3ef088 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 1 Apr 2007 16:23:36 +0000 Subject: Fix off-by-one error git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2573 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index c5cb2d0d4..9f2d24962 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2331,8 +2331,8 @@ static void disas_sparc_insn(DisasContext * dc) #endif } if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || \ - (xop > 0x17 && xop < 0x1d ) || \ - (xop > 0x2c && xop < 0x33) || xop == 0x1f) { + (xop > 0x17 && xop <= 0x1d ) || \ + (xop > 0x2c && xop <= 0x33) || xop == 0x1f) { switch (xop) { case 0x0: /* load word */ gen_op_ldst(ld); -- cgit v1.2.3 From 74287114c98ecb969b7ce4b5c959da8a8a431d0f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 1 Apr 2007 17:56:37 +0000 Subject: Improved initrd support for mips. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2574 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf_ops.h | 12 +++++++++++- hw/arm_boot.c | 2 +- hw/mips_malta.c | 47 +++++++++++++++++++++++++++++++---------------- hw/mips_r4k.c | 27 ++++++++++++++++++++------- hw/sun4m.c | 4 ++-- hw/sun4u.c | 4 ++-- loader.c | 8 +++++--- vl.h | 3 ++- 8 files changed, 74 insertions(+), 33 deletions(-) diff --git a/elf_ops.h b/elf_ops.h index abcce093e..3fdde8128 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -139,11 +139,13 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) } int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, - int must_swab, uint64_t *pentry) + int must_swab, uint64_t *pentry, + uint64_t *lowaddr, uint64_t *highaddr) { struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; + elf_word low = 0, high = 0; elf_word mem_size, addr; uint8_t *data = NULL; @@ -193,12 +195,20 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, cpu_physical_memory_write_rom(addr, data, mem_size); total_size += mem_size; + if (!low || addr < low) + low = addr; + if (!high || (addr + mem_size) > high) + high = addr + mem_size; qemu_free(data); data = NULL; } } qemu_free(phdr); + if (lowaddr) + *lowaddr = (uint64_t)low; + if (highaddr) + *highaddr = (uint64_t)high; return total_size; fail: qemu_free(data); diff --git a/hw/arm_boot.c b/hw/arm_boot.c index dfc00db28..095b0bb79 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -101,7 +101,7 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, qemu_register_reset(main_cpu_reset, env); } /* Assume that raw images are linux kernels, and ELF images are not. */ - kernel_size = load_elf(kernel_filename, 0, &elf_entry); + kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); entry = elf_entry; if (kernel_size < 0) { kernel_size = load_uboot(kernel_filename, &entry, &is_linux); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index e4b43bea9..0ba3359ef 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -31,13 +31,13 @@ #endif #ifdef TARGET_MIPS64 -#define INITRD_LOAD_ADDR (int64_t)0x80800000 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) #else -#define INITRD_LOAD_ADDR (int32_t)0x80800000 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) #endif -#define ENVP_ADDR (int32_t)0x80002000 -#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) +#define ENVP_ADDR (int32_t)0x80002000 +#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) #define ENVP_NB_ENTRIES 16 #define ENVP_ENTRY_SIZE 256 @@ -536,7 +536,7 @@ static void network_init (PCIBus *pci_bus) a3 - RAM size in bytes */ -static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr) +static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry) { uint32_t *p; @@ -555,8 +555,8 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */ stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ - stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */; - stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */ + stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */ + stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */ stl_raw(p++, 0x03e00008); /* jr ra */ stl_raw(p++, 0x00000000); /* nop */ } @@ -592,11 +592,13 @@ static void prom_set(int index, const char *string, ...) /* Kernel */ static int64_t load_kernel (CPUState *env) { - int64_t kernel_addr = 0; + int64_t kernel_entry, kernel_low, kernel_high; int index = 0; long initrd_size; + ram_addr_t initrd_offset; - if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) { + if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, + &kernel_entry, &kernel_low, &kernel_high) < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", env->kernel_filename); exit(1); @@ -604,9 +606,20 @@ static int64_t load_kernel (CPUState *env) /* load initrd */ initrd_size = 0; + initrd_offset = 0; if (env->initrd_filename) { - initrd_size = load_image(env->initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); + initrd_size = get_image_size (env->initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > env->ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + env->initrd_filename); + exit(1); + } + initrd_size = load_image(env->initrd_filename, + phys_ram_base + initrd_offset); + } if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", env->initrd_filename); @@ -617,7 +630,9 @@ static int64_t load_kernel (CPUState *env) /* Store command line. */ prom_set(index++, env->kernel_filename); if (initrd_size > 0) - prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline); + prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s", + PHYS_TO_VIRT(initrd_offset), initrd_size, + env->kernel_cmdline); else prom_set(index++, env->kernel_cmdline); @@ -628,7 +643,7 @@ static int64_t load_kernel (CPUState *env) prom_set(index++, "38400n8r"); prom_set(index++, NULL); - return kernel_addr; + return kernel_entry; } static void main_cpu_reset(void *opaque) @@ -651,7 +666,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, { char buf[1024]; unsigned long bios_offset; - int64_t kernel_addr; + int64_t kernel_entry; PCIBus *pci_bus; CPUState *env; RTCState *rtc_state; @@ -693,8 +708,8 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, env->kernel_filename = kernel_filename; env->kernel_cmdline = kernel_cmdline; env->initrd_filename = initrd_filename; - kernel_addr = load_kernel(env); - write_bootloader(env, bios_offset, kernel_addr); + kernel_entry = load_kernel(env); + write_bootloader(env, bios_offset, kernel_entry); } else { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); ret = load_image(buf, phys_ram_base + bios_offset); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 487983e46..8fbddf3c3 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -16,9 +16,9 @@ #endif #ifdef TARGET_MIPS64 -#define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) #else -#define INITRD_LOAD_ADDR (int32_t)0x80800000 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) #endif #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) @@ -73,10 +73,12 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename) { - int64_t entry = 0; + int64_t entry, kernel_low, kernel_high; long kernel_size, initrd_size; + ram_addr_t initrd_offset; - kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); + kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, + &entry, &kernel_low, &kernel_high); if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; @@ -89,9 +91,20 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, /* load initrd */ initrd_size = 0; + initrd_offset = 0; if (initrd_filename) { - initrd_size = load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); + initrd_size = get_image_size (initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_offset); + } if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); @@ -104,7 +117,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, int ret; ret = sprintf(phys_ram_base + (16 << 20) - 256, "rd_start=0x" TARGET_FMT_lx " rd_size=%li ", - INITRD_LOAD_ADDR, + PHYS_TO_VIRT((uint32_t)initrd_offset), initrd_size); strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline); } diff --git a/hw/sun4m.c b/hw/sun4m.c index a23baee17..ee34c1b5b 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -295,7 +295,7 @@ static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - ret = load_elf(buf, 0, NULL); + ret = load_elf(buf, 0, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -304,7 +304,7 @@ static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, kernel_size = 0; if (linux_boot) { - kernel_size = load_elf(kernel_filename, -0xf0000000, NULL); + kernel_size = load_elf(kernel_filename, -0xf0000000, NULL, NULL, NULL); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) diff --git a/hw/sun4u.c b/hw/sun4u.c index 906695690..e536c48ea 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -292,7 +292,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - ret = load_elf(buf, 0, NULL); + ret = load_elf(buf, 0, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -303,7 +303,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, initrd_size = 0; if (linux_boot) { /* XXX: put correct offset */ - kernel_size = load_elf(kernel_filename, 0, NULL); + kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) diff --git a/loader.c b/loader.c index 827d456d2..2e4fecc34 100644 --- a/loader.c +++ b/loader.c @@ -196,7 +196,7 @@ static void *load_at(int fd, int offset, int size) /* return < 0 if error, otherwise the number of bytes loaded in memory */ int load_elf(const char *filename, int64_t virt_to_phys_addend, - uint64_t *pentry) + uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) { int fd, data_order, host_data_order, must_swab, ret; uint8_t e_ident[EI_NIDENT]; @@ -230,9 +230,11 @@ int load_elf(const char *filename, int64_t virt_to_phys_addend, lseek(fd, 0, SEEK_SET); if (e_ident[EI_CLASS] == ELFCLASS64) { - ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry); + ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry, + lowaddr, highaddr); } else { - ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry); + ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry, + lowaddr, highaddr); } close(fd); diff --git a/vl.h b/vl.h index be24d72a4..2fbfa7fc1 100644 --- a/vl.h +++ b/vl.h @@ -1180,7 +1180,8 @@ void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); /* loader.c */ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); -int load_elf(const char *filename, int64_t virt_to_phys_addend, uint64_t *pentry); +int load_elf(const char *filename, int64_t virt_to_phys_addend, + uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr); int load_aout(const char *filename, uint8_t *addr); int load_uboot(const char *filename, target_ulong *ep, int *is_linux); -- cgit v1.2.3 From 2053152b7fb7049600dfe6e5cbe43490e58aa166 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 1 Apr 2007 18:26:11 +0000 Subject: Single mode for PIC i8259, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2575 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/i8259.c b/hw/i8259.c index f8b5a984b..631e4113b 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -44,6 +44,7 @@ typedef struct PicState { uint8_t rotate_on_auto_eoi; uint8_t special_fully_nested_mode; uint8_t init4; /* true if 4 byte init */ + uint8_t single_mode; /* true if slave pic is not initialized */ uint8_t elcr; /* PIIX edge/trigger selection*/ uint8_t elcr_mask; PicState2 *pics_state; @@ -278,6 +279,7 @@ static void pic_reset(void *opaque) s->rotate_on_auto_eoi = 0; s->special_fully_nested_mode = 0; s->init4 = 0; + s->single_mode = 0; /* Note: ELCR is not reset */ } @@ -298,8 +300,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0); s->init_state = 1; s->init4 = val & 1; - if (val & 0x02) - hw_error("single mode not supported"); + s->single_mode = val & 2; if (val & 0x08) hw_error("level sensitive irq not supported"); } else if (val & 0x08) { @@ -356,7 +357,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case 1: s->irq_base = val & 0xf8; - s->init_state = 2; + s->init_state = s->single_mode && s->init4 ? 3 : 2; break; case 2: if (s->init4) { @@ -468,6 +469,7 @@ static void pic_save(QEMUFile *f, void *opaque) qemu_put_8s(f, &s->rotate_on_auto_eoi); qemu_put_8s(f, &s->special_fully_nested_mode); qemu_put_8s(f, &s->init4); + qemu_put_8s(f, &s->single_mode); qemu_put_8s(f, &s->elcr); } @@ -492,6 +494,7 @@ static int pic_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->rotate_on_auto_eoi); qemu_get_8s(f, &s->special_fully_nested_mode); qemu_get_8s(f, &s->init4); + qemu_get_8s(f, &s->single_mode); qemu_get_8s(f, &s->elcr); return 0; } -- cgit v1.2.3 From e5febef5f1811dfd59aa197aad83e96db26a9516 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 1 Apr 2007 18:31:35 +0000 Subject: Conditionalize more syscall implementations, by Mike Frysinger. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2576 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c3a172b11..33778aaba 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2057,6 +2057,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_fork: ret = get_errno(do_fork(cpu_env, SIGCHLD, 0)); break; +#ifdef TARGET_NR_waitpid case TARGET_NR_waitpid: { int status; @@ -2065,6 +2066,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, tput32(arg2, status); } break; +#endif case TARGET_NR_creat: p = lock_user_string(arg1); ret = get_errno(creat(p, arg2)); @@ -2193,11 +2195,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(p3, arg3, 0); break; } +#ifdef TARGET_NR_umount case TARGET_NR_umount: p = lock_user_string(arg1); ret = get_errno(umount(p)); unlock_user(p, arg1, 0); break; +#endif case TARGET_NR_stime: { time_t host_time; @@ -2217,6 +2221,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_pause: ret = get_errno(pause()); break; +#ifdef TARGET_NR_utime case TARGET_NR_utime: { struct utimbuf tbuf, *host_tbuf; @@ -2235,6 +2240,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(p, arg1, 0); } break; +#endif case TARGET_NR_utimes: { struct timeval *tvp, tv[2]; @@ -2331,9 +2337,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_prof: goto unimplemented; #endif +#ifdef TARGET_NR_signal case TARGET_NR_signal: goto unimplemented; - +#endif case TARGET_NR_acct: p = lock_user_string(arg1); ret = get_errno(acct(path(p))); @@ -2391,6 +2398,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_setsid: ret = get_errno(setsid()); break; +#ifdef TARGET_NR_sigaction case TARGET_NR_sigaction: { #if !defined(TARGET_MIPS) @@ -2445,6 +2453,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif } break; +#endif case TARGET_NR_rt_sigaction: { struct target_sigaction *act; @@ -2486,6 +2495,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = target_set; } break; +#ifdef TARGET_NR_sigprocmask case TARGET_NR_sigprocmask: { int how = arg1; @@ -2522,6 +2532,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#endif case TARGET_NR_rt_sigprocmask: { int how = arg1; @@ -2558,6 +2569,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#ifdef TARGET_NR_sigpending case TARGET_NR_sigpending: { sigset_t set; @@ -2569,6 +2581,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#endif case TARGET_NR_rt_sigpending: { sigset_t set; @@ -2580,6 +2593,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#ifdef TARGET_NR_sigsuspend case TARGET_NR_sigsuspend: { sigset_t set; @@ -2589,6 +2603,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(sigsuspend(&set)); } break; +#endif case TARGET_NR_rt_sigsuspend: { sigset_t set; @@ -2630,10 +2645,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); } break; +#ifdef TARGET_NR_sigreturn case TARGET_NR_sigreturn: /* NOTE: ret is eax, so not transcoding must be done */ ret = do_sigreturn(cpu_env); break; +#endif case TARGET_NR_rt_sigreturn: /* NOTE: ret is eax, so not transcoding must be done */ ret = do_rt_sigreturn(cpu_env); @@ -2739,17 +2756,24 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(p, arg1, 0); } break; +#ifdef TARGET_NR_uselib case TARGET_NR_uselib: goto unimplemented; +#endif +#ifdef TARGET_NR_swapon case TARGET_NR_swapon: p = lock_user_string(arg1); ret = get_errno(swapon(p, arg2)); unlock_user(p, arg1, 0); break; +#endif case TARGET_NR_reboot: goto unimplemented; +#ifdef TARGET_NR_readdir case TARGET_NR_readdir: goto unimplemented; +#endif +#ifdef TARGET_NR_mmap case TARGET_NR_mmap: #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K) { @@ -2774,6 +2798,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, arg6)); #endif break; +#endif #ifdef TARGET_NR_mmap2 case TARGET_NR_mmap2: #if defined(TARGET_SPARC) || defined(TARGET_MIPS) @@ -2793,25 +2818,37 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_mprotect: ret = get_errno(target_mprotect(arg1, arg2, arg3)); break; +#ifdef TARGET_NR_mremap case TARGET_NR_mremap: ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5)); break; +#endif /* ??? msync/mlock/munlock are broken for softmmu. */ +#ifdef TARGET_NR_msync case TARGET_NR_msync: ret = get_errno(msync(g2h(arg1), arg2, arg3)); break; +#endif +#ifdef TARGET_NR_mlock case TARGET_NR_mlock: ret = get_errno(mlock(g2h(arg1), arg2)); break; +#endif +#ifdef TARGET_NR_munlock case TARGET_NR_munlock: ret = get_errno(munlock(g2h(arg1), arg2)); break; +#endif +#ifdef TARGET_NR_mlockall case TARGET_NR_mlockall: ret = get_errno(mlockall(arg1)); break; +#endif +#ifdef TARGET_NR_munlockall case TARGET_NR_munlockall: ret = get_errno(munlockall()); break; +#endif case TARGET_NR_truncate: p = lock_user_string(arg1); ret = get_errno(truncate(p, arg2)); @@ -2889,10 +2926,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_ioperm: goto unimplemented; #endif +#ifdef TARGET_NR_socketcall case TARGET_NR_socketcall: ret = do_socketcall(arg1, arg2); break; - +#endif #ifdef TARGET_NR_accept case TARGET_NR_accept: ret = do_accept(arg1, arg2, arg3); @@ -3101,11 +3139,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#ifdef TARGET_NR_swapoff case TARGET_NR_swapoff: p = lock_user_string(arg1); ret = get_errno(swapoff(p)); unlock_user(p, arg1, 0); break; +#endif case TARGET_NR_sysinfo: { struct target_sysinfo *target_value; @@ -3133,9 +3173,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#ifdef TARGET_NR_ipc case TARGET_NR_ipc: ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); break; +#endif case TARGET_NR_fsync: ret = get_errno(fsync(arg1)); break; @@ -3184,10 +3226,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif case TARGET_NR_adjtimex: goto unimplemented; +#ifdef TARGET_NR_create_module case TARGET_NR_create_module: +#endif case TARGET_NR_init_module: case TARGET_NR_delete_module: +#ifdef TARGET_NR_get_kernel_syms case TARGET_NR_get_kernel_syms: +#endif goto unimplemented; case TARGET_NR_quotactl: goto unimplemented; @@ -3199,13 +3245,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; case TARGET_NR_bdflush: goto unimplemented; +#ifdef TARGET_NR_sysfs case TARGET_NR_sysfs: goto unimplemented; +#endif case TARGET_NR_personality: ret = get_errno(personality(arg1)); break; +#ifdef TARGET_NR_afs_syscall case TARGET_NR_afs_syscall: goto unimplemented; +#endif case TARGET_NR__llseek: { #if defined (__x86_64__) @@ -3319,9 +3369,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; #endif /* TARGET_NR_getdents64 */ +#ifdef TARGET_NR__newselect case TARGET_NR__newselect: ret = do_select(arg1, arg2, arg3, arg4, arg5); break; +#endif +#ifdef TARGET_NR_poll case TARGET_NR_poll: { struct target_pollfd *target_pfd; @@ -3347,6 +3400,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(target_pfd, arg1, ret); } break; +#endif case TARGET_NR_flock: /* NOTE: the flock constant seems to be the same for every Linux platform */ @@ -3448,10 +3502,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } } break; +#ifdef TARGET_NR_query_module case TARGET_NR_query_module: goto unimplemented; +#endif +#ifdef TARGET_NR_nfsservctl case TARGET_NR_nfsservctl: goto unimplemented; +#endif case TARGET_NR_prctl: switch (arg1) { @@ -4004,8 +4062,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_gettid: ret = get_errno(gettid()); break; +#ifdef TARGET_NR_readahead case TARGET_NR_readahead: goto unimplemented; +#endif #ifdef TARGET_NR_setxattr case TARGET_NR_setxattr: case TARGET_NR_lsetxattr: -- cgit v1.2.3 From 0475a5ca544e3a59fb961f14342228aad1d0acb6 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 1 Apr 2007 18:54:44 +0000 Subject: Solaris 9/x86 support, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2577 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 6 ++++++ configure | 18 +++++++++++++++++- fpu/softfloat-native.c | 19 +++++++++++++++++++ fpu/softfloat.h | 4 ++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 3d221babb..f53b02442 100644 --- a/Makefile.target +++ b/Makefile.target @@ -217,6 +217,12 @@ LIBS+=-lwinmm -lws2_32 -liphlpapi endif ifdef CONFIG_SOLARIS LIBS+=-lsocket -lnsl -lresolv +ifdef NEEDS_LIBSUNMATH +LIBS+=-lsunmath +LDFLAGS+=-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib +OP_CFLAGS+=-I/opt/SUNWspro/prod/include/cc +BASE_CFLAGS+=-I/opt/SUNWspro/prod/include/cc +endif endif # profiling code diff --git a/configure b/configure index 7754774d6..a7761ca28 100755 --- a/configure +++ b/configure @@ -139,9 +139,21 @@ SunOS) solaris="yes" make="gmake" install="ginstall" + needs_libsunmath="no" solarisrev=`uname -r | cut -f2 -d.` if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then - if test "$solarisrev" -ge 10 ; then + if test "$solarisrev" -le 9 ; then + if test -f /opt/SUNWspro/prod/lib/libsunmath.so.1; then + needs_libsunmath="yes" + else + echo "QEMU will not link correctly on Solaris 8/X86 or 9/x86 without" + echo "libsunmath from the Sun Studio compilers tools, due to a lack of" + echo "C99 math features in libm.so in Solaris 8/x86 and Solaris 9/x86" + echo "Studio 11 can be downloaded from www.sun.com." + exit 1 + fi + fi + if test "$solarisrev" -ge 9 ; then kqemu="yes" fi fi @@ -727,6 +739,10 @@ fi if test "$solaris" = "yes" ; then echo "CONFIG_SOLARIS=yes" >> $config_mak echo "#define HOST_SOLARIS $solarisrev" >> $config_h + if test "$needs_libsunmath" = "yes" ; then + echo "NEEDS_LIBSUNMATH=yes" >> $config_mak + echo "#define NEEDS_LIBSUNMATH 1" >> $config_h + fi fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index c629926f8..d827ae6fe 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -30,6 +30,25 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) #define sqrtf(f) ((float)sqrt(f)) #define remainderf(fa, fb) ((float)remainder(fa, fb)) #define rintf(f) ((float)rint(f)) +#if !defined(__sparc__) && HOST_SOLARIS < 10 +extern long double rintl(long double); +extern long double scalbnl(long double, int); + +long long +llrintl(long double x) { + return ((long long) rintl(x)); +} + +long +lrintl(long double x) { + return ((long) rintl(x)); +} + +long double +ldexpl(long double x, int n) { + return (scalbnl(x, n)); +} +#endif #endif #if defined(__powerpc__) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 00ec56b05..21100c0d0 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -32,6 +32,10 @@ these four paragraphs for those parts of this code that are retained. #ifndef SOFTFLOAT_H #define SOFTFLOAT_H +#if defined(HOST_SOLARIS) && defined(NEEDS_LIBSUNMATH) +#include +#endif + #include #include "config.h" -- cgit v1.2.3 From a4080ece74523492856ac67e709a10675b080da0 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 1 Apr 2007 19:01:40 +0000 Subject: Qcow2 corruption fix, by Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2578 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block-qcow2.c b/block-qcow2.c index a876ea2e2..0f7a06961 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -1933,6 +1933,7 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) qemu_free(s->refcount_table); s->refcount_table = new_table; s->refcount_table_size = new_table_size; + s->refcount_table_offset = table_offset; update_refcount(bs, table_offset, new_table_size2, 1); return 0; -- cgit v1.2.3 From d34cab9f49bc3ad83a2a968fc2d2719179db2c15 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 01:10:46 +0000 Subject: VMware SVGA II emulation, by Andrzej Zaborowski. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2579 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/cirrus_vga.c | 3 + hw/pc.c | 6 + hw/vga.c | 12 +- hw/vga_int.h | 4 + hw/vmware_vga.c | 1187 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ sdl.c | 95 ++++- vl.c | 13 + vl.h | 13 +- 9 files changed, 1327 insertions(+), 8 deletions(-) create mode 100644 hw/vmware_vga.c diff --git a/Makefile.target b/Makefile.target index f53b02442..f1fbc578d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -403,7 +403,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) 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 mixeng.o apic.o parallel.o acpi.o piix_pci.o -VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o +VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o vmware_vga.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index d8fb37a89..2cbafe174 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -3193,6 +3193,9 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, device_id, 1); + + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + s->pci_dev = (PCIDevice *)d; /* setup memory space */ diff --git a/hw/pc.c b/hw/pc.c index 7a156eb9f..332bb1c68 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -664,6 +664,12 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); } + } else if (vmsvga_enabled) { + if (pci_enabled) + pci_vmsvga_init(pci_bus, ds, phys_ram_base + ram_size, + ram_size, vga_ram_size); + else + fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); } else { if (pci_enabled) { pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, diff --git a/hw/vga.c b/hw/vga.c index 5acacf9b3..2dadcca5b 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1788,12 +1788,13 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, s->get_bpp = vga_get_bpp; s->get_offsets = vga_get_offsets; s->get_resolution = vga_get_resolution; - graphic_console_init(s->ds, vga_update_display, vga_invalidate_display, - vga_screen_dump, s); + s->update = vga_update_display; + s->invalidate = vga_invalidate_display; + s->screen_dump = vga_screen_dump; } /* used by both ISA and PCI */ -static void vga_init(VGAState *s) +void vga_init(VGAState *s) { int vga_io_memory; @@ -1856,6 +1857,8 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); vga_init(s); + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + #ifdef CONFIG_BOCHS_VBE /* XXX: use optimized standard vga accesses */ cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, @@ -1881,6 +1884,9 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); vga_init(s); + + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + s->pci_dev = &d->dev; pci_conf = d->dev.config; diff --git a/hw/vga_int.h b/hw/vga_int.h index 633f344c7..e7df0f72b 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -134,6 +134,9 @@ uint32_t cursor_offset; \ unsigned int (*rgb_to_pixel)(unsigned int r, \ unsigned int g, unsigned b); \ + vga_hw_update_ptr update; \ + vga_hw_invalidate_ptr invalidate; \ + vga_hw_screen_dump_ptr screen_dump; \ /* hardware mouse cursor support */ \ uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \ void (*cursor_invalidate)(struct VGAState *s); \ @@ -157,6 +160,7 @@ static inline int c6_to_8(int v) void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); +void vga_init(VGAState *s); uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr); void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val); void vga_invalidate_scanlines(VGAState *s, int y1, int y2); diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c new file mode 100644 index 000000000..1a4f4cd9d --- /dev/null +++ b/hw/vmware_vga.c @@ -0,0 +1,1187 @@ +/* + * QEMU VMware-SVGA "chipset". + * + * Copyright (c) 2007 Andrzej Zaborowski + * + * 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 VERBOSE +#define EMBED_STDVGA +#undef DIRECT_VRAM +#define HW_RECT_ACCEL +#define HW_FILL_ACCEL +#define HW_MOUSE_ACCEL + +#ifdef EMBED_STDVGA +# include "vga_int.h" +#endif + +struct vmsvga_state_s { +#ifdef EMBED_STDVGA + VGA_STATE_COMMON +#endif + + int width; + int height; + int invalidated; + int depth; + int bypp; + int enable; + int config; + struct { + int id; + int x; + int y; + int on; + } cursor; + +#ifndef EMBED_STDVGA + DisplayState *ds; + int vram_size; +#endif + uint8_t *vram; + + int index; + int scratch_size; + uint32_t *scratch; + int new_width; + int new_height; + uint32_t guest; + uint32_t svgaid; + uint32_t wred; + uint32_t wgreen; + uint32_t wblue; + int syncing; + int fb_size; + + union { + uint32_t *fifo; + struct __attribute__((__packed__)) { + uint32_t min; + uint32_t max; + uint32_t next_cmd; + uint32_t stop; + /* Add registers here when adding capabilities. */ + uint32_t fifo[0]; + } *cmd; + }; + +#define REDRAW_FIFO_LEN 512 + struct vmsvga_rect_s { + int x, y, w, h; + } redraw_fifo[REDRAW_FIFO_LEN]; + int redraw_fifo_first, redraw_fifo_last; +}; + +struct pci_vmsvga_state_s { + PCIDevice card; + struct vmsvga_state_s chip; +}; + +#define SVGA_MAGIC 0x900000UL +#define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver)) +#define SVGA_ID_0 SVGA_MAKE_ID(0) +#define SVGA_ID_1 SVGA_MAKE_ID(1) +#define SVGA_ID_2 SVGA_MAKE_ID(2) + +#define SVGA_LEGACY_BASE_PORT 0x4560 +#define SVGA_INDEX_PORT 0x0 +#define SVGA_VALUE_PORT 0x1 +#define SVGA_BIOS_PORT 0x2 + +#define SVGA_VERSION_2 + +#ifdef SVGA_VERSION_2 +# define SVGA_ID SVGA_ID_2 +# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT +# define SVGA_IO_MUL 1 +# define SVGA_FIFO_SIZE 0x10000 +# define SVGA_MEM_BASE 0xec000000 +# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2 +#else +# define SVGA_ID SVGA_ID_1 +# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT +# define SVGA_IO_MUL 4 +# define SVGA_FIFO_SIZE 0x10000 +# define SVGA_MEM_BASE 0xec000000 +# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA +#endif + +enum { + /* ID 0, 1 and 2 registers */ + SVGA_REG_ID = 0, + SVGA_REG_ENABLE = 1, + SVGA_REG_WIDTH = 2, + SVGA_REG_HEIGHT = 3, + SVGA_REG_MAX_WIDTH = 4, + SVGA_REG_MAX_HEIGHT = 5, + SVGA_REG_DEPTH = 6, + SVGA_REG_BITS_PER_PIXEL = 7, /* Current bpp in the guest */ + SVGA_REG_PSEUDOCOLOR = 8, + SVGA_REG_RED_MASK = 9, + SVGA_REG_GREEN_MASK = 10, + SVGA_REG_BLUE_MASK = 11, + SVGA_REG_BYTES_PER_LINE = 12, + SVGA_REG_FB_START = 13, + SVGA_REG_FB_OFFSET = 14, + SVGA_REG_VRAM_SIZE = 15, + SVGA_REG_FB_SIZE = 16, + + /* ID 1 and 2 registers */ + SVGA_REG_CAPABILITIES = 17, + SVGA_REG_MEM_START = 18, /* Memory for command FIFO */ + SVGA_REG_MEM_SIZE = 19, + SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */ + SVGA_REG_SYNC = 21, /* Write to force synchronization */ + SVGA_REG_BUSY = 22, /* Read to check if sync is done */ + SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */ + SVGA_REG_CURSOR_ID = 24, /* ID of cursor */ + SVGA_REG_CURSOR_X = 25, /* Set cursor X position */ + SVGA_REG_CURSOR_Y = 26, /* Set cursor Y position */ + SVGA_REG_CURSOR_ON = 27, /* Turn cursor on/off */ + SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* Current bpp in the host */ + SVGA_REG_SCRATCH_SIZE = 29, /* Number of scratch registers */ + SVGA_REG_MEM_REGS = 30, /* Number of FIFO registers */ + SVGA_REG_NUM_DISPLAYS = 31, /* Number of guest displays */ + SVGA_REG_PITCHLOCK = 32, /* Fixed pitch for all modes */ + + SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ + SVGA_PALETTE_END = SVGA_PALETTE_BASE + 767, + SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + 768, +}; + +#define SVGA_CAP_NONE 0 +#define SVGA_CAP_RECT_FILL (1 << 0) +#define SVGA_CAP_RECT_COPY (1 << 1) +#define SVGA_CAP_RECT_PAT_FILL (1 << 2) +#define SVGA_CAP_LEGACY_OFFSCREEN (1 << 3) +#define SVGA_CAP_RASTER_OP (1 << 4) +#define SVGA_CAP_CURSOR (1 << 5) +#define SVGA_CAP_CURSOR_BYPASS (1 << 6) +#define SVGA_CAP_CURSOR_BYPASS_2 (1 << 7) +#define SVGA_CAP_8BIT_EMULATION (1 << 8) +#define SVGA_CAP_ALPHA_CURSOR (1 << 9) +#define SVGA_CAP_GLYPH (1 << 10) +#define SVGA_CAP_GLYPH_CLIPPING (1 << 11) +#define SVGA_CAP_OFFSCREEN_1 (1 << 12) +#define SVGA_CAP_ALPHA_BLEND (1 << 13) +#define SVGA_CAP_3D (1 << 14) +#define SVGA_CAP_EXTENDED_FIFO (1 << 15) +#define SVGA_CAP_MULTIMON (1 << 16) +#define SVGA_CAP_PITCHLOCK (1 << 17) + +/* + * FIFO offsets (seen as an array of 32-bit words) + */ +enum { + /* + * The original defined FIFO offsets + */ + SVGA_FIFO_MIN = 0, + SVGA_FIFO_MAX, /* The distance from MIN to MAX must be at least 10K */ + SVGA_FIFO_NEXT_CMD, + SVGA_FIFO_STOP, + + /* + * Additional offsets added as of SVGA_CAP_EXTENDED_FIFO + */ + SVGA_FIFO_CAPABILITIES = 4, + SVGA_FIFO_FLAGS, + SVGA_FIFO_FENCE, + SVGA_FIFO_3D_HWVERSION, + SVGA_FIFO_PITCHLOCK, +}; + +#define SVGA_FIFO_CAP_NONE 0 +#define SVGA_FIFO_CAP_FENCE (1 << 0) +#define SVGA_FIFO_CAP_ACCELFRONT (1 << 1) +#define SVGA_FIFO_CAP_PITCHLOCK (1 << 2) + +#define SVGA_FIFO_FLAG_NONE 0 +#define SVGA_FIFO_FLAG_ACCELFRONT (1 << 0) + +/* These values can probably be changed arbitrarily. */ +#define SVGA_SCRATCH_SIZE 0x8000 +#define SVGA_MAX_WIDTH 2360 +#define SVGA_MAX_HEIGHT 1770 + +#ifdef VERBOSE +# define GUEST_OS_BASE 0x5001 +static const char *vmsvga_guest_id[] = { + [0x0] = "Dos", + [0x1] = "Windows 3.1", + [0x2] = "Windows 95", + [0x3] = "Windows 98", + [0x4] = "Windows ME", + [0x5] = "Windows NT", + [0x6] = "Windows 2000", + [0x7] = "Linux", + [0x8] = "OS/2", + [0x9] = "Unknown", + [0xa] = "BSD", + [0xb] = "Whistler", +}; +#endif + +enum { + SVGA_CMD_INVALID_CMD = 0, + SVGA_CMD_UPDATE = 1, + SVGA_CMD_RECT_FILL = 2, + SVGA_CMD_RECT_COPY = 3, + SVGA_CMD_DEFINE_BITMAP = 4, + SVGA_CMD_DEFINE_BITMAP_SCANLINE = 5, + SVGA_CMD_DEFINE_PIXMAP = 6, + SVGA_CMD_DEFINE_PIXMAP_SCANLINE = 7, + SVGA_CMD_RECT_BITMAP_FILL = 8, + SVGA_CMD_RECT_PIXMAP_FILL = 9, + SVGA_CMD_RECT_BITMAP_COPY = 10, + SVGA_CMD_RECT_PIXMAP_COPY = 11, + SVGA_CMD_FREE_OBJECT = 12, + SVGA_CMD_RECT_ROP_FILL = 13, + SVGA_CMD_RECT_ROP_COPY = 14, + SVGA_CMD_RECT_ROP_BITMAP_FILL = 15, + SVGA_CMD_RECT_ROP_PIXMAP_FILL = 16, + SVGA_CMD_RECT_ROP_BITMAP_COPY = 17, + SVGA_CMD_RECT_ROP_PIXMAP_COPY = 18, + SVGA_CMD_DEFINE_CURSOR = 19, + SVGA_CMD_DISPLAY_CURSOR = 20, + SVGA_CMD_MOVE_CURSOR = 21, + SVGA_CMD_DEFINE_ALPHA_CURSOR = 22, + SVGA_CMD_DRAW_GLYPH = 23, + SVGA_CMD_DRAW_GLYPH_CLIPPED = 24, + SVGA_CMD_UPDATE_VERBOSE = 25, + SVGA_CMD_SURFACE_FILL = 26, + SVGA_CMD_SURFACE_COPY = 27, + SVGA_CMD_SURFACE_ALPHA_BLEND = 28, + SVGA_CMD_FRONT_ROP_FILL = 29, + SVGA_CMD_FENCE = 30, +}; + +/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */ +enum { + SVGA_CURSOR_ON_HIDE = 0, + SVGA_CURSOR_ON_SHOW = 1, + SVGA_CURSOR_ON_REMOVE_FROM_FB = 2, + SVGA_CURSOR_ON_RESTORE_TO_FB = 3, +}; + +static inline void vmsvga_update_rect(struct vmsvga_state_s *s, + int x, int y, int w, int h) +{ +#ifndef DIRECT_VRAM + int line = h; + int bypl = s->bypp * s->width; + int width = s->bypp * w; + int start = s->bypp * x + bypl * y; + uint8_t *src = s->vram + start; + uint8_t *dst = s->ds->data + start; + + for (; line > 0; line --, src += bypl, dst += bypl) + memcpy(dst, src, width); +#endif + + dpy_update(s->ds, x, y, w, h); +} + +static inline void vmsvga_update_screen(struct vmsvga_state_s *s) +{ +#ifndef DIRECT_VRAM + memcpy(s->ds->data, s->vram, s->bypp * s->width * s->height); +#endif + + dpy_update(s->ds, 0, 0, s->width, s->height); +} + +#ifdef DIRECT_VRAM +# define vmsvga_update_rect_delayed vmsvga_update_rect +#else +static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s, + int x, int y, int w, int h) +{ + struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last ++]; + s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1; + rect->x = x; + rect->y = y; + rect->w = w; + rect->h = h; +} +#endif + +static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s) +{ + struct vmsvga_rect_s *rect; + if (s->invalidated) { + s->redraw_fifo_first = s->redraw_fifo_last; + return; + } + /* Overlapping region updates can be optimised out here - if someone + * knows a smart algorithm to do that, please share. */ + while (s->redraw_fifo_first != s->redraw_fifo_last) { + rect = &s->redraw_fifo[s->redraw_fifo_first ++]; + s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1; + vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h); + } +} + +#ifdef HW_RECT_ACCEL +static inline void vmsvga_copy_rect(struct vmsvga_state_s *s, + int x0, int y0, int x1, int y1, int w, int h) +{ +# ifdef DIRECT_VRAM + uint8_t *vram = s->ds->data; +# else + uint8_t *vram = s->vram; +# endif + int bypl = s->bypp * s->width; + int width = s->bypp * w; + int line = h; + uint8_t *ptr[2]; + +# ifdef DIRECT_VRAM + if (s->ds->dpy_copy) + s->ds->dpy_copy(s->ds, x0, y0, x1, y1, w, h); + else +# endif + { + if (y1 > y0) { + ptr[0] = vram + s->bypp * x0 + bypl * (y0 + h - 1); + ptr[1] = vram + s->bypp * x1 + bypl * (y1 + h - 1); + for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl) + memmove(ptr[1], ptr[0], width); + } else { + ptr[0] = vram + s->bypp * x0 + bypl * y0; + ptr[1] = vram + s->bypp * x1 + bypl * y1; + for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl) + memmove(ptr[1], ptr[0], width); + } + } + + vmsvga_update_rect_delayed(s, x1, y1, w, h); +} +#endif + +#ifdef HW_FILL_ACCEL +static inline void vmsvga_fill_rect(struct vmsvga_state_s *s, + uint32_t c, int x, int y, int w, int h) +{ +# ifdef DIRECT_VRAM + uint8_t *vram = s->ds->data; +# else + uint8_t *vram = s->vram; +# endif + int bypp = s->bypp; + int bypl = bypp * s->width; + int width = bypp * w; + int line = h; + int column; + uint8_t *fst = vram + bypp * x + bypl * y; + uint8_t *dst; + uint8_t *src; + uint8_t col[4]; + +# ifdef DIRECT_VRAM + if (s->ds->dpy_fill) + s->ds->dpy_fill(s->ds, x, y, w, h, c); + else +# endif + { + col[0] = c; + col[1] = c >> 8; + col[2] = c >> 16; + col[3] = c >> 24; + + if (line --) { + dst = fst; + src = col; + for (column = width; column > 0; column --) { + *(dst ++) = *(src ++); + if (src - col == bypp) + src = col; + } + dst = fst; + for (; line > 0; line --) { + dst += bypl; + memcpy(dst, fst, width); + } + } + } + + vmsvga_update_rect_delayed(s, x, y, w, h); +} +#endif + +struct vmsvga_cursor_definition_s { + int width; + int height; + int id; + int bpp; + int hot_x; + int hot_y; + uint32_t mask[1024]; + uint32_t image[1024]; +}; + +#define SVGA_BITMAP_SIZE(w, h) ((((w) + 31) >> 5) * (h)) +#define SVGA_PIXMAP_SIZE(w, h, bpp) (((((w) * (bpp)) + 31) >> 5) * (h)) + +#ifdef HW_MOUSE_ACCEL +static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, + struct vmsvga_cursor_definition_s *c) +{ + int i; + for (i = SVGA_BITMAP_SIZE(c->width, c->height) - 1; i >= 0; i --) + c->mask[i] = ~c->mask[i]; + + if (s->ds->cursor_define) + s->ds->cursor_define(c->width, c->height, c->bpp, c->hot_x, c->hot_y, + (uint8_t *) c->image, (uint8_t *) c->mask); +} +#endif + +static inline int vmsvga_fifo_empty(struct vmsvga_state_s *s) +{ + if (!s->config || !s->enable) + return 0; + return (s->cmd->next_cmd == s->cmd->stop); +} + +static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s) +{ + uint32_t cmd = s->fifo[s->cmd->stop >> 2]; + s->cmd->stop += 4; + if (s->cmd->stop >= s->cmd->max) + s->cmd->stop = s->cmd->min; + return cmd; +} + +static void vmsvga_fifo_run(struct vmsvga_state_s *s) +{ + uint32_t cmd, colour; + int args = 0; + int x, y, dx, dy, width, height; + struct vmsvga_cursor_definition_s cursor; + while (!vmsvga_fifo_empty(s)) + switch (cmd = vmsvga_fifo_read(s)) { + case SVGA_CMD_UPDATE: + case SVGA_CMD_UPDATE_VERBOSE: + x = vmsvga_fifo_read(s); + y = vmsvga_fifo_read(s); + width = vmsvga_fifo_read(s); + height = vmsvga_fifo_read(s); + vmsvga_update_rect_delayed(s, x, y, width, height); + break; + + case SVGA_CMD_RECT_FILL: + colour = vmsvga_fifo_read(s); + x = vmsvga_fifo_read(s); + y = vmsvga_fifo_read(s); + width = vmsvga_fifo_read(s); + height = vmsvga_fifo_read(s); +#ifdef HW_FILL_ACCEL + vmsvga_fill_rect(s, colour, x, y, width, height); + break; +#else + goto badcmd; +#endif + + case SVGA_CMD_RECT_COPY: + x = vmsvga_fifo_read(s); + y = vmsvga_fifo_read(s); + dx = vmsvga_fifo_read(s); + dy = vmsvga_fifo_read(s); + width = vmsvga_fifo_read(s); + height = vmsvga_fifo_read(s); +#ifdef HW_RECT_ACCEL + vmsvga_copy_rect(s, x, y, dx, dy, width, height); + break; +#else + goto badcmd; +#endif + + case SVGA_CMD_DEFINE_CURSOR: + cursor.id = vmsvga_fifo_read(s); + cursor.hot_x = vmsvga_fifo_read(s); + cursor.hot_y = vmsvga_fifo_read(s); + cursor.width = x = vmsvga_fifo_read(s); + cursor.height = y = vmsvga_fifo_read(s); + vmsvga_fifo_read(s); + cursor.bpp = vmsvga_fifo_read(s); + for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++) + cursor.mask[args] = vmsvga_fifo_read(s); + for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args ++) + cursor.image[args] = vmsvga_fifo_read(s); +#ifdef HW_MOUSE_ACCEL + vmsvga_cursor_define(s, &cursor); + break; +#else + args = 0; + goto badcmd; +#endif + + /* + * Other commands that we at least know the number of arguments + * for so we can avoid FIFO desync if driver uses them illegally. + */ + case SVGA_CMD_DEFINE_ALPHA_CURSOR: + vmsvga_fifo_read(s); + vmsvga_fifo_read(s); + vmsvga_fifo_read(s); + x = vmsvga_fifo_read(s); + y = vmsvga_fifo_read(s); + args = x * y; + goto badcmd; + case SVGA_CMD_RECT_ROP_FILL: + args = 6; + goto badcmd; + case SVGA_CMD_RECT_ROP_COPY: + args = 7; + goto badcmd; + case SVGA_CMD_DRAW_GLYPH_CLIPPED: + vmsvga_fifo_read(s); + vmsvga_fifo_read(s); + args = 7 + (vmsvga_fifo_read(s) >> 2); + goto badcmd; + case SVGA_CMD_SURFACE_ALPHA_BLEND: + args = 12; + goto badcmd; + + /* + * Other commands that are not listed as depending on any + * CAPABILITIES bits, but are not described in the README either. + */ + case SVGA_CMD_SURFACE_FILL: + case SVGA_CMD_SURFACE_COPY: + case SVGA_CMD_FRONT_ROP_FILL: + case SVGA_CMD_FENCE: + case SVGA_CMD_INVALID_CMD: + break; /* Nop */ + + default: + badcmd: + while (args --) + vmsvga_fifo_read(s); + printf("%s: Unknown command 0x%02x in SVGA command FIFO\n", + __FUNCTION__, cmd); + break; + } + + s->syncing = 0; +} + +static uint32_t vmsvga_index_read(void *opaque, uint32_t address) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + return s->index; +} + +static void vmsvga_index_write(void *opaque, uint32_t address, uint32_t index) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + s->index = index; +} + +static uint32_t vmsvga_value_read(void *opaque, uint32_t address) +{ + uint32_t caps; + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + switch (s->index) { + case SVGA_REG_ID: + return s->svgaid; + + case SVGA_REG_ENABLE: + return s->enable; + + case SVGA_REG_WIDTH: + return s->width; + + case SVGA_REG_HEIGHT: + return s->height; + + case SVGA_REG_MAX_WIDTH: + return SVGA_MAX_WIDTH; + + case SVGA_REG_MAX_HEIGHT: + return SVGA_MAX_WIDTH; + + case SVGA_REG_DEPTH: + return s->depth; + + case SVGA_REG_BITS_PER_PIXEL: + return (s->depth + 7) & ~7; + + case SVGA_REG_PSEUDOCOLOR: + return 0x0; + + case SVGA_REG_RED_MASK: + return s->wred; + case SVGA_REG_GREEN_MASK: + return s->wgreen; + case SVGA_REG_BLUE_MASK: + return s->wblue; + + case SVGA_REG_BYTES_PER_LINE: + return ((s->depth + 7) >> 3) * s->new_width; + + case SVGA_REG_FB_START: + return SVGA_MEM_BASE; + + case SVGA_REG_FB_OFFSET: + return 0x0; + + case SVGA_REG_VRAM_SIZE: + return s->vram_size - SVGA_FIFO_SIZE; + + case SVGA_REG_FB_SIZE: + return s->fb_size; + + case SVGA_REG_CAPABILITIES: + caps = SVGA_CAP_NONE; +#ifdef HW_RECT_ACCEL + caps |= SVGA_CAP_RECT_COPY; +#endif +#ifdef HW_FILL_ACCEL + caps |= SVGA_CAP_RECT_FILL; +#endif +#ifdef HW_MOUSE_ACCEL + if (s->ds->mouse_set) + caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 | + SVGA_CAP_CURSOR_BYPASS; +#endif + return caps; + + case SVGA_REG_MEM_START: + return SVGA_MEM_BASE + s->vram_size - SVGA_FIFO_SIZE; + + case SVGA_REG_MEM_SIZE: + return SVGA_FIFO_SIZE; + + case SVGA_REG_CONFIG_DONE: + return s->config; + + case SVGA_REG_SYNC: + case SVGA_REG_BUSY: + return s->syncing; + + case SVGA_REG_GUEST_ID: + return s->guest; + + case SVGA_REG_CURSOR_ID: + return s->cursor.id; + + case SVGA_REG_CURSOR_X: + return s->cursor.x; + + case SVGA_REG_CURSOR_Y: + return s->cursor.x; + + case SVGA_REG_CURSOR_ON: + return s->cursor.on; + + case SVGA_REG_HOST_BITS_PER_PIXEL: + return (s->depth + 7) & ~7; + + case SVGA_REG_SCRATCH_SIZE: + return s->scratch_size; + + case SVGA_REG_MEM_REGS: + case SVGA_REG_NUM_DISPLAYS: + case SVGA_REG_PITCHLOCK: + case SVGA_PALETTE_BASE ... SVGA_PALETTE_END: + return 0; + + default: + if (s->index >= SVGA_SCRATCH_BASE && + s->index < SVGA_SCRATCH_BASE + s->scratch_size) + return s->scratch[s->index - SVGA_SCRATCH_BASE]; + printf("%s: Bad register %02x\n", __FUNCTION__, s->index); + } + + return 0; +} + +static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + switch (s->index) { + case SVGA_REG_ID: + if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0) + s->svgaid = value; + break; + + case SVGA_REG_ENABLE: + s->enable = s->config = value & s->config; + s->width = -1; + s->height = -1; + s->invalidated = 1; +#ifdef EMBED_STDVGA + s->invalidate(opaque); +#endif + if (s->enable) + s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height; + break; + + case SVGA_REG_WIDTH: + s->new_width = value; + s->invalidated = 1; + break; + + case SVGA_REG_HEIGHT: + s->new_height = value; + s->invalidated = 1; + break; + + case SVGA_REG_DEPTH: + case SVGA_REG_BITS_PER_PIXEL: + if (value != s->depth) { + printf("%s: Bad colour depth: %i bits\n", __FUNCTION__, value); + s->config = 0; + } + break; + + case SVGA_REG_CONFIG_DONE: + if (value) { + s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE]; + /* Check range and alignment. */ + if ((s->cmd->min | s->cmd->max | + s->cmd->next_cmd | s->cmd->stop) & 3) + break; + if (s->cmd->min < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) + break; + if (s->cmd->max > SVGA_FIFO_SIZE) + break; + if (s->cmd->max < s->cmd->min + 10 * 1024) + break; + } + s->config = value; + break; + + case SVGA_REG_SYNC: + s->syncing = 1; + vmsvga_fifo_run(s); /* Or should we just wait for update_display? */ + break; + + case SVGA_REG_GUEST_ID: + s->guest = value; +#ifdef VERBOSE + if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE + + sizeof(vmsvga_guest_id) / sizeof(*vmsvga_guest_id)) + printf("%s: guest runs %s.\n", __FUNCTION__, + vmsvga_guest_id[value - GUEST_OS_BASE]); +#endif + break; + + case SVGA_REG_CURSOR_ID: + s->cursor.id = value; + break; + + case SVGA_REG_CURSOR_X: + s->cursor.x = value; + break; + + case SVGA_REG_CURSOR_Y: + s->cursor.y = value; + break; + + case SVGA_REG_CURSOR_ON: + s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW); + s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE); +#ifdef HW_MOUSE_ACCEL + if (s->ds->mouse_set && value <= SVGA_CURSOR_ON_SHOW) + s->ds->mouse_set(s->cursor.x, s->cursor.y, s->cursor.on); +#endif + break; + + case SVGA_REG_MEM_REGS: + case SVGA_REG_NUM_DISPLAYS: + case SVGA_REG_PITCHLOCK: + case SVGA_PALETTE_BASE ... SVGA_PALETTE_END: + break; + + default: + if (s->index >= SVGA_SCRATCH_BASE && + s->index < SVGA_SCRATCH_BASE + s->scratch_size) { + s->scratch[s->index - SVGA_SCRATCH_BASE] = value; + break; + } + printf("%s: Bad register %02x\n", __FUNCTION__, s->index); + } +} + +static uint32_t vmsvga_bios_read(void *opaque, uint32_t address) +{ + printf("%s: what are we supposed to return?\n", __FUNCTION__); + return 0xcafe; +} + +static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data) +{ + printf("%s: what are we supposed to do with (%08x)?\n", + __FUNCTION__, data); +} + +static inline void vmsvga_size(struct vmsvga_state_s *s) +{ + if (s->new_width != s->width || s->new_height != s->height) { + s->width = s->new_width; + s->height = s->new_height; + dpy_resize(s->ds, s->width, s->height); + s->invalidated = 1; + } +} + +static void vmsvga_update_display(void *opaque) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + if (!s->enable) { +#ifdef EMBED_STDVGA + s->update(opaque); +#endif + return; + } + + vmsvga_size(s); + + vmsvga_fifo_run(s); + vmsvga_update_rect_flush(s); + + /* + * Is it more efficient to look at vram VGA-dirty bits or wait + * for the driver to issue SVGA_CMD_UPDATE? + */ + if (s->invalidated) { + s->invalidated = 0; + vmsvga_update_screen(s); + } +} + +static void vmsvga_reset(struct vmsvga_state_s *s) +{ + s->index = 0; + s->enable = 0; + s->config = 0; + s->width = -1; + s->height = -1; + s->svgaid = SVGA_ID; + s->depth = s->ds->depth ? s->ds->depth : 24; + s->bypp = (s->depth + 7) >> 3; + s->cursor.on = 0; + s->redraw_fifo_first = 0; + s->redraw_fifo_last = 0; + switch (s->depth) { + case 8: + s->wred = 0x00000007; + s->wgreen = 0x00000038; + s->wblue = 0x000000c0; + break; + case 15: + s->wred = 0x0000001f; + s->wgreen = 0x000003e0; + s->wblue = 0x00007c00; + break; + case 16: + s->wred = 0x0000001f; + s->wgreen = 0x000007e0; + s->wblue = 0x0000f800; + break; + case 24: + s->wred = 0x000000ff; + s->wgreen = 0x0000ff00; + s->wblue = 0x00ff0000; + break; + case 32: + s->wred = 0x000000ff; + s->wgreen = 0x0000ff00; + s->wblue = 0x00ff0000; + break; + } + s->syncing = 0; +} + +static void vmsvga_invalidate_display(void *opaque) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + if (!s->enable) { +#ifdef EMBED_STDVGA + s->invalidate(opaque); +#endif + return; + } + + s->invalidated = 1; +} + +static void vmsvga_screen_dump(void *opaque, const char *filename) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + if (!s->enable) { +#ifdef EMBED_STDVGA + s->screen_dump(opaque, filename); +#endif + return; + } + + /* TODO */ +} + +#ifdef DIRECT_VRAM +static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + addr -= SVGA_MEM_BASE; + if (addr < s->fb_size) + return *(uint8_t *) (s->ds->data + addr); + else + return *(uint8_t *) (s->vram + addr); +} + +static uint32_t vmsvga_vram_readw(void *opaque, target_phys_addr_t addr) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + addr -= SVGA_MEM_BASE; + if (addr < s->fb_size) + return *(uint16_t *) (s->ds->data + addr); + else + return *(uint16_t *) (s->vram + addr); +} + +static uint32_t vmsvga_vram_readl(void *opaque, target_phys_addr_t addr) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + addr -= SVGA_MEM_BASE; + if (addr < s->fb_size) + return *(uint32_t *) (s->ds->data + addr); + else + return *(uint32_t *) (s->vram + addr); +} + +static void vmsvga_vram_writeb(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + addr -= SVGA_MEM_BASE; + if (addr < s->fb_size) + *(uint8_t *) (s->ds->data + addr) = value; + else + *(uint8_t *) (s->vram + addr) = value; +} + +static void vmsvga_vram_writew(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + addr -= SVGA_MEM_BASE; + if (addr < s->fb_size) + *(uint16_t *) (s->ds->data + addr) = value; + else + *(uint16_t *) (s->vram + addr) = value; +} + +static void vmsvga_vram_writel(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; + addr -= SVGA_MEM_BASE; + if (addr < s->fb_size) + *(uint32_t *) (s->ds->data + addr) = value; + else + *(uint32_t *) (s->vram + addr) = value; +} + +static CPUReadMemoryFunc *vmsvga_vram_read[] = { + vmsvga_vram_readb, + vmsvga_vram_readw, + vmsvga_vram_readl, +}; + +static CPUWriteMemoryFunc *vmsvga_vram_write[] = { + vmsvga_vram_writeb, + vmsvga_vram_writew, + vmsvga_vram_writel, +}; +#endif + +static void vmsvga_save(struct vmsvga_state_s *s, QEMUFile *f) +{ + qemu_put_be32s(f, &s->depth); + qemu_put_be32s(f, &s->enable); + qemu_put_be32s(f, &s->config); + qemu_put_be32s(f, &s->cursor.id); + qemu_put_be32s(f, &s->cursor.x); + qemu_put_be32s(f, &s->cursor.y); + qemu_put_be32s(f, &s->cursor.on); + qemu_put_be32s(f, &s->index); + qemu_put_buffer(f, (uint8_t *) s->scratch, s->scratch_size * 4); + qemu_put_be32s(f, &s->new_width); + qemu_put_be32s(f, &s->new_height); + qemu_put_be32s(f, &s->guest); + qemu_put_be32s(f, &s->svgaid); + qemu_put_be32s(f, &s->syncing); + qemu_put_be32s(f, &s->fb_size); +} + +static int vmsvga_load(struct vmsvga_state_s *s, QEMUFile *f) +{ + int depth; + qemu_get_be32s(f, &depth); + qemu_get_be32s(f, &s->enable); + qemu_get_be32s(f, &s->config); + qemu_get_be32s(f, &s->cursor.id); + qemu_get_be32s(f, &s->cursor.x); + qemu_get_be32s(f, &s->cursor.y); + qemu_get_be32s(f, &s->cursor.on); + qemu_get_be32s(f, &s->index); + qemu_get_buffer(f, (uint8_t *) s->scratch, s->scratch_size * 4); + qemu_get_be32s(f, &s->new_width); + qemu_get_be32s(f, &s->new_height); + qemu_get_be32s(f, &s->guest); + qemu_get_be32s(f, &s->svgaid); + qemu_get_be32s(f, &s->syncing); + qemu_get_be32s(f, &s->fb_size); + + if (s->enable && depth != s->depth) { + printf("%s: need colour depth of %i bits to resume operation.\n", + __FUNCTION__, depth); + return -EINVAL; + } + + s->invalidated = 1; + if (s->config) + s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE]; + + return 0; +} + +static void vmsvga_init(struct vmsvga_state_s *s, DisplayState *ds, + uint8_t *vga_ram_base, unsigned long vga_ram_offset, + int vga_ram_size) +{ + int iomemtype; + s->ds = ds; + s->vram = vga_ram_base; + s->vram_size = vga_ram_size; + + s->scratch_size = SVGA_SCRATCH_SIZE; + s->scratch = (uint32_t *) qemu_malloc(s->scratch_size * 4); + + vmsvga_reset(s); + +#ifdef DIRECT_VRAM + iomemtype = cpu_register_io_memory(0, vmsvga_vram_read, + vmsvga_vram_write, s); +#else + iomemtype = vga_ram_offset | IO_MEM_RAM; +#endif + cpu_register_physical_memory(SVGA_MEM_BASE, vga_ram_size, + iomemtype); + + register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT, + 1, 4, vmsvga_index_read, s); + register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT, + 1, 4, vmsvga_index_write, s); + register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT, + 1, 4, vmsvga_value_read, s); + register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT, + 1, 4, vmsvga_value_write, s); + register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT, + 1, 4, vmsvga_bios_read, s); + register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT, + 1, 4, vmsvga_bios_write, s); + + graphic_console_init(ds, vmsvga_update_display, + vmsvga_invalidate_display, vmsvga_screen_dump, s); + +#ifdef EMBED_STDVGA + vga_common_init((VGAState *) s, ds, + vga_ram_base, vga_ram_offset, vga_ram_size); + vga_init((VGAState *) s); +#endif +} + +static void pci_vmsvga_save(QEMUFile *f, void *opaque) +{ + struct pci_vmsvga_state_s *s = (struct pci_vmsvga_state_s *) opaque; + pci_device_save(&s->card, f); + vmsvga_save(&s->chip, f); +} + +static int pci_vmsvga_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pci_vmsvga_state_s *s = (struct pci_vmsvga_state_s *) opaque; + int ret; + + ret = pci_device_load(&s->card, f); + if (ret < 0) + return ret; + + ret = vmsvga_load(&s->chip, f); + if (ret < 0) + return ret; + + return 0; +} + +#define PCI_VENDOR_ID_VMWARE 0x15ad +#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 +#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 +#define PCI_DEVICE_ID_VMWARE_NET 0x0720 +#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 +#define PCI_DEVICE_ID_VMWARE_IDE 0x1729 +#define PCI_CLASS_BASE_DISPLAY 0x03 +#define PCI_CLASS_SUB_VGA 0x00 +#define PCI_CLASS_HEADERTYPE_00h 0x00 + +void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size) +{ + struct pci_vmsvga_state_s *s; + + /* Setup PCI configuration */ + s = (struct pci_vmsvga_state_s *) + pci_register_device(bus, "QEMUware SVGA", + sizeof(struct pci_vmsvga_state_s), -1, 0, 0); + s->card.config[PCI_VENDOR_ID] = PCI_VENDOR_ID_VMWARE & 0xff; + s->card.config[PCI_VENDOR_ID + 1] = PCI_VENDOR_ID_VMWARE >> 8; + s->card.config[PCI_DEVICE_ID] = SVGA_PCI_DEVICE_ID & 0xff; + s->card.config[PCI_DEVICE_ID + 1] = SVGA_PCI_DEVICE_ID >> 8; + s->card.config[PCI_COMMAND] = 0x07; /* I/O + Memory */ + s->card.config[PCI_CLASS_DEVICE] = PCI_CLASS_SUB_VGA; + s->card.config[0x0b] = PCI_CLASS_BASE_DISPLAY; + s->card.config[0x0c] = 0x08; /* Cache line size */ + s->card.config[0x0d] = 0x40; /* Latency timer */ + s->card.config[0x0e] = PCI_CLASS_HEADERTYPE_00h; + s->card.config[0x10] = ((SVGA_IO_BASE >> 0) & 0xff) | 1; + s->card.config[0x11] = (SVGA_IO_BASE >> 8) & 0xff; + s->card.config[0x12] = (SVGA_IO_BASE >> 16) & 0xff; + s->card.config[0x13] = (SVGA_IO_BASE >> 24) & 0xff; + s->card.config[0x18] = (SVGA_MEM_BASE >> 0) & 0xff; + s->card.config[0x19] = (SVGA_MEM_BASE >> 8) & 0xff; + s->card.config[0x1a] = (SVGA_MEM_BASE >> 16) & 0xff; + s->card.config[0x1b] = (SVGA_MEM_BASE >> 24) & 0xff; + s->card.config[0x2c] = PCI_VENDOR_ID_VMWARE & 0xff; + s->card.config[0x2d] = PCI_VENDOR_ID_VMWARE >> 8; + s->card.config[0x2e] = SVGA_PCI_DEVICE_ID & 0xff; + s->card.config[0x2f] = SVGA_PCI_DEVICE_ID >> 8; + s->card.config[0x3c] = 0xff; /* End */ + + vmsvga_init(&s->chip, ds, vga_ram_base, vga_ram_offset, vga_ram_size); + + register_savevm("vmware_vga", 0, 0, pci_vmsvga_save, pci_vmsvga_load, s); +} diff --git a/sdl.c b/sdl.c index aa5c66992..a8dbc2c73 100644 --- a/sdl.c +++ b/sdl.c @@ -44,6 +44,9 @@ static int width, height; static SDL_Cursor *sdl_cursor_normal; static SDL_Cursor *sdl_cursor_hidden; static int absolute_enabled = 0; +static int guest_cursor = 0; +static int guest_x, guest_y; +static SDL_Cursor *guest_sprite = 0; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { @@ -245,13 +248,21 @@ static void sdl_show_cursor(void) { if (!kbd_mouse_is_absolute()) { SDL_ShowCursor(1); - SDL_SetCursor(sdl_cursor_normal); + if (guest_cursor && + (gui_grab || kbd_mouse_is_absolute() || absolute_enabled)) + SDL_SetCursor(guest_sprite); + else + SDL_SetCursor(sdl_cursor_normal); } } static void sdl_grab_start(void) { - sdl_hide_cursor(); + if (guest_cursor) { + SDL_SetCursor(guest_sprite); + SDL_WarpMouse(guest_x, guest_y); + } else + sdl_hide_cursor(); SDL_WM_GrabInput(SDL_GRAB_ON); /* dummy read to avoid moving the mouse */ SDL_GetRelativeMouseState(NULL, NULL); @@ -262,8 +273,8 @@ static void sdl_grab_start(void) static void sdl_grab_end(void) { SDL_WM_GrabInput(SDL_GRAB_OFF); - sdl_show_cursor(); gui_grab = 0; + sdl_show_cursor(); sdl_update_caption(); } @@ -294,6 +305,12 @@ static void sdl_send_mouse_event(int dz) } else if (absolute_enabled) { sdl_show_cursor(); absolute_enabled = 0; + } else if (guest_cursor) { + SDL_GetMouseState(&dx, &dy); + dx -= guest_x; + dy -= guest_y; + guest_x += dx; + guest_y += dy; } kbd_mouse_event(dx, dy, dz, buttons); @@ -472,8 +489,77 @@ static void sdl_refresh(DisplayState *ds) } } +static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c) +{ + SDL_Rect dst = { x, y, w, h }; + SDL_FillRect(screen, &dst, c); +} + +static void sdl_mouse_warp(int x, int y, int on) +{ + if (on) { + if (!guest_cursor) + sdl_show_cursor(); + if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) { + SDL_SetCursor(guest_sprite); + SDL_WarpMouse(x, y); + } + } else if (gui_grab) + sdl_hide_cursor(); + guest_cursor = on; + guest_x = x, guest_y = y; +} + +static void sdl_mouse_define(int width, int height, int bpp, + int hot_x, int hot_y, + uint8_t *image, uint8_t *mask) +{ + uint8_t sprite[256], *line; + int x, y, dst, bypl, src = 0; + if (guest_sprite) + SDL_FreeCursor(guest_sprite); + + memset(sprite, 0, 256); + bypl = ((width * bpp + 31) >> 5) << 2; + for (y = 0, dst = 0; y < height; y ++, image += bypl) { + line = image; + for (x = 0; x < width; x ++, dst ++) { + switch (bpp) { + case 24: + src = *(line ++); src |= *(line ++); src |= *(line ++); + break; + case 16: + case 15: + src = *(line ++); src |= *(line ++); + break; + case 8: + src = *(line ++); + break; + case 4: + src = 0xf & (line[x >> 1] >> ((x & 1)) << 2); + break; + case 2: + src = 3 & (line[x >> 2] >> ((x & 3)) << 1); + break; + case 1: + src = 1 & (line[x >> 3] >> (x & 7)); + break; + } + if (!src) + sprite[dst >> 3] |= (1 << (~dst & 7)) & mask[dst >> 3]; + } + } + guest_sprite = SDL_CreateCursor(sprite, mask, width, height, hot_x, hot_y); + + if (guest_cursor && + (gui_grab || kbd_mouse_is_absolute() || absolute_enabled)) + SDL_SetCursor(guest_sprite); +} + static void sdl_cleanup(void) { + if (guest_sprite) + SDL_FreeCursor(guest_sprite); SDL_Quit(); } @@ -510,6 +596,9 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) ds->dpy_update = sdl_update; ds->dpy_resize = sdl_resize; ds->dpy_refresh = sdl_refresh; + ds->dpy_fill = sdl_fill; + ds->mouse_set = sdl_mouse_warp; + ds->cursor_define = sdl_mouse_define; sdl_resize(ds, 640, 400); sdl_update_caption(); diff --git a/vl.c b/vl.c index eee74d6a8..487c4a8d9 100644 --- a/vl.c +++ b/vl.c @@ -154,6 +154,7 @@ QEMUTimer *gui_timer; int vm_running; int rtc_utc = 1; int cirrus_vga_enabled = 1; +int vmsvga_enabled = 0; #ifdef TARGET_SPARC int graphic_width = 1024; int graphic_height = 768; @@ -543,6 +544,10 @@ int kbd_mouse_is_absolute(void) return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute; } +void (*kbd_mouse_set)(int x, int y, int on) = NULL; +void (*kbd_cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, + uint8_t *image, uint8_t *mask) = NULL; + void do_info_mice(void) { QEMUPutMouseEntry *cursor; @@ -6509,6 +6514,7 @@ enum { QEMU_OPTION_k, QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, + QEMU_OPTION_vmsvga, QEMU_OPTION_g, QEMU_OPTION_std_vga, QEMU_OPTION_echr, @@ -6616,6 +6622,7 @@ const QEMUOption qemu_options[] = { /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, + { "vmwarevga", 0, QEMU_OPTION_vmsvga }, { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "no-reboot", 0, QEMU_OPTION_no_reboot }, { "daemonize", 0, QEMU_OPTION_daemonize }, @@ -7184,9 +7191,15 @@ int main(int argc, char **argv) break; case QEMU_OPTION_cirrusvga: cirrus_vga_enabled = 1; + vmsvga_enabled = 0; + break; + case QEMU_OPTION_vmsvga: + cirrus_vga_enabled = 0; + vmsvga_enabled = 1; break; case QEMU_OPTION_std_vga: cirrus_vga_enabled = 0; + vmsvga_enabled = 0; break; case QEMU_OPTION_g: { diff --git a/vl.h b/vl.h index 2fbfa7fc1..d27b7115a 100644 --- a/vl.h +++ b/vl.h @@ -149,6 +149,7 @@ extern int ram_size; extern int bios_size; extern int rtc_utc; extern int cirrus_vga_enabled; +extern int vmsvga_enabled; extern int graphic_width; extern int graphic_height; extern int graphic_depth; @@ -903,7 +904,13 @@ struct DisplayState { void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); void (*dpy_resize)(struct DisplayState *s, int w, int h); void (*dpy_refresh)(struct DisplayState *s); - void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h); + void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, + int dst_x, int dst_y, int w, int h); + void (*dpy_fill)(struct DisplayState *s, int x, int y, + int w, int h, uint32_t c); + void (*mouse_set)(int x, int y, int on); + void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, + uint8_t *image, uint8_t *mask); }; static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) @@ -928,6 +935,10 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); +/* vmware_vga.c */ +void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); + /* sdl.c */ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); -- cgit v1.2.3 From 687fa640d49ce19b9b9a2258fde19e1500bfabb4 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 08:18:36 +0000 Subject: Random bug fixes from code inspection, by Wang Cheng Yeh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2580 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lsi53c895a.c | 1 + hw/smc91c111.c | 6 +++--- target-arm/translate.c | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 07e09f3cc..193ff1220 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1046,6 +1046,7 @@ again: case 5: /* SHR */ op1 = op0 & 1; op0 = (op0 >> 1) | (s->carry << 7); + s->carry = op1; break; case 6: /* ADD */ op0 += op1; diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 0249cfe98..855a9b1f1 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -446,7 +446,9 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) case 7: /* Not implemented. */ return 0; - case 8: /* Free memory available. */ + case 8: /* Memory size. */ + return NUM_PACKETS; + case 9: /* Free memory available. */ { int i; int n; @@ -457,8 +459,6 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) } return n; } - case 9: /* Memory size. */ - return NUM_PACKETS; case 10: case 11: /* RPCR */ /* Not implemented. */ return 0; diff --git a/target-arm/translate.c b/target-arm/translate.c index 4cb9142f4..1631fcd31 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2583,8 +2583,8 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, " "); } psr = cpsr_read(env); - cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d %x\n", - psr, + cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n", + psr, psr & (1 << 31) ? 'N' : '-', psr & (1 << 30) ? 'Z' : '-', psr & (1 << 29) ? 'C' : '-', -- cgit v1.2.3 From 28c1c656333251dd68c125fcf27d454bb1b94612 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 08:19:57 +0000 Subject: ne2k buffer full bug fix, by Marcel Block. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2581 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index a045a2043..df3f3b54a 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -206,7 +206,7 @@ static int ne2000_buffer_full(NE2000State *s) index = s->curpag << 8; boundary = s->boundary << 8; - if (index <= boundary) + if (index < boundary) avail = boundary - index; else avail = (s->stop - s->start) - (index - boundary); -- cgit v1.2.3 From b0ee3ff06e54a30b1540c08507b873a00192aa0e Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 08:56:24 +0000 Subject: ltr for x86_64 should check the upper descriptor type, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2582 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 70370fca2..aa136707e 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1864,8 +1864,11 @@ void helper_ltr_T0(void) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - uint32_t e3; + uint32_t e3, e4; e3 = ldl_kernel(ptr + 8); + e4 = ldl_kernel(ptr + 12); + if ((e4 >> DESC_TYPE_SHIFT) & 0xf) + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); load_seg_cache_raw_dt(&env->tr, e1, e2); env->tr.base |= (target_ulong)e3 << 32; } else -- cgit v1.2.3 From f0c757e431fa48248a411dc07dea98ce9be6a537 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 10:07:55 +0000 Subject: audio/ossaudio.c for OpenBSD, by Todd T. Fries. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2583 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/ossaudio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 125e4c8ff..cedcea45f 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -21,10 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include #include #include +#ifdef __OpenBSD__ +#include +#else #include +#endif #include "vl.h" #define AUDIO_CAP "oss" -- cgit v1.2.3 From 663e8e5164e0f9ad38e12d91de89d553d89060d2 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 12:35:34 +0000 Subject: Eepro100 emulation, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2584 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 8 +- hw/eepro100.c | 1714 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/eeprom93xx.c | 312 ++++++++++ hw/eeprom93xx.h | 43 ++ hw/pci.c | 6 + vl.h | 6 + 6 files changed, 2088 insertions(+), 1 deletion(-) create mode 100644 hw/eepro100.c create mode 100644 hw/eeprom93xx.c create mode 100644 hw/eeprom93xx.h diff --git a/Makefile.target b/Makefile.target index f1fbc578d..323961a73 100644 --- a/Makefile.target +++ b/Makefile.target @@ -395,8 +395,14 @@ 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 +# EEPROM emulation +VL_OBJS += eeprom93xx.o + # PCI network cards -VL_OBJS+= ne2000.o rtl8139.o pcnet.o +VL_OBJS += eepro100.o +VL_OBJS += ne2000.o +VL_OBJS += pcnet.o +VL_OBJS += rtl8139.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support diff --git a/hw/eepro100.c b/hw/eepro100.c new file mode 100644 index 000000000..ea18b890d --- /dev/null +++ b/hw/eepro100.c @@ -0,0 +1,1714 @@ +/* + * QEMU i8255x (PRO100) emulation + * + * Copyright (c) 2006-2007 Stefan Weil + * + * Portions of the code are copies from grub / etherboot eepro100.c + * and linux e100.c. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Tested features (i82559): + * PXE boot (i386) no valid link + * Linux networking (i386) ok + * + * Untested: + * non-i386 platforms + * Windows networking + * + * References: + * + * Intel 8255x 10/100 Mbps Ethernet Controller Family + * Open Source Software Developer Manual + */ + +#if defined(TARGET_I386) +# warning "PXE boot still not working!" +#endif + +#include +#include /* offsetof */ +#include "vl.h" +#include "eeprom93xx.h" + +/* Common declarations for all PCI devices. */ + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_STATUS 0x06 /* 16 bits */ + +#define PCI_REVISION_ID 0x08 /* 8 bits */ +#define PCI_CLASS_CODE 0x0b /* 8 bits */ +#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */ +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ + +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ +#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */ +#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */ +#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ +#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ +#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ + +#define PCI_CONFIG_8(offset, value) \ + (pci_conf[offset] = (value)) +#define PCI_CONFIG_16(offset, value) \ + (*(uint16_t *)&pci_conf[offset] = cpu_to_le16(value)) +#define PCI_CONFIG_32(offset, value) \ + (*(uint32_t *)&pci_conf[offset] = cpu_to_le32(value)) + +#define KiB 1024 + +/* debug EEPRO100 card */ +//~ #define DEBUG_EEPRO100 + +#ifdef DEBUG_EEPRO100 +#define logout(fmt, args...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ##args) +#else +#define logout(fmt, args...) ((void)0) +#endif + +/* Set flags to 0 to disable debug output. */ +#define MDI 0 + +#define TRACE(flag, command) ((flag) ? (command) : (void)0) + +#define missing(text) assert(!"feature is missing in this emulation: " text) + +#define MAX_ETH_FRAME_SIZE 1514 + +/* This driver supports several different devices which are declared here. */ +#define i82551 0x82551 +#define i82557B 0x82557b +#define i82557C 0x82557c +#define i82558B 0x82558b +#define i82559C 0x82559c +#define i82559ER 0x82559e +#define i82562 0x82562 + +#define EEPROM_SIZE 64 + +#define PCI_MEM_SIZE (4 * KiB) +#define PCI_IO_SIZE 64 +#define PCI_FLASH_SIZE (128 * KiB) + +#define BIT(n) (1 << (n)) +#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m) + +/* The SCB accepts the following controls for the Tx and Rx units: */ +#define CU_NOP 0x0000 /* No operation. */ +#define CU_START 0x0010 /* CU start. */ +#define CU_RESUME 0x0020 /* CU resume. */ +#define CU_STATSADDR 0x0040 /* Load dump counters address. */ +#define CU_SHOWSTATS 0x0050 /* Dump statistical counters. */ +#define CU_CMD_BASE 0x0060 /* Load CU base address. */ +#define CU_DUMPSTATS 0x0070 /* Dump and reset statistical counters. */ +#define CU_SRESUME 0x00a0 /* CU static resume. */ + +#define RU_NOP 0x0000 +#define RX_START 0x0001 +#define RX_RESUME 0x0002 +#define RX_ABORT 0x0004 +#define RX_ADDR_LOAD 0x0006 +#define RX_RESUMENR 0x0007 +#define INT_MASK 0x0100 +#define DRVR_INT 0x0200 /* Driver generated interrupt. */ + +typedef unsigned char bool; + +/* Offsets to the various registers. + All accesses need not be longword aligned. */ +enum speedo_offsets { + SCBStatus = 0, + SCBAck = 1, + SCBCmd = 2, /* Rx/Command Unit command and status. */ + SCBIntmask = 3, + SCBPointer = 4, /* General purpose pointer. */ + SCBPort = 8, /* Misc. commands and operands. */ + SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ + SCBCtrlMDI = 16, /* MDI interface control. */ + SCBEarlyRx = 20, /* Early receive byte count. */ +}; + +/* A speedo3 transmit buffer descriptor with two buffers... */ +typedef struct { + uint16_t status; + uint16_t command; + uint32_t link; /* void * */ + uint32_t tx_desc_addr; /* transmit buffer decsriptor array address. */ + uint16_t tcb_bytes; /* transmit command block byte count (in lower 14 bits */ + uint8_t tx_threshold; /* transmit threshold */ + uint8_t tbd_count; /* TBD number */ + //~ /* This constitutes two "TBD" entries: hdr and data */ + //~ uint32_t tx_buf_addr0; /* void *, header of frame to be transmitted. */ + //~ int32_t tx_buf_size0; /* Length of Tx hdr. */ + //~ uint32_t tx_buf_addr1; /* void *, data to be transmitted. */ + //~ int32_t tx_buf_size1; /* Length of Tx data. */ +} eepro100_tx_t; + +/* Receive frame descriptor. */ +typedef struct { + int16_t status; + uint16_t command; + uint32_t link; /* struct RxFD * */ + uint32_t rx_buf_addr; /* void * */ + uint16_t count; + uint16_t size; + char packet[MAX_ETH_FRAME_SIZE + 4]; +} eepro100_rx_t; + +typedef struct { + uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions, + tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, + tx_multiple_collisions, tx_total_collisions; + uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors, + rx_resource_errors, rx_overrun_errors, rx_cdt_errors, + rx_short_frame_errors; + uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; + uint16_t xmt_tco_frames, rcv_tco_frames; + uint32_t complete; +} eepro100_stats_t; + +typedef enum { + cu_idle = 0, + cu_suspended = 1, + cu_active = 2, + cu_lpq_active = 2, + cu_hqp_active = 3 +} cu_state_t; + +typedef enum { + ru_idle = 0, + ru_suspended = 1, + ru_no_resources = 2, + ru_ready = 4 +} ru_state_t; + +#if defined(__BIG_ENDIAN_BITFIELD) +#define X(a,b) b,a +#else +#define X(a,b) a,b +#endif + +typedef struct { +#if 1 + uint8_t cmd; + uint32_t start; + uint32_t stop; + uint8_t boundary; + uint8_t tsr; + uint8_t tpsr; + uint16_t tcnt; + uint16_t rcnt; + uint32_t rsar; + uint8_t rsr; + uint8_t rxcr; + uint8_t isr; + uint8_t dcfg; + uint8_t imr; + uint8_t phys[6]; /* mac address */ + uint8_t curpag; + uint8_t mult[8]; /* multicast mask array */ + int mmio_index; + PCIDevice *pci_dev; + VLANClientState *vc; +#endif + uint8_t scb_stat; /* SCB stat/ack byte */ + uint8_t int_stat; /* PCI interrupt status */ + uint32_t region[3]; /* PCI region addresses */ + uint8_t macaddr[6]; + uint32_t statcounter[19]; + uint16_t mdimem[32]; + eeprom_t *eeprom; + uint32_t device; /* device variant */ + uint32_t pointer; + /* (cu_base + cu_offset) address the next command block in the command block list. */ + uint32_t cu_base; /* CU base address */ + uint32_t cu_offset; /* CU address offset */ + /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */ + uint32_t ru_base; /* RU base address */ + uint32_t ru_offset; /* RU address offset */ + uint32_t statsaddr; /* pointer to eepro100_stats_t */ + eepro100_stats_t statistics; /* statistical counters */ +#if 0 + uint16_t status; +#endif + + /* Configuration bytes. */ + uint8_t configuration[22]; + + /* Data in mem is always in the byte order of the controller (le). */ + uint8_t mem[PCI_MEM_SIZE]; +} EEPRO100State; + +/* Default values for MDI (PHY) registers */ +static const uint16_t eepro100_mdi_default[] = { + /* MDI Registers 0 - 6, 7 */ + 0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000, + /* MDI Registers 8 - 15 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* MDI Registers 16 - 31 */ + 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +/* Readonly mask for MDI (PHY) registers */ +static const uint16_t eepro100_mdi_mask[] = { + 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +#define POLYNOMIAL 0x04c11db6 + +/* From FreeBSD */ +/* XXX: optimize */ +static int compute_mcast_idx(const uint8_t * ep) +{ + uint32_t crc; + int carry, i, j; + uint8_t b; + + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + b = *ep++; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); + crc <<= 1; + b >>= 1; + if (carry) + crc = ((crc ^ POLYNOMIAL) | carry); + } + } + return (crc >> 26); +} + +#if defined(DEBUG_EEPRO100) +static const char *nic_dump(const uint8_t * buf, unsigned size) +{ + static char dump[3 * 16 + 1]; + char *p = &dump[0]; + if (size > 16) + size = 16; + while (size-- > 0) { + p += sprintf(p, " %02x", *buf++); + } + return dump; +} +#endif /* DEBUG_EEPRO100 */ + +enum scb_stat_ack { + stat_ack_not_ours = 0x00, + stat_ack_sw_gen = 0x04, + stat_ack_rnr = 0x10, + stat_ack_cu_idle = 0x20, + stat_ack_frame_rx = 0x40, + stat_ack_cu_cmd_done = 0x80, + stat_ack_not_present = 0xFF, + stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx), + stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done), +}; + +static void disable_interrupt(EEPRO100State * s) +{ + if (s->int_stat) { + logout("interrupt disabled\n"); + pci_set_irq(s->pci_dev, 0, 0); + s->int_stat = 0; + } +} + +static void enable_interrupt(EEPRO100State * s) +{ + if (!s->int_stat) { + logout("interrupt enabled\n"); + pci_set_irq(s->pci_dev, 0, 1); + s->int_stat = 1; + } +} + +static void eepro100_acknowledge(EEPRO100State * s) +{ + s->scb_stat &= ~s->mem[SCBAck]; + s->mem[SCBAck] = s->scb_stat; + if (s->scb_stat == 0) { + disable_interrupt(s); + } +} + +static void eepro100_interrupt(EEPRO100State * s, uint8_t stat) +{ + uint8_t mask = ~s->mem[SCBIntmask]; + s->mem[SCBAck] |= stat; + stat = s->scb_stat = s->mem[SCBAck]; + stat &= (mask | 0x0f); + //~ stat &= (~s->mem[SCBIntmask] | 0x0xf); + if (stat && (mask & 0x01)) { + /* SCB mask and SCB Bit M do not disable interrupt. */ + enable_interrupt(s); + } else if (s->int_stat) { + disable_interrupt(s); + } +} + +static void eepro100_cx_interrupt(EEPRO100State * s) +{ + /* CU completed action command. */ + /* Transmit not ok (82557 only, not in emulation). */ + eepro100_interrupt(s, 0x80); +} + +static void eepro100_cna_interrupt(EEPRO100State * s) +{ + /* CU left the active state. */ + eepro100_interrupt(s, 0x20); +} + +static void eepro100_fr_interrupt(EEPRO100State * s) +{ + /* RU received a complete frame. */ + eepro100_interrupt(s, 0x40); +} + +#if 0 +static void eepro100_rnr_interrupt(EEPRO100State * s) +{ + /* RU is not ready. */ + eepro100_interrupt(s, 0x10); +} +#endif + +static void eepro100_mdi_interrupt(EEPRO100State * s) +{ + /* MDI completed read or write cycle. */ + eepro100_interrupt(s, 0x08); +} + +static void eepro100_swi_interrupt(EEPRO100State * s) +{ + /* Software has requested an interrupt. */ + eepro100_interrupt(s, 0x04); +} + +#if 0 +static void eepro100_fcp_interrupt(EEPRO100State * s) +{ + /* Flow control pause interrupt (82558 and later). */ + eepro100_interrupt(s, 0x01); +} +#endif + +static void pci_reset(EEPRO100State * s) +{ + uint32_t device = s->device; + uint8_t *pci_conf = s->pci_dev->config; + + logout("%p\n", s); + + /* PCI Vendor ID */ + PCI_CONFIG_16(PCI_VENDOR_ID, 0x8086); + /* PCI Device ID */ + PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209); + /* PCI Command */ + PCI_CONFIG_16(PCI_COMMAND, 0x0000); + /* PCI Status */ + PCI_CONFIG_16(PCI_STATUS, 0x2800); + /* PCI Revision ID */ + PCI_CONFIG_8(PCI_REVISION_ID, 0x08); + /* PCI Class Code */ + PCI_CONFIG_8(0x09, 0x00); + PCI_CONFIG_8(PCI_SUBCLASS_CODE, 0x00); // ethernet network controller + PCI_CONFIG_8(PCI_CLASS_CODE, 0x02); // network controller + /* PCI Cache Line Size */ + /* check cache line size!!! */ + //~ PCI_CONFIG_8(0x0c, 0x00); + /* PCI Latency Timer */ + PCI_CONFIG_8(0x0d, 0x20); // latency timer = 32 clocks + /* PCI Header Type */ + /* BIST (built-in self test) */ +#if defined(TARGET_I386) +// !!! workaround for buggy bios +//~ #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0 +#endif +#if 0 + /* PCI Base Address Registers */ + /* CSR Memory Mapped Base Address */ + PCI_CONFIG_32(PCI_BASE_ADDRESS_0, + PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH); + /* CSR I/O Mapped Base Address */ + PCI_CONFIG_32(PCI_BASE_ADDRESS_1, PCI_ADDRESS_SPACE_IO); +#if 0 + /* Flash Memory Mapped Base Address */ + PCI_CONFIG_32(PCI_BASE_ADDRESS_2, 0xfffe0000 | PCI_ADDRESS_SPACE_MEM); +#endif +#endif + /* Expansion ROM Base Address (depends on boot disable!!!) */ + PCI_CONFIG_32(0x30, 0x00000000); + /* Capability Pointer */ + PCI_CONFIG_8(0x34, 0xdc); + /* Interrupt Pin */ + PCI_CONFIG_8(0x3d, 1); // interrupt pin 0 + /* Minimum Grant */ + PCI_CONFIG_8(0x3e, 0x08); + /* Maximum Latency */ + PCI_CONFIG_8(0x3f, 0x18); + /* Power Management Capabilities / Next Item Pointer / Capability ID */ + PCI_CONFIG_32(0xdc, 0x7e210001); + + switch (device) { + case i82551: + //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209); + PCI_CONFIG_8(PCI_REVISION_ID, 0x0f); + break; + case i82557B: + PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229); + PCI_CONFIG_8(PCI_REVISION_ID, 0x02); + break; + case i82557C: + PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229); + PCI_CONFIG_8(PCI_REVISION_ID, 0x03); + break; + case i82558B: + PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229); + PCI_CONFIG_16(PCI_STATUS, 0x2810); + PCI_CONFIG_8(PCI_REVISION_ID, 0x05); + break; + case i82559C: + PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229); + PCI_CONFIG_16(PCI_STATUS, 0x2810); + //~ PCI_CONFIG_8(PCI_REVISION_ID, 0x08); + break; + case i82559ER: + //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209); + PCI_CONFIG_16(PCI_STATUS, 0x2810); + PCI_CONFIG_8(PCI_REVISION_ID, 0x09); + break; + //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1029); + //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1030); /* 82559 InBusiness 10/100 */ + default: + logout("Device %X is undefined!\n", device); + } + + if (device == i82557C || device == i82558B || device == i82559C) { + logout("Get device id and revision from EEPROM!!!\n"); + } +} + +static void nic_selective_reset(EEPRO100State * s) +{ + size_t i; + uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom); + //~ eeprom93xx_reset(s->eeprom); + memcpy(eeprom_contents, s->macaddr, 6); + eeprom_contents[0xa] = 0x4000; + uint16_t sum = 0; + for (i = 0; i < EEPROM_SIZE - 1; i++) { + sum += eeprom_contents[i]; + } + eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum; + + memset(s->mem, 0, sizeof(s->mem)); + uint32_t val = BIT(21); + memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val)); + + assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default)); + memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem)); +} + +static void nic_reset(void *opaque) +{ + EEPRO100State *s = (EEPRO100State *) opaque; + logout("%p\n", s); + static int first; + if (!first) { + first = 1; + } + nic_selective_reset(s); +} + +#if defined(DEBUG_EEPRO100) +static const char *reg[PCI_IO_SIZE / 4] = { + "Command/Status", + "General Pointer", + "Port", + "EEPROM/Flash Control", + "MDI Control", + "Receive DMA Byte Count", + "Flow control register", + "General Status/Control" +}; + +static char *regname(uint32_t addr) +{ + static char buf[16]; + if (addr < PCI_IO_SIZE) { + const char *r = reg[addr / 4]; + if (r != 0) { + sprintf(buf, "%s+%u", r, addr % 4); + } else { + sprintf(buf, "0x%02x", addr); + } + } else { + sprintf(buf, "??? 0x%08x", addr); + } + return buf; +} +#endif /* DEBUG_EEPRO100 */ + +#if 0 +static uint16_t eepro100_read_status(EEPRO100State * s) +{ + uint16_t val = s->status; + logout("val=0x%04x\n", val); + return val; +} + +static void eepro100_write_status(EEPRO100State * s, uint16_t val) +{ + logout("val=0x%04x\n", val); + s->status = val; +} +#endif + +/***************************************************************************** + * + * Command emulation. + * + ****************************************************************************/ + +#if 0 +static uint16_t eepro100_read_command(EEPRO100State * s) +{ + uint16_t val = 0xffff; + //~ logout("val=0x%04x\n", val); + return val; +} +#endif + +/* Commands that can be put in a command list entry. */ +enum commands { + CmdNOp = 0, + CmdIASetup = 1, + CmdConfigure = 2, + CmdMulticastList = 3, + CmdTx = 4, + CmdTDR = 5, /* load microcode */ + CmdDump = 6, + CmdDiagnose = 7, + + /* And some extra flags: */ + CmdSuspend = 0x4000, /* Suspend after completion. */ + CmdIntr = 0x2000, /* Interrupt after completion. */ + CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */ +}; + +static cu_state_t get_cu_state(EEPRO100State * s) +{ + return ((s->mem[SCBStatus] >> 6) & 0x03); +} + +static void set_cu_state(EEPRO100State * s, cu_state_t state) +{ + s->mem[SCBStatus] = (s->mem[SCBStatus] & 0x3f) + (state << 6); +} + +static ru_state_t get_ru_state(EEPRO100State * s) +{ + return ((s->mem[SCBStatus] >> 2) & 0x0f); +} + +static void set_ru_state(EEPRO100State * s, ru_state_t state) +{ + s->mem[SCBStatus] = (s->mem[SCBStatus] & 0xc3) + (state << 2); +} + +static void dump_statistics(EEPRO100State * s) +{ + /* Dump statistical data. Most data is never changed by the emulation + * and always 0, so we first just copy the whole block and then those + * values which really matter. + * Number of data should check configuration!!! + */ + cpu_physical_memory_write(s->statsaddr, (uint8_t *) & s->statistics, 64); + stl_phys(s->statsaddr + 0, s->statistics.tx_good_frames); + stl_phys(s->statsaddr + 36, s->statistics.rx_good_frames); + stl_phys(s->statsaddr + 48, s->statistics.rx_resource_errors); + stl_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors); + //~ stw_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames); + //~ stw_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames); + //~ missing("CU dump statistical counters"); +} + +static void eepro100_cu_command(EEPRO100State * s, uint8_t val) +{ + eepro100_tx_t tx; + uint32_t cb_address; + switch (val) { + case CU_NOP: + /* No operation. */ + break; + case CU_START: + if (get_cu_state(s) != cu_idle) { + /* Intel documentation says that CU must be idle for the CU + * start command. Intel driver for Linux also starts the CU + * from suspended state. */ + logout("CU state is %u, should be %u\n", get_cu_state(s), cu_idle); + //~ assert(!"wrong CU state"); + } + set_cu_state(s, cu_active); + s->cu_offset = s->pointer; + next_command: + cb_address = s->cu_base + s->cu_offset; + cpu_physical_memory_read(cb_address, (uint8_t *) & tx, sizeof(tx)); + uint16_t status = le16_to_cpu(tx.status); + uint16_t command = le16_to_cpu(tx.command); + logout + ("val=0x%02x (cu start), status=0x%04x, command=0x%04x, link=0x%08x\n", + val, status, command, tx.link); + bool bit_el = ((command & 0x8000) != 0); + bool bit_s = ((command & 0x4000) != 0); + bool bit_i = ((command & 0x2000) != 0); + bool bit_nc = ((command & 0x0010) != 0); + //~ bool bit_sf = ((command & 0x0008) != 0); + uint16_t cmd = command & 0x0007; + s->cu_offset = le32_to_cpu(tx.link); + switch (cmd) { + case CmdNOp: + /* Do nothing. */ + break; + case CmdIASetup: + cpu_physical_memory_read(cb_address + 8, &s->macaddr[0], 6); + logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6)); + break; + case CmdConfigure: + cpu_physical_memory_read(cb_address + 8, &s->configuration[0], + sizeof(s->configuration)); + logout("configuration: %s\n", nic_dump(&s->configuration[0], 16)); + break; + case CmdMulticastList: + //~ missing("multicast list"); + break; + case CmdTx: + (void)0; + uint32_t tbd_array = le32_to_cpu(tx.tx_desc_addr); + uint16_t tcb_bytes = (le16_to_cpu(tx.tcb_bytes) & 0x3fff); + logout + ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n", + tbd_array, tcb_bytes, tx.tbd_count); + assert(!bit_nc); + //~ assert(!bit_sf); + assert(tcb_bytes <= 2600); + /* Next assertion fails for local configuration. */ + //~ assert((tcb_bytes > 0) || (tbd_array != 0xffffffff)); + if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) { + logout + ("illegal values of TBD array address and TCB byte count!\n"); + } + uint8_t buf[MAX_ETH_FRAME_SIZE + 4]; + uint16_t size = 0; + uint32_t tbd_address = cb_address + 0x10; + assert(tcb_bytes <= sizeof(buf)); + while (size < tcb_bytes) { + uint32_t tx_buffer_address = ldl_phys(tbd_address); + uint16_t tx_buffer_size = lduw_phys(tbd_address + 4); + //~ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6); + tbd_address += 8; + logout + ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n", + tx_buffer_address, tx_buffer_size); + cpu_physical_memory_read(tx_buffer_address, &buf[size], + tx_buffer_size); + size += tx_buffer_size; + } + if (tbd_array == 0xffffffff) { + /* Simplified mode. Was already handled by code above. */ + } else { + /* Flexible mode. */ + uint8_t tbd_count = 0; + if (!(s->configuration[6] & BIT(4))) { + /* Extended TCB. */ + assert(tcb_bytes == 0); + for (; tbd_count < 2; tbd_count++) { + uint32_t tx_buffer_address = ldl_phys(tbd_address); + uint16_t tx_buffer_size = lduw_phys(tbd_address + 4); + uint16_t tx_buffer_el = lduw_phys(tbd_address + 6); + tbd_address += 8; + logout + ("TBD (extended mode): buffer address 0x%08x, size 0x%04x\n", + tx_buffer_address, tx_buffer_size); + cpu_physical_memory_read(tx_buffer_address, &buf[size], + tx_buffer_size); + size += tx_buffer_size; + if (tx_buffer_el & 1) { + break; + } + } + } + tbd_address = tbd_array; + for (; tbd_count < tx.tbd_count; tbd_count++) { + uint32_t tx_buffer_address = ldl_phys(tbd_address); + uint16_t tx_buffer_size = lduw_phys(tbd_address + 4); + uint16_t tx_buffer_el = lduw_phys(tbd_address + 6); + tbd_address += 8; + logout + ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n", + tx_buffer_address, tx_buffer_size); + cpu_physical_memory_read(tx_buffer_address, &buf[size], + tx_buffer_size); + size += tx_buffer_size; + if (tx_buffer_el & 1) { + break; + } + } + } + qemu_send_packet(s->vc, buf, size); + s->statistics.tx_good_frames++; + /* Transmit with bad status would raise an CX/TNO interrupt. + * (82557 only). Emulation never has bad status. */ + //~ eepro100_cx_interrupt(s); + break; + case CmdTDR: + logout("load microcode\n"); + /* Starting with offset 8, the command contains + * 64 dwords microcode which we just ignore here. */ + break; + default: + missing("undefined command"); + } + /* Write new status (success). */ + stw_phys(cb_address, status | 0x8000 | 0x2000); + if (bit_i) { + /* CU completed action. */ + eepro100_cx_interrupt(s); + } + if (bit_el) { + /* CU becomes idle. */ + set_cu_state(s, cu_idle); + eepro100_cna_interrupt(s); + } else if (bit_s) { + /* CU becomes suspended. */ + set_cu_state(s, cu_suspended); + eepro100_cna_interrupt(s); + } else { + /* More entries in list. */ + logout("CU list with at least one more entry\n"); + goto next_command; + } + logout("CU list empty\n"); + /* List is empty. Now CU is idle or suspended. */ + break; + case CU_RESUME: + if (get_cu_state(s) != cu_suspended) { + logout("bad CU resume from CU state %u\n", get_cu_state(s)); + /* Workaround for bad Linux eepro100 driver which resumes + * from idle state. */ + //~ missing("cu resume"); + set_cu_state(s, cu_suspended); + } + if (get_cu_state(s) == cu_suspended) { + logout("CU resuming\n"); + set_cu_state(s, cu_active); + goto next_command; + } + break; + case CU_STATSADDR: + /* Load dump counters address. */ + s->statsaddr = s->pointer; + logout("val=0x%02x (status address)\n", val); + break; + case CU_SHOWSTATS: + /* Dump statistical counters. */ + dump_statistics(s); + break; + case CU_CMD_BASE: + /* Load CU base. */ + logout("val=0x%02x (CU base address)\n", val); + s->cu_base = s->pointer; + break; + case CU_DUMPSTATS: + /* Dump and reset statistical counters. */ + dump_statistics(s); + memset(&s->statistics, 0, sizeof(s->statistics)); + break; + case CU_SRESUME: + /* CU static resume. */ + missing("CU static resume"); + break; + default: + missing("Undefined CU command"); + } +} + +static void eepro100_ru_command(EEPRO100State * s, uint8_t val) +{ + switch (val) { + case RU_NOP: + /* No operation. */ + break; + case RX_START: + /* RU start. */ + if (get_ru_state(s) != ru_idle) { + logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle); + //~ assert(!"wrong RU state"); + } + set_ru_state(s, ru_ready); + s->ru_offset = s->pointer; + logout("val=0x%02x (rx start)\n", val); + break; + case RX_RESUME: + /* Restart RU. */ + if (get_ru_state(s) != ru_suspended) { + logout("RU state is %u, should be %u\n", get_ru_state(s), + ru_suspended); + //~ assert(!"wrong RU state"); + } + set_ru_state(s, ru_ready); + break; + case RX_ADDR_LOAD: + /* Load RU base. */ + logout("val=0x%02x (RU base address)\n", val); + s->ru_base = s->pointer; + break; + default: + logout("val=0x%02x (undefined RU command)\n", val); + missing("Undefined SU command"); + } +} + +static void eepro100_write_command(EEPRO100State * s, uint8_t val) +{ + eepro100_ru_command(s, val & 0x0f); + eepro100_cu_command(s, val & 0xf0); + if ((val) == 0) { + logout("val=0x%02x\n", val); + } + /* Clear command byte after command was accepted. */ + s->mem[SCBCmd] = 0; +} + +/***************************************************************************** + * + * EEPROM emulation. + * + ****************************************************************************/ + +#define EEPROM_CS 0x02 +#define EEPROM_SK 0x01 +#define EEPROM_DI 0x04 +#define EEPROM_DO 0x08 + +static uint16_t eepro100_read_eeprom(EEPRO100State * s) +{ + uint16_t val; + memcpy(&val, &s->mem[SCBeeprom], sizeof(val)); + if (eeprom93xx_read(s->eeprom)) { + val |= EEPROM_DO; + } else { + val &= ~EEPROM_DO; + } + return val; +} + +static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val) +{ + logout("write val=0x%02x\n", val); + + /* mask unwriteable bits */ + //~ val = SET_MASKED(val, 0x31, eeprom->value); + + int eecs = ((val & EEPROM_CS) != 0); + int eesk = ((val & EEPROM_SK) != 0); + int eedi = ((val & EEPROM_DI) != 0); + eeprom93xx_write(eeprom, eecs, eesk, eedi); +} + +static void eepro100_write_pointer(EEPRO100State * s, uint32_t val) +{ + s->pointer = le32_to_cpu(val); + logout("val=0x%08x\n", val); +} + +/***************************************************************************** + * + * MDI emulation. + * + ****************************************************************************/ + +#if defined(DEBUG_EEPRO100) +static const char *mdi_op_name[] = { + "opcode 0", + "write", + "read", + "opcode 3" +}; + +static const char *mdi_reg_name[] = { + "Control", + "Status", + "PHY Identification (Word 1)", + "PHY Identification (Word 2)", + "Auto-Negotiation Advertisement", + "Auto-Negotiation Link Partner Ability", + "Auto-Negotiation Expansion" +}; +#endif /* DEBUG_EEPRO100 */ + +static uint32_t eepro100_read_mdi(EEPRO100State * s) +{ + uint32_t val; + memcpy(&val, &s->mem[0x10], sizeof(val)); + +#ifdef DEBUG_EEPRO100 + uint8_t raiseint = (val & BIT(29)) >> 29; + uint8_t opcode = (val & BITS(27, 26)) >> 26; + uint8_t phy = (val & BITS(25, 21)) >> 21; + uint8_t reg = (val & BITS(20, 16)) >> 16; + uint16_t data = (val & BITS(15, 0)); +#endif + /* Emulation takes no time to finish MDI transaction. */ + val |= BIT(28); + TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n", + val, raiseint, mdi_op_name[opcode], phy, + mdi_reg_name[reg], data)); + return val; +} + +//~ #define BITS(val, upper, lower) (val & ???) +static void eepro100_write_mdi(EEPRO100State * s, uint32_t val) +{ + uint8_t raiseint = (val & BIT(29)) >> 29; + uint8_t opcode = (val & BITS(27, 26)) >> 26; + uint8_t phy = (val & BITS(25, 21)) >> 21; + uint8_t reg = (val & BITS(20, 16)) >> 16; + uint16_t data = (val & BITS(15, 0)); + if (phy != 1) { + /* Unsupported PHY address. */ + //~ logout("phy must be 1 but is %u\n", phy); + data = 0; + } else if (opcode != 1 && opcode != 2) { + /* Unsupported opcode. */ + logout("opcode must be 1 or 2 but is %u\n", opcode); + data = 0; + } else if (reg > 6) { + /* Unsupported register. */ + logout("register must be 0...6 but is %u\n", reg); + data = 0; + } else { + TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n", + val, raiseint, mdi_op_name[opcode], phy, + mdi_reg_name[reg], data)); + if (opcode == 1) { + /* MDI write */ + switch (reg) { + case 0: /* Control Register */ + if (data & 0x8000) { + /* Reset status and control registers to default. */ + s->mdimem[0] = eepro100_mdi_default[0]; + s->mdimem[1] = eepro100_mdi_default[1]; + data = s->mdimem[reg]; + } else { + /* Restart Auto Configuration = Normal Operation */ + data &= ~0x0200; + } + break; + case 1: /* Status Register */ + missing("not writable"); + data = s->mdimem[reg]; + break; + case 2: /* PHY Identification Register (Word 1) */ + case 3: /* PHY Identification Register (Word 2) */ + missing("not implemented"); + break; + case 4: /* Auto-Negotiation Advertisement Register */ + case 5: /* Auto-Negotiation Link Partner Ability Register */ + break; + case 6: /* Auto-Negotiation Expansion Register */ + default: + missing("not implemented"); + } + s->mdimem[reg] = data; + } else if (opcode == 2) { + /* MDI read */ + switch (reg) { + case 0: /* Control Register */ + if (data & 0x8000) { + /* Reset status and control registers to default. */ + s->mdimem[0] = eepro100_mdi_default[0]; + s->mdimem[1] = eepro100_mdi_default[1]; + } + break; + case 1: /* Status Register */ + s->mdimem[reg] |= 0x0020; + break; + case 2: /* PHY Identification Register (Word 1) */ + case 3: /* PHY Identification Register (Word 2) */ + case 4: /* Auto-Negotiation Advertisement Register */ + break; + case 5: /* Auto-Negotiation Link Partner Ability Register */ + s->mdimem[reg] = 0x41fe; + break; + case 6: /* Auto-Negotiation Expansion Register */ + s->mdimem[reg] = 0x0001; + break; + } + data = s->mdimem[reg]; + } + /* Emulation takes no time to finish MDI transaction. + * Set MDI bit in SCB status register. */ + s->mem[SCBAck] |= 0x08; + val |= BIT(28); + if (raiseint) { + eepro100_mdi_interrupt(s); + } + } + val = (val & 0xffff0000) + data; + memcpy(&s->mem[0x10], &val, sizeof(val)); +} + +/***************************************************************************** + * + * Port emulation. + * + ****************************************************************************/ + +#define PORT_SOFTWARE_RESET 0 +#define PORT_SELFTEST 1 +#define PORT_SELECTIVE_RESET 2 +#define PORT_DUMP 3 +#define PORT_SELECTION_MASK 3 + +typedef struct { + uint32_t st_sign; /* Self Test Signature */ + uint32_t st_result; /* Self Test Results */ +} eepro100_selftest_t; + +static uint32_t eepro100_read_port(EEPRO100State * s) +{ + return 0; +} + +static void eepro100_write_port(EEPRO100State * s, uint32_t val) +{ + val = le32_to_cpu(val); + uint32_t address = (val & ~PORT_SELECTION_MASK); + uint8_t selection = (val & PORT_SELECTION_MASK); + switch (selection) { + case PORT_SOFTWARE_RESET: + nic_reset(s); + break; + case PORT_SELFTEST: + logout("selftest address=0x%08x\n", address); + eepro100_selftest_t data; + cpu_physical_memory_read(address, (uint8_t *) & data, sizeof(data)); + data.st_sign = 0xffffffff; + data.st_result = 0; + cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data)); + break; + case PORT_SELECTIVE_RESET: + logout("selective reset, selftest address=0x%08x\n", address); + nic_selective_reset(s); + break; + default: + logout("val=0x%08x\n", val); + missing("unknown port selection"); + } +} + +/***************************************************************************** + * + * General hardware emulation. + * + ****************************************************************************/ + +static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr) +{ + uint8_t val; + if (addr <= sizeof(s->mem) - sizeof(val)) { + memcpy(&val, &s->mem[addr], sizeof(val)); + } + + switch (addr) { + case SCBStatus: + //~ val = eepro100_read_status(s); + logout("addr=%s val=0x%02x\n", regname(addr), val); + break; + case SCBAck: + //~ val = eepro100_read_status(s); + logout("addr=%s val=0x%02x\n", regname(addr), val); + break; + case SCBCmd: + logout("addr=%s val=0x%02x\n", regname(addr), val); + //~ val = eepro100_read_command(s); + break; + case SCBIntmask: + logout("addr=%s val=0x%02x\n", regname(addr), val); + break; + case SCBPort + 3: + logout("addr=%s val=0x%02x\n", regname(addr), val); + break; + case SCBeeprom: + val = eepro100_read_eeprom(s); + break; + case 0x1b: /* PMDR (power management driver register) */ + val = 0; + logout("addr=%s val=0x%02x\n", regname(addr), val); + break; + case 0x1d: /* general status register */ + /* 100 Mbps full duplex, valid link */ + val = 0x07; + logout("addr=General Status val=%02x\n", val); + break; + default: + logout("addr=%s val=0x%02x\n", regname(addr), val); + missing("unknown byte read"); + } + return val; +} + +static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr) +{ + uint16_t val; + if (addr <= sizeof(s->mem) - sizeof(val)) { + memcpy(&val, &s->mem[addr], sizeof(val)); + } + + logout("addr=%s val=0x%04x\n", regname(addr), val); + + switch (addr) { + case SCBStatus: + //~ val = eepro100_read_status(s); + break; + case SCBeeprom: + val = eepro100_read_eeprom(s); + break; + default: + logout("addr=%s val=0x%04x\n", regname(addr), val); + missing("unknown word read"); + } + return val; +} + +static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr) +{ + uint32_t val; + if (addr <= sizeof(s->mem) - sizeof(val)) { + memcpy(&val, &s->mem[addr], sizeof(val)); + } + + switch (addr) { + case SCBStatus: + //~ val = eepro100_read_status(s); + logout("addr=%s val=0x%08x\n", regname(addr), val); + break; + case SCBPointer: + //~ val = eepro100_read_pointer(s); + logout("addr=%s val=0x%08x\n", regname(addr), val); + break; + case SCBPort: + val = eepro100_read_port(s); + logout("addr=%s val=0x%08x\n", regname(addr), val); + break; + case SCBCtrlMDI: + val = eepro100_read_mdi(s); + break; + default: + logout("addr=%s val=0x%08x\n", regname(addr), val); + missing("unknown longword read"); + } + return val; +} + +static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val) +{ + if (addr <= sizeof(s->mem) - sizeof(val)) { + memcpy(&s->mem[addr], &val, sizeof(val)); + } + + logout("addr=%s val=0x%02x\n", regname(addr), val); + + switch (addr) { + case SCBStatus: + //~ eepro100_write_status(s, val); + break; + case SCBAck: + eepro100_acknowledge(s); + break; + case SCBCmd: + eepro100_write_command(s, val); + break; + case SCBIntmask: + if (val & BIT(1)) { + eepro100_swi_interrupt(s); + } + eepro100_interrupt(s, 0); + break; + case SCBPort + 3: + logout("addr=%s val=0x%02x\n", regname(addr), val); + break; + case SCBeeprom: + eepro100_write_eeprom(s->eeprom, val); + break; + default: + logout("addr=%s val=0x%02x\n", regname(addr), val); + missing("unknown byte write"); + } +} + +static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val) +{ + if (addr <= sizeof(s->mem) - sizeof(val)) { + memcpy(&s->mem[addr], &val, sizeof(val)); + } + + logout("addr=%s val=0x%04x\n", regname(addr), val); + + switch (addr) { + case SCBStatus: + //~ eepro100_write_status(s, val); + eepro100_acknowledge(s); + break; + case SCBCmd: + eepro100_write_command(s, val); + eepro100_write1(s, SCBIntmask, val >> 8); + break; + case SCBeeprom: + eepro100_write_eeprom(s->eeprom, val); + break; + default: + logout("addr=%s val=0x%04x\n", regname(addr), val); + missing("unknown word write"); + } +} + +static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val) +{ + if (addr <= sizeof(s->mem) - sizeof(val)) { + memcpy(&s->mem[addr], &val, sizeof(val)); + } + + switch (addr) { + case SCBPointer: + eepro100_write_pointer(s, val); + break; + case SCBPort: + logout("addr=%s val=0x%08x\n", regname(addr), val); + eepro100_write_port(s, val); + break; + case SCBCtrlMDI: + eepro100_write_mdi(s, val); + break; + default: + logout("addr=%s val=0x%08x\n", regname(addr), val); + missing("unknown longword write"); + } +} + +static uint32_t ioport_read1(void *opaque, uint32_t addr) +{ + EEPRO100State *s = opaque; + //~ logout("addr=%s\n", regname(addr)); + return eepro100_read1(s, addr - s->region[1]); +} + +static uint32_t ioport_read2(void *opaque, uint32_t addr) +{ + EEPRO100State *s = opaque; + return eepro100_read2(s, addr - s->region[1]); +} + +static uint32_t ioport_read4(void *opaque, uint32_t addr) +{ + EEPRO100State *s = opaque; + return eepro100_read4(s, addr - s->region[1]); +} + +static void ioport_write1(void *opaque, uint32_t addr, uint32_t val) +{ + EEPRO100State *s = opaque; + //~ logout("addr=%s val=0x%02x\n", regname(addr), val); + eepro100_write1(s, addr - s->region[1], val); +} + +static void ioport_write2(void *opaque, uint32_t addr, uint32_t val) +{ + EEPRO100State *s = opaque; + eepro100_write2(s, addr - s->region[1], val); +} + +static void ioport_write4(void *opaque, uint32_t addr, uint32_t val) +{ + EEPRO100State *s = opaque; + eepro100_write4(s, addr - s->region[1], val); +} + +/***********************************************************/ +/* PCI EEPRO100 definitions */ + +typedef struct PCIEEPRO100State { + PCIDevice dev; + EEPRO100State eepro100; +} PCIEEPRO100State; + +static void pci_map(PCIDevice * pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIEEPRO100State *d = (PCIEEPRO100State *) pci_dev; + EEPRO100State *s = &d->eepro100; + + logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n", + region_num, addr, size, type); + + assert(region_num == 1); + register_ioport_write(addr, size, 1, ioport_write1, s); + register_ioport_read(addr, size, 1, ioport_read1, s); + register_ioport_write(addr, size, 2, ioport_write2, s); + register_ioport_read(addr, size, 2, ioport_read2, s); + register_ioport_write(addr, size, 4, ioport_write4, s); + register_ioport_read(addr, size, 4, ioport_read4, s); + + s->region[region_num] = addr; +} + +static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + EEPRO100State *s = opaque; + addr -= s->region[0]; + //~ logout("addr=%s val=0x%02x\n", regname(addr), val); + eepro100_write1(s, addr, val); +} + +static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + EEPRO100State *s = opaque; + addr -= s->region[0]; + //~ logout("addr=%s val=0x%02x\n", regname(addr), val); + eepro100_write2(s, addr, val); +} + +static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + EEPRO100State *s = opaque; + addr -= s->region[0]; + //~ logout("addr=%s val=0x%02x\n", regname(addr), val); + eepro100_write4(s, addr, val); +} + +static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + EEPRO100State *s = opaque; + addr -= s->region[0]; + //~ logout("addr=%s\n", regname(addr)); + return eepro100_read1(s, addr); +} + +static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + EEPRO100State *s = opaque; + addr -= s->region[0]; + //~ logout("addr=%s\n", regname(addr)); + return eepro100_read2(s, addr); +} + +static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + EEPRO100State *s = opaque; + addr -= s->region[0]; + //~ logout("addr=%s\n", regname(addr)); + return eepro100_read4(s, addr); +} + +static CPUWriteMemoryFunc *pci_mmio_write[] = { + pci_mmio_writeb, + pci_mmio_writew, + pci_mmio_writel +}; + +static CPUReadMemoryFunc *pci_mmio_read[] = { + pci_mmio_readb, + pci_mmio_readw, + pci_mmio_readl +}; + +static void pci_mmio_map(PCIDevice * pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + PCIEEPRO100State *d = (PCIEEPRO100State *) pci_dev; + + logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n", + region_num, addr, size, type); + + if (region_num == 0) { + /* Map control / status registers. */ + cpu_register_physical_memory(addr, size, d->eepro100.mmio_index); + d->eepro100.region[region_num] = addr; + } +} + +static int nic_can_receive(void *opaque) +{ + EEPRO100State *s = opaque; + logout("%p\n", s); + return get_ru_state(s) == ru_ready; + //~ return !eepro100_buffer_full(s); +} + +#define MIN_BUF_SIZE 60 + +static void nic_receive(void *opaque, const uint8_t * buf, int size) +{ + /* TODO: + * - Magic packets should set bit 30 in power management driver register. + * - Interesting packets should set bit 29 in power management driver register. + */ + EEPRO100State *s = opaque; + uint16_t rfd_status = 0xa000; + static const uint8_t broadcast_macaddr[6] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + /* TODO: check multiple IA bit. */ + assert(!(s->configuration[20] & BIT(6))); + + if (s->configuration[8] & 0x80) { + /* CSMA is disabled. */ + logout("%p received while CSMA is disabled\n", s); + return; + } else if (size < 64 && (s->configuration[7] & 1)) { + /* Short frame and configuration byte 7/0 (discard short receive) set: + * Short frame is discarded */ + logout("%p received short frame (%d byte)\n", s, size); + s->statistics.rx_short_frame_errors++; + //~ return; + } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & 8)) { + /* Long frame and configuration byte 18/3 (long receive ok) not set: + * Long frames are discarded. */ + logout("%p received long frame (%d byte), ignored\n", s, size); + return; + } else if (memcmp(buf, s->macaddr, 6) == 0) { // !!! + /* Frame matches individual address. */ + /* TODO: check configuration byte 15/4 (ignore U/L). */ + logout("%p received frame for me, len=%d\n", s, size); + } else if (memcmp(buf, broadcast_macaddr, 6) == 0) { + /* Broadcast frame. */ + logout("%p received broadcast, len=%d\n", s, size); + rfd_status |= 0x0002; + } else if (buf[0] & 0x01) { // !!! + /* Multicast frame. */ + logout("%p received multicast, len=%d\n", s, size); + /* TODO: check multicast all bit. */ + assert(!(s->configuration[21] & BIT(3))); + int mcast_idx = compute_mcast_idx(buf); + if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { + return; + } + rfd_status |= 0x0002; + } else if (s->configuration[15] & 1) { + /* Promiscuous: receive all. */ + logout("%p received frame in promiscuous mode, len=%d\n", s, size); + rfd_status |= 0x0004; + } else { + logout("%p received frame, ignored, len=%d,%s\n", s, size, + nic_dump(buf, size)); + return; + } + + if (get_ru_state(s) != ru_ready) { + /* No ressources available. */ + logout("no ressources, state=%u\n", get_ru_state(s)); + s->statistics.rx_resource_errors++; + //~ assert(!"no ressources"); + return; + } + //~ !!! +//~ $3 = {status = 0x0, command = 0xc000, link = 0x2d220, rx_buf_addr = 0x207dc, count = 0x0, size = 0x5f8, packet = {0x0 }} + eepro100_rx_t rx; + cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx, + offsetof(eepro100_rx_t, packet)); + uint16_t rfd_command = le16_to_cpu(rx.command); + uint16_t rfd_size = le16_to_cpu(rx.size); + assert(size <= rfd_size); + if (size < 64) { + rfd_status |= 0x0080; + } + logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n", rfd_command, + rx.link, rx.rx_buf_addr, rfd_size); + stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status), + rfd_status); + stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size); + /* Early receive interrupt not supported. */ + //~ eepro100_er_interrupt(s); + /* Receive CRC Transfer not supported. */ + assert(!(s->configuration[18] & 4)); + /* TODO: check stripping enable bit. */ + //~ assert(!(s->configuration[17] & 1)); + cpu_physical_memory_write(s->ru_base + s->ru_offset + + offsetof(eepro100_rx_t, packet), buf, size); + s->statistics.rx_good_frames++; + eepro100_fr_interrupt(s); + s->ru_offset = le32_to_cpu(rx.link); + if (rfd_command & 0x8000) { + /* EL bit is set, so this was the last frame. */ + assert(0); + } + if (rfd_command & 0x4000) { + /* S bit is set. */ + set_ru_state(s, ru_suspended); + } +} + +static int nic_load(QEMUFile * f, void *opaque, int version_id) +{ + EEPRO100State *s = (EEPRO100State *) opaque; + int ret; + + missing("NIC load"); + + if (version_id > 3) + return -EINVAL; + + if (s->pci_dev && version_id >= 3) { + ret = pci_device_load(s->pci_dev, f); + if (ret < 0) + return ret; + } + + if (version_id >= 2) { + qemu_get_8s(f, &s->rxcr); + } else { + s->rxcr = 0x0c; + } + + qemu_get_8s(f, &s->cmd); + qemu_get_be32s(f, &s->start); + qemu_get_be32s(f, &s->stop); + qemu_get_8s(f, &s->boundary); + qemu_get_8s(f, &s->tsr); + qemu_get_8s(f, &s->tpsr); + qemu_get_be16s(f, &s->tcnt); + qemu_get_be16s(f, &s->rcnt); + qemu_get_be32s(f, &s->rsar); + qemu_get_8s(f, &s->rsr); + qemu_get_8s(f, &s->isr); + qemu_get_8s(f, &s->dcfg); + qemu_get_8s(f, &s->imr); + qemu_get_buffer(f, s->phys, 6); + qemu_get_8s(f, &s->curpag); + qemu_get_buffer(f, s->mult, 8); + qemu_get_buffer(f, s->mem, sizeof(s->mem)); + + return 0; +} + +static void nic_save(QEMUFile * f, void *opaque) +{ + EEPRO100State *s = (EEPRO100State *) opaque; + + missing("NIC save"); + + if (s->pci_dev) + pci_device_save(s->pci_dev, f); + + qemu_put_8s(f, &s->rxcr); + + qemu_put_8s(f, &s->cmd); + qemu_put_be32s(f, &s->start); + qemu_put_be32s(f, &s->stop); + qemu_put_8s(f, &s->boundary); + qemu_put_8s(f, &s->tsr); + qemu_put_8s(f, &s->tpsr); + qemu_put_be16s(f, &s->tcnt); + qemu_put_be16s(f, &s->rcnt); + qemu_put_be32s(f, &s->rsar); + qemu_put_8s(f, &s->rsr); + qemu_put_8s(f, &s->isr); + qemu_put_8s(f, &s->dcfg); + qemu_put_8s(f, &s->imr); + qemu_put_buffer(f, s->phys, 6); + qemu_put_8s(f, &s->curpag); + qemu_put_buffer(f, s->mult, 8); + qemu_put_buffer(f, s->mem, sizeof(s->mem)); +} + +static void nic_init(PCIBus * bus, NICInfo * nd, + const char *name, uint32_t device) +{ + PCIEEPRO100State *d; + EEPRO100State *s; + + logout("\n"); + + d = (PCIEEPRO100State *) pci_register_device(bus, name, + sizeof(PCIEEPRO100State), -1, + NULL, NULL); + + s = &d->eepro100; + s->device = device; + s->pci_dev = &d->dev; + + pci_reset(s); + + /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM, + * i82559 and later support 64 or 256 word EEPROM. */ + s->eeprom = eeprom93xx_new(EEPROM_SIZE); + + /* Handler for memory-mapped I/O */ + d->eepro100.mmio_index = + cpu_register_io_memory(0, pci_mmio_read, pci_mmio_write, s); + + pci_register_io_region(&d->dev, 0, PCI_MEM_SIZE, + PCI_ADDRESS_SPACE_MEM | + PCI_ADDRESS_SPACE_MEM_PREFETCH, pci_mmio_map); + pci_register_io_region(&d->dev, 1, PCI_IO_SIZE, PCI_ADDRESS_SPACE_IO, + pci_map); + pci_register_io_region(&d->dev, 2, PCI_FLASH_SIZE, PCI_ADDRESS_SPACE_MEM, + pci_mmio_map); + + memcpy(s->macaddr, nd->macaddr, 6); + logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6)); + assert(s->region[1] == 0); + + nic_reset(s); + + s->vc = qemu_new_vlan_client(nd->vlan, nic_receive, nic_can_receive, s); + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "eepro100 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->macaddr[0], + s->macaddr[1], + s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); + + qemu_register_reset(nic_reset, s); + + /* XXX: instance number ? */ + register_savevm(name, 0, 3, nic_save, nic_load, s); +} + +void pci_i82551_init(PCIBus * bus, NICInfo * nd, int devfn) +{ + nic_init(bus, nd, "i82551", i82551); + //~ uint8_t *pci_conf = d->dev.config; +} + +void pci_i82557b_init(PCIBus * bus, NICInfo * nd, int devfn) +{ + nic_init(bus, nd, "i82557b", i82557B); +} + +void pci_i82559er_init(PCIBus * bus, NICInfo * nd, int devfn) +{ + nic_init(bus, nd, "i82559er", i82559ER); +} + +/* eof */ diff --git a/hw/eeprom93xx.c b/hw/eeprom93xx.c new file mode 100644 index 000000000..14f018914 --- /dev/null +++ b/hw/eeprom93xx.c @@ -0,0 +1,312 @@ +/* + * QEMU EEPROM 93xx emulation + * + * Copyright (c) 2006-2007 Stefan Weil + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Emulation for serial EEPROMs: + * NMC93C06 256-Bit (16 x 16) + * NMC93C46 1024-Bit (64 x 16) + * NMC93C56 2028 Bit (128 x 16) + * NMC93C66 4096 Bit (256 x 16) + * Compatible devices include FM93C46 and others. + * + * Other drivers use these interface functions: + * eeprom93xx_new - add a new EEPROM (with 16, 64 or 256 words) + * eeprom93xx_free - destroy EEPROM + * eeprom93xx_read - read data from the EEPROM + * eeprom93xx_write - write data to the EEPROM + * eeprom93xx_data - get EEPROM data array for external manipulation + * + * Todo list: + * - No emulation of EEPROM timings. + */ + +#include +#include "eeprom93xx.h" + +/* Debug EEPROM emulation. */ +//~ #define DEBUG_EEPROM + +#ifdef DEBUG_EEPROM +#define logout(fmt, args...) fprintf(stderr, "EEPROM\t%-24s" fmt, __func__, ##args) +#else +#define logout(fmt, args...) ((void)0) +#endif + +static int eeprom_instance = 0; +static const int eeprom_version = 20061112; + +#if 0 +typedef enum { + eeprom_read = 0x80, /* read register xx */ + eeprom_write = 0x40, /* write register xx */ + eeprom_erase = 0xc0, /* erase register xx */ + eeprom_ewen = 0x30, /* erase / write enable */ + eeprom_ewds = 0x00, /* erase / write disable */ + eeprom_eral = 0x20, /* erase all registers */ + eeprom_wral = 0x10, /* write all registers */ + eeprom_amask = 0x0f, + eeprom_imask = 0xf0 +} eeprom_instruction_t; +#endif + +#ifdef DEBUG_EEPROM +static const char *opstring[] = { + "extended", "write", "read", "erase" +}; +#endif + +struct _eeprom_t { + uint8_t tick; + uint8_t address; + uint8_t command; + uint8_t writeable; + + uint8_t eecs; + uint8_t eesk; + uint8_t eedo; + + uint8_t addrbits; + uint8_t size; + uint16_t data; + uint16_t contents[0]; +}; + +/* Code for saving and restoring of EEPROM state. */ + +static void eeprom_save(QEMUFile *f, void *opaque) +{ + /* Save EEPROM data. */ + unsigned address; + eeprom_t *eeprom = (eeprom_t *)opaque; + qemu_put_buffer(f, (uint8_t *)eeprom, sizeof(*eeprom) - 2); + qemu_put_be16(f, eeprom->data); + for (address = 0; address < eeprom->size; address++) { + qemu_put_be16(f, eeprom->contents[address]); + } +} + +static int eeprom_load(QEMUFile *f, void *opaque, int version_id) +{ + /* Load EEPROM data from saved data if version and EEPROM size + of data and current EEPROM are identical. */ + eeprom_t *eeprom = (eeprom_t *)opaque; + int result = -EINVAL; + if (version_id == eeprom_version) { + unsigned address; + uint8_t size = eeprom->size; + qemu_get_buffer(f, (uint8_t *)eeprom, sizeof(*eeprom) - 2); + if (eeprom->size == size) { + eeprom->data = qemu_get_be16(f); + for (address = 0; address < eeprom->size; address++) { + eeprom->contents[address] = qemu_get_be16(f); + } + result = 0; + } + } + return result; +} + +void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi) +{ + uint8_t tick = eeprom->tick; + uint8_t eedo = eeprom->eedo; + uint16_t address = eeprom->address; + uint8_t command = eeprom->command; + + logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n", + eecs, eesk, eedi, eedo, tick); + + if (! eeprom->eecs && eecs) { + /* Start chip select cycle. */ + logout("Cycle start, waiting for 1st start bit (0)\n"); + tick = 0; + command = 0x0; + address = 0x0; + } else if (eeprom->eecs && ! eecs) { + /* End chip select cycle. This triggers write / erase. */ + if (eeprom->writeable) { + uint8_t subcommand = address >> (eeprom->addrbits - 2); + if (command == 0 && subcommand == 2) { + /* Erase all. */ + for (address = 0; address < eeprom->size; address++) { + eeprom->contents[address] = 0xffff; + } + } else if (command == 3) { + /* Erase word. */ + eeprom->contents[address] = 0xffff; + } else if (tick >= 2 + 2 + eeprom->addrbits + 16) { + if (command == 1) { + /* Write word. */ + eeprom->contents[address] &= eeprom->data; + } else if (command == 0 && subcommand == 1) { + /* Write all. */ + for (address = 0; address < eeprom->size; address++) { + eeprom->contents[address] &= eeprom->data; + } + } + } + } + /* Output DO is tristate, read results in 1. */ + eedo = 1; + } else if (eecs && ! eeprom->eesk && eesk) { + /* Raising edge of clock shifts data in. */ + if (tick == 0) { + /* Wait for 1st start bit. */ + if (eedi == 0) { + logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n"); + tick++; + } else { + logout("wrong 1st start bit (is 1, should be 0)\n"); + tick = 2; + //~ assert(!"wrong start bit"); + } + } else if (tick == 1) { + /* Wait for 2nd start bit. */ + if (eedi != 0) { + logout("Got correct 2nd start bit, getting command + address\n"); + tick++; + } else { + logout("1st start bit is longer than needed\n"); + } + } else if (tick < 2 + 2) { + /* Got 2 start bits, transfer 2 opcode bits. */ + tick++; + command <<= 1; + if (eedi) { + command += 1; + } + } else if (tick < 2 + 2 + eeprom->addrbits) { + /* Got 2 start bits and 2 opcode bits, transfer all address bits. */ + tick++; + address = ((address << 1) | eedi); + if (tick == 2 + 2 + eeprom->addrbits) { + logout("%s command, address = 0x%02x (value 0x%04x)\n", + opstring[command], address, eeprom->contents[address]); + if (command == 2) { + eedo = 0; + } + address = address % eeprom->size; + if (command == 0) { + /* Command code in upper 2 bits of address. */ + switch (address >> (eeprom->addrbits - 2)) { + case 0: + logout("write disable command\n"); + eeprom->writeable = 0; + break; + case 1: + logout("write all command\n"); + break; + case 2: + logout("erase all command\n"); + break; + case 3: + logout("write enable command\n"); + eeprom->writeable = 1; + break; + } + } else { + /* Read, write or erase word. */ + eeprom->data = eeprom->contents[address]; + } + } + } else if (tick < 2 + 2 + eeprom->addrbits + 16) { + /* Transfer 16 data bits. */ + tick++; + if (command == 2) { + /* Read word. */ + eedo = ((eeprom->data & 0x8000) != 0); + } + eeprom->data <<= 1; + eeprom->data += eedi; + } else { + logout("additional unneeded tick, not processed\n"); + } + } + /* Save status of EEPROM. */ + eeprom->tick = tick; + eeprom->eecs = eecs; + eeprom->eesk = eesk; + eeprom->eedo = eedo; + eeprom->address = address; + eeprom->command = command; +} + +uint16_t eeprom93xx_read(eeprom_t *eeprom) +{ + /* Return status of pin DO (0 or 1). */ + logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo); + return (eeprom->eedo); +} + +#if 0 +void eeprom93xx_reset(eeprom_t *eeprom) +{ + /* prepare eeprom */ + logout("eeprom = 0x%p\n", eeprom); + eeprom->tick = 0; + eeprom->command = 0; +} +#endif + +eeprom_t *eeprom93xx_new(uint16_t nwords) +{ + /* Add a new EEPROM (with 16, 64 or 256 words). */ + eeprom_t *eeprom; + uint8_t addrbits; + + switch (nwords) { + case 16: + case 64: + addrbits = 6; + break; + case 128: + case 256: + addrbits = 8; + break; + default: + assert(!"Unsupported EEPROM size, fallback to 64 words!"); + nwords = 64; + addrbits = 6; + } + + eeprom = (eeprom_t *)qemu_mallocz(sizeof(*eeprom) + nwords * 2); + eeprom->size = nwords; + eeprom->addrbits = addrbits; + /* Output DO is tristate, read results in 1. */ + eeprom->eedo = 1; + logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords); + register_savevm("eeprom", eeprom_instance, eeprom_version, + eeprom_save, eeprom_load, eeprom); + return eeprom; +} + +void eeprom93xx_free(eeprom_t *eeprom) +{ + /* Destroy EEPROM. */ + logout("eeprom = 0x%p\n", eeprom); + qemu_free(eeprom); +} + +uint16_t *eeprom93xx_data(eeprom_t *eeprom) +{ + /* Get EEPROM data array. */ + return &eeprom->contents[0]; +} + +/* eof */ diff --git a/hw/eeprom93xx.h b/hw/eeprom93xx.h new file mode 100644 index 000000000..fde4912e8 --- /dev/null +++ b/hw/eeprom93xx.h @@ -0,0 +1,43 @@ +/* + * QEMU EEPROM 93xx emulation + * + * Copyright (c) 2006-2007 Stefan Weil + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef EEPROM93XX_H +#define EEPROM93XX_H + +#include "vl.h" + +typedef struct _eeprom_t eeprom_t; + +/* Create a new EEPROM with (nwords * 2) bytes. */ +eeprom_t *eeprom93xx_new(uint16_t nwords); + +/* Destroy an existing EEPROM. */ +void eeprom93xx_free(eeprom_t *eeprom); + +/* Read from the EEPROM. */ +uint16_t eeprom93xx_read(eeprom_t *eeprom); + +/* Write to the EEPROM. */ +void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi); + +/* Get EEPROM data array. */ +uint16_t *eeprom93xx_data(eeprom_t *eeprom); + +#endif /* EEPROM93XX_H */ diff --git a/hw/pci.c b/hw/pci.c index eeaef9e83..4d9eb0329 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -548,6 +548,12 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn) { if (strcmp(nd->model, "ne2k_pci") == 0) { pci_ne2000_init(bus, nd, devfn); + } else if (strcmp(nd->model, "i82551") == 0) { + pci_i82551_init(bus, nd, devfn); + } else if (strcmp(nd->model, "i82557b") == 0) { + pci_i82557b_init(bus, nd, devfn); + } else if (strcmp(nd->model, "i82559er") == 0) { + pci_i82559er_init(bus, nd, devfn); } else if (strcmp(nd->model, "rtl8139") == 0) { pci_rtl8139_init(bus, nd, devfn); } else if (strcmp(nd->model, "pcnet") == 0) { diff --git a/vl.h b/vl.h index d27b7115a..d44d6aa00 100644 --- a/vl.h +++ b/vl.h @@ -1009,6 +1009,12 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, BlockDriverState **fds); int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); +/* eepro100.c */ + +void pci_i82551_init(PCIBus *bus, NICInfo *nd, int devfn); +void pci_i82557b_init(PCIBus *bus, NICInfo *nd, int devfn); +void pci_i82559er_init(PCIBus *bus, NICInfo *nd, int devfn); + /* ne2000.c */ void isa_ne2000_init(int base, int irq, NICInfo *nd); -- cgit v1.2.3 From cce1075c767d5804e44e65513625a419296939ee Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 12:39:43 +0000 Subject: Use __sFILE to typedef for _BSD. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2585 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dyngen-exec.h b/dyngen-exec.h index c63eb265d..69c3cd99c 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -78,7 +78,11 @@ typedef void * host_reg_t; #define UINT32_MAX (4294967295U) #define UINT64_MAX ((uint64_t)(18446744073709551615)) +#ifdef _BSD +typedef struct __sFILE FILE; +#else typedef struct FILE FILE; +#endif extern int fprintf(FILE *, const char *, ...); extern int fputs(const char *, FILE *); extern int printf(const char *, ...); -- cgit v1.2.3 From 23be50f1afbb8c3db746ecd7735f74eacc89db24 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 12:48:47 +0000 Subject: Qcow2: Release refcount table clusters after growing the refcount table, by Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2586 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/block-qcow2.c b/block-qcow2.c index 0f7a06961..273359c28 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -1886,6 +1886,8 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) int64_t table_offset; uint64_t data64; uint32_t data32; + int old_table_size; + int64_t old_table_offset; if (min_size <= s->refcount_table_size) return 0; @@ -1931,11 +1933,14 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) &data32, sizeof(data32)) != sizeof(data32)) goto fail; qemu_free(s->refcount_table); + old_table_offset = s->refcount_table_offset; + old_table_size = s->refcount_table_size; s->refcount_table = new_table; s->refcount_table_size = new_table_size; s->refcount_table_offset = table_offset; update_refcount(bs, table_offset, new_table_size2, 1); + free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t)); return 0; fail: free_clusters(bs, table_offset, new_table_size2); -- cgit v1.2.3 From 2d0e944d1c985a0d4639ee5d98c3c371cd63afa3 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 15:54:05 +0000 Subject: Build fix for 64bit machines. (This is still not correct mul/div handling.) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2587 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index af3938798..7b6442e8f 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -17,6 +17,7 @@ * 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 #include "exec.h" #define MIPS_DEBUG_DISAS @@ -222,29 +223,34 @@ void do_msubu (void) #ifdef TARGET_MIPS64 void do_dmult (void) { + env->LO = (int64_t)T0 * (int64_t)T1; /* XXX */ - set_HILO((int64_t)T0 * (int64_t)T1); + env->HI = (env->LO | (1ULL << 63)) ? ~0ULL : 0ULL; } void do_dmultu (void) { + env->LO = T0 * T1; /* XXX */ - set_HILO((uint64_t)T0 * (uint64_t)T1); + env->HI = 0; } void do_ddiv (void) { if (T1 != 0) { - env->LO = (int64_t)T0 / (int64_t)T1; - env->HI = (int64_t)T0 % (int64_t)T1; + lldiv_t res = lldiv((int64_t)T0, (int64_t)T1); + env->LO = res.quot; + env->HI = res.rem; } } void do_ddivu (void) { if (T1 != 0) { - env->LO = T0 / T1; - env->HI = T0 % T1; + /* XXX: lldivu? */ + lldiv_t res = lldiv(T0, T1); + env->LO = (uint64_t)res.quot; + env->HI = (uint64_t)res.rem; } } #endif -- cgit v1.2.3 From 7524c84d82bd9d66ba14bac7da0456d02e47ea66 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 16:33:41 +0000 Subject: Fix guest x86/amd64 helper_fprem/helper_fprem1, by Julian Seward. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2588 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 97 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index aa136707e..ef760adad 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3139,30 +3139,51 @@ void helper_fprem1(void) CPU86_LDouble dblq, fpsrcop, fptemp; CPU86_LDoubleU fpsrcop1, fptemp1; int expdif; - int q; + signed long long int q; + + if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { + ST0 = 0.0 / 0.0; /* NaN */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + return; + } fpsrcop = ST0; fptemp = ST1; fpsrcop1.d = fpsrcop; fptemp1.d = fptemp; expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + + if (expdif < 0) { + /* optimisation? taken from the AMD docs */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* ST0 is unchanged */ + return; + } + if (expdif < 53) { dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ + /* round dblq towards nearest integer */ + dblq = rint(dblq); + ST0 = fpsrcop - fptemp * dblq; + + /* convert dblq to q by truncating towards zero */ + if (dblq < 0.0) + q = (signed long long int)(-dblq); + else + q = (signed long long int)dblq; + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + /* (C0,C3,C1) <-- (q2,q1,q0) */ + env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ + env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ + env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ } else { env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); + fptemp = pow(2.0, expdif - 50); fpsrcop = (ST0 / ST1) / fptemp; - /* fpsrcop = integer obtained by rounding to the nearest */ - fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? - floor(fpsrcop): ceil(fpsrcop); + /* fpsrcop = integer obtained by chopping */ + fpsrcop = (fpsrcop < 0.0) ? + -(floor(fabs(fpsrcop))) : floor(fpsrcop); ST0 -= (ST1 * fpsrcop * fptemp); } } @@ -3172,30 +3193,52 @@ void helper_fprem(void) CPU86_LDouble dblq, fpsrcop, fptemp; CPU86_LDoubleU fpsrcop1, fptemp1; int expdif; - int q; - - fpsrcop = ST0; - fptemp = ST1; + signed long long int q; + + if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) { + ST0 = 0.0 / 0.0; /* NaN */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + return; + } + + fpsrcop = (CPU86_LDouble)ST0; + fptemp = (CPU86_LDouble)ST1; fpsrcop1.d = fpsrcop; fptemp1.d = fptemp; expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + + if (expdif < 0) { + /* optimisation? taken from the AMD docs */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* ST0 is unchanged */ + return; + } + if ( expdif < 53 ) { - dblq = fpsrcop / fptemp; - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); - ST0 = fpsrcop - fptemp*dblq; - q = (int)dblq; /* cutting off top bits is assumed here */ + dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/; + /* round dblq towards zero */ + dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq); + ST0 = fpsrcop/*ST0*/ - fptemp * dblq; + + /* convert dblq to q by truncating towards zero */ + if (dblq < 0.0) + q = (signed long long int)(-dblq); + else + q = (signed long long int)dblq; + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ - /* (C0,C1,C3) <-- (q2,q1,q0) */ - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + /* (C0,C3,C1) <-- (q2,q1,q0) */ + env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */ + env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */ + env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */ } else { + int N = 32 + (expdif % 32); /* as per AMD docs */ env->fpus |= 0x400; /* C2 <-- 1 */ - fptemp = pow(2.0, expdif-50); + fptemp = pow(2.0, (double)(expdif - N)); fpsrcop = (ST0 / ST1) / fptemp; /* fpsrcop = integer obtained by chopping */ - fpsrcop = (fpsrcop < 0.0)? - -(floor(fabs(fpsrcop))): floor(fpsrcop); + fpsrcop = (fpsrcop < 0.0) ? + -(floor(fabs(fpsrcop))) : floor(fpsrcop); ST0 -= (ST1 * fpsrcop * fptemp); } } -- cgit v1.2.3 From 38121543c7e614fed740c5d902e7ea986ddb2fb8 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 2 Apr 2007 17:28:07 +0000 Subject: MIPS32R2 needs RDPGPR/WRPGPR instructions even when no shadow registers are implemented. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2589 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 469f2ec51..9ed30a799 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1375,7 +1375,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, - "undefined branch in delay slot at pc 0x%08x\n", ctx->pc); + "undefined branch in delay slot at PC " TARGET_FMT_lx "\n", + ctx->pc); } MIPS_INVAL("branch/jump in bdelay slot"); generate_exception(ctx, EXCP_RI); @@ -4841,9 +4842,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } GEN_STORE_TN_REG(rt, T0); break; - /* Shadow registers (not implemented). */ case OPC_RDPGPR: case OPC_WRPGPR: + if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) { + /* Shadow registers not implemented. */ + GEN_LOAD_REG_TN(T0, rt); + GEN_STORE_TN_REG(rd, T0); + } else + generate_exception(ctx, EXCP_RI); + break; default: generate_exception(ctx, EXCP_RI); break; -- cgit v1.2.3 From af655b6d827d7e56b945032adbb6359cfe58dbad Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 3 Apr 2007 14:05:42 +0000 Subject: Fix Malta tty2 UART registers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2590 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 0ba3359ef..2f3288bd7 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -244,14 +244,14 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) /* UART Registers */ case 0x00900: - case 0x00904: case 0x00908: - case 0x0090c: case 0x00910: - case 0x00914: case 0x00918: - case 0x0091c: - val = serial_mm_readl(s->uart, addr); + case 0x00920: + case 0x00928: + case 0x00930: + case 0x00938: + val = serial_mm_readb(s->uart, addr); break; /* GPOUT Register */ @@ -356,14 +356,14 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, /* UART Registers */ case 0x00900: - case 0x00904: case 0x00908: - case 0x0090c: case 0x00910: - case 0x00914: case 0x00918: - case 0x0091c: - serial_mm_writel(s->uart, addr, val); + case 0x00920: + case 0x00928: + case 0x00930: + case 0x00938: + serial_mm_writeb(s->uart, addr, val); break; /* GPOUT Register */ -- cgit v1.2.3 From eae7629bfdb25f5d89444fcae532b13e78c6d608 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 3 Apr 2007 16:38:34 +0000 Subject: i386 return APIC ID with cpuid, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2591 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 1 + target-i386/cpu.h | 1 + target-i386/helper.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/apic.c b/hw/apic.c index 8c9776195..f964360c8 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -816,6 +816,7 @@ int apic_init(CPUState *env) env->apic_state = s; apic_init_ipi(s); s->id = last_apic_id++; + env->cpuid_apic_id = s->id; s->cpu_env = env; s->apicbase = 0xfee00000 | (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 104f31e2c..2b4295ae1 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -530,6 +530,7 @@ typedef struct CPUX86State { uint32_t cpuid_xlevel; uint32_t cpuid_model[12]; uint32_t cpuid_ext2_features; + uint32_t cpuid_apic_id; #ifdef USE_KQEMU int kqemu_enabled; diff --git a/target-i386/helper.c b/target-i386/helper.c index ef760adad..4656596eb 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1653,7 +1653,7 @@ void helper_cpuid(void) break; case 1: EAX = env->cpuid_version; - EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ + EBX = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ ECX = env->cpuid_ext_features; EDX = env->cpuid_features; break; -- cgit v1.2.3 From bc98a7efa43efae9fc17062c87cc43c589d3cbae Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 4 Apr 2007 07:55:12 +0000 Subject: Add missing 64 bits memory accessors. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2592 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 3 +++ exec.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index 9b617fcc7..08d42188a 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -644,12 +644,14 @@ static inline void stfq_be_p(void *ptr, float64 v) #define lduw_code(p) lduw_raw(p) #define ldsw_code(p) ldsw_raw(p) #define ldl_code(p) ldl_raw(p) +#define ldq_code(p) ldq_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 ldq_kernel(p) ldq_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) @@ -882,6 +884,7 @@ 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 stq_phys_notdirty(target_phys_addr_t addr, uint64_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); diff --git a/exec.c b/exec.c index c168abef4..818fe21a3 100644 --- a/exec.c +++ b/exec.c @@ -338,7 +338,7 @@ void tb_flush(CPUState *env1) #ifdef DEBUG_TB_CHECK -static void tb_invalidate_check(unsigned long address) +static void tb_invalidate_check(target_ulong address) { TranslationBlock *tb; int i; @@ -2433,6 +2433,36 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) } } +void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) +{ + int io_index; + uint8_t *ptr; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); +#ifdef TARGET_WORDS_BIGENDIAN + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val); +#else + io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); + io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32); +#endif + } else { + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + stq_p(ptr, val); + } +} + /* warning: addr must be aligned */ void stl_phys(target_phys_addr_t addr, uint32_t val) { -- cgit v1.2.3 From b62b461bd3850d21c18056a94181828c94ea2f79 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 4 Apr 2007 07:58:14 +0000 Subject: TARGET_FMT_ld may also be useful for debugging purposes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2593 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpu-defs.h b/cpu-defs.h index 04fde7e89..46cda2017 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -44,10 +44,12 @@ typedef int32_t target_long; typedef uint32_t target_ulong; #define TARGET_FMT_lx "%08x" +#define TARGET_FMT_ld "%d" #elif TARGET_LONG_SIZE == 8 typedef int64_t target_long; typedef uint64_t target_ulong; #define TARGET_FMT_lx "%016" PRIx64 +#define TARGET_FMT_ld "%" PRId64 #else #error TARGET_LONG_SIZE undefined #endif -- cgit v1.2.3 From 3079c59ac254cd2316c529a9e45cc9e1146434f5 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 4 Apr 2007 08:00:14 +0000 Subject: Change NIC registration to be consistent with other machines definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2594 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index e9d6670e4..55ca6ac53 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -473,14 +473,14 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); - + /* XXX: use Mac Serial port */ serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); - for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(pci_bus, &nd_table[i], -1); + if (!nd_table[i].model) + nd_table[i].model = "ne2k_pci"; + pci_nic_init(pci_bus, &nd_table[i], -1); } - #if 1 ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13); ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14); -- cgit v1.2.3 From 876d4b07832b3b4fd30510420631570b6b8c94ea Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 4 Apr 2007 21:07:17 +0000 Subject: Fix code formatting. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2595 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 132 ++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 9ed30a799..74bb42d20 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2353,7 +2353,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 4: switch (sel) { @@ -2367,7 +2367,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } + } break; case 5: switch (sel) { @@ -2381,7 +2381,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 6: switch (sel) { @@ -2411,7 +2411,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } + } break; case 7: switch (sel) { @@ -2421,7 +2421,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 8: /* ignored */ @@ -2433,12 +2433,12 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) gen_op_mtc0_count(); rn = "Count"; break; - /* 6,7 are implementation dependent */ + /* 6,7 are implementation dependent */ default: goto die; - } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 10: switch (sel) { @@ -2448,7 +2448,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 11: switch (sel) { @@ -2459,9 +2459,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) /* 6,7 are implementation dependent */ default: goto die; - } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 12: switch (sel) { @@ -2483,9 +2483,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 13: switch (sel) { @@ -2495,9 +2495,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 14: switch (sel) { @@ -2507,7 +2507,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 15: switch (sel) { @@ -2969,7 +2969,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } + } break; case 5: switch (sel) { @@ -2983,7 +2983,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 6: switch (sel) { @@ -3013,7 +3013,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } + } break; case 7: switch (sel) { @@ -3023,7 +3023,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 8: switch (sel) { @@ -3033,7 +3033,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 9: switch (sel) { @@ -3044,7 +3044,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) /* 6,7 are implementation dependent */ default: goto die; - } + } break; case 10: switch (sel) { @@ -3054,7 +3054,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 11: switch (sel) { @@ -3062,10 +3062,10 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) gen_op_mfc0_compare(); rn = "Compare"; break; - /* 6,7 are implementation dependent */ + /* 6,7 are implementation dependent */ default: goto die; - } + } break; case 12: switch (sel) { @@ -3087,7 +3087,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 13: switch (sel) { @@ -3097,7 +3097,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 14: switch (sel) { @@ -3107,7 +3107,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 15: switch (sel) { @@ -3121,7 +3121,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 16: switch (sel) { @@ -3406,7 +3406,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) } break; default: - goto die; + goto die; } #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { @@ -3537,7 +3537,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 4: switch (sel) { @@ -3551,7 +3551,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } + } break; case 5: switch (sel) { @@ -3565,7 +3565,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 6: switch (sel) { @@ -3595,7 +3595,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } + } break; case 7: switch (sel) { @@ -3605,7 +3605,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 8: /* ignored */ @@ -3617,12 +3617,12 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) gen_op_mtc0_count(); rn = "Count"; break; - /* 6,7 are implementation dependent */ + /* 6,7 are implementation dependent */ default: goto die; - } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 10: switch (sel) { @@ -3632,7 +3632,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 11: switch (sel) { @@ -3640,12 +3640,12 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) gen_op_mtc0_compare(); rn = "Compare"; break; - /* 6,7 are implementation dependent */ + /* 6,7 are implementation dependent */ default: goto die; - } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 12: switch (sel) { @@ -3665,11 +3665,11 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) gen_op_mtc0_srsmap(); /* shadow registers */ rn = "SRSMap"; break; - default: + default: goto die; - } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 13: switch (sel) { @@ -3679,9 +3679,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + } + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 14: switch (sel) { @@ -3691,7 +3691,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 15: switch (sel) { @@ -3705,7 +3705,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 16: switch (sel) { @@ -3844,7 +3844,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 22: /* ignored */ rn = "Diagnostic"; /* implementation dependent */ - break; + break; case 23: switch (sel) { case 0: @@ -3920,11 +3920,11 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) default: goto die; } - break; + break; case 26: - /* ignored */ + /* ignored */ rn = "ECC"; - break; + break; case 27: switch (sel) { case 0 ... 3: @@ -3934,7 +3934,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) default: goto die; } - break; + break; case 28: switch (sel) { case 0: @@ -3975,7 +3975,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "invalid sel"; goto die; } - break; + break; case 30: switch (sel) { case 0: @@ -3995,11 +3995,11 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; default: - goto die; + goto die; } #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { -- cgit v1.2.3 From 6fa4cea9e8e904f7aac0c3d4f73a883c9e1e53bd Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 06:43:27 +0000 Subject: Infrastructure to support more than 2 MMU modes. Add example for Alpha and PowerPC hypervisor mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2596 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 11 ++++++++++- exec.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/cpu-defs.h b/cpu-defs.h index 46cda2017..202eaee2e 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -108,6 +108,15 @@ typedef struct CPUTLBEntry { target_phys_addr_t addend; } CPUTLBEntry; +/* Alpha has 4 different running levels */ +#if defined(TARGET_ALPHA) +#define NB_MMU_MODES 4 +#elif defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ +#define NB_MMU_MODES 3 +#else +#define NB_MMU_MODES 2 +#endif + #define CPU_COMMON \ struct TranslationBlock *current_tb; /* currently executing TB */ \ /* soft mmu support */ \ @@ -119,7 +128,7 @@ typedef struct CPUTLBEntry { 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]; \ + CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ \ /* from this point: preserved by CPU reset */ \ diff --git a/exec.c b/exec.c index 818fe21a3..c49c86f1a 100644 --- a/exec.c +++ b/exec.c @@ -1300,6 +1300,16 @@ void tlb_flush(CPUState *env, int flush_global) env->tlb_table[1][i].addr_read = -1; env->tlb_table[1][i].addr_write = -1; env->tlb_table[1][i].addr_code = -1; +#if (NB_MMU_MODES >= 3) + env->tlb_table[2][i].addr_read = -1; + env->tlb_table[2][i].addr_write = -1; + env->tlb_table[2][i].addr_code = -1; +#if (NB_MMU_MODES == 4) + env->tlb_table[3][i].addr_read = -1; + env->tlb_table[3][i].addr_write = -1; + env->tlb_table[3][i].addr_code = -1; +#endif +#endif } memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); @@ -1345,6 +1355,12 @@ void tlb_flush_page(CPUState *env, target_ulong addr) i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_flush_entry(&env->tlb_table[0][i], addr); tlb_flush_entry(&env->tlb_table[1][i], addr); +#if (NB_MMU_MODES >= 3) + tlb_flush_entry(&env->tlb_table[2][i], addr); +#if (NB_MMU_MODES == 4) + tlb_flush_entry(&env->tlb_table[3][i], addr); +#endif +#endif /* Discard jump cache entries for any tb which might potentially overlap the flushed page. */ @@ -1434,6 +1450,14 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length); for(i = 0; i < CPU_TLB_SIZE; i++) tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length); +#if (NB_MMU_MODES >= 3) + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length); +#if (NB_MMU_MODES == 4) + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length); +#endif +#endif } #if !defined(CONFIG_SOFTMMU) @@ -1486,6 +1510,14 @@ void cpu_tlb_update_dirty(CPUState *env) tlb_update_dirty(&env->tlb_table[0][i]); for(i = 0; i < CPU_TLB_SIZE; i++) tlb_update_dirty(&env->tlb_table[1][i]); +#if (NB_MMU_MODES >= 3) + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_update_dirty(&env->tlb_table[2][i]); +#if (NB_MMU_MODES == 4) + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_update_dirty(&env->tlb_table[3][i]); +#endif +#endif } static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, @@ -1511,6 +1543,12 @@ static inline void tlb_set_dirty(CPUState *env, i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); tlb_set_dirty1(&env->tlb_table[0][i], addr); tlb_set_dirty1(&env->tlb_table[1][i], addr); +#if (NB_MMU_MODES >= 3) + tlb_set_dirty1(&env->tlb_table[2][i], addr); +#if (NB_MMU_MODES == 4) + tlb_set_dirty1(&env->tlb_table[3][i], addr); +#endif +#endif } /* add a new TLB entry. At most one entry for a given virtual address -- cgit v1.2.3 From 4c9649a967e45bc3086d2e752871878e08d6cdf2 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 06:58:33 +0000 Subject: Alpha architecture emulation core. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2597 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/cpu.h | 385 ++++++++ target-alpha/exec.h | 82 ++ target-alpha/helper.c | 454 +++++++++ target-alpha/op.c | 1103 ++++++++++++++++++++++ target-alpha/op_helper.c | 1255 +++++++++++++++++++++++++ target-alpha/op_helper.h | 141 +++ target-alpha/op_helper_mem.h | 40 + target-alpha/op_mem.h | 125 +++ target-alpha/op_template.h | 167 ++++ target-alpha/translate.c | 2117 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 5869 insertions(+) create mode 100644 target-alpha/cpu.h create mode 100644 target-alpha/exec.h create mode 100644 target-alpha/helper.c create mode 100644 target-alpha/op.c create mode 100644 target-alpha/op_helper.c create mode 100644 target-alpha/op_helper.h create mode 100644 target-alpha/op_helper_mem.h create mode 100644 target-alpha/op_mem.h create mode 100644 target-alpha/op_template.h create mode 100644 target-alpha/translate.c diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h new file mode 100644 index 000000000..ca12105f2 --- /dev/null +++ b/target-alpha/cpu.h @@ -0,0 +1,385 @@ +/* + * Alpha emulation cpu definitions for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * 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 (__CPU_ALPHA_H__) +#define __CPU_ALPHA_H__ + +#include "config.h" + +#define TARGET_LONG_BITS 64 + +#include "cpu-defs.h" + + +#include + +#include "softfloat.h" + +/* XXX: put this in a common place */ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define TARGET_HAS_ICE 1 + +#define ELF_MACHINE EM_ALPHA + +#define ICACHE_LINE_SIZE 32 +#define DCACHE_LINE_SIZE 32 + +#define TARGET_PAGE_BITS 12 + +#define VA_BITS 43 + +/* Alpha major type */ +enum { + ALPHA_EV3 = 1, + ALPHA_EV4 = 2, + ALPHA_SIM = 3, + ALPHA_LCA = 4, + ALPHA_EV5 = 5, /* 21164 */ + ALPHA_EV45 = 6, /* 21064A */ + ALPHA_EV56 = 7, /* 21164A */ +}; + +/* EV4 minor type */ +enum { + ALPHA_EV4_2 = 0, + ALPHA_EV4_3 = 1, +}; + +/* LCA minor type */ +enum { + ALPHA_LCA_1 = 1, /* 21066 */ + ALPHA_LCA_2 = 2, /* 20166 */ + ALPHA_LCA_3 = 3, /* 21068 */ + ALPHA_LCA_4 = 4, /* 21068 */ + ALPHA_LCA_5 = 5, /* 21066A */ + ALPHA_LCA_6 = 6, /* 21068A */ +}; + +/* EV5 minor type */ +enum { + ALPHA_EV5_1 = 1, /* Rev BA, CA */ + ALPHA_EV5_2 = 2, /* Rev DA, EA */ + ALPHA_EV5_3 = 3, /* Pass 3 */ + ALPHA_EV5_4 = 4, /* Pass 3.2 */ + ALPHA_EV5_5 = 5, /* Pass 4 */ +}; + +/* EV45 minor type */ +enum { + ALPHA_EV45_1 = 1, /* Pass 1 */ + ALPHA_EV45_2 = 2, /* Pass 1.1 */ + ALPHA_EV45_3 = 3, /* Pass 2 */ +}; + +/* EV56 minor type */ +enum { + ALPHA_EV56_1 = 1, /* Pass 1 */ + ALPHA_EV56_2 = 2, /* Pass 2 */ +}; + +enum { + IMPLVER_2106x = 0, /* EV4, EV45 & LCA45 */ + IMPLVER_21164 = 1, /* EV5, EV56 & PCA45 */ + IMPLVER_21264 = 2, /* EV6, EV67 & EV68x */ + IMPLVER_21364 = 3, /* EV7 & EV79 */ +}; + +enum { + AMASK_BWX = 0x00000001, + AMASK_FIX = 0x00000002, + AMASK_CIX = 0x00000004, + AMASK_MVI = 0x00000100, + AMASK_TRAP = 0x00000200, + AMASK_PREFETCH = 0x00001000, +}; + +enum { + VAX_ROUND_NORMAL = 0, + VAX_ROUND_CHOPPED, +}; + +enum { + IEEE_ROUND_NORMAL = 0, + IEEE_ROUND_DYNAMIC, + IEEE_ROUND_PLUS, + IEEE_ROUND_MINUS, + IEEE_ROUND_CHOPPED, +}; + +/* IEEE floating-point operations encoding */ +/* Trap mode */ +enum { + FP_TRAP_I = 0x0, + FP_TRAP_U = 0x1, + FP_TRAP_S = 0x4, + FP_TRAP_SU = 0x5, + FP_TRAP_SUI = 0x7, +}; + +/* Rounding mode */ +enum { + FP_ROUND_CHOPPED = 0x0, + FP_ROUND_MINUS = 0x1, + FP_ROUND_NORMAL = 0x2, + FP_ROUND_DYNAMIC = 0x3, +}; + +/* Internal processor registers */ +/* XXX: TOFIX: most of those registers are implementation dependant */ +enum { + /* Ebox IPRs */ + IPR_CC = 0xC0, + IPR_CC_CTL = 0xC1, + IPR_VA = 0xC2, + IPR_VA_CTL = 0xC4, + IPR_VA_FORM = 0xC3, + /* Ibox IPRs */ + IPR_ITB_TAG = 0x00, + IPR_ITB_PTE = 0x01, + IPT_ITB_IAP = 0x02, + IPT_ITB_IA = 0x03, + IPT_ITB_IS = 0x04, + IPR_PMPC = 0x05, + IPR_EXC_ADDR = 0x06, + IPR_IVA_FORM = 0x07, + IPR_CM = 0x09, + IPR_IER = 0x0A, + IPR_SIRR = 0x0C, + IPR_ISUM = 0x0D, + IPR_HW_INT_CLR = 0x0E, + IPR_EXC_SUM = 0x0F, + IPR_PAL_BASE = 0x10, + IPR_I_CTL = 0x11, + IPR_I_STAT = 0x16, + IPR_IC_FLUSH = 0x13, + IPR_IC_FLUSH_ASM = 0x12, + IPR_CLR_MAP = 0x15, + IPR_SLEEP = 0x17, + IPR_PCTX = 0x40, + IPR_PCTR_CTL = 0x14, + /* Mbox IPRs */ + IPR_DTB_TAG0 = 0x20, + IPR_DTB_TAG1 = 0xA0, + IPR_DTB_PTE0 = 0x21, + IPR_DTB_PTE1 = 0xA1, + IPR_DTB_ALTMODE = 0xA6, + IPR_DTB_IAP = 0xA2, + IPR_DTB_IA = 0xA3, + IPR_DTB_IS0 = 0x24, + IPR_DTB_IS1 = 0xA4, + IPR_DTB_ASN0 = 0x25, + IPR_DTB_ASN1 = 0xA5, + IPR_MM_STAT = 0x27, + IPR_M_CTL = 0x28, + IPR_DC_CTL = 0x29, + IPR_DC_STAT = 0x2A, + /* Cbox IPRs */ + IPR_C_DATA = 0x2B, + IPR_C_SHIFT = 0x2C, + + IPR_ASN, + IPR_ASTEN, + IPR_ASTSR, + IPR_DATFX, + IPR_ESP, + IPR_FEN, + IPR_IPIR, + IPR_IPL, + IPR_KSP, + IPR_MCES, + IPR_PERFMON, + IPR_PCBB, + IPR_PRBR, + IPR_PTBR, + IPR_SCBB, + IPR_SISR, + IPR_SSP, + IPR_SYSPTBR, + IPR_TBCHK, + IPR_TBIA, + IPR_TBIAP, + IPR_TBIS, + IPR_TBISD, + IPR_TBISI, + IPR_USP, + IPR_VIRBND, + IPR_VPTB, + IPR_WHAMI, + IPR_ALT_MODE, + IPR_LAST, +}; + +typedef struct CPUAlphaState CPUAlphaState; + +typedef struct pal_handler_t pal_handler_t; +struct pal_handler_t { + /* Reset */ + void (*reset)(CPUAlphaState *env); + /* Uncorrectable hardware error */ + void (*machine_check)(CPUAlphaState *env); + /* Arithmetic exception */ + void (*arithmetic)(CPUAlphaState *env); + /* Interrupt / correctable hardware error */ + void (*interrupt)(CPUAlphaState *env); + /* Data fault */ + void (*dfault)(CPUAlphaState *env); + /* DTB miss pal */ + void (*dtb_miss_pal)(CPUAlphaState *env); + /* DTB miss native */ + void (*dtb_miss_native)(CPUAlphaState *env); + /* Unaligned access */ + void (*unalign)(CPUAlphaState *env); + /* ITB miss */ + void (*itb_miss)(CPUAlphaState *env); + /* Instruction stream access violation */ + void (*itb_acv)(CPUAlphaState *env); + /* Reserved or privileged opcode */ + void (*opcdec)(CPUAlphaState *env); + /* Floating point exception */ + void (*fen)(CPUAlphaState *env); + /* Call pal instruction */ + void (*call_pal)(CPUAlphaState *env, uint32_t palcode); +}; + +struct CPUAlphaState { + uint64_t ir[31]; + float64 fir[31]; + float_status fp_status; + uint64_t fpcr; + uint64_t pc; + uint64_t lock; + uint32_t pcc[2]; + uint64_t ipr[IPR_LAST]; + uint64_t ps; + uint64_t unique; + int saved_mode; /* Used for HW_LD / HW_ST */ + + /* */ + double ft0, ft1, ft2; + + /* Those resources are used only in Qemu core */ + CPU_COMMON + + jmp_buf jmp_env; + int user_mode_only; /* user mode only simulation */ + uint32_t hflags; + int halted; + + int exception_index; + int error_code; + int interrupt_request; + + uint32_t features; + uint32_t amask; + int implver; + pal_handler_t *pal_handler; +}; + +#include "cpu-all.h" + +enum { + FEATURE_ASN = 0x00000001, + FEATURE_SPS = 0x00000002, + FEATURE_VIRBND = 0x00000004, + FEATURE_TBCHK = 0x00000008, +}; + +enum { + EXCP_RESET = 0x0000, + EXCP_MCHK = 0x0020, + EXCP_ARITH = 0x0060, + EXCP_HW_INTERRUPT = 0x00E0, + EXCP_DFAULT = 0x01E0, + EXCP_DTB_MISS_PAL = 0x09E0, + EXCP_ITB_MISS = 0x03E0, + EXCP_ITB_ACV = 0x07E0, + EXCP_DTB_MISS_NATIVE = 0x08E0, + EXCP_UNALIGN = 0x11E0, + EXCP_OPCDEC = 0x13E0, + EXCP_FEN = 0x17E0, + EXCP_CALL_PAL = 0x2000, + EXCP_CALL_PALP = 0x3000, + EXCP_CALL_PALE = 0x4000, + /* Pseudo exception for console */ + EXCP_CONSOLE_DISPATCH = 0x4001, + EXCP_CONSOLE_FIXUP = 0x4002, +}; + +/* Arithmetic exception */ +enum { + EXCP_ARITH_OVERFLOW, +}; + +enum { + PALCODE_CALL = 0x00000000, + PALCODE_LD = 0x01000000, + PALCODE_ST = 0x02000000, + PALCODE_MFPR = 0x03000000, + PALCODE_MTPR = 0x04000000, + PALCODE_REI = 0x05000000, + PALCODE_INIT = 0xF0000000, +}; + +enum { + IR_V0 = 0, + IR_T0 = 1, + IR_T1 = 2, + IR_T2 = 3, + IR_T3 = 4, + IR_T4 = 5, + IR_T5 = 6, + IR_T6 = 7, + IR_T7 = 8, + IR_S0 = 9, + IR_S1 = 10, + IR_S2 = 11, + IR_S3 = 12, + IR_S4 = 13, + IR_S5 = 14, + IR_S6 = 15, +#define IR_FP IR_S6 + IR_A0 = 16, + IR_A1 = 17, + IR_A2 = 18, + IR_A3 = 19, + IR_A4 = 20, + IR_A5 = 21, + IR_T8 = 22, + IR_T9 = 23, + IR_T10 = 24, + IR_T11 = 25, + IR_RA = 26, + IR_T12 = 27, +#define IR_PV IR_T12 + IR_AT = 28, + IR_GP = 29, + IR_SP = 30, + IR_ZERO = 31, +}; + +int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); +int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); +void cpu_loop_exit (void); +void pal_init (CPUState *env); +void call_pal (CPUState *env, int palcode); + +#endif /* !defined (__CPU_ALPHA_H__) */ diff --git a/target-alpha/exec.h b/target-alpha/exec.h new file mode 100644 index 000000000..f109160a5 --- /dev/null +++ b/target-alpha/exec.h @@ -0,0 +1,82 @@ +/* + * Alpha emulation cpu run-time definitions for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * 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 (__ALPHA_EXEC_H__) +#define __ALPHA_EXEC_H__ + +#include "config.h" + +#include "dyngen-exec.h" + +#define TARGET_LONG_BITS 64 + +register struct CPUAlphaState *env asm(AREG0); + +#if TARGET_LONG_BITS > HOST_LONG_BITS + +/* no registers can be used */ +#define T0 (env->t0) +#define T1 (env->t1) +#define T2 (env->t2) + +#else + +register uint64_t T0 asm(AREG1); +register uint64_t T1 asm(AREG2); +register uint64_t T2 asm(AREG3); + +#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ + +#define PARAM(n) ((uint64_t)PARAM##n) +#define SPARAM(n) ((int32_t)PARAM##n) +#define FT0 (env->ft0) +#define FT1 (env->ft1) +#define FT2 (env->ft2) +#define FP_STATUS (env->fp_status) + +#if defined (DEBUG_OP) +#define RETURN() __asm__ __volatile__("nop" : : : "memory"); +#else +#define RETURN() __asm__ __volatile__("" : : : "memory"); +#endif + +#include "cpu.h" +#include "exec-all.h" + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif /* !defined(CONFIG_USER_ONLY) */ + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw, + int is_user, int is_softmmu); +int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); +int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); + +void do_interrupt (CPUState *env); + +#endif /* !defined (__ALPHA_EXEC_H__) */ diff --git a/target-alpha/helper.c b/target-alpha/helper.c new file mode 100644 index 000000000..0049c397a --- /dev/null +++ b/target-alpha/helper.c @@ -0,0 +1,454 @@ +/* + * Alpha emulation cpu helpers for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * 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 +#include +#include + +#include "cpu.h" +#include "exec-all.h" + +#if defined(CONFIG_USER_ONLY) + +int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + if (rw == 2) + env->exception_index = EXCP_ITB_MISS; + else + env->exception_index = EXCP_DFAULT; + env->ipr[IPR_EXC_ADDR] = address; + + return 1; +} + +target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr) +{ + return addr; +} + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; +} + +#else + +target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr) +{ + return -1; +} + +int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + uint32_t opc; + + if (rw == 2) { + /* Instruction translation buffer miss */ + env->exception_index = EXCP_ITB_MISS; + } else { + if (env->ipr[IPR_EXC_ADDR] & 1) + env->exception_index = EXCP_DTB_MISS_PAL; + else + env->exception_index = EXCP_DTB_MISS_NATIVE; + opc = (ldl_code(env->pc) >> 21) << 4; + if (rw) { + opc |= 0x9; + } else { + opc |= 0x4; + } + env->ipr[IPR_MM_STAT] = opc; + } + + return 1; +} + +int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp) +{ + uint64_t hwpcb; + int ret = 0; + + hwpcb = env->ipr[IPR_PCBB]; + switch (iprn) { + case IPR_ASN: + if (env->features & FEATURE_ASN) + *valp = env->ipr[IPR_ASN]; + else + *valp = 0; + break; + case IPR_ASTEN: + *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60; + break; + case IPR_ASTSR: + *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60; + break; + case IPR_DATFX: + /* Write only */ + ret = -1; + break; + case IPR_ESP: + if (env->features & FEATURE_SPS) + *valp = env->ipr[IPR_ESP]; + else + *valp = ldq_raw(hwpcb + 8); + break; + case IPR_FEN: + *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63; + break; + case IPR_IPIR: + /* Write-only */ + ret = -1; + break; + case IPR_IPL: + *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59; + break; + case IPR_KSP: + if (!(env->ipr[IPR_EXC_ADDR] & 1)) { + ret = -1; + } else { + if (env->features & FEATURE_SPS) + *valp = env->ipr[IPR_KSP]; + else + *valp = ldq_raw(hwpcb + 0); + } + break; + case IPR_MCES: + *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59; + break; + case IPR_PERFMON: + /* Implementation specific */ + *valp = 0; + break; + case IPR_PCBB: + *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16; + break; + case IPR_PRBR: + *valp = env->ipr[IPR_PRBR]; + break; + case IPR_PTBR: + *valp = env->ipr[IPR_PTBR]; + break; + case IPR_SCBB: + *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]); + break; + case IPR_SIRR: + /* Write-only */ + ret = -1; + break; + case IPR_SISR: + *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]); + case IPR_SSP: + if (env->features & FEATURE_SPS) + *valp = env->ipr[IPR_SSP]; + else + *valp = ldq_raw(hwpcb + 16); + break; + case IPR_SYSPTBR: + if (env->features & FEATURE_VIRBND) + *valp = env->ipr[IPR_SYSPTBR]; + else + ret = -1; + break; + case IPR_TBCHK: + if ((env->features & FEATURE_TBCHK)) { + /* XXX: TODO */ + *valp = 0; + ret = -1; + } else { + ret = -1; + } + break; + case IPR_TBIA: + /* Write-only */ + ret = -1; + break; + case IPR_TBIAP: + /* Write-only */ + ret = -1; + break; + case IPR_TBIS: + /* Write-only */ + ret = -1; + break; + case IPR_TBISD: + /* Write-only */ + ret = -1; + break; + case IPR_TBISI: + /* Write-only */ + ret = -1; + break; + case IPR_USP: + if (env->features & FEATURE_SPS) + *valp = env->ipr[IPR_USP]; + else + *valp = ldq_raw(hwpcb + 24); + break; + case IPR_VIRBND: + if (env->features & FEATURE_VIRBND) + *valp = env->ipr[IPR_VIRBND]; + else + ret = -1; + break; + case IPR_VPTB: + *valp = env->ipr[IPR_VPTB]; + break; + case IPR_WHAMI: + *valp = env->ipr[IPR_WHAMI]; + break; + default: + /* Invalid */ + ret = -1; + break; + } + + return ret; +} + +int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp) +{ + uint64_t hwpcb, tmp64; + uint8_t tmp8; + int ret = 0; + + hwpcb = env->ipr[IPR_PCBB]; + switch (iprn) { + case IPR_ASN: + /* Read-only */ + ret = -1; + break; + case IPR_ASTEN: + tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4; + *oldvalp = tmp8; + tmp8 &= val & 0xF; + tmp8 |= (val >> 4) & 0xF; + env->ipr[IPR_ASTEN] &= ~0xF; + env->ipr[IPR_ASTEN] |= tmp8; + ret = 1; + break; + case IPR_ASTSR: + tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4; + *oldvalp = tmp8; + tmp8 &= val & 0xF; + tmp8 |= (val >> 4) & 0xF; + env->ipr[IPR_ASTSR] &= ~0xF; + env->ipr[IPR_ASTSR] |= tmp8; + ret = 1; + case IPR_DATFX: + env->ipr[IPR_DATFX] &= ~0x1; + env->ipr[IPR_DATFX] |= val & 1; + tmp64 = ldq_raw(hwpcb + 56); + tmp64 &= ~0x8000000000000000ULL; + tmp64 |= (val & 1) << 63; + stq_raw(hwpcb + 56, tmp64); + break; + case IPR_ESP: + if (env->features & FEATURE_SPS) + env->ipr[IPR_ESP] = val; + else + stq_raw(hwpcb + 8, val); + break; + case IPR_FEN: + env->ipr[IPR_FEN] = val & 1; + tmp64 = ldq_raw(hwpcb + 56); + tmp64 &= ~1; + tmp64 |= val & 1; + stq_raw(hwpcb + 56, tmp64); + break; + case IPR_IPIR: + /* XXX: TODO: Send IRQ to CPU #ir[16] */ + break; + case IPR_IPL: + *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59; + env->ipr[IPR_IPL] &= ~0x1F; + env->ipr[IPR_IPL] |= val & 0x1F; + /* XXX: may issue an interrupt or ASR _now_ */ + ret = 1; + break; + case IPR_KSP: + if (!(env->ipr[IPR_EXC_ADDR] & 1)) { + ret = -1; + } else { + if (env->features & FEATURE_SPS) + env->ipr[IPR_KSP] = val; + else + stq_raw(hwpcb + 0, val); + } + break; + case IPR_MCES: + env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18); + env->ipr[IPR_MCES] |= val & 0x18; + break; + case IPR_PERFMON: + /* Implementation specific */ + *oldvalp = 0; + ret = 1; + break; + case IPR_PCBB: + /* Read-only */ + ret = -1; + break; + case IPR_PRBR: + env->ipr[IPR_PRBR] = val; + break; + case IPR_PTBR: + /* Read-only */ + ret = -1; + break; + case IPR_SCBB: + env->ipr[IPR_SCBB] = (uint32_t)val; + break; + case IPR_SIRR: + if (val & 0xF) { + env->ipr[IPR_SISR] |= 1 << (val & 0xF); + /* XXX: request a software interrupt _now_ */ + } + break; + case IPR_SISR: + /* Read-only */ + ret = -1; + break; + case IPR_SSP: + if (env->features & FEATURE_SPS) + env->ipr[IPR_SSP] = val; + else + stq_raw(hwpcb + 16, val); + break; + case IPR_SYSPTBR: + if (env->features & FEATURE_VIRBND) + env->ipr[IPR_SYSPTBR] = val; + else + ret = -1; + case IPR_TBCHK: + /* Read-only */ + ret = -1; + break; + case IPR_TBIA: + tlb_flush(env, 1); + break; + case IPR_TBIAP: + tlb_flush(env, 1); + break; + case IPR_TBIS: + tlb_flush_page(env, val); + break; + case IPR_TBISD: + tlb_flush_page(env, val); + break; + case IPR_TBISI: + tlb_flush_page(env, val); + break; + case IPR_USP: + if (env->features & FEATURE_SPS) + env->ipr[IPR_USP] = val; + else + stq_raw(hwpcb + 24, val); + break; + case IPR_VIRBND: + if (env->features & FEATURE_VIRBND) + env->ipr[IPR_VIRBND] = val; + else + ret = -1; + break; + case IPR_VPTB: + env->ipr[IPR_VPTB] = val; + break; + case IPR_WHAMI: + /* Read-only */ + ret = -1; + break; + default: + /* Invalid */ + ret = -1; + break; + } + + return ret; +} + +void do_interrupt (CPUState *env) +{ + int excp; + + env->ipr[IPR_EXC_ADDR] = env->pc | 1; + excp = env->exception_index; + env->exception_index = 0; + env->error_code = 0; + /* XXX: disable interrupts and memory mapping */ + if (env->ipr[IPR_PAL_BASE] != -1ULL) { + /* We use native PALcode */ + env->pc = env->ipr[IPR_PAL_BASE] + excp; + } else { + /* We use emulated PALcode */ + call_pal(env); + /* Emulate REI */ + env->pc = env->ipr[IPR_EXC_ADDR] & ~7; + env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1; + /* XXX: re-enable interrupts and memory mapping */ + } +} +#endif + +void cpu_dump_state (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + static unsigned char *linux_reg_names[] = { + "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", + }; + int i; + + cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n", + env->pc, env->ps); + for (i = 0; i < 31; i++) { + cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i, + linux_reg_names[i], env->ir[i]); + if ((i % 3) == 2) + cpu_fprintf(f, "\n"); + } + cpu_fprintf(f, "\n"); + for (i = 0; i < 31; i++) { + cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i, + *((uint64_t *)(&env->fir[i]))); + if ((i % 3) == 2) + cpu_fprintf(f, "\n"); + } + cpu_fprintf(f, "FT " TARGET_FMT_lx " " TARGET_FMT_lx " " TARGET_FMT_lx, + *((uint64_t *)(&env->ft0)), *((uint64_t *)(&env->ft1)), + *((uint64_t *)(&env->ft2))); + cpu_fprintf(f, "\nMEM " TARGET_FMT_lx " %d %d\n", + ldq_raw(0x000000004007df60ULL), + (uint8_t *)(&env->ft0), (uint8_t *)(&env->fir[0])); +} + +void cpu_dump_EA (target_ulong EA) +{ + FILE *f; + + if (logfile) + f = logfile; + else + f = stdout; + fprintf(f, "Memory access at address " TARGET_FMT_lx "\n", EA); +} diff --git a/target-alpha/op.c b/target-alpha/op.c new file mode 100644 index 000000000..8a22c5c08 --- /dev/null +++ b/target-alpha/op.c @@ -0,0 +1,1103 @@ +/* + * Alpha emulation cpu micro-operations for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define DEBUG_OP + +#include "config.h" +#include "exec.h" + +#include "op_helper.h" + +#define REG 0 +#include "op_template.h" + +#define REG 1 +#include "op_template.h" + +#define REG 2 +#include "op_template.h" + +#define REG 3 +#include "op_template.h" + +#define REG 4 +#include "op_template.h" + +#define REG 5 +#include "op_template.h" + +#define REG 6 +#include "op_template.h" + +#define REG 7 +#include "op_template.h" + +#define REG 8 +#include "op_template.h" + +#define REG 9 +#include "op_template.h" + +#define REG 10 +#include "op_template.h" + +#define REG 11 +#include "op_template.h" + +#define REG 12 +#include "op_template.h" + +#define REG 13 +#include "op_template.h" + +#define REG 14 +#include "op_template.h" + +#define REG 15 +#include "op_template.h" + +#define REG 16 +#include "op_template.h" + +#define REG 17 +#include "op_template.h" + +#define REG 18 +#include "op_template.h" + +#define REG 19 +#include "op_template.h" + +#define REG 20 +#include "op_template.h" + +#define REG 21 +#include "op_template.h" + +#define REG 22 +#include "op_template.h" + +#define REG 23 +#include "op_template.h" + +#define REG 24 +#include "op_template.h" + +#define REG 25 +#include "op_template.h" + +#define REG 26 +#include "op_template.h" + +#define REG 27 +#include "op_template.h" + +#define REG 28 +#include "op_template.h" + +#define REG 29 +#include "op_template.h" + +#define REG 30 +#include "op_template.h" + +#define REG 31 +#include "op_template.h" + +/* Debug stuff */ +void OPPROTO op_no_op (void) +{ +#if !defined (DEBUG_OP) + __asm__ __volatile__("nop" : : : "memory"); +#endif + RETURN(); +} + +void OPPROTO op_tb_flush (void) +{ + helper_tb_flush(); + RETURN(); +} + +/* Load and stores */ +#define MEMSUFFIX _raw +#include "op_mem.h" +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_mem.h" +#define MEMSUFFIX _kernel +#include "op_mem.h" +/* Those are used for supervisor, executive and pal modes */ +#define MEMSUFFIX _data +#include "op_mem.h" +#endif + +/* Special operation for load and store */ +void OPPROTO op_n7 (void) +{ + T0 &= ~(uint64_t)0x7; + RETURN(); +} + +/* Misc */ +void OPPROTO op_excp (void) +{ + helper_excp(PARAM(1), PARAM(2)); + RETURN(); +} + +void OPPROTO op_load_amask (void) +{ + helper_amask(); + RETURN(); +} + +void OPPROTO op_load_pcc (void) +{ + helper_load_pcc(); + RETURN(); +} + +void OPPROTO op_load_implver (void) +{ + helper_load_implver(); + RETURN(); +} + +void OPPROTO op_load_fpcr (void) +{ + helper_load_fpcr(); + RETURN(); +} + +void OPPROTO op_store_fpcr (void) +{ + helper_store_fpcr(); + RETURN(); +} + +void OPPROTO op_load_irf (void) +{ + helper_load_irf(); + RETURN(); +} + +void OPPROTO op_set_irf (void) +{ + helper_set_irf(); + RETURN(); +} + +void OPPROTO op_clear_irf (void) +{ + helper_clear_irf(); + RETURN(); +} + +void OPPROTO op_exit_tb (void) +{ + EXIT_TB(); +} + +/* Arithmetic */ +void OPPROTO op_addq (void) +{ + T0 += T1; + RETURN(); +} + +void OPPROTO op_addqv (void) +{ + helper_addqv(); + RETURN(); +} + +void OPPROTO op_addl (void) +{ + T0 = (int64_t)((int32_t)(T0 + T1)); + RETURN(); +} + +void OPPROTO op_addlv (void) +{ + helper_addlv(); + RETURN(); +} + +void OPPROTO op_subq (void) +{ + T0 -= T1; + RETURN(); +} + +void OPPROTO op_subqv (void) +{ + helper_subqv(); + RETURN(); +} + +void OPPROTO op_subl (void) +{ + T0 = (int64_t)((int32_t)(T0 - T1)); + RETURN(); +} + +void OPPROTO op_sublv (void) +{ + helper_sublv(); + RETURN(); +} + +void OPPROTO op_s4 (void) +{ + T0 <<= 2; + RETURN(); +} + +void OPPROTO op_s8 (void) +{ + T0 <<= 3; + RETURN(); +} + +void OPPROTO op_mull (void) +{ + T0 = (int64_t)((int32_t)T0 * (int32_t)T1); + RETURN(); +} + +void OPPROTO op_mullv (void) +{ + helper_mullv(); + RETURN(); +} + +void OPPROTO op_mulq (void) +{ + T0 *= T1; + RETURN(); +} + +void OPPROTO op_mulqv (void) +{ + helper_mulqv(); + RETURN(); +} + +void OPPROTO op_umulh (void) +{ + helper_umulh(); + RETURN(); +} + +/* Logical */ +void OPPROTO op_and (void) +{ + T0 &= T1; + RETURN(); +} + +void OPPROTO op_bic (void) +{ + T0 &= ~T1; + RETURN(); +} + +void OPPROTO op_bis (void) +{ + T0 |= T1; + RETURN(); +} + +void OPPROTO op_eqv (void) +{ + T0 ^= ~T1; + RETURN(); +} + +void OPPROTO op_ornot (void) +{ + T0 |= ~T1; + RETURN(); +} + +void OPPROTO op_xor (void) +{ + T0 ^= T1; + RETURN(); +} + +void OPPROTO op_sll (void) +{ + T0 <<= T1; + RETURN(); +} + +void OPPROTO op_srl (void) +{ + T0 >>= T1; + RETURN(); +} + +void OPPROTO op_sra (void) +{ + T0 = (int64_t)T0 >> T1; + RETURN(); +} + +void OPPROTO op_sextb (void) +{ + T0 = (int64_t)((int8_t)T0); + RETURN(); +} + +void OPPROTO op_sextw (void) +{ + T0 = (int64_t)((int16_t)T0); + RETURN(); + +} + +void OPPROTO op_ctpop (void) +{ + helper_ctpop(); + RETURN(); +} + +void OPPROTO op_ctlz (void) +{ + helper_ctlz(); + RETURN(); +} + +void OPPROTO op_cttz (void) +{ + helper_cttz(); + RETURN(); +} + +void OPPROTO op_mskbl (void) +{ + helper_mskbl(); + RETURN(); +} + +void OPPROTO op_extbl (void) +{ + helper_extbl(); + RETURN(); +} + +void OPPROTO op_insbl (void) +{ + helper_insbl(); + RETURN(); +} + +void OPPROTO op_mskwl (void) +{ + helper_mskwl(); + RETURN(); +} + +void OPPROTO op_extwl (void) +{ + helper_extwl(); + RETURN(); +} + +void OPPROTO op_inswl (void) +{ + helper_inswl(); + RETURN(); +} + +void OPPROTO op_mskll (void) +{ + helper_mskll(); + RETURN(); +} + +void OPPROTO op_extll (void) +{ + helper_extll(); + RETURN(); +} + +void OPPROTO op_insll (void) +{ + helper_insll(); + RETURN(); +} + +void OPPROTO op_zap (void) +{ + helper_zap(); + RETURN(); +} + +void OPPROTO op_zapnot (void) +{ + helper_zapnot(); + RETURN(); +} + +void OPPROTO op_mskql (void) +{ + helper_mskql(); + RETURN(); +} + +void OPPROTO op_extql (void) +{ + helper_extql(); + RETURN(); +} + +void OPPROTO op_insql (void) +{ + helper_insql(); + RETURN(); +} + +void OPPROTO op_mskwh (void) +{ + helper_mskwh(); + RETURN(); +} + +void OPPROTO op_inswh (void) +{ + helper_inswh(); + RETURN(); +} + +void OPPROTO op_extwh (void) +{ + helper_extwh(); + RETURN(); +} + +void OPPROTO op_msklh (void) +{ + helper_msklh(); + RETURN(); +} + +void OPPROTO op_inslh (void) +{ + helper_inslh(); + RETURN(); +} + +void OPPROTO op_extlh (void) +{ + helper_extlh(); + RETURN(); +} + +void OPPROTO op_mskqh (void) +{ + helper_mskqh(); + RETURN(); +} + +void OPPROTO op_insqh (void) +{ + helper_insqh(); + RETURN(); +} + +void OPPROTO op_extqh (void) +{ + helper_extqh(); + RETURN(); +} + +/* Tests */ +void OPPROTO op_cmpult (void) +{ + if (T0 < T1) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmpule (void) +{ + if (T0 <= T1) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmpeq (void) +{ + if (T0 == T1) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmplt (void) +{ + if ((int64_t)T0 < (int64_t)T1) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmple (void) +{ + if ((int64_t)T0 <= (int64_t)T1) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmpbge (void) +{ + helper_cmpbge(); + RETURN(); +} + +void OPPROTO op_cmpeqz (void) +{ + if (T0 == 0) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmpnez (void) +{ + if (T0 != 0) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmpltz (void) +{ + if ((int64_t)T0 < 0) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmplez (void) +{ + if ((int64_t)T0 <= 0) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmpgtz (void) +{ + if ((int64_t)T0 > 0) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmpgez (void) +{ + if ((int64_t)T0 >= 0) + T0 = 1; + else + T0 = 0; + RETURN(); +} + +void OPPROTO op_cmplbs (void) +{ + T0 &= 1; + RETURN(); +} + +void OPPROTO op_cmplbc (void) +{ + T0 = (~T0) & 1; + RETURN(); +} + +/* Branches */ +void OPPROTO op_branch (void) +{ + env->pc = T0 & ~3; + RETURN(); +} + +void OPPROTO op_addq1 (void) +{ + T1 += T0; + RETURN(); +} + +#if 0 // Qemu does not know how to do this... +void OPPROTO op_bcond (void) +{ + if (T0) + env->pc = T1 & ~3; + else + env->pc = PARAM(1); + RETURN(); +} +#else +void OPPROTO op_bcond (void) +{ + if (T0) + env->pc = T1 & ~3; + else + env->pc = ((uint64_t)PARAM(1) << 32) | (uint64_t)PARAM(2); + RETURN(); +} +#endif + +#if 0 // Qemu does not know how to do this... +void OPPROTO op_update_pc (void) +{ + env->pc = PARAM(1); + RETURN(); +} +#else +void OPPROTO op_update_pc (void) +{ + env->pc = ((uint64_t)PARAM(1) << 32) | (uint64_t)PARAM(2); + RETURN(); +} +#endif + +/* Optimization for 32 bits hosts architectures */ +void OPPROTO op_update_pc32 (void) +{ + env->pc = (uint64_t)PARAM(1); + RETURN(); +} + +/* IEEE floating point arithmetic */ +/* S floating (single) */ +void OPPROTO op_adds (void) +{ + FT0 = float32_add(FT0, FT1, &FP_STATUS); + RETURN(); +} + +void OPPROTO op_subs (void) +{ + FT0 = float32_sub(FT0, FT1, &FP_STATUS); + RETURN(); +} + +void OPPROTO op_muls (void) +{ + FT0 = float32_mul(FT0, FT1, &FP_STATUS); + RETURN(); +} + +void OPPROTO op_divs (void) +{ + FT0 = float32_div(FT0, FT1, &FP_STATUS); + RETURN(); +} + +void OPPROTO op_sqrts (void) +{ + helper_sqrts(); + RETURN(); +} + +void OPPROTO op_cpys (void) +{ + helper_cpys(); + RETURN(); +} + +void OPPROTO op_cpysn (void) +{ + helper_cpysn(); + RETURN(); +} + +void OPPROTO op_cpyse (void) +{ + helper_cpyse(); + RETURN(); +} + +void OPPROTO op_itofs (void) +{ + helper_itofs(); + RETURN(); +} + +void OPPROTO op_ftois (void) +{ + helper_ftois(); + RETURN(); +} + +/* T floating (double) */ +void OPPROTO op_addt (void) +{ + FT0 = float64_add(FT0, FT1, &FP_STATUS); + RETURN(); +} + +void OPPROTO op_subt (void) +{ + FT0 = float64_sub(FT0, FT1, &FP_STATUS); + RETURN(); +} + +void OPPROTO op_mult (void) +{ + FT0 = float64_mul(FT0, FT1, &FP_STATUS); + RETURN(); +} + +void OPPROTO op_divt (void) +{ + FT0 = float64_div(FT0, FT1, &FP_STATUS); + RETURN(); +} + +void OPPROTO op_sqrtt (void) +{ + helper_sqrtt(); + RETURN(); +} + +void OPPROTO op_cmptun (void) +{ + helper_cmptun(); + RETURN(); +} + +void OPPROTO op_cmpteq (void) +{ + helper_cmpteq(); + RETURN(); +} + +void OPPROTO op_cmptle (void) +{ + helper_cmptle(); + RETURN(); +} + +void OPPROTO op_cmptlt (void) +{ + helper_cmptlt(); + RETURN(); +} + +void OPPROTO op_itoft (void) +{ + helper_itoft(); + RETURN(); +} + +void OPPROTO op_ftoit (void) +{ + helper_ftoit(); + RETURN(); +} + +/* VAX floating point arithmetic */ +/* F floating */ +void OPPROTO op_addf (void) +{ + helper_addf(); + RETURN(); +} + +void OPPROTO op_subf (void) +{ + helper_subf(); + RETURN(); +} + +void OPPROTO op_mulf (void) +{ + helper_mulf(); + RETURN(); +} + +void OPPROTO op_divf (void) +{ + helper_divf(); + RETURN(); +} + +void OPPROTO op_sqrtf (void) +{ + helper_sqrtf(); + RETURN(); +} + +void OPPROTO op_cmpfeq (void) +{ + helper_cmpfeq(); + RETURN(); +} + +void OPPROTO op_cmpfne (void) +{ + helper_cmpfne(); + RETURN(); +} + +void OPPROTO op_cmpflt (void) +{ + helper_cmpflt(); + RETURN(); +} + +void OPPROTO op_cmpfle (void) +{ + helper_cmpfle(); + RETURN(); +} + +void OPPROTO op_cmpfgt (void) +{ + helper_cmpfgt(); + RETURN(); +} + +void OPPROTO op_cmpfge (void) +{ + helper_cmpfge(); + RETURN(); +} + +void OPPROTO op_itoff (void) +{ + helper_itoff(); + RETURN(); +} + +/* G floating */ +void OPPROTO op_addg (void) +{ + helper_addg(); + RETURN(); +} + +void OPPROTO op_subg (void) +{ + helper_subg(); + RETURN(); +} + +void OPPROTO op_mulg (void) +{ + helper_mulg(); + RETURN(); +} + +void OPPROTO op_divg (void) +{ + helper_divg(); + RETURN(); +} + +void OPPROTO op_sqrtg (void) +{ + helper_sqrtg(); + RETURN(); +} + +void OPPROTO op_cmpgeq (void) +{ + helper_cmpgeq(); + RETURN(); +} + +void OPPROTO op_cmpglt (void) +{ + helper_cmpglt(); + RETURN(); +} + +void OPPROTO op_cmpgle (void) +{ + helper_cmpgle(); + RETURN(); +} + +/* Floating point format conversion */ +void OPPROTO op_cvtst (void) +{ + FT0 = (float)FT0; + RETURN(); +} + +void OPPROTO op_cvtqs (void) +{ + helper_cvtqs(); + RETURN(); +} + +void OPPROTO op_cvtts (void) +{ + FT0 = (float)FT0; + RETURN(); +} + +void OPPROTO op_cvttq (void) +{ + helper_cvttq(); + RETURN(); +} + +void OPPROTO op_cvtqt (void) +{ + helper_cvtqt(); + RETURN(); +} + +void OPPROTO op_cvtqf (void) +{ + helper_cvtqf(); + RETURN(); +} + +void OPPROTO op_cvtgf (void) +{ + helper_cvtgf(); + RETURN(); +} + +void OPPROTO op_cvtgd (void) +{ + helper_cvtgd(); + RETURN(); +} + +void OPPROTO op_cvtgq (void) +{ + helper_cvtgq(); + RETURN(); +} + +void OPPROTO op_cvtqg (void) +{ + helper_cvtqg(); + RETURN(); +} + +void OPPROTO op_cvtdg (void) +{ + helper_cvtdg(); + RETURN(); +} + +void OPPROTO op_cvtlq (void) +{ + helper_cvtlq(); + RETURN(); +} + +void OPPROTO op_cvtql (void) +{ + helper_cvtql(); + RETURN(); +} + +void OPPROTO op_cvtqlv (void) +{ + helper_cvtqlv(); + RETURN(); +} + +void OPPROTO op_cvtqlsv (void) +{ + helper_cvtqlsv(); + RETURN(); +} + +/* PALcode support special instructions */ +#if !defined (CONFIG_USER_ONLY) +void OPPROTO op_hw_rei (void) +{ + env->pc = env->ipr[IPR_EXC_ADDR] & ~3; + env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1; + /* XXX: re-enable interrupts and memory mapping */ + RETURN(); +} + +void OPPROTO op_hw_ret (void) +{ + env->pc = T0 & ~3; + env->ipr[IPR_EXC_ADDR] = T0 & 1; + /* XXX: re-enable interrupts and memory mapping */ + RETURN(); +} + +void OPPROTO op_mfpr (void) +{ + helper_mfpr(PARAM(1)); + RETURN(); +} + +void OPPROTO op_mtpr (void) +{ + helper_mtpr(PARAM(1)); + RETURN(); +} + +void OPPROTO op_set_alt_mode (void) +{ + env->saved_mode = env->ps & 0xC; + env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC); + RETURN(); +} + +void OPPROTO op_restore_mode (void) +{ + env->ps = (env->ps & ~0xC) | env->saved_mode; + RETURN(); +} + +void OPPROTO op_ld_phys_to_virt (void) +{ + helper_ld_phys_to_virt(); + RETURN(); +} + +void OPPROTO op_st_phys_to_virt (void) +{ + helper_st_phys_to_virt(); + RETURN(); +} +#endif /* !defined (CONFIG_USER_ONLY) */ diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c new file mode 100644 index 000000000..746665a42 --- /dev/null +++ b/target-alpha/op_helper.c @@ -0,0 +1,1255 @@ +/* + * Alpha emulation cpu micro-operations helpers for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "exec.h" +#include "softfloat.h" + +#include "op_helper.h" + +#define MEMSUFFIX _raw +#include "op_helper_mem.h" + +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_helper_mem.h" + +#define MEMSUFFIX _kernel +#include "op_helper_mem.h" + +/* Those are used for supervisor and executive modes */ +#define MEMSUFFIX _data +#include "op_helper_mem.h" +#endif + +void helper_tb_flush (void) +{ + tlb_flush(env, 1); +} + +void cpu_dump_EA (target_ulong EA); +void helper_print_mem_EA (target_ulong EA) +{ + cpu_dump_EA(EA); +} + +/*****************************************************************************/ +/* Exceptions processing helpers */ +void helper_excp (uint32_t excp, uint32_t error) +{ + env->exception_index = excp; + env->error_code = error; + cpu_loop_exit(); +} + +void helper_amask (void) +{ + switch (env->implver) { + case IMPLVER_2106x: + /* EV4, EV45, LCA, LCA45 & EV5 */ + break; + case IMPLVER_21164: + case IMPLVER_21264: + case IMPLVER_21364: + T0 &= ~env->amask; + break; + } +} + +void helper_load_pcc (void) +{ + /* XXX: TODO */ + T0 = 0; +} + +void helper_load_implver (void) +{ + T0 = env->implver; +} + +void helper_load_fpcr (void) +{ + T0 = 0; +#ifdef CONFIG_SOFTFLOAT + T0 |= env->fp_status.float_exception_flags << 52; + if (env->fp_status.float_exception_flags) + T0 |= 1ULL << 63; + env->ipr[IPR_EXC_SUM] &= ~0x3E: + env->ipr[IPR_EXC_SUM] |= env->fp_status.float_exception_flags << 1; +#endif + switch (env->fp_status.float_rounding_mode) { + case float_round_nearest_even: + T0 |= 2ULL << 58; + break; + case float_round_down: + T0 |= 1ULL << 58; + break; + case float_round_up: + T0 |= 3ULL << 58; + break; + case float_round_to_zero: + break; + } +} + +void helper_store_fpcr (void) +{ +#ifdef CONFIG_SOFTFLOAT + set_float_exception_flags((T0 >> 52) & 0x3F, &FP_STATUS); +#endif + switch ((T0 >> 58) & 3) { + case 0: + set_float_rounding_mode(float_round_to_zero, &FP_STATUS); + break; + case 1: + set_float_rounding_mode(float_round_down, &FP_STATUS); + break; + case 2: + set_float_rounding_mode(float_round_nearest_even, &FP_STATUS); + break; + case 3: + set_float_rounding_mode(float_round_up, &FP_STATUS); + break; + } +} + +void helper_load_irf (void) +{ + /* XXX: TODO */ + T0 = 0; +} + +void helper_set_irf (void) +{ + /* XXX: TODO */ +} + +void helper_clear_irf (void) +{ + /* XXX: TODO */ +} + +void helper_addqv (void) +{ + T2 = T0; + T0 += T1; + if (unlikely((T2 ^ T1 ^ (-1ULL)) & (T2 ^ T0) & (1ULL << 63))) { + helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + } +} + +void helper_addlv (void) +{ + T2 = T0; + T0 = (uint32_t)(T0 + T1); + if (unlikely((T2 ^ T1 ^ (-1UL)) & (T2 ^ T0) & (1UL << 31))) { + helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + } +} + +void helper_subqv (void) +{ + T2 = T0; + T0 -= T1; + if (unlikely(((~T2) ^ T0 ^ (-1ULL)) & ((~T2) ^ T1) & (1ULL << 63))) { + helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + } +} + +void helper_sublv (void) +{ + T2 = T0; + T0 = (uint32_t)(T0 - T1); + if (unlikely(((~T2) ^ T0 ^ (-1UL)) & ((~T2) ^ T1) & (1UL << 31))) { + helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + } +} + +void helper_mullv (void) +{ + int64_t res = (int64_t)T0 * (int64_t)T1; + + if (unlikely((int32_t)res != res)) { + helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + } + T0 = (int64_t)((int32_t)res); +} + +void helper_mulqv () +{ + uint64_t res, tmp0, tmp1; + + res = (T0 >> 32) * (T1 >> 32); + tmp0 = ((T0 & 0xFFFFFFFF) * (T1 >> 32)) + + ((T0 >> 32) * (T1 & 0xFFFFFFFF)); + tmp1 = (T0 & 0xFFFFFFFF) * (T1 & 0xFFFFFFFF); + tmp0 += tmp1 >> 32; + res += tmp0 >> 32; + T0 *= T1; + if (unlikely(res != 0)) { + helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + } +} + +void helper_umulh (void) +{ + uint64_t tmp0, tmp1; + + tmp0 = ((T0 & 0xFFFFFFFF) * (T1 >> 32)) + + ((T0 >> 32) * (T1 & 0xFFFFFFFF)); + tmp1 = (T0 & 0xFFFFFFFF) * (T1 & 0xFFFFFFFF); + tmp0 += tmp1 >> 32; + T0 = (T0 >> 32) * (T0 >> 32); + T0 += tmp0 >> 32; +} + +void helper_ctpop (void) +{ + int n; + + for (n = 0; T0 != 0; n++) + T0 = T0 ^ (T0 - 1); + T0 = n; +} + +void helper_ctlz (void) +{ + uint32_t op32; + int n; + + n = 0; + if (!(T0 & 0xFFFFFFFF00000000ULL)) { + n += 32; + T0 <<= 32; + } + /* Make it easier for 32 bits hosts */ + op32 = T0 >> 32; + if (!(op32 & 0xFFFF0000UL)) { + n += 16; + op32 <<= 16; + } + if (!(op32 & 0xFF000000UL)) { + n += 8; + op32 <<= 8; + } + if (!(op32 & 0xF0000000UL)) { + n += 4; + op32 <<= 4; + } + if (!(op32 & 0xC0000000UL)) { + n += 2; + op32 <<= 2; + } + if (!(op32 & 0x80000000UL)) { + n++; + op32 <<= 1; + } + if (!(op32 & 0x80000000UL)) { + n++; + } + T0 = n; +} + +void helper_cttz (void) +{ + uint32_t op32; + int n; + + n = 0; + if (!(T0 & 0x00000000FFFFFFFFULL)) { + n += 32; + T0 >>= 32; + } + /* Make it easier for 32 bits hosts */ + op32 = T0; + if (!(op32 & 0x0000FFFFUL)) { + n += 16; + op32 >>= 16; + } + if (!(op32 & 0x000000FFUL)) { + n += 8; + op32 >>= 8; + } + if (!(op32 & 0x0000000FUL)) { + n += 4; + op32 >>= 4; + } + if (!(op32 & 0x00000003UL)) { + n += 2; + op32 >>= 2; + } + if (!(op32 & 0x00000001UL)) { + n++; + op32 >>= 1; + } + if (!(op32 & 0x00000001UL)) { + n++; + } + T0 = n; +} + +static inline uint64_t byte_zap (uint64_t op, uint8_t mskb) +{ + uint64_t mask; + + mask = 0; + mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL; + mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL; + mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL; + mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL; + mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL; + mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL; + mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL; + mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL; + + return op & ~mask; +} + +void helper_mskbl (void) +{ + T0 = byte_zap(T0, 0x01 << (T1 & 7)); +} + +void helper_extbl (void) +{ + T0 >>= (T1 & 7) * 8; + T0 = byte_zap(T0, 0xFE); +} + +void helper_insbl (void) +{ + T0 <<= (T1 & 7) * 8; + T0 = byte_zap(T0, ~(0x01 << (T1 & 7))); +} + +void helper_mskwl (void) +{ + T0 = byte_zap(T0, 0x03 << (T1 & 7)); +} + +void helper_extwl (void) +{ + T0 >>= (T1 & 7) * 8; + T0 = byte_zap(T0, 0xFC); +} + +void helper_inswl (void) +{ + T0 <<= (T1 & 7) * 8; + T0 = byte_zap(T0, ~(0x03 << (T1 & 7))); +} + +void helper_mskll (void) +{ + T0 = byte_zap(T0, 0x0F << (T1 & 7)); +} + +void helper_extll (void) +{ + T0 >>= (T1 & 7) * 8; + T0 = byte_zap(T0, 0xF0); +} + +void helper_insll (void) +{ + T0 <<= (T1 & 7) * 8; + T0 = byte_zap(T0, ~(0x0F << (T1 & 7))); +} + +void helper_zap (void) +{ + T0 = byte_zap(T0, T1); +} + +void helper_zapnot (void) +{ + T0 = byte_zap(T0, ~T1); +} + +void helper_mskql (void) +{ + T0 = byte_zap(T0, 0xFF << (T1 & 7)); +} + +void helper_extql (void) +{ + T0 >>= (T1 & 7) * 8; + T0 = byte_zap(T0, 0x00); +} + +void helper_insql (void) +{ + T0 <<= (T1 & 7) * 8; + T0 = byte_zap(T0, ~(0xFF << (T1 & 7))); +} + +void helper_mskwh (void) +{ + T0 = byte_zap(T0, (0x03 << (T1 & 7)) >> 8); +} + +void helper_inswh (void) +{ + T0 >>= 64 - ((T1 & 7) * 8); + T0 = byte_zap(T0, ~((0x03 << (T1 & 7)) >> 8)); +} + +void helper_extwh (void) +{ + T0 <<= 64 - ((T1 & 7) * 8); + T0 = byte_zap(T0, ~0x07); +} + +void helper_msklh (void) +{ + T0 = byte_zap(T0, (0x0F << (T1 & 7)) >> 8); +} + +void helper_inslh (void) +{ + T0 >>= 64 - ((T1 & 7) * 8); + T0 = byte_zap(T0, ~((0x0F << (T1 & 7)) >> 8)); +} + +void helper_extlh (void) +{ + T0 <<= 64 - ((T1 & 7) * 8); + T0 = byte_zap(T0, ~0x0F); +} + +void helper_mskqh (void) +{ + T0 = byte_zap(T0, (0xFF << (T1 & 7)) >> 8); +} + +void helper_insqh (void) +{ + T0 >>= 64 - ((T1 & 7) * 8); + T0 = byte_zap(T0, ~((0xFF << (T1 & 7)) >> 8)); +} + +void helper_extqh (void) +{ + T0 <<= 64 - ((T1 & 7) * 8); + T0 = byte_zap(T0, 0x00); +} + +void helper_cmpbge (void) +{ + uint8_t opa, opb, res; + int i; + + res = 0; + for (i = 0; i < 7; i++) { + opa = T0 >> (i * 8); + opb = T1 >> (i * 8); + if (opa >= opb) + res |= 1 << i; + } + T0 = res; +} + +void helper_cmov_fir (int freg) +{ + if (FT0 != 0) + env->fir[freg] = FT1; +} + +void helper_sqrts (void) +{ + FT0 = float32_sqrt(FT0, &FP_STATUS); +} + +void helper_cpys (void) +{ + union { + double d; + uint64_t i; + } p, q, r; + + p.d = FT0; + q.d = FT1; + r.i = p.i & 0x8000000000000000ULL; + r.i |= q.i & ~0x8000000000000000ULL; + FT0 = r.d; +} + +void helper_cpysn (void) +{ + union { + double d; + uint64_t i; + } p, q, r; + + p.d = FT0; + q.d = FT1; + r.i = (~p.i) & 0x8000000000000000ULL; + r.i |= q.i & ~0x8000000000000000ULL; + FT0 = r.d; +} + +void helper_cpyse (void) +{ + union { + double d; + uint64_t i; + } p, q, r; + + p.d = FT0; + q.d = FT1; + r.i = p.i & 0xFFF0000000000000ULL; + r.i |= q.i & ~0xFFF0000000000000ULL; + FT0 = r.d; +} + +void helper_itofs (void) +{ + union { + double d; + uint64_t i; + } p; + + p.d = FT0; + FT0 = int64_to_float32(p.i, &FP_STATUS); +} + +void helper_ftois (void) +{ + union { + double d; + uint64_t i; + } p; + + p.i = float32_to_int64(FT0, &FP_STATUS); + FT0 = p.d; +} + +void helper_sqrtt (void) +{ + FT0 = float64_sqrt(FT0, &FP_STATUS); +} + +void helper_cmptun (void) +{ + union { + double d; + uint64_t i; + } p; + + p.i = 0; + if (float64_is_nan(FT0) || float64_is_nan(FT1)) + p.i = 0x4000000000000000ULL; + FT0 = p.d; +} + +void helper_cmpteq (void) +{ + union { + double d; + uint64_t i; + } p; + + p.i = 0; + if (float64_eq(FT0, FT1, &FP_STATUS)) + p.i = 0x4000000000000000ULL; + FT0 = p.d; +} + +void helper_cmptle (void) +{ + union { + double d; + uint64_t i; + } p; + + p.i = 0; + if (float64_le(FT0, FT1, &FP_STATUS)) + p.i = 0x4000000000000000ULL; + FT0 = p.d; +} + +void helper_cmptlt (void) +{ + union { + double d; + uint64_t i; + } p; + + p.i = 0; + if (float64_lt(FT0, FT1, &FP_STATUS)) + p.i = 0x4000000000000000ULL; + FT0 = p.d; +} + +void helper_itoft (void) +{ + union { + double d; + uint64_t i; + } p; + + p.d = FT0; + FT0 = int64_to_float64(p.i, &FP_STATUS); +} + +void helper_ftoit (void) +{ + union { + double d; + uint64_t i; + } p; + + p.i = float64_to_int64(FT0, &FP_STATUS); + FT0 = p.d; +} + +static int vaxf_is_valid (float ff) +{ + union { + float f; + uint32_t i; + } p; + uint32_t exp, mant; + + p.f = ff; + exp = (p.i >> 23) & 0xFF; + mant = p.i & 0x007FFFFF; + if (exp == 0 && ((p.i & 0x80000000) || mant != 0)) { + /* Reserved operands / Dirty zero */ + return 0; + } + + return 1; +} + +static float vaxf_to_ieee32 (float ff) +{ + union { + float f; + uint32_t i; + } p; + uint32_t exp; + + p.f = ff; + exp = (p.i >> 23) & 0xFF; + if (exp < 3) { + /* Underflow */ + p.f = 0.0; + } else { + p.f *= 0.25; + } + + return p.f; +} + +static float ieee32_to_vaxf (float fi) +{ + union { + float f; + uint32_t i; + } p; + uint32_t exp, mant; + + p.f = fi; + exp = (p.i >> 23) & 0xFF; + mant = p.i & 0x007FFFFF; + if (exp == 255) { + /* NaN or infinity */ + p.i = 1; + } else if (exp == 0) { + if (mant == 0) { + /* Zero */ + p.i = 0; + } else { + /* Denormalized */ + p.f *= 2.0; + } + } else { + if (exp >= 253) { + /* Overflow */ + p.i = 1; + } else { + p.f *= 4.0; + } + } + + return p.f; +} + +void helper_addf (void) +{ + float ft0, ft1, ft2; + + if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxf_to_ieee32(FT0); + ft1 = vaxf_to_ieee32(FT1); + ft2 = float32_add(ft0, ft1, &FP_STATUS); + FT0 = ieee32_to_vaxf(ft2); +} + +void helper_subf (void) +{ + float ft0, ft1, ft2; + + if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxf_to_ieee32(FT0); + ft1 = vaxf_to_ieee32(FT1); + ft2 = float32_sub(ft0, ft1, &FP_STATUS); + FT0 = ieee32_to_vaxf(ft2); +} + +void helper_mulf (void) +{ + float ft0, ft1, ft2; + + if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxf_to_ieee32(FT0); + ft1 = vaxf_to_ieee32(FT1); + ft2 = float32_mul(ft0, ft1, &FP_STATUS); + FT0 = ieee32_to_vaxf(ft2); +} + +void helper_divf (void) +{ + float ft0, ft1, ft2; + + if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxf_to_ieee32(FT0); + ft1 = vaxf_to_ieee32(FT1); + ft2 = float32_div(ft0, ft1, &FP_STATUS); + FT0 = ieee32_to_vaxf(ft2); +} + +void helper_sqrtf (void) +{ + float ft0, ft1; + + if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxf_to_ieee32(FT0); + ft1 = float32_sqrt(ft0, &FP_STATUS); + FT0 = ieee32_to_vaxf(ft1); +} + +void helper_itoff (void) +{ + /* XXX: TODO */ +} + +static int vaxg_is_valid (double ff) +{ + union { + double f; + uint64_t i; + } p; + uint64_t exp, mant; + + p.f = ff; + exp = (p.i >> 52) & 0x7FF; + mant = p.i & 0x000FFFFFFFFFFFFFULL; + if (exp == 0 && ((p.i & 0x8000000000000000ULL) || mant != 0)) { + /* Reserved operands / Dirty zero */ + return 0; + } + + return 1; +} + +static double vaxg_to_ieee64 (double fg) +{ + union { + double f; + uint64_t i; + } p; + uint32_t exp; + + p.f = fg; + exp = (p.i >> 52) & 0x7FF; + if (exp < 3) { + /* Underflow */ + p.f = 0.0; + } else { + p.f *= 0.25; + } + + return p.f; +} + +static double ieee64_to_vaxg (double fi) +{ + union { + double f; + uint64_t i; + } p; + uint64_t mant; + uint32_t exp; + + p.f = fi; + exp = (p.i >> 52) & 0x7FF; + mant = p.i & 0x000FFFFFFFFFFFFFULL; + if (exp == 255) { + /* NaN or infinity */ + p.i = 1; /* VAX dirty zero */ + } else if (exp == 0) { + if (mant == 0) { + /* Zero */ + p.i = 0; + } else { + /* Denormalized */ + p.f *= 2.0; + } + } else { + if (exp >= 2045) { + /* Overflow */ + p.i = 1; /* VAX dirty zero */ + } else { + p.f *= 4.0; + } + } + + return p.f; +} + +void helper_addg (void) +{ + double ft0, ft1, ft2; + + if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxg_to_ieee64(FT0); + ft1 = vaxg_to_ieee64(FT1); + ft2 = float64_add(ft0, ft1, &FP_STATUS); + FT0 = ieee64_to_vaxg(ft2); +} + +void helper_subg (void) +{ + double ft0, ft1, ft2; + + if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxg_to_ieee64(FT0); + ft1 = vaxg_to_ieee64(FT1); + ft2 = float64_sub(ft0, ft1, &FP_STATUS); + FT0 = ieee64_to_vaxg(ft2); +} + +void helper_mulg (void) +{ + double ft0, ft1, ft2; + + if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxg_to_ieee64(FT0); + ft1 = vaxg_to_ieee64(FT1); + ft2 = float64_mul(ft0, ft1, &FP_STATUS); + FT0 = ieee64_to_vaxg(ft2); +} + +void helper_divg (void) +{ + double ft0, ft1, ft2; + + if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxg_to_ieee64(FT0); + ft1 = vaxg_to_ieee64(FT1); + ft2 = float64_div(ft0, ft1, &FP_STATUS); + FT0 = ieee64_to_vaxg(ft2); +} + +void helper_sqrtg (void) +{ + double ft0, ft1; + + if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxg_to_ieee64(FT0); + ft1 = float64_sqrt(ft0, &FP_STATUS); + FT0 = ieee64_to_vaxg(ft1); +} + +void helper_cmpgeq (void) +{ + union { + double d; + uint64_t u; + } p; + double ft0, ft1; + + if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxg_to_ieee64(FT0); + ft1 = vaxg_to_ieee64(FT1); + p.u = 0; + if (float64_eq(ft0, ft1, &FP_STATUS)) + p.u = 0x4000000000000000ULL; + FT0 = p.d; +} + +void helper_cmpglt (void) +{ + union { + double d; + uint64_t u; + } p; + double ft0, ft1; + + if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxg_to_ieee64(FT0); + ft1 = vaxg_to_ieee64(FT1); + p.u = 0; + if (float64_lt(ft0, ft1, &FP_STATUS)) + p.u = 0x4000000000000000ULL; + FT0 = p.d; +} + +void helper_cmpgle (void) +{ + union { + double d; + uint64_t u; + } p; + double ft0, ft1; + + if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) { + /* XXX: TODO */ + } + ft0 = vaxg_to_ieee64(FT0); + ft1 = vaxg_to_ieee64(FT1); + p.u = 0; + if (float64_le(ft0, ft1, &FP_STATUS)) + p.u = 0x4000000000000000ULL; + FT0 = p.d; +} + +void helper_cvtqs (void) +{ + union { + double d; + uint64_t u; + } p; + + p.d = FT0; + FT0 = (float)p.u; +} + +void helper_cvttq (void) +{ + union { + double d; + uint64_t u; + } p; + + p.u = FT0; + FT0 = p.d; +} + +void helper_cvtqt (void) +{ + union { + double d; + uint64_t u; + } p; + + p.d = FT0; + FT0 = p.u; +} + +void helper_cvtqf (void) +{ + union { + double d; + uint64_t u; + } p; + + p.d = FT0; + FT0 = ieee32_to_vaxf(p.u); +} + +void helper_cvtgf (void) +{ + double ft0; + + ft0 = vaxg_to_ieee64(FT0); + FT0 = ieee32_to_vaxf(ft0); +} + +void helper_cvtgd (void) +{ + /* XXX: TODO */ +} + +void helper_cvtgq (void) +{ + union { + double d; + uint64_t u; + } p; + + p.u = vaxg_to_ieee64(FT0); + FT0 = p.d; +} + +void helper_cvtqg (void) +{ + union { + double d; + uint64_t u; + } p; + + p.d = FT0; + FT0 = ieee64_to_vaxg(p.u); +} + +void helper_cvtdg (void) +{ + /* XXX: TODO */ +} + +void helper_cvtlq (void) +{ + union { + double d; + uint64_t u; + } p, q; + + p.d = FT0; + q.u = (p.u >> 29) & 0x3FFFFFFF; + q.u |= (p.u >> 32); + q.u = (int64_t)((int32_t)q.u); + FT0 = q.d; +} + +static inline void __helper_cvtql (int s, int v) +{ + union { + double d; + uint64_t u; + } p, q; + + p.d = FT0; + q.u = ((uint64_t)(p.u & 0xC0000000)) << 32; + q.u |= ((uint64_t)(p.u & 0x7FFFFFFF)) << 29; + FT0 = q.d; + if (v && (int64_t)((int32_t)p.u) != (int64_t)p.u) { + helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + } + if (s) { + /* TODO */ + } +} + +void helper_cvtql (void) +{ + __helper_cvtql(0, 0); +} + +void helper_cvtqlv (void) +{ + __helper_cvtql(0, 1); +} + +void helper_cvtqlsv (void) +{ + __helper_cvtql(1, 1); +} + +void helper_cmpfeq (void) +{ + if (float64_eq(FT0, FT1, &FP_STATUS)) + T0 = 1; + else + T0 = 0; +} + +void helper_cmpfne (void) +{ + if (float64_eq(FT0, FT1, &FP_STATUS)) + T0 = 0; + else + T0 = 1; +} + +void helper_cmpflt (void) +{ + if (float64_lt(FT0, FT1, &FP_STATUS)) + T0 = 1; + else + T0 = 0; +} + +void helper_cmpfle (void) +{ + if (float64_lt(FT0, FT1, &FP_STATUS)) + T0 = 1; + else + T0 = 0; +} + +void helper_cmpfgt (void) +{ + if (float64_le(FT0, FT1, &FP_STATUS)) + T0 = 0; + else + T0 = 1; +} + +void helper_cmpfge (void) +{ + if (float64_lt(FT0, FT1, &FP_STATUS)) + T0 = 0; + else + T0 = 1; +} + +#if !defined (CONFIG_USER_ONLY) +void helper_mfpr (int iprn) +{ + uint64_t val; + + if (cpu_alpha_mfpr(env, iprn, &val) == 0) + T0 = val; +} + +void helper_mtpr (int iprn) +{ + cpu_alpha_mtpr(env, iprn, T0, NULL); +} +#endif + +/*****************************************************************************/ +/* Softmmu support */ +#if !defined (CONFIG_USER_ONLY) + +#define GETPC() (__builtin_return_address(0)) + +/* XXX: the two following helpers are pure hacks. + * Hopefully, we emulate the PALcode, then we should never see + * HW_LD / HW_ST instructions. + */ +void helper_ld_phys_to_virt (void) +{ + uint64_t tlb_addr, physaddr; + int index, is_user; + void *retaddr; + + is_user = (env->ps >> 3) & 3; + index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[is_user][index].addr_read; + if ((T0 & TARGET_PAGE_MASK) == + (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + physaddr = T0 + env->tlb_table[is_user][index].addend; + } else { + /* the page is not in the TLB : fill it */ + retaddr = GETPC(); + tlb_fill(T0, 0, is_user, retaddr); + goto redo; + } + T0 = physaddr; +} + +void helper_st_phys_to_virt (void) +{ + uint64_t tlb_addr, physaddr; + int index, is_user; + void *retaddr; + + is_user = (env->ps >> 3) & 3; + index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + redo: + tlb_addr = env->tlb_table[is_user][index].addr_write; + if ((T0 & TARGET_PAGE_MASK) == + (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + physaddr = T0 + env->tlb_table[is_user][index].addend; + } else { + /* the page is not in the TLB : fill it */ + retaddr = GETPC(); + tlb_fill(T0, 1, is_user, retaddr); + goto redo; + } + T0 = physaddr; +} + +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + target_phys_addr_t pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (!likely(ret == 0)) { + if (likely(retaddr)) { + /* now we have a real cpu fault */ + pc = (target_phys_addr_t)retaddr; + tb = tb_find_pc(pc); + if (likely(tb)) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc, NULL); + } + } + /* Exception index and error code are already set */ + cpu_loop_exit(); + } + env = saved_env; +} + +#endif diff --git a/target-alpha/op_helper.h b/target-alpha/op_helper.h new file mode 100644 index 000000000..fb55eff37 --- /dev/null +++ b/target-alpha/op_helper.h @@ -0,0 +1,141 @@ +/* + * Alpha emulation cpu micro-operations helpers definitions for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void helper_call_pal (uint32_t palcode); +void helper_excp (uint32_t excp, uint32_t error); +void helper_amask (void); +void helper_load_pcc (void); +void helper_load_implver (void); +void helper_load_fpcr (void); +void helper_store_fpcr (void); +void helper_load_irf (void); +void helper_set_irf (void); +void helper_clear_irf (void); +void helper_addqv (void); +void helper_addlv (void); +void helper_subqv (void); +void helper_sublv (void); +void helper_mullv (void); +void helper_mulqv (void); +void helper_umulh (void); +void helper_ctpop (void); +void helper_ctlz (void); +void helper_cttz (void); +void helper_mskbl (void); +void helper_extbl (void); +void helper_insbl (void); +void helper_mskwl (void); +void helper_extwl (void); +void helper_inswl (void); +void helper_mskll (void); +void helper_extll (void); +void helper_insll (void); +void helper_zap (void); +void helper_zapnot (void); +void helper_mskql (void); +void helper_extql (void); +void helper_insql (void); +void helper_mskwh (void); +void helper_inswh (void); +void helper_extwh (void); +void helper_msklh (void); +void helper_inslh (void); +void helper_extlh (void); +void helper_mskqh (void); +void helper_insqh (void); +void helper_extqh (void); +void helper_cmpbge (void); +void helper_cmov_fir (int freg); + +double helper_ldff_raw (target_ulong ea); +void helper_stff_raw (target_ulong ea, double op); +double helper_ldfg_raw (target_ulong ea); +void helper_stfg_raw (target_ulong ea, double op); +#if !defined(CONFIG_USER_ONLY) +double helper_ldff_user (target_ulong ea); +void helper_stff_user (target_ulong ea, double op); +double helper_ldff_kernel (target_ulong ea); +void helper_stff_kernel (target_ulong ea, double op); +double helper_ldff_data (target_ulong ea); +void helper_stff_data (target_ulong ea, double op); +double helper_ldfg_user (target_ulong ea); +void helper_stfg_user (target_ulong ea, double op); +double helper_ldfg_kernel (target_ulong ea); +void helper_stfg_kernel (target_ulong ea, double op); +double helper_ldfg_data (target_ulong ea); +void helper_stfg_data (target_ulong ea, double op); +#endif + +void helper_sqrts (void); +void helper_cpys (void); +void helper_cpysn (void); +void helper_cpyse (void); +void helper_itofs (void); +void helper_ftois (void); + +void helper_sqrtt (void); +void helper_cmptun (void); +void helper_cmpteq (void); +void helper_cmptle (void); +void helper_cmptlt (void); +void helper_itoft (void); +void helper_ftoit (void); + +void helper_addf (void); +void helper_subf (void); +void helper_mulf (void); +void helper_divf (void); +void helper_sqrtf (void); +void helper_cmpfeq (void); +void helper_cmpfne (void); +void helper_cmpflt (void); +void helper_cmpfle (void); +void helper_cmpfgt (void); +void helper_cmpfge (void); +void helper_itoff (void); + +void helper_addg (void); +void helper_subg (void); +void helper_mulg (void); +void helper_divg (void); +void helper_sqrtg (void); +void helper_cmpgeq (void); +void helper_cmpglt (void); +void helper_cmpgle (void); + +void helper_cvtqs (void); +void helper_cvttq (void); +void helper_cvtqt (void); +void helper_cvtqf (void); +void helper_cvtgf (void); +void helper_cvtgd (void); +void helper_cvtgq (void); +void helper_cvtqg (void); +void helper_cvtdg (void); +void helper_cvtlq (void); +void helper_cvtql (void); +void helper_cvtqlv (void); +void helper_cvtqlsv (void); + +void helper_mfpr (int iprn); +void helper_mtpr (int iprn); +void helper_ld_phys_to_virt (void); +void helper_st_phys_to_virt (void); +void helper_tb_flush (void); diff --git a/target-alpha/op_helper_mem.h b/target-alpha/op_helper_mem.h new file mode 100644 index 000000000..7ab5718b9 --- /dev/null +++ b/target-alpha/op_helper_mem.h @@ -0,0 +1,40 @@ +/* + * Alpha emulation cpu micro-operations helpers for memory accesses for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * 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 + */ + +/* XXX: TODO */ +double glue(helper_ldff, MEMSUFFIX) (target_ulong ea) +{ + return 0; +} + +void glue(helper_stff, MEMSUFFIX) (target_ulong ea, double op) +{ +} + +double glue(helper_ldfg, MEMSUFFIX) (target_ulong ea) +{ + return 0; +} + +void glue(helper_stfg, MEMSUFFIX) (target_ulong ea, double op) +{ +} + +#undef MEMSUFFIX diff --git a/target-alpha/op_mem.h b/target-alpha/op_mem.h new file mode 100644 index 000000000..9f017a2af --- /dev/null +++ b/target-alpha/op_mem.h @@ -0,0 +1,125 @@ +/* + * Alpha emulation cpu micro-operations for memory accesses for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define DEBUG_MEM_ACCESSES +#if defined (DEBUG_MEM_ACCESSES) +void helper_print_mem_EA (target_ulong EA); +#define print_mem_EA(EA) do { helper_print_mem_EA(EA); } while (0) +#else +#define print_mem_EA(EA) do { } while (0) +#endif + +static inline uint32_t glue(ldl_l, MEMSUFFIX) (target_ulong EA) +{ + env->lock = EA; + + return glue(ldl, MEMSUFFIX)(EA); +} + +static inline uint32_t glue(ldq_l, MEMSUFFIX) (target_ulong EA) +{ + env->lock = EA; + + return glue(ldq, MEMSUFFIX)(EA); +} + +static inline void glue(stl_c, MEMSUFFIX) (target_ulong EA, uint32_t data) +{ + if (EA == env->lock) { + glue(stl, MEMSUFFIX)(EA, data); + T0 = 0; + } else { + T0 = 1; + } + env->lock = -1; +} + +static inline void glue(stq_c, MEMSUFFIX) (target_ulong EA, uint64_t data) +{ + if (EA == env->lock) { + glue(stq, MEMSUFFIX)(EA, data); + T0 = 0; + } else { + T0 = 1; + } + env->lock = -1; +} + +#define ALPHA_LD_OP(name, op) \ +void OPPROTO glue(glue(op_ld, name), MEMSUFFIX) (void) \ +{ \ + print_mem_EA(T0); \ + T1 = glue(op, MEMSUFFIX)(T0); \ + RETURN(); \ +} + +#define ALPHA_ST_OP(name, op) \ +void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \ +{ \ + print_mem_EA(T0); \ + glue(op, MEMSUFFIX)(T0, T1); \ + RETURN(); \ +} + +ALPHA_LD_OP(bu, ldub); +ALPHA_ST_OP(b, stb); +ALPHA_LD_OP(wu, lduw); +ALPHA_ST_OP(w, stw); +ALPHA_LD_OP(l, ldl); +ALPHA_ST_OP(l, stl); +ALPHA_LD_OP(q, ldq); +ALPHA_ST_OP(q, stq); + +ALPHA_LD_OP(q_u, ldq); +ALPHA_ST_OP(q_u, stq); + +ALPHA_LD_OP(l_l, ldl_l); +ALPHA_LD_OP(q_l, ldq_l); +ALPHA_ST_OP(l_c, stl_c); +ALPHA_ST_OP(q_c, stq_c); + +#define ALPHA_LDF_OP(name, op) \ +void OPPROTO glue(glue(op_ld, name), MEMSUFFIX) (void) \ +{ \ + print_mem_EA(T0); \ + FT1 = glue(op, MEMSUFFIX)(T0); \ + RETURN(); \ +} + +#define ALPHA_STF_OP(name, op) \ +void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \ +{ \ + print_mem_EA(T0); \ + glue(op, MEMSUFFIX)(T0, FT1); \ + RETURN(); \ +} + +ALPHA_LDF_OP(t, ldfq); +ALPHA_STF_OP(t, stfq); +ALPHA_LDF_OP(s, ldfl); +ALPHA_STF_OP(s, stfl); + +/* VAX floating point */ +ALPHA_LDF_OP(f, helper_ldff); +ALPHA_STF_OP(f, helper_stff); +ALPHA_LDF_OP(g, helper_ldfg); +ALPHA_STF_OP(g, helper_stfg); + +#undef MEMSUFFIX diff --git a/target-alpha/op_template.h b/target-alpha/op_template.h new file mode 100644 index 000000000..e96303ba3 --- /dev/null +++ b/target-alpha/op_template.h @@ -0,0 +1,167 @@ +/* + * Alpha emulation cpu micro-operations templates for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * 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 + */ + +/* Optimized constant loads */ +#if REG < 3 +void OPPROTO glue(op_reset_T, REG) (void) +{ + glue(T, REG) = 0; + RETURN(); +} + +void OPPROTO glue(op_reset_FT, REG) (void) +{ + glue(FT, REG) = 0; + RETURN(); +} + +/* XXX: This can be great on most RISC machines */ +#if !defined(__i386__) && !defined(__x86_64__) +void OPPROTO glue(op_set_s16_T, REG) (void) +{ + glue(T, REG) = (int16_t)PARAM(1); + RETURN(); +} + +void OPPROTO glue(op_set_u16_T, REG) (void) +{ + glue(T, REG) = (uint16_t)PARAM(1); + RETURN(); +} +#endif + +void OPPROTO glue(op_set_s32_T, REG) (void) +{ + glue(T, REG) = (int32_t)PARAM(1); + RETURN(); +} + +void OPPROTO glue(op_set_u32_T, REG) (void) +{ + glue(T, REG) = (uint32_t)PARAM(1); + RETURN(); +} + +#if 0 // Qemu does not know how to do this... +void OPPROTO glue(op_set_64_T, REG) (void) +{ + glue(T, REG) = (int64_t)PARAM(1); + RETURN(); +} +#else +void OPPROTO glue(op_set_64_T, REG) (void) +{ + glue(T, REG) = ((int64_t)PARAM(1) << 32) | (int64_t)PARAM(2); + RETURN(); +} +#endif + +#endif /* REG < 3 */ + +/* Fixed-point register moves */ +#if REG < 31 +void OPPROTO glue(op_load_T0_ir, REG) (void) +{ + T0 = env->ir[REG]; + RETURN(); +} + +void OPPROTO glue(op_load_T1_ir, REG) (void) +{ + T1 = env->ir[REG]; + RETURN(); +} + +void OPPROTO glue(op_load_T2_ir, REG) (void) +{ + T2 = env->ir[REG]; + RETURN(); +} + +void OPPROTO glue(op_store_T0_ir, REG) (void) +{ + env->ir[REG] = T0; + RETURN(); +} + +void OPPROTO glue(op_store_T1_ir, REG) (void) +{ + env->ir[REG] = T1; + RETURN(); +} + +void OPPROTO glue(op_store_T2_ir, REG) (void) +{ + env->ir[REG] = T2; + RETURN(); +} + +void OPPROTO glue(op_cmov_ir, REG) (void) +{ + if (T0) + env->ir[REG] = T1; + RETURN(); +} + +/* floating point registers moves */ +void OPPROTO glue(op_load_FT0_fir, REG) (void) +{ + FT0 = env->fir[REG]; + RETURN(); +} + +void OPPROTO glue(op_load_FT1_fir, REG) (void) +{ + FT1 = env->fir[REG]; + RETURN(); +} + +void OPPROTO glue(op_load_FT2_fir, REG) (void) +{ + FT2 = env->fir[REG]; + RETURN(); +} + +void OPPROTO glue(op_store_FT0_fir, REG) (void) +{ + env->fir[REG] = FT0; + RETURN(); +} + +void OPPROTO glue(op_store_FT1_fir, REG) (void) +{ + env->fir[REG] = FT1; + RETURN(); +} + +void OPPROTO glue(op_store_FT2_fir, REG) (void) +{ + env->fir[REG] = FT2; + RETURN(); +} + +void OPPROTO glue(op_cmov_fir, REG) (void) +{ + helper_cmov_fir(REG); + RETURN(); +} +#endif /* REG < 31 */ + +#undef REG diff --git a/target-alpha/translate.c b/target-alpha/translate.c new file mode 100644 index 000000000..0afd8964c --- /dev/null +++ b/target-alpha/translate.c @@ -0,0 +1,2117 @@ +/* + * Alpha emulation cpu translation for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * 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 +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +#define DO_SINGLE_STEP +#define GENERATE_NOP +#define ALPHA_DEBUG_DISAS +#define DO_TB_FLUSH + +typedef struct DisasContext DisasContext; +struct DisasContext { + uint64_t pc; + int mem_idx; +#if !defined (CONFIG_USER_ONLY) + int pal_mode; +#endif + uint32_t amask; +}; + +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) (long)(x) +#endif + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; + +#include "gen-op.h" + +static inline void gen_op_nop (void) +{ +#if defined(GENERATE_NOP) + gen_op_no_op(); +#endif +} + +#define GEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ +} + +/* IR moves */ +/* Special hacks for ir31 */ +#define gen_op_load_T0_ir31 gen_op_reset_T0 +#define gen_op_load_T1_ir31 gen_op_reset_T1 +#define gen_op_load_T2_ir31 gen_op_reset_T2 +#define gen_op_store_T0_ir31 gen_op_nop +#define gen_op_store_T1_ir31 gen_op_nop +#define gen_op_store_T2_ir31 gen_op_nop +#define gen_op_cmov_ir31 gen_op_nop +GEN32(gen_op_load_T0_ir, gen_op_load_T0_ir); +GEN32(gen_op_load_T1_ir, gen_op_load_T1_ir); +GEN32(gen_op_load_T2_ir, gen_op_load_T2_ir); +GEN32(gen_op_store_T0_ir, gen_op_store_T0_ir); +GEN32(gen_op_store_T1_ir, gen_op_store_T1_ir); +GEN32(gen_op_store_T2_ir, gen_op_store_T2_ir); +GEN32(gen_op_cmov_ir, gen_op_cmov_ir); + +static inline void gen_load_ir (DisasContext *ctx, int irn, int Tn) +{ + switch (Tn) { + case 0: + gen_op_load_T0_ir(irn); + break; + case 1: + gen_op_load_T1_ir(irn); + break; + case 2: + gen_op_load_T2_ir(irn); + break; + } +} + +static inline void gen_store_ir (DisasContext *ctx, int irn, int Tn) +{ + switch (Tn) { + case 0: + gen_op_store_T0_ir(irn); + break; + case 1: + gen_op_store_T1_ir(irn); + break; + case 2: + gen_op_store_T2_ir(irn); + break; + } +} + +/* FIR moves */ +/* Special hacks for fir31 */ +#define gen_op_load_FT0_fir31 gen_op_reset_FT0 +#define gen_op_load_FT1_fir31 gen_op_reset_FT1 +#define gen_op_load_FT2_fir31 gen_op_reset_FT2 +#define gen_op_store_FT0_fir31 gen_op_nop +#define gen_op_store_FT1_fir31 gen_op_nop +#define gen_op_store_FT2_fir31 gen_op_nop +#define gen_op_cmov_fir31 gen_op_nop +GEN32(gen_op_load_FT0_fir, gen_op_load_FT0_fir); +GEN32(gen_op_load_FT1_fir, gen_op_load_FT1_fir); +GEN32(gen_op_load_FT2_fir, gen_op_load_FT2_fir); +GEN32(gen_op_store_FT0_fir, gen_op_store_FT0_fir); +GEN32(gen_op_store_FT1_fir, gen_op_store_FT1_fir); +GEN32(gen_op_store_FT2_fir, gen_op_store_FT2_fir); +GEN32(gen_op_cmov_fir, gen_op_cmov_fir); + +static inline void gen_load_fir (DisasContext *ctx, int firn, int Tn) +{ + switch (Tn) { + case 0: + gen_op_load_FT0_fir(firn); + break; + case 1: + gen_op_load_FT1_fir(firn); + break; + case 2: + gen_op_load_FT2_fir(firn); + break; + } +} + +static inline void gen_store_fir (DisasContext *ctx, int firn, int Tn) +{ + switch (Tn) { + case 0: + gen_op_store_FT0_fir(firn); + break; + case 1: + gen_op_store_FT1_fir(firn); + break; + case 2: + gen_op_store_FT2_fir(firn); + break; + } +} + +/* Memory moves */ +#if defined(CONFIG_USER_ONLY) +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_ld##width[] = { \ + &gen_op_ld##width##_raw, \ +} +#define OP_ST_TABLE(width) \ +static GenOpFunc *gen_op_st##width[] = { \ + &gen_op_st##width##_raw, \ +} +#else +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_ld##width[] = { \ + &gen_op_ld##width##_kernel, \ + &gen_op_ld##width##_user, /* executive */ \ + &gen_op_ld##width##_data, /* supervisor */ \ + &gen_op_ld##width##_data, /* user */ \ +} +#define OP_ST_TABLE(width) \ +static GenOpFunc *gen_op_st##width[] = { \ + &gen_op_st##width##_kernel, \ + &gen_op_st##width##_user, /* executive */ \ + &gen_op_st##width##_data, /* supervisor */ \ + &gen_op_st##width##_data, /* user */ \ +} +#endif + +#define GEN_LD(width) \ +OP_LD_TABLE(width); \ +static void gen_ld##width (DisasContext *ctx) \ +{ \ + (*gen_op_ld##width[ctx->mem_idx])(); \ +} + +#define GEN_ST(width) \ +OP_ST_TABLE(width); \ +static void gen_st##width (DisasContext *ctx) \ +{ \ + (*gen_op_st##width[ctx->mem_idx])(); \ +} + +GEN_LD(bu); +GEN_ST(b); +GEN_LD(wu); +GEN_ST(w); +GEN_LD(l); +GEN_ST(l); +GEN_LD(q); +GEN_ST(q); +GEN_LD(q_u); +GEN_ST(q_u); +GEN_LD(l_l); +GEN_ST(l_c); +GEN_LD(q_l); +GEN_ST(q_c); + +GEN_LD(f); +GEN_ST(f); +GEN_LD(g); +GEN_ST(g); +GEN_LD(s); +GEN_ST(s); +GEN_LD(t); +GEN_ST(t); + +#if defined(__i386__) || defined(__x86_64__) +static inline void gen_op_set_s16_T0 (int16_t imm) +{ + gen_op_set_s32_T0((int32_t)imm); +} + +static inline void gen_op_set_s16_T1 (int16_t imm) +{ + gen_op_set_s32_T1((int32_t)imm); +} + +static inline void gen_op_set_u16_T0 (uint16_t imm) +{ + gen_op_set_s32_T0((uint32_t)imm); +} + +static inline void gen_op_set_u16_T1 (uint16_t imm) +{ + gen_op_set_s32_T1((uint32_t)imm); +} +#endif + +static inline void gen_set_sT0 (DisasContext *ctx, int64_t imm) +{ + int32_t imm32; + int16_t imm16; + + imm32 = imm; + if (imm32 == imm) { + imm16 = imm; + if (imm16 == imm) { + if (imm == 0) { + gen_op_reset_T0(); + } else { + gen_op_set_s16_T0(imm16); + } + } else { + gen_op_set_s32_T0(imm32); + } + } else { +#if 0 // Qemu does not know how to do this... + gen_op_set_64_T0(imm); +#else + gen_op_set_64_T0(imm >> 32, imm); +#endif + } +} + +static inline void gen_set_sT1 (DisasContext *ctx, int64_t imm) +{ + int32_t imm32; + int16_t imm16; + + imm32 = imm; + if (imm32 == imm) { + imm16 = imm; + if (imm16 == imm) { + if (imm == 0) { + gen_op_reset_T1(); + } else { + gen_op_set_s16_T1(imm16); + } + } else { + gen_op_set_s32_T1(imm32); + } + } else { +#if 0 // Qemu does not know how to do this... + gen_op_set_64_T1(imm); +#else + gen_op_set_64_T1(imm >> 32, imm); +#endif + } +} + +static inline void gen_set_uT0 (DisasContext *ctx, uint64_t imm) +{ + if (!(imm >> 32)) { + if ((!imm >> 16)) { + if (imm == 0) + gen_op_reset_T0(); + else + gen_op_set_u16_T0(imm); + } else { + gen_op_set_u32_T0(imm); + } + } else { +#if 0 // Qemu does not know how to do this... + gen_op_set_64_T0(imm); +#else + gen_op_set_64_T0(imm >> 32, imm); +#endif + } +} + +static inline void gen_set_uT1 (DisasContext *ctx, uint64_t imm) +{ + if (!(imm >> 32)) { + if ((!imm >> 16)) { + if (imm == 0) + gen_op_reset_T1(); + else + gen_op_set_u16_T1(imm); + } else { + gen_op_set_u32_T1(imm); + } + } else { +#if 0 // Qemu does not know how to do this... + gen_op_set_64_T1(imm); +#else + gen_op_set_64_T1(imm >> 32, imm); +#endif + } +} + +static inline void gen_update_pc (DisasContext *ctx) +{ + if (!(ctx->pc >> 32)) { + gen_op_update_pc32(ctx->pc); + } else { +#if 0 // Qemu does not know how to do this... + gen_op_update_pc(ctx->pc); +#else + gen_op_update_pc(ctx->pc >> 32, ctx->pc); +#endif + } +} + +static inline void _gen_op_bcond (DisasContext *ctx) +{ +#if 0 // Qemu does not know how to do this... + gen_op_bcond(ctx->pc); +#else + gen_op_bcond(ctx->pc >> 32, ctx->pc); +#endif +} + +static inline void gen_excp (DisasContext *ctx, int exception, int error_code) +{ + gen_update_pc(ctx); + gen_op_excp(exception, error_code); +} + +static inline void gen_invalid (DisasContext *ctx) +{ + gen_excp(ctx, EXCP_OPCDEC, 0); +} + +static void gen_load_mem (DisasContext *ctx, + void (*gen_load_op)(DisasContext *ctx), + int ra, int rb, int32_t disp16, int clear) +{ + if (ra == 31 && disp16 == 0) { + /* UNOP */ + gen_op_nop(); + } else { + gen_load_ir(ctx, rb, 0); + if (disp16 != 0) { + gen_set_sT1(ctx, disp16); + gen_op_addq(); + } + if (clear) + gen_op_n7(); + (*gen_load_op)(ctx); + gen_store_ir(ctx, ra, 1); + } +} + +static void gen_store_mem (DisasContext *ctx, + void (*gen_store_op)(DisasContext *ctx), + int ra, int rb, int32_t disp16, int clear) +{ + gen_load_ir(ctx, rb, 0); + if (disp16 != 0) { + gen_set_sT1(ctx, disp16); + gen_op_addq(); + } + if (clear) + gen_op_n7(); + gen_load_ir(ctx, ra, 1); + (*gen_store_op)(ctx); +} + +static void gen_load_fmem (DisasContext *ctx, + void (*gen_load_fop)(DisasContext *ctx), + int ra, int rb, int32_t disp16) +{ + gen_load_ir(ctx, rb, 0); + if (disp16 != 0) { + gen_set_sT1(ctx, disp16); + gen_op_addq(); + } + (*gen_load_fop)(ctx); + gen_store_fir(ctx, ra, 1); +} + +static void gen_store_fmem (DisasContext *ctx, + void (*gen_store_fop)(DisasContext *ctx), + int ra, int rb, int32_t disp16) +{ + gen_load_ir(ctx, rb, 0); + if (disp16 != 0) { + gen_set_sT1(ctx, disp16); + gen_op_addq(); + } + gen_load_fir(ctx, ra, 1); + (*gen_store_fop)(ctx); +} + +static void gen_bcond (DisasContext *ctx, void (*gen_test_op)(void), + int ra, int32_t disp16) +{ + if (disp16 != 0) { + gen_set_uT0(ctx, ctx->pc); + gen_set_sT1(ctx, disp16 << 2); + gen_op_addq1(); + } else { + gen_set_uT1(ctx, ctx->pc); + } + gen_load_ir(ctx, ra, 0); + (*gen_test_op)(); + _gen_op_bcond(ctx); +} + +static void gen_fbcond (DisasContext *ctx, void (*gen_test_op)(void), + int ra, int32_t disp16) +{ + if (disp16 != 0) { + gen_set_uT0(ctx, ctx->pc); + gen_set_sT1(ctx, disp16 << 2); + gen_op_addq1(); + } else { + gen_set_uT1(ctx, ctx->pc); + } + gen_load_fir(ctx, ra, 0); + (*gen_test_op)(); + _gen_op_bcond(ctx); +} + +static void gen_arith2 (DisasContext *ctx, void (*gen_arith_op)(void), + int rb, int rc, int islit, int8_t lit) +{ + if (islit) + gen_set_sT0(ctx, lit); + else + gen_load_ir(ctx, rb, 0); + (*gen_arith_op)(); + gen_store_ir(ctx, rc, 0); +} + +static void gen_arith3 (DisasContext *ctx, void (*gen_arith_op)(void), + int ra, int rb, int rc, int islit, int8_t lit) +{ + gen_load_ir(ctx, ra, 0); + if (islit) + gen_set_sT1(ctx, lit); + else + gen_load_ir(ctx, rb, 1); + (*gen_arith_op)(); + gen_store_ir(ctx, rc, 0); +} + +static void gen_cmov (DisasContext *ctx, void (*gen_test_op)(void), + int ra, int rb, int rc, int islit, int8_t lit) +{ + gen_load_ir(ctx, ra, 1); + if (islit) + gen_set_sT0(ctx, lit); + else + gen_load_ir(ctx, rb, 0); + (*gen_test_op)(); + gen_op_cmov_ir(rc); +} + +static void gen_farith2 (DisasContext *ctx, void (*gen_arith_fop)(void), + int rb, int rc) +{ + gen_load_fir(ctx, rb, 0); + (*gen_arith_fop)(); + gen_store_fir(ctx, rc, 0); +} + +static void gen_farith3 (DisasContext *ctx, void (*gen_arith_fop)(void), + int ra, int rb, int rc) +{ + gen_load_fir(ctx, ra, 0); + gen_load_fir(ctx, rb, 1); + (*gen_arith_fop)(); + gen_store_fir(ctx, rc, 0); +} + +static void gen_fcmov (DisasContext *ctx, void (*gen_test_fop)(void), + int ra, int rb, int rc) +{ + gen_load_fir(ctx, ra, 0); + gen_load_fir(ctx, rb, 1); + (*gen_test_fop)(); + gen_op_cmov_fir(rc); +} + +static void gen_fti (DisasContext *ctx, void (*gen_move_fop)(void), + int ra, int rc) +{ + gen_load_fir(ctx, rc, 0); + (*gen_move_fop)(); + gen_store_ir(ctx, ra, 0); +} + +static void gen_itf (DisasContext *ctx, void (*gen_move_fop)(void), + int ra, int rc) +{ + gen_load_ir(ctx, ra, 0); + (*gen_move_fop)(); + gen_store_fir(ctx, rc, 0); +} + +static void gen_s4addl (void) +{ + gen_op_s4(); + gen_op_addl(); +} + +static void gen_s4subl (void) +{ + gen_op_s4(); + gen_op_subl(); +} + +static void gen_s8addl (void) +{ + gen_op_s8(); + gen_op_addl(); +} + +static void gen_s8subl (void) +{ + gen_op_s8(); + gen_op_subl(); +} + +static void gen_s4addq (void) +{ + gen_op_s4(); + gen_op_addq(); +} + +static void gen_s4subq (void) +{ + gen_op_s4(); + gen_op_subq(); +} + +static void gen_s8addq (void) +{ + gen_op_s8(); + gen_op_addq(); +} + +static void gen_s8subq (void) +{ + gen_op_s8(); + gen_op_subq(); +} + +static void gen_amask (void) +{ + gen_op_load_amask(); + gen_op_bic(); +} + +static int translate_one (DisasContext *ctx, uint32_t insn) +{ + uint32_t palcode; + int32_t disp21, disp16, disp12; + uint16_t fn11, fn16; + uint8_t opc, ra, rb, rc, sbz, fpfn, fn7, fn2, islit; + int8_t lit; + int ret; + + /* Decode all instruction fields */ + opc = insn >> 26; + ra = (insn >> 21) & 0x1F; + rb = (insn >> 16) & 0x1F; + rc = insn & 0x1F; + sbz = (insn >> 13) & 0x07; + islit = (insn >> 12) & 1; + lit = (insn >> 13) & 0xFF; + palcode = insn & 0x03FFFFFF; + disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11; + disp16 = (int16_t)(insn & 0x0000FFFF); + disp12 = (int32_t)((insn & 0x00000FFF) << 20) >> 20; + fn16 = insn & 0x0000FFFF; + fn11 = (insn >> 5) & 0x000007FF; + fpfn = fn11 & 0x3F; + fn7 = (insn >> 5) & 0x0000007F; + fn2 = (insn >> 5) & 0x00000003; + ret = 0; +#if defined ALPHA_DEBUG_DISAS + if (logfile != NULL) { + fprintf(logfile, "opc %02x ra %d rb %d rc %d disp16 %04x\n", + opc, ra, rb, rc, disp16); + } +#endif + switch (opc) { + case 0x00: + /* CALL_PAL */ + if (palcode >= 0x80 && palcode < 0xC0) { + /* Unprivileged PAL call */ + gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x1F) << 6), 0); +#if !defined (CONFIG_USER_ONLY) + } else if (palcode < 0x40) { + /* Privileged PAL code */ + if (ctx->mem_idx & 1) + goto invalid_opc; + else + gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x1F) << 6), 0); +#endif + } else { + /* Invalid PAL call */ + goto invalid_opc; + } + ret = 3; + break; + case 0x01: + /* OPC01 */ + goto invalid_opc; + case 0x02: + /* OPC02 */ + goto invalid_opc; + case 0x03: + /* OPC03 */ + goto invalid_opc; + case 0x04: + /* OPC04 */ + goto invalid_opc; + case 0x05: + /* OPC05 */ + goto invalid_opc; + case 0x06: + /* OPC06 */ + goto invalid_opc; + case 0x07: + /* OPC07 */ + goto invalid_opc; + case 0x08: + /* LDA */ + gen_load_ir(ctx, rb, 0); + gen_set_sT1(ctx, disp16); + gen_op_addq(); + gen_store_ir(ctx, ra, 0); + break; + case 0x09: + /* LDAH */ + gen_load_ir(ctx, rb, 0); + gen_set_sT1(ctx, disp16 << 16); + gen_op_addq(); + gen_store_ir(ctx, ra, 0); + break; + case 0x0A: + /* LDBU */ + if (!(ctx->amask & AMASK_BWX)) + goto invalid_opc; + gen_load_mem(ctx, &gen_ldbu, ra, rb, disp16, 0); + break; + case 0x0B: + /* LDQ_U */ + gen_load_mem(ctx, &gen_ldq_u, ra, rb, disp16, 1); + break; + case 0x0C: + /* LDWU */ + if (!(ctx->amask & AMASK_BWX)) + goto invalid_opc; + gen_load_mem(ctx, &gen_ldwu, ra, rb, disp16, 0); + break; + case 0x0D: + /* STW */ + if (!(ctx->amask & AMASK_BWX)) + goto invalid_opc; + gen_store_mem(ctx, &gen_stw, ra, rb, disp16, 0); + break; + case 0x0E: + /* STB */ + if (!(ctx->amask & AMASK_BWX)) + goto invalid_opc; + gen_store_mem(ctx, &gen_stb, ra, rb, disp16, 0); + break; + case 0x0F: + /* STQ_U */ + gen_store_mem(ctx, &gen_stq_u, ra, rb, disp16, 1); + break; + case 0x10: + switch (fn7) { + case 0x00: + /* ADDL */ + gen_arith3(ctx, &gen_op_addl, ra, rb, rc, islit, lit); + break; + case 0x02: + /* S4ADDL */ + gen_arith3(ctx, &gen_s4addl, ra, rb, rc, islit, lit); + break; + case 0x09: + /* SUBL */ + gen_arith3(ctx, &gen_op_subl, ra, rb, rc, islit, lit); + break; + case 0x0B: + /* S4SUBL */ + gen_arith3(ctx, &gen_s4subl, ra, rb, rc, islit, lit); + break; + case 0x0F: + /* CMPBGE */ + gen_arith3(ctx, &gen_op_cmpbge, ra, rb, rc, islit, lit); + break; + case 0x12: + /* S8ADDL */ + gen_arith3(ctx, &gen_s8addl, ra, rb, rc, islit, lit); + break; + case 0x1B: + /* S8SUBL */ + gen_arith3(ctx, &gen_s8subl, ra, rb, rc, islit, lit); + break; + case 0x1D: + /* CMPULT */ + gen_arith3(ctx, &gen_op_cmpult, ra, rb, rc, islit, lit); + break; + case 0x20: + /* ADDQ */ + gen_arith3(ctx, &gen_op_addq, ra, rb, rc, islit, lit); + break; + case 0x22: + /* S4ADDQ */ + gen_arith3(ctx, &gen_s4addq, ra, rb, rc, islit, lit); + break; + case 0x29: + /* SUBQ */ + gen_arith3(ctx, &gen_op_subq, ra, rb, rc, islit, lit); + break; + case 0x2B: + /* S4SUBQ */ + gen_arith3(ctx, &gen_s4subq, ra, rb, rc, islit, lit); + break; + case 0x2D: + /* CMPEQ */ + gen_arith3(ctx, &gen_op_cmpeq, ra, rb, rc, islit, lit); + break; + case 0x32: + /* S8ADDQ */ + gen_arith3(ctx, &gen_s8addq, ra, rb, rc, islit, lit); + break; + case 0x3B: + /* S8SUBQ */ + gen_arith3(ctx, &gen_s8subq, ra, rb, rc, islit, lit); + break; + case 0x3D: + /* CMPULE */ + gen_arith3(ctx, &gen_op_cmpule, ra, rb, rc, islit, lit); + break; + case 0x40: + /* ADDL/V */ + gen_arith3(ctx, &gen_op_addlv, ra, rb, rc, islit, lit); + break; + case 0x49: + /* SUBL/V */ + gen_arith3(ctx, &gen_op_sublv, ra, rb, rc, islit, lit); + break; + case 0x4D: + /* CMPLT */ + gen_arith3(ctx, &gen_op_cmplt, ra, rb, rc, islit, lit); + break; + case 0x60: + /* ADDQ/V */ + gen_arith3(ctx, &gen_op_addqv, ra, rb, rc, islit, lit); + break; + case 0x69: + /* SUBQ/V */ + gen_arith3(ctx, &gen_op_subqv, ra, rb, rc, islit, lit); + break; + case 0x6D: + /* CMPLE */ + gen_arith3(ctx, &gen_op_cmple, ra, rb, rc, islit, lit); + break; + default: + goto invalid_opc; + } + break; + case 0x11: + switch (fn7) { + case 0x00: + /* AND */ + gen_arith3(ctx, &gen_op_and, ra, rb, rc, islit, lit); + break; + case 0x08: + /* BIC */ + gen_arith3(ctx, &gen_op_bic, ra, rb, rc, islit, lit); + break; + case 0x14: + /* CMOVLBS */ + gen_cmov(ctx, &gen_op_cmplbs, ra, rb, rc, islit, lit); + break; + case 0x16: + /* CMOVLBC */ + gen_cmov(ctx, &gen_op_cmplbc, ra, rb, rc, islit, lit); + break; + case 0x20: + /* BIS */ + if (ra == rb || ra == 31 || rb == 31) { + if (ra == 31 && rc == 31) { + /* NOP */ + gen_op_nop(); + } else { + /* MOV */ + gen_load_ir(ctx, rb, 0); + gen_store_ir(ctx, rc, 0); + } + } else { + gen_arith3(ctx, &gen_op_bis, ra, rb, rc, islit, lit); + } + break; + case 0x24: + /* CMOVEQ */ + gen_cmov(ctx, &gen_op_cmpeqz, ra, rb, rc, islit, lit); + break; + case 0x26: + /* CMOVNE */ + gen_cmov(ctx, &gen_op_cmpnez, ra, rb, rc, islit, lit); + break; + case 0x28: + /* ORNOT */ + gen_arith3(ctx, &gen_op_ornot, ra, rb, rc, islit, lit); + break; + case 0x40: + /* XOR */ + gen_arith3(ctx, &gen_op_xor, ra, rb, rc, islit, lit); + break; + case 0x44: + /* CMOVLT */ + gen_cmov(ctx, &gen_op_cmpltz, ra, rb, rc, islit, lit); + break; + case 0x46: + /* CMOVGE */ + gen_cmov(ctx, &gen_op_cmpgez, ra, rb, rc, islit, lit); + break; + case 0x48: + /* EQV */ + gen_arith3(ctx, &gen_op_eqv, ra, rb, rc, islit, lit); + break; + case 0x61: + /* AMASK */ + gen_arith2(ctx, &gen_amask, rb, rc, islit, lit); + break; + case 0x64: + /* CMOVLE */ + gen_cmov(ctx, &gen_op_cmplez, ra, rb, rc, islit, lit); + break; + case 0x66: + /* CMOVGT */ + gen_cmov(ctx, &gen_op_cmpgtz, ra, rb, rc, islit, lit); + break; + case 0x6C: + /* IMPLVER */ + gen_op_load_implver(); + gen_store_ir(ctx, rc, 0); + break; + default: + goto invalid_opc; + } + break; + case 0x12: + switch (fn7) { + case 0x02: + /* MSKBL */ + gen_arith3(ctx, &gen_op_mskbl, ra, rb, rc, islit, lit); + break; + case 0x06: + /* EXTBL */ + gen_arith3(ctx, &gen_op_extbl, ra, rb, rc, islit, lit); + break; + case 0x0B: + /* INSBL */ + gen_arith3(ctx, &gen_op_insbl, ra, rb, rc, islit, lit); + break; + case 0x12: + /* MSKWL */ + gen_arith3(ctx, &gen_op_mskwl, ra, rb, rc, islit, lit); + break; + case 0x16: + /* EXTWL */ + gen_arith3(ctx, &gen_op_extwl, ra, rb, rc, islit, lit); + break; + case 0x1B: + /* INSWL */ + gen_arith3(ctx, &gen_op_inswl, ra, rb, rc, islit, lit); + break; + case 0x22: + /* MSKLL */ + gen_arith3(ctx, &gen_op_mskll, ra, rb, rc, islit, lit); + break; + case 0x26: + /* EXTLL */ + gen_arith3(ctx, &gen_op_extll, ra, rb, rc, islit, lit); + break; + case 0x2B: + /* INSLL */ + gen_arith3(ctx, &gen_op_insll, ra, rb, rc, islit, lit); + break; + case 0x30: + /* ZAP */ + gen_arith3(ctx, &gen_op_zap, ra, rb, rc, islit, lit); + break; + case 0x31: + /* ZAPNOT */ + gen_arith3(ctx, &gen_op_zapnot, ra, rb, rc, islit, lit); + break; + case 0x32: + /* MSKQL */ + gen_arith3(ctx, &gen_op_mskql, ra, rb, rc, islit, lit); + break; + case 0x34: + /* SRL */ + gen_arith3(ctx, &gen_op_srl, ra, rb, rc, islit, lit); + break; + case 0x36: + /* EXTQL */ + gen_arith3(ctx, &gen_op_extql, ra, rb, rc, islit, lit); + break; + case 0x39: + /* SLL */ + gen_arith3(ctx, &gen_op_sll, ra, rb, rc, islit, lit); + break; + case 0x3B: + /* INSQL */ + gen_arith3(ctx, &gen_op_insql, ra, rb, rc, islit, lit); + break; + case 0x3C: + /* SRA */ + gen_arith3(ctx, &gen_op_sra, ra, rb, rc, islit, lit); + break; + case 0x52: + /* MSKWH */ + gen_arith3(ctx, &gen_op_mskwh, ra, rb, rc, islit, lit); + break; + case 0x57: + /* INSWH */ + gen_arith3(ctx, &gen_op_inswh, ra, rb, rc, islit, lit); + break; + case 0x5A: + /* EXTWH */ + gen_arith3(ctx, &gen_op_extwh, ra, rb, rc, islit, lit); + break; + case 0x62: + /* MSKLH */ + gen_arith3(ctx, &gen_op_msklh, ra, rb, rc, islit, lit); + break; + case 0x67: + /* INSLH */ + gen_arith3(ctx, &gen_op_inslh, ra, rb, rc, islit, lit); + break; + case 0x6A: + /* EXTLH */ + gen_arith3(ctx, &gen_op_extlh, ra, rb, rc, islit, lit); + break; + case 0x72: + /* MSKQH */ + gen_arith3(ctx, &gen_op_mskqh, ra, rb, rc, islit, lit); + break; + case 0x77: + /* INSQH */ + gen_arith3(ctx, &gen_op_insqh, ra, rb, rc, islit, lit); + break; + case 0x7A: + /* EXTQH */ + gen_arith3(ctx, &gen_op_extqh, ra, rb, rc, islit, lit); + break; + default: + goto invalid_opc; + } + break; + case 0x13: + switch (fn7) { + case 0x00: + /* MULL */ + gen_arith3(ctx, &gen_op_mull, ra, rb, rc, islit, lit); + break; + case 0x20: + /* MULQ */ + gen_arith3(ctx, &gen_op_mulq, ra, rb, rc, islit, lit); + break; + case 0x30: + /* UMULH */ + gen_arith3(ctx, &gen_op_umulh, ra, rb, rc, islit, lit); + break; + case 0x40: + /* MULL/V */ + gen_arith3(ctx, &gen_op_mullv, ra, rb, rc, islit, lit); + break; + case 0x60: + /* MULQ/V */ + gen_arith3(ctx, &gen_op_mulqv, ra, rb, rc, islit, lit); + break; + default: + goto invalid_opc; + } + break; + case 0x14: + switch (fpfn) { /* f11 & 0x3F */ + case 0x04: + /* ITOFS */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; + gen_itf(ctx, &gen_op_itofs, ra, rc); + break; + case 0x0A: + /* SQRTF */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; + gen_farith2(ctx, &gen_op_sqrtf, rb, rc); + break; + case 0x0B: + /* SQRTS */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; + gen_farith2(ctx, &gen_op_sqrts, rb, rc); + break; + case 0x14: + /* ITOFF */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; +#if 0 // TODO + gen_itf(ctx, &gen_op_itoff, ra, rc); +#else + goto invalid_opc; +#endif + break; + case 0x24: + /* ITOFT */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; + gen_itf(ctx, &gen_op_itoft, ra, rc); + break; + case 0x2A: + /* SQRTG */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; + gen_farith2(ctx, &gen_op_sqrtg, rb, rc); + break; + case 0x02B: + /* SQRTT */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; + gen_farith2(ctx, &gen_op_sqrtt, rb, rc); + break; + default: + goto invalid_opc; + } + break; + case 0x15: + /* VAX floating point */ + /* XXX: rounding mode and trap are ignored (!) */ + switch (fpfn) { /* f11 & 0x3F */ + case 0x00: + /* ADDF */ + gen_farith3(ctx, &gen_op_addf, ra, rb, rc); + break; + case 0x01: + /* SUBF */ + gen_farith3(ctx, &gen_op_subf, ra, rb, rc); + break; + case 0x02: + /* MULF */ + gen_farith3(ctx, &gen_op_mulf, ra, rb, rc); + break; + case 0x03: + /* DIVF */ + gen_farith3(ctx, &gen_op_divf, ra, rb, rc); + break; + case 0x1E: + /* CVTDG */ +#if 0 // TODO + gen_farith2(ctx, &gen_op_cvtdg, rb, rc); +#else + goto invalid_opc; +#endif + break; + case 0x20: + /* ADDG */ + gen_farith3(ctx, &gen_op_addg, ra, rb, rc); + break; + case 0x21: + /* SUBG */ + gen_farith3(ctx, &gen_op_subg, ra, rb, rc); + break; + case 0x22: + /* MULG */ + gen_farith3(ctx, &gen_op_mulg, ra, rb, rc); + break; + case 0x23: + /* DIVG */ + gen_farith3(ctx, &gen_op_divg, ra, rb, rc); + break; + case 0x25: + /* CMPGEQ */ + gen_farith3(ctx, &gen_op_cmpgeq, ra, rb, rc); + break; + case 0x26: + /* CMPGLT */ + gen_farith3(ctx, &gen_op_cmpglt, ra, rb, rc); + break; + case 0x27: + /* CMPGLE */ + gen_farith3(ctx, &gen_op_cmpgle, ra, rb, rc); + break; + case 0x2C: + /* CVTGF */ + gen_farith2(ctx, &gen_op_cvtgf, rb, rc); + break; + case 0x2D: + /* CVTGD */ +#if 0 // TODO + gen_farith2(ctx, &gen_op_cvtgd, rb, rc); +#else + goto invalid_opc; +#endif + break; + case 0x2F: + /* CVTGQ */ + gen_farith2(ctx, &gen_op_cvtgq, rb, rc); + break; + case 0x3C: + /* CVTQF */ + gen_farith2(ctx, &gen_op_cvtqf, rb, rc); + break; + case 0x3E: + /* CVTQG */ + gen_farith2(ctx, &gen_op_cvtqg, rb, rc); + break; + default: + goto invalid_opc; + } + break; + case 0x16: + /* IEEE floating-point */ + /* XXX: rounding mode and traps are ignored (!) */ + switch (fpfn) { /* f11 & 0x3F */ + case 0x00: + /* ADDS */ + gen_farith3(ctx, &gen_op_adds, ra, rb, rc); + break; + case 0x01: + /* SUBS */ + gen_farith3(ctx, &gen_op_subs, ra, rb, rc); + break; + case 0x02: + /* MULS */ + gen_farith3(ctx, &gen_op_muls, ra, rb, rc); + break; + case 0x03: + /* DIVS */ + gen_farith3(ctx, &gen_op_divs, ra, rb, rc); + break; + case 0x20: + /* ADDT */ + gen_farith3(ctx, &gen_op_addt, ra, rb, rc); + break; + case 0x21: + /* SUBT */ + gen_farith3(ctx, &gen_op_subt, ra, rb, rc); + break; + case 0x22: + /* MULT */ + gen_farith3(ctx, &gen_op_mult, ra, rb, rc); + break; + case 0x23: + /* DIVT */ + gen_farith3(ctx, &gen_op_divt, ra, rb, rc); + break; + case 0x24: + /* CMPTUN */ + gen_farith3(ctx, &gen_op_cmptun, ra, rb, rc); + break; + case 0x25: + /* CMPTEQ */ + gen_farith3(ctx, &gen_op_cmpteq, ra, rb, rc); + break; + case 0x26: + /* CMPTLT */ + gen_farith3(ctx, &gen_op_cmptlt, ra, rb, rc); + break; + case 0x27: + /* CMPTLE */ + gen_farith3(ctx, &gen_op_cmptle, ra, rb, rc); + break; + case 0x2C: + /* XXX: incorrect */ + if (fn11 == 0x2AC) { + /* CVTST */ + gen_farith2(ctx, &gen_op_cvtst, rb, rc); + } else { + /* CVTTS */ + gen_farith2(ctx, &gen_op_cvtts, rb, rc); + } + break; + case 0x2F: + /* CVTTQ */ + gen_farith2(ctx, &gen_op_cvttq, rb, rc); + break; + case 0x3C: + /* CVTQS */ + gen_farith2(ctx, &gen_op_cvtqs, rb, rc); + break; + case 0x3E: + /* CVTQT */ + gen_farith2(ctx, &gen_op_cvtqt, rb, rc); + break; + default: + goto invalid_opc; + } + break; + case 0x17: + switch (fn11) { + case 0x010: + /* CVTLQ */ + gen_farith2(ctx, &gen_op_cvtlq, rb, rc); + break; + case 0x020: + /* CPYS */ + if (ra == rb) { + if (ra == 31 && rc == 31) { + /* FNOP */ + gen_op_nop(); + } else { + /* FMOV */ + gen_load_fir(ctx, rb, 0); + gen_store_fir(ctx, rc, 0); + } + } else { + gen_farith3(ctx, &gen_op_cpys, ra, rb, rc); + } + break; + case 0x021: + /* CPYSN */ + gen_farith2(ctx, &gen_op_cpysn, rb, rc); + break; + case 0x022: + /* CPYSE */ + gen_farith2(ctx, &gen_op_cpyse, rb, rc); + break; + case 0x024: + /* MT_FPCR */ + gen_load_fir(ctx, ra, 0); + gen_op_store_fpcr(); + break; + case 0x025: + /* MF_FPCR */ + gen_op_load_fpcr(); + gen_store_fir(ctx, ra, 0); + break; + case 0x02A: + /* FCMOVEQ */ + gen_fcmov(ctx, &gen_op_cmpfeq, ra, rb, rc); + break; + case 0x02B: + /* FCMOVNE */ + gen_fcmov(ctx, &gen_op_cmpfne, ra, rb, rc); + break; + case 0x02C: + /* FCMOVLT */ + gen_fcmov(ctx, &gen_op_cmpflt, ra, rb, rc); + break; + case 0x02D: + /* FCMOVGE */ + gen_fcmov(ctx, &gen_op_cmpfge, ra, rb, rc); + break; + case 0x02E: + /* FCMOVLE */ + gen_fcmov(ctx, &gen_op_cmpfle, ra, rb, rc); + break; + case 0x02F: + /* FCMOVGT */ + gen_fcmov(ctx, &gen_op_cmpfgt, ra, rb, rc); + break; + case 0x030: + /* CVTQL */ + gen_farith2(ctx, &gen_op_cvtql, rb, rc); + break; + case 0x130: + /* CVTQL/V */ + gen_farith2(ctx, &gen_op_cvtqlv, rb, rc); + break; + case 0x530: + /* CVTQL/SV */ + gen_farith2(ctx, &gen_op_cvtqlsv, rb, rc); + break; + default: + goto invalid_opc; + } + break; + case 0x18: + switch ((uint16_t)disp16) { + case 0x0000: + /* TRAPB */ + /* No-op. Just exit from the current tb */ + ret = 2; + break; + case 0x0400: + /* EXCB */ + /* No-op. Just exit from the current tb */ + ret = 2; + break; + case 0x4000: + /* MB */ + /* No-op */ + break; + case 0x4400: + /* WMB */ + /* No-op */ + break; + case 0x8000: + /* FETCH */ + /* No-op */ + break; + case 0xA000: + /* FETCH_M */ + /* No-op */ + break; + case 0xC000: + /* RPCC */ + gen_op_load_pcc(); + gen_store_ir(ctx, ra, 0); + break; + case 0xE000: + /* RC */ + gen_op_load_irf(); + gen_store_ir(ctx, ra, 0); + gen_op_clear_irf(); + break; + case 0xE800: + /* ECB */ + /* XXX: TODO: evict tb cache at address rb */ +#if 0 + ret = 2; +#else + goto invalid_opc; +#endif + break; + case 0xF000: + /* RS */ + gen_op_load_irf(); + gen_store_ir(ctx, ra, 0); + gen_op_set_irf(); + break; + case 0xF800: + /* WH64 */ + /* No-op */ + break; + default: + goto invalid_opc; + } + break; + case 0x19: + /* HW_MFPR (PALcode) */ +#if defined (CONFIG_USER_ONLY) + goto invalid_opc; +#else + if (!ctx->pal_mode) + goto invalid_opc; + gen_op_mfpr(insn & 0xFF); + gen_store_ir(ctx, ra, 0); + break; +#endif + case 0x1A: + gen_load_ir(ctx, rb, 0); + if (ra != 31) { + gen_set_uT1(ctx, ctx->pc); + gen_store_ir(ctx, ra, 1); + } + gen_op_branch(); + /* Those four jumps only differ by the branch prediction hint */ + switch (fn2) { + case 0x0: + /* JMP */ + break; + case 0x1: + /* JSR */ + break; + case 0x2: + /* RET */ + break; + case 0x3: + /* JSR_COROUTINE */ + break; + } + ret = 1; + break; + case 0x1B: + /* HW_LD (PALcode) */ +#if defined (CONFIG_USER_ONLY) + goto invalid_opc; +#else + if (!ctx->pal_mode) + goto invalid_opc; + gen_load_ir(ctx, rb, 0); + gen_set_sT1(ctx, disp12); + gen_op_addq(); + switch ((insn >> 12) & 0xF) { + case 0x0: + /* Longword physical access */ + gen_op_ldl_raw(); + break; + case 0x1: + /* Quadword physical access */ + gen_op_ldq_raw(); + break; + case 0x2: + /* Longword physical access with lock */ + gen_op_ldl_l_raw(); + break; + case 0x3: + /* Quadword physical access with lock */ + gen_op_ldq_l_raw(); + break; + case 0x4: + /* Longword virtual PTE fetch */ + gen_op_ldl_kernel(); + break; + case 0x5: + /* Quadword virtual PTE fetch */ + gen_op_ldq_kernel(); + break; + case 0x6: + /* Invalid */ + goto invalid_opc; + case 0x7: + /* Invalid */ + goto invalid_opc; + case 0x8: + /* Longword virtual access */ + gen_op_ld_phys_to_virt(); + gen_op_ldl_raw(); + break; + case 0x9: + /* Quadword virtual access */ + gen_op_ld_phys_to_virt(); + gen_op_ldq_raw(); + break; + case 0xA: + /* Longword virtual access with protection check */ + gen_ldl(ctx); + break; + case 0xB: + /* Quadword virtual access with protection check */ + gen_ldq(ctx); + break; + case 0xC: + /* Longword virtual access with altenate access mode */ + gen_op_set_alt_mode(); + gen_op_ld_phys_to_virt(); + gen_op_ldl_raw(); + gen_op_restore_mode(); + break; + case 0xD: + /* Quadword virtual access with altenate access mode */ + gen_op_set_alt_mode(); + gen_op_ld_phys_to_virt(); + gen_op_ldq_raw(); + gen_op_restore_mode(); + break; + case 0xE: + /* Longword virtual access with alternate access mode and + * protection checks + */ + gen_op_set_alt_mode(); + gen_op_ldl_data(); + gen_op_restore_mode(); + break; + case 0xF: + /* Quadword virtual access with alternate access mode and + * protection checks + */ + gen_op_set_alt_mode(); + gen_op_ldq_data(); + gen_op_restore_mode(); + break; + } + gen_store_ir(ctx, ra, 1); + break; +#endif + case 0x1C: + switch (fn7) { + case 0x00: + /* SEXTB */ + if (!(ctx->amask & AMASK_BWX)) + goto invalid_opc; + gen_arith2(ctx, &gen_op_sextb, rb, rc, islit, lit); + break; + case 0x01: + /* SEXTW */ + if (!(ctx->amask & AMASK_BWX)) + goto invalid_opc; + gen_arith2(ctx, &gen_op_sextw, rb, rc, islit, lit); + break; + case 0x30: + /* CTPOP */ + if (!(ctx->amask & AMASK_CIX)) + goto invalid_opc; + gen_arith2(ctx, &gen_op_ctpop, rb, rc, 0, 0); + break; + case 0x31: + /* PERR */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x32: + /* CTLZ */ + if (!(ctx->amask & AMASK_CIX)) + goto invalid_opc; + gen_arith2(ctx, &gen_op_ctlz, rb, rc, 0, 0); + break; + case 0x33: + /* CTTZ */ + if (!(ctx->amask & AMASK_CIX)) + goto invalid_opc; + gen_arith2(ctx, &gen_op_cttz, rb, rc, 0, 0); + break; + case 0x34: + /* UNPKBW */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x35: + /* UNPKWL */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x36: + /* PKWB */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x37: + /* PKLB */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x38: + /* MINSB8 */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x39: + /* MINSW4 */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x3A: + /* MINUB8 */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x3B: + /* MINUW4 */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x3C: + /* MAXUB8 */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x3D: + /* MAXUW4 */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x3E: + /* MAXSB8 */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x3F: + /* MAXSW4 */ + if (!(ctx->amask & AMASK_MVI)) + goto invalid_opc; + /* XXX: TODO */ + goto invalid_opc; + break; + case 0x70: + /* FTOIT */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; + gen_fti(ctx, &gen_op_ftoit, ra, rb); + break; + case 0x78: + /* FTOIS */ + if (!(ctx->amask & AMASK_FIX)) + goto invalid_opc; + gen_fti(ctx, &gen_op_ftois, ra, rb); + break; + default: + goto invalid_opc; + } + break; + case 0x1D: + /* HW_MTPR (PALcode) */ +#if defined (CONFIG_USER_ONLY) + goto invalid_opc; +#else + if (!ctx->pal_mode) + goto invalid_opc; + gen_load_ir(ctx, ra, 0); + gen_op_mtpr(insn & 0xFF); + ret = 2; + break; +#endif + case 0x1E: + /* HW_REI (PALcode) */ +#if defined (CONFIG_USER_ONLY) + goto invalid_opc; +#else + if (!ctx->pal_mode) + goto invalid_opc; + if (rb == 31) { + /* "Old" alpha */ + gen_op_hw_rei(); + } else { + gen_load_ir(ctx, rb, 0); + gen_set_uT1(ctx, (((int64_t)insn << 51) >> 51)); + gen_op_addq(); + gen_op_hw_ret(); + } + ret = 2; + break; +#endif + case 0x1F: + /* HW_ST (PALcode) */ +#if defined (CONFIG_USER_ONLY) + goto invalid_opc; +#else + if (!ctx->pal_mode) + goto invalid_opc; + gen_load_ir(ctx, rb, 0); + gen_set_sT1(ctx, disp12); + gen_op_addq(); + gen_load_ir(ctx, ra, 1); + switch ((insn >> 12) & 0xF) { + case 0x0: + /* Longword physical access */ + gen_op_stl_raw(); + break; + case 0x1: + /* Quadword physical access */ + gen_op_stq_raw(); + break; + case 0x2: + /* Longword physical access with lock */ + gen_op_stl_c_raw(); + break; + case 0x3: + /* Quadword physical access with lock */ + gen_op_stq_c_raw(); + break; + case 0x4: + /* Longword virtual access */ + gen_op_st_phys_to_virt(); + gen_op_stl_raw(); + break; + case 0x5: + /* Quadword virtual access */ + gen_op_st_phys_to_virt(); + gen_op_stq_raw(); + break; + case 0x6: + /* Invalid */ + goto invalid_opc; + case 0x7: + /* Invalid */ + goto invalid_opc; + case 0x8: + /* Invalid */ + goto invalid_opc; + case 0x9: + /* Invalid */ + goto invalid_opc; + case 0xA: + /* Invalid */ + goto invalid_opc; + case 0xB: + /* Invalid */ + goto invalid_opc; + case 0xC: + /* Longword virtual access with alternate access mode */ + gen_op_set_alt_mode(); + gen_op_st_phys_to_virt(); + gen_op_ldl_raw(); + gen_op_restore_mode(); + break; + case 0xD: + /* Quadword virtual access with alternate access mode */ + gen_op_set_alt_mode(); + gen_op_st_phys_to_virt(); + gen_op_ldq_raw(); + gen_op_restore_mode(); + break; + case 0xE: + /* Invalid */ + goto invalid_opc; + case 0xF: + /* Invalid */ + goto invalid_opc; + } + ret = 2; + break; +#endif + case 0x20: + /* LDF */ +#if 0 // TODO + gen_load_fmem(ctx, &gen_ldf, ra, rb, disp16); +#else + goto invalid_opc; +#endif + break; + case 0x21: + /* LDG */ +#if 0 // TODO + gen_load_fmem(ctx, &gen_ldg, ra, rb, disp16); +#else + goto invalid_opc; +#endif + break; + case 0x22: + /* LDS */ + gen_load_fmem(ctx, &gen_lds, ra, rb, disp16); + break; + case 0x23: + /* LDT */ + gen_load_fmem(ctx, &gen_ldt, ra, rb, disp16); + break; + case 0x24: + /* STF */ +#if 0 // TODO + gen_store_fmem(ctx, &gen_stf, ra, rb, disp16); +#else + goto invalid_opc; +#endif + break; + case 0x25: + /* STG */ +#if 0 // TODO + gen_store_fmem(ctx, &gen_stg, ra, rb, disp16); +#else + goto invalid_opc; +#endif + break; + case 0x26: + /* STS */ + gen_store_fmem(ctx, &gen_sts, ra, rb, disp16); + break; + case 0x27: + /* STT */ + gen_store_fmem(ctx, &gen_stt, ra, rb, disp16); + break; + case 0x28: + /* LDL */ + gen_load_mem(ctx, &gen_ldl, ra, rb, disp16, 0); + break; + case 0x29: + /* LDQ */ + gen_load_mem(ctx, &gen_ldq, ra, rb, disp16, 0); + break; + case 0x2A: + /* LDL_L */ + gen_load_mem(ctx, &gen_ldl_l, ra, rb, disp16, 0); + break; + case 0x2B: + /* LDQ_L */ + gen_load_mem(ctx, &gen_ldq_l, ra, rb, disp16, 0); + break; + case 0x2C: + /* STL */ + gen_store_mem(ctx, &gen_stl, ra, rb, disp16, 0); + break; + case 0x2D: + /* STQ */ + gen_store_mem(ctx, &gen_stq, ra, rb, disp16, 0); + break; + case 0x2E: + /* STL_C */ + gen_store_mem(ctx, &gen_stl_c, ra, rb, disp16, 0); + break; + case 0x2F: + /* STQ_C */ + gen_store_mem(ctx, &gen_stq_c, ra, rb, disp16, 0); + break; + case 0x30: + /* BR */ + gen_set_uT0(ctx, ctx->pc); + gen_store_ir(ctx, ra, 0); + if (disp21 != 0) { + gen_set_sT1(ctx, disp21 << 2); + gen_op_addq(); + } + gen_op_branch(); + ret = 1; + break; + case 0x31: + /* FBEQ */ + gen_fbcond(ctx, &gen_op_cmpfeq, ra, disp16); + ret = 1; + break; + case 0x32: + /* FBLT */ + gen_fbcond(ctx, &gen_op_cmpflt, ra, disp16); + ret = 1; + break; + case 0x33: + /* FBLE */ + gen_fbcond(ctx, &gen_op_cmpfle, ra, disp16); + ret = 1; + break; + case 0x34: + /* BSR */ + gen_set_uT0(ctx, ctx->pc); + gen_store_ir(ctx, ra, 0); + if (disp21 != 0) { + gen_set_sT1(ctx, disp21 << 2); + gen_op_addq(); + } + gen_op_branch(); + ret = 1; + break; + case 0x35: + /* FBNE */ + gen_fbcond(ctx, &gen_op_cmpfne, ra, disp16); + ret = 1; + break; + case 0x36: + /* FBGE */ + gen_fbcond(ctx, &gen_op_cmpfge, ra, disp16); + ret = 1; + break; + case 0x37: + /* FBGT */ + gen_fbcond(ctx, &gen_op_cmpfgt, ra, disp16); + ret = 1; + break; + case 0x38: + /* BLBC */ + gen_bcond(ctx, &gen_op_cmplbc, ra, disp16); + ret = 1; + break; + case 0x39: + /* BEQ */ + gen_bcond(ctx, &gen_op_cmpeqz, ra, disp16); + ret = 1; + break; + case 0x3A: + /* BLT */ + gen_bcond(ctx, &gen_op_cmpltz, ra, disp16); + ret = 1; + break; + case 0x3B: + /* BLE */ + gen_bcond(ctx, &gen_op_cmplez, ra, disp16); + ret = 1; + break; + case 0x3C: + /* BLBS */ + gen_bcond(ctx, &gen_op_cmplbs, ra, disp16); + ret = 1; + break; + case 0x3D: + /* BNE */ + gen_bcond(ctx, &gen_op_cmpnez, ra, disp16); + ret = 1; + break; + case 0x3E: + /* BGE */ + gen_bcond(ctx, &gen_op_cmpgez, ra, disp16); + ret = 1; + break; + case 0x3F: + /* BGT */ + gen_bcond(ctx, &gen_op_cmpgtz, ra, disp16); + ret = 1; + break; + invalid_opc: + gen_invalid(ctx); + ret = 3; + break; + } + + return ret; +} + +int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, + int search_pc) +{ +#if defined ALPHA_DEBUG_DISAS + static int insn_count; +#endif + DisasContext ctx, *ctxp = &ctx; + target_ulong pc_start; + uint32_t insn; + uint16_t *gen_opc_end; + int j, lj = -1; + int ret; + + pc_start = tb->pc; + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + nb_gen_labels = 0; + ctx.pc = pc_start; + ctx.amask = env->amask; +#if defined (CONFIG_USER_ONLY) + ctx.mem_idx = 0; +#else + ctx.mem_idx = ((env->ps >> 3) & 3); + ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1; +#endif + for (ret = 0; ret == 0;) { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == ctx.pc) { + gen_excp(&ctx, EXCP_DEBUG, 0); + break; + } + } + } + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + gen_opc_pc[lj] = ctx.pc; + gen_opc_instr_start[lj] = 1; + } + } +#if defined ALPHA_DEBUG_DISAS + insn_count++; + if (logfile != NULL) { + fprintf(logfile, "pc %016lx mem_idx\n", ctx.pc, ctx.mem_idx); + } +#endif + insn = ldl_code(ctx.pc); +#if defined ALPHA_DEBUG_DISAS + insn_count++; + if (logfile != NULL) { + fprintf(logfile, "opcode %08x %d\n", insn, insn_count); + } +#endif + ctx.pc += 4; + ret = translate_one(ctxp, insn); + if (ret != 0) + break; + /* if we reach a page boundary or are single stepping, stop + * generation + */ + if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) || + (env->singlestep_enabled)) { + break; + } +#if defined (DO_SINGLE_STEP) + break; +#endif + } + if (ret != 1 && ret != 3) { + gen_update_pc(&ctx); + } + gen_op_reset_T0(); +#if defined (DO_TB_FLUSH) + gen_op_tb_flush(); +#endif + /* Generate the return instruction */ + gen_op_exit_tb(); + *gen_opc_ptr = INDEX_op_end; + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + tb->size = 0; + } else { + tb->size = ctx.pc - pc_start; + } +#if defined ALPHA_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_CPU) { + cpu_dump_state(env, logfile, fprintf, 0); + } + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + target_disas(logfile, pc_start, ctx.pc - pc_start, 1); + fprintf(logfile, "\n"); + } + if (loglevel & CPU_LOG_TB_OP) { + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + + return 0; +} + +int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 1); +} + +CPUAlphaState * cpu_alpha_init (void) +{ + CPUAlphaState *env; + uint64_t hwpcb; + + env = qemu_mallocz(sizeof(CPUAlphaState)); + if (!env) + return NULL; + cpu_exec_init(env); + tlb_flush(env, 1); + /* XXX: should not be hardcoded */ + env->implver = IMPLVER_2106x; + env->ps = 0x1F00; +#if defined (CONFIG_USER_ONLY) + env->ps |= 1 << 3; +#endif + pal_init(env); + /* Initialize IPR */ + hwpcb = env->ipr[IPR_PCBB]; + env->ipr[IPR_ASN] = 0; + env->ipr[IPR_ASTEN] = 0; + env->ipr[IPR_ASTSR] = 0; + env->ipr[IPR_DATFX] = 0; + /* XXX: fix this */ + // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8); + // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0); + // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16); + // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24); + env->ipr[IPR_FEN] = 0; + env->ipr[IPR_IPL] = 31; + env->ipr[IPR_MCES] = 0; + env->ipr[IPR_PERFMON] = 0; /* Implementation specific */ + // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32); + env->ipr[IPR_SISR] = 0; + env->ipr[IPR_VIRBND] = -1ULL; + + return env; +} -- cgit v1.2.3 From b82945bcdbf4468327b29b8547bc12b0f07062f0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 07:04:40 +0000 Subject: Alpha CPU palcode emulation. Only usable in user mode for now with code provision for full emulation support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2598 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/alpha_palcode.c | 1099 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1099 insertions(+) create mode 100644 hw/alpha_palcode.c diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c new file mode 100644 index 000000000..0fe9d969f --- /dev/null +++ b/hw/alpha_palcode.c @@ -0,0 +1,1099 @@ +/* + * Alpha emulation - PALcode emulation for qemu. + * + * Copyright (c) 2007 Jocelyn Mayer + * + * 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 +#include +#include + +#include "qemu.h" +#include "cpu.h" +#include "exec-all.h" + +#if !defined (CONFIG_USER_ONLY) +/* Shared handlers */ +static void pal_reset (CPUState *env); +/* Console handlers */ +static void pal_console_call (CPUState *env, uint32_t palcode); +/* OpenVMS handlers */ +static void pal_openvms_call (CPUState *env, uint32_t palcode); +/* UNIX / Linux handlers */ +static void pal_unix_call (CPUState *env, uint32_t palcode); + +pal_handler_t pal_handlers[] = { + /* Console handler */ + { + .reset = &pal_reset, + .call_pal = &pal_console_call, + }, + /* OpenVMS handler */ + { + .reset = &pal_reset, + .call_pal = &pal_openvms_call, + }, + /* UNIX / Linux handler */ + { + .reset = &pal_reset, + .call_pal = &pal_unix_call, + }, +}; + +#if 0 +/* One must explicitely check that the TB is valid and the FOE bit is reset */ +static void update_itb () +{ + /* This writes into a temp register, not the actual one */ + mtpr(TB_TAG); + mtpr(TB_CTL); + /* This commits the TB update */ + mtpr(ITB_PTE); +} + +static void update_dtb (); +{ + mtpr(TB_CTL); + /* This write into a temp register, not the actual one */ + mtpr(TB_TAG); + /* This commits the TB update */ + mtpr(DTB_PTE); +} +#endif + +static void pal_reset (CPUState *env) +{ +} + +static void do_swappal (CPUState *env, uint64_t palid) +{ + pal_handler_t *pal_handler; + int status; + + status = 0; + switch (palid) { + case 0 ... 2: + pal_handler = &pal_handlers[palid]; + env->pal_handler = pal_handler; + env->ipr[IPR_PAL_BASE] = -1ULL; + (*pal_handler->reset)(env); + break; + case 3 ... 255: + /* Unknown identifier */ + env->ir[0] = 1; + return; + default: + /* We were given the entry point address */ + env->pal_handler = NULL; + env->ipr[IPR_PAL_BASE] = palid; + env->pc = env->ipr[IPR_PAL_BASE]; + cpu_loop_exit(); + } +} + +static void pal_console_call (CPUState *env, uint32_t palcode) +{ + uint64_t palid; + + if (palcode < 0x00000080) { + /* Privileged palcodes */ + if (!(env->ps >> 3)) { + /* TODO: generate privilege exception */ + } + } + switch (palcode) { + case 0x00000000: + /* HALT */ + /* REQUIRED */ + break; + case 0x00000001: + /* CFLUSH */ + break; + case 0x00000002: + /* DRAINA */ + /* REQUIRED */ + /* Implemented as no-op */ + break; + case 0x00000009: + /* CSERVE */ + /* REQUIRED */ + break; + case 0x0000000A: + /* SWPPAL */ + /* REQUIRED */ + palid = env->ir[16]; + do_swappal(env, palid); + break; + case 0x00000080: + /* BPT */ + /* REQUIRED */ + break; + case 0x00000081: + /* BUGCHK */ + /* REQUIRED */ + break; + case 0x00000086: + /* IMB */ + /* REQUIRED */ + /* Implemented as no-op */ + break; + case 0x0000009E: + /* RDUNIQUE */ + /* REQUIRED */ + break; + case 0x0000009F: + /* WRUNIQUE */ + /* REQUIRED */ + break; + case 0x000000AA: + /* GENTRAP */ + /* REQUIRED */ + break; + default: + break; + } +} + +static void pal_openvms_call (CPUState *env, uint32_t palcode) +{ + uint64_t palid, val, oldval; + + if (palcode < 0x00000080) { + /* Privileged palcodes */ + if (!(env->ps >> 3)) { + /* TODO: generate privilege exception */ + } + } + switch (palcode) { + case 0x00000000: + /* HALT */ + /* REQUIRED */ + break; + case 0x00000001: + /* CFLUSH */ + break; + case 0x00000002: + /* DRAINA */ + /* REQUIRED */ + /* Implemented as no-op */ + break; + case 0x00000003: + /* LDQP */ + break; + case 0x00000004: + /* STQP */ + break; + case 0x00000005: + /* SWPCTX */ + break; + case 0x00000006: + /* MFPR_ASN */ + if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0) + env->ir[0] = val; + break; + case 0x00000007: + /* MTPR_ASTEN */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000008: + /* MTPR_ASTSR */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000009: + /* CSERVE */ + /* REQUIRED */ + break; + case 0x0000000A: + /* SWPPAL */ + /* REQUIRED */ + palid = env->ir[16]; + do_swappal(env, palid); + break; + case 0x0000000B: + /* MFPR_FEN */ + if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0) + env->ir[0] = val; + break; + case 0x0000000C: + /* MTPR_FEN */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000000D: + /* MTPR_IPIR */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000000E: + /* MFPR_IPL */ + if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0) + env->ir[0] = val; + break; + case 0x0000000F: + /* MTPR_IPL */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000010: + /* MFPR_MCES */ + if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0) + env->ir[0] = val; + break; + case 0x00000011: + /* MTPR_MCES */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000012: + /* MFPR_PCBB */ + if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0) + env->ir[0] = val; + break; + case 0x00000013: + /* MFPR_PRBR */ + if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0) + env->ir[0] = val; + break; + case 0x00000014: + /* MTPR_PRBR */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000015: + /* MFPR_PTBR */ + if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0) + env->ir[0] = val; + break; + case 0x00000016: + /* MFPR_SCBB */ + if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0) + env->ir[0] = val; + break; + case 0x00000017: + /* MTPR_SCBB */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000018: + /* MTPR_SIRR */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000019: + /* MFPR_SISR */ + if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0) + env->ir[0] = val; + break; + case 0x0000001A: + /* MFPR_TBCHK */ + if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0) + env->ir[0] = val; + break; + case 0x0000001B: + /* MTPR_TBIA */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000001C: + /* MTPR_TBIAP */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000001D: + /* MTPR_TBIS */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000001E: + /* MFPR_ESP */ + if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0) + env->ir[0] = val; + break; + case 0x0000001F: + /* MTPR_ESP */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000020: + /* MFPR_SSP */ + if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0) + env->ir[0] = val; + break; + case 0x00000021: + /* MTPR_SSP */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000022: + /* MFPR_USP */ + if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0) + env->ir[0] = val; + break; + case 0x00000023: + /* MTPR_USP */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000024: + /* MTPR_TBISD */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000025: + /* MTPR_TBISI */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000026: + /* MFPR_ASTEN */ + if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0) + env->ir[0] = val; + break; + case 0x00000027: + /* MFPR_ASTSR */ + if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0) + env->ir[0] = val; + break; + case 0x00000029: + /* MFPR_VPTB */ + if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0) + env->ir[0] = val; + break; + case 0x0000002A: + /* MTPR_VPTB */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000002B: + /* MTPR_PERFMON */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000002E: + /* MTPR_DATFX */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000003E: + /* WTINT */ + break; + case 0x0000003F: + /* MFPR_WHAMI */ + if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) + env->ir[0] = val; + break; + case 0x00000080: + /* BPT */ + /* REQUIRED */ + break; + case 0x00000081: + /* BUGCHK */ + /* REQUIRED */ + break; + case 0x00000082: + /* CHME */ + break; + case 0x00000083: + /* CHMK */ + break; + case 0x00000084: + /* CHMS */ + break; + case 0x00000085: + /* CHMU */ + break; + case 0x00000086: + /* IMB */ + /* REQUIRED */ + /* Implemented as no-op */ + break; + case 0x00000087: + /* INSQHIL */ + break; + case 0x00000088: + /* INSQTIL */ + break; + case 0x00000089: + /* INSQHIQ */ + break; + case 0x0000008A: + /* INSQTIQ */ + break; + case 0x0000008B: + /* INSQUEL */ + break; + case 0x0000008C: + /* INSQUEQ */ + break; + case 0x0000008D: + /* INSQUEL/D */ + break; + case 0x0000008E: + /* INSQUEQ/D */ + break; + case 0x0000008F: + /* PROBER */ + break; + case 0x00000090: + /* PROBEW */ + break; + case 0x00000091: + /* RD_PS */ + break; + case 0x00000092: + /* REI */ + break; + case 0x00000093: + /* REMQHIL */ + break; + case 0x00000094: + /* REMQTIL */ + break; + case 0x00000095: + /* REMQHIQ */ + break; + case 0x00000096: + /* REMQTIQ */ + break; + case 0x00000097: + /* REMQUEL */ + break; + case 0x00000098: + /* REMQUEQ */ + break; + case 0x00000099: + /* REMQUEL/D */ + break; + case 0x0000009A: + /* REMQUEQ/D */ + break; + case 0x0000009B: + /* SWASTEN */ + break; + case 0x0000009C: + /* WR_PS_SW */ + break; + case 0x0000009D: + /* RSCC */ + break; + case 0x0000009E: + /* READ_UNQ */ + /* REQUIRED */ + break; + case 0x0000009F: + /* WRITE_UNQ */ + /* REQUIRED */ + break; + case 0x000000A0: + /* AMOVRR */ + break; + case 0x000000A1: + /* AMOVRM */ + break; + case 0x000000A2: + /* INSQHILR */ + break; + case 0x000000A3: + /* INSQTILR */ + break; + case 0x000000A4: + /* INSQHIQR */ + break; + case 0x000000A5: + /* INSQTIQR */ + break; + case 0x000000A6: + /* REMQHILR */ + break; + case 0x000000A7: + /* REMQTILR */ + break; + case 0x000000A8: + /* REMQHIQR */ + break; + case 0x000000A9: + /* REMQTIQR */ + break; + case 0x000000AA: + /* GENTRAP */ + /* REQUIRED */ + break; + case 0x000000AE: + /* CLRFEN */ + break; + default: + break; + } +} + +static void pal_unix_call (CPUState *env, uint32_t palcode) +{ + uint64_t palid, val, oldval; + + if (palcode < 0x00000080) { + /* Privileged palcodes */ + if (!(env->ps >> 3)) { + /* TODO: generate privilege exception */ + } + } + switch (palcode) { + case 0x00000000: + /* HALT */ + /* REQUIRED */ + break; + case 0x00000001: + /* CFLUSH */ + break; + case 0x00000002: + /* DRAINA */ + /* REQUIRED */ + /* Implemented as no-op */ + break; + case 0x00000009: + /* CSERVE */ + /* REQUIRED */ + break; + case 0x0000000A: + /* SWPPAL */ + /* REQUIRED */ + palid = env->ir[16]; + do_swappal(env, palid); + break; + case 0x0000000D: + /* WRIPIR */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000010: + /* RDMCES */ + if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0) + env->ir[0] = val; + break; + case 0x00000011: + /* WRMCES */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000002B: + /* WRFEN */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000002D: + /* WRVPTPTR */ + break; + case 0x00000030: + /* SWPCTX */ + break; + case 0x00000031: + /* WRVAL */ + break; + case 0x00000032: + /* RDVAL */ + break; + case 0x00000033: + /* TBI */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000034: + /* WRENT */ + break; + case 0x00000035: + /* SWPIPL */ + break; + case 0x00000036: + /* RDPS */ + break; + case 0x00000037: + /* WRKGP */ + break; + case 0x00000038: + /* WRUSP */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x00000039: + /* WRPERFMON */ + val = env->ir[16]; + if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) + env->ir[0] = val; + break; + case 0x0000003A: + /* RDUSP */ + if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0) + env->ir[0] = val; + break; + case 0x0000003C: + /* WHAMI */ + if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) + env->ir[0] = val; + break; + case 0x0000003D: + /* RETSYS */ + break; + case 0x0000003E: + /* WTINT */ + break; + case 0x0000003F: + /* RTI */ + if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) + env->ir[0] = val; + break; + case 0x00000080: + /* BPT */ + /* REQUIRED */ + break; + case 0x00000081: + /* BUGCHK */ + /* REQUIRED */ + break; + case 0x00000083: + /* CALLSYS */ + break; + case 0x00000086: + /* IMB */ + /* REQUIRED */ + /* Implemented as no-op */ + break; + case 0x00000092: + /* URTI */ + break; + case 0x0000009E: + /* RDUNIQUE */ + /* REQUIRED */ + break; + case 0x0000009F: + /* WRUNIQUE */ + /* REQUIRED */ + break; + case 0x000000AA: + /* GENTRAP */ + /* REQUIRED */ + break; + case 0x000000AE: + /* CLRFEN */ + break; + default: + break; + } +} + +void call_pal (CPUState *env) +{ + pal_handler_t *pal_handler = env->pal_handler; + + switch (env->exception_index) { + case EXCP_RESET: + (*pal_handler->reset)(env); + break; + case EXCP_MCHK: + (*pal_handler->machine_check)(env); + break; + case EXCP_ARITH: + (*pal_handler->arithmetic)(env); + break; + case EXCP_INTERRUPT: + (*pal_handler->interrupt)(env); + break; + case EXCP_DFAULT: + (*pal_handler->dfault)(env); + break; + case EXCP_DTB_MISS_PAL: + (*pal_handler->dtb_miss_pal)(env); + break; + case EXCP_DTB_MISS_NATIVE: + (*pal_handler->dtb_miss_native)(env); + break; + case EXCP_UNALIGN: + (*pal_handler->unalign)(env); + break; + case EXCP_ITB_MISS: + (*pal_handler->itb_miss)(env); + break; + case EXCP_ITB_ACV: + (*pal_handler->itb_acv)(env); + break; + case EXCP_OPCDEC: + (*pal_handler->opcdec)(env); + break; + case EXCP_FEN: + (*pal_handler->fen)(env); + break; + default: + if (env->exception_index >= EXCP_CALL_PAL && + env->exception_index < EXCP_CALL_PALP) { + /* Unprivileged PAL call */ + (*pal_handler->call_pal) + (env, (env->exception_index - EXCP_CALL_PAL) >> 6); + } else if (env->exception_index >= EXCP_CALL_PALP && + env->exception_index < EXCP_CALL_PALE) { + /* Privileged PAL call */ + (*pal_handler->call_pal) + (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80); + } else { + /* Should never happen */ + } + break; + } + env->ipr[IPR_EXC_ADDR] &= ~1; +} + +void pal_init (CPUState *env) +{ + do_swappal(env, 0); +} + +#if 0 +static uint64_t get_ptebase (CPUState *env, uint64_t vaddr) +{ + uint64_t virbnd, ptbr; + + if ((env->features & FEATURE_VIRBND)) { + cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd); + if (vaddr >= virbnd) + cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr); + else + cpu_alpha_mfpr(env, IPR_PTBR, &ptbr); + } else { + cpu_alpha_mfpr(env, IPR_PTBR, &ptbr); + } + + return ptbr; +} + +static int get_page_bits (CPUState *env) +{ + /* XXX */ + return 13; +} + +static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp, + uint64_t ptebase, int page_bits, uint64_t level, + int is_user, int rw) +{ + uint64_t pteaddr, pte, pfn; + uint8_t gh; + int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar; + + pteaddr = (ptebase << page_bits) + (8 * level); + pte = ldq_raw(pteaddr); + /* Decode all interresting PTE fields */ + pfn = pte >> 32; + uwe = (pte >> 13) & 1; + kwe = (pte >> 12) & 1; + ure = (pte >> 9) & 1; + kre = (pte >> 8) & 1; + gh = (pte >> 5) & 3; + foE = (pte >> 3) & 1; + foW = (pte >> 2) & 1; + foR = (pte >> 1) & 1; + v = pte & 1; + ret = 0; + if (!v) + ret = 0x1; + /* Check access rights */ + ar = 0; + if (is_user) { + if (ure) + ar |= PAGE_READ; + if (uwe) + ar |= PAGE_WRITE; + if (rw == 1 && !uwe) + ret |= 0x2; + if (rw != 1 && !ure) + ret |= 0x2; + } else { + if (kre) + ar |= PAGE_READ; + if (kwe) + ar |= PAGE_WRITE; + if (rw == 1 && !kwe) + ret |= 0x2; + if (rw != 1 && !kre) + ret |= 0x2; + } + if (rw == 0 && foR) + ret |= 0x4; + if (rw == 2 && foE) + ret |= 0x8; + if (rw == 1 && foW) + ret |= 0xC; + *pfnp = pfn; + if (zbitsp != NULL) + *zbitsp = page_bits + (3 * gh); + if (protp != NULL) + *protp = ar; + + return ret; +} + +static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot, + uint64_t ptebase, int page_bits, + uint64_t vaddr, int is_user, int rw) +{ + uint64_t pfn, page_mask, lvl_mask, level1, level2, level3; + int lvl_bits, ret; + + page_mask = (1ULL << page_bits) - 1ULL; + lvl_bits = page_bits - 3; + lvl_mask = (1ULL << lvl_bits) - 1ULL; + level3 = (vaddr >> page_bits) & lvl_mask; + level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask; + level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask; + /* Level 1 PTE */ + ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0); + switch (ret) { + case 3: + /* Access violation */ + return 2; + case 2: + /* translation not valid */ + return 1; + default: + /* OK */ + break; + } + /* Level 2 PTE */ + ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0); + switch (ret) { + case 3: + /* Access violation */ + return 2; + case 2: + /* translation not valid */ + return 1; + default: + /* OK */ + break; + } + /* Level 3 PTE */ + ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, is_user, rw); + if (ret & 0x1) { + /* Translation not valid */ + ret = 1; + } else if (ret & 2) { + /* Access violation */ + ret = 2; + } else { + switch (ret & 0xC) { + case 0: + /* OK */ + ret = 0; + break; + case 0x4: + /* Fault on read */ + ret = 3; + break; + case 0x8: + /* Fault on execute */ + ret = 4; + break; + case 0xC: + /* Fault on write */ + ret = 5; + break; + } + } + *paddr = (pfn << page_bits) | (vaddr & page_mask); + + return 0; +} + +static int virtual_to_physical (CPUState *env, uint64_t *physp, + int *zbitsp, int *protp, + uint64_t virtual, int is_user, int rw) +{ + uint64_t sva, ptebase; + int seg, page_bits, ret; + + sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS); + if (sva != virtual) + seg = -1; + else + seg = sva >> (VA_BITS - 2); + virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43)); + ptebase = get_ptebase(env, virtual); + page_bits = get_page_bits(env); + ret = 0; + switch (seg) { + case 0: + /* seg1: 3 levels of PTE */ + ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, + virtual, is_user, rw); + break; + case 1: + /* seg1: 2 levels of PTE */ + ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, + virtual, is_user, rw); + break; + case 2: + /* kernel segment */ + if (is_user) { + ret = 2; + } else { + *physp = virtual; + } + break; + case 3: + /* seg1: TB mapped */ + ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, + virtual, is_user, rw); + break; + default: + ret = 1; + break; + } + + return ret; +} + +/* XXX: code provision */ +int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu) +{ + uint64_t physical, page_size, end; + int prot, zbits, ret; + + if (env->user_mode_only) { + ret = 2; + } else { + ret = virtual_to_physical(env, &physical, &zbits, &prot, + address, is_user, rw); + } + switch (ret) { + case 0: + /* No fault */ + page_size = 1ULL << zbits; + address &= ~(page_size - 1); + for (end = physical + page_size; physical < end; physical += 0x1000) { + ret = tlb_set_page(env, address, physical, prot, + is_user, is_softmmu); + address += 0x1000; + } + break; +#if 0 + case 1: + env->exception_index = EXCP_DFAULT; + env->ipr[IPR_EXC_ADDR] = address; + ret = 1; + break; + case 2: + env->exception_index = EXCP_ACCESS_VIOLATION; + env->ipr[IPR_EXC_ADDR] = address; + ret = 1; + break; + case 3: + env->exception_index = EXCP_FAULT_ON_READ; + env->ipr[IPR_EXC_ADDR] = address; + ret = 1; + break; + case 4: + env->exception_index = EXCP_FAULT_ON_EXECUTE; + env->ipr[IPR_EXC_ADDR] = address; + ret = 1; + case 5: + env->exception_index = EXCP_FAULT_ON_WRITE; + env->ipr[IPR_EXC_ADDR] = address; + ret = 1; +#endif + default: + /* Should never happen */ + env->exception_index = EXCP_MCHK; + env->ipr[IPR_EXC_ADDR] = address; + ret = 1; + break; + } + + return ret; +} +#endif + +#else /* !defined (CONFIG_USER_ONLY) */ +void pal_init (CPUState *env) +{ +} + +void call_pal (CPUState *env, int palcode) +{ + target_ulong ret; + + printf("%s: palcode %02x\n", __func__, palcode); + if (logfile != NULL) + fprintf(logfile, "%s: palcode %02x\n", __func__, palcode); + switch (palcode) { + case 0x83: + /* CALLSYS */ + printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); + if (logfile != NULL) + fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); + ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1], + env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4], + env->ir[IR_A5]); + env->ir[IR_A3] = ret; + if (ret > (target_ulong)(-515)) { + env->ir[IR_V0] = 1; + } else { + env->ir[IR_V0] = 0; + } + break; + case 0x9E: + /* RDUNIQUE */ + env->ir[IR_V0] = env->unique; + printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique); + break; + case 0x9F: + /* WRUNIQUE */ + env->unique = env->ir[IR_A0]; + printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique); + break; + default: + printf("%s: unhandled palcode %02x\n", __func__, palcode); + if (logfile != NULL) + fprintf(logfile, "%s: unhandled palcode %02x\n", + __func__, palcode); + exit(1); + } +} +#endif -- cgit v1.2.3 From 86cc1ce08362ac8f7da40b7c2aafb9093ab3ae24 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 07:06:55 +0000 Subject: Definitions needed for Alpha linux user-mode emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2599 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/alpha/syscall.h | 115 +++++++++++++ linux-user/alpha/syscall_nr.h | 381 ++++++++++++++++++++++++++++++++++++++++++ linux-user/alpha/termbits.h | 265 +++++++++++++++++++++++++++++ 3 files changed, 761 insertions(+) create mode 100644 linux-user/alpha/syscall.h create mode 100644 linux-user/alpha/syscall_nr.h create mode 100644 linux-user/alpha/termbits.h diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h new file mode 100644 index 000000000..def680e5a --- /dev/null +++ b/linux-user/alpha/syscall.h @@ -0,0 +1,115 @@ +/* default linux values for the selectors */ +#define __USER_DS (1) + +struct target_pt_regs { + target_ulong r0; + target_ulong r1; + target_ulong r2; + target_ulong r3; + target_ulong r4; + target_ulong r5; + target_ulong r6; + target_ulong r7; + target_ulong r8; + target_ulong r19; + target_ulong r20; + target_ulong r21; + target_ulong r22; + target_ulong r23; + target_ulong r24; + target_ulong r25; + target_ulong r26; + target_ulong r27; + target_ulong r28; + target_ulong hae; +/* JRP - These are the values provided to a0-a2 by PALcode */ + target_ulong trap_a0; + target_ulong trap_a1; + target_ulong trap_a2; +/* These are saved by PAL-code: */ + target_ulong ps; + target_ulong pc; + target_ulong gp; + target_ulong r16; + target_ulong r17; + target_ulong r18; +/* Those is needed by qemu to temporary store the user stack pointer */ + target_ulong usp; + target_ulong unique; +}; + +#define TARGET_SEMOP 1 +#define TARGET_SEMGET 2 +#define TARGET_SEMCTL 3 +#define TARGET_MSGSND 11 +#define TARGET_MSGRCV 12 +#define TARGET_MSGGET 13 +#define TARGET_MSGCTL 14 +#define TARGET_SHMAT 21 +#define TARGET_SHMDT 22 +#define TARGET_SHMGET 23 +#define TARGET_SHMCTL 24 + +struct target_msgbuf { + int mtype; + char mtext[1]; +}; + +struct target_ipc_kludge { + unsigned int msgp; /* Really (struct msgbuf *) */ + int msgtyp; +}; + +struct target_ipc_perm { + int key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +struct target_msqid_ds { + struct target_ipc_perm msg_perm; + unsigned int msg_first; /* really struct target_msg* */ + unsigned int msg_last; /* really struct target_msg* */ + unsigned int msg_stime; /* really target_time_t */ + unsigned int msg_rtime; /* really target_time_t */ + unsigned int msg_ctime; /* really target_time_t */ + unsigned int wwait; /* really struct wait_queue* */ + unsigned int rwait; /* really struct wait_queue* */ + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + unsigned short msg_lspid; + unsigned short msg_lrpid; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; + int shm_segsz; + unsigned int shm_atime; /* really target_time_t */ + unsigned int shm_dtime; /* really target_time_t */ + unsigned int shm_ctime; /* really target_time_t */ + unsigned short shm_cpid; + unsigned short shm_lpid; + short shm_nattch; + unsigned short shm_npages; + unsigned long *shm_pages; + void *attaches; /* really struct shm_desc * */ +}; + +#define TARGET_IPC_RMID 0 +#define TARGET_IPC_SET 1 +#define TARGET_IPC_STAT 2 + +union target_semun { + int val; + unsigned int buf; /* really struct semid_ds * */ + unsigned int array; /* really unsigned short * */ + unsigned int __buf; /* really struct seminfo * */ + unsigned int __pad; /* really void* */ +}; + +#define UNAME_MACHINE "alpha" diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h new file mode 100644 index 000000000..b39b6d8df --- /dev/null +++ b/linux-user/alpha/syscall_nr.h @@ -0,0 +1,381 @@ +#define TARGET_NR_osf_syscall 0 /* not implemented */ +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_osf_old_open 5 /* not implemented */ +#define TARGET_NR_close 6 +#define TARGET_NR_osf_wait4 7 +#define TARGET_NR_osf_old_creat 8 /* not implemented */ +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_osf_execve 11 /* not implemented */ +#define TARGET_NR_chdir 12 +#define TARGET_NR_fchdir 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_chown 16 +#define TARGET_NR_brk 17 +#define TARGET_NR_osf_getfsstat 18 /* not implemented */ +#define TARGET_NR_lseek 19 +#define TARGET_NR_getxpid 20 +#define TARGET_NR_osf_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getxuid 24 +#define TARGET_NR_exec_with_loader 25 /* not implemented */ +#define TARGET_NR_ptrace 26 +#define TARGET_NR_osf_nrecvmsg 27 /* not implemented */ +#define TARGET_NR_osf_nsendmsg 28 /* not implemented */ +#define TARGET_NR_osf_nrecvfrom 29 /* not implemented */ +#define TARGET_NR_osf_naccept 30 /* not implemented */ +#define TARGET_NR_osf_ngetpeername 31 /* not implemented */ +#define TARGET_NR_osf_ngetsockname 32 /* not implemented */ +#define TARGET_NR_access 33 +#define TARGET_NR_osf_chflags 34 /* not implemented */ +#define TARGET_NR_osf_fchflags 35 /* not implemented */ +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_osf_old_stat 38 /* not implemented */ +#define TARGET_NR_setpgid 39 +#define TARGET_NR_osf_old_lstat 40 /* not implemented */ +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_osf_set_program_attributes 43 +#define TARGET_NR_osf_profil 44 /* not implemented */ +#define TARGET_NR_open 45 +#define TARGET_NR_osf_old_sigaction 46 /* not implemented */ +#define TARGET_NR_getxgid 47 +#define TARGET_NR_osf_sigprocmask 48 +#define TARGET_NR_osf_getlogin 49 /* not implemented */ +#define TARGET_NR_osf_setlogin 50 /* not implemented */ +#define TARGET_NR_acct 51 +#define TARGET_NR_sigpending 52 + +#define TARGET_NR_ioctl 54 +#define TARGET_NR_osf_reboot 55 /* not implemented */ +#define TARGET_NR_osf_revoke 56 /* not implemented */ +#define TARGET_NR_symlink 57 +#define TARGET_NR_readlink 58 +#define TARGET_NR_execve 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_osf_old_fstat 62 /* not implemented */ +#define TARGET_NR_getpgrp 63 +#define TARGET_NR_getpagesize 64 +#define TARGET_NR_osf_mremap 65 /* not implemented */ +#define TARGET_NR_vfork 66 +#define TARGET_NR_stat 67 +#define TARGET_NR_lstat 68 +#define TARGET_NR_osf_sbrk 69 /* not implemented */ +#define TARGET_NR_osf_sstk 70 /* not implemented */ +#define TARGET_NR_mmap 71 /* OSF/1 mmap is superset of Linux */ +#define TARGET_NR_osf_old_vadvise 72 /* not implemented */ +#define TARGET_NR_munmap 73 +#define TARGET_NR_mprotect 74 +#define TARGET_NR_madvise 75 +#define TARGET_NR_vhangup 76 +#define TARGET_NR_osf_kmodcall 77 /* not implemented */ +#define TARGET_NR_osf_mincore 78 /* not implemented */ +#define TARGET_NR_getgroups 79 +#define TARGET_NR_setgroups 80 +#define TARGET_NR_osf_old_getpgrp 81 /* not implemented */ +#define TARGET_NR_setpgrp 82 /* BSD alias for setpgid */ +#define TARGET_NR_osf_setitimer 83 +#define TARGET_NR_osf_old_wait 84 /* not implemented */ +#define TARGET_NR_osf_table 85 /* not implemented */ +#define TARGET_NR_osf_getitimer 86 +#define TARGET_NR_gethostname 87 +#define TARGET_NR_sethostname 88 +#define TARGET_NR_getdtablesize 89 +#define TARGET_NR_dup2 90 +#define TARGET_NR_fstat 91 +#define TARGET_NR_fcntl 92 +#define TARGET_NR_osf_select 93 +#define TARGET_NR_poll 94 +#define TARGET_NR_fsync 95 +#define TARGET_NR_setpriority 96 +#define TARGET_NR_socket 97 +#define TARGET_NR_connect 98 +#define TARGET_NR_accept 99 +#define TARGET_NR_getpriority 100 +#define TARGET_NR_send 101 +#define TARGET_NR_recv 102 +#define TARGET_NR_sigreturn 103 +#define TARGET_NR_bind 104 +#define TARGET_NR_setsockopt 105 +#define TARGET_NR_listen 106 +#define TARGET_NR_osf_plock 107 /* not implemented */ +#define TARGET_NR_osf_old_sigvec 108 /* not implemented */ +#define TARGET_NR_osf_old_sigblock 109 /* not implemented */ +#define TARGET_NR_osf_old_sigsetmask 110 /* not implemented */ +#define TARGET_NR_sigsuspend 111 +#define TARGET_NR_osf_sigstack 112 +#define TARGET_NR_recvmsg 113 +#define TARGET_NR_sendmsg 114 +#define TARGET_NR_osf_old_vtrace 115 /* not implemented */ +#define TARGET_NR_osf_gettimeofday 116 +#define TARGET_NR_osf_getrusage 117 +#define TARGET_NR_getsockopt 118 + +#define TARGET_NR_readv 120 +#define TARGET_NR_writev 121 +#define TARGET_NR_osf_settimeofday 122 +#define TARGET_NR_fchown 123 +#define TARGET_NR_fchmod 124 +#define TARGET_NR_recvfrom 125 +#define TARGET_NR_setreuid 126 +#define TARGET_NR_setregid 127 +#define TARGET_NR_rename 128 +#define TARGET_NR_truncate 129 +#define TARGET_NR_ftruncate 130 +#define TARGET_NR_flock 131 +#define TARGET_NR_setgid 132 +#define TARGET_NR_sendto 133 +#define TARGET_NR_shutdown 134 +#define TARGET_NR_socketpair 135 +#define TARGET_NR_mkdir 136 +#define TARGET_NR_rmdir 137 +#define TARGET_NR_osf_utimes 138 +#define TARGET_NR_osf_old_sigreturn 139 /* not implemented */ +#define TARGET_NR_osf_adjtime 140 /* not implemented */ +#define TARGET_NR_getpeername 141 +#define TARGET_NR_osf_gethostid 142 /* not implemented */ +#define TARGET_NR_osf_sethostid 143 /* not implemented */ +#define TARGET_NR_getrlimit 144 +#define TARGET_NR_setrlimit 145 +#define TARGET_NR_osf_old_killpg 146 /* not implemented */ +#define TARGET_NR_setsid 147 +#define TARGET_NR_quotactl 148 +#define TARGET_NR_osf_oldquota 149 /* not implemented */ +#define TARGET_NR_getsockname 150 + +#define TARGET_NR_osf_pid_block 153 /* not implemented */ +#define TARGET_NR_osf_pid_unblock 154 /* not implemented */ + +#define TARGET_NR_sigaction 156 +#define TARGET_NR_osf_sigwaitprim 157 /* not implemented */ +#define TARGET_NR_osf_nfssvc 158 /* not implemented */ +#define TARGET_NR_osf_getdirentries 159 +#define TARGET_NR_osf_statfs 160 +#define TARGET_NR_osf_fstatfs 161 + +#define TARGET_NR_osf_asynch_daemon 163 /* not implemented */ +#define TARGET_NR_osf_getfh 164 /* not implemented */ +#define TARGET_NR_osf_getdomainname 165 +#define TARGET_NR_setdomainname 166 + +#define TARGET_NR_osf_exportfs 169 /* not implemented */ + +#define TARGET_NR_osf_alt_plock 181 /* not implemented */ + +#define TARGET_NR_osf_getmnt 184 /* not implemented */ + +#define TARGET_NR_osf_alt_sigpending 187 /* not implemented */ +#define TARGET_NR_osf_alt_setsid 188 /* not implemented */ + +#define TARGET_NR_osf_swapon 199 +#define TARGET_NR_msgctl 200 +#define TARGET_NR_msgget 201 +#define TARGET_NR_msgrcv 202 +#define TARGET_NR_msgsnd 203 +#define TARGET_NR_semctl 204 +#define TARGET_NR_semget 205 +#define TARGET_NR_semop 206 +#define TARGET_NR_osf_utsname 207 +#define TARGET_NR_lchown 208 +#define TARGET_NR_osf_shmat 209 +#define TARGET_NR_shmctl 210 +#define TARGET_NR_shmdt 211 +#define TARGET_NR_shmget 212 +#define TARGET_NR_osf_mvalid 213 /* not implemented */ +#define TARGET_NR_osf_getaddressconf 214 /* not implemented */ +#define TARGET_NR_osf_msleep 215 /* not implemented */ +#define TARGET_NR_osf_mwakeup 216 /* not implemented */ +#define TARGET_NR_msync 217 +#define TARGET_NR_osf_signal 218 /* not implemented */ +#define TARGET_NR_osf_utc_gettime 219 /* not implemented */ +#define TARGET_NR_osf_utc_adjtime 220 /* not implemented */ + +#define TARGET_NR_osf_security 222 /* not implemented */ +#define TARGET_NR_osf_kloadcall 223 /* not implemented */ + +#define TARGET_NR_getpgid 233 +#define TARGET_NR_getsid 234 +#define TARGET_NR_sigaltstack 235 +#define TARGET_NR_osf_waitid 236 /* not implemented */ +#define TARGET_NR_osf_priocntlset 237 /* not implemented */ +#define TARGET_NR_osf_sigsendset 238 /* not implemented */ +#define TARGET_NR_osf_set_speculative 239 /* not implemented */ +#define TARGET_NR_osf_msfs_syscall 240 /* not implemented */ +#define TARGET_NR_osf_sysinfo 241 +#define TARGET_NR_osf_uadmin 242 /* not implemented */ +#define TARGET_NR_osf_fuser 243 /* not implemented */ +#define TARGET_NR_osf_proplist_syscall 244 +#define TARGET_NR_osf_ntp_adjtime 245 /* not implemented */ +#define TARGET_NR_osf_ntp_gettime 246 /* not implemented */ +#define TARGET_NR_osf_pathconf 247 /* not implemented */ +#define TARGET_NR_osf_fpathconf 248 /* not implemented */ + +#define TARGET_NR_osf_uswitch 250 /* not implemented */ +#define TARGET_NR_osf_usleep_thread 251 +#define TARGET_NR_osf_audcntl 252 /* not implemented */ +#define TARGET_NR_osf_audgen 253 /* not implemented */ +#define TARGET_NR_sysfs 254 +#define TARGET_NR_osf_subsys_info 255 /* not implemented */ +#define TARGET_NR_osf_getsysinfo 256 +#define TARGET_NR_osf_setsysinfo 257 +#define TARGET_NR_osf_afs_syscall 258 /* not implemented */ +#define TARGET_NR_osf_swapctl 259 /* not implemented */ +#define TARGET_NR_osf_memcntl 260 /* not implemented */ +#define TARGET_NR_osf_fdatasync 261 /* not implemented */ + + +/* + * Linux-specific system calls begin at 300 + */ +#define TARGET_NR_bdflush 300 +#define TARGET_NR_sethae 301 +#define TARGET_NR_mount 302 +#define TARGET_NR_old_adjtimex 303 +#define TARGET_NR_swapoff 304 +#define TARGET_NR_getdents 305 +#define TARGET_NR_create_module 306 +#define TARGET_NR_init_module 307 +#define TARGET_NR_delete_module 308 +#define TARGET_NR_get_kernel_syms 309 +#define TARGET_NR_syslog 310 +#define TARGET_NR_reboot 311 +#define TARGET_NR_clone 312 +#define TARGET_NR_uselib 313 +#define TARGET_NR_mlock 314 +#define TARGET_NR_munlock 315 +#define TARGET_NR_mlockall 316 +#define TARGET_NR_munlockall 317 +#define TARGET_NR_sysinfo 318 +#define TARGET_NR__sysctl 319 +/* 320 was sys_idle. */ +#define TARGET_NR_oldumount 321 +#define TARGET_NR_swapon 322 +#define TARGET_NR_times 323 +#define TARGET_NR_personality 324 +#define TARGET_NR_setfsuid 325 +#define TARGET_NR_setfsgid 326 +#define TARGET_NR_ustat 327 +#define TARGET_NR_statfs 328 +#define TARGET_NR_fstatfs 329 +#define TARGET_NR_sched_setparam 330 +#define TARGET_NR_sched_getparam 331 +#define TARGET_NR_sched_setscheduler 332 +#define TARGET_NR_sched_getscheduler 333 +#define TARGET_NR_sched_yield 334 +#define TARGET_NR_sched_get_priority_max 335 +#define TARGET_NR_sched_get_priority_min 336 +#define TARGET_NR_sched_rr_get_interval 337 +#define TARGET_NR_afs_syscall 338 +#define TARGET_NR_uname 339 +#define TARGET_NR_nanosleep 340 +#define TARGET_NR_mremap 341 +#define TARGET_NR_nfsservctl 342 +#define TARGET_NR_setresuid 343 +#define TARGET_NR_getresuid 344 +#define TARGET_NR_pciconfig_read 345 +#define TARGET_NR_pciconfig_write 346 +#define TARGET_NR_query_module 347 +#define TARGET_NR_prctl 348 +#define TARGET_NR_pread64 349 +#define TARGET_NR_pwrite64 350 +#define TARGET_NR_rt_sigreturn 351 +#define TARGET_NR_rt_sigaction 352 +#define TARGET_NR_rt_sigprocmask 353 +#define TARGET_NR_rt_sigpending 354 +#define TARGET_NR_rt_sigtimedwait 355 +#define TARGET_NR_rt_sigqueueinfo 356 +#define TARGET_NR_rt_sigsuspend 357 +#define TARGET_NR_select 358 +#define TARGET_NR_gettimeofday 359 +#define TARGET_NR_settimeofday 360 +#define TARGET_NR_getitimer 361 +#define TARGET_NR_setitimer 362 +#define TARGET_NR_utimes 363 +#define TARGET_NR_getrusage 364 +#define TARGET_NR_wait4 365 +#define TARGET_NR_adjtimex 366 +#define TARGET_NR_getcwd 367 +#define TARGET_NR_capget 368 +#define TARGET_NR_capset 369 +#define TARGET_NR_sendfile 370 +#define TARGET_NR_setresgid 371 +#define TARGET_NR_getresgid 372 +#define TARGET_NR_dipc 373 +#define TARGET_NR_pivot_root 374 +#define TARGET_NR_mincore 375 +#define TARGET_NR_pciconfig_iobase 376 +#define TARGET_NR_getdents64 377 +#define TARGET_NR_gettid 378 +#define TARGET_NR_readahead 379 +/* 380 is unused */ +#define TARGET_NR_tkill 381 +#define TARGET_NR_setxattr 382 +#define TARGET_NR_lsetxattr 383 +#define TARGET_NR_fsetxattr 384 +#define TARGET_NR_getxattr 385 +#define TARGET_NR_lgetxattr 386 +#define TARGET_NR_fgetxattr 387 +#define TARGET_NR_listxattr 388 +#define TARGET_NR_llistxattr 389 +#define TARGET_NR_flistxattr 390 +#define TARGET_NR_removexattr 391 +#define TARGET_NR_lremovexattr 392 +#define TARGET_NR_fremovexattr 393 +#define TARGET_NR_futex 394 +#define TARGET_NR_sched_setaffinity 395 +#define TARGET_NR_sched_getaffinity 396 +#define TARGET_NR_tuxcall 397 +#define TARGET_NR_io_setup 398 +#define TARGET_NR_io_destroy 399 +#define TARGET_NR_io_getevents 400 +#define TARGET_NR_io_submit 401 +#define TARGET_NR_io_cancel 402 +#define TARGET_NR_exit_group 405 +#define TARGET_NR_lookup_dcookie 406 +#define TARGET_NR_sys_epoll_create 407 +#define TARGET_NR_sys_epoll_ctl 408 +#define TARGET_NR_sys_epoll_wait 409 +#define TARGET_NR_remap_file_pages 410 +#define TARGET_NR_set_tid_address 411 +#define TARGET_NR_restart_syscall 412 +#define TARGET_NR_fadvise64 413 +#define TARGET_NR_timer_create 414 +#define TARGET_NR_timer_settime 415 +#define TARGET_NR_timer_gettime 416 +#define TARGET_NR_timer_getoverrun 417 +#define TARGET_NR_timer_delete 418 +#define TARGET_NR_clock_settime 419 +#define TARGET_NR_clock_gettime 420 +#define TARGET_NR_clock_getres 421 +#define TARGET_NR_clock_nanosleep 422 +#define TARGET_NR_semtimedop 423 +#define TARGET_NR_tgkill 424 +#define TARGET_NR_stat64 425 +#define TARGET_NR_lstat64 426 +#define TARGET_NR_fstat64 427 +#define TARGET_NR_vserver 428 +#define TARGET_NR_mbind 429 +#define TARGET_NR_get_mempolicy 430 +#define TARGET_NR_set_mempolicy 431 +#define TARGET_NR_mq_open 432 +#define TARGET_NR_mq_unlink 433 +#define TARGET_NR_mq_timedsend 434 +#define TARGET_NR_mq_timedreceive 435 +#define TARGET_NR_mq_notify 436 +#define TARGET_NR_mq_getsetattr 437 +#define TARGET_NR_waitid 438 +#define TARGET_NR_add_key 439 +#define TARGET_NR_request_key 440 +#define TARGET_NR_keyctl 441 +#define TARGET_NR_ioprio_set 442 +#define TARGET_NR_ioprio_get 443 +#define TARGET_NR_inotify_init 444 +#define TARGET_NR_inotify_add_watch 445 +#define TARGET_NR_inotify_rm_watch 446 diff --git a/linux-user/alpha/termbits.h b/linux-user/alpha/termbits.h new file mode 100644 index 000000000..a30c2a982 --- /dev/null +++ b/linux-user/alpha/termbits.h @@ -0,0 +1,265 @@ +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define TARGET_NCCS 19 +struct target_termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_cc[TARGET_NCCS]; /* control characters */ + cc_t c_line; /* line discipline (== c_cc[19]) */ + speed_t c_ispeed; /* input speed */ + speed_t c_ospeed; /* output speed */ +}; + +/* c_cc characters */ +#define TARGET_VEOF 0 +#define TARGET_VEOL 1 +#define TARGET_VEOL2 2 +#define TARGET_VERASE 3 +#define TARGET_VWERASE 4 +#define TARGET_VKILL 5 +#define TARGET_VREPRINT 6 +#define TARGET_VSWTC 7 +#define TARGET_VINTR 8 +#define TARGET_VQUIT 9 +#define TARGET_VSUSP 10 +#define TARGET_VSTART 12 +#define TARGET_VSTOP 13 +#define TARGET_VLNEXT 14 +#define TARGET_VDISCARD 15 +#define TARGET_VMIN 16 +#define TARGET_VTIME 17 + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IXON 0001000 +#define TARGET_IXOFF 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IUCLC 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_ONLCR 0000002 +#define TARGET_OLCUC 0000004 + +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 + +#define TARGET_OFILL 00000100 +#define TARGET_OFDEL 00000200 +#define TARGET_NLDLY 00001400 +#define TARGET_NL0 00000000 +#define TARGET_NL1 00000400 +#define TARGET_NL2 00001000 +#define TARGET_NL3 00001400 +#define TARGET_TABDLY 00006000 +#define TARGET_TAB0 00000000 +#define TARGET_TAB1 00002000 +#define TARGET_TAB2 00004000 +#define TARGET_TAB3 00006000 +#define TARGET_CRDLY 00030000 +#define TARGET_CR0 00000000 +#define TARGET_CR1 00010000 +#define TARGET_CR2 00020000 +#define TARGET_CR3 00030000 +#define TARGET_FFDLY 00040000 +#define TARGET_FF0 00000000 +#define TARGET_FF1 00040000 +#define TARGET_BSDLY 00100000 +#define TARGET_BS0 00000000 +#define TARGET_BS1 00100000 +#define TARGET_VTDLY 00200000 +#define TARGET_VT0 00000000 +#define TARGET_VT1 00200000 +#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0000037 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CBAUDEX 0000000 +#define TARGET_B57600 00020 +#define TARGET_B115200 00021 +#define TARGET_B230400 00022 +#define TARGET_B460800 00023 +#define TARGET_B500000 00024 +#define TARGET_B576000 00025 +#define TARGET_B921600 00026 +#define TARGET_B1000000 00027 +#define TARGET_B1152000 00030 +#define TARGET_B1500000 00031 +#define TARGET_B2000000 00032 +#define TARGET_B2500000 00033 +#define TARGET_B3000000 00034 +#define TARGET_B3500000 00035 +#define TARGET_B4000000 00036 + +#define TARGET_CSIZE 00001400 +#define TARGET_CS5 00000000 +#define TARGET_CS6 00000400 +#define TARGET_CS7 00001000 +#define TARGET_CS8 00001400 + +#define TARGET_CSTOPB 00002000 +#define TARGET_CREAD 00004000 +#define TARGET_PARENB 00010000 +#define TARGET_PARODD 00020000 +#define TARGET_HUPCL 00040000 + +#define TARGET_CLOCAL 00100000 +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000080 +#define TARGET_ICANON 0x00000100 +#define TARGET_XCASE 0x00004000 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000002 +#define TARGET_ECHOK 0x00000004 +#define TARGET_ECHONL 0x00000010 +#define TARGET_NOFLSH 0x80000000 +#define TARGET_TOSTOP 0x00400000 +#define TARGET_ECHOCTL 0x00000040 +#define TARGET_ECHOPRT 0x00000020 +#define TARGET_ECHOKE 0x00000001 +#define TARGET_FLUSHO 0x00800000 +#define TARGET_PENDIN 0x20000000 +#define TARGET_IEXTEN 0x00000400 + +#define TARGET_FIOCLEX _IO('f', 1) +#define TARGET_FIONCLEX _IO('f', 2) +#define TARGET_FIOASYNC _IOW('f', 125, int) +#define TARGET_FIONBIO _IOW('f', 126, int) +#define TARGET_FIONREAD _IOR('f', 127, int) +#define TARGET_TIOCINQ FIONREAD +#define TARGET_FIOQSIZE _IOR('f', 128, loff_t) + +#define TARGET_TIOCGETP _IOR('t', 8, struct sgttyb) +#define TARGET_TIOCSETP _IOW('t', 9, struct sgttyb) +#define TARGET_TIOCSETN _IOW('t', 10, struct sgttyb) /* TIOCSETP wo flush */ + +#define TARGET_TIOCSETC _IOW('t', 17, struct tchars) +#define TARGET_TIOCGETC _IOR('t', 18, struct tchars) +#define TARGET_TCGETS _IOR('t', 19, struct termios) +#define TARGET_TCSETS _IOW('t', 20, struct termios) +#define TARGET_TCSETSW _IOW('t', 21, struct termios) +#define TARGET_TCSETSF _IOW('t', 22, struct termios) + +#define TARGET_TCGETA _IOR('t', 23, struct termio) +#define TARGET_TCSETA _IOW('t', 24, struct termio) +#define TARGET_TCSETAW _IOW('t', 25, struct termio) +#define TARGET_TCSETAF _IOW('t', 28, struct termio) + +#define TARGET_TCSBRK _IO('t', 29) +#define TARGET_TCXONC _IO('t', 30) +#define TARGET_TCFLSH _IO('t', 31) + +#define TARGET_TIOCSWINSZ _IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ _IOR('t', 104, struct winsize) +#define TARGET_TIOCSTART _IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP _IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ _IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCGLTC _IOR('t', 116, struct ltchars) +#define TARGET_TIOCSLTC _IOW('t', 117, struct ltchars) +#define TARGET_TIOCSPGRP _IOW('t', 118, int) +#define TARGET_TIOCGPGRP _IOR('t', 119, int) + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E + +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +# define TARGET_TIOCM_LE 0x001 +# define TARGET_TIOCM_DTR 0x002 +# define TARGET_TIOCM_RTS 0x004 +# define TARGET_TIOCM_ST 0x008 +# define TARGET_TIOCM_SR 0x010 +# define TARGET_TIOCM_CTS 0x020 +# define TARGET_TIOCM_CAR 0x040 +# define TARGET_TIOCM_RNG 0x080 +# define TARGET_TIOCM_DSR 0x100 +# define TARGET_TIOCM_CD TIOCM_CAR +# define TARGET_TIOCM_RI TIOCM_RNG +# define TARGET_TIOCM_OUT1 0x2000 +# define TARGET_TIOCM_OUT2 0x4000 +# define TARGET_TIOCM_LOOP 0x8000 + +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +# define TARGET_TIOCPKT_DATA 0 +# define TARGET_TIOCPKT_FLUSHREAD 1 +# define TARGET_TIOCPKT_FLUSHWRITE 2 +# define TARGET_TIOCPKT_STOP 4 +# define TARGET_TIOCPKT_START 8 +# define TARGET_TIOCPKT_NOSTOP 16 +# define TARGET_TIOCPKT_DOSTOP 32 + + +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + -- cgit v1.2.3 From 7a3148a955e3350720a01f57163ab230b72aca7e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 07:13:51 +0000 Subject: Preliminary patch for Alpha Linux user mode emulation support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2600 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 31 ++++++++++++-- linux-user/main.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 36 ++++++++++++++++ linux-user/syscall_defs.h | 48 +++++++++++++++++++++- 4 files changed, 212 insertions(+), 5 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c0ea5a012..5caa44eaf 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -313,6 +313,31 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif +#ifdef TARGET_ALPHA + +#define ELF_START_MMAP (0x30000000000ULL) + +#define elf_check_arch(x) ( (x) == ELF_ARCH ) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_ALPHA + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->pc = infop->entry; + regs->ps = 8; + regs->usp = infop->start_stack; + regs->unique = infop->start_data; /* ? */ + printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", + regs->unique, infop->start_data); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +#endif /* TARGET_ALPHA */ + #ifndef ELF_PLATFORM #define ELF_PLATFORM (NULL) #endif @@ -431,11 +456,11 @@ static void bswap_shdr(struct elf_shdr *shdr) bswaptls(&shdr->sh_entsize); } -static void bswap_sym(Elf32_Sym *sym) +static void bswap_sym(struct elf_sym *sym) { bswap32s(&sym->st_name); - bswap32s(&sym->st_value); - bswap32s(&sym->st_size); + bswaptls(&sym->st_value); + bswaptls(&sym->st_size); bswap16s(&sym->st_shndx); } #endif diff --git a/linux-user/main.c b/linux-user/main.c index 0c5e6b5b4..cad10e646 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1534,6 +1534,96 @@ void cpu_loop(CPUM68KState *env) } #endif /* TARGET_M68K */ +#ifdef TARGET_ALPHA +void cpu_loop (CPUState *env) +{ + int trapnr, ret; + target_siginfo_t info; + + while (1) { + trapnr = cpu_alpha_exec (env); + + switch (trapnr) { + case EXCP_RESET: + fprintf(stderr, "Reset requested. Exit\n"); + exit(1); + break; + case EXCP_MCHK: + fprintf(stderr, "Machine check exception. Exit\n"); + exit(1); + break; + case EXCP_ARITH: + fprintf(stderr, "Arithmetic trap.\n"); + exit(1); + break; + case EXCP_HW_INTERRUPT: + fprintf(stderr, "External interrupt. Exit\n"); + exit(1); + break; + case EXCP_DFAULT: + fprintf(stderr, "MMU data fault\n"); + exit(1); + break; + case EXCP_DTB_MISS_PAL: + fprintf(stderr, "MMU data TLB miss in PALcode\n"); + exit(1); + break; + case EXCP_ITB_MISS: + fprintf(stderr, "MMU instruction TLB miss\n"); + exit(1); + break; + case EXCP_ITB_ACV: + fprintf(stderr, "MMU instruction access violation\n"); + exit(1); + break; + case EXCP_DTB_MISS_NATIVE: + fprintf(stderr, "MMU data TLB miss\n"); + exit(1); + break; + case EXCP_UNALIGN: + fprintf(stderr, "Unaligned access\n"); + exit(1); + break; + case EXCP_OPCDEC: + fprintf(stderr, "Invalid instruction\n"); + exit(1); + break; + case EXCP_FEN: + fprintf(stderr, "Floating-point not allowed\n"); + exit(1); + break; + case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1): + fprintf(stderr, "Call to PALcode\n"); + call_pal(env, (trapnr >> 6) | 0x80); + break; + case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): + fprintf(stderr, "Priviledged call to PALcode\n"); + exit(1); + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + exit (1); + } + process_pending_signals (env); + } +} +#endif /* TARGET_ALPHA */ + void usage(void) { printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n" @@ -1877,6 +1967,18 @@ int main(int argc, char **argv) } env->pc = regs->pc; } +#elif defined(TARGET_ALPHA) + { + int i; + + for(i = 0; i < 28; i++) { + env->ir[i] = ((target_ulong *)regs)[i]; + } + env->ipr[IPR_USP] = regs->usp; + env->ir[30] = regs->usp; + env->pc = regs->pc; + env->unique = regs->unique; + } #else #error unsupported target CPU #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 33778aaba..9dc0b09b0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1765,6 +1765,16 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) newsp = env->gregs[15]; new_env->gregs[15] = newsp; /* XXXXX */ +#elif defined(TARGET_ALPHA) + if (!newsp) + newsp = env->ir[30]; + new_env->ir[30] = newsp; + /* ? */ + { + int i; + for (i = 7; i < 30; i++) + new_env->ir[i] = 0; + } #else #error unsupported target CPU #endif @@ -2067,11 +2077,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } break; #endif +#ifdef TARGET_NR_creat /* not on alpha */ case TARGET_NR_creat: p = lock_user_string(arg1); ret = get_errno(creat(p, arg2)); unlock_user(p, arg1, 0); break; +#endif case TARGET_NR_link: { void * p2; @@ -2179,7 +2191,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_lseek: ret = get_errno(lseek(arg1, arg2, arg3)); break; +#ifdef TARGET_NR_getxpid + case TARGET_NR_getxpid: +#else case TARGET_NR_getpid: +#endif ret = get_errno(getpid()); break; case TARGET_NR_mount: @@ -2202,6 +2218,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(p, arg1, 0); break; #endif +#ifdef TARGET_NR_stime /* not on alpha */ case TARGET_NR_stime: { time_t host_time; @@ -2209,18 +2226,23 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(stime(&host_time)); } break; +#endif case TARGET_NR_ptrace: goto unimplemented; +#ifdef TARGET_NR_alarm /* not on alpha */ case TARGET_NR_alarm: ret = alarm(arg1); break; +#endif #ifdef TARGET_NR_oldfstat case TARGET_NR_oldfstat: goto unimplemented; #endif +#ifdef TARGET_NR_pause /* not on alpha */ case TARGET_NR_pause: ret = get_errno(pause()); break; +#endif #ifdef TARGET_NR_utime case TARGET_NR_utime: { @@ -2270,9 +2292,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(access(p, arg2)); unlock_user(p, arg1, 0); break; +#ifdef TARGET_NR_nice /* not on alpha */ case TARGET_NR_nice: ret = get_errno(nice(arg1)); break; +#endif #ifdef TARGET_NR_ftime case TARGET_NR_ftime: goto unimplemented; @@ -2346,11 +2370,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(acct(path(p))); unlock_user(p, arg1, 0); break; +#ifdef TARGET_NR_umount2 /* not on alpha */ case TARGET_NR_umount2: p = lock_user_string(arg1); ret = get_errno(umount2(p, arg2)); unlock_user(p, arg1, 0); break; +#endif #ifdef TARGET_NR_lock case TARGET_NR_lock: goto unimplemented; @@ -2389,9 +2415,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_dup2: ret = get_errno(dup2(arg1, arg2)); break; +#ifdef TARGET_NR_getppid /* not on alpha */ case TARGET_NR_getppid: ret = get_errno(getppid()); break; +#endif case TARGET_NR_getpgrp: ret = get_errno(getpgrp()); break; @@ -2474,6 +2502,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user_struct(oact, arg3, 1); } break; +#ifdef TARGET_NR_sgetmask /* not on alpha */ case TARGET_NR_sgetmask: { sigset_t cur_set; @@ -2483,6 +2512,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = target_set; } break; +#endif +#ifdef TARGET_NR_ssetmask /* not on alpha */ case TARGET_NR_ssetmask: { sigset_t set, oset, cur_set; @@ -2495,6 +2526,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = target_set; } break; +#endif #ifdef TARGET_NR_sigprocmask case TARGET_NR_sigprocmask: { @@ -3256,6 +3288,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_afs_syscall: goto unimplemented; #endif +#ifdef TARGET_NR__llseek /* Not on alpha */ case TARGET_NR__llseek: { #if defined (__x86_64__) @@ -3268,6 +3301,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif } break; +#endif case TARGET_NR_getdents: #if TARGET_LONG_SIZE != 4 goto unimplemented; @@ -3431,9 +3465,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getsid: ret = get_errno(getsid(arg1)); break; +#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */ case TARGET_NR_fdatasync: ret = get_errno(fdatasync(arg1)); break; +#endif case TARGET_NR__sysctl: /* We don't implement this, but ENODIR is always a safe return value. */ diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index e33c12beb..2989bb763 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -49,7 +49,7 @@ #define TARGET_IOC_TYPEBITS 8 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ - || defined(TARGET_M68K) + || defined(TARGET_M68K) || defined(TARGET_ALPHA) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -294,7 +294,7 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) #if defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u @@ -1203,6 +1203,50 @@ struct target_stat64 { int64_t st_blocks; }; + +#elif defined(TARGET_ALPHA) + +struct target_stat { + unsigned int st_dev; + unsigned int st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned int st_rdev; + target_long st_size; + target_ulong target_st_atime; + target_ulong target_st_mtime; + target_ulong target_st_ctime; + unsigned int st_blksize; + unsigned int st_blocks; + unsigned int st_flags; + unsigned int st_gen; +}; + +struct target_stat64 { + target_ulong st_dev; + target_ulong st_ino; + target_ulong st_rdev; + target_long st_size; + target_ulong st_blocks; + + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int st_blksize; + unsigned int st_nlink; + unsigned int __pad0; + + target_ulong target_st_atime; + target_ulong target_st_atime_nsec; + target_ulong target_st_mtime; + target_ulong target_st_mtime_nsec; + target_ulong target_st_ctime; + target_ulong target_st_ctime_nsec; + target_long __unused[3]; +}; + #else #error unsupported CPU #endif -- cgit v1.2.3 From eddf68a6ac4b5ca6eb1efbb69e50d04878a87aa5 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 07:22:49 +0000 Subject: Integrate Alpha target in Qemu core. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2601 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 7 ++++++ cpu-exec.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- dis-asm.h | 2 ++ disas.c | 3 +++ exec-all.h | 2 ++ softmmu_header.h | 4 ++++ translate-all.c | 2 ++ vl.c | 2 ++ 8 files changed, 92 insertions(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index 08d42188a..d2382857a 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -748,6 +748,13 @@ void page_unprotect_range(target_ulong data, target_ulong data_size); #define cpu_gen_code cpu_sh4_gen_code #define cpu_signal_handler cpu_sh4_signal_handler +#elif defined(TARGET_ALPHA) +#define CPUState CPUAlphaState +#define cpu_init cpu_alpha_init +#define cpu_exec cpu_alpha_exec +#define cpu_gen_code cpu_alpha_gen_code +#define cpu_signal_handler cpu_alpha_signal_handler + #else #error unsupported target CPU diff --git a/cpu-exec.c b/cpu-exec.c index 4916b1af6..0eabacd64 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -40,7 +40,8 @@ int tb_invalidated_flag; //#define DEBUG_EXEC //#define DEBUG_SIGNAL -#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K) +#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K) || \ + defined(TARGET_ALPHA) /* XXX: unify with i386 target */ void cpu_loop_exit(void) { @@ -202,6 +203,10 @@ static inline TranslationBlock *tb_find_fast(void) flags = env->sr & (SR_MD | SR_RB); cs_base = 0; /* XXXXX */ pc = env->pc; +#elif defined(TARGET_ALPHA) + flags = env->ps; + cs_base = 0; + pc = env->pc; #else #error unsupported CPU #endif @@ -291,6 +296,14 @@ int cpu_exec(CPUState *env1) return EXCP_HALTED; } } +#elif defined(TARGET_ALPHA) + if (env1->halted) { + if (env1->interrupt_request & CPU_INTERRUPT_HARD) { + env1->halted = 0; + } else { + return EXCP_HALTED; + } + } #endif cpu_single_env = env1; @@ -324,6 +337,8 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) /* XXXXX */ +#elif defined(TARGET_ALPHA) + env_to_regs(); #else #error unsupported target CPU #endif @@ -372,6 +387,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_SH4) do_interrupt(env); +#elif defined(TARGET_ALPHA) + do_interrupt(env); #endif } env->exception_index = -1; @@ -518,6 +535,10 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_SH4) /* XXXXX */ +#elif defined(TARGET_ALPHA) + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + } #endif /* Don't use the cached interupt_request value, do_interrupt may have updated the EXITTB flag. */ @@ -586,6 +607,8 @@ int cpu_exec(CPUState *env1) cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_SH4) cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_ALPHA) + cpu_dump_state(env, logfile, fprintf, 0); #else #error unsupported target CPU #endif @@ -778,6 +801,7 @@ int cpu_exec(CPUState *env1) | env->cc_dest | (env->cc_x << 4); #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) +#elif defined(TARGET_ALPHA) /* XXXXX */ #else #error unsupported target CPU @@ -1164,6 +1188,51 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* never comes here */ return 1; } + +#elif defined (TARGET_ALPHA) +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_alpha_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 diff --git a/dis-asm.h b/dis-asm.h index 73b4380b7..2b2f1d1de 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -181,6 +181,7 @@ enum bfd_architecture #define bfd_mach_sh4al_dsp 0x4d #define bfd_mach_sh5 0x50 bfd_arch_alpha, /* Dec Alpha */ +#define bfd_mach_alpha 1 bfd_arch_arm, /* Advanced Risc Machines ARM */ #define bfd_mach_arm_2 1 #define bfd_mach_arm_2a 2 @@ -377,6 +378,7 @@ 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*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/disas.c b/disas.c index 297992798..c583c1d4d 100644 --- a/disas.c +++ b/disas.c @@ -197,6 +197,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #elif defined(TARGET_SH4) disasm_info.mach = bfd_mach_sh4; print_insn = print_insn_sh; +#elif defined(TARGET_ALPHA) + disasm_info.mach = bfd_mach_alpha; + print_insn = print_insn_alpha; #else fprintf(out, "0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", code); diff --git a/exec-all.h b/exec-all.h index 73b85436c..cb8936a69 100644 --- a/exec-all.h +++ b/exec-all.h @@ -572,6 +572,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR); #elif defined (TARGET_SH4) is_user = ((env->sr & SR_MD) == 0); +#elif defined (TARGET_ALPHA) + is_user = ((env->ps >> 3) & 3); #else #error unimplemented CPU #endif diff --git a/softmmu_header.h b/softmmu_header.h index d5b3debc7..8c6cf74ad 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -63,6 +63,8 @@ #define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) #elif defined (TARGET_SH4) #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) +#elif defined (TARGET_ALPHA) +#define CPU_MEM_INDEX ((env->ps >> 3) & 3) #else #error unsupported CPU #endif @@ -82,6 +84,8 @@ #define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) #elif defined (TARGET_SH4) #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) +#elif defined (TARGET_ALPHA) +#define CPU_MEM_INDEX ((env->ps >> 3) & 3) #else #error unsupported CPU #endif diff --git a/translate-all.c b/translate-all.c index 43365478b..491b3b3d3 100644 --- a/translate-all.c +++ b/translate-all.c @@ -308,6 +308,8 @@ int cpu_restore_state(TranslationBlock *tb, env->PC = gen_opc_pc[j]; env->hflags &= ~MIPS_HFLAG_BMASK; env->hflags |= gen_opc_hflags[j]; +#elif defined(TARGET_ALPHA) + env->pc = gen_opc_pc[j]; #endif return 0; } diff --git a/vl.c b/vl.c index 487c4a8d9..355f7ff82 100644 --- a/vl.c +++ b/vl.c @@ -6707,6 +6707,8 @@ void register_machines(void) qemu_register_machine(&realview_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); +#elif defined(TARGET_ALPHA) + /* XXX: TODO */ #else #error unsupported CPU #endif -- cgit v1.2.3 From 803b3c7b4d3a74d54a3f63857ffecefd539279f9 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 5 Apr 2007 17:00:23 +0000 Subject: Fill in real SparcStation 10 values git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2602 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index ee34c1b5b..49e9c2287 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -272,7 +272,8 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->me_irq, slavio_intctl); - cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); + if (hwdef->cs_base != (target_ulong)-1) + cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); } @@ -375,21 +376,20 @@ static const struct hwdef hwdefs[] = { }, }, /* SS-10 */ - /* XXX: Replace with real values */ { - .iommu_base = 0x10000000, - .tcx_base = 0x50000000, - .cs_base = 0x6c000000, - .slavio_base = 0x71000000, - .ms_kb_base = 0x71000000, - .serial_base = 0x71100000, - .nvram_base = 0x71200000, - .fd_base = 0x71400000, - .counter_base = 0x71d00000, - .intctl_base = 0x71e00000, - .dma_base = 0x78400000, - .esp_base = 0x78800000, - .le_base = 0x78c00000, + .iommu_base = 0xe0000000, // XXX Actually at 0xfe0000000ULL (36 bits) + .tcx_base = 0x21000000, // 0xe21000000ULL, + .cs_base = -1, + .slavio_base = 0xf1000000, // 0xff1000000ULL, + .ms_kb_base = 0xf1000000, // 0xff1000000ULL, + .serial_base = 0xf1100000, // 0xff1100000ULL, + .nvram_base = 0xf1200000, // 0xff1200000ULL, + .fd_base = 0xf1700000, // 0xff1700000ULL, + .counter_base = 0xf1300000, // 0xff1300000ULL, + .intctl_base = 0xf1400000, // 0xff1400000ULL, + .dma_base = 0xf0400000, // 0xef0400000ULL, + .esp_base = 0xf0800000, // 0xef0800000ULL, + .le_base = 0xf0c00000, // 0xef0c00000ULL, .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -400,8 +400,8 @@ static const struct hwdef hwdefs[] = { .ser_irq = 15, .fd_irq = 22, .me_irq = 30, - .cs_irq = 5, - .machine_id = 0x73, + .cs_irq = -1, + .machine_id = 0x72, .intbit_to_level = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, -- cgit v1.2.3 From a4d17f1992cd04bb4c1c65e239e6921b66363fc3 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 5 Apr 2007 18:09:15 +0000 Subject: Fix co-processor branch and store ops (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2603 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 9f2d24962..53a3a674c 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1012,6 +1012,11 @@ static void disas_sparc_insn(DisasContext * dc) do_fbranch(dc, target, insn, cc); goto jmp_insn; } +#else + case 0x7: /* CBN+x */ + { + goto ncp_insn; + } #endif case 0x2: /* BN+x */ { @@ -2444,12 +2449,7 @@ static void disas_sparc_insn(DisasContext * dc) case 0x30: /* ldc */ case 0x31: /* ldcsr */ case 0x33: /* lddc */ - case 0x34: /* stc */ - case 0x35: /* stcsr */ - case 0x36: /* stdcq */ - case 0x37: /* stdc */ goto ncp_insn; - break; /* avoid warnings */ (void) &gen_op_stfa; (void) &gen_op_stdfa; @@ -2612,8 +2612,8 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; } } else if (xop > 0x33 && xop < 0x3f) { -#ifdef TARGET_SPARC64 switch (xop) { +#ifdef TARGET_SPARC64 case 0x34: /* V9 stfa */ gen_op_stfa(insn, 0, 0, 0); // XXX break; @@ -2628,12 +2628,16 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x36: /* V9 stqfa */ goto nfpu_insn; +#else + case 0x34: /* stc */ + case 0x35: /* stcsr */ + case 0x36: /* stdcq */ + case 0x37: /* stdc */ + goto ncp_insn; +#endif default: goto illegal_insn; } -#else - goto illegal_insn; -#endif } else goto illegal_insn; -- cgit v1.2.3 From 9143e59842952d89533937dba9043b7b36b76a82 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 5 Apr 2007 18:12:08 +0000 Subject: Fix stdfq op (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2604 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 3 ++- target-sparc/translate.c | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 3279cfdea..7233b8b14 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -127,6 +127,7 @@ #define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) #define FSR_FTT_IEEE_EXCP (1 << 14) #define FSR_FTT_UNIMPFPOP (3 << 14) +#define FSR_FTT_SEQ_ERROR (4 << 14) #define FSR_FTT_INVAL_FPR (6 << 14) #define FSR_FCC1 (1<<11) @@ -239,7 +240,7 @@ typedef struct CPUSPARCState { #else #define GET_FSR32(env) (env->fsr) #define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ - env->fsr = (_tmp & 0xcfc1ffff) | (env->fsr & 0x000e0000); \ + env->fsr = (_tmp & 0xcfc1dfff) | (env->fsr & 0x000e0000); \ } while (0) #endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 53a3a674c..cb11b928f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2602,8 +2602,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_stfsr(); gen_op_ldst(stf); break; +#if !defined(CONFIG_USER_ONLY) case 0x26: /* stdfq */ - goto nfpu_insn; + if (!supervisor(dc)) + goto priv_insn; + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + goto nfq_insn; +#endif case 0x27: gen_op_load_fpr_DT0(DFPREG(rd)); gen_op_ldst(stdf); @@ -2675,6 +2681,13 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); dc->is_br = 1; return; +#if !defined(CONFIG_USER_ONLY) + nfq_insn: + save_state(dc); + gen_op_fpexception_im(FSR_FTT_SEQ_ERROR); + dc->is_br = 1; + return; +#endif #ifndef TARGET_SPARC64 ncp_insn: save_state(dc); -- cgit v1.2.3 From f6b647cd9ece4f26e3c48790930818be1c3a4426 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 5 Apr 2007 18:40:23 +0000 Subject: Documentation update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2605 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + qemu-tech.texi | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index 1ecf09b2d..19a5da7fd 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,7 @@ - Monitor multiplexing to several I/O channels (Jason Wessel) - ds1225y nvram support (Herve Poussineau) - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) + - Several Sparc fixes (Aurelien Jarno, Blue Swirl) version 0.9.0: diff --git a/qemu-tech.texi b/qemu-tech.texi index ca913caf6..fc72ff1b6 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -169,11 +169,11 @@ FPU and MMU. @itemize -@item Somewhat complete SPARC V8 emulation, including privileged +@item Full SPARC V8 emulation, including privileged instructions, FPU and MMU. SPARC V9 emulation includes most privileged -instructions, FPU and I/D MMU, but misses VIS instructions. +instructions, FPU and I/D MMU, but misses most VIS instructions. -@item Can run some 32-bit SPARC Linux binaries. +@item Can run most 32-bit SPARC Linux binaries and some handcrafted 64-bit SPARC Linux binaries. @end itemize -- cgit v1.2.3 From bedb69ea0453a65a1c5a7b159ab485c542ecd15c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 20:08:21 +0000 Subject: Temporary hack for alpha user-mode emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2606 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/exec.c b/exec.c index c49c86f1a..2467b6295 100644 --- a/exec.c +++ b/exec.c @@ -64,6 +64,9 @@ #if defined(TARGET_SPARC64) #define TARGET_PHYS_ADDR_SPACE_BITS 41 +#elif defined(TARGET_ALPHA) +#define TARGET_PHYS_ADDR_SPACE_BITS 42 +#define TARGET_VIRT_ADDR_SPACE_BITS 42 #elif defined(TARGET_PPC64) #define TARGET_PHYS_ADDR_SPACE_BITS 42 #else @@ -109,7 +112,15 @@ typedef struct PhysPageDesc { } PhysPageDesc; #define L2_BITS 10 +#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS) +/* XXX: this is a temporary hack for alpha target. + * In the future, this is to be replaced by a multi-level table + * to actually be able to handle the complete 64 bits address space. + */ +#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS) +#else #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) +#endif #define L1_SIZE (1 << L1_BITS) #define L2_SIZE (1 << L2_BITS) -- cgit v1.2.3 From cf6c1b169c62e6aba5a384a2a118aef12e9608e6 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 20:46:02 +0000 Subject: Rules needed to compile linux user-mode alpha target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2607 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 + Makefile.target | 9 +++++++++ configure | 6 +++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 60e3ec197..9249c7fea 100644 --- a/Makefile +++ b/Makefile @@ -151,6 +151,7 @@ tarbin: $(bindir)/qemu-ppc \ $(bindir)/qemu-mips \ $(bindir)/qemu-mipsel \ + $(bindir)/qemu-alpha \ $(bindir)/qemu-img \ $(datadir)/bios.bin \ $(datadir)/vgabios.bin \ diff --git a/Makefile.target b/Makefile.target index 323961a73..274299185 100644 --- a/Makefile.target +++ b/Makefile.target @@ -304,6 +304,10 @@ ifeq ($(TARGET_BASE_ARCH), m68k) LIBOBJS+= helper.o endif +ifeq ($(TARGET_BASE_ARCH), alpha) +LIBOBJS+= op_helper.o helper.o alpha_palcode.o +endif + # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) @@ -605,6 +609,11 @@ sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h tc58128.o: tc58128.c endif +ifeq ($(TARGET_BASE_ARCH), alpha) +op.o: op.c op_template.h op_mem.h +op_helper.o: op_helper_mem.h +endif + $(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h %.o: %.c diff --git a/configure b/configure index a7761ca28..f8879dfc2 100755 --- a/configure +++ b/configure @@ -437,7 +437,7 @@ if test -z "$target_list" ; then fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then @@ -943,6 +943,10 @@ elif test "$target_cpu" = "m68k" ; then echo "#define TARGET_ARCH \"m68k\"" >> $config_h echo "#define TARGET_M68K 1" >> $config_h bflt="yes" +elif test "$target_cpu" = "alpha" ; then + echo "TARGET_ARCH=alpha" >> $config_mak + echo "#define TARGET_ARCH \"alpha\"" >> $config_h + echo "#define TARGET_ALPHA 1" >> $config_h else echo "Unsupported target CPU" exit 1 -- cgit v1.2.3 From bf9525e9d8e8a8f56d350f7e7fec33bd9eacb5dd Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 5 Apr 2007 21:12:28 +0000 Subject: Fix alpha target compilation on 32 bits hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2608 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/cpu.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index ca12105f2..a77af17ef 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -273,6 +273,12 @@ struct CPUAlphaState { uint64_t unique; int saved_mode; /* Used for HW_LD / HW_ST */ +#if TARGET_LONG_BITS > HOST_LONG_BITS + /* temporary fixed-point registers + * used to emulate 64 bits target on 32 bits hosts + */ + target_ulong t0, t1, t2; +#endif /* */ double ft0, ft1, ft2; -- cgit v1.2.3 From fb82fea06403d7d7b064b9ef7acc9c62dcd52850 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 5 Apr 2007 23:12:54 +0000 Subject: Clear BEV and ERL for the fake bootloader. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2609 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2f3288bd7..97707c116 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -654,8 +654,10 @@ static void main_cpu_reset(void *opaque) /* The bootload does not need to be rewritten as it is located in a read only location. The kernel location and the arguments table location does not change. */ - if (env->kernel_filename) + if (env->kernel_filename) { + env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); load_kernel (env); + } } static @@ -709,6 +711,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, env->kernel_cmdline = kernel_cmdline; env->initrd_filename = initrd_filename; kernel_entry = load_kernel(env); + env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); write_bootloader(env, bios_offset, kernel_entry); } else { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); -- cgit v1.2.3 From f7cfb2a176208d3b5139a2e792b40edf1adb43b4 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 5 Apr 2007 23:14:23 +0000 Subject: 64bit MIPS FPUs have 32 registers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2610 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 3849e503c..4b1792970 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -62,9 +62,8 @@ struct CPUMIPSState { target_ulong t2; #endif target_ulong HI, LO; - uint32_t DCR; /* ? */ /* Floating point registers */ - fpr_t fpr[16]; + fpr_t fpr[32]; #define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2]) #define FPR_FD(cpu, n) (FPR(cpu, n)->fd) #define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX]) -- cgit v1.2.3 From 1579a72ec5957297786ba5928e60571f4ab2f844 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 5 Apr 2007 23:16:25 +0000 Subject: Fix RDHWR handling. Code formatting. Don't use *_direct versions to raise exceptions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2611 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 68 +++++++++++++++------ target-mips/translate.c | 155 +++++++++++++++++++++++++----------------------- 2 files changed, 131 insertions(+), 92 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index db430a7ee..d09b8da2d 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -336,7 +336,7 @@ void op_addo (void) T0 = (int32_t)T0 + (int32_t)T1; if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) { /* operands of same sign, result different sign */ - CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); + CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); } T0 = (int32_t)T0; RETURN(); @@ -356,7 +356,7 @@ void op_subo (void) T0 = (int32_t)T0 - (int32_t)T1; if (((tmp ^ T1) & (tmp ^ T0)) >> 31) { /* operands of different sign, first operand and result different sign */ - CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); + CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); } T0 = (int32_t)T0; RETURN(); @@ -402,7 +402,7 @@ void op_daddo (void) T0 += T1; if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 63) { /* operands of same sign, result different sign */ - CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); + CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); } RETURN(); } @@ -421,7 +421,7 @@ void op_dsubo (void) T0 = (int64_t)T0 - (int64_t)T1; if (((tmp ^ T1) & (tmp ^ T0)) >> 63) { /* operands of different sign, first operand and result different sign */ - CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW); + CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); } RETURN(); } @@ -1650,7 +1650,7 @@ void op_cp0_enabled(void) { if (!(env->CP0_Status & (1 << CP0St_CU0)) && (env->hflags & MIPS_HFLAG_UM)) { - CALL_FROM_TB2(do_raise_exception_direct_err, EXCP_CpU, 0); + CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 0); } RETURN(); } @@ -1658,7 +1658,7 @@ void op_cp0_enabled(void) void op_cp1_enabled(void) { if (!(env->CP0_Status & (1 << CP0St_CU1))) { - CALL_FROM_TB2(do_raise_exception_direct_err, EXCP_CpU, 1); + CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1); } RETURN(); } @@ -2063,7 +2063,7 @@ void op_ei (void) void op_trap (void) { if (T0) { - CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP); + CALL_FROM_TB1(do_raise_exception, EXCP_TRAP); } RETURN(); } @@ -2116,37 +2116,67 @@ void op_deret (void) void op_rdhwr_cpunum(void) { - if (env->CP0_HWREna & (1 << 0)) - T0 = env->CP0_EBase & 0x2ff; + if (!(env->hflags & MIPS_HFLAG_UM) || + (env->CP0_HWREna & (1 << 0)) || + (env->CP0_Status & (1 << CP0St_CU0))) + T0 = env->CP0_EBase & 0x3ff; else - CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI); + CALL_FROM_TB1(do_raise_exception, EXCP_RI); RETURN(); } void op_rdhwr_synci_step(void) { - if (env->CP0_HWREna & (1 << 1)) - T0 = env->SYNCI_Step; + if (!(env->hflags & MIPS_HFLAG_UM) || + (env->CP0_HWREna & (1 << 1)) || + (env->CP0_Status & (1 << CP0St_CU0))) + T0 = env->SYNCI_Step; else - CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI); + CALL_FROM_TB1(do_raise_exception, EXCP_RI); RETURN(); } void op_rdhwr_cc(void) { - if (env->CP0_HWREna & (1 << 2)) - T0 = env->CP0_Count; + if (!(env->hflags & MIPS_HFLAG_UM) || + (env->CP0_HWREna & (1 << 2)) || + (env->CP0_Status & (1 << CP0St_CU0))) + T0 = env->CP0_Count; else - CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI); + CALL_FROM_TB1(do_raise_exception, EXCP_RI); RETURN(); } void op_rdhwr_ccres(void) { - if (env->CP0_HWREna & (1 << 3)) - T0 = env->CCRes; + if (!(env->hflags & MIPS_HFLAG_UM) || + (env->CP0_HWREna & (1 << 3)) || + (env->CP0_Status & (1 << CP0St_CU0))) + T0 = env->CCRes; else - CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI); + CALL_FROM_TB1(do_raise_exception, EXCP_RI); + RETURN(); +} + +void op_rdhwr_unimpl30(void) +{ + if (!(env->hflags & MIPS_HFLAG_UM) || + (env->CP0_HWREna & (1 << 30)) || + (env->CP0_Status & (1 << CP0St_CU0))) + T0 = 0; + else + CALL_FROM_TB1(do_raise_exception, EXCP_RI); + RETURN(); +} + +void op_rdhwr_unimpl31(void) +{ + if (!(env->hflags & MIPS_HFLAG_UM) || + (env->CP0_HWREna & (1 << 31)) || + (env->CP0_Status & (1 << CP0St_CU0))) + T0 = 0; + else + CALL_FROM_TB1(do_raise_exception, EXCP_RI); RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index 74bb42d20..816b91e1c 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1762,7 +1762,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 4: switch (sel) { @@ -1776,7 +1776,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } + } break; case 5: switch (sel) { @@ -1790,7 +1790,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 6: switch (sel) { @@ -1820,7 +1820,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) // break; default: goto die; - } + } break; case 7: switch (sel) { @@ -1830,7 +1830,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 8: switch (sel) { @@ -1861,7 +1861,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 11: switch (sel) { @@ -1914,7 +1914,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 15: switch (sel) { @@ -2521,7 +2521,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 16: switch (sel) { @@ -2955,7 +2955,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; default: goto die; - } + } break; case 4: switch (sel) { @@ -4703,83 +4703,92 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_SPECIAL3: - op1 = MASK_SPECIAL3(ctx->opcode); - switch (op1) { - case OPC_EXT: - case OPC_INS: - gen_bitops(ctx, op1, rt, rs, sa, rd); + op1 = MASK_SPECIAL3(ctx->opcode); + switch (op1) { + case OPC_EXT: + case OPC_INS: + gen_bitops(ctx, op1, rt, rs, sa, rd); + break; + case OPC_BSHFL: + op2 = MASK_BSHFL(ctx->opcode); + switch (op2) { + case OPC_WSBH: + GEN_LOAD_REG_TN(T1, rt); + gen_op_wsbh(); + break; + case OPC_SEB: + GEN_LOAD_REG_TN(T1, rt); + gen_op_seb(); + break; + case OPC_SEH: + GEN_LOAD_REG_TN(T1, rt); + gen_op_seh(); + break; + default: /* Invalid */ + MIPS_INVAL("bshfl"); + generate_exception(ctx, EXCP_RI); + break; + } + GEN_STORE_TN_REG(rd, T0); break; - case OPC_BSHFL: - op2 = MASK_BSHFL(ctx->opcode); - switch (op2) { - case OPC_WSBH: - GEN_LOAD_REG_TN(T1, rt); - gen_op_wsbh(); + case OPC_RDHWR: + switch (rd) { + case 0: + gen_op_rdhwr_cpunum(); break; - case OPC_SEB: - GEN_LOAD_REG_TN(T1, rt); - gen_op_seb(); + case 1: + gen_op_rdhwr_synci_step(); break; - case OPC_SEH: - GEN_LOAD_REG_TN(T1, rt); - gen_op_seh(); + case 2: + gen_op_rdhwr_cc(); break; - default: /* Invalid */ - MIPS_INVAL("bshfl"); - generate_exception(ctx, EXCP_RI); + case 3: + gen_op_rdhwr_ccres(); break; - } - GEN_STORE_TN_REG(rd, T0); - break; - case OPC_RDHWR: - switch (rd) { - case 0: - gen_op_rdhwr_cpunum(); - break; - case 1: - gen_op_rdhwr_synci_step(); - break; - case 2: - gen_op_rdhwr_cc(); - break; - case 3: - gen_op_rdhwr_ccres(); - break; + case 29: #if defined (CONFIG_USER_ONLY) - case 29: - gen_op_tls_value (); - GEN_STORE_TN_REG(rt, T0); - break; + gen_op_tls_value (); +#else + generate_exception(ctx, EXCP_RI); #endif - default: /* Invalid */ - MIPS_INVAL("rdhwr"); - generate_exception(ctx, EXCP_RI); - break; - } - GEN_STORE_TN_REG(rt, T0); - break; + break; + case 30: + /* Implementation dependent */; + gen_op_rdhwr_unimpl30(); + break; + case 31: + /* Implementation dependent */; + gen_op_rdhwr_unimpl31(); + break; + default: /* Invalid */ + MIPS_INVAL("rdhwr"); + generate_exception(ctx, EXCP_RI); + break; + } + GEN_STORE_TN_REG(rt, T0); + break; #ifdef TARGET_MIPS64 - case OPC_DEXTM ... OPC_DEXT: - case OPC_DINSM ... OPC_DINS: - gen_bitops(ctx, op1, rt, rs, sa, rd); + case OPC_DEXTM ... OPC_DEXT: + case OPC_DINSM ... OPC_DINS: + gen_bitops(ctx, op1, rt, rs, sa, rd); break; - case OPC_DBSHFL: - op2 = MASK_DBSHFL(ctx->opcode); - switch (op2) { - case OPC_DSBH: - GEN_LOAD_REG_TN(T1, rt); - gen_op_dsbh(); - break; - case OPC_DSHD: - GEN_LOAD_REG_TN(T1, rt); - gen_op_dshd(); - break; + case OPC_DBSHFL: + op2 = MASK_DBSHFL(ctx->opcode); + switch (op2) { + case OPC_DSBH: + GEN_LOAD_REG_TN(T1, rt); + gen_op_dsbh(); + break; + case OPC_DSHD: + GEN_LOAD_REG_TN(T1, rt); + gen_op_dshd(); + break; default: /* Invalid */ MIPS_INVAL("dbshfl"); generate_exception(ctx, EXCP_RI); break; - } - GEN_STORE_TN_REG(rd, T0); + } + GEN_STORE_TN_REG(rd, T0); #endif default: /* Invalid */ MIPS_INVAL("special3"); -- cgit v1.2.3 From 3529b538ce91df31b7300ce2fbd838a2ca36e1fc Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 5 Apr 2007 23:17:40 +0000 Subject: Fix disabling of the Cause register for R2. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2612 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_timer.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 055ee5b89..9128cbff7 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -22,14 +22,11 @@ uint32_t cpu_mips_get_count (CPUState *env) 100 * 1000 * 1000, ticks_per_sec); } -static void cpu_mips_update_count (CPUState *env, uint32_t count, - uint32_t compare) +void cpu_mips_store_count (CPUState *env, uint32_t count) { uint64_t now, next; uint32_t tmp; - - if (env->CP0_Cause & (1 << CP0Ca_DC)) - return; + uint32_t compare = env->CP0_Compare; tmp = count; if (count == compare) @@ -52,14 +49,18 @@ static void cpu_mips_update_count (CPUState *env, uint32_t count, qemu_mod_timer(env->timer, next); } -void cpu_mips_store_count (CPUState *env, uint32_t value) +static void cpu_mips_update_count (CPUState *env, uint32_t count) { - cpu_mips_update_count(env, value, env->CP0_Compare); + if (env->CP0_Cause & (1 << CP0Ca_DC)) + return; + + cpu_mips_store_count(env, count); } void cpu_mips_store_compare (CPUState *env, uint32_t value) { - cpu_mips_update_count(env, cpu_mips_get_count(env), value); + env->CP0_Compare = value; + cpu_mips_update_count(env, cpu_mips_get_count(env)); if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) env->CP0_Cause &= ~(1 << CP0Ca_TI); cpu_mips_irq_request(env, 7, 0); @@ -75,7 +76,7 @@ static void mips_timer_cb (void *opaque) fprintf(logfile, "%s\n", __func__); } #endif - cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); + cpu_mips_update_count(env, cpu_mips_get_count(env)); if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) env->CP0_Cause |= 1 << CP0Ca_TI; cpu_mips_irq_request(env, 7, 1); @@ -85,6 +86,5 @@ void cpu_mips_clock_init (CPUState *env) { env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); env->CP0_Compare = 0; - cpu_mips_update_count(env, 1, 0); + cpu_mips_update_count(env, 1); } - -- cgit v1.2.3 From acd858d91f73fe310627e2b92a8fdd529ec06ade Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 5 Apr 2007 23:18:13 +0000 Subject: Handle EBase properly. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2613 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 2572050bb..dc5181467 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -398,7 +398,7 @@ void do_interrupt (CPUState *env) if (env->CP0_Status & (1 << CP0St_BEV)) { env->PC = (int32_t)0xBFC00200; } else { - env->PC = (int32_t)0x80000000; + env->PC = (int32_t)(env->CP0_EBase & ~0x3ff); } env->PC += offset; env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); -- cgit v1.2.3 From 5a63bcb2d27675a3fc2c5bc8a8c323e5c756e749 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 5 Apr 2007 23:20:05 +0000 Subject: Fix rotr immediate ops, mask shift/rotate arguments to their allowed size. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2614 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 19 +++----- target-mips/op_helper.c | 6 +-- target-mips/translate.c | 126 +++++++++++++++++++++++++++++++++++------------- 3 files changed, 103 insertions(+), 48 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index d09b8da2d..d440896f3 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -493,19 +493,19 @@ void op_xor (void) void op_sll (void) { - T0 = (int32_t)((uint32_t)T0 << (uint32_t)T1); + T0 = (int32_t)((uint32_t)T0 << T1); RETURN(); } void op_sra (void) { - T0 = (int32_t)((int32_t)T0 >> (uint32_t)T1); + T0 = (int32_t)((int32_t)T0 >> T1); RETURN(); } void op_srl (void) { - T0 = (int32_t)((uint32_t)T0 >> (uint32_t)T1); + T0 = (int32_t)((uint32_t)T0 >> T1); RETURN(); } @@ -514,10 +514,9 @@ void op_rotr (void) target_ulong tmp; if (T1) { - tmp = (int32_t)((uint32_t)T0 << (0x20 - (uint32_t)T1)); - T0 = (int32_t)((uint32_t)T0 >> (uint32_t)T1) | tmp; - } else - T0 = T1; + tmp = (int32_t)((uint32_t)T0 << (0x20 - T1)); + T0 = (int32_t)((uint32_t)T0 >> T1) | tmp; + } RETURN(); } @@ -707,8 +706,7 @@ void op_drotr (void) if (T1) { tmp = T0 << (0x40 - T1); T0 = (T0 >> T1) | tmp; - } else - T0 = T1; + } RETURN(); } @@ -719,8 +717,7 @@ void op_drotr32 (void) if (T1) { tmp = T0 << (0x40 - (32 + T1)); T0 = (T0 >> (32 + T1)) | tmp; - } else - T0 = T1; + } RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 7b6442e8f..ba02f0d84 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -120,8 +120,7 @@ void do_drotr (void) if (T1) { tmp = T0 << (0x40 - T1); T0 = (T0 >> T1) | tmp; - } else - T0 = T1; + } } void do_drotr32 (void) @@ -131,8 +130,7 @@ void do_drotr32 (void) if (T1) { tmp = T0 << (0x40 - (32 + T1)); T0 = (T0 >> (32 + T1)) | tmp; - } else - T0 = T1; + } } void do_dsllv (void) diff --git a/target-mips/translate.c b/target-mips/translate.c index 816b91e1c..7b7c464fb 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -849,18 +849,43 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, MIPS_DEBUG("NOP"); return; } - if (opc == OPC_ADDI || opc == OPC_ADDIU || - opc == OPC_DADDI || opc == OPC_DADDIU || - opc == OPC_SLTI || opc == OPC_SLTIU) + uimm = (uint16_t)imm; + switch (opc) { + case OPC_ADDI: + case OPC_ADDIU: +#ifdef TARGET_MIPS64 + case OPC_DADDI: + case OPC_DADDIU: +#endif + case OPC_SLTI: + case OPC_SLTIU: uimm = (int32_t)imm; /* Sign extend to 32 bits */ - else - uimm = (uint16_t)imm; - if (opc != OPC_LUI) { + /* Fall through. */ + case OPC_ANDI: + case OPC_ORI: + case OPC_XORI: GEN_LOAD_REG_TN(T0, rs); GEN_LOAD_IMM_TN(T1, uimm); - } else { - uimm = uimm << 16; + break; + case OPC_LUI: + uimm <<= 16; GEN_LOAD_IMM_TN(T0, uimm); + break; + case OPC_SLL: + case OPC_SRA: + case OPC_SRL: +#ifdef TARGET_MIPS64 + case OPC_DSLL: + case OPC_DSRA: + case OPC_DSRL: + case OPC_DSLL32: + case OPC_DSRA32: + case OPC_DSRL32: +#endif + uimm &= 0x1f; + GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_IMM_TN(T1, uimm); + break; } switch (opc) { case OPC_ADDI: @@ -915,13 +940,20 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, opn = "sra"; break; case OPC_SRL: - if ((ctx->opcode >> 21) & 1) { - gen_op_rotr(); - opn = "rotr"; - } else { + switch ((ctx->opcode >> 21) & 0x1f) { + case 0: gen_op_srl(); opn = "srl"; - } + break; + case 1: + gen_op_rotr(); + opn = "rotr"; + break; + default: + MIPS_INVAL("invalid srl flag"); + generate_exception(ctx, EXCP_RI); + break; + } break; #ifdef TARGET_MIPS64 case OPC_DSLL: @@ -933,13 +965,20 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, opn = "dsra"; break; case OPC_DSRL: - if ((ctx->opcode >> 21) & 1) { - gen_op_drotr(); - opn = "drotr"; - } else { + switch ((ctx->opcode >> 21) & 0x1f) { + case 0: gen_op_dsrl(); opn = "dsrl"; - } + break; + case 1: + gen_op_drotr(); + opn = "drotr"; + break; + default: + MIPS_INVAL("invalid dsrl flag"); + generate_exception(ctx, EXCP_RI); + break; + } break; case OPC_DSLL32: gen_op_dsll32(); @@ -950,13 +989,20 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, opn = "dsra32"; break; case OPC_DSRL32: - if ((ctx->opcode >> 21) & 1) { - gen_op_drotr32(); - opn = "drotr32"; - } else { + switch ((ctx->opcode >> 21) & 0x1f) { + case 0: gen_op_dsrl32(); opn = "dsrl32"; - } + break; + case 1: + gen_op_drotr32(); + opn = "drotr32"; + break; + default: + MIPS_INVAL("invalid dsrl32 flag"); + generate_exception(ctx, EXCP_RI); + break; + } break; #endif default: @@ -1068,13 +1114,20 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, opn = "srav"; break; case OPC_SRLV: - if ((ctx->opcode >> 6) & 1) { - gen_op_rotrv(); - opn = "rotrv"; - } else { + switch ((ctx->opcode >> 6) & 0x1f) { + case 0: gen_op_srlv(); opn = "srlv"; - } + break; + case 1: + gen_op_rotrv(); + opn = "rotrv"; + break; + default: + MIPS_INVAL("invalid srlv flag"); + generate_exception(ctx, EXCP_RI); + break; + } break; #ifdef TARGET_MIPS64 case OPC_DSLLV: @@ -1086,13 +1139,20 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, opn = "dsrav"; break; case OPC_DSRLV: - if ((ctx->opcode >> 6) & 1) { - gen_op_drotrv(); - opn = "drotrv"; - } else { + switch ((ctx->opcode >> 6) & 0x1f) { + case 0: gen_op_dsrlv(); opn = "dsrlv"; - } + break; + case 1: + gen_op_drotrv(); + opn = "drotrv"; + break; + default: + MIPS_INVAL("invalid dsrlv flag"); + generate_exception(ctx, EXCP_RI); + break; + } break; #endif default: -- cgit v1.2.3 From c53f4a62e3a87b4200d7245ae273a4d187394779 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 5 Apr 2007 23:21:37 +0000 Subject: fix branch delay slot cornercases. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2615 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 2 +- target-mips/translate.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index dc5181467..0cda1ef54 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -387,7 +387,6 @@ void do_interrupt (CPUState *env) come back to the jump. */ env->CP0_EPC = env->PC - 4; env->CP0_Cause |= (1 << CP0Ca_BD); - env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_EPC = env->PC; env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -395,6 +394,7 @@ void do_interrupt (CPUState *env) env->CP0_Status |= (1 << CP0St_EXL); env->hflags &= ~MIPS_HFLAG_UM; } + env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { env->PC = (int32_t)0xBFC00200; } else { diff --git a/target-mips/translate.c b/target-mips/translate.c index 7b7c464fb..8da8cc403 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1640,6 +1640,10 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, likely: ctx->hflags |= MIPS_HFLAG_BL; break; + default: + MIPS_INVAL("conditional branch/jump"); + generate_exception(ctx, EXCP_RI); + return; } gen_op_set_bcond(); } @@ -1650,7 +1654,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, gen_op_set_T0(ctx->pc + 8); gen_op_store_T0_gpr(blink); } - return; } /* special3 bitfield operations */ @@ -5053,7 +5056,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; } if (ctx->hflags & MIPS_HFLAG_BMASK) { - int hflags = ctx->hflags; + int hflags = ctx->hflags & MIPS_HFLAG_BMASK; /* Branches completion */ ctx->hflags &= ~MIPS_HFLAG_BMASK; ctx->bstate = BS_BRANCH; -- cgit v1.2.3 From 74aa04299641a376eba3bc68baaf59f8680a1664 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 6 Apr 2007 06:40:51 +0000 Subject: Code provision for 64 bits linux user-mode targets support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2616 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ppc64/syscall.h | 130 +++++++++++++++++++ linux-user/ppc64/syscall_nr.h | 258 +++++++++++++++++++++++++++++++++++++ linux-user/ppc64/termbits.h | 235 ++++++++++++++++++++++++++++++++++ linux-user/x86_64/syscall.h | 92 ++++++++++++++ linux-user/x86_64/syscall_nr.h | 280 +++++++++++++++++++++++++++++++++++++++++ linux-user/x86_64/termbits.h | 247 ++++++++++++++++++++++++++++++++++++ 6 files changed, 1242 insertions(+) create mode 100644 linux-user/ppc64/syscall.h create mode 100644 linux-user/ppc64/syscall_nr.h create mode 100644 linux-user/ppc64/termbits.h create mode 100644 linux-user/x86_64/syscall.h create mode 100644 linux-user/x86_64/syscall_nr.h create mode 100644 linux-user/x86_64/termbits.h diff --git a/linux-user/ppc64/syscall.h b/linux-user/ppc64/syscall.h new file mode 100644 index 000000000..eea8a7c9a --- /dev/null +++ b/linux-user/ppc64/syscall.h @@ -0,0 +1,130 @@ +/* + * PPC emulation for qemu: syscall definitions. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * 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 + */ + +/* XXX: ABSOLUTELY BUGGY: + * for now, this is quite just a cut-and-paste from i386 target... + */ + +/* default linux values for the selectors */ +#define __USER_DS (1) + +struct target_pt_regs { + unsigned long gpr[32]; + unsigned long nip; + unsigned long msr; + unsigned long orig_gpr3; /* Used for restarting system calls */ + unsigned long ctr; + unsigned long link; + unsigned long xer; + unsigned long ccr; + unsigned long mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + unsigned long trap; /* Reason for being here */ + unsigned long dar; /* Fault registers */ + unsigned long dsisr; + unsigned long result; /* Result of a system call */ +}; + +/* ioctls */ +struct target_revectored_struct { + target_ulong __map[8]; /* 256 bits */ +}; + +/* + * flags masks + */ + +/* ipcs */ + +#define TARGET_SEMOP 1 +#define TARGET_SEMGET 2 +#define TARGET_SEMCTL 3 +#define TARGET_MSGSND 11 +#define TARGET_MSGRCV 12 +#define TARGET_MSGGET 13 +#define TARGET_MSGCTL 14 +#define TARGET_SHMAT 21 +#define TARGET_SHMDT 22 +#define TARGET_SHMGET 23 +#define TARGET_SHMCTL 24 + +struct target_msgbuf { + int mtype; + char mtext[1]; +}; + +struct target_ipc_kludge { + unsigned int msgp; /* Really (struct msgbuf *) */ + int msgtyp; +}; + +struct target_ipc_perm { + int key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +struct target_msqid_ds { + struct target_ipc_perm msg_perm; + unsigned int msg_first; /* really struct target_msg* */ + unsigned int msg_last; /* really struct target_msg* */ + unsigned int msg_stime; /* really target_time_t */ + unsigned int msg_rtime; /* really target_time_t */ + unsigned int msg_ctime; /* really target_time_t */ + unsigned int wwait; /* really struct wait_queue* */ + unsigned int rwait; /* really struct wait_queue* */ + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + unsigned short msg_lspid; + unsigned short msg_lrpid; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; + int shm_segsz; + unsigned int shm_atime; /* really target_time_t */ + unsigned int shm_dtime; /* really target_time_t */ + unsigned int shm_ctime; /* really target_time_t */ + unsigned short shm_cpid; + unsigned short shm_lpid; + short shm_nattch; + unsigned short shm_npages; + unsigned long *shm_pages; + void *attaches; /* really struct shm_desc * */ +}; + +#define TARGET_IPC_RMID 0 +#define TARGET_IPC_SET 1 +#define TARGET_IPC_STAT 2 + +union target_semun { + int val; + unsigned int buf; /* really struct semid_ds * */ + unsigned int array; /* really unsigned short * */ + unsigned int __buf; /* really struct seminfo * */ + unsigned int __pad; /* really void* */ +}; + +#define UNAME_MACHINE "ppc" diff --git a/linux-user/ppc64/syscall_nr.h b/linux-user/ppc64/syscall_nr.h new file mode 100644 index 000000000..b97189a2e --- /dev/null +++ b/linux-user/ppc64/syscall_nr.h @@ -0,0 +1,258 @@ +/* + * This file contains the system call numbers. + */ +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown32 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid32 23 +#define TARGET_NR_getuid32 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid32 46 +#define TARGET_NR_getgid32 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid32 49 +#define TARGET_NR_getegid32 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid32 70 +#define TARGET_NR_setregid32 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups32 80 +#define TARGET_NR_setgroups32 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown32 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid32 138 +#define TARGET_NR_setfsgid32 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid32 164 +#define TARGET_NR_getresuid32 165 +#define TARGET_NR_query_module 166 +#define TARGET_NR_poll 167 +#define TARGET_NR_nfsservctl 168 +#define TARGET_NR_setresgid32 169 +#define TARGET_NR_getresgid32 170 +#define TARGET_NR_prctl 171 +#define TARGET_NR_rt_sigreturn 172 +#define TARGET_NR_rt_sigaction 173 +#define TARGET_NR_rt_sigprocmask 174 +#define TARGET_NR_rt_sigpending 175 +#define TARGET_NR_rt_sigtimedwait 176 +#define TARGET_NR_rt_sigqueueinfo 177 +#define TARGET_NR_rt_sigsuspend 178 +#define TARGET_NR_pread64 179 +#define TARGET_NR_pwrite64 180 +#define TARGET_NR_chown32 181 +#define TARGET_NR_getcwd 182 +#define TARGET_NR_capget 183 +#define TARGET_NR_capset 184 +#define TARGET_NR_sigaltstack 185 +#define TARGET_NR_sendfile 186 +#define TARGET_NR_getpmsg 187 /* some people actually want streams */ +#define TARGET_NR_putpmsg 188 /* some people actually want streams */ +#define TARGET_NR_vfork 189 +#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */ +#define TARGET_NR_readahead 191 +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_pciconfig_read 198 +#define TARGET_NR_pciconfig_write 199 +#define TARGET_NR_pciconfig_iobase 200 +#define TARGET_NR_multiplexer 201 +#define TARGET_NR_getdents64 202 +#define TARGET_NR_pivot_root 203 +#define TARGET_NR_fcntl64 204 +#define TARGET_NR_madvise 205 +#define TARGET_NR_mincore 206 +#define TARGET_NR_gettid 207 +#define TARGET_NR_tkill 208 +#define TARGET_NR_setxattr 209 +#define TARGET_NR_lsetxattr 210 +#define TARGET_NR_fsetxattr 211 +#define TARGET_NR_getxattr 212 +#define TARGET_NR_lgetxattr 213 +#define TARGET_NR_fgetxattr 214 +#define TARGET_NR_listxattr 215 +#define TARGET_NR_llistxattr 216 +#define TARGET_NR_flistxattr 217 +#define TARGET_NR_removexattr 218 +#define TARGET_NR_lremovexattr 219 +#define TARGET_NR_fremovexattr 220 +#define TARGET_NR_futex 221 +#define TARGET_NR_sched_setaffinity 222 +#define TARGET_NR_sched_getaffinity 223 +/* 224 currently unused */ +#define TARGET_NR_tuxcall 225 +#define TARGET_NR_sendfile64 226 +#define TARGET_NR_io_setup 227 +#define TARGET_NR_io_destroy 228 +#define TARGET_NR_io_getevents 229 +#define TARGET_NR_io_submit 230 +#define TARGET_NR_io_cancel 231 +#define TARGET_NR_set_tid_address 232 +#define TARGET_NR_fadvise64 233 +#define TARGET_NR_exit_group 234 +#define TARGET_NR_lookup_dcookie 235 +#define TARGET_NR_epoll_create 236 +#define TARGET_NR_epoll_ctl 237 +#define TARGET_NR_epoll_wait 238 +#define TARGET_NR_remap_file_pages 239 +#define TARGET_NR_timer_create 240 +#define TARGET_NR_timer_settime 241 +#define TARGET_NR_timer_gettime 242 +#define TARGET_NR_timer_getoverrun 243 +#define TARGET_NR_timer_delete 244 +#define TARGET_NR_clock_settime 245 +#define TARGET_NR_clock_gettime 246 +#define TARGET_NR_clock_getres 247 +#define TARGET_NR_clock_nanosleep 248 +#define TARGET_NR_swapcontext 249 +#define TARGET_NR_tgkill 250 +#define TARGET_NR_utimes 251 +#define TARGET_NR_statfs64 252 +#define TARGET_NR_fstatfs64 253 +#define TARGET_NR_fadvise64_64 254 diff --git a/linux-user/ppc64/termbits.h b/linux-user/ppc64/termbits.h new file mode 100644 index 000000000..6326747ee --- /dev/null +++ b/linux-user/ppc64/termbits.h @@ -0,0 +1,235 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ + unsigned int c_ispeed; /* input speed */ + unsigned int c_ospeed; /* output speed */ +}; + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VMIN 5 +#define TARGET_VEOL 6 +#define TARGET_VTIME 7 +#define TARGET_VEOL2 8 +#define TARGET_VSWTC 9 + +#define TARGET_VWERASE 10 +#define TARGET_VREPRINT 11 +#define TARGET_VSUSP 12 +#define TARGET_VSTART 13 +#define TARGET_VSTOP 14 +#define TARGET_VLNEXT 15 +#define TARGET_VDISCARD 16 + +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IXON 0001000 +#define TARGET_IXOFF 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IUCLC 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_ONLCR 0000002 +#define TARGET_OLCUC 0000004 + +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 + +#define TARGET_OFILL 00000100 +#define TARGET_OFDEL 00000200 +#define TARGET_NLDLY 00001400 +#define TARGET_NL0 00000000 +#define TARGET_NL1 00000400 +#define TARGET_NL2 00001000 +#define TARGET_NL3 00001400 +#define TARGET_TABDLY 00006000 +#define TARGET_TAB0 00000000 +#define TARGET_TAB1 00002000 +#define TARGET_TAB2 00004000 +#define TARGET_TAB3 00006000 +#define TARGET_CRDLY 00030000 +#define TARGET_CR0 00000000 +#define TARGET_CR1 00010000 +#define TARGET_CR2 00020000 +#define TARGET_CR3 00030000 +#define TARGET_FFDLY 00040000 +#define TARGET_FF0 00000000 +#define TARGET_FF1 00040000 +#define TARGET_BSDLY 00100000 +#define TARGET_BS0 00000000 +#define TARGET_BS1 00100000 +#define TARGET_VTDLY 00200000 +#define TARGET_VT0 00000000 +#define TARGET_VT1 00200000 +#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0000377 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CBAUDEX 0000000 +#define TARGET_B57600 00020 +#define TARGET_B115200 00021 +#define TARGET_B230400 00022 +#define TARGET_B460800 00023 +#define TARGET_B500000 00024 +#define TARGET_B576000 00025 +#define TARGET_B921600 00026 +#define TARGET_B1000000 00027 +#define TARGET_B1152000 00030 +#define TARGET_B1500000 00031 +#define TARGET_B2000000 00032 +#define TARGET_B2500000 00033 +#define TARGET_B3000000 00034 +#define TARGET_B3500000 00035 +#define TARGET_B4000000 00036 + +#define TARGET_CSIZE 00001400 +#define TARGET_CS5 00000000 +#define TARGET_CS6 00000400 +#define TARGET_CS7 00001000 +#define TARGET_CS8 00001400 + +#define TARGET_CSTOPB 00002000 +#define TARGET_CREAD 00004000 +#define TARGET_PARENB 00010000 +#define TARGET_PARODD 00020000 +#define TARGET_HUPCL 00040000 + +#define TARGET_CLOCAL 00100000 +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000080 +#define TARGET_ICANON 0x00000100 +#define TARGET_XCASE 0x00004000 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000002 +#define TARGET_ECHOK 0x00000004 +#define TARGET_ECHONL 0x00000010 +#define TARGET_NOFLSH 0x80000000 +#define TARGET_TOSTOP 0x00400000 +#define TARGET_ECHOCTL 0x00000040 +#define TARGET_ECHOPRT 0x00000020 +#define TARGET_ECHOKE 0x00000001 +#define TARGET_FLUSHO 0x00800000 +#define TARGET_PENDIN 0x20000000 +#define TARGET_IEXTEN 0x00000400 + +/* ioctls */ + +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD +//#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) + +#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios) + +#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio) + +#define TARGET_TCSBRK TARGET_IO('t', 29) +#define TARGET_TCXONC TARGET_IO('t', 30) +#define TARGET_TCFLSH TARGET_IO('t', 31) + +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars) +#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars) +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E + +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 + +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 + +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ + diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h new file mode 100644 index 000000000..2f87dc964 --- /dev/null +++ b/linux-user/x86_64/syscall.h @@ -0,0 +1,92 @@ +#define __USER_CS (0x33) +#define __USER_DS (0x2B) + +struct target_pt_regs { + target_ulong r15; + target_ulong r14; + target_ulong r13; + target_ulong r12; + target_ulong rbp; + target_ulong rbx; +/* arguments: non interrupts/non tracing syscalls only save upto here*/ + target_ulong r11; + target_ulong r10; + target_ulong r9; + target_ulong r8; + target_ulong rax; + target_ulong rcx; + target_ulong rdx; + target_ulong rsi; + target_ulong rdi; + target_ulong orig_rax; +/* end of arguments */ +/* cpu exception frame or undefined */ + target_ulong rip; + target_ulong cs; + target_ulong eflags; + target_ulong rsp; + target_ulong ss; +/* top of stack page */ +}; + +/* Maximum number of LDT entries supported. */ +#define TARGET_LDT_ENTRIES 8192 +/* The size of each LDT entry. */ +#define TARGET_LDT_ENTRY_SIZE 8 + +#define TARGET_GDT_ENTRY_TLS_ENTRIES 3 +#define TARGET_GDT_ENTRY_TLS_MIN 12 +#define TARGET_GDT_ENTRY_TLS_MAX 14 + +#if 0 // Redefine this +struct target_modify_ldt_ldt_s { + unsigned int entry_number; + target_ulong base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int lm:1; +}; +#else +struct target_modify_ldt_ldt_s { + unsigned int entry_number; + target_ulong base_addr; + unsigned int limit; + unsigned int flags; +}; +#endif + +struct target_ipc64_perm +{ + int key; + uint32_t uid; + uint32_t gid; + uint32_t cuid; + uint32_t cgid; + unsigned short mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + target_ulong __unused1; + target_ulong __unused2; +}; + +struct target_msqid64_ds { + struct target_ipc64_perm msg_perm; + unsigned int msg_stime; /* last msgsnd time */ + unsigned int msg_rtime; /* last msgrcv time */ + unsigned int msg_ctime; /* last change time */ + target_ulong msg_cbytes; /* current number of bytes on queue */ + target_ulong msg_qnum; /* number of messages in queue */ + target_ulong msg_qbytes; /* max number of bytes on queue */ + unsigned int msg_lspid; /* pid of last msgsnd */ + unsigned int msg_lrpid; /* last receive pid */ + target_ulong __unused4; + target_ulong __unused5; +}; + +#define UNAME_MACHINE "x86_64" diff --git a/linux-user/x86_64/syscall_nr.h b/linux-user/x86_64/syscall_nr.h new file mode 100644 index 000000000..e1a8ca20b --- /dev/null +++ b/linux-user/x86_64/syscall_nr.h @@ -0,0 +1,280 @@ +#define TARGET_NR_read 0 +#define TARGET_NR_write 1 +#define TARGET_NR_open 2 +#define TARGET_NR_close 3 +#define TARGET_NR_stat 4 +#define TARGET_NR_fstat 5 +#define TARGET_NR_lstat 6 +#define TARGET_NR_poll 7 +#define TARGET_NR_lseek 8 +#define TARGET_NR_mmap 9 +#define TARGET_NR_mprotect 10 +#define TARGET_NR_munmap 11 +#define TARGET_NR_brk 12 +#define TARGET_NR_rt_sigaction 13 +#define TARGET_NR_rt_sigprocmask 14 +#define TARGET_NR_rt_sigreturn 15 +#define TARGET_NR_ioctl 16 +#define TARGET_NR_pread64 17 +#define TARGET_NR_pwrite64 18 +#define TARGET_NR_readv 19 +#define TARGET_NR_writev 20 +#define TARGET_NR_access 21 +#define TARGET_NR_pipe 22 +#define TARGET_NR_select 23 +#define TARGET_NR_sched_yield 24 +#define TARGET_NR_mremap 25 +#define TARGET_NR_msync 26 +#define TARGET_NR_mincore 27 +#define TARGET_NR_madvise 28 +#define TARGET_NR_shmget 29 +#define TARGET_NR_shmat 30 +#define TARGET_NR_shmctl 31 +#define TARGET_NR_dup 32 +#define TARGET_NR_dup2 33 +#define TARGET_NR_pause 34 +#define TARGET_NR_nanosleep 35 +#define TARGET_NR_getitimer 36 +#define TARGET_NR_alarm 37 +#define TARGET_NR_setitimer 38 +#define TARGET_NR_getpid 39 +#define TARGET_NR_sendfile 40 +#define TARGET_NR_socket 41 +#define TARGET_NR_connect 42 +#define TARGET_NR_accept 43 +#define TARGET_NR_sendto 44 +#define TARGET_NR_recvfrom 45 +#define TARGET_NR_sendmsg 46 +#define TARGET_NR_recvmsg 47 +#define TARGET_NR_shutdown 48 +#define TARGET_NR_bind 49 +#define TARGET_NR_listen 50 +#define TARGET_NR_getsockname 51 +#define TARGET_NR_getpeername 52 +#define TARGET_NR_socketpair 53 +#define TARGET_NR_setsockopt 54 +#define TARGET_NR_getsockopt 55 +#define TARGET_NR_clone 56 +#define TARGET_NR_fork 57 +#define TARGET_NR_vfork 58 +#define TARGET_NR_execve 59 +#define TARGET_NR_exit 60 +#define TARGET_NR_wait4 61 +#define TARGET_NR_kill 62 +#define TARGET_NR_uname 63 +#define TARGET_NR_semget 64 +#define TARGET_NR_semop 65 +#define TARGET_NR_semctl 66 +#define TARGET_NR_shmdt 67 +#define TARGET_NR_msgget 68 +#define TARGET_NR_msgsnd 69 +#define TARGET_NR_msgrcv 70 +#define TARGET_NR_msgctl 71 +#define TARGET_NR_fcntl 72 +#define TARGET_NR_flock 73 +#define TARGET_NR_fsync 74 +#define TARGET_NR_fdatasync 75 +#define TARGET_NR_truncate 76 +#define TARGET_NR_ftruncate 77 +#define TARGET_NR_getdents 78 +#define TARGET_NR_getcwd 79 +#define TARGET_NR_chdir 80 +#define TARGET_NR_fchdir 81 +#define TARGET_NR_rename 82 +#define TARGET_NR_mkdir 83 +#define TARGET_NR_rmdir 84 +#define TARGET_NR_creat 85 +#define TARGET_NR_link 86 +#define TARGET_NR_unlink 87 +#define TARGET_NR_symlink 88 +#define TARGET_NR_readlink 89 +#define TARGET_NR_chmod 90 +#define TARGET_NR_fchmod 91 +#define TARGET_NR_chown 92 +#define TARGET_NR_fchown 93 +#define TARGET_NR_lchown 94 +#define TARGET_NR_umask 95 +#define TARGET_NR_gettimeofday 96 +#define TARGET_NR_getrlimit 97 +#define TARGET_NR_getrusage 98 +#define TARGET_NR_sysinfo 99 +#define TARGET_NR_times 100 +#define TARGET_NR_ptrace 101 +#define TARGET_NR_getuid 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_getgid 104 +#define TARGET_NR_setuid 105 +#define TARGET_NR_setgid 106 +#define TARGET_NR_geteuid 107 +#define TARGET_NR_getegid 108 +#define TARGET_NR_setpgid 109 +#define TARGET_NR_getppid 110 +#define TARGET_NR_getpgrp 111 +#define TARGET_NR_setsid 112 +#define TARGET_NR_setreuid 113 +#define TARGET_NR_setregid 114 +#define TARGET_NR_getgroups 115 +#define TARGET_NR_setgroups 116 +#define TARGET_NR_setresuid 117 +#define TARGET_NR_getresuid 118 +#define TARGET_NR_setresgid 119 +#define TARGET_NR_getresgid 120 +#define TARGET_NR_getpgid 121 +#define TARGET_NR_setfsuid 122 +#define TARGET_NR_setfsgid 123 +#define TARGET_NR_getsid 124 +#define TARGET_NR_capget 125 +#define TARGET_NR_capset 126 +#define TARGET_NR_rt_sigpending 127 +#define TARGET_NR_rt_sigtimedwait 128 +#define TARGET_NR_rt_sigqueueinfo 129 +#define TARGET_NR_rt_sigsuspend 130 +#define TARGET_NR_sigaltstack 131 +#define TARGET_NR_utime 132 +#define TARGET_NR_mknod 133 +#define TARGET_NR_uselib 134 +#define TARGET_NR_personality 135 +#define TARGET_NR_ustat 136 +#define TARGET_NR_statfs 137 +#define TARGET_NR_fstatfs 138 +#define TARGET_NR_sysfs 139 +#define TARGET_NR_getpriority 140 +#define TARGET_NR_setpriority 141 +#define TARGET_NR_sched_setparam 142 +#define TARGET_NR_sched_getparam 143 +#define TARGET_NR_sched_setscheduler 144 +#define TARGET_NR_sched_getscheduler 145 +#define TARGET_NR_sched_get_priority_max 146 +#define TARGET_NR_sched_get_priority_min 147 +#define TARGET_NR_sched_rr_get_interval 148 +#define TARGET_NR_mlock 149 +#define TARGET_NR_munlock 150 +#define TARGET_NR_mlockall 151 +#define TARGET_NR_munlockall 152 +#define TARGET_NR_vhangup 153 +#define TARGET_NR_modify_ldt 154 +#define TARGET_NR_pivot_root 155 +#define TARGET_NR__sysctl 156 +#define TARGET_NR_prctl 157 +#define TARGET_NR_arch_prctl 158 +#define TARGET_NR_adjtimex 159 +#define TARGET_NR_setrlimit 160 +#define TARGET_NR_chroot 161 +#define TARGET_NR_sync 162 +#define TARGET_NR_acct 163 +#define TARGET_NR_settimeofday 164 +#define TARGET_NR_mount 165 +#define TARGET_NR_umount2 166 +#define TARGET_NR_swapon 167 +#define TARGET_NR_swapoff 168 +#define TARGET_NR_reboot 169 +#define TARGET_NR_sethostname 170 +#define TARGET_NR_setdomainname 171 +#define TARGET_NR_iopl 172 +#define TARGET_NR_ioperm 173 +#define TARGET_NR_create_module 174 +#define TARGET_NR_init_module 175 +#define TARGET_NR_delete_module 176 +#define TARGET_NR_get_kernel_syms 177 +#define TARGET_NR_query_module 178 +#define TARGET_NR_quotactl 179 +#define TARGET_NR_nfsservctl 180 +#define TARGET_NR_getpmsg 181 /* reserved for LiS/STREAMS */ +#define TARGET_NR_putpmsg 182 /* reserved for LiS/STREAMS */ +#define TARGET_NR_afs_syscall 183 /* reserved for AFS */ +#define TARGET_NR_tuxcall 184 /* reserved for tux */ +#define TARGET_NR_security 185 +#define TARGET_NR_gettid 186 +#define TARGET_NR_readahead 187 +#define TARGET_NR_setxattr 188 +#define TARGET_NR_lsetxattr 189 +#define TARGET_NR_fsetxattr 190 +#define TARGET_NR_getxattr 191 +#define TARGET_NR_lgetxattr 192 +#define TARGET_NR_fgetxattr 193 +#define TARGET_NR_listxattr 194 +#define TARGET_NR_llistxattr 195 +#define TARGET_NR_flistxattr 196 +#define TARGET_NR_removexattr 197 +#define TARGET_NR_lremovexattr 198 +#define TARGET_NR_fremovexattr 199 +#define TARGET_NR_tkill 200 +#define TARGET_NR_time 201 +#define TARGET_NR_futex 202 +#define TARGET_NR_sched_setaffinity 203 +#define TARGET_NR_sched_getaffinity 204 +#define TARGET_NR_set_thread_area 205 +#define TARGET_NR_io_setup 206 +#define TARGET_NR_io_destroy 207 +#define TARGET_NR_io_getevents 208 +#define TARGET_NR_io_submit 209 +#define TARGET_NR_io_cancel 210 +#define TARGET_NR_get_thread_area 211 +#define TARGET_NR_lookup_dcookie 212 +#define TARGET_NR_epoll_create 213 +#define TARGET_NR_epoll_ctl_old 214 +#define TARGET_NR_epoll_wait_old 215 +#define TARGET_NR_remap_file_pages 216 +#define TARGET_NR_getdents64 217 +#define TARGET_NR_set_tid_address 218 +#define TARGET_NR_restart_syscall 219 +#define TARGET_NR_semtimedop 220 +#define TARGET_NR_fadvise64 221 +#define TARGET_NR_timer_create 222 +#define TARGET_NR_timer_settime 223 +#define TARGET_NR_timer_gettime 224 +#define TARGET_NR_timer_getoverrun 225 +#define TARGET_NR_timer_delete 226 +#define TARGET_NR_clock_settime 227 +#define TARGET_NR_clock_gettime 228 +#define TARGET_NR_clock_getres 229 +#define TARGET_NR_clock_nanosleep 230 +#define TARGET_NR_exit_group 231 +#define TARGET_NR_epoll_wait 232 +#define TARGET_NR_epoll_ctl 233 +#define TARGET_NR_tgkill 234 +#define TARGET_NR_utimes 235 +#define TARGET_NR_vserver 236 +#define TARGET_NR_mbind 237 +#define TARGET_NR_set_mempolicy 238 +#define TARGET_NR_get_mempolicy 239 +#define TARGET_NR_mq_open 240 +#define TARGET_NR_mq_unlink 241 +#define TARGET_NR_mq_timedsend 242 +#define TARGET_NR_mq_timedreceive 243 +#define TARGET_NR_mq_notify 244 +#define TARGET_NR_mq_getsetattr 245 +#define TARGET_NR_kexec_load 246 +#define TARGET_NR_waitid 247 +#define TARGET_NR_add_key 248 +#define TARGET_NR_request_key 249 +#define TARGET_NR_keyctl 250 +#define TARGET_NR_ioprio_set 251 +#define TARGET_NR_ioprio_get 252 +#define TARGET_NR_inotify_init 253 +#define TARGET_NR_inotify_add_watch 254 +#define TARGET_NR_inotify_rm_watch 255 +#define TARGET_NR_migrate_pages 256 +#define TARGET_NR_openat 257 +#define TARGET_NR_mkdirat 258 +#define TARGET_NR_mknodat 259 +#define TARGET_NR_fchownat 260 +#define TARGET_NR_futimesat 261 +#define TARGET_NR_newfstatat 262 +#define TARGET_NR_unlinkat 263 +#define TARGET_NR_renameat 264 +#define TARGET_NR_linkat 265 +#define TARGET_NR_symlinkat 266 +#define TARGET_NR_readlinkat 267 +#define TARGET_NR_fchmodat 268 +#define TARGET_NR_faccessat 269 +#define TARGET_NR_pselect6 270 +#define TARGET_NR_ppoll 271 +#define TARGET_NR_unshare 272 +#define TARGET_NR_set_robust_list 273 +#define TARGET_NR_get_robust_list 274 +#define TARGET_NR_splice 275 +#define TARGET_NR_tee 276 +#define TARGET_NR_sync_file_range 277 +#define TARGET_NR_vmsplice 278 +#define TARGET_NR_move_pages 279 diff --git a/linux-user/x86_64/termbits.h b/linux-user/x86_64/termbits.h new file mode 100644 index 000000000..1c3445c6a --- /dev/null +++ b/linux-user/x86_64/termbits.h @@ -0,0 +1,247 @@ +#define TARGET_NCCS 19 + +typedef unsigned char target_cc_t; +typedef unsigned int target_speed_t; +typedef unsigned int target_tcflag_t; +struct target_termios { + target_tcflag_t c_iflag; /* input mode flags */ + target_tcflag_t c_oflag; /* output mode flags */ + target_tcflag_t c_cflag; /* control mode flags */ + target_tcflag_t c_lflag; /* local mode flags */ + target_cc_t c_line; /* line discipline */ + target_cc_t c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_BOTHER 0010000 /* non standard rate */ +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 +#define TARGET_CIBAUD 002003600000 /* input baud rate */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +#define TARGET_IBSHIFT 8 /* Shift from CBAUD to CIBAUD */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* tcflow() and TCXONC use these */ +#define TARGET_TCOOFF 0 +#define TARGET_TCOON 1 +#define TARGET_TCIOFF 2 +#define TARGET_TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TARGET_TCIFLUSH 0 +#define TARGET_TCOFLUSH 1 +#define TARGET_TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TARGET_TCSANOW 0 +#define TARGET_TCSADRAIN 1 +#define TARGET_TCSAFLUSH 2 + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TCGETS2 _IOR('T',0x2A, struct termios2) +#define TARGET_TCSETS2 _IOW('T',0x2B, struct termios2) +#define TARGET_TCSETSW2 _IOW('T',0x2C, struct termios2) +#define TARGET_TCSETSF2 _IOW('T',0x2D, struct termios2) +#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define TARGET_FIOQSIZE 0x5460 + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -- cgit v1.2.3 From 9d53c7535f0305a537c5f0278b61cbe34074247c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 6 Apr 2007 07:59:47 +0000 Subject: Fix for PowerPC 64 rotates. Fix for PowerPC 64 load & store with immediate index. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2617 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 62 ++++++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2d9a346ed..614570118 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1264,8 +1264,8 @@ static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn) { uint32_t sh, mb; - sh = SH(ctx->opcode) | (1 << shn); - mb = (MB(ctx->opcode) << 1) | mbn; + sh = SH(ctx->opcode) | (shn << 5); + mb = MB(ctx->opcode) | (mbn << 5); gen_rldinm(ctx, mb, 63, sh); } GEN_PPC64_R4(rldicl, 0x1E, 0x00); @@ -1274,8 +1274,8 @@ static inline void gen_rldicr (DisasContext *ctx, int men, int shn) { uint32_t sh, me; - sh = SH(ctx->opcode) | (1 << shn); - me = (MB(ctx->opcode) << 1) | men; + sh = SH(ctx->opcode) | (shn << 5); + me = MB(ctx->opcode) | (men << 5); gen_rldinm(ctx, 0, me, sh); } GEN_PPC64_R4(rldicr, 0x1E, 0x02); @@ -1284,8 +1284,8 @@ static inline void gen_rldic (DisasContext *ctx, int mbn, int shn) { uint32_t sh, mb; - sh = SH(ctx->opcode) | (1 << shn); - mb = (MB(ctx->opcode) << 1) | mbn; + sh = SH(ctx->opcode) | (shn << 5); + mb = MB(ctx->opcode) | (mbn << 5); gen_rldinm(ctx, mb, 63 - sh, sh); } GEN_PPC64_R4(rldic, 0x1E, 0x04); @@ -1308,7 +1308,7 @@ static inline void gen_rldcl (DisasContext *ctx, int mbn) { uint32_t mb; - mb = (MB(ctx->opcode) << 1) | mbn; + mb = MB(ctx->opcode) | (mbn << 5); gen_rldnm(ctx, mb, 63); } GEN_PPC64_R2(rldcl, 0x1E, 0x08) @@ -1317,7 +1317,7 @@ static inline void gen_rldcr (DisasContext *ctx, int men) { uint32_t me; - me = (MB(ctx->opcode) << 1) | men; + me = MB(ctx->opcode) | (men << 5); gen_rldnm(ctx, 0, me); } GEN_PPC64_R2(rldcr, 0x1E, 0x09) @@ -1327,8 +1327,8 @@ static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) uint64_t mask; uint32_t sh, mb; - sh = SH(ctx->opcode) | (1 << shn); - mb = (MB(ctx->opcode) << 1) | mbn; + sh = SH(ctx->opcode) | (shn << 5); + mb = MB(ctx->opcode) | (mbn << 5); if (likely(sh == 0)) { if (likely(mb == 0)) { gen_op_load_gpr_T0(rS(ctx->opcode)); @@ -1732,10 +1732,12 @@ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) /*** Addressing modes ***/ /* Register indirect with immediate index : EA = (rA|0) + SIMM */ -static inline void gen_addr_imm_index (DisasContext *ctx) +static inline void gen_addr_imm_index (DisasContext *ctx, int maskl) { target_long simm = SIMM(ctx->opcode); + if (maskl) + simm &= ~0x03; if (rA(ctx->opcode) == 0) { gen_set_T0(simm); } else { @@ -1856,7 +1858,7 @@ static GenOpFunc *gen_op_st##width[] = { \ #define GEN_LD(width, opc, type) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ - gen_addr_imm_index(ctx); \ + gen_addr_imm_index(ctx, 0); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ } @@ -1869,7 +1871,10 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ RET_INVAL(ctx); \ return; \ } \ - gen_addr_imm_index(ctx); \ + if (type == PPC_64B) \ + gen_addr_imm_index(ctx, 1); \ + else \ + gen_addr_imm_index(ctx, 0); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1932,7 +1937,7 @@ GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B) return; } } - gen_addr_imm_index(ctx); + gen_addr_imm_index(ctx, 1); if (ctx->opcode & 0x02) { /* lwa (lwau is undefined) */ op_ldst(lwa); @@ -1950,7 +1955,7 @@ GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B) #define GEN_ST(width, opc, type) \ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ - gen_addr_imm_index(ctx); \ + gen_addr_imm_index(ctx, 0); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ } @@ -1962,7 +1967,10 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ RET_INVAL(ctx); \ return; \ } \ - gen_addr_imm_index(ctx); \ + if (type == PPC_64B) \ + gen_addr_imm_index(ctx, 1); \ + else \ + gen_addr_imm_index(ctx, 0); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -2014,7 +2022,7 @@ GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B) return; } } - gen_addr_imm_index(ctx); + gen_addr_imm_index(ctx, 1); gen_op_load_gpr_T1(rS(ctx->opcode)); op_ldst(std); if (Rc(ctx->opcode)) @@ -2102,7 +2110,7 @@ GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx); + gen_addr_imm_index(ctx, 0); op_ldstm(lmw, rD(ctx->opcode)); } @@ -2111,7 +2119,7 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx); + gen_addr_imm_index(ctx, 0); op_ldstm(stmw, rS(ctx->opcode)); } @@ -2435,7 +2443,7 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - gen_addr_imm_index(ctx); \ + gen_addr_imm_index(ctx, 0); \ op_ldst(l##width); \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ } @@ -2451,7 +2459,7 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ RET_INVAL(ctx); \ return; \ } \ - gen_addr_imm_index(ctx); \ + gen_addr_imm_index(ctx, 0); \ op_ldst(l##width); \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -2506,7 +2514,7 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - gen_addr_imm_index(ctx); \ + gen_addr_imm_index(ctx, 0); \ gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ } @@ -2522,7 +2530,7 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ RET_INVAL(ctx); \ return; \ } \ - gen_addr_imm_index(ctx); \ + gen_addr_imm_index(ctx, 0); \ gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -4102,7 +4110,7 @@ GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx); + gen_addr_imm_index(ctx, 0); op_POWER2_lfq(); gen_op_store_FT0_fpr(rD(ctx->opcode)); gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); @@ -4115,7 +4123,7 @@ GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx); + gen_addr_imm_index(ctx, 0); op_POWER2_lfq(); gen_op_store_FT0_fpr(rD(ctx->opcode)); gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); @@ -4154,7 +4162,7 @@ GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx); + gen_addr_imm_index(ctx, 0); gen_op_load_fpr_FT0(rS(ctx->opcode)); gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); op_POWER2_stfq(); @@ -4167,7 +4175,7 @@ GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2) /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - gen_addr_imm_index(ctx); + gen_addr_imm_index(ctx, 0); gen_op_load_fpr_FT0(rS(ctx->opcode)); gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); op_POWER2_stfq(); -- cgit v1.2.3 From 9ead1a126356a05b61eb4388ef0729f08454a78c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 6 Apr 2007 08:07:06 +0000 Subject: Add alpha targets. Code provision for x86_64 and PowerPC 64 linux user targets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2618 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.cvsignore b/.cvsignore index 5277a1d7d..45d63262d 100644 --- a/.cvsignore +++ b/.cvsignore @@ -11,6 +11,7 @@ ppc-softmmu ppc64-softmmu ppc-darwin-user ppc-linux-user +ppc64-linux-user qemu-doc.html qemu-tech.html qemu-doc.info @@ -23,6 +24,7 @@ sparc-linux-user qemu-img sparc-softmmu x86_64-softmmu +x86_64-linux-user sparc64-linux-user sparc64-softmmu mips-softmmu @@ -37,6 +39,8 @@ m68k-linux-user .gdbinit sh4-linux-user sh4-softmmu +alpha-linux-user +alpha-softmmu *.aux *.cp *.dvi -- cgit v1.2.3 From 84409ddbda9b4d8f2d2ad4f580e987800b8e7c4e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 6 Apr 2007 08:56:50 +0000 Subject: Code provision for x86_64 and PowerPC 64 linux user mode support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2619 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 41 +++++++++++++++++++++++++++++++++++++++++ linux-user/main.c | 35 +++++++++++++++++++++++++++++++---- linux-user/qemu.h | 2 +- linux-user/signal.c | 6 +++++- linux-user/syscall.c | 4 ++++ 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5caa44eaf..1256dba95 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -44,6 +44,23 @@ static uint32_t get_elf_hwcap(void) return global_env->cpuid_features; } +#ifdef TARGET_X86_64 +#define ELF_START_MMAP 0x2aaaaab000ULL +#define elf_check_arch(x) ( ((x) == ELF_ARCH) ) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_X86_64 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->rax = 0; + regs->rsp = infop->start_stack; + regs->rip = infop->entry; +} + +#else + #define ELF_START_MMAP 0x80000000 /* @@ -72,6 +89,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i A value of 0 tells we have no such handler. */ regs->edx = 0; } +#endif #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 @@ -177,9 +195,20 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 +#ifdef TARGET_PPC64 + +#define elf_check_arch(x) ( (x) == EM_PPC64 ) + +#define ELF_CLASS ELFCLASS64 + +#else + #define elf_check_arch(x) ( (x) == EM_PPC ) #define ELF_CLASS ELFCLASS32 + +#endif + #ifdef TARGET_WORDS_BIGENDIAN #define ELF_DATA ELFDATA2MSB #else @@ -222,9 +251,18 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * { target_ulong pos = infop->start_stack; target_ulong tmp; +#ifdef TARGET_PPC64 + target_ulong entry, toc; +#endif _regs->msr = 1 << MSR_PR; /* Set user mode */ _regs->gpr[1] = infop->start_stack; +#ifdef TARGET_PPC64 + entry = ldq_raw(infop->entry) + infop->load_addr; + toc = ldq_raw(infop->entry + 8) + infop->load_addr; + _regs->gpr[2] = toc; + infop->entry = entry; +#endif _regs->nip = infop->entry; /* Note that isn't exactly what regular kernel does * but this is what the ABI wants and is needed to allow @@ -917,6 +955,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, unsigned long elf_entry, interp_load_addr = 0; int status; unsigned long start_code, end_code, end_data; + unsigned long reloc_func_desc = 0; unsigned long elf_stack; char passed_fileno[6]; @@ -1181,6 +1220,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, load_bias += error - TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); load_addr += load_bias; + reloc_func_desc = load_bias; } } k = elf_ppnt->p_vaddr; @@ -1213,6 +1253,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, &interp_load_addr); } + reloc_func_desc = interp_load_addr; close(interpreter_fd); free(elf_interpreter); diff --git a/linux-user/main.c b/linux-user/main.c index cad10e646..74798c7cc 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -194,9 +194,12 @@ void cpu_loop(CPUX86State *env) queue_signal(info.si_signo, &info); break; case EXCP0D_GPF: +#ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_fault(env); - } else { + } else +#endif + { info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; @@ -215,9 +218,12 @@ void cpu_loop(CPUX86State *env) queue_signal(info.si_signo, &info); break; case EXCP00_DIVZ: +#ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); - } else { + } else +#endif + { /* division by zero */ info.si_signo = SIGFPE; info.si_errno = 0; @@ -228,9 +234,12 @@ void cpu_loop(CPUX86State *env) break; case EXCP01_SSTP: case EXCP03_INT3: +#ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); - } else { + } else +#endif + { info.si_signo = SIGTRAP; info.si_errno = 0; if (trapnr == EXCP01_SSTP) { @@ -245,9 +254,12 @@ void cpu_loop(CPUX86State *env) break; case EXCP04_INTO: case EXCP05_BOUND: +#ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_trap(env, trapnr); - } else { + } else +#endif + { info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; @@ -1807,6 +1819,17 @@ int main(int argc, char **argv) env->eflags |= IF_MASK; /* linux register setup */ +#if defined(TARGET_X86_64) + env->regs[R_EAX] = regs->rax; + env->regs[R_EBX] = regs->rbx; + env->regs[R_ECX] = regs->rcx; + env->regs[R_EDX] = regs->rdx; + env->regs[R_ESI] = regs->rsi; + env->regs[R_EDI] = regs->rdi; + env->regs[R_EBP] = regs->rbp; + env->regs[R_ESP] = regs->rsp; + env->eip = regs->rip; +#else env->regs[R_EAX] = regs->eax; env->regs[R_EBX] = regs->ebx; env->regs[R_ECX] = regs->ecx; @@ -1816,6 +1839,7 @@ int main(int argc, char **argv) env->regs[R_EBP] = regs->ebp; env->regs[R_ESP] = regs->esp; env->eip = regs->eip; +#endif /* linux interrupt setup */ env->idt.base = h2g(idt_table); @@ -1903,6 +1927,9 @@ int main(int argc, char **argv) if (i != 12 && i != 6 && i != 13) env->msr[i] = (regs->msr >> i) & 1; } +#if defined(TARGET_PPC64) + msr_sf = 1; +#endif env->nip = regs->nip; for(i = 0; i < 32; i++) { env->gpr[i] = regs->gpr[i]; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index f894dde08..31e29da7d 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -68,7 +68,7 @@ typedef struct TaskState { uint32_t heap_limit; int swi_errno; #endif -#ifdef TARGET_I386 +#if defined(TARGET_I386) && !defined(TARGET_X86_64) target_ulong target_v86; struct vm86_saved_state vm86_saved_regs; struct target_vm86plus_struct vm86plus; diff --git a/linux-user/signal.c b/linux-user/signal.c index 1e29c2c50..5a99e610d 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -690,7 +690,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, err |= __put_user(frame->retcode, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ err |= __put_user(0xb858, (short *)(frame->retcode+0)); +#if defined(TARGET_X86_64) +#warning "Fix this !" +#else err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); +#endif err |= __put_user(0x80cd, (short *)(frame->retcode+6)); } @@ -2048,7 +2052,7 @@ void process_pending_signals(void *cpu_env) host_to_target_sigset_internal(&target_old_set, &old_set); /* if the CPU is in VM86 mode, we restore the 32 bit values */ -#ifdef TARGET_I386 +#if defined(TARGET_I386) && !defined(TARGET_X86_64) { CPUX86State *env = cpu_env; if (env->eflags & VM_MASK) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9dc0b09b0..7ab506dd3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3250,11 +3250,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_modify_ldt: ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3)); break; +#if !defined(TARGET_X86_64) case TARGET_NR_vm86old: goto unimplemented; case TARGET_NR_vm86: ret = do_vm86(cpu_env, arg1, arg2); break; +#endif #endif case TARGET_NR_adjtimex: goto unimplemented; @@ -3275,8 +3277,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_fchdir: ret = get_errno(fchdir(arg1)); break; +#ifdef TARGET_NR_bdflush /* not on x86_64 */ case TARGET_NR_bdflush: goto unimplemented; +#endif #ifdef TARGET_NR_sysfs case TARGET_NR_sysfs: goto unimplemented; -- cgit v1.2.3 From a1bb27b1e98a372545f37a599c0f9ea785502554 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 6 Apr 2007 16:49:48 +0000 Subject: SD card emulation (initial implementation by Andrzei Zaborowski). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2620 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/integratorcp.c | 3 +- hw/pl181.c | 445 ++++++++++++++++ hw/realview.c | 4 +- hw/sd.c | 1508 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/sd.h | 82 +++ hw/versatilepb.c | 12 +- qemu-doc.texi | 6 + vl.c | 23 +- vl.h | 5 + 10 files changed, 2084 insertions(+), 8 deletions(-) create mode 100644 hw/pl181.c create mode 100644 hw/sd.c create mode 100644 hw/sd.h diff --git a/Makefile.target b/Makefile.target index 274299185..16adfc7e4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -442,8 +442,8 @@ 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_boot.o pl011.o pl050.o pl080.o pl110.o pl181.o pl190.o +VL_OBJS+= versatile_pci.o sd.o VL_OBJS+= arm_gic.o realview.o arm_sysctl.o VL_OBJS+= arm-semi.o endif diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 5e4c636f0..1d8b722cf 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -1,7 +1,7 @@ /* * ARM Integrator CP System emulation. * - * Copyright (c) 2005-2006 CodeSourcery. + * Copyright (c) 2005-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL @@ -500,6 +500,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, icp_control_init(0xcb000000); pl050_init(0x18000000, pic, 3, 0); pl050_init(0x19000000, pic, 4, 1); + pl181_init(0x1c000000, sd_bdrv, pic, 23, 24); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "smc91c111") == 0) { diff --git a/hw/pl181.c b/hw/pl181.c new file mode 100644 index 000000000..7912c280b --- /dev/null +++ b/hw/pl181.c @@ -0,0 +1,445 @@ +/* + * Arm PrimeCell PL181 MultiMedia Card Interface + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "sd.h" + +//#define DEBUG_PL181 1 + +#ifdef DEBUG_PL181 +#define DPRINTF(fmt, args...) \ +do { printf("pl181: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +#define PL181_FIFO_LEN 16 + +typedef struct { + struct sd_state_s *card; + uint32_t base; + uint32_t clock; + uint32_t power; + uint32_t cmdarg; + uint32_t cmd; + uint32_t datatimer; + uint32_t datalength; + uint32_t respcmd; + uint32_t response[4]; + uint32_t datactrl; + uint32_t datacnt; + uint32_t status; + uint32_t mask[2]; + uint32_t fifocnt; + int fifo_pos; + int fifo_len; + uint32_t fifo[PL181_FIFO_LEN]; + void *pic; + int irq[2]; +} pl181_state; + +#define PL181_CMD_INDEX 0x3f +#define PL181_CMD_RESPONSE (1 << 6) +#define PL181_CMD_LONGRESP (1 << 7) +#define PL181_CMD_INTERRUPT (1 << 8) +#define PL181_CMD_PENDING (1 << 9) +#define PL181_CMD_ENABLE (1 << 10) + +#define PL181_DATA_ENABLE (1 << 0) +#define PL181_DATA_DIRECTION (1 << 1) +#define PL181_DATA_MODE (1 << 2) +#define PL181_DATA_DMAENABLE (1 << 3) + +#define PL181_STATUS_CMDCRCFAIL (1 << 0) +#define PL181_STATUS_DATACRCFAIL (1 << 1) +#define PL181_STATUS_CMDTIMEOUT (1 << 2) +#define PL181_STATUS_DATATIMEOUT (1 << 3) +#define PL181_STATUS_TXUNDERRUN (1 << 4) +#define PL181_STATUS_RXOVERRUN (1 << 5) +#define PL181_STATUS_CMDRESPEND (1 << 6) +#define PL181_STATUS_CMDSENT (1 << 7) +#define PL181_STATUS_DATAEND (1 << 8) +#define PL181_STATUS_DATABLOCKEND (1 << 10) +#define PL181_STATUS_CMDACTIVE (1 << 11) +#define PL181_STATUS_TXACTIVE (1 << 12) +#define PL181_STATUS_RXACTIVE (1 << 13) +#define PL181_STATUS_TXFIFOHALFEMPTY (1 << 14) +#define PL181_STATUS_RXFIFOHALFFULL (1 << 15) +#define PL181_STATUS_TXFIFOFULL (1 << 16) +#define PL181_STATUS_RXFIFOFULL (1 << 17) +#define PL181_STATUS_TXFIFOEMPTY (1 << 18) +#define PL181_STATUS_RXFIFOEMPTY (1 << 19) +#define PL181_STATUS_TXDATAAVLBL (1 << 20) +#define PL181_STATUS_RXDATAAVLBL (1 << 21) + +#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \ + |PL181_STATUS_TXFIFOHALFEMPTY \ + |PL181_STATUS_TXFIFOFULL \ + |PL181_STATUS_TXFIFOEMPTY \ + |PL181_STATUS_TXDATAAVLBL) +#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \ + |PL181_STATUS_RXFIFOHALFFULL \ + |PL181_STATUS_RXFIFOFULL \ + |PL181_STATUS_RXFIFOEMPTY \ + |PL181_STATUS_RXDATAAVLBL) + +static const unsigned char pl181_id[] = +{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; + +static void pl181_update(pl181_state *s) +{ + int i; + for (i = 0; i < 2; i++) { + pic_set_irq_new(s->pic, s->irq[i], (s->status & s->mask[i]) != 0); + } +} + +static void pl181_fifo_push(pl181_state *s, uint32_t value) +{ + int n; + + if (s->fifo_len == PL181_FIFO_LEN) { + fprintf(stderr, "pl181: FIFO overflow\n"); + return; + } + n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1); + s->fifo_len++; + s->fifo[n] = value; + DPRINTF("FIFO push %08x\n", (int)value); +} + +static uint32_t pl181_fifo_pop(pl181_state *s) +{ + uint32_t value; + + if (s->fifo_len == 0) { + fprintf(stderr, "pl181: FIFO underflow\n"); + return 0; + } + value = s->fifo[s->fifo_pos]; + s->fifo_len--; + s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1); + DPRINTF("FIFO pop %08x\n", (int)value); + return value; +} + +static void pl181_send_command(pl181_state *s) +{ + struct sd_request_s request; + uint8_t response[16]; + int rlen; + + request.cmd = s->cmd & PL181_CMD_INDEX; + request.arg = s->cmdarg; + DPRINTF("Command %d %08x\n", request.cmd, request.arg); + rlen = sd_do_command(s->card, &request, response); + if (rlen < 0) + goto error; + if (s->cmd & PL181_CMD_RESPONSE) { +#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \ + | (response[n + 2] << 8) | response[n + 3]) + if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP))) + goto error; + if (rlen != 4 && rlen != 16) + goto error; + s->response[0] = RWORD(0); + if (rlen == 4) { + s->response[1] = s->response[2] = s->response[3] = 0; + } else { + s->response[1] = RWORD(4); + s->response[2] = RWORD(8); + s->response[3] = RWORD(12) & ~1; + } + DPRINTF("Response recieved\n"); + s->status |= PL181_STATUS_CMDRESPEND; +#undef RWORD + } else { + DPRINTF("Command sent\n"); + s->status |= PL181_STATUS_CMDSENT; + } + return; + +error: + DPRINTF("Timeout\n"); + s->status |= PL181_STATUS_CMDTIMEOUT; +} + +/* Transfer data between teh card and the FIFO. This is complicated by + the FIFO holding 32-bit words and the card taking data in single byte + chunks. FIFO bytes are transferred in little-endian order. */ + +static void pl181_fifo_run(pl181_state *s) +{ + uint32_t bits; + uint32_t value; + int n; + int limit; + int is_read; + + is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0; + if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))) { + limit = is_read ? PL181_FIFO_LEN : 0; + n = 0; + value = 0; + while (s->datacnt && s->fifo_len != limit) { + if (is_read) { + value |= (uint32_t)sd_read_data(s->card) << (n * 8); + n++; + if (n == 4) { + pl181_fifo_push(s, value); + value = 0; + n = 0; + } + } else { + if (n == 0) { + value = pl181_fifo_pop(s); + n = 4; + } + sd_write_data(s->card, value & 0xff); + value >>= 8; + n--; + } + s->datacnt--; + } + if (n && is_read) { + pl181_fifo_push(s, value); + } + } + s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO); + if (s->datacnt == 0) { + s->status |= PL181_STATUS_DATAEND; + /* HACK: */ + s->status |= PL181_STATUS_DATABLOCKEND; + DPRINTF("Transfer Complete\n"); + } + if (s->datacnt == 0 && s->fifocnt == 0) { + s->datactrl &= ~PL181_DATA_ENABLE; + DPRINTF("Data engine idle\n"); + } else { + /* Update FIFO bits. */ + bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE; + if (s->fifo_len == 0) { + bits |= PL181_STATUS_TXFIFOEMPTY; + bits |= PL181_STATUS_RXFIFOEMPTY; + } else { + bits |= PL181_STATUS_TXDATAAVLBL; + bits |= PL181_STATUS_RXDATAAVLBL; + } + if (s->fifo_len == 16) { + bits |= PL181_STATUS_TXFIFOFULL; + bits |= PL181_STATUS_RXFIFOFULL; + } + if (s->fifo_len <= 8) { + bits |= PL181_STATUS_TXFIFOHALFEMPTY; + } + if (s->fifo_len >= 8) { + bits |= PL181_STATUS_RXFIFOHALFFULL; + } + if (s->datactrl & PL181_DATA_DIRECTION) { + bits &= PL181_STATUS_RX_FIFO; + } else { + bits &= PL181_STATUS_TX_FIFO; + } + s->status |= bits; + } +} + +static uint32_t pl181_read(void *opaque, target_phys_addr_t offset) +{ + pl181_state *s = (pl181_state *)opaque; + + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) { + return pl181_id[(offset - 0xfe0) >> 2]; + } + switch (offset) { + case 0x00: /* Power */ + return s->power; + case 0x04: /* Clock */ + return s->clock; + case 0x08: /* Argument */ + return s->cmdarg; + case 0x0c: /* Command */ + return s->cmd; + case 0x10: /* RespCmd */ + return s->respcmd; + case 0x14: /* Response0 */ + return s->response[0]; + case 0x18: /* Response1 */ + return s->response[1]; + case 0x1c: /* Response2 */ + return s->response[2]; + case 0x20: /* Response3 */ + return s->response[3]; + case 0x24: /* DataTimer */ + return s->datatimer; + case 0x28: /* DataLength */ + return s->datalength; + case 0x2c: /* DataCtrl */ + return s->datactrl; + case 0x30: /* DataCnt */ + return s->datacnt; + case 0x34: /* Status */ + return s->status; + case 0x3c: /* Mask0 */ + return s->mask[0]; + case 0x40: /* Mask1 */ + return s->mask[1]; + case 0x48: /* FifoCnt */ + return s->fifocnt; + case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ + case 0x90: case 0x94: case 0x98: case 0x9c: + case 0xa0: case 0xa4: case 0xa8: case 0xac: + case 0xb0: case 0xb4: case 0xb8: case 0xbc: + if (s->fifocnt == 0) { + fprintf(stderr, "pl181: Unexpected FIFO read\n"); + return 0; + } else { + uint32_t value; + s->fifocnt--; + value = pl181_fifo_pop(s); + pl181_fifo_run(s); + pl181_update(s); + return value; + } + default: + cpu_abort (cpu_single_env, "pl181_read: Bad offset %x\n", offset); + return 0; + } +} + +static void pl181_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + pl181_state *s = (pl181_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* Power */ + s->power = value & 0xff; + break; + case 0x04: /* Clock */ + s->clock = value & 0xff; + break; + case 0x08: /* Argument */ + s->cmdarg = value; + break; + case 0x0c: /* Command */ + s->cmd = value; + if (s->cmd & PL181_CMD_ENABLE) { + if (s->cmd & PL181_CMD_INTERRUPT) { + fprintf(stderr, "pl181: Interrupt mode not implemented\n"); + abort(); + } if (s->cmd & PL181_CMD_PENDING) { + fprintf(stderr, "pl181: Pending commands not implemented\n"); + abort(); + } else { + pl181_send_command(s); + pl181_fifo_run(s); + } + /* The command has completed one way or the other. */ + s->cmd &= ~PL181_CMD_ENABLE; + } + break; + case 0x24: /* DataTimer */ + s->datatimer = value; + break; + case 0x28: /* DataLength */ + s->datalength = value & 0xffff; + break; + case 0x2c: /* DataCtrl */ + s->datactrl = value & 0xff; + if (value & PL181_DATA_ENABLE) { + s->datacnt = s->datalength; + s->fifocnt = (s->datalength + 3) >> 2; + pl181_fifo_run(s); + } + break; + case 0x38: /* Clear */ + s->status &= ~(value & 0x7ff); + break; + case 0x3c: /* Mask0 */ + s->mask[0] = value; + break; + case 0x40: /* Mask1 */ + s->mask[1] = value; + break; + case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ + case 0x90: case 0x94: case 0x98: case 0x9c: + case 0xa0: case 0xa4: case 0xa8: case 0xac: + case 0xb0: case 0xb4: case 0xb8: case 0xbc: + if (s->fifocnt == 0) { + fprintf(stderr, "pl181: Unexpected FIFO write\n"); + } else { + s->fifocnt--; + pl181_fifo_push(s, value); + pl181_fifo_run(s); + } + break; + default: + cpu_abort (cpu_single_env, "pl181_write: Bad offset %x\n", offset); + } + pl181_update(s); +} + +static CPUReadMemoryFunc *pl181_readfn[] = { + pl181_read, + pl181_read, + pl181_read +}; + +static CPUWriteMemoryFunc *pl181_writefn[] = { + pl181_write, + pl181_write, + pl181_write +}; + +static void pl181_reset(void *opaque) +{ + pl181_state *s = (pl181_state *)opaque; + + s->power = 0; + s->cmdarg = 0; + s->cmd = 0; + s->datatimer = 0; + s->datalength = 0; + s->respcmd = 0; + s->response[0] = 0; + s->response[1] = 0; + s->response[2] = 0; + s->response[3] = 0; + s->datatimer = 0; + s->datalength = 0; + s->datactrl = 0; + s->datacnt = 0; + s->status = 0; + s->mask[0] = 0; + s->mask[1] = 0; + s->fifocnt = 0; +} + +void pl181_init(uint32_t base, BlockDriverState *bd, + void *pic, int irq0, int irq1) +{ + int iomemtype; + pl181_state *s; + + s = (pl181_state *)qemu_mallocz(sizeof(pl181_state)); + iomemtype = cpu_register_io_memory(0, pl181_readfn, + pl181_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + s->base = base; + s->card = sd_init(bd); + s->pic = pic; + s->irq[0] = irq0; + s->irq[1] = irq1; + qemu_register_reset(pl181_reset, s); + pl181_reset(s); + /* ??? Save/restore. */ +} diff --git a/hw/realview.c b/hw/realview.c index a5607e79b..1d351bf2b 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -1,7 +1,7 @@ /* * ARM RealView Baseboard System emulation. * - * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2006-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL. @@ -55,6 +55,8 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, pl110_init(ds, 0x10020000, pic, 23, 1); + pl181_init(0x10005000, sd_bdrv, pic, 17, 18); + pci_bus = pci_vpb_init(pic, 48, 1); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); diff --git a/hw/sd.c b/hw/sd.c new file mode 100644 index 000000000..799c94533 --- /dev/null +++ b/hw/sd.c @@ -0,0 +1,1508 @@ +/* + * SD Memory Card emulation as defined in the "SD Memory Card Physical + * layer specification, Version 1.10." + * + * Copyright (c) 2006 Andrzej Zaborowski + * Copyright (c) 2007 CodeSourcery + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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 "sd.h" + +//#define DEBUG_SD 1 + +#ifdef DEBUG_SD +#define DPRINTF(fmt, args...) \ +do { printf("SD: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +typedef enum { + sd_r0 = 0, /* no response */ + sd_r1, /* normal response command */ + sd_r2_i, /* CID register */ + sd_r2_s, /* CSD register */ + sd_r3, /* OCR register */ + sd_r6 = 6, /* Published RCA response */ + sd_r1b = -1, +} sd_rsp_type_t; + +struct SDState { + enum { + sd_inactive, + sd_card_identification_mode, + sd_data_transfer_mode, + } mode; + enum { + sd_inactive_state = -1, + sd_idle_state = 0, + sd_ready_state, + sd_identification_state, + sd_standby_state, + sd_transfer_state, + sd_sendingdata_state, + sd_receivingdata_state, + sd_programming_state, + sd_disconnect_state, + } state; + uint32_t ocr; + uint8_t scr[8]; + uint8_t cid[16]; + uint8_t csd[16]; + uint16_t rca; + uint32_t card_status; + uint8_t sd_status[64]; + int wp_switch; + int *wp_groups; + uint32_t size; + int blk_len; + uint32_t erase_start; + uint32_t erase_end; + uint8_t pwd[16]; + int pwd_len; + int function_group[6]; + + int current_cmd; + int blk_written; + uint32_t data_start; + uint32_t data_offset; + uint8_t data[512]; + void (*readonly_cb)(void *, int); + void (*inserted_cb)(void *, int); + void *opaque; + BlockDriverState *bdrv; +}; + +static void sd_set_status(SDState *sd) +{ + switch (sd->state) { + case sd_inactive_state: + sd->mode = sd_inactive; + break; + + case sd_idle_state: + case sd_ready_state: + case sd_identification_state: + sd->mode = sd_card_identification_mode; + break; + + case sd_standby_state: + case sd_transfer_state: + case sd_sendingdata_state: + case sd_receivingdata_state: + case sd_programming_state: + case sd_disconnect_state: + sd->mode = sd_data_transfer_mode; + break; + } + + sd->card_status &= ~CURRENT_STATE; + sd->card_status |= sd->state << 9; +} + +const sd_cmd_type_t sd_cmd_type[64] = { + sd_bc, sd_none, sd_bcr, sd_bcr, sd_none, sd_none, sd_none, sd_ac, + sd_none, sd_ac, sd_ac, sd_adtc, sd_ac, sd_ac, sd_none, sd_ac, + sd_ac, sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, + sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac, sd_ac, sd_adtc, sd_none, + sd_ac, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none, + sd_none, sd_none, sd_bc, sd_none, sd_none, sd_none, sd_none, sd_none, + sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac, + sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, +}; + +const sd_cmd_type_t sd_acmd_type[64] = { + sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none, + sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none, + sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_ac, + sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, + sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, + sd_none, sd_bcr, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_none, + sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none, sd_none, sd_none, + sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, +}; + +static const int sd_cmd_class[64] = { + 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, + 5, 5, 10, 10, 10, 10, 5, 9, 9, 9, 7, 7, 7, 7, 7, 7, + 7, 7, 10, 7, 9, 9, 9, 8, 8, 10, 8, 8, 8, 8, 8, 8, +}; + +static uint8_t sd_crc7(void *message, size_t width) +{ + int i, bit; + uint8_t shift_reg = 0x00; + uint8_t *msg = (uint8_t *) message; + + for (i = 0; i < width; i ++, msg ++) + for (bit = 7; bit >= 0; bit --) { + shift_reg <<= 1; + if ((shift_reg >> 7) ^ ((*msg >> bit) & 1)) + shift_reg ^= 0x89; + } + + return shift_reg; +} + +static uint16_t sd_crc16(void *message, size_t width) +{ + int i, bit; + uint16_t shift_reg = 0x0000; + uint16_t *msg = (uint16_t *) message; + width <<= 1; + + for (i = 0; i < width; i ++, msg ++) + for (bit = 15; bit >= 0; bit --) { + shift_reg <<= 1; + if ((shift_reg >> 15) ^ ((*msg >> bit) & 1)) + shift_reg ^= 0x1011; + } + + return shift_reg; +} + +static void sd_set_ocr(SDState *sd) +{ + sd->ocr = 0x80fffff0; +} + +static void sd_set_scr(SDState *sd) +{ + sd->scr[0] = 0x00; /* SCR Structure */ + sd->scr[1] = 0x2f; /* SD Security Support */ + sd->scr[2] = 0x00; + sd->scr[3] = 0x00; + sd->scr[4] = 0x00; + sd->scr[5] = 0x00; + sd->scr[6] = 0x00; + sd->scr[7] = 0x00; +} + +#define MID 0xaa +#define OID "XY" +#define PNM "QEMU!" +#define PRV 0x01 +#define MDT_YR 2006 +#define MDT_MON 2 + +static void sd_set_cid(SDState *sd) +{ + sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */ + sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */ + sd->cid[2] = OID[1]; + sd->cid[3] = PNM[0]; /* Fake product name (PNM) */ + sd->cid[4] = PNM[1]; + sd->cid[5] = PNM[2]; + sd->cid[6] = PNM[3]; + sd->cid[7] = PNM[4]; + sd->cid[8] = PRV; /* Fake product revision (PRV) */ + sd->cid[9] = 0xde; /* Fake serial number (PSN) */ + sd->cid[10] = 0xad; + sd->cid[11] = 0xbe; + sd->cid[12] = 0xef; + sd->cid[13] = 0x00 | /* Manufacture date (MDT) */ + ((MDT_YR - 2000) / 10); + sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON; + sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1; +} + +#define HWBLOCK_SHIFT 9 /* 512 bytes */ +#define SECTOR_SHIFT 5 /* 16 kilobytes */ +#define WPGROUP_SHIFT 7 /* 2 megs */ +#define CMULT_SHIFT 9 /* 512 times HWBLOCK_SIZE */ +#define BLOCK_SIZE (1 << (HWBLOCK_SHIFT)) +#define SECTOR_SIZE (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT)) +#define WPGROUP_SIZE (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + +static const uint8_t sd_csd_rw_mask[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, +}; + +static void sd_set_csd(SDState *sd, uint32_t size) +{ + uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1; + uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1; + uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1; + + sd->csd[0] = 0x00; /* CSD structure */ + sd->csd[1] = 0x26; /* Data read access-time-1 */ + sd->csd[2] = 0x00; /* Data read access-time-2 */ + sd->csd[3] = 0x5a; /* Max. data transfer rate */ + sd->csd[4] = 0x5f; /* Card Command Classes */ + sd->csd[5] = 0x50 | /* Max. read data block length */ + HWBLOCK_SHIFT; + sd->csd[6] = 0xe0 | /* Partial block for read allowed */ + ((csize >> 10) & 0x03); + sd->csd[7] = 0x00 | /* Device size */ + ((csize >> 2) & 0xff); + sd->csd[8] = 0x3f | /* Max. read current */ + ((csize << 6) & 0xc0); + sd->csd[9] = 0xfc | /* Max. write current */ + ((CMULT_SHIFT - 2) >> 1); + sd->csd[10] = 0x40 | /* Erase sector size */ + (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1); + sd->csd[11] = 0x00 | /* Write protect group size */ + ((sectsize << 7) & 0x80) | wpsize; + sd->csd[12] = 0x90 | /* Write speed factor */ + (HWBLOCK_SHIFT >> 2); + sd->csd[13] = 0x20 | /* Max. write data block length */ + ((HWBLOCK_SHIFT << 6) & 0xc0); + sd->csd[14] = 0x00; /* File format group */ + sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1; +} + +static void sd_set_rca(SDState *sd) +{ + sd->rca += 0x4567; +} + +#define CARD_STATUS_A 0x02004100 +#define CARD_STATUS_B 0x00c01e00 +#define CARD_STATUS_C 0xfd39a028 + +static void sd_set_cardstatus(SDState *sd) +{ + sd->card_status = 0x00000100; +} + +static void sd_set_sdstatus(SDState *sd) +{ + memset(sd->sd_status, 0, 64); +} + +static int sd_req_crc_validate(struct sd_request_s *req) +{ + uint8_t buffer[5]; + buffer[0] = 0x40 | req->cmd; + buffer[1] = (req->arg >> 24) & 0xff; + buffer[2] = (req->arg >> 16) & 0xff; + buffer[3] = (req->arg >> 8) & 0xff; + buffer[4] = (req->arg >> 0) & 0xff; + return 0; + return sd_crc7(buffer, 5) != req->crc; /* TODO */ +} + +void sd_response_r1_make(SDState *sd, + uint8_t *response, uint32_t last_status) +{ + uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND; + uint32_t status; + + status = (sd->card_status & ~mask) | (last_status & mask); + sd->card_status &= ~CARD_STATUS_C | APP_CMD; + + response[0] = (status >> 24) & 0xff; + response[1] = (status >> 16) & 0xff; + response[2] = (status >> 8) & 0xff; + response[3] = (status >> 0) & 0xff; +} + +void sd_response_r3_make(SDState *sd, uint8_t *response) +{ + response[0] = (sd->ocr >> 24) & 0xff; + response[1] = (sd->ocr >> 16) & 0xff; + response[2] = (sd->ocr >> 8) & 0xff; + response[3] = (sd->ocr >> 0) & 0xff; +} + +void sd_response_r6_make(SDState *sd, uint8_t *response) +{ + uint16_t arg; + uint16_t status; + + arg = sd->rca; + status = ((sd->card_status >> 8) & 0xc000) | + ((sd->card_status >> 6) & 0x2000) | + (sd->card_status & 0x1fff); + + response[0] = (arg >> 8) & 0xff; + response[1] = arg & 0xff; + response[2] = (status >> 8) & 0xff; + response[3] = status & 0xff; +} + +static void sd_reset(SDState *sd, BlockDriverState *bdrv) +{ + uint32_t size; + uint64_t sect; + + bdrv_get_geometry(bdrv, §); + sect <<= 9; + + if (sect > 0x40000000) + size = 0x40000000; /* 1 gig */ + else + size = sect + 1; + + sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1; + + sd->state = sd_idle_state; + sd->rca = 0x0000; + sd_set_ocr(sd); + sd_set_scr(sd); + sd_set_cid(sd); + sd_set_csd(sd, size); + sd_set_cardstatus(sd); + sd_set_sdstatus(sd); + + sd->bdrv = bdrv; + + sd->wp_switch = bdrv_is_read_only(bdrv); + sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect); + memset(sd->wp_groups, 0, sizeof(int) * sect); + memset(sd->function_group, 0, sizeof(int) * 6); + sd->erase_start = 0; + sd->erase_end = 0; + sd->size = size; + sd->blk_len = 0x200; + sd->pwd_len = 0; +} + +static void sd_cardchange(void *opaque) +{ + SDState *sd = opaque; + if (sd->inserted_cb) + sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv)); + if (bdrv_is_inserted(sd->bdrv)) { + sd_reset(sd, sd->bdrv); + if (sd->readonly_cb) + sd->readonly_cb(sd->opaque, sd->wp_switch); + } +} + +SDState *sd_init(BlockDriverState *bs) +{ + SDState *sd; + + sd = (SDState *) qemu_mallocz(sizeof(SDState)); + sd_reset(sd, bs); + return sd; +} + +void sd_set_cb(SDState *sd, void *opaque, + void (*readonly_cb)(void *, int), + void (*inserted_cb)(void *, int)) +{ + sd->opaque = opaque; + sd->readonly_cb = readonly_cb; + sd->inserted_cb = inserted_cb; + if (sd->readonly_cb) + sd->readonly_cb(sd->opaque, bdrv_is_read_only(sd->bdrv)); + if (sd->inserted_cb) + sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv)); + bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd); +} + +static void sd_erase(SDState *sd) +{ + int i, start, end; + if (!sd->erase_start || !sd->erase_end) { + sd->card_status |= ERASE_SEQ_ERROR; + return; + } + + start = sd->erase_start >> + (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT); + end = sd->erase_end >> + (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT); + sd->erase_start = 0; + sd->erase_end = 0; + sd->csd[14] |= 0x40; + + for (i = start; i <= end; i ++) + if (sd->wp_groups[i]) + sd->card_status |= WP_ERASE_SKIP; +} + +static uint32_t sd_wpbits(SDState *sd, uint32_t addr) +{ + uint32_t i, wpnum; + uint32_t ret = 0; + + wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT); + + for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE) + if (addr < sd->size && sd->wp_groups[wpnum]) + ret |= (1 << i); + + return ret; +} + +static void sd_function_switch(SDState *sd, uint32_t arg) +{ + int i, mode, new_func, crc; + mode = !!(arg & 0x80000000); + + sd->data[0] = 0x00; /* Maximum current consumption */ + sd->data[1] = 0x01; + sd->data[2] = 0x80; /* Supported group 6 functions */ + sd->data[3] = 0x01; + sd->data[4] = 0x80; /* Supported group 5 functions */ + sd->data[5] = 0x01; + sd->data[6] = 0x80; /* Supported group 4 functions */ + sd->data[7] = 0x01; + sd->data[8] = 0x80; /* Supported group 3 functions */ + sd->data[9] = 0x01; + sd->data[10] = 0x80; /* Supported group 2 functions */ + sd->data[11] = 0x43; + sd->data[12] = 0x80; /* Supported group 1 functions */ + sd->data[13] = 0x03; + for (i = 0; i < 6; i ++) { + new_func = (arg >> (i * 4)) & 0x0f; + if (mode && new_func != 0x0f) + sd->function_group[i] = new_func; + sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4); + } + memset(&sd->data[17], 0, 47); + crc = sd_crc16(sd->data, 64); + sd->data[65] = crc >> 8; + sd->data[66] = crc & 0xff; +} + +static inline int sd_wp_addr(SDState *sd, uint32_t addr) +{ + return sd->wp_groups[addr >> + (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)]; +} + +static void sd_lock_command(SDState *sd) +{ + int erase, lock, clr_pwd, set_pwd, pwd_len; + erase = !!(sd->data[0] & 0x08); + lock = sd->data[0] & 0x04; + clr_pwd = sd->data[0] & 0x02; + set_pwd = sd->data[0] & 0x01; + + if (sd->blk_len > 1) + pwd_len = sd->data[1]; + else + pwd_len = 0; + + if (erase) { + if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 || + set_pwd || clr_pwd || lock || sd->wp_switch || + (sd->csd[14] & 0x20)) { + sd->card_status |= LOCK_UNLOCK_FAILED; + return; + } + memset(sd->wp_groups, 0, sizeof(int) * (sd->size >> + (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT))); + sd->csd[14] &= ~0x10; + sd->card_status &= ~CARD_IS_LOCKED; + sd->pwd_len = 0; + /* Erasing the entire card here! */ + printf("SD: Card force-erased by CMD42\n"); + return; + } + + if (sd->blk_len < 2 + pwd_len || + pwd_len <= sd->pwd_len || + pwd_len > sd->pwd_len + 16) { + sd->card_status |= LOCK_UNLOCK_FAILED; + return; + } + + if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) { + sd->card_status |= LOCK_UNLOCK_FAILED; + return; + } + + pwd_len -= sd->pwd_len; + if ((pwd_len && !set_pwd) || + (clr_pwd && (set_pwd || lock)) || + (lock && !sd->pwd_len && !set_pwd) || + (!set_pwd && !clr_pwd && + (((sd->card_status & CARD_IS_LOCKED) && lock) || + (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) { + sd->card_status |= LOCK_UNLOCK_FAILED; + return; + } + + if (set_pwd) { + memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len); + sd->pwd_len = pwd_len; + } + + if (clr_pwd) { + sd->pwd_len = 0; + } + + if (lock) + sd->card_status |= CARD_IS_LOCKED; + else + sd->card_status &= ~CARD_IS_LOCKED; +} + +static sd_rsp_type_t sd_normal_command(SDState *sd, + struct sd_request_s req) +{ + uint32_t rca = 0x0000; + + if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc) + rca = req.arg >> 16; + + DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state); + switch (req.cmd) { + /* Basic commands (Class 0 and Class 1) */ + case 0: /* CMD0: GO_IDLE_STATE */ + switch (sd->state) { + case sd_inactive_state: + return sd_r0; + + default: + sd->state = sd_idle_state; + sd_reset(sd, sd->bdrv); + return sd_r0; + } + break; + + case 2: /* CMD2: ALL_SEND_CID */ + switch (sd->state) { + case sd_ready_state: + sd->state = sd_identification_state; + return sd_r2_i; + + default: + break; + } + break; + + case 3: /* CMD3: SEND_RELATIVE_ADDR */ + switch (sd->state) { + case sd_identification_state: + case sd_standby_state: + sd->state = sd_standby_state; + sd_set_rca(sd); + return sd_r6; + + default: + break; + } + break; + + case 4: /* CMD4: SEND_DSR */ + switch (sd->state) { + case sd_standby_state: + break; + + default: + break; + } + break; + + case 6: /* CMD6: SWITCH_FUNCTION */ + switch (sd->mode) { + case sd_data_transfer_mode: + sd_function_switch(sd, req.arg); + sd->state = sd_sendingdata_state; + sd->data_start = 0; + sd->data_offset = 0; + return sd_r1; + + default: + break; + } + break; + + case 7: /* CMD7: SELECT/DESELECT_CARD */ + switch (sd->state) { + case sd_standby_state: + if (sd->rca != rca) + return sd_r0; + + sd->state = sd_transfer_state; + return sd_r1b; + + case sd_transfer_state: + case sd_sendingdata_state: + if (sd->rca == rca) + break; + + sd->state = sd_standby_state; + return sd_r1b; + + case sd_disconnect_state: + if (sd->rca != rca) + return sd_r0; + + sd->state = sd_programming_state; + return sd_r1b; + + case sd_programming_state: + if (sd->rca == rca) + break; + + sd->state = sd_disconnect_state; + return sd_r1b; + + default: + break; + } + break; + + case 9: /* CMD9: SEND_CSD */ + switch (sd->state) { + case sd_standby_state: + if (sd->rca != rca) + return sd_r0; + + return sd_r2_s; + + default: + break; + } + break; + + case 10: /* CMD10: SEND_CID */ + switch (sd->state) { + case sd_standby_state: + if (sd->rca != rca) + return sd_r0; + + return sd_r2_i; + + default: + break; + } + break; + + case 11: /* CMD11: READ_DAT_UNTIL_STOP */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_sendingdata_state; + sd->data_start = req.arg; + sd->data_offset = 0; + + if (sd->data_start + sd->blk_len > sd->size) + sd->card_status |= ADDRESS_ERROR; + return sd_r0; + + default: + break; + } + break; + + case 12: /* CMD12: STOP_TRANSMISSION */ + switch (sd->state) { + case sd_sendingdata_state: + sd->state = sd_transfer_state; + return sd_r1b; + + case sd_receivingdata_state: + sd->state = sd_programming_state; + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_transfer_state; + return sd_r1b; + + default: + break; + } + break; + + case 13: /* CMD13: SEND_STATUS */ + switch (sd->mode) { + case sd_data_transfer_mode: + if (sd->rca != rca) + return sd_r0; + + return sd_r1; + + default: + break; + } + break; + + case 15: /* CMD15: GO_INACTIVE_STATE */ + switch (sd->mode) { + case sd_data_transfer_mode: + if (sd->rca != rca) + return sd_r0; + + sd->state = sd_inactive_state; + return sd_r0; + + default: + break; + } + break; + + /* Block read commands (Classs 2) */ + case 16: /* CMD16: SET_BLOCKLEN */ + switch (sd->state) { + case sd_transfer_state: + if (req.arg > (1 << HWBLOCK_SHIFT)) + sd->card_status |= BLOCK_LEN_ERROR; + else + sd->blk_len = req.arg; + + return sd_r1; + + default: + break; + } + break; + + case 17: /* CMD17: READ_SINGLE_BLOCK */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_sendingdata_state; + sd->data_start = req.arg; + sd->data_offset = 0; + + if (sd->data_start + sd->blk_len > sd->size) + sd->card_status |= ADDRESS_ERROR; + return sd_r1; + + default: + break; + } + break; + + case 18: /* CMD18: READ_MULTIPLE_BLOCK */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_sendingdata_state; + sd->data_start = req.arg; + sd->data_offset = 0; + + if (sd->data_start + sd->blk_len > sd->size) + sd->card_status |= ADDRESS_ERROR; + return sd_r1; + + default: + break; + } + break; + + /* Block write commands (Class 4) */ + case 24: /* CMD24: WRITE_SINGLE_BLOCK */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_receivingdata_state; + sd->data_start = req.arg; + sd->data_offset = 0; + sd->blk_written = 0; + + if (sd->data_start + sd->blk_len > sd->size) + sd->card_status |= ADDRESS_ERROR; + if (sd_wp_addr(sd, sd->data_start)) + sd->card_status |= WP_VIOLATION; + if (sd->csd[14] & 0x30) + sd->card_status |= WP_VIOLATION; + return sd_r1; + + default: + break; + } + break; + + case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_receivingdata_state; + sd->data_start = req.arg; + sd->data_offset = 0; + sd->blk_written = 0; + + if (sd->data_start + sd->blk_len > sd->size) + sd->card_status |= ADDRESS_ERROR; + if (sd_wp_addr(sd, sd->data_start)) + sd->card_status |= WP_VIOLATION; + if (sd->csd[14] & 0x30) + sd->card_status |= WP_VIOLATION; + return sd_r1; + + default: + break; + } + break; + + case 26: /* CMD26: PROGRAM_CID */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_receivingdata_state; + sd->data_start = 0; + sd->data_offset = 0; + return sd_r1; + + default: + break; + } + break; + + case 27: /* CMD27: PROGRAM_CSD */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_receivingdata_state; + sd->data_start = 0; + sd->data_offset = 0; + return sd_r1; + + default: + break; + } + break; + + /* Write protection (Class 6) */ + case 28: /* CMD28: SET_WRITE_PROT */ + switch (sd->state) { + case sd_transfer_state: + if (req.arg >= sd->size) { + sd->card_status = ADDRESS_ERROR; + return sd_r1b; + } + + sd->state = sd_programming_state; + sd->wp_groups[req.arg >> (HWBLOCK_SHIFT + + SECTOR_SHIFT + WPGROUP_SHIFT)] = 1; + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_transfer_state; + return sd_r1b; + + default: + break; + } + break; + + case 29: /* CMD29: CLR_WRITE_PROT */ + switch (sd->state) { + case sd_transfer_state: + if (req.arg >= sd->size) { + sd->card_status = ADDRESS_ERROR; + return sd_r1b; + } + + sd->state = sd_programming_state; + sd->wp_groups[req.arg >> (HWBLOCK_SHIFT + + SECTOR_SHIFT + WPGROUP_SHIFT)] = 0; + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_transfer_state; + return sd_r1b; + + default: + break; + } + break; + + case 30: /* CMD30: SEND_WRITE_PROT */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_sendingdata_state; + *(uint32_t *) sd->data = sd_wpbits(sd, req.arg); + sd->data_start = req.arg; + sd->data_offset = 0; + return sd_r1b; + + default: + break; + } + break; + + /* Erase commands (Class 5) */ + case 32: /* CMD32: ERASE_WR_BLK_START */ + switch (sd->state) { + case sd_transfer_state: + sd->erase_start = req.arg; + return sd_r1; + + default: + break; + } + break; + + case 33: /* CMD33: ERASE_WR_BLK_END */ + switch (sd->state) { + case sd_transfer_state: + sd->erase_end = req.arg; + return sd_r1; + + default: + break; + } + break; + + case 38: /* CMD38: ERASE */ + switch (sd->state) { + case sd_transfer_state: + if (sd->csd[14] & 0x30) { + sd->card_status |= WP_VIOLATION; + return sd_r1b; + } + + sd->state = sd_programming_state; + sd_erase(sd); + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_transfer_state; + return sd_r1b; + + default: + break; + } + break; + + /* Lock card commands (Class 7) */ + case 42: /* CMD42: LOCK_UNLOCK */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_receivingdata_state; + sd->data_start = 0; + sd->data_offset = 0; + return sd_r1; + + default: + break; + } + break; + + /* Application specific commands (Class 8) */ + case 55: /* CMD55: APP_CMD */ + if (sd->rca != rca) + return sd_r0; + + sd->card_status |= APP_CMD; + return sd_r1; + + case 56: /* CMD56: GEN_CMD */ + printf("SD: GEN_CMD 0x%08x\n", req.arg); + + switch (sd->state) { + case sd_transfer_state: + sd->data_offset = 0; + if (req.arg & 1) + sd->state = sd_sendingdata_state; + else + sd->state = sd_receivingdata_state; + return sd_r1; + + default: + break; + } + break; + + default: + sd->card_status |= ILLEGAL_COMMAND; + + printf("SD: Unknown CMD%i\n", req.cmd); + return sd_r0; + } + + sd->card_status |= ILLEGAL_COMMAND; + printf("SD: CMD%i in a wrong state\n", req.cmd); + return sd_r0; +} + +static sd_rsp_type_t sd_app_command(SDState *sd, + struct sd_request_s req) { + uint32_t rca; + + if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc) + rca = req.arg >> 16; + + DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg); + switch (req.cmd) { + case 6: /* ACMD6: SET_BUS_WIDTH */ + switch (sd->state) { + case sd_transfer_state: + sd->sd_status[0] &= 0x3f; + sd->sd_status[0] |= (req.arg & 0x03) << 6; + return sd_r1; + + default: + break; + } + break; + + case 13: /* ACMD13: SD_STATUS */ + switch (sd->state) { + case sd_transfer_state: + sd->data_start = 0; + sd->data_offset = 0; + return sd_r1; + + default: + break; + } + break; + + case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ + switch (sd->state) { + case sd_transfer_state: + *(uint32_t *) sd->data = sd->blk_written; + + sd->data_start = 0; + sd->data_offset = 0; + return sd_r1; + + default: + break; + } + break; + + case 23: /* ACMD23: SET_WR_BLK_ERASE_COUNT */ + switch (sd->state) { + case sd_transfer_state: + return sd_r1; + + default: + break; + } + break; + + case 41: /* ACMD41: SD_APP_OP_COND */ + switch (sd->state) { + case sd_idle_state: + /* We accept any voltage. 10000 V is nothing. */ + if (req.arg) + sd->state = sd_ready_state; + + return sd_r3; + + default: + break; + } + break; + + case 42: /* ACMD42: SET_CLR_CARD_DETECT */ + switch (sd->state) { + case sd_transfer_state: + /* Bringing in the 50KOhm pull-up resistor... Done. */ + return sd_r1; + + default: + break; + } + break; + + case 51: /* ACMD51: SEND_SCR */ + switch (sd->state) { + case sd_transfer_state: + sd->state = sd_sendingdata_state; + sd->data_start = 0; + sd->data_offset = 0; + return sd_r1; + + default: + break; + } + break; + + default: + /* Fall back to standard commands. */ + sd->card_status &= ~APP_CMD; + return sd_normal_command(sd, req); + } + + printf("SD: ACMD%i in a wrong state\n", req.cmd); + return sd_r0; +} + +int sd_do_command(SDState *sd, struct sd_request_s *req, + uint8_t *response) { + uint32_t last_status = sd->card_status; + sd_rsp_type_t rtype; + int rsplen; + + if (!bdrv_is_inserted(sd->bdrv)) { + return 0; + } + + if (sd_req_crc_validate(req)) { + sd->card_status &= ~COM_CRC_ERROR; + return 0; + } + + sd->card_status &= ~CARD_STATUS_B; + sd_set_status(sd); + + if (last_status & CARD_IS_LOCKED) + if (((last_status & APP_CMD) && + req->cmd == 41) || + (!(last_status & APP_CMD) && + (sd_cmd_class[req->cmd] == 0 || + sd_cmd_class[req->cmd] == 7 || + req->cmd == 16 || req->cmd == 55))) { + sd->card_status |= ILLEGAL_COMMAND; + printf("SD: Card is locked\n"); + return 0; + } + + if (last_status & APP_CMD) + rtype = sd_app_command(sd, *req); + else + rtype = sd_normal_command(sd, *req); + + sd->current_cmd = req->cmd; + + switch (rtype) { + case sd_r1: + case sd_r1b: + sd_response_r1_make(sd, response, last_status); + rsplen = 4; + break; + + case sd_r2_i: + memcpy(response, sd->cid, sizeof(sd->cid)); + response[7] |= 1; + rsplen = 16; + break; + + case sd_r2_s: + memcpy(response, sd->csd, sizeof(sd->csd)); + response[7] |= 1; + rsplen = 16; + break; + + case sd_r3: + sd_response_r3_make(sd, response); + rsplen = 4; + break; + + case sd_r6: + sd_response_r6_make(sd, response); + rsplen = 4; + break; + + case sd_r0: + default: + rsplen = 0; + break; + } + + if (sd->card_status & ILLEGAL_COMMAND) + rsplen = 0; + +#ifdef DEBUG_SD + if (rsplen) { + int i; + DPRINTF("Response:"); + for (i = 0; i < rsplen; i++) + printf(" %02x", response[i]); + printf(" state %d\n", sd->state); + } else { + DPRINTF("No response %d\n", sd->state); + } +#endif + + return rsplen; +} + +/* No real need for 64 bit addresses here */ +static void sd_blk_read(BlockDriverState *bdrv, + void *data, uint32_t addr, uint32_t len) +{ + uint8_t buf[512]; + uint32_t end = addr + len; + + if (!bdrv || bdrv_read(bdrv, addr >> 9, buf, 1) == -1) { + printf("sd_blk_read: read error on host side\n"); + return; + } + + if (end > (addr & ~511) + 512) { + memcpy(data, buf + (addr & 511), 512 - (addr & 511)); + + if (bdrv_read(bdrv, end >> 9, buf, 1) == -1) { + printf("sd_blk_read: read error on host side\n"); + return; + } + memcpy(data + 512 - (addr & 511), buf, end & 511); + } else + memcpy(data, buf + (addr & 511), len); +} + +static void sd_blk_write(BlockDriverState *bdrv, + void *data, uint32_t addr, uint32_t len) +{ + uint8_t buf[512]; + uint32_t end = addr + len; + + if ((addr & 511) || len < 512) + if (!bdrv || bdrv_read(bdrv, addr >> 9, buf, 1) == -1) { + printf("sd_blk_write: read error on host side\n"); + return; + } + + if (end > (addr & ~511) + 512) { + memcpy(buf + (addr & 511), data, 512 - (addr & 511)); + if (bdrv_write(bdrv, addr >> 9, buf, 1) == -1) { + printf("sd_blk_write: write error on host side\n"); + return; + } + + if (bdrv_read(bdrv, end >> 9, buf, 1) == -1) { + printf("sd_blk_write: read error on host side\n"); + return; + } + memcpy(buf, data + 512 - (addr & 511), end & 511); + if (bdrv_write(bdrv, end >> 9, buf, 1) == -1) + printf("sd_blk_write: write error on host side\n"); + } else { + memcpy(buf + (addr & 511), data, len); + if (!bdrv || bdrv_write(bdrv, addr >> 9, buf, 1) == -1) + printf("sd_blk_write: write error on host side\n"); + } +} + +#define BLK_READ_BLOCK(a, len) sd_blk_read(sd->bdrv, sd->data, a, len) +#define BLK_WRITE_BLOCK(a, len) sd_blk_write(sd->bdrv, sd->data, a, len) +#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len) +#define APP_WRITE_BLOCK(a, len) + +void sd_write_data(SDState *sd, uint8_t value) +{ + int i; + + if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv)) + return; + + if (sd->state != sd_receivingdata_state) { + printf("sd_write_data: not in Receiving-Data state\n"); + return; + } + + if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) + return; + + switch (sd->current_cmd) { + case 24: /* CMD24: WRITE_SINGLE_BLOCK */ + sd->data[sd->data_offset ++] = value; + if (sd->data_offset >= sd->blk_len) { + /* TODO: Check CRC before committing */ + sd->state = sd_programming_state; + BLK_WRITE_BLOCK(sd->data_start, sd->data_offset); + sd->blk_written ++; + sd->csd[14] |= 0x40; + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_transfer_state; + } + break; + + case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ + sd->data[sd->data_offset ++] = value; + if (sd->data_offset >= sd->blk_len) { + /* TODO: Check CRC before committing */ + sd->state = sd_programming_state; + BLK_WRITE_BLOCK(sd->data_start, sd->data_offset); + sd->blk_written ++; + sd->data_start += sd->blk_len; + sd->data_offset = 0; + if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; + break; + } + if (sd_wp_addr(sd, sd->data_start)) { + sd->card_status |= WP_VIOLATION; + break; + } + sd->csd[14] |= 0x40; + + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_receivingdata_state; + } + break; + + case 26: /* CMD26: PROGRAM_CID */ + sd->data[sd->data_offset ++] = value; + if (sd->data_offset >= sizeof(sd->cid)) { + /* TODO: Check CRC before committing */ + sd->state = sd_programming_state; + for (i = 0; i < sizeof(sd->cid); i ++) + if ((sd->cid[i] | 0x00) != sd->data[i]) + sd->card_status |= CID_CSD_OVERWRITE; + + if (!(sd->card_status & CID_CSD_OVERWRITE)) + for (i = 0; i < sizeof(sd->cid); i ++) { + sd->cid[i] |= 0x00; + sd->cid[i] &= sd->data[i]; + } + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_transfer_state; + } + break; + + case 27: /* CMD27: PROGRAM_CSD */ + sd->data[sd->data_offset ++] = value; + if (sd->data_offset >= sizeof(sd->csd)) { + /* TODO: Check CRC before committing */ + sd->state = sd_programming_state; + for (i = 0; i < sizeof(sd->csd); i ++) + if ((sd->csd[i] | sd_csd_rw_mask[i]) != + (sd->data[i] | sd_csd_rw_mask[i])) + sd->card_status |= CID_CSD_OVERWRITE; + + /* Copy flag (OTP) & Permanent write protect */ + if (sd->csd[14] & ~sd->data[14] & 0x60) + sd->card_status |= CID_CSD_OVERWRITE; + + if (!(sd->card_status & CID_CSD_OVERWRITE)) + for (i = 0; i < sizeof(sd->csd); i ++) { + sd->csd[i] |= sd_csd_rw_mask[i]; + sd->csd[i] &= sd->data[i]; + } + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_transfer_state; + } + break; + + case 42: /* CMD42: LOCK_UNLOCK */ + sd->data[sd->data_offset ++] = value; + if (sd->data_offset >= sd->blk_len) { + /* TODO: Check CRC before committing */ + sd->state = sd_programming_state; + sd_lock_command(sd); + /* Bzzzzzzztt .... Operation complete. */ + sd->state = sd_transfer_state; + } + break; + + case 56: /* CMD56: GEN_CMD */ + sd->data[sd->data_offset ++] = value; + if (sd->data_offset >= sd->blk_len) { + APP_WRITE_BLOCK(sd->data_start, sd->data_offset); + sd->state = sd_transfer_state; + } + break; + + default: + printf("sd_write_data: unknown command\n"); + break; + } +} + +uint8_t sd_read_data(SDState *sd) +{ + /* TODO: Append CRCs */ + uint8_t ret; + + if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv)) + return 0x00; + + if (sd->state != sd_sendingdata_state) { + printf("sd_read_data: not in Sending-Data state\n"); + return 0x00; + } + + if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) + return 0x00; + + switch (sd->current_cmd) { + case 6: /* CMD6: SWITCH_FUNCTION */ + ret = sd->data[sd->data_offset ++]; + + if (sd->data_offset >= 64) + sd->state = sd_transfer_state; + break; + + case 11: /* CMD11: READ_DAT_UNTIL_STOP */ + if (sd->data_offset == 0) + BLK_READ_BLOCK(sd->data_start, sd->blk_len); + ret = sd->data[sd->data_offset ++]; + + if (sd->data_offset >= sd->blk_len) { + sd->data_start += sd->blk_len; + sd->data_offset = 0; + if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; + break; + } + } + break; + + case 13: /* ACMD13: SD_STATUS */ + ret = sd->sd_status[sd->data_offset ++]; + + if (sd->data_offset >= sizeof(sd->sd_status)) + sd->state = sd_transfer_state; + break; + + case 17: /* CMD17: READ_SINGLE_BLOCK */ + if (sd->data_offset == 0) + BLK_READ_BLOCK(sd->data_start, sd->blk_len); + ret = sd->data[sd->data_offset ++]; + + if (sd->data_offset >= sd->blk_len) + sd->state = sd_transfer_state; + break; + + case 18: /* CMD18: READ_MULTIPLE_BLOCK */ + if (sd->data_offset == 0) + BLK_READ_BLOCK(sd->data_start, sd->blk_len); + ret = sd->data[sd->data_offset ++]; + + if (sd->data_offset >= sd->blk_len) { + sd->data_start += sd->blk_len; + sd->data_offset = 0; + if (sd->data_start + sd->blk_len > sd->size) { + sd->card_status |= ADDRESS_ERROR; + break; + } + } + break; + + case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */ + ret = sd->data[sd->data_offset ++]; + + if (sd->data_offset >= 4) + sd->state = sd_transfer_state; + break; + + case 30: /* CMD30: SEND_WRITE_PROT */ + ret = sd->data[sd->data_offset ++]; + + if (sd->data_offset >= 4) + sd->state = sd_transfer_state; + break; + + case 51: /* ACMD51: SEND_SCR */ + ret = sd->scr[sd->data_offset ++]; + + if (sd->data_offset >= sizeof(sd->scr)) + sd->state = sd_transfer_state; + break; + + case 56: /* CMD56: GEN_CMD */ + if (sd->data_offset == 0) + APP_READ_BLOCK(sd->data_start, sd->blk_len); + ret = sd->data[sd->data_offset ++]; + + if (sd->data_offset >= sd->blk_len) + sd->state = sd_transfer_state; + break; + + default: + printf("sd_read_data: unknown command\n"); + return 0x00; + } + + return ret; +} + +int sd_data_ready(SDState *sd) +{ + return sd->state == sd_sendingdata_state; +} diff --git a/hw/sd.h b/hw/sd.h new file mode 100644 index 000000000..cc05dbf17 --- /dev/null +++ b/hw/sd.h @@ -0,0 +1,82 @@ +/* + * SD Memory Card emulation. Mostly correct for MMC too. + * + * Copyright (c) 2006 Andrzej Zaborowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + */ +#ifndef __hw_sd_h +#define __hw_sd_h 1 + +#include + +#define OUT_OF_RANGE (1 << 31) +#define ADDRESS_ERROR (1 << 30) +#define BLOCK_LEN_ERROR (1 << 29) +#define ERASE_SEQ_ERROR (1 << 28) +#define ERASE_PARAM (1 << 27) +#define WP_VIOLATION (1 << 26) +#define CARD_IS_LOCKED (1 << 25) +#define LOCK_UNLOCK_FAILED (1 << 24) +#define COM_CRC_ERROR (1 << 23) +#define ILLEGAL_COMMAND (1 << 22) +#define CARD_ECC_FAILED (1 << 21) +#define CC_ERROR (1 << 20) +#define SD_ERROR (1 << 19) +#define CID_CSD_OVERWRITE (1 << 16) +#define WP_ERASE_SKIP (1 << 15) +#define CARD_ECC_DISABLED (1 << 14) +#define ERASE_RESET (1 << 13) +#define CURRENT_STATE (7 << 9) +#define READY_FOR_DATA (1 << 8) +#define APP_CMD (1 << 5) +#define AKE_SEQ_ERROR (1 << 3) + +typedef enum { + sd_none = -1, + sd_bc = 0, /* broadcast -- no response */ + sd_bcr, /* broadcast with response */ + sd_ac, /* addressed -- no data transfer */ + sd_adtc, /* addressed with data transfer */ +} sd_cmd_type_t; + +struct sd_request_s { + uint8_t cmd; + uint32_t arg; + uint8_t crc; +}; + +typedef struct SDState SDState; + +SDState *sd_init(BlockDriverState *bs); +int sd_do_command(SDState *sd, struct sd_request_s *req, + uint8_t *response); +void sd_write_data(SDState *sd, uint8_t value); +uint8_t sd_read_data(SDState *sd); +void sd_set_cb(SDState *sd, void *opaque, + void (*readonly_cb)(void *, int), + void (*inserted_cb)(void *, int)); +int sd_data_ready(SDState *sd); + +#endif /* __hw_sd_h */ diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 5d3e857ee..a91d7eff8 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -1,7 +1,7 @@ /* * ARM Versatile Platform/Application Baseboard System emulation. * - * Copyright (c) 2005-2006 CodeSourcery. + * Copyright (c) 2005-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL. @@ -217,19 +217,25 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, that includes hardware cursor support from the PL111. */ pl110_init(ds, 0x10120000, pic, 16, 1); + pl181_init(0x10005000, sd_bdrv, sic, 22, 1); +#if 0 + /* Disabled because there's no way of specifying a block device. */ + pl181_init(0x1000b000, NULL, sic, 23, 2); +#endif + /* Memory map for Versatile/PB: */ /* 0x10000000 System registers. */ /* 0x10001000 PCI controller config registers. */ /* 0x10002000 Serial bus interface. */ /* 0x10003000 Secondary interrupt controller. */ /* 0x10004000 AACI (audio). */ - /* 0x10005000 MMCI0. */ + /* 0x10005000 MMCI0. */ /* 0x10006000 KMI0 (keyboard). */ /* 0x10007000 KMI1 (mouse). */ /* 0x10008000 Character LCD Interface. */ /* 0x10009000 UART3. */ /* 0x1000a000 Smart card 1. */ - /* 0x1000b000 MMCI1. */ + /* 0x1000b000 MMCI1. */ /* 0x10010000 Ethernet. */ /* 0x10020000 USB. */ /* 0x10100000 SSMC. */ diff --git a/qemu-doc.texi b/qemu-doc.texi index 5db875c56..b5c913197 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1719,6 +1719,8 @@ SMC 91c111 Ethernet adapter PL110 LCD controller @item PL050 KMI with PS/2 keyboard and mouse. +@item +PL181 MultiMedia Card Interface with SD card. @end itemize The ARM Versatile baseboard is emulated with the following devices: @@ -1746,6 +1748,8 @@ mapped control registers. PCI OHCI USB controller. @item LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices. +@item +PL181 MultiMedia Card Interface with SD card. @end itemize The ARM RealView Emulation baseboard is emulated with the following devices: @@ -1769,6 +1773,8 @@ PCI host bridge PCI OHCI USB controller @item LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices +@item +PL181 MultiMedia Card Interface with SD card. @end itemize A Linux 2.6 test image is available on the QEMU web site. More diff --git a/vl.c b/vl.c index 355f7ff82..853b8911e 100644 --- a/vl.c +++ b/vl.c @@ -138,6 +138,7 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; /* Note: bs_table[MAX_DISKS] is a dummy block driver if none available to store the VM snapshots */ BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; +BlockDriverState *sd_bdrv; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; int vga_ram_size; @@ -6345,6 +6346,7 @@ void help(void) "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" + "-sd file use 'file' as SecureDigital card image\n" "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" "-snapshot write to temporary files instead of disk image files\n" #ifdef CONFIG_SDL @@ -6482,6 +6484,7 @@ enum { QEMU_OPTION_hdc, QEMU_OPTION_hdd, QEMU_OPTION_cdrom, + QEMU_OPTION_sd, QEMU_OPTION_boot, QEMU_OPTION_snapshot, #ifdef TARGET_I386 @@ -6560,6 +6563,7 @@ const QEMUOption qemu_options[] = { { "hdc", HAS_ARG, QEMU_OPTION_hdc }, { "hdd", HAS_ARG, QEMU_OPTION_hdd }, { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, + { "sd", HAS_ARG, QEMU_OPTION_sd }, { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, #ifdef TARGET_I386 @@ -6847,6 +6851,7 @@ int main(int argc, char **argv) int snapshot, linux_boot; const char *initrd_filename; const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; + const char *sd_filename; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; @@ -6907,6 +6912,7 @@ int main(int argc, char **argv) fd_filename[i] = NULL; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; + sd_filename = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; #ifdef CONFIG_GDBSTUB @@ -7025,6 +7031,9 @@ int main(int argc, char **argv) cdrom_index = -1; } break; + case QEMU_OPTION_sd: + sd_filename = optarg; + break; case QEMU_OPTION_snapshot: snapshot = 1; break; @@ -7523,7 +7532,7 @@ int main(int argc, char **argv) fd_table[i] = bdrv_new(buf); bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY); } - if (fd_filename[i] != '\0') { + if (fd_filename[i][0] != '\0') { if (bdrv_open(fd_table[i], fd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { fprintf(stderr, "qemu: could not open floppy disk image '%s'\n", @@ -7534,6 +7543,18 @@ int main(int argc, char **argv) } } + sd_bdrv = bdrv_new ("sd"); + /* FIXME: This isn't really a floppy, but it's a reasonable + approximation. */ + bdrv_set_type_hint(sd_bdrv, BDRV_TYPE_FLOPPY); + if (sd_filename) { + if (bdrv_open(sd_bdrv, sd_filename, + snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { + fprintf(stderr, "qemu: could not open SD card image %s\n", + sd_filename); + } + } + register_savevm("timer", 0, 2, timer_save, timer_load, NULL); register_savevm("ram", 0, 2, ram_save, ram_load, NULL); diff --git a/vl.h b/vl.h index d44d6aa00..eb87a511a 100644 --- a/vl.h +++ b/vl.h @@ -956,6 +956,7 @@ extern uint8_t _translate_keycode(const int key); #define MAX_DISKS 4 extern BlockDriverState *bs_table[MAX_DISKS + 1]; +extern BlockDriverState *sd_bdrv; void isa_ide_init(int iobase, int iobase2, int irq, BlockDriverState *hd0, BlockDriverState *hd1); @@ -1385,6 +1386,10 @@ void pl050_init(uint32_t base, void *pic, int irq, int is_mouse); /* pl080.c */ void *pl080_init(uint32_t base, void *pic, int irq, int nchannels); +/* pl181.c */ +void pl181_init(uint32_t base, BlockDriverState *bd, + void *pic, int irq0, int irq1); + /* pl190.c */ void *pl190_init(uint32_t base, void *parent, int irq, int fiq); -- cgit v1.2.3 From 42a10898a8247821d161e3ac799b758f79fbe3b3 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 6 Apr 2007 16:54:11 +0000 Subject: Use correct type for card field. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2621 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl181.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pl181.c b/hw/pl181.c index 7912c280b..7c3b5de4c 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -22,7 +22,7 @@ do { printf("pl181: " fmt , ##args); } while (0) #define PL181_FIFO_LEN 16 typedef struct { - struct sd_state_s *card; + SDState *card; uint32_t base; uint32_t clock; uint32_t power; -- cgit v1.2.3 From f41c52f17031325652387086006c5847bc703abd Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 6 Apr 2007 18:46:01 +0000 Subject: Save state for all CP0 instructions, they may throw a CPU exception. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2622 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 22 +++++++++++++++++----- target-mips/op_helper.c | 38 +++++++++++++++++++++++++++----------- target-mips/translate.c | 1 + 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index d440896f3..5048bc0f9 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1360,9 +1360,14 @@ void op_mtc0_status (void) no 64bit addressing implemented. */ val = (int32_t)T0 & 0xF878FF17; old = env->CP0_Status; + if (!(val & (1 << CP0St_EXL)) && + !(val & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM) && + (val & (1 << CP0St_UM))) + env->hflags |= MIPS_HFLAG_UM; env->CP0_Status = val; - if (loglevel & CPU_LOG_TB_IN_ASM) - CALL_FROM_TB2(do_mtc0_status_debug, old, val); + if (loglevel & CPU_LOG_EXEC) + CALL_FROM_TB2(do_mtc0_status_debug, old, val); CALL_FROM_TB1(cpu_mips_update_irq, env); RETURN(); } @@ -2077,10 +2082,12 @@ void op_set_lladdr (void) RETURN(); } -void debug_eret (void); +void debug_pre_eret (void); +void debug_post_eret (void); void op_eret (void) { - CALL_FROM_TB0(debug_eret); + if (loglevel & CPU_LOG_EXEC) + CALL_FROM_TB0(debug_pre_eret); if (env->CP0_Status & (1 << CP0St_ERL)) { env->PC = env->CP0_ErrorEPC; env->CP0_Status &= ~(1 << CP0St_ERL); @@ -2093,13 +2100,16 @@ void op_eret (void) !(env->hflags & MIPS_HFLAG_DM) && (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; + if (loglevel & CPU_LOG_EXEC) + CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; RETURN(); } void op_deret (void) { - CALL_FROM_TB0(debug_eret); + if (loglevel & CPU_LOG_EXEC) + CALL_FROM_TB0(debug_pre_eret); env->PC = env->CP0_DEPC; env->hflags |= MIPS_HFLAG_DM; if (!(env->CP0_Status & (1 << CP0St_EXL)) && @@ -2107,6 +2117,8 @@ void op_deret (void) !(env->hflags & MIPS_HFLAG_DM) && (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; + if (loglevel & CPU_LOG_EXEC) + CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index ba02f0d84..92712a899 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -329,10 +329,12 @@ void do_mfc0_count (void) void do_mtc0_status_debug(uint32_t old, uint32_t val) { - const uint32_t mask = 0x0000FF00; - fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n", - old, val, env->CP0_Cause, old & mask, val & mask, - env->CP0_Cause & mask); + fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x", + old, old & env->CP0_Cause & CP0Ca_IP_mask, + val, val & env->CP0_Cause & CP0Ca_IP_mask, + env->CP0_Cause); + (env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile) + : fputs("\n", logfile); } void do_mtc0_status_irqraise_debug(void) @@ -508,15 +510,29 @@ void dump_sc (void) } } -void debug_eret (void) +void debug_pre_eret (void) { - if (loglevel) { - fprintf(logfile, "ERET: pc " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->PC, env->CP0_EPC); - if (env->CP0_Status & (1 << CP0St_ERL)) - fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); + fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, + env->PC, env->CP0_EPC); + if (env->CP0_Status & (1 << CP0St_ERL)) + fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); + if (env->hflags & MIPS_HFLAG_DM) + fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC); + fputs("\n", logfile); +} + +void debug_post_eret (void) +{ + fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, + env->PC, env->CP0_EPC); + if (env->CP0_Status & (1 << CP0St_ERL)) + fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); + if (env->hflags & MIPS_HFLAG_DM) + fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC); + if (env->hflags & MIPS_HFLAG_UM) + fputs(", UM\n", logfile); + else fputs("\n", logfile); - } } void do_pmon (int function) diff --git a/target-mips/translate.c b/target-mips/translate.c index 8da8cc403..f3b2de446 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4880,6 +4880,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_CP0: + save_cpu_state(ctx, 1); gen_op_cp0_enabled(); op1 = MASK_CP0(ctx->opcode); switch (op1) { -- cgit v1.2.3 From beb811bdd693ff1e2fe5c6c81e65b0b8e9053755 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 6 Apr 2007 19:31:06 +0000 Subject: Fix handling of ADES exceptions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2623 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 0cda1ef54..d48c32b22 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -339,9 +339,11 @@ void do_interrupt (CPUState *env) /* XXX: TODO: manage defered watch exceptions */ goto set_EPC; case EXCP_AdEL: - case EXCP_AdES: cause = 4; goto set_EPC; + case EXCP_AdES: + cause = 5; + goto set_EPC; case EXCP_TLBL: cause = 2; if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) -- cgit v1.2.3 From c185970a0e3c72b5f70bad599c4160d037427c81 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 6 Apr 2007 20:02:09 +0000 Subject: Enforce even float register pair for double register ops (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2624 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index cb11b928f..34a3357f9 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -90,7 +90,7 @@ enum { #ifdef TARGET_SPARC64 #define DFPREG(r) (((r & 1) << 6) | (r & 0x1e)) #else -#define DFPREG(r) (r) +#define DFPREG(r) (r & 0x1e) #endif #ifdef USE_DIRECT_JUMP -- cgit v1.2.3 From 417454b0322ab1eed03615fe563d770fa7e4c9f9 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 6 Apr 2007 20:03:29 +0000 Subject: Full implementation of IEEE exceptions (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2625 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 9 ++++++ target-sparc/op.c | 63 ++++++++++++++++++++++++++++++++++++++++++ target-sparc/op_helper.c | 71 +++++++++++++++++++++++++++++++++++++++++------- target-sparc/translate.c | 25 ++++++++++++++--- 4 files changed, 154 insertions(+), 14 deletions(-) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 934f5ce96..8a9fa89ec 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -61,6 +61,8 @@ void do_fsqrts(void); void do_fsqrtd(void); void do_fcmps(void); void do_fcmpd(void); +void do_fcmpes(void); +void do_fcmped(void); #ifdef TARGET_SPARC64 void do_fabsd(void); void do_fcmps_fcc1(void); @@ -69,6 +71,12 @@ void do_fcmps_fcc2(void); void do_fcmpd_fcc2(void); void do_fcmps_fcc3(void); void do_fcmpd_fcc3(void); +void do_fcmpes_fcc1(void); +void do_fcmped_fcc1(void); +void do_fcmpes_fcc2(void); +void do_fcmped_fcc2(void); +void do_fcmpes_fcc3(void); +void do_fcmped_fcc3(void); void do_popc(); void do_wrpstate(); void do_done(); @@ -79,6 +87,7 @@ void do_ldd_user(target_ulong addr); void do_ldd_raw(target_ulong addr); void do_interrupt(int intno); void raise_exception(int tt); +void check_ieee_exceptions(); void memcpy32(target_ulong *dst, const target_ulong *src); target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev); void dump_mmu(CPUState *env); diff --git a/target-sparc/op.c b/target-sparc/op.c index 2c8949048..c9f068457 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1534,16 +1534,25 @@ void OPPROTO op_flush_T0(void) helper_flush(T0); } +void OPPROTO op_clear_ieee_excp_and_FTT(void) +{ + env->fsr &= ~(FSR_FTT_MASK | FSR_CEXC_MASK);; +} + #define F_OP(name, p) void OPPROTO op_f##name##p(void) #define F_BINOP(name) \ F_OP(name, s) \ { \ + set_float_exception_flags(0, &env->fp_status); \ FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \ + check_ieee_exceptions(); \ } \ F_OP(name, d) \ { \ + set_float_exception_flags(0, &env->fp_status); \ DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ + check_ieee_exceptions(); \ } F_BINOP(add); @@ -1554,9 +1563,11 @@ F_BINOP(div); void OPPROTO op_fsmuld(void) { + set_float_exception_flags(0, &env->fp_status); DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status), float32_to_float64(FT1, &env->fp_status), &env->fp_status); + check_ieee_exceptions(); } #define F_HELPER(name) \ @@ -1582,6 +1593,7 @@ F_OP(abs, s) } F_HELPER(cmp); +F_HELPER(cmpe); #ifdef TARGET_SPARC64 F_OP(neg, d) @@ -1623,6 +1635,37 @@ void OPPROTO op_fcmpd_fcc3(void) { do_fcmpd_fcc3(); } + +void OPPROTO op_fcmpes_fcc1(void) +{ + do_fcmpes_fcc1(); +} + +void OPPROTO op_fcmped_fcc1(void) +{ + do_fcmped_fcc1(); +} + +void OPPROTO op_fcmpes_fcc2(void) +{ + do_fcmpes_fcc2(); +} + +void OPPROTO op_fcmped_fcc2(void) +{ + do_fcmped_fcc2(); +} + +void OPPROTO op_fcmpes_fcc3(void) +{ + do_fcmpes_fcc3(); +} + +void OPPROTO op_fcmped_fcc3(void) +{ + do_fcmped_fcc3(); +} + #endif /* Integer to float conversion. */ @@ -1631,23 +1674,31 @@ F_HELPER(ito); #else F_OP(ito, s) { + set_float_exception_flags(0, &env->fp_status); FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status); + check_ieee_exceptions(); } F_OP(ito, d) { + set_float_exception_flags(0, &env->fp_status); DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); + check_ieee_exceptions(); } #ifdef TARGET_SPARC64 F_OP(xto, s) { + set_float_exception_flags(0, &env->fp_status); FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status); + check_ieee_exceptions(); } F_OP(xto, d) { + set_float_exception_flags(0, &env->fp_status); DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); + check_ieee_exceptions(); } #endif #endif @@ -1656,34 +1707,46 @@ F_OP(xto, d) /* floating point conversion */ void OPPROTO op_fdtos(void) { + set_float_exception_flags(0, &env->fp_status); FT0 = float64_to_float32(DT1, &env->fp_status); + check_ieee_exceptions(); } void OPPROTO op_fstod(void) { + set_float_exception_flags(0, &env->fp_status); DT0 = float32_to_float64(FT1, &env->fp_status); + check_ieee_exceptions(); } /* Float to integer conversion. */ void OPPROTO op_fstoi(void) { + set_float_exception_flags(0, &env->fp_status); *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status); + check_ieee_exceptions(); } void OPPROTO op_fdtoi(void) { + set_float_exception_flags(0, &env->fp_status); *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status); + check_ieee_exceptions(); } #ifdef TARGET_SPARC64 void OPPROTO op_fstox(void) { + set_float_exception_flags(0, &env->fp_status); *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status); + check_ieee_exceptions(); } void OPPROTO op_fdtox(void) { + set_float_exception_flags(0, &env->fp_status); *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status); + check_ieee_exceptions(); } void OPPROTO op_fmovs_cc(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 8a9b7bb3c..21612bd23 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -9,10 +9,43 @@ void raise_exception(int tt) cpu_loop_exit(); } +void check_ieee_exceptions() +{ + T0 = get_float_exception_flags(&env->fp_status); + if (T0) + { + /* Copy IEEE 754 flags into FSR */ + if (T0 & float_flag_invalid) + env->fsr |= FSR_NVC; + if (T0 & float_flag_overflow) + env->fsr |= FSR_OFC; + if (T0 & float_flag_underflow) + env->fsr |= FSR_UFC; + if (T0 & float_flag_divbyzero) + env->fsr |= FSR_DZC; + if (T0 & float_flag_inexact) + env->fsr |= FSR_NXC; + + if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) + { + /* Unmasked exception, generate a trap */ + env->fsr |= FSR_FTT_IEEE_EXCP; + raise_exception(TT_FP_EXCP); + } + else + { + /* Accumulate exceptions */ + env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; + } + } +} + #ifdef USE_INT_TO_FLOAT_HELPERS void do_fitos(void) { + set_float_exception_flags(0, &env->fp_status); FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status); + check_ieee_exceptions(); } void do_fitod(void) @@ -35,23 +68,29 @@ void do_fabsd(void) void do_fsqrts(void) { + set_float_exception_flags(0, &env->fp_status); FT0 = float32_sqrt(FT1, &env->fp_status); + check_ieee_exceptions(); } void do_fsqrtd(void) { + set_float_exception_flags(0, &env->fp_status); DT0 = float64_sqrt(DT1, &env->fp_status); + check_ieee_exceptions(); } -#define GEN_FCMP(name, size, reg1, reg2, FS) \ +#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \ void glue(do_, name) (void) \ { \ env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ case float_relation_unordered: \ T0 = (FSR_FCC1 | FSR_FCC0) << FS; \ - if (env->fsr & FSR_NVM) { \ + if ((env->fsr & FSR_NVM) || TRAP) { \ env->fsr |= T0; \ + env->fsr |= FSR_NVC; \ + env->fsr |= FSR_FTT_IEEE_EXCP; \ raise_exception(TT_FP_EXCP); \ } else { \ env->fsr |= FSR_NVA; \ @@ -70,18 +109,30 @@ void do_fsqrtd(void) env->fsr |= T0; \ } -GEN_FCMP(fcmps, float32, FT0, FT1, 0); -GEN_FCMP(fcmpd, float64, DT0, DT1, 0); +GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0); +GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); + +GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1); +GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); #ifdef TARGET_SPARC64 -GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22); -GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22); +GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0); +GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); + +GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0); +GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0); + +GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0); +GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0); + +GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1); +GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1); -GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24); -GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24); +GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1); +GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); -GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26); -GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26); +GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); +GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); #endif #if defined(CONFIG_USER_ONLY) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 34a3357f9..0d71da3b8 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -943,6 +943,21 @@ static GenOpFunc * const gen_fcmpd[4] = { gen_op_fcmpd_fcc2, gen_op_fcmpd_fcc3, }; + +static GenOpFunc * const gen_fcmpes[4] = { + gen_op_fcmpes, + gen_op_fcmpes_fcc1, + gen_op_fcmpes_fcc2, + gen_op_fcmpes_fcc3, +}; + +static GenOpFunc * const gen_fcmped[4] = { + gen_op_fcmped, + gen_op_fcmped_fcc1, + gen_op_fcmped_fcc2, + gen_op_fcmped_fcc3, +}; + #endif static int gen_trap_ifnofpu(DisasContext * dc) @@ -1289,6 +1304,7 @@ static void disas_sparc_insn(DisasContext * dc) } else if (xop == 0x34) { /* FPU Operations */ if (gen_trap_ifnofpu(dc)) goto jmp_insn; + gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); @@ -1476,6 +1492,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif if (gen_trap_ifnofpu(dc)) goto jmp_insn; + gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); @@ -1653,18 +1670,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); #ifdef TARGET_SPARC64 - gen_fcmps[rd & 3](); + gen_fcmpes[rd & 3](); #else - gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */ + gen_op_fcmpes(); #endif break; case 0x56: /* fcmped, V9 %fcc */ gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); #ifdef TARGET_SPARC64 - gen_fcmpd[rd & 3](); + gen_fcmped[rd & 3](); #else - gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */ + gen_op_fcmped(); #endif break; case 0x57: /* fcmpeq */ -- cgit v1.2.3 From d85fb99bf7ad9b6ebf163c2276333cef4faec147 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 6 Apr 2007 20:58:25 +0000 Subject: Comment spelling fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2626 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm_timer.c b/hw/arm_timer.c index c8864f13c..068d0a0f7 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -233,7 +233,7 @@ static void *arm_timer_init(uint32_t freq, void *pic, int irq) /* ARM PrimeCell SP804 dual timer module. Docs for this device don't seem to be publicly available. This - implementation is based on gueswork, the linux kernel sources and the + implementation is based on guesswork, the linux kernel sources and the Integrator/CP timer modules. */ typedef struct { -- cgit v1.2.3 From f757d6ff29128dd0a09e02299306be22fa38821e Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 7 Apr 2007 01:09:17 +0000 Subject: Fix ins/ext cornercase. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2627 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 5048bc0f9..1e2dbc8c2 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -2232,7 +2232,7 @@ void op_ext(void) unsigned int pos = PARAM1; unsigned int size = PARAM2; - T0 = ((uint32_t)T1 >> pos) & ((1 << size) - 1); + T0 = ((uint32_t)T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0); RETURN(); } @@ -2240,7 +2240,7 @@ void op_ins(void) { unsigned int pos = PARAM1; unsigned int size = PARAM2; - target_ulong mask = ((1 << size) - 1) << pos; + target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; T0 = (T2 & ~mask) | (((uint32_t)T1 << pos) & mask); RETURN(); @@ -2258,7 +2258,7 @@ void op_dext(void) unsigned int pos = PARAM1; unsigned int size = PARAM2; - T0 = (T1 >> pos) & ((1 << size) - 1); + T0 = (T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0); RETURN(); } @@ -2266,7 +2266,7 @@ void op_dins(void) { unsigned int pos = PARAM1; unsigned int size = PARAM2; - target_ulong mask = ((1 << size) - 1) << pos; + target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; T0 = (T2 & ~mask) | ((T1 << pos) & mask); RETURN(); -- cgit v1.2.3 From e04bcc691b54cb680138e3aa6e583c82c91cfca2 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 7 Apr 2007 01:10:22 +0000 Subject: Actually skip over delay slot for a non-taken branch likely. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2628 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index f3b2de446..c646f7f37 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1530,14 +1530,14 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BLTZALL: /* 0 < 0 likely */ gen_op_set_T0(ctx->pc + 8); gen_op_store_T0_gpr(31); - gen_goto_tb(ctx, 0, ctx->pc + 4); + gen_goto_tb(ctx, 0, ctx->pc + 8); return; case OPC_BNEL: /* rx != rx likely */ case OPC_BGTZL: /* 0 > 0 likely */ case OPC_BLTZL: /* 0 < 0 likely */ /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever and skip"); - gen_goto_tb(ctx, 0, ctx->pc + 4); + gen_goto_tb(ctx, 0, ctx->pc + 8); return; case OPC_J: ctx->hflags |= MIPS_HFLAG_B; -- cgit v1.2.3 From cbeb0857da13d8a06453dd1527a2bcca61556497 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 7 Apr 2007 01:11:15 +0000 Subject: Set proper BadVAddress value for unaligned instruction fetch. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2629 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index c646f7f37..eaea42516 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1486,7 +1486,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, /* Jump to register */ if (offset != 0 && offset != 16) { /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the - others are reserved. */ + others are reserved. */ generate_exception(ctx, EXCP_RI); return; } @@ -4629,6 +4629,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) /* make sure instructions are on a word boundary */ if (ctx->pc & 0x3) { + env->CP0_BadVAddr = ctx->pc; generate_exception(ctx, EXCP_AdEL); return; } -- cgit v1.2.3 From e0c84da78c3bc78e9920d99cdca0d111417ecc2f Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 7 Apr 2007 01:11:39 +0000 Subject: Implement prefx. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2630 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index eaea42516..fa56f0603 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -358,7 +358,44 @@ enum { #define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) #define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) -#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) + +enum { + OPC_MFC2 = (0x00 << 21) | OPC_CP2, + OPC_DMFC2 = (0x01 << 21) | OPC_CP2, + OPC_CFC2 = (0x02 << 21) | OPC_CP2, + OPC_MFHC2 = (0x03 << 21) | OPC_CP2, + OPC_MTC2 = (0x04 << 21) | OPC_CP2, + OPC_DMTC2 = (0x05 << 21) | OPC_CP2, + OPC_CTC2 = (0x06 << 21) | OPC_CP2, + OPC_MTHC2 = (0x07 << 21) | OPC_CP2, + OPC_BC2 = (0x08 << 21) | OPC_CP2, +}; + +#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & 0x3F) + +enum { + OPC_LWXC1 = 0x00 | OPC_CP3, + OPC_LDXC1 = 0x01 | OPC_CP3, + OPC_LUXC1 = 0x05 | OPC_CP3, + OPC_SWXC1 = 0x08 | OPC_CP3, + OPC_SDXC1 = 0x09 | OPC_CP3, + OPC_SUXC1 = 0x0D | OPC_CP3, + OPC_PREFX = 0x0F | OPC_CP3, + OPC_ALNV_PS = 0x1E | OPC_CP3, + OPC_MADD_S = 0x20 | OPC_CP3, + OPC_MADD_D = 0x21 | OPC_CP3, + OPC_MADD_PS = 0x26 | OPC_CP3, + OPC_MSUB_S = 0x28 | OPC_CP3, + OPC_MSUB_D = 0x29 | OPC_CP3, + OPC_MSUB_PS = 0x2E | OPC_CP3, + OPC_NMADD_S = 0x30 | OPC_CP3, + OPC_NMADD_D = 0x32 | OPC_CP3, + OPC_NMADD_PS= 0x36 | OPC_CP3, + OPC_NMSUB_S = 0x38 | OPC_CP3, + OPC_NMSUB_D = 0x39 | OPC_CP3, + OPC_NMSUB_PS= 0x3E | OPC_CP3, +}; + const unsigned char *regnames[] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", @@ -5019,6 +5056,9 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_op_cp1_enabled(); op1 = MASK_CP3(ctx->opcode); switch (op1) { + case OPC_PREFX: + /* treat as noop */ + break; /* Not implemented */ default: generate_exception (ctx, EXCP_RI); -- cgit v1.2.3 From 544c4be626e8b4a9f5b4845dc181e0674d8cf762 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 7 Apr 2007 01:24:43 +0000 Subject: Remove dead code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2631 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 0cd252173..e608cc574 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2590,44 +2590,6 @@ static void piix3_reset(PCIIDEState *d) pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */ } -void pci_piix_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) -{ - PCIIDEState *d; - uint8_t *pci_conf; - - /* register a function 1 of PIIX */ - d = (PCIIDEState *)pci_register_device(bus, "PIIX IDE", - sizeof(PCIIDEState), - devfn, - NULL, NULL); - d->type = IDE_TYPE_PIIX3; - - pci_conf = d->dev.config; - pci_conf[0x00] = 0x86; // Intel - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x30; - pci_conf[0x03] = 0x12; - pci_conf[0x08] = 0x02; // Step A1 - pci_conf[0x09] = 0x80; // legacy ATA mode - pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE - pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage - pci_conf[0x0e] = 0x00; // header_type - - piix3_reset(d); - - pci_register_io_region((PCIDevice *)d, 4, 0x10, - PCI_ADDRESS_SPACE_IO, bmdma_map); - - ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], - pic_set_irq_new, isa_pic, 14); - ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], - pic_set_irq_new, isa_pic, 15); - ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); - ide_init_ioport(&d->ide_if[2], 0x170, 0x376); - - register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); -} - /* hd_table must contain 4 block drivers */ /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) -- cgit v1.2.3 From 80a34d67a5061ef1fbe8d8f77e866aa350f70959 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 7 Apr 2007 01:41:49 +0000 Subject: Remove dead code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2632 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/rtl8139.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 6ca275a3d..ee5b9f5e3 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -461,7 +461,6 @@ typedef struct RTL8139State { uint16_t CpCmd; uint8_t TxThresh; - int irq; PCIDevice *pci_dev; VLANClientState *vc; uint8_t macaddr[6]; @@ -685,16 +684,10 @@ static void rtl8139_update_irq(RTL8139State *s) int isr; isr = (s->IntrStatus & s->IntrMask) & 0xffff; - DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", - s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask)); + DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n", + isr ? 1 : 0, s->IntrStatus, s->IntrMask)); - if (s->irq == 16) { - /* PCI irq */ - pci_set_irq(s->pci_dev, 0, (isr != 0)); - } else { - /* ISA irq */ - pic_set_irq(s->irq, (isr != 0)); - } + pci_set_irq(s->pci_dev, 0, (isr != 0)); } #define POLYNOMIAL 0x04c11db6 @@ -3173,7 +3166,8 @@ static void rtl8139_save(QEMUFile* f,void* opaque) qemu_put_be16s(f, &s->CpCmd); qemu_put_8s(f, &s->TxThresh); - qemu_put_be32s(f, &s->irq); + i = 0; + qemu_put_be32s(f, &i); /* unused. */ qemu_put_buffer(f, s->macaddr, 6); qemu_put_be32s(f, &s->rtl8139_mmio_io_addr); @@ -3267,7 +3261,7 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) qemu_get_be16s(f, &s->CpCmd); qemu_get_8s(f, &s->TxThresh); - qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &i); /* unused. */ qemu_get_buffer(f, s->macaddr, 6); qemu_get_be32s(f, &s->rtl8139_mmio_io_addr); @@ -3447,7 +3441,6 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) pci_register_io_region(&d->dev, 1, 0x100, PCI_ADDRESS_SPACE_MEM, rtl8139_mmio_map); - s->irq = 16; /* PCI interrupt */ s->pci_dev = (PCIDevice *)d; memcpy(s->macaddr, nd->macaddr, 6); rtl8139_reset(s); -- cgit v1.2.3 From 9b3c35e0e6cea178b7c757300f9045258bc5cd10 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 7 Apr 2007 11:21:28 +0000 Subject: cpu_get_phys_page_debug should return target_phys_addr_t instead of target_ulong to be consistent. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2633 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 2 +- exec.c | 6 ++++-- target-alpha/helper.c | 4 ++-- target-arm/helper.c | 4 ++-- target-i386/helper2.c | 4 ++-- target-m68k/translate.c | 2 +- target-mips/helper.c | 4 ++-- target-ppc/helper.c | 4 ++-- target-sh4/helper.c | 4 ++-- target-sparc/translate.c | 4 ++-- 10 files changed, 20 insertions(+), 18 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index d2382857a..2fc2f9a99 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -799,7 +799,7 @@ 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); +target_phys_addr_t 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) diff --git a/exec.c b/exec.c index 2467b6295..084b84409 100644 --- a/exec.c +++ b/exec.c @@ -1030,7 +1030,8 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) #if defined(TARGET_HAS_ICE) static void breakpoint_invalidate(CPUState *env, target_ulong pc) { - target_ulong addr, pd; + target_phys_addr_t addr; + target_ulong pd; ram_addr_t ram_addr; PhysPageDesc *p; @@ -2574,7 +2575,8 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write) { int l; - target_ulong page, phys_addr; + target_phys_addr_t phys_addr; + target_ulong page; while (len > 0) { page = addr & TARGET_PAGE_MASK; diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 0049c397a..98200d9fb 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -39,7 +39,7 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 1; } -target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { return addr; } @@ -51,7 +51,7 @@ void do_interrupt (CPUState *env) #else -target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { return -1; } diff --git a/target-arm/helper.c b/target-arm/helper.c index 242dd28f7..111b84652 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -126,7 +126,7 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 1; } -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } @@ -441,7 +441,7 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, return 1; } -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { uint32_t phys_addr; int prot; diff --git a/target-i386/helper2.c b/target-i386/helper2.c index dc6a5000e..f05a284f9 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -578,7 +578,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, return 1; } -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } @@ -876,7 +876,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, return 1; } -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { uint32_t pde_addr, pte_addr; uint32_t pde, pte, paddr, page_offset, page_size; diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 5d47c5469..3b2563582 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2738,7 +2738,7 @@ void cpu_dump_state(CPUState *env, FILE *f, } /* ??? */ -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } diff --git a/target-mips/helper.c b/target-mips/helper.c index d48c32b22..c23e9c6b3 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -141,12 +141,12 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } #if defined(CONFIG_USER_ONLY) -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } #else -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { target_ulong phys_addr; int prot; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 1d973dc43..69ed260f7 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -60,7 +60,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, return 1; } -target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { return addr; } @@ -821,7 +821,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, return ret; } -target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { mmu_ctx_t ctx; diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 1839c96dd..1063ece2d 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -53,7 +53,7 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, return 1; } -target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) { return addr; } @@ -429,7 +429,7 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, return tlb_set_page(env, address, physical, prot, is_user, is_softmmu); } -target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) { target_ulong physical; int prot; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 0d71da3b8..e51a2e459 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3012,7 +3012,7 @@ void cpu_dump_state(CPUState *env, FILE *f, } #if defined(CONFIG_USER_ONLY) -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; } @@ -3022,7 +3022,7 @@ extern int get_physical_address (CPUState *env, target_phys_addr_t *physical, in int *access_index, target_ulong address, int rw, int is_user); -target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { target_phys_addr_t phys_addr; int prot, access_index; -- cgit v1.2.3 From b6e27ab8b12ef6075d85fc505f821643804a3a79 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 7 Apr 2007 11:48:04 +0000 Subject: PowerPC 64 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2634 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index b284798dc..3a2f5f85b 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -777,7 +777,7 @@ void OPPROTO op_adde_64 (void) /* add immediate */ PPC_OP(addi) { - T0 += PARAM(1); + T0 += (int32_t)PARAM(1); RETURN(); } @@ -1074,7 +1074,7 @@ void OPPROTO op_subfe_64 (void) /* substract from immediate carrying */ void OPPROTO op_subfic (void) { - T0 = PARAM1 + ~T0 + 1; + T0 = (int32_t)PARAM1 + ~T0 + 1; if ((uint32_t)T0 <= (uint32_t)PARAM1) { xer_ca = 1; } else { -- cgit v1.2.3 From d537cf6c8624b27ce2b63431d2f8937f6356f652 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 7 Apr 2007 18:14:41 +0000 Subject: Unify IRQ handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2635 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + hw/acpi.c | 2 +- hw/adlib.c | 2 +- hw/apb_pci.c | 6 +-- hw/arm_gic.c | 20 ++++----- hw/arm_pic.c | 43 ++++--------------- hw/arm_pic.h | 6 +-- hw/arm_timer.c | 37 +++++++--------- hw/cs4231.c | 3 -- hw/cuda.c | 12 ++---- hw/eepro100.c | 4 +- hw/es1370.c | 4 +- hw/fdc.c | 10 ++--- hw/grackle_pci.c | 6 +-- hw/gt64xxx.c | 6 +-- hw/heathrow_pic.c | 10 ++--- hw/i8254.c | 6 +-- hw/i8259.c | 27 +++++------- hw/ide.c | 42 ++++++++---------- hw/integratorcp.c | 55 +++++++++++------------- hw/irq.c | 57 +++++++++++++++++++++++++ hw/irq.h | 21 +++++++++ hw/lsi53c895a.c | 2 +- hw/m48t59.c | 12 +++--- hw/m48t59.h | 2 +- hw/mc146818rtc.c | 12 +++--- hw/mips_int.c | 13 +++++- hw/mips_malta.c | 32 ++++++-------- hw/mips_r4k.c | 24 +++++------ hw/mips_timer.c | 4 +- hw/ne2000.c | 25 +++++------ hw/openpic.c | 10 ++--- hw/parallel.c | 8 ++-- hw/pc.c | 46 +++++++++++--------- hw/pci.c | 9 ++-- hw/pckbd.c | 19 +++------ hw/pcnet.c | 24 +++-------- hw/pcspk.c | 2 +- hw/piix_pci.c | 10 ++--- hw/pl011.c | 8 ++-- hw/pl050.c | 8 ++-- hw/pl080.c | 10 ++--- hw/pl110.c | 6 +-- hw/pl181.c | 8 ++-- hw/pl190.c | 18 ++++---- hw/ppc.c | 14 +++++- hw/ppc_chrp.c | 32 ++++++-------- hw/ppc_prep.c | 27 ++++++------ hw/prep_pci.c | 8 ++-- hw/realview.c | 28 ++++++------ hw/rtl8139.c | 2 +- hw/sb16.c | 24 ++++++----- hw/serial.c | 20 +++------ hw/shix.c | 5 --- hw/slavio_intctl.c | 8 ++-- hw/slavio_misc.c | 22 +++++----- hw/slavio_serial.c | 25 ++++++----- hw/slavio_timer.c | 3 -- hw/smc91c111.c | 8 ++-- hw/sparc32_dma.c | 39 +++++++++-------- hw/sun4m.c | 32 +++++++------- hw/sun4u.c | 20 +++------ hw/unin_pci.c | 6 +-- hw/usb-ohci.c | 19 +++------ hw/usb-uhci.c | 2 +- hw/usb.h | 2 +- hw/versatile_pci.c | 6 +-- hw/versatilepb.c | 46 ++++++++++---------- target-mips/cpu.h | 2 + target-ppc/cpu.h | 1 + vl.h | 123 +++++++++++++++++++++++++---------------------------- 71 files changed, 592 insertions(+), 624 deletions(-) create mode 100644 hw/irq.c create mode 100644 hw/irq.h diff --git a/Makefile.target b/Makefile.target index 16adfc7e4..79b2aa581 100644 --- a/Makefile.target +++ b/Makefile.target @@ -360,6 +360,7 @@ 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 +VL_OBJS+=irq.o ifdef CONFIG_WIN32 VL_OBJS+=tap-win32.o endif diff --git a/hw/acpi.c b/hw/acpi.c index 78c4feabb..e78e56d62 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -92,7 +92,7 @@ static void pm_update_sci(PIIX4PMState *s) pmsts = get_pmsts(s); sci_level = (((pmsts & s->pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); - pci_set_irq(&s->dev, 0, sci_level); + qemu_set_irq(s->dev.irq[0], sci_level); /* schedule a timer interruption if needed */ if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ); diff --git a/hw/adlib.c b/hw/adlib.c index b47bc3eec..805365e70 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -267,7 +267,7 @@ static void Adlib_fini (AdlibState *s) AUD_remove_card (&s->card); } -int Adlib_init (AudioState *audio) +int Adlib_init (AudioState *audio, qemu_irq *pic) { AdlibState *s = &glob_adlib; audsettings_t as; diff --git a/hw/apb_pci.c b/hw/apb_pci.c index a5fe9b989..627fd9bc0 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -200,14 +200,14 @@ static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num) return bus_offset + irq_num; } -static void pci_apb_set_irq(void *pic, int irq_num, int level) +static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level) { /* PCI IRQ map onto the first 32 INO. */ - pic_set_irq_new(pic, irq_num, level); + qemu_set_irq(pic[irq_num], level); } PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, - void *pic) + qemu_irq *pic) { APBState *s; PCIDevice *d; diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 2901f3466..eee5b7c72 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -60,10 +60,8 @@ typedef struct gic_irq_state typedef struct gic_state { - arm_pic_handler handler; uint32_t base; - void *parent; - int parent_irq; + qemu_irq parent_irq; int enabled; int cpu_enabled; @@ -88,7 +86,7 @@ static void gic_update(gic_state *s) s->current_pending = 1023; if (!s->enabled || !s->cpu_enabled) { - pic_set_irq_new(s->parent, s->parent_irq, 0); + qemu_irq_lower(s->parent_irq); return; } best_prio = 0x100; @@ -102,12 +100,12 @@ static void gic_update(gic_state *s) } } if (best_prio > s->priority_mask) { - pic_set_irq_new(s->parent, s->parent_irq, 0); + qemu_irq_lower(s->parent_irq); } else { s->current_pending = best_irq; if (best_prio < s->running_priority) { DPRINTF("Raised pending IRQ %d\n", best_irq); - pic_set_irq_new(s->parent, s->parent_irq, 1); + qemu_irq_raise(s->parent_irq); } } } @@ -150,7 +148,7 @@ static uint32_t gic_acknowledge_irq(gic_state *s) DPRINTF("ACK no pending IRQ\n"); return 1023; } - pic_set_irq_new(s->parent, s->parent_irq, 0); + qemu_irq_lower(s->parent_irq); s->last_active[new_irq] = s->running_irq; /* For level triggered interrupts we clear the pending bit while the interrupt is active. */ @@ -520,16 +518,16 @@ static void gic_reset(gic_state *s) s->cpu_enabled = 0; } -void *arm_gic_init(uint32_t base, void *parent, int parent_irq) +qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq) { gic_state *s; + qemu_irq *qi; int iomemtype; s = (gic_state *)qemu_mallocz(sizeof(gic_state)); if (!s) return NULL; - s->handler = gic_set_irq; - s->parent = parent; + qi = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ); s->parent_irq = parent_irq; if (base != 0xffffffff) { iomemtype = cpu_register_io_memory(0, gic_cpu_readfn, @@ -543,5 +541,5 @@ void *arm_gic_init(uint32_t base, void *parent, int parent_irq) s->base = 0; } gic_reset(s); - return s; + return qi; } diff --git a/hw/arm_pic.c b/hw/arm_pic.c index fbc2d67d0..dcc1198e4 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -11,11 +11,6 @@ #include "arm_pic.h" /* Stub functions for hardware that doesn't exist. */ -void pic_set_irq(int irq, int level) -{ - cpu_abort(cpu_single_env, "pic_set_irq"); -} - void pic_info(void) { } @@ -25,49 +20,29 @@ void irq_info(void) } -void pic_set_irq_new(void *opaque, int irq, int level) -{ - arm_pic_handler *p = (arm_pic_handler *)opaque; - /* Call the real handler. */ - (*p)(opaque, irq, level); -} - -/* Model the IRQ/FIQ CPU interrupt lines as a two input interrupt controller. - Input 0 is IRQ and input 1 is FIQ. */ -typedef struct -{ - arm_pic_handler handler; - CPUState *cpu_env; -} arm_pic_cpu_state; - +/* Input 0 is IRQ and input 1 is FIQ. */ static void arm_pic_cpu_handler(void *opaque, int irq, int level) { - arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque; + CPUState *env = (CPUState *)opaque; switch (irq) { case ARM_PIC_CPU_IRQ: if (level) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + cpu_interrupt(env, CPU_INTERRUPT_HARD); else - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); break; case ARM_PIC_CPU_FIQ: if (level) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + cpu_interrupt(env, CPU_INTERRUPT_FIQ); else - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ); break; default: - cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n", - irq); + cpu_abort(env, "arm_pic_cpu_handler: Bad interrput line %d\n", irq); } } -void *arm_pic_init_cpu(CPUState *env) +qemu_irq *arm_pic_init_cpu(CPUState *env) { - arm_pic_cpu_state *s; - - s = (arm_pic_cpu_state *)malloc(sizeof(arm_pic_cpu_state)); - s->handler = arm_pic_cpu_handler; - s->cpu_env = env; - return s; + return qemu_allocate_irqs(arm_pic_cpu_handler, env, 2); } diff --git a/hw/arm_pic.h b/hw/arm_pic.h index b29914985..6c5ed1758 100644 --- a/hw/arm_pic.h +++ b/hw/arm_pic.h @@ -14,14 +14,10 @@ #ifndef ARM_INTERRUPT_H #define ARM_INTERRUPT_H 1 -/* The first element of an individual PIC state structures should - be a pointer to the handler routine. */ -typedef void (*arm_pic_handler)(void *opaque, int irq, int level); - /* The CPU is also modeled as an interrupt controller. */ #define ARM_PIC_CPU_IRQ 0 #define ARM_PIC_CPU_FIQ 1 -void *arm_pic_init_cpu(CPUState *env); +qemu_irq *arm_pic_init_cpu(CPUState *env); #endif /* !ARM_INTERRUPT_H */ diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 068d0a0f7..3c6c0d239 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -32,8 +32,7 @@ typedef struct { int raw_freq; int freq; int int_level; - void *pic; - int irq; + qemu_irq irq; } arm_timer_state; /* Calculate the new expiry time of the given timer. */ @@ -85,9 +84,9 @@ static void arm_timer_update(arm_timer_state *s, int64_t now) } /* Update interrupts. */ if (s->int_level && (s->control & TIMER_CTRL_IE)) { - pic_set_irq_new(s->pic, s->irq, 1); + qemu_irq_raise(s->irq); } else { - pic_set_irq_new(s->pic, s->irq, 0); + qemu_irq_lower(s->irq); } next = now; @@ -215,12 +214,11 @@ static void arm_timer_tick(void *opaque) arm_timer_update((arm_timer_state *)opaque, now); } -static void *arm_timer_init(uint32_t freq, void *pic, int irq) +static void *arm_timer_init(uint32_t freq, qemu_irq irq) { arm_timer_state *s; s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state)); - s->pic = pic; s->irq = irq; s->raw_freq = s->freq = 1000000; s->control = TIMER_CTRL_IE; @@ -237,22 +235,19 @@ static void *arm_timer_init(uint32_t freq, void *pic, int irq) Integrator/CP timer modules. */ typedef struct { - /* Include a pseudo-PIC device to merge the two interrupt sources. */ - arm_pic_handler handler; void *timer[2]; int level[2]; uint32_t base; - /* The output PIC device. */ - void *pic; - int irq; + qemu_irq irq; } sp804_state; +/* Merge the IRQs from the two component devices. */ static void sp804_set_irq(void *opaque, int irq, int level) { sp804_state *s = (sp804_state *)opaque; s->level[irq] = level; - pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]); + qemu_set_irq(s->irq, s->level[0] || s->level[1]); } static uint32_t sp804_read(void *opaque, target_phys_addr_t offset) @@ -293,20 +288,20 @@ static CPUWriteMemoryFunc *sp804_writefn[] = { sp804_write }; -void sp804_init(uint32_t base, void *pic, int irq) +void sp804_init(uint32_t base, qemu_irq irq) { int iomemtype; sp804_state *s; + qemu_irq *qi; s = (sp804_state *)qemu_mallocz(sizeof(sp804_state)); - s->handler = sp804_set_irq; + qi = qemu_allocate_irqs(sp804_set_irq, s, 2); s->base = base; - s->pic = pic; s->irq = irq; /* ??? The timers are actually configurable between 32kHz and 1MHz, but we don't implement that. */ - s->timer[0] = arm_timer_init(1000000, s, 0); - s->timer[1] = arm_timer_init(1000000, s, 1); + s->timer[0] = arm_timer_init(1000000, qi[0]); + s->timer[1] = arm_timer_init(1000000, qi[1]); iomemtype = cpu_register_io_memory(0, sp804_readfn, sp804_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); @@ -362,7 +357,7 @@ static CPUWriteMemoryFunc *icp_pit_writefn[] = { icp_pit_write }; -void icp_pit_init(uint32_t base, void *pic, int irq) +void icp_pit_init(uint32_t base, qemu_irq *pic, int irq) { int iomemtype; icp_pit_state *s; @@ -370,10 +365,10 @@ void icp_pit_init(uint32_t base, void *pic, int irq) s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state)); s->base = base; /* Timer 0 runs at the system clock speed (40MHz). */ - s->timer[0] = arm_timer_init(40000000, pic, irq); + s->timer[0] = arm_timer_init(40000000, pic[irq]); /* The other two timers run at 1MHz. */ - s->timer[1] = arm_timer_init(1000000, pic, irq + 1); - s->timer[2] = arm_timer_init(1000000, pic, irq + 2); + s->timer[1] = arm_timer_init(1000000, pic[irq + 1]); + s->timer[2] = arm_timer_init(1000000, pic[irq + 2]); iomemtype = cpu_register_io_memory(0, icp_pit_readfn, icp_pit_writefn, s); diff --git a/hw/cs4231.c b/hw/cs4231.c index a15468556..6df881d41 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -47,9 +47,6 @@ typedef struct CSState { #ifdef DEBUG_CS #define DPRINTF(fmt, args...) \ do { printf("CS: " fmt , ##args); } while (0) -#define pic_set_irq_new(intctl, irq, level) \ - do { printf("CS: set_irq(%d): %d\n", (irq), (level)); \ - pic_set_irq_new((intctl), (irq),(level));} while (0) #else #define DPRINTF(fmt, args...) #endif diff --git a/hw/cuda.c b/hw/cuda.c index f3c2b5601..c29045078 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -124,9 +124,7 @@ typedef struct CUDAState { int data_in_index; int data_out_index; - SetIRQFunc *set_irq; - int irq; - void *irq_opaque; + qemu_irq irq; uint8_t autopoll; uint8_t data_in[128]; uint8_t data_out[16]; @@ -145,9 +143,9 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti, static void cuda_update_irq(CUDAState *s) { if (s->ifr & s->ier & (SR_INT | T1_INT)) { - s->set_irq(s->irq_opaque, s->irq, 1); + qemu_irq_raise(s->irq); } else { - s->set_irq(s->irq_opaque, s->irq, 0); + qemu_irq_lower(s->irq); } } @@ -630,13 +628,11 @@ static CPUReadMemoryFunc *cuda_read[] = { &cuda_readl, }; -int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq) +int cuda_init(qemu_irq irq) { CUDAState *s = &cuda_state; int cuda_mem_index; - s->set_irq = set_irq; - s->irq_opaque = irq_opaque; s->irq = irq; s->timers[0].index = 0; diff --git a/hw/eepro100.c b/hw/eepro100.c index ea18b890d..bb570675a 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -326,7 +326,7 @@ static void disable_interrupt(EEPRO100State * s) { if (s->int_stat) { logout("interrupt disabled\n"); - pci_set_irq(s->pci_dev, 0, 0); + qemu_irq_lower(s->pci_dev->irq[0]); s->int_stat = 0; } } @@ -335,7 +335,7 @@ static void enable_interrupt(EEPRO100State * s) { if (!s->int_stat) { logout("interrupt enabled\n"); - pci_set_irq(s->pci_dev, 0, 1); + qemu_irq_raise(s->pci_dev->irq[0]); s->int_stat = 1; } } diff --git a/hw/es1370.c b/hw/es1370.c index 0d2d86116..d607a9485 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -324,7 +324,7 @@ static void es1370_update_status (ES1370State *s, uint32_t new_status) else { s->status = new_status & ~STAT_INTR; } - pci_set_irq (s->pci_dev, 0, !!level); + qemu_set_irq(s->pci_dev->irq[0], !!level); } static void es1370_reset (ES1370State *s) @@ -350,7 +350,7 @@ static void es1370_reset (ES1370State *s) s->dac_voice[i] = NULL; } } - pci_set_irq (s->pci_dev, 0, 0); + qemu_irq_lower(s->pci_dev->irq[0]); } static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl) diff --git a/hw/fdc.c b/hw/fdc.c index 0012834f4..a12eb0af5 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -368,7 +368,7 @@ struct fdctrl_t { /* Controller's identification */ uint8_t version; /* HW */ - int irq_lvl; + qemu_irq irq; int dma_chann; uint32_t io_base; /* Controller state */ @@ -485,7 +485,7 @@ static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { fdctrl_write_mem, }; -fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, +fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, uint32_t io_base, BlockDriverState **fds) { @@ -501,7 +501,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl_result_timer, fdctrl); fdctrl->version = 0x90; /* Intel 82078 controller */ - fdctrl->irq_lvl = irq_lvl; + fdctrl->irq = irq; fdctrl->dma_chann = dma_chann; fdctrl->io_base = io_base; fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */ @@ -542,7 +542,7 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num) static void fdctrl_reset_irq (fdctrl_t *fdctrl) { FLOPPY_DPRINTF("Reset interrupt\n"); - pic_set_irq(fdctrl->irq_lvl, 0); + qemu_set_irq(fdctrl->irq, 0); fdctrl->state &= ~FD_CTRL_INTR; } @@ -557,7 +557,7 @@ static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) } #endif if (~(fdctrl->state & FD_CTRL_INTR)) { - pic_set_irq(fdctrl->irq_lvl, 1); + qemu_set_irq(fdctrl->irq, 1); fdctrl->state |= FD_CTRL_INTR; } FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status); diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 4004f9942..74d4efccc 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -80,12 +80,12 @@ static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num) return (irq_num + (pci_dev->devfn >> 3)) & 3; } -static void pci_grackle_set_irq(void *pic, int irq_num, int level) +static void pci_grackle_set_irq(qemu_irq *pic, int irq_num, int level) { - heathrow_pic_set_irq(pic, irq_num + 8, level); + qemu_set_irq(pic[irq_num + 8], level); } -PCIBus *pci_grackle_init(uint32_t base, void *pic) +PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) { GrackleState *s; PCIDevice *d; diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 9d6bb44eb..3300d40be 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -520,7 +520,7 @@ static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num) extern PCIDevice *piix4_dev; static int pci_irq_levels[4]; -static void pci_gt64120_set_irq(void *pic, int irq_num, int level) +static void pci_gt64120_set_irq(qemu_irq *pic, int irq_num, int level) { int i, pic_irq, pic_level; @@ -537,7 +537,7 @@ static void pci_gt64120_set_irq(void *pic, int irq_num, int level) if (pic_irq == piix4_dev->config[0x60 + i]) pic_level |= pci_irq_levels[i]; } - pic_set_irq(pic_irq, pic_level); + qemu_set_irq(pic[pic_irq], pic_level); } } @@ -608,7 +608,7 @@ void gt64120_reset(void *opaque) gt64120_pci_mapping(s); } -PCIBus *pci_gt64120_init(void *pic) +PCIBus *pci_gt64120_init(qemu_irq *pic) { GT64120State *s; PCIDevice *d; diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index 4980cef46..c0edaea77 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -32,9 +32,9 @@ typedef struct HeathrowPIC { uint32_t level_triggered; } HeathrowPIC; -struct HeathrowPICS { +typedef struct HeathrowPICS { HeathrowPIC pics[2]; -}; +} HeathrowPICS; static inline int check_irq(HeathrowPIC *pic) { @@ -130,7 +130,7 @@ static CPUReadMemoryFunc *pic_read[] = { }; -void heathrow_pic_set_irq(void *opaque, int num, int level) +static void heathrow_pic_set_irq(void *opaque, int num, int level) { HeathrowPICS *s = opaque; HeathrowPIC *pic; @@ -156,7 +156,7 @@ void heathrow_pic_set_irq(void *opaque, int num, int level) heathrow_pic_update(s); } -HeathrowPICS *heathrow_pic_init(int *pmem_index) +qemu_irq *heathrow_pic_init(int *pmem_index) { HeathrowPICS *s; @@ -164,5 +164,5 @@ HeathrowPICS *heathrow_pic_init(int *pmem_index) s->pics[0].level_triggered = 0; s->pics[1].level_triggered = 0x1ff00000; *pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s); - return s; + return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64); } diff --git a/hw/i8254.c b/hw/i8254.c index a4097632e..f0b41d75c 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -47,7 +47,7 @@ typedef struct PITChannelState { /* irq handling */ int64_t next_transition_time; QEMUTimer *irq_timer; - int irq; + qemu_irq irq; } PITChannelState; struct PITState { @@ -366,7 +366,7 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) return; expire_time = pit_get_next_transition_time(s, current_time); irq_level = pit_get_out1(s, current_time); - pic_set_irq(s->irq, irq_level); + qemu_set_irq(s->irq, irq_level); #ifdef DEBUG_PIT printf("irq_level=%d next_delay=%f\n", irq_level, @@ -460,7 +460,7 @@ static void pit_reset(void *opaque) } } -PITState *pit_init(int base, int irq) +PITState *pit_init(int base, qemu_irq irq) { PITState *pit = &pit_state; PITChannelState *s; diff --git a/hw/i8259.c b/hw/i8259.c index 631e4113b..4b25df3b9 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -54,7 +54,7 @@ struct PicState2 { /* 0 is master pic, 1 is slave pic */ /* XXX: better separation between the two pics */ PicState pics[2]; - IRQRequestFunc *irq_request; + qemu_irq parent_irq; void *irq_request_opaque; /* IOAPIC callback support */ SetIRQFunc *alt_irq_func; @@ -160,13 +160,13 @@ void pic_update_irq(PicState2 *s) } printf("pic: cpu_interrupt\n"); #endif - s->irq_request(s->irq_request_opaque, 1); + qemu_irq_raise(s->parent_irq); } /* all targets should do this rather than acking the IRQ in the cpu */ #if defined(TARGET_MIPS) else { - s->irq_request(s->irq_request_opaque, 0); + qemu_irq_lower(s->parent_irq); } #endif } @@ -175,14 +175,14 @@ void pic_update_irq(PicState2 *s) int64_t irq_time[16]; #endif -void pic_set_irq_new(void *opaque, int irq, int level) +void i8259_set_irq(void *opaque, int irq, int level) { PicState2 *s = opaque; #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq]) { #if defined(DEBUG_PIC) - printf("pic_set_irq: irq=%d level=%d\n", irq, level); + printf("i8259_set_irq: irq=%d level=%d\n", irq, level); #endif irq_level[irq] = level; #ifdef DEBUG_IRQ_COUNT @@ -203,12 +203,6 @@ void pic_set_irq_new(void *opaque, int irq, int level) pic_update_irq(s); } -/* obsolete function */ -void pic_set_irq(int irq, int level) -{ - pic_set_irq_new(isa_pic, irq, level); -} - /* acknowledge interrupt 'irq' */ static inline void pic_intack(PicState *s, int irq) { @@ -297,7 +291,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* init */ pic_reset(s); /* deassert a pending interrupt */ - s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0); + qemu_irq_lower(s->pics_state->parent_irq); s->init_state = 1; s->init4 = val & 1; s->single_mode = val & 2; @@ -546,9 +540,10 @@ void irq_info(void) #endif } -PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque) +qemu_irq *i8259_init(qemu_irq parent_irq) { PicState2 *s; + s = qemu_mallocz(sizeof(PicState2)); if (!s) return NULL; @@ -556,11 +551,11 @@ PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque) pic_init1(0xa0, 0x4d1, &s->pics[1]); s->pics[0].elcr_mask = 0xf8; s->pics[1].elcr_mask = 0xde; - s->irq_request = irq_request; - s->irq_request_opaque = irq_request_opaque; + s->parent_irq = parent_irq; s->pics[0].pics_state = s; s->pics[1].pics_state = s; - return s; + isa_pic = s; + return qemu_allocate_irqs(i8259_set_irq, s, 16); } void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, diff --git a/hw/ide.c b/hw/ide.c index e608cc574..ffee8dde9 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -300,9 +300,7 @@ typedef struct IDEState { int mult_sectors; int identify_set; uint16_t identify_data[256]; - SetIRQFunc *set_irq; - void *irq_opaque; - int irq; + qemu_irq irq; PCIDevice *pci_dev; struct BMDMAState *bmdma; int drive_serial; @@ -575,7 +573,7 @@ static inline void ide_set_irq(IDEState *s) if (bm) { bm->status |= BM_STATUS_INT; } - s->set_irq(s->irq_opaque, s->irq, 1); + qemu_irq_raise(s->irq); } } @@ -1889,7 +1887,7 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = 0; else ret = s->status; - s->set_irq(s->irq_opaque, s->irq, 0); + qemu_irq_lower(s->irq); break; } #ifdef DEBUG_IDE @@ -2084,7 +2082,7 @@ static int guess_disk_lchs(IDEState *s, static void ide_init2(IDEState *ide_state, BlockDriverState *hd0, BlockDriverState *hd1, - SetIRQFunc *set_irq, void *irq_opaque, int irq) + qemu_irq irq) { IDEState *s; static int drive_serial = 1; @@ -2155,8 +2153,6 @@ static void ide_init2(IDEState *ide_state, } } s->drive_serial = drive_serial++; - s->set_irq = set_irq; - s->irq_opaque = irq_opaque; s->irq = irq; s->sector_write_timer = qemu_new_timer(vm_clock, ide_sector_write_timer_cb, s); @@ -2183,7 +2179,7 @@ static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2) /***********************************************************/ /* ISA IDE definitions */ -void isa_ide_init(int iobase, int iobase2, int irq, +void isa_ide_init(int iobase, int iobase2, qemu_irq irq, BlockDriverState *hd0, BlockDriverState *hd1) { IDEState *ide_state; @@ -2192,7 +2188,7 @@ void isa_ide_init(int iobase, int iobase2, int irq, if (!ide_state) return; - ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq); + ide_init2(ide_state, hd0, hd1, irq); ide_init_ioport(ide_state, iobase, iobase2); } @@ -2399,7 +2395,7 @@ static void cmd646_update_irq(PCIIDEState *d) !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) || ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) && !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1)); - pci_set_irq((PCIDevice *)d, 0, pci_level); + qemu_set_irq(d->dev.irq[0], pci_level); } /* the PCI irq level is the logical OR of the two channels */ @@ -2423,6 +2419,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, PCIIDEState *d; uint8_t *pci_conf; int i; + qemu_irq *irq; d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE", sizeof(PCIIDEState), @@ -2462,10 +2459,10 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, for(i = 0; i < 4; i++) d->ide_if[i].pci_dev = (PCIDevice *)d; - ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], - cmd646_set_irq, d, 0); - ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], - cmd646_set_irq, d, 1); + + irq = qemu_allocate_irqs(cmd646_set_irq, d, 2); + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], irq[0]); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], irq[1]); } static void pci_ide_save(QEMUFile* f, void *opaque) @@ -2592,7 +2589,8 @@ static void piix3_reset(PCIIDEState *d) /* hd_table must contain 4 block drivers */ /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ -void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, + qemu_irq *pic) { PCIIDEState *d; uint8_t *pci_conf; @@ -2619,10 +2617,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) pci_register_io_region((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, bmdma_map); - ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], - pic_set_irq_new, isa_pic, 14); - ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], - pic_set_irq_new, isa_pic, 15); + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]); ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); ide_init_ioport(&d->ide_if[2], 0x170, 0x376); @@ -2741,15 +2737,13 @@ static CPUReadMemoryFunc *pmac_ide_read[] = { /* hd_table must contain 4 block drivers */ /* PowerMac uses memory mapped registers, not I/O. Return the memory I/O index to access the ide. */ -int pmac_ide_init (BlockDriverState **hd_table, - SetIRQFunc *set_irq, void *irq_opaque, int irq) +int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq) { IDEState *ide_if; int pmac_ide_memory; ide_if = qemu_mallocz(sizeof(IDEState) * 2); - ide_init2(&ide_if[0], hd_table[0], hd_table[1], - set_irq, irq_opaque, irq); + ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq); pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, pmac_ide_write, &ide_if[0]); diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 1d8b722cf..34c3b8112 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -267,28 +267,22 @@ static void integratorcm_init(int memsz, uint32_t flash_offset) typedef struct icp_pic_state { - arm_pic_handler handler; uint32_t base; uint32_t level; uint32_t irq_enabled; uint32_t fiq_enabled; - void *parent; - int parent_irq; - int parent_fiq; + qemu_irq parent_irq; + qemu_irq parent_fiq; } icp_pic_state; static void icp_pic_update(icp_pic_state *s) { uint32_t flags; - if (s->parent_irq != -1) { - flags = (s->level & s->irq_enabled); - pic_set_irq_new(s->parent, s->parent_irq, flags != 0); - } - if (s->parent_fiq != -1) { - flags = (s->level & s->fiq_enabled); - pic_set_irq_new(s->parent, s->parent_fiq, flags != 0); - } + flags = (s->level & s->irq_enabled); + qemu_set_irq(s->parent_irq, flags != 0); + flags = (s->level & s->fiq_enabled); + qemu_set_irq(s->parent_fiq, flags != 0); } static void icp_pic_set_irq(void *opaque, int irq, int level) @@ -345,11 +339,11 @@ static void icp_pic_write(void *opaque, target_phys_addr_t offset, break; case 4: /* INT_SOFTSET */ if (value & 1) - pic_set_irq_new(s, 0, 1); + icp_pic_set_irq(s, 0, 1); break; case 5: /* INT_SOFTCLR */ if (value & 1) - pic_set_irq_new(s, 0, 0); + icp_pic_set_irq(s, 0, 0); break; case 10: /* FRQ_ENABLESET */ s->fiq_enabled |= value; @@ -380,25 +374,25 @@ static CPUWriteMemoryFunc *icp_pic_writefn[] = { icp_pic_write }; -static icp_pic_state *icp_pic_init(uint32_t base, void *parent, - int parent_irq, int parent_fiq) +static qemu_irq *icp_pic_init(uint32_t base, + qemu_irq parent_irq, qemu_irq parent_fiq) { icp_pic_state *s; int iomemtype; + qemu_irq *qi; s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state)); if (!s) return NULL; - s->handler = icp_pic_set_irq; + qi = qemu_allocate_irqs(icp_pic_set_irq, s, 32); s->base = base; - s->parent = parent; s->parent_irq = parent_irq; s->parent_fiq = parent_fiq; iomemtype = cpu_register_io_memory(0, icp_pic_readfn, icp_pic_writefn, s); cpu_register_physical_memory(base, 0x007fffff, iomemtype); /* ??? Save/restore. */ - return s; + return qi; } /* CP control registers. */ @@ -475,8 +469,8 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, { CPUState *env; uint32_t bios_offset; - icp_pic_state *pic; - void *cpu_pic; + qemu_irq *pic; + qemu_irq *cpu_pic; env = cpu_init(); if (!cpu_model) @@ -492,25 +486,26 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, integratorcm_init(ram_size >> 20, bios_offset); cpu_pic = arm_pic_init_cpu(env); - pic = icp_pic_init(0x14000000, cpu_pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); - icp_pic_init(0xca000000, pic, 26, -1); + pic = icp_pic_init(0x14000000, cpu_pic[ARM_PIC_CPU_IRQ], + cpu_pic[ARM_PIC_CPU_FIQ]); + icp_pic_init(0xca000000, pic[26], NULL); icp_pit_init(0x13000000, pic, 5); - pl011_init(0x16000000, pic, 1, serial_hds[0]); - pl011_init(0x17000000, pic, 2, serial_hds[1]); + pl011_init(0x16000000, pic[1], serial_hds[0]); + pl011_init(0x17000000, pic[2], serial_hds[1]); icp_control_init(0xcb000000); - pl050_init(0x18000000, pic, 3, 0); - pl050_init(0x19000000, pic, 4, 1); - pl181_init(0x1c000000, sd_bdrv, pic, 23, 24); + pl050_init(0x18000000, pic[3], 0); + pl050_init(0x19000000, pic[4], 1); + pl181_init(0x1c000000, sd_bdrv, pic[23], pic[24]); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "smc91c111") == 0) { - smc91c111_init(&nd_table[0], 0xc8000000, pic, 27); + smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); } } - pl110_init(ds, 0xc0000000, pic, 22, 0); + pl110_init(ds, 0xc0000000, pic[22], 0); arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, initrd_filename, 0x113); diff --git a/hw/irq.c b/hw/irq.c new file mode 100644 index 000000000..4bc8d80de --- /dev/null +++ b/hw/irq.c @@ -0,0 +1,57 @@ +/* + * QEMU IRQ/GPIO common code. + * + * Copyright (c) 2007 CodeSourcery. + * + * 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" + +struct IRQState { + qemu_irq_handler handler; + void *opaque; + int n; +}; + +void qemu_set_irq(qemu_irq irq, int level) +{ + if (!irq) + return; + + irq->handler(irq->opaque, irq->n, level); +} + +qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) +{ + qemu_irq *s; + struct IRQState *p; + int i; + + s = (qemu_irq *)qemu_mallocz(sizeof(qemu_irq) * n); + p = (struct IRQState *)qemu_mallocz(sizeof(struct IRQState) * n); + for (i = 0; i < n; i++) { + p->handler = handler; + p->opaque = opaque; + p->n = i; + s[i] = p; + p++; + } + return s; +} + diff --git a/hw/irq.h b/hw/irq.h new file mode 100644 index 000000000..652fd6abe --- /dev/null +++ b/hw/irq.h @@ -0,0 +1,21 @@ +/* Generic IRQ/GPIO pin infrastructure. */ + +typedef void (*qemu_irq_handler)(void *opaque, int n, int level); + +typedef struct IRQState *qemu_irq; + +void qemu_set_irq(qemu_irq irq, int level); + +static inline void qemu_irq_raise(qemu_irq irq) +{ + qemu_set_irq(irq, 1); +} + +static inline void qemu_irq_lower(qemu_irq irq) +{ + qemu_set_irq(irq, 0); +} + +/* Returns an array of N IRQs. */ +qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); + diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 193ff1220..88806a60a 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -374,7 +374,7 @@ static void lsi_update_irq(LSIState *s) level, s->dstat, s->sist1, s->sist0); last_level = level; } - pci_set_irq(&s->pci_dev, 0, level); + qemu_set_irq(s->pci_dev.irq[0], level); } /* Stop SCRIPTS execution and raise a SCSI interrupt. */ diff --git a/hw/m48t59.c b/hw/m48t59.c index daa1c524d..1c61401c5 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -41,7 +41,7 @@ struct m48t59_t { /* Model parameters */ int type; // 8 = m48t08, 59 = m48t59 /* Hardware parameters */ - int IRQ; + qemu_irq IRQ; int mem_index; uint32_t mem_base; uint32_t io_base; @@ -100,7 +100,7 @@ static void alarm_cb (void *opaque) uint64_t next_time; m48t59_t *NVRAM = opaque; - pic_set_irq(NVRAM->IRQ, 1); + qemu_set_irq(NVRAM->IRQ, 1); if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && (NVRAM->buffer[0x1FF4] & 0x80) == 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 && @@ -137,7 +137,7 @@ static void alarm_cb (void *opaque) next_time = 1 + mktime(&tm_now); } qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); - pic_set_irq(NVRAM->IRQ, 0); + qemu_set_irq(NVRAM->IRQ, 0); } @@ -173,8 +173,8 @@ static void watchdog_cb (void *opaque) /* May it be a hw CPU Reset instead ? */ qemu_system_reset_request(); } else { - pic_set_irq(NVRAM->IRQ, 1); - pic_set_irq(NVRAM->IRQ, 0); + qemu_set_irq(NVRAM->IRQ, 1); + qemu_set_irq(NVRAM->IRQ, 0); } } @@ -576,7 +576,7 @@ static CPUReadMemoryFunc *nvram_read[] = { }; /* Initialisation routine */ -m48t59_t *m48t59_init (int IRQ, target_ulong mem_base, +m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base, uint32_t io_base, uint16_t size, int type) { diff --git a/hw/m48t59.h b/hw/m48t59.h index af22dc112..df383e91c 100644 --- a/hw/m48t59.h +++ b/hw/m48t59.h @@ -6,7 +6,7 @@ typedef struct m48t59_t m48t59_t; void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val); uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr); void m48t59_toggle_lock (m48t59_t *NVRAM, int lock); -m48t59_t *m48t59_init (int IRQ, target_ulong mem_base, +m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base, uint32_t io_base, uint16_t size, int type); diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index bad4cbd86..8b9357459 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -54,7 +54,7 @@ struct RTCState { uint8_t cmos_data[128]; uint8_t cmos_index; struct tm current_tm; - int irq; + qemu_irq irq; /* periodic timer */ QEMUTimer *periodic_timer; int64_t next_periodic_time; @@ -95,7 +95,7 @@ static void rtc_periodic_timer(void *opaque) rtc_timer_update(s, s->next_periodic_time); s->cmos_data[RTC_REG_C] |= 0xc0; - pic_set_irq(s->irq, 1); + qemu_irq_raise(s->irq); } static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) @@ -314,14 +314,14 @@ static void rtc_update_second2(void *opaque) s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) { s->cmos_data[RTC_REG_C] |= 0xa0; - pic_set_irq(s->irq, 1); + qemu_irq_raise(s->irq); } } /* update ended interrupt */ if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { s->cmos_data[RTC_REG_C] |= 0x90; - pic_set_irq(s->irq, 1); + qemu_irq_raise(s->irq); } /* clear update in progress bit */ @@ -353,7 +353,7 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) break; case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; - pic_set_irq(s->irq, 0); + qemu_irq_lower(s->irq); s->cmos_data[RTC_REG_C] = 0x00; break; default: @@ -453,7 +453,7 @@ static int rtc_load(QEMUFile *f, void *opaque, int version_id) return 0; } -RTCState *rtc_init(int base, int irq) +RTCState *rtc_init(int base, qemu_irq irq) { RTCState *s; diff --git a/hw/mips_int.c b/hw/mips_int.c index ed489f1a1..f4e22dcf8 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -17,7 +17,7 @@ void cpu_mips_update_irq(CPUState *env) cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } -void cpu_mips_irq_request(void *opaque, int irq, int level) +static void cpu_mips_irq_request(void *opaque, int irq, int level) { CPUState *env = (CPUState *)opaque; @@ -31,3 +31,14 @@ void cpu_mips_irq_request(void *opaque, int irq, int level) } cpu_mips_update_irq(env); } + +void cpu_mips_irq_init_cpu(CPUState *env) +{ + qemu_irq *qi; + int i; + + qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8); + for (i = 0; i < 8; i++) { + env->irq[i] = qi[i]; + } +} diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 97707c116..6102ecb9a 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -60,12 +60,6 @@ typedef struct { static PITState *pit; -/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ -static void pic_irq_request(void *opaque, int level) -{ - cpu_mips_irq_request(opaque, 2, level); -} - /* Malta FPGA */ static void malta_fpga_update_display(void *opaque) { @@ -451,8 +445,7 @@ MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env) uart_chr = qemu_chr_open("vc"); qemu_chr_printf(uart_chr, "CBUS UART\r\n"); - s->uart = serial_mm_init(&cpu_mips_irq_request, env, base, 3, 2, - uart_chr, 0); + s->uart = serial_mm_init(base, 3, env->irq[2], uart_chr, 0); malta_fpga_reset(s); qemu_register_reset(malta_fpga_reset, s); @@ -676,6 +669,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, MaltaFPGAState *malta_fpga; int ret; mips_def_t *def; + qemu_irq *i8259; /* init CPUs */ if (cpu_model == NULL) { @@ -729,6 +723,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420); /* Init internal devices */ + cpu_mips_irq_init_cpu(env); cpu_mips_clock_init(env); cpu_mips_irqctrl_init(); @@ -736,31 +731,32 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, malta_fpga = malta_fpga_init(0x1f000000LL, env); /* Interrupt controller */ - isa_pic = pic_init(pic_irq_request, env); + /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ + i8259 = i8259_init(env->irq[2]); /* Northbridge */ - pci_bus = pci_gt64120_init(isa_pic); + pci_bus = pci_gt64120_init(i8259); /* Southbridge */ piix4_init(pci_bus, 80); - pci_piix3_ide_init(pci_bus, bs_table, 81); + pci_piix3_ide_init(pci_bus, bs_table, 81, i8259); usb_uhci_init(pci_bus, 82); piix4_pm_init(pci_bus, 83); - pit = pit_init(0x40, 0); + pit = pit_init(0x40, i8259[0]); DMA_init(0); /* Super I/O */ - kbd_init(); - rtc_state = rtc_init(0x70, 8); + i8042_init(i8259[1], i8259[12], 0x60); + rtc_state = rtc_init(0x70, i8259[8]); if (serial_hds[0]) - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); + serial_init(0x3f8, i8259[4], serial_hds[0]); if (serial_hds[1]) - serial_init(&pic_set_irq_new, isa_pic, 0x2f8, 3, serial_hds[1]); + serial_init(0x2f8, i8259[3], serial_hds[1]); if (parallel_hds[0]) - parallel_init(0x378, 7, parallel_hds[0]); + parallel_init(0x378, i8259[7], parallel_hds[0]); /* XXX: The floppy controller does not work correctly, something is probably wrong. - floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */ + floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); */ /* Sound card */ #ifdef HAS_AUDIO diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 8fbddf3c3..f6af322fd 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -35,11 +35,6 @@ extern FILE *logfile; static PITState *pit; /* PIT i8254 */ /*i8254 PIT is attached to the IRQ0 at PIC i8259 */ -/*The PIC is attached to the MIPS CPU INT0 pin */ -static void pic_irq_request(void *opaque, int level) -{ - cpu_mips_irq_request(opaque, 2, level); -} static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, uint32_t val) @@ -152,6 +147,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, RTCState *rtc_state; int i; mips_def_t *def; + qemu_irq *i8259; /* init CPUs */ if (cpu_model == NULL) { @@ -203,22 +199,24 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, } /* Init CPU internal devices */ + cpu_mips_irq_init_cpu(env); cpu_mips_clock_init(env); cpu_mips_irqctrl_init(); - rtc_state = rtc_init(0x70, 8); + /* The PIC is attached to the MIPS CPU INT0 pin */ + i8259 = i8259_init(env->irq[2]); + + rtc_state = rtc_init(0x70, i8259[8]); /* Register 64 KB of ISA IO space at 0x14000000 */ isa_mmio_init(0x14000000, 0x00010000); isa_mem_base = 0x10000000; - isa_pic = pic_init(pic_irq_request, env); - pit = pit_init(0x40, 0); + pit = pit_init(0x40, i8259[0]); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(&pic_set_irq_new, isa_pic, - serial_io[i], serial_irq[i], serial_hds[i]); + serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]); } } @@ -228,7 +226,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "ne2k_isa") == 0) { - isa_ne2000_init(0x300, 9, &nd_table[0]); + isa_ne2000_init(0x300, i8259[9], &nd_table[0]); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); @@ -236,10 +234,10 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, } for(i = 0; i < 2; i++) - isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], bs_table[2 * i], bs_table[2 * i + 1]); - kbd_init(); + i8042_init(i8259[1], i8259[12], 0x60); ds1225y_init(0x9000, "nvram"); } diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 9128cbff7..bd89e5dee 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -63,7 +63,7 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value) cpu_mips_update_count(env, cpu_mips_get_count(env)); if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) env->CP0_Cause &= ~(1 << CP0Ca_TI); - cpu_mips_irq_request(env, 7, 0); + qemu_irq_lower(env->irq[7]); } static void mips_timer_cb (void *opaque) @@ -79,7 +79,7 @@ static void mips_timer_cb (void *opaque) cpu_mips_update_count(env, cpu_mips_get_count(env)); if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) env->CP0_Cause |= 1 << CP0Ca_TI; - cpu_mips_irq_request(env, 7, 1); + qemu_irq_raise(env->irq[7]); } void cpu_mips_clock_init (CPUState *env) diff --git a/hw/ne2000.c b/hw/ne2000.c index df3f3b54a..1830ab548 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -136,7 +136,7 @@ typedef struct NE2000State { uint8_t phys[6]; /* mac address */ uint8_t curpag; uint8_t mult[8]; /* multicast mask array */ - int irq; + qemu_irq irq; PCIDevice *pci_dev; VLANClientState *vc; uint8_t macaddr[6]; @@ -164,16 +164,10 @@ static void ne2000_update_irq(NE2000State *s) int isr; isr = (s->isr & s->imr) & 0x7f; #if defined(DEBUG_NE2000) - printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n", - s->irq, isr ? 1 : 0, s->isr, s->imr); + printf("NE2000: Set IRQ to %d (%02x %02x)\n", + isr ? 1 : 0, s->isr, s->imr); #endif - if (s->irq == 16) { - /* PCI irq */ - pci_set_irq(s->pci_dev, 0, (isr != 0)); - } else { - /* ISA irq */ - pic_set_irq(s->irq, (isr != 0)); - } + qemu_set_irq(s->irq, (isr != 0)); } #define POLYNOMIAL 0x04c11db6 @@ -647,6 +641,7 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) static void ne2000_save(QEMUFile* f,void* opaque) { NE2000State* s=(NE2000State*)opaque; + int tmp; if (s->pci_dev) pci_device_save(s->pci_dev, f); @@ -669,7 +664,8 @@ static void ne2000_save(QEMUFile* f,void* opaque) qemu_put_buffer(f, s->phys, 6); qemu_put_8s(f, &s->curpag); qemu_put_buffer(f, s->mult, 8); - qemu_put_be32s(f, &s->irq); + tmp = 0; + qemu_put_be32s(f, &tmp); /* ignored, was irq */ qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE); } @@ -677,6 +673,7 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) { NE2000State* s=(NE2000State*)opaque; int ret; + int tmp; if (version_id > 3) return -EINVAL; @@ -709,13 +706,13 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) qemu_get_buffer(f, s->phys, 6); qemu_get_8s(f, &s->curpag); qemu_get_buffer(f, s->mult, 8); - qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &tmp); /* ignored */ qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE); return 0; } -void isa_ne2000_init(int base, int irq, NICInfo *nd) +void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) { NE2000State *s; @@ -804,7 +801,7 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) pci_register_io_region(&d->dev, 0, 0x100, PCI_ADDRESS_SPACE_IO, ne2000_map); s = &d->ne2000; - s->irq = 16; // PCI interrupt + s->irq = d->dev.irq[0]; s->pci_dev = (PCIDevice *)d; memcpy(s->macaddr, nd->macaddr, 6); ne2000_reset(s); diff --git a/hw/openpic.c b/hw/openpic.c index 1d9166511..3481f2d52 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -162,7 +162,7 @@ typedef struct IRQ_dst_t { CPUState *env; } IRQ_dst_t; -struct openpic_t { +typedef struct openpic_t { PCIDevice pci_dev; SetIRQFunc *set_irq; int mem_index; @@ -196,7 +196,7 @@ struct openpic_t { uint32_t mbr; /* Mailbox register */ } mailboxes[MAX_MAILBOXES]; #endif -}; +} openpic_t; static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) { @@ -321,7 +321,7 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) } } -void openpic_set_irq(void *opaque, int n_IRQ, int level) +static void openpic_set_irq(void *opaque, int n_IRQ, int level) { openpic_t *opp = opaque; IRQ_src_t *src; @@ -964,7 +964,7 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, #endif } -openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, +qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, int *pmem_index, int nb_cpus, CPUState **envp) { openpic_t *opp; @@ -1024,5 +1024,5 @@ openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, openpic_reset(opp); if (pmem_index) *pmem_index = opp->mem_index; - return opp; + return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ); } diff --git a/hw/parallel.c b/hw/parallel.c index d751d7a3a..c927ddd96 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -65,7 +65,7 @@ struct ParallelState { uint8_t datar; uint8_t status; uint8_t control; - int irq; + qemu_irq irq; int irq_pending; CharDriverState *chr; int hw_driver; @@ -76,9 +76,9 @@ struct ParallelState { static void parallel_update_irq(ParallelState *s) { if (s->irq_pending) - pic_set_irq(s->irq, 1); + qemu_irq_raise(s->irq); else - pic_set_irq(s->irq, 0); + qemu_irq_lower(s->irq); } static void @@ -401,7 +401,7 @@ static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr) } /* If fd is zero, it means that the parallel device uses the console */ -ParallelState *parallel_init(int base, int irq, CharDriverState *chr) +ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr) { ParallelState *s; uint8_t dummy; diff --git a/hw/pc.c b/hw/pc.c index 332bb1c68..e8dca4de0 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -49,15 +49,16 @@ static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) } /* MSDOS compatibility mode FPU exception support */ +static qemu_irq ferr_irq; /* XXX: add IGNNE support */ void cpu_set_ferr(CPUX86State *s) { - pic_set_irq(13, 1); + qemu_irq_raise(ferr_irq); } static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) { - pic_set_irq(13, 0); + qemu_irq_lower(ferr_irq); } /* TSC handling */ @@ -101,7 +102,7 @@ int cpu_get_pic_interrupt(CPUState *env) return intno; } -static void pic_irq_request(void *opaque, int level) +static void pic_irq_request(void *opaque, int irq, int level) { CPUState *env = opaque; if (level) @@ -403,7 +404,7 @@ static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; #ifdef HAS_AUDIO -static void audio_init (PCIBus *pci_bus) +static void audio_init (PCIBus *pci_bus, qemu_irq *pic) { struct soundhw *c; int audio_enabled = 0; @@ -420,7 +421,7 @@ static void audio_init (PCIBus *pci_bus) for (c = soundhw; c->name; ++c) { if (c->enabled) { if (c->isa) { - c->init.init_isa (s); + c->init.init_isa (s, pic); } else { if (pci_bus) { @@ -434,13 +435,13 @@ static void audio_init (PCIBus *pci_bus) } #endif -static void pc_init_ne2k_isa(NICInfo *nd) +static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic) { static int nb_ne2k = 0; if (nb_ne2k == NE2000_NB_MAX) return; - isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd); + isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd); nb_ne2k++; } @@ -460,6 +461,8 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, int piix3_devfn = -1; CPUState *env; NICInfo *nd; + qemu_irq *cpu_irq; + qemu_irq *i8259; linux_boot = (kernel_filename != NULL); @@ -643,8 +646,12 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); } + cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1); + i8259 = i8259_init(cpu_irq[0]); + ferr_irq = i8259[13]; + if (pci_enabled) { - pci_bus = i440fx_init(&i440fx_state); + pci_bus = i440fx_init(&i440fx_state, i8259); piix3_devfn = piix3_init(pci_bus, -1); } else { pci_bus = NULL; @@ -680,7 +687,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } } - rtc_state = rtc_init(0x70, 8); + rtc_state = rtc_init(0x70, i8259[8]); register_ioport_read(0x92, 1, 1, ioport92_read, NULL); register_ioport_write(0x92, 1, 1, ioport92_write, NULL); @@ -688,8 +695,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled) { ioapic = ioapic_init(); } - isa_pic = pic_init(pic_irq_request, first_cpu); - pit = pit_init(0x40, 0); + pit = pit_init(0x40, i8259[0]); pcspk_init(pit); if (pci_enabled) { pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); @@ -697,14 +703,14 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(&pic_set_irq_new, isa_pic, - serial_io[i], serial_irq[i], serial_hds[i]); + serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]); } } for(i = 0; i < MAX_PARALLEL_PORTS; i++) { if (parallel_hds[i]) { - parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); + parallel_init(parallel_io[i], i8259[parallel_irq[i]], + parallel_hds[i]); } } @@ -718,7 +724,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } } if (strcmp(nd->model, "ne2k_isa") == 0) { - pc_init_ne2k_isa(nd); + pc_init_ne2k_isa(nd, i8259); } else if (pci_enabled) { pci_nic_init(pci_bus, nd, -1); } else { @@ -728,21 +734,21 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } if (pci_enabled) { - pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1); + pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1, i8259); } else { for(i = 0; i < 2; i++) { - isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], bs_table[2 * i], bs_table[2 * i + 1]); } } - kbd_init(); + i8042_init(i8259[1], i8259[12], 0x60); DMA_init(0); #ifdef HAS_AUDIO - audio_init(pci_enabled ? pci_bus : NULL); + audio_init(pci_enabled ? pci_bus : NULL, i8259); #endif - floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); + floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); cmos_init(ram_size, boot_device, bs_table); diff --git a/hw/pci.c b/hw/pci.c index 4d9eb0329..b5dcbdafd 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -33,7 +33,7 @@ struct PCIBus { uint32_t config_reg; /* XXX: suppress */ /* low level pic */ SetIRQFunc *low_set_irq; - void *irq_opaque; + qemu_irq *irq_opaque; PCIDevice *devices[256]; PCIDevice *parent_dev; PCIBus *next; @@ -43,13 +43,14 @@ struct PCIBus { }; static void pci_update_mappings(PCIDevice *d); +static void pci_set_irq(void *opaque, int irq_num, int level); target_phys_addr_t pci_mem_base; static int pci_irq_index; static PCIBus *first_bus; PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *pic, int devfn_min, int nirq) + qemu_irq *pic, int devfn_min, int nirq) { PCIBus *bus; bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int))); @@ -129,6 +130,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, pci_dev->config_write = config_write; pci_dev->irq_index = pci_irq_index++; bus->devices[devfn] = pci_dev; + pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4); return pci_dev; } @@ -433,8 +435,9 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len) /* generic PCI irq support */ /* 0 <= irq_num <= 3. level must be 0 or 1 */ -void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) +static void pci_set_irq(void *opaque, int irq_num, int level) { + PCIDevice *pci_dev = (PCIDevice *)opaque; PCIBus *bus; int change; diff --git a/hw/pckbd.c b/hw/pckbd.c index 0ace3c0c9..a6f9d09ca 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -122,8 +122,8 @@ typedef struct KBDState { void *kbd; void *mouse; - int irq_kbd; - int irq_mouse; + qemu_irq irq_kbd; + qemu_irq irq_mouse; } KBDState; KBDState kbd_state; @@ -151,8 +151,8 @@ static void kbd_update_irq(KBDState *s) irq_kbd_level = 1; } } - pic_set_irq(s->irq_kbd, irq_kbd_level); - pic_set_irq(s->irq_mouse, irq_mouse_level); + qemu_set_irq(s->irq_kbd, irq_kbd_level); + qemu_set_irq(s->irq_mouse, irq_mouse_level); } static void kbd_update_kbd_irq(void *opaque, int level) @@ -356,12 +356,12 @@ static int kbd_load(QEMUFile* f, void* opaque, int version_id) return 0; } -void i8042_init(int kbd_irq_lvl, int mouse_irq_lvl, uint32_t io_base) +void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base) { KBDState *s = &kbd_state; - s->irq_kbd = kbd_irq_lvl; - s->irq_mouse = mouse_irq_lvl; + s->irq_kbd = kbd_irq; + s->irq_mouse = mouse_irq; kbd_reset(s); register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); @@ -377,8 +377,3 @@ void i8042_init(int kbd_irq_lvl, int mouse_irq_lvl, uint32_t io_base) #endif qemu_register_reset(kbd_reset, s); } - -void kbd_init(void) -{ - return i8042_init(1, 12, 0x60); -} diff --git a/hw/pcnet.c b/hw/pcnet.c index 71b8cf2a9..f2130d7b4 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -69,7 +69,7 @@ struct PCNetState_st { int xmit_pos, recv_pos; uint8_t buffer[4096]; int tx_busy; - void (*set_irq_cb)(void *s, int isr); + qemu_irq irq; void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, @@ -823,7 +823,7 @@ static void pcnet_update_irq(PCNetState *s) printf("pcnet: INTA=%d\n", isr); #endif } - s->set_irq_cb(s, isr); + qemu_set_irq(s->irq, isr); s->isr = isr; } @@ -1940,13 +1940,6 @@ static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index); } -static void pcnet_pci_set_irq_cb(void *opaque, int isr) -{ - PCNetState *s = opaque; - - pci_set_irq(&s->dev, 0, isr); -} - static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap) { @@ -2001,7 +1994,7 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); - d->set_irq_cb = pcnet_pci_set_irq_cb; + d->irq = d->dev.irq[0]; d->phys_mem_read = pci_physical_memory_read; d->phys_mem_write = pci_physical_memory_write; d->pci_dev = &d->dev; @@ -2025,14 +2018,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { (CPUWriteMemoryFunc *)&pcnet_ioport_writew, }; -static void pcnet_sparc_set_irq_cb(void *opaque, int isr) -{ - PCNetState *s = opaque; - - ledma_set_irq(s->dma_opaque, isr); -} - -void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque) +void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq) { PCNetState *d; int lance_io_memory; @@ -2047,7 +2033,7 @@ void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque) d->dma_opaque = dma_opaque; cpu_register_physical_memory(leaddr, 4, lance_io_memory); - d->set_irq_cb = pcnet_sparc_set_irq_cb; + d->irq = irq; d->phys_mem_read = ledma_memory_read; d->phys_mem_write = ledma_memory_write; diff --git a/hw/pcspk.c b/hw/pcspk.c index 0d52b31b4..2cbeff377 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -92,7 +92,7 @@ static void pcspk_callback(void *opaque, int free) } } -int pcspk_audio_init(AudioState *audio) +int pcspk_audio_init(AudioState *audio, qemu_irq *pic) { PCSpkState *s = &pcspk_state; audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0}; diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 1b16652bc..095698c9d 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -40,7 +40,7 @@ static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr) return s->config_reg; } -static void piix3_set_irq(void *pic, int irq_num, int level); +static void piix3_set_irq(qemu_irq *pic, int irq_num, int level); /* return the global irq number corresponding to a given device irq pin. We could also use the bus number to have a more precise @@ -155,14 +155,14 @@ static int i440fx_load(QEMUFile* f, void *opaque, int version_id) return 0; } -PCIBus *i440fx_init(PCIDevice **pi440fx_state) +PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) { PCIBus *b; PCIDevice *d; I440FXState *s; s = qemu_mallocz(sizeof(I440FXState)); - b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0, 4); + b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, pic, 0, 4); s->bus = b; register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); @@ -204,7 +204,7 @@ PCIDevice *piix4_dev; static int pci_irq_levels[4]; -static void piix3_set_irq(void *pic, int irq_num, int level) +static void piix3_set_irq(qemu_irq *pic, int irq_num, int level) { int i, pic_irq, pic_level; @@ -221,7 +221,7 @@ static void piix3_set_irq(void *pic, int irq_num, int level) if (pic_irq == piix3_dev->config[0x60 + i]) pic_level |= pci_irq_levels[i]; } - pic_set_irq(pic_irq, pic_level); + qemu_set_irq(pic[pic_irq], pic_level); } } diff --git a/hw/pl011.c b/hw/pl011.c index fb7ab7b53..29e551ad8 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -27,8 +27,7 @@ typedef struct { int read_count; int read_trigger; CharDriverState *chr; - void *pic; - int irq; + qemu_irq irq; } pl011_state; #define PL011_INT_TX 0x20 @@ -47,7 +46,7 @@ static void pl011_update(pl011_state *s) uint32_t flags; flags = s->int_level & s->int_enabled; - pic_set_irq_new(s->pic, s->irq, flags != 0); + qemu_set_irq(s->irq, flags != 0); } static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) @@ -224,7 +223,7 @@ static CPUWriteMemoryFunc *pl011_writefn[] = { pl011_write }; -void pl011_init(uint32_t base, void *pic, int irq, +void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr) { int iomemtype; @@ -235,7 +234,6 @@ void pl011_init(uint32_t base, void *pic, int irq, pl011_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); s->base = base; - s->pic = pic; s->irq = irq; s->chr = chr; s->read_trigger = 1; diff --git a/hw/pl050.c b/hw/pl050.c index 20451e532..eed729461 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -15,9 +15,8 @@ typedef struct { uint32_t cr; uint32_t clk; uint32_t last; - void *pic; int pending; - int irq; + qemu_irq irq; int is_mouse; } pl050_state; @@ -32,7 +31,7 @@ static void pl050_update(void *opaque, int level) s->pending = level; raise = (s->pending && (s->cr & 0x10) != 0) || (s->cr & 0x08) != 0; - pic_set_irq_new(s->pic, s->irq, raise); + qemu_set_irq(s->irq, raise); } static uint32_t pl050_read(void *opaque, target_phys_addr_t offset) @@ -105,7 +104,7 @@ static CPUWriteMemoryFunc *pl050_writefn[] = { pl050_write }; -void pl050_init(uint32_t base, void *pic, int irq, int is_mouse) +void pl050_init(uint32_t base, qemu_irq irq, int is_mouse) { int iomemtype; pl050_state *s; @@ -115,7 +114,6 @@ void pl050_init(uint32_t base, void *pic, int irq, int is_mouse) pl050_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); s->base = base; - s->pic = pic; s->irq = irq; s->is_mouse = is_mouse; if (is_mouse) diff --git a/hw/pl080.c b/hw/pl080.c index 549b3bfd1..aab1cacb9 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -49,8 +49,7 @@ typedef struct { int nchannels; /* Flag to avoid recursive DMA invocations. */ int running; - void *pic; - int irq; + qemu_irq irq; } pl080_state; static const unsigned char pl080_id[] = @@ -63,9 +62,9 @@ static void pl080_update(pl080_state *s) { if ((s->tc_int & s->tc_mask) || (s->err_int & s->err_mask)) - pic_set_irq_new(s->pic, s->irq, 1); + qemu_irq_raise(s->irq); else - pic_set_irq_new(s->pic, s->irq, 1); + qemu_irq_lower(s->irq); } static void pl080_run(pl080_state *s) @@ -325,7 +324,7 @@ static CPUWriteMemoryFunc *pl080_writefn[] = { /* The PL080 and PL081 are the same except for the number of channels they implement (8 and 2 respectively). */ -void *pl080_init(uint32_t base, void *pic, int irq, int nchannels) +void *pl080_init(uint32_t base, qemu_irq irq, int nchannels) { int iomemtype; pl080_state *s; @@ -335,7 +334,6 @@ void *pl080_init(uint32_t base, void *pic, int irq, int nchannels) pl080_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); s->base = base; - s->pic = pic; s->irq = irq; s->nchannels = nchannels; /* ??? Save/restore. */ diff --git a/hw/pl110.c b/hw/pl110.c index 16de16c0d..92a7e0bb6 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -29,7 +29,6 @@ typedef struct { DisplayState *ds; /* The Versatile/PB uses a slightly modified PL110 controller. */ int versatile; - void *pic; uint32_t timing[4]; uint32_t cr; uint32_t upbase; @@ -42,7 +41,7 @@ typedef struct { int invalidate; uint32_t pallette[256]; uint32_t raw_pallette[128]; - int irq; + qemu_irq irq; } pl110_state; static const unsigned char pl110_id[] = @@ -399,7 +398,7 @@ static CPUWriteMemoryFunc *pl110_writefn[] = { pl110_write }; -void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, +void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int versatile) { pl110_state *s; @@ -412,7 +411,6 @@ void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, s->base = base; s->ds = ds; s->versatile = versatile; - s->pic = pic; s->irq = irq; graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, NULL, s); diff --git a/hw/pl181.c b/hw/pl181.c index 7c3b5de4c..cf731cce9 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -40,8 +40,7 @@ typedef struct { int fifo_pos; int fifo_len; uint32_t fifo[PL181_FIFO_LEN]; - void *pic; - int irq[2]; + qemu_irq irq[2]; } pl181_state; #define PL181_CMD_INDEX 0x3f @@ -96,7 +95,7 @@ static void pl181_update(pl181_state *s) { int i; for (i = 0; i < 2; i++) { - pic_set_irq_new(s->pic, s->irq[i], (s->status & s->mask[i]) != 0); + qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0); } } @@ -425,7 +424,7 @@ static void pl181_reset(void *opaque) } void pl181_init(uint32_t base, BlockDriverState *bd, - void *pic, int irq0, int irq1) + qemu_irq irq0, qemu_irq irq1) { int iomemtype; pl181_state *s; @@ -436,7 +435,6 @@ void pl181_init(uint32_t base, BlockDriverState *bd, cpu_register_physical_memory(base, 0x00000fff, iomemtype); s->base = base; s->card = sd_init(bd); - s->pic = pic; s->irq[0] = irq0; s->irq[1] = irq1; qemu_register_reset(pl181_reset, s); diff --git a/hw/pl190.c b/hw/pl190.c index 55c7180f5..12d935f8a 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -17,7 +17,6 @@ #define PL190_NUM_PRIO 17 typedef struct { - arm_pic_handler handler; uint32_t base; DisplayState *ds; uint32_t level; @@ -33,9 +32,8 @@ typedef struct { /* Current priority level. */ int priority; int prev_prio[PL190_NUM_PRIO]; - void *parent; - int irq; - int fiq; + qemu_irq irq; + qemu_irq fiq; } pl190_state; static const unsigned char pl190_id[] = @@ -53,9 +51,9 @@ static void pl190_update(pl190_state *s) int set; set = (level & s->prio_mask[s->priority]) != 0; - pic_set_irq_new(s->parent, s->irq, set); + qemu_set_irq(s->irq, set); set = ((s->level | s->soft_level) & s->fiq_select) != 0; - pic_set_irq_new(s->parent, s->fiq, set); + qemu_set_irq(s->fiq, set); } static void pl190_set_irq(void *opaque, int irq, int level) @@ -232,21 +230,21 @@ void pl190_reset(pl190_state *s) pl190_update_vectors(s); } -void *pl190_init(uint32_t base, void *parent, int irq, int fiq) +qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq) { pl190_state *s; + qemu_irq *qi; int iomemtype; s = (pl190_state *)qemu_mallocz(sizeof(pl190_state)); iomemtype = cpu_register_io_memory(0, pl190_readfn, pl190_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); - s->handler = pl190_set_irq; + qi = qemu_allocate_irqs(pl190_set_irq, s, 16); s->base = base; - s->parent = parent; s->irq = irq; s->fiq = fiq; pl190_reset(s); /* ??? Save/restore. */ - return s; + return qi; } diff --git a/hw/ppc.c b/hw/ppc.c index 273c75f02..44555bd63 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -31,8 +31,7 @@ extern int loglevel; /* PowerPC internal fake IRQ controller * used to manage multiple sources hardware events */ -/* XXX: should be protected */ -void ppc_set_irq (void *opaque, int n_IRQ, int level) +static void ppc_set_irq (void *opaque, int n_IRQ, int level) { CPUState *env; @@ -51,6 +50,17 @@ void ppc_set_irq (void *opaque, int n_IRQ, int level) #endif } +void cpu_ppc_irq_init_cpu(CPUState *env) +{ + qemu_irq *qi; + int i; + + qi = qemu_allocate_irqs(ppc_set_irq, env, 32); + for (i = 0; i < 32; i++) { + env->irq[i] = qi[i]; + } +} + /* External IRQ callback from OpenPIC IRQ controller */ void ppc_openpic_irq (void *opaque, int n_IRQ, int level) { diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 55ca6ac53..18a1aab2b 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -264,11 +264,6 @@ static int vga_osi_call(CPUState *env) return 1; /* osi_call handled */ } -/* XXX: suppress that */ -static void pic_irq_request(void *opaque, int level) -{ -} - static uint8_t nvram_chksum(const uint8_t *buf, int n) { int sum, i; @@ -303,8 +298,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, { CPUState *env; char buf[1024]; - SetIRQFunc *set_irq; - void *pic; + qemu_irq *pic; m48t59_t *nvram; int unin_memory; int linux_boot, i; @@ -314,6 +308,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, PCIBus *pci_bus; const char *arch_name; int vga_bios_size, bios_size; + qemu_irq *dummy_irq; linux_boot = (kernel_filename != NULL); @@ -335,6 +330,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } cpu_ppc_register(env, def); + cpu_ppc_irq_init_cpu(env); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); @@ -416,17 +412,16 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* init basic PC hardware */ pic = heathrow_pic_init(&heathrow_pic_mem_index); - set_irq = heathrow_pic_set_irq; pci_bus = pci_grackle_init(0xfec00000, pic); pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); /* XXX: suppress that */ - isa_pic = pic_init(pic_irq_request, NULL); + dummy_irq = i8259_init(NULL); /* XXX: use Mac Serial port */ - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); + serial_init(0x3f8, dummy_irq[4], serial_hds[0]); for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) @@ -437,7 +432,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); /* cuda also initialize ADB */ - cuda_mem_index = cuda_init(set_irq, pic, 0x12); + cuda_mem_index = cuda_init(pic[0x12]); adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); @@ -450,7 +445,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, macio_init(pci_bus, 0x0017); - nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59); + nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59); arch_name = "HEATHROW"; } else { @@ -464,7 +459,6 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); pic = openpic_init(NULL, &ppc_openpic_irq, &openpic_mem_index, 1, &env); - set_irq = openpic_set_irq; pci_bus = pci_pmac_init(pic); /* init basic PC hardware */ pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, @@ -472,30 +466,30 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, vga_bios_offset, vga_bios_size); /* XXX: suppress that */ - isa_pic = pic_init(pic_irq_request, NULL); + dummy_irq = i8259_init(NULL); /* XXX: use Mac Serial port */ - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); + serial_init(0x3f8, dummy_irq[4], serial_hds[0]); for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) nd_table[i].model = "ne2k_pci"; pci_nic_init(pci_bus, &nd_table[i], -1); } #if 1 - ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13); - ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14); + ide0_mem_index = pmac_ide_init(&bs_table[0], pic[0x13]); + ide1_mem_index = pmac_ide_init(&bs_table[2], pic[0x14]); #else pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); #endif /* cuda also initialize ADB */ - cuda_mem_index = cuda_init(set_irq, pic, 0x19); + cuda_mem_index = cuda_init(pic[0x19]); adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); macio_init(pci_bus, 0x0022); - nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59); + nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59); arch_name = "MAC99"; } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index d504b1c6d..225b53168 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -96,11 +96,6 @@ static uint32_t speaker_ioport_read (void *opaque, uint32_t addr) return 0; } -static void pic_irq_request (void *opaque, int level) -{ - ppc_set_irq(opaque, PPC_INTERRUPT_EXT, level); -} - /* PCI intack register */ /* Read-only register (?) */ static void _PPC_intack_write (void *opaque, @@ -532,6 +527,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, uint32_t kernel_base, kernel_size, initrd_base, initrd_size; ppc_def_t *def; PCIBus *pci_bus; + qemu_irq *i8259; sysctrl = qemu_mallocz(sizeof(sysctrl_t)); if (sysctrl == NULL) @@ -552,6 +548,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } cpu_ppc_register(env, def); + cpu_ppc_irq_init_cpu(env); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); @@ -602,7 +599,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, } isa_mem_base = 0xc0000000; - pci_bus = pci_prep_init(); + i8259 = i8259_init(first_cpu->irq[PPC_INTERRUPT_EXT]); + pci_bus = pci_prep_init(i8259); // pci_bus = i440fx_init(); /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read, @@ -612,19 +610,18 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, /* init basic PC hardware */ pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0, 0); - rtc_init(0x70, 8); // openpic = openpic_init(0x00000000, 0xF0000000, 1); - isa_pic = pic_init(pic_irq_request, first_cpu); - // pit = pit_init(0x40, 0); + // pit = pit_init(0x40, i8259[0]); + rtc_init(0x70, i8259[8]); - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); + serial_init(0x3f8, i8259[4], serial_hds[0]); nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; for(i = 0; i < nb_nics1; i++) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "ne2k_isa") == 0) { - isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); @@ -632,15 +629,15 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, } for(i = 0; i < 2; i++) { - isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], bs_table[2 * i], bs_table[2 * i + 1]); } - kbd_init(); + i8042_init(i8259[1], i8259[12], 0x60); DMA_init(1); // AUD_init(); // SB16_init(); - fdctrl_init(6, 2, 0, 0x3f0, fd_table); + fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); /* Register speaker port */ register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); @@ -667,7 +664,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, usb_ohci_init_pci(pci_bus, 3, -1); } - nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); + nvram = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59); if (nvram == NULL) return; sysctrl->nvram = nvram; diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 3d93c065f..be62b8953 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -123,19 +123,19 @@ static int prep_map_irq(PCIDevice *pci_dev, int irq_num) return (irq_num + (pci_dev->devfn >> 3)) & 1; } -static void prep_set_irq(void *pic, int irq_num, int level) +static void prep_set_irq(qemu_irq *pic, int irq_num, int level) { - pic_set_irq(irq_num ? 11 : 9, level); + qemu_set_irq(pic[irq_num ? 11 : 9], level); } -PCIBus *pci_prep_init(void) +PCIBus *pci_prep_init(qemu_irq *pic) { PREPPCIState *s; PCIDevice *d; int PPC_io_memory; s = qemu_mallocz(sizeof(PREPPCIState)); - s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0, 2); + s->bus = pci_register_bus(prep_set_irq, prep_map_irq, pic, 0, 2); register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); diff --git a/hw/realview.c b/hw/realview.c index 1d351bf2b..c15c23152 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -18,7 +18,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename, const char *cpu_model) { CPUState *env; - void *pic; + qemu_irq *pic; void *scsi_hba; PCIBus *pci_bus; NICInfo *nd; @@ -38,24 +38,24 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3 is nIRQ (there are inconsistencies). However Linux 2.6.17 expects GIC1 to be nIRQ and ignores all the others, so do that for now. */ - pic = arm_gic_init(0x10040000, pic, ARM_PIC_CPU_IRQ); - pl050_init(0x10006000, pic, 20, 0); - pl050_init(0x10007000, pic, 21, 1); + pic = arm_gic_init(0x10040000, pic[ARM_PIC_CPU_IRQ]); + pl050_init(0x10006000, pic[20], 0); + pl050_init(0x10007000, pic[21], 1); - pl011_init(0x10009000, pic, 12, serial_hds[0]); - pl011_init(0x1000a000, pic, 13, serial_hds[1]); - pl011_init(0x1000b000, pic, 14, serial_hds[2]); - pl011_init(0x1000c000, pic, 15, serial_hds[3]); + pl011_init(0x10009000, pic[12], serial_hds[0]); + pl011_init(0x1000a000, pic[13], serial_hds[1]); + pl011_init(0x1000b000, pic[14], serial_hds[2]); + pl011_init(0x1000c000, pic[15], serial_hds[3]); /* DMA controller is optional, apparently. */ - pl080_init(0x10030000, pic, 24, 2); + pl080_init(0x10030000, pic[24], 2); - sp804_init(0x10011000, pic, 4); - sp804_init(0x10012000, pic, 5); + sp804_init(0x10011000, pic[4]); + sp804_init(0x10012000, pic[5]); - pl110_init(ds, 0x10020000, pic, 23, 1); + pl110_init(ds, 0x10020000, pic[23], 1); - pl181_init(0x10005000, sd_bdrv, pic, 17, 18); + pl181_init(0x10005000, sd_bdrv, pic[17], pic[18]); pci_bus = pci_vpb_init(pic, 48, 1); if (usb_enabled) { @@ -72,7 +72,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, if (!nd->model) nd->model = done_smc ? "rtl8139" : "smc91c111"; if (strcmp(nd->model, "smc91c111") == 0) { - smc91c111_init(nd, 0x4e000000, pic, 28); + smc91c111_init(nd, 0x4e000000, pic[28]); } else { pci_nic_init(pci_bus, nd, -1); } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index ee5b9f5e3..d1e60e829 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -687,7 +687,7 @@ static void rtl8139_update_irq(RTL8139State *s) DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus, s->IntrMask)); - pci_set_irq(s->pci_dev, 0, (isr != 0)); + qemu_set_irq(s->pci_dev->irq[0], (isr != 0)); } #define POLYNOMIAL 0x04c11db6 diff --git a/hw/sb16.c b/hw/sb16.c index 04325ac03..1610b3288 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -54,6 +54,7 @@ static struct { typedef struct SB16State { QEMUSoundCard card; + qemu_irq *pic; int irq; int dma; int hdma; @@ -187,7 +188,7 @@ static void aux_timer (void *opaque) { SB16State *s = opaque; s->can_write = 1; - pic_set_irq (s->irq, 1); + qemu_irq_raise (s->pic[s->irq]); } #define DMA8_AUTO 1 @@ -595,7 +596,7 @@ static void command (SB16State *s, uint8_t cmd) case 0xf3: dsp_out_data (s, 0xaa); s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2; - pic_set_irq (s->irq, 1); + qemu_irq_raise (s->pic[s->irq]); break; case 0xf9: @@ -763,7 +764,7 @@ static void complete (SB16State *s) bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); ticks = (bytes * ticks_per_sec) / freq; if (ticks < ticks_per_sec / 1024) { - pic_set_irq (s->irq, 1); + qemu_irq_raise (s->pic[s->irq]); } else { if (s->aux_ts) { @@ -855,10 +856,10 @@ static void legacy_reset (SB16State *s) static void reset (SB16State *s) { - pic_set_irq (s->irq, 0); + qemu_irq_lower (s->pic[s->irq]); if (s->dma_auto) { - pic_set_irq (s->irq, 1); - pic_set_irq (s->irq, 0); + qemu_irq_raise (s->pic[s->irq]); + qemu_irq_lower (s->pic[s->irq]); } s->mixer_regs[0x82] = 0; @@ -894,7 +895,7 @@ static IO_WRITE_PROTO (dsp_write) if (s->v2x6 == 1) { if (0 && s->highspeed) { s->highspeed = 0; - pic_set_irq (s->irq, 0); + qemu_irq_lower (s->pic[s->irq]); control (s, 0); } else { @@ -1005,7 +1006,7 @@ static IO_READ_PROTO (dsp_read) if (s->mixer_regs[0x82] & 1) { ack = 1; s->mixer_regs[0x82] &= 1; - pic_set_irq (s->irq, 0); + qemu_irq_lower (s->pic[s->irq]); } break; @@ -1014,7 +1015,7 @@ static IO_READ_PROTO (dsp_read) if (s->mixer_regs[0x82] & 2) { ack = 1; s->mixer_regs[0x82] &= 2; - pic_set_irq (s->irq, 0); + qemu_irq_lower (s->pic[s->irq]); } break; @@ -1222,7 +1223,7 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) if (s->left_till_irq <= 0) { s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1; - pic_set_irq (s->irq, 1); + qemu_irq_raise (s->pic[s->irq]); if (0 == s->dma_auto) { control (s, 0); speaker (s, 0); @@ -1389,7 +1390,7 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) return 0; } -int SB16_init (AudioState *audio) +int SB16_init (AudioState *audio, qemu_irq *pic) { SB16State *s; int i; @@ -1409,6 +1410,7 @@ int SB16_init (AudioState *audio) } s->cmd = -1; + s->pic = pic; s->irq = conf.irq; s->dma = conf.dma; s->hdma = conf.hdma; diff --git a/hw/serial.c b/hw/serial.c index ed2a85700..e0ff3a72c 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -83,9 +83,7 @@ struct SerialState { /* NOTE: this hidden state is necessary for tx irq generation as it can be reset while reading iir */ int thr_ipending; - SetIRQFunc *set_irq; - void *irq_opaque; - int irq; + qemu_irq irq; CharDriverState *chr; int last_break_enable; target_ulong base; @@ -102,9 +100,9 @@ static void serial_update_irq(SerialState *s) s->iir = UART_IIR_NO_INT; } if (s->iir != UART_IIR_NO_INT) { - s->set_irq(s->irq_opaque, s->irq, 1); + qemu_irq_raise(s->irq); } else { - s->set_irq(s->irq_opaque, s->irq, 0); + qemu_irq_lower(s->irq); } } @@ -345,16 +343,13 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id) } /* If fd is zero, it means that the serial device uses the console */ -SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, - int base, int irq, CharDriverState *chr) +SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr) { SerialState *s; s = qemu_mallocz(sizeof(SerialState)); if (!s) return NULL; - s->set_irq = set_irq; - s->irq_opaque = opaque; s->irq = irq; s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; @@ -428,9 +423,8 @@ static CPUWriteMemoryFunc *serial_mm_write[] = { &serial_mm_writel, }; -SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, - target_ulong base, int it_shift, - int irq, CharDriverState *chr, +SerialState *serial_mm_init (target_ulong base, int it_shift, + qemu_irq irq, CharDriverState *chr, int ioregister) { SerialState *s; @@ -439,8 +433,6 @@ SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, s = qemu_mallocz(sizeof(SerialState)); if (!s) return NULL; - s->set_irq = set_irq; - s->irq_opaque = opaque; s->irq = irq; s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; diff --git a/hw/shix.c b/hw/shix.c index 5857d0e06..000fd6af4 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -42,11 +42,6 @@ void irq_info(void) /* XXXXX */ } -void pic_set_irq(int irq, int level) -{ - /* XXXXX */ -} - void pic_info() { /* XXXXX */ diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index ed145a3e1..0c1eb5835 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -277,7 +277,7 @@ static void slavio_check_interrupts(void *opaque) * "irq" here is the bit number in the system interrupt register to * separate serial and keyboard interrupts sharing a level. */ -void pic_set_irq_new(void *opaque, int irq, int level) +void slavio_set_irq(void *opaque, int irq, int level) { SLAVIO_INTCTLState *s = opaque; @@ -305,7 +305,7 @@ void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu) DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level); if (cpu == (unsigned int)-1) { - pic_set_irq_new(opaque, irq, level); + slavio_set_irq(opaque, irq, level); return; } if (irq < 32) { @@ -372,7 +372,8 @@ void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env) } void *slavio_intctl_init(uint32_t addr, uint32_t addrg, - const uint32_t *intbit_to_level) + const uint32_t *intbit_to_level, + qemu_irq **irq) { int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; SLAVIO_INTCTLState *s; @@ -392,6 +393,7 @@ void *slavio_intctl_init(uint32_t addr, uint32_t addrg, register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); qemu_register_reset(slavio_intctl_reset, s); + *irq = qemu_allocate_irqs(slavio_set_irq, s, 32); slavio_intctl_reset(s); return s; } diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 1f4128e3f..9e7629ebb 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -36,19 +36,15 @@ #ifdef DEBUG_MISC #define MISC_DPRINTF(fmt, args...) \ do { printf("MISC: " fmt , ##args); } while (0) -#define pic_set_irq_new(intctl, irq, level) \ - do { printf("MISC: set_irq(%d): %d\n", (irq), (level)); \ - pic_set_irq_new((intctl), (irq),(level));} while (0) #else #define MISC_DPRINTF(fmt, args...) #endif typedef struct MiscState { - int irq; + qemu_irq irq; uint8_t config; uint8_t aux1, aux2; uint8_t diag, mctrl, sysctrl; - void *intctl; } MiscState; #define MISC_MAXADDR 1 @@ -58,9 +54,11 @@ static void slavio_misc_update_irq(void *opaque) MiscState *s = opaque; if ((s->aux2 & 0x4) && (s->config & 0x8)) { - pic_set_irq_new(s->intctl, s->irq, 1); + MISC_DPRINTF("Raise IRQ\n"); + qemu_irq_raise(s->irq); } else { - pic_set_irq_new(s->intctl, s->irq, 0); + MISC_DPRINTF("Lower IRQ\n"); + qemu_irq_lower(s->irq); } } @@ -184,8 +182,10 @@ static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = { static void slavio_misc_save(QEMUFile *f, void *opaque) { MiscState *s = opaque; + int tmp; - qemu_put_be32s(f, &s->irq); + tmp = 0; + qemu_put_be32s(f, &tmp); /* ignored, was IRQ. */ qemu_put_8s(f, &s->config); qemu_put_8s(f, &s->aux1); qemu_put_8s(f, &s->aux2); @@ -197,11 +197,12 @@ static void slavio_misc_save(QEMUFile *f, void *opaque) static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) { MiscState *s = opaque; + int tmp; if (version_id != 1) return -EINVAL; - qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &tmp); qemu_get_8s(f, &s->config); qemu_get_8s(f, &s->aux1); qemu_get_8s(f, &s->aux2); @@ -211,7 +212,7 @@ static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void *slavio_misc_init(uint32_t base, int irq, void *intctl) +void *slavio_misc_init(uint32_t base, qemu_irq irq) { int slavio_misc_io_memory; MiscState *s; @@ -237,7 +238,6 @@ void *slavio_misc_init(uint32_t base, int irq, void *intctl) cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory); s->irq = irq; - s->intctl = intctl; register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s); qemu_register_reset(slavio_misc_reset, s); diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 847710e3d..2ca3eed65 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -52,9 +52,6 @@ #ifdef DEBUG_SERIAL #define SER_DPRINTF(fmt, args...) \ do { printf("SER: " fmt , ##args); } while (0) -#define pic_set_irq_new(intctl, irq, level) \ - do { printf("SER: set_irq(%d): %d\n", (irq), (level)); \ - pic_set_irq_new((intctl), (irq),(level));} while (0) #else #define SER_DPRINTF(fmt, args...) #endif @@ -89,7 +86,7 @@ typedef struct { } SERIOQueue; typedef struct ChannelState { - int irq; + qemu_irq irq; int reg; int rxint, txint, rxint_under_svc, txint_under_svc; chn_id_t chn; // this channel, A (base+4) or B (base+0) @@ -98,7 +95,6 @@ typedef struct ChannelState { uint8_t rx, tx, wregs[16], rregs[16]; SERIOQueue queue; CharDriverState *chr; - void *intctl; } ChannelState; struct SerialState { @@ -166,7 +162,8 @@ static void slavio_serial_update_irq(ChannelState *s) irq = slavio_serial_update_irq_chn(s); irq |= slavio_serial_update_irq_chn(s->otherchn); - pic_set_irq_new(s->intctl, s->irq, irq); + SER_DPRINTF("IRQ = %d\n", irq); + qemu_set_irq(s->irq, irq); } static void slavio_serial_reset_chn(ChannelState *s) @@ -494,7 +491,9 @@ static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = { static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) { - qemu_put_be32s(f, &s->irq); + int tmp; + tmp = 0; + qemu_put_be32s(f, &tmp); /* unused, was IRQ. */ qemu_put_be32s(f, &s->reg); qemu_put_be32s(f, &s->rxint); qemu_put_be32s(f, &s->txint); @@ -516,10 +515,12 @@ static void slavio_serial_save(QEMUFile *f, void *opaque) static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) { + int tmp; + if (version_id > 2) return -EINVAL; - qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &tmp); /* unused */ qemu_get_be32s(f, &s->reg); qemu_get_be32s(f, &s->rxint); qemu_get_be32s(f, &s->txint); @@ -547,8 +548,8 @@ static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) } -SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, - CharDriverState *chr2, void *intctl) +SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1, + CharDriverState *chr2) { int slavio_serial_io_memory, i; SerialState *s; @@ -567,7 +568,6 @@ SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, s->chn[i].irq = irq; s->chn[i].chn = 1 - i; s->chn[i].type = ser; - s->chn[i].intctl = intctl; if (s->chn[i].chr) { qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, serial_receive1, serial_event, &s->chn[i]); @@ -665,7 +665,7 @@ static void sunmouse_event(void *opaque, put_queue(s, 0); } -void slavio_serial_ms_kbd_init(int base, int irq, void *intctl) +void slavio_serial_ms_kbd_init(int base, qemu_irq irq) { int slavio_serial_io_memory, i; SerialState *s; @@ -677,7 +677,6 @@ void slavio_serial_ms_kbd_init(int base, int irq, void *intctl) s->chn[i].irq = irq; s->chn[i].chn = 1 - i; s->chn[i].chr = NULL; - s->chn[i].intctl = intctl; } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 59fe6832f..8898afc46 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -28,9 +28,6 @@ #ifdef DEBUG_TIMER #define DPRINTF(fmt, args...) \ do { printf("TIMER: " fmt , ##args); } while (0) -#define pic_set_irq_new(intctl, irq, level) \ - do { printf("TIMER: set_irq(%d): %d\n", (irq), (level)); \ - pic_set_irq_new((intctl), (irq),(level));} while (0) #else #define DPRINTF(fmt, args...) #endif diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 855a9b1f1..d90ab32f6 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -24,8 +24,7 @@ typedef struct { uint16_t gpr; uint16_t ptr; uint16_t ercv; - void *pic; - int irq; + qemu_irq irq; int bank; int packet_num; int tx_alloc; @@ -86,7 +85,7 @@ static void smc91c111_update(smc91c111_state *s) if (s->tx_fifo_done_len != 0) s->int_level |= INT_TX; level = (s->int_level & s->int_mask) != 0; - pic_set_irq_new(s->pic, s->irq, level); + qemu_set_irq(s->irq, level); } /* Try to allocate a packet. Returns 0x80 on failure. */ @@ -693,7 +692,7 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = { smc91c111_writel }; -void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq) +void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) { smc91c111_state *s; int iomemtype; @@ -703,7 +702,6 @@ void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq) smc91c111_writefn, s); cpu_register_physical_memory(base, 16, iomemtype); s->base = base; - s->pic = pic; s->irq = irq; memcpy(s->macaddr, nd->macaddr, 6); diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index b17a12b9e..8480c8dbe 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -37,9 +37,6 @@ #ifdef DEBUG_DMA #define DPRINTF(fmt, args...) \ do { printf("DMA: " fmt , ##args); } while (0) -#define pic_set_irq_new(ctl, irq, level) \ - do { printf("DMA: set_irq(%d): %d\n", (irq), (level)); \ - pic_set_irq_new((ctl), (irq),(level));} while (0) #else #define DPRINTF(fmt, args...) #endif @@ -58,17 +55,11 @@ typedef struct DMAState DMAState; struct DMAState { uint32_t dmaregs[DMA_REGS]; - int espirq, leirq; - void *iommu, *esp_opaque, *lance_opaque, *intctl; + qemu_irq espirq, leirq; + void *iommu, *esp_opaque, *lance_opaque; + qemu_irq *pic; }; -void ledma_set_irq(void *opaque, int isr) -{ - DMAState *s = opaque; - - pic_set_irq_new(s->intctl, s->leirq, isr); -} - /* Note: on sparc, the lance 16 bit bus is swapped */ void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap) @@ -125,8 +116,9 @@ void espdma_raise_irq(void *opaque) { DMAState *s = opaque; + DPRINTF("Raise ESP IRQ\n"); s->dmaregs[0] |= DMA_INTR; - pic_set_irq_new(s->intctl, s->espirq, 1); + qemu_irq_raise(s->espirq); } void espdma_clear_irq(void *opaque) @@ -134,7 +126,8 @@ void espdma_clear_irq(void *opaque) DMAState *s = opaque; s->dmaregs[0] &= ~DMA_INTR; - pic_set_irq_new(s->intctl, s->espirq, 0); + DPRINTF("Lower ESP IRQ\n"); + qemu_irq_lower(s->espirq); } void espdma_memory_read(void *opaque, uint8_t *buf, int len) @@ -179,8 +172,10 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->dmaregs[saddr], val); switch (saddr) { case 0: - if (!(val & DMA_INTREN)) - pic_set_irq_new(s->intctl, s->espirq, 0); + if (!(val & DMA_INTREN)) { + DPRINTF("Lower ESP IRQ\n"); + qemu_irq_lower(s->espirq); + } if (val & DMA_RESET) { esp_reset(s->esp_opaque); } else if (val & 0x40) { @@ -194,8 +189,12 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) s->dmaregs[0] |= DMA_LOADED; break; case 4: - if (!(val & DMA_INTREN)) - pic_set_irq_new(s->intctl, s->leirq, 0); + /* ??? Should this mask out the lance IRQ? The NIC may re-assert + this IRQ unexpectedly. */ + if (!(val & DMA_INTREN)) { + DPRINTF("Lower Lance IRQ\n"); + qemu_irq_lower(s->leirq); + } if (val & DMA_RESET) pcnet_h_reset(s->lance_opaque); val &= 0x0fffffff; @@ -250,7 +249,8 @@ static int dma_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, void *intctl) +void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq, + void *iommu) { DMAState *s; int dma_io_memory; @@ -262,7 +262,6 @@ void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, void s->espirq = espirq; s->leirq = leirq; s->iommu = iommu; - s->intctl = intctl; dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s); cpu_register_physical_memory(daddr, 16 * 2, dma_io_memory); diff --git a/hw/sun4m.c b/hw/sun4m.c index 49e9c2287..b41dd25b1 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -182,11 +182,6 @@ void irq_info() slavio_irq_info(slavio_intctl); } -void pic_set_irq(int irq, int level) -{ - pic_set_irq_new(slavio_intctl, irq, level); -} - static void *slavio_misc; void qemu_system_powerdown(void) @@ -208,6 +203,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, unsigned int i; void *iommu, *dma, *main_esp, *main_lance = NULL; const sparc_def_t *def; + qemu_irq *slavio_irq; /* init CPUs */ sparc_find_by_name(cpu_model, &def); @@ -230,38 +226,40 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, iommu = iommu_init(hwdef->iommu_base); slavio_intctl = slavio_intctl_init(hwdef->intctl_base, hwdef->intctl_base + 0x10000, - &hwdef->intbit_to_level[0]); + &hwdef->intbit_to_level[0], + &slavio_irq); for(i = 0; i < smp_cpus; i++) { slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } - dma = sparc32_dma_init(hwdef->dma_base, hwdef->esp_irq, - hwdef->le_irq, iommu, slavio_intctl); + dma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], + slavio_irq[hwdef->le_irq], iommu); tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size, hwdef->vram_size, graphic_width, graphic_height); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { - main_lance = lance_init(&nd_table[0], hwdef->le_base, dma); + main_lance = lance_init(&nd_table[0], hwdef->le_base, dma, + slavio_irq[hwdef->le_irq]); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); } } - nvram = m48t59_init(0, hwdef->nvram_base, 0, hwdef->nvram_size, 8); + nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, + hwdef->nvram_size, 8); for (i = 0; i < MAX_CPUS; i++) { slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE, hwdef->clock_irq, 0, i, slavio_intctl); } slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2, (unsigned int)-1, slavio_intctl); - slavio_serial_ms_kbd_init(hwdef->ms_kb_base, hwdef->ms_kb_irq, - slavio_intctl); + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device - slavio_serial_init(hwdef->serial_base, hwdef->ser_irq, - serial_hds[1], serial_hds[0], slavio_intctl); - fdctrl_init(hwdef->fd_irq, 0, 1, hwdef->fd_base, fd_table); + slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], + serial_hds[1], serial_hds[0]); + fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table); main_esp = esp_init(bs_table, hwdef->esp_base, dma); for (i = 0; i < MAX_DISKS; i++) { @@ -270,8 +268,8 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, } } - slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->me_irq, - slavio_intctl); + slavio_misc = slavio_misc_init(hwdef->slavio_base, + slavio_irq[hwdef->me_irq]); if (hwdef->cs_base != (target_ulong)-1) cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); diff --git a/hw/sun4u.c b/hw/sun4u.c index e536c48ea..b10722f6e 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -223,14 +223,6 @@ void irq_info() { } -void pic_set_irq(int irq, int level) -{ -} - -void pic_set_irq_new(void *opaque, int irq, int level) -{ -} - void qemu_system_powerdown(void) { } @@ -340,14 +332,13 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(&pic_set_irq_new, NULL, - serial_io[i], serial_irq[i], serial_hds[i]); + serial_init(serial_io[i], NULL/*serial_irq[i]*/, serial_hds[i]); } } for(i = 0; i < MAX_PARALLEL_PORTS; i++) { if (parallel_hds[i]) { - parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); + parallel_init(parallel_io[i], NULL/*parallel_irq[i]*/, parallel_hds[i]); } } @@ -358,9 +349,10 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } pci_cmd646_ide_init(pci_bus, bs_table, 1); - kbd_init(); - floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); - nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); + /* FIXME: wire up interrupts. */ + i8042_init(NULL/*1*/, NULL/*12*/, 0x60); + floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table); + nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59); sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device, KERNEL_LOAD_ADDR, kernel_size, kernel_cmdline, diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 6448a6f25..f32d19522 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -146,12 +146,12 @@ static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num) return (irq_num + (pci_dev->devfn >> 3)) & 3; } -static void pci_unin_set_irq(void *pic, int irq_num, int level) +static void pci_unin_set_irq(qemu_irq *pic, int irq_num, int level) { - openpic_set_irq(pic, irq_num + 8, level); + qemu_set_irq(pic[irq_num + 8], level); } -PCIBus *pci_pmac_init(void *pic) +PCIBus *pci_pmac_init(qemu_irq *pic) { UNINState *s; PCIDevice *d; diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index a4f8aa6e3..680857956 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -59,8 +59,7 @@ enum ohci_type { }; typedef struct { - void *pic; - int irq; + qemu_irq irq; enum ohci_type type; target_phys_addr_t mem_base; int mem; @@ -282,10 +281,7 @@ static inline void ohci_intr_update(OHCIState *ohci) (ohci->intr_status & ohci->intr)) level = 1; - if (ohci->type == OHCI_TYPE_PCI) - pci_set_irq((PCIDevice *)ohci->pic, ohci->irq, level); - else - pic_set_irq_new(ohci->pic, ohci->irq, level); + qemu_set_irq(ohci->irq, level); } /* Set an interrupt */ @@ -1263,7 +1259,7 @@ static CPUWriteMemoryFunc *ohci_writefn[3]={ }; static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn, - void *pic, int irq, enum ohci_type type, const char *name) + qemu_irq irq, enum ohci_type type, const char *name) { int i; @@ -1286,7 +1282,6 @@ static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn, ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); ohci->name = name; - ohci->pic = pic; ohci->irq = irq; ohci->type = type; @@ -1334,19 +1329,19 @@ void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn) ohci->pci_dev.config[0x0b] = 0xc; ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ - usb_ohci_init(&ohci->state, num_ports, devfn, &ohci->pci_dev, - 0, OHCI_TYPE_PCI, ohci->pci_dev.name); + usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0], + OHCI_TYPE_PCI, ohci->pci_dev.name); pci_register_io_region((struct PCIDevice *)ohci, 0, 256, PCI_ADDRESS_SPACE_MEM, ohci_mapfunc); } void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, - void *pic, int irq) + qemu_irq irq) { OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState)); - usb_ohci_init(ohci, num_ports, devfn, pic, irq, + usb_ohci_init(ohci, num_ports, devfn, irq, OHCI_TYPE_PXA, "OHCI USB"); ohci->mem_base = base; diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 509c54f7c..638b199c4 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -119,7 +119,7 @@ static void uhci_update_irq(UHCIState *s) } else { level = 0; } - pci_set_irq(&s->dev, 3, level); + qemu_set_irq(s->dev.irq[3], level); } static void uhci_reset(UHCIState *s) diff --git a/hw/usb.h b/hw/usb.h index bd77eea8b..02a7355e6 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -208,7 +208,7 @@ void usb_uhci_init(PCIBus *bus, int devfn); /* usb-ohci.c */ void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn); void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, - void *pic, int irq); + qemu_irq irq); /* usb-linux.c */ USBDevice *usb_host_device_open(const char *devname); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 32854c2f9..98a2f4fb1 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -84,12 +84,12 @@ static int pci_vpb_map_irq(PCIDevice *d, int irq_num) return irq_num; } -static void pci_vpb_set_irq(void *pic, int irq_num, int level) +static void pci_vpb_set_irq(qemu_irq *pic, int irq_num, int level) { - pic_set_irq_new(pic, pci_vpb_irq + irq_num, level); + qemu_set_irq(pic[pci_vpb_irq + irq_num], level); } -PCIBus *pci_vpb_init(void *pic, int irq, int realview) +PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview) { PCIBus *s; PCIDevice *d; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index a91d7eff8..c0908161a 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -14,12 +14,11 @@ typedef struct vpb_sic_state { - arm_pic_handler handler; uint32_t base; uint32_t level; uint32_t mask; uint32_t pic_enable; - void *parent; + qemu_irq *parent; int irq; } vpb_sic_state; @@ -28,7 +27,7 @@ static void vpb_sic_update(vpb_sic_state *s) uint32_t flags; flags = s->level & s->mask; - pic_set_irq_new(s->parent, s->irq, flags != 0); + qemu_set_irq(s->parent[s->irq], flags != 0); } static void vpb_sic_update_pic(vpb_sic_state *s) @@ -40,7 +39,7 @@ static void vpb_sic_update_pic(vpb_sic_state *s) mask = 1u << i; if (!(s->pic_enable & mask)) continue; - pic_set_irq_new(s->parent, i, (s->level & mask) != 0); + qemu_set_irq(s->parent[i], (s->level & mask) != 0); } } @@ -52,7 +51,7 @@ static void vpb_sic_set_irq(void *opaque, int irq, int level) else s->level &= ~(1u << irq); if (s->pic_enable & (1u << irq)) - pic_set_irq_new(s->parent, irq, level); + qemu_set_irq(s->parent[irq], level); vpb_sic_update(s); } @@ -126,15 +125,16 @@ static CPUWriteMemoryFunc *vpb_sic_writefn[] = { vpb_sic_write }; -static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) +static qemu_irq *vpb_sic_init(uint32_t base, qemu_irq *parent, int irq) { vpb_sic_state *s; + qemu_irq *qi; int iomemtype; s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state)); if (!s) return NULL; - s->handler = vpb_sic_set_irq; + qi = qemu_allocate_irqs(vpb_sic_set_irq, s, 32); s->base = base; s->parent = parent; s->irq = irq; @@ -142,7 +142,7 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) vpb_sic_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); /* ??? Save/restore. */ - return s; + return qi; } /* Board init. */ @@ -158,8 +158,8 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, int board_id) { CPUState *env; - void *pic; - void *sic; + qemu_irq *pic; + qemu_irq *sic; void *scsi_hba; PCIBus *pci_bus; NICInfo *nd; @@ -176,10 +176,10 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, arm_sysctl_init(0x10000000, 0x41007004); pic = arm_pic_init_cpu(env); - pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); + pic = pl190_init(0x10140000, pic[0], pic[1]); sic = vpb_sic_init(0x10003000, pic, 31); - pl050_init(0x10006000, sic, 3, 0); - pl050_init(0x10007000, sic, 4, 1); + pl050_init(0x10006000, sic[3], 0); + pl050_init(0x10007000, sic[4], 1); pci_bus = pci_vpb_init(sic, 27, 0); /* The Versatile PCI bridge does not provide access to PCI IO space, @@ -189,7 +189,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, if (!nd->model) nd->model = done_smc ? "rtl8139" : "smc91c111"; if (strcmp(nd->model, "smc91c111") == 0) { - smc91c111_init(nd, 0x10010000, sic, 25); + smc91c111_init(nd, 0x10010000, sic[25]); } else { pci_nic_init(pci_bus, nd, -1); } @@ -204,20 +204,20 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, } } - pl011_init(0x101f1000, pic, 12, serial_hds[0]); - pl011_init(0x101f2000, pic, 13, serial_hds[1]); - pl011_init(0x101f3000, pic, 14, serial_hds[2]); - pl011_init(0x10009000, sic, 6, serial_hds[3]); + pl011_init(0x101f1000, pic[12], serial_hds[0]); + pl011_init(0x101f2000, pic[13], serial_hds[1]); + pl011_init(0x101f3000, pic[14], serial_hds[2]); + pl011_init(0x10009000, sic[6], serial_hds[3]); - pl080_init(0x10130000, pic, 17, 8); - sp804_init(0x101e2000, pic, 4); - sp804_init(0x101e3000, pic, 5); + pl080_init(0x10130000, pic[17], 8); + sp804_init(0x101e2000, pic[4]); + sp804_init(0x101e3000, pic[5]); /* The versatile/PB actually has a modified Color LCD controller that includes hardware cursor support from the PL111. */ - pl110_init(ds, 0x10120000, pic, 16, 1); + pl110_init(ds, 0x10120000, pic[16], 1); - pl181_init(0x10005000, sd_bdrv, sic, 22, 1); + pl181_init(0x10005000, sd_bdrv, sic[22], sic[1]); #if 0 /* Disabled because there's no way of specifying a block device. */ pl181_init(0x1000b000, NULL, sic, 23, 2); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 4b1792970..c91e2cac4 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -269,6 +269,8 @@ struct CPUMIPSState { #if defined(CONFIG_USER_ONLY) target_ulong tls_value; +#else + void *irq[8]; #endif CPU_COMMON diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7204abe02..1515af993 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -758,6 +758,7 @@ struct CPUPPCState { int error_code; int interrupt_request; uint32_t pending_interrupts; + void *irq[32]; /* Those resources are used only during code translation */ /* Next instruction pointer */ diff --git a/vl.h b/vl.h index eb87a511a..2f87946e8 100644 --- a/vl.h +++ b/vl.h @@ -709,7 +709,6 @@ typedef struct QEMUMachine { int qemu_register_machine(QEMUMachine *m); typedef void SetIRQFunc(void *opaque, int irq_num, int level); -typedef void IRQRequestFunc(void *opaque, int level); #if defined(TARGET_PPC) void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); @@ -719,6 +718,8 @@ void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); #endif +#include "hw/irq.h" + /* ISA bus */ extern target_phys_addr_t isa_mem_base; @@ -791,6 +792,9 @@ struct PCIDevice { /* ??? This is a PC-specific hack, and should be removed. */ int irq_index; + /* IRQ objects for the INTA-INTD pins. */ + qemu_irq *irq; + /* Current IRQ levels. Used internally by the generic PCI code. */ int irq_state[4]; }; @@ -804,8 +808,6 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, uint32_t size, int type, PCIMapIORegionFunc *map_func); -void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level); - uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len); void pci_default_write_config(PCIDevice *d, @@ -813,10 +815,10 @@ void pci_default_write_config(PCIDevice *d, void pci_device_save(PCIDevice *s, QEMUFile *f); int pci_device_load(PCIDevice *s, QEMUFile *f); -typedef void (*pci_set_irq_fn)(void *pic, int irq_num, int level); +typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level); typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - void *pic, int devfn_min, int nirq); + qemu_irq *pic, int devfn_min, int nirq); void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn); void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); @@ -829,22 +831,22 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, pci_map_irq_fn map_irq, const char *name); /* prep_pci.c */ -PCIBus *pci_prep_init(void); +PCIBus *pci_prep_init(qemu_irq *pic); /* grackle_pci.c */ -PCIBus *pci_grackle_init(uint32_t base, void *pic); +PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic); /* unin_pci.c */ -PCIBus *pci_pmac_init(void *pic); +PCIBus *pci_pmac_init(qemu_irq *pic); /* apb_pci.c */ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, - void *pic); + qemu_irq *pic); -PCIBus *pci_vpb_init(void *pic, int irq, int realview); +PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview); /* piix_pci.c */ -PCIBus *i440fx_init(PCIDevice **pi440fx_state); +PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic); void i440fx_set_smm(PCIDevice *d, int val); int piix3_init(PCIBus *bus, int devfn); void i440fx_init_memory_mappings(PCIDevice *d); @@ -852,7 +854,6 @@ void i440fx_init_memory_mappings(PCIDevice *d); int piix4_init(PCIBus *bus, int devfn); /* openpic.c */ -typedef struct openpic_t openpic_t; enum { OPENPIC_EVT_INT = 0, /* IRQ */ OPENPIC_EVT_CINT, /* critical IRQ */ @@ -860,18 +861,15 @@ enum { OPENPIC_EVT_DEBUG, /* Inconditional debug event */ OPENPIC_EVT_RESET, /* Core reset event */ }; -void openpic_set_irq(void *opaque, int n_IRQ, int level); -openpic_t *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, - int *pmem_index, int nb_cpus, - struct CPUState **envp); +qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, + int *pmem_index, int nb_cpus, + struct CPUState **envp); /* heathrow_pic.c */ -typedef struct HeathrowPICS HeathrowPICS; -void heathrow_pic_set_irq(void *opaque, int num, int level); -HeathrowPICS *heathrow_pic_init(int *pmem_index); +qemu_irq *heathrow_pic_init(int *pmem_index); /* gt64xxx.c */ -PCIBus *pci_gt64120_init(void *pic); +PCIBus *pci_gt64120_init(qemu_irq *pic); #ifdef HAS_AUDIO struct soundhw { @@ -880,7 +878,7 @@ struct soundhw { int enabled; int isa; union { - int (*init_isa) (AudioState *s); + int (*init_isa) (AudioState *s, qemu_irq *pic); int (*init_pci) (PCIBus *bus, AudioState *s); } init; }; @@ -958,13 +956,13 @@ extern uint8_t _translate_keycode(const int key); extern BlockDriverState *bs_table[MAX_DISKS + 1]; extern BlockDriverState *sd_bdrv; -void isa_ide_init(int iobase, int iobase2, int irq, +void isa_ide_init(int iobase, int iobase2, qemu_irq irq, BlockDriverState *hd0, BlockDriverState *hd1); void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, int secondary_ide_enabled); -void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn); -int pmac_ide_init (BlockDriverState **hd_table, - SetIRQFunc *set_irq, void *irq_opaque, int irq); +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, + qemu_irq *pic); +int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq); /* cdrom.c */ int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); @@ -978,13 +976,13 @@ ds1225y_t *ds1225y_init(target_ulong mem_base, const char *filename); int es1370_init (PCIBus *bus, AudioState *s); /* sb16.c */ -int SB16_init (AudioState *s); +int SB16_init (AudioState *s, qemu_irq *pic); /* adlib.c */ -int Adlib_init (AudioState *s); +int Adlib_init (AudioState *s, qemu_irq *pic); /* gus.c */ -int GUS_init (AudioState *s); +int GUS_init (AudioState *s, qemu_irq *pic); /* dma.c */ typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); @@ -1005,7 +1003,7 @@ extern BlockDriverState *fd_table[MAX_FD]; typedef struct fdctrl_t fdctrl_t; -fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, +fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, uint32_t io_base, BlockDriverState **fds); int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); @@ -1018,7 +1016,7 @@ void pci_i82559er_init(PCIBus *bus, NICInfo *nd, int devfn); /* ne2000.c */ -void isa_ne2000_init(int base, int irq, NICInfo *nd); +void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd); void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn); /* rtl8139.c */ @@ -1029,31 +1027,29 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); void pcnet_h_reset(void *opaque); -void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque); +void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq); /* vmmouse.c */ void *vmmouse_init(void *m); /* pckbd.c */ -void kbd_init(void); +void i8042_init(qemu_irq kdb_irq, qemu_irq mouse_irq, uint32_t io_base); /* mc146818rtc.c */ typedef struct RTCState RTCState; -RTCState *rtc_init(int base, int irq); +RTCState *rtc_init(int base, qemu_irq irq); void rtc_set_memory(RTCState *s, int addr, int val); void rtc_set_date(RTCState *s, const struct tm *tm); /* serial.c */ typedef struct SerialState SerialState; -SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, - int base, int irq, CharDriverState *chr); -SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, - target_ulong base, int it_shift, - int irq, CharDriverState *chr, +SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr); +SerialState *serial_mm_init (target_ulong base, int it_shift, + qemu_irq irq, CharDriverState *chr, int ioregister); uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr); void serial_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value); @@ -1065,7 +1061,7 @@ void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value); /* parallel.c */ typedef struct ParallelState ParallelState; -ParallelState *parallel_init(int base, int irq, CharDriverState *chr); +ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr); /* i8259.c */ @@ -1073,7 +1069,7 @@ typedef struct PicState2 PicState2; extern PicState2 *isa_pic; void pic_set_irq(int irq, int level); void pic_set_irq_new(void *opaque, int irq, int level); -PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque); +qemu_irq *i8259_init(qemu_irq parent_irq); void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, void *alt_irq_opaque); int pic_read_irq(PicState2 *s); @@ -1096,7 +1092,7 @@ void ioapic_set_irq(void *opaque, int vector, int level); typedef struct PITState PITState; -PITState *pit_init(int base, int irq); +PITState *pit_init(int base, qemu_irq irq); void pit_set_gate(PITState *pit, int channel, int val); int pit_get_gate(PITState *pit, int channel); int pit_get_initial_count(PITState *pit, int channel); @@ -1105,7 +1101,7 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); /* pcspk.c */ void pcspk_init(PITState *); -int pcspk_audio_init(AudioState *); +int pcspk_audio_init(AudioState *, qemu_irq *pic); #include "hw/smbus.h" @@ -1138,7 +1134,7 @@ extern QEMUMachine mips_machine; extern QEMUMachine mips_malta_machine; /* mips_int */ -extern void cpu_mips_irq_request(void *opaque, int irq, int level); +extern void cpu_mips_irq_init_cpu(CPUState *env); /* mips_timer.c */ extern void cpu_mips_clock_init(CPUState *); @@ -1149,7 +1145,7 @@ extern QEMUMachine shix_machine; #ifdef TARGET_PPC /* PowerPC hardware exceptions management helpers */ -void ppc_set_irq (void *opaque, int n_IRQ, int level); +void cpu_ppc_irq_init_cpu(CPUState *env); void ppc_openpic_irq (void *opaque, int n_IRQ, int level); int ppc_hw_interrupt (CPUState *env); ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); @@ -1188,12 +1184,11 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, /* slavio_intctl.c */ void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); void *slavio_intctl_init(uint32_t addr, uint32_t addrg, - const uint32_t *intbit_to_level); + const uint32_t *intbit_to_level, + qemu_irq **irq); void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); void slavio_pic_info(void *opaque); void slavio_irq_info(void *opaque); -void slavio_pic_set_irq(void *opaque, int irq, int level); -void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); /* loader.c */ int get_image_size(const char *filename); @@ -1208,12 +1203,12 @@ void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu, void *intctl); /* slavio_serial.c */ -SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, - CharDriverState *chr2, void *intctl); -void slavio_serial_ms_kbd_init(int base, int irq, void *intctl); +SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1, + CharDriverState *chr2); +void slavio_serial_ms_kbd_init(int base, qemu_irq); /* slavio_misc.c */ -void *slavio_misc_init(uint32_t base, int irq, void *intctl); +void *slavio_misc_init(uint32_t base, qemu_irq irq); void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ @@ -1222,8 +1217,8 @@ void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque); void esp_reset(void *opaque); /* sparc32_dma.c */ -void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, - void *intctl); +void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq, + void *iommu); void ledma_set_irq(void *opaque, int isr); void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); @@ -1307,7 +1302,7 @@ void adb_mouse_init(ADBBusState *bus); /* cuda.c */ extern ADBBusState adb_bus; -int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); +int cuda_init(qemu_irq irq); #include "hw/usb.h" @@ -1372,36 +1367,36 @@ void ps2_keyboard_set_translation(void *opaque, int mode); void ps2_mouse_fake_event(void *opaque); /* smc91c111.c */ -void smc91c111_init(NICInfo *, uint32_t, void *, int); +void smc91c111_init(NICInfo *, uint32_t, qemu_irq); /* pl110.c */ -void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int); +void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int); /* pl011.c */ -void pl011_init(uint32_t base, void *pic, int irq, CharDriverState *chr); +void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr); /* pl050.c */ -void pl050_init(uint32_t base, void *pic, int irq, int is_mouse); +void pl050_init(uint32_t base, qemu_irq irq, int is_mouse); /* pl080.c */ -void *pl080_init(uint32_t base, void *pic, int irq, int nchannels); +void *pl080_init(uint32_t base, qemu_irq irq, int nchannels); /* pl181.c */ void pl181_init(uint32_t base, BlockDriverState *bd, - void *pic, int irq0, int irq1); + qemu_irq irq0, qemu_irq irq1); /* pl190.c */ -void *pl190_init(uint32_t base, void *parent, int irq, int fiq); +qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq); /* arm-timer.c */ -void sp804_init(uint32_t base, void *pic, int irq); -void icp_pit_init(uint32_t base, void *pic, int irq); +void sp804_init(uint32_t base, qemu_irq irq); +void icp_pit_init(uint32_t base, qemu_irq *pic, int irq); /* arm_sysctl.c */ void arm_sysctl_init(uint32_t base, uint32_t sys_id); /* arm_gic.c */ -void *arm_gic_init(uint32_t base, void *parent, int parent_irq); +qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq); /* arm_boot.c */ -- cgit v1.2.3 From 1c6e907082cf00c483be24612c9c4504446f09e1 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 7 Apr 2007 19:33:54 +0000 Subject: Fix TCX base on SS10 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2636 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index b41dd25b1..f37127873 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -376,7 +376,7 @@ static const struct hwdef hwdefs[] = { /* SS-10 */ { .iommu_base = 0xe0000000, // XXX Actually at 0xfe0000000ULL (36 bits) - .tcx_base = 0x21000000, // 0xe21000000ULL, + .tcx_base = 0x20000000, // 0xe20000000ULL, .cs_base = -1, .slavio_base = 0xf1000000, // 0xff1000000ULL, .ms_kb_base = 0xf1000000, // 0xff1000000ULL, -- cgit v1.2.3 From 925fb139be707fe637bdadb25138c72efcf333b5 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 8 Apr 2007 06:29:06 +0000 Subject: Sparc32/64 CPU selection for user emulator git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2637 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 74798c7cc..277f194d9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1745,6 +1745,8 @@ int main(int argc, char **argv) arm_cpu_list(); #elif defined(TARGET_MIPS) mips_cpu_list(stdout, &fprintf); +#elif defined(TARGET_SPARC) + sparc_cpu_list(stdout, &fprintf); #endif _exit(1); } @@ -1900,6 +1902,20 @@ int main(int argc, char **argv) #elif defined(TARGET_SPARC) { int i; + const sparc_def_t *def; +#ifdef TARGET_SPARC64 + if (cpu_model == NULL) + cpu_model = "TI UltraSparc II"; +#else + if (cpu_model == NULL) + cpu_model = "Fujitsu MB86904"; +#endif + sparc_find_by_name(cpu_model, &def); + if (def == NULL) { + fprintf(stderr, "Unable to find Sparc CPU definition\n"); + exit(1); + } + cpu_sparc_register(env, def); env->pc = regs->pc; env->npc = regs->npc; env->y = regs->y; -- cgit v1.2.3 From 6ecd45348408054bd7afa43a95ed5d47ba3c2809 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 8 Apr 2007 11:22:29 +0000 Subject: Fix generated code disasm output on Sparc64 host git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2638 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/disas.c b/disas.c index c583c1d4d..c8fb2129b 100644 --- a/disas.c +++ b/disas.c @@ -258,6 +258,9 @@ void disas(FILE *out, void *code, unsigned long size) print_insn = print_insn_alpha; #elif defined(__sparc__) print_insn = print_insn_sparc; +#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) + disasm_info.mach = bfd_mach_sparc_v9b; +#endif #elif defined(__arm__) print_insn = print_insn_arm; #elif defined(__MIPSEB__) -- cgit v1.2.3 From 069dd10acf3e3109d119ffe02282b67f4bce5c44 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 9 Apr 2007 02:01:57 +0000 Subject: ARM IRQ fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2639 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl190.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pl190.c b/hw/pl190.c index 12d935f8a..64385b89d 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -240,7 +240,7 @@ qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq) iomemtype = cpu_register_io_memory(0, pl190_readfn, pl190_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); - qi = qemu_allocate_irqs(pl190_set_irq, s, 16); + qi = qemu_allocate_irqs(pl190_set_irq, s, 32); s->base = base; s->irq = irq; s->fiq = fiq; -- cgit v1.2.3 From dac93210243ec987eeaa8e78867f8b04de2c559e Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 9 Apr 2007 12:31:31 +0000 Subject: Remove bogus mtc0 handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2640 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index fa56f0603..fd11e1b8d 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4134,11 +4134,6 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) opn = "mfc0"; break; case OPC_MTC0: - /* If we get an exception, we want to restart at next instruction */ - /* XXX: breaks for mtc in delay slot */ - ctx->pc += 4; - save_cpu_state(ctx, 1); - ctx->pc -= 4; GEN_LOAD_REG_TN(T0, rt); gen_mtc0(ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; @@ -4153,11 +4148,6 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) opn = "dmfc0"; break; case OPC_DMTC0: - /* If we get an exception, we want to restart at next instruction */ - /* XXX: breaks for dmtc in delay slot */ - ctx->pc += 4; - save_cpu_state(ctx, 1); - ctx->pc -= 4; GEN_LOAD_REG_TN(T0, rt); gen_dmtc0(ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; -- cgit v1.2.3 From 97428a4d84a22795e0d9f1517677ec01cb1bede1 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 9 Apr 2007 14:13:40 +0000 Subject: Fix exception handling cornercase for rdhwr. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2641 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 30 ++++-------------------------- target-mips/translate.c | 16 +++++----------- 2 files changed, 9 insertions(+), 37 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 1e2dbc8c2..aec6a022f 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -2126,7 +2126,7 @@ void op_deret (void) void op_rdhwr_cpunum(void) { if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 0)) || + (env->CP0_HWREna & (1 << 0)) || (env->CP0_Status & (1 << CP0St_CU0))) T0 = env->CP0_EBase & 0x3ff; else @@ -2137,7 +2137,7 @@ void op_rdhwr_cpunum(void) void op_rdhwr_synci_step(void) { if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 1)) || + (env->CP0_HWREna & (1 << 1)) || (env->CP0_Status & (1 << CP0St_CU0))) T0 = env->SYNCI_Step; else @@ -2148,7 +2148,7 @@ void op_rdhwr_synci_step(void) void op_rdhwr_cc(void) { if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 2)) || + (env->CP0_HWREna & (1 << 2)) || (env->CP0_Status & (1 << CP0St_CU0))) T0 = env->CP0_Count; else @@ -2159,7 +2159,7 @@ void op_rdhwr_cc(void) void op_rdhwr_ccres(void) { if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 3)) || + (env->CP0_HWREna & (1 << 3)) || (env->CP0_Status & (1 << CP0St_CU0))) T0 = env->CCRes; else @@ -2167,28 +2167,6 @@ void op_rdhwr_ccres(void) RETURN(); } -void op_rdhwr_unimpl30(void) -{ - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 30)) || - (env->CP0_Status & (1 << CP0St_CU0))) - T0 = 0; - else - CALL_FROM_TB1(do_raise_exception, EXCP_RI); - RETURN(); -} - -void op_rdhwr_unimpl31(void) -{ - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 31)) || - (env->CP0_Status & (1 << CP0St_CU0))) - T0 = 0; - else - CALL_FROM_TB1(do_raise_exception, EXCP_RI); - RETURN(); -} - void op_save_state (void) { env->hflags = PARAM1; diff --git a/target-mips/translate.c b/target-mips/translate.c index fd11e1b8d..57527a5e9 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4825,32 +4825,26 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_RDHWR: switch (rd) { case 0: + save_cpu_state(ctx, 1); gen_op_rdhwr_cpunum(); break; case 1: + save_cpu_state(ctx, 1); gen_op_rdhwr_synci_step(); break; case 2: + save_cpu_state(ctx, 1); gen_op_rdhwr_cc(); break; case 3: + save_cpu_state(ctx, 1); gen_op_rdhwr_ccres(); break; case 29: #if defined (CONFIG_USER_ONLY) gen_op_tls_value (); -#else - generate_exception(ctx, EXCP_RI); -#endif - break; - case 30: - /* Implementation dependent */; - gen_op_rdhwr_unimpl30(); - break; - case 31: - /* Implementation dependent */; - gen_op_rdhwr_unimpl31(); break; +#endif default: /* Invalid */ MIPS_INVAL("rdhwr"); generate_exception(ctx, EXCP_RI); -- cgit v1.2.3 From 62c5609aa537a9c7f3c70e4baa5e67060368baa3 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 9 Apr 2007 14:14:21 +0000 Subject: Catch unaligned sc/scd. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2642 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_mem.c | 8 ++++++++ target-mips/translate.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index a1991721a..19373cf00 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -117,6 +117,10 @@ void glue(op_ll, MEMSUFFIX) (void) void glue(op_sc, MEMSUFFIX) (void) { CALL_FROM_TB0(dump_sc); + if (T0 & 0x3) { + env->CP0_BadVAddr = T0; + CALL_FROM_TB1(do_raise_exception, EXCP_AdES); + } if (T0 == env->CP0_LLAddr) { glue(stl, MEMSUFFIX)(T0, T1); T0 = 1; @@ -182,6 +186,10 @@ void glue(op_lld, MEMSUFFIX) (void) void glue(op_scd, MEMSUFFIX) (void) { CALL_FROM_TB0(dump_sc); + if (T0 & 0x7) { + env->CP0_BadVAddr = T0; + CALL_FROM_TB1(do_raise_exception, EXCP_AdES); + } if (T0 == env->CP0_LLAddr) { glue(stq, MEMSUFFIX)(T0, T1); T0 = 1; diff --git a/target-mips/translate.c b/target-mips/translate.c index 57527a5e9..e5eff065a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -714,6 +714,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, opn = "sd"; break; case OPC_SCD: + save_cpu_state(ctx, 1); GEN_LOAD_REG_TN(T1, rt); op_ldst(scd); opn = "scd"; @@ -812,6 +813,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, opn = "ll"; break; case OPC_SC: + save_cpu_state(ctx, 1); GEN_LOAD_REG_TN(T1, rt); op_ldst(sc); GEN_STORE_TN_REG(rt, T0); -- cgit v1.2.3 From 4e7a4a4e84998ec1e57d6e2b466db1bee462002e Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 9 Apr 2007 14:15:41 +0000 Subject: Mark watchpoint features as unimplemented. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2643 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 11 ++++++++--- target-mips/translate.c | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index aec6a022f..d7f0306fd 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1444,13 +1444,16 @@ void op_mtc0_config2 (void) void op_mtc0_watchlo0 (void) { - env->CP0_WatchLo = (int32_t)T0; + /* Watch exceptions for instructions, data loads, data stores + not implemented. */ + env->CP0_WatchLo = (int32_t)(T0 & ~0x7); RETURN(); } void op_mtc0_watchhi0 (void) { - env->CP0_WatchHi = T0 & 0x40FF0FF8; + env->CP0_WatchHi = (T0 & 0x40FF0FF8); + env->CP0_WatchHi &= ~(env->CP0_WatchHi & T0 & 0x7); RETURN(); } @@ -1620,7 +1623,9 @@ void op_dmtc0_epc (void) void op_dmtc0_watchlo0 (void) { - env->CP0_WatchLo = T0; + /* Watch exceptions for instructions, data loads, data stores + not implemented. */ + env->CP0_WatchLo = T0 & ~0x7; RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index e5eff065a..a1af8ab3b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5406,6 +5406,7 @@ void cpu_reset (CPUMIPSState *env) env->CP0_EBase = 0x80000000; env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); env->CP0_WatchLo = 0; + env->CP0_WatchHi = 0; /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); #endif -- cgit v1.2.3 From c50da3df61eae8b0c41b7591e315aaf5e9e8d507 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 9 Apr 2007 14:16:30 +0000 Subject: Proper handling of reserved bits in the context register. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2644 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op.c b/target-mips/op.c index d7f0306fd..4eb8a8926 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1293,7 +1293,7 @@ void op_mtc0_entrylo1 (void) void op_mtc0_context (void) { - env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0); + env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & ~0x007FFFFF); RETURN(); } -- cgit v1.2.3 From c090a8f4406ac674c1ae0ab4f3a789ca7dcb9720 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 9 Apr 2007 14:17:31 +0000 Subject: Fix CP0_IntCtl handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2645 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 5 +++-- target-mips/translate.c | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 4eb8a8926..026b08ab6 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1374,8 +1374,9 @@ void op_mtc0_status (void) void op_mtc0_intctl (void) { - /* vectored interrupts not implemented */ - env->CP0_IntCtl = 0; + /* vectored interrupts not implemented, timer on int 7, + no performance counters. */ + env->CP0_IntCtl |= T0 & 0x000002e0; RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index a1af8ab3b..0d9226a06 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5405,6 +5405,9 @@ void cpu_reset (CPUMIPSState *env) /* SMP not implemented */ env->CP0_EBase = 0x80000000; env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); + /* vectored interrupts not implemented, timer on int 7, + no performance counters. */ + env->CP0_IntCtl = 0xe0000000; env->CP0_WatchLo = 0; env->CP0_WatchHi = 0; /* Count register increments in debug mode, EJTAG version 1 */ -- cgit v1.2.3 From 682c4f15598fa82eb00973b9b14be86d1e5a726c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 9 Apr 2007 15:14:57 +0000 Subject: Fix monitor disasm output for Sparc64 target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2646 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/disas.c b/disas.c index c8fb2129b..fd14f682a 100644 --- a/disas.c +++ b/disas.c @@ -384,6 +384,9 @@ void monitor_disas(CPUState *env, 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) #ifdef TARGET_PPC64 disasm_info.mach = bfd_mach_ppc64; -- cgit v1.2.3 From e9df014c0b433ecd9785db4a423e472bc3db386a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 9 Apr 2007 22:45:36 +0000 Subject: Implement embedded IRQ controller for PowerPC 6xx/740 & 750. Fix PowerPC external interrupt input handling and lowering. Fix OpenPIC output pins management. Fix multiples bugs in OpenPIC IRQ management. Fix OpenPIC CPU(s) reset function. Fix Mac99 machine to properly route OpenPIC outputs to the PowerPC input pins. Fix PREP machine to properly route i8259 output to the PowerPC external interrupt pin. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2647 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 12 ++--- hw/openpic.c | 106 +++++++++++++++++++++++++------------ hw/ppc.c | 126 +++++++++++++++++++++++++++++++------------- hw/ppc_chrp.c | 42 +++++++++++---- hw/ppc_prep.c | 3 +- target-ppc/cpu.h | 46 ++++++++++++---- target-ppc/helper.c | 16 +++--- target-ppc/translate_init.c | 35 ++++++++++++ vl.h | 20 ++++--- 9 files changed, 287 insertions(+), 119 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 0eabacd64..284cb92ae 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -467,16 +467,14 @@ int cpu_exec(CPUState *env1) } #endif if (interrupt_request & CPU_INTERRUPT_HARD) { - if (ppc_hw_interrupt(env) == 1) { - /* Some exception was raised */ - if (env->pending_interrupts == 0) - env->interrupt_request &= ~CPU_INTERRUPT_HARD; + ppc_hw_interrupt(env); + if (env->pending_interrupts == 0) + env->interrupt_request &= ~CPU_INTERRUPT_HARD; #if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; + tmp_T0 = 0; #else - T0 = 0; + T0 = 0; #endif - } } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && diff --git a/hw/openpic.c b/hw/openpic.c index 3481f2d52..d52eb751e 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -159,18 +159,18 @@ typedef struct IRQ_dst_t { uint32_t pcsr; /* CPU sensitivity register */ IRQ_queue_t raised; IRQ_queue_t servicing; - CPUState *env; + qemu_irq *irqs; } IRQ_dst_t; typedef struct openpic_t { PCIDevice pci_dev; - SetIRQFunc *set_irq; int mem_index; /* Global registers */ uint32_t frep; /* Feature reporting register */ uint32_t glbc; /* Global configuration register */ uint32_t micr; /* MPIC interrupt configuration register */ uint32_t veni; /* Vendor identification register */ + uint32_t pint; /* Processor initialization register */ uint32_t spve; /* Spurious vector register */ uint32_t tifr; /* Timer frequency reporting register */ /* Source registers */ @@ -196,6 +196,8 @@ typedef struct openpic_t { uint32_t mbr; /* Mailbox register */ } mailboxes[MAX_MAILBOXES]; #endif + /* IRQ out is used when in bypass mode (not implemented) */ + qemu_irq irq_out; } openpic_t; static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) @@ -255,19 +257,34 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) priority = IPVP_PRIORITY(src->ipvp); if (priority <= dst->pctp) { /* Too low priority */ + DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", + __func__, n_IRQ, n_CPU); return; } if (IRQ_testbit(&dst->raised, n_IRQ)) { /* Interrupt miss */ + DPRINTF("%s: IRQ %d was missed on CPU %d\n", + __func__, n_IRQ, n_CPU); return; } set_bit(&src->ipvp, IPVP_ACTIVITY); IRQ_setbit(&dst->raised, n_IRQ); - if (priority > dst->raised.priority) { - IRQ_get_next(opp, &dst->raised); - DPRINTF("Raise CPU IRQ fn %p env %p\n", opp->set_irq, dst->env); - opp->set_irq(dst->env, OPENPIC_EVT_INT, 1); + if (priority < dst->raised.priority) { + /* An higher priority IRQ is already raised */ + DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n", + __func__, n_IRQ, dst->raised.next, n_CPU); + return; + } + IRQ_get_next(opp, &dst->raised); + if (IRQ_get_next(opp, &dst->servicing) != -1 && + priority < dst->servicing.priority) { + DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", + __func__, n_IRQ, dst->servicing.next, n_CPU); + /* Already servicing a higher priority IRQ */ + return; } + DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); } /* update pic state because registers for n_IRQ have changed value */ @@ -280,27 +297,34 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) if (!src->pending) { /* no irq pending */ + DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); return; } if (test_bit(&src->ipvp, IPVP_MASK)) { /* Interrupt source is disabled */ + DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); return; } if (IPVP_PRIORITY(src->ipvp) == 0) { /* Priority set to zero */ + DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); return; } if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { /* IRQ already active */ + DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); return; } if (src->ide == 0x00000000) { /* No target */ + DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; } - if (!test_bit(&src->ipvp, IPVP_MODE) || - src->ide == (1 << src->last_cpu)) { + if (src->ide == (1 << src->last_cpu)) { + /* Only one CPU is allowed to receive this IRQ */ + IRQ_local_pipe(opp, src->last_cpu, n_IRQ); + } else if (!test_bit(&src->ipvp, IPVP_MODE)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { if (test_bit(&src->ide, i)) @@ -308,9 +332,8 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) } } else { /* Distributed delivery mode */ - /* XXX: incorrect code */ - for (i = src->last_cpu; i < src->last_cpu; i++) { - if (i == MAX_IRQ) + for (i = src->last_cpu + 1; i != src->last_cpu; i++) { + if (i == opp->nb_cpus) i = 0; if (test_bit(&src->ide, i)) { IRQ_local_pipe(opp, i, n_IRQ); @@ -350,6 +373,7 @@ static void openpic_reset (openpic_t *opp) /* Initialise controller registers */ opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; opp->veni = VENI; + opp->pint = 0x00000000; opp->spve = 0x000000FF; opp->tifr = 0x003F7A00; /* ? */ @@ -360,7 +384,7 @@ static void openpic_reset (openpic_t *opp) opp->src[i].ide = 0x00000000; } /* Initialise IRQ destinations */ - for (i = 0; i < opp->nb_cpus; i++) { + for (i = 0; i < MAX_CPU; i++) { opp->dst[i].pctp = 0x0000000F; opp->dst[i].pcsr = 0x00000000; memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); @@ -511,6 +535,8 @@ static void write_mailbox_register (openpic_t *opp, int n_mbx, static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) { openpic_t *opp = opaque; + IRQ_dst_t *dst; + int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) @@ -530,11 +556,18 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) case 0x80: /* VENI */ break; case 0x90: /* PINT */ - /* XXX: Should be able to reset any CPU */ - if (val & 1) { - DPRINTF("Reset CPU IRQ\n"); - // opp->set_irq(dst->env, OPENPIC_EVT_RESET, 1); + for (idx = 0; idx < opp->nb_cpus; idx++) { + if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) { + DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); + dst = &opp->dst[idx]; + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); + } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) { + DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); + dst = &opp->dst[idx]; + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); + } } + opp->pint = val; break; #if MAX_IPI > 0 case 0xA0: /* IPI_IPVP */ @@ -735,7 +768,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) openpic_t *opp = opaque; IRQ_src_t *src; IRQ_dst_t *dst; - int idx, n_IRQ; + int idx, s_IRQ, n_IRQ; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) @@ -770,21 +803,21 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) break; case 0xB0: /* PEOI */ DPRINTF("PEOI\n"); - n_IRQ = IRQ_get_next(opp, &dst->servicing); - IRQ_resetbit(&dst->servicing, n_IRQ); + s_IRQ = IRQ_get_next(opp, &dst->servicing); + IRQ_resetbit(&dst->servicing, s_IRQ); dst->servicing.next = -1; - src = &opp->src[n_IRQ]; /* Set up next servicing IRQ */ - IRQ_get_next(opp, &dst->servicing); - /* Check queued interrupts. */ - n_IRQ = IRQ_get_next(opp, &dst->raised); - if (n_IRQ != -1) { - src = &opp->src[n_IRQ]; - if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { - DPRINTF("Raise CPU IRQ\n"); - opp->set_irq(dst->env, OPENPIC_EVT_INT, 1); - } - } + s_IRQ = IRQ_get_next(opp, &dst->servicing); + /* Check queued interrupts. */ + n_IRQ = IRQ_get_next(opp, &dst->raised); + src = &opp->src[n_IRQ]; + if (n_IRQ != -1 && + (s_IRQ == -1 || + IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { + DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", + idx, n_IRQ); + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); + } break; default: break; @@ -815,11 +848,13 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) retval = idx; break; case 0xA0: /* PIAC */ + DPRINTF("Lower OpenPIC INT output\n"); + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); n_IRQ = IRQ_get_next(opp, &dst->raised); DPRINTF("PIAC: irq=%d\n", n_IRQ); if (n_IRQ == -1) { /* No more interrupt pending */ - retval = opp->spve; + retval = IPVP_VECTOR(opp->spve); } else { src = &opp->src[n_IRQ]; if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || @@ -964,8 +999,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, #endif } -qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, - int *pmem_index, int nb_cpus, CPUState **envp) +qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + qemu_irq **irqs, qemu_irq irq_out) { openpic_t *opp; uint8_t *pci_conf; @@ -995,7 +1030,6 @@ qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, } else { opp = qemu_mallocz(sizeof(openpic_t)); } - opp->set_irq = set_irq; opp->mem_index = cpu_register_io_memory(0, openpic_read, openpic_write, opp); @@ -1020,9 +1054,11 @@ qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, opp->src[i].type = IRQ_INTERNAL; } for (i = 0; i < nb_cpus; i++) - opp->dst[i].env = envp[i]; + opp->dst[i].irqs = irqs[i]; + opp->irq_out = irq_out; openpic_reset(opp); if (pmem_index) *pmem_index = opp->mem_index; + return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ); } diff --git a/hw/ppc.c b/hw/ppc.c index 44555bd63..f5c45001b 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -1,5 +1,5 @@ /* - * QEMU generic PPC hardware System Emulator + * QEMU generic PowerPC hardware System Emulator * * Copyright (c) 2003-2007 Jocelyn Mayer * @@ -24,18 +24,13 @@ #include "vl.h" #include "m48t59.h" +//#define PPC_DEBUG_IRQ + extern FILE *logfile; extern int loglevel; -/*****************************************************************************/ -/* PowerPC internal fake IRQ controller - * used to manage multiple sources hardware events - */ -static void ppc_set_irq (void *opaque, int n_IRQ, int level) +void ppc_set_irq (CPUState *env, int n_IRQ, int level) { - CPUState *env; - - env = opaque; if (level) { env->pending_interrupts |= 1 << n_IRQ; cpu_interrupt(env, CPU_INTERRUPT_HARD); @@ -44,49 +39,104 @@ static void ppc_set_irq (void *opaque, int n_IRQ, int level) if (env->pending_interrupts == 0) cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } -#if 0 +#if defined(PPC_DEBUG_IRQ) printf("%s: %p n_IRQ %d level %d => pending %08x req %08x\n", __func__, env, n_IRQ, level, env->pending_interrupts, env->interrupt_request); #endif } -void cpu_ppc_irq_init_cpu(CPUState *env) +/* PowerPC 6xx / 7xx internal IRQ controller */ +static void ppc6xx_set_irq (void *opaque, int pin, int level) { - qemu_irq *qi; - int i; + CPUState *env = opaque; + int cur_level; - qi = qemu_allocate_irqs(ppc_set_irq, env, 32); - for (i = 0; i < 32; i++) { - env->irq[i] = qi[i]; +#if defined(PPC_DEBUG_IRQ) + printf("%s: env %p pin %d level %d\n", __func__, env, pin, level); +#endif + cur_level = (env->irq_input_state >> pin) & 1; + /* Don't generate spurious events */ + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0) || 0) { + switch (pin) { + case PPC_INPUT_INT: + /* Level sensitive - asserted high */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the external IRQ state to %d\n", __func__, level); +#endif + ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + break; + case PPC_INPUT_SMI: + /* Level sensitive - active high */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the SMI IRQ state to %d\n", __func__, level); +#endif + ppc_set_irq(env, PPC_INTERRUPT_SMI, level); + break; + case PPC_INPUT_MCP: + /* Negative edge sensitive */ + /* XXX: TODO: actual reaction may depends on HID0 status + * 603/604/740/750: check HID0[EMCP] + */ + if (cur_level == 1 && level == 0) { +#if defined(PPC_DEBUG_IRQ) + printf("%s: raise machine check state\n", __func__); +#endif + ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + } + break; + case PPC_INPUT_CKSTP_IN: + /* Level sensitive - active low */ + /* XXX: TODO: relay the signal to CKSTP_OUT pin */ + if (level) { +#if defined(PPC_DEBUG_IRQ) + printf("%s: stop the CPU\n", __func__); +#endif + env->halted = 1; + } else { +#if defined(PPC_DEBUG_IRQ) + printf("%s: restart the CPU\n", __func__); +#endif + env->halted = 0; + } + break; + case PPC_INPUT_HRESET: + /* Level sensitive - active low */ + if (level) { +#if 0 // XXX: TOFIX +#if defined(PPC_DEBUG_IRQ) + printf("%s: reset the CPU\n", __func__); +#endif + cpu_reset(env); +#endif + } + break; + case PPC_INPUT_SRESET: +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the RESET IRQ state to %d\n", __func__, level); +#endif + ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + break; + default: + /* Unknown pin - do nothing */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: unknown IRQ pin %d\n", __func__, pin); +#endif + return; + } + if (level) + env->irq_input_state |= 1 << pin; + else + env->irq_input_state &= ~(1 << pin); } } -/* External IRQ callback from OpenPIC IRQ controller */ -void ppc_openpic_irq (void *opaque, int n_IRQ, int level) +void ppc6xx_irq_init (CPUState *env) { - switch (n_IRQ) { - case OPENPIC_EVT_INT: - n_IRQ = PPC_INTERRUPT_EXT; - break; - case OPENPIC_EVT_CINT: - /* On PowerPC BookE, critical input use vector 0 */ - n_IRQ = PPC_INTERRUPT_RESET; - break; - case OPENPIC_EVT_MCK: - n_IRQ = PPC_INTERRUPT_MCK; - break; - case OPENPIC_EVT_DEBUG: - n_IRQ = PPC_INTERRUPT_DEBUG; - break; - case OPENPIC_EVT_RESET: - qemu_system_reset_request(); - return; - } - ppc_set_irq(opaque, n_IRQ, level); + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6); } /*****************************************************************************/ -/* PPC time base and decrementer emulation */ +/* PowerPC time base and decrementer emulation */ //#define DEBUG_TB struct ppc_tb_t { diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 18a1aab2b..c418cd1b4 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -23,6 +23,9 @@ */ #include "vl.h" +/* SMP is not enabled, for now */ +#define MAX_CPUS 1 + #define BIOS_FILENAME "ppc_rom.bin" #define VGABIOS_FILENAME "video.x" #define NVRAM_SIZE 0x2000 @@ -296,9 +299,9 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, const char *cpu_model, int is_heathrow) { - CPUState *env; + CPUState *env, *envs[MAX_CPUS]; char buf[1024]; - qemu_irq *pic; + qemu_irq *pic, **openpic_irqs; m48t59_t *nvram; int unin_memory; int linux_boot, i; @@ -329,13 +332,13 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, if (def == NULL) { cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } - cpu_ppc_register(env, def); - cpu_ppc_irq_init_cpu(env); - - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); - - env->osi_call = vga_osi_call; + for (i = 0; i < smp_cpus; i++) { + cpu_ppc_register(env, def); + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + env->osi_call = vga_osi_call; + envs[i] = env; + } /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -458,7 +461,26 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); - pic = openpic_init(NULL, &ppc_openpic_irq, &openpic_mem_index, 1, &env); + openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *)); + openpic_irqs[0] = + qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); + for (i = 0; i < smp_cpus; i++) { + /* Mac99 IRQ connection between OpenPIC outputs pins + * and PowerPC input pins + */ + openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); + openpic_irqs[i][OPENPIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_MCK] = + ((qemu_irq *)env->irq_inputs)[PPC_INPUT_MCP]; + openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; /* Not connected ? */ + openpic_irqs[i][OPENPIC_OUTPUT_RESET] = + ((qemu_irq *)env->irq_inputs)[PPC_INPUT_HRESET]; /* Check this */ + } + pic = openpic_init(NULL, &openpic_mem_index, smp_cpus, + openpic_irqs, NULL); pci_bus = pci_pmac_init(pic); /* init basic PC hardware */ pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 225b53168..8b53ef30a 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -548,7 +548,6 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } cpu_ppc_register(env, def); - cpu_ppc_irq_init_cpu(env); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); @@ -599,7 +598,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, } isa_mem_base = 0xc0000000; - i8259 = i8259_init(first_cpu->irq[PPC_INTERRUPT_EXT]); + i8259 = i8259_init(first_cpu->irq_inputs[PPC_INPUT_INT]); pci_bus = pci_prep_init(i8259); // pci_bus = i440fx_init(); /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1515af993..0560a38a1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -758,7 +758,13 @@ struct CPUPPCState { int error_code; int interrupt_request; uint32_t pending_interrupts; - void *irq[32]; +#if !defined(CONFIG_USER_ONLY) + /* This is the IRQ controller, which is implementation dependant + * and only relevant when emulating a complete machine. + */ + uint32_t irq_input_state; + void **irq_inputs; +#endif /* Those resources are used only during code translation */ /* Next instruction pointer */ @@ -801,6 +807,7 @@ int cpu_ppc_signal_handler(int host_signum, void *pinfo, void *puc); void do_interrupt (CPUPPCState *env); +void ppc_hw_interrupt (CPUPPCState *env); void cpu_loop_exit(void); void dump_stack (CPUPPCState *env); @@ -1303,16 +1310,35 @@ enum { /* Hardware interruption sources: * all those exception can be raised simulteaneously */ +/* Input pins definitions */ +enum { + /* 6xx bus input pins */ + PPC_INPUT_HRESET = 0, + PPC_INPUT_SRESET = 1, + PPC_INPUT_CKSTP_IN = 2, + PPC_INPUT_MCP = 3, + PPC_INPUT_SMI = 4, + PPC_INPUT_INT = 5, + /* Embedded PowerPC input pins */ + PPC_INPUT_CINT = 6, + PPC_INPUT_NB, +}; + +/* Hardware exceptions definitions */ enum { - PPC_INTERRUPT_RESET = 0, /* Reset / critical input */ - PPC_INTERRUPT_MCK = 1, /* Machine check exception */ - PPC_INTERRUPT_EXT = 2, /* External interrupt */ - PPC_INTERRUPT_DECR = 3, /* Decrementer exception */ - PPC_INTERRUPT_HDECR = 4, /* Hypervisor decrementer exception */ - PPC_INTERRUPT_PIT = 5, /* Programmable inteval timer interrupt */ - PPC_INTERRUPT_FIT = 6, /* Fixed interval timer interrupt */ - PPC_INTERRUPT_WDT = 7, /* Watchdog timer interrupt */ - PPC_INTERRUPT_DEBUG = 8, /* External debug exception */ + /* External hardware exception sources */ + PPC_INTERRUPT_RESET = 0, /* Reset exception */ + PPC_INTERRUPT_MCK = 1, /* Machine check exception */ + PPC_INTERRUPT_EXT = 2, /* External interrupt */ + PPC_INTERRUPT_SMI = 3, /* System management interrupt */ + PPC_INTERRUPT_CEXT = 4, /* Critical external interrupt */ + PPC_INTERRUPT_DEBUG = 5, /* External debug exception */ + /* Internal hardware exception sources */ + PPC_INTERRUPT_DECR = 6, /* Decrementer exception */ + PPC_INTERRUPT_HDECR = 7, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT = 8, /* Programmable inteval timer interrupt */ + PPC_INTERRUPT_FIT = 9, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT = 10, /* Watchdog timer interrupt */ }; /*****************************************************************************/ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 69ed260f7..b9a55b1f2 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1358,11 +1358,9 @@ void do_interrupt (CPUState *env) env->exception_index = -1; } -int ppc_hw_interrupt (CPUState *env) +void ppc_hw_interrupt (CPUState *env) { env->exception_index = -1; - - return 0; } #else /* defined (CONFIG_USER_ONLY) */ static void dump_syscall(CPUState *env) @@ -1927,7 +1925,7 @@ void do_interrupt (CPUState *env) env->exception_index = EXCP_NONE; } -int ppc_hw_interrupt (CPUState *env) +void ppc_hw_interrupt (CPUPPCState *env) { int raised = 0; @@ -1940,6 +1938,9 @@ int ppc_hw_interrupt (CPUState *env) /* Raise it */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { /* External reset / critical input */ + /* XXX: critical input should be handled another way. + * This code is not correct ! + */ env->exception_index = EXCP_RESET; env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); raised = 1; @@ -1984,7 +1985,12 @@ int ppc_hw_interrupt (CPUState *env) /* External interrupt */ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { env->exception_index = EXCP_EXTERNAL; + /* Taking an external interrupt does not clear the external + * interrupt status + */ +#if 0 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); +#endif raised = 1; } #if 0 // TODO @@ -1999,7 +2005,5 @@ int ppc_hw_interrupt (CPUState *env) env->error_code = 0; do_interrupt(env); } - - return raised; } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d5626316c..805c89724 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -35,6 +35,18 @@ struct ppc_def_t { uint64_t msr_mask; }; +/* For user-mode emulation, we don't emulate any IRQ controller */ +#if defined(CONFIG_USER_ONLY) +#define PPC_IRQ_INIT_FN(name) \ +static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \ +{ \ +} +#else +#define PPC_IRQ_INIT_FN(name) \ +void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); +#endif +PPC_IRQ_INIT_FN(6xx); + /* Generic callbacks: * do nothing but store/retrieve spr value */ @@ -1865,6 +1877,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_403GA: /* 403 GA family */ @@ -1879,6 +1892,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_405CR: /* 405 GP/CR family */ @@ -1895,6 +1909,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_NPE405H: /* NPe405 H family */ @@ -1909,6 +1924,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; #if defined (TODO) @@ -1940,6 +1956,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_440EP: /* 440 EP family */ @@ -1959,6 +1976,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; /* Embedded PowerPC from Freescale */ @@ -1994,6 +2012,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; #if defined (TODO) @@ -2038,6 +2057,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_ways = 2; env->id_tlbs = 0; env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ break; case CPU_PPC_602: /* PowerPC 602 */ @@ -2060,6 +2080,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_603: /* PowerPC 603 */ @@ -2087,6 +2109,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_G2: /* PowerPC G2 family */ @@ -2123,6 +2147,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_604: /* PowerPC 604 */ @@ -2146,6 +2172,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_74x: /* PowerPC 740 / 750 */ @@ -2178,6 +2206,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_750FX10: /* IBM PowerPC 750 FX */ @@ -2213,6 +2243,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; case CPU_PPC_755_10: /* PowerPC 755 */ @@ -2257,6 +2289,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); break; #if defined (TODO) @@ -2326,6 +2360,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) default: gen_spr_generic(env); + /* XXX: TODO: allocate internal IRQ controller */ break; } if (env->nb_BATs == -1) diff --git a/vl.h b/vl.h index 2f87946e8..b40ff3747 100644 --- a/vl.h +++ b/vl.h @@ -854,16 +854,17 @@ void i440fx_init_memory_mappings(PCIDevice *d); int piix4_init(PCIBus *bus, int devfn); /* openpic.c */ +/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ enum { - OPENPIC_EVT_INT = 0, /* IRQ */ - OPENPIC_EVT_CINT, /* critical IRQ */ - OPENPIC_EVT_MCK, /* Machine check event */ - OPENPIC_EVT_DEBUG, /* Inconditional debug event */ - OPENPIC_EVT_RESET, /* Core reset event */ + OPENPIC_OUTPUT_INT = 0, /* IRQ */ + OPENPIC_OUTPUT_CINT, /* critical IRQ */ + OPENPIC_OUTPUT_MCK, /* Machine check event */ + OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ + OPENPIC_OUTPUT_RESET, /* Core reset event */ + OPENPIC_OUTPUT_NB, }; -qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, - int *pmem_index, int nb_cpus, - struct CPUState **envp); +qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + qemu_irq **irqs, qemu_irq irq_out); /* heathrow_pic.c */ qemu_irq *heathrow_pic_init(int *pmem_index); @@ -1145,9 +1146,6 @@ extern QEMUMachine shix_machine; #ifdef TARGET_PPC /* PowerPC hardware exceptions management helpers */ -void cpu_ppc_irq_init_cpu(CPUState *env); -void ppc_openpic_irq (void *opaque, int n_IRQ, int level); -int ppc_hw_interrupt (CPUState *env); ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); #endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); -- cgit v1.2.3 From 534ce69ff05bee2448419f9cad796d6511bc1f9a Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Apr 2007 02:13:00 +0000 Subject: More Context/Xcontext fixes. Ifdef some 64bit-only ops, they may end up empty for 32bit mips, which dyngen trips over. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2648 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 14 +++++--------- target-mips/translate.c | 6 +++++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 026b08ab6..9818847fe 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1293,7 +1293,7 @@ void op_mtc0_entrylo1 (void) void op_mtc0_context (void) { - env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & ~0x007FFFFF); + env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (T0 & ~0x007FFFFF); RETURN(); } @@ -1458,12 +1458,6 @@ void op_mtc0_watchhi0 (void) RETURN(); } -void op_mtc0_xcontext (void) -{ - env->CP0_XContext = (int32_t)T0; /* XXX */ - RETURN(); -} - void op_mtc0_framemask (void) { env->CP0_Framemask = T0; /* XXX */ @@ -1528,6 +1522,7 @@ void op_mtc0_desave (void) RETURN(); } +#ifdef TARGET_MIPS64 void op_dmfc0_entrylo0 (void) { T0 = env->CP0_EntryLo0; @@ -1612,7 +1607,7 @@ void op_dmtc0_entrylo1 (void) void op_dmtc0_context (void) { - env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0); + env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (T0 & ~0x007FFFFF); RETURN(); } @@ -1632,7 +1627,7 @@ void op_dmtc0_watchlo0 (void) void op_dmtc0_xcontext (void) { - env->CP0_XContext = T0; /* XXX */ + env->CP0_XContext = (env->CP0_XContext & 0xffffffff) | (T0 & ~0xffffffff); RETURN(); } @@ -1647,6 +1642,7 @@ void op_dmtc0_errorepc (void) env->CP0_ErrorEPC = T0; RETURN(); } +#endif /* TARGET_MIPS64 */ #if 0 # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) diff --git a/target-mips/translate.c b/target-mips/translate.c index 0d9226a06..8aacbd02f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2750,7 +2750,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) switch (sel) { case 0: /* 64 bit MMU only */ - gen_op_mtc0_xcontext(); + /* Nothing writable in lower 32 bits */ rn = "XContext"; break; default: @@ -2946,6 +2946,7 @@ die: generate_exception(ctx, EXCP_RI); } +#ifdef TARGET_MIPS64 static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -4120,6 +4121,7 @@ die: #endif generate_exception(ctx, EXCP_RI); } +#endif /* TARGET_MIPS64 */ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) { @@ -4140,6 +4142,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) gen_mtc0(ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; break; +#ifdef TARGET_MIPS64 case OPC_DMFC0: if (rt == 0) { /* Treat as NOP */ @@ -4154,6 +4157,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) gen_dmtc0(ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; break; +#endif #if defined(MIPS_USES_R4K_TLB) case OPC_TLBWI: gen_op_tlbwi(); -- cgit v1.2.3 From 2423f6601a19fa0ac4eac360de9d3fe80a18d715 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Apr 2007 02:15:08 +0000 Subject: Code formatting fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2649 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 1873 ++++++++++++++++++++++++----------------------- 1 file changed, 938 insertions(+), 935 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 8aacbd02f..170160762 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1761,21 +1761,21 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 0: switch (sel) { case 0: - gen_op_mfc0_index(); + gen_op_mfc0_index(); rn = "Index"; break; case 1: -// gen_op_mfc0_mvpcontrol(); /* MT ASE */ +// gen_op_mfc0_mvpcontrol(); /* MT ASE */ rn = "MVPControl"; -// break; +// break; case 2: -// gen_op_mfc0_mvpconf0(); /* MT ASE */ +// gen_op_mfc0_mvpconf0(); /* MT ASE */ rn = "MVPConf0"; -// break; +// break; case 3: -// gen_op_mfc0_mvpconf1(); /* MT ASE */ +// gen_op_mfc0_mvpconf1(); /* MT ASE */ rn = "MVPConf1"; -// break; +// break; default: goto die; } @@ -1785,35 +1785,35 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 0: gen_op_mfc0_random(); rn = "Random"; - break; + break; case 1: -// gen_op_mfc0_vpecontrol(); /* MT ASE */ +// gen_op_mfc0_vpecontrol(); /* MT ASE */ rn = "VPEControl"; -// break; +// break; case 2: -// gen_op_mfc0_vpeconf0(); /* MT ASE */ +// gen_op_mfc0_vpeconf0(); /* MT ASE */ rn = "VPEConf0"; -// break; +// break; case 3: -// gen_op_mfc0_vpeconf1(); /* MT ASE */ +// gen_op_mfc0_vpeconf1(); /* MT ASE */ rn = "VPEConf1"; -// break; +// break; case 4: -// gen_op_mfc0_YQMask(); /* MT ASE */ +// gen_op_mfc0_YQMask(); /* MT ASE */ rn = "YQMask"; -// break; +// break; case 5: -// gen_op_mfc0_vpeschedule(); /* MT ASE */ +// gen_op_mfc0_vpeschedule(); /* MT ASE */ rn = "VPESchedule"; -// break; +// break; case 6: -// gen_op_mfc0_vpeschefback(); /* MT ASE */ +// gen_op_mfc0_vpeschefback(); /* MT ASE */ rn = "VPEScheFBack"; -// break; +// break; case 7: -// gen_op_mfc0_vpeopt(); /* MT ASE */ +// gen_op_mfc0_vpeopt(); /* MT ASE */ rn = "VPEOpt"; -// break; +// break; default: goto die; } @@ -1821,37 +1821,37 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 2: switch (sel) { case 0: - gen_op_mfc0_entrylo0(); - rn = "EntryLo0"; - break; + gen_op_mfc0_entrylo0(); + rn = "EntryLo0"; + break; case 1: -// gen_op_mfc0_tcstatus(); /* MT ASE */ - rn = "TCStatus"; -// break; +// gen_op_mfc0_tcstatus(); /* MT ASE */ + rn = "TCStatus"; +// break; case 2: -// gen_op_mfc0_tcbind(); /* MT ASE */ - rn = "TCBind"; -// break; +// gen_op_mfc0_tcbind(); /* MT ASE */ + rn = "TCBind"; +// break; case 3: -// gen_op_mfc0_tcrestart(); /* MT ASE */ - rn = "TCRestart"; -// break; +// gen_op_mfc0_tcrestart(); /* MT ASE */ + rn = "TCRestart"; +// break; case 4: -// gen_op_mfc0_tchalt(); /* MT ASE */ - rn = "TCHalt"; -// break; +// gen_op_mfc0_tchalt(); /* MT ASE */ + rn = "TCHalt"; +// break; case 5: -// gen_op_mfc0_tccontext(); /* MT ASE */ - rn = "TCContext"; -// break; +// gen_op_mfc0_tccontext(); /* MT ASE */ + rn = "TCContext"; +// break; case 6: -// gen_op_mfc0_tcschedule(); /* MT ASE */ - rn = "TCSchedule"; -// break; +// gen_op_mfc0_tcschedule(); /* MT ASE */ + rn = "TCSchedule"; +// break; case 7: -// gen_op_mfc0_tcschefback(); /* MT ASE */ - rn = "TCScheFBack"; -// break; +// gen_op_mfc0_tcschefback(); /* MT ASE */ + rn = "TCScheFBack"; +// break; default: goto die; } @@ -1859,9 +1859,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 3: switch (sel) { case 0: - gen_op_mfc0_entrylo1(); - rn = "EntryLo1"; - break; + gen_op_mfc0_entrylo1(); + rn = "EntryLo1"; + break; default: goto die; } @@ -1869,13 +1869,13 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 4: switch (sel) { case 0: - gen_op_mfc0_context(); - rn = "Context"; - break; + gen_op_mfc0_context(); + rn = "Context"; + break; case 1: -// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */ - rn = "ContextConfig"; -// break; +// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */ + rn = "ContextConfig"; +// break; default: goto die; } @@ -1883,13 +1883,13 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 5: switch (sel) { case 0: - gen_op_mfc0_pagemask(); - rn = "PageMask"; - break; + gen_op_mfc0_pagemask(); + rn = "PageMask"; + break; case 1: - gen_op_mfc0_pagegrain(); - rn = "PageGrain"; - break; + gen_op_mfc0_pagegrain(); + rn = "PageGrain"; + break; default: goto die; } @@ -1897,29 +1897,29 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 6: switch (sel) { case 0: - gen_op_mfc0_wired(); - rn = "Wired"; - break; + gen_op_mfc0_wired(); + rn = "Wired"; + break; case 1: -// gen_op_mfc0_srsconf0(); /* shadow registers */ - rn = "SRSConf0"; -// break; +// gen_op_mfc0_srsconf0(); /* shadow registers */ + rn = "SRSConf0"; +// break; case 2: -// gen_op_mfc0_srsconf1(); /* shadow registers */ - rn = "SRSConf1"; -// break; +// gen_op_mfc0_srsconf1(); /* shadow registers */ + rn = "SRSConf1"; +// break; case 3: -// gen_op_mfc0_srsconf2(); /* shadow registers */ - rn = "SRSConf2"; -// break; +// gen_op_mfc0_srsconf2(); /* shadow registers */ + rn = "SRSConf2"; +// break; case 4: -// gen_op_mfc0_srsconf3(); /* shadow registers */ - rn = "SRSConf3"; -// break; +// gen_op_mfc0_srsconf3(); /* shadow registers */ + rn = "SRSConf3"; +// break; case 5: -// gen_op_mfc0_srsconf4(); /* shadow registers */ - rn = "SRSConf4"; -// break; +// gen_op_mfc0_srsconf4(); /* shadow registers */ + rn = "SRSConf4"; +// break; default: goto die; } @@ -1927,9 +1927,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: - gen_op_mfc0_hwrena(); - rn = "HWREna"; - break; + gen_op_mfc0_hwrena(); + rn = "HWREna"; + break; default: goto die; } @@ -1937,9 +1937,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 8: switch (sel) { case 0: - gen_op_mfc0_badvaddr(); - rn = "BadVaddr"; - break; + gen_op_mfc0_badvaddr(); + rn = "BadVaddr"; + break; default: goto die; } @@ -1947,20 +1947,20 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 9: switch (sel) { case 0: - gen_op_mfc0_count(); - rn = "Count"; - break; - /* 6,7 are implementation dependent */ + gen_op_mfc0_count(); + rn = "Count"; + break; + /* 6,7 are implementation dependent */ default: goto die; - } + } break; case 10: switch (sel) { case 0: - gen_op_mfc0_entryhi(); - rn = "EntryHi"; - break; + gen_op_mfc0_entryhi(); + rn = "EntryHi"; + break; default: goto die; } @@ -1968,32 +1968,32 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 11: switch (sel) { case 0: - gen_op_mfc0_compare(); - rn = "Compare"; - break; - /* 6,7 are implementation dependent */ + gen_op_mfc0_compare(); + rn = "Compare"; + break; + /* 6,7 are implementation dependent */ default: goto die; - } + } break; case 12: switch (sel) { case 0: - gen_op_mfc0_status(); - rn = "Status"; - break; + gen_op_mfc0_status(); + rn = "Status"; + break; case 1: - gen_op_mfc0_intctl(); - rn = "IntCtl"; - break; + gen_op_mfc0_intctl(); + rn = "IntCtl"; + break; case 2: - gen_op_mfc0_srsctl(); - rn = "SRSCtl"; - break; + gen_op_mfc0_srsctl(); + rn = "SRSCtl"; + break; case 3: -// gen_op_mfc0_srsmap(); /* shadow registers */ - rn = "SRSMap"; -// break; +// gen_op_mfc0_srsmap(); /* shadow registers */ + rn = "SRSMap"; +// break; default: goto die; } @@ -2001,9 +2001,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 13: switch (sel) { case 0: - gen_op_mfc0_cause(); - rn = "Cause"; - break; + gen_op_mfc0_cause(); + rn = "Cause"; + break; default: goto die; } @@ -2011,9 +2011,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 14: switch (sel) { case 0: - gen_op_mfc0_epc(); - rn = "EPC"; - break; + gen_op_mfc0_epc(); + rn = "EPC"; + break; default: goto die; } @@ -2021,13 +2021,13 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 15: switch (sel) { case 0: - gen_op_mfc0_prid(); - rn = "PRid"; - break; + gen_op_mfc0_prid(); + rn = "PRid"; + break; case 1: - gen_op_mfc0_ebase(); - rn = "EBase"; - break; + gen_op_mfc0_ebase(); + rn = "EBase"; + break; default: goto die; } @@ -2067,9 +2067,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 17: switch (sel) { case 0: - gen_op_mfc0_lladdr(); - rn = "LLAddr"; - break; + gen_op_mfc0_lladdr(); + rn = "LLAddr"; + break; default: goto die; } @@ -2077,37 +2077,37 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 18: switch (sel) { case 0: - gen_op_mfc0_watchlo0(); - rn = "WatchLo"; - break; + gen_op_mfc0_watchlo0(); + rn = "WatchLo"; + break; case 1: -// gen_op_mfc0_watchlo1(); - rn = "WatchLo1"; -// break; +// gen_op_mfc0_watchlo1(); + rn = "WatchLo1"; +// break; case 2: -// gen_op_mfc0_watchlo2(); - rn = "WatchLo2"; -// break; +// gen_op_mfc0_watchlo2(); + rn = "WatchLo2"; +// break; case 3: -// gen_op_mfc0_watchlo3(); - rn = "WatchLo3"; -// break; +// gen_op_mfc0_watchlo3(); + rn = "WatchLo3"; +// break; case 4: -// gen_op_mfc0_watchlo4(); - rn = "WatchLo4"; -// break; +// gen_op_mfc0_watchlo4(); + rn = "WatchLo4"; +// break; case 5: -// gen_op_mfc0_watchlo5(); - rn = "WatchLo5"; -// break; +// gen_op_mfc0_watchlo5(); + rn = "WatchLo5"; +// break; case 6: -// gen_op_mfc0_watchlo6(); - rn = "WatchLo6"; -// break; +// gen_op_mfc0_watchlo6(); + rn = "WatchLo6"; +// break; case 7: -// gen_op_mfc0_watchlo7(); - rn = "WatchLo7"; -// break; +// gen_op_mfc0_watchlo7(); + rn = "WatchLo7"; +// break; default: goto die; } @@ -2115,37 +2115,37 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 19: switch (sel) { case 0: - gen_op_mfc0_watchhi0(); - rn = "WatchHi"; - break; + gen_op_mfc0_watchhi0(); + rn = "WatchHi"; + break; case 1: -// gen_op_mfc0_watchhi1(); - rn = "WatchHi1"; -// break; +// gen_op_mfc0_watchhi1(); + rn = "WatchHi1"; +// break; case 2: -// gen_op_mfc0_watchhi2(); - rn = "WatchHi2"; -// break; +// gen_op_mfc0_watchhi2(); + rn = "WatchHi2"; +// break; case 3: -// gen_op_mfc0_watchhi3(); - rn = "WatchHi3"; -// break; +// gen_op_mfc0_watchhi3(); + rn = "WatchHi3"; +// break; case 4: -// gen_op_mfc0_watchhi4(); - rn = "WatchHi4"; -// break; +// gen_op_mfc0_watchhi4(); + rn = "WatchHi4"; +// break; case 5: -// gen_op_mfc0_watchhi5(); - rn = "WatchHi5"; -// break; +// gen_op_mfc0_watchhi5(); + rn = "WatchHi5"; +// break; case 6: -// gen_op_mfc0_watchhi6(); - rn = "WatchHi6"; -// break; +// gen_op_mfc0_watchhi6(); + rn = "WatchHi6"; +// break; case 7: -// gen_op_mfc0_watchhi7(); - rn = "WatchHi7"; -// break; +// gen_op_mfc0_watchhi7(); + rn = "WatchHi7"; +// break; default: goto die; } @@ -2153,10 +2153,10 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: - /* 64 bit MMU only */ - gen_op_mfc0_xcontext(); - rn = "XContext"; - break; + /* 64 bit MMU only */ + gen_op_mfc0_xcontext(); + rn = "XContext"; + break; default: goto die; } @@ -2165,39 +2165,39 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mfc0_framemask(); - rn = "Framemask"; - break; + gen_op_mfc0_framemask(); + rn = "Framemask"; + break; default: goto die; } break; case 22: - /* ignored */ - rn = "'Diagnostic"; /* implementation dependent */ - break; + /* ignored */ + rn = "'Diagnostic"; /* implementation dependent */ + break; case 23: switch (sel) { case 0: - gen_op_mfc0_debug(); /* EJTAG support */ - rn = "Debug"; - break; + gen_op_mfc0_debug(); /* EJTAG support */ + rn = "Debug"; + break; case 1: -// gen_op_mfc0_tracecontrol(); /* PDtrace support */ - rn = "TraceControl"; -// break; +// gen_op_mfc0_tracecontrol(); /* PDtrace support */ + rn = "TraceControl"; +// break; case 2: -// gen_op_mfc0_tracecontrol2(); /* PDtrace support */ - rn = "TraceControl2"; -// break; +// gen_op_mfc0_tracecontrol2(); /* PDtrace support */ + rn = "TraceControl2"; +// break; case 3: -// gen_op_mfc0_usertracedata(); /* PDtrace support */ - rn = "UserTraceData"; -// break; +// gen_op_mfc0_usertracedata(); /* PDtrace support */ + rn = "UserTraceData"; +// break; case 4: -// gen_op_mfc0_debug(); /* PDtrace support */ - rn = "TraceBPC"; -// break; +// gen_op_mfc0_debug(); /* PDtrace support */ + rn = "TraceBPC"; +// break; default: goto die; } @@ -2205,9 +2205,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 24: switch (sel) { case 0: - gen_op_mfc0_depc(); /* EJTAG support */ - rn = "DEPC"; - break; + gen_op_mfc0_depc(); /* EJTAG support */ + rn = "DEPC"; + break; default: goto die; } @@ -2215,37 +2215,37 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 25: switch (sel) { case 0: - gen_op_mfc0_performance0(); - rn = "Performance0"; + gen_op_mfc0_performance0(); + rn = "Performance0"; break; case 1: -// gen_op_mfc0_performance1(); - rn = "Performance1"; -// break; +// gen_op_mfc0_performance1(); + rn = "Performance1"; +// break; case 2: -// gen_op_mfc0_performance2(); - rn = "Performance2"; -// break; +// gen_op_mfc0_performance2(); + rn = "Performance2"; +// break; case 3: -// gen_op_mfc0_performance3(); - rn = "Performance3"; -// break; +// gen_op_mfc0_performance3(); + rn = "Performance3"; +// break; case 4: -// gen_op_mfc0_performance4(); - rn = "Performance4"; -// break; +// gen_op_mfc0_performance4(); + rn = "Performance4"; +// break; case 5: -// gen_op_mfc0_performance5(); - rn = "Performance5"; -// break; +// gen_op_mfc0_performance5(); + rn = "Performance5"; +// break; case 6: -// gen_op_mfc0_performance6(); - rn = "Performance6"; -// break; +// gen_op_mfc0_performance6(); + rn = "Performance6"; +// break; case 7: -// gen_op_mfc0_performance7(); - rn = "Performance7"; -// break; +// gen_op_mfc0_performance7(); + rn = "Performance7"; +// break; default: goto die; } @@ -2257,8 +2257,8 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) switch (sel) { /* ignored */ case 0 ... 3: - rn = "CacheErr"; - break; + rn = "CacheErr"; + break; default: goto die; } @@ -2306,9 +2306,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 30: switch (sel) { case 0: - gen_op_mfc0_errorepc(); - rn = "ErrorEPC"; - break; + gen_op_mfc0_errorepc(); + rn = "ErrorEPC"; + break; default: goto die; } @@ -2316,9 +2316,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 31: switch (sel) { case 0: - gen_op_mfc0_desave(); /* EJTAG support */ - rn = "DESAVE"; - break; + gen_op_mfc0_desave(); /* EJTAG support */ + rn = "DESAVE"; + break; default: goto die; } @@ -2356,17 +2356,17 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mtc0_mvpcontrol(); /* MT ASE */ +// gen_op_mtc0_mvpcontrol(); /* MT ASE */ rn = "MVPControl"; -// break; +// break; case 2: -// gen_op_mtc0_mvpconf0(); /* MT ASE */ +// gen_op_mtc0_mvpconf0(); /* MT ASE */ rn = "MVPConf0"; -// break; +// break; case 3: -// gen_op_mtc0_mvpconf1(); /* MT ASE */ +// gen_op_mtc0_mvpconf1(); /* MT ASE */ rn = "MVPConf1"; -// break; +// break; default: goto die; } @@ -2374,37 +2374,37 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 1: switch (sel) { case 0: - /* ignored */ + /* ignored */ rn = "Random"; - break; + break; case 1: -// gen_op_mtc0_vpecontrol(); /* MT ASE */ +// gen_op_mtc0_vpecontrol(); /* MT ASE */ rn = "VPEControl"; -// break; +// break; case 2: -// gen_op_mtc0_vpeconf0(); /* MT ASE */ +// gen_op_mtc0_vpeconf0(); /* MT ASE */ rn = "VPEConf0"; -// break; +// break; case 3: -// gen_op_mtc0_vpeconf1(); /* MT ASE */ +// gen_op_mtc0_vpeconf1(); /* MT ASE */ rn = "VPEConf1"; -// break; +// break; case 4: -// gen_op_mtc0_YQMask(); /* MT ASE */ +// gen_op_mtc0_YQMask(); /* MT ASE */ rn = "YQMask"; -// break; +// break; case 5: -// gen_op_mtc0_vpeschedule(); /* MT ASE */ +// gen_op_mtc0_vpeschedule(); /* MT ASE */ rn = "VPESchedule"; -// break; +// break; case 6: -// gen_op_mtc0_vpeschefback(); /* MT ASE */ +// gen_op_mtc0_vpeschefback(); /* MT ASE */ rn = "VPEScheFBack"; -// break; +// break; case 7: -// gen_op_mtc0_vpeopt(); /* MT ASE */ +// gen_op_mtc0_vpeopt(); /* MT ASE */ rn = "VPEOpt"; -// break; +// break; default: goto die; } @@ -2412,37 +2412,37 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 2: switch (sel) { case 0: - gen_op_mtc0_entrylo0(); - rn = "EntryLo0"; - break; + gen_op_mtc0_entrylo0(); + rn = "EntryLo0"; + break; case 1: -// gen_op_mtc0_tcstatus(); /* MT ASE */ - rn = "TCStatus"; -// break; +// gen_op_mtc0_tcstatus(); /* MT ASE */ + rn = "TCStatus"; +// break; case 2: -// gen_op_mtc0_tcbind(); /* MT ASE */ - rn = "TCBind"; -// break; +// gen_op_mtc0_tcbind(); /* MT ASE */ + rn = "TCBind"; +// break; case 3: -// gen_op_mtc0_tcrestart(); /* MT ASE */ - rn = "TCRestart"; -// break; +// gen_op_mtc0_tcrestart(); /* MT ASE */ + rn = "TCRestart"; +// break; case 4: -// gen_op_mtc0_tchalt(); /* MT ASE */ - rn = "TCHalt"; -// break; +// gen_op_mtc0_tchalt(); /* MT ASE */ + rn = "TCHalt"; +// break; case 5: -// gen_op_mtc0_tccontext(); /* MT ASE */ - rn = "TCContext"; -// break; +// gen_op_mtc0_tccontext(); /* MT ASE */ + rn = "TCContext"; +// break; case 6: -// gen_op_mtc0_tcschedule(); /* MT ASE */ - rn = "TCSchedule"; -// break; +// gen_op_mtc0_tcschedule(); /* MT ASE */ + rn = "TCSchedule"; +// break; case 7: -// gen_op_mtc0_tcschefback(); /* MT ASE */ - rn = "TCScheFBack"; -// break; +// gen_op_mtc0_tcschefback(); /* MT ASE */ + rn = "TCScheFBack"; +// break; default: goto die; } @@ -2450,9 +2450,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 3: switch (sel) { case 0: - gen_op_mtc0_entrylo1(); - rn = "EntryLo1"; - break; + gen_op_mtc0_entrylo1(); + rn = "EntryLo1"; + break; default: goto die; } @@ -2460,13 +2460,13 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 4: switch (sel) { case 0: - gen_op_mtc0_context(); - rn = "Context"; - break; + gen_op_mtc0_context(); + rn = "Context"; + break; case 1: -// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */ - rn = "ContextConfig"; -// break; +// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */ + rn = "ContextConfig"; +// break; default: goto die; } @@ -2474,13 +2474,13 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 5: switch (sel) { case 0: - gen_op_mtc0_pagemask(); - rn = "PageMask"; - break; + gen_op_mtc0_pagemask(); + rn = "PageMask"; + break; case 1: - gen_op_mtc0_pagegrain(); - rn = "PageGrain"; - break; + gen_op_mtc0_pagegrain(); + rn = "PageGrain"; + break; default: goto die; } @@ -2488,29 +2488,29 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 6: switch (sel) { case 0: - gen_op_mtc0_wired(); - rn = "Wired"; - break; + gen_op_mtc0_wired(); + rn = "Wired"; + break; case 1: -// gen_op_mtc0_srsconf0(); /* shadow registers */ - rn = "SRSConf0"; -// break; +// gen_op_mtc0_srsconf0(); /* shadow registers */ + rn = "SRSConf0"; +// break; case 2: -// gen_op_mtc0_srsconf1(); /* shadow registers */ - rn = "SRSConf1"; -// break; +// gen_op_mtc0_srsconf1(); /* shadow registers */ + rn = "SRSConf1"; +// break; case 3: -// gen_op_mtc0_srsconf2(); /* shadow registers */ - rn = "SRSConf2"; -// break; +// gen_op_mtc0_srsconf2(); /* shadow registers */ + rn = "SRSConf2"; +// break; case 4: -// gen_op_mtc0_srsconf3(); /* shadow registers */ - rn = "SRSConf3"; -// break; +// gen_op_mtc0_srsconf3(); /* shadow registers */ + rn = "SRSConf3"; +// break; case 5: -// gen_op_mtc0_srsconf4(); /* shadow registers */ - rn = "SRSConf4"; -// break; +// gen_op_mtc0_srsconf4(); /* shadow registers */ + rn = "SRSConf4"; +// break; default: goto die; } @@ -2518,9 +2518,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: - gen_op_mtc0_hwrena(); - rn = "HWREna"; - break; + gen_op_mtc0_hwrena(); + rn = "HWREna"; + break; default: goto die; } @@ -2532,9 +2532,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 9: switch (sel) { case 0: - gen_op_mtc0_count(); - rn = "Count"; - break; + gen_op_mtc0_count(); + rn = "Count"; + break; /* 6,7 are implementation dependent */ default: goto die; @@ -2545,9 +2545,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 10: switch (sel) { case 0: - gen_op_mtc0_entryhi(); - rn = "EntryHi"; - break; + gen_op_mtc0_entryhi(); + rn = "EntryHi"; + break; default: goto die; } @@ -2555,10 +2555,10 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 11: switch (sel) { case 0: - gen_op_mtc0_compare(); - rn = "Compare"; - break; - /* 6,7 are implementation dependent */ + gen_op_mtc0_compare(); + rn = "Compare"; + break; + /* 6,7 are implementation dependent */ default: goto die; } @@ -2568,21 +2568,21 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 12: switch (sel) { case 0: - gen_op_mtc0_status(); - rn = "Status"; - break; + gen_op_mtc0_status(); + rn = "Status"; + break; case 1: - gen_op_mtc0_intctl(); - rn = "IntCtl"; - break; + gen_op_mtc0_intctl(); + rn = "IntCtl"; + break; case 2: - gen_op_mtc0_srsctl(); - rn = "SRSCtl"; - break; + gen_op_mtc0_srsctl(); + rn = "SRSCtl"; + break; case 3: -// gen_op_mtc0_srsmap(); /* shadow registers */ - rn = "SRSMap"; -// break; +// gen_op_mtc0_srsmap(); /* shadow registers */ + rn = "SRSMap"; +// break; default: goto die; } @@ -2592,9 +2592,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 13: switch (sel) { case 0: - gen_op_mtc0_cause(); - rn = "Cause"; - break; + gen_op_mtc0_cause(); + rn = "Cause"; + break; default: goto die; } @@ -2604,9 +2604,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 14: switch (sel) { case 0: - gen_op_mtc0_epc(); - rn = "EPC"; - break; + gen_op_mtc0_epc(); + rn = "EPC"; + break; default: goto die; } @@ -2614,13 +2614,13 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 15: switch (sel) { case 0: - /* ignored */ - rn = "PRid"; - break; + /* ignored */ + rn = "PRid"; + break; case 1: - gen_op_mtc0_ebase(); - rn = "EBase"; - break; + gen_op_mtc0_ebase(); + rn = "EBase"; + break; default: goto die; } @@ -2630,6 +2630,8 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 0: gen_op_mtc0_config0(); rn = "Config"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 1: /* ignored, read only */ @@ -2638,6 +2640,8 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 2: gen_op_mtc0_config2(); rn = "Config2"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 3: /* ignored, read only */ @@ -2657,15 +2661,13 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) rn = "Invalid config selector"; goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 17: switch (sel) { case 0: - /* ignored */ - rn = "LLAddr"; - break; + /* ignored */ + rn = "LLAddr"; + break; default: goto die; } @@ -2673,37 +2675,37 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 18: switch (sel) { case 0: - gen_op_mtc0_watchlo0(); - rn = "WatchLo"; - break; + gen_op_mtc0_watchlo0(); + rn = "WatchLo"; + break; case 1: -// gen_op_mtc0_watchlo1(); - rn = "WatchLo1"; -// break; +// gen_op_mtc0_watchlo1(); + rn = "WatchLo1"; +// break; case 2: -// gen_op_mtc0_watchlo2(); - rn = "WatchLo2"; -// break; +// gen_op_mtc0_watchlo2(); + rn = "WatchLo2"; +// break; case 3: -// gen_op_mtc0_watchlo3(); - rn = "WatchLo3"; -// break; +// gen_op_mtc0_watchlo3(); + rn = "WatchLo3"; +// break; case 4: -// gen_op_mtc0_watchlo4(); - rn = "WatchLo4"; -// break; +// gen_op_mtc0_watchlo4(); + rn = "WatchLo4"; +// break; case 5: -// gen_op_mtc0_watchlo5(); - rn = "WatchLo5"; -// break; +// gen_op_mtc0_watchlo5(); + rn = "WatchLo5"; +// break; case 6: -// gen_op_mtc0_watchlo6(); - rn = "WatchLo6"; -// break; +// gen_op_mtc0_watchlo6(); + rn = "WatchLo6"; +// break; case 7: -// gen_op_mtc0_watchlo7(); - rn = "WatchLo7"; -// break; +// gen_op_mtc0_watchlo7(); + rn = "WatchLo7"; +// break; default: goto die; } @@ -2711,37 +2713,37 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 19: switch (sel) { case 0: - gen_op_mtc0_watchhi0(); - rn = "WatchHi"; - break; + gen_op_mtc0_watchhi0(); + rn = "WatchHi"; + break; case 1: -// gen_op_mtc0_watchhi1(); - rn = "WatchHi1"; -// break; +// gen_op_mtc0_watchhi1(); + rn = "WatchHi1"; +// break; case 2: -// gen_op_mtc0_watchhi2(); - rn = "WatchHi2"; -// break; +// gen_op_mtc0_watchhi2(); + rn = "WatchHi2"; +// break; case 3: -// gen_op_mtc0_watchhi3(); - rn = "WatchHi3"; -// break; +// gen_op_mtc0_watchhi3(); + rn = "WatchHi3"; +// break; case 4: -// gen_op_mtc0_watchhi4(); - rn = "WatchHi4"; -// break; +// gen_op_mtc0_watchhi4(); + rn = "WatchHi4"; +// break; case 5: -// gen_op_mtc0_watchhi5(); - rn = "WatchHi5"; -// break; +// gen_op_mtc0_watchhi5(); + rn = "WatchHi5"; +// break; case 6: -// gen_op_mtc0_watchhi6(); - rn = "WatchHi6"; -// break; +// gen_op_mtc0_watchhi6(); + rn = "WatchHi6"; +// break; case 7: -// gen_op_mtc0_watchhi7(); - rn = "WatchHi7"; -// break; +// gen_op_mtc0_watchhi7(); + rn = "WatchHi7"; +// break; default: goto die; } @@ -2749,10 +2751,10 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: - /* 64 bit MMU only */ - /* Nothing writable in lower 32 bits */ - rn = "XContext"; - break; + /* 64 bit MMU only */ + /* Nothing writable in lower 32 bits */ + rn = "XContext"; + break; default: goto die; } @@ -2761,9 +2763,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mtc0_framemask(); - rn = "Framemask"; - break; + gen_op_mtc0_framemask(); + rn = "Framemask"; + break; default: goto die; } @@ -2771,41 +2773,41 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 22: /* ignored */ rn = "Diagnostic"; /* implementation dependent */ - break; + break; case 23: switch (sel) { case 0: - gen_op_mtc0_debug(); /* EJTAG support */ - rn = "Debug"; - break; + gen_op_mtc0_debug(); /* EJTAG support */ + rn = "Debug"; + break; case 1: -// gen_op_mtc0_tracecontrol(); /* PDtrace support */ - rn = "TraceControl"; -// break; +// gen_op_mtc0_tracecontrol(); /* PDtrace support */ + rn = "TraceControl"; +// break; case 2: -// gen_op_mtc0_tracecontrol2(); /* PDtrace support */ - rn = "TraceControl2"; -// break; +// gen_op_mtc0_tracecontrol2(); /* PDtrace support */ + rn = "TraceControl2"; +// break; case 3: -// gen_op_mtc0_usertracedata(); /* PDtrace support */ - rn = "UserTraceData"; -// break; +// gen_op_mtc0_usertracedata(); /* PDtrace support */ + rn = "UserTraceData"; +// break; case 4: -// gen_op_mtc0_debug(); /* PDtrace support */ - rn = "TraceBPC"; -// break; +// gen_op_mtc0_debug(); /* PDtrace support */ + rn = "TraceBPC"; +// break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 24: switch (sel) { case 0: - gen_op_mtc0_depc(); /* EJTAG support */ - rn = "DEPC"; - break; + gen_op_mtc0_depc(); /* EJTAG support */ + rn = "DEPC"; + break; default: goto die; } @@ -2813,51 +2815,51 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 25: switch (sel) { case 0: - gen_op_mtc0_performance0(); - rn = "Performance0"; - break; + gen_op_mtc0_performance0(); + rn = "Performance0"; + break; case 1: -// gen_op_mtc0_performance1(); - rn = "Performance1"; -// break; +// gen_op_mtc0_performance1(); + rn = "Performance1"; +// break; case 2: -// gen_op_mtc0_performance2(); - rn = "Performance2"; -// break; +// gen_op_mtc0_performance2(); + rn = "Performance2"; +// break; case 3: -// gen_op_mtc0_performance3(); - rn = "Performance3"; -// break; +// gen_op_mtc0_performance3(); + rn = "Performance3"; +// break; case 4: -// gen_op_mtc0_performance4(); - rn = "Performance4"; -// break; +// gen_op_mtc0_performance4(); + rn = "Performance4"; +// break; case 5: -// gen_op_mtc0_performance5(); - rn = "Performance5"; -// break; +// gen_op_mtc0_performance5(); + rn = "Performance5"; +// break; case 6: -// gen_op_mtc0_performance6(); - rn = "Performance6"; -// break; +// gen_op_mtc0_performance6(); + rn = "Performance6"; +// break; case 7: -// gen_op_mtc0_performance7(); - rn = "Performance7"; -// break; +// gen_op_mtc0_performance7(); + rn = "Performance7"; +// break; default: goto die; } break; case 26: - /* ignored */ + /* ignored */ rn = "ECC"; - break; + break; case 27: switch (sel) { case 0 ... 3: - /* ignored */ - rn = "CacheErr"; - break; + /* ignored */ + rn = "CacheErr"; + break; default: goto die; } @@ -2875,7 +2877,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 3: case 5: case 7: - gen_op_mtc0_datalo(); + gen_op_mtc0_datalo(); rn = "DataLo"; break; default: @@ -2895,7 +2897,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 3: case 5: case 7: - gen_op_mtc0_datahi(); + gen_op_mtc0_datahi(); rn = "DataHi"; break; default: @@ -2906,9 +2908,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 30: switch (sel) { case 0: - gen_op_mtc0_errorepc(); - rn = "ErrorEPC"; - break; + gen_op_mtc0_errorepc(); + rn = "ErrorEPC"; + break; default: goto die; } @@ -2916,14 +2918,14 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 31: switch (sel) { case 0: - gen_op_mtc0_desave(); /* EJTAG support */ - rn = "DESAVE"; - break; + gen_op_mtc0_desave(); /* EJTAG support */ + rn = "DESAVE"; + break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; default: goto die; @@ -2955,21 +2957,21 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 0: switch (sel) { case 0: - gen_op_mfc0_index(); + gen_op_mfc0_index(); rn = "Index"; break; case 1: -// gen_op_dmfc0_mvpcontrol(); /* MT ASE */ +// gen_op_dmfc0_mvpcontrol(); /* MT ASE */ rn = "MVPControl"; -// break; +// break; case 2: -// gen_op_dmfc0_mvpconf0(); /* MT ASE */ +// gen_op_dmfc0_mvpconf0(); /* MT ASE */ rn = "MVPConf0"; -// break; +// break; case 3: -// gen_op_dmfc0_mvpconf1(); /* MT ASE */ +// gen_op_dmfc0_mvpconf1(); /* MT ASE */ rn = "MVPConf1"; -// break; +// break; default: goto die; } @@ -2979,35 +2981,35 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 0: gen_op_mfc0_random(); rn = "Random"; - break; + break; case 1: -// gen_op_dmfc0_vpecontrol(); /* MT ASE */ +// gen_op_dmfc0_vpecontrol(); /* MT ASE */ rn = "VPEControl"; -// break; +// break; case 2: -// gen_op_dmfc0_vpeconf0(); /* MT ASE */ +// gen_op_dmfc0_vpeconf0(); /* MT ASE */ rn = "VPEConf0"; -// break; +// break; case 3: -// gen_op_dmfc0_vpeconf1(); /* MT ASE */ +// gen_op_dmfc0_vpeconf1(); /* MT ASE */ rn = "VPEConf1"; -// break; +// break; case 4: -// gen_op_dmfc0_YQMask(); /* MT ASE */ +// gen_op_dmfc0_YQMask(); /* MT ASE */ rn = "YQMask"; -// break; +// break; case 5: -// gen_op_dmfc0_vpeschedule(); /* MT ASE */ +// gen_op_dmfc0_vpeschedule(); /* MT ASE */ rn = "VPESchedule"; -// break; +// break; case 6: -// gen_op_dmfc0_vpeschefback(); /* MT ASE */ +// gen_op_dmfc0_vpeschefback(); /* MT ASE */ rn = "VPEScheFBack"; -// break; +// break; case 7: -// gen_op_dmfc0_vpeopt(); /* MT ASE */ +// gen_op_dmfc0_vpeopt(); /* MT ASE */ rn = "VPEOpt"; -// break; +// break; default: goto die; } @@ -3015,37 +3017,37 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 2: switch (sel) { case 0: - gen_op_dmfc0_entrylo0(); - rn = "EntryLo0"; - break; + gen_op_dmfc0_entrylo0(); + rn = "EntryLo0"; + break; case 1: -// gen_op_dmfc0_tcstatus(); /* MT ASE */ - rn = "TCStatus"; -// break; +// gen_op_dmfc0_tcstatus(); /* MT ASE */ + rn = "TCStatus"; +// break; case 2: -// gen_op_dmfc0_tcbind(); /* MT ASE */ - rn = "TCBind"; -// break; +// gen_op_dmfc0_tcbind(); /* MT ASE */ + rn = "TCBind"; +// break; case 3: -// gen_op_dmfc0_tcrestart(); /* MT ASE */ - rn = "TCRestart"; -// break; +// gen_op_dmfc0_tcrestart(); /* MT ASE */ + rn = "TCRestart"; +// break; case 4: -// gen_op_dmfc0_tchalt(); /* MT ASE */ - rn = "TCHalt"; -// break; +// gen_op_dmfc0_tchalt(); /* MT ASE */ + rn = "TCHalt"; +// break; case 5: -// gen_op_dmfc0_tccontext(); /* MT ASE */ - rn = "TCContext"; -// break; +// gen_op_dmfc0_tccontext(); /* MT ASE */ + rn = "TCContext"; +// break; case 6: -// gen_op_dmfc0_tcschedule(); /* MT ASE */ - rn = "TCSchedule"; -// break; +// gen_op_dmfc0_tcschedule(); /* MT ASE */ + rn = "TCSchedule"; +// break; case 7: -// gen_op_dmfc0_tcschefback(); /* MT ASE */ - rn = "TCScheFBack"; -// break; +// gen_op_dmfc0_tcschefback(); /* MT ASE */ + rn = "TCScheFBack"; +// break; default: goto die; } @@ -3053,9 +3055,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 3: switch (sel) { case 0: - gen_op_dmfc0_entrylo1(); - rn = "EntryLo1"; - break; + gen_op_dmfc0_entrylo1(); + rn = "EntryLo1"; + break; default: goto die; } @@ -3063,13 +3065,13 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 4: switch (sel) { case 0: - gen_op_dmfc0_context(); - rn = "Context"; - break; + gen_op_dmfc0_context(); + rn = "Context"; + break; case 1: -// gen_op_dmfc0_contextconfig(); /* SmartMIPS ASE */ - rn = "ContextConfig"; -// break; +// gen_op_dmfc0_contextconfig(); /* SmartMIPS ASE */ + rn = "ContextConfig"; +// break; default: goto die; } @@ -3077,13 +3079,13 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 5: switch (sel) { case 0: - gen_op_mfc0_pagemask(); - rn = "PageMask"; - break; + gen_op_mfc0_pagemask(); + rn = "PageMask"; + break; case 1: - gen_op_mfc0_pagegrain(); - rn = "PageGrain"; - break; + gen_op_mfc0_pagegrain(); + rn = "PageGrain"; + break; default: goto die; } @@ -3091,29 +3093,29 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 6: switch (sel) { case 0: - gen_op_mfc0_wired(); - rn = "Wired"; - break; + gen_op_mfc0_wired(); + rn = "Wired"; + break; case 1: -// gen_op_dmfc0_srsconf0(); /* shadow registers */ - rn = "SRSConf0"; -// break; +// gen_op_dmfc0_srsconf0(); /* shadow registers */ + rn = "SRSConf0"; +// break; case 2: -// gen_op_dmfc0_srsconf1(); /* shadow registers */ - rn = "SRSConf1"; -// break; +// gen_op_dmfc0_srsconf1(); /* shadow registers */ + rn = "SRSConf1"; +// break; case 3: -// gen_op_dmfc0_srsconf2(); /* shadow registers */ - rn = "SRSConf2"; -// break; +// gen_op_dmfc0_srsconf2(); /* shadow registers */ + rn = "SRSConf2"; +// break; case 4: -// gen_op_dmfc0_srsconf3(); /* shadow registers */ - rn = "SRSConf3"; -// break; +// gen_op_dmfc0_srsconf3(); /* shadow registers */ + rn = "SRSConf3"; +// break; case 5: -// gen_op_dmfc0_srsconf4(); /* shadow registers */ - rn = "SRSConf4"; -// break; +// gen_op_dmfc0_srsconf4(); /* shadow registers */ + rn = "SRSConf4"; +// break; default: goto die; } @@ -3121,9 +3123,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: - gen_op_mfc0_hwrena(); - rn = "HWREna"; - break; + gen_op_mfc0_hwrena(); + rn = "HWREna"; + break; default: goto die; } @@ -3131,9 +3133,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 8: switch (sel) { case 0: - gen_op_dmfc0_badvaddr(); - rn = "BadVaddr"; - break; + gen_op_dmfc0_badvaddr(); + rn = "BadVaddr"; + break; default: goto die; } @@ -3141,10 +3143,10 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 9: switch (sel) { case 0: - gen_op_mfc0_count(); - rn = "Count"; - break; - /* 6,7 are implementation dependent */ + gen_op_mfc0_count(); + rn = "Count"; + break; + /* 6,7 are implementation dependent */ default: goto die; } @@ -3152,9 +3154,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 10: switch (sel) { case 0: - gen_op_dmfc0_entryhi(); - rn = "EntryHi"; - break; + gen_op_dmfc0_entryhi(); + rn = "EntryHi"; + break; default: goto die; } @@ -3162,9 +3164,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 11: switch (sel) { case 0: - gen_op_mfc0_compare(); - rn = "Compare"; - break; + gen_op_mfc0_compare(); + rn = "Compare"; + break; /* 6,7 are implementation dependent */ default: goto die; @@ -3173,21 +3175,21 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 12: switch (sel) { case 0: - gen_op_mfc0_status(); - rn = "Status"; - break; + gen_op_mfc0_status(); + rn = "Status"; + break; case 1: - gen_op_mfc0_intctl(); - rn = "IntCtl"; - break; + gen_op_mfc0_intctl(); + rn = "IntCtl"; + break; case 2: - gen_op_mfc0_srsctl(); - rn = "SRSCtl"; - break; + gen_op_mfc0_srsctl(); + rn = "SRSCtl"; + break; case 3: - gen_op_mfc0_srsmap(); /* shadow registers */ - rn = "SRSMap"; - break; + gen_op_mfc0_srsmap(); /* shadow registers */ + rn = "SRSMap"; + break; default: goto die; } @@ -3195,9 +3197,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 13: switch (sel) { case 0: - gen_op_mfc0_cause(); - rn = "Cause"; - break; + gen_op_mfc0_cause(); + rn = "Cause"; + break; default: goto die; } @@ -3205,9 +3207,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 14: switch (sel) { case 0: - gen_op_dmfc0_epc(); - rn = "EPC"; - break; + gen_op_dmfc0_epc(); + rn = "EPC"; + break; default: goto die; } @@ -3215,13 +3217,13 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 15: switch (sel) { case 0: - gen_op_mfc0_prid(); - rn = "PRid"; - break; + gen_op_mfc0_prid(); + rn = "PRid"; + break; case 1: - gen_op_mfc0_ebase(); - rn = "EBase"; - break; + gen_op_mfc0_ebase(); + rn = "EBase"; + break; default: goto die; } @@ -3229,19 +3231,19 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 16: switch (sel) { case 0: - gen_op_mfc0_config0(); + gen_op_mfc0_config0(); rn = "Config"; break; case 1: - gen_op_mfc0_config1(); + gen_op_mfc0_config1(); rn = "Config1"; break; case 2: - gen_op_mfc0_config2(); + gen_op_mfc0_config2(); rn = "Config2"; break; case 3: - gen_op_mfc0_config3(); + gen_op_mfc0_config3(); rn = "Config3"; break; /* 6,7 are implementation dependent */ @@ -3252,9 +3254,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 17: switch (sel) { case 0: - gen_op_dmfc0_lladdr(); - rn = "LLAddr"; - break; + gen_op_dmfc0_lladdr(); + rn = "LLAddr"; + break; default: goto die; } @@ -3262,37 +3264,37 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 18: switch (sel) { case 0: - gen_op_dmfc0_watchlo0(); - rn = "WatchLo"; - break; + gen_op_dmfc0_watchlo0(); + rn = "WatchLo"; + break; case 1: -// gen_op_dmfc0_watchlo1(); - rn = "WatchLo1"; -// break; +// gen_op_dmfc0_watchlo1(); + rn = "WatchLo1"; +// break; case 2: -// gen_op_dmfc0_watchlo2(); - rn = "WatchLo2"; -// break; +// gen_op_dmfc0_watchlo2(); + rn = "WatchLo2"; +// break; case 3: -// gen_op_dmfc0_watchlo3(); - rn = "WatchLo3"; -// break; +// gen_op_dmfc0_watchlo3(); + rn = "WatchLo3"; +// break; case 4: -// gen_op_dmfc0_watchlo4(); - rn = "WatchLo4"; -// break; +// gen_op_dmfc0_watchlo4(); + rn = "WatchLo4"; +// break; case 5: -// gen_op_dmfc0_watchlo5(); - rn = "WatchLo5"; -// break; +// gen_op_dmfc0_watchlo5(); + rn = "WatchLo5"; +// break; case 6: -// gen_op_dmfc0_watchlo6(); - rn = "WatchLo6"; -// break; +// gen_op_dmfc0_watchlo6(); + rn = "WatchLo6"; +// break; case 7: -// gen_op_dmfc0_watchlo7(); - rn = "WatchLo7"; -// break; +// gen_op_dmfc0_watchlo7(); + rn = "WatchLo7"; +// break; default: goto die; } @@ -3300,37 +3302,37 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 19: switch (sel) { case 0: - gen_op_mfc0_watchhi0(); - rn = "WatchHi"; - break; + gen_op_mfc0_watchhi0(); + rn = "WatchHi"; + break; case 1: -// gen_op_mfc0_watchhi1(); - rn = "WatchHi1"; -// break; +// gen_op_mfc0_watchhi1(); + rn = "WatchHi1"; +// break; case 2: -// gen_op_mfc0_watchhi2(); - rn = "WatchHi2"; -// break; +// gen_op_mfc0_watchhi2(); + rn = "WatchHi2"; +// break; case 3: -// gen_op_mfc0_watchhi3(); - rn = "WatchHi3"; -// break; +// gen_op_mfc0_watchhi3(); + rn = "WatchHi3"; +// break; case 4: -// gen_op_mfc0_watchhi4(); - rn = "WatchHi4"; -// break; +// gen_op_mfc0_watchhi4(); + rn = "WatchHi4"; +// break; case 5: -// gen_op_mfc0_watchhi5(); - rn = "WatchHi5"; -// break; +// gen_op_mfc0_watchhi5(); + rn = "WatchHi5"; +// break; case 6: -// gen_op_mfc0_watchhi6(); - rn = "WatchHi6"; -// break; +// gen_op_mfc0_watchhi6(); + rn = "WatchHi6"; +// break; case 7: -// gen_op_mfc0_watchhi7(); - rn = "WatchHi7"; -// break; +// gen_op_mfc0_watchhi7(); + rn = "WatchHi7"; +// break; default: goto die; } @@ -3338,10 +3340,10 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: - /* 64 bit MMU only */ - gen_op_dmfc0_xcontext(); - rn = "XContext"; - break; + /* 64 bit MMU only */ + gen_op_dmfc0_xcontext(); + rn = "XContext"; + break; default: goto die; } @@ -3350,39 +3352,39 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mfc0_framemask(); - rn = "Framemask"; - break; + gen_op_mfc0_framemask(); + rn = "Framemask"; + break; default: goto die; } break; case 22: - /* ignored */ - rn = "'Diagnostic"; /* implementation dependent */ - break; + /* ignored */ + rn = "'Diagnostic"; /* implementation dependent */ + break; case 23: switch (sel) { case 0: - gen_op_mfc0_debug(); /* EJTAG support */ - rn = "Debug"; - break; + gen_op_mfc0_debug(); /* EJTAG support */ + rn = "Debug"; + break; case 1: -// gen_op_dmfc0_tracecontrol(); /* PDtrace support */ - rn = "TraceControl"; -// break; +// gen_op_dmfc0_tracecontrol(); /* PDtrace support */ + rn = "TraceControl"; +// break; case 2: -// gen_op_dmfc0_tracecontrol2(); /* PDtrace support */ - rn = "TraceControl2"; -// break; +// gen_op_dmfc0_tracecontrol2(); /* PDtrace support */ + rn = "TraceControl2"; +// break; case 3: -// gen_op_dmfc0_usertracedata(); /* PDtrace support */ - rn = "UserTraceData"; -// break; +// gen_op_dmfc0_usertracedata(); /* PDtrace support */ + rn = "UserTraceData"; +// break; case 4: -// gen_op_dmfc0_debug(); /* PDtrace support */ - rn = "TraceBPC"; -// break; +// gen_op_dmfc0_debug(); /* PDtrace support */ + rn = "TraceBPC"; +// break; default: goto die; } @@ -3390,9 +3392,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 24: switch (sel) { case 0: - gen_op_dmfc0_depc(); /* EJTAG support */ - rn = "DEPC"; - break; + gen_op_dmfc0_depc(); /* EJTAG support */ + rn = "DEPC"; + break; default: goto die; } @@ -3400,37 +3402,37 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 25: switch (sel) { case 0: - gen_op_mfc0_performance0(); - rn = "Performance0"; + gen_op_mfc0_performance0(); + rn = "Performance0"; break; case 1: -// gen_op_dmfc0_performance1(); - rn = "Performance1"; -// break; +// gen_op_dmfc0_performance1(); + rn = "Performance1"; +// break; case 2: -// gen_op_dmfc0_performance2(); - rn = "Performance2"; -// break; +// gen_op_dmfc0_performance2(); + rn = "Performance2"; +// break; case 3: -// gen_op_dmfc0_performance3(); - rn = "Performance3"; -// break; +// gen_op_dmfc0_performance3(); + rn = "Performance3"; +// break; case 4: -// gen_op_dmfc0_performance4(); - rn = "Performance4"; -// break; +// gen_op_dmfc0_performance4(); + rn = "Performance4"; +// break; case 5: -// gen_op_dmfc0_performance5(); - rn = "Performance5"; -// break; +// gen_op_dmfc0_performance5(); + rn = "Performance5"; +// break; case 6: -// gen_op_dmfc0_performance6(); - rn = "Performance6"; -// break; +// gen_op_dmfc0_performance6(); + rn = "Performance6"; +// break; case 7: -// gen_op_dmfc0_performance7(); - rn = "Performance7"; -// break; +// gen_op_dmfc0_performance7(); + rn = "Performance7"; +// break; default: goto die; } @@ -3442,8 +3444,8 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) switch (sel) { /* ignored */ case 0 ... 3: - rn = "CacheErr"; - break; + rn = "CacheErr"; + break; default: goto die; } @@ -3491,9 +3493,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 30: switch (sel) { case 0: - gen_op_dmfc0_errorepc(); - rn = "ErrorEPC"; - break; + gen_op_dmfc0_errorepc(); + rn = "ErrorEPC"; + break; default: goto die; } @@ -3501,9 +3503,9 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 31: switch (sel) { case 0: - gen_op_mfc0_desave(); /* EJTAG support */ - rn = "DESAVE"; - break; + gen_op_mfc0_desave(); /* EJTAG support */ + rn = "DESAVE"; + break; default: goto die; } @@ -3541,17 +3543,17 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_dmtc0_mvpcontrol(); /* MT ASE */ +// gen_op_dmtc0_mvpcontrol(); /* MT ASE */ rn = "MVPControl"; -// break; +// break; case 2: -// gen_op_dmtc0_mvpconf0(); /* MT ASE */ +// gen_op_dmtc0_mvpconf0(); /* MT ASE */ rn = "MVPConf0"; -// break; +// break; case 3: -// gen_op_dmtc0_mvpconf1(); /* MT ASE */ +// gen_op_dmtc0_mvpconf1(); /* MT ASE */ rn = "MVPConf1"; -// break; +// break; default: goto die; } @@ -3559,37 +3561,37 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 1: switch (sel) { case 0: - /* ignored */ + /* ignored */ rn = "Random"; - break; + break; case 1: -// gen_op_dmtc0_vpecontrol(); /* MT ASE */ +// gen_op_dmtc0_vpecontrol(); /* MT ASE */ rn = "VPEControl"; -// break; +// break; case 2: -// gen_op_dmtc0_vpeconf0(); /* MT ASE */ +// gen_op_dmtc0_vpeconf0(); /* MT ASE */ rn = "VPEConf0"; -// break; +// break; case 3: -// gen_op_dmtc0_vpeconf1(); /* MT ASE */ +// gen_op_dmtc0_vpeconf1(); /* MT ASE */ rn = "VPEConf1"; -// break; +// break; case 4: -// gen_op_dmtc0_YQMask(); /* MT ASE */ +// gen_op_dmtc0_YQMask(); /* MT ASE */ rn = "YQMask"; -// break; +// break; case 5: -// gen_op_dmtc0_vpeschedule(); /* MT ASE */ +// gen_op_dmtc0_vpeschedule(); /* MT ASE */ rn = "VPESchedule"; -// break; +// break; case 6: -// gen_op_dmtc0_vpeschefback(); /* MT ASE */ +// gen_op_dmtc0_vpeschefback(); /* MT ASE */ rn = "VPEScheFBack"; -// break; +// break; case 7: -// gen_op_dmtc0_vpeopt(); /* MT ASE */ +// gen_op_dmtc0_vpeopt(); /* MT ASE */ rn = "VPEOpt"; -// break; +// break; default: goto die; } @@ -3597,37 +3599,37 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 2: switch (sel) { case 0: - gen_op_dmtc0_entrylo0(); - rn = "EntryLo0"; - break; + gen_op_dmtc0_entrylo0(); + rn = "EntryLo0"; + break; case 1: -// gen_op_dmtc0_tcstatus(); /* MT ASE */ - rn = "TCStatus"; -// break; +// gen_op_dmtc0_tcstatus(); /* MT ASE */ + rn = "TCStatus"; +// break; case 2: -// gen_op_dmtc0_tcbind(); /* MT ASE */ - rn = "TCBind"; -// break; +// gen_op_dmtc0_tcbind(); /* MT ASE */ + rn = "TCBind"; +// break; case 3: -// gen_op_dmtc0_tcrestart(); /* MT ASE */ - rn = "TCRestart"; -// break; +// gen_op_dmtc0_tcrestart(); /* MT ASE */ + rn = "TCRestart"; +// break; case 4: -// gen_op_dmtc0_tchalt(); /* MT ASE */ - rn = "TCHalt"; -// break; +// gen_op_dmtc0_tchalt(); /* MT ASE */ + rn = "TCHalt"; +// break; case 5: -// gen_op_dmtc0_tccontext(); /* MT ASE */ - rn = "TCContext"; -// break; +// gen_op_dmtc0_tccontext(); /* MT ASE */ + rn = "TCContext"; +// break; case 6: -// gen_op_dmtc0_tcschedule(); /* MT ASE */ - rn = "TCSchedule"; -// break; +// gen_op_dmtc0_tcschedule(); /* MT ASE */ + rn = "TCSchedule"; +// break; case 7: -// gen_op_dmtc0_tcschefback(); /* MT ASE */ - rn = "TCScheFBack"; -// break; +// gen_op_dmtc0_tcschefback(); /* MT ASE */ + rn = "TCScheFBack"; +// break; default: goto die; } @@ -3635,9 +3637,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 3: switch (sel) { case 0: - gen_op_dmtc0_entrylo1(); - rn = "EntryLo1"; - break; + gen_op_dmtc0_entrylo1(); + rn = "EntryLo1"; + break; default: goto die; } @@ -3645,13 +3647,13 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 4: switch (sel) { case 0: - gen_op_dmtc0_context(); - rn = "Context"; - break; + gen_op_dmtc0_context(); + rn = "Context"; + break; case 1: -// gen_op_dmtc0_contextconfig(); /* SmartMIPS ASE */ - rn = "ContextConfig"; -// break; +// gen_op_dmtc0_contextconfig(); /* SmartMIPS ASE */ + rn = "ContextConfig"; +// break; default: goto die; } @@ -3659,13 +3661,13 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 5: switch (sel) { case 0: - gen_op_mtc0_pagemask(); - rn = "PageMask"; - break; + gen_op_mtc0_pagemask(); + rn = "PageMask"; + break; case 1: - gen_op_mtc0_pagegrain(); - rn = "PageGrain"; - break; + gen_op_mtc0_pagegrain(); + rn = "PageGrain"; + break; default: goto die; } @@ -3673,29 +3675,29 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 6: switch (sel) { case 0: - gen_op_mtc0_wired(); - rn = "Wired"; - break; + gen_op_mtc0_wired(); + rn = "Wired"; + break; case 1: -// gen_op_dmtc0_srsconf0(); /* shadow registers */ - rn = "SRSConf0"; -// break; +// gen_op_dmtc0_srsconf0(); /* shadow registers */ + rn = "SRSConf0"; +// break; case 2: -// gen_op_dmtc0_srsconf1(); /* shadow registers */ - rn = "SRSConf1"; -// break; +// gen_op_dmtc0_srsconf1(); /* shadow registers */ + rn = "SRSConf1"; +// break; case 3: -// gen_op_dmtc0_srsconf2(); /* shadow registers */ - rn = "SRSConf2"; -// break; +// gen_op_dmtc0_srsconf2(); /* shadow registers */ + rn = "SRSConf2"; +// break; case 4: -// gen_op_dmtc0_srsconf3(); /* shadow registers */ - rn = "SRSConf3"; -// break; +// gen_op_dmtc0_srsconf3(); /* shadow registers */ + rn = "SRSConf3"; +// break; case 5: -// gen_op_dmtc0_srsconf4(); /* shadow registers */ - rn = "SRSConf4"; -// break; +// gen_op_dmtc0_srsconf4(); /* shadow registers */ + rn = "SRSConf4"; +// break; default: goto die; } @@ -3703,9 +3705,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: - gen_op_mtc0_hwrena(); - rn = "HWREna"; - break; + gen_op_mtc0_hwrena(); + rn = "HWREna"; + break; default: goto die; } @@ -3717,9 +3719,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 9: switch (sel) { case 0: - gen_op_mtc0_count(); - rn = "Count"; - break; + gen_op_mtc0_count(); + rn = "Count"; + break; /* 6,7 are implementation dependent */ default: goto die; @@ -3730,9 +3732,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 10: switch (sel) { case 0: - gen_op_mtc0_entryhi(); - rn = "EntryHi"; - break; + gen_op_mtc0_entryhi(); + rn = "EntryHi"; + break; default: goto die; } @@ -3740,9 +3742,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 11: switch (sel) { case 0: - gen_op_mtc0_compare(); - rn = "Compare"; - break; + gen_op_mtc0_compare(); + rn = "Compare"; + break; /* 6,7 are implementation dependent */ default: goto die; @@ -3753,22 +3755,22 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 12: switch (sel) { case 0: - gen_op_mtc0_status(); - rn = "Status"; - break; + gen_op_mtc0_status(); + rn = "Status"; + break; case 1: - gen_op_mtc0_intctl(); - rn = "IntCtl"; - break; + gen_op_mtc0_intctl(); + rn = "IntCtl"; + break; case 2: - gen_op_mtc0_srsctl(); - rn = "SRSCtl"; - break; + gen_op_mtc0_srsctl(); + rn = "SRSCtl"; + break; case 3: - gen_op_mtc0_srsmap(); /* shadow registers */ - rn = "SRSMap"; - break; - default: + gen_op_mtc0_srsmap(); /* shadow registers */ + rn = "SRSMap"; + break; + default: goto die; } /* Stop translation as we may have switched the execution mode */ @@ -3777,9 +3779,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 13: switch (sel) { case 0: - gen_op_mtc0_cause(); - rn = "Cause"; - break; + gen_op_mtc0_cause(); + rn = "Cause"; + break; default: goto die; } @@ -3789,9 +3791,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 14: switch (sel) { case 0: - gen_op_dmtc0_epc(); - rn = "EPC"; - break; + gen_op_dmtc0_epc(); + rn = "EPC"; + break; default: goto die; } @@ -3799,13 +3801,13 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 15: switch (sel) { case 0: - /* ignored */ - rn = "PRid"; - break; + /* ignored */ + rn = "PRid"; + break; case 1: - gen_op_mtc0_ebase(); - rn = "EBase"; - break; + gen_op_mtc0_ebase(); + rn = "EBase"; + break; default: goto die; } @@ -3815,17 +3817,21 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 0: gen_op_mtc0_config0(); rn = "Config"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 1: - /* ignored */ + /* ignored */ rn = "Config1"; break; case 2: gen_op_mtc0_config2(); rn = "Config2"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 3: - /* ignored */ + /* ignored */ rn = "Config3"; break; /* 6,7 are implementation dependent */ @@ -3833,15 +3839,13 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "Invalid config selector"; goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 17: switch (sel) { case 0: - /* ignored */ - rn = "LLAddr"; - break; + /* ignored */ + rn = "LLAddr"; + break; default: goto die; } @@ -3849,37 +3853,37 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 18: switch (sel) { case 0: - gen_op_dmtc0_watchlo0(); - rn = "WatchLo"; - break; + gen_op_dmtc0_watchlo0(); + rn = "WatchLo"; + break; case 1: -// gen_op_dmtc0_watchlo1(); - rn = "WatchLo1"; -// break; +// gen_op_dmtc0_watchlo1(); + rn = "WatchLo1"; +// break; case 2: -// gen_op_dmtc0_watchlo2(); - rn = "WatchLo2"; -// break; +// gen_op_dmtc0_watchlo2(); + rn = "WatchLo2"; +// break; case 3: -// gen_op_dmtc0_watchlo3(); - rn = "WatchLo3"; -// break; +// gen_op_dmtc0_watchlo3(); + rn = "WatchLo3"; +// break; case 4: -// gen_op_dmtc0_watchlo4(); - rn = "WatchLo4"; -// break; +// gen_op_dmtc0_watchlo4(); + rn = "WatchLo4"; +// break; case 5: -// gen_op_dmtc0_watchlo5(); - rn = "WatchLo5"; -// break; +// gen_op_dmtc0_watchlo5(); + rn = "WatchLo5"; +// break; case 6: -// gen_op_dmtc0_watchlo6(); - rn = "WatchLo6"; -// break; +// gen_op_dmtc0_watchlo6(); + rn = "WatchLo6"; +// break; case 7: -// gen_op_dmtc0_watchlo7(); - rn = "WatchLo7"; -// break; +// gen_op_dmtc0_watchlo7(); + rn = "WatchLo7"; +// break; default: goto die; } @@ -3887,37 +3891,37 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 19: switch (sel) { case 0: - gen_op_mtc0_watchhi0(); - rn = "WatchHi"; - break; + gen_op_mtc0_watchhi0(); + rn = "WatchHi"; + break; case 1: -// gen_op_dmtc0_watchhi1(); - rn = "WatchHi1"; -// break; +// gen_op_dmtc0_watchhi1(); + rn = "WatchHi1"; +// break; case 2: -// gen_op_dmtc0_watchhi2(); - rn = "WatchHi2"; -// break; +// gen_op_dmtc0_watchhi2(); + rn = "WatchHi2"; +// break; case 3: -// gen_op_dmtc0_watchhi3(); - rn = "WatchHi3"; -// break; +// gen_op_dmtc0_watchhi3(); + rn = "WatchHi3"; +// break; case 4: -// gen_op_dmtc0_watchhi4(); - rn = "WatchHi4"; -// break; +// gen_op_dmtc0_watchhi4(); + rn = "WatchHi4"; +// break; case 5: -// gen_op_dmtc0_watchhi5(); - rn = "WatchHi5"; -// break; +// gen_op_dmtc0_watchhi5(); + rn = "WatchHi5"; +// break; case 6: -// gen_op_dmtc0_watchhi6(); - rn = "WatchHi6"; -// break; +// gen_op_dmtc0_watchhi6(); + rn = "WatchHi6"; +// break; case 7: -// gen_op_dmtc0_watchhi7(); - rn = "WatchHi7"; -// break; +// gen_op_dmtc0_watchhi7(); + rn = "WatchHi7"; +// break; default: goto die; } @@ -3925,10 +3929,10 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: - /* 64 bit MMU only */ - gen_op_dmtc0_xcontext(); - rn = "XContext"; - break; + /* 64 bit MMU only */ + gen_op_dmtc0_xcontext(); + rn = "XContext"; + break; default: goto die; } @@ -3937,9 +3941,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) /* Officially reserved, but sel 0 is used for R1x000 framemask */ switch (sel) { case 0: - gen_op_mtc0_framemask(); - rn = "Framemask"; - break; + gen_op_mtc0_framemask(); + rn = "Framemask"; + break; default: goto die; } @@ -3951,37 +3955,37 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 23: switch (sel) { case 0: - gen_op_mtc0_debug(); /* EJTAG support */ - rn = "Debug"; - break; + gen_op_mtc0_debug(); /* EJTAG support */ + rn = "Debug"; + break; case 1: -// gen_op_dmtc0_tracecontrol(); /* PDtrace support */ - rn = "TraceControl"; -// break; +// gen_op_dmtc0_tracecontrol(); /* PDtrace support */ + rn = "TraceControl"; +// break; case 2: -// gen_op_dmtc0_tracecontrol2(); /* PDtrace support */ - rn = "TraceControl2"; -// break; +// gen_op_dmtc0_tracecontrol2(); /* PDtrace support */ + rn = "TraceControl2"; +// break; case 3: -// gen_op_dmtc0_usertracedata(); /* PDtrace support */ - rn = "UserTraceData"; -// break; +// gen_op_dmtc0_usertracedata(); /* PDtrace support */ + rn = "UserTraceData"; +// break; case 4: -// gen_op_dmtc0_debug(); /* PDtrace support */ - rn = "TraceBPC"; -// break; +// gen_op_dmtc0_debug(); /* PDtrace support */ + rn = "TraceBPC"; +// break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 24: switch (sel) { case 0: - gen_op_dmtc0_depc(); /* EJTAG support */ - rn = "DEPC"; - break; + gen_op_dmtc0_depc(); /* EJTAG support */ + rn = "DEPC"; + break; default: goto die; } @@ -3989,37 +3993,37 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 25: switch (sel) { case 0: - gen_op_mtc0_performance0(); - rn = "Performance0"; - break; + gen_op_mtc0_performance0(); + rn = "Performance0"; + break; case 1: -// gen_op_dmtc0_performance1(); - rn = "Performance1"; -// break; +// gen_op_dmtc0_performance1(); + rn = "Performance1"; +// break; case 2: -// gen_op_dmtc0_performance2(); - rn = "Performance2"; -// break; +// gen_op_dmtc0_performance2(); + rn = "Performance2"; +// break; case 3: -// gen_op_dmtc0_performance3(); - rn = "Performance3"; -// break; +// gen_op_dmtc0_performance3(); + rn = "Performance3"; +// break; case 4: -// gen_op_dmtc0_performance4(); - rn = "Performance4"; -// break; +// gen_op_dmtc0_performance4(); + rn = "Performance4"; +// break; case 5: -// gen_op_dmtc0_performance5(); - rn = "Performance5"; -// break; +// gen_op_dmtc0_performance5(); + rn = "Performance5"; +// break; case 6: -// gen_op_dmtc0_performance6(); - rn = "Performance6"; -// break; +// gen_op_dmtc0_performance6(); + rn = "Performance6"; +// break; case 7: -// gen_op_dmtc0_performance7(); - rn = "Performance7"; -// break; +// gen_op_dmtc0_performance7(); + rn = "Performance7"; +// break; default: goto die; } @@ -4031,9 +4035,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 27: switch (sel) { case 0 ... 3: - /* ignored */ - rn = "CacheErr"; - break; + /* ignored */ + rn = "CacheErr"; + break; default: goto die; } @@ -4051,7 +4055,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 3: case 5: case 7: - gen_op_mtc0_datalo(); + gen_op_mtc0_datalo(); rn = "DataLo"; break; default: @@ -4071,7 +4075,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 3: case 5: case 7: - gen_op_mtc0_datahi(); + gen_op_mtc0_datahi(); rn = "DataHi"; break; default: @@ -4082,9 +4086,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 30: switch (sel) { case 0: - gen_op_dmtc0_errorepc(); - rn = "ErrorEPC"; - break; + gen_op_dmtc0_errorepc(); + rn = "ErrorEPC"; + break; default: goto die; } @@ -4092,9 +4096,9 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 31: switch (sel) { case 0: - gen_op_mtc0_desave(); /* EJTAG support */ - rn = "DESAVE"; - break; + gen_op_mtc0_desave(); /* EJTAG support */ + rn = "DESAVE"; + break; default: goto die; } @@ -4716,7 +4720,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case OPC_SYSCALL: generate_exception(ctx, EXCP_SYSCALL); - ctx->bstate = BS_EXCP; break; case OPC_BREAK: generate_exception(ctx, EXCP_BREAK); -- cgit v1.2.3 From b48cfdffd9f15432355c8e4ed9d2781eab9e4358 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Apr 2007 02:24:14 +0000 Subject: Throw RI for invalid MFMC0-class instructions. Introduce optional MIPS_STRICT_STANDARD define to adhere more to the spec than it makes sense in normal operation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2650 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/mips-defs.h | 5 +++++ target-mips/translate.c | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 8b29e8b2d..14043be27 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -19,4 +19,9 @@ #define TARGET_LONG_BITS 32 #endif +/* Strictly follow the architecture standard: Disallow "special" + instruction handling for PMON/SPIM, force cycle-dependent + Count/Compare maintenance. */ +//#define MIPS_STRICT_STANDARD 1 + #endif /* !defined (__QEMU_MIPS_DEFS_H__) */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 170160762..96ae2cd67 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -305,7 +305,7 @@ enum { }; /* MFMC0 opcodes */ -#define MASK_MFMC0(op) MASK_CP0(op) | (op & ((0x0C << 11) | (1 << 5))) +#define MASK_MFMC0(op) MASK_CP0(op) | (op & 0xFFFF) enum { OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0, @@ -4715,8 +4715,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_MTLO: /* Move to HI/LO */ gen_HILO(ctx, op1, rs); break; - case OPC_PMON: /* Pmon entry point */ + case OPC_PMON: /* Pmon entry point, also R4010 selsl */ +#ifdef MIPS_STRICT_STANDARD + MIPS_INVAL("PMON / selsl"); + generate_exception(ctx, EXCP_RI); +#else gen_op_pmon(sa); +#endif break; case OPC_SYSCALL: generate_exception(ctx, EXCP_SYSCALL); @@ -4724,10 +4729,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_BREAK: generate_exception(ctx, EXCP_BREAK); break; - case OPC_SPIM: /* SPIM ? */ + case OPC_SPIM: +#ifdef MIPS_STRICT_STANDARD + MIPS_INVAL("SPIM"); + generate_exception(ctx, EXCP_RI); +#else /* Implemented as RI exception for now. */ MIPS_INVAL("spim (unofficial)"); generate_exception(ctx, EXCP_RI); +#endif break; case OPC_SYNC: /* Treat as a noop. */ -- cgit v1.2.3 From 2f6445458e5e9eec54c9f47071bbc6ac70c54c02 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Apr 2007 20:34:23 +0000 Subject: Make SYNCI_Step and CCRes CPU-specific. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2651 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 3 --- target-mips/translate_init.c | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 96ae2cd67..75221c9c8 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5435,9 +5435,6 @@ void cpu_reset (CPUMIPSState *env) env->hflags |= MIPS_HFLAG_UM; env->user_mode_only = 1; #endif - /* XXX some guesswork here, values are CPU specific */ - env->SYNCI_Step = 16; - env->CCRes = 2; } #include "translate_init.c" diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 456a6cd83..f2966ea89 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -67,6 +67,8 @@ struct mips_def_t { int32_t CP0_Config3; int32_t CP0_Config6; int32_t CP0_Config7; + int32_t SYNCI_Step; + int32_t CCRes; int32_t CP1_fcr0; }; @@ -82,6 +84,8 @@ static mips_def_t mips_defs[] = .CP0_Config1 = MIPS_CONFIG1, .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, .CP1_fcr0 = MIPS_FCR0, }, { @@ -91,6 +95,8 @@ static mips_def_t mips_defs[] = .CP0_Config1 = MIPS_CONFIG1, .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, .CP1_fcr0 = MIPS_FCR0, }, { @@ -100,6 +106,8 @@ static mips_def_t mips_defs[] = .CP0_Config1 = MIPS_CONFIG1, .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, .CP1_fcr0 = MIPS_FCR0, }, { @@ -109,6 +117,8 @@ static mips_def_t mips_defs[] = .CP0_Config1 = MIPS_CONFIG1, .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, .CP1_fcr0 = MIPS_FCR0, }, { @@ -118,6 +128,8 @@ static mips_def_t mips_defs[] = .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, .CP1_fcr0 = MIPS_FCR0, }, #else @@ -128,6 +140,8 @@ static mips_def_t mips_defs[] = .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 16, + .CCRes = 2, .CP1_fcr0 = MIPS_FCR0, }, #endif @@ -175,6 +189,8 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_Config3 = def->CP0_Config3; env->CP0_Config6 = def->CP0_Config6; env->CP0_Config7 = def->CP0_Config7; + env->SYNCI_Step = def->SYNCI_Step; + env->CCRes = def->CCRes; env->fcr0 = def->CP1_fcr0; return 0; } -- cgit v1.2.3 From 83b1fb88f854fcd631dc411ab955d5bd3498fbd3 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Apr 2007 22:46:06 +0000 Subject: Fix bad variable name. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2652 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 79b2aa581..afca82601 100644 --- a/Makefile.target +++ b/Makefile.target @@ -428,7 +428,7 @@ ifeq ($(TARGET_BASE_ARCH), mips) VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) -DEFINES += -DHAS_AUDIO +CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -- cgit v1.2.3 From 2e719ba3476fcf1c7c74649d9e16f486eb8c02fc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 12 Apr 2007 21:11:03 +0000 Subject: Embedded PowerPC Device Control Registers infrastructure. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2653 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ target-ppc/cpu.h | 6 ++-- target-ppc/op_helper.c | 16 ++++++--- vl.h | 7 ++++ 4 files changed, 117 insertions(+), 7 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index f5c45001b..f502271bc 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -547,6 +547,101 @@ void ppc_emb_timers_init (CPUState *env) } } +/*****************************************************************************/ +/* Embedded PowerPC Device Control Registers */ +typedef struct ppc_dcrn_t ppc_dcrn_t; +struct ppc_dcrn_t { + dcr_read_cb dcr_read; + dcr_write_cb dcr_write; + void *opaque; +}; + +#define DCRN_NB 1024 +struct ppc_dcr_t { + ppc_dcrn_t dcrn[DCRN_NB]; + int (*read_error)(int dcrn); + int (*write_error)(int dcrn); +}; + +int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp) +{ + ppc_dcrn_t *dcr; + + if (dcrn < 0 || dcrn >= DCRN_NB) + goto error; + dcr = &dcr_env->dcrn[dcrn]; + if (dcr->dcr_read == NULL) + goto error; + *valp = (*dcr->dcr_read)(dcr->opaque, dcrn); + + return 0; + + error: + if (dcr_env->read_error != NULL) + return (*dcr_env->read_error)(dcrn); + + return -1; +} + +int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val) +{ + ppc_dcrn_t *dcr; + + if (dcrn < 0 || dcrn >= DCRN_NB) + goto error; + dcr = &dcr_env->dcrn[dcrn]; + if (dcr->dcr_write == NULL) + goto error; + (*dcr->dcr_write)(dcr->opaque, dcrn, val); + + return 0; + + error: + if (dcr_env->write_error != NULL) + return (*dcr_env->write_error)(dcrn); + + return -1; +} + +int ppc_dcr_register (CPUState *env, int dcrn, void *opaque, + dcr_read_cb dcr_read, dcr_write_cb dcr_write) +{ + ppc_dcr_t *dcr_env; + ppc_dcrn_t *dcr; + + dcr_env = env->dcr_env; + if (dcr_env == NULL) + return -1; + if (dcrn < 0 || dcrn >= DCRN_NB) + return -1; + dcr = &dcr_env->dcrn[dcrn]; + if (dcr->opaque != NULL || + dcr->dcr_read != NULL || + dcr->dcr_write != NULL) + return -1; + dcr->opaque = opaque; + dcr->dcr_read = dcr_read; + dcr->dcr_write = dcr_write; + + return 0; +} + +int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn), + int (*write_error)(int dcrn)) +{ + ppc_dcr_t *dcr_env; + + dcr_env = qemu_mallocz(sizeof(ppc_dcr_t)); + if (dcr_env == NULL) + return -1; + dcr_env->read_error = read_error; + dcr_env->write_error = write_error; + env->dcr_env = dcr_env; + + return 0; +} + + #if 0 /*****************************************************************************/ /* Handle system reset (for now, just stop emulation) */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 0560a38a1..2a2c4409d 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -730,8 +730,6 @@ struct CPUPPCState { /* Time base and decrementer */ ppc_tb_t *tb_env; /* Device control registers */ - int (*dcr_read)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong *val); - int (*dcr_write)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong val); ppc_dcr_t *dcr_env; /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */ @@ -863,6 +861,10 @@ void store_booke_tsr (CPUPPCState *env, target_ulong val); #endif #endif +/* Device control registers */ +int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp); +int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); + #define TARGET_PAGE_BITS 12 #include "cpu-all.h" diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index e1fff7f49..a65da36b7 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1249,20 +1249,26 @@ void do_load_dcr (void) { target_ulong val; - if (unlikely(env->dcr_read == NULL)) + if (unlikely(env->dcr_env == NULL)) { + printf("No DCR environment\n"); do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); - else if (unlikely((*env->dcr_read)(env->dcr_env, T0, &val) != 0)) + } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) { + printf("DCR read error\n"); do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); - else + } else { T0 = val; + } } void do_store_dcr (void) { - if (unlikely(env->dcr_write == NULL)) + if (unlikely(env->dcr_env == NULL)) { + printf("No DCR environment\n"); do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); - else if (unlikely((*env->dcr_write)(env->dcr_env, T0, T1) != 0)) + } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) { + printf("DCR write error\n"); do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); + } } void do_load_403_pb (int num) diff --git a/vl.h b/vl.h index b40ff3747..df76a9fbc 100644 --- a/vl.h +++ b/vl.h @@ -1147,6 +1147,13 @@ extern QEMUMachine shix_machine; #ifdef TARGET_PPC /* PowerPC hardware exceptions management helpers */ ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); +/* Embedded PowerPC DCR management */ +typedef target_ulong (*dcr_read_cb)(void *opaque, int dcrn); +typedef void (*dcr_write_cb)(void *opaque, int dcrn, target_ulong val); +int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn), + int (*dcr_write_error)(int dcrn)); +int ppc_dcr_register (CPUState *env, int dcrn, void *opaque, + dcr_read_cb drc_read, dcr_write_cb dcr_write); #endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); -- cgit v1.2.3 From 24be5ae3a075319a57477fd03b1bdfb74f7f4d05 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 12 Apr 2007 21:24:29 +0000 Subject: Add PowerPC 405 input pins (IRQ, resets, ...) model. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2654 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 102 ++++++++++++++++++++++++++++++++++++++++---- hw/ppc_chrp.c | 8 ++-- hw/ppc_prep.c | 2 +- target-ppc/cpu.h | 35 +++++++++++---- target-ppc/translate_init.c | 10 +++-- 5 files changed, 133 insertions(+), 24 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index f502271bc..8438bc6d1 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -56,23 +56,23 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) #endif cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ - if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0) || 0) { + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { switch (pin) { - case PPC_INPUT_INT: - /* Level sensitive - asserted high */ + case PPC6xx_INPUT_INT: + /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) printf("%s: set the external IRQ state to %d\n", __func__, level); #endif ppc_set_irq(env, PPC_INTERRUPT_EXT, level); break; - case PPC_INPUT_SMI: + case PPC6xx_INPUT_SMI: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) printf("%s: set the SMI IRQ state to %d\n", __func__, level); #endif ppc_set_irq(env, PPC_INTERRUPT_SMI, level); break; - case PPC_INPUT_MCP: + case PPC6xx_INPUT_MCP: /* Negative edge sensitive */ /* XXX: TODO: actual reaction may depends on HID0 status * 603/604/740/750: check HID0[EMCP] @@ -84,7 +84,7 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); } break; - case PPC_INPUT_CKSTP_IN: + case PPC6xx_INPUT_CKSTP_IN: /* Level sensitive - active low */ /* XXX: TODO: relay the signal to CKSTP_OUT pin */ if (level) { @@ -99,7 +99,7 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) env->halted = 0; } break; - case PPC_INPUT_HRESET: + case PPC6xx_INPUT_HRESET: /* Level sensitive - active low */ if (level) { #if 0 // XXX: TOFIX @@ -110,7 +110,7 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) #endif } break; - case PPC_INPUT_SRESET: + case PPC6xx_INPUT_SRESET: #if defined(PPC_DEBUG_IRQ) printf("%s: set the RESET IRQ state to %d\n", __func__, level); #endif @@ -135,6 +135,92 @@ void ppc6xx_irq_init (CPUState *env) env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6); } +/* PowerPC 405 internal IRQ controller */ +static void ppc405_set_irq (void *opaque, int pin, int level) +{ + CPUState *env = opaque; + int cur_level; + +#if defined(PPC_DEBUG_IRQ) + printf("%s: env %p pin %d level %d\n", __func__, env, pin, level); +#endif + cur_level = (env->irq_input_state >> pin) & 1; + /* Don't generate spurious events */ + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + switch (pin) { + case PPC405_INPUT_RESET_SYS: + /* XXX: TODO: reset all peripherals */ + /* No break here */ + case PPC405_INPUT_RESET_CHIP: + /* XXX: TODO: reset on-chip peripherals */ + /* No break here */ + case PPC405_INPUT_RESET_CORE: + /* XXX: TODO: update DBSR[MRR] */ + if (level) { +#if 0 // XXX: TOFIX +#if defined(PPC_DEBUG_IRQ) + printf("%s: reset the CPU\n", __func__); +#endif + cpu_reset(env); +#endif + } + break; + case PPC405_INPUT_CINT: + /* Level sensitive - active high */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the critical IRQ state to %d\n", __func__, level); +#endif + /* XXX: TOFIX */ + ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + break; + case PPC405_INPUT_INT: + /* Level sensitive - active high */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the external IRQ state to %d\n", __func__, level); +#endif + ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + break; + case PPC405_INPUT_HALT: + /* Level sensitive - active low */ + if (level) { +#if defined(PPC_DEBUG_IRQ) + printf("%s: stop the CPU\n", __func__); +#endif + env->halted = 1; + } else { +#if defined(PPC_DEBUG_IRQ) + printf("%s: restart the CPU\n", __func__); +#endif + env->halted = 0; + } + break; + case PPC405_INPUT_DEBUG: + /* Level sensitive - active high */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: set the external IRQ state to %d\n", __func__, level); +#endif + ppc_set_irq(env, EXCP_40x_DEBUG, level); + break; + default: + /* Unknown pin - do nothing */ +#if defined(PPC_DEBUG_IRQ) + printf("%s: unknown IRQ pin %d\n", __func__, pin); +#endif + return; + } + if (level) + env->irq_input_state |= 1 << pin; + else + env->irq_input_state &= ~(1 << pin); + } +} + +void ppc405_irq_init (CPUState *env) +{ + printf("%s\n", __func__); + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc405_set_irq, env, 7); +} + /*****************************************************************************/ /* PowerPC time base and decrementer emulation */ //#define DEBUG_TB diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index c418cd1b4..70571fd4e 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -470,14 +470,14 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, */ openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); openpic_irqs[i][OPENPIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT]; + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; openpic_irqs[i][OPENPIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT]; + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; openpic_irqs[i][OPENPIC_OUTPUT_MCK] = - ((qemu_irq *)env->irq_inputs)[PPC_INPUT_MCP]; + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP]; openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; /* Not connected ? */ openpic_irqs[i][OPENPIC_OUTPUT_RESET] = - ((qemu_irq *)env->irq_inputs)[PPC_INPUT_HRESET]; /* Check this */ + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET]; /* Check this */ } pic = openpic_init(NULL, &openpic_mem_index, smp_cpus, openpic_irqs, NULL); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 8b53ef30a..421d18920 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -598,7 +598,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, } isa_mem_base = 0xc0000000; - i8259 = i8259_init(first_cpu->irq_inputs[PPC_INPUT_INT]); + i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]); pci_bus = pci_prep_init(i8259); // pci_bus = i440fx_init(); /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 2a2c4409d..4b67f1a25 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1315,15 +1315,34 @@ enum { /* Input pins definitions */ enum { /* 6xx bus input pins */ - PPC_INPUT_HRESET = 0, - PPC_INPUT_SRESET = 1, - PPC_INPUT_CKSTP_IN = 2, - PPC_INPUT_MCP = 3, - PPC_INPUT_SMI = 4, - PPC_INPUT_INT = 5, + PPC6xx_INPUT_HRESET = 0, + PPC6xx_INPUT_SRESET = 1, + PPC6xx_INPUT_CKSTP_IN = 2, + PPC6xx_INPUT_MCP = 3, + PPC6xx_INPUT_SMI = 4, + PPC6xx_INPUT_INT = 5, +}; + +enum { /* Embedded PowerPC input pins */ - PPC_INPUT_CINT = 6, - PPC_INPUT_NB, + PPCBookE_INPUT_HRESET = 0, + PPCBookE_INPUT_SRESET = 1, + PPCBookE_INPUT_CKSTP_IN = 2, + PPCBookE_INPUT_MCP = 3, + PPCBookE_INPUT_SMI = 4, + PPCBookE_INPUT_INT = 5, + PPCBookE_INPUT_CINT = 6, +}; + +enum { + /* PowerPC 405 input pins */ + PPC405_INPUT_RESET_CORE = 0, + PPC405_INPUT_RESET_CHIP = 1, + PPC405_INPUT_RESET_SYS = 2, + PPC405_INPUT_CINT = 3, + PPC405_INPUT_INT = 4, + PPC405_INPUT_HALT = 5, + PPC405_INPUT_DEBUG = 6, }; /* Hardware exceptions definitions */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 805c89724..72e577dc2 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -45,6 +45,7 @@ static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \ #define PPC_IRQ_INIT_FN(name) \ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); #endif +PPC_IRQ_INIT_FN(405); PPC_IRQ_INIT_FN(6xx); /* Generic callbacks: @@ -1909,7 +1910,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc405_irq_init(env); break; case CPU_PPC_NPE405H: /* NPe405 H family */ @@ -1924,7 +1926,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc405_irq_init(env); break; #if defined (TODO) @@ -1956,7 +1959,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc405_irq_init(env); break; case CPU_PPC_440EP: /* 440 EP family */ -- cgit v1.2.3 From d2889a3efc3851e62de69cb9d88fb784c28e0ed8 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 13 Apr 2007 15:46:16 +0000 Subject: Alignment check mechanism (not fully enabled yet) (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2655 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 2 ++ target-sparc/op.c | 5 ++++- target-sparc/op_helper.c | 12 ++++++++++++ target-sparc/translate.c | 1 - 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 7233b8b14..50e162a27 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -35,6 +35,7 @@ #define TT_NFPU_INSN 0x04 #define TT_WIN_OVF 0x05 #define TT_WIN_UNF 0x06 +#define TT_UNALIGNED 0x07 #define TT_FP_EXCP 0x08 #define TT_DFAULT 0x09 #define TT_TOVF 0x0a @@ -55,6 +56,7 @@ #define TT_DFAULT 0x30 #define TT_DMISS 0x31 #define TT_DPROT 0x32 +#define TT_UNALIGNED 0x34 #define TT_PRIV_ACT 0x37 #define TT_EXTINT 0x40 #define TT_SPILL 0x80 diff --git a/target-sparc/op.c b/target-sparc/op.c index c9f068457..96c8b2db7 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1486,7 +1486,10 @@ void OPPROTO op_movl_npc_im(void) void OPPROTO op_movl_npc_T0(void) { - env->npc = T0; + if (T0 & 0x3) + raise_exception(TT_UNALIGNED); + else + env->npc = T0; } void OPPROTO op_mov_pc_npc(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 21612bd23..2edc8d741 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -923,7 +923,11 @@ void do_interrupt(int intno) #if !defined(CONFIG_USER_ONLY) +static void do_unaligned_access(target_ulong addr, int is_write, int is_user, + void *retaddr); + #define MMUSUFFIX _mmu +#define ALIGNED_ONLY #define GETPC() (__builtin_return_address(0)) #define SHIFT 0 @@ -938,6 +942,14 @@ void do_interrupt(int intno) #define SHIFT 3 #include "softmmu_template.h" +static void do_unaligned_access(target_ulong addr, int is_write, int is_user, + void *retaddr) +{ + /* Uncomment the following line to enable mem_address_not_aligned traps */ + /* Not enabled yet because of bugs in OpenBIOS */ + //raise_exception(TT_UNALIGNED); + //printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc); +} /* try to fill the TLB and return an exception if error. If retaddr is NULL, it means that the function was called in C code (i.e. not diff --git a/target-sparc/translate.c b/target-sparc/translate.c index e51a2e459..19b10a200 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -25,7 +25,6 @@ Rest of V9 instructions, VIS instructions NPC/PC static optimisations (use JUMP_TB when possible) Optimize synthetic instructions - Optional alignment check 128-bit float */ -- cgit v1.2.3 From 3299908c834fd1699f59638dd36eba187963a694 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 13 Apr 2007 15:49:56 +0000 Subject: Fix Sparc64 wrfprs, move VIS ops where they belong, more VIS ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2656 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 20 ++++++++ target-sparc/translate.c | 129 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 111 insertions(+), 38 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 96c8b2db7..2c21b5331 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1864,4 +1864,24 @@ void OPPROTO op_faligndata() tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8); (*((uint64_t *)&DT0)) = tmp; } + +void OPPROTO op_movl_FT0_0(void) +{ + (*((uint32_t *)&FT0)) = 0; +} + +void OPPROTO op_movl_DT0_0(void) +{ + (*((uint64_t *)&DT0)) = 0; +} + +void OPPROTO op_movl_FT0_1(void) +{ + (*((uint32_t *)&FT0)) = 0xffffffff; +} + +void OPPROTO op_movl_DT0_1(void) +{ + (*((uint64_t *)&DT0)) = 0xffffffffffffffffULL; +} #endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 19b10a200..20dffe0d9 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1931,7 +1931,13 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movl_env_T0(offsetof(CPUSPARCState, asi)); break; case 0x6: /* V9 wrfprs */ + gen_op_xor_T1_T0(); gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs)); + save_state(dc); + gen_op_next_insn(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; break; case 0xf: /* V9 sir, nop if user */ #if !defined(CONFIG_USER_ONLY) @@ -2148,47 +2154,94 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; } - case 0x36: /* UltraSparc shutdown, VIS */ - { - int opf = GET_FIELD_SP(insn, 5, 13); - rs1 = GET_FIELD(insn, 13, 17); - rs2 = GET_FIELD(insn, 27, 31); - - switch (opf) { - case 0x018: /* VIS I alignaddr */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; - gen_movl_reg_T0(rs1); - gen_movl_reg_T1(rs2); - gen_op_alignaddr(); - gen_movl_T0_reg(rd); - break; - case 0x01a: /* VIS I alignaddrl */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; - // XXX - break; - case 0x048: /* VIS I faligndata */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); - gen_op_faligndata(); - gen_op_store_DT0_fpr(rd); - break; - default: - goto illegal_insn; - } - break; - } #endif default: goto illegal_insn; } } - } else if (xop == 0x36 || xop == 0x37) { /* CPop1 & CPop2, - V9 impdep1 & - impdep2 */ + } else if (xop == 0x36) { /* UltraSparc shutdown, VIS, V8 CPop1 */ +#ifdef TARGET_SPARC64 + int opf = GET_FIELD_SP(insn, 5, 13); + rs1 = GET_FIELD(insn, 13, 17); + rs2 = GET_FIELD(insn, 27, 31); + + switch (opf) { + case 0x018: /* VIS I alignaddr */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_movl_reg_T0(rs1); + gen_movl_reg_T1(rs2); + gen_op_alignaddr(); + gen_movl_T0_reg(rd); + break; + case 0x01a: /* VIS I alignaddrl */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + // XXX + break; + case 0x048: /* VIS I faligndata */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_faligndata(); + gen_op_store_DT0_fpr(rd); + break; + case 0x060: /* VIS I fzero */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_movl_DT0_0(); + gen_op_store_DT0_fpr(rd); + break; + case 0x061: /* VIS I fzeros */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_movl_FT0_0(); + gen_op_store_FT0_fpr(rd); + break; + case 0x074: /* VIS I fsrc1 */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_load_fpr_DT0(rs1); + gen_op_store_DT0_fpr(rd); + break; + case 0x075: /* VIS I fsrc1s */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_load_fpr_FT0(rs1); + gen_op_store_FT0_fpr(rd); + break; + case 0x078: /* VIS I fsrc2 */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_load_fpr_DT0(rs2); + gen_op_store_DT0_fpr(rd); + break; + case 0x079: /* VIS I fsrc2s */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_load_fpr_FT0(rs2); + gen_op_store_FT0_fpr(rd); + break; + case 0x07e: /* VIS I fone */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_movl_DT0_1(); + gen_op_store_DT0_fpr(rd); + break; + case 0x07f: /* VIS I fones */ + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + gen_op_movl_FT0_1(); + gen_op_store_FT0_fpr(rd); + break; + default: + goto illegal_insn; + } +#else + goto ncp_insn; +#endif + } else if (xop == 0x37) { /* V8 CPop2, V9 impdep2 */ #ifdef TARGET_SPARC64 goto illegal_insn; #else @@ -2995,8 +3048,8 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "\n"); } #ifdef TARGET_SPARC64 - cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d\n", - env->pstate, GET_CCR(env), env->asi, env->tl); + cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n", + env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs); cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d cleanwin %d cwp %d\n", env->cansave, env->canrestore, env->otherwin, env->wstate, env->cleanwin, NWINDOWS - 1 - env->cwp); -- cgit v1.2.3 From 5425a2164c99de50ac79e29cdd2cafbc3aafd2f4 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 13 Apr 2007 19:24:07 +0000 Subject: Fix Sparc32 device save methods git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2657 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 17 ++++++++++++++--- hw/slavio_serial.c | 1 + hw/tcx.c | 2 ++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index fea08d878..88d74c9a1 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -507,15 +507,21 @@ static void esp_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->ti_rptr); qemu_put_be32s(f, &s->ti_wptr); qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); + qemu_put_be32s(f, &s->sense); qemu_put_be32s(f, &s->dma); + qemu_put_buffer(f, s->cmdbuf, TI_BUFSZ); + qemu_put_be32s(f, &s->cmdlen); + qemu_put_be32s(f, &s->do_cmd); + qemu_put_be32s(f, &s->dma_left); + // There should be no transfers in progress, so dma_counter is not saved } static int esp_load(QEMUFile *f, void *opaque, int version_id) { ESPState *s = opaque; - if (version_id != 2) - return -EINVAL; // Cannot emulate 1 + if (version_id != 3) + return -EINVAL; // Cannot emulate 2 qemu_get_buffer(f, s->rregs, ESP_MAXREG); qemu_get_buffer(f, s->wregs, ESP_MAXREG); @@ -523,7 +529,12 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->ti_rptr); qemu_get_be32s(f, &s->ti_wptr); qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); + qemu_get_be32s(f, &s->sense); qemu_get_be32s(f, &s->dma); + qemu_get_buffer(f, s->cmdbuf, TI_BUFSZ); + qemu_get_be32s(f, &s->cmdlen); + qemu_get_be32s(f, &s->do_cmd); + qemu_get_be32s(f, &s->dma_left); return 0; } @@ -568,7 +579,7 @@ void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque) esp_reset(s); - register_savevm("esp", espaddr, 2, esp_save, esp_load, s); + register_savevm("esp", espaddr, 3, esp_save, esp_load, s); qemu_register_reset(esp_reset, s); return s; diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 2ca3eed65..165629251 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -688,6 +688,7 @@ void slavio_serial_ms_kbd_init(int base, qemu_irq irq) qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, "QEMU Sun Mouse"); qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); + register_savevm("slavio_serial_mouse", base, 2, slavio_serial_save, slavio_serial_load, s); qemu_register_reset(slavio_serial_reset, s); slavio_serial_reset(s); } diff --git a/hw/tcx.c b/hw/tcx.c index a1a6b6855..7ab0aa33a 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -243,6 +243,8 @@ static int tcx_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->dac_index); qemu_get_8s(f, &s->dac_state); update_palette_entries(s, 0, 256); + tcx_invalidate_display(s); + return 0; } -- cgit v1.2.3 From e58c8ba5f6b1bd9af00cf5fcebce4bdba0f0aabb Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 13 Apr 2007 20:17:54 +0000 Subject: Another fix for CP0 Cause register handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2658 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 2 +- target-mips/op.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index c23e9c6b3..71a972339 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -403,7 +403,7 @@ void do_interrupt (CPUState *env) env->PC = (int32_t)(env->CP0_EBase & ~0x3ff); } env->PC += offset; - env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); + env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); break; default: if (logfile) { diff --git a/target-mips/op.c b/target-mips/op.c index 9818847fe..395120416 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1401,7 +1401,7 @@ void op_mtc0_cause (void) if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) mask |= 1 << CP0Ca_DC; - env->CP0_Cause = (env->CP0_Cause & 0xFCC0FF7C) | (T0 & mask); + env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask); /* Handle the software interrupt as an hardware one, as they are very similar */ -- cgit v1.2.3 From 744e0915969881c86074b2365dec3c5f839b8331 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 13 Apr 2007 22:30:36 +0000 Subject: Nicer Log formatting. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2659 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 92712a899..258744aab 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -523,7 +523,7 @@ void debug_pre_eret (void) void debug_post_eret (void) { - fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, + fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, env->PC, env->CP0_EPC); if (env->CP0_Status & (1 << CP0St_ERL)) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); -- cgit v1.2.3 From ba13c4327e19c083dd76d69805c5bf3dd44ca46c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 14 Apr 2007 12:15:36 +0000 Subject: Add TARGET_FMT_plx to properly display target_phys_addr_t variables. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2660 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpu-defs.h b/cpu-defs.h index 202eaee2e..a19fef72d 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -62,8 +62,10 @@ typedef uint64_t target_ulong; #if TARGET_PHYS_ADDR_BITS == 32 typedef uint32_t target_phys_addr_t; +#define TARGET_FMT_plx "%08x" #elif TARGET_PHYS_ADDR_BITS == 64 typedef uint64_t target_phys_addr_t; +#define TARGET_FMT_plx "%016" PRIx64 #else #error TARGET_PHYS_ADDR_BITS undefined #endif -- cgit v1.2.3 From e96efcfcb19b81d87ed3baec419b14cdd6e021a4 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 14 Apr 2007 12:17:09 +0000 Subject: Fix miscellaneous display warnings for PowerPC & alpha targets and parallel CFI flash driver. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2661 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pflash_cfi02.c | 22 +++++++++++++--------- hw/ppc.c | 15 ++++++++------- hw/ppc_chrp.c | 6 +++--- linux-user/main.c | 6 +++--- target-alpha/cpu.h | 7 +++++++ target-alpha/translate.c | 3 ++- target-ppc/cpu.h | 8 +++++--- target-ppc/helper.c | 10 +++++----- 8 files changed, 46 insertions(+), 31 deletions(-) diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 0db8b5645..fc38cd6f4 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -91,7 +91,7 @@ static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width) uint32_t ret; uint8_t *p; - DPRINTF("%s: offset %08x\n", __func__, offset); + DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset); ret = -1; offset -= pfl->base; boff = offset & 0xFF; @@ -161,7 +161,7 @@ static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width) default: goto flash_read; } - DPRINTF("%s: ID %d %x\n", __func__, boff, ret); + DPRINTF("%s: ID " TARGET_FMT_ld " %x\n", __func__, boff, ret); break; case 0xA0: case 0x10: @@ -214,7 +214,8 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, offset -= pfl->base; cmd = value; - DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width); + DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__, + offset, value, width); if (pfl->cmd != 0xA0 && cmd == 0xF0) { DPRINTF("%s: flash reset asked (%02x %02x)\n", __func__, pfl->cmd, cmd); @@ -239,7 +240,7 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, return; } if (boff != 0x555 || cmd != 0xAA) { - DPRINTF("%s: unlock0 failed %04x %02x %04x\n", + DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n", __func__, boff, cmd, 0x555); goto reset_flash; } @@ -249,7 +250,8 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, /* We started an unlock sequence */ check_unlock1: if (boff != 0x2AA || cmd != 0x55) { - DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd); + DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__, + boff, cmd); goto reset_flash; } DPRINTF("%s: unlock sequence done\n", __func__); @@ -257,7 +259,8 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, case 2: /* We finished an unlock sequence */ if (!pfl->bypass && boff != 0x555) { - DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd); + DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__, + boff, cmd); goto reset_flash; } switch (cmd) { @@ -281,7 +284,7 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, /* We need another unlock sequence */ goto check_unlock0; case 0xA0: - DPRINTF("%s: write data offset %08x %08x %d\n", + DPRINTF("%s: write data offset " TARGET_FMT_lx " %08x %d\n", __func__, offset, value, width); p = pfl->storage; switch (width) { @@ -352,7 +355,7 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, switch (cmd) { case 0x10: if (boff != 0x555) { - DPRINTF("%s: chip erase: invalid address %04x\n", + DPRINTF("%s: chip erase: invalid address " TARGET_FMT_lx "\n", __func__, offset); goto reset_flash; } @@ -369,7 +372,8 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, /* Sector erase */ p = pfl->storage; offset &= ~(pfl->sector_len - 1); - DPRINTF("%s: start sector erase at %08x\n", __func__, offset); + DPRINTF("%s: start sector erase at " TARGET_FMT_lx "\n", __func__, + offset); memset(p + offset, 0xFF, pfl->sector_len); pflash_update(pfl, offset, pfl->sector_len); pfl->status = 0x00; diff --git a/hw/ppc.c b/hw/ppc.c index 8438bc6d1..4cd0c6673 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -464,8 +464,8 @@ static void cpu_4xx_fit_cb (void *opaque) if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) ppc_set_irq(env, PPC_INTERRUPT_FIT, 1); if (loglevel) { - fprintf(logfile, "%s: ir %d TCR %08x TSR %08x\n", __func__, - (env->spr[SPR_40x_TCR] >> 23) & 0x1, + fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__, + (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); } } @@ -495,9 +495,10 @@ static void cpu_4xx_pit_cb (void *opaque) if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) ppc_set_irq(env, PPC_INTERRUPT_PIT, 1); if (loglevel) { - fprintf(logfile, "%s: ar %d ir %d TCR %08x TSR %08x %08lx\n", __func__, - (env->spr[SPR_40x_TCR] >> 22) & 0x1, - (env->spr[SPR_40x_TCR] >> 26) & 0x1, + fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " " + "%016" PRIx64 "\n", __func__, + (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), + (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1), env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], ppcemb_timer->pit_reload); } @@ -536,7 +537,7 @@ static void cpu_4xx_wdt_cb (void *opaque) if (next == now) next++; if (loglevel) { - fprintf(logfile, "%s: TCR %08x TSR %08x\n", __func__, + fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__, env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); } switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { @@ -587,7 +588,7 @@ void store_40x_pit (CPUState *env, target_ulong val) qemu_del_timer(tb_env->decr_timer); } else { if (loglevel) - fprintf(logfile, "%s: start PIT 0x%08x\n", __func__, val); + fprintf(logfile, "%s: start PIT 0x" ADDRX "\n", __func__, val); now = qemu_get_clock(vm_clock); next = now + muldiv64(val, ticks_per_sec, tb_env->tb_freq); if (next == now) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 70571fd4e..9a7538cad 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -48,7 +48,7 @@ static int macio_nvram_mem_index = -1; static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { - printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value); + printf("%s: 0x" PADDRX " <= 0x%08x\n", __func__, addr, value); } static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value) @@ -61,7 +61,7 @@ static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) { - printf("%s: 0x%08x => 0x00000000\n", __func__, addr); + printf("%s: 0x" PADDRX " => 0x00000000\n", __func__, addr); return 0; } @@ -261,7 +261,7 @@ static int vga_osi_call(CPUState *env) /* R6 = x, R7 = y, R8 = visible, R9 = data */ break; default: - fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]); + fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]); break; } return 1; /* osi_call handled */ diff --git a/linux-user/main.c b/linux-user/main.c index 277f194d9..d14b49916 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -755,10 +755,10 @@ void cpu_loop(CPUPPCState *env) info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); case EXCP_DSI: - fprintf(stderr, "Invalid data memory access: 0x%08x\n", + fprintf(stderr, "Invalid data memory access: 0x" ADDRX "\n", env->spr[SPR_DAR]); if (loglevel) { - fprintf(logfile, "Invalid data memory access: 0x%08x\n", + fprintf(logfile, "Invalid data memory access: 0x" ADDRX "\n", env->spr[SPR_DAR]); } switch (env->error_code & 0xFF000000) { @@ -1549,7 +1549,7 @@ void cpu_loop(CPUM68KState *env) #ifdef TARGET_ALPHA void cpu_loop (CPUState *env) { - int trapnr, ret; + int trapnr; target_siginfo_t info; while (1) { diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index a77af17ef..729d5876e 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -382,6 +382,13 @@ enum { IR_ZERO = 31, }; +CPUAlphaState * cpu_alpha_init (void); +int cpu_alpha_exec(CPUAlphaState *s); +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +int cpu_alpha_signal_handler(int host_signum, void *pinfo, + void *puc); int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); void cpu_loop_exit (void); diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 0afd8964c..08e0624db 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -2004,7 +2004,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #if defined ALPHA_DEBUG_DISAS insn_count++; if (logfile != NULL) { - fprintf(logfile, "pc %016lx mem_idx\n", ctx.pc, ctx.mem_idx); + fprintf(logfile, "pc " TARGET_FMT_lx " mem_idx %d\n", + ctx.pc, ctx.mem_idx); } #endif insn = ldl_code(ctx.pc); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 4b67f1a25..740bc1b4c 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -35,24 +35,26 @@ typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 64 #define TARGET_GPR_BITS 64 #define REGX "%016" PRIx64 -#define ADDRX "%016" PRIx64 #elif defined(TARGET_PPCSPE) +/* e500v2 have 36 bits physical address space */ +#define TARGET_PHYS_ADDR_BITS 64 /* GPR are 64 bits: used by vector extension */ typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 32 #define TARGET_GPR_BITS 64 #define REGX "%016" PRIx64 -#define ADDRX "%08" PRIx32 #else typedef uint32_t ppc_gpr_t; #define TARGET_LONG_BITS 32 #define TARGET_GPR_BITS 32 #define REGX "%08" PRIx32 -#define ADDRX "%08" PRIx32 #endif #include "cpu-defs.h" +#define ADDRX TARGET_FMT_lx +#define PADDRX TARGET_FMT_plx + #include #include "softfloat.h" diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b9a55b1f2..a7d039182 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -38,7 +38,7 @@ /* PowerPC MMU emulation */ #if defined(CONFIG_USER_ONLY) -int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, +int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { int exception, error_code; @@ -631,7 +631,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, - uint32_t address, int rw, int access_type) + target_ulong address, int rw, int access_type) { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; @@ -649,8 +649,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } mask = ~(tlb->size - 1); if (loglevel) { - fprintf(logfile, "%s: TLB %d address %08x PID %04x <=> " - "%08x %08x %04x\n", + fprintf(logfile, "%s: TLB %d address " ADDRX " PID " ADDRX " <=> " + ADDRX " " ADDRX " " ADDRX "\n", __func__, i, address, env->spr[SPR_40x_PID], tlb->EPN, mask, tlb->PID); } @@ -832,7 +832,7 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) } /* Perform address translation */ -int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, +int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { mmu_ctx_t ctx; -- cgit v1.2.3 From 1c5bf3bf8ce43924663e58f1c92708ac3e59272a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 14 Apr 2007 12:17:59 +0000 Subject: Fix incorrect pointers casts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2662 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 +- monitor.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7ab506dd3..7f4f77169 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3345,7 +3345,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, strncpy(tde->d_name, de->d_name, tnamelen); de = (struct dirent *)((char *)de + reclen); len -= reclen; - tde = (struct dirent *)((char *)tde + treclen); + tde = (struct target_dirent *)((char *)tde + treclen); count1 += treclen; } ret = count1; diff --git a/monitor.c b/monitor.c index 86b1f389b..24c4dfb44 100644 --- a/monitor.c +++ b/monitor.c @@ -2116,9 +2116,9 @@ static void monitor_handle_command(const char *cmdline) } if (nb_args + 3 > MAX_ARGS) goto error_args; - args[nb_args++] = (void*)count; - args[nb_args++] = (void*)format; - args[nb_args++] = (void*)size; + args[nb_args++] = (void*)(long)count; + args[nb_args++] = (void*)(long)format; + args[nb_args++] = (void*)(long)size; } break; case 'i': @@ -2146,7 +2146,7 @@ static void monitor_handle_command(const char *cmdline) typestr++; if (nb_args >= MAX_ARGS) goto error_args; - args[nb_args++] = (void *)has_arg; + args[nb_args++] = (void *)(long)has_arg; if (!has_arg) { if (nb_args >= MAX_ARGS) goto error_args; @@ -2160,16 +2160,16 @@ static void monitor_handle_command(const char *cmdline) if (c == 'i') { if (nb_args >= MAX_ARGS) goto error_args; - args[nb_args++] = (void *)(int)val; + args[nb_args++] = (void *)(long)val; } else { if ((nb_args + 1) >= MAX_ARGS) goto error_args; #if TARGET_LONG_BITS == 64 - args[nb_args++] = (void *)(int)((val >> 32) & 0xffffffff); + args[nb_args++] = (void *)(long)((val >> 32) & 0xffffffff); #else args[nb_args++] = (void *)0; #endif - args[nb_args++] = (void *)(int)(val & 0xffffffff); + args[nb_args++] = (void *)(long)(val & 0xffffffff); } } break; @@ -2196,7 +2196,7 @@ static void monitor_handle_command(const char *cmdline) } if (nb_args >= MAX_ARGS) goto error_args; - args[nb_args++] = (void *)has_option; + args[nb_args++] = (void *)(long)has_option; } break; default: -- cgit v1.2.3 From dcb5b19a4e32d300a3ddf14fa8cc9a0a055dd1db Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 14 Apr 2007 12:24:46 +0000 Subject: Know about more PCI device classes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2663 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/hw/pci.c b/hw/pci.c index b5dcbdafd..def2dc088 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -469,11 +469,38 @@ static pci_class_desc pci_class_descriptions[] = { { 0x0100, "SCSI controller"}, { 0x0101, "IDE controller"}, + { 0x0102, "Floppy controller"}, + { 0x0103, "IPI controller"}, + { 0x0104, "RAID controller"}, + { 0x0106, "SATA controller"}, + { 0x0107, "SAS controller"}, + { 0x0180, "Storage controller"}, { 0x0200, "Ethernet controller"}, + { 0x0201, "Token Ring controller"}, + { 0x0202, "FDDI controller"}, + { 0x0203, "ATM controller"}, + { 0x0280, "Network controller"}, { 0x0300, "VGA controller"}, + { 0x0301, "XGA controller"}, + { 0x0302, "3D controller"}, + { 0x0380, "Display controller"}, + { 0x0400, "Video controller"}, + { 0x0401, "Audio controller"}, + { 0x0402, "Phone"}, + { 0x0480, "Multimedia controller"}, + { 0x0500, "RAM controller"}, + { 0x0501, "Flash controller"}, + { 0x0580, "Memory controller"}, { 0x0600, "Host bridge"}, { 0x0601, "ISA bridge"}, + { 0x0602, "EISA bridge"}, + { 0x0603, "MC bridge"}, { 0x0604, "PCI bridge"}, + { 0x0605, "PCMCIA bridge"}, + { 0x0606, "NUBUS bridge"}, + { 0x0607, "CARDBUS bridge"}, + { 0x0608, "RACEWAY bridge"}, + { 0x0680, "Bridge"}, { 0x0c03, "USB controller"}, { 0, NULL} }; -- cgit v1.2.3 From 16c00cb2c2017aaa04f2849903210761825145e7 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 14 Apr 2007 12:56:46 +0000 Subject: Restart interrupts after an exception. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2664 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 15 ++++++++++++++- target-mips/translate.c | 27 +++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 395120416..9e9f8eb75 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1365,7 +1365,7 @@ void op_mtc0_status (void) !(env->hflags & MIPS_HFLAG_DM) && (val & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; - env->CP0_Status = val; + env->CP0_Status = (env->CP0_Status & ~0xF878FF17) | val; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB2(do_mtc0_status_debug, old, val); CALL_FROM_TB1(cpu_mips_update_irq, env); @@ -2181,6 +2181,19 @@ void op_save_pc (void) RETURN(); } +void op_interrupt_restart (void) +{ + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & (1 << CP0St_IE)) && + (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) { + env->CP0_Cause &= ~(0x1f << CP0Ca_EC); + CALL_FROM_TB1(do_raise_exception, EXCP_EXT_INTERRUPT); + } + RETURN(); +} + void op_raise_exception (void) { CALL_FROM_TB1(do_raise_exception, PARAM1); diff --git a/target-mips/translate.c b/target-mips/translate.c index 75221c9c8..b0cc3e717 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5234,15 +5234,26 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (env->singlestep_enabled) { save_cpu_state(ctxp, ctx.bstate == BS_NONE); gen_op_debug(); - goto done_generating; - } - else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) { - save_cpu_state(ctxp, 0); - gen_goto_tb(&ctx, 0, ctx.pc); + } else { + switch (ctx.bstate) { + case BS_EXCP: + gen_op_interrupt_restart(); + break; + case BS_STOP: + gen_op_interrupt_restart(); + /* Fall through. */ + case BS_NONE: + save_cpu_state(ctxp, 0); + gen_goto_tb(&ctx, 0, ctx.pc); + break; + case BS_BRANCH: + default: + break; + } + gen_op_reset_T0(); + /* Generate the return instruction. */ + gen_op_exit_tb(); } - gen_op_reset_T0(); - /* Generate the return instruction */ - gen_op_exit_tb(); done_generating: *gen_opc_ptr = INDEX_op_end; if (search_pc) { -- cgit v1.2.3 From 3ccacc4a16f01a6dc0e863e2cbdbcc6ba1171e99 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 14 Apr 2007 13:01:31 +0000 Subject: Add device save and reset methods to FDC and M48T59 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2665 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/m48t59.c | 41 +++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index a12eb0af5..d89b2263e 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1,7 +1,7 @@ /* * QEMU Floppy disk emulator (Intel 82078) * - * Copyright (c) 2003 Jocelyn Mayer + * Copyright (c) 2003, 2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -485,6 +485,99 @@ static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { fdctrl_write_mem, }; +static void fd_save (QEMUFile *f, fdrive_t *fd) +{ + uint8_t tmp; + + tmp = fd->drflags; + qemu_put_8s(f, &tmp); + qemu_put_8s(f, &fd->head); + qemu_put_8s(f, &fd->track); + qemu_put_8s(f, &fd->sect); + qemu_put_8s(f, &fd->dir); + qemu_put_8s(f, &fd->rw); +} + +static void fdc_save (QEMUFile *f, void *opaque) +{ + fdctrl_t *s = opaque; + + qemu_put_8s(f, &s->state); + qemu_put_8s(f, &s->dma_en); + qemu_put_8s(f, &s->cur_drv); + qemu_put_8s(f, &s->bootsel); + qemu_put_buffer(f, s->fifo, FD_SECTOR_LEN); + qemu_put_be32s(f, &s->data_pos); + qemu_put_be32s(f, &s->data_len); + qemu_put_8s(f, &s->data_state); + qemu_put_8s(f, &s->data_dir); + qemu_put_8s(f, &s->int_status); + qemu_put_8s(f, &s->eot); + qemu_put_8s(f, &s->timer0); + qemu_put_8s(f, &s->timer1); + qemu_put_8s(f, &s->precomp_trk); + qemu_put_8s(f, &s->config); + qemu_put_8s(f, &s->lock); + qemu_put_8s(f, &s->pwrd); + fd_save(f, &s->drives[0]); + fd_save(f, &s->drives[1]); +} + +static int fd_load (QEMUFile *f, fdrive_t *fd) +{ + uint8_t tmp; + + qemu_get_8s(f, &tmp); + fd->drflags = tmp; + qemu_get_8s(f, &fd->head); + qemu_get_8s(f, &fd->track); + qemu_get_8s(f, &fd->sect); + qemu_get_8s(f, &fd->dir); + qemu_get_8s(f, &fd->rw); + + return 0; +} + +static int fdc_load (QEMUFile *f, void *opaque, int version_id) +{ + fdctrl_t *s = opaque; + int ret; + + if (version_id != 1) + return -EINVAL; + + qemu_get_8s(f, &s->state); + qemu_get_8s(f, &s->dma_en); + qemu_get_8s(f, &s->cur_drv); + qemu_get_8s(f, &s->bootsel); + qemu_get_buffer(f, s->fifo, FD_SECTOR_LEN); + qemu_get_be32s(f, &s->data_pos); + qemu_get_be32s(f, &s->data_len); + qemu_get_8s(f, &s->data_state); + qemu_get_8s(f, &s->data_dir); + qemu_get_8s(f, &s->int_status); + qemu_get_8s(f, &s->eot); + qemu_get_8s(f, &s->timer0); + qemu_get_8s(f, &s->timer1); + qemu_get_8s(f, &s->precomp_trk); + qemu_get_8s(f, &s->config); + qemu_get_8s(f, &s->lock); + qemu_get_8s(f, &s->pwrd); + + ret = fd_load(f, &s->drives[0]); + if (ret == 0) + ret = fd_load(f, &s->drives[1]); + + return ret; +} + +static void fdctrl_external_reset(void *opaque) +{ + fdctrl_t *s = opaque; + + fdctrl_reset(s, 0); +} + fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, uint32_t io_base, BlockDriverState **fds) @@ -525,6 +618,8 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl); register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl); } + register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl); + qemu_register_reset(fdctrl_external_reset, fdctrl); for (i = 0; i < 2; i++) { fd_revalidate(&fdctrl->drives[i]); } diff --git a/hw/m48t59.c b/hw/m48t59.c index 1c61401c5..e9fb0901b 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -1,7 +1,7 @@ /* * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms * - * Copyright (c) 2003-2005 Jocelyn Mayer + * Copyright (c) 2003-2005, 2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -575,12 +575,47 @@ static CPUReadMemoryFunc *nvram_read[] = { &nvram_readl, }; +static void m48t59_save(QEMUFile *f, void *opaque) +{ + m48t59_t *s = opaque; + + qemu_put_8s(f, &s->lock); + qemu_put_be16s(f, &s->addr); + qemu_put_buffer(f, s->buffer, s->size); +} + +static int m48t59_load(QEMUFile *f, void *opaque, int version_id) +{ + m48t59_t *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_8s(f, &s->lock); + qemu_get_be16s(f, &s->addr); + qemu_get_buffer(f, s->buffer, s->size); + + return 0; +} + +static void m48t59_reset(void *opaque) +{ + m48t59_t *NVRAM = opaque; + + if (NVRAM->alrm_timer != NULL) + qemu_del_timer(NVRAM->alrm_timer); + + if (NVRAM->wd_timer != NULL) + qemu_del_timer(NVRAM->wd_timer); +} + /* Initialisation routine */ m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base, uint32_t io_base, uint16_t size, int type) { m48t59_t *s; + target_ulong save_base; s = qemu_mallocz(sizeof(m48t59_t)); if (!s) @@ -610,5 +645,9 @@ m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base, } s->lock = 0; + qemu_register_reset(m48t59_reset, s); + save_base = mem_base ? mem_base : io_base; + register_savevm("m48t59", save_base, 1, m48t59_save, m48t59_load, s); + return s; } -- cgit v1.2.3 From 8979596d1785fd52badbdb177a5ef09d4f182f40 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 14 Apr 2007 16:15:48 +0000 Subject: Fix Sparc64 double float gdb protocol (initial version by Paul Brook) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2666 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 4d62a8891..813502f36 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -377,9 +377,9 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) for (i = 0; i < 64; i += 2) { uint64_t tmp; - tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32; - tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1])); - registers[i/2 + 32] = tmp; + tmp = ((uint64_t)*(uint32_t *)&env->fpr[i]) << 32; + tmp |= *(uint32_t *)&env->fpr[i + 1]; + registers[i / 2 + 32] = tswap64(tmp); } registers[64] = tswapl(env->pc); registers[65] = tswapl(env->npc); @@ -419,8 +419,11 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->fsr = tswapl(registers[70]); #else for (i = 0; i < 64; i += 2) { - *((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32); - *((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 0xffffffff); + uint64_t tmp; + + tmp = tswap64(registers[i / 2 + 32]); + *((uint32_t *)&env->fpr[i]) = tmp >> 32; + *((uint32_t *)&env->fpr[i + 1]) = tmp & 0xffffffff; } env->pc = tswapl(registers[64]); env->npc = tswapl(registers[65]); -- cgit v1.2.3 From aa6290b7e56270c42bce32cd57ff18de8608d4f7 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 14 Apr 2007 22:35:50 +0000 Subject: Fix format specified for watchpoint address. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2667 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gdbstub.c b/gdbstub.c index 813502f36..79f54f51f 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -929,7 +929,8 @@ static void gdb_vm_stopped(void *opaque, int reason) if (reason == EXCP_DEBUG) { if (s->env->watchpoint_hit) { - snprintf(buf, sizeof(buf), "T%02xwatch:%x;", SIGTRAP, + snprintf(buf, sizeof(buf), "T%02xwatch:" TARGET_FMT_lx ";", + SIGTRAP, s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr); put_packet(s, buf); s->env->watchpoint_hit = 0; -- cgit v1.2.3 From 080a0ba4b19aafac78f6764787785e6dee6e5a2f Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 15 Apr 2007 06:38:29 +0000 Subject: Update OpenBIOS for Sparc32 and add a Sparc64 image git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2668 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 1 + pc-bios/openbios-sparc32 | Bin 241940 -> 248348 bytes pc-bios/openbios-sparc64 | Bin 0 -> 1442408 bytes 3 files changed, 1 insertion(+) create mode 100644 pc-bios/openbios-sparc64 diff --git a/pc-bios/README b/pc-bios/README index 45e4b7cba..84551e9cf 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,6 +14,7 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. + The included Sparc32 and Sparc64 images are built from SVN version 123. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index b3f2c5238..ba9b78aba 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 new file mode 100644 index 000000000..65bae1177 Binary files /dev/null and b/pc-bios/openbios-sparc64 differ -- cgit v1.2.3 From 2a1094cd88afa69c0e7ecd1e81c712cc8f635153 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 15 Apr 2007 14:13:11 +0000 Subject: bFLT loader alignment fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2669 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/flatload.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/linux-user/flatload.c b/linux-user/flatload.c index c9f1acd55..bf10d7968 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -393,6 +393,7 @@ static int load_flat_file(struct linux_binprm * bprm, int i, rev, relocs = 0; target_ulong fpos; target_ulong start_code, end_code; + target_ulong indx_len; hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ @@ -443,6 +444,11 @@ static int load_flat_file(struct linux_binprm * bprm, if (extra < bss_len + stack_len) extra = bss_len + stack_len; + /* Add space for library base pointers. Make sure this does not + misalign the doesn't misalign the data segment. */ + indx_len = MAX_SHARED_LIBS * sizeof(target_ulong); + indx_len = (indx_len + 15) & ~(target_ulong)15; + /* * there are a couple of cases here, the separate code/data * case, and then the fully copied to RAM case which lumps @@ -462,8 +468,7 @@ static int load_flat_file(struct linux_binprm * bprm, return -1; } - realdatastart = target_mmap(0, data_len + extra + - MAX_SHARED_LIBS * sizeof(target_ulong), + realdatastart = target_mmap(0, data_len + extra + indx_len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -471,7 +476,7 @@ static int load_flat_file(struct linux_binprm * bprm, fprintf(stderr, "Unable to allocate RAM for process data\n"); return realdatastart; } - datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong); + datapos = realdatastart + indx_len; DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", (int)(data_len + bss_len + stack_len), (int)datapos); @@ -498,8 +503,7 @@ static int load_flat_file(struct linux_binprm * bprm, } else { - textpos = target_mmap(0, text_len + data_len + extra + - MAX_SHARED_LIBS * sizeof(target_ulong), + textpos = target_mmap(0, text_len + data_len + extra + indx_len, PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (textpos == -1 ) { @@ -508,9 +512,8 @@ static int load_flat_file(struct linux_binprm * bprm, } realdatastart = textpos + ntohl(hdr->data_start); - datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong); - reloc = (textpos + ntohl(hdr->reloc_start) + - MAX_SHARED_LIBS * sizeof(target_ulong)); + datapos = realdatastart + indx_len; + reloc = (textpos + ntohl(hdr->reloc_start) + indx_len); memp = textpos; #ifdef CONFIG_BINFMT_ZFLAT -- cgit v1.2.3 From bc687ec92249437eac5997de881e130d28736b0a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 15 Apr 2007 15:15:10 +0000 Subject: Gallileo fixes, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2670 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 3300d40be..3a0e8b153 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -550,7 +550,7 @@ void gt64120_reset(void *opaque) #ifdef TARGET_WORDS_BIGENDIAN s->regs[GT_CPU] = 0x00000000; #else - s->regs[GT_CPU] = 0x00000800; + s->regs[GT_CPU] = 0x00001000; #endif s->regs[GT_MULTI] = 0x00000000; @@ -608,6 +608,24 @@ void gt64120_reset(void *opaque) gt64120_pci_mapping(s); } +static uint32_t gt64120_read_config(PCIDevice *d, uint32_t address, int len) +{ + uint32_t val = pci_default_read_config(d, address, len); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static void gt64120_write_config(PCIDevice *d, uint32_t address, uint32_t val, + int len) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + pci_default_write_config(d, address, val, len); +} + PCIBus *pci_gt64120_init(qemu_irq *pic) { GT64120State *s; @@ -626,12 +644,12 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120); d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), - 0, NULL, NULL); + 0, gt64120_read_config, gt64120_write_config); d->config[0x00] = 0xab; // vendor_id d->config[0x01] = 0x11; - d->config[0x02] = 0x46; // device_id - d->config[0x03] = 0x20; + d->config[0x02] = 0x20; // device_id + d->config[0x03] = 0x46; d->config[0x04] = 0x06; d->config[0x05] = 0x00; d->config[0x06] = 0x80; -- cgit v1.2.3 From fff739ccd55a5fd2a15f51fedbad3debc1c8cd4a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 15 Apr 2007 17:27:07 +0000 Subject: Delete unused define. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2671 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 258744aab..576787d3f 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -20,8 +20,6 @@ #include #include "exec.h" -#define MIPS_DEBUG_DISAS - #define GETPC() (__builtin_return_address(0)) /*****************************************************************************/ -- cgit v1.2.3 From a85427b147f3174748a4eed13a7379a769bb05fd Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 15 Apr 2007 19:52:12 +0000 Subject: Small code generation optimization. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2672 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index b0cc3e717..59868f695 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5238,6 +5238,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, switch (ctx.bstate) { case BS_EXCP: gen_op_interrupt_restart(); + gen_op_reset_T0(); + /* Generate the return instruction. */ + gen_op_exit_tb(); break; case BS_STOP: gen_op_interrupt_restart(); @@ -5248,11 +5251,11 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, break; case BS_BRANCH: default: + gen_op_reset_T0(); + /* Generate the return instruction. */ + gen_op_exit_tb(); break; } - gen_op_reset_T0(); - /* Generate the return instruction. */ - gen_op_exit_tb(); } done_generating: *gen_opc_ptr = INDEX_op_end; -- cgit v1.2.3 From 80c27194a7be757ef5a9cec978d1d8faaa4cee81 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 15 Apr 2007 21:21:33 +0000 Subject: Fix qemu SIGFPE caused by division-by-zero due to underflow. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2673 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 7 ++++++- target-mips/op.c | 23 +++++++++++------------ target-mips/op_helper.c | 11 +++++++++++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index 54f4d5a75..cfe69a3ff 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -82,6 +82,9 @@ void do_drotrv (void); #endif #endif +#if HOST_LONG_BITS < 64 +void do_div (void); +#endif #if TARGET_LONG_BITS > HOST_LONG_BITS void do_mult (void); void do_multu (void); @@ -89,10 +92,12 @@ void do_madd (void); void do_maddu (void); void do_msub (void); void do_msubu (void); +#endif +#ifdef TARGET_MIPS64 void do_ddiv (void); +#if TARGET_LONG_BITS > HOST_LONG_BITS void do_ddivu (void); #endif -#ifdef TARGET_MIPS64 void do_dmult (void); void do_dmultu (void); #endif diff --git a/target-mips/op.c b/target-mips/op.c index 9e9f8eb75..2ea84b65a 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -368,14 +368,22 @@ void op_mul (void) RETURN(); } +#if HOST_LONG_BITS < 64 +void op_div (void) +{ + CALL_FROM_TB0(do_div); + RETURN(); +} +#else void op_div (void) { if (T1 != 0) { - env->LO = (int32_t)((int32_t)T0 / (int32_t)T1); - env->HI = (int32_t)((int32_t)T0 % (int32_t)T1); + env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); + env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); } RETURN(); } +#endif void op_divu (void) { @@ -432,7 +440,6 @@ void op_dmul (void) RETURN(); } -#if TARGET_LONG_BITS > HOST_LONG_BITS /* Those might call libgcc functions. */ void op_ddiv (void) { @@ -440,21 +447,13 @@ void op_ddiv (void) RETURN(); } +#if TARGET_LONG_BITS > HOST_LONG_BITS void op_ddivu (void) { do_ddivu(); RETURN(); } #else -void op_ddiv (void) -{ - if (T1 != 0) { - env->LO = (int64_t)T0 / (int64_t)T1; - env->HI = (int64_t)T0 % (int64_t)T1; - } - RETURN(); -} - void op_ddivu (void) { if (T1 != 0) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 576787d3f..14696aa92 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -216,6 +216,17 @@ void do_msubu (void) } #endif +#if HOST_LONG_BITS < 64 +void do_div (void) +{ + /* 64bit datatypes because we may see overflow/underflow. */ + if (T1 != 0) { + env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); + env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); + } +} +#endif + #ifdef TARGET_MIPS64 void do_dmult (void) { -- cgit v1.2.3 From 171b31e7c7b771dc9e20fcb8305fc330ee59c7a6 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 15 Apr 2007 21:26:37 +0000 Subject: Don't use T2 for INS, it conflicts with branch delay slot handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2674 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 4 ++-- target-mips/translate.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 2ea84b65a..08ef2281f 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -2234,7 +2234,7 @@ void op_ins(void) unsigned int size = PARAM2; target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; - T0 = (T2 & ~mask) | (((uint32_t)T1 << pos) & mask); + T0 = (T0 & ~mask) | (((uint32_t)T1 << pos) & mask); RETURN(); } @@ -2260,7 +2260,7 @@ void op_dins(void) unsigned int size = PARAM2; target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; - T0 = (T2 & ~mask) | ((T1 << pos) & mask); + T0 = (T0 & ~mask) | ((T1 << pos) & mask); RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index 59868f695..00ca4e21c 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1722,25 +1722,25 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, case OPC_INS: if (lsb > msb) goto fail; - GEN_LOAD_REG_TN(T2, rt); + GEN_LOAD_REG_TN(T0, rt); gen_op_ins(lsb, msb - lsb + 1); break; case OPC_DINSM: if (lsb > msb) goto fail; - GEN_LOAD_REG_TN(T2, rt); + GEN_LOAD_REG_TN(T0, rt); gen_op_ins(lsb, msb - lsb + 1 + 32); break; case OPC_DINSU: if (lsb > msb) goto fail; - GEN_LOAD_REG_TN(T2, rt); + GEN_LOAD_REG_TN(T0, rt); gen_op_ins(lsb + 32, msb - lsb + 1); break; case OPC_DINS: if (lsb > msb) goto fail; - GEN_LOAD_REG_TN(T2, rt); + GEN_LOAD_REG_TN(T0, rt); gen_op_ins(lsb, msb - lsb + 1); break; default: -- cgit v1.2.3 From e9a9a0811f0d445cca8c05a7257616ed1298424e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 15 Apr 2007 23:54:20 +0000 Subject: Remove unused variable. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2675 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/acpi.c b/hw/acpi.c index e78e56d62..5310570ec 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -473,7 +473,7 @@ void piix4_pm_init(PCIBus *bus, int devfn) { PIIX4PMState *s; uint8_t *pci_conf; - uint32_t pm_io_base, smb_io_base; + uint32_t smb_io_base; s = (PIIX4PMState *)pci_register_device(bus, "PM", sizeof(PIIX4PMState), -- cgit v1.2.3 From 9898128f55e46b695a3d39ac091356c1c296e9b4 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 16 Apr 2007 01:35:29 +0000 Subject: Simplify branch likely handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2676 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 00ca4e21c..35c98aba7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1455,12 +1455,11 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) gen_op_goto_tb1(TBPARAM(tb)); gen_op_save_pc(dest); gen_op_set_T0((long)tb + n); - gen_op_exit_tb(); } else { gen_op_save_pc(dest); - gen_op_set_T0(0); - gen_op_exit_tb(); + gen_op_reset_T0(); } + gen_op_exit_tb(); } /* Branches (before delay slot) */ @@ -1565,18 +1564,21 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BLTZAL: /* 0 < 0 */ gen_op_set_T0(ctx->pc + 8); gen_op_store_T0_gpr(31); + MIPS_DEBUG("bnever and link"); return; case OPC_BLTZALL: /* 0 < 0 likely */ gen_op_set_T0(ctx->pc + 8); gen_op_store_T0_gpr(31); - gen_goto_tb(ctx, 0, ctx->pc + 8); + /* Skip the instruction in the delay slot */ + MIPS_DEBUG("bnever, link and skip"); + ctx->pc += 4; return; case OPC_BNEL: /* rx != rx likely */ case OPC_BGTZL: /* 0 > 0 likely */ case OPC_BLTZL: /* 0 < 0 likely */ /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever and skip"); - gen_goto_tb(ctx, 0, ctx->pc + 8); + ctx->pc += 4; return; case OPC_J: ctx->hflags |= MIPS_HFLAG_B; @@ -5275,7 +5277,7 @@ done_generating: #endif if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, ctx.pc - pc_start, 0); + target_disas(logfile, pc_start, ctx.pc - pc_start, 0); fprintf(logfile, "\n"); } if (loglevel & CPU_LOG_TB_OP) { -- cgit v1.2.3 From a496775f87da7f2c445b146e0b31d3895d4af1e0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 07:10:48 +0000 Subject: Fix a lot of debug traces for PowerPC emulation: use logfile instead of stdout git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2677 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 106 +++++++++++++++++++++++++++++++++----------- target-ppc/helper.c | 53 ++++++++++++++++------ target-ppc/op.c | 33 ++++++++++++-- target-ppc/op_helper.c | 41 +++++++++++++++-- target-ppc/op_helper.h | 4 ++ target-ppc/translate.c | 10 +++++ target-ppc/translate_init.c | 18 ++++++++ 7 files changed, 216 insertions(+), 49 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 4cd0c6673..b16f30530 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -40,8 +40,11 @@ void ppc_set_irq (CPUState *env, int n_IRQ, int level) cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } #if defined(PPC_DEBUG_IRQ) - printf("%s: %p n_IRQ %d level %d => pending %08x req %08x\n", __func__, - env, n_IRQ, level, env->pending_interrupts, env->interrupt_request); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08x req %08x\n", + __func__, env, n_IRQ, level, + env->pending_interrupts, env->interrupt_request); + } #endif } @@ -52,7 +55,10 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) int cur_level; #if defined(PPC_DEBUG_IRQ) - printf("%s: env %p pin %d level %d\n", __func__, env, pin, level); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: env %p pin %d level %d\n", __func__, + env, pin, level); + } #endif cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ @@ -61,14 +67,20 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) case PPC6xx_INPUT_INT: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) - printf("%s: set the external IRQ state to %d\n", __func__, level); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the external IRQ state to %d\n", + __func__, level); + } #endif ppc_set_irq(env, PPC_INTERRUPT_EXT, level); break; case PPC6xx_INPUT_SMI: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) - printf("%s: set the SMI IRQ state to %d\n", __func__, level); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the SMI IRQ state to %d\n", + __func__, level); + } #endif ppc_set_irq(env, PPC_INTERRUPT_SMI, level); break; @@ -79,7 +91,10 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) */ if (cur_level == 1 && level == 0) { #if defined(PPC_DEBUG_IRQ) - printf("%s: raise machine check state\n", __func__); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: raise machine check state\n", + __func__); + } #endif ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); } @@ -89,12 +104,16 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) /* XXX: TODO: relay the signal to CKSTP_OUT pin */ if (level) { #if defined(PPC_DEBUG_IRQ) - printf("%s: stop the CPU\n", __func__); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: stop the CPU\n", __func__); + } #endif env->halted = 1; } else { #if defined(PPC_DEBUG_IRQ) - printf("%s: restart the CPU\n", __func__); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: restart the CPU\n", __func__); + } #endif env->halted = 0; } @@ -104,7 +123,9 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) if (level) { #if 0 // XXX: TOFIX #if defined(PPC_DEBUG_IRQ) - printf("%s: reset the CPU\n", __func__); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: reset the CPU\n", __func__); + } #endif cpu_reset(env); #endif @@ -112,14 +133,19 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) break; case PPC6xx_INPUT_SRESET: #if defined(PPC_DEBUG_IRQ) - printf("%s: set the RESET IRQ state to %d\n", __func__, level); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the RESET IRQ state to %d\n", + __func__, level); + } #endif ppc_set_irq(env, PPC_INTERRUPT_RESET, level); break; default: /* Unknown pin - do nothing */ #if defined(PPC_DEBUG_IRQ) - printf("%s: unknown IRQ pin %d\n", __func__, pin); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin); + } #endif return; } @@ -176,7 +202,10 @@ static void ppc405_set_irq (void *opaque, int pin, int level) case PPC405_INPUT_INT: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) - printf("%s: set the external IRQ state to %d\n", __func__, level); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the external IRQ state to %d\n", + __func__, level); + } #endif ppc_set_irq(env, PPC_INTERRUPT_EXT, level); break; @@ -184,12 +213,16 @@ static void ppc405_set_irq (void *opaque, int pin, int level) /* Level sensitive - active low */ if (level) { #if defined(PPC_DEBUG_IRQ) - printf("%s: stop the CPU\n", __func__); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: stop the CPU\n", __func__); + } #endif env->halted = 1; } else { #if defined(PPC_DEBUG_IRQ) - printf("%s: restart the CPU\n", __func__); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: restart the CPU\n", __func__); + } #endif env->halted = 0; } @@ -197,14 +230,19 @@ static void ppc405_set_irq (void *opaque, int pin, int level) case PPC405_INPUT_DEBUG: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) - printf("%s: set the external IRQ state to %d\n", __func__, level); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the external IRQ state to %d\n", + __func__, level); + } #endif ppc_set_irq(env, EXCP_40x_DEBUG, level); break; default: /* Unknown pin - do nothing */ #if defined(PPC_DEBUG_IRQ) - printf("%s: unknown IRQ pin %d\n", __func__, pin); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin); + } #endif return; } @@ -217,7 +255,6 @@ static void ppc405_set_irq (void *opaque, int pin, int level) void ppc405_irq_init (CPUState *env) { - printf("%s\n", __func__); env->irq_inputs = (void **)qemu_allocate_irqs(&ppc405_set_irq, env, 7); } @@ -255,8 +292,10 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) now = time(NULL); if (last_time != now) { last_time = now; - printf("%s: tb=0x%016lx %d %08lx\n", - __func__, tb, now, tb_env->tb_offset); + if (loglevel) { + fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n", + __func__, tb, now, tb_env->tb_offset); + } } } #endif @@ -271,7 +310,9 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) tb = cpu_ppc_get_tb(tb_env); #ifdef DEBUG_TB - printf("%s: tb=0x%016lx\n", __func__, tb); + if (loglevel) { + fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); + } #endif return tb >> 32; @@ -282,7 +323,9 @@ static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) - qemu_get_clock(vm_clock); #ifdef DEBUG_TB - printf("%s: tb=0x%016lx offset=%08x\n", __func__, value); + if (loglevel) { + fprintf(logfile, "%s: tb=0x%016lx offset=%08x\n", __func__, value); + } #endif } @@ -314,7 +357,9 @@ uint32_t cpu_ppc_load_decr (CPUState *env) else decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec); #if defined(DEBUG_TB) - printf("%s: 0x%08x\n", __func__, decr); + if (loglevel) { + fprintf(logfile, "%s: 0x%08x\n", __func__, decr); + } #endif return decr; @@ -327,7 +372,9 @@ static inline void cpu_ppc_decr_excp (CPUState *env) { /* Raise it */ #ifdef DEBUG_TB - printf("raise decrementer exception\n"); + if (loglevel) { + fprintf(logfile, "raise decrementer exception\n"); + } #endif ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); } @@ -339,7 +386,9 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, uint64_t now, next; #ifdef DEBUG_TB - printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value); + if (loglevel) { + fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value); + } #endif now = qemu_get_clock(vm_clock); next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); @@ -578,17 +627,20 @@ void store_40x_pit (CPUState *env, target_ulong val) tb_env = env->tb_env; ppcemb_timer = tb_env->opaque; - if (loglevel) + if (loglevel) { fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); + } ppcemb_timer->pit_reload = val; if (val == 0) { /* Stop PIT */ - if (loglevel) + if (loglevel) { fprintf(logfile, "%s: stop PIT\n", __func__); + } qemu_del_timer(tb_env->decr_timer); } else { - if (loglevel) + if (loglevel) { fprintf(logfile, "%s: start PIT 0x" ADDRX "\n", __func__, val); + } now = qemu_get_clock(vm_clock); next = now + muldiv64(val, ticks_per_sec, tb_env->tb_freq); if (next == now) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index a7d039182..aac790782 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -649,10 +649,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } mask = ~(tlb->size - 1); if (loglevel) { - fprintf(logfile, "%s: TLB %d address " ADDRX " PID " ADDRX " <=> " - ADDRX " " ADDRX " " ADDRX "\n", - __func__, i, address, env->spr[SPR_40x_PID], - tlb->EPN, mask, tlb->PID); + fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " + ADDRX " " ADDRX " %d\n", + __func__, i, address, (int)env->spr[SPR_40x_PID], + tlb->EPN, mask, (int)tlb->PID); } /* Check PID */ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) @@ -1450,9 +1450,6 @@ void do_interrupt (CPUState *env) if (loglevel) { fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); - } else { - printf("DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX "\n", - env->spr[SPR_DSISR], env->spr[SPR_DAR]); } #endif goto store_next; @@ -1495,7 +1492,9 @@ void do_interrupt (CPUState *env) case EXCP_FP: if (msr_fe0 == 0 && msr_fe1 == 0) { #if defined (DEBUG_EXCEPTIONS) - printf("Ignore floating point exception\n"); + if (loglevel) { + fprintf(logfile, "Ignore floating point exception\n"); + } #endif return; } @@ -1508,7 +1507,12 @@ void do_interrupt (CPUState *env) env->fpscr[7] |= 0x4; break; case EXCP_INVAL: - // printf("Invalid instruction at 0x" ADDRX "\n", env->nip); +#if defined (DEBUG_EXCEPTIONS) + if (loglevel) { + fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n", + env->nip); + } +#endif msr |= 0x00080000; break; case EXCP_PRIV: @@ -1609,8 +1613,10 @@ void do_interrupt (CPUState *env) case PPC_FLAGS_EXCP_40x: /* PIT on 4xx */ msr &= ~0xFFFF0000; +#if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) fprintf(logfile, "PIT exception\n"); +#endif goto store_next; case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: @@ -1630,8 +1636,10 @@ void do_interrupt (CPUState *env) case PPC_FLAGS_EXCP_40x: /* FIT on 4xx */ msr &= ~0xFFFF0000; +#if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) fprintf(logfile, "FIT exception\n"); +#endif goto store_next; default: cpu_abort(env, "Invalid exception 0x1010 !\n"); @@ -1644,8 +1652,10 @@ void do_interrupt (CPUState *env) case PPC_FLAGS_EXCP_40x: /* Watchdog on 4xx */ msr &= ~0xFFFF0000; +#if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) fprintf(logfile, "WDT exception\n"); +#endif goto store_next; case PPC_FLAGS_EXCP_BOOKE: srr_0 = &env->spr[SPR_BOOKE_CSRR0]; @@ -1929,11 +1939,12 @@ void ppc_hw_interrupt (CPUPPCState *env) { int raised = 0; -#if 0 - printf("%s: %p pending %08x req %08x %08x me %d ee %d\n", - __func__, env, env->pending_interrupts, - env->interrupt_request, interrupt_request, - msr_me, msr_ee); +#if 1 + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n", + __func__, env, env->pending_interrupts, + env->interrupt_request, msr_me, msr_ee); + } #endif /* Raise it */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { @@ -2007,3 +2018,17 @@ void ppc_hw_interrupt (CPUPPCState *env) } } #endif /* !CONFIG_USER_ONLY */ + +void cpu_dump_EA (target_ulong EA) +{ + FILE *f; + + if (logfile) { + f = logfile; + } else { + f = stdout; + return; + } + fprintf(f, "Memory access at address " TARGET_FMT_lx "\n", EA); +} + diff --git a/target-ppc/op.c b/target-ppc/op.c index 3a2f5f85b..68828f5f1 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -130,6 +130,13 @@ #define REG 31 #include "op_template.h" + +void OPPROTO op_print_mem_EA (void) +{ + do_print_mem_EA(T0); + RETURN(); +} + /* PowerPC state maintenance operations */ /* set_Rc0 */ PPC_OP(set_Rc0) @@ -360,15 +367,33 @@ void OPPROTO op_store_msr_32 (void) #endif /* SPR */ -PPC_OP(load_spr) +void OPPROTO op_load_spr (void) +{ + T0 = env->spr[PARAM1]; + RETURN(); +} + +void OPPROTO op_store_spr (void) +{ + env->spr[PARAM1] = T0; + RETURN(); +} + +void OPPROTO op_load_dump_spr (void) +{ + T0 = ppc_load_dump_spr(PARAM1); + RETURN(); +} + +void OPPROTO op_store_dump_spr (void) { - T0 = regs->spr[PARAM(1)]; + ppc_store_dump_spr(PARAM1, T0); RETURN(); } -PPC_OP(store_spr) +void OPPROTO op_mask_spr (void) { - regs->spr[PARAM(1)] = T0; + env->spr[PARAM1] &= ~T0; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index a65da36b7..140b7f5cb 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -68,6 +68,12 @@ void do_raise_exception (uint32_t exception) do_raise_exception_err(exception, 0); } +void cpu_dump_EA (target_ulong EA); +void do_print_mem_EA (target_ulong EA) +{ + cpu_dump_EA(EA); +} + /*****************************************************************************/ /* Registers load and stores */ void do_load_cr (void) @@ -181,6 +187,25 @@ void do_store_fpscr (uint32_t mask) set_float_rounding_mode(rnd_type, &env->fp_status); } +target_ulong ppc_load_dump_spr (int sprn) +{ + if (loglevel) { + fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n", + sprn, sprn, env->spr[sprn]); + } + + return env->spr[sprn]; +} + +void ppc_store_dump_spr (int sprn, target_ulong val) +{ + if (loglevel) { + fprintf(logfile, "Write SPR %d %03x => " ADDRX " <= " ADDRX "\n", + sprn, sprn, env->spr[sprn], val); + } + env->spr[sprn] = val; +} + /*****************************************************************************/ /* Fixed point operations helpers */ #if defined(TARGET_PPC64) @@ -1250,10 +1275,14 @@ void do_load_dcr (void) target_ulong val; if (unlikely(env->dcr_env == NULL)) { - printf("No DCR environment\n"); + if (loglevel) { + fprintf(logfile, "No DCR environment\n"); + } do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) { - printf("DCR read error\n"); + if (loglevel) { + fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0); + } do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); } else { T0 = val; @@ -1263,10 +1292,14 @@ void do_load_dcr (void) void do_store_dcr (void) { if (unlikely(env->dcr_env == NULL)) { - printf("No DCR environment\n"); + if (loglevel) { + fprintf(logfile, "No DCR environment\n"); + } do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) { - printf("DCR write error\n"); + if (loglevel) { + fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0); + } do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); } } diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index abc295a4d..293031075 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -50,6 +50,8 @@ void glue(do_icbi_64, MEMSUFFIX) (void); #else +void do_print_mem_EA (target_ulong EA); + /* Registers load and stores */ void do_load_cr (void); void do_store_cr (uint32_t mask); @@ -57,6 +59,8 @@ void do_load_xer (void); void do_store_xer (void); void do_load_fpscr (void); void do_store_fpscr (uint32_t mask); +target_ulong ppc_load_dump_spr (int sprn); +void ppc_store_dump_spr (int sprn, target_ulong val); /* Integer arithmetic helpers */ void do_adde (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 614570118..fa533fe9e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -29,6 +29,7 @@ //#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS +//#define DEBUG_MEMORY_ACCESSES //#define DO_PPC_STATISTICS #if defined(USE_DIRECT_JUMP) @@ -1745,6 +1746,9 @@ static inline void gen_addr_imm_index (DisasContext *ctx, int maskl) if (likely(simm != 0)) gen_op_addi(simm); } +#ifdef DEBUG_MEMORY_ACCESSES + gen_op_print_mem_EA(); +#endif } static inline void gen_addr_reg_index (DisasContext *ctx) @@ -1756,6 +1760,9 @@ static inline void gen_addr_reg_index (DisasContext *ctx) gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_add(); } +#ifdef DEBUG_MEMORY_ACCESSES + gen_op_print_mem_EA(); +#endif } static inline void gen_addr_register (DisasContext *ctx) @@ -1765,6 +1772,9 @@ static inline void gen_addr_register (DisasContext *ctx) } else { gen_op_load_gpr_T0(rA(ctx->opcode)); } +#ifdef DEBUG_MEMORY_ACCESSES + gen_op_print_mem_EA(); +#endif } /*** Integer load ***/ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 72e577dc2..c7a732454 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -25,6 +25,7 @@ //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR +//#define PPC_DEBUG_IRQ struct ppc_def_t { const unsigned char *name; @@ -61,6 +62,23 @@ static void spr_write_generic (void *opaque, int sprn) gen_op_store_spr(sprn); } +static void spr_read_dump (void *opaque, int sprn) +{ + gen_op_load_dump_spr(sprn); +} + +static void spr_write_dump (void *opaque, int sprn) +{ + gen_op_store_dump_spr(sprn); +} + +#if !defined(CONFIG_USER_ONLY) +static void spr_write_clear (void *opaque, int sprn) +{ + gen_op_mask_spr(sprn); +} +#endif + /* SPR common to all PowerPC */ /* XER */ static void spr_read_xer (void *opaque, int sprn) -- cgit v1.2.3 From 95d1f3edd5ecebcf8d1b8efe1a0b4533e3629e39 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 07:14:26 +0000 Subject: Parallel flash bugfixes: - always need to register flash area back to IO_MEM_ROMD at reset time - disabled buffered write as it's not actually supported - don't check flash time at registration time git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2678 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pflash_cfi02.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index fc38cd6f4..76e4a1d9b 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -208,19 +208,23 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, /* WARNING: when the memory area is in ROMD mode, the offset is a ram offset, not a physical address */ + cmd = value; + if (pfl->cmd != 0xA0 && cmd == 0xF0) { +#if 0 + DPRINTF("%s: flash reset asked (%02x %02x)\n", + __func__, pfl->cmd, cmd); +#endif + goto reset_flash; + } + DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__, + offset, value, width, pfl->wcycle); if (pfl->wcycle == 0) offset -= (target_ulong)(long)pfl->storage; else offset -= pfl->base; - cmd = value; DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__, offset, value, width); - if (pfl->cmd != 0xA0 && cmd == 0xF0) { - DPRINTF("%s: flash reset asked (%02x %02x)\n", - __func__, pfl->cmd, cmd); - goto reset_flash; - } /* Set the device in I/O access mode */ cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem); boff = offset & (pfl->sector_len - 1); @@ -416,10 +420,8 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, /* Reset flash */ reset_flash: - if (pfl->wcycle != 0) { - cpu_register_physical_memory(pfl->base, pfl->total_len, - pfl->off | IO_MEM_ROMD | pfl->fl_mem); - } + cpu_register_physical_memory(pfl->base, pfl->total_len, + pfl->off | IO_MEM_ROMD | pfl->fl_mem); pfl->bypass = 0; pfl->wcycle = 0; pfl->cmd = 0; @@ -530,14 +532,17 @@ pflash_t *pflash_register (target_ulong base, ram_addr_t off, total_len = sector_len * nb_blocs; /* XXX: to be fixed */ +#if 0 if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024)) return NULL; +#endif pfl = qemu_mallocz(sizeof(pflash_t)); if (pfl == NULL) return NULL; pfl->storage = phys_ram_base + off; - pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl); + pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, + pfl); pfl->off = off; cpu_register_physical_memory(base, total_len, off | pfl->fl_mem | IO_MEM_ROMD); @@ -613,7 +618,9 @@ pflash_t *pflash_register (target_ulong base, ram_addr_t off, pfl->cfi_table[0x28] = 0x02; pfl->cfi_table[0x29] = 0x00; /* Max number of bytes in multi-bytes write */ - pfl->cfi_table[0x2A] = 0x05; + /* XXX: disable buffered write as it's not supported */ + // pfl->cfi_table[0x2A] = 0x05; + pfl->cfi_table[0x2A] = 0x00; pfl->cfi_table[0x2B] = 0x00; /* Number of erase block regions (uniform) */ pfl->cfi_table[0x2C] = 0x01; -- cgit v1.2.3 From 08e46e54ea498b7e9a2a415435844f21c17064fc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 07:18:42 +0000 Subject: PowerPC emulation bugfixes: - don't generate multiple exit_tb at the end of conditional branches - disable TRACE exception as it is not correct for embedded PowerPC. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2679 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index fa533fe9e..0658fec28 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2806,11 +2806,11 @@ static inline void gen_bcond(DisasContext *ctx, int type) #endif gen_op_btest_T1(ctx->nip); gen_op_reset_T0(); - } no_test: - if (ctx->singlestep_enabled) - gen_op_debug(); - gen_op_exit_tb(); + if (ctx->singlestep_enabled) + gen_op_debug(); + gen_op_exit_tb(); + } ctx->exception = EXCP_BRANCH; } @@ -4725,7 +4725,7 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON) #endif } -/* PPC 440 specific instructions */ +/* PowerPC 440 specific instructions */ /* dlmzb */ GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC) { @@ -5838,6 +5838,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, handler->count++; #endif /* Check trace mode exceptions */ +#if 0 // XXX: buggy on embedded PowerPC if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) || /* Check in single step trace mode * we need to stop except if: @@ -5852,6 +5853,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, ctx.exception != EXCP_TRAP))) { RET_EXCP(ctxp, EXCP_TRACE, 0); } +#endif /* if we reach a page boundary or are single stepping, stop * generation */ -- cgit v1.2.3 From d0dfae6e91d9b2044523ed4db890860f898af86b Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 07:34:39 +0000 Subject: Add bus model (or input pins) into PowerPC CPU flags. Add PowerPC 970 bus and exceptions model. Add code provision for PowerPC 970 instanciation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2680 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 122 ++++++++++++++++++++++++++++++++++++++++++++ target-ppc/cpu.h | 119 +++++++++++++++++++++++++++--------------- target-ppc/helper.c | 7 +++ target-ppc/translate_init.c | 32 ++++++++++++ 4 files changed, 238 insertions(+), 42 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index b16f30530..62e9e1b1e 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -161,6 +161,128 @@ void ppc6xx_irq_init (CPUState *env) env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6); } +/* PowerPC 970 internal IRQ controller */ +static void ppc970_set_irq (void *opaque, int pin, int level) +{ + CPUState *env = opaque; + int cur_level; + +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: env %p pin %d level %d\n", __func__, + env, pin, level); + } +#endif + cur_level = (env->irq_input_state >> pin) & 1; + /* Don't generate spurious events */ + if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + switch (pin) { + case PPC970_INPUT_INT: + /* Level sensitive - active high */ +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the external IRQ state to %d\n", + __func__, level); + } +#endif + ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + break; + case PPC970_INPUT_THINT: + /* Level sensitive - active high */ +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__, + level); + } +#endif + ppc_set_irq(env, PPC_INTERRUPT_THERM, level); + break; + case PPC970_INPUT_MCP: + /* Negative edge sensitive */ + /* XXX: TODO: actual reaction may depends on HID0 status + * 603/604/740/750: check HID0[EMCP] + */ + if (cur_level == 1 && level == 0) { +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: raise machine check state\n", + __func__); + } +#endif + ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + } + break; + case PPC970_INPUT_CKSTP: + /* Level sensitive - active low */ + /* XXX: TODO: relay the signal to CKSTP_OUT pin */ + if (level) { +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: stop the CPU\n", __func__); + } +#endif + env->halted = 1; + } else { +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: restart the CPU\n", __func__); + } +#endif + env->halted = 0; + } + break; + case PPC970_INPUT_HRESET: + /* Level sensitive - active low */ + if (level) { +#if 0 // XXX: TOFIX +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: reset the CPU\n", __func__); + } +#endif + cpu_reset(env); +#endif + } + break; + case PPC970_INPUT_SRESET: +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the RESET IRQ state to %d\n", + __func__, level); + } +#endif + ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + break; + case PPC970_INPUT_TBEN: +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the TBEN state to %d\n", __func__, + level); + } +#endif + /* XXX: TODO */ + break; + default: + /* Unknown pin - do nothing */ +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin); + } +#endif + return; + } + if (level) + env->irq_input_state |= 1 << pin; + else + env->irq_input_state &= ~(1 << pin); + } +} + +void ppc970_irq_init (CPUState *env) +{ + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7); +} + /* PowerPC 405 internal IRQ controller */ static void ppc405_set_irq (void *opaque, int pin, int level) { diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 740bc1b4c..1e309f91d 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -393,51 +393,60 @@ enum { /* CPU run-time flags (MMU and exception model) */ enum { /* MMU model */ - PPC_FLAGS_MMU_MASK = 0x0000000F, + PPC_FLAGS_MMU_MASK = 0x000000FF, /* Standard 32 bits PowerPC MMU */ - PPC_FLAGS_MMU_32B = 0x00000000, + PPC_FLAGS_MMU_32B = 0x00000000, /* Standard 64 bits PowerPC MMU */ - PPC_FLAGS_MMU_64B = 0x00000001, + PPC_FLAGS_MMU_64B = 0x00000001, /* PowerPC 601 MMU */ - PPC_FLAGS_MMU_601 = 0x00000002, + PPC_FLAGS_MMU_601 = 0x00000002, /* PowerPC 6xx MMU with software TLB */ - PPC_FLAGS_MMU_SOFT_6xx = 0x00000003, + PPC_FLAGS_MMU_SOFT_6xx = 0x00000003, /* PowerPC 4xx MMU with software TLB */ - PPC_FLAGS_MMU_SOFT_4xx = 0x00000004, + PPC_FLAGS_MMU_SOFT_4xx = 0x00000004, /* PowerPC 403 MMU */ - PPC_FLAGS_MMU_403 = 0x00000005, - /* Freescale e500 MMU model */ - PPC_FLAGS_MMU_e500 = 0x00000006, + PPC_FLAGS_MMU_403 = 0x00000005, + /* BookE FSL MMU model */ + PPC_FLAGS_MMU_BOOKE_FSL = 0x00000006, /* BookE MMU model */ - PPC_FLAGS_MMU_BOOKE = 0x00000007, + PPC_FLAGS_MMU_BOOKE = 0x00000007, + /* 64 bits "bridge" PowerPC MMU */ + PPC_FLAGS_MMU_64BRIDGE = 0x00000008, /* Exception model */ - PPC_FLAGS_EXCP_MASK = 0x000000F0, + PPC_FLAGS_EXCP_MASK = 0x0000FF00, /* Standard PowerPC exception model */ - PPC_FLAGS_EXCP_STD = 0x00000000, + PPC_FLAGS_EXCP_STD = 0x00000000, /* PowerPC 40x exception model */ - PPC_FLAGS_EXCP_40x = 0x00000010, + PPC_FLAGS_EXCP_40x = 0x00000100, /* PowerPC 601 exception model */ - PPC_FLAGS_EXCP_601 = 0x00000020, + PPC_FLAGS_EXCP_601 = 0x00000200, /* PowerPC 602 exception model */ - PPC_FLAGS_EXCP_602 = 0x00000030, + PPC_FLAGS_EXCP_602 = 0x00000300, /* PowerPC 603 exception model */ - PPC_FLAGS_EXCP_603 = 0x00000040, + PPC_FLAGS_EXCP_603 = 0x00000400, /* PowerPC 604 exception model */ - PPC_FLAGS_EXCP_604 = 0x00000050, + PPC_FLAGS_EXCP_604 = 0x00000500, /* PowerPC 7x0 exception model */ - PPC_FLAGS_EXCP_7x0 = 0x00000060, + PPC_FLAGS_EXCP_7x0 = 0x00000600, /* PowerPC 7x5 exception model */ - PPC_FLAGS_EXCP_7x5 = 0x00000070, + PPC_FLAGS_EXCP_7x5 = 0x00000700, /* PowerPC 74xx exception model */ - PPC_FLAGS_EXCP_74xx = 0x00000080, + PPC_FLAGS_EXCP_74xx = 0x00000800, /* PowerPC 970 exception model */ - PPC_FLAGS_EXCP_970 = 0x00000090, + PPC_FLAGS_EXCP_970 = 0x00000900, /* BookE exception model */ - PPC_FLAGS_EXCP_BOOKE = 0x000000A0, + PPC_FLAGS_EXCP_BOOKE = 0x00000A00, + /* Input pins model */ + PPC_FLAGS_INPUT_MASK = 0x000F0000, + PPC_FLAGS_INPUT_6xx = 0x00000000, + PPC_FLAGS_INPUT_BookE = 0x00010000, + PPC_FLAGS_INPUT_40x = 0x00020000, + PPC_FLAGS_INPUT_970 = 0x00030000, }; #define PPC_MMU(env) (env->flags & PPC_FLAGS_MMU_MASK) #define PPC_EXCP(env) (env->flags & PPC_FLAGS_EXCP_MASK) +#define PPC_INPUT(env) (env->flags & PPC_FLAGS_INPUT_MASK) /*****************************************************************************/ /* Supported instruction set definitions */ @@ -454,64 +463,78 @@ enum { #define PPC_INSNS_403 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIA | PPC_4xx_COMMON | PPC_40x_EXCP | \ PPC_40x_SPEC) -#define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x) +#define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x | \ + PPC_FLAGS_INPUT_40x) /* PowerPC 405 */ #define PPC_INSNS_405 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_CACHE_OPT | PPC_MEM_TLBIA | PPC_TB | \ PPC_4xx_COMMON | PPC_40x_SPEC | PPC_40x_EXCP | \ PPC_405_MAC) -#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x) +#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x | \ + PPC_FLAGS_INPUT_40x) /* PowerPC 440 */ #define PPC_INSNS_440 (PPC_INSNS_EMB | PPC_CACHE_OPT | PPC_BOOKE | \ PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) -#define PPC_FLAGS_440 (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE) +#define PPC_FLAGS_440 (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE | \ + PPC_FLAGS_INPUT_BookE) /* Generic BookE PowerPC */ #define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \ PPC_FLOAT | PPC_FLOAT_OPT | PPC_CACHE_OPT) -#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE) +#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE | \ + PPC_FLAGS_INPUT_BookE) /* e500 core */ #define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \ PPC_CACHE_OPT | PPC_E500_VECTOR) -#define PPC_FLAGS_E500 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x) +#define PPC_FLAGS_E500 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x | \ + PPC_FLAGS_INPUT_BookE) /* Non-embedded PowerPC */ #define PPC_INSNS_COMMON (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \ - PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE) + PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE) /* PowerPC 601 */ #define PPC_INSNS_601 (PPC_INSNS_COMMON | PPC_EXTERN | PPC_POWER_BR) -#define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601) +#define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601 | \ + PPC_FLAGS_INPUT_6xx) /* PowerPC 602 */ #define PPC_INSNS_602 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ PPC_MEM_TLBSYNC | PPC_TB | PPC_602_SPEC) -#define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602) +#define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602 | \ + PPC_FLAGS_INPUT_6xx) /* PowerPC 603 */ #define PPC_INSNS_603 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB) -#define PPC_FLAGS_603 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603) +#define PPC_FLAGS_603 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603 | \ + PPC_FLAGS_INPUT_6xx) /* PowerPC G2 */ #define PPC_INSNS_G2 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB) -#define PPC_FLAGS_G2 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603) +#define PPC_FLAGS_G2 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603 | \ + PPC_FLAGS_INPUT_6xx) /* PowerPC 604 */ #define PPC_INSNS_604 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ PPC_MEM_TLBSYNC | PPC_TB) -#define PPC_FLAGS_604 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_604) +#define PPC_FLAGS_604 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_604 | \ + PPC_FLAGS_INPUT_6xx) /* PowerPC 740/750 (aka G3) */ #define PPC_INSNS_7x0 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ PPC_MEM_TLBSYNC | PPC_TB) -#define PPC_FLAGS_7x0 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_7x0) +#define PPC_FLAGS_7x0 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_7x0 | \ + PPC_FLAGS_INPUT_6xx) /* PowerPC 745/755 */ #define PPC_INSNS_7x5 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ PPC_MEM_TLBSYNC | PPC_TB | PPC_6xx_TLB) -#define PPC_FLAGS_7x5 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_7x5) +#define PPC_FLAGS_7x5 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_7x5 | \ + PPC_FLAGS_INPUT_6xx) /* PowerPC 74xx (aka G4) */ #define PPC_INSNS_74xx (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_ALTIVEC | \ PPC_MEM_TLBSYNC | PPC_TB) -#define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx) +#define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx | \ + PPC_FLAGS_INPUT_6xx) /* PowerPC 970 (aka G5) */ #define PPC_INSNS_970 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_FLOAT_OPT | \ PPC_ALTIVEC | PPC_MEM_TLBSYNC | PPC_TB | \ PPC_64B | PPC_64_BRIDGE | PPC_SLBI) -#define PPC_FLAGS_970 (PPC_FLAGS_MMU_64B | PPC_FLAGS_EXCP_970) +#define PPC_FLAGS_970 (PPC_FLAGS_MMU_64BRIDGE | PPC_FLAGS_EXCP_970 | \ + PPC_FLAGS_INPUT_970) /* Default PowerPC will be 604/970 */ #define PPC_INSNS_PPC32 PPC_INSNS_604 @@ -1347,6 +1370,17 @@ enum { PPC405_INPUT_DEBUG = 6, }; +enum { + /* PowerPC 970 input pins */ + PPC970_INPUT_HRESET = 0, + PPC970_INPUT_SRESET = 1, + PPC970_INPUT_CKSTP = 2, + PPC970_INPUT_TBEN = 3, + PPC970_INPUT_MCP = 4, + PPC970_INPUT_INT = 5, + PPC970_INPUT_THINT = 6, +}; + /* Hardware exceptions definitions */ enum { /* External hardware exception sources */ @@ -1356,12 +1390,13 @@ enum { PPC_INTERRUPT_SMI = 3, /* System management interrupt */ PPC_INTERRUPT_CEXT = 4, /* Critical external interrupt */ PPC_INTERRUPT_DEBUG = 5, /* External debug exception */ + PPC_INTERRUPT_THERM = 6, /* Thermal exception */ /* Internal hardware exception sources */ - PPC_INTERRUPT_DECR = 6, /* Decrementer exception */ - PPC_INTERRUPT_HDECR = 7, /* Hypervisor decrementer exception */ - PPC_INTERRUPT_PIT = 8, /* Programmable inteval timer interrupt */ - PPC_INTERRUPT_FIT = 9, /* Fixed interval timer interrupt */ - PPC_INTERRUPT_WDT = 10, /* Watchdog timer interrupt */ + PPC_INTERRUPT_DECR = 7, /* Decrementer exception */ + PPC_INTERRUPT_HDECR = 8, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT = 9, /* Programmable inteval timer interrupt */ + PPC_INTERRUPT_FIT = 10, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT = 11, /* Watchdog timer interrupt */ }; /*****************************************************************************/ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index aac790782..161cc1b14 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2003,6 +2003,13 @@ void ppc_hw_interrupt (CPUPPCState *env) env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); #endif raised = 1; +#if 0 // TODO + /* Thermal interrupt */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { + env->exception_index = EXCP_970_THRM; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); + raised = 1; +#endif } #if 0 // TODO /* External debug exception */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index c7a732454..018512328 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -48,6 +48,7 @@ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); #endif PPC_IRQ_INIT_FN(405); PPC_IRQ_INIT_FN(6xx); +PPC_IRQ_INIT_FN(970); /* Generic callbacks: * do nothing but store/retrieve spr value @@ -2350,6 +2351,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) case CPU_PPC_POWER5: /* Power 5 */ case CPU_PPC_POWER5P: /* Power 5+ */ #endif + break; + case CPU_PPC_970: /* PowerPC 970 */ case CPU_PPC_970FX10: /* PowerPC 970 FX */ case CPU_PPC_970FX20: @@ -2358,12 +2361,41 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) case CPU_PPC_970FX31: case CPU_PPC_970MP10: /* PowerPC 970 MP */ case CPU_PPC_970MP11: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* XXX: not correct */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_7xx(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Allocate hardware IRQ controller */ + ppc970_irq_init(env); + break; + #if defined (TODO) case CPU_PPC_CELL10: /* Cell family */ case CPU_PPC_CELL20: case CPU_PPC_CELL30: case CPU_PPC_CELL31: #endif + break; + #if defined (TODO) case CPU_PPC_RS64: /* Apache (RS64/A35) */ case CPU_PPC_RS64II: /* NorthStar (RS64-II/A50) */ -- cgit v1.2.3 From dd37a5e4d7ebc4e698f4c69ad2a5ee922824703f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 07:41:07 +0000 Subject: PREP and heathrow machines only support PowerPC CPU with a 6xx bus. Mac99 machine may also support PowerPC 970 CPU. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2681 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 52 ++++++++++++++++++++++++++++++++++++++++------------ hw/ppc_prep.c | 4 ++++ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 9a7538cad..8eef28982 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -409,14 +409,18 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, if (is_heathrow) { isa_mem_base = 0x80000000; - + /* Register 2 MB of ISA IO space */ isa_mmio_init(0xfe000000, 0x00200000); /* init basic PC hardware */ + if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { + cpu_abort(env, "Only 6xx bus is supported on heathrow machine\n"); + exit(1); + } pic = heathrow_pic_init(&heathrow_pic_mem_index); pci_bus = pci_grackle_init(0xfec00000, pic); - pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, + pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); @@ -468,16 +472,40 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* Mac99 IRQ connection between OpenPIC outputs pins * and PowerPC input pins */ - openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); - openpic_irqs[i][OPENPIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; - openpic_irqs[i][OPENPIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; - openpic_irqs[i][OPENPIC_OUTPUT_MCK] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP]; - openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; /* Not connected ? */ - openpic_irqs[i][OPENPIC_OUTPUT_RESET] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET]; /* Check this */ + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_6xx: + openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); + openpic_irqs[i][OPENPIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_MCK] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP]; + /* Not connected ? */ + openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; + /* Check this */ + openpic_irqs[i][OPENPIC_OUTPUT_RESET] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET]; + break; + case PPC_FLAGS_INPUT_970: + openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); + openpic_irqs[i][OPENPIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_MCK] = + ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP]; + /* Not connected ? */ + openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; + /* Check this */ + openpic_irqs[i][OPENPIC_OUTPUT_RESET] = + ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET]; + break; + default: + cpu_abort(env, + "Only bus model not supported on mac99 machine\n"); + exit(1); + } } pic = openpic_init(NULL, &openpic_mem_index, smp_cpus, openpic_irqs, NULL); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 421d18920..8fce9cc6c 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -598,6 +598,10 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, } isa_mem_base = 0xc0000000; + if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { + cpu_abort(env, "Only 6xx bus is supported on PREP machine\n"); + exit(1); + } i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]); pci_bus = pci_prep_init(i8259); // pci_bus = i440fx_init(); -- cgit v1.2.3 From 0a032cbec69c268272a118f19e64c16e73d56cc0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 08:56:52 +0000 Subject: Add reset callbacks for PowerPC CPU. Move cpu_ppc_init, cpu_ppc_close, cpu_ppc_reset and ppc_tlb_invalidate into helper.c as they are to be called from outside of the translated code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2682 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 1 + hw/ppc_prep.c | 5 +-- target-ppc/cpu.h | 4 +++ target-ppc/helper.c | 78 +++++++++++++++++++++++++++++++++++++++++++++ target-ppc/op_helper.c | 30 +---------------- target-ppc/translate_init.c | 33 ------------------- 6 files changed, 87 insertions(+), 64 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 8eef28982..456832824 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -317,6 +317,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* init CPUs */ env = cpu_init(); + qemu_register_reset(&cpu_ppc_reset, env); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); /* Default CPU is a generic 74x/75x */ diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 8fce9cc6c..2f10338b1 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -531,13 +531,14 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, sysctrl = qemu_mallocz(sizeof(sysctrl_t)); if (sysctrl == NULL) - return; + return; linux_boot = (kernel_filename != NULL); - + /* init CPUs */ env = cpu_init(); + qemu_register_reset(&cpu_ppc_reset, env); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); /* Default CPU is a 604 */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1e309f91d..5cd1b6008 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -860,6 +860,9 @@ void do_store_msr (CPUPPCState *env, target_ulong value); void ppc_store_msr_32 (CPUPPCState *env, uint32_t value); void do_compute_hflags (CPUPPCState *env); +void cpu_ppc_reset (void *opaque); +CPUPPCState *cpu_ppc_init (void); +void cpu_ppc_close(CPUPPCState *env); int ppc_find_by_name (const unsigned char *name, ppc_def_t **def); int ppc_find_by_pvr (uint32_t apvr, ppc_def_t **def); @@ -883,6 +886,7 @@ target_ulong load_40x_pit (CPUPPCState *env); void store_40x_pit (CPUPPCState *env, target_ulong val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); +void ppc_tlb_invalidate_all (CPUPPCState *env); #endif #endif diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 161cc1b14..5f46ae0fd 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -630,6 +630,25 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, return ret; } +void ppc4xx_tlb_invalidate_all (CPUState *env) +{ + ppcemb_tlb_t *tlb; + int i; + + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb[i].tlbe; + if (tlb->prot & PAGE_VALID) { +#if 0 // XXX: TLB have variable sizes then we flush all Qemu TLB. + end = tlb->EPN + tlb->size; + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) + tlb_flush_page(env, page); +#endif + tlb->prot &= ~PAGE_VALID; + } + } + tlb_flush(env, 1); +} + int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong address, int rw, int access_type) { @@ -1105,6 +1124,20 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) env->DBAT[1][nr] = value; } + +/*****************************************************************************/ +/* TLB management */ +void ppc_tlb_invalidate_all (CPUPPCState *env) +{ + if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + ppc6xx_tlb_invalidate_all(env); + } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + ppc4xx_tlb_invalidate_all(env); + } else { + tlb_flush(env, 1); + } +} + /*****************************************************************************/ /* Special registers manipulation */ #if defined(TARGET_PPC64) @@ -2039,3 +2072,48 @@ void cpu_dump_EA (target_ulong EA) fprintf(f, "Memory access at address " TARGET_FMT_lx "\n", EA); } +void cpu_ppc_reset (void *opaque) +{ + CPUPPCState *env; + + env = opaque; +#if defined (DO_SINGLE_STEP) && 0 + /* Single step trace mode */ + msr_se = 1; + msr_be = 1; +#endif + msr_fp = 1; /* Allow floating point exceptions */ + msr_me = 1; /* Allow machine check exceptions */ +#if defined(TARGET_PPC64) + msr_sf = 0; /* Boot in 32 bits mode */ + msr_cm = 0; +#endif +#if defined(CONFIG_USER_ONLY) + msr_pr = 1; + tlb_flush(env, 1); +#else + env->nip = 0xFFFFFFFC; + ppc_tlb_invalidate_all(env); +#endif + do_compute_hflags(env); + env->reserve = -1; +} + +CPUPPCState *cpu_ppc_init (void) +{ + CPUPPCState *env; + + env = qemu_mallocz(sizeof(CPUPPCState)); + if (!env) + return NULL; + cpu_exec_init(env); + cpu_ppc_reset(env); + + return env; +} + +void cpu_ppc_close (CPUPPCState *env) +{ + /* Should also remove all opcode tables... */ + free(env); +} diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 140b7f5cb..590b31e72 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2256,16 +2256,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) /* TLB invalidation helpers */ void do_tlbia (void) { - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { - ppc6xx_tlb_invalidate_all(env); - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { - /* XXX: TODO */ -#if 0 - ppcbooke_tlb_invalidate_all(env); -#endif - } else { - tlb_flush(env, 1); - } + ppc_tlb_invalidate_all(env); } void do_tlbie (void) @@ -2473,25 +2464,6 @@ static int booke_page_size_to_tlb (target_ulong page_size) } /* Helpers for 4xx TLB management */ -void do_4xx_tlbia (void) -{ - ppcemb_tlb_t *tlb; - int i; - - for (i = 0; i < 64; i++) { - tlb = &env->tlb[i].tlbe; - if (tlb->prot & PAGE_VALID) { -#if 0 - end = tlb->EPN + tlb->size; - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) - tlb_flush_page(env, page); -#endif - tlb->prot &= ~PAGE_VALID; - } - } - tlb_flush(env, 1); -} - void do_4xx_tlbre_lo (void) { ppcemb_tlb_t *tlb; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 018512328..ab8d8694a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2713,39 +2713,6 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) return 0; } -void do_compute_hflags (CPUPPCState *env); -CPUPPCState *cpu_ppc_init (void) -{ - CPUPPCState *env; - - env = qemu_mallocz(sizeof(CPUPPCState)); - if (!env) - return NULL; - cpu_exec_init(env); - tlb_flush(env, 1); -#if defined (DO_SINGLE_STEP) && 0 - /* Single step trace mode */ - msr_se = 1; - msr_be = 1; -#endif - msr_fp = 1; /* Allow floating point exceptions */ - msr_me = 1; /* Allow machine check exceptions */ -#if defined(CONFIG_USER_ONLY) - msr_pr = 1; -#else - env->nip = 0xFFFFFFFC; -#endif - do_compute_hflags(env); - env->reserve = -1; - return env; -} - -void cpu_ppc_close(CPUPPCState *env) -{ - /* Should also remove all opcode tables... */ - free(env); -} - /*****************************************************************************/ /* PowerPC CPU definitions */ static ppc_def_t ppc_defs[] = -- cgit v1.2.3 From c55e9aefa7c151176e2e88c0f79044580930a970 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 09:21:46 +0000 Subject: PowerPC 4xx software driven TLB fixes + debug traces. Add code provision for more MMU models support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2683 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 12 ++--- target-ppc/helper.c | 138 +++++++++++++++++++++++++++++++++++++++---------- target-ppc/op_helper.c | 52 +++++++++++++++++-- 3 files changed, 163 insertions(+), 39 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 5cd1b6008..eb3340c52 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -581,12 +581,12 @@ struct ppc6xx_tlb_t { typedef struct ppcemb_tlb_t ppcemb_tlb_t; struct ppcemb_tlb_t { - target_ulong RPN; + target_phys_addr_t RPN; target_ulong EPN; target_ulong PID; - int size; - int prot; - int attr; /* Storage attributes */ + target_ulong size; + uint32_t prot; + uint32_t attr; /* Storage attributes */ }; union ppc_tlb_t { @@ -765,10 +765,6 @@ struct CPUPPCState { int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ int nb_pids; /* Number of available PID registers */ ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ - /* Callbacks for specific checks on some implementations */ - int (*tlb_check_more)(CPUPPCState *env, ppc_tlb_t *tlb, int *prot, - target_ulong vaddr, int rw, int acc_type, - int is_user); /* 403 dedicated access protection registers */ target_ulong pb[4]; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 5f46ae0fd..2fc5ecd12 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -657,7 +657,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong mask; int i, ret, zsel, zpr; - ret = -6; + ret = -1; + raddr = -1; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; /* Check valid flag */ @@ -691,8 +692,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, switch (zpr) { case 0x0: if (msr_pr) { - ret = -3; ctx->prot = 0; + ret = -3; break; } /* No break here */ @@ -702,25 +703,26 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, if (!(tlb->prot & PAGE_EXEC)) { ret = -3; } else { - if (tlb->prot & PAGE_WRITE) + if (tlb->prot & PAGE_WRITE) { ctx->prot = PAGE_READ | PAGE_WRITE; - else + } else { ctx->prot = PAGE_READ; + } ret = 0; } break; case 0x3: /* All accesses granted */ - ret = 0; ctx->prot = PAGE_READ | PAGE_WRITE; + ret = 0; break; } } else { switch (zpr) { case 0x0: if (msr_pr) { - ret = -2; ctx->prot = 0; + ret = -2; break; } /* No break here */ @@ -728,20 +730,21 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, case 0x2: /* Check from TLB entry */ /* Check write protection bit */ - if (rw && !(tlb->prot & PAGE_WRITE)) { - ret = -2; + if (tlb->prot & PAGE_WRITE) { + ctx->prot = PAGE_READ | PAGE_WRITE; + ret = 0; } else { - ret = 2; - if (tlb->prot & PAGE_WRITE) - ctx->prot = PAGE_READ | PAGE_WRITE; + ctx->prot = PAGE_READ; + if (rw) + ret = -2; else - ctx->prot = PAGE_READ; + ret = 0; } break; case 0x3: /* All accesses granted */ - ret = 2; ctx->prot = PAGE_READ | PAGE_WRITE; + ret = 0; break; } } @@ -749,11 +752,17 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ctx->raddr = raddr; if (loglevel) { fprintf(logfile, "%s: access granted " ADDRX " => " REGX - " %d\n", __func__, address, ctx->raddr, ctx->prot); + " %d %d\n", __func__, address, ctx->raddr, ctx->prot, + ret); } - return i; + return 0; } } + if (loglevel) { + fprintf(logfile, "%s: access refused " ADDRX " => " REGX + " %d %d\n", __func__, address, raddr, ctx->prot, + ret); + } return ret; } @@ -808,32 +817,49 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, /* No address translation */ ret = check_physical(env, ctx, eaddr, rw); } else { + ret = -1; switch (PPC_MMU(env)) { case PPC_FLAGS_MMU_32B: case PPC_FLAGS_MMU_SOFT_6xx: /* Try to find a BAT */ - ret = -1; if (check_BATs) ret = get_bat(env, ctx, eaddr, rw, access_type); + /* No break here */ +#if defined(TARGET_PPC64) + case PPC_FLAGS_MMU_64B: + case PPC_FLAGS_MMU_64BRIDGE: +#endif if (ret < 0) { - /* We didn't match any BAT entry */ + /* We didn't match any BAT entry or don't have BATs */ ret = get_segment(env, ctx, eaddr, rw, access_type); } break; case PPC_FLAGS_MMU_SOFT_4xx: + case PPC_FLAGS_MMU_403: ret = mmu4xx_get_physical_address(env, ctx, eaddr, rw, access_type); break; - default: + case PPC_FLAGS_MMU_601: + /* XXX: TODO */ + cpu_abort(env, "601 MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookeE MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "BookE FSL MMU model not implemented\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); return -1; } } #if 0 if (loglevel > 0) { - fprintf(logfile, "%s address " ADDRX " => " ADDRX "\n", - __func__, eaddr, ctx->raddr); + fprintf(logfile, "%s address " ADDRX " => %d " ADDRX "\n", + __func__, eaddr, ret, ctx->raddr); } #endif @@ -885,19 +911,48 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, switch (ret) { case -1: /* No matches in page tables or TLB */ - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + switch (PPC_MMU(env)) { + case PPC_FLAGS_MMU_SOFT_6xx: exception = EXCP_I_TLBMISS; env->spr[SPR_IMISS] = address; env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; error_code = 1 << 18; goto tlb_miss; - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + case PPC_FLAGS_MMU_SOFT_4xx: + case PPC_FLAGS_MMU_403: exception = EXCP_40x_ITLBMISS; error_code = 0; env->spr[SPR_40x_DEAR] = address; env->spr[SPR_40x_ESR] = 0x00000000; - } else { + break; + case PPC_FLAGS_MMU_32B: error_code = 0x40000000; + break; +#if defined(TARGET_PPC64) + case PPC_FLAGS_MMU_64B: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_64BRIDGE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; +#endif + case PPC_FLAGS_MMU_601: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; } break; case -2: @@ -924,7 +979,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, switch (ret) { case -1: /* No matches in page tables or TLB */ - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + switch (PPC_MMU(env)) { + case PPC_FLAGS_MMU_SOFT_6xx: if (rw == 1) { exception = EXCP_DS_TLBMISS; error_code = 1 << 16; @@ -940,7 +996,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_HASH2] = ctx.pg_addr[1]; /* Do not alter DAR nor DSISR */ goto out; - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + case PPC_FLAGS_MMU_SOFT_4xx: + case PPC_FLAGS_MMU_403: exception = EXCP_40x_DTLBMISS; error_code = 0; env->spr[SPR_40x_DEAR] = address; @@ -948,8 +1005,35 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_40x_ESR] = 0x00800000; else env->spr[SPR_40x_ESR] = 0x00000000; - } else { + break; + case PPC_FLAGS_MMU_32B: error_code = 0x40000000; + break; +#if defined(TARGET_PPC64) + case PPC_FLAGS_MMU_64B: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_64BRIDGE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; +#endif + case PPC_FLAGS_MMU_601: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + case PPC_FLAGS_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + return -1; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; } break; case -2: diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 590b31e72..e994486cf 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2537,39 +2537,72 @@ void do_4xx_tlbsx_ (void) env->crf[0] = tmp; } -void do_4xx_tlbwe_lo (void) +void do_4xx_tlbwe_hi (void) { ppcemb_tlb_t *tlb; target_ulong page, end; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + } +#endif T0 &= 0x3F; tlb = &env->tlb[T0].tlbe; /* Invalidate previous TLB (if it's valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX + " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end); + } +#endif for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); } tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); - if (T1 & 0x400) + if (T1 & 0x40) tlb->prot |= PAGE_VALID; else tlb->prot &= ~PAGE_VALID; - tlb->PID = env->spr[SPR_BOOKE_PID]; /* PID */ + tlb->PID = env->spr[SPR_40x_PID]; /* PID */ tlb->attr = T1 & 0xFF; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX + " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, + (int)T0, tlb->RPN, tlb->EPN, tlb->size, + tlb->prot & PAGE_READ ? 'r' : '-', + tlb->prot & PAGE_WRITE ? 'w' : '-', + tlb->prot & PAGE_EXEC ? 'x' : '-', + tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); + } +#endif /* Invalidate new TLB (if valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s: invalidate TLB %d start " ADDRX + " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end); + } +#endif for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); } } -void do_4xx_tlbwe_hi (void) +void do_4xx_tlbwe_lo (void) { ppcemb_tlb_t *tlb; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + } +#endif T0 &= 0x3F; tlb = &env->tlb[T0].tlbe; tlb->RPN = T1 & 0xFFFFFC00; @@ -2578,5 +2611,16 @@ void do_4xx_tlbwe_hi (void) tlb->prot |= PAGE_EXEC; if (T1 & 0x100) tlb->prot |= PAGE_WRITE; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel) { + fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX + " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, + (int)T0, tlb->RPN, tlb->EPN, tlb->size, + tlb->prot & PAGE_READ ? 'r' : '-', + tlb->prot & PAGE_WRITE ? 'w' : '-', + tlb->prot & PAGE_EXEC ? 'x' : '-', + tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); + } +#endif } #endif /* !CONFIG_USER_ONLY */ -- cgit v1.2.3 From 3a6078548d3abf01ea24df75eae794d078194481 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 09:31:49 +0000 Subject: Cleanup and add more PowerPC core definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2684 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 2236 ++++++++++++++++++++++--------------------- 1 file changed, 1120 insertions(+), 1116 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ab8d8694a..215bdcbe6 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1875,7 +1875,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) def->pvr); printf("%s: PVR %08x mask %08x => %08x\n", __func__, def->pvr, def->pvr_mask, def->pvr & def->pvr_mask); - switch (def->pvr & def->pvr_mask) { + switch (def->pvr) { /* Embedded PowerPC from IBM */ case CPU_PPC_401A1: /* 401 A1 family */ case CPU_PPC_401B2: /* 401 B2 family */ @@ -2715,1174 +2715,1178 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) /*****************************************************************************/ /* PowerPC CPU definitions */ -static ppc_def_t ppc_defs[] = - { - /* Embedded PowerPC */ -#if defined (TODO) - /* PowerPC 401 */ - { - .name = "401", - .pvr = CPU_PPC_401, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* IOP480 (401 microcontroler) */ - { - .name = "iop480", - .pvr = CPU_PPC_IOP480, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* IBM Processor for Network Resources */ - { - .name = "Cobra", - .pvr = CPU_PPC_COBRA, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* Generic PowerPC 403 */ - { - .name = "403", - .pvr = CPU_PPC_403, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, -#endif -#if defined (TODO) - /* PowerPC 403 GA */ - { - .name = "403ga", - .pvr = CPU_PPC_403GA, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, -#endif -#if defined (TODO) - /* PowerPC 403 GB */ - { - .name = "403gb", - .pvr = CPU_PPC_403GB, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, -#endif -#if defined (TODO) - /* PowerPC 403 GC */ - { - .name = "403gc", - .pvr = CPU_PPC_403GC, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, -#endif -#if defined (TODO) - /* PowerPC 403 GCX */ - { - .name = "403gcx", - .pvr = CPU_PPC_403GCX, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, -#endif -#if defined (TODO) - /* Generic PowerPC 405 */ - { - .name = "405", - .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, +static ppc_def_t ppc_defs[] = { + /* Embedded PowerPC */ +#if defined (TODO) + /* PowerPC 401 */ + { + .name = "401", + .pvr = CPU_PPC_401, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* PowerPC 405 CR */ - { - .name = "405cr", - .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* IOP480 (401 microcontroler) */ + { + .name = "iop480", + .pvr = CPU_PPC_IOP480, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* PowerPC 405 GP */ - { - .name = "405gp", - .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* IBM Processor for Network Resources */ + { + .name = "Cobra", + .pvr = CPU_PPC_COBRA, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* PowerPC 405 EP */ - { - .name = "405ep", - .pvr = CPU_PPC_405EP, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* Generic PowerPC 403 */ + { + .name = "403", + .pvr = CPU_PPC_403, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PowerPC 405 GPR */ - { - .name = "405gpr", - .pvr = CPU_PPC_405GPR, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 403 GA */ + { + .name = "403ga", + .pvr = CPU_PPC_403GA, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PowerPC 405 D2 */ - { - .name = "405d2", - .pvr = CPU_PPC_405D2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 403 GB */ + { + .name = "403gb", + .pvr = CPU_PPC_403GB, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PowerPC 405 D4 */ - { - .name = "405d4", - .pvr = CPU_PPC_405D4, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 403 GC */ + { + .name = "403gc", + .pvr = CPU_PPC_403GC, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* Npe405 H */ - { - .name = "Npe405H", - .pvr = CPU_PPC_NPE405H, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 403 GCX */ + { + .name = "403gcx", + .pvr = CPU_PPC_403GCX, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, +#endif + /* Generic PowerPC 405 */ + { + .name = "405", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + /* PowerPC 405 CR */ + { + .name = "405cr", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#if defined (TODO) + /* PowerPC 405 GP */ + { + .name = "405gp", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif + /* PowerPC 405 EP */ + { + .name = "405ep", + .pvr = CPU_PPC_405EP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#if defined (TODO) + /* PowerPC 405 EZ */ + { + .name = "405ez", + .pvr = CPU_PPC_405EZ, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* Npe405 L */ - { - .name = "Npe405L", - .pvr = CPU_PPC_NPE405L, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 GPR */ + { + .name = "405gpr", + .pvr = CPU_PPC_405GPR, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB010000 */ - { - .name = "STB01000", - .pvr = CPU_PPC_STB01000, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 D2 */ + { + .name = "405d2", + .pvr = CPU_PPC_405D2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB01010 */ - { - .name = "STB01010", - .pvr = CPU_PPC_STB01010, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 D4 */ + { + .name = "405d4", + .pvr = CPU_PPC_405D4, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB0210 */ - { - .name = "STB0210", - .pvr = CPU_PPC_STB0210, - .pvr_mask = 0xFFFF0000, + /* Npe405 H */ + { + .name = "Npe405H", + .pvr = CPU_PPC_NPE405H, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB03xx */ - { - .name = "STB03", - .pvr = CPU_PPC_STB03, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* Npe405 L */ + { + .name = "Npe405L", + .pvr = CPU_PPC_NPE405L, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB043x */ - { - .name = "STB043", - .pvr = CPU_PPC_STB043, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* STB010000 */ + { + .name = "STB01000", + .pvr = CPU_PPC_STB01000, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB045x */ - { - .name = "STB045", - .pvr = CPU_PPC_STB045, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* STB01010 */ + { + .name = "STB01010", + .pvr = CPU_PPC_STB01010, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB25xx */ - { - .name = "STB25", - .pvr = CPU_PPC_STB25, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* STB0210 */ + { + .name = "STB0210", + .pvr = CPU_PPC_STB0210, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) || 1 + /* STB03xx */ + { + .name = "STB03", + .pvr = CPU_PPC_STB03, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB130 */ - { - .name = "STB130", - .pvr = CPU_PPC_STB130, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* STB043x */ + { + .name = "STB043", + .pvr = CPU_PPC_STB043, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* STB045x */ + { + .name = "STB045", + .pvr = CPU_PPC_STB045, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) || 1 + /* STB25xx */ + { + .name = "STB25", + .pvr = CPU_PPC_STB25, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, +#endif +#if defined (TODO) + /* STB130 */ + { + .name = "STB130", + .pvr = CPU_PPC_STB130, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif /* Xilinx PowerPC 405 cores */ #if defined (TODO) - { - .name = "x2vp4", - .pvr = CPU_PPC_X2VP4, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, - { - .name = "x2vp7", - .pvr = CPU_PPC_X2VP7, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, - { - .name = "x2vp20", - .pvr = CPU_PPC_X2VP20, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, - { - .name = "x2vp50", - .pvr = CPU_PPC_X2VP50, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, -#endif -#if defined (TODO) - /* PowerPC 440 EP */ - { - .name = "440ep", - .pvr = CPU_PPC_440EP, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, -#endif -#if defined (TODO) - /* PowerPC 440 GR */ - { - .name = "440gr", - .pvr = CPU_PPC_440GR, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, -#endif -#if defined (TODO) - /* PowerPC 440 GP */ - { - .name = "440gp", - .pvr = CPU_PPC_440GP, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, -#endif -#if defined (TODO) - /* PowerPC 440 GX */ - { - .name = "440gx", - .pvr = CPU_PPC_440GX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + { + .name = "x2vp4", + .pvr = CPU_PPC_X2VP4, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp7", + .pvr = CPU_PPC_X2VP7, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp20", + .pvr = CPU_PPC_X2VP20, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp50", + .pvr = CPU_PPC_X2VP50, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PowerPC 440 GXc */ - { - .name = "440gxc", - .pvr = CPU_PPC_440GXC, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* PowerPC 440 EP */ + { + .name = "440ep", + .pvr = CPU_PPC_440EP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PowerPC 440 GXf */ - { - .name = "440gxf", - .pvr = CPU_PPC_440GXF, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* PowerPC 440 GR */ + { + .name = "440gr", + .pvr = CPU_PPC_440GR, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PowerPC 440 SP */ - { - .name = "440sp", - .pvr = CPU_PPC_440SP, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* PowerPC 440 GP */ + { + .name = "440gp", + .pvr = CPU_PPC_440GP, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PowerPC 440 SP2 */ - { - .name = "440sp2", - .pvr = CPU_PPC_440SP2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* PowerPC 440 GX */ + { + .name = "440gx", + .pvr = CPU_PPC_440GX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PowerPC 440 SPE */ - { - .name = "440spe", - .pvr = CPU_PPC_440SPE, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, -#endif - /* Fake generic BookE PowerPC */ - { - .name = "BookE", - .pvr = CPU_PPC_e500, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_BOOKE, - .flags = PPC_FLAGS_BOOKE, - .msr_mask = 0x000000000006D630, - }, - /* PowerPC 460 cores - TODO */ - /* PowerPC MPC 5xx cores - TODO */ - /* PowerPC MPC 8xx cores - TODO */ - /* PowerPC MPC 8xxx cores - TODO */ - /* e200 cores - TODO */ - /* e500 cores - TODO */ - /* e600 cores - TODO */ - - /* 32 bits "classic" PowerPC */ -#if defined (TODO) - /* PowerPC 601 */ - { - .name = "601", - .pvr = CPU_PPC_601, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_601, - .flags = PPC_FLAGS_601, - .msr_mask = 0x000000000000FD70, - }, -#endif -#if defined (TODO) - /* PowerPC 602 */ - { - .name = "602", - .pvr = CPU_PPC_602, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_602, - .flags = PPC_FLAGS_602, - .msr_mask = 0x0000000000C7FF73, - }, -#endif - /* PowerPC 603 */ - { - .name = "603", - .pvr = CPU_PPC_603, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - /* PowerPC 603e */ - { - .name = "603e", - .pvr = CPU_PPC_603E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - { - .name = "Stretch", - .pvr = CPU_PPC_603E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - /* PowerPC 603p */ - { - .name = "603p", - .pvr = CPU_PPC_603P, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - /* PowerPC 603e7 */ - { - .name = "603e7", - .pvr = CPU_PPC_603E7, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - /* PowerPC 603e7v */ - { - .name = "603e7v", - .pvr = CPU_PPC_603E7v, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - /* PowerPC 603e7v2 */ - { - .name = "603e7v2", - .pvr = CPU_PPC_603E7v2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - /* PowerPC 603r */ - { - .name = "603r", - .pvr = CPU_PPC_603R, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - { - .name = "Goldeneye", - .pvr = CPU_PPC_603R, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, -#if defined (TODO) - /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ - { - .name = "G2", - .pvr = CPU_PPC_G2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, - }, - { - .name = "G2h4", - .pvr = CPU_PPC_G2H4, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, - }, - { - .name = "G2gp", - .pvr = CPU_PPC_G2gp, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, - }, - { - .name = "G2ls", - .pvr = CPU_PPC_G2ls, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, - }, - { /* Same as G2, with LE mode support */ - .name = "G2le", - .pvr = CPU_PPC_G2LE, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3, - }, - { - .name = "G2legp", - .pvr = CPU_PPC_G2LEgp, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3, - }, - { - .name = "G2lels", - .pvr = CPU_PPC_G2LEls, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3, - }, -#endif - /* PowerPC 604 */ - { - .name = "604", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* PowerPC 604e */ - { - .name = "604e", - .pvr = CPU_PPC_604E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* PowerPC 604r */ - { - .name = "604r", - .pvr = CPU_PPC_604R, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* generic G3 */ - { - .name = "G3", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - /* MPC740 (G3) */ - { - .name = "740", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Arthur", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC745 (G3) */ - { - .name = "745", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Goldfinger", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* MPC750 (G3) */ - { - .name = "750", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC755 (G3) */ - { - .name = "755", - .pvr = CPU_PPC_755, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* MPC740P (G3) */ - { - .name = "740p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Conan/Doyle", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC745P (G3) */ - { - .name = "745p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* MPC750P (G3) */ - { - .name = "750p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC755P (G3) */ - { - .name = "755p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* IBM 750CXe (G3 embedded) */ - { - .name = "750cxe", - .pvr = CPU_PPC_750CXE, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - /* IBM 750FX (G3 embedded) */ - { - .name = "750fx", - .pvr = CPU_PPC_750FX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - /* IBM 750GX (G3 embedded) */ - { - .name = "750gx", - .pvr = CPU_PPC_750GX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* generic G4 */ - { - .name = "G4", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif -#if defined (TODO) - /* PowerPC 7400 (G4) */ - { - .name = "7400", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Max", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif -#if defined (TODO) - /* PowerPC 7410 (G4) */ - { - .name = "7410", - .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Nitro", - .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif - /* XXX: 7441 */ - /* XXX: 7445 */ - /* XXX: 7447 */ - /* XXX: 7447A */ -#if defined (TODO) - /* PowerPC 7450 (G4) */ - { - .name = "7450", - .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Vger", - .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif - /* XXX: 7451 */ -#if defined (TODO) - /* PowerPC 7455 (G4) */ - { - .name = "7455", - .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 6", - .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif -#if defined (TODO) - /* PowerPC 7457 (G4) */ - { - .name = "7457", - .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 7", - .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif -#if defined (TODO) - /* PowerPC 7457A (G4) */ - { - .name = "7457A", - .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 7 PM", - .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif - /* 64 bits PowerPC */ + /* PowerPC 440 GXc */ + { + .name = "440gxc", + .pvr = CPU_PPC_440GXC, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, +#endif +#if defined (TODO) + /* PowerPC 440 GXf */ + { + .name = "440gxf", + .pvr = CPU_PPC_440GXF, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, +#endif +#if defined (TODO) + /* PowerPC 440 SP */ + { + .name = "440sp", + .pvr = CPU_PPC_440SP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, +#endif +#if defined (TODO) + /* PowerPC 440 SP2 */ + { + .name = "440sp2", + .pvr = CPU_PPC_440SP2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, +#endif +#if defined (TODO) + /* PowerPC 440 SPE */ + { + .name = "440spe", + .pvr = CPU_PPC_440SPE, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, +#endif + /* Fake generic BookE PowerPC */ + { + .name = "BookE", + .pvr = CPU_PPC_e500, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_BOOKE, + .flags = PPC_FLAGS_BOOKE, + .msr_mask = 0x000000000006D630, + }, + /* PowerPC 460 cores - TODO */ + /* PowerPC MPC 5xx cores - TODO */ + /* PowerPC MPC 8xx cores - TODO */ + /* PowerPC MPC 8xxx cores - TODO */ + /* e200 cores - TODO */ + /* e500 cores - TODO */ + /* e600 cores - TODO */ + + /* 32 bits "classic" PowerPC */ +#if defined (TODO) + /* PowerPC 601 */ + { + .name = "601", + .pvr = CPU_PPC_601, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_601, + .flags = PPC_FLAGS_601, + .msr_mask = 0x000000000000FD70, + }, +#endif +#if defined (TODO) + /* PowerPC 602 */ + { + .name = "602", + .pvr = CPU_PPC_602, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_602, + .flags = PPC_FLAGS_602, + .msr_mask = 0x0000000000C7FF73, + }, +#endif + /* PowerPC 603 */ + { + .name = "603", + .pvr = CPU_PPC_603, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e */ + { + .name = "603e", + .pvr = CPU_PPC_603E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + { + .name = "Stretch", + .pvr = CPU_PPC_603E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603p */ + { + .name = "603p", + .pvr = CPU_PPC_603P, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7 */ + { + .name = "603e7", + .pvr = CPU_PPC_603E7, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7v */ + { + .name = "603e7v", + .pvr = CPU_PPC_603E7v, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7v2 */ + { + .name = "603e7v2", + .pvr = CPU_PPC_603E7v2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603r */ + { + .name = "603r", + .pvr = CPU_PPC_603R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + { + .name = "Goldeneye", + .pvr = CPU_PPC_603R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, +#if defined (TODO) + /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ + { + .name = "G2", + .pvr = CPU_PPC_G2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2h4", + .pvr = CPU_PPC_G2H4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2gp", + .pvr = CPU_PPC_G2gp, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2ls", + .pvr = CPU_PPC_G2ls, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { /* Same as G2, with LE mode support */ + .name = "G2le", + .pvr = CPU_PPC_G2LE, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, + { + .name = "G2legp", + .pvr = CPU_PPC_G2LEgp, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, + { + .name = "G2lels", + .pvr = CPU_PPC_G2LEls, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, +#endif + /* PowerPC 604 */ + { + .name = "604", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* PowerPC 604e */ + { + .name = "604e", + .pvr = CPU_PPC_604E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* PowerPC 604r */ + { + .name = "604r", + .pvr = CPU_PPC_604R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* generic G3 */ + { + .name = "G3", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* MPC740 (G3) */ + { + .name = "740", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Arthur", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* MPC745 (G3) */ + { + .name = "745", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Goldfinger", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, +#endif + /* MPC750 (G3) */ + { + .name = "750", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* MPC755 (G3) */ + { + .name = "755", + .pvr = CPU_PPC_755, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, +#endif + /* MPC740P (G3) */ + { + .name = "740p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Conan/Doyle", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* MPC745P (G3) */ + { + .name = "745p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, +#endif + /* MPC750P (G3) */ + { + .name = "750p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* MPC755P (G3) */ + { + .name = "755p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, +#endif + /* IBM 750CXe (G3 embedded) */ + { + .name = "750cxe", + .pvr = CPU_PPC_750CXE, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* IBM 750FX (G3 embedded) */ + { + .name = "750fx", + .pvr = CPU_PPC_750FX, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* IBM 750GX (G3 embedded) */ + { + .name = "750gx", + .pvr = CPU_PPC_750GX, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, +#if defined (TODO) + /* generic G4 */ + { + .name = "G4", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif +#if defined (TODO) + /* PowerPC 7400 (G4) */ + { + .name = "7400", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Max", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif +#if defined (TODO) + /* PowerPC 7410 (G4) */ + { + .name = "7410", + .pvr = CPU_PPC_7410, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Nitro", + .pvr = CPU_PPC_7410, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif + /* XXX: 7441 */ + /* XXX: 7445 */ + /* XXX: 7447 */ + /* XXX: 7447A */ +#if defined (TODO) + /* PowerPC 7450 (G4) */ + { + .name = "7450", + .pvr = CPU_PPC_7450, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Vger", + .pvr = CPU_PPC_7450, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif + /* XXX: 7451 */ +#if defined (TODO) + /* PowerPC 7455 (G4) */ + { + .name = "7455", + .pvr = CPU_PPC_7455, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 6", + .pvr = CPU_PPC_7455, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif +#if defined (TODO) + /* PowerPC 7457 (G4) */ + { + .name = "7457", + .pvr = CPU_PPC_7457, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 7", + .pvr = CPU_PPC_7457, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif +#if defined (TODO) + /* PowerPC 7457A (G4) */ + { + .name = "7457A", + .pvr = CPU_PPC_7457A, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 7 PM", + .pvr = CPU_PPC_7457A, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, +#endif + /* 64 bits PowerPC */ #if defined (TARGET_PPC64) #if defined (TODO) - /* PowerPC 620 */ - { - .name = "620", - .pvr = CPU_PPC_620, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_620, - .flags = PPC_FLAGS_620, - .msr_mask = 0x800000000005FF73, - }, -#endif -#if defined (TODO) - /* PowerPC 630 (POWER3) */ - { - .name = "630", - .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_630, - .flags = PPC_FLAGS_630, - .msr_mask = xxx, - } - { - .name = "POWER3", - .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_630, - .flags = PPC_FLAGS_630, - .msr_mask = xxx, - } + /* PowerPC 620 */ + { + .name = "620", + .pvr = CPU_PPC_620, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_620, + .flags = PPC_FLAGS_620, + .msr_mask = 0x800000000005FF73, + }, #endif #if defined (TODO) - /* PowerPC 631 (Power 3+)*/ - { - .name = "631", - .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_631, - .flags = PPC_FLAGS_631, - .msr_mask = xxx, - }, - { - .name = "POWER3+", - .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_631, - .flags = PPC_FLAGS_631, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER4 */ - { - .name = "POWER4", - .pvr = CPU_PPC_POWER4, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER4, - .flags = PPC_FLAGS_POWER4, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER4p */ - { - .name = "POWER4+", - .pvr = CPU_PPC_POWER4P, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER4, - .flags = PPC_FLAGS_POWER4, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER5 */ - { - .name = "POWER5", - .pvr = CPU_PPC_POWER5, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER5, - .flags = PPC_FLAGS_POWER5, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER5+ */ - { - .name = "POWER5+", - .pvr = CPU_PPC_POWER5P, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER5, - .flags = PPC_FLAGS_POWER5, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* PowerPC 970 */ - { - .name = "970", - .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_970, - .flags = PPC_FLAGS_970, - .msr_mask = 0x900000000204FF36, - }, -#endif -#if defined (TODO) - /* PowerPC 970FX (G5) */ - { - .name = "970fx", - .pvr = CPU_PPC_970FX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_970FX, - .flags = PPC_FLAGS_970FX, - .msr_mask = 0x800000000204FF36, - }, -#endif -#if defined (TODO) - /* RS64 (Apache/A35) */ - /* This one seems to support the whole POWER2 instruction set - * and the PowerPC 64 one. - */ - { - .name = "RS64", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "Apache", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "A35", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* RS64-II (NorthStar/A50) */ - { - .name = "RS64-II", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "NortStar", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "A50", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* RS64-III (Pulsar) */ - { - .name = "RS64-III", - .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "Pulsar", - .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* RS64-IV (IceStar/IStar/SStar) */ - { - .name = "RS64-IV", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "IceStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "IStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "SStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, -#endif - /* POWER */ -#if defined (TODO) - /* Original POWER */ - { - .name = "POWER", - .pvr = CPU_POWER, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER, - .flags = PPC_FLAGS_POWER, - .msr_mask = xxx, - }, + /* PowerPC 630 (POWER3) */ + { + .name = "630", + .pvr = CPU_PPC_630, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_630, + .flags = PPC_FLAGS_630, + .msr_mask = xxx, + } + { + .name = "POWER3", + .pvr = CPU_PPC_630, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_630, + .flags = PPC_FLAGS_630, + .msr_mask = xxx, + } +#endif +#if defined (TODO) + /* PowerPC 631 (Power 3+)*/ + { + .name = "631", + .pvr = CPU_PPC_631, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_631, + .flags = PPC_FLAGS_631, + .msr_mask = xxx, + }, + { + .name = "POWER3+", + .pvr = CPU_PPC_631, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_631, + .flags = PPC_FLAGS_631, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER4 */ + { + .name = "POWER4", + .pvr = CPU_PPC_POWER4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER4, + .flags = PPC_FLAGS_POWER4, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER4p */ + { + .name = "POWER4+", + .pvr = CPU_PPC_POWER4P, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER4, + .flags = PPC_FLAGS_POWER4, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER5 */ + { + .name = "POWER5", + .pvr = CPU_PPC_POWER5, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER5, + .flags = PPC_FLAGS_POWER5, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER5+ */ + { + .name = "POWER5+", + .pvr = CPU_PPC_POWER5P, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER5, + .flags = PPC_FLAGS_POWER5, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) || 1 + /* PowerPC 970 */ + { + .name = "970", + .pvr = CPU_PPC_970, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_970, + .flags = PPC_FLAGS_970, + .msr_mask = 0x900000000204FF36, + }, +#endif +#if defined (TODO) + /* PowerPC 970FX (G5) */ + { + .name = "970fx", + .pvr = CPU_PPC_970FX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_970FX, + .flags = PPC_FLAGS_970FX, + .msr_mask = 0x800000000204FF36, + }, +#endif +#if defined (TODO) + /* RS64 (Apache/A35) */ + /* This one seems to support the whole POWER2 instruction set + * and the PowerPC 64 one. + */ + { + .name = "RS64", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "Apache", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "A35", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-II (NorthStar/A50) */ + { + .name = "RS64-II", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "NortStar", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "A50", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-III (Pulsar) */ + { + .name = "RS64-III", + .pvr = CPU_PPC_RS64III, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "Pulsar", + .pvr = CPU_PPC_RS64III, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-IV (IceStar/IStar/SStar) */ + { + .name = "RS64-IV", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "IceStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "IStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "SStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif + /* POWER */ +#if defined (TODO) + /* Original POWER */ + { + .name = "POWER", + .pvr = CPU_POWER, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER, + .flags = PPC_FLAGS_POWER, + .msr_mask = xxx, + }, #endif #endif /* defined (TARGET_PPC64) */ #if defined (TODO) - /* POWER2 */ - { - .name = "POWER2", - .pvr = CPU_POWER2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER, - .flags = PPC_FLAGS_POWER, - .msr_mask = xxx, - }, -#endif - /* Generic PowerPCs */ -#if defined (TODO) - { - .name = "ppc64", - .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_PPC64, - .flags = PPC_FLAGS_PPC64, - .msr_mask = 0xA00000000204FF36, - }, -#endif - { - .name = "ppc32", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_PPC32, - .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77, - }, - /* Fallback */ - { - .name = "ppc", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_PPC32, - .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77, - }, - }; + /* POWER2 */ + { + .name = "POWER2", + .pvr = CPU_POWER2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER, + .flags = PPC_FLAGS_POWER, + .msr_mask = xxx, + }, +#endif + /* Generic PowerPCs */ +#if defined (TODO) || 1 + { + .name = "ppc64", + .pvr = CPU_PPC_970, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_PPC64, + .flags = PPC_FLAGS_PPC64, + .msr_mask = 0xA00000000204FF36, + }, +#endif + { + .name = "ppc32", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_PPC32, + .flags = PPC_FLAGS_PPC32, + .msr_mask = 0x000000000005FF77, + }, + /* Fallback */ + { + .name = "ppc", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_PPC32, + .flags = PPC_FLAGS_PPC32, + .msr_mask = 0x000000000005FF77, + }, +}; int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) { -- cgit v1.2.3 From b92bb99b80166f76fae32e166b3deaa22fec8687 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 16 Apr 2007 17:20:48 +0000 Subject: Memory-mapped interface for PS/2 controller, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2685 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- vl.h | 3 ++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index a6f9d09ca..52b65d7d9 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -124,6 +124,7 @@ typedef struct KBDState { qemu_irq irq_kbd; qemu_irq irq_mouse; + target_phys_addr_t base; } KBDState; KBDState kbd_state; @@ -140,7 +141,7 @@ static void kbd_update_irq(KBDState *s) s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); if (s->pending) { s->status |= KBD_STAT_OBF; - /* kdb data takes priority over aux data. */ + /* kbd data takes priority over aux data. */ if (s->pending == KBD_PENDING_AUX) { s->status |= KBD_STAT_MOUSE_OBF; if (s->mode & KBD_MODE_MOUSE_INT) @@ -362,7 +363,7 @@ void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base) s->irq_kbd = kbd_irq; s->irq_mouse = mouse_irq; - + kbd_reset(s); register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); register_ioport_read(io_base, 1, 1, kbd_read_data, s); @@ -377,3 +378,59 @@ void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base) #endif qemu_register_reset(kbd_reset, s); } + +/* Memory mapped interface */ +uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr) +{ + KBDState *s = opaque; + + if (addr == s->base) + return kbd_read_data(s, 0); + else + return kbd_read_status(s, 0); +} + +void kbd_mm_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + KBDState *s = opaque; + + if (addr == s->base) + kbd_write_data(s, 0, value); + else + kbd_write_command(s, 0, value); +} + +static CPUReadMemoryFunc *kbd_mm_read[] = { + &kbd_mm_readb, + &kbd_mm_readb, + &kbd_mm_readb, +}; + +static CPUWriteMemoryFunc *kbd_mm_write[] = { + &kbd_mm_writeb, + &kbd_mm_writeb, + &kbd_mm_writeb, +}; + +void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, int it_shift) +{ + KBDState *s = &kbd_state; + int s_io_memory; + + s->irq_kbd = kbd_irq; + s->irq_mouse = mouse_irq; + s->base = base; + + kbd_reset(s); + register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); + s_io_memory = cpu_register_io_memory(0, kbd_mm_read, kbd_mm_write, s); + cpu_register_physical_memory(base & ~(TARGET_PAGE_SIZE - 1), TARGET_PAGE_SIZE, s_io_memory); + + s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); + s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); +#ifdef TARGET_I386 + vmmouse_init(s->mouse); +#endif + qemu_register_reset(kbd_reset, s); +} diff --git a/vl.h b/vl.h index df76a9fbc..052ef1cb1 100644 --- a/vl.h +++ b/vl.h @@ -1035,7 +1035,8 @@ void *vmmouse_init(void *m); /* pckbd.c */ -void i8042_init(qemu_irq kdb_irq, qemu_irq mouse_irq, uint32_t io_base); +void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); +void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, int it_shift); /* mc146818rtc.c */ -- cgit v1.2.3 From 2ca9d01385dd5e24938eb15147f9072825217d21 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 16 Apr 2007 17:21:21 +0000 Subject: Memory-mapped interface for RTC, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2686 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mc146818rtc.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 1 + 2 files changed, 94 insertions(+) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 8b9357459..af7665495 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -55,6 +55,7 @@ struct RTCState { uint8_t cmos_index; struct tm current_tm; qemu_irq irq; + target_phys_addr_t base; /* periodic timer */ QEMUTimer *periodic_timer; int64_t next_periodic_time; @@ -486,3 +487,95 @@ RTCState *rtc_init(int base, qemu_irq irq) return s; } +/* Memory mapped interface */ +uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr) +{ + RTCState *s = opaque; + + return cmos_ioport_read(s, addr - s->base) & 0xFF; +} + +void cmos_mm_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + RTCState *s = opaque; + + cmos_ioport_write(s, addr - s->base, value & 0xFF); +} + +uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr) +{ + RTCState *s = opaque; + + return cmos_ioport_read(s, addr - s->base) & 0xFFFF; +} + +void cmos_mm_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + RTCState *s = opaque; + + cmos_ioport_write(s, addr - s->base, value & 0xFFFF); +} + +uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr) +{ + RTCState *s = opaque; + + return cmos_ioport_read(s, addr - s->base); +} + +void cmos_mm_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + RTCState *s = opaque; + + cmos_ioport_write(s, addr - s->base, value); +} + +static CPUReadMemoryFunc *rtc_mm_read[] = { + &cmos_mm_readb, + &cmos_mm_readw, + &cmos_mm_readl, +}; + +static CPUWriteMemoryFunc *rtc_mm_write[] = { + &cmos_mm_writeb, + &cmos_mm_writew, + &cmos_mm_writel, +}; + +RTCState *rtc_mm_init(target_phys_addr_t base, qemu_irq irq) +{ + RTCState *s; + int io_memory; + + s = qemu_mallocz(sizeof(RTCState)); + if (!s) + return NULL; + + s->irq = irq; + s->cmos_data[RTC_REG_A] = 0x26; + s->cmos_data[RTC_REG_B] = 0x02; + s->cmos_data[RTC_REG_C] = 0x00; + s->cmos_data[RTC_REG_D] = 0x80; + s->base = base; + + rtc_set_date_from_host(s); + + s->periodic_timer = qemu_new_timer(vm_clock, + rtc_periodic_timer, s); + s->second_timer = qemu_new_timer(vm_clock, + rtc_update_second, s); + s->second_timer2 = qemu_new_timer(vm_clock, + rtc_update_second2, s); + + s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100; + qemu_mod_timer(s->second_timer2, s->next_second_time); + + io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s); + cpu_register_physical_memory(base, 2, io_memory); + + register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); + return s; +} diff --git a/vl.h b/vl.h index 052ef1cb1..632b4f6bc 100644 --- a/vl.h +++ b/vl.h @@ -1043,6 +1043,7 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, int typedef struct RTCState RTCState; RTCState *rtc_init(int base, qemu_irq irq); +RTCState *rtc_mm_init(target_phys_addr_t base, qemu_irq irq); void rtc_set_memory(RTCState *s, int addr, int val); void rtc_set_date(RTCState *s, const struct tm *tm); -- cgit v1.2.3 From ad6fe1d2d96699e82d0b8b4f6fa4326c198a1d1a Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 16 Apr 2007 17:23:27 +0000 Subject: Acer Pica 61 machine, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2687 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +- hw/mips_pica61.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 1 + vl.h | 5 +- 4 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 hw/mips_pica61.c diff --git a/Makefile.target b/Makefile.target index afca82601..0f6e21f38 100644 --- a/Makefile.target +++ b/Makefile.target @@ -425,7 +425,8 @@ VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), mips) -VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o +VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o +VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) CPPFLAGS += -DHAS_AUDIO diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c new file mode 100644 index 000000000..9d9400a69 --- /dev/null +++ b/hw/mips_pica61.c @@ -0,0 +1,175 @@ +/* + * QEMU Malta board support + * + * Copyright (c) 2007 Herv Poussineau + * + * 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" + +#ifdef TARGET_WORDS_BIGENDIAN +#define BIOS_FILENAME "mips_bios.bin" +#else +#define BIOS_FILENAME "mipsel_bios.bin" +#endif + +#ifdef TARGET_MIPS64 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) +#else +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) +#endif + +#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) + +static const int ide_iobase[2] = { 0x1f0, 0x170 }; +static const int ide_iobase2[2] = { 0x3f6, 0x376 }; +static const int ide_irq[2] = { 14, 15 }; + +static uint32_t serial_base[MAX_SERIAL_PORTS] = { 0x80006000, 0x80007000 }; +static int serial_irq[MAX_SERIAL_PORTS] = { 8, 9 }; + +extern FILE *logfile; + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); +} + +static +void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + char buf[1024]; + unsigned long bios_offset; + int bios_size; + CPUState *env; + int i; + mips_def_t *def; + int available_ram; + qemu_irq *i8259; + + /* init CPUs */ + if (cpu_model == NULL) { +#ifdef TARGET_MIPS64 + cpu_model = "R4000"; +#else + cpu_model = "4KEc"; +#endif + } + if (mips_find_by_name(cpu_model, &def) != 0) + def = NULL; + env = cpu_init(); + cpu_mips_register(env, def); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + qemu_register_reset(main_cpu_reset, env); + + /* allocate RAM (limited to 256 MB) */ + if (ram_size < 256 * 1024 * 1024) + available_ram = ram_size; + else + available_ram = 256 * 1024 * 1024; + cpu_register_physical_memory(0, available_ram, IO_MEM_RAM); + + /* load a BIOS image */ + bios_offset = ram_size + vga_ram_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + bios_size = load_image(buf, phys_ram_base + bios_offset); + if ((bios_size <= 0) || (bios_size > BIOS_SIZE)) { + /* fatal */ + fprintf(stderr, "qemu: Error, could not load MIPS bios '%s'\n", + buf); + exit(1); + } + cpu_register_physical_memory(0x1fc00000, + BIOS_SIZE, bios_offset | IO_MEM_ROM); + + /* Device map + * + * addr 0xe0004000: mc146818 + * addr 0xe0005000 intr 6: ps2 keyboard + * addr 0xe0005000 intr 7: ps2 mouse + * addr 0xe0006000 intr 8: ns16550a, + * addr 0xe0007000 intr 9: ns16550a + * isa_io_base 0xe2000000 isa_mem_base 0xe3000000 + */ + + /* Init CPU internal devices */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + cpu_mips_irqctrl_init(); + + /* Register 64 KB of ISA IO space at 0x10000000 */ + isa_mmio_init(0x10000000, 0x00010000); + isa_mem_base = 0x11000000; + + /* PC style IRQ (i8259/i8254) and DMA (i8257) */ + /* The PIC is attached to the MIPS CPU INT0 pin */ + i8259 = i8259_init(env->irq[2]); + rtc_mm_init(0x80004070, i8259[14]); + pit_init(0x40, 0); + + /* Keyboard (i8042) */ + i8042_mm_init(i8259[6], i8259[7], 0x80005060, 0); + + /* IDE controller */ + for(i = 0; i < 2; i++) + isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], + bs_table[2 * i], bs_table[2 * i + 1]); + + /* Network controller */ + /* FIXME: missing NS SONIC DP83932 */ + + /* SCSI adapter */ + /* FIXME: missing NCR 53C94 */ + + /* ISA devices (floppy, serial, parallel) */ + fdctrl_init(i8259[1], 1, 1, 0x80003000, fd_table); + for(i = 0; i < MAX_SERIAL_PORTS; i++) { + if (serial_hds[i]) { + serial_mm_init(serial_base[i], 0, i8259[serial_irq[i]], serial_hds[i], 1); + } + } + for (i = 0; i < MAX_PARALLEL_PORTS; i++) { + if (parallel_hds[i]) { + /* FIXME: memory mapped! parallel_init(0x80008000, i8259[17], parallel_hds[i]); */ + } + } + + /* Sound card */ + /* FIXME: missing Jazz sound, IRQ 18 */ + + /* LED indicator */ + /* FIXME: missing LED indicator */ + + /* NVRAM */ + ds1225y_init(0x80009000, "nvram"); + + /* Video card */ + //isa_vga_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); +} + +QEMUMachine mips_pica61_machine = { + "pica61", + "Acer Pica 61", + mips_pica61_init, +}; diff --git a/vl.c b/vl.c index 853b8911e..1c79cfd78 100644 --- a/vl.c +++ b/vl.c @@ -6697,6 +6697,7 @@ void register_machines(void) #elif defined(TARGET_MIPS) qemu_register_machine(&mips_machine); qemu_register_machine(&mips_malta_machine); + qemu_register_machine(&mips_pica61_machine); #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 qemu_register_machine(&sun4u_machine); diff --git a/vl.h b/vl.h index 632b4f6bc..b0e37dd78 100644 --- a/vl.h +++ b/vl.h @@ -1136,9 +1136,12 @@ extern QEMUMachine mips_machine; /* mips_malta.c */ extern QEMUMachine mips_malta_machine; -/* mips_int */ +/* mips_int.c */ extern void cpu_mips_irq_init_cpu(CPUState *env); +/* mips_pica61.c */ +extern QEMUMachine mips_pica61_machine; + /* mips_timer.c */ extern void cpu_mips_clock_init(CPUState *); extern void cpu_mips_irqctrl_init (void); -- cgit v1.2.3 From 6083f93345fedc7102184282766e5ff74db81773 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 16 Apr 2007 17:41:15 +0000 Subject: Update OpenBIOS Sparc images to SVN 125 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2688 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 2 +- pc-bios/openbios-sparc32 | Bin 248348 -> 248348 bytes pc-bios/openbios-sparc64 | Bin 1442408 -> 410216 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/README b/pc-bios/README index 84551e9cf..8d4fe584a 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,7 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 and Sparc64 images are built from SVN version 123. + The included Sparc32 and Sparc64 images are built from SVN version 125. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index ba9b78aba..a0d17af94 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 65bae1177..1bf14bd3c 100644 Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ -- cgit v1.2.3 From 3142255c62f3e69a1fa75427426a3e64b6349fbd Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 16 Apr 2007 18:27:06 +0000 Subject: Sparc host update (Ben Taylor, Martin Bochnig) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2689 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 7 +++---- Makefile.target | 44 ++++++++++++++++++++++++-------------------- configure | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- cpu-all.h | 2 +- 4 files changed, 76 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 9249c7fea..c547453d5 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,9 @@ include config-host.mak BASE_CFLAGS= BASE_LDFLAGS= -BASE_CFLAGS += $(OS_CFLAGS) -ifeq ($(ARCH),sparc) -BASE_CFLAGS += -mcpu=ultrasparc -endif +BASE_CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS) +BASE_LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS) + CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS= TOOLS=qemu-img$(EXESUF) diff --git a/Makefile.target b/Makefile.target index 0f6e21f38..7129de0a4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -132,25 +132,25 @@ 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 + BASE_CFLAGS+=-ffixed-g2 -ffixed-g3 + OP_CFLAGS+=-fno-delayed-branch -ffixed-i0 + ifeq ($(CONFIG_SOLARIS),yes) + OP_CFLAGS+=-fno-omit-frame-pointer + else + BASE_CFLAGS+=-ffixed-g1 -ffixed-g6 + 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 + BASE_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 + OP_CFLAGS+=-mcpu=ultrasparc -m64 -fno-delayed-branch -ffixed-i0 + ifneq ($(CONFIG_SOLARIS),yes) + BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld + OP_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 + endif endif ifeq ($(ARCH),alpha) @@ -202,8 +202,10 @@ ifdef CONFIG_DARWIN_USER BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000 endif -BASE_CFLAGS+=$(OS_CFLAGS) -OP_CFLAGS+=$(OS_CFLAGS) +BASE_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS) +BASE_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS) +OP_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS) +OP_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS) ######################################################### @@ -500,8 +502,10 @@ 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 + VL_LDFLAGS+=-m64 + ifneq ($(CONFIG_SOLARIS),yes) + VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld + endif endif ifdef CONFIG_WIN32 diff --git a/configure b/configure index f8879dfc2..adfc268e4 100755 --- a/configure +++ b/configure @@ -56,7 +56,7 @@ case "$cpu" in s390) cpu="s390" ;; - sparc|sun4[muv]) + sparc|sun4[cdmuv]) cpu="sparc" ;; sparc64) @@ -266,6 +266,18 @@ for opt do ;; --enable-uname-release=*) uname_release="$optarg" ;; + --sparc_cpu=*) + sparc_cpu="$optarg" + case $sparc_cpu in + v7|v8) SP_CFLAGS="-m32 -mcpu=${sparc_cpu} -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m32" + target_cpu="sparc"; cpu="sparc" ;; + v8plus|v8plusa) SP_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m32" + target_cpu="sparc"; cpu="sparc" ;; + v9) SP_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m64" + target_cpu="sparc64"; cpu="sparc64" ;; + *) echo "undefined SPARC architecture. Exiting";exit 1;; + esac + ;; esac done @@ -279,6 +291,29 @@ fi CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing" LDFLAGS="$LDFLAGS -g" +# +# If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right +# ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit) +# +case $cpu in + sparc) if test -z "$sparc_cpu" ; then + ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__" + ARCH_LDFLAGS="-m32" + else + ARCH_CFLAGS="${SP_CFLAGS}" + ARCH_LDFLAGS="${SP_LDFLAGS}" + fi + ;; + sparc64) if test -z "$sparc_cpu" ; then + ARCH_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__" + ARCH_LDFLAGS="-m64" + else + ARCH_CFLAGS="${SP_CFLAGS}" + ARCH_LDFLAGS="${SP_LDFLAGS}" + fi + ;; +esac + if test x"$show_help" = x"yes" ; then cat << EOF @@ -320,6 +355,7 @@ echo " --disable-darwin-user disable all darwin 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 " --sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -635,6 +671,9 @@ else fmod_support="" fi echo "FMOD support $fmod $fmod_support" +if test -n "$sparc_cpu"; then + echo "Target Sparc Arch $sparc_cpu" +fi echo "kqemu support $kqemu" echo "Documentation $build_docs" [ ! -z "$uname_release" ] && \ @@ -668,6 +707,9 @@ 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 "OS_LDFLAGS=$OS_LDFLAGS" >> $config_mak +echo "ARCH_CFLAGS=$ARCH_CFLAGS" >> $config_mak +echo "ARCH_LDFLAGS=$ARCH_LDFLAGS" >> $config_mak echo "CFLAGS=$CFLAGS" >> $config_mak echo "LDFLAGS=$LDFLAGS" >> $config_mak echo "EXESUF=$EXESUF" >> $config_mak @@ -712,7 +754,7 @@ elif test "$cpu" = "m68k" ; then echo "ARCH=m68k" >> $config_mak echo "#define HOST_M68K 1" >> $config_h else - echo "Unsupported CPU" + echo "Unsupported CPU = $cpu" exit 1 fi if test "$bigendian" = "yes" ; then @@ -744,6 +786,10 @@ if test "$solaris" = "yes" ; then echo "#define NEEDS_LIBSUNMATH 1" >> $config_h fi fi +if test -n "$sparc_cpu"; then + echo "CONFIG__sparc_${sparc_cpu}__=yes" >> $config_mak + echo "#define __sparc_${sparc_cpu}__ 1" >> $config_h +fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak echo "#define CONFIG_GDBSTUB 1" >> $config_h diff --git a/cpu-all.h b/cpu-all.h index 2fc2f9a99..db1e947fe 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -1000,7 +1000,7 @@ static inline int64_t cpu_get_real_ticks(void) return val; } -#elif defined(__sparc_v9__) +#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) static inline int64_t cpu_get_real_ticks (void) { -- cgit v1.2.3 From 8ecc7913525ecb6a1a41ceceac93d485a544054f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 16 Apr 2007 20:09:45 +0000 Subject: Add callbacks to allow dynamic change of PowerPC clocks (to be improved) Fix embedded PowerPC watchdog and timers Fix PowerPC 405 SPR Add generic PowerPC 405 core instanciation code + resets support. Implement simple peripherals shared by most PowerPC 405 implementations PowerPC 405 EC & EP microcontrollers preliminary support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2690 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/ppc.c | 97 +- hw/ppc405_uc.c | 2756 +++++++++++++++++++++++++++++++++++++++++++ target-ppc/cpu.h | 1 + target-ppc/exec.h | 1 + target-ppc/op.c | 5 + target-ppc/translate_init.c | 28 +- vl.h | 67 +- 8 files changed, 2912 insertions(+), 47 deletions(-) create mode 100644 hw/ppc405_uc.c diff --git a/Makefile.target b/Makefile.target index 7129de0a4..45a8ab4d2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -421,9 +421,9 @@ CPPFLAGS += -DHAS_AUDIO 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+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o pflash_cfi02.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o -VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o +VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o ppc405_uc.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), mips) diff --git a/hw/ppc.c b/hw/ppc.c index 62e9e1b1e..1f6efee13 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -290,33 +290,55 @@ static void ppc405_set_irq (void *opaque, int pin, int level) int cur_level; #if defined(PPC_DEBUG_IRQ) - printf("%s: env %p pin %d level %d\n", __func__, env, pin, level); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: env %p pin %d level %d\n", __func__, + env, pin, level); + } #endif cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { switch (pin) { case PPC405_INPUT_RESET_SYS: - /* XXX: TODO: reset all peripherals */ - /* No break here */ + if (level) { +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: reset the PowerPC system\n", + __func__); + } +#endif + ppc40x_system_reset(env); + } + break; case PPC405_INPUT_RESET_CHIP: - /* XXX: TODO: reset on-chip peripherals */ + if (level) { +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: reset the PowerPC chip\n", __func__); + } +#endif + ppc40x_chip_reset(env); + } + break; /* No break here */ case PPC405_INPUT_RESET_CORE: /* XXX: TODO: update DBSR[MRR] */ if (level) { -#if 0 // XXX: TOFIX #if defined(PPC_DEBUG_IRQ) - printf("%s: reset the CPU\n", __func__); -#endif - cpu_reset(env); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: reset the PowerPC core\n", __func__); + } #endif + ppc40x_core_reset(env); } break; case PPC405_INPUT_CINT: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) - printf("%s: set the critical IRQ state to %d\n", __func__, level); + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: set the critical IRQ state to %d\n", + __func__, level); + } #endif /* XXX: TOFIX */ ppc_set_irq(env, PPC_INTERRUPT_RESET, level); @@ -538,8 +560,21 @@ static void cpu_ppc_decr_cb (void *opaque) _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); } +static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) +{ + CPUState *env = opaque; + ppc_tb_t *tb_env = env->tb_env; + + tb_env->tb_freq = freq; + /* There is a bug in Linux 2.4 kernels: + * if a decrementer exception is pending when it enables msr_ee at startup, + * it's not ready to handle it... + */ + _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); +} + /* Set up (once) timebase frequency (in Hz) */ -ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq) +clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq) { ppc_tb_t *tb_env; @@ -547,23 +582,15 @@ ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq) if (tb_env == NULL) return NULL; env->tb_env = tb_env; - if (tb_env->tb_freq == 0 || 1) { - tb_env->tb_freq = freq; - /* Create new timer */ - tb_env->decr_timer = - qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); - /* There is a bug in Linux 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee, - * it's not ready to handle it... - */ - _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); - } + /* Create new timer */ + tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); + cpu_ppc_set_tb_clk(env, freq); - return tb_env; + return &cpu_ppc_set_tb_clk; } /* Specific helpers for POWER & PowerPC 601 RTC */ -ppc_tb_t *cpu_ppc601_rtc_init (CPUState *env) +clk_setup_cb cpu_ppc601_rtc_init (CPUState *env) { return cpu_ppc_tb_init(env, 7812500); } @@ -733,10 +760,14 @@ static void cpu_4xx_wdt_cb (void *opaque) /* No reset */ break; case 0x1: /* Core reset */ + ppc40x_core_reset(env); + break; case 0x2: /* Chip reset */ + ppc40x_chip_reset(env); + break; case 0x3: /* System reset */ - qemu_system_reset_request(); - return; + ppc40x_system_reset(env); + break; } } } @@ -784,20 +815,25 @@ void store_booke_tsr (CPUState *env, target_ulong val) void store_booke_tcr (CPUState *env, target_ulong val) { - /* We don't update timers now. Maybe we should... */ env->spr[SPR_40x_TCR] = val & 0xFF800000; + cpu_4xx_wdt_cb(env); } -void ppc_emb_timers_init (CPUState *env) +clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) { ppc_tb_t *tb_env; ppcemb_timer_t *ppcemb_timer; - tb_env = env->tb_env; + tb_env = qemu_mallocz(sizeof(ppc_tb_t)); + if (tb_env == NULL) + return NULL; + env->tb_env = tb_env; ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t)); + tb_env->tb_freq = freq; tb_env->opaque = ppcemb_timer; - if (loglevel) + if (loglevel) { fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); + } if (ppcemb_timer != NULL) { /* We use decr timer for PIT */ tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env); @@ -806,6 +842,9 @@ void ppc_emb_timers_init (CPUState *env) ppcemb_timer->wdt_timer = qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env); } + + /* XXX: TODO: add callback for clock frequency change */ + return NULL; } /*****************************************************************************/ diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c new file mode 100644 index 000000000..0b7ef1273 --- /dev/null +++ b/hw/ppc405_uc.c @@ -0,0 +1,2756 @@ +/* + * QEMU PowerPC 405 embedded processors emulation + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +extern int loglevel; +extern FILE *logfile; + +#define DEBUG_MMIO +#define DEBUG_OPBA +#define DEBUG_SDRAM +#define DEBUG_GPIO +#define DEBUG_SERIAL +#define DEBUG_OCM +#define DEBUG_I2C +#define DEBUG_UIC +#define DEBUG_CLOCKS +#define DEBUG_UNASSIGNED + +/*****************************************************************************/ +/* Generic PowerPC 405 processor instanciation */ +CPUState *ppc405_init (const unsigned char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk) +{ + CPUState *env; + ppc_def_t *def; + + /* init CPUs */ + env = cpu_init(); + qemu_register_reset(&cpu_ppc_reset, env); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + ppc_find_by_name(cpu_model, &def); + if (def == NULL) { + cpu_abort(env, "Unable to find PowerPC %s CPU definition\n", + cpu_model); + } + cpu_ppc_register(env, def); + cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ + cpu_clk->opaque = env; + /* Set time-base frequency to sysclk */ + tb_clk->cb = ppc_emb_timers_init(env, sysclk); + tb_clk->opaque = env; + ppc_dcr_init(env, NULL, NULL); + + return env; +} + +/*****************************************************************************/ +/* Shared peripherals */ + +/*****************************************************************************/ +/* Fake device used to map multiple devices in a single memory page */ +#define MMIO_AREA_BITS 8 +#define MMIO_AREA_LEN (1 << MMIO_AREA_BITS) +#define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS)) +#define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1)) +struct ppc4xx_mmio_t { + uint32_t base; + CPUReadMemoryFunc **mem_read[MMIO_AREA_NB]; + CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB]; + void *opaque[MMIO_AREA_NB]; +}; + +static uint32_t unassigned_mem_readb (void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem read 0x" PADDRX "\n", addr); +#endif + + return 0; +} + +static void unassigned_mem_writeb (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem write 0x" PADDRX " = 0x%x\n", addr, val); +#endif +} + +static CPUReadMemoryFunc *unassigned_mem_read[3] = { + unassigned_mem_readb, + unassigned_mem_readb, + unassigned_mem_readb, +}; + +static CPUWriteMemoryFunc *unassigned_mem_write[3] = { + unassigned_mem_writeb, + unassigned_mem_writeb, + unassigned_mem_writeb, +}; + +static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, + target_phys_addr_t addr, int len) +{ + CPUReadMemoryFunc **mem_read; + uint32_t ret; + int idx; + + idx = MMIO_IDX(addr - mmio->base); +#if defined(DEBUG_MMIO) + printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__, + mmio, len, addr, idx); +#endif + mem_read = mmio->mem_read[idx]; + ret = (*mem_read[len])(mmio->opaque[idx], addr); + + return ret; +} + +static void mmio_writelen (ppc4xx_mmio_t *mmio, + target_phys_addr_t addr, uint32_t value, int len) +{ + CPUWriteMemoryFunc **mem_write; + int idx; + + idx = MMIO_IDX(addr - mmio->base); +#if defined(DEBUG_MMIO) + printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__, + mmio, len, addr, idx, value); +#endif + mem_write = mmio->mem_write[idx]; + (*mem_write[len])(mmio->opaque[idx], addr, value); +} + +static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return mmio_readlen(opaque, addr, 0); +} + +static void mmio_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + mmio_writelen(opaque, addr, value, 0); +} + +static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return mmio_readlen(opaque, addr, 1); +} + +static void mmio_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + mmio_writelen(opaque, addr, value, 1); +} + +static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return mmio_readlen(opaque, addr, 2); +} + +static void mmio_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + mmio_writelen(opaque, addr, value, 2); +} + +static CPUReadMemoryFunc *mmio_read[] = { + &mmio_readb, + &mmio_readw, + &mmio_readl, +}; + +static CPUWriteMemoryFunc *mmio_write[] = { + &mmio_writeb, + &mmio_writew, + &mmio_writel, +}; + +int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, + uint32_t offset, uint32_t len, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, void *opaque) +{ + uint32_t end; + int idx, eidx; + + if ((offset + len) > TARGET_PAGE_SIZE) + return -1; + idx = MMIO_IDX(offset); + end = offset + len - 1; + eidx = MMIO_IDX(end); +#if defined(DEBUG_MMIO) + printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len, + end, idx, eidx); +#endif + for (; idx <= eidx; idx++) { + mmio->mem_read[idx] = mem_read; + mmio->mem_write[idx] = mem_write; + mmio->opaque[idx] = opaque; + } + + return 0; +} + +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, uint32_t base) +{ + ppc4xx_mmio_t *mmio; + int mmio_memory; + + mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t)); + if (mmio != NULL) { + mmio->base = base; + mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); +#if defined(DEBUG_MMIO) + printf("%s: %p base %08x len %08x %d\n", __func__, + mmio, base, TARGET_PAGE_SIZE, mmio_memory); +#endif + cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); + ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, + unassigned_mem_read, unassigned_mem_write, NULL); + } + + return mmio; +} + +/*****************************************************************************/ +/* Peripheral local bus arbitrer */ +enum { + PLB0_BESR = 0x084, + PLB0_BEAR = 0x086, + PLB0_ACR = 0x087, +}; + +typedef struct ppc4xx_plb_t ppc4xx_plb_t; +struct ppc4xx_plb_t { + uint32_t acr; + uint32_t bear; + uint32_t besr; +}; + +static target_ulong dcr_read_plb (void *opaque, int dcrn) +{ + ppc4xx_plb_t *plb; + target_ulong ret; + + plb = opaque; + switch (dcrn) { + case PLB0_ACR: + ret = plb->acr; + break; + case PLB0_BEAR: + ret = plb->bear; + break; + case PLB0_BESR: + ret = plb->besr; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_plb (void *opaque, int dcrn, target_ulong val) +{ + ppc4xx_plb_t *plb; + + plb = opaque; + switch (dcrn) { + case PLB0_ACR: + plb->acr = val & 0xFC000000; + break; + case PLB0_BEAR: + /* Read only */ + break; + case PLB0_BESR: + /* Write-clear */ + plb->besr &= ~val; + break; + } +} + +static void ppc4xx_plb_reset (void *opaque) +{ + ppc4xx_plb_t *plb; + + plb = opaque; + plb->acr = 0x00000000; + plb->bear = 0x00000000; + plb->besr = 0x00000000; +} + +void ppc4xx_plb_init (CPUState *env) +{ + ppc4xx_plb_t *plb; + + plb = qemu_mallocz(sizeof(ppc4xx_plb_t)); + if (plb != NULL) { + ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb); + ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb); + ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb); + ppc4xx_plb_reset(plb); + qemu_register_reset(ppc4xx_plb_reset, plb); + } +} + +/*****************************************************************************/ +/* PLB to OPB bridge */ +enum { + POB0_BESR0 = 0x0A0, + POB0_BESR1 = 0x0A2, + POB0_BEAR = 0x0A4, +}; + +typedef struct ppc4xx_pob_t ppc4xx_pob_t; +struct ppc4xx_pob_t { + uint32_t bear; + uint32_t besr[2]; +}; + +static target_ulong dcr_read_pob (void *opaque, int dcrn) +{ + ppc4xx_pob_t *pob; + target_ulong ret; + + pob = opaque; + switch (dcrn) { + case POB0_BEAR: + ret = pob->bear; + break; + case POB0_BESR0: + case POB0_BESR1: + ret = pob->besr[dcrn - POB0_BESR0]; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_pob (void *opaque, int dcrn, target_ulong val) +{ + ppc4xx_pob_t *pob; + + pob = opaque; + switch (dcrn) { + case POB0_BEAR: + /* Read only */ + break; + case POB0_BESR0: + case POB0_BESR1: + /* Write-clear */ + pob->besr[dcrn - POB0_BESR0] &= ~val; + break; + } +} + +static void ppc4xx_pob_reset (void *opaque) +{ + ppc4xx_pob_t *pob; + + pob = opaque; + /* No error */ + pob->bear = 0x00000000; + pob->besr[0] = 0x0000000; + pob->besr[1] = 0x0000000; +} + +void ppc4xx_pob_init (CPUState *env) +{ + ppc4xx_pob_t *pob; + + pob = qemu_mallocz(sizeof(ppc4xx_pob_t)); + if (pob != NULL) { + ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob); + ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob); + ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob); + qemu_register_reset(ppc4xx_pob_reset, pob); + ppc4xx_pob_reset(env); + } +} + +/*****************************************************************************/ +/* OPB arbitrer */ +typedef struct ppc4xx_opba_t ppc4xx_opba_t; +struct ppc4xx_opba_t { + target_ulong base; + uint8_t cr; + uint8_t pr; +}; + +static uint32_t opba_readb (void *opaque, target_phys_addr_t addr) +{ + ppc4xx_opba_t *opba; + uint32_t ret; + +#ifdef DEBUG_OPBA + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + opba = opaque; + switch (addr - opba->base) { + case 0x00: + ret = opba->cr; + break; + case 0x01: + ret = opba->pr; + break; + default: + ret = 0x00; + break; + } + + return ret; +} + +static void opba_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ppc4xx_opba_t *opba; + +#ifdef DEBUG_OPBA + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + opba = opaque; + switch (addr - opba->base) { + case 0x00: + opba->cr = value & 0xF8; + break; + case 0x01: + opba->pr = value & 0xFF; + break; + default: + break; + } +} + +static uint32_t opba_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + +#ifdef DEBUG_OPBA + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + ret = opba_readb(opaque, addr) << 8; + ret |= opba_readb(opaque, addr + 1); + + return ret; +} + +static void opba_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#ifdef DEBUG_OPBA + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + opba_writeb(opaque, addr, value >> 8); + opba_writeb(opaque, addr + 1, value); +} + +static uint32_t opba_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + +#ifdef DEBUG_OPBA + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + ret = opba_readb(opaque, addr) << 24; + ret |= opba_readb(opaque, addr + 1) << 16; + + return ret; +} + +static void opba_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#ifdef DEBUG_OPBA + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + opba_writeb(opaque, addr, value >> 24); + opba_writeb(opaque, addr + 1, value >> 16); +} + +static CPUReadMemoryFunc *opba_read[] = { + &opba_readb, + &opba_readw, + &opba_readl, +}; + +static CPUWriteMemoryFunc *opba_write[] = { + &opba_writeb, + &opba_writew, + &opba_writel, +}; + +static void ppc4xx_opba_reset (void *opaque) +{ + ppc4xx_opba_t *opba; + + opba = opaque; + opba->cr = 0x00; /* No dynamic priorities - park disabled */ + opba->pr = 0x11; +} + +void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset) +{ + ppc4xx_opba_t *opba; + + opba = qemu_mallocz(sizeof(ppc4xx_opba_t)); + if (opba != NULL) { + opba->base = mmio->base + offset; +#ifdef DEBUG_OPBA + printf("%s: offset=%08x\n", __func__, offset); +#endif + ppc4xx_mmio_register(env, mmio, offset, 0x002, + opba_read, opba_write, opba); + qemu_register_reset(ppc4xx_opba_reset, opba); + ppc4xx_opba_reset(opba); + } +} + +/*****************************************************************************/ +/* "Universal" Interrupt controller */ +enum { + DCR_UICSR = 0x000, + DCR_UICSRS = 0x001, + DCR_UICER = 0x002, + DCR_UICCR = 0x003, + DCR_UICPR = 0x004, + DCR_UICTR = 0x005, + DCR_UICMSR = 0x006, + DCR_UICVR = 0x007, + DCR_UICVCR = 0x008, + DCR_UICMAX = 0x009, +}; + +#define UIC_MAX_IRQ 32 +typedef struct ppcuic_t ppcuic_t; +struct ppcuic_t { + uint32_t dcr_base; + int use_vectors; + uint32_t uicsr; /* Status register */ + uint32_t uicer; /* Enable register */ + uint32_t uiccr; /* Critical register */ + uint32_t uicpr; /* Polarity register */ + uint32_t uictr; /* Triggering register */ + uint32_t uicvcr; /* Vector configuration register */ + uint32_t uicvr; + qemu_irq *irqs; +}; + +static void ppcuic_trigger_irq (ppcuic_t *uic) +{ + uint32_t ir, cr; + int start, end, inc, i; + + /* Trigger interrupt if any is pending */ + ir = uic->uicsr & uic->uicer & (~uic->uiccr); + cr = uic->uicsr & uic->uicer & uic->uiccr; +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n" + " %08x ir %08x cr %08x\n", __func__, + uic->uicsr, uic->uicer, uic->uiccr, + uic->uicsr & uic->uicer, ir, cr); + } +#endif + if (ir != 0x0000000) { +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Raise UIC interrupt\n"); + } +#endif + qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); + } else { +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Lower UIC interrupt\n"); + } +#endif + qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); + } + /* Trigger critical interrupt if any is pending and update vector */ + if (cr != 0x0000000) { + qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); + if (uic->use_vectors) { + /* Compute critical IRQ vector */ + if (uic->uicvcr & 1) { + start = 31; + end = 0; + inc = -1; + } else { + start = 0; + end = 31; + inc = 1; + } + uic->uicvr = uic->uicvcr & 0xFFFFFFFC; + for (i = start; i <= end; i += inc) { + if (cr & (1 << i)) { + uic->uicvr += (i - start) * 512 * inc; + break; + } + } + } +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n", + uic->uicvr); + } +#endif + } else { +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Lower UIC critical interrupt\n"); + } +#endif + qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); + uic->uicvr = 0x00000000; + } +} + +static void ppcuic_set_irq (void *opaque, int irq_num, int level) +{ + ppcuic_t *uic; + uint32_t mask, sr; + + uic = opaque; + mask = 1 << irq_num; +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x " + "%08x\n", __func__, irq_num, level, + uic->uicsr, mask, uic->uicsr & mask, level << irq_num); + } +#endif + if (irq_num < 0 || irq_num > 31) + return; + sr = uic->uicsr; + if (!(uic->uicpr & mask)) { + /* Negatively asserted IRQ */ + level = level == 0 ? 1 : 0; + } + /* Update status register */ + if (uic->uictr & mask) { + /* Edge sensitive interrupt */ + if (level == 1) + uic->uicsr |= mask; + } else { + /* Level sensitive interrupt */ + if (level == 1) + uic->uicsr |= mask; + else + uic->uicsr &= ~mask; + } +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__, + irq_num, level, uic->uicsr, sr); + } +#endif + if (sr != uic->uicsr) + ppcuic_trigger_irq(uic); +} + +static target_ulong dcr_read_uic (void *opaque, int dcrn) +{ + ppcuic_t *uic; + target_ulong ret; + + uic = opaque; + dcrn -= uic->dcr_base; + switch (dcrn) { + case DCR_UICSR: + case DCR_UICSRS: + ret = uic->uicsr; + break; + case DCR_UICER: + ret = uic->uicer; + break; + case DCR_UICCR: + ret = uic->uiccr; + break; + case DCR_UICPR: + ret = uic->uicpr; + break; + case DCR_UICTR: + ret = uic->uictr; + break; + case DCR_UICMSR: + ret = uic->uicsr & uic->uicer; + break; + case DCR_UICVR: + if (!uic->use_vectors) + goto no_read; + ret = uic->uicvr; + break; + case DCR_UICVCR: + if (!uic->use_vectors) + goto no_read; + ret = uic->uicvcr; + break; + default: + no_read: + ret = 0x00000000; + break; + } + + return ret; +} + +static void dcr_write_uic (void *opaque, int dcrn, target_ulong val) +{ + ppcuic_t *uic; + + uic = opaque; + dcrn -= uic->dcr_base; +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val); + } +#endif + switch (dcrn) { + case DCR_UICSR: + uic->uicsr &= ~val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICSRS: + uic->uicsr |= val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICER: + uic->uicer = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICCR: + uic->uiccr = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICPR: + uic->uicpr = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICTR: + uic->uictr = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICMSR: + break; + case DCR_UICVR: + break; + case DCR_UICVCR: + uic->uicvcr = val & 0xFFFFFFFD; + ppcuic_trigger_irq(uic); + break; + } +} + +static void ppcuic_reset (void *opaque) +{ + ppcuic_t *uic; + + uic = opaque; + uic->uiccr = 0x00000000; + uic->uicer = 0x00000000; + uic->uicpr = 0x00000000; + uic->uicsr = 0x00000000; + uic->uictr = 0x00000000; + if (uic->use_vectors) { + uic->uicvcr = 0x00000000; + uic->uicvr = 0x0000000; + } +} + +qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, + uint32_t dcr_base, int has_ssr, int has_vr) +{ + ppcuic_t *uic; + int i; + + uic = qemu_mallocz(sizeof(ppcuic_t)); + if (uic != NULL) { + uic->dcr_base = dcr_base; + uic->irqs = irqs; + if (has_vr) + uic->use_vectors = 1; + for (i = 0; i < DCR_UICMAX; i++) { + ppc_dcr_register(env, dcr_base + i, uic, + &dcr_read_uic, &dcr_write_uic); + } + qemu_register_reset(ppcuic_reset, uic); + ppcuic_reset(uic); + } + + return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); +} + +/*****************************************************************************/ +/* Code decompression controller */ +/* XXX: TODO */ + +/*****************************************************************************/ +/* SDRAM controller */ +typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; +struct ppc4xx_sdram_t { + uint32_t addr; + int nbanks; + target_ulong ram_bases[4]; + target_ulong ram_sizes[4]; + uint32_t besr0; + uint32_t besr1; + uint32_t bear; + uint32_t cfg; + uint32_t status; + uint32_t rtr; + uint32_t pmit; + uint32_t bcr[4]; + uint32_t tr; + uint32_t ecccfg; + uint32_t eccesr; + qemu_irq irq; +}; + +enum { + SDRAM0_CFGADDR = 0x010, + SDRAM0_CFGDATA = 0x011, +}; + +static uint32_t sdram_bcr (target_ulong ram_base, target_ulong ram_size) +{ + uint32_t bcr; + + switch (ram_size) { + case (4 * 1024 * 1024): + bcr = 0x00000000; + break; + case (8 * 1024 * 1024): + bcr = 0x00020000; + break; + case (16 * 1024 * 1024): + bcr = 0x00040000; + break; + case (32 * 1024 * 1024): + bcr = 0x00060000; + break; + case (64 * 1024 * 1024): + bcr = 0x00080000; + break; + case (128 * 1024 * 1024): + bcr = 0x000A0000; + break; + case (256 * 1024 * 1024): + bcr = 0x000C0000; + break; + default: + printf("%s: invalid RAM size " TARGET_FMT_ld "\n", __func__, ram_size); + return 0x00000000; + } + bcr |= ram_base & 0xFF800000; + bcr |= 1; + + return bcr; +} + +static inline target_ulong sdram_base (uint32_t bcr) +{ + return bcr & 0xFF800000; +} + +static target_ulong sdram_size (uint32_t bcr) +{ + target_ulong size; + int sh; + + sh = (bcr >> 17) & 0x7; + if (sh == 7) + size = -1; + else + size = (4 * 1024 * 1024) << sh; + + return size; +} + +static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled) +{ + if (*bcrp & 0x00000001) { + /* Unmap RAM */ +#ifdef DEBUG_SDRAM + printf("%s: unmap RAM area " ADDRX " " ADDRX "\n", __func__, + sdram_base(*bcrp), sdram_size(*bcrp)); +#endif + cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp), + IO_MEM_UNASSIGNED); + } + *bcrp = bcr & 0xFFDEE001; + if (enabled && (bcr & 0x00000001)) { +#ifdef DEBUG_SDRAM + printf("%s: Map RAM area " ADDRX " " ADDRX "\n", __func__, + sdram_base(bcr), sdram_size(bcr)); +#endif + cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr), + sdram_base(bcr) | IO_MEM_RAM); + } +} + +static void sdram_map_bcr (ppc4xx_sdram_t *sdram) +{ + int i; + + for (i = 0; i < sdram->nbanks; i++) { + if (sdram->ram_sizes[i] != 0) { + sdram_set_bcr(&sdram->bcr[i], + sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]), + 1); + } else { + sdram_set_bcr(&sdram->bcr[i], 0x00000000, 0); + } + } +} + +static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) +{ + int i; + + for (i = 0; i < sdram->nbanks; i++) { + cpu_register_physical_memory(sdram_base(sdram->bcr[i]), + sdram_size(sdram->bcr[i]), + IO_MEM_UNASSIGNED); + } +} + +static target_ulong dcr_read_sdram (void *opaque, int dcrn) +{ + ppc4xx_sdram_t *sdram; + target_ulong ret; + + sdram = opaque; + switch (dcrn) { + case SDRAM0_CFGADDR: + ret = sdram->addr; + break; + case SDRAM0_CFGDATA: + switch (sdram->addr) { + case 0x00: /* SDRAM_BESR0 */ + ret = sdram->besr0; + break; + case 0x08: /* SDRAM_BESR1 */ + ret = sdram->besr1; + break; + case 0x10: /* SDRAM_BEAR */ + ret = sdram->bear; + break; + case 0x20: /* SDRAM_CFG */ + ret = sdram->cfg; + break; + case 0x24: /* SDRAM_STATUS */ + ret = sdram->status; + break; + case 0x30: /* SDRAM_RTR */ + ret = sdram->rtr; + break; + case 0x34: /* SDRAM_PMIT */ + ret = sdram->pmit; + break; + case 0x40: /* SDRAM_B0CR */ + ret = sdram->bcr[0]; + break; + case 0x44: /* SDRAM_B1CR */ + ret = sdram->bcr[1]; + break; + case 0x48: /* SDRAM_B2CR */ + ret = sdram->bcr[2]; + break; + case 0x4C: /* SDRAM_B3CR */ + ret = sdram->bcr[3]; + break; + case 0x80: /* SDRAM_TR */ + ret = -1; /* ? */ + break; + case 0x94: /* SDRAM_ECCCFG */ + ret = sdram->ecccfg; + break; + case 0x98: /* SDRAM_ECCESR */ + ret = sdram->eccesr; + break; + default: /* Error */ + ret = -1; + break; + } + break; + default: + /* Avoid gcc warning */ + ret = 0x00000000; + break; + } + + return ret; +} + +static void dcr_write_sdram (void *opaque, int dcrn, target_ulong val) +{ + ppc4xx_sdram_t *sdram; + + sdram = opaque; + switch (dcrn) { + case SDRAM0_CFGADDR: + sdram->addr = val; + break; + case SDRAM0_CFGDATA: + switch (sdram->addr) { + case 0x00: /* SDRAM_BESR0 */ + sdram->besr0 &= ~val; + break; + case 0x08: /* SDRAM_BESR1 */ + sdram->besr1 &= ~val; + break; + case 0x10: /* SDRAM_BEAR */ + sdram->bear = val; + break; + case 0x20: /* SDRAM_CFG */ + val &= 0xFFE00000; + if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { +#ifdef DEBUG_SDRAM + printf("%s: enable SDRAM controller\n", __func__); +#endif + /* validate all RAM mappings */ + sdram_map_bcr(sdram); + sdram->status &= ~0x80000000; + } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { +#ifdef DEBUG_SDRAM + printf("%s: disable SDRAM controller\n", __func__); +#endif + /* invalidate all RAM mappings */ + sdram_unmap_bcr(sdram); + sdram->status |= 0x80000000; + } + if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) + sdram->status |= 0x40000000; + else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) + sdram->status &= ~0x40000000; + sdram->cfg = val; + break; + case 0x24: /* SDRAM_STATUS */ + /* Read-only register */ + break; + case 0x30: /* SDRAM_RTR */ + sdram->rtr = val & 0x3FF80000; + break; + case 0x34: /* SDRAM_PMIT */ + sdram->pmit = (val & 0xF8000000) | 0x07C00000; + break; + case 0x40: /* SDRAM_B0CR */ + sdram_set_bcr(&sdram->bcr[0], val, sdram->cfg & 0x80000000); + break; + case 0x44: /* SDRAM_B1CR */ + sdram_set_bcr(&sdram->bcr[1], val, sdram->cfg & 0x80000000); + break; + case 0x48: /* SDRAM_B2CR */ + sdram_set_bcr(&sdram->bcr[2], val, sdram->cfg & 0x80000000); + break; + case 0x4C: /* SDRAM_B3CR */ + sdram_set_bcr(&sdram->bcr[3], val, sdram->cfg & 0x80000000); + break; + case 0x80: /* SDRAM_TR */ + sdram->tr = val & 0x018FC01F; + break; + case 0x94: /* SDRAM_ECCCFG */ + sdram->ecccfg = val & 0x00F00000; + break; + case 0x98: /* SDRAM_ECCESR */ + val &= 0xFFF0F000; + if (sdram->eccesr == 0 && val != 0) + qemu_irq_raise(sdram->irq); + else if (sdram->eccesr != 0 && val == 0) + qemu_irq_lower(sdram->irq); + sdram->eccesr = val; + break; + default: /* Error */ + break; + } + break; + } +} + +static void sdram_reset (void *opaque) +{ + ppc4xx_sdram_t *sdram; + + sdram = opaque; + sdram->addr = 0x00000000; + sdram->bear = 0x00000000; + sdram->besr0 = 0x00000000; /* No error */ + sdram->besr1 = 0x00000000; /* No error */ + sdram->cfg = 0x00000000; + sdram->ecccfg = 0x00000000; /* No ECC */ + sdram->eccesr = 0x00000000; /* No error */ + sdram->pmit = 0x07C00000; + sdram->rtr = 0x05F00000; + sdram->tr = 0x00854009; + /* We pre-initialize RAM banks */ + sdram->status = 0x00000000; + sdram->cfg = 0x00800000; + sdram_unmap_bcr(sdram); +} + +void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, + target_ulong *ram_bases, target_ulong *ram_sizes) +{ + ppc4xx_sdram_t *sdram; + + sdram = qemu_mallocz(sizeof(ppc4xx_sdram_t)); + if (sdram != NULL) { + sdram->irq = irq; + sdram->nbanks = nbanks; + memset(sdram->ram_bases, 0, 4 * sizeof(target_ulong)); + memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(target_ulong)); + memset(sdram->ram_sizes, 0, 4 * sizeof(target_ulong)); + memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(target_ulong)); + sdram_reset(sdram); + qemu_register_reset(&sdram_reset, sdram); + ppc_dcr_register(env, SDRAM0_CFGADDR, + sdram, &dcr_read_sdram, &dcr_write_sdram); + ppc_dcr_register(env, SDRAM0_CFGDATA, + sdram, &dcr_read_sdram, &dcr_write_sdram); + } +} + +/*****************************************************************************/ +/* Peripheral controller */ +typedef struct ppc4xx_ebc_t ppc4xx_ebc_t; +struct ppc4xx_ebc_t { + uint32_t addr; + uint32_t bcr[8]; + uint32_t bap[8]; + uint32_t bear; + uint32_t besr0; + uint32_t besr1; + uint32_t cfg; +}; + +enum { + EBC0_CFGADDR = 0x012, + EBC0_CFGDATA = 0x013, +}; + +static target_ulong dcr_read_ebc (void *opaque, int dcrn) +{ + ppc4xx_ebc_t *ebc; + target_ulong ret; + + ebc = opaque; + switch (dcrn) { + case EBC0_CFGADDR: + ret = ebc->addr; + break; + case EBC0_CFGDATA: + switch (ebc->addr) { + case 0x00: /* B0CR */ + ret = ebc->bcr[0]; + break; + case 0x01: /* B1CR */ + ret = ebc->bcr[1]; + break; + case 0x02: /* B2CR */ + ret = ebc->bcr[2]; + break; + case 0x03: /* B3CR */ + ret = ebc->bcr[3]; + break; + case 0x04: /* B4CR */ + ret = ebc->bcr[4]; + break; + case 0x05: /* B5CR */ + ret = ebc->bcr[5]; + break; + case 0x06: /* B6CR */ + ret = ebc->bcr[6]; + break; + case 0x07: /* B7CR */ + ret = ebc->bcr[7]; + break; + case 0x10: /* B0AP */ + ret = ebc->bap[0]; + break; + case 0x11: /* B1AP */ + ret = ebc->bap[1]; + break; + case 0x12: /* B2AP */ + ret = ebc->bap[2]; + break; + case 0x13: /* B3AP */ + ret = ebc->bap[3]; + break; + case 0x14: /* B4AP */ + ret = ebc->bap[4]; + break; + case 0x15: /* B5AP */ + ret = ebc->bap[5]; + break; + case 0x16: /* B6AP */ + ret = ebc->bap[6]; + break; + case 0x17: /* B7AP */ + ret = ebc->bap[7]; + break; + case 0x20: /* BEAR */ + ret = ebc->bear; + break; + case 0x21: /* BESR0 */ + ret = ebc->besr0; + break; + case 0x22: /* BESR1 */ + ret = ebc->besr1; + break; + case 0x23: /* CFG */ + ret = ebc->cfg; + break; + default: + ret = 0x00000000; + break; + } + default: + ret = 0x00000000; + break; + } + + return ret; +} + +static void dcr_write_ebc (void *opaque, int dcrn, target_ulong val) +{ + ppc4xx_ebc_t *ebc; + + ebc = opaque; + switch (dcrn) { + case EBC0_CFGADDR: + ebc->addr = val; + break; + case EBC0_CFGDATA: + switch (ebc->addr) { + case 0x00: /* B0CR */ + break; + case 0x01: /* B1CR */ + break; + case 0x02: /* B2CR */ + break; + case 0x03: /* B3CR */ + break; + case 0x04: /* B4CR */ + break; + case 0x05: /* B5CR */ + break; + case 0x06: /* B6CR */ + break; + case 0x07: /* B7CR */ + break; + case 0x10: /* B0AP */ + break; + case 0x11: /* B1AP */ + break; + case 0x12: /* B2AP */ + break; + case 0x13: /* B3AP */ + break; + case 0x14: /* B4AP */ + break; + case 0x15: /* B5AP */ + break; + case 0x16: /* B6AP */ + break; + case 0x17: /* B7AP */ + break; + case 0x20: /* BEAR */ + break; + case 0x21: /* BESR0 */ + break; + case 0x22: /* BESR1 */ + break; + case 0x23: /* CFG */ + break; + default: + break; + } + break; + default: + break; + } +} + +static void ebc_reset (void *opaque) +{ + ppc4xx_ebc_t *ebc; + int i; + + ebc = opaque; + ebc->addr = 0x00000000; + ebc->bap[0] = 0x7F8FFE80; + ebc->bcr[0] = 0xFFE28000; + for (i = 0; i < 8; i++) { + ebc->bap[i] = 0x00000000; + ebc->bcr[i] = 0x00000000; + } + ebc->besr0 = 0x00000000; + ebc->besr1 = 0x00000000; + ebc->cfg = 0x07C00000; +} + +void ppc405_ebc_init (CPUState *env) +{ + ppc4xx_ebc_t *ebc; + + ebc = qemu_mallocz(sizeof(ppc4xx_ebc_t)); + if (ebc != NULL) { + ebc_reset(ebc); + qemu_register_reset(&ebc_reset, ebc); + ppc_dcr_register(env, EBC0_CFGADDR, + ebc, &dcr_read_ebc, &dcr_write_ebc); + ppc_dcr_register(env, EBC0_CFGDATA, + ebc, &dcr_read_ebc, &dcr_write_ebc); + } +} + +/*****************************************************************************/ +/* DMA controller */ +enum { + DMA0_CR0 = 0x100, + DMA0_CT0 = 0x101, + DMA0_DA0 = 0x102, + DMA0_SA0 = 0x103, + DMA0_SG0 = 0x104, + DMA0_CR1 = 0x108, + DMA0_CT1 = 0x109, + DMA0_DA1 = 0x10A, + DMA0_SA1 = 0x10B, + DMA0_SG1 = 0x10C, + DMA0_CR2 = 0x110, + DMA0_CT2 = 0x111, + DMA0_DA2 = 0x112, + DMA0_SA2 = 0x113, + DMA0_SG2 = 0x114, + DMA0_CR3 = 0x118, + DMA0_CT3 = 0x119, + DMA0_DA3 = 0x11A, + DMA0_SA3 = 0x11B, + DMA0_SG3 = 0x11C, + DMA0_SR = 0x120, + DMA0_SGC = 0x123, + DMA0_SLP = 0x125, + DMA0_POL = 0x126, +}; + +typedef struct ppc405_dma_t ppc405_dma_t; +struct ppc405_dma_t { + qemu_irq irqs[4]; + uint32_t cr[4]; + uint32_t ct[4]; + uint32_t da[4]; + uint32_t sa[4]; + uint32_t sg[4]; + uint32_t sr; + uint32_t sgc; + uint32_t slp; + uint32_t pol; +}; + +static target_ulong dcr_read_dma (void *opaque, int dcrn) +{ + ppc405_dma_t *dma; + + dma = opaque; + + return 0; +} + +static void dcr_write_dma (void *opaque, int dcrn, target_ulong val) +{ + ppc405_dma_t *dma; + + dma = opaque; +} + +static void ppc405_dma_reset (void *opaque) +{ + ppc405_dma_t *dma; + int i; + + dma = opaque; + for (i = 0; i < 4; i++) { + dma->cr[i] = 0x00000000; + dma->ct[i] = 0x00000000; + dma->da[i] = 0x00000000; + dma->sa[i] = 0x00000000; + dma->sg[i] = 0x00000000; + } + dma->sr = 0x00000000; + dma->sgc = 0x00000000; + dma->slp = 0x7C000000; + dma->pol = 0x00000000; +} + +void ppc405_dma_init (CPUState *env, qemu_irq irqs[4]) +{ + ppc405_dma_t *dma; + + dma = qemu_mallocz(sizeof(ppc405_dma_t)); + if (dma != NULL) { + memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq)); + ppc405_dma_reset(dma); + qemu_register_reset(&ppc405_dma_reset, dma); + ppc_dcr_register(env, DMA0_CR0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CT0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_DA0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SA0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SG0, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CR1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CT1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_DA1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SA1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SG1, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CR2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CT2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_DA2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SA2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SG2, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CR3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_CT3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_DA3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SA3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SG3, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SR, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SGC, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_SLP, + dma, &dcr_read_dma, &dcr_write_dma); + ppc_dcr_register(env, DMA0_POL, + dma, &dcr_read_dma, &dcr_write_dma); + } +} + +/*****************************************************************************/ +/* GPIO */ +typedef struct ppc405_gpio_t ppc405_gpio_t; +struct ppc405_gpio_t { + uint32_t base; + uint32_t or; + uint32_t tcr; + uint32_t osrh; + uint32_t osrl; + uint32_t tsrh; + uint32_t tsrl; + uint32_t odr; + uint32_t ir; + uint32_t rr1; + uint32_t isr1h; + uint32_t isr1l; +}; + +static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr) +{ + ppc405_gpio_t *gpio; + + gpio = opaque; +#ifdef DEBUG_GPIO + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return 0; +} + +static void ppc405_gpio_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ppc405_gpio_t *gpio; + + gpio = opaque; +#ifdef DEBUG_GPIO + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif +} + +static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr) +{ + ppc405_gpio_t *gpio; + + gpio = opaque; +#ifdef DEBUG_GPIO + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return 0; +} + +static void ppc405_gpio_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ppc405_gpio_t *gpio; + + gpio = opaque; +#ifdef DEBUG_GPIO + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif +} + +static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr) +{ + ppc405_gpio_t *gpio; + + gpio = opaque; +#ifdef DEBUG_GPIO + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return 0; +} + +static void ppc405_gpio_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ppc405_gpio_t *gpio; + + gpio = opaque; +#ifdef DEBUG_GPIO + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif +} + +static CPUReadMemoryFunc *ppc405_gpio_read[] = { + &ppc405_gpio_readb, + &ppc405_gpio_readw, + &ppc405_gpio_readl, +}; + +static CPUWriteMemoryFunc *ppc405_gpio_write[] = { + &ppc405_gpio_writeb, + &ppc405_gpio_writew, + &ppc405_gpio_writel, +}; + +static void ppc405_gpio_reset (void *opaque) +{ + ppc405_gpio_t *gpio; + + gpio = opaque; +} + +void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset) +{ + ppc405_gpio_t *gpio; + + gpio = qemu_mallocz(sizeof(ppc405_gpio_t)); + if (gpio != NULL) { + gpio->base = mmio->base + offset; + ppc405_gpio_reset(gpio); + qemu_register_reset(&ppc405_gpio_reset, gpio); +#ifdef DEBUG_GPIO + printf("%s: offset=%08x\n", __func__, offset); +#endif + ppc4xx_mmio_register(env, mmio, offset, 0x038, + ppc405_gpio_read, ppc405_gpio_write, gpio); + } +} + +/*****************************************************************************/ +/* Serial ports */ +static CPUReadMemoryFunc *serial_mm_read[] = { + &serial_mm_readb, + &serial_mm_readw, + &serial_mm_readl, +}; + +static CPUWriteMemoryFunc *serial_mm_write[] = { + &serial_mm_writeb, + &serial_mm_writew, + &serial_mm_writel, +}; + +void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio, + uint32_t offset, qemu_irq irq, + CharDriverState *chr) +{ + void *serial; + +#ifdef DEBUG_SERIAL + printf("%s: offset=%08x\n", __func__, offset); +#endif + serial = serial_mm_init(mmio->base + offset, 0, irq, chr, 0); + ppc4xx_mmio_register(env, mmio, offset, 0x008, + serial_mm_read, serial_mm_write, serial); +} + +/*****************************************************************************/ +/* On Chip Memory */ +enum { + OCM0_ISARC = 0x018, + OCM0_ISACNTL = 0x019, + OCM0_DSARC = 0x01A, + OCM0_DSACNTL = 0x01B, +}; + +typedef struct ppc405_ocm_t ppc405_ocm_t; +struct ppc405_ocm_t { + target_ulong offset; + uint32_t isarc; + uint32_t isacntl; + uint32_t dsarc; + uint32_t dsacntl; +}; + +static void ocm_update_mappings (ppc405_ocm_t *ocm, + uint32_t isarc, uint32_t isacntl, + uint32_t dsarc, uint32_t dsacntl) +{ +#ifdef DEBUG_OCM + printf("OCM update ISA %08x %08x (%08x %08x) DSA %08x %08x (%08x %08x)\n", + isarc, isacntl, dsarc, dsacntl, + ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl); +#endif + if (ocm->isarc != isarc || + (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) { + if (ocm->isacntl & 0x80000000) { + /* Unmap previously assigned memory region */ + printf("OCM unmap ISA %08x\n", ocm->isarc); + cpu_register_physical_memory(ocm->isarc, 0x04000000, + IO_MEM_UNASSIGNED); + } + if (isacntl & 0x80000000) { + /* Map new instruction memory region */ +#ifdef DEBUG_OCM + printf("OCM map ISA %08x\n", isarc); +#endif + cpu_register_physical_memory(isarc, 0x04000000, + ocm->offset | IO_MEM_RAM); + } + } + if (ocm->dsarc != dsarc || + (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) { + if (ocm->dsacntl & 0x80000000) { + /* Beware not to unmap the region we just mapped */ + if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) { + /* Unmap previously assigned memory region */ +#ifdef DEBUG_OCM + printf("OCM unmap DSA %08x\n", ocm->dsarc); +#endif + cpu_register_physical_memory(ocm->dsarc, 0x04000000, + IO_MEM_UNASSIGNED); + } + } + if (dsacntl & 0x80000000) { + /* Beware not to remap the region we just mapped */ + if (!(isacntl & 0x80000000) || dsarc != isarc) { + /* Map new data memory region */ +#ifdef DEBUG_OCM + printf("OCM map DSA %08x\n", dsarc); +#endif + cpu_register_physical_memory(dsarc, 0x04000000, + ocm->offset | IO_MEM_RAM); + } + } + } +} + +static target_ulong dcr_read_ocm (void *opaque, int dcrn) +{ + ppc405_ocm_t *ocm; + target_ulong ret; + + ocm = opaque; + switch (dcrn) { + case OCM0_ISARC: + ret = ocm->isarc; + break; + case OCM0_ISACNTL: + ret = ocm->isacntl; + break; + case OCM0_DSARC: + ret = ocm->dsarc; + break; + case OCM0_DSACNTL: + ret = ocm->dsacntl; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_ocm (void *opaque, int dcrn, target_ulong val) +{ + ppc405_ocm_t *ocm; + uint32_t isarc, dsarc, isacntl, dsacntl; + + ocm = opaque; + isarc = ocm->isarc; + dsarc = ocm->dsarc; + isacntl = ocm->isacntl; + dsacntl = ocm->dsacntl; + switch (dcrn) { + case OCM0_ISARC: + isarc = val & 0xFC000000; + break; + case OCM0_ISACNTL: + isacntl = val & 0xC0000000; + break; + case OCM0_DSARC: + isarc = val & 0xFC000000; + break; + case OCM0_DSACNTL: + isacntl = val & 0xC0000000; + break; + } + ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl); + ocm->isarc = isarc; + ocm->dsarc = dsarc; + ocm->isacntl = isacntl; + ocm->dsacntl = dsacntl; +} + +static void ocm_reset (void *opaque) +{ + ppc405_ocm_t *ocm; + uint32_t isarc, dsarc, isacntl, dsacntl; + + ocm = opaque; + isarc = 0x00000000; + isacntl = 0x00000000; + dsarc = 0x00000000; + dsacntl = 0x00000000; + ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl); + ocm->isarc = isarc; + ocm->dsarc = dsarc; + ocm->isacntl = isacntl; + ocm->dsacntl = dsacntl; +} + +void ppc405_ocm_init (CPUState *env, unsigned long offset) +{ + ppc405_ocm_t *ocm; + + ocm = qemu_mallocz(sizeof(ppc405_ocm_t)); + if (ocm != NULL) { + ocm->offset = offset; + ocm_reset(ocm); + qemu_register_reset(&ocm_reset, ocm); + ppc_dcr_register(env, OCM0_ISARC, + ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc_dcr_register(env, OCM0_ISACNTL, + ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc_dcr_register(env, OCM0_DSARC, + ocm, &dcr_read_ocm, &dcr_write_ocm); + ppc_dcr_register(env, OCM0_DSACNTL, + ocm, &dcr_read_ocm, &dcr_write_ocm); + } +} + +/*****************************************************************************/ +/* I2C controller */ +typedef struct ppc4xx_i2c_t ppc4xx_i2c_t; +struct ppc4xx_i2c_t { + uint32_t base; + uint8_t mdata; + uint8_t lmadr; + uint8_t hmadr; + uint8_t cntl; + uint8_t mdcntl; + uint8_t sts; + uint8_t extsts; + uint8_t sdata; + uint8_t lsadr; + uint8_t hsadr; + uint8_t clkdiv; + uint8_t intrmsk; + uint8_t xfrcnt; + uint8_t xtcntlss; + uint8_t directcntl; +}; + +static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr) +{ + ppc4xx_i2c_t *i2c; + uint32_t ret; + +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + i2c = opaque; + switch (addr - i2c->base) { + case 0x00: + // i2c_readbyte(&i2c->mdata); + ret = i2c->mdata; + break; + case 0x02: + ret = i2c->sdata; + break; + case 0x04: + ret = i2c->lmadr; + break; + case 0x05: + ret = i2c->hmadr; + break; + case 0x06: + ret = i2c->cntl; + break; + case 0x07: + ret = i2c->mdcntl; + break; + case 0x08: + ret = i2c->sts; + break; + case 0x09: + ret = i2c->extsts; + break; + case 0x0A: + ret = i2c->lsadr; + break; + case 0x0B: + ret = i2c->hsadr; + break; + case 0x0C: + ret = i2c->clkdiv; + break; + case 0x0D: + ret = i2c->intrmsk; + break; + case 0x0E: + ret = i2c->xfrcnt; + break; + case 0x0F: + ret = i2c->xtcntlss; + break; + case 0x10: + ret = i2c->directcntl; + break; + default: + ret = 0x00; + break; + } +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX " %02x\n", __func__, addr, ret); +#endif + + return ret; +} + +static void ppc4xx_i2c_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ppc4xx_i2c_t *i2c; + +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + i2c = opaque; + switch (addr - i2c->base) { + case 0x00: + i2c->mdata = value; + // i2c_sendbyte(&i2c->mdata); + break; + case 0x02: + i2c->sdata = value; + break; + case 0x04: + i2c->lmadr = value; + break; + case 0x05: + i2c->hmadr = value; + break; + case 0x06: + i2c->cntl = value; + break; + case 0x07: + i2c->mdcntl = value & 0xDF; + break; + case 0x08: + i2c->sts &= ~(value & 0x0A); + break; + case 0x09: + i2c->extsts &= ~(value & 0x8F); + break; + case 0x0A: + i2c->lsadr = value; + break; + case 0x0B: + i2c->hsadr = value; + break; + case 0x0C: + i2c->clkdiv = value; + break; + case 0x0D: + i2c->intrmsk = value; + break; + case 0x0E: + i2c->xfrcnt = value & 0x77; + break; + case 0x0F: + i2c->xtcntlss = value; + break; + case 0x10: + i2c->directcntl = value & 0x7; + break; + } +} + +static uint32_t ppc4xx_i2c_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + ret = ppc4xx_i2c_readb(opaque, addr) << 8; + ret |= ppc4xx_i2c_readb(opaque, addr + 1); + + return ret; +} + +static void ppc4xx_i2c_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + ppc4xx_i2c_writeb(opaque, addr, value >> 8); + ppc4xx_i2c_writeb(opaque, addr + 1, value); +} + +static uint32_t ppc4xx_i2c_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + ret = ppc4xx_i2c_readb(opaque, addr) << 24; + ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16; + ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8; + ret |= ppc4xx_i2c_readb(opaque, addr + 3); + + return ret; +} + +static void ppc4xx_i2c_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + ppc4xx_i2c_writeb(opaque, addr, value >> 24); + ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16); + ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8); + ppc4xx_i2c_writeb(opaque, addr + 3, value); +} + +static CPUReadMemoryFunc *i2c_read[] = { + &ppc4xx_i2c_readb, + &ppc4xx_i2c_readw, + &ppc4xx_i2c_readl, +}; + +static CPUWriteMemoryFunc *i2c_write[] = { + &ppc4xx_i2c_writeb, + &ppc4xx_i2c_writew, + &ppc4xx_i2c_writel, +}; + +static void ppc4xx_i2c_reset (void *opaque) +{ + ppc4xx_i2c_t *i2c; + + i2c = opaque; + i2c->mdata = 0x00; + i2c->sdata = 0x00; + i2c->cntl = 0x00; + i2c->mdcntl = 0x00; + i2c->sts = 0x00; + i2c->extsts = 0x00; + i2c->clkdiv = 0x00; + i2c->xfrcnt = 0x00; + i2c->directcntl = 0x0F; +} + +void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset) +{ + ppc4xx_i2c_t *i2c; + + i2c = qemu_mallocz(sizeof(ppc4xx_i2c_t)); + if (i2c != NULL) { + i2c->base = mmio->base + offset; + ppc4xx_i2c_reset(i2c); +#ifdef DEBUG_I2C + printf("%s: offset=%08x\n", __func__, offset); +#endif + ppc4xx_mmio_register(env, mmio, offset, 0x011, + i2c_read, i2c_write, i2c); + qemu_register_reset(ppc4xx_i2c_reset, i2c); + } +} + +/*****************************************************************************/ +/* SPR */ +void ppc40x_core_reset (CPUState *env) +{ + target_ulong dbsr; + + printf("Reset PowerPC core\n"); + cpu_ppc_reset(env); + dbsr = env->spr[SPR_40x_DBSR]; + dbsr &= ~0x00000300; + dbsr |= 0x00000100; + env->spr[SPR_40x_DBSR] = dbsr; + cpu_loop_exit(); +} + +void ppc40x_chip_reset (CPUState *env) +{ + target_ulong dbsr; + + printf("Reset PowerPC chip\n"); + cpu_ppc_reset(env); + /* XXX: TODO reset all internal peripherals */ + dbsr = env->spr[SPR_40x_DBSR]; + dbsr &= ~0x00000300; + dbsr |= 0x00000100; + env->spr[SPR_40x_DBSR] = dbsr; + cpu_loop_exit(); +} + +void ppc40x_system_reset (CPUState *env) +{ + printf("Reset PowerPC system\n"); + qemu_system_reset_request(); +} + +void store_40x_dbcr0 (CPUState *env, uint32_t val) +{ + switch ((val >> 28) & 0x3) { + case 0x0: + /* No action */ + break; + case 0x1: + /* Core reset */ + ppc40x_core_reset(env); + break; + case 0x2: + /* Chip reset */ + ppc40x_chip_reset(env); + break; + case 0x3: + /* System reset */ + ppc40x_system_reset(env); + break; + } +} + +/*****************************************************************************/ +/* PowerPC 405CR */ +enum { + PPC405CR_CPC0_PLLMR = 0x0B0, + PPC405CR_CPC0_CR0 = 0x0B1, + PPC405CR_CPC0_CR1 = 0x0B2, + PPC405CR_CPC0_PSR = 0x0B4, + PPC405CR_CPC0_JTAGID = 0x0B5, + PPC405CR_CPC0_ER = 0x0B9, + PPC405CR_CPC0_FR = 0x0BA, + PPC405CR_CPC0_SR = 0x0BB, +}; + +typedef struct ppc405cr_cpc_t ppc405cr_cpc_t; +struct ppc405cr_cpc_t { + clk_setup_t clk_setup[7]; + uint32_t sysclk; + uint32_t psr; + uint32_t cr0; + uint32_t cr1; + uint32_t jtagid; + uint32_t pllmr; + uint32_t er; + uint32_t fr; +}; + +static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc) +{ + uint64_t VCO_out, PLL_out; + uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk; + int M, D0, D1, D2; + + D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */ + if (cpc->pllmr & 0x80000000) { + D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */ + D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */ + M = D0 * D1 * D2; + VCO_out = cpc->sysclk * M; + if (VCO_out < 400000000 || VCO_out > 800000000) { + /* PLL cannot lock */ + cpc->pllmr &= ~0x80000000; + goto bypass_pll; + } + PLL_out = VCO_out / D2; + } else { + /* Bypass PLL */ + bypass_pll: + M = D0; + PLL_out = cpc->sysclk * M; + } + CPU_clk = PLL_out; + if (cpc->cr1 & 0x00800000) + TMR_clk = cpc->sysclk; /* Should have a separate clock */ + else + TMR_clk = CPU_clk; + PLB_clk = CPU_clk / D0; + SDRAM_clk = PLB_clk; + D0 = ((cpc->pllmr >> 10) & 0x3) + 1; + OPB_clk = PLB_clk / D0; + D0 = ((cpc->pllmr >> 24) & 0x3) + 2; + EXT_clk = PLB_clk / D0; + D0 = ((cpc->cr0 >> 1) & 0x1F) + 1; + UART_clk = CPU_clk / D0; + /* Setup CPU clocks */ + clk_setup(&cpc->clk_setup[0], CPU_clk); + /* Setup time-base clock */ + clk_setup(&cpc->clk_setup[1], TMR_clk); + /* Setup PLB clock */ + clk_setup(&cpc->clk_setup[2], PLB_clk); + /* Setup SDRAM clock */ + clk_setup(&cpc->clk_setup[3], SDRAM_clk); + /* Setup OPB clock */ + clk_setup(&cpc->clk_setup[4], OPB_clk); + /* Setup external clock */ + clk_setup(&cpc->clk_setup[5], EXT_clk); + /* Setup UART clock */ + clk_setup(&cpc->clk_setup[6], UART_clk); +} + +static target_ulong dcr_read_crcpc (void *opaque, int dcrn) +{ + ppc405cr_cpc_t *cpc; + target_ulong ret; + + cpc = opaque; + switch (dcrn) { + case PPC405CR_CPC0_PLLMR: + ret = cpc->pllmr; + break; + case PPC405CR_CPC0_CR0: + ret = cpc->cr0; + break; + case PPC405CR_CPC0_CR1: + ret = cpc->cr1; + break; + case PPC405CR_CPC0_PSR: + ret = cpc->psr; + break; + case PPC405CR_CPC0_JTAGID: + ret = cpc->jtagid; + break; + case PPC405CR_CPC0_ER: + ret = cpc->er; + break; + case PPC405CR_CPC0_FR: + ret = cpc->fr; + break; + case PPC405CR_CPC0_SR: + ret = ~(cpc->er | cpc->fr) & 0xFFFF0000; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_crcpc (void *opaque, int dcrn, target_ulong val) +{ + ppc405cr_cpc_t *cpc; + + cpc = opaque; + switch (dcrn) { + case PPC405CR_CPC0_PLLMR: + cpc->pllmr = val & 0xFFF77C3F; + break; + case PPC405CR_CPC0_CR0: + cpc->cr0 = val & 0x0FFFFFFE; + break; + case PPC405CR_CPC0_CR1: + cpc->cr1 = val & 0x00800000; + break; + case PPC405CR_CPC0_PSR: + /* Read-only */ + break; + case PPC405CR_CPC0_JTAGID: + /* Read-only */ + break; + case PPC405CR_CPC0_ER: + cpc->er = val & 0xBFFC0000; + break; + case PPC405CR_CPC0_FR: + cpc->fr = val & 0xBFFC0000; + break; + case PPC405CR_CPC0_SR: + /* Read-only */ + break; + } +} + +static void ppc405cr_cpc_reset (void *opaque) +{ + ppc405cr_cpc_t *cpc; + int D; + + cpc = opaque; + /* Compute PLLMR value from PSR settings */ + cpc->pllmr = 0x80000000; + /* PFWD */ + switch ((cpc->psr >> 30) & 3) { + case 0: + /* Bypass */ + cpc->pllmr &= ~0x80000000; + break; + case 1: + /* Divide by 3 */ + cpc->pllmr |= 5 << 16; + break; + case 2: + /* Divide by 4 */ + cpc->pllmr |= 4 << 16; + break; + case 3: + /* Divide by 6 */ + cpc->pllmr |= 2 << 16; + break; + } + /* PFBD */ + D = (cpc->psr >> 28) & 3; + cpc->pllmr |= (D + 1) << 20; + /* PT */ + D = (cpc->psr >> 25) & 7; + switch (D) { + case 0x2: + cpc->pllmr |= 0x13; + break; + case 0x4: + cpc->pllmr |= 0x15; + break; + case 0x5: + cpc->pllmr |= 0x16; + break; + default: + break; + } + /* PDC */ + D = (cpc->psr >> 23) & 3; + cpc->pllmr |= D << 26; + /* ODP */ + D = (cpc->psr >> 21) & 3; + cpc->pllmr |= D << 10; + /* EBPD */ + D = (cpc->psr >> 17) & 3; + cpc->pllmr |= D << 24; + cpc->cr0 = 0x0000003C; + cpc->cr1 = 0x2B0D8800; + cpc->er = 0x00000000; + cpc->fr = 0x00000000; + ppc405cr_clk_setup(cpc); +} + +static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc) +{ + int D; + + /* XXX: this should be read from IO pins */ + cpc->psr = 0x00000000; /* 8 bits ROM */ + /* PFWD */ + D = 0x2; /* Divide by 4 */ + cpc->psr |= D << 30; + /* PFBD */ + D = 0x1; /* Divide by 2 */ + cpc->psr |= D << 28; + /* PDC */ + D = 0x1; /* Divide by 2 */ + cpc->psr |= D << 23; + /* PT */ + D = 0x5; /* M = 16 */ + cpc->psr |= D << 25; + /* ODP */ + D = 0x1; /* Divide by 2 */ + cpc->psr |= D << 21; + /* EBDP */ + D = 0x2; /* Divide by 4 */ + cpc->psr |= D << 17; +} + +static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7], + uint32_t sysclk) +{ + ppc405cr_cpc_t *cpc; + + cpc = qemu_mallocz(sizeof(ppc405cr_cpc_t)); + if (cpc != NULL) { + memcpy(cpc->clk_setup, clk_setup, 7 * sizeof(clk_setup_t)); + cpc->sysclk = sysclk; + cpc->jtagid = 0x42051049; + ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc, + &dcr_read_crcpc, &dcr_write_crcpc); + ppc405cr_clk_init(cpc); + qemu_register_reset(ppc405cr_cpc_reset, cpc); + ppc405cr_cpc_reset(cpc); + } +} + +CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], + uint32_t sysclk, qemu_irq **picp, + ram_addr_t *offsetp) +{ + clk_setup_t clk_setup[7]; + qemu_irq dma_irqs[4]; + CPUState *env; + ppc4xx_mmio_t *mmio; + qemu_irq *pic, *irqs; + ram_addr_t offset; + int i; + + memset(clk_setup, 0, sizeof(clk_setup)); + env = ppc405_init("405cr", &clk_setup[0], &clk_setup[1], sysclk); + /* Memory mapped devices registers */ + mmio = ppc4xx_mmio_init(env, 0xEF600000); + /* PLB arbitrer */ + ppc4xx_plb_init(env); + /* PLB to OPB bridge */ + ppc4xx_pob_init(env); + /* OBP arbitrer */ + ppc4xx_opba_init(env, mmio, 0x600); + /* Universal interrupt controller */ + irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_CINT]; + pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); + *picp = pic; + /* SDRAM controller */ + ppc405_sdram_init(env, pic[17], 1, ram_bases, ram_sizes); + offset = 0; + for (i = 0; i < 4; i++) + offset += ram_sizes[i]; + /* External bus controller */ + ppc405_ebc_init(env); + /* DMA controller */ + dma_irqs[0] = pic[5]; + dma_irqs[1] = pic[6]; + dma_irqs[2] = pic[7]; + dma_irqs[3] = pic[8]; + ppc405_dma_init(env, dma_irqs); + /* Serial ports */ + if (serial_hds[0] != NULL) { + ppc405_serial_init(env, mmio, 0x400, pic[0], serial_hds[0]); + } + if (serial_hds[1] != NULL) { + ppc405_serial_init(env, mmio, 0x300, pic[1], serial_hds[1]); + } + /* IIC controller */ + ppc405_i2c_init(env, mmio, 0x500); + /* GPIO */ + ppc405_gpio_init(env, mmio, 0x700); + /* CPU control */ + ppc405cr_cpc_init(env, clk_setup, sysclk); + *offsetp = offset; + + return env; +} + +/*****************************************************************************/ +/* PowerPC 405EP */ +/* CPU control */ +enum { + PPC405EP_CPC0_PLLMR0 = 0x0F0, + PPC405EP_CPC0_BOOT = 0x0F1, + PPC405EP_CPC0_EPCTL = 0x0F3, + PPC405EP_CPC0_PLLMR1 = 0x0F4, + PPC405EP_CPC0_UCR = 0x0F5, + PPC405EP_CPC0_SRR = 0x0F6, + PPC405EP_CPC0_JTAGID = 0x0F7, + PPC405EP_CPC0_PCI = 0x0F9, +}; + +typedef struct ppc405ep_cpc_t ppc405ep_cpc_t; +struct ppc405ep_cpc_t { + uint32_t sysclk; + clk_setup_t clk_setup[8]; + uint32_t boot; + uint32_t epctl; + uint32_t pllmr[2]; + uint32_t ucr; + uint32_t srr; + uint32_t jtagid; + uint32_t pci; +}; + +static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) +{ + uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk; + uint32_t UART0_clk, UART1_clk; + uint64_t VCO_out, PLL_out; + int M, D; + + VCO_out = 0; + if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) { + M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */ + // printf("FBMUL %01x %d\n", (cpc->pllmr[1] >> 20) & 0xF, M); + D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */ + // printf("FWDA %01x %d\n", (cpc->pllmr[1] >> 16) & 0x7, D); + VCO_out = cpc->sysclk * M * D; + if (VCO_out < 500000000UL || VCO_out > 1000000000UL) { + /* Error - unlock the PLL */ + printf("VCO out of range %" PRIu64 "\n", VCO_out); +#if 0 + cpc->pllmr[1] &= ~0x80000000; + goto pll_bypass; +#endif + } + PLL_out = VCO_out / D; + } else { +#if 0 + pll_bypass: +#endif + PLL_out = cpc->sysclk; + } + /* Now, compute all other clocks */ + D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */ +#ifdef DEBUG_CLOCKS + // printf("CCDV %01x %d\n", (cpc->pllmr[0] >> 20) & 0x3, D); +#endif + CPU_clk = PLL_out / D; + D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */ +#ifdef DEBUG_CLOCKS + // printf("CBDV %01x %d\n", (cpc->pllmr[0] >> 16) & 0x3, D); +#endif + PLB_clk = CPU_clk / D; + D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */ +#ifdef DEBUG_CLOCKS + // printf("OPDV %01x %d\n", (cpc->pllmr[0] >> 12) & 0x3, D); +#endif + OPB_clk = PLB_clk / D; + D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */ +#ifdef DEBUG_CLOCKS + // printf("EPDV %01x %d\n", (cpc->pllmr[0] >> 8) & 0x3, D); +#endif + EBC_clk = PLB_clk / D; + D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */ +#ifdef DEBUG_CLOCKS + // printf("MPDV %01x %d\n", (cpc->pllmr[0] >> 4) & 0x3, D); +#endif + MAL_clk = PLB_clk / D; + D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */ +#ifdef DEBUG_CLOCKS + // printf("PPDV %01x %d\n", cpc->pllmr[0] & 0x3, D); +#endif + PCI_clk = PLB_clk / D; + D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */ +#ifdef DEBUG_CLOCKS + // printf("U0DIV %01x %d\n", cpc->ucr & 0x7F, D); +#endif + UART0_clk = PLL_out / D; + D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */ +#ifdef DEBUG_CLOCKS + // printf("U1DIV %01x %d\n", (cpc->ucr >> 8) & 0x7F, D); +#endif + UART1_clk = PLL_out / D; +#ifdef DEBUG_CLOCKS + printf("Setup PPC405EP clocks - sysclk %d VCO %" PRIu64 + " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out); + printf("CPU %d PLB %d OPB %d EBC %d MAL %d PCI %d UART0 %d UART1 %d\n", + CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk, + UART0_clk, UART1_clk); +#endif + /* Setup CPU clocks */ + clk_setup(&cpc->clk_setup[0], CPU_clk); + /* Setup PLB clock */ + clk_setup(&cpc->clk_setup[1], PLB_clk); + /* Setup OPB clock */ + clk_setup(&cpc->clk_setup[2], OPB_clk); + /* Setup external clock */ + clk_setup(&cpc->clk_setup[3], EBC_clk); + /* Setup MAL clock */ + clk_setup(&cpc->clk_setup[4], MAL_clk); + /* Setup PCI clock */ + clk_setup(&cpc->clk_setup[5], PCI_clk); + /* Setup UART0 clock */ + clk_setup(&cpc->clk_setup[6], UART0_clk); + /* Setup UART1 clock */ + clk_setup(&cpc->clk_setup[7], UART0_clk); +} + +static target_ulong dcr_read_epcpc (void *opaque, int dcrn) +{ + ppc405ep_cpc_t *cpc; + target_ulong ret; + + cpc = opaque; + switch (dcrn) { + case PPC405EP_CPC0_BOOT: + ret = cpc->boot; + break; + case PPC405EP_CPC0_EPCTL: + ret = cpc->epctl; + break; + case PPC405EP_CPC0_PLLMR0: + ret = cpc->pllmr[0]; + break; + case PPC405EP_CPC0_PLLMR1: + ret = cpc->pllmr[1]; + break; + case PPC405EP_CPC0_UCR: + ret = cpc->ucr; + break; + case PPC405EP_CPC0_SRR: + ret = cpc->srr; + break; + case PPC405EP_CPC0_JTAGID: + ret = cpc->jtagid; + break; + case PPC405EP_CPC0_PCI: + ret = cpc->pci; + break; + default: + /* Avoid gcc warning */ + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_epcpc (void *opaque, int dcrn, target_ulong val) +{ + ppc405ep_cpc_t *cpc; + + cpc = opaque; + switch (dcrn) { + case PPC405EP_CPC0_BOOT: + /* Read-only register */ + break; + case PPC405EP_CPC0_EPCTL: + /* Don't care for now */ + cpc->epctl = val & 0xC00000F3; + break; + case PPC405EP_CPC0_PLLMR0: + cpc->pllmr[0] = val & 0x00633333; + ppc405ep_compute_clocks(cpc); + break; + case PPC405EP_CPC0_PLLMR1: + cpc->pllmr[1] = val & 0xC0F73FFF; + ppc405ep_compute_clocks(cpc); + break; + case PPC405EP_CPC0_UCR: + /* UART control - don't care for now */ + cpc->ucr = val & 0x003F7F7F; + break; + case PPC405EP_CPC0_SRR: + cpc->srr = val; + break; + case PPC405EP_CPC0_JTAGID: + /* Read-only */ + break; + case PPC405EP_CPC0_PCI: + cpc->pci = val; + break; + } +} + +static void ppc405ep_cpc_reset (void *opaque) +{ + ppc405ep_cpc_t *cpc = opaque; + + cpc->boot = 0x00000010; /* Boot from PCI - IIC EEPROM disabled */ + cpc->epctl = 0x00000000; + cpc->pllmr[0] = 0x00011010; + cpc->pllmr[1] = 0x40000000; + cpc->ucr = 0x00000000; + cpc->srr = 0x00040000; + cpc->pci = 0x00000000; + ppc405ep_compute_clocks(cpc); +} + +/* XXX: sysclk should be between 25 and 100 MHz */ +static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8], + uint32_t sysclk) +{ + ppc405ep_cpc_t *cpc; + + cpc = qemu_mallocz(sizeof(ppc405ep_cpc_t)); + if (cpc != NULL) { + memcpy(cpc->clk_setup, clk_setup, 7 * sizeof(clk_setup_t)); + cpc->jtagid = 0x20267049; + cpc->sysclk = sysclk; + ppc405ep_cpc_reset(cpc); + qemu_register_reset(&ppc405ep_cpc_reset, cpc); + ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + } +} + +CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], + uint32_t sysclk, qemu_irq **picp, + ram_addr_t *offsetp) +{ + clk_setup_t clk_setup[8]; + qemu_irq dma_irqs[4]; + CPUState *env; + ppc4xx_mmio_t *mmio; + qemu_irq *pic, *irqs; + ram_addr_t offset; + int i; + + memset(clk_setup, 0, sizeof(clk_setup)); + /* init CPUs */ + env = ppc405_init("405ep", &clk_setup[0], &clk_setup[1], sysclk); + /* Internal devices init */ + /* Memory mapped devices registers */ + mmio = ppc4xx_mmio_init(env, 0xEF600000); + /* PLB arbitrer */ + ppc4xx_plb_init(env); + /* PLB to OPB bridge */ + ppc4xx_pob_init(env); + /* OBP arbitrer */ + ppc4xx_opba_init(env, mmio, 0x600); + /* Universal interrupt controller */ + irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_CINT]; + pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); + *picp = pic; + /* SDRAM controller */ + ppc405_sdram_init(env, pic[17], 2, ram_bases, ram_sizes); + offset = 0; + for (i = 0; i < 2; i++) + offset += ram_sizes[i]; + /* External bus controller */ + ppc405_ebc_init(env); + /* DMA controller */ + dma_irqs[0] = pic[5]; + dma_irqs[1] = pic[6]; + dma_irqs[2] = pic[7]; + dma_irqs[3] = pic[8]; + ppc405_dma_init(env, dma_irqs); + /* IIC controller */ + ppc405_i2c_init(env, mmio, 0x500); + /* GPIO */ + ppc405_gpio_init(env, mmio, 0x700); + /* Serial ports */ + if (serial_hds[0] != NULL) { + ppc405_serial_init(env, mmio, 0x300, pic[0], serial_hds[0]); + } + if (serial_hds[1] != NULL) { + ppc405_serial_init(env, mmio, 0x400, pic[1], serial_hds[1]); + } + /* OCM */ + ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]); + offset += 4096; + /* PCI */ + /* CPU control */ + ppc405ep_cpc_init(env, clk_setup, sysclk); + *offsetp = offset; + + return env; +} diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index eb3340c52..f17f84641 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -880,6 +880,7 @@ void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value); void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value); target_ulong load_40x_pit (CPUPPCState *env); void store_40x_pit (CPUPPCState *env, target_ulong val); +void store_40x_dbcr0 (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void ppc_tlb_invalidate_all (CPUPPCState *env); diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 87e8c1836..a0f91ccd4 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -109,6 +109,7 @@ void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, int is_code); void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1); +void ppc4xx_tlb_invalidate_all (CPUState *env); static inline void env_to_regs(void) { diff --git a/target-ppc/op.c b/target-ppc/op.c index 68828f5f1..b8498f182 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2454,6 +2454,11 @@ void OPPROTO op_store_40x_pit (void) RETURN(); } +void OPPROTO op_store_40x_dbcr0 (void) +{ + store_40x_dbcr0(env, T0); +} + void OPPROTO op_store_booke_tcr (void) { store_booke_tcr(env, T0); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 215bdcbe6..cb40dfbdd 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -344,6 +344,15 @@ static void spr_write_40x_pit (void *opaque, int sprn) gen_op_store_40x_pit(); } +static void spr_write_40x_dbcr0 (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_40x_dbcr0(); + /* We must stop translation as we may have rebooted */ + RET_STOP(ctx); +} + static void spr_write_booke_tcr (void *opaque, int sprn) { gen_op_store_booke_tcr(); @@ -1175,7 +1184,7 @@ static void gen_spr_BookE (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_BOOKE_DBSR, "DBSR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_clear, 0x00000000); spr_register(env, SPR_BOOKE_DEAR, "DEAR", SPR_NOACCESS, SPR_NOACCESS, @@ -1651,13 +1660,13 @@ static void gen_spr_40x (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_40x_DBCR0, "DBCR0", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_40x_dbcr0, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_40x_DBSR, "DBSR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - /* Last reset was system reset (system boot */ + &spr_read_generic, &spr_write_clear, + /* Last reset was system reset */ 0x00000300); /* XXX : not implemented */ spr_register(env, SPR_40x_IAC1, "IAC1", @@ -1751,17 +1760,6 @@ static void gen_spr_405 (CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* Debug */ - /* XXX : not implemented */ - spr_register(env, SPR_40x_DAC2, "DAC2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_40x_IAC2, "IAC2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); } /* SPR shared between PowerPC 401 & 403 implementations */ diff --git a/vl.h b/vl.h index b0e37dd78..fbad5e2a1 100644 --- a/vl.h +++ b/vl.h @@ -1151,7 +1151,19 @@ extern QEMUMachine shix_machine; #ifdef TARGET_PPC /* PowerPC hardware exceptions management helpers */ -ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); +typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); +typedef struct clk_setup_t clk_setup_t; +struct clk_setup_t { + clk_setup_cb cb; + void *opaque; +}; +static inline void clk_setup (clk_setup_t *clk, uint32_t freq) +{ + if (clk->cb != NULL) + (*clk->cb)(clk->opaque, freq); +} + +clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq); /* Embedded PowerPC DCR management */ typedef target_ulong (*dcr_read_cb)(void *opaque, int dcrn); typedef void (*dcr_write_cb)(void *opaque, int dcrn, target_ulong val); @@ -1159,6 +1171,59 @@ int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn), int (*dcr_write_error)(int dcrn)); int ppc_dcr_register (CPUState *env, int dcrn, void *opaque, dcr_read_cb drc_read, dcr_write_cb dcr_write); +clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq); +/* PowerPC 405 core */ +CPUPPCState *ppc405_init (const unsigned char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk); +void ppc40x_core_reset (CPUState *env); +void ppc40x_chip_reset (CPUState *env); +void ppc40x_system_reset (CPUState *env); +/* */ +typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; +int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, + uint32_t offset, uint32_t len, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, void *opaque); +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, uint32_t base); +/* PowerPC 4xx peripheral local bus arbitrer */ +void ppc4xx_plb_init (CPUState *env); +/* PLB to OPB bridge */ +void ppc4xx_pob_init (CPUState *env); +/* OPB arbitrer */ +void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +/* PowerPC 4xx universal interrupt controller */ +enum { + PPCUIC_OUTPUT_INT = 0, + PPCUIC_OUTPUT_CINT = 1, + PPCUIC_OUTPUT_NB, +}; +qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, + uint32_t dcr_base, int has_ssr, int has_vr); +/* SDRAM controller */ +void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, + target_ulong *ram_bases, target_ulong *ram_sizes); +/* Peripheral controller */ +void ppc405_ebc_init (CPUState *env); +/* DMA controller */ +void ppc405_dma_init (CPUState *env, qemu_irq irqs[4]); +/* GPIO */ +void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +/* Serial ports */ +void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio, + uint32_t offset, qemu_irq irq, + CharDriverState *chr); +/* On Chip Memory */ +void ppc405_ocm_init (CPUState *env, unsigned long offset); +/* I2C controller */ +void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +/* PowerPC 405 microcontrollers */ +CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], + uint32_t sysclk, qemu_irq **picp, + ram_addr_t *offsetp); +CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], + uint32_t sysclk, qemu_irq **picp, + ram_addr_t *offsetp); #endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); -- cgit v1.2.3 From 80355292503667b5367f09ec8716126c3caa1e3a Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 16 Apr 2007 22:47:54 +0000 Subject: Support it_shift for mmapped pckbd. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2691 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index 52b65d7d9..de508b309 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -125,6 +125,7 @@ typedef struct KBDState { qemu_irq irq_kbd; qemu_irq irq_mouse; target_phys_addr_t base; + int it_shift; } KBDState; KBDState kbd_state; @@ -384,21 +385,28 @@ uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr) { KBDState *s = opaque; - if (addr == s->base) - return kbd_read_data(s, 0); - else - return kbd_read_status(s, 0); + switch ((addr - s->base) >> s->it_shift) { + case 0: + return kbd_read_data(s, 0) & 0xff; + case 1: + return kbd_read_status(s, 0) & 0xff; + default: + return 0xff; + } } -void kbd_mm_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) +void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { KBDState *s = opaque; - if (addr == s->base) - kbd_write_data(s, 0, value); - else - kbd_write_command(s, 0, value); + switch ((addr - s->base) >> s->it_shift) { + case 0: + kbd_write_data(s, 0, value & 0xff); + break; + case 1: + kbd_write_command(s, 0, value & 0xff); + break; + } } static CPUReadMemoryFunc *kbd_mm_read[] = { @@ -413,7 +421,8 @@ static CPUWriteMemoryFunc *kbd_mm_write[] = { &kbd_mm_writeb, }; -void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, int it_shift) +void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, + int it_shift) { KBDState *s = &kbd_state; int s_io_memory; @@ -421,11 +430,12 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, int s->irq_kbd = kbd_irq; s->irq_mouse = mouse_irq; s->base = base; + s->it_shift = it_shift; kbd_reset(s); register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); s_io_memory = cpu_register_io_memory(0, kbd_mm_read, kbd_mm_write, s); - cpu_register_physical_memory(base & ~(TARGET_PAGE_SIZE - 1), TARGET_PAGE_SIZE, s_io_memory); + cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); -- cgit v1.2.3 From 04f20795ac815cf3ad5d1fdc99462f60eb871f25 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 17 Apr 2007 02:50:56 +0000 Subject: Move PowerPC 405 specific definitions into a separate file Preliminary code for -kernel option support for PowerPC 405 boards Fix DBSR in case of PowerPC 405 chip reset Add enums for PowerPC 405 clocks. Fix IRQ numbers (IBM reversed bits numbering...) Fix SPRG4-7 read access right Fix MSR mask in CPU definitions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2692 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405.h | 117 +++++++++++++++++++++++ hw/ppc405_uc.c | 162 +++++++++++++++++++++++--------- target-ppc/translate_init.c | 220 ++++++++++++++++++++++---------------------- vl.h | 52 ----------- 4 files changed, 347 insertions(+), 204 deletions(-) create mode 100644 hw/ppc405.h diff --git a/hw/ppc405.h b/hw/ppc405.h new file mode 100644 index 000000000..e3a544dd1 --- /dev/null +++ b/hw/ppc405.h @@ -0,0 +1,117 @@ +/* + * QEMU PowerPC 405 shared definitions + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if !defined(PPC_405_H) +#define PPC_405_H + +/* Bootinfo as set-up by u-boot */ +typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t; +struct ppc4xx_bd_info_t { + uint32_t bi_memstart; + uint32_t bi_memsize; + uint32_t bi_flashstart; + uint32_t bi_flashsize; + uint32_t bi_flashoffset; /* 0x10 */ + uint32_t bi_sramstart; + uint32_t bi_sramsize; + uint32_t bi_bootflags; + uint32_t bi_ipaddr; /* 0x20 */ + uint8_t bi_enetaddr[6]; + uint16_t bi_ethspeed; + uint32_t bi_intfreq; + uint32_t bi_busfreq; /* 0x30 */ + uint32_t bi_baudrate; + uint8_t bi_s_version[4]; + uint8_t bi_r_version[32]; + uint32_t bi_procfreq; + uint32_t bi_plb_busfreq; + uint32_t bi_pci_busfreq; + uint8_t bi_pci_enetaddr[6]; + uint32_t bi_pci_enetaddr2[6]; + uint32_t bi_opbfreq; + uint32_t bi_iic_fast[2]; +}; + +/* PowerPC 405 core */ +CPUState *ppc405_init (const unsigned char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk); +ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd); + +void ppc40x_core_reset (CPUState *env); +void ppc40x_chip_reset (CPUState *env); +void ppc40x_system_reset (CPUState *env); +/* */ +typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; +int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, + uint32_t offset, uint32_t len, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, void *opaque); +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, uint32_t base); +/* PowerPC 4xx peripheral local bus arbitrer */ +void ppc4xx_plb_init (CPUState *env); +/* PLB to OPB bridge */ +void ppc4xx_pob_init (CPUState *env); +/* OPB arbitrer */ +void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +/* PowerPC 4xx universal interrupt controller */ +enum { + PPCUIC_OUTPUT_INT = 0, + PPCUIC_OUTPUT_CINT = 1, + PPCUIC_OUTPUT_NB, +}; +qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, + uint32_t dcr_base, int has_ssr, int has_vr); +/* SDRAM controller */ +void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, + target_ulong *ram_bases, target_ulong *ram_sizes, + int do_init); +/* Peripheral controller */ +void ppc405_ebc_init (CPUState *env); +/* DMA controller */ +void ppc405_dma_init (CPUState *env, qemu_irq irqs[4]); +/* GPIO */ +void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +/* Serial ports */ +void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio, + uint32_t offset, qemu_irq irq, + CharDriverState *chr); +/* On Chip Memory */ +void ppc405_ocm_init (CPUState *env, unsigned long offset); +/* I2C controller */ +void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +/* PowerPC 405 microcontrollers */ +CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], + uint32_t sysclk, qemu_irq **picp, + ram_addr_t *offsetp, int do_init); +CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], + uint32_t sysclk, qemu_irq **picp, + ram_addr_t *offsetp, int do_init); +/* IBM STBxxx microcontrollers */ +CPUState *ppc_stb025_init (target_ulong ram_bases[2], + target_ulong ram_sizes[2], + uint32_t sysclk, qemu_irq **picp, + ram_addr_t *offsetp); + +#endif /* !defined(PPC_405_H) */ diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 0b7ef1273..f5c1c31bd 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include "ppc405.h" extern int loglevel; extern FILE *logfile; @@ -66,6 +67,51 @@ CPUState *ppc405_init (const unsigned char *cpu_model, return env; } +ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd) +{ + ram_addr_t bdloc; + int i, n; + + /* We put the bd structure at the top of memory */ + bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t); + stl_raw(phys_ram_base + bdloc + 0x00, bd->bi_memstart); + stl_raw(phys_ram_base + bdloc + 0x04, bd->bi_memsize); + stl_raw(phys_ram_base + bdloc + 0x08, bd->bi_flashstart); + stl_raw(phys_ram_base + bdloc + 0x0C, bd->bi_flashsize); + stl_raw(phys_ram_base + bdloc + 0x10, bd->bi_flashoffset); + stl_raw(phys_ram_base + bdloc + 0x14, bd->bi_sramstart); + stl_raw(phys_ram_base + bdloc + 0x18, bd->bi_sramsize); + stl_raw(phys_ram_base + bdloc + 0x1C, bd->bi_bootflags); + stl_raw(phys_ram_base + bdloc + 0x20, bd->bi_ipaddr); + for (i = 0; i < 6; i++) + stb_raw(phys_ram_base + bdloc + 0x24 + i, bd->bi_enetaddr[i]); + stw_raw(phys_ram_base + bdloc + 0x2A, bd->bi_ethspeed); + stl_raw(phys_ram_base + bdloc + 0x2C, bd->bi_intfreq); + stl_raw(phys_ram_base + bdloc + 0x30, bd->bi_busfreq); + stl_raw(phys_ram_base + bdloc + 0x34, bd->bi_baudrate); + for (i = 0; i < 4; i++) + stb_raw(phys_ram_base + bdloc + 0x38 + i, bd->bi_s_version[i]); + for (i = 0; i < 32; i++) + stb_raw(phys_ram_base + bdloc + 0x3C + i, bd->bi_s_version[i]); + stl_raw(phys_ram_base + bdloc + 0x5C, bd->bi_plb_busfreq); + stl_raw(phys_ram_base + bdloc + 0x60, bd->bi_pci_busfreq); + for (i = 0; i < 6; i++) + stb_raw(phys_ram_base + bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]); + n = 0x6A; + if (env->spr[SPR_PVR] == CPU_PPC_405EP) { + for (i = 0; i < 6; i++) + stb_raw(phys_ram_base + bdloc + n++, bd->bi_pci_enetaddr2[i]); + } + stl_raw(phys_ram_base + bdloc + n, bd->bi_opbfreq); + n += 4; + for (i = 0; i < 2; i++) { + stl_raw(phys_ram_base + bdloc + n, bd->bi_iic_fast[i]); + n += 4; + } + + return bdloc; +} + /*****************************************************************************/ /* Shared peripherals */ @@ -960,6 +1006,10 @@ static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) int i; for (i = 0; i < sdram->nbanks; i++) { +#ifdef DEBUG_SDRAM + printf("%s: Unmap RAM area " ADDRX " " ADDRX "\n", __func__, + sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); +#endif cpu_register_physical_memory(sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]), IO_MEM_UNASSIGNED); @@ -1141,7 +1191,8 @@ static void sdram_reset (void *opaque) } void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, - target_ulong *ram_bases, target_ulong *ram_sizes) + target_ulong *ram_bases, target_ulong *ram_sizes, + int do_init) { ppc4xx_sdram_t *sdram; @@ -1159,6 +1210,8 @@ void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, sdram, &dcr_read_sdram, &dcr_write_sdram); ppc_dcr_register(env, SDRAM0_CFGDATA, sdram, &dcr_read_sdram, &dcr_write_sdram); + if (do_init) + sdram_map_bcr(sdram); } } @@ -2079,7 +2132,7 @@ void ppc40x_chip_reset (CPUState *env) /* XXX: TODO reset all internal peripherals */ dbsr = env->spr[SPR_40x_DBSR]; dbsr &= ~0x00000300; - dbsr |= 0x00000100; + dbsr |= 0x00000200; env->spr[SPR_40x_DBSR] = dbsr; cpu_loop_exit(); } @@ -2124,9 +2177,20 @@ enum { PPC405CR_CPC0_SR = 0x0BB, }; +enum { + PPC405CR_CPU_CLK = 0, + PPC405CR_TMR_CLK = 1, + PPC405CR_PLB_CLK = 2, + PPC405CR_SDRAM_CLK = 3, + PPC405CR_OPB_CLK = 4, + PPC405CR_EXT_CLK = 5, + PPC405CR_UART_CLK = 6, + PPC405CR_CLK_NB = 7, +}; + typedef struct ppc405cr_cpc_t ppc405cr_cpc_t; struct ppc405cr_cpc_t { - clk_setup_t clk_setup[7]; + clk_setup_t clk_setup[PPC405CR_CLK_NB]; uint32_t sysclk; uint32_t psr; uint32_t cr0; @@ -2175,19 +2239,19 @@ static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc) D0 = ((cpc->cr0 >> 1) & 0x1F) + 1; UART_clk = CPU_clk / D0; /* Setup CPU clocks */ - clk_setup(&cpc->clk_setup[0], CPU_clk); + clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk); /* Setup time-base clock */ - clk_setup(&cpc->clk_setup[1], TMR_clk); + clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk); /* Setup PLB clock */ - clk_setup(&cpc->clk_setup[2], PLB_clk); + clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk); /* Setup SDRAM clock */ - clk_setup(&cpc->clk_setup[3], SDRAM_clk); + clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk); /* Setup OPB clock */ - clk_setup(&cpc->clk_setup[4], OPB_clk); + clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk); /* Setup external clock */ - clk_setup(&cpc->clk_setup[5], EXT_clk); + clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk); /* Setup UART clock */ - clk_setup(&cpc->clk_setup[6], UART_clk); + clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk); } static target_ulong dcr_read_crcpc (void *opaque, int dcrn) @@ -2357,7 +2421,8 @@ static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7], cpc = qemu_mallocz(sizeof(ppc405cr_cpc_t)); if (cpc != NULL) { - memcpy(cpc->clk_setup, clk_setup, 7 * sizeof(clk_setup_t)); + memcpy(cpc->clk_setup, clk_setup, + PPC405CR_CLK_NB * sizeof(clk_setup_t)); cpc->sysclk = sysclk; cpc->jtagid = 0x42051049; ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc, @@ -2384,9 +2449,9 @@ static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7], CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], uint32_t sysclk, qemu_irq **picp, - ram_addr_t *offsetp) + ram_addr_t *offsetp, int do_init) { - clk_setup_t clk_setup[7]; + clk_setup_t clk_setup[PPC405CR_CLK_NB]; qemu_irq dma_irqs[4]; CPUState *env; ppc4xx_mmio_t *mmio; @@ -2395,7 +2460,8 @@ CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], int i; memset(clk_setup, 0, sizeof(clk_setup)); - env = ppc405_init("405cr", &clk_setup[0], &clk_setup[1], sysclk); + env = ppc405_init("405cr", &clk_setup[PPC405CR_CPU_CLK], + &clk_setup[PPC405CR_TMR_CLK], sysclk); /* Memory mapped devices registers */ mmio = ppc4xx_mmio_init(env, 0xEF600000); /* PLB arbitrer */ @@ -2413,24 +2479,24 @@ CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); *picp = pic; /* SDRAM controller */ - ppc405_sdram_init(env, pic[17], 1, ram_bases, ram_sizes); + ppc405_sdram_init(env, pic[14], 1, ram_bases, ram_sizes, do_init); offset = 0; for (i = 0; i < 4; i++) offset += ram_sizes[i]; /* External bus controller */ ppc405_ebc_init(env); /* DMA controller */ - dma_irqs[0] = pic[5]; - dma_irqs[1] = pic[6]; - dma_irqs[2] = pic[7]; - dma_irqs[3] = pic[8]; + dma_irqs[0] = pic[26]; + dma_irqs[1] = pic[25]; + dma_irqs[2] = pic[24]; + dma_irqs[3] = pic[23]; ppc405_dma_init(env, dma_irqs); /* Serial ports */ if (serial_hds[0] != NULL) { - ppc405_serial_init(env, mmio, 0x400, pic[0], serial_hds[0]); + ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]); } if (serial_hds[1] != NULL) { - ppc405_serial_init(env, mmio, 0x300, pic[1], serial_hds[1]); + ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]); } /* IIC controller */ ppc405_i2c_init(env, mmio, 0x500); @@ -2457,10 +2523,22 @@ enum { PPC405EP_CPC0_PCI = 0x0F9, }; +enum { + PPC405EP_CPU_CLK = 0, + PPC405EP_PLB_CLK = 1, + PPC405EP_OPB_CLK = 2, + PPC405EP_EBC_CLK = 3, + PPC405EP_MAL_CLK = 4, + PPC405EP_PCI_CLK = 5, + PPC405EP_UART0_CLK = 6, + PPC405EP_UART1_CLK = 7, + PPC405EP_CLK_NB = 8, +}; + typedef struct ppc405ep_cpc_t ppc405ep_cpc_t; struct ppc405ep_cpc_t { uint32_t sysclk; - clk_setup_t clk_setup[8]; + clk_setup_t clk_setup[PPC405EP_CLK_NB]; uint32_t boot; uint32_t epctl; uint32_t pllmr[2]; @@ -2548,21 +2626,21 @@ static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) UART0_clk, UART1_clk); #endif /* Setup CPU clocks */ - clk_setup(&cpc->clk_setup[0], CPU_clk); + clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk); /* Setup PLB clock */ - clk_setup(&cpc->clk_setup[1], PLB_clk); + clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk); /* Setup OPB clock */ - clk_setup(&cpc->clk_setup[2], OPB_clk); + clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk); /* Setup external clock */ - clk_setup(&cpc->clk_setup[3], EBC_clk); + clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk); /* Setup MAL clock */ - clk_setup(&cpc->clk_setup[4], MAL_clk); + clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk); /* Setup PCI clock */ - clk_setup(&cpc->clk_setup[5], PCI_clk); + clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk); /* Setup UART0 clock */ - clk_setup(&cpc->clk_setup[6], UART0_clk); + clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk); /* Setup UART1 clock */ - clk_setup(&cpc->clk_setup[7], UART0_clk); + clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk); } static target_ulong dcr_read_epcpc (void *opaque, int dcrn) @@ -2664,7 +2742,8 @@ static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8], cpc = qemu_mallocz(sizeof(ppc405ep_cpc_t)); if (cpc != NULL) { - memcpy(cpc->clk_setup, clk_setup, 7 * sizeof(clk_setup_t)); + memcpy(cpc->clk_setup, clk_setup, + PPC405EP_CLK_NB * sizeof(clk_setup_t)); cpc->jtagid = 0x20267049; cpc->sysclk = sysclk; ppc405ep_cpc_reset(cpc); @@ -2690,9 +2769,9 @@ static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8], CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], uint32_t sysclk, qemu_irq **picp, - ram_addr_t *offsetp) + ram_addr_t *offsetp, int do_init) { - clk_setup_t clk_setup[8]; + clk_setup_t clk_setup[PPC405EP_CLK_NB]; qemu_irq dma_irqs[4]; CPUState *env; ppc4xx_mmio_t *mmio; @@ -2702,7 +2781,8 @@ CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], memset(clk_setup, 0, sizeof(clk_setup)); /* init CPUs */ - env = ppc405_init("405ep", &clk_setup[0], &clk_setup[1], sysclk); + env = ppc405_init("405ep", &clk_setup[PPC405EP_CPU_CLK], + &clk_setup[PPC405EP_PLB_CLK], sysclk); /* Internal devices init */ /* Memory mapped devices registers */ mmio = ppc4xx_mmio_init(env, 0xEF600000); @@ -2721,17 +2801,17 @@ CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); *picp = pic; /* SDRAM controller */ - ppc405_sdram_init(env, pic[17], 2, ram_bases, ram_sizes); + ppc405_sdram_init(env, pic[14], 2, ram_bases, ram_sizes, do_init); offset = 0; for (i = 0; i < 2; i++) offset += ram_sizes[i]; /* External bus controller */ ppc405_ebc_init(env); /* DMA controller */ - dma_irqs[0] = pic[5]; - dma_irqs[1] = pic[6]; - dma_irqs[2] = pic[7]; - dma_irqs[3] = pic[8]; + dma_irqs[0] = pic[26]; + dma_irqs[1] = pic[25]; + dma_irqs[2] = pic[24]; + dma_irqs[3] = pic[23]; ppc405_dma_init(env, dma_irqs); /* IIC controller */ ppc405_i2c_init(env, mmio, 0x500); @@ -2739,10 +2819,10 @@ CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], ppc405_gpio_init(env, mmio, 0x700); /* Serial ports */ if (serial_hds[0] != NULL) { - ppc405_serial_init(env, mmio, 0x300, pic[0], serial_hds[0]); + ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]); } if (serial_hds[1] != NULL) { - ppc405_serial_init(env, mmio, 0x400, pic[1], serial_hds[1]); + ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]); } /* OCM */ ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index cb40dfbdd..0868f308c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -53,25 +53,27 @@ PPC_IRQ_INIT_FN(970); /* Generic callbacks: * do nothing but store/retrieve spr value */ +#ifdef PPC_DUMP_SPR_ACCESSES static void spr_read_generic (void *opaque, int sprn) { - gen_op_load_spr(sprn); + gen_op_load_dump_spr(sprn); } static void spr_write_generic (void *opaque, int sprn) { - gen_op_store_spr(sprn); + gen_op_store_dump_spr(sprn); } - -static void spr_read_dump (void *opaque, int sprn) +#else +static void spr_read_generic (void *opaque, int sprn) { - gen_op_load_dump_spr(sprn); + gen_op_load_spr(sprn); } -static void spr_write_dump (void *opaque, int sprn) +static void spr_write_generic (void *opaque, int sprn) { - gen_op_store_dump_spr(sprn); + gen_op_store_spr(sprn); } +#endif #if !defined(CONFIG_USER_ONLY) static void spr_write_clear (void *opaque, int sprn) @@ -1730,7 +1732,7 @@ static void gen_spr_405 (CPUPPCState *env) 0x00000000); spr_register(env, SPR_SPRG4, "SPRG4", SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, + &spr_read_generic, &spr_write_generic, 0x00000000); spr_register(env, SPR_USPRG4, "USPRG4", &spr_read_ureg, SPR_NOACCESS, @@ -1738,7 +1740,7 @@ static void gen_spr_405 (CPUPPCState *env) 0x00000000); spr_register(env, SPR_SPRG5, "SPRG5", SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, + spr_read_generic, &spr_write_generic, 0x00000000); spr_register(env, SPR_USPRG5, "USPRG5", &spr_read_ureg, SPR_NOACCESS, @@ -1746,7 +1748,7 @@ static void gen_spr_405 (CPUPPCState *env) 0x00000000); spr_register(env, SPR_SPRG6, "SPRG6", SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, + spr_read_generic, &spr_write_generic, 0x00000000); spr_register(env, SPR_USPRG6, "USPRG6", &spr_read_ureg, SPR_NOACCESS, @@ -1754,7 +1756,7 @@ static void gen_spr_405 (CPUPPCState *env) 0x00000000); spr_register(env, SPR_SPRG7, "SPRG7", SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, + spr_read_generic, &spr_write_generic, 0x00000000); spr_register(env, SPR_USPRG7, "USPRG7", &spr_read_ureg, SPR_NOACCESS, @@ -2756,7 +2758,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFF00, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, + .msr_mask = 0x000000000007D23DULL, }, #endif #if defined (TODO) @@ -2767,7 +2769,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFF00, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, + .msr_mask = 0x000000000007D23DULL, }, #endif #if defined (TODO) @@ -2778,7 +2780,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFF00, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, + .msr_mask = 0x000000000007D23DULL, }, #endif #if defined (TODO) @@ -2789,7 +2791,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFF00, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, + .msr_mask = 0x000000000007D23DULL, }, #endif #if defined (TODO) @@ -2800,7 +2802,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFF00, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, + .msr_mask = 0x000000000007D23DULL, }, #endif /* Generic PowerPC 405 */ @@ -2810,7 +2812,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, /* PowerPC 405 CR */ { @@ -2819,7 +2821,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #if defined (TODO) /* PowerPC 405 GP */ @@ -2829,7 +2831,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif /* PowerPC 405 EP */ @@ -2839,7 +2841,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #if defined (TODO) /* PowerPC 405 EZ */ @@ -2849,7 +2851,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -2860,10 +2862,9 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif -#if defined (TODO) /* PowerPC 405 D2 */ { .name = "405d2", @@ -2871,10 +2872,8 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, -#endif -#if defined (TODO) /* PowerPC 405 D4 */ { .name = "405d4", @@ -2882,9 +2881,8 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, -#endif #if defined (TODO) /* Npe405 H */ { @@ -2893,7 +2891,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -2904,7 +2902,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -2915,7 +2913,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -2926,7 +2924,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -2937,10 +2935,10 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif -#if defined (TODO) || 1 +#if defined (TODO) /* STB03xx */ { .name = "STB03", @@ -2948,7 +2946,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -2959,7 +2957,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -2970,10 +2968,10 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif -#if defined (TODO) || 1 +#if defined (TODO) /* STB25xx */ { .name = "STB25", @@ -2981,7 +2979,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -2992,7 +2990,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif /* Xilinx PowerPC 405 cores */ @@ -3003,7 +3001,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, { .name = "x2vp7", @@ -3011,7 +3009,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, { .name = "x2vp20", @@ -3019,7 +3017,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, { .name = "x2vp50", @@ -3027,7 +3025,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, + .msr_mask = 0x00000000020EFF30ULL, }, #endif #if defined (TODO) @@ -3038,7 +3036,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif #if defined (TODO) @@ -3049,7 +3047,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif #if defined (TODO) @@ -3060,7 +3058,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFF00, .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif #if defined (TODO) @@ -3071,7 +3069,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif #if defined (TODO) @@ -3082,7 +3080,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif #if defined (TODO) @@ -3093,7 +3091,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif #if defined (TODO) @@ -3104,7 +3102,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif #if defined (TODO) @@ -3115,7 +3113,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif #if defined (TODO) @@ -3126,7 +3124,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, #endif /* Fake generic BookE PowerPC */ @@ -3136,7 +3134,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_BOOKE, .flags = PPC_FLAGS_BOOKE, - .msr_mask = 0x000000000006D630, + .msr_mask = 0x000000000006D630ULL, }, /* PowerPC 460 cores - TODO */ /* PowerPC MPC 5xx cores - TODO */ @@ -3155,7 +3153,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_601, .flags = PPC_FLAGS_601, - .msr_mask = 0x000000000000FD70, + .msr_mask = 0x000000000000FD70ULL, }, #endif #if defined (TODO) @@ -3166,7 +3164,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_602, .flags = PPC_FLAGS_602, - .msr_mask = 0x0000000000C7FF73, + .msr_mask = 0x0000000000C7FF73ULL, }, #endif /* PowerPC 603 */ @@ -3176,7 +3174,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, /* PowerPC 603e */ { @@ -3185,7 +3183,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, { .name = "Stretch", @@ -3193,7 +3191,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, /* PowerPC 603p */ { @@ -3202,7 +3200,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, /* PowerPC 603e7 */ { @@ -3211,7 +3209,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, /* PowerPC 603e7v */ { @@ -3220,7 +3218,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, /* PowerPC 603e7v2 */ { @@ -3229,7 +3227,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, /* PowerPC 603r */ { @@ -3238,7 +3236,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, { .name = "Goldeneye", @@ -3246,7 +3244,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_603, .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, + .msr_mask = 0x000000000007FF73ULL, }, #if defined (TODO) /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ @@ -3256,7 +3254,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, + .msr_mask = 0x000000000006FFF2ULL, }, { .name = "G2h4", @@ -3264,7 +3262,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, + .msr_mask = 0x000000000006FFF2ULL, }, { .name = "G2gp", @@ -3272,7 +3270,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, + .msr_mask = 0x000000000006FFF2ULL, }, { .name = "G2ls", @@ -3280,7 +3278,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, + .msr_mask = 0x000000000006FFF2ULL, }, { /* Same as G2, with LE mode support */ .name = "G2le", @@ -3288,7 +3286,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3, + .msr_mask = 0x000000000007FFF3ULL, }, { .name = "G2legp", @@ -3296,7 +3294,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3, + .msr_mask = 0x000000000007FFF3ULL, }, { .name = "G2lels", @@ -3304,7 +3302,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3, + .msr_mask = 0x000000000007FFF3ULL, }, #endif /* PowerPC 604 */ @@ -3314,7 +3312,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_604, .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, + .msr_mask = 0x000000000005FF77ULL, }, /* PowerPC 604e */ { @@ -3323,7 +3321,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_604, .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, + .msr_mask = 0x000000000005FF77ULL, }, /* PowerPC 604r */ { @@ -3332,7 +3330,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_604, .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, + .msr_mask = 0x000000000005FF77ULL, }, /* generic G3 */ { @@ -3341,7 +3339,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, /* MPC740 (G3) */ { @@ -3350,7 +3348,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, { .name = "Arthur", @@ -3358,7 +3356,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #if defined (TODO) /* MPC745 (G3) */ @@ -3368,7 +3366,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFF000, .insns_flags = PPC_INSNS_7x5, .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, { .name = "Goldfinger", @@ -3376,7 +3374,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFF000, .insns_flags = PPC_INSNS_7x5, .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #endif /* MPC750 (G3) */ @@ -3386,7 +3384,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #if defined (TODO) /* MPC755 (G3) */ @@ -3396,7 +3394,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFF000, .insns_flags = PPC_INSNS_7x5, .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #endif /* MPC740P (G3) */ @@ -3406,7 +3404,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, { .name = "Conan/Doyle", @@ -3414,7 +3412,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #if defined (TODO) /* MPC745P (G3) */ @@ -3424,7 +3422,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFF000, .insns_flags = PPC_INSNS_7x5, .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #endif /* MPC750P (G3) */ @@ -3434,7 +3432,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #if defined (TODO) /* MPC755P (G3) */ @@ -3444,7 +3442,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFF000, .insns_flags = PPC_INSNS_7x5, .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #endif /* IBM 750CXe (G3 embedded) */ @@ -3454,7 +3452,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, /* IBM 750FX (G3 embedded) */ { @@ -3463,7 +3461,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, /* IBM 750GX (G3 embedded) */ { @@ -3472,7 +3470,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, + .msr_mask = 0x000000000007FF77ULL, }, #if defined (TODO) /* generic G4 */ @@ -3482,7 +3480,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, #endif #if defined (TODO) @@ -3493,7 +3491,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, { .name = "Max", @@ -3501,7 +3499,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, #endif #if defined (TODO) @@ -3512,7 +3510,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, { .name = "Nitro", @@ -3520,7 +3518,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, #endif /* XXX: 7441 */ @@ -3535,7 +3533,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, { .name = "Vger", @@ -3543,7 +3541,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, #endif /* XXX: 7451 */ @@ -3555,7 +3553,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, { .name = "Apollo 6", @@ -3563,7 +3561,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, #endif #if defined (TODO) @@ -3574,7 +3572,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, { .name = "Apollo 7", @@ -3582,7 +3580,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, #endif #if defined (TODO) @@ -3593,7 +3591,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, { .name = "Apollo 7 PM", @@ -3601,7 +3599,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, + .msr_mask = 0x000000000205FF77ULL, }, #endif /* 64 bits PowerPC */ @@ -3614,7 +3612,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_620, .flags = PPC_FLAGS_620, - .msr_mask = 0x800000000005FF73, + .msr_mask = 0x800000000005FF73ULL, }, #endif #if defined (TODO) @@ -3699,7 +3697,7 @@ static ppc_def_t ppc_defs[] = { .msr_mask = xxx, }, #endif -#if defined (TODO) || 1 +#if defined (TODO) /* PowerPC 970 */ { .name = "970", @@ -3707,7 +3705,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_970, .flags = PPC_FLAGS_970, - .msr_mask = 0x900000000204FF36, + .msr_mask = 0x900000000204FF36ULL, }, #endif #if defined (TODO) @@ -3718,7 +3716,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_970FX, .flags = PPC_FLAGS_970FX, - .msr_mask = 0x800000000204FF36, + .msr_mask = 0x800000000204FF36ULL, }, #endif #if defined (TODO) @@ -3857,14 +3855,14 @@ static ppc_def_t ppc_defs[] = { }, #endif /* Generic PowerPCs */ -#if defined (TODO) || 1 +#if defined (TODO) { .name = "ppc64", .pvr = CPU_PPC_970, .pvr_mask = 0xFFFF0000, .insns_flags = PPC_INSNS_PPC64, .flags = PPC_FLAGS_PPC64, - .msr_mask = 0xA00000000204FF36, + .msr_mask = 0xA00000000204FF36ULL, }, #endif { @@ -3873,7 +3871,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_PPC32, .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77, + .msr_mask = 0x000000000005FF77ULL, }, /* Fallback */ { @@ -3882,7 +3880,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_PPC32, .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77, + .msr_mask = 0x000000000005FF77ULL, }, }; diff --git a/vl.h b/vl.h index fbad5e2a1..c4be86d25 100644 --- a/vl.h +++ b/vl.h @@ -1172,58 +1172,6 @@ int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn), int ppc_dcr_register (CPUState *env, int dcrn, void *opaque, dcr_read_cb drc_read, dcr_write_cb dcr_write); clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq); -/* PowerPC 405 core */ -CPUPPCState *ppc405_init (const unsigned char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk); -void ppc40x_core_reset (CPUState *env); -void ppc40x_chip_reset (CPUState *env); -void ppc40x_system_reset (CPUState *env); -/* */ -typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; -int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, - uint32_t offset, uint32_t len, - CPUReadMemoryFunc **mem_read, - CPUWriteMemoryFunc **mem_write, void *opaque); -ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, uint32_t base); -/* PowerPC 4xx peripheral local bus arbitrer */ -void ppc4xx_plb_init (CPUState *env); -/* PLB to OPB bridge */ -void ppc4xx_pob_init (CPUState *env); -/* OPB arbitrer */ -void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); -/* PowerPC 4xx universal interrupt controller */ -enum { - PPCUIC_OUTPUT_INT = 0, - PPCUIC_OUTPUT_CINT = 1, - PPCUIC_OUTPUT_NB, -}; -qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, - uint32_t dcr_base, int has_ssr, int has_vr); -/* SDRAM controller */ -void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, - target_ulong *ram_bases, target_ulong *ram_sizes); -/* Peripheral controller */ -void ppc405_ebc_init (CPUState *env); -/* DMA controller */ -void ppc405_dma_init (CPUState *env, qemu_irq irqs[4]); -/* GPIO */ -void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); -/* Serial ports */ -void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio, - uint32_t offset, qemu_irq irq, - CharDriverState *chr); -/* On Chip Memory */ -void ppc405_ocm_init (CPUState *env, unsigned long offset); -/* I2C controller */ -void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); -/* PowerPC 405 microcontrollers */ -CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], - uint32_t sysclk, qemu_irq **picp, - ram_addr_t *offsetp); -CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], - uint32_t sysclk, qemu_irq **picp, - ram_addr_t *offsetp); #endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); -- cgit v1.2.3 From fcb4a419f52e538b68510a68f30d8834dd211155 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 17 Apr 2007 15:26:47 +0000 Subject: Choose number of TLBs at runtime, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2693 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_timer.c | 2 +- target-mips/cpu.h | 1 + target-mips/mips-defs.h | 1 - target-mips/op.c | 4 ++-- target-mips/op_helper.c | 20 +++++++++----------- target-mips/translate.c | 4 ---- target-mips/translate_init.c | 21 +++++++++++++-------- 7 files changed, 26 insertions(+), 27 deletions(-) diff --git a/hw/mips_timer.c b/hw/mips_timer.c index bd89e5dee..6a517e184 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -10,7 +10,7 @@ uint32_t cpu_mips_get_random (CPUState *env) static uint32_t seed = 0; uint32_t idx; seed = seed * 314159 + 1; - idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired; + idx = (seed >> 16) % (env->nb_tlb - env->CP0_Wired) + env->CP0_Wired; return idx; } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c91e2cac4..36b890efb 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -99,6 +99,7 @@ struct CPUMIPSState { #if defined(MIPS_USES_R4K_TLB) tlb_t tlb[MIPS_TLB_MAX]; uint32_t tlb_in_use; + uint32_t nb_tlb; #endif int32_t CP0_Index; int32_t CP0_Random; diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 14043be27..01034c3d0 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -10,7 +10,6 @@ #define TARGET_PAGE_BITS 12 /* Uses MIPS R4Kc TLB model */ #define MIPS_USES_R4K_TLB -#define MIPS_TLB_NB 16 #define MIPS_TLB_MAX 128 #ifdef TARGET_MIPS64 diff --git a/target-mips/op.c b/target-mips/op.c index 08ef2281f..0b5e8bacb 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1270,7 +1270,7 @@ void op_mfc0_desave (void) void op_mtc0_index (void) { - env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 & (MIPS_TLB_NB - 1)); + env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->nb_tlb); RETURN(); } @@ -1314,7 +1314,7 @@ void op_mtc0_pagegrain (void) void op_mtc0_wired (void) { - env->CP0_Wired = T0 & (MIPS_TLB_NB - 1); + env->CP0_Wired = T0 % env->nb_tlb; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 14696aa92..2ebcede65 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -394,7 +394,7 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) { /* Flush qemu's TLB and discard all shadowed entries. */ tlb_flush (env, flush_global); - env->tlb_in_use = MIPS_TLB_NB; + env->tlb_in_use = env->nb_tlb; } static void mips_tlb_flush_extra (CPUState *env, int first) @@ -430,12 +430,10 @@ void do_tlbwi (void) /* Discard cached TLB entries. We could avoid doing this if the tlbwi is just upgrading access permissions on the current entry; that might be a further win. */ - mips_tlb_flush_extra (env, MIPS_TLB_NB); + mips_tlb_flush_extra (env, env->nb_tlb); - /* Wildly undefined effects for CP0_Index containing a too high value and - MIPS_TLB_NB not being a power of two. But so does real silicon. */ - invalidate_tlb(env, env->CP0_Index & (MIPS_TLB_NB - 1), 0); - fill_tlb(env->CP0_Index & (MIPS_TLB_NB - 1)); + invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0); + fill_tlb(env->CP0_Index % env->nb_tlb); } void do_tlbwr (void) @@ -455,7 +453,7 @@ void do_tlbp (void) tag = env->CP0_EntryHi & (int32_t)0xFFFFE000; ASID = env->CP0_EntryHi & 0xFF; - for (i = 0; i < MIPS_TLB_NB; i++) { + for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { @@ -464,9 +462,9 @@ void do_tlbp (void) break; } } - if (i == MIPS_TLB_NB) { + if (i == env->nb_tlb) { /* No match. Discard any shadow entries, if any of them match. */ - for (i = MIPS_TLB_NB; i < env->tlb_in_use; i++) { + for (i = env->nb_tlb; i < env->tlb_in_use; i++) { tlb = &env->tlb[i]; /* Check ASID, virtual page number & size */ @@ -486,13 +484,13 @@ void do_tlbr (void) uint8_t ASID; ASID = env->CP0_EntryHi & 0xFF; - tlb = &env->tlb[env->CP0_Index & (MIPS_TLB_NB - 1)]; + tlb = &env->tlb[env->CP0_Index % env->nb_tlb]; /* If this will change the current ASID, flush qemu's TLB. */ if (ASID != tlb->ASID) cpu_mips_tlb_flush (env, 1); - mips_tlb_flush_extra(env, MIPS_TLB_NB); + mips_tlb_flush_extra(env, env->nb_tlb); env->CP0_EntryHi = tlb->VPN | tlb->ASID; env->CP0_PageMask = tlb->PageMask; diff --git a/target-mips/translate.c b/target-mips/translate.c index 35c98aba7..3035ea26f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5430,10 +5430,6 @@ void cpu_reset (CPUMIPSState *env) } env->hflags = 0; env->PC = (int32_t)0xBFC00000; -#if defined (MIPS_USES_R4K_TLB) - env->CP0_Random = MIPS_TLB_NB - 1; - env->tlb_in_use = MIPS_TLB_NB; -#endif env->CP0_Wired = 0; /* SMP not implemented */ env->CP0_EBase = 0x80000000; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index f2966ea89..51c571d0e 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -28,13 +28,13 @@ (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) | \ (0x2 << CP0C0_K0)) -/* Have config2, 16 TLB entries, 64 sets Icache, 16 bytes Icache line, +/* Have config2, 64 sets Icache, 16 bytes Icache line, 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, no coprocessor2 attached, no MDMX support attached, no performance counters, watch registers present, no code compression, EJTAG present, no FPU */ #define MIPS_CONFIG1 \ -((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) | \ +((1 << CP0C1_M) | \ (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \ (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \ @@ -81,7 +81,7 @@ static mips_def_t mips_defs[] = .name = "4Kc", .CP0_PRid = 0x00018000, .CP0_Config0 = MIPS_CONFIG0, - .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -92,7 +92,7 @@ static mips_def_t mips_defs[] = .name = "4KEcR1", .CP0_PRid = 0x00018400, .CP0_Config0 = MIPS_CONFIG0, - .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -103,7 +103,7 @@ static mips_def_t mips_defs[] = .name = "4KEc", .CP0_PRid = 0x00019000, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), - .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -114,7 +114,7 @@ static mips_def_t mips_defs[] = .name = "24Kc", .CP0_PRid = 0x00019300, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), - .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -125,7 +125,7 @@ static mips_def_t mips_defs[] = .name = "24Kf", .CP0_PRid = 0x00019300, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), - .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -137,7 +137,7 @@ static mips_def_t mips_defs[] = .name = "R4000", .CP0_PRid = 0x00000400, .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT), - .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 16, @@ -192,5 +192,10 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->SYNCI_Step = def->SYNCI_Step; env->CCRes = def->CCRes; env->fcr0 = def->CP1_fcr0; +#if defined (MIPS_USES_R4K_TLB) + env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); + env->CP0_Random = env->nb_tlb - 1; + env->tlb_in_use = env->nb_tlb; +#endif return 0; } -- cgit v1.2.3 From 18c6e2ff5adc016031566f409382417f6fde626d Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 17 Apr 2007 16:28:29 +0000 Subject: Fix mmapped register alignment and endianness handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2694 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mc146818rtc.c | 35 +++++++++++++++++++++++++---------- hw/mips_pica61.c | 2 +- vl.h | 2 +- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index af7665495..e30791f8a 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -56,6 +56,7 @@ struct RTCState { struct tm current_tm; qemu_irq irq; target_phys_addr_t base; + int it_shift; /* periodic timer */ QEMUTimer *periodic_timer; int64_t next_periodic_time; @@ -492,7 +493,7 @@ uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr) { RTCState *s = opaque; - return cmos_ioport_read(s, addr - s->base) & 0xFF; + return cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF; } void cmos_mm_writeb (void *opaque, @@ -500,37 +501,51 @@ void cmos_mm_writeb (void *opaque, { RTCState *s = opaque; - cmos_ioport_write(s, addr - s->base, value & 0xFF); + cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF); } uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr) { RTCState *s = opaque; + uint32_t val; - return cmos_ioport_read(s, addr - s->base) & 0xFFFF; + val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; } void cmos_mm_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { RTCState *s = opaque; - - cmos_ioport_write(s, addr - s->base, value & 0xFFFF); +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif + cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF); } uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr) { RTCState *s = opaque; + uint32_t val; - return cmos_ioport_read(s, addr - s->base); + val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; } void cmos_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { RTCState *s = opaque; - - cmos_ioport_write(s, addr - s->base, value); +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif + cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value); } static CPUReadMemoryFunc *rtc_mm_read[] = { @@ -545,7 +560,7 @@ static CPUWriteMemoryFunc *rtc_mm_write[] = { &cmos_mm_writel, }; -RTCState *rtc_mm_init(target_phys_addr_t base, qemu_irq irq) +RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq) { RTCState *s; int io_memory; @@ -574,7 +589,7 @@ RTCState *rtc_mm_init(target_phys_addr_t base, qemu_irq irq) qemu_mod_timer(s->second_timer2, s->next_second_time); io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s); - cpu_register_physical_memory(base, 2, io_memory); + cpu_register_physical_memory(base, 2 << it_shift, io_memory); register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); return s; diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 9d9400a69..8e1058a79 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -125,7 +125,7 @@ void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device, /* PC style IRQ (i8259/i8254) and DMA (i8257) */ /* The PIC is attached to the MIPS CPU INT0 pin */ i8259 = i8259_init(env->irq[2]); - rtc_mm_init(0x80004070, i8259[14]); + rtc_mm_init(0x80004070, 1, i8259[14]); pit_init(0x40, 0); /* Keyboard (i8042) */ diff --git a/vl.h b/vl.h index c4be86d25..217fd2f40 100644 --- a/vl.h +++ b/vl.h @@ -1043,7 +1043,7 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, int typedef struct RTCState RTCState; RTCState *rtc_init(int base, qemu_irq irq); -RTCState *rtc_mm_init(target_phys_addr_t base, qemu_irq irq); +RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq); void rtc_set_memory(RTCState *s, int addr, int val); void rtc_set_date(RTCState *s, const struct tm *tm); -- cgit v1.2.3 From 5c8cdbf833511c1d078642d08bc3248130d7c76f Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 17 Apr 2007 19:42:21 +0000 Subject: TCX palette bug fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2695 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/tcx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/tcx.c b/hw/tcx.c index 7ab0aa33a..20d9340c4 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -296,6 +296,7 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val) case 2: s->b[s->dac_index] = val >> 24; update_palette_entries(s, s->dac_index, s->dac_index + 1); + s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement default: s->dac_state = 0; break; -- cgit v1.2.3 From c94655b0b53fdc40bb0917612daaeb96f2de3c23 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 17 Apr 2007 21:57:02 +0000 Subject: Updated Solaris isinf support, by Juergen Keil and Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2696 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 8a0d1ad37..49cff5d89 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -33,6 +33,29 @@ #define isunordered(x,y) unordered(x, y) #endif +#if defined(__sun__) && !defined(NEED_LIBSUNMATH) + +#ifndef isnan +# define isnan(x) \ + (sizeof (x) == sizeof (long double) ? isnan_ld (x) \ + : sizeof (x) == sizeof (double) ? isnan_d (x) \ + : isnan_f (x)) +static inline int isnan_f (float x) { return x != x; } +static inline int isnan_d (double x) { return x != x; } +static inline int isnan_ld (long double x) { return x != x; } +#endif + +#ifndef isinf +# define isinf(x) \ + (sizeof (x) == sizeof (long double) ? isinf_ld (x) \ + : sizeof (x) == sizeof (double) ? isinf_d (x) \ + : isinf_f (x)) +static inline int isinf_f (float x) { return isnan (x - x); } +static inline int isinf_d (double x) { return isnan (x - x); } +static inline int isinf_ld (long double x) { return isnan (x - x); } +#endif +#endif + typedef float float32; typedef double float64; #ifdef FLOATX80 -- cgit v1.2.3 From af661ad11bbcd00b1eb437ab5032817e7ecf35fc Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 17 Apr 2007 23:08:56 +0000 Subject: Ptable calculation broken for 32bit code under x86_64, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2697 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index f05a284f9..cbf17caa1 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -670,7 +670,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, #endif { /* XXX: load them when cr3 is loaded ? */ - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & env->a20_mask; pdpe = ldq_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { @@ -765,7 +765,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, uint32_t pde; /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask; pde = ldl_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) { @@ -910,7 +910,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } else #endif { - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & env->a20_mask; pdpe = ldl_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) @@ -940,7 +940,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) page_size = 4096; } else { /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask; + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask; pde = ldl_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) return -1; -- cgit v1.2.3 From 4b70269e1c1f4ad7470602b31aa1ca3d1da7e2bd Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 17 Apr 2007 23:25:06 +0000 Subject: Fix helper.c with isinf on Solaris 9/Sparc, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2698 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-i386/helper.c b/target-i386/helper.c index 4656596eb..968d3991f 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -21,6 +21,11 @@ //#define DEBUG_PCALL +#if defined(__sparc__) && (HOST_SOLARIS < 10) +#include +#define isinf(x) (fpclass(x) == FP_NINF || fpclass(x) == FP_PINF) +#endif + #if 0 #define raise_exception_err(a, b)\ do {\ -- cgit v1.2.3 From 92d88ecbac89a181c103719bab2d1b4b30a7283d Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 17 Apr 2007 23:53:10 +0000 Subject: Another lsi53c895a patch, by Wang Cheng Yeh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2699 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lsi53c895a.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 88806a60a..06107b5f7 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1434,10 +1434,13 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) if (val & LSI_ISTAT0_SRST) { lsi_soft_reset(s); } + break; case 0x16: /* MBOX0 */ s->mbox0 = val; + break; case 0x17: /* MBOX1 */ s->mbox1 = val; + break; case 0x1b: /* CTEST3 */ s->ctest3 = val & 0x0f; break; -- cgit v1.2.3 From 095f61d202ef65e8efa88d98c87759bac420dbe3 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 18 Apr 2007 11:15:56 +0000 Subject: Revert, this is already fixed in a better way. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2700 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 968d3991f..4656596eb 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -21,11 +21,6 @@ //#define DEBUG_PCALL -#if defined(__sparc__) && (HOST_SOLARIS < 10) -#include -#define isinf(x) (fpclass(x) == FP_NINF || fpclass(x) == FP_PINF) -#endif - #if 0 #define raise_exception_err(a, b)\ do {\ -- cgit v1.2.3 From e6b1e558aca0e065a674f580d5347e5714da345f Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 18 Apr 2007 17:56:02 +0000 Subject: Win32 Tap inferface PPC Guest issue, by Ely Soto. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2701 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index 1c79cfd78..ab7aacffd 100644 --- a/vl.c +++ b/vl.c @@ -6143,7 +6143,7 @@ void main_loop_wait(int timeout) { IOHandlerRecord *ioh; fd_set rfds, wfds, xfds; - int ret, nfds; + int ret, ret2, nfds, i; struct timeval tv; PollingEntry *pe; @@ -6154,7 +6154,7 @@ void main_loop_wait(int timeout) ret |= pe->func(pe->opaque); } #ifdef _WIN32 - if (ret == 0 && timeout > 0) { + if (ret == 0) { int err; WaitObjects *w = &wait_objects; @@ -6162,10 +6162,25 @@ void main_loop_wait(int timeout) if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { if (w->func[ret - WAIT_OBJECT_0]) w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); + + /* Check for additional signaled events */ + for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) { + + /* Check if event is signaled */ + ret2 = WaitForSingleObject(w->events[i], 0); + if(ret2 == WAIT_OBJECT_0) { + if (w->func[i]) + w->func[i](w->opaque[i]); + } else if (ret2 == WAIT_TIMEOUT) { + } else { + err = GetLastError(); + fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err); + } + } } else if (ret == WAIT_TIMEOUT) { } else { err = GetLastError(); - fprintf(stderr, "Wait error %d %d\n", ret, err); + fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err); } } #endif -- cgit v1.2.3 From 877cf882321aeb74b246043d3970e1c707a89f1e Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 18 Apr 2007 18:11:47 +0000 Subject: Fix compiler warning. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2702 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index ab7aacffd..999fcefce 100644 --- a/vl.c +++ b/vl.c @@ -6143,7 +6143,10 @@ void main_loop_wait(int timeout) { IOHandlerRecord *ioh; fd_set rfds, wfds, xfds; - int ret, ret2, nfds, i; + int ret, nfds; +#ifdef _WIN32 + int ret2, i; +#endif struct timeval tv; PollingEntry *pe; -- cgit v1.2.3 From 67deb56246f006fa23b8a61681663f88e5b976fc Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 18 Apr 2007 19:21:38 +0000 Subject: Fix keyboard detection bugs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2703 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 165629251..54debce4a 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -108,6 +108,13 @@ static int serial_can_receive(void *opaque); static void serial_receive_byte(ChannelState *s, int ch); static inline void set_txint(ChannelState *s); +static void clear_queue(void *opaque) +{ + ChannelState *s = opaque; + SERIOQueue *q = &s->queue; + q->rptr = q->wptr = q->count = 0; +} + static void put_queue(void *opaque, int b) { ChannelState *s = opaque; @@ -137,7 +144,7 @@ static uint32_t get_queue(void *opaque) q->rptr = 0; q->count--; } - KBD_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val); + SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val); if (q->count > 0) serial_receive_byte(s, 0); return val; @@ -186,6 +193,7 @@ static void slavio_serial_reset_chn(ChannelState *s) s->rx = s->tx = 0; s->rxint = s->txint = 0; s->rxint_under_svc = s->txint_under_svc = 0; + clear_queue(s); } static void slavio_serial_reset(void *opaque) @@ -199,10 +207,19 @@ static inline void clr_rxint(ChannelState *s) { s->rxint = 0; s->rxint_under_svc = 0; - if (s->chn == chn_a) + if (s->chn == chn_a) { + if (s->wregs[9] & 0x10) + s->otherchn->rregs[2] = 0x60; + else + s->otherchn->rregs[2] = 0x06; s->rregs[3] &= ~0x20; - else + } else { + if (s->wregs[9] & 0x10) + s->rregs[2] = 0x60; + else + s->rregs[2] = 0x06; s->otherchn->rregs[3] &= ~4; + } if (s->txint) set_txint(s); else @@ -215,11 +232,19 @@ static inline void set_rxint(ChannelState *s) s->rxint = 1; if (!s->txint_under_svc) { s->rxint_under_svc = 1; - if (s->chn == chn_a) + if (s->chn == chn_a) { + if (s->wregs[9] & 0x10) + s->otherchn->rregs[2] = 0x30; + else + s->otherchn->rregs[2] = 0x0c; s->rregs[3] |= 0x20; - else + } else { + if (s->wregs[9] & 0x10) + s->rregs[2] = 0x20; + else + s->rregs[2] = 0x04; s->otherchn->rregs[3] |= 4; - s->rregs[2] = 4; + } slavio_serial_update_irq(s); } } @@ -607,12 +632,15 @@ static void handle_kbd_command(ChannelState *s, int val) KBD_DPRINTF("Command %d\n", val); switch (val) { case 1: // Reset, return type code + clear_queue(s); put_queue(s, 0xff); - put_queue(s, 5); // Type 5 + put_queue(s, 4); // Type 4 break; case 7: // Query layout + case 0xf: + clear_queue(s); put_queue(s, 0xfe); - put_queue(s, 0x20); // XXX, layout? + put_queue(s, 19); // XXX, layout? break; default: break; @@ -625,9 +653,6 @@ static void sunmouse_event(void *opaque, ChannelState *s = opaque; int ch; - /* XXX: SDL sometimes generates nul events: we delete them */ - if (dx == 0 && dy == 0 && dz == 0 && buttons_state == 0) - return; MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state); ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */ -- cgit v1.2.3 From f9d6b6b061fcb44bc6da6dc458d07a9efbaf0d93 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 19 Apr 2007 07:16:51 +0000 Subject: Duplicated SPR fix for BookE PowerPC by Guglielmo Morandin git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2704 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 0868f308c..d7473fef6 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1201,10 +1201,6 @@ static void gen_spr_BookE (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Exception vectors */ - spr_register(env, SPR_BOOKE_IVPR, "IVPR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); spr_register(env, SPR_BOOKE_IVOR0, "IVOR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, -- cgit v1.2.3 From 0405f55b57271e25fe9dfdbdacb015e3ca672653 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 19 Apr 2007 07:17:50 +0000 Subject: termios structure definition fix by Stuart Anderson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2705 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ppc/termbits.h | 2 +- linux-user/ppc64/termbits.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/ppc/termbits.h b/linux-user/ppc/termbits.h index 6326747ee..7bf14eb5c 100644 --- a/linux-user/ppc/termbits.h +++ b/linux-user/ppc/termbits.h @@ -7,8 +7,8 @@ struct target_termios { unsigned int c_oflag; /* output mode flags */ unsigned int c_cflag; /* control mode flags */ unsigned int c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ unsigned char c_cc[TARGET_NCCS]; /* control characters */ + unsigned char c_line; /* line discipline */ unsigned int c_ispeed; /* input speed */ unsigned int c_ospeed; /* output speed */ }; diff --git a/linux-user/ppc64/termbits.h b/linux-user/ppc64/termbits.h index 6326747ee..7bf14eb5c 100644 --- a/linux-user/ppc64/termbits.h +++ b/linux-user/ppc64/termbits.h @@ -7,8 +7,8 @@ struct target_termios { unsigned int c_oflag; /* output mode flags */ unsigned int c_cflag; /* control mode flags */ unsigned int c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ unsigned char c_cc[TARGET_NCCS]; /* control characters */ + unsigned char c_line; /* line discipline */ unsigned int c_ispeed; /* input speed */ unsigned int c_ospeed; /* output speed */ }; -- cgit v1.2.3 From 4a0577124ac36b7cdf8e33bf91baa92d2c503a4c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 19 Apr 2007 08:42:21 +0000 Subject: No functional changes: - compilation warning fixes - make loglevel tests consistent - use cpu_abort instead of printf(...); exit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2706 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405.h | 3 -- hw/ppc_chrp.c | 12 +++--- hw/ppc_prep.c | 15 ++++--- target-ppc/helper.c | 114 ++++++++++++++++++++++++++++--------------------- target-ppc/translate.c | 16 +++---- vl.h | 4 ++ 6 files changed, 91 insertions(+), 73 deletions(-) diff --git a/hw/ppc405.h b/hw/ppc405.h index e3a544dd1..e61cc58b3 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -59,9 +59,6 @@ CPUState *ppc405_init (const unsigned char *cpu_model, uint32_t sysclk); ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd); -void ppc40x_core_reset (CPUState *env); -void ppc40x_chip_reset (CPUState *env); -void ppc40x_system_reset (CPUState *env); /* */ typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 456832824..a8114fa2e 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -349,11 +349,11 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); bios_size = load_image(buf, phys_ram_base + bios_offset); if (bios_size < 0 || bios_size > BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf); + cpu_abort(env, "qemu: could not load PowerPC bios '%s'\n", buf); exit(1); } bios_size = (bios_size + 0xfff) & ~0xfff; - cpu_register_physical_memory((uint32_t)(-bios_size), + cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); /* allocate and load VGA BIOS */ @@ -382,8 +382,8 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* now we can load the kernel */ kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + cpu_abort(env, "qemu: could not load kernel '%s'\n", + kernel_filename); exit(1); } /* load initrd */ @@ -392,8 +392,8 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + cpu_abort(env, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); exit(1); } } else { diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 2f10338b1..6a3cd907b 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -560,11 +560,11 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); bios_size = load_image(buf, phys_ram_base + bios_offset); if (bios_size < 0 || bios_size > BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf); + cpu_abort(env, "qemu: could not load PPC PREP bios '%s'\n", buf); exit(1); } bios_size = (bios_size + 0xfff) & ~0xfff; - cpu_register_physical_memory((uint32_t)(-bios_size), + cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); if (linux_boot) { @@ -572,8 +572,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, /* now we can load the kernel */ kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + cpu_abort(env, "qemu: could not load kernel '%s'\n", + kernel_filename); exit(1); } /* load initrd */ @@ -582,8 +582,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + cpu_abort(env, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); exit(1); } } else { @@ -627,7 +627,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, || strcmp(nd_table[0].model, "ne2k_isa") == 0) { isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]); } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + /* Why ? */ + cpu_abort(env, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); } } diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 2fc5ecd12..e93f5a6d1 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -124,14 +124,14 @@ static int pte_check (mmu_ctx_t *ctx, (rw == 1 && (access & PAGE_WRITE))) { /* Access granted */ #if defined (DEBUG_MMU) - if (loglevel > 0) + if (loglevel != 0) fprintf(logfile, "PTE access granted !\n"); #endif ret = 0; } else { /* Access right violation */ #if defined (DEBUG_MMU) - if (loglevel > 0) + if (loglevel != 0) fprintf(logfile, "PTE access rejected\n"); #endif ret = -2; @@ -214,10 +214,10 @@ static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, int is_code, int match_epn) { +#if !defined(FLUSH_ALL_TLBS) ppc6xx_tlb_t *tlb; int way, nr; -#if !defined(FLUSH_ALL_TLBS) /* Invalidate ITLB + DTLB, all ways */ for (way = 0; way < env->nb_ways; way++) { nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); @@ -331,7 +331,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, if (best != -1) { done: #if defined (DEBUG_SOFTWARE_TLB) - if (loglevel > 0) { + if (loglevel != 0) { fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n", ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); } @@ -353,7 +353,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, int ret = -1; #if defined (DEBUG_BATS) - if (loglevel > 0) { + if (loglevel != 0) { fprintf(logfile, "%s: %cBAT v 0x" ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } @@ -369,7 +369,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, break; } #if defined (DEBUG_BATS) - if (loglevel > 0) { + if (loglevel != 0) { fprintf(logfile, "%s...: %cBAT v 0x" ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } @@ -382,7 +382,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, BEPIl = *BATu & 0x0FFE0000; bl = (*BATu & 0x00001FFC) << 15; #if defined (DEBUG_BATS) - if (loglevel > 0) { + if (loglevel != 0) { fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX " BATl 0x" ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, @@ -403,8 +403,8 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, if (*BATl & 0x00000002) ctx->prot = PAGE_WRITE | PAGE_READ; #if defined (DEBUG_BATS) - if (loglevel > 0) { - fprintf(logfile, "BAT %d match: r 0x" ADDRX + if (loglevel != 0) { + fprintf(logfile, "BAT %d match: r 0x" PADDRX " prot=%c%c\n", i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', ctx->prot & PAGE_WRITE ? 'W' : '-'); @@ -417,18 +417,20 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, } if (ret < 0) { #if defined (DEBUG_BATS) - printf("no BAT match for 0x" ADDRX ":\n", virtual); - for (i = 0; i < 4; i++) { - BATu = &BATut[i]; - BATl = &BATlt[i]; - BEPIu = *BATu & 0xF0000000; - BEPIl = *BATu & 0x0FFE0000; - bl = (*BATu & 0x00001FFC) << 15; - printf("%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX - " BATl 0x" ADDRX " \n\t" - "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n", - __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, - *BATu, *BATl, BEPIu, BEPIl, bl); + if (loglevel != 0) { + fprintf(logfile, "no BAT match for 0x" ADDRX ":\n", virtual); + for (i = 0; i < 4; i++) { + BATu = &BATut[i]; + BATl = &BATlt[i]; + BEPIu = *BATu & 0xF0000000; + BEPIl = *BATu & 0x0FFE0000; + bl = (*BATu & 0x00001FFC) << 15; + fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX + " BATl 0x" ADDRX " \n\t" + "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n", + __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, + *BATu, *BATl, BEPIu, BEPIl, bl); + } } #endif } @@ -483,8 +485,8 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw) if (good != -1) { done: #if defined (DEBUG_MMU) - if (loglevel > 0) { - fprintf(logfile, "found PTE at addr 0x" ADDRX " prot=0x%01x " + if (loglevel != 0) { + fprintf(logfile, "found PTE at addr 0x" PADDRX " prot=0x%01x " "ret=%d\n", ctx->raddr, ctx->prot, ret); } @@ -551,10 +553,11 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); } else { #if defined (DEBUG_MMU) - if (loglevel > 0) { - fprintf(logfile, "0 sdr1=0x" ADDRX " vsid=0x%06x " - "api=0x%04x hash=0x%07x pg_addr=0x" ADDRX "\n", - sdr, vsid, pgidx, hash, ctx->pg_addr[0]); + if (loglevel != 0) { + fprintf(logfile, "0 sdr1=0x" PADDRX " vsid=0x%06x " + "api=0x%04x hash=0x%07x pg_addr=0x" PADDRX "\n", + sdr, (uint32_t)vsid, (uint32_t)pgidx, + (uint32_t)hash, ctx->pg_addr[0]); } #endif /* Primary table lookup */ @@ -562,11 +565,12 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, if (ret < 0) { /* Secondary table lookup */ #if defined (DEBUG_MMU) - if (eaddr != 0xEFFFFFFF && loglevel > 0) { + if (eaddr != 0xEFFFFFFF && loglevel != 0) { fprintf(logfile, - "1 sdr1=0x" ADDRX " vsid=0x%06x api=0x%04x " - "hash=0x%05x pg_addr=0x" ADDRX "\n", - sdr, vsid, pgidx, hash, ctx->pg_addr[1]); + "1 sdr1=0x" PADDRX " vsid=0x%06x api=0x%04x " + "hash=0x%05x pg_addr=0x" PADDRX "\n", + sdr, (uint32_t)vsid, (uint32_t)pgidx, + (uint32_t)hash, ctx->pg_addr[1]); } #endif ret2 = find_pte(ctx, 1, rw); @@ -576,14 +580,14 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } } else { #if defined (DEBUG_MMU) - if (loglevel > 0) + if (loglevel != 0) fprintf(logfile, "No access allowed\n"); #endif ret = -3; } } else { #if defined (DEBUG_MMU) - if (loglevel > 0) + if (loglevel != 0) fprintf(logfile, "direct store...\n"); #endif /* Direct-store segment : absolutely *BUGGY* for now */ @@ -615,8 +619,6 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, fprintf(logfile, "ERROR: instruction should not need " "address translation\n"); } - printf("ERROR: instruction should not need " - "address translation\n"); return -4; } if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) { @@ -663,12 +665,12 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, tlb = &env->tlb[i].tlbe; /* Check valid flag */ if (!(tlb->prot & PAGE_VALID)) { - if (loglevel) + if (loglevel != 0) fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); continue; } mask = ~(tlb->size - 1); - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " ADDRX " " ADDRX " %d\n", __func__, i, address, (int)env->spr[SPR_40x_PID], @@ -683,7 +685,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, raddr = (tlb->RPN & mask) | (address & ~mask); zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", __func__, i, zsel, zpr, rw, tlb->attr); } @@ -750,7 +752,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } if (ret >= 0) { ctx->raddr = raddr; - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s: access granted " ADDRX " => " REGX " %d %d\n", __func__, address, ctx->raddr, ctx->prot, ret); @@ -758,7 +760,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, return 0; } } - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s: access refused " ADDRX " => " REGX " %d %d\n", __func__, address, raddr, ctx->prot, ret); @@ -808,7 +810,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, { int ret; #if 0 - if (loglevel > 0) { + if (loglevel != 0) { fprintf(logfile, "%s\n", __func__); } #endif @@ -857,8 +859,8 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, } } #if 0 - if (loglevel > 0) { - fprintf(logfile, "%s address " ADDRX " => %d " ADDRX "\n", + if (loglevel != 0) { + fprintf(logfile, "%s address " ADDRX " => %d " PADDRX "\n", __func__, eaddr, ret, ctx->raddr); } #endif @@ -903,7 +905,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, is_user, is_softmmu); } else if (ret < 0) { #if defined (DEBUG_MMU) - if (loglevel > 0) + if (loglevel != 0) cpu_dump_state(env, logfile, fprintf, 0); #endif if (access_type == ACCESS_CODE) { @@ -1564,7 +1566,7 @@ void do_interrupt (CPUState *env) idx = 2; msr &= ~0xFFFF0000; #if defined (DEBUG_EXCEPTIONS) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } @@ -1609,7 +1611,7 @@ void do_interrupt (CPUState *env) case EXCP_FP: if (msr_fe0 == 0 && msr_fe1 == 0) { #if defined (DEBUG_EXCEPTIONS) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "Ignore floating point exception\n"); } #endif @@ -1625,7 +1627,7 @@ void do_interrupt (CPUState *env) break; case EXCP_INVAL: #if defined (DEBUG_EXCEPTIONS) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n", env->nip); } @@ -1836,7 +1838,7 @@ void do_interrupt (CPUState *env) cmp = &env->spr[SPR_DCMP]; } fprintf(logfile, "6xx %sTLB miss: %cM " ADDRX " %cC " ADDRX - " H1 " ADDRX " H2 " ADDRX " " ADDRX "\n", + " H1 " ADDRX " H2 " ADDRX " %08x\n", es, en, *miss, en, *cmp, env->spr[SPR_HASH1], env->spr[SPR_HASH2], env->error_code); @@ -2153,7 +2155,21 @@ void cpu_dump_EA (target_ulong EA) f = stdout; return; } - fprintf(f, "Memory access at address " TARGET_FMT_lx "\n", EA); + fprintf(f, "Memory access at address " ADDRX "\n", EA); +} + +void cpu_dump_rfi (target_ulong RA, target_ulong msr) +{ + FILE *f; + + if (logfile) { + f = logfile; + } else { + f = stdout; + return; + } + fprintf(f, "Return from exception at " ADDRX " with flags " ADDRX "\n", + RA, msr); } void cpu_ppc_reset (void *opaque) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 0658fec28..6e27854bc 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3025,7 +3025,7 @@ static inline void gen_op_mfspr (DisasContext *ctx) gen_op_store_T0_gpr(rD(ctx->opcode)); } else { /* Privilege exception */ - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "Trying to read priviledged spr %d %03x\n", sprn, sprn); } @@ -3034,7 +3034,7 @@ static inline void gen_op_mfspr (DisasContext *ctx) } } else { /* Not defined */ - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "Trying to read invalid spr %d %03x\n", sprn, sprn); } @@ -3131,7 +3131,7 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) (*write_cb)(ctx, sprn); } else { /* Privilege exception */ - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "Trying to write priviledged spr %d %03x\n", sprn, sprn); } @@ -3140,7 +3140,7 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) } } else { /* Not defined */ - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "Trying to write invalid spr %d %03x\n", sprn, sprn); } @@ -3378,7 +3378,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) RET_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - if (loglevel) + if (loglevel != 0) fprintf(logfile, "%s: ! supervisor\n", __func__); RET_PRIVOPC(ctx); return; @@ -3434,7 +3434,7 @@ GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI) RET_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - if (loglevel) + if (loglevel != 0) fprintf(logfile, "%s: ! supervisor\n", __func__); RET_PRIVOPC(ctx); return; @@ -5803,7 +5803,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, } /* Is opcode *REALLY* valid ? */ if (unlikely(handler->handler == &gen_invalid)) { - if (loglevel > 0) { + if (loglevel != 0) { fprintf(logfile, "invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), @@ -5816,7 +5816,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, } } else { if (unlikely((ctx.opcode & handler->inval) != 0)) { - if (loglevel > 0) { + if (loglevel != 0) { fprintf(logfile, "invalid bits: %08x for opcode: " "%02x -%02x - %02x (%08x) 0x" ADDRX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), diff --git a/vl.h b/vl.h index 217fd2f40..5e47bf98b 100644 --- a/vl.h +++ b/vl.h @@ -1172,6 +1172,10 @@ int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn), int ppc_dcr_register (CPUState *env, int dcrn, void *opaque, dcr_read_cb drc_read, dcr_write_cb dcr_write); clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq); +/* Embedded PowerPC reset */ +void ppc40x_core_reset (CPUState *env); +void ppc40x_chip_reset (CPUState *env); +void ppc40x_system_reset (CPUState *env); #endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); -- cgit v1.2.3 From 2802bfe387a0ab5689b0781743682a5b71a9fdc2 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 19 Apr 2007 15:38:26 +0000 Subject: More Gallileo register initialization, by Aurelien Jarno and Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2707 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 6102ecb9a..4f5090187 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -548,6 +548,50 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */ stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ + + /* Load BAR registers as done by YAMON */ + stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c08c000); /* lui t0, 0xc000 */ +#else + stl_raw(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */ +#endif + stl_raw(p++, 0xad280048); /* sw t0, 0x0048(t1) */ +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c084000); /* lui t0, 0x4000 */ +#else + stl_raw(p++, 0x34080040); /* ori t0, r0, 0x0040 */ +#endif + stl_raw(p++, 0xad280050); /* sw t0, 0x0050(t1) */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c088000); /* lui t0, 0x8000 */ +#else + stl_raw(p++, 0x34080080); /* ori t0, r0, 0x0080 */ +#endif + stl_raw(p++, 0xad280058); /* sw t0, 0x0058(t1) */ +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c083f00); /* lui t0, 0x3f00 */ +#else + stl_raw(p++, 0x3408003f); /* ori t0, r0, 0x003f */ +#endif + stl_raw(p++, 0xad280060); /* sw t0, 0x0060(t1) */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c08c100); /* lui t0, 0xc100 */ +#else + stl_raw(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */ +#endif + stl_raw(p++, 0xad280080); /* sw t0, 0x0080(t1) */ +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c085e00); /* lui t0, 0x5e00 */ +#else + stl_raw(p++, 0x3408005e); /* ori t0, r0, 0x005e */ +#endif + stl_raw(p++, 0xad280088); /* sw t0, 0x0088(t1) */ + + /* Jump to kernel code */ stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */ stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */ stl_raw(p++, 0x03e00008); /* jr ra */ -- cgit v1.2.3 From 19221bdaf816bc15dbc0c1a4b5594bf7a4ea2ce5 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 19 Apr 2007 16:35:09 +0000 Subject: Update comment. We can't easily adhere to the architecture spec because it would involve counting the actually executed instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2708 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/mips-defs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 01034c3d0..95b5ef8f0 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -18,9 +18,9 @@ #define TARGET_LONG_BITS 32 #endif -/* Strictly follow the architecture standard: Disallow "special" - instruction handling for PMON/SPIM, force cycle-dependent - Count/Compare maintenance. */ +/* Strictly follow the architecture standard: + - Disallow "special" instruction handling for PMON/SPIM. + Note that we still maintain Count/Compare to match the host clock. */ //#define MIPS_STRICT_STANDARD 1 #endif /* !defined (__QEMU_MIPS_DEFS_H__) */ -- cgit v1.2.3 From b9652ca3a5c027f8bc55323e0f6010f641479255 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 20 Apr 2007 19:35:25 +0000 Subject: Fix keyboard serial and mouse bugs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2709 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 54debce4a..0e3a622db 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -222,8 +222,6 @@ static inline void clr_rxint(ChannelState *s) } if (s->txint) set_txint(s); - else - s->rregs[2] = 6; slavio_serial_update_irq(s); } @@ -237,30 +235,39 @@ static inline void set_rxint(ChannelState *s) s->otherchn->rregs[2] = 0x30; else s->otherchn->rregs[2] = 0x0c; - s->rregs[3] |= 0x20; } else { if (s->wregs[9] & 0x10) s->rregs[2] = 0x20; else s->rregs[2] = 0x04; - s->otherchn->rregs[3] |= 4; } - slavio_serial_update_irq(s); } + if (s->chn == chn_a) + s->rregs[3] |= 0x20; + else + s->otherchn->rregs[3] |= 4; + slavio_serial_update_irq(s); } static inline void clr_txint(ChannelState *s) { s->txint = 0; s->txint_under_svc = 0; - if (s->chn == chn_a) + if (s->chn == chn_a) { + if (s->wregs[9] & 0x10) + s->otherchn->rregs[2] = 0x60; + else + s->otherchn->rregs[2] = 0x06; s->rregs[3] &= ~0x10; - else + } else { + if (s->wregs[9] & 0x10) + s->rregs[2] = 0x60; + else + s->rregs[2] = 0x06; s->otherchn->rregs[3] &= ~2; + } if (s->rxint) set_rxint(s); - else - s->rregs[2] = 6; slavio_serial_update_irq(s); } @@ -269,13 +276,20 @@ static inline void set_txint(ChannelState *s) s->txint = 1; if (!s->rxint_under_svc) { s->txint_under_svc = 1; - if (s->chn == chn_a) - s->rregs[3] |= 0x10; - else - s->otherchn->rregs[3] |= 2; - s->rregs[2] = 0; - slavio_serial_update_irq(s); + if (s->chn == chn_a) { + if (s->wregs[9] & 0x10) + s->otherchn->rregs[2] = 0x10; + else + s->otherchn->rregs[2] = 0x08; + } else { + s->rregs[2] = 0; + } } + if (s->chn == chn_a) + s->rregs[3] |= 0x10; + else + s->otherchn->rregs[3] |= 2; + slavio_serial_update_irq(s); } static void slavio_serial_update_parameters(ChannelState *s) -- cgit v1.2.3 From eee0b8367b01ff1bbe6159212a8d33ff587fc200 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 21 Apr 2007 19:45:49 +0000 Subject: TCX 24 bit model support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2710 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 6 +- hw/tcx.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- vl.c | 3 +- vl.h | 7 +- 4 files changed, 232 insertions(+), 15 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index f37127873..c24e52aad 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -234,8 +234,12 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, dma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], slavio_irq[hwdef->le_irq], iommu); + if (graphic_depth != 8 && graphic_depth != 24) { + fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); + exit (1); + } tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size, - hwdef->vram_size, graphic_width, graphic_height); + hwdef->vram_size, graphic_width, graphic_height, graphic_depth); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { diff --git a/hw/tcx.c b/hw/tcx.c index 20d9340c4..73ea813a1 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -31,14 +31,16 @@ typedef struct TCXState { uint32_t addr; DisplayState *ds; uint8_t *vram; - ram_addr_t vram_offset; - uint16_t width, height; + uint32_t *vram24, *cplane; + ram_addr_t vram_offset, vram24_offset, cplane_offset; + uint16_t width, height, depth; uint8_t r[256], g[256], b[256]; uint32_t palette[256]; uint8_t dac_index, dac_state; } TCXState; static void tcx_screen_dump(void *opaque, const char *filename); +static void tcx24_screen_dump(void *opaque, const char *filename); /* XXX: unify with vga draw line functions */ static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) @@ -121,6 +123,57 @@ static void tcx_draw_line8(TCXState *s1, uint8_t *d, } } +static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, + const uint8_t *s, int width, + const uint32_t *cplane, + const uint32_t *s24) +{ + int x; + uint8_t val; + uint32_t *p = (uint32_t *)d; + uint32_t dval; + + for(x = 0; x < width; x++, s++, s24++) { + if ((bswap32(*cplane++) & 0xff000000) == 0x03000000) { // 24-bit direct + dval = bswap32(*s24) & 0x00ffffff; + } else { + val = *s; + dval = s1->palette[val]; + } + *p++ = dval; + } +} + +static inline int check_dirty(TCXState *ts, ram_addr_t page, ram_addr_t page24, + ram_addr_t cpage) +{ + int ret; + unsigned int off; + + ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG); + for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) { + ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG); + ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG); + } + return ret; +} + +static inline void reset_dirty(TCXState *ts, ram_addr_t page_min, + ram_addr_t page_max, ram_addr_t page24, + ram_addr_t cpage) +{ + cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, + VGA_DIRTY_FLAG); + page_min -= ts->vram_offset; + page_max -= ts->vram_offset; + cpu_physical_memory_reset_dirty(page24 + page_min * 4, + page24 + page_max * 4 + TARGET_PAGE_SIZE, + VGA_DIRTY_FLAG); + cpu_physical_memory_reset_dirty(cpage + page_min * 4, + cpage + page_max * 4 + TARGET_PAGE_SIZE, + VGA_DIRTY_FLAG); +} + /* Fixed line length 1024 allows us to do nice tricks not possible on VGA... */ static void tcx_update_display(void *opaque) @@ -201,6 +254,82 @@ static void tcx_update_display(void *opaque) } } +static void tcx24_update_display(void *opaque) +{ + TCXState *ts = opaque; + ram_addr_t page, page_min, page_max, cpage, page24; + int y, y_start, dd, ds; + uint8_t *d, *s; + uint32_t *cptr, *s24; + + if (ts->ds->depth != 32) + return; + page = ts->vram_offset; + page24 = ts->vram24_offset; + cpage = ts->cplane_offset; + y_start = -1; + page_min = 0xffffffff; + page_max = 0; + d = ts->ds->data; + s = ts->vram; + s24 = ts->vram24; + cptr = ts->cplane; + dd = ts->ds->linesize; + ds = 1024; + + for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE, + page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { + if (check_dirty(ts, page, page24, cpage)) { + if (y_start < 0) + y_start = y; + if (page < page_min) + page_min = page; + if (page > page_max) + page_max = page; + tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + d += dd; + s += ds; + cptr += ds; + s24 += ds; + tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + d += dd; + s += ds; + cptr += ds; + s24 += ds; + tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + d += dd; + s += ds; + cptr += ds; + s24 += ds; + tcx24_draw_line32(ts, d, s, ts->width, cptr, s24); + d += dd; + s += ds; + cptr += ds; + s24 += ds; + } else { + if (y_start >= 0) { + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + ts->width, y - y_start); + y_start = -1; + } + d += dd * 4; + s += ds * 4; + cptr += ds * 4; + s24 += ds * 4; + } + } + if (y_start >= 0) { + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + ts->width, y - y_start); + } + /* reset modified pages */ + if (page_min <= page_max) { + reset_dirty(ts, page_min, page_max, page24, cpage); + } +} + static void tcx_invalidate_display(void *opaque) { TCXState *s = opaque; @@ -211,14 +340,29 @@ static void tcx_invalidate_display(void *opaque) } } +static void tcx24_invalidate_display(void *opaque) +{ + TCXState *s = opaque; + int i; + + tcx_invalidate_display(s); + for (i = 0; i < MAXX*MAXY * 4; i += TARGET_PAGE_SIZE) { + cpu_physical_memory_set_dirty(s->vram24_offset + i); + cpu_physical_memory_set_dirty(s->cplane_offset + i); + } +} + static void tcx_save(QEMUFile *f, void *opaque) { TCXState *s = opaque; qemu_put_be32s(f, (uint32_t *)&s->addr); qemu_put_be32s(f, (uint32_t *)&s->vram); + qemu_put_be32s(f, (uint32_t *)&s->vram24); + qemu_put_be32s(f, (uint32_t *)&s->cplane); qemu_put_be16s(f, (uint16_t *)&s->height); qemu_put_be16s(f, (uint16_t *)&s->width); + qemu_put_be16s(f, (uint16_t *)&s->depth); qemu_put_buffer(f, s->r, 256); qemu_put_buffer(f, s->g, 256); qemu_put_buffer(f, s->b, 256); @@ -230,13 +374,16 @@ static int tcx_load(QEMUFile *f, void *opaque, int version_id) { TCXState *s = opaque; - if (version_id != 1) + if (version_id != 2) return -EINVAL; qemu_get_be32s(f, (uint32_t *)&s->addr); qemu_get_be32s(f, (uint32_t *)&s->vram); + qemu_get_be32s(f, (uint32_t *)&s->vram24); + qemu_get_be32s(f, (uint32_t *)&s->cplane); qemu_get_be16s(f, (uint16_t *)&s->height); qemu_get_be16s(f, (uint16_t *)&s->width); + qemu_get_be16s(f, (uint16_t *)&s->depth); qemu_get_buffer(f, s->r, 256); qemu_get_buffer(f, s->g, 256); qemu_get_buffer(f, s->b, 256); @@ -259,8 +406,8 @@ static void tcx_reset(void *opaque) s->r[255] = s->g[255] = s->b[255] = 255; update_palette_entries(s, 0, 256); memset(s->vram, 0, MAXX*MAXY); - cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY, - VGA_DIRTY_FLAG); + cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + + MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG); s->dac_index = 0; s->dac_state = 0; } @@ -321,27 +468,54 @@ static CPUWriteMemoryFunc *tcx_dac_write[3] = { }; void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, - unsigned long vram_offset, int vram_size, int width, int height) + unsigned long vram_offset, int vram_size, int width, int height, + int depth) { TCXState *s; int io_memory; + int size; s = qemu_mallocz(sizeof(TCXState)); if (!s) return; s->ds = ds; s->addr = addr; - s->vram = vram_base; s->vram_offset = vram_offset; s->width = width; s->height = height; + s->depth = depth; + + // 8-bit plane + s->vram = vram_base; + size = vram_size; + cpu_register_physical_memory(addr + 0x00800000, size, vram_offset); + vram_offset += size; + vram_base += size; - cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset); io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); - cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory); + cpu_register_physical_memory(addr + 0x00200000, TCX_DAC_NREGS, io_memory); + + if (depth == 24) { + // 24-bit plane + size = vram_size * 4; + s->vram24 = (uint32_t *)vram_base; + s->vram24_offset = vram_offset; + cpu_register_physical_memory(addr + 0x02000000, size, vram_offset); + vram_offset += size; + vram_base += size; + + // Control plane + size = vram_size * 4; + s->cplane = (uint32_t *)vram_base; + s->cplane_offset = vram_offset; + cpu_register_physical_memory(addr + 0x0a000000, size, vram_offset); + graphic_console_init(s->ds, tcx24_update_display, tcx24_invalidate_display, + tcx24_screen_dump, s); + } else { + graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, + tcx_screen_dump, s); + } - graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, - tcx_screen_dump, s); register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); qemu_register_reset(tcx_reset, s); tcx_reset(s); @@ -375,5 +549,38 @@ static void tcx_screen_dump(void *opaque, const char *filename) return; } +static void tcx24_screen_dump(void *opaque, const char *filename) +{ + TCXState *s = opaque; + FILE *f; + uint8_t *d, *d1, v; + uint32_t *s24, *cptr, dval; + int y, x; - + f = fopen(filename, "wb"); + if (!f) + return; + fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + d1 = s->vram; + s24 = s->vram24; + cptr = s->cplane; + for(y = 0; y < s->height; y++) { + d = d1; + for(x = 0; x < s->width; x++, d++, s24++) { + if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct + dval = *s24 & 0x00ffffff; + fputc((dval >> 16) & 0xff, f); + fputc((dval >> 8) & 0xff, f); + fputc(dval & 0xff, f); + } else { + v = *d; + fputc(s->r[v], f); + fputc(s->g[v], f); + fputc(s->b[v], f); + } + } + d1 += MAXX; + } + fclose(f); + return; +} diff --git a/vl.c b/vl.c index 999fcefce..ad632a20e 100644 --- a/vl.c +++ b/vl.c @@ -159,11 +159,12 @@ int vmsvga_enabled = 0; #ifdef TARGET_SPARC int graphic_width = 1024; int graphic_height = 768; +int graphic_depth = 8; #else int graphic_width = 800; int graphic_height = 600; -#endif int graphic_depth = 15; +#endif int full_screen = 0; int no_frame = 0; int no_quit = 0; diff --git a/vl.h b/vl.h index 5e47bf98b..855a854ec 100644 --- a/vl.h +++ b/vl.h @@ -889,7 +889,11 @@ extern struct soundhw soundhw[]; /* vga.c */ +#ifndef TARGET_SPARC #define VGA_RAM_SIZE (8192 * 1024) +#else +#define VGA_RAM_SIZE (9 * 1024 * 1024) +#endif struct DisplayState { uint8_t *data; @@ -1206,7 +1210,8 @@ static inline void sparc_iommu_memory_write(void *opaque, /* tcx.c */ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, - unsigned long vram_offset, int vram_size, int width, int height); + unsigned long vram_offset, int vram_size, int width, int height, + int depth); /* slavio_intctl.c */ void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); -- cgit v1.2.3 From a68156d016383c2f2fb183080b3f75ce0d32abd1 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 22 Apr 2007 12:45:28 +0000 Subject: Constification git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2711 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 20dffe0d9..5a5868f81 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -108,7 +108,7 @@ static int sign_extend(int x, int len) static void disas_sparc_insn(DisasContext * dc); -static GenOpFunc *gen_op_movl_TN_reg[2][32] = { +static GenOpFunc * const gen_op_movl_TN_reg[2][32] = { { gen_op_movl_g0_T0, gen_op_movl_g1_T0, @@ -179,7 +179,7 @@ static GenOpFunc *gen_op_movl_TN_reg[2][32] = { } }; -static GenOpFunc *gen_op_movl_reg_TN[3][32] = { +static GenOpFunc * const gen_op_movl_reg_TN[3][32] = { { gen_op_movl_T0_g0, gen_op_movl_T0_g1, @@ -284,7 +284,7 @@ static GenOpFunc *gen_op_movl_reg_TN[3][32] = { } }; -static GenOpFunc1 *gen_op_movl_TN_im[3] = { +static GenOpFunc1 * const gen_op_movl_TN_im[3] = { gen_op_movl_T0_im, gen_op_movl_T1_im, gen_op_movl_T2_im @@ -299,7 +299,7 @@ static GenOpFunc1 * const gen_op_movl_TN_sim[3] = { #ifdef TARGET_SPARC64 #define GEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [64] = { \ +static GenOpFunc * const NAME ## _table [64] = { \ NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ @@ -319,7 +319,7 @@ static inline void func(int n) \ } #else #define GEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ +static GenOpFunc *const NAME ## _table [32] = { \ NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ @@ -380,7 +380,7 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); #else #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() #define OP_LD_TABLE(width) \ - static GenOpFunc *gen_op_##width[] = { \ + static GenOpFunc * const gen_op_##width[] = { \ &gen_op_##width##_user, \ &gen_op_##width##_kernel, \ }; \ @@ -414,7 +414,7 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); #else #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() #define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_##width[] = { \ +static GenOpFunc * const gen_op_##width[] = { \ &gen_op_##width##_user, \ &gen_op_##width##_kernel, \ }; \ -- cgit v1.2.3 From fc81ba536bc3d8cdbcf9e92369e9bc5ede69da10 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 22 Apr 2007 17:16:54 +0000 Subject: Check that HOST_SOLARIS is defined before relying on its value. Spotted by Joachim Henke. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2712 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-native.c | 4 ++-- fpu/softfloat-native.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index d827ae6fe..9994f6d27 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -30,7 +30,7 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) #define sqrtf(f) ((float)sqrt(f)) #define remainderf(fa, fb) ((float)remainder(fa, fb)) #define rintf(f) ((float)rint(f)) -#if !defined(__sparc__) && HOST_SOLARIS < 10 +#if !defined(__sparc__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10 extern long double rintl(long double); extern long double scalbnl(long double, int); @@ -336,7 +336,7 @@ uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision operations. *----------------------------------------------------------------------------*/ -#if ( defined(__sun__) && ( HOST_SOLARIS < 10 )) +#if defined(__sun__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10 static inline float64 trunc(float64 x) { return x < 0 ? -floor(-x) : floor(x); diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 49cff5d89..29777178b 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -15,7 +15,7 @@ * Solaris 10 with GCC4 does not need these macros as they * are defined in with a compiler directive */ -#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ( ( HOST_SOLARIS >= 10 ) && ( __GNUC__ <= 4) )) +#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) && (__GNUC__ <= 4))) /* * C99 7.12.3 classification macros * and -- cgit v1.2.3 From 3d834c78b28ec08f857ce1fcbd2e962ad7b87740 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 22 Apr 2007 17:18:38 +0000 Subject: Typo fix, by Wang Cheng Yeh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2713 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lsi53c895a.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 06107b5f7..71afd1f73 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1389,7 +1389,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) break; case 0x02: /* SCNTL2 */ val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS); - s->scntl3 = val; + s->scntl2 = val; break; case 0x03: /* SCNTL3 */ s->scntl3 = val; @@ -1457,19 +1457,19 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) } s->ctest5 = val; break; - case 0x2c: /* DSPS[0:7] */ + case 0x2c: /* DSP[0:7] */ s->dsp &= 0xffffff00; s->dsp |= val; break; - case 0x2d: /* DSPS[8:15] */ + case 0x2d: /* DSP[8:15] */ s->dsp &= 0xffff00ff; s->dsp |= val << 8; break; - case 0x2e: /* DSPS[16:23] */ + case 0x2e: /* DSP[16:23] */ s->dsp &= 0xff00ffff; s->dsp |= val << 16; break; - case 0x2f: /* DSPS[14:31] */ + case 0x2f: /* DSP[24:31] */ s->dsp &= 0x00ffffff; s->dsp |= val << 24; if ((s->dmode & LSI_DMODE_MAN) == 0 -- cgit v1.2.3 From e9ebed4d41fc0630e433a32ecfd1057cae8b10bf Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 22 Apr 2007 19:14:52 +0000 Subject: Sparc64 update: more VIS ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2714 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 3 + target-sparc/op.c | 467 ++++++++++++++++++++++++++++++++++++++++++++++- target-sparc/translate.c | 450 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 884 insertions(+), 36 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 50e162a27..f3f872ff7 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -225,6 +225,9 @@ typedef struct CPUSPARCState { uint64_t fprs; uint64_t tick_cmpr, stick_cmpr; uint64_t gsr; + uint32_t gl; // UA2005 + /* UA 2005 hyperprivileged registers */ + uint64_t hpstate, htstate[MAXTL], hintp, htba, hver, hstick_cmpr, ssr; #endif #if !defined(TARGET_SPARC64) && !defined(reg_T2) target_ulong t2; diff --git a/target-sparc/op.c b/target-sparc/op.c index 2c21b5331..7a4bd7957 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1095,7 +1095,7 @@ void OPPROTO op_rdtick(void) void OPPROTO op_wrtick(void) { - // XXX write cycle counter and bit 31 + T0 = 0; // XXX write cycle counter and bit 31 } void OPPROTO op_rdtpc(void) @@ -1818,8 +1818,7 @@ void OPPROTO op_retry(void) void OPPROTO op_sir(void) { - // XXX - + T0 = 0; // XXX } void OPPROTO op_ld_asi_reg() @@ -1846,6 +1845,44 @@ void OPPROTO op_st_asi() } #ifdef TARGET_SPARC64 +// This function uses non-native bit order +#define GET_FIELD(X, FROM, TO) \ + ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1)) + +// This function uses the order in the manuals, i.e. bit 0 is 2^0 +#define GET_FIELD_SP(X, FROM, TO) \ + GET_FIELD(X, 63 - (TO), 63 - (FROM)) + +void OPPROTO op_array8() +{ + T0 = (GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) | + (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) | + (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) | + (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) | + (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) | + (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12); +} + +void OPPROTO op_array16() +{ + T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) | + (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) | + (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) | + (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) | + (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) | + (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 1; +} + +void OPPROTO op_array32() +{ + T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) | + (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) | + (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) | + (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) | + (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) | + (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 2; +} + void OPPROTO op_alignaddr() { uint64_t tmp; @@ -1862,26 +1899,440 @@ void OPPROTO op_faligndata() tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8); tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8); - (*((uint64_t *)&DT0)) = tmp; + *((uint64_t *)&DT0) = tmp; } void OPPROTO op_movl_FT0_0(void) { - (*((uint32_t *)&FT0)) = 0; + *((uint32_t *)&FT0) = 0; } void OPPROTO op_movl_DT0_0(void) { - (*((uint64_t *)&DT0)) = 0; + *((uint64_t *)&DT0) = 0; } void OPPROTO op_movl_FT0_1(void) { - (*((uint32_t *)&FT0)) = 0xffffffff; + *((uint32_t *)&FT0) = 0xffffffff; } void OPPROTO op_movl_DT0_1(void) { - (*((uint64_t *)&DT0)) = 0xffffffffffffffffULL; + *((uint64_t *)&DT0) = 0xffffffffffffffffULL; +} + +void OPPROTO op_fnot(void) +{ + *(uint64_t *)&DT0 = ~*(uint64_t *)&DT1; +} + +void OPPROTO op_fnots(void) +{ + *(uint32_t *)&FT0 = ~*(uint32_t *)&FT1; +} + +void OPPROTO op_fnor(void) +{ + *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 | *(uint64_t *)&DT1); +} + +void OPPROTO op_fnors(void) +{ + *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 | *(uint32_t *)&FT1); +} + +void OPPROTO op_for(void) +{ + *(uint64_t *)&DT0 |= *(uint64_t *)&DT1; +} + +void OPPROTO op_fors(void) +{ + *(uint32_t *)&FT0 |= *(uint32_t *)&FT1; +} + +void OPPROTO op_fxor(void) +{ + *(uint64_t *)&DT0 ^= *(uint64_t *)&DT1; +} + +void OPPROTO op_fxors(void) +{ + *(uint32_t *)&FT0 ^= *(uint32_t *)&FT1; +} + +void OPPROTO op_fand(void) +{ + *(uint64_t *)&DT0 &= *(uint64_t *)&DT1; +} + +void OPPROTO op_fands(void) +{ + *(uint32_t *)&FT0 &= *(uint32_t *)&FT1; +} + +void OPPROTO op_fornot(void) +{ + *(uint64_t *)&DT0 = *(uint64_t *)&DT0 | ~*(uint64_t *)&DT1; +} + +void OPPROTO op_fornots(void) +{ + *(uint32_t *)&FT0 = *(uint32_t *)&FT0 | ~*(uint32_t *)&FT1; +} + +void OPPROTO op_fandnot(void) +{ + *(uint64_t *)&DT0 = *(uint64_t *)&DT0 & ~*(uint64_t *)&DT1; +} + +void OPPROTO op_fandnots(void) +{ + *(uint32_t *)&FT0 = *(uint32_t *)&FT0 & ~*(uint32_t *)&FT1; +} + +void OPPROTO op_fnand(void) +{ + *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 & *(uint64_t *)&DT1); +} + +void OPPROTO op_fnands(void) +{ + *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 & *(uint32_t *)&FT1); +} + +void OPPROTO op_fxnor(void) +{ + *(uint64_t *)&DT0 ^= ~*(uint64_t *)&DT1; +} + +void OPPROTO op_fxnors(void) +{ + *(uint32_t *)&FT0 ^= ~*(uint32_t *)&FT1; +} + +#ifdef WORDS_BIGENDIAN +#define VIS_B64(n) b[7 - (n)] +#define VIS_W64(n) w[3 - (n)] +#define VIS_SW64(n) sw[3 - (n)] +#define VIS_L64(n) l[1 - (n)] +#define VIS_B32(n) b[3 - (n)] +#define VIS_W32(n) w[1 - (n)] +#else +#define VIS_B64(n) b[n] +#define VIS_W64(n) w[n] +#define VIS_SW64(n) sw[n] +#define VIS_L64(n) l[n] +#define VIS_B32(n) b[n] +#define VIS_W32(n) w[n] +#endif + +typedef union { + uint8_t b[8]; + uint16_t w[4]; + int16_t sw[4]; + uint32_t l[2]; + float64 d; +} vis64; + +typedef union { + uint8_t b[4]; + uint16_t w[2]; + uint32_t l; + float32 f; +} vis32; + +void OPPROTO op_fpmerge(void) +{ + vis64 s, d; + + s.d = DT0; + d.d = DT1; + + // Reverse calculation order to handle overlap + d.VIS_B64(7) = s.VIS_B64(3); + d.VIS_B64(6) = d.VIS_B64(3); + d.VIS_B64(5) = s.VIS_B64(2); + d.VIS_B64(4) = d.VIS_B64(2); + d.VIS_B64(3) = s.VIS_B64(1); + d.VIS_B64(2) = d.VIS_B64(1); + d.VIS_B64(1) = s.VIS_B64(0); + //d.VIS_B64(0) = d.VIS_B64(0); + + DT0 = d.d; +} + +void OPPROTO op_fmul8x16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void OPPROTO op_fmul8x16al(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; } + +void OPPROTO op_fmul8x16au(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void OPPROTO op_fmul8sux16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void OPPROTO op_fmul8ulx16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_W64(r) = tmp >> 8; + + PMUL(0); + PMUL(1); + PMUL(2); + PMUL(3); +#undef PMUL + + DT0 = d.d; +} + +void OPPROTO op_fmuld8sux16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_L64(r) = tmp; + + // Reverse calculation order to handle overlap + PMUL(1); + PMUL(0); +#undef PMUL + + DT0 = d.d; +} + +void OPPROTO op_fmuld8ulx16(void) +{ + vis64 s, d; + uint32_t tmp; + + s.d = DT0; + d.d = DT1; + +#define PMUL(r) \ + tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ + if ((tmp & 0xff) > 0x7f) \ + tmp += 0x100; \ + d.VIS_L64(r) = tmp; + + // Reverse calculation order to handle overlap + PMUL(1); + PMUL(0); +#undef PMUL + + DT0 = d.d; +} + +void OPPROTO op_fexpand(void) +{ + vis32 s; + vis64 d; + + s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff); + d.d = DT1; + d.VIS_L64(0) = s.VIS_W32(0) << 4; + d.VIS_L64(1) = s.VIS_W32(1) << 4; + d.VIS_L64(2) = s.VIS_W32(2) << 4; + d.VIS_L64(3) = s.VIS_W32(3) << 4; + + DT0 = d.d; +} + +#define VIS_OP(name, F) \ + void OPPROTO name##16(void) \ + { \ + vis64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \ + d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \ + d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \ + d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \ + \ + DT0 = d.d; \ + } \ + \ + void OPPROTO name##16s(void) \ + { \ + vis32 s, d; \ + \ + s.f = FT0; \ + d.f = FT1; \ + \ + d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \ + d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \ + \ + FT0 = d.f; \ + } \ + \ + void OPPROTO name##32(void) \ + { \ + vis64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \ + d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \ + \ + DT0 = d.d; \ + } \ + \ + void OPPROTO name##32s(void) \ + { \ + vis32 s, d; \ + \ + s.f = FT0; \ + d.f = FT1; \ + \ + d.l = F(d.l, s.l); \ + \ + FT0 = d.f; \ + } + +#define FADD(a, b) ((a) + (b)) +#define FSUB(a, b) ((a) - (b)) +VIS_OP(op_fpadd, FADD) +VIS_OP(op_fpsub, FSUB) + +#define VIS_CMPOP(name, F) \ + void OPPROTO name##16(void) \ + { \ + vis64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0; \ + d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0; \ + d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0; \ + d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0; \ + \ + DT0 = d.d; \ + } \ + \ + void OPPROTO name##32(void) \ + { \ + vis64 s, d; \ + \ + s.d = DT0; \ + d.d = DT1; \ + \ + d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0; \ + d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0; \ + \ + DT0 = d.d; \ + } + +#define FCMPGT(a, b) ((a) > (b)) +#define FCMPEQ(a, b) ((a) == (b)) +#define FCMPLE(a, b) ((a) <= (b)) +#define FCMPNE(a, b) ((a) != (b)) + +VIS_CMPOP(op_fcmpgt, FCMPGT) +VIS_CMPOP(op_fcmpeq, FCMPEQ) +VIS_CMPOP(op_fcmple, FCMPLE) +VIS_CMPOP(op_fcmpne, FCMPNE) + #endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 5a5868f81..0812e95a3 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -350,6 +350,7 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); // 'a' versions allowed to user depending on asi #if defined(CONFIG_USER_ONLY) #define supervisor(dc) 0 +#define hypervisor(dc) 0 #define gen_op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) \ static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ @@ -405,6 +406,7 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); } #define supervisor(dc) (dc->mem_idx == 1) +#define hypervisor(dc) (dc->mem_idx == 2) #endif #else #if defined(CONFIG_USER_ONLY) @@ -1218,14 +1220,40 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; } #if !defined(CONFIG_USER_ONLY) + } else if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */ #ifndef TARGET_SPARC64 - } else if (xop == 0x29) { /* rdpsr / V9 unimp */ if (!supervisor(dc)) goto priv_insn; gen_op_rdpsr(); +#else + if (!hypervisor(dc)) + goto priv_insn; + rs1 = GET_FIELD(insn, 13, 17); + switch (rs1) { + case 0: // hpstate + // gen_op_rdhpstate(); + break; + case 1: // htstate + // gen_op_rdhtstate(); + break; + case 3: // hintp + gen_op_movl_T0_env(offsetof(CPUSPARCState, hintp)); + break; + case 5: // htba + gen_op_movl_T0_env(offsetof(CPUSPARCState, htba)); + break; + case 6: // hver + gen_op_movl_T0_env(offsetof(CPUSPARCState, hver)); + break; + case 31: // hstick_cmpr + gen_op_movl_env_T0(offsetof(CPUSPARCState, hstick_cmpr)); + break; + default: + goto illegal_insn; + } +#endif gen_movl_T0_reg(rd); break; -#endif } else if (xop == 0x2a) { /* rdwim / V9 rdpr */ if (!supervisor(dc)) goto priv_insn; @@ -1277,6 +1305,14 @@ static void disas_sparc_insn(DisasContext * dc) case 14: // wstate gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate)); break; + case 16: // UA2005 gl + gen_op_movl_T0_env(offsetof(CPUSPARCState, gl)); + break; + case 26: // UA2005 strand status + if (!hypervisor(dc)) + goto priv_insn; + gen_op_movl_T0_env(offsetof(CPUSPARCState, ssr)); + break; case 31: // ver gen_op_movtl_T0_env(offsetof(CPUSPARCState, version)); break; @@ -1997,6 +2033,11 @@ static void disas_sparc_insn(DisasContext * dc) case 1: gen_op_restored(); break; + case 2: /* UA2005 allclean */ + case 3: /* UA2005 otherw */ + case 4: /* UA2005 normalw */ + case 5: /* UA2005 invalw */ + // XXX default: goto illegal_insn; } @@ -2068,6 +2109,14 @@ static void disas_sparc_insn(DisasContext * dc) case 14: // wstate gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate)); break; + case 16: // UA2005 gl + gen_op_movl_env_T0(offsetof(CPUSPARCState, gl)); + break; + case 26: // UA2005 strand status + if (!hypervisor(dc)) + goto priv_insn; + gen_op_movl_env_T0(offsetof(CPUSPARCState, ssr)); + break; default: goto illegal_insn; } @@ -2076,17 +2125,46 @@ static void disas_sparc_insn(DisasContext * dc) #endif } break; -#ifndef TARGET_SPARC64 - case 0x33: /* wrtbr, V9 unimp */ + case 0x33: /* wrtbr, UA2005 wrhpr */ { +#ifndef TARGET_SPARC64 if (!supervisor(dc)) goto priv_insn; gen_op_xor_T1_T0(); - gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); +#else + if (!hypervisor(dc)) + goto priv_insn; + gen_op_xor_T1_T0(); + switch (rd) { + case 0: // hpstate + // XXX gen_op_wrhpstate(); + save_state(dc); + gen_op_next_insn(); + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; + break; + case 1: // htstate + // XXX gen_op_wrhtstate(); + break; + case 3: // hintp + gen_op_movl_env_T0(offsetof(CPUSPARCState, hintp)); + break; + case 5: // htba + gen_op_movl_env_T0(offsetof(CPUSPARCState, htba)); + break; + case 31: // hstick_cmpr + gen_op_movl_env_T0(offsetof(CPUSPARCState, hstick_cmpr)); + break; + case 6: // hver readonly + default: + goto illegal_insn; + } +#endif } break; #endif -#endif #ifdef TARGET_SPARC64 case 0x2c: /* V9 movcc */ { @@ -2164,77 +2242,393 @@ static void disas_sparc_insn(DisasContext * dc) int opf = GET_FIELD_SP(insn, 5, 13); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; switch (opf) { + case 0x000: /* VIS I edge8cc */ + case 0x001: /* VIS II edge8n */ + case 0x002: /* VIS I edge8lcc */ + case 0x003: /* VIS II edge8ln */ + case 0x004: /* VIS I edge16cc */ + case 0x005: /* VIS II edge16n */ + case 0x006: /* VIS I edge16lcc */ + case 0x007: /* VIS II edge16ln */ + case 0x008: /* VIS I edge32cc */ + case 0x009: /* VIS II edge32n */ + case 0x00a: /* VIS I edge32lcc */ + case 0x00b: /* VIS II edge32ln */ + // XXX + goto illegal_insn; + case 0x010: /* VIS I array8 */ + gen_movl_reg_T0(rs1); + gen_movl_reg_T1(rs2); + gen_op_array8(); + gen_movl_T0_reg(rd); + break; + case 0x012: /* VIS I array16 */ + gen_movl_reg_T0(rs1); + gen_movl_reg_T1(rs2); + gen_op_array16(); + gen_movl_T0_reg(rd); + break; + case 0x014: /* VIS I array32 */ + gen_movl_reg_T0(rs1); + gen_movl_reg_T1(rs2); + gen_op_array32(); + gen_movl_T0_reg(rd); + break; case 0x018: /* VIS I alignaddr */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_movl_reg_T0(rs1); gen_movl_reg_T1(rs2); gen_op_alignaddr(); gen_movl_T0_reg(rd); break; + case 0x019: /* VIS II bmask */ case 0x01a: /* VIS I alignaddrl */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; // XXX + goto illegal_insn; + case 0x020: /* VIS I fcmple16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmple16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x022: /* VIS I fcmpne16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpne16(); + gen_op_store_DT0_fpr(rd); break; + case 0x024: /* VIS I fcmple32 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmple32(); + gen_op_store_DT0_fpr(rd); + break; + case 0x026: /* VIS I fcmpne32 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpne32(); + gen_op_store_DT0_fpr(rd); + break; + case 0x028: /* VIS I fcmpgt16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpgt16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x02a: /* VIS I fcmpeq16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpeq16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x02c: /* VIS I fcmpgt32 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpgt32(); + gen_op_store_DT0_fpr(rd); + break; + case 0x02e: /* VIS I fcmpeq32 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fcmpeq32(); + gen_op_store_DT0_fpr(rd); + break; + case 0x031: /* VIS I fmul8x16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fmul8x16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x033: /* VIS I fmul8x16au */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fmul8x16au(); + gen_op_store_DT0_fpr(rd); + break; + case 0x035: /* VIS I fmul8x16al */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fmul8x16al(); + gen_op_store_DT0_fpr(rd); + break; + case 0x036: /* VIS I fmul8sux16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fmul8sux16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x037: /* VIS I fmul8ulx16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fmul8ulx16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x038: /* VIS I fmuld8sux16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fmuld8sux16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x039: /* VIS I fmuld8ulx16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fmuld8ulx16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x03a: /* VIS I fpack32 */ + case 0x03b: /* VIS I fpack16 */ + case 0x03d: /* VIS I fpackfix */ + case 0x03e: /* VIS I pdist */ + // XXX + goto illegal_insn; case 0x048: /* VIS I faligndata */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_load_fpr_DT0(rs1); gen_op_load_fpr_DT1(rs2); gen_op_faligndata(); gen_op_store_DT0_fpr(rd); break; + case 0x04b: /* VIS I fpmerge */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fpmerge(); + gen_op_store_DT0_fpr(rd); + break; + case 0x04c: /* VIS II bshuffle */ + // XXX + goto illegal_insn; + case 0x04d: /* VIS I fexpand */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fexpand(); + gen_op_store_DT0_fpr(rd); + break; + case 0x050: /* VIS I fpadd16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fpadd16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x051: /* VIS I fpadd16s */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fpadd16s(); + gen_op_store_FT0_fpr(rd); + break; + case 0x052: /* VIS I fpadd32 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fpadd32(); + gen_op_store_DT0_fpr(rd); + break; + case 0x053: /* VIS I fpadd32s */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fpadd32s(); + gen_op_store_FT0_fpr(rd); + break; + case 0x054: /* VIS I fpsub16 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fpsub16(); + gen_op_store_DT0_fpr(rd); + break; + case 0x055: /* VIS I fpsub16s */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fpsub16s(); + gen_op_store_FT0_fpr(rd); + break; + case 0x056: /* VIS I fpsub32 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fpadd32(); + gen_op_store_DT0_fpr(rd); + break; + case 0x057: /* VIS I fpsub32s */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fpsub32s(); + gen_op_store_FT0_fpr(rd); + break; case 0x060: /* VIS I fzero */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_movl_DT0_0(); gen_op_store_DT0_fpr(rd); break; case 0x061: /* VIS I fzeros */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_movl_FT0_0(); gen_op_store_FT0_fpr(rd); break; + case 0x062: /* VIS I fnor */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fnor(); + gen_op_store_DT0_fpr(rd); + break; + case 0x063: /* VIS I fnors */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fnors(); + gen_op_store_FT0_fpr(rd); + break; + case 0x064: /* VIS I fandnot2 */ + gen_op_load_fpr_DT1(rs1); + gen_op_load_fpr_DT0(rs2); + gen_op_fandnot(); + gen_op_store_DT0_fpr(rd); + break; + case 0x065: /* VIS I fandnot2s */ + gen_op_load_fpr_FT1(rs1); + gen_op_load_fpr_FT0(rs2); + gen_op_fandnots(); + gen_op_store_FT0_fpr(rd); + break; + case 0x066: /* VIS I fnot2 */ + gen_op_load_fpr_DT1(rs2); + gen_op_fnot(); + gen_op_store_DT0_fpr(rd); + break; + case 0x067: /* VIS I fnot2s */ + gen_op_load_fpr_FT1(rs2); + gen_op_fnot(); + gen_op_store_FT0_fpr(rd); + break; + case 0x068: /* VIS I fandnot1 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fandnot(); + gen_op_store_DT0_fpr(rd); + break; + case 0x069: /* VIS I fandnot1s */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fandnots(); + gen_op_store_FT0_fpr(rd); + break; + case 0x06a: /* VIS I fnot1 */ + gen_op_load_fpr_DT1(rs1); + gen_op_fnot(); + gen_op_store_DT0_fpr(rd); + break; + case 0x06b: /* VIS I fnot1s */ + gen_op_load_fpr_FT1(rs1); + gen_op_fnot(); + gen_op_store_FT0_fpr(rd); + break; + case 0x06c: /* VIS I fxor */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fxor(); + gen_op_store_DT0_fpr(rd); + break; + case 0x06d: /* VIS I fxors */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fxors(); + gen_op_store_FT0_fpr(rd); + break; + case 0x06e: /* VIS I fnand */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fnand(); + gen_op_store_DT0_fpr(rd); + break; + case 0x06f: /* VIS I fnands */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fnands(); + gen_op_store_FT0_fpr(rd); + break; + case 0x070: /* VIS I fand */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fand(); + gen_op_store_DT0_fpr(rd); + break; + case 0x071: /* VIS I fands */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fands(); + gen_op_store_FT0_fpr(rd); + break; + case 0x072: /* VIS I fxnor */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fxnor(); + gen_op_store_DT0_fpr(rd); + break; + case 0x073: /* VIS I fxnors */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fxnors(); + gen_op_store_FT0_fpr(rd); + break; case 0x074: /* VIS I fsrc1 */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_load_fpr_DT0(rs1); gen_op_store_DT0_fpr(rd); break; case 0x075: /* VIS I fsrc1s */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_load_fpr_FT0(rs1); gen_op_store_FT0_fpr(rd); break; + case 0x076: /* VIS I fornot2 */ + gen_op_load_fpr_DT1(rs1); + gen_op_load_fpr_DT0(rs2); + gen_op_fornot(); + gen_op_store_DT0_fpr(rd); + break; + case 0x077: /* VIS I fornot2s */ + gen_op_load_fpr_FT1(rs1); + gen_op_load_fpr_FT0(rs2); + gen_op_fornots(); + gen_op_store_FT0_fpr(rd); + break; case 0x078: /* VIS I fsrc2 */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_load_fpr_DT0(rs2); gen_op_store_DT0_fpr(rd); break; case 0x079: /* VIS I fsrc2s */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_load_fpr_FT0(rs2); gen_op_store_FT0_fpr(rd); break; + case 0x07a: /* VIS I fornot1 */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_fornot(); + gen_op_store_DT0_fpr(rd); + break; + case 0x07b: /* VIS I fornot1s */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fornots(); + gen_op_store_FT0_fpr(rd); + break; + case 0x07c: /* VIS I for */ + gen_op_load_fpr_DT0(rs1); + gen_op_load_fpr_DT1(rs2); + gen_op_for(); + gen_op_store_DT0_fpr(rd); + break; + case 0x07d: /* VIS I fors */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fors(); + gen_op_store_FT0_fpr(rd); + break; case 0x07e: /* VIS I fone */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_movl_DT0_1(); gen_op_store_DT0_fpr(rd); break; case 0x07f: /* VIS I fones */ - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; gen_op_movl_FT0_1(); gen_op_store_FT0_fpr(rd); break; + case 0x080: /* VIS I shutdown */ + case 0x081: /* VIS II siam */ + // XXX + goto illegal_insn; default: goto illegal_insn; } -- cgit v1.2.3 From 4b6d0a4c7a3d029cdc4bf6520280275814f501c9 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 06:32:00 +0000 Subject: PowerPC embedded timers fixes. Improve PowerPC timers debug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2715 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 154 +++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 101 insertions(+), 53 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 1f6efee13..b4748f66e 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -25,6 +25,7 @@ #include "m48t59.h" //#define PPC_DEBUG_IRQ +//#define PPC_DEBUG_TB extern FILE *logfile; extern int loglevel; @@ -404,8 +405,6 @@ void ppc405_irq_init (CPUState *env) /*****************************************************************************/ /* PowerPC time base and decrementer emulation */ -//#define DEBUG_TB - struct ppc_tb_t { /* Time base management */ int64_t tb_offset; /* Compensation */ @@ -429,14 +428,14 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) uint64_t tb; tb = cpu_ppc_get_tb(tb_env); -#ifdef DEBUG_TB +#ifdef PPC_DEBUG_TB { static int last_time; int now; now = time(NULL); if (last_time != now) { last_time = now; - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n", __func__, tb, now, tb_env->tb_offset); } @@ -453,8 +452,8 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) uint64_t tb; tb = cpu_ppc_get_tb(tb_env); -#ifdef DEBUG_TB - if (loglevel) { +#if defined(PPC_DEBUG_TB) + if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); } #endif @@ -466,9 +465,10 @@ static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) { tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) - qemu_get_clock(vm_clock); -#ifdef DEBUG_TB - if (loglevel) { - fprintf(logfile, "%s: tb=0x%016lx offset=%08x\n", __func__, value); +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { + fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value, + tb_env->tb_offset); } #endif } @@ -500,8 +500,8 @@ uint32_t cpu_ppc_load_decr (CPUState *env) decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec); else decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec); -#if defined(DEBUG_TB) - if (loglevel) { +#if defined(PPC_DEBUG_TB) + if (loglevel != 0) { fprintf(logfile, "%s: 0x%08x\n", __func__, decr); } #endif @@ -515,8 +515,8 @@ uint32_t cpu_ppc_load_decr (CPUState *env) static inline void cpu_ppc_decr_excp (CPUState *env) { /* Raise it */ -#ifdef DEBUG_TB - if (loglevel) { +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { fprintf(logfile, "raise decrementer exception\n"); } #endif @@ -529,8 +529,8 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, ppc_tb_t *tb_env = env->tb_env; uint64_t now, next; -#ifdef DEBUG_TB - if (loglevel) { +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value); } #endif @@ -657,42 +657,69 @@ static void cpu_4xx_fit_cb (void *opaque) if (next == now) next++; qemu_mod_timer(ppcemb_timer->fit_timer, next); - tb_env->decr_next = next; env->spr[SPR_40x_TSR] |= 1 << 26; if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) ppc_set_irq(env, PPC_INTERRUPT_FIT, 1); - if (loglevel) { +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__, (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); } +#endif } /* Programmable interval timer */ -static void cpu_4xx_pit_cb (void *opaque) +static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp) { - CPUState *env; - ppc_tb_t *tb_env; ppcemb_timer_t *ppcemb_timer; uint64_t now, next; - env = opaque; - tb_env = env->tb_env; ppcemb_timer = tb_env->opaque; - now = qemu_get_clock(vm_clock); - if ((env->spr[SPR_40x_TCR] >> 22) & 0x1) { - /* Auto reload */ + if (ppcemb_timer->pit_reload <= 1 || + !((env->spr[SPR_40x_TCR] >> 26) & 0x1) || + (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) { + /* Stop PIT */ +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { + fprintf(logfile, "%s: stop PIT\n", __func__); + } +#endif + qemu_del_timer(tb_env->decr_timer); + } else { +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { + fprintf(logfile, "%s: start PIT 0x" REGX "\n", + __func__, ppcemb_timer->pit_reload); + } +#endif + now = qemu_get_clock(vm_clock); next = now + muldiv64(ppcemb_timer->pit_reload, ticks_per_sec, tb_env->tb_freq); + if (is_excp) + next += tb_env->decr_next - now; if (next == now) next++; qemu_mod_timer(tb_env->decr_timer, next); tb_env->decr_next = next; } +} + +static void cpu_4xx_pit_cb (void *opaque) +{ + CPUState *env; + ppc_tb_t *tb_env; + ppcemb_timer_t *ppcemb_timer; + + env = opaque; + tb_env = env->tb_env; + ppcemb_timer = tb_env->opaque; env->spr[SPR_40x_TSR] |= 1 << 27; if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) ppc_set_irq(env, PPC_INTERRUPT_PIT, 1); - if (loglevel) { + start_stop_pit(env, tb_env, 1); +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " " "%016" PRIx64 "\n", __func__, (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1), @@ -700,6 +727,7 @@ static void cpu_4xx_pit_cb (void *opaque) env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR], ppcemb_timer->pit_reload); } +#endif } /* Watchdog timer */ @@ -734,10 +762,12 @@ static void cpu_4xx_wdt_cb (void *opaque) next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq); if (next == now) next++; - if (loglevel) { +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__, env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); } +#endif switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) { case 0x0: case 0x1: @@ -776,31 +806,16 @@ void store_40x_pit (CPUState *env, target_ulong val) { ppc_tb_t *tb_env; ppcemb_timer_t *ppcemb_timer; - uint64_t now, next; tb_env = env->tb_env; ppcemb_timer = tb_env->opaque; - if (loglevel) { +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); } +#endif ppcemb_timer->pit_reload = val; - if (val == 0) { - /* Stop PIT */ - if (loglevel) { - fprintf(logfile, "%s: stop PIT\n", __func__); - } - qemu_del_timer(tb_env->decr_timer); - } else { - if (loglevel) { - fprintf(logfile, "%s: start PIT 0x" ADDRX "\n", __func__, val); - } - now = qemu_get_clock(vm_clock); - next = now + muldiv64(val, ticks_per_sec, tb_env->tb_freq); - if (next == now) - next++; - qemu_mod_timer(tb_env->decr_timer, next); - tb_env->decr_next = next; - } + start_stop_pit(env, tb_env, 0); } target_ulong load_40x_pit (CPUState *env) @@ -810,30 +825,64 @@ target_ulong load_40x_pit (CPUState *env) void store_booke_tsr (CPUState *env, target_ulong val) { - env->spr[SPR_40x_TSR] = val & 0xFC000000; +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { + fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val); + } +#endif + env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); + if (val & 0x80000000) + ppc_set_irq(env, PPC_INTERRUPT_PIT, 0); } void store_booke_tcr (CPUState *env, target_ulong val) { - env->spr[SPR_40x_TCR] = val & 0xFF800000; + ppc_tb_t *tb_env; + + tb_env = env->tb_env; +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { + fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val); + } +#endif + env->spr[SPR_40x_TCR] = val & 0xFFC00000; + start_stop_pit(env, tb_env, 1); cpu_4xx_wdt_cb(env); } +static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq) +{ + CPUState *env = opaque; + ppc_tb_t *tb_env = env->tb_env; + +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { + fprintf(logfile, "%s set new frequency to %u\n", __func__, freq); + } +#endif + tb_env->tb_freq = freq; + /* XXX: we should also update all timers */ +} + clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) { ppc_tb_t *tb_env; ppcemb_timer_t *ppcemb_timer; tb_env = qemu_mallocz(sizeof(ppc_tb_t)); - if (tb_env == NULL) + if (tb_env == NULL) { return NULL; + } env->tb_env = tb_env; ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t)); tb_env->tb_freq = freq; tb_env->opaque = ppcemb_timer; - if (loglevel) { - fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { + fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer, + &ppc_emb_set_tb_clk); } +#endif if (ppcemb_timer != NULL) { /* We use decr timer for PIT */ tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env); @@ -843,8 +892,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env); } - /* XXX: TODO: add callback for clock frequency change */ - return NULL; + return &ppc_emb_set_tb_clk; } /*****************************************************************************/ -- cgit v1.2.3 From 9c02f1a2e607b7be71f2dba1cafc096dd3c2dda9 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 06:37:21 +0000 Subject: PowerPC 405 microcontrollers fixes and improvments: - use target_phys_addr_t for physical addresses / offsets - implement fake general purpose timers and memory access layer for PowerPC 405EP - more assigned internal IRQs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2716 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405.h | 20 +- hw/ppc405_uc.c | 702 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 673 insertions(+), 49 deletions(-) diff --git a/hw/ppc405.h b/hw/ppc405.h index e61cc58b3..c491ed55e 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -62,16 +62,17 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd); /* */ typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, - uint32_t offset, uint32_t len, + target_phys_addr_t offset, uint32_t len, CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, void *opaque); -ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, uint32_t base); +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base); /* PowerPC 4xx peripheral local bus arbitrer */ void ppc4xx_plb_init (CPUState *env); /* PLB to OPB bridge */ void ppc4xx_pob_init (CPUState *env); /* OPB arbitrer */ -void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset); /* PowerPC 4xx universal interrupt controller */ enum { PPCUIC_OUTPUT_INT = 0, @@ -89,15 +90,22 @@ void ppc405_ebc_init (CPUState *env); /* DMA controller */ void ppc405_dma_init (CPUState *env, qemu_irq irqs[4]); /* GPIO */ -void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset); /* Serial ports */ void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio, - uint32_t offset, qemu_irq irq, + target_phys_addr_t offset, qemu_irq irq, CharDriverState *chr); /* On Chip Memory */ void ppc405_ocm_init (CPUState *env, unsigned long offset); /* I2C controller */ -void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset); +void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset, qemu_irq irq); +/* General purpose timers */ +void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset, qemu_irq irq[5]); +/* Memory access layer */ +void ppc405_mal_init (CPUState *env, qemu_irq irqs[4]); /* PowerPC 405 microcontrollers */ CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], uint32_t sysclk, qemu_irq **picp, diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index f5c1c31bd..e06165d52 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -27,16 +27,18 @@ extern int loglevel; extern FILE *logfile; -#define DEBUG_MMIO +//#define DEBUG_MMIO #define DEBUG_OPBA #define DEBUG_SDRAM #define DEBUG_GPIO #define DEBUG_SERIAL #define DEBUG_OCM -#define DEBUG_I2C +//#define DEBUG_I2C +#define DEBUG_GPT +#define DEBUG_MAL #define DEBUG_UIC #define DEBUG_CLOCKS -#define DEBUG_UNASSIGNED +//#define DEBUG_UNASSIGNED /*****************************************************************************/ /* Generic PowerPC 405 processor instanciation */ @@ -122,39 +124,47 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd) #define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS)) #define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1)) struct ppc4xx_mmio_t { - uint32_t base; + target_phys_addr_t base; CPUReadMemoryFunc **mem_read[MMIO_AREA_NB]; CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB]; void *opaque[MMIO_AREA_NB]; }; -static uint32_t unassigned_mem_readb (void *opaque, target_phys_addr_t addr) +static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem read 0x" PADDRX "\n", addr); + ppc4xx_mmio_t *mmio; + + mmio = opaque; + printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n", + addr, mmio->base); #endif return 0; } -static void unassigned_mem_writeb (void *opaque, +static void unassigned_mmio_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem write 0x" PADDRX " = 0x%x\n", addr, val); + ppc4xx_mmio_t *mmio; + + mmio = opaque; + printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n", + addr, val, mmio->base); #endif } -static CPUReadMemoryFunc *unassigned_mem_read[3] = { - unassigned_mem_readb, - unassigned_mem_readb, - unassigned_mem_readb, +static CPUReadMemoryFunc *unassigned_mmio_read[3] = { + unassigned_mmio_readb, + unassigned_mmio_readb, + unassigned_mmio_readb, }; -static CPUWriteMemoryFunc *unassigned_mem_write[3] = { - unassigned_mem_writeb, - unassigned_mem_writeb, - unassigned_mem_writeb, +static CPUWriteMemoryFunc *unassigned_mmio_write[3] = { + unassigned_mmio_writeb, + unassigned_mmio_writeb, + unassigned_mmio_writeb, }; static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, @@ -170,7 +180,7 @@ static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, mmio, len, addr, idx); #endif mem_read = mmio->mem_read[idx]; - ret = (*mem_read[len])(mmio->opaque[idx], addr); + ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base); return ret; } @@ -187,7 +197,7 @@ static void mmio_writelen (ppc4xx_mmio_t *mmio, mmio, len, addr, idx, value); #endif mem_write = mmio->mem_write[idx]; - (*mem_write[len])(mmio->opaque[idx], addr, value); + (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value); } static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr) @@ -257,7 +267,7 @@ static CPUWriteMemoryFunc *mmio_write[] = { }; int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, - uint32_t offset, uint32_t len, + target_phys_addr_t offset, uint32_t len, CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, void *opaque) { @@ -282,7 +292,7 @@ int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, return 0; } -ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, uint32_t base) +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) { ppc4xx_mmio_t *mmio; int mmio_memory; @@ -297,7 +307,8 @@ ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, uint32_t base) #endif cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, - unassigned_mem_read, unassigned_mem_write, NULL); + unassigned_mmio_read, unassigned_mmio_write, + mmio); } return mmio; @@ -350,7 +361,10 @@ static void dcr_write_plb (void *opaque, int dcrn, target_ulong val) plb = opaque; switch (dcrn) { case PLB0_ACR: - plb->acr = val & 0xFC000000; + /* We don't care about the actual parameters written as + * we don't manage any priorities on the bus + */ + plb->acr = val & 0xF8000000; break; case PLB0_BEAR: /* Read only */ @@ -469,7 +483,7 @@ void ppc4xx_pob_init (CPUState *env) /* OPB arbitrer */ typedef struct ppc4xx_opba_t ppc4xx_opba_t; struct ppc4xx_opba_t { - target_ulong base; + target_phys_addr_t base; uint8_t cr; uint8_t pr; }; @@ -586,15 +600,16 @@ static void ppc4xx_opba_reset (void *opaque) opba->pr = 0x11; } -void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset) +void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset) { ppc4xx_opba_t *opba; opba = qemu_mallocz(sizeof(ppc4xx_opba_t)); if (opba != NULL) { - opba->base = mmio->base + offset; + opba->base = offset; #ifdef DEBUG_OPBA - printf("%s: offset=%08x\n", __func__, offset); + printf("%s: offset=" PADDRX "\n", __func__, offset); #endif ppc4xx_mmio_register(env, mmio, offset, 0x002, opba_read, opba_write, opba); @@ -1392,7 +1407,7 @@ static void ebc_reset (void *opaque) } ebc->besr0 = 0x00000000; ebc->besr1 = 0x00000000; - ebc->cfg = 0x07C00000; + ebc->cfg = 0x80400000; } void ppc405_ebc_init (CPUState *env) @@ -1552,7 +1567,7 @@ void ppc405_dma_init (CPUState *env, qemu_irq irqs[4]) /* GPIO */ typedef struct ppc405_gpio_t ppc405_gpio_t; struct ppc405_gpio_t { - uint32_t base; + target_phys_addr_t base; uint32_t or; uint32_t tcr; uint32_t osrh; @@ -1654,17 +1669,18 @@ static void ppc405_gpio_reset (void *opaque) gpio = opaque; } -void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset) +void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset) { ppc405_gpio_t *gpio; gpio = qemu_mallocz(sizeof(ppc405_gpio_t)); if (gpio != NULL) { - gpio->base = mmio->base + offset; + gpio->base = offset; ppc405_gpio_reset(gpio); qemu_register_reset(&ppc405_gpio_reset, gpio); #ifdef DEBUG_GPIO - printf("%s: offset=%08x\n", __func__, offset); + printf("%s: offset=" PADDRX "\n", __func__, offset); #endif ppc4xx_mmio_register(env, mmio, offset, 0x038, ppc405_gpio_read, ppc405_gpio_write, gpio); @@ -1686,15 +1702,15 @@ static CPUWriteMemoryFunc *serial_mm_write[] = { }; void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio, - uint32_t offset, qemu_irq irq, + target_phys_addr_t offset, qemu_irq irq, CharDriverState *chr) { void *serial; #ifdef DEBUG_SERIAL - printf("%s: offset=%08x\n", __func__, offset); + printf("%s: offset=" PADDRX "\n", __func__, offset); #endif - serial = serial_mm_init(mmio->base + offset, 0, irq, chr, 0); + serial = serial_mm_init(offset, 0, irq, chr, 0); ppc4xx_mmio_register(env, mmio, offset, 0x008, serial_mm_read, serial_mm_write, serial); } @@ -1869,7 +1885,8 @@ void ppc405_ocm_init (CPUState *env, unsigned long offset) /* I2C controller */ typedef struct ppc4xx_i2c_t ppc4xx_i2c_t; struct ppc4xx_i2c_t { - uint32_t base; + target_phys_addr_t base; + qemu_irq irq; uint8_t mdata; uint8_t lmadr; uint8_t hmadr; @@ -2091,16 +2108,18 @@ static void ppc4xx_i2c_reset (void *opaque) i2c->directcntl = 0x0F; } -void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset) +void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset, qemu_irq irq) { ppc4xx_i2c_t *i2c; i2c = qemu_mallocz(sizeof(ppc4xx_i2c_t)); if (i2c != NULL) { - i2c->base = mmio->base + offset; + i2c->base = offset; + i2c->irq = irq; ppc4xx_i2c_reset(i2c); #ifdef DEBUG_I2C - printf("%s: offset=%08x\n", __func__, offset); + printf("%s: offset=" PADDRX "\n", __func__, offset); #endif ppc4xx_mmio_register(env, mmio, offset, 0x011, i2c_read, i2c_write, i2c); @@ -2108,6 +2127,557 @@ void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, uint32_t offset) } } +/*****************************************************************************/ +/* General purpose timers */ +typedef struct ppc4xx_gpt_t ppc4xx_gpt_t; +struct ppc4xx_gpt_t { + target_phys_addr_t base; + int64_t tb_offset; + uint32_t tb_freq; + struct QEMUTimer *timer; + qemu_irq irqs[5]; + uint32_t oe; + uint32_t ol; + uint32_t im; + uint32_t is; + uint32_t ie; + uint32_t comp[5]; + uint32_t mask[5]; +}; + +static uint32_t ppc4xx_gpt_readb (void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_GPT + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + /* XXX: generate a bus fault */ + return -1; +} + +static void ppc4xx_gpt_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + /* XXX: generate a bus fault */ +} + +static uint32_t ppc4xx_gpt_readw (void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_GPT + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + /* XXX: generate a bus fault */ + return -1; +} + +static void ppc4xx_gpt_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + /* XXX: generate a bus fault */ +} + +static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n) +{ + /* XXX: TODO */ + return 0; +} + +static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level) +{ + /* XXX: TODO */ +} + +static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt) +{ + uint32_t mask; + int i; + + mask = 0x80000000; + for (i = 0; i < 5; i++) { + if (gpt->oe & mask) { + /* Output is enabled */ + if (ppc4xx_gpt_compare(gpt, i)) { + /* Comparison is OK */ + ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask); + } else { + /* Comparison is KO */ + ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1); + } + } + mask = mask >> 1; + } + +} + +static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) +{ + uint32_t mask; + int i; + + mask = 0x00008000; + for (i = 0; i < 5; i++) { + if (gpt->is & gpt->im & mask) + qemu_irq_raise(gpt->irqs[i]); + else + qemu_irq_lower(gpt->irqs[i]); + mask = mask >> 1; + } + +} + +static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt) +{ + /* XXX: TODO */ +} + +static uint32_t ppc4xx_gpt_readl (void *opaque, target_phys_addr_t addr) +{ + ppc4xx_gpt_t *gpt; + uint32_t ret; + int idx; + +#ifdef DEBUG_GPT + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + gpt = opaque; + switch (addr - gpt->base) { + case 0x00: + /* Time base counter */ + ret = muldiv64(qemu_get_clock(vm_clock) + gpt->tb_offset, + gpt->tb_freq, ticks_per_sec); + break; + case 0x10: + /* Output enable */ + ret = gpt->oe; + break; + case 0x14: + /* Output level */ + ret = gpt->ol; + break; + case 0x18: + /* Interrupt mask */ + ret = gpt->im; + break; + case 0x1C: + case 0x20: + /* Interrupt status */ + ret = gpt->is; + break; + case 0x24: + /* Interrupt enable */ + ret = gpt->ie; + break; + case 0x80 ... 0x90: + /* Compare timer */ + idx = ((addr - gpt->base) - 0x80) >> 2; + ret = gpt->comp[idx]; + break; + case 0xC0 ... 0xD0: + /* Compare mask */ + idx = ((addr - gpt->base) - 0xC0) >> 2; + ret = gpt->mask[idx]; + break; + default: + ret = -1; + break; + } + + return ret; +} + +static void ppc4xx_gpt_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ppc4xx_gpt_t *gpt; + int idx; + +#ifdef DEBUG_I2C + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + gpt = opaque; + switch (addr - gpt->base) { + case 0x00: + /* Time base counter */ + gpt->tb_offset = muldiv64(value, ticks_per_sec, gpt->tb_freq) + - qemu_get_clock(vm_clock); + ppc4xx_gpt_compute_timer(gpt); + break; + case 0x10: + /* Output enable */ + gpt->oe = value & 0xF8000000; + ppc4xx_gpt_set_outputs(gpt); + break; + case 0x14: + /* Output level */ + gpt->ol = value & 0xF8000000; + ppc4xx_gpt_set_outputs(gpt); + break; + case 0x18: + /* Interrupt mask */ + gpt->im = value & 0x0000F800; + break; + case 0x1C: + /* Interrupt status set */ + gpt->is |= value & 0x0000F800; + ppc4xx_gpt_set_irqs(gpt); + break; + case 0x20: + /* Interrupt status clear */ + gpt->is &= ~(value & 0x0000F800); + ppc4xx_gpt_set_irqs(gpt); + break; + case 0x24: + /* Interrupt enable */ + gpt->ie = value & 0x0000F800; + ppc4xx_gpt_set_irqs(gpt); + break; + case 0x80 ... 0x90: + /* Compare timer */ + idx = ((addr - gpt->base) - 0x80) >> 2; + gpt->comp[idx] = value & 0xF8000000; + ppc4xx_gpt_compute_timer(gpt); + break; + case 0xC0 ... 0xD0: + /* Compare mask */ + idx = ((addr - gpt->base) - 0xC0) >> 2; + gpt->mask[idx] = value & 0xF8000000; + ppc4xx_gpt_compute_timer(gpt); + break; + } +} + +static CPUReadMemoryFunc *gpt_read[] = { + &ppc4xx_gpt_readb, + &ppc4xx_gpt_readw, + &ppc4xx_gpt_readl, +}; + +static CPUWriteMemoryFunc *gpt_write[] = { + &ppc4xx_gpt_writeb, + &ppc4xx_gpt_writew, + &ppc4xx_gpt_writel, +}; + +static void ppc4xx_gpt_cb (void *opaque) +{ + ppc4xx_gpt_t *gpt; + + gpt = opaque; + ppc4xx_gpt_set_irqs(gpt); + ppc4xx_gpt_set_outputs(gpt); + ppc4xx_gpt_compute_timer(gpt); +} + +static void ppc4xx_gpt_reset (void *opaque) +{ + ppc4xx_gpt_t *gpt; + int i; + + gpt = opaque; + qemu_del_timer(gpt->timer); + gpt->oe = 0x00000000; + gpt->ol = 0x00000000; + gpt->im = 0x00000000; + gpt->is = 0x00000000; + gpt->ie = 0x00000000; + for (i = 0; i < 5; i++) { + gpt->comp[i] = 0x00000000; + gpt->mask[i] = 0x00000000; + } +} + +void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset, qemu_irq irqs[5]) +{ + ppc4xx_gpt_t *gpt; + int i; + + gpt = qemu_mallocz(sizeof(ppc4xx_gpt_t)); + if (gpt != NULL) { + gpt->base = offset; + for (i = 0; i < 5; i++) + gpt->irqs[i] = irqs[i]; + gpt->timer = qemu_new_timer(vm_clock, &ppc4xx_gpt_cb, gpt); + ppc4xx_gpt_reset(gpt); +#ifdef DEBUG_GPT + printf("%s: offset=" PADDRX "\n", __func__, offset); +#endif + ppc4xx_mmio_register(env, mmio, offset, 0x0D4, + gpt_read, gpt_write, gpt); + qemu_register_reset(ppc4xx_gpt_reset, gpt); + } +} + +/*****************************************************************************/ +/* MAL */ +enum { + MAL0_CFG = 0x180, + MAL0_ESR = 0x181, + MAL0_IER = 0x182, + MAL0_TXCASR = 0x184, + MAL0_TXCARR = 0x185, + MAL0_TXEOBISR = 0x186, + MAL0_TXDEIR = 0x187, + MAL0_RXCASR = 0x190, + MAL0_RXCARR = 0x191, + MAL0_RXEOBISR = 0x192, + MAL0_RXDEIR = 0x193, + MAL0_TXCTP0R = 0x1A0, + MAL0_TXCTP1R = 0x1A1, + MAL0_TXCTP2R = 0x1A2, + MAL0_TXCTP3R = 0x1A3, + MAL0_RXCTP0R = 0x1C0, + MAL0_RXCTP1R = 0x1C1, + MAL0_RCBS0 = 0x1E0, + MAL0_RCBS1 = 0x1E1, +}; + +typedef struct ppc40x_mal_t ppc40x_mal_t; +struct ppc40x_mal_t { + qemu_irq irqs[4]; + uint32_t cfg; + uint32_t esr; + uint32_t ier; + uint32_t txcasr; + uint32_t txcarr; + uint32_t txeobisr; + uint32_t txdeir; + uint32_t rxcasr; + uint32_t rxcarr; + uint32_t rxeobisr; + uint32_t rxdeir; + uint32_t txctpr[4]; + uint32_t rxctpr[2]; + uint32_t rcbs[2]; +}; + +static void ppc40x_mal_reset (void *opaque); + +static target_ulong dcr_read_mal (void *opaque, int dcrn) +{ + ppc40x_mal_t *mal; + target_ulong ret; + + mal = opaque; + switch (dcrn) { + case MAL0_CFG: + ret = mal->cfg; + break; + case MAL0_ESR: + ret = mal->esr; + break; + case MAL0_IER: + ret = mal->ier; + break; + case MAL0_TXCASR: + ret = mal->txcasr; + break; + case MAL0_TXCARR: + ret = mal->txcarr; + break; + case MAL0_TXEOBISR: + ret = mal->txeobisr; + break; + case MAL0_TXDEIR: + ret = mal->txdeir; + break; + case MAL0_RXCASR: + ret = mal->rxcasr; + break; + case MAL0_RXCARR: + ret = mal->rxcarr; + break; + case MAL0_RXEOBISR: + ret = mal->rxeobisr; + break; + case MAL0_RXDEIR: + ret = mal->rxdeir; + break; + case MAL0_TXCTP0R: + ret = mal->txctpr[0]; + break; + case MAL0_TXCTP1R: + ret = mal->txctpr[1]; + break; + case MAL0_TXCTP2R: + ret = mal->txctpr[2]; + break; + case MAL0_TXCTP3R: + ret = mal->txctpr[3]; + break; + case MAL0_RXCTP0R: + ret = mal->rxctpr[0]; + break; + case MAL0_RXCTP1R: + ret = mal->rxctpr[1]; + break; + case MAL0_RCBS0: + ret = mal->rcbs[0]; + break; + case MAL0_RCBS1: + ret = mal->rcbs[1]; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void dcr_write_mal (void *opaque, int dcrn, target_ulong val) +{ + ppc40x_mal_t *mal; + int idx; + + mal = opaque; + switch (dcrn) { + case MAL0_CFG: + if (val & 0x80000000) + ppc40x_mal_reset(mal); + mal->cfg = val & 0x00FFC087; + break; + case MAL0_ESR: + /* Read/clear */ + mal->esr &= ~val; + break; + case MAL0_IER: + mal->ier = val & 0x0000001F; + break; + case MAL0_TXCASR: + mal->txcasr = val & 0xF0000000; + break; + case MAL0_TXCARR: + mal->txcarr = val & 0xF0000000; + break; + case MAL0_TXEOBISR: + /* Read/clear */ + mal->txeobisr &= ~val; + break; + case MAL0_TXDEIR: + /* Read/clear */ + mal->txdeir &= ~val; + break; + case MAL0_RXCASR: + mal->rxcasr = val & 0xC0000000; + break; + case MAL0_RXCARR: + mal->rxcarr = val & 0xC0000000; + break; + case MAL0_RXEOBISR: + /* Read/clear */ + mal->rxeobisr &= ~val; + break; + case MAL0_RXDEIR: + /* Read/clear */ + mal->rxdeir &= ~val; + break; + case MAL0_TXCTP0R: + idx = 0; + goto update_tx_ptr; + case MAL0_TXCTP1R: + idx = 1; + goto update_tx_ptr; + case MAL0_TXCTP2R: + idx = 2; + goto update_tx_ptr; + case MAL0_TXCTP3R: + idx = 3; + update_tx_ptr: + mal->txctpr[idx] = val; + break; + case MAL0_RXCTP0R: + idx = 0; + goto update_rx_ptr; + case MAL0_RXCTP1R: + idx = 1; + update_rx_ptr: + mal->rxctpr[idx] = val; + break; + case MAL0_RCBS0: + idx = 0; + goto update_rx_size; + case MAL0_RCBS1: + idx = 1; + update_rx_size: + mal->rcbs[idx] = val & 0x000000FF; + break; + } +} + +static void ppc40x_mal_reset (void *opaque) +{ + ppc40x_mal_t *mal; + + mal = opaque; + mal->cfg = 0x0007C000; + mal->esr = 0x00000000; + mal->ier = 0x00000000; + mal->rxcasr = 0x00000000; + mal->rxdeir = 0x00000000; + mal->rxeobisr = 0x00000000; + mal->txcasr = 0x00000000; + mal->txdeir = 0x00000000; + mal->txeobisr = 0x00000000; +} + +void ppc405_mal_init (CPUState *env, qemu_irq irqs[4]) +{ + ppc40x_mal_t *mal; + int i; + + mal = qemu_mallocz(sizeof(ppc40x_mal_t)); + if (mal != NULL) { + for (i = 0; i < 4; i++) + mal->irqs[i] = irqs[i]; + ppc40x_mal_reset(mal); + qemu_register_reset(&ppc40x_mal_reset, mal); + ppc_dcr_register(env, MAL0_CFG, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_ESR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_IER, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCASR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCARR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXEOBISR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXDEIR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCASR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCARR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXEOBISR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXDEIR, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP0R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP1R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP2R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_TXCTP3R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCTP0R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RXCTP1R, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RCBS0, + mal, &dcr_read_mal, &dcr_write_mal); + ppc_dcr_register(env, MAL0_RCBS1, + mal, &dcr_read_mal, &dcr_write_mal); + } +} + /*****************************************************************************/ /* SPR */ void ppc40x_core_reset (CPUState *env) @@ -2499,7 +3069,7 @@ CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]); } /* IIC controller */ - ppc405_i2c_init(env, mmio, 0x500); + ppc405_i2c_init(env, mmio, 0x500, pic[29]); /* GPIO */ ppc405_gpio_init(env, mmio, 0x700); /* CPU control */ @@ -2521,6 +3091,11 @@ enum { PPC405EP_CPC0_SRR = 0x0F6, PPC405EP_CPC0_JTAGID = 0x0F7, PPC405EP_CPC0_PCI = 0x0F9, +#if 0 + PPC405EP_CPC0_ER = xxx, + PPC405EP_CPC0_FR = xxx, + PPC405EP_CPC0_SR = xxx, +#endif }; enum { @@ -2546,6 +3121,10 @@ struct ppc405ep_cpc_t { uint32_t srr; uint32_t jtagid; uint32_t pci; + /* Clock and power management */ + uint32_t er; + uint32_t fr; + uint32_t sr; }; static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) @@ -2571,11 +3150,17 @@ static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) #endif } PLL_out = VCO_out / D; + /* Pretend the PLL is locked */ + cpc->boot |= 0x00000001; } else { #if 0 pll_bypass: #endif PLL_out = cpc->sysclk; + if (cpc->pllmr[1] & 0x40000000) { + /* Pretend the PLL is not locked */ + cpc->boot &= ~0x00000001; + } } /* Now, compute all other clocks */ D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */ @@ -2624,6 +3209,8 @@ static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) printf("CPU %d PLB %d OPB %d EBC %d MAL %d PCI %d UART0 %d UART1 %d\n", CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk, UART0_clk, UART1_clk); + printf("CB %p opaque %p\n", cpc->clk_setup[PPC405EP_CPU_CLK].cb, + cpc->clk_setup[PPC405EP_CPU_CLK].opaque); #endif /* Setup CPU clocks */ clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk); @@ -2731,6 +3318,9 @@ static void ppc405ep_cpc_reset (void *opaque) cpc->ucr = 0x00000000; cpc->srr = 0x00040000; cpc->pci = 0x00000000; + cpc->er = 0x00000000; + cpc->fr = 0x00000000; + cpc->sr = 0x00000000; ppc405ep_compute_clocks(cpc); } @@ -2764,6 +3354,14 @@ static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8], &dcr_read_epcpc, &dcr_write_epcpc); ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc, &dcr_read_epcpc, &dcr_write_epcpc); +#if 0 + ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); + ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc, + &dcr_read_epcpc, &dcr_write_epcpc); +#endif } } @@ -2771,8 +3369,8 @@ CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], uint32_t sysclk, qemu_irq **picp, ram_addr_t *offsetp, int do_init) { - clk_setup_t clk_setup[PPC405EP_CLK_NB]; - qemu_irq dma_irqs[4]; + clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup; + qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4]; CPUState *env; ppc4xx_mmio_t *mmio; qemu_irq *pic, *irqs; @@ -2782,7 +3380,9 @@ CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], memset(clk_setup, 0, sizeof(clk_setup)); /* init CPUs */ env = ppc405_init("405ep", &clk_setup[PPC405EP_CPU_CLK], - &clk_setup[PPC405EP_PLB_CLK], sysclk); + &tlb_clk_setup, sysclk); + clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; + clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; /* Internal devices init */ /* Memory mapped devices registers */ mmio = ppc4xx_mmio_init(env, 0xEF600000); @@ -2814,7 +3414,7 @@ CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], dma_irqs[3] = pic[23]; ppc405_dma_init(env, dma_irqs); /* IIC controller */ - ppc405_i2c_init(env, mmio, 0x500); + ppc405_i2c_init(env, mmio, 0x500, pic[29]); /* GPIO */ ppc405_gpio_init(env, mmio, 0x700); /* Serial ports */ @@ -2827,7 +3427,23 @@ CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], /* OCM */ ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]); offset += 4096; + /* GPT */ + gpt_irqs[0] = pic[12]; + gpt_irqs[1] = pic[11]; + gpt_irqs[2] = pic[10]; + gpt_irqs[3] = pic[9]; + gpt_irqs[4] = pic[8]; + ppc4xx_gpt_init(env, mmio, 0x000, gpt_irqs); /* PCI */ + /* Uses pic[28], pic[15], pic[13] */ + /* MAL */ + mal_irqs[0] = pic[20]; + mal_irqs[1] = pic[19]; + mal_irqs[2] = pic[18]; + mal_irqs[3] = pic[17]; + ppc405_mal_init(env, mal_irqs); + /* Ethernet */ + /* Uses pic[22], pic[16], pic[14] */ /* CPU control */ ppc405ep_cpc_init(env, clk_setup, sysclk); *offsetp = offset; -- cgit v1.2.3 From c294fc587a52f4991b1dcbb328b5a9d09f8c8e2e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 06:44:14 +0000 Subject: Improve PowerPC 405 MMU model / share more code for other embedded targets support. Fix PowerPC 405 MSR mask. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2717 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 + target-ppc/helper.c | 96 ++++++++++++++++++++++++++++++++++----------- target-ppc/op.c | 6 +++ target-ppc/op_helper.c | 48 ++++++++--------------- target-ppc/translate_init.c | 16 ++++++-- 5 files changed, 111 insertions(+), 57 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f17f84641..4a241f1b3 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -881,9 +881,11 @@ void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value); target_ulong load_40x_pit (CPUPPCState *env); void store_40x_pit (CPUPPCState *env, target_ulong val); void store_40x_dbcr0 (CPUPPCState *env, uint32_t val); +void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void ppc_tlb_invalidate_all (CPUPPCState *env); +int ppcemb_tlb_search (CPUPPCState *env, target_ulong address); #endif #endif diff --git a/target-ppc/helper.c b/target-ppc/helper.c index e93f5a6d1..e3700b5f2 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -632,6 +632,58 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, return ret; } +/* Generic TLB check function for embedded PowerPC implementations */ +static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, + target_phys_addr_t *raddrp, + target_ulong address, int i) +{ + target_ulong mask; + + /* Check valid flag */ + if (!(tlb->prot & PAGE_VALID)) { + if (loglevel != 0) + fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); + return -1; + } + mask = ~(tlb->size - 1); + if (loglevel != 0) { + fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " + ADDRX " " ADDRX " %d\n", + __func__, i, address, (int)env->spr[SPR_40x_PID], + tlb->EPN, mask, (int)tlb->PID); + } + /* Check PID */ + if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) + return -1; + /* Check effective address */ + if ((address & mask) != tlb->EPN) + return -1; + *raddrp = (tlb->RPN & mask) | (address & ~mask); + + return 0; +} + +/* Generic TLB search function for PowerPC embedded implementations */ +int ppcemb_tlb_search (CPUState *env, target_ulong address) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + int i, ret; + + /* Default return value is no match */ + ret = -1; + for (i = 0; i < 64; i++) { + tlb = &env->tlb[i].tlbe; + if (ppcemb_tlb_check(env, tlb, &raddr, address, i) == 0) { + ret = i; + break; + } + } + + return ret; +} + +/* Helpers specific to PowerPC 40x implementations */ void ppc4xx_tlb_invalidate_all (CPUState *env) { ppcemb_tlb_t *tlb; @@ -656,33 +708,14 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; - target_ulong mask; int i, ret, zsel, zpr; ret = -1; raddr = -1; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; - /* Check valid flag */ - if (!(tlb->prot & PAGE_VALID)) { - if (loglevel != 0) - fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); - continue; - } - mask = ~(tlb->size - 1); - if (loglevel != 0) { - fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " - ADDRX " " ADDRX " %d\n", - __func__, i, address, (int)env->spr[SPR_40x_PID], - tlb->EPN, mask, (int)tlb->PID); - } - /* Check PID */ - if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) - continue; - /* Check effective address */ - if ((address & mask) != tlb->EPN) + if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0) continue; - raddr = (tlb->RPN & mask) | (address & ~mask); zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; if (loglevel != 0) { @@ -692,6 +725,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, if (access_type == ACCESS_CODE) { /* Check execute enable bit */ switch (zpr) { + case 0x2: + if (msr_pr) + goto check_exec_perm; + goto exec_granted; case 0x0: if (msr_pr) { ctx->prot = 0; @@ -700,7 +737,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } /* No break here */ case 0x1: - case 0x2: + check_exec_perm: /* Check from TLB entry */ if (!(tlb->prot & PAGE_EXEC)) { ret = -3; @@ -714,6 +751,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } break; case 0x3: + exec_granted: /* All accesses granted */ ctx->prot = PAGE_READ | PAGE_WRITE; ret = 0; @@ -721,6 +759,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } } else { switch (zpr) { + case 0x2: + if (msr_pr) + goto check_rw_perm; + goto rw_granted; case 0x0: if (msr_pr) { ctx->prot = 0; @@ -729,7 +771,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } /* No break here */ case 0x1: - case 0x2: + check_rw_perm: /* Check from TLB entry */ /* Check write protection bit */ if (tlb->prot & PAGE_WRITE) { @@ -744,6 +786,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } break; case 0x3: + rw_granted: /* All accesses granted */ ctx->prot = PAGE_READ | PAGE_WRITE; ret = 0; @@ -769,6 +812,15 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, return ret; } +void store_40x_sler (CPUPPCState *env, uint32_t val) +{ + /* XXX: TO BE FIXED */ + if (val != 0x00000000) { + cpu_abort(env, "Little-endian regions are not supported by now\n"); + } + env->spr[SPR_405_SLER] = val; +} + static int check_physical (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw) { diff --git a/target-ppc/op.c b/target-ppc/op.c index b8498f182..f18e7f3f9 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2459,6 +2459,12 @@ void OPPROTO op_store_40x_dbcr0 (void) store_40x_dbcr0(env, T0); } +void OPPROTO op_store_40x_sler (void) +{ + store_40x_sler(env, T0); + RETURN(); +} + void OPPROTO op_store_booke_tcr (void) { store_booke_tcr(env, T0); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index e994486cf..a888821d2 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2494,44 +2494,16 @@ void do_4xx_tlbre_hi (void) T0 |= 0x100; } -static int tlb_4xx_search (target_ulong virtual) -{ - ppcemb_tlb_t *tlb; - target_ulong base, mask; - int i, ret; - - /* Default return value is no match */ - ret = -1; - for (i = 0; i < 64; i++) { - tlb = &env->tlb[i].tlbe; - /* Check TLB validity */ - if (!(tlb->prot & PAGE_VALID)) - continue; - /* Check TLB PID vs current PID */ - if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) - continue; - /* Check TLB address vs virtual address */ - base = tlb->EPN; - mask = ~(tlb->size - 1); - if ((base & mask) != (virtual & mask)) - continue; - ret = i; - break; - } - - return ret; -} - void do_4xx_tlbsx (void) { - T0 = tlb_4xx_search(T0); + T0 = ppcemb_tlb_search(env, T0); } void do_4xx_tlbsx_ (void) { int tmp = xer_ov; - T0 = tlb_4xx_search(T0); + T0 = ppcemb_tlb_search(env, T0); if (T0 != -1) tmp |= 0x02; env->crf[0] = tmp; @@ -2562,16 +2534,28 @@ void do_4xx_tlbwe_hi (void) tlb_flush_page(env, page); } tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); + /* We cannot handle TLB size < TARGET_PAGE_SIZE. + * If this ever occurs, one should use the ppcemb target instead + * of the ppc or ppc64 one + */ + if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) { + cpu_abort(env, "TLB size %u < %u are not supported (%d)\n", + tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7)); + } tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); if (T1 & 0x40) tlb->prot |= PAGE_VALID; else tlb->prot &= ~PAGE_VALID; + if (T1 & 0x20) { + /* XXX: TO BE FIXED */ + cpu_abort(env, "Little-endian TLB entries are not supported by now\n"); + } tlb->PID = env->spr[SPR_40x_PID]; /* PID */ tlb->attr = T1 & 0xFF; #if defined (DEBUG_SOFTWARE_TLB) - if (loglevel) { - fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX + if (loglevel != 0) { + fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, (int)T0, tlb->RPN, tlb->EPN, tlb->size, tlb->prot & PAGE_READ ? 'r' : '-', diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d7473fef6..51332ff4b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -355,6 +355,17 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn) RET_STOP(ctx); } +static void spr_write_40x_sler (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_40x_sler(); + /* We must stop the translation as we may have changed + * some regions endianness + */ + RET_STOP(ctx); +} + static void spr_write_booke_tcr (void *opaque, int sprn) { gen_op_store_booke_tcr(); @@ -1711,10 +1722,9 @@ static void gen_spr_405 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Storage control */ - /* XXX : not implemented */ spr_register(env, SPR_405_SLER, "SLER", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_40x_sler, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_405_SU0R, "SU0R", @@ -2837,7 +2847,7 @@ static ppc_def_t ppc_defs[] = { .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, + .msr_mask = 0x00000000000ED630ULL, }, #if defined (TODO) /* PowerPC 405 EZ */ -- cgit v1.2.3 From 35cdaad645d7a97e67690582feb1fc3a050c92ad Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 06:50:21 +0000 Subject: Code provision for new PowerPC embedded target support with: - 1 kB page size - 64 bits GPR - 64 bits physical address space - SPE extension support. Change TARGET_PPCSPE into TARGET_PPCEMB git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2718 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 11 ++++++++--- target-ppc/exec.h | 2 +- target-ppc/op.c | 4 ++-- target-ppc/op_helper.c | 4 ++-- target-ppc/op_helper.h | 8 ++++---- target-ppc/op_mem.h | 8 ++++---- target-ppc/op_template.h | 4 ++-- target-ppc/translate.c | 6 +++--- 8 files changed, 26 insertions(+), 21 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 4a241f1b3..a25d30a62 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -23,11 +23,13 @@ #include "config.h" #include +#if !defined(TARGET_PPCEMB) #if defined(TARGET_PPC64) || (HOST_LONG_BITS >= 64) /* When using 64 bits temporary registers, * we can use 64 bits GPR with no extra cost */ -#define TARGET_PPCSPE +#define TARGET_PPCEMB +#endif #endif #if defined (TARGET_PPC64) @@ -35,7 +37,8 @@ typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 64 #define TARGET_GPR_BITS 64 #define REGX "%016" PRIx64 -#elif defined(TARGET_PPCSPE) +#define TARGET_PAGE_BITS 12 +#elif defined(TARGET_PPCEMB) /* e500v2 have 36 bits physical address space */ #define TARGET_PHYS_ADDR_BITS 64 /* GPR are 64 bits: used by vector extension */ @@ -43,11 +46,14 @@ typedef uint64_t ppc_gpr_t; #define TARGET_LONG_BITS 32 #define TARGET_GPR_BITS 64 #define REGX "%016" PRIx64 +/* Pages can be 1 kB small */ +#define TARGET_PAGE_BITS 10 #else typedef uint32_t ppc_gpr_t; #define TARGET_LONG_BITS 32 #define TARGET_GPR_BITS 32 #define REGX "%08" PRIx32 +#define TARGET_PAGE_BITS 12 #endif #include "cpu-defs.h" @@ -893,7 +899,6 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address); int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp); int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); -#define TARGET_PAGE_BITS 12 #include "cpu-all.h" /*****************************************************************************/ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index a0f91ccd4..4f5abe906 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -43,7 +43,7 @@ register unsigned long T1 asm(AREG2); register unsigned long T2 asm(AREG3); #endif /* We may, sometime, need 64 bits registers on 32 bits target */ -#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE) || (HOST_LONG_BITS == 64) +#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) || (HOST_LONG_BITS == 64) #define T0_64 T0 #define T1_64 T1 #define T2_64 T2 diff --git a/target-ppc/op.c b/target-ppc/op.c index f18e7f3f9..019594c13 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2479,7 +2479,7 @@ void OPPROTO op_store_booke_tsr (void) #endif /* !defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) /* SPE extension */ void OPPROTO op_splatw_T1_64 (void) { @@ -3198,4 +3198,4 @@ void OPPROTO op_efdtsteq (void) T0 = _do_efdtsteq(T0_64, T1_64); RETURN(); } -#endif /* defined(TARGET_PPCSPE) */ +#endif /* defined(TARGET_PPCEMB) */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index a888821d2..10390a9c1 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1340,7 +1340,7 @@ void do_440_dlmzb (void) T0 = i; } -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) /* SPE extension helpers */ /* Use a table to make this quicker */ static uint8_t hbrev[16] = { @@ -2200,7 +2200,7 @@ DO_SPE_OP1(fsctuiz); DO_SPE_OP1(fsctsf); /* evfsctuf */ DO_SPE_OP1(fsctuf); -#endif /* defined(TARGET_PPCSPE) */ +#endif /* defined(TARGET_PPCEMB) */ /*****************************************************************************/ /* Softmmu support */ diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 293031075..82307d44f 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -183,7 +183,7 @@ void do_load_403_pb (int num); void do_store_403_pb (int num); #endif -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) /* SPE extension helpers */ void do_brinc (void); /* Fixed-point vector helpers */ @@ -264,7 +264,7 @@ void do_evfsctsi (void); void do_evfsctui (void); void do_evfsctsiz (void); void do_evfsctuiz (void); -#endif /* defined(TARGET_PPCSPE) */ +#endif /* defined(TARGET_PPCEMB) */ /* Inlined helpers: used in micro-operation as well as helpers */ /* Generic fixed-point helpers */ @@ -338,7 +338,7 @@ static inline int _do_cntlzd (uint64_t val) return cnt; } -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) /* SPE extension */ /* Single precision floating-point helpers */ static inline uint32_t _do_efsabs (uint32_t val) @@ -459,5 +459,5 @@ static inline int _do_efdtsteq (uint64_t op1, uint64_t op2) u2.u = op2; return float64_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0; } -#endif /* defined(TARGET_PPCSPE) */ +#endif /* defined(TARGET_PPCEMB) */ #endif diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index a78aa62c4..612d120a5 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -37,7 +37,7 @@ static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); } -#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE) +#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) { uint64_t tmp = glue(ldq, MEMSUFFIX)(EA); @@ -79,7 +79,7 @@ static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t data) glue(stl, MEMSUFFIX)(EA, tmp); } -#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE) +#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) static inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t data) { uint64_t tmp = ((data & 0xFF00000000000000ULL) >> 56) | @@ -895,7 +895,7 @@ void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void) RETURN(); } -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) /* SPE extension */ #define _PPC_SPE_LD_OP(name, op) \ void OPPROTO glue(glue(op_spe_l, name), MEMSUFFIX) (void) \ @@ -1151,6 +1151,6 @@ static inline uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whsplat_le, spe_lwhsplat_le); -#endif /* defined(TARGET_PPCSPE) */ +#endif /* defined(TARGET_PPCEMB) */ #undef MEMSUFFIX diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index bcef1a5cb..4487a879c 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -57,7 +57,7 @@ void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) } #endif -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void) { T0_64 = regs->gpr[REG]; @@ -97,7 +97,7 @@ void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) RETURN(); } #endif -#endif /* defined(TARGET_PPCSPE) */ +#endif /* defined(TARGET_PPCEMB) */ #if REG <= 7 /* Condition register moves */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6e27854bc..2ea759ad9 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -161,7 +161,7 @@ typedef struct DisasContext { int sf_mode; #endif int fpu_enabled; -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) int spe_enabled; #endif ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ @@ -4761,7 +4761,7 @@ GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE) */ } -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) /*** SPE extension ***/ /* Register moves */ @@ -5740,7 +5740,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, ctx.sf_mode = msr_sf; #endif ctx.fpu_enabled = msr_fp; -#if defined(TARGET_PPCSPE) +#if defined(TARGET_PPCEMB) ctx.spe_enabled = msr_spe; #endif ctx.singlestep_enabled = env->singlestep_enabled; -- cgit v1.2.3 From 86f55663bd3926abba1d37e0440503a89ed2900f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 06:52:59 +0000 Subject: Add -pflash option to register parallel flash bloc devices. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2719 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 34 +++++++++++++++++++++++++++++++++- vl.h | 2 ++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index ad632a20e..6a3acbeb0 100644 --- a/vl.c +++ b/vl.c @@ -138,6 +138,7 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; /* Note: bs_table[MAX_DISKS] is a dummy block driver if none available to store the VM snapshots */ BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; +BlockDriverState *pflash_table[MAX_PFLASH]; BlockDriverState *sd_bdrv; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; @@ -6366,6 +6367,7 @@ void help(void) "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-sd file use 'file' as SecureDigital card image\n" + "-pflash file use 'file' as a parallel flash image\n" "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" "-snapshot write to temporary files instead of disk image files\n" #ifdef CONFIG_SDL @@ -6504,6 +6506,7 @@ enum { QEMU_OPTION_hdd, QEMU_OPTION_cdrom, QEMU_OPTION_sd, + QEMU_OPTION_pflash, QEMU_OPTION_boot, QEMU_OPTION_snapshot, #ifdef TARGET_I386 @@ -6583,6 +6586,7 @@ const QEMUOption qemu_options[] = { { "hdd", HAS_ARG, QEMU_OPTION_hdd }, { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, { "sd", HAS_ARG, QEMU_OPTION_sd }, + { "pflash", HAS_ARG, QEMU_OPTION_pflash }, { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, #ifdef TARGET_I386 @@ -6867,10 +6871,11 @@ int main(int argc, char **argv) int use_gdbstub; const char *gdbstub_port; #endif - int i, cdrom_index; + int i, cdrom_index, pflash_index; int snapshot, linux_boot; const char *initrd_filename; const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; + const char *pflash_filename[MAX_PFLASH]; const char *sd_filename; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; @@ -6932,6 +6937,9 @@ int main(int argc, char **argv) fd_filename[i] = NULL; for(i = 0; i < MAX_DISKS; i++) hd_filename[i] = NULL; + for(i = 0; i < MAX_PFLASH; i++) + pflash_filename[i] = NULL; + pflash_index = 0; sd_filename = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; @@ -7054,6 +7062,13 @@ int main(int argc, char **argv) case QEMU_OPTION_sd: sd_filename = optarg; break; + case QEMU_OPTION_pflash: + if (pflash_index >= MAX_PFLASH) { + fprintf(stderr, "qemu: too many parallel flash images\n"); + exit(1); + } + pflash_filename[pflash_index++] = optarg; + break; case QEMU_OPTION_snapshot: snapshot = 1; break; @@ -7563,6 +7578,23 @@ int main(int argc, char **argv) } } + /* Open the virtual parallel flash bloc devices */ + for(i = 0; i < MAX_PFLASH; i++) { + if (pflash_filename[i]) { + if (!pflash_table[i]) { + char buf[64]; + snprintf(buf, sizeof(buf), "fl%c", i + 'a'); + pflash_table[i] = bdrv_new(buf); + } + if (bdrv_open(pflash_table[i], pflash_filename[i], + snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { + fprintf(stderr, "qemu: could not open flash image '%s'\n", + pflash_filename[i]); + exit(1); + } + } + } + sd_bdrv = bdrv_new ("sd"); /* FIXME: This isn't really a floppy, but it's a reasonable approximation. */ diff --git a/vl.h b/vl.h index 855a854ec..f9967d346 100644 --- a/vl.h +++ b/vl.h @@ -1459,6 +1459,8 @@ int sh7750_register_io_device(struct SH7750State *s, int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); /* NOR flash devices */ +#define MAX_PFLASH 4 +extern BlockDriverState *pflash_table[MAX_PFLASH]; typedef struct pflash_t pflash_t; pflash_t *pflash_register (target_ulong base, ram_addr_t off, -- cgit v1.2.3 From d4082e95f18fdcbe4f1a80534086d4a28f651d38 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 07:34:03 +0000 Subject: New target for embedded PowerPC emulation (only system emulation, for now). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2720 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 +++ Makefile.target | 3 +++ configure | 8 +++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c547453d5..65ad05616 100644 --- a/Makefile +++ b/Makefile @@ -136,6 +136,8 @@ tarbin: ( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \ $(bindir)/qemu \ $(bindir)/qemu-system-ppc \ + $(bindir)/qemu-system-ppc64 \ + $(bindir)/qemu-system-ppcemb \ $(bindir)/qemu-system-sparc \ $(bindir)/qemu-system-x86_64 \ $(bindir)/qemu-system-mips \ @@ -148,6 +150,7 @@ tarbin: $(bindir)/qemu-armeb \ $(bindir)/qemu-sparc \ $(bindir)/qemu-ppc \ + $(bindir)/qemu-ppc64 \ $(bindir)/qemu-mips \ $(bindir)/qemu-mipsel \ $(bindir)/qemu-alpha \ diff --git a/Makefile.target b/Makefile.target index 45a8ab4d2..7c9590fe0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -10,6 +10,9 @@ endif ifeq ($(TARGET_ARCH), ppc64) TARGET_BASE_ARCH:=ppc endif +ifeq ($(TARGET_ARCH), ppcemb) +TARGET_BASE_ARCH:=ppc +endif ifeq ($(TARGET_ARCH), sparc64) TARGET_BASE_ARCH:=sparc endif diff --git a/configure b/configure index adfc268e4..e8c8257f6 100755 --- a/configure +++ b/configure @@ -469,7 +469,7 @@ 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 mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu " fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then @@ -868,6 +868,7 @@ target_bigendian="no" [ "$target_cpu" = "sparc64" ] && target_bigendian=yes [ "$target_cpu" = "ppc" ] && target_bigendian=yes [ "$target_cpu" = "ppc64" ] && target_bigendian=yes +[ "$target_cpu" = "ppcemb" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes [ "$target_cpu" = "mips64" ] && target_bigendian=yes [ "$target_cpu" = "sh4eb" ] && target_bigendian=yes @@ -958,6 +959,11 @@ elif test "$target_cpu" = "ppc64" ; then 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" = "ppcemb" ; then + echo "TARGET_ARCH=ppcemb" >> $config_mak + echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h + echo "#define TARGET_PPC 1" >> $config_h + echo "#define TARGET_PPCEMB 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 -- cgit v1.2.3 From 6b80055dfa4625cad6c0377e0c82ab7fc162c7dd Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 07:36:03 +0000 Subject: Debug traces fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2721 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 10390a9c1..ee46253c7 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -189,7 +189,7 @@ void do_store_fpscr (uint32_t mask) target_ulong ppc_load_dump_spr (int sprn) { - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n", sprn, sprn, env->spr[sprn]); } @@ -199,7 +199,7 @@ target_ulong ppc_load_dump_spr (int sprn) void ppc_store_dump_spr (int sprn, target_ulong val) { - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "Write SPR %d %03x => " ADDRX " <= " ADDRX "\n", sprn, sprn, env->spr[sprn], val); } @@ -904,6 +904,7 @@ void do_fcmpo (void) } #if !defined (CONFIG_USER_ONLY) +void cpu_dump_rfi (target_ulong RA, target_ulong msr); void do_rfi (void) { #if defined(TARGET_PPC64) @@ -919,7 +920,7 @@ void do_rfi (void) do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); #endif #if defined (DEBUG_OP) - dump_rfi(); + cpu_dump_rfi(env->nip, do_load_msr(env)); #endif env->interrupt_request |= CPU_INTERRUPT_EXITTB; } @@ -935,7 +936,7 @@ void do_rfid (void) do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); } #if defined (DEBUG_OP) - dump_rfi(); + cpu_dump_rfi(env->nip, do_load_msr(env)); #endif env->interrupt_request |= CPU_INTERRUPT_EXITTB; } @@ -1136,7 +1137,7 @@ void do_POWER_rfsvc (void) T0 = env->ctr & 0x0000FFFFUL; do_store_msr(env, T0); #if defined (DEBUG_OP) - dump_rfi(); + cpu_dump_rfi(env->nip, do_load_msr(env)); #endif env->interrupt_request |= CPU_INTERRUPT_EXITTB; } @@ -1214,7 +1215,7 @@ void do_40x_rfci (void) env->nip = env->spr[SPR_40x_SRR2]; do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000); #if defined (DEBUG_OP) - dump_rfi(); + cpu_dump_rfi(env->nip, do_load_msr(env)); #endif env->interrupt_request = CPU_INTERRUPT_EXITTB; } @@ -1231,7 +1232,7 @@ void do_rfci (void) } do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_CSRR1] & ~0x3FFF0000); #if defined (DEBUG_OP) - dump_rfi(); + cpu_dump_rfi(env->nip, do_load_msr(env)); #endif env->interrupt_request = CPU_INTERRUPT_EXITTB; } @@ -1248,7 +1249,7 @@ void do_rfdi (void) } do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_DSRR1] & ~0x3FFF0000); #if defined (DEBUG_OP) - dump_rfi(); + cpu_dump_rfi(env->nip, do_load_msr(env)); #endif env->interrupt_request = CPU_INTERRUPT_EXITTB; } @@ -1265,7 +1266,7 @@ void do_rfmci (void) } do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_MCSRR1] & ~0x3FFF0000); #if defined (DEBUG_OP) - dump_rfi(); + cpu_dump_rfi(env->nip, do_load_msr(env)); #endif env->interrupt_request = CPU_INTERRUPT_EXITTB; } @@ -1275,12 +1276,12 @@ void do_load_dcr (void) target_ulong val; if (unlikely(env->dcr_env == NULL)) { - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "No DCR environment\n"); } do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) { - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0); } do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); @@ -1292,12 +1293,12 @@ void do_load_dcr (void) void do_store_dcr (void) { if (unlikely(env->dcr_env == NULL)) { - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "No DCR environment\n"); } do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) { - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0); } do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); @@ -2515,7 +2516,7 @@ void do_4xx_tlbwe_hi (void) target_ulong page, end; #if defined (DEBUG_SOFTWARE_TLB) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); } #endif @@ -2525,7 +2526,7 @@ void do_4xx_tlbwe_hi (void) if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; #if defined (DEBUG_SOFTWARE_TLB) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end); } @@ -2568,7 +2569,7 @@ void do_4xx_tlbwe_hi (void) if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; #if defined (DEBUG_SOFTWARE_TLB) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s: invalidate TLB %d start " ADDRX " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end); } @@ -2583,7 +2584,7 @@ void do_4xx_tlbwe_lo (void) ppcemb_tlb_t *tlb; #if defined (DEBUG_SOFTWARE_TLB) - if (loglevel) { + if (loglevel != 0) { fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); } #endif @@ -2596,8 +2597,8 @@ void do_4xx_tlbwe_lo (void) if (T1 & 0x100) tlb->prot |= PAGE_WRITE; #if defined (DEBUG_SOFTWARE_TLB) - if (loglevel) { - fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX + if (loglevel != 0) { + fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, (int)T0, tlb->RPN, tlb->EPN, tlb->size, tlb->prot & PAGE_READ ? 'r' : '-', -- cgit v1.2.3 From 1a6c0886203689bd522d814d3c698328d35aaf91 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 07:40:49 +0000 Subject: Evaluation boards for PowerPC 405EP. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2722 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/ppc405_boards.c | 630 +++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 2 + vl.h | 2 + 4 files changed, 635 insertions(+), 1 deletion(-) create mode 100644 hw/ppc405_boards.c diff --git a/Makefile.target b/Makefile.target index 7c9590fe0..b76694634 100644 --- a/Makefile.target +++ b/Makefile.target @@ -426,7 +426,7 @@ 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 pflash_cfi02.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o -VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o ppc405_uc.o +VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o ppc405_uc.o ppc405_boards.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), mips) diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c new file mode 100644 index 000000000..2e2ca0e74 --- /dev/null +++ b/hw/ppc405_boards.c @@ -0,0 +1,630 @@ +/* + * QEMU PowerPC 405 evaluation boards emulation + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "ppc405.h" + +extern int loglevel; +extern FILE *logfile; + +#define BIOS_FILENAME "ppc405_rom.bin" +#undef BIOS_SIZE +#define BIOS_SIZE (2048 * 1024) + +#define KERNEL_LOAD_ADDR 0x00000000 +#define INITRD_LOAD_ADDR 0x01800000 + +#define USE_FLASH_BIOS + +#define DEBUG_BOARD_INIT + +/*****************************************************************************/ +/* PPC405EP reference board (IBM) */ +/* Standalone board with: + * - PowerPC 405EP CPU + * - SDRAM (0x00000000) + * - Flash (0xFFF80000) + * - SRAM (0xFFF00000) + * - NVRAM (0xF0000000) + * - FPGA (0xF0300000) + */ +typedef struct ref405ep_fpga_t ref405ep_fpga_t; +struct ref405ep_fpga_t { + uint32_t base; + uint8_t reg0; + uint8_t reg1; +}; + +static uint32_t ref405ep_fpga_readb (void *opaque, target_phys_addr_t addr) +{ + ref405ep_fpga_t *fpga; + uint32_t ret; + + fpga = opaque; + addr -= fpga->base; + switch (addr) { + case 0x0: + ret = fpga->reg0; + break; + case 0x1: + ret = fpga->reg1; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void ref405ep_fpga_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ref405ep_fpga_t *fpga; + + fpga = opaque; + addr -= fpga->base; + switch (addr) { + case 0x0: + /* Read only */ + break; + case 0x1: + fpga->reg1 = value; + break; + default: + break; + } +} + +static uint32_t ref405ep_fpga_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + + ret = ref405ep_fpga_readb(opaque, addr) << 8; + ret |= ref405ep_fpga_readb(opaque, addr + 1); + + return ret; +} + +static void ref405ep_fpga_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF); + ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF); +} + +static uint32_t ref405ep_fpga_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + + ret = ref405ep_fpga_readb(opaque, addr) << 24; + ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16; + ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8; + ret |= ref405ep_fpga_readb(opaque, addr + 3); + + return ret; +} + +static void ref405ep_fpga_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ref405ep_fpga_writel(opaque, addr, (value >> 24) & 0xFF); + ref405ep_fpga_writel(opaque, addr + 1, (value >> 16) & 0xFF); + ref405ep_fpga_writel(opaque, addr + 2, (value >> 8) & 0xFF); + ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF); +} + +static CPUReadMemoryFunc *ref405ep_fpga_read[] = { + &ref405ep_fpga_readb, + &ref405ep_fpga_readw, + &ref405ep_fpga_readl, +}; + +static CPUWriteMemoryFunc *ref405ep_fpga_write[] = { + &ref405ep_fpga_writeb, + &ref405ep_fpga_writew, + &ref405ep_fpga_writel, +}; + +static void ref405ep_fpga_reset (void *opaque) +{ + ref405ep_fpga_t *fpga; + + fpga = opaque; + fpga->reg0 = 0x00; + fpga->reg1 = 0x0F; +} + +static void ref405ep_fpga_init (uint32_t base) +{ + ref405ep_fpga_t *fpga; + int fpga_memory; + + fpga = qemu_mallocz(sizeof(ref405ep_fpga_t)); + if (fpga != NULL) { + fpga->base = base; + fpga_memory = cpu_register_io_memory(0, ref405ep_fpga_read, + ref405ep_fpga_write, fpga); + cpu_register_physical_memory(base, 0x00000100, fpga_memory); + ref405ep_fpga_reset(fpga); + qemu_register_reset(&ref405ep_fpga_reset, fpga); + } +} + +static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + char buf[1024]; + ppc4xx_bd_info_t bd; + CPUPPCState *env; + qemu_irq *pic; + ram_addr_t sram_offset, bios_offset, bdloc; + target_ulong ram_bases[2], ram_sizes[2]; + target_ulong sram_size, bios_size; + //int phy_addr = 0; + //static int phy_addr = 1; + target_ulong kernel_base, kernel_size, initrd_base, initrd_size; + int linux_boot; + int fl_idx, fl_sectors, len; + + /* XXX: fix this */ + ram_bases[0] = 0x00000000; + ram_sizes[0] = 0x08000000; + ram_bases[1] = 0x00000000; + ram_sizes[1] = 0x00000000; + ram_size = 128 * 1024 * 1024; +#ifdef DEBUG_BOARD_INIT + printf("%s: register cpu\n", __func__); +#endif + env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &sram_offset, + kernel_filename == NULL ? 0 : 1); + /* allocate SRAM */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset); +#endif + sram_size = 512 * 1024; + cpu_register_physical_memory(0xFFF00000, sram_size, + sram_offset | IO_MEM_RAM); + /* allocate and load BIOS */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register BIOS\n", __func__); +#endif + bios_offset = sram_offset + sram_size; + fl_idx = 0; +#ifdef USE_FLASH_BIOS + if (pflash_table[fl_idx] != NULL) { + bios_size = bdrv_getlength(pflash_table[fl_idx]); + fl_sectors = (bios_size + 65535) >> 16; +#ifdef DEBUG_BOARD_INIT + printf("Register parallel flash %d size " ADDRX " at offset %08lx " + " addr " ADDRX " '%s' %d\n", + fl_idx, bios_size, bios_offset, -bios_size, + bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors); +#endif + pflash_register(-(bios_size), bios_offset, pflash_table[fl_idx], + 65536, fl_sectors, 2, + 0x0001, 0x22DA, 0x0000, 0x0000); + fl_idx++; + } else +#endif + { +#ifdef DEBUG_BOARD_INIT + printf("Load BIOS from file\n"); +#endif + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + bios_size = load_image(buf, phys_ram_base + bios_offset); + if (bios_size < 0 || bios_size > BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf); + exit(1); + } + bios_size = (bios_size + 0xfff) & ~0xfff; + cpu_register_physical_memory((uint32_t)(-bios_size), + bios_size, bios_offset | IO_MEM_ROM); + } + bios_offset += bios_size; + /* Register FPGA */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register FPGA\n", __func__); +#endif + ref405ep_fpga_init(0xF0300000); + /* Register NVRAM */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register NVRAM\n", __func__); +#endif + m48t59_init(NULL, 0xF0000000, 0, 8192, 8); + /* Load kernel */ + linux_boot = (kernel_filename != NULL); + if (linux_boot) { +#ifdef DEBUG_BOARD_INIT + printf("%s: load kernel\n", __func__); +#endif + memset(&bd, 0, sizeof(bd)); + bd.bi_memstart = 0x00000000; + bd.bi_memsize = ram_size; + bd.bi_flashstart = -(bios_size); + bd.bi_flashsize = -bios_size; + bd.bi_flashoffset = 0; + bd.bi_sramstart = 0xFFF00000; + bd.bi_sramsize = sram_size; + bd.bi_bootflags = 0; + bd.bi_intfreq = 133333333; + bd.bi_busfreq = 33333333; + bd.bi_baudrate = 115200; + bd.bi_s_version[0] = 'Q'; + bd.bi_s_version[1] = 'M'; + bd.bi_s_version[2] = 'U'; + bd.bi_s_version[3] = '\0'; + bd.bi_r_version[0] = 'Q'; + bd.bi_r_version[1] = 'E'; + bd.bi_r_version[2] = 'M'; + bd.bi_r_version[3] = 'U'; + bd.bi_r_version[4] = '\0'; + bd.bi_procfreq = 133333333; + bd.bi_plb_busfreq = 33333333; + bd.bi_pci_busfreq = 33333333; + bd.bi_opbfreq = 33333333; + bdloc = ppc405_set_bootinfo(env, &bd); + env->gpr[3] = bdloc; + kernel_base = KERNEL_LOAD_ADDR; + /* now we can load the kernel */ + kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx + " %02x %02x %02x %02x\n", kernel_size, kernel_base, + *(char *)(phys_ram_base + kernel_base), + *(char *)(phys_ram_base + kernel_base + 1), + *(char *)(phys_ram_base + kernel_base + 2), + *(char *)(phys_ram_base + kernel_base + 3)); + /* load initrd */ + if (initrd_filename) { + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_base); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + env->gpr[4] = initrd_base; + env->gpr[5] = initrd_size; + boot_device = 'm'; + if (kernel_cmdline != NULL) { + len = strlen(kernel_cmdline); + bdloc -= ((len + 255) & ~255); + memcpy(phys_ram_base + bdloc, kernel_cmdline, len + 1); + env->gpr[6] = bdloc; + env->gpr[7] = bdloc + len; + } else { + env->gpr[6] = 0; + env->gpr[7] = 0; + } + env->nip = KERNEL_LOAD_ADDR; + } else { + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; + bdloc = 0; + } +#ifdef DEBUG_BOARD_INIT + printf("%s: Done\n", __func__); +#endif + printf("bdloc %016lx %s\n", + (unsigned long)bdloc, (char *)(phys_ram_base + bdloc)); +} + +QEMUMachine ref405ep_machine = { + "ref405ep", + "ref405ep", + ref405ep_init, +}; + +/*****************************************************************************/ +/* AMCC Taihu evaluation board */ +/* - PowerPC 405EP processor + * - SDRAM 128 MB at 0x00000000 + * - Boot flash 2 MB at 0xFFE00000 + * - Application flash 32 MB at 0xFC000000 + * - 2 serial ports + * - 2 ethernet PHY + * - 1 USB 1.1 device 0x50000000 + * - 1 LCD display 0x50100000 + * - 1 CPLD 0x50100000 + * - 1 I2C EEPROM + * - 1 I2C thermal sensor + * - a set of LEDs + * - bit-bang SPI port using GPIOs + * - 1 EBC interface connector 0 0x50200000 + * - 1 cardbus controller + expansion slot. + * - 1 PCI expansion slot. + */ +typedef struct taihu_cpld_t taihu_cpld_t; +struct taihu_cpld_t { + uint32_t base; + uint8_t reg0; + uint8_t reg1; +}; + +static uint32_t taihu_cpld_readb (void *opaque, target_phys_addr_t addr) +{ + taihu_cpld_t *cpld; + uint32_t ret; + + cpld = opaque; + addr -= cpld->base; + switch (addr) { + case 0x0: + ret = cpld->reg0; + break; + case 0x1: + ret = cpld->reg1; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void taihu_cpld_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + taihu_cpld_t *cpld; + + cpld = opaque; + addr -= cpld->base; + switch (addr) { + case 0x0: + /* Read only */ + break; + case 0x1: + cpld->reg1 = value; + break; + default: + break; + } +} + +static uint32_t taihu_cpld_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + + ret = taihu_cpld_readb(opaque, addr) << 8; + ret |= taihu_cpld_readb(opaque, addr + 1); + + return ret; +} + +static void taihu_cpld_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF); + taihu_cpld_writeb(opaque, addr + 1, value & 0xFF); +} + +static uint32_t taihu_cpld_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t ret; + + ret = taihu_cpld_readb(opaque, addr) << 24; + ret |= taihu_cpld_readb(opaque, addr + 1) << 16; + ret |= taihu_cpld_readb(opaque, addr + 2) << 8; + ret |= taihu_cpld_readb(opaque, addr + 3); + + return ret; +} + +static void taihu_cpld_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF); + taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF); + taihu_cpld_writel(opaque, addr + 2, (value >> 8) & 0xFF); + taihu_cpld_writeb(opaque, addr + 3, value & 0xFF); +} + +static CPUReadMemoryFunc *taihu_cpld_read[] = { + &taihu_cpld_readb, + &taihu_cpld_readw, + &taihu_cpld_readl, +}; + +static CPUWriteMemoryFunc *taihu_cpld_write[] = { + &taihu_cpld_writeb, + &taihu_cpld_writew, + &taihu_cpld_writel, +}; + +static void taihu_cpld_reset (void *opaque) +{ + taihu_cpld_t *cpld; + + cpld = opaque; + cpld->reg0 = 0x01; + cpld->reg1 = 0x80; +} + +static void taihu_cpld_init (uint32_t base) +{ + taihu_cpld_t *cpld; + int cpld_memory; + + cpld = qemu_mallocz(sizeof(taihu_cpld_t)); + if (cpld != NULL) { + cpld->base = base; + cpld_memory = cpu_register_io_memory(0, taihu_cpld_read, + taihu_cpld_write, cpld); + cpu_register_physical_memory(base, 0x00000100, cpld_memory); + taihu_cpld_reset(cpld); + qemu_register_reset(&taihu_cpld_reset, cpld); + } +} + +static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + char buf[1024]; + CPUPPCState *env; + qemu_irq *pic; + ram_addr_t bios_offset; + target_ulong ram_bases[2], ram_sizes[2]; + target_ulong bios_size; + target_ulong kernel_base, kernel_size, initrd_base, initrd_size; + int linux_boot; + int fl_idx, fl_sectors; + + /* RAM is soldered to the board so the size cannot be changed */ + ram_bases[0] = 0x00000000; + ram_sizes[0] = 0x04000000; + ram_bases[1] = 0x04000000; + ram_sizes[1] = 0x04000000; +#ifdef DEBUG_BOARD_INIT + printf("%s: register cpu\n", __func__); +#endif + env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &bios_offset, + kernel_filename == NULL ? 0 : 1); + /* allocate and load BIOS */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register BIOS\n", __func__); +#endif + fl_idx = 0; +#if defined(USE_FLASH_BIOS) + if (pflash_table[fl_idx] != NULL) { + bios_size = bdrv_getlength(pflash_table[fl_idx]); + /* XXX: should check that size is 2MB */ + // bios_size = 2 * 1024 * 1024; + fl_sectors = (bios_size + 65535) >> 16; +#ifdef DEBUG_BOARD_INIT + printf("Register parallel flash %d size " ADDRX " at offset %08lx " + " addr " ADDRX " '%s' %d\n", + fl_idx, bios_size, bios_offset, -bios_size, + bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors); +#endif + pflash_register(-(bios_size), bios_offset, pflash_table[fl_idx], + 65536, fl_sectors, 4, + 0x0001, 0x22DA, 0x0000, 0x0000); + fl_idx++; + } else +#endif + { +#ifdef DEBUG_BOARD_INIT + printf("Load BIOS from file\n"); +#endif + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + bios_size = load_image(buf, phys_ram_base + bios_offset); + if (bios_size < 0 || bios_size > BIOS_SIZE) { + fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf); + exit(1); + } + bios_size = (bios_size + 0xfff) & ~0xfff; + cpu_register_physical_memory((uint32_t)(-bios_size), + bios_size, bios_offset | IO_MEM_ROM); + } + bios_offset += bios_size; + /* Register Linux flash */ + if (pflash_table[fl_idx] != NULL) { + bios_size = bdrv_getlength(pflash_table[fl_idx]); + /* XXX: should check that size is 32MB */ + bios_size = 32 * 1024 * 1024; + fl_sectors = (bios_size + 65535) >> 16; +#ifdef DEBUG_BOARD_INIT + printf("Register parallel flash %d size " ADDRX " at offset %08lx " + " addr " ADDRX " '%s'\n", + fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000, + bdrv_get_device_name(pflash_table[fl_idx])); +#endif + pflash_register(0xfc000000, bios_offset, pflash_table[fl_idx], + 65536, fl_sectors, 4, + 0x0001, 0x22DA, 0x0000, 0x0000); + fl_idx++; + } + /* Register CLPD & LCD display */ +#ifdef DEBUG_BOARD_INIT + printf("%s: register CPLD\n", __func__); +#endif + taihu_cpld_init(0x50100000); + /* Load kernel */ + linux_boot = (kernel_filename != NULL); + if (linux_boot) { +#ifdef DEBUG_BOARD_INIT + printf("%s: load kernel\n", __func__); +#endif + kernel_base = KERNEL_LOAD_ADDR; + /* now we can load the kernel */ + kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + /* load initrd */ + if (initrd_filename) { + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_base); + if (initrd_size < 0) { + fprintf(stderr, + "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + boot_device = 'm'; + } else { + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; + } +#ifdef DEBUG_BOARD_INIT + printf("%s: Done\n", __func__); +#endif +} + +QEMUMachine taihu_machine = { + "taihu", + "taihu", + taihu_405ep_init, +}; diff --git a/vl.c b/vl.c index 6a3acbeb0..bf3aaca58 100644 --- a/vl.c +++ b/vl.c @@ -6717,6 +6717,8 @@ void register_machines(void) qemu_register_machine(&heathrow_machine); qemu_register_machine(&core99_machine); qemu_register_machine(&prep_machine); + qemu_register_machine(&ref405ep_machine); + qemu_register_machine(&taihu_machine); #elif defined(TARGET_MIPS) qemu_register_machine(&mips_machine); qemu_register_machine(&mips_malta_machine); diff --git a/vl.h b/vl.h index f9967d346..0046b4353 100644 --- a/vl.h +++ b/vl.h @@ -1133,6 +1133,8 @@ int ioport_get_a20(void); extern QEMUMachine prep_machine; extern QEMUMachine core99_machine; extern QEMUMachine heathrow_machine; +extern QEMUMachine ref405ep_machine; +extern QEMUMachine taihu_machine; /* mips_r4k.c */ extern QEMUMachine mips_machine; -- cgit v1.2.3 From eb143ca75dec6ecbae53e6ac152ac20c6c17a43a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 07:43:37 +0000 Subject: Update .cvsignore for new PowerPC embedded target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2723 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cvsignore b/.cvsignore index 45d63262d..7d638f64d 100644 --- a/.cvsignore +++ b/.cvsignore @@ -9,9 +9,11 @@ i386-darwin-user i386-linux-user ppc-softmmu ppc64-softmmu +ppcemb-softmmu ppc-darwin-user ppc-linux-user ppc64-linux-user +ppcemb-linux-user qemu-doc.html qemu-tech.html qemu-doc.info -- cgit v1.2.3 From 74563c166108d296d9c7531d89f2da064e45c258 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 24 Apr 2007 07:51:56 +0000 Subject: Update PowerPC target status. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2724 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/STATUS | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/target-ppc/STATUS b/target-ppc/STATUS index d5089f766..662a4a156 100644 --- a/target-ppc/STATUS +++ b/target-ppc/STATUS @@ -10,6 +10,7 @@ PowerPC CPU known to work (ie booting at least Linux 2.4): - PowerPC 604 & derivatives - PowerPC 740 & derivatives - PowerPC 750 & derivatives +- PowerPC 405 PowerPC that should work but are not supported by standard Linux kernel (then remain mostly untested) @@ -18,7 +19,6 @@ PowerPC that should work but are not supported by standard Linux kernel Work in progress: * embedded PowerPC cores -- PowerPC 405 - BookE PowerPC - e500 core (Freescale PowerQUICC) * main stream PowerPC cores @@ -59,8 +59,12 @@ TODO: =============================================================================== PowerPC microcontrollers emulation status +Implemementation should be sufficient to boot Linux: +- PowerPC 405CR +- PowerPC 405EP + TODO: -- PowerPC 40x microcontrollers emulation +- More PowerPC 40x microcontrollers emulation - PowerQUICC microcontrollers emulation =============================================================================== @@ -80,11 +84,21 @@ PowerPC based platforms emulation status - Gentoo Linux live CDROM 1.4 - boots, compiles linux kernel - Debian Linux woody - boots from CDROM and HDD - Mandrake Linux 9 - boots from CDROM, freezes during install +- Knoppix 2003-07-13_4 boots from CDROM, pb with X configuration + distribution bug: X runs with a properly hand-coded configuration. +- rock Linux 2.0 runs from CDROM + +* Linux 2.6 support seems deadly broken (used to boot...). + +* PowerPC 405EP reference boards: +- can boot Linux 2.4 & 2.6. + Need to provide a flash image ready to boot for reproductible tests. TODO: - MCA based RS/6000 emulation - CHRP emulation (not PowerMac) - PPAR emulation +- ePPAR emulation - misc PowerPC reference boards emulation =============================================================================== -- cgit v1.2.3 From d52fff710acfeaad0102c9a0c04bfb614441dcac Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 24 Apr 2007 22:57:37 +0000 Subject: Improved mini-bootloader, based on a patch by Alec Voropay. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2725 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 4f5090187..3a115032b 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -535,13 +535,14 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t /* Small bootloader */ p = (uint32_t *) (phys_ram_base + bios_offset); - stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */ + stl_raw(p++, 0x0bf00006); /* j 0x1fc00018 */ stl_raw(p++, 0x00000000); /* nop */ /* Second part of the bootloader */ - p = (uint32_t *) (phys_ram_base + bios_offset + 0x040); - stl_raw(p++, 0x3c040000); /* lui a0, 0 */ - stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */ + p = (uint32_t *) (phys_ram_base + bios_offset + 0x018); + stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */ + stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */ + stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, a0, low(ENVP_ADDR) */ stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */ stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ -- cgit v1.2.3 From 7bc45061eee222bd198db8485e2e9364190ff8f1 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 25 Apr 2007 13:58:52 +0000 Subject: Fix lui sign extension. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2726 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 3035ea26f..96a0f37d2 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -907,7 +907,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, GEN_LOAD_IMM_TN(T1, uimm); break; case OPC_LUI: - uimm <<= 16; + uimm = (int32_t)(imm << 16); GEN_LOAD_IMM_TN(T0, uimm); break; case OPC_SLL: -- cgit v1.2.3 From d6929309b689264755963fe5ee18767a7f1c4af5 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 25 Apr 2007 16:41:11 +0000 Subject: Next attempt to get the lui sign extension right. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2727 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_template.c | 2 +- target-mips/translate.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 8d4c4e404..04677cd84 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -54,7 +54,7 @@ void glue(op_load_gpr_T2_gpr, REG) (void) #define SET_RESET(treg, tregname) \ void glue(op_set, tregname)(void) \ { \ - treg = PARAM1; \ + treg = (int32_t)PARAM1; \ RETURN(); \ } \ void glue(op_reset, tregname)(void) \ diff --git a/target-mips/translate.c b/target-mips/translate.c index 96a0f37d2..06581f2cc 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -907,8 +907,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, GEN_LOAD_IMM_TN(T1, uimm); break; case OPC_LUI: - uimm = (int32_t)(imm << 16); - GEN_LOAD_IMM_TN(T0, uimm); + GEN_LOAD_IMM_TN(T0, uimm << 16); break; case OPC_SLL: case OPC_SRA: -- cgit v1.2.3 From 945446c653dba61ba0bd304d14e5d4f9938e2647 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 26 Apr 2007 18:32:00 +0000 Subject: Update Sparc32 rom to support *BSD boot and 24 bit TCX git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2728 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 3 ++- pc-bios/openbios-sparc32 | Bin 248348 -> 252444 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pc-bios/README b/pc-bios/README index 8d4fe584a..2b03d619e 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,8 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 and Sparc64 images are built from SVN version 125. + The included Sparc32 image is built from SVN version 131 and Sparc64 + image from version 125. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index a0d17af94..1b246eeed 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ -- cgit v1.2.3 From 8bf5a8047549eb589e09b8bb6fab47673d372e03 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 26 Apr 2007 23:48:49 +0000 Subject: Fix opcode for sts.l fpul/cpscr, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2729 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 1c9fe40f5..d53e28bd2 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1003,8 +1003,8 @@ void decode_opc(DisasContext * ctx) LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,) LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,) LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,) - LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x0052, sts,) - LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x0062, sts, ctx->flags |= + LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,) + LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |= MODE_CHANGE;) case 0x00c3: /* movca.l R0,@Rm */ gen_op_movl_rN_T0(REG(0)); -- cgit v1.2.3 From 56e0794aa7260d6ca0cd553a877dff19bfe83126 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 26 Apr 2007 23:49:45 +0000 Subject: Use 16-bit uid wrappers, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2730 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7f4f77169..78d8dfaa8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -74,7 +74,7 @@ //#define DEBUG #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ - || defined(TARGET_M68K) + || defined(TARGET_M68K) || defined(TARGET_SH4) /* 16 bit uid wrappers emulation */ #define USE_UID16 #endif -- cgit v1.2.3 From 0a61814043bbf21bd081820f8be44a11a300f96f Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 26 Apr 2007 23:50:46 +0000 Subject: Fix inc8 and dec8 operations, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2731 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/op.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-sh4/op.c b/target-sh4/op.c index d3b68bc66..758aa53b7 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -737,7 +737,7 @@ void OPPROTO op_dec4_rN(void) void OPPROTO op_dec8_rN(void) { - env->gregs[PARAM1] -= 4; + env->gregs[PARAM1] -= 8; RETURN(); } @@ -761,7 +761,7 @@ void OPPROTO op_inc4_rN(void) void OPPROTO op_inc8_rN(void) { - env->gregs[PARAM1] += 4; + env->gregs[PARAM1] += 8; RETURN(); } -- cgit v1.2.3 From 2f6ecc62eef8c591d9266309362989e8518dad7e Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 27 Apr 2007 00:01:20 +0000 Subject: Workaround qemu guest SIGSEGVs with cmpxchg8b insn, by Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2732 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index 735acb0e4..53ccc8599 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3797,6 +3797,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; + gen_jmp_im(pc_start - s->cs_base); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); -- cgit v1.2.3 From 9957427e1f0b3aee7752bac09b3083477aee064f Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 28 Apr 2007 15:18:14 +0000 Subject: Fix Sparc32 ldscript git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2733 c046a42c-6fe2-441c-8c8c-71466251a162 --- sparc.ld | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sparc.ld b/sparc.ld index 6333928ad..2b19d57ff 100644 --- a/sparc.ld +++ b/sparc.ld @@ -64,6 +64,8 @@ SECTIONS CONSTRUCTORS } .data1 : { *(.data1) } + .tdata : { *(.tdata) } + .tbss : { *(.tbss) } .ctors : { *(.ctors) @@ -125,4 +127,5 @@ SECTIONS .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } /* These must appear regardless of . */ + /DISCARD/ : { *(.note.GNU-stack) *(.note.ABI-tag) } } -- cgit v1.2.3 From 85a6f129250efde1fe0af91a981d5006a0646b96 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 28 Apr 2007 19:00:30 +0000 Subject: Update ppc.ld to work with newer binutils. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2734 c046a42c-6fe2-441c-8c8c-71466251a162 --- ppc.ld | 224 +++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 156 insertions(+), 68 deletions(-) diff --git a/ppc.ld b/ppc.ld index d0a0dcb9e..1e6bbe9a6 100644 --- a/ppc.ld +++ b/ppc.ld @@ -2,8 +2,8 @@ * Written by Martin Mares ; */ OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") -OUTPUT_ARCH(powerpc) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); +OUTPUT_ARCH(powerpc:common) +SEARCH_DIR(/usr/powerpc-linux-gnu/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib) ENTRY(_start) SECTIONS { @@ -16,93 +16,179 @@ SECTIONS .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 : + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rela.got1 : { *(.rela.got1) } + .rela.got2 : { *(.rela.got2) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { - *(.text) + KEEP (*(.init)) + } =0 + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) - *(.gnu.linkonce.t*) + *(.glink) + } =0x47ff041f + .fini : + { + KEEP (*(.fini)) } =0x47ff041f - _etext = .; + PROVIDE (__etext = .); + PROVIDE (_etext = .); PROVIDE (etext = .); - .fini : { *(.fini) } =0x47ff041f - . = ALIGN(32 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array : { *(.preinit_array) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { *(.init_array) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { *(.fini_array) } - PROVIDE (__fini_array_end = .); - .rodata : { *(.rodata) *(.gnu.linkonce.r*) } - .rodata1 : { *(.rodata1) } - .reginfo : { *(.reginfo) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + PROVIDE (_SDA2_BASE_ = 32768); + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } /* 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 : + . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .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 : { - *(.data) - *(.gnu.linkonce.d*) - CONSTRUCTORS + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) } - .data1 : { *(.data1) } - .ctors : + .dtors : { - *(.ctors) + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) } - .dtors : + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .got1 : { *(.got1) } + .got2 : { *(.got2) } + .dynamic : { *(.dynamic) } + .got : SPECIAL { *(.got) } + . = DATA_SEGMENT_RELRO_END (0, .); + .plt : SPECIAL { *(.plt) } + .data : { - *(.dtors) + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) } - .plt : { *(.plt) } - .got : { *(.got.plt) *(.got) } - .dynamic : { *(.dynamic) } + .data1 : { *(.data1) } + .got : SPECIAL { *(.got) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } - _edata = .; - PROVIDE (edata = .); + .sdata : + { + PROVIDE (_SDA_BASE_ = 32768); + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; PROVIDE (edata = .); __bss_start = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : + .sbss : + { + PROVIDE (__sbss_start = .); PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .); + } + .plt : SPECIAL { *(.plt) } + .bss : { *(.dynbss) - *(.bss) + *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); } - _end = . ; - PROVIDE (end = .); + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } @@ -137,4 +223,6 @@ SECTIONS .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } /* These must appear regardless of . */ + /DISCARD/ : { *(.fixup) } + /DISCARD/ : { *(.note.GNU-stack) } } -- cgit v1.2.3 From 7faa239ca39b986a64ca99056311b32bc6cff55f Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 28 Apr 2007 20:45:04 +0000 Subject: Fix length mismatch condition, by Wang Cheng Yeh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2735 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/lsi53c895a.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 71afd1f73..19bf2a195 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -855,6 +855,7 @@ again: offset = sxt24(addr); cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8); s->dbc = cpu_to_le32(buf[0]); + s->rbc = s->dbc; addr = cpu_to_le32(buf[1]); } if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { @@ -864,6 +865,8 @@ again: break; } s->dnad = addr; + /* ??? Set ESA. */ + s->ia = s->dsp - 8; switch (s->sstat1 & 0x7) { case PHASE_DO: s->waiting = 2; @@ -898,8 +901,6 @@ again: s->sbc = s->dbc; s->rbc -= s->dbc; s->ua = addr + s->dbc; - /* ??? Set ESA. */ - s->ia = s->dsp - 8; break; case 1: /* IO or Read/Write instruction. */ -- cgit v1.2.3 From 67cd24a89738ba03f5e8d9a4073c9a923d882bf6 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 28 Apr 2007 20:47:59 +0000 Subject: Buffer length fixes, by Wang Cheng Yeh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2736 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/scsi-disk.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index c6280fd55..92f745726 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -345,7 +345,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) DPRINTF("Request Sense (len %d)\n", len); if (len < 4) goto fail; - memset(buf, 0, 4); + memset(outbuf, 0, 4); outbuf[0] = 0xf0; outbuf[1] = 0; outbuf[2] = s->sense; @@ -371,7 +371,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) Some later commands are also implemented. */ outbuf[2] = 3; outbuf[3] = 2; /* Format 2 */ - outbuf[4] = 32; + outbuf[4] = 31; /* Sync data transfer and TCQ. */ outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0); r->buf_len = 36; @@ -404,10 +404,11 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) p += 4; if ((page == 8 || page == 0x3f)) { /* Caching page. */ + memset(p,0,20); p[0] = 8; p[1] = 0x12; p[2] = 4; /* WCE */ - p += 19; + p += 20; } if ((page == 0x3f || page == 0x2a) && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) { @@ -437,7 +438,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) p[19] = (16 * 176) & 0xff; p[20] = (16 * 176) >> 8; // 16x write speed current p[21] = (16 * 176) & 0xff; - p += 21; + p += 22; } r->buf_len = p - outbuf; outbuf[0] = r->buf_len - 4; -- cgit v1.2.3 From 931f03ee60ea341ee67ded1f0e269bc4c2420940 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 28 Apr 2007 20:49:36 +0000 Subject: Fix typo, by Linus Nordberg. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2737 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index bf3aaca58..3691f38fd 100644 --- a/vl.c +++ b/vl.c @@ -3922,7 +3922,7 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, int so_type=-1, optlen=sizeof(so_type); if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, &optlen)< 0) { - fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd); + fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd); return NULL; } switch(so_type) { -- cgit v1.2.3 From 1c32f43eeaf829774958325f7c50078f7077e614 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 28 Apr 2007 21:07:41 +0000 Subject: Switch default CPU to 24Kf for now, as the Linux FPU emulation in the current qemu mips emulation fails in some cases. (The Linux FPU emulation works on real FPU-less hardware.) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2738 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 2 +- hw/mips_pica61.c | 3 ++- hw/mips_r4k.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 3a115032b..42627e82a 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -721,7 +721,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, #ifdef TARGET_MIPS64 cpu_model = "R4000"; #else - cpu_model = "4KEc"; + cpu_model = "24Kf"; #endif } if (mips_find_by_name(cpu_model, &def) != 0) diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 8e1058a79..3f2a937e8 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -73,7 +73,8 @@ void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device, #ifdef TARGET_MIPS64 cpu_model = "R4000"; #else - cpu_model = "4KEc"; + /* FIXME: All wrong, this maybe should be R3000 for the older PICAs. */ + cpu_model = "24Kf"; #endif } if (mips_find_by_name(cpu_model, &def) != 0) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index f6af322fd..72e9ac8a6 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -154,7 +154,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, #ifdef TARGET_MIPS64 cpu_model = "R4000"; #else - cpu_model = "4KEc"; + cpu_model = "24Kf"; #endif } if (mips_find_by_name(cpu_model, &def) != 0) -- cgit v1.2.3 From 509b8ab2cc082759ac06a5c0fb5e6012022b17cb Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 28 Apr 2007 21:44:04 +0000 Subject: Update TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2739 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-mips/TODO b/target-mips/TODO index c92cbaf97..defe49112 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -6,6 +6,11 @@ General - [ls][dw][lr] report broken (aligned) BadVAddr - Missing per-CPU instruction decoding, currently all implemented instructions are regarded as valid +- Applications running on top of a emulated Linux segfault sometimes + when the Qemu FPU emulation is disabled. This is apparently a qemu + bug triggered by the Linux in-kernel FPU emulator. +- The Timesys Linux installer shell hangs for e.g. "read foo". Likewise, + telnet'ting in the installer fails and hangs the telnetd. MIPS64 ------ @@ -17,6 +22,10 @@ MIPS64 ------------------------------ - Doesn't correspond to any real hardware. +PICA 61 system emulation +------------------------ +- No framebuffer support yet. + MALTA system emulation ---------------------- - We fake firmware support instead of doing the real thing -- cgit v1.2.3 From 2abec30bcf132b4f9e5911c4155e2a32a33665e9 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 29 Apr 2007 01:47:26 +0000 Subject: Memory-mapped interface for VGA, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2740 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_pica61.c | 5 ++- hw/vga.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/vga_int.h | 2 ++ vl.h | 4 +++ 4 files changed, 109 insertions(+), 1 deletion(-) diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 3f2a937e8..40ea8b5a6 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -166,7 +166,10 @@ void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device, ds1225y_init(0x80009000, "nvram"); /* Video card */ - //isa_vga_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); + /* FIXME: This card is not the real one which was in the original PICA, + * but let's do with what Qemu currenly emulates... */ + isa_vga_mm_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size, + 0x40000000, 0x60000000, 0); } QEMUMachine mips_pica61_machine = { diff --git a/hw/vga.c b/hw/vga.c index 2dadcca5b..3032ccfb5 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1845,6 +1845,81 @@ void vga_init(VGAState *s) vga_io_memory); } +/* Memory mapped interface */ +static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr) +{ + VGAState *s = opaque; + + return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xff; +} + +static void vga_mm_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + VGAState *s = opaque; + + vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xff); +} + +static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr) +{ + VGAState *s = opaque; + + return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xffff; +} + +static void vga_mm_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + VGAState *s = opaque; + + vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xffff); +} + +static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr) +{ + VGAState *s = opaque; + + return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift); +} + +static void vga_mm_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + VGAState *s = opaque; + + vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value); +} + +static CPUReadMemoryFunc *vga_mm_read_ctrl[] = { + &vga_mm_readb, + &vga_mm_readw, + &vga_mm_readl, +}; + +static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = { + &vga_mm_writeb, + &vga_mm_writew, + &vga_mm_writel, +}; + +static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base, + target_phys_addr_t ctrl_base, int it_shift) +{ + int s_ioport_ctrl, vga_io_memory; + + s->base_ctrl = ctrl_base; + s->it_shift = it_shift; + s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s); + vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); + + register_savevm("vga", 0, 2, vga_save, vga_load, s); + + cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl); + s->bank_offset = 0; + cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory); +} + int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { @@ -1867,6 +1942,30 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, return 0; } +int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size, + target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, + int it_shift) +{ + VGAState *s; + + s = qemu_mallocz(sizeof(VGAState)); + if (!s) + return -1; + + vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); + vga_mm_init(s, vram_base, ctrl_base, it_shift); + + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); + +#ifdef CONFIG_BOCHS_VBE + /* XXX: use optimized standard vga accesses */ + cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, + vga_ram_size, vga_ram_offset); +#endif + return 0; +} + int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size, unsigned long vga_bios_offset, int vga_bios_size) diff --git a/hw/vga_int.h b/hw/vga_int.h index e7df0f72b..7b1624743 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -85,6 +85,8 @@ unsigned int vram_size; \ unsigned long bios_offset; \ unsigned int bios_size; \ + target_phys_addr_t base_ctrl; \ + int it_shift; \ PCIDevice *pci_dev; \ uint32_t latch; \ uint8_t sr_index; \ diff --git a/vl.h b/vl.h index 0046b4353..0ea199a9c 100644 --- a/vl.h +++ b/vl.h @@ -931,6 +931,10 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size, unsigned long vga_bios_offset, int vga_bios_size); +int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size, + target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, + int it_shift); /* cirrus_vga.c */ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, -- cgit v1.2.3 From cf2d385c43b4387bec5a546c9b85ac654273cfa3 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 29 Apr 2007 01:53:20 +0000 Subject: Crop VNC update requests to avoid segfaults, by Thomas Tuttle. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2741 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vnc.c b/vnc.c index aba60d4c2..70d30d9d8 100644 --- a/vnc.c +++ b/vnc.c @@ -852,6 +852,15 @@ static void framebuffer_update_request(VncState *vs, int incremental, int x_position, int y_position, int w, int h) { + if (x_position > vs->ds->width) + x_position = vs->ds->width; + if (y_position > vs->ds->height) + y_position = vs->ds->height; + if (x_position + w >= vs->ds->width) + w = vs->ds->width - x_position; + if (y_position + h >= vs->ds->height) + h = vs->ds->height - y_position; + int i; vs->need_update = 1; if (!incremental) { -- cgit v1.2.3 From c73c3aa081cae0e565b8669ad7fba192749f8397 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 29 Apr 2007 19:06:34 +0000 Subject: Fix ARM fine pagetables. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2742 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 111b84652..bae4c9fdb 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -372,7 +372,13 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, code = 13; } else { /* Lookup l2 entry. */ - table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + if (type == 1) { + /* Coarse pagetable. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + } else { + /* Fine pagetable. */ + table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); + } desc = ldl_phys(table); switch (desc & 3) { case 0: /* Page translation fault. */ -- cgit v1.2.3 From 32af58f95f7b4e855f0369b25b46cbbbae69ae6c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 29 Apr 2007 19:49:15 +0000 Subject: Fix CPU type zapped by system_reset git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2743 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 0812e95a3..645b41422 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3301,7 +3301,6 @@ extern int ram_size; void cpu_reset(CPUSPARCState *env) { - memset(env, 0, sizeof(*env)); tlb_flush(env, 1); env->cwp = 0; env->wim = 1; @@ -3313,14 +3312,15 @@ void cpu_reset(CPUSPARCState *env) env->cansave = NWINDOWS - 1; #endif #else + env->psret = 0; env->psrs = 1; env->psrps = 1; - env->gregs[1] = ram_size; #ifdef TARGET_SPARC64 env->pstate = PS_PRIV; env->pc = 0x1fff0000000ULL; #else env->pc = 0xffd00000; + env->mmuregs[0] &= ~(MMU_E | MMU_NF); #endif env->npc = env->pc + 4; #endif -- cgit v1.2.3 From 5ef62c5c4224afdce2f98fb2c3b43f734ab47f72 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 29 Apr 2007 19:54:32 +0000 Subject: More Sparc32 CPUs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2744 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 645b41422..4b8b3d261 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3355,11 +3355,28 @@ static const sparc_def_t sparc_defs[] = { .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */ }, { - /* XXX: Replace with real values */ + .name = "Fujitsu MB86907", + .iu_version = 0x05 << 24, /* Impl 0, ver 5 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */ + }, + { + .name = "TI MicroSparc I", + .iu_version = 0x41000000, + .fpu_version = 4 << 17, + .mmu_version = 0x41000000, + }, + { .name = "TI SuperSparc II", .iu_version = 0x40000000, - .fpu_version = 0x00000000, - .mmu_version = 0x00000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + }, + { + .name = "Ross RT620", + .iu_version = 0x1e000000, + .fpu_version = 1 << 17, + .mmu_version = 0x17000000, }, #endif }; -- cgit v1.2.3 From bc8191fce98cf4faa6440baab0a223912809f9e3 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 29 Apr 2007 20:13:19 +0000 Subject: Hopefully the final fix for LUI sign extensions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2745 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 04677cd84..71e30d3ef 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -54,7 +54,7 @@ void glue(op_load_gpr_T2_gpr, REG) (void) #define SET_RESET(treg, tregname) \ void glue(op_set, tregname)(void) \ { \ - treg = (int32_t)PARAM1; \ + treg = (int32_t)(uint32_t)PARAM1;\ RETURN(); \ } \ void glue(op_reset, tregname)(void) \ -- cgit v1.2.3 From c631c88ceed80daa012cbe6509e4de2e4e24ec11 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 29 Apr 2007 21:19:03 +0000 Subject: Revert last checkin. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2746 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_template.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 71e30d3ef..04677cd84 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -54,7 +54,7 @@ void glue(op_load_gpr_T2_gpr, REG) (void) #define SET_RESET(treg, tregname) \ void glue(op_set, tregname)(void) \ { \ - treg = (int32_t)(uint32_t)PARAM1;\ + treg = (int32_t)PARAM1; \ RETURN(); \ } \ void glue(op_reset, tregname)(void) \ -- cgit v1.2.3 From 01179c382ba7bf8d5b063ca6afaa57c33f813287 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 29 Apr 2007 21:26:37 +0000 Subject: Kill broken host register definitions, thanks to Paul Brook and Herve Poussineau for debugging this. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2747 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 15 ++++----------- target-mips/mips-defs.h | 2 -- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index cfe69a3ff..b00263f1b 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -6,25 +6,18 @@ #include "config.h" #include "mips-defs.h" #include "dyngen-exec.h" +#include "cpu-defs.h" register struct CPUMIPSState *env asm(AREG0); -#if defined (USE_64BITS_REGS) -typedef int64_t host_int_t; -typedef uint64_t host_uint_t; -#else -typedef int32_t host_int_t; -typedef uint32_t host_uint_t; -#endif - #if TARGET_LONG_BITS > HOST_LONG_BITS #define T0 (env->t0) #define T1 (env->t1) #define T2 (env->t2) #else -register host_uint_t T0 asm(AREG1); -register host_uint_t T1 asm(AREG2); -register host_uint_t T2 asm(AREG3); +register target_ulong T0 asm(AREG1); +register target_ulong T1 asm(AREG2); +register target_ulong T2 asm(AREG3); #endif #if defined (USE_HOST_FLOAT_REGS) diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 95b5ef8f0..414f476db 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -1,8 +1,6 @@ #if !defined (__QEMU_MIPS_DEFS_H__) #define __QEMU_MIPS_DEFS_H__ -/* If we want to use 64 bits host regs... */ -//#define USE_64BITS_REGS /* If we want to use host float regs... */ //#define USE_HOST_FLOAT_REGS -- cgit v1.2.3 From 201a51fc386c0a2b55b13ad99589b1dfd1f39a5d Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 00:51:09 +0000 Subject: PCMCIA bus support. Parts of CF-ATA command set. Hitachi DSCM microdrive emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2748 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 741 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- monitor.c | 2 + vl.c | 42 ++++ vl.h | 50 +++++ 4 files changed, 831 insertions(+), 4 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index ffee8dde9..1417e2898 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2,6 +2,7 @@ * QEMU IDE disk and CD-ROM Emulator * * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2006 Openedhand Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -131,6 +132,7 @@ #define WIN_SPECIFY 0x91 /* set drive geometry translation */ #define WIN_DOWNLOAD_MICROCODE 0x92 #define WIN_STANDBYNOW2 0x94 +#define CFA_IDLEIMMEDIATE 0x95 /* force drive to become "ready" */ #define WIN_STANDBY2 0x96 #define WIN_SETIDLE2 0x97 #define WIN_CHECKPOWERMODE2 0x98 @@ -142,7 +144,8 @@ #define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ #define WIN_QUEUED_SERVICE 0xA2 #define WIN_SMART 0xB0 /* self-monitoring and reporting */ -#define CFA_ERASE_SECTORS 0xC0 +#define CFA_ACCESS_METADATA_STORAGE 0xB8 +#define CFA_ERASE_SECTORS 0xC0 /* microdrives implement as NOP */ #define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ #define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ #define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ @@ -176,11 +179,13 @@ #define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ #define WIN_SETFEATURES 0xEF /* set special drive features */ #define EXABYTE_ENABLE_NEST 0xF0 +#define IBM_SENSE_CONDITION 0xF0 /* measure disk temperature */ #define WIN_SECURITY_SET_PASS 0xF1 #define WIN_SECURITY_UNLOCK 0xF2 #define WIN_SECURITY_ERASE_PREPARE 0xF3 #define WIN_SECURITY_ERASE_UNIT 0xF4 #define WIN_SECURITY_FREEZE_LOCK 0xF5 +#define CFA_WEAR_LEVEL 0xF5 /* microdrives implement as NOP */ #define WIN_SECURITY_DISABLE 0xF6 #define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ #define WIN_SET_MAX 0xF9 @@ -282,6 +287,12 @@ #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 +#define CFA_NO_ERROR 0x00 +#define CFA_MISC_ERROR 0x09 +#define CFA_INVALID_COMMAND 0x20 +#define CFA_INVALID_ADDRESS 0x21 +#define CFA_ADDRESS_OVERFLOW 0x2f + #define SENSE_NONE 0 #define SENSE_NOT_READY 2 #define SENSE_ILLEGAL_REQUEST 5 @@ -295,6 +306,7 @@ typedef void EndTransferFunc(struct IDEState *); typedef struct IDEState { /* ide config */ int is_cdrom; + int is_cf; int cylinders, heads, sectors; int64_t nb_sectors; int mult_sectors; @@ -347,6 +359,12 @@ typedef struct IDEState { uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; QEMUTimer *sector_write_timer; /* only used for win2k instal hack */ uint32_t irq_count; /* counts IRQs when using win2k install hack */ + /* CF-ATA extended error */ + uint8_t ext_error; + /* CF-ATA metadata storage */ + uint32_t mdata_size; + uint8_t *mdata_storage; + int media_changed; } IDEState; #define BM_STATUS_DMAING 0x01 @@ -542,6 +560,74 @@ static void ide_atapi_identify(IDEState *s) s->identify_set = 1; } +static void ide_cfata_identify(IDEState *s) +{ + uint16_t *p; + uint32_t cur_sec; + char buf[20]; + + p = (uint16_t *) s->identify_data; + if (s->identify_set) + goto fill_buffer; + + memset(p, 0, sizeof(s->identify_data)); + + cur_sec = s->cylinders * s->heads * s->sectors; + + put_le16(p + 0, 0x848a); /* CF Storage Card signature */ + put_le16(p + 1, s->cylinders); /* Default cylinders */ + put_le16(p + 3, s->heads); /* Default heads */ + put_le16(p + 6, s->sectors); /* Default sectors per track */ + put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */ + put_le16(p + 8, s->nb_sectors); /* Sectors per card */ + snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); + padstr((uint8_t *)(p + 10), buf, 20); /* Serial number in ASCII */ + put_le16(p + 22, 0x0004); /* ECC bytes */ + padstr((uint8_t *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */ + padstr((uint8_t *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */ +#if MAX_MULT_SECTORS > 1 + put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); +#else + put_le16(p + 47, 0x0000); +#endif + put_le16(p + 49, 0x0f00); /* Capabilities */ + put_le16(p + 51, 0x0002); /* PIO cycle timing mode */ + put_le16(p + 52, 0x0001); /* DMA cycle timing mode */ + put_le16(p + 53, 0x0003); /* Translation params valid */ + put_le16(p + 54, s->cylinders); /* Current cylinders */ + put_le16(p + 55, s->heads); /* Current heads */ + put_le16(p + 56, s->sectors); /* Current sectors */ + put_le16(p + 57, cur_sec); /* Current capacity */ + put_le16(p + 58, cur_sec >> 16); /* Current capacity */ + if (s->mult_sectors) /* Multiple sector setting */ + put_le16(p + 59, 0x100 | s->mult_sectors); + put_le16(p + 60, s->nb_sectors); /* Total LBA sectors */ + put_le16(p + 61, s->nb_sectors >> 16); /* Total LBA sectors */ + put_le16(p + 63, 0x0203); /* Multiword DMA capability */ + put_le16(p + 64, 0x0001); /* Flow Control PIO support */ + put_le16(p + 65, 0x0096); /* Min. Multiword DMA cycle */ + put_le16(p + 66, 0x0096); /* Rec. Multiword DMA cycle */ + put_le16(p + 68, 0x00b4); /* Min. PIO cycle time */ + put_le16(p + 82, 0x400c); /* Command Set supported */ + put_le16(p + 83, 0x7068); /* Command Set supported */ + put_le16(p + 84, 0x4000); /* Features supported */ + put_le16(p + 85, 0x000c); /* Command Set enabled */ + put_le16(p + 86, 0x7044); /* Command Set enabled */ + put_le16(p + 87, 0x4000); /* Features enabled */ + put_le16(p + 91, 0x4060); /* Current APM level */ + put_le16(p + 129, 0x0002); /* Current features option */ + put_le16(p + 130, 0x0005); /* Reassigned sectors */ + put_le16(p + 131, 0x0001); /* Initial power mode */ + put_le16(p + 132, 0x0000); /* User signature */ + put_le16(p + 160, 0x8100); /* Power requirement */ + put_le16(p + 161, 0x8001); /* CF command set */ + + s->identify_set = 1; + +fill_buffer: + memcpy(s->io_buffer, p, sizeof(s->identify_data)); +} + static void ide_set_signature(IDEState *s) { s->select &= 0xf0; /* clear head */ @@ -1496,6 +1582,59 @@ static void ide_atapi_cmd(IDEState *s) } } +static void ide_cfata_metadata_inquiry(IDEState *s) +{ + uint16_t *p; + uint32_t spd; + + p = (uint16_t *) s->io_buffer; + memset(p, 0, 0x200); + spd = ((s->mdata_size - 1) >> 9) + 1; + + put_le16(p + 0, 0x0001); /* Data format revision */ + put_le16(p + 1, 0x0000); /* Media property: silicon */ + put_le16(p + 2, s->media_changed); /* Media status */ + put_le16(p + 3, s->mdata_size & 0xffff); /* Capacity in bytes (low) */ + put_le16(p + 4, s->mdata_size >> 16); /* Capacity in bytes (high) */ + put_le16(p + 5, spd & 0xffff); /* Sectors per device (low) */ + put_le16(p + 6, spd >> 16); /* Sectors per device (high) */ +} + +static void ide_cfata_metadata_read(IDEState *s) +{ + uint16_t *p; + + if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) { + s->status = ERR_STAT; + s->error = ABRT_ERR; + return; + } + + p = (uint16_t *) s->io_buffer; + memset(p, 0, 0x200); + + put_le16(p + 0, s->media_changed); /* Media status */ + memcpy(p + 1, s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9), + MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9), + s->nsector << 9), 0x200 - 2)); +} + +static void ide_cfata_metadata_write(IDEState *s) +{ + if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) { + s->status = ERR_STAT; + s->error = ABRT_ERR; + return; + } + + s->media_changed = 0; + + memcpy(s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9), + s->io_buffer + 2, + MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9), + s->nsector << 9), 0x200 - 2)); +} + /* called when the inserted state of the media has changed */ static void cdrom_change_cb(void *opaque) { @@ -1611,7 +1750,10 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) switch(val) { case WIN_IDENTIFY: if (s->bs && !s->is_cdrom) { - ide_identify(s); + if (!s->is_cf) + ide_identify(s); + else + ide_cfata_identify(s); s->status = READY_STAT | SEEK_STAT; ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); } else { @@ -1629,7 +1771,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) ide_set_irq(s); break; case WIN_SETMULT: - if ((s->nsector & 0xff) != 0 && + if (s->is_cf && s->nsector == 0) { + /* Disable Read and Write Multiple */ + s->mult_sectors = 0; + s->status = READY_STAT; + } else if ((s->nsector & 0xff) != 0 && ((s->nsector & 0xff) > MAX_MULT_SECTORS || (s->nsector & (s->nsector - 1)) != 0)) { ide_abort_command(s); @@ -1662,11 +1808,14 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) lba48 = 1; case WIN_WRITE: case WIN_WRITE_ONCE: + case CFA_WRITE_SECT_WO_ERASE: + case WIN_WRITE_VERIFY: ide_cmd_lba48_transform(s, lba48); s->error = 0; s->status = SEEK_STAT | READY_STAT; s->req_nb_sectors = 1; ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); + s->media_changed = 1; break; case WIN_MULTREAD_EXT: lba48 = 1; @@ -1680,6 +1829,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case WIN_MULTWRITE_EXT: lba48 = 1; case WIN_MULTWRITE: + case CFA_WRITE_MULTI_WO_ERASE: if (!s->mult_sectors) goto abort_cmd; ide_cmd_lba48_transform(s, lba48); @@ -1690,6 +1840,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (n > s->req_nb_sectors) n = s->req_nb_sectors; ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); + s->media_changed = 1; break; case WIN_READDMA_EXT: lba48 = 1; @@ -1708,6 +1859,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) goto abort_cmd; ide_cmd_lba48_transform(s, lba48); ide_sector_write_dma(s); + s->media_changed = 1; break; case WIN_READ_NATIVE_MAX_EXT: lba48 = 1; @@ -1718,6 +1870,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) ide_set_irq(s); break; case WIN_CHECKPOWERMODE1: + case WIN_CHECKPOWERMODE2: s->nsector = 0xff; /* device active or idle */ s->status = READY_STAT; ide_set_irq(s); @@ -1733,6 +1886,12 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0x82: /* write cache disable */ case 0xaa: /* read look-ahead enable */ case 0x55: /* read look-ahead disable */ + case 0x05: /* set advanced power management mode */ + case 0x85: /* disable advanced power management mode */ + case 0x69: /* NOP */ + case 0x67: /* NOP */ + case 0x96: /* NOP */ + case 0x9a: /* NOP */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; @@ -1772,7 +1931,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) ide_set_irq(s); break; case WIN_STANDBYNOW1: + case WIN_STANDBYNOW2: case WIN_IDLEIMMEDIATE: + case CFA_IDLEIMMEDIATE: + case WIN_SETIDLE1: + case WIN_SETIDLE2: s->status = READY_STAT; ide_set_irq(s); break; @@ -1810,6 +1973,79 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, ide_atapi_cmd); break; + /* CF-ATA commands */ + case CFA_REQ_EXT_ERROR_CODE: + if (!s->is_cf) + goto abort_cmd; + s->error = 0x09; /* miscellaneous error */ + s->status = READY_STAT; + ide_set_irq(s); + break; + case CFA_ERASE_SECTORS: + case CFA_WEAR_LEVEL: + if (!s->is_cf) + goto abort_cmd; + if (val == CFA_WEAR_LEVEL) + s->nsector = 0; + if (val == CFA_ERASE_SECTORS) + s->media_changed = 1; + s->error = 0x00; + s->status = READY_STAT; + ide_set_irq(s); + break; + case CFA_TRANSLATE_SECTOR: + if (!s->is_cf) + goto abort_cmd; + s->error = 0x00; + s->status = READY_STAT; + memset(s->io_buffer, 0, 0x200); + s->io_buffer[0x00] = s->hcyl; /* Cyl MSB */ + s->io_buffer[0x01] = s->lcyl; /* Cyl LSB */ + s->io_buffer[0x02] = s->select; /* Head */ + s->io_buffer[0x03] = s->sector; /* Sector */ + s->io_buffer[0x04] = ide_get_sector(s) >> 16; /* LBA MSB */ + s->io_buffer[0x05] = ide_get_sector(s) >> 8; /* LBA */ + s->io_buffer[0x06] = ide_get_sector(s) >> 0; /* LBA LSB */ + s->io_buffer[0x13] = 0x00; /* Erase flag */ + s->io_buffer[0x18] = 0x00; /* Hot count */ + s->io_buffer[0x19] = 0x00; /* Hot count */ + s->io_buffer[0x1a] = 0x01; /* Hot count */ + ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); + ide_set_irq(s); + break; + case CFA_ACCESS_METADATA_STORAGE: + if (!s->is_cf) + goto abort_cmd; + switch (s->feature) { + case 0x02: /* Inquiry Metadata Storage */ + ide_cfata_metadata_inquiry(s); + break; + case 0x03: /* Read Metadata Storage */ + ide_cfata_metadata_read(s); + break; + case 0x04: /* Write Metadata Storage */ + ide_cfata_metadata_write(s); + break; + default: + goto abort_cmd; + } + ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop); + s->status = 0x00; /* NOTE: READY is _not_ set */ + ide_set_irq(s); + break; + case IBM_SENSE_CONDITION: + if (!s->is_cf) + goto abort_cmd; + switch (s->feature) { + case 0x01: /* sense temperature in device */ + s->nsector = 0x50; /* +20 C */ + break; + default: + goto abort_cmd; + } + s->status = READY_STAT; + ide_set_irq(s); + break; default: abort_cmd: ide_abort_command(s); @@ -2015,7 +2251,10 @@ static void ide_dummy_transfer_stop(IDEState *s) static void ide_reset(IDEState *s) { - s->mult_sectors = MAX_MULT_SECTORS; + if (s->is_cf) + s->mult_sectors = 0; + else + s->mult_sectors = MAX_MULT_SECTORS; s->cur_drive = s; s->select = 0xa0; s->status = READY_STAT; @@ -2024,6 +2263,7 @@ static void ide_reset(IDEState *s) accesses */ s->end_transfer_func = ide_dummy_transfer_stop; ide_dummy_transfer_stop(s); + s->media_changed = 0; } struct partition { @@ -2749,3 +2989,496 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq) pmac_ide_write, &ide_if[0]); return pmac_ide_memory; } + +/***********************************************************/ +/* CF-ATA Microdrive */ + +#define METADATA_SIZE 0x20 + +/* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface. */ +struct md_s { + IDEState ide[2]; + struct pcmcia_card_s card; + uint32_t attr_base; + uint32_t io_base; + + /* Card state */ + uint8_t opt; + uint8_t stat; + uint8_t pins; + + uint8_t ctrl; + uint16_t io; + int cycle; +}; + +/* Register bitfields */ +enum md_opt { + OPT_MODE_MMAP = 0, + OPT_MODE_IOMAP16 = 1, + OPT_MODE_IOMAP1 = 2, + OPT_MODE_IOMAP2 = 3, + OPT_MODE = 0x3f, + OPT_LEVIREQ = 0x40, + OPT_SRESET = 0x80, +}; +enum md_cstat { + STAT_INT = 0x02, + STAT_PWRDWN = 0x04, + STAT_XE = 0x10, + STAT_IOIS8 = 0x20, + STAT_SIGCHG = 0x40, + STAT_CHANGED = 0x80, +}; +enum md_pins { + PINS_MRDY = 0x02, + PINS_CRDY = 0x20, +}; +enum md_ctrl { + CTRL_IEN = 0x02, + CTRL_SRST = 0x04, +}; + +static inline void md_interrupt_update(struct md_s *s) +{ + if (!s->card.slot) + return; + + qemu_set_irq(s->card.slot->irq, + !(s->stat & STAT_INT) && /* Inverted */ + !(s->ctrl & (CTRL_IEN | CTRL_SRST)) && + !(s->opt & OPT_SRESET)); +} + +static void md_set_irq(void *opaque, int irq, int level) +{ + struct md_s *s = (struct md_s *) opaque; + if (level) + s->stat |= STAT_INT; + else + s->stat &= ~STAT_INT; + + md_interrupt_update(s); +} + +static void md_reset(struct md_s *s) +{ + s->opt = OPT_MODE_MMAP; + s->stat = 0; + s->pins = 0; + s->cycle = 0; + s->ctrl = 0; + ide_reset(s->ide); +} + +static uint8_t md_attr_read(void *opaque, uint16_t at) +{ + struct md_s *s = (struct md_s *) opaque; + if (at < s->attr_base) { + if (at < s->card.cis_len) + return s->card.cis[at]; + else + return 0x00; + } + + at -= s->attr_base; + + switch (at) { + case 0x00: /* Configuration Option Register */ + return s->opt; + case 0x02: /* Card Configuration Status Register */ + if (s->ctrl & CTRL_IEN) + return s->stat & ~STAT_INT; + else + return s->stat; + case 0x04: /* Pin Replacement Register */ + return (s->pins & PINS_CRDY) | 0x0c; + case 0x06: /* Socket and Copy Register */ + return 0x00; +#ifdef VERBOSE + default: + printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at); +#endif + } + + return 0; +} + +static void md_attr_write(void *opaque, uint16_t at, uint8_t value) +{ + struct md_s *s = (struct md_s *) opaque; + at -= s->attr_base; + + switch (at) { + case 0x00: /* Configuration Option Register */ + s->opt = value & 0xcf; + if (value & OPT_SRESET) + md_reset(s); + md_interrupt_update(s); + break; + case 0x02: /* Card Configuration Status Register */ + if ((s->stat ^ value) & STAT_PWRDWN) + s->pins |= PINS_CRDY; + s->stat &= 0x82; + s->stat |= value & 0x74; + md_interrupt_update(s); + /* Word 170 in Identify Device must be equal to STAT_XE */ + break; + case 0x04: /* Pin Replacement Register */ + s->pins &= PINS_CRDY; + s->pins |= value & PINS_MRDY; + break; + case 0x06: /* Socket and Copy Register */ + break; + default: + printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at); + } +} + +static uint16_t md_common_read(void *opaque, uint16_t at) +{ + struct md_s *s = (struct md_s *) opaque; + uint16_t ret; + at -= s->io_base; + + switch (s->opt & OPT_MODE) { + case OPT_MODE_MMAP: + if ((at & ~0x3ff) == 0x400) + at = 0; + break; + case OPT_MODE_IOMAP16: + at &= 0xf; + break; + case OPT_MODE_IOMAP1: + if ((at & ~0xf) == 0x3f0) + at -= 0x3e8; + else if ((at & ~0xf) == 0x1f0) + at -= 0x1f0; + break; + case OPT_MODE_IOMAP2: + if ((at & ~0xf) == 0x370) + at -= 0x368; + else if ((at & ~0xf) == 0x170) + at -= 0x170; + } + + switch (at) { + case 0x0: /* Even RD Data */ + case 0x8: + return ide_data_readw(s->ide, 0); + + /* TODO: 8-bit accesses */ + if (s->cycle) + ret = s->io >> 8; + else { + s->io = ide_data_readw(s->ide, 0); + ret = s->io & 0xff; + } + s->cycle = !s->cycle; + return ret; + case 0x9: /* Odd RD Data */ + return s->io >> 8; + case 0xd: /* Error */ + return ide_ioport_read(s->ide, 0x1); + case 0xe: /* Alternate Status */ + if (s->ide->cur_drive->bs) + return s->ide->cur_drive->status; + else + return 0; + case 0xf: /* Device Address */ + return 0xc2 | ((~s->ide->select << 2) & 0x3c); + default: + return ide_ioport_read(s->ide, at); + } + + return 0; +} + +static void md_common_write(void *opaque, uint16_t at, uint16_t value) +{ + struct md_s *s = (struct md_s *) opaque; + at -= s->io_base; + + switch (s->opt & OPT_MODE) { + case OPT_MODE_MMAP: + if ((at & ~0x3ff) == 0x400) + at = 0; + break; + case OPT_MODE_IOMAP16: + at &= 0xf; + break; + case OPT_MODE_IOMAP1: + if ((at & ~0xf) == 0x3f0) + at -= 0x3e8; + else if ((at & ~0xf) == 0x1f0) + at -= 0x1f0; + break; + case OPT_MODE_IOMAP2: + if ((at & ~0xf) == 0x370) + at -= 0x368; + else if ((at & ~0xf) == 0x170) + at -= 0x170; + } + + switch (at) { + case 0x0: /* Even WR Data */ + case 0x8: + ide_data_writew(s->ide, 0, value); + break; + + /* TODO: 8-bit accesses */ + if (s->cycle) + ide_data_writew(s->ide, 0, s->io | (value << 8)); + else + s->io = value & 0xff; + s->cycle = !s->cycle; + break; + case 0x9: + s->io = value & 0xff; + s->cycle = !s->cycle; + break; + case 0xd: /* Features */ + ide_ioport_write(s->ide, 0x1, value); + break; + case 0xe: /* Device Control */ + s->ctrl = value; + if (value & CTRL_SRST) + md_reset(s); + md_interrupt_update(s); + break; + default: + if (s->stat & STAT_PWRDWN) { + s->pins |= PINS_CRDY; + s->stat &= ~STAT_PWRDWN; + } + ide_ioport_write(s->ide, at, value); + } +} + +static const uint8_t dscm1xxxx_cis[0x14a] = { + [0x000] = CISTPL_DEVICE, /* 5V Device Information */ + [0x002] = 0x03, /* Tuple length = 4 bytes */ + [0x004] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */ + [0x006] = 0x01, /* Size = 2K bytes */ + [0x008] = CISTPL_ENDMARK, + + [0x00a] = CISTPL_DEVICE_OC, /* Additional Device Information */ + [0x00c] = 0x04, /* Tuple length = 4 byest */ + [0x00e] = 0x03, /* Conditions: Ext = 0, Vcc 3.3V, MWAIT = 1 */ + [0x010] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */ + [0x012] = 0x01, /* Size = 2K bytes */ + [0x014] = CISTPL_ENDMARK, + + [0x016] = CISTPL_JEDEC_C, /* JEDEC ID */ + [0x018] = 0x02, /* Tuple length = 2 bytes */ + [0x01a] = 0xdf, /* PC Card ATA with no Vpp required */ + [0x01c] = 0x01, + + [0x01e] = CISTPL_MANFID, /* Manufacture ID */ + [0x020] = 0x04, /* Tuple length = 4 bytes */ + [0x022] = 0xa4, /* TPLMID_MANF = 00a4 (IBM) */ + [0x024] = 0x00, + [0x026] = 0x00, /* PLMID_CARD = 0000 */ + [0x028] = 0x00, + + [0x02a] = CISTPL_VERS_1, /* Level 1 Version */ + [0x02c] = 0x12, /* Tuple length = 23 bytes */ + [0x02e] = 0x04, /* Major Version = JEIDA 4.2 / PCMCIA 2.1 */ + [0x030] = 0x01, /* Minor Version = 1 */ + [0x032] = 'I', + [0x034] = 'B', + [0x036] = 'M', + [0x038] = 0x00, + [0x03a] = 'm', + [0x03c] = 'i', + [0x03e] = 'c', + [0x040] = 'r', + [0x042] = 'o', + [0x044] = 'd', + [0x046] = 'r', + [0x048] = 'i', + [0x04a] = 'v', + [0x04c] = 'e', + [0x04e] = 0x00, + [0x050] = CISTPL_ENDMARK, + + [0x052] = CISTPL_FUNCID, /* Function ID */ + [0x054] = 0x02, /* Tuple length = 2 bytes */ + [0x056] = 0x04, /* TPLFID_FUNCTION = Fixed Disk */ + [0x058] = 0x01, /* TPLFID_SYSINIT: POST = 1, ROM = 0 */ + + [0x05a] = CISTPL_FUNCE, /* Function Extension */ + [0x05c] = 0x02, /* Tuple length = 2 bytes */ + [0x05e] = 0x01, /* TPLFE_TYPE = Disk Device Interface */ + [0x060] = 0x01, /* TPLFE_DATA = PC Card ATA Interface */ + + [0x062] = CISTPL_FUNCE, /* Function Extension */ + [0x064] = 0x03, /* Tuple length = 3 bytes */ + [0x066] = 0x02, /* TPLFE_TYPE = Basic PC Card ATA Interface */ + [0x068] = 0x08, /* TPLFE_DATA: Rotating, Unique, Single */ + [0x06a] = 0x0f, /* TPLFE_DATA: Sleep, Standby, Idle, Auto */ + + [0x06c] = CISTPL_CONFIG, /* Configuration */ + [0x06e] = 0x05, /* Tuple length = 5 bytes */ + [0x070] = 0x01, /* TPCC_RASZ = 2 bytes, TPCC_RMSZ = 1 byte */ + [0x072] = 0x07, /* TPCC_LAST = 7 */ + [0x074] = 0x00, /* TPCC_RADR = 0200 */ + [0x076] = 0x02, + [0x078] = 0x0f, /* TPCC_RMSK = 200, 202, 204, 206 */ + + [0x07a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */ + [0x07c] = 0x0b, /* Tuple length = 11 bytes */ + [0x07e] = 0xc0, /* TPCE_INDX = Memory Mode, Default, Iface */ + [0x080] = 0xc0, /* TPCE_IF = Memory, no BVDs, no WP, READY */ + [0x082] = 0xa1, /* TPCE_FS = Vcc only, no I/O, Memory, Misc */ + [0x084] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */ + [0x086] = 0x55, /* NomV: 5.0 V */ + [0x088] = 0x4d, /* MinV: 4.5 V */ + [0x08a] = 0x5d, /* MaxV: 5.5 V */ + [0x08c] = 0x4e, /* Peakl: 450 mA */ + [0x08e] = 0x08, /* TPCE_MS = 1 window, 1 byte, Host address */ + [0x090] = 0x00, /* Window descriptor: Window length = 0 */ + [0x092] = 0x20, /* TPCE_MI: support power down mode, RW */ + + [0x094] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */ + [0x096] = 0x06, /* Tuple length = 6 bytes */ + [0x098] = 0x00, /* TPCE_INDX = Memory Mode, no Default */ + [0x09a] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */ + [0x09c] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */ + [0x09e] = 0xb5, /* NomV: 3.3 V */ + [0x0a0] = 0x1e, + [0x0a2] = 0x3e, /* Peakl: 350 mA */ + + [0x0a4] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */ + [0x0a6] = 0x0d, /* Tuple length = 13 bytes */ + [0x0a8] = 0xc1, /* TPCE_INDX = I/O and Memory Mode, Default */ + [0x0aa] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */ + [0x0ac] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */ + [0x0ae] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */ + [0x0b0] = 0x55, /* NomV: 5.0 V */ + [0x0b2] = 0x4d, /* MinV: 4.5 V */ + [0x0b4] = 0x5d, /* MaxV: 5.5 V */ + [0x0b6] = 0x4e, /* Peakl: 450 mA */ + [0x0b8] = 0x64, /* TPCE_IO = 16-byte boundary, 16/8 accesses */ + [0x0ba] = 0xf0, /* TPCE_IR = MASK, Level, Pulse, Share */ + [0x0bc] = 0xff, /* IRQ0..IRQ7 supported */ + [0x0be] = 0xff, /* IRQ8..IRQ15 supported */ + [0x0c0] = 0x20, /* TPCE_MI = support power down mode */ + + [0x0c2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */ + [0x0c4] = 0x06, /* Tuple length = 6 bytes */ + [0x0c6] = 0x01, /* TPCE_INDX = I/O and Memory Mode */ + [0x0c8] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */ + [0x0ca] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */ + [0x0cc] = 0xb5, /* NomV: 3.3 V */ + [0x0ce] = 0x1e, + [0x0d0] = 0x3e, /* Peakl: 350 mA */ + + [0x0d2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */ + [0x0d4] = 0x12, /* Tuple length = 18 bytes */ + [0x0d6] = 0xc2, /* TPCE_INDX = I/O Primary Mode */ + [0x0d8] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */ + [0x0da] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */ + [0x0dc] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */ + [0x0de] = 0x55, /* NomV: 5.0 V */ + [0x0e0] = 0x4d, /* MinV: 4.5 V */ + [0x0e2] = 0x5d, /* MaxV: 5.5 V */ + [0x0e4] = 0x4e, /* Peakl: 450 mA */ + [0x0e6] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */ + [0x0e8] = 0x61, /* Range: 2 fields, 2 bytes addr, 1 byte len */ + [0x0ea] = 0xf0, /* Field 1 address = 0x01f0 */ + [0x0ec] = 0x01, + [0x0ee] = 0x07, /* Address block length = 8 */ + [0x0f0] = 0xf6, /* Field 2 address = 0x03f6 */ + [0x0f2] = 0x03, + [0x0f4] = 0x01, /* Address block length = 2 */ + [0x0f6] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */ + [0x0f8] = 0x20, /* TPCE_MI = support power down mode */ + + [0x0fa] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */ + [0x0fc] = 0x06, /* Tuple length = 6 bytes */ + [0x0fe] = 0x02, /* TPCE_INDX = I/O Primary Mode, no Default */ + [0x100] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */ + [0x102] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */ + [0x104] = 0xb5, /* NomV: 3.3 V */ + [0x106] = 0x1e, + [0x108] = 0x3e, /* Peakl: 350 mA */ + + [0x10a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */ + [0x10c] = 0x12, /* Tuple length = 18 bytes */ + [0x10e] = 0xc3, /* TPCE_INDX = I/O Secondary Mode, Default */ + [0x110] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */ + [0x112] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */ + [0x114] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */ + [0x116] = 0x55, /* NomV: 5.0 V */ + [0x118] = 0x4d, /* MinV: 4.5 V */ + [0x11a] = 0x5d, /* MaxV: 5.5 V */ + [0x11c] = 0x4e, /* Peakl: 450 mA */ + [0x11e] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */ + [0x120] = 0x61, /* Range: 2 fields, 2 byte addr, 1 byte len */ + [0x122] = 0x70, /* Field 1 address = 0x0170 */ + [0x124] = 0x01, + [0x126] = 0x07, /* Address block length = 8 */ + [0x128] = 0x76, /* Field 2 address = 0x0376 */ + [0x12a] = 0x03, + [0x12c] = 0x01, /* Address block length = 2 */ + [0x12e] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */ + [0x130] = 0x20, /* TPCE_MI = support power down mode */ + + [0x132] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */ + [0x134] = 0x06, /* Tuple length = 6 bytes */ + [0x136] = 0x03, /* TPCE_INDX = I/O Secondary Mode */ + [0x138] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */ + [0x13a] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */ + [0x13c] = 0xb5, /* NomV: 3.3 V */ + [0x13e] = 0x1e, + [0x140] = 0x3e, /* Peakl: 350 mA */ + + [0x142] = CISTPL_NO_LINK, /* No Link */ + [0x144] = 0x00, /* Tuple length = 0 bytes */ + + [0x146] = CISTPL_END, /* Tuple End */ +}; + +static int dscm1xxxx_attach(void *opaque) +{ + struct md_s *md = (struct md_s *) opaque; + md->card.attr_read = md_attr_read; + md->card.attr_write = md_attr_write; + md->card.common_read = md_common_read; + md->card.common_write = md_common_write; + md->card.io_read = md_common_read; + md->card.io_write = md_common_write; + + md->attr_base = md->card.cis[0x74] | (md->card.cis[0x76] << 8); + md->io_base = 0x0; + + md_reset(md); + md_interrupt_update(md); + + md->card.slot->card_string = "DSCM-1xxxx Hitachi Microdrive"; + return 0; +} + +static int dscm1xxxx_detach(void *opaque) +{ + struct md_s *md = (struct md_s *) opaque; + md_reset(md); + return 0; +} + +struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv) +{ + struct md_s *md = (struct md_s *) qemu_mallocz(sizeof(struct md_s)); + md->card.state = md; + md->card.attach = dscm1xxxx_attach; + md->card.detach = dscm1xxxx_detach; + md->card.cis = dscm1xxxx_cis; + md->card.cis_len = sizeof(dscm1xxxx_cis); + + ide_init2(md->ide, bdrv, 0, qemu_allocate_irqs(md_set_irq, md, 1)[0]); + md->ide->is_cf = 1; + md->ide->mdata_size = METADATA_SIZE; + md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE); + return &md->card; +} diff --git a/monitor.c b/monitor.c index 24c4dfb44..ed03b345e 100644 --- a/monitor.c +++ b/monitor.c @@ -1316,6 +1316,8 @@ static term_cmd_t info_cmds[] = { "", "show capture information" }, { "snapshots", "", do_info_snapshots, "", "show the currently saved VM snapshots" }, + { "pcmcia", "", pcmcia_info, + "", "show guest PCMCIA status" }, { "mice", "", do_info_mice, "", "show which guest mouse is receiving events" }, { "vnc", "", do_info_vnc, diff --git a/vl.c b/vl.c index 3691f38fd..8707a1f96 100644 --- a/vl.c +++ b/vl.c @@ -4411,6 +4411,48 @@ void usb_info(void) } } +/***********************************************************/ +/* PCMCIA/Cardbus */ + +static struct pcmcia_socket_entry_s { + struct pcmcia_socket_s *socket; + struct pcmcia_socket_entry_s *next; +} *pcmcia_sockets = 0; + +void pcmcia_socket_register(struct pcmcia_socket_s *socket) +{ + struct pcmcia_socket_entry_s *entry; + + entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s)); + entry->socket = socket; + entry->next = pcmcia_sockets; + pcmcia_sockets = entry; +} + +void pcmcia_socket_unregister(struct pcmcia_socket_s *socket) +{ + struct pcmcia_socket_entry_s *entry, **ptr; + + ptr = &pcmcia_sockets; + for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr) + if (entry->socket == socket) { + *ptr = entry->next; + qemu_free(entry); + } +} + +void pcmcia_info(void) +{ + struct pcmcia_socket_entry_s *iter; + if (!pcmcia_sockets) + term_printf("No PCMCIA sockets\n"); + + for (iter = pcmcia_sockets; iter; iter = iter->next) + term_printf("%s: %s\n", iter->socket->slot_string, + iter->socket->attached ? iter->socket->card_string : + "Empty"); +} + /***********************************************************/ /* dumb display */ diff --git a/vl.h b/vl.h index 0ea199a9c..09db43ef3 100644 --- a/vl.h +++ b/vl.h @@ -1475,6 +1475,56 @@ pflash_t *pflash_register (target_ulong base, ram_addr_t off, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); +/* PCMCIA/Cardbus */ + +struct pcmcia_socket_s { + qemu_irq irq; + int attached; + const char *slot_string; + const char *card_string; +}; + +void pcmcia_socket_register(struct pcmcia_socket_s *socket); +void pcmcia_socket_unregister(struct pcmcia_socket_s *socket); +void pcmcia_info(void); + +struct pcmcia_card_s { + void *state; + struct pcmcia_socket_s *slot; + int (*attach)(void *state); + int (*detach)(void *state); + const uint8_t *cis; + int cis_len; + + /* Only valid if attached */ + uint8_t (*attr_read)(void *state, uint16_t address); + void (*attr_write)(void *state, uint16_t address, uint8_t value); + uint16_t (*common_read)(void *state, uint16_t address); + void (*common_write)(void *state, uint16_t address, uint16_t value); + uint16_t (*io_read)(void *state, uint16_t address); + void (*io_write)(void *state, uint16_t address, uint16_t value); +}; + +#define CISTPL_DEVICE 0x01 /* 5V Device Information Tuple */ +#define CISTPL_NO_LINK 0x14 /* No Link Tuple */ +#define CISTPL_VERS_1 0x15 /* Level 1 Version Tuple */ +#define CISTPL_JEDEC_C 0x18 /* JEDEC ID Tuple */ +#define CISTPL_JEDEC_A 0x19 /* JEDEC ID Tuple */ +#define CISTPL_CONFIG 0x1a /* Configuration Tuple */ +#define CISTPL_CFTABLE_ENTRY 0x1b /* 16-bit PCCard Configuration */ +#define CISTPL_DEVICE_OC 0x1c /* Additional Device Information */ +#define CISTPL_DEVICE_OA 0x1d /* Additional Device Information */ +#define CISTPL_DEVICE_GEO 0x1e /* Additional Device Information */ +#define CISTPL_DEVICE_GEO_A 0x1f /* Additional Device Information */ +#define CISTPL_MANFID 0x20 /* Manufacture ID Tuple */ +#define CISTPL_FUNCID 0x21 /* Function ID Tuple */ +#define CISTPL_FUNCE 0x22 /* Function Extension Tuple */ +#define CISTPL_END 0xff /* Tuple End */ +#define CISTPL_ENDMARK 0xff + +/* dscm1xxxx.c */ +struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv); + #include "gdbstub.h" #endif /* defined(QEMU_TOOL) */ -- cgit v1.2.3 From c1713132e07955819477a87a0ce830358e77a147 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 01:26:42 +0000 Subject: Core features of ARM XScale processors. Main PXA270 and PXA255 peripherals. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2749 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa.h | 176 +++++ hw/pxa2xx.c | 1673 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/pxa2xx_dma.c | 496 ++++++++++++++ hw/pxa2xx_gpio.c | 290 +++++++++ hw/pxa2xx_pic.c | 280 ++++++++ target-arm/cpu.h | 38 +- target-arm/exec.h | 2 + target-arm/helper.c | 135 +++- target-arm/op.c | 14 +- target-arm/translate.c | 37 ++ vl.h | 2 + 11 files changed, 3127 insertions(+), 16 deletions(-) create mode 100644 hw/pxa.h create mode 100644 hw/pxa2xx.c create mode 100644 hw/pxa2xx_dma.c create mode 100644 hw/pxa2xx_gpio.c create mode 100644 hw/pxa2xx_pic.c diff --git a/hw/pxa.h b/hw/pxa.h new file mode 100644 index 000000000..8a4ffa8c4 --- /dev/null +++ b/hw/pxa.h @@ -0,0 +1,176 @@ +/* + * Intel XScale PXA255/270 processor support. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licenced under the GPL. + */ +#ifndef PXA_H +# define PXA_H "pxa.h" + +/* Interrupt numbers */ +# define PXA2XX_PIC_SSP3 0 +# define PXA2XX_PIC_USBH2 2 +# define PXA2XX_PIC_USBH1 3 +# define PXA2XX_PIC_PWRI2C 6 +# define PXA25X_PIC_HWUART 7 +# define PXA27X_PIC_OST_4_11 7 +# define PXA2XX_PIC_GPIO_0 8 +# define PXA2XX_PIC_GPIO_1 9 +# define PXA2XX_PIC_GPIO_X 10 +# define PXA2XX_PIC_I2S 13 +# define PXA26X_PIC_ASSP 15 +# define PXA25X_PIC_NSSP 16 +# define PXA27X_PIC_SSP2 16 +# define PXA2XX_PIC_LCD 17 +# define PXA2XX_PIC_I2C 18 +# define PXA2XX_PIC_ICP 19 +# define PXA2XX_PIC_STUART 20 +# define PXA2XX_PIC_BTUART 21 +# define PXA2XX_PIC_FFUART 22 +# define PXA2XX_PIC_MMC 23 +# define PXA2XX_PIC_SSP 24 +# define PXA2XX_PIC_DMA 25 +# define PXA2XX_PIC_OST_0 26 +# define PXA2XX_PIC_RTC1HZ 30 +# define PXA2XX_PIC_RTCALARM 31 + +/* DMA requests */ +# define PXA2XX_RX_RQ_I2S 2 +# define PXA2XX_TX_RQ_I2S 3 +# define PXA2XX_RX_RQ_BTUART 4 +# define PXA2XX_TX_RQ_BTUART 5 +# define PXA2XX_RX_RQ_FFUART 6 +# define PXA2XX_TX_RQ_FFUART 7 +# define PXA2XX_RX_RQ_SSP1 13 +# define PXA2XX_TX_RQ_SSP1 14 +# define PXA2XX_RX_RQ_SSP2 15 +# define PXA2XX_TX_RQ_SSP2 16 +# define PXA2XX_RX_RQ_ICP 17 +# define PXA2XX_TX_RQ_ICP 18 +# define PXA2XX_RX_RQ_STUART 19 +# define PXA2XX_TX_RQ_STUART 20 +# define PXA2XX_RX_RQ_MMCI 21 +# define PXA2XX_TX_RQ_MMCI 22 +# define PXA2XX_USB_RQ(x) ((x) + 24) +# define PXA2XX_RX_RQ_SSP3 66 +# define PXA2XX_TX_RQ_SSP3 67 + +# define PXA2XX_RAM_BASE 0xa0000000 + +/* pxa2xx_pic.c */ +struct pxa2xx_pic_state_s; +qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env); + +/* pxa2xx_gpio.c */ +struct pxa2xx_gpio_info_s; +struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, + CPUState *env, qemu_irq *pic, int lines); +void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level); +void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line, + gpio_handler_t handler, void *opaque); +void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, + void (*handler)(void *opaque), void *opaque); + +/* pxa2xx_dma.c */ +struct pxa2xx_dma_state_s; +struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base, + qemu_irq irq); +struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base, + qemu_irq irq); +void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on); + +/* pxa2xx.c */ +struct pxa2xx_ssp_s; +void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, + uint32_t (*readfn)(void *opaque), + void (*writefn)(void *opaque, uint32_t value), void *opaque); + +struct pxa2xx_i2s_s; +struct pxa2xx_fir_s; + +struct pxa2xx_state_s { + CPUState *env; + qemu_irq *pic; + struct pxa2xx_dma_state_s *dma; + struct pxa2xx_gpio_info_s *gpio; + struct pxa2xx_ssp_s **ssp; + struct pxa2xx_i2s_s *i2s; + struct pxa2xx_fir_s *fir; + + /* Power management */ + target_phys_addr_t pm_base; + uint32_t pm_regs[0x40]; + + /* Clock management */ + target_phys_addr_t cm_base; + uint32_t cm_regs[4]; + uint32_t clkcfg; + + /* Memory management */ + target_phys_addr_t mm_base; + uint32_t mm_regs[0x1a]; + + /* Performance monitoring */ + uint32_t pmnc; + + /* Real-Time clock */ + target_phys_addr_t rtc_base; + uint32_t rttr; + uint32_t rtsr; + uint32_t rtar; + uint32_t rdar1; + uint32_t rdar2; + uint32_t ryar1; + uint32_t ryar2; + uint32_t swar1; + uint32_t swar2; + uint32_t piar; + uint32_t last_rcnr; + uint32_t last_rdcr; + uint32_t last_rycr; + uint32_t last_swcr; + uint32_t last_rtcpicr; + int64_t last_hz; + int64_t last_sw; + int64_t last_pi; + QEMUTimer *rtc_hz; + QEMUTimer *rtc_rdal1; + QEMUTimer *rtc_rdal2; + QEMUTimer *rtc_swal1; + QEMUTimer *rtc_swal2; + QEMUTimer *rtc_pi; +}; + +struct pxa2xx_i2s_s { + target_phys_addr_t base; + qemu_irq irq; + struct pxa2xx_dma_state_s *dma; + void (*data_req)(void *, int, int); + + uint32_t control[2]; + uint32_t status; + uint32_t mask; + uint32_t clk; + + int enable; + int rx_len; + int tx_len; + void (*codec_out)(void *, uint32_t); + uint32_t (*codec_in)(void *); + void *opaque; + + int fifo_len; + uint32_t fifo[16]; +}; + +# define PA_FMT "0x%08lx" +# define REG_FMT "0x%lx" + +struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision); +struct pxa2xx_state_s *pxa255_init(DisplayState *ds); + +void pxa2xx_reset(int line, int level, void *opaque); + +#endif /* PXA_H */ diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c new file mode 100644 index 000000000..f9d2925bf --- /dev/null +++ b/hw/pxa2xx.c @@ -0,0 +1,1673 @@ +/* + * Intel XScale PXA255/270 processor support. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licenced under the GPL. + */ + +# include "vl.h" + +static struct { + target_phys_addr_t io_base; + int irqn; +} pxa255_serial[] = { + { 0x40100000, PXA2XX_PIC_FFUART }, + { 0x40200000, PXA2XX_PIC_BTUART }, + { 0x40700000, PXA2XX_PIC_STUART }, + { 0x41600000, PXA25X_PIC_HWUART }, + { 0, 0 } +}, pxa270_serial[] = { + { 0x40100000, PXA2XX_PIC_FFUART }, + { 0x40200000, PXA2XX_PIC_BTUART }, + { 0x40700000, PXA2XX_PIC_STUART }, + { 0, 0 } +}; + +static struct { + target_phys_addr_t io_base; + int irqn; +} pxa250_ssp[] = { + { 0x41000000, PXA2XX_PIC_SSP }, + { 0, 0 } +}, pxa255_ssp[] = { + { 0x41000000, PXA2XX_PIC_SSP }, + { 0x41400000, PXA25X_PIC_NSSP }, + { 0, 0 } +}, pxa26x_ssp[] = { + { 0x41000000, PXA2XX_PIC_SSP }, + { 0x41400000, PXA25X_PIC_NSSP }, + { 0x41500000, PXA26X_PIC_ASSP }, + { 0, 0 } +}, pxa27x_ssp[] = { + { 0x41000000, PXA2XX_PIC_SSP }, + { 0x41700000, PXA27X_PIC_SSP2 }, + { 0x41900000, PXA2XX_PIC_SSP3 }, + { 0, 0 } +}; + +#define PMCR 0x00 /* Power Manager Control register */ +#define PSSR 0x04 /* Power Manager Sleep Status register */ +#define PSPR 0x08 /* Power Manager Scratch-Pad register */ +#define PWER 0x0c /* Power Manager Wake-Up Enable register */ +#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */ +#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */ +#define PEDR 0x18 /* Power Manager Edge-Detect Status register */ +#define PCFR 0x1c /* Power Manager General Configuration register */ +#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */ +#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */ +#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */ +#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */ +#define RCSR 0x30 /* Reset Controller Status register */ +#define PSLR 0x34 /* Power Manager Sleep Configuration register */ +#define PTSR 0x38 /* Power Manager Standby Configuration register */ +#define PVCR 0x40 /* Power Manager Voltage Change Control register */ +#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */ +#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */ +#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */ +#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */ +#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */ + +static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + addr -= s->pm_base; + + switch (addr) { + case PMCR ... PCMD31: + if (addr & 3) + goto fail; + + return s->pm_regs[addr >> 2]; + default: + fail: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + addr -= s->pm_base; + + switch (addr) { + case PMCR: + s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a); + s->pm_regs[addr >> 2] |= value & 0x15; + break; + + case PSSR: /* Read-clean registers */ + case RCSR: + case PKSR: + s->pm_regs[addr >> 2] &= ~value; + break; + + default: /* Read-write registers */ + if (addr >= PMCR && addr <= PCMD31 && !(addr & 3)) { + s->pm_regs[addr >> 2] = value; + break; + } + + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } +} + +static CPUReadMemoryFunc *pxa2xx_pm_readfn[] = { + pxa2xx_pm_read, + pxa2xx_pm_read, + pxa2xx_pm_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_pm_writefn[] = { + pxa2xx_pm_write, + pxa2xx_pm_write, + pxa2xx_pm_write, +}; + +#define CCCR 0x00 /* Core Clock Configuration register */ +#define CKEN 0x04 /* Clock Enable register */ +#define OSCC 0x08 /* Oscillator Configuration register */ +#define CCSR 0x0c /* Core Clock Status register */ + +static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + addr -= s->cm_base; + + switch (addr) { + case CCCR: + case CKEN: + case OSCC: + return s->cm_regs[addr >> 2]; + + case CCSR: + return s->cm_regs[CCCR >> 2] | (3 << 28); + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + addr -= s->cm_base; + + switch (addr) { + case CCCR: + case CKEN: + s->cm_regs[addr >> 2] = value; + break; + + case OSCC: + s->cm_regs[addr >> 2] &= ~0x6e; + s->cm_regs[addr >> 2] |= value & 0x6e; + break; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } +} + +static CPUReadMemoryFunc *pxa2xx_cm_readfn[] = { + pxa2xx_cm_read, + pxa2xx_cm_read, + pxa2xx_cm_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_cm_writefn[] = { + pxa2xx_cm_write, + pxa2xx_cm_write, + pxa2xx_cm_write, +}; + +static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + + switch (reg) { + case 6: /* Clock Configuration register */ + return s->clkcfg; + + case 7: /* Power Mode register */ + return 0; + + default: + printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); + break; + } + return 0; +} + +static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, + uint32_t value) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + static const char *pwrmode[8] = { + "Normal", "Idle", "Deep-idle", "Standby", + "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep", + }; + + switch (reg) { + case 6: /* Clock Configuration register */ + s->clkcfg = value & 0xf; + if (value & 2) + printf("%s: CPU frequency change attempt\n", __FUNCTION__); + break; + + case 7: /* Power Mode register */ + if (value & 8) + printf("%s: CPU voltage change attempt\n", __FUNCTION__); + switch (value & 7) { + case 0: + /* Do nothing */ + break; + + case 1: + /* Idle */ + if (!(s->cm_regs[CCCR] & (1 << 31))) { /* CPDIS */ + cpu_interrupt(s->env, CPU_INTERRUPT_HALT); + break; + } + /* Fall through. */ + + case 2: + /* Deep-Idle */ + cpu_interrupt(s->env, CPU_INTERRUPT_HALT); + s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ + goto message; + + case 3: + cpu_reset(s->env); + s->env->cp15.c1_sys = 0; + s->env->cp15.c1_coproc = 0; + s->env->cp15.c2 = 0; + s->env->cp15.c3 = 0; + s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ + s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ + + /* + * The scratch-pad register is almost universally used + * for storing the return address on suspend. For the + * lack of a resuming bootloader, perform a jump + * directly to that address. + */ + memset(s->env->regs, 0, 4 * 15); + s->env->regs[15] = s->pm_regs[PSPR >> 2]; + +#if 0 + buffer = 0xe59ff000; /* ldr pc, [pc, #0] */ + cpu_physical_memory_write(0, &buffer, 4); + buffer = s->pm_regs[PSPR >> 2]; + cpu_physical_memory_write(8, &buffer, 4); +#endif + + /* Suspend */ + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); + + goto message; + + default: + message: + printf("%s: machine entered %s mode\n", __FUNCTION__, + pwrmode[value & 7]); + } + break; + + default: + printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); + break; + } +} + +/* Performace Monitoring Registers */ +#define CPPMNC 0 /* Performance Monitor Control register */ +#define CPCCNT 1 /* Clock Counter register */ +#define CPINTEN 4 /* Interrupt Enable register */ +#define CPFLAG 5 /* Overflow Flag register */ +#define CPEVTSEL 8 /* Event Selection register */ + +#define CPPMN0 0 /* Performance Count register 0 */ +#define CPPMN1 1 /* Performance Count register 1 */ +#define CPPMN2 2 /* Performance Count register 2 */ +#define CPPMN3 3 /* Performance Count register 3 */ + +static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + + switch (reg) { + case CPPMNC: + return s->pmnc; + case CPCCNT: + if (s->pmnc & 1) + return qemu_get_clock(vm_clock); + else + return 0; + case CPINTEN: + case CPFLAG: + case CPEVTSEL: + return 0; + + default: + printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); + break; + } + return 0; +} + +static void pxa2xx_perf_write(void *opaque, int op2, int reg, int crm, + uint32_t value) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + + switch (reg) { + case CPPMNC: + s->pmnc = value; + break; + + case CPCCNT: + case CPINTEN: + case CPFLAG: + case CPEVTSEL: + break; + + default: + printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); + break; + } +} + +static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm) +{ + switch (crm) { + case 0: + return pxa2xx_clkpwr_read(opaque, op2, reg, crm); + case 1: + return pxa2xx_perf_read(opaque, op2, reg, crm); + case 2: + switch (reg) { + case CPPMN0: + case CPPMN1: + case CPPMN2: + case CPPMN3: + return 0; + } + /* Fall through */ + default: + printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); + break; + } + return 0; +} + +static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm, + uint32_t value) +{ + switch (crm) { + case 0: + pxa2xx_clkpwr_write(opaque, op2, reg, crm, value); + break; + case 1: + pxa2xx_perf_write(opaque, op2, reg, crm, value); + break; + case 2: + switch (reg) { + case CPPMN0: + case CPPMN1: + case CPPMN2: + case CPPMN3: + return; + } + /* Fall through */ + default: + printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); + break; + } +} + +#define MDCNFG 0x00 /* SDRAM Configuration register */ +#define MDREFR 0x04 /* SDRAM Refresh Control register */ +#define MSC0 0x08 /* Static Memory Control register 0 */ +#define MSC1 0x0c /* Static Memory Control register 1 */ +#define MSC2 0x10 /* Static Memory Control register 2 */ +#define MECR 0x14 /* Expansion Memory Bus Config register */ +#define SXCNFG 0x1c /* Synchronous Static Memory Config register */ +#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */ +#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */ +#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */ +#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */ +#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */ +#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */ +#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */ +#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */ +#define ARB_CNTL 0x48 /* Arbiter Control register */ +#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */ +#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */ +#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */ +#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */ +#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */ +#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */ +#define SA1110 0x64 /* SA-1110 Memory Compatibility register */ + +static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + addr -= s->mm_base; + + switch (addr) { + case MDCNFG ... SA1110: + if ((addr & 3) == 0) + return s->mm_regs[addr >> 2]; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + addr -= s->mm_base; + + switch (addr) { + case MDCNFG ... SA1110: + if ((addr & 3) == 0) { + s->mm_regs[addr >> 2] = value; + break; + } + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } +} + +static CPUReadMemoryFunc *pxa2xx_mm_readfn[] = { + pxa2xx_mm_read, + pxa2xx_mm_read, + pxa2xx_mm_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_mm_writefn[] = { + pxa2xx_mm_write, + pxa2xx_mm_write, + pxa2xx_mm_write, +}; + +/* Synchronous Serial Ports */ +struct pxa2xx_ssp_s { + target_phys_addr_t base; + qemu_irq irq; + int enable; + + uint32_t sscr[2]; + uint32_t sspsp; + uint32_t ssto; + uint32_t ssitr; + uint32_t sssr; + uint8_t sstsa; + uint8_t ssrsa; + uint8_t ssacd; + + uint32_t rx_fifo[16]; + int rx_level; + int rx_start; + + uint32_t (*readfn)(void *opaque); + void (*writefn)(void *opaque, uint32_t value); + void *opaque; +}; + +#define SSCR0 0x00 /* SSP Control register 0 */ +#define SSCR1 0x04 /* SSP Control register 1 */ +#define SSSR 0x08 /* SSP Status register */ +#define SSITR 0x0c /* SSP Interrupt Test register */ +#define SSDR 0x10 /* SSP Data register */ +#define SSTO 0x28 /* SSP Time-Out register */ +#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */ +#define SSTSA 0x30 /* SSP TX Time Slot Active register */ +#define SSRSA 0x34 /* SSP RX Time Slot Active register */ +#define SSTSS 0x38 /* SSP Time Slot Status register */ +#define SSACD 0x3c /* SSP Audio Clock Divider register */ + +/* Bitfields for above registers */ +#define SSCR0_SPI(x) (((x) & 0x30) == 0x00) +#define SSCR0_SSP(x) (((x) & 0x30) == 0x10) +#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20) +#define SSCR0_PSP(x) (((x) & 0x30) == 0x30) +#define SSCR0_SSE (1 << 7) +#define SSCR0_RIM (1 << 22) +#define SSCR0_TIM (1 << 23) +#define SSCR0_MOD (1 << 31) +#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1) +#define SSCR1_RIE (1 << 0) +#define SSCR1_TIE (1 << 1) +#define SSCR1_LBM (1 << 2) +#define SSCR1_MWDS (1 << 5) +#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1) +#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1) +#define SSCR1_EFWR (1 << 14) +#define SSCR1_PINTE (1 << 18) +#define SSCR1_TINTE (1 << 19) +#define SSCR1_RSRE (1 << 20) +#define SSCR1_TSRE (1 << 21) +#define SSCR1_EBCEI (1 << 29) +#define SSITR_INT (7 << 5) +#define SSSR_TNF (1 << 2) +#define SSSR_RNE (1 << 3) +#define SSSR_TFS (1 << 5) +#define SSSR_RFS (1 << 6) +#define SSSR_ROR (1 << 7) +#define SSSR_PINT (1 << 18) +#define SSSR_TINT (1 << 19) +#define SSSR_EOC (1 << 20) +#define SSSR_TUR (1 << 21) +#define SSSR_BCE (1 << 23) +#define SSSR_RW 0x00bc0080 + +static void pxa2xx_ssp_int_update(struct pxa2xx_ssp_s *s) +{ + int level = 0; + + level |= s->ssitr & SSITR_INT; + level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI); + level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM); + level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT)); + level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE); + level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE); + level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM); + level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE); + level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE); + qemu_set_irq(s->irq, !!level); +} + +static void pxa2xx_ssp_fifo_update(struct pxa2xx_ssp_s *s) +{ + s->sssr &= ~(0xf << 12); /* Clear RFL */ + s->sssr &= ~(0xf << 8); /* Clear TFL */ + s->sssr &= ~SSSR_TNF; + if (s->enable) { + s->sssr |= ((s->rx_level - 1) & 0xf) << 12; + if (s->rx_level >= SSCR1_RFT(s->sscr[1])) + s->sssr |= SSSR_RFS; + else + s->sssr &= ~SSSR_RFS; + if (0 <= SSCR1_TFT(s->sscr[1])) + s->sssr |= SSSR_TFS; + else + s->sssr &= ~SSSR_TFS; + if (s->rx_level) + s->sssr |= SSSR_RNE; + else + s->sssr &= ~SSSR_RNE; + s->sssr |= SSSR_TNF; + } + + pxa2xx_ssp_int_update(s); +} + +static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr) +{ + struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque; + uint32_t retval; + addr -= s->base; + + switch (addr) { + case SSCR0: + return s->sscr[0]; + case SSCR1: + return s->sscr[1]; + case SSPSP: + return s->sspsp; + case SSTO: + return s->ssto; + case SSITR: + return s->ssitr; + case SSSR: + return s->sssr | s->ssitr; + case SSDR: + if (!s->enable) + return 0xffffffff; + if (s->rx_level < 1) { + printf("%s: SSP Rx Underrun\n", __FUNCTION__); + return 0xffffffff; + } + s->rx_level --; + retval = s->rx_fifo[s->rx_start ++]; + s->rx_start &= 0xf; + pxa2xx_ssp_fifo_update(s); + return retval; + case SSTSA: + return s->sstsa; + case SSRSA: + return s->ssrsa; + case SSTSS: + return 0; + case SSACD: + return s->ssacd; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque; + addr -= s->base; + + switch (addr) { + case SSCR0: + s->sscr[0] = value & 0xc7ffffff; + s->enable = value & SSCR0_SSE; + if (value & SSCR0_MOD) + printf("%s: Attempt to use network mode\n", __FUNCTION__); + if (s->enable && SSCR0_DSS(value) < 4) + printf("%s: Wrong data size: %i bits\n", __FUNCTION__, + SSCR0_DSS(value)); + if (!(value & SSCR0_SSE)) { + s->sssr = 0; + s->ssitr = 0; + s->rx_level = 0; + } + pxa2xx_ssp_fifo_update(s); + break; + + case SSCR1: + s->sscr[1] = value; + if (value & (SSCR1_LBM | SSCR1_EFWR)) + printf("%s: Attempt to use SSP test mode\n", __FUNCTION__); + pxa2xx_ssp_fifo_update(s); + break; + + case SSPSP: + s->sspsp = value; + break; + + case SSTO: + s->ssto = value; + break; + + case SSITR: + s->ssitr = value & SSITR_INT; + pxa2xx_ssp_int_update(s); + break; + + case SSSR: + s->sssr &= ~(value & SSSR_RW); + pxa2xx_ssp_int_update(s); + break; + + case SSDR: + if (SSCR0_UWIRE(s->sscr[0])) { + if (s->sscr[1] & SSCR1_MWDS) + value &= 0xffff; + else + value &= 0xff; + } else + /* Note how 32bits overflow does no harm here */ + value &= (1 << SSCR0_DSS(s->sscr[0])) - 1; + + /* Data goes from here to the Tx FIFO and is shifted out from + * there directly to the slave, no need to buffer it. + */ + if (s->enable) { + if (s->writefn) + s->writefn(s->opaque, value); + + if (s->rx_level < 0x10) { + if (s->readfn) + s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = + s->readfn(s->opaque); + else + s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = 0x0; + } else + s->sssr |= SSSR_ROR; + } + pxa2xx_ssp_fifo_update(s); + break; + + case SSTSA: + s->sstsa = value; + break; + + case SSRSA: + s->ssrsa = value; + break; + + case SSACD: + s->ssacd = value; + break; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } +} + +void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, + uint32_t (*readfn)(void *opaque), + void (*writefn)(void *opaque, uint32_t value), void *opaque) +{ + if (!port) { + printf("%s: no such SSP\n", __FUNCTION__); + exit(-1); + } + + port->opaque = opaque; + port->readfn = readfn; + port->writefn = writefn; +} + +static CPUReadMemoryFunc *pxa2xx_ssp_readfn[] = { + pxa2xx_ssp_read, + pxa2xx_ssp_read, + pxa2xx_ssp_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_ssp_writefn[] = { + pxa2xx_ssp_write, + pxa2xx_ssp_write, + pxa2xx_ssp_write, +}; + +/* Real-Time Clock */ +#define RCNR 0x00 /* RTC Counter register */ +#define RTAR 0x04 /* RTC Alarm register */ +#define RTSR 0x08 /* RTC Status register */ +#define RTTR 0x0c /* RTC Timer Trim register */ +#define RDCR 0x10 /* RTC Day Counter register */ +#define RYCR 0x14 /* RTC Year Counter register */ +#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */ +#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */ +#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */ +#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */ +#define SWCR 0x28 /* RTC Stopwatch Counter register */ +#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */ +#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */ +#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */ +#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */ + +static inline void pxa2xx_rtc_int_update(struct pxa2xx_state_s *s) +{ + qemu_set_irq(s->pic[PXA2XX_PIC_RTCALARM], !!(s->rtsr & 0x2553)); +} + +static void pxa2xx_rtc_hzupdate(struct pxa2xx_state_s *s) +{ + int64_t rt = qemu_get_clock(rt_clock); + s->last_rcnr += ((rt - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + s->last_rdcr += ((rt - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + s->last_hz = rt; +} + +static void pxa2xx_rtc_swupdate(struct pxa2xx_state_s *s) +{ + int64_t rt = qemu_get_clock(rt_clock); + if (s->rtsr & (1 << 12)) + s->last_swcr += (rt - s->last_sw) / 10; + s->last_sw = rt; +} + +static void pxa2xx_rtc_piupdate(struct pxa2xx_state_s *s) +{ + int64_t rt = qemu_get_clock(rt_clock); + if (s->rtsr & (1 << 15)) + s->last_swcr += rt - s->last_pi; + s->last_pi = rt; +} + +static inline void pxa2xx_rtc_alarm_update(struct pxa2xx_state_s *s, + uint32_t rtsr) +{ + if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0))) + qemu_mod_timer(s->rtc_hz, s->last_hz + + (((s->rtar - s->last_rcnr) * 1000 * + ((s->rttr & 0xffff) + 1)) >> 15)); + else + qemu_del_timer(s->rtc_hz); + + if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4))) + qemu_mod_timer(s->rtc_rdal1, s->last_hz + + (((s->rdar1 - s->last_rdcr) * 1000 * + ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ + else + qemu_del_timer(s->rtc_rdal1); + + if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6))) + qemu_mod_timer(s->rtc_rdal2, s->last_hz + + (((s->rdar2 - s->last_rdcr) * 1000 * + ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */ + else + qemu_del_timer(s->rtc_rdal2); + + if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8))) + qemu_mod_timer(s->rtc_swal1, s->last_sw + + (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */ + else + qemu_del_timer(s->rtc_swal1); + + if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10))) + qemu_mod_timer(s->rtc_swal2, s->last_sw + + (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */ + else + qemu_del_timer(s->rtc_swal2); + + if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13))) + qemu_mod_timer(s->rtc_pi, s->last_pi + + (s->piar & 0xffff) - s->last_rtcpicr); + else + qemu_del_timer(s->rtc_pi); +} + +static inline void pxa2xx_rtc_hz_tick(void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + s->rtsr |= (1 << 0); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_rdal1_tick(void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + s->rtsr |= (1 << 4); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_rdal2_tick(void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + s->rtsr |= (1 << 6); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_swal1_tick(void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + s->rtsr |= (1 << 8); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_swal2_tick(void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + s->rtsr |= (1 << 10); + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static inline void pxa2xx_rtc_pi_tick(void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + s->rtsr |= (1 << 13); + pxa2xx_rtc_piupdate(s); + s->last_rtcpicr = 0; + pxa2xx_rtc_alarm_update(s, s->rtsr); + pxa2xx_rtc_int_update(s); +} + +static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + addr -= s->rtc_base; + + switch (addr) { + case RTTR: + return s->rttr; + case RTSR: + return s->rtsr; + case RTAR: + return s->rtar; + case RDAR1: + return s->rdar1; + case RDAR2: + return s->rdar2; + case RYAR1: + return s->ryar1; + case RYAR2: + return s->ryar2; + case SWAR1: + return s->swar1; + case SWAR2: + return s->swar2; + case PIAR: + return s->piar; + case RCNR: + return s->last_rcnr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + case RDCR: + return s->last_rdcr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) / + (1000 * ((s->rttr & 0xffff) + 1)); + case RYCR: + return s->last_rycr; + case SWCR: + if (s->rtsr & (1 << 12)) + return s->last_swcr + (qemu_get_clock(rt_clock) - s->last_sw) / 10; + else + return s->last_swcr; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + addr -= s->rtc_base; + + switch (addr) { + case RTTR: + if (!(s->rttr & (1 << 31))) { + pxa2xx_rtc_hzupdate(s); + s->rttr = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + } + break; + + case RTSR: + if ((s->rtsr ^ value) & (1 << 15)) + pxa2xx_rtc_piupdate(s); + + if ((s->rtsr ^ value) & (1 << 12)) + pxa2xx_rtc_swupdate(s); + + if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac)) + pxa2xx_rtc_alarm_update(s, value); + + s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac)); + pxa2xx_rtc_int_update(s); + break; + + case RTAR: + s->rtar = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RDAR1: + s->rdar1 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RDAR2: + s->rdar2 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RYAR1: + s->ryar1 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RYAR2: + s->ryar2 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case SWAR1: + pxa2xx_rtc_swupdate(s); + s->swar1 = value; + s->last_swcr = 0; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case SWAR2: + s->swar2 = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case PIAR: + s->piar = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RCNR: + pxa2xx_rtc_hzupdate(s); + s->last_rcnr = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RDCR: + pxa2xx_rtc_hzupdate(s); + s->last_rdcr = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RYCR: + s->last_rycr = value; + break; + + case SWCR: + pxa2xx_rtc_swupdate(s); + s->last_swcr = value; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + case RTCPICR: + pxa2xx_rtc_piupdate(s); + s->last_rtcpicr = value & 0xffff; + pxa2xx_rtc_alarm_update(s, s->rtsr); + break; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + } +} + +static void pxa2xx_rtc_reset(struct pxa2xx_state_s *s) +{ + struct tm *tm; + time_t ti; + int wom; + + s->rttr = 0x7fff; + s->rtsr = 0; + + time(&ti); + if (rtc_utc) + tm = gmtime(&ti); + else + tm = localtime(&ti); + wom = ((tm->tm_mday - 1) / 7) + 1; + + s->last_rcnr = (uint32_t) ti; + s->last_rdcr = (wom << 20) | ((tm->tm_wday + 1) << 17) | + (tm->tm_hour << 12) | (tm->tm_min << 6) | tm->tm_sec; + s->last_rycr = ((tm->tm_year + 1900) << 9) | + ((tm->tm_mon + 1) << 5) | tm->tm_mday; + s->last_swcr = (tm->tm_hour << 19) | + (tm->tm_min << 13) | (tm->tm_sec << 7); + s->last_rtcpicr = 0; + s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock); + + s->rtc_hz = qemu_new_timer(rt_clock, pxa2xx_rtc_hz_tick, s); + s->rtc_rdal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal1_tick, s); + s->rtc_rdal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal2_tick, s); + s->rtc_swal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal1_tick, s); + s->rtc_swal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal2_tick, s); + s->rtc_pi = qemu_new_timer(rt_clock, pxa2xx_rtc_pi_tick, s); +} + +static CPUReadMemoryFunc *pxa2xx_rtc_readfn[] = { + pxa2xx_rtc_read, + pxa2xx_rtc_read, + pxa2xx_rtc_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = { + pxa2xx_rtc_write, + pxa2xx_rtc_write, + pxa2xx_rtc_write, +}; + +/* PXA Inter-IC Sound Controller */ +static void pxa2xx_i2s_reset(struct pxa2xx_i2s_s *i2s) +{ + i2s->rx_len = 0; + i2s->tx_len = 0; + i2s->fifo_len = 0; + i2s->clk = 0x1a; + i2s->control[0] = 0x00; + i2s->control[1] = 0x00; + i2s->status = 0x00; + i2s->mask = 0x00; +} + +#define SACR_TFTH(val) ((val >> 8) & 0xf) +#define SACR_RFTH(val) ((val >> 12) & 0xf) +#define SACR_DREC(val) (val & (1 << 3)) +#define SACR_DPRL(val) (val & (1 << 4)) + +static inline void pxa2xx_i2s_update(struct pxa2xx_i2s_s *i2s) +{ + int rfs, tfs; + rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len && + !SACR_DREC(i2s->control[1]); + tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) && + i2s->enable && !SACR_DPRL(i2s->control[1]); + + pxa2xx_dma_request(i2s->dma, PXA2XX_RX_RQ_I2S, rfs); + pxa2xx_dma_request(i2s->dma, PXA2XX_TX_RQ_I2S, tfs); + + i2s->status &= 0xe0; + if (i2s->rx_len) + i2s->status |= 1 << 1; /* RNE */ + if (i2s->enable) + i2s->status |= 1 << 2; /* BSY */ + if (tfs) + i2s->status |= 1 << 3; /* TFS */ + if (rfs) + i2s->status |= 1 << 4; /* RFS */ + if (!(i2s->tx_len && i2s->enable)) + i2s->status |= i2s->fifo_len << 8; /* TFL */ + i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */ + + qemu_set_irq(i2s->irq, i2s->status & i2s->mask); +} + +#define SACR0 0x00 /* Serial Audio Global Control register */ +#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */ +#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */ +#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */ +#define SAICR 0x18 /* Serial Audio Interrupt Clear register */ +#define SADIV 0x60 /* Serial Audio Clock Divider register */ +#define SADR 0x80 /* Serial Audio Data register */ + +static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr) +{ + struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque; + addr -= s->base; + + switch (addr) { + case SACR0: + return s->control[0]; + case SACR1: + return s->control[1]; + case SASR0: + return s->status; + case SAIMR: + return s->mask; + case SAICR: + return 0; + case SADIV: + return s->clk; + case SADR: + if (s->rx_len > 0) { + s->rx_len --; + pxa2xx_i2s_update(s); + return s->codec_in(s->opaque); + } + return 0; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque; + uint32_t *sample; + addr -= s->base; + + switch (addr) { + case SACR0: + if (value & (1 << 3)) /* RST */ + pxa2xx_i2s_reset(s); + s->control[0] = value & 0xff3d; + if (!s->enable && (value & 1) && s->tx_len) { /* ENB */ + for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++) + s->codec_out(s->opaque, *sample); + s->status &= ~(1 << 7); /* I2SOFF */ + } + if (value & (1 << 4)) /* EFWR */ + printf("%s: Attempt to use special function\n", __FUNCTION__); + s->enable = ((value ^ 4) & 5) == 5; /* ENB && !RST*/ + pxa2xx_i2s_update(s); + break; + case SACR1: + s->control[1] = value & 0x0039; + if (value & (1 << 5)) /* ENLBF */ + printf("%s: Attempt to use loopback function\n", __FUNCTION__); + if (value & (1 << 4)) /* DPRL */ + s->fifo_len = 0; + pxa2xx_i2s_update(s); + break; + case SAIMR: + s->mask = value & 0x0078; + pxa2xx_i2s_update(s); + break; + case SAICR: + s->status &= ~(value & (3 << 5)); + pxa2xx_i2s_update(s); + break; + case SADIV: + s->clk = value & 0x007f; + break; + case SADR: + if (s->tx_len && s->enable) { + s->tx_len --; + pxa2xx_i2s_update(s); + s->codec_out(s->opaque, value); + } else if (s->fifo_len < 16) { + s->fifo[s->fifo_len ++] = value; + pxa2xx_i2s_update(s); + } + break; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + } +} + +static CPUReadMemoryFunc *pxa2xx_i2s_readfn[] = { + pxa2xx_i2s_read, + pxa2xx_i2s_read, + pxa2xx_i2s_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_i2s_writefn[] = { + pxa2xx_i2s_write, + pxa2xx_i2s_write, + pxa2xx_i2s_write, +}; + +static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) +{ + struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque; + uint32_t *sample; + + /* Signal FIFO errors */ + if (s->enable && s->tx_len) + s->status |= 1 << 5; /* TUR */ + if (s->enable && s->rx_len) + s->status |= 1 << 6; /* ROR */ + + /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to + * handle the cases where it makes a difference. */ + s->tx_len = tx - s->fifo_len; + s->rx_len = rx; + /* Note that is s->codec_out wasn't set, we wouldn't get called. */ + if (s->enable) + for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++) + s->codec_out(s->opaque, *sample); + pxa2xx_i2s_update(s); +} + +static struct pxa2xx_i2s_s *pxa2xx_i2s_init(target_phys_addr_t base, + qemu_irq irq, struct pxa2xx_dma_state_s *dma) +{ + int iomemtype; + struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) + qemu_mallocz(sizeof(struct pxa2xx_i2s_s)); + + s->base = base; + s->irq = irq; + s->dma = dma; + s->data_req = pxa2xx_i2s_data_req; + + pxa2xx_i2s_reset(s); + + iomemtype = cpu_register_io_memory(0, pxa2xx_i2s_readfn, + pxa2xx_i2s_writefn, s); + cpu_register_physical_memory(s->base & 0xfff00000, 0xfffff, iomemtype); + + return s; +} + +/* PXA Fast Infra-red Communications Port */ +struct pxa2xx_fir_s { + target_phys_addr_t base; + qemu_irq irq; + struct pxa2xx_dma_state_s *dma; + int enable; + CharDriverState *chr; + + uint8_t control[3]; + uint8_t status[2]; + + int rx_len; + int rx_start; + uint8_t rx_fifo[64]; +}; + +static void pxa2xx_fir_reset(struct pxa2xx_fir_s *s) +{ + s->control[0] = 0x00; + s->control[1] = 0x00; + s->control[2] = 0x00; + s->status[0] = 0x00; + s->status[1] = 0x00; + s->enable = 0; +} + +static inline void pxa2xx_fir_update(struct pxa2xx_fir_s *s) +{ + static const int tresh[4] = { 8, 16, 32, 0 }; + int intr = 0; + if ((s->control[0] & (1 << 4)) && /* RXE */ + s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */ + s->status[0] |= 1 << 4; /* RFS */ + else + s->status[0] &= ~(1 << 4); /* RFS */ + if (s->control[0] & (1 << 3)) /* TXE */ + s->status[0] |= 1 << 3; /* TFS */ + else + s->status[0] &= ~(1 << 3); /* TFS */ + if (s->rx_len) + s->status[1] |= 1 << 2; /* RNE */ + else + s->status[1] &= ~(1 << 2); /* RNE */ + if (s->control[0] & (1 << 4)) /* RXE */ + s->status[1] |= 1 << 0; /* RSY */ + else + s->status[1] &= ~(1 << 0); /* RSY */ + + intr |= (s->control[0] & (1 << 5)) && /* RIE */ + (s->status[0] & (1 << 4)); /* RFS */ + intr |= (s->control[0] & (1 << 6)) && /* TIE */ + (s->status[0] & (1 << 3)); /* TFS */ + intr |= (s->control[2] & (1 << 4)) && /* TRAIL */ + (s->status[0] & (1 << 6)); /* EOC */ + intr |= (s->control[0] & (1 << 2)) && /* TUS */ + (s->status[0] & (1 << 1)); /* TUR */ + intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */ + + pxa2xx_dma_request(s->dma, PXA2XX_RX_RQ_ICP, (s->status[0] >> 4) & 1); + pxa2xx_dma_request(s->dma, PXA2XX_TX_RQ_ICP, (s->status[0] >> 3) & 1); + + qemu_set_irq(s->irq, intr && s->enable); +} + +#define ICCR0 0x00 /* FICP Control register 0 */ +#define ICCR1 0x04 /* FICP Control register 1 */ +#define ICCR2 0x08 /* FICP Control register 2 */ +#define ICDR 0x0c /* FICP Data register */ +#define ICSR0 0x14 /* FICP Status register 0 */ +#define ICSR1 0x18 /* FICP Status register 1 */ +#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */ + +static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr) +{ + struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque; + uint8_t ret; + addr -= s->base; + + switch (addr) { + case ICCR0: + return s->control[0]; + case ICCR1: + return s->control[1]; + case ICCR2: + return s->control[2]; + case ICDR: + s->status[0] &= ~0x01; + s->status[1] &= ~0x72; + if (s->rx_len) { + s->rx_len --; + ret = s->rx_fifo[s->rx_start ++]; + s->rx_start &= 63; + pxa2xx_fir_update(s); + return ret; + } + printf("%s: Rx FIFO underrun.\n", __FUNCTION__); + break; + case ICSR0: + return s->status[0]; + case ICSR1: + return s->status[1] | (1 << 3); /* TNF */ + case ICFOR: + return s->rx_len; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque; + uint8_t ch; + addr -= s->base; + + switch (addr) { + case ICCR0: + s->control[0] = value; + if (!(value & (1 << 4))) /* RXE */ + s->rx_len = s->rx_start = 0; + if (!(value & (1 << 3))) /* TXE */ + /* Nop */; + s->enable = value & 1; /* ITR */ + if (!s->enable) + s->status[0] = 0; + pxa2xx_fir_update(s); + break; + case ICCR1: + s->control[1] = value; + break; + case ICCR2: + s->control[2] = value & 0x3f; + pxa2xx_fir_update(s); + break; + case ICDR: + if (s->control[2] & (1 << 2)) /* TXP */ + ch = value; + else + ch = ~value; + if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */ + qemu_chr_write(s->chr, &ch, 1); + break; + case ICSR0: + s->status[0] &= ~(value & 0x66); + pxa2xx_fir_update(s); + break; + case ICFOR: + break; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + } +} + +static CPUReadMemoryFunc *pxa2xx_fir_readfn[] = { + pxa2xx_fir_read, + pxa2xx_fir_read, + pxa2xx_fir_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_fir_writefn[] = { + pxa2xx_fir_write, + pxa2xx_fir_write, + pxa2xx_fir_write, +}; + +static int pxa2xx_fir_is_empty(void *opaque) +{ + struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque; + return (s->rx_len < 64); +} + +static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size) +{ + struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque; + if (!(s->control[0] & (1 << 4))) /* RXE */ + return; + + while (size --) { + s->status[1] |= 1 << 4; /* EOF */ + if (s->rx_len >= 64) { + s->status[1] |= 1 << 6; /* ROR */ + break; + } + + if (s->control[2] & (1 << 3)) /* RXP */ + s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++); + else + s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++); + } + + pxa2xx_fir_update(s); +} + +static void pxa2xx_fir_event(void *opaque, int event) +{ +} + +static struct pxa2xx_fir_s *pxa2xx_fir_init(target_phys_addr_t base, + qemu_irq irq, struct pxa2xx_dma_state_s *dma, + CharDriverState *chr) +{ + int iomemtype; + struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) + qemu_mallocz(sizeof(struct pxa2xx_fir_s)); + + s->base = base; + s->irq = irq; + s->dma = dma; + s->chr = chr; + + pxa2xx_fir_reset(s); + + iomemtype = cpu_register_io_memory(0, pxa2xx_fir_readfn, + pxa2xx_fir_writefn, s); + cpu_register_physical_memory(s->base, 0xfff, iomemtype); + + if (chr) + qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, + pxa2xx_fir_rx, pxa2xx_fir_event, s); + + return s; +} + +void pxa2xx_reset(int line, int level, void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */ + cpu_reset(s->env); + /* TODO: reset peripherals */ + } +} + +/* Initialise a PXA270 integrated chip (ARM based core). */ +struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) +{ + struct pxa2xx_state_s *s; + struct pxa2xx_ssp_s *ssp; + char *cpu_model; + int iomemtype, i; + s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s)); + + s->env = cpu_init(); + asprintf(&cpu_model, "pxa270-%s", revision); + cpu_arm_set_model(s->env, cpu_model); + free(cpu_model); + + s->pic = pxa2xx_pic_init(0x40d00000, s->env); + + s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); + + s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); + + for (i = 0; pxa270_serial[i].io_base; i ++) + if (serial_hds[i]) + serial_mm_init(pxa270_serial[i].io_base, 2, + s->pic[pxa270_serial[i].irqn], serial_hds[i], 1); + else + break; + if (serial_hds[i]) + s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], + s->dma, serial_hds[i]); + + s->cm_base = 0x41300000; + s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ + s->clkcfg = 0x00000009; /* Turbo mode active */ + iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, + pxa2xx_cm_writefn, s); + cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype); + + cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); + + s->mm_base = 0x48000000; + s->mm_regs[MDMRS >> 2] = 0x00020002; + s->mm_regs[MDREFR >> 2] = 0x03ca4000; + s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ + iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn, + pxa2xx_mm_writefn, s); + cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype); + + for (i = 0; pxa27x_ssp[i].io_base; i ++); + s->ssp = (struct pxa2xx_ssp_s **) + qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i); + ssp = (struct pxa2xx_ssp_s *) + qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i); + for (i = 0; pxa27x_ssp[i].io_base; i ++) { + s->ssp[i] = &ssp[i]; + ssp[i].base = pxa27x_ssp[i].io_base; + ssp[i].irq = s->pic[pxa27x_ssp[i].irqn]; + + iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn, + pxa2xx_ssp_writefn, &ssp[i]); + cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); + } + + s->rtc_base = 0x40900000; + iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, + pxa2xx_rtc_writefn, s); + cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype); + pxa2xx_rtc_reset(s); + + s->pm_base = 0x40f00000; + iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, + pxa2xx_pm_writefn, s); + cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype); + + s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); + + /* GPIO1 resets the processor */ + /* The handler can be overriden by board-specific code */ + pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s); + return s; +} + +/* Initialise a PXA255 integrated chip (ARM based core). */ +struct pxa2xx_state_s *pxa255_init(DisplayState *ds) +{ + struct pxa2xx_state_s *s; + struct pxa2xx_ssp_s *ssp; + int iomemtype, i; + s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s)); + + s->env = cpu_init(); + cpu_arm_set_model(s->env, "pxa255"); + + s->pic = pxa2xx_pic_init(0x40d00000, s->env); + + s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); + + s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); + + for (i = 0; pxa255_serial[i].io_base; i ++) + if (serial_hds[i]) + serial_mm_init(pxa255_serial[i].io_base, 2, + s->pic[pxa255_serial[i].irqn], serial_hds[i], 1); + else + break; + if (serial_hds[i]) + s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], + s->dma, serial_hds[i]); + + s->cm_base = 0x41300000; + s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ + s->clkcfg = 0x00000009; /* Turbo mode active */ + iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, + pxa2xx_cm_writefn, s); + cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype); + + cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); + + s->mm_base = 0x48000000; + s->mm_regs[MDMRS >> 2] = 0x00020002; + s->mm_regs[MDREFR >> 2] = 0x03ca4000; + s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ + iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn, + pxa2xx_mm_writefn, s); + cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype); + + for (i = 0; pxa255_ssp[i].io_base; i ++); + s->ssp = (struct pxa2xx_ssp_s **) + qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i); + ssp = (struct pxa2xx_ssp_s *) + qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i); + for (i = 0; pxa255_ssp[i].io_base; i ++) { + s->ssp[i] = &ssp[i]; + ssp[i].base = pxa255_ssp[i].io_base; + ssp[i].irq = s->pic[pxa255_ssp[i].irqn]; + + iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn, + pxa2xx_ssp_writefn, &ssp[i]); + cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); + } + + s->rtc_base = 0x40900000; + iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, + pxa2xx_rtc_writefn, s); + cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype); + pxa2xx_rtc_reset(s); + + s->pm_base = 0x40f00000; + iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, + pxa2xx_pm_writefn, s); + cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype); + + s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); + + /* GPIO1 resets the processor */ + /* The handler can be overriden by board-specific code */ + pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s); + return s; +} diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c new file mode 100644 index 000000000..63d2fb79c --- /dev/null +++ b/hw/pxa2xx_dma.c @@ -0,0 +1,496 @@ +/* + * Intel XScale PXA255/270 DMA controller. + * + * Copyright (c) 2006 Openedhand Ltd. + * Copyright (c) 2006 Thorsten Zitterell + * Written by Andrzej Zaborowski + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +struct pxa2xx_dma_channel_s { + target_phys_addr_t descr; + target_phys_addr_t src; + target_phys_addr_t dest; + uint32_t cmd; + uint32_t state; + int request; +}; + +/* Allow the DMA to be used as a PIC. */ +typedef void (*pxa2xx_dma_handler_t)(void *opaque, int irq, int level); + +struct pxa2xx_dma_state_s { + pxa2xx_dma_handler_t handler; + target_phys_addr_t base; + qemu_irq irq; + + uint32_t stopintr; + uint32_t eorintr; + uint32_t rasintr; + uint32_t startintr; + uint32_t endintr; + + uint32_t align; + uint32_t pio; + + int channels; + struct pxa2xx_dma_channel_s *chan; + + uint8_t *req; + + /* Flag to avoid recursive DMA invocations. */ + int running; +}; + +#define PXA255_DMA_NUM_CHANNELS 16 +#define PXA27X_DMA_NUM_CHANNELS 32 + +#define PXA2XX_DMA_NUM_REQUESTS 75 + +#define DCSR0 0x0000 /* DMA Control / Status register for Channel 0 */ +#define DCSR31 0x007c /* DMA Control / Status register for Channel 31 */ +#define DALGN 0x00a0 /* DMA Alignment register */ +#define DPCSR 0x00a4 /* DMA Programmed I/O Control Status register */ +#define DRQSR0 0x00e0 /* DMA DREQ<0> Status register */ +#define DRQSR1 0x00e4 /* DMA DREQ<1> Status register */ +#define DRQSR2 0x00e8 /* DMA DREQ<2> Status register */ +#define DINT 0x00f0 /* DMA Interrupt register */ +#define DRCMR0 0x0100 /* Request to Channel Map register 0 */ +#define DRCMR63 0x01fc /* Request to Channel Map register 63 */ +#define D_CH0 0x0200 /* Channel 0 Descriptor start */ +#define DRCMR64 0x1100 /* Request to Channel Map register 64 */ +#define DRCMR74 0x1128 /* Request to Channel Map register 74 */ + +/* Per-channel register */ +#define DDADR 0x00 +#define DSADR 0x01 +#define DTADR 0x02 +#define DCMD 0x03 + +/* Bit-field masks */ +#define DRCMR_CHLNUM 0x1f +#define DRCMR_MAPVLD (1 << 7) +#define DDADR_STOP (1 << 0) +#define DDADR_BREN (1 << 1) +#define DCMD_LEN 0x1fff +#define DCMD_WIDTH(x) (1 << ((((x) >> 14) & 3) - 1)) +#define DCMD_SIZE(x) (4 << (((x) >> 16) & 3)) +#define DCMD_FLYBYT (1 << 19) +#define DCMD_FLYBYS (1 << 20) +#define DCMD_ENDIRQEN (1 << 21) +#define DCMD_STARTIRQEN (1 << 22) +#define DCMD_CMPEN (1 << 25) +#define DCMD_FLOWTRG (1 << 28) +#define DCMD_FLOWSRC (1 << 29) +#define DCMD_INCTRGADDR (1 << 30) +#define DCMD_INCSRCADDR (1 << 31) +#define DCSR_BUSERRINTR (1 << 0) +#define DCSR_STARTINTR (1 << 1) +#define DCSR_ENDINTR (1 << 2) +#define DCSR_STOPINTR (1 << 3) +#define DCSR_RASINTR (1 << 4) +#define DCSR_REQPEND (1 << 8) +#define DCSR_EORINT (1 << 9) +#define DCSR_CMPST (1 << 10) +#define DCSR_MASKRUN (1 << 22) +#define DCSR_RASIRQEN (1 << 23) +#define DCSR_CLRCMPST (1 << 24) +#define DCSR_SETCMPST (1 << 25) +#define DCSR_EORSTOPEN (1 << 26) +#define DCSR_EORJMPEN (1 << 27) +#define DCSR_EORIRQEN (1 << 28) +#define DCSR_STOPIRQEN (1 << 29) +#define DCSR_NODESCFETCH (1 << 30) +#define DCSR_RUN (1 << 31) + +static inline void pxa2xx_dma_update(struct pxa2xx_dma_state_s *s, int ch) +{ + if (ch >= 0) { + if ((s->chan[ch].state & DCSR_STOPIRQEN) && + (s->chan[ch].state & DCSR_STOPINTR)) + s->stopintr |= 1 << ch; + else + s->stopintr &= ~(1 << ch); + + if ((s->chan[ch].state & DCSR_EORIRQEN) && + (s->chan[ch].state & DCSR_EORINT)) + s->eorintr |= 1 << ch; + else + s->eorintr &= ~(1 << ch); + + if ((s->chan[ch].state & DCSR_RASIRQEN) && + (s->chan[ch].state & DCSR_RASINTR)) + s->rasintr |= 1 << ch; + else + s->rasintr &= ~(1 << ch); + + if (s->chan[ch].state & DCSR_STARTINTR) + s->startintr |= 1 << ch; + else + s->startintr &= ~(1 << ch); + + if (s->chan[ch].state & DCSR_ENDINTR) + s->endintr |= 1 << ch; + else + s->endintr &= ~(1 << ch); + } + + if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr) + qemu_irq_raise(s->irq); + else + qemu_irq_lower(s->irq); +} + +static inline void pxa2xx_dma_descriptor_fetch( + struct pxa2xx_dma_state_s *s, int ch) +{ + uint32_t desc[4]; + target_phys_addr_t daddr = s->chan[ch].descr & ~0xf; + if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST)) + daddr += 32; + + cpu_physical_memory_read(daddr, (uint8_t *) desc, 16); + s->chan[ch].descr = desc[DDADR]; + s->chan[ch].src = desc[DSADR]; + s->chan[ch].dest = desc[DTADR]; + s->chan[ch].cmd = desc[DCMD]; + + if (s->chan[ch].cmd & DCMD_FLOWSRC) + s->chan[ch].src &= ~3; + if (s->chan[ch].cmd & DCMD_FLOWTRG) + s->chan[ch].dest &= ~3; + + if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT)) + printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch); + + if (s->chan[ch].cmd & DCMD_STARTIRQEN) + s->chan[ch].state |= DCSR_STARTINTR; +} + +static void pxa2xx_dma_run(struct pxa2xx_dma_state_s *s) +{ + int c, srcinc, destinc; + uint32_t n, size; + uint32_t width; + uint32_t length; + char buffer[32]; + struct pxa2xx_dma_channel_s *ch; + + if (s->running ++) + return; + + while (s->running) { + s->running = 1; + for (c = 0; c < s->channels; c ++) { + ch = &s->chan[c]; + + while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) { + /* Test for pending requests */ + if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request) + break; + + length = ch->cmd & DCMD_LEN; + size = DCMD_SIZE(ch->cmd); + width = DCMD_WIDTH(ch->cmd); + + srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0; + destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0; + + while (length) { + size = MIN(length, size); + + for (n = 0; n < size; n += width) { + cpu_physical_memory_read(ch->src, buffer + n, width); + ch->src += srcinc; + } + + for (n = 0; n < size; n += width) { + cpu_physical_memory_write(ch->dest, buffer + n, width); + ch->dest += destinc; + } + + length -= size; + + if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && + !ch->request) { + ch->state |= DCSR_EORINT; + if (ch->state & DCSR_EORSTOPEN) + ch->state |= DCSR_STOPINTR; + if ((ch->state & DCSR_EORJMPEN) && + !(ch->state & DCSR_NODESCFETCH)) + pxa2xx_dma_descriptor_fetch(s, c); + break; + } + } + + ch->cmd = (ch->cmd & ~DCMD_LEN) | length; + + /* Is the transfer complete now? */ + if (!length) { + if (ch->cmd & DCMD_ENDIRQEN) + ch->state |= DCSR_ENDINTR; + + if ((ch->state & DCSR_NODESCFETCH) || + (ch->descr & DDADR_STOP) || + (ch->state & DCSR_EORSTOPEN)) { + ch->state |= DCSR_STOPINTR; + ch->state &= ~DCSR_RUN; + + break; + } + + ch->state |= DCSR_STOPINTR; + break; + } + } + } + + s->running --; + } +} + +static uint32_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque; + unsigned int channel; + offset -= s->base; + + switch (offset) { + case DRCMR64 ... DRCMR74: + offset -= DRCMR64 - DRCMR0 - (64 << 2); + /* Fall through */ + case DRCMR0 ... DRCMR63: + channel = (offset - DRCMR0) >> 2; + return s->req[channel]; + + case DRQSR0: + case DRQSR1: + case DRQSR2: + return 0; + + case DCSR0 ... DCSR31: + channel = offset >> 2; + if (s->chan[channel].request) + return s->chan[channel].state | DCSR_REQPEND; + return s->chan[channel].state; + + case DINT: + return s->stopintr | s->eorintr | s->rasintr | + s->startintr | s->endintr; + + case DALGN: + return s->align; + + case DPCSR: + return s->pio; + } + + if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) { + channel = (offset - D_CH0) >> 4; + switch ((offset & 0x0f) >> 2) { + case DDADR: + return s->chan[channel].descr; + case DSADR: + return s->chan[channel].src; + case DTADR: + return s->chan[channel].dest; + case DCMD: + return s->chan[channel].cmd; + } + } + + cpu_abort(cpu_single_env, + "%s: Bad offset 0x%04lx\n", __FUNCTION__, offset); + return 7; +} + +static void pxa2xx_dma_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque; + unsigned int channel; + offset -= s->base; + + switch (offset) { + case DRCMR64 ... DRCMR74: + offset -= DRCMR64 - DRCMR0 - (64 << 2); + /* Fall through */ + case DRCMR0 ... DRCMR63: + channel = (offset - DRCMR0) >> 2; + + if (value & DRCMR_MAPVLD) + if ((value & DRCMR_CHLNUM) > s->channels) + cpu_abort(cpu_single_env, "%s: Bad DMA channel %i\n", + __FUNCTION__, value & DRCMR_CHLNUM); + + s->req[channel] = value; + break; + + case DRQSR0: + case DRQSR1: + case DRQSR2: + /* Nothing to do */ + break; + + case DCSR0 ... DCSR31: + channel = offset >> 2; + s->chan[channel].state &= 0x0000071f & ~(value & + (DCSR_EORINT | DCSR_ENDINTR | + DCSR_STARTINTR | DCSR_BUSERRINTR)); + s->chan[channel].state |= value & 0xfc800000; + + if (s->chan[channel].state & DCSR_STOPIRQEN) + s->chan[channel].state &= ~DCSR_STOPINTR; + + if (value & DCSR_NODESCFETCH) { + /* No-descriptor-fetch mode */ + if (value & DCSR_RUN) + pxa2xx_dma_run(s); + } else { + /* Descriptor-fetch mode */ + if (value & DCSR_RUN) { + s->chan[channel].state &= ~DCSR_STOPINTR; + pxa2xx_dma_descriptor_fetch(s, channel); + pxa2xx_dma_run(s); + } + } + + /* Shouldn't matter as our DMA is synchronous. */ + if (!(value & (DCSR_RUN | DCSR_MASKRUN))) + s->chan[channel].state |= DCSR_STOPINTR; + + if (value & DCSR_CLRCMPST) + s->chan[channel].state &= ~DCSR_CMPST; + if (value & DCSR_SETCMPST) + s->chan[channel].state |= DCSR_CMPST; + + pxa2xx_dma_update(s, channel); + break; + + case DALGN: + s->align = value; + break; + + case DPCSR: + s->pio = value & 0x80000001; + break; + + default: + if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) { + channel = (offset - D_CH0) >> 4; + switch ((offset & 0x0f) >> 2) { + case DDADR: + s->chan[channel].descr = value; + break; + case DSADR: + s->chan[channel].src = value; + break; + case DTADR: + s->chan[channel].dest = value; + break; + case DCMD: + s->chan[channel].cmd = value; + break; + default: + goto fail; + } + + break; + } + fail: + cpu_abort(cpu_single_env, "%s: Bad offset 0x%04lx\n", + __FUNCTION__, offset); + } +} + +static uint32_t pxa2xx_dma_readbad(void *opaque, target_phys_addr_t offset) +{ + cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__); + return 5; +} + +static void pxa2xx_dma_writebad(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__); +} + +static CPUReadMemoryFunc *pxa2xx_dma_readfn[] = { + pxa2xx_dma_readbad, + pxa2xx_dma_readbad, + pxa2xx_dma_read +}; + +static CPUWriteMemoryFunc *pxa2xx_dma_writefn[] = { + pxa2xx_dma_writebad, + pxa2xx_dma_writebad, + pxa2xx_dma_write +}; + +static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base, + qemu_irq irq, int channels) +{ + int i, iomemtype; + struct pxa2xx_dma_state_s *s; + s = (struct pxa2xx_dma_state_s *) + qemu_mallocz(sizeof(struct pxa2xx_dma_state_s)); + + s->channels = channels; + s->chan = qemu_mallocz(sizeof(struct pxa2xx_dma_channel_s) * s->channels); + s->base = base; + s->irq = irq; + s->handler = (pxa2xx_dma_handler_t) pxa2xx_dma_request; + s->req = qemu_mallocz(sizeof(int) * PXA2XX_DMA_NUM_REQUESTS); + + memset(s->chan, 0, sizeof(struct pxa2xx_dma_channel_s) * s->channels); + for (i = 0; i < s->channels; i ++) + s->chan[i].state = DCSR_STOPINTR; + + memset(s->req, 0, sizeof(int) * PXA2XX_DMA_NUM_REQUESTS); + + iomemtype = cpu_register_io_memory(0, pxa2xx_dma_readfn, + pxa2xx_dma_writefn, s); + cpu_register_physical_memory(base, 0x0000ffff, iomemtype); + + return s; +} + +struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base, + qemu_irq irq) +{ + return pxa2xx_dma_init(base, irq, PXA27X_DMA_NUM_CHANNELS); +} + +struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base, + qemu_irq irq) +{ + return pxa2xx_dma_init(base, irq, PXA255_DMA_NUM_CHANNELS); +} + +void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on) +{ + int ch; + if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS) + cpu_abort(cpu_single_env, + "%s: Bad DMA request %i\n", __FUNCTION__, req_num); + + if (!(s->req[req_num] & DRCMR_MAPVLD)) + return; + ch = s->req[req_num] & DRCMR_CHLNUM; + + if (!s->chan[ch].request && on) + s->chan[ch].state |= DCSR_RASINTR; + else + s->chan[ch].state &= ~DCSR_RASINTR; + if (s->chan[ch].request && !on) + s->chan[ch].state |= DCSR_EORINT; + + s->chan[ch].request = on; + if (on) { + pxa2xx_dma_run(s); + pxa2xx_dma_update(s, ch); + } +} diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c new file mode 100644 index 000000000..eab2e7225 --- /dev/null +++ b/hw/pxa2xx_gpio.c @@ -0,0 +1,290 @@ +/* + * Intel XScale PXA255/270 GPIO controller emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPL. + */ + +#include "vl.h" + +#define PXA2XX_GPIO_BANKS 4 + +struct pxa2xx_gpio_info_s { + target_phys_addr_t base; + qemu_irq *pic; + int lines; + CPUState *cpu_env; + + /* XXX: GNU C vectors are more suitable */ + uint32_t ilevel[PXA2XX_GPIO_BANKS]; + uint32_t olevel[PXA2XX_GPIO_BANKS]; + uint32_t dir[PXA2XX_GPIO_BANKS]; + uint32_t rising[PXA2XX_GPIO_BANKS]; + uint32_t falling[PXA2XX_GPIO_BANKS]; + uint32_t status[PXA2XX_GPIO_BANKS]; + uint32_t gafr[PXA2XX_GPIO_BANKS * 2]; + + uint32_t prev_level[PXA2XX_GPIO_BANKS]; + struct { + gpio_handler_t fn; + void *opaque; + } handler[PXA2XX_GPIO_BANKS * 32]; + + void (*read_notify)(void *opaque); + void *opaque; +}; + +static struct { + enum { + GPIO_NONE, + GPLR, + GPSR, + GPCR, + GPDR, + GRER, + GFER, + GEDR, + GAFR_L, + GAFR_U, + } reg; + int bank; +} pxa2xx_gpio_regs[0x200] = { + [0 ... 0x1ff] = { GPIO_NONE, 0 }, +#define PXA2XX_REG(reg, a0, a1, a2, a3) \ + [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 }, + + PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100) + PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118) + PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124) + PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c) + PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130) + PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c) + PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148) + PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c) + PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070) +}; + +static void pxa2xx_gpio_irq_update(struct pxa2xx_gpio_info_s *s) +{ + if (s->status[0] & (1 << 0)) + qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_0]); + else + qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_0]); + + if (s->status[0] & (1 << 1)) + qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_1]); + else + qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_1]); + + if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3]) + qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_X]); + else + qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_X]); +} + +/* Bitmap of pins used as standby and sleep wake-up sources. */ +const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { + 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f, +}; + +void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level) +{ + int bank; + uint32_t mask; + + if (line >= s->lines) { + printf("%s: No GPIO pin %i\n", __FUNCTION__, line); + return; + } + + bank = line >> 5; + mask = 1 << (line & 31); + + if (level) { + s->status[bank] |= s->rising[bank] & mask & + ~s->ilevel[bank] & ~s->dir[bank]; + s->ilevel[bank] |= mask; + } else { + s->status[bank] |= s->falling[bank] & mask & + s->ilevel[bank] & ~s->dir[bank]; + s->ilevel[bank] &= ~mask; + } + + if (s->status[bank] & mask) + pxa2xx_gpio_irq_update(s); + + /* Wake-up GPIOs */ + if (s->cpu_env->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB); +} + +static void pxa2xx_gpio_handler_update(struct pxa2xx_gpio_info_s *s) { + uint32_t level, diff; + int i, bit, line; + for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) { + level = s->olevel[i] & s->dir[i]; + + for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + line = bit + 32 * i; + if (s->handler[line].fn) + s->handler[line].fn(line, (level >> bit) & 1, + s->handler[line].opaque); + } + + s->prev_level[i] = level; + } +} + +static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque; + uint32_t ret; + int bank; + offset -= s->base; + if (offset >= 0x200) + return 0; + + bank = pxa2xx_gpio_regs[offset].bank; + switch (pxa2xx_gpio_regs[offset].reg) { + case GPDR: /* GPIO Pin-Direction registers */ + return s->dir[bank]; + + case GRER: /* GPIO Rising-Edge Detect Enable registers */ + return s->rising[bank]; + + case GFER: /* GPIO Falling-Edge Detect Enable registers */ + return s->falling[bank]; + + case GAFR_L: /* GPIO Alternate Function registers */ + return s->gafr[bank * 2]; + + case GAFR_U: /* GPIO Alternate Function registers */ + return s->gafr[bank * 2 + 1]; + + case GPLR: /* GPIO Pin-Level registers */ + ret = (s->olevel[bank] & s->dir[bank]) | + (s->ilevel[bank] & ~s->dir[bank]); + if (s->read_notify) + s->read_notify(s->opaque); + return ret; + + case GEDR: /* GPIO Edge Detect Status registers */ + return s->status[bank]; + + default: + cpu_abort(cpu_single_env, + "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + } + + return 0; +} + +static void pxa2xx_gpio_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque; + int bank; + offset -= s->base; + if (offset >= 0x200) + return; + + bank = pxa2xx_gpio_regs[offset].bank; + switch (pxa2xx_gpio_regs[offset].reg) { + case GPDR: /* GPIO Pin-Direction registers */ + s->dir[bank] = value; + pxa2xx_gpio_handler_update(s); + break; + + case GPSR: /* GPIO Pin-Output Set registers */ + s->olevel[bank] |= value; + pxa2xx_gpio_handler_update(s); + break; + + case GPCR: /* GPIO Pin-Output Clear registers */ + s->olevel[bank] &= ~value; + pxa2xx_gpio_handler_update(s); + break; + + case GRER: /* GPIO Rising-Edge Detect Enable registers */ + s->rising[bank] = value; + break; + + case GFER: /* GPIO Falling-Edge Detect Enable registers */ + s->falling[bank] = value; + break; + + case GAFR_L: /* GPIO Alternate Function registers */ + s->gafr[bank * 2] = value; + break; + + case GAFR_U: /* GPIO Alternate Function registers */ + s->gafr[bank * 2 + 1] = value; + break; + + case GEDR: /* GPIO Edge Detect Status registers */ + s->status[bank] &= ~value; + pxa2xx_gpio_irq_update(s); + break; + + default: + cpu_abort(cpu_single_env, + "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + } +} + +static CPUReadMemoryFunc *pxa2xx_gpio_readfn[] = { + pxa2xx_gpio_read, + pxa2xx_gpio_read, + pxa2xx_gpio_read +}; + +static CPUWriteMemoryFunc *pxa2xx_gpio_writefn[] = { + pxa2xx_gpio_write, + pxa2xx_gpio_write, + pxa2xx_gpio_write +}; + +struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, + CPUState *env, qemu_irq *pic, int lines) +{ + int iomemtype; + struct pxa2xx_gpio_info_s *s; + + s = (struct pxa2xx_gpio_info_s *) + qemu_mallocz(sizeof(struct pxa2xx_gpio_info_s)); + memset(s, 0, sizeof(struct pxa2xx_gpio_info_s)); + s->base = base; + s->pic = pic; + s->lines = lines; + s->cpu_env = env; + + iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn, + pxa2xx_gpio_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + + return s; +} + +void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line, + gpio_handler_t handler, void *opaque) { + if (line >= s->lines) { + printf("%s: No GPIO pin %i\n", __FUNCTION__, line); + return; + } + + s->handler[line].fn = handler; + s->handler[line].opaque = opaque; +} + +/* + * Registers a callback to notify on GPLR reads. This normally + * shouldn't be needed but it is used for the hack on Spitz machines. + */ +void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, + void (*handler)(void *opaque), void *opaque) { + s->read_notify = handler; + s->opaque = opaque; +} diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c new file mode 100644 index 000000000..e3cf24178 --- /dev/null +++ b/hw/pxa2xx_pic.c @@ -0,0 +1,280 @@ +/* + * Intel XScale PXA Programmable Interrupt Controller. + * + * Copyright (c) 2006 Openedhand Ltd. + * Copyright (c) 2006 Thorsten Zitterell + * Written by Andrzej Zaborowski + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ +#define ICMR 0x04 /* Interrupt Controller Mask register */ +#define ICLR 0x08 /* Interrupt Controller Level register */ +#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */ +#define ICPR 0x10 /* Interrupt Controller Pending register */ +#define ICCR 0x14 /* Interrupt Controller Control register */ +#define ICHP 0x18 /* Interrupt Controller Highest Priority register */ +#define IPR0 0x1c /* Interrupt Controller Priority register 0 */ +#define IPR31 0x98 /* Interrupt Controller Priority register 31 */ +#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */ +#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */ +#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */ +#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */ +#define ICPR2 0xac /* Interrupt Controller Pending register 2 */ +#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */ +#define IPR39 0xcc /* Interrupt Controller Priority register 39 */ + +#define PXA2XX_PIC_SRCS 40 + +struct pxa2xx_pic_state_s { + target_phys_addr_t base; + CPUState *cpu_env; + uint32_t int_enabled[2]; + uint32_t int_pending[2]; + uint32_t is_fiq[2]; + uint32_t int_idle; + uint32_t priority[PXA2XX_PIC_SRCS]; +}; + +static void pxa2xx_pic_update(void *opaque) +{ + uint32_t mask[2]; + struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; + + if (s->cpu_env->halted) { + mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); + mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); + if (mask[0] || mask[1]) + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB); + } + + mask[0] = s->int_pending[0] & s->int_enabled[0]; + mask[1] = s->int_pending[1] & s->int_enabled[1]; + + if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + else + cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + + if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); +} + +/* Note: Here level means state of the signal on a pin, not + * IRQ/FIQ distinction as in PXA Developer Manual. */ +static void pxa2xx_pic_set_irq(void *opaque, int irq, int level) +{ + struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; + int int_set = (irq >= 32); + irq &= 31; + + if (level) + s->int_pending[int_set] |= 1 << irq; + else + s->int_pending[int_set] &= ~(1 << irq); + + pxa2xx_pic_update(opaque); +} + +static inline uint32_t pxa2xx_pic_highest(struct pxa2xx_pic_state_s *s) { + int i, int_set, irq; + uint32_t bit, mask[2]; + uint32_t ichp = 0x003f003f; /* Both IDs invalid */ + + mask[0] = s->int_pending[0] & s->int_enabled[0]; + mask[1] = s->int_pending[1] & s->int_enabled[1]; + + for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) { + irq = s->priority[i] & 0x3f; + if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) { + /* Source peripheral ID is valid. */ + bit = 1 << (irq & 31); + int_set = (irq >= 32); + + if (mask[int_set] & bit & s->is_fiq[int_set]) { + /* FIQ asserted */ + ichp &= 0xffff0000; + ichp |= (1 << 15) | irq; + } + + if (mask[int_set] & bit & ~s->is_fiq[int_set]) { + /* IRQ asserted */ + ichp &= 0x0000ffff; + ichp |= (1 << 31) | (irq << 16); + } + } + } + + return ichp; +} + +static uint32_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; + offset -= s->base; + + switch (offset) { + case ICIP: /* IRQ Pending register */ + return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0]; + case ICIP2: /* IRQ Pending register 2 */ + return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1]; + case ICMR: /* Mask register */ + return s->int_enabled[0]; + case ICMR2: /* Mask register 2 */ + return s->int_enabled[1]; + case ICLR: /* Level register */ + return s->is_fiq[0]; + case ICLR2: /* Level register 2 */ + return s->is_fiq[1]; + case ICCR: /* Idle mask */ + return (s->int_idle == 0); + case ICFP: /* FIQ Pending register */ + return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0]; + case ICFP2: /* FIQ Pending register 2 */ + return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1]; + case ICPR: /* Pending register */ + return s->int_pending[0]; + case ICPR2: /* Pending register 2 */ + return s->int_pending[1]; + case IPR0 ... IPR31: + return s->priority[0 + ((offset - IPR0 ) >> 2)]; + case IPR32 ... IPR39: + return s->priority[32 + ((offset - IPR32) >> 2)]; + case ICHP: /* Highest Priority register */ + return pxa2xx_pic_highest(s); + default: + printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); + return 0; + } +} + +static void pxa2xx_pic_mem_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; + offset -= s->base; + + switch (offset) { + case ICMR: /* Mask register */ + s->int_enabled[0] = value; + break; + case ICMR2: /* Mask register 2 */ + s->int_enabled[1] = value; + break; + case ICLR: /* Level register */ + s->is_fiq[0] = value; + break; + case ICLR2: /* Level register 2 */ + s->is_fiq[1] = value; + break; + case ICCR: /* Idle mask */ + s->int_idle = (value & 1) ? 0 : ~0; + break; + case IPR0 ... IPR31: + s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f; + break; + case IPR32 ... IPR39: + s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f; + break; + default: + printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); + return; + } + pxa2xx_pic_update(opaque); +} + +/* Interrupt Controller Coprocessor Space Register Mapping */ +static const int pxa2xx_cp_reg_map[0x10] = { + [0x0 ... 0xf] = -1, + [0x0] = ICIP, + [0x1] = ICMR, + [0x2] = ICLR, + [0x3] = ICFP, + [0x4] = ICPR, + [0x5] = ICHP, + [0x6] = ICIP2, + [0x7] = ICMR2, + [0x8] = ICLR2, + [0x9] = ICFP2, + [0xa] = ICPR2, +}; + +static uint32_t pxa2xx_pic_cp_read(void *opaque, int op2, int reg, int crm) +{ + struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; + target_phys_addr_t offset; + + if (pxa2xx_cp_reg_map[reg] == -1) { + printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); + return 0; + } + + offset = s->base + pxa2xx_cp_reg_map[reg]; + return pxa2xx_pic_mem_read(opaque, offset); +} + +static void pxa2xx_pic_cp_write(void *opaque, int op2, int reg, int crm, + uint32_t value) +{ + struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; + target_phys_addr_t offset; + + if (pxa2xx_cp_reg_map[reg] == -1) { + printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); + return; + } + + offset = s->base + pxa2xx_cp_reg_map[reg]; + pxa2xx_pic_mem_write(opaque, offset, value); +} + +static CPUReadMemoryFunc *pxa2xx_pic_readfn[] = { + pxa2xx_pic_mem_read, + pxa2xx_pic_mem_read, + pxa2xx_pic_mem_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_pic_writefn[] = { + pxa2xx_pic_mem_write, + pxa2xx_pic_mem_write, + pxa2xx_pic_mem_write, +}; + +qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env) +{ + struct pxa2xx_pic_state_s *s; + int iomemtype; + qemu_irq *qi; + + s = (struct pxa2xx_pic_state_s *) + qemu_mallocz(sizeof(struct pxa2xx_pic_state_s)); + if (!s) + return NULL; + + s->cpu_env = env; + s->base = base; + + s->int_pending[0] = 0; + s->int_pending[1] = 0; + s->int_enabled[0] = 0; + s->int_enabled[1] = 0; + s->is_fiq[0] = 0; + s->is_fiq[1] = 0; + + qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS); + + /* Enable IC memory-mapped registers access. */ + iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn, + pxa2xx_pic_writefn, s); + cpu_register_physical_memory(base, 0x000fffff, iomemtype); + + /* Enable IC coprocessor access. */ + cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s); + + return qi; +} diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 68bf3fd0f..6e2ae905f 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -38,6 +38,11 @@ #define EXCP_FIQ 6 #define EXCP_BKPT 7 +typedef void ARMWriteCPFunc(void *opaque, int cp_info, + int srcreg, int operand, uint32_t value); +typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info, + int dstreg, int operand); + /* We currently assume float and double are IEEE single and double precision respectively. Doing runtime conversions is tricky because VFP registers may contain @@ -75,6 +80,7 @@ typedef struct CPUARMState { /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; + uint32_t c0_cachetype; uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ uint32_t c2; /* MMU translation table base. */ @@ -87,8 +93,16 @@ typedef struct CPUARMState { uint32_t c9_data; uint32_t c13_fcse; /* FCSE PID. */ uint32_t c13_context; /* Context ID. */ + uint32_t c15_cpar; /* XScale Coprocessor Access Register */ } cp15; + /* Coprocessor IO used by peripherals */ + struct { + ARMReadCPFunc *cp_read; + ARMWriteCPFunc *cp_write; + void *opaque; + } cp[15]; + /* Internal CPU feature flags. */ uint32_t features; @@ -204,10 +218,10 @@ enum arm_cpu_mode { #define ARM_VFP_FPINST 9 #define ARM_VFP_FPINST2 10 - enum arm_features { ARM_FEATURE_VFP, - ARM_FEATURE_AUXCR /* ARM1026 Auxiliary control register. */ + ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ + ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ }; static inline int arm_feature(CPUARMState *env, int feature) @@ -218,8 +232,24 @@ static inline int arm_feature(CPUARMState *env, int feature) void arm_cpu_list(void); void cpu_arm_set_model(CPUARMState *env, const char *name); -#define ARM_CPUID_ARM1026 0x4106a262 -#define ARM_CPUID_ARM926 0x41069265 +void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, + ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, + void *opaque); + +#define ARM_CPUID_ARM1026 0x4106a262 +#define ARM_CPUID_ARM926 0x41069265 +#define ARM_CPUID_PXA250 0x69052100 +#define ARM_CPUID_PXA255 0x69052d00 +#define ARM_CPUID_PXA260 0x69052903 +#define ARM_CPUID_PXA261 0x69052d05 +#define ARM_CPUID_PXA262 0x69052d06 +#define ARM_CPUID_PXA270 0x69054110 +#define ARM_CPUID_PXA270_A0 0x69054110 +#define ARM_CPUID_PXA270_A1 0x69054111 +#define ARM_CPUID_PXA270_B0 0x69054112 +#define ARM_CPUID_PXA270_B1 0x69054113 +#define ARM_CPUID_PXA270_C0 0x69054114 +#define ARM_CPUID_PXA270_C5 0x69054117 #if defined(CONFIG_USER_ONLY) #define TARGET_PAGE_BITS 12 diff --git a/target-arm/exec.h b/target-arm/exec.h index e73e12dc5..87c41b218 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -54,6 +54,8 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, void cpu_lock(void); void cpu_unlock(void); +void helper_set_cp(CPUState *, uint32_t, uint32_t); +uint32_t helper_get_cp(CPUState *, uint32_t); void helper_set_cp15(CPUState *, uint32_t, uint32_t); uint32_t helper_get_cp15(CPUState *, uint32_t); diff --git a/target-arm/helper.c b/target-arm/helper.c index bae4c9fdb..798df304e 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -17,11 +17,32 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) case ARM_CPUID_ARM926: set_feature(env, ARM_FEATURE_VFP); env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; + env->cp15.c0_cachetype = 0x1dd20d2; break; case ARM_CPUID_ARM1026: set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; + env->cp15.c0_cachetype = 0x1dd20d2; + break; + case ARM_CPUID_PXA250: + case ARM_CPUID_PXA255: + case ARM_CPUID_PXA260: + case ARM_CPUID_PXA261: + case ARM_CPUID_PXA262: + set_feature(env, ARM_FEATURE_XSCALE); + /* JTAG_ID is ((id << 28) | 0x09265013) */ + env->cp15.c0_cachetype = 0xd172172; + break; + case ARM_CPUID_PXA270_A0: + case ARM_CPUID_PXA270_A1: + case ARM_CPUID_PXA270_B0: + case ARM_CPUID_PXA270_B1: + case ARM_CPUID_PXA270_C0: + case ARM_CPUID_PXA270_C5: + set_feature(env, ARM_FEATURE_XSCALE); + /* JTAG_ID is ((id << 28) | 0x09265013) */ + env->cp15.c0_cachetype = 0xd172172; break; default: cpu_abort(env, "Bad CPU ID: %x\n", id); @@ -68,6 +89,18 @@ struct arm_cpu_t { static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_ARM926, "arm926"}, { ARM_CPUID_ARM1026, "arm1026"}, + { ARM_CPUID_PXA250, "pxa250" }, + { ARM_CPUID_PXA255, "pxa255" }, + { ARM_CPUID_PXA260, "pxa260" }, + { ARM_CPUID_PXA261, "pxa261" }, + { ARM_CPUID_PXA262, "pxa262" }, + { ARM_CPUID_PXA270, "pxa270" }, + { ARM_CPUID_PXA270_A0, "pxa270-a0" }, + { ARM_CPUID_PXA270_A1, "pxa270-a1" }, + { ARM_CPUID_PXA270_B0, "pxa270-b0" }, + { ARM_CPUID_PXA270_B1, "pxa270-b1" }, + { ARM_CPUID_PXA270_C0, "pxa270-c0" }, + { ARM_CPUID_PXA270_C5, "pxa270-c5" }, { 0, NULL} }; @@ -132,6 +165,20 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) } /* These should probably raise undefined insn exceptions. */ +void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return; +} + +uint32_t helper_get_cp(CPUState *env, uint32_t insn) +{ + int op1 = (insn >> 8) & 0xf; + cpu_abort(env, "cp%i insn %08x\n", op1, insn); + return 0; +} + void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) { cpu_abort(env, "cp15 insn %08x\n", insn); @@ -393,12 +440,16 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, ap = (desc >> (4 + ((address >> 13) & 6))) & 3; break; case 3: /* 1k page. */ - if (type == 1) { - /* Page translation fault. */ - code = 7; - goto do_fault; + if (arm_feature(env, ARM_FEATURE_XSCALE)) + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + else { + if (type == 1) { + /* Page translation fault. */ + code = 7; + goto do_fault; + } + phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); } - phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); ap = (desc >> 4) & 3; break; default: @@ -461,6 +512,31 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return phys_addr; } +void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val) +{ + int cp_num = (insn >> 8) & 0xf; + int cp_info = (insn >> 5) & 7; + int src = (insn >> 16) & 0xf; + int operand = insn & 0xf; + + if (env->cp[cp_num].cp_write) + env->cp[cp_num].cp_write(env->cp[cp_num].opaque, + cp_info, src, operand, val); +} + +uint32_t helper_get_cp(CPUState *env, uint32_t insn) +{ + int cp_num = (insn >> 8) & 0xf; + int cp_info = (insn >> 5) & 7; + int dest = (insn >> 16) & 0xf; + int operand = insn & 0xf; + + if (env->cp[cp_num].cp_read) + return env->cp[cp_num].cp_read(env->cp[cp_num].opaque, + cp_info, dest, operand); + return 0; +} + void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) { uint32_t op2; @@ -472,15 +548,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 1: /* System configuration. */ switch (op2) { case 0: - env->cp15.c1_sys = val; + if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0xf) == 0) + env->cp15.c1_sys = val; /* ??? Lots of these bits are not implemented. */ /* This may enable/disable the MMU, so do a TLB flush. */ tlb_flush(env, 1); break; + case 1: + /* XScale doesn't implement AUX CR (P-Bit) but allows + * writing with zero and reading. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + break; + goto bad_reg; case 2: env->cp15.c1_coproc = val; /* ??? Is this safe when called from within a TB? */ tb_flush(env); + break; default: goto bad_reg; } @@ -584,13 +668,21 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 14: /* Reserved. */ goto bad_reg; case 15: /* Implementation specific. */ - /* ??? Internal registers not implemented. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + if (op2 == 0 && (insn & 0xf) == 1) { + /* Changes cp0 to cp13 behavior, so needs a TB flush. */ + tb_flush(env); + env->cp15.c15_cpar = (val & 0x3fff) | 2; + break; + } + goto bad_reg; + } break; } return; bad_reg: /* ??? For debugging only. Should raise illegal instruction exception. */ - cpu_abort(env, "Unimplemented cp15 register read\n"); + cpu_abort(env, "Unimplemented cp15 register write\n"); } uint32_t helper_get_cp15(CPUState *env, uint32_t insn) @@ -604,7 +696,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) default: /* Device ID. */ return env->cp15.c0_cpuid; case 1: /* Cache Type. */ - return 0x1dd20d2; + return env->cp15.c0_cachetype; case 2: /* TCM status. */ return 0; } @@ -615,6 +707,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 1: /* Auxiliary control register. */ if (arm_feature(env, ARM_FEATURE_AUXCR)) return 1; + if (arm_feature(env, ARM_FEATURE_XSCALE)) + return 0; goto bad_reg; case 2: /* Coprocessor access register. */ return env->cp15.c1_coproc; @@ -649,7 +743,7 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) } case 7: /* Cache control. */ /* ??? This is for test, clean and invaidate operations that set the - Z flag. We can't represent N = Z = 1, so it also clears clears + Z flag. We can't represent N = Z = 1, so it also clears the N flag. Oh well. */ env->NZF = 0; return 0; @@ -682,7 +776,12 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 14: /* Reserved. */ goto bad_reg; case 15: /* Implementation specific. */ - /* ??? Internal registers not implemented. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + if (op2 == 0 && (insn & 0xf) == 1) + return env->cp15.c15_cpar; + + goto bad_reg; + } return 0; } bad_reg: @@ -691,4 +790,18 @@ bad_reg: return 0; } +void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, + ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, + void *opaque) +{ + if (cpnum < 0 || cpnum > 14) { + cpu_abort(env, "Bad coprocessor number: %i\n", cpnum); + return; + } + + env->cp[cpnum].cp_read = cp_read; + env->cp[cpnum].cp_write = cp_write; + env->cp[cpnum].opaque = opaque; +} + #endif diff --git a/target-arm/op.c b/target-arm/op.c index f17b81273..9cfb46237 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -1142,12 +1142,24 @@ void OPPROTO op_vfp_mdrr(void) FT0d = u.d; } -/* Copy the most significant bit to T0 to all bits of T1. */ +/* Copy the most significant bit of T0 to all bits of T1. */ void OPPROTO op_signbit_T1_T0(void) { T1 = (int32_t)T0 >> 31; } +void OPPROTO op_movl_cp_T0(void) +{ + helper_set_cp(env, PARAM1, T0); + FORCE_RET(); +} + +void OPPROTO op_movl_T0_cp(void) +{ + T0 = helper_get_cp(env, PARAM1); + FORCE_RET(); +} + void OPPROTO op_movl_cp15_T0(void) { helper_set_cp15(env, PARAM1, T0); diff --git a/target-arm/translate.c b/target-arm/translate.c index 1631fcd31..65d234ae0 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -492,6 +492,34 @@ static inline void gen_mov_vreg_F0(int dp, int reg) gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); } +/* Disassemble system coprocessor instruction. Return nonzero if + instruction is not defined. */ +static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + uint32_t rd = (insn >> 12) & 0xf; + uint32_t cp = (insn >> 8) & 0xf; + if (IS_USER(s)) { + return 1; + } + + if (insn & (1 << 20)) { + if (!env->cp[cp].cp_read) + return 1; + gen_op_movl_T0_im((uint32_t) s->pc); + gen_op_movl_reg_TN[0][15](); + gen_op_movl_T0_cp(insn); + gen_movl_reg_T0(s, rd); + } else { + if (!env->cp[cp].cp_write) + return 1; + gen_op_movl_T0_im((uint32_t) s->pc); + gen_op_movl_reg_TN[0][15](); + gen_movl_T0_reg(s, rd); + gen_op_movl_cp_T0(insn); + } + return 0; +} + /* Disassemble system coprocessor (cp15) instruction. Return nonzero if instruction is not defined. */ static int disas_cp15_insn(DisasContext *s, uint32_t insn) @@ -1812,7 +1840,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0xe: /* Coprocessor. */ op1 = (insn >> 8) & 0xf; + if (arm_feature(env, ARM_FEATURE_XSCALE) && + ((env->cp15.c15_cpar ^ 0x3fff) & (1 << op1))) + goto illegal_op; switch (op1) { + case 0 ... 1: + case 2 ... 9: + case 12 ... 14: + if (disas_cp_insn (env, s, insn)) + goto illegal_op; + break; case 10: case 11: if (disas_vfp_insn (env, s, insn)) diff --git a/vl.h b/vl.h index 09db43ef3..3b12d372c 100644 --- a/vl.h +++ b/vl.h @@ -1525,6 +1525,8 @@ struct pcmcia_card_s { /* dscm1xxxx.c */ struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv); +#include "hw/pxa.h" + #include "gdbstub.h" #endif /* defined(QEMU_TOOL) */ -- cgit v1.2.3 From 2bac601963afc6777692777c2e19666b589e85cd Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 01:34:31 +0000 Subject: Remove repeated code and enable encrypted SD cards and USB sticks images. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2750 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-msd.c | 2 ++ monitor.c | 12 +----------- vl.c | 38 ++++++++++++++++++++++++-------------- vl.h | 2 ++ 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 251bd64b2..08fc5c335 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -522,6 +522,8 @@ USBDevice *usb_msd_init(const char *filename) bdrv = bdrv_new("usb"); if (bdrv_open(bdrv, filename, 0) < 0) goto fail; + if (qemu_key_check(bdrv, filename)) + goto fail; s->bs = bdrv; s->dev.speed = USB_SPEED_FULL; diff --git a/monitor.c b/monitor.c index ed03b345e..9f76c0976 100644 --- a/monitor.c +++ b/monitor.c @@ -386,8 +386,6 @@ static void do_eject(int force, const char *filename) static void do_change(const char *device, const char *filename) { BlockDriverState *bs; - int i; - char password[256]; bs = bdrv_find(device); if (!bs) { @@ -397,15 +395,7 @@ static void do_change(const char *device, const char *filename) if (eject_device(bs, 0) < 0) return; bdrv_open(bs, filename, 0); - if (bdrv_is_encrypted(bs)) { - term_printf("%s is encrypted.\n", device); - for(i = 0; i < 3; i++) { - monitor_readline("Password: ", 1, password, sizeof(password)); - if (bdrv_set_key(bs, password) == 0) - break; - term_printf("invalid password\n"); - } - } + qemu_key_check(bs, filename); } static void do_screen_dump(const char *filename) diff --git a/vl.c b/vl.c index 8707a1f96..bb36281e7 100644 --- a/vl.c +++ b/vl.c @@ -6714,6 +6714,24 @@ static uint8_t *signal_stack; /* password input */ +int qemu_key_check(BlockDriverState *bs, const char *name) +{ + char password[256]; + int i; + + if (!bdrv_is_encrypted(bs)) + return 0; + + term_printf("%s is encrypted.\n", name); + for(i = 0; i < 3; i++) { + monitor_readline("Password: ", 1, password, sizeof(password)); + if (bdrv_set_key(bs, password) == 0) + return 0; + term_printf("invalid password\n"); + } + return -EPERM; +} + static BlockDriverState *get_bdrv(int index) { BlockDriverState *bs; @@ -6731,21 +6749,12 @@ static BlockDriverState *get_bdrv(int index) static void read_passwords(void) { BlockDriverState *bs; - int i, j; - char password[256]; + int i; for(i = 0; i < 6; i++) { bs = get_bdrv(i); - if (bs && bdrv_is_encrypted(bs)) { - term_printf("%s is encrypted.\n", bdrv_get_device_name(bs)); - for(j = 0; j < 3; j++) { - monitor_readline("Password: ", - 1, password, sizeof(password)); - if (bdrv_set_key(bs, password) == 0) - break; - term_printf("invalid password\n"); - } - } + if (bs) + qemu_key_check(bs, bdrv_get_device_name(bs)); } } @@ -7622,7 +7631,7 @@ int main(int argc, char **argv) } } - /* Open the virtual parallel flash bloc devices */ + /* Open the virtual parallel flash block devices */ for(i = 0; i < MAX_PFLASH; i++) { if (pflash_filename[i]) { if (!pflash_table[i]) { @@ -7648,7 +7657,8 @@ int main(int argc, char **argv) snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { fprintf(stderr, "qemu: could not open SD card image %s\n", sd_filename); - } + } else + qemu_key_check(bs, sd_filename); } register_savevm("timer", 0, 2, timer_save, timer_load, NULL); diff --git a/vl.h b/vl.h index 3b12d372c..7bc3eba62 100644 --- a/vl.h +++ b/vl.h @@ -632,6 +632,8 @@ void qemu_aio_wait_start(void); void qemu_aio_wait(void); void qemu_aio_wait_end(void); +int qemu_key_check(BlockDriverState *bs, const char *name); + /* Ensure contents are flushed to disk. */ void bdrv_flush(BlockDriverState *bs); -- cgit v1.2.3 From a171fe394a82e3a2dad76e901959d859b1966541 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 01:48:07 +0000 Subject: Add remaining PXA2xx on-chip peripherals except I2C master. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2751 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa.h | 32 ++ hw/pxa2xx.c | 29 ++ hw/pxa2xx_lcd.c | 1001 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pxa2xx_mmci.c | 472 ++++++++++++++++++++++++ hw/pxa2xx_pcmcia.c | 224 +++++++++++ hw/pxa2xx_template.h | 431 ++++++++++++++++++++++ hw/pxa2xx_timer.c | 433 ++++++++++++++++++++++ vl.c | 21 +- vl.h | 1 + 9 files changed, 2642 insertions(+), 2 deletions(-) create mode 100644 hw/pxa2xx_lcd.c create mode 100644 hw/pxa2xx_mmci.c create mode 100644 hw/pxa2xx_pcmcia.c create mode 100644 hw/pxa2xx_template.h create mode 100644 hw/pxa2xx_timer.c diff --git a/hw/pxa.h b/hw/pxa.h index 8a4ffa8c4..d6d87c62b 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -63,6 +63,12 @@ struct pxa2xx_pic_state_s; qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env); +/* pxa2xx_timer.c */ +void pxa25x_timer_init(target_phys_addr_t base, + qemu_irq *irqs, CPUState *cpustate); +void pxa27x_timer_init(target_phys_addr_t base, + qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate); + /* pxa2xx_gpio.c */ struct pxa2xx_gpio_info_s; struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, @@ -81,6 +87,29 @@ struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base, qemu_irq irq); void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on); +/* pxa2xx_lcd.c */ +struct pxa2xx_lcdc_s; +struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, + qemu_irq irq, DisplayState *ds); +void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s, + void (*cb)(void *opaque), void *opaque); +void pxa2xx_lcdc_oritentation(void *opaque, int angle); + +/* pxa2xx_mmci.c */ +struct pxa2xx_mmci_s; +struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, + qemu_irq irq, void *dma); +void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque, + void (*readonly_cb)(void *, int), + void (*coverswitch_cb)(void *, int)); + +/* pxa2xx_pcmcia.c */ +struct pxa2xx_pcmcia_s; +struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base); +int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card); +int pxa2xx_pcmcia_dettach(void *opaque); +void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq); + /* pxa2xx.c */ struct pxa2xx_ssp_s; void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, @@ -95,7 +124,10 @@ struct pxa2xx_state_s { qemu_irq *pic; struct pxa2xx_dma_state_s *dma; struct pxa2xx_gpio_info_s *gpio; + struct pxa2xx_lcdc_s *lcd; struct pxa2xx_ssp_s **ssp; + struct pxa2xx_mmci_s *mmc; + struct pxa2xx_pcmcia_s *pcmcia[2]; struct pxa2xx_i2s_s *i2s; struct pxa2xx_fir_s *fir; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index f9d2925bf..d49e851d3 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1531,8 +1531,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); + pxa27x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0], + s->pic[PXA27X_PIC_OST_4_11], s->env); + s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); + s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma); + for (i = 0; pxa270_serial[i].io_base; i ++) if (serial_hds[i]) serial_mm_init(pxa270_serial[i].io_base, 2, @@ -1543,6 +1548,9 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], s->dma, serial_hds[i]); + if (ds) + s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds); + s->cm_base = 0x41300000; s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ s->clkcfg = 0x00000009; /* Turbo mode active */ @@ -1575,6 +1583,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); } + if (usb_enabled) { + usb_ohci_init_pxa(0x4c000000, 3, -1, s->pic[PXA2XX_PIC_USBH1]); + } + + s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000); + s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000); + s->rtc_base = 0x40900000; iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, pxa2xx_rtc_writefn, s); @@ -1609,8 +1624,12 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); + pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0], s->env); + s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); + s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma); + for (i = 0; pxa255_serial[i].io_base; i ++) if (serial_hds[i]) serial_mm_init(pxa255_serial[i].io_base, 2, @@ -1621,6 +1640,9 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP], s->dma, serial_hds[i]); + if (ds) + s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds); + s->cm_base = 0x41300000; s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ s->clkcfg = 0x00000009; /* Turbo mode active */ @@ -1653,6 +1675,13 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); } + if (usb_enabled) { + usb_ohci_init_pxa(0x4c000000, 3, -1, s->pic[PXA2XX_PIC_USBH1]); + } + + s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000); + s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000); + s->rtc_base = 0x40900000; iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, pxa2xx_rtc_writefn, s); diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c new file mode 100644 index 000000000..a599dd768 --- /dev/null +++ b/hw/pxa2xx_lcd.c @@ -0,0 +1,1001 @@ +/* + * Intel XScale PXA255/270 LCDC emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPLv2. + */ + +#include "vl.h" + +typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int); + +struct pxa2xx_lcdc_s { + target_phys_addr_t base; + qemu_irq irq; + int irqlevel; + + int invalidated; + DisplayState *ds; + drawfn *line_fn[2]; + int dest_width; + int xres, yres; + int pal_for; + int transp; + enum { + pxa_lcdc_2bpp = 1, + pxa_lcdc_4bpp = 2, + pxa_lcdc_8bpp = 3, + pxa_lcdc_16bpp = 4, + pxa_lcdc_18bpp = 5, + pxa_lcdc_18pbpp = 6, + pxa_lcdc_19bpp = 7, + pxa_lcdc_19pbpp = 8, + pxa_lcdc_24bpp = 9, + pxa_lcdc_25bpp = 10, + } bpp; + + uint32_t control[6]; + uint32_t status[2]; + uint32_t ovl1c[2]; + uint32_t ovl2c[2]; + uint32_t ccr; + uint32_t cmdcr; + uint32_t trgbr; + uint32_t tcr; + uint32_t liidr; + uint8_t bscntr; + + struct { + target_phys_addr_t branch; + int up; + uint8_t palette[1024]; + uint8_t pbuffer[1024]; + void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb, + int *miny, int *maxy); + + target_phys_addr_t descriptor; + target_phys_addr_t source; + uint32_t id; + uint32_t command; + } dma_ch[7]; + + void (*vsync_cb)(void *opaque); + void *opaque; + int orientation; +}; + +struct __attribute__ ((__packed__)) pxa_frame_descriptor_s { + uint32_t fdaddr; + uint32_t fsaddr; + uint32_t fidr; + uint32_t ldcmd; +}; + +#define LCCR0 0x000 /* LCD Controller Control register 0 */ +#define LCCR1 0x004 /* LCD Controller Control register 1 */ +#define LCCR2 0x008 /* LCD Controller Control register 2 */ +#define LCCR3 0x00c /* LCD Controller Control register 3 */ +#define LCCR4 0x010 /* LCD Controller Control register 4 */ +#define LCCR5 0x014 /* LCD Controller Control register 5 */ + +#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */ +#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */ +#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */ +#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */ +#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */ +#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */ +#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */ + +#define LCSR1 0x034 /* LCD Controller Status register 1 */ +#define LCSR0 0x038 /* LCD Controller Status register 0 */ +#define LIIDR 0x03c /* LCD Controller Interrupt ID register */ + +#define TRGBR 0x040 /* TMED RGB Seed register */ +#define TCR 0x044 /* TMED Control register */ + +#define OVL1C1 0x050 /* Overlay 1 Control register 1 */ +#define OVL1C2 0x060 /* Overlay 1 Control register 2 */ +#define OVL2C1 0x070 /* Overlay 2 Control register 1 */ +#define OVL2C2 0x080 /* Overlay 2 Control register 2 */ +#define CCR 0x090 /* Cursor Control register */ + +#define CMDCR 0x100 /* Command Control register */ +#define PRSR 0x104 /* Panel Read Status register */ + +#define PXA_LCDDMA_CHANS 7 +#define DMA_FDADR 0x00 /* Frame Descriptor Address register */ +#define DMA_FSADR 0x04 /* Frame Source Address register */ +#define DMA_FIDR 0x08 /* Frame ID register */ +#define DMA_LDCMD 0x0c /* Command register */ + +/* LCD Buffer Strength Control register */ +#define BSCNTR 0x04000054 + +/* Bitfield masks */ +#define LCCR0_ENB (1 << 0) +#define LCCR0_CMS (1 << 1) +#define LCCR0_SDS (1 << 2) +#define LCCR0_LDM (1 << 3) +#define LCCR0_SOFM0 (1 << 4) +#define LCCR0_IUM (1 << 5) +#define LCCR0_EOFM0 (1 << 6) +#define LCCR0_PAS (1 << 7) +#define LCCR0_DPD (1 << 9) +#define LCCR0_DIS (1 << 10) +#define LCCR0_QDM (1 << 11) +#define LCCR0_PDD (0xff << 12) +#define LCCR0_BSM0 (1 << 20) +#define LCCR0_OUM (1 << 21) +#define LCCR0_LCDT (1 << 22) +#define LCCR0_RDSTM (1 << 23) +#define LCCR0_CMDIM (1 << 24) +#define LCCR0_OUC (1 << 25) +#define LCCR0_LDDALT (1 << 26) +#define LCCR1_PPL(x) ((x) & 0x3ff) +#define LCCR2_LPP(x) ((x) & 0x3ff) +#define LCCR3_API (15 << 16) +#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8)) +#define LCCR3_PDFOR(x) (((x) >> 30) & 3) +#define LCCR4_K1(x) (((x) >> 0) & 7) +#define LCCR4_K2(x) (((x) >> 3) & 7) +#define LCCR4_K3(x) (((x) >> 6) & 7) +#define LCCR4_PALFOR(x) (((x) >> 15) & 3) +#define LCCR5_SOFM(ch) (1 << (ch - 1)) +#define LCCR5_EOFM(ch) (1 << (ch + 7)) +#define LCCR5_BSM(ch) (1 << (ch + 15)) +#define LCCR5_IUM(ch) (1 << (ch + 23)) +#define OVLC1_EN (1 << 31) +#define CCR_CEN (1 << 31) +#define FBR_BRA (1 << 0) +#define FBR_BINT (1 << 1) +#define FBR_SRCADDR (0xfffffff << 4) +#define LCSR0_LDD (1 << 0) +#define LCSR0_SOF0 (1 << 1) +#define LCSR0_BER (1 << 2) +#define LCSR0_ABC (1 << 3) +#define LCSR0_IU0 (1 << 4) +#define LCSR0_IU1 (1 << 5) +#define LCSR0_OU (1 << 6) +#define LCSR0_QD (1 << 7) +#define LCSR0_EOF0 (1 << 8) +#define LCSR0_BS0 (1 << 9) +#define LCSR0_SINT (1 << 10) +#define LCSR0_RDST (1 << 11) +#define LCSR0_CMDINT (1 << 12) +#define LCSR0_BERCH(x) (((x) & 7) << 28) +#define LCSR1_SOF(ch) (1 << (ch - 1)) +#define LCSR1_EOF(ch) (1 << (ch + 7)) +#define LCSR1_BS(ch) (1 << (ch + 15)) +#define LCSR1_IU(ch) (1 << (ch + 23)) +#define LDCMD_LENGTH(x) ((x) & 0x001ffffc) +#define LDCMD_EOFINT (1 << 21) +#define LDCMD_SOFINT (1 << 22) +#define LDCMD_PAL (1 << 26) + +/* Route internal interrupt lines to the global IC */ +static void pxa2xx_lcdc_int_update(struct pxa2xx_lcdc_s *s) +{ + int level = 0; + level |= (s->status[0] & LCSR0_LDD) && !(s->control[0] & LCCR0_LDM); + level |= (s->status[0] & LCSR0_SOF0) && !(s->control[0] & LCCR0_SOFM0); + level |= (s->status[0] & LCSR0_IU0) && !(s->control[0] & LCCR0_IUM); + level |= (s->status[0] & LCSR0_IU1) && !(s->control[5] & LCCR5_IUM(1)); + level |= (s->status[0] & LCSR0_OU) && !(s->control[0] & LCCR0_OUM); + level |= (s->status[0] & LCSR0_QD) && !(s->control[0] & LCCR0_QDM); + level |= (s->status[0] & LCSR0_EOF0) && !(s->control[0] & LCCR0_EOFM0); + level |= (s->status[0] & LCSR0_BS0) && !(s->control[0] & LCCR0_BSM0); + level |= (s->status[0] & LCSR0_RDST) && !(s->control[0] & LCCR0_RDSTM); + level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM); + level |= (s->status[1] & ~s->control[5]); + + qemu_set_irq(s->irq, !!level); + s->irqlevel = level; +} + +/* Set Branch Status interrupt high and poke associated registers */ +static inline void pxa2xx_dma_bs_set(struct pxa2xx_lcdc_s *s, int ch) +{ + int unmasked; + if (ch == 0) { + s->status[0] |= LCSR0_BS0; + unmasked = !(s->control[0] & LCCR0_BSM0); + } else { + s->status[1] |= LCSR1_BS(ch); + unmasked = !(s->control[5] & LCCR5_BSM(ch)); + } + + if (unmasked) { + if (s->irqlevel) + s->status[0] |= LCSR0_SINT; + else + s->liidr = s->dma_ch[ch].id; + } +} + +/* Set Start Of Frame Status interrupt high and poke associated registers */ +static inline void pxa2xx_dma_sof_set(struct pxa2xx_lcdc_s *s, int ch) +{ + int unmasked; + if (!(s->dma_ch[ch].command & LDCMD_SOFINT)) + return; + + if (ch == 0) { + s->status[0] |= LCSR0_SOF0; + unmasked = !(s->control[0] & LCCR0_SOFM0); + } else { + s->status[1] |= LCSR1_SOF(ch); + unmasked = !(s->control[5] & LCCR5_SOFM(ch)); + } + + if (unmasked) { + if (s->irqlevel) + s->status[0] |= LCSR0_SINT; + else + s->liidr = s->dma_ch[ch].id; + } +} + +/* Set End Of Frame Status interrupt high and poke associated registers */ +static inline void pxa2xx_dma_eof_set(struct pxa2xx_lcdc_s *s, int ch) +{ + int unmasked; + if (!(s->dma_ch[ch].command & LDCMD_EOFINT)) + return; + + if (ch == 0) { + s->status[0] |= LCSR0_EOF0; + unmasked = !(s->control[0] & LCCR0_EOFM0); + } else { + s->status[1] |= LCSR1_EOF(ch); + unmasked = !(s->control[5] & LCCR5_EOFM(ch)); + } + + if (unmasked) { + if (s->irqlevel) + s->status[0] |= LCSR0_SINT; + else + s->liidr = s->dma_ch[ch].id; + } +} + +/* Set Bus Error Status interrupt high and poke associated registers */ +static inline void pxa2xx_dma_ber_set(struct pxa2xx_lcdc_s *s, int ch) +{ + s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER; + if (s->irqlevel) + s->status[0] |= LCSR0_SINT; + else + s->liidr = s->dma_ch[ch].id; +} + +/* Set Read Status interrupt high and poke associated registers */ +static inline void pxa2xx_dma_rdst_set(struct pxa2xx_lcdc_s *s) +{ + s->status[0] |= LCSR0_RDST; + if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM)) + s->status[0] |= LCSR0_SINT; +} + +/* Load new Frame Descriptors from DMA */ +static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s) +{ + struct pxa_frame_descriptor_s *desc[PXA_LCDDMA_CHANS]; + target_phys_addr_t descptr; + int i; + + for (i = 0; i < PXA_LCDDMA_CHANS; i ++) { + desc[i] = 0; + s->dma_ch[i].source = 0; + + if (!s->dma_ch[i].up) + continue; + + if (s->dma_ch[i].branch & FBR_BRA) { + descptr = s->dma_ch[i].branch & FBR_SRCADDR; + if (s->dma_ch[i].branch & FBR_BINT) + pxa2xx_dma_bs_set(s, i); + s->dma_ch[i].branch &= ~FBR_BRA; + } else + descptr = s->dma_ch[i].descriptor; + + if (!(descptr >= PXA2XX_RAM_BASE && descptr + + sizeof(*desc[i]) <= PXA2XX_RAM_BASE + phys_ram_size)) + continue; + + descptr -= PXA2XX_RAM_BASE; + desc[i] = (struct pxa_frame_descriptor_s *) (phys_ram_base + descptr); + s->dma_ch[i].descriptor = desc[i]->fdaddr; + s->dma_ch[i].source = desc[i]->fsaddr; + s->dma_ch[i].id = desc[i]->fidr; + s->dma_ch[i].command = desc[i]->ldcmd; + } +} + +static uint32_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; + int ch; + offset -= s->base; + + switch (offset) { + case LCCR0: + return s->control[0]; + case LCCR1: + return s->control[1]; + case LCCR2: + return s->control[2]; + case LCCR3: + return s->control[3]; + case LCCR4: + return s->control[4]; + case LCCR5: + return s->control[5]; + + case OVL1C1: + return s->ovl1c[0]; + case OVL1C2: + return s->ovl1c[1]; + case OVL2C1: + return s->ovl2c[0]; + case OVL2C2: + return s->ovl2c[1]; + + case CCR: + return s->ccr; + + case CMDCR: + return s->cmdcr; + + case TRGBR: + return s->trgbr; + case TCR: + return s->tcr; + + case 0x200 ... 0x1000: /* DMA per-channel registers */ + ch = (offset - 0x200) >> 4; + if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) + goto fail; + + switch (offset & 0xf) { + case DMA_FDADR: + return s->dma_ch[ch].descriptor; + case DMA_FSADR: + return s->dma_ch[ch].source; + case DMA_FIDR: + return s->dma_ch[ch].id; + case DMA_LDCMD: + return s->dma_ch[ch].command; + default: + goto fail; + } + + case FBR0: + return s->dma_ch[0].branch; + case FBR1: + return s->dma_ch[1].branch; + case FBR2: + return s->dma_ch[2].branch; + case FBR3: + return s->dma_ch[3].branch; + case FBR4: + return s->dma_ch[4].branch; + case FBR5: + return s->dma_ch[5].branch; + case FBR6: + return s->dma_ch[6].branch; + + case BSCNTR: + return s->bscntr; + + case PRSR: + return 0; + + case LCSR0: + return s->status[0]; + case LCSR1: + return s->status[1]; + case LIIDR: + return s->liidr; + + default: + fail: + cpu_abort(cpu_single_env, + "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + } + + return 0; +} + +static void pxa2xx_lcdc_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; + int ch; + offset -= s->base; + + switch (offset) { + case LCCR0: + /* ACK Quick Disable done */ + if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB)) + s->status[0] |= LCSR0_QD; + + if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) + printf("%s: internal frame buffer unsupported\n", __FUNCTION__); + + if ((s->control[3] & LCCR3_API) && + (value & LCCR0_ENB) && !(value & LCCR0_LCDT)) + s->status[0] |= LCSR0_ABC; + + s->control[0] = value & 0x07ffffff; + pxa2xx_lcdc_int_update(s); + + s->dma_ch[0].up = !!(value & LCCR0_ENB); + s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS); + break; + + case LCCR1: + s->control[1] = value; + break; + + case LCCR2: + s->control[2] = value; + break; + + case LCCR3: + s->control[3] = value & 0xefffffff; + s->bpp = LCCR3_BPP(value); + break; + + case LCCR4: + s->control[4] = value & 0x83ff81ff; + break; + + case LCCR5: + s->control[5] = value & 0x3f3f3f3f; + break; + + case OVL1C1: + if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) + printf("%s: Overlay 1 not supported\n", __FUNCTION__); + + s->ovl1c[0] = value & 0x80ffffff; + s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS); + break; + + case OVL1C2: + s->ovl1c[1] = value & 0x000fffff; + break; + + case OVL2C1: + if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) + printf("%s: Overlay 2 not supported\n", __FUNCTION__); + + s->ovl2c[0] = value & 0x80ffffff; + s->dma_ch[2].up = !!(value & OVLC1_EN); + s->dma_ch[3].up = !!(value & OVLC1_EN); + s->dma_ch[4].up = !!(value & OVLC1_EN); + break; + + case OVL2C2: + s->ovl2c[1] = value & 0x007fffff; + break; + + case CCR: + if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) + printf("%s: Hardware cursor unimplemented\n", __FUNCTION__); + + s->ccr = value & 0x81ffffe7; + s->dma_ch[5].up = !!(value & CCR_CEN); + break; + + case CMDCR: + s->cmdcr = value & 0xff; + break; + + case TRGBR: + s->trgbr = value & 0x00ffffff; + break; + + case TCR: + s->tcr = value & 0x7fff; + break; + + case 0x200 ... 0x1000: /* DMA per-channel registers */ + ch = (offset - 0x200) >> 4; + if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS)) + goto fail; + + switch (offset & 0xf) { + case DMA_FDADR: + s->dma_ch[ch].descriptor = value & 0xfffffff0; + break; + + default: + goto fail; + } + break; + + case FBR0: + s->dma_ch[0].branch = value & 0xfffffff3; + break; + case FBR1: + s->dma_ch[1].branch = value & 0xfffffff3; + break; + case FBR2: + s->dma_ch[2].branch = value & 0xfffffff3; + break; + case FBR3: + s->dma_ch[3].branch = value & 0xfffffff3; + break; + case FBR4: + s->dma_ch[4].branch = value & 0xfffffff3; + break; + case FBR5: + s->dma_ch[5].branch = value & 0xfffffff3; + break; + case FBR6: + s->dma_ch[6].branch = value & 0xfffffff3; + break; + + case BSCNTR: + s->bscntr = value & 0xf; + break; + + case PRSR: + break; + + case LCSR0: + s->status[0] &= ~(value & 0xfff); + if (value & LCSR0_BER) + s->status[0] &= ~LCSR0_BERCH(7); + break; + + case LCSR1: + s->status[1] &= ~(value & 0x3e3f3f); + break; + + default: + fail: + cpu_abort(cpu_single_env, + "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + } +} + +static CPUReadMemoryFunc *pxa2xx_lcdc_readfn[] = { + pxa2xx_lcdc_read, + pxa2xx_lcdc_read, + pxa2xx_lcdc_read +}; + +static CPUWriteMemoryFunc *pxa2xx_lcdc_writefn[] = { + pxa2xx_lcdc_write, + pxa2xx_lcdc_write, + pxa2xx_lcdc_write +}; + +static inline +uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); +} + +static inline +uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); +} + +static inline +uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) +{ + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); +} + +static inline +uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b) +{ + return (r << 16) | (g << 8) | b; +} + +static inline +uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) +{ + return (r << 16) | (g << 8) | b; +} + +/* Load new palette for a given DMA channel, convert to internal format */ +static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp) +{ + int i, n, format, r, g, b, alpha; + uint32_t *dest, *src; + s->pal_for = LCCR4_PALFOR(s->control[4]); + format = s->pal_for; + + switch (bpp) { + case pxa_lcdc_2bpp: + n = 4; + break; + case pxa_lcdc_4bpp: + n = 16; + break; + case pxa_lcdc_8bpp: + n = 256; + break; + default: + format = 0; + return; + } + + src = (uint32_t *) s->dma_ch[ch].pbuffer; + dest = (uint32_t *) s->dma_ch[ch].palette; + alpha = r = g = b = 0; + + for (i = 0; i < n; i ++) { + switch (format) { + case 0: /* 16 bpp, no transparency */ + alpha = 0; + if (s->control[0] & LCCR0_CMS) + r = g = b = *src & 0xff; + else { + r = (*src & 0xf800) >> 8; + g = (*src & 0x07e0) >> 3; + b = (*src & 0x001f) << 3; + } + break; + case 1: /* 16 bpp plus transparency */ + alpha = *src & (1 << 24); + if (s->control[0] & LCCR0_CMS) + r = g = b = *src & 0xff; + else { + r = (*src & 0xf800) >> 8; + g = (*src & 0x07e0) >> 3; + b = (*src & 0x001f) << 3; + } + break; + case 2: /* 18 bpp plus transparency */ + alpha = *src & (1 << 24); + if (s->control[0] & LCCR0_CMS) + r = g = b = *src & 0xff; + else { + r = (*src & 0xf80000) >> 16; + g = (*src & 0x00fc00) >> 8; + b = (*src & 0x0000f8); + } + break; + case 3: /* 24 bpp plus transparency */ + alpha = *src & (1 << 24); + if (s->control[0] & LCCR0_CMS) + r = g = b = *src & 0xff; + else { + r = (*src & 0xff0000) >> 16; + g = (*src & 0x00ff00) >> 8; + b = (*src & 0x0000ff); + } + break; + } + switch (s->ds->depth) { + case 8: + *dest = rgb_to_pixel8(r, g, b) | alpha; + break; + case 15: + *dest = rgb_to_pixel15(r, g, b) | alpha; + break; + case 16: + *dest = rgb_to_pixel16(r, g, b) | alpha; + break; + case 24: + *dest = rgb_to_pixel24(r, g, b) | alpha; + break; + case 32: + *dest = rgb_to_pixel32(r, g, b) | alpha; + break; + } + src ++; + dest ++; + } +} + +static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s, + uint8_t *fb, int *miny, int *maxy) +{ + int y, src_width, dest_width, dirty[2]; + uint8_t *src, *dest; + ram_addr_t x, addr, new_addr, start, end; + drawfn fn = 0; + if (s->dest_width) + fn = s->line_fn[s->transp][s->bpp]; + if (!fn) + return; + + src = fb; + src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ + if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) + src_width *= 3; + else if (s->bpp > pxa_lcdc_16bpp) + src_width *= 4; + else if (s->bpp > pxa_lcdc_8bpp) + src_width *= 2; + + dest = s->ds->data; + dest_width = s->xres * s->dest_width; + + addr = (ram_addr_t) (fb - phys_ram_base); + start = addr + s->yres * src_width; + end = addr; + dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG); + for (y = 0; y < s->yres; y ++) { + new_addr = addr + src_width; + for (x = addr + TARGET_PAGE_SIZE; x < new_addr; + x += TARGET_PAGE_SIZE) { + dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); + dirty[0] |= dirty[1]; + } + if (dirty[0] || s->invalidated) { + fn((uint32_t *) s->dma_ch[0].palette, + dest, src, s->xres, s->dest_width); + if (addr < start) + start = addr; + if (new_addr > end) + end = new_addr; + if (y < *miny) + *miny = y; + if (y >= *maxy) + *maxy = y + 1; + } + addr = new_addr; + dirty[0] = dirty[1]; + src += src_width; + dest += dest_width; + } + + if (end > start) + cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG); +} + +static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s, + uint8_t *fb, int *miny, int *maxy) +{ + int y, src_width, dest_width, dirty[2]; + uint8_t *src, *dest; + ram_addr_t x, addr, new_addr, start, end; + drawfn fn = 0; + if (s->dest_width) + fn = s->line_fn[s->transp][s->bpp]; + if (!fn) + return; + + src = fb; + src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */ + if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) + src_width *= 3; + else if (s->bpp > pxa_lcdc_16bpp) + src_width *= 4; + else if (s->bpp > pxa_lcdc_8bpp) + src_width *= 2; + + dest_width = s->yres * s->dest_width; + dest = s->ds->data + dest_width * (s->xres - 1); + + addr = (ram_addr_t) (fb - phys_ram_base); + start = addr + s->yres * src_width; + end = addr; + dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG); + for (y = 0; y < s->yres; y ++) { + new_addr = addr + src_width; + for (x = addr + TARGET_PAGE_SIZE; x < new_addr; + x += TARGET_PAGE_SIZE) { + dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); + dirty[0] |= dirty[1]; + } + if (dirty[0] || s->invalidated) { + fn((uint32_t *) s->dma_ch[0].palette, + dest, src, s->xres, -dest_width); + if (addr < start) + start = addr; + if (new_addr > end) + end = new_addr; + if (y < *miny) + *miny = y; + if (y >= *maxy) + *maxy = y + 1; + } + addr = new_addr; + dirty[0] = dirty[1]; + src += src_width; + dest += s->dest_width; + } + + if (end > start) + cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG); +} + +static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s) +{ + int width, height; + if (!(s->control[0] & LCCR0_ENB)) + return; + + width = LCCR1_PPL(s->control[1]) + 1; + height = LCCR2_LPP(s->control[2]) + 1; + + if (width != s->xres || height != s->yres) { + if (s->orientation) + dpy_resize(s->ds, height, width); + else + dpy_resize(s->ds, width, height); + s->invalidated = 1; + s->xres = width; + s->yres = height; + } +} + +static void pxa2xx_update_display(void *opaque) +{ + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; + uint8_t *fb; + target_phys_addr_t fbptr; + int miny, maxy; + int ch; + if (!(s->control[0] & LCCR0_ENB)) + return; + + pxa2xx_descriptor_load(s); + + pxa2xx_lcdc_resize(s); + miny = s->yres; + maxy = 0; + s->transp = s->dma_ch[2].up || s->dma_ch[3].up; + /* Note: With overlay planes the order depends on LCCR0 bit 25. */ + for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++) + if (s->dma_ch[ch].up) { + if (!s->dma_ch[ch].source) { + pxa2xx_dma_ber_set(s, ch); + continue; + } + fbptr = s->dma_ch[ch].source; + if (!(fbptr >= PXA2XX_RAM_BASE && + fbptr <= PXA2XX_RAM_BASE + phys_ram_size)) { + pxa2xx_dma_ber_set(s, ch); + continue; + } + fbptr -= PXA2XX_RAM_BASE; + fb = phys_ram_base + fbptr; + + if (s->dma_ch[ch].command & LDCMD_PAL) { + memcpy(s->dma_ch[ch].pbuffer, fb, + MAX(LDCMD_LENGTH(s->dma_ch[ch].command), + sizeof(s->dma_ch[ch].pbuffer))); + pxa2xx_palette_parse(s, ch, s->bpp); + } else { + /* Do we need to reparse palette */ + if (LCCR4_PALFOR(s->control[4]) != s->pal_for) + pxa2xx_palette_parse(s, ch, s->bpp); + + /* ACK frame start */ + pxa2xx_dma_sof_set(s, ch); + + s->dma_ch[ch].redraw(s, fb, &miny, &maxy); + s->invalidated = 0; + + /* ACK frame completed */ + pxa2xx_dma_eof_set(s, ch); + } + } + + if (s->control[0] & LCCR0_DIS) { + /* ACK last frame completed */ + s->control[0] &= ~LCCR0_ENB; + s->status[0] |= LCSR0_LDD; + } + + if (s->orientation) + dpy_update(s->ds, miny, 0, maxy, s->xres); + else + dpy_update(s->ds, 0, miny, s->xres, maxy); + pxa2xx_lcdc_int_update(s); + + if (s->vsync_cb) + s->vsync_cb(s->opaque); +} + +static void pxa2xx_invalidate_display(void *opaque) +{ + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; + s->invalidated = 1; +} + +static void pxa2xx_screen_dump(void *opaque, const char *filename) +{ + /* TODO */ +} + +void pxa2xx_lcdc_orientation(void *opaque, int angle) +{ + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; + + if (angle) { + s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert; + } else { + s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz; + } + + s->orientation = angle; + s->xres = s->yres = -1; + pxa2xx_lcdc_resize(s); +} + +#define BITS 8 +#include "pxa2xx_template.h" +#define BITS 15 +#include "pxa2xx_template.h" +#define BITS 16 +#include "pxa2xx_template.h" +#define BITS 24 +#include "pxa2xx_template.h" +#define BITS 32 +#include "pxa2xx_template.h" + +struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, + DisplayState *ds) +{ + int iomemtype; + struct pxa2xx_lcdc_s *s; + + s = (struct pxa2xx_lcdc_s *) qemu_mallocz(sizeof(struct pxa2xx_lcdc_s)); + s->base = base; + s->invalidated = 1; + s->irq = irq; + s->ds = ds; + + pxa2xx_lcdc_orientation(s, graphic_rotate); + + iomemtype = cpu_register_io_memory(0, pxa2xx_lcdc_readfn, + pxa2xx_lcdc_writefn, s); + cpu_register_physical_memory(base, 0x000fffff, iomemtype); + + graphic_console_init(ds, pxa2xx_update_display, + pxa2xx_invalidate_display, pxa2xx_screen_dump, s); + + switch (s->ds->depth) { + case 0: + s->dest_width = 0; + break; + case 8: + s->line_fn[0] = pxa2xx_draw_fn_8; + s->line_fn[1] = pxa2xx_draw_fn_8t; + s->dest_width = 1; + break; + case 15: + s->line_fn[0] = pxa2xx_draw_fn_15; + s->line_fn[1] = pxa2xx_draw_fn_15t; + s->dest_width = 2; + break; + case 16: + s->line_fn[0] = pxa2xx_draw_fn_16; + s->line_fn[1] = pxa2xx_draw_fn_16t; + s->dest_width = 2; + break; + case 24: + s->line_fn[0] = pxa2xx_draw_fn_24; + s->line_fn[1] = pxa2xx_draw_fn_24t; + s->dest_width = 3; + break; + case 32: + s->line_fn[0] = pxa2xx_draw_fn_32; + s->line_fn[1] = pxa2xx_draw_fn_32t; + s->dest_width = 4; + break; + default: + fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__); + exit(1); + } + return s; +} + +void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s, + void (*cb)(void *opaque), void *opaque) { + s->vsync_cb = cb; + s->opaque = opaque; +} diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c new file mode 100644 index 000000000..7515ab887 --- /dev/null +++ b/hw/pxa2xx_mmci.c @@ -0,0 +1,472 @@ +/* + * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPLv2. + */ + +#include "vl.h" +#include "sd.h" + +struct pxa2xx_mmci_s { + target_phys_addr_t base; + qemu_irq irq; + void *dma; + + SDState *card; + + uint32_t status; + uint32_t clkrt; + uint32_t spi; + uint32_t cmdat; + uint32_t resp_tout; + uint32_t read_tout; + int blklen; + int numblk; + uint32_t intmask; + uint32_t intreq; + int cmd; + uint32_t arg; + + int active; + int bytesleft; + uint8_t tx_fifo[64]; + int tx_start; + int tx_len; + uint8_t rx_fifo[32]; + int rx_start; + int rx_len; + uint16_t resp_fifo[9]; + int resp_len; + + int cmdreq; + int ac_width; +}; + +#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */ +#define MMC_STAT 0x04 /* MMC Status register */ +#define MMC_CLKRT 0x08 /* MMC Clock Rate register */ +#define MMC_SPI 0x0c /* MMC SPI Mode register */ +#define MMC_CMDAT 0x10 /* MMC Command/Data register */ +#define MMC_RESTO 0x14 /* MMC Response Time-Out register */ +#define MMC_RDTO 0x18 /* MMC Read Time-Out register */ +#define MMC_BLKLEN 0x1c /* MMC Block Length register */ +#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */ +#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */ +#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */ +#define MMC_I_REG 0x2c /* MMC Interrupt Request register */ +#define MMC_CMD 0x30 /* MMC Command register */ +#define MMC_ARGH 0x34 /* MMC Argument High register */ +#define MMC_ARGL 0x38 /* MMC Argument Low register */ +#define MMC_RES 0x3c /* MMC Response FIFO */ +#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */ +#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */ +#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */ +#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */ + +/* Bitfield masks */ +#define STRPCL_STOP_CLK (1 << 0) +#define STRPCL_STRT_CLK (1 << 1) +#define STAT_TOUT_RES (1 << 1) +#define STAT_CLK_EN (1 << 8) +#define STAT_DATA_DONE (1 << 11) +#define STAT_PRG_DONE (1 << 12) +#define STAT_END_CMDRES (1 << 13) +#define SPI_SPI_MODE (1 << 0) +#define CMDAT_RES_TYPE (3 << 0) +#define CMDAT_DATA_EN (1 << 2) +#define CMDAT_WR_RD (1 << 3) +#define CMDAT_DMA_EN (1 << 7) +#define CMDAT_STOP_TRAN (1 << 10) +#define INT_DATA_DONE (1 << 0) +#define INT_PRG_DONE (1 << 1) +#define INT_END_CMD (1 << 2) +#define INT_STOP_CMD (1 << 3) +#define INT_CLK_OFF (1 << 4) +#define INT_RXFIFO_REQ (1 << 5) +#define INT_TXFIFO_REQ (1 << 6) +#define INT_TINT (1 << 7) +#define INT_DAT_ERR (1 << 8) +#define INT_RES_ERR (1 << 9) +#define INT_RD_STALLED (1 << 10) +#define INT_SDIO_INT (1 << 11) +#define INT_SDIO_SACK (1 << 12) +#define PRTBUF_PRT_BUF (1 << 0) + +/* Route internal interrupt lines to the global IC and DMA */ +static void pxa2xx_mmci_int_update(struct pxa2xx_mmci_s *s) +{ + uint32_t mask = s->intmask; + if (s->cmdat & CMDAT_DMA_EN) { + mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ; + + pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma, + PXA2XX_RX_RQ_MMCI, !!(s->intreq & INT_RXFIFO_REQ)); + pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma, + PXA2XX_TX_RQ_MMCI, !!(s->intreq & INT_TXFIFO_REQ)); + } + + qemu_set_irq(s->irq, !!(s->intreq & ~mask)); +} + +static void pxa2xx_mmci_fifo_update(struct pxa2xx_mmci_s *s) +{ + if (!s->active) + return; + + if (s->cmdat & CMDAT_WR_RD) { + while (s->bytesleft && s->tx_len) { + sd_write_data(s->card, s->tx_fifo[s->tx_start ++]); + s->tx_start &= 0x1f; + s->tx_len --; + s->bytesleft --; + } + if (s->bytesleft) + s->intreq |= INT_TXFIFO_REQ; + } else + while (s->bytesleft && s->rx_len < 32) { + s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] = + sd_read_data(s->card); + s->bytesleft --; + s->intreq |= INT_RXFIFO_REQ; + } + + if (!s->bytesleft) { + s->active = 0; + s->intreq |= INT_DATA_DONE; + s->status |= STAT_DATA_DONE; + + if (s->cmdat & CMDAT_WR_RD) { + s->intreq |= INT_PRG_DONE; + s->status |= STAT_PRG_DONE; + } + } + + pxa2xx_mmci_int_update(s); +} + +static void pxa2xx_mmci_wakequeues(struct pxa2xx_mmci_s *s) +{ + int rsplen, i; + struct sd_request_s request; + uint8_t response[16]; + + s->active = 1; + s->rx_len = 0; + s->tx_len = 0; + s->cmdreq = 0; + + request.cmd = s->cmd; + request.arg = s->arg; + request.crc = 0; /* FIXME */ + + rsplen = sd_do_command(s->card, &request, response); + s->intreq |= INT_END_CMD; + + memset(s->resp_fifo, 0, sizeof(s->resp_fifo)); + switch (s->cmdat & CMDAT_RES_TYPE) { +#define PXAMMCI_RESP(wd, value0, value1) \ + s->resp_fifo[(wd) + 0] |= (value0); \ + s->resp_fifo[(wd) + 1] |= (value1) << 8; + case 0: /* No response */ + goto complete; + + case 1: /* R1, R4, R5 or R6 */ + if (rsplen < 4) + goto timeout; + goto complete; + + case 2: /* R2 */ + if (rsplen < 16) + goto timeout; + goto complete; + + case 3: /* R3 */ + if (rsplen < 4) + goto timeout; + goto complete; + + complete: + for (i = 0; rsplen > 0; i ++, rsplen -= 2) { + PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]); + } + s->status |= STAT_END_CMDRES; + + if (!(s->cmdat & CMDAT_DATA_EN)) + s->active = 0; + else + s->bytesleft = s->numblk * s->blklen; + + s->resp_len = 0; + break; + + timeout: + s->active = 0; + s->status |= STAT_TOUT_RES; + break; + } + + pxa2xx_mmci_fifo_update(s); +} + +static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + uint32_t ret; + offset -= s->base; + + switch (offset) { + case MMC_STRPCL: + return 0; + case MMC_STAT: + return s->status; + case MMC_CLKRT: + return s->clkrt; + case MMC_SPI: + return s->spi; + case MMC_CMDAT: + return s->cmdat; + case MMC_RESTO: + return s->resp_tout; + case MMC_RDTO: + return s->read_tout; + case MMC_BLKLEN: + return s->blklen; + case MMC_NUMBLK: + return s->numblk; + case MMC_PRTBUF: + return 0; + case MMC_I_MASK: + return s->intmask; + case MMC_I_REG: + return s->intreq; + case MMC_CMD: + return s->cmd | 0x40; + case MMC_ARGH: + return s->arg >> 16; + case MMC_ARGL: + return s->arg & 0xffff; + case MMC_RES: + if (s->resp_len < 9) + return s->resp_fifo[s->resp_len ++]; + return 0; + case MMC_RXFIFO: + ret = 0; + while (s->ac_width -- && s->rx_len) { + ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3); + s->rx_start &= 0x1f; + s->rx_len --; + } + s->intreq &= ~INT_RXFIFO_REQ; + pxa2xx_mmci_fifo_update(s); + return ret; + case MMC_RDWAIT: + return 0; + case MMC_BLKS_REM: + return s->numblk; + default: + cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", + __FUNCTION__, offset); + } + + return 0; +} + +static void pxa2xx_mmci_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + offset -= s->base; + + switch (offset) { + case MMC_STRPCL: + if (value & STRPCL_STRT_CLK) { + s->status |= STAT_CLK_EN; + s->intreq &= ~INT_CLK_OFF; + + if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) { + s->status &= STAT_CLK_EN; + pxa2xx_mmci_wakequeues(s); + } + } + + if (value & STRPCL_STOP_CLK) { + s->status &= ~STAT_CLK_EN; + s->intreq |= INT_CLK_OFF; + s->active = 0; + } + + pxa2xx_mmci_int_update(s); + break; + + case MMC_CLKRT: + s->clkrt = value & 7; + break; + + case MMC_SPI: + s->spi = value & 0xf; + if (value & SPI_SPI_MODE) + printf("%s: attempted to use card in SPI mode\n", __FUNCTION__); + break; + + case MMC_CMDAT: + s->cmdat = value & 0x3dff; + s->active = 0; + s->cmdreq = 1; + if (!(value & CMDAT_STOP_TRAN)) { + s->status &= STAT_CLK_EN; + + if (s->status & STAT_CLK_EN) + pxa2xx_mmci_wakequeues(s); + } + + pxa2xx_mmci_int_update(s); + break; + + case MMC_RESTO: + s->resp_tout = value & 0x7f; + break; + + case MMC_RDTO: + s->read_tout = value & 0xffff; + break; + + case MMC_BLKLEN: + s->blklen = value & 0xfff; + break; + + case MMC_NUMBLK: + s->numblk = value & 0xffff; + break; + + case MMC_PRTBUF: + if (value & PRTBUF_PRT_BUF) { + s->tx_start ^= 32; + s->tx_len = 0; + } + pxa2xx_mmci_fifo_update(s); + break; + + case MMC_I_MASK: + s->intmask = value & 0x1fff; + pxa2xx_mmci_int_update(s); + break; + + case MMC_CMD: + s->cmd = value & 0x3f; + break; + + case MMC_ARGH: + s->arg &= 0x0000ffff; + s->arg |= value << 16; + break; + + case MMC_ARGL: + s->arg &= 0xffff0000; + s->arg |= value & 0x0000ffff; + break; + + case MMC_TXFIFO: + while (s->ac_width -- && s->tx_len < 0x20) + s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] = + (value >> (s->ac_width << 3)) & 0xff; + s->intreq &= ~INT_TXFIFO_REQ; + pxa2xx_mmci_fifo_update(s); + break; + + case MMC_RDWAIT: + case MMC_BLKS_REM: + break; + + default: + cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", + __FUNCTION__, offset); + } +} + +static uint32_t pxa2xx_mmci_readb(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + s->ac_width = 1; + return pxa2xx_mmci_read(opaque, offset); +} + +static uint32_t pxa2xx_mmci_readh(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + s->ac_width = 2; + return pxa2xx_mmci_read(opaque, offset); +} + +static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + s->ac_width = 4; + return pxa2xx_mmci_read(opaque, offset); +} + +static CPUReadMemoryFunc *pxa2xx_mmci_readfn[] = { + pxa2xx_mmci_readb, + pxa2xx_mmci_readh, + pxa2xx_mmci_readw +}; + +static void pxa2xx_mmci_writeb(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + s->ac_width = 1; + pxa2xx_mmci_write(opaque, offset, value); +} + +static void pxa2xx_mmci_writeh(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + s->ac_width = 2; + pxa2xx_mmci_write(opaque, offset, value); +} + +static void pxa2xx_mmci_writew(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + s->ac_width = 4; + pxa2xx_mmci_write(opaque, offset, value); +} + +static CPUWriteMemoryFunc *pxa2xx_mmci_writefn[] = { + pxa2xx_mmci_writeb, + pxa2xx_mmci_writeh, + pxa2xx_mmci_writew +}; + +struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, + qemu_irq irq, void *dma) +{ + int iomemtype; + struct pxa2xx_mmci_s *s; + + s = (struct pxa2xx_mmci_s *) qemu_mallocz(sizeof(struct pxa2xx_mmci_s)); + s->base = base; + s->irq = irq; + s->dma = dma; + + iomemtype = cpu_register_io_memory(0, pxa2xx_mmci_readfn, + pxa2xx_mmci_writefn, s); + cpu_register_physical_memory(base, 0x000fffff, iomemtype); + + /* Instantiate the actual storage */ + s->card = sd_init(sd_bdrv); + + return s; +} + +void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque, + void (*readonly_cb)(void *, int), + void (*coverswitch_cb)(void *, int)) +{ + sd_set_cb(s->card, opaque, readonly_cb, coverswitch_cb); +} diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c new file mode 100644 index 000000000..171d90279 --- /dev/null +++ b/hw/pxa2xx_pcmcia.c @@ -0,0 +1,224 @@ +/* + * Intel XScale PXA255/270 PC Card and CompactFlash Interface. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPLv2. + */ + +#include "vl.h" + +struct pxa2xx_pcmcia_s { + struct pcmcia_socket_s slot; + struct pcmcia_card_s *card; + target_phys_addr_t common_base; + target_phys_addr_t attr_base; + target_phys_addr_t io_base; + + qemu_irq irq; + qemu_irq cd_irq; +}; + +static uint32_t pxa2xx_pcmcia_common_read(void *opaque, + target_phys_addr_t offset) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + + if (s->slot.attached) { + offset -= s->common_base; + return s->card->common_read(s->card->state, offset); + } + + return 0; +} + +static void pxa2xx_pcmcia_common_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + + if (s->slot.attached) { + offset -= s->common_base; + s->card->common_write(s->card->state, offset, value); + } +} + +static uint32_t pxa2xx_pcmcia_attr_read(void *opaque, + target_phys_addr_t offset) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + + if (s->slot.attached) { + offset -= s->attr_base; + return s->card->attr_read(s->card->state, offset); + } + + return 0; +} + +static void pxa2xx_pcmcia_attr_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + + if (s->slot.attached) { + offset -= s->attr_base; + s->card->attr_write(s->card->state, offset, value); + } +} + +static uint32_t pxa2xx_pcmcia_io_read(void *opaque, + target_phys_addr_t offset) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + + if (s->slot.attached) { + offset -= s->io_base; + return s->card->io_read(s->card->state, offset); + } + + return 0; +} + +static void pxa2xx_pcmcia_io_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + + if (s->slot.attached) { + offset -= s->io_base; + s->card->io_write(s->card->state, offset, value); + } +} + +static CPUReadMemoryFunc *pxa2xx_pcmcia_common_readfn[] = { + pxa2xx_pcmcia_common_read, + pxa2xx_pcmcia_common_read, + pxa2xx_pcmcia_common_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_pcmcia_common_writefn[] = { + pxa2xx_pcmcia_common_write, + pxa2xx_pcmcia_common_write, + pxa2xx_pcmcia_common_write, +}; + +static CPUReadMemoryFunc *pxa2xx_pcmcia_attr_readfn[] = { + pxa2xx_pcmcia_attr_read, + pxa2xx_pcmcia_attr_read, + pxa2xx_pcmcia_attr_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_pcmcia_attr_writefn[] = { + pxa2xx_pcmcia_attr_write, + pxa2xx_pcmcia_attr_write, + pxa2xx_pcmcia_attr_write, +}; + +static CPUReadMemoryFunc *pxa2xx_pcmcia_io_readfn[] = { + pxa2xx_pcmcia_io_read, + pxa2xx_pcmcia_io_read, + pxa2xx_pcmcia_io_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_pcmcia_io_writefn[] = { + pxa2xx_pcmcia_io_write, + pxa2xx_pcmcia_io_write, + pxa2xx_pcmcia_io_write, +}; + +static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + if (!s->irq) + return; + + qemu_set_irq(s->irq, level); +} + +struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base) +{ + int iomemtype; + struct pxa2xx_pcmcia_s *s; + + s = (struct pxa2xx_pcmcia_s *) + qemu_mallocz(sizeof(struct pxa2xx_pcmcia_s)); + + /* Socket I/O Memory Space */ + s->io_base = base | 0x00000000; + iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_io_readfn, + pxa2xx_pcmcia_io_writefn, s); + cpu_register_physical_memory(s->io_base, 0x03ffffff, iomemtype); + + /* Then next 64 MB is reserved */ + + /* Socket Attribute Memory Space */ + s->attr_base = base | 0x08000000; + iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_attr_readfn, + pxa2xx_pcmcia_attr_writefn, s); + cpu_register_physical_memory(s->attr_base, 0x03ffffff, iomemtype); + + /* Socket Common Memory Space */ + s->common_base = base | 0x0c000000; + iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_common_readfn, + pxa2xx_pcmcia_common_writefn, s); + cpu_register_physical_memory(s->common_base, 0x03ffffff, iomemtype); + + if (base == 0x30000000) + s->slot.slot_string = "PXA PC Card Socket 1"; + else + s->slot.slot_string = "PXA PC Card Socket 0"; + s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0]; + pcmcia_socket_register(&s->slot); + return s; +} + +/* Insert a new card into a slot */ +int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + if (s->slot.attached) + return -EEXIST; + + if (s->cd_irq) { + qemu_irq_raise(s->cd_irq); + } + + s->card = card; + + s->slot.attached = 1; + s->card->slot = &s->slot; + s->card->attach(s->card->state); + + return 0; +} + +/* Eject card from the slot */ +int pxa2xx_pcmcia_dettach(void *opaque) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + if (!s->slot.attached) + return -ENOENT; + + s->card->detach(s->card->state); + s->card->slot = 0; + s->card = 0; + + s->slot.attached = 0; + + if (s->irq) + qemu_irq_lower(s->irq); + if (s->cd_irq) + qemu_irq_lower(s->cd_irq); + + return 0; +} + +/* Who to notify on card events */ +void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq) +{ + struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque; + s->irq = irq; + s->cd_irq = cd_irq; +} diff --git a/hw/pxa2xx_template.h b/hw/pxa2xx_template.h new file mode 100644 index 000000000..341be12e5 --- /dev/null +++ b/hw/pxa2xx_template.h @@ -0,0 +1,431 @@ +/* + * Intel XScale PXA255/270 LCDC emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GPLv2. + * + * Framebuffer format conversion routines. + */ + +# define SKIP_PIXEL(to) to += deststep +#if BITS == 8 +# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) +#elif BITS == 15 || BITS == 16 +# define COPY_PIXEL(to, from) *(uint16_t *) to = from; SKIP_PIXEL(to) +#elif BITS == 24 +# define COPY_PIXEL(to, from) \ + *(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to) +#elif BITS == 32 +# define COPY_PIXEL(to, from) *(uint32_t *) to = from; SKIP_PIXEL(to) +#else +# error unknown bit depth +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP_WORDS 1 +#endif + +#define FN_2(x) FN(x + 1) FN(x) +#define FN_4(x) FN_2(x + 2) FN_2(x) + +static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + while (width > 0) { + data = *(uint32_t *) src; +#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]); +#ifdef SWAP_WORDS + FN_4(12) + FN_4(8) + FN_4(4) + FN_4(0) +#else + FN_4(0) + FN_4(4) + FN_4(8) + FN_4(12) +#endif +#undef FN + width -= 16; + src += 4; + } +} + +static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + while (width > 0) { + data = *(uint32_t *) src; +#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]); +#ifdef SWAP_WORDS + FN_2(6) + FN_2(4) + FN_2(2) + FN_2(0) +#else + FN_2(0) + FN_2(2) + FN_2(4) + FN_2(6) +#endif +#undef FN + width -= 8; + src += 4; + } +} + +static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + while (width > 0) { + data = *(uint32_t *) src; +#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]); +#ifdef SWAP_WORDS + FN(24) + FN(16) + FN(8) + FN(0) +#else + FN(0) + FN(8) + FN(16) + FN(24) +#endif +#undef FN + width -= 4; + src += 4; + } +} + +static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *) src; +#ifdef SWAP_WORDS + data = bswap32(data); +#endif + b = (data & 0x1f) << 3; + data >>= 5; + g = (data & 0x3f) << 2; + data >>= 6; + r = (data & 0x1f) << 3; + data >>= 5; + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + b = (data & 0x1f) << 3; + data >>= 5; + g = (data & 0x3f) << 2; + data >>= 6; + r = (data & 0x1f) << 3; + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 2; + src += 4; + } +} + +static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *) src; +#ifdef SWAP_WORDS + data = bswap32(data); +#endif + b = (data & 0x1f) << 3; + data >>= 5; + g = (data & 0x1f) << 3; + data >>= 5; + r = (data & 0x1f) << 3; + data >>= 5; + if (data & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + data >>= 1; + b = (data & 0x1f) << 3; + data >>= 5; + g = (data & 0x1f) << 3; + data >>= 5; + r = (data & 0x1f) << 3; + if (data & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 2; + src += 4; + } +} + +static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *) src; +#ifdef SWAP_WORDS + data = bswap32(data); +#endif + b = (data & 0x3f) << 2; + data >>= 6; + g = (data & 0x3f) << 2; + data >>= 6; + r = (data & 0x3f) << 2; + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 1; + src += 4; + } +} + +/* The wicked packed format */ +static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data[3]; + unsigned int r, g, b; + while (width > 0) { + data[0] = *(uint32_t *) src; + src += 4; + data[1] = *(uint32_t *) src; + src += 4; + data[2] = *(uint32_t *) src; + src += 4; +#ifdef SWAP_WORDS + data[0] = bswap32(data[0]); + data[1] = bswap32(data[1]); + data[2] = bswap32(data[2]); +#endif + b = (data[0] & 0x3f) << 2; + data[0] >>= 6; + g = (data[0] & 0x3f) << 2; + data[0] >>= 6; + r = (data[0] & 0x3f) << 2; + data[0] >>= 12; + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + b = (data[0] & 0x3f) << 2; + data[0] >>= 6; + g = ((data[1] & 0xf) << 4) | (data[0] << 2); + data[1] >>= 4; + r = (data[1] & 0x3f) << 2; + data[1] >>= 12; + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + b = (data[1] & 0x3f) << 2; + data[1] >>= 6; + g = (data[1] & 0x3f) << 2; + data[1] >>= 6; + r = ((data[2] & 0x3) << 6) | (data[1] << 2); + data[2] >>= 8; + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + b = (data[2] & 0x3f) << 2; + data[2] >>= 6; + g = (data[2] & 0x3f) << 2; + data[2] >>= 6; + r = data[2] << 2; + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 4; + } +} + +static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *) src; +#ifdef SWAP_WORDS + data = bswap32(data); +#endif + b = (data & 0x3f) << 2; + data >>= 6; + g = (data & 0x3f) << 2; + data >>= 6; + r = (data & 0x3f) << 2; + data >>= 6; + if (data & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 1; + src += 4; + } +} + +/* The wicked packed format */ +static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data[3]; + unsigned int r, g, b; + while (width > 0) { + data[0] = *(uint32_t *) src; + src += 4; + data[1] = *(uint32_t *) src; + src += 4; + data[2] = *(uint32_t *) src; + src += 4; +# ifdef SWAP_WORDS + data[0] = bswap32(data[0]); + data[1] = bswap32(data[1]); + data[2] = bswap32(data[2]); +# endif + b = (data[0] & 0x3f) << 2; + data[0] >>= 6; + g = (data[0] & 0x3f) << 2; + data[0] >>= 6; + r = (data[0] & 0x3f) << 2; + data[0] >>= 6; + if (data[0] & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + data[0] >>= 6; + b = (data[0] & 0x3f) << 2; + data[0] >>= 6; + g = ((data[1] & 0xf) << 4) | (data[0] << 2); + data[1] >>= 4; + r = (data[1] & 0x3f) << 2; + data[1] >>= 6; + if (data[1] & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + data[1] >>= 6; + b = (data[1] & 0x3f) << 2; + data[1] >>= 6; + g = (data[1] & 0x3f) << 2; + data[1] >>= 6; + r = ((data[2] & 0x3) << 6) | (data[1] << 2); + data[2] >>= 2; + if (data[2] & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + data[2] >>= 6; + b = (data[2] & 0x3f) << 2; + data[2] >>= 6; + g = (data[2] & 0x3f) << 2; + data[2] >>= 6; + r = data[2] << 2; + data[2] >>= 6; + if (data[2] & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 4; + } +} + +static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *) src; +#ifdef SWAP_WORDS + data = bswap32(data); +#endif + b = data & 0xff; + data >>= 8; + g = data & 0xff; + data >>= 8; + r = data & 0xff; + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 1; + src += 4; + } +} + +static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *) src; +#ifdef SWAP_WORDS + data = bswap32(data); +#endif + b = (data & 0x7f) << 1; + data >>= 7; + g = data & 0xff; + data >>= 8; + r = data & 0xff; + data >>= 8; + if (data & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 1; + src += 4; + } +} + +static void glue(pxa2xx_draw_line25_, BITS)(uint32_t *palette, + uint8_t *dest, const uint8_t *src, int width, int deststep) +{ + uint32_t data; + unsigned int r, g, b; + while (width > 0) { + data = *(uint32_t *) src; +#ifdef SWAP_WORDS + data = bswap32(data); +#endif + b = data & 0xff; + data >>= 8; + g = data & 0xff; + data >>= 8; + r = data & 0xff; + data >>= 8; + if (data & 1) + SKIP_PIXEL(dest); + else + COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b)); + width -= 1; + src += 4; + } +} + +/* Overlay planes disabled, no transparency */ +static drawfn glue(pxa2xx_draw_fn_, BITS)[16] = +{ + [0 ... 0xf] = 0, + [pxa_lcdc_2bpp] = glue(pxa2xx_draw_line2_, BITS), + [pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS), + [pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS), + [pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16_, BITS), + [pxa_lcdc_18bpp] = glue(pxa2xx_draw_line18_, BITS), + [pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS), + [pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24_, BITS), +}; + +/* Overlay planes enabled, transparency used */ +static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] = +{ + [0 ... 0xf] = 0, + [pxa_lcdc_4bpp] = glue(pxa2xx_draw_line4_, BITS), + [pxa_lcdc_8bpp] = glue(pxa2xx_draw_line8_, BITS), + [pxa_lcdc_16bpp] = glue(pxa2xx_draw_line16t_, BITS), + [pxa_lcdc_19bpp] = glue(pxa2xx_draw_line19_, BITS), + [pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS), + [pxa_lcdc_24bpp] = glue(pxa2xx_draw_line24t_, BITS), + [pxa_lcdc_25bpp] = glue(pxa2xx_draw_line25_, BITS), +}; + +#undef BITS +#undef COPY_PIXEL +#undef SKIP_PIXEL + +#ifdef SWAP_WORDS +# undef SWAP_WORDS +#endif diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c new file mode 100644 index 000000000..3ab714932 --- /dev/null +++ b/hw/pxa2xx_timer.c @@ -0,0 +1,433 @@ +/* + * Intel XScale PXA255/270 OS Timers. + * + * Copyright (c) 2006 Openedhand Ltd. + * Copyright (c) 2006 Thorsten Zitterell + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +#define OSMR0 0x00 +#define OSMR1 0x04 +#define OSMR2 0x08 +#define OSMR3 0x0c +#define OSMR4 0x80 +#define OSMR5 0x84 +#define OSMR6 0x88 +#define OSMR7 0x8c +#define OSMR8 0x90 +#define OSMR9 0x94 +#define OSMR10 0x98 +#define OSMR11 0x9c +#define OSCR 0x10 /* OS Timer Count */ +#define OSCR4 0x40 +#define OSCR5 0x44 +#define OSCR6 0x48 +#define OSCR7 0x4c +#define OSCR8 0x50 +#define OSCR9 0x54 +#define OSCR10 0x58 +#define OSCR11 0x5c +#define OSSR 0x14 /* Timer status register */ +#define OWER 0x18 +#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */ +#define OMCR4 0xc0 /* OS Match Control registers */ +#define OMCR5 0xc4 +#define OMCR6 0xc8 +#define OMCR7 0xcc +#define OMCR8 0xd0 +#define OMCR9 0xd4 +#define OMCR10 0xd8 +#define OMCR11 0xdc +#define OSNR 0x20 + +#define PXA25X_FREQ 3686400 /* 3.6864 MHz */ +#define PXA27X_FREQ 3250000 /* 3.25 MHz */ + +static int pxa2xx_timer4_freq[8] = { + [0] = 0, + [1] = 32768, + [2] = 1000, + [3] = 1, + [4] = 1000000, + /* [5] is the "Externally supplied clock". Assign if necessary. */ + [5 ... 7] = 0, +}; + +struct pxa2xx_timer0_s { + uint32_t value; + int level; + qemu_irq irq; + QEMUTimer *qtimer; + int num; + void *info; +}; + +struct pxa2xx_timer4_s { + uint32_t value; + int level; + qemu_irq irq; + QEMUTimer *qtimer; + int num; + void *info; + int32_t oldclock; + int32_t clock; + uint64_t lastload; + uint32_t freq; + uint32_t control; +}; + +typedef struct { + uint32_t base; + int32_t clock; + int32_t oldclock; + uint64_t lastload; + uint32_t freq; + struct pxa2xx_timer0_s timer[4]; + struct pxa2xx_timer4_s *tm4; + uint32_t events; + uint32_t irq_enabled; + uint32_t reset3; + CPUState *cpustate; + int64_t qemu_ticks; + uint32_t snapshot; +} pxa2xx_timer_info; + +static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) +{ + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; + int i; + uint32_t now_vm; + uint64_t new_qemu; + + now_vm = s->clock + + muldiv64(now_qemu - s->lastload, s->freq, ticks_per_sec); + + for (i = 0; i < 4; i ++) { + new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), + ticks_per_sec, s->freq); + qemu_mod_timer(s->timer[i].qtimer, new_qemu); + } +} + +static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) +{ + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; + uint32_t now_vm; + uint64_t new_qemu; + static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; + int counter; + + if (s->tm4[n].control & (1 << 7)) + counter = n; + else + counter = counters[n]; + + if (!s->tm4[counter].freq) { + qemu_del_timer(s->timer[n].qtimer); + return; + } + + now_vm = s->tm4[counter].clock + muldiv64(now_qemu - + s->tm4[counter].lastload, + s->tm4[counter].freq, ticks_per_sec); + + new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].value - now_vm), + ticks_per_sec, s->tm4[counter].freq); + qemu_mod_timer(s->timer[n].qtimer, new_qemu); +} + +static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset) +{ + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; + int tm = 0; + + offset -= s->base; + + switch (offset) { + case OSMR3: tm ++; + case OSMR2: tm ++; + case OSMR1: tm ++; + case OSMR0: + return s->timer[tm].value; + case OSMR11: tm ++; + case OSMR10: tm ++; + case OSMR9: tm ++; + case OSMR8: tm ++; + case OSMR7: tm ++; + case OSMR6: tm ++; + case OSMR5: tm ++; + case OSMR4: + if (!s->tm4) + goto badreg; + return s->tm4[tm].value; + case OSCR: + return s->clock + muldiv64(qemu_get_clock(vm_clock) - + s->lastload, s->freq, ticks_per_sec); + case OSCR11: tm ++; + case OSCR10: tm ++; + case OSCR9: tm ++; + case OSCR8: tm ++; + case OSCR7: tm ++; + case OSCR6: tm ++; + case OSCR5: tm ++; + case OSCR4: + if (!s->tm4) + goto badreg; + + if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { + if (s->tm4[tm - 1].freq) + s->snapshot = s->tm4[tm - 1].clock + muldiv64( + qemu_get_clock(vm_clock) - + s->tm4[tm - 1].lastload, + s->tm4[tm - 1].freq, ticks_per_sec); + else + s->snapshot = s->tm4[tm - 1].clock; + } + + if (!s->tm4[tm].freq) + return s->tm4[tm].clock; + return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) - + s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec); + case OIER: + return s->irq_enabled; + case OSSR: /* Status register */ + return s->events; + case OWER: + return s->reset3; + case OMCR11: tm ++; + case OMCR10: tm ++; + case OMCR9: tm ++; + case OMCR8: tm ++; + case OMCR7: tm ++; + case OMCR6: tm ++; + case OMCR5: tm ++; + case OMCR4: + if (!s->tm4) + goto badreg; + return s->tm4[tm].control; + case OSNR: + return s->snapshot; + default: + badreg: + cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset " + REG_FMT "\n", offset); + } + + return 0; +} + +static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + int i, tm = 0; + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; + + offset -= s->base; + + switch (offset) { + case OSMR3: tm ++; + case OSMR2: tm ++; + case OSMR1: tm ++; + case OSMR0: + s->timer[tm].value = value; + pxa2xx_timer_update(s, qemu_get_clock(vm_clock)); + break; + case OSMR11: tm ++; + case OSMR10: tm ++; + case OSMR9: tm ++; + case OSMR8: tm ++; + case OSMR7: tm ++; + case OSMR6: tm ++; + case OSMR5: tm ++; + case OSMR4: + if (!s->tm4) + goto badreg; + s->tm4[tm].value = value; + pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); + break; + case OSCR: + s->oldclock = s->clock; + s->lastload = qemu_get_clock(vm_clock); + s->clock = value; + pxa2xx_timer_update(s, s->lastload); + break; + case OSCR11: tm ++; + case OSCR10: tm ++; + case OSCR9: tm ++; + case OSCR8: tm ++; + case OSCR7: tm ++; + case OSCR6: tm ++; + case OSCR5: tm ++; + case OSCR4: + if (!s->tm4) + goto badreg; + s->tm4[tm].oldclock = s->tm4[tm].clock; + s->tm4[tm].lastload = qemu_get_clock(vm_clock); + s->tm4[tm].clock = value; + pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); + break; + case OIER: + s->irq_enabled = value & 0xfff; + break; + case OSSR: /* Status register */ + s->events &= ~value; + for (i = 0; i < 4; i ++, value >>= 1) { + if (s->timer[i].level && (value & 1)) { + s->timer[i].level = 0; + qemu_irq_lower(s->timer[i].irq); + } + } + if (s->tm4) { + for (i = 0; i < 8; i ++, value >>= 1) + if (s->tm4[i].level && (value & 1)) + s->tm4[i].level = 0; + if (!(s->events & 0xff0)) + qemu_irq_lower(s->tm4->irq); + } + break; + case OWER: /* XXX: Reset on OSMR3 match? */ + s->reset3 = value; + break; + case OMCR7: tm ++; + case OMCR6: tm ++; + case OMCR5: tm ++; + case OMCR4: + if (!s->tm4) + goto badreg; + s->tm4[tm].control = value & 0x0ff; + /* XXX Stop if running (shouldn't happen) */ + if ((value & (1 << 7)) || tm == 0) + s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; + else { + s->tm4[tm].freq = 0; + pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); + } + break; + case OMCR11: tm ++; + case OMCR10: tm ++; + case OMCR9: tm ++; + case OMCR8: tm += 4; + if (!s->tm4) + goto badreg; + s->tm4[tm].control = value & 0x3ff; + /* XXX Stop if running (shouldn't happen) */ + if ((value & (1 << 7)) || !(tm & 1)) + s->tm4[tm].freq = + pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; + else { + s->tm4[tm].freq = 0; + pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); + } + break; + default: + badreg: + cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset " + REG_FMT "\n", offset); + } +} + +static CPUReadMemoryFunc *pxa2xx_timer_readfn[] = { + pxa2xx_timer_read, + pxa2xx_timer_read, + pxa2xx_timer_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = { + pxa2xx_timer_write, + pxa2xx_timer_write, + pxa2xx_timer_write, +}; + +static void pxa2xx_timer_tick(void *opaque) +{ + struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque; + pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info; + + if (i->irq_enabled & (1 << t->num)) { + t->level = 1; + i->events |= 1 << t->num; + qemu_irq_raise(t->irq); + } + + if (t->num == 3) + if (i->reset3 & 1) { + i->reset3 = 0; + cpu_reset(i->cpustate); + } +} + +static void pxa2xx_timer_tick4(void *opaque) +{ + struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque; + pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info; + + pxa2xx_timer_tick4(opaque); + if (t->control & (1 << 3)) + t->clock = 0; + if (t->control & (1 << 6)) + pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->num - 4); +} + +static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, + qemu_irq *irqs, CPUState *cpustate) +{ + int i; + int iomemtype; + pxa2xx_timer_info *s; + + s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info)); + s->base = base; + s->irq_enabled = 0; + s->oldclock = 0; + s->clock = 0; + s->lastload = qemu_get_clock(vm_clock); + s->reset3 = 0; + s->cpustate = cpustate; + + for (i = 0; i < 4; i ++) { + s->timer[i].value = 0; + s->timer[i].irq = irqs[i]; + s->timer[i].info = s; + s->timer[i].num = i; + s->timer[i].level = 0; + s->timer[i].qtimer = qemu_new_timer(vm_clock, + pxa2xx_timer_tick, &s->timer[i]); + } + + iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn, + pxa2xx_timer_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + return s; +} + +void pxa25x_timer_init(target_phys_addr_t base, + qemu_irq *irqs, CPUState *cpustate) +{ + pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate); + s->freq = PXA25X_FREQ; + s->tm4 = 0; +} + +void pxa27x_timer_init(target_phys_addr_t base, + qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate) +{ + pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate); + int i; + s->freq = PXA27X_FREQ; + s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 * + sizeof(struct pxa2xx_timer4_s)); + for (i = 0; i < 8; i ++) { + s->tm4[i].value = 0; + s->tm4[i].irq = irq4; + s->tm4[i].info = s; + s->tm4[i].num = i + 4; + s->tm4[i].level = 0; + s->tm4[i].freq = 0; + s->tm4[i].control = 0x0; + s->tm4[i].qtimer = qemu_new_timer(vm_clock, + pxa2xx_timer_tick4, &s->tm4[i]); + } +} diff --git a/vl.c b/vl.c index bb36281e7..0ed74152e 100644 --- a/vl.c +++ b/vl.c @@ -188,6 +188,7 @@ const char *vnc_display; int acpi_enabled = 1; int fd_bootchk = 1; int no_reboot = 0; +int graphic_rotate = 0; int daemonize = 0; const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; @@ -524,6 +525,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) { QEMUPutMouseEvent *mouse_event; void *mouse_event_opaque; + int width; if (!qemu_put_mouse_event_current) { return; @@ -535,7 +537,16 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) qemu_put_mouse_event_current->qemu_put_mouse_event_opaque; if (mouse_event) { - mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state); + if (graphic_rotate) { + if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute) + width = 0x7fff; + else + width = graphic_width; + mouse_event(mouse_event_opaque, + width - dy, dx, dz, buttons_state); + } else + mouse_event(mouse_event_opaque, + dx, dy, dz, buttons_state); } } @@ -6422,6 +6433,7 @@ void help(void) "-m megs set virtual RAM size to megs MB [default=%d]\n" "-smp n set the number of CPUs to 'n' [default=1]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" + "-portrait rotate graphical output 90 deg left (only PXA LCD)\n" #ifndef _WIN32 "-k language use keyboard layout (for example \"fr\" for French)\n" #endif @@ -6556,6 +6568,7 @@ enum { #endif QEMU_OPTION_m, QEMU_OPTION_nographic, + QEMU_OPTION_portrait, #ifdef HAS_AUDIO QEMU_OPTION_audio_help, QEMU_OPTION_soundhw, @@ -6636,6 +6649,7 @@ const QEMUOption qemu_options[] = { #endif { "m", HAS_ARG, QEMU_OPTION_m }, { "nographic", 0, QEMU_OPTION_nographic }, + { "portrait", 0, QEMU_OPTION_portrait }, { "k", HAS_ARG, QEMU_OPTION_k }, #ifdef HAS_AUDIO { "audio-help", 0, QEMU_OPTION_audio_help }, @@ -7167,6 +7181,9 @@ int main(int argc, char **argv) pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); nographic = 1; break; + case QEMU_OPTION_portrait: + graphic_rotate = 1; + break; case QEMU_OPTION_kernel: kernel_filename = optarg; break; @@ -7658,7 +7675,7 @@ int main(int argc, char **argv) fprintf(stderr, "qemu: could not open SD card image %s\n", sd_filename); } else - qemu_key_check(bs, sd_filename); + qemu_key_check(sd_bdrv, sd_filename); } register_savevm("timer", 0, 2, timer_save, timer_load, NULL); diff --git a/vl.h b/vl.h index 7bc3eba62..23d8dd668 100644 --- a/vl.h +++ b/vl.h @@ -158,6 +158,7 @@ extern int kqemu_allowed; extern int win2k_install_hack; extern int usb_enabled; extern int smp_cpus; +extern int graphic_rotate; extern int no_quit; extern int semihosting_enabled; extern int autostart; -- cgit v1.2.3 From 18c9b56060e6d69e38d0d91ffb02d510d8ce1971 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 02:02:17 +0000 Subject: Implement iwMMXt instruction set for the PXA270 cpu. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2752 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/cpu.h | 19 + target-arm/exec.h | 2 + target-arm/helper.c | 2 + target-arm/op.c | 3 + target-arm/op_iwmmxt.c | 707 +++++++++++++++++++++++++++++++ target-arm/op_mem.h | 20 + target-arm/translate.c | 1083 ++++++++++++++++++++++++++++++++++++++++++++++- tests/Makefile | 3 + tests/test-arm-iwmmxt.s | 49 +++ 9 files changed, 1882 insertions(+), 6 deletions(-) create mode 100644 target-arm/op_iwmmxt.c create mode 100644 tests/test-arm-iwmmxt.s diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 6e2ae905f..7cb08ebaf 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -129,6 +129,14 @@ typedef struct CPUARMState { float_status fp_status; } vfp; + /* iwMMXt coprocessor state. */ + struct { + uint64_t regs[16]; + uint64_t val; + + uint32_t cregs[16]; + } iwmmxt; + #if defined(CONFIG_USER_ONLY) /* For usermode syscall translation. */ int eabi; @@ -218,10 +226,21 @@ enum arm_cpu_mode { #define ARM_VFP_FPINST 9 #define ARM_VFP_FPINST2 10 +/* iwMMXt coprocessor control registers. */ +#define ARM_IWMMXT_wCID 0 +#define ARM_IWMMXT_wCon 1 +#define ARM_IWMMXT_wCSSF 2 +#define ARM_IWMMXT_wCASF 3 +#define ARM_IWMMXT_wCGR0 8 +#define ARM_IWMMXT_wCGR1 9 +#define ARM_IWMMXT_wCGR2 10 +#define ARM_IWMMXT_wCGR3 11 + enum arm_features { ARM_FEATURE_VFP, ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ + ARM_FEATURE_IWMMXT /* Intel iwMMXt extension. */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/exec.h b/target-arm/exec.h index 87c41b218..d99dfa5f0 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -32,6 +32,8 @@ register uint32_t T2 asm(AREG3); #define FT0d env->vfp.tmp0d #define FT1d env->vfp.tmp1d +#define M0 env->iwmmxt.val + #include "cpu.h" #include "exec-all.h" diff --git a/target-arm/helper.c b/target-arm/helper.c index 798df304e..8526883fb 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -42,6 +42,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) case ARM_CPUID_PXA270_C5: set_feature(env, ARM_FEATURE_XSCALE); /* JTAG_ID is ((id << 28) | 0x09265013) */ + set_feature(env, ARM_FEATURE_IWMMXT); + env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q'; env->cp15.c0_cachetype = 0xd172172; break; default: diff --git a/target-arm/op.c b/target-arm/op.c index 9cfb46237..fd44a40f8 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -1213,3 +1213,6 @@ void OPPROTO op_movl_T0_T2(void) { T0 = T2; } + +/* iwMMXt support */ +#include "op_iwmmxt.c" diff --git a/target-arm/op_iwmmxt.c b/target-arm/op_iwmmxt.c new file mode 100644 index 000000000..0639f3703 --- /dev/null +++ b/target-arm/op_iwmmxt.c @@ -0,0 +1,707 @@ +/* + * iwMMXt micro operations for XScale. + * + * Copyright (c) 2007 OpenedHand, Ltd. + * Written by Andrzej Zaborowski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define M1 env->iwmmxt.regs[PARAM1] + +/* iwMMXt macros extracted from GNU gdb. */ + +/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */ +#define SIMD8_SET( v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n))) +#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n))) +#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n))) +#define SIMD64_SET(v, n) ((v != 0) << (32 + (n))) +/* Flags to pass as "n" above. */ +#define SIMD_NBIT -1 +#define SIMD_ZBIT -2 +#define SIMD_CBIT -3 +#define SIMD_VBIT -4 +/* Various status bit macros. */ +#define NBIT8(x) ((x) & 0x80) +#define NBIT16(x) ((x) & 0x8000) +#define NBIT32(x) ((x) & 0x80000000) +#define NBIT64(x) ((x) & 0x8000000000000000ULL) +#define ZBIT8(x) (((x) & 0xff) == 0) +#define ZBIT16(x) (((x) & 0xffff) == 0) +#define ZBIT32(x) (((x) & 0xffffffff) == 0) +#define ZBIT64(x) (x == 0) +/* Sign extension macros. */ +#define EXTEND8H(a) ((uint16_t) (int8_t) (a)) +#define EXTEND8(a) ((uint32_t) (int8_t) (a)) +#define EXTEND16(a) ((uint32_t) (int16_t) (a)) +#define EXTEND16S(a) ((int32_t) (int16_t) (a)) +#define EXTEND32(a) ((uint64_t) (int32_t) (a)) + +void OPPROTO op_iwmmxt_movl_T0_T1_wRn(void) +{ + T0 = M1 & ~(uint32_t) 0; + T1 = M1 >> 32; +} + +void OPPROTO op_iwmmxt_movl_wRn_T0_T1(void) +{ + M1 = ((uint64_t) T1 << 32) | T0; +} + +void OPPROTO op_iwmmxt_movq_M0_wRn(void) +{ + M0 = M1; +} + +void OPPROTO op_iwmmxt_orq_M0_wRn(void) +{ + M0 |= M1; +} + +void OPPROTO op_iwmmxt_andq_M0_wRn(void) +{ + M0 &= M1; +} + +void OPPROTO op_iwmmxt_xorq_M0_wRn(void) +{ + M0 ^= M1; +} + +void OPPROTO op_iwmmxt_maddsq_M0_wRn(void) +{ + M0 = (( + EXTEND16S((M0 >> 0) & 0xffff) * EXTEND16S((M1 >> 0) & 0xffff) + + EXTEND16S((M0 >> 16) & 0xffff) * EXTEND16S((M1 >> 16) & 0xffff) + ) & 0xffffffff) | ((uint64_t) ( + EXTEND16S((M0 >> 32) & 0xffff) * EXTEND16S((M1 >> 32) & 0xffff) + + EXTEND16S((M0 >> 48) & 0xffff) * EXTEND16S((M1 >> 48) & 0xffff) + ) << 32); +} + +void OPPROTO op_iwmmxt_madduq_M0_wRn(void) +{ + M0 = (( + ((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) + + ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff) + ) & 0xffffffff) | (( + ((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) + + ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff) + ) << 32); +} + +void OPPROTO op_iwmmxt_sadb_M0_wRn(void) +{ +#define abs(x) (((x) >= 0) ? x : -x) +#define SADB(SHR) abs((int) ((M0 >> SHR) & 0xff) - (int) ((M1 >> SHR) & 0xff)) + M0 = + SADB(0) + SADB(8) + SADB(16) + SADB(24) + + SADB(32) + SADB(40) + SADB(48) + SADB(56); +#undef SADB +} + +void OPPROTO op_iwmmxt_sadw_M0_wRn(void) +{ +#define SADW(SHR) \ + abs((int) ((M0 >> SHR) & 0xffff) - (int) ((M1 >> SHR) & 0xffff)) + M0 = SADW(0) + SADW(16) + SADW(32) + SADW(48); +#undef SADW +} + +void OPPROTO op_iwmmxt_addl_M0_wRn(void) +{ + M0 += env->iwmmxt.regs[PARAM1] & 0xffffffff; +} + +void OPPROTO op_iwmmxt_mulsw_M0_wRn(void) +{ +#define MULS(SHR) ((uint64_t) ((( \ + EXTEND16S((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff) \ + ) >> PARAM2) & 0xffff) << SHR) + M0 = MULS(0) | MULS(16) | MULS(32) | MULS(48); +#undef MULS +} + +void OPPROTO op_iwmmxt_muluw_M0_wRn(void) +{ +#define MULU(SHR) ((uint64_t) ((( \ + ((M0 >> SHR) & 0xffff) * ((M1 >> SHR) & 0xffff) \ + ) >> PARAM2) & 0xffff) << SHR) + M0 = MULU(0) | MULU(16) | MULU(32) | MULU(48); +#undef MULU +} + +void OPPROTO op_iwmmxt_macsw_M0_wRn(void) +{ +#define MACS(SHR) ( \ + EXTEND16((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff)) + M0 = (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48)); +#undef MACS +} + +void OPPROTO op_iwmmxt_macuw_M0_wRn(void) +{ +#define MACU(SHR) ( \ + (uint32_t) ((M0 >> SHR) & 0xffff) * \ + (uint32_t) ((M1 >> SHR) & 0xffff)) + M0 = MACU(0) + MACU(16) + MACU(32) + MACU(48); +#undef MACU +} + +void OPPROTO op_iwmmxt_addsq_M0_wRn(void) +{ + M0 = (int64_t) M0 + (int64_t) M1; +} + +void OPPROTO op_iwmmxt_adduq_M0_wRn(void) +{ + M0 += M1; +} + +void OPPROTO op_iwmmxt_movq_wRn_M0(void) +{ + M1 = M0; +} + +void OPPROTO op_iwmmxt_movl_wCx_T0(void) +{ + env->iwmmxt.cregs[PARAM1] = T0; +} + +void OPPROTO op_iwmmxt_movl_T0_wCx(void) +{ + T0 = env->iwmmxt.cregs[PARAM1]; +} + +void OPPROTO op_iwmmxt_movl_T1_wCx(void) +{ + T1 = env->iwmmxt.cregs[PARAM1]; +} + +void OPPROTO op_iwmmxt_set_mup(void) +{ + env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 2; +} + +void OPPROTO op_iwmmxt_set_cup(void) +{ + env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 1; +} + +void OPPROTO op_iwmmxt_setpsr_nz(void) +{ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + SIMD64_SET((M0 == 0), SIMD_ZBIT) | + SIMD64_SET((M0 & (1ULL << 63)), SIMD_NBIT); +} + +void OPPROTO op_iwmmxt_negq_M0(void) +{ + M0 = ~M0; +} + +#define NZBIT8(x, i) \ + SIMD8_SET(NBIT8((x) & 0xff), SIMD_NBIT, i) | \ + SIMD8_SET(ZBIT8((x) & 0xff), SIMD_ZBIT, i) +#define NZBIT16(x, i) \ + SIMD16_SET(NBIT16((x) & 0xffff), SIMD_NBIT, i) | \ + SIMD16_SET(ZBIT16((x) & 0xffff), SIMD_ZBIT, i) +#define NZBIT32(x, i) \ + SIMD32_SET(NBIT32((x) & 0xffffffff), SIMD_NBIT, i) | \ + SIMD32_SET(ZBIT32((x) & 0xffffffff), SIMD_ZBIT, i) +#define NZBIT64(x) \ + SIMD64_SET(NBIT64(x), SIMD_NBIT) | \ + SIMD64_SET(ZBIT64(x), SIMD_ZBIT) +#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, b_M0_wRn))(void) \ +{ \ + M0 = \ + (((M0 >> SH0) & 0xff) << 0) | (((M1 >> SH0) & 0xff) << 8) | \ + (((M0 >> SH1) & 0xff) << 16) | (((M1 >> SH1) & 0xff) << 24) | \ + (((M0 >> SH2) & 0xff) << 32) | (((M1 >> SH2) & 0xff) << 40) | \ + (((M0 >> SH3) & 0xff) << 48) | (((M1 >> SH3) & 0xff) << 56); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | \ + NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | \ + NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | \ + NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); \ +} \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, w_M0_wRn))(void) \ +{ \ + M0 = \ + (((M0 >> SH0) & 0xffff) << 0) | \ + (((M1 >> SH0) & 0xffff) << 16) | \ + (((M0 >> SH2) & 0xffff) << 32) | \ + (((M1 >> SH2) & 0xffff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 16, 1) | \ + NZBIT8(M0 >> 32, 2) | NZBIT8(M0 >> 48, 3); \ +} \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, l_M0_wRn))(void) \ +{ \ + M0 = \ + (((M0 >> SH0) & 0xffffffff) << 0) | \ + (((M1 >> SH0) & 0xffffffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \ +} \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, ub_M0))(void) \ +{ \ + M0 = \ + (((M0 >> SH0) & 0xff) << 0) | \ + (((M0 >> SH1) & 0xff) << 16) | \ + (((M0 >> SH2) & 0xff) << 32) | \ + (((M0 >> SH3) & 0xff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \ + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \ +} \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, uw_M0))(void) \ +{ \ + M0 = \ + (((M0 >> SH0) & 0xffff) << 0) | \ + (((M0 >> SH2) & 0xffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \ +} \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, ul_M0))(void) \ +{ \ + M0 = (((M0 >> SH0) & 0xffffffff) << 0); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0); \ +} \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, sb_M0))(void) \ +{ \ + M0 = \ + ((uint64_t) EXTEND8H((M0 >> SH0) & 0xff) << 0) | \ + ((uint64_t) EXTEND8H((M0 >> SH1) & 0xff) << 16) | \ + ((uint64_t) EXTEND8H((M0 >> SH2) & 0xff) << 32) | \ + ((uint64_t) EXTEND8H((M0 >> SH3) & 0xff) << 48); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \ + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \ +} \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, sw_M0))(void) \ +{ \ + M0 = \ + ((uint64_t) EXTEND16((M0 >> SH0) & 0xffff) << 0) | \ + ((uint64_t) EXTEND16((M0 >> SH2) & 0xffff) << 32); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \ +} \ +void OPPROTO glue(op_iwmmxt_unpack, glue(S, sl_M0))(void) \ +{ \ + M0 = EXTEND32((M0 >> SH0) & 0xffffffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0); \ +} +IWMMXT_OP_UNPACK(l, 0, 8, 16, 24) +IWMMXT_OP_UNPACK(h, 32, 40, 48, 56) + +#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \ +void OPPROTO glue(op_iwmmxt_, glue(SUFF, b_M0_wRn))(void) \ +{ \ + M0 = \ + CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \ + CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \ + CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \ + CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | \ + NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | \ + NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | \ + NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); \ +} \ +void OPPROTO glue(op_iwmmxt_, glue(SUFF, w_M0_wRn))(void) \ +{ \ + M0 = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \ + CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \ + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \ +} \ +void OPPROTO glue(op_iwmmxt_, glue(SUFF, l_M0_wRn))(void) \ +{ \ + M0 = CMP(0, Tl, O, 0xffffffff) | \ + CMP(32, Tl, O, 0xffffffff); \ + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \ + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \ +} +#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((M0 >> SHR) & MASK) OPER \ + (TYPE) ((M1 >> SHR) & MASK)) ? (uint64_t) MASK : 0) << SHR) +IWMMXT_OP_CMP(cmpeq, uint8_t, uint16_t, uint32_t, ==) +IWMMXT_OP_CMP(cmpgts, int8_t, int16_t, int32_t, >) +IWMMXT_OP_CMP(cmpgtu, uint8_t, uint16_t, uint32_t, >) +#undef CMP +#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((M0 >> SHR) & MASK) OPER \ + (TYPE) ((M1 >> SHR) & MASK)) ? M0 : M1) & ((uint64_t) MASK << SHR)) +IWMMXT_OP_CMP(mins, int8_t, int16_t, int32_t, <) +IWMMXT_OP_CMP(minu, uint8_t, uint16_t, uint32_t, <) +IWMMXT_OP_CMP(maxs, int8_t, int16_t, int32_t, >) +IWMMXT_OP_CMP(maxu, uint8_t, uint16_t, uint32_t, >) +#undef CMP +#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((M0 >> SHR) & MASK) \ + OPER (TYPE) ((M1 >> SHR) & MASK)) & MASK) << SHR) +IWMMXT_OP_CMP(subn, uint8_t, uint16_t, uint32_t, -) +IWMMXT_OP_CMP(addn, uint8_t, uint16_t, uint32_t, +) +#undef CMP +/* TODO Signed- and Unsigned-Saturation */ +#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((M0 >> SHR) & MASK) \ + OPER (TYPE) ((M1 >> SHR) & MASK)) & MASK) << SHR) +IWMMXT_OP_CMP(subu, uint8_t, uint16_t, uint32_t, -) +IWMMXT_OP_CMP(addu, uint8_t, uint16_t, uint32_t, +) +IWMMXT_OP_CMP(subs, int8_t, int16_t, int32_t, -) +IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +) +#undef CMP +#undef IWMMXT_OP_CMP + +void OPPROTO op_iwmmxt_avgb_M0_wRn(void) +{ +#define AVGB(SHR) ((( \ + ((M0 >> SHR) & 0xff) + ((M1 >> SHR) & 0xff) + PARAM2) >> 1) << SHR) + M0 = + AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) | + AVGB(32) | AVGB(40) | AVGB(48) | AVGB(56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + SIMD8_SET(ZBIT8((M0 >> 0) & 0xff), SIMD_ZBIT, 0) | + SIMD8_SET(ZBIT8((M0 >> 8) & 0xff), SIMD_ZBIT, 1) | + SIMD8_SET(ZBIT8((M0 >> 16) & 0xff), SIMD_ZBIT, 2) | + SIMD8_SET(ZBIT8((M0 >> 24) & 0xff), SIMD_ZBIT, 3) | + SIMD8_SET(ZBIT8((M0 >> 32) & 0xff), SIMD_ZBIT, 4) | + SIMD8_SET(ZBIT8((M0 >> 40) & 0xff), SIMD_ZBIT, 5) | + SIMD8_SET(ZBIT8((M0 >> 48) & 0xff), SIMD_ZBIT, 6) | + SIMD8_SET(ZBIT8((M0 >> 56) & 0xff), SIMD_ZBIT, 7); +#undef AVGB +} + +void OPPROTO op_iwmmxt_avgw_M0_wRn(void) +{ +#define AVGW(SHR) ((( \ + ((M0 >> SHR) & 0xffff) + ((M1 >> SHR) & 0xffff) + PARAM2) >> 1) << SHR) + M0 = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + SIMD16_SET(ZBIT16((M0 >> 0) & 0xffff), SIMD_ZBIT, 0) | + SIMD16_SET(ZBIT16((M0 >> 16) & 0xffff), SIMD_ZBIT, 1) | + SIMD16_SET(ZBIT16((M0 >> 32) & 0xffff), SIMD_ZBIT, 2) | + SIMD16_SET(ZBIT16((M0 >> 48) & 0xffff), SIMD_ZBIT, 3); +#undef AVGW +} + +void OPPROTO op_iwmmxt_msadb_M0_wRn(void) +{ + M0 = ((((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) + + ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff)) & 0xffffffff) | + ((((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) + + ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff)) << 32); +} + +void OPPROTO op_iwmmxt_align_M0_T0_wRn(void) +{ + M0 >>= T0 << 3; + M0 |= M1 << (64 - (T0 << 3)); +} + +void OPPROTO op_iwmmxt_insr_M0_T0_T1(void) +{ + M0 &= ~((uint64_t) T1 << PARAM1); + M0 |= (uint64_t) (T0 & T1) << PARAM1; +} + +void OPPROTO op_iwmmxt_extrsb_T0_M0(void) +{ + T0 = EXTEND8((M0 >> PARAM1) & 0xff); +} + +void OPPROTO op_iwmmxt_extrsw_T0_M0(void) +{ + T0 = EXTEND16((M0 >> PARAM1) & 0xffff); +} + +void OPPROTO op_iwmmxt_extru_T0_M0_T1(void) +{ + T0 = (M0 >> PARAM1) & T1; +} + +void OPPROTO op_iwmmxt_bcstb_M0_T0(void) +{ + T0 &= 0xff; + M0 = + ((uint64_t) T0 << 0) | ((uint64_t) T0 << 8) | + ((uint64_t) T0 << 16) | ((uint64_t) T0 << 24) | + ((uint64_t) T0 << 32) | ((uint64_t) T0 << 40) | + ((uint64_t) T0 << 48) | ((uint64_t) T0 << 56); +} + +void OPPROTO op_iwmmxt_bcstw_M0_T0(void) +{ + T0 &= 0xffff; + M0 = + ((uint64_t) T0 << 0) | ((uint64_t) T0 << 16) | + ((uint64_t) T0 << 32) | ((uint64_t) T0 << 48); +} + +void OPPROTO op_iwmmxt_bcstl_M0_T0(void) +{ + M0 = ((uint64_t) T0 << 0) | ((uint64_t) T0 << 32); +} + +void OPPROTO op_iwmmxt_addcb_M0(void) +{ + M0 = + ((M0 >> 0) & 0xff) + ((M0 >> 8) & 0xff) + + ((M0 >> 16) & 0xff) + ((M0 >> 24) & 0xff) + + ((M0 >> 32) & 0xff) + ((M0 >> 40) & 0xff) + + ((M0 >> 48) & 0xff) + ((M0 >> 56) & 0xff); +} + +void OPPROTO op_iwmmxt_addcw_M0(void) +{ + M0 = + ((M0 >> 0) & 0xffff) + ((M0 >> 16) & 0xffff) + + ((M0 >> 32) & 0xffff) + ((M0 >> 48) & 0xffff); +} + +void OPPROTO op_iwmmxt_addcl_M0(void) +{ + M0 = (M0 & 0xffffffff) + (M0 >> 32); +} + +void OPPROTO op_iwmmxt_msbb_T0_M0(void) +{ + T0 = + ((M0 >> 7) & 0x01) | ((M0 >> 14) & 0x02) | + ((M0 >> 21) & 0x04) | ((M0 >> 28) & 0x08) | + ((M0 >> 35) & 0x10) | ((M0 >> 42) & 0x20) | + ((M0 >> 49) & 0x40) | ((M0 >> 56) & 0x80); +} + +void OPPROTO op_iwmmxt_msbw_T0_M0(void) +{ + T0 = + ((M0 >> 15) & 0x01) | ((M0 >> 30) & 0x02) | + ((M0 >> 45) & 0x04) | ((M0 >> 52) & 0x08); +} + +void OPPROTO op_iwmmxt_msbl_T0_M0(void) +{ + T0 = ((M0 >> 31) & 0x01) | ((M0 >> 62) & 0x02); +} + +void OPPROTO op_iwmmxt_srlw_M0_T0(void) +{ + M0 = + (((M0 & (0xffffll << 0)) >> T0) & (0xffffll << 0)) | + (((M0 & (0xffffll << 16)) >> T0) & (0xffffll << 16)) | + (((M0 & (0xffffll << 32)) >> T0) & (0xffffll << 32)) | + (((M0 & (0xffffll << 48)) >> T0) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); +} + +void OPPROTO op_iwmmxt_srll_M0_T0(void) +{ + M0 = + ((M0 & (0xffffffffll << 0)) >> T0) | + ((M0 >> T0) & (0xffffffffll << 32)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); +} + +void OPPROTO op_iwmmxt_srlq_M0_T0(void) +{ + M0 >>= T0; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0); +} + +void OPPROTO op_iwmmxt_sllw_M0_T0(void) +{ + M0 = + (((M0 & (0xffffll << 0)) << T0) & (0xffffll << 0)) | + (((M0 & (0xffffll << 16)) << T0) & (0xffffll << 16)) | + (((M0 & (0xffffll << 32)) << T0) & (0xffffll << 32)) | + (((M0 & (0xffffll << 48)) << T0) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); +} + +void OPPROTO op_iwmmxt_slll_M0_T0(void) +{ + M0 = + ((M0 << T0) & (0xffffffffll << 0)) | + ((M0 & (0xffffffffll << 32)) << T0); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); +} + +void OPPROTO op_iwmmxt_sllq_M0_T0(void) +{ + M0 <<= T0; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0); +} + +void OPPROTO op_iwmmxt_sraw_M0_T0(void) +{ + M0 = + ((uint64_t) ((EXTEND16(M0 >> 0) >> T0) & 0xffff) << 0) | + ((uint64_t) ((EXTEND16(M0 >> 16) >> T0) & 0xffff) << 16) | + ((uint64_t) ((EXTEND16(M0 >> 32) >> T0) & 0xffff) << 32) | + ((uint64_t) ((EXTEND16(M0 >> 48) >> T0) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); +} + +void OPPROTO op_iwmmxt_sral_M0_T0(void) +{ + M0 = + (((EXTEND32(M0 >> 0) >> T0) & 0xffffffff) << 0) | + (((EXTEND32(M0 >> 32) >> T0) & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); +} + +void OPPROTO op_iwmmxt_sraq_M0_T0(void) +{ + M0 = (int64_t) M0 >> T0; + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0); +} + +void OPPROTO op_iwmmxt_rorw_M0_T0(void) +{ + M0 = + ((((M0 & (0xffffll << 0)) >> T0) | + ((M0 & (0xffffll << 0)) << (16 - T0))) & (0xffffll << 0)) | + ((((M0 & (0xffffll << 16)) >> T0) | + ((M0 & (0xffffll << 16)) << (16 - T0))) & (0xffffll << 16)) | + ((((M0 & (0xffffll << 32)) >> T0) | + ((M0 & (0xffffll << 32)) << (16 - T0))) & (0xffffll << 32)) | + ((((M0 & (0xffffll << 48)) >> T0) | + ((M0 & (0xffffll << 48)) << (16 - T0))) & (0xffffll << 48)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); +} + +void OPPROTO op_iwmmxt_rorl_M0_T0(void) +{ + M0 = + ((M0 & (0xffffffffll << 0)) >> T0) | + ((M0 >> T0) & (0xffffffffll << 32)) | + ((M0 << (32 - T0)) & (0xffffffffll << 0)) | + ((M0 & (0xffffffffll << 32)) << (32 - T0)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); +} + +void OPPROTO op_iwmmxt_rorq_M0_T0(void) +{ + M0 = (M0 >> T0) | (M0 << (64 - T0)); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0); +} + +void OPPROTO op_iwmmxt_shufh_M0_T0(void) +{ + M0 = + (((M0 >> ((T0 << 4) & 0x30)) & 0xffff) << 0) | + (((M0 >> ((T0 << 2) & 0x30)) & 0xffff) << 16) | + (((M0 >> ((T0 << 0) & 0x30)) & 0xffff) << 32) | + (((M0 >> ((T0 >> 2) & 0x30)) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); +} + +/* TODO: Unsigned-Saturation */ +void OPPROTO op_iwmmxt_packuw_M0_wRn(void) +{ + M0 = + (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) | + (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) | + (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) | + (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | + NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | + NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | + NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); +} + +void OPPROTO op_iwmmxt_packul_M0_wRn(void) +{ + M0 = + (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) | + (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); +} + +void OPPROTO op_iwmmxt_packuq_M0_wRn(void) +{ + M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); +} + +/* TODO: Signed-Saturation */ +void OPPROTO op_iwmmxt_packsw_M0_wRn(void) +{ + M0 = + (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) | + (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) | + (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) | + (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | + NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | + NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | + NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); +} + +void OPPROTO op_iwmmxt_packsl_M0_wRn(void) +{ + M0 = + (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) | + (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | + NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); +} + +void OPPROTO op_iwmmxt_packsq_M0_wRn(void) +{ + M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32); + env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = + NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); +} + +void OPPROTO op_iwmmxt_muladdsl_M0_T0_T1(void) +{ + M0 += (int32_t) EXTEND32(T0) * (int32_t) EXTEND32(T1); +} + +void OPPROTO op_iwmmxt_muladdsw_M0_T0_T1(void) +{ + M0 += EXTEND32(EXTEND16S((T0 >> 0) & 0xffff) * + EXTEND16S((T1 >> 0) & 0xffff)); + M0 += EXTEND32(EXTEND16S((T0 >> 16) & 0xffff) * + EXTEND16S((T1 >> 16) & 0xffff)); +} + +void OPPROTO op_iwmmxt_muladdswl_M0_T0_T1(void) +{ + M0 += EXTEND32(EXTEND16S(T0 & 0xffff) * + EXTEND16S(T1 & 0xffff)); +} diff --git a/target-arm/op_mem.h b/target-arm/op_mem.h index 29fd85bc3..6bccb0651 100644 --- a/target-arm/op_mem.h +++ b/target-arm/op_mem.h @@ -67,4 +67,24 @@ VFP_MEM_OP(d,q) #undef VFP_MEM_OP +/* iwMMXt load/store. Address is in T1 */ +#define MMX_MEM_OP(name, ldname) \ +void OPPROTO glue(op_iwmmxt_ld##name,MEMSUFFIX)(void) \ +{ \ + M0 = glue(ld##ldname,MEMSUFFIX)(T1); \ + FORCE_RET(); \ +} \ +void OPPROTO glue(op_iwmmxt_st##name,MEMSUFFIX)(void) \ +{ \ + glue(st##name,MEMSUFFIX)(T1, M0); \ + FORCE_RET(); \ +} + +MMX_MEM_OP(b, ub) +MMX_MEM_OP(w, uw) +MMX_MEM_OP(l, l) +MMX_MEM_OP(q, q) + +#undef MMX_MEM_OP + #undef MEMSUFFIX diff --git a/target-arm/translate.c b/target-arm/translate.c index 65d234ae0..3d3dc3fd2 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3,6 +3,7 @@ * * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2005 CodeSourcery, LLC + * Copyright (c) 2007 OpenedHand, Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -492,6 +493,1067 @@ static inline void gen_mov_vreg_F0(int dp, int reg) gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); } +#define ARM_CP_RW_BIT (1 << 20) + +static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn) +{ + int rd; + uint32_t offset; + + rd = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rd); + + offset = (insn & 0xff) << ((insn >> 7) & 2); + if (insn & (1 << 24)) { + /* Pre indexed */ + if (insn & (1 << 23)) + gen_op_addl_T1_im(offset); + else + gen_op_addl_T1_im(-offset); + + if (insn & (1 << 21)) + gen_movl_reg_T1(s, rd); + } else if (insn & (1 << 21)) { + /* Post indexed */ + if (insn & (1 << 23)) + gen_op_movl_T0_im(offset); + else + gen_op_movl_T0_im(- offset); + gen_op_addl_T0_T1(); + gen_movl_reg_T0(s, rd); + } else if (!(insn & (1 << 23))) + return 1; + return 0; +} + +static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask) +{ + int rd = (insn >> 0) & 0xf; + + if (insn & (1 << 8)) + if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) + return 1; + else + gen_op_iwmmxt_movl_T0_wCx(rd); + else + gen_op_iwmmxt_movl_T0_T1_wRn(rd); + + gen_op_movl_T1_im(mask); + gen_op_andl_T0_T1(); + return 0; +} + +/* Disassemble an iwMMXt instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + int rd, wrd; + int rdhi, rdlo, rd0, rd1, i; + + if ((insn & 0x0e000e00) == 0x0c000000) { + if ((insn & 0x0fe00ff0) == 0x0c400000) { + wrd = insn & 0xf; + rdlo = (insn >> 12) & 0xf; + rdhi = (insn >> 16) & 0xf; + if (insn & ARM_CP_RW_BIT) { /* TMRRC */ + gen_op_iwmmxt_movl_T0_T1_wRn(wrd); + gen_movl_reg_T0(s, rdlo); + gen_movl_reg_T1(s, rdhi); + } else { /* TMCRR */ + gen_movl_T0_reg(s, rdlo); + gen_movl_T1_reg(s, rdhi); + gen_op_iwmmxt_movl_wRn_T0_T1(wrd); + gen_op_iwmmxt_set_mup(); + } + return 0; + } + + wrd = (insn >> 12) & 0xf; + if (gen_iwmmxt_address(s, insn)) + return 1; + if (insn & ARM_CP_RW_BIT) { + if ((insn >> 28) == 0xf) { /* WLDRW wCx */ + gen_ldst(ldl, s); + gen_op_iwmmxt_movl_wCx_T0(wrd); + } else { + if (insn & (1 << 8)) + if (insn & (1 << 22)) /* WLDRD */ + gen_ldst(iwmmxt_ldq, s); + else /* WLDRW wRd */ + gen_ldst(iwmmxt_ldl, s); + else + if (insn & (1 << 22)) /* WLDRH */ + gen_ldst(iwmmxt_ldw, s); + else /* WLDRB */ + gen_ldst(iwmmxt_ldb, s); + gen_op_iwmmxt_movq_wRn_M0(wrd); + } + } else { + if ((insn >> 28) == 0xf) { /* WSTRW wCx */ + gen_op_iwmmxt_movl_T0_wCx(wrd); + gen_ldst(stl, s); + } else { + gen_op_iwmmxt_movq_M0_wRn(wrd); + if (insn & (1 << 8)) + if (insn & (1 << 22)) /* WSTRD */ + gen_ldst(iwmmxt_stq, s); + else /* WSTRW wRd */ + gen_ldst(iwmmxt_stl, s); + else + if (insn & (1 << 22)) /* WSTRH */ + gen_ldst(iwmmxt_ldw, s); + else /* WSTRB */ + gen_ldst(iwmmxt_stb, s); + } + } + return 0; + } + + if ((insn & 0x0f000000) != 0x0e000000) + return 1; + + switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) { + case 0x000: /* WOR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_orq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x011: /* TMCR */ + if (insn & 0xf) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + switch (wrd) { + case ARM_IWMMXT_wCID: + case ARM_IWMMXT_wCASF: + break; + case ARM_IWMMXT_wCon: + gen_op_iwmmxt_set_cup(); + /* Fall through. */ + case ARM_IWMMXT_wCSSF: + gen_op_iwmmxt_movl_T0_wCx(wrd); + gen_movl_T1_reg(s, rd); + gen_op_bicl_T0_T1(); + gen_op_iwmmxt_movl_wCx_T0(wrd); + break; + case ARM_IWMMXT_wCGR0: + case ARM_IWMMXT_wCGR1: + case ARM_IWMMXT_wCGR2: + case ARM_IWMMXT_wCGR3: + gen_op_iwmmxt_set_cup(); + gen_movl_reg_T0(s, rd); + gen_op_iwmmxt_movl_wCx_T0(wrd); + break; + default: + return 1; + } + break; + case 0x100: /* WXOR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_xorq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x111: /* TMRC */ + if (insn & 0xf) + return 1; + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + gen_op_iwmmxt_movl_T0_wCx(wrd); + gen_movl_reg_T0(s, rd); + break; + case 0x300: /* WANDN */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_negq_M0(); + gen_op_iwmmxt_andq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x200: /* WAND */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_andq_M0_wRn(rd1); + gen_op_iwmmxt_setpsr_nz(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x810: case 0xa10: /* WMADD */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 0) & 0xf; + rd1 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) + gen_op_iwmmxt_maddsq_M0_wRn(rd1); + else + gen_op_iwmmxt_madduq_M0_wRn(rd1); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_unpacklb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_unpacklw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_unpackll_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_unpackhb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_unpackhw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_unpackhl_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 22)) + gen_op_iwmmxt_sadw_M0_wRn(rd1); + else + gen_op_iwmmxt_sadb_M0_wRn(rd1); + if (!(insn & (1 << 20))) + gen_op_iwmmxt_addl_M0_wRn(wrd); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) + gen_op_iwmmxt_mulsw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0); + else + gen_op_iwmmxt_muluw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 21)) + gen_op_iwmmxt_macsw_M0_wRn(rd1); + else + gen_op_iwmmxt_macuw_M0_wRn(rd1); + if (!(insn & (1 << 20))) { + if (insn & (1 << 21)) + gen_op_iwmmxt_addsq_M0_wRn(wrd); + else + gen_op_iwmmxt_adduq_M0_wRn(wrd); + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_cmpeqb_M0_wRn(rd1); + break; + case 1: + gen_op_iwmmxt_cmpeqw_M0_wRn(rd1); + break; + case 2: + gen_op_iwmmxt_cmpeql_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (insn & (1 << 22)) + gen_op_iwmmxt_avgw_M0_wRn(rd1, (insn >> 20) & 1); + else + gen_op_iwmmxt_avgb_M0_wRn(rd1, (insn >> 20) & 1); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_iwmmxt_movl_T0_wCx(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3)); + gen_op_movl_T1_im(7); + gen_op_andl_T0_T1(); + gen_op_iwmmxt_align_M0_T0_wRn(rd1); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */ + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + gen_movl_T0_reg(s, rd); + gen_op_iwmmxt_movq_M0_wRn(wrd); + switch ((insn >> 6) & 3) { + case 0: + gen_op_movl_T1_im(0xff); + gen_op_iwmmxt_insr_M0_T0_T1((insn & 7) << 3); + break; + case 1: + gen_op_movl_T1_im(0xffff); + gen_op_iwmmxt_insr_M0_T0_T1((insn & 3) << 4); + break; + case 2: + gen_op_movl_T1_im(0xffffffff); + gen_op_iwmmxt_insr_M0_T0_T1((insn & 1) << 5); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */ + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + if (rd == 15) + return 1; + gen_op_iwmmxt_movq_M0_wRn(wrd); + switch ((insn >> 22) & 3) { + case 0: + if (insn & 8) + gen_op_iwmmxt_extrsb_T0_M0((insn & 7) << 3); + else { + gen_op_movl_T1_im(0xff); + gen_op_iwmmxt_extru_T0_M0_T1((insn & 7) << 3); + } + break; + case 1: + if (insn & 8) + gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4); + else { + gen_op_movl_T1_im(0xffff); + gen_op_iwmmxt_extru_T0_M0_T1((insn & 3) << 4); + } + break; + case 2: + gen_op_movl_T1_im(0xffffffff); + gen_op_iwmmxt_extru_T0_M0_T1((insn & 1) << 5); + break; + case 3: + return 1; + } + gen_op_movl_reg_TN[0][rd](); + break; + case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */ + if ((insn & 0x000ff008) != 0x0003f000) + return 1; + gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF); + switch ((insn >> 22) & 3) { + case 0: + gen_op_shrl_T1_im(((insn & 7) << 2) + 0); + break; + case 1: + gen_op_shrl_T1_im(((insn & 3) << 3) + 4); + break; + case 2: + gen_op_shrl_T1_im(((insn & 1) << 4) + 12); + break; + case 3: + return 1; + } + gen_op_shll_T1_im(28); + gen_op_movl_T0_T1(); + gen_op_movl_cpsr_T0(0xf0000000); + break; + case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */ + rd = (insn >> 12) & 0xf; + wrd = (insn >> 16) & 0xf; + gen_movl_T0_reg(s, rd); + switch ((insn >> 6) & 3) { + case 0: + gen_op_iwmmxt_bcstb_M0_T0(); + break; + case 1: + gen_op_iwmmxt_bcstw_M0_T0(); + break; + case 2: + gen_op_iwmmxt_bcstl_M0_T0(); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */ + if ((insn & 0x000ff00f) != 0x0003f000) + return 1; + gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF); + switch ((insn >> 22) & 3) { + case 0: + for (i = 0; i < 7; i ++) { + gen_op_shll_T1_im(4); + gen_op_andl_T0_T1(); + } + break; + case 1: + for (i = 0; i < 3; i ++) { + gen_op_shll_T1_im(8); + gen_op_andl_T0_T1(); + } + break; + case 2: + gen_op_shll_T1_im(16); + gen_op_andl_T0_T1(); + break; + case 3: + return 1; + } + gen_op_movl_cpsr_T0(0xf0000000); + break; + case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */ + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_addcb_M0(); + break; + case 1: + gen_op_iwmmxt_addcw_M0(); + break; + case 2: + gen_op_iwmmxt_addcl_M0(); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */ + if ((insn & 0x000ff00f) != 0x0003f000) + return 1; + gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF); + switch ((insn >> 22) & 3) { + case 0: + for (i = 0; i < 7; i ++) { + gen_op_shll_T1_im(4); + gen_op_orl_T0_T1(); + } + break; + case 1: + for (i = 0; i < 3; i ++) { + gen_op_shll_T1_im(8); + gen_op_orl_T0_T1(); + } + break; + case 2: + gen_op_shll_T1_im(16); + gen_op_orl_T0_T1(); + break; + case 3: + return 1; + } + gen_op_movl_T1_im(0xf0000000); + gen_op_andl_T0_T1(); + gen_op_movl_cpsr_T0(0xf0000000); + break; + case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */ + rd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + if ((insn & 0xf) != 0) + return 1; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + gen_op_iwmmxt_msbb_T0_M0(); + break; + case 1: + gen_op_iwmmxt_msbw_T0_M0(); + break; + case 2: + gen_op_iwmmxt_msbl_T0_M0(); + break; + case 3: + return 1; + } + gen_movl_reg_T0(s, rd); + break; + case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */ + case 0x906: case 0xb06: case 0xd06: case 0xf06: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1); + else + gen_op_iwmmxt_cmpgtul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */ + case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsb_M0(); + else + gen_op_iwmmxt_unpacklub_M0(); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsw_M0(); + else + gen_op_iwmmxt_unpackluw_M0(); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpacklsl_M0(); + else + gen_op_iwmmxt_unpacklul_M0(); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */ + case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsb_M0(); + else + gen_op_iwmmxt_unpackhub_M0(); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsw_M0(); + else + gen_op_iwmmxt_unpackhuw_M0(); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_unpackhsl_M0(); + else + gen_op_iwmmxt_unpackhul_M0(); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */ + case 0x214: case 0x614: case 0xa14: case 0xe14: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (gen_iwmmxt_shift(insn, 0xff)) + return 1; + switch ((insn >> 22) & 3) { + case 0: + return 1; + case 1: + gen_op_iwmmxt_srlw_M0_T0(); + break; + case 2: + gen_op_iwmmxt_srll_M0_T0(); + break; + case 3: + gen_op_iwmmxt_srlq_M0_T0(); + break; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */ + case 0x014: case 0x414: case 0x814: case 0xc14: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (gen_iwmmxt_shift(insn, 0xff)) + return 1; + switch ((insn >> 22) & 3) { + case 0: + return 1; + case 1: + gen_op_iwmmxt_sraw_M0_T0(); + break; + case 2: + gen_op_iwmmxt_sral_M0_T0(); + break; + case 3: + gen_op_iwmmxt_sraq_M0_T0(); + break; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */ + case 0x114: case 0x514: case 0x914: case 0xd14: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (gen_iwmmxt_shift(insn, 0xff)) + return 1; + switch ((insn >> 22) & 3) { + case 0: + return 1; + case 1: + gen_op_iwmmxt_sllw_M0_T0(); + break; + case 2: + gen_op_iwmmxt_slll_M0_T0(); + break; + case 3: + gen_op_iwmmxt_sllq_M0_T0(); + break; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */ + case 0x314: case 0x714: case 0xb14: case 0xf14: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + return 1; + case 1: + if (gen_iwmmxt_shift(insn, 0xf)) + return 1; + gen_op_iwmmxt_rorw_M0_T0(); + break; + case 2: + if (gen_iwmmxt_shift(insn, 0x1f)) + return 1; + gen_op_iwmmxt_rorl_M0_T0(); + break; + case 3: + if (gen_iwmmxt_shift(insn, 0x3f)) + return 1; + gen_op_iwmmxt_rorq_M0_T0(); + break; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */ + case 0x916: case 0xb16: case 0xd16: case 0xf16: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsb_M0_wRn(rd1); + else + gen_op_iwmmxt_minub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsw_M0_wRn(rd1); + else + gen_op_iwmmxt_minuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_minsl_M0_wRn(rd1); + else + gen_op_iwmmxt_minul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */ + case 0x816: case 0xa16: case 0xc16: case 0xe16: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 22) & 3) { + case 0: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsb_M0_wRn(rd1); + else + gen_op_iwmmxt_maxub_M0_wRn(rd1); + break; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsw_M0_wRn(rd1); + else + gen_op_iwmmxt_maxuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_maxsl_M0_wRn(rd1); + else + gen_op_iwmmxt_maxul_M0_wRn(rd1); + break; + case 3: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */ + case 0x402: case 0x502: case 0x602: case 0x702: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_movl_T0_im((insn >> 20) & 3); + gen_op_iwmmxt_align_M0_T0_wRn(rd1); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */ + case 0x41a: case 0x51a: case 0x61a: case 0x71a: + case 0x81a: case 0x91a: case 0xa1a: case 0xb1a: + case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 20) & 0xf) { + case 0x0: + gen_op_iwmmxt_subnb_M0_wRn(rd1); + break; + case 0x1: + gen_op_iwmmxt_subub_M0_wRn(rd1); + break; + case 0x3: + gen_op_iwmmxt_subsb_M0_wRn(rd1); + break; + case 0x4: + gen_op_iwmmxt_subnw_M0_wRn(rd1); + break; + case 0x5: + gen_op_iwmmxt_subuw_M0_wRn(rd1); + break; + case 0x7: + gen_op_iwmmxt_subsw_M0_wRn(rd1); + break; + case 0x8: + gen_op_iwmmxt_subnl_M0_wRn(rd1); + break; + case 0x9: + gen_op_iwmmxt_subul_M0_wRn(rd1); + break; + case 0xb: + gen_op_iwmmxt_subsl_M0_wRn(rd1); + break; + default: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */ + case 0x41e: case 0x51e: case 0x61e: case 0x71e: + case 0x81e: case 0x91e: case 0xa1e: case 0xb1e: + case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + gen_op_movl_T0_im(((insn >> 16) & 0xf0) | (insn & 0x0f)); + gen_op_iwmmxt_shufh_M0_T0(); + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */ + case 0x418: case 0x518: case 0x618: case 0x718: + case 0x818: case 0x918: case 0xa18: case 0xb18: + case 0xc18: case 0xd18: case 0xe18: case 0xf18: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + switch ((insn >> 20) & 0xf) { + case 0x0: + gen_op_iwmmxt_addnb_M0_wRn(rd1); + break; + case 0x1: + gen_op_iwmmxt_addub_M0_wRn(rd1); + break; + case 0x3: + gen_op_iwmmxt_addsb_M0_wRn(rd1); + break; + case 0x4: + gen_op_iwmmxt_addnw_M0_wRn(rd1); + break; + case 0x5: + gen_op_iwmmxt_adduw_M0_wRn(rd1); + break; + case 0x7: + gen_op_iwmmxt_addsw_M0_wRn(rd1); + break; + case 0x8: + gen_op_iwmmxt_addnl_M0_wRn(rd1); + break; + case 0x9: + gen_op_iwmmxt_addul_M0_wRn(rd1); + break; + case 0xb: + gen_op_iwmmxt_addsl_M0_wRn(rd1); + break; + default: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */ + case 0x408: case 0x508: case 0x608: case 0x708: + case 0x808: case 0x908: case 0xa08: case 0xb08: + case 0xc08: case 0xd08: case 0xe08: case 0xf08: + wrd = (insn >> 12) & 0xf; + rd0 = (insn >> 16) & 0xf; + rd1 = (insn >> 0) & 0xf; + gen_op_iwmmxt_movq_M0_wRn(rd0); + if (!(insn & (1 << 20))) + return 1; + switch ((insn >> 22) & 3) { + case 0: + return 1; + case 1: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsw_M0_wRn(rd1); + else + gen_op_iwmmxt_packuw_M0_wRn(rd1); + break; + case 2: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsl_M0_wRn(rd1); + else + gen_op_iwmmxt_packul_M0_wRn(rd1); + break; + case 3: + if (insn & (1 << 21)) + gen_op_iwmmxt_packsq_M0_wRn(rd1); + else + gen_op_iwmmxt_packuq_M0_wRn(rd1); + break; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + gen_op_iwmmxt_set_cup(); + break; + case 0x201: case 0x203: case 0x205: case 0x207: + case 0x209: case 0x20b: case 0x20d: case 0x20f: + case 0x211: case 0x213: case 0x215: case 0x217: + case 0x219: case 0x21b: case 0x21d: case 0x21f: + wrd = (insn >> 5) & 0xf; + rd0 = (insn >> 12) & 0xf; + rd1 = (insn >> 0) & 0xf; + if (rd0 == 0xf || rd1 == 0xf) + return 1; + gen_op_iwmmxt_movq_M0_wRn(wrd); + switch ((insn >> 16) & 0xf) { + case 0x0: /* TMIA */ + gen_op_movl_TN_reg[0][rd0](); + gen_op_movl_TN_reg[1][rd1](); + gen_op_iwmmxt_muladdsl_M0_T0_T1(); + break; + case 0x8: /* TMIAPH */ + gen_op_movl_TN_reg[0][rd0](); + gen_op_movl_TN_reg[1][rd1](); + gen_op_iwmmxt_muladdsw_M0_T0_T1(); + break; + case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */ + gen_op_movl_TN_reg[1][rd0](); + if (insn & (1 << 16)) + gen_op_shrl_T1_im(16); + gen_op_movl_T0_T1(); + gen_op_movl_TN_reg[1][rd1](); + if (insn & (1 << 17)) + gen_op_shrl_T1_im(16); + gen_op_iwmmxt_muladdswl_M0_T0_T1(); + break; + default: + return 1; + } + gen_op_iwmmxt_movq_wRn_M0(wrd); + gen_op_iwmmxt_set_mup(); + break; + default: + return 1; + } + + return 0; +} + +/* Disassemble an XScale DSP instruction. Returns nonzero if an error occured + (ie. an undefined instruction). */ +static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn) +{ + int acc, rd0, rd1, rdhi, rdlo; + + if ((insn & 0x0ff00f10) == 0x0e200010) { + /* Multiply with Internal Accumulate Format */ + rd0 = (insn >> 12) & 0xf; + rd1 = insn & 0xf; + acc = (insn >> 5) & 7; + + if (acc != 0) + return 1; + + switch ((insn >> 16) & 0xf) { + case 0x0: /* MIA */ + gen_op_movl_TN_reg[0][rd0](); + gen_op_movl_TN_reg[1][rd1](); + gen_op_iwmmxt_muladdsl_M0_T0_T1(); + break; + case 0x8: /* MIAPH */ + gen_op_movl_TN_reg[0][rd0](); + gen_op_movl_TN_reg[1][rd1](); + gen_op_iwmmxt_muladdsw_M0_T0_T1(); + break; + case 0xc: /* MIABB */ + case 0xd: /* MIABT */ + case 0xe: /* MIATB */ + case 0xf: /* MIATT */ + gen_op_movl_TN_reg[1][rd0](); + if (insn & (1 << 16)) + gen_op_shrl_T1_im(16); + gen_op_movl_T0_T1(); + gen_op_movl_TN_reg[1][rd1](); + if (insn & (1 << 17)) + gen_op_shrl_T1_im(16); + gen_op_iwmmxt_muladdswl_M0_T0_T1(); + break; + default: + return 1; + } + + gen_op_iwmmxt_movq_wRn_M0(acc); + return 0; + } + + if ((insn & 0x0fe00ff8) == 0x0c400000) { + /* Internal Accumulator Access Format */ + rdhi = (insn >> 16) & 0xf; + rdlo = (insn >> 12) & 0xf; + acc = insn & 7; + + if (acc != 0) + return 1; + + if (insn & ARM_CP_RW_BIT) { /* MRA */ + gen_op_iwmmxt_movl_T0_T1_wRn(acc); + gen_op_movl_reg_TN[0][rdlo](); + gen_op_movl_T0_im((1 << (40 - 32)) - 1); + gen_op_andl_T0_T1(); + gen_op_movl_reg_TN[0][rdhi](); + } else { /* MAR */ + gen_op_movl_TN_reg[0][rdlo](); + gen_op_movl_TN_reg[1][rdhi](); + gen_op_iwmmxt_movl_wRn_T0_T1(acc); + } + return 0; + } + + return 1; +} + /* Disassemble system coprocessor instruction. Return nonzero if instruction is not defined. */ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) @@ -502,7 +1564,7 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) return 1; } - if (insn & (1 << 20)) { + if (insn & ARM_CP_RW_BIT) { if (!env->cp[cp].cp_read) return 1; gen_op_movl_T0_im((uint32_t) s->pc); @@ -540,7 +1602,7 @@ static int disas_cp15_insn(DisasContext *s, uint32_t insn) return 0; } rd = (insn >> 12) & 0xf; - if (insn & (1 << 20)) { + if (insn & ARM_CP_RW_BIT) { gen_op_movl_T0_cp15(insn); /* If the destination register is r15 then sets condition codes. */ if (rd != 15) @@ -587,7 +1649,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) we only set half the register. */ gen_mov_F0_vreg(1, rn); gen_op_vfp_mrrd(); - if (insn & (1 << 20)) { + if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ if (insn & (1 << 21)) gen_movl_reg_T1(s, rd); @@ -604,7 +1666,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) } } else { rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); - if (insn & (1 << 20)) { + if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ if (insn & (1 << 21)) { /* system register */ @@ -938,7 +2000,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) } else rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); - if (insn & (1 << 20)) { + if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ if (dp) { gen_mov_F0_vreg(1, rm); @@ -1005,7 +2067,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) else offset = 4; for (i = 0; i < n; i++) { - if (insn & (1 << 20)) { + if (insn & ARM_CP_RW_BIT) { /* load */ gen_vfp_ld(s, dp); gen_mov_vreg_F0(dp, rd + i); @@ -1845,6 +2907,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; switch (op1) { case 0 ... 1: + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + if (disas_iwmmxt_insn(env, s, insn)) + goto illegal_op; + } else if (arm_feature(env, ARM_FEATURE_XSCALE)) { + if (disas_dsp_insn(env, s, insn)) + goto illegal_op; + } else + goto illegal_op; + break; case 2 ... 9: case 12 ... 14: if (disas_cp_insn (env, s, insn)) diff --git a/tests/Makefile b/tests/Makefile index 79a3d55b5..ec3a93ce6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -82,6 +82,9 @@ hello-arm: hello-arm.o hello-arm.o: hello-arm.c arm-linux-gcc -Wall -g -O2 -c -o $@ $< +test-arm-iwmmxt: test-arm-iwmmxt.s + cpp < $< | arm-linux-gnu-gcc -Wall -static -march=iwmmxt -mabi=aapcs -x assembler - -o $@ + # MIPS test hello-mips: hello-mips.c mips-linux-gnu-gcc -nostdlib -static -mno-abicalls -fno-PIC -mabi=32 -Wall -Wextra -g -O2 -o $@ $< diff --git a/tests/test-arm-iwmmxt.s b/tests/test-arm-iwmmxt.s new file mode 100644 index 000000000..d647f9404 --- /dev/null +++ b/tests/test-arm-iwmmxt.s @@ -0,0 +1,49 @@ +@ Checks whether iwMMXt is functional. +.code 32 +.globl main + +main: +ldr r0, =data0 +ldr r1, =data1 +ldr r2, =data2 +#ifndef FPA +wldrd wr0, [r0, #0] +wldrd wr1, [r0, #8] +wldrd wr2, [r1, #0] +wldrd wr3, [r1, #8] +wsubb wr2, wr2, wr0 +wsubb wr3, wr3, wr1 +wldrd wr0, [r2, #0] +wldrd wr1, [r2, #8] +waddb wr0, wr0, wr2 +waddb wr1, wr1, wr3 +wstrd wr0, [r2, #0] +wstrd wr1, [r2, #8] +#else +ldfe f0, [r0, #0] +ldfe f1, [r0, #8] +ldfe f2, [r1, #0] +ldfe f3, [r1, #8] +adfdp f2, f2, f0 +adfdp f3, f3, f1 +ldfe f0, [r2, #0] +ldfe f1, [r2, #8] +adfd f0, f0, f2 +adfd f1, f1, f3 +stfe f0, [r2, #0] +stfe f1, [r2, #8] +#endif +mov r0, #1 +mov r1, r2 +mov r2, #0x11 +swi #0x900004 +mov r0, #0 +swi #0x900001 + +.data +data0: +.string "aaaabbbbccccdddd" +data1: +.string "bbbbccccddddeeee" +data2: +.string "hvLLWs\x1fsdrs9\x1fNJ-\n" -- cgit v1.2.3 From 3e3d5815cbc1fdbf33adbe55f63ede3acead886f Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 02:09:25 +0000 Subject: NAND Flash memory emulation and ECC calculation helpers for use by NAND controllers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2753 c046a42c-6fe2-441c-8c8c-71466251a162 --- ecc.h | 77 ++++++++ hw/nand.c | 603 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 21 +++ vl.h | 22 +++ 4 files changed, 723 insertions(+) create mode 100644 ecc.h create mode 100644 hw/nand.c diff --git a/ecc.h b/ecc.h new file mode 100644 index 000000000..11e6d0113 --- /dev/null +++ b/ecc.h @@ -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 + * + * This code is licensed under the GNU GPL v2. + */ + +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, + 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, + 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, + 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, + 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, +}; + +/* Update ECC parity count. */ +static inline uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample) +{ + uint8_t idx = nand_ecc_precalc_table[sample]; + + s->cp ^= idx & 0x3f; + if (idx & 0x40) { + s->lp[0] ^= ~s->count; + s->lp[1] ^= s->count; + } + s->count ++; + + return sample; +} + +/* Reinitialise the counters. */ +static inline void ecc_reset(struct ecc_state_s *s) +{ + s->lp[0] = 0x0000; + s->lp[1] = 0x0000; + s->cp = 0x00; + s->count = 0; +} diff --git a/hw/nand.c b/hw/nand.c new file mode 100644 index 000000000..04967817b --- /dev/null +++ b/hw/nand.c @@ -0,0 +1,603 @@ +/* + * Flash NAND memory emulation. Based on "16M x 8 Bit NAND Flash + * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from + * Samsung Electronic. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + */ + +#ifndef NAND_IO + +# include "vl.h" + +# define NAND_CMD_READ0 0x00 +# define NAND_CMD_READ1 0x01 +# define NAND_CMD_READ2 0x50 +# define NAND_CMD_LPREAD2 0x30 +# define NAND_CMD_NOSERIALREAD2 0x35 +# define NAND_CMD_RANDOMREAD1 0x05 +# define NAND_CMD_RANDOMREAD2 0xe0 +# define NAND_CMD_READID 0x90 +# define NAND_CMD_RESET 0xff +# define NAND_CMD_PAGEPROGRAM1 0x80 +# define NAND_CMD_PAGEPROGRAM2 0x10 +# define NAND_CMD_CACHEPROGRAM2 0x15 +# define NAND_CMD_BLOCKERASE1 0x60 +# define NAND_CMD_BLOCKERASE2 0xd0 +# define NAND_CMD_READSTATUS 0x70 +# define NAND_CMD_COPYBACKPRG1 0x85 + +# define NAND_IOSTATUS_ERROR (1 << 0) +# define NAND_IOSTATUS_PLANE0 (1 << 1) +# define NAND_IOSTATUS_PLANE1 (1 << 2) +# define NAND_IOSTATUS_PLANE2 (1 << 3) +# define NAND_IOSTATUS_PLANE3 (1 << 4) +# define NAND_IOSTATUS_BUSY (1 << 6) +# define NAND_IOSTATUS_UNPROTCT (1 << 7) + +# define MAX_PAGE 0x800 +# define MAX_OOB 0x40 + +struct nand_flash_s { + uint8_t manf_id, chip_id; + int size, pages; + int page_shift, oob_shift, erase_shift, addr_shift; + uint8_t *storage; + BlockDriverState *bdrv; + int mem_oob; + + int cle, ale, ce, wp, gnd; + + uint8_t io[MAX_PAGE + MAX_OOB + 0x400]; + uint8_t *ioaddr; + int iolen; + + uint32_t cmd, addr; + int addrlen; + int status; + int offset; + + void (*blk_write)(struct nand_flash_s *s); + void (*blk_erase)(struct nand_flash_s *s); + void (*blk_load)(struct nand_flash_s *s, uint32_t addr, int offset); +}; + +# define NAND_NO_AUTOINCR 0x00000001 +# define NAND_BUSWIDTH_16 0x00000002 +# define NAND_NO_PADDING 0x00000004 +# define NAND_CACHEPRG 0x00000008 +# define NAND_COPYBACK 0x00000010 +# define NAND_IS_AND 0x00000020 +# define NAND_4PAGE_ARRAY 0x00000040 +# define NAND_NO_READRDY 0x00000100 +# define NAND_SAMSUNG_LP (NAND_NO_PADDING | NAND_COPYBACK) + +# define NAND_IO + +# define PAGE(addr) ((addr) >> ADDR_SHIFT) +# define PAGE_START(page) (PAGE(page) * (PAGE_SIZE + OOB_SIZE)) +# define PAGE_MASK ((1 << ADDR_SHIFT) - 1) +# define OOB_SHIFT (PAGE_SHIFT - 5) +# define OOB_SIZE (1 << OOB_SHIFT) +# define SECTOR(addr) ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT)) +# define SECTOR_OFFSET(addr) ((addr) & ((511 >> PAGE_SHIFT) << 8)) + +# define PAGE_SIZE 256 +# define PAGE_SHIFT 8 +# define PAGE_SECTORS 1 +# define ADDR_SHIFT 8 +# include "nand.c" +# define PAGE_SIZE 512 +# define PAGE_SHIFT 9 +# define PAGE_SECTORS 1 +# define ADDR_SHIFT 8 +# include "nand.c" +# define PAGE_SIZE 2048 +# define PAGE_SHIFT 11 +# define PAGE_SECTORS 4 +# define ADDR_SHIFT 16 +# include "nand.c" + +/* Information based on Linux drivers/mtd/nand/nand_ids.c */ +struct nand_info_s { + int size; + int width; + int page_shift; + int erase_shift; + uint32_t options; +} nand_flash_ids[0x100] = { + [0 ... 0xff] = { 0 }, + + [0x6e] = { 1, 8, 8, 4, 0 }, + [0x64] = { 2, 8, 8, 4, 0 }, + [0x6b] = { 4, 8, 9, 4, 0 }, + [0xe8] = { 1, 8, 8, 4, 0 }, + [0xec] = { 1, 8, 8, 4, 0 }, + [0xea] = { 2, 8, 8, 4, 0 }, + [0xd5] = { 4, 8, 9, 4, 0 }, + [0xe3] = { 4, 8, 9, 4, 0 }, + [0xe5] = { 4, 8, 9, 4, 0 }, + [0xd6] = { 8, 8, 9, 4, 0 }, + + [0x39] = { 8, 8, 9, 4, 0 }, + [0xe6] = { 8, 8, 9, 4, 0 }, + [0x49] = { 8, 16, 9, 4, NAND_BUSWIDTH_16 }, + [0x59] = { 8, 16, 9, 4, NAND_BUSWIDTH_16 }, + + [0x33] = { 16, 8, 9, 5, 0 }, + [0x73] = { 16, 8, 9, 5, 0 }, + [0x43] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 }, + [0x53] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 }, + + [0x35] = { 32, 8, 9, 5, 0 }, + [0x75] = { 32, 8, 9, 5, 0 }, + [0x45] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 }, + [0x55] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 }, + + [0x36] = { 64, 8, 9, 5, 0 }, + [0x76] = { 64, 8, 9, 5, 0 }, + [0x46] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 }, + [0x56] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 }, + + [0x78] = { 128, 8, 9, 5, 0 }, + [0x39] = { 128, 8, 9, 5, 0 }, + [0x79] = { 128, 8, 9, 5, 0 }, + [0x72] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, + [0x49] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, + [0x74] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, + [0x59] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, + + [0x71] = { 256, 8, 9, 5, 0 }, + + /* + * These are the new chips with large page size. The pagesize and the + * erasesize is determined from the extended id bytes + */ +# define LP_OPTIONS (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR) +# define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) + + /* 512 Megabit */ + [0xa2] = { 64, 8, 0, 0, LP_OPTIONS }, + [0xf2] = { 64, 8, 0, 0, LP_OPTIONS }, + [0xb2] = { 64, 16, 0, 0, LP_OPTIONS16 }, + [0xc2] = { 64, 16, 0, 0, LP_OPTIONS16 }, + + /* 1 Gigabit */ + [0xa1] = { 128, 8, 0, 0, LP_OPTIONS }, + [0xf1] = { 128, 8, 0, 0, LP_OPTIONS }, + [0xb1] = { 128, 16, 0, 0, LP_OPTIONS16 }, + [0xc1] = { 128, 16, 0, 0, LP_OPTIONS16 }, + + /* 2 Gigabit */ + [0xaa] = { 256, 8, 0, 0, LP_OPTIONS }, + [0xda] = { 256, 8, 0, 0, LP_OPTIONS }, + [0xba] = { 256, 16, 0, 0, LP_OPTIONS16 }, + [0xca] = { 256, 16, 0, 0, LP_OPTIONS16 }, + + /* 4 Gigabit */ + [0xac] = { 512, 8, 0, 0, LP_OPTIONS }, + [0xdc] = { 512, 8, 0, 0, LP_OPTIONS }, + [0xbc] = { 512, 16, 0, 0, LP_OPTIONS16 }, + [0xcc] = { 512, 16, 0, 0, LP_OPTIONS16 }, + + /* 8 Gigabit */ + [0xa3] = { 1024, 8, 0, 0, LP_OPTIONS }, + [0xd3] = { 1024, 8, 0, 0, LP_OPTIONS }, + [0xb3] = { 1024, 16, 0, 0, LP_OPTIONS16 }, + [0xc3] = { 1024, 16, 0, 0, LP_OPTIONS16 }, + + /* 16 Gigabit */ + [0xa5] = { 2048, 8, 0, 0, LP_OPTIONS }, + [0xd5] = { 2048, 8, 0, 0, LP_OPTIONS }, + [0xb5] = { 2048, 16, 0, 0, LP_OPTIONS16 }, + [0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 }, +}; + +static void nand_reset(struct nand_flash_s *s) +{ + s->cmd = NAND_CMD_READ0; + s->addr = 0; + s->addrlen = 0; + s->iolen = 0; + s->offset = 0; + s->status &= NAND_IOSTATUS_UNPROTCT; +} + +static void nand_command(struct nand_flash_s *s) +{ + switch (s->cmd) { + case NAND_CMD_READ0: + s->iolen = 0; + break; + + case NAND_CMD_READID: + s->io[0] = s->manf_id; + s->io[1] = s->chip_id; + s->io[2] = 'Q'; /* Don't-care byte (often 0xa5) */ + if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) + s->io[3] = 0x15; /* Page Size, Block Size, Spare Size.. */ + else + s->io[3] = 0xc0; /* Multi-plane */ + s->ioaddr = s->io; + s->iolen = 4; + break; + + case NAND_CMD_RANDOMREAD2: + case NAND_CMD_NOSERIALREAD2: + if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)) + break; + + s->blk_load(s, s->addr, s->addr & ((1 << s->addr_shift) - 1)); + break; + + case NAND_CMD_RESET: + nand_reset(s); + break; + + case NAND_CMD_PAGEPROGRAM1: + s->ioaddr = s->io; + s->iolen = 0; + break; + + case NAND_CMD_PAGEPROGRAM2: + if (s->wp) { + s->blk_write(s); + } + break; + + case NAND_CMD_BLOCKERASE1: + break; + + case NAND_CMD_BLOCKERASE2: + if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) + s->addr <<= 16; + else + s->addr <<= 8; + + if (s->wp) { + s->blk_erase(s); + } + break; + + case NAND_CMD_READSTATUS: + s->io[0] = s->status; + s->ioaddr = s->io; + s->iolen = 1; + break; + + default: + printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd); + } +} + +/* + * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip + * outputs are R/B and eight I/O pins. + * + * CE, WP and R/B are active low. + */ +void nand_setpins(struct nand_flash_s *s, + int cle, int ale, int ce, int wp, int gnd) +{ + s->cle = cle; + s->ale = ale; + s->ce = ce; + s->wp = wp; + s->gnd = gnd; + if (wp) + s->status |= NAND_IOSTATUS_UNPROTCT; + else + s->status &= ~NAND_IOSTATUS_UNPROTCT; +} + +void nand_getpins(struct nand_flash_s *s, int *rb) +{ + *rb = 1; +} + +void nand_setio(struct nand_flash_s *s, uint8_t value) +{ + if (!s->ce && s->cle) { + if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) { + if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2) + return; + if (value == NAND_CMD_RANDOMREAD1) { + s->addr &= ~((1 << s->addr_shift) - 1); + s->addrlen = 0; + return; + } + } + if (value == NAND_CMD_READ0) + s->offset = 0; + else if (value == NAND_CMD_READ1) { + s->offset = 0x100; + value = NAND_CMD_READ0; + } + else if (value == NAND_CMD_READ2) { + s->offset = 1 << s->page_shift; + value = NAND_CMD_READ0; + } + + s->cmd = value; + + if (s->cmd == NAND_CMD_READSTATUS || + s->cmd == NAND_CMD_PAGEPROGRAM2 || + s->cmd == NAND_CMD_BLOCKERASE1 || + s->cmd == NAND_CMD_BLOCKERASE2 || + s->cmd == NAND_CMD_NOSERIALREAD2 || + s->cmd == NAND_CMD_RANDOMREAD2 || + s->cmd == NAND_CMD_RESET) + nand_command(s); + + if (s->cmd != NAND_CMD_RANDOMREAD2) { + s->addrlen = 0; + s->addr = 0; + } + } + + if (s->ale) { + s->addr |= value << (s->addrlen * 8); + s->addrlen ++; + + if (s->addrlen == 1 && s->cmd == NAND_CMD_READID) + nand_command(s); + + if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && + s->addrlen == 3 && ( + s->cmd == NAND_CMD_READ0 || + s->cmd == NAND_CMD_PAGEPROGRAM1)) + nand_command(s); + if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && + s->addrlen == 4 && ( + s->cmd == NAND_CMD_READ0 || + s->cmd == NAND_CMD_PAGEPROGRAM1)) + nand_command(s); + } + + if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) { + if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) + s->io[s->iolen ++] = value; + } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) { + if ((s->addr & ((1 << s->addr_shift) - 1)) < + (1 << s->page_shift) + (1 << s->oob_shift)) { + s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value; + s->addr ++; + } + } +} + +uint8_t nand_getio(struct nand_flash_s *s) +{ + int offset; + + /* Allow sequential reading */ + if (!s->iolen && s->cmd == NAND_CMD_READ0) { + offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset; + s->offset = 0; + + s->blk_load(s, s->addr, offset); + if (s->gnd) + s->iolen = (1 << s->page_shift) - offset; + else + s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset; + } + + if (s->ce || s->iolen <= 0) + return 0; + + s->iolen --; + return *(s->ioaddr ++); +} + +struct nand_flash_s *nand_init(int manf_id, int chip_id) +{ + int pagesize; + struct nand_flash_s *s; + + if (nand_flash_ids[chip_id].size == 0) { + cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n", + __FUNCTION__); + } + + s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s)); + s->bdrv = mtd_bdrv; + s->manf_id = manf_id; + s->chip_id = chip_id; + s->size = nand_flash_ids[s->chip_id].size << 20; + if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) { + s->page_shift = 11; + s->erase_shift = 6; + } else { + s->page_shift = nand_flash_ids[s->chip_id].page_shift; + s->erase_shift = nand_flash_ids[s->chip_id].erase_shift; + } + + switch (1 << s->page_shift) { + case 256: + nand_init_256(s); + break; + case 512: + nand_init_512(s); + break; + case 2048: + nand_init_2048(s); + break; + default: + cpu_abort(cpu_single_env, "%s: Unsupported NAND block size.\n", + __FUNCTION__); + } + + pagesize = 1 << s->oob_shift; + s->mem_oob = 1; + if (s->bdrv && bdrv_getlength(s->bdrv) >= + (s->pages << s->page_shift) + (s->pages << s->oob_shift)) { + pagesize = 0; + s->mem_oob = 0; + } + + if (!s->bdrv) + pagesize += 1 << s->page_shift; + if (pagesize) + s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize), + 0xff, s->pages * pagesize); + return s; +} + +void nand_done(struct nand_flash_s *s) +{ + if (s->bdrv) { + bdrv_close(s->bdrv); + bdrv_delete(s->bdrv); + } + + if (!s->bdrv || s->mem_oob) + free(s->storage); + + free(s); +} + +#else + +/* Program a single page */ +static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s) +{ + uint32_t off, page, sector, soff; + uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200]; + if (PAGE(s->addr) >= s->pages) + return; + + if (!s->bdrv) { + memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) + + s->offset, s->io, s->iolen); + } else if (s->mem_oob) { + sector = SECTOR(s->addr); + off = (s->addr & PAGE_MASK) + s->offset; + soff = SECTOR_OFFSET(s->addr); + if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) { + printf("%s: read error in sector %i\n", __FUNCTION__, sector); + return; + } + + memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off)); + if (off + s->iolen > PAGE_SIZE) { + page = PAGE(s->addr); + memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off, + MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE)); + } + + if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) + printf("%s: write error in sector %i\n", __FUNCTION__, sector); + } else { + off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset; + sector = off >> 9; + soff = off & 0x1ff; + if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) { + printf("%s: read error in sector %i\n", __FUNCTION__, sector); + return; + } + + memcpy(iobuf + soff, s->io, s->iolen); + + if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) + printf("%s: write error in sector %i\n", __FUNCTION__, sector); + } + s->offset = 0; +} + +/* Erase a single block */ +static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s) +{ + uint32_t i, page, addr; + uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, }; + addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1); + + if (PAGE(addr) >= s->pages) + return; + + if (!s->bdrv) { + memset(s->storage + PAGE_START(addr), + 0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift); + } else if (s->mem_oob) { + memset(s->storage + (PAGE(addr) << OOB_SHIFT), + 0xff, OOB_SIZE << s->erase_shift); + i = SECTOR(addr); + page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift)); + for (; i < page; i ++) + if (bdrv_write(s->bdrv, i, iobuf, 1) == -1) + printf("%s: write error in sector %i\n", __FUNCTION__, i); + } else { + addr = PAGE_START(addr); + page = addr >> 9; + if (bdrv_read(s->bdrv, page, iobuf, 1) == -1) + printf("%s: read error in sector %i\n", __FUNCTION__, page); + memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1); + if (bdrv_write(s->bdrv, page, iobuf, 1) == -1) + printf("%s: write error in sector %i\n", __FUNCTION__, page); + + memset(iobuf, 0xff, 0x200); + i = (addr & ~0x1ff) + 0x200; + for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200; + i < addr; i += 0x200) + if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1) + printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9); + + page = i >> 9; + if (bdrv_read(s->bdrv, page, iobuf, 1) == -1) + printf("%s: read error in sector %i\n", __FUNCTION__, page); + memset(iobuf, 0xff, addr & 0x1ff); + if (bdrv_write(s->bdrv, page, iobuf, 1) == -1) + printf("%s: write error in sector %i\n", __FUNCTION__, page); + } +} + +static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s, + uint32_t addr, int offset) +{ + if (PAGE(addr) >= s->pages) + return; + + if (s->bdrv) { + if (s->mem_oob) { + if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1) + printf("%s: read error in sector %i\n", + __FUNCTION__, SECTOR(addr)); + memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE, + s->storage + (PAGE(s->addr) << OOB_SHIFT), + OOB_SIZE); + s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; + } else { + if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9, + s->io, (PAGE_SECTORS + 2)) == -1) + printf("%s: read error in sector %i\n", + __FUNCTION__, PAGE_START(addr) >> 9); + s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset; + } + } else { + memcpy(s->io, s->storage + PAGE_START(s->addr) + + offset, PAGE_SIZE + OOB_SIZE - offset); + s->ioaddr = s->io; + } + + s->addr &= PAGE_SIZE - 1; + s->addr += PAGE_SIZE; +} + +static void glue(nand_init_, PAGE_SIZE)(struct nand_flash_s *s) +{ + s->oob_shift = PAGE_SHIFT - 5; + s->pages = s->size >> PAGE_SHIFT; + s->addr_shift = ADDR_SHIFT; + + s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE); + s->blk_write = glue(nand_blk_write_, PAGE_SIZE); + s->blk_load = glue(nand_blk_load_, PAGE_SIZE); +} + +# undef PAGE_SIZE +# undef PAGE_SHIFT +# undef PAGE_SECTORS +# undef ADDR_SHIFT +#endif /* NAND_IO */ diff --git a/vl.c b/vl.c index 0ed74152e..70534acb7 100644 --- a/vl.c +++ b/vl.c @@ -140,6 +140,7 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; BlockDriverState *pflash_table[MAX_PFLASH]; BlockDriverState *sd_bdrv; +BlockDriverState *mtd_bdrv; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; int vga_ram_size; @@ -6419,6 +6420,7 @@ void help(void) "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" + "-mtdblock file use 'file' as on-board Flash memory image\n" "-sd file use 'file' as SecureDigital card image\n" "-pflash file use 'file' as a parallel flash image\n" "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" @@ -6559,6 +6561,7 @@ enum { QEMU_OPTION_hdc, QEMU_OPTION_hdd, QEMU_OPTION_cdrom, + QEMU_OPTION_mtdblock, QEMU_OPTION_sd, QEMU_OPTION_pflash, QEMU_OPTION_boot, @@ -6640,6 +6643,7 @@ const QEMUOption qemu_options[] = { { "hdc", HAS_ARG, QEMU_OPTION_hdc }, { "hdd", HAS_ARG, QEMU_OPTION_hdd }, { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, + { "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock }, { "sd", HAS_ARG, QEMU_OPTION_sd }, { "pflash", HAS_ARG, QEMU_OPTION_pflash }, { "boot", HAS_ARG, QEMU_OPTION_boot }, @@ -6944,6 +6948,7 @@ int main(int argc, char **argv) const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *pflash_filename[MAX_PFLASH]; const char *sd_filename; + const char *mtd_filename; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; @@ -7008,6 +7013,7 @@ int main(int argc, char **argv) pflash_filename[i] = NULL; pflash_index = 0; sd_filename = NULL; + mtd_filename = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; #ifdef CONFIG_GDBSTUB @@ -7126,6 +7132,9 @@ int main(int argc, char **argv) cdrom_index = -1; } break; + case QEMU_OPTION_mtdblock: + mtd_filename = optarg; + break; case QEMU_OPTION_sd: sd_filename = optarg; break; @@ -7678,6 +7687,18 @@ int main(int argc, char **argv) qemu_key_check(sd_bdrv, sd_filename); } + if (mtd_filename) { + mtd_bdrv = bdrv_new ("mtd"); + if (bdrv_open(mtd_bdrv, mtd_filename, + snapshot ? BDRV_O_SNAPSHOT : 0) < 0 || + qemu_key_check(mtd_bdrv, mtd_filename)) { + fprintf(stderr, "qemu: could not open Flash image %s\n", + mtd_filename); + bdrv_delete(mtd_bdrv); + mtd_bdrv = 0; + } + } + register_savevm("timer", 0, 2, timer_save, timer_load, NULL); register_savevm("ram", 0, 2, ram_save, ram_load, NULL); diff --git a/vl.h b/vl.h index 23d8dd668..e427991ff 100644 --- a/vl.h +++ b/vl.h @@ -967,6 +967,7 @@ extern uint8_t _translate_keycode(const int key); extern BlockDriverState *bs_table[MAX_DISKS + 1]; extern BlockDriverState *sd_bdrv; +extern BlockDriverState *mtd_bdrv; void isa_ide_init(int iobase, int iobase2, qemu_irq irq, BlockDriverState *hd0, BlockDriverState *hd1); @@ -1478,6 +1479,27 @@ pflash_t *pflash_register (target_ulong base, ram_addr_t off, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); +/* nand.c */ +struct nand_flash_s; +struct nand_flash_s *nand_init(int manf_id, int chip_id); +void nand_done(struct nand_flash_s *s); +void nand_setpins(struct nand_flash_s *s, + int cle, int ale, int ce, int wp, int gnd); +void nand_getpins(struct nand_flash_s *s, int *rb); +void nand_setio(struct nand_flash_s *s, uint8_t value); +uint8_t nand_getio(struct nand_flash_s *s); + +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_NATIONAL 0x8f +#define NAND_MFR_RENESAS 0x07 +#define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_MICRON 0x2c + +#include "ecc.h" + /* PCMCIA/Cardbus */ struct pcmcia_socket_s { -- cgit v1.2.3 From fd5a3b33d1f19b4859a8c528097abdbc4463e7e0 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 02:12:42 +0000 Subject: Texas Instruments ADS7846 ADC chip. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2754 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ads7846.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 6 +++ 2 files changed, 137 insertions(+) create mode 100644 hw/ads7846.c diff --git a/hw/ads7846.c b/hw/ads7846.c new file mode 100644 index 000000000..d63a91541 --- /dev/null +++ b/hw/ads7846.c @@ -0,0 +1,131 @@ +/* + * TI ADS7846 chip emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + */ + +#include + +struct ads7846_state_s { + qemu_irq interrupt; + + int input[8]; + int pressure; + int noise; + + int cycle; + int output; +}; + +/* Control-byte bitfields */ +#define CB_PD0 (1 << 0) +#define CB_PD1 (1 << 1) +#define CB_SER (1 << 2) +#define CB_MODE (1 << 3) +#define CB_A0 (1 << 4) +#define CB_A1 (1 << 5) +#define CB_A2 (1 << 6) +#define CB_START (1 << 7) + +#define X_AXIS_DMAX 3680 +#define X_AXIS_MIN 150 +#define Y_AXIS_DMAX 3640 +#define Y_AXIS_MIN 190 + +#define ADS_VBAT 2000 +#define ADS_VAUX 2000 +#define ADS_TEMP0 2000 +#define ADS_TEMP1 3000 +#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15)) +#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15)) +#define ADS_Z1POS(x, y) 600 +#define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y)) + +static void ads7846_int_update(struct ads7846_state_s *s) +{ + if (s->interrupt) + qemu_set_irq(s->interrupt, s->pressure == 0); +} + +uint32_t ads7846_read(void *opaque) +{ + struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; + + return s->output; +} + +void ads7846_write(void *opaque, uint32_t value) +{ + struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; + + switch (s->cycle ++) { + case 0: + if (!(value & CB_START)) { + s->cycle = 0; + break; + } + + s->output = s->input[(value >> 4) & 7]; + + /* Imitate the ADC noise, some drivers expect this. */ + s->noise = (s->noise + 3) & 7; + switch ((value >> 4) & 7) { + case 1: s->output += s->noise ^ 2; break; + case 3: s->output += s->noise ^ 0; break; + case 4: s->output += s->noise ^ 7; break; + case 5: s->output += s->noise ^ 5; break; + } + + if (value & CB_MODE) + s->output >>= 4; /* 8 bits instead of 12 */ + + break; + case 1: + s->cycle = 0; + break; + } +} + +static void ads7846_ts_event(void *opaque, + int x, int y, int z, int buttons_state) +{ + struct ads7846_state_s *s = opaque; + + if (buttons_state) { + s->input[1] = ADS_YPOS(x, y); + s->input[3] = ADS_Z1POS(x, y); + s->input[4] = ADS_Z2POS(x, y); + s->input[5] = ADS_XPOS(x, y); + } + + if (s->pressure == !buttons_state) { + s->pressure = !!buttons_state; + + ads7846_int_update(s); + } +} + +struct ads7846_state_s *ads7846_init(qemu_irq penirq) +{ + struct ads7846_state_s *s; + s = (struct ads7846_state_s *) + qemu_mallocz(sizeof(struct ads7846_state_s)); + memset(s, 0, sizeof(struct ads7846_state_s)); + + s->interrupt = penirq; + + s->input[0] = ADS_TEMP0; /* TEMP0 */ + s->input[2] = ADS_VBAT; /* VBAT */ + s->input[6] = ADS_VAUX; /* VAUX */ + s->input[7] = ADS_TEMP1; /* TEMP1 */ + + /* We want absolute coordinates */ + qemu_add_mouse_event_handler(ads7846_ts_event, s, 1, + "QEMU ADS7846-driven Touchscreen"); + + ads7846_int_update(s); + return s; +} diff --git a/vl.h b/vl.h index e427991ff..7365d6766 100644 --- a/vl.h +++ b/vl.h @@ -1500,6 +1500,12 @@ uint8_t nand_getio(struct nand_flash_s *s); #include "ecc.h" +/* ads7846.c */ +struct ads7846_state_s; +uint32_t ads7846_read(void *opaque); +void ads7846_write(void *opaque, uint32_t value); +struct ads7846_state_s *ads7846_init(qemu_irq penirq); + /* PCMCIA/Cardbus */ struct pcmcia_socket_s { -- cgit v1.2.3 From c824cacdb1aa8bfd9e057dd64b4b8a16f5727fff Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 02:14:00 +0000 Subject: Maxim MAX1110/1111 ADC chip. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2755 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/max111x.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 8 ++++ 2 files changed, 144 insertions(+) create mode 100644 hw/max111x.c diff --git a/hw/max111x.c b/hw/max111x.c new file mode 100644 index 000000000..69019de7a --- /dev/null +++ b/hw/max111x.c @@ -0,0 +1,136 @@ +/* + * Maxim MAX1110/1111 ADC chip emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GNU GPLv2. + */ + +#include + +struct max111x_s { + qemu_irq interrupt; + uint8_t tb1, rb2, rb3; + int cycle; + + int input[8]; + int inputs, com; +}; + +/* Control-byte bitfields */ +#define CB_PD0 (1 << 0) +#define CB_PD1 (1 << 1) +#define CB_SGL (1 << 2) +#define CB_UNI (1 << 3) +#define CB_SEL0 (1 << 4) +#define CB_SEL1 (1 << 5) +#define CB_SEL2 (1 << 6) +#define CB_START (1 << 7) + +#define CHANNEL_NUM(v, b0, b1, b2) \ + ((((v) >> (2 + (b0))) & 4) | \ + (((v) >> (3 + (b1))) & 2) | \ + (((v) >> (4 + (b2))) & 1)) + +uint32_t max111x_read(void *opaque) +{ + struct max111x_s *s = (struct max111x_s *) opaque; + + if (!s->tb1) + return 0; + + switch (s->cycle ++) { + case 1: + return s->rb2; + case 2: + return s->rb3; + } + + return 0; +} + +/* Interpret a control-byte */ +void max111x_write(void *opaque, uint32_t value) +{ + struct max111x_s *s = (struct max111x_s *) opaque; + int measure, chan; + + /* Ignore the value if START bit is zero */ + if (!(value & CB_START)) + return; + + s->cycle = 0; + + if (!(value & CB_PD1)) { + s->tb1 = 0; + return; + } + + s->tb1 = value; + + if (s->inputs == 8) + chan = CHANNEL_NUM(value, 1, 0, 2); + else + chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2); + + if (value & CB_SGL) + measure = s->input[chan] - s->com; + else + measure = s->input[chan] - s->input[chan ^ 1]; + + if (!(value & CB_UNI)) + measure ^= 0x80; + + s->rb2 = (measure >> 2) & 0x3f; + s->rb3 = (measure << 6) & 0xc0; + + if (s->interrupt) + qemu_irq_raise(s->interrupt); +} + +static struct max111x_s *max111x_init(qemu_irq cb) +{ + struct max111x_s *s; + s = (struct max111x_s *) + qemu_mallocz(sizeof(struct max111x_s)); + memset(s, 0, sizeof(struct max111x_s)); + + s->interrupt = cb; + + /* TODO: add a user interface for setting these */ + s->input[0] = 0xf0; + s->input[1] = 0xe0; + s->input[2] = 0xd0; + s->input[3] = 0xc0; + s->input[4] = 0xb0; + s->input[5] = 0xa0; + s->input[6] = 0x90; + s->input[7] = 0x80; + s->com = 0; + return s; +} + +struct max111x_s *max1110_init(qemu_irq cb) +{ + struct max111x_s *s = max111x_init(cb); + s->inputs = 8; + return s; +} + +struct max111x_s *max1111_init(qemu_irq cb) +{ + struct max111x_s *s = max111x_init(cb); + s->inputs = 4; + return s; +} + +void max111x_set_input(struct max111x_s *s, int line, uint8_t value) +{ + if (line >= s->inputs) { + printf("%s: There's no input %i\n", __FUNCTION__, line); + return; + } + + s->input[line] = value; +} diff --git a/vl.h b/vl.h index 7365d6766..18476adcb 100644 --- a/vl.h +++ b/vl.h @@ -1506,6 +1506,14 @@ uint32_t ads7846_read(void *opaque); void ads7846_write(void *opaque, uint32_t value); struct ads7846_state_s *ads7846_init(qemu_irq penirq); +/* max111x.c */ +struct max111x_s; +uint32_t max111x_read(void *opaque); +void max111x_write(void *opaque, uint32_t value); +struct max111x_s *max1110_init(qemu_irq cb); +struct max111x_s *max1111_init(qemu_irq cb); +void max111x_set_input(struct max111x_s *s, int line, uint8_t value); + /* PCMCIA/Cardbus */ struct pcmcia_socket_s { -- cgit v1.2.3 From b00052e496395a9cd38b7efb558aa78855a1e179 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 02:22:06 +0000 Subject: Spitz PDA, example PXA270 machine (four similar models). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2756 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 14 +- hw/spitz.c | 1100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-doc.texi | 31 ++ vl.c | 6 + vl.h | 6 + 5 files changed, 1152 insertions(+), 5 deletions(-) create mode 100644 hw/spitz.c diff --git a/Makefile.target b/Makefile.target index b76694634..a576796df 100644 --- a/Makefile.target +++ b/Makefile.target @@ -371,7 +371,7 @@ VL_OBJS+=tap-win32.o endif SOUND_HW = sb16.o es1370.o -AUDIODRV = audio.o noaudio.o wavaudio.o +AUDIODRV = audio.o noaudio.o wavaudio.o mixeng.o ifdef CONFIG_SDL AUDIODRV += sdlaudio.o endif @@ -418,16 +418,16 @@ 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 mixeng.o apic.o parallel.o acpi.o piix_pci.o +VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o vmware_vga.o -CPPFLAGS += -DHAS_AUDIO +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 pflash_cfi02.o -VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.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 ppc405_uc.o ppc405_boards.o -CPPFLAGS += -DHAS_AUDIO +CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif ifeq ($(TARGET_BASE_ARCH), mips) VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o @@ -453,6 +453,10 @@ VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl181.o pl190.o VL_OBJS+= versatile_pci.o sd.o VL_OBJS+= arm_gic.o realview.o arm_sysctl.o VL_OBJS+= arm-semi.o +VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o +VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o +VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) +CPPFLAGS += -DHAS_AUDIO -DHIGH_LATENCY endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o diff --git a/hw/spitz.c b/hw/spitz.c new file mode 100644 index 000000000..84cd30507 --- /dev/null +++ b/hw/spitz.c @@ -0,0 +1,1100 @@ +/* + * PXA270-based Clamshell PDA platforms. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + */ + +#include "vl.h" + +#define spitz_printf(format, ...) \ + fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__) +#undef REG_FMT +#define REG_FMT "0x%02lx" + +/* Spitz Flash */ +#define FLASH_BASE 0x0c000000 +#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */ +#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */ +#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */ +#define FLASH_ECCCNTR 0x0c /* ECC byte counter */ +#define FLASH_ECCCLRR 0x10 /* Clear ECC */ +#define FLASH_FLASHIO 0x14 /* Flash I/O */ +#define FLASH_FLASHCTL 0x18 /* Flash Control */ + +#define FLASHCTL_CE0 (1 << 0) +#define FLASHCTL_CLE (1 << 1) +#define FLASHCTL_ALE (1 << 2) +#define FLASHCTL_WP (1 << 3) +#define FLASHCTL_CE1 (1 << 4) +#define FLASHCTL_RYBY (1 << 5) +#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1) + +struct sl_nand_s { + target_phys_addr_t target_base; + struct nand_flash_s *nand; + uint8_t ctl; + struct ecc_state_s ecc; +}; + +static uint32_t sl_readb(void *opaque, target_phys_addr_t addr) +{ + struct sl_nand_s *s = (struct sl_nand_s *) opaque; + int ryby; + addr -= s->target_base; + + switch (addr) { +#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to)) + case FLASH_ECCLPLB: + return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) | + BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7); + +#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to)) + case FLASH_ECCLPUB: + return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) | + BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7); + + case FLASH_ECCCP: + return s->ecc.cp; + + case FLASH_ECCCNTR: + return s->ecc.count & 0xff; + + case FLASH_FLASHCTL: + nand_getpins(s->nand, &ryby); + if (ryby) + return s->ctl | FLASHCTL_RYBY; + else + return s->ctl; + + case FLASH_FLASHIO: + return ecc_digest(&s->ecc, nand_getio(s->nand)); + + default: + spitz_printf("Bad register offset " REG_FMT "\n", addr); + } + return 0; +} + +static void sl_writeb(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct sl_nand_s *s = (struct sl_nand_s *) opaque; + addr -= s->target_base; + + switch (addr) { + case FLASH_ECCCLRR: + /* Value is ignored. */ + ecc_reset(&s->ecc); + break; + + case FLASH_FLASHCTL: + s->ctl = value & 0xff & ~FLASHCTL_RYBY; + nand_setpins(s->nand, + s->ctl & FLASHCTL_CLE, + s->ctl & FLASHCTL_ALE, + s->ctl & FLASHCTL_NCE, + s->ctl & FLASHCTL_WP, + 0); + break; + + case FLASH_FLASHIO: + nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff)); + break; + + default: + spitz_printf("Bad register offset " REG_FMT "\n", addr); + } +} + +enum { + FLASH_128M, + FLASH_1024M, +}; + +static void sl_flash_register(struct pxa2xx_state_s *cpu, int size) +{ + int iomemtype; + struct sl_nand_s *s; + CPUReadMemoryFunc *sl_readfn[] = { + sl_readb, + sl_readb, + sl_readb, + }; + CPUWriteMemoryFunc *sl_writefn[] = { + sl_writeb, + sl_writeb, + sl_writeb, + }; + + s = (struct sl_nand_s *) qemu_mallocz(sizeof(struct sl_nand_s)); + s->target_base = FLASH_BASE; + s->ctl = 0; + if (size == FLASH_128M) + s->nand = nand_init(NAND_MFR_SAMSUNG, 0x73); + else if (size == FLASH_1024M) + s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1); + + iomemtype = cpu_register_io_memory(0, sl_readfn, + sl_writefn, s); + cpu_register_physical_memory(s->target_base, 0x40, iomemtype); +} + +/* Spitz Keyboard */ + +#define SPITZ_KEY_STROBE_NUM 11 +#define SPITZ_KEY_SENSE_NUM 7 + +static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = { + 12, 17, 91, 34, 36, 38, 39 +}; + +static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = { + 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114 +}; + +/* Eighth additional row maps the special keys */ +static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = { + { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 }, + { -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 }, + { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 }, + { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 }, + { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 }, + { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x3d }, + { 0x37, 0x38, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 }, + { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 }, +}; + +#define SPITZ_GPIO_AK_INT 13 /* Remote control */ +#define SPITZ_GPIO_SYNC 16 /* Sync button */ +#define SPITZ_GPIO_ON_KEY 95 /* Power button */ +#define SPITZ_GPIO_SWA 97 /* Lid */ +#define SPITZ_GPIO_SWB 96 /* Tablet mode */ + +/* The special buttons are mapped to unused keys */ +static const int spitz_gpiomap[5] = { + SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY, + SPITZ_GPIO_SWA, SPITZ_GPIO_SWB, +}; +static int spitz_gpio_invert[5] = { 0, 0, 0, 0, 0, }; + +struct spitz_keyboard_s { + struct pxa2xx_state_s *cpu; + int keymap[0x80]; + uint16_t keyrow[SPITZ_KEY_SENSE_NUM]; + uint16_t strobe_state; + uint16_t sense_state; + + uint16_t pre_map[0x100]; + uint16_t modifiers; + uint16_t imodifiers; + uint8_t fifo[16]; + int fifopos, fifolen; + QEMUTimer *kbdtimer; +}; + +static void spitz_keyboard_sense_update(struct spitz_keyboard_s *s) +{ + int i; + uint16_t strobe, sense = 0; + for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) { + strobe = s->keyrow[i] & s->strobe_state; + if (strobe) { + sense |= 1 << i; + if (!(s->sense_state & (1 << i))) + pxa2xx_gpio_set(s->cpu->gpio, spitz_gpio_key_sense[i], 1); + } else if (s->sense_state & (1 << i)) + pxa2xx_gpio_set(s->cpu->gpio, spitz_gpio_key_sense[i], 0); + } + + s->sense_state = sense; +} + +static void spitz_keyboard_strobe(int line, int level, + struct spitz_keyboard_s *s) +{ + int i; + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++) + if (spitz_gpio_key_strobe[i] == line) { + if (level) + s->strobe_state |= 1 << i; + else + s->strobe_state &= ~(1 << i); + + spitz_keyboard_sense_update(s); + break; + } +} + +static void spitz_keyboard_keydown(struct spitz_keyboard_s *s, int keycode) +{ + int spitz_keycode = s->keymap[keycode & 0x7f]; + if (spitz_keycode == -1) + return; + + /* Handle the additional keys */ + if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) { + pxa2xx_gpio_set(s->cpu->gpio, spitz_gpiomap[spitz_keycode & 0xf], + (keycode < 0x80) ^ + spitz_gpio_invert[spitz_keycode & 0xf]); + return; + } + + if (keycode & 0x80) + s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf)); + else + s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf); + + spitz_keyboard_sense_update(s); +} + +#define SHIFT (1 << 7) +#define CTRL (1 << 8) +#define FN (1 << 9) + +#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c + +static void spitz_keyboard_handler(struct spitz_keyboard_s *s, int keycode) +{ + uint16_t code; + int mapcode; + switch (keycode) { + case 0x2a: /* Left Shift */ + s->modifiers |= 1; + break; + case 0xaa: + s->modifiers &= ~1; + break; + case 0x36: /* Right Shift */ + s->modifiers |= 2; + break; + case 0xb6: + s->modifiers &= ~2; + break; + case 0x1d: /* Control */ + s->modifiers |= 4; + break; + case 0x9d: + s->modifiers &= ~4; + break; + case 0x38: /* Alt */ + s->modifiers |= 8; + break; + case 0xb8: + s->modifiers &= ~8; + break; + } + + code = s->pre_map[mapcode = ((s->modifiers & 3) ? + (keycode | SHIFT) : + (keycode & ~SHIFT))]; + + if (code != mapcode) { +#if 0 + if ((code & SHIFT) && !(s->modifiers & 1)) + QUEUE_KEY(0x2a | (keycode & 0x80)); + if ((code & CTRL ) && !(s->modifiers & 4)) + QUEUE_KEY(0x1d | (keycode & 0x80)); + if ((code & FN ) && !(s->modifiers & 8)) + QUEUE_KEY(0x38 | (keycode & 0x80)); + if ((code & FN ) && (s->modifiers & 1)) + QUEUE_KEY(0x2a | (~keycode & 0x80)); + if ((code & FN ) && (s->modifiers & 2)) + QUEUE_KEY(0x36 | (~keycode & 0x80)); +#else + if (keycode & 0x80) { + if ((s->imodifiers & 1 ) && !(s->modifiers & 1)) + QUEUE_KEY(0x2a | 0x80); + if ((s->imodifiers & 4 ) && !(s->modifiers & 4)) + QUEUE_KEY(0x1d | 0x80); + if ((s->imodifiers & 8 ) && !(s->modifiers & 8)) + QUEUE_KEY(0x38 | 0x80); + if ((s->imodifiers & 0x10) && (s->modifiers & 1)) + QUEUE_KEY(0x2a); + if ((s->imodifiers & 0x20) && (s->modifiers & 2)) + QUEUE_KEY(0x36); + s->imodifiers = 0; + } else { + if ((code & SHIFT) && !((s->modifiers | s->imodifiers) & 1)) { + QUEUE_KEY(0x2a); + s->imodifiers |= 1; + } + if ((code & CTRL ) && !((s->modifiers | s->imodifiers) & 4)) { + QUEUE_KEY(0x1d); + s->imodifiers |= 4; + } + if ((code & FN ) && !((s->modifiers | s->imodifiers) & 8)) { + QUEUE_KEY(0x38); + s->imodifiers |= 8; + } + if ((code & FN ) && (s->modifiers & 1) && + !(s->imodifiers & 0x10)) { + QUEUE_KEY(0x2a | 0x80); + s->imodifiers |= 0x10; + } + if ((code & FN ) && (s->modifiers & 2) && + !(s->imodifiers & 0x20)) { + QUEUE_KEY(0x36 | 0x80); + s->imodifiers |= 0x20; + } + } +#endif + } + + QUEUE_KEY((code & 0x7f) | (keycode & 0x80)); +} + +static void spitz_keyboard_tick(void *opaque) +{ + struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque; + + if (s->fifolen) { + spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]); + s->fifolen --; + if (s->fifopos >= 16) + s->fifopos = 0; + } + + qemu_mod_timer(s->kbdtimer, qemu_get_clock(vm_clock) + ticks_per_sec / 32); +} + +static void spitz_keyboard_pre_map(struct spitz_keyboard_s *s) +{ + int i; + for (i = 0; i < 0x100; i ++) + s->pre_map[i] = i; + s->pre_map[0x02 | SHIFT ] = 0x02 | SHIFT; /* exclam */ + s->pre_map[0x28 | SHIFT ] = 0x03 | SHIFT; /* quotedbl */ + s->pre_map[0x04 | SHIFT ] = 0x04 | SHIFT; /* numbersign */ + s->pre_map[0x05 | SHIFT ] = 0x05 | SHIFT; /* dollar */ + s->pre_map[0x06 | SHIFT ] = 0x06 | SHIFT; /* percent */ + s->pre_map[0x08 | SHIFT ] = 0x07 | SHIFT; /* ampersand */ + s->pre_map[0x28 ] = 0x08 | SHIFT; /* apostrophe */ + s->pre_map[0x0a | SHIFT ] = 0x09 | SHIFT; /* parenleft */ + s->pre_map[0x0b | SHIFT ] = 0x0a | SHIFT; /* parenright */ + s->pre_map[0x29 | SHIFT ] = 0x0b | SHIFT; /* asciitilde */ + s->pre_map[0x03 | SHIFT ] = 0x0c | SHIFT; /* at */ + s->pre_map[0xd3 ] = 0x0e | FN; /* Delete */ + s->pre_map[0x3a ] = 0x0f | FN; /* Caps_Lock */ + s->pre_map[0x07 | SHIFT ] = 0x11 | FN; /* asciicircum */ + s->pre_map[0x0d ] = 0x12 | FN; /* equal */ + s->pre_map[0x0d | SHIFT ] = 0x13 | FN; /* plus */ + s->pre_map[0x1a ] = 0x14 | FN; /* bracketleft */ + s->pre_map[0x1b ] = 0x15 | FN; /* bracketright */ + s->pre_map[0x27 ] = 0x22 | FN; /* semicolon */ + s->pre_map[0x27 | SHIFT ] = 0x23 | FN; /* colon */ + s->pre_map[0x09 | SHIFT ] = 0x24 | FN; /* asterisk */ + s->pre_map[0x2b ] = 0x25 | FN; /* backslash */ + s->pre_map[0x2b | SHIFT ] = 0x26 | FN; /* bar */ + s->pre_map[0x0c | SHIFT ] = 0x30 | FN; /* underscore */ + s->pre_map[0x35 ] = 0x33 | SHIFT; /* slash */ + s->pre_map[0x35 | SHIFT ] = 0x34 | SHIFT; /* question */ + s->pre_map[0x49 ] = 0x48 | FN; /* Page_Up */ + s->pre_map[0x51 ] = 0x50 | FN; /* Page_Down */ + + s->modifiers = 0; + s->imodifiers = 0; + s->fifopos = 0; + s->fifolen = 0; + s->kbdtimer = qemu_new_timer(vm_clock, spitz_keyboard_tick, s); + spitz_keyboard_tick(s); +} + +#undef SHIFT +#undef CTRL +#undef FN + +static void spitz_keyboard_register(struct pxa2xx_state_s *cpu) +{ + int i, j; + struct spitz_keyboard_s *s; + + s = (struct spitz_keyboard_s *) + qemu_mallocz(sizeof(struct spitz_keyboard_s)); + memset(s, 0, sizeof(struct spitz_keyboard_s)); + s->cpu = cpu; + + for (i = 0; i < 0x80; i ++) + s->keymap[i] = -1; + for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++) + for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++) + if (spitz_keymap[i][j] != -1) + s->keymap[spitz_keymap[i][j]] = (i << 4) | j; + + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++) + pxa2xx_gpio_handler_set(cpu->gpio, spitz_gpio_key_strobe[i], + (gpio_handler_t) spitz_keyboard_strobe, s); + + spitz_keyboard_pre_map(s); + qemu_add_kbd_event_handler((QEMUPutKBDEvent *) spitz_keyboard_handler, s); +} + +/* SCOOP devices */ + +struct scoop_info_s { + target_phys_addr_t target_base; + uint16_t status; + uint16_t power; + uint32_t gpio_level; + uint32_t gpio_dir; + uint32_t prev_level; + struct { + gpio_handler_t fn; + void *opaque; + } handler[16]; + + uint16_t mcr; + uint16_t cdr; + uint16_t ccr; + uint16_t irr; + uint16_t imr; + uint16_t isr; + uint16_t gprr; +}; + +#define SCOOP_MCR 0x00 +#define SCOOP_CDR 0x04 +#define SCOOP_CSR 0x08 +#define SCOOP_CPR 0x0c +#define SCOOP_CCR 0x10 +#define SCOOP_IRR_IRM 0x14 +#define SCOOP_IMR 0x18 +#define SCOOP_ISR 0x1c +#define SCOOP_GPCR 0x20 +#define SCOOP_GPWR 0x24 +#define SCOOP_GPRR 0x28 + +static inline void scoop_gpio_handler_update(struct scoop_info_s *s) { + uint32_t level, diff; + int bit; + level = s->gpio_level & s->gpio_dir; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + if (s->handler[bit].fn) + s->handler[bit].fn(bit, (level >> bit) & 1, + s->handler[bit].opaque); + } + + s->prev_level = level; +} + +static uint32_t scoop_readb(void *opaque, target_phys_addr_t addr) +{ + struct scoop_info_s *s = (struct scoop_info_s *) opaque; + addr -= s->target_base; + + switch (addr) { + case SCOOP_MCR: + return s->mcr; + case SCOOP_CDR: + return s->cdr; + case SCOOP_CSR: + return s->status; + case SCOOP_CPR: + return s->power; + case SCOOP_CCR: + return s->ccr; + case SCOOP_IRR_IRM: + return s->irr; + case SCOOP_IMR: + return s->imr; + case SCOOP_ISR: + return s->isr; + case SCOOP_GPCR: + return s->gpio_dir; + case SCOOP_GPWR: + return s->gpio_level; + case SCOOP_GPRR: + return s->gprr; + default: + spitz_printf("Bad register offset " REG_FMT "\n", addr); + } + + return 0; +} + +static void scoop_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct scoop_info_s *s = (struct scoop_info_s *) opaque; + addr -= s->target_base; + value &= 0xffff; + + switch (addr) { + case SCOOP_MCR: + s->mcr = value; + break; + case SCOOP_CDR: + s->cdr = value; + break; + case SCOOP_CPR: + s->power = value; + if (value & 0x80) + s->power |= 0x8040; + break; + case SCOOP_CCR: + s->ccr = value; + break; + case SCOOP_IRR_IRM: + s->irr = value; + break; + case SCOOP_IMR: + s->imr = value; + break; + case SCOOP_ISR: + s->isr = value; + break; + case SCOOP_GPCR: + s->gpio_dir = value; + scoop_gpio_handler_update(s); + break; + case SCOOP_GPWR: + s->gpio_level = value & s->gpio_dir; + scoop_gpio_handler_update(s); + break; + case SCOOP_GPRR: + s->gprr = value; + break; + default: + spitz_printf("Bad register offset " REG_FMT "\n", addr); + } +} + +CPUReadMemoryFunc *scoop_readfn[] = { + scoop_readb, + scoop_readb, + scoop_readb, +}; +CPUWriteMemoryFunc *scoop_writefn[] = { + scoop_writeb, + scoop_writeb, + scoop_writeb, +}; + +static inline void scoop_gpio_set(struct scoop_info_s *s, int line, int level) +{ + if (line >= 16) { + spitz_printf("No GPIO pin %i\n", line); + return; + } + + if (level) + s->gpio_level |= (1 << line); + else + s->gpio_level &= ~(1 << line); +} + +static inline void scoop_gpio_handler_set(struct scoop_info_s *s, int line, + gpio_handler_t handler, void *opaque) { + if (line >= 16) { + spitz_printf("No GPIO pin %i\n", line); + return; + } + + s->handler[line].fn = handler; + s->handler[line].opaque = opaque; +} + +static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, + int count) { + int iomemtype; + struct scoop_info_s *s; + + s = (struct scoop_info_s *) + qemu_mallocz(sizeof(struct scoop_info_s) * 2); + memset(s, 0, sizeof(struct scoop_info_s) * count); + s[0].target_base = 0x10800000; + s[1].target_base = 0x08800040; + + /* Ready */ + s[0].status = 0x02; + s[1].status = 0x02; + + iomemtype = cpu_register_io_memory(0, scoop_readfn, + scoop_writefn, &s[0]); + cpu_register_physical_memory(s[0].target_base, 0xfff, iomemtype); + + if (count < 2) + return s; + + iomemtype = cpu_register_io_memory(0, scoop_readfn, + scoop_writefn, &s[1]); + cpu_register_physical_memory(s[1].target_base, 0xfff, iomemtype); + + return s; +} + +/* LCD backlight controller */ + +#define LCDTG_RESCTL 0x00 +#define LCDTG_PHACTRL 0x01 +#define LCDTG_DUTYCTRL 0x02 +#define LCDTG_POWERREG0 0x03 +#define LCDTG_POWERREG1 0x04 +#define LCDTG_GPOR3 0x05 +#define LCDTG_PICTRL 0x06 +#define LCDTG_POLCTRL 0x07 + +static int bl_intensity, bl_power; + +static void spitz_bl_update(struct pxa2xx_state_s *s) +{ + if (bl_power && bl_intensity) + spitz_printf("LCD Backlight now at %i/63\n", bl_intensity); + else + spitz_printf("LCD Backlight now off\n"); +} + +static void spitz_bl_bit5(int line, int level, void *opaque) +{ + int prev = bl_intensity; + + if (level) + bl_intensity &= ~0x20; + else + bl_intensity |= 0x20; + + if (bl_power && prev != bl_intensity) + spitz_bl_update((struct pxa2xx_state_s *) opaque); +} + +static void spitz_bl_power(int line, int level, void *opaque) +{ + bl_power = !!level; + spitz_bl_update((struct pxa2xx_state_s *) opaque); +} + +static void spitz_lcdtg_dac_put(void *opaque, uint8_t cmd) +{ + int addr, value; + addr = cmd >> 5; + value = cmd & 0x1f; + + switch (addr) { + case LCDTG_RESCTL: + if (value) + spitz_printf("LCD in QVGA mode\n"); + else + spitz_printf("LCD in VGA mode\n"); + break; + + case LCDTG_DUTYCTRL: + bl_intensity &= ~0x1f; + bl_intensity |= value; + if (bl_power) + spitz_bl_update((struct pxa2xx_state_s *) opaque); + break; + + case LCDTG_POWERREG0: + /* Set common voltage to M62332FP */ + break; + } +} + +/* SSP devices */ + +#define CORGI_SSP_PORT 2 + +#define SPITZ_GPIO_LCDCON_CS 53 +#define SPITZ_GPIO_ADS7846_CS 14 +#define SPITZ_GPIO_MAX1111_CS 20 +#define SPITZ_GPIO_TP_INT 11 + +static int lcd_en, ads_en, max_en; +static struct max111x_s *max1111; +static struct ads7846_state_s *ads7846; + +/* "Demux" the signal based on current chipselect */ +static uint32_t corgi_ssp_read(void *opaque) +{ + if (lcd_en) + return 0; + if (ads_en) + return ads7846_read(ads7846); + if (max_en) + return max111x_read(max1111); + return 0; +} + +static void corgi_ssp_write(void *opaque, uint32_t value) +{ + if (lcd_en) + spitz_lcdtg_dac_put(opaque, value); + if (ads_en) + ads7846_write(ads7846, value); + if (max_en) + max111x_write(max1111, value); +} + +static void corgi_ssp_gpio_cs(int line, int level, struct pxa2xx_state_s *s) +{ + if (line == SPITZ_GPIO_LCDCON_CS) + lcd_en = !level; + else if (line == SPITZ_GPIO_ADS7846_CS) + ads_en = !level; + else if (line == SPITZ_GPIO_MAX1111_CS) + max_en = !level; +} + +#define MAX1111_BATT_VOLT 1 +#define MAX1111_BATT_TEMP 2 +#define MAX1111_ACIN_VOLT 3 + +#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */ +#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */ +#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */ + +static void spitz_adc_temp_on(int line, int level, void *opaque) +{ + if (!max1111) + return; + + if (level) + max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP); + else + max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); +} + +static void spitz_pendown_set(void *opaque, int line, int level) +{ + struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; + pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_TP_INT, level); +} + +static void spitz_ssp_attach(struct pxa2xx_state_s *cpu) +{ + lcd_en = ads_en = max_en = 0; + + ads7846 = ads7846_init(qemu_allocate_irqs(spitz_pendown_set, cpu, 1)[0]); + + max1111 = max1111_init(0); + max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT); + max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); + max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN); + + pxa2xx_ssp_attach(cpu->ssp[CORGI_SSP_PORT - 1], corgi_ssp_read, + corgi_ssp_write, cpu); + + pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_LCDCON_CS, + (gpio_handler_t) corgi_ssp_gpio_cs, cpu); + pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_ADS7846_CS, + (gpio_handler_t) corgi_ssp_gpio_cs, cpu); + pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_MAX1111_CS, + (gpio_handler_t) corgi_ssp_gpio_cs, cpu); + + bl_intensity = 0x20; + bl_power = 0; +} + +/* CF Microdrive */ + +static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu) +{ + struct pcmcia_card_s *md; + BlockDriverState *bs = bs_table[0]; + + if (bs && bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) { + md = dscm1xxxx_init(bs); + pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); + } +} + +/* Other peripherals */ + +static void spitz_charge_switch(int line, int level, void *opaque) +{ + spitz_printf("Charging %s.\n", level ? "off" : "on"); +} + +static void spitz_discharge_switch(int line, int level, void *opaque) +{ + spitz_printf("Discharging %s.\n", level ? "on" : "off"); +} + +static void spitz_greenled_switch(int line, int level, void *opaque) +{ + spitz_printf("Green LED %s.\n", level ? "on" : "off"); +} + +static void spitz_orangeled_switch(int line, int level, void *opaque) +{ + spitz_printf("Orange LED %s.\n", level ? "on" : "off"); +} + +#define SPITZ_SCP_LED_GREEN 1 +#define SPITZ_SCP_JK_B 2 +#define SPITZ_SCP_CHRG_ON 3 +#define SPITZ_SCP_MUTE_L 4 +#define SPITZ_SCP_MUTE_R 5 +#define SPITZ_SCP_CF_POWER 6 +#define SPITZ_SCP_LED_ORANGE 7 +#define SPITZ_SCP_JK_A 8 +#define SPITZ_SCP_ADC_TEMP_ON 9 +#define SPITZ_SCP2_IR_ON 1 +#define SPITZ_SCP2_AKIN_PULLUP 2 +#define SPITZ_SCP2_BACKLIGHT_CONT 7 +#define SPITZ_SCP2_BACKLIGHT_ON 8 +#define SPITZ_SCP2_MIC_BIAS 9 + +static void spitz_scoop_gpio_setup(struct pxa2xx_state_s *cpu, + struct scoop_info_s *scp, int num) +{ + scoop_gpio_handler_set(&scp[0], SPITZ_SCP_CHRG_ON, + spitz_charge_switch, cpu); + scoop_gpio_handler_set(&scp[0], SPITZ_SCP_JK_B, + spitz_discharge_switch, cpu); + scoop_gpio_handler_set(&scp[0], SPITZ_SCP_LED_GREEN, + spitz_greenled_switch, cpu); + scoop_gpio_handler_set(&scp[0], SPITZ_SCP_LED_ORANGE, + spitz_orangeled_switch, cpu); + + if (num >= 2) { + scoop_gpio_handler_set(&scp[1], SPITZ_SCP2_BACKLIGHT_CONT, + spitz_bl_bit5, cpu); + scoop_gpio_handler_set(&scp[1], SPITZ_SCP2_BACKLIGHT_ON, + spitz_bl_power, cpu); + } + + scoop_gpio_handler_set(&scp[0], SPITZ_SCP_ADC_TEMP_ON, + spitz_adc_temp_on, cpu); +} + +#define SPITZ_GPIO_HSYNC 22 +#define SPITZ_GPIO_SD_DETECT 9 +#define SPITZ_GPIO_SD_WP 81 +#define SPITZ_GPIO_ON_RESET 89 +#define SPITZ_GPIO_BAT_COVER 90 +#define SPITZ_GPIO_CF1_IRQ 105 +#define SPITZ_GPIO_CF1_CD 94 +#define SPITZ_GPIO_CF2_IRQ 106 +#define SPITZ_GPIO_CF2_CD 93 + +int spitz_hsync; + +static void spitz_lcd_hsync_handler(void *opaque) +{ + struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; + pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_HSYNC, spitz_hsync); + spitz_hsync ^= 1; +} + +static void spitz_mmc_coverswitch_change(void *opaque, int in) +{ + struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; + pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SD_DETECT, in); +} + +static void spitz_mmc_writeprotect_change(void *opaque, int wp) +{ + struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; + pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SD_WP, wp); +} + +static void spitz_pcmcia_cb(void *opaque, int line, int level) +{ + struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; + static const int gpio_map[] = { + SPITZ_GPIO_CF1_IRQ, SPITZ_GPIO_CF1_CD, + SPITZ_GPIO_CF2_IRQ, SPITZ_GPIO_CF2_CD, + }; + pxa2xx_gpio_set(cpu->gpio, gpio_map[line], level); +} + +static void spitz_gpio_setup(struct pxa2xx_state_s *cpu, int slots) +{ + qemu_irq *pcmcia_cb; + /* + * Bad hack: We toggle the LCD hsync GPIO on every GPIO status + * read to satisfy broken guests that poll-wait for hsync. + * Simulating a real hsync event would be less practical and + * wouldn't guarantee that a guest ever exits the loop. + */ + spitz_hsync = 0; + pxa2xx_gpio_read_notifier(cpu->gpio, spitz_lcd_hsync_handler, cpu); + pxa2xx_lcd_vsync_cb(cpu->lcd, spitz_lcd_hsync_handler, cpu); + + /* MMC/SD host */ + pxa2xx_mmci_handlers(cpu->mmc, cpu, spitz_mmc_writeprotect_change, + spitz_mmc_coverswitch_change); + + /* Battery lock always closed */ + pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_BAT_COVER, 1); + + /* Handle reset */ + pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_ON_RESET, pxa2xx_reset, cpu); + + /* PCMCIA signals: card's IRQ and Card-Detect */ + pcmcia_cb = qemu_allocate_irqs(spitz_pcmcia_cb, cpu, slots * 2); + if (slots >= 1) + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], pcmcia_cb[0], pcmcia_cb[1]); + if (slots >= 2) + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], pcmcia_cb[2], pcmcia_cb[3]); + + /* Initialise the screen rotation related signals */ + spitz_gpio_invert[3] = 0; /* Always open */ + if (graphic_rotate) { /* Tablet mode */ + spitz_gpio_invert[4] = 0; + } else { /* Portrait mode */ + spitz_gpio_invert[4] = 1; + } + pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SWA, spitz_gpio_invert[3]); + pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SWB, spitz_gpio_invert[4]); +} + +/* Write the bootloader parameters memory area. */ + +#define MAGIC_CHG(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a) + +struct __attribute__ ((__packed__)) sl_param_info { + uint32_t comadj_keyword; + int32_t comadj; + + uint32_t uuid_keyword; + char uuid[16]; + + uint32_t touch_keyword; + int32_t touch_xp; + int32_t touch_yp; + int32_t touch_xd; + int32_t touch_yd; + + uint32_t adadj_keyword; + int32_t adadj; + + uint32_t phad_keyword; + int32_t phadadj; +} spitz_bootparam = { + .comadj_keyword = MAGIC_CHG('C', 'M', 'A', 'D'), + .comadj = 125, + .uuid_keyword = MAGIC_CHG('U', 'U', 'I', 'D'), + .uuid = { -1 }, + .touch_keyword = MAGIC_CHG('T', 'U', 'C', 'H'), + .touch_xp = -1, + .adadj_keyword = MAGIC_CHG('B', 'V', 'A', 'D'), + .adadj = -1, + .phad_keyword = MAGIC_CHG('P', 'H', 'A', 'D'), + .phadadj = 0x01, +}; + +static void sl_bootparam_write(uint32_t ptr) +{ + memcpy(phys_ram_base + ptr, &spitz_bootparam, + sizeof(struct sl_param_info)); +} + +#define SL_PXA_PARAM_BASE 0xa0000a00 + +/* Board init. */ +enum spitz_model_e { spitz, akita, borzoi, terrier }; + +static void spitz_common_init(int ram_size, int vga_ram_size, + DisplayState *ds, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + enum spitz_model_e model, int arm_id) +{ + uint32_t spitz_ram = 0x04000000; + uint32_t spitz_rom = 0x00800000; + struct pxa2xx_state_s *cpu; + struct scoop_info_s *scp; + + cpu = pxa270_init(ds, (model == terrier) ? "c5" : "c0"); + + /* Setup memory */ + if (ram_size < spitz_ram + spitz_rom) { + fprintf(stderr, "This platform requires %i bytes of memory\n", + spitz_ram + spitz_rom); + exit(1); + } + cpu_register_physical_memory(PXA2XX_RAM_BASE, spitz_ram, IO_MEM_RAM); + + sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M); + + cpu_register_physical_memory(0, spitz_rom, spitz_ram | IO_MEM_ROM); + + /* Setup peripherals */ + spitz_keyboard_register(cpu); + + spitz_ssp_attach(cpu); + + scp = spitz_scoop_init(cpu, (model == akita) ? 1 : 2); + + spitz_scoop_gpio_setup(cpu, scp, (model == akita) ? 1 : 2); + + spitz_gpio_setup(cpu, (model == akita) ? 1 : 2); + + if (model == terrier) + /* A 6.0 GB microdrive is permanently sitting in CF slot 0. */ + spitz_microdrive_attach(cpu); + else if (model != akita) + /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ + spitz_microdrive_attach(cpu); + + /* Setup initial (reset) machine state */ + cpu->env->regs[15] = PXA2XX_RAM_BASE; + + arm_load_kernel(cpu->env, ram_size, kernel_filename, kernel_cmdline, + initrd_filename, arm_id); + sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_RAM_BASE); +} + +static void spitz_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename, + kernel_cmdline, initrd_filename, spitz, 0x2c9); +} + +static void borzoi_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename, + kernel_cmdline, initrd_filename, borzoi, 0x33f); +} + +static void akita_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename, + kernel_cmdline, initrd_filename, akita, 0x2e8); +} + +static void terrier_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename, + kernel_cmdline, initrd_filename, terrier, 0x33f); +} + +QEMUMachine akitapda_machine = { + "akita", + "Akita PDA (PXA270)", + akita_init, +}; + +QEMUMachine spitzpda_machine = { + "spitz", + "Spitz PDA (PXA270)", + spitz_init, +}; + +QEMUMachine borzoipda_machine = { + "borzoi", + "Borzoi PDA (PXA270)", + borzoi_init, +}; + +QEMUMachine terrierpda_machine = { + "terrier", + "Terrier PDA (PXA270)", + terrier_init, +}; diff --git a/qemu-doc.texi b/qemu-doc.texi index b5c913197..830a2b6f4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -80,6 +80,7 @@ For system emulation, the following hardware targets are supported: @item ARM Integrator/CP (ARM926E or 1026E processor) @item ARM Versatile baseboard (ARM926E) @item ARM RealView Emulation baseboard (ARM926EJ-S) +@item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) @end itemize For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported. @@ -1777,6 +1778,36 @@ LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices PL181 MultiMedia Card Interface with SD card. @end itemize +The XScale-based clamshell PDA models ("Spitz", "Akita", "Borzoi" +and "Terrier") emulation includes the following peripherals: + +@itemize @minus +@item +Intel PXA270 System-on-chip (ARM V5TE core) +@item +NAND Flash memory +@item +IBM/Hitachi DSCM microdrive in a PXA PCMCIA slot - not in "Akita" +@item +On-chip OHCI USB controller +@item +On-chip LCD controller +@item +On-chip Real Time Clock +@item +TI ADS7846 touchscreen controller on SSP bus +@item +Maxim MAX1111 analog-digital converter on I@math{^2}C bus +@item +GPIO-connected keyboard controller and LEDs +@item +Secure Digital card conntected to PXA MMC/SD host +@item +Three on-chip UARTs +@item +WM8750 audio CODEC on I@math{^2}C and I@math{^2}S busses +@end itemize + A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. diff --git a/vl.c b/vl.c index 70534acb7..6a06b8635 100644 --- a/vl.c +++ b/vl.c @@ -6804,6 +6804,10 @@ void register_machines(void) qemu_register_machine(&versatilepb_machine); qemu_register_machine(&versatileab_machine); qemu_register_machine(&realview_machine); + qemu_register_machine(&akitapda_machine); + qemu_register_machine(&spitzpda_machine); + qemu_register_machine(&borzoipda_machine); + qemu_register_machine(&terrierpda_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); #elif defined(TARGET_ALPHA) @@ -6815,6 +6819,7 @@ void register_machines(void) #ifdef HAS_AUDIO struct soundhw soundhw[] = { +#ifdef HAS_AUDIO_CHOICE #ifdef TARGET_I386 { "pcspk", @@ -6863,6 +6868,7 @@ struct soundhw soundhw[] = { 0, { .init_pci = es1370_init } }, +#endif { NULL, NULL, 0, 0, { NULL } } }; diff --git a/vl.h b/vl.h index 18476adcb..f904ff269 100644 --- a/vl.h +++ b/vl.h @@ -1398,6 +1398,12 @@ extern QEMUMachine versatileab_machine; /* realview.c */ extern QEMUMachine realview_machine; +/* spitz.c */ +extern QEMUMachine akitapda_machine; +extern QEMUMachine spitzpda_machine; +extern QEMUMachine borzoipda_machine; +extern QEMUMachine terrierpda_machine; + /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); -- cgit v1.2.3 From 9d55199763d4067158d6c556e78312f7d007d914 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 02:24:42 +0000 Subject: Account for machine with RAM which is not mapped at 0x0 in arm_boot.c. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2757 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_boot.c | 19 ++++++++++--------- hw/integratorcp.c | 2 +- hw/realview.c | 2 +- hw/spitz.c | 2 +- hw/versatilepb.c | 2 +- target-arm/cpu.h | 3 ++- vl.h | 2 +- 7 files changed, 17 insertions(+), 15 deletions(-) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 095b0bb79..ed3ec5830 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -32,11 +32,12 @@ static void main_cpu_reset(void *opaque) if (env->kernel_filename) arm_load_kernel(env, env->ram_size, env->kernel_filename, env->kernel_cmdline, env->initrd_filename, - env->board_id); + env->board_id, env->loader_start); } static void set_kernel_args(uint32_t ram_size, int initrd_size, - const char *kernel_cmdline) + const char *kernel_cmdline, + target_phys_addr_t loader_start) { uint32_t *p; @@ -51,12 +52,12 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size, stl_raw(p++, 4); stl_raw(p++, 0x54410002); stl_raw(p++, ram_size); - stl_raw(p++, 0); + stl_raw(p++, loader_start); if (initrd_size) { /* ATAG_INITRD2 */ stl_raw(p++, 4); stl_raw(p++, 0x54420005); - stl_raw(p++, INITRD_LOAD_ADDR); + stl_raw(p++, loader_start + INITRD_LOAD_ADDR); stl_raw(p++, initrd_size); } if (kernel_cmdline && *kernel_cmdline) { @@ -77,7 +78,7 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size, void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, - int board_id) + int board_id, target_phys_addr_t loader_start) { int kernel_size; int initrd_size; @@ -98,6 +99,7 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, env->kernel_cmdline = kernel_cmdline; env->initrd_filename = initrd_filename; env->board_id = board_id; + env->loader_start = loader_start; qemu_register_reset(main_cpu_reset, env); } /* Assume that raw images are linux kernels, and ELF images are not. */ @@ -109,7 +111,7 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, if (kernel_size < 0) { kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - entry = KERNEL_LOAD_ADDR; + entry = loader_start + KERNEL_LOAD_ADDR; is_linux = 1; } if (kernel_size < 0) { @@ -134,11 +136,10 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, } bootloader[1] |= board_id & 0xff; bootloader[2] |= (board_id >> 8) & 0xff; - bootloader[5] = KERNEL_ARGS_ADDR; + bootloader[5] = loader_start + KERNEL_ARGS_ADDR; bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) stl_raw(phys_ram_base + (n * 4), bootloader[n]); - set_kernel_args(ram_size, initrd_size, kernel_cmdline); + set_kernel_args(ram_size, initrd_size, kernel_cmdline, loader_start); } } - diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 34c3b8112..c9e1715f3 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -508,7 +508,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, pl110_init(ds, 0xc0000000, pic[22], 0); arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, 0x113); + initrd_filename, 0x113, 0x0); } QEMUMachine integratorcp_machine = { diff --git a/hw/realview.c b/hw/realview.c index c15c23152..4f4858990 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -131,7 +131,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, /* 0x6c000000 PCI mem 2. */ arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, 0x33b); + initrd_filename, 0x33b, 0x0); } QEMUMachine realview_machine = { diff --git a/hw/spitz.c b/hw/spitz.c index 84cd30507..3b17dfe7e 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1035,7 +1035,7 @@ static void spitz_common_init(int ram_size, int vga_ram_size, cpu->env->regs[15] = PXA2XX_RAM_BASE; arm_load_kernel(cpu->env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, arm_id); + initrd_filename, arm_id, PXA2XX_RAM_BASE); sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_RAM_BASE); } diff --git a/hw/versatilepb.c b/hw/versatilepb.c index c0908161a..5b1774a64 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -260,7 +260,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, /* 0x101f4000 SSPI. */ arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, board_id); + initrd_filename, board_id, 0x0); } static void vpb_init(int ram_size, int vga_ram_size, int boot_device, diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7cb08ebaf..09083b723 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -144,12 +144,13 @@ typedef struct CPUARMState { CPU_COMMON - /* These fields after the common ones so thes are preserved on reset. */ + /* These fields after the common ones so they are preserved on reset. */ int ram_size; const char *kernel_filename; const char *kernel_cmdline; const char *initrd_filename; int board_id; + target_phys_addr_t loader_start; } CPUARMState; CPUARMState *cpu_arm_init(void); diff --git a/vl.h b/vl.h index f904ff269..49f5efff3 100644 --- a/vl.h +++ b/vl.h @@ -1450,7 +1450,7 @@ qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq); void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, - int board_id); + int board_id, target_phys_addr_t loader_start); /* sh7750.c */ struct SH7750State; -- cgit v1.2.3 From 2a1d1880e53d25fbec0e5d3f29f86cf65ad06241 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 02:33:10 +0000 Subject: Add missing gpio_handler_t definition. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2758 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vl.h b/vl.h index 49f5efff3..bc3e6cfeb 100644 --- a/vl.h +++ b/vl.h @@ -1506,6 +1506,9 @@ uint8_t nand_getio(struct nand_flash_s *s); #include "ecc.h" +/* GPIO */ +typedef void (*gpio_handler_t)(int line, int level, void *opaque); + /* ads7846.c */ struct ads7846_state_s; uint32_t ads7846_read(void *opaque); -- cgit v1.2.3 From 9e61ec315374120c92cc7a20e1e078b89b217e69 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 30 Apr 2007 02:39:55 +0000 Subject: PL050 status register fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2759 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl050.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/hw/pl050.c b/hw/pl050.c index eed729461..40274e1d8 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -1,7 +1,7 @@ /* * Arm PrimeCell PL050 Keyboard / Mouse Interface * - * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2006-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL. @@ -20,6 +20,14 @@ typedef struct { int is_mouse; } pl050_state; +#define PL050_TXEMPTY (1 << 6) +#define PL050_TXBUSY (1 << 5) +#define PL050_RXFULL (1 << 4) +#define PL050_RXBUSY (1 << 3) +#define PL050_RXPARITY (1 << 2) +#define PL050_KMIC (1 << 1) +#define PL050_KMID (1 << 0) + static const unsigned char pl050_id[] = { 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; @@ -45,11 +53,22 @@ static uint32_t pl050_read(void *opaque, target_phys_addr_t offset) case 0: /* KMICR */ return s->cr; case 1: /* KMISTAT */ - /* KMIC and KMID bits not implemented. */ - if (s->pending) { - return 0x10; - } else { - return 0; + { + uint8_t val; + uint32_t stat; + + val = s->last; + val = val ^ (val >> 4); + val = val ^ (val >> 2); + val = (val ^ (val >> 1)) & 1; + + stat = PL050_TXEMPTY; + if (val) + stat |= PL050_RXPARITY; + if (s->pending) + stat |= PL050_RXFULL; + + return stat; } case 2: /* KMIDATA */ if (s->pending) -- cgit v1.2.3 From 21bd785e84742aa8370d0084ca1bc84aa4752b8a Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Apr 2007 18:43:50 +0000 Subject: Remove the use of Linux / BSD specific asprintf call. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2760 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index d49e851d3..ad5f2672d 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1518,14 +1518,13 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) { struct pxa2xx_state_s *s; struct pxa2xx_ssp_s *ssp; - char *cpu_model; + char cpu_model[16]; int iomemtype, i; s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s)); s->env = cpu_init(); - asprintf(&cpu_model, "pxa270-%s", revision); + snprintf(cpu_model, sizeof(cpu_model), "pxa270-%s", revision); cpu_arm_set_model(s->env, cpu_model); - free(cpu_model); s->pic = pxa2xx_pic_init(0x40d00000, s->env); -- cgit v1.2.3 From 4207117c93357347500235952ce7891688089cb1 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 1 May 2007 01:03:32 +0000 Subject: Honour limited subset of --cpu values instead of ignoring. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2761 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx.c | 9 ++++++--- hw/spitz.c | 14 ++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index ad5f2672d..2f5dc9606 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1518,13 +1518,16 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) { struct pxa2xx_state_s *s; struct pxa2xx_ssp_s *ssp; - char cpu_model[16]; int iomemtype, i; s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s)); + if (revision && strncmp(revision, "pxa27", 5)) { + fprintf(stderr, "Machine requires a PXA27x processor.\n"); + exit(1); + } + s->env = cpu_init(); - snprintf(cpu_model, sizeof(cpu_model), "pxa270-%s", revision); - cpu_arm_set_model(s->env, cpu_model); + cpu_arm_set_model(s->env, revision ?: "pxa270"); s->pic = pxa2xx_pic_init(0x40d00000, s->env); diff --git a/hw/spitz.c b/hw/spitz.c index 3b17dfe7e..4b0f18e77 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -992,14 +992,16 @@ enum spitz_model_e { spitz, akita, borzoi, terrier }; static void spitz_common_init(int ram_size, int vga_ram_size, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, - enum spitz_model_e model, int arm_id) + const char *cpu_model, enum spitz_model_e model, int arm_id) { uint32_t spitz_ram = 0x04000000; uint32_t spitz_rom = 0x00800000; struct pxa2xx_state_s *cpu; struct scoop_info_s *scp; - cpu = pxa270_init(ds, (model == terrier) ? "c5" : "c0"); + if (!cpu_model) + cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; + cpu = pxa270_init(ds, cpu_model); /* Setup memory */ if (ram_size < spitz_ram + spitz_rom) { @@ -1045,7 +1047,7 @@ static void spitz_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename, const char *cpu_model) { spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename, - kernel_cmdline, initrd_filename, spitz, 0x2c9); + kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9); } static void borzoi_init(int ram_size, int vga_ram_size, int boot_device, @@ -1054,7 +1056,7 @@ static void borzoi_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename, const char *cpu_model) { spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename, - kernel_cmdline, initrd_filename, borzoi, 0x33f); + kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f); } static void akita_init(int ram_size, int vga_ram_size, int boot_device, @@ -1063,7 +1065,7 @@ static void akita_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename, const char *cpu_model) { spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename, - kernel_cmdline, initrd_filename, akita, 0x2e8); + kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8); } static void terrier_init(int ram_size, int vga_ram_size, int boot_device, @@ -1072,7 +1074,7 @@ static void terrier_init(int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename, const char *cpu_model) { spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename, - kernel_cmdline, initrd_filename, terrier, 0x33f); + kernel_cmdline, initrd_filename, cpu_model, terrier, 0x33f); } QEMUMachine akitapda_machine = { -- cgit v1.2.3 From a90b7318ba55b1aed71e299ec965bbd8f393b9b3 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 1 May 2007 01:28:01 +0000 Subject: Implement power state changes (IDLE and SLEEP) for PXA. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2762 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 3 ++- cpu-exec.c | 23 ++++++++++++++--------- hw/pxa2xx.c | 3 ++- target-arm/translate.c | 11 ++++++++--- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index db1e947fe..0aa384354 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -772,7 +772,8 @@ void cpu_dump_statistics (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags); -void cpu_abort(CPUState *env, const char *fmt, ...); +void cpu_abort(CPUState *env, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); extern CPUState *first_cpu; extern CPUState *cpu_single_env; extern int code_copy_enabled; diff --git a/cpu-exec.c b/cpu-exec.c index 284cb92ae..4777babd2 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -279,9 +279,10 @@ int cpu_exec(CPUState *env1) #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)) { + set. We use EXITTB to silently wake CPU without causing an + actual interrupt. */ + if (env1->interrupt_request & + (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) { env1->halted = 0; } else { return EXCP_HALTED; @@ -432,6 +433,15 @@ int cpu_exec(CPUState *env1) env->exception_index = EXCP_DEBUG; cpu_loop_exit(); } +#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ + defined(TARGET_PPC) || defined(TARGET_ALPHA) + if (interrupt_request & CPU_INTERRUPT_HALT) { + env->interrupt_request &= ~CPU_INTERRUPT_HALT; + env->halted = 1; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); + } +#endif #if defined(TARGET_I386) if ((interrupt_request & CPU_INTERRUPT_SMI) && !(env->hflags & HF_SMM_MASK)) { @@ -514,12 +524,7 @@ int cpu_exec(CPUState *env1) } 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)) { diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 2f5dc9606..43d40c7fd 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -247,7 +247,8 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, goto message; case 3: - cpu_reset(s->env); + s->env->uncached_cpsr = + ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; s->env->cp15.c1_sys = 0; s->env->cp15.c1_coproc = 0; s->env->cp15.c2 = 0; diff --git a/target-arm/translate.c b/target-arm/translate.c index 3d3dc3fd2..364f4eadb 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1584,7 +1584,7 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) /* Disassemble system coprocessor (cp15) instruction. Return nonzero if instruction is not defined. */ -static int disas_cp15_insn(DisasContext *s, uint32_t insn) +static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) { uint32_t rd; @@ -1610,8 +1610,13 @@ static int disas_cp15_insn(DisasContext *s, uint32_t insn) } else { gen_movl_T0_reg(s, rd); gen_op_movl_cp15_T0(insn); + /* Normally we would always end the TB here, but Linux + * arch/arm/mach-pxa/sleep.S expects two instructions following + * an MMU enable to execute from cache. Imitate this behaviour. */ + if (!arm_feature(env, ARM_FEATURE_XSCALE) || + (insn & 0x0fff0fff) != 0x0e010f10) + gen_lookup_tb(s); } - gen_lookup_tb(s); return 0; } @@ -2927,7 +2932,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; break; case 15: - if (disas_cp15_insn (s, insn)) + if (disas_cp15_insn (env, s, insn)) goto illegal_op; break; default: -- cgit v1.2.3 From 9467cd4602adfdacb457478d6aa074ea02652645 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 1 May 2007 01:34:14 +0000 Subject: -show-cursor switch to inhibit SDL hiding cursor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2763 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 6 ++++++ vl.c | 6 ++++++ vl.h | 1 + 3 files changed, 13 insertions(+) diff --git a/sdl.c b/sdl.c index a8dbc2c73..6c30db146 100644 --- a/sdl.c +++ b/sdl.c @@ -236,6 +236,9 @@ static void sdl_update_caption(void) static void sdl_hide_cursor(void) { + if (!cursor_hide) + return; + if (kbd_mouse_is_absolute()) { SDL_ShowCursor(1); SDL_SetCursor(sdl_cursor_hidden); @@ -246,6 +249,9 @@ static void sdl_hide_cursor(void) static void sdl_show_cursor(void) { + if (!cursor_hide) + return; + if (!kbd_mouse_is_absolute()) { SDL_ShowCursor(1); if (guest_cursor && diff --git a/vl.c b/vl.c index 6a06b8635..bf8df5dc9 100644 --- a/vl.c +++ b/vl.c @@ -189,6 +189,7 @@ const char *vnc_display; int acpi_enabled = 1; int fd_bootchk = 1; int no_reboot = 0; +int cursor_hide = 1; int graphic_rotate = 0; int daemonize = 0; const char *option_rom[MAX_OPTION_ROMS]; @@ -6618,6 +6619,7 @@ enum { QEMU_OPTION_vnc, QEMU_OPTION_no_acpi, QEMU_OPTION_no_reboot, + QEMU_OPTION_show_cursor, QEMU_OPTION_daemonize, QEMU_OPTION_option_rom, QEMU_OPTION_semihosting, @@ -6712,6 +6714,7 @@ const QEMUOption qemu_options[] = { { "vmwarevga", 0, QEMU_OPTION_vmsvga }, { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "no-reboot", 0, QEMU_OPTION_no_reboot }, + { "show-cursor", 0, QEMU_OPTION_show_cursor }, { "daemonize", 0, QEMU_OPTION_daemonize }, { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, #if defined(TARGET_ARM) @@ -7455,6 +7458,9 @@ int main(int argc, char **argv) case QEMU_OPTION_no_reboot: no_reboot = 1; break; + case QEMU_OPTION_show_cursor: + cursor_hide = 0; + break; case QEMU_OPTION_daemonize: daemonize = 1; break; diff --git a/vl.h b/vl.h index bc3e6cfeb..26e72bd7c 100644 --- a/vl.h +++ b/vl.h @@ -158,6 +158,7 @@ extern int kqemu_allowed; extern int win2k_install_hack; extern int usb_enabled; extern int smp_cpus; +extern int cursor_hide; extern int graphic_rotate; extern int no_quit; extern int semihosting_enabled; -- cgit v1.2.3 From 66508601adbc5faac5f25d944f073921e82d79d4 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 1 May 2007 14:16:52 +0000 Subject: Set OpenBIOS variables in NVRAM git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2764 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- hw/sun4u.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-doc.texi | 9 +++++++++ vl.c | 21 ++++++++++++++++++++ vl.h | 6 ++++++ 5 files changed, 144 insertions(+), 5 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index c24e52aad..ae9222af1 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -117,6 +117,34 @@ static void nvram_set_string (m48t59_t *nvram, uint32_t addr, m48t59_write(nvram, addr + max - 1, '\0'); } +static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr, + const unsigned char *str) +{ + uint32_t len; + + len = strlen(str) + 1; + nvram_set_string(nvram, addr, str, len); + + return addr + len; +} + +static void nvram_finish_partition (m48t59_t *nvram, uint32_t start, + uint32_t end) +{ + unsigned int i, sum; + + // Length divided by 16 + m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff); + m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff); + // Checksum + sum = m48t59_read(nvram, start); + for (i = 0; i < 14; i++) { + sum += m48t59_read(nvram, start + 2 + i); + sum = (sum + ((sum & 0xff00) >> 8)) & 0xff; + } + m48t59_write(nvram, start + 1, sum & 0xff); +} + static m48t59_t *nvram; extern int nographic; @@ -128,7 +156,8 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, int machine_id) { unsigned char tmp = 0; - int i, j; + unsigned int i, j; + uint32_t start, end; // Try to match PPC NVRAM nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); @@ -151,8 +180,30 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, nvram_set_word(nvram, 0x56, height); nvram_set_word(nvram, 0x58, depth); + // OpenBIOS nvram variables + // Variable partition + start = 252; + m48t59_write(nvram, start, 0x70); + nvram_set_string(nvram, start + 4, "system", 12); + + end = start + 16; + for (i = 0; i < nb_prom_envs; i++) + end = nvram_set_var(nvram, end, prom_envs[i]); + + m48t59_write(nvram, end++ , 0); + end = start + ((end - start + 15) & ~15); + nvram_finish_partition(nvram, start, end); + + // free partition + start = end; + m48t59_write(nvram, start, 0x7f); + nvram_set_string(nvram, start + 4, "free", 12); + + end = 0x1fd0; + nvram_finish_partition(nvram, start, end); + // Sun4m specific use - i = 0x1fd8; + start = i = 0x1fd8; m48t59_write(nvram, i++, 0x01); m48t59_write(nvram, i++, machine_id); j = 0; @@ -164,10 +215,10 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, m48t59_write(nvram, i, macaddr[j]); /* Calculate checksum */ - for (i = 0x1fd8; i < 0x1fe7; i++) { - tmp ^= m48t59_read(nvram, i); + for (i = start; i < start + 15; i++) { + tmp ^= m48t59_read(nvram, i); } - m48t59_write(nvram, 0x1fe7, tmp); + m48t59_write(nvram, start + 15, tmp); } static void *slavio_intctl; diff --git a/hw/sun4u.c b/hw/sun4u.c index b10722f6e..952beff3c 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -170,6 +170,34 @@ uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) return crc; } +static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr, + const unsigned char *str) +{ + uint32_t len; + + len = strlen(str) + 1; + NVRAM_set_string(nvram, addr, str, len); + + return addr + len; +} + +static void nvram_finish_partition (m48t59_t *nvram, uint32_t start, + uint32_t end) +{ + unsigned int i, sum; + + // Length divided by 16 + m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff); + m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff); + // Checksum + sum = m48t59_read(nvram, start); + for (i = 0; i < 14; i++) { + sum += m48t59_read(nvram, start + 2 + i); + sum = (sum + ((sum & 0xff00) >> 8)) & 0xff; + } + m48t59_write(nvram, start + 1, sum & 0xff); +} + extern int nographic; int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, @@ -182,6 +210,8 @@ int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, int width, int height, int depth) { uint16_t crc; + unsigned int i; + uint32_t start, end; /* Set parameters for Open Hack'Ware BIOS */ NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); @@ -212,6 +242,28 @@ int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); NVRAM_set_word(nvram, 0xFC, crc); + // OpenBIOS nvram variables + // Variable partition + start = 252; + m48t59_write(nvram, start, 0x70); + NVRAM_set_string(nvram, start + 4, "system", 12); + + end = start + 16; + for (i = 0; i < nb_prom_envs; i++) + end = nvram_set_var(nvram, end, prom_envs[i]); + + m48t59_write(nvram, end++ , 0); + end = start + ((end - start + 15) & ~15); + nvram_finish_partition(nvram, start, end); + + // free partition + start = end; + m48t59_write(nvram, start, 0x7f); + NVRAM_set_string(nvram, start + 4, "free", 12); + + end = 0x1fd0; + nvram_finish_partition(nvram, start, end); + return 0; } diff --git a/qemu-doc.texi b/qemu-doc.texi index 830a2b6f4..43d34defe 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1661,6 +1661,15 @@ The following options are specific to the Sparc emulation: Set the initial TCX graphic mode. The default is 1024x768. +@item -prom-env string + +Set OpenBIOS variables in NVRAM, for example: + +@example +qemu-system-sparc -prom-env 'auto-boot?=false' \ + -prom-env 'boot-device=sd(0,2,0):d' -prom-env 'boot-args=linux single' +@end example + @end table @c man end diff --git a/vl.c b/vl.c index bf8df5dc9..f4be19468 100644 --- a/vl.c +++ b/vl.c @@ -197,6 +197,10 @@ int nb_option_roms; int semihosting_enabled = 0; int autostart = 1; const char *qemu_name; +#ifdef TARGET_SPARC +unsigned int nb_prom_envs = 0; +const char *prom_envs[MAX_PROM_ENVS]; +#endif /***********************************************************/ /* x86 ISA bus support */ @@ -6530,6 +6534,9 @@ void help(void) "-daemonize daemonize QEMU after initializing\n" #endif "-option-rom rom load a file, rom, into the option ROM space\n" +#ifdef TARGET_SPARC + "-prom-env variable=value set OpenBIOS nvram variables\n" +#endif "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -6624,6 +6631,7 @@ enum { QEMU_OPTION_option_rom, QEMU_OPTION_semihosting, QEMU_OPTION_name, + QEMU_OPTION_prom_env, }; typedef struct QEMUOption { @@ -6721,6 +6729,9 @@ const QEMUOption qemu_options[] = { { "semihosting", 0, QEMU_OPTION_semihosting }, #endif { "name", HAS_ARG, QEMU_OPTION_name }, +#if defined(TARGET_SPARC) + { "prom-env", HAS_ARG, QEMU_OPTION_prom_env }, +#endif { NULL }, }; @@ -7478,6 +7489,16 @@ int main(int argc, char **argv) case QEMU_OPTION_name: qemu_name = optarg; break; +#ifdef TARGET_SPARC + case QEMU_OPTION_prom_env: + if (nb_prom_envs >= MAX_PROM_ENVS) { + fprintf(stderr, "Too many prom variables\n"); + exit(1); + } + prom_envs[nb_prom_envs] = optarg; + nb_prom_envs++; + break; +#endif } } } diff --git a/vl.h b/vl.h index 26e72bd7c..f44eeab5f 100644 --- a/vl.h +++ b/vl.h @@ -169,6 +169,12 @@ extern const char *bootp_filename; extern const char *option_rom[MAX_OPTION_ROMS]; extern int nb_option_roms; +#ifdef TARGET_SPARC +#define MAX_PROM_ENVS 128 +extern const char *prom_envs[MAX_PROM_ENVS]; +extern unsigned int nb_prom_envs; +#endif + /* XXX: make it dynamic */ #define MAX_BIOS_SIZE (4 * 1024 * 1024) #if defined (TARGET_PPC) || defined (TARGET_SPARC64) -- cgit v1.2.3 From 549444e1f03d56674f43dfe67a5950638bc3d200 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 1 May 2007 17:53:37 +0000 Subject: Correct a docs typo and list of available NIC names (by Stefan Weil). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2765 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 43d34defe..b1afb95f6 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -357,10 +357,12 @@ Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n} = 0 is the default). The NIC is currently an NE2000 on the PC target. Optionally, the MAC address can be changed. If no @option{-net} option is specified, a single NIC is created. -Qemu can emulate several different models of network card. Valid values for -@var{type} are @code{ne2k_pci}, @code{ne2k_isa}, @code{rtl8139}, -@code{smc91c111} and @code{lance}. Not all devices are supported on all -targets. +Qemu can emulate several different models of network card. +Valid values for @var{type} are +@code{i82551}, @code{i82557b}, @code{i82559er}, +@code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139}, +@code{smc91c111} and @code{lance}. +Not all devices are supported on all targets. @item -net user[,vlan=n][,hostname=name] Use the user mode network stack which requires no administrator @@ -1810,7 +1812,7 @@ Maxim MAX1111 analog-digital converter on I@math{^2}C bus @item GPIO-connected keyboard controller and LEDs @item -Secure Digital card conntected to PXA MMC/SD host +Secure Digital card connected to PXA MMC/SD host @item Three on-chip UARTs @item -- cgit v1.2.3 From 5a1237c45f8ae84da2cbffe07a344e29952c689b Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 2 May 2007 02:11:51 +0000 Subject: Don't define HIGH_LATENCY for ARM, this was a workaround for an ALSA problem. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2766 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- audio/alsaaudio.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.target b/Makefile.target index a576796df..6a5ff9002 100644 --- a/Makefile.target +++ b/Makefile.target @@ -456,7 +456,7 @@ VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) -CPPFLAGS += -DHAS_AUDIO -DHIGH_LATENCY +CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 2e59dfa4c..3f9ffdbbc 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -57,6 +57,8 @@ static struct { int period_size_out_overriden; int verbose; } conf = { +#define DEFAULT_BUFFER_SIZE 1024 +#define DEFAULT_PERIOD_SIZE 256 #ifdef HIGH_LATENCY .size_in_usec_in = 1, .size_in_usec_out = 1, @@ -69,8 +71,6 @@ static struct { .buffer_size_out = 400000, .period_size_out = 400000 / 4, #else -#define DEFAULT_BUFFER_SIZE 1024 -#define DEFAULT_PERIOD_SIZE 256 .buffer_size_in = DEFAULT_BUFFER_SIZE * 4, .period_size_in = DEFAULT_PERIOD_SIZE * 4, .buffer_size_out = DEFAULT_BUFFER_SIZE, -- cgit v1.2.3 From 14a1120e5c8c4c29441141b4657f91e04d10fac0 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 2 May 2007 16:37:44 +0000 Subject: Handle division by zero case in Sparc64 udivx and sdivx ops git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2767 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-sparc/op.c b/target-sparc/op.c index 7a4bd7957..5fbbd6db0 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -926,12 +926,18 @@ void OPPROTO op_mulx_T1_T0(void) void OPPROTO op_udivx_T1_T0(void) { + if (T1 == 0) { + raise_exception(TT_DIV_ZERO); + } T0 /= T1; FORCE_RET(); } void OPPROTO op_sdivx_T1_T0(void) { + if (T1 == 0) { + raise_exception(TT_DIV_ZERO); + } if (T0 == INT64_MIN && T1 == -1) T0 = INT64_MIN; else -- cgit v1.2.3 From 1f72aae5f33866a088e4c7d0063d40ef88a71b70 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 3 May 2007 10:09:56 +0000 Subject: Change the PCI IO region start to that hardcoded in VBE bios (reported by Jeremy Katz) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2768 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vmware_vga.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 1a4f4cd9d..dda45dfef 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -114,14 +114,14 @@ struct pci_vmsvga_state_s { # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT # define SVGA_IO_MUL 1 # define SVGA_FIFO_SIZE 0x10000 -# define SVGA_MEM_BASE 0xec000000 +# define SVGA_MEM_BASE 0xe0000000 # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2 #else # define SVGA_ID SVGA_ID_1 # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT # define SVGA_IO_MUL 4 # define SVGA_FIFO_SIZE 0x10000 -# define SVGA_MEM_BASE 0xec000000 +# define SVGA_MEM_BASE 0xe0000000 # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA #endif -- cgit v1.2.3 From f7cf7945ab309508bbf4dfbcf5e47edc7212f928 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 3 May 2007 10:13:54 +0000 Subject: Remove obsolete variables that came with VMware svga by mistake. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2769 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vl.c b/vl.c index f4be19468..2a864ba87 100644 --- a/vl.c +++ b/vl.c @@ -564,10 +564,6 @@ int kbd_mouse_is_absolute(void) return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute; } -void (*kbd_mouse_set)(int x, int y, int on) = NULL; -void (*kbd_cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, - uint8_t *image, uint8_t *mask) = NULL; - void do_info_mice(void) { QEMUPutMouseEntry *cursor; -- cgit v1.2.3 From 26ea091859c76d5e1b8a95148aa60b59dc8ee196 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 4 May 2007 14:34:34 +0000 Subject: Support for simple YAMON output, by Alec Voropay. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2770 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 42627e82a..82ba80952 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -535,11 +535,27 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t /* Small bootloader */ p = (uint32_t *) (phys_ram_base + bios_offset); - stl_raw(p++, 0x0bf00006); /* j 0x1fc00018 */ + stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */ stl_raw(p++, 0x00000000); /* nop */ + /* YAMON service vector */ + stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */ + stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c); /* print_count: */ + stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */ + stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800); /* flush_cache: */ + stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808); /* print: */ + stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800); /* reg_cpu_isr: */ + stl_raw(phys_ram_base + bios_offset + 0x53c, 0xbfc00800); /* unred_cpu_isr: */ + stl_raw(phys_ram_base + bios_offset + 0x540, 0xbfc00800); /* reg_ic_isr: */ + stl_raw(phys_ram_base + bios_offset + 0x544, 0xbfc00800); /* unred_ic_isr: */ + stl_raw(phys_ram_base + bios_offset + 0x548, 0xbfc00800); /* reg_esr: */ + stl_raw(phys_ram_base + bios_offset + 0x54c, 0xbfc00800); /* unreg_esr: */ + stl_raw(phys_ram_base + bios_offset + 0x550, 0xbfc00800); /* getchar: */ + stl_raw(phys_ram_base + bios_offset + 0x554, 0xbfc00800); /* syscon_read: */ + + /* Second part of the bootloader */ - p = (uint32_t *) (phys_ram_base + bios_offset + 0x018); + p = (uint32_t *) (phys_ram_base + bios_offset + 0x580); stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */ stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */ stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, a0, low(ENVP_ADDR) */ @@ -597,6 +613,50 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */ stl_raw(p++, 0x03e00008); /* jr ra */ stl_raw(p++, 0x00000000); /* nop */ + + /* YAMON subroutines */ + p = (uint32_t *) (phys_ram_base + bios_offset + 0x800); + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0x24020000); /* li v0,0 */ + /* 808 YAMON print */ + stl_raw(p++, 0x03e06821); /* move t5,ra */ + stl_raw(p++, 0x00805821); /* move t3,a0 */ + stl_raw(p++, 0x00a05021); /* move t2,a1 */ + stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ + stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ + stl_raw(p++, 0x10800005); /* beqz a0,834 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x0ff0021c); /* jal 870 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x08000205); /* j 814 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x01a00008); /* jr t5 */ + stl_raw(p++, 0x01602021); /* move a0,t3 */ + /* 0x83c YAMON print_count */ + stl_raw(p++, 0x03e06821); /* move t5,ra */ + stl_raw(p++, 0x00805821); /* move t3,a0 */ + stl_raw(p++, 0x00a05021); /* move t2,a1 */ + stl_raw(p++, 0x00c06021); /* move t4,a2 */ + stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */ + stl_raw(p++, 0x0ff0021c); /* jal 870 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */ + stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */ + stl_raw(p++, 0x1580fffa); /* bnez t4,84c */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x01a00008); /* jr t5 */ + stl_raw(p++, 0x01602021); /* move a0,t3 */ + /* 0x870 */ + stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */ + stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */ + stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */ + stl_raw(p++, 0x1120fffc); /* beqz t1,878 */ + stl_raw(p++, 0x00000000); /* nop */ + stl_raw(p++, 0x03e00008); /* jr ra */ + stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */ + } static void prom_set(int index, const char *string, ...) -- cgit v1.2.3 From c4b89d18ba3b494545266970fe8714bc3d7f5917 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 5 May 2007 19:23:11 +0000 Subject: Some bits of Linux/MIPS host support, still segfaulty. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2771 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 ++ cpu-all.h | 23 ++++++++++++++- cpu-exec.c | 18 +++++++++-- dyngen-exec.h | 11 ++++++- dyngen.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dyngen.h | 8 +++++ exec-all.h | 22 ++++++++++++++ 7 files changed, 172 insertions(+), 4 deletions(-) diff --git a/Makefile.target b/Makefile.target index 6a5ff9002..9bb12c2f5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -181,6 +181,7 @@ BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),mips) +OP_CFLAGS+=-G 0 -fomit-frame-pointer -fno-delayed-branch ifeq ($(WORDS_BIGENDIAN),yes) BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld else @@ -189,6 +190,7 @@ endif endif ifeq ($(ARCH),mips64) +OP_CFLAGS+=-G 0 -fomit-frame-pointer -fno-delayed-branch ifeq ($(WORDS_BIGENDIAN),yes) BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld else diff --git a/cpu-all.h b/cpu-all.h index 0aa384354..920a0f7e9 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -20,7 +20,7 @@ #ifndef CPU_ALL_H #define CPU_ALL_H -#if defined(__arm__) || defined(__sparc__) +#if defined(__arm__) || defined(__sparc__) || defined(__mips__) #define WORDS_ALIGNED #endif @@ -1022,6 +1022,27 @@ static inline int64_t cpu_get_real_ticks (void) return rval.i64; #endif } + +#elif defined(__mips__) + +static inline int64_t cpu_get_real_ticks(void) +{ +#if __mips_isa_rev >= 2 + uint32_t count; + static uint32_t cyc_per_count = 0; + + if (!cyc_per_count) + __asm__ __volatile__("rdhwr %0, $3" : "=r" (cyc_per_count)); + + __asm__ __volatile__("rdhwr %1, $2" : "=r" (count)); + return (int64_t)(count * cyc_per_count); +#else + /* FIXME */ + static int64_t ticks = 0; + return ticks++; +#endif +} + #else /* The host CPU doesn't have an easily accessible cycle counter. Just return a monotonically increasing vlue. This will be totally wrong, diff --git a/cpu-exec.c b/cpu-exec.c index 4777babd2..cd74412a7 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1540,8 +1540,22 @@ int cpu_signal_handler(int host_signum, void *pinfo, /* XXX: compute is_write */ is_write = 0; return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, - &uc->uc_sigmask, puc); + is_write, &uc->uc_sigmask, puc); +} + +#elif defined(__mips__) + +int cpu_signal_handler(int host_signum, struct siginfo *info, + void *puc) +{ + struct ucontext *uc = puc; + greg_t pc = uc->uc_mcontext.pc; + int is_write; + + /* XXX: compute is_write */ + is_write = 0; + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + is_write, &uc->uc_sigmask, puc); } #else diff --git a/dyngen-exec.h b/dyngen-exec.h index 69c3cd99c..8ceb2301d 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -129,10 +129,15 @@ extern int printf(const char *, ...); #define AREG3 "r6" #endif #ifdef __mips__ -#define AREG0 "s3" +#define AREG0 "fp" #define AREG1 "s0" #define AREG2 "s1" #define AREG3 "s2" +#define AREG4 "s3" +#define AREG5 "s4" +#define AREG6 "s5" +#define AREG7 "s6" +#define AREG8 "s7" #endif #ifdef __sparc__ #ifdef HOST_SOLARIS @@ -280,5 +285,9 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __mc68000 #define EXIT_TB() asm volatile ("rts") #endif +#ifdef __mips__ +#define EXIT_TB() asm volatile ("jr $ra") +#define GOTO_LABEL_PARAM(n) asm volatile (".set noat; la $1, " ASM_NAME(__op_gen_label) #n "; jr $1; .set at") +#endif #endif /* !defined(__DYNGEN_EXEC_H__) */ diff --git a/dyngen.c b/dyngen.c index 953b36c11..dd46ea0ca 100644 --- a/dyngen.c +++ b/dyngen.c @@ -117,6 +117,13 @@ #define elf_check_arch(x) ((x) == EM_68K) #define ELF_USES_RELOCA +#elif defined(HOST_MIPS) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_MIPS +#define elf_check_arch(x) ((x) == EM_MIPS) +#define ELF_USES_RELOC + #else #error unsupported CPU - please update the code #endif @@ -1641,6 +1648,26 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, error("rts expected at the end of %s", name); copy_size = p - p_start; } +#elif defined(HOST_MIPS) + { +#define INSN_RETURN 0x03e00008 +#define INSN_NOP 0x00000000 + + uint8_t *p = p_end; + + if (p < (p_start + 0x8)) { + error("empty code for %s", name); + } else { + uint32_t end_insn1, end_insn2; + + p -= 0x8; + end_insn1 = get32((uint32_t *)(p + 0x0)); + end_insn2 = get32((uint32_t *)(p + 0x4)); + if (end_insn1 != INSN_RETURN && end_insn2 != INSN_NOP) + error("jr ra not found at end of %s", name); + } + copy_size = p - p_start; + } #else #error unsupported CPU #endif @@ -2483,6 +2510,71 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#elif defined(HOST_MIPS) + { + for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { + char name[256]; + int type; + int addend; + int reloc_offset; + + sym_name = strtab + symtab[ELF32_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_MIPS_HI16: + fprintf(outfile, " /* R_MIPS_HI16 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "((*(uint32_t *)(gen_code_ptr + 0x%x)) " + " & ~0xffff) " + " | (((%s - 0x8000) >> 16) & 0xffff);\n", + reloc_offset, reloc_offset, name); + break; + case R_MIPS_LO16: + fprintf(outfile, " /* R_MIPS_LO16 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "((*(uint32_t *)(gen_code_ptr + 0x%x)) " + " & ~0xffff) " + " | (%s & 0xffff);\n", + reloc_offset, reloc_offset, name); + break; + case R_MIPS_PC16: + fprintf(outfile, " /* R_MIPS_PC16 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "(0x%x & ~0xffff) " + "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) " + " & 0xffff);\n", + reloc_offset, addend, addend, name, reloc_offset); + break; + case R_MIPS_GOT16: + case R_MIPS_CALL16: + fprintf(outfile, " /* R_MIPS_GOT16 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "((*(uint32_t *)(gen_code_ptr + 0x%x)) " + " & ~0xffff) " + " | (((%s - 0x8000) >> 16) & 0xffff);\n", + reloc_offset, reloc_offset, name); + break; + default: + error("unsupported MIPS relocation (%d)", type); + } + } + } + } #else #error unsupported CPU #endif diff --git a/dyngen.h b/dyngen.h index 2a87c448f..e8bf72bfd 100644 --- a/dyngen.h +++ b/dyngen.h @@ -463,3 +463,11 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp, } #endif + +#ifdef __mips__ +#include +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + _flush_cache ((void *)start, stop - start, BCACHE); +} +#endif diff --git a/exec-all.h b/exec-all.h index cb8936a69..bc118c8a4 100644 --- a/exec-all.h +++ b/exec-all.h @@ -481,6 +481,28 @@ static inline int testandset (int *p) } #endif +#ifdef __mips__ +static inline int testandset (int *p) +{ + int ret; + + __asm__ __volatile__ ( + " .set push \n" + " .set noat \n" + " .set mips2 \n" + "1: li $1, 1 \n" + " ll %0, %1 \n" + " sc $1, %1 \n" + " bnez $1, 1b \n" + " .set pop " + : "=r" (ret), "+R" (*p) + : + : "memory"); + + return ret; +} +#endif + typedef int spinlock_t; #define SPIN_LOCK_UNLOCKED 0 -- cgit v1.2.3 From 608e8ce280cee231b3de0e7922060efd23447a54 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 5 May 2007 19:24:38 +0000 Subject: Linker scripts for MIPS hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2772 c046a42c-6fe2-441c-8c8c-71466251a162 --- mips.ld | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mipsel.ld | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+) create mode 100644 mips.ld create mode 100644 mipsel.ld diff --git a/mips.ld b/mips.ld new file mode 100644 index 000000000..94fa63be4 --- /dev/null +++ b/mips.ld @@ -0,0 +1,225 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", + "elf32-tradlittlemips") +OUTPUT_ARCH(mips) +ENTRY(__start) +SEARCH_DIR("/usr/mips-linux-gnu/lib"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .reginfo : { *(.reginfo) } + .dynamic : { *(.dynamic) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x47ff041f + .plt : { *(.plt) } + .text : + { + _ftext = . ; + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.mips16.fn.*) *(.mips16.call.*) + } =0x47ff041f + .fini : + { + KEEP (*(.fini)) + } =0x47ff041f + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* 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 (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .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 : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + _fdata = . ; + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + . = .; + _gp = ALIGN(16) + 0x7ff0; + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/mipsel.ld b/mipsel.ld new file mode 100644 index 000000000..e37938c8d --- /dev/null +++ b/mipsel.ld @@ -0,0 +1,225 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips", + "elf32-tradlittlemips") +OUTPUT_ARCH(mips) +ENTRY(__start) +SEARCH_DIR("/usr/mips-linux-gnu/lib"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .reginfo : { *(.reginfo) } + .dynamic : { *(.dynamic) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rel.data.rel.ro : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) } + .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } + .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } + .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } + .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } + .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } + .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } + .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } + .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } + .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x47ff041f + .plt : { *(.plt) } + .text : + { + _ftext = . ; + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.mips16.fn.*) *(.mips16.call.*) + } =0x47ff041f + .fini : + { + KEEP (*(.fini)) + } =0x47ff041f + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* 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 (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .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 : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin*.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin*.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + _fdata = . ; + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + . = .; + _gp = ALIGN(16) + 0x7ff0; + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + /DISCARD/ : { *(.note.GNU-stack) } +} -- cgit v1.2.3 From 9aca99a06d68ba2a84ff8a0f9bd337402fd5ffe5 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 5 May 2007 20:13:13 +0000 Subject: Fix a really stupid bug in the [ls]d[lr] emulation, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2773 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper_mem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index 56eeaadd0..8663d9a52 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -126,10 +126,10 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) #ifdef TARGET_MIPS64 -# ifdef TARGET_WORDS_BIGENDIAN -#define GET_LMASK64(v) ((v) & 4) +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK64(v) ((v) & 7) #else -#define GET_LMASK64(v) (((v) & 4) ^ 4) +#define GET_LMASK64(v) (((v) & 7) ^ 7) #endif void glue(do_ldl, MEMSUFFIX) (uint64_t tmp) -- cgit v1.2.3 From 384ccb5d348656584de998fc0aee81d5efa3b11e Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 6 May 2007 17:33:14 +0000 Subject: Fix slavio_misc base git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2774 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index ae9222af1..89f4b418d 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -401,7 +401,7 @@ static const struct hwdef hwdefs[] = { .iommu_base = 0x10000000, .tcx_base = 0x50000000, .cs_base = 0x6c000000, - .slavio_base = 0x71000000, + .slavio_base = 0x70000000, .ms_kb_base = 0x71000000, .serial_base = 0x71100000, .nvram_base = 0x71200000, @@ -433,7 +433,7 @@ static const struct hwdef hwdefs[] = { .iommu_base = 0xe0000000, // XXX Actually at 0xfe0000000ULL (36 bits) .tcx_base = 0x20000000, // 0xe20000000ULL, .cs_base = -1, - .slavio_base = 0xf1000000, // 0xff1000000ULL, + .slavio_base = 0xf0000000, // 0xff0000000ULL, .ms_kb_base = 0xf1000000, // 0xff1000000ULL, .serial_base = 0xf1100000, // 0xff1100000ULL, .nvram_base = 0xf1200000, // 0xff1200000ULL, -- cgit v1.2.3 From 8508b89e366906ec4f1b15fdd2e9ce5fab2b1bd6 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 6 May 2007 17:39:55 +0000 Subject: Add dummy THC and TEC registers to TCX git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2775 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/tcx.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/hw/tcx.c b/hw/tcx.c index 73ea813a1..db27dcf49 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -26,6 +26,9 @@ #define MAXX 1024 #define MAXY 768 #define TCX_DAC_NREGS 16 +#define TCX_THC_NREGS_8 0x081c +#define TCX_THC_NREGS_24 0x1000 +#define TCX_TEC_NREGS 0x1000 typedef struct TCXState { uint32_t addr; @@ -467,12 +470,34 @@ static CPUWriteMemoryFunc *tcx_dac_write[3] = { tcx_dac_writel, }; +static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +} + +static CPUReadMemoryFunc *tcx_dummy_read[3] = { + tcx_dummy_readl, + tcx_dummy_readl, + tcx_dummy_readl, +}; + +static CPUWriteMemoryFunc *tcx_dummy_write[3] = { + tcx_dummy_writel, + tcx_dummy_writel, + tcx_dummy_writel, +}; + void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, unsigned long vram_offset, int vram_size, int width, int height, int depth) { TCXState *s; - int io_memory; + int io_memory, dummy_memory; int size; s = qemu_mallocz(sizeof(TCXState)); @@ -495,6 +520,10 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); cpu_register_physical_memory(addr + 0x00200000, TCX_DAC_NREGS, io_memory); + dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write, + s); + cpu_register_physical_memory(addr + 0x00700000, TCX_TEC_NREGS, + dummy_memory); if (depth == 24) { // 24-bit plane size = vram_size * 4; @@ -509,9 +538,13 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, s->cplane = (uint32_t *)vram_base; s->cplane_offset = vram_offset; cpu_register_physical_memory(addr + 0x0a000000, size, vram_offset); - graphic_console_init(s->ds, tcx24_update_display, tcx24_invalidate_display, - tcx24_screen_dump, s); + cpu_register_physical_memory(addr + 0x00301000, TCX_THC_NREGS_24, + dummy_memory); + graphic_console_init(s->ds, tcx24_update_display, + tcx24_invalidate_display, tcx24_screen_dump, s); } else { + cpu_register_physical_memory(addr + 0x00300000, TCX_THC_NREGS_8, + dummy_memory); graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, tcx_screen_dump, s); } -- cgit v1.2.3 From b4f0a316b5585b6aeca13bf9022e2ad3de8bafd3 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 6 May 2007 17:59:24 +0000 Subject: Report unassigned memory access to CPU (not enabled yet) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2776 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 8 ++++++++ target-sparc/cpu.h | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 084b84409..4261dc06b 100644 --- a/exec.c +++ b/exec.c @@ -1958,6 +1958,10 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) { #ifdef DEBUG_UNASSIGNED printf("Unassigned mem read 0x%08x\n", (int)addr); +#endif +#ifdef TARGET_SPARC + // Not enabled yet because of bugs in gdbstub etc. + //raise_exception(TT_DATA_ACCESS); #endif return 0; } @@ -1967,6 +1971,10 @@ static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_ #ifdef DEBUG_UNASSIGNED printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val); #endif +#ifdef TARGET_SPARC + // Not enabled yet because of bugs in gdbstub etc. + //raise_exception(TT_DATA_ACCESS); +#endif } static CPUReadMemoryFunc *unassigned_mem_read[3] = { diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index f3f872ff7..91ed11fd0 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -40,6 +40,7 @@ #define TT_DFAULT 0x09 #define TT_TOVF 0x0a #define TT_EXTINT 0x10 +#define TT_DATA_ACCESS 0x29 #define TT_DIV_ZERO 0x2a #define TT_NCP_INSN 0x24 #define TT_TRAP 0x80 @@ -55,7 +56,8 @@ #define TT_DIV_ZERO 0x28 #define TT_DFAULT 0x30 #define TT_DMISS 0x31 -#define TT_DPROT 0x32 +#define TT_DATA_ACCESS 0x32 +#define TT_DPROT 0x33 #define TT_UNALIGNED 0x34 #define TT_PRIV_ACT 0x37 #define TT_EXTINT 0x40 @@ -287,6 +289,7 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); #endif int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); +void raise_exception(int tt); #include "cpu-all.h" -- cgit v1.2.3 From 0a6de7500261839c9383b30207ba2ca5f7a402eb Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 7 May 2007 12:46:25 +0000 Subject: Clear BD slot on next exception if appropriate. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2777 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-mips/helper.c b/target-mips/helper.c index 71a972339..8d9435a23 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -302,6 +302,8 @@ void do_interrupt (CPUState *env) env->hflags |= MIPS_HFLAG_DM; env->hflags &= ~MIPS_HFLAG_UM; /* EJTAG probe trap enable is not implemented... */ + if (!(env->CP0_Status & (1 << CP0St_EXL))) + env->CP0_Cause &= ~(1 << CP0Ca_BD); env->PC = (int32_t)0xBFC00480; break; case EXCP_RESET: @@ -324,6 +326,8 @@ void do_interrupt (CPUState *env) } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->hflags &= ~MIPS_HFLAG_UM; + if (!(env->CP0_Status & (1 << CP0St_EXL))) + env->CP0_Cause &= ~(1 << CP0Ca_BD); env->PC = (int32_t)0xBFC00000; break; case EXCP_MCHECK: -- cgit v1.2.3 From 8b4af7052757965b9a03998f400955016b456431 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 7 May 2007 12:52:18 +0000 Subject: Update TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2778 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index defe49112..f91b5c6c6 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -7,10 +7,9 @@ General - Missing per-CPU instruction decoding, currently all implemented instructions are regarded as valid - Applications running on top of a emulated Linux segfault sometimes - when the Qemu FPU emulation is disabled. This is apparently a qemu - bug triggered by the Linux in-kernel FPU emulator. -- The Timesys Linux installer shell hangs for e.g. "read foo". Likewise, - telnet'ting in the installer fails and hangs the telnetd. + when the Qemu FPU emulation is disabled. Also gdb inside the emulated + system does not work. Both problems are caused by insufficient + handling of self-modifying code. MIPS64 ------ -- cgit v1.2.3 From 5a5012ecbdcd341bb1d2e8200db91f6212aa44df Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 7 May 2007 13:55:33 +0000 Subject: MIPS 64-bit FPU support, plus some collateral bugfixes in the conditional branch handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2779 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + gdbstub.c | 4 +- target-mips/TODO | 3 +- target-mips/cpu.h | 44 +- target-mips/exec.h | 6 + target-mips/fop_template.c | 123 +++-- target-mips/helper.c | 3 + target-mips/op.c | 920 ++++++++++++++++++++++++++++-------- target-mips/op_mem.c | 32 ++ target-mips/translate.c | 1067 ++++++++++++++++++++++++++++++++---------- target-mips/translate_init.c | 20 +- 11 files changed, 1703 insertions(+), 520 deletions(-) diff --git a/Changelog b/Changelog index 19a5da7fd..9aaac1877 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ - ds1225y nvram support (Herve Poussineau) - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) - Several Sparc fixes (Aurelien Jarno, Blue Swirl) + - MIPS 64-bit FPU support (Thiemo Seufer) version 0.9.0: diff --git a/gdbstub.c b/gdbstub.c index 79f54f51f..62c1db297 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -575,7 +575,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { for (i = 0; i < 32; i++) { - *(uint32_t *)ptr = tswapl(FPR_W (env, i)); + *(uint32_t *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]); ptr += 4; } @@ -637,7 +637,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { for (i = 0; i < 32; i++) { - FPR_W (env, i) = tswapl(*(uint32_t *)ptr); + env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(uint32_t *)ptr); ptr += 4; } diff --git a/target-mips/TODO b/target-mips/TODO index f91b5c6c6..a5842ff27 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -10,11 +10,12 @@ General when the Qemu FPU emulation is disabled. Also gdb inside the emulated system does not work. Both problems are caused by insufficient handling of self-modifying code. +- Floating point exception emulation is incomplete. MIPS64 ------ - No 64bit TLB support -- no 64bit wide registers for FPU +- 64bit FPU not fully implemented - 64bit mul/div handling broken "Generic" 4Kc system emulation diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 36b890efb..33cb6573e 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -21,7 +21,7 @@ typedef union fpr_t fpr_t; union fpr_t { float64 fd; /* ieee double precision */ float32 fs[2];/* ieee single precision */ - uint64_t d; /* binary single fixed-point */ + uint64_t d; /* binary double fixed-point */ uint32_t w[2]; /* binary single fixed-point */ }; /* define FP_ENDIAN_IDX to access the same location @@ -64,31 +64,35 @@ struct CPUMIPSState { target_ulong HI, LO; /* Floating point registers */ fpr_t fpr[32]; -#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2]) -#define FPR_FD(cpu, n) (FPR(cpu, n)->fd) -#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX]) -#define FPR_D(cpu, n) (FPR(cpu, n)->d) -#define FPR_W(cpu, n) (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX]) - #ifndef USE_HOST_FLOAT_REGS fpr_t ft0; fpr_t ft1; fpr_t ft2; #endif float_status fp_status; - /* fpu implementation/revision register */ + /* fpu implementation/revision register (fir) */ uint32_t fcr0; +#define FCR0_F64 22 +#define FCR0_L 21 +#define FCR0_W 20 +#define FCR0_3D 19 +#define FCR0_PS 18 +#define FCR0_D 17 +#define FCR0_S 16 +#define FCR0_PRID 8 +#define FCR0_REV 0 /* fcsr */ uint32_t fcr31; -#define SET_FP_COND(reg) do { (reg) |= (1<<23); } while(0) -#define CLEAR_FP_COND(reg) do { (reg) &= ~(1<<23); } while(0) -#define IS_FP_COND_SET(reg) (((reg) & (1<<23)) != 0) -#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) -#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) -#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) -#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 12); } while(0) -#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v) << 7); } while(0) -#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v) << 2); } while(0) +#define SET_FP_COND(num,env) do { (env->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0) +#define CLEAR_FP_COND(num,env) do { (env->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0) +#define IS_FP_COND_SET(num,env) (((env->fcr31) & ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23)))) != 0) +#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) +#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) +#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) +#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v & 0x3f) << 12); } while(0) +#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v & 0x1f) << 7); } while(0) +#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v & 0x1f) << 2); } while(0) +#define UPDATE_FP_FLAGS(reg,v) do { (reg) |= ((v & 0x1f) << 2); } while(0) #define FP_INEXACT 1 #define FP_UNDERFLOW 2 #define FP_OVERFLOW 4 @@ -267,6 +271,7 @@ struct CPUMIPSState { int SYNCI_Step; /* Address step size for SYNCI */ int CCRes; /* Cycle count resolution/divisor */ + int Status_rw_bitmask; /* Read/write bits in CP0_Status */ #if defined(CONFIG_USER_ONLY) target_ulong tls_value; @@ -330,10 +335,11 @@ enum { EXCP_RI, EXCP_OVERFLOW, EXCP_TRAP, + EXCP_FPE, EXCP_DDBS, EXCP_DWATCH, - EXCP_LAE, - EXCP_SAE, /* 24 */ + EXCP_LAE, /* 24 */ + EXCP_SAE, EXCP_LTLBL, EXCP_TLBL, EXCP_TLBS, diff --git a/target-mips/exec.h b/target-mips/exec.h index b00263f1b..d9160a1f3 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -29,12 +29,18 @@ register target_ulong T2 asm(AREG3); #define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) #define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) #define FST2 (env->ft2.fs[FP_ENDIAN_IDX]) +#define FSTH0 (env->ft0.fs[!FP_ENDIAN_IDX]) +#define FSTH1 (env->ft1.fs[!FP_ENDIAN_IDX]) +#define FSTH2 (env->ft2.fs[!FP_ENDIAN_IDX]) #define DT0 (env->ft0.d) #define DT1 (env->ft1.d) #define DT2 (env->ft2.d) #define WT0 (env->ft0.w[FP_ENDIAN_IDX]) #define WT1 (env->ft1.w[FP_ENDIAN_IDX]) #define WT2 (env->ft2.w[FP_ENDIAN_IDX]) +#define WTH0 (env->ft0.w[!FP_ENDIAN_IDX]) +#define WTH1 (env->ft1.w[!FP_ENDIAN_IDX]) +#define WTH2 (env->ft2.w[!FP_ENDIAN_IDX]) #endif #if defined (DEBUG_OP) diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index 4ebb46bff..bb288f11e 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -19,75 +19,103 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#if defined(SFREG) +#if defined(FREG) -#define OP_WLOAD_FREG(treg, tregname, SFREG) \ - void glue(glue(op_load_fpr_,tregname), SFREG) (void) \ - { \ - treg = FPR_W(env, SFREG); \ - RETURN(); \ +#define OP_WLOAD_FREG(treg, tregname, FREG) \ + void glue(glue(op_load_fpr_,tregname), FREG) (void) \ + { \ + treg = env->fpr[FREG].fs[FP_ENDIAN_IDX]; \ + RETURN(); \ } -#define OP_WSTORE_FREG(treg, tregname, SFREG) \ - void glue(glue(op_store_fpr_,tregname), SFREG) (void)\ - { \ - FPR_W(env, SFREG) = treg; \ - RETURN(); \ +#define OP_WSTORE_FREG(treg, tregname, FREG) \ + void glue(glue(op_store_fpr_,tregname), FREG) (void) \ + { \ + env->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \ + RETURN(); \ } -/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */ -OP_WLOAD_FREG(WT0, WT0_fpr, SFREG) -/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */ -OP_WSTORE_FREG(WT0, WT0_fpr, SFREG) +/* WT0 = FREG.w: op_load_fpr_WT0_fprFREG */ +OP_WLOAD_FREG(WT0, WT0_fpr, FREG) +/* FREG.w = WT0: op_store_fpr_WT0_fprFREG */ +OP_WSTORE_FREG(WT0, WT0_fpr, FREG) + +OP_WLOAD_FREG(WT1, WT1_fpr, FREG) +OP_WSTORE_FREG(WT1, WT1_fpr, FREG) + +OP_WLOAD_FREG(WT2, WT2_fpr, FREG) +OP_WSTORE_FREG(WT2, WT2_fpr, FREG) + +#define OP_DLOAD_FREG(treg, tregname, FREG) \ + void glue(glue(op_load_fpr_,tregname), FREG) (void) \ + { \ + if (env->CP0_Status & (1 << CP0St_FR)) \ + treg = env->fpr[FREG].fd; \ + else \ + treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ + env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \ + RETURN(); \ + } -OP_WLOAD_FREG(WT1, WT1_fpr, SFREG) -OP_WSTORE_FREG(WT1, WT1_fpr, SFREG) +#define OP_DSTORE_FREG(treg, tregname, FREG) \ + void glue(glue(op_store_fpr_,tregname), FREG) (void) \ + { \ + if (env->CP0_Status & (1 << CP0St_FR)) \ + env->fpr[FREG].fd = treg; \ + else { \ + env->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ + env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \ + } \ + RETURN(); \ + } -OP_WLOAD_FREG(WT2, WT2_fpr, SFREG) -OP_WSTORE_FREG(WT2, WT2_fpr, SFREG) +OP_DLOAD_FREG(DT0, DT0_fpr, FREG) +OP_DSTORE_FREG(DT0, DT0_fpr, FREG) -#endif +OP_DLOAD_FREG(DT1, DT1_fpr, FREG) +OP_DSTORE_FREG(DT1, DT1_fpr, FREG) -#if defined(DFREG) +OP_DLOAD_FREG(DT2, DT2_fpr, FREG) +OP_DSTORE_FREG(DT2, DT2_fpr, FREG) -#define OP_DLOAD_FREG(treg, tregname, DFREG) \ - void glue(glue(op_load_fpr_,tregname), DFREG) (void) \ - { \ - treg = FPR_D(env, DFREG); \ - RETURN(); \ +#define OP_PSLOAD_FREG(treg, tregname, FREG) \ + void glue(glue(op_load_fpr_,tregname), FREG) (void) \ + { \ + treg = env->fpr[FREG].fs[!FP_ENDIAN_IDX]; \ + RETURN(); \ } -#define OP_DSTORE_FREG(treg, tregname, DFREG) \ - void glue(glue(op_store_fpr_,tregname), DFREG) (void)\ - { \ - FPR_D(env, DFREG) = treg; \ - RETURN(); \ +#define OP_PSSTORE_FREG(treg, tregname, FREG) \ + void glue(glue(op_store_fpr_,tregname), FREG) (void) \ + { \ + env->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \ + RETURN(); \ } -OP_DLOAD_FREG(DT0, DT0_fpr, DFREG) -OP_DSTORE_FREG(DT0, DT0_fpr, DFREG) +OP_PSLOAD_FREG(WTH0, WTH0_fpr, FREG) +OP_PSSTORE_FREG(WTH0, WTH0_fpr, FREG) -OP_DLOAD_FREG(DT1, DT1_fpr, DFREG) -OP_DSTORE_FREG(DT1, DT1_fpr, DFREG) +OP_PSLOAD_FREG(WTH1, WTH1_fpr, FREG) +OP_PSSTORE_FREG(WTH1, WTH1_fpr, FREG) -OP_DLOAD_FREG(DT2, DT2_fpr, DFREG) -OP_DSTORE_FREG(DT2, DT2_fpr, DFREG) +OP_PSLOAD_FREG(WTH2, WTH2_fpr, FREG) +OP_PSSTORE_FREG(WTH2, WTH2_fpr, FREG) #endif #if defined (FTN) -#define SET_RESET(treg, tregname) \ +#define SET_RESET(treg, tregname) \ void glue(op_set, tregname)(void) \ - { \ - treg = PARAM1; \ - RETURN(); \ - } \ + { \ + treg = PARAM1; \ + RETURN(); \ + } \ void glue(op_reset, tregname)(void) \ - { \ - treg = 0; \ - RETURN(); \ - } \ + { \ + treg = 0; \ + RETURN(); \ + } SET_RESET(WT0, _WT0) SET_RESET(WT1, _WT1) @@ -95,6 +123,9 @@ SET_RESET(WT2, _WT2) SET_RESET(DT0, _DT0) SET_RESET(DT1, _DT1) SET_RESET(DT2, _DT2) +SET_RESET(WTH0, _WTH0) +SET_RESET(WTH1, _WTH1) +SET_RESET(WTH2, _WTH2) #undef SET_RESET #endif diff --git a/target-mips/helper.c b/target-mips/helper.c index 8d9435a23..909db5d37 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -379,6 +379,9 @@ void do_interrupt (CPUState *env) case EXCP_TRAP: cause = 13; goto set_EPC; + case EXCP_FPE: + cause = 15; + goto set_EPC; case EXCP_LTLBL: cause = 1; goto set_EPC; diff --git a/target-mips/op.c b/target-mips/op.c index 0b5e8bacb..899892f68 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -23,27 +23,27 @@ #include "exec.h" #ifndef CALL_FROM_TB0 -#define CALL_FROM_TB0(func) func(); +#define CALL_FROM_TB0(func) func() #endif #ifndef CALL_FROM_TB1 -#define CALL_FROM_TB1(func, arg0) func(arg0); +#define CALL_FROM_TB1(func, arg0) func(arg0) #endif #ifndef CALL_FROM_TB1_CONST16 -#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0); +#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0) #endif #ifndef CALL_FROM_TB2 -#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1); +#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1) #endif #ifndef CALL_FROM_TB2_CONST16 #define CALL_FROM_TB2_CONST16(func, arg0, arg1) \ -CALL_FROM_TB2(func, arg0, arg1); + CALL_FROM_TB2(func, arg0, arg1) #endif #ifndef CALL_FROM_TB3 -#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2); +#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2) #endif #ifndef CALL_FROM_TB4 #define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \ - func(arg0, arg1, arg2, arg3); + func(arg0, arg1, arg2, arg3) #endif #define REG 1 @@ -144,134 +144,102 @@ CALL_FROM_TB2(func, arg0, arg1); #include "op_template.c" #undef TN -#define SFREG 0 -#define DFREG 0 +#define FREG 0 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 1 +#undef FREG +#define FREG 1 #include "fop_template.c" -#undef SFREG -#define SFREG 2 -#define DFREG 2 +#undef FREG +#define FREG 2 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 3 +#undef FREG +#define FREG 3 #include "fop_template.c" -#undef SFREG -#define SFREG 4 -#define DFREG 4 +#undef FREG +#define FREG 4 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 5 +#undef FREG +#define FREG 5 #include "fop_template.c" -#undef SFREG -#define SFREG 6 -#define DFREG 6 +#undef FREG +#define FREG 6 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 7 +#undef FREG +#define FREG 7 #include "fop_template.c" -#undef SFREG -#define SFREG 8 -#define DFREG 8 +#undef FREG +#define FREG 8 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 9 +#undef FREG +#define FREG 9 #include "fop_template.c" -#undef SFREG -#define SFREG 10 -#define DFREG 10 +#undef FREG +#define FREG 10 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 11 +#undef FREG +#define FREG 11 #include "fop_template.c" -#undef SFREG -#define SFREG 12 -#define DFREG 12 +#undef FREG +#define FREG 12 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 13 +#undef FREG +#define FREG 13 #include "fop_template.c" -#undef SFREG -#define SFREG 14 -#define DFREG 14 +#undef FREG +#define FREG 14 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 15 +#undef FREG +#define FREG 15 #include "fop_template.c" -#undef SFREG -#define SFREG 16 -#define DFREG 16 +#undef FREG +#define FREG 16 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 17 +#undef FREG +#define FREG 17 #include "fop_template.c" -#undef SFREG -#define SFREG 18 -#define DFREG 18 +#undef FREG +#define FREG 18 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 19 +#undef FREG +#define FREG 19 #include "fop_template.c" -#undef SFREG -#define SFREG 20 -#define DFREG 20 +#undef FREG +#define FREG 20 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 21 +#undef FREG +#define FREG 21 #include "fop_template.c" -#undef SFREG -#define SFREG 22 -#define DFREG 22 +#undef FREG +#define FREG 22 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 23 +#undef FREG +#define FREG 23 #include "fop_template.c" -#undef SFREG -#define SFREG 24 -#define DFREG 24 +#undef FREG +#define FREG 24 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 25 +#undef FREG +#define FREG 25 #include "fop_template.c" -#undef SFREG -#define SFREG 26 -#define DFREG 26 +#undef FREG +#define FREG 26 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 27 +#undef FREG +#define FREG 27 #include "fop_template.c" -#undef SFREG -#define SFREG 28 -#define DFREG 28 +#undef FREG +#define FREG 28 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 29 +#undef FREG +#define FREG 29 #include "fop_template.c" -#undef SFREG -#define SFREG 30 -#define DFREG 30 +#undef FREG +#define FREG 30 #include "fop_template.c" -#undef SFREG -#undef DFREG -#define SFREG 31 +#undef FREG +#define FREG 31 #include "fop_template.c" -#undef SFREG +#undef FREG #define FTN #include "fop_template.c" @@ -919,14 +887,14 @@ void op_movz (void) void op_movf (void) { if (!(env->fcr31 & PARAM1)) - env->gpr[PARAM2] = env->gpr[PARAM3]; + T0 = T1; RETURN(); } void op_movt (void) { if (env->fcr31 & PARAM1) - env->gpr[PARAM2] = env->gpr[PARAM3]; + T0 = T1; RETURN(); } @@ -1354,17 +1322,18 @@ void op_mtc0_compare (void) void op_mtc0_status (void) { uint32_t val, old; + uint32_t mask = env->Status_rw_bitmask; - /* No 64bit FPU, no reverse endianness, no MDMX/DSP, no 64bit ops, + /* No reverse endianness, no MDMX/DSP, no 64bit ops, no 64bit addressing implemented. */ - val = (int32_t)T0 & 0xF878FF17; + val = (int32_t)T0 & mask; old = env->CP0_Status; if (!(val & (1 << CP0St_EXL)) && !(val & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM) && (val & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; - env->CP0_Status = (env->CP0_Status & ~0xF878FF17) | val; + env->CP0_Status = (env->CP0_Status & ~mask) | val; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB2(do_mtc0_status_debug, old, val); CALL_FROM_TB1(cpu_mips_update_irq, env); @@ -1643,6 +1612,7 @@ void op_dmtc0_errorepc (void) } #endif /* TARGET_MIPS64 */ +/* CP1 functions */ #if 0 # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) #else @@ -1666,20 +1636,6 @@ void op_cp1_enabled(void) RETURN(); } -/* CP1 functions */ -void op_cfc1 (void) -{ - if (T1 == 0) { - T0 = env->fcr0; - } - else { - /* fetch fcr31, masking unused bits */ - T0 = env->fcr31 & 0x0183FFFF; - } - DEBUG_FPU_STATE(); - RETURN(); -} - /* convert MIPS rounding mode in FCR31 to IEEE library */ unsigned int ieee_rm[] = { float_round_nearest_even, @@ -1691,26 +1647,93 @@ unsigned int ieee_rm[] = { #define RESTORE_ROUNDING_MODE \ set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) -void op_ctc1 (void) +inline char ieee_ex_to_mips(char ieee) { - if (T1 == 0) { - /* XXX should this throw an exception? - * don't write to FCR0. - * env->fcr0 = T0; - */ - } - else { - /* store new fcr31, masking unused bits */ - env->fcr31 = T0 & 0x0183FFFF; + return (ieee & float_flag_inexact) >> 5 | + (ieee & float_flag_underflow) >> 3 | + (ieee & float_flag_overflow) >> 1 | + (ieee & float_flag_divbyzero) << 1 | + (ieee & float_flag_invalid) << 4; +} - /* set rounding mode */ - RESTORE_ROUNDING_MODE; +inline char mips_ex_to_ieee(char mips) +{ + return (mips & FP_INEXACT) << 5 | + (mips & FP_UNDERFLOW) << 3 | + (mips & FP_OVERFLOW) << 1 | + (mips & FP_DIV0) >> 1 | + (mips & FP_INVALID) >> 4; +} -#ifndef CONFIG_SOFTFLOAT - /* no floating point exception for native float */ - SET_FP_ENABLE(env->fcr31, 0); -#endif +inline void update_fcr31(void) +{ + int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status)); + + SET_FP_CAUSE(env->fcr31, tmp); + if (GET_FP_ENABLE(env->fcr31) & tmp) + CALL_FROM_TB1(do_raise_exception, EXCP_FPE); + else + UPDATE_FP_FLAGS(env->fcr31, tmp); +} + + +void op_cfc1 (void) +{ + switch (T1) { + case 0: + T0 = (int32_t)env->fcr0; + break; + case 25: + T0 = ((env->fcr31 >> 24) & 0xfe) | ((env->fcr31 >> 23) & 0x1); + break; + case 26: + T0 = env->fcr31 & 0x0003f07c; + break; + case 28: + T0 = (env->fcr31 & 0x00000f83) | ((env->fcr31 >> 22) & 0x4); + break; + default: + T0 = (int32_t)env->fcr31; + break; + } + DEBUG_FPU_STATE(); + RETURN(); +} + +void op_ctc1 (void) +{ + switch(T1) { + case 25: + if (T0 & 0xffffff00) + goto leave; + env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | + ((T0 & 0x1) << 23); + break; + case 26: + if (T0 & 0x007c0000) + goto leave; + env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); + break; + case 28: + if (T0 & 0x007c0000) + goto leave; + env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | + ((T0 & 0x4) << 22); + break; + case 31: + if (T0 & 0x007c0000) + goto leave; + env->fcr31 = T0; + break; + default: + goto leave; } + /* set rounding mode */ + RESTORE_ROUNDING_MODE; + set_float_exception_flags(0, &env->fp_status); + if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31)) + CALL_FROM_TB1(do_raise_exception, EXCP_FPE); + leave: DEBUG_FPU_STATE(); RETURN(); } @@ -1729,55 +1752,219 @@ void op_mtc1 (void) RETURN(); } +void op_dmfc1 (void) +{ + T0 = DT0; + DEBUG_FPU_STATE(); + RETURN(); +} + +void op_dmtc1 (void) +{ + DT0 = T0; + DEBUG_FPU_STATE(); + RETURN(); +} + +void op_mfhc1 (void) +{ + T0 = WTH0; + DEBUG_FPU_STATE(); + RETURN(); +} + +void op_mthc1 (void) +{ + WTH0 = T0; + DEBUG_FPU_STATE(); + RETURN(); +} + /* Float support. Single precition routines have a "s" suffix, double precision a - "d" suffix. */ + "d" suffix, 32bit integer "w", 64bit integer "l", paired singe "ps", + paired single lowwer "pl", paired single upper "pu". */ #define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void) FLOAT_OP(cvtd, s) { + set_float_exception_flags(0, &env->fp_status); FDT2 = float32_to_float64(FST0, &env->fp_status); + update_fcr31(); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtd, w) { + set_float_exception_flags(0, &env->fp_status); FDT2 = int32_to_float64(WT0, &env->fp_status); + update_fcr31(); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvtd, l) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = int64_to_float64(DT0, &env->fp_status); + update_fcr31(); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvtl, d) +{ + set_float_exception_flags(0, &env->fp_status); + DT2 = float64_to_int64(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvtl, s) +{ + set_float_exception_flags(0, &env->fp_status); + DT2 = float32_to_int64(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvtps, s) +{ + WT2 = WT0; + WTH2 = WT1; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvtps, pw) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = int32_to_float32(WT0, &env->fp_status); + FSTH2 = int32_to_float32(WTH0, &env->fp_status); + update_fcr31(); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvtpw, ps) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = float32_to_int32(FST0, &env->fp_status); + WTH2 = float32_to_int32(FSTH0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, d) { + set_float_exception_flags(0, &env->fp_status); FST2 = float64_to_float32(FDT0, &env->fp_status); + update_fcr31(); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, w) { + set_float_exception_flags(0, &env->fp_status); FST2 = int32_to_float32(WT0, &env->fp_status); + update_fcr31(); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvts, l) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = int64_to_float32(DT0, &env->fp_status); + update_fcr31(); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvts, pl) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = WT0; + update_fcr31(); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(cvts, pu) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = WTH0; + update_fcr31(); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtw, s) { + set_float_exception_flags(0, &env->fp_status); WT2 = float32_to_int32(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtw, d) { + set_float_exception_flags(0, &env->fp_status); WT2 = float64_to_int32(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; + DEBUG_FPU_STATE(); + RETURN(); +} + +FLOAT_OP(pll, ps) +{ + DT2 = ((uint64_t)WT0 << 32) | WT1; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(plu, ps) +{ + DT2 = ((uint64_t)WT0 << 32) | WTH1; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(pul, ps) +{ + DT2 = ((uint64_t)WTH0 << 32) | WT1; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(puu, ps) +{ + DT2 = ((uint64_t)WTH0 << 32) | WTH1; DEBUG_FPU_STATE(); RETURN(); } +FLOAT_OP(roundl, d) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(roundl, s) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} FLOAT_OP(roundw, d) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); WT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; - DEBUG_FPU_STATE(); RETURN(); } @@ -1790,6 +1977,18 @@ FLOAT_OP(roundw, s) RETURN(); } +FLOAT_OP(truncl, d) +{ + DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(truncl, s) +{ + DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); + DEBUG_FPU_STATE(); + RETURN(); +} FLOAT_OP(truncw, d) { WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); @@ -1803,12 +2002,27 @@ FLOAT_OP(truncw, s) RETURN(); } +FLOAT_OP(ceill, d) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(ceill, s) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} FLOAT_OP(ceilw, d) { set_float_rounding_mode(float_round_up, &env->fp_status); WT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; - DEBUG_FPU_STATE(); RETURN(); } @@ -1821,12 +2035,27 @@ FLOAT_OP(ceilw, s) RETURN(); } +FLOAT_OP(floorl, d) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(floorl, s) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + DEBUG_FPU_STATE(); + RETURN(); +} FLOAT_OP(floorw, d) { set_float_rounding_mode(float_round_down, &env->fp_status); WT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; - DEBUG_FPU_STATE(); RETURN(); } @@ -1839,16 +2068,121 @@ FLOAT_OP(floorw, s) RETURN(); } +FLOAT_OP(movf, d) +{ + if (!(env->fcr31 & PARAM1)) + DT2 = DT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movf, s) +{ + if (!(env->fcr31 & PARAM1)) + WT2 = WT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movf, ps) +{ + if (!(env->fcr31 & PARAM1)) { + WT2 = WT0; + WTH2 = WTH0; + } + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movt, d) +{ + if (env->fcr31 & PARAM1) + DT2 = DT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movt, s) +{ + if (env->fcr31 & PARAM1) + WT2 = WT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movt, ps) +{ + if (env->fcr31 & PARAM1) { + WT2 = WT0; + WTH2 = WTH0; + } + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movz, d) +{ + if (!T0) + DT2 = DT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movz, s) +{ + if (!T0) + WT2 = WT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movz, ps) +{ + if (!T0) { + WT2 = WT0; + WTH2 = WTH0; + } + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movn, d) +{ + if (T0) + DT2 = DT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movn, s) +{ + if (T0) + WT2 = WT0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(movn, ps) +{ + if (T0) { + WT2 = WT0; + WTH2 = WTH0; + } + DEBUG_FPU_STATE(); + RETURN(); +} + /* binary operations */ #define FLOAT_BINOP(name) \ FLOAT_OP(name, d) \ { \ + set_float_exception_flags(0, &env->fp_status); \ FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ + update_fcr31(); \ DEBUG_FPU_STATE(); \ } \ FLOAT_OP(name, s) \ { \ + set_float_exception_flags(0, &env->fp_status); \ FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ + update_fcr31(); \ + DEBUG_FPU_STATE(); \ +} \ +FLOAT_OP(name, ps) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ + FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ + update_fcr31(); \ DEBUG_FPU_STATE(); \ } FLOAT_BINOP(add) @@ -1857,6 +2191,32 @@ FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP +/* ternary operations */ +#define FLOAT_TERNOP(name1, name2) \ +FLOAT_OP(name1 ## name2, d) \ +{ \ + FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \ + FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \ + DEBUG_FPU_STATE(); \ +} \ +FLOAT_OP(name1 ## name2, s) \ +{ \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ + DEBUG_FPU_STATE(); \ +} \ +FLOAT_OP(name1 ## name2, ps) \ +{ \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ + FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ + FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \ + DEBUG_FPU_STATE(); \ +} +FLOAT_TERNOP(mul, add) +FLOAT_TERNOP(mul, sub) +#undef FLOAT_TERNOP + /* unary operations, modifying fp status */ #define FLOAT_UNOP(name) \ FLOAT_OP(name, d) \ @@ -1868,6 +2228,12 @@ FLOAT_OP(name, s) \ { \ FST2 = float32_ ## name(FST0, &env->fp_status); \ DEBUG_FPU_STATE(); \ +} \ +FLOAT_OP(name, ps) \ +{ \ + FST2 = float32_ ## name(FST0, &env->fp_status); \ + FSTH2 = float32_ ## name(FSTH0, &env->fp_status); \ + DEBUG_FPU_STATE(); \ } FLOAT_UNOP(sqrt) #undef FLOAT_UNOP @@ -1883,6 +2249,12 @@ FLOAT_OP(name, s) \ { \ FST2 = float32_ ## name(FST0); \ DEBUG_FPU_STATE(); \ +} \ +FLOAT_OP(name, ps) \ +{ \ + FST2 = float32_ ## name(FST0); \ + FSTH2 = float32_ ## name(FSTH0); \ + DEBUG_FPU_STATE(); \ } FLOAT_UNOP(abs) FLOAT_UNOP(chs) @@ -1900,6 +2272,35 @@ FLOAT_OP(mov, s) DEBUG_FPU_STATE(); RETURN(); } +FLOAT_OP(mov, ps) +{ + FST2 = FST0; + FSTH2 = FSTH0; + DEBUG_FPU_STATE(); + RETURN(); +} +FLOAT_OP(alnv, ps) +{ + switch (T0 & 0x7) { + case 0: + FST2 = FST0; + FSTH2 = FSTH0; + break; + case 4: +#ifdef TARGET_WORDS_BIGENDIAN + FSTH2 = FST0; + FST2 = FSTH1; +#else + FSTH2 = FST1; + FST2 = FSTH0; +#endif + break; + default: /* unpredictable */ + break; + } + DEBUG_FPU_STATE(); + RETURN(); +} #ifdef CONFIG_SOFTFLOAT #define clear_invalid() do { \ @@ -1913,96 +2314,200 @@ FLOAT_OP(mov, s) extern void dump_fpu_s(CPUState *env); -#define FOP_COND(fmt, op, sig, cond) \ -void op_cmp_ ## fmt ## _ ## op (void) \ +#define FOP_COND_D(op, cond) \ +void op_cmp_d_ ## op (void) \ { \ - if (cond) \ - SET_FP_COND(env->fcr31); \ + int c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(PARAM1, env); \ else \ - CLEAR_FP_COND(env->fcr31); \ - if (!sig) \ - clear_invalid(); \ - /*CALL_FROM_TB1(dump_fpu_s, env);*/ \ + CLEAR_FP_COND(PARAM1, env); \ DEBUG_FPU_STATE(); \ RETURN(); \ } -int float64_is_unordered(float64 a, float64 b STATUS_PARAM) +int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) { - if (float64_is_nan(a) || float64_is_nan(b)) { + if (float64_is_signaling_nan(a) || + float64_is_signaling_nan(b) || + (sig && (float64_is_nan(a) || float64_is_nan(b)))) { float_raise(float_flag_invalid, status); return 1; - } - else { + } else if (float64_is_nan(a) || float64_is_nan(b)) { + return 1; + } else { return 0; } } -FOP_COND(d, f, 0, 0) -FOP_COND(d, un, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status)) -FOP_COND(d, eq, 0, float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, olt, 0, float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, ole, 0, float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, ule, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called - */ -FOP_COND(d, sf, 1, (float64_is_unordered(FDT0, FDT1, &env->fp_status), 0)) -FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status)) -FOP_COND(d, seq, 1, float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, lt, 1, float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, le, 1, float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) - -flag float32_is_unordered(float32 a, float32 b STATUS_PARAM) -{ - extern flag float32_is_nan( float32 a ); - if (float32_is_nan(a) || float32_is_nan(b)) { + * but float*_is_unordered() is still called. */ +FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0)) +FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)) +FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0)) +FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status)) +FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) + +#define FOP_COND_S(op, cond) \ +void op_cmp_s_ ## op (void) \ +{ \ + int c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(PARAM1, env); \ + else \ + CLEAR_FP_COND(PARAM1, env); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} + +flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) +{ + extern flag float32_is_nan(float32 a); + if (float32_is_signaling_nan(a) || + float32_is_signaling_nan(b) || + (sig && (float32_is_nan(a) || float32_is_nan(b)))) { float_raise(float_flag_invalid, status); return 1; - } - else { + } else if (float32_is_nan(a) || float32_is_nan(b)) { + return 1; + } else { return 0; } } /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called - */ -FOP_COND(s, f, 0, 0) -FOP_COND(s, un, 0, float32_is_unordered(FST1, FST0, &env->fp_status)) -FOP_COND(s, eq, 0, float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND(s, olt, 0, float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND(s, ole, 0, float32_le(FST0, FST1, &env->fp_status)) -FOP_COND(s, ule, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) + * but float*_is_unordered() is still called. */ +FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0)) +FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status)) +FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called - */ -FOP_COND(s, sf, 1, (float32_is_unordered(FST0, FST1, &env->fp_status), 0)) -FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status)) -FOP_COND(s, seq, 1, float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND(s, lt, 1, float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND(s, le, 1, float32_le(FST0, FST1, &env->fp_status)) -FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) + * but float*_is_unordered() is still called. */ +FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0)) +FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status)) +FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) + +#define FOP_COND_PS(op, condl, condh) \ +void op_cmp_ps_ ## op (void) \ +{ \ + int cl = condl; \ + int ch = condh; \ + update_fcr31(); \ + if (cl) \ + SET_FP_COND(PARAM1, env); \ + else \ + CLEAR_FP_COND(PARAM1, env); \ + if (ch) \ + SET_FP_COND(PARAM1 + 1, env); \ + else \ + CLEAR_FP_COND(PARAM1 + 1, env); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0), + (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0)) +FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)) +FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0), + (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0)) +FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)) +FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) void op_bc1f (void) { - T0 = ! IS_FP_COND_SET(env->fcr31); + T0 = !IS_FP_COND_SET(PARAM1, env); + DEBUG_FPU_STATE(); + RETURN(); +} +void op_bc1fany2 (void) +{ + T0 = (!IS_FP_COND_SET(PARAM1, env) || + !IS_FP_COND_SET(PARAM1 + 1, env)); + DEBUG_FPU_STATE(); + RETURN(); +} +void op_bc1fany4 (void) +{ + T0 = (!IS_FP_COND_SET(PARAM1, env) || + !IS_FP_COND_SET(PARAM1 + 1, env) || + !IS_FP_COND_SET(PARAM1 + 2, env) || + !IS_FP_COND_SET(PARAM1 + 3, env)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1t (void) { - T0 = IS_FP_COND_SET(env->fcr31); + T0 = IS_FP_COND_SET(PARAM1, env); + DEBUG_FPU_STATE(); + RETURN(); +} +void op_bc1tany2 (void) +{ + T0 = (IS_FP_COND_SET(PARAM1, env) || + IS_FP_COND_SET(PARAM1 + 1, env)); + DEBUG_FPU_STATE(); + RETURN(); +} +void op_bc1tany4 (void) +{ + T0 = (IS_FP_COND_SET(PARAM1, env) || + IS_FP_COND_SET(PARAM1 + 1, env) || + IS_FP_COND_SET(PARAM1 + 2, env) || + IS_FP_COND_SET(PARAM1 + 3, env)); DEBUG_FPU_STATE(); RETURN(); } @@ -2037,7 +2542,7 @@ void op_tlbr (void) #if defined (CONFIG_USER_ONLY) void op_tls_value (void) { - T0 = env->tls_value; + T0 = env->tls_value; } #endif @@ -2180,6 +2685,17 @@ void op_save_pc (void) RETURN(); } +void op_save_fp_status (void) +{ + union fps { + uint32_t i; + float_status f; + } fps; + fps.i = PARAM1; + env->fp_status = fps.f; + RETURN(); +} + void op_interrupt_restart (void) { if (!(env->CP0_Status & (1 << CP0St_EXL)) && diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 19373cf00..f0eebc09d 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -220,3 +220,35 @@ void glue(op_sdc1, MEMSUFFIX) (void) glue(stq, MEMSUFFIX)(T0, DT0); RETURN(); } +void glue(op_lwxc1, MEMSUFFIX) (void) +{ + WT0 = glue(ldl, MEMSUFFIX)(T0 + T1); + RETURN(); +} +void glue(op_swxc1, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)(T0 + T1, WT0); + RETURN(); +} +void glue(op_ldxc1, MEMSUFFIX) (void) +{ + DT0 = glue(ldq, MEMSUFFIX)(T0 + T1); + RETURN(); +} +void glue(op_sdxc1, MEMSUFFIX) (void) +{ + glue(stq, MEMSUFFIX)(T0 + T1, DT0); + RETURN(); +} +void glue(op_luxc1, MEMSUFFIX) (void) +{ + /* XXX: is defined as unaligned */ + DT0 = glue(ldq, MEMSUFFIX)(T0 + T1); + RETURN(); +} +void glue(op_suxc1, MEMSUFFIX) (void) +{ + /* XXX: is defined as unaligned */ + glue(stq, MEMSUFFIX)(T0 + T1, DT0); + RETURN(); +} diff --git a/target-mips/translate.c b/target-mips/translate.c index 06581f2cc..6098b2a10 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -333,20 +333,26 @@ enum { OPC_MFC1 = (0x00 << 21) | OPC_CP1, OPC_DMFC1 = (0x01 << 21) | OPC_CP1, OPC_CFC1 = (0x02 << 21) | OPC_CP1, - OPC_MFHCI = (0x03 << 21) | OPC_CP1, + OPC_MFHC1 = (0x03 << 21) | OPC_CP1, OPC_MTC1 = (0x04 << 21) | OPC_CP1, OPC_DMTC1 = (0x05 << 21) | OPC_CP1, OPC_CTC1 = (0x06 << 21) | OPC_CP1, - OPC_MTHCI = (0x07 << 21) | OPC_CP1, + OPC_MTHC1 = (0x07 << 21) | OPC_CP1, OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */ + OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1, + OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1, OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */ OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */ OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */ OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */ OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */ OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */ + OPC_PS_FMT = (0x16 << 21) | OPC_CP1, /* 22: fmt=paired single fp */ }; +#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) +#define MASK_BC1(op) MASK_CP1(op) | (op & (0x3 << 16)) + enum { OPC_BC1F = (0x00 << 16) | OPC_BC1, OPC_BC1T = (0x01 << 16) | OPC_BC1, @@ -354,8 +360,15 @@ enum { OPC_BC1TL = (0x03 << 16) | OPC_BC1, }; -#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & (0x3 << 16)) -#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F) +enum { + OPC_BC1FANY2 = (0x00 << 16) | OPC_BC1ANY2, + OPC_BC1TANY2 = (0x01 << 16) | OPC_BC1ANY2, +}; + +enum { + OPC_BC1FANY4 = (0x00 << 16) | OPC_BC1ANY4, + OPC_BC1TANY4 = (0x01 << 16) | OPC_BC1ANY4, +}; #define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21)) @@ -404,20 +417,20 @@ const unsigned char *regnames[] = "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; /* Warning: no function for r0 register (hard wired to zero) */ -#define GEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static inline void func(int n) \ -{ \ - NAME ## _table[n](); \ +#define GEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = { \ +NULL, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ } /* General purpose registers moves */ @@ -434,58 +447,51 @@ static const char *fregnames[] = "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; -# define SFGEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ -NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ -NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ -NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ -NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ -NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ -NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ -NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ -}; \ -static inline void func(int n) \ -{ \ - NAME ## _table[n](); \ +#define FGEN32(func, NAME) \ +static GenOpFunc *NAME ## _table [32] = { \ +NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ +NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ +NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ +NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ +NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ +NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ +NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ +NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ +}; \ +static inline void func(int n) \ +{ \ + NAME ## _table[n](); \ } -# define DFGEN32(func, NAME) \ -static GenOpFunc *NAME ## _table [32] = { \ -NAME ## 0, 0, NAME ## 2, 0, \ -NAME ## 4, 0, NAME ## 6, 0, \ -NAME ## 8, 0, NAME ## 10, 0, \ -NAME ## 12, 0, NAME ## 14, 0, \ -NAME ## 16, 0, NAME ## 18, 0, \ -NAME ## 20, 0, NAME ## 22, 0, \ -NAME ## 24, 0, NAME ## 26, 0, \ -NAME ## 28, 0, NAME ## 30, 0, \ -}; \ -static inline void func(int n) \ -{ \ - NAME ## _table[n](); \ -} +FGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); +FGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); + +FGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); +FGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); -SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr); -SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr); +FGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); +FGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); -SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr); -SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr); +FGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); +FGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); -SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr); -SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr); +FGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); +FGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); -DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr); -DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr); +FGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); +FGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); -DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr); -DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr); +FGEN32(gen_op_load_fpr_WTH0, gen_op_load_fpr_WTH0_fpr); +FGEN32(gen_op_store_fpr_WTH0, gen_op_store_fpr_WTH0_fpr); -DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr); -DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr); +FGEN32(gen_op_load_fpr_WTH1, gen_op_load_fpr_WTH1_fpr); +FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr); + +FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); +FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); #define FOP_CONDS(fmt) \ -static GenOpFunc * cond_ ## fmt ## _table[16] = { \ +static GenOpFunc1 * cond_ ## fmt ## _table[16] = { \ gen_op_cmp_ ## fmt ## _f, \ gen_op_cmp_ ## fmt ## _un, \ gen_op_cmp_ ## fmt ## _eq, \ @@ -503,18 +509,20 @@ static GenOpFunc * cond_ ## fmt ## _table[16] = { \ gen_op_cmp_ ## fmt ## _le, \ gen_op_cmp_ ## fmt ## _ngt, \ }; \ -static inline void gen_cmp_ ## fmt(int n) \ +static inline void gen_cmp_ ## fmt(int n, long cc) \ { \ - cond_ ## fmt ## _table[n](); \ + cond_ ## fmt ## _table[n](cc); \ } FOP_CONDS(d) FOP_CONDS(s) +FOP_CONDS(ps) typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; uint32_t opcode; + uint32_t fp_status, saved_fp_status; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; @@ -600,17 +608,31 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) if (ctx->hflags != ctx->saved_hflags) { gen_op_save_state(ctx->hflags); ctx->saved_hflags = ctx->hflags; - if (ctx->hflags & MIPS_HFLAG_BR) { + switch (ctx->hflags & MIPS_HFLAG_BMASK) { + case MIPS_HFLAG_BR: gen_op_save_breg_target(); - } else if (ctx->hflags & MIPS_HFLAG_B) { - gen_op_save_btarget(ctx->btarget); - } else if (ctx->hflags & MIPS_HFLAG_BMASK) { + break; + case MIPS_HFLAG_BC: gen_op_save_bcond(); + /* fall through */ + case MIPS_HFLAG_BL: + /* bcond was already saved by the BL insn */ + /* fall through */ + case MIPS_HFLAG_B: gen_op_save_btarget(ctx->btarget); + break; } } } +static inline void save_fpu_state (DisasContext *ctx) +{ + if (ctx->fp_status != ctx->saved_fp_status) { + gen_op_save_fp_status(ctx->fp_status); + ctx->saved_fp_status = ctx->fp_status; + } +} + static inline void generate_exception_err (DisasContext *ctx, int excp, int err) { #if defined MIPS_DEBUG_DISAS @@ -677,6 +699,12 @@ OP_LD_TABLE(wc1); OP_ST_TABLE(wc1); OP_LD_TABLE(dc1); OP_ST_TABLE(dc1); +OP_LD_TABLE(wxc1); +OP_ST_TABLE(wxc1); +OP_LD_TABLE(dxc1); +OP_ST_TABLE(dxc1); +OP_LD_TABLE(uxc1); +OP_ST_TABLE(uxc1); /* Load and store */ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, @@ -1472,7 +1500,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, - "undefined branch in delay slot at PC " TARGET_FMT_lx "\n", + "Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); } MIPS_INVAL("branch/jump in bdelay slot"); @@ -1672,6 +1700,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); not_likely: ctx->hflags |= MIPS_HFLAG_BC; + gen_op_set_bcond(); break; case OPC_BLTZALL: gen_op_ltz(); @@ -1679,13 +1708,14 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); likely: ctx->hflags |= MIPS_HFLAG_BL; + gen_op_set_bcond(); + gen_op_save_bcond(); break; default: MIPS_INVAL("conditional branch/jump"); generate_exception(ctx, EXCP_RI); return; } - gen_op_set_bcond(); } MIPS_DEBUG("enter ds: link %d cond %02x target %08x", blink, ctx->hflags, btarget); @@ -4220,7 +4250,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) /* CP1 Branches (before delay slot) */ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, - int32_t offset) + int32_t cc, int32_t offset) { target_ulong btarget; @@ -4228,31 +4258,49 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, switch (op) { case OPC_BC1F: - gen_op_bc1f(); + gen_op_bc1f(cc); MIPS_DEBUG("bc1f " TARGET_FMT_lx, btarget); goto not_likely; case OPC_BC1FL: - gen_op_bc1f(); + gen_op_bc1f(cc); MIPS_DEBUG("bc1fl " TARGET_FMT_lx, btarget); goto likely; case OPC_BC1T: - gen_op_bc1t(); + gen_op_bc1t(cc); MIPS_DEBUG("bc1t " TARGET_FMT_lx, btarget); - not_likely: - ctx->hflags |= MIPS_HFLAG_BC; - break; + goto not_likely; case OPC_BC1TL: - gen_op_bc1t(); + gen_op_bc1t(cc); MIPS_DEBUG("bc1tl " TARGET_FMT_lx, btarget); likely: ctx->hflags |= MIPS_HFLAG_BL; + gen_op_set_bcond(); + gen_op_save_bcond(); break; - default: - MIPS_INVAL("cp1 branch/jump"); + case OPC_BC1FANY2: + gen_op_bc1fany2(cc); + MIPS_DEBUG("bc1fany2 " TARGET_FMT_lx, btarget); + goto not_likely; + case OPC_BC1TANY2: + gen_op_bc1tany2(cc); + MIPS_DEBUG("bc1tany2 " TARGET_FMT_lx, btarget); + goto not_likely; + case OPC_BC1FANY4: + gen_op_bc1fany4(cc); + MIPS_DEBUG("bc1fany4 " TARGET_FMT_lx, btarget); + goto not_likely; + case OPC_BC1TANY4: + gen_op_bc1tany4(cc); + MIPS_DEBUG("bc1tany4 " TARGET_FMT_lx, btarget); + not_likely: + ctx->hflags |= MIPS_HFLAG_BC; + gen_op_set_bcond(); + break; + default: + MIPS_INVAL("cp1 branch"); generate_exception (ctx, EXCP_RI); return; } - gen_op_set_bcond(); MIPS_DEBUG("enter ds: cond %02x target " TARGET_FMT_lx, ctx->hflags, btarget); @@ -4262,6 +4310,29 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, } /* Coprocessor 1 (FPU) */ + +/* verify if floating point register is valid; an operation is not defined + * if bit 0 of any register specification is set and the FR bit in the + * Status register equals zero, since the register numbers specify an + * even-odd pair of adjacent coprocessor general registers. When the FR bit + * in the Status register equals one, both even and odd register numbers + * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. + * + * Multiple 64 bit wide registers can be checked by calling + * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); + * + * FIXME: This is broken for R2, it needs to be checked at runtime, not + * at translation time. + */ +#define CHECK_FR(ctx, freg) do { \ + if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \ + generate_exception (ctx, EXCP_RI); \ + return; \ + } \ + } while(0) + +#define FOP(func, fmt) (((fmt) << 21) | (func)) + static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) { const char *opn = "unk"; @@ -4280,30 +4351,43 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "mtc1"; break; case OPC_CFC1: - if (fs != 0 && fs != 31) { - MIPS_INVAL("cfc1 freg"); - generate_exception (ctx, EXCP_RI); - return; - } GEN_LOAD_IMM_TN(T1, fs); gen_op_cfc1(); GEN_STORE_TN_REG(rt, T0); opn = "cfc1"; break; case OPC_CTC1: - if (fs != 0 && fs != 31) { - MIPS_INVAL("ctc1 freg"); - generate_exception (ctx, EXCP_RI); - return; - } GEN_LOAD_IMM_TN(T1, fs); GEN_LOAD_REG_TN(T0, rt); gen_op_ctc1(); opn = "ctc1"; break; case OPC_DMFC1: + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_dmfc1(); + GEN_STORE_TN_REG(rt, T0); + opn = "dmfc1"; + break; case OPC_DMTC1: - /* Not implemented, fallthrough. */ + GEN_LOAD_REG_TN(T0, rt); + gen_op_dmtc1(); + GEN_STORE_FTN_FREG(fs, DT0); + opn = "dmtc1"; + break; + case OPC_MFHC1: + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_mfhc1(); + GEN_STORE_TN_REG(rt, T0); + opn = "mfhc1"; + break; + case OPC_MTHC1: + CHECK_FR(ctx, fs); + GEN_LOAD_REG_TN(T0, rt); + gen_op_mthc1(); + GEN_STORE_FTN_FREG(fs, WTH0); + opn = "mthc1"; + break; default: if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", @@ -4316,26 +4400,44 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]); } -/* verify if floating point register is valid; an operation is not defined - * if bit 0 of any register specification is set and the FR bit in the - * Status register equals zero, since the register numbers specify an - * even-odd pair of adjacent coprocessor general registers. When the FR bit - * in the Status register equals one, both even and odd register numbers - * are valid. This limitation exists only for 64 bit wide (d,l) registers. - * - * Multiple 64 bit wide registers can be checked by calling - * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); - */ -#define CHECK_FR(ctx, freg) do { \ - if (!((ctx)->CP0_Status & (1<opcode & 0x3f; switch (ctx->opcode & FOP(0x3f, 0x1f)) { + case FOP(0, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_add_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "add.s"; + binary = 1; + break; + case FOP(1, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_sub_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "sub.s"; + binary = 1; + break; + case FOP(2, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_mul_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "mul.s"; + binary = 1; + break; + case FOP(3, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_div_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "div.s"; + binary = 1; + break; + case FOP(4, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_sqrt_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "sqrt.s"; + break; + case FOP(5, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_abs_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "abs.s"; + break; + case FOP(6, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_mov_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "mov.s"; + break; + case FOP(7, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_chs_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "neg.s"; + break; + case FOP(8, 16): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_roundl_s(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "round.l.s"; + break; + case FOP(9, 16): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_truncl_s(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "trunc.l.s"; + break; + case FOP(10, 16): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_ceill_s(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "ceil.l.s"; + break; + case FOP(11, 16): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_floorl_s(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "floor.l.s"; + break; + case FOP(12, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_roundw_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "round.w.s"; + break; + case FOP(13, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_truncw_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "trunc.w.s"; + break; + case FOP(14, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_ceilw_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "ceil.w.s"; + break; + case FOP(15, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_floorw_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "floor.w.s"; + break; + case FOP(17, 16): + GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "movcf.s"; + break; + case FOP(18, 16): + GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + gen_op_float_movz_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "movz.s"; + break; + case FOP(19, 16): + GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + gen_op_float_movn_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "movn.s"; + break; + case FOP(33, 16): + CHECK_FR(ctx, fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvtd_s(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "cvt.d.s"; + break; + case FOP(36, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvtw_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "cvt.w.s"; + break; + case FOP(37, 16): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvtl_s(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "cvt.l.s"; + break; + case FOP(38, 16): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WT1, fs); + GEN_LOAD_FREG_FTN(WT0, ft); + gen_op_float_cvtps_s(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "cvt.ps.s"; + break; + case FOP(48, 16): + case FOP(49, 16): + case FOP(50, 16): + case FOP(51, 16): + case FOP(52, 16): + case FOP(53, 16): + case FOP(54, 16): + case FOP(55, 16): + case FOP(56, 16): + case FOP(57, 16): + case FOP(58, 16): + case FOP(59, 16): + case FOP(60, 16): + case FOP(61, 16): + case FOP(62, 16): + case FOP(63, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_cmp_s(func-48, cc); + opn = condnames[func-48]; + break; case FOP(0, 17): CHECK_FR(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); @@ -4424,10 +4707,34 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) GEN_STORE_FTN_FREG(fd, DT2); opn = "neg.d"; break; - /* 8 - round.l */ - /* 9 - trunc.l */ - /* 10 - ceil.l */ - /* 11 - floor.l */ + case FOP(8, 17): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_roundl_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "round.l.d"; + break; + case FOP(9, 17): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_truncl_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "trunc.l.d"; + break; + case FOP(10, 17): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_ceill_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "ceil.l.d"; + break; + case FOP(11, 17): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_floorl_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "floor.l.d"; + break; case FOP(12, 17): CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); @@ -4456,19 +4763,29 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) GEN_STORE_FTN_FREG(fd, WT2); opn = "floor.w.d"; break; - case FOP(33, 16): - CHECK_FR(ctx, fd); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtd_s(); + case FOP(17, 17): + GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT2, fd); + gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1); GEN_STORE_FTN_FREG(fd, DT2); - opn = "cvt.d.s"; + opn = "movcf.d"; break; - case FOP(33, 20): - CHECK_FR(ctx, fd); - GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtd_w(); + case FOP(18, 17): + GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT2, fd); + gen_op_float_movz_d(); GEN_STORE_FTN_FREG(fd, DT2); - opn = "cvt.d.w"; + opn = "movz.d"; + break; + case FOP(19, 17): + GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT2, fd); + gen_op_float_movn_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "movn.d"; break; case FOP(48, 17): case FOP(49, 17): @@ -4489,125 +4806,240 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) CHECK_FR(ctx, fs | ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); - gen_cmp_d(func-48); + gen_cmp_d(func-48, cc); opn = condnames[func-48]; break; - case FOP(0, 16): + case FOP(32, 17): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_cvts_d(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "cvt.s.d"; + break; + case FOP(36, 17): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_cvtw_d(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "cvt.w.d"; + break; + case FOP(37, 17): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_cvtl_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "cvt.l.d"; + break; + case FOP(32, 20): GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_add_s(); + gen_op_float_cvts_w(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "add.s"; - binary = 1; + opn = "cvt.s.w"; break; - case FOP(1, 16): + case FOP(33, 20): + CHECK_FR(ctx, fd); GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_cvtd_w(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "cvt.d.w"; + break; + case FOP(32, 21): + CHECK_FR(ctx, fs); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_cvts_l(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "cvt.s.l"; + break; + case FOP(33, 21): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_cvtd_l(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "cvt.d.l"; + break; + case FOP(38, 20): + case FOP(38, 21): + CHECK_FR(ctx, fs | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_float_cvtps_pw(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "cvt.ps.pw"; + break; + case FOP(0, 22): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_sub_s(); + GEN_LOAD_FREG_FTN(WTH1, ft); + gen_op_float_add_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "sub.s"; - binary = 1; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "add.ps"; break; - case FOP(2, 16): + case FOP(1, 22): + CHECK_FR(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_mul_s(); + GEN_LOAD_FREG_FTN(WTH1, ft); + gen_op_float_sub_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "mul.s"; - binary = 1; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "sub.ps"; break; - case FOP(3, 16): + case FOP(2, 22): + CHECK_FR(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); - gen_op_float_div_s(); + GEN_LOAD_FREG_FTN(WTH1, ft); + gen_op_float_mul_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "div.s"; - binary = 1; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "mul.ps"; break; - case FOP(4, 16): + case FOP(5, 22): + CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_sqrt_s(); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_float_abs_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "sqrt.s"; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "abs.ps"; break; - case FOP(5, 16): + case FOP(6, 22): + CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_abs_s(); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_float_mov_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "abs.s"; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "mov.ps"; break; - case FOP(6, 16): + case FOP(7, 22): + CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_mov_s(); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_float_chs_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "mov.s"; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "neg.ps"; break; - case FOP(7, 16): + case FOP(17, 22): + GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_chs_s(); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + GEN_LOAD_FREG_FTN(WTH2, fd); + gen_movcf_ps(ctx, (ft >> 2) & 0x7, ft & 0x1); GEN_STORE_FTN_FREG(fd, WT2); - opn = "neg.s"; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "movcf.ps"; break; - case FOP(12, 16): + case FOP(18, 22): + GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_roundw_s(); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + GEN_LOAD_FREG_FTN(WTH2, fd); + gen_op_float_movz_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "round.w.s"; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "movz.ps"; break; - case FOP(13, 16): + case FOP(19, 22): + GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_truncw_s(); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + GEN_LOAD_FREG_FTN(WTH2, fd); + gen_op_float_movn_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "trunc.w.s"; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "movn.ps"; break; - case FOP(32, 17): + case FOP(32, 22): CHECK_FR(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvts_d(); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_float_cvts_pu(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "cvt.s.d"; + opn = "cvt.s.pu"; break; - case FOP(32, 20): + case FOP(36, 22): + CHECK_FR(ctx, fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvts_w(); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_float_cvtpw_ps(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "cvt.s.w"; + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "cvt.pw.ps"; break; - case FOP(36, 16): + case FOP(40, 22): + CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(WT0, fs); - gen_op_float_cvtw_s(); + gen_op_float_cvts_pl(); GEN_STORE_FTN_FREG(fd, WT2); - opn = "cvt.w.s"; + opn = "cvt.s.pl"; break; - case FOP(36, 17): - CHECK_FR(ctx, fs); - GEN_LOAD_FREG_FTN(DT0, fs); - gen_op_float_cvtw_d(); - GEN_STORE_FTN_FREG(fd, WT2); - opn = "cvt.w.d"; + case FOP(44, 22): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + gen_op_float_pll_ps(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "pll.ps"; break; - case FOP(48, 16): - case FOP(49, 16): - case FOP(50, 16): - case FOP(51, 16): - case FOP(52, 16): - case FOP(53, 16): - case FOP(54, 16): - case FOP(55, 16): - case FOP(56, 16): - case FOP(57, 16): - case FOP(58, 16): - case FOP(59, 16): - case FOP(60, 16): - case FOP(61, 16): - case FOP(62, 16): - case FOP(63, 16): + case FOP(45, 22): + CHECK_FR(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH1, ft); + gen_op_float_plu_ps(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "plu.ps"; + break; + case FOP(46, 22): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); - gen_cmp_s(func-48); + gen_op_float_pul_ps(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "pul.ps"; + break; + case FOP(47, 22): + CHECK_FR(ctx, fs | ft | fd); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WTH1, ft); + gen_op_float_puu_ps(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "puu.ps"; + break; + case FOP(48, 22): + case FOP(49, 22): + case FOP(50, 22): + case FOP(51, 22): + case FOP(52, 22): + case FOP(53, 22): + case FOP(54, 22): + case FOP(55, 22): + case FOP(56, 22): + case FOP(57, 22): + case FOP(58, 22): + case FOP(59, 22): + case FOP(60, 22): + case FOP(61, 22): + case FOP(62, 22): + case FOP(63, 22): + CHECK_FR(ctx, fs | ft); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WTH1, ft); + gen_cmp_ps(func-48, cc); opn = condnames[func-48]; break; - default: + default: if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n", ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, @@ -4622,18 +5054,134 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd) MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]); } -static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) +/* Coprocessor 3 (FPU) */ +static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, + int base, int index) { - uint32_t ccbit; + const char *opn = "unk"; - if (cc) - ccbit = 1 << (24 + cc); - else - ccbit = 1 << 23; - if (!tf) - gen_op_movf(ccbit, rd, rs); - else - gen_op_movt(ccbit, rd, rs); + GEN_LOAD_REG_TN(T0, base); + GEN_LOAD_REG_TN(T1, index); + /* Don't do NOP if destination is zero: we must perform the actual + * memory access + */ + switch (opc) { + case OPC_LWXC1: + op_ldst(lwxc1); + GEN_STORE_FTN_FREG(fd, WT0); + opn = "lwxc1"; + break; + case OPC_LDXC1: + op_ldst(ldxc1); + GEN_STORE_FTN_FREG(fd, DT0); + opn = "ldxc1"; + break; + case OPC_LUXC1: + op_ldst(luxc1); + GEN_STORE_FTN_FREG(fd, DT0); + opn = "luxc1"; + break; + case OPC_SWXC1: + GEN_LOAD_FREG_FTN(WT0, fd); + op_ldst(swxc1); + opn = "swxc1"; + break; + case OPC_SDXC1: + GEN_LOAD_FREG_FTN(DT0, fd); + op_ldst(sdxc1); + opn = "sdxc1"; + break; + case OPC_SUXC1: + GEN_LOAD_FREG_FTN(DT0, fd); + op_ldst(suxc1); + opn = "suxc1"; + break; + default: + MIPS_INVAL("extended float load/store"); + generate_exception(ctx, EXCP_RI); + return; + } + MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[fd],regnames[index], regnames[base]); +} + +static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, + int fr, int fs, int ft) +{ + const char *opn = "unk"; + + /* All of those work only on 64bit FPUs. */ + CHECK_FR(ctx, fd | fr | fs | ft); + switch (opc) { + case OPC_ALNV_PS: + GEN_LOAD_REG_TN(T0, fr); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + gen_op_float_alnv_ps(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "alnv.ps"; + break; + case OPC_MADD_S: + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WT2, fr); + gen_op_float_muladd_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "madd.s"; + break; + case OPC_MADD_D: + generate_exception (ctx, EXCP_RI); + opn = "madd.d"; + break; + case OPC_MADD_PS: + generate_exception (ctx, EXCP_RI); + opn = "madd.ps"; + break; + case OPC_MSUB_S: + generate_exception (ctx, EXCP_RI); + opn = "msub.s"; + break; + case OPC_MSUB_D: + generate_exception (ctx, EXCP_RI); + opn = "msub.d"; + break; + case OPC_MSUB_PS: + generate_exception (ctx, EXCP_RI); + opn = "msub.ps"; + break; + case OPC_NMADD_S: + generate_exception (ctx, EXCP_RI); + opn = "nmadd.s"; + break; + case OPC_NMADD_D: + generate_exception (ctx, EXCP_RI); + opn = "nmadd.d"; + break; + case OPC_NMADD_PS: + generate_exception (ctx, EXCP_RI); + opn = "nmadd.ps"; + break; + case OPC_NMSUB_S: + generate_exception (ctx, EXCP_RI); + opn = "nmsub.s"; + break; + case OPC_NMSUB_D: + generate_exception (ctx, EXCP_RI); + opn = "nmsub.d"; + break; + case OPC_NMSUB_PS: + generate_exception (ctx, EXCP_RI); + opn = "nmsub.ps"; + break; + default: + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "Invalid extended FP arith function: %08x %03x %03x\n", + ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F); + } + generate_exception (ctx, EXCP_RI); + return; + } + MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr], + fregnames[fs], fregnames[ft]); } /* ISA extensions (ASEs) */ @@ -4641,23 +5189,12 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) /* SmartMIPS extension to MIPS32 */ #ifdef TARGET_MIPS64 -/* Coprocessor 3 (FPU) */ /* MDMX extension to MIPS64 */ /* MIPS-3D extension to MIPS64 */ #endif -static void gen_blikely(DisasContext *ctx) -{ - int l1; - l1 = gen_new_label(); - gen_op_jnz_T2(l1); - gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); - gen_goto_tb(ctx, 1, ctx->pc + 4); - gen_set_label(l1); -} - static void decode_opc (CPUState *env, DisasContext *ctx) { int32_t offset; @@ -4673,9 +5210,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) { + int l1; /* Handle blikely not taken case */ MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4); - gen_blikely(ctx); + l1 = gen_new_label(); + gen_op_jnz_T2(l1); + gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK); + gen_goto_tb(ctx, 1, ctx->pc + 4); + gen_set_label(l1); } op = MASK_OP_MAJOR(ctx->opcode); rs = (ctx->opcode >> 21) & 0x1f; @@ -5024,16 +5566,21 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_DMFC1: case OPC_DMTC1: #endif + case OPC_MFHC1: + case OPC_MTHC1: gen_cp1(ctx, op1, rt, rd); break; case OPC_BC1: - gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2); + gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), + (rt >> 2) & 0x7, imm << 2); return; case OPC_S_FMT: case OPC_D_FMT: case OPC_W_FMT: case OPC_L_FMT: - gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa); + case OPC_PS_FMT: + gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa, + (imm >> 8) & 0x7); break; default: generate_exception (ctx, EXCP_RI); @@ -5060,10 +5607,32 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_op_cp1_enabled(); op1 = MASK_CP3(ctx->opcode); switch (op1) { + case OPC_LWXC1: + case OPC_LDXC1: + case OPC_LUXC1: + case OPC_SWXC1: + case OPC_SDXC1: + case OPC_SUXC1: + gen_flt3_ldst(ctx, op1, sa, rs, rt); + break; case OPC_PREFX: /* treat as noop */ break; - /* Not implemented */ + case OPC_ALNV_PS: + case OPC_MADD_S: + case OPC_MADD_D: + case OPC_MADD_PS: + case OPC_MSUB_S: + case OPC_MSUB_D: + case OPC_MSUB_PS: + case OPC_NMADD_S: + case OPC_NMADD_D: + case OPC_NMADD_PS: + case OPC_NMSUB_S: + case OPC_NMSUB_D: + case OPC_NMSUB_PS: + gen_flt3_arith(ctx, op1, sa, rs, rd, rt); + break; default: generate_exception (ctx, EXCP_RI); break; @@ -5107,7 +5676,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) ctx->hflags &= ~MIPS_HFLAG_BMASK; ctx->bstate = BS_BRANCH; save_cpu_state(ctx, 0); - switch (hflags & MIPS_HFLAG_BMASK) { + switch (hflags) { case MIPS_HFLAG_B: /* unconditional branch */ MIPS_DEBUG("unconditional branch"); @@ -5134,6 +5703,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) /* unconditional branch to register */ MIPS_DEBUG("branch to register"); gen_op_breg(); + gen_op_reset_T0(); + gen_op_exit_tb(); break; default: MIPS_DEBUG("unknown branch"); @@ -5166,16 +5737,18 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, /* Restore delay slot state from the tb context. */ ctx.hflags = tb->flags; ctx.saved_hflags = ctx.hflags; - if (ctx.hflags & MIPS_HFLAG_BR) { + switch (ctx.hflags & MIPS_HFLAG_BMASK) { + case MIPS_HFLAG_BR: gen_op_restore_breg_target(); - } else if (ctx.hflags & MIPS_HFLAG_B) { + break; + case MIPS_HFLAG_B: ctx.btarget = env->btarget; - } else if (ctx.hflags & MIPS_HFLAG_BMASK) { - /* If we are in the delay slot of a conditional branch, - * restore the branch condition from env->bcond to T2 - */ + break; + case MIPS_HFLAG_BC: + case MIPS_HFLAG_BL: ctx.btarget = env->btarget; gen_op_restore_bcond(); + break; } #if defined(CONFIG_USER_ONLY) ctx.mem_idx = 0; @@ -5237,12 +5810,6 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_op_debug(); } else { switch (ctx.bstate) { - case BS_EXCP: - gen_op_interrupt_restart(); - gen_op_reset_T0(); - /* Generate the return instruction. */ - gen_op_exit_tb(); - break; case BS_STOP: gen_op_interrupt_restart(); /* Fall through. */ @@ -5250,12 +5817,14 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, save_cpu_state(ctxp, 0); gen_goto_tb(&ctx, 0, ctx.pc); break; - case BS_BRANCH: - default: + case BS_EXCP: + gen_op_interrupt_restart(); gen_op_reset_T0(); - /* Generate the return instruction. */ gen_op_exit_tb(); break; + case BS_BRANCH: + default: + break; } } done_generating: @@ -5307,21 +5876,33 @@ void fpu_dump_state(CPUState *env, FILE *f, int flags) { int i; - -# define printfpr(fp) do { \ - fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \ - (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \ + int is_fpu64 = !!(env->CP0_Status & (1 << CP0St_FR)); + +#define printfpr(fp) \ + do { \ + if (is_fpu64) \ + fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu: %13g\n", \ + (fp)->w[FP_ENDIAN_IDX], (fp)->d, (fp)->fd, \ + (fp)->fs[FP_ENDIAN_IDX], (fp)->fs[!FP_ENDIAN_IDX]); \ + else { \ + fpr_t tmp; \ + tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ + tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ + fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu:%13g\n", \ + tmp.w[FP_ENDIAN_IDX], tmp.d, tmp.fd, \ + tmp.fs[FP_ENDIAN_IDX], tmp.fs[!FP_ENDIAN_IDX]); \ + } \ } while(0) - fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n", - env->fcr0, env->fcr31, - (env->CP0_Status & (1 << CP0St_FR)) != 0); + + fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n", + env->fcr0, env->fcr31, is_fpu64, env->fp_status, get_float_exception_flags(&env->fp_status)); fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); - for(i = 0; i < 32; i += 2) { - fpu_fprintf(f, "%s: ", fregnames[i]); - printfpr(FPR(env, i)); + for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { + fpu_fprintf(f, "%3s: ", fregnames[i]); + printfpr(&env->fpr[i]); } #undef printfpr diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 51c571d0e..a166bdd5e 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -55,7 +55,7 @@ /* Define a implementation number of 1. Define a major version 1, minor version 0. */ -#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0) +#define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV)) struct mips_def_t { @@ -69,6 +69,7 @@ struct mips_def_t { int32_t CP0_Config7; int32_t SYNCI_Step; int32_t CCRes; + int32_t Status_rw_bitmask; int32_t CP1_fcr0; }; @@ -86,7 +87,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .CP1_fcr0 = MIPS_FCR0, + .Status_rw_bitmask = 0x3278FF17, }, { .name = "4KEcR1", @@ -97,7 +98,6 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .CP1_fcr0 = MIPS_FCR0, }, { .name = "4KEc", @@ -108,7 +108,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .CP1_fcr0 = MIPS_FCR0, + .Status_rw_bitmask = 0x3278FF17, }, { .name = "24Kc", @@ -119,7 +119,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .CP1_fcr0 = MIPS_FCR0, + .Status_rw_bitmask = 0x3278FF17, }, { .name = "24Kf", @@ -130,7 +130,9 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .CP1_fcr0 = MIPS_FCR0, + .Status_rw_bitmask = 0x3678FF17, + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), }, #else { @@ -142,7 +144,10 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 16, .CCRes = 2, - .CP1_fcr0 = MIPS_FCR0, + .Status_rw_bitmask = 0x3678FFFF, + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + (1 << FCR0_D) | (1 << FCR0_S) | + (0x4 << FCR0_PRID) | (0x0 << FCR0_REV), }, #endif }; @@ -191,6 +196,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_Config7 = def->CP0_Config7; env->SYNCI_Step = def->SYNCI_Step; env->CCRes = def->CCRes; + env->Status_rw_bitmask = def->Status_rw_bitmask; env->fcr0 = def->CP1_fcr0; #if defined (MIPS_USES_R4K_TLB) env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); -- cgit v1.2.3 From 2371aaa295bbbdf4930e481828db5ab636f49aff Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 7 May 2007 17:01:15 +0000 Subject: Fix pc/npc for unaligned load/stores, maybe other exceptions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2780 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 4b8b3d261..c5eefad4e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2776,6 +2776,7 @@ static void disas_sparc_insn(DisasContext * dc) { unsigned int xop = GET_FIELD(insn, 7, 12); rs1 = GET_FIELD(insn, 13, 17); + save_state(dc); gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); -- cgit v1.2.3 From 64ddcd797a06a4598e0f5fe77aa82f7a11ef5695 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 7 May 2007 17:59:32 +0000 Subject: Update OpenBIOS/Sparc32 to SVN 144. Changes: - Fix power-management location - Fix out of bounds accesses - Increase virtual memory supply to meet NetBSD and OpenBSD demand - More obviously alarming return values for find_pte - Fix unaligned memory access - Fix memory corruption problems reported by glibc - Fix boot-device use - Use nvram boot-args and boot-device variables - Set variable defaults before nvram_init - Improve escape sequence handling - Fix nvram parameter area - More Sparc32 CPUs - Clear preloaded kernel parameters to avoid crash at reset git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2781 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 2 +- pc-bios/openbios-sparc32 | Bin 252444 -> 268852 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/README b/pc-bios/README index 2b03d619e..3360f9f37 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,7 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 image is built from SVN version 131 and Sparc64 + The included Sparc32 image is built from SVN version 144 and Sparc64 image from version 125. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 1b246eeed..6be9400c4 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ -- cgit v1.2.3 From 945545501641bad0b650350168e365eff9a3eef3 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 7 May 2007 18:05:05 +0000 Subject: Enable unaligned access faults git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2782 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 2edc8d741..4349503ff 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -2,6 +2,7 @@ //#define DEBUG_PCALL //#define DEBUG_MMU +//#define DEBUG_UNALIGNED void raise_exception(int tt) { @@ -945,10 +946,10 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user, static void do_unaligned_access(target_ulong addr, int is_write, int is_user, void *retaddr) { - /* Uncomment the following line to enable mem_address_not_aligned traps */ - /* Not enabled yet because of bugs in OpenBIOS */ - //raise_exception(TT_UNALIGNED); - //printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc); +#ifdef DEBUG_UNALIGNED + printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc); +#endif + raise_exception(TT_UNALIGNED); } /* try to fill the TLB and return an exception if error. If retaddr is -- cgit v1.2.3 From ce8198612e08f737057d9984a9fa1bf18af8ce4b Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 8 May 2007 02:30:40 +0000 Subject: ARM946 CPU support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2783 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx.c | 2 +- qemu-doc.texi | 4 +- target-arm/cpu.h | 12 ++- target-arm/helper.c | 250 +++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 221 insertions(+), 47 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 43d40c7fd..9f4c46c68 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -251,7 +251,7 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; s->env->cp15.c1_sys = 0; s->env->cp15.c1_coproc = 0; - s->env->cp15.c2 = 0; + s->env->cp15.c2_base = 0; s->env->cp15.c3 = 0; s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ diff --git a/qemu-doc.texi b/qemu-doc.texi index b1afb95f6..95e7de261 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -77,7 +77,7 @@ For system emulation, the following hardware targets are supported: @item Sun4m (32-bit Sparc processor) @item Sun4u (64-bit Sparc processor, in progress) @item Malta board (32-bit MIPS processor) -@item ARM Integrator/CP (ARM926E or 1026E processor) +@item ARM Integrator/CP (ARM926E, 1026E or 946E processor) @item ARM Versatile baseboard (ARM926E) @item ARM RealView Emulation baseboard (ARM926EJ-S) @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) @@ -1722,7 +1722,7 @@ devices: @itemize @minus @item -ARM926E or ARM1026E CPU +ARM926E, ARM1026E or ARM946E CPU @item Two PL011 UARTs @item diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 09083b723..472380762 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -83,10 +83,14 @@ typedef struct CPUARMState { uint32_t c0_cachetype; uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ - uint32_t c2; /* MMU translation table base. */ - uint32_t c3; /* MMU domain access control register. */ + uint32_t c2_base; /* MMU translation table base. */ + uint32_t c2_data; /* MPU data cachable bits. */ + uint32_t c2_insn; /* MPU instruction cachable bits. */ + uint32_t c3; /* MMU domain access control register + MPU write buffer control. */ uint32_t c5_insn; /* Fault status registers. */ uint32_t c5_data; + uint32_t c6_region[8]; /* MPU base/size registers. */ uint32_t c6_insn; /* Fault address registers. */ uint32_t c6_data; uint32_t c9_insn; /* Cache lockdown registers. */ @@ -241,7 +245,8 @@ enum arm_features { ARM_FEATURE_VFP, ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ - ARM_FEATURE_IWMMXT /* Intel iwMMXt extension. */ + ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */ + ARM_FEATURE_MPU /* Only has Memory Protection Unit, not full MMU. */ }; static inline int arm_feature(CPUARMState *env, int feature) @@ -258,6 +263,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define ARM_CPUID_ARM1026 0x4106a262 #define ARM_CPUID_ARM926 0x41069265 +#define ARM_CPUID_ARM946 0x41059461 #define ARM_CPUID_PXA250 0x69052100 #define ARM_CPUID_PXA255 0x69052d00 #define ARM_CPUID_PXA260 0x69052903 diff --git a/target-arm/helper.c b/target-arm/helper.c index 8526883fb..e8a216975 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -19,6 +19,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; env->cp15.c0_cachetype = 0x1dd20d2; break; + case ARM_CPUID_ARM946: + set_feature(env, ARM_FEATURE_MPU); + env->cp15.c0_cachetype = 0x0f004006; + break; case ARM_CPUID_ARM1026: set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); @@ -90,6 +94,7 @@ struct arm_cpu_t { static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_ARM926, "arm926"}, + { ARM_CPUID_ARM946, "arm946"}, { ARM_CPUID_ARM1026, "arm1026"}, { ARM_CPUID_PXA250, "pxa250" }, { ARM_CPUID_PXA255, "pxa255" }, @@ -392,13 +397,67 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, address += env->cp15.c13_fcse; if ((env->cp15.c1_sys & 1) == 0) { - /* MMU diusabled. */ + /* MMU/MPU disabled. */ *phys_ptr = address; *prot = PAGE_READ | PAGE_WRITE; + } else if (arm_feature(env, ARM_FEATURE_MPU)) { + int n; + uint32_t mask; + uint32_t base; + + *phys_ptr = address; + for (n = 7; n >= 0; n--) { + base = env->cp15.c6_region[n]; + if ((base & 1) == 0) + continue; + mask = 1 << ((base >> 1) & 0x1f); + /* Keep this shift separate from the above to avoid an + (undefined) << 32. */ + mask = (mask << 1) - 1; + if (((base ^ address) & ~mask) == 0) + break; + } + if (n < 0) + return 2; + + if (access_type == 2) { + mask = env->cp15.c5_insn; + } else { + mask = env->cp15.c5_data; + } + mask = (mask >> (n * 4)) & 0xf; + switch (mask) { + case 0: + return 1; + case 1: + if (is_user) + return 1; + *prot = PAGE_READ | PAGE_WRITE; + break; + case 2: + *prot = PAGE_READ; + if (!is_user) + *prot |= PAGE_WRITE; + break; + case 3: + *prot = PAGE_READ | PAGE_WRITE; + break; + case 5: + if (is_user) + return 1; + *prot = PAGE_READ; + break; + case 6: + *prot = PAGE_READ; + break; + default: + /* Bad permission. */ + return 1; + } } else { /* Pagetable walk. */ /* Lookup l1 descriptor. */ - table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); + table = (env->cp15.c2_base & 0xffffc000) | ((address >> 18) & 0x3ffc); desc = ldl_phys(table); type = (desc & 3); domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; @@ -539,18 +598,50 @@ uint32_t helper_get_cp(CPUState *env, uint32_t insn) return 0; } +/* Return basic MPU access permission bits. */ +static uint32_t simple_mpu_ap_bits(uint32_t val) +{ + uint32_t ret; + uint32_t mask; + int i; + ret = 0; + mask = 3; + for (i = 0; i < 16; i += 2) { + ret |= (val >> i) & mask; + mask <<= 2; + } + return ret; +} + +/* Pad basic MPU access permission bits to extended format. */ +static uint32_t extended_mpu_ap_bits(uint32_t val) +{ + uint32_t ret; + uint32_t mask; + int i; + ret = 0; + mask = 3; + for (i = 0; i < 16; i += 2) { + ret |= (val & mask) << i; + mask <<= 2; + } + return ret; +} + void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) { uint32_t op2; + uint32_t crm; op2 = (insn >> 5) & 7; + crm = insn & 0xf; switch ((insn >> 16) & 0xf) { case 0: /* ID codes. */ goto bad_reg; case 1: /* System configuration. */ switch (op2) { case 0: - if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0xf) == 0) + if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0) env->cp15.c1_sys = val; /* ??? Lots of these bits are not implemented. */ /* This may enable/disable the MMU, so do a TLB flush. */ @@ -571,38 +662,71 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) goto bad_reg; } break; - case 2: /* MMU Page table control. */ - env->cp15.c2 = val; + case 2: /* MMU Page table control / MPU cache control. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + switch (op2) { + case 0: + env->cp15.c2_data = val; + break; + case 1: + env->cp15.c2_insn = val; + break; + default: + goto bad_reg; + } + } else { + env->cp15.c2_base = val; + } break; - case 3: /* MMU Domain access control. */ + case 3: /* MMU Domain access control / MPU write buffer control. */ env->cp15.c3 = val; break; case 4: /* Reserved. */ goto bad_reg; - case 5: /* MMU Fault status. */ + case 5: /* MMU Fault status / MPU access permission. */ switch (op2) { case 0: + if (arm_feature(env, ARM_FEATURE_MPU)) + val = extended_mpu_ap_bits(val); env->cp15.c5_data = val; break; case 1: + if (arm_feature(env, ARM_FEATURE_MPU)) + val = extended_mpu_ap_bits(val); env->cp15.c5_insn = val; break; - default: - goto bad_reg; - } - break; - case 6: /* MMU Fault address. */ - switch (op2) { - case 0: - env->cp15.c6_data = val; + case 2: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + env->cp15.c5_data = val; break; - case 1: - env->cp15.c6_insn = val; + case 3: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + env->cp15.c5_insn = val; break; default: goto bad_reg; } break; + case 6: /* MMU Fault address / MPU base/size. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + if (crm >= 8) + goto bad_reg; + env->cp15.c6_region[crm] = val; + } else { + switch (op2) { + case 0: + env->cp15.c6_data = val; + break; + case 1: + env->cp15.c6_insn = val; + break; + default: + goto bad_reg; + } + } + break; case 7: /* Cache control. */ /* No cache, so nothing to do. */ break; @@ -629,14 +753,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) goto bad_reg; } break; - case 9: /* Cache lockdown. */ - switch (op2) { - case 0: - env->cp15.c9_data = val; - break; - case 1: - env->cp15.c9_insn = val; + case 9: + switch (crm) { + case 0: /* Cache lockdown. */ + switch (op2) { + case 0: + env->cp15.c9_data = val; + break; + case 1: + env->cp15.c9_insn = val; + break; + default: + goto bad_reg; + } break; + case 1: /* TCM memory region registers. */ + /* Not implemented. */ + goto bad_reg; default: goto bad_reg; } @@ -644,12 +777,13 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 10: /* MMU TLB lockdown. */ /* ??? TLB lockdown not implemented. */ break; - case 11: /* TCM DMA control. */ case 12: /* Reserved. */ goto bad_reg; case 13: /* Process ID. */ switch (op2) { case 0: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; /* Unlike real hardware the qemu TLB uses virtual addresses, not modified virtual addresses, so this causes a TLB flush. */ @@ -659,7 +793,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) break; case 1: /* This changes the ASID, so do a TLB flush. */ - if (env->cp15.c13_context != val) + if (env->cp15.c13_context != val + && !arm_feature(env, ARM_FEATURE_MPU)) tlb_flush(env, 0); env->cp15.c13_context = val; break; @@ -671,7 +806,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) goto bad_reg; case 15: /* Implementation specific. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { - if (op2 == 0 && (insn & 0xf) == 1) { + if (op2 == 0 && crm == 1) { /* Changes cp0 to cp13 behavior, so needs a TB flush. */ tb_flush(env); env->cp15.c15_cpar = (val & 0x3fff) | 2; @@ -717,31 +852,64 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) default: goto bad_reg; } - case 2: /* MMU Page table control. */ - return env->cp15.c2; - case 3: /* MMU Domain access control. */ + case 2: /* MMU Page table control / MPU cache control. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + switch (op2) { + case 0: + return env->cp15.c2_data; + break; + case 1: + return env->cp15.c2_insn; + break; + default: + goto bad_reg; + } + } else { + return env->cp15.c2_base; + } + case 3: /* MMU Domain access control / MPU write buffer control. */ return env->cp15.c3; case 4: /* Reserved. */ goto bad_reg; - case 5: /* MMU Fault status. */ + case 5: /* MMU Fault status / MPU access permission. */ switch (op2) { case 0: + if (arm_feature(env, ARM_FEATURE_MPU)) + return simple_mpu_ap_bits(env->cp15.c5_data); return env->cp15.c5_data; case 1: + if (arm_feature(env, ARM_FEATURE_MPU)) + return simple_mpu_ap_bits(env->cp15.c5_data); + return env->cp15.c5_insn; + case 2: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; + return env->cp15.c5_data; + case 3: + if (!arm_feature(env, ARM_FEATURE_MPU)) + goto bad_reg; return env->cp15.c5_insn; default: goto bad_reg; } - case 6: /* MMU Fault address. */ - switch (op2) { - case 0: - return env->cp15.c6_data; - case 1: - /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't - do any harm. */ - return env->cp15.c6_insn; - default: - goto bad_reg; + case 6: /* MMU Fault address / MPU base/size. */ + if (arm_feature(env, ARM_FEATURE_MPU)) { + int n; + n = (insn & 0xf); + if (n >= 8) + goto bad_reg; + return env->cp15.c6_region[n]; + } else { + switch (op2) { + case 0: + return env->cp15.c6_data; + case 1: + /* Arm9 doesn't have an IFAR, but implementing it anyway + shouldn't do any harm. */ + return env->cp15.c6_insn; + default: + goto bad_reg; + } } case 7: /* Cache control. */ /* ??? This is for test, clean and invaidate operations that set the -- cgit v1.2.3 From d95b2f8d365a3ef431111e9188d219de1f577a90 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 8 May 2007 19:03:12 +0000 Subject: Switch to qemu_ram_alloc() for memory allocation in PXA255/270. Pass correct RAM size to arm_load_kernel (currently unused) - thanks to BobOfDoom. Register the Xscale Internal Memory Storage. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2784 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa.h | 8 +++++--- hw/pxa2xx.c | 18 ++++++++++++++++-- hw/pxa2xx_lcd.c | 12 ++++++------ hw/spitz.c | 16 ++++++++-------- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/hw/pxa.h b/hw/pxa.h index d6d87c62b..28cc1798b 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -57,7 +57,8 @@ # define PXA2XX_RX_RQ_SSP3 66 # define PXA2XX_TX_RQ_SSP3 67 -# define PXA2XX_RAM_BASE 0xa0000000 +# define PXA2XX_SDRAM_BASE 0xa0000000 +# define PXA2XX_INTERNAL_BASE 0x5c000000 /* pxa2xx_pic.c */ struct pxa2xx_pic_state_s; @@ -200,8 +201,9 @@ struct pxa2xx_i2s_s { # define PA_FMT "0x%08lx" # define REG_FMT "0x%lx" -struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision); -struct pxa2xx_state_s *pxa255_init(DisplayState *ds); +struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, DisplayState *ds, + const char *revision); +struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, DisplayState *ds); void pxa2xx_reset(int line, int level, void *opaque); diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 9f4c46c68..19494b88b 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1515,7 +1515,8 @@ void pxa2xx_reset(int line, int level, void *opaque) } /* Initialise a PXA270 integrated chip (ARM based core). */ -struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) +struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, + DisplayState *ds, const char *revision) { struct pxa2xx_state_s *s; struct pxa2xx_ssp_s *ssp; @@ -1530,6 +1531,12 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) s->env = cpu_init(); cpu_arm_set_model(s->env, revision ?: "pxa270"); + /* SDRAM & Internal Memory Storage */ + cpu_register_physical_memory(PXA2XX_SDRAM_BASE, + sdram_size, qemu_ram_alloc(sdram_size) | IO_MEM_RAM); + cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, + 0x40000, qemu_ram_alloc(0x40000) | IO_MEM_RAM); + s->pic = pxa2xx_pic_init(0x40d00000, s->env); s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); @@ -1613,7 +1620,8 @@ struct pxa2xx_state_s *pxa270_init(DisplayState *ds, const char *revision) } /* Initialise a PXA255 integrated chip (ARM based core). */ -struct pxa2xx_state_s *pxa255_init(DisplayState *ds) +struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, + DisplayState *ds) { struct pxa2xx_state_s *s; struct pxa2xx_ssp_s *ssp; @@ -1623,6 +1631,12 @@ struct pxa2xx_state_s *pxa255_init(DisplayState *ds) s->env = cpu_init(); cpu_arm_set_model(s->env, "pxa255"); + /* SDRAM & Internal Memory Storage */ + cpu_register_physical_memory(PXA2XX_SDRAM_BASE, + sdram_size, qemu_ram_alloc(sdram_size) | IO_MEM_RAM); + cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, + 0x40000, qemu_ram_alloc(0x40000) | IO_MEM_RAM); + s->pic = pxa2xx_pic_init(0x40d00000, s->env); s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index a599dd768..a594e278f 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -300,11 +300,11 @@ static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s) } else descptr = s->dma_ch[i].descriptor; - if (!(descptr >= PXA2XX_RAM_BASE && descptr + - sizeof(*desc[i]) <= PXA2XX_RAM_BASE + phys_ram_size)) + if (!(descptr >= PXA2XX_SDRAM_BASE && descptr + + sizeof(*desc[i]) <= PXA2XX_SDRAM_BASE + phys_ram_size)) continue; - descptr -= PXA2XX_RAM_BASE; + descptr -= PXA2XX_SDRAM_BASE; desc[i] = (struct pxa_frame_descriptor_s *) (phys_ram_base + descptr); s->dma_ch[i].descriptor = desc[i]->fdaddr; s->dma_ch[i].source = desc[i]->fsaddr; @@ -855,12 +855,12 @@ static void pxa2xx_update_display(void *opaque) continue; } fbptr = s->dma_ch[ch].source; - if (!(fbptr >= PXA2XX_RAM_BASE && - fbptr <= PXA2XX_RAM_BASE + phys_ram_size)) { + if (!(fbptr >= PXA2XX_SDRAM_BASE && + fbptr <= PXA2XX_SDRAM_BASE + phys_ram_size)) { pxa2xx_dma_ber_set(s, ch); continue; } - fbptr -= PXA2XX_RAM_BASE; + fbptr -= PXA2XX_SDRAM_BASE; fb = phys_ram_base + fbptr; if (s->dma_ch[ch].command & LDCMD_PAL) { diff --git a/hw/spitz.c b/hw/spitz.c index 4b0f18e77..aecace007 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1001,19 +1001,19 @@ static void spitz_common_init(int ram_size, int vga_ram_size, if (!cpu_model) cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; - cpu = pxa270_init(ds, cpu_model); - /* Setup memory */ + /* Setup CPU & memory */ if (ram_size < spitz_ram + spitz_rom) { fprintf(stderr, "This platform requires %i bytes of memory\n", spitz_ram + spitz_rom); exit(1); } - cpu_register_physical_memory(PXA2XX_RAM_BASE, spitz_ram, IO_MEM_RAM); + cpu = pxa270_init(spitz_ram, ds, cpu_model); sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M); - cpu_register_physical_memory(0, spitz_rom, spitz_ram | IO_MEM_ROM); + cpu_register_physical_memory(0, spitz_rom, + qemu_ram_alloc(spitz_rom) | IO_MEM_ROM); /* Setup peripherals */ spitz_keyboard_register(cpu); @@ -1034,11 +1034,11 @@ static void spitz_common_init(int ram_size, int vga_ram_size, spitz_microdrive_attach(cpu); /* Setup initial (reset) machine state */ - cpu->env->regs[15] = PXA2XX_RAM_BASE; + cpu->env->regs[15] = PXA2XX_SDRAM_BASE; - arm_load_kernel(cpu->env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, arm_id, PXA2XX_RAM_BASE); - sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_RAM_BASE); + arm_load_kernel(cpu->env, spitz_ram, kernel_filename, kernel_cmdline, + initrd_filename, arm_id, PXA2XX_SDRAM_BASE); + sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE); } static void spitz_init(int ram_size, int vga_ram_size, int boot_device, -- cgit v1.2.3 From 565d28951e971abf342fcc8701861163b7421f23 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 8 May 2007 19:20:04 +0000 Subject: Set OOK when OON is set in OSCC register (thanks to BobOfDoom). Correct a fatal typo in timer code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2785 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx.c | 4 +++- hw/pxa2xx_timer.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 19494b88b..eb8bd15df 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -168,8 +168,10 @@ static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr, break; case OSCC: - s->cm_regs[addr >> 2] &= ~0x6e; + s->cm_regs[addr >> 2] &= ~0x6c; s->cm_regs[addr >> 2] |= value & 0x6e; + if ((value >> 1) & 1) /* OON */ + s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */ break; default: diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 3ab714932..8c083595c 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -364,7 +364,7 @@ static void pxa2xx_timer_tick4(void *opaque) struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque; pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info; - pxa2xx_timer_tick4(opaque); + pxa2xx_timer_tick(opaque); if (t->control & (1 << 3)) t->clock = 0; if (t->control & (1 << 6)) -- cgit v1.2.3 From 09c69c5b23e904bf59608942da15650bf9428921 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 8 May 2007 20:51:26 +0000 Subject: Work around gcc's mips define, spotted by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2786 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 899892f68..aedd7bd84 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1647,22 +1647,22 @@ unsigned int ieee_rm[] = { #define RESTORE_ROUNDING_MODE \ set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) -inline char ieee_ex_to_mips(char ieee) +inline char ieee_ex_to_mips(char xcpt) { - return (ieee & float_flag_inexact) >> 5 | - (ieee & float_flag_underflow) >> 3 | - (ieee & float_flag_overflow) >> 1 | - (ieee & float_flag_divbyzero) << 1 | - (ieee & float_flag_invalid) << 4; + return (xcpt & float_flag_inexact) >> 5 | + (xcpt & float_flag_underflow) >> 3 | + (xcpt & float_flag_overflow) >> 1 | + (xcpt & float_flag_divbyzero) << 1 | + (xcpt & float_flag_invalid) << 4; } -inline char mips_ex_to_ieee(char mips) +inline char mips_ex_to_ieee(char xcpt) { - return (mips & FP_INEXACT) << 5 | - (mips & FP_UNDERFLOW) << 3 | - (mips & FP_OVERFLOW) << 1 | - (mips & FP_DIV0) >> 1 | - (mips & FP_INVALID) >> 4; + return (xcpt & FP_INEXACT) << 5 | + (xcpt & FP_UNDERFLOW) << 3 | + (xcpt & FP_OVERFLOW) << 1 | + (xcpt & FP_DIV0) >> 1 | + (xcpt & FP_INVALID) >> 4; } inline void update_fcr31(void) -- cgit v1.2.3 From e14a693ddaec910888ba2870aab35b5eb8793e5d Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 8 May 2007 20:57:52 +0000 Subject: Silence sdl-config stderr output, by Jeff Chua. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2787 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index e8c8257f6..187ac35a1 100755 --- a/configure +++ b/configure @@ -562,8 +562,8 @@ 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` +`$sdl_config --static-libs 2>/dev/null | grep \\\-laa > /dev/null` && aa="yes" +sdl_static_libs=`$sdl_config --static-libs 2>/dev/null` if [ "$aa" = "yes" ] ; then sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`" fi -- cgit v1.2.3 From 9617efe8e78fe977c8ddbb18d7b14b532ab07c3e Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 8 May 2007 21:05:55 +0000 Subject: Another bunch of mips host support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2788 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++-- cpu-exec.c | 3 ++- dyngen.c | 22 ++++++++++++++++++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Makefile.target b/Makefile.target index 9bb12c2f5..aa99f39cd 100644 --- a/Makefile.target +++ b/Makefile.target @@ -181,7 +181,7 @@ BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif ifeq ($(ARCH),mips) -OP_CFLAGS+=-G 0 -fomit-frame-pointer -fno-delayed-branch +OP_CFLAGS+=-mabi=32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0 ifeq ($(WORDS_BIGENDIAN),yes) BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld else @@ -190,7 +190,7 @@ endif endif ifeq ($(ARCH),mips64) -OP_CFLAGS+=-G 0 -fomit-frame-pointer -fno-delayed-branch +OP_CFLAGS+=-mabi=n32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0 ifeq ($(WORDS_BIGENDIAN),yes) BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld else diff --git a/cpu-exec.c b/cpu-exec.c index cd74412a7..fedabef60 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1545,9 +1545,10 @@ int cpu_signal_handler(int host_signum, void *pinfo, #elif defined(__mips__) -int cpu_signal_handler(int host_signum, struct siginfo *info, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { + siginfo_t *info = pinfo; struct ucontext *uc = puc; greg_t pc = uc->uc_mcontext.pc; int is_write; diff --git a/dyngen.c b/dyngen.c index dd46ea0ca..b8950b11d 100644 --- a/dyngen.c +++ b/dyngen.c @@ -124,6 +124,14 @@ #define elf_check_arch(x) ((x) == EM_MIPS) #define ELF_USES_RELOC +#elif defined(HOST_MIPS64) + +/* Assume n32 ABI here, which is ELF32. */ +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_MIPS +#define elf_check_arch(x) ((x) == EM_MIPS) +#define ELF_USES_RELOCA + #else #error unsupported CPU - please update the code #endif @@ -1648,7 +1656,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, error("rts expected at the end of %s", name); copy_size = p - p_start; } -#elif defined(HOST_MIPS) +#elif defined(HOST_MIPS) || defined(HOST_MIPS64) { #define INSN_RETURN 0x03e00008 #define INSN_NOP 0x00000000 @@ -2510,7 +2518,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } -#elif defined(HOST_MIPS) +#elif defined(HOST_MIPS) || defined(HOST_MIPS64) { for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { @@ -2528,6 +2536,16 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, addend = get32((uint32_t *)(text + rel->r_offset)); reloc_offset = rel->r_offset - start_offset; switch (type) { + case R_MIPS_26: + fprintf(outfile, " /* R_MIPS_26 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "(0x%x & ~0x3fffff) " + "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) " + " & 0x3fffff);\n", + reloc_offset, addend, addend, name, reloc_offset); + break; case R_MIPS_HI16: fprintf(outfile, " /* R_MIPS_HI16 RELOC, offset 0x%x, name %s */\n", rel->r_offset, sym_name); -- cgit v1.2.3 From 3bdd58a4dfaf284868e7b34f29ae74c60ad23ac9 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 8 May 2007 22:51:00 +0000 Subject: Correct the number of PXA255 GPIO lines. Reuse the PXA timers struct for PXA27x additional timers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2789 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx.c | 2 +- hw/pxa2xx_timer.c | 37 ++++++++++++++++--------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index eb8bd15df..4661011d7 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1645,7 +1645,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0], s->env); - s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); + s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85); s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma); diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 8c083595c..fe55ce0bd 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -66,12 +66,7 @@ struct pxa2xx_timer0_s { }; struct pxa2xx_timer4_s { - uint32_t value; - int level; - qemu_irq irq; - QEMUTimer *qtimer; - int num; - void *info; + struct pxa2xx_timer0_s tm; int32_t oldclock; int32_t clock; uint64_t lastload; @@ -134,7 +129,7 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) s->tm4[counter].lastload, s->tm4[counter].freq, ticks_per_sec); - new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].value - now_vm), + new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), ticks_per_sec, s->tm4[counter].freq); qemu_mod_timer(s->timer[n].qtimer, new_qemu); } @@ -162,7 +157,7 @@ static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset) case OSMR4: if (!s->tm4) goto badreg; - return s->tm4[tm].value; + return s->tm4[tm].tm.value; case OSCR: return s->clock + muldiv64(qemu_get_clock(vm_clock) - s->lastload, s->freq, ticks_per_sec); @@ -245,7 +240,7 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset, case OSMR4: if (!s->tm4) goto badreg; - s->tm4[tm].value = value; + s->tm4[tm].tm.value = value; pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm); break; case OSCR: @@ -282,10 +277,10 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset, } if (s->tm4) { for (i = 0; i < 8; i ++, value >>= 1) - if (s->tm4[i].level && (value & 1)) - s->tm4[i].level = 0; + if (s->tm4[i].tm.level && (value & 1)) + s->tm4[i].tm.level = 0; if (!(s->events & 0xff0)) - qemu_irq_lower(s->tm4->irq); + qemu_irq_lower(s->tm4->tm.irq); } break; case OWER: /* XXX: Reset on OSMR3 match? */ @@ -362,13 +357,13 @@ static void pxa2xx_timer_tick(void *opaque) static void pxa2xx_timer_tick4(void *opaque) { struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque; - pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info; + pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->tm.info; - pxa2xx_timer_tick(opaque); + pxa2xx_timer_tick(&t->tm); if (t->control & (1 << 3)) t->clock = 0; if (t->control & (1 << 6)) - pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->num - 4); + pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4); } static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, @@ -420,14 +415,14 @@ void pxa27x_timer_init(target_phys_addr_t base, s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 * sizeof(struct pxa2xx_timer4_s)); for (i = 0; i < 8; i ++) { - s->tm4[i].value = 0; - s->tm4[i].irq = irq4; - s->tm4[i].info = s; - s->tm4[i].num = i + 4; - s->tm4[i].level = 0; + s->tm4[i].tm.value = 0; + s->tm4[i].tm.irq = irq4; + s->tm4[i].tm.info = s; + s->tm4[i].tm.num = i + 4; + s->tm4[i].tm.level = 0; s->tm4[i].freq = 0; s->tm4[i].control = 0x0; - s->tm4[i].qtimer = qemu_new_timer(vm_clock, + s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock, pxa2xx_timer_tick4, &s->tm4[i]); } } -- cgit v1.2.3 From 85028e4db6b92b9b2f0282971efdb0a0144bfcd3 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 8 May 2007 22:51:41 +0000 Subject: Spelling fixes, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2790 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 4 ++-- dyngen.c | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 920a0f7e9..5f0a7e989 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -1045,8 +1045,8 @@ static inline int64_t cpu_get_real_ticks(void) #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. */ + Just return a monotonically increasing value. This will be + totally wrong, but hopefully better than nothing. */ static inline int64_t cpu_get_real_ticks (void) { static int64_t ticks = 0; diff --git a/dyngen.c b/dyngen.c index b8950b11d..4ed48227e 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1750,8 +1750,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #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); + /* Set __attribute((unused)) on darwin because we + want 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) /* @@ -1836,7 +1837,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } - /* load parameres in variables */ + /* load parameters in variables */ for(i = 0; i < nb_args; i++) { fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1); } -- cgit v1.2.3 From 522777bbafd9151da17199f558c036f791b5cac1 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 8 May 2007 23:30:44 +0000 Subject: Make detection of unsupported hosts easier, inspired by a patch from Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2791 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 62 +++++++++++++++++++++++------------------------------------ dyngen.h | 59 ++++++++++++++++---------------------------------------- 2 files changed, 41 insertions(+), 80 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 8ceb2301d..9f5fcc6ce 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -89,21 +89,19 @@ extern int printf(const char *, ...); #undef NULL #define NULL 0 -#ifdef __i386__ +#if defined(__i386__) #define AREG0 "ebp" #define AREG1 "ebx" #define AREG2 "esi" #define AREG3 "edi" -#endif -#ifdef __x86_64__ +#elif defined(__x86_64__) #define AREG0 "r14" #define AREG1 "r15" #define AREG2 "r12" #define AREG3 "r13" //#define AREG4 "rbp" //#define AREG5 "rbx" -#endif -#ifdef __powerpc__ +#elif defined(__powerpc__) #define AREG0 "r27" #define AREG1 "r24" #define AREG2 "r25" @@ -121,14 +119,12 @@ extern int printf(const char *, ...); #endif #define USE_INT_TO_FLOAT_HELPERS #define BUGGY_GCC_DIV64 -#endif -#ifdef __arm__ +#elif defined(__arm__) #define AREG0 "r7" #define AREG1 "r4" #define AREG2 "r5" #define AREG3 "r6" -#endif -#ifdef __mips__ +#elif defined(__mips__) #define AREG0 "fp" #define AREG1 "s0" #define AREG2 "s1" @@ -138,8 +134,7 @@ extern int printf(const char *, ...); #define AREG6 "s5" #define AREG7 "s6" #define AREG8 "s7" -#endif -#ifdef __sparc__ +#elif defined(__sparc__) #ifdef HOST_SOLARIS #define AREG0 "g2" #define AREG1 "g3" @@ -168,14 +163,12 @@ extern int printf(const char *, ...); #endif #endif #define USE_FP_CONVERT -#endif -#ifdef __s390__ +#elif defined(__s390__) #define AREG0 "r10" #define AREG1 "r7" #define AREG2 "r8" #define AREG3 "r9" -#endif -#ifdef __alpha__ +#elif defined(__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" @@ -185,19 +178,19 @@ extern int printf(const char *, ...); #define AREG4 "$12" #define AREG5 "$13" #define AREG6 "$14" -#endif -#ifdef __mc68000 +#elif defined(__mc68000) #define AREG0 "%a5" #define AREG1 "%a4" #define AREG2 "%d7" #define AREG3 "%d6" #define AREG4 "%d5" -#endif -#ifdef __ia64__ +#elif defined(__ia64__) #define AREG0 "r7" #define AREG1 "r4" #define AREG2 "r5" #define AREG3 "r6" +#else +#error unsupported CPU #endif /* force GCC to generate only one epilog at the end of the function */ @@ -250,44 +243,37 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #define ASM_NAME(x) #x #endif -#ifdef __i386__ +#if defined(__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__ +#elif defined(__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__ +#elif defined(__powerpc__) #define EXIT_TB() asm volatile ("blr") #define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n) -#endif -#ifdef __s390__ +#elif defined(__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__ +#elif defined(__alpha__) #define EXIT_TB() asm volatile ("ret") -#endif -#ifdef __ia64__ +#elif defined(__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__ +#elif defined(__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__ +#elif defined(__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 +#elif defined(__mc68000) #define EXIT_TB() asm volatile ("rts") -#endif -#ifdef __mips__ +#elif defined(__mips__) #define EXIT_TB() asm volatile ("jr $ra") #define GOTO_LABEL_PARAM(n) asm volatile (".set noat; la $1, " ASM_NAME(__op_gen_label) #n "; jr $1; .set at") +#else +#error unsupported CPU #endif #endif /* !defined(__DYNGEN_EXEC_H__) */ diff --git a/dyngen.h b/dyngen.h index e8bf72bfd..48e40192c 100644 --- a/dyngen.h +++ b/dyngen.h @@ -28,25 +28,11 @@ int __op_param1, __op_param2, __op_param3; #endif int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; -#ifdef __i386__ +#if defined(__i386__) || defined(__x86_64__) || defined(__s390__) 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__ +#elif defined(__ia64__) static inline void flush_icache_range(unsigned long start, unsigned long stop) { while (start < stop) { @@ -55,9 +41,7 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) } asm volatile (";;sync.i;;srlz.i;;"); } -#endif - -#ifdef __powerpc__ +#elif defined(__powerpc__) #define MIN_CACHE_LINE_SIZE 8 /* conservative value */ @@ -78,17 +62,12 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) asm volatile ("sync" : : : "memory"); asm volatile ("isync" : : : "memory"); } -#endif - -#ifdef __alpha__ +#elif defined(__alpha__) static inline void flush_icache_range(unsigned long start, unsigned long stop) { asm ("imb"); } -#endif - -#ifdef __sparc__ - +#elif defined(__sparc__) static void inline flush_icache_range(unsigned long start, unsigned long stop) { unsigned long p; @@ -99,10 +78,7 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) for (; p < stop; p += 8) __asm__ __volatile__("flush\t%0" : : "r" (p)); } - -#endif - -#ifdef __arm__ +#elif defined(__arm__) static inline void flush_icache_range(unsigned long start, unsigned long stop) { register unsigned long _beg __asm ("a1") = start; @@ -110,14 +86,22 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) register unsigned long _flg __asm ("a3") = 0; __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); } -#endif +#elif defined(__mc68000) -#ifdef __mc68000 -#include +# include static inline void flush_icache_range(unsigned long start, unsigned long stop) { cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16); } +#elif defined(__mips__) + +#include +static inline void flush_icache_range(unsigned long start, unsigned long stop) +{ + _flush_cache ((void *)start, stop - start, BCACHE); +} +#else +#error unsupported CPU #endif #ifdef __alpha__ @@ -248,7 +232,6 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, #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) { @@ -463,11 +446,3 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp, } #endif - -#ifdef __mips__ -#include -static inline void flush_icache_range(unsigned long start, unsigned long stop) -{ - _flush_cache ((void *)start, stop - start, BCACHE); -} -#endif -- cgit v1.2.3 From 204a1b8d5ec12af7f0e4757f51802672fc2e6681 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 8 May 2007 23:40:45 +0000 Subject: Another #elif'ication. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2792 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/exec-all.h b/exec-all.h index bc118c8a4..d6bbbd20b 100644 --- a/exec-all.h +++ b/exec-all.h @@ -357,7 +357,7 @@ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; -#ifdef __powerpc__ +#if defined(__powerpc__) static inline int testandset (int *p) { int ret; @@ -373,9 +373,7 @@ static inline int testandset (int *p) : "cr0", "memory"); return ret; } -#endif - -#ifdef __i386__ +#elif defined(__i386__) static inline int testandset (int *p) { long int readval = 0; @@ -386,9 +384,7 @@ static inline int testandset (int *p) : "cc"); return readval; } -#endif - -#ifdef __x86_64__ +#elif defined(__x86_64__) static inline int testandset (int *p) { long int readval = 0; @@ -399,9 +395,7 @@ static inline int testandset (int *p) : "cc"); return readval; } -#endif - -#ifdef __s390__ +#elif defined(__s390__) static inline int testandset (int *p) { int ret; @@ -413,9 +407,7 @@ static inline int testandset (int *p) : "cc", "memory" ); return ret; } -#endif - -#ifdef __alpha__ +#elif defined(__alpha__) static inline int testandset (int *p) { int ret; @@ -432,9 +424,7 @@ static inline int testandset (int *p) : "m" (*p)); return ret; } -#endif - -#ifdef __sparc__ +#elif defined(__sparc__) static inline int testandset (int *p) { int ret; @@ -446,9 +436,7 @@ static inline int testandset (int *p) return (ret ? 1 : 0); } -#endif - -#ifdef __arm__ +#elif defined(__arm__) static inline int testandset (int *spinlock) { register unsigned int ret; @@ -458,9 +446,7 @@ static inline int testandset (int *spinlock) return ret; } -#endif - -#ifdef __mc68000 +#elif defined(__mc68000) static inline int testandset (int *p) { char ret; @@ -470,18 +456,15 @@ static inline int testandset (int *p) : "cc","memory"); return ret; } -#endif +#elif defined(__ia64) -#ifdef __ia64 #include static inline int testandset (int *p) { return __sync_lock_test_and_set (p, 1); } -#endif - -#ifdef __mips__ +#elif defined(__mips__) static inline int testandset (int *p) { int ret; @@ -501,6 +484,8 @@ static inline int testandset (int *p) return ret; } +#else +#error unimplemented CPU support #endif typedef int spinlock_t; -- cgit v1.2.3 From a6763a588127d8b0f7e64312e9153c6c6bae822f Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 9 May 2007 09:33:33 +0000 Subject: Fix MIPS64 address computation specialcase, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2793 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 16 ++++++++++++++++ target-mips/translate.c | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index aedd7bd84..9b0cee0e3 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -289,6 +289,22 @@ void op_store_LO (void) #undef MEMSUFFIX #endif +/* Addresses computation */ +void op_addr_add (void) +{ +/* For compatibility with 32-bit code, data reference in user mode + with Status_UX = 0 should be casted to 32-bit and sign extended. + See the MIPS64 PRA manual, section 4.10. */ +#ifdef TARGET_MIPS64 + if ((env->CP0_Status & (1 << CP0St_UM)) && + !(env->CP0_Status & (1 << CP0St_UX))) + T0 = (int64_t)(int32_t)(T0 + T1); + else +#endif + T0 += T1; + RETURN(); +} + /* Arithmetic */ void op_add (void) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 6098b2a10..debe17d7c 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -719,7 +719,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, } else { gen_op_load_gpr_T0(base); gen_op_set_T1(offset); - gen_op_add(); + gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual * memory access @@ -868,7 +868,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, } else { gen_op_load_gpr_T0(base); gen_op_set_T1(offset); - gen_op_add(); + gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual * memory access -- cgit v1.2.3 From b4ab4b4e1b8119ac1d9b28510d90682e30259c38 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 9 May 2007 09:34:30 +0000 Subject: Preliminary MIPS 64-bit MMU implementation, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2794 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 909db5d37..1b61a3124 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -77,8 +77,13 @@ static int get_physical_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) { - /* User mode can only access useg */ + /* User mode can only access useg/xuseg */ int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM; +#ifdef TARGET_MIPS64 + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; +#endif int ret = TLBRET_MATCH; #if 0 @@ -87,10 +92,18 @@ static int get_physical_address (CPUState *env, target_ulong *physical, user_mode, env->hflags); } #endif + +#ifdef TARGET_MIPS64 + if (user_mode && address > 0x3FFFFFFFFFFFFFFFULL) + return TLBRET_BADADDR; +#else if (user_mode && address > 0x7FFFFFFFUL) return TLBRET_BADADDR; - if (address < (int32_t)0x80000000UL) { - if (!(env->CP0_Status & (1 << CP0St_ERL))) { +#endif + + if (address <= (int32_t)0x7FFFFFFFUL) { + /* useg */ + if (!(env->CP0_Status & (1 << CP0St_ERL) && user_mode)) { #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); #else @@ -101,6 +114,45 @@ static int get_physical_address (CPUState *env, target_ulong *physical, *physical = address; *prot = PAGE_READ | PAGE_WRITE; } +#ifdef TARGET_MIPS64 +/* + XXX: Assuming : + - PABITS = 36 (correct for MIPS64R1) + - SEGBITS = 40 +*/ + } else if (address < 0x3FFFFFFFFFFFFFFFULL) { + /* xuseg */ + if (UX && address < 0x000000FFFFFFFFFFULL) { + ret = map_address(env, physical, prot, address, rw, access_type); + } else { + ret = TLBRET_BADADDR; + } + } else if (address < 0x7FFFFFFFFFFFFFFFULL) { + /* xsseg */ + if (SX && address < 0x400000FFFFFFFFFFULL) { + ret = map_address(env, physical, prot, address, rw, access_type); + } else { + ret = TLBRET_BADADDR; + } + } else if (address < 0xBFFFFFFFFFFFFFFFULL) { + /* xkphys */ + /* XXX: check supervisor mode */ + if (KX && (address & 0x03FFFFFFFFFFFFFFULL) < 0X0000000FFFFFFFFFULL) + { + *physical = address & 0X000000FFFFFFFFFFULL; + *prot = PAGE_READ | PAGE_WRITE; + } else { + ret = TLBRET_BADADDR; + } + } else if (address < 0xFFFFFFFF7FFFFFFFULL) { + /* xkseg */ + /* XXX: check supervisor mode */ + if (KX && address < 0xC00000FF7FFFFFFFULL) { + ret = map_address(env, physical, prot, address, rw, access_type); + } else { + ret = TLBRET_BADADDR; + } +#endif } else if (address < (int32_t)0xA0000000UL) { /* kseg0 */ /* XXX: check supervisor mode */ @@ -116,7 +168,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); #else - *physical = address; + *physical = address & 0xFFFFFFFF; *prot = PAGE_READ | PAGE_WRITE; #endif } else { @@ -126,7 +178,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); #else - *physical = address; + *physical = address & 0xFFFFFFFF; *prot = PAGE_READ | PAGE_WRITE; #endif } -- cgit v1.2.3 From 6c59186721b28590f45e49b853f3f16ec317757e Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 9 May 2007 13:55:03 +0000 Subject: Suppress warning messages from "which". git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2795 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 187ac35a1..245b2059d 100755 --- a/configure +++ b/configure @@ -606,7 +606,8 @@ EOF fi # Check if tools are available to build documentation. -if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then +if [ -x "`which texi2html 2>/dev/null`" ] && \ + [ -x "`which pod2man 2>/dev/null`" ]; then build_docs="yes" fi -- cgit v1.2.3 From f54f432ec7197ffe7e077fcb5cc6557aa21c9ffd Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 9 May 2007 14:06:06 +0000 Subject: Avoid use of which to detect gcc, as it is broken on darwin. Patch by Joachim Henke. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2796 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/configure b/configure index 245b2059d..65fdeed9d 100755 --- a/configure +++ b/configure @@ -394,18 +394,13 @@ if test "$check_gcc" = "yes" ; then #endif int main(){return 0;} EOF - check_cc() { - which "$1" 2> /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 "$cross_prefix$compat_cc" ; then + if "$cross_prefix$compat_cc" --version > /dev/null 2>&1 ; then echo "Found \"$compat_cc\"" cc="$cross_prefix$compat_cc" found_compat_cc="yes" -- cgit v1.2.3 From 9e315fa93c14d6da7dc5b8fef193a671b51defd8 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 9 May 2007 20:25:36 +0000 Subject: PCMCIA addresses are 26-bit, widen the address type from 16 to 32 bits. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2797 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 8 ++++---- vl.h | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 1417e2898..a1aebc994 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -3071,7 +3071,7 @@ static void md_reset(struct md_s *s) ide_reset(s->ide); } -static uint8_t md_attr_read(void *opaque, uint16_t at) +static uint8_t md_attr_read(void *opaque, uint32_t at) { struct md_s *s = (struct md_s *) opaque; if (at < s->attr_base) { @@ -3104,7 +3104,7 @@ static uint8_t md_attr_read(void *opaque, uint16_t at) return 0; } -static void md_attr_write(void *opaque, uint16_t at, uint8_t value) +static void md_attr_write(void *opaque, uint32_t at, uint8_t value) { struct md_s *s = (struct md_s *) opaque; at -= s->attr_base; @@ -3135,7 +3135,7 @@ static void md_attr_write(void *opaque, uint16_t at, uint8_t value) } } -static uint16_t md_common_read(void *opaque, uint16_t at) +static uint16_t md_common_read(void *opaque, uint32_t at) { struct md_s *s = (struct md_s *) opaque; uint16_t ret; @@ -3194,7 +3194,7 @@ static uint16_t md_common_read(void *opaque, uint16_t at) return 0; } -static void md_common_write(void *opaque, uint16_t at, uint16_t value) +static void md_common_write(void *opaque, uint32_t at, uint16_t value) { struct md_s *s = (struct md_s *) opaque; at -= s->io_base; diff --git a/vl.h b/vl.h index f44eeab5f..171b02b87 100644 --- a/vl.h +++ b/vl.h @@ -1552,12 +1552,12 @@ struct pcmcia_card_s { int cis_len; /* Only valid if attached */ - uint8_t (*attr_read)(void *state, uint16_t address); - void (*attr_write)(void *state, uint16_t address, uint8_t value); - uint16_t (*common_read)(void *state, uint16_t address); - void (*common_write)(void *state, uint16_t address, uint16_t value); - uint16_t (*io_read)(void *state, uint16_t address); - void (*io_write)(void *state, uint16_t address, uint16_t value); + uint8_t (*attr_read)(void *state, uint32_t address); + void (*attr_write)(void *state, uint32_t address, uint8_t value); + uint16_t (*common_read)(void *state, uint32_t address); + void (*common_write)(void *state, uint32_t address, uint16_t value); + uint16_t (*io_read)(void *state, uint32_t address); + void (*io_write)(void *state, uint32_t address, uint16_t value); }; #define CISTPL_DEVICE 0x01 /* 5V Device Information Tuple */ -- cgit v1.2.3 From 976a0d0d0d8f8a6f5ba3ac097e8bc4429bd370ae Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 10 May 2007 00:33:40 +0000 Subject: Fix wrong branch condition in MIPS testandset. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2798 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec-all.h b/exec-all.h index d6bbbd20b..863ca3bdb 100644 --- a/exec-all.h +++ b/exec-all.h @@ -476,7 +476,7 @@ static inline int testandset (int *p) "1: li $1, 1 \n" " ll %0, %1 \n" " sc $1, %1 \n" - " bnez $1, 1b \n" + " beqz $1, 1b \n" " .set pop " : "=r" (ret), "+R" (*p) : -- cgit v1.2.3 From beebb570f41693eb3fcda8f31d2532d17c9ef75a Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 10 May 2007 00:51:01 +0000 Subject: Fix for the scd instruction, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2799 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index debe17d7c..449a920a0 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -745,6 +745,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, save_cpu_state(ctx, 1); GEN_LOAD_REG_TN(T1, rt); op_ldst(scd); + GEN_STORE_TN_REG(rt, T0); opn = "scd"; break; case OPC_LDL: -- cgit v1.2.3 From 4759513bd9bff5e4b12f2af96d6462b97dc4500c Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 11 May 2007 00:02:14 +0000 Subject: Fix missing status ro mask initialization, thanks Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2800 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index a166bdd5e..e38ab2882 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -98,6 +98,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, + .Status_rw_bitmask = 0x3278FF17, }, { .name = "4KEc", -- cgit v1.2.3 From 923617a396249fcac8710048f9db76345246f999 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 11 May 2007 00:16:06 +0000 Subject: Improved debug output for the MIPS opcode decoder. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2801 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 162 +++++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 85 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 449a920a0..dda44d037 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -540,7 +540,7 @@ enum { BS_EXCP = 3, /* We reached an exception condition */ }; -#if defined MIPS_DEBUG_DISAS +#ifdef MIPS_DEBUG_DISAS #define MIPS_DEBUG(fmt, args...) \ do { \ if (loglevel & CPU_LOG_TB_IN_ASM) { \ @@ -710,7 +710,7 @@ OP_ST_TABLE(uxc1); static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, int base, int16_t offset) { - const char *opn = "unk"; + const char *opn = "ldst"; if (base == 0) { GEN_LOAD_IMM_TN(T0, offset); @@ -849,7 +849,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, opn = "sc"; break; default: - MIPS_INVAL("load/store"); + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -860,7 +860,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, int base, int16_t offset) { - const char *opn = "unk"; + const char *opn = "flt_ldst"; if (base == 0) { GEN_LOAD_IMM_TN(T0, offset); @@ -896,7 +896,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, opn = "sdc1"; break; default: - MIPS_INVAL("float load/store"); + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -908,7 +908,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) { uint32_t uimm; - const char *opn = "unk"; + const char *opn = "imm arith"; if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { /* if no destination, treat it as a NOP @@ -1073,7 +1073,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, break; #endif default: - MIPS_INVAL("imm arith"); + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -1085,7 +1085,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, static void gen_arith (DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { - const char *opn = "unk"; + const char *opn = "arith"; if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB && opc != OPC_DADD && opc != OPC_DSUB) { @@ -1223,7 +1223,7 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, break; #endif default: - MIPS_INVAL("arith"); + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -1235,7 +1235,7 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, /* Arithmetic on HI/LO registers */ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) { - const char *opn = "unk"; + const char *opn = "hilo"; if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { /* Treat as a NOP */ @@ -1264,7 +1264,7 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) opn = "mtlo"; break; default: - MIPS_INVAL("HILO"); + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -1274,7 +1274,7 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) static void gen_muldiv (DisasContext *ctx, uint32_t opc, int rs, int rt) { - const char *opn = "unk"; + const char *opn = "mul/div"; GEN_LOAD_REG_TN(T0, rs); GEN_LOAD_REG_TN(T1, rt); @@ -1330,7 +1330,7 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, opn = "msubu"; break; default: - MIPS_INVAL("mul/div"); + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -1340,7 +1340,7 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, static void gen_cl (DisasContext *ctx, uint32_t opc, int rd, int rs) { - const char *opn = "unk"; + const char *opn = "CLx"; if (rd == 0) { /* Treat as a NOP */ MIPS_DEBUG("NOP"); @@ -1367,7 +1367,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, break; #endif default: - MIPS_INVAL("CLx"); + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -1431,7 +1431,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, /* Never trap: treat as NOP */ return; default: - MIPS_INVAL("TRAP"); + MIPS_INVAL("trap"); generate_exception(ctx, EXCP_RI); return; } @@ -1462,7 +1462,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, gen_op_ne(); break; default: - MIPS_INVAL("TRAP"); + MIPS_INVAL("trap"); generate_exception(ctx, EXCP_RI); return; } @@ -1499,12 +1499,13 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, int bcond = 0; if (ctx->hflags & MIPS_HFLAG_BMASK) { +#ifdef MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); } - MIPS_INVAL("branch/jump in bdelay slot"); +#endif generate_exception(ctx, EXCP_RI); return; } @@ -1553,6 +1554,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, if (offset != 0 && offset != 16) { /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the others are reserved. */ + MIPS_INVAL("jump hint"); generate_exception(ctx, EXCP_RI); return; } @@ -1610,12 +1612,12 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, return; case OPC_J: ctx->hflags |= MIPS_HFLAG_B; - MIPS_DEBUG("j %08x", btarget); + MIPS_DEBUG("j " TARGET_FMT_lx, btarget); break; case OPC_JAL: blink = 31; ctx->hflags |= MIPS_HFLAG_B; - MIPS_DEBUG("jal %08x", btarget); + MIPS_DEBUG("jal " TARGET_FMT_lx, btarget); break; case OPC_JR: ctx->hflags |= MIPS_HFLAG_BR; @@ -1635,70 +1637,70 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, switch (opc) { case OPC_BEQ: gen_op_eq(); - MIPS_DEBUG("beq %s, %s, %08x", + MIPS_DEBUG("beq %s, %s, " TARGET_FMT_lx, regnames[rs], regnames[rt], btarget); goto not_likely; case OPC_BEQL: gen_op_eq(); - MIPS_DEBUG("beql %s, %s, %08x", + MIPS_DEBUG("beql %s, %s, " TARGET_FMT_lx, regnames[rs], regnames[rt], btarget); goto likely; case OPC_BNE: gen_op_ne(); - MIPS_DEBUG("bne %s, %s, %08x", + MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx, regnames[rs], regnames[rt], btarget); goto not_likely; case OPC_BNEL: gen_op_ne(); - MIPS_DEBUG("bnel %s, %s, %08x", + MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx, regnames[rs], regnames[rt], btarget); goto likely; case OPC_BGEZ: gen_op_gez(); - MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btarget); goto not_likely; case OPC_BGEZL: gen_op_gez(); - MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btarget); goto likely; case OPC_BGEZAL: gen_op_gez(); - MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btarget); blink = 31; goto not_likely; case OPC_BGEZALL: gen_op_gez(); blink = 31; - MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btarget); goto likely; case OPC_BGTZ: gen_op_gtz(); - MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btarget); goto not_likely; case OPC_BGTZL: gen_op_gtz(); - MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btarget); goto likely; case OPC_BLEZ: gen_op_lez(); - MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btarget); goto not_likely; case OPC_BLEZL: gen_op_lez(); - MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btarget); goto likely; case OPC_BLTZ: gen_op_ltz(); - MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btarget); goto not_likely; case OPC_BLTZL: gen_op_ltz(); - MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btarget); goto likely; case OPC_BLTZAL: gen_op_ltz(); blink = 31; - MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btarget); not_likely: ctx->hflags |= MIPS_HFLAG_BC; gen_op_set_bcond(); @@ -1706,7 +1708,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BLTZALL: gen_op_ltz(); blink = 31; - MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget); + MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btarget); likely: ctx->hflags |= MIPS_HFLAG_BL; gen_op_set_bcond(); @@ -1718,7 +1720,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, return; } } - MIPS_DEBUG("enter ds: link %d cond %02x target %08x", + MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx, blink, ctx->hflags, btarget); ctx->btarget = btarget; if (blink > 0) { @@ -4221,6 +4223,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) case OPC_DERET: opn = "deret"; if (!(ctx->hflags & MIPS_HFLAG_DM)) { + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); } else { save_cpu_state(ctx, 0); @@ -4238,11 +4241,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) ctx->bstate = BS_EXCP; break; default: - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n", - ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, - ((ctx->opcode >> 16) & 0x1F)); - } + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -4254,25 +4253,26 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, int32_t cc, int32_t offset) { target_ulong btarget; + const char *opn = "cp1 cond branch"; btarget = ctx->pc + 4 + offset; switch (op) { case OPC_BC1F: gen_op_bc1f(cc); - MIPS_DEBUG("bc1f " TARGET_FMT_lx, btarget); + opn = "bc1f"; goto not_likely; case OPC_BC1FL: gen_op_bc1f(cc); - MIPS_DEBUG("bc1fl " TARGET_FMT_lx, btarget); + opn = "bc1fl"; goto likely; case OPC_BC1T: gen_op_bc1t(cc); - MIPS_DEBUG("bc1t " TARGET_FMT_lx, btarget); + opn = "bc1t"; goto not_likely; case OPC_BC1TL: gen_op_bc1t(cc); - MIPS_DEBUG("bc1tl " TARGET_FMT_lx, btarget); + opn = "bc1tl"; likely: ctx->hflags |= MIPS_HFLAG_BL; gen_op_set_bcond(); @@ -4280,34 +4280,31 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, break; case OPC_BC1FANY2: gen_op_bc1fany2(cc); - MIPS_DEBUG("bc1fany2 " TARGET_FMT_lx, btarget); + opn = "bc1fany2"; goto not_likely; case OPC_BC1TANY2: gen_op_bc1tany2(cc); - MIPS_DEBUG("bc1tany2 " TARGET_FMT_lx, btarget); + opn = "bc1tany2"; goto not_likely; case OPC_BC1FANY4: gen_op_bc1fany4(cc); - MIPS_DEBUG("bc1fany4 " TARGET_FMT_lx, btarget); + opn = "bc1fany4"; goto not_likely; case OPC_BC1TANY4: gen_op_bc1tany4(cc); - MIPS_DEBUG("bc1tany4 " TARGET_FMT_lx, btarget); + opn = "bc1tany4"; not_likely: ctx->hflags |= MIPS_HFLAG_BC; gen_op_set_bcond(); break; default: - MIPS_INVAL("cp1 branch"); + MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); return; } - - MIPS_DEBUG("enter ds: cond %02x target " TARGET_FMT_lx, + MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, ctx->hflags, btarget); ctx->btarget = btarget; - - return; } /* Coprocessor 1 (FPU) */ @@ -4325,18 +4322,19 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, * FIXME: This is broken for R2, it needs to be checked at runtime, not * at translation time. */ -#define CHECK_FR(ctx, freg) do { \ +#define CHECK_FR(ctx, freg) do { \ if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \ - generate_exception (ctx, EXCP_RI); \ - return; \ - } \ + MIPS_INVAL("FPU mode"); \ + generate_exception (ctx, EXCP_RI); \ + return; \ + } \ } while(0) #define FOP(func, fmt) (((fmt) << 21) | (func)) static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) { - const char *opn = "unk"; + const char *opn = "cp1 move"; switch (opc) { case OPC_MFC1: @@ -4390,11 +4388,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "mthc1"; break; default: - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n", - ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, - ((ctx->opcode >> 16) & 0x1F)); - } + MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); return; } @@ -4440,7 +4434,7 @@ GEN_MOVCF(ps); static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd, int cc) { - const char *opn = "unk"; + const char *opn = "farith"; const char *condnames[] = { "c.f", "c.un", @@ -5041,11 +5035,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = condnames[func-48]; break; default: - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n", - ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F, - ((ctx->opcode >> 16) & 0x1F)); - } + MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); return; } @@ -5059,7 +5049,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, int base, int index) { - const char *opn = "unk"; + const char *opn = "extended float load/store"; GEN_LOAD_REG_TN(T0, base); GEN_LOAD_REG_TN(T1, index); @@ -5098,7 +5088,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, opn = "suxc1"; break; default: - MIPS_INVAL("extended float load/store"); + MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } @@ -5108,7 +5098,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, int fr, int fs, int ft) { - const char *opn = "unk"; + const char *opn = "flt3_arith"; /* All of those work only on 64bit FPUs. */ CHECK_FR(ctx, fd | fr | fs | ft); @@ -5173,11 +5163,8 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, generate_exception (ctx, EXCP_RI); opn = "nmsub.ps"; break; - default: - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "Invalid extended FP arith function: %08x %03x %03x\n", - ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F); - } + default: + MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); return; } @@ -5459,7 +5446,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) /* treat as noop */ break; default: /* Invalid */ - MIPS_INVAL("REGIMM"); + MIPS_INVAL("regimm"); generate_exception(ctx, EXCP_RI); break; } @@ -5494,7 +5481,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) ctx->bstate = BS_STOP; break; default: /* Invalid */ - MIPS_INVAL("MFMC0"); + MIPS_INVAL("mfmc0"); generate_exception(ctx, EXCP_RI); break; } @@ -5506,10 +5493,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) /* Shadow registers not implemented. */ GEN_LOAD_REG_TN(T0, rt); GEN_STORE_TN_REG(rd, T0); - } else + } else { + MIPS_INVAL("shadow register move"); generate_exception(ctx, EXCP_RI); + } break; default: + MIPS_INVAL("cp0"); generate_exception(ctx, EXCP_RI); break; } @@ -5539,7 +5529,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) /* Treat as a noop */ break; - /* Floating point. */ + /* Floating point (COP1). */ case OPC_LWC1: case OPC_LDC1: case OPC_SWC1: @@ -5584,6 +5574,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) (imm >> 8) & 0x7); break; default: + MIPS_INVAL("cp1"); generate_exception (ctx, EXCP_RI); break; } @@ -5635,6 +5626,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_flt3_arith(ctx, op1, sa, rs, rd, rt); break; default: + MIPS_INVAL("cp3"); generate_exception (ctx, EXCP_RI); break; } @@ -5667,7 +5659,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) /* MDMX: Not implemented. */ #endif default: /* Invalid */ - MIPS_INVAL(""); + MIPS_INVAL("major opcode"); generate_exception(ctx, EXCP_RI); break; } @@ -5764,7 +5756,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, cpu_dump_state(env, logfile, fprintf, 0); } #endif -#if defined MIPS_DEBUG_DISAS +#ifdef MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) fprintf(logfile, "\ntb %p super %d cond %04x\n", tb, ctx.mem_idx, ctx.hflags); -- cgit v1.2.3 From fbcc68286a427fe75e7af98d28dee92c71ba0cb5 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 11 May 2007 09:59:10 +0000 Subject: Implement FP madd/msub, wire up bc1any[24][ft]. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2802 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 55 ++++++++++++++++++++++++++++ target-mips/translate.c | 97 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 140 insertions(+), 12 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 9b0cee0e3..15c541cf8 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -2185,6 +2185,7 @@ FLOAT_OP(name, d) \ FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ update_fcr31(); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } \ FLOAT_OP(name, s) \ { \ @@ -2192,6 +2193,7 @@ FLOAT_OP(name, s) \ FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ update_fcr31(); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } \ FLOAT_OP(name, ps) \ { \ @@ -2200,6 +2202,7 @@ FLOAT_OP(name, ps) \ FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ update_fcr31(); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } FLOAT_BINOP(add) FLOAT_BINOP(sub) @@ -2207,6 +2210,16 @@ FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP +FLOAT_OP(addr, ps) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_add (FST0, FSTH0, &env->fp_status); + FSTH2 = float32_add (FST1, FSTH1, &env->fp_status); + update_fcr31(); + DEBUG_FPU_STATE(); + RETURN(); +} + /* ternary operations */ #define FLOAT_TERNOP(name1, name2) \ FLOAT_OP(name1 ## name2, d) \ @@ -2214,12 +2227,14 @@ FLOAT_OP(name1 ## name2, d) \ FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \ FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } \ FLOAT_OP(name1 ## name2, s) \ { \ FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } \ FLOAT_OP(name1 ## name2, ps) \ { \ @@ -2228,28 +2243,65 @@ FLOAT_OP(name1 ## name2, ps) \ FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } FLOAT_TERNOP(mul, add) FLOAT_TERNOP(mul, sub) #undef FLOAT_TERNOP +/* negated ternary operations */ +#define FLOAT_NTERNOP(name1, name2) \ +FLOAT_OP(n ## name1 ## name2, d) \ +{ \ + FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \ + FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \ + FDT2 ^= 1ULL << 63; \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} \ +FLOAT_OP(n ## name1 ## name2, s) \ +{ \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ + FST2 ^= 1 << 31; \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} \ +FLOAT_OP(n ## name1 ## name2, ps) \ +{ \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ + FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ + FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \ + FST2 ^= 1 << 31; \ + FSTH2 ^= 1 << 31; \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} +FLOAT_NTERNOP(mul, add) +FLOAT_NTERNOP(mul, sub) +#undef FLOAT_NTERNOP + /* unary operations, modifying fp status */ #define FLOAT_UNOP(name) \ FLOAT_OP(name, d) \ { \ FDT2 = float64_ ## name(FDT0, &env->fp_status); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } \ FLOAT_OP(name, s) \ { \ FST2 = float32_ ## name(FST0, &env->fp_status); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } \ FLOAT_OP(name, ps) \ { \ FST2 = float32_ ## name(FST0, &env->fp_status); \ FSTH2 = float32_ ## name(FSTH0, &env->fp_status); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } FLOAT_UNOP(sqrt) #undef FLOAT_UNOP @@ -2260,17 +2312,20 @@ FLOAT_OP(name, d) \ { \ FDT2 = float64_ ## name(FDT0); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } \ FLOAT_OP(name, s) \ { \ FST2 = float32_ ## name(FST0); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } \ FLOAT_OP(name, ps) \ { \ FST2 = float32_ ## name(FST0); \ FSTH2 = float32_ ## name(FSTH0); \ DEBUG_FPU_STATE(); \ + RETURN(); \ } FLOAT_UNOP(abs) FLOAT_UNOP(chs) diff --git a/target-mips/translate.c b/target-mips/translate.c index dda44d037..8114178cf 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -402,7 +402,7 @@ enum { OPC_MSUB_D = 0x29 | OPC_CP3, OPC_MSUB_PS = 0x2E | OPC_CP3, OPC_NMADD_S = 0x30 | OPC_CP3, - OPC_NMADD_D = 0x32 | OPC_CP3, + OPC_NMADD_D = 0x31 | OPC_CP3, OPC_NMADD_PS= 0x36 | OPC_CP3, OPC_NMSUB_S = 0x38 | OPC_CP3, OPC_NMSUB_D = 0x39 | OPC_CP3, @@ -4955,6 +4955,17 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, GEN_STORE_FTN_FREG(fd, WTH2); opn = "movn.ps"; break; + case FOP(24, 22): + CHECK_FR(ctx, fs | fd | ft); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WTH1, ft); + gen_op_float_addr_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "addr.ps"; + break; case FOP(32, 22): CHECK_FR(ctx, fs); GEN_LOAD_FREG_FTN(WTH0, fs); @@ -5120,47 +5131,107 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, opn = "madd.s"; break; case OPC_MADD_D: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + GEN_LOAD_FREG_FTN(DT2, fr); + gen_op_float_muladd_d(); + GEN_STORE_FTN_FREG(fd, DT2); opn = "madd.d"; break; case OPC_MADD_PS: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WTH1, ft); + GEN_LOAD_FREG_FTN(WT2, fr); + GEN_LOAD_FREG_FTN(WTH2, fr); + gen_op_float_muladd_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); opn = "madd.ps"; break; case OPC_MSUB_S: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WT2, fr); + gen_op_float_mulsub_s(); + GEN_STORE_FTN_FREG(fd, WT2); opn = "msub.s"; break; case OPC_MSUB_D: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + GEN_LOAD_FREG_FTN(DT2, fr); + gen_op_float_mulsub_d(); + GEN_STORE_FTN_FREG(fd, DT2); opn = "msub.d"; break; case OPC_MSUB_PS: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WTH1, ft); + GEN_LOAD_FREG_FTN(WT2, fr); + GEN_LOAD_FREG_FTN(WTH2, fr); + gen_op_float_mulsub_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); opn = "msub.ps"; break; case OPC_NMADD_S: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WT2, fr); + gen_op_float_nmuladd_s(); + GEN_STORE_FTN_FREG(fd, WT2); opn = "nmadd.s"; break; case OPC_NMADD_D: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + GEN_LOAD_FREG_FTN(DT2, fr); + gen_op_float_nmuladd_d(); + GEN_STORE_FTN_FREG(fd, DT2); opn = "nmadd.d"; break; case OPC_NMADD_PS: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WTH1, ft); + GEN_LOAD_FREG_FTN(WT2, fr); + GEN_LOAD_FREG_FTN(WTH2, fr); + gen_op_float_nmuladd_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); opn = "nmadd.ps"; break; case OPC_NMSUB_S: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WT2, fr); + gen_op_float_nmulsub_s(); + GEN_STORE_FTN_FREG(fd, WT2); opn = "nmsub.s"; break; case OPC_NMSUB_D: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT1, ft); + GEN_LOAD_FREG_FTN(DT2, fr); + gen_op_float_nmulsub_d(); + GEN_STORE_FTN_FREG(fd, DT2); opn = "nmsub.d"; break; case OPC_NMSUB_PS: - generate_exception (ctx, EXCP_RI); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WTH1, ft); + GEN_LOAD_FREG_FTN(WT2, fr); + GEN_LOAD_FREG_FTN(WTH2, fr); + gen_op_float_nmulsub_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); opn = "nmsub.ps"; break; default: @@ -5562,6 +5633,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_cp1(ctx, op1, rt, rd); break; case OPC_BC1: + case OPC_BC1ANY2: + case OPC_BC1ANY4: gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); return; -- cgit v1.2.3 From 287c4b84f49d86176f9fd2ea7d06872dd8c1f2ca Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 11 May 2007 10:43:55 +0000 Subject: Another bit of nicer debug output. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2803 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 8114178cf..94fce57a3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4163,7 +4163,7 @@ die: static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) { - const char *opn = "unk"; + const char *opn = "ldst"; switch (opc) { case OPC_MFC0: -- cgit v1.2.3 From 5a1e8ffbe746b2ba4fb8dbdebf3f99d2403fb53e Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 11 May 2007 17:08:26 +0000 Subject: Implemented cabs FP instructions, and improve exception handling for trunc/floor/ceil/round. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2804 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 97 ++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 123 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 180 insertions(+), 40 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 15c541cf8..748f997d2 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1965,6 +1965,9 @@ FLOAT_OP(roundl, d) set_float_rounding_mode(float_round_nearest_even, &env->fp_status); DT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; DEBUG_FPU_STATE(); RETURN(); } @@ -1973,6 +1976,9 @@ FLOAT_OP(roundl, s) set_float_rounding_mode(float_round_nearest_even, &env->fp_status); DT2 = float32_round_to_int(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; DEBUG_FPU_STATE(); RETURN(); } @@ -1981,6 +1987,9 @@ FLOAT_OP(roundw, d) set_float_rounding_mode(float_round_nearest_even, &env->fp_status); WT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } @@ -1989,6 +1998,9 @@ FLOAT_OP(roundw, s) set_float_rounding_mode(float_round_nearest_even, &env->fp_status); WT2 = float32_round_to_int(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } @@ -1996,24 +2008,36 @@ FLOAT_OP(roundw, s) FLOAT_OP(truncl, d) { DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(truncl, s) { DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(truncw, d) { WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(truncw, s) { WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } @@ -2023,6 +2047,9 @@ FLOAT_OP(ceill, d) set_float_rounding_mode(float_round_up, &env->fp_status); DT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; DEBUG_FPU_STATE(); RETURN(); } @@ -2031,6 +2058,9 @@ FLOAT_OP(ceill, s) set_float_rounding_mode(float_round_up, &env->fp_status); DT2 = float32_round_to_int(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; DEBUG_FPU_STATE(); RETURN(); } @@ -2039,6 +2069,9 @@ FLOAT_OP(ceilw, d) set_float_rounding_mode(float_round_up, &env->fp_status); WT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } @@ -2047,6 +2080,9 @@ FLOAT_OP(ceilw, s) set_float_rounding_mode(float_round_up, &env->fp_status); WT2 = float32_round_to_int(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } @@ -2056,6 +2092,9 @@ FLOAT_OP(floorl, d) set_float_rounding_mode(float_round_down, &env->fp_status); DT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; DEBUG_FPU_STATE(); RETURN(); } @@ -2064,6 +2103,9 @@ FLOAT_OP(floorl, s) set_float_rounding_mode(float_round_down, &env->fp_status); DT2 = float32_round_to_int(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; DEBUG_FPU_STATE(); RETURN(); } @@ -2072,6 +2114,9 @@ FLOAT_OP(floorw, d) set_float_rounding_mode(float_round_down, &env->fp_status); WT2 = float64_round_to_int(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } @@ -2080,6 +2125,9 @@ FLOAT_OP(floorw, s) set_float_rounding_mode(float_round_down, &env->fp_status); WT2 = float32_round_to_int(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; DEBUG_FPU_STATE(); RETURN(); } @@ -2396,6 +2444,20 @@ void op_cmp_d_ ## op (void) \ CLEAR_FP_COND(PARAM1, env); \ DEBUG_FPU_STATE(); \ RETURN(); \ +} \ +void op_cmpabs_d_ ## op (void) \ +{ \ + int c; \ + FDT0 &= ~(1ULL << 63); \ + FDT1 &= ~(1ULL << 63); \ + c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(PARAM1, env); \ + else \ + CLEAR_FP_COND(PARAM1, env); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ } int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) @@ -2444,6 +2506,20 @@ void op_cmp_s_ ## op (void) \ CLEAR_FP_COND(PARAM1, env); \ DEBUG_FPU_STATE(); \ RETURN(); \ +} \ +void op_cmpabs_s_ ## op (void) \ +{ \ + int c; \ + FST0 &= ~(1 << 31); \ + FST1 &= ~(1 << 31); \ + c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(PARAM1, env); \ + else \ + CLEAR_FP_COND(PARAM1, env); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ } flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) @@ -2498,6 +2574,27 @@ void op_cmp_ps_ ## op (void) \ CLEAR_FP_COND(PARAM1 + 1, env); \ DEBUG_FPU_STATE(); \ RETURN(); \ +} \ +void op_cmpabs_ps_ ## op (void) \ +{ \ + int cl, ch; \ + FST0 &= ~(1 << 31); \ + FSTH0 &= ~(1 << 31); \ + FST1 &= ~(1 << 31); \ + FSTH1 &= ~(1 << 31); \ + cl = condl; \ + ch = condh; \ + update_fcr31(); \ + if (cl) \ + SET_FP_COND(PARAM1, env); \ + else \ + CLEAR_FP_COND(PARAM1, env); \ + if (ch) \ + SET_FP_COND(PARAM1 + 1, env); \ + else \ + CLEAR_FP_COND(PARAM1 + 1, env); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ } /* NOTE: the comma operator will make "cond" to eval to false, diff --git a/target-mips/translate.c b/target-mips/translate.c index 94fce57a3..79a33c5a5 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -490,33 +490,36 @@ FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr); FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); -#define FOP_CONDS(fmt) \ -static GenOpFunc1 * cond_ ## fmt ## _table[16] = { \ - gen_op_cmp_ ## fmt ## _f, \ - gen_op_cmp_ ## fmt ## _un, \ - gen_op_cmp_ ## fmt ## _eq, \ - gen_op_cmp_ ## fmt ## _ueq, \ - gen_op_cmp_ ## fmt ## _olt, \ - gen_op_cmp_ ## fmt ## _ult, \ - gen_op_cmp_ ## fmt ## _ole, \ - gen_op_cmp_ ## fmt ## _ule, \ - gen_op_cmp_ ## fmt ## _sf, \ - gen_op_cmp_ ## fmt ## _ngle, \ - gen_op_cmp_ ## fmt ## _seq, \ - gen_op_cmp_ ## fmt ## _ngl, \ - gen_op_cmp_ ## fmt ## _lt, \ - gen_op_cmp_ ## fmt ## _nge, \ - gen_op_cmp_ ## fmt ## _le, \ - gen_op_cmp_ ## fmt ## _ngt, \ +#define FOP_CONDS(type, fmt) \ +static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = { \ + gen_op_cmp ## type ## _ ## fmt ## _f, \ + gen_op_cmp ## type ## _ ## fmt ## _un, \ + gen_op_cmp ## type ## _ ## fmt ## _eq, \ + gen_op_cmp ## type ## _ ## fmt ## _ueq, \ + gen_op_cmp ## type ## _ ## fmt ## _olt, \ + gen_op_cmp ## type ## _ ## fmt ## _ult, \ + gen_op_cmp ## type ## _ ## fmt ## _ole, \ + gen_op_cmp ## type ## _ ## fmt ## _ule, \ + gen_op_cmp ## type ## _ ## fmt ## _sf, \ + gen_op_cmp ## type ## _ ## fmt ## _ngle, \ + gen_op_cmp ## type ## _ ## fmt ## _seq, \ + gen_op_cmp ## type ## _ ## fmt ## _ngl, \ + gen_op_cmp ## type ## _ ## fmt ## _lt, \ + gen_op_cmp ## type ## _ ## fmt ## _nge, \ + gen_op_cmp ## type ## _ ## fmt ## _le, \ + gen_op_cmp ## type ## _ ## fmt ## _ngt, \ }; \ -static inline void gen_cmp_ ## fmt(int n, long cc) \ +static inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \ { \ - cond_ ## fmt ## _table[n](cc); \ + cond ## type ## _ ## fmt ## _table[n](cc); \ } -FOP_CONDS(d) -FOP_CONDS(s) -FOP_CONDS(ps) +FOP_CONDS(, d) +FOP_CONDS(abs, d) +FOP_CONDS(, s) +FOP_CONDS(abs, s) +FOP_CONDS(, ps) +FOP_CONDS(abs, ps) typedef struct DisasContext { struct TranslationBlock *tb; @@ -4453,7 +4456,25 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, "c.le", "c.ngt", }; - int binary = 0; + const char *condnames_abs[] = { + "cabs.f", + "cabs.un", + "cabs.eq", + "cabs.ueq", + "cabs.olt", + "cabs.ult", + "cabs.ole", + "cabs.ule", + "cabs.sf", + "cabs.ngle", + "cabs.seq", + "cabs.ngl", + "cabs.lt", + "cabs.nge", + "cabs.le", + "cabs.ngt", + }; + enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP; uint32_t func = ctx->opcode & 0x3f; switch (ctx->opcode & FOP(0x3f, 0x1f)) { @@ -4463,7 +4484,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, gen_op_float_add_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "add.s"; - binary = 1; + optype = BINOP; break; case FOP(1, 16): GEN_LOAD_FREG_FTN(WT0, fs); @@ -4471,7 +4492,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, gen_op_float_sub_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "sub.s"; - binary = 1; + optype = BINOP; break; case FOP(2, 16): GEN_LOAD_FREG_FTN(WT0, fs); @@ -4479,7 +4500,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, gen_op_float_mul_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "mul.s"; - binary = 1; + optype = BINOP; break; case FOP(3, 16): GEN_LOAD_FREG_FTN(WT0, fs); @@ -4487,7 +4508,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, gen_op_float_div_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "div.s"; - binary = 1; + optype = BINOP; break; case FOP(4, 16): GEN_LOAD_FREG_FTN(WT0, fs); @@ -4635,8 +4656,13 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(63, 16): GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); - gen_cmp_s(func-48, cc); - opn = condnames[func-48]; + if (ctx->opcode & (1 << 6)) { + gen_cmpabs_s(func-48, cc); + opn = condnames_abs[func-48]; + } else { + gen_cmp_s(func-48, cc); + opn = condnames[func-48]; + } break; case FOP(0, 17): CHECK_FR(ctx, fs | ft | fd); @@ -4645,7 +4671,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, gen_op_float_add_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "add.d"; - binary = 1; + optype = BINOP; break; case FOP(1, 17): CHECK_FR(ctx, fs | ft | fd); @@ -4654,7 +4680,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, gen_op_float_sub_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "sub.d"; - binary = 1; + optype = BINOP; break; case FOP(2, 17): CHECK_FR(ctx, fs | ft | fd); @@ -4663,7 +4689,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, gen_op_float_mul_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "mul.d"; - binary = 1; + optype = BINOP; break; case FOP(3, 17): CHECK_FR(ctx, fs | ft | fd); @@ -4672,7 +4698,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, gen_op_float_div_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "div.d"; - binary = 1; + optype = BINOP; break; case FOP(4, 17): CHECK_FR(ctx, fs | fd); @@ -4801,8 +4827,13 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, CHECK_FR(ctx, fs | ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); - gen_cmp_d(func-48, cc); - opn = condnames[func-48]; + if (ctx->opcode & (1 << 6)) { + gen_cmpabs_d(func-48, cc); + opn = condnames_abs[func-48]; + } else { + gen_cmp_d(func-48, cc); + opn = condnames[func-48]; + } break; case FOP(32, 17): CHECK_FR(ctx, fs); @@ -5042,18 +5073,30 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); GEN_LOAD_FREG_FTN(WTH1, ft); - gen_cmp_ps(func-48, cc); - opn = condnames[func-48]; + if (ctx->opcode & (1 << 6)) { + gen_cmpabs_ps(func-48, cc); + opn = condnames_abs[func-48]; + } else { + gen_cmp_ps(func-48, cc); + opn = condnames[func-48]; + } break; default: MIPS_INVAL(opn); generate_exception (ctx, EXCP_RI); return; } - if (binary) + switch (optype) { + case BINOP: MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]); - else + break; + case CMPOP: + MIPS_DEBUG("%s %s,%s", opn, fregnames[fs], fregnames[ft]); + break; + default: MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]); + break; + } } /* Coprocessor 3 (FPU) */ -- cgit v1.2.3 From b645bb48850fea8db017026897827f0ab42fbdea Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 11 May 2007 17:10:14 +0000 Subject: Fix softfloat NaN handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2805 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-specialize.h | 48 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index f9b6f0cbc..2802eaa8d 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -61,7 +61,11 @@ typedef struct { /*---------------------------------------------------------------------------- | The pattern for a default generated single-precision NaN. *----------------------------------------------------------------------------*/ +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#define float32_default_nan 0xFF800000 +#else #define float32_default_nan 0xFFC00000 +#endif /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is a NaN; @@ -70,9 +74,11 @@ typedef struct { int float32_is_nan( float32 a ) { - - return ( 0xFF000000 < (bits32) ( a<<1 ) ); - +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); +#else + return ( 0xFF800000 <= (bits32) ( a<<1 ) ); +#endif } /*---------------------------------------------------------------------------- @@ -82,9 +88,11 @@ int float32_is_nan( float32 a ) int float32_is_signaling_nan( float32 a ) { - +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) + return ( 0xFF800000 <= (bits32) ( a<<1 ) ); +#else return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); - +#endif } /*---------------------------------------------------------------------------- @@ -131,8 +139,13 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) aIsSignalingNaN = float32_is_signaling_nan( a ); bIsNaN = float32_is_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) + a &= ~0x00400000; + b &= ~0x00400000; +#else a |= 0x00400000; b |= 0x00400000; +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; @@ -154,7 +167,11 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) /*---------------------------------------------------------------------------- | The pattern for a default generated double-precision NaN. *----------------------------------------------------------------------------*/ +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#define float64_default_nan LIT64( 0xFFF0000000000000 ) +#else #define float64_default_nan LIT64( 0xFFF8000000000000 ) +#endif /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is a NaN; @@ -163,9 +180,13 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) int float64_is_nan( float64 a ) { - - return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); - +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); +#else + return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#endif } /*---------------------------------------------------------------------------- @@ -175,11 +196,13 @@ int float64_is_nan( float64 a ) int float64_is_signaling_nan( float64 a ) { - +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) + return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#else return ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); - +#endif } /*---------------------------------------------------------------------------- @@ -229,8 +252,13 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) aIsSignalingNaN = float64_is_signaling_nan( a ); bIsNaN = float64_is_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) + a &= ~LIT64( 0x0008000000000000 ); + b &= ~LIT64( 0x0008000000000000 ); +#else a |= LIT64( 0x0008000000000000 ); b |= LIT64( 0x0008000000000000 ); +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; -- cgit v1.2.3 From a07dec2212d6ba9751dd1dac2b3f4b560325fee0 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 12 May 2007 09:19:36 +0000 Subject: Correct NAND erase block size. Misc fixes in Spitz code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2806 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/nand.c | 2 +- hw/pxa.h | 2 +- hw/pxa2xx.c | 8 ++++---- hw/pxa2xx_lcd.c | 3 +-- hw/spitz.c | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/hw/nand.c b/hw/nand.c index 04967817b..5bce25052 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -547,7 +547,7 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s) page = i >> 9; if (bdrv_read(s->bdrv, page, iobuf, 1) == -1) printf("%s: read error in sector %i\n", __FUNCTION__, page); - memset(iobuf, 0xff, addr & 0x1ff); + memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1); if (bdrv_write(s->bdrv, page, iobuf, 1) == -1) printf("%s: write error in sector %i\n", __FUNCTION__, page); } diff --git a/hw/pxa.h b/hw/pxa.h index 28cc1798b..8e82c28e0 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -59,9 +59,9 @@ # define PXA2XX_SDRAM_BASE 0xa0000000 # define PXA2XX_INTERNAL_BASE 0x5c000000 +# define PXA2XX_INTERNAL_SIZE 0x40000 /* pxa2xx_pic.c */ -struct pxa2xx_pic_state_s; qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env); /* pxa2xx_timer.c */ diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 4661011d7..a791f0845 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1634,10 +1634,10 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, cpu_arm_set_model(s->env, "pxa255"); /* SDRAM & Internal Memory Storage */ - cpu_register_physical_memory(PXA2XX_SDRAM_BASE, - sdram_size, qemu_ram_alloc(sdram_size) | IO_MEM_RAM); - cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, - 0x40000, qemu_ram_alloc(0x40000) | IO_MEM_RAM); + cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size, + qemu_ram_alloc(sdram_size) | IO_MEM_RAM); + cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, PXA2XX_INTERNAL_SIZE, + qemu_ram_alloc(PXA2XX_INTERNAL_SIZE) | IO_MEM_RAM); s->pic = pxa2xx_pic_init(0x40d00000, s->env); diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index a594e278f..db20a9366 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -737,8 +737,7 @@ static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s, dest, src, s->xres, s->dest_width); if (addr < start) start = addr; - if (new_addr > end) - end = new_addr; + end = new_addr; if (y < *miny) *miny = y; if (y >= *maxy) diff --git a/hw/spitz.c b/hw/spitz.c index aecace007..72b049e4e 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1003,9 +1003,9 @@ static void spitz_common_init(int ram_size, int vga_ram_size, cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; /* Setup CPU & memory */ - if (ram_size < spitz_ram + spitz_rom) { + if (ram_size < spitz_ram + spitz_rom + PXA2XX_INTERNAL_SIZE) { fprintf(stderr, "This platform requires %i bytes of memory\n", - spitz_ram + spitz_rom); + spitz_ram + spitz_rom + PXA2XX_INTERNAL_SIZE); exit(1); } cpu = pxa270_init(spitz_ram, ds, cpu_model); -- cgit v1.2.3 From 1eb5207bfd3dbe4aa7dae076c527f84c4f5c804b Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 12 May 2007 16:57:42 +0000 Subject: Update debug output. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2807 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index fedabef60..fcac463ba 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1132,8 +1132,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } if (ret == 1) { #if 0 - printf("PF exception: NIP=0x%08x error=0x%x %p\n", - env->nip, env->error_code, tb); + printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n", + env->PC, env->error_code, tb); #endif /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ -- cgit v1.2.3 From f707cfba9a5ee2d4ea6edc3d0588163141f285ad Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 13 May 2007 13:26:49 +0000 Subject: Allow VMware-SVGA operation enable before command FIFO is configured. Implement "screendump" for 32 bit colour depth. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2808 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 4 ++-- hw/vga_int.h | 2 ++ hw/vmware_vga.c | 48 +++++++++++++++++++++++++++--------------------- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 3032ccfb5..9dbbfe237 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -2036,8 +2036,8 @@ static void vga_save_dpy_refresh(DisplayState *s) { } -static int ppm_save(const char *filename, uint8_t *data, - int w, int h, int linesize) +int ppm_save(const char *filename, uint8_t *data, + int w, int h, int linesize) { FILE *f; uint8_t *d, *d1; diff --git a/hw/vga_int.h b/hw/vga_int.h index 7b1624743..2a4e9b981 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -166,6 +166,8 @@ void vga_init(VGAState *s); uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr); void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val); void vga_invalidate_scanlines(VGAState *s, int y1, int y2); +int ppm_save(const char *filename, uint8_t *data, + int w, int h, int linesize); void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1, int poffset, int w, diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index dda45dfef..e850952da 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -226,18 +226,19 @@ enum { #ifdef VERBOSE # define GUEST_OS_BASE 0x5001 static const char *vmsvga_guest_id[] = { - [0x0] = "Dos", - [0x1] = "Windows 3.1", - [0x2] = "Windows 95", - [0x3] = "Windows 98", - [0x4] = "Windows ME", - [0x5] = "Windows NT", - [0x6] = "Windows 2000", - [0x7] = "Linux", - [0x8] = "OS/2", - [0x9] = "Unknown", - [0xa] = "BSD", - [0xb] = "Whistler", + [0x00 ... 0x15] = "an unknown OS", + [0x00] = "Dos", + [0x01] = "Windows 3.1", + [0x02] = "Windows 95", + [0x03] = "Windows 98", + [0x04] = "Windows ME", + [0x05] = "Windows NT", + [0x06] = "Windows 2000", + [0x07] = "Linux", + [0x08] = "OS/2", + [0x0a] = "BSD", + [0x0b] = "Whistler", + [0x15] = "Windows 2003", }; #endif @@ -459,7 +460,7 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, static inline int vmsvga_fifo_empty(struct vmsvga_state_s *s) { if (!s->config || !s->enable) - return 0; + return 1; return (s->cmd->next_cmd == s->cmd->stop); } @@ -619,7 +620,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) return SVGA_MAX_WIDTH; case SVGA_REG_MAX_HEIGHT: - return SVGA_MAX_WIDTH; + return SVGA_MAX_HEIGHT; case SVGA_REG_DEPTH: return s->depth; @@ -727,7 +728,8 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) break; case SVGA_REG_ENABLE: - s->enable = s->config = value & s->config; + s->enable = value; + s->config &= !!value; s->width = -1; s->height = -1; s->invalidated = 1; @@ -770,7 +772,7 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) if (s->cmd->max < s->cmd->min + 10 * 1024) break; } - s->config = value; + s->config = !!value; break; case SVGA_REG_SYNC: @@ -902,14 +904,14 @@ static void vmsvga_reset(struct vmsvga_state_s *s) s->wblue = 0x0000f800; break; case 24: - s->wred = 0x000000ff; + s->wred = 0x00ff0000; s->wgreen = 0x0000ff00; - s->wblue = 0x00ff0000; + s->wblue = 0x000000ff; break; case 32: - s->wred = 0x000000ff; + s->wred = 0x00ff0000; s->wgreen = 0x0000ff00; - s->wblue = 0x00ff0000; + s->wblue = 0x000000ff; break; } s->syncing = 0; @@ -928,6 +930,8 @@ static void vmsvga_invalidate_display(void *opaque) s->invalidated = 1; } +/* save the vga display in a PPM image even if no display is + available */ static void vmsvga_screen_dump(void *opaque, const char *filename) { struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; @@ -938,7 +942,9 @@ static void vmsvga_screen_dump(void *opaque, const char *filename) return; } - /* TODO */ + if (s->depth == 32) { + ppm_save(filename, s->vram, s->width, s->height, s->ds->linesize); + } } #ifdef DIRECT_VRAM -- cgit v1.2.3 From 29929e349009731a2fb22a983da75f67b6e78362 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 13:49:44 +0000 Subject: MIPS TLB style selection at runtime, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2809 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 32 +++++++++++++++----- target-mips/exec.h | 6 +--- target-mips/helper.c | 72 +++++++++++++++++++++++++------------------- target-mips/mips-defs.h | 2 -- target-mips/op.c | 17 +++-------- target-mips/op_helper.c | 64 +++++++++++++-------------------------- target-mips/translate.c | 25 +++++++++------ target-mips/translate_init.c | 45 ++++++++++++++++++++++++--- 8 files changed, 149 insertions(+), 114 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 33cb6573e..9e029199b 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -33,9 +33,8 @@ union fpr_t { # define FP_ENDIAN_IDX 0 #endif -#if defined(MIPS_USES_R4K_TLB) -typedef struct tlb_t tlb_t; -struct tlb_t { +typedef struct r4k_tlb_t r4k_tlb_t; +struct r4k_tlb_t { target_ulong VPN; uint32_t PageMask; uint_fast8_t ASID; @@ -48,7 +47,6 @@ struct tlb_t { uint_fast16_t D1:1; target_ulong PFN[2]; }; -#endif typedef struct CPUMIPSState CPUMIPSState; struct CPUMIPSState { @@ -100,11 +98,19 @@ struct CPUMIPSState { #define FP_INVALID 16 #define FP_UNIMPLEMENTED 32 -#if defined(MIPS_USES_R4K_TLB) - tlb_t tlb[MIPS_TLB_MAX]; - uint32_t tlb_in_use; uint32_t nb_tlb; -#endif + uint32_t tlb_in_use; + int (*map_address) (CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type); + void (*do_tlbwi) (void); + void (*do_tlbwr) (void); + void (*do_tlbp) (void); + void (*do_tlbr) (void); + union { + struct { + r4k_tlb_t tlb[MIPS_TLB_MAX]; + } r4k; + } mmu; + int32_t CP0_Index; int32_t CP0_Random; target_ulong CP0_EntryLo0; @@ -289,6 +295,16 @@ struct CPUMIPSState { struct QEMUTimer *timer; /* Internal timer */ }; +int no_mmu_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, + target_ulong address, int rw, int access_type); +int fixed_mmu_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, + target_ulong address, int rw, int access_type); +int r4k_map_address (CPUMIPSState *env, target_ulong *physical, int *prot, + target_ulong address, int rw, int access_type); +void r4k_do_tlbwi (void); +void r4k_do_tlbwr (void); +void r4k_do_tlbp (void); +void r4k_do_tlbr (void); typedef struct mips_def_t mips_def_t; int mips_find_by_name (const unsigned char *name, mips_def_t **def); void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); diff --git a/target-mips/exec.h b/target-mips/exec.h index d9160a1f3..44314a98b 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -105,10 +105,6 @@ void do_mfc0_count(void); void do_mtc0_entryhi(uint32_t in); void do_mtc0_status_debug(uint32_t old, uint32_t val); void do_mtc0_status_irqraise_debug(void); -void do_tlbwi (void); -void do_tlbwr (void); -void do_tlbp (void); -void do_tlbr (void); void dump_fpu(CPUState *env); void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), @@ -151,7 +147,7 @@ void dump_sc (void); int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); void do_interrupt (CPUState *env); -void invalidate_tlb (CPUState *env, int idx, int use_extra); +void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra); void cpu_loop_exit(void); void do_raise_exception_err (uint32_t exception, int error_code); diff --git a/target-mips/helper.c b/target-mips/helper.c index 1b61a3124..cb568f11a 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -36,16 +36,42 @@ enum { TLBRET_MATCH = 0 }; -/* MIPS32 4K MMU emulation */ -#ifdef MIPS_USES_R4K_TLB -static int map_address (CPUState *env, target_ulong *physical, int *prot, +/* no MMU emulation */ +int no_mmu_map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type) +{ + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; + return TLBRET_MATCH; +} + +/* fixed mapping MMU emulation */ +int fixed_mmu_map_address (CPUState *env, target_ulong *physical, int *prot, + target_ulong address, int rw, int access_type) +{ + if (address <= (int32_t)0x7FFFFFFFUL) { + if (!(env->CP0_Status & (1 << CP0St_ERL))) + *physical = address + 0x40000000UL; + else + *physical = address; + } else if (address <= (int32_t)0xBFFFFFFFUL) + *physical = address & 0x1FFFFFFF; + else + *physical = address; + + *prot = PAGE_READ | PAGE_WRITE; + return TLBRET_MATCH; +} + +/* MIPS32/MIPS64 R4000-style MMU emulation */ +int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, + target_ulong address, int rw, int access_type) { uint8_t ASID = env->CP0_EntryHi & 0xFF; int i; for (i = 0; i < env->tlb_in_use; i++) { - tlb_t *tlb = &env->tlb[i]; + r4k_tlb_t *tlb = &env->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ target_ulong mask = tlb->PageMask | 0x1FFF; target_ulong tag = address & ~mask; @@ -71,7 +97,6 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot, } return TLBRET_NOMATCH; } -#endif static int get_physical_address (CPUState *env, target_ulong *physical, int *prot, target_ulong address, @@ -104,14 +129,9 @@ static int get_physical_address (CPUState *env, target_ulong *physical, if (address <= (int32_t)0x7FFFFFFFUL) { /* useg */ if (!(env->CP0_Status & (1 << CP0St_ERL) && user_mode)) { -#ifdef MIPS_USES_R4K_TLB - ret = map_address(env, physical, prot, address, rw, access_type); -#else - *physical = address + 0x40000000UL; - *prot = PAGE_READ | PAGE_WRITE; -#endif + ret = env->map_address(env, physical, prot, address, rw, access_type); } else { - *physical = address; + *physical = address & 0xFFFFFFFF; *prot = PAGE_READ | PAGE_WRITE; } #ifdef TARGET_MIPS64 @@ -123,14 +143,14 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else if (address < 0x3FFFFFFFFFFFFFFFULL) { /* xuseg */ if (UX && address < 0x000000FFFFFFFFFFULL) { - ret = map_address(env, physical, prot, address, rw, access_type); + ret = env->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } } else if (address < 0x7FFFFFFFFFFFFFFFULL) { /* xsseg */ if (SX && address < 0x400000FFFFFFFFFFULL) { - ret = map_address(env, physical, prot, address, rw, access_type); + ret = env->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } @@ -148,7 +168,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, /* xkseg */ /* XXX: check supervisor mode */ if (KX && address < 0xC00000FF7FFFFFFFULL) { - ret = map_address(env, physical, prot, address, rw, access_type); + ret = env->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } @@ -165,22 +185,12 @@ static int get_physical_address (CPUState *env, target_ulong *physical, *prot = PAGE_READ | PAGE_WRITE; } else if (address < (int32_t)0xE0000000UL) { /* kseg2 */ -#ifdef MIPS_USES_R4K_TLB - ret = map_address(env, physical, prot, address, rw, access_type); -#else - *physical = address & 0xFFFFFFFF; - *prot = PAGE_READ | PAGE_WRITE; -#endif + ret = env->map_address(env, physical, prot, address, rw, access_type); } else { /* kseg3 */ /* XXX: check supervisor mode */ /* XXX: debug segment is not emulated */ -#ifdef MIPS_USES_R4K_TLB - ret = map_address(env, physical, prot, address, rw, access_type); -#else - *physical = address & 0xFFFFFFFF; - *prot = PAGE_READ | PAGE_WRITE; -#endif + ret = env->map_address(env, physical, prot, address, rw, access_type); } #if 0 if (logfile) { @@ -483,15 +493,15 @@ void do_interrupt (CPUState *env) } #endif /* !defined(CONFIG_USER_ONLY) */ -void invalidate_tlb (CPUState *env, int idx, int use_extra) +void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) { - tlb_t *tlb; + r4k_tlb_t *tlb; target_ulong addr; target_ulong end; uint8_t ASID = env->CP0_EntryHi & 0xFF; target_ulong mask; - tlb = &env->tlb[idx]; + tlb = &env->mmu.r4k.tlb[idx]; /* The qemu TLB is flushed then the ASID changes, so no need to flush these entries again. */ if (tlb->G == 0 && tlb->ASID != ASID) { @@ -502,7 +512,7 @@ void invalidate_tlb (CPUState *env, int idx, int use_extra) /* For tlbwr, we can shadow the discarded entry into a new (fake) TLB entry, as long as the guest can not tell that it's there. */ - env->tlb[env->tlb_in_use] = *tlb; + env->mmu.r4k.tlb[env->tlb_in_use] = *tlb; env->tlb_in_use++; return; } diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 414f476db..6f012a964 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -6,8 +6,6 @@ /* real pages are variable size... */ #define TARGET_PAGE_BITS 12 -/* Uses MIPS R4Kc TLB model */ -#define MIPS_USES_R4K_TLB #define MIPS_TLB_MAX 128 #ifdef TARGET_MIPS64 diff --git a/target-mips/op.c b/target-mips/op.c index 748f997d2..a0611e01c 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1411,12 +1411,7 @@ void op_mtc0_ebase (void) void op_mtc0_config0 (void) { -#if defined(MIPS_USES_R4K_TLB) - /* Fixed mapping MMU not implemented */ - env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF88) | (T0 & 0x00000001); -#else - env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF88) | (T0 & 0x00000001); -#endif + env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (T0 & 0x00000001); RETURN(); } @@ -2680,31 +2675,29 @@ void op_bc1tany4 (void) RETURN(); } -#if defined(MIPS_USES_R4K_TLB) void op_tlbwi (void) { - CALL_FROM_TB0(do_tlbwi); + CALL_FROM_TB0(env->do_tlbwi); RETURN(); } void op_tlbwr (void) { - CALL_FROM_TB0(do_tlbwr); + CALL_FROM_TB0(env->do_tlbwr); RETURN(); } void op_tlbp (void) { - CALL_FROM_TB0(do_tlbp); + CALL_FROM_TB0(env->do_tlbp); RETURN(); } void op_tlbr (void) { - CALL_FROM_TB0(do_tlbr); + CALL_FROM_TB0(env->do_tlbr); RETURN(); } -#endif /* Specials */ #if defined (CONFIG_USER_ONLY) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 2ebcede65..9d7a56000 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -298,26 +298,6 @@ void do_mtc0_status_irqraise_debug (void) cpu_abort(env, "mtc0 status irqraise debug\n"); } -void do_tlbwi (void) -{ - cpu_abort(env, "tlbwi\n"); -} - -void do_tlbwr (void) -{ - cpu_abort(env, "tlbwr\n"); -} - -void do_tlbp (void) -{ - cpu_abort(env, "tlbp\n"); -} - -void do_tlbr (void) -{ - cpu_abort(env, "tlbr\n"); -} - void cpu_mips_tlb_flush (CPUState *env, int flush_global) { cpu_abort(env, "mips_tlb_flush\n"); @@ -389,7 +369,6 @@ void fpu_handle_exception(void) } /* TLB management */ -#if defined(MIPS_USES_R4K_TLB) void cpu_mips_tlb_flush (CPUState *env, int flush_global) { /* Flush qemu's TLB and discard all shadowed entries. */ @@ -397,20 +376,20 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) env->tlb_in_use = env->nb_tlb; } -static void mips_tlb_flush_extra (CPUState *env, int first) +static void r4k_mips_tlb_flush_extra (CPUState *env, int first) { /* Discard entries from env->tlb[first] onwards. */ while (env->tlb_in_use > first) { - invalidate_tlb(env, --env->tlb_in_use, 0); + r4k_invalidate_tlb(env, --env->tlb_in_use, 0); } } -static void fill_tlb (int idx) +static void r4k_fill_tlb (int idx) { - tlb_t *tlb; + r4k_tlb_t *tlb; /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ - tlb = &env->tlb[idx]; + tlb = &env->mmu.r4k.tlb[idx]; tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF; tlb->ASID = env->CP0_EntryHi & 0xFF; tlb->PageMask = env->CP0_PageMask; @@ -425,28 +404,28 @@ static void fill_tlb (int idx) tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; } -void do_tlbwi (void) +void r4k_do_tlbwi (void) { /* Discard cached TLB entries. We could avoid doing this if the tlbwi is just upgrading access permissions on the current entry; that might be a further win. */ - mips_tlb_flush_extra (env, env->nb_tlb); + r4k_mips_tlb_flush_extra (env, env->nb_tlb); - invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0); - fill_tlb(env->CP0_Index % env->nb_tlb); + r4k_invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0); + r4k_fill_tlb(env->CP0_Index % env->nb_tlb); } -void do_tlbwr (void) +void r4k_do_tlbwr (void) { int r = cpu_mips_get_random(env); - invalidate_tlb(env, r, 1); - fill_tlb(r); + r4k_invalidate_tlb(env, r, 1); + r4k_fill_tlb(r); } -void do_tlbp (void) +void r4k_do_tlbp (void) { - tlb_t *tlb; + r4k_tlb_t *tlb; target_ulong tag; uint8_t ASID; int i; @@ -454,7 +433,7 @@ void do_tlbp (void) tag = env->CP0_EntryHi & (int32_t)0xFFFFE000; ASID = env->CP0_EntryHi & 0xFF; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i]; + tlb = &env->mmu.r4k.tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { /* TLB match */ @@ -465,11 +444,11 @@ void do_tlbp (void) if (i == env->nb_tlb) { /* No match. Discard any shadow entries, if any of them match. */ for (i = env->nb_tlb; i < env->tlb_in_use; i++) { - tlb = &env->tlb[i]; + tlb = &env->mmu.r4k.tlb[i]; /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { - mips_tlb_flush_extra (env, i); + r4k_mips_tlb_flush_extra (env, i); break; } } @@ -478,19 +457,19 @@ void do_tlbp (void) } } -void do_tlbr (void) +void r4k_do_tlbr (void) { - tlb_t *tlb; + r4k_tlb_t *tlb; uint8_t ASID; ASID = env->CP0_EntryHi & 0xFF; - tlb = &env->tlb[env->CP0_Index % env->nb_tlb]; + tlb = &env->mmu.r4k.tlb[env->CP0_Index % env->nb_tlb]; /* If this will change the current ASID, flush qemu's TLB. */ if (ASID != tlb->ASID) cpu_mips_tlb_flush (env, 1); - mips_tlb_flush_extra(env, env->nb_tlb); + r4k_mips_tlb_flush_extra(env, env->nb_tlb); env->CP0_EntryHi = tlb->VPN | tlb->ASID; env->CP0_PageMask = tlb->PageMask; @@ -499,7 +478,6 @@ void do_tlbr (void) env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | (tlb->C1 << 3) | (tlb->PFN[1] >> 6); } -#endif #endif /* !CONFIG_USER_ONLY */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 79a33c5a5..fb802f0c6 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4164,7 +4164,7 @@ die: } #endif /* TARGET_MIPS64 */ -static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) +static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rd) { const char *opn = "ldst"; @@ -4199,24 +4199,30 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) opn = "dmtc0"; break; #endif -#if defined(MIPS_USES_R4K_TLB) case OPC_TLBWI: - gen_op_tlbwi(); opn = "tlbwi"; + if (!env->do_tlbwi) + goto die; + gen_op_tlbwi(); break; case OPC_TLBWR: - gen_op_tlbwr(); opn = "tlbwr"; + if (!env->do_tlbwr) + goto die; + gen_op_tlbwr(); break; case OPC_TLBP: - gen_op_tlbp(); opn = "tlbp"; + if (!env->do_tlbp) + goto die; + gen_op_tlbp(); break; case OPC_TLBR: - gen_op_tlbr(); opn = "tlbr"; + if (!env->do_tlbr) + goto die; + gen_op_tlbr(); break; -#endif case OPC_ERET: opn = "eret"; save_cpu_state(ctx, 0); @@ -4244,6 +4250,7 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) ctx->bstate = BS_EXCP; break; default: + die: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; @@ -5576,10 +5583,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_DMFC0: case OPC_DMTC0: #endif - gen_cp0(ctx, op1, rt, rd); + gen_cp0(env, ctx, op1, rt, rd); break; case OPC_C0_FIRST ... OPC_C0_LAST: - gen_cp0(ctx, MASK_C0(ctx->opcode), rt, rd); + gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); break; case OPC_MFMC0: op2 = MASK_MFMC0(ctx->opcode); diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index e38ab2882..7d60f19b2 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -148,7 +148,7 @@ static mips_def_t mips_defs[] = .Status_rw_bitmask = 0x3678FFFF, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | - (0x4 << FCR0_PRID) | (0x0 << FCR0_REV), + (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), }, #endif }; @@ -180,6 +180,30 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) } } +#ifndef CONFIG_USER_ONLY +static void no_mmu_init (CPUMIPSState *env, mips_def_t *def) +{ + env->nb_tlb = 1; + env->map_address = &no_mmu_map_address; +} + +static void fixed_mmu_init (CPUMIPSState *env, mips_def_t *def) +{ + env->nb_tlb = 1; + env->map_address = &fixed_mmu_map_address; +} + +static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def) +{ + env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); + env->map_address = &r4k_map_address; + env->do_tlbwi = r4k_do_tlbwi; + env->do_tlbwr = r4k_do_tlbwr; + env->do_tlbp = r4k_do_tlbp; + env->do_tlbr = r4k_do_tlbr; +} +#endif /* CONFIG_USER_ONLY */ + int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) { if (!def) @@ -199,10 +223,23 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CCRes = def->CCRes; env->Status_rw_bitmask = def->Status_rw_bitmask; env->fcr0 = def->CP1_fcr0; -#if defined (MIPS_USES_R4K_TLB) - env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); +#ifndef CONFIG_USER_ONLY + switch ((env->CP0_Config0 >> CP0C0_MT) & 3) { + case 0: + no_mmu_init(env, def); + break; + case 1: + r4k_mmu_init(env, def); + break; + case 3: + fixed_mmu_init(env, def); + break; + default: + /* Older CPUs like the R3000 may need nonstandard handling here. */ + cpu_abort(env, "MMU type not supported\n"); + } env->CP0_Random = env->nb_tlb - 1; env->tlb_in_use = env->nb_tlb; -#endif +#endif /* CONFIG_USER_ONLY */ return 0; } -- cgit v1.2.3 From 388bb21af622a413cc37f6df1f3ac5a92e951760 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 13:58:00 +0000 Subject: MIPS linux-user update. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2810 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 7 + linux-user/main.c | 104 +++++++----- linux-user/mips/syscall_nr.h | 380 +++++++++++++++++++++++-------------------- linux-user/signal.c | 80 +++++---- linux-user/syscall.c | 10 +- target-mips/cpu.h | 1 + 6 files changed, 321 insertions(+), 261 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 1256dba95..c1306929c 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -287,7 +287,11 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * #define elf_check_arch(x) ( (x) == EM_MIPS ) +#ifdef TARGET_MIPS64 +#define ELF_CLASS ELFCLASS64 +#else #define ELF_CLASS ELFCLASS32 +#endif #ifdef TARGET_WORDS_BIGENDIAN #define ELF_DATA ELFDATA2MSB #else @@ -302,6 +306,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->regs[29] = infop->start_stack; } +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + #endif /* TARGET_MIPS */ #ifdef TARGET_SH4 diff --git a/linux-user/main.c b/linux-user/main.c index d14b49916..ccb8c269d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1312,9 +1312,41 @@ static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_waitid , 4) MIPS_SYS(sys_ni_syscall , 0) /* available, was setaltroot */ MIPS_SYS(sys_add_key , 5) - MIPS_SYS(sys_request_key , 4) + MIPS_SYS(sys_request_key, 4) MIPS_SYS(sys_keyctl , 5) MIPS_SYS(sys_set_thread_area, 1) + MIPS_SYS(sys_inotify_init, 0) + MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */ + MIPS_SYS(sys_inotify_rm_watch, 2) + MIPS_SYS(sys_migrate_pages, 4) + MIPS_SYS(sys_openat, 4) + MIPS_SYS(sys_mkdirat, 3) + MIPS_SYS(sys_mknodat, 4) /* 4290 */ + MIPS_SYS(sys_fchownat, 5) + MIPS_SYS(sys_futimesat, 3) + MIPS_SYS(sys_fstatat64, 4) + MIPS_SYS(sys_unlinkat, 3) + MIPS_SYS(sys_renameat, 4) /* 4295 */ + MIPS_SYS(sys_linkat, 5) + MIPS_SYS(sys_symlinkat, 3) + MIPS_SYS(sys_readlinkat, 4) + MIPS_SYS(sys_fchmodat, 3) + MIPS_SYS(sys_faccessat, 3) /* 4300 */ + MIPS_SYS(sys_pselect6, 6) + MIPS_SYS(sys_ppoll, 5) + MIPS_SYS(sys_unshare, 1) + MIPS_SYS(sys_splice, 4) + MIPS_SYS(sys_sync_file_range, 7) /* 4305 */ + MIPS_SYS(sys_tee, 4) + MIPS_SYS(sys_vmsplice, 4) + MIPS_SYS(sys_move_pages, 6) + MIPS_SYS(sys_set_robust_list, 2) + MIPS_SYS(sys_get_robust_list, 3) /* 4310 */ + MIPS_SYS(sys_kexec_load, 4) + MIPS_SYS(sys_getcpu, 3) + MIPS_SYS(sys_epoll_pwait, 6) + MIPS_SYS(sys_ioprio_set, 3) + MIPS_SYS(sys_ioprio_get, 2) }; #undef MIPS_SYS @@ -1322,53 +1354,45 @@ static const uint8_t mips_syscall_args[] = { void cpu_loop(CPUMIPSState *env) { target_siginfo_t info; - int trapnr, ret, nb_args; + int trapnr, ret; unsigned int syscall_num; - target_ulong arg5, arg6, sp_reg; for(;;) { trapnr = cpu_mips_exec(env); switch(trapnr) { case EXCP_SYSCALL: - { - syscall_num = env->gpr[2] - 4000; - env->PC += 4; - if (syscall_num >= sizeof(mips_syscall_args)) { - ret = -ENOSYS; - } else { - nb_args = mips_syscall_args[syscall_num]; - if (nb_args >= 5) { - sp_reg = env->gpr[29]; - /* these arguments are taken from the stack */ - arg5 = tgetl(sp_reg + 16); - if (nb_args >= 6) { - arg6 = tgetl(sp_reg + 20); - } else { - arg6 = 0; - } - } else { - arg5 = 0; - arg6 = 0; - } - ret = do_syscall(env, - env->gpr[2], - env->gpr[4], - env->gpr[5], - env->gpr[6], - env->gpr[7], - arg5, - arg6); - } - if ((unsigned int)ret >= (unsigned int)(-1133)) { - env->gpr[7] = 1; /* error flag */ - ret = -ret; - env->gpr[0] = ret; - env->gpr[2] = ret; - } else { - env->gpr[7] = 0; /* error flag */ - env->gpr[2] = ret; + syscall_num = env->gpr[2] - 4000; + env->PC += 4; + if (syscall_num >= sizeof(mips_syscall_args)) { + ret = -ENOSYS; + } else { + int nb_args; + target_ulong sp_reg; + target_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; + + nb_args = mips_syscall_args[syscall_num]; + sp_reg = env->gpr[29]; + switch (nb_args) { + /* these arguments are taken from the stack */ + case 8: arg8 = tgetl(sp_reg + 28); + case 7: arg7 = tgetl(sp_reg + 24); + case 6: arg6 = tgetl(sp_reg + 20); + case 5: arg5 = tgetl(sp_reg + 16); + default: + break; } + ret = do_syscall(env, env->gpr[2], + env->gpr[4], env->gpr[5], + env->gpr[6], env->gpr[7], + arg5, arg6/*, arg7, arg8*/); + } + if ((unsigned int)ret >= (unsigned int)(-1133)) { + env->gpr[7] = 1; /* error flag */ + ret = -ret; + } else { + env->gpr[7] = 0; /* error flag */ } + env->gpr[2] = ret; break; case EXCP_TLBL: case EXCP_TLBS: diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h index e869bcdd6..f86f86a6e 100644 --- a/linux-user/mips/syscall_nr.h +++ b/linux-user/mips/syscall_nr.h @@ -2,45 +2,45 @@ * Linux o32 style syscalls are in the range from 4000 to 4999. */ #define TARGET_NR_Linux 4000 -#define TARGET_NR_syscall (TARGET_NR_Linux + 0) +#define TARGET_NR_syscall (TARGET_NR_Linux + 0) #define TARGET_NR_exit (TARGET_NR_Linux + 1) #define TARGET_NR_fork (TARGET_NR_Linux + 2) #define TARGET_NR_read (TARGET_NR_Linux + 3) #define TARGET_NR_write (TARGET_NR_Linux + 4) #define TARGET_NR_open (TARGET_NR_Linux + 5) #define TARGET_NR_close (TARGET_NR_Linux + 6) -#define TARGET_NR_waitpid (TARGET_NR_Linux + 7) +#define TARGET_NR_waitpid (TARGET_NR_Linux + 7) #define TARGET_NR_creat (TARGET_NR_Linux + 8) #define TARGET_NR_link (TARGET_NR_Linux + 9) -#define TARGET_NR_unlink (TARGET_NR_Linux + 10) -#define TARGET_NR_execve (TARGET_NR_Linux + 11) +#define TARGET_NR_unlink (TARGET_NR_Linux + 10) +#define TARGET_NR_execve (TARGET_NR_Linux + 11) #define TARGET_NR_chdir (TARGET_NR_Linux + 12) #define TARGET_NR_time (TARGET_NR_Linux + 13) #define TARGET_NR_mknod (TARGET_NR_Linux + 14) #define TARGET_NR_chmod (TARGET_NR_Linux + 15) -#define TARGET_NR_lchown32 (TARGET_NR_Linux + 16) +#define TARGET_NR_lchown32 (TARGET_NR_Linux + 16) #define TARGET_NR_break (TARGET_NR_Linux + 17) -#define TARGET_NR_unused18 (TARGET_NR_Linux + 18) +#define TARGET_NR_unused18 (TARGET_NR_Linux + 18) #define TARGET_NR_lseek (TARGET_NR_Linux + 19) -#define TARGET_NR_getpid (TARGET_NR_Linux + 20) +#define TARGET_NR_getpid (TARGET_NR_Linux + 20) #define TARGET_NR_mount (TARGET_NR_Linux + 21) -#define TARGET_NR_umount (TARGET_NR_Linux + 22) -#define TARGET_NR_setuid32 (TARGET_NR_Linux + 23) -#define TARGET_NR_getuid32 (TARGET_NR_Linux + 24) +#define TARGET_NR_umount (TARGET_NR_Linux + 22) +#define TARGET_NR_setuid32 (TARGET_NR_Linux + 23) +#define TARGET_NR_getuid32 (TARGET_NR_Linux + 24) #define TARGET_NR_stime (TARGET_NR_Linux + 25) -#define TARGET_NR_ptrace (TARGET_NR_Linux + 26) +#define TARGET_NR_ptrace (TARGET_NR_Linux + 26) #define TARGET_NR_alarm (TARGET_NR_Linux + 27) -#define TARGET_NR_unused28 (TARGET_NR_Linux + 28) +#define TARGET_NR_unused28 (TARGET_NR_Linux + 28) #define TARGET_NR_pause (TARGET_NR_Linux + 29) #define TARGET_NR_utime (TARGET_NR_Linux + 30) #define TARGET_NR_stty (TARGET_NR_Linux + 31) #define TARGET_NR_gtty (TARGET_NR_Linux + 32) -#define TARGET_NR_access (TARGET_NR_Linux + 33) +#define TARGET_NR_access (TARGET_NR_Linux + 33) #define TARGET_NR_nice (TARGET_NR_Linux + 34) #define TARGET_NR_ftime (TARGET_NR_Linux + 35) #define TARGET_NR_sync (TARGET_NR_Linux + 36) #define TARGET_NR_kill (TARGET_NR_Linux + 37) -#define TARGET_NR_rename (TARGET_NR_Linux + 38) +#define TARGET_NR_rename (TARGET_NR_Linux + 38) #define TARGET_NR_mkdir (TARGET_NR_Linux + 39) #define TARGET_NR_rmdir (TARGET_NR_Linux + 40) #define TARGET_NR_dup (TARGET_NR_Linux + 41) @@ -48,241 +48,273 @@ #define TARGET_NR_times (TARGET_NR_Linux + 43) #define TARGET_NR_prof (TARGET_NR_Linux + 44) #define TARGET_NR_brk (TARGET_NR_Linux + 45) -#define TARGET_NR_setgid32 (TARGET_NR_Linux + 46) -#define TARGET_NR_getgid32 (TARGET_NR_Linux + 47) -#define TARGET_NR_signal (TARGET_NR_Linux + 48) -#define TARGET_NR_geteuid32 (TARGET_NR_Linux + 49) -#define TARGET_NR_getegid32 (TARGET_NR_Linux + 50) +#define TARGET_NR_setgid32 (TARGET_NR_Linux + 46) +#define TARGET_NR_getgid32 (TARGET_NR_Linux + 47) +#define TARGET_NR_signal (TARGET_NR_Linux + 48) +#define TARGET_NR_geteuid32 (TARGET_NR_Linux + 49) +#define TARGET_NR_getegid32 (TARGET_NR_Linux + 50) #define TARGET_NR_acct (TARGET_NR_Linux + 51) -#define TARGET_NR_umount2 (TARGET_NR_Linux + 52) +#define TARGET_NR_umount2 (TARGET_NR_Linux + 52) #define TARGET_NR_lock (TARGET_NR_Linux + 53) #define TARGET_NR_ioctl (TARGET_NR_Linux + 54) #define TARGET_NR_fcntl (TARGET_NR_Linux + 55) #define TARGET_NR_mpx (TARGET_NR_Linux + 56) -#define TARGET_NR_setpgid (TARGET_NR_Linux + 57) -#define TARGET_NR_ulimit (TARGET_NR_Linux + 58) -#define TARGET_NR_unused59 (TARGET_NR_Linux + 59) +#define TARGET_NR_setpgid (TARGET_NR_Linux + 57) +#define TARGET_NR_ulimit (TARGET_NR_Linux + 58) +#define TARGET_NR_unused59 (TARGET_NR_Linux + 59) #define TARGET_NR_umask (TARGET_NR_Linux + 60) -#define TARGET_NR_chroot (TARGET_NR_Linux + 61) +#define TARGET_NR_chroot (TARGET_NR_Linux + 61) #define TARGET_NR_ustat (TARGET_NR_Linux + 62) #define TARGET_NR_dup2 (TARGET_NR_Linux + 63) -#define TARGET_NR_getppid (TARGET_NR_Linux + 64) -#define TARGET_NR_getpgrp (TARGET_NR_Linux + 65) -#define TARGET_NR_setsid (TARGET_NR_Linux + 66) -#define TARGET_NR_sigaction (TARGET_NR_Linux + 67) -#define TARGET_NR_sgetmask (TARGET_NR_Linux + 68) -#define TARGET_NR_ssetmask (TARGET_NR_Linux + 69) -#define TARGET_NR_setreuid32 (TARGET_NR_Linux + 70) -#define TARGET_NR_setregid32 (TARGET_NR_Linux + 71) -#define TARGET_NR_sigsuspend (TARGET_NR_Linux + 72) -#define TARGET_NR_sigpending (TARGET_NR_Linux + 73) +#define TARGET_NR_getppid (TARGET_NR_Linux + 64) +#define TARGET_NR_getpgrp (TARGET_NR_Linux + 65) +#define TARGET_NR_setsid (TARGET_NR_Linux + 66) +#define TARGET_NR_sigaction (TARGET_NR_Linux + 67) +#define TARGET_NR_sgetmask (TARGET_NR_Linux + 68) +#define TARGET_NR_ssetmask (TARGET_NR_Linux + 69) +#define TARGET_NR_setreuid32 (TARGET_NR_Linux + 70) +#define TARGET_NR_setregid32 (TARGET_NR_Linux + 71) +#define TARGET_NR_sigsuspend (TARGET_NR_Linux + 72) +#define TARGET_NR_sigpending (TARGET_NR_Linux + 73) #define TARGET_NR_sethostname (TARGET_NR_Linux + 74) -#define TARGET_NR_setrlimit (TARGET_NR_Linux + 75) -#define TARGET_NR_getrlimit (TARGET_NR_Linux + 76) -#define TARGET_NR_getrusage (TARGET_NR_Linux + 77) +#define TARGET_NR_setrlimit (TARGET_NR_Linux + 75) +#define TARGET_NR_getrlimit (TARGET_NR_Linux + 76) +#define TARGET_NR_getrusage (TARGET_NR_Linux + 77) #define TARGET_NR_gettimeofday (TARGET_NR_Linux + 78) #define TARGET_NR_settimeofday (TARGET_NR_Linux + 79) -#define TARGET_NR_getgroups32 (TARGET_NR_Linux + 80) -#define TARGET_NR_setgroups32 (TARGET_NR_Linux + 81) -#define TARGET_NR_reserved82 (TARGET_NR_Linux + 82) -#define TARGET_NR_symlink (TARGET_NR_Linux + 83) -#define TARGET_NR_unused84 (TARGET_NR_Linux + 84) -#define TARGET_NR_readlink (TARGET_NR_Linux + 85) -#define TARGET_NR_uselib (TARGET_NR_Linux + 86) -#define TARGET_NR_swapon (TARGET_NR_Linux + 87) -#define TARGET_NR_reboot (TARGET_NR_Linux + 88) -#define TARGET_NR_readdir (TARGET_NR_Linux + 89) +#define TARGET_NR_getgroups32 (TARGET_NR_Linux + 80) +#define TARGET_NR_setgroups32 (TARGET_NR_Linux + 81) +#define TARGET_NR_reserved82 (TARGET_NR_Linux + 82) +#define TARGET_NR_symlink (TARGET_NR_Linux + 83) +#define TARGET_NR_unused84 (TARGET_NR_Linux + 84) +#define TARGET_NR_readlink (TARGET_NR_Linux + 85) +#define TARGET_NR_uselib (TARGET_NR_Linux + 86) +#define TARGET_NR_swapon (TARGET_NR_Linux + 87) +#define TARGET_NR_reboot (TARGET_NR_Linux + 88) +#define TARGET_NR_readdir (TARGET_NR_Linux + 89) #define TARGET_NR_mmap (TARGET_NR_Linux + 90) -#define TARGET_NR_munmap (TARGET_NR_Linux + 91) -#define TARGET_NR_truncate (TARGET_NR_Linux + 92) -#define TARGET_NR_ftruncate (TARGET_NR_Linux + 93) -#define TARGET_NR_fchmod (TARGET_NR_Linux + 94) -#define TARGET_NR_fchown32 (TARGET_NR_Linux + 95) +#define TARGET_NR_munmap (TARGET_NR_Linux + 91) +#define TARGET_NR_truncate (TARGET_NR_Linux + 92) +#define TARGET_NR_ftruncate (TARGET_NR_Linux + 93) +#define TARGET_NR_fchmod (TARGET_NR_Linux + 94) +#define TARGET_NR_fchown32 (TARGET_NR_Linux + 95) #define TARGET_NR_getpriority (TARGET_NR_Linux + 96) #define TARGET_NR_setpriority (TARGET_NR_Linux + 97) -#define TARGET_NR_profil (TARGET_NR_Linux + 98) -#define TARGET_NR_statfs (TARGET_NR_Linux + 99) -#define TARGET_NR_fstatfs (TARGET_NR_Linux + 100) -#define TARGET_NR_ioperm (TARGET_NR_Linux + 101) -#define TARGET_NR_socketcall (TARGET_NR_Linux + 102) -#define TARGET_NR_syslog (TARGET_NR_Linux + 103) -#define TARGET_NR_setitimer (TARGET_NR_Linux + 104) -#define TARGET_NR_getitimer (TARGET_NR_Linux + 105) +#define TARGET_NR_profil (TARGET_NR_Linux + 98) +#define TARGET_NR_statfs (TARGET_NR_Linux + 99) +#define TARGET_NR_fstatfs (TARGET_NR_Linux + 100) +#define TARGET_NR_ioperm (TARGET_NR_Linux + 101) +#define TARGET_NR_socketcall (TARGET_NR_Linux + 102) +#define TARGET_NR_syslog (TARGET_NR_Linux + 103) +#define TARGET_NR_setitimer (TARGET_NR_Linux + 104) +#define TARGET_NR_getitimer (TARGET_NR_Linux + 105) #define TARGET_NR_stat (TARGET_NR_Linux + 106) #define TARGET_NR_lstat (TARGET_NR_Linux + 107) #define TARGET_NR_fstat (TARGET_NR_Linux + 108) -#define TARGET_NR_unused109 (TARGET_NR_Linux + 109) +#define TARGET_NR_unused109 (TARGET_NR_Linux + 109) #define TARGET_NR_iopl (TARGET_NR_Linux + 110) -#define TARGET_NR_vhangup (TARGET_NR_Linux + 111) +#define TARGET_NR_vhangup (TARGET_NR_Linux + 111) #define TARGET_NR_idle (TARGET_NR_Linux + 112) #define TARGET_NR_vm86 (TARGET_NR_Linux + 113) #define TARGET_NR_wait4 (TARGET_NR_Linux + 114) -#define TARGET_NR_swapoff (TARGET_NR_Linux + 115) -#define TARGET_NR_sysinfo (TARGET_NR_Linux + 116) +#define TARGET_NR_swapoff (TARGET_NR_Linux + 115) +#define TARGET_NR_sysinfo (TARGET_NR_Linux + 116) #define TARGET_NR_ipc (TARGET_NR_Linux + 117) #define TARGET_NR_fsync (TARGET_NR_Linux + 118) -#define TARGET_NR_sigreturn (TARGET_NR_Linux + 119) +#define TARGET_NR_sigreturn (TARGET_NR_Linux + 119) #define TARGET_NR_clone (TARGET_NR_Linux + 120) #define TARGET_NR_setdomainname (TARGET_NR_Linux + 121) #define TARGET_NR_uname (TARGET_NR_Linux + 122) -#define TARGET_NR_modify_ldt (TARGET_NR_Linux + 123) -#define TARGET_NR_adjtimex (TARGET_NR_Linux + 124) -#define TARGET_NR_mprotect (TARGET_NR_Linux + 125) +#define TARGET_NR_modify_ldt (TARGET_NR_Linux + 123) +#define TARGET_NR_adjtimex (TARGET_NR_Linux + 124) +#define TARGET_NR_mprotect (TARGET_NR_Linux + 125) #define TARGET_NR_sigprocmask (TARGET_NR_Linux + 126) #define TARGET_NR_create_module (TARGET_NR_Linux + 127) #define TARGET_NR_init_module (TARGET_NR_Linux + 128) #define TARGET_NR_delete_module (TARGET_NR_Linux + 129) -#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 130) -#define TARGET_NR_quotactl (TARGET_NR_Linux + 131) -#define TARGET_NR_getpgid (TARGET_NR_Linux + 132) -#define TARGET_NR_fchdir (TARGET_NR_Linux + 133) -#define TARGET_NR_bdflush (TARGET_NR_Linux + 134) +#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 130) +#define TARGET_NR_quotactl (TARGET_NR_Linux + 131) +#define TARGET_NR_getpgid (TARGET_NR_Linux + 132) +#define TARGET_NR_fchdir (TARGET_NR_Linux + 133) +#define TARGET_NR_bdflush (TARGET_NR_Linux + 134) #define TARGET_NR_sysfs (TARGET_NR_Linux + 135) #define TARGET_NR_personality (TARGET_NR_Linux + 136) #define TARGET_NR_afs_syscall (TARGET_NR_Linux + 137) /* Syscall for Andrew File System */ -#define TARGET_NR_setfsuid32 (TARGET_NR_Linux + 138) -#define TARGET_NR_setfsgid32 (TARGET_NR_Linux + 139) -#define TARGET_NR__llseek (TARGET_NR_Linux + 140) -#define TARGET_NR_getdents (TARGET_NR_Linux + 141) -#define TARGET_NR__newselect (TARGET_NR_Linux + 142) +#define TARGET_NR_setfsuid32 (TARGET_NR_Linux + 138) +#define TARGET_NR_setfsgid32 (TARGET_NR_Linux + 139) +#define TARGET_NR__llseek (TARGET_NR_Linux + 140) +#define TARGET_NR_getdents (TARGET_NR_Linux + 141) +#define TARGET_NR__newselect (TARGET_NR_Linux + 142) #define TARGET_NR_flock (TARGET_NR_Linux + 143) #define TARGET_NR_msync (TARGET_NR_Linux + 144) #define TARGET_NR_readv (TARGET_NR_Linux + 145) -#define TARGET_NR_writev (TARGET_NR_Linux + 146) -#define TARGET_NR_cacheflush (TARGET_NR_Linux + 147) -#define TARGET_NR_cachectl (TARGET_NR_Linux + 148) -#define TARGET_NR_sysmips (TARGET_NR_Linux + 149) -#define TARGET_NR_unused150 (TARGET_NR_Linux + 150) -#define TARGET_NR_getsid (TARGET_NR_Linux + 151) -#define TARGET_NR_fdatasync (TARGET_NR_Linux + 152) -#define TARGET_NR__sysctl (TARGET_NR_Linux + 153) +#define TARGET_NR_writev (TARGET_NR_Linux + 146) +#define TARGET_NR_cacheflush (TARGET_NR_Linux + 147) +#define TARGET_NR_cachectl (TARGET_NR_Linux + 148) +#define TARGET_NR_sysmips (TARGET_NR_Linux + 149) +#define TARGET_NR_unused150 (TARGET_NR_Linux + 150) +#define TARGET_NR_getsid (TARGET_NR_Linux + 151) +#define TARGET_NR_fdatasync (TARGET_NR_Linux + 152) +#define TARGET_NR__sysctl (TARGET_NR_Linux + 153) #define TARGET_NR_mlock (TARGET_NR_Linux + 154) -#define TARGET_NR_munlock (TARGET_NR_Linux + 155) -#define TARGET_NR_mlockall (TARGET_NR_Linux + 156) -#define TARGET_NR_munlockall (TARGET_NR_Linux + 157) -#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 158) -#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 159) -#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 160) -#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 161) +#define TARGET_NR_munlock (TARGET_NR_Linux + 155) +#define TARGET_NR_mlockall (TARGET_NR_Linux + 156) +#define TARGET_NR_munlockall (TARGET_NR_Linux + 157) +#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 158) +#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 159) +#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 160) +#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 161) #define TARGET_NR_sched_yield (TARGET_NR_Linux + 162) #define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 163) #define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 164) #define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 165) -#define TARGET_NR_nanosleep (TARGET_NR_Linux + 166) -#define TARGET_NR_mremap (TARGET_NR_Linux + 167) -#define TARGET_NR_accept (TARGET_NR_Linux + 168) +#define TARGET_NR_nanosleep (TARGET_NR_Linux + 166) +#define TARGET_NR_mremap (TARGET_NR_Linux + 167) +#define TARGET_NR_accept (TARGET_NR_Linux + 168) #define TARGET_NR_bind (TARGET_NR_Linux + 169) -#define TARGET_NR_connect (TARGET_NR_Linux + 170) +#define TARGET_NR_connect (TARGET_NR_Linux + 170) #define TARGET_NR_getpeername (TARGET_NR_Linux + 171) #define TARGET_NR_getsockname (TARGET_NR_Linux + 172) -#define TARGET_NR_getsockopt (TARGET_NR_Linux + 173) -#define TARGET_NR_listen (TARGET_NR_Linux + 174) +#define TARGET_NR_getsockopt (TARGET_NR_Linux + 173) +#define TARGET_NR_listen (TARGET_NR_Linux + 174) #define TARGET_NR_recv (TARGET_NR_Linux + 175) -#define TARGET_NR_recvfrom (TARGET_NR_Linux + 176) -#define TARGET_NR_recvmsg (TARGET_NR_Linux + 177) +#define TARGET_NR_recvfrom (TARGET_NR_Linux + 176) +#define TARGET_NR_recvmsg (TARGET_NR_Linux + 177) #define TARGET_NR_send (TARGET_NR_Linux + 178) -#define TARGET_NR_sendmsg (TARGET_NR_Linux + 179) -#define TARGET_NR_sendto (TARGET_NR_Linux + 180) -#define TARGET_NR_setsockopt (TARGET_NR_Linux + 181) -#define TARGET_NR_shutdown (TARGET_NR_Linux + 182) -#define TARGET_NR_socket (TARGET_NR_Linux + 183) -#define TARGET_NR_socketpair (TARGET_NR_Linux + 184) -#define TARGET_NR_setresuid32 (TARGET_NR_Linux + 185) -#define TARGET_NR_getresuid32 (TARGET_NR_Linux + 186) +#define TARGET_NR_sendmsg (TARGET_NR_Linux + 179) +#define TARGET_NR_sendto (TARGET_NR_Linux + 180) +#define TARGET_NR_setsockopt (TARGET_NR_Linux + 181) +#define TARGET_NR_shutdown (TARGET_NR_Linux + 182) +#define TARGET_NR_socket (TARGET_NR_Linux + 183) +#define TARGET_NR_socketpair (TARGET_NR_Linux + 184) +#define TARGET_NR_setresuid32 (TARGET_NR_Linux + 185) +#define TARGET_NR_getresuid32 (TARGET_NR_Linux + 186) #define TARGET_NR_query_module (TARGET_NR_Linux + 187) #define TARGET_NR_poll (TARGET_NR_Linux + 188) -#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 189) -#define TARGET_NR_setresgid32 (TARGET_NR_Linux + 190) -#define TARGET_NR_getresgid32 (TARGET_NR_Linux + 191) +#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 189) +#define TARGET_NR_setresgid32 (TARGET_NR_Linux + 190) +#define TARGET_NR_getresgid32 (TARGET_NR_Linux + 191) #define TARGET_NR_prctl (TARGET_NR_Linux + 192) #define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 193) #define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 194) -#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 195) +#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 195) #define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 196) -#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 197) -#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 198) +#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 197) +#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 198) #define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 199) -#define TARGET_NR_pread64 (TARGET_NR_Linux + 200) -#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 201) -#define TARGET_NR_chown32 (TARGET_NR_Linux + 202) -#define TARGET_NR_getcwd (TARGET_NR_Linux + 203) -#define TARGET_NR_capget (TARGET_NR_Linux + 204) -#define TARGET_NR_capset (TARGET_NR_Linux + 205) +#define TARGET_NR_pread64 (TARGET_NR_Linux + 200) +#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 201) +#define TARGET_NR_chown32 (TARGET_NR_Linux + 202) +#define TARGET_NR_getcwd (TARGET_NR_Linux + 203) +#define TARGET_NR_capget (TARGET_NR_Linux + 204) +#define TARGET_NR_capset (TARGET_NR_Linux + 205) #define TARGET_NR_sigaltstack (TARGET_NR_Linux + 206) -#define TARGET_NR_sendfile (TARGET_NR_Linux + 207) -#define TARGET_NR_getpmsg (TARGET_NR_Linux + 208) -#define TARGET_NR_putpmsg (TARGET_NR_Linux + 209) +#define TARGET_NR_sendfile (TARGET_NR_Linux + 207) +#define TARGET_NR_getpmsg (TARGET_NR_Linux + 208) +#define TARGET_NR_putpmsg (TARGET_NR_Linux + 209) #define TARGET_NR_mmap2 (TARGET_NR_Linux + 210) -#define TARGET_NR_truncate64 (TARGET_NR_Linux + 211) +#define TARGET_NR_truncate64 (TARGET_NR_Linux + 211) #define TARGET_NR_ftruncate64 (TARGET_NR_Linux + 212) -#define TARGET_NR_stat64 (TARGET_NR_Linux + 213) -#define TARGET_NR_lstat64 (TARGET_NR_Linux + 214) -#define TARGET_NR_fstat64 (TARGET_NR_Linux + 215) -#define TARGET_NR_pivot_root (TARGET_NR_Linux + 216) -#define TARGET_NR_mincore (TARGET_NR_Linux + 217) -#define TARGET_NR_madvise (TARGET_NR_Linux + 218) -#define TARGET_NR_getdents64 (TARGET_NR_Linux + 219) -#define TARGET_NR_fcntl64 (TARGET_NR_Linux + 220) +#define TARGET_NR_stat64 (TARGET_NR_Linux + 213) +#define TARGET_NR_lstat64 (TARGET_NR_Linux + 214) +#define TARGET_NR_fstat64 (TARGET_NR_Linux + 215) +#define TARGET_NR_pivot_root (TARGET_NR_Linux + 216) +#define TARGET_NR_mincore (TARGET_NR_Linux + 217) +#define TARGET_NR_madvise (TARGET_NR_Linux + 218) +#define TARGET_NR_getdents64 (TARGET_NR_Linux + 219) +#define TARGET_NR_fcntl64 (TARGET_NR_Linux + 220) #define TARGET_NR_reserved221 (TARGET_NR_Linux + 221) -#define TARGET_NR_gettid (TARGET_NR_Linux + 222) -#define TARGET_NR_readahead (TARGET_NR_Linux + 223) -#define TARGET_NR_setxattr (TARGET_NR_Linux + 224) -#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 225) -#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 226) -#define TARGET_NR_getxattr (TARGET_NR_Linux + 227) -#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 228) -#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 229) -#define TARGET_NR_listxattr (TARGET_NR_Linux + 230) -#define TARGET_NR_llistxattr (TARGET_NR_Linux + 231) -#define TARGET_NR_flistxattr (TARGET_NR_Linux + 232) +#define TARGET_NR_gettid (TARGET_NR_Linux + 222) +#define TARGET_NR_readahead (TARGET_NR_Linux + 223) +#define TARGET_NR_setxattr (TARGET_NR_Linux + 224) +#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 225) +#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 226) +#define TARGET_NR_getxattr (TARGET_NR_Linux + 227) +#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 228) +#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 229) +#define TARGET_NR_listxattr (TARGET_NR_Linux + 230) +#define TARGET_NR_llistxattr (TARGET_NR_Linux + 231) +#define TARGET_NR_flistxattr (TARGET_NR_Linux + 232) #define TARGET_NR_removexattr (TARGET_NR_Linux + 233) #define TARGET_NR_lremovexattr (TARGET_NR_Linux + 234) #define TARGET_NR_fremovexattr (TARGET_NR_Linux + 235) #define TARGET_NR_tkill (TARGET_NR_Linux + 236) -#define TARGET_NR_sendfile64 (TARGET_NR_Linux + 237) +#define TARGET_NR_sendfile64 (TARGET_NR_Linux + 237) #define TARGET_NR_futex (TARGET_NR_Linux + 238) -#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 239) -#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 240) -#define TARGET_NR_io_setup (TARGET_NR_Linux + 241) -#define TARGET_NR_io_destroy (TARGET_NR_Linux + 242) +#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 239) +#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 240) +#define TARGET_NR_io_setup (TARGET_NR_Linux + 241) +#define TARGET_NR_io_destroy (TARGET_NR_Linux + 242) #define TARGET_NR_io_getevents (TARGET_NR_Linux + 243) -#define TARGET_NR_io_submit (TARGET_NR_Linux + 244) -#define TARGET_NR_io_cancel (TARGET_NR_Linux + 245) -#define TARGET_NR_exit_group (TARGET_NR_Linux + 246) -#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 247) +#define TARGET_NR_io_submit (TARGET_NR_Linux + 244) +#define TARGET_NR_io_cancel (TARGET_NR_Linux + 245) +#define TARGET_NR_exit_group (TARGET_NR_Linux + 246) +#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 247) #define TARGET_NR_epoll_create (TARGET_NR_Linux + 248) -#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 249) -#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 250) -#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 251) -#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 252) -#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 253) -#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 254) -#define TARGET_NR_statfs64 (TARGET_NR_Linux + 255) -#define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 256) +#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 249) +#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 250) +#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 251) +#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 252) +#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 253) +#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 254) +#define TARGET_NR_statfs64 (TARGET_NR_Linux + 255) +#define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 256) #define TARGET_NR_timer_create (TARGET_NR_Linux + 257) #define TARGET_NR_timer_settime (TARGET_NR_Linux + 258) #define TARGET_NR_timer_gettime (TARGET_NR_Linux + 259) -#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 260) +#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 260) #define TARGET_NR_timer_delete (TARGET_NR_Linux + 261) #define TARGET_NR_clock_settime (TARGET_NR_Linux + 262) #define TARGET_NR_clock_gettime (TARGET_NR_Linux + 263) #define TARGET_NR_clock_getres (TARGET_NR_Linux + 264) -#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 265) -#define TARGET_NR_tgkill (TARGET_NR_Linux + 266) -#define TARGET_NR_utimes (TARGET_NR_Linux + 267) +#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 265) +#define TARGET_NR_tgkill (TARGET_NR_Linux + 266) +#define TARGET_NR_utimes (TARGET_NR_Linux + 267) #define TARGET_NR_mbind (TARGET_NR_Linux + 268) #define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 269) #define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 270) -#define TARGET_NR_mq_open (TARGET_NR_Linux + 271) -#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 272) +#define TARGET_NR_mq_open (TARGET_NR_Linux + 271) +#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 272) #define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 273) -#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 274) -#define TARGET_NR_mq_notify (TARGET_NR_Linux + 275) +#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 274) +#define TARGET_NR_mq_notify (TARGET_NR_Linux + 275) #define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 276) -#define TARGET_NR_vserver (TARGET_NR_Linux + 277) -#define TARGET_NR_waitid (TARGET_NR_Linux + 278) -/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 279) */ -#define TARGET_NR_add_key (TARGET_NR_Linux + 280) +#define TARGET_NR_vserver (TARGET_NR_Linux + 277) +#define TARGET_NR_waitid (TARGET_NR_Linux + 278) +/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 279) */ +#define TARGET_NR_add_key (TARGET_NR_Linux + 280) #define TARGET_NR_request_key (TARGET_NR_Linux + 281) -#define TARGET_NR_keyctl (TARGET_NR_Linux + 282) +#define TARGET_NR_keyctl (TARGET_NR_Linux + 282) #define TARGET_NR_set_thread_area (TARGET_NR_Linux + 283) +#define TARGET_NR_inotify_init (TARGET_NR_Linux + 284) +#define TARGET_NR_inotify_add_watch (TARGET_NR_Linux + 285) +#define TARGET_NR_inotify_rm_watch (TARGET_NR_Linux + 286) +#define TARGET_NR_migrate_pages (TARGET_NR_Linux + 287) +#define TARGET_NR_openat (TARGET_NR_Linux + 288) +#define TARGET_NR_mkdirat (TARGET_NR_Linux + 289) +#define TARGET_NR_mknodat (TARGET_NR_Linux + 290) +#define TARGET_NR_fchownat (TARGET_NR_Linux + 291) +#define TARGET_NR_futimesat (TARGET_NR_Linux + 292) +#define TARGET_NR_fstatat64 (TARGET_NR_Linux + 293) +#define TARGET_NR_unlinkat (TARGET_NR_Linux + 294) +#define TARGET_NR_renameat (TARGET_NR_Linux + 295) +#define TARGET_NR_linkat (TARGET_NR_Linux + 296) +#define TARGET_NR_symlinkat (TARGET_NR_Linux + 297) +#define TARGET_NR_readlinkat (TARGET_NR_Linux + 298) +#define TARGET_NR_fchmodat (TARGET_NR_Linux + 299) +#define TARGET_NR_faccessat (TARGET_NR_Linux + 300) +#define TARGET_NR_pselect6 (TARGET_NR_Linux + 301) +#define TARGET_NR_ppoll (TARGET_NR_Linux + 302) +#define TARGET_NR_unshare (TARGET_NR_Linux + 303) +#define TARGET_NR_splice (TARGET_NR_Linux + 304) +#define TARGET_NR_sync_file_range (TARGET_NR_Linux + 305) +#define TARGET_NR_tee (TARGET_NR_Linux + 306) +#define TARGET_NR_vmsplice (TARGET_NR_Linux + 307) +#define TARGET_NR_move_pages (TARGET_NR_Linux + 308) +#define TARGET_NR_set_robust_list (TARGET_NR_Linux + 309) +#define TARGET_NR_get_robust_list (TARGET_NR_Linux + 310) +#define TARGET_NR_kexec_load (TARGET_NR_Linux + 311) +#define TARGET_NR_getcpu (TARGET_NR_Linux + 312) +#define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 313) +#define TARGET_NR_ioprio_set (TARGET_NR_Linux + 314) +#define TARGET_NR_ioprio_get (TARGET_NR_Linux + 315) diff --git a/linux-user/signal.c b/linux-user/signal.c index 5a99e610d..5b1334a1c 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -432,17 +432,17 @@ int do_sigaction(int sig, const struct target_sigaction *act, if (oact) { oact->_sa_handler = tswapl(k->sa._sa_handler); oact->sa_flags = tswapl(k->sa.sa_flags); - #if !defined(TARGET_MIPS) - oact->sa_restorer = tswapl(k->sa.sa_restorer); - #endif +#if !defined(TARGET_MIPS) + oact->sa_restorer = tswapl(k->sa.sa_restorer); +#endif oact->sa_mask = k->sa.sa_mask; } if (act) { k->sa._sa_handler = tswapl(act->_sa_handler); k->sa.sa_flags = tswapl(act->sa_flags); - #if !defined(TARGET_MIPS) - k->sa.sa_restorer = tswapl(act->sa_restorer); - #endif +#if !defined(TARGET_MIPS) + k->sa.sa_restorer = tswapl(act->sa_restorer); +#endif k->sa.sa_mask = act->sa_mask; /* we update the host linux signal state */ @@ -1684,8 +1684,8 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) err |= __put_user(regs->PC, &sc->sc_pc); - #define save_gp_reg(i) do { \ - err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \ +#define save_gp_reg(i) do { \ + err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \ } while(0) __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); @@ -1696,7 +1696,7 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); save_gp_reg(31); - #undef save_gp_reg +#undef save_gp_reg err |= __put_user(regs->HI, &sc->sc_mdhi); err |= __put_user(regs->LO, &sc->sc_mdlo); @@ -1713,7 +1713,7 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); } /* same with 64 bit */ - #ifdef CONFIG_64BIT +#ifdef CONFIG_64BIT err |= __put_user(regs->hi, &sc->sc_hi[0]); err |= __put_user(regs->lo, &sc->sc_lo[0]); if (cpu_has_dsp) { @@ -1725,13 +1725,10 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) err |= __put_user(mflo3(), &sc->sc_lo[3]); err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); } - #endif - - - #endif - +#endif +#endif - #if 0 +#if 0 err |= __put_user(!!used_math(), &sc->sc_used_math); if (!used_math()) @@ -1765,7 +1762,7 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) err |= __get_user(regs->HI, &sc->sc_mdhi); err |= __get_user(regs->LO, &sc->sc_mdlo); - #define restore_gp_reg(i) do { \ +#define restore_gp_reg(i) do { \ err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \ } while(0) restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); @@ -1779,7 +1776,7 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); restore_gp_reg(31); - #undef restore_gp_reg +#undef restore_gp_reg #if 0 if (cpu_has_dsp) { @@ -1791,7 +1788,7 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); } - #ifdef CONFIG_64BIT +#ifdef CONFIG_64BIT err |= __get_user(regs->hi, &sc->sc_hi[0]); err |= __get_user(regs->lo, &sc->sc_lo[0]); if (cpu_has_dsp) { @@ -1803,7 +1800,7 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg); err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); } - #endif +#endif err |= __get_user(used_math, &sc->sc_used_math); conditional_used_math(used_math); @@ -1898,51 +1895,50 @@ give_sigsegv: long do_sigreturn(CPUState *regs) { - struct sigframe *frame; - sigset_t blocked; - target_sigset_t target_set; - int i; + struct sigframe *frame; + sigset_t blocked; + target_sigset_t target_set; + int i; #if defined(DEBUG_SIGNAL) - fprintf(stderr, "do_sigreturn\n"); + fprintf(stderr, "do_sigreturn\n"); #endif - frame = (struct sigframe *) regs->gpr[29]; - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + frame = (struct sigframe *) regs->gpr[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; - for(i = 0; i < TARGET_NSIG_WORDS; i++) { + for(i = 0; i < TARGET_NSIG_WORDS; i++) { if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i])) goto badframe; - } + } - target_to_host_sigset_internal(&blocked, &target_set); - sigprocmask(SIG_SETMASK, &blocked, NULL); + target_to_host_sigset_internal(&blocked, &target_set); + sigprocmask(SIG_SETMASK, &blocked, NULL); - if (restore_sigcontext(regs, &frame->sf_sc)) + if (restore_sigcontext(regs, &frame->sf_sc)) goto badframe; #if 0 - /* - * Don't let your children do this ... - */ - __asm__ __volatile__( + /* + * Don't let your children do this ... + */ + __asm__ __volatile__( "move\t$29, %0\n\t" "j\tsyscall_exit" :/* no outputs */ :"r" (®s)); - /* Unreached */ + /* Unreached */ #endif regs->PC = regs->CP0_EPC; - /* I am not sure this is right, but it seems to work + /* I am not sure this is right, but it seems to work * maybe a problem with nested signals ? */ regs->CP0_EPC = 0; return 0; badframe: - force_sig(TARGET_SIGSEGV/*, current*/); - return 0; - + force_sig(TARGET_SIGSEGV/*, current*/); + return 0; } static void setup_rt_frame(int sig, struct emulated_sigaction *ka, @@ -2070,5 +2066,3 @@ void process_pending_signals(void *cpu_env) if (q != &k->info) free_sigqueue(q); } - - diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 78d8dfaa8..abefe856b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1750,7 +1750,9 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) new_env->dregs[0] = 0; /* ??? is this sufficient? */ #elif defined(TARGET_MIPS) - printf ("HELPME: %s:%d\n", __FILE__, __LINE__); + if (!newsp) + newsp = env->gpr[29]; + new_env->gpr[29] = newsp; #elif defined(TARGET_PPC) if (!newsp) newsp = env->gpr[1]; @@ -2429,7 +2431,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #ifdef TARGET_NR_sigaction case TARGET_NR_sigaction: { - #if !defined(TARGET_MIPS) +#if !defined(TARGET_MIPS) struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; if (arg2) { @@ -2452,7 +2454,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, old_act->sa_restorer = oact.sa_restorer; unlock_user_struct(old_act, arg3, 1); } - #else +#else struct target_sigaction act, oact, *pact, *old_act; if (arg2) { @@ -2478,7 +2480,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, old_act->sa_mask.sig[3] = 0; unlock_user_struct(old_act, arg3, 1); } - #endif +#endif } break; #endif diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 9e029199b..d127d00e8 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -372,5 +372,6 @@ enum { int cpu_mips_exec(CPUMIPSState *s); CPUMIPSState *cpu_mips_init(void); uint32_t cpu_mips_get_clock (void); +int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); #endif /* !defined (__MIPS_CPU_H__) */ -- cgit v1.2.3 From f2e9ebef12c6f00d650eb06f33dbdd06db0919f2 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 14:07:26 +0000 Subject: MMU code improvements, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2811 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 22 ++++++++++------------ target-mips/op.c | 2 +- target-mips/op_helper.c | 18 +++++++++++++----- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index cb568f11a..484834a59 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -73,19 +73,18 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, for (i = 0; i < env->tlb_in_use; i++) { r4k_tlb_t *tlb = &env->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ - target_ulong mask = tlb->PageMask | 0x1FFF; + target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); target_ulong tag = address & ~mask; - int n; + target_ulong VPN = tlb->VPN & ~mask; /* Check ASID, virtual page number & size */ - if ((tlb->G == 1 || tlb->ASID == ASID) && - tlb->VPN == tag) { + if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { /* TLB match */ - n = !!(address & mask & ~(mask >> 1)); + int n = !!(address & mask & ~(mask >> 1)); /* Check access rights */ - if (!(n ? tlb->V1 : tlb->V0)) + if (!(n ? tlb->V1 : tlb->V0)) return TLBRET_INVALID; - if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { + if (rw == 0 || (n ? tlb->D1 : tlb->D0)) { *physical = tlb->PFN[n] | (address & (mask >> 1)); *prot = PAGE_READ; if (n ? tlb->D1 : tlb->D0) @@ -502,7 +501,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) target_ulong mask; tlb = &env->mmu.r4k.tlb[idx]; - /* The qemu TLB is flushed then the ASID changes, so no need to + /* The qemu TLB is flushed when the ASID changes, so no need to flush these entries again. */ if (tlb->G == 0 && tlb->ASID != ASID) { return; @@ -518,9 +517,9 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) } /* 1k pages are not supported. */ - mask = tlb->PageMask | 0x1FFF; + mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); if (tlb->V0) { - addr = tlb->VPN; + addr = tlb->VPN & ~mask; end = addr | (mask >> 1); while (addr < end) { tlb_flush_page (env, addr); @@ -528,8 +527,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) } } if (tlb->V1) { - addr = tlb->VPN | ((mask >> 1) + 1); - addr = tlb->VPN + TARGET_PAGE_SIZE; + addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); end = addr | mask; while (addr < end) { tlb_flush_page (env, addr); diff --git a/target-mips/op.c b/target-mips/op.c index a0611e01c..835b02a64 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1283,7 +1283,7 @@ void op_mtc0_context (void) void op_mtc0_pagemask (void) { /* 1k pages not implemented */ - env->CP0_PageMask = T0 & 0x1FFFE000; + env->CP0_PageMask = T0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9d7a56000..895ca7ff8 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -390,7 +390,7 @@ static void r4k_fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->mmu.r4k.tlb[idx]; - tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF; + tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); tlb->ASID = env->CP0_EntryHi & 0xFF; tlb->PageMask = env->CP0_PageMask; tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; @@ -426,16 +426,21 @@ void r4k_do_tlbwr (void) void r4k_do_tlbp (void) { r4k_tlb_t *tlb; + target_ulong mask; target_ulong tag; + target_ulong VPN; uint8_t ASID; int i; - tag = env->CP0_EntryHi & (int32_t)0xFFFFE000; ASID = env->CP0_EntryHi & 0xFF; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->mmu.r4k.tlb[i]; + /* 1k pages are not supported. */ + mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); + tag = env->CP0_EntryHi & ~mask; + VPN = tlb->VPN & ~mask; /* Check ASID, virtual page number & size */ - if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { + if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { /* TLB match */ env->CP0_Index = i; break; @@ -445,9 +450,12 @@ void r4k_do_tlbp (void) /* No match. Discard any shadow entries, if any of them match. */ for (i = env->nb_tlb; i < env->tlb_in_use; i++) { tlb = &env->mmu.r4k.tlb[i]; - + /* 1k pages are not supported. */ + mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); + tag = env->CP0_EntryHi & ~mask; + VPN = tlb->VPN & ~mask; /* Check ASID, virtual page number & size */ - if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) { + if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { r4k_mips_tlb_flush_extra (env, i); break; } -- cgit v1.2.3 From 703eaf379ed63da63b0929e12137ad4edab9899d Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 14:42:18 +0000 Subject: Don't decode CP0 XContext on 32bit MIPS. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2812 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index fb802f0c6..98794504f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2190,10 +2190,11 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: - /* 64 bit MMU only */ +#ifdef TARGET_MIPS64 gen_op_mfc0_xcontext(); rn = "XContext"; break; +#endif default: goto die; } @@ -2788,10 +2789,11 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: - /* 64 bit MMU only */ +#ifdef TARGET_MIPS64 /* Nothing writable in lower 32 bits */ rn = "XContext"; break; +#endif default: goto die; } @@ -3377,10 +3379,11 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: - /* 64 bit MMU only */ +#ifdef TARGET_MIPS64 gen_op_dmfc0_xcontext(); rn = "XContext"; break; +#endif default: goto die; } @@ -3966,10 +3969,11 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: - /* 64 bit MMU only */ +#ifdef TARGET_MIPS64 gen_op_dmtc0_xcontext(); rn = "XContext"; break; +#endif default: goto die; } -- cgit v1.2.3 From 72d46479da2ab00dfe43fa56fd2c900377b7d458 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 14:54:54 +0000 Subject: Windows: redirect serial port to console, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2813 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 2a864ba87..fededf20e 100644 --- a/vl.c +++ b/vl.c @@ -2420,7 +2420,12 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) qemu_chr_reset(chr); return chr; } - + +static CharDriverState *qemu_chr_open_win_con(const char *filename) +{ + return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); +} + static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) { HANDLE fd_out; @@ -2962,6 +2967,9 @@ CharDriverState *qemu_chr_open(const char *filename) if (strstart(filename, "pipe:", &p)) { return qemu_chr_open_win_pipe(p); } else + if (strstart(filename, "con:", NULL)) { + return qemu_chr_open_win_con(filename); + } else if (strstart(filename, "file:", &p)) { return qemu_chr_open_win_file_out(p); } -- cgit v1.2.3 From 7b62f20c085ca13cbab84a07b0f52e5582a5c450 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 15:29:26 +0000 Subject: Delete misleading comment. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2814 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 835b02a64..10a9b2760 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -938,8 +938,6 @@ OP_COND(lez, (int32_t)T0 <= 0); OP_COND(ltz, (int32_t)T0 < 0); /* Branches */ -//#undef USE_DIRECT_JUMP - void OPPROTO op_goto_tb0(void) { GOTO_TB(op_goto_tb0, PARAM1, 0); -- cgit v1.2.3 From f09111e0886d16425fa59ec11cfb3293095cb06c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 16:33:43 +0000 Subject: Fix XHACK() macro and use FREG if possible, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2815 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index d53e28bd2..c70288ebf 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -236,7 +236,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) ? (x) + 16 : (x)) #define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x)) -#define XHACK(x) (((x) & 1 ) << 4 | ((x) & 0xe ) << 1) +#define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe)) #define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x)) #define CHECK_NOT_DELAY_SLOT \ @@ -685,7 +685,7 @@ void decode_opc(DisasContext * ctx) } else { gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfl_T0_FT0(ctx); - gen_op_fmov_FT0_frN(XREG(B11_8)); + gen_op_fmov_FT0_frN(FREG(B11_8)); } return; case 0xf009: /* fmov @Rm+,{F,D,X}Rn */ @@ -704,7 +704,7 @@ void decode_opc(DisasContext * ctx) } else { gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfl_T0_FT0(ctx); - gen_op_fmov_FT0_frN(XREG(B11_8)); + gen_op_fmov_FT0_frN(FREG(B11_8)); gen_op_inc4_rN(REG(B7_4)); } return; @@ -745,7 +745,7 @@ void decode_opc(DisasContext * ctx) gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); gen_op_ldfl_T0_FT0(ctx); - gen_op_fmov_FT0_frN(XREG(B11_8)); + gen_op_fmov_FT0_frN(FREG(B11_8)); } return; case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) */ -- cgit v1.2.3 From a5d251bd7e5ad862146f2f94d912bd52149843fa Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 16:35:35 +0000 Subject: Remove unnecessary pointer magic in shift operations, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2816 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/op.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-sh4/op.c b/target-sh4/op.c index 758aa53b7..1b52e8103 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -561,14 +561,14 @@ void OPPROTO op_shal_Rn(void) void OPPROTO op_shar_Rn(void) { cond_t(env->gregs[PARAM1] & 1); - *(int32_t *) & env->gregs[PARAM1] >>= 1; + env->gregs[PARAM1] >>= 1; RETURN(); } void OPPROTO op_shlr_Rn(void) { cond_t(env->gregs[PARAM1] & 1); - *(uint32_t *) & env->gregs[PARAM1] >>= 1; + env->gregs[PARAM1] >>= 1; RETURN(); } @@ -592,19 +592,19 @@ void OPPROTO op_shll16_Rn(void) void OPPROTO op_shlr2_Rn(void) { - *(uint32_t *) & env->gregs[PARAM1] >>= 2; + env->gregs[PARAM1] >>= 2; RETURN(); } void OPPROTO op_shlr8_Rn(void) { - *(uint32_t *) & env->gregs[PARAM1] >>= 8; + env->gregs[PARAM1] >>= 8; RETURN(); } void OPPROTO op_shlr16_Rn(void) { - *(uint32_t *) & env->gregs[PARAM1] >>= 16; + env->gregs[PARAM1] >>= 16; RETURN(); } -- cgit v1.2.3 From 6ef99fc59c74a3fde6daaa005ff8a6159b720105 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 16:36:24 +0000 Subject: Add fpu register support to the gdb code, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2817 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 62c1db297..7dcaade66 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -657,6 +657,9 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } } #elif defined (TARGET_SH4) + +/* Hint: Use "set architecture sh4" in GDB to see fpu registers */ + static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { uint32_t *ptr = (uint32_t *)mem_buf; @@ -676,12 +679,14 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) SAVE (env->mach); SAVE (env->macl); SAVE (env->sr); - SAVE (0); /* TICKS */ - SAVE (0); /* STALLS */ - SAVE (0); /* CYCLES */ - SAVE (0); /* INSTS */ - SAVE (0); /* PLR */ - + SAVE (env->fpul); + SAVE (env->fpscr); + for (i = 0; i < 16; i++) + SAVE(env->fregs[i + ((env->fpscr & FPSCR_FR) ? 16 : 0)]); + SAVE (env->ssr); + SAVE (env->spc); + for (i = 0; i < 8; i++) SAVE(env->gregs[i]); + for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]); return ((uint8_t *)ptr - mem_buf); } @@ -704,6 +709,14 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) LOAD (env->mach); LOAD (env->macl); LOAD (env->sr); + LOAD (env->fpul); + LOAD (env->fpscr); + for (i = 0; i < 16; i++) + LOAD(env->fregs[i + ((env->fpscr & FPSCR_FR) ? 16 : 0)]); + LOAD (env->ssr); + LOAD (env->spc); + for (i = 0; i < 8; i++) LOAD(env->gregs[i]); + for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]); } #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) -- cgit v1.2.3 From 6b4d2ba13f597328161b1156e1fe0df820a90df2 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 18:02:43 +0000 Subject: Support OSS on solaris, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2818 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index 65fdeed9d..7436c5fc7 100755 --- a/configure +++ b/configure @@ -157,6 +157,9 @@ SunOS) kqemu="yes" fi fi + if test -f /usr/include/sys/soundcard.h ; then + oss=yes + fi ;; *) oss="yes" @@ -667,6 +670,7 @@ else fmod_support="" fi echo "FMOD support $fmod $fmod_support" +echo "OSS support $oss" if test -n "$sparc_cpu"; then echo "Target Sparc Arch $sparc_cpu" fi -- cgit v1.2.3 From f1b0aa5de7f48650aa6260d5dfb8ece1899e286c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 18:39:10 +0000 Subject: Fix mfc0 and dmtc0 instructions on MIPS64, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2819 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 78 +++++++-------------------------- target-mips/translate.c | 114 ++++++++++++++++++++++++------------------------ 2 files changed, 72 insertions(+), 120 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 10a9b2760..a820aad7b 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1260,7 +1260,7 @@ void op_mtc0_entrylo0 (void) { /* Large physaddr not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo0 = (int32_t)T0 & 0x3FFFFFFF; + env->CP0_EntryLo0 = T0 & 0x3FFFFFFF; RETURN(); } @@ -1268,7 +1268,7 @@ void op_mtc0_entrylo1 (void) { /* Large physaddr not implemented */ /* 1k pages not implemented */ - env->CP0_EntryLo1 = (int32_t)T0 & 0x3FFFFFFF; + env->CP0_EntryLo1 = T0 & 0x3FFFFFFF; RETURN(); } @@ -1338,9 +1338,9 @@ void op_mtc0_status (void) uint32_t val, old; uint32_t mask = env->Status_rw_bitmask; - /* No reverse endianness, no MDMX/DSP, no 64bit ops, - no 64bit addressing implemented. */ - val = (int32_t)T0 & mask; + /* No reverse endianness, no MDMX/DSP, no 64bit ops + implemented. */ + val = T0 & mask; old = env->CP0_Status; if (!(val & (1 << CP0St_EXL)) && !(val & (1 << CP0St_ERL)) && @@ -1395,7 +1395,7 @@ void op_mtc0_cause (void) void op_mtc0_epc (void) { - env->CP0_EPC = (int32_t)T0; + env->CP0_EPC = T0; RETURN(); } @@ -1424,7 +1424,7 @@ void op_mtc0_watchlo0 (void) { /* Watch exceptions for instructions, data loads, data stores not implemented. */ - env->CP0_WatchLo = (int32_t)(T0 & ~0x7); + env->CP0_WatchLo = (T0 & ~0x7); RETURN(); } @@ -1453,7 +1453,7 @@ void op_mtc0_debug (void) void op_mtc0_depc (void) { - env->CP0_DEPC = (int32_t)T0; + env->CP0_DEPC = T0; RETURN(); } @@ -1489,7 +1489,7 @@ void op_mtc0_datahi (void) void op_mtc0_errorepc (void) { - env->CP0_ErrorEPC = (int32_t)T0; + env->CP0_ErrorEPC = T0; RETURN(); } @@ -1500,6 +1500,12 @@ void op_mtc0_desave (void) } #ifdef TARGET_MIPS64 +void op_mtc0_xcontext (void) +{ + env->CP0_XContext = (env->CP0_XContext & 0x1ffffffffULL) | (T0 & ~0x1ffffffffULL); + RETURN(); +} + void op_dmfc0_entrylo0 (void) { T0 = env->CP0_EntryLo0; @@ -1565,60 +1571,6 @@ void op_dmfc0_errorepc (void) T0 = env->CP0_ErrorEPC; RETURN(); } - -void op_dmtc0_entrylo0 (void) -{ - /* Large physaddr not implemented */ - /* 1k pages not implemented */ - env->CP0_EntryLo0 = T0 & 0x3FFFFFFF; - RETURN(); -} - -void op_dmtc0_entrylo1 (void) -{ - /* Large physaddr not implemented */ - /* 1k pages not implemented */ - env->CP0_EntryLo1 = T0 & 0x3FFFFFFF; - RETURN(); -} - -void op_dmtc0_context (void) -{ - env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (T0 & ~0x007FFFFF); - RETURN(); -} - -void op_dmtc0_epc (void) -{ - env->CP0_EPC = T0; - RETURN(); -} - -void op_dmtc0_watchlo0 (void) -{ - /* Watch exceptions for instructions, data loads, data stores - not implemented. */ - env->CP0_WatchLo = T0 & ~0x7; - RETURN(); -} - -void op_dmtc0_xcontext (void) -{ - env->CP0_XContext = (env->CP0_XContext & 0xffffffff) | (T0 & ~0xffffffff); - RETURN(); -} - -void op_dmtc0_depc (void) -{ - env->CP0_DEPC = T0; - RETURN(); -} - -void op_dmtc0_errorepc (void) -{ - env->CP0_ErrorEPC = T0; - RETURN(); -} #endif /* TARGET_MIPS64 */ /* CP1 functions */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 98794504f..410560c28 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2790,7 +2790,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) switch (sel) { case 0: #ifdef TARGET_MIPS64 - /* Nothing writable in lower 32 bits */ + gen_op_mtc0_xcontext(); rn = "XContext"; break; #endif @@ -3583,15 +3583,15 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_dmtc0_mvpcontrol(); /* MT ASE */ +// gen_op_mtc0_mvpcontrol(); /* MT ASE */ rn = "MVPControl"; // break; case 2: -// gen_op_dmtc0_mvpconf0(); /* MT ASE */ +// gen_op_mtc0_mvpconf0(); /* MT ASE */ rn = "MVPConf0"; // break; case 3: -// gen_op_dmtc0_mvpconf1(); /* MT ASE */ +// gen_op_mtc0_mvpconf1(); /* MT ASE */ rn = "MVPConf1"; // break; default: @@ -3605,31 +3605,31 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_dmtc0_vpecontrol(); /* MT ASE */ +// gen_op_mtc0_vpecontrol(); /* MT ASE */ rn = "VPEControl"; // break; case 2: -// gen_op_dmtc0_vpeconf0(); /* MT ASE */ +// gen_op_mtc0_vpeconf0(); /* MT ASE */ rn = "VPEConf0"; // break; case 3: -// gen_op_dmtc0_vpeconf1(); /* MT ASE */ +// gen_op_mtc0_vpeconf1(); /* MT ASE */ rn = "VPEConf1"; // break; case 4: -// gen_op_dmtc0_YQMask(); /* MT ASE */ +// gen_op_mtc0_YQMask(); /* MT ASE */ rn = "YQMask"; // break; case 5: -// gen_op_dmtc0_vpeschedule(); /* MT ASE */ +// gen_op_mtc0_vpeschedule(); /* MT ASE */ rn = "VPESchedule"; // break; case 6: -// gen_op_dmtc0_vpeschefback(); /* MT ASE */ +// gen_op_mtc0_vpeschefback(); /* MT ASE */ rn = "VPEScheFBack"; // break; case 7: -// gen_op_dmtc0_vpeopt(); /* MT ASE */ +// gen_op_mtc0_vpeopt(); /* MT ASE */ rn = "VPEOpt"; // break; default: @@ -3639,35 +3639,35 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 2: switch (sel) { case 0: - gen_op_dmtc0_entrylo0(); + gen_op_mtc0_entrylo0(); rn = "EntryLo0"; break; case 1: -// gen_op_dmtc0_tcstatus(); /* MT ASE */ +// gen_op_mtc0_tcstatus(); /* MT ASE */ rn = "TCStatus"; // break; case 2: -// gen_op_dmtc0_tcbind(); /* MT ASE */ +// gen_op_mtc0_tcbind(); /* MT ASE */ rn = "TCBind"; // break; case 3: -// gen_op_dmtc0_tcrestart(); /* MT ASE */ +// gen_op_mtc0_tcrestart(); /* MT ASE */ rn = "TCRestart"; // break; case 4: -// gen_op_dmtc0_tchalt(); /* MT ASE */ +// gen_op_mtc0_tchalt(); /* MT ASE */ rn = "TCHalt"; // break; case 5: -// gen_op_dmtc0_tccontext(); /* MT ASE */ +// gen_op_mtc0_tccontext(); /* MT ASE */ rn = "TCContext"; // break; case 6: -// gen_op_dmtc0_tcschedule(); /* MT ASE */ +// gen_op_mtc0_tcschedule(); /* MT ASE */ rn = "TCSchedule"; // break; case 7: -// gen_op_dmtc0_tcschefback(); /* MT ASE */ +// gen_op_mtc0_tcschefback(); /* MT ASE */ rn = "TCScheFBack"; // break; default: @@ -3677,7 +3677,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 3: switch (sel) { case 0: - gen_op_dmtc0_entrylo1(); + gen_op_mtc0_entrylo1(); rn = "EntryLo1"; break; default: @@ -3687,11 +3687,11 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 4: switch (sel) { case 0: - gen_op_dmtc0_context(); + gen_op_mtc0_context(); rn = "Context"; break; case 1: -// gen_op_dmtc0_contextconfig(); /* SmartMIPS ASE */ +// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */ rn = "ContextConfig"; // break; default: @@ -3719,23 +3719,23 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_dmtc0_srsconf0(); /* shadow registers */ +// gen_op_mtc0_srsconf0(); /* shadow registers */ rn = "SRSConf0"; // break; case 2: -// gen_op_dmtc0_srsconf1(); /* shadow registers */ +// gen_op_mtc0_srsconf1(); /* shadow registers */ rn = "SRSConf1"; // break; case 3: -// gen_op_dmtc0_srsconf2(); /* shadow registers */ +// gen_op_mtc0_srsconf2(); /* shadow registers */ rn = "SRSConf2"; // break; case 4: -// gen_op_dmtc0_srsconf3(); /* shadow registers */ +// gen_op_mtc0_srsconf3(); /* shadow registers */ rn = "SRSConf3"; // break; case 5: -// gen_op_dmtc0_srsconf4(); /* shadow registers */ +// gen_op_mtc0_srsconf4(); /* shadow registers */ rn = "SRSConf4"; // break; default: @@ -3831,7 +3831,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 14: switch (sel) { case 0: - gen_op_dmtc0_epc(); + gen_op_mtc0_epc(); rn = "EPC"; break; default: @@ -3893,35 +3893,35 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 18: switch (sel) { case 0: - gen_op_dmtc0_watchlo0(); + gen_op_mtc0_watchlo0(); rn = "WatchLo"; break; case 1: -// gen_op_dmtc0_watchlo1(); +// gen_op_mtc0_watchlo1(); rn = "WatchLo1"; // break; case 2: -// gen_op_dmtc0_watchlo2(); +// gen_op_mtc0_watchlo2(); rn = "WatchLo2"; // break; case 3: -// gen_op_dmtc0_watchlo3(); +// gen_op_mtc0_watchlo3(); rn = "WatchLo3"; // break; case 4: -// gen_op_dmtc0_watchlo4(); +// gen_op_mtc0_watchlo4(); rn = "WatchLo4"; // break; case 5: -// gen_op_dmtc0_watchlo5(); +// gen_op_mtc0_watchlo5(); rn = "WatchLo5"; // break; case 6: -// gen_op_dmtc0_watchlo6(); +// gen_op_mtc0_watchlo6(); rn = "WatchLo6"; // break; case 7: -// gen_op_dmtc0_watchlo7(); +// gen_op_mtc0_watchlo7(); rn = "WatchLo7"; // break; default: @@ -3935,31 +3935,31 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "WatchHi"; break; case 1: -// gen_op_dmtc0_watchhi1(); +// gen_op_mtc0_watchhi1(); rn = "WatchHi1"; // break; case 2: -// gen_op_dmtc0_watchhi2(); +// gen_op_mtc0_watchhi2(); rn = "WatchHi2"; // break; case 3: -// gen_op_dmtc0_watchhi3(); +// gen_op_mtc0_watchhi3(); rn = "WatchHi3"; // break; case 4: -// gen_op_dmtc0_watchhi4(); +// gen_op_mtc0_watchhi4(); rn = "WatchHi4"; // break; case 5: -// gen_op_dmtc0_watchhi5(); +// gen_op_mtc0_watchhi5(); rn = "WatchHi5"; // break; case 6: -// gen_op_dmtc0_watchhi6(); +// gen_op_mtc0_watchhi6(); rn = "WatchHi6"; // break; case 7: -// gen_op_dmtc0_watchhi7(); +// gen_op_mtc0_watchhi7(); rn = "WatchHi7"; // break; default: @@ -3970,7 +3970,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) switch (sel) { case 0: #ifdef TARGET_MIPS64 - gen_op_dmtc0_xcontext(); + gen_op_mtc0_xcontext(); rn = "XContext"; break; #endif @@ -4000,19 +4000,19 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "Debug"; break; case 1: -// gen_op_dmtc0_tracecontrol(); /* PDtrace support */ +// gen_op_mtc0_tracecontrol(); /* PDtrace support */ rn = "TraceControl"; // break; case 2: -// gen_op_dmtc0_tracecontrol2(); /* PDtrace support */ +// gen_op_mtc0_tracecontrol2(); /* PDtrace support */ rn = "TraceControl2"; // break; case 3: -// gen_op_dmtc0_usertracedata(); /* PDtrace support */ +// gen_op_mtc0_usertracedata(); /* PDtrace support */ rn = "UserTraceData"; // break; case 4: -// gen_op_dmtc0_debug(); /* PDtrace support */ +// gen_op_mtc0_debug(); /* PDtrace support */ rn = "TraceBPC"; // break; default: @@ -4024,7 +4024,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 24: switch (sel) { case 0: - gen_op_dmtc0_depc(); /* EJTAG support */ + gen_op_mtc0_depc(); /* EJTAG support */ rn = "DEPC"; break; default: @@ -4038,31 +4038,31 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "Performance0"; break; case 1: -// gen_op_dmtc0_performance1(); +// gen_op_mtc0_performance1(); rn = "Performance1"; // break; case 2: -// gen_op_dmtc0_performance2(); +// gen_op_mtc0_performance2(); rn = "Performance2"; // break; case 3: -// gen_op_dmtc0_performance3(); +// gen_op_mtc0_performance3(); rn = "Performance3"; // break; case 4: -// gen_op_dmtc0_performance4(); +// gen_op_mtc0_performance4(); rn = "Performance4"; // break; case 5: -// gen_op_dmtc0_performance5(); +// gen_op_mtc0_performance5(); rn = "Performance5"; // break; case 6: -// gen_op_dmtc0_performance6(); +// gen_op_mtc0_performance6(); rn = "Performance6"; // break; case 7: -// gen_op_dmtc0_performance7(); +// gen_op_mtc0_performance7(); rn = "Performance7"; // break; default: @@ -4127,7 +4127,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 30: switch (sel) { case 0: - gen_op_dmtc0_errorepc(); + gen_op_mtc0_errorepc(); rn = "ErrorEPC"; break; default: -- cgit v1.2.3 From 100ce98812c2624a7e7922055d80ebbd81e8caa9 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 13 May 2007 19:22:13 +0000 Subject: Full MIPS64 MMU implementation, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2820 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 51 ++++++++++++++++++++++++++++++++++++++++++++----- target-mips/op.c | 6 ++++-- target-mips/op_helper.c | 3 +++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 484834a59..306ddf0b6 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -76,6 +76,9 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); target_ulong tag = address & ~mask; target_ulong VPN = tlb->VPN & ~mask; +#ifdef TARGET_MIPS64 + tag &= 0xC00000FFFFFFFFFFULL; +#endif /* Check ASID, virtual page number & size */ if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) { @@ -295,10 +298,16 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, } /* Raise exception */ env->CP0_BadVAddr = address; - env->CP0_Context = (env->CP0_Context & 0xff800000) | + env->CP0_Context = (env->CP0_Context & ~0x007fffff) | ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); +#ifdef TARGET_MIPS64 + env->CP0_EntryHi &= 0xc00000ffffffffffULL; + env->CP0_XContext = (env->CP0_XContext & 0xfffffffe00000000ULL) | + ((address >> 31) & 0x0000000180000000ULL) | + ((address >> 9) & 0x000000007ffffff0ULL); +#endif env->exception_index = exception; env->error_code = error_code; ret = 1; @@ -411,8 +420,19 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBL: cause = 2; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) - offset = 0x000; + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { +#ifdef TARGET_MIPS64 + int R = env->CP0_BadVAddr >> 62; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + offset = 0x080; + else +#endif + offset = 0x000; + } goto set_EPC; case EXCP_IBE: cause = 6; @@ -448,8 +468,19 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBS: cause = 3; - if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) - offset = 0x000; + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { +#ifdef TARGET_MIPS64 + int R = env->CP0_BadVAddr >> 62; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; + + if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) + offset = 0x080; + else +#endif + offset = 0x000; + } set_EPC: if (!(env->CP0_Status & (1 << CP0St_EXL))) { if (env->hflags & MIPS_HFLAG_BMASK) { @@ -520,6 +551,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); if (tlb->V0) { addr = tlb->VPN & ~mask; +#ifdef TARGET_MIPS64 + if (addr >= 0xC00000FF80000000ULL) { + addr |= 0x3FFFFF0000000000ULL; + } +#endif end = addr | (mask >> 1); while (addr < end) { tlb_flush_page (env, addr); @@ -528,6 +564,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) } if (tlb->V1) { addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); +#ifdef TARGET_MIPS64 + if (addr >= 0xC00000FF80000000ULL) { + addr |= 0x3FFFFF0000000000ULL; + } +#endif end = addr | mask; while (addr < end) { tlb_flush_page (env, addr); diff --git a/target-mips/op.c b/target-mips/op.c index a820aad7b..ddc3cdea5 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1317,8 +1317,10 @@ void op_mtc0_entryhi (void) target_ulong old, val; /* 1k pages not implemented */ - /* Ignore MIPS64 TLB for now */ - val = (target_ulong)(int32_t)T0 & ~(target_ulong)0x1F00; + val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF); +#ifdef TARGET_MIPS64 + val = T0 & 0xC00000FFFFFFFFFFULL; +#endif old = env->CP0_EntryHi; env->CP0_EntryHi = val; /* If the ASID changes, flush qemu's TLB. */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 895ca7ff8..2dd0f887b 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -391,6 +391,9 @@ static void r4k_fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->mmu.r4k.tlb[idx]; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); +#ifdef TARGET_MIPS64 + tlb->VPN &= 0xC00000FFFFFFFFFFULL; +#endif tlb->ASID = env->CP0_EntryHi & 0xFF; tlb->PageMask = env->CP0_PageMask; tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; -- cgit v1.2.3 From 69d357286d0ab5a852e827dad1dc4b05917aaaa8 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 16 May 2007 11:59:40 +0000 Subject: More generic 64 bit multiplication support, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2821 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + exec-all.h | 3 ++ host-utils.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ target-i386/helper.c | 50 ++------------------------------- target-mips/exec.h | 2 -- target-mips/op.c | 4 +-- target-mips/op_helper.c | 14 --------- 7 files changed, 84 insertions(+), 65 deletions(-) create mode 100644 host-utils.c diff --git a/Makefile.target b/Makefile.target index aa99f39cd..1e573f44b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -365,6 +365,7 @@ 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+=host-utils.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 VL_OBJS+=irq.o diff --git a/exec-all.h b/exec-all.h index 863ca3bdb..2b9376930 100644 --- a/exec-all.h +++ b/exec-all.h @@ -78,6 +78,9 @@ void optimize_flags_init(void); extern FILE *logfile; extern int loglevel; +void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b); +void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); + int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); diff --git a/host-utils.c b/host-utils.c new file mode 100644 index 000000000..10341063f --- /dev/null +++ b/host-utils.c @@ -0,0 +1,75 @@ +/* + * Utility compute operations used by translated code. + * + * Copyright (c) 2007 Aurelien Jarno + * + * 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" + +/* Signed 64x64 -> 128 multiplication */ + +void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b) +{ +#if defined(__x86_64__) + __asm__ ("imul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b) + ); +#else + int64_t ph; + uint64_t pm1, pm2, pl; + + pl = (uint64_t)((uint32_t)a) * (uint64_t)((uint32_t)b); + pm1 = (a >> 32) * (uint32_t)b; + pm2 = (uint32_t)a * (b >> 32); + ph = (a >> 32) * (b >> 32); + + ph += (int64_t)pm1 >> 32; + pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32); + + *phigh = ph + ((int64_t)pm1 >> 32); + *plow = (pm1 << 32) + (uint32_t)pl; +#endif +} + +/* Unsigned 64x64 -> 128 multiplication */ +void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b) +{ +#if defined(__x86_64__) + __asm__ ("mul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b) + ); +#else + uint64_t ph, pm1, pm2, pl; + + pl = (uint64_t)((uint32_t)a) * (uint64_t)((uint32_t)b); + pm1 = (a >> 32) * (uint32_t)b; + pm2 = (uint32_t)a * (b >> 32); + ph = (a >> 32) * (b >> 32); + + ph += pm1 >> 32; + pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32); + + *phigh = ph + (pm1 >> 32); + *plow = (pm1 << 32) + (uint32_t)pl; +#endif +} diff --git a/target-i386/helper.c b/target-i386/helper.c index 4656596eb..20c1f5762 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3620,50 +3620,6 @@ static void neg128(uint64_t *plow, uint64_t *phigh) add128(plow, phigh, 1, 0); } -static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) -{ - uint32_t a0, a1, b0, b1; - uint64_t v; - - a0 = a; - a1 = a >> 32; - - b0 = b; - b1 = b >> 32; - - v = (uint64_t)a0 * (uint64_t)b0; - *plow = v; - *phigh = 0; - - v = (uint64_t)a0 * (uint64_t)b1; - add128(plow, phigh, v << 32, v >> 32); - - v = (uint64_t)a1 * (uint64_t)b0; - add128(plow, phigh, v << 32, v >> 32); - - v = (uint64_t)a1 * (uint64_t)b1; - *phigh += v; -#ifdef DEBUG_MULDIV - printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n", - a, b, *phigh, *plow); -#endif -} - -static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) -{ - int sa, sb; - sa = (a < 0); - if (sa) - a = -a; - sb = (b < 0); - if (sb) - b = -b; - mul64(plow, phigh, a, b); - if (sa ^ sb) { - neg128(plow, phigh); - } -} - /* return TRUE if overflow */ static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) { @@ -3731,7 +3687,7 @@ void helper_mulq_EAX_T0(void) { uint64_t r0, r1; - mul64(&r0, &r1, EAX, T0); + mulu64(&r1, &r0, EAX, T0); EAX = r0; EDX = r1; CC_DST = r0; @@ -3742,7 +3698,7 @@ void helper_imulq_EAX_T0(void) { uint64_t r0, r1; - imul64(&r0, &r1, EAX, T0); + muls64(&r1, &r0, EAX, T0); EAX = r0; EDX = r1; CC_DST = r0; @@ -3753,7 +3709,7 @@ void helper_imulq_T0_T1(void) { uint64_t r0, r1; - imul64(&r0, &r1, T0, T1); + muls64(&r1, &r0, T0, T1); T0 = r0; CC_DST = r0; CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); diff --git a/target-mips/exec.h b/target-mips/exec.h index 44314a98b..e82b71651 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -97,8 +97,6 @@ void do_ddiv (void); #if TARGET_LONG_BITS > HOST_LONG_BITS void do_ddivu (void); #endif -void do_dmult (void); -void do_dmultu (void); #endif void do_mfc0_random(void); void do_mfc0_count(void); diff --git a/target-mips/op.c b/target-mips/op.c index ddc3cdea5..1188e8284 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -874,13 +874,13 @@ void op_msubu (void) #ifdef TARGET_MIPS64 void op_dmult (void) { - CALL_FROM_TB0(do_dmult); + CALL_FROM_TB4(muls64, &(env->HI), &(env->LO), T0, T1); RETURN(); } void op_dmultu (void) { - CALL_FROM_TB0(do_dmultu); + CALL_FROM_TB4(mulu64, &(env->HI), &(env->LO), T0, T1); RETURN(); } #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 2dd0f887b..9cc55dcef 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -228,20 +228,6 @@ void do_div (void) #endif #ifdef TARGET_MIPS64 -void do_dmult (void) -{ - env->LO = (int64_t)T0 * (int64_t)T1; - /* XXX */ - env->HI = (env->LO | (1ULL << 63)) ? ~0ULL : 0ULL; -} - -void do_dmultu (void) -{ - env->LO = T0 * T1; - /* XXX */ - env->HI = 0; -} - void do_ddiv (void) { if (T1 != 0) { -- cgit v1.2.3 From 3d29fbef063ab1e8bfb9bc759ca94ab0becca9fa Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 17 May 2007 19:21:46 +0000 Subject: Force the primary CPU to run and other CPUs to halt, recalculate timers after system_reset. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2822 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_timer.c | 2 +- hw/sun4m.c | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 8898afc46..acf94f3d5 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -263,7 +263,7 @@ static void slavio_timer_reset(void *opaque) s->reached = 0; s->mode &= 2; s->stopped = 1; - slavio_timer_get_out(s); + slavio_timer_irq(s); } void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu, diff --git a/hw/sun4m.c b/hw/sun4m.c index 89f4b418d..fc410bdd7 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -243,7 +243,17 @@ void qemu_system_powerdown(void) static void main_cpu_reset(void *opaque) { CPUState *env = opaque; + cpu_reset(env); + env->halted = 0; +} + +static void secondary_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + + cpu_reset(env); + env->halted = 1; } static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, @@ -266,10 +276,13 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, env = cpu_init(); cpu_sparc_register(env, def); envs[i] = env; - if (i != 0) + if (i == 0) { + qemu_register_reset(main_cpu_reset, env); + } else { + qemu_register_reset(secondary_cpu_reset, env); env->halted = 1; + } register_savevm("cpu", i, 3, cpu_save, cpu_load, env); - qemu_register_reset(main_cpu_reset, env); } /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); -- cgit v1.2.3 From 4edebb0e8e14a5b934114b5ff74cb86437bb2532 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 17 May 2007 19:25:14 +0000 Subject: Set limits for memory size to avoid overlap with devices git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2823 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index fc410bdd7..ec195def4 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -478,8 +478,13 @@ static const struct hwdef hwdefs[] = { static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, - unsigned int machine) + unsigned int machine, int max_ram) { + if (ram_size > max_ram) { + fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", + ram_size / (1024 * 1024), max_ram / (1024 * 1024)); + exit(1); + } sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model); sun4m_load_kernel(hwdefs[machine].vram_size, ram_size, boot_device, @@ -497,7 +502,7 @@ static void ss5_init(int ram_size, int vga_ram_size, int boot_device, cpu_model = "Fujitsu MB86904"; sun4m_common_init(ram_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, - 0); + 0, 0x10000000); } /* SPARCstation 10 hardware initialisation */ @@ -510,7 +515,7 @@ static void ss10_init(int ram_size, int vga_ram_size, int boot_device, cpu_model = "TI SuperSparc II"; sun4m_common_init(ram_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, - 1); + 1, 0x20000000); // XXX tcx overlap, actually first 4GB ok } QEMUMachine ss5_machine = { -- cgit v1.2.3 From 6c36d3fa860b1dfa55de1e8248be6fffcd876f69 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 17 May 2007 19:30:10 +0000 Subject: Enable faults for unassigned memory accesses and unimplemented ASIs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2824 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 4 ++ exec.c | 10 ++-- target-sparc/cpu.h | 2 + target-sparc/op_helper.c | 131 +++++++++++++++++++++++++++++++++++++++++------ target-sparc/translate.c | 2 + 5 files changed, 126 insertions(+), 23 deletions(-) diff --git a/exec-all.h b/exec-all.h index 2b9376930..c6b7bd198 100644 --- a/exec-all.h +++ b/exec-all.h @@ -593,7 +593,11 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) } pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { +#ifdef TARGET_SPARC + do_unassigned_access(addr, 0, 1, 0); +#else cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); +#endif } return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; } diff --git a/exec.c b/exec.c index 4261dc06b..bf2d82b9f 100644 --- a/exec.c +++ b/exec.c @@ -1957,11 +1957,10 @@ void qemu_ram_free(ram_addr_t addr) static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem read 0x%08x\n", (int)addr); + printf("Unassigned mem read " TARGET_FMT_lx "\n", addr); #endif #ifdef TARGET_SPARC - // Not enabled yet because of bugs in gdbstub etc. - //raise_exception(TT_DATA_ACCESS); + do_unassigned_access(addr, 0, 0, 0); #endif return 0; } @@ -1969,11 +1968,10 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val); + printf("Unassigned mem write " TARGET_FMT_lx " = 0x%x\n", addr, val); #endif #ifdef TARGET_SPARC - // Not enabled yet because of bugs in gdbstub etc. - //raise_exception(TT_DATA_ACCESS); + do_unassigned_access(addr, 1, 0, 0); #endif } diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 91ed11fd0..7e993b7a1 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -290,6 +290,8 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); void raise_exception(int tt); +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, + int is_asi); #include "cpu-all.h" diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 4349503ff..bdc5b0e15 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -3,6 +3,7 @@ //#define DEBUG_PCALL //#define DEBUG_MMU //#define DEBUG_UNALIGNED +//#define DEBUG_UNASSIGNED void raise_exception(int tt) { @@ -151,6 +152,8 @@ void helper_ld_asi(int asi, int size, int sign) uint32_t ret = 0; switch (asi) { + case 2: /* SuperSparc MXCC registers */ + break; case 3: /* MMU probe */ { int mmulev; @@ -179,7 +182,30 @@ void helper_ld_asi(int asi, int size, int sign) #endif } break; - case 0x20 ... 0x2f: /* MMU passthrough */ + case 9: /* Supervisor code access */ + switch(size) { + case 1: + ret = ldub_code(T0); + break; + case 2: + ret = lduw_code(T0 & ~1); + break; + default: + case 4: + ret = ldl_code(T0 & ~3); + break; + case 8: + ret = ldl_code(T0 & ~3); + T0 = ldl_code((T0 + 4) & ~3); + break; + } + break; + case 0xc: /* I-cache tag */ + case 0xd: /* I-cache data */ + case 0xe: /* D-cache tag */ + case 0xf: /* D-cache data */ + break; + case 0x20: /* MMU passthrough */ switch(size) { case 1: ret = ldub_phys(T0); @@ -197,7 +223,9 @@ void helper_ld_asi(int asi, int size, int sign) break; } break; + case 0x21 ... 0x2f: /* MMU passthrough, unassigned */ default: + do_unassigned_access(T0, 0, 0, 1); ret = 0; break; } @@ -207,6 +235,8 @@ void helper_ld_asi(int asi, int size, int sign) void helper_st_asi(int asi, int size, int sign) { switch(asi) { + case 2: /* SuperSparc MXCC registers */ + break; case 3: /* MMU flush */ { int mmulev; @@ -271,18 +301,28 @@ void helper_st_asi(int asi, int size, int sign) #endif return; } + case 0xc: /* I-cache tag */ + case 0xd: /* I-cache data */ + case 0xe: /* D-cache tag */ + case 0xf: /* D-cache data */ + case 0x10: /* I/D-cache flush page */ + case 0x11: /* I/D-cache flush segment */ + case 0x12: /* I/D-cache flush region */ + case 0x13: /* I/D-cache flush context */ + case 0x14: /* I/D-cache flush user */ + break; case 0x17: /* Block copy, sta access */ { // value (T1) = src // address (T0) = dst // copy 32 bytes - uint32_t src = T1, dst = T0; - uint8_t temp[32]; + unsigned int i; + uint32_t src = T1 & ~3, dst = T0 & ~3, temp; - tswap32s(&src); - - cpu_physical_memory_read(src, (void *) &temp, 32); - cpu_physical_memory_write(dst, (void *) &temp, 32); + for (i = 0; i < 32; i += 4, src += 4, dst += 4) { + temp = ldl_kernel(src); + stl_kernel(dst, temp); + } } return; case 0x1f: /* Block fill, stda access */ @@ -290,19 +330,17 @@ void helper_st_asi(int asi, int size, int sign) // value (T1, T2) // address (T0) = dst // fill 32 bytes - int i; - uint32_t dst = T0; - uint64_t val; - - val = (((uint64_t)T1) << 32) | T2; - tswap64s(&val); + unsigned int i; + uint32_t dst = T0 & 7; + uint64_t val; - for (i = 0; i < 32; i += 8, dst += 8) { - cpu_physical_memory_write(dst, (void *) &val, 8); - } + val = (((uint64_t)T1) << 32) | T2; + + for (i = 0; i < 32; i += 8, dst += 8) + stq_kernel(dst, val); } return; - case 0x20 ... 0x2f: /* MMU passthrough */ + case 0x20: /* MMU passthrough */ { switch(size) { case 1: @@ -322,7 +360,14 @@ void helper_st_asi(int asi, int size, int sign) } } return; + case 0x31: /* Ross RT620 I-cache flush */ + case 0x36: /* I-cache flash clear */ + case 0x37: /* D-cache flash clear */ + break; + case 9: /* Supervisor code access, XXX */ + case 0x21 ... 0x2f: /* MMU passthrough, unassigned */ default: + do_unassigned_access(T0, 1, 0, 1); return; } } @@ -441,6 +486,7 @@ void helper_ld_asi(int asi, int size, int sign) case 0x5f: // D-MMU demap, WO case 0x77: // Interrupt vector, WO default: + do_unassigned_access(T0, 0, 0, 1); ret = 0; break; } @@ -656,6 +702,7 @@ void helper_st_asi(int asi, int size, int sign) case 0x8a: // Primary no-fault LE, RO case 0x8b: // Secondary no-fault LE, RO default: + do_unassigned_access(T0, 1, 0, 1); return; } } @@ -986,3 +1033,53 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) } #endif + +#ifndef TARGET_SPARC64 +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, + int is_asi) +{ + CPUState *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + if (env->mmuregs[3]) /* Fault status register */ + env->mmuregs[3] = 1; /* overflow (not read before another fault) */ + if (is_asi) + env->mmuregs[3] |= 1 << 16; + if (env->psrs) + env->mmuregs[3] |= 1 << 5; + if (is_exec) + env->mmuregs[3] |= 1 << 6; + if (is_write) + env->mmuregs[3] |= 1 << 7; + env->mmuregs[3] |= (5 << 2) | 2; + env->mmuregs[4] = addr; /* Fault address register */ + if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { +#ifdef DEBUG_UNASSIGNED + printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx + "\n", addr, env->pc); +#endif + raise_exception(TT_DATA_ACCESS); + } + env = saved_env; +} +#else +void do_unassigned_access(target_ulong addr, int is_write, int is_exec, + int is_asi) +{ +#ifdef DEBUG_UNASSIGNED + CPUState *saved_env; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx "\n", + addr, env->pc); + env = saved_env; +#endif + raise_exception(TT_DATA_ACCESS); +} +#endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index c5eefad4e..38d2a1319 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3494,6 +3494,8 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 0, 0) != 0) return -1; + if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) + return -1; return phys_addr; } #endif -- cgit v1.2.3 From 31ade715088fa40976cdaf7bd4c01345ea8fda26 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 17 May 2007 19:32:20 +0000 Subject: Fix Qemu division by zero triggered by NetBSD git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2825 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_timer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index acf94f3d5..91148583a 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -80,13 +80,11 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) out = (ticks > s->expire_time); if (out) s->reached = 0x80000000; - if (!s->limit) - limit = 0x7fffffff; - else - limit = s->limit; - // Convert register units to counter ticks - limit = limit >> 9; + limit = s->limit >> 9; + + if (!limit) + limit = 0x7fffffff >> 9; // Convert cpu ticks to counter ticks diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec); -- cgit v1.2.3 From f96f4c9d720bced5ee0f57c9dc36cf17347155b9 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 17 May 2007 19:34:41 +0000 Subject: Make TCX registers match what NetBSD expects git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2826 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/tcx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/tcx.c b/hw/tcx.c index db27dcf49..326f45865 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -538,8 +538,6 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, s->cplane = (uint32_t *)vram_base; s->cplane_offset = vram_offset; cpu_register_physical_memory(addr + 0x0a000000, size, vram_offset); - cpu_register_physical_memory(addr + 0x00301000, TCX_THC_NREGS_24, - dummy_memory); graphic_console_init(s->ds, tcx24_update_display, tcx24_invalidate_display, tcx24_screen_dump, s); } else { @@ -548,6 +546,9 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, tcx_screen_dump, s); } + // NetBSD writes here even with 8-bit display + cpu_register_physical_memory(addr + 0x00301000, TCX_THC_NREGS_24, + dummy_memory); register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); qemu_register_reset(tcx_reset, s); -- cgit v1.2.3 From 34ae7b51f54a5d58d30e31a92f8ece02973de50b Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 18 May 2007 01:13:09 +0000 Subject: Work around the lack of proper handling for self-modifying code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2827 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 10 ++++++++++ target-mips/translate.c | 22 ++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 1188e8284..e119765b3 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1001,6 +1001,16 @@ void op_jnz_T2 (void) RETURN(); } +void op_flush_icache_range(void) { + CALL_FROM_TB2(tlb_flush_page, env, T0 + T1); + RETURN(); +} + +void op_flush_icache_all(void) { + CALL_FROM_TB1(tb_flush, env); + RETURN(); +} + /* CP0 functions */ void op_mfc0_index (void) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 410560c28..66e9def85 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5648,8 +5648,26 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_ldst(ctx, op, rt, rs, imm); break; case OPC_CACHE: - /* Treat as a noop */ - break; + /* FIXME: This works around self-modifying code, but only + if the guest OS handles it properly, and if there's no + such code executed in uncached space. */ + if (!(rt & 0x3)) + switch ((rt >> 2) & 0x7) { + case 4: + GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_IMM_TN(T1, imm); + gen_op_flush_icache_range(); + break; + case 2: + case 1: + case 0: + /* Can be very inefficient. */ + gen_op_flush_icache_all(); + break; + default: + break; + } + break; case OPC_PREF: /* Treat as a noop */ break; -- cgit v1.2.3 From fd4a04ebb220b1ada72275297fc12cb85e89bbfb Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 18 May 2007 11:55:54 +0000 Subject: - Move FPU exception handling into helper functions, since they are big. - Fix FP-conditional branches. - Check FPU register mode at runtime, not translation time, as the F64 status bit can change. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2828 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 6 +- target-mips/exec.h | 71 ++++++ target-mips/op.c | 639 ++++++++---------------------------------------- target-mips/op_helper.c | 541 ++++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 176 ++++++------- 5 files changed, 795 insertions(+), 638 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index d127d00e8..e0f03eda7 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -81,9 +81,9 @@ struct CPUMIPSState { #define FCR0_REV 0 /* fcsr */ uint32_t fcr31; -#define SET_FP_COND(num,env) do { (env->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0) -#define CLEAR_FP_COND(num,env) do { (env->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0) -#define IS_FP_COND_SET(num,env) (((env->fcr31) & ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23)))) != 0) +#define SET_FP_COND(num,env) do { ((env)->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) +#define CLEAR_FP_COND(num,env) do { ((env)->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) +#define GET_FP_COND(env) ((((env)->fcr31 >> 24) & 0xfe) | (((env)->fcr31 >> 23) & 0x1)) #define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) #define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) #define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) diff --git a/target-mips/exec.h b/target-mips/exec.h index e82b71651..7ebfd78e7 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -165,4 +165,75 @@ void cpu_mips_update_irq (CPUState *env); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); +void do_ctc1 (void); +void do_float_cvtd_s(void); +void do_float_cvtd_w(void); +void do_float_cvtd_l(void); +void do_float_cvtl_d(void); +void do_float_cvtl_s(void); +void do_float_cvtps_pw(void); +void do_float_cvtpw_ps(void); +void do_float_cvts_d(void); +void do_float_cvts_w(void); +void do_float_cvts_l(void); +void do_float_cvts_pl(void); +void do_float_cvts_pu(void); +void do_float_cvtw_s(void); +void do_float_cvtw_d(void); +void do_float_roundl_d(void); +void do_float_roundl_s(void); +void do_float_roundw_d(void); +void do_float_roundw_s(void); +void do_float_truncl_d(void); +void do_float_truncl_s(void); +void do_float_truncw_d(void); +void do_float_truncw_s(void); +void do_float_ceill_d(void); +void do_float_ceill_s(void); +void do_float_ceilw_d(void); +void do_float_ceilw_s(void); +void do_float_floorl_d(void); +void do_float_floorl_s(void); +void do_float_floorw_d(void); +void do_float_floorw_s(void); +void do_float_add_d(void); +void do_float_add_s(void); +void do_float_add_ps(void); +void do_float_sub_d(void); +void do_float_sub_s(void); +void do_float_sub_ps(void); +void do_float_mul_d(void); +void do_float_mul_s(void); +void do_float_mul_ps(void); +void do_float_div_d(void); +void do_float_div_s(void); +void do_float_div_ps(void); +void do_float_addr_ps(void); + +#define CMP_OPS(op) \ +void do_cmp_d_ ## op(long cc); \ +void do_cmpabs_d_ ## op(long cc); \ +void do_cmp_s_ ## op(long cc); \ +void do_cmpabs_s_ ## op(long cc); \ +void do_cmp_ps_ ## op(long cc); \ +void do_cmpabs_ps_ ## op(long cc); + +CMP_OPS(f) +CMP_OPS(un) +CMP_OPS(eq) +CMP_OPS(ueq) +CMP_OPS(olt) +CMP_OPS(ult) +CMP_OPS(ole) +CMP_OPS(ule) +CMP_OPS(sf) +CMP_OPS(ngle) +CMP_OPS(seq) +CMP_OPS(ngl) +CMP_OPS(lt) +CMP_OPS(nge) +CMP_OPS(le) +CMP_OPS(ngt) +#undef CMP_OPS + #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ diff --git a/target-mips/op.c b/target-mips/op.c index e119765b3..5e3c79732 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1609,47 +1609,25 @@ void op_cp1_enabled(void) RETURN(); } -/* convert MIPS rounding mode in FCR31 to IEEE library */ -unsigned int ieee_rm[] = { - float_round_nearest_even, - float_round_to_zero, - float_round_up, - float_round_down -}; - -#define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) - -inline char ieee_ex_to_mips(char xcpt) -{ - return (xcpt & float_flag_inexact) >> 5 | - (xcpt & float_flag_underflow) >> 3 | - (xcpt & float_flag_overflow) >> 1 | - (xcpt & float_flag_divbyzero) << 1 | - (xcpt & float_flag_invalid) << 4; -} - -inline char mips_ex_to_ieee(char xcpt) -{ - return (xcpt & FP_INEXACT) << 5 | - (xcpt & FP_UNDERFLOW) << 3 | - (xcpt & FP_OVERFLOW) << 1 | - (xcpt & FP_DIV0) >> 1 | - (xcpt & FP_INVALID) >> 4; -} - -inline void update_fcr31(void) +/* + * Verify if floating point register is valid; an operation is not defined + * if bit 0 of any register specification is set and the FR bit in the + * Status register equals zero, since the register numbers specify an + * even-odd pair of adjacent coprocessor general registers. When the FR bit + * in the Status register equals one, both even and odd register numbers + * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. + * + * Multiple 64 bit wide registers can be checked by calling + * gen_op_cp1_registers(freg1 | freg2 | ... | fregN); + */ +void op_cp1_registers(void) { - int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status)); - - SET_FP_CAUSE(env->fcr31, tmp); - if (GET_FP_ENABLE(env->fcr31) & tmp) - CALL_FROM_TB1(do_raise_exception, EXCP_FPE); - else - UPDATE_FP_FLAGS(env->fcr31, tmp); + if (!(env->CP0_Status & (1 << CP0St_FR)) && (PARAM1 & 1)) { + CALL_FROM_TB1(do_raise_exception, EXCP_RI); + } + RETURN(); } - void op_cfc1 (void) { switch (T1) { @@ -1675,38 +1653,7 @@ void op_cfc1 (void) void op_ctc1 (void) { - switch(T1) { - case 25: - if (T0 & 0xffffff00) - goto leave; - env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | - ((T0 & 0x1) << 23); - break; - case 26: - if (T0 & 0x007c0000) - goto leave; - env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); - break; - case 28: - if (T0 & 0x007c0000) - goto leave; - env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | - ((T0 & 0x4) << 22); - break; - case 31: - if (T0 & 0x007c0000) - goto leave; - env->fcr31 = T0; - break; - default: - goto leave; - } - /* set rounding mode */ - RESTORE_ROUNDING_MODE; - set_float_exception_flags(0, &env->fp_status); - if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31)) - CALL_FROM_TB1(do_raise_exception, EXCP_FPE); - leave: + CALL_FROM_TB0(do_ctc1); DEBUG_FPU_STATE(); RETURN(); } @@ -1762,45 +1709,31 @@ void op_mthc1 (void) FLOAT_OP(cvtd, s) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float32_to_float64(FST0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvtd_s); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtd, w) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = int32_to_float64(WT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvtd_w); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtd, l) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = int64_to_float64(DT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvtd_l); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtl, d) { - set_float_exception_flags(0, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + CALL_FROM_TB0(do_float_cvtl_d); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtl, s) { - set_float_exception_flags(0, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + CALL_FROM_TB0(do_float_cvtl_s); DEBUG_FPU_STATE(); RETURN(); } @@ -1813,81 +1746,55 @@ FLOAT_OP(cvtps, s) } FLOAT_OP(cvtps, pw) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int32_to_float32(WT0, &env->fp_status); - FSTH2 = int32_to_float32(WTH0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvtps_pw); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtpw, ps) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); - WTH2 = float32_to_int32(FSTH0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + CALL_FROM_TB0(do_float_cvtpw_ps); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, d) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float64_to_float32(FDT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_d); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, w) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int32_to_float32(WT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_w); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, l) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int64_to_float32(DT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_l); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, pl) { - set_float_exception_flags(0, &env->fp_status); - WT2 = WT0; - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_pl); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, pu) { - set_float_exception_flags(0, &env->fp_status); - WT2 = WTH0; - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_pu); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtw, s) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + CALL_FROM_TB0(do_float_cvtw_s); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtw, d) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + CALL_FROM_TB0(do_float_cvtw_d); DEBUG_FPU_STATE(); RETURN(); } @@ -1917,177 +1824,34 @@ FLOAT_OP(puu, ps) RETURN(); } -FLOAT_OP(roundl, d) -{ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(roundl, s) -{ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(roundw, d) -{ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(roundw, s) -{ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); +#define FLOAT_ROUNDOP(op, ttype, stype) \ +FLOAT_OP(op ## ttype, stype) \ +{ \ + CALL_FROM_TB0(do_float_ ## op ## ttype ## _ ## stype); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ } -FLOAT_OP(truncl, d) -{ - DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(truncl, s) -{ - DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(truncw, d) -{ - WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(truncw, s) -{ - WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} +FLOAT_ROUNDOP(round, l, d) +FLOAT_ROUNDOP(round, l, s) +FLOAT_ROUNDOP(round, w, d) +FLOAT_ROUNDOP(round, w, s) -FLOAT_OP(ceill, d) -{ - set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(ceill, s) -{ - set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(ceilw, d) -{ - set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(ceilw, s) -{ - set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} +FLOAT_ROUNDOP(trunc, l, d) +FLOAT_ROUNDOP(trunc, l, s) +FLOAT_ROUNDOP(trunc, w, d) +FLOAT_ROUNDOP(trunc, w, s) -FLOAT_OP(floorl, d) -{ - set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(floorl, s) -{ - set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(floorw, d) -{ - set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(floorw, s) -{ - set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} +FLOAT_ROUNDOP(ceil, l, d) +FLOAT_ROUNDOP(ceil, l, s) +FLOAT_ROUNDOP(ceil, w, d) +FLOAT_ROUNDOP(ceil, w, s) + +FLOAT_ROUNDOP(floor, l, d) +FLOAT_ROUNDOP(floor, l, s) +FLOAT_ROUNDOP(floor, w, d) +FLOAT_ROUNDOP(floor, w, s) +#undef FLOAR_ROUNDOP FLOAT_OP(movf, d) { @@ -2186,26 +1950,19 @@ FLOAT_OP(movn, ps) #define FLOAT_BINOP(name) \ FLOAT_OP(name, d) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ - update_fcr31(); \ + CALL_FROM_TB0(do_float_ ## name ## _d); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name, s) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - update_fcr31(); \ + CALL_FROM_TB0(do_float_ ## name ## _s); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name, ps) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ - update_fcr31(); \ + CALL_FROM_TB0(do_float_ ## name ## _ps); \ DEBUG_FPU_STATE(); \ RETURN(); \ } @@ -2217,10 +1974,7 @@ FLOAT_BINOP(div) FLOAT_OP(addr, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_add (FST0, FSTH0, &env->fp_status); - FSTH2 = float32_add (FST1, FSTH1, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_addr_ps); DEBUG_FPU_STATE(); RETURN(); } @@ -2390,249 +2144,77 @@ FLOAT_OP(alnv, ps) extern void dump_fpu_s(CPUState *env); -#define FOP_COND_D(op, cond) \ -void op_cmp_d_ ## op (void) \ -{ \ - int c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} \ -void op_cmpabs_d_ ## op (void) \ -{ \ - int c; \ - FDT0 &= ~(1ULL << 63); \ - FDT1 &= ~(1ULL << 63); \ - c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} - -int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) -{ - if (float64_is_signaling_nan(a) || - float64_is_signaling_nan(b) || - (sig && (float64_is_nan(a) || float64_is_nan(b)))) { - float_raise(float_flag_invalid, status); - return 1; - } else if (float64_is_nan(a) || float64_is_nan(b)) { - return 1; - } else { - return 0; - } -} - -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0)) -FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)) -FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0)) -FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status)) -FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) - -#define FOP_COND_S(op, cond) \ -void op_cmp_s_ ## op (void) \ -{ \ - int c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} \ -void op_cmpabs_s_ ## op (void) \ -{ \ - int c; \ - FST0 &= ~(1 << 31); \ - FST1 &= ~(1 << 31); \ - c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} - -flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) -{ - extern flag float32_is_nan(float32 a); - if (float32_is_signaling_nan(a) || - float32_is_signaling_nan(b) || - (sig && (float32_is_nan(a) || float32_is_nan(b)))) { - float_raise(float_flag_invalid, status); - return 1; - } else if (float32_is_nan(a) || float32_is_nan(b)) { - return 1; - } else { - return 0; - } -} - -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0)) -FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status)) -FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) -FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0)) -FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status)) -FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) -FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) - -#define FOP_COND_PS(op, condl, condh) \ -void op_cmp_ps_ ## op (void) \ -{ \ - int cl = condl; \ - int ch = condh; \ - update_fcr31(); \ - if (cl) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - if (ch) \ - SET_FP_COND(PARAM1 + 1, env); \ - else \ - CLEAR_FP_COND(PARAM1 + 1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} \ -void op_cmpabs_ps_ ## op (void) \ -{ \ - int cl, ch; \ - FST0 &= ~(1 << 31); \ - FSTH0 &= ~(1 << 31); \ - FST1 &= ~(1 << 31); \ - FSTH1 &= ~(1 << 31); \ - cl = condl; \ - ch = condh; \ - update_fcr31(); \ - if (cl) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - if (ch) \ - SET_FP_COND(PARAM1 + 1, env); \ - else \ - CLEAR_FP_COND(PARAM1 + 1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} - -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0), - (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0)) -FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)) -FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0), - (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0)) -FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)) -FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +#define CMP_OP(fmt, op) \ +void OPPROTO op_cmp ## _ ## fmt ## _ ## op(void) \ +{ \ + CALL_FROM_TB1(do_cmp ## _ ## fmt ## _ ## op, PARAM1); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} \ +void OPPROTO op_cmpabs ## _ ## fmt ## _ ## op(void) \ +{ \ + CALL_FROM_TB1(do_cmpabs ## _ ## fmt ## _ ## op, PARAM1); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} +#define CMP_OPS(op) \ +CMP_OP(d, op) \ +CMP_OP(s, op) \ +CMP_OP(ps, op) + +CMP_OPS(f) +CMP_OPS(un) +CMP_OPS(eq) +CMP_OPS(ueq) +CMP_OPS(olt) +CMP_OPS(ult) +CMP_OPS(ole) +CMP_OPS(ule) +CMP_OPS(sf) +CMP_OPS(ngle) +CMP_OPS(seq) +CMP_OPS(ngl) +CMP_OPS(lt) +CMP_OPS(nge) +CMP_OPS(le) +CMP_OPS(ngt) +#undef CMP_OPS +#undef CMP_OP void op_bc1f (void) { - T0 = !IS_FP_COND_SET(PARAM1, env); + T0 = !!(~GET_FP_COND(env) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } -void op_bc1fany2 (void) +void op_bc1any2f (void) { - T0 = (!IS_FP_COND_SET(PARAM1, env) || - !IS_FP_COND_SET(PARAM1 + 1, env)); + T0 = !!(~GET_FP_COND(env) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } -void op_bc1fany4 (void) +void op_bc1any4f (void) { - T0 = (!IS_FP_COND_SET(PARAM1, env) || - !IS_FP_COND_SET(PARAM1 + 1, env) || - !IS_FP_COND_SET(PARAM1 + 2, env) || - !IS_FP_COND_SET(PARAM1 + 3, env)); + T0 = !!(~GET_FP_COND(env) & (0xf << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1t (void) { - T0 = IS_FP_COND_SET(PARAM1, env); + T0 = !!(GET_FP_COND(env) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } -void op_bc1tany2 (void) +void op_bc1any2t (void) { - T0 = (IS_FP_COND_SET(PARAM1, env) || - IS_FP_COND_SET(PARAM1 + 1, env)); + T0 = !!(GET_FP_COND(env) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } -void op_bc1tany4 (void) +void op_bc1any4t (void) { - T0 = (IS_FP_COND_SET(PARAM1, env) || - IS_FP_COND_SET(PARAM1 + 1, env) || - IS_FP_COND_SET(PARAM1 + 2, env) || - IS_FP_COND_SET(PARAM1 + 3, env)); + T0 = !!(GET_FP_COND(env) & (0xf << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } @@ -2808,17 +2390,6 @@ void op_save_pc (void) RETURN(); } -void op_save_fp_status (void) -{ - union fps { - uint32_t i; - float_status f; - } fps; - fps.i = PARAM1; - env->fp_status = fps.f; - RETURN(); -} - void op_interrupt_restart (void) { if (!(env->CP0_Status & (1 << CP0St_EXL)) && diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9cc55dcef..85ad33355 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -598,3 +598,544 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) } #endif + +/* Complex FPU operations which may need stack space. */ + +/* convert MIPS rounding mode in FCR31 to IEEE library */ +unsigned int ieee_rm[] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + +#define RESTORE_ROUNDING_MODE \ + set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) + +void do_ctc1 (void) +{ + switch(T1) { + case 25: + if (T0 & 0xffffff00) + return; + env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | + ((T0 & 0x1) << 23); + break; + case 26: + if (T0 & 0x007c0000) + return; + env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); + break; + case 28: + if (T0 & 0x007c0000) + return; + env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | + ((T0 & 0x4) << 22); + break; + case 31: + if (T0 & 0x007c0000) + return; + env->fcr31 = T0; + break; + default: + return; + } + /* set rounding mode */ + RESTORE_ROUNDING_MODE; + set_float_exception_flags(0, &env->fp_status); + if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31)) + do_raise_exception(EXCP_FPE); +} + +inline char ieee_ex_to_mips(char xcpt) +{ + return (xcpt & float_flag_inexact) >> 5 | + (xcpt & float_flag_underflow) >> 3 | + (xcpt & float_flag_overflow) >> 1 | + (xcpt & float_flag_divbyzero) << 1 | + (xcpt & float_flag_invalid) << 4; +} + +inline char mips_ex_to_ieee(char xcpt) +{ + return (xcpt & FP_INEXACT) << 5 | + (xcpt & FP_UNDERFLOW) << 3 | + (xcpt & FP_OVERFLOW) << 1 | + (xcpt & FP_DIV0) >> 1 | + (xcpt & FP_INVALID) >> 4; +} + +inline void update_fcr31(void) +{ + int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status)); + + SET_FP_CAUSE(env->fcr31, tmp); + if (GET_FP_ENABLE(env->fcr31) & tmp) + do_raise_exception(EXCP_FPE); + else + UPDATE_FP_FLAGS(env->fcr31, tmp); +} + +#define FLOAT_OP(name, p) void do_float_##name##_##p(void) + +FLOAT_OP(cvtd, s) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = float32_to_float64(FST0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvtd, w) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = int32_to_float64(WT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvtd, l) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = int64_to_float64(DT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvtl, d) +{ + set_float_exception_flags(0, &env->fp_status); + DT2 = float64_to_int64(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(cvtl, s) +{ + set_float_exception_flags(0, &env->fp_status); + DT2 = float32_to_int64(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} + +FLOAT_OP(cvtps, pw) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = int32_to_float32(WT0, &env->fp_status); + FSTH2 = int32_to_float32(WTH0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvtpw, ps) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = float32_to_int32(FST0, &env->fp_status); + WTH2 = float32_to_int32(FSTH0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(cvts, d) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float64_to_float32(FDT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvts, w) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = int32_to_float32(WT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvts, l) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = int64_to_float32(DT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvts, pl) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = WT0; + update_fcr31(); +} +FLOAT_OP(cvts, pu) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = WTH0; + update_fcr31(); +} +FLOAT_OP(cvtw, s) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = float32_to_int32(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(cvtw, d) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = float64_to_int32(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +FLOAT_OP(roundl, d) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(roundl, s) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(roundw, d) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(roundw, s) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +FLOAT_OP(truncl, d) +{ + DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(truncl, s) +{ + DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(truncw, d) +{ + WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(truncw, s) +{ + WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +FLOAT_OP(ceill, d) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(ceill, s) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(ceilw, d) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(ceilw, s) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +FLOAT_OP(floorl, d) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(floorl, s) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(floorw, d) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(floorw, s) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +/* binary operations */ +#define FLOAT_BINOP(name) \ +FLOAT_OP(name, d) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ + FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, ps) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ + FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ + update_fcr31(); \ +} +FLOAT_BINOP(add) +FLOAT_BINOP(sub) +FLOAT_BINOP(mul) +FLOAT_BINOP(div) +#undef FLOAT_BINOP + +FLOAT_OP(addr, ps) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_add (FST0, FSTH0, &env->fp_status); + FSTH2 = float32_add (FST1, FSTH1, &env->fp_status); + update_fcr31(); +} + +#define FOP_COND_D(op, cond) \ +void do_cmp_d_ ## op (long cc) \ +{ \ + int c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ +} \ +void do_cmpabs_d_ ## op (long cc) \ +{ \ + int c; \ + FDT0 &= ~(1ULL << 63); \ + FDT1 &= ~(1ULL << 63); \ + c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ +} + +int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) +{ + if (float64_is_signaling_nan(a) || + float64_is_signaling_nan(b) || + (sig && (float64_is_nan(a) || float64_is_nan(b)))) { + float_raise(float_flag_invalid, status); + return 1; + } else if (float64_is_nan(a) || float64_is_nan(b)) { + return 1; + } else { + return 0; + } +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0)) +FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)) +FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0)) +FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status)) +FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) + +#define FOP_COND_S(op, cond) \ +void do_cmp_s_ ## op (long cc) \ +{ \ + int c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ +} \ +void do_cmpabs_s_ ## op (long cc) \ +{ \ + int c; \ + FST0 &= ~(1 << 31); \ + FST1 &= ~(1 << 31); \ + c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ +} + +flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) +{ + extern flag float32_is_nan(float32 a); + if (float32_is_signaling_nan(a) || + float32_is_signaling_nan(b) || + (sig && (float32_is_nan(a) || float32_is_nan(b)))) { + float_raise(float_flag_invalid, status); + return 1; + } else if (float32_is_nan(a) || float32_is_nan(b)) { + return 1; + } else { + return 0; + } +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0)) +FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status)) +FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0)) +FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status)) +FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) + +#define FOP_COND_PS(op, condl, condh) \ +void do_cmp_ps_ ## op (long cc) \ +{ \ + int cl = condl; \ + int ch = condh; \ + update_fcr31(); \ + if (cl) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ + if (ch) \ + SET_FP_COND(cc + 1, env); \ + else \ + CLEAR_FP_COND(cc + 1, env); \ +} \ +void do_cmpabs_ps_ ## op (long cc) \ +{ \ + int cl, ch; \ + FST0 &= ~(1 << 31); \ + FSTH0 &= ~(1 << 31); \ + FST1 &= ~(1 << 31); \ + FSTH1 &= ~(1 << 31); \ + cl = condl; \ + ch = condh; \ + update_fcr31(); \ + if (cl) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ + if (ch) \ + SET_FP_COND(cc + 1, env); \ + else \ + CLEAR_FP_COND(cc + 1, env); \ +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0), + (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0)) +FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)) +FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0), + (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0)) +FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)) +FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) diff --git a/target-mips/translate.c b/target-mips/translate.c index 66e9def85..57e5777cc 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -491,7 +491,7 @@ FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); #define FOP_CONDS(type, fmt) \ -static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = { \ +static GenOpFunc1 * gen_op_cmp ## type ## _ ## fmt ## _table[16] = { \ gen_op_cmp ## type ## _ ## fmt ## _f, \ gen_op_cmp ## type ## _ ## fmt ## _un, \ gen_op_cmp ## type ## _ ## fmt ## _eq, \ @@ -511,7 +511,7 @@ static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = { \ }; \ static inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \ { \ - cond ## type ## _ ## fmt ## _table[n](cc); \ + gen_op_cmp ## type ## _ ## fmt ## _table[n](cc); \ } FOP_CONDS(, d) @@ -525,11 +525,10 @@ typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; uint32_t opcode; - uint32_t fp_status, saved_fp_status; + uint32_t fp_status; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; - uint32_t CP0_Status; int bstate; target_ulong btarget; } DisasContext; @@ -628,11 +627,21 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) } } -static inline void save_fpu_state (DisasContext *ctx) +static inline void restore_cpu_state (CPUState *env, DisasContext *ctx) { - if (ctx->fp_status != ctx->saved_fp_status) { - gen_op_save_fp_status(ctx->fp_status); - ctx->saved_fp_status = ctx->fp_status; + ctx->saved_hflags = ctx->hflags; + switch (ctx->hflags & MIPS_HFLAG_BMASK) { + case MIPS_HFLAG_BR: + gen_op_restore_breg_target(); + break; + case MIPS_HFLAG_B: + ctx->btarget = env->btarget; + break; + case MIPS_HFLAG_BC: + case MIPS_HFLAG_BL: + ctx->btarget = env->btarget; + gen_op_restore_bcond(); + break; } } @@ -4293,20 +4302,20 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, gen_op_save_bcond(); break; case OPC_BC1FANY2: - gen_op_bc1fany2(cc); - opn = "bc1fany2"; + gen_op_bc1any2f(cc); + opn = "bc1any2f"; goto not_likely; case OPC_BC1TANY2: - gen_op_bc1tany2(cc); - opn = "bc1tany2"; + gen_op_bc1any2t(cc); + opn = "bc1any2t"; goto not_likely; case OPC_BC1FANY4: - gen_op_bc1fany4(cc); - opn = "bc1fany4"; + gen_op_bc1any4f(cc); + opn = "bc1any4f"; goto not_likely; case OPC_BC1TANY4: - gen_op_bc1tany4(cc); - opn = "bc1tany4"; + gen_op_bc1any4t(cc); + opn = "bc1any4t"; not_likely: ctx->hflags |= MIPS_HFLAG_BC; gen_op_set_bcond(); @@ -4323,27 +4332,6 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, /* Coprocessor 1 (FPU) */ -/* verify if floating point register is valid; an operation is not defined - * if bit 0 of any register specification is set and the FR bit in the - * Status register equals zero, since the register numbers specify an - * even-odd pair of adjacent coprocessor general registers. When the FR bit - * in the Status register equals one, both even and odd register numbers - * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. - * - * Multiple 64 bit wide registers can be checked by calling - * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); - * - * FIXME: This is broken for R2, it needs to be checked at runtime, not - * at translation time. - */ -#define CHECK_FR(ctx, freg) do { \ - if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \ - MIPS_INVAL("FPU mode"); \ - generate_exception (ctx, EXCP_RI); \ - return; \ - } \ - } while(0) - #define FOP(func, fmt) (((fmt) << 21) | (func)) static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) @@ -4388,14 +4376,14 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "dmtc1"; break; case OPC_MFHC1: - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_mfhc1(); GEN_STORE_TN_REG(rt, T0); opn = "mfhc1"; break; case OPC_MTHC1: - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_REG_TN(T0, rt); gen_op_mthc1(); GEN_STORE_FTN_FREG(fs, WTH0); @@ -4546,28 +4534,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "neg.s"; break; case FOP(8, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_roundl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.s"; break; case FOP(9, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_truncl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.s"; break; case FOP(10, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_ceill_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.s"; break; case FOP(11, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_floorl_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4622,7 +4610,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.s"; break; case FOP(33, 16): - CHECK_FR(ctx, fd); + gen_op_cp1_registers(fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4635,14 +4623,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.w.s"; break; case FOP(37, 16): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.l.s"; break; case FOP(38, 16): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT1, fs); GEN_LOAD_FREG_FTN(WT0, ft); gen_op_float_cvtps_s(); @@ -4676,7 +4664,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, } break; case FOP(0, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_add_d(); @@ -4685,7 +4673,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(1, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_sub_d(); @@ -4694,7 +4682,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(2, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_mul_d(); @@ -4703,7 +4691,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(3, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_div_d(); @@ -4712,84 +4700,84 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(4, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_sqrt_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "sqrt.d"; break; case FOP(5, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_abs_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "abs.d"; break; case FOP(6, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_mov_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "mov.d"; break; case FOP(7, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_chs_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "neg.d"; break; case FOP(8, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.d"; break; case FOP(9, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.d"; break; case FOP(10, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceill_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.d"; break; case FOP(11, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "floor.l.d"; break; case FOP(12, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "round.w.d"; break; case FOP(13, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "trunc.w.d"; break; case FOP(14, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceilw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "ceil.w.d"; break; case FOP(15, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorw_d(); GEN_STORE_FTN_FREG(fd, WT2); @@ -4835,7 +4823,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 17): case FOP(62, 17): case FOP(63, 17): - CHECK_FR(ctx, fs | ft); + gen_op_cp1_registers(fs | ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); if (ctx->opcode & (1 << 6)) { @@ -4847,21 +4835,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, } break; case FOP(32, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.d"; break; case FOP(36, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.w.d"; break; case FOP(37, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtl_d(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4874,21 +4862,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.s.w"; break; case FOP(33, 20): - CHECK_FR(ctx, fd); + gen_op_cp1_registers(fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_w(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.d.w"; break; case FOP(32, 21): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_l(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.l"; break; case FOP(33, 21): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtd_l(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4896,7 +4884,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, break; case FOP(38, 20): case FOP(38, 21): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtps_pw(); @@ -4905,7 +4893,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.ps.pw"; break; case FOP(0, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4916,7 +4904,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "add.ps"; break; case FOP(1, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4927,7 +4915,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "sub.ps"; break; case FOP(2, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4938,7 +4926,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mul.ps"; break; case FOP(5, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_abs_ps(); @@ -4947,7 +4935,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "abs.ps"; break; case FOP(6, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_mov_ps(); @@ -4956,7 +4944,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mov.ps"; break; case FOP(7, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_chs_ps(); @@ -4998,7 +4986,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.ps"; break; case FOP(24, 22): - CHECK_FR(ctx, fs | fd | ft); + gen_op_cp1_registers(fs | fd | ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5009,14 +4997,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "addr.ps"; break; case FOP(32, 22): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvts_pu(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pu"; break; case FOP(36, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtpw_ps(); @@ -5025,14 +5013,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.pw.ps"; break; case FOP(40, 22): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvts_pl(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pl"; break; case FOP(44, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pll_ps(); @@ -5040,7 +5028,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pll.ps"; break; case FOP(45, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_plu_ps(); @@ -5048,7 +5036,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "plu.ps"; break; case FOP(46, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pul_ps(); @@ -5056,7 +5044,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pul.ps"; break; case FOP(47, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_puu_ps(); @@ -5079,7 +5067,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 22): case FOP(62, 22): case FOP(63, 22): - CHECK_FR(ctx, fs | ft); + gen_op_cp1_registers(fs | ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5166,7 +5154,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, const char *opn = "flt3_arith"; /* All of those work only on 64bit FPUs. */ - CHECK_FR(ctx, fd | fr | fs | ft); + gen_op_cp1_registers(fd | fr | fs | ft); switch (opc) { case OPC_ALNV_PS: GEN_LOAD_REG_TN(T0, fr); @@ -5874,26 +5862,12 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.bstate = BS_NONE; /* Restore delay slot state from the tb context. */ ctx.hflags = tb->flags; - ctx.saved_hflags = ctx.hflags; - switch (ctx.hflags & MIPS_HFLAG_BMASK) { - case MIPS_HFLAG_BR: - gen_op_restore_breg_target(); - break; - case MIPS_HFLAG_B: - ctx.btarget = env->btarget; - break; - case MIPS_HFLAG_BC: - case MIPS_HFLAG_BL: - ctx.btarget = env->btarget; - gen_op_restore_bcond(); - break; - } + restore_cpu_state(env, &ctx); #if defined(CONFIG_USER_ONLY) ctx.mem_idx = 0; #else ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); #endif - ctx.CP0_Status = env->CP0_Status; #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "------------------------------------------------\n"); -- cgit v1.2.3 From 36ddb83bd8fcb587e5d3b759543a13680e6836fb Mon Sep 17 00:00:00 2001 From: balrog Date: Fri, 18 May 2007 17:46:59 +0000 Subject: Fix sysrq support from the monitor mux (originally by Jason Wessel). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2829 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vl.c b/vl.c index fededf20e..7dcfb5831 100644 --- a/vl.c +++ b/vl.c @@ -1365,8 +1365,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) } break; case 'b': - if (chr->chr_event) - chr->chr_event(chr->opaque, CHR_EVENT_BREAK); + qemu_chr_event(chr, CHR_EVENT_BREAK); break; case 'c': /* Switch to the next registered device */ -- cgit v1.2.3 From 5dcb6b914e5b99b64243477a23aea7e2a9852d17 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 19 May 2007 12:58:30 +0000 Subject: Use full 36-bit physical address space on SS10 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2830 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 2 ++ hw/esp.c | 3 ++- hw/fdc.c | 20 +++++++++------- hw/iommu.c | 58 +++++++++++++++++++++++--------------------- hw/m48t59.c | 6 ++--- hw/m48t59.h | 2 +- hw/pcnet.c | 3 ++- hw/slavio_intctl.c | 2 +- hw/slavio_misc.c | 5 ++-- hw/slavio_serial.c | 6 ++--- hw/slavio_timer.c | 4 ++-- hw/sparc32_dma.c | 4 ++-- hw/sun4m.c | 54 ++++++++++++++++++++++------------------- hw/tcx.c | 24 +++++++++---------- target-sparc/cpu.h | 2 +- target-sparc/helper.c | 43 +++++++++++++++++++-------------- target-sparc/op_helper.c | 62 +++++++++++++++++++++++++++++++++++++++++++----- vl.h | 33 ++++++++++++++------------ 18 files changed, 204 insertions(+), 129 deletions(-) diff --git a/exec.c b/exec.c index bf2d82b9f..1d94ec12e 100644 --- a/exec.c +++ b/exec.c @@ -64,6 +64,8 @@ #if defined(TARGET_SPARC64) #define TARGET_PHYS_ADDR_SPACE_BITS 41 +#elif defined(TARGET_SPARC) +#define TARGET_PHYS_ADDR_SPACE_BITS 36 #elif defined(TARGET_ALPHA) #define TARGET_PHYS_ADDR_SPACE_BITS 42 #define TARGET_VIRT_ADDR_SPACE_BITS 42 diff --git a/hw/esp.c b/hw/esp.c index 88d74c9a1..65feaea6e 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -562,7 +562,8 @@ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id) s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s); } -void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque) +void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, + void *dma_opaque) { ESPState *s; int esp_io_memory; diff --git a/hw/fdc.c b/hw/fdc.c index d89b2263e..ca2d32072 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -370,7 +370,7 @@ struct fdctrl_t { /* HW */ qemu_irq irq; int dma_chann; - uint32_t io_base; + target_phys_addr_t io_base; /* Controller state */ QEMUTimer *result_timer; uint8_t state; @@ -464,13 +464,13 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg) { - return fdctrl_read(opaque, reg); + return fdctrl_read(opaque, (uint32_t)reg); } static void fdctrl_write_mem (void *opaque, target_phys_addr_t reg, uint32_t value) { - fdctrl_write(opaque, reg, value); + fdctrl_write(opaque, (uint32_t)reg, value); } static CPUReadMemoryFunc *fdctrl_mem_read[3] = { @@ -579,7 +579,7 @@ static void fdctrl_external_reset(void *opaque) } fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, - uint32_t io_base, + target_phys_addr_t io_base, BlockDriverState **fds) { fdctrl_t *fdctrl; @@ -613,10 +613,14 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl); cpu_register_physical_memory(io_base, 0x08, io_mem); } else { - register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl); - register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl); - register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl); - register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl); + register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read, + fdctrl); + register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read, + fdctrl); + register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write, + fdctrl); + register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write, + fdctrl); } register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl); qemu_register_reset(fdctrl_external_reset, fdctrl); diff --git a/hw/iommu.c b/hw/iommu.c index 5c2768cee..082451f98 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -87,15 +87,15 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define PAGE_MASK (PAGE_SIZE - 1) typedef struct IOMMUState { - uint32_t addr; + target_phys_addr_t addr; uint32_t regs[IOMMU_NREGS]; - uint32_t iostart; + target_phys_addr_t iostart; } IOMMUState; static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) { IOMMUState *s = opaque; - uint32_t saddr; + target_phys_addr_t saddr; saddr = (addr - s->addr) >> 2; switch (saddr) { @@ -110,7 +110,7 @@ static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { IOMMUState *s = opaque; - uint32_t saddr; + target_phys_addr_t saddr; saddr = (addr - s->addr) >> 2; DPRINTF("write reg[%d] = %x\n", saddr, val); @@ -118,32 +118,32 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val case IOMMU_CTRL: switch (val & IOMMU_CTRL_RNGE) { case IOMMU_RNGE_16MB: - s->iostart = 0xff000000; + s->iostart = 0xffffffffff000000ULL; break; case IOMMU_RNGE_32MB: - s->iostart = 0xfe000000; + s->iostart = 0xfffffffffe000000ULL; break; case IOMMU_RNGE_64MB: - s->iostart = 0xfc000000; + s->iostart = 0xfffffffffc000000ULL; break; case IOMMU_RNGE_128MB: - s->iostart = 0xf8000000; + s->iostart = 0xfffffffff8000000ULL; break; case IOMMU_RNGE_256MB: - s->iostart = 0xf0000000; + s->iostart = 0xfffffffff0000000ULL; break; case IOMMU_RNGE_512MB: - s->iostart = 0xe0000000; + s->iostart = 0xffffffffe0000000ULL; break; case IOMMU_RNGE_1GB: - s->iostart = 0xc0000000; + s->iostart = 0xffffffffc0000000ULL; break; default: case IOMMU_RNGE_2GB: - s->iostart = 0x80000000; + s->iostart = 0xffffffff80000000ULL; break; } - DPRINTF("iostart = %x\n", s->iostart); + DPRINTF("iostart = %llx\n", s->iostart); s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION); break; case IOMMU_BASE: @@ -186,7 +186,7 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { iommu_mem_writew, }; -static uint32_t iommu_page_get_flags(IOMMUState *s, uint32_t addr) +static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) { uint32_t iopte; @@ -196,21 +196,27 @@ static uint32_t iommu_page_get_flags(IOMMUState *s, uint32_t addr) return ldl_phys(iopte); } -static uint32_t iommu_translate_pa(IOMMUState *s, uint32_t addr, uint32_t pa) +static target_phys_addr_t iommu_translate_pa(IOMMUState *s, + target_phys_addr_t addr, + uint32_t pte) { uint32_t tmppte; + target_phys_addr_t pa; + + tmppte = pte; + pa = ((pte & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); + DPRINTF("xlate dva " TARGET_FMT_plx " => pa " TARGET_FMT_plx + " (iopte = %x)\n", addr, pa, tmppte); - tmppte = pa; - pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); - DPRINTF("xlate dva %x => pa %x (iopte = %x)\n", addr, pa, tmppte); return pa; } void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { - int l, flags; - target_ulong page, phys_addr; + int l; + uint32_t flags; + target_phys_addr_t page, phys_addr; while (len > 0) { page = addr & TARGET_PAGE_MASK; @@ -239,10 +245,9 @@ static void iommu_save(QEMUFile *f, void *opaque) IOMMUState *s = opaque; int i; - qemu_put_be32s(f, &s->addr); for (i = 0; i < IOMMU_NREGS; i++) qemu_put_be32s(f, &s->regs[i]); - qemu_put_be32s(f, &s->iostart); + qemu_put_be64s(f, &s->iostart); } static int iommu_load(QEMUFile *f, void *opaque, int version_id) @@ -250,13 +255,12 @@ static int iommu_load(QEMUFile *f, void *opaque, int version_id) IOMMUState *s = opaque; int i; - if (version_id != 1) + if (version_id != 2) return -EINVAL; - qemu_get_be32s(f, &s->addr); for (i = 0; i < IOMMU_NREGS; i++) qemu_put_be32s(f, &s->regs[i]); - qemu_get_be32s(f, &s->iostart); + qemu_get_be64s(f, &s->iostart); return 0; } @@ -270,7 +274,7 @@ static void iommu_reset(void *opaque) s->regs[0] = IOMMU_VERSION; } -void *iommu_init(uint32_t addr) +void *iommu_init(target_phys_addr_t addr) { IOMMUState *s; int iommu_io_memory; @@ -284,7 +288,7 @@ void *iommu_init(uint32_t addr) iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); - register_savevm("iommu", addr, 1, iommu_save, iommu_load, s); + register_savevm("iommu", addr, 2, iommu_save, iommu_load, s); qemu_register_reset(iommu_reset, s); return s; } diff --git a/hw/m48t59.c b/hw/m48t59.c index e9fb0901b..cda28c2f6 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -43,7 +43,7 @@ struct m48t59_t { /* Hardware parameters */ qemu_irq IRQ; int mem_index; - uint32_t mem_base; + target_phys_addr_t mem_base; uint32_t io_base; uint16_t size; /* RTC management */ @@ -610,12 +610,12 @@ static void m48t59_reset(void *opaque) } /* Initialisation routine */ -m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base, +m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, uint32_t io_base, uint16_t size, int type) { m48t59_t *s; - target_ulong save_base; + target_phys_addr_t save_base; s = qemu_mallocz(sizeof(m48t59_t)); if (!s) diff --git a/hw/m48t59.h b/hw/m48t59.h index df383e91c..cfe9b2af5 100644 --- a/hw/m48t59.h +++ b/hw/m48t59.h @@ -6,7 +6,7 @@ typedef struct m48t59_t m48t59_t; void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val); uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr); void m48t59_toggle_lock (m48t59_t *NVRAM, int lock); -m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base, +m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, uint32_t io_base, uint16_t size, int type); diff --git a/hw/pcnet.c b/hw/pcnet.c index f2130d7b4..12d973479 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -2018,7 +2018,8 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { (CPUWriteMemoryFunc *)&pcnet_ioport_writew, }; -void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq) +void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, + qemu_irq irq) { PCNetState *d; int lance_io_memory; diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 0c1eb5835..94a6c965c 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -371,7 +371,7 @@ void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env) s->cpu_envs[cpu] = env; } -void *slavio_intctl_init(uint32_t addr, uint32_t addrg, +void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, const uint32_t *intbit_to_level, qemu_irq **irq) { diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 9e7629ebb..100723824 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -212,7 +212,8 @@ static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void *slavio_misc_init(uint32_t base, qemu_irq irq) +void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, + qemu_irq irq) { int slavio_misc_io_memory; MiscState *s; @@ -235,7 +236,7 @@ void *slavio_misc_init(uint32_t base, qemu_irq irq) // System control cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory); // Power management - cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory); + cpu_register_physical_memory(power_base, MISC_MAXADDR, slavio_misc_io_memory); s->irq = irq; diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 0e3a622db..3da40eb6c 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -587,8 +587,8 @@ static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) } -SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1, - CharDriverState *chr2) +SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, + CharDriverState *chr1, CharDriverState *chr2) { int slavio_serial_io_memory, i; SerialState *s; @@ -704,7 +704,7 @@ static void sunmouse_event(void *opaque, put_queue(s, 0); } -void slavio_serial_ms_kbd_init(int base, qemu_irq irq) +void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq) { int slavio_serial_io_memory, i; SerialState *s; diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 91148583a..114770467 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -264,8 +264,8 @@ static void slavio_timer_reset(void *opaque) slavio_timer_irq(s); } -void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu, - void *intctl) +void slavio_timer_init(target_phys_addr_t addr, int irq, int mode, + unsigned int cpu, void *intctl) { int slavio_timer_io_memory; SLAVIO_TIMERState *s; diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 8480c8dbe..e1baee8b8 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -249,8 +249,8 @@ static int dma_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq, - void *iommu) +void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq espirq, + qemu_irq leirq, void *iommu) { DMAState *s; int dma_io_memory; diff --git a/hw/sun4m.c b/hw/sun4m.c index ec195def4..313e5b4aa 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -48,11 +48,11 @@ #define MAX_CPUS 16 struct hwdef { - target_ulong iommu_base, slavio_base; - target_ulong intctl_base, counter_base, nvram_base, ms_kb_base, serial_base; - target_ulong fd_base; - target_ulong dma_base, esp_base, le_base; - target_ulong tcx_base, cs_base; + target_phys_addr_t iommu_base, slavio_base; + target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base; + target_phys_addr_t serial_base, fd_base; + target_phys_addr_t dma_base, esp_base, le_base; + target_phys_addr_t tcx_base, cs_base, power_base; long vram_size, nvram_size; // IRQ numbers are not PIL ones, but master interrupt controller register // bit numbers @@ -289,7 +289,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, iommu = iommu_init(hwdef->iommu_base); slavio_intctl = slavio_intctl_init(hwdef->intctl_base, - hwdef->intctl_base + 0x10000, + hwdef->intctl_base + 0x10000ULL, &hwdef->intbit_to_level[0], &slavio_irq); for(i = 0; i < smp_cpus; i++) { @@ -317,10 +317,11 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, hwdef->nvram_size, 8); for (i = 0; i < MAX_CPUS; i++) { - slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE, + slavio_timer_init(hwdef->counter_base + + (target_phys_addr_t)(i * TARGET_PAGE_SIZE), hwdef->clock_irq, 0, i, slavio_intctl); } - slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2, + slavio_timer_init(hwdef->counter_base + 0x10000ULL, hwdef->clock1_irq, 2, (unsigned int)-1, slavio_intctl); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device @@ -336,9 +337,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, } } - slavio_misc = slavio_misc_init(hwdef->slavio_base, + slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->power_base, slavio_irq[hwdef->me_irq]); - if (hwdef->cs_base != (target_ulong)-1) + if (hwdef->cs_base != (target_phys_addr_t)-1) cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); sparc32_dma_set_reset_data(dma, main_esp, main_lance); } @@ -424,6 +425,7 @@ static const struct hwdef hwdefs[] = { .dma_base = 0x78400000, .esp_base = 0x78800000, .le_base = 0x78c00000, + .power_base = 0x7a000000, .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -443,19 +445,20 @@ static const struct hwdef hwdefs[] = { }, /* SS-10 */ { - .iommu_base = 0xe0000000, // XXX Actually at 0xfe0000000ULL (36 bits) - .tcx_base = 0x20000000, // 0xe20000000ULL, + .iommu_base = 0xfe0000000ULL, + .tcx_base = 0xe20000000ULL, .cs_base = -1, - .slavio_base = 0xf0000000, // 0xff0000000ULL, - .ms_kb_base = 0xf1000000, // 0xff1000000ULL, - .serial_base = 0xf1100000, // 0xff1100000ULL, - .nvram_base = 0xf1200000, // 0xff1200000ULL, - .fd_base = 0xf1700000, // 0xff1700000ULL, - .counter_base = 0xf1300000, // 0xff1300000ULL, - .intctl_base = 0xf1400000, // 0xff1400000ULL, - .dma_base = 0xf0400000, // 0xef0400000ULL, - .esp_base = 0xf0800000, // 0xef0800000ULL, - .le_base = 0xf0c00000, // 0xef0c00000ULL, + .slavio_base = 0xff0000000ULL, + .ms_kb_base = 0xff1000000ULL, + .serial_base = 0xff1100000ULL, + .nvram_base = 0xff1200000ULL, + .fd_base = 0xff1700000ULL, + .counter_base = 0xff1300000ULL, + .intctl_base = 0xff1400000ULL, + .dma_base = 0xef0400000ULL, + .esp_base = 0xef0800000ULL, + .le_base = 0xef0c00000ULL, + .power_base = 0xefa000000ULL, .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -480,9 +483,10 @@ static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds, const char *initrd_filename, const char *cpu_model, unsigned int machine, int max_ram) { - if (ram_size > max_ram) { + if ((unsigned int)ram_size > (unsigned int)max_ram) { fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", - ram_size / (1024 * 1024), max_ram / (1024 * 1024)); + (unsigned int)ram_size / (1024 * 1024), + (unsigned int)max_ram / (1024 * 1024)); exit(1); } sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model); @@ -515,7 +519,7 @@ static void ss10_init(int ram_size, int vga_ram_size, int boot_device, cpu_model = "TI SuperSparc II"; sun4m_common_init(ram_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, - 1, 0x20000000); // XXX tcx overlap, actually first 4GB ok + 1, PROM_ADDR); // XXX prom overlap, actually first 4GB ok } QEMUMachine ss5_machine = { diff --git a/hw/tcx.c b/hw/tcx.c index 326f45865..80d60baae 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -31,7 +31,7 @@ #define TCX_TEC_NREGS 0x1000 typedef struct TCXState { - uint32_t addr; + target_phys_addr_t addr; DisplayState *ds; uint8_t *vram; uint32_t *vram24, *cplane; @@ -359,7 +359,6 @@ static void tcx_save(QEMUFile *f, void *opaque) { TCXState *s = opaque; - qemu_put_be32s(f, (uint32_t *)&s->addr); qemu_put_be32s(f, (uint32_t *)&s->vram); qemu_put_be32s(f, (uint32_t *)&s->vram24); qemu_put_be32s(f, (uint32_t *)&s->cplane); @@ -377,10 +376,9 @@ static int tcx_load(QEMUFile *f, void *opaque, int version_id) { TCXState *s = opaque; - if (version_id != 2) + if (version_id != 3) return -EINVAL; - qemu_get_be32s(f, (uint32_t *)&s->addr); qemu_get_be32s(f, (uint32_t *)&s->vram); qemu_get_be32s(f, (uint32_t *)&s->vram24); qemu_get_be32s(f, (uint32_t *)&s->cplane); @@ -492,7 +490,7 @@ static CPUWriteMemoryFunc *tcx_dummy_write[3] = { tcx_dummy_writel, }; -void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, +void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, unsigned long vram_offset, int vram_size, int width, int height, int depth) { @@ -513,23 +511,23 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, // 8-bit plane s->vram = vram_base; size = vram_size; - cpu_register_physical_memory(addr + 0x00800000, size, vram_offset); + cpu_register_physical_memory(addr + 0x00800000ULL, size, vram_offset); vram_offset += size; vram_base += size; io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); - cpu_register_physical_memory(addr + 0x00200000, TCX_DAC_NREGS, io_memory); + cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, io_memory); dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write, s); - cpu_register_physical_memory(addr + 0x00700000, TCX_TEC_NREGS, + cpu_register_physical_memory(addr + 0x00700000ULL, TCX_TEC_NREGS, dummy_memory); if (depth == 24) { // 24-bit plane size = vram_size * 4; s->vram24 = (uint32_t *)vram_base; s->vram24_offset = vram_offset; - cpu_register_physical_memory(addr + 0x02000000, size, vram_offset); + cpu_register_physical_memory(addr + 0x02000000ULL, size, vram_offset); vram_offset += size; vram_base += size; @@ -537,20 +535,20 @@ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, size = vram_size * 4; s->cplane = (uint32_t *)vram_base; s->cplane_offset = vram_offset; - cpu_register_physical_memory(addr + 0x0a000000, size, vram_offset); + cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset); graphic_console_init(s->ds, tcx24_update_display, tcx24_invalidate_display, tcx24_screen_dump, s); } else { - cpu_register_physical_memory(addr + 0x00300000, TCX_THC_NREGS_8, + cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8, dummy_memory); graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, tcx_screen_dump, s); } // NetBSD writes here even with 8-bit display - cpu_register_physical_memory(addr + 0x00301000, TCX_THC_NREGS_24, + cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24, dummy_memory); - register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); + register_savevm("tcx", addr, 3, tcx_save, tcx_load, s); qemu_register_reset(tcx_reset, s); tcx_reset(s); dpy_resize(s->ds, width, height); diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 7e993b7a1..b067d7b9b 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -290,7 +290,7 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); void raise_exception(int tt); -void do_unassigned_access(target_ulong addr, int is_write, int is_exec, +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int is_asi); #include "cpu-all.h" diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 8f12667df..da81562fc 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -117,7 +117,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot } *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); - *physical = 0xfffff000; + *physical = 0xffffffffffff0000ULL; /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ /* Context base + context number */ @@ -203,7 +203,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot /* Even if large ptes, we map only one 4KB page in the cache to avoid filling it too fast */ - *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset; + *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset; return error_code; } @@ -212,7 +212,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { target_phys_addr_t paddr; - unsigned long vaddr; + target_ulong vaddr; int error_code = 0, prot, ret = 0, access_index; error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); @@ -220,7 +220,8 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, vaddr = address & TARGET_PAGE_MASK; paddr &= TARGET_PAGE_MASK; #ifdef DEBUG_MMU - printf("Translate at 0x%lx -> 0x%lx, vaddr 0x%lx\n", (long)address, (long)paddr, (long)vaddr); + printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " + TARGET_FMT_lx "\n", address, paddr, vaddr); #endif ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; @@ -255,7 +256,8 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) uint32_t pde; /* Context base + context number */ - pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); + pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) + + (env->mmuregs[2] << 2); pde = ldl_phys(pde_ptr); switch (pde & PTE_ENTRYTYPE_MASK) { @@ -314,30 +316,35 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) #ifdef DEBUG_MMU void dump_mmu(CPUState *env) { - target_ulong va, va1, va2; - unsigned int n, m, o; - target_phys_addr_t pde_ptr, pa; + target_ulong va, va1, va2; + unsigned int n, m, o; + target_phys_addr_t pde_ptr, pa; uint32_t pde; printf("MMU dump:\n"); pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); pde = ldl_phys(pde_ptr); - printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]); + printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n", + (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { - pde_ptr = mmu_probe(env, va, 2); - if (pde_ptr) { + pde = mmu_probe(env, va, 2); + if (pde) { pa = cpu_get_phys_page_debug(env, va); - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr); + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx + " PDE: " TARGET_FMT_lx "\n", va, pa, pde); for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { - pde_ptr = mmu_probe(env, va1, 1); - if (pde_ptr) { + pde = mmu_probe(env, va1, 1); + if (pde) { pa = cpu_get_phys_page_debug(env, va1); - printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr); + printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx + " PDE: " TARGET_FMT_lx "\n", va1, pa, pde); for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { - pde_ptr = mmu_probe(env, va2, 0); - if (pde_ptr) { + pde = mmu_probe(env, va2, 0); + if (pde) { pa = cpu_get_phys_page_debug(env, va2); - printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr); + printf(" VA: " TARGET_FMT_lx ", PA: " + TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n", + va2, pa, pde); } } } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index bdc5b0e15..93f61a802 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -223,7 +223,31 @@ void helper_ld_asi(int asi, int size, int sign) break; } break; - case 0x21 ... 0x2f: /* MMU passthrough, unassigned */ + case 0x2e: /* MMU passthrough, 0xexxxxxxxx */ + case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */ + switch(size) { + case 1: + ret = ldub_phys((target_phys_addr_t)T0 + | ((target_phys_addr_t)(asi & 0xf) << 32)); + break; + case 2: + ret = lduw_phys((target_phys_addr_t)(T0 & ~1) + | ((target_phys_addr_t)(asi & 0xf) << 32)); + break; + default: + case 4: + ret = ldl_phys((target_phys_addr_t)(T0 & ~3) + | ((target_phys_addr_t)(asi & 0xf) << 32)); + break; + case 8: + ret = ldl_phys((target_phys_addr_t)(T0 & ~3) + | ((target_phys_addr_t)(asi & 0xf) << 32)); + T0 = ldl_phys((target_phys_addr_t)((T0 + 4) & ~3) + | ((target_phys_addr_t)(asi & 0xf) << 32)); + break; + } + break; + case 0x21 ... 0x2d: /* MMU passthrough, unassigned */ default: do_unassigned_access(T0, 0, 0, 1); ret = 0; @@ -360,12 +384,38 @@ void helper_st_asi(int asi, int size, int sign) } } return; + case 0x2e: /* MMU passthrough, 0xexxxxxxxx */ + case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */ + { + switch(size) { + case 1: + stb_phys((target_phys_addr_t)T0 + | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + break; + case 2: + stw_phys((target_phys_addr_t)(T0 & ~1) + | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + break; + case 4: + default: + stl_phys((target_phys_addr_t)(T0 & ~3) + | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + break; + case 8: + stl_phys((target_phys_addr_t)(T0 & ~3) + | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + stl_phys((target_phys_addr_t)((T0 + 4) & ~3) + | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + break; + } + } + return; case 0x31: /* Ross RT620 I-cache flush */ case 0x36: /* I-cache flash clear */ case 0x37: /* D-cache flash clear */ break; case 9: /* Supervisor code access, XXX */ - case 0x21 ... 0x2f: /* MMU passthrough, unassigned */ + case 0x21 ... 0x2d: /* MMU passthrough, unassigned */ default: do_unassigned_access(T0, 1, 0, 1); return; @@ -1035,7 +1085,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) #endif #ifndef TARGET_SPARC64 -void do_unassigned_access(target_ulong addr, int is_write, int is_exec, +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int is_asi) { CPUState *saved_env; @@ -1058,7 +1108,7 @@ void do_unassigned_access(target_ulong addr, int is_write, int is_exec, env->mmuregs[4] = addr; /* Fault address register */ if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx + printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx "\n", addr, env->pc); #endif raise_exception(TT_DATA_ACCESS); @@ -1066,7 +1116,7 @@ void do_unassigned_access(target_ulong addr, int is_write, int is_exec, env = saved_env; } #else -void do_unassigned_access(target_ulong addr, int is_write, int is_exec, +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int is_asi) { #ifdef DEBUG_UNASSIGNED @@ -1076,7 +1126,7 @@ void do_unassigned_access(target_ulong addr, int is_write, int is_exec, generated code */ saved_env = env; env = cpu_single_env; - printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx "\n", + printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx "\n", addr, env->pc); env = saved_env; #endif diff --git a/vl.h b/vl.h index 171b02b87..36ab2d2bb 100644 --- a/vl.h +++ b/vl.h @@ -1024,7 +1024,7 @@ extern BlockDriverState *fd_table[MAX_FD]; typedef struct fdctrl_t fdctrl_t; fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, - uint32_t io_base, + target_phys_addr_t io_base, BlockDriverState **fds); int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); @@ -1047,7 +1047,8 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); void pcnet_h_reset(void *opaque); -void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq); +void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, + qemu_irq irq); /* vmmouse.c */ void *vmmouse_init(void *m); @@ -1208,7 +1209,7 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); extern QEMUMachine ss5_machine, ss10_machine; /* iommu.c */ -void *iommu_init(uint32_t addr); +void *iommu_init(target_phys_addr_t addr); void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write); static inline void sparc_iommu_memory_read(void *opaque, @@ -1226,13 +1227,13 @@ static inline void sparc_iommu_memory_write(void *opaque, } /* tcx.c */ -void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, - unsigned long vram_offset, int vram_size, int width, int height, +void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size, int width, int height, int depth); /* slavio_intctl.c */ void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); -void *slavio_intctl_init(uint32_t addr, uint32_t addrg, +void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, const uint32_t *intbit_to_level, qemu_irq **irq); void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); @@ -1248,26 +1249,28 @@ int load_aout(const char *filename, uint8_t *addr); int load_uboot(const char *filename, target_ulong *ep, int *is_linux); /* slavio_timer.c */ -void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu, - void *intctl); +void slavio_timer_init(target_phys_addr_t addr, int irq, int mode, + unsigned int cpu, void *intctl); /* slavio_serial.c */ -SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1, - CharDriverState *chr2); -void slavio_serial_ms_kbd_init(int base, qemu_irq); +SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, + CharDriverState *chr1, CharDriverState *chr2); +void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq); /* slavio_misc.c */ -void *slavio_misc_init(uint32_t base, qemu_irq irq); +void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, + qemu_irq irq); void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); -void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque); +void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, + void *dma_opaque); void esp_reset(void *opaque); /* sparc32_dma.c */ -void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq, - void *iommu); +void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq espirq, + qemu_irq leirq, void *iommu); void ledma_set_irq(void *opaque, int isr); void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); -- cgit v1.2.3 From 642b043a9eb85ee98636b44935aa39006f6d3643 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 19 May 2007 13:12:09 +0000 Subject: Update Sparc32 OpenBIOS image to SVN revision 149. Changes: r145: Fix power-management location for SS-10 r146: Fix overallocation r147: NetBSD and OpenBSD fixes: - Correct timer and interrupt controller mappings - Add ESP clock frequency to avoid division by zero - CS4231 exists only in SS5 - Disable BPP for now, it's not emulated by Qemu anyway With these fixes, one NetBSD kernel even got to root device prompt on SS5. r148: Update vsprintf.c from Linux to get 64-bit output r149: Use full 36-bit physical address space on SS10 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2831 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 2 +- pc-bios/openbios-sparc32 | Bin 268852 -> 272948 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/README b/pc-bios/README index 3360f9f37..ba1568e57 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,7 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 image is built from SVN version 144 and Sparc64 + The included Sparc32 image is built from SVN version 149 and Sparc64 image from version 125. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 6be9400c4..62cc5eb7b 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ -- cgit v1.2.3 From 5d46d55d4b0f2be4ff7f553013fca4f7980549ab Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 19 May 2007 17:44:33 +0000 Subject: Fix ldl/ldr implementation, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2832 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 57e5777cc..a360d11fc 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -761,6 +761,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, opn = "scd"; break; case OPC_LDL: + GEN_LOAD_REG_TN(T1, rt); op_ldst(ldl); GEN_STORE_TN_REG(rt, T0); opn = "ldl"; @@ -771,6 +772,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, opn = "sdl"; break; case OPC_LDR: + GEN_LOAD_REG_TN(T1, rt); op_ldst(ldr); GEN_STORE_TN_REG(rt, T0); opn = "ldr"; -- cgit v1.2.3 From f469b9db01a1287ae8946159beace6285c2e213a Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 19 May 2007 17:45:43 +0000 Subject: Fix slti/sltiu for MIPS64, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2833 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 12 ++++++------ target-mips/translate.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 5e3c79732..c60871afe 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -928,14 +928,14 @@ void glue(op_, name) (void) \ OP_COND(eq, T0 == T1); OP_COND(ne, T0 != T1); -OP_COND(ge, (int32_t)T0 >= (int32_t)T1); +OP_COND(ge, (target_long)T0 >= (target_long)T1); OP_COND(geu, T0 >= T1); -OP_COND(lt, (int32_t)T0 < (int32_t)T1); +OP_COND(lt, (target_long)T0 < (target_long)T1); OP_COND(ltu, T0 < T1); -OP_COND(gez, (int32_t)T0 >= 0); -OP_COND(gtz, (int32_t)T0 > 0); -OP_COND(lez, (int32_t)T0 <= 0); -OP_COND(ltz, (int32_t)T0 < 0); +OP_COND(gez, (target_long)T0 >= 0); +OP_COND(gtz, (target_long)T0 > 0); +OP_COND(lez, (target_long)T0 <= 0); +OP_COND(ltz, (target_long)T0 < 0); /* Branches */ void OPPROTO op_goto_tb0(void) diff --git a/target-mips/translate.c b/target-mips/translate.c index a360d11fc..0396ac396 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -921,7 +921,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) { - uint32_t uimm; + target_ulong uimm; const char *opn = "imm arith"; if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { @@ -941,7 +941,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, #endif case OPC_SLTI: case OPC_SLTIU: - uimm = (int32_t)imm; /* Sign extend to 32 bits */ + uimm = (target_long)imm; /* Sign extend to 32/64 bits */ /* Fall through. */ case OPC_ANDI: case OPC_ORI: -- cgit v1.2.3 From 57fa1fb31c23f1bf78664159d5813206bf2e4d0e Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 19 May 2007 20:29:41 +0000 Subject: More MIPS 64-bit FPU support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2834 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 96 ++++++++++----------- target-mips/op.c | 68 ++++++++++----- target-mips/op_helper.c | 92 +++++++++++++++++++++ target-mips/translate.c | 216 +++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 369 insertions(+), 103 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index 7ebfd78e7..6d004102b 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -166,6 +166,36 @@ void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); void do_ctc1 (void); + +#define FOP_PROTO(op) \ +void do_float_ ## op ## _s(void); \ +void do_float_ ## op ## _d(void); +FOP_PROTO(roundl) +FOP_PROTO(roundw) +FOP_PROTO(truncl) +FOP_PROTO(truncw) +FOP_PROTO(ceill) +FOP_PROTO(ceilw) +FOP_PROTO(floorl) +FOP_PROTO(floorw) +FOP_PROTO(rsqrt) +FOP_PROTO(recip) +#undef FOP_PROTO + +#define FOP_PROTO(op) \ +void do_float_ ## op ## _s(void); \ +void do_float_ ## op ## _d(void); \ +void do_float_ ## op ## _ps(void); +FOP_PROTO(add) +FOP_PROTO(sub) +FOP_PROTO(mul) +FOP_PROTO(div) +FOP_PROTO(recip1) +FOP_PROTO(recip2) +FOP_PROTO(rsqrt1) +FOP_PROTO(rsqrt2) +#undef FOP_PROTO + void do_float_cvtd_s(void); void do_float_cvtd_w(void); void do_float_cvtd_l(void); @@ -180,37 +210,11 @@ void do_float_cvts_pl(void); void do_float_cvts_pu(void); void do_float_cvtw_s(void); void do_float_cvtw_d(void); -void do_float_roundl_d(void); -void do_float_roundl_s(void); -void do_float_roundw_d(void); -void do_float_roundw_s(void); -void do_float_truncl_d(void); -void do_float_truncl_s(void); -void do_float_truncw_d(void); -void do_float_truncw_s(void); -void do_float_ceill_d(void); -void do_float_ceill_s(void); -void do_float_ceilw_d(void); -void do_float_ceilw_s(void); -void do_float_floorl_d(void); -void do_float_floorl_s(void); -void do_float_floorw_d(void); -void do_float_floorw_s(void); -void do_float_add_d(void); -void do_float_add_s(void); -void do_float_add_ps(void); -void do_float_sub_d(void); -void do_float_sub_s(void); -void do_float_sub_ps(void); -void do_float_mul_d(void); -void do_float_mul_s(void); -void do_float_mul_ps(void); -void do_float_div_d(void); -void do_float_div_s(void); -void do_float_div_ps(void); + void do_float_addr_ps(void); +void do_float_mulr_ps(void); -#define CMP_OPS(op) \ +#define FOP_PROTO(op) \ void do_cmp_d_ ## op(long cc); \ void do_cmpabs_d_ ## op(long cc); \ void do_cmp_s_ ## op(long cc); \ @@ -218,22 +222,22 @@ void do_cmpabs_s_ ## op(long cc); \ void do_cmp_ps_ ## op(long cc); \ void do_cmpabs_ps_ ## op(long cc); -CMP_OPS(f) -CMP_OPS(un) -CMP_OPS(eq) -CMP_OPS(ueq) -CMP_OPS(olt) -CMP_OPS(ult) -CMP_OPS(ole) -CMP_OPS(ule) -CMP_OPS(sf) -CMP_OPS(ngle) -CMP_OPS(seq) -CMP_OPS(ngl) -CMP_OPS(lt) -CMP_OPS(nge) -CMP_OPS(le) -CMP_OPS(ngt) -#undef CMP_OPS +FOP_PROTO(f) +FOP_PROTO(un) +FOP_PROTO(eq) +FOP_PROTO(ueq) +FOP_PROTO(olt) +FOP_PROTO(ult) +FOP_PROTO(ole) +FOP_PROTO(ule) +FOP_PROTO(sf) +FOP_PROTO(ngle) +FOP_PROTO(seq) +FOP_PROTO(ngl) +FOP_PROTO(lt) +FOP_PROTO(nge) +FOP_PROTO(le) +FOP_PROTO(ngt) +#undef FOP_PROTO #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ diff --git a/target-mips/op.c b/target-mips/op.c index c60871afe..8c0c687a8 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1609,6 +1609,14 @@ void op_cp1_enabled(void) RETURN(); } +void op_cp1_64bitmode(void) +{ + if (!(env->CP0_Status & (1 << CP0St_FR))) { + CALL_FROM_TB1(do_raise_exception, EXCP_RI); + } + RETURN(); +} + /* * Verify if floating point register is valid; an operation is not defined * if bit 0 of any register specification is set and the FR bit in the @@ -1946,8 +1954,8 @@ FLOAT_OP(movn, ps) RETURN(); } -/* binary operations */ -#define FLOAT_BINOP(name) \ +/* operations calling helpers, for s, d and ps */ +#define FLOAT_HOP(name) \ FLOAT_OP(name, d) \ { \ CALL_FROM_TB0(do_float_ ## name ## _d); \ @@ -1966,18 +1974,45 @@ FLOAT_OP(name, ps) \ DEBUG_FPU_STATE(); \ RETURN(); \ } -FLOAT_BINOP(add) -FLOAT_BINOP(sub) -FLOAT_BINOP(mul) -FLOAT_BINOP(div) -#undef FLOAT_BINOP +FLOAT_HOP(add) +FLOAT_HOP(sub) +FLOAT_HOP(mul) +FLOAT_HOP(div) +FLOAT_HOP(recip2) +FLOAT_HOP(rsqrt2) +FLOAT_HOP(rsqrt1) +FLOAT_HOP(recip1) +#undef FLOAT_HOP + +/* operations calling helpers, for s and d */ +#define FLOAT_HOP(name) \ +FLOAT_OP(name, d) \ +{ \ + CALL_FROM_TB0(do_float_ ## name ## _d); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + CALL_FROM_TB0(do_float_ ## name ## _s); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} +FLOAT_HOP(rsqrt) +FLOAT_HOP(recip) +#undef FLOAT_HOP -FLOAT_OP(addr, ps) -{ - CALL_FROM_TB0(do_float_addr_ps); - DEBUG_FPU_STATE(); - RETURN(); +/* operations calling helpers, for ps */ +#define FLOAT_HOP(name) \ +FLOAT_OP(name, ps) \ +{ \ + CALL_FROM_TB0(do_float_ ## name ## _ps); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ } +FLOAT_HOP(addr) +FLOAT_HOP(mulr) +#undef FLOAT_HOP /* ternary operations */ #define FLOAT_TERNOP(name1, name2) \ @@ -2053,14 +2088,7 @@ FLOAT_OP(name, s) \ { \ FST2 = float32_ ## name(FST0, &env->fp_status); \ DEBUG_FPU_STATE(); \ - RETURN(); \ -} \ -FLOAT_OP(name, ps) \ -{ \ - FST2 = float32_ ## name(FST0, &env->fp_status); \ - FSTH2 = float32_ ## name(FSTH0, &env->fp_status); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ + RETURN(); \ } FLOAT_UNOP(sqrt) #undef FLOAT_UNOP diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 85ad33355..9a0ffee9a 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -916,6 +916,59 @@ FLOAT_OP(floorw, s) WT2 = 0x7fffffff; } +/* unary operations, MIPS specific, s and d */ +#define FLOAT_UNOP(name) \ +FLOAT_OP(name, d) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ +/* XXX: not implemented */ \ +/* FDT2 = float64_ ## name (FDT0, &env->fp_status);*/ \ +do_raise_exception(EXCP_RI); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ +/* XXX: not implemented */ \ +/* FST2 = float32_ ## name (FST0, &env->fp_status);*/ \ +do_raise_exception(EXCP_RI); \ + update_fcr31(); \ +} +FLOAT_UNOP(rsqrt) +FLOAT_UNOP(recip) +#undef FLOAT_UNOP + +/* unary operations, MIPS specific, s, d and ps */ +#define FLOAT_UNOP(name) \ +FLOAT_OP(name, d) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ +/* XXX: not implemented */ \ +/* FDT2 = float64_ ## name (FDT0, &env->fp_status);*/ \ +do_raise_exception(EXCP_RI); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ +/* XXX: not implemented */ \ +/* FST2 = float32_ ## name (FST0, &env->fp_status);*/ \ +do_raise_exception(EXCP_RI); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, ps) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ +/* XXX: not implemented */ \ +/* FST2 = float32_ ## name (FST0, &env->fp_status);*/ \ +/* FSTH2 = float32_ ## name (FSTH0, &env->fp_status);*/ \ +do_raise_exception(EXCP_RI); \ + update_fcr31(); \ +} +FLOAT_UNOP(rsqrt1) +FLOAT_UNOP(recip1) +#undef FLOAT_UNOP + /* binary operations */ #define FLOAT_BINOP(name) \ FLOAT_OP(name, d) \ @@ -943,6 +996,37 @@ FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP +/* binary operations, MIPS specific */ +#define FLOAT_BINOP(name) \ +FLOAT_OP(name, d) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ +/* XXX: not implemented */ \ +/* FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);*/ \ +do_raise_exception(EXCP_RI); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ +/* XXX: not implemented */ \ +/* FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/ \ +do_raise_exception(EXCP_RI); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, ps) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ +/* XXX: not implemented */ \ +/* FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/ \ +/* FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status);*/ \ +do_raise_exception(EXCP_RI); \ + update_fcr31(); \ +} +FLOAT_BINOP(rsqrt2) +FLOAT_BINOP(recip2) +#undef FLOAT_BINOP + FLOAT_OP(addr, ps) { set_float_exception_flags(0, &env->fp_status); @@ -951,6 +1035,14 @@ FLOAT_OP(addr, ps) update_fcr31(); } +FLOAT_OP(mulr, ps) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_mul (FST0, FSTH0, &env->fp_status); + FSTH2 = float32_mul (FST1, FSTH1, &env->fp_status); + update_fcr31(); +} + #define FOP_COND_D(op, cond) \ void do_cmp_d_ ## op (long cc) \ { \ diff --git a/target-mips/translate.c b/target-mips/translate.c index 0396ac396..075be1ed0 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4378,14 +4378,12 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "dmtc1"; break; case OPC_MFHC1: - gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_mfhc1(); GEN_STORE_TN_REG(rt, T0); opn = "mfhc1"; break; case OPC_MTHC1: - gen_op_cp1_registers(fs); GEN_LOAD_REG_TN(T0, rt); gen_op_mthc1(); GEN_STORE_FTN_FREG(fs, WTH0); @@ -4405,9 +4403,9 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) GEN_LOAD_REG_TN(T0, rd); GEN_LOAD_REG_TN(T1, rs); - if (cc) + if (cc) { ccbit = 1 << (24 + cc); - else + } else ccbit = 1 << 23; if (!tf) gen_op_movf(ccbit); @@ -4421,9 +4419,9 @@ static void glue(gen_movcf_, fmt) (DisasContext *ctx, int cc, int tf) \ { \ uint32_t ccbit; \ \ - if (cc) \ + if (cc) { \ ccbit = 1 << (24 + cc); \ - else \ + } else \ ccbit = 1 << 23; \ if (!tf) \ glue(gen_op_float_movf_, fmt)(ccbit); \ @@ -4536,28 +4534,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "neg.s"; break; case FOP(8, 16): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_roundl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.s"; break; case FOP(9, 16): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_truncl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.s"; break; case FOP(10, 16): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_ceill_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.s"; break; case FOP(11, 16): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_floorl_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4611,6 +4609,48 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, GEN_STORE_FTN_FREG(fd, WT2); opn = "movn.s"; break; + case FOP(21, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_recip_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "recip.s"; + break; + case FOP(22, 16): + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_rsqrt_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "rsqrt.s"; + break; + case FOP(28, 16): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + gen_op_float_recip2_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "recip2.s"; + break; + case FOP(29, 16): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_recip1_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "recip1.s"; + break; + case FOP(30, 16): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + gen_op_float_rsqrt1_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "rsqrt1.s"; + break; + case FOP(31, 16): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + gen_op_float_rsqrt2_s(); + GEN_STORE_FTN_FREG(fd, WT2); + opn = "rsqrt2.s"; + break; case FOP(33, 16): gen_op_cp1_registers(fd); GEN_LOAD_FREG_FTN(WT0, fs); @@ -4625,14 +4665,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.w.s"; break; case FOP(37, 16): - gen_op_cp1_registers(fs | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.l.s"; break; case FOP(38, 16): - gen_op_cp1_registers(fs | ft | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT1, fs); GEN_LOAD_FREG_FTN(WT0, ft); gen_op_float_cvtps_s(); @@ -4658,6 +4698,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); if (ctx->opcode & (1 << 6)) { + gen_op_cp1_64bitmode(); gen_cmpabs_s(func-48, cc); opn = condnames_abs[func-48]; } else { @@ -4730,28 +4771,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "neg.d"; break; case FOP(8, 17): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.d"; break; case FOP(9, 17): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.d"; break; case FOP(10, 17): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceill_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.d"; break; case FOP(11, 17): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorl_d(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4809,6 +4850,50 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, GEN_STORE_FTN_FREG(fd, DT2); opn = "movn.d"; break; + case FOP(21, 17): + gen_op_cp1_registers(fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_recip_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "recip.d"; + break; + case FOP(22, 17): + gen_op_cp1_registers(fs | fd); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_rsqrt_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "rsqrt.d"; + break; + case FOP(28, 17): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT2, ft); + gen_op_float_recip2_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "recip2.d"; + break; + case FOP(29, 17): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_recip1_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "recip1.d"; + break; + case FOP(30, 17): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(DT0, fs); + gen_op_float_rsqrt1_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "rsqrt1.d"; + break; + case FOP(31, 17): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(DT0, fs); + GEN_LOAD_FREG_FTN(DT2, ft); + gen_op_float_rsqrt2_d(); + GEN_STORE_FTN_FREG(fd, DT2); + opn = "rsqrt2.d"; + break; case FOP(48, 17): case FOP(49, 17): case FOP(50, 17): @@ -4825,13 +4910,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 17): case FOP(62, 17): case FOP(63, 17): - gen_op_cp1_registers(fs | ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); if (ctx->opcode & (1 << 6)) { + gen_op_cp1_64bitmode(); gen_cmpabs_d(func-48, cc); opn = condnames_abs[func-48]; } else { + gen_op_cp1_registers(fs | ft); gen_cmp_d(func-48, cc); opn = condnames[func-48]; } @@ -4851,7 +4937,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.w.d"; break; case FOP(37, 17): - gen_op_cp1_registers(fs | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtl_d(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4871,14 +4957,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.d.w"; break; case FOP(32, 21): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_l(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.l"; break; case FOP(33, 21): - gen_op_cp1_registers(fs | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtd_l(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4886,7 +4972,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, break; case FOP(38, 20): case FOP(38, 21): - gen_op_cp1_registers(fs | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtps_pw(); @@ -4895,7 +4981,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.ps.pw"; break; case FOP(0, 22): - gen_op_cp1_registers(fs | ft | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4906,7 +4992,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "add.ps"; break; case FOP(1, 22): - gen_op_cp1_registers(fs | ft | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4917,7 +5003,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "sub.ps"; break; case FOP(2, 22): - gen_op_cp1_registers(fs | ft | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4928,7 +5014,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mul.ps"; break; case FOP(5, 22): - gen_op_cp1_registers(fs | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_abs_ps(); @@ -4937,7 +5023,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "abs.ps"; break; case FOP(6, 22): - gen_op_cp1_registers(fs | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_mov_ps(); @@ -4946,7 +5032,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mov.ps"; break; case FOP(7, 22): - gen_op_cp1_registers(fs | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_chs_ps(); @@ -4955,6 +5041,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "neg.ps"; break; case FOP(17, 22): + gen_op_cp1_64bitmode(); GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); @@ -4966,6 +5053,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movcf.ps"; break; case FOP(18, 22): + gen_op_cp1_64bitmode(); GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); @@ -4977,6 +5065,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movz.ps"; break; case FOP(19, 22): + gen_op_cp1_64bitmode(); GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); @@ -4988,7 +5077,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.ps"; break; case FOP(24, 22): - gen_op_cp1_registers(fs | fd | ft); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4998,15 +5087,66 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, GEN_STORE_FTN_FREG(fd, WTH2); opn = "addr.ps"; break; + case FOP(26, 22): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT1, ft); + GEN_LOAD_FREG_FTN(WTH1, ft); + gen_op_float_mulr_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "mulr.ps"; + break; + case FOP(28, 22): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + GEN_LOAD_FREG_FTN(WTH2, fd); + gen_op_float_recip2_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "recip2.ps"; + break; + case FOP(29, 22): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_float_recip1_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "recip1.ps"; + break; + case FOP(30, 22): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + gen_op_float_rsqrt1_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "rsqrt1.ps"; + break; + case FOP(31, 22): + gen_op_cp1_64bitmode(); + GEN_LOAD_FREG_FTN(WT0, fs); + GEN_LOAD_FREG_FTN(WTH0, fs); + GEN_LOAD_FREG_FTN(WT2, fd); + GEN_LOAD_FREG_FTN(WTH2, fd); + gen_op_float_rsqrt2_ps(); + GEN_STORE_FTN_FREG(fd, WT2); + GEN_STORE_FTN_FREG(fd, WTH2); + opn = "rsqrt2.ps"; + break; case FOP(32, 22): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvts_pu(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pu"; break; case FOP(36, 22): - gen_op_cp1_registers(fs | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtpw_ps(); @@ -5015,14 +5155,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.pw.ps"; break; case FOP(40, 22): - gen_op_cp1_registers(fs); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvts_pl(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pl"; break; case FOP(44, 22): - gen_op_cp1_registers(fs | ft | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pll_ps(); @@ -5030,7 +5170,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pll.ps"; break; case FOP(45, 22): - gen_op_cp1_registers(fs | ft | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_plu_ps(); @@ -5038,7 +5178,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "plu.ps"; break; case FOP(46, 22): - gen_op_cp1_registers(fs | ft | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pul_ps(); @@ -5046,7 +5186,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pul.ps"; break; case FOP(47, 22): - gen_op_cp1_registers(fs | ft | fd); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_puu_ps(); @@ -5069,7 +5209,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 22): case FOP(62, 22): case FOP(63, 22): - gen_op_cp1_registers(fs | ft); + gen_op_cp1_64bitmode(); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5106,6 +5246,8 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, { const char *opn = "extended float load/store"; + /* All of those work only on 64bit FPUs. */ + gen_op_cp1_64bitmode(); GEN_LOAD_REG_TN(T0, base); GEN_LOAD_REG_TN(T1, index); /* Don't do NOP if destination is zero: we must perform the actual @@ -5156,7 +5298,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, const char *opn = "flt3_arith"; /* All of those work only on 64bit FPUs. */ - gen_op_cp1_registers(fd | fr | fs | ft); + gen_op_cp1_64bitmode(); switch (opc) { case OPC_ALNV_PS: GEN_LOAD_REG_TN(T0, fr); -- cgit v1.2.3 From 642a4f967f69a86bd59ad7c7d0adf8e80d0b4b54 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 19 May 2007 21:04:38 +0000 Subject: Linux loader rewrite, by H. Peter Anvin. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2835 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 304 ++++++++++++++++++++++++++++++++++++++++--------------- pc-bios/Makefile | 7 -- 2 files changed, 222 insertions(+), 89 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index e8dca4de0..89e93e83f 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -31,10 +31,6 @@ #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin" #define LINUX_BOOT_FILENAME "linux_boot.bin" -#define KERNEL_LOAD_ADDR 0x00100000 -#define MAX_INITRD_LOAD_ADDR 0x38000000 -#define KERNEL_PARAMS_ADDR 0x00090000 -#define KERNEL_CMDLINE_ADDR 0x00099000 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ #define ACPI_DATA_SIZE 0x10000 @@ -350,6 +346,61 @@ void bochs_bios_init(void) register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); } +/* Generate an initial boot sector which sets state and jump to + a specified vector */ +static int generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) +{ + uint8_t bootsect[512], *p; + int i; + + if (bs_table[0] == NULL) { + fprintf(stderr, "A disk image must be given for 'hda' when booting " + "a Linux kernel\n"); + exit(1); + } + + memset(bootsect, 0, sizeof(bootsect)); + + /* Copy the MSDOS partition table if possible */ + bdrv_read(bs_table[0], 0, bootsect, 1); + + /* Make sure we have a partition signature */ + bootsect[510] = 0x55; + bootsect[511] = 0xaa; + + /* Actual code */ + p = bootsect; + *p++ = 0xfa; /* CLI */ + *p++ = 0xfc; /* CLD */ + + for (i = 0; i < 6; i++) { + if (i == 1) /* Skip CS */ + continue; + + *p++ = 0xb8; /* MOV AX,imm16 */ + *p++ = segs[i]; + *p++ = segs[i] >> 8; + *p++ = 0x8e; /* MOV ,AX */ + *p++ = 0xc0 + (i << 3); + } + + for (i = 0; i < 8; i++) { + *p++ = 0x66; /* 32-bit operand size */ + *p++ = 0xb8 + i; /* MOV ,imm32 */ + *p++ = gpr[i]; + *p++ = gpr[i] >> 8; + *p++ = gpr[i] >> 16; + *p++ = gpr[i] >> 24; + } + + *p++ = 0xea; /* JMP FAR */ + *p++ = ip; /* IP */ + *p++ = ip >> 8; + *p++ = segs[1]; /* CS */ + *p++ = segs[1] >> 8; + + bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); +} int load_kernel(const char *filename, uint8_t *addr, uint8_t *real_addr) @@ -370,7 +421,7 @@ int load_kernel(const char *filename, uint8_t *addr, if (read(fd, real_addr + 512, setup_sects * 512) != setup_sects * 512) goto fail; - + /* load 32 bit code */ size = read(fd, addr, 16 * 1024 * 1024); if (size < 0) @@ -382,6 +433,169 @@ int load_kernel(const char *filename, uint8_t *addr, return -1; } +static long get_file_size(FILE *f) +{ + long where, size; + + /* XXX: on Unix systems, using fstat() probably makes more sense */ + + where = ftell(f); + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, where, SEEK_SET); + + return size; +} + +static void load_linux(const char *kernel_filename, + const char *initrd_filename, + const char *kernel_cmdline) +{ + uint16_t protocol; + uint32_t gpr[8]; + uint16_t seg[6]; + uint16_t real_seg; + int setup_size, kernel_size, initrd_size, cmdline_size; + uint32_t initrd_max; + uint8_t header[1024]; + uint8_t *real_addr, *prot_addr, *cmdline_addr, *initrd_addr; + FILE *f, *fi; + + /* Align to 16 bytes as a paranoia measure */ + cmdline_size = (strlen(kernel_cmdline)+16) & ~15; + + /* load the kernel header */ + f = fopen(kernel_filename, "rb"); + if (!f || !(kernel_size = get_file_size(f)) || + fread(header, 1, 1024, f) != 1024) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* kernel protocol version */ + fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202)); + if (ldl_p(header+0x202) == 0x53726448) + protocol = lduw_p(header+0x206); + else + protocol = 0; + + if (protocol < 0x200 || !(header[0x211] & 0x01)) { + /* Low kernel */ + real_addr = phys_ram_base + 0x90000; + cmdline_addr = phys_ram_base + 0x9a000 - cmdline_size; + prot_addr = phys_ram_base + 0x10000; + } else if (protocol < 0x202) { + /* High but ancient kernel */ + real_addr = phys_ram_base + 0x90000; + cmdline_addr = phys_ram_base + 0x9a000 - cmdline_size; + prot_addr = phys_ram_base + 0x100000; + } else { + /* High and recent kernel */ + real_addr = phys_ram_base + 0x10000; + cmdline_addr = phys_ram_base + 0x20000; + prot_addr = phys_ram_base + 0x100000; + } + + fprintf(stderr, + "qemu: real_addr = %#zx\n" + "qemu: cmdline_addr = %#zx\n" + "qemu: prot_addr = %#zx\n", + real_addr-phys_ram_base, + cmdline_addr-phys_ram_base, + prot_addr-phys_ram_base); + + /* highest address for loading the initrd */ + if (protocol >= 0x203) + initrd_max = ldl_p(header+0x22c); + else + initrd_max = 0x37ffffff; + + if (initrd_max >= ram_size-ACPI_DATA_SIZE) + initrd_max = ram_size-ACPI_DATA_SIZE-1; + + /* kernel command line */ + pstrcpy(cmdline_addr, 4096, kernel_cmdline); + + if (protocol >= 0x202) { + stl_p(header+0x228, cmdline_addr-phys_ram_base); + } else { + stw_p(header+0x20, 0xA33F); + stw_p(header+0x22, cmdline_addr-real_addr); + } + + /* loader type */ + /* High nybble = B reserved for Qemu; low nybble is revision number. + If this code is substantially changed, you may want to consider + incrementing the revision. */ + if (protocol >= 0x200) + header[0x210] = 0xB0; + + /* heap */ + if (protocol >= 0x201) { + header[0x211] |= 0x80; /* CAN_USE_HEAP */ + stw_p(header+0x224, cmdline_addr-real_addr-0x200); + } + + /* load initrd */ + if (initrd_filename) { + if (protocol < 0x200) { + fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n"); + exit(1); + } + + fi = fopen(initrd_filename, "rb"); + if (!fi) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + + initrd_size = get_file_size(fi); + initrd_addr = phys_ram_base + ((initrd_max-initrd_size) & ~4095); + + fprintf(stderr, "qemu: loading initrd (%#x bytes) at %#zx\n", + initrd_size, initrd_addr-phys_ram_base); + + if (fread(initrd_addr, 1, initrd_size, fi) != initrd_size) { + fprintf(stderr, "qemu: read error on initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + fclose(fi); + + stl_p(header+0x218, initrd_addr-phys_ram_base); + stl_p(header+0x21c, initrd_size); + } + + /* store the finalized header and load the rest of the kernel */ + memcpy(real_addr, header, 1024); + + setup_size = header[0x1f1]; + if (setup_size == 0) + setup_size = 4; + + setup_size = (setup_size+1)*512; + kernel_size -= setup_size; /* Size of protected-mode code */ + + if (fread(real_addr+1024, 1, setup_size-1024, f) != setup_size-1024 || + fread(prot_addr, 1, kernel_size, f) != kernel_size) { + fprintf(stderr, "qemu: read error on kernel '%s'\n", + kernel_filename); + exit(1); + } + fclose(f); + + /* generate bootsector to set up the initial register state */ + real_seg = (real_addr-phys_ram_base) >> 4; + seg[0] = seg[2] = seg[3] = seg[4] = seg[4] = real_seg; + seg[1] = real_seg+0x20; /* CS */ + memset(gpr, 0, sizeof gpr); + gpr[4] = cmdline_addr-real_addr-16; /* SP (-16 is paranoia) */ + + generate_bootsect(gpr, seg, 0); +} + static void main_cpu_reset(void *opaque) { CPUState *env = opaque; @@ -453,9 +667,8 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, int pci_enabled) { char buf[1024]; - int ret, linux_boot, initrd_size, i; + int ret, linux_boot, i; ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset; - ram_addr_t initrd_offset; int bios_size, isa_bios_size, vga_bios_size; PCIBus *pci_bus; int piix3_devfn = -1; @@ -570,81 +783,8 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, bochs_bios_init(); - if (linux_boot) { - uint8_t bootsect[512]; - uint8_t old_bootsect[512]; - - if (bs_table[0] == NULL) { - fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); - exit(1); - } - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); - ret = load_image(buf, bootsect); - if (ret != sizeof(bootsect)) { - fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", - buf); - exit(1); - } - - if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) { - /* copy the MSDOS partition table */ - memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40); - } - - bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); - - /* now we can load the kernel */ - ret = load_kernel(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR, - phys_ram_base + KERNEL_PARAMS_ADDR); - if (ret < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - initrd_offset = 0; - if (initrd_filename) { - initrd_size = get_image_size (initrd_filename); - if (initrd_size > 0) { - initrd_offset = (ram_size - initrd_size) & TARGET_PAGE_MASK; - /* Leave space for BIOS ACPI tables. */ - initrd_offset -= ACPI_DATA_SIZE; - /* Avoid the last 64k to avoid 2.2.x kernel bugs. */ - initrd_offset -= 0x10000; - if (initrd_offset > MAX_INITRD_LOAD_ADDR) - initrd_offset = MAX_INITRD_LOAD_ADDR; - - if (initrd_size > ram_size - || initrd_offset < KERNEL_LOAD_ADDR + ret) { - fprintf(stderr, - "qemu: memory too small for initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - initrd_size = load_image(initrd_filename, - phys_ram_base + initrd_offset); - } - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - if (initrd_size > 0) { - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, initrd_offset); - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); - } - pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, - kernel_cmdline); - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, - KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); - /* loader type */ - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); - } + if (linux_boot) + load_linux(kernel_filename, initrd_filename, kernel_cmdline); cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1); i8259 = i8259_init(cpu_irq[0]); diff --git a/pc-bios/Makefile b/pc-bios/Makefile index 7ae0ff02a..c817e851c 100644 --- a/pc-bios/Makefile +++ b/pc-bios/Makefile @@ -6,16 +6,9 @@ include ../config-host.mak DEFINES= TARGETS= -ifeq ($(ARCH),i386) -TARGETS+=linux_boot.bin -endif all: $(TARGETS) -linux_boot.bin: linux_boot.o - ld --oformat binary -Ttext 0 -o $@ $< - chmod a-x $@ - %.o: %.S $(CC) $(DEFINES) -c -o $@ $< -- cgit v1.2.3 From cfc05abe4c4640a3a83c36a6874815a1514d31e7 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 20 May 2007 01:34:23 +0000 Subject: Remove leftover file, should have happened in the Linux loader rewrite commit. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2836 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/linux_boot.S | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 pc-bios/linux_boot.S diff --git a/pc-bios/linux_boot.S b/pc-bios/linux_boot.S deleted file mode 100644 index 22fcd4be8..000000000 --- a/pc-bios/linux_boot.S +++ /dev/null @@ -1,29 +0,0 @@ -/* - * QEMU Boot sector to launch a preloaded Linux kernel - * Copyright (c) 2004 Fabrice Bellard - */ - -#define LOAD_SEG 0x9000 - -.code16 -.text - .globl _start - -_start: - cli - cld - mov $LOAD_SEG, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - mov $0x8ffe, %sp - ljmp $LOAD_SEG + 0x20, $0 - -1: - .fill 510 - (1b - _start), 1, 0 - - /* boot sector signature */ - .byte 0x55 - .byte 0xaa -- cgit v1.2.3 From 93b12ccc62debf438f0881898e6be0eeb51e1bdd Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 20 May 2007 01:36:29 +0000 Subject: Fix indexed FP load/store instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2837 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 1 + target-mips/op_mem.c | 26 ++------------------------ target-mips/translate.c | 45 ++++++++++++++++++++++++++++----------------- 3 files changed, 31 insertions(+), 41 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 8c0c687a8..9ba0050ce 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004-2005 Jocelyn Mayer * Copyright (c) 2006 Marius Groeger (FPU operations) + * Copyright (c) 2007 Thiemo Seufer (64-bit FPU support) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index f0eebc09d..f9fc69c8e 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -220,35 +220,13 @@ void glue(op_sdc1, MEMSUFFIX) (void) glue(stq, MEMSUFFIX)(T0, DT0); RETURN(); } -void glue(op_lwxc1, MEMSUFFIX) (void) -{ - WT0 = glue(ldl, MEMSUFFIX)(T0 + T1); - RETURN(); -} -void glue(op_swxc1, MEMSUFFIX) (void) -{ - glue(stl, MEMSUFFIX)(T0 + T1, WT0); - RETURN(); -} -void glue(op_ldxc1, MEMSUFFIX) (void) -{ - DT0 = glue(ldq, MEMSUFFIX)(T0 + T1); - RETURN(); -} -void glue(op_sdxc1, MEMSUFFIX) (void) -{ - glue(stq, MEMSUFFIX)(T0 + T1, DT0); - RETURN(); -} void glue(op_luxc1, MEMSUFFIX) (void) { - /* XXX: is defined as unaligned */ - DT0 = glue(ldq, MEMSUFFIX)(T0 + T1); + DT0 = glue(ldq, MEMSUFFIX)(T0 & ~0x7); RETURN(); } void glue(op_suxc1, MEMSUFFIX) (void) { - /* XXX: is defined as unaligned */ - glue(stq, MEMSUFFIX)(T0 + T1, DT0); + glue(stq, MEMSUFFIX)(T0 & ~0x7, DT0); RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index 075be1ed0..03f802a27 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -711,10 +711,6 @@ OP_LD_TABLE(wc1); OP_ST_TABLE(wc1); OP_LD_TABLE(dc1); OP_ST_TABLE(dc1); -OP_LD_TABLE(wxc1); -OP_ST_TABLE(wxc1); -OP_LD_TABLE(dxc1); -OP_ST_TABLE(dxc1); OP_LD_TABLE(uxc1); OP_ST_TABLE(uxc1); @@ -1092,7 +1088,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, return; } GEN_STORE_TN_REG(rt, T0); - MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm); + MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); } /* Arithmetic */ @@ -5242,25 +5238,36 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, /* Coprocessor 3 (FPU) */ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, - int base, int index) + int fs, int base, int index) { const char *opn = "extended float load/store"; + int store = 0; /* All of those work only on 64bit FPUs. */ gen_op_cp1_64bitmode(); - GEN_LOAD_REG_TN(T0, base); - GEN_LOAD_REG_TN(T1, index); + if (base == 0) { + if (index == 0) + gen_op_reset_T0(); + else + GEN_LOAD_REG_TN(T0, index); + } else if (index == 0) { + GEN_LOAD_REG_TN(T0, base); + } else { + GEN_LOAD_REG_TN(T0, base); + GEN_LOAD_REG_TN(T1, index); + gen_op_addr_add(); + } /* Don't do NOP if destination is zero: we must perform the actual * memory access */ switch (opc) { case OPC_LWXC1: - op_ldst(lwxc1); + op_ldst(lwc1); GEN_STORE_FTN_FREG(fd, WT0); opn = "lwxc1"; break; case OPC_LDXC1: - op_ldst(ldxc1); + op_ldst(ldc1); GEN_STORE_FTN_FREG(fd, DT0); opn = "ldxc1"; break; @@ -5270,26 +5277,30 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, opn = "luxc1"; break; case OPC_SWXC1: - GEN_LOAD_FREG_FTN(WT0, fd); - op_ldst(swxc1); + GEN_LOAD_FREG_FTN(WT0, fs); + op_ldst(swc1); opn = "swxc1"; + store = 1; break; case OPC_SDXC1: - GEN_LOAD_FREG_FTN(DT0, fd); - op_ldst(sdxc1); + GEN_LOAD_FREG_FTN(DT0, fs); + op_ldst(sdc1); opn = "sdxc1"; + store = 1; break; case OPC_SUXC1: - GEN_LOAD_FREG_FTN(DT0, fd); + GEN_LOAD_FREG_FTN(DT0, fs); op_ldst(suxc1); opn = "suxc1"; + store = 1; break; default: MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); return; } - MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[fd],regnames[index], regnames[base]); + MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd], + regnames[index], regnames[base]); } static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, @@ -5882,7 +5893,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_SWXC1: case OPC_SDXC1: case OPC_SUXC1: - gen_flt3_ldst(ctx, op1, sa, rs, rt); + gen_flt3_ldst(ctx, op1, sa, rd, rs, rt); break; case OPC_PREFX: /* treat as noop */ -- cgit v1.2.3 From d640d6d4c2c8fc545c149c3e78fa35be86e7ee32 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 20 May 2007 10:53:26 +0000 Subject: Delete one more leftover file. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2838 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/linux_boot.bin | Bin 512 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 pc-bios/linux_boot.bin diff --git a/pc-bios/linux_boot.bin b/pc-bios/linux_boot.bin deleted file mode 100644 index 80f7b5fee..000000000 Binary files a/pc-bios/linux_boot.bin and /dev/null differ -- cgit v1.2.3 From 860c6c526f3f122e399a5a7e8a20ca2a8ef0af70 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 20 May 2007 10:54:50 +0000 Subject: Delete linux_boot.bin from the install target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2839 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 65ad05616..73d4cf382 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ install: all $(if $(BUILD_DOCS),install-doc) $(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 \ + video.x openbios-sparc32 pxe-ne2k_pci.bin \ pxe-rtl8139.bin pxe-pcnet.bin; do \ $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ done @@ -161,7 +161,6 @@ tarbin: $(datadir)/ppc_rom.bin \ $(datadir)/video.x \ $(datadir)/openbios-sparc32 \ - $(datadir)/linux_boot.bin \ $(datadir)/pxe-ne2k_pci.bin \ $(datadir)/pxe-rtl8139.bin \ $(datadir)/pxe-pcnet.bin \ -- cgit v1.2.3 From 5f30d62c261e0808e3135a3c75beb761f4d2a1c9 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 20 May 2007 10:59:07 +0000 Subject: Delete now unused define. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2840 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index 89e93e83f..a311c4206 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -29,7 +29,6 @@ #define BIOS_FILENAME "bios.bin" #define VGABIOS_FILENAME "vgabios.bin" #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin" -#define LINUX_BOOT_FILENAME "linux_boot.bin" /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ #define ACPI_DATA_SIZE 0x10000 -- cgit v1.2.3 From 3a5b360dac4ce1900e1cb19b7ad870086936869c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 20 May 2007 13:27:58 +0000 Subject: Catch more MIPS FPU cornercases, fix addr.ps and mulr.ps instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2841 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 25 +++++++++++++++++++++++-- target-mips/translate.c | 16 ++++++++-------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9a0ffee9a..9092ffc39 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -975,13 +975,25 @@ FLOAT_OP(name, d) \ { \ set_float_exception_flags(0, &env->fp_status); \ FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ - update_fcr31(); \ + update_fcr31(); \ + if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) \ + FDT2 = 0x7ff7ffffffffffffULL; \ + else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ + if ((env->fcr31 & 0x3) == 0) \ + FDT2 &= 0x8000000000000000ULL; \ + } \ } \ FLOAT_OP(name, s) \ { \ set_float_exception_flags(0, &env->fp_status); \ FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - update_fcr31(); \ + update_fcr31(); \ + if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) \ + FST2 = 0x7fbfffff; \ + else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ + if ((env->fcr31 & 0x3) == 0) \ + FST2 &= 0x80000000ULL; \ + } \ } \ FLOAT_OP(name, ps) \ { \ @@ -989,6 +1001,15 @@ FLOAT_OP(name, ps) \ FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ update_fcr31(); \ + if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) { \ + FST2 = 0x7fbfffff; \ + FSTH2 = 0x7fbfffff; \ + } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ + if ((env->fcr31 & 0x3) == 0) { \ + FST2 &= 0x80000000ULL; \ + FSTH2 &= 0x80000000ULL; \ + } \ + } \ } FLOAT_BINOP(add) FLOAT_BINOP(sub) diff --git a/target-mips/translate.c b/target-mips/translate.c index 03f802a27..5b497d0fd 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5074,10 +5074,10 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, break; case FOP(24, 22): gen_op_cp1_64bitmode(); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); + GEN_LOAD_FREG_FTN(WT0, ft); + GEN_LOAD_FREG_FTN(WTH0, ft); + GEN_LOAD_FREG_FTN(WT1, fs); + GEN_LOAD_FREG_FTN(WTH1, fs); gen_op_float_addr_ps(); GEN_STORE_FTN_FREG(fd, WT2); GEN_STORE_FTN_FREG(fd, WTH2); @@ -5085,10 +5085,10 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, break; case FOP(26, 22): gen_op_cp1_64bitmode(); - GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT1, ft); - GEN_LOAD_FREG_FTN(WTH1, ft); + GEN_LOAD_FREG_FTN(WT0, ft); + GEN_LOAD_FREG_FTN(WTH0, ft); + GEN_LOAD_FREG_FTN(WT1, fs); + GEN_LOAD_FREG_FTN(WTH1, fs); gen_op_float_mulr_ps(); GEN_STORE_FTN_FREG(fd, WT2); GEN_STORE_FTN_FREG(fd, WTH2); -- cgit v1.2.3 From 8d7fe05385e2e0ac1243ac437d3f400b2c5cb919 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 20 May 2007 22:20:28 +0000 Subject: M68k addx/subx fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2842 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/op.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-m68k/op.c b/target-m68k/op.c index 8ea7589c3..34878c021 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -170,7 +170,7 @@ OP(btest) FORCE_RET(); } -OP(addx_cc) +OP(subx_cc) { uint32_t op1 = get_op(PARAM1); uint32_t op2 = get_op(PARAM2); @@ -188,7 +188,7 @@ OP(addx_cc) FORCE_RET(); } -OP(subx_cc) +OP(addx_cc) { uint32_t op1 = get_op(PARAM1); uint32_t op2 = get_op(PARAM2); -- cgit v1.2.3 From 1b1afeb95b1e31ca32b48b07ff862a7b885b3896 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 21 May 2007 17:48:01 +0000 Subject: Don't touch carry flag in ASR with zero , submitted by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2843 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/op.c b/target-arm/op.c index fd44a40f8..d7ac6de06 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -667,7 +667,7 @@ void OPPROTO op_sarl_T1_T0_cc(void) if (shift >= 32) { env->CF = (T1 >> 31) & 1; T1 = (int32_t)T1 >> 31; - } else { + } else if (shift != 0) { env->CF = (T1 >> (shift - 1)) & 1; T1 = (int32_t)T1 >> shift; } -- cgit v1.2.3 From c6fdf5fca0149fbc2d05d8d5ad43e3686c37514e Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 21 May 2007 18:08:36 +0000 Subject: Fix interrupt controller address masking git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2844 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 94a6c965c..2d1f6552e 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -58,7 +58,8 @@ typedef struct SLAVIO_INTCTLState { } SLAVIO_INTCTLState; #define INTCTL_MAXADDR 0xf -#define INTCTLM_MAXADDR 0xf +#define INTCTLM_MAXADDR 0x13 +#define INTCTLM_MASK 0x1f static void slavio_check_interrupts(void *opaque); // per-cpu interrupt controller @@ -143,7 +144,7 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin SLAVIO_INTCTLState *s = opaque; uint32_t saddr; - saddr = (addr & INTCTLM_MAXADDR) >> 2; + saddr = (addr & INTCTLM_MASK) >> 2; switch (saddr) { case 2: // clear (enable) // Force clear unused bits -- cgit v1.2.3 From 0ff596d02fd9d876a31d038255a6d4f89da9dfed Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 23 May 2007 00:03:59 +0000 Subject: I2C/SMBus framework. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2845 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 + hw/acpi.c | 57 ++++------ hw/i2c.c | 117 +++++++++++++++++++++ hw/i2c.h | 49 +++++++++ hw/pc.c | 9 +- hw/smbus.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/smbus.h | 46 +++++++-- hw/smbus_eeprom.c | 46 ++++++--- vl.h | 7 +- 9 files changed, 566 insertions(+), 70 deletions(-) create mode 100644 hw/i2c.c create mode 100644 hw/i2c.h create mode 100644 hw/smbus.c diff --git a/Makefile.target b/Makefile.target index 1e573f44b..dc30d4722 100644 --- a/Makefile.target +++ b/Makefile.target @@ -402,6 +402,8 @@ SOUND_HW += fmopl.o adlib.o endif AUDIODRV+= wavcapture.o +VL_OBJS += i2c.o smbus.o + # SCSI layer VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o diff --git a/hw/acpi.c b/hw/acpi.c index 5310570ec..de4002e92 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -35,7 +35,7 @@ typedef struct PIIX4PMState { uint8_t apms; QEMUTimer *tmr_timer; int64_t tmr_overflow_time; - SMBusDevice *smb_dev[128]; + i2c_bus *smbus; uint8_t smb_stat; uint8_t smb_ctl; uint8_t smb_cmd; @@ -63,9 +63,6 @@ typedef struct PIIX4PMState { #define SMBHSTDAT1 0x06 #define SMBBLKDAT 0x07 -/* Note: only used for piix4_smbus_register_device */ -static PIIX4PMState *piix4_pm_state; - static uint32_t get_pmtmr(PIIX4PMState *s) { uint32_t d; @@ -258,59 +255,44 @@ static void smb_transaction(PIIX4PMState *s) uint8_t read = s->smb_addr & 0x01; uint8_t cmd = s->smb_cmd; uint8_t addr = s->smb_addr >> 1; - SMBusDevice *dev = s->smb_dev[addr]; + i2c_bus *bus = s->smbus; #ifdef DEBUG printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); #endif - if (!dev) goto error; - switch(prot) { case 0x0: - if (!dev->quick_cmd) goto error; - (*dev->quick_cmd)(dev, read); + smbus_quick_command(bus, addr, read); break; case 0x1: if (read) { - if (!dev->receive_byte) goto error; - s->smb_data0 = (*dev->receive_byte)(dev); - } - else { - if (!dev->send_byte) goto error; - (*dev->send_byte)(dev, cmd); + s->smb_data0 = smbus_receive_byte(bus, addr); + } else { + smbus_send_byte(bus, addr, cmd); } break; case 0x2: if (read) { - if (!dev->read_byte) goto error; - s->smb_data0 = (*dev->read_byte)(dev, cmd); - } - else { - if (!dev->write_byte) goto error; - (*dev->write_byte)(dev, cmd, s->smb_data0); + s->smb_data0 = smbus_read_byte(bus, addr, cmd); + } else { + smbus_write_byte(bus, addr, cmd, s->smb_data0); } break; case 0x3: if (read) { uint16_t val; - if (!dev->read_word) goto error; - val = (*dev->read_word)(dev, cmd); + val = smbus_read_word(bus, addr, cmd); s->smb_data0 = val; s->smb_data1 = val >> 8; - } - else { - if (!dev->write_word) goto error; - (*dev->write_word)(dev, cmd, (s->smb_data1 << 8) | s->smb_data0); + } else { + smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); } break; case 0x5: if (read) { - if (!dev->read_block) goto error; - s->smb_data0 = (*dev->read_block)(dev, cmd, s->smb_data); - } - else { - if (!dev->write_block) goto error; - (*dev->write_block)(dev, cmd, s->smb_data0, s->smb_data); + s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data); + } else { + smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); } break; default: @@ -469,7 +451,7 @@ static int pm_load(QEMUFile* f,void* opaque,int version_id) return 0; } -void piix4_pm_init(PCIBus *bus, int devfn) +i2c_bus *piix4_pm_init(PCIBus *bus, int devfn) { PIIX4PMState *s; uint8_t *pci_conf; @@ -514,10 +496,7 @@ void piix4_pm_init(PCIBus *bus, int devfn) s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s); - piix4_pm_state = s; -} -void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr) -{ - piix4_pm_state->smb_dev[addr] = dev; + s->smbus = i2c_init_bus(); + return s->smbus; } diff --git a/hw/i2c.c b/hw/i2c.c new file mode 100644 index 000000000..5d9319da4 --- /dev/null +++ b/hw/i2c.c @@ -0,0 +1,117 @@ +/* + * QEMU I2C bus interface. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +#include "vl.h" + +struct i2c_bus +{ + i2c_slave *current_dev; + i2c_slave *dev; +}; + +/* Create a new I2C bus. */ +i2c_bus *i2c_init_bus(void) +{ + i2c_bus *bus; + + bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus)); + return bus; +} + +/* Create a new slave device. */ +i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size) +{ + i2c_slave *dev; + + if (size < sizeof(i2c_slave)) + cpu_abort(cpu_single_env, "I2C struct too small"); + + dev = (i2c_slave *)qemu_mallocz(size); + dev->address = address; + dev->next = bus->dev; + bus->dev = dev; + + return dev; +} + +void i2c_set_slave_address(i2c_slave *dev, int address) +{ + dev->address = address; +} + +/* Return nonzero if bus is busy. */ +int i2c_bus_busy(i2c_bus *bus) +{ + return bus->current_dev != NULL; +} + +/* Returns nonzero if the bus is already busy, or is the address is not + valid. */ +/* TODO: Make this handle multiple masters. */ +int i2c_start_transfer(i2c_bus *bus, int address, int recv) +{ + i2c_slave *dev; + + for (dev = bus->dev; dev; dev = dev->next) { + if (dev->address == address) + break; + } + + if (!dev) + return 1; + + /* If the bus is already busy, assume this is a repeated + start condition. */ + bus->current_dev = dev; + dev->event(dev, recv ? I2C_START_RECV : I2C_START_SEND); + return 0; +} + +void i2c_end_transfer(i2c_bus *bus) +{ + i2c_slave *dev = bus->current_dev; + + if (!dev) + return; + + dev->event(dev, I2C_FINISH); + + bus->current_dev = NULL; +} + +int i2c_send(i2c_bus *bus, uint8_t data) +{ + i2c_slave *dev = bus->current_dev; + + if (!dev) + return -1; + + return dev->send(dev, data); +} + +int i2c_recv(i2c_bus *bus) +{ + i2c_slave *dev = bus->current_dev; + + if (!dev) + return -1; + + return dev->recv(dev); +} + +void i2c_nack(i2c_bus *bus) +{ + i2c_slave *dev = bus->current_dev; + + if (!dev) + return; + + dev->event(dev, I2C_NACK); +} + diff --git a/hw/i2c.h b/hw/i2c.h new file mode 100644 index 000000000..a3c4de3ca --- /dev/null +++ b/hw/i2c.h @@ -0,0 +1,49 @@ +#ifndef QEMU_I2C_H +#define QEMU_I2C_H + +/* The QEMU I2C implementation only supports simple transfers that complete + immediately. It does not support slave devices that need to be able to + defer their response (eg. CPU slave interfaces where the data is supplied + by the device driver in response to an interrupt). */ + +enum i2c_event { + I2C_START_RECV, + I2C_START_SEND, + I2C_FINISH, + I2C_NACK /* Masker NACKed a recieve byte. */ +}; + +typedef struct i2c_slave i2c_slave; + +/* Master to slave. */ +typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data); +/* Slave to master. */ +typedef int (*i2c_recv_cb)(i2c_slave *s); +/* Notify the slave of a bus state change. */ +typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event); + +struct i2c_slave +{ + /* Callbacks to be set by the device. */ + i2c_event_cb event; + i2c_recv_cb recv; + i2c_send_cb send; + + /* Remaining fields for internal use by the I2C code. */ + int address; + void *next; +}; + +typedef struct i2c_bus i2c_bus; + +i2c_bus *i2c_init_bus(void); +i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size); +void i2c_set_slave_address(i2c_slave *dev, int address); +int i2c_bus_busy(i2c_bus *bus); +int i2c_start_transfer(i2c_bus *bus, int address, int recv); +void i2c_end_transfer(i2c_bus *bus); +void i2c_nack(i2c_bus *bus); +int i2c_send(i2c_bus *bus, uint8_t data); +int i2c_recv(i2c_bus *bus); + +#endif diff --git a/hw/pc.c b/hw/pc.c index a311c4206..a698ba546 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -897,11 +897,12 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled && acpi_enabled) { uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ - piix4_pm_init(pci_bus, piix3_devfn + 3); + i2c_bus *smbus; + + /* TODO: Populate SPD eeprom data. */ + smbus = piix4_pm_init(pci_bus, piix3_devfn + 3); for (i = 0; i < 8; i++) { - SMBusDevice *eeprom = smbus_eeprom_device_init(0x50 + i, - eeprom_buf + (i * 256)); - piix4_smbus_register_device(eeprom, 0x50 + i); + smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); } } diff --git a/hw/smbus.c b/hw/smbus.c new file mode 100644 index 000000000..651a7a0b9 --- /dev/null +++ b/hw/smbus.c @@ -0,0 +1,303 @@ +/* + * QEMU SMBus device emulation. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + */ + +/* TODO: Implement PEC. */ + +#include "vl.h" + +//#define DEBUG_SMBUS 1 + +#ifdef DEBUG_SMBUS +#define DPRINTF(fmt, args...) \ +do { printf("smbus(%02x): " fmt , dev->i2c.address, ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "smbus: error: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "smbus: error: " fmt , ##args);} while (0) +#endif + +enum { + SMBUS_IDLE, + SMBUS_WRITE_DATA, + SMBUS_RECV_BYTE, + SMBUS_READ_DATA, + SMBUS_DONE, + SMBUS_CONFUSED = -1 +}; + +static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) +{ + DPRINTF("Quick Command %d\n", recv); + if (dev->quick_cmd) + dev->quick_cmd(dev, recv); +} + +static void smbus_do_write(SMBusDevice *dev) +{ + if (dev->data_len == 0) { + smbus_do_quick_cmd(dev, 0); + } else if (dev->data_len == 1) { + DPRINTF("Send Byte\n"); + if (dev->send_byte) { + dev->send_byte(dev, dev->data_buf[0]); + } + } else { + dev->command = dev->data_buf[0]; + DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1); + if (dev->write_data) { + dev->write_data(dev, dev->command, dev->data_buf + 1, + dev->data_len - 1); + } + } +} + +void smbus_i2c_event(i2c_slave *s, enum i2c_event event) +{ + SMBusDevice *dev = (SMBusDevice *)s; + switch (event) { + case I2C_START_SEND: + switch (dev->mode) { + case SMBUS_IDLE: + DPRINTF("Incoming data\n"); + dev->mode = SMBUS_WRITE_DATA; + break; + default: + BADF("Unexpected send start condition in state %d\n", dev->mode); + dev->mode = SMBUS_CONFUSED; + break; + } + break; + + case I2C_START_RECV: + switch (dev->mode) { + case SMBUS_IDLE: + DPRINTF("Read mode\n"); + dev->mode = SMBUS_RECV_BYTE; + break; + case SMBUS_WRITE_DATA: + if (dev->data_len == 0) { + BADF("Read after write with no data\n"); + dev->mode = SMBUS_CONFUSED; + } else { + if (dev->data_len > 1) { + smbus_do_write(dev); + } else { + dev->command = dev->data_buf[0]; + DPRINTF("%02x: Command %d\n", dev->i2c.address, + dev->command); + } + DPRINTF("Read mode\n"); + dev->data_len = 0; + dev->mode = SMBUS_READ_DATA; + } + break; + default: + BADF("Unexpected recv start condition in state %d\n", dev->mode); + dev->mode = SMBUS_CONFUSED; + break; + } + break; + + case I2C_FINISH: + switch (dev->mode) { + case SMBUS_WRITE_DATA: + smbus_do_write(dev); + break; + case SMBUS_RECV_BYTE: + smbus_do_quick_cmd(dev, 1); + break; + case SMBUS_READ_DATA: + BADF("Unexpected stop during receive\n"); + break; + default: + /* Nothing to do. */ + break; + } + dev->mode = SMBUS_IDLE; + dev->data_len = 0; + break; + + case I2C_NACK: + switch (dev->mode) { + case SMBUS_DONE: + /* Nothing to do. */ + break; + case SMBUS_READ_DATA: + dev->mode = SMBUS_DONE; + break; + default: + BADF("Unexpected NACK in state %d\n", dev->mode); + dev->mode = SMBUS_CONFUSED; + break; + } + } +} + +static int smbus_i2c_recv(i2c_slave *s) +{ + SMBusDevice *dev = (SMBusDevice *)s; + int ret; + + switch (dev->mode) { + case SMBUS_RECV_BYTE: + if (dev->receive_byte) { + ret = dev->receive_byte(dev); + } else { + ret = 0; + } + DPRINTF("Receive Byte %02x\n", ret); + dev->mode = SMBUS_DONE; + break; + case SMBUS_READ_DATA: + if (dev->read_data) { + ret = dev->read_data(dev, dev->command, dev->data_len); + dev->data_len++; + } else { + ret = 0; + } + DPRINTF("Read data %02x\n", ret); + break; + default: + BADF("Unexpected read in state %d\n", dev->mode); + dev->mode = SMBUS_CONFUSED; + ret = 0; + break; + } + return ret; +} + +static int smbus_i2c_send(i2c_slave *s, uint8_t data) +{ + SMBusDevice *dev = (SMBusDevice *)s; + switch (dev->mode) { + case SMBUS_WRITE_DATA: + DPRINTF("Write data %02x\n", data); + dev->data_buf[dev->data_len++] = data; + break; + default: + BADF("Unexpected write in state %d\n", dev->mode); + break; + } + return 0; +} + +SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size) +{ + SMBusDevice *dev; + + dev = (SMBusDevice *)i2c_slave_init(bus, address, size); + dev->i2c.event = smbus_i2c_event; + dev->i2c.recv = smbus_i2c_recv; + dev->i2c.send = smbus_i2c_send; + + return dev; +} + +/* Master device commands. */ +void smbus_quick_command(i2c_bus *bus, int addr, int read) +{ + i2c_start_transfer(bus, addr, read); + i2c_end_transfer(bus); +} + +uint8_t smbus_receive_byte(i2c_bus *bus, int addr) +{ + uint8_t data; + + i2c_start_transfer(bus, addr, 1); + data = i2c_recv(bus); + i2c_nack(bus); + i2c_end_transfer(bus); + return data; +} + +void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data) +{ + i2c_start_transfer(bus, addr, 0); + i2c_send(bus, data); + i2c_end_transfer(bus); +} + +uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command) +{ + uint8_t data; + i2c_start_transfer(bus, addr, 0); + i2c_send(bus, command); + i2c_start_transfer(bus, addr, 1); + data = i2c_recv(bus); + i2c_nack(bus); + i2c_end_transfer(bus); + return data; +} + +void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data) +{ + i2c_start_transfer(bus, addr, 0); + i2c_send(bus, command); + i2c_send(bus, data); + i2c_end_transfer(bus); +} + +uint16_t smbus_read_word(i2c_bus *bus, int addr, uint8_t command) +{ + uint16_t data; + i2c_start_transfer(bus, addr, 0); + i2c_send(bus, command); + i2c_start_transfer(bus, addr, 1); + data = i2c_recv(bus); + data |= i2c_recv(bus) << 8; + i2c_nack(bus); + i2c_end_transfer(bus); + return data; +} + +void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data) +{ + i2c_start_transfer(bus, addr, 0); + i2c_send(bus, command); + i2c_send(bus, data & 0xff); + i2c_send(bus, data >> 8); + i2c_end_transfer(bus); +} + +int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data) +{ + int len; + int i; + + i2c_start_transfer(bus, addr, 0); + i2c_send(bus, command); + i2c_start_transfer(bus, addr, 1); + len = i2c_recv(bus); + if (len > 32) + len = 0; + for (i = 0; i < len; i++) + data[i] = i2c_recv(bus); + i2c_nack(bus); + i2c_end_transfer(bus); + return len; +} + +void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data, + int len) +{ + int i; + + if (len > 32) + len = 32; + + i2c_start_transfer(bus, addr, 0); + i2c_send(bus, command); + i2c_send(bus, len); + for (i = 0; i < len; i++) + i2c_send(bus, data[i]); + i2c_end_transfer(bus); +} diff --git a/hw/smbus.h b/hw/smbus.h index 76fc3c839..9125896cc 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -25,14 +25,46 @@ typedef struct SMBusDevice SMBusDevice; struct SMBusDevice { - uint8_t addr; + /* The SMBus protocol is implemented on top of I2C. */ + i2c_slave i2c; + + /* Callbacks set by the device. */ void (*quick_cmd)(SMBusDevice *dev, uint8_t read); void (*send_byte)(SMBusDevice *dev, uint8_t val); uint8_t (*receive_byte)(SMBusDevice *dev); - void (*write_byte)(SMBusDevice *dev, uint8_t cmd, uint8_t val); - uint8_t (*read_byte)(SMBusDevice *dev, uint8_t cmd); - void (*write_word)(SMBusDevice *dev, uint8_t cmd, uint16_t val); - uint16_t (*read_word)(SMBusDevice *dev, uint8_t cmd); - void (*write_block)(SMBusDevice *dev, uint8_t cmd, uint8_t len, uint8_t *buf); - uint8_t (*read_block)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf); + /* We can't distinguish between a word write and a block write with + length 1, so pass the whole data block including the length byte + (if present). The device is responsible figuring out what type of + command this is. */ + void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len); + /* Likewise we can't distinguish between defferent reads, or even know + the length of the read until the read is complete, so read data a + byte at a time. The device is responsible for adding the length + byte on block reads. */ + uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n); + + /* Remaining fields for internal use only. */ + int mode; + int data_len; + uint8_t data_buf[34]; /* command + len + 32 bytes of data. */ + uint8_t command; }; + +/* Create a slave device. */ +SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size); + +/* Master device commands. */ +void smbus_quick_command(i2c_bus *bus, int addr, int read); +uint8_t smbus_receive_byte(i2c_bus *bus, int addr); +void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data); +uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command); +void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data); +uint16_t smbus_read_word(i2c_bus *bus, int addr, uint8_t command); +void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data); +int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data); +void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data, + int len); + +/* smbus_eeprom.c */ +void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf); + diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index d401b1756..699bd5417 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -58,37 +58,51 @@ static uint8_t eeprom_receive_byte(SMBusDevice *dev) return val; } -static void eeprom_write_byte(SMBusDevice *dev, uint8_t cmd, uint8_t val) +static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len) { SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; + int n; #ifdef DEBUG printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", dev->addr, - cmd, val); + cmd, buf[0]); #endif - eeprom->data[cmd] = val; + /* An page write operation is not a valid SMBus command. + It is a block write without a length byte. Fortunately we + get the full block anyway. */ + /* TODO: Should this set the current location? */ + if (cmd + len > 256) + n = 256 - cmd; + else + n = len; + memcpy(eeprom->data + cmd, buf, n); + len -= n; + if (len) + memcpy(eeprom->data, buf + n, len); } -static uint8_t eeprom_read_byte(SMBusDevice *dev, uint8_t cmd) +static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) { SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; - uint8_t val = eeprom->data[cmd]; -#ifdef DEBUG - printf("eeprom_read_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", dev->addr, - cmd, val); -#endif - return val; + /* If this is the first byte then set the current position. */ + if (n == 0) + eeprom->offset = cmd; + /* As with writes, we implement block reads without the + SMBus length byte. */ + return eeprom_receive_byte(dev); } -SMBusDevice *smbus_eeprom_device_init(uint8_t addr, uint8_t *buf) +void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf) { - SMBusEEPROMDevice *eeprom = qemu_mallocz(sizeof(SMBusEEPROMDevice)); - eeprom->dev.addr = addr; + SMBusEEPROMDevice *eeprom; + + eeprom = (SMBusEEPROMDevice *)smbus_device_init(bus, addr, + sizeof(SMBusEEPROMDevice)); + eeprom->dev.quick_cmd = eeprom_quick_cmd; eeprom->dev.send_byte = eeprom_send_byte; eeprom->dev.receive_byte = eeprom_receive_byte; - eeprom->dev.write_byte = eeprom_write_byte; - eeprom->dev.read_byte = eeprom_read_byte; + eeprom->dev.write_data = eeprom_write_data; + eeprom->dev.read_data = eeprom_read_data; eeprom->data = buf; eeprom->offset = 0; - return (SMBusDevice *) eeprom; } diff --git a/vl.h b/vl.h index 36ab2d2bb..b831d8d2d 100644 --- a/vl.h +++ b/vl.h @@ -1126,17 +1126,16 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); void pcspk_init(PITState *); int pcspk_audio_init(AudioState *, qemu_irq *pic); +#include "hw/i2c.h" + #include "hw/smbus.h" /* acpi.c */ extern int acpi_enabled; -void piix4_pm_init(PCIBus *bus, int devfn); +i2c_bus *piix4_pm_init(PCIBus *bus, int devfn); void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); void acpi_bios_init(void); -/* smbus_eeprom.c */ -SMBusDevice *smbus_eeprom_device_init(uint8_t addr, uint8_t *buf); - /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; -- cgit v1.2.3 From 423f0742a8483430fe031861c316b09f1967319d Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 23 May 2007 00:06:54 +0000 Subject: Add periodic timer implementation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2846 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_timer.c | 157 +++++++++++++++--------------------------------------- hw/ptimer.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 8 ++- 3 files changed, 213 insertions(+), 116 deletions(-) create mode 100644 hw/ptimer.c diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 3c6c0d239..f98de1ff6 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -22,114 +22,24 @@ #define TIMER_CTRL_ENABLE (1 << 7) typedef struct { - int64_t next_time; - int64_t expires; - int64_t loaded; - QEMUTimer *timer; + ptimer_state *timer; uint32_t control; - uint32_t count; uint32_t limit; - int raw_freq; int freq; int int_level; qemu_irq irq; } arm_timer_state; -/* Calculate the new expiry time of the given timer. */ - -static void arm_timer_reload(arm_timer_state *s) -{ - int64_t delay; - - s->loaded = s->expires; - delay = muldiv64(s->count, ticks_per_sec, s->freq); - if (delay == 0) - delay = 1; - s->expires += delay; -} - /* Check all active timers, and schedule the next timer interrupt. */ -static void arm_timer_update(arm_timer_state *s, int64_t now) +static void arm_timer_update(arm_timer_state *s) { - int64_t next; - - /* Ignore disabled timers. */ - if ((s->control & TIMER_CTRL_ENABLE) == 0) - return; - /* Ignore expired one-shot timers. */ - if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT)) - return; - if (s->expires - now <= 0) { - /* Timer has expired. */ - s->int_level = 1; - if (s->control & TIMER_CTRL_ONESHOT) { - /* One-shot. */ - s->count = 0; - } else { - if ((s->control & TIMER_CTRL_PERIODIC) == 0) { - /* Free running. */ - if (s->control & TIMER_CTRL_32BIT) - s->count = 0xffffffff; - else - s->count = 0xffff; - } else { - /* Periodic. */ - s->count = s->limit; - } - } - } - while (s->expires - now <= 0) { - arm_timer_reload(s); - } /* Update interrupts. */ if (s->int_level && (s->control & TIMER_CTRL_IE)) { qemu_irq_raise(s->irq); } else { qemu_irq_lower(s->irq); } - - next = now; - if (next - s->expires < 0) - next = s->expires; - - /* Schedule the next timer interrupt. */ - if (next == now) { - qemu_del_timer(s->timer); - s->next_time = 0; - } else if (next != s->next_time) { - qemu_mod_timer(s->timer, next); - s->next_time = next; - } -} - -/* Return the current value of the timer. */ -static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now) -{ - int64_t left; - int64_t period; - - if (s->count == 0) - return 0; - if ((s->control & TIMER_CTRL_ENABLE) == 0) - return s->count; - left = s->expires - now; - period = s->expires - s->loaded; - /* If the timer should have expired then return 0. This can happen - when the host timer signal doesnt occur immediately. It's better to - have a timer appear to sit at zero for a while than have it wrap - around before the guest interrupt is raised. */ - /* ??? Could we trigger the interrupt here? */ - if (left < 0) - return 0; - /* We need to calculate count * elapsed / period without overfowing. - Scale both elapsed and period so they fit in a 32-bit int. */ - while (period != (int32_t)period) { - period >>= 1; - left >>= 1; - } - return ((uint64_t)s->count * (uint64_t)(int32_t)left) - / (int32_t)period; } uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) @@ -141,7 +51,7 @@ uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) case 6: /* TimerBGLoad */ return s->limit; case 1: /* TimerValue */ - return arm_timer_getcount(s, qemu_get_clock(vm_clock)); + return ptimer_get_count(s->timer); case 2: /* TimerControl */ return s->control; case 4: /* TimerRIS */ @@ -151,24 +61,40 @@ uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) return 0; return s->int_level; default: - cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", + (int)offset); return 0; } } +/* Reset the timer limit after settings have changed. */ +static void arm_timer_recalibrate(arm_timer_state *s, int reload) +{ + uint32_t limit; + + if ((s->control & TIMER_CTRL_PERIODIC) == 0) { + /* Free running. */ + if (s->control & TIMER_CTRL_32BIT) + limit = 0xffffffff; + else + limit = 0xffff; + } else { + /* Periodic. */ + limit = s->limit; + } + ptimer_set_limit(s->timer, limit, reload); +} + static void arm_timer_write(void *opaque, target_phys_addr_t offset, uint32_t value) { arm_timer_state *s = (arm_timer_state *)opaque; - int64_t now; + int freq; - now = qemu_get_clock(vm_clock); switch (offset >> 2) { case 0: /* TimerLoad */ s->limit = value; - s->count = value; - s->expires = now; - arm_timer_reload(s); + arm_timer_recalibrate(s, 1); break; case 1: /* TimerValue */ /* ??? Linux seems to want to write to this readonly register. @@ -179,19 +105,20 @@ static void arm_timer_write(void *opaque, target_phys_addr_t offset, /* Pause the timer if it is running. This may cause some inaccuracy dure to rounding, but avoids a whole lot of other messyness. */ - s->count = arm_timer_getcount(s, now); + ptimer_stop(s->timer); } s->control = value; - s->freq = s->raw_freq; + freq = s->freq; /* ??? Need to recalculate expiry time after changing divisor. */ switch ((value >> 2) & 3) { - case 1: s->freq >>= 4; break; - case 2: s->freq >>= 8; break; + case 1: freq >>= 4; break; + case 2: freq >>= 8; break; } + arm_timer_recalibrate(s, 0); + ptimer_set_freq(s->timer, freq); if (s->control & TIMER_CTRL_ENABLE) { /* Restart the timer if still enabled. */ - s->expires = now; - arm_timer_reload(s); + ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0); } break; case 3: /* TimerIntClr */ @@ -199,32 +126,34 @@ static void arm_timer_write(void *opaque, target_phys_addr_t offset, break; case 6: /* TimerBGLoad */ s->limit = value; + arm_timer_recalibrate(s, 0); break; default: - cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", + (int)offset); } - arm_timer_update(s, now); + arm_timer_update(s); } static void arm_timer_tick(void *opaque) { - int64_t now; - - now = qemu_get_clock(vm_clock); - arm_timer_update((arm_timer_state *)opaque, now); + arm_timer_state *s = (arm_timer_state *)opaque; + s->int_level = 1; + arm_timer_update(s); } static void *arm_timer_init(uint32_t freq, qemu_irq irq) { arm_timer_state *s; + QEMUBH *bh; s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state)); s->irq = irq; - s->raw_freq = s->freq = 1000000; + s->freq = freq; s->control = TIMER_CTRL_IE; - s->count = 0xffffffff; - s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s); + bh = qemu_bh_new(arm_timer_tick, s); + s->timer = ptimer_init(bh); /* ??? Save/restore. */ return s; } diff --git a/hw/ptimer.c b/hw/ptimer.c new file mode 100644 index 000000000..2f350fc09 --- /dev/null +++ b/hw/ptimer.c @@ -0,0 +1,164 @@ +/* + * General purpose implementation of a simple periodic countdown timer. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GNU LGPL. + */ +#include "vl.h" + + +struct ptimer_state +{ + int enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */ + uint32_t limit; + uint32_t delta; + uint32_t period_frac; + int64_t period; + int64_t last_event; + int64_t next_event; + QEMUBH *bh; + QEMUTimer *timer; +}; + +/* Use a bottom-half routine to avoid reentrancy issues. */ +static void ptimer_trigger(ptimer_state *s) +{ + if (s->bh) { + qemu_bh_schedule(s->bh); + } +} + +static void ptimer_reload(ptimer_state *s) +{ + if (s->delta == 0) { + ptimer_trigger(s); + s->delta = s->limit; + } + if (s->delta == 0 || s->period == 0) { + fprintf(stderr, "Timer with period zero, disabling\n"); + s->enabled = 0; + return; + } + + s->last_event = s->next_event; + s->next_event = s->last_event + s->delta * s->period; + if (s->period_frac) { + s->next_event += ((int64_t)s->period_frac * s->delta) >> 32; + } + qemu_mod_timer(s->timer, s->next_event); +} + +static void ptimer_tick(void *opaque) +{ + ptimer_state *s = (ptimer_state *)opaque; + ptimer_trigger(s); + s->delta = 0; + if (s->enabled == 2) { + s->enabled = 0; + } else { + ptimer_reload(s); + } +} + +uint32_t ptimer_get_count(ptimer_state *s) +{ + int64_t now; + uint32_t counter; + + if (s->enabled) { + now = qemu_get_clock(vm_clock); + /* Figure out the current counter value. */ + if (now - s->next_event > 0 + || s->period == 0) { + /* Prevent timer underflowing if it should already have + triggered. */ + counter = 0; + } else { + int64_t rem; + int64_t div; + + rem = s->next_event - now; + div = s->period; + counter = rem / div; + } + } else { + counter = s->delta; + } + return counter; +} + +void ptimer_set_count(ptimer_state *s, uint32_t count) +{ + s->delta = count; + if (s->enabled) { + s->next_event = qemu_get_clock(vm_clock); + ptimer_reload(s); + } +} + +void ptimer_run(ptimer_state *s, int oneshot) +{ + if (s->period == 0) { + fprintf(stderr, "Timer with period zero, disabling\n"); + return; + } + s->enabled = oneshot ? 2 : 1; + s->next_event = qemu_get_clock(vm_clock); + ptimer_reload(s); +} + +/* Pause a timer. Note that this may cause it to "loose" time, even if it + is immediately restarted. */ +void ptimer_stop(ptimer_state *s) +{ + if (!s->enabled) + return; + + s->delta = ptimer_get_count(s); + qemu_del_timer(s->timer); + s->enabled = 0; +} + +/* Set counter increment interval in nanoseconds. */ +void ptimer_set_period(ptimer_state *s, int64_t period) +{ + if (s->enabled) { + fprintf(stderr, "FIXME: ptimer_set_period with running timer"); + } + s->period = period; + s->period_frac = 0; +} + +/* Set counter frequency in Hz. */ +void ptimer_set_freq(ptimer_state *s, uint32_t freq) +{ + if (s->enabled) { + fprintf(stderr, "FIXME: ptimer_set_freq with running timer"); + } + s->period = 1000000000ll / freq; + s->period_frac = (1000000000ll << 32) / freq; +} + +/* Set the initial countdown value. If reload is nonzero then also set + count = limit. */ +void ptimer_set_limit(ptimer_state *s, uint32_t limit, int reload) +{ + if (s->enabled) { + fprintf(stderr, "FIXME: ptimer_set_limit with running timer"); + } + s->limit = limit; + if (reload) + s->delta = limit; +} + +ptimer_state *ptimer_init(QEMUBH *bh) +{ + ptimer_state *s; + + s = (ptimer_state *)qemu_mallocz(sizeof(ptimer_state)); + s->bh = bh; + s->timer = qemu_new_timer(vm_clock, ptimer_tick, s); + return s; +} + diff --git a/vl.c b/vl.c index 7dcfb5831..02c3c9cf7 100644 --- a/vl.c +++ b/vl.c @@ -6322,7 +6322,6 @@ void main_loop_wait(int timeout) } #endif qemu_aio_poll(); - qemu_bh_poll(); if (vm_running) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], @@ -6330,10 +6329,15 @@ void main_loop_wait(int timeout) /* run dma transfers, if any */ DMA_run(); } - + /* real time timers */ qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock)); + + /* Check bottom-halves last in case any of the earlier events triggered + them. */ + qemu_bh_poll(); + } static CPUState *cur_cpu; -- cgit v1.2.3 From 6963d7af10c657d2b654dc85fca6a3104d32d8a9 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 23 May 2007 01:13:57 +0000 Subject: Add ptimer.c function declarations and makefile rule. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2847 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- vl.h | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index dc30d4722..e5b3ecc05 100644 --- a/Makefile.target +++ b/Makefile.target @@ -455,7 +455,7 @@ 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 pl181.o pl190.o -VL_OBJS+= versatile_pci.o sd.o +VL_OBJS+= versatile_pci.o sd.o ptimer.o VL_OBJS+= arm_gic.o realview.o arm_sysctl.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o diff --git a/vl.h b/vl.h index b831d8d2d..88ebdbccf 100644 --- a/vl.h +++ b/vl.h @@ -1582,6 +1582,19 @@ struct pcmcia_card_s { /* dscm1xxxx.c */ struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv); +/* ptimer.c */ +typedef struct ptimer_state ptimer_state; +typedef void (*ptimer_cb)(void *opaque); + +ptimer_state *ptimer_init(QEMUBH *bh); +void ptimer_set_period(ptimer_state *s, int64_t period); +void ptimer_set_freq(ptimer_state *s, uint32_t freq); +void ptimer_set_limit(ptimer_state *s, uint32_t limit, int reload); +uint32_t ptimer_get_count(ptimer_state *s); +void ptimer_set_count(ptimer_state *s, uint32_t count); +void ptimer_run(ptimer_state *s, int oneshot); +void ptimer_stop(ptimer_state *s); + #include "hw/pxa.h" #include "gdbstub.h" -- cgit v1.2.3 From df1561e22df42643d769aacdcc7d6d239f243366 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 23 May 2007 08:18:27 +0000 Subject: The previous patch to make breakpoints work was a performance disaster, use a similiar hack as ARM does instead. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2848 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 10 ---------- target-mips/translate.c | 29 +++++++---------------------- 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 9ba0050ce..8f5b11c75 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1002,16 +1002,6 @@ void op_jnz_T2 (void) RETURN(); } -void op_flush_icache_range(void) { - CALL_FROM_TB2(tlb_flush_page, env, T0 + T1); - RETURN(); -} - -void op_flush_icache_all(void) { - CALL_FROM_TB1(tb_flush, env); - RETURN(); -} - /* CP0 functions */ void op_mfc0_index (void) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 5b497d0fd..ddf560d7c 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4236,7 +4236,6 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; case OPC_ERET: opn = "eret"; - save_cpu_state(ctx, 0); gen_op_eret(); ctx->bstate = BS_EXCP; break; @@ -4246,7 +4245,6 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); } else { - save_cpu_state(ctx, 0); gen_op_deret(); ctx->bstate = BS_EXCP; } @@ -5526,6 +5524,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_SYSCALL); break; case OPC_BREAK: + /* XXX: Hack to work around wrong handling of self-modifying code. */ + ctx->pc += 4; + save_cpu_state(ctx, 1); + ctx->pc -= 4; generate_exception(ctx, EXCP_BREAK); break; case OPC_SPIM: @@ -5791,25 +5793,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_ldst(ctx, op, rt, rs, imm); break; case OPC_CACHE: - /* FIXME: This works around self-modifying code, but only - if the guest OS handles it properly, and if there's no - such code executed in uncached space. */ - if (!(rt & 0x3)) - switch ((rt >> 2) & 0x7) { - case 4: - GEN_LOAD_REG_TN(T0, rs); - GEN_LOAD_IMM_TN(T1, imm); - gen_op_flush_icache_range(); - break; - case 2: - case 1: - case 0: - /* Can be very inefficient. */ - gen_op_flush_icache_all(); - break; - default: - break; - } + /* Treat as a noop */ break; case OPC_PREF: /* Treat as a noop */ @@ -6079,7 +6063,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, switch (ctx.bstate) { case BS_STOP: gen_op_interrupt_restart(); - /* Fall through. */ + gen_goto_tb(&ctx, 0, ctx.pc); + break; case BS_NONE: save_cpu_state(ctxp, 0); gen_goto_tb(&ctx, 0, ctx.pc); -- cgit v1.2.3 From fd88b6abab9a4425505b292b5fedbad31d0dfe4f Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 23 May 2007 08:24:25 +0000 Subject: The 24k wants more watch and srsmap registers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2849 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 4 +- target-mips/helper.c | 2 +- target-mips/op.c | 22 ++-- target-mips/translate.c | 278 ++++++------------------------------------------ 4 files changed, 45 insertions(+), 261 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index e0f03eda7..9cddc174d 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -216,8 +216,8 @@ struct CPUMIPSState { int32_t CP0_Config6; int32_t CP0_Config7; target_ulong CP0_LLAddr; - target_ulong CP0_WatchLo; - int32_t CP0_WatchHi; + target_ulong CP0_WatchLo[8]; + int32_t CP0_WatchHi[8]; target_ulong CP0_XContext; int32_t CP0_Framemask; int32_t CP0_Debug; diff --git a/target-mips/helper.c b/target-mips/helper.c index 306ddf0b6..2dfaffc23 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -381,7 +381,7 @@ void do_interrupt (CPUState *env) break; case EXCP_SRESET: env->CP0_Status |= (1 << CP0St_SR); - env->CP0_WatchLo = 0; + memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo)); goto set_error_EPC; case EXCP_NMI: env->CP0_Status |= (1 << CP0St_NMI); diff --git a/target-mips/op.c b/target-mips/op.c index 8f5b11c75..8f67041ca 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1171,15 +1171,15 @@ void op_mfc0_lladdr (void) RETURN(); } -void op_mfc0_watchlo0 (void) +void op_mfc0_watchlo (void) { - T0 = (int32_t)env->CP0_WatchLo; + T0 = (int32_t)env->CP0_WatchLo[PARAM1]; RETURN(); } -void op_mfc0_watchhi0 (void) +void op_mfc0_watchhi (void) { - T0 = env->CP0_WatchHi; + T0 = env->CP0_WatchHi[PARAM1]; RETURN(); } @@ -1423,18 +1423,18 @@ void op_mtc0_config2 (void) RETURN(); } -void op_mtc0_watchlo0 (void) +void op_mtc0_watchlo (void) { /* Watch exceptions for instructions, data loads, data stores not implemented. */ - env->CP0_WatchLo = (T0 & ~0x7); + env->CP0_WatchLo[PARAM1] = (T0 & ~0x7); RETURN(); } -void op_mtc0_watchhi0 (void) +void op_mtc0_watchhi (void) { - env->CP0_WatchHi = (T0 & 0x40FF0FF8); - env->CP0_WatchHi &= ~(env->CP0_WatchHi & T0 & 0x7); + env->CP0_WatchHi[PARAM1] = (T0 & 0x40FF0FF8); + env->CP0_WatchHi[PARAM1] &= ~(env->CP0_WatchHi[PARAM1] & T0 & 0x7); RETURN(); } @@ -1551,9 +1551,9 @@ void op_dmfc0_lladdr (void) RETURN(); } -void op_dmfc0_watchlo0 (void) +void op_dmfc0_watchlo (void) { - T0 = env->CP0_WatchLo; + T0 = env->CP0_WatchLo[PARAM1]; RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index ddf560d7c..4da5b7b85 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2035,9 +2035,9 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) rn = "SRSCtl"; break; case 3: -// gen_op_mfc0_srsmap(); /* shadow registers */ + gen_op_mfc0_srsmap(); rn = "SRSMap"; -// break; + break; default: goto die; } @@ -2120,76 +2120,20 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) break; case 18: switch (sel) { - case 0: - gen_op_mfc0_watchlo0(); + case 0 ... 7: + gen_op_mfc0_watchlo(sel); rn = "WatchLo"; break; - case 1: -// gen_op_mfc0_watchlo1(); - rn = "WatchLo1"; -// break; - case 2: -// gen_op_mfc0_watchlo2(); - rn = "WatchLo2"; -// break; - case 3: -// gen_op_mfc0_watchlo3(); - rn = "WatchLo3"; -// break; - case 4: -// gen_op_mfc0_watchlo4(); - rn = "WatchLo4"; -// break; - case 5: -// gen_op_mfc0_watchlo5(); - rn = "WatchLo5"; -// break; - case 6: -// gen_op_mfc0_watchlo6(); - rn = "WatchLo6"; -// break; - case 7: -// gen_op_mfc0_watchlo7(); - rn = "WatchLo7"; -// break; default: goto die; } break; case 19: switch (sel) { - case 0: - gen_op_mfc0_watchhi0(); + case 0 ...7: + gen_op_mfc0_watchhi(sel); rn = "WatchHi"; break; - case 1: -// gen_op_mfc0_watchhi1(); - rn = "WatchHi1"; -// break; - case 2: -// gen_op_mfc0_watchhi2(); - rn = "WatchHi2"; -// break; - case 3: -// gen_op_mfc0_watchhi3(); - rn = "WatchHi3"; -// break; - case 4: -// gen_op_mfc0_watchhi4(); - rn = "WatchHi4"; -// break; - case 5: -// gen_op_mfc0_watchhi5(); - rn = "WatchHi5"; -// break; - case 6: -// gen_op_mfc0_watchhi6(); - rn = "WatchHi6"; -// break; - case 7: -// gen_op_mfc0_watchhi7(); - rn = "WatchHi7"; -// break; default: goto die; } @@ -2625,9 +2569,9 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) rn = "SRSCtl"; break; case 3: -// gen_op_mtc0_srsmap(); /* shadow registers */ + gen_op_mtc0_srsmap(); rn = "SRSMap"; -// break; + break; default: goto die; } @@ -2719,76 +2663,20 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) break; case 18: switch (sel) { - case 0: - gen_op_mtc0_watchlo0(); + case 0 ... 7: + gen_op_mtc0_watchlo(sel); rn = "WatchLo"; break; - case 1: -// gen_op_mtc0_watchlo1(); - rn = "WatchLo1"; -// break; - case 2: -// gen_op_mtc0_watchlo2(); - rn = "WatchLo2"; -// break; - case 3: -// gen_op_mtc0_watchlo3(); - rn = "WatchLo3"; -// break; - case 4: -// gen_op_mtc0_watchlo4(); - rn = "WatchLo4"; -// break; - case 5: -// gen_op_mtc0_watchlo5(); - rn = "WatchLo5"; -// break; - case 6: -// gen_op_mtc0_watchlo6(); - rn = "WatchLo6"; -// break; - case 7: -// gen_op_mtc0_watchlo7(); - rn = "WatchLo7"; -// break; default: goto die; } break; case 19: switch (sel) { - case 0: - gen_op_mtc0_watchhi0(); + case 0 ... 7: + gen_op_mtc0_watchhi(sel); rn = "WatchHi"; break; - case 1: -// gen_op_mtc0_watchhi1(); - rn = "WatchHi1"; -// break; - case 2: -// gen_op_mtc0_watchhi2(); - rn = "WatchHi2"; -// break; - case 3: -// gen_op_mtc0_watchhi3(); - rn = "WatchHi3"; -// break; - case 4: -// gen_op_mtc0_watchhi4(); - rn = "WatchHi4"; -// break; - case 5: -// gen_op_mtc0_watchhi5(); - rn = "WatchHi5"; -// break; - case 6: -// gen_op_mtc0_watchhi6(); - rn = "WatchHi6"; -// break; - case 7: -// gen_op_mtc0_watchhi7(); - rn = "WatchHi7"; -// break; default: goto die; } @@ -3309,76 +3197,20 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) break; case 18: switch (sel) { - case 0: - gen_op_dmfc0_watchlo0(); + case 0 ... 7: + gen_op_dmfc0_watchlo(sel); rn = "WatchLo"; break; - case 1: -// gen_op_dmfc0_watchlo1(); - rn = "WatchLo1"; -// break; - case 2: -// gen_op_dmfc0_watchlo2(); - rn = "WatchLo2"; -// break; - case 3: -// gen_op_dmfc0_watchlo3(); - rn = "WatchLo3"; -// break; - case 4: -// gen_op_dmfc0_watchlo4(); - rn = "WatchLo4"; -// break; - case 5: -// gen_op_dmfc0_watchlo5(); - rn = "WatchLo5"; -// break; - case 6: -// gen_op_dmfc0_watchlo6(); - rn = "WatchLo6"; -// break; - case 7: -// gen_op_dmfc0_watchlo7(); - rn = "WatchLo7"; -// break; default: goto die; } break; case 19: switch (sel) { - case 0: - gen_op_mfc0_watchhi0(); + case 0 ... 7: + gen_op_mfc0_watchhi(sel); rn = "WatchHi"; break; - case 1: -// gen_op_mfc0_watchhi1(); - rn = "WatchHi1"; -// break; - case 2: -// gen_op_mfc0_watchhi2(); - rn = "WatchHi2"; -// break; - case 3: -// gen_op_mfc0_watchhi3(); - rn = "WatchHi3"; -// break; - case 4: -// gen_op_mfc0_watchhi4(); - rn = "WatchHi4"; -// break; - case 5: -// gen_op_mfc0_watchhi5(); - rn = "WatchHi5"; -// break; - case 6: -// gen_op_mfc0_watchhi6(); - rn = "WatchHi6"; -// break; - case 7: -// gen_op_mfc0_watchhi7(); - rn = "WatchHi7"; -// break; default: goto die; } @@ -3814,7 +3646,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "SRSCtl"; break; case 3: - gen_op_mtc0_srsmap(); /* shadow registers */ + gen_op_mtc0_srsmap(); rn = "SRSMap"; break; default: @@ -3899,76 +3731,20 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) break; case 18: switch (sel) { - case 0: - gen_op_mtc0_watchlo0(); + case 0 ... 7: + gen_op_mtc0_watchlo(sel); rn = "WatchLo"; break; - case 1: -// gen_op_mtc0_watchlo1(); - rn = "WatchLo1"; -// break; - case 2: -// gen_op_mtc0_watchlo2(); - rn = "WatchLo2"; -// break; - case 3: -// gen_op_mtc0_watchlo3(); - rn = "WatchLo3"; -// break; - case 4: -// gen_op_mtc0_watchlo4(); - rn = "WatchLo4"; -// break; - case 5: -// gen_op_mtc0_watchlo5(); - rn = "WatchLo5"; -// break; - case 6: -// gen_op_mtc0_watchlo6(); - rn = "WatchLo6"; -// break; - case 7: -// gen_op_mtc0_watchlo7(); - rn = "WatchLo7"; -// break; default: goto die; } break; case 19: switch (sel) { - case 0: - gen_op_mtc0_watchhi0(); + case 0 ... 7: + gen_op_mtc0_watchhi(sel); rn = "WatchHi"; break; - case 1: -// gen_op_mtc0_watchhi1(); - rn = "WatchHi1"; -// break; - case 2: -// gen_op_mtc0_watchhi2(); - rn = "WatchHi2"; -// break; - case 3: -// gen_op_mtc0_watchhi3(); - rn = "WatchHi3"; -// break; - case 4: -// gen_op_mtc0_watchhi4(); - rn = "WatchHi4"; -// break; - case 5: -// gen_op_mtc0_watchhi5(); - rn = "WatchHi5"; -// break; - case 6: -// gen_op_mtc0_watchhi6(); - rn = "WatchHi6"; -// break; - case 7: -// gen_op_mtc0_watchhi7(); - rn = "WatchHi7"; -// break; default: goto die; } @@ -6269,8 +6045,16 @@ void cpu_reset (CPUMIPSState *env) /* vectored interrupts not implemented, timer on int 7, no performance counters. */ env->CP0_IntCtl = 0xe0000000; - env->CP0_WatchLo = 0; - env->CP0_WatchHi = 0; + { + int i; + + for (i = 0; i < 7; i++) { + env->CP0_WatchLo[i] = 0; + env->CP0_WatchHi[i] = 0x80000000; + } + env->CP0_WatchLo[7] = 0; + env->CP0_WatchHi[7] = 0; + } /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); #endif -- cgit v1.2.3 From 9daea9067aae3e324f14c6b139621c10683fc550 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 23 May 2007 08:35:19 +0000 Subject: Add more cpu.h dependencies. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2850 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index e5b3ecc05..65a4882bc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -610,8 +610,8 @@ endif ifeq ($(TARGET_BASE_ARCH), mips) helper.o: cpu.h exec-all.h -op.o: op_template.c fop_template.c op_mem.c exec.h -op_helper.o: op_helper_mem.c exec.h softmmu_template.h +op.o: op_template.c fop_template.c op_mem.c exec.h cpu.h +op_helper.o: op_helper_mem.c exec.h softmmu_template.h cpu.h translate.o: translate_init.c exec-all.h disas.h endif -- cgit v1.2.3 From 0633879f1ac38b18d84c46dda506300cc8329723 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 23 May 2007 19:58:11 +0000 Subject: m68k/ColdFire system emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2851 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 +- configure | 2 +- cpu-exec.c | 18 +- exec-all.h | 2 + hw/an5206.c | 89 ++++++ hw/mcf5206.c | 813 ++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/main.c | 7 +- softmmu_header.h | 4 + target-m68k/cpu.h | 29 +- target-m68k/exec.h | 4 + target-m68k/helper.c | 64 +++- target-m68k/op-hacks.h | 30 +- target-m68k/op.c | 101 ++---- target-m68k/op_helper.c | 140 +++++++++ target-m68k/op_mem.h | 46 +++ target-m68k/qregs.def | 1 + target-m68k/translate.c | 392 ++++++++++++++++------- vl.c | 2 + vl.h | 6 + 19 files changed, 1548 insertions(+), 207 deletions(-) create mode 100644 hw/an5206.c create mode 100644 hw/mcf5206.c create mode 100644 target-m68k/op_helper.c create mode 100644 target-m68k/op_mem.h diff --git a/Makefile.target b/Makefile.target index 65a4882bc..d24f4a567 100644 --- a/Makefile.target +++ b/Makefile.target @@ -308,7 +308,7 @@ LIBOBJS+= op_helper.o helper.o endif ifeq ($(TARGET_BASE_ARCH), m68k) -LIBOBJS+= helper.o +LIBOBJS+= op_helper.o helper.o endif ifeq ($(TARGET_BASE_ARCH), alpha) @@ -466,6 +466,9 @@ endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o endif +ifeq ($(TARGET_BASE_ARCH), m68k) +VL_OBJS+= an5206.o mcf5206.o ptimer.o +endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o endif diff --git a/configure b/configure index 7436c5fc7..8b2743f25 100755 --- a/configure +++ b/configure @@ -467,7 +467,7 @@ 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 mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu " + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then diff --git a/cpu-exec.c b/cpu-exec.c index fcac463ba..ea18b73ff 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -196,7 +196,7 @@ static inline TranslationBlock *tb_find_fast(void) cs_base = 0; pc = env->PC; #elif defined(TARGET_M68K) - flags = env->fpcr & M68K_FPCR_PREC; + flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S); cs_base = 0; pc = env->pc; #elif defined(TARGET_SH4) @@ -297,7 +297,7 @@ int cpu_exec(CPUState *env1) return EXCP_HALTED; } } -#elif defined(TARGET_ALPHA) +#elif defined(TARGET_ALPHA) || defined(TARGET_M68K) if (env1->halted) { if (env1->interrupt_request & CPU_INTERRUPT_HARD) { env1->halted = 0; @@ -390,6 +390,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_ALPHA) do_interrupt(env); +#elif defined(TARGET_M68K) + do_interrupt(0); #endif } env->exception_index = -1; @@ -542,6 +544,18 @@ int cpu_exec(CPUState *env1) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); } +#elif defined(TARGET_M68K) + if (interrupt_request & CPU_INTERRUPT_HARD + && ((env->sr & SR_I) >> SR_I_SHIFT) + < env->pending_level) { + /* Real hardware gets the interrupt vector via an + IACK cycle at this point. Current emulated + hardware doesn't rely on this, so we + provide/save the vector when the interrupt is + first signalled. */ + env->exception_index = env->pending_vector; + do_interrupt(1); + } #endif /* Don't use the cached interupt_request value, do_interrupt may have updated the EXITTB flag. */ diff --git a/exec-all.h b/exec-all.h index c6b7bd198..dbfe45761 100644 --- a/exec-all.h +++ b/exec-all.h @@ -584,6 +584,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) is_user = ((env->sr & SR_MD) == 0); #elif defined (TARGET_ALPHA) is_user = ((env->ps >> 3) & 3); +#elif defined (TARGET_M68K) + is_user = ((env->sr & SR_S) == 0); #else #error unimplemented CPU #endif diff --git a/hw/an5206.c b/hw/an5206.c new file mode 100644 index 000000000..1306d1964 --- /dev/null +++ b/hw/an5206.c @@ -0,0 +1,89 @@ +/* + * Arnewsh 5206 ColdFire system emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GPL + */ + +#include "vl.h" + +#define KERNEL_LOAD_ADDR 0x10000 +#define AN5206_MBAR_ADDR 0x10000000 +#define AN5206_RAMBAR_ADDR 0x20000000 + +/* Stub functions for hardware that doesn't exist. */ +void pic_info(void) +{ +} + +void irq_info(void) +{ +} + +void DMA_run (void) +{ +} + +/* Board init. */ + +static void an5206_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env; + int kernel_size; + uint64_t elf_entry; + target_ulong entry; + + env = cpu_init(); + if (!cpu_model) + cpu_model = "m5206"; + cpu_m68k_set_model(env, cpu_model); + + /* Initialize CPU registers. */ + env->vbr = 0; + /* TODO: allow changing MBAR and RAMBAR. */ + env->mbar = AN5206_MBAR_ADDR | 1; + env->rambar0 = AN5206_RAMBAR_ADDR | 1; + + /* DRAM at address zero */ + cpu_register_physical_memory(0, ram_size, + qemu_ram_alloc(ram_size) | IO_MEM_RAM); + + /* Internal SRAM. */ + cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512, + qemu_ram_alloc(512) | IO_MEM_RAM); + + mcf5206_init(AN5206_MBAR_ADDR, env); + + /* Load kernel. */ + if (!kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + + kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uboot(kernel_filename, &entry, NULL); + } + if (kernel_size < 0) { + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR); + entry = KERNEL_LOAD_ADDR; + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + env->pc = entry; +} + +QEMUMachine an5206_machine = { + "an5206", + "Arnewsh 5206", + an5206_init, +}; diff --git a/hw/mcf5206.c b/hw/mcf5206.c new file mode 100644 index 000000000..0da791293 --- /dev/null +++ b/hw/mcf5206.c @@ -0,0 +1,813 @@ +/* + * Motorola ColdFire MCF5206 SoC embedded peripheral emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GPL + */ +#include "vl.h" + +/* General purpose timer module. */ +typedef struct { + uint16_t tmr; + uint16_t trr; + uint16_t tcr; + uint16_t ter; + ptimer_state *timer; + qemu_irq irq; + int irq_state; +} m5206_timer_state; + +#define TMR_RST 0x01 +#define TMR_CLK 0x06 +#define TMR_FRR 0x08 +#define TMR_ORI 0x10 +#define TMR_OM 0x20 +#define TMR_CE 0xc0 + +#define TER_CAP 0x01 +#define TER_REF 0x02 + +static void m5206_timer_update(m5206_timer_state *s) +{ + if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF)) + qemu_irq_raise(s->irq); + else + qemu_irq_lower(s->irq); +} + +static void m5206_timer_reset(m5206_timer_state *s) +{ + s->tmr = 0; + s->trr = 0; +} + +static void m5206_timer_recalibrate(m5206_timer_state *s) +{ + int prescale; + int mode; + + ptimer_stop(s->timer); + + if ((s->tmr & TMR_RST) == 0) + return; + + prescale = (s->tmr >> 8) + 1; + mode = (s->tmr >> 1) & 3; + if (mode == 2) + prescale *= 16; + + if (mode == 3 || mode == 0) + cpu_abort(cpu_single_env, + "m5206_timer: mode %d not implemented\n", mode); + if ((s->tmr & TMR_FRR) == 0) + cpu_abort(cpu_single_env, + "m5206_timer: free running mode not implemented\n"); + + /* Assume 66MHz system clock. */ + ptimer_set_freq(s->timer, 66000000 / prescale); + + ptimer_set_limit(s->timer, s->trr, 0); + + ptimer_run(s->timer, 0); +} + +static void m5206_timer_trigger(void *opaque) +{ + m5206_timer_state *s = (m5206_timer_state *)opaque; + s->ter |= TER_REF; + m5206_timer_update(s); +} + +static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr) +{ + switch (addr) { + case 0: + return s->tmr; + case 4: + return s->trr; + case 8: + return s->tcr; + case 0xc: + return s->trr - ptimer_get_count(s->timer); + case 0x11: + return s->ter; + default: + return 0; + } +} + +static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) +{ + switch (addr) { + case 0: + if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) { + m5206_timer_reset(s); + } + s->tmr = val; + m5206_timer_recalibrate(s); + break; + case 4: + s->trr = val; + m5206_timer_recalibrate(s); + break; + case 8: + s->tcr = val; + break; + case 0xc: + ptimer_set_count(s->timer, val); + break; + case 0x11: + s->ter &= ~val; + break; + default: + break; + } + m5206_timer_update(s); +} + +static m5206_timer_state *m5206_timer_init(qemu_irq irq) +{ + m5206_timer_state *s; + QEMUBH *bh; + + s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state)); + bh = qemu_bh_new(m5206_timer_trigger, s); + s->timer = ptimer_init(bh); + s->irq = irq; + m5206_timer_reset(s); + return s; +} + +/* UART */ + +typedef struct { + uint8_t mr[2]; + uint8_t sr; + uint8_t isr; + uint8_t imr; + uint8_t bg1; + uint8_t bg2; + uint8_t fifo[4]; + uint8_t tb; + int current_mr; + int fifo_len; + int tx_enabled; + int rx_enabled; + qemu_irq irq; + CharDriverState *chr; +} m5206_uart_state; + +/* UART Status Register bits. */ +#define M5206_UART_RxRDY 0x01 +#define M5206_UART_FFULL 0x02 +#define M5206_UART_TxRDY 0x04 +#define M5206_UART_TxEMP 0x08 +#define M5206_UART_OE 0x10 +#define M5206_UART_PE 0x20 +#define M5206_UART_FE 0x40 +#define M5206_UART_RB 0x80 + +/* Interrupt flags. */ +#define M5206_UART_TxINT 0x01 +#define M5206_UART_RxINT 0x02 +#define M5206_UART_DBINT 0x04 +#define M5206_UART_COSINT 0x80 + +/* UMR1 flags. */ +#define M5206_UART_BC0 0x01 +#define M5206_UART_BC1 0x02 +#define M5206_UART_PT 0x04 +#define M5206_UART_PM0 0x08 +#define M5206_UART_PM1 0x10 +#define M5206_UART_ERR 0x20 +#define M5206_UART_RxIRQ 0x40 +#define M5206_UART_RxRTS 0x80 + +static void m5206_uart_update(m5206_uart_state *s) +{ + s->isr &= ~(M5206_UART_TxINT | M5206_UART_RxINT); + if (s->sr & M5206_UART_TxRDY) + s->isr |= M5206_UART_TxINT; + if ((s->sr & ((s->mr[0] & M5206_UART_RxIRQ) + ? M5206_UART_FFULL : M5206_UART_RxRDY)) != 0) + s->isr |= M5206_UART_RxINT; + + qemu_set_irq(s->irq, (s->isr & s->imr) != 0); +} + +static uint32_t m5206_uart_read(m5206_uart_state *s, uint32_t addr) +{ + switch (addr) { + case 0x00: + return s->mr[s->current_mr]; + case 0x04: + return s->sr; + case 0x0c: + { + uint8_t val; + int i; + + if (s->fifo_len == 0) + return 0; + + val = s->fifo[0]; + s->fifo_len--; + for (i = 0; i < s->fifo_len; i++) + s->fifo[i] = s->fifo[i + 1]; + s->sr &= ~M5206_UART_FFULL; + if (s->fifo_len == 0) + s->sr &= ~M5206_UART_RxRDY; + m5206_uart_update(s); + return val; + } + case 0x10: + /* TODO: Implement IPCR. */ + return 0; + case 0x14: + return s->isr; + case 0x18: + return s->bg1; + case 0x1c: + return s->bg2; + default: + return 0; + } +} + +/* Update TxRDY flag and set data if present and enabled. */ +static void m5206_uart_do_tx(m5206_uart_state *s) +{ + if (s->tx_enabled && (s->sr & M5206_UART_TxEMP) == 0) { + if (s->chr) + qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1); + s->sr |= M5206_UART_TxEMP; + } + if (s->tx_enabled) { + s->sr |= M5206_UART_TxRDY; + } else { + s->sr &= ~M5206_UART_TxRDY; + } +} + +static void m5206_do_command(m5206_uart_state *s, uint8_t cmd) +{ + /* Misc command. */ + switch ((cmd >> 4) & 3) { + case 0: /* No-op. */ + break; + case 1: /* Reset mode register pointer. */ + s->current_mr = 0; + break; + case 2: /* Reset receiver. */ + s->rx_enabled = 0; + s->fifo_len = 0; + s->sr &= ~(M5206_UART_RxRDY | M5206_UART_FFULL); + break; + case 3: /* Reset transmitter. */ + s->tx_enabled = 0; + s->sr |= M5206_UART_TxEMP; + s->sr &= ~M5206_UART_TxRDY; + break; + case 4: /* Reset error status. */ + break; + case 5: /* Reset break-change interrupt. */ + s->isr &= ~M5206_UART_DBINT; + break; + case 6: /* Start break. */ + case 7: /* Stop break. */ + break; + } + + /* Transmitter command. */ + switch ((cmd >> 2) & 3) { + case 0: /* No-op. */ + break; + case 1: /* Enable. */ + s->tx_enabled = 1; + m5206_uart_do_tx(s); + break; + case 2: /* Disable. */ + s->tx_enabled = 0; + m5206_uart_do_tx(s); + break; + case 3: /* Reserved. */ + fprintf(stderr, "m5206_uart: Bad TX command\n"); + break; + } + + /* Receiver command. */ + switch (cmd & 3) { + case 0: /* No-op. */ + break; + case 1: /* Enable. */ + s->rx_enabled = 1; + break; + case 2: + s->rx_enabled = 0; + break; + case 3: /* Reserved. */ + fprintf(stderr, "m5206_uart: Bad RX command\n"); + break; + } +} + +static void m5206_uart_write(m5206_uart_state *s, uint32_t addr, uint32_t val) +{ + switch (addr) { + case 0x00: + s->mr[s->current_mr] = val; + s->current_mr = 1; + break; + case 0x04: + /* CSR is ignored. */ + break; + case 0x08: /* Command Register. */ + m5206_do_command(s, val); + break; + case 0x0c: /* Transmit Buffer. */ + s->sr &= ~M5206_UART_TxEMP; + s->tb = val; + m5206_uart_do_tx(s); + break; + case 0x10: + /* ACR is ignored. */ + break; + case 0x14: + s->imr = val; + break; + default: + break; + } + m5206_uart_update(s); +} + +static void m5206_uart_reset(m5206_uart_state *s) +{ + s->fifo_len = 0; + s->mr[0] = 0; + s->mr[1] = 0; + s->sr = M5206_UART_TxEMP; + s->tx_enabled = 0; + s->rx_enabled = 0; + s->isr = 0; + s->imr = 0; +} + +static void m5206_uart_push_byte(m5206_uart_state *s, uint8_t data) +{ + /* Break events overwrite the last byte if the fifo is full. */ + if (s->fifo_len == 4) + s->fifo_len--; + + s->fifo[s->fifo_len] = data; + s->fifo_len++; + s->sr |= M5206_UART_RxRDY; + if (s->fifo_len == 4) + s->sr |= M5206_UART_FFULL; + + m5206_uart_update(s); +} + +static void m5206_uart_event(void *opaque, int event) +{ + m5206_uart_state *s = (m5206_uart_state *)opaque; + + switch (event) { + case CHR_EVENT_BREAK: + s->isr |= M5206_UART_DBINT; + m5206_uart_push_byte(s, 0); + break; + default: + break; + } +} + +static int m5206_uart_can_receive(void *opaque) +{ + m5206_uart_state *s = (m5206_uart_state *)opaque; + + return s->rx_enabled && (s->sr & M5206_UART_FFULL) == 0; +} + +static void m5206_uart_receive(void *opaque, const uint8_t *buf, int size) +{ + m5206_uart_state *s = (m5206_uart_state *)opaque; + + m5206_uart_push_byte(s, buf[0]); +} + +static m5206_uart_state *m5206_uart_init(qemu_irq irq, CharDriverState *chr) +{ + m5206_uart_state *s; + + s = qemu_mallocz(sizeof(m5206_uart_state)); + s->chr = chr; + s->irq = irq; + if (chr) { + qemu_chr_add_handlers(chr, m5206_uart_can_receive, m5206_uart_receive, + m5206_uart_event, s); + } + m5206_uart_reset(s); + return s; +} + +/* System Integration Module. */ + +typedef struct { + CPUState *env; + m5206_timer_state *timer[2]; + m5206_uart_state *uart[2]; + uint8_t scr; + uint8_t icr[14]; + uint16_t imr; /* 1 == interrupt is masked. */ + uint16_t ipr; + uint8_t rsr; + uint8_t swivr; + uint8_t par; + /* Include the UART vector registers here. */ + uint8_t uivr[2]; +} m5206_mbar_state; + +/* Interrupt controller. */ + +static int m5206_find_pending_irq(m5206_mbar_state *s) +{ + int level; + int vector; + uint16_t active; + int i; + + level = 0; + vector = 0; + active = s->ipr & ~s->imr; + if (!active) + return 0; + + for (i = 1; i < 14; i++) { + if (active & (1 << i)) { + if ((s->icr[i] & 0x1f) > level) { + level = s->icr[i] & 0x1f; + vector = i; + } + } + } + + if (level < 4) + vector = 0; + + return vector; +} + +static void m5206_mbar_update(m5206_mbar_state *s) +{ + int irq; + int vector; + int level; + + irq = m5206_find_pending_irq(s); + if (irq) { + int tmp; + tmp = s->icr[irq]; + level = (tmp >> 2) & 7; + if (tmp & 0x80) { + /* Autovector. */ + vector = 24 + level; + } else { + switch (irq) { + case 8: /* SWT */ + vector = s->swivr; + break; + case 12: /* UART1 */ + vector = s->uivr[0]; + break; + case 13: /* UART2 */ + vector = s->uivr[1]; + break; + default: + /* Unknown vector. */ + fprintf(stderr, "Unhandled vector for IRQ %d\n", irq); + vector = 0xf; + break; + } + } + } else { + level = 0; + vector = 0; + } + m68k_set_irq_level(s->env, level, vector); +} + +static void m5206_mbar_set_irq(void *opaque, int irq, int level) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + if (level) { + s->ipr |= 1 << irq; + } else { + s->ipr &= ~(1 << irq); + } + m5206_mbar_update(s); +} + +/* System Integration Module. */ + +static void m5206_mbar_reset(m5206_mbar_state *s) +{ + s->scr = 0xc0; + s->icr[1] = 0x04; + s->icr[2] = 0x08; + s->icr[3] = 0x0c; + s->icr[4] = 0x10; + s->icr[5] = 0x14; + s->icr[6] = 0x18; + s->icr[7] = 0x1c; + s->icr[8] = 0x1c; + s->icr[9] = 0x80; + s->icr[10] = 0x80; + s->icr[11] = 0x80; + s->icr[12] = 0x00; + s->icr[13] = 0x00; + s->imr = 0x3ffe; + s->rsr = 0x80; + s->swivr = 0x0f; + s->par = 0; +} + +static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset) +{ + if (offset >= 0x100 && offset < 0x120) { + return m5206_timer_read(s->timer[0], offset - 0x100); + } else if (offset >= 0x120 && offset < 0x140) { + return m5206_timer_read(s->timer[1], offset - 0x120); + } else if (offset >= 0x140 && offset < 0x160) { + return m5206_uart_read(s->uart[0], offset - 0x140); + } else if (offset >= 0x180 && offset < 0x1a0) { + return m5206_uart_read(s->uart[1], offset - 0x180); + } + switch (offset) { + case 0x03: return s->scr; + case 0x14 ... 0x20: return s->icr[offset - 0x13]; + case 0x36: return s->imr; + case 0x3a: return s->ipr; + case 0x40: return s->rsr; + case 0x41: return 0; + case 0x42: return s->swivr; + case 0x50: + /* DRAM mask register. */ + /* FIXME: currently hardcoded to 128Mb. */ + { + uint32_t mask = ~0; + while (mask > ram_size) + mask >>= 1; + return mask & 0x0ffe0000; + } + case 0x5c: return 1; /* DRAM bank 1 empty. */ + case 0xcb: return s->par; + case 0x170: return s->uivr[0]; + case 0x1b0: return s->uivr[1]; + } + cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset); + return 0; +} + +static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, + uint32_t value) +{ + if (offset >= 0x100 && offset < 0x120) { + m5206_timer_write(s->timer[0], offset - 0x100, value); + return; + } else if (offset >= 0x120 && offset < 0x140) { + m5206_timer_write(s->timer[1], offset - 0x120, value); + return; + } else if (offset >= 0x140 && offset < 0x160) { + m5206_uart_write(s->uart[0], offset - 0x140, value); + return; + } else if (offset >= 0x180 && offset < 0x1a0) { + m5206_uart_write(s->uart[1], offset - 0x180, value); + return; + } + switch (offset) { + case 0x03: + s->scr = value; + break; + case 0x14 ... 0x20: + s->icr[offset - 0x13] = value; + m5206_mbar_update(s); + break; + case 0x36: + s->imr = value; + m5206_mbar_update(s); + break; + case 0x40: + s->rsr &= ~value; + break; + case 0x41: + /* TODO: implement watchdog. */ + break; + case 0x42: + s->swivr = value; + break; + case 0xcb: + s->par = value; + break; + case 0x170: + s->uivr[0] = value; + break; + case 0x178: case 0x17c: case 0x1c8: case 0x1bc: + /* Not implemented: UART Output port bits. */ + break; + case 0x1b0: + s->uivr[1] = value; + break; + default: + cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset); + break; + } +} + +/* Internal peripherals use a variety of register widths. + This lookup table allows a single routine to handle all of them. */ +static const int m5206_mbar_width[] = +{ + /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, + /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, + /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0, + /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset); +static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset); + +static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + offset &= 0x3ff; + if (offset > 0x200) { + cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset); + } + if (m5206_mbar_width[offset >> 2] > 1) { + uint16_t val; + val = m5206_mbar_readw(opaque, offset & ~1); + if ((offset & 1) == 0) { + val >>= 8; + } + return val & 0xff; + } + return m5206_mbar_read(s, offset); +} + +static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset > 0x200) { + cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 2) { + uint32_t val; + val = m5206_mbar_readl(opaque, offset & ~3); + if ((offset & 3) == 0) + val >>= 16; + return val & 0xffff; + } else if (width < 2) { + uint16_t val; + val = m5206_mbar_readb(opaque, offset) << 8; + val |= m5206_mbar_readb(opaque, offset + 1); + return val; + } + return m5206_mbar_read(s, offset); +} + +static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset > 0x200) { + cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width < 4) { + uint32_t val; + val = m5206_mbar_readw(opaque, offset) << 16; + val |= m5206_mbar_readw(opaque, offset + 2); + return val; + } + return m5206_mbar_read(s, offset); +} + +static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, + uint32_t value); +static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, + uint32_t value); + +static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset > 0x200) { + cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 1) { + uint32_t tmp; + tmp = m5206_mbar_readw(opaque, offset & ~1); + if (offset & 1) { + tmp = (tmp & 0xff00) | value; + } else { + tmp = (tmp & 0x00ff) | (value << 8); + } + m5206_mbar_writew(opaque, offset & ~1, tmp); + return; + } + m5206_mbar_write(s, offset, value); +} + +static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset > 0x200) { + cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width > 2) { + uint32_t tmp; + tmp = m5206_mbar_readl(opaque, offset & ~3); + if (offset & 3) { + tmp = (tmp & 0xffff0000) | value; + } else { + tmp = (tmp & 0x0000ffff) | (value << 16); + } + m5206_mbar_writel(opaque, offset & ~3, tmp); + return; + } else if (width < 2) { + m5206_mbar_writeb(opaque, offset, value >> 8); + m5206_mbar_writeb(opaque, offset + 1, value & 0xff); + return; + } + m5206_mbar_write(s, offset, value); +} + +static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; + if (offset > 0x200) { + cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; + if (width < 4) { + m5206_mbar_writew(opaque, offset, value >> 16); + m5206_mbar_writew(opaque, offset + 2, value & 0xffff); + return; + } + m5206_mbar_write(s, offset, value); +} + +static CPUReadMemoryFunc *m5206_mbar_readfn[] = { + m5206_mbar_readb, + m5206_mbar_readw, + m5206_mbar_readl +}; + +static CPUWriteMemoryFunc *m5206_mbar_writefn[] = { + m5206_mbar_writeb, + m5206_mbar_writew, + m5206_mbar_writel +}; + +qemu_irq *mcf5206_init(uint32_t base, CPUState *env) +{ + m5206_mbar_state *s; + qemu_irq *pic; + int iomemtype; + + s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state)); + iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn, + m5206_mbar_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + + pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); + s->timer[0] = m5206_timer_init(pic[9]); + s->timer[1] = m5206_timer_init(pic[10]); + s->uart[0] = m5206_uart_init(pic[12], serial_hds[0]); + s->uart[1] = m5206_uart_init(pic[13], serial_hds[1]); + s->env = env; + + m5206_mbar_reset(s); + return pic; +} + diff --git a/linux-user/main.c b/linux-user/main.c index ccb8c269d..0f4dbdadf 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1977,13 +1977,12 @@ int main(int argc, char **argv) } #elif defined(TARGET_M68K) { - m68k_def_t *def; - def = m68k_find_by_name("cfv4e"); - if (def == NULL) { + if (cpu_model == NULL) + cpu_model = "cfv4e"; + if (cpu_m68k_set_model(env, cpu_model)) { cpu_abort(cpu_single_env, "Unable to find m68k CPU definition\n"); } - cpu_m68k_register(cpu_single_env, def); env->pc = regs->pc; env->dregs[0] = regs->d0; env->dregs[1] = regs->d1; diff --git a/softmmu_header.h b/softmmu_header.h index 8c6cf74ad..317288448 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -65,6 +65,8 @@ #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) #elif defined (TARGET_ALPHA) #define CPU_MEM_INDEX ((env->ps >> 3) & 3) +#elif defined (TARGET_M68K) +#define CPU_MEM_INDEX ((env->sr & SR_S) == 0) #else #error unsupported CPU #endif @@ -86,6 +88,8 @@ #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) #elif defined (TARGET_ALPHA) #define CPU_MEM_INDEX ((env->ps >> 3) & 3) +#elif defined (TARGET_M68K) +#define CPU_MEM_INDEX ((env->sr & SR_S) == 0) #else #error unsupported CPU #endif diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index de37baf9a..c916ad7cd 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -1,7 +1,7 @@ /* * m68k virtual CPU header * - * Copyright (c) 2005-2006 CodeSourcery + * Copyright (c) 2005-2007 CodeSourcery * Written by Paul Brook * * This library is free software; you can redistribute it and/or @@ -50,6 +50,8 @@ #define EXCP_UNSUPPORTED 61 #define EXCP_ICE 13 +#define EXCP_RTE 0x100 + typedef struct CPUM68KState { uint32_t dregs[8]; uint32_t aregs[8]; @@ -76,6 +78,12 @@ typedef struct CPUM68KState { struct { uint32_t ar; } mmu; + + /* Control registers. */ + uint32_t vbr; + uint32_t mbar; + uint32_t rambar0; + /* ??? remove this. */ uint32_t t1; @@ -84,7 +92,10 @@ typedef struct CPUM68KState { int exception_index; int interrupt_request; int user_mode_only; - uint32_t address; + int halted; + + int pending_vector; + int pending_level; uint32_t qregs[MAX_QREGS]; @@ -94,6 +105,7 @@ typedef struct CPUM68KState { CPUM68KState *cpu_m68k_init(void); int cpu_m68k_exec(CPUM68KState *s); void cpu_m68k_close(CPUM68KState *s); +void do_interrupt(int is_hw); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ @@ -120,12 +132,19 @@ enum { #define CCF_V 0x02 #define CCF_Z 0x04 #define CCF_N 0x08 -#define CCF_X 0x01 +#define CCF_X 0x10 + +#define SR_I_SHIFT 8 +#define SR_I 0x0700 +#define SR_M 0x1000 +#define SR_S 0x2000 +#define SR_T 0x8000 typedef struct m68k_def_t m68k_def_t; -m68k_def_t *m68k_find_by_name(const char *); -void cpu_m68k_register(CPUM68KState *, m68k_def_t *); +int cpu_m68k_set_model(CPUM68KState *env, const char * name); + +void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); #define M68K_FPCR_PREC (1 << 6) diff --git a/target-m68k/exec.h b/target-m68k/exec.h index ef4adeb39..254f5581f 100644 --- a/target-m68k/exec.h +++ b/target-m68k/exec.h @@ -40,8 +40,12 @@ static inline void regs_to_env(void) int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op); float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1); +void helper_movec(CPUM68KState *env, int reg, uint32_t val); void cpu_loop_exit(void); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 6b8f18d15..640fe4fb8 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -1,7 +1,7 @@ /* * m68k op helpers * - * Copyright (c) 2006 CodeSourcery + * Copyright (c) 2006-2007 CodeSourcery * Written by Paul Brook * * This library is free software; you can redistribute it and/or @@ -147,3 +147,65 @@ float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1) } return res; } + +void helper_movec(CPUM68KState *env, int reg, uint32_t val) +{ + switch (reg) { + case 0x02: /* CACR */ + /* Ignored. */ + break; + case 0x801: /* VBR */ + env->vbr = val; + break; + /* TODO: Implement control registers. */ + default: + cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n", + reg, val); + } +} + +/* MMU */ + +/* TODO: This will need fixing once the MMU is implemented. */ +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} + +#if defined(CONFIG_USER_ONLY) + +int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + env->exception_index = EXCP_ACCESS; + env->mmu.ar = address; + return 1; +} + +#else + +int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + int prot; + + address &= TARGET_PAGE_MASK; + prot = PAGE_READ | PAGE_WRITE; + return tlb_set_page(env, address, address, prot, is_user, is_softmmu); +} + +/* Notify CPU of a pending interrupt. Prioritization and vectoring should + be handled by the interrupt controller. Real hardware only requests + the vector when the interrupt is acknowledged by the CPU. For + simplicitly we calculate it when the interrupt is signalled. */ +void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector) +{ + env->pending_level = level; + env->pending_vector = vector; + if (level) + cpu_interrupt(env, CPU_INTERRUPT_HARD); + else + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); +} + +#endif diff --git a/target-m68k/op-hacks.h b/target-m68k/op-hacks.h index c7865638e..01a158d83 100644 --- a/target-m68k/op-hacks.h +++ b/target-m68k/op-hacks.h @@ -27,16 +27,38 @@ static inline int gen_im32(uint32_t i) return qreg; } -static inline void gen_op_ldf32(int dest, int addr) +static inline void gen_op_ldf32_raw(int dest, int addr) { - gen_op_ld32(dest, addr); + gen_op_ld32_raw(dest, addr); } -static inline void gen_op_stf32(int addr, int dest) +static inline void gen_op_stf32_raw(int addr, int dest) { - gen_op_st32(addr, dest); + gen_op_st32_raw(addr, dest); } +#if !defined(CONFIG_USER_ONLY) +static inline void gen_op_ldf32_user(int dest, int addr) +{ + gen_op_ld32_user(dest, addr); +} + +static inline void gen_op_stf32_user(int addr, int dest) +{ + gen_op_st32_user(addr, dest); +} + +static inline void gen_op_ldf32_kernel(int dest, int addr) +{ + gen_op_ld32_kernel(dest, addr); +} + +static inline void gen_op_stf32_kernel(int addr, int dest) +{ + gen_op_st32_kernel(addr, dest); +} +#endif + static inline void gen_op_pack_32_f32(int dest, int src) { gen_op_mov32(dest, src); diff --git a/target-m68k/op.c b/target-m68k/op.c index 34878c021..ad6f403f5 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -1,7 +1,7 @@ /* * m68k micro operations * - * Copyright (c) 2006 CodeSourcery + * Copyright (c) 2006-2007 CodeSourcery * Written by Paul Brook * * This library is free software; you can redistribute it and/or @@ -86,7 +86,7 @@ void set_opf64(int qreg, float64 val) } } -#define OP(name) void OPPROTO op_##name (void) +#define OP(name) void OPPROTO glue(op_,name) (void) OP(mov32) { @@ -316,77 +316,6 @@ OP(ext16s32) FORCE_RET(); } -/* Load/store ops. */ -OP(ld8u32) -{ - uint32_t addr = get_op(PARAM2); - set_op(PARAM1, ldub(addr)); - FORCE_RET(); -} - -OP(ld8s32) -{ - uint32_t addr = get_op(PARAM2); - set_op(PARAM1, ldsb(addr)); - FORCE_RET(); -} - -OP(ld16u32) -{ - uint32_t addr = get_op(PARAM2); - set_op(PARAM1, lduw(addr)); - FORCE_RET(); -} - -OP(ld16s32) -{ - uint32_t addr = get_op(PARAM2); - set_op(PARAM1, ldsw(addr)); - FORCE_RET(); -} - -OP(ld32) -{ - uint32_t addr = get_op(PARAM2); - set_op(PARAM1, ldl(addr)); - FORCE_RET(); -} - -OP(st8) -{ - uint32_t addr = get_op(PARAM1); - stb(addr, get_op(PARAM2)); - FORCE_RET(); -} - -OP(st16) -{ - uint32_t addr = get_op(PARAM1); - stw(addr, get_op(PARAM2)); - FORCE_RET(); -} - -OP(st32) -{ - uint32_t addr = get_op(PARAM1); - stl(addr, get_op(PARAM2)); - FORCE_RET(); -} - -OP(ldf64) -{ - uint32_t addr = get_op(PARAM2); - set_opf64(PARAM1, ldfq(addr)); - FORCE_RET(); -} - -OP(stf64) -{ - uint32_t addr = get_op(PARAM1); - stfq(addr, get_opf64(PARAM2)); - FORCE_RET(); -} - OP(flush_flags) { int cc_op = PARAM1; @@ -454,6 +383,13 @@ OP(divs) FORCE_RET(); } +OP(halt) +{ + env->halted = 1; + RAISE_EXCEPTION(EXCP_HLT); + FORCE_RET(); +} + OP(raise_exception) { RAISE_EXCEPTION(PARAM1); @@ -679,3 +615,22 @@ OP(compare_quietf64) set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS)); FORCE_RET(); } + +OP(movec) +{ + int op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + helper_movec(env, op1, op2); +} + +/* Memory access. */ + +#define MEMSUFFIX _raw +#include "op_mem.h" + +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_mem.h" +#define MEMSUFFIX _kernel +#include "op_mem.h" +#endif diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c new file mode 100644 index 000000000..7455e3165 --- /dev/null +++ b/target-m68k/op_helper.c @@ -0,0 +1,140 @@ +/* + * M68K helper routines + * + * Copyright (c) 2007 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "exec.h" + +#if defined(CONFIG_USER_ONLY) + +void do_interrupt(int is_hw) +{ + env->exception_index = -1; +} + +#else + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* Try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + target_phys_addr_t pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (__builtin_expect(ret, 0)) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (target_phys_addr_t)retaddr; + 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, NULL); + } + } + cpu_loop_exit(); + } + env = saved_env; +} + +static void do_rte(void) +{ + uint32_t sp; + uint32_t fmt; + + sp = env->aregs[7]; + fmt = ldl_kernel(sp); + env->pc = ldl_kernel(sp + 4); + sp |= (fmt >> 28) & 3; + env->sr = fmt & 0xffff; + env->aregs[7] = sp + 8; +} + +void do_interrupt(int is_hw) +{ + uint32_t sp; + uint32_t fmt; + uint32_t retaddr; + uint32_t vector; + + fmt = 0; + retaddr = env->pc; + + if (!is_hw) { + switch (env->exception_index) { + case EXCP_RTE: + /* Return from an exception. */ + do_rte(); + return; + } + if (env->exception_index >= EXCP_TRAP0 + && env->exception_index <= EXCP_TRAP15) { + /* Move the PC after the trap instruction. */ + retaddr += 2; + } + } + + /* TODO: Implement USP. */ + sp = env->aregs[7]; + + vector = env->exception_index << 2; + + fmt |= 0x40000000; + fmt |= (sp & 3) << 28; + fmt |= vector << 16; + fmt |= env->sr; + + /* ??? This could cause MMU faults. */ + sp &= ~3; + sp -= 4; + stl_kernel(sp, retaddr); + sp -= 4; + stl_kernel(sp, fmt); + env->aregs[7] = sp; + env->sr |= SR_S; + if (is_hw) { + env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); + } + /* Jump to vector. */ + env->pc = ldl_kernel(env->vbr + vector); +} + +#endif diff --git a/target-m68k/op_mem.h b/target-m68k/op_mem.h new file mode 100644 index 000000000..556829f69 --- /dev/null +++ b/target-m68k/op_mem.h @@ -0,0 +1,46 @@ +/* Load/store ops. */ +#define MEM_LD_OP(name,suffix) \ +OP(glue(glue(ld,name),MEMSUFFIX)) \ +{ \ + uint32_t addr = get_op(PARAM2); \ + set_op(PARAM1, glue(glue(ld,suffix),MEMSUFFIX)(addr)); \ + FORCE_RET(); \ +} + +MEM_LD_OP(8u32,ub) +MEM_LD_OP(8s32,sb) +MEM_LD_OP(16u32,uw) +MEM_LD_OP(16s32,sw) +MEM_LD_OP(32,l) + +#undef MEM_LD_OP + +#define MEM_ST_OP(name,suffix) \ +OP(glue(glue(st,name),MEMSUFFIX)) \ +{ \ + uint32_t addr = get_op(PARAM1); \ + glue(glue(st,suffix),MEMSUFFIX)(addr, get_op(PARAM2)); \ + FORCE_RET(); \ +} + +MEM_ST_OP(8,b) +MEM_ST_OP(16,w) +MEM_ST_OP(32,l) + +#undef MEM_ST_OP + +OP(glue(ldf64,MEMSUFFIX)) +{ + uint32_t addr = get_op(PARAM2); + set_opf64(PARAM1, glue(ldfq,MEMSUFFIX)(addr)); + FORCE_RET(); +} + +OP(glue(stf64,MEMSUFFIX)) +{ + uint32_t addr = get_op(PARAM1); + glue(stfq,MEMSUFFIX)(addr, get_opf64(PARAM2)); + FORCE_RET(); +} + +#undef MEMSUFFIX diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def index d8c194408..08e7e8515 100644 --- a/target-m68k/qregs.def +++ b/target-m68k/qregs.def @@ -24,6 +24,7 @@ DEFF64(F6, fregs[6]) DEFF64(F7, fregs[7]) DEFF64(FP_RESULT, fp_result) DEFO32(PC, pc) +DEFO32(SR, sr) DEFO32(CC_OP, cc_op) DEFR(T0, AREG1, QMODE_I32) DEFO32(CC_DEST, cc_dest) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 3b2563582..eff32867b 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1,7 +1,7 @@ /* * m68k translation * - * Copyright (c) 2005-2006 CodeSourcery + * Copyright (c) 2005-2007 CodeSourcery * Written by Paul Brook * * This library is free software; you can redistribute it and/or @@ -30,6 +30,8 @@ #include "disas.h" #include "m68k-qreg.h" +//#define DEBUG_DISPATCH 1 + static inline void qemu_assert(int cond, const char *msg) { if (!cond) { @@ -43,6 +45,7 @@ typedef struct DisasContext { target_ulong pc; int is_jmp; int cc_op; + int user; uint32_t fpcr; struct TranslationBlock *tb; int singlestep_enabled; @@ -50,6 +53,12 @@ typedef struct DisasContext { #define DISAS_JUMP_NEXT 4 +#if defined(CONFIG_USER_ONLY) +#define IS_USER(s) 1 +#else +#define IS_USER(s) s->user +#endif + /* XXX: move that elsewhere */ /* ??? Fix exceptions. */ static void *gen_throws_exception; @@ -68,6 +77,25 @@ enum { }; #include "gen-op.h" + +#if defined(CONFIG_USER_ONLY) +#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val) +#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr) +#else +#define gen_st(s, name, addr, val) do { \ + if (IS_USER(s)) \ + gen_op_st##name##_user(addr, val); \ + else \ + gen_op_st##name##_kernel(addr, val); \ + } while (0) +#define gen_ld(s, name, val, addr) do { \ + if (IS_USER(s)) \ + gen_op_ld##name##_user(val, addr); \ + else \ + gen_op_ld##name##_kernel(val, addr); \ + } while (0) +#endif + #include "op-hacks.h" #define OS_BYTE 0 @@ -101,40 +129,49 @@ static m68k_def_t m68k_cpu_defs[] = { typedef void (*disas_proc)(DisasContext *, uint16_t); +#ifdef DEBUG_DISPATCH +#define DISAS_INSN(name) \ + static void real_disas_##name (DisasContext *s, uint16_t insn); \ + static void disas_##name (DisasContext *s, uint16_t insn) { \ + if (logfile) fprintf(logfile, "Dispatch " #name "\n"); \ + real_disas_##name(s, insn); } \ + static void real_disas_##name (DisasContext *s, uint16_t insn) +#else #define DISAS_INSN(name) \ static void disas_##name (DisasContext *s, uint16_t insn) +#endif /* Generate a load from the specified address. Narrow values are sign extended to full register width. */ -static inline int gen_load(int opsize, int addr, int sign) +static inline int gen_load(DisasContext * s, int opsize, int addr, int sign) { int tmp; switch(opsize) { case OS_BYTE: tmp = gen_new_qreg(QMODE_I32); if (sign) - gen_op_ld8s32(tmp, addr); + gen_ld(s, 8s32, tmp, addr); else - gen_op_ld8u32(tmp, addr); + gen_ld(s, 8u32, tmp, addr); break; case OS_WORD: tmp = gen_new_qreg(QMODE_I32); if (sign) - gen_op_ld16s32(tmp, addr); + gen_ld(s, 16s32, tmp, addr); else - gen_op_ld16u32(tmp, addr); + gen_ld(s, 16u32, tmp, addr); break; case OS_LONG: tmp = gen_new_qreg(QMODE_I32); - gen_op_ld32(tmp, addr); + gen_ld(s, 32, tmp, addr); break; case OS_SINGLE: tmp = gen_new_qreg(QMODE_F32); - gen_op_ldf32(tmp, addr); + gen_ld(s, f32, tmp, addr); break; case OS_DOUBLE: tmp = gen_new_qreg(QMODE_F64); - gen_op_ldf64(tmp, addr); + gen_ld(s, f64, tmp, addr); break; default: qemu_assert(0, "bad load size"); @@ -144,23 +181,23 @@ static inline int gen_load(int opsize, int addr, int sign) } /* Generate a store. */ -static inline void gen_store(int opsize, int addr, int val) +static inline void gen_store(DisasContext *s, int opsize, int addr, int val) { switch(opsize) { case OS_BYTE: - gen_op_st8(addr, val); + gen_st(s, 8, addr, val); break; case OS_WORD: - gen_op_st16(addr, val); + gen_st(s, 16, addr, val); break; case OS_LONG: - gen_op_st32(addr, val); + gen_st(s, 32, addr, val); break; case OS_SINGLE: - gen_op_stf32(addr, val); + gen_st(s, f32, addr, val); break; case OS_DOUBLE: - gen_op_stf64(addr, val); + gen_st(s, f64, addr, val); break; default: qemu_assert(0, "bad store size"); @@ -170,13 +207,13 @@ static inline void gen_store(int opsize, int addr, int val) /* Generate an unsigned load if VAL is 0 a signed load if val is -1, otherwise generate a store. */ -static int gen_ldst(int opsize, int addr, int val) +static int gen_ldst(DisasContext *s, int opsize, int addr, int val) { if (val > 0) { - gen_store(opsize, addr, val); + gen_store(s, opsize, addr, val); return 0; } else { - return gen_load(opsize, addr, val != 0); + return gen_load(s, opsize, addr, val != 0); } } @@ -191,7 +228,7 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base) int tmp; offset = s->pc; - ext = lduw(s->pc); + ext = lduw_code(s->pc); s->pc += 2; tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0); /* ??? Check W/L bit. */ @@ -216,9 +253,9 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base) static inline uint32_t read_im32(DisasContext *s) { uint32_t im; - im = ((uint32_t)lduw(s->pc)) << 16; + im = ((uint32_t)lduw_code(s->pc)) << 16; s->pc += 2; - im |= lduw(s->pc); + im |= lduw_code(s->pc); s->pc += 2; return im; } @@ -343,7 +380,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) case 5: /* Indirect displacement. */ reg += QREG_A0; tmp = gen_new_qreg(QMODE_I32); - ext = lduw(s->pc); + ext = lduw_code(s->pc); s->pc += 2; gen_op_add32(tmp, reg, gen_im32((int16_t)ext)); return tmp; @@ -353,7 +390,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) case 7: /* Other */ switch (reg) { case 0: /* Absolute short. */ - offset = ldsw(s->pc); + offset = ldsw_code(s->pc); s->pc += 2; return gen_im32(offset); case 1: /* Absolute long. */ @@ -362,7 +399,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) case 2: /* pc displacement */ tmp = gen_new_qreg(QMODE_I32); offset = s->pc; - offset += ldsw(s->pc); + offset += ldsw_code(s->pc); s->pc += 2; return gen_im32(offset); case 3: /* pc index+displacement. */ @@ -391,7 +428,7 @@ static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize, if (addrp) *addrp = tmp; } - return gen_ldst(opsize, tmp, val); + return gen_ldst(s, opsize, tmp, val); } /* Generate code to load/store a value ito/from an EA. If VAL > 0 this is @@ -424,10 +461,10 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, } case 2: /* Indirect register */ reg += QREG_A0; - return gen_ldst(opsize, reg, val); + return gen_ldst(s, opsize, reg, val); case 3: /* Indirect postincrement. */ reg += QREG_A0; - result = gen_ldst(opsize, reg, val); + result = gen_ldst(s, opsize, reg, val); /* ??? This is not exception safe. The instruction may still fault after this point. */ if (val > 0 || !addrp) @@ -443,7 +480,7 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, if (addrp) *addrp = tmp; } - result = gen_ldst(opsize, tmp, val); + result = gen_ldst(s, opsize, tmp, val); /* ??? This is not exception safe. The instruction may still fault after this point. */ if (val > 0 || !addrp) { @@ -467,16 +504,16 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, switch (opsize) { case OS_BYTE: if (val) - offset = ldsb(s->pc + 1); + offset = ldsb_code(s->pc + 1); else - offset = ldub(s->pc + 1); + offset = ldub_code(s->pc + 1); s->pc += 2; break; case OS_WORD: if (val) - offset = ldsw(s->pc); + offset = ldsw_code(s->pc); else - offset = lduw(s->pc); + offset = lduw_code(s->pc); s->pc += 2; break; case OS_LONG: @@ -622,6 +659,14 @@ DISAS_INSN(scc) gen_set_label(l1); } +/* Force a TB lookup after an instruction that changes the CPU state. */ +static void gen_lookup_tb(DisasContext *s) +{ + gen_flush_cc_op(s); + gen_op_mov32(QREG_PC, gen_im32(s->pc)); + s->is_jmp = DISAS_UPDATE; +} + /* Generate a jump to to the address in qreg DEST. */ static void gen_jmp(DisasContext *s, int dest) { @@ -735,7 +780,7 @@ DISAS_INSN(divl) int reg; uint16_t ext; - ext = lduw(s->pc); + ext = lduw_code(s->pc); s->pc += 2; if (ext & 0x87f8) { gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); @@ -903,13 +948,13 @@ DISAS_INSN(sats) gen_logic_cc(s, tmp); } -static void gen_push(int val) +static void gen_push(DisasContext *s, int val) { int tmp; tmp = gen_new_qreg(QMODE_I32); gen_op_sub32(tmp, QREG_SP, gen_im32(4)); - gen_store(OS_LONG, tmp, val); + gen_store(s, OS_LONG, tmp, val); gen_op_mov32(QREG_SP, tmp); } @@ -922,7 +967,7 @@ DISAS_INSN(movem) int tmp; int is_load; - mask = lduw(s->pc); + mask = lduw_code(s->pc); s->pc += 2; tmp = gen_lea(s, insn, OS_LONG); addr = gen_new_qreg(QMODE_I32); @@ -935,10 +980,10 @@ DISAS_INSN(movem) else reg = AREG(i, 0); if (is_load) { - tmp = gen_load(OS_LONG, addr, 0); + tmp = gen_load(s, OS_LONG, addr, 0); gen_op_mov32(reg, tmp); } else { - gen_store(OS_LONG, addr, reg); + gen_store(s, OS_LONG, addr, reg); } if (mask != 1) gen_op_add32(addr, addr, gen_im32(4)); @@ -963,7 +1008,7 @@ DISAS_INSN(bitop_im) opsize = OS_LONG; op = (insn >> 6) & 3; - bitnum = lduw(s->pc); + bitnum = lduw_code(s->pc); s->pc += 2; if (bitnum & 0xff00) { disas_undef(s, insn); @@ -1155,9 +1200,8 @@ DISAS_INSN(clr) gen_logic_cc(s, gen_im32(0)); } -DISAS_INSN(move_from_ccr) +static int gen_get_ccr(DisasContext *s) { - int reg; int dest; gen_flush_flags(s); @@ -1165,8 +1209,17 @@ DISAS_INSN(move_from_ccr) gen_op_get_xflag(dest); gen_op_shl32(dest, dest, gen_im32(4)); gen_op_or32(dest, dest, QREG_CC_DEST); + return dest; +} + +DISAS_INSN(move_from_ccr) +{ + int reg; + int ccr; + + ccr = gen_get_ccr(s); reg = DREG(insn, 0); - gen_partset_reg(OS_WORD, reg, dest); + gen_partset_reg(OS_WORD, reg, ccr); } DISAS_INSN(neg) @@ -1184,7 +1237,16 @@ DISAS_INSN(neg) s->cc_op = CC_OP_SUB; } -DISAS_INSN(move_to_ccr) +static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) +{ + gen_op_logic_cc(gen_im32(val & 0xf)); + gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4)); + if (!ccr_only) { + gen_op_mov32(QREG_SR, gen_im32(val & 0xff00)); + } +} + +static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only) { int src1; int reg; @@ -1199,19 +1261,26 @@ DISAS_INSN(move_to_ccr) gen_op_shr32(src1, reg, gen_im32(4)); gen_op_and32(src1, src1, gen_im32(1)); gen_op_update_xflag_tst(src1); + if (!ccr_only) { + gen_op_and32(QREG_SR, reg, gen_im32(0xff00)); + } } - else if ((insn & 0x3f) != 0x3c) + else if ((insn & 0x3f) == 0x3c) { - uint8_t val; - val = ldsb(s->pc); + uint16_t val; + val = lduw_code(s->pc); s->pc += 2; - gen_op_logic_cc(gen_im32(val & 0xf)); - gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4)); + gen_set_sr_im(s, val, ccr_only); } else disas_undef(s, insn); } +DISAS_INSN(move_to_ccr) +{ + gen_set_sr(s, insn, 1); +} + DISAS_INSN(not) { int reg; @@ -1244,7 +1313,7 @@ DISAS_INSN(pea) int tmp; tmp = gen_lea(s, insn, OS_LONG); - gen_push(tmp); + gen_push(s, tmp); } DISAS_INSN(ext) @@ -1322,7 +1391,7 @@ DISAS_INSN(mull) /* The upper 32 bits of the product are discarded, so muls.l and mulu.l are functionally equivalent. */ - ext = lduw(s->pc); + ext = lduw_code(s->pc); s->pc += 2; if (ext & 0x87ff) { gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); @@ -1343,12 +1412,12 @@ DISAS_INSN(link) int reg; int tmp; - offset = ldsw(s->pc); + offset = ldsw_code(s->pc); s->pc += 2; reg = AREG(insn, 0); tmp = gen_new_qreg(QMODE_I32); gen_op_sub32(tmp, QREG_SP, gen_im32(4)); - gen_store(OS_LONG, tmp, reg); + gen_store(s, OS_LONG, tmp, reg); if (reg != QREG_SP) gen_op_mov32(reg, tmp); gen_op_add32(QREG_SP, tmp, gen_im32(offset)); @@ -1363,7 +1432,7 @@ DISAS_INSN(unlk) src = gen_new_qreg(QMODE_I32); reg = AREG(insn, 0); gen_op_mov32(src, reg); - tmp = gen_load(OS_LONG, src, 0); + tmp = gen_load(s, OS_LONG, src, 0); gen_op_mov32(reg, tmp); gen_op_add32(QREG_SP, src, gen_im32(4)); } @@ -1376,7 +1445,7 @@ DISAS_INSN(rts) { int tmp; - tmp = gen_load(OS_LONG, QREG_SP, 0); + tmp = gen_load(s, OS_LONG, QREG_SP, 0); gen_op_add32(QREG_SP, QREG_SP, gen_im32(4)); gen_jmp(s, tmp); } @@ -1390,7 +1459,7 @@ DISAS_INSN(jump) tmp = gen_lea(s, insn, OS_LONG); if ((insn & 0x40) == 0) { /* jsr */ - gen_push(gen_im32(s->pc)); + gen_push(s, gen_im32(s->pc)); } gen_jmp(s, tmp); } @@ -1460,14 +1529,14 @@ DISAS_INSN(branch) op = (insn >> 8) & 0xf; offset = (int8_t)insn; if (offset == 0) { - offset = ldsw(s->pc); + offset = ldsw_code(s->pc); s->pc += 2; } else if (offset == -1) { offset = read_im32(s); } if (op == 1) { /* bsr */ - gen_push(gen_im32(s->pc)); + gen_push(s, gen_im32(s->pc)); } gen_flush_cc_op(s); if (op > 1) { @@ -1752,68 +1821,154 @@ DISAS_INSN(ff1) cpu_abort(NULL, "Unimplemented insn: ff1"); } +static int gen_get_sr(DisasContext *s) +{ + int ccr; + int sr; + + ccr = gen_get_ccr(s); + sr = gen_new_qreg(QMODE_I32); + gen_op_and32(sr, QREG_SR, gen_im32(0xffe0)); + gen_op_or32(sr, sr, ccr); + return sr; +} + DISAS_INSN(strldsr) { uint16_t ext; uint32_t addr; addr = s->pc - 2; - ext = lduw(s->pc); + ext = lduw_code(s->pc); s->pc += 2; - if (ext != 0x46FC) + if (ext != 0x46FC) { gen_exception(s, addr, EXCP_UNSUPPORTED); - else + return; + } + ext = lduw_code(s->pc); + s->pc += 2; + if (IS_USER(s) || (ext & SR_S) == 0) { gen_exception(s, addr, EXCP_PRIVILEGE); + return; + } + gen_push(s, gen_get_sr(s)); + gen_set_sr_im(s, ext, 0); } DISAS_INSN(move_from_sr) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + int reg; + int sr; + + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + sr = gen_get_sr(s); + reg = DREG(insn, 0); + gen_partset_reg(OS_WORD, reg, sr); } DISAS_INSN(move_to_sr) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + gen_set_sr(s, insn, 0); + gen_lookup_tb(s); } DISAS_INSN(move_from_usp) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + /* TODO: Implement USP. */ + gen_exception(s, s->pc - 2, EXCP_ILLEGAL); } DISAS_INSN(move_to_usp) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + /* TODO: Implement USP. */ + gen_exception(s, s->pc - 2, EXCP_ILLEGAL); } DISAS_INSN(halt) { - gen_exception(s, s->pc, EXCP_HLT); + gen_flush_cc_op(s); + gen_jmp(s, gen_im32(s->pc)); + gen_op_halt(); } DISAS_INSN(stop) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + uint16_t ext; + + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + + ext = lduw_code(s->pc); + s->pc += 2; + + gen_set_sr_im(s, ext, 0); + disas_halt(s, insn); } DISAS_INSN(rte) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + gen_exception(s, s->pc - 2, EXCP_RTE); } DISAS_INSN(movec) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + uint16_t ext; + int reg; + + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + + ext = lduw_code(s->pc); + s->pc += 2; + + if (ext & 0x8000) { + reg = AREG(ext, 12); + } else { + reg = DREG(ext, 12); + } + gen_op_movec(gen_im32(ext & 0xfff), reg); + gen_lookup_tb(s); } DISAS_INSN(intouch) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + /* ICache fetch. Implement as no-op. */ } DISAS_INSN(cpushl) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + /* Cache push/invalidate. Implement as no-op. */ } DISAS_INSN(wddata) @@ -1823,7 +1978,12 @@ DISAS_INSN(wddata) DISAS_INSN(wdebug) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + if (IS_USER(s)) { + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } + /* TODO: Implement wdebug. */ + qemu_assert(0, "WDEBUG not implemented"); } DISAS_INSN(trap) @@ -1843,7 +2003,7 @@ DISAS_INSN(fpu) int round; int opsize; - ext = lduw(s->pc); + ext = lduw_code(s->pc); s->pc += 2; opmode = ext & 0x7f; switch ((ext >> 13) & 7) { @@ -1928,10 +2088,10 @@ DISAS_INSN(fpu) if (ext & mask) { if (ext & (1 << 13)) { /* store */ - gen_op_stf64(addr, dest); + gen_st(s, f64, addr, dest); } else { /* load */ - gen_op_ldf64(dest, addr); + gen_ld(s, f64, dest, addr); } if (ext & (mask - 1)) gen_op_add32(addr, addr, gen_im32(8)); @@ -2060,10 +2220,10 @@ DISAS_INSN(fbcc) int l1; addr = s->pc; - offset = ldsw(s->pc); + offset = ldsw_code(s->pc); s->pc += 2; if (insn & (1 << 6)) { - offset = (offset << 16) | lduw(s->pc); + offset = (offset << 16) | lduw_code(s->pc); s->pc += 2; } @@ -2143,6 +2303,18 @@ DISAS_INSN(fbcc) gen_jmp_tb(s, 1, addr + offset); } +DISAS_INSN(frestore) +{ + /* TODO: Implement frestore. */ + qemu_assert(0, "FRESTORE not implemented"); +} + +DISAS_INSN(fsave) +{ + /* TODO: Implement fsave. */ + qemu_assert(0, "FSAVE not implemented"); +} + static disas_proc opcode_table[65536]; static void @@ -2168,11 +2340,10 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) i <<= 1; from = opcode & ~(i - 1); to = from + i; - for (i = from; i < to; i++) - { + for (i = from; i < to; i++) { if ((i & mask) == opcode) opcode_table[i] = proc; - } + } } /* Register m68k opcode handlers. Order is important. @@ -2274,6 +2445,8 @@ register_m68k_insns (m68k_def_t *def) INSN(undef_fpu, f000, f000, CF_A); INSN(fpu, f200, ffc0, CF_FPU); INSN(fbcc, f280, ffc0, CF_FPU); + INSN(frestore, f340, ffc0, CF_FPU); + INSN(fsave, f340, ffc0, CF_FPU); INSN(intouch, f340, ffc0, CF_A); INSN(cpushl, f428, ff38, CF_A); INSN(wddata, fb00, ff00, CF_A); @@ -2287,7 +2460,7 @@ static void disas_m68k_insn(CPUState * env, DisasContext *s) { uint16_t insn; - insn = lduw(s->pc); + insn = lduw_code(s->pc); s->pc += 2; opcode_table[insn](s, insn); @@ -2576,6 +2749,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, dc->cc_op = CC_OP_DYNAMIC; dc->singlestep_enabled = env->singlestep_enabled; dc->fpcr = env->fpcr; + dc->user = (env->sr & SR_S) == 0; nb_gen_labels = 0; lj = -1; do { @@ -2675,6 +2849,19 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } +void cpu_reset(CPUM68KState *env) +{ + memset(env, 0, offsetof(CPUM68KState, breakpoints)); +#if !defined (CONFIG_USER_ONLY) + env->sr = 0x2700; +#endif + /* ??? FP regs should be initialized to NaN. */ + env->cc_op = CC_OP_FLAGS; + /* TODO: We should set PC from the interrupt vector. */ + env->pc = 0; + tlb_flush(env, 1); +} + CPUM68KState *cpu_m68k_init(void) { CPUM68KState *env; @@ -2684,10 +2871,7 @@ CPUM68KState *cpu_m68k_init(void) return NULL; cpu_exec_init(env); - memset(env, 0, sizeof(CPUM68KState)); - /* ??? FP regs should be initialized to NaN. */ - cpu_single_env = env; - env->cc_op = CC_OP_FLAGS; + cpu_reset(env); return env; } @@ -2696,23 +2880,20 @@ void cpu_m68k_close(CPUM68KState *env) free(env); } -m68k_def_t *m68k_find_by_name(const char *name) +int cpu_m68k_set_model(CPUM68KState *env, const char * name) { m68k_def_t *def; - def = m68k_cpu_defs; - while (def->name) - { + for (def = m68k_cpu_defs; def->name; def++) { if (strcmp(def->name, name) == 0) - return def; - def++; - } - return NULL; -} + break; + } + if (!def->name) + return 1; -void cpu_m68k_register(CPUM68KState *env, m68k_def_t *def) -{ register_m68k_insns(def); + + return 0; } void cpu_dump_state(CPUState *env, FILE *f, @@ -2737,24 +2918,3 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result); } -/* ??? */ -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) -{ - return addr; -} - -#if defined(CONFIG_USER_ONLY) - -int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) -{ - env->exception_index = EXCP_ACCESS; - env->mmu.ar = address; - return 1; -} - -#else - -#error not implemented - -#endif diff --git a/vl.c b/vl.c index 02c3c9cf7..373435b4a 100644 --- a/vl.c +++ b/vl.c @@ -6833,6 +6833,8 @@ void register_machines(void) qemu_register_machine(&shix_machine); #elif defined(TARGET_ALPHA) /* XXX: TODO */ +#elif defined(TARGET_M68K) + qemu_register_machine(&an5206_machine); #else #error unsupported CPU #endif diff --git a/vl.h b/vl.h index 88ebdbccf..330861e09 100644 --- a/vl.h +++ b/vl.h @@ -1597,6 +1597,12 @@ void ptimer_stop(ptimer_state *s); #include "hw/pxa.h" +/* mcf5206.c */ +qemu_irq *mcf5206_init(uint32_t base, CPUState *env); + +/* an5206.c */ +extern QEMUMachine an5206_machine; + #include "gdbstub.h" #endif /* defined(QEMU_TOOL) */ -- cgit v1.2.3 From 209a4e691d230b01cf44c9f954a34db04d5708be Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 23 May 2007 20:16:15 +0000 Subject: Document ColdFire system emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2852 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 95e7de261..544de3b00 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -81,6 +81,7 @@ For system emulation, the following hardware targets are supported: @item ARM Versatile baseboard (ARM926E) @item ARM RealView Emulation baseboard (ARM926EJ-S) @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) +@item Arnewsh MCF5206 evaluation board (ColdFire V2). @end itemize For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported. @@ -1549,6 +1550,7 @@ differences are mentionned in the following sections. * Sparc64 System emulator invocation:: * MIPS System emulator invocation:: * ARM System emulator invocation:: +* ColdFire System emulator invocation:: @end menu @node QEMU PowerPC System emulator @@ -1822,6 +1824,20 @@ WM8750 audio CODEC on I@math{^2}C and I@math{^2}S busses A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. +@node ColdFire System emulator invocation +@section ColdFire System emulator invocation + +Use the executable @file{qemu-system-m68k} to simulate a ColdFire machine. +The emulator is able to boot a uClinux kernel. +The following devices are emulated: + +@itemize @minus +@item +MCF5206 ColdFire V2 Microprocessor. +@item +Two on-chip UARTs. +@end itemize + @node QEMU User space emulator @chapter QEMU User space emulator -- cgit v1.2.3 From 3f582262e5443ded25ba6c8f016a114279a3b59f Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 23 May 2007 21:47:51 +0000 Subject: Implement the PXA2xx I2C master controller. Fix PXA270-specific timers and make minor changes in other PXA parts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2853 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa.h | 12 ++- hw/pxa2xx.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/pxa2xx_dma.c | 6 +- hw/pxa2xx_lcd.c | 3 +- hw/pxa2xx_pcmcia.c | 1 + hw/pxa2xx_timer.c | 22 ++--- hw/smbus.c | 3 + hw/smbus.h | 2 +- 8 files changed, 271 insertions(+), 25 deletions(-) diff --git a/hw/pxa.h b/hw/pxa.h index 8e82c28e0..986dffac7 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -65,10 +65,8 @@ qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env); /* pxa2xx_timer.c */ -void pxa25x_timer_init(target_phys_addr_t base, - qemu_irq *irqs, CPUState *cpustate); -void pxa27x_timer_init(target_phys_addr_t base, - qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate); +void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs); +void pxa27x_timer_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq irq4); /* pxa2xx_gpio.c */ struct pxa2xx_gpio_info_s; @@ -117,6 +115,11 @@ void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, uint32_t (*readfn)(void *opaque), void (*writefn)(void *opaque, uint32_t value), void *opaque); +struct pxa2xx_i2c_s; +struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, + qemu_irq irq, int ioregister); +i2c_bus *pxa2xx_i2c_bus(struct pxa2xx_i2c_s *s); + struct pxa2xx_i2s_s; struct pxa2xx_fir_s; @@ -127,6 +130,7 @@ struct pxa2xx_state_s { struct pxa2xx_gpio_info_s *gpio; struct pxa2xx_lcdc_s *lcd; struct pxa2xx_ssp_s **ssp; + struct pxa2xx_i2c_s *i2c[2]; struct pxa2xx_mmci_s *mmc; struct pxa2xx_pcmcia_s *pcmcia[2]; struct pxa2xx_i2s_s *i2s; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index a791f0845..913c0bd76 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -69,9 +69,16 @@ static struct { #define PCMD0 0x80 /* Power Manager I2C Command register File 0 */ #define PCMD31 0xfc /* Power Manager I2C Command register File 31 */ +static uint32_t pxa2xx_i2c_read(void *, target_phys_addr_t); +static void pxa2xx_i2c_write(void *, target_phys_addr_t, uint32_t); + static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr) { struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + if (addr > s->pm_base + PCMD31) { + /* Special case: PWRI2C registers appear in the same range. */ + return pxa2xx_i2c_read(s->i2c[1], addr); + } addr -= s->pm_base; switch (addr) { @@ -92,6 +99,11 @@ static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + if (addr > s->pm_base + PCMD31) { + /* Special case: PWRI2C registers appear in the same range. */ + pxa2xx_i2c_write(s->i2c[1], addr, value); + return; + } addr -= s->pm_base; switch (addr) { @@ -1086,6 +1098,225 @@ static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = { pxa2xx_rtc_write, }; +/* I2C Interface */ +struct pxa2xx_i2c_s { + i2c_slave slave; + i2c_bus *bus; + target_phys_addr_t base; + qemu_irq irq; + + uint16_t control; + uint16_t status; + uint8_t ibmr; + uint8_t data; +}; + +#define IBMR 0x80 /* I2C Bus Monitor register */ +#define IDBR 0x88 /* I2C Data Buffer register */ +#define ICR 0x90 /* I2C Control register */ +#define ISR 0x98 /* I2C Status register */ +#define ISAR 0xa0 /* I2C Slave Address register */ + +static void pxa2xx_i2c_update(struct pxa2xx_i2c_s *s) +{ + uint16_t level = 0; + level |= s->status & s->control & (1 << 10); /* BED */ + level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */ + level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */ + level |= s->status & (1 << 9); /* SAD */ + qemu_set_irq(s->irq, !!level); +} + +/* These are only stubs now. */ +static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event) +{ + struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c; + + switch (event) { + case I2C_START_SEND: + s->status |= (1 << 9); /* set SAD */ + s->status &= ~(1 << 0); /* clear RWM */ + break; + case I2C_START_RECV: + s->status |= (1 << 9); /* set SAD */ + s->status |= 1 << 0; /* set RWM */ + break; + case I2C_FINISH: + s->status |= (1 << 4); /* set SSD */ + break; + case I2C_NACK: + s->status |= 1 << 1; /* set ACKNAK */ + break; + } + pxa2xx_i2c_update(s); +} + +static int pxa2xx_i2c_rx(i2c_slave *i2c) +{ + struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c; + if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) + return 0; + + if (s->status & (1 << 0)) { /* RWM */ + s->status |= 1 << 6; /* set ITE */ + } + pxa2xx_i2c_update(s); + + return s->data; +} + +static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data) +{ + struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c; + if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) + return 1; + + if (!(s->status & (1 << 0))) { /* RWM */ + s->status |= 1 << 7; /* set IRF */ + s->data = data; + } + pxa2xx_i2c_update(s); + + return 1; +} + +static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr) +{ + struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque; + addr -= s->base; + + switch (addr) { + case ICR: + return s->control; + case ISR: + return s->status | (i2c_bus_busy(s->bus) << 2); + case ISAR: + return s->slave.address; + case IDBR: + return s->data; + case IBMR: + if (s->status & (1 << 2)) + s->ibmr ^= 3; /* Fake SCL and SDA pin changes */ + else + s->ibmr = 0; + return s->ibmr; + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + break; + } + return 0; +} + +static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque; + int ack; + addr -= s->base; + + switch (addr) { + case ICR: + s->control = value & 0xfff7; + if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */ + /* TODO: slave mode */ + if (value & (1 << 0)) { /* START condition */ + if (s->data & 1) + s->status |= 1 << 0; /* set RWM */ + else + s->status &= ~(1 << 0); /* clear RWM */ + ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1); + } else { + if (s->status & (1 << 0)) { /* RWM */ + s->data = i2c_recv(s->bus); + if (value & (1 << 2)) /* ACKNAK */ + i2c_nack(s->bus); + ack = 1; + } else + ack = !i2c_send(s->bus, s->data); + } + + if (value & (1 << 1)) /* STOP condition */ + i2c_end_transfer(s->bus); + + if (ack) { + if (value & (1 << 0)) /* START condition */ + s->status |= 1 << 6; /* set ITE */ + else + if (s->status & (1 << 0)) /* RWM */ + s->status |= 1 << 7; /* set IRF */ + else + s->status |= 1 << 6; /* set ITE */ + s->status &= ~(1 << 1); /* clear ACKNAK */ + } else { + s->status |= 1 << 6; /* set ITE */ + s->status |= 1 << 10; /* set BED */ + s->status |= 1 << 1; /* set ACKNAK */ + } + } + if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */ + if (value & (1 << 4)) /* MA */ + i2c_end_transfer(s->bus); + pxa2xx_i2c_update(s); + break; + + case ISR: + s->status &= ~(value & 0x07f0); + pxa2xx_i2c_update(s); + break; + + case ISAR: + i2c_set_slave_address(&s->slave, value & 0x7f); + break; + + case IDBR: + s->data = value & 0xff; + break; + + default: + printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr); + } +} + +static CPUReadMemoryFunc *pxa2xx_i2c_readfn[] = { + pxa2xx_i2c_read, + pxa2xx_i2c_read, + pxa2xx_i2c_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_i2c_writefn[] = { + pxa2xx_i2c_write, + pxa2xx_i2c_write, + pxa2xx_i2c_write, +}; + +struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, + qemu_irq irq, int ioregister) +{ + int iomemtype; + struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) + qemu_mallocz(sizeof(struct pxa2xx_i2c_s)); + + s->base = base; + s->irq = irq; + s->slave.event = pxa2xx_i2c_event; + s->slave.recv = pxa2xx_i2c_rx; + s->slave.send = pxa2xx_i2c_tx; + s->bus = i2c_init_bus(); + + if (ioregister) { + iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn, + pxa2xx_i2c_writefn, s); + cpu_register_physical_memory(s->base & 0xfffff000, 0xfff, iomemtype); + } + + return s; +} + +i2c_bus *pxa2xx_i2c_bus(struct pxa2xx_i2c_s *s) +{ + return s->bus; +} + /* PXA Inter-IC Sound Controller */ static void pxa2xx_i2s_reset(struct pxa2xx_i2s_s *i2s) { @@ -1544,7 +1775,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); pxa27x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0], - s->pic[PXA27X_PIC_OST_4_11], s->env); + s->pic[PXA27X_PIC_OST_4_11]); s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); @@ -1608,6 +1839,12 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype); pxa2xx_rtc_reset(s); + /* Note that PM registers are in the same page with PWRI2C registers. + * As a workaround we don't map PWRI2C into memory and we expect + * PM handlers to call PWRI2C handlers when appropriate. */ + s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 1); + s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0); + s->pm_base = 0x40f00000; iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, pxa2xx_pm_writefn, s); @@ -1643,7 +1880,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]); - pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0], s->env); + pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0]); s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85); @@ -1707,6 +1944,12 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype); pxa2xx_rtc_reset(s); + /* Note that PM registers are in the same page with PWRI2C registers. + * As a workaround we don't map PWRI2C into memory and we expect + * PM handlers to call PWRI2C handlers when appropriate. */ + s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 1); + s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0); + s->pm_base = 0x40f00000; iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, pxa2xx_pm_writefn, s); diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 63d2fb79c..d2ed62357 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -443,16 +443,16 @@ static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base, s->base = base; s->irq = irq; s->handler = (pxa2xx_dma_handler_t) pxa2xx_dma_request; - s->req = qemu_mallocz(sizeof(int) * PXA2XX_DMA_NUM_REQUESTS); + s->req = qemu_mallocz(sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS); memset(s->chan, 0, sizeof(struct pxa2xx_dma_channel_s) * s->channels); for (i = 0; i < s->channels; i ++) s->chan[i].state = DCSR_STOPINTR; - memset(s->req, 0, sizeof(int) * PXA2XX_DMA_NUM_REQUESTS); + memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS); iomemtype = cpu_register_io_memory(0, pxa2xx_dma_readfn, - pxa2xx_dma_writefn, s); + pxa2xx_dma_writefn, s); cpu_register_physical_memory(base, 0x0000ffff, iomemtype); return s; diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index db20a9366..f8ddbb4a4 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -793,8 +793,7 @@ static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s, dest, src, s->xres, -dest_width); if (addr < start) start = addr; - if (new_addr > end) - end = new_addr; + end = new_addr; if (y < *miny) *miny = y; if (y >= *maxy) diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index 171d90279..586fd8c95 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -171,6 +171,7 @@ struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base) s->slot.slot_string = "PXA PC Card Socket 0"; s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0]; pcmcia_socket_register(&s->slot); + return s; } diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index fe55ce0bd..073806a64 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -75,7 +75,7 @@ struct pxa2xx_timer4_s { }; typedef struct { - uint32_t base; + target_phys_addr_t base; int32_t clock; int32_t oldclock; uint64_t lastload; @@ -85,8 +85,6 @@ typedef struct { uint32_t events; uint32_t irq_enabled; uint32_t reset3; - CPUState *cpustate; - int64_t qemu_ticks; uint32_t snapshot; } pxa2xx_timer_info; @@ -121,7 +119,7 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) counter = counters[n]; if (!s->tm4[counter].freq) { - qemu_del_timer(s->timer[n].qtimer); + qemu_del_timer(s->tm4[n].tm.qtimer); return; } @@ -131,7 +129,7 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), ticks_per_sec, s->tm4[counter].freq); - qemu_mod_timer(s->timer[n].qtimer, new_qemu); + qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu); } static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset) @@ -350,7 +348,7 @@ static void pxa2xx_timer_tick(void *opaque) if (t->num == 3) if (i->reset3 & 1) { i->reset3 = 0; - cpu_reset(i->cpustate); + qemu_system_reset_request(); } } @@ -367,7 +365,7 @@ static void pxa2xx_timer_tick4(void *opaque) } static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, - qemu_irq *irqs, CPUState *cpustate) + qemu_irq *irqs) { int i; int iomemtype; @@ -380,7 +378,6 @@ static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, s->clock = 0; s->lastload = qemu_get_clock(vm_clock); s->reset3 = 0; - s->cpustate = cpustate; for (i = 0; i < 4; i ++) { s->timer[i].value = 0; @@ -398,18 +395,17 @@ static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, return s; } -void pxa25x_timer_init(target_phys_addr_t base, - qemu_irq *irqs, CPUState *cpustate) +void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs) { - pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate); + pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs); s->freq = PXA25X_FREQ; s->tm4 = 0; } void pxa27x_timer_init(target_phys_addr_t base, - qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate) + qemu_irq *irqs, qemu_irq irq4) { - pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate); + pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs); int i; s->freq = PXA27X_FREQ; s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 * diff --git a/hw/smbus.c b/hw/smbus.c index 651a7a0b9..5189d51df 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -193,6 +193,9 @@ SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size) { SMBusDevice *dev; + if (size < sizeof(SMBusDevice)) + cpu_abort(cpu_single_env, "SMBus struct too small"); + dev = (SMBusDevice *)i2c_slave_init(bus, address, size); dev->i2c.event = smbus_i2c_event; dev->i2c.recv = smbus_i2c_recv; diff --git a/hw/smbus.h b/hw/smbus.h index 9125896cc..36977731e 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -37,7 +37,7 @@ struct SMBusDevice { (if present). The device is responsible figuring out what type of command this is. */ void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len); - /* Likewise we can't distinguish between defferent reads, or even know + /* Likewise we can't distinguish between different reads, or even know the length of the read until the read is complete, so read data a byte at a time. The device is responsible for adding the length byte on block reads. */ -- cgit v1.2.3 From adb86c372e1596c07437682ff7aa71c905dbc14f Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 23 May 2007 22:04:23 +0000 Subject: Add WM8750 and MAX7310 chips (I2C slaves). Wolfson Microsystems WM8750 audio chip and Maxim MAX7310 gpio expander chip are used in the Spitz. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2854 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/i2c.h | 14 ++ hw/max7310.c | 188 +++++++++++++++++++ hw/spitz.c | 56 ++++++ hw/wm8750.c | 545 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 805 insertions(+), 2 deletions(-) create mode 100644 hw/max7310.c create mode 100644 hw/wm8750.c diff --git a/Makefile.target b/Makefile.target index d24f4a567..a48652e88 100644 --- a/Makefile.target +++ b/Makefile.target @@ -459,8 +459,8 @@ VL_OBJS+= versatile_pci.o sd.o ptimer.o VL_OBJS+= arm_gic.o realview.o arm_sysctl.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o -VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o -VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) +VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o +VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) diff --git a/hw/i2c.h b/hw/i2c.h index a3c4de3ca..dec45e552 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -46,4 +46,18 @@ void i2c_nack(i2c_bus *bus); int i2c_send(i2c_bus *bus, uint8_t data); int i2c_recv(i2c_bus *bus); +/* max7310.c */ +i2c_slave *max7310_init(i2c_bus *bus); +void max7310_reset(i2c_slave *i2c); +qemu_irq *max7310_gpio_in_get(i2c_slave *i2c); +void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler); + +/* wm8750.c */ +i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio); +void wm8750_reset(i2c_slave *i2c); +void wm8750_data_req_set(i2c_slave *i2c, + void (*data_req)(void *, int, int), void *opaque); +void wm8750_dac_dat(void *opaque, uint32_t sample); +uint32_t wm8750_adc_dat(void *opaque); + #endif diff --git a/hw/max7310.c b/hw/max7310.c new file mode 100644 index 000000000..a4aaf17d2 --- /dev/null +++ b/hw/max7310.c @@ -0,0 +1,188 @@ +/* + * MAX7310 8-port GPIO expansion chip. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This file is licensed under GNU GPL. + */ + +#include "vl.h" + +struct max7310_s { + i2c_slave i2c; + int i2c_command_byte; + int len; + + uint8_t level; + uint8_t direction; + uint8_t polarity; + uint8_t status; + uint8_t command; + qemu_irq handler[8]; + qemu_irq *gpio_in; +}; + +void max7310_reset(i2c_slave *i2c) +{ + struct max7310_s *s = (struct max7310_s *) i2c; + s->level &= s->direction; + s->direction = 0xff; + s->polarity = 0xf0; + s->status = 0x01; + s->command = 0x00; +} + +static int max7310_rx(i2c_slave *i2c) +{ + struct max7310_s *s = (struct max7310_s *) i2c; + + switch (s->command) { + case 0x00: /* Input port */ + return s->level ^ s->polarity; + break; + + case 0x01: /* Output port */ + return s->level & ~s->direction; + break; + + case 0x02: /* Polarity inversion */ + return s->polarity; + + case 0x03: /* Configuration */ + return s->direction; + + case 0x04: /* Timeout */ + return s->status; + break; + + case 0xff: /* Reserved */ + return 0xff; + + default: +#ifdef VERBOSE + printf("%s: unknown register %02x\n", __FUNCTION__, s->command); +#endif + break; + } + return 0xff; +} + +static int max7310_tx(i2c_slave *i2c, uint8_t data) +{ + struct max7310_s *s = (struct max7310_s *) i2c; + uint8_t diff; + int line; + + if (s->len ++ > 1) { +#ifdef VERBOSE + printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len); +#endif + return 1; + } + + if (s->i2c_command_byte) { + s->command = data; + s->i2c_command_byte = 0; + return 0; + } + + switch (s->command) { + case 0x01: /* Output port */ + for (diff = (data ^ s->level) & ~s->direction; diff; + diff &= ~(1 << line)) { + line = ffs(diff) - 1; + if (s->handler[line]) + qemu_set_irq(s->handler[line], (data >> line) & 1); + } + s->level = (s->level & s->direction) | (data & ~s->direction); + break; + + case 0x02: /* Polarity inversion */ + s->polarity = data; + break; + + case 0x03: /* Configuration */ + s->level &= ~(s->direction ^ data); + s->direction = data; + break; + + case 0x04: /* Timeout */ + s->status = data; + break; + + case 0x00: /* Input port - ignore writes */ + break; + default: +#ifdef VERBOSE + printf("%s: unknown register %02x\n", __FUNCTION__, s->command); +#endif + return 1; + } + + return 0; +} + +static void max7310_event(i2c_slave *i2c, enum i2c_event event) +{ + struct max7310_s *s = (struct max7310_s *) i2c; + s->len = 0; + + switch (event) { + case I2C_START_SEND: + s->i2c_command_byte = 1; + break; + case I2C_FINISH: + if (s->len == 1) +#ifdef VERBOSE + printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len); +#endif + break; + default: + break; + } +} + +static void max7310_gpio_set(void *opaque, int line, int level) +{ + struct max7310_s *s = (struct max7310_s *) opaque; + if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0) + cpu_abort(cpu_single_env, "bad GPIO line"); + + if (level) + s->level |= s->direction & (1 << line); + else + s->level &= ~(s->direction & (1 << line)); +} + +/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols), + * but also accepts sequences that are not SMBus so return an I2C device. */ +struct i2c_slave *max7310_init(i2c_bus *bus) +{ + struct max7310_s *s = (struct max7310_s *) + i2c_slave_init(bus, 0, sizeof(struct max7310_s)); + s->i2c.event = max7310_event; + s->i2c.recv = max7310_rx; + s->i2c.send = max7310_tx; + s->gpio_in = qemu_allocate_irqs(max7310_gpio_set, s, + sizeof(s->handler) / sizeof(*s->handler)); + + max7310_reset(&s->i2c); + + return &s->i2c; +} + +qemu_irq *max7310_gpio_in_get(i2c_slave *i2c) +{ + struct max7310_s *s = (struct max7310_s *) i2c; + return s->gpio_in; +} + +void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler) +{ + struct max7310_s *s = (struct max7310_s *) i2c; + if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0) + cpu_abort(cpu_single_env, "bad GPIO line"); + + s->handler[line] = handler; +} diff --git a/hw/spitz.c b/hw/spitz.c index 72b049e4e..4dd59bb6e 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -801,6 +801,57 @@ static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu) } } +/* Wm8750 and Max7310 on I2C */ + +#define AKITA_MAX_ADDR 0x18 +#define SPITZ_WM_ADDRL 0x1a +#define SPITZ_WM_ADDRH 0x1b + +#define SPITZ_GPIO_WM 5 + +#ifdef HAS_AUDIO +static void spitz_wm8750_addr(int line, int level, void *opaque) +{ + i2c_slave *wm = (i2c_slave *) opaque; + if (level) + i2c_set_slave_address(wm, SPITZ_WM_ADDRH); + else + i2c_set_slave_address(wm, SPITZ_WM_ADDRL); +} +#endif + +static void spitz_i2c_setup(struct pxa2xx_state_s *cpu) +{ + /* Attach the CPU on one end of our I2C bus. */ + i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); + +#ifdef HAS_AUDIO + AudioState *audio; + i2c_slave *wm; + + audio = AUD_init(); + if (!audio) + return; + /* Attach a WM8750 to the bus */ + wm = wm8750_init(bus, audio); + + spitz_wm8750_addr(0, 0, wm); + pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_WM, spitz_wm8750_addr, wm); + /* .. and to the sound interface. */ + cpu->i2s->opaque = wm; + cpu->i2s->codec_out = wm8750_dac_dat; + cpu->i2s->codec_in = wm8750_adc_dat; + wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s); +#endif +} + +static void spitz_akita_i2c_setup(struct pxa2xx_state_s *cpu) +{ + /* Attach a Max7310 to Akita I2C bus. */ + i2c_set_slave_address(max7310_init(pxa2xx_i2c_bus(cpu->i2c[0])), + AKITA_MAX_ADDR); +} + /* Other peripherals */ static void spitz_charge_switch(int line, int level, void *opaque) @@ -1026,6 +1077,11 @@ static void spitz_common_init(int ram_size, int vga_ram_size, spitz_gpio_setup(cpu, (model == akita) ? 1 : 2); + spitz_i2c_setup(cpu); + + if (model == akita) + spitz_akita_i2c_setup(cpu); + if (model == terrier) /* A 6.0 GB microdrive is permanently sitting in CF slot 0. */ spitz_microdrive_attach(cpu); diff --git a/hw/wm8750.c b/hw/wm8750.c new file mode 100644 index 000000000..c08eb7300 --- /dev/null +++ b/hw/wm8750.c @@ -0,0 +1,545 @@ +/* + * WM8750 audio CODEC. + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This file is licensed under GNU GPL. + */ + +#include "vl.h" + +#define IN_PORT_N 3 +#define OUT_PORT_N 3 + +#define CODEC "wm8750" + +struct wm_rate_s; +struct wm8750_s { + i2c_slave i2c; + uint8_t i2c_data[2]; + int i2c_len; + QEMUSoundCard card; + SWVoiceIn *adc_voice[IN_PORT_N]; + SWVoiceOut *dac_voice[OUT_PORT_N]; + int enable; + void (*data_req)(void *, int, int); + void *opaque; + uint8_t data_in[4096]; + uint8_t data_out[4096]; + int idx_in, req_in; + int idx_out, req_out; + + SWVoiceOut **out[2]; + uint8_t outvol[7], outmute[2]; + SWVoiceIn **in[2]; + uint8_t invol[4], inmute[2]; + + uint8_t diff[2], pol, ds, monomix[2], alc, mute; + uint8_t path[4], mpath[2], power, format; + uint32_t inmask, outmask; + const struct wm_rate_s *rate; +}; + +static inline void wm8750_in_load(struct wm8750_s *s) +{ + int acquired; + if (s->idx_in + s->req_in <= sizeof(s->data_in)) + return; + s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in); + acquired = AUD_read(*s->in[0], s->data_in + s->idx_in, + sizeof(s->data_in) - s->idx_in); +} + +static inline void wm8750_out_flush(struct wm8750_s *s) +{ + int sent; + if (!s->idx_out) + return; + sent = AUD_write(*s->out[0], s->data_out, s->idx_out); + s->idx_out = 0; +} + +static void wm8750_audio_in_cb(void *opaque, int avail_b) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + s->req_in = avail_b; + s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2); + +#if 0 + wm8750_in_load(s); +#endif +} + +static void wm8750_audio_out_cb(void *opaque, int free_b) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + wm8750_out_flush(s); + + s->req_out = free_b; + s->data_req(s->opaque, free_b >> 2, s->req_in >> 2); +} + +struct wm_rate_s { + int adc; + int adc_hz; + int dac; + int dac_hz; +}; + +static const struct wm_rate_s wm_rate_table[] = { + { 256, 48000, 256, 48000 }, /* SR: 00000 */ + { 384, 48000, 384, 48000 }, /* SR: 00001 */ + { 256, 48000, 1536, 8000 }, /* SR: 00010 */ + { 384, 48000, 2304, 8000 }, /* SR: 00011 */ + { 1536, 8000, 256, 48000 }, /* SR: 00100 */ + { 2304, 8000, 384, 48000 }, /* SR: 00101 */ + { 1536, 8000, 1536, 8000 }, /* SR: 00110 */ + { 2304, 8000, 2304, 8000 }, /* SR: 00111 */ + { 1024, 12000, 1024, 12000 }, /* SR: 01000 */ + { 1526, 12000, 1536, 12000 }, /* SR: 01001 */ + { 768, 16000, 768, 16000 }, /* SR: 01010 */ + { 1152, 16000, 1152, 16000 }, /* SR: 01011 */ + { 384, 32000, 384, 32000 }, /* SR: 01100 */ + { 576, 32000, 576, 32000 }, /* SR: 01101 */ + { 128, 96000, 128, 96000 }, /* SR: 01110 */ + { 192, 96000, 192, 96000 }, /* SR: 01111 */ + { 256, 44100, 256, 44100 }, /* SR: 10000 */ + { 384, 44100, 384, 44100 }, /* SR: 10001 */ + { 256, 44100, 1408, 8018 }, /* SR: 10010 */ + { 384, 44100, 2112, 8018 }, /* SR: 10011 */ + { 1408, 8018, 256, 44100 }, /* SR: 10100 */ + { 2112, 8018, 384, 44100 }, /* SR: 10101 */ + { 1408, 8018, 1408, 8018 }, /* SR: 10110 */ + { 2112, 8018, 2112, 8018 }, /* SR: 10111 */ + { 1024, 11025, 1024, 11025 }, /* SR: 11000 */ + { 1536, 11025, 1536, 11025 }, /* SR: 11001 */ + { 512, 22050, 512, 22050 }, /* SR: 11010 */ + { 768, 22050, 768, 22050 }, /* SR: 11011 */ + { 512, 24000, 512, 24000 }, /* SR: 11100 */ + { 768, 24000, 768, 24000 }, /* SR: 11101 */ + { 128, 88200, 128, 88200 }, /* SR: 11110 */ + { 192, 88200, 128, 88200 }, /* SR: 11111 */ +}; + +void wm8750_set_format(struct wm8750_s *s) +{ + int i; + audsettings_t in_fmt; + audsettings_t out_fmt; + audsettings_t monoout_fmt; + + wm8750_out_flush(s); + + if (s->in[0] && *s->in[0]) + AUD_set_active_in(*s->in[0], 0); + if (s->out[0] && *s->out[0]) + AUD_set_active_out(*s->out[0], 0); + + for (i = 0; i < IN_PORT_N; i ++) + if (s->adc_voice[i]) { + AUD_close_in(&s->card, s->adc_voice[i]); + s->adc_voice[i] = 0; + } + for (i = 0; i < OUT_PORT_N; i ++) + if (s->dac_voice[i]) { + AUD_close_out(&s->card, s->dac_voice[i]); + s->dac_voice[i] = 0; + } + + if (!s->enable) + return; + + /* Setup input */ + in_fmt.endianness = 0; + in_fmt.nchannels = 2; + in_fmt.freq = s->rate->adc_hz; + in_fmt.fmt = AUD_FMT_S16; + + s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0], + CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt); + s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1], + CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt); + s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2], + CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt); + + /* Setup output */ + out_fmt.endianness = 0; + out_fmt.nchannels = 2; + out_fmt.freq = s->rate->dac_hz; + out_fmt.fmt = AUD_FMT_S16; + monoout_fmt.endianness = 0; + monoout_fmt.nchannels = 1; + monoout_fmt.freq = s->rate->dac_hz; + monoout_fmt.fmt = AUD_FMT_S16; + + s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], + CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt); + s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1], + CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt); + /* MONOMIX is also in stereo for simplicity */ + s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2], + CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt); + /* no sense emulating OUT3 which is a mix of other outputs */ + + /* We should connect the left and right channels to their + * respective inputs/outputs but we have completely no need + * for mixing or combining paths to different ports, so we + * connect both channels to where the left channel is routed. */ + if (s->in[0] && *s->in[0]) + AUD_set_active_in(*s->in[0], 1); + if (s->out[0] && *s->out[0]) + AUD_set_active_out(*s->out[0], 1); +} + +void inline wm8750_mask_update(struct wm8750_s *s) +{ +#define R_ONLY 0x0000ffff +#define L_ONLY 0xffff0000 +#define BOTH (R_ONLY | L_ONLY) +#define NONE (R_ONLY & L_ONLY) + s->inmask = + (s->inmute[0] ? R_ONLY : BOTH) & + (s->inmute[1] ? L_ONLY : BOTH) & + (s->mute ? NONE : BOTH); + s->outmask = + (s->outmute[0] ? R_ONLY : BOTH) & + (s->outmute[1] ? L_ONLY : BOTH) & + (s->mute ? NONE : BOTH); +} + +void wm8750_reset(i2c_slave *i2c) +{ + struct wm8750_s *s = (struct wm8750_s *) i2c; + s->enable = 0; + wm8750_set_format(s); + s->diff[0] = 0; + s->diff[1] = 0; + s->ds = 0; + s->alc = 0; + s->in[0] = &s->adc_voice[0]; + s->invol[0] = 0x17; + s->invol[1] = 0x17; + s->invol[2] = 0xc3; + s->invol[3] = 0xc3; + s->out[0] = &s->dac_voice[0]; + s->outvol[0] = 0xff; + s->outvol[1] = 0xff; + s->outvol[2] = 0x79; + s->outvol[3] = 0x79; + s->outvol[4] = 0x79; + s->outvol[5] = 0x79; + s->inmute[0] = 0; + s->inmute[1] = 0; + s->outmute[0] = 0; + s->outmute[1] = 0; + s->mute = 1; + s->path[0] = 0; + s->path[1] = 0; + s->path[2] = 0; + s->path[3] = 0; + s->mpath[0] = 0; + s->mpath[1] = 0; + s->format = 0x0a; + s->idx_in = sizeof(s->data_in); + s->req_in = 0; + s->idx_out = 0; + s->req_out = 0; + wm8750_mask_update(s); + s->i2c_len = 0; +} + +static void wm8750_event(i2c_slave *i2c, enum i2c_event event) +{ + struct wm8750_s *s = (struct wm8750_s *) i2c; + + switch (event) { + case I2C_START_SEND: + s->i2c_len = 0; + break; + case I2C_FINISH: +#ifdef VERBOSE + if (s->i2c_len < 2) + printf("%s: message too short (%i bytes)\n", + __FUNCTION__, s->i2c_len); +#endif + break; + default: + break; + } +} + +#define WM8750_LINVOL 0x00 +#define WM8750_RINVOL 0x01 +#define WM8750_LOUT1V 0x02 +#define WM8750_ROUT1V 0x03 +#define WM8750_ADCDAC 0x05 +#define WM8750_IFACE 0x07 +#define WM8750_SRATE 0x08 +#define WM8750_LDAC 0x0a +#define WM8750_RDAC 0x0b +#define WM8750_BASS 0x0c +#define WM8750_TREBLE 0x0d +#define WM8750_RESET 0x0f +#define WM8750_3D 0x10 +#define WM8750_ALC1 0x11 +#define WM8750_ALC2 0x12 +#define WM8750_ALC3 0x13 +#define WM8750_NGATE 0x14 +#define WM8750_LADC 0x15 +#define WM8750_RADC 0x16 +#define WM8750_ADCTL1 0x17 +#define WM8750_ADCTL2 0x18 +#define WM8750_PWR1 0x19 +#define WM8750_PWR2 0x1a +#define WM8750_ADCTL3 0x1b +#define WM8750_ADCIN 0x1f +#define WM8750_LADCIN 0x20 +#define WM8750_RADCIN 0x21 +#define WM8750_LOUTM1 0x22 +#define WM8750_LOUTM2 0x23 +#define WM8750_ROUTM1 0x24 +#define WM8750_ROUTM2 0x25 +#define WM8750_MOUTM1 0x26 +#define WM8750_MOUTM2 0x27 +#define WM8750_LOUT2V 0x28 +#define WM8750_ROUT2V 0x29 +#define WM8750_MOUTV 0x2a + +static int wm8750_tx(i2c_slave *i2c, uint8_t data) +{ + struct wm8750_s *s = (struct wm8750_s *) i2c; + uint8_t cmd; + uint16_t value; + + if (s->i2c_len >= 2) { + printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len); +#ifdef VERBOSE + return 1; +#endif + } + s->i2c_data[s->i2c_len ++] = data; + if (s->i2c_len != 2) + return 0; + + cmd = s->i2c_data[0] >> 1; + value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff; + + switch (cmd) { + case WM8750_LADCIN: /* ADC Signal Path Control (Left) */ + s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */ + if (s->diff[0]) + s->in[0] = &s->adc_voice[0 + s->ds * 1]; + else + s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0]; + break; + + case WM8750_RADCIN: /* ADC Signal Path Control (Right) */ + s->diff[1] = (((value >> 6) & 3) == 3); /* RINSEL */ + if (s->diff[1]) + s->in[1] = &s->adc_voice[0 + s->ds * 1]; + else + s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0]; + break; + + case WM8750_ADCIN: /* ADC Input Mode */ + s->ds = (value >> 8) & 1; /* DS */ + if (s->diff[0]) + s->in[0] = &s->adc_voice[0 + s->ds * 1]; + if (s->diff[1]) + s->in[1] = &s->adc_voice[0 + s->ds * 1]; + s->monomix[0] = (value >> 6) & 3; /* MONOMIX */ + break; + + case WM8750_ADCTL1: /* Additional Control (1) */ + s->monomix[1] = (value >> 1) & 1; /* DMONOMIX */ + break; + + case WM8750_PWR1: /* Power Management (1) */ + s->enable = ((value >> 6) & 7) == 3; /* VMIDSEL, VREF */ + wm8750_set_format(s); + break; + + case WM8750_LINVOL: /* Left Channel PGA */ + s->invol[0] = value & 0x3f; /* LINVOL */ + s->inmute[0] = (value >> 7) & 1; /* LINMUTE */ + wm8750_mask_update(s); + break; + + case WM8750_RINVOL: /* Right Channel PGA */ + s->invol[1] = value & 0x3f; /* RINVOL */ + s->inmute[1] = (value >> 7) & 1; /* RINMUTE */ + wm8750_mask_update(s); + break; + + case WM8750_ADCDAC: /* ADC and DAC Control */ + s->pol = (value >> 5) & 3; /* ADCPOL */ + s->mute = (value >> 3) & 1; /* DACMU */ + wm8750_mask_update(s); + break; + + case WM8750_ADCTL3: /* Additional Control (3) */ + break; + + case WM8750_LADC: /* Left ADC Digital Volume */ + s->invol[2] = value & 0xff; /* LADCVOL */ + break; + + case WM8750_RADC: /* Right ADC Digital Volume */ + s->invol[3] = value & 0xff; /* RADCVOL */ + break; + + case WM8750_ALC1: /* ALC Control (1) */ + s->alc = (value >> 7) & 3; /* ALCSEL */ + break; + + case WM8750_NGATE: /* Noise Gate Control */ + case WM8750_3D: /* 3D enhance */ + break; + + case WM8750_LDAC: /* Left Channel Digital Volume */ + s->outvol[0] = value & 0xff; /* LDACVOL */ + break; + + case WM8750_RDAC: /* Right Channel Digital Volume */ + s->outvol[1] = value & 0xff; /* RDACVOL */ + break; + + case WM8750_BASS: /* Bass Control */ + break; + + case WM8750_LOUTM1: /* Left Mixer Control (1) */ + s->path[0] = (value >> 8) & 1; /* LD2LO */ + break; + + case WM8750_LOUTM2: /* Left Mixer Control (2) */ + s->path[1] = (value >> 8) & 1; /* RD2LO */ + break; + + case WM8750_ROUTM1: /* Right Mixer Control (1) */ + s->path[2] = (value >> 8) & 1; /* LD2RO */ + break; + + case WM8750_ROUTM2: /* Right Mixer Control (2) */ + s->path[3] = (value >> 8) & 1; /* RD2RO */ + break; + + case WM8750_MOUTM1: /* Mono Mixer Control (1) */ + s->mpath[0] = (value >> 8) & 1; /* LD2MO */ + break; + + case WM8750_MOUTM2: /* Mono Mixer Control (2) */ + s->mpath[1] = (value >> 8) & 1; /* RD2MO */ + break; + + case WM8750_LOUT1V: /* LOUT1 Volume */ + s->outvol[2] = value & 0x7f; /* LOUT2VOL */ + break; + + case WM8750_LOUT2V: /* LOUT2 Volume */ + s->outvol[4] = value & 0x7f; /* LOUT2VOL */ + break; + + case WM8750_ROUT1V: /* ROUT1 Volume */ + s->outvol[3] = value & 0x7f; /* ROUT2VOL */ + break; + + case WM8750_ROUT2V: /* ROUT2 Volume */ + s->outvol[5] = value & 0x7f; /* ROUT2VOL */ + break; + + case WM8750_MOUTV: /* MONOOUT Volume */ + s->outvol[6] = value & 0x7f; /* MONOOUTVOL */ + break; + + case WM8750_ADCTL2: /* Additional Control (2) */ + break; + + case WM8750_PWR2: /* Power Management (2) */ + s->power = value & 0x7e; + break; + + case WM8750_IFACE: /* Digital Audio Interface Format */ +#ifdef VERBOSE + if (value & 0x40) /* MS */ + printf("%s: attempt to enable Master Mode\n", __FUNCTION__); +#endif + s->format = value; + wm8750_set_format(s); + break; + + case WM8750_SRATE: /* Clocking and Sample Rate Control */ + s->rate = &wm_rate_table[(value >> 1) & 0x1f]; + wm8750_set_format(s); + break; + + case WM8750_RESET: /* Reset */ + wm8750_reset(&s->i2c); + break; + +#ifdef VERBOSE + default: + printf("%s: unknown register %02x\n", __FUNCTION__, cmd); +#endif + } + + return 0; +} + +static int wm8750_rx(i2c_slave *i2c) +{ + return 0x00; +} + +i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio) +{ + struct wm8750_s *s = (struct wm8750_s *) + i2c_slave_init(bus, 0, sizeof(struct wm8750_s)); + s->i2c.event = wm8750_event; + s->i2c.recv = wm8750_rx; + s->i2c.send = wm8750_tx; + + AUD_register_card(audio, CODEC, &s->card); + wm8750_reset(&s->i2c); + + return &s->i2c; +} + +void wm8750_fini(i2c_slave *i2c) +{ + struct wm8750_s *s = (struct wm8750_s *) i2c; + wm8750_reset(&s->i2c); + AUD_remove_card(&s->card); + qemu_free(s); +} + +void wm8750_data_req_set(i2c_slave *i2c, + void (*data_req)(void *, int, int), void *opaque) +{ + struct wm8750_s *s = (struct wm8750_s *) i2c; + s->data_req = data_req; + s->opaque = opaque; +} + +void wm8750_dac_dat(void *opaque, uint32_t sample) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + uint32_t *data = (uint32_t *) &s->data_out[s->idx_out]; + *data = sample & s->outmask; + s->req_out -= 4; + s->idx_out += 4; + if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0) + wm8750_out_flush(s); +} + +uint32_t wm8750_adc_dat(void *opaque) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + uint32_t *data; + if (s->idx_in >= sizeof(s->data_in)) + wm8750_in_load(s); + data = (uint32_t *) &s->data_in[s->idx_in]; + s->req_in -= 4; + s->idx_in += 4; + return *data & s->inmask; +} -- cgit v1.2.3 From 7ec47eadc7048435b54bc53ccb41307851098409 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 23 May 2007 22:07:36 +0000 Subject: Speed up m68k by 20%. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2855 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/op.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target-m68k/op.c b/target-m68k/op.c index ad6f403f5..6134bb018 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -48,23 +48,23 @@ static long qreg_offsets[] = { uint32_t get_op(int qreg) { - if (qreg == QREG_T0) { + if (qreg >= TARGET_NUM_QREGS) { + return env->qregs[qreg - TARGET_NUM_QREGS]; + } else if (qreg == QREG_T0) { return T0; - } else if (qreg < TARGET_NUM_QREGS) { - return *(uint32_t *)(((long)env) + qreg_offsets[qreg]); } else { - return env->qregs[qreg - TARGET_NUM_QREGS]; + return *(uint32_t *)(((long)env) + qreg_offsets[qreg]); } } void set_op(int qreg, uint32_t val) { - if (qreg == QREG_T0) { + if (qreg >= TARGET_NUM_QREGS) { + env->qregs[qreg - TARGET_NUM_QREGS] = val; + } else if (qreg == QREG_T0) { T0 = val; - } else if (qreg < TARGET_NUM_QREGS) { - *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val; } else { - env->qregs[qreg - TARGET_NUM_QREGS] = val; + *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val; } } -- cgit v1.2.3 From 3f6c925f37cd8a1dddb8a8fbbcef4630ea347775 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 23 May 2007 22:21:27 +0000 Subject: Use i2c_slave_init() to allocate the PXA (dummy) I2C slave. Hush the warning: hw/pc.c:402: warning: control reaches end of non-void function git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2856 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 2 +- hw/pxa2xx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index a698ba546..388d65729 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -347,7 +347,7 @@ void bochs_bios_init(void) /* Generate an initial boot sector which sets state and jump to a specified vector */ -static int generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) +static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) { uint8_t bootsect[512], *p; int i; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 913c0bd76..03f4b4731 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1294,7 +1294,7 @@ struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, { int iomemtype; struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) - qemu_mallocz(sizeof(struct pxa2xx_i2c_s)); + i2c_slave_init(i2c_init_bus(), 0, sizeof(struct pxa2xx_i2c_s)); s->base = base; s->irq = irq; -- cgit v1.2.3 From aa941b944500bf77f0bdbfa0a7112b4e89670ff1 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 24 May 2007 18:50:09 +0000 Subject: Savevm/loadvm bits for ARM core, the PXA2xx peripherals and Spitz hardware. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2857 c046a42c-6fe2-441c-8c8c-71466251a162 --- ecc.h | 17 +++ hw/ads7846.c | 37 ++++++- hw/i2c.c | 31 ++++++ hw/i2c.h | 4 + hw/ide.c | 157 ++++++++++++++++++--------- hw/max111x.c | 37 +++++++ hw/max7310.c | 38 +++++++ hw/nand.c | 47 ++++++++ hw/pxa2xx.c | 315 +++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/pxa2xx_dma.c | 57 ++++++++++ hw/pxa2xx_gpio.c | 48 +++++++++ hw/pxa2xx_lcd.c | 79 ++++++++++++++ hw/pxa2xx_mmci.c | 81 ++++++++++++++ hw/pxa2xx_pic.c | 37 +++++++ hw/pxa2xx_timer.c | 71 ++++++++++++ hw/spitz.c | 115 ++++++++++++++++++++ hw/wm8750.c | 89 +++++++++++++++ vl.c | 133 ++++++++++++++++++++++- 18 files changed, 1330 insertions(+), 63 deletions(-) diff --git a/ecc.h b/ecc.h index 11e6d0113..e8e39426f 100644 --- a/ecc.h +++ b/ecc.h @@ -75,3 +75,20 @@ static inline void ecc_reset(struct ecc_state_s *s) s->cp = 0x00; s->count = 0; } + +/* Save/restore */ +static inline void ecc_put(QEMUFile *f, struct ecc_state_s *s) +{ + qemu_put_8s(f, &s->cp); + qemu_put_be16s(f, &s->lp[0]); + qemu_put_be16s(f, &s->lp[1]); + qemu_put_be16s(f, &s->count); +} + +static inline void ecc_get(QEMUFile *f, struct ecc_state_s *s) +{ + qemu_get_8s(f, &s->cp); + qemu_get_be16s(f, &s->lp[0]); + qemu_get_be16s(f, &s->lp[1]); + qemu_get_be16s(f, &s->count); +} diff --git a/hw/ads7846.c b/hw/ads7846.c index d63a91541..8eeb143b1 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -104,10 +104,41 @@ static void ads7846_ts_event(void *opaque, if (s->pressure == !buttons_state) { s->pressure = !!buttons_state; - ads7846_int_update(s); + ads7846_int_update(s); } } +static void ads7846_save(QEMUFile *f, void *opaque) +{ + struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; + int i; + + for (i = 0; i < 8; i ++) + qemu_put_be32(f, s->input[i]); + qemu_put_be32(f, s->noise); + qemu_put_be32(f, s->cycle); + qemu_put_be32(f, s->output); +} + +static int ads7846_load(QEMUFile *f, void *opaque, int version_id) +{ + struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; + int i; + + for (i = 0; i < 8; i ++) + s->input[i] = qemu_get_be32(f); + s->noise = qemu_get_be32(f); + s->cycle = qemu_get_be32(f); + s->output = qemu_get_be32(f); + + s->pressure = 0; + ads7846_int_update(s); + + return 0; +} + +static int ads7846_iid = 0; + struct ads7846_state_s *ads7846_init(qemu_irq penirq) { struct ads7846_state_s *s; @@ -127,5 +158,9 @@ struct ads7846_state_s *ads7846_init(qemu_irq penirq) "QEMU ADS7846-driven Touchscreen"); ads7846_int_update(s); + + register_savevm("ads7846", ads7846_iid ++, 0, + ads7846_save, ads7846_load, s); + return s; } diff --git a/hw/i2c.c b/hw/i2c.c index 5d9319da4..3fc073332 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -115,3 +115,34 @@ void i2c_nack(i2c_bus *bus) dev->event(dev, I2C_NACK); } +void i2c_bus_save(QEMUFile *f, i2c_bus *bus) +{ + qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : 0x00); +} + +void i2c_bus_load(QEMUFile *f, i2c_bus *bus) +{ + i2c_slave *dev; + uint8_t address = qemu_get_byte(f); + + if (address) { + for (dev = bus->dev; dev; dev = dev->next) + if (dev->address == address) { + bus->current_dev = dev; + return; + } + + fprintf(stderr, "%s: I2C slave with address %02x disappeared\n", + __FUNCTION__, address); + } +} + +void i2c_slave_save(QEMUFile *f, i2c_slave *dev) +{ + qemu_put_byte(f, dev->address); +} + +void i2c_slave_load(QEMUFile *f, i2c_slave *dev) +{ + dev->address = qemu_get_byte(f); +} diff --git a/hw/i2c.h b/hw/i2c.h index dec45e552..17e52e7e8 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -45,6 +45,10 @@ void i2c_end_transfer(i2c_bus *bus); void i2c_nack(i2c_bus *bus); int i2c_send(i2c_bus *bus, uint8_t data); int i2c_recv(i2c_bus *bus); +void i2c_bus_save(QEMUFile *f, i2c_bus *bus); +void i2c_bus_load(QEMUFile *f, i2c_bus *bus); +void i2c_slave_save(QEMUFile *f, i2c_slave *dev); +void i2c_slave_load(QEMUFile *f, i2c_slave *dev); /* max7310.c */ i2c_slave *max7310_init(i2c_bus *bus); diff --git a/hw/ide.c b/hw/ide.c index a1aebc994..03875ce9a 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2416,6 +2416,62 @@ static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2) register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state); } +/* save per IDE drive data */ +static void ide_save(QEMUFile* f, IDEState *s) +{ + qemu_put_be32s(f, &s->mult_sectors); + qemu_put_be32s(f, &s->identify_set); + if (s->identify_set) { + qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512); + } + qemu_put_8s(f, &s->feature); + qemu_put_8s(f, &s->error); + qemu_put_be32s(f, &s->nsector); + qemu_put_8s(f, &s->sector); + qemu_put_8s(f, &s->lcyl); + qemu_put_8s(f, &s->hcyl); + qemu_put_8s(f, &s->hob_feature); + qemu_put_8s(f, &s->hob_nsector); + qemu_put_8s(f, &s->hob_sector); + qemu_put_8s(f, &s->hob_lcyl); + qemu_put_8s(f, &s->hob_hcyl); + qemu_put_8s(f, &s->select); + qemu_put_8s(f, &s->status); + qemu_put_8s(f, &s->lba48); + + qemu_put_8s(f, &s->sense_key); + qemu_put_8s(f, &s->asc); + /* XXX: if a transfer is pending, we do not save it yet */ +} + +/* load per IDE drive data */ +static void ide_load(QEMUFile* f, IDEState *s) +{ + qemu_get_be32s(f, &s->mult_sectors); + qemu_get_be32s(f, &s->identify_set); + if (s->identify_set) { + qemu_get_buffer(f, (uint8_t *)s->identify_data, 512); + } + qemu_get_8s(f, &s->feature); + qemu_get_8s(f, &s->error); + qemu_get_be32s(f, &s->nsector); + qemu_get_8s(f, &s->sector); + qemu_get_8s(f, &s->lcyl); + qemu_get_8s(f, &s->hcyl); + qemu_get_8s(f, &s->hob_feature); + qemu_get_8s(f, &s->hob_nsector); + qemu_get_8s(f, &s->hob_sector); + qemu_get_8s(f, &s->hob_lcyl); + qemu_get_8s(f, &s->hob_hcyl); + qemu_get_8s(f, &s->select); + qemu_get_8s(f, &s->status); + qemu_get_8s(f, &s->lba48); + + qemu_get_8s(f, &s->sense_key); + qemu_get_8s(f, &s->asc); + /* XXX: if a transfer is pending, we do not save it yet */ +} + /***********************************************************/ /* ISA IDE definitions */ @@ -2731,30 +2787,7 @@ static void pci_ide_save(QEMUFile* f, void *opaque) /* per IDE drive data */ for(i = 0; i < 4; i++) { - IDEState *s = &d->ide_if[i]; - qemu_put_be32s(f, &s->mult_sectors); - qemu_put_be32s(f, &s->identify_set); - if (s->identify_set) { - qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512); - } - qemu_put_8s(f, &s->feature); - qemu_put_8s(f, &s->error); - qemu_put_be32s(f, &s->nsector); - qemu_put_8s(f, &s->sector); - qemu_put_8s(f, &s->lcyl); - qemu_put_8s(f, &s->hcyl); - qemu_put_8s(f, &s->hob_feature); - qemu_put_8s(f, &s->hob_nsector); - qemu_put_8s(f, &s->hob_sector); - qemu_put_8s(f, &s->hob_lcyl); - qemu_put_8s(f, &s->hob_hcyl); - qemu_put_8s(f, &s->select); - qemu_put_8s(f, &s->status); - qemu_put_8s(f, &s->lba48); - - qemu_put_8s(f, &s->sense_key); - qemu_put_8s(f, &s->asc); - /* XXX: if a transfer is pending, we do not save it yet */ + ide_save(f, &d->ide_if[i]); } } @@ -2788,30 +2821,7 @@ static int pci_ide_load(QEMUFile* f, void *opaque, int version_id) /* per IDE drive data */ for(i = 0; i < 4; i++) { - IDEState *s = &d->ide_if[i]; - qemu_get_be32s(f, &s->mult_sectors); - qemu_get_be32s(f, &s->identify_set); - if (s->identify_set) { - qemu_get_buffer(f, (uint8_t *)s->identify_data, 512); - } - qemu_get_8s(f, &s->feature); - qemu_get_8s(f, &s->error); - qemu_get_be32s(f, &s->nsector); - qemu_get_8s(f, &s->sector); - qemu_get_8s(f, &s->lcyl); - qemu_get_8s(f, &s->hcyl); - qemu_get_8s(f, &s->hob_feature); - qemu_get_8s(f, &s->hob_nsector); - qemu_get_8s(f, &s->hob_sector); - qemu_get_8s(f, &s->hob_lcyl); - qemu_get_8s(f, &s->hob_hcyl); - qemu_get_8s(f, &s->select); - qemu_get_8s(f, &s->status); - qemu_get_8s(f, &s->lba48); - - qemu_get_8s(f, &s->sense_key); - qemu_get_8s(f, &s->asc); - /* XXX: if a transfer is pending, we do not save it yet */ + ide_load(f, &d->ide_if[i]); } return 0; } @@ -3255,6 +3265,54 @@ static void md_common_write(void *opaque, uint32_t at, uint16_t value) } } +static void md_save(QEMUFile *f, void *opaque) +{ + struct md_s *s = (struct md_s *) opaque; + int i; + uint8_t drive1_selected; + + qemu_put_8s(f, &s->opt); + qemu_put_8s(f, &s->stat); + qemu_put_8s(f, &s->pins); + + qemu_put_8s(f, &s->ctrl); + qemu_put_be16s(f, &s->io); + qemu_put_byte(f, s->cycle); + + drive1_selected = (s->ide->cur_drive != s->ide); + qemu_put_8s(f, &s->ide->cmd); + qemu_put_8s(f, &drive1_selected); + + for (i = 0; i < 2; i ++) + ide_save(f, &s->ide[i]); +} + +static int md_load(QEMUFile *f, void *opaque, int version_id) +{ + struct md_s *s = (struct md_s *) opaque; + int i; + uint8_t drive1_selected; + + qemu_get_8s(f, &s->opt); + qemu_get_8s(f, &s->stat); + qemu_get_8s(f, &s->pins); + + qemu_get_8s(f, &s->ctrl); + qemu_get_be16s(f, &s->io); + s->cycle = qemu_get_byte(f); + + qemu_get_8s(f, &s->ide->cmd); + qemu_get_8s(f, &drive1_selected); + s->ide->cur_drive = &s->ide[(drive1_selected != 0)]; + + for (i = 0; i < 2; i ++) + ide_load(f, &s->ide[i]); + + return 0; +} + +static int md_iid = 0; + static const uint8_t dscm1xxxx_cis[0x14a] = { [0x000] = CISTPL_DEVICE, /* 5V Device Information */ [0x002] = 0x03, /* Tuple length = 4 bytes */ @@ -3480,5 +3538,8 @@ struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv) md->ide->is_cf = 1; md->ide->mdata_size = METADATA_SIZE; md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE); + + register_savevm("microdrive", md_iid ++, 0, md_save, md_load, md); + return &md->card; } diff --git a/hw/max111x.c b/hw/max111x.c index 69019de7a..8425bee57 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -89,6 +89,39 @@ void max111x_write(void *opaque, uint32_t value) qemu_irq_raise(s->interrupt); } +static void max111x_save(QEMUFile *f, void *opaque) +{ + struct max111x_s *s = (struct max111x_s *) opaque; + int i; + + qemu_put_8s(f, &s->tb1); + qemu_put_8s(f, &s->rb2); + qemu_put_8s(f, &s->rb3); + qemu_put_be32(f, s->inputs); + qemu_put_be32(f, s->com); + for (i = 0; i < s->inputs; i ++) + qemu_put_byte(f, s->input[i]); +} + +static int max111x_load(QEMUFile *f, void *opaque, int version_id) +{ + struct max111x_s *s = (struct max111x_s *) opaque; + int i; + + qemu_get_8s(f, &s->tb1); + qemu_get_8s(f, &s->rb2); + qemu_get_8s(f, &s->rb3); + if (s->inputs != qemu_get_be32(f)) + return -EINVAL; + s->com = qemu_get_be32(f); + for (i = 0; i < s->inputs; i ++) + s->input[i] = qemu_get_byte(f); + + return 0; +} + +static int max111x_iid = 0; + static struct max111x_s *max111x_init(qemu_irq cb) { struct max111x_s *s; @@ -108,6 +141,10 @@ static struct max111x_s *max111x_init(qemu_irq cb) s->input[6] = 0x90; s->input[7] = 0x80; s->com = 0; + + register_savevm("max111x", max111x_iid ++, 0, + max111x_save, max111x_load, s); + return s; } diff --git a/hw/max7310.c b/hw/max7310.c index a4aaf17d2..6b180d9b6 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -143,6 +143,41 @@ static void max7310_event(i2c_slave *i2c, enum i2c_event event) } } +static void max7310_save(QEMUFile *f, void *opaque) +{ + struct max7310_s *s = (struct max7310_s *) opaque; + + qemu_put_be32(f, s->i2c_command_byte); + qemu_put_be32(f, s->len); + + qemu_put_8s(f, &s->level); + qemu_put_8s(f, &s->direction); + qemu_put_8s(f, &s->polarity); + qemu_put_8s(f, &s->status); + qemu_put_8s(f, &s->command); + + i2c_slave_save(f, &s->i2c); +} + +static int max7310_load(QEMUFile *f, void *opaque, int version_id) +{ + struct max7310_s *s = (struct max7310_s *) opaque; + + s->i2c_command_byte = qemu_get_be32(f); + s->len = qemu_get_be32(f); + + qemu_get_8s(f, &s->level); + qemu_get_8s(f, &s->direction); + qemu_get_8s(f, &s->polarity); + qemu_get_8s(f, &s->status); + qemu_get_8s(f, &s->command); + + i2c_slave_load(f, &s->i2c); + return 0; +} + +static int max7310_iid = 0; + static void max7310_gpio_set(void *opaque, int line, int level) { struct max7310_s *s = (struct max7310_s *) opaque; @@ -169,6 +204,9 @@ struct i2c_slave *max7310_init(i2c_bus *bus) max7310_reset(&s->i2c); + register_savevm("max7310", max7310_iid ++, 0, + max7310_save, max7310_load, s); + return &s->i2c; } diff --git a/hw/nand.c b/hw/nand.c index 5bce25052..8e39acd6e 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -273,6 +273,50 @@ static void nand_command(struct nand_flash_s *s) } } +static void nand_save(QEMUFile *f, void *opaque) +{ + struct nand_flash_s *s = (struct nand_flash_s *) opaque; + qemu_put_byte(f, s->cle); + qemu_put_byte(f, s->ale); + qemu_put_byte(f, s->ce); + qemu_put_byte(f, s->wp); + qemu_put_byte(f, s->gnd); + qemu_put_buffer(f, s->io, sizeof(s->io)); + qemu_put_be32(f, s->ioaddr - s->io); + qemu_put_be32(f, s->iolen); + + qemu_put_be32s(f, &s->cmd); + qemu_put_be32s(f, &s->addr); + qemu_put_be32(f, s->addrlen); + qemu_put_be32(f, s->status); + qemu_put_be32(f, s->offset); + /* XXX: do we want to save s->storage too? */ +} + +static int nand_load(QEMUFile *f, void *opaque, int version_id) +{ + struct nand_flash_s *s = (struct nand_flash_s *) opaque; + s->cle = qemu_get_byte(f); + s->ale = qemu_get_byte(f); + s->ce = qemu_get_byte(f); + s->wp = qemu_get_byte(f); + s->gnd = qemu_get_byte(f); + qemu_get_buffer(f, s->io, sizeof(s->io)); + s->ioaddr = s->io + qemu_get_be32(f); + s->iolen = qemu_get_be32(f); + if (s->ioaddr >= s->io + sizeof(s->io) || s->ioaddr < s->io) + return -EINVAL; + + qemu_get_be32s(f, &s->cmd); + qemu_get_be32s(f, &s->addr); + s->addrlen = qemu_get_be32(f); + s->status = qemu_get_be32(f); + s->offset = qemu_get_be32(f); + return 0; +} + +static int nand_iid = 0; + /* * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip * outputs are R/B and eight I/O pins. @@ -443,6 +487,9 @@ struct nand_flash_s *nand_init(int manf_id, int chip_id) if (pagesize) s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize), 0xff, s->pages * pagesize); + + register_savevm("nand", nand_iid ++, 0, nand_save, nand_load, s); + return s; } diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 03f4b4731..087acd0af 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -141,6 +141,26 @@ static CPUWriteMemoryFunc *pxa2xx_pm_writefn[] = { pxa2xx_pm_write, }; +static void pxa2xx_pm_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + int i; + + for (i = 0; i < 0x40; i ++) + qemu_put_be32s(f, &s->pm_regs[i]); +} + +static int pxa2xx_pm_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + int i; + + for (i = 0; i < 0x40; i ++) + qemu_get_be32s(f, &s->pm_regs[i]); + + return 0; +} + #define CCCR 0x00 /* Core Clock Configuration register */ #define CKEN 0x04 /* Clock Enable register */ #define OSCC 0x08 /* Oscillator Configuration register */ @@ -204,6 +224,30 @@ static CPUWriteMemoryFunc *pxa2xx_cm_writefn[] = { pxa2xx_cm_write, }; +static void pxa2xx_cm_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + int i; + + for (i = 0; i < 4; i ++) + qemu_put_be32s(f, &s->cm_regs[i]); + qemu_put_be32s(f, &s->clkcfg); + qemu_put_be32s(f, &s->pmnc); +} + +static int pxa2xx_cm_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + int i; + + for (i = 0; i < 4; i ++) + qemu_get_be32s(f, &s->cm_regs[i]); + qemu_get_be32s(f, &s->clkcfg); + qemu_get_be32s(f, &s->pmnc); + + return 0; +} + static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm) { struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; @@ -482,6 +526,26 @@ static CPUWriteMemoryFunc *pxa2xx_mm_writefn[] = { pxa2xx_mm_write, }; +static void pxa2xx_mm_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + int i; + + for (i = 0; i < 0x1a; i ++) + qemu_put_be32s(f, &s->mm_regs[i]); +} + +static int pxa2xx_mm_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + int i; + + for (i = 0; i < 0x1a; i ++) + qemu_get_be32s(f, &s->mm_regs[i]); + + return 0; +} + /* Synchronous Serial Ports */ struct pxa2xx_ssp_s { target_phys_addr_t base; @@ -761,6 +825,53 @@ static CPUWriteMemoryFunc *pxa2xx_ssp_writefn[] = { pxa2xx_ssp_write, }; +static void pxa2xx_ssp_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque; + int i; + + qemu_put_be32(f, s->enable); + + qemu_put_be32s(f, &s->sscr[0]); + qemu_put_be32s(f, &s->sscr[1]); + qemu_put_be32s(f, &s->sspsp); + qemu_put_be32s(f, &s->ssto); + qemu_put_be32s(f, &s->ssitr); + qemu_put_be32s(f, &s->sssr); + qemu_put_8s(f, &s->sstsa); + qemu_put_8s(f, &s->ssrsa); + qemu_put_8s(f, &s->ssacd); + + qemu_put_byte(f, s->rx_level); + for (i = 0; i < s->rx_level; i ++) + qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]); +} + +static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque; + int i; + + s->enable = qemu_get_be32(f); + + qemu_get_be32s(f, &s->sscr[0]); + qemu_get_be32s(f, &s->sscr[1]); + qemu_get_be32s(f, &s->sspsp); + qemu_get_be32s(f, &s->ssto); + qemu_get_be32s(f, &s->ssitr); + qemu_get_be32s(f, &s->sssr); + qemu_get_8s(f, &s->sstsa); + qemu_get_8s(f, &s->ssrsa); + qemu_get_8s(f, &s->ssacd); + + s->rx_level = qemu_get_byte(f); + s->rx_start = 0; + for (i = 0; i < s->rx_level; i ++) + s->rx_fifo[i] = qemu_get_byte(f); + + return 0; +} + /* Real-Time Clock */ #define RCNR 0x00 /* RTC Counter register */ #define RTAR 0x04 /* RTC Alarm register */ @@ -1052,7 +1163,19 @@ static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr, } } -static void pxa2xx_rtc_reset(struct pxa2xx_state_s *s) +static CPUReadMemoryFunc *pxa2xx_rtc_readfn[] = { + pxa2xx_rtc_read, + pxa2xx_rtc_read, + pxa2xx_rtc_read, +}; + +static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = { + pxa2xx_rtc_write, + pxa2xx_rtc_write, + pxa2xx_rtc_write, +}; + +static void pxa2xx_rtc_init(struct pxa2xx_state_s *s) { struct tm *tm; time_t ti; @@ -1086,17 +1209,61 @@ static void pxa2xx_rtc_reset(struct pxa2xx_state_s *s) s->rtc_pi = qemu_new_timer(rt_clock, pxa2xx_rtc_pi_tick, s); } -static CPUReadMemoryFunc *pxa2xx_rtc_readfn[] = { - pxa2xx_rtc_read, - pxa2xx_rtc_read, - pxa2xx_rtc_read, -}; +static void pxa2xx_rtc_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; -static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = { - pxa2xx_rtc_write, - pxa2xx_rtc_write, - pxa2xx_rtc_write, -}; + pxa2xx_rtc_hzupdate(s); + pxa2xx_rtc_piupdate(s); + pxa2xx_rtc_swupdate(s); + + qemu_put_be32s(f, &s->rttr); + qemu_put_be32s(f, &s->rtsr); + qemu_put_be32s(f, &s->rtar); + qemu_put_be32s(f, &s->rdar1); + qemu_put_be32s(f, &s->rdar2); + qemu_put_be32s(f, &s->ryar1); + qemu_put_be32s(f, &s->ryar2); + qemu_put_be32s(f, &s->swar1); + qemu_put_be32s(f, &s->swar2); + qemu_put_be32s(f, &s->piar); + qemu_put_be32s(f, &s->last_rcnr); + qemu_put_be32s(f, &s->last_rdcr); + qemu_put_be32s(f, &s->last_rycr); + qemu_put_be32s(f, &s->last_swcr); + qemu_put_be32s(f, &s->last_rtcpicr); + qemu_put_be64s(f, &s->last_hz); + qemu_put_be64s(f, &s->last_sw); + qemu_put_be64s(f, &s->last_pi); +} + +static int pxa2xx_rtc_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + + qemu_get_be32s(f, &s->rttr); + qemu_get_be32s(f, &s->rtsr); + qemu_get_be32s(f, &s->rtar); + qemu_get_be32s(f, &s->rdar1); + qemu_get_be32s(f, &s->rdar2); + qemu_get_be32s(f, &s->ryar1); + qemu_get_be32s(f, &s->ryar2); + qemu_get_be32s(f, &s->swar1); + qemu_get_be32s(f, &s->swar2); + qemu_get_be32s(f, &s->piar); + qemu_get_be32s(f, &s->last_rcnr); + qemu_get_be32s(f, &s->last_rdcr); + qemu_get_be32s(f, &s->last_rycr); + qemu_get_be32s(f, &s->last_swcr); + qemu_get_be32s(f, &s->last_rtcpicr); + qemu_get_be64s(f, &s->last_hz); + qemu_get_be64s(f, &s->last_sw); + qemu_get_be64s(f, &s->last_pi); + + pxa2xx_rtc_alarm_update(s, s->rtsr); + + return 0; +} /* I2C Interface */ struct pxa2xx_i2c_s { @@ -1289,6 +1456,33 @@ static CPUWriteMemoryFunc *pxa2xx_i2c_writefn[] = { pxa2xx_i2c_write, }; +static void pxa2xx_i2c_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque; + + qemu_put_be16s(f, &s->control); + qemu_put_be16s(f, &s->status); + qemu_put_8s(f, &s->ibmr); + qemu_put_8s(f, &s->data); + + i2c_bus_save(f, s->bus); + i2c_slave_save(f, &s->slave); +} + +static int pxa2xx_i2c_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque; + + qemu_get_be16s(f, &s->control); + qemu_get_be16s(f, &s->status); + qemu_get_8s(f, &s->ibmr); + qemu_get_8s(f, &s->data); + + i2c_bus_load(f, s->bus); + i2c_slave_load(f, &s->slave); + return 0; +} + struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, qemu_irq irq, int ioregister) { @@ -1309,6 +1503,9 @@ struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, cpu_register_physical_memory(s->base & 0xfffff000, 0xfff, iomemtype); } + register_savevm("pxa2xx_i2c", base, 0, + pxa2xx_i2c_save, pxa2xx_i2c_load, s); + return s; } @@ -1470,6 +1667,40 @@ static CPUWriteMemoryFunc *pxa2xx_i2s_writefn[] = { pxa2xx_i2s_write, }; +static void pxa2xx_i2s_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque; + + qemu_put_be32s(f, &s->control[0]); + qemu_put_be32s(f, &s->control[1]); + qemu_put_be32s(f, &s->status); + qemu_put_be32s(f, &s->mask); + qemu_put_be32s(f, &s->clk); + + qemu_put_be32(f, s->enable); + qemu_put_be32(f, s->rx_len); + qemu_put_be32(f, s->tx_len); + qemu_put_be32(f, s->fifo_len); +} + +static int pxa2xx_i2s_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque; + + qemu_get_be32s(f, &s->control[0]); + qemu_get_be32s(f, &s->control[1]); + qemu_get_be32s(f, &s->status); + qemu_get_be32s(f, &s->mask); + qemu_get_be32s(f, &s->clk); + + s->enable = qemu_get_be32(f); + s->rx_len = qemu_get_be32(f); + s->tx_len = qemu_get_be32(f); + s->fifo_len = qemu_get_be32(f); + + return 0; +} + static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) { struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque; @@ -1510,6 +1741,9 @@ static struct pxa2xx_i2s_s *pxa2xx_i2s_init(target_phys_addr_t base, pxa2xx_i2s_writefn, s); cpu_register_physical_memory(s->base & 0xfff00000, 0xfffff, iomemtype); + register_savevm("pxa2xx_i2s", base, 0, + pxa2xx_i2s_save, pxa2xx_i2s_load, s); + return s; } @@ -1712,6 +1946,45 @@ static void pxa2xx_fir_event(void *opaque, int event) { } +static void pxa2xx_fir_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque; + int i; + + qemu_put_be32(f, s->enable); + + qemu_put_8s(f, &s->control[0]); + qemu_put_8s(f, &s->control[1]); + qemu_put_8s(f, &s->control[2]); + qemu_put_8s(f, &s->status[0]); + qemu_put_8s(f, &s->status[1]); + + qemu_put_byte(f, s->rx_len); + for (i = 0; i < s->rx_len; i ++) + qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]); +} + +static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque; + int i; + + s->enable = qemu_get_be32(f); + + qemu_get_8s(f, &s->control[0]); + qemu_get_8s(f, &s->control[1]); + qemu_get_8s(f, &s->control[2]); + qemu_get_8s(f, &s->status[0]); + qemu_get_8s(f, &s->status[1]); + + s->rx_len = qemu_get_byte(f); + s->rx_start = 0; + for (i = 0; i < s->rx_len; i ++) + s->rx_fifo[i] = qemu_get_byte(f); + + return 0; +} + static struct pxa2xx_fir_s *pxa2xx_fir_init(target_phys_addr_t base, qemu_irq irq, struct pxa2xx_dma_state_s *dma, CharDriverState *chr) @@ -1735,6 +2008,8 @@ static struct pxa2xx_fir_s *pxa2xx_fir_init(target_phys_addr_t base, qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, pxa2xx_fir_rx, pxa2xx_fir_event, s); + register_savevm("pxa2xx_fir", 0, 0, pxa2xx_fir_save, pxa2xx_fir_load, s); + return s; } @@ -1763,6 +2038,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->env = cpu_init(); cpu_arm_set_model(s->env, revision ?: "pxa270"); + register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env); /* SDRAM & Internal Memory Storage */ cpu_register_physical_memory(PXA2XX_SDRAM_BASE, @@ -1800,6 +2076,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, pxa2xx_cm_writefn, s); cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype); + register_savevm("pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -1810,6 +2087,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn, pxa2xx_mm_writefn, s); cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype); + register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); for (i = 0; pxa27x_ssp[i].io_base; i ++); s->ssp = (struct pxa2xx_ssp_s **) @@ -1824,6 +2102,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn, pxa2xx_ssp_writefn, &ssp[i]); cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); + register_savevm("pxa2xx_ssp", i, 0, + pxa2xx_ssp_save, pxa2xx_ssp_load, s); } if (usb_enabled) { @@ -1837,7 +2117,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, pxa2xx_rtc_writefn, s); cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype); - pxa2xx_rtc_reset(s); + pxa2xx_rtc_init(s); + register_savevm("pxa2xx_rtc", 0, 0, pxa2xx_rtc_save, pxa2xx_rtc_load, s); /* Note that PM registers are in the same page with PWRI2C registers. * As a workaround we don't map PWRI2C into memory and we expect @@ -1849,6 +2130,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, pxa2xx_pm_writefn, s); cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype); + register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); @@ -1869,6 +2151,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->env = cpu_init(); cpu_arm_set_model(s->env, "pxa255"); + register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env); /* SDRAM & Internal Memory Storage */ cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size, @@ -1905,6 +2188,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, pxa2xx_cm_writefn, s); cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype); + register_savevm("pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -1915,6 +2199,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn, pxa2xx_mm_writefn, s); cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype); + register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); for (i = 0; pxa255_ssp[i].io_base; i ++); s->ssp = (struct pxa2xx_ssp_s **) @@ -1929,6 +2214,8 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn, pxa2xx_ssp_writefn, &ssp[i]); cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); + register_savevm("pxa2xx_ssp", i, 0, + pxa2xx_ssp_save, pxa2xx_ssp_load, s); } if (usb_enabled) { @@ -1942,7 +2229,8 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, pxa2xx_rtc_writefn, s); cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype); - pxa2xx_rtc_reset(s); + pxa2xx_rtc_init(s); + register_savevm("pxa2xx_rtc", 0, 0, pxa2xx_rtc_save, pxa2xx_rtc_load, s); /* Note that PM registers are in the same page with PWRI2C registers. * As a workaround we don't map PWRI2C into memory and we expect @@ -1954,6 +2242,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, pxa2xx_pm_writefn, s); cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype); + register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index d2ed62357..1a79c8d9a 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -430,6 +430,61 @@ static CPUWriteMemoryFunc *pxa2xx_dma_writefn[] = { pxa2xx_dma_write }; +static void pxa2xx_dma_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque; + int i; + + qemu_put_be32(f, s->channels); + + qemu_put_be32s(f, &s->stopintr); + qemu_put_be32s(f, &s->eorintr); + qemu_put_be32s(f, &s->rasintr); + qemu_put_be32s(f, &s->startintr); + qemu_put_be32s(f, &s->endintr); + qemu_put_be32s(f, &s->align); + qemu_put_be32s(f, &s->pio); + + qemu_put_buffer(f, s->req, PXA2XX_DMA_NUM_REQUESTS); + for (i = 0; i < s->channels; i ++) { + qemu_put_betl(f, s->chan[i].descr); + qemu_put_betl(f, s->chan[i].src); + qemu_put_betl(f, s->chan[i].dest); + qemu_put_be32s(f, &s->chan[i].cmd); + qemu_put_be32s(f, &s->chan[i].state); + qemu_put_be32(f, s->chan[i].request); + }; +} + +static int pxa2xx_dma_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque; + int i; + + if (qemu_get_be32(f) != s->channels) + return -EINVAL; + + qemu_get_be32s(f, &s->stopintr); + qemu_get_be32s(f, &s->eorintr); + qemu_get_be32s(f, &s->rasintr); + qemu_get_be32s(f, &s->startintr); + qemu_get_be32s(f, &s->endintr); + qemu_get_be32s(f, &s->align); + qemu_get_be32s(f, &s->pio); + + qemu_get_buffer(f, s->req, PXA2XX_DMA_NUM_REQUESTS); + for (i = 0; i < s->channels; i ++) { + s->chan[i].descr = qemu_get_betl(f); + s->chan[i].src = qemu_get_betl(f); + s->chan[i].dest = qemu_get_betl(f); + qemu_get_be32s(f, &s->chan[i].cmd); + qemu_get_be32s(f, &s->chan[i].state); + s->chan[i].request = qemu_get_be32(f); + }; + + return 0; +} + static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base, qemu_irq irq, int channels) { @@ -455,6 +510,8 @@ static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base, pxa2xx_dma_writefn, s); cpu_register_physical_memory(base, 0x0000ffff, iomemtype); + register_savevm("pxa2xx_dma", 0, 0, pxa2xx_dma_save, pxa2xx_dma_load, s); + return s; } diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index eab2e7225..0e32329ed 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -247,6 +247,51 @@ static CPUWriteMemoryFunc *pxa2xx_gpio_writefn[] = { pxa2xx_gpio_write }; +static void pxa2xx_gpio_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque; + int i; + + qemu_put_be32(f, s->lines); + + for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) { + qemu_put_be32s(f, &s->ilevel[i]); + qemu_put_be32s(f, &s->olevel[i]); + qemu_put_be32s(f, &s->dir[i]); + qemu_put_be32s(f, &s->rising[i]); + qemu_put_be32s(f, &s->falling[i]); + qemu_put_be32s(f, &s->status[i]); + qemu_put_be32s(f, &s->gafr[i * 2 + 0]); + qemu_put_be32s(f, &s->gafr[i * 2 + 1]); + + qemu_put_be32s(f, &s->prev_level[i]); + } +} + +static int pxa2xx_gpio_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque; + int i; + + if (qemu_get_be32(f) != s->lines) + return -EINVAL; + + for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) { + qemu_get_be32s(f, &s->ilevel[i]); + qemu_get_be32s(f, &s->olevel[i]); + qemu_get_be32s(f, &s->dir[i]); + qemu_get_be32s(f, &s->rising[i]); + qemu_get_be32s(f, &s->falling[i]); + qemu_get_be32s(f, &s->status[i]); + qemu_get_be32s(f, &s->gafr[i * 2 + 0]); + qemu_get_be32s(f, &s->gafr[i * 2 + 1]); + + qemu_get_be32s(f, &s->prev_level[i]); + } + + return 0; +} + struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, CPUState *env, qemu_irq *pic, int lines) { @@ -265,6 +310,9 @@ struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, pxa2xx_gpio_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); + register_savevm("pxa2xx_gpio", 0, 0, + pxa2xx_gpio_save, pxa2xx_gpio_load, s); + return s; } diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index f8ddbb4a4..232effdb1 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -924,6 +924,81 @@ void pxa2xx_lcdc_orientation(void *opaque, int angle) pxa2xx_lcdc_resize(s); } +static void pxa2xx_lcdc_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; + int i; + + qemu_put_be32(f, s->irqlevel); + qemu_put_be32(f, s->transp); + + for (i = 0; i < 6; i ++) + qemu_put_be32s(f, &s->control[i]); + for (i = 0; i < 2; i ++) + qemu_put_be32s(f, &s->status[i]); + for (i = 0; i < 2; i ++) + qemu_put_be32s(f, &s->ovl1c[i]); + for (i = 0; i < 2; i ++) + qemu_put_be32s(f, &s->ovl2c[i]); + qemu_put_be32s(f, &s->ccr); + qemu_put_be32s(f, &s->cmdcr); + qemu_put_be32s(f, &s->trgbr); + qemu_put_be32s(f, &s->tcr); + qemu_put_be32s(f, &s->liidr); + qemu_put_8s(f, &s->bscntr); + + for (i = 0; i < 7; i ++) { + qemu_put_betl(f, s->dma_ch[i].branch); + qemu_put_byte(f, s->dma_ch[i].up); + qemu_put_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer)); + + qemu_put_betl(f, s->dma_ch[i].descriptor); + qemu_put_betl(f, s->dma_ch[i].source); + qemu_put_be32s(f, &s->dma_ch[i].id); + qemu_put_be32s(f, &s->dma_ch[i].command); + } +} + +static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; + int i; + + s->irqlevel = qemu_get_be32(f); + s->transp = qemu_get_be32(f); + + for (i = 0; i < 6; i ++) + qemu_get_be32s(f, &s->control[i]); + for (i = 0; i < 2; i ++) + qemu_get_be32s(f, &s->status[i]); + for (i = 0; i < 2; i ++) + qemu_get_be32s(f, &s->ovl1c[i]); + for (i = 0; i < 2; i ++) + qemu_get_be32s(f, &s->ovl2c[i]); + qemu_get_be32s(f, &s->ccr); + qemu_get_be32s(f, &s->cmdcr); + qemu_get_be32s(f, &s->trgbr); + qemu_get_be32s(f, &s->tcr); + qemu_get_be32s(f, &s->liidr); + qemu_get_8s(f, &s->bscntr); + + for (i = 0; i < 7; i ++) { + s->dma_ch[i].branch = qemu_get_betl(f); + s->dma_ch[i].up = qemu_get_byte(f); + qemu_get_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer)); + + s->dma_ch[i].descriptor = qemu_get_betl(f); + s->dma_ch[i].source = qemu_get_betl(f); + qemu_get_be32s(f, &s->dma_ch[i].id); + qemu_get_be32s(f, &s->dma_ch[i].command); + } + + s->bpp = LCCR3_BPP(s->control[3]); + s->xres = s->yres = s->pal_for = -1; + + return 0; +} + #define BITS 8 #include "pxa2xx_template.h" #define BITS 15 @@ -989,6 +1064,10 @@ struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__); exit(1); } + + register_savevm("pxa2xx_lcdc", 0, 0, + pxa2xx_lcdc_save, pxa2xx_lcdc_load, s); + return s; } diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 7515ab887..2081b54db 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -443,6 +443,84 @@ static CPUWriteMemoryFunc *pxa2xx_mmci_writefn[] = { pxa2xx_mmci_writew }; +static void pxa2xx_mmci_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + int i; + + qemu_put_be32s(f, &s->status); + qemu_put_be32s(f, &s->clkrt); + qemu_put_be32s(f, &s->spi); + qemu_put_be32s(f, &s->cmdat); + qemu_put_be32s(f, &s->resp_tout); + qemu_put_be32s(f, &s->read_tout); + qemu_put_be32(f, s->blklen); + qemu_put_be32(f, s->numblk); + qemu_put_be32s(f, &s->intmask); + qemu_put_be32s(f, &s->intreq); + qemu_put_be32(f, s->cmd); + qemu_put_be32s(f, &s->arg); + qemu_put_be32(f, s->cmdreq); + qemu_put_be32(f, s->active); + qemu_put_be32(f, s->bytesleft); + + qemu_put_byte(f, s->tx_len); + for (i = 0; i < s->tx_len; i ++) + qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]); + + qemu_put_byte(f, s->rx_len); + for (i = 0; i < s->rx_len; i ++) + qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]); + + qemu_put_byte(f, s->resp_len); + for (i = s->resp_len; i < 9; i ++) + qemu_put_be16s(f, &s->resp_fifo[i]); +} + +static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque; + int i; + + qemu_get_be32s(f, &s->status); + qemu_get_be32s(f, &s->clkrt); + qemu_get_be32s(f, &s->spi); + qemu_get_be32s(f, &s->cmdat); + qemu_get_be32s(f, &s->resp_tout); + qemu_get_be32s(f, &s->read_tout); + s->blklen = qemu_get_be32(f); + s->numblk = qemu_get_be32(f); + qemu_get_be32s(f, &s->intmask); + qemu_get_be32s(f, &s->intreq); + s->cmd = qemu_get_be32(f); + qemu_get_be32s(f, &s->arg); + s->cmdreq = qemu_get_be32(f); + s->active = qemu_get_be32(f); + s->bytesleft = qemu_get_be32(f); + + s->tx_len = qemu_get_byte(f); + s->tx_start = 0; + if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0) + return -EINVAL; + for (i = 0; i < s->tx_len; i ++) + s->tx_fifo[i] = qemu_get_byte(f); + + s->rx_len = qemu_get_byte(f); + s->rx_start = 0; + if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0) + return -EINVAL; + for (i = 0; i < s->rx_len; i ++) + s->rx_fifo[i] = qemu_get_byte(f); + + s->resp_len = qemu_get_byte(f); + if (s->resp_len > 9 || s->resp_len < 0) + return -EINVAL; + for (i = s->resp_len; i < 9; i ++) + qemu_get_be16s(f, &s->resp_fifo[i]); + + return 0; +} + struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, qemu_irq irq, void *dma) { @@ -461,6 +539,9 @@ struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, /* Instantiate the actual storage */ s->card = sd_init(sd_bdrv); + register_savevm("pxa2xx_mmci", 0, 0, + pxa2xx_mmci_save, pxa2xx_mmci_load, s); + return s; } diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index e3cf24178..77e0b6cef 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -245,6 +245,41 @@ static CPUWriteMemoryFunc *pxa2xx_pic_writefn[] = { pxa2xx_pic_mem_write, }; +static void pxa2xx_pic_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; + int i; + + for (i = 0; i < 2; i ++) + qemu_put_be32s(f, &s->int_enabled[i]); + for (i = 0; i < 2; i ++) + qemu_put_be32s(f, &s->int_pending[i]); + for (i = 0; i < 2; i ++) + qemu_put_be32s(f, &s->is_fiq[i]); + qemu_put_be32s(f, &s->int_idle); + for (i = 0; i < PXA2XX_PIC_SRCS; i ++) + qemu_put_be32s(f, &s->priority[i]); +} + +static int pxa2xx_pic_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; + int i; + + for (i = 0; i < 2; i ++) + qemu_get_be32s(f, &s->int_enabled[i]); + for (i = 0; i < 2; i ++) + qemu_get_be32s(f, &s->int_pending[i]); + for (i = 0; i < 2; i ++) + qemu_get_be32s(f, &s->is_fiq[i]); + qemu_get_be32s(f, &s->int_idle); + for (i = 0; i < PXA2XX_PIC_SRCS; i ++) + qemu_get_be32s(f, &s->priority[i]); + + pxa2xx_pic_update(opaque); + return 0; +} + qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env) { struct pxa2xx_pic_state_s *s; @@ -276,5 +311,7 @@ qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env) /* Enable IC coprocessor access. */ cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s); + register_savevm("pxa2xx_pic", 0, 0, pxa2xx_pic_save, pxa2xx_pic_load, s); + return qi; } diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 073806a64..284f53040 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -364,6 +364,73 @@ static void pxa2xx_timer_tick4(void *opaque) pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4); } +static void pxa2xx_timer_save(QEMUFile *f, void *opaque) +{ + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; + int i; + + qemu_put_be32s(f, &s->clock); + qemu_put_be32s(f, &s->oldclock); + qemu_put_be64s(f, &s->lastload); + + for (i = 0; i < 4; i ++) { + qemu_put_be32s(f, &s->timer[i].value); + qemu_put_be32(f, s->timer[i].level); + } + if (s->tm4) + for (i = 0; i < 8; i ++) { + qemu_put_be32s(f, &s->tm4[i].tm.value); + qemu_put_be32(f, s->tm4[i].tm.level); + qemu_put_be32s(f, &s->tm4[i].oldclock); + qemu_put_be32s(f, &s->tm4[i].clock); + qemu_put_be64s(f, &s->tm4[i].lastload); + qemu_put_be32s(f, &s->tm4[i].freq); + qemu_put_be32s(f, &s->tm4[i].control); + } + + qemu_put_be32s(f, &s->events); + qemu_put_be32s(f, &s->irq_enabled); + qemu_put_be32s(f, &s->reset3); + qemu_put_be32s(f, &s->snapshot); +} + +static int pxa2xx_timer_load(QEMUFile *f, void *opaque, int version_id) +{ + pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque; + int64_t now; + int i; + + qemu_get_be32s(f, &s->clock); + qemu_get_be32s(f, &s->oldclock); + qemu_get_be64s(f, &s->lastload); + + now = qemu_get_clock(vm_clock); + for (i = 0; i < 4; i ++) { + qemu_get_be32s(f, &s->timer[i].value); + s->timer[i].level = qemu_get_be32(f); + } + pxa2xx_timer_update(s, now); + + if (s->tm4) + for (i = 0; i < 8; i ++) { + qemu_get_be32s(f, &s->tm4[i].tm.value); + s->tm4[i].tm.level = qemu_get_be32(f); + qemu_get_be32s(f, &s->tm4[i].oldclock); + qemu_get_be32s(f, &s->tm4[i].clock); + qemu_get_be64s(f, &s->tm4[i].lastload); + qemu_get_be32s(f, &s->tm4[i].freq); + qemu_get_be32s(f, &s->tm4[i].control); + pxa2xx_timer_update4(s, now, i); + } + + qemu_get_be32s(f, &s->events); + qemu_get_be32s(f, &s->irq_enabled); + qemu_get_be32s(f, &s->reset3); + qemu_get_be32s(f, &s->snapshot); + + return 0; +} + static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, qemu_irq *irqs) { @@ -392,6 +459,10 @@ static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn, pxa2xx_timer_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); + + register_savevm("pxa2xx_timer", 0, 0, + pxa2xx_timer_save, pxa2xx_timer_load, s); + return s; } diff --git a/hw/spitz.c b/hw/spitz.c index 4dd59bb6e..171dba2e9 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -109,6 +109,24 @@ static void sl_writeb(void *opaque, target_phys_addr_t addr, } } +static void sl_save(QEMUFile *f, void *opaque) +{ + struct sl_nand_s *s = (struct sl_nand_s *) opaque; + + qemu_put_8s(f, &s->ctl); + ecc_put(f, &s->ecc); +} + +static int sl_load(QEMUFile *f, void *opaque, int version_id) +{ + struct sl_nand_s *s = (struct sl_nand_s *) opaque; + + qemu_get_8s(f, &s->ctl); + ecc_get(f, &s->ecc); + + return 0; +} + enum { FLASH_128M, FLASH_1024M, @@ -140,6 +158,8 @@ static void sl_flash_register(struct pxa2xx_state_s *cpu, int size) iomemtype = cpu_register_io_memory(0, sl_readfn, sl_writefn, s); cpu_register_physical_memory(s->target_base, 0x40, iomemtype); + + register_savevm("sl_flash", 0, 0, sl_save, sl_load, s); } /* Spitz Keyboard */ @@ -406,6 +426,38 @@ static void spitz_keyboard_pre_map(struct spitz_keyboard_s *s) #undef CTRL #undef FN +static void spitz_keyboard_save(QEMUFile *f, void *opaque) +{ + struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque; + int i; + + qemu_put_be16s(f, &s->sense_state); + qemu_put_be16s(f, &s->strobe_state); + for (i = 0; i < 5; i ++) + qemu_put_byte(f, spitz_gpio_invert[i]); +} + +static int spitz_keyboard_load(QEMUFile *f, void *opaque, int version_id) +{ + struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque; + int i; + + qemu_get_be16s(f, &s->sense_state); + qemu_get_be16s(f, &s->strobe_state); + for (i = 0; i < 5; i ++) + spitz_gpio_invert[i] = qemu_get_byte(f); + + /* Release all pressed keys */ + memset(s->keyrow, 0, sizeof(s->keyrow)); + spitz_keyboard_sense_update(s); + s->modifiers = 0; + s->imodifiers = 0; + s->fifopos = 0; + s->fifolen = 0; + + return 0; +} + static void spitz_keyboard_register(struct pxa2xx_state_s *cpu) { int i, j; @@ -429,6 +481,9 @@ static void spitz_keyboard_register(struct pxa2xx_state_s *cpu) spitz_keyboard_pre_map(s); qemu_add_kbd_event_handler((QEMUPutKBDEvent *) spitz_keyboard_handler, s); + + register_savevm("spitz_keyboard", 0, 0, + spitz_keyboard_save, spitz_keyboard_load, s); } /* SCOOP devices */ @@ -597,6 +652,42 @@ static inline void scoop_gpio_handler_set(struct scoop_info_s *s, int line, s->handler[line].opaque = opaque; } +static void scoop_save(QEMUFile *f, void *opaque) +{ + struct scoop_info_s *s = (struct scoop_info_s *) opaque; + qemu_put_be16s(f, &s->status); + qemu_put_be16s(f, &s->power); + qemu_put_be32s(f, &s->gpio_level); + qemu_put_be32s(f, &s->gpio_dir); + qemu_put_be32s(f, &s->prev_level); + qemu_put_be16s(f, &s->mcr); + qemu_put_be16s(f, &s->cdr); + qemu_put_be16s(f, &s->ccr); + qemu_put_be16s(f, &s->irr); + qemu_put_be16s(f, &s->imr); + qemu_put_be16s(f, &s->isr); + qemu_put_be16s(f, &s->gprr); +} + +static int scoop_load(QEMUFile *f, void *opaque, int version_id) +{ + struct scoop_info_s *s = (struct scoop_info_s *) opaque; + qemu_get_be16s(f, &s->status); + qemu_get_be16s(f, &s->power); + qemu_get_be32s(f, &s->gpio_level); + qemu_get_be32s(f, &s->gpio_dir); + qemu_get_be32s(f, &s->prev_level); + qemu_get_be16s(f, &s->mcr); + qemu_get_be16s(f, &s->cdr); + qemu_get_be16s(f, &s->ccr); + qemu_get_be16s(f, &s->irr); + qemu_get_be16s(f, &s->imr); + qemu_get_be16s(f, &s->isr); + qemu_get_be16s(f, &s->gprr); + + return 0; +} + static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, int count) { int iomemtype; @@ -615,6 +706,7 @@ static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, iomemtype = cpu_register_io_memory(0, scoop_readfn, scoop_writefn, &s[0]); cpu_register_physical_memory(s[0].target_base, 0xfff, iomemtype); + register_savevm("scoop", 0, 0, scoop_save, scoop_load, &s[0]); if (count < 2) return s; @@ -622,6 +714,7 @@ static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, iomemtype = cpu_register_io_memory(0, scoop_readfn, scoop_writefn, &s[1]); cpu_register_physical_memory(s[1].target_base, 0xfff, iomemtype); + register_savevm("scoop", 1, 0, scoop_save, scoop_load, &s[1]); return s; } @@ -763,6 +856,26 @@ static void spitz_pendown_set(void *opaque, int line, int level) pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_TP_INT, level); } +static void spitz_ssp_save(QEMUFile *f, void *opaque) +{ + qemu_put_be32(f, lcd_en); + qemu_put_be32(f, ads_en); + qemu_put_be32(f, max_en); + qemu_put_be32(f, bl_intensity); + qemu_put_be32(f, bl_power); +} + +static int spitz_ssp_load(QEMUFile *f, void *opaque, int version_id) +{ + lcd_en = qemu_get_be32(f); + ads_en = qemu_get_be32(f); + max_en = qemu_get_be32(f); + bl_intensity = qemu_get_be32(f); + bl_power = qemu_get_be32(f); + + return 0; +} + static void spitz_ssp_attach(struct pxa2xx_state_s *cpu) { lcd_en = ads_en = max_en = 0; @@ -786,6 +899,8 @@ static void spitz_ssp_attach(struct pxa2xx_state_s *cpu) bl_intensity = 0x20; bl_power = 0; + + register_savevm("spitz_ssp", 0, 0, spitz_ssp_save, spitz_ssp_load, cpu); } /* CF Microdrive */ diff --git a/hw/wm8750.c b/hw/wm8750.c index c08eb7300..b999890ef 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -491,6 +491,93 @@ static int wm8750_rx(i2c_slave *i2c) return 0x00; } +static void wm8750_save(QEMUFile *f, void *opaque) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + int i; + qemu_put_8s(f, &s->i2c_data[0]); + qemu_put_8s(f, &s->i2c_data[1]); + qemu_put_be32(f, s->i2c_len); + qemu_put_be32(f, s->enable); + qemu_put_be32(f, s->idx_in); + qemu_put_be32(f, s->req_in); + qemu_put_be32(f, s->idx_out); + qemu_put_be32(f, s->req_out); + + for (i = 0; i < 7; i ++) + qemu_put_8s(f, &s->outvol[i]); + for (i = 0; i < 2; i ++) + qemu_put_8s(f, &s->outmute[i]); + for (i = 0; i < 4; i ++) + qemu_put_8s(f, &s->invol[i]); + for (i = 0; i < 2; i ++) + qemu_put_8s(f, &s->inmute[i]); + + for (i = 0; i < 2; i ++) + qemu_put_8s(f, &s->diff[i]); + qemu_put_8s(f, &s->pol); + qemu_put_8s(f, &s->ds); + for (i = 0; i < 2; i ++) + qemu_put_8s(f, &s->monomix[i]); + qemu_put_8s(f, &s->alc); + qemu_put_8s(f, &s->mute); + for (i = 0; i < 4; i ++) + qemu_put_8s(f, &s->path[i]); + for (i = 0; i < 2; i ++) + qemu_put_8s(f, &s->mpath[i]); + qemu_put_8s(f, &s->format); + qemu_put_8s(f, &s->power); + qemu_put_be32s(f, &s->inmask); + qemu_put_be32s(f, &s->outmask); + qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate)); + i2c_slave_save(f, &s->i2c); +} + +static int wm8750_load(QEMUFile *f, void *opaque, int version_id) +{ + struct wm8750_s *s = (struct wm8750_s *) opaque; + int i; + qemu_get_8s(f, &s->i2c_data[0]); + qemu_get_8s(f, &s->i2c_data[1]); + s->i2c_len = qemu_get_be32(f); + s->enable = qemu_get_be32(f); + s->idx_in = qemu_get_be32(f); + s->req_in = qemu_get_be32(f); + s->idx_out = qemu_get_be32(f); + s->req_out = qemu_get_be32(f); + + for (i = 0; i < 7; i ++) + qemu_get_8s(f, &s->outvol[i]); + for (i = 0; i < 2; i ++) + qemu_get_8s(f, &s->outmute[i]); + for (i = 0; i < 4; i ++) + qemu_get_8s(f, &s->invol[i]); + for (i = 0; i < 2; i ++) + qemu_get_8s(f, &s->inmute[i]); + + for (i = 0; i < 2; i ++) + qemu_get_8s(f, &s->diff[i]); + qemu_get_8s(f, &s->pol); + qemu_get_8s(f, &s->ds); + for (i = 0; i < 2; i ++) + qemu_get_8s(f, &s->monomix[i]); + qemu_get_8s(f, &s->alc); + qemu_get_8s(f, &s->mute); + for (i = 0; i < 4; i ++) + qemu_get_8s(f, &s->path[i]); + for (i = 0; i < 2; i ++) + qemu_get_8s(f, &s->mpath[i]); + qemu_get_8s(f, &s->format); + qemu_get_8s(f, &s->power); + qemu_get_be32s(f, &s->inmask); + qemu_get_be32s(f, &s->outmask); + s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f]; + i2c_slave_load(f, &s->i2c); + return 0; +} + +static int wm8750_iid = 0; + i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio) { struct wm8750_s *s = (struct wm8750_s *) @@ -502,6 +589,8 @@ i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio) AUD_register_card(audio, CODEC, &s->card); wm8750_reset(&s->i2c); + register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s); + return &s->i2c; } diff --git a/vl.c b/vl.c index 373435b4a..7277165c7 100644 --- a/vl.c +++ b/vl.c @@ -5679,13 +5679,144 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) #elif defined(TARGET_ARM) -/* ??? Need to implement these. */ void cpu_save(QEMUFile *f, void *opaque) { + int i; + CPUARMState *env = (CPUARMState *)opaque; + + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->regs[i]); + } + qemu_put_be32(f, cpsr_read(env)); + qemu_put_be32(f, env->spsr); + for (i = 0; i < 6; i++) { + qemu_put_be32(f, env->banked_spsr[i]); + qemu_put_be32(f, env->banked_r13[i]); + qemu_put_be32(f, env->banked_r14[i]); + } + for (i = 0; i < 5; i++) { + qemu_put_be32(f, env->usr_regs[i]); + qemu_put_be32(f, env->fiq_regs[i]); + } + qemu_put_be32(f, env->cp15.c0_cpuid); + qemu_put_be32(f, env->cp15.c0_cachetype); + qemu_put_be32(f, env->cp15.c1_sys); + qemu_put_be32(f, env->cp15.c1_coproc); + qemu_put_be32(f, env->cp15.c2_base); + qemu_put_be32(f, env->cp15.c2_data); + qemu_put_be32(f, env->cp15.c2_insn); + qemu_put_be32(f, env->cp15.c3); + qemu_put_be32(f, env->cp15.c5_insn); + qemu_put_be32(f, env->cp15.c5_data); + for (i = 0; i < 8; i++) { + qemu_put_be32(f, env->cp15.c6_region[i]); + } + qemu_put_be32(f, env->cp15.c6_insn); + qemu_put_be32(f, env->cp15.c6_data); + qemu_put_be32(f, env->cp15.c9_insn); + qemu_put_be32(f, env->cp15.c9_data); + qemu_put_be32(f, env->cp15.c13_fcse); + qemu_put_be32(f, env->cp15.c13_context); + qemu_put_be32(f, env->cp15.c15_cpar); + + qemu_put_be32(f, env->features); + + if (arm_feature(env, ARM_FEATURE_VFP)) { + for (i = 0; i < 16; i++) { + CPU_DoubleU u; + u.d = env->vfp.regs[i]; + qemu_put_be32(f, u.l.upper); + qemu_put_be32(f, u.l.lower); + } + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->vfp.xregs[i]); + } + + /* TODO: Should use proper FPSCR access functions. */ + qemu_put_be32(f, env->vfp.vec_len); + qemu_put_be32(f, env->vfp.vec_stride); + } + + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + for (i = 0; i < 16; i++) { + qemu_put_be64(f, env->iwmmxt.regs[i]); + } + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->iwmmxt.cregs[i]); + } + } } int cpu_load(QEMUFile *f, void *opaque, int version_id) { + CPUARMState *env = (CPUARMState *)opaque; + int i; + + if (version_id != 0) + return -EINVAL; + + for (i = 0; i < 16; i++) { + env->regs[i] = qemu_get_be32(f); + } + cpsr_write(env, qemu_get_be32(f), 0xffffffff); + env->spsr = qemu_get_be32(f); + for (i = 0; i < 6; i++) { + env->banked_spsr[i] = qemu_get_be32(f); + env->banked_r13[i] = qemu_get_be32(f); + env->banked_r14[i] = qemu_get_be32(f); + } + for (i = 0; i < 5; i++) { + env->usr_regs[i] = qemu_get_be32(f); + env->fiq_regs[i] = qemu_get_be32(f); + } + env->cp15.c0_cpuid = qemu_get_be32(f); + env->cp15.c0_cachetype = qemu_get_be32(f); + env->cp15.c1_sys = qemu_get_be32(f); + env->cp15.c1_coproc = qemu_get_be32(f); + env->cp15.c2_base = qemu_get_be32(f); + env->cp15.c2_data = qemu_get_be32(f); + env->cp15.c2_insn = qemu_get_be32(f); + env->cp15.c3 = qemu_get_be32(f); + env->cp15.c5_insn = qemu_get_be32(f); + env->cp15.c5_data = qemu_get_be32(f); + for (i = 0; i < 8; i++) { + env->cp15.c6_region[i] = qemu_get_be32(f); + } + env->cp15.c6_insn = qemu_get_be32(f); + env->cp15.c6_data = qemu_get_be32(f); + env->cp15.c9_insn = qemu_get_be32(f); + env->cp15.c9_data = qemu_get_be32(f); + env->cp15.c13_fcse = qemu_get_be32(f); + env->cp15.c13_context = qemu_get_be32(f); + env->cp15.c15_cpar = qemu_get_be32(f); + + env->features = qemu_get_be32(f); + + if (arm_feature(env, ARM_FEATURE_VFP)) { + for (i = 0; i < 16; i++) { + CPU_DoubleU u; + u.l.upper = qemu_get_be32(f); + u.l.lower = qemu_get_be32(f); + env->vfp.regs[i] = u.d; + } + for (i = 0; i < 16; i++) { + env->vfp.xregs[i] = qemu_get_be32(f); + } + + /* TODO: Should use proper FPSCR access functions. */ + env->vfp.vec_len = qemu_get_be32(f); + env->vfp.vec_stride = qemu_get_be32(f); + } + + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + for (i = 0; i < 16; i++) { + env->iwmmxt.regs[i] = qemu_get_be64(f); + } + for (i = 0; i < 16; i++) { + env->iwmmxt.cregs[i] = qemu_get_be32(f); + } + } + return 0; } -- cgit v1.2.3 From 2dc7b602df142a470cbf82b5d7ef1ea99f761785 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 24 May 2007 18:53:22 +0000 Subject: Commit NAND image changes on "commit all" or "commit mtd". git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2858 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 5 ++++- vl.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index 9f76c0976..370bdfe98 100644 --- a/monitor.c +++ b/monitor.c @@ -202,7 +202,7 @@ static void do_help(const char *name) static void do_commit(const char *device) { int i, all_devices; - + all_devices = !strcmp(device, "all"); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { @@ -211,6 +211,9 @@ static void do_commit(const char *device) bdrv_commit(bs_table[i]); } } + if (mtd_bdrv) + if (all_devices || !strcmp(bdrv_get_device_name(mtd_bdrv), device)) + bdrv_commit(mtd_bdrv); } static void do_info(const char *item) diff --git a/vl.c b/vl.c index 7277165c7..24aef572f 100644 --- a/vl.c +++ b/vl.c @@ -1362,6 +1362,8 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) if (bs_table[i]) bdrv_commit(bs_table[i]); } + if (mtd_bdrv) + bdrv_commit(mtd_bdrv); } break; case 'b': -- cgit v1.2.3 From 8d05ea8a33c9d450d2a3079e967c69ea38ec28ba Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 24 May 2007 19:48:41 +0000 Subject: Change ptimer API to use 64-bit values, add save and load methods Use ptimers for Sparc32 Slavio git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2859 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/ptimer.c | 63 ++++++++++++++++++------- hw/slavio_timer.c | 139 +++++++++++++++++++++++------------------------------- vl.h | 8 ++-- 4 files changed, 110 insertions(+), 102 deletions(-) diff --git a/Makefile.target b/Makefile.target index a48652e88..98fe7e12b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -449,7 +449,7 @@ 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 +VL_OBJS+= cs4231.o ptimer.o endif endif ifeq ($(TARGET_BASE_ARCH), arm) diff --git a/hw/ptimer.c b/hw/ptimer.c index 2f350fc09..feabefed9 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -11,8 +11,8 @@ struct ptimer_state { int enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */ - uint32_t limit; - uint32_t delta; + uint64_t limit; + uint64_t delta; uint32_t period_frac; int64_t period; int64_t last_event; @@ -61,10 +61,10 @@ static void ptimer_tick(void *opaque) } } -uint32_t ptimer_get_count(ptimer_state *s) +uint64_t ptimer_get_count(ptimer_state *s) { int64_t now; - uint32_t counter; + uint64_t counter; if (s->enabled) { now = qemu_get_clock(vm_clock); @@ -75,8 +75,8 @@ uint32_t ptimer_get_count(ptimer_state *s) triggered. */ counter = 0; } else { - int64_t rem; - int64_t div; + uint64_t rem; + uint64_t div; rem = s->next_event - now; div = s->period; @@ -88,7 +88,7 @@ uint32_t ptimer_get_count(ptimer_state *s) return counter; } -void ptimer_set_count(ptimer_state *s, uint32_t count) +void ptimer_set_count(ptimer_state *s, uint64_t count) { s->delta = count; if (s->enabled) { @@ -108,7 +108,7 @@ void ptimer_run(ptimer_state *s, int oneshot) ptimer_reload(s); } -/* Pause a timer. Note that this may cause it to "loose" time, even if it +/* Pause a timer. Note that this may cause it to "lose" time, even if it is immediately restarted. */ void ptimer_stop(ptimer_state *s) { @@ -123,33 +123,60 @@ void ptimer_stop(ptimer_state *s) /* Set counter increment interval in nanoseconds. */ void ptimer_set_period(ptimer_state *s, int64_t period) { - if (s->enabled) { - fprintf(stderr, "FIXME: ptimer_set_period with running timer"); - } s->period = period; s->period_frac = 0; + if (s->enabled) { + s->next_event = qemu_get_clock(vm_clock); + ptimer_reload(s); + } } /* Set counter frequency in Hz. */ void ptimer_set_freq(ptimer_state *s, uint32_t freq) { - if (s->enabled) { - fprintf(stderr, "FIXME: ptimer_set_freq with running timer"); - } s->period = 1000000000ll / freq; s->period_frac = (1000000000ll << 32) / freq; + if (s->enabled) { + s->next_event = qemu_get_clock(vm_clock); + ptimer_reload(s); + } } /* Set the initial countdown value. If reload is nonzero then also set count = limit. */ -void ptimer_set_limit(ptimer_state *s, uint32_t limit, int reload) +void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) { - if (s->enabled) { - fprintf(stderr, "FIXME: ptimer_set_limit with running timer"); - } s->limit = limit; if (reload) s->delta = limit; + if (s->enabled) { + s->next_event = qemu_get_clock(vm_clock); + ptimer_reload(s); + } +} + +void qemu_put_ptimer(QEMUFile *f, ptimer_state *s) +{ + qemu_put_byte(f, s->enabled); + qemu_put_be64s(f, &s->limit); + qemu_put_be64s(f, &s->delta); + qemu_put_be32s(f, &s->period_frac); + qemu_put_be64s(f, &s->period); + qemu_put_be64s(f, &s->last_event); + qemu_put_be64s(f, &s->next_event); + qemu_put_timer(f, s->timer); +} + +void qemu_get_ptimer(QEMUFile *f, ptimer_state *s) +{ + s->enabled = qemu_get_byte(f); + qemu_get_be64s(f, &s->limit); + qemu_get_be64s(f, &s->delta); + qemu_get_be32s(f, &s->period_frac); + qemu_get_be64s(f, &s->period); + qemu_get_be64s(f, &s->last_event); + qemu_get_be64s(f, &s->next_event); + qemu_get_timer(f, s->timer); } ptimer_state *ptimer_init(QEMUBH *bh) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 114770467..e8b435f1c 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -48,61 +48,29 @@ do { printf("TIMER: " fmt , ##args); } while (0) */ typedef struct SLAVIO_TIMERState { - uint32_t limit, count, counthigh; - int64_t count_load_time; - int64_t expire_time; - int64_t stop_time, tick_offset; - QEMUTimer *irq_timer; + ptimer_state *timer; + uint32_t count, counthigh, reached; + uint64_t limit; int irq; - int reached, stopped; + int stopped; int mode; // 0 = processor, 1 = user, 2 = system unsigned int cpu; void *intctl; } SLAVIO_TIMERState; #define TIMER_MAXADDR 0x1f -#define CNT_FREQ 2000000 // Update count, set irq, update expire_time +// Convert from ptimer countdown units static void slavio_timer_get_out(SLAVIO_TIMERState *s) { - int out; - int64_t diff, ticks, count; - uint32_t limit; + uint64_t count; - // There are three clock tick units: CPU ticks, register units - // (nanoseconds), and counter ticks (500 ns). - if (s->mode == 1 && s->stopped) - ticks = s->stop_time; - else - ticks = qemu_get_clock(vm_clock) - s->tick_offset; - - out = (ticks > s->expire_time); - if (out) - s->reached = 0x80000000; - // Convert register units to counter ticks - limit = s->limit >> 9; - - if (!limit) - limit = 0x7fffffff >> 9; - - // Convert cpu ticks to counter ticks - diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec); - - // Calculate what the counter should be, convert to register - // units - count = diff % limit; - s->count = count << 9; - s->counthigh = count >> 22; - - // Expire time: CPU ticks left to next interrupt - // Convert remaining counter ticks to CPU ticks - s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); - - DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); - - if (s->mode != 1) - pic_set_irq_cpu(s->intctl, s->irq, out, s->cpu); + count = s->limit - (ptimer_get_count(s->timer) << 9); + DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit, s->counthigh, + s->count); + s->count = count & 0xfffffe00; + s->counthigh = count >> 32; } // timer callback @@ -110,17 +78,17 @@ static void slavio_timer_irq(void *opaque) { SLAVIO_TIMERState *s = opaque; - if (!s->irq_timer) - return; slavio_timer_get_out(s); + DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); + s->reached = 0x80000000; if (s->mode != 1) - qemu_mod_timer(s->irq_timer, s->expire_time); + pic_set_irq_cpu(s->intctl, s->irq, 1, s->cpu); } static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) { SLAVIO_TIMERState *s = opaque; - uint32_t saddr; + uint32_t saddr, ret; saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { @@ -131,60 +99,69 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) // clear irq pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu); s->reached = 0; - return s->limit; + ret = s->limit & 0x7fffffff; } else { slavio_timer_get_out(s); - return s->counthigh & 0x7fffffff; + ret = s->counthigh & 0x7fffffff; } + break; case 1: // read counter and reached bit (system mode) or read lsbits // of counter (user mode) slavio_timer_get_out(s); if (s->mode != 1) - return (s->count & 0x7fffffff) | s->reached; + ret = (s->count & 0x7fffffff) | s->reached; else - return s->count; + ret = s->count; + break; case 3: // read start/stop status - return s->stopped; + ret = s->stopped; + break; case 4: // read user/system mode - return s->mode & 1; + ret = s->mode & 1; + break; default: - return 0; + ret = 0; + break; } + DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret); + + return ret; } static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { SLAVIO_TIMERState *s = opaque; uint32_t saddr; + int reload = 0; + DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val); saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { case 0: // set limit, reset counter - s->count_load_time = qemu_get_clock(vm_clock); + reload = 1; + pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu); // fall through case 2: // set limit without resetting counter - if (!val) - s->limit = 0x7fffffff; - else - s->limit = val & 0x7fffffff; - slavio_timer_irq(s); + s->limit = val & 0x7ffffe00ULL; + if (!s->limit) + s->limit = 0x7ffffe00ULL; + ptimer_set_limit(s->timer, s->limit >> 9, reload); break; case 3: // start/stop user counter if (s->mode == 1) { if (val & 1) { - s->stop_time = qemu_get_clock(vm_clock); + ptimer_stop(s->timer); s->stopped = 1; } else { - if (s->stopped) - s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time; + ptimer_run(s->timer, 0); s->stopped = 0; } } @@ -193,6 +170,11 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 // bit 0: user (1) or system (0) counter mode if (s->mode == 0 || s->mode == 1) s->mode = val & 1; + if (s->mode == 1) { + pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu); + s->limit = -1ULL; + } + ptimer_set_limit(s->timer, s->limit >> 9, 1); break; default: break; @@ -215,37 +197,32 @@ static void slavio_timer_save(QEMUFile *f, void *opaque) { SLAVIO_TIMERState *s = opaque; - qemu_put_be32s(f, &s->limit); + qemu_put_be64s(f, &s->limit); qemu_put_be32s(f, &s->count); qemu_put_be32s(f, &s->counthigh); - qemu_put_be64s(f, &s->count_load_time); - qemu_put_be64s(f, &s->expire_time); - qemu_put_be64s(f, &s->stop_time); - qemu_put_be64s(f, &s->tick_offset); qemu_put_be32s(f, &s->irq); qemu_put_be32s(f, &s->reached); qemu_put_be32s(f, &s->stopped); qemu_put_be32s(f, &s->mode); + qemu_put_ptimer(f, s->timer); } static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) { SLAVIO_TIMERState *s = opaque; - if (version_id != 1) + if (version_id != 2) return -EINVAL; - qemu_get_be32s(f, &s->limit); + qemu_get_be64s(f, &s->limit); qemu_get_be32s(f, &s->count); qemu_get_be32s(f, &s->counthigh); - qemu_get_be64s(f, &s->count_load_time); - qemu_get_be64s(f, &s->expire_time); - qemu_get_be64s(f, &s->stop_time); - qemu_get_be64s(f, &s->tick_offset); qemu_get_be32s(f, &s->irq); qemu_get_be32s(f, &s->reached); qemu_get_be32s(f, &s->stopped); qemu_get_be32s(f, &s->mode); + qemu_get_ptimer(f, s->timer); + return 0; } @@ -253,13 +230,12 @@ static void slavio_timer_reset(void *opaque) { SLAVIO_TIMERState *s = opaque; - s->limit = 0; + s->limit = 0x7ffffe00ULL; s->count = 0; - s->count_load_time = qemu_get_clock(vm_clock);; - s->stop_time = s->count_load_time; - s->tick_offset = 0; s->reached = 0; s->mode &= 2; + ptimer_set_limit(s->timer, s->limit >> 9, 1); + ptimer_run(s->timer, 0); s->stopped = 1; slavio_timer_irq(s); } @@ -269,6 +245,7 @@ void slavio_timer_init(target_phys_addr_t addr, int irq, int mode, { int slavio_timer_io_memory; SLAVIO_TIMERState *s; + QEMUBH *bh; s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); if (!s) @@ -276,13 +253,15 @@ void slavio_timer_init(target_phys_addr_t addr, int irq, int mode, s->irq = irq; s->mode = mode; s->cpu = cpu; - s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); + bh = qemu_bh_new(slavio_timer_irq, s); + s->timer = ptimer_init(bh); + ptimer_set_period(s->timer, 500ULL); s->intctl = intctl; slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, slavio_timer_mem_write, s); cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory); - register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s); + register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s); qemu_register_reset(slavio_timer_reset, s); slavio_timer_reset(s); } diff --git a/vl.h b/vl.h index 330861e09..497cf8da5 100644 --- a/vl.h +++ b/vl.h @@ -1589,11 +1589,13 @@ typedef void (*ptimer_cb)(void *opaque); ptimer_state *ptimer_init(QEMUBH *bh); void ptimer_set_period(ptimer_state *s, int64_t period); void ptimer_set_freq(ptimer_state *s, uint32_t freq); -void ptimer_set_limit(ptimer_state *s, uint32_t limit, int reload); -uint32_t ptimer_get_count(ptimer_state *s); -void ptimer_set_count(ptimer_state *s, uint32_t count); +void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload); +uint64_t ptimer_get_count(ptimer_state *s); +void ptimer_set_count(ptimer_state *s, uint64_t count); void ptimer_run(ptimer_state *s, int oneshot); void ptimer_stop(ptimer_state *s); +void qemu_put_ptimer(QEMUFile *f, ptimer_state *s); +void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); #include "hw/pxa.h" -- cgit v1.2.3 From 20c9f095c4536e64e60432a5c72fce38e8306cbb Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 25 May 2007 18:50:28 +0000 Subject: Implement Sparc64 CPU timers using ptimers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2860 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/sun4u.c | 41 +++++++++++++++++++++++++++++++++++++++++ target-sparc/cpu.h | 5 +++++ target-sparc/op.c | 30 ++++++++++++++++++++++++++++-- target-sparc/op_helper.c | 17 +++++++++++++++++ target-sparc/translate.c | 13 ++++++++----- 6 files changed, 100 insertions(+), 8 deletions(-) diff --git a/Makefile.target b/Makefile.target index 98fe7e12b..d066cc03d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -445,7 +445,7 @@ 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 +VL_OBJS+= cirrus_vga.o parallel.o ptimer.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 diff --git a/hw/sun4u.c b/hw/sun4u.c index 952beff3c..a7b9ad8f0 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -282,7 +282,35 @@ void qemu_system_powerdown(void) static void main_cpu_reset(void *opaque) { CPUState *env = opaque; + cpu_reset(env); + ptimer_set_limit(env->tick, 0x7fffffffffffffffULL, 1); + ptimer_run(env->tick, 0); + ptimer_set_limit(env->stick, 0x7fffffffffffffffULL, 1); + ptimer_run(env->stick, 0); + ptimer_set_limit(env->hstick, 0x7fffffffffffffffULL, 1); + ptimer_run(env->hstick, 0); +} + +void tick_irq(void *opaque) +{ + CPUState *env = opaque; + + cpu_interrupt(env, CPU_INTERRUPT_TIMER); +} + +void stick_irq(void *opaque) +{ + CPUState *env = opaque; + + cpu_interrupt(env, CPU_INTERRUPT_TIMER); +} + +void hstick_irq(void *opaque) +{ + CPUState *env = opaque; + + cpu_interrupt(env, CPU_INTERRUPT_TIMER); } static const int ide_iobase[2] = { 0x1f0, 0x170 }; @@ -311,6 +339,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, long prom_offset, initrd_size, kernel_size; PCIBus *pci_bus; const sparc_def_t *def; + QEMUBH *bh; linux_boot = (kernel_filename != NULL); @@ -324,8 +353,20 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } env = cpu_init(); cpu_sparc_register(env, def); + bh = qemu_bh_new(tick_irq, env); + env->tick = ptimer_init(bh); + ptimer_set_period(env->tick, 1ULL); + + bh = qemu_bh_new(stick_irq, env); + env->stick = ptimer_init(bh); + ptimer_set_period(env->stick, 1ULL); + + bh = qemu_bh_new(hstick_irq, env); + env->hstick = ptimer_init(bh); + ptimer_set_period(env->hstick, 1ULL); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); + main_cpu_reset(env); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index b067d7b9b..c5ccd28a8 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -226,10 +226,12 @@ typedef struct CPUSPARCState { uint64_t mgregs[8]; /* mmu general registers */ uint64_t fprs; uint64_t tick_cmpr, stick_cmpr; + void *tick, *stick; uint64_t gsr; uint32_t gl; // UA2005 /* UA 2005 hyperprivileged registers */ uint64_t hpstate, htstate[MAXTL], hintp, htba, hver, hstick_cmpr, ssr; + void *hstick; // UA 2005 #endif #if !defined(TARGET_SPARC64) && !defined(reg_T2) target_ulong t2; @@ -292,6 +294,9 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); void raise_exception(int tt); void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int is_asi); +void do_tick_set_count(void *opaque, uint64_t count); +uint64_t do_tick_get_count(void *opaque); +void do_tick_set_limit(void *opaque, uint64_t limit); #include "cpu-all.h" diff --git a/target-sparc/op.c b/target-sparc/op.c index 5fbbd6db0..c0aee8f4a 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1096,12 +1096,38 @@ void OPPROTO op_wrccr(void) void OPPROTO op_rdtick(void) { - T0 = 0; // XXX read cycle counter and bit 31 + T0 = do_tick_get_count(env->tick); } void OPPROTO op_wrtick(void) { - T0 = 0; // XXX write cycle counter and bit 31 + do_tick_set_count(env->tick, T0); +} + +void OPPROTO op_wrtick_cmpr(void) +{ + do_tick_set_limit(env->tick, T0); +} + +void OPPROTO op_rdstick(void) +{ + T0 = do_tick_get_count(env->stick); +} + +void OPPROTO op_wrstick(void) +{ + do_tick_set_count(env->stick, T0); + do_tick_set_count(env->hstick, T0); +} + +void OPPROTO op_wrstick_cmpr(void) +{ + do_tick_set_limit(env->stick, T0); +} + +void OPPROTO op_wrhstick_cmpr(void) +{ + do_tick_set_limit(env->hstick, T0); } void OPPROTO op_rdtpc(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 93f61a802..b2f982f4e 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1133,3 +1133,20 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, raise_exception(TT_DATA_ACCESS); } #endif + +#ifdef TARGET_SPARC64 +void do_tick_set_count(void *opaque, uint64_t count) +{ + ptimer_set_count(opaque, -count); +} + +uint64_t do_tick_get_count(void *opaque) +{ + return -ptimer_get_count(opaque); +} + +void do_tick_set_limit(void *opaque, uint64_t limit) +{ + ptimer_set_limit(opaque, -limit, 0); +} +#endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 38d2a1319..8dbe3370f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1202,7 +1202,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; case 0x18: /* System tick */ - gen_op_rdtick(); // XXX + gen_op_rdstick(); gen_movl_T0_reg(rd); break; case 0x19: /* System tick compare */ @@ -1991,21 +1991,23 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); + gen_op_wrtick_cmpr(); break; case 0x18: /* System tick */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); + gen_op_wrstick(); break; case 0x19: /* System tick compare */ #if !defined(CONFIG_USER_ONLY) if (!supervisor(dc)) goto illegal_insn; #endif - gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); + gen_op_wrstick_cmpr(); break; case 0x10: /* Performance Control */ @@ -2155,7 +2157,8 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movl_env_T0(offsetof(CPUSPARCState, htba)); break; case 31: // hstick_cmpr - gen_op_movl_env_T0(offsetof(CPUSPARCState, hstick_cmpr)); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, hstick_cmpr)); + gen_op_wrhstick_cmpr(); break; case 6: // hver readonly default: -- cgit v1.2.3 From a87295e8df0923dab9857c1a340d23fe3278a336 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 15:09:38 +0000 Subject: M68k system mode semihosting. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2861 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + arm-semi.c | 52 +------ gdbstub.c | 13 +- linux-user/m68k-semi.c | 216 ----------------------------- linux-user/main.c | 15 +- linux-user/qemu.h | 10 +- m68k-semi.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++++ qemu-doc.texi | 6 +- target-m68k/cpu.h | 3 + target-m68k/op.c | 7 + target-m68k/op_helper.c | 16 +++ target-m68k/translate.c | 4 +- vl.c | 2 +- 13 files changed, 415 insertions(+), 283 deletions(-) delete mode 100644 linux-user/m68k-semi.c create mode 100644 m68k-semi.c diff --git a/Makefile.target b/Makefile.target index d066cc03d..45928f3c4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -468,6 +468,7 @@ VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o endif ifeq ($(TARGET_BASE_ARCH), m68k) VL_OBJS+= an5206.o mcf5206.o ptimer.o +VL_OBJS+= m68k-semi.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/arm-semi.c b/arm-semi.c index 4ddbc73c2..56d8d4bf4 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -112,57 +112,7 @@ static inline uint32_t set_swi_errno(CPUState *env, uint32_t code) return code; } -static uint32_t softmmu_tget32(CPUState *env, uint32_t addr) -{ - uint32_t val; - - cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0); - return tswap32(val); -} -static uint32_t softmmu_tget8(CPUState *env, uint32_t addr) -{ - uint8_t val; - - cpu_memory_rw_debug(env, addr, &val, 1, 0); - return val; -} -#define tget32(p) softmmu_tget32(env, p) -#define tget8(p) softmmu_tget8(env, p) - -static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len, - int copy) -{ - char *p; - /* TODO: Make this something that isn't fixed size. */ - p = malloc(len); - if (copy) - cpu_memory_rw_debug(env, addr, p, len, 0); - return p; -} -#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy) -static char *softmmu_lock_user_string(CPUState *env, uint32_t addr) -{ - char *p; - char *s; - uint8_t c; - /* TODO: Make this something that isn't fixed size. */ - s = p = malloc(1024); - do { - cpu_memory_rw_debug(env, addr, &c, 1, 0); - addr++; - *(p++) = c; - } while (c); - return s; -} -#define lock_user_string(p) softmmu_lock_user_string(env, p) -static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr, - target_ulong len) -{ - if (len) - cpu_memory_rw_debug(env, addr, p, len, 1); - free(p); -} -#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) +#include "softmmu-semi.h" #endif static target_ulong arm_semi_syscall_len; diff --git a/gdbstub.c b/gdbstub.c index 7dcaade66..fd20c9ca7 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -963,14 +963,16 @@ static void gdb_vm_stopped(void *opaque, int reason) /* Send a gdb syscall request. This accepts limited printf-style format specifiers, specifically: - %x - target_ulong argument printed in hex. - %s - string pointer (target_ulong) and length (int) pair. */ + %x - target_ulong argument printed in hex. + %lx - 64-bit argument printed in hex. + %s - string pointer (target_ulong) and length (int) pair. */ void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...) { va_list va; char buf[256]; char *p; target_ulong addr; + uint64_t i64; GDBState *s; s = gdb_syscall_state; @@ -993,11 +995,18 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...) addr = va_arg(va, target_ulong); p += sprintf(p, TARGET_FMT_lx, addr); break; + case 'l': + if (*(fmt++) != 'x') + goto bad_format; + i64 = va_arg(va, uint64_t); + p += sprintf(p, "%" PRIx64, i64); + break; case 's': addr = va_arg(va, target_ulong); p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int)); break; default: + bad_format: fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n", fmt - 1); break; diff --git a/linux-user/m68k-semi.c b/linux-user/m68k-semi.c deleted file mode 100644 index 7f6dddaee..000000000 --- a/linux-user/m68k-semi.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * m68k/ColdFire Semihosting ssycall interface - * - * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "qemu.h" - -#define HOSTED_EXIT 0 -#define HOSTED_PUTCHAR 1 /* Obsolete */ -#define HOSTED_OPEN 2 -#define HOSTED_CLOSE 3 -#define HOSTED_READ 4 -#define HOSTED_WRITE 5 -#define HOSTED_LSEEK 6 -#define HOSTED_RENAME 7 -#define HOSTED_UNLINK 8 -#define HOSTED_STAT 9 -#define HOSTED_FSTAT 10 -#define HOSTED_GETTIMEOFDAY 11 -#define HOSTED_ISATTY 12 -#define HOSTED_SYSTEM 13 - -typedef uint32_t gdb_mode_t; -typedef uint32_t gdb_time_t; - -struct m68k_gdb_stat { - uint32_t gdb_st_dev; /* device */ - uint32_t gdb_st_ino; /* inode */ - gdb_mode_t gdb_st_mode; /* protection */ - uint32_t gdb_st_nlink; /* number of hard links */ - uint32_t gdb_st_uid; /* user ID of owner */ - uint32_t gdb_st_gid; /* group ID of owner */ - uint32_t gdb_st_rdev; /* device type (if inode device) */ - uint64_t gdb_st_size; /* total size, in bytes */ - uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ - uint64_t gdb_st_blocks; /* number of blocks allocated */ - gdb_time_t gdb_st_atime; /* time of last access */ - gdb_time_t gdb_st_mtime; /* time of last modification */ - gdb_time_t gdb_st_ctime; /* time of last change */ -}; - -struct gdb_timeval { - gdb_time_t tv_sec; /* second */ - uint64_t tv_usec; /* microsecond */ -}; - -#define GDB_O_RDONLY 0x0 -#define GDB_O_WRONLY 0x1 -#define GDB_O_RDWR 0x2 -#define GDB_O_APPEND 0x8 -#define GDB_O_CREAT 0x200 -#define GDB_O_TRUNC 0x400 -#define GDB_O_EXCL 0x800 - -static int translate_openflags(int flags) -{ - int hf; - - if (flags & GDB_O_WRONLY) - hf = O_WRONLY; - else if (flags & GDB_O_RDWR) - hf = O_RDWR; - else - hf = O_RDONLY; - - if (flags & GDB_O_APPEND) hf |= O_APPEND; - if (flags & GDB_O_CREAT) hf |= O_CREAT; - if (flags & GDB_O_TRUNC) hf |= O_TRUNC; - if (flags & GDB_O_EXCL) hf |= O_EXCL; - - return hf; -} - -static void translate_stat(struct m68k_gdb_stat *p, struct stat *s) -{ - p->gdb_st_dev = tswap16(s->st_dev); - p->gdb_st_ino = tswap16(s->st_ino); - p->gdb_st_mode = tswap32(s->st_mode); - p->gdb_st_nlink = tswap16(s->st_nlink); - p->gdb_st_uid = tswap16(s->st_uid); - p->gdb_st_gid = tswap16(s->st_gid); - p->gdb_st_rdev = tswap16(s->st_rdev); - p->gdb_st_size = tswap32(s->st_size); - p->gdb_st_atime = tswap32(s->st_atime); - p->gdb_st_mtime = tswap32(s->st_mtime); - p->gdb_st_ctime = tswap32(s->st_ctime); - p->gdb_st_blksize = tswap32(s->st_blksize); - p->gdb_st_blocks = tswap32(s->st_blocks); -} - -static inline uint32_t check_err(CPUM68KState *env, uint32_t code) -{ - if (code == (uint32_t)-1) { - env->sr |= CCF_C; - } else { - env->sr &= ~CCF_C; - env->dregs[0] = code; - } - return code; -} - -#define ARG(x) tswap32(args[x]) -void do_m68k_semihosting(CPUM68KState *env, int nr) -{ - uint32_t *args; - - args = (uint32_t *)env->dregs[1]; - switch (nr) { - case HOSTED_EXIT: - exit(env->dregs[0]); - case HOSTED_OPEN: - /* Assume name is NULL terminated. */ - check_err(env, open((char *)ARG(0), translate_openflags(ARG(2)), - ARG(3))); - break; - case HOSTED_CLOSE: - { - /* Ignore attempts to close stdin/out/err. */ - int fd = ARG(0); - if (fd > 2) - check_err(env, close(fd)); - else - check_err(env, 0); - break; - } - case HOSTED_READ: - check_err(env, read(ARG(0), (void *)ARG(1), ARG(2))); - break; - case HOSTED_WRITE: - check_err(env, write(ARG(0), (void *)ARG(1), ARG(2))); - break; - case HOSTED_LSEEK: - { - uint64_t off; - off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32); - check_err(env, lseek(ARG(0), off, ARG(3))); - } - break; - case HOSTED_RENAME: - /* Assume names are NULL terminated. */ - check_err(env, rename((char *)ARG(0), (char *)ARG(2))); - break; - case HOSTED_UNLINK: - /* Assume name is NULL terminated. */ - check_err(env, unlink((char *)ARG(0))); - break; - case HOSTED_STAT: - /* Assume name is NULL terminated. */ - { - struct stat s; - int rc; - rc = check_err(env, stat((char *)ARG(0), &s)); - if (rc == 0) { - translate_stat((struct m68k_gdb_stat *)ARG(2), &s); - } - } - break; - case HOSTED_FSTAT: - { - struct stat s; - int rc; - rc = check_err(env, fstat(ARG(0), &s)); - if (rc == 0) { - translate_stat((struct m68k_gdb_stat *)ARG(1), &s); - } - } - break; - case HOSTED_GETTIMEOFDAY: - { - struct timeval tv; - struct gdb_timeval *p; - int rc; - rc = check_err(env, gettimeofday(&tv, NULL)); - if (rc != 0) { - p = (struct gdb_timeval *)ARG(0); - p->tv_sec = tswap32(tv.tv_sec); - p->tv_usec = tswap64(tv.tv_usec); - } - } - break; - case HOSTED_ISATTY: - check_err(env, isatty(ARG(0))); - break; - case HOSTED_SYSTEM: - /* Assume name is NULL terminated. */ - check_err(env, system((char *)ARG(0))); - break; - default: - cpu_abort(env, "Unsupported semihosting syscall %d\n", nr); - } -} diff --git a/linux-user/main.c b/linux-user/main.c index 0f4dbdadf..45b03000d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1502,9 +1502,9 @@ void cpu_loop(CPUM68KState *env) } } break; - case EXCP_HALTED: + case EXCP_HALT_INSN: /* Semihosing syscall. */ - env->pc += 2; + env->pc += 4; do_m68k_semihosting(env, env->dregs[0]); break; case EXCP_LINEA: @@ -1918,10 +1918,6 @@ int main(int argc, char **argv) for(i = 0; i < 16; i++) { env->regs[i] = regs->uregs[i]; } - ts->stack_base = info->start_stack; - ts->heap_base = info->brk; - /* This will be filled in on the first SYS_HEAPINFO call. */ - ts->heap_limit = 0; } #elif defined(TARGET_SPARC) { @@ -2049,6 +2045,13 @@ int main(int argc, char **argv) #error unsupported target CPU #endif +#if defined(TARGET_ARM) || defined(TARGET_M68K) + ts->stack_base = info->start_stack; + ts->heap_base = info->brk; + /* This will be filled in on the first SYS_HEAPINFO call. */ + ts->heap_limit = 0; +#endif + if (gdbstub_port) { gdbserver_start (gdbstub_port); gdb_handlesig(env, 0); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 31e29da7d..076145e1a 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -62,10 +62,6 @@ typedef struct TaskState { #ifdef TARGET_ARM /* FPA state */ FPA11 fpa; - /* Extra fields for semihosted binaries. */ - uint32_t stack_base; - uint32_t heap_base; - uint32_t heap_limit; int swi_errno; #endif #if defined(TARGET_I386) && !defined(TARGET_X86_64) @@ -77,6 +73,12 @@ typedef struct TaskState { #endif #ifdef TARGET_M68K int sim_syscalls; +#endif +#if defined(TARGET_ARM) || defined(TARGET_M68K) + /* Extra fields for semihosted binaries. */ + uint32_t stack_base; + uint32_t heap_base; + uint32_t heap_limit; #endif int used; /* non zero if used */ struct image_info *info; diff --git a/m68k-semi.c b/m68k-semi.c new file mode 100644 index 000000000..27bdce8e2 --- /dev/null +++ b/m68k-semi.c @@ -0,0 +1,353 @@ +/* + * m68k/ColdFire Semihosting syscall interface + * + * Copyright (c) 2005-2007 CodeSourcery. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#if defined(CONFIG_USER_ONLY) +#include "qemu.h" +#define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024) +#else +#include "vl.h" +#include "softmmu-semi.h" +#endif + +#define HOSTED_EXIT 0 +#define HOSTED_INIT_SIM 1 +#define HOSTED_OPEN 2 +#define HOSTED_CLOSE 3 +#define HOSTED_READ 4 +#define HOSTED_WRITE 5 +#define HOSTED_LSEEK 6 +#define HOSTED_RENAME 7 +#define HOSTED_UNLINK 8 +#define HOSTED_STAT 9 +#define HOSTED_FSTAT 10 +#define HOSTED_GETTIMEOFDAY 11 +#define HOSTED_ISATTY 12 +#define HOSTED_SYSTEM 13 + +typedef uint32_t gdb_mode_t; +typedef uint32_t gdb_time_t; + +struct m68k_gdb_stat { + uint32_t gdb_st_dev; /* device */ + uint32_t gdb_st_ino; /* inode */ + gdb_mode_t gdb_st_mode; /* protection */ + uint32_t gdb_st_nlink; /* number of hard links */ + uint32_t gdb_st_uid; /* user ID of owner */ + uint32_t gdb_st_gid; /* group ID of owner */ + uint32_t gdb_st_rdev; /* device type (if inode device) */ + uint64_t gdb_st_size; /* total size, in bytes */ + uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ + uint64_t gdb_st_blocks; /* number of blocks allocated */ + gdb_time_t gdb_st_atime; /* time of last access */ + gdb_time_t gdb_st_mtime; /* time of last modification */ + gdb_time_t gdb_st_ctime; /* time of last change */ +} __attribute__((packed)); + +struct gdb_timeval { + gdb_time_t tv_sec; /* second */ + uint64_t tv_usec; /* microsecond */ +} __attribute__((packed)); + +#define GDB_O_RDONLY 0x0 +#define GDB_O_WRONLY 0x1 +#define GDB_O_RDWR 0x2 +#define GDB_O_APPEND 0x8 +#define GDB_O_CREAT 0x200 +#define GDB_O_TRUNC 0x400 +#define GDB_O_EXCL 0x800 + +static int translate_openflags(int flags) +{ + int hf; + + if (flags & GDB_O_WRONLY) + hf = O_WRONLY; + else if (flags & GDB_O_RDWR) + hf = O_RDWR; + else + hf = O_RDONLY; + + if (flags & GDB_O_APPEND) hf |= O_APPEND; + if (flags & GDB_O_CREAT) hf |= O_CREAT; + if (flags & GDB_O_TRUNC) hf |= O_TRUNC; + if (flags & GDB_O_EXCL) hf |= O_EXCL; + + return hf; +} + +static void translate_stat(CPUState *env, target_ulong addr, struct stat *s) +{ + struct m68k_gdb_stat *p; + + p = lock_user(addr, sizeof(struct m68k_gdb_stat), 0); + p->gdb_st_dev = cpu_to_be32(s->st_dev); + p->gdb_st_ino = cpu_to_be32(s->st_ino); + p->gdb_st_mode = cpu_to_be32(s->st_mode); + p->gdb_st_nlink = cpu_to_be32(s->st_nlink); + p->gdb_st_uid = cpu_to_be32(s->st_uid); + p->gdb_st_gid = cpu_to_be32(s->st_gid); + p->gdb_st_rdev = cpu_to_be32(s->st_rdev); + p->gdb_st_size = cpu_to_be64(s->st_size); + p->gdb_st_blksize = cpu_to_be64(s->st_blksize); + p->gdb_st_blocks = cpu_to_be64(s->st_blocks); + p->gdb_st_atime = cpu_to_be32(s->st_atime); + p->gdb_st_mtime = cpu_to_be32(s->st_mtime); + p->gdb_st_ctime = cpu_to_be32(s->st_ctime); + unlock_user(p, addr, sizeof(struct m68k_gdb_stat)); +} + +static int m68k_semi_is_fseek; + +static void m68k_semi_cb(CPUState *env, target_ulong ret, target_ulong err) +{ + target_ulong args; + + args = env->dregs[1]; + if (m68k_semi_is_fseek) { + /* FIXME: We've already lost the high bits of the fseek + return value. */ + tput32(args, 0); + args += 4; + m68k_semi_is_fseek = 0; + } + tput32(args, ret); + tput32(args + 4, errno); +} + +#define ARG(x) tget32(args + (x) * 4) +#define PARG(x) ((unsigned long)ARG(x)) +void do_m68k_semihosting(CPUM68KState *env, int nr) +{ + uint32_t args; + void *p; + void *q; + uint32_t len; + uint32_t result; + + args = env->dregs[1]; + switch (nr) { + case HOSTED_EXIT: + exit(env->dregs[0]); + case HOSTED_OPEN: + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", ARG(0), (int)ARG(1), + ARG(2), ARG(3)); + return; + } else { + p = lock_user_string(ARG(0)); + result = open(p, translate_openflags(ARG(2)), ARG(3)); + unlock_user(p, ARG(0), 0); + } + break; + case HOSTED_CLOSE: + { + /* Ignore attempts to close stdin/out/err. */ + int fd = ARG(0); + if (fd > 2) { + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "close,%x", ARG(0)); + return; + } else { + result = close(fd); + } + } else { + result = 0; + } + break; + } + case HOSTED_READ: + len = ARG(2); + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x", + ARG(0), ARG(1), len); + return; + } else { + p = lock_user(ARG(1), len, 0); + result = read(ARG(0), p, len); + unlock_user(p, ARG(1), len); + } + break; + case HOSTED_WRITE: + len = ARG(2); + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x", + ARG(0), ARG(1), len); + return; + } else { + p = lock_user(ARG(1), len, 1); + result = write(ARG(0), p, len); + unlock_user(p, ARG(0), 0); + } + break; + case HOSTED_LSEEK: + { + uint64_t off; + off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32); + if (use_gdb_syscalls()) { + m68k_semi_is_fseek = 1; + gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x", + ARG(0), off, ARG(3)); + } else { + off = lseek(ARG(0), off, ARG(3)); + tput32(args, off >> 32); + tput32(args + 4, off); + tput32(args + 8, errno); + } + return; + } + case HOSTED_RENAME: + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "rename,%s,%s", + ARG(0), (int)ARG(1), ARG(2), (int)ARG(3)); + return; + } else { + p = lock_user_string(ARG(0)); + q = lock_user_string(ARG(2)); + result = rename(p, q); + unlock_user(p, ARG(0), 0); + unlock_user(q, ARG(2), 0); + } + break; + case HOSTED_UNLINK: + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "unlink,%s", + ARG(0), (int)ARG(1)); + return; + } else { + p = lock_user_string(ARG(0)); + result = unlink(p); + unlock_user(p, ARG(0), 0); + } + break; + case HOSTED_STAT: + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "stat,%s,%x", + ARG(0), (int)ARG(1), ARG(2)); + return; + } else { + struct stat s; + p = lock_user_string(ARG(0)); + result = stat(p, &s); + unlock_user(p, ARG(0), 0); + if (result == 0) { + translate_stat(env, ARG(2), &s); + } + } + break; + case HOSTED_FSTAT: + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x", + ARG(0), ARG(1)); + return; + } else { + struct stat s; + result = fstat(ARG(0), &s); + if (result == 0) { + translate_stat(env, ARG(1), &s); + } + } + break; + case HOSTED_GETTIMEOFDAY: + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x", + ARG(0), ARG(1)); + return; + } else { + struct timeval tv; + struct gdb_timeval *p; + result = gettimeofday(&tv, NULL); + if (result != 0) { + p = lock_user(ARG(0), sizeof(struct gdb_timeval), 0); + p->tv_sec = cpu_to_be32(tv.tv_sec); + p->tv_usec = cpu_to_be64(tv.tv_usec); + unlock_user(p, ARG(0), sizeof(struct gdb_timeval)); + } + } + break; + case HOSTED_ISATTY: + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "isatty,%x", ARG(0)); + return; + } else { + result = isatty(ARG(0)); + } + break; + case HOSTED_SYSTEM: + if (use_gdb_syscalls()) { + gdb_do_syscall(m68k_semi_cb, "system,%s", + ARG(0), (int)ARG(1)); + return; + } else { + p = lock_user_string(ARG(0)); + result = system(p); + unlock_user(p, ARG(0), 0); + } + break; + case HOSTED_INIT_SIM: +#if defined(CONFIG_USER_ONLY) + { + TaskState *ts = env->opaque; + /* Allocate the heap using sbrk. */ + if (!ts->heap_limit) { + long ret; + uint32_t size; + uint32_t base; + + base = do_brk(0); + size = SEMIHOSTING_HEAP_SIZE; + /* Try a big heap, and reduce the size if that fails. */ + for (;;) { + ret = do_brk(base + size); + if (ret != -1) + break; + size >>= 1; + } + ts->heap_limit = base + size; + } + /* This call may happen before we have writable memory, so return + values directly in registers. */ + env->dregs[1] = ts->heap_limit; + env->aregs[7] = ts->stack_base; + } +#else + /* FIXME: This is wrong for boards where RAM does not start at + address zero. */ + env->dregs[1] = ram_size; + env->aregs[7] = ram_size; +#endif + return; + default: + cpu_abort(env, "Unsupported semihosting syscall %d\n", nr); + result = 0; + } + tput32(args, result); + tput32(args + 4, errno); +} diff --git a/qemu-doc.texi b/qemu-doc.texi index 544de3b00..81ddfb047 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -715,7 +715,11 @@ Exit instead of rebooting. Start right away with a saved state (@code{loadvm} in monitor) @item -semihosting -Enable "Angel" semihosting interface (ARM target machines only). +Enable semihosting syscall emulation (ARM and M68K target machines only). + +On ARM this implements the "Angel" interface. +On M68K this implements the "ColdFire GDB" interface used by libgloss. + Note that this allows guest direct access to the host filesystem, so should only be used with trusted guest OS. @end table diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index c916ad7cd..93080cfe1 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -51,6 +51,7 @@ #define EXCP_ICE 13 #define EXCP_RTE 0x100 +#define EXCP_HALT_INSN 0x101 typedef struct CPUM68KState { uint32_t dregs[8]; @@ -148,6 +149,8 @@ void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); #define M68K_FPCR_PREC (1 << 6) +void do_m68k_semihosting(CPUM68KState *env, int nr); + #ifdef CONFIG_USER_ONLY /* Linux uses 8k pages. */ #define TARGET_PAGE_BITS 13 diff --git a/target-m68k/op.c b/target-m68k/op.c index 6134bb018..69d1fde9a 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -383,7 +383,14 @@ OP(divs) FORCE_RET(); } +/* Halt is special because it may be a semihosting call. */ OP(halt) +{ + RAISE_EXCEPTION(EXCP_HALT_INSN); + FORCE_RET(); +} + +OP(stop) { env->halted = 1; RAISE_EXCEPTION(EXCP_HLT); diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 7455e3165..f5593eca0 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -28,6 +28,8 @@ void do_interrupt(int is_hw) #else +extern int semihosting_enabled; + #define MMUSUFFIX _mmu #define GETPC() (__builtin_return_address(0)) @@ -104,6 +106,20 @@ void do_interrupt(int is_hw) /* Return from an exception. */ do_rte(); return; + case EXCP_HALT_INSN: + if (semihosting_enabled + && (env->sr & SR_S) != 0 + && (env->pc & 3) == 0 + && lduw_code(env->pc - 4) == 0x4e71 + && ldl_code(env->pc) == 0x4e7bf000) { + env->pc += 4; + do_m68k_semihosting(env, env->dregs[0]); + return; + } + env->halted = 1; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); + return; } if (env->exception_index >= EXCP_TRAP0 && env->exception_index <= EXCP_TRAP15) { diff --git a/target-m68k/translate.c b/target-m68k/translate.c index eff32867b..d7162fea6 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1901,7 +1901,6 @@ DISAS_INSN(move_to_usp) DISAS_INSN(halt) { - gen_flush_cc_op(s); gen_jmp(s, gen_im32(s->pc)); gen_op_halt(); } @@ -1919,7 +1918,8 @@ DISAS_INSN(stop) s->pc += 2; gen_set_sr_im(s, ext, 0); - disas_halt(s, insn); + gen_jmp(s, gen_im32(s->pc)); + gen_op_stop(); } DISAS_INSN(rte) diff --git a/vl.c b/vl.c index 24aef572f..d23af87a7 100644 --- a/vl.c +++ b/vl.c @@ -6865,7 +6865,7 @@ const QEMUOption qemu_options[] = { { "show-cursor", 0, QEMU_OPTION_show_cursor }, { "daemonize", 0, QEMU_OPTION_daemonize }, { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, -#if defined(TARGET_ARM) +#if defined(TARGET_ARM) || defined(TARGET_M68K) { "semihosting", 0, QEMU_OPTION_semihosting }, #endif { "name", HAS_ARG, QEMU_OPTION_name }, -- cgit v1.2.3 From 342debdcf87d79ee88c63965e6bab478b3ad47eb Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 15:18:52 +0000 Subject: Suppress pointer from integer of different size warning. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2862 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall_defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 2989bb763..88f7a217b 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -182,10 +182,10 @@ __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cms __cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))); - if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) tswapl(__mhdr->msg_control) + if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) (unsigned long)tswapl(__mhdr->msg_control) + tswapl(__mhdr->msg_controllen)) || ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)) - > ((unsigned char *) tswapl(__mhdr->msg_control) + > ((unsigned char *) (unsigned long) tswapl(__mhdr->msg_control) + tswapl(__mhdr->msg_controllen)))) /* No more entries. */ return 0; -- cgit v1.2.3 From 9e407a85f1b291cecd5178e55ea7c8a86ef1371b Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 16:38:53 +0000 Subject: Reject invalid targets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2863 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/configure b/configure index 8b2743f25..793d9d156 100755 --- a/configure +++ b/configure @@ -874,23 +874,26 @@ target_bigendian="no" [ "$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 - target_linux_user="no" -if expr $target : '.*-linux-user' > /dev/null ; then - target_linux_user="yes" -fi - target_darwin_user="no" -if expr $target : '.*-darwin-user' > /dev/null ; then - target_darwin_user="yes" -fi +case "$target" in + ${target_cpu}-softmmu) + target_softmmu="yes" + ;; + ${target_cpu}-linux-user) + target_user_only="yes" + target_linux_user="yes" + ;; + ${target_cpu}-darwin-user) + target_user_only="yes" + target_darwin_user="yes" + ;; + *) + echo "ERROR: Target '$target' not recognised" + exit 1 + ;; +esac if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ -a "$sdl" = "no" -a "$cocoa" = "no" ; then -- cgit v1.2.3 From 6b3a45ccea29d5e87a1ffa2506b847b5ba96f983 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 16:46:21 +0000 Subject: Add missing file. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2864 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu-semi.h | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 softmmu-semi.h diff --git a/softmmu-semi.h b/softmmu-semi.h new file mode 100644 index 000000000..a5b897645 --- /dev/null +++ b/softmmu-semi.h @@ -0,0 +1,67 @@ +/* + * Helper routines to provide target memory access for semihosting + * syscalls in system emulation mode. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GPL + */ + +static inline uint32_t softmmu_tget32(CPUState *env, uint32_t addr) +{ + uint32_t val; + + cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0); + return tswap32(val); +} +static inline uint32_t softmmu_tget8(CPUState *env, uint32_t addr) +{ + uint8_t val; + + cpu_memory_rw_debug(env, addr, &val, 1, 0); + return val; +} +#define tget32(p) softmmu_tget32(env, p) +#define tget8(p) softmmu_tget8(env, p) + +static inline void softmmu_tput32(CPUState *env, uint32_t addr, uint32_t val) +{ + val = tswap32(val); + cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 1); +} +#define tput32(p, val) softmmu_tput32(env, p, val) + +static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len, + int copy) +{ + char *p; + /* TODO: Make this something that isn't fixed size. */ + p = malloc(len); + if (copy) + cpu_memory_rw_debug(env, addr, p, len, 0); + return p; +} +#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy) +static char *softmmu_lock_user_string(CPUState *env, uint32_t addr) +{ + char *p; + char *s; + uint8_t c; + /* TODO: Make this something that isn't fixed size. */ + s = p = malloc(1024); + do { + cpu_memory_rw_debug(env, addr, &c, 1, 0); + addr++; + *(p++) = c; + } while (c); + return s; +} +#define lock_user_string(p) softmmu_lock_user_string(env, p) +static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr, + target_ulong len) +{ + if (len) + cpu_memory_rw_debug(env, addr, p, len, 1); + free(p); +} +#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len) -- cgit v1.2.3 From 0402f767b5f11ec0efaf6abe50a11487801fc2ef Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 16:52:21 +0000 Subject: Rework m68k cpu feature flags. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2865 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- target-m68k/cpu.h | 19 ++++ target-m68k/helper.c | 63 ++++++++++++++ target-m68k/translate.c | 225 ++++++++++++++++++++---------------------------- 4 files changed, 176 insertions(+), 133 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 45b03000d..dc242f621 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1974,7 +1974,7 @@ int main(int argc, char **argv) #elif defined(TARGET_M68K) { if (cpu_model == NULL) - cpu_model = "cfv4e"; + cpu_model = "any"; if (cpu_m68k_set_model(env, cpu_model)) { cpu_abort(cpu_single_env, "Unable to find m68k CPU definition\n"); diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 93080cfe1..3a1a13888 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -85,6 +85,8 @@ typedef struct CPUM68KState { uint32_t mbar; uint32_t rambar0; + uint32_t features; + /* ??? remove this. */ uint32_t t1; @@ -151,6 +153,23 @@ void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); void do_m68k_semihosting(CPUM68KState *env, int nr); +enum m68k_features { + M68K_FEATURE_CF_ISA_A, + M68K_FEATURE_CF_ISA_B, + M68K_FEATURE_CF_ISA_C, + M68K_FEATURE_CF_FPU, + M68K_FEATURE_CF_MAC, + M68K_FEATURE_CF_EMAC, + M68K_FEATURE_EXT_FULL /* 68020+ full extension word. */ +}; + +static inline int m68k_feature(CPUM68KState *env, int feature) +{ + return (env->features & (1u << feature)) != 0; +} + +void register_m68k_insns (CPUM68KState *env); + #ifdef CONFIG_USER_ONLY /* Linux uses 8k pages. */ #define TARGET_PAGE_BITS 13 diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 640fe4fb8..12e3f7867 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -20,11 +20,74 @@ */ #include +#include #include "config.h" #include "cpu.h" #include "exec-all.h" +enum m68k_cpuid { + M68K_CPUID_M5206, + M68K_CPUID_CFV4E, + M68K_CPUID_ANY, +}; + +struct m68k_def_t { + const char * name; + enum m68k_cpuid id; +}; + +static m68k_def_t m68k_cpu_defs[] = { + {"m5206", M68K_CPUID_M5206}, + {"cfv4e", M68K_CPUID_CFV4E}, + {"any", M68K_CPUID_ANY}, + {NULL, 0}, +}; + +static void m68k_set_feature(CPUM68KState *env, int feature) +{ + env->features |= (1u << feature); +} + +int cpu_m68k_set_model(CPUM68KState *env, const char * name) +{ + m68k_def_t *def; + + for (def = m68k_cpu_defs; def->name; def++) { + if (strcmp(def->name, name) == 0) + break; + } + if (!def->name) + return 1; + + switch (def->id) { + case M68K_CPUID_M5206: + m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); + break; + case M68K_CPUID_CFV4E: + m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); + m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); + m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); + m68k_set_feature(env, M68K_FEATURE_CF_FPU); + m68k_set_feature(env, M68K_FEATURE_CF_MAC); + m68k_set_feature(env, M68K_FEATURE_CF_EMAC); + break; + case M68K_CPUID_ANY: + m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); + m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); + m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); + m68k_set_feature(env, M68K_FEATURE_CF_FPU); + m68k_set_feature(env, M68K_FEATURE_CF_MAC); + m68k_set_feature(env, M68K_FEATURE_CF_EMAC); + m68k_set_feature(env, M68K_FEATURE_EXT_FULL); + break; + } + + register_m68k_insns(env); + + return 0; +} + void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) { int flags; diff --git a/target-m68k/translate.c b/target-m68k/translate.c index d7162fea6..b9b16b5c0 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -108,25 +108,6 @@ enum { #define AREG(insn, pos) (((insn >> pos) & 7) + QREG_A0) #define FREG(insn, pos) (((insn >> pos) & 7) + QREG_F0) -#define M68K_INSN_CF_A (1 << 0) -#define M68K_INSN_CF_B (1 << 1) -#define M68K_INSN_CF_C (1 << 2) -#define M68K_INSN_CF_MAC (1 << 3) -#define M68K_INSN_CF_EMAC (1 << 4) -#define M68K_INSN_CF_FPU (1 << 5) - -struct m68k_def_t { - const char * name; - uint32_t insns; -}; - -static m68k_def_t m68k_cpu_defs[] = { - {"m5206", M68K_INSN_CF_A}, - {"cfv4e", M68K_INSN_CF_A | M68K_INSN_CF_B | M68K_INSN_CF_C - | M68K_INSN_CF_MAC | M68K_INSN_CF_EMAC | M68K_INSN_CF_FPU}, - {NULL, 0}, -}; - typedef void (*disas_proc)(DisasContext *, uint16_t); #ifdef DEBUG_DISPATCH @@ -2348,109 +2329,105 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) /* Register m68k opcode handlers. Order is important. Later insn override earlier ones. */ -static void -register_m68k_insns (m68k_def_t *def) +void register_m68k_insns (CPUM68KState *env) { - uint32_t iflags; - - iflags = def->insns; -#define INSN(name, opcode, mask, isa) \ - if (iflags & M68K_INSN_##isa) \ +#define INSN(name, opcode, mask, feature) \ + if (m68k_feature(env, M68K_FEATURE_##feature)) \ register_opcode(disas_##name, 0x##opcode, 0x##mask) - INSN(undef, 0000, 0000, CF_A); - INSN(arith_im, 0080, fff8, CF_A); - INSN(bitrev, 00c0, fff8, CF_C); - INSN(bitop_reg, 0100, f1c0, CF_A); - INSN(bitop_reg, 0140, f1c0, CF_A); - INSN(bitop_reg, 0180, f1c0, CF_A); - INSN(bitop_reg, 01c0, f1c0, CF_A); - INSN(arith_im, 0280, fff8, CF_A); - INSN(byterev, 02c0, fff8, CF_A); - INSN(arith_im, 0480, fff8, CF_A); - INSN(ff1, 04c0, fff8, CF_C); - INSN(arith_im, 0680, fff8, CF_A); - INSN(bitop_im, 0800, ffc0, CF_A); - INSN(bitop_im, 0840, ffc0, CF_A); - INSN(bitop_im, 0880, ffc0, CF_A); - INSN(bitop_im, 08c0, ffc0, CF_A); - INSN(arith_im, 0a80, fff8, CF_A); - INSN(arith_im, 0c00, ff38, CF_A); - INSN(move, 1000, f000, CF_A); - INSN(move, 2000, f000, CF_A); - INSN(move, 3000, f000, CF_A); - INSN(strldsr, 40e7, ffff, CF_A); - INSN(negx, 4080, fff8, CF_A); - INSN(move_from_sr, 40c0, fff8, CF_A); - INSN(lea, 41c0, f1c0, CF_A); - INSN(clr, 4200, ff00, CF_A); - INSN(undef, 42c0, ffc0, CF_A); - INSN(move_from_ccr, 42c0, fff8, CF_A); - INSN(neg, 4480, fff8, CF_A); - INSN(move_to_ccr, 44c0, ffc0, CF_A); - INSN(not, 4680, fff8, CF_A); - INSN(move_to_sr, 46c0, ffc0, CF_A); - INSN(pea, 4840, ffc0, CF_A); - INSN(swap, 4840, fff8, CF_A); - INSN(movem, 48c0, fbc0, CF_A); - INSN(ext, 4880, fff8, CF_A); - INSN(ext, 48c0, fff8, CF_A); - INSN(ext, 49c0, fff8, CF_A); - INSN(tst, 4a00, ff00, CF_A); - INSN(tas, 4ac0, ffc0, CF_B); - INSN(halt, 4ac8, ffff, CF_A); - INSN(pulse, 4acc, ffff, CF_A); - INSN(illegal, 4afc, ffff, CF_A); - INSN(mull, 4c00, ffc0, CF_A); - INSN(divl, 4c40, ffc0, CF_A); - INSN(sats, 4c80, fff8, CF_B); - INSN(trap, 4e40, fff0, CF_A); - INSN(link, 4e50, fff8, CF_A); - INSN(unlk, 4e58, fff8, CF_A); - INSN(move_to_usp, 4e60, fff8, CF_B); - INSN(move_from_usp, 4e68, fff8, CF_B); - INSN(nop, 4e71, ffff, CF_A); - INSN(stop, 4e72, ffff, CF_A); - INSN(rte, 4e73, ffff, CF_A); - INSN(rts, 4e75, ffff, CF_A); - INSN(movec, 4e7b, ffff, CF_A); - INSN(jump, 4e80, ffc0, CF_A); - INSN(jump, 4ec0, ffc0, CF_A); - INSN(addsubq, 5180, f1c0, CF_A); - INSN(scc, 50c0, f0f8, CF_A); - INSN(addsubq, 5080, f1c0, CF_A); - INSN(tpf, 51f8, fff8, CF_A); - INSN(branch, 6000, f000, CF_A); - INSN(moveq, 7000, f100, CF_A); - INSN(mvzs, 7100, f100, CF_B); - INSN(or, 8000, f000, CF_A); - INSN(divw, 80c0, f0c0, CF_A); - INSN(addsub, 9000, f000, CF_A); - INSN(subx, 9180, f1f8, CF_A); - INSN(suba, 91c0, f1c0, CF_A); - INSN(undef_mac, a000, f000, CF_A); - INSN(mov3q, a140, f1c0, CF_B); - INSN(cmp, b000, f1c0, CF_B); /* cmp.b */ - INSN(cmp, b040, f1c0, CF_B); /* cmp.w */ - INSN(cmpa, b0c0, f1c0, CF_B); /* cmpa.w */ - INSN(cmp, b080, f1c0, CF_A); - INSN(cmpa, b1c0, f1c0, CF_A); - INSN(eor, b180, f1c0, CF_A); - INSN(and, c000, f000, CF_A); - INSN(mulw, c0c0, f0c0, CF_A); - INSN(addsub, d000, f000, CF_A); - INSN(addx, d180, f1f8, CF_A); - INSN(adda, d1c0, f1c0, CF_A); - INSN(shift_im, e080, f0f0, CF_A); - INSN(shift_reg, e0a0, f0f0, CF_A); - INSN(undef_fpu, f000, f000, CF_A); + INSN(undef, 0000, 0000, CF_ISA_A); + INSN(arith_im, 0080, fff8, CF_ISA_A); + INSN(bitrev, 00c0, fff8, CF_ISA_C); + INSN(bitop_reg, 0100, f1c0, CF_ISA_A); + INSN(bitop_reg, 0140, f1c0, CF_ISA_A); + INSN(bitop_reg, 0180, f1c0, CF_ISA_A); + INSN(bitop_reg, 01c0, f1c0, CF_ISA_A); + INSN(arith_im, 0280, fff8, CF_ISA_A); + INSN(byterev, 02c0, fff8, CF_ISA_A); + INSN(arith_im, 0480, fff8, CF_ISA_A); + INSN(ff1, 04c0, fff8, CF_ISA_C); + INSN(arith_im, 0680, fff8, CF_ISA_A); + INSN(bitop_im, 0800, ffc0, CF_ISA_A); + INSN(bitop_im, 0840, ffc0, CF_ISA_A); + INSN(bitop_im, 0880, ffc0, CF_ISA_A); + INSN(bitop_im, 08c0, ffc0, CF_ISA_A); + INSN(arith_im, 0a80, fff8, CF_ISA_A); + INSN(arith_im, 0c00, ff38, CF_ISA_A); + INSN(move, 1000, f000, CF_ISA_A); + INSN(move, 2000, f000, CF_ISA_A); + INSN(move, 3000, f000, CF_ISA_A); + INSN(strldsr, 40e7, ffff, CF_ISA_A); + INSN(negx, 4080, fff8, CF_ISA_A); + INSN(move_from_sr, 40c0, fff8, CF_ISA_A); + INSN(lea, 41c0, f1c0, CF_ISA_A); + INSN(clr, 4200, ff00, CF_ISA_A); + INSN(undef, 42c0, ffc0, CF_ISA_A); + INSN(move_from_ccr, 42c0, fff8, CF_ISA_A); + INSN(neg, 4480, fff8, CF_ISA_A); + INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A); + INSN(not, 4680, fff8, CF_ISA_A); + INSN(move_to_sr, 46c0, ffc0, CF_ISA_A); + INSN(pea, 4840, ffc0, CF_ISA_A); + INSN(swap, 4840, fff8, CF_ISA_A); + INSN(movem, 48c0, fbc0, CF_ISA_A); + INSN(ext, 4880, fff8, CF_ISA_A); + INSN(ext, 48c0, fff8, CF_ISA_A); + INSN(ext, 49c0, fff8, CF_ISA_A); + INSN(tst, 4a00, ff00, CF_ISA_A); + INSN(tas, 4ac0, ffc0, CF_ISA_B); + INSN(halt, 4ac8, ffff, CF_ISA_A); + INSN(pulse, 4acc, ffff, CF_ISA_A); + INSN(illegal, 4afc, ffff, CF_ISA_A); + INSN(mull, 4c00, ffc0, CF_ISA_A); + INSN(divl, 4c40, ffc0, CF_ISA_A); + INSN(sats, 4c80, fff8, CF_ISA_B); + INSN(trap, 4e40, fff0, CF_ISA_A); + INSN(link, 4e50, fff8, CF_ISA_A); + INSN(unlk, 4e58, fff8, CF_ISA_A); + INSN(move_to_usp, 4e60, fff8, CF_ISA_B); + INSN(move_from_usp, 4e68, fff8, CF_ISA_B); + INSN(nop, 4e71, ffff, CF_ISA_A); + INSN(stop, 4e72, ffff, CF_ISA_A); + INSN(rte, 4e73, ffff, CF_ISA_A); + INSN(rts, 4e75, ffff, CF_ISA_A); + INSN(movec, 4e7b, ffff, CF_ISA_A); + INSN(jump, 4e80, ffc0, CF_ISA_A); + INSN(jump, 4ec0, ffc0, CF_ISA_A); + INSN(addsubq, 5180, f1c0, CF_ISA_A); + INSN(scc, 50c0, f0f8, CF_ISA_A); + INSN(addsubq, 5080, f1c0, CF_ISA_A); + INSN(tpf, 51f8, fff8, CF_ISA_A); + INSN(branch, 6000, f000, CF_ISA_A); + INSN(moveq, 7000, f100, CF_ISA_A); + INSN(mvzs, 7100, f100, CF_ISA_B); + INSN(or, 8000, f000, CF_ISA_A); + INSN(divw, 80c0, f0c0, CF_ISA_A); + INSN(addsub, 9000, f000, CF_ISA_A); + INSN(subx, 9180, f1f8, CF_ISA_A); + INSN(suba, 91c0, f1c0, CF_ISA_A); + INSN(undef_mac, a000, f000, CF_ISA_A); + INSN(mov3q, a140, f1c0, CF_ISA_B); + INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */ + INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */ + INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */ + INSN(cmp, b080, f1c0, CF_ISA_A); + INSN(cmpa, b1c0, f1c0, CF_ISA_A); + INSN(eor, b180, f1c0, CF_ISA_A); + INSN(and, c000, f000, CF_ISA_A); + INSN(mulw, c0c0, f0c0, CF_ISA_A); + INSN(addsub, d000, f000, CF_ISA_A); + INSN(addx, d180, f1f8, CF_ISA_A); + INSN(adda, d1c0, f1c0, CF_ISA_A); + INSN(shift_im, e080, f0f0, CF_ISA_A); + INSN(shift_reg, e0a0, f0f0, CF_ISA_A); + INSN(undef_fpu, f000, f000, CF_ISA_A); INSN(fpu, f200, ffc0, CF_FPU); INSN(fbcc, f280, ffc0, CF_FPU); INSN(frestore, f340, ffc0, CF_FPU); INSN(fsave, f340, ffc0, CF_FPU); - INSN(intouch, f340, ffc0, CF_A); - INSN(cpushl, f428, ff38, CF_A); - INSN(wddata, fb00, ff00, CF_A); - INSN(wdebug, fbc0, ffc0, CF_A); + INSN(intouch, f340, ffc0, CF_ISA_A); + INSN(cpushl, f428, ff38, CF_ISA_A); + INSN(wddata, fb00, ff00, CF_ISA_A); + INSN(wdebug, fbc0, ffc0, CF_ISA_A); #undef INSN } @@ -2880,22 +2857,6 @@ void cpu_m68k_close(CPUM68KState *env) free(env); } -int cpu_m68k_set_model(CPUM68KState *env, const char * name) -{ - m68k_def_t *def; - - for (def = m68k_cpu_defs; def->name; def++) { - if (strcmp(def->name, name) == 0) - break; - } - if (!def->name) - return 1; - - register_m68k_insns(def); - - return 0; -} - void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) -- cgit v1.2.3 From b65df01527038e9def009b6f3d5a2b777695adf9 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 16:56:01 +0000 Subject: Update Changelog. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2866 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index 9aaac1877..bddbe1564 100644 --- a/Changelog +++ b/Changelog @@ -5,6 +5,8 @@ - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) - Several Sparc fixes (Aurelien Jarno, Blue Swirl) - MIPS 64-bit FPU support (Thiemo Seufer) + - Xscale PDA emulation (Andrzei Zaborowski) + - ColdFire system emulation (Paul Brook) version 0.9.0: -- cgit v1.2.3 From 57074f98bb109a1b8b83e1125b151d0426fc97da Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 16:59:05 +0000 Subject: Ignore m68k-softmmu. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2867 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.cvsignore b/.cvsignore index 7d638f64d..830aaa1f1 100644 --- a/.cvsignore +++ b/.cvsignore @@ -38,6 +38,7 @@ mips64el-softmmu mips64-linux-user mips64el-linux-user m68k-linux-user +m68k-softmmu .gdbinit sh4-linux-user sh4-softmmu -- cgit v1.2.3 From db7b5426a4b424249b4aba3496bf14da69a6625b Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 26 May 2007 17:36:03 +0000 Subject: Implement generic sub-page I/O based on earlier work by J. Mayer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2868 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + exec.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 225 insertions(+), 7 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 5f0a7e989..5db290356 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -858,6 +858,7 @@ extern uint8_t *phys_ram_dirty; exception, the write memory callback gets the ram offset instead of the physical address */ #define IO_MEM_ROMD (1) +#define IO_MEM_SUBPAGE (2) typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); diff --git a/exec.c b/exec.c index 1d94ec12e..321d8a566 100644 --- a/exec.c +++ b/exec.c @@ -48,6 +48,7 @@ //#define DEBUG_TLB_CHECK //#define DEBUG_IOPORT +//#define DEBUG_SUBPAGE #if !defined(CONFIG_USER_ONLY) /* TB consistency checks only implemented for usermode emulation. */ @@ -157,6 +158,14 @@ static int tlb_flush_count; static int tb_flush_count; static int tb_phys_invalidate_count; +#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK) +typedef struct subpage_t { + target_phys_addr_t base; + CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE]; + CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE]; + void *opaque[TARGET_PAGE_SIZE]; +} subpage_t; + static void page_init(void) { /* NOTE: we can always suppose that qemu_host_page_size >= @@ -1898,6 +1907,30 @@ static inline void tlb_set_dirty(CPUState *env, } #endif /* defined(CONFIG_USER_ONLY) */ +static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, + int memory); +static void *subpage_init (target_phys_addr_t base, uint32_t *phys, + int orig_memory); +#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \ + need_subpage) \ + do { \ + if (addr > start_addr) \ + start_addr2 = 0; \ + else { \ + start_addr2 = start_addr & ~TARGET_PAGE_MASK; \ + if (start_addr2 > 0) \ + need_subpage = 1; \ + } \ + \ + if (end_addr - addr > TARGET_PAGE_SIZE) \ + end_addr2 = TARGET_PAGE_SIZE - 1; \ + else { \ + end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \ + if (end_addr2 < TARGET_PAGE_SIZE - 1) \ + need_subpage = 1; \ + } \ + } while (0) + /* register physical memory. 'size' must be a multiple of the target page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an io memory page */ @@ -1908,15 +1941,56 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, target_phys_addr_t addr, end_addr; PhysPageDesc *p; CPUState *env; + unsigned long orig_size = size; + void *subpage; + end_addr = start_addr + (target_phys_addr_t)size; size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; - end_addr = start_addr + size; - for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { - p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); - p->phys_offset = phys_offset; - if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || - (phys_offset & IO_MEM_ROMD)) - phys_offset += TARGET_PAGE_SIZE; + for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (p && p->phys_offset != IO_MEM_UNASSIGNED) { + unsigned long orig_memory = p->phys_offset; + target_phys_addr_t start_addr2, end_addr2; + int need_subpage = 0; + + CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, + need_subpage); + if (need_subpage) { + if (!(orig_memory & IO_MEM_SUBPAGE)) { + subpage = subpage_init((addr & TARGET_PAGE_MASK), + &p->phys_offset, orig_memory); + } else { + subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK) + >> IO_MEM_SHIFT]; + } + subpage_register(subpage, start_addr2, end_addr2, phys_offset); + } else { + p->phys_offset = phys_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) + phys_offset += TARGET_PAGE_SIZE; + } + } else { + p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); + p->phys_offset = phys_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) + phys_offset += TARGET_PAGE_SIZE; + else { + target_phys_addr_t start_addr2, end_addr2; + int need_subpage = 0; + + CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, + end_addr2, need_subpage); + + if (need_subpage) { + subpage = subpage_init((addr & TARGET_PAGE_MASK), + &p->phys_offset, IO_MEM_UNASSIGNED); + subpage_register(subpage, start_addr2, end_addr2, + phys_offset); + } + } + } } /* since each CPU stores ram addresses in its TLB cache, we must @@ -2158,6 +2232,149 @@ static CPUWriteMemoryFunc *watch_mem_write[3] = { }; #endif +static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr, + unsigned int len) +{ + CPUReadMemoryFunc **mem_read; + uint32_t ret; + unsigned int idx; + + idx = SUBPAGE_IDX(addr - mmio->base); +#if defined(DEBUG_SUBPAGE) + printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__, + mmio, len, addr, idx); +#endif + mem_read = mmio->mem_read[idx]; + ret = (*mem_read[len])(mmio->opaque[idx], addr); + + return ret; +} + +static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr, + uint32_t value, unsigned int len) +{ + CPUWriteMemoryFunc **mem_write; + unsigned int idx; + + idx = SUBPAGE_IDX(addr - mmio->base); +#if defined(DEBUG_SUBPAGE) + printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__, + mmio, len, addr, idx, value); +#endif + mem_write = mmio->mem_write[idx]; + (*mem_write[len])(mmio->opaque[idx], addr, value); +} + +static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 0); +} + +static void subpage_writeb (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 0); +} + +static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 1); +} + +static void subpage_writew (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 1); +} + +static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); +#endif + + return subpage_readlen(opaque, addr, 2); +} + +static void subpage_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_SUBPAGE) + printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value); +#endif + subpage_writelen(opaque, addr, value, 2); +} + +static CPUReadMemoryFunc *subpage_read[] = { + &subpage_readb, + &subpage_readw, + &subpage_readl, +}; + +static CPUWriteMemoryFunc *subpage_write[] = { + &subpage_writeb, + &subpage_writew, + &subpage_writel, +}; + +static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end, + int memory) +{ + int idx, eidx; + + if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE) + return -1; + idx = SUBPAGE_IDX(start); + eidx = SUBPAGE_IDX(end); +#if defined(DEBUG_SUBPAGE) + printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__, + mmio, start, end, idx, eidx, memory); +#endif + memory >>= IO_MEM_SHIFT; + for (; idx <= eidx; idx++) { + mmio->mem_read[idx] = io_mem_read[memory]; + mmio->mem_write[idx] = io_mem_write[memory]; + mmio->opaque[idx] = io_mem_opaque[memory]; + } + + return 0; +} + +static void *subpage_init (target_phys_addr_t base, uint32_t *phys, + int orig_memory) +{ + subpage_t *mmio; + int subpage_memory; + + mmio = qemu_mallocz(sizeof(subpage_t)); + if (mmio != NULL) { + mmio->base = base; + subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio); +#if defined(DEBUG_SUBPAGE) + printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__, + mmio, base, TARGET_PAGE_SIZE, subpage_memory); +#endif + *phys = subpage_memory | IO_MEM_SUBPAGE; + subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory); + } + + return mmio; +} + static void io_mem_init(void) { cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL); -- cgit v1.2.3 From 5aca8c3b2fbada188ff86781fba24685d346cef9 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 26 May 2007 17:39:43 +0000 Subject: Split DMA controller in two Fix register size related bugs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2869 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cs4231.c | 3 ++- hw/esp.c | 29 ++++++++++++---------- hw/pcnet.c | 4 ++- hw/slavio_intctl.c | 7 ++++-- hw/slavio_misc.c | 22 +++++++++++------ hw/slavio_serial.c | 7 +++--- hw/slavio_timer.c | 3 ++- hw/sparc32_dma.c | 72 +++++++++++++++++++++++------------------------------- hw/sun4m.c | 13 +++++----- vl.h | 9 +++---- 10 files changed, 87 insertions(+), 82 deletions(-) diff --git a/hw/cs4231.c b/hw/cs4231.c index 6df881d41..390ef746f 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -30,6 +30,7 @@ * In addition to Crystal CS4231 there is a DMA controller on Sparc. */ #define CS_MAXADDR 0x3f +#define CS_SIZE (CS_MAXADDR + 1) #define CS_REGS 16 #define CS_DREGS 32 #define CS_MAXDREG (CS_DREGS - 1) @@ -173,7 +174,7 @@ void cs_init(target_phys_addr_t base, int irq, void *intctl) return; cs_io_memory = cpu_register_io_memory(0, cs_mem_read, cs_mem_write, s); - cpu_register_physical_memory(base, CS_MAXADDR, cs_io_memory); + cpu_register_physical_memory(base, CS_SIZE, cs_io_memory); register_savevm("cs4231", base, 1, cs_save, cs_load, s); qemu_register_reset(cs_reset, s); cs_reset(s); diff --git a/hw/esp.c b/hw/esp.c index 65feaea6e..627d90cab 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -41,7 +41,9 @@ do { printf("ESP: " fmt , ##args); } while (0) #define DPRINTF(fmt, args...) #endif -#define ESP_MAXREG 0x3f +#define ESP_MASK 0x3f +#define ESP_REGS 16 +#define ESP_SIZE (ESP_REGS * 4) #define TI_BUFSZ 32 /* The HBA is ID 7, so for simplicitly limit to 7 devices. */ #define ESP_MAX_DEVS 7 @@ -50,8 +52,8 @@ typedef struct ESPState ESPState; struct ESPState { BlockDriverState **bd; - uint8_t rregs[ESP_MAXREG]; - uint8_t wregs[ESP_MAXREG]; + uint8_t rregs[ESP_REGS]; + uint8_t wregs[ESP_REGS]; int32_t ti_size; uint32_t ti_rptr, ti_wptr; uint8_t ti_buf[TI_BUFSZ]; @@ -327,12 +329,12 @@ static void handle_ti(ESPState *s) } } -void esp_reset(void *opaque) +static void esp_reset(void *opaque) { ESPState *s = opaque; - memset(s->rregs, 0, ESP_MAXREG); - memset(s->wregs, 0, ESP_MAXREG); + memset(s->rregs, 0, ESP_REGS); + memset(s->wregs, 0, ESP_REGS); s->rregs[0x0e] = 0x4; // Indicate fas100a s->ti_size = 0; s->ti_rptr = 0; @@ -346,7 +348,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) ESPState *s = opaque; uint32_t saddr; - saddr = (addr & ESP_MAXREG) >> 2; + saddr = (addr & ESP_MASK) >> 2; DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); switch (saddr) { case 2: @@ -384,7 +386,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) ESPState *s = opaque; uint32_t saddr; - saddr = (addr & ESP_MAXREG) >> 2; + saddr = (addr & ESP_MASK) >> 2; DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); switch (saddr) { case 0: @@ -501,8 +503,8 @@ static void esp_save(QEMUFile *f, void *opaque) { ESPState *s = opaque; - qemu_put_buffer(f, s->rregs, ESP_MAXREG); - qemu_put_buffer(f, s->wregs, ESP_MAXREG); + qemu_put_buffer(f, s->rregs, ESP_REGS); + qemu_put_buffer(f, s->wregs, ESP_REGS); qemu_put_be32s(f, &s->ti_size); qemu_put_be32s(f, &s->ti_rptr); qemu_put_be32s(f, &s->ti_wptr); @@ -523,8 +525,8 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id) if (version_id != 3) return -EINVAL; // Cannot emulate 2 - qemu_get_buffer(f, s->rregs, ESP_MAXREG); - qemu_get_buffer(f, s->wregs, ESP_MAXREG); + qemu_get_buffer(f, s->rregs, ESP_REGS); + qemu_get_buffer(f, s->wregs, ESP_REGS); qemu_get_be32s(f, &s->ti_size); qemu_get_be32s(f, &s->ti_rptr); qemu_get_be32s(f, &s->ti_wptr); @@ -574,9 +576,10 @@ void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, s->bd = bd; s->dma_opaque = dma_opaque; + sparc32_dma_set_reset_data(dma_opaque, esp_reset, s); esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); - cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory); + cpu_register_physical_memory(espaddr, ESP_SIZE, esp_io_memory); esp_reset(s); diff --git a/hw/pcnet.c b/hw/pcnet.c index 12d973479..4c4278ffa 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1554,7 +1554,7 @@ static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) return val; } -void pcnet_h_reset(void *opaque) +static void pcnet_h_reset(void *opaque) { PCNetState *s = opaque; int i; @@ -2032,6 +2032,8 @@ void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); d->dma_opaque = dma_opaque; + sparc32_dma_set_reset_data(dma_opaque, pcnet_h_reset, d); + cpu_register_physical_memory(leaddr, 4, lance_io_memory); d->irq = irq; diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 2d1f6552e..7f93b22e3 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -58,7 +58,9 @@ typedef struct SLAVIO_INTCTLState { } SLAVIO_INTCTLState; #define INTCTL_MAXADDR 0xf +#define INTCTL_SIZE (INTCTL_MAXADDR + 1) #define INTCTLM_MAXADDR 0x13 +#define INTCTLM_SIZE (INTCTLM_MAXADDR + 1) #define INTCTLM_MASK 0x1f static void slavio_check_interrupts(void *opaque); @@ -386,11 +388,12 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, s->intbit_to_level = intbit_to_level; for (i = 0; i < MAX_CPUS; i++) { slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); - cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory); + cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, + slavio_intctl_io_memory); } slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); - cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory); + cpu_register_physical_memory(addrg, INTCTLM_SIZE, slavio_intctlm_io_memory); register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); qemu_register_reset(slavio_intctl_reset, s); diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 100723824..e8a4ea4d4 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -47,7 +47,7 @@ typedef struct MiscState { uint8_t diag, mctrl, sysctrl; } MiscState; -#define MISC_MAXADDR 1 +#define MISC_SIZE 1 static void slavio_misc_update_irq(void *opaque) { @@ -224,19 +224,25 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s); // Slavio control - cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory); + cpu_register_physical_memory(base + 0x1800000, MISC_SIZE, + slavio_misc_io_memory); // AUX 1 - cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory); + cpu_register_physical_memory(base + 0x1900000, MISC_SIZE, + slavio_misc_io_memory); // AUX 2 - cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory); + cpu_register_physical_memory(base + 0x1910000, MISC_SIZE, + slavio_misc_io_memory); // Diagnostics - cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory); + cpu_register_physical_memory(base + 0x1a00000, MISC_SIZE, + slavio_misc_io_memory); // Modem control - cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory); + cpu_register_physical_memory(base + 0x1b00000, MISC_SIZE, + slavio_misc_io_memory); // System control - cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory); + cpu_register_physical_memory(base + 0x1f00000, MISC_SIZE, + slavio_misc_io_memory); // Power management - cpu_register_physical_memory(power_base, MISC_MAXADDR, slavio_misc_io_memory); + cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory); s->irq = irq; diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 3da40eb6c..0a2c87330 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -102,6 +102,7 @@ struct SerialState { }; #define SERIAL_MAXADDR 7 +#define SERIAL_SIZE (SERIAL_MAXADDR + 1) static void handle_kbd_command(ChannelState *s, int val); static int serial_can_receive(void *opaque); @@ -178,7 +179,7 @@ static void slavio_serial_reset_chn(ChannelState *s) int i; s->reg = 0; - for (i = 0; i < SERIAL_MAXADDR; i++) { + for (i = 0; i < SERIAL_SIZE; i++) { s->rregs[i] = 0; s->wregs[i] = 0; } @@ -598,7 +599,7 @@ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, return NULL; slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); - cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); + cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory); s->chn[0].chr = chr1; s->chn[1].chr = chr2; @@ -723,7 +724,7 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq) s->chn[1].type = kbd; slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); - cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); + cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory); qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, "QEMU Sun Mouse"); qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index e8b435f1c..6bc293e67 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -59,6 +59,7 @@ typedef struct SLAVIO_TIMERState { } SLAVIO_TIMERState; #define TIMER_MAXADDR 0x1f +#define TIMER_SIZE (TIMER_MAXADDR + 1) // Update count, set irq, update expire_time // Convert from ptimer countdown units @@ -260,7 +261,7 @@ void slavio_timer_init(target_phys_addr_t addr, int irq, int mode, slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, slavio_timer_mem_write, s); - cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory); + cpu_register_physical_memory(addr, TIMER_SIZE, slavio_timer_io_memory); register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s); qemu_register_reset(slavio_timer_reset, s); slavio_timer_reset(s); diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index e1baee8b8..de1499876 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -41,22 +41,25 @@ do { printf("DMA: " fmt , ##args); } while (0) #define DPRINTF(fmt, args...) #endif -#define DMA_REGS 8 -#define DMA_MAXADDR (DMA_REGS * 4 - 1) +#define DMA_REGS 4 +#define DMA_SIZE (4 * sizeof(uint32_t)) +#define DMA_MAXADDR (DMA_SIZE - 1) #define DMA_VER 0xa0000000 #define DMA_INTR 1 #define DMA_INTREN 0x10 #define DMA_WRITE_MEM 0x100 #define DMA_LOADED 0x04000000 +#define DMA_DRAIN_FIFO 0x40 #define DMA_RESET 0x80 typedef struct DMAState DMAState; struct DMAState { uint32_t dmaregs[DMA_REGS]; - qemu_irq espirq, leirq; - void *iommu, *esp_opaque, *lance_opaque; + qemu_irq irq; + void *iommu, *dev_opaque; + void (*dev_reset)(void *dev_opaque); qemu_irq *pic; }; @@ -69,7 +72,7 @@ void ledma_memory_read(void *opaque, target_phys_addr_t addr, DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n", s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); - addr |= s->dmaregs[7]; + addr |= s->dmaregs[3]; if (do_bswap) { sparc_iommu_memory_read(s->iommu, addr, buf, len); } else { @@ -91,7 +94,7 @@ void ledma_memory_write(void *opaque, target_phys_addr_t addr, DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n", s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); - addr |= s->dmaregs[7]; + addr |= s->dmaregs[3]; if (do_bswap) { sparc_iommu_memory_write(s->iommu, addr, buf, len); } else { @@ -118,7 +121,7 @@ void espdma_raise_irq(void *opaque) DPRINTF("Raise ESP IRQ\n"); s->dmaregs[0] |= DMA_INTR; - qemu_irq_raise(s->espirq); + qemu_irq_raise(s->irq); } void espdma_clear_irq(void *opaque) @@ -127,7 +130,7 @@ void espdma_clear_irq(void *opaque) s->dmaregs[0] &= ~DMA_INTR; DPRINTF("Lower ESP IRQ\n"); - qemu_irq_lower(s->espirq); + qemu_irq_lower(s->irq); } void espdma_memory_read(void *opaque, uint8_t *buf, int len) @@ -158,7 +161,8 @@ static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr) uint32_t saddr; saddr = (addr & DMA_MAXADDR) >> 2; - DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->dmaregs[saddr]); + DPRINTF("read dmareg " TARGET_FMT_plx ": 0x%8.8x\n", addr, + s->dmaregs[saddr]); return s->dmaregs[saddr]; } @@ -169,37 +173,26 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) uint32_t saddr; saddr = (addr & DMA_MAXADDR) >> 2; - DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->dmaregs[saddr], val); + DPRINTF("write dmareg " TARGET_FMT_plx ": 0x%8.8x -> 0x%8.8x\n", addr, + s->dmaregs[saddr], val); switch (saddr) { case 0: if (!(val & DMA_INTREN)) { - DPRINTF("Lower ESP IRQ\n"); - qemu_irq_lower(s->espirq); + DPRINTF("Lower IRQ\n"); + qemu_irq_lower(s->irq); } if (val & DMA_RESET) { - esp_reset(s->esp_opaque); - } else if (val & 0x40) { - val &= ~0x40; + s->dev_reset(s->dev_opaque); + } else if (val & DMA_DRAIN_FIFO) { + val &= ~DMA_DRAIN_FIFO; } else if (val == 0) - val = 0x40; + val = DMA_DRAIN_FIFO; val &= 0x0fffffff; val |= DMA_VER; break; case 1: s->dmaregs[0] |= DMA_LOADED; break; - case 4: - /* ??? Should this mask out the lance IRQ? The NIC may re-assert - this IRQ unexpectedly. */ - if (!(val & DMA_INTREN)) { - DPRINTF("Lower Lance IRQ\n"); - qemu_irq_lower(s->leirq); - } - if (val & DMA_RESET) - pcnet_h_reset(s->lance_opaque); - val &= 0x0fffffff; - val |= DMA_VER; - break; default: break; } @@ -222,9 +215,8 @@ static void dma_reset(void *opaque) { DMAState *s = opaque; - memset(s->dmaregs, 0, DMA_REGS * 4); + memset(s->dmaregs, 0, DMA_SIZE); s->dmaregs[0] = DMA_VER; - s->dmaregs[4] = DMA_VER; } static void dma_save(QEMUFile *f, void *opaque) @@ -241,7 +233,7 @@ static int dma_load(QEMUFile *f, void *opaque, int version_id) DMAState *s = opaque; unsigned int i; - if (version_id != 1) + if (version_id != 2) return -EINVAL; for (i = 0; i < DMA_REGS; i++) qemu_get_be32s(f, &s->dmaregs[i]); @@ -249,8 +241,7 @@ static int dma_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq espirq, - qemu_irq leirq, void *iommu) +void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq irq, void *iommu) { DMAState *s; int dma_io_memory; @@ -259,24 +250,23 @@ void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq espirq, if (!s) return NULL; - s->espirq = espirq; - s->leirq = leirq; + s->irq = irq; s->iommu = iommu; dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s); - cpu_register_physical_memory(daddr, 16 * 2, dma_io_memory); + cpu_register_physical_memory(daddr, DMA_SIZE, dma_io_memory); - register_savevm("sparc32_dma", daddr, 1, dma_save, dma_load, s); + register_savevm("sparc32_dma", daddr, 2, dma_save, dma_load, s); qemu_register_reset(dma_reset, s); return s; } -void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque, - void *lance_opaque) +void sparc32_dma_set_reset_data(void *opaque, void (*dev_reset)(void *opaque), + void *dev_opaque) { DMAState *s = opaque; - s->esp_opaque = esp_opaque; - s->lance_opaque = lance_opaque; + s->dev_reset = dev_reset; + s->dev_opaque = dev_opaque; } diff --git a/hw/sun4m.c b/hw/sun4m.c index 313e5b4aa..10473baa4 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -262,7 +262,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, { CPUState *env, *envs[MAX_CPUS]; unsigned int i; - void *iommu, *dma, *main_esp, *main_lance = NULL; + void *iommu, *espdma, *ledma, *main_esp, *main_lance = NULL; const sparc_def_t *def; qemu_irq *slavio_irq; @@ -295,8 +295,10 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, for(i = 0; i < smp_cpus; i++) { slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } - dma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], - slavio_irq[hwdef->le_irq], iommu); + espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], + iommu); + ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, + slavio_irq[hwdef->le_irq], iommu); if (graphic_depth != 8 && graphic_depth != 24) { fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); @@ -307,7 +309,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { - main_lance = lance_init(&nd_table[0], hwdef->le_base, dma, + main_lance = lance_init(&nd_table[0], hwdef->le_base, ledma, slavio_irq[hwdef->le_irq]); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); @@ -329,7 +331,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], serial_hds[1], serial_hds[0]); fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table); - main_esp = esp_init(bs_table, hwdef->esp_base, dma); + main_esp = esp_init(bs_table, hwdef->esp_base, espdma); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { @@ -341,7 +343,6 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, slavio_irq[hwdef->me_irq]); if (hwdef->cs_base != (target_phys_addr_t)-1) cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); - sparc32_dma_set_reset_data(dma, main_esp, main_lance); } static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, diff --git a/vl.h b/vl.h index 497cf8da5..6d90aeb05 100644 --- a/vl.h +++ b/vl.h @@ -1046,7 +1046,6 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); /* pcnet.c */ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); -void pcnet_h_reset(void *opaque); void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, qemu_irq irq); @@ -1265,11 +1264,9 @@ void slavio_set_power_fail(void *opaque, int power_failing); void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, void *dma_opaque); -void esp_reset(void *opaque); /* sparc32_dma.c */ -void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq espirq, - qemu_irq leirq, void *iommu); +void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq irq, void *iommu); void ledma_set_irq(void *opaque, int isr); void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); @@ -1279,8 +1276,8 @@ void espdma_raise_irq(void *opaque); void espdma_clear_irq(void *opaque); void espdma_memory_read(void *opaque, uint8_t *buf, int len); void espdma_memory_write(void *opaque, uint8_t *buf, int len); -void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque, - void *lance_opaque); +void sparc32_dma_set_reset_data(void *opaque, void (*dev_reset)(void *opaque), + void *dev_opaque); /* cs4231.c */ void cs_init(target_phys_addr_t base, int irq, void *intctl); -- cgit v1.2.3 From e6dbd3b3f08318196cbdb1f0c23a7eefd9b38cb7 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 21:16:48 +0000 Subject: M68k extended addressing modes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2870 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/cpu.h | 3 +- target-m68k/translate.c | 147 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 121 insertions(+), 29 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 3a1a13888..a81b91dff 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -160,7 +160,8 @@ enum m68k_features { M68K_FEATURE_CF_FPU, M68K_FEATURE_CF_MAC, M68K_FEATURE_CF_EMAC, - M68K_FEATURE_EXT_FULL /* 68020+ full extension word. */ + M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */ + M68K_FEATURE_WORD_INDEX /* word sized address index registers. */ }; static inline int m68k_feature(CPUM68KState *env, int feature) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index b9b16b5c0..93879c930 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -42,6 +42,7 @@ static inline void qemu_assert(int cond, const char *msg) /* internal defines */ typedef struct DisasContext { + CPUM68KState *env; target_ulong pc; int is_jmp; int cc_op; @@ -198,50 +199,139 @@ static int gen_ldst(DisasContext *s, int opsize, int addr, int val) } } +/* Read a 32-bit immediate constant. */ +static inline uint32_t read_im32(DisasContext *s) +{ + uint32_t im; + im = ((uint32_t)lduw_code(s->pc)) << 16; + s->pc += 2; + im |= lduw_code(s->pc); + s->pc += 2; + return im; +} + +/* Calculate and address index. */ +static int gen_addr_index(uint16_t ext, int tmp) +{ + int add; + int scale; + + add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12); + if ((ext & 0x800) == 0) { + gen_op_ext16s32(tmp, add); + add = tmp; + } + scale = (ext >> 9) & 3; + if (scale != 0) { + gen_op_shl32(tmp, add, gen_im32(scale)); + add = tmp; + } + return add; +} + /* Handle a base + index + displacement effective addresss. A base of -1 means pc-relative. */ static int gen_lea_indexed(DisasContext *s, int opsize, int base) { - int scale; uint32_t offset; uint16_t ext; int add; int tmp; + uint32_t bd, od; offset = s->pc; ext = lduw_code(s->pc); s->pc += 2; - tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0); - /* ??? Check W/L bit. */ - scale = (ext >> 9) & 3; - if (scale == 0) { - add = tmp; - } else { - add = gen_new_qreg(QMODE_I32); - gen_op_shl32(add, tmp, gen_im32(scale)); - } - tmp = gen_new_qreg(QMODE_I32); - if (base != -1) { - gen_op_add32(tmp, base, gen_im32((int8_t)ext)); - gen_op_add32(tmp, tmp, add); + + if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) + return -1; + + if (ext & 0x100) { + /* full extension word format */ + if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) + return -1; + + if ((ext & 0x30) > 0x10) { + /* base displacement */ + if ((ext & 0x30) == 0x20) { + bd = (int16_t)lduw_code(s->pc); + s->pc += 2; + } else { + bd = read_im32(s); + } + } else { + bd = 0; + } + tmp = gen_new_qreg(QMODE_I32); + if ((ext & 0x44) == 0) { + /* pre-index */ + add = gen_addr_index(ext, tmp); + } else { + add = QREG_NULL; + } + if ((ext & 0x80) == 0) { + /* base not suppressed */ + if (base == -1) { + base = gen_im32(offset + bd); + bd = 0; + } + if (add) { + gen_op_add32(tmp, add, base); + add = tmp; + } else { + add = base; + } + } + if (add) { + if (bd != 0) { + gen_op_add32(tmp, add, gen_im32(bd)); + add = tmp; + } + } else { + add = gen_im32(bd); + } + if ((ext & 3) != 0) { + /* memory indirect */ + base = gen_load(s, OS_LONG, add, 0); + if ((ext & 0x44) == 4) { + add = gen_addr_index(ext, tmp); + gen_op_add32(tmp, add, base); + add = tmp; + } else { + add = base; + } + if ((ext & 3) > 1) { + /* outer displacement */ + if ((ext & 3) == 2) { + od = (int16_t)lduw_code(s->pc); + s->pc += 2; + } else { + od = read_im32(s); + } + } else { + od = 0; + } + if (od != 0) { + gen_op_add32(add, tmp, gen_im32(od)); + add = tmp; + } + } } else { - gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext)); + /* brief extension word format */ + tmp = gen_new_qreg(QMODE_I32); + add = gen_addr_index(ext, tmp); + if (base != -1) { + gen_op_add32(tmp, add, base); + if ((int8_t)ext) + gen_op_add32(tmp, tmp, gen_im32((int8_t)ext)); + } else { + gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext)); + } + add = tmp; } - return tmp; -} - -/* Read a 32-bit immediate constant. */ -static inline uint32_t read_im32(DisasContext *s) -{ - uint32_t im; - im = ((uint32_t)lduw_code(s->pc)) << 16; - s->pc += 2; - im |= lduw_code(s->pc); - s->pc += 2; - return im; + return add; } - /* Update the CPU env CC_OP state. */ static inline void gen_flush_cc_op(DisasContext *s) { @@ -2721,6 +2811,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; + dc->env = env; dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; dc->cc_op = CC_OP_DYNAMIC; -- cgit v1.2.3 From 510ff0b730d1ba25a382ac3f6f73571ea731b8e5 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 22:11:13 +0000 Subject: Generate m68k address faults. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2871 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/translate.c | 131 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 43 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 93879c930..6ee35f07b 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -43,6 +43,7 @@ static inline void qemu_assert(int cond, const char *msg) /* internal defines */ typedef struct DisasContext { CPUM68KState *env; + target_ulong insn_pc; /* Start of the current instruction. */ target_ulong pc; int is_jmp; int cc_op; @@ -437,8 +438,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) switch ((insn >> 3) & 7) { case 0: /* Data register direct. */ case 1: /* Address register direct. */ - /* ??? generate bad addressing mode fault. */ - qemu_assert(0, "invalid addressing mode"); + return -1; case 2: /* Indirect register */ case 3: /* Indirect postincrement. */ reg += QREG_A0; @@ -477,8 +477,7 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize) return gen_lea_indexed(s, opsize, -1); case 4: /* Immediate. */ default: - /* ??? generate bad addressing mode fault. */ - qemu_assert(0, "invalid addressing mode"); + return -1; } } /* Should never happen. */ @@ -496,6 +495,8 @@ static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize, tmp = *addrp; } else { tmp = gen_lea(s, insn, opsize); + if (tmp == -1) + return -1; if (addrp) *addrp = tmp; } @@ -548,6 +549,8 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, tmp = *addrp; } else { tmp = gen_lea(s, insn, opsize); + if (tmp == -1) + return -1; if (addrp) *addrp = tmp; } @@ -595,7 +598,7 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val, } return gen_im32(offset); default: - qemu_assert(0, "invalid addressing mode"); + return -1; } } /* Should never happen. */ @@ -753,6 +756,27 @@ static void gen_exception(DisasContext *s, uint32_t where, int nr) gen_op_raise_exception(nr); } +static inline void gen_addr_fault(DisasContext *s) +{ + gen_exception(s, s->insn_pc, EXCP_ADDRESS); +} + +#define SRC_EA(result, opsize, val, addrp) do { \ + result = gen_ea(s, insn, opsize, val, addrp); \ + if (result == -1) { \ + gen_addr_fault(s); \ + return; \ + } \ + } while (0) + +#define DEST_EA(insn, opsize, val, addrp) do { \ + int ea_result = gen_ea(s, insn, opsize, val, addrp); \ + if (ea_result == -1) { \ + gen_addr_fault(s); \ + return; \ + } \ + } while (0) + /* Generate a jump to an immediate address. */ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) { @@ -806,7 +830,7 @@ DISAS_INSN(mulw) gen_op_ext16s32(tmp, reg); else gen_op_ext16u32(tmp, reg); - src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL); + SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL); gen_op_mul32(tmp, tmp, src); gen_op_mov32(reg, tmp); /* Unlike m68k, coldfire always clears the overflow bit. */ @@ -827,7 +851,7 @@ DISAS_INSN(divw) } else { gen_op_ext16u32(QREG_DIV1, reg); } - src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL); + SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL); gen_op_mov32(QREG_DIV2, src); if (sign) { gen_op_divs(1); @@ -860,7 +884,7 @@ DISAS_INSN(divl) num = DREG(ext, 12); reg = DREG(ext, 0); gen_op_mov32(QREG_DIV1, num); - den = gen_ea(s, insn, OS_LONG, 0, NULL); + SRC_EA(den, OS_LONG, 0, NULL); gen_op_mov32(QREG_DIV2, den); if (ext & 0x0800) { gen_op_divs(2); @@ -891,11 +915,11 @@ DISAS_INSN(addsub) reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); if (insn & 0x100) { - tmp = gen_ea(s, insn, OS_LONG, 0, &addr); + SRC_EA(tmp, OS_LONG, 0, &addr); src = reg; } else { tmp = reg; - src = gen_ea(s, insn, OS_LONG, 0, NULL); + SRC_EA(src, OS_LONG, 0, NULL); } if (add) { gen_op_add32(dest, tmp, src); @@ -908,7 +932,7 @@ DISAS_INSN(addsub) } gen_op_update_cc_add(dest, src); if (insn & 0x100) { - gen_ea(s, insn, OS_LONG, dest, &addr); + DEST_EA(insn, OS_LONG, dest, &addr); } else { gen_op_mov32(reg, dest); } @@ -966,7 +990,7 @@ DISAS_INSN(bitop_reg) else opsize = OS_LONG; op = (insn >> 6) & 3; - src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL); + SRC_EA(src1, opsize, 0, op ? &addr: NULL); src2 = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); @@ -996,7 +1020,7 @@ DISAS_INSN(bitop_reg) break; } if (op) - gen_ea(s, insn, opsize, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } DISAS_INSN(sats) @@ -1041,6 +1065,10 @@ DISAS_INSN(movem) mask = lduw_code(s->pc); s->pc += 2; tmp = gen_lea(s, insn, OS_LONG); + if (tmp == -1) { + gen_addr_fault(s); + return; + } addr = gen_new_qreg(QMODE_I32); gen_op_mov32(addr, tmp); is_load = ((insn & 0x0400) != 0); @@ -1086,7 +1114,7 @@ DISAS_INSN(bitop_im) return; } - src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL); + SRC_EA(src1, opsize, 0, op ? &addr: NULL); gen_flush_flags(s); tmp = gen_new_qreg(QMODE_I32); @@ -1116,7 +1144,7 @@ DISAS_INSN(bitop_im) break; } if (op) - gen_ea(s, insn, opsize, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } DISAS_INSN(arith_im) @@ -1128,7 +1156,7 @@ DISAS_INSN(arith_im) int addr; op = (insn >> 9) & 7; - src1 = gen_ea(s, insn, OS_LONG, 0, (op == 6) ? NULL : &addr); + SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr); src2 = gen_im32(read_im32(s)); dest = gen_new_qreg(QMODE_I32); switch (op) { @@ -1168,7 +1196,7 @@ DISAS_INSN(arith_im) abort(); } if (op != 6) { - gen_ea(s, insn, OS_LONG, dest, &addr); + DEST_EA(insn, OS_LONG, dest, &addr); } } @@ -1200,7 +1228,7 @@ DISAS_INSN(move) default: abort(); } - src = gen_ea(s, insn, opsize, -1, NULL); + SRC_EA(src, opsize, -1, NULL); op = (insn >> 6) & 7; if (op == 1) { /* movea */ @@ -1211,7 +1239,7 @@ DISAS_INSN(move) /* normal move */ uint16_t dest_ea; dest_ea = ((insn >> 9) & 7) | (op << 3); - gen_ea(s, dest_ea, opsize, src, NULL); + DEST_EA(dest_ea, opsize, src, NULL); /* This will be correct because loads sign extend. */ gen_logic_cc(s, src); } @@ -1247,6 +1275,10 @@ DISAS_INSN(lea) reg = AREG(insn, 9); tmp = gen_lea(s, insn, OS_LONG); + if (tmp == -1) { + gen_addr_fault(s); + return; + } gen_op_mov32(reg, tmp); } @@ -1267,7 +1299,7 @@ DISAS_INSN(clr) default: abort(); } - gen_ea (s, insn, opsize, gen_im32(0), NULL); + DEST_EA(insn, opsize, gen_im32(0), NULL); gen_logic_cc(s, gen_im32(0)); } @@ -1384,6 +1416,10 @@ DISAS_INSN(pea) int tmp; tmp = gen_lea(s, insn, OS_LONG); + if (tmp == -1) { + gen_addr_fault(s); + return; + } gen_push(s, tmp); } @@ -1425,7 +1461,7 @@ DISAS_INSN(tst) default: abort(); } - tmp = gen_ea(s, insn, opsize, -1, NULL); + SRC_EA(tmp, opsize, -1, NULL); gen_logic_cc(s, tmp); } @@ -1447,10 +1483,10 @@ DISAS_INSN(tas) int addr; dest = gen_new_qreg(QMODE_I32); - src1 = gen_ea(s, insn, OS_BYTE, -1, &addr); + SRC_EA(src1, OS_BYTE, -1, &addr); gen_logic_cc(s, src1); gen_op_or32(dest, src1, gen_im32(0x80)); - gen_ea(s, insn, OS_BYTE, dest, &addr); + DEST_EA(insn, OS_BYTE, dest, &addr); } DISAS_INSN(mull) @@ -1469,7 +1505,7 @@ DISAS_INSN(mull) return; } reg = DREG(ext, 12); - src1 = gen_ea(s, insn, OS_LONG, 0, NULL); + SRC_EA(src1, OS_LONG, 0, NULL); dest = gen_new_qreg(QMODE_I32); gen_op_mul32(dest, src1, reg); gen_op_mov32(reg, dest); @@ -1528,6 +1564,10 @@ DISAS_INSN(jump) /* Load the target address first to ensure correct exception behavior. */ tmp = gen_lea(s, insn, OS_LONG); + if (tmp == -1) { + gen_addr_fault(s); + return; + } if ((insn & 0x40) == 0) { /* jsr */ gen_push(s, gen_im32(s->pc)); @@ -1543,7 +1583,7 @@ DISAS_INSN(addsubq) int val; int addr; - src1 = gen_ea(s, insn, OS_LONG, 0, &addr); + SRC_EA(src1, OS_LONG, 0, &addr); val = (insn >> 9) & 7; if (val == 0) val = 8; @@ -1570,7 +1610,7 @@ DISAS_INSN(addsubq) } gen_op_update_cc_add(dest, src2); } - gen_ea(s, insn, OS_LONG, dest, &addr); + DEST_EA(insn, OS_LONG, dest, &addr); } DISAS_INSN(tpf) @@ -1642,7 +1682,7 @@ DISAS_INSN(mvzs) opsize = OS_WORD; else opsize = OS_BYTE; - src = gen_ea(s, insn, opsize, (insn & 0x80) ? 0 : -1, NULL); + SRC_EA(src, opsize, (insn & 0x80) ? 0 : -1, NULL); reg = DREG(insn, 9); gen_op_mov32(reg, src); gen_logic_cc(s, src); @@ -1658,11 +1698,11 @@ DISAS_INSN(or) reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); if (insn & 0x100) { - src = gen_ea(s, insn, OS_LONG, 0, &addr); + SRC_EA(src, OS_LONG, 0, &addr); gen_op_or32(dest, src, reg); - gen_ea(s, insn, OS_LONG, dest, &addr); + DEST_EA(insn, OS_LONG, dest, &addr); } else { - src = gen_ea(s, insn, OS_LONG, 0, NULL); + SRC_EA(src, OS_LONG, 0, NULL); gen_op_or32(dest, src, reg); gen_op_mov32(reg, dest); } @@ -1674,7 +1714,7 @@ DISAS_INSN(suba) int src; int reg; - src = gen_ea(s, insn, OS_LONG, 0, NULL); + SRC_EA(src, OS_LONG, 0, NULL); reg = AREG(insn, 9); gen_op_sub32(reg, reg, src); } @@ -1714,7 +1754,7 @@ DISAS_INSN(mov3q) val = -1; src = gen_im32(val); gen_logic_cc(s, src); - gen_ea(s, insn, OS_LONG, src, NULL); + DEST_EA(insn, OS_LONG, src, NULL); } DISAS_INSN(cmp) @@ -1742,7 +1782,7 @@ DISAS_INSN(cmp) default: abort(); } - src = gen_ea(s, insn, opsize, -1, NULL); + SRC_EA(src, opsize, -1, NULL); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); gen_op_sub32(dest, reg, src); @@ -1761,7 +1801,7 @@ DISAS_INSN(cmpa) } else { opsize = OS_WORD; } - src = gen_ea(s, insn, opsize, -1, NULL); + SRC_EA(src, opsize, -1, NULL); reg = AREG(insn, 9); dest = gen_new_qreg(QMODE_I32); gen_op_sub32(dest, reg, src); @@ -1776,12 +1816,12 @@ DISAS_INSN(eor) int dest; int addr; - src = gen_ea(s, insn, OS_LONG, 0, &addr); + SRC_EA(src, OS_LONG, 0, &addr); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); gen_op_xor32(dest, src, reg); gen_logic_cc(s, dest); - gen_ea(s, insn, OS_LONG, dest, &addr); + DEST_EA(insn, OS_LONG, dest, &addr); } DISAS_INSN(and) @@ -1794,11 +1834,11 @@ DISAS_INSN(and) reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); if (insn & 0x100) { - src = gen_ea(s, insn, OS_LONG, 0, &addr); + SRC_EA(src, OS_LONG, 0, &addr); gen_op_and32(dest, src, reg); - gen_ea(s, insn, OS_LONG, dest, &addr); + DEST_EA(insn, OS_LONG, dest, &addr); } else { - src = gen_ea(s, insn, OS_LONG, 0, NULL); + SRC_EA(src, OS_LONG, 0, NULL); gen_op_and32(dest, src, reg); gen_op_mov32(reg, dest); } @@ -1810,7 +1850,7 @@ DISAS_INSN(adda) int src; int reg; - src = gen_ea(s, insn, OS_LONG, 0, NULL); + SRC_EA(src, OS_LONG, 0, NULL); reg = AREG(insn, 9); gen_op_add32(reg, reg, src); } @@ -2114,7 +2154,7 @@ DISAS_INSN(fpu) default: goto undef; } - gen_ea(s, insn, opsize, res, NULL); + DEST_EA(insn, opsize, res, NULL); return; case 4: /* fmove to control register. */ switch ((ext >> 10) & 7) { @@ -2141,7 +2181,7 @@ DISAS_INSN(fpu) (ext >> 10) & 7); goto undef; } - gen_ea(s, insn, OS_LONG, res, NULL); + DEST_EA(insn, OS_LONG, res, NULL); break; case 6: /* fmovem */ case 7: @@ -2151,6 +2191,10 @@ DISAS_INSN(fpu) if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) goto undef; src = gen_lea(s, insn, OS_LONG); + if (src == -1) { + gen_addr_fault(s); + return; + } addr = gen_new_qreg(QMODE_I32); gen_op_mov32(addr, src); mask = 0x80; @@ -2186,7 +2230,7 @@ DISAS_INSN(fpu) default: goto undef; } - tmp = gen_ea(s, insn, opsize, -1, NULL); + SRC_EA(tmp, opsize, -1, NULL); if (opsize == OS_DOUBLE) { src = tmp; } else { @@ -2846,6 +2890,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, gen_opc_instr_start[lj] = 1; } last_cc_op = dc->cc_op; + dc->insn_pc = dc->pc; disas_m68k_insn(env, dc); } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && -- cgit v1.2.3 From 2bc1abb7cd9b1f9a275f57221e76a2cd52ce6168 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 26 May 2007 23:48:38 +0000 Subject: Fix typo in m68k outer displacement addressing (Andreas Schwab). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2872 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 6ee35f07b..10b733fa0 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -313,7 +313,7 @@ static int gen_lea_indexed(DisasContext *s, int opsize, int base) od = 0; } if (od != 0) { - gen_op_add32(add, tmp, gen_im32(od)); + gen_op_add32(tmp, add, gen_im32(od)); add = tmp; } } -- cgit v1.2.3 From 70c0de96a3ed38d9e9a67bddea0f35a871aac095 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 16:36:10 +0000 Subject: Use qemu_irqs between dma controllers and esp, lance git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2873 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 20 +++++++++++--------- hw/pcnet.c | 6 ++---- hw/sparc32_dma.c | 30 ++++++++++++++---------------- hw/sun4m.c | 13 ++++++------- vl.h | 10 ++++------ 5 files changed, 37 insertions(+), 42 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 627d90cab..5a7e4ac6b 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -51,6 +51,7 @@ do { printf("ESP: " fmt , ##args); } while (0) typedef struct ESPState ESPState; struct ESPState { + qemu_irq irq; BlockDriverState **bd; uint8_t rregs[ESP_REGS]; uint8_t wregs[ESP_REGS]; @@ -126,7 +127,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) s->rregs[4] = STAT_IN; s->rregs[5] = INTR_DC; s->rregs[6] = SEQ_0; - espdma_raise_irq(s->dma_opaque); + qemu_irq_raise(s->irq); return 0; } s->current_dev = s->scsi_dev[target]; @@ -156,7 +157,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) } s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; - espdma_raise_irq(s->dma_opaque); + qemu_irq_raise(s->irq); } static void handle_satn(ESPState *s) @@ -178,7 +179,7 @@ static void handle_satn_stop(ESPState *s) s->rregs[4] = STAT_IN | STAT_TC | STAT_CD; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; - espdma_raise_irq(s->dma_opaque); + qemu_irq_raise(s->irq); } } @@ -198,7 +199,7 @@ static void write_response(ESPState *s) s->ti_wptr = 0; s->rregs[7] = 2; } - espdma_raise_irq(s->dma_opaque); + qemu_irq_raise(s->irq); } static void esp_dma_done(ESPState *s) @@ -209,7 +210,7 @@ static void esp_dma_done(ESPState *s) s->rregs[7] = 0; s->rregs[0] = 0; s->rregs[1] = 0; - espdma_raise_irq(s->dma_opaque); + qemu_irq_raise(s->irq); } static void esp_do_dma(ESPState *s) @@ -362,7 +363,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) } else { s->rregs[2] = s->ti_buf[s->ti_rptr++]; } - espdma_raise_irq(s->dma_opaque); + qemu_irq_raise(s->irq); } if (s->ti_size == 0) { s->ti_rptr = 0; @@ -373,7 +374,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) // interrupt // Clear interrupt/error status bits s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE); - espdma_clear_irq(s->dma_opaque); + qemu_irq_lower(s->irq); break; default: break; @@ -436,7 +437,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) DPRINTF("Bus reset (%2.2x)\n", val); s->rregs[5] = INTR_RST; if (!(s->wregs[8] & 0x40)) { - espdma_raise_irq(s->dma_opaque); + qemu_irq_raise(s->irq); } break; case 0x10: @@ -565,7 +566,7 @@ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id) } void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, - void *dma_opaque) + void *dma_opaque, qemu_irq irq) { ESPState *s; int esp_io_memory; @@ -575,6 +576,7 @@ void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, return NULL; s->bd = bd; + s->irq = irq; s->dma_opaque = dma_opaque; sparc32_dma_set_reset_data(dma_opaque, esp_reset, s); diff --git a/hw/pcnet.c b/hw/pcnet.c index 4c4278ffa..9c4dd06cf 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -2018,7 +2018,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { (CPUWriteMemoryFunc *)&pcnet_ioport_writew, }; -void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, +void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, qemu_irq irq) { PCNetState *d; @@ -2026,7 +2026,7 @@ void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, d = qemu_mallocz(sizeof(PCNetState)); if (!d) - return NULL; + return; lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); @@ -2041,7 +2041,5 @@ void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, d->phys_mem_write = ledma_memory_write; pcnet_common_init(d, nd, "lance"); - - return d; } #endif /* TARGET_SPARC */ diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index de1499876..f26b4bec7 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -115,22 +115,18 @@ void ledma_memory_write(void *opaque, target_phys_addr_t addr, } } -void espdma_raise_irq(void *opaque) +static void dma_set_irq(void *opaque, int irq, int level) { DMAState *s = opaque; - - DPRINTF("Raise ESP IRQ\n"); - s->dmaregs[0] |= DMA_INTR; - qemu_irq_raise(s->irq); -} - -void espdma_clear_irq(void *opaque) -{ - DMAState *s = opaque; - - s->dmaregs[0] &= ~DMA_INTR; - DPRINTF("Lower ESP IRQ\n"); - qemu_irq_lower(s->irq); + if (level) { + DPRINTF("Raise ESP IRQ\n"); + s->dmaregs[0] |= DMA_INTR; + qemu_irq_raise(s->irq); + } else { + s->dmaregs[0] &= ~DMA_INTR; + DPRINTF("Lower ESP IRQ\n"); + qemu_irq_lower(s->irq); + } } void espdma_memory_read(void *opaque, uint8_t *buf, int len) @@ -241,7 +237,8 @@ static int dma_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq irq, void *iommu) +void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, + void *iommu, qemu_irq **dev_irq) { DMAState *s; int dma_io_memory; @@ -250,7 +247,7 @@ void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq irq, void *iommu) if (!s) return NULL; - s->irq = irq; + s->irq = parent_irq; s->iommu = iommu; dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s); @@ -258,6 +255,7 @@ void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq irq, void *iommu) register_savevm("sparc32_dma", daddr, 2, dma_save, dma_load, s); qemu_register_reset(dma_reset, s); + *dev_irq = qemu_allocate_irqs(dma_set_irq, s, 1); return s; } diff --git a/hw/sun4m.c b/hw/sun4m.c index 10473baa4..04eae00ee 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -262,9 +262,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, { CPUState *env, *envs[MAX_CPUS]; unsigned int i; - void *iommu, *espdma, *ledma, *main_esp, *main_lance = NULL; + void *iommu, *espdma, *ledma, *main_esp; const sparc_def_t *def; - qemu_irq *slavio_irq; + qemu_irq *slavio_irq, *espdma_irq, *ledma_irq; /* init CPUs */ sparc_find_by_name(cpu_model, &def); @@ -296,9 +296,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], - iommu); + iommu, &espdma_irq); ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, - slavio_irq[hwdef->le_irq], iommu); + slavio_irq[hwdef->le_irq], iommu, &ledma_irq); if (graphic_depth != 8 && graphic_depth != 24) { fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); @@ -309,8 +309,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { - main_lance = lance_init(&nd_table[0], hwdef->le_base, ledma, - slavio_irq[hwdef->le_irq]); + lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); @@ -331,7 +330,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], serial_hds[1], serial_hds[0]); fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table); - main_esp = esp_init(bs_table, hwdef->esp_base, espdma); + main_esp = esp_init(bs_table, hwdef->esp_base, espdma, *espdma_irq); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { diff --git a/vl.h b/vl.h index 6d90aeb05..0a13f2618 100644 --- a/vl.h +++ b/vl.h @@ -1046,7 +1046,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); /* pcnet.c */ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); -void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, +void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, qemu_irq irq); /* vmmouse.c */ @@ -1263,17 +1263,15 @@ void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, - void *dma_opaque); + void *dma_opaque, qemu_irq irq); /* sparc32_dma.c */ -void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq irq, void *iommu); -void ledma_set_irq(void *opaque, int isr); +void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, + void *iommu, qemu_irq **dev_irq); void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); -void espdma_raise_irq(void *opaque); -void espdma_clear_irq(void *opaque); void espdma_memory_read(void *opaque, uint8_t *buf, int len); void espdma_memory_write(void *opaque, uint8_t *buf, int len); void sparc32_dma_set_reset_data(void *opaque, void (*dev_reset)(void *opaque), -- cgit v1.2.3 From d7edfd27021b36c5ca065293e13639e139ddd5da Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 16:37:49 +0000 Subject: Use qemu_irq between interrupt controller and timers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2874 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 35 ++++++++++++++++++----------------- hw/slavio_timer.c | 24 ++++++++++-------------- hw/sun4m.c | 14 ++++++++------ vl.h | 7 +++---- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 7f93b22e3..279254f7f 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -55,6 +55,7 @@ typedef struct SLAVIO_INTCTLState { #endif CPUState *cpu_envs[MAX_CPUS]; const uint32_t *intbit_to_level; + uint32_t cputimer_bit; } SLAVIO_INTCTLState; #define INTCTL_MAXADDR 0xf @@ -280,7 +281,7 @@ static void slavio_check_interrupts(void *opaque) * "irq" here is the bit number in the system interrupt register to * separate serial and keyboard interrupts sharing a level. */ -void slavio_set_irq(void *opaque, int irq, int level) +static void slavio_set_irq(void *opaque, int irq, int level) { SLAVIO_INTCTLState *s = opaque; @@ -302,26 +303,20 @@ void slavio_set_irq(void *opaque, int irq, int level) } } -void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu) +static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) { SLAVIO_INTCTLState *s = opaque; - DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level); - if (cpu == (unsigned int)-1) { - slavio_set_irq(opaque, irq, level); + DPRINTF("Set cpu %d local level %d\n", cpu, level); + if (!s->cpu_envs[cpu]) return; + + if (level) { + s->intreg_pending[cpu] |= s->cputimer_bit; + } else { + s->intreg_pending[cpu] &= ~s->cputimer_bit; } - if (irq < 32) { - uint32_t pil = s->intbit_to_level[irq]; - if (pil > 0) { - if (level) { - s->intreg_pending[cpu] |= 1 << pil; - } - else { - s->intreg_pending[cpu] &= ~(1 << pil); - } - } - } + slavio_check_interrupts(s); } @@ -371,12 +366,15 @@ static void slavio_intctl_reset(void *opaque) void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env) { SLAVIO_INTCTLState *s = opaque; + s->cpu_envs[cpu] = env; } void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, const uint32_t *intbit_to_level, - qemu_irq **irq) + qemu_irq **irq, qemu_irq **cpu_irq, + unsigned int cputimer) + { int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; SLAVIO_INTCTLState *s; @@ -398,6 +396,9 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); qemu_register_reset(slavio_intctl_reset, s); *irq = qemu_allocate_irqs(slavio_set_irq, s, 32); + + *cpu_irq = qemu_allocate_irqs(slavio_set_timer_irq_cpu, s, MAX_CPUS); + s->cputimer_bit = 1 << s->intbit_to_level[cputimer]; slavio_intctl_reset(s); return s; } diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 6bc293e67..2ade17788 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -48,14 +48,12 @@ do { printf("TIMER: " fmt , ##args); } while (0) */ typedef struct SLAVIO_TIMERState { + qemu_irq irq; ptimer_state *timer; uint32_t count, counthigh, reached; uint64_t limit; - int irq; int stopped; int mode; // 0 = processor, 1 = user, 2 = system - unsigned int cpu; - void *intctl; } SLAVIO_TIMERState; #define TIMER_MAXADDR 0x1f @@ -83,7 +81,7 @@ static void slavio_timer_irq(void *opaque) DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); s->reached = 0x80000000; if (s->mode != 1) - pic_set_irq_cpu(s->intctl, s->irq, 1, s->cpu); + qemu_irq_raise(s->irq); } static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) @@ -98,7 +96,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) // part of counter (user mode) if (s->mode != 1) { // clear irq - pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu); + qemu_irq_lower(s->irq); s->reached = 0; ret = s->limit & 0x7fffffff; } @@ -145,7 +143,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 case 0: // set limit, reset counter reload = 1; - pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu); + qemu_irq_lower(s->irq); // fall through case 2: // set limit without resetting counter @@ -172,7 +170,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 if (s->mode == 0 || s->mode == 1) s->mode = val & 1; if (s->mode == 1) { - pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu); + qemu_irq_lower(s->irq); s->limit = -1ULL; } ptimer_set_limit(s->timer, s->limit >> 9, 1); @@ -201,7 +199,7 @@ static void slavio_timer_save(QEMUFile *f, void *opaque) qemu_put_be64s(f, &s->limit); qemu_put_be32s(f, &s->count); qemu_put_be32s(f, &s->counthigh); - qemu_put_be32s(f, &s->irq); + qemu_put_be32(f, 0); // Was irq qemu_put_be32s(f, &s->reached); qemu_put_be32s(f, &s->stopped); qemu_put_be32s(f, &s->mode); @@ -211,6 +209,7 @@ static void slavio_timer_save(QEMUFile *f, void *opaque) static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) { SLAVIO_TIMERState *s = opaque; + uint32_t tmp; if (version_id != 2) return -EINVAL; @@ -218,7 +217,7 @@ static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be64s(f, &s->limit); qemu_get_be32s(f, &s->count); qemu_get_be32s(f, &s->counthigh); - qemu_get_be32s(f, &s->irq); + qemu_get_be32s(f, &tmp); // Was irq qemu_get_be32s(f, &s->reached); qemu_get_be32s(f, &s->stopped); qemu_get_be32s(f, &s->mode); @@ -238,11 +237,10 @@ static void slavio_timer_reset(void *opaque) ptimer_set_limit(s->timer, s->limit >> 9, 1); ptimer_run(s->timer, 0); s->stopped = 1; - slavio_timer_irq(s); + qemu_irq_lower(s->irq); } -void slavio_timer_init(target_phys_addr_t addr, int irq, int mode, - unsigned int cpu, void *intctl) +void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) { int slavio_timer_io_memory; SLAVIO_TIMERState *s; @@ -253,11 +251,9 @@ void slavio_timer_init(target_phys_addr_t addr, int irq, int mode, return; s->irq = irq; s->mode = mode; - s->cpu = cpu; bh = qemu_bh_new(slavio_timer_irq, s); s->timer = ptimer_init(bh); ptimer_set_period(s->timer, 500ULL); - s->intctl = intctl; slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, slavio_timer_mem_write, s); diff --git a/hw/sun4m.c b/hw/sun4m.c index 04eae00ee..ed3be4e1d 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -56,7 +56,7 @@ struct hwdef { long vram_size, nvram_size; // IRQ numbers are not PIL ones, but master interrupt controller register // bit numbers - int intctl_g_intr, esp_irq, le_irq, cpu_irq, clock_irq, clock1_irq; + int intctl_g_intr, esp_irq, le_irq, clock_irq, clock1_irq; int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq; int machine_id; // For NVRAM uint32_t intbit_to_level[32]; @@ -264,7 +264,8 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, unsigned int i; void *iommu, *espdma, *ledma, *main_esp; const sparc_def_t *def; - qemu_irq *slavio_irq, *espdma_irq, *ledma_irq; + qemu_irq *slavio_irq, *slavio_cpu_irq, + *espdma_irq, *ledma_irq; /* init CPUs */ sparc_find_by_name(cpu_model, &def); @@ -291,7 +292,8 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, slavio_intctl = slavio_intctl_init(hwdef->intctl_base, hwdef->intctl_base + 0x10000ULL, &hwdef->intbit_to_level[0], - &slavio_irq); + &slavio_irq, &slavio_cpu_irq, + hwdef->clock_irq); for(i = 0; i < smp_cpus; i++) { slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } @@ -320,10 +322,10 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, for (i = 0; i < MAX_CPUS; i++) { slavio_timer_init(hwdef->counter_base + (target_phys_addr_t)(i * TARGET_PAGE_SIZE), - hwdef->clock_irq, 0, i, slavio_intctl); + slavio_cpu_irq[i], 0); } - slavio_timer_init(hwdef->counter_base + 0x10000ULL, hwdef->clock1_irq, 2, - (unsigned int)-1, slavio_intctl); + slavio_timer_init(hwdef->counter_base + 0x10000ULL, + slavio_irq[hwdef->clock1_irq], 2); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device diff --git a/vl.h b/vl.h index 0a13f2618..d6a76f6c9 100644 --- a/vl.h +++ b/vl.h @@ -1230,10 +1230,10 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, int depth); /* slavio_intctl.c */ -void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, const uint32_t *intbit_to_level, - qemu_irq **irq); + qemu_irq **irq, qemu_irq **cpu_irq, + unsigned int cputimer); void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); void slavio_pic_info(void *opaque); void slavio_irq_info(void *opaque); @@ -1247,8 +1247,7 @@ int load_aout(const char *filename, uint8_t *addr); int load_uboot(const char *filename, target_ulong *ep, int *is_linux); /* slavio_timer.c */ -void slavio_timer_init(target_phys_addr_t addr, int irq, int mode, - unsigned int cpu, void *intctl); +void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode); /* slavio_serial.c */ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, -- cgit v1.2.3 From b3a2319792ad5c0f0f8c3d2f4d02b95fd7efbc69 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 16:42:29 +0000 Subject: Use qemu_irqs between CPUs and interrupt controller Fix interrupt priority handling which prevented SMP from working git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2875 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 130 ++++++++++++++++++++++------------------------------- hw/sun4m.c | 49 ++++++++++++++++++-- vl.h | 3 +- 3 files changed, 99 insertions(+), 83 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 279254f7f..d89f86315 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -44,6 +44,7 @@ do { printf("IRQ: " fmt , ##args); } while (0) */ #define MAX_CPUS 16 +#define MAX_PILS 16 typedef struct SLAVIO_INTCTLState { uint32_t intreg_pending[MAX_CPUS]; @@ -53,9 +54,10 @@ typedef struct SLAVIO_INTCTLState { #ifdef DEBUG_IRQ_COUNT uint64_t irq_count[32]; #endif - CPUState *cpu_envs[MAX_CPUS]; + qemu_irq *cpu_irqs[MAX_CPUS]; const uint32_t *intbit_to_level; uint32_t cputimer_bit; + uint32_t pil_out[MAX_CPUS]; } SLAVIO_INTCTLState; #define INTCTL_MAXADDR 0xf @@ -213,67 +215,53 @@ void slavio_irq_info(void *opaque) #endif } +static void raise_pil(SLAVIO_INTCTLState *s, unsigned int pil, + unsigned int cpu) +{ + qemu_irq irq; + unsigned int oldmax; + + irq = s->cpu_irqs[cpu][pil]; + +#ifdef DEBUG_IRQ_COUNT + s->irq_count[pil]++; +#endif + oldmax = s->pil_out[cpu]; + if (oldmax > 0 && oldmax != pil) + qemu_irq_lower(s->cpu_irqs[cpu][oldmax]); + s->pil_out[cpu] = pil; + if (pil > 0) + qemu_irq_raise(irq); + DPRINTF("cpu %d pil %d\n", cpu, pil); +} + static void slavio_check_interrupts(void *opaque) { - CPUState *env; SLAVIO_INTCTLState *s = opaque; uint32_t pending = s->intregm_pending; unsigned int i, j, max = 0; pending &= ~s->intregm_disabled; - if (pending && !(s->intregm_disabled & 0x80000000)) { - for (i = 0; i < 32; i++) { - if (pending & (1 << i)) { - if (max < s->intbit_to_level[i]) - max = s->intbit_to_level[i]; - } - } - env = s->cpu_envs[s->target_cpu]; - if (!env) { - DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending); - } - else { - if (env->halted) - env->halted = 0; - if (env->interrupt_index == 0) { - DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max); -#ifdef DEBUG_IRQ_COUNT - s->irq_count[max]++; -#endif - env->interrupt_index = TT_EXTINT | max; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } - else - DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index); - } - } - else - DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled); - + DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); for (i = 0; i < MAX_CPUS; i++) { max = 0; - env = s->cpu_envs[i]; - if (!env) - continue; + if (pending && !(s->intregm_disabled & 0x80000000) && + (i == s->target_cpu)) { + for (j = 0; j < 32; j++) { + if (pending & (1 << j)) { + if (max < s->intbit_to_level[j]) + max = s->intbit_to_level[j]; + } + } + } for (j = 17; j < 32; j++) { if (s->intreg_pending[i] & (1 << j)) { if (max < j - 16) max = j - 16; } } - if (max > 0) { - if (env->halted) - env->halted = 0; - if (env->interrupt_index == 0) { - DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending); -#ifdef DEBUG_IRQ_COUNT - s->irq_count[max]++; -#endif - env->interrupt_index = TT_EXTINT | max; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } - } + raise_pil(s, max, i); } } @@ -284,22 +272,20 @@ static void slavio_check_interrupts(void *opaque) static void slavio_set_irq(void *opaque, int irq, int level) { SLAVIO_INTCTLState *s = opaque; - - DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level); - if (irq < 32) { - uint32_t mask = 1 << irq; - uint32_t pil = s->intbit_to_level[irq]; - if (pil > 0) { - if (level) { - s->intregm_pending |= mask; - s->intreg_pending[s->target_cpu] |= 1 << pil; - slavio_check_interrupts(s); - } - else { - s->intregm_pending &= ~mask; - s->intreg_pending[s->target_cpu] &= ~(1 << pil); - } - } + uint32_t mask = 1 << irq; + uint32_t pil = s->intbit_to_level[irq]; + + DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil, + level); + if (pil > 0) { + if (level) { + s->intregm_pending |= mask; + s->intreg_pending[s->target_cpu] |= 1 << pil; + } else { + s->intregm_pending &= ~mask; + s->intreg_pending[s->target_cpu] &= ~(1 << pil); + } + slavio_check_interrupts(s); } } @@ -307,15 +293,12 @@ static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) { SLAVIO_INTCTLState *s = opaque; - DPRINTF("Set cpu %d local level %d\n", cpu, level); - if (!s->cpu_envs[cpu]) - return; + DPRINTF("Set cpu %d local timer level %d\n", cpu, level); - if (level) { + if (level) s->intreg_pending[cpu] |= s->cputimer_bit; - } else { + else s->intreg_pending[cpu] &= ~s->cputimer_bit; - } slavio_check_interrupts(s); } @@ -363,18 +346,10 @@ static void slavio_intctl_reset(void *opaque) s->target_cpu = 0; } -void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env) -{ - SLAVIO_INTCTLState *s = opaque; - - s->cpu_envs[cpu] = env; -} - void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, const uint32_t *intbit_to_level, qemu_irq **irq, qemu_irq **cpu_irq, - unsigned int cputimer) - + qemu_irq **parent_irq, unsigned int cputimer) { int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; SLAVIO_INTCTLState *s; @@ -388,6 +363,7 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, slavio_intctl_io_memory); + s->cpu_irqs[i] = parent_irq[i]; } slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); diff --git a/hw/sun4m.c b/hw/sun4m.c index ed3be4e1d..c69d732f9 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +//#define DEBUG_IRQ /* * Sun4m architecture was used in the following machines: @@ -38,6 +39,13 @@ * See for example: http://www.sunhelp.org/faq/sunref1.html */ +#ifdef DEBUG_IRQ +#define DPRINTF(fmt, args...) \ + do { printf("CPUIRQ: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + #define KERNEL_LOAD_ADDR 0x00004000 #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 @@ -46,6 +54,7 @@ #define PROM_FILENAME "openbios-sparc32" #define MAX_CPUS 16 +#define MAX_PILS 16 struct hwdef { target_phys_addr_t iommu_base, slavio_base; @@ -233,6 +242,33 @@ void irq_info() slavio_irq_info(slavio_intctl); } +static void cpu_set_irq(void *opaque, int irq, int level) +{ + CPUState *env = opaque; + + if (level) { + DPRINTF("Raise CPU IRQ %d\n", irq); + + env->halted = 0; + + if (env->interrupt_index == 0 || + ((env->interrupt_index & ~15) == TT_EXTINT && + (env->interrupt_index & 15) < irq)) { + env->interrupt_index = TT_EXTINT | irq; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + DPRINTF("Not triggered, pending exception %d\n", + env->interrupt_index); + } + } else { + DPRINTF("Lower CPU IRQ %d\n", irq); + } +} + +static void dummy_cpu_set_irq(void *opaque, int irq, int level) +{ +} + static void *slavio_misc; void qemu_system_powerdown(void) @@ -264,7 +300,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, unsigned int i; void *iommu, *espdma, *ledma, *main_esp; const sparc_def_t *def; - qemu_irq *slavio_irq, *slavio_cpu_irq, + qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; /* init CPUs */ @@ -273,6 +309,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, fprintf(stderr, "Unable to find Sparc CPU definition\n"); exit(1); } + for(i = 0; i < smp_cpus; i++) { env = cpu_init(); cpu_sparc_register(env, def); @@ -284,7 +321,12 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, env->halted = 1; } register_savevm("cpu", i, 3, cpu_save, cpu_load, env); + cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS); } + + for (i = smp_cpus; i < MAX_CPUS; i++) + cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); + /* allocate RAM */ cpu_register_physical_memory(0, ram_size, 0); @@ -293,10 +335,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, hwdef->intctl_base + 0x10000ULL, &hwdef->intbit_to_level[0], &slavio_irq, &slavio_cpu_irq, + cpu_irqs, hwdef->clock_irq); - for(i = 0; i < smp_cpus; i++) { - slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); - } + espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], iommu, &espdma_irq); ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, diff --git a/vl.h b/vl.h index d6a76f6c9..e8caaf8df 100644 --- a/vl.h +++ b/vl.h @@ -1233,8 +1233,7 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, const uint32_t *intbit_to_level, qemu_irq **irq, qemu_irq **cpu_irq, - unsigned int cputimer); -void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); + qemu_irq **parent_irq, unsigned int cputimer); void slavio_pic_info(void *opaque); void slavio_irq_info(void *opaque); -- cgit v1.2.3 From 1b2e93c175a947653326efce9a6f36791d458691 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 19:36:00 +0000 Subject: Separate fault for code access to unassigned memory git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2876 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 2 ++ target-sparc/op_helper.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index c5ccd28a8..215862931 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -40,6 +40,7 @@ #define TT_DFAULT 0x09 #define TT_TOVF 0x0a #define TT_EXTINT 0x10 +#define TT_CODE_ACCESS 0x21 #define TT_DATA_ACCESS 0x29 #define TT_DIV_ZERO 0x2a #define TT_NCP_INSN 0x24 @@ -47,6 +48,7 @@ #else #define TT_TFAULT 0x08 #define TT_TMISS 0x09 +#define TT_CODE_ACCESS 0x0a #define TT_ILL_INSN 0x10 #define TT_PRIV_INSN 0x11 #define TT_NFPU_INSN 0x20 diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index b2f982f4e..dc1c04deb 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1111,7 +1111,10 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx "\n", addr, env->pc); #endif - raise_exception(TT_DATA_ACCESS); + if (is_exec) + raise_exception(TT_CODE_ACCESS); + else + raise_exception(TT_DATA_ACCESS); } env = saved_env; } @@ -1130,7 +1133,10 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, addr, env->pc); env = saved_env; #endif - raise_exception(TT_DATA_ACCESS); + if (is_exec) + raise_exception(TT_CODE_ACCESS); + else + raise_exception(TT_DATA_ACCESS); } #endif -- cgit v1.2.3 From 833c7174ce5145397d2b3405f6857ca607fed1f1 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 19:36:43 +0000 Subject: Improved sanity checking to -net options git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2877 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 18 ++++++++++++++++++ vl.h | 1 + 2 files changed, 19 insertions(+) diff --git a/vl.c b/vl.c index d23af87a7..61c6c1a01 100644 --- a/vl.c +++ b/vl.c @@ -4197,6 +4197,7 @@ static int net_client_init(const char *str) } nd->vlan = vlan; nb_nics++; + vlan->nb_guest_devs++; ret = 0; } else if (!strcmp(device, "none")) { @@ -4209,6 +4210,7 @@ static int net_client_init(const char *str) if (get_param_value(buf, sizeof(buf), "hostname", p)) { pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); } + vlan->nb_host_devs++; ret = net_slirp_init(vlan); } else #endif @@ -4219,6 +4221,7 @@ static int net_client_init(const char *str) fprintf(stderr, "tap: no interface name\n"); return -1; } + vlan->nb_host_devs++; ret = tap_win32_init(vlan, ifname); } else #else @@ -4238,6 +4241,7 @@ static int net_client_init(const char *str) if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); } + vlan->nb_host_devs++; ret = net_tap_init(vlan, ifname, setup_script); } } else @@ -4259,6 +4263,7 @@ static int net_client_init(const char *str) fprintf(stderr, "Unknown socket options: %s\n", p); return -1; } + vlan->nb_host_devs++; } else { fprintf(stderr, "Unknown network device: %s\n", device); @@ -7131,6 +7136,7 @@ int main(int argc, char **argv) int usb_devices_index; int fds[2]; const char *pid_file = NULL; + VLANState *vlan; LIST_INIT (&vm_change_state_head); #ifndef _WIN32 @@ -7750,6 +7756,18 @@ int main(int argc, char **argv) if (net_client_init(net_clients[i]) < 0) exit(1); } + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0) + continue; + if (vlan->nb_guest_devs == 0) { + fprintf(stderr, "Invalid vlan (%d) with no nics\n", vlan->id); + exit(1); + } + if (vlan->nb_host_devs == 0) + fprintf(stderr, + "Warning: vlan %d is not connected to host network\n", + vlan->id); + } #ifdef TARGET_I386 if (boot_device == 'n') { diff --git a/vl.h b/vl.h index e8caaf8df..8fed8374d 100644 --- a/vl.h +++ b/vl.h @@ -389,6 +389,7 @@ typedef struct VLANState { int id; VLANClientState *first_client; struct VLANState *next; + unsigned int nb_guest_devs, nb_host_devs; } VLANState; VLANState *qemu_find_vlan(int id); -- cgit v1.2.3 From dbe06e1841028ffa080ffe06273397fc583a7fcc Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 19:38:20 +0000 Subject: Handle unconnected vlan case in lance git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2878 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 33 +++++++++++++++++++-------------- hw/sun4m.c | 16 ++++++++-------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index 9c4dd06cf..3fffd44fb 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1267,7 +1267,8 @@ static void pcnet_transmit(PCNetState *s) if (CSR_LOOP(s)) pcnet_receive(s, s->buffer, s->xmit_pos); else - qemu_send_packet(s->vc, s->buffer, s->xmit_pos); + if (s->vc) + qemu_send_packet(s->vc, s->buffer, s->xmit_pos); s->csr[0] &= ~0x0008; /* clear TDMD */ s->csr[4] |= 0x0004; /* set TXSTRT */ @@ -1562,7 +1563,8 @@ static void pcnet_h_reset(void *opaque) /* Initialize the PROM */ - memcpy(s->prom, s->nd->macaddr, 6); + if (s->nd) + memcpy(s->prom, s->nd->macaddr, 6); s->prom[12] = s->prom[13] = 0x00; s->prom[14] = s->prom[15] = 0x57; @@ -1898,18 +1900,21 @@ static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char *info_str) d->nd = nd; - d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, - pcnet_can_receive, d); - - snprintf(d->vc->info_str, sizeof(d->vc->info_str), - "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - d->nd->macaddr[0], - d->nd->macaddr[1], - d->nd->macaddr[2], - d->nd->macaddr[3], - d->nd->macaddr[4], - d->nd->macaddr[5]); - + if (nd && nd->vlan) { + d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, + pcnet_can_receive, d); + + snprintf(d->vc->info_str, sizeof(d->vc->info_str), + "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + d->nd->macaddr[0], + d->nd->macaddr[1], + d->nd->macaddr[2], + d->nd->macaddr[3], + d->nd->macaddr[4], + d->nd->macaddr[5]); + } else { + d->vc = NULL; + } pcnet_h_reset(d); register_savevm("pcnet", 0, 2, pcnet_save, pcnet_load, d); } diff --git a/hw/sun4m.c b/hw/sun4m.c index c69d732f9..9efcdd62d 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -349,15 +349,15 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, } tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size, hwdef->vram_size, graphic_width, graphic_height, graphic_depth); - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } + + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "lance") == 0) { + lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); } + nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, hwdef->nvram_size, 8); for (i = 0; i < MAX_CPUS; i++) { -- cgit v1.2.3 From 7f75ffd39e4857dbeea32594e7523bf311aecf87 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 19:39:27 +0000 Subject: Spelling fix (Mark Glines) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2879 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- sparc-dis.c | 2 +- target-i386/helper.c | 14 +++++++------- target-i386/translate.c | 2 +- target-ppc/translate.c | 10 +++++----- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index dc242f621..259173bb8 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1633,7 +1633,7 @@ void cpu_loop (CPUState *env) call_pal(env, (trapnr >> 6) | 0x80); break; case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): - fprintf(stderr, "Priviledged call to PALcode\n"); + fprintf(stderr, "Privileged call to PALcode\n"); exit(1); break; case EXCP_DEBUG: diff --git a/sparc-dis.c b/sparc-dis.c index 2be874ac9..f04f135df 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -276,7 +276,7 @@ const struct sparc_opcode_arch sparc_opcode_archs[] = { { "v8", MASK_V6 | MASK_V7 | MASK_V8 }, { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET }, { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE }, - /* ??? Don't some v8 priviledged insns conflict with v9? */ + /* ??? Don't some v8 privileged insns conflict with v9? */ { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 }, /* v9 with ultrasparc additions */ { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A }, diff --git a/target-i386/helper.c b/target-i386/helper.c index 20c1f5762..ef4b77e88 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -687,7 +687,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); if (!(e2 & DESC_C_MASK) && dpl < cpl) { - /* to inner priviledge */ + /* to inner privilege */ get_ss_esp_from_tss(&ss, &esp, dpl); if ((ss & 0xfffc) == 0) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); @@ -708,7 +708,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, sp_mask = get_sp_mask(ss_e2); ssp = get_seg_base(ss_e1, ss_e2); } else if ((e2 & DESC_C_MASK) || dpl == cpl) { - /* to same priviledge */ + /* to same privilege */ if (env->eflags & VM_MASK) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; @@ -901,7 +901,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { - /* to inner priviledge */ + /* to inner privilege */ if (ist != 0) esp = get_rsp_from_tss(ist + 3); else @@ -910,7 +910,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, ss = 0; new_stack = 1; } else if ((e2 & DESC_C_MASK) || dpl == cpl) { - /* to same priviledge */ + /* to same privilege */ if (env->eflags & VM_MASK) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); new_stack = 0; @@ -2208,7 +2208,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); if (!(e2 & DESC_C_MASK) && dpl < cpl) { - /* to inner priviledge */ + /* to inner privilege */ get_ss_esp_from_tss(&ss, &sp, dpl); #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_PCALL) @@ -2255,7 +2255,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) } new_stack = 1; } else { - /* to same priviledge */ + /* to same privilege */ sp = ESP; sp_mask = get_sp_mask(env->segs[R_SS].flags); ssp = env->segs[R_SS].base; @@ -2437,7 +2437,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) get_seg_limit(e1, e2), e2); } else { - /* return to different priviledge level */ + /* return to different privilege level */ #ifdef TARGET_X86_64 if (shift == 2) { POPQ(sp, new_esp); diff --git a/target-i386/translate.c b/target-i386/translate.c index 53ccc8599..e36e03d82 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2245,7 +2245,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) } /* an interrupt is different from an exception because of the - priviledge checks */ + privilege checks */ static void gen_interrupt(DisasContext *s, int intno, target_ulong cur_eip, target_ulong next_eip) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2ea759ad9..e5064c082 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3026,10 +3026,10 @@ static inline void gen_op_mfspr (DisasContext *ctx) } else { /* Privilege exception */ if (loglevel != 0) { - fprintf(logfile, "Trying to read priviledged spr %d %03x\n", + fprintf(logfile, "Trying to read privileged spr %d %03x\n", sprn, sprn); } - printf("Trying to read priviledged spr %d %03x\n", sprn, sprn); + printf("Trying to read privileged spr %d %03x\n", sprn, sprn); RET_PRIVREG(ctx); } } else { @@ -3132,10 +3132,10 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) } else { /* Privilege exception */ if (loglevel != 0) { - fprintf(logfile, "Trying to write priviledged spr %d %03x\n", + fprintf(logfile, "Trying to write privileged spr %d %03x\n", sprn, sprn); } - printf("Trying to write priviledged spr %d %03x\n", sprn, sprn); + printf("Trying to write privileged spr %d %03x\n", sprn, sprn); RET_PRIVREG(ctx); } } else { @@ -4019,7 +4019,7 @@ GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER) /* cli */ GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER) { - /* Cache line invalidate: priviledged and treated as no-op */ + /* Cache line invalidate: privileged and treated as no-op */ #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else -- cgit v1.2.3 From c4a7060cf70e2e72f44a98307f453eba07e09bea Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 19:41:17 +0000 Subject: New option -net nic,model=? (Mark Glines) Network documentation update (Mark Glines) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2880 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/integratorcp.c | 3 +++ hw/mips_r4k.c | 3 +++ hw/pc.c | 5 +++++ hw/pci.c | 4 ++++ hw/ppc_prep.c | 3 +++ hw/sun4m.c | 3 +++ qemu-doc.texi | 9 +++++---- 7 files changed, 26 insertions(+), 4 deletions(-) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index c9e1715f3..6572af8ec 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -500,6 +500,9 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "smc91c111") == 0) { smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); + } else if (strcmp(nd_table[0].model, "?") == 0) { + fprintf(stderr, "qemu: Supported NICs: smc91c111\n"); + exit (1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 72e9ac8a6..d600dbbb0 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -227,6 +227,9 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "ne2k_isa") == 0) { isa_ne2000_init(0x300, i8259[9], &nd_table[0]); + } else if (strcmp(nd_table[0].model, "?") == 0) { + fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n"); + exit (1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); diff --git a/hw/pc.c b/hw/pc.c index 388d65729..b91b64fae 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -865,7 +865,12 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (strcmp(nd->model, "ne2k_isa") == 0) { pc_init_ne2k_isa(nd, i8259); } else if (pci_enabled) { + if (strcmp(nd->model, "?") == 0) + fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n"); pci_nic_init(pci_bus, nd, -1); + } else if (strcmp(nd->model, "?") == 0) { + fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n"); + exit(1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit(1); diff --git a/hw/pci.c b/hw/pci.c index def2dc088..c7ea31469 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -588,6 +588,10 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn) pci_rtl8139_init(bus, nd, devfn); } else if (strcmp(nd->model, "pcnet") == 0) { pci_pcnet_init(bus, nd, devfn); + } else if (strcmp(nd->model, "?") == 0) { + fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er" + " ne2k_pci pcnet rtl8139\n"); + exit (1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit (1); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 6a3cd907b..4b9d9d13f 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -626,6 +626,9 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "ne2k_isa") == 0) { isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]); + } else if (strcmp(nd_table[0].model, "?") == 0) { + fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n"); + exit (1); } else { /* Why ? */ cpu_abort(env, "qemu: Unsupported NIC: %s\n", nd_table[0].model); diff --git a/hw/sun4m.c b/hw/sun4m.c index 9efcdd62d..2f7f22e4c 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -353,6 +353,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq); + } else if (strcmp(nd_table[0].model, "?") == 0) { + fprintf(stderr, "qemu: Supported NICs: lance\n"); + exit (1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); diff --git a/qemu-doc.texi b/qemu-doc.texi index 81ddfb047..3a4481b8e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -153,7 +153,7 @@ PS/2 mouse and keyboard @item Floppy disk @item -NE2000 PCI network adapters +PCI/ISA PCI network adapters @item Serial ports @item @@ -355,7 +355,7 @@ Network options: @item -net nic[,vlan=n][,macaddr=addr][,model=type] Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n} -= 0 is the default). The NIC is currently an NE2000 on the PC += 0 is the default). The NIC is an ne2k_pci by default on the PC target. Optionally, the MAC address can be changed. If no @option{-net} option is specified, a single NIC is created. Qemu can emulate several different models of network card. @@ -363,7 +363,8 @@ Valid values for @var{type} are @code{i82551}, @code{i82557b}, @code{i82559er}, @code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139}, @code{smc91c111} and @code{lance}. -Not all devices are supported on all targets. +Not all devices are supported on all targets. Use -net nic,model=? +for a list of available devices for your target. @item -net user[,vlan=n][,hostname=name] Use the user mode network stack which requires no administrator @@ -1208,7 +1209,7 @@ What you should @emph{never} do: @node pcsys_network @section Network emulation -QEMU can simulate several networks cards (NE2000 boards on the PC +QEMU can simulate several networks cards (PCI or ISA cards on the PC target) and can connect them to an arbitrary number of Virtual Local Area Networks (VLANs). Host TAP devices can be connected to any QEMU VLAN. VLAN can be connected between separate instances of QEMU to -- cgit v1.2.3 From dd4131b39492bd91dc87d216e761ca4cf210fb67 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 27 May 2007 19:42:35 +0000 Subject: Interrupt debugging DPRINTFs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2881 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index d89f86315..acde370e5 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -71,18 +71,22 @@ static void slavio_check_interrupts(void *opaque); static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) { SLAVIO_INTCTLState *s = opaque; - uint32_t saddr; + uint32_t saddr, ret; int cpu; cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; saddr = (addr & INTCTL_MAXADDR) >> 2; switch (saddr) { case 0: - return s->intreg_pending[cpu]; + ret = s->intreg_pending[cpu]; + break; default: - break; + ret = 0; + break; } - return 0; + DPRINTF("read cpu %d reg 0x%x = %x\n", addr, ret); + + return ret; } static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -93,6 +97,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; saddr = (addr & INTCTL_MAXADDR) >> 2; + DPRINTF("write cpu %d reg 0x%x = %x\n", cpu, addr, val); switch (saddr) { case 1: // clear pending softints if (val & 0x4000) @@ -128,20 +133,26 @@ static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = { static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) { SLAVIO_INTCTLState *s = opaque; - uint32_t saddr; + uint32_t saddr, ret; saddr = (addr & INTCTLM_MAXADDR) >> 2; switch (saddr) { case 0: - return s->intregm_pending & 0x7fffffff; + ret = s->intregm_pending & 0x7fffffff; + break; case 1: - return s->intregm_disabled; + ret = s->intregm_disabled; + break; case 4: - return s->target_cpu; + ret = s->target_cpu; + break; default: - break; + ret = 0; + break; } - return 0; + DPRINTF("read system reg 0x%x = %x\n", addr, ret); + + return ret; } static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) @@ -150,6 +161,7 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin uint32_t saddr; saddr = (addr & INTCTLM_MASK) >> 2; + DPRINTF("write system reg 0x%x = %x\n", addr, val); switch (saddr) { case 2: // clear (enable) // Force clear unused bits -- cgit v1.2.3 From 5fc4adf6cedc991c0ee9f16a5d2431bcca07c902 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 28 May 2007 01:46:43 +0000 Subject: Add diagnostic for bad opcode masks. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2882 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/translate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 10b733fa0..52f38e4c0 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2440,8 +2440,12 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) int to; /* Sanity check. All set bits must be included in the mask. */ - if (opcode & ~mask) + if (opcode & ~mask) { + fprintf(stderr, + "qemu internal error: bogus opcode definition %04x/%04x\n", + opcode, mask); abort(); + } /* This could probably be cleverer. For now just optimize the case where the top bits are known. */ /* Find the first zero bit in the mask. */ -- cgit v1.2.3 From 821f7e76100f71d9ad104be9d1e12835e201ce80 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 28 May 2007 02:20:34 +0000 Subject: Implement ColdFire ff1. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2883 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/op.c | 10 ++++++++++ target-m68k/translate.c | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/target-m68k/op.c b/target-m68k/op.c index 69d1fde9a..d483488be 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -170,6 +170,16 @@ OP(btest) FORCE_RET(); } +OP(ff1) +{ + uint32_t arg = get_op(PARAM2); + int n; + for (n = 32; arg; n--) + arg >>= 1; + set_op(PARAM1, n); + FORCE_RET(); +} + OP(subx_cc) { uint32_t op1 = get_op(PARAM1); diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 52f38e4c0..7c9176027 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1929,7 +1929,10 @@ DISAS_INSN(shift_reg) DISAS_INSN(ff1) { - cpu_abort(NULL, "Unimplemented insn: ff1"); + int reg; + reg = DREG(insn, 0); + gen_logic_cc(s, reg); + gen_op_ff1(reg, reg); } static int gen_get_sr(DisasContext *s) -- cgit v1.2.3 From 4f01035ff23b505e2feec470aee874c60cc74434 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 28 May 2007 02:29:59 +0000 Subject: Fix tap device counting. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2884 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 61c6c1a01..c949a4752 100644 --- a/vl.c +++ b/vl.c @@ -4229,6 +4229,7 @@ static int net_client_init(const char *str) char ifname[64]; char setup_script[1024]; int fd; + vlan->nb_host_devs++; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { fd = strtol(buf, NULL, 0); ret = -1; @@ -4241,7 +4242,6 @@ static int net_client_init(const char *str) if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); } - vlan->nb_host_devs++; ret = net_tap_init(vlan, ifname, setup_script); } } else -- cgit v1.2.3 From 2a1639291bf9f3c88c62d10459fedaa677536ff5 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 28 May 2007 11:26:15 +0000 Subject: Remove a local subpage IO hack, now that general subpage IO works. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2885 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa.h | 2 +- hw/pxa2xx.c | 60 ++++++++++++++++++++---------------------------------------- 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/hw/pxa.h b/hw/pxa.h index 986dffac7..90ffd6076 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -117,7 +117,7 @@ void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, struct pxa2xx_i2c_s; struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, - qemu_irq irq, int ioregister); + qemu_irq irq, uint32_t page_size); i2c_bus *pxa2xx_i2c_bus(struct pxa2xx_i2c_s *s); struct pxa2xx_i2s_s; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 087acd0af..2f3a63a7b 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -69,16 +69,9 @@ static struct { #define PCMD0 0x80 /* Power Manager I2C Command register File 0 */ #define PCMD31 0xfc /* Power Manager I2C Command register File 31 */ -static uint32_t pxa2xx_i2c_read(void *, target_phys_addr_t); -static void pxa2xx_i2c_write(void *, target_phys_addr_t, uint32_t); - static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr) { struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; - if (addr > s->pm_base + PCMD31) { - /* Special case: PWRI2C registers appear in the same range. */ - return pxa2xx_i2c_read(s->i2c[1], addr); - } addr -= s->pm_base; switch (addr) { @@ -99,11 +92,6 @@ static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; - if (addr > s->pm_base + PCMD31) { - /* Special case: PWRI2C registers appear in the same range. */ - pxa2xx_i2c_write(s->i2c[1], addr, value); - return; - } addr -= s->pm_base; switch (addr) { @@ -1484,7 +1472,7 @@ static int pxa2xx_i2c_load(QEMUFile *f, void *opaque, int version_id) } struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, - qemu_irq irq, int ioregister) + qemu_irq irq, uint32_t page_size) { int iomemtype; struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) @@ -1497,11 +1485,9 @@ struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, s->slave.send = pxa2xx_i2c_tx; s->bus = i2c_init_bus(); - if (ioregister) { - iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn, - pxa2xx_i2c_writefn, s); - cpu_register_physical_memory(s->base & 0xfffff000, 0xfff, iomemtype); - } + iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn, + pxa2xx_i2c_writefn, s); + cpu_register_physical_memory(s->base & ~page_size, page_size, iomemtype); register_savevm("pxa2xx_i2c", base, 0, pxa2xx_i2c_save, pxa2xx_i2c_load, s); @@ -2089,6 +2075,12 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype); register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); + s->pm_base = 0x40f00000; + iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, + pxa2xx_pm_writefn, s); + cpu_register_physical_memory(s->pm_base, 0xff, iomemtype); + register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); + for (i = 0; pxa27x_ssp[i].io_base; i ++); s->ssp = (struct pxa2xx_ssp_s **) qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i); @@ -2120,17 +2112,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, pxa2xx_rtc_init(s); register_savevm("pxa2xx_rtc", 0, 0, pxa2xx_rtc_save, pxa2xx_rtc_load, s); - /* Note that PM registers are in the same page with PWRI2C registers. - * As a workaround we don't map PWRI2C into memory and we expect - * PM handlers to call PWRI2C handlers when appropriate. */ - s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 1); - s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0); - - s->pm_base = 0x40f00000; - iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, - pxa2xx_pm_writefn, s); - cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype); - register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); + s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 0xffff); + s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0xff); s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); @@ -2201,6 +2184,12 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype); register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); + s->pm_base = 0x40f00000; + iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, + pxa2xx_pm_writefn, s); + cpu_register_physical_memory(s->pm_base, 0xff, iomemtype); + register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); + for (i = 0; pxa255_ssp[i].io_base; i ++); s->ssp = (struct pxa2xx_ssp_s **) qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i); @@ -2232,17 +2221,8 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, pxa2xx_rtc_init(s); register_savevm("pxa2xx_rtc", 0, 0, pxa2xx_rtc_save, pxa2xx_rtc_load, s); - /* Note that PM registers are in the same page with PWRI2C registers. - * As a workaround we don't map PWRI2C into memory and we expect - * PM handlers to call PWRI2C handlers when appropriate. */ - s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 1); - s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0); - - s->pm_base = 0x40f00000; - iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, - pxa2xx_pm_writefn, s); - cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype); - register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); + s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 0xffff); + s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0xff); s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); -- cgit v1.2.3 From 29490584bfcd365236de7292ce5c1881a80dd8b9 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 13:40:10 +0000 Subject: MIPS disassembler update. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2886 c046a42c-6fe2-441c-8c8c-71466251a162 --- mips-dis.c | 2695 +++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 1645 insertions(+), 1050 deletions(-) diff --git a/mips-dis.c b/mips-dis.c index 2e7dc85d1..a29884f3d 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -207,12 +207,72 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * #define OP_OP_SDC2 0x3e #define OP_OP_SDC3 0x3f /* a.k.a. sd */ +/* MIPS DSP ASE */ +#define OP_SH_DSPACC 11 +#define OP_MASK_DSPACC 0x3 +#define OP_SH_DSPACC_S 21 +#define OP_MASK_DSPACC_S 0x3 +#define OP_SH_DSPSFT 20 +#define OP_MASK_DSPSFT 0x3f +#define OP_SH_DSPSFT_7 19 +#define OP_MASK_DSPSFT_7 0x7f +#define OP_SH_SA3 21 +#define OP_MASK_SA3 0x7 +#define OP_SH_SA4 21 +#define OP_MASK_SA4 0xf +#define OP_SH_IMM8 16 +#define OP_MASK_IMM8 0xff +#define OP_SH_IMM10 16 +#define OP_MASK_IMM10 0x3ff +#define OP_SH_WRDSP 11 +#define OP_MASK_WRDSP 0x3f +#define OP_SH_RDDSP 16 +#define OP_MASK_RDDSP 0x3f +#define OP_SH_BP 11 +#define OP_MASK_BP 0x3 + +/* MIPS MT ASE */ +#define OP_SH_MT_U 5 +#define OP_MASK_MT_U 0x1 +#define OP_SH_MT_H 4 +#define OP_MASK_MT_H 0x1 +#define OP_SH_MTACC_T 18 +#define OP_MASK_MTACC_T 0x3 +#define OP_SH_MTACC_D 13 +#define OP_MASK_MTACC_D 0x3 + +#define OP_OP_COP0 0x10 +#define OP_OP_COP1 0x11 +#define OP_OP_COP2 0x12 +#define OP_OP_COP3 0x13 +#define OP_OP_LWC1 0x31 +#define OP_OP_LWC2 0x32 +#define OP_OP_LWC3 0x33 /* a.k.a. pref */ +#define OP_OP_LDC1 0x35 +#define OP_OP_LDC2 0x36 +#define OP_OP_LDC3 0x37 /* a.k.a. ld */ +#define OP_OP_SWC1 0x39 +#define OP_OP_SWC2 0x3a +#define OP_OP_SWC3 0x3b +#define OP_OP_SDC1 0x3d +#define OP_OP_SDC2 0x3e +#define OP_OP_SDC3 0x3f /* a.k.a. sd */ + /* Values in the 'VSEL' field. */ #define MDMX_FMTSEL_IMM_QH 0x1d #define MDMX_FMTSEL_IMM_OB 0x1e #define MDMX_FMTSEL_VEC_QH 0x15 #define MDMX_FMTSEL_VEC_OB 0x16 +/* UDI */ +#define OP_SH_UDI1 6 +#define OP_MASK_UDI1 0x1f +#define OP_SH_UDI2 6 +#define OP_MASK_UDI2 0x3ff +#define OP_SH_UDI3 6 +#define OP_MASK_UDI3 0x7fff +#define OP_SH_UDI4 6 +#define OP_MASK_UDI4 0xfffff /* This structure holds information for a particular instruction. */ struct mips_opcode @@ -235,6 +295,8 @@ struct mips_opcode of bits describing the instruction, notably any relevant hazard information. */ unsigned long pinfo; + /* A collection of additional bits describing the instruction. */ + unsigned long pinfo2; /* A collection of bits describing the instruction sets of which this instruction or macro is a member. */ unsigned long membership; @@ -276,19 +338,20 @@ struct mips_opcode "x" accept and ignore register name "z" must be zero register "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD) - "+A" 5 bit ins/ext position, which becomes LSB (OP_*_SHAMT). + "+A" 5 bit ins/ext/dins/dext/dinsm/dextm position, which becomes + LSB (OP_*_SHAMT). Enforces: 0 <= pos < 32. - "+B" 5 bit ins size, which becomes MSB (OP_*_INSMSB). + "+B" 5 bit ins/dins size, which becomes MSB (OP_*_INSMSB). Requires that "+A" or "+E" occur first to set position. Enforces: 0 < (pos+size) <= 32. - "+C" 5 bit ext size, which becomes MSBD (OP_*_EXTMSBD). + "+C" 5 bit ext/dext size, which becomes MSBD (OP_*_EXTMSBD). Requires that "+A" or "+E" occur first to set position. Enforces: 0 < (pos+size) <= 32. (Also used by "dext" w/ different limits, but limits for that are checked by the M_DEXT macro.) - "+E" 5 bit dins/dext position, which becomes LSB-32 (OP_*_SHAMT). + "+E" 5 bit dinsu/dextu position, which becomes LSB-32 (OP_*_SHAMT). Enforces: 32 <= pos < 64. - "+F" 5 bit "dinsm" size, which becomes MSB-32 (OP_*_INSMSB). + "+F" 5 bit "dinsm/dinsu" size, which becomes MSB-32 (OP_*_INSMSB). Requires that "+A" or "+E" occur first to set position. Enforces: 32 < (pos+size) <= 64. "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD). @@ -336,6 +399,35 @@ struct mips_opcode "Y" MDMX source register (OP_*_FS) "Z" MDMX source register (OP_*_FT) + DSP ASE usage: + "2" 2 bit unsigned immediate for byte align (OP_*_BP) + "3" 3 bit unsigned immediate (OP_*_SA3) + "4" 4 bit unsigned immediate (OP_*_SA4) + "5" 8 bit unsigned immediate (OP_*_IMM8) + "6" 5 bit unsigned immediate (OP_*_RS) + "7" 2 bit dsp accumulator register (OP_*_DSPACC) + "8" 6 bit unsigned immediate (OP_*_WRDSP) + "9" 2 bit dsp accumulator register (OP_*_DSPACC_S) + "0" 6 bit signed immediate (OP_*_DSPSFT) + ":" 7 bit signed immediate (OP_*_DSPSFT_7) + "'" 6 bit unsigned immediate (OP_*_RDDSP) + "@" 10 bit signed immediate (OP_*_IMM10) + + MT ASE usage: + "!" 1 bit usermode flag (OP_*_MT_U) + "$" 1 bit load high flag (OP_*_MT_H) + "*" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_T) + "&" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_D) + "g" 5 bit coprocessor 1 and 2 destination register (OP_*_RD) + "+t" 5 bit coprocessor 0 destination register (OP_*_RT) + "+T" 5 bit coprocessor 0 destination register (OP_*_RT) - disassembly only + + UDI immediates: + "+1" UDI immediate bits 6-10 + "+2" UDI immediate bits 6-15 + "+3" UDI immediate bits 6-20 + "+4" UDI immediate bits 6-25 + Other: "()" parens surrounding optional value "," separates operands @@ -343,13 +435,16 @@ struct mips_opcode "+" Start of extension sequence. Characters used so far, for quick reference when adding more: - "%[]<>(),+" + "234567890" + "%[]<>(),+:'@!$*&" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefhijklopqrstuvwxz" + "abcdefghijklopqrstuvwxz" Extension character sequences used so far ("+" followed by the following), for quick reference when adding more: - "ABCDEFGHI" + "1234" + "ABCDEFGHIT" + "t" */ /* These are the bits which may be set in the pinfo field of an @@ -419,10 +514,16 @@ struct mips_opcode #define INSN_MULT 0x40000000 /* Instruction synchronize shared memory. */ #define INSN_SYNC 0x80000000 -/* Instruction reads MDMX accumulator. XXX FIXME: No bits left! */ -#define INSN_READ_MDMX_ACC 0 -/* Instruction writes MDMX accumulator. XXX FIXME: No bits left! */ -#define INSN_WRITE_MDMX_ACC 0 + +/* These are the bits which may be set in the pinfo2 field of an + instruction. */ + +/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */ +#define INSN2_ALIAS 0x00000001 +/* Instruction reads MDMX accumulator. */ +#define INSN2_READ_MDMX_ACC 0x00000002 +/* Instruction writes MDMX accumulator. */ +#define INSN2_WRITE_MDMX_ACC 0x00000004 /* Instruction is actually a macro. It should be ignored by the disassembler, and requires special treatment by the assembler. */ @@ -447,12 +548,13 @@ struct mips_opcode /* Masks used for MIPS-defined ASEs. */ #define INSN_ASE_MASK 0x0000f000 +/* DSP ASE */ +#define INSN_DSP 0x00001000 +#define INSN_DSP64 0x00002000 /* MIPS 16 ASE */ -#define INSN_MIPS16 0x00002000 +#define INSN_MIPS16 0x00004000 /* MIPS-3D ASE */ -#define INSN_MIPS3D 0x00004000 -/* MDMX ASE */ -#define INSN_MDMX 0x00008000 +#define INSN_MIPS3D 0x00008000 /* Chip specific instructions. These are bitmasks. */ @@ -477,6 +579,15 @@ struct mips_opcode /* NEC VR5500 instruction. */ #define INSN_5500 0x02000000 +/* MDMX ASE */ +#define INSN_MDMX 0x04000000 +/* MT ASE */ +#define INSN_MT 0x08000000 +/* SmartMIPS ASE */ +#define INSN_SMARTMIPS 0x10000000 +/* DSP R2 ASE */ +#define INSN_DSPR2 0x20000000 + /* MIPS ISA defines, use instead of hardcoding ISA level. */ #define ISA_UNKNOWN 0 /* Gas internal use. */ @@ -533,6 +644,7 @@ struct mips_opcode (((insn)->membership & isa) != 0 \ || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0) \ || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0) \ + || (cpu == CPU_RM9000 && ((insn)->membership & INSN_4650) != 0) \ || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0) \ || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0) \ || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0) \ @@ -563,6 +675,7 @@ enum M_ADD_I, M_ADDU_I, M_AND_I, + M_BALIGN, M_BEQ, M_BEQ_I, M_BEQL_I, @@ -601,6 +714,7 @@ enum M_BNE, M_BNE_I, M_BNEL_I, + M_CACHE_AB, M_DABS, M_DADD_I, M_DADDU_I, @@ -907,6 +1021,11 @@ extern int bfd_mips_num_opcodes; "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5) */ +/* Save/restore encoding for the args field when all 4 registers are + either saved as arguments or saved/restored as statics. */ +#define MIPS16_ALL_ARGS 0xe +#define MIPS16_ALL_STATICS 0xb + /* For the mips16, we use the same opcode table format and a few of the same flags. However, most of the flags are different. */ @@ -1008,8 +1127,8 @@ extern const int bfd_mips16_num_opcodes; #define IS_M INSN_MULT -#define WR_MACC INSN_WRITE_MDMX_ACC -#define RD_MACC INSN_READ_MDMX_ACC +#define WR_MACC INSN2_WRITE_MDMX_ACC +#define RD_MACC INSN2_READ_MDMX_ACC #define I1 INSN_ISA1 #define I2 INSN_ISA2 @@ -1024,6 +1143,9 @@ extern const int bfd_mips16_num_opcodes; /* MIPS64 MIPS-3D ASE support. */ #define I16 INSN_MIPS16 +/* MIPS32 SmartMIPS ASE support. */ +#define SMT INSN_SMARTMIPS + /* MIPS64 MIPS-3D ASE support. */ #define M3D INSN_MIPS3D @@ -1051,6 +1173,38 @@ extern const int bfd_mips16_num_opcodes; #define G3 (I4 \ ) +/* MIPS DSP ASE support. + NOTE: + 1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3). $ac0 is the pair + of original HI and LO. $ac1, $ac2 and $ac3 are new registers, and have + the same structure as $ac0 (HI + LO). For DSP instructions that write or + read accumulators (that may be $ac0), we add WR_a (WR_HILO) or RD_a + (RD_HILO) attributes, such that HILO dependencies are maintained + conservatively. + + 2. For some mul. instructions that use integer registers as destinations + but destroy HI+LO as side-effect, we add WR_HILO to their attributes. + + 3. MIPS DSP ASE includes a new DSP control register, which has 6 fields + (ccond, outflag, EFI, c, scount, pos). Many DSP instructions read or write + certain fields of the DSP control register. For simplicity, we decide not + to track dependencies of these fields. + However, "bposge32" is a branch instruction that depends on the "pos" + field. In order to make sure that GAS does not reorder DSP instructions + that writes the "pos" field and "bposge32", we add DSP_VOLA (INSN_TRAP) + attribute to those instructions that write the "pos" field. */ + +#define WR_a WR_HILO /* Write dsp accumulators (reuse WR_HILO) */ +#define RD_a RD_HILO /* Read dsp accumulators (reuse RD_HILO) */ +#define MOD_a WR_a|RD_a +#define DSP_VOLA INSN_TRAP +#define D32 INSN_DSP +#define D33 INSN_DSPR2 +#define D64 INSN_DSP64 + +/* MIPS MT ASE support. */ +#define MT32 INSN_MT + /* The order of overloaded instructions matters. Label arguments and register arguments look the same. Instructions that can have either for arguments must apear in the correct order in this table for the @@ -1070,1083 +1224,1524 @@ const struct mips_opcode mips_builtin_opcodes[] = them first. The assemblers uses a hash table based on the instruction name anyhow. */ /* name, args, match, mask, pinfo, membership */ -{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, I4|I32|G3 }, -{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, I4 }, -{"nop", "", 0x00000000, 0xffffffff, 0, I1 }, /* sll */ -{"ssnop", "", 0x00000040, 0xffffffff, 0, I32|N55 }, /* sll */ -{"ehb", "", 0x000000c0, 0xffffffff, 0, I33 }, /* sll */ -{"li", "t,j", 0x24000000, 0xffe00000, WR_t, I1 }, /* addiu */ -{"li", "t,i", 0x34000000, 0xffe00000, WR_t, I1 }, /* ori */ -{"li", "t,I", 0, (int) M_LI, INSN_MACRO, I1 }, -{"move", "d,s", 0, (int) M_MOVE, INSN_MACRO, I1 }, -{"move", "d,s", 0x0000002d, 0xfc1f07ff, WR_d|RD_s, I3 },/* daddu */ -{"move", "d,s", 0x00000021, 0xfc1f07ff, WR_d|RD_s, I1 },/* addu */ -{"move", "d,s", 0x00000025, 0xfc1f07ff, WR_d|RD_s, I1 },/* or */ -{"b", "p", 0x10000000, 0xffff0000, UBD, I1 },/* beq 0,0 */ -{"b", "p", 0x04010000, 0xffff0000, UBD, I1 },/* bgez 0 */ -{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, I1 },/* bgezal 0*/ - -{"abs", "d,v", 0, (int) M_ABS, INSN_MACRO, I1 }, -{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_D|RD_S|FP_S, I1 }, -{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_D|RD_S|FP_D, I1 }, -{"abs.ps", "D,V", 0x46c00005, 0xffff003f, WR_D|RD_S|FP_D, I5 }, -{"add", "d,v,t", 0x00000020, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"add", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, I1 }, -{"add.s", "D,V,T", 0x46000000, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 }, -{"add.d", "D,V,T", 0x46200000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 }, -{"add.ob", "X,Y,Q", 0x7800000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"add.ob", "D,S,T", 0x4ac0000b, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"add.ob", "D,S,T[e]", 0x4800000b, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"add.ob", "D,S,k", 0x4bc0000b, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"add.ps", "D,V,T", 0x46c00000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, -{"add.qh", "X,Y,Q", 0x7820000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"adda.ob", "Y,Q", 0x78000037, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"adda.qh", "Y,Q", 0x78200037, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"addi", "t,r,j", 0x20000000, 0xfc000000, WR_t|RD_s, I1 }, -{"addiu", "t,r,j", 0x24000000, 0xfc000000, WR_t|RD_s, I1 }, -{"addl.ob", "Y,Q", 0x78000437, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"addl.qh", "Y,Q", 0x78200437, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"addr.ps", "D,S,T", 0x46c00018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D }, -{"addu", "d,v,t", 0x00000021, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"addu", "t,r,I", 0, (int) M_ADDU_I, INSN_MACRO, I1 }, -{"alni.ob", "X,Y,Z,O", 0x78000018, 0xff00003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"alni.ob", "D,S,T,%", 0x48000018, 0xff00003f, WR_D|RD_S|RD_T, N54 }, -{"alni.qh", "X,Y,Z,O", 0x7800001a, 0xff00003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"alnv.ps", "D,V,T,s", 0x4c00001e, 0xfc00003f, WR_D|RD_S|RD_T|FP_D, I5 }, -{"alnv.ob", "X,Y,Z,s", 0x78000019, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, MX|SB1 }, -{"alnv.qh", "X,Y,Z,s", 0x7800001b, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, MX }, -{"and", "d,v,t", 0x00000024, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"and", "t,r,I", 0, (int) M_AND_I, INSN_MACRO, I1 }, -{"and.ob", "X,Y,Q", 0x7800000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"and.ob", "D,S,T", 0x4ac0000c, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"and.ob", "D,S,T[e]", 0x4800000c, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"and.ob", "D,S,k", 0x4bc0000c, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"and.qh", "X,Y,Q", 0x7820000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"andi", "t,r,i", 0x30000000, 0xfc000000, WR_t|RD_s, I1 }, +{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, +{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, +{"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ +{"ssnop", "", 0x00000040, 0xffffffff, 0, INSN2_ALIAS, I32|N55 }, /* sll */ +{"ehb", "", 0x000000c0, 0xffffffff, 0, INSN2_ALIAS, I33 }, /* sll */ +{"li", "t,j", 0x24000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* addiu */ +{"li", "t,i", 0x34000000, 0xffe00000, WR_t, INSN2_ALIAS, I1 }, /* ori */ +{"li", "t,I", 0, (int) M_LI, INSN_MACRO, 0, I1 }, +{"move", "d,s", 0, (int) M_MOVE, INSN_MACRO, 0, I1 }, +{"move", "d,s", 0x0000002d, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I3 },/* daddu */ +{"move", "d,s", 0x00000021, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* addu */ +{"move", "d,s", 0x00000025, 0xfc1f07ff, WR_d|RD_s, INSN2_ALIAS, I1 },/* or */ +{"b", "p", 0x10000000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* beq 0,0 */ +{"b", "p", 0x04010000, 0xffff0000, UBD, INSN2_ALIAS, I1 },/* bgez 0 */ +{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, INSN2_ALIAS, I1 },/* bgezal 0*/ + +{"abs", "d,v", 0, (int) M_ABS, INSN_MACRO, 0, I1 }, +{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"abs.ps", "D,V", 0x46c00005, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"add", "d,v,t", 0x00000020, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"add", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, 0, I1 }, +{"add.s", "D,V,T", 0x46000000, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"add.d", "D,V,T", 0x46200000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"add.ob", "X,Y,Q", 0x7800000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"add.ob", "D,S,T", 0x4ac0000b, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ob", "D,S,T[e]", 0x4800000b, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ob", "D,S,k", 0x4bc0000b, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"add.ps", "D,V,T", 0x46c00000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"add.qh", "X,Y,Q", 0x7820000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"adda.ob", "Y,Q", 0x78000037, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"adda.qh", "Y,Q", 0x78200037, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"addi", "t,r,j", 0x20000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addiu", "t,r,j", 0x24000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"addl.ob", "Y,Q", 0x78000437, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"addl.qh", "Y,Q", 0x78200437, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"addr.ps", "D,S,T", 0x46c00018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"addu", "d,v,t", 0x00000021, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"addu", "t,r,I", 0, (int) M_ADDU_I, INSN_MACRO, 0, I1 }, +{"alni.ob", "X,Y,Z,O", 0x78000018, 0xff00003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"alni.ob", "D,S,T,%", 0x48000018, 0xff00003f, WR_D|RD_S|RD_T, 0, N54 }, +{"alni.qh", "X,Y,Z,O", 0x7800001a, 0xff00003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"alnv.ps", "D,V,T,s", 0x4c00001e, 0xfc00003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"alnv.ob", "X,Y,Z,s", 0x78000019, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, 0, MX|SB1 }, +{"alnv.qh", "X,Y,Z,s", 0x7800001b, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, 0, MX }, +{"and", "d,v,t", 0x00000024, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"and", "t,r,I", 0, (int) M_AND_I, INSN_MACRO, 0, I1 }, +{"and.ob", "X,Y,Q", 0x7800000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"and.ob", "D,S,T", 0x4ac0000c, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.ob", "D,S,T[e]", 0x4800000c, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.ob", "D,S,k", 0x4bc0000c, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"and.qh", "X,Y,Q", 0x7820000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"andi", "t,r,i", 0x30000000, 0xfc000000, WR_t|RD_s, 0, I1 }, /* b is at the top of the table. */ /* bal is at the top of the table. */ -{"bc0f", "p", 0x41000000, 0xffff0000, CBD|RD_CC, I1 }, -{"bc0fl", "p", 0x41020000, 0xffff0000, CBL|RD_CC, I2|T3 }, -{"bc0t", "p", 0x41010000, 0xffff0000, CBD|RD_CC, I1 }, -{"bc0tl", "p", 0x41030000, 0xffff0000, CBL|RD_CC, I2|T3 }, -{"bc1any2f", "N,p", 0x45200000, 0xffe30000, CBD|RD_CC|FP_S, M3D }, -{"bc1any2t", "N,p", 0x45210000, 0xffe30000, CBD|RD_CC|FP_S, M3D }, -{"bc1any4f", "N,p", 0x45400000, 0xffe30000, CBD|RD_CC|FP_S, M3D }, -{"bc1any4t", "N,p", 0x45410000, 0xffe30000, CBD|RD_CC|FP_S, M3D }, -{"bc1f", "p", 0x45000000, 0xffff0000, CBD|RD_CC|FP_S, I1 }, -{"bc1f", "N,p", 0x45000000, 0xffe30000, CBD|RD_CC|FP_S, I4|I32 }, -{"bc1fl", "p", 0x45020000, 0xffff0000, CBL|RD_CC|FP_S, I2|T3 }, -{"bc1fl", "N,p", 0x45020000, 0xffe30000, CBL|RD_CC|FP_S, I4|I32 }, -{"bc1t", "p", 0x45010000, 0xffff0000, CBD|RD_CC|FP_S, I1 }, -{"bc1t", "N,p", 0x45010000, 0xffe30000, CBD|RD_CC|FP_S, I4|I32 }, -{"bc1tl", "p", 0x45030000, 0xffff0000, CBL|RD_CC|FP_S, I2|T3 }, -{"bc1tl", "N,p", 0x45030000, 0xffe30000, CBL|RD_CC|FP_S, I4|I32 }, +/* bc0[tf]l? are at the bottom of the table. */ +{"bc1any2f", "N,p", 0x45200000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any2t", "N,p", 0x45210000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any4f", "N,p", 0x45400000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1any4t", "N,p", 0x45410000, 0xffe30000, CBD|RD_CC|FP_S, 0, M3D }, +{"bc1f", "p", 0x45000000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1f", "N,p", 0x45000000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4|I32 }, +{"bc1fl", "p", 0x45020000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2|T3 }, +{"bc1fl", "N,p", 0x45020000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4|I32 }, +{"bc1t", "p", 0x45010000, 0xffff0000, CBD|RD_CC|FP_S, 0, I1 }, +{"bc1t", "N,p", 0x45010000, 0xffe30000, CBD|RD_CC|FP_S, 0, I4|I32 }, +{"bc1tl", "p", 0x45030000, 0xffff0000, CBL|RD_CC|FP_S, 0, I2|T3 }, +{"bc1tl", "N,p", 0x45030000, 0xffe30000, CBL|RD_CC|FP_S, 0, I4|I32 }, /* bc2* are at the bottom of the table. */ -{"bc3f", "p", 0x4d000000, 0xffff0000, CBD|RD_CC, I1 }, -{"bc3fl", "p", 0x4d020000, 0xffff0000, CBL|RD_CC, I2|T3 }, -{"bc3t", "p", 0x4d010000, 0xffff0000, CBD|RD_CC, I1 }, -{"bc3tl", "p", 0x4d030000, 0xffff0000, CBL|RD_CC, I2|T3 }, -{"beqz", "s,p", 0x10000000, 0xfc1f0000, CBD|RD_s, I1 }, -{"beqzl", "s,p", 0x50000000, 0xfc1f0000, CBL|RD_s, I2|T3 }, -{"beq", "s,t,p", 0x10000000, 0xfc000000, CBD|RD_s|RD_t, I1 }, -{"beq", "s,I,p", 0, (int) M_BEQ_I, INSN_MACRO, I1 }, -{"beql", "s,t,p", 0x50000000, 0xfc000000, CBL|RD_s|RD_t, I2|T3 }, -{"beql", "s,I,p", 0, (int) M_BEQL_I, INSN_MACRO, I2|T3 }, -{"bge", "s,t,p", 0, (int) M_BGE, INSN_MACRO, I1 }, -{"bge", "s,I,p", 0, (int) M_BGE_I, INSN_MACRO, I1 }, -{"bgel", "s,t,p", 0, (int) M_BGEL, INSN_MACRO, I2|T3 }, -{"bgel", "s,I,p", 0, (int) M_BGEL_I, INSN_MACRO, I2|T3 }, -{"bgeu", "s,t,p", 0, (int) M_BGEU, INSN_MACRO, I1 }, -{"bgeu", "s,I,p", 0, (int) M_BGEU_I, INSN_MACRO, I1 }, -{"bgeul", "s,t,p", 0, (int) M_BGEUL, INSN_MACRO, I2|T3 }, -{"bgeul", "s,I,p", 0, (int) M_BGEUL_I, INSN_MACRO, I2|T3 }, -{"bgez", "s,p", 0x04010000, 0xfc1f0000, CBD|RD_s, I1 }, -{"bgezl", "s,p", 0x04030000, 0xfc1f0000, CBL|RD_s, I2|T3 }, -{"bgezal", "s,p", 0x04110000, 0xfc1f0000, CBD|RD_s|WR_31, I1 }, -{"bgezall", "s,p", 0x04130000, 0xfc1f0000, CBL|RD_s|WR_31, I2|T3 }, -{"bgt", "s,t,p", 0, (int) M_BGT, INSN_MACRO, I1 }, -{"bgt", "s,I,p", 0, (int) M_BGT_I, INSN_MACRO, I1 }, -{"bgtl", "s,t,p", 0, (int) M_BGTL, INSN_MACRO, I2|T3 }, -{"bgtl", "s,I,p", 0, (int) M_BGTL_I, INSN_MACRO, I2|T3 }, -{"bgtu", "s,t,p", 0, (int) M_BGTU, INSN_MACRO, I1 }, -{"bgtu", "s,I,p", 0, (int) M_BGTU_I, INSN_MACRO, I1 }, -{"bgtul", "s,t,p", 0, (int) M_BGTUL, INSN_MACRO, I2|T3 }, -{"bgtul", "s,I,p", 0, (int) M_BGTUL_I, INSN_MACRO, I2|T3 }, -{"bgtz", "s,p", 0x1c000000, 0xfc1f0000, CBD|RD_s, I1 }, -{"bgtzl", "s,p", 0x5c000000, 0xfc1f0000, CBL|RD_s, I2|T3 }, -{"ble", "s,t,p", 0, (int) M_BLE, INSN_MACRO, I1 }, -{"ble", "s,I,p", 0, (int) M_BLE_I, INSN_MACRO, I1 }, -{"blel", "s,t,p", 0, (int) M_BLEL, INSN_MACRO, I2|T3 }, -{"blel", "s,I,p", 0, (int) M_BLEL_I, INSN_MACRO, I2|T3 }, -{"bleu", "s,t,p", 0, (int) M_BLEU, INSN_MACRO, I1 }, -{"bleu", "s,I,p", 0, (int) M_BLEU_I, INSN_MACRO, I1 }, -{"bleul", "s,t,p", 0, (int) M_BLEUL, INSN_MACRO, I2|T3 }, -{"bleul", "s,I,p", 0, (int) M_BLEUL_I, INSN_MACRO, I2|T3 }, -{"blez", "s,p", 0x18000000, 0xfc1f0000, CBD|RD_s, I1 }, -{"blezl", "s,p", 0x58000000, 0xfc1f0000, CBL|RD_s, I2|T3 }, -{"blt", "s,t,p", 0, (int) M_BLT, INSN_MACRO, I1 }, -{"blt", "s,I,p", 0, (int) M_BLT_I, INSN_MACRO, I1 }, -{"bltl", "s,t,p", 0, (int) M_BLTL, INSN_MACRO, I2|T3 }, -{"bltl", "s,I,p", 0, (int) M_BLTL_I, INSN_MACRO, I2|T3 }, -{"bltu", "s,t,p", 0, (int) M_BLTU, INSN_MACRO, I1 }, -{"bltu", "s,I,p", 0, (int) M_BLTU_I, INSN_MACRO, I1 }, -{"bltul", "s,t,p", 0, (int) M_BLTUL, INSN_MACRO, I2|T3 }, -{"bltul", "s,I,p", 0, (int) M_BLTUL_I, INSN_MACRO, I2|T3 }, -{"bltz", "s,p", 0x04000000, 0xfc1f0000, CBD|RD_s, I1 }, -{"bltzl", "s,p", 0x04020000, 0xfc1f0000, CBL|RD_s, I2|T3 }, -{"bltzal", "s,p", 0x04100000, 0xfc1f0000, CBD|RD_s|WR_31, I1 }, -{"bltzall", "s,p", 0x04120000, 0xfc1f0000, CBL|RD_s|WR_31, I2|T3 }, -{"bnez", "s,p", 0x14000000, 0xfc1f0000, CBD|RD_s, I1 }, -{"bnezl", "s,p", 0x54000000, 0xfc1f0000, CBL|RD_s, I2|T3 }, -{"bne", "s,t,p", 0x14000000, 0xfc000000, CBD|RD_s|RD_t, I1 }, -{"bne", "s,I,p", 0, (int) M_BNE_I, INSN_MACRO, I1 }, -{"bnel", "s,t,p", 0x54000000, 0xfc000000, CBL|RD_s|RD_t, I2|T3 }, -{"bnel", "s,I,p", 0, (int) M_BNEL_I, INSN_MACRO, I2|T3 }, -{"break", "", 0x0000000d, 0xffffffff, TRAP, I1 }, -{"break", "c", 0x0000000d, 0xfc00ffff, TRAP, I1 }, -{"break", "c,q", 0x0000000d, 0xfc00003f, TRAP, I1 }, -{"c.f.d", "S,T", 0x46200030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.f.d", "M,S,T", 0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.f.s", "S,T", 0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.f.s", "M,S,T", 0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.f.ps", "S,T", 0x46c00030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.f.ps", "M,S,T", 0x46c00030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.un.d", "S,T", 0x46200031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.un.d", "M,S,T", 0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.un.s", "S,T", 0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.un.s", "M,S,T", 0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.un.ps", "S,T", 0x46c00031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.un.ps", "M,S,T", 0x46c00031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.eq.d", "S,T", 0x46200032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.eq.d", "M,S,T", 0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.eq.s", "S,T", 0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.eq.s", "M,S,T", 0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.eq.ob", "Y,Q", 0x78000001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 }, -{"c.eq.ob", "S,T", 0x4ac00001, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.eq.ob", "S,T[e]", 0x48000001, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.eq.ob", "S,k", 0x4bc00001, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.eq.ps", "S,T", 0x46c00032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.eq.ps", "M,S,T", 0x46c00032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.eq.qh", "Y,Q", 0x78200001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX }, -{"c.ueq.d", "S,T", 0x46200033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.ueq.d", "M,S,T", 0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.ueq.s", "S,T", 0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.ueq.s", "M,S,T", 0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.ueq.ps","S,T", 0x46c00033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ueq.ps","M,S,T", 0x46c00033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.olt.d", "S,T", 0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.olt.d", "M,S,T", 0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.olt.s", "S,T", 0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.olt.s", "M,S,T", 0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.olt.ps","S,T", 0x46c00034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.olt.ps","M,S,T", 0x46c00034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ult.d", "S,T", 0x46200035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.ult.d", "M,S,T", 0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.ult.s", "S,T", 0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.ult.s", "M,S,T", 0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.ult.ps","S,T", 0x46c00035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ult.ps","M,S,T", 0x46c00035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ole.d", "S,T", 0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.ole.d", "M,S,T", 0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.ole.s", "S,T", 0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.ole.s", "M,S,T", 0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.ole.ps","S,T", 0x46c00036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ole.ps","M,S,T", 0x46c00036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ule.d", "S,T", 0x46200037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.ule.d", "M,S,T", 0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.ule.s", "S,T", 0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.ule.s", "M,S,T", 0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.ule.ps","S,T", 0x46c00037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ule.ps","M,S,T", 0x46c00037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.sf.d", "S,T", 0x46200038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.sf.d", "M,S,T", 0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.sf.s", "S,T", 0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.sf.s", "M,S,T", 0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.sf.ps", "S,T", 0x46c00038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.sf.ps", "M,S,T", 0x46c00038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ngle.d","S,T", 0x46200039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.ngle.d","M,S,T", 0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.ngle.s","S,T", 0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.ngle.s","M,S,T", 0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.ngle.ps","S,T", 0x46c00039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ngle.ps","M,S,T", 0x46c00039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.seq.d", "S,T", 0x4620003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.seq.d", "M,S,T", 0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.seq.s", "S,T", 0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.seq.s", "M,S,T", 0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.seq.ps","S,T", 0x46c0003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.seq.ps","M,S,T", 0x46c0003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ngl.d", "S,T", 0x4620003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.ngl.d", "M,S,T", 0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.ngl.s", "S,T", 0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.ngl.s", "M,S,T", 0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.ngl.ps","S,T", 0x46c0003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ngl.ps","M,S,T", 0x46c0003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.lt.d", "S,T", 0x4620003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.lt.d", "M,S,T", 0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.lt.s", "S,T", 0x4600003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.lt.s", "M,S,T", 0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.lt.ob", "Y,Q", 0x78000004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 }, -{"c.lt.ob", "S,T", 0x4ac00004, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.lt.ob", "S,T[e]", 0x48000004, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.lt.ob", "S,k", 0x4bc00004, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.lt.ps", "S,T", 0x46c0003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.lt.ps", "M,S,T", 0x46c0003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.lt.qh", "Y,Q", 0x78200004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX }, -{"c.nge.d", "S,T", 0x4620003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.nge.d", "M,S,T", 0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.nge.s", "S,T", 0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.nge.s", "M,S,T", 0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.nge.ps","S,T", 0x46c0003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.nge.ps","M,S,T", 0x46c0003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.le.d", "S,T", 0x4620003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.le.d", "M,S,T", 0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.le.s", "S,T", 0x4600003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.le.s", "M,S,T", 0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.le.ob", "Y,Q", 0x78000005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 }, -{"c.le.ob", "S,T", 0x4ac00005, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.le.ob", "S,T[e]", 0x48000005, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.le.ob", "S,k", 0x4bc00005, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"c.le.ps", "S,T", 0x46c0003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.le.ps", "M,S,T", 0x46c0003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.le.qh", "Y,Q", 0x78200005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX }, -{"c.ngt.d", "S,T", 0x4620003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 }, -{"c.ngt.d", "M,S,T", 0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 }, -{"c.ngt.s", "S,T", 0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 }, -{"c.ngt.s", "M,S,T", 0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 }, -{"c.ngt.ps","S,T", 0x46c0003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"c.ngt.ps","M,S,T", 0x46c0003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 }, -{"cabs.eq.d", "M,S,T", 0x46200072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.eq.ps", "M,S,T", 0x46c00072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.eq.s", "M,S,T", 0x46000072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.f.d", "M,S,T", 0x46200070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.f.ps", "M,S,T", 0x46c00070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.f.s", "M,S,T", 0x46000070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.le.d", "M,S,T", 0x4620007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.le.ps", "M,S,T", 0x46c0007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.le.s", "M,S,T", 0x4600007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.lt.d", "M,S,T", 0x4620007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.lt.ps", "M,S,T", 0x46c0007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.lt.s", "M,S,T", 0x4600007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.nge.d", "M,S,T", 0x4620007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.nge.ps","M,S,T", 0x46c0007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.nge.s", "M,S,T", 0x4600007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.ngl.d", "M,S,T", 0x4620007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ngl.ps","M,S,T", 0x46c0007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ngl.s", "M,S,T", 0x4600007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.ngle.d","M,S,T", 0x46200079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ngle.s","M,S,T", 0x46000079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.ngt.d", "M,S,T", 0x4620007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ngt.ps","M,S,T", 0x46c0007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ngt.s", "M,S,T", 0x4600007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.ole.d", "M,S,T", 0x46200076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ole.ps","M,S,T", 0x46c00076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ole.s", "M,S,T", 0x46000076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.olt.d", "M,S,T", 0x46200074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.olt.ps","M,S,T", 0x46c00074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.olt.s", "M,S,T", 0x46000074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.seq.d", "M,S,T", 0x4620007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.seq.ps","M,S,T", 0x46c0007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.seq.s", "M,S,T", 0x4600007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.sf.d", "M,S,T", 0x46200078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.sf.ps", "M,S,T", 0x46c00078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.sf.s", "M,S,T", 0x46000078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.ueq.d", "M,S,T", 0x46200073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ueq.ps","M,S,T", 0x46c00073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ueq.s", "M,S,T", 0x46000073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.ule.d", "M,S,T", 0x46200077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ule.ps","M,S,T", 0x46c00077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ule.s", "M,S,T", 0x46000077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.ult.d", "M,S,T", 0x46200075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ult.ps","M,S,T", 0x46c00075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.ult.s", "M,S,T", 0x46000075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cabs.un.d", "M,S,T", 0x46200071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.un.ps", "M,S,T", 0x46c00071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D }, -{"cabs.un.s", "M,S,T", 0x46000071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D }, -{"cache", "k,o(b)", 0xbc000000, 0xfc000000, RD_b, I3|I32|T3}, -{"ceil.l.d", "D,S", 0x4620000a, 0xffff003f, WR_D|RD_S|FP_D, I3 }, -{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S, I3 }, -{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_D, I2 }, -{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, I2 }, -{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, I1 }, -{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, I1 }, -{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, I1 }, +/* bc3* are at the bottom of the table. */ +{"beqz", "s,p", 0x10000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"beqzl", "s,p", 0x50000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"beq", "s,t,p", 0x10000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"beq", "s,I,p", 0, (int) M_BEQ_I, INSN_MACRO, 0, I1 }, +{"beql", "s,t,p", 0x50000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2|T3 }, +{"beql", "s,I,p", 0, (int) M_BEQL_I, INSN_MACRO, 0, I2|T3 }, +{"bge", "s,t,p", 0, (int) M_BGE, INSN_MACRO, 0, I1 }, +{"bge", "s,I,p", 0, (int) M_BGE_I, INSN_MACRO, 0, I1 }, +{"bgel", "s,t,p", 0, (int) M_BGEL, INSN_MACRO, 0, I2|T3 }, +{"bgel", "s,I,p", 0, (int) M_BGEL_I, INSN_MACRO, 0, I2|T3 }, +{"bgeu", "s,t,p", 0, (int) M_BGEU, INSN_MACRO, 0, I1 }, +{"bgeu", "s,I,p", 0, (int) M_BGEU_I, INSN_MACRO, 0, I1 }, +{"bgeul", "s,t,p", 0, (int) M_BGEUL, INSN_MACRO, 0, I2|T3 }, +{"bgeul", "s,I,p", 0, (int) M_BGEUL_I, INSN_MACRO, 0, I2|T3 }, +{"bgez", "s,p", 0x04010000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgezl", "s,p", 0x04030000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bgezal", "s,p", 0x04110000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bgezall", "s,p", 0x04130000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2|T3 }, +{"bgt", "s,t,p", 0, (int) M_BGT, INSN_MACRO, 0, I1 }, +{"bgt", "s,I,p", 0, (int) M_BGT_I, INSN_MACRO, 0, I1 }, +{"bgtl", "s,t,p", 0, (int) M_BGTL, INSN_MACRO, 0, I2|T3 }, +{"bgtl", "s,I,p", 0, (int) M_BGTL_I, INSN_MACRO, 0, I2|T3 }, +{"bgtu", "s,t,p", 0, (int) M_BGTU, INSN_MACRO, 0, I1 }, +{"bgtu", "s,I,p", 0, (int) M_BGTU_I, INSN_MACRO, 0, I1 }, +{"bgtul", "s,t,p", 0, (int) M_BGTUL, INSN_MACRO, 0, I2|T3 }, +{"bgtul", "s,I,p", 0, (int) M_BGTUL_I, INSN_MACRO, 0, I2|T3 }, +{"bgtz", "s,p", 0x1c000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bgtzl", "s,p", 0x5c000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"ble", "s,t,p", 0, (int) M_BLE, INSN_MACRO, 0, I1 }, +{"ble", "s,I,p", 0, (int) M_BLE_I, INSN_MACRO, 0, I1 }, +{"blel", "s,t,p", 0, (int) M_BLEL, INSN_MACRO, 0, I2|T3 }, +{"blel", "s,I,p", 0, (int) M_BLEL_I, INSN_MACRO, 0, I2|T3 }, +{"bleu", "s,t,p", 0, (int) M_BLEU, INSN_MACRO, 0, I1 }, +{"bleu", "s,I,p", 0, (int) M_BLEU_I, INSN_MACRO, 0, I1 }, +{"bleul", "s,t,p", 0, (int) M_BLEUL, INSN_MACRO, 0, I2|T3 }, +{"bleul", "s,I,p", 0, (int) M_BLEUL_I, INSN_MACRO, 0, I2|T3 }, +{"blez", "s,p", 0x18000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"blezl", "s,p", 0x58000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"blt", "s,t,p", 0, (int) M_BLT, INSN_MACRO, 0, I1 }, +{"blt", "s,I,p", 0, (int) M_BLT_I, INSN_MACRO, 0, I1 }, +{"bltl", "s,t,p", 0, (int) M_BLTL, INSN_MACRO, 0, I2|T3 }, +{"bltl", "s,I,p", 0, (int) M_BLTL_I, INSN_MACRO, 0, I2|T3 }, +{"bltu", "s,t,p", 0, (int) M_BLTU, INSN_MACRO, 0, I1 }, +{"bltu", "s,I,p", 0, (int) M_BLTU_I, INSN_MACRO, 0, I1 }, +{"bltul", "s,t,p", 0, (int) M_BLTUL, INSN_MACRO, 0, I2|T3 }, +{"bltul", "s,I,p", 0, (int) M_BLTUL_I, INSN_MACRO, 0, I2|T3 }, +{"bltz", "s,p", 0x04000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bltzl", "s,p", 0x04020000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bltzal", "s,p", 0x04100000, 0xfc1f0000, CBD|RD_s|WR_31, 0, I1 }, +{"bltzall", "s,p", 0x04120000, 0xfc1f0000, CBL|RD_s|WR_31, 0, I2|T3 }, +{"bnez", "s,p", 0x14000000, 0xfc1f0000, CBD|RD_s, 0, I1 }, +{"bnezl", "s,p", 0x54000000, 0xfc1f0000, CBL|RD_s, 0, I2|T3 }, +{"bne", "s,t,p", 0x14000000, 0xfc000000, CBD|RD_s|RD_t, 0, I1 }, +{"bne", "s,I,p", 0, (int) M_BNE_I, INSN_MACRO, 0, I1 }, +{"bnel", "s,t,p", 0x54000000, 0xfc000000, CBL|RD_s|RD_t, 0, I2|T3 }, +{"bnel", "s,I,p", 0, (int) M_BNEL_I, INSN_MACRO, 0, I2|T3 }, +{"break", "", 0x0000000d, 0xffffffff, TRAP, 0, I1 }, +{"break", "c", 0x0000000d, 0xfc00ffff, TRAP, 0, I1 }, +{"break", "c,q", 0x0000000d, 0xfc00003f, TRAP, 0, I1 }, +{"c.f.d", "S,T", 0x46200030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.f.d", "M,S,T", 0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.f.s", "S,T", 0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.f.s", "M,S,T", 0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.f.ps", "S,T", 0x46c00030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.f.ps", "M,S,T", 0x46c00030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.un.d", "S,T", 0x46200031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.un.d", "M,S,T", 0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.un.s", "S,T", 0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.un.s", "M,S,T", 0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.un.ps", "S,T", 0x46c00031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.un.ps", "M,S,T", 0x46c00031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.d", "S,T", 0x46200032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.eq.d", "M,S,T", 0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.eq.s", "S,T", 0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.eq.s", "M,S,T", 0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.eq.ob", "Y,Q", 0x78000001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.eq.ob", "S,T", 0x4ac00001, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ob", "S,T[e]", 0x48000001, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ob", "S,k", 0x4bc00001, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.eq.ps", "S,T", 0x46c00032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.ps", "M,S,T", 0x46c00032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.eq.qh", "Y,Q", 0x78200001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.ueq.d", "S,T", 0x46200033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ueq.d", "M,S,T", 0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ueq.s", "S,T", 0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ueq.s", "M,S,T", 0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ueq.ps","S,T", 0x46c00033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ueq.ps","M,S,T", 0x46c00033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.olt.d", "S,T", 0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.olt.d", "M,S,T", 0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.olt.s", "S,T", 0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.olt.s", "M,S,T", 0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.olt.ps","S,T", 0x46c00034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.olt.ps","M,S,T", 0x46c00034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ult.d", "S,T", 0x46200035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ult.d", "M,S,T", 0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ult.s", "S,T", 0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ult.s", "M,S,T", 0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ult.ps","S,T", 0x46c00035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ult.ps","M,S,T", 0x46c00035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ole.d", "S,T", 0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ole.d", "M,S,T", 0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ole.s", "S,T", 0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ole.s", "M,S,T", 0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ole.ps","S,T", 0x46c00036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ole.ps","M,S,T", 0x46c00036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ule.d", "S,T", 0x46200037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ule.d", "M,S,T", 0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ule.s", "S,T", 0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ule.s", "M,S,T", 0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ule.ps","S,T", 0x46c00037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ule.ps","M,S,T", 0x46c00037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.sf.d", "S,T", 0x46200038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.sf.d", "M,S,T", 0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.sf.s", "S,T", 0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.sf.s", "M,S,T", 0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.sf.ps", "S,T", 0x46c00038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.sf.ps", "M,S,T", 0x46c00038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngle.d","S,T", 0x46200039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngle.d","M,S,T", 0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngle.s","S,T", 0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngle.s","M,S,T", 0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngle.ps","S,T", 0x46c00039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngle.ps","M,S,T", 0x46c00039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.seq.d", "S,T", 0x4620003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.seq.d", "M,S,T", 0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.seq.s", "S,T", 0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.seq.s", "M,S,T", 0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.seq.ps","S,T", 0x46c0003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.seq.ps","M,S,T", 0x46c0003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngl.d", "S,T", 0x4620003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngl.d", "M,S,T", 0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngl.s", "S,T", 0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngl.s", "M,S,T", 0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngl.ps","S,T", 0x46c0003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngl.ps","M,S,T", 0x46c0003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.d", "S,T", 0x4620003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.lt.d", "M,S,T", 0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.lt.s", "S,T", 0x4600003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.lt.s", "M,S,T", 0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.lt.ob", "Y,Q", 0x78000004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.lt.ob", "S,T", 0x4ac00004, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ob", "S,T[e]", 0x48000004, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ob", "S,k", 0x4bc00004, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.lt.ps", "S,T", 0x46c0003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.ps", "M,S,T", 0x46c0003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.lt.qh", "Y,Q", 0x78200004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.nge.d", "S,T", 0x4620003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.nge.d", "M,S,T", 0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.nge.s", "S,T", 0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.nge.s", "M,S,T", 0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.nge.ps","S,T", 0x46c0003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.nge.ps","M,S,T", 0x46c0003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.d", "S,T", 0x4620003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.le.d", "M,S,T", 0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.le.s", "S,T", 0x4600003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.le.s", "M,S,T", 0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.le.ob", "Y,Q", 0x78000005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"c.le.ob", "S,T", 0x4ac00005, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ob", "S,T[e]", 0x48000005, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ob", "S,k", 0x4bc00005, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"c.le.ps", "S,T", 0x46c0003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.ps", "M,S,T", 0x46c0003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.le.qh", "Y,Q", 0x78200005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, 0, MX }, +{"c.ngt.d", "S,T", 0x4620003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I1 }, +{"c.ngt.d", "M,S,T", 0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I4|I32 }, +{"c.ngt.s", "S,T", 0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, 0, I1 }, +{"c.ngt.s", "M,S,T", 0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, I4|I32 }, +{"c.ngt.ps","S,T", 0x46c0003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"c.ngt.ps","M,S,T", 0x46c0003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, I5|I33 }, +{"cabs.eq.d", "M,S,T", 0x46200072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.eq.ps", "M,S,T", 0x46c00072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.eq.s", "M,S,T", 0x46000072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.f.d", "M,S,T", 0x46200070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.f.ps", "M,S,T", 0x46c00070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.f.s", "M,S,T", 0x46000070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.le.d", "M,S,T", 0x4620007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.le.ps", "M,S,T", 0x46c0007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.le.s", "M,S,T", 0x4600007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.lt.d", "M,S,T", 0x4620007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.lt.ps", "M,S,T", 0x46c0007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.lt.s", "M,S,T", 0x4600007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.nge.d", "M,S,T", 0x4620007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.nge.ps","M,S,T", 0x46c0007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.nge.s", "M,S,T", 0x4600007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngl.d", "M,S,T", 0x4620007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngl.ps","M,S,T", 0x46c0007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngl.s", "M,S,T", 0x4600007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngle.d","M,S,T", 0x46200079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngle.s","M,S,T", 0x46000079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ngt.d", "M,S,T", 0x4620007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngt.ps","M,S,T", 0x46c0007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ngt.s", "M,S,T", 0x4600007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ole.d", "M,S,T", 0x46200076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ole.ps","M,S,T", 0x46c00076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ole.s", "M,S,T", 0x46000076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.olt.d", "M,S,T", 0x46200074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.olt.ps","M,S,T", 0x46c00074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.olt.s", "M,S,T", 0x46000074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.seq.d", "M,S,T", 0x4620007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.seq.ps","M,S,T", 0x46c0007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.seq.s", "M,S,T", 0x4600007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.sf.d", "M,S,T", 0x46200078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.sf.ps", "M,S,T", 0x46c00078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.sf.s", "M,S,T", 0x46000078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ueq.d", "M,S,T", 0x46200073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ueq.ps","M,S,T", 0x46c00073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ueq.s", "M,S,T", 0x46000073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ule.d", "M,S,T", 0x46200077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ule.ps","M,S,T", 0x46c00077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ule.s", "M,S,T", 0x46000077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.ult.d", "M,S,T", 0x46200075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ult.ps","M,S,T", 0x46c00075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.ult.s", "M,S,T", 0x46000075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +{"cabs.un.d", "M,S,T", 0x46200071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.un.ps", "M,S,T", 0x46c00071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, 0, M3D }, +{"cabs.un.s", "M,S,T", 0x46000071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, 0, M3D }, +/* CW4010 instructions which are aliases for the cache instruction. */ +{"flushi", "", 0xbc010000, 0xffffffff, 0, 0, L1 }, +{"flushd", "", 0xbc020000, 0xffffffff, 0, 0, L1 }, +{"flushid", "", 0xbc030000, 0xffffffff, 0, 0, L1 }, +{"wb", "o(b)", 0xbc040000, 0xfc1f0000, SM|RD_b, 0, L1 }, +{"cache", "k,o(b)", 0xbc000000, 0xfc000000, RD_b, 0, I3|I32|T3}, +{"cache", "k,A(b)", 0, (int) M_CACHE_AB, INSN_MACRO, 0, I3|I32|T3}, +{"ceil.l.d", "D,S", 0x4620000a, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, +{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, /* cfc2 is at the bottom of the table. */ -{"cfc3", "t,G", 0x4c400000, 0xffe007ff, LCD|WR_t|RD_C3, I1 }, -{"clo", "U,s", 0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, I32|N55 }, -{"clz", "U,s", 0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, I32|N55 }, -{"ctc0", "t,G", 0x40c00000, 0xffe007ff, COD|RD_t|WR_CC, I1 }, -{"ctc1", "t,G", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, I1 }, -{"ctc1", "t,S", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, I1 }, +/* cfc3 is at the bottom of the table. */ +{"cftc1", "d,E", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc1", "d,T", 0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0, MT32 }, +{"cftc2", "d,E", 0x41000025, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"clo", "U,s", 0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32|N55 }, +{"clz", "U,s", 0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 0, I32|N55 }, +{"ctc0", "t,G", 0x40c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"ctc1", "t,G", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, +{"ctc1", "t,S", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, 0, I1 }, /* ctc2 is at the bottom of the table. */ -{"ctc3", "t,G", 0x4cc00000, 0xffe007ff, COD|RD_t|WR_CC, I1 }, -{"cvt.d.l", "D,S", 0x46a00021, 0xffff003f, WR_D|RD_S|FP_D, I3 }, -{"cvt.d.s", "D,S", 0x46000021, 0xffff003f, WR_D|RD_S|FP_D|FP_S, I1 }, -{"cvt.d.w", "D,S", 0x46800021, 0xffff003f, WR_D|RD_S|FP_D, I1 }, -{"cvt.l.d", "D,S", 0x46200025, 0xffff003f, WR_D|RD_S|FP_D, I3 }, -{"cvt.l.s", "D,S", 0x46000025, 0xffff003f, WR_D|RD_S|FP_S, I3 }, -{"cvt.s.l", "D,S", 0x46a00020, 0xffff003f, WR_D|RD_S|FP_S, I3 }, -{"cvt.s.d", "D,S", 0x46200020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I1 }, -{"cvt.s.w", "D,S", 0x46800020, 0xffff003f, WR_D|RD_S|FP_S, I1 }, -{"cvt.s.pl","D,S", 0x46c00028, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I5 }, -{"cvt.s.pu","D,S", 0x46c00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I5 }, -{"cvt.w.d", "D,S", 0x46200024, 0xffff003f, WR_D|RD_S|FP_D, I1 }, -{"cvt.w.s", "D,S", 0x46000024, 0xffff003f, WR_D|RD_S|FP_S, I1 }, -{"cvt.ps.pw", "D,S", 0x46800026, 0xffff003f, WR_D|RD_S|FP_S|FP_D, M3D }, -{"cvt.ps.s","D,V,T", 0x46000026, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, -{"cvt.pw.ps", "D,S", 0x46c00024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, M3D }, -{"dabs", "d,v", 0, (int) M_DABS, INSN_MACRO, I3 }, -{"dadd", "d,v,t", 0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t, I3 }, -{"dadd", "t,r,I", 0, (int) M_DADD_I, INSN_MACRO, I3 }, -{"daddi", "t,r,j", 0x60000000, 0xfc000000, WR_t|RD_s, I3 }, -{"daddiu", "t,r,j", 0x64000000, 0xfc000000, WR_t|RD_s, I3 }, -{"daddu", "d,v,t", 0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t, I3 }, -{"daddu", "t,r,I", 0, (int) M_DADDU_I, INSN_MACRO, I3 }, -{"dbreak", "", 0x7000003f, 0xffffffff, 0, N5 }, -{"dclo", "U,s", 0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, I64|N55 }, -{"dclz", "U,s", 0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, I64|N55 }, +/* ctc3 is at the bottom of the table. */ +{"cttc1", "t,g", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc1", "t,S", 0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0, MT32 }, +{"cttc2", "t,g", 0x41800025, 0xffe007ff, TRAP|COD|RD_t|WR_CC, 0, MT32 }, +{"cvt.d.l", "D,S", 0x46a00021, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"cvt.d.s", "D,S", 0x46000021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.d.w", "D,S", 0x46800021, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.l.d", "D,S", 0x46200025, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"cvt.l.s", "D,S", 0x46000025, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"cvt.s.l", "D,S", 0x46a00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"cvt.s.d", "D,S", 0x46200020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.s.w", "D,S", 0x46800020, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.s.pl","D,S", 0x46c00028, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5|I33 }, +{"cvt.s.pu","D,S", 0x46c00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I5|I33 }, +{"cvt.w.d", "D,S", 0x46200024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I1 }, +{"cvt.w.s", "D,S", 0x46000024, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"cvt.ps.pw", "D,S", 0x46800026, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, M3D }, +{"cvt.ps.s","D,V,T", 0x46000026, 0xffe0003f, WR_D|RD_S|RD_T|FP_S|FP_D, 0, I5|I33 }, +{"cvt.pw.ps", "D,S", 0x46c00024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, M3D }, +{"dabs", "d,v", 0, (int) M_DABS, INSN_MACRO, 0, I3 }, +{"dadd", "d,v,t", 0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dadd", "t,r,I", 0, (int) M_DADD_I, INSN_MACRO, 0, I3 }, +{"daddi", "t,r,j", 0x60000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddiu", "t,r,j", 0x64000000, 0xfc000000, WR_t|RD_s, 0, I3 }, +{"daddu", "d,v,t", 0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"daddu", "t,r,I", 0, (int) M_DADDU_I, INSN_MACRO, 0, I3 }, +{"dbreak", "", 0x7000003f, 0xffffffff, 0, 0, N5 }, +{"dclo", "U,s", 0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64|N55 }, +{"dclz", "U,s", 0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, 0, I64|N55 }, /* dctr and dctw are used on the r5000. */ -{"dctr", "o(b)", 0xbc050000, 0xfc1f0000, RD_b, I3 }, -{"dctw", "o(b)", 0xbc090000, 0xfc1f0000, RD_b, I3 }, -{"deret", "", 0x4200001f, 0xffffffff, 0, I32|G2 }, -{"dext", "t,r,I,+I", 0, (int) M_DEXT, INSN_MACRO, I65 }, -{"dext", "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s, I65 }, -{"dextm", "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s, I65 }, -{"dextu", "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s, I65 }, +{"dctr", "o(b)", 0xbc050000, 0xfc1f0000, RD_b, 0, I3 }, +{"dctw", "o(b)", 0xbc090000, 0xfc1f0000, RD_b, 0, I3 }, +{"deret", "", 0x4200001f, 0xffffffff, 0, 0, I32|G2 }, +{"dext", "t,r,I,+I", 0, (int) M_DEXT, INSN_MACRO, 0, I65 }, +{"dext", "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextm", "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dextu", "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s, 0, I65 }, /* For ddiv, see the comments about div. */ -{"ddiv", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, -{"ddiv", "d,v,t", 0, (int) M_DDIV_3, INSN_MACRO, I3 }, -{"ddiv", "d,v,I", 0, (int) M_DDIV_3I, INSN_MACRO, I3 }, +{"ddiv", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"ddiv", "d,v,t", 0, (int) M_DDIV_3, INSN_MACRO, 0, I3 }, +{"ddiv", "d,v,I", 0, (int) M_DDIV_3I, INSN_MACRO, 0, I3 }, /* For ddivu, see the comments about div. */ -{"ddivu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, -{"ddivu", "d,v,t", 0, (int) M_DDIVU_3, INSN_MACRO, I3 }, -{"ddivu", "d,v,I", 0, (int) M_DDIVU_3I, INSN_MACRO, I3 }, -{"di", "", 0x41606000, 0xffffffff, WR_t|WR_C0, I33 }, -{"di", "t", 0x41606000, 0xffe0ffff, WR_t|WR_C0, I33 }, -{"dins", "t,r,I,+I", 0, (int) M_DINS, INSN_MACRO, I65 }, -{"dins", "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s, I65 }, -{"dinsm", "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s, I65 }, -{"dinsu", "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s, I65 }, +{"ddivu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"ddivu", "d,v,t", 0, (int) M_DDIVU_3, INSN_MACRO, 0, I3 }, +{"ddivu", "d,v,I", 0, (int) M_DDIVU_3I, INSN_MACRO, 0, I3 }, +{"di", "", 0x41606000, 0xffffffff, WR_t|WR_C0, 0, I33 }, +{"di", "t", 0x41606000, 0xffe0ffff, WR_t|WR_C0, 0, I33 }, +{"dins", "t,r,I,+I", 0, (int) M_DINS, INSN_MACRO, 0, I65 }, +{"dins", "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsm", "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s, 0, I65 }, +{"dinsu", "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s, 0, I65 }, /* The MIPS assembler treats the div opcode with two operands as though the first operand appeared twice (the first operand is both a source and a destination). To get the div machine instruction, you must use an explicit destination of $0. */ -{"div", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 }, -{"div", "z,t", 0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO, I1 }, -{"div", "d,v,t", 0, (int) M_DIV_3, INSN_MACRO, I1 }, -{"div", "d,v,I", 0, (int) M_DIV_3I, INSN_MACRO, I1 }, -{"div.d", "D,V,T", 0x46200003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 }, -{"div.s", "D,V,T", 0x46000003, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 }, -{"div.ps", "D,V,T", 0x46c00003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, SB1 }, +{"div", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "z,t", 0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"div", "d,v,t", 0, (int) M_DIV_3, INSN_MACRO, 0, I1 }, +{"div", "d,v,I", 0, (int) M_DIV_3I, INSN_MACRO, 0, I1 }, +{"div.d", "D,V,T", 0x46200003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"div.s", "D,V,T", 0x46000003, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"div.ps", "D,V,T", 0x46c00003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, /* For divu, see the comments about div. */ -{"divu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 }, -{"divu", "z,t", 0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO, I1 }, -{"divu", "d,v,t", 0, (int) M_DIVU_3, INSN_MACRO, I1 }, -{"divu", "d,v,I", 0, (int) M_DIVU_3I, INSN_MACRO, I1 }, -{"dla", "t,A(b)", 0, (int) M_DLA_AB, INSN_MACRO, I3 }, -{"dlca", "t,A(b)", 0, (int) M_DLCA_AB, INSN_MACRO, I3 }, -{"dli", "t,j", 0x24000000, 0xffe00000, WR_t, I3 }, /* addiu */ -{"dli", "t,i", 0x34000000, 0xffe00000, WR_t, I3 }, /* ori */ -{"dli", "t,I", 0, (int) M_DLI, INSN_MACRO, I3 }, -{"dmacc", "d,s,t", 0x00000029, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, -{"dmacchi", "d,s,t", 0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, -{"dmacchis", "d,s,t", 0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, -{"dmacchiu", "d,s,t", 0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, -{"dmacchius", "d,s,t", 0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, -{"dmaccs", "d,s,t", 0x00000429, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, -{"dmaccu", "d,s,t", 0x00000069, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, -{"dmaccus", "d,s,t", 0x00000469, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 }, -{"dmadd16", "s,t", 0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO, N411 }, -{"dmfc0", "t,G", 0x40200000, 0xffe007ff, LCD|WR_t|RD_C0, I3 }, -{"dmfc0", "t,+D", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, I64 }, -{"dmfc0", "t,G,H", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, I64 }, -{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, I3 }, -{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I64 }, -{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I64 }, -{"dmfc1", "t,S", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I3 }, -{"dmfc1", "t,G", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I3 }, -{"dmtc1", "t,S", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I3 }, -{"dmtc1", "t,G", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I3 }, +{"divu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "z,t", 0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"divu", "d,v,t", 0, (int) M_DIVU_3, INSN_MACRO, 0, I1 }, +{"divu", "d,v,I", 0, (int) M_DIVU_3I, INSN_MACRO, 0, I1 }, +{"dla", "t,A(b)", 0, (int) M_DLA_AB, INSN_MACRO, 0, I3 }, +{"dlca", "t,A(b)", 0, (int) M_DLCA_AB, INSN_MACRO, 0, I3 }, +{"dli", "t,j", 0x24000000, 0xffe00000, WR_t, 0, I3 }, /* addiu */ +{"dli", "t,i", 0x34000000, 0xffe00000, WR_t, 0, I3 }, /* ori */ +{"dli", "t,I", 0, (int) M_DLI, INSN_MACRO, 0, I3 }, +{"dmacc", "d,s,t", 0x00000029, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchi", "d,s,t", 0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchis", "d,s,t", 0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchiu", "d,s,t", 0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmacchius", "d,s,t", 0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccs", "d,s,t", 0x00000429, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccu", "d,s,t", 0x00000069, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmaccus", "d,s,t", 0x00000469, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, 0, N412 }, +{"dmadd16", "s,t", 0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO, 0, N411 }, +{"dmfc0", "t,G", 0x40200000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I3 }, +{"dmfc0", "t,+D", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64 }, +{"dmfc0", "t,G,H", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I64 }, +{"dmt", "", 0x41600bc1, 0xffffffff, TRAP, 0, MT32 }, +{"dmt", "t", 0x41600bc1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I3 }, +{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64 }, +{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I64 }, +{"dmfc1", "t,S", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmfc1", "t,G", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I3 }, +{"dmtc1", "t,S", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, +{"dmtc1", "t,G", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I3 }, /* dmfc2 is at the bottom of the table. */ /* dmtc2 is at the bottom of the table. */ -{"dmfc3", "t,G", 0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, I3 }, -{"dmfc3", "t,G,H", 0x4c200000, 0xffe007f8, LCD|WR_t|RD_C3, I64 }, -{"dmtc3", "t,G", 0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, I3 }, -{"dmtc3", "t,G,H", 0x4ca00000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, I64 }, -{"dmul", "d,v,t", 0, (int) M_DMUL, INSN_MACRO, I3 }, -{"dmul", "d,v,I", 0, (int) M_DMUL_I, INSN_MACRO, I3 }, -{"dmulo", "d,v,t", 0, (int) M_DMULO, INSN_MACRO, I3 }, -{"dmulo", "d,v,I", 0, (int) M_DMULO_I, INSN_MACRO, I3 }, -{"dmulou", "d,v,t", 0, (int) M_DMULOU, INSN_MACRO, I3 }, -{"dmulou", "d,v,I", 0, (int) M_DMULOU_I, INSN_MACRO, I3 }, -{"dmult", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, -{"dmultu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, -{"dneg", "d,w", 0x0000002e, 0xffe007ff, WR_d|RD_t, I3 }, /* dsub 0 */ -{"dnegu", "d,w", 0x0000002f, 0xffe007ff, WR_d|RD_t, I3 }, /* dsubu 0*/ -{"drem", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, -{"drem", "d,v,t", 3, (int) M_DREM_3, INSN_MACRO, I3 }, -{"drem", "d,v,I", 3, (int) M_DREM_3I, INSN_MACRO, I3 }, -{"dremu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 }, -{"dremu", "d,v,t", 3, (int) M_DREMU_3, INSN_MACRO, I3 }, -{"dremu", "d,v,I", 3, (int) M_DREMU_3I, INSN_MACRO, I3 }, -{"dret", "", 0x7000003e, 0xffffffff, 0, N5 }, -{"drol", "d,v,t", 0, (int) M_DROL, INSN_MACRO, I3 }, -{"drol", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, I3 }, -{"dror", "d,v,t", 0, (int) M_DROR, INSN_MACRO, I3 }, -{"dror", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, I3 }, -{"dror", "d,w,<", 0x0020003a, 0xffe0003f, WR_d|RD_t, N5|I65 }, -{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, N5|I65 }, -{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, N5|I65 }, -{"drotl", "d,v,t", 0, (int) M_DROL, INSN_MACRO, I65 }, -{"drotl", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, I65 }, -{"drotr", "d,v,t", 0, (int) M_DROR, INSN_MACRO, I65 }, -{"drotr", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, I65 }, -{"drotrv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, I65 }, -{"drotr32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, I65 }, -{"dsbh", "d,w", 0x7c0000a4, 0xffe007ff, WR_d|RD_t, I65 }, -{"dshd", "d,w", 0x7c000164, 0xffe007ff, WR_d|RD_t, I65 }, -{"dsllv", "d,t,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, -{"dsll32", "d,w,<", 0x0000003c, 0xffe0003f, WR_d|RD_t, I3 }, -{"dsll", "d,w,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsllv */ -{"dsll", "d,w,>", 0x0000003c, 0xffe0003f, WR_d|RD_t, I3 }, /* dsll32 */ -{"dsll", "d,w,<", 0x00000038, 0xffe0003f, WR_d|RD_t, I3 }, -{"dsrav", "d,t,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, -{"dsra32", "d,w,<", 0x0000003f, 0xffe0003f, WR_d|RD_t, I3 }, -{"dsra", "d,w,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsrav */ -{"dsra", "d,w,>", 0x0000003f, 0xffe0003f, WR_d|RD_t, I3 }, /* dsra32 */ -{"dsra", "d,w,<", 0x0000003b, 0xffe0003f, WR_d|RD_t, I3 }, -{"dsrlv", "d,t,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, -{"dsrl32", "d,w,<", 0x0000003e, 0xffe0003f, WR_d|RD_t, I3 }, -{"dsrl", "d,w,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsrlv */ -{"dsrl", "d,w,>", 0x0000003e, 0xffe0003f, WR_d|RD_t, I3 }, /* dsrl32 */ -{"dsrl", "d,w,<", 0x0000003a, 0xffe0003f, WR_d|RD_t, I3 }, -{"dsub", "d,v,t", 0x0000002e, 0xfc0007ff, WR_d|RD_s|RD_t, I3 }, -{"dsub", "d,v,I", 0, (int) M_DSUB_I, INSN_MACRO, I3 }, -{"dsubu", "d,v,t", 0x0000002f, 0xfc0007ff, WR_d|RD_s|RD_t, I3 }, -{"dsubu", "d,v,I", 0, (int) M_DSUBU_I, INSN_MACRO, I3 }, -{"ei", "", 0x41606020, 0xffffffff, WR_t|WR_C0, I33 }, -{"ei", "t", 0x41606020, 0xffe0ffff, WR_t|WR_C0, I33 }, -{"eret", "", 0x42000018, 0xffffffff, 0, I3|I32 }, -{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, I33 }, -{"floor.l.d", "D,S", 0x4620000b, 0xffff003f, WR_D|RD_S|FP_D, I3 }, -{"floor.l.s", "D,S", 0x4600000b, 0xffff003f, WR_D|RD_S|FP_S, I3 }, -{"floor.w.d", "D,S", 0x4620000f, 0xffff003f, WR_D|RD_S|FP_D, I2 }, -{"floor.w.s", "D,S", 0x4600000f, 0xffff003f, WR_D|RD_S|FP_S, I2 }, -{"flushi", "", 0xbc010000, 0xffffffff, 0, L1 }, -{"flushd", "", 0xbc020000, 0xffffffff, 0, L1 }, -{"flushid", "", 0xbc030000, 0xffffffff, 0, L1 }, -{"hibernate","", 0x42000023, 0xffffffff, 0, V1 }, -{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, I33 }, -{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, I1 }, -{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, I33 }, -{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, I1 }, /* jr */ +/* dmfc3 is at the bottom of the table. */ +/* dmtc3 is at the bottom of the table. */ +{"dmul", "d,v,t", 0, (int) M_DMUL, INSN_MACRO, 0, I3 }, +{"dmul", "d,v,I", 0, (int) M_DMUL_I, INSN_MACRO, 0, I3 }, +{"dmulo", "d,v,t", 0, (int) M_DMULO, INSN_MACRO, 0, I3 }, +{"dmulo", "d,v,I", 0, (int) M_DMULO_I, INSN_MACRO, 0, I3 }, +{"dmulou", "d,v,t", 0, (int) M_DMULOU, INSN_MACRO, 0, I3 }, +{"dmulou", "d,v,I", 0, (int) M_DMULOU_I, INSN_MACRO, 0, I3 }, +{"dmult", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dmultu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dneg", "d,w", 0x0000002e, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsub 0 */ +{"dnegu", "d,w", 0x0000002f, 0xffe007ff, WR_d|RD_t, 0, I3 }, /* dsubu 0*/ +{"drem", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"drem", "d,v,t", 3, (int) M_DREM_3, INSN_MACRO, 0, I3 }, +{"drem", "d,v,I", 3, (int) M_DREM_3I, INSN_MACRO, 0, I3 }, +{"dremu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I3 }, +{"dremu", "d,v,t", 3, (int) M_DREMU_3, INSN_MACRO, 0, I3 }, +{"dremu", "d,v,I", 3, (int) M_DREMU_3I, INSN_MACRO, 0, I3 }, +{"dret", "", 0x7000003e, 0xffffffff, 0, 0, N5 }, +{"drol", "d,v,t", 0, (int) M_DROL, INSN_MACRO, 0, I3 }, +{"drol", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, 0, I3 }, +{"dror", "d,v,t", 0, (int) M_DROR, INSN_MACRO, 0, I3 }, +{"dror", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, 0, I3 }, +{"dror", "d,w,<", 0x0020003a, 0xffe0003f, WR_d|RD_t, 0, N5|I65 }, +{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, N5|I65 }, +{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, N5|I65 }, +{"drotl", "d,v,t", 0, (int) M_DROL, INSN_MACRO, 0, I65 }, +{"drotl", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, 0, I65 }, +{"drotr", "d,v,t", 0, (int) M_DROR, INSN_MACRO, 0, I65 }, +{"drotr", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, 0, I65 }, +{"drotrv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I65 }, +{"drotr32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, 0, I65 }, +{"dsbh", "d,w", 0x7c0000a4, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dshd", "d,w", 0x7c000164, 0xffe007ff, WR_d|RD_t, 0, I65 }, +{"dsllv", "d,t,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsll32", "d,w,<", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsll", "d,w,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsllv */ +{"dsll", "d,w,>", 0x0000003c, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsll32 */ +{"dsll", "d,w,<", 0x00000038, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrav", "d,t,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsra32", "d,w,<", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsra", "d,w,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrav */ +{"dsra", "d,w,>", 0x0000003f, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsra32 */ +{"dsra", "d,w,<", 0x0000003b, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrlv", "d,t,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, +{"dsrl32", "d,w,<", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsrl", "d,w,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I3 }, /* dsrlv */ +{"dsrl", "d,w,>", 0x0000003e, 0xffe0003f, WR_d|RD_t, 0, I3 }, /* dsrl32 */ +{"dsrl", "d,w,<", 0x0000003a, 0xffe0003f, WR_d|RD_t, 0, I3 }, +{"dsub", "d,v,t", 0x0000002e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsub", "d,v,I", 0, (int) M_DSUB_I, INSN_MACRO, 0, I3 }, +{"dsubu", "d,v,t", 0x0000002f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I3 }, +{"dsubu", "d,v,I", 0, (int) M_DSUBU_I, INSN_MACRO, 0, I3 }, +{"dvpe", "", 0x41600001, 0xffffffff, TRAP, 0, MT32 }, +{"dvpe", "t", 0x41600001, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ei", "", 0x41606020, 0xffffffff, WR_t|WR_C0, 0, I33 }, +{"ei", "t", 0x41606020, 0xffe0ffff, WR_t|WR_C0, 0, I33 }, +{"emt", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 }, +{"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"eret", "", 0x42000018, 0xffffffff, 0, 0, I3|I32 }, +{"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 }, +{"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, +{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"floor.l.d", "D,S", 0x4620000b, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"floor.l.s", "D,S", 0x4600000b, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"floor.w.d", "D,S", 0x4620000f, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"floor.w.s", "D,S", 0x4600000f, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"hibernate","", 0x42000023, 0xffffffff, 0, 0, V1 }, +{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, 0, I33 }, +{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, +/* jr.hb is officially MIPS{32,64}R2, but it works on R1 as jr with + the same hazard barrier effect. */ +{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, 0, I32 }, +{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, 0, I1 }, /* jr */ /* SVR4 PIC code requires special handling for j, so it must be a macro. */ -{"j", "a", 0, (int) M_J_A, INSN_MACRO, I1 }, +{"j", "a", 0, (int) M_J_A, INSN_MACRO, 0, I1 }, /* This form of j is used by the disassembler and internally by the assembler, but will never match user input (because the line above will match first). */ -{"j", "a", 0x08000000, 0xfc000000, UBD, I1 }, -{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, I1 }, -{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, I1 }, -{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, I33 }, -{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, I33 }, +{"j", "a", 0x08000000, 0xfc000000, UBD, 0, I1 }, +{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, 0, I1 }, +{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I1 }, +/* jalr.hb is officially MIPS{32,64}R2, but it works on R1 as jalr + with the same hazard barrier effect. */ +{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, 0, I32 }, +{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, 0, I32 }, /* SVR4 PIC code requires special handling for jal, so it must be a macro. */ -{"jal", "d,s", 0, (int) M_JAL_2, INSN_MACRO, I1 }, -{"jal", "s", 0, (int) M_JAL_1, INSN_MACRO, I1 }, -{"jal", "a", 0, (int) M_JAL_A, INSN_MACRO, I1 }, +{"jal", "d,s", 0, (int) M_JAL_2, INSN_MACRO, 0, I1 }, +{"jal", "s", 0, (int) M_JAL_1, INSN_MACRO, 0, I1 }, +{"jal", "a", 0, (int) M_JAL_A, INSN_MACRO, 0, I1 }, /* This form of jal is used by the disassembler and internally by the assembler, but will never match user input (because the line above will match first). */ -{"jal", "a", 0x0c000000, 0xfc000000, UBD|WR_31, I1 }, -{"jalx", "a", 0x74000000, 0xfc000000, UBD|WR_31, I16 }, -{"la", "t,A(b)", 0, (int) M_LA_AB, INSN_MACRO, I1 }, -{"lb", "t,o(b)", 0x80000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, -{"lb", "t,A(b)", 0, (int) M_LB_AB, INSN_MACRO, I1 }, -{"lbu", "t,o(b)", 0x90000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, -{"lbu", "t,A(b)", 0, (int) M_LBU_AB, INSN_MACRO, I1 }, -{"lca", "t,A(b)", 0, (int) M_LCA_AB, INSN_MACRO, I1 }, -{"ld", "t,o(b)", 0xdc000000, 0xfc000000, WR_t|RD_b, I3 }, -{"ld", "t,o(b)", 0, (int) M_LD_OB, INSN_MACRO, I1 }, -{"ld", "t,A(b)", 0, (int) M_LD_AB, INSN_MACRO, I1 }, -{"ldc1", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 }, -{"ldc1", "E,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 }, -{"ldc1", "T,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, I2 }, -{"ldc1", "E,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, I2 }, -{"l.d", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 }, /* ldc1 */ -{"l.d", "T,o(b)", 0, (int) M_L_DOB, INSN_MACRO, I1 }, -{"l.d", "T,A(b)", 0, (int) M_L_DAB, INSN_MACRO, I1 }, -{"ldc2", "E,o(b)", 0xd8000000, 0xfc000000, CLD|RD_b|WR_CC, I2 }, -{"ldc2", "E,A(b)", 0, (int) M_LDC2_AB, INSN_MACRO, I2 }, -{"ldc3", "E,o(b)", 0xdc000000, 0xfc000000, CLD|RD_b|WR_CC, I2 }, -{"ldc3", "E,A(b)", 0, (int) M_LDC3_AB, INSN_MACRO, I2 }, -{"ldl", "t,o(b)", 0x68000000, 0xfc000000, LDD|WR_t|RD_b, I3 }, -{"ldl", "t,A(b)", 0, (int) M_LDL_AB, INSN_MACRO, I3 }, -{"ldr", "t,o(b)", 0x6c000000, 0xfc000000, LDD|WR_t|RD_b, I3 }, -{"ldr", "t,A(b)", 0, (int) M_LDR_AB, INSN_MACRO, I3 }, -{"ldxc1", "D,t(b)", 0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I4 }, -{"lh", "t,o(b)", 0x84000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, -{"lh", "t,A(b)", 0, (int) M_LH_AB, INSN_MACRO, I1 }, -{"lhu", "t,o(b)", 0x94000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, -{"lhu", "t,A(b)", 0, (int) M_LHU_AB, INSN_MACRO, I1 }, +{"jal", "a", 0x0c000000, 0xfc000000, UBD|WR_31, 0, I1 }, +{"jalx", "a", 0x74000000, 0xfc000000, UBD|WR_31, 0, I16 }, +{"la", "t,A(b)", 0, (int) M_LA_AB, INSN_MACRO, 0, I1 }, +{"lb", "t,o(b)", 0x80000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lb", "t,A(b)", 0, (int) M_LB_AB, INSN_MACRO, 0, I1 }, +{"lbu", "t,o(b)", 0x90000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lbu", "t,A(b)", 0, (int) M_LBU_AB, INSN_MACRO, 0, I1 }, +{"lca", "t,A(b)", 0, (int) M_LCA_AB, INSN_MACRO, 0, I1 }, +{"ld", "t,o(b)", 0xdc000000, 0xfc000000, WR_t|RD_b, 0, I3 }, +{"ld", "t,o(b)", 0, (int) M_LD_OB, INSN_MACRO, 0, I1 }, +{"ld", "t,A(b)", 0, (int) M_LD_AB, INSN_MACRO, 0, I1 }, +{"ldc1", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "E,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, +{"ldc1", "T,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, 0, I2 }, +{"ldc1", "E,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, 0, I2 }, +{"l.d", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, 0, I2 }, /* ldc1 */ +{"l.d", "T,o(b)", 0, (int) M_L_DOB, INSN_MACRO, 0, I1 }, +{"l.d", "T,A(b)", 0, (int) M_L_DAB, INSN_MACRO, 0, I1 }, +{"ldc2", "E,o(b)", 0xd8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc2", "E,A(b)", 0, (int) M_LDC2_AB, INSN_MACRO, 0, I2 }, +{"ldc3", "E,o(b)", 0xdc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I2 }, +{"ldc3", "E,A(b)", 0, (int) M_LDC3_AB, INSN_MACRO, 0, I2 }, +{"ldl", "t,o(b)", 0x68000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldl", "t,A(b)", 0, (int) M_LDL_AB, INSN_MACRO, 0, I3 }, +{"ldr", "t,o(b)", 0x6c000000, 0xfc000000, LDD|WR_t|RD_b, 0, I3 }, +{"ldr", "t,A(b)", 0, (int) M_LDR_AB, INSN_MACRO, 0, I3 }, +{"ldxc1", "D,t(b)", 0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"lh", "t,o(b)", 0x84000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lh", "t,A(b)", 0, (int) M_LH_AB, INSN_MACRO, 0, I1 }, +{"lhu", "t,o(b)", 0x94000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lhu", "t,A(b)", 0, (int) M_LHU_AB, INSN_MACRO, 0, I1 }, /* li is at the start of the table. */ -{"li.d", "t,F", 0, (int) M_LI_D, INSN_MACRO, I1 }, -{"li.d", "T,L", 0, (int) M_LI_DD, INSN_MACRO, I1 }, -{"li.s", "t,f", 0, (int) M_LI_S, INSN_MACRO, I1 }, -{"li.s", "T,l", 0, (int) M_LI_SS, INSN_MACRO, I1 }, -{"ll", "t,o(b)", 0xc0000000, 0xfc000000, LDD|RD_b|WR_t, I2 }, -{"ll", "t,A(b)", 0, (int) M_LL_AB, INSN_MACRO, I2 }, -{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, I3 }, -{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, I3 }, -{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, I1 }, -{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I5|N55 }, -{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, -{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, I1 }, -{"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, CLD|RD_b|WR_CC, I1 }, -{"lwc0", "E,A(b)", 0, (int) M_LWC0_AB, INSN_MACRO, I1 }, -{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 }, -{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 }, -{"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 }, -{"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 }, -{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 }, /* lwc1 */ -{"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 }, -{"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, CLD|RD_b|WR_CC, I1 }, -{"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, I1 }, -{"lwc3", "E,o(b)", 0xcc000000, 0xfc000000, CLD|RD_b|WR_CC, I1 }, -{"lwc3", "E,A(b)", 0, (int) M_LWC3_AB, INSN_MACRO, I1 }, -{"lwl", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, -{"lwl", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, I1 }, -{"lcache", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, I2 }, /* same */ -{"lcache", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, I2 }, /* as lwl */ -{"lwr", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, I1 }, -{"lwr", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, I1 }, -{"flush", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, I2 }, /* same */ -{"flush", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, I2 }, /* as lwr */ -{"lwu", "t,o(b)", 0x9c000000, 0xfc000000, LDD|RD_b|WR_t, I3 }, -{"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, I3 }, -{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I4 }, -{"macc", "d,s,t", 0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, -{"macc", "d,s,t", 0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"maccs", "d,s,t", 0x00000428, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, -{"macchi", "d,s,t", 0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, -{"macchi", "d,s,t", 0x00000358, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"macchis", "d,s,t", 0x00000628, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, -{"macchiu", "d,s,t", 0x00000268, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, -{"macchiu", "d,s,t", 0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"macchius","d,s,t", 0x00000668, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, -{"maccu", "d,s,t", 0x00000068, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, -{"maccu", "d,s,t", 0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"maccus", "d,s,t", 0x00000468, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 }, -{"mad", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, P3 }, -{"madu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, P3 }, -{"madd.d", "D,R,S,T", 0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 }, -{"madd.s", "D,R,S,T", 0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 }, -{"madd.ps", "D,R,S,T", 0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 }, -{"madd", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 }, -{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55}, -{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, G1 }, -{"madd", "d,s,t", 0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 }, -{"maddu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 }, -{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55}, -{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, G1 }, -{"maddu", "d,s,t", 0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 }, -{"madd16", "s,t", 0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO, N411 }, -{"max.ob", "X,Y,Q", 0x78000007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"max.ob", "D,S,T", 0x4ac00007, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"max.ob", "D,S,T[e]", 0x48000007, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"max.ob", "D,S,k", 0x4bc00007, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"max.qh", "X,Y,Q", 0x78200007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"mfpc", "t,P", 0x4000c801, 0xffe0ffc1, LCD|WR_t|RD_C0, M1|N5 }, -{"mfps", "t,P", 0x4000c800, 0xffe0ffc1, LCD|WR_t|RD_C0, M1|N5 }, -{"mfc0", "t,G", 0x40000000, 0xffe007ff, LCD|WR_t|RD_C0, I1 }, -{"mfc0", "t,+D", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, I32 }, -{"mfc0", "t,G,H", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, I32 }, -{"mfc1", "t,S", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I1 }, -{"mfc1", "t,G", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I1 }, -{"mfhc1", "t,S", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I33 }, -{"mfhc1", "t,G", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I33 }, +{"li.d", "t,F", 0, (int) M_LI_D, INSN_MACRO, 0, I1 }, +{"li.d", "T,L", 0, (int) M_LI_DD, INSN_MACRO, 0, I1 }, +{"li.s", "t,f", 0, (int) M_LI_S, INSN_MACRO, 0, I1 }, +{"li.s", "T,l", 0, (int) M_LI_SS, INSN_MACRO, 0, I1 }, +{"ll", "t,o(b)", 0xc0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, +{"ll", "t,A(b)", 0, (int) M_LL_AB, INSN_MACRO, 0, I2 }, +{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 }, +{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, +{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55}, +{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 }, +{"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc0", "E,A(b)", 0, (int) M_LWC0_AB, INSN_MACRO, 0, I1 }, +{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, +{"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, 0, I1 }, /* lwc1 */ +{"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, 0, I1 }, +{"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, 0, I1 }, +{"lwc3", "E,o(b)", 0xcc000000, 0xfc000000, CLD|RD_b|WR_CC, 0, I1 }, +{"lwc3", "E,A(b)", 0, (int) M_LWC3_AB, INSN_MACRO, 0, I1 }, +{"lwl", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwl", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I1 }, +{"lcache", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"lcache", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I2 }, /* as lwl */ +{"lwr", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, +{"lwr", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I1 }, +{"flush", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, 0, I2 }, /* same */ +{"flush", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I2 }, /* as lwr */ +{"fork", "d,s,t", 0x7c000008, 0xfc0007ff, TRAP|WR_d|RD_s|RD_t, 0, MT32 }, +{"lwu", "t,o(b)", 0x9c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, +{"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, 0, I3 }, +{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"lwxs", "d,t(b)", 0x70000088, 0xfc0007ff, LDD|RD_b|RD_t|WR_d, 0, SMT }, +{"macc", "d,s,t", 0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macc", "d,s,t", 0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"maccs", "d,s,t", 0x00000428, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchi", "d,s,t", 0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchi", "d,s,t", 0x00000358, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"macchis", "d,s,t", 0x00000628, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchiu", "d,s,t", 0x00000268, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"macchiu", "d,s,t", 0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"macchius","d,s,t", 0x00000668, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"maccu", "d,s,t", 0x00000068, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"maccu", "d,s,t", 0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"maccus", "d,s,t", 0x00000468, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N412 }, +{"mad", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, P3 }, +{"madu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, P3 }, +{"madd.d", "D,R,S,T", 0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"madd.s", "D,R,S,T", 0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"madd.ps", "D,R,S,T", 0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"madd", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, G1 }, +{"madd", "7,s,t", 0x70000000, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"madd", "d,s,t", 0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"maddp", "s,t", 0x70000441, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"maddu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, G1 }, +{"maddu", "7,s,t", 0x70000001, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"maddu", "d,s,t", 0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"madd16", "s,t", 0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, N411 }, +{"max.ob", "X,Y,Q", 0x78000007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"max.ob", "D,S,T", 0x4ac00007, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.ob", "D,S,T[e]", 0x48000007, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.ob", "D,S,k", 0x4bc00007, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"max.qh", "X,Y,Q", 0x78200007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mfpc", "t,P", 0x4000c801, 0xffe0ffc1, LCD|WR_t|RD_C0, 0, M1|N5 }, +{"mfps", "t,P", 0x4000c800, 0xffe0ffc1, LCD|WR_t|RD_C0, 0, M1|N5 }, +{"mftacx", "d", 0x41020021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftacx", "d,*", 0x41020021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftc0", "d,+t", 0x41000000, 0xffe007ff, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,+T", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc0", "d,E,H", 0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0, 0, MT32 }, +{"mftc1", "d,T", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc1", "d,E", 0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0, MT32 }, +{"mftc2", "d,E", 0x41000024, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mftdsp", "d", 0x41100021, 0xffff07ff, TRAP|WR_d, 0, MT32 }, +{"mftgpr", "d,t", 0x41000020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mfthc1", "d,T", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc1", "d,E", 0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0, MT32 }, +{"mfthc2", "d,E", 0x41000034, 0xffe007ff, TRAP|LCD|WR_d|RD_C2, 0, MT32 }, +{"mfthi", "d", 0x41010021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mfthi", "d,*", 0x41010021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d", 0x41000021, 0xffff07ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftlo", "d,*", 0x41000021, 0xfff307ff, TRAP|WR_d|RD_a, 0, MT32 }, +{"mftr", "d,t,!,H,$", 0x41000000, 0xffe007c8, TRAP|WR_d, 0, MT32 }, +{"mfc0", "t,G", 0x40000000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, +{"mfc0", "t,+D", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32 }, +{"mfc0", "t,G,H", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I32 }, +{"mfc1", "t,S", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfc1", "t,G", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, 0, I1 }, +{"mfhc1", "t,S", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, +{"mfhc1", "t,G", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_D, 0, I33 }, /* mfc2 is at the bottom of the table. */ /* mfhc2 is at the bottom of the table. */ -{"mfc3", "t,G", 0x4c000000, 0xffe007ff, LCD|WR_t|RD_C3, I1 }, -{"mfc3", "t,G,H", 0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, I32 }, -{"mfdr", "t,G", 0x7000003d, 0xffe007ff, LCD|WR_t|RD_C0, N5 }, -{"mfhi", "d", 0x00000010, 0xffff07ff, WR_d|RD_HI, I1 }, -{"mflo", "d", 0x00000012, 0xffff07ff, WR_d|RD_LO, I1 }, -{"min.ob", "X,Y,Q", 0x78000006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"min.ob", "D,S,T", 0x4ac00006, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"min.ob", "D,S,T[e]", 0x48000006, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"min.ob", "D,S,k", 0x4bc00006, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"min.qh", "X,Y,Q", 0x78200006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"mov.d", "D,S", 0x46200006, 0xffff003f, WR_D|RD_S|FP_D, I1 }, -{"mov.s", "D,S", 0x46000006, 0xffff003f, WR_D|RD_S|FP_S, I1 }, -{"mov.ps", "D,S", 0x46c00006, 0xffff003f, WR_D|RD_S|FP_D, I5 }, -{"movf", "d,s,N", 0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_D|FP_S, I4|I32}, -{"movf.d", "D,S,N", 0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I4|I32 }, -{"movf.l", "D,S,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 }, -{"movf.l", "X,Y,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 }, -{"movf.s", "D,S,N", 0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, I4|I32 }, -{"movf.ps", "D,S,N", 0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I5 }, -{"movn", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, I4|I32 }, -{"ffc", "d,v", 0x0000000b, 0xfc1f07ff, WR_d|RD_s, L1 }, -{"movn.d", "D,S,t", 0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I4|I32 }, -{"movn.l", "D,S,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 }, -{"movn.l", "X,Y,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 }, -{"movn.s", "D,S,t", 0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, I4|I32 }, -{"movn.ps", "D,S,t", 0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I5 }, -{"movt", "d,s,N", 0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC, I4|I32 }, -{"movt.d", "D,S,N", 0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I4|I32 }, -{"movt.l", "D,S,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 }, -{"movt.l", "X,Y,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 }, -{"movt.s", "D,S,N", 0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, I4|I32 }, -{"movt.ps", "D,S,N", 0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I5 }, -{"movz", "d,v,t", 0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, I4|I32 }, -{"ffs", "d,v", 0x0000000a, 0xfc1f07ff, WR_d|RD_s, L1 }, -{"movz.d", "D,S,t", 0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I4|I32 }, -{"movz.l", "D,S,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 }, -{"movz.l", "X,Y,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 }, -{"movz.s", "D,S,t", 0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, I4|I32 }, -{"movz.ps", "D,S,t", 0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I5 }, -{"msac", "d,s,t", 0x000001d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"msacu", "d,s,t", 0x000001d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"msachi", "d,s,t", 0x000003d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"msachiu", "d,s,t", 0x000003d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, +/* mfc3 is at the bottom of the table. */ +{"mfdr", "t,G", 0x7000003d, 0xffe007ff, LCD|WR_t|RD_C0, 0, N5 }, +{"mfhi", "d", 0x00000010, 0xffff07ff, WR_d|RD_HI, 0, I1 }, +{"mfhi", "d,9", 0x00000010, 0xff9f07ff, WR_d|RD_HI, 0, D32 }, +{"mflo", "d", 0x00000012, 0xffff07ff, WR_d|RD_LO, 0, I1 }, +{"mflo", "d,9", 0x00000012, 0xff9f07ff, WR_d|RD_LO, 0, D32 }, +{"mflhxu", "d", 0x00000052, 0xffff07ff, WR_d|MOD_HILO, 0, SMT }, +{"min.ob", "X,Y,Q", 0x78000006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"min.ob", "D,S,T", 0x4ac00006, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.ob", "D,S,T[e]", 0x48000006, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.ob", "D,S,k", 0x4bc00006, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"min.qh", "X,Y,Q", 0x78200006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mov.d", "D,S", 0x46200006, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"mov.s", "D,S", 0x46000006, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"mov.ps", "D,S", 0x46c00006, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"movf", "d,s,N", 0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4|I32 }, +{"movf.d", "D,S,N", 0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4|I32 }, +{"movf.l", "D,S,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movf.l", "X,Y,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movf.s", "D,S,N", 0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4|I32 }, +{"movf.ps", "D,S,N", 0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5|I33 }, +{"movn", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4|I32 }, +{"ffc", "d,v", 0x0000000b, 0xfc1f07ff, WR_d|RD_s, 0, L1 }, +{"movn.d", "D,S,t", 0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4|I32 }, +{"movn.l", "D,S,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movn.l", "X,Y,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movn.s", "D,S,t", 0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4|I32 }, +{"movn.ps", "D,S,t", 0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5|I33 }, +{"movt", "d,s,N", 0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0, I4|I32 }, +{"movt.d", "D,S,N", 0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I4|I32 }, +{"movt.l", "D,S,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movt.l", "X,Y,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, MX|SB1 }, +{"movt.s", "D,S,N", 0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, 0, I4|I32 }, +{"movt.ps", "D,S,N", 0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, 0, I5|I33 }, +{"movz", "d,v,t", 0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I4|I32 }, +{"ffs", "d,v", 0x0000000a, 0xfc1f07ff, WR_d|RD_s, 0, L1 }, +{"movz.d", "D,S,t", 0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I4|I32 }, +{"movz.l", "D,S,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movz.l", "X,Y,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, MX|SB1 }, +{"movz.s", "D,S,t", 0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, 0, I4|I32 }, +{"movz.ps", "D,S,t", 0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, 0, I5|I33 }, +{"msac", "d,s,t", 0x000001d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msacu", "d,s,t", 0x000001d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msachi", "d,s,t", 0x000003d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"msachiu", "d,s,t", 0x000003d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, /* move is at the top of the table. */ -{"msgn.qh", "X,Y,Q", 0x78200000, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"msub.d", "D,R,S,T", 0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 }, -{"msub.s", "D,R,S,T", 0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 }, -{"msub.ps", "D,R,S,T", 0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 }, -{"msub", "s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 }, -{"msub", "s,t", 0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55 }, -{"msubu", "s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 }, -{"msubu", "s,t", 0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55 }, -{"mtpc", "t,P", 0x4080c801, 0xffe0ffc1, COD|RD_t|WR_C0, M1|N5 }, -{"mtps", "t,P", 0x4080c800, 0xffe0ffc1, COD|RD_t|WR_C0, M1|N5 }, -{"mtc0", "t,G", 0x40800000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, I1 }, -{"mtc0", "t,+D", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I32 }, -{"mtc0", "t,G,H", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I32 }, -{"mtc1", "t,S", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I1 }, -{"mtc1", "t,G", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I1 }, -{"mthc1", "t,S", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I33 }, -{"mthc1", "t,G", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I33 }, +{"msgn.qh", "X,Y,Q", 0x78200000, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"msub.d", "D,R,S,T", 0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"msub.s", "D,R,S,T", 0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"msub.ps", "D,R,S,T", 0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"msub", "s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"msub", "s,t", 0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"msub", "7,s,t", 0x70000004, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"msubu", "s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, L1 }, +{"msubu", "s,t", 0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, I32|N55 }, +{"msubu", "7,s,t", 0x70000005, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"mtpc", "t,P", 0x4080c801, 0xffe0ffc1, COD|RD_t|WR_C0, 0, M1|N5 }, +{"mtps", "t,P", 0x4080c800, 0xffe0ffc1, COD|RD_t|WR_C0, 0, M1|N5 }, +{"mtc0", "t,G", 0x40800000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, 0, I1 }, +{"mtc0", "t,+D", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32 }, +{"mtc0", "t,G,H", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I32 }, +{"mtc1", "t,S", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mtc1", "t,G", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, 0, I1 }, +{"mthc1", "t,S", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, +{"mthc1", "t,G", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_D, 0, I33 }, /* mtc2 is at the bottom of the table. */ /* mthc2 is at the bottom of the table. */ -{"mtc3", "t,G", 0x4c800000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, I1 }, -{"mtc3", "t,G,H", 0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, I32 }, -{"mtdr", "t,G", 0x7080003d, 0xffe007ff, COD|RD_t|WR_C0, N5 }, -{"mthi", "s", 0x00000011, 0xfc1fffff, RD_s|WR_HI, I1 }, -{"mtlo", "s", 0x00000013, 0xfc1fffff, RD_s|WR_LO, I1 }, -{"mul.d", "D,V,T", 0x46200002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 }, -{"mul.s", "D,V,T", 0x46000002, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 }, -{"mul.ob", "X,Y,Q", 0x78000030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"mul.ob", "D,S,T", 0x4ac00030, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"mul.ob", "D,S,T[e]", 0x48000030, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"mul.ob", "D,S,k", 0x4bc00030, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"mul.ps", "D,V,T", 0x46c00002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, -{"mul.qh", "X,Y,Q", 0x78200030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"mul", "d,v,t", 0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, I32|P3|N55}, -{"mul", "d,s,t", 0x00000058, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N54 }, -{"mul", "d,v,t", 0, (int) M_MUL, INSN_MACRO, I1 }, -{"mul", "d,v,I", 0, (int) M_MUL_I, INSN_MACRO, I1 }, -{"mula.ob", "Y,Q", 0x78000033, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"mula.ob", "S,T", 0x4ac00033, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"mula.ob", "S,T[e]", 0x48000033, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, -{"mula.ob", "S,k", 0x4bc00033, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"mula.qh", "Y,Q", 0x78200033, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"mulhi", "d,s,t", 0x00000258, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"mulhiu", "d,s,t", 0x00000259, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"mull.ob", "Y,Q", 0x78000433, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"mull.ob", "S,T", 0x4ac00433, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"mull.ob", "S,T[e]", 0x48000433, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, -{"mull.ob", "S,k", 0x4bc00433, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"mull.qh", "Y,Q", 0x78200433, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"mulo", "d,v,t", 0, (int) M_MULO, INSN_MACRO, I1 }, -{"mulo", "d,v,I", 0, (int) M_MULO_I, INSN_MACRO, I1 }, -{"mulou", "d,v,t", 0, (int) M_MULOU, INSN_MACRO, I1 }, -{"mulou", "d,v,I", 0, (int) M_MULOU_I, INSN_MACRO, I1 }, -{"mulr.ps", "D,S,T", 0x46c0001a, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D }, -{"muls", "d,s,t", 0x000000d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"mulsu", "d,s,t", 0x000000d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"mulshi", "d,s,t", 0x000002d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"mulshiu", "d,s,t", 0x000002d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"muls.ob", "Y,Q", 0x78000032, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"muls.ob", "S,T", 0x4ac00032, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"muls.ob", "S,T[e]", 0x48000032, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, -{"muls.ob", "S,k", 0x4bc00032, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"muls.qh", "Y,Q", 0x78200032, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"mulsl.ob", "Y,Q", 0x78000432, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"mulsl.ob", "S,T", 0x4ac00432, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"mulsl.ob", "S,T[e]", 0x48000432, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 }, -{"mulsl.ob", "S,k", 0x4bc00432, 0xffe007ff, WR_CC|RD_S|RD_T, N54 }, -{"mulsl.qh", "Y,Q", 0x78200432, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"mult", "s,t", 0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1 }, -{"mult", "d,s,t", 0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 }, -{"multu", "s,t", 0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1 }, -{"multu", "d,s,t", 0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 }, -{"mulu", "d,s,t", 0x00000059, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 }, -{"neg", "d,w", 0x00000022, 0xffe007ff, WR_d|RD_t, I1 }, /* sub 0 */ -{"negu", "d,w", 0x00000023, 0xffe007ff, WR_d|RD_t, I1 }, /* subu 0 */ -{"neg.d", "D,V", 0x46200007, 0xffff003f, WR_D|RD_S|FP_D, I1 }, -{"neg.s", "D,V", 0x46000007, 0xffff003f, WR_D|RD_S|FP_S, I1 }, -{"neg.ps", "D,V", 0x46c00007, 0xffff003f, WR_D|RD_S|FP_D, I5 }, -{"nmadd.d", "D,R,S,T", 0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 }, -{"nmadd.s", "D,R,S,T", 0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 }, -{"nmadd.ps","D,R,S,T", 0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 }, -{"nmsub.d", "D,R,S,T", 0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 }, -{"nmsub.s", "D,R,S,T", 0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 }, -{"nmsub.ps","D,R,S,T", 0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 }, +/* mtc3 is at the bottom of the table. */ +{"mtdr", "t,G", 0x7080003d, 0xffe007ff, COD|RD_t|WR_C0, 0, N5 }, +{"mthi", "s", 0x00000011, 0xfc1fffff, RD_s|WR_HI, 0, I1 }, +{"mthi", "s,7", 0x00000011, 0xfc1fe7ff, RD_s|WR_HI, 0, D32 }, +{"mtlo", "s", 0x00000013, 0xfc1fffff, RD_s|WR_LO, 0, I1 }, +{"mtlo", "s,7", 0x00000013, 0xfc1fe7ff, RD_s|WR_LO, 0, D32 }, +{"mtlhx", "s", 0x00000053, 0xfc1fffff, RD_s|MOD_HILO, 0, SMT }, +{"mttc0", "t,G", 0x41800000, 0xffe007ff, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,+D", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc0", "t,G,H", 0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0, MT32 }, +{"mttc1", "t,S", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc1", "t,G", 0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0, MT32 }, +{"mttc2", "t,g", 0x41800024, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mttacx", "t", 0x41801021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttacx", "t,&", 0x41801021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttdsp", "t", 0x41808021, 0xffe0ffff, TRAP|RD_t, 0, MT32 }, +{"mttgpr", "t,d", 0x41800020, 0xffe007ff, TRAP|WR_d|RD_t, 0, MT32 }, +{"mtthc1", "t,S", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc1", "t,G", 0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0, MT32 }, +{"mtthc2", "t,g", 0x41800034, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0, MT32 }, +{"mtthi", "t", 0x41800821, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mtthi", "t,&", 0x41800821, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t", 0x41800021, 0xffe0ffff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttlo", "t,&", 0x41800021, 0xffe09fff, TRAP|WR_a|RD_t, 0, MT32 }, +{"mttr", "t,d,!,H,$", 0x41800000, 0xffe007c8, TRAP|RD_t, 0, MT32 }, +{"mul.d", "D,V,T", 0x46200002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"mul.s", "D,V,T", 0x46000002, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"mul.ob", "X,Y,Q", 0x78000030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"mul.ob", "D,S,T", 0x4ac00030, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ob", "D,S,T[e]", 0x48000030, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ob", "D,S,k", 0x4bc00030, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"mul.ps", "D,V,T", 0x46c00002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"mul.qh", "X,Y,Q", 0x78200030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"mul", "d,v,t", 0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, I32|P3|N55}, +{"mul", "d,s,t", 0x00000058, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N54 }, +{"mul", "d,v,t", 0, (int) M_MUL, INSN_MACRO, 0, I1 }, +{"mul", "d,v,I", 0, (int) M_MUL_I, INSN_MACRO, 0, I1 }, +{"mula.ob", "Y,Q", 0x78000033, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mula.ob", "S,T", 0x4ac00033, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.ob", "S,T[e]", 0x48000033, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.ob", "S,k", 0x4bc00033, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mula.qh", "Y,Q", 0x78200033, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulhi", "d,s,t", 0x00000258, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulhiu", "d,s,t", 0x00000259, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mull.ob", "Y,Q", 0x78000433, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mull.ob", "S,T", 0x4ac00433, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.ob", "S,T[e]", 0x48000433, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.ob", "S,k", 0x4bc00433, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mull.qh", "Y,Q", 0x78200433, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulo", "d,v,t", 0, (int) M_MULO, INSN_MACRO, 0, I1 }, +{"mulo", "d,v,I", 0, (int) M_MULO_I, INSN_MACRO, 0, I1 }, +{"mulou", "d,v,t", 0, (int) M_MULOU, INSN_MACRO, 0, I1 }, +{"mulou", "d,v,I", 0, (int) M_MULOU_I, INSN_MACRO, 0, I1 }, +{"mulr.ps", "D,S,T", 0x46c0001a, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"muls", "d,s,t", 0x000000d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulsu", "d,s,t", 0x000000d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulshi", "d,s,t", 0x000002d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"mulshiu", "d,s,t", 0x000002d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"muls.ob", "Y,Q", 0x78000032, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"muls.ob", "S,T", 0x4ac00032, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.ob", "S,T[e]", 0x48000032, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.ob", "S,k", 0x4bc00032, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"muls.qh", "Y,Q", 0x78200032, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mulsl.ob", "Y,Q", 0x78000432, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"mulsl.ob", "S,T", 0x4ac00432, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.ob", "S,T[e]", 0x48000432, 0xfe2007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.ob", "S,k", 0x4bc00432, 0xffe007ff, WR_CC|RD_S|RD_T, 0, N54 }, +{"mulsl.qh", "Y,Q", 0x78200432, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"mult", "s,t", 0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"mult", "7,s,t", 0x00000018, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D33 }, +{"mult", "d,s,t", 0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"multp", "s,t", 0x00000459, 0xfc00ffff, RD_s|RD_t|MOD_HILO, 0, SMT }, +{"multu", "s,t", 0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0, I1 }, +{"multu", "7,s,t", 0x00000019, 0xfc00e7ff, WR_a|RD_s|RD_t, 0, D33 }, +{"multu", "d,s,t", 0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0, G1 }, +{"mulu", "d,s,t", 0x00000059, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0, N5 }, +{"neg", "d,w", 0x00000022, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* sub 0 */ +{"negu", "d,w", 0x00000023, 0xffe007ff, WR_d|RD_t, 0, I1 }, /* subu 0 */ +{"neg.d", "D,V", 0x46200007, 0xffff003f, WR_D|RD_S|FP_D, 0, I1 }, +{"neg.s", "D,V", 0x46000007, 0xffff003f, WR_D|RD_S|FP_S, 0, I1 }, +{"neg.ps", "D,V", 0x46c00007, 0xffff003f, WR_D|RD_S|FP_D, 0, I5|I33 }, +{"nmadd.d", "D,R,S,T", 0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"nmadd.s", "D,R,S,T", 0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"nmadd.ps","D,R,S,T", 0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, +{"nmsub.d", "D,R,S,T", 0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I4|I33 }, +{"nmsub.s", "D,R,S,T", 0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0, I4|I33 }, +{"nmsub.ps","D,R,S,T", 0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0, I5|I33 }, /* nop is at the start of the table. */ -{"nor", "d,v,t", 0x00000027, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"nor", "t,r,I", 0, (int) M_NOR_I, INSN_MACRO, I1 }, -{"nor.ob", "X,Y,Q", 0x7800000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"nor.ob", "D,S,T", 0x4ac0000f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"nor.ob", "D,S,T[e]", 0x4800000f, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"nor.ob", "D,S,k", 0x4bc0000f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"nor.qh", "X,Y,Q", 0x7820000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"not", "d,v", 0x00000027, 0xfc1f07ff, WR_d|RD_s|RD_t, I1 },/*nor d,s,0*/ -{"or", "d,v,t", 0x00000025, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"or", "t,r,I", 0, (int) M_OR_I, INSN_MACRO, I1 }, -{"or.ob", "X,Y,Q", 0x7800000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"or.ob", "D,S,T", 0x4ac0000e, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"or.ob", "D,S,T[e]", 0x4800000e, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"or.ob", "D,S,k", 0x4bc0000e, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"or.qh", "X,Y,Q", 0x7820000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"ori", "t,r,i", 0x34000000, 0xfc000000, WR_t|RD_s, I1 }, -{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, SB1 }, -{"pabsdiffc.ob", "Y,Q", 0x78000035, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, SB1 }, -{"pavg.ob", "X,Y,Q", 0x78000008, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, SB1 }, -{"pickf.ob", "X,Y,Q", 0x78000002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"pickf.ob", "D,S,T", 0x4ac00002, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"pickf.ob", "D,S,k", 0x4bc00002, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"pickf.qh", "X,Y,Q", 0x78200002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"pickt.ob", "X,Y,Q", 0x78000003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"pickt.ob", "D,S,T", 0x4ac00003, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"pickt.ob", "D,S,k", 0x4bc00003, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"pickt.qh", "X,Y,Q", 0x78200003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"pll.ps", "D,V,T", 0x46c0002c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, -{"plu.ps", "D,V,T", 0x46c0002d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, +{"nor", "d,v,t", 0x00000027, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"nor", "t,r,I", 0, (int) M_NOR_I, INSN_MACRO, 0, I1 }, +{"nor.ob", "X,Y,Q", 0x7800000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"nor.ob", "D,S,T", 0x4ac0000f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.ob", "D,S,T[e]", 0x4800000f, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.ob", "D,S,k", 0x4bc0000f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"nor.qh", "X,Y,Q", 0x7820000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"not", "d,v", 0x00000027, 0xfc1f07ff, WR_d|RD_s|RD_t, 0, I1 },/*nor d,s,0*/ +{"or", "d,v,t", 0x00000025, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"or", "t,r,I", 0, (int) M_OR_I, INSN_MACRO, 0, I1 }, +{"or.ob", "X,Y,Q", 0x7800000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"or.ob", "D,S,T", 0x4ac0000e, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.ob", "D,S,T[e]", 0x4800000e, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.ob", "D,S,k", 0x4bc0000e, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"or.qh", "X,Y,Q", 0x7820000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"ori", "t,r,i", 0x34000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +{"pabsdiffc.ob", "Y,Q", 0x78000035, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, SB1 }, +{"pavg.ob", "X,Y,Q", 0x78000008, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, SB1 }, +{"pickf.ob", "X,Y,Q", 0x78000002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"pickf.ob", "D,S,T", 0x4ac00002, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.ob", "D,S,k", 0x4bc00002, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickf.qh", "X,Y,Q", 0x78200002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"pickt.ob", "X,Y,Q", 0x78000003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"pickt.ob", "D,S,T", 0x4ac00003, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.ob", "D,S,k", 0x4bc00003, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"pickt.qh", "X,Y,Q", 0x78200003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"pll.ps", "D,V,T", 0x46c0002c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"plu.ps", "D,V,T", 0x46c0002d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, /* pref and prefx are at the start of the table. */ -{"pul.ps", "D,V,T", 0x46c0002e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, -{"puu.ps", "D,V,T", 0x46c0002f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, -{"rach.ob", "X", 0x7a00003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 }, -{"rach.ob", "D", 0x4a00003f, 0xfffff83f, WR_D, N54 }, -{"rach.qh", "X", 0x7a20003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX }, -{"racl.ob", "X", 0x7800003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 }, -{"racl.ob", "D", 0x4800003f, 0xfffff83f, WR_D, N54 }, -{"racl.qh", "X", 0x7820003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX }, -{"racm.ob", "X", 0x7900003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 }, -{"racm.ob", "D", 0x4900003f, 0xfffff83f, WR_D, N54 }, -{"racm.qh", "X", 0x7920003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX }, -{"recip.d", "D,S", 0x46200015, 0xffff003f, WR_D|RD_S|FP_D, I4 }, -{"recip.ps","D,S", 0x46c00015, 0xffff003f, WR_D|RD_S|FP_D, SB1 }, -{"recip.s", "D,S", 0x46000015, 0xffff003f, WR_D|RD_S|FP_S, I4 }, -{"recip1.d", "D,S", 0x4620001d, 0xffff003f, WR_D|RD_S|FP_D, M3D }, -{"recip1.ps", "D,S", 0x46c0001d, 0xffff003f, WR_D|RD_S|FP_S, M3D }, -{"recip1.s", "D,S", 0x4600001d, 0xffff003f, WR_D|RD_S|FP_S, M3D }, -{"recip2.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D }, -{"recip2.ps", "D,S,T", 0x46c0001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D }, -{"recip2.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D }, -{"rem", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 }, -{"rem", "d,v,t", 0, (int) M_REM_3, INSN_MACRO, I1 }, -{"rem", "d,v,I", 0, (int) M_REM_3I, INSN_MACRO, I1 }, -{"remu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 }, -{"remu", "d,v,t", 0, (int) M_REMU_3, INSN_MACRO, I1 }, -{"remu", "d,v,I", 0, (int) M_REMU_3I, INSN_MACRO, I1 }, -{"rdhwr", "t,K", 0x7c00003b, 0xffe007ff, WR_t, I33 }, -{"rdpgpr", "d,w", 0x41400000, 0xffe007ff, WR_d, I33 }, -{"rfe", "", 0x42000010, 0xffffffff, 0, I1|T3 }, -{"rnas.qh", "X,Q", 0x78200025, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, -{"rnau.ob", "X,Q", 0x78000021, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 }, -{"rnau.qh", "X,Q", 0x78200021, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, -{"rnes.qh", "X,Q", 0x78200026, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, -{"rneu.ob", "X,Q", 0x78000022, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 }, -{"rneu.qh", "X,Q", 0x78200022, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, -{"rol", "d,v,t", 0, (int) M_ROL, INSN_MACRO, I1 }, -{"rol", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, I1 }, -{"ror", "d,v,t", 0, (int) M_ROR, INSN_MACRO, I1 }, -{"ror", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, I1 }, -{"ror", "d,w,<", 0x00200002, 0xffe0003f, WR_d|RD_t, N5|I33 }, -{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, N5|I33 }, -{"rotl", "d,v,t", 0, (int) M_ROL, INSN_MACRO, I33 }, -{"rotl", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, I33 }, -{"rotr", "d,v,t", 0, (int) M_ROR, INSN_MACRO, I33 }, -{"rotr", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, I33 }, -{"rotrv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, I33 }, -{"round.l.d", "D,S", 0x46200008, 0xffff003f, WR_D|RD_S|FP_D, I3 }, -{"round.l.s", "D,S", 0x46000008, 0xffff003f, WR_D|RD_S|FP_S, I3 }, -{"round.w.d", "D,S", 0x4620000c, 0xffff003f, WR_D|RD_S|FP_D, I2 }, -{"round.w.s", "D,S", 0x4600000c, 0xffff003f, WR_D|RD_S|FP_S, I2 }, -{"rsqrt.d", "D,S", 0x46200016, 0xffff003f, WR_D|RD_S|FP_D, I4 }, -{"rsqrt.ps","D,S", 0x46c00016, 0xffff003f, WR_D|RD_S|FP_D, SB1 }, -{"rsqrt.s", "D,S", 0x46000016, 0xffff003f, WR_D|RD_S|FP_S, I4 }, -{"rsqrt1.d", "D,S", 0x4620001e, 0xffff003f, WR_D|RD_S|FP_D, M3D }, -{"rsqrt1.ps", "D,S", 0x46c0001e, 0xffff003f, WR_D|RD_S|FP_S, M3D }, -{"rsqrt1.s", "D,S", 0x4600001e, 0xffff003f, WR_D|RD_S|FP_S, M3D }, -{"rsqrt2.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D }, -{"rsqrt2.ps", "D,S,T", 0x46c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D }, -{"rsqrt2.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D }, -{"rzs.qh", "X,Q", 0x78200024, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, -{"rzu.ob", "X,Q", 0x78000020, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 }, -{"rzu.ob", "D,k", 0x4bc00020, 0xffe0f83f, WR_D|RD_S|RD_T, N54 }, -{"rzu.qh", "X,Q", 0x78200020, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX }, -{"sb", "t,o(b)", 0xa0000000, 0xfc000000, SM|RD_t|RD_b, I1 }, -{"sb", "t,A(b)", 0, (int) M_SB_AB, INSN_MACRO, I1 }, -{"sc", "t,o(b)", 0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, I2 }, -{"sc", "t,A(b)", 0, (int) M_SC_AB, INSN_MACRO, I2 }, -{"scd", "t,o(b)", 0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, I3 }, -{"scd", "t,A(b)", 0, (int) M_SCD_AB, INSN_MACRO, I3 }, -{"sd", "t,o(b)", 0xfc000000, 0xfc000000, SM|RD_t|RD_b, I3 }, -{"sd", "t,o(b)", 0, (int) M_SD_OB, INSN_MACRO, I1 }, -{"sd", "t,A(b)", 0, (int) M_SD_AB, INSN_MACRO, I1 }, -{"sdbbp", "", 0x0000000e, 0xffffffff, TRAP, G2 }, -{"sdbbp", "c", 0x0000000e, 0xfc00ffff, TRAP, G2 }, -{"sdbbp", "c,q", 0x0000000e, 0xfc00003f, TRAP, G2 }, -{"sdbbp", "", 0x7000003f, 0xffffffff, TRAP, I32 }, -{"sdbbp", "B", 0x7000003f, 0xfc00003f, TRAP, I32 }, -{"sdc1", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 }, -{"sdc1", "E,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 }, -{"sdc1", "T,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, I2 }, -{"sdc1", "E,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, I2 }, -{"sdc2", "E,o(b)", 0xf8000000, 0xfc000000, SM|RD_C2|RD_b, I2 }, -{"sdc2", "E,A(b)", 0, (int) M_SDC2_AB, INSN_MACRO, I2 }, -{"sdc3", "E,o(b)", 0xfc000000, 0xfc000000, SM|RD_C3|RD_b, I2 }, -{"sdc3", "E,A(b)", 0, (int) M_SDC3_AB, INSN_MACRO, I2 }, -{"s.d", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 }, -{"s.d", "T,o(b)", 0, (int) M_S_DOB, INSN_MACRO, I1 }, -{"s.d", "T,A(b)", 0, (int) M_S_DAB, INSN_MACRO, I1 }, -{"sdl", "t,o(b)", 0xb0000000, 0xfc000000, SM|RD_t|RD_b, I3 }, -{"sdl", "t,A(b)", 0, (int) M_SDL_AB, INSN_MACRO, I3 }, -{"sdr", "t,o(b)", 0xb4000000, 0xfc000000, SM|RD_t|RD_b, I3 }, -{"sdr", "t,A(b)", 0, (int) M_SDR_AB, INSN_MACRO, I3 }, -{"sdxc1", "S,t(b)", 0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I4 }, -{"seb", "d,w", 0x7c000420, 0xffe007ff, WR_d|RD_t, I33 }, -{"seh", "d,w", 0x7c000620, 0xffe007ff, WR_d|RD_t, I33 }, -{"selsl", "d,v,t", 0x00000005, 0xfc0007ff, WR_d|RD_s|RD_t, L1 }, -{"selsr", "d,v,t", 0x00000001, 0xfc0007ff, WR_d|RD_s|RD_t, L1 }, -{"seq", "d,v,t", 0, (int) M_SEQ, INSN_MACRO, I1 }, -{"seq", "d,v,I", 0, (int) M_SEQ_I, INSN_MACRO, I1 }, -{"sge", "d,v,t", 0, (int) M_SGE, INSN_MACRO, I1 }, -{"sge", "d,v,I", 0, (int) M_SGE_I, INSN_MACRO, I1 }, -{"sgeu", "d,v,t", 0, (int) M_SGEU, INSN_MACRO, I1 }, -{"sgeu", "d,v,I", 0, (int) M_SGEU_I, INSN_MACRO, I1 }, -{"sgt", "d,v,t", 0, (int) M_SGT, INSN_MACRO, I1 }, -{"sgt", "d,v,I", 0, (int) M_SGT_I, INSN_MACRO, I1 }, -{"sgtu", "d,v,t", 0, (int) M_SGTU, INSN_MACRO, I1 }, -{"sgtu", "d,v,I", 0, (int) M_SGTU_I, INSN_MACRO, I1 }, -{"sh", "t,o(b)", 0xa4000000, 0xfc000000, SM|RD_t|RD_b, I1 }, -{"sh", "t,A(b)", 0, (int) M_SH_AB, INSN_MACRO, I1 }, -{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"sle", "d,v,t", 0, (int) M_SLE, INSN_MACRO, I1 }, -{"sle", "d,v,I", 0, (int) M_SLE_I, INSN_MACRO, I1 }, -{"sleu", "d,v,t", 0, (int) M_SLEU, INSN_MACRO, I1 }, -{"sleu", "d,v,I", 0, (int) M_SLEU_I, INSN_MACRO, I1 }, -{"sllv", "d,t,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, -{"sll", "d,w,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* sllv */ -{"sll", "d,w,<", 0x00000000, 0xffe0003f, WR_d|RD_t, I1 }, -{"sll.ob", "X,Y,Q", 0x78000010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"sll.ob", "D,S,T[e]", 0x48000010, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"sll.ob", "D,S,k", 0x4bc00010, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"sll.qh", "X,Y,Q", 0x78200010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"slt", "d,v,t", 0x0000002a, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"slt", "d,v,I", 0, (int) M_SLT_I, INSN_MACRO, I1 }, -{"slti", "t,r,j", 0x28000000, 0xfc000000, WR_t|RD_s, I1 }, -{"sltiu", "t,r,j", 0x2c000000, 0xfc000000, WR_t|RD_s, I1 }, -{"sltu", "d,v,t", 0x0000002b, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"sltu", "d,v,I", 0, (int) M_SLTU_I, INSN_MACRO, I1 }, -{"sne", "d,v,t", 0, (int) M_SNE, INSN_MACRO, I1 }, -{"sne", "d,v,I", 0, (int) M_SNE_I, INSN_MACRO, I1 }, -{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_D|RD_S|FP_D, I2 }, -{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_D|RD_S|FP_S, I2 }, -{"sqrt.ps", "D,S", 0x46c00004, 0xffff003f, WR_D|RD_S|FP_D, SB1 }, -{"srav", "d,t,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, -{"sra", "d,w,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* srav */ -{"sra", "d,w,<", 0x00000003, 0xffe0003f, WR_d|RD_t, I1 }, -{"sra.qh", "X,Y,Q", 0x78200013, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"srlv", "d,t,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, -{"srl", "d,w,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* srlv */ -{"srl", "d,w,<", 0x00000002, 0xffe0003f, WR_d|RD_t, I1 }, -{"srl.ob", "X,Y,Q", 0x78000012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"srl.ob", "D,S,T[e]", 0x48000012, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"srl.ob", "D,S,k", 0x4bc00012, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"srl.qh", "X,Y,Q", 0x78200012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, +{"pul.ps", "D,V,T", 0x46c0002e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"puu.ps", "D,V,T", 0x46c0002f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"pperm", "s,t", 0x70000481, 0xfc00ffff, MOD_HILO|RD_s|RD_t, 0, SMT }, +{"rach.ob", "X", 0x7a00003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"rach.ob", "D", 0x4a00003f, 0xfffff83f, WR_D, 0, N54 }, +{"rach.qh", "X", 0x7a20003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"racl.ob", "X", 0x7800003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"racl.ob", "D", 0x4800003f, 0xfffff83f, WR_D, 0, N54 }, +{"racl.qh", "X", 0x7820003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"racm.ob", "X", 0x7900003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX|SB1 }, +{"racm.ob", "D", 0x4900003f, 0xfffff83f, WR_D, 0, N54 }, +{"racm.qh", "X", 0x7920003f, 0xfffff83f, WR_D|FP_D, RD_MACC, MX }, +{"recip.d", "D,S", 0x46200015, 0xffff003f, WR_D|RD_S|FP_D, 0, I4|I33 }, +{"recip.ps","D,S", 0x46c00015, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"recip.s", "D,S", 0x46000015, 0xffff003f, WR_D|RD_S|FP_S, 0, I4|I33 }, +{"recip1.d", "D,S", 0x4620001d, 0xffff003f, WR_D|RD_S|FP_D, 0, M3D }, +{"recip1.ps", "D,S", 0x46c0001d, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"recip1.s", "D,S", 0x4600001d, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"recip2.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"recip2.ps", "D,S,T", 0x46c0001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"recip2.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rem", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"rem", "d,v,t", 0, (int) M_REM_3, INSN_MACRO, 0, I1 }, +{"rem", "d,v,I", 0, (int) M_REM_3I, INSN_MACRO, 0, I1 }, +{"remu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, 0, I1 }, +{"remu", "d,v,t", 0, (int) M_REMU_3, INSN_MACRO, 0, I1 }, +{"remu", "d,v,I", 0, (int) M_REMU_3I, INSN_MACRO, 0, I1 }, +{"rdhwr", "t,K", 0x7c00003b, 0xffe007ff, WR_t, 0, I33 }, +{"rdpgpr", "d,w", 0x41400000, 0xffe007ff, WR_d, 0, I33 }, +{"rfe", "", 0x42000010, 0xffffffff, 0, 0, I1|T3 }, +{"rnas.qh", "X,Q", 0x78200025, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rnau.ob", "X,Q", 0x78000021, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rnau.qh", "X,Q", 0x78200021, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rnes.qh", "X,Q", 0x78200026, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rneu.ob", "X,Q", 0x78000022, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rneu.qh", "X,Q", 0x78200022, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rol", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I1 }, +{"rol", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I1 }, +{"ror", "d,v,t", 0, (int) M_ROR, INSN_MACRO, 0, I1 }, +{"ror", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I1 }, +{"ror", "d,w,<", 0x00200002, 0xffe0003f, WR_d|RD_t, 0, N5|I33|SMT }, +{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, N5|I33|SMT }, +{"rotl", "d,v,t", 0, (int) M_ROL, INSN_MACRO, 0, I33|SMT }, +{"rotl", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, 0, I33|SMT }, +{"rotr", "d,v,t", 0, (int) M_ROR, INSN_MACRO, 0, I33|SMT }, +{"rotr", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, 0, I33|SMT }, +{"rotrv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, 0, I33|SMT }, +{"round.l.d", "D,S", 0x46200008, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"round.l.s", "D,S", 0x46000008, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"round.w.d", "D,S", 0x4620000c, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"round.w.s", "D,S", 0x4600000c, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"rsqrt.d", "D,S", 0x46200016, 0xffff003f, WR_D|RD_S|FP_D, 0, I4|I33 }, +{"rsqrt.ps","D,S", 0x46c00016, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"rsqrt.s", "D,S", 0x46000016, 0xffff003f, WR_D|RD_S|FP_S, 0, I4|I33 }, +{"rsqrt1.d", "D,S", 0x4620001e, 0xffff003f, WR_D|RD_S|FP_D, 0, M3D }, +{"rsqrt1.ps", "D,S", 0x46c0001e, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"rsqrt1.s", "D,S", 0x4600001e, 0xffff003f, WR_D|RD_S|FP_S, 0, M3D }, +{"rsqrt2.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, M3D }, +{"rsqrt2.ps", "D,S,T", 0x46c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rsqrt2.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, M3D }, +{"rzs.qh", "X,Q", 0x78200024, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"rzu.ob", "X,Q", 0x78000020, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX|SB1 }, +{"rzu.ob", "D,k", 0x4bc00020, 0xffe0f83f, WR_D|RD_S|RD_T, 0, N54 }, +{"rzu.qh", "X,Q", 0x78200020, 0xfc20f83f, WR_D|RD_T|FP_D, RD_MACC, MX }, +{"sb", "t,o(b)", 0xa0000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sb", "t,A(b)", 0, (int) M_SB_AB, INSN_MACRO, 0, I1 }, +{"sc", "t,o(b)", 0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I2 }, +{"sc", "t,A(b)", 0, (int) M_SC_AB, INSN_MACRO, 0, I2 }, +{"scd", "t,o(b)", 0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, 0, I3 }, +{"scd", "t,A(b)", 0, (int) M_SCD_AB, INSN_MACRO, 0, I3 }, +{"sd", "t,o(b)", 0xfc000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sd", "t,o(b)", 0, (int) M_SD_OB, INSN_MACRO, 0, I1 }, +{"sd", "t,A(b)", 0, (int) M_SD_AB, INSN_MACRO, 0, I1 }, +{"sdbbp", "", 0x0000000e, 0xffffffff, TRAP, 0, G2 }, +{"sdbbp", "c", 0x0000000e, 0xfc00ffff, TRAP, 0, G2 }, +{"sdbbp", "c,q", 0x0000000e, 0xfc00003f, TRAP, 0, G2 }, +{"sdbbp", "", 0x7000003f, 0xffffffff, TRAP, 0, I32 }, +{"sdbbp", "B", 0x7000003f, 0xfc00003f, TRAP, 0, I32 }, +{"sdc1", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "E,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"sdc1", "T,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, 0, I2 }, +{"sdc1", "E,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, 0, I2 }, +{"sdc2", "E,o(b)", 0xf8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I2 }, +{"sdc2", "E,A(b)", 0, (int) M_SDC2_AB, INSN_MACRO, 0, I2 }, +{"sdc3", "E,o(b)", 0xfc000000, 0xfc000000, SM|RD_C3|RD_b, 0, I2 }, +{"sdc3", "E,A(b)", 0, (int) M_SDC3_AB, INSN_MACRO, 0, I2 }, +{"s.d", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, 0, I2 }, +{"s.d", "T,o(b)", 0, (int) M_S_DOB, INSN_MACRO, 0, I1 }, +{"s.d", "T,A(b)", 0, (int) M_S_DAB, INSN_MACRO, 0, I1 }, +{"sdl", "t,o(b)", 0xb0000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdl", "t,A(b)", 0, (int) M_SDL_AB, INSN_MACRO, 0, I3 }, +{"sdr", "t,o(b)", 0xb4000000, 0xfc000000, SM|RD_t|RD_b, 0, I3 }, +{"sdr", "t,A(b)", 0, (int) M_SDR_AB, INSN_MACRO, 0, I3 }, +{"sdxc1", "S,t(b)", 0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D, 0, I4|I33 }, +{"seb", "d,w", 0x7c000420, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"seh", "d,w", 0x7c000620, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"selsl", "d,v,t", 0x00000005, 0xfc0007ff, WR_d|RD_s|RD_t, 0, L1 }, +{"selsr", "d,v,t", 0x00000001, 0xfc0007ff, WR_d|RD_s|RD_t, 0, L1 }, +{"seq", "d,v,t", 0, (int) M_SEQ, INSN_MACRO, 0, I1 }, +{"seq", "d,v,I", 0, (int) M_SEQ_I, INSN_MACRO, 0, I1 }, +{"sge", "d,v,t", 0, (int) M_SGE, INSN_MACRO, 0, I1 }, +{"sge", "d,v,I", 0, (int) M_SGE_I, INSN_MACRO, 0, I1 }, +{"sgeu", "d,v,t", 0, (int) M_SGEU, INSN_MACRO, 0, I1 }, +{"sgeu", "d,v,I", 0, (int) M_SGEU_I, INSN_MACRO, 0, I1 }, +{"sgt", "d,v,t", 0, (int) M_SGT, INSN_MACRO, 0, I1 }, +{"sgt", "d,v,I", 0, (int) M_SGT_I, INSN_MACRO, 0, I1 }, +{"sgtu", "d,v,t", 0, (int) M_SGTU, INSN_MACRO, 0, I1 }, +{"sgtu", "d,v,I", 0, (int) M_SGTU_I, INSN_MACRO, 0, I1 }, +{"sh", "t,o(b)", 0xa4000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sh", "t,A(b)", 0, (int) M_SH_AB, INSN_MACRO, 0, I1 }, +{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sle", "d,v,t", 0, (int) M_SLE, INSN_MACRO, 0, I1 }, +{"sle", "d,v,I", 0, (int) M_SLE_I, INSN_MACRO, 0, I1 }, +{"sleu", "d,v,t", 0, (int) M_SLEU, INSN_MACRO, 0, I1 }, +{"sleu", "d,v,I", 0, (int) M_SLEU_I, INSN_MACRO, 0, I1 }, +{"sllv", "d,t,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sll", "d,w,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* sllv */ +{"sll", "d,w,<", 0x00000000, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"sll.ob", "X,Y,Q", 0x78000010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sll.ob", "D,S,T[e]", 0x48000010, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sll.ob", "D,S,k", 0x4bc00010, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sll.qh", "X,Y,Q", 0x78200010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"slt", "d,v,t", 0x0000002a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"slt", "d,v,I", 0, (int) M_SLT_I, INSN_MACRO, 0, I1 }, +{"slti", "t,r,j", 0x28000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltiu", "t,r,j", 0x2c000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"sltu", "d,v,t", 0x0000002b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sltu", "d,v,I", 0, (int) M_SLTU_I, INSN_MACRO, 0, I1 }, +{"sne", "d,v,t", 0, (int) M_SNE, INSN_MACRO, 0, I1 }, +{"sne", "d,v,I", 0, (int) M_SNE_I, INSN_MACRO, 0, I1 }, +{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_D|RD_S|FP_D, 0, I2 }, +{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"sqrt.ps", "D,S", 0x46c00004, 0xffff003f, WR_D|RD_S|FP_D, 0, SB1 }, +{"srav", "d,t,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"sra", "d,w,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srav */ +{"sra", "d,w,<", 0x00000003, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"sra.qh", "X,Y,Q", 0x78200013, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"srlv", "d,t,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, +{"srl", "d,w,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, 0, I1 }, /* srlv */ +{"srl", "d,w,<", 0x00000002, 0xffe0003f, WR_d|RD_t, 0, I1 }, +{"srl.ob", "X,Y,Q", 0x78000012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"srl.ob", "D,S,T[e]", 0x48000012, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"srl.ob", "D,S,k", 0x4bc00012, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"srl.qh", "X,Y,Q", 0x78200012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, /* ssnop is at the start of the table. */ -{"standby", "", 0x42000021, 0xffffffff, 0, V1 }, -{"sub", "d,v,t", 0x00000022, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"sub", "d,v,I", 0, (int) M_SUB_I, INSN_MACRO, I1 }, -{"sub.d", "D,V,T", 0x46200001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 }, -{"sub.s", "D,V,T", 0x46000001, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 }, -{"sub.ob", "X,Y,Q", 0x7800000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"sub.ob", "D,S,T", 0x4ac0000a, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"sub.ob", "D,S,T[e]", 0x4800000a, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"sub.ob", "D,S,k", 0x4bc0000a, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"sub.ps", "D,V,T", 0x46c00001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 }, -{"sub.qh", "X,Y,Q", 0x7820000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"suba.ob", "Y,Q", 0x78000036, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"suba.qh", "Y,Q", 0x78200036, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"subl.ob", "Y,Q", 0x78000436, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"subl.qh", "Y,Q", 0x78200436, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"subu", "d,v,t", 0x00000023, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"subu", "d,v,I", 0, (int) M_SUBU_I, INSN_MACRO, I1 }, -{"suspend", "", 0x42000022, 0xffffffff, 0, V1 }, -{"suxc1", "S,t(b)", 0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I5|N55 }, -{"sw", "t,o(b)", 0xac000000, 0xfc000000, SM|RD_t|RD_b, I1 }, -{"sw", "t,A(b)", 0, (int) M_SW_AB, INSN_MACRO, I1 }, -{"swc0", "E,o(b)", 0xe0000000, 0xfc000000, SM|RD_C0|RD_b, I1 }, -{"swc0", "E,A(b)", 0, (int) M_SWC0_AB, INSN_MACRO, I1 }, -{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 }, -{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 }, -{"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 }, -{"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 }, -{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 }, /* swc1 */ -{"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 }, -{"swc2", "E,o(b)", 0xe8000000, 0xfc000000, SM|RD_C2|RD_b, I1 }, -{"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, I1 }, -{"swc3", "E,o(b)", 0xec000000, 0xfc000000, SM|RD_C3|RD_b, I1 }, -{"swc3", "E,A(b)", 0, (int) M_SWC3_AB, INSN_MACRO, I1 }, -{"swl", "t,o(b)", 0xa8000000, 0xfc000000, SM|RD_t|RD_b, I1 }, -{"swl", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, I1 }, -{"scache", "t,o(b)", 0xa8000000, 0xfc000000, RD_t|RD_b, I2 }, /* same */ -{"scache", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, I2 }, /* as swl */ -{"swr", "t,o(b)", 0xb8000000, 0xfc000000, SM|RD_t|RD_b, I1 }, -{"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, I1 }, -{"invalidate", "t,o(b)",0xb8000000, 0xfc000000, RD_t|RD_b, I2 }, /* same */ -{"invalidate", "t,A(b)",0, (int) M_SWR_AB, INSN_MACRO, I2 }, /* as swr */ -{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I4 }, -{"sync", "", 0x0000000f, 0xffffffff, INSN_SYNC, I2|G1 }, -{"sync.p", "", 0x0000040f, 0xffffffff, INSN_SYNC, I2 }, -{"sync.l", "", 0x0000000f, 0xffffffff, INSN_SYNC, I2 }, -{"synci", "o(b)", 0x041f0000, 0xfc1f0000, SM|RD_b, I33 }, -{"syscall", "", 0x0000000c, 0xffffffff, TRAP, I1 }, -{"syscall", "B", 0x0000000c, 0xfc00003f, TRAP, I1 }, -{"teqi", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, I2 }, -{"teq", "s,t", 0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, -{"teq", "s,t,q", 0x00000034, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, -{"teq", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* teqi */ -{"teq", "s,I", 0, (int) M_TEQ_I, INSN_MACRO, I2 }, -{"tgei", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, I2 }, -{"tge", "s,t", 0x00000030, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, -{"tge", "s,t,q", 0x00000030, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, -{"tge", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tgei */ -{"tge", "s,I", 0, (int) M_TGE_I, INSN_MACRO, I2 }, -{"tgeiu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, I2 }, -{"tgeu", "s,t", 0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, -{"tgeu", "s,t,q", 0x00000031, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, -{"tgeu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tgeiu */ -{"tgeu", "s,I", 0, (int) M_TGEU_I, INSN_MACRO, I2 }, -{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, I1 }, -{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, I1 }, -{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, I1 }, -{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, I1 }, -{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, I2 }, -{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, -{"tlt", "s,t,q", 0x00000032, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, -{"tlt", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tlti */ -{"tlt", "s,I", 0, (int) M_TLT_I, INSN_MACRO, I2 }, -{"tltiu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, I2 }, -{"tltu", "s,t", 0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, -{"tltu", "s,t,q", 0x00000033, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, -{"tltu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tltiu */ -{"tltu", "s,I", 0, (int) M_TLTU_I, INSN_MACRO, I2 }, -{"tnei", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, I2 }, -{"tne", "s,t", 0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP, I2 }, -{"tne", "s,t,q", 0x00000036, 0xfc00003f, RD_s|RD_t|TRAP, I2 }, -{"tne", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tnei */ -{"tne", "s,I", 0, (int) M_TNE_I, INSN_MACRO, I2 }, -{"trunc.l.d", "D,S", 0x46200009, 0xffff003f, WR_D|RD_S|FP_D, I3 }, -{"trunc.l.s", "D,S", 0x46000009, 0xffff003f, WR_D|RD_S|FP_S, I3 }, -{"trunc.w.d", "D,S", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_D, I2 }, -{"trunc.w.d", "D,S,x", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_D, I2 }, -{"trunc.w.d", "D,S,t", 0, (int) M_TRUNCWD, INSN_MACRO, I1 }, -{"trunc.w.s", "D,S", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, I2 }, -{"trunc.w.s", "D,S,x", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, I2 }, -{"trunc.w.s", "D,S,t", 0, (int) M_TRUNCWS, INSN_MACRO, I1 }, -{"uld", "t,o(b)", 0, (int) M_ULD, INSN_MACRO, I3 }, -{"uld", "t,A(b)", 0, (int) M_ULD_A, INSN_MACRO, I3 }, -{"ulh", "t,o(b)", 0, (int) M_ULH, INSN_MACRO, I1 }, -{"ulh", "t,A(b)", 0, (int) M_ULH_A, INSN_MACRO, I1 }, -{"ulhu", "t,o(b)", 0, (int) M_ULHU, INSN_MACRO, I1 }, -{"ulhu", "t,A(b)", 0, (int) M_ULHU_A, INSN_MACRO, I1 }, -{"ulw", "t,o(b)", 0, (int) M_ULW, INSN_MACRO, I1 }, -{"ulw", "t,A(b)", 0, (int) M_ULW_A, INSN_MACRO, I1 }, -{"usd", "t,o(b)", 0, (int) M_USD, INSN_MACRO, I3 }, -{"usd", "t,A(b)", 0, (int) M_USD_A, INSN_MACRO, I3 }, -{"ush", "t,o(b)", 0, (int) M_USH, INSN_MACRO, I1 }, -{"ush", "t,A(b)", 0, (int) M_USH_A, INSN_MACRO, I1 }, -{"usw", "t,o(b)", 0, (int) M_USW, INSN_MACRO, I1 }, -{"usw", "t,A(b)", 0, (int) M_USW_A, INSN_MACRO, I1 }, -{"wach.ob", "Y", 0x7a00003e, 0xffff07ff, WR_MACC|RD_S|FP_D, MX|SB1 }, -{"wach.ob", "S", 0x4a00003e, 0xffff07ff, RD_S, N54 }, -{"wach.qh", "Y", 0x7a20003e, 0xffff07ff, WR_MACC|RD_S|FP_D, MX }, -{"wacl.ob", "Y,Z", 0x7800003e, 0xffe007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 }, -{"wacl.ob", "S,T", 0x4800003e, 0xffe007ff, RD_S|RD_T, N54 }, -{"wacl.qh", "Y,Z", 0x7820003e, 0xffe007ff, WR_MACC|RD_S|RD_T|FP_D, MX }, -{"wait", "", 0x42000020, 0xffffffff, TRAP, I3|I32 }, -{"wait", "J", 0x42000020, 0xfe00003f, TRAP, I32|N55 }, -{"waiti", "", 0x42000020, 0xffffffff, TRAP, L1 }, -{"wb", "o(b)", 0xbc040000, 0xfc1f0000, SM|RD_b, L1 }, -{"wrpgpr", "d,w", 0x41c00000, 0xffe007ff, RD_t, I33 }, -{"wsbh", "d,w", 0x7c0000a0, 0xffe007ff, WR_d|RD_t, I33 }, -{"xor", "d,v,t", 0x00000026, 0xfc0007ff, WR_d|RD_s|RD_t, I1 }, -{"xor", "t,r,I", 0, (int) M_XOR_I, INSN_MACRO, I1 }, -{"xor.ob", "X,Y,Q", 0x7800000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 }, -{"xor.ob", "D,S,T", 0x4ac0000d, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"xor.ob", "D,S,T[e]", 0x4800000d, 0xfe20003f, WR_D|RD_S|RD_T, N54 }, -{"xor.ob", "D,S,k", 0x4bc0000d, 0xffe0003f, WR_D|RD_S|RD_T, N54 }, -{"xor.qh", "X,Y,Q", 0x7820000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX }, -{"xori", "t,r,i", 0x38000000, 0xfc000000, WR_t|RD_s, I1 }, +{"standby", "", 0x42000021, 0xffffffff, 0, 0, V1 }, +{"sub", "d,v,t", 0x00000022, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"sub", "d,v,I", 0, (int) M_SUB_I, INSN_MACRO, 0, I1 }, +{"sub.d", "D,V,T", 0x46200001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I1 }, +{"sub.s", "D,V,T", 0x46000001, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I1 }, +{"sub.ob", "X,Y,Q", 0x7800000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"sub.ob", "D,S,T", 0x4ac0000a, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ob", "D,S,T[e]", 0x4800000a, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ob", "D,S,k", 0x4bc0000a, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"sub.ps", "D,V,T", 0x46c00001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I5|I33 }, +{"sub.qh", "X,Y,Q", 0x7820000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"suba.ob", "Y,Q", 0x78000036, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"suba.qh", "Y,Q", 0x78200036, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"subl.ob", "Y,Q", 0x78000436, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"subl.qh", "Y,Q", 0x78200436, 0xfc2007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"subu", "d,v,t", 0x00000023, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"subu", "d,v,I", 0, (int) M_SUBU_I, INSN_MACRO, 0, I1 }, +{"suspend", "", 0x42000022, 0xffffffff, 0, 0, V1 }, +{"suxc1", "S,t(b)", 0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b, 0, I5|I33|N55}, +{"sw", "t,o(b)", 0xac000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"sw", "t,A(b)", 0, (int) M_SW_AB, INSN_MACRO, 0, I1 }, +{"swc0", "E,o(b)", 0xe0000000, 0xfc000000, SM|RD_C0|RD_b, 0, I1 }, +{"swc0", "E,A(b)", 0, (int) M_SWC0_AB, INSN_MACRO, 0, I1 }, +{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, +{"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, 0, I1 }, /* swc1 */ +{"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, 0, I1 }, +{"swc2", "E,o(b)", 0xe8000000, 0xfc000000, SM|RD_C2|RD_b, 0, I1 }, +{"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, 0, I1 }, +{"swc3", "E,o(b)", 0xec000000, 0xfc000000, SM|RD_C3|RD_b, 0, I1 }, +{"swc3", "E,A(b)", 0, (int) M_SWC3_AB, INSN_MACRO, 0, I1 }, +{"swl", "t,o(b)", 0xa8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swl", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I1 }, +{"scache", "t,o(b)", 0xa8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"scache", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I2 }, /* as swl */ +{"swr", "t,o(b)", 0xb8000000, 0xfc000000, SM|RD_t|RD_b, 0, I1 }, +{"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, 0, I1 }, +{"invalidate", "t,o(b)",0xb8000000, 0xfc000000, RD_t|RD_b, 0, I2 }, /* same */ +{"invalidate", "t,A(b)",0, (int) M_SWR_AB, INSN_MACRO, 0, I2 }, /* as swr */ +{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_S, 0, I4|I33 }, +{"sync", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2|G1 }, +{"sync.p", "", 0x0000040f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"sync.l", "", 0x0000000f, 0xffffffff, INSN_SYNC, 0, I2 }, +{"synci", "o(b)", 0x041f0000, 0xfc1f0000, SM|RD_b, 0, I33 }, +{"syscall", "", 0x0000000c, 0xffffffff, TRAP, 0, I1 }, +{"syscall", "B", 0x0000000c, 0xfc00003f, TRAP, 0, I1 }, +{"teqi", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"teq", "s,t", 0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,t,q", 0x00000034, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"teq", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* teqi */ +{"teq", "s,I", 0, (int) M_TEQ_I, INSN_MACRO, 0, I2 }, +{"tgei", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tge", "s,t", 0x00000030, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,t,q", 0x00000030, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tge", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgei */ +{"tge", "s,I", 0, (int) M_TGE_I, INSN_MACRO, 0, I2 }, +{"tgeiu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tgeu", "s,t", 0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,t,q", 0x00000031, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tgeu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tgeiu */ +{"tgeu", "s,I", 0, (int) M_TGEU_I, INSN_MACRO, 0, I2 }, +{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,t,q", 0x00000032, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tlt", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tlti */ +{"tlt", "s,I", 0, (int) M_TLT_I, INSN_MACRO, 0, I2 }, +{"tltiu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tltu", "s,t", 0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,t,q", 0x00000033, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tltu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tltiu */ +{"tltu", "s,I", 0, (int) M_TLTU_I, INSN_MACRO, 0, I2 }, +{"tnei", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, +{"tne", "s,t", 0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,t,q", 0x00000036, 0xfc00003f, RD_s|RD_t|TRAP, 0, I2 }, +{"tne", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, /* tnei */ +{"tne", "s,I", 0, (int) M_TNE_I, INSN_MACRO, 0, I2 }, +{"trunc.l.d", "D,S", 0x46200009, 0xffff003f, WR_D|RD_S|FP_D, 0, I3|I33 }, +{"trunc.l.s", "D,S", 0x46000009, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, +{"trunc.w.d", "D,S", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,x", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, +{"trunc.w.d", "D,S,t", 0, (int) M_TRUNCWD, INSN_MACRO, 0, I1 }, +{"trunc.w.s", "D,S", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,x", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"trunc.w.s", "D,S,t", 0, (int) M_TRUNCWS, INSN_MACRO, 0, I1 }, +{"uld", "t,o(b)", 0, (int) M_ULD, INSN_MACRO, 0, I3 }, +{"uld", "t,A(b)", 0, (int) M_ULD_A, INSN_MACRO, 0, I3 }, +{"ulh", "t,o(b)", 0, (int) M_ULH, INSN_MACRO, 0, I1 }, +{"ulh", "t,A(b)", 0, (int) M_ULH_A, INSN_MACRO, 0, I1 }, +{"ulhu", "t,o(b)", 0, (int) M_ULHU, INSN_MACRO, 0, I1 }, +{"ulhu", "t,A(b)", 0, (int) M_ULHU_A, INSN_MACRO, 0, I1 }, +{"ulw", "t,o(b)", 0, (int) M_ULW, INSN_MACRO, 0, I1 }, +{"ulw", "t,A(b)", 0, (int) M_ULW_A, INSN_MACRO, 0, I1 }, +{"usd", "t,o(b)", 0, (int) M_USD, INSN_MACRO, 0, I3 }, +{"usd", "t,A(b)", 0, (int) M_USD_A, INSN_MACRO, 0, I3 }, +{"ush", "t,o(b)", 0, (int) M_USH, INSN_MACRO, 0, I1 }, +{"ush", "t,A(b)", 0, (int) M_USH_A, INSN_MACRO, 0, I1 }, +{"usw", "t,o(b)", 0, (int) M_USW, INSN_MACRO, 0, I1 }, +{"usw", "t,A(b)", 0, (int) M_USW_A, INSN_MACRO, 0, I1 }, +{"wach.ob", "Y", 0x7a00003e, 0xffff07ff, RD_S|FP_D, WR_MACC, MX|SB1 }, +{"wach.ob", "S", 0x4a00003e, 0xffff07ff, RD_S, 0, N54 }, +{"wach.qh", "Y", 0x7a20003e, 0xffff07ff, RD_S|FP_D, WR_MACC, MX }, +{"wacl.ob", "Y,Z", 0x7800003e, 0xffe007ff, RD_S|RD_T|FP_D, WR_MACC, MX|SB1 }, +{"wacl.ob", "S,T", 0x4800003e, 0xffe007ff, RD_S|RD_T, 0, N54 }, +{"wacl.qh", "Y,Z", 0x7820003e, 0xffe007ff, RD_S|RD_T|FP_D, WR_MACC, MX }, +{"wait", "", 0x42000020, 0xffffffff, TRAP, 0, I3|I32 }, +{"wait", "J", 0x42000020, 0xfe00003f, TRAP, 0, I32|N55 }, +{"waiti", "", 0x42000020, 0xffffffff, TRAP, 0, L1 }, +{"wrpgpr", "d,w", 0x41c00000, 0xffe007ff, RD_t, 0, I33 }, +{"wsbh", "d,w", 0x7c0000a0, 0xffe007ff, WR_d|RD_t, 0, I33 }, +{"xor", "d,v,t", 0x00000026, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I1 }, +{"xor", "t,r,I", 0, (int) M_XOR_I, INSN_MACRO, 0, I1 }, +{"xor.ob", "X,Y,Q", 0x7800000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX|SB1 }, +{"xor.ob", "D,S,T", 0x4ac0000d, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.ob", "D,S,T[e]", 0x4800000d, 0xfe20003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.ob", "D,S,k", 0x4bc0000d, 0xffe0003f, WR_D|RD_S|RD_T, 0, N54 }, +{"xor.qh", "X,Y,Q", 0x7820000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, 0, MX }, +{"xori", "t,r,i", 0x38000000, 0xfc000000, WR_t|RD_s, 0, I1 }, +{"yield", "s", 0x7c000009, 0xfc1fffff, TRAP|RD_s, 0, MT32 }, +{"yield", "d,s", 0x7c000009, 0xfc1f07ff, TRAP|WR_d|RD_s, 0, MT32 }, + +/* User Defined Instruction. */ +{"udi0", "s,t,d,+1",0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,t,+2", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "s,+3", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi0", "+4", 0x70000010, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,d,+1",0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,t,+2", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "s,+3", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi1", "+4", 0x70000011, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,d,+1",0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,t,+2", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "s,+3", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi2", "+4", 0x70000012, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,d,+1",0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,t,+2", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "s,+3", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi3", "+4", 0x70000013, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,d,+1",0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,t,+2", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "s,+3", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi4", "+4", 0x70000014, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,d,+1",0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,t,+2", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "s,+3", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi5", "+4", 0x70000015, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,d,+1",0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,t,+2", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "s,+3", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi6", "+4", 0x70000016, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,d,+1",0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,t,+2", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "s,+3", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi7", "+4", 0x70000017, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,d,+1",0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,t,+2", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "s,+3", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi8", "+4", 0x70000018, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,d,+1",0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,t,+2", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "s,+3", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi9", "+4", 0x70000019, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,d,+1",0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,t,+2", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "s,+3", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi10", "+4", 0x7000001a, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,d,+1",0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,t,+2", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "s,+3", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi11", "+4", 0x7000001b, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,d,+1",0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,t,+2", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "s,+3", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi12", "+4", 0x7000001c, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,d,+1",0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,t,+2", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "s,+3", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi13", "+4", 0x7000001d, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,d,+1",0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,t,+2", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "s,+3", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi14", "+4", 0x7000001e, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,d,+1",0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,t,+2", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "s,+3", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, +{"udi15", "+4", 0x7000001f, 0xfc00003f, WR_d|RD_s|RD_t, 0, I33 }, /* Coprocessor 2 move/branch operations overlap with VR5400 .ob format instructions so they are here for the latters to take precedence. */ -{"bc2f", "p", 0x49000000, 0xffff0000, CBD|RD_CC, I1 }, -{"bc2fl", "p", 0x49020000, 0xffff0000, CBL|RD_CC, I2|T3 }, -{"bc2t", "p", 0x49010000, 0xffff0000, CBD|RD_CC, I1 }, -{"bc2tl", "p", 0x49030000, 0xffff0000, CBL|RD_CC, I2|T3 }, -{"cfc2", "t,G", 0x48400000, 0xffe007ff, LCD|WR_t|RD_C2, I1 }, -{"ctc2", "t,G", 0x48c00000, 0xffe007ff, COD|RD_t|WR_CC, I1 }, -{"dmfc2", "t,G", 0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, I3 }, -{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, I64 }, -{"dmtc2", "t,G", 0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, I3 }, -{"dmtc2", "t,G,H", 0x48a00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, I64 }, -{"mfc2", "t,G", 0x48000000, 0xffe007ff, LCD|WR_t|RD_C2, I1 }, -{"mfc2", "t,G,H", 0x48000000, 0xffe007f8, LCD|WR_t|RD_C2, I32 }, -{"mfhc2", "t,i", 0x48600000, 0xffe00000, LCD|WR_t|RD_C2, I33 }, -{"mtc2", "t,G", 0x48800000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, I1 }, -{"mtc2", "t,G,H", 0x48800000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, I32 }, -{"mthc2", "t,i", 0x48e00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, I33 }, +{"bc2f", "p", 0x49000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2f", "N,p", 0x49000000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2fl", "p", 0x49020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc2fl", "N,p", 0x49020000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"bc2t", "p", 0x49010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc2t", "N,p", 0x49010000, 0xffe30000, CBD|RD_CC, 0, I32 }, +{"bc2tl", "p", 0x49030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc2tl", "N,p", 0x49030000, 0xffe30000, CBL|RD_CC, 0, I32 }, +{"cfc2", "t,G", 0x48400000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"ctc2", "t,G", 0x48c00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc2", "t,G", 0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I3 }, +{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I64 }, +{"dmtc2", "t,G", 0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I3 }, +{"dmtc2", "t,G,H", 0x48a00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I64 }, +{"mfc2", "t,G", 0x48000000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I1 }, +{"mfc2", "t,G,H", 0x48000000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I32 }, +{"mfhc2", "t,G", 0x48600000, 0xffe007ff, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,G,H", 0x48600000, 0xffe007f8, LCD|WR_t|RD_C2, 0, I33 }, +{"mfhc2", "t,i", 0x48600000, 0xffe00000, LCD|WR_t|RD_C2, 0, I33 }, +{"mtc2", "t,G", 0x48800000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I1 }, +{"mtc2", "t,G,H", 0x48800000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I32 }, +{"mthc2", "t,G", 0x48e00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,G,H", 0x48e00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, 0, I33 }, +{"mthc2", "t,i", 0x48e00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, 0, I33 }, + +/* Coprocessor 3 move/branch operations overlap with MIPS IV COP1X + instructions, so they are here for the latters to take precedence. */ +{"bc3f", "p", 0x4d000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3fl", "p", 0x4d020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc3t", "p", 0x4d010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc3tl", "p", 0x4d030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"cfc3", "t,G", 0x4c400000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"ctc3", "t,G", 0x4cc00000, 0xffe007ff, COD|RD_t|WR_CC, 0, I1 }, +{"dmfc3", "t,G", 0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I3 }, +{"dmtc3", "t,G", 0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I3 }, +{"mfc3", "t,G", 0x4c000000, 0xffe007ff, LCD|WR_t|RD_C3, 0, I1 }, +{"mfc3", "t,G,H", 0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 0, I32 }, +{"mtc3", "t,G", 0x4c800000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, 0, I1 }, +{"mtc3", "t,G,H", 0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, 0, I32 }, /* No hazard protection on coprocessor instructions--they shouldn't change the state of the processor and if they do it's up to the user to put in nops as necessary. These are at the end so that the disassembler recognizes more specific versions first. */ -{"c0", "C", 0x42000000, 0xfe000000, 0, I1 }, -{"c1", "C", 0x46000000, 0xfe000000, 0, I1 }, -{"c2", "C", 0x4a000000, 0xfe000000, 0, I1 }, -{"c3", "C", 0x4e000000, 0xfe000000, 0, I1 }, -{"cop0", "C", 0, (int) M_COP0, INSN_MACRO, I1 }, -{"cop1", "C", 0, (int) M_COP1, INSN_MACRO, I1 }, -{"cop2", "C", 0, (int) M_COP2, INSN_MACRO, I1 }, -{"cop3", "C", 0, (int) M_COP3, INSN_MACRO, I1 }, - +{"c0", "C", 0x42000000, 0xfe000000, 0, 0, I1 }, +{"c1", "C", 0x46000000, 0xfe000000, 0, 0, I1 }, +{"c2", "C", 0x4a000000, 0xfe000000, 0, 0, I1 }, +{"c3", "C", 0x4e000000, 0xfe000000, 0, 0, I1 }, +{"cop0", "C", 0, (int) M_COP0, INSN_MACRO, 0, I1 }, +{"cop1", "C", 0, (int) M_COP1, INSN_MACRO, 0, I1 }, +{"cop2", "C", 0, (int) M_COP2, INSN_MACRO, 0, I1 }, +{"cop3", "C", 0, (int) M_COP3, INSN_MACRO, 0, I1 }, /* Conflicts with the 4650's "mul" instruction. Nobody's using the 4010 any more, so move this insn out of the way. If the object format gave us more info, we could do this right. */ -{"addciu", "t,r,j", 0x70000000, 0xfc000000, WR_t|RD_s, L1 }, +{"addciu", "t,r,j", 0x70000000, 0xfc000000, WR_t|RD_s, 0, L1 }, +/* MIPS DSP ASE */ +{"absq_s.ph", "d,t", 0x7c000252, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"absq_s.pw", "d,t", 0x7c000456, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.qh", "d,t", 0x7c000256, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"absq_s.w", "d,t", 0x7c000452, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"addq.ph", "d,s,t", 0x7c000290, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq.pw", "d,s,t", 0x7c000494, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq.qh", "d,s,t", 0x7c000294, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.ph", "d,s,t", 0x7c000390, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addq_s.pw", "d,s,t", 0x7c000594, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.qh", "d,s,t", 0x7c000394, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addq_s.w", "d,s,t", 0x7c000590, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addsc", "d,s,t", 0x7c000410, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu.ob", "d,s,t", 0x7c000014, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu.qb", "d,s,t", 0x7c000010, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addu_s.ob", "d,s,t", 0x7c000114, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"addu_s.qb", "d,s,t", 0x7c000110, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"addwc", "d,s,t", 0x7c000450, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"bitrev", "d,t", 0x7c0006d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"bposge32", "p", 0x041c0000, 0xffff0000, CBD, 0, D32 }, +{"bposge64", "p", 0x041d0000, 0xffff0000, CBD, 0, D64 }, +{"cmp.eq.ph", "s,t", 0x7c000211, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.eq.pw", "s,t", 0x7c000415, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.eq.qh", "s,t", 0x7c000215, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.ob", "d,s,t", 0x7c000115, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.eq.qb", "d,s,t", 0x7c000111, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.le.ob", "d,s,t", 0x7c000195, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.le.qb", "d,s,t", 0x7c000191, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmpgu.lt.ob", "d,s,t", 0x7c000155, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"cmpgu.lt.qb", "d,s,t", 0x7c000151, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"cmp.le.ph", "s,t", 0x7c000291, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.le.pw", "s,t", 0x7c000495, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.le.qh", "s,t", 0x7c000295, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.ph", "s,t", 0x7c000251, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmp.lt.pw", "s,t", 0x7c000455, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmp.lt.qh", "s,t", 0x7c000255, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.ob", "s,t", 0x7c000015, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.eq.qb", "s,t", 0x7c000011, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.le.ob", "s,t", 0x7c000095, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.le.qb", "s,t", 0x7c000091, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"cmpu.lt.ob", "s,t", 0x7c000055, 0xfc00ffff, RD_s|RD_t, 0, D64 }, +{"cmpu.lt.qb", "s,t", 0x7c000051, 0xfc00ffff, RD_s|RD_t, 0, D32 }, +{"dextpdp", "t,7,6", 0x7c0002bc, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D64 }, +{"dextpdpv", "t,7,s", 0x7c0002fc, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D64 }, +{"dextp", "t,7,6", 0x7c0000bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextpv", "t,7,s", 0x7c0000fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.l", "t,7,6", 0x7c00043c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.l", "t,7,6", 0x7c00053c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.l", "t,7,6", 0x7c0005bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_rs.w", "t,7,6", 0x7c0001bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_r.w", "t,7,6", 0x7c00013c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextr_s.h", "t,7,6", 0x7c0003bc, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dextrv.l", "t,7,s", 0x7c00047c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.l", "t,7,s", 0x7c00057c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.l", "t,7,s", 0x7c0005fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_rs.w", "t,7,s", 0x7c0001fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_r.w", "t,7,s", 0x7c00017c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv_s.h", "t,7,s", 0x7c0003fc, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextrv.w", "t,7,s", 0x7c00007c, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D64 }, +{"dextr.w", "t,7,6", 0x7c00003c, 0xfc00e7ff, WR_t|RD_a, 0, D64 }, +{"dinsv", "t,s", 0x7c00000d, 0xfc00ffff, WR_t|RD_s, 0, D64 }, +{"dmadd", "7,s,t", 0x7c000674, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmaddu", "7,s,t", 0x7c000774, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsub", "7,s,t", 0x7c0006f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmsubu", "7,s,t", 0x7c0007f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dmthlip", "s,7", 0x7c0007fc, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D64 }, +{"dpaq_sa.l.pw", "7,s,t", 0x7c000334, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpaq_sa.l.w", "7,s,t", 0x7c000330, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.ph", "7,s,t", 0x7c000130, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpaq_s.w.qh", "7,s,t", 0x7c000134, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obl", "7,s,t", 0x7c0000f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.obr", "7,s,t", 0x7c0001f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpau.h.qbl", "7,s,t", 0x7c0000f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpau.h.qbr", "7,s,t", 0x7c0001f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_sa.l.pw", "7,s,t", 0x7c000374, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsq_sa.l.w", "7,s,t", 0x7c000370, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.ph", "7,s,t", 0x7c000170, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsq_s.w.qh", "7,s,t", 0x7c000174, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obl", "7,s,t", 0x7c0002f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.obr", "7,s,t", 0x7c0003f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"dpsu.h.qbl", "7,s,t", 0x7c0002f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dpsu.h.qbr", "7,s,t", 0x7c0003f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"dshilo", "7,:", 0x7c0006bc, 0xfc07e7ff, MOD_a, 0, D64 }, +{"dshilov", "7,s", 0x7c0006fc, 0xfc1fe7ff, MOD_a|RD_s, 0, D64 }, +{"extpdp", "t,7,6", 0x7c0002b8, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA, 0, D32 }, +{"extpdpv", "t,7,s", 0x7c0002f8, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0, D32 }, +{"extp", "t,7,6", 0x7c0000b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extpv", "t,7,s", 0x7c0000f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr_rs.w", "t,7,6", 0x7c0001b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_r.w", "t,7,6", 0x7c000138, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extr_s.h", "t,7,6", 0x7c0003b8, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"extrv_rs.w", "t,7,s", 0x7c0001f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_r.w", "t,7,s", 0x7c000178, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv_s.h", "t,7,s", 0x7c0003f8, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extrv.w", "t,7,s", 0x7c000078, 0xfc00e7ff, WR_t|RD_a|RD_s, 0, D32 }, +{"extr.w", "t,7,6", 0x7c000038, 0xfc00e7ff, WR_t|RD_a, 0, D32 }, +{"insv", "t,s", 0x7c00000c, 0xfc00ffff, WR_t|RD_s, 0, D32 }, +{"lbux", "d,t(b)", 0x7c00018a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"ldx", "d,t(b)", 0x7c00020a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D64 }, +{"lhx", "d,t(b)", 0x7c00010a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"lwx", "d,t(b)", 0x7c00000a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b, 0, D32 }, +{"maq_sa.w.phl", "7,s,t", 0x7c000430, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.phr", "7,s,t", 0x7c0004b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_sa.w.qhll", "7,s,t", 0x7c000434, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhlr", "7,s,t", 0x7c000474, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrl", "7,s,t", 0x7c0004b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_sa.w.qhrr", "7,s,t", 0x7c0004f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwl", "7,s,t", 0x7c000734, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.l.pwr", "7,s,t", 0x7c0007b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.phl", "7,s,t", 0x7c000530, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.phr", "7,s,t", 0x7c0005b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"maq_s.w.qhll", "7,s,t", 0x7c000534, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhlr", "7,s,t", 0x7c000574, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrl", "7,s,t", 0x7c0005b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"maq_s.w.qhrr", "7,s,t", 0x7c0005f4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"modsub", "d,s,t", 0x7c000490, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"mthlip", "s,7", 0x7c0007f8, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA, 0, D32 }, +{"muleq_s.pw.qhl", "d,s,t", 0x7c000714, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.pw.qhr", "d,s,t", 0x7c000754, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleq_s.w.phl", "d,s,t", 0x7c000710, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleq_s.w.phr", "d,s,t", 0x7c000750, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbl", "d,s,t", 0x7c000190, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.ph.qbr", "d,s,t", 0x7c0001d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"muleu_s.qh.obl", "d,s,t", 0x7c000194, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"muleu_s.qh.obr", "d,s,t", 0x7c0001d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulq_rs.ph", "d,s,t", 0x7c0007d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D32 }, +{"mulq_rs.qh", "d,s,t", 0x7c0007d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D64 }, +{"mulsaq_s.l.pw", "7,s,t", 0x7c0003b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"mulsaq_s.w.ph", "7,s,t", 0x7c0001b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D32 }, +{"mulsaq_s.w.qh", "7,s,t", 0x7c0001b4, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D64 }, +{"packrl.ph", "d,s,t", 0x7c000391, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"packrl.pw", "d,s,t", 0x7c000395, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ob", "d,s,t", 0x7c0000d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.ph", "d,s,t", 0x7c0002d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.pw", "d,s,t", 0x7c0004d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"pick.qb", "d,s,t", 0x7c0000d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"pick.qh", "d,s,t", 0x7c0002d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"preceq.pw.qhla", "d,t", 0x7c000396, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhl", "d,t", 0x7c000316, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhra", "d,t", 0x7c0003d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.pw.qhr", "d,t", 0x7c000356, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwl", "d,t", 0x7c000516, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.s.l.pwr", "d,t", 0x7c000556, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.ph.qbla", "d,t", 0x7c000192, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbl", "d,t", 0x7c000112, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbra", "d,t", 0x7c0001d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.ph.qbr", "d,t", 0x7c000152, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"precequ.pw.qhla", "d,t", 0x7c000196, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhl", "d,t", 0x7c000116, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhra", "d,t", 0x7c0001d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precequ.pw.qhr", "d,t", 0x7c000156, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceq.w.phl", "d,t", 0x7c000312, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceq.w.phr", "d,t", 0x7c000352, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbla", "d,t", 0x7c000792, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbl", "d,t", 0x7c000712, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbra", "d,t", 0x7c0007d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.ph.qbr", "d,t", 0x7c000752, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"preceu.qh.obla", "d,t", 0x7c000796, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obl", "d,t", 0x7c000716, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obra", "d,t", 0x7c0007d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"preceu.qh.obr", "d,t", 0x7c000756, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"precrq.ob.qh", "d,s,t", 0x7c000315, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.ph.w", "d,s,t", 0x7c000511, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.pw.l", "d,s,t", 0x7c000715, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq.qb.ph", "d,s,t", 0x7c000311, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq.qh.pw", "d,s,t", 0x7c000515, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrq_rs.ph.w", "d,s,t", 0x7c000551, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"precrq_rs.qh.pw", "d,s,t", 0x7c000555, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.ob.qh", "d,s,t", 0x7c0003d5, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"precrqu_s.qb.ph", "d,s,t", 0x7c0003d1, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"raddu.l.ob", "d,s", 0x7c000514, 0xfc1f07ff, WR_d|RD_s, 0, D64 }, +{"raddu.w.qb", "d,s", 0x7c000510, 0xfc1f07ff, WR_d|RD_s, 0, D32 }, +{"rddsp", "d", 0x7fff04b8, 0xffff07ff, WR_d, 0, D32 }, +{"rddsp", "d,'", 0x7c0004b8, 0xffc007ff, WR_d, 0, D32 }, +{"repl.ob", "d,5", 0x7c000096, 0xff0007ff, WR_d, 0, D64 }, +{"repl.ph", "d,@", 0x7c000292, 0xfc0007ff, WR_d, 0, D32 }, +{"repl.pw", "d,@", 0x7c000496, 0xfc0007ff, WR_d, 0, D64 }, +{"repl.qb", "d,5", 0x7c000092, 0xff0007ff, WR_d, 0, D32 }, +{"repl.qh", "d,@", 0x7c000296, 0xfc0007ff, WR_d, 0, D64 }, +{"replv.ob", "d,t", 0x7c0000d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.ph", "d,t", 0x7c0002d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.pw", "d,t", 0x7c0004d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"replv.qb", "d,t", 0x7c0000d2, 0xffe007ff, WR_d|RD_t, 0, D32 }, +{"replv.qh", "d,t", 0x7c0002d6, 0xffe007ff, WR_d|RD_t, 0, D64 }, +{"shilo", "7,0", 0x7c0006b8, 0xfc0fe7ff, MOD_a, 0, D32 }, +{"shilov", "7,s", 0x7c0006f8, 0xfc1fe7ff, MOD_a|RD_s, 0, D32 }, +{"shll.ob", "d,t,3", 0x7c000017, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shll.ph", "d,t,4", 0x7c000213, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll.pw", "d,t,6", 0x7c000417, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll.qb", "d,t,3", 0x7c000013, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shll.qh", "d,t,4", 0x7c000217, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.ph", "d,t,4", 0x7c000313, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shll_s.pw", "d,t,6", 0x7c000517, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.qh", "d,t,4", 0x7c000317, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shll_s.w", "d,t,6", 0x7c000513, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shllv.ob", "d,t,s", 0x7c000097, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.ph", "d,t,s", 0x7c000293, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.pw", "d,t,s", 0x7c000497, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv.qb", "d,t,s", 0x7c000093, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv.qh", "d,t,s", 0x7c000297, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.ph", "d,t,s", 0x7c000393, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shllv_s.pw", "d,t,s", 0x7c000597, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.qh", "d,t,s", 0x7c000397, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shllv_s.w", "d,t,s", 0x7c000593, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shra.ph", "d,t,4", 0x7c000253, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra.pw", "d,t,6", 0x7c000457, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra.qh", "d,t,4", 0x7c000257, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.ph", "d,t,4", 0x7c000353, 0xfe0007ff, WR_d|RD_t, 0, D32 }, +{"shra_r.pw", "d,t,6", 0x7c000557, 0xfc0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.qh", "d,t,4", 0x7c000357, 0xfe0007ff, WR_d|RD_t, 0, D64 }, +{"shra_r.w", "d,t,6", 0x7c000553, 0xfc0007ff, WR_d|RD_t, 0, D32 }, +{"shrav.ph", "d,t,s", 0x7c0002d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav.pw", "d,t,s", 0x7c0004d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav.qh", "d,t,s", 0x7c0002d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.ph", "d,t,s", 0x7c0003d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrav_r.pw", "d,t,s", 0x7c0005d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.qh", "d,t,s", 0x7c0003d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrav_r.w", "d,t,s", 0x7c0005d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"shrl.ob", "d,t,3", 0x7c000057, 0xff0007ff, WR_d|RD_t, 0, D64 }, +{"shrl.qb", "d,t,3", 0x7c000053, 0xff0007ff, WR_d|RD_t, 0, D32 }, +{"shrlv.ob", "d,t,s", 0x7c0000d7, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"shrlv.qb", "d,t,s", 0x7c0000d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.ph", "d,s,t", 0x7c0002d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq.pw", "d,s,t", 0x7c0004d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq.qh", "d,s,t", 0x7c0002d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.ph", "d,s,t", 0x7c0003d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subq_s.pw", "d,s,t", 0x7c0005d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.qh", "d,s,t", 0x7c0003d4, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subq_s.w", "d,s,t", 0x7c0005d0, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu.ob", "d,s,t", 0x7c000054, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu.qb", "d,s,t", 0x7c000050, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"subu_s.ob", "d,s,t", 0x7c000154, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D64 }, +{"subu_s.qb", "d,s,t", 0x7c000150, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D32 }, +{"wrdsp", "s", 0x7c1ffcf8, 0xfc1fffff, RD_s|DSP_VOLA, 0, D32 }, +{"wrdsp", "s,8", 0x7c0004f8, 0xfc1e07ff, RD_s|DSP_VOLA, 0, D32 }, +/* MIPS DSP ASE Rev2 */ +{"absq_s.qb", "d,t", 0x7c000052, 0xffe007ff, WR_d|RD_t, 0, D33 }, +{"addu.ph", "d,s,t", 0x7c000210, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addu_s.ph", "d,s,t", 0x7c000310, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh.qb", "d,s,t", 0x7c000018, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"adduh_r.qb", "d,s,t", 0x7c000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"append", "t,s,h", 0x7c000031, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"balign", "t,s,I", 0, (int) M_BALIGN, INSN_MACRO, 0, D33 }, +{"balign", "t,s,2", 0x7c000431, 0xfc00e7ff, WR_t|RD_t|RD_s, 0, D33 }, +{"cmpgdu.eq.qb", "d,s,t", 0x7c000611, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.lt.qb", "d,s,t", 0x7c000651, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"cmpgdu.le.qb", "d,s,t", 0x7c000691, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpa.w.ph", "7,s,t", 0x7c000030, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dps.w.ph", "7,s,t", 0x7c000070, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"mul.ph", "d,s,t", 0x7c000318, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mul_s.ph", "d,s,t", 0x7c000398, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_rs.w", "d,s,t", 0x7c0005d8, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.ph", "d,s,t", 0x7c000790, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulq_s.w", "d,s,t", 0x7c000598, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0, D33 }, +{"mulsa.w.ph", "7,s,t", 0x7c0000b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"precr.qb.ph", "d,s,t", 0x7c000351, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"precr_sra.ph.w", "t,s,h", 0x7c000791, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"precr_sra_r.ph.w", "t,s,h", 0x7c0007d1, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"prepend", "t,s,h", 0x7c000071, 0xfc0007ff, WR_t|RD_t|RD_s, 0, D33 }, +{"shra.qb", "d,t,3", 0x7c000113, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shra_r.qb", "d,t,3", 0x7c000153, 0xff0007ff, WR_d|RD_t, 0, D33 }, +{"shrav.qb", "d,t,s", 0x7c000193, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrav_r.qb", "d,t,s", 0x7c0001d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"shrl.ph", "d,t,4", 0x7c000653, 0xfe0007ff, WR_d|RD_t, 0, D33 }, +{"shrlv.ph", "d,t,s", 0x7c0006d3, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu.ph", "d,s,t", 0x7c000250, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subu_s.ph", "d,s,t", 0x7c000350, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh.qb", "d,s,t", 0x7c000058, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subuh_r.qb", "d,s,t", 0x7c0000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.ph", "d,s,t", 0x7c000218, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.ph", "d,s,t", 0x7c000298, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh.w", "d,s,t", 0x7c000418, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"addqh_r.w", "d,s,t", 0x7c000498, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.ph", "d,s,t", 0x7c000258, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.ph", "d,s,t", 0x7c0002d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh.w", "d,s,t", 0x7c000458, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"subqh_r.w", "d,s,t", 0x7c0004d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, D33 }, +{"dpax.w.ph", "7,s,t", 0x7c000230, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsx.w.ph", "7,s,t", 0x7c000270, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_s.w.ph", "7,s,t", 0x7c000630, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpaqx_sa.w.ph", "7,s,t", 0x7c0006b0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_s.w.ph", "7,s,t", 0x7c000670, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +{"dpsqx_sa.w.ph", "7,s,t", 0x7c0006f0, 0xfc00e7ff, MOD_a|RD_s|RD_t, 0, D33 }, +/* Move bc0* after mftr and mttr to avoid opcode collision. */ +{"bc0f", "p", 0x41000000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0fl", "p", 0x41020000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, +{"bc0t", "p", 0x41010000, 0xffff0000, CBD|RD_CC, 0, I1 }, +{"bc0tl", "p", 0x41030000, 0xffff0000, CBL|RD_CC, 0, I2|T3 }, }; #define MIPS_NUM_OPCODES \ -- cgit v1.2.3 From 4020f27707e748a2da58de72461dc1befd6bc9c5 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 14:05:41 +0000 Subject: Fix do_socketcall argument, by Daniel Jacobowitz. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2887 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index abefe856b..cf9399756 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -953,7 +953,7 @@ static long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, return ret; } -static long do_socketcall(int num, target_ulong vptr) +static long do_socketcall(int num, target_phys_addr_t vptr) { long ret; const int n = sizeof(target_ulong); -- cgit v1.2.3 From 9b9e4393dd08481530f8d6389ed0ac64405aa4fa Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 17:03:28 +0000 Subject: MIPS64 addressing fixes, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2888 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 16 +++++++++++++ target-mips/op_template.c | 16 +++++++++++++ target-mips/translate.c | 58 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 8f67041ca..f4598fb46 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -976,6 +976,14 @@ void op_save_btarget (void) RETURN(); } +#ifdef TARGET_MIPS64 +void op_save_btarget64 (void) +{ + env->btarget = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; + RETURN(); +} +#endif + /* Conditional branch */ void op_set_bcond (void) { @@ -2409,6 +2417,14 @@ void op_save_pc (void) RETURN(); } +#ifdef TARGET_MIPS64 +void op_save_pc64 (void) +{ + env->PC = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; + RETURN(); +} +#endif + void op_interrupt_restart (void) { if (!(env->CP0_Status & (1 << CP0St_EXL)) && diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 04677cd84..8236acc18 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -68,4 +68,20 @@ SET_RESET(T1, _T1) SET_RESET(T2, _T2) #undef SET_RESET + +#ifdef TARGET_MIPS64 +#define SET64(treg, tregname) \ + void glue(op_set64, tregname)(void) \ + { \ + treg = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; \ + RETURN(); \ + } + +SET64(T0, _T0) +SET64(T1, _T1) +SET64(T2, _T2) + +#undef SET64 + +#endif #endif diff --git a/target-mips/translate.c b/target-mips/translate.c index 4da5b7b85..ffa5c4bc9 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -569,6 +569,18 @@ do { \ } \ } while (0) +#ifdef TARGET_MIPS64 +#define GEN_LOAD_IMM_TN(Tn, Imm) \ +do { \ + if (Imm == 0) { \ + glue(gen_op_reset_, Tn)(); \ + } else if ((int32_t)Imm == Imm) { \ + glue(gen_op_set_, Tn)(Imm); \ + } else { \ + glue(gen_op_set64_, Tn)(((uint64_t)Imm) >> 32, (uint32_t)Imm); \ + } \ +} while (0) +#else #define GEN_LOAD_IMM_TN(Tn, Imm) \ do { \ if (Imm == 0) { \ @@ -577,6 +589,7 @@ do { \ glue(gen_op_set_, Tn)(Imm); \ } \ } while (0) +#endif #define GEN_STORE_TN_REG(Rn, Tn) \ do { \ @@ -595,6 +608,32 @@ do { \ glue(gen_op_store_fpr_, FTn)(Fn); \ } while (0) +static inline void gen_save_pc(target_ulong pc) +{ +#ifdef TARGET_MIPS64 + if (pc == (int32_t)pc) { + gen_op_save_pc(pc); + } else { + gen_op_save_pc64(pc >> 32, (uint32_t)pc); + } +#else + gen_op_save_pc(pc); +#endif +} + +static inline void gen_save_btarget(target_ulong btarget) +{ +#ifdef TARGET_MIPS64 + if (btarget == (int32_t)btarget) { + gen_op_save_btarget(btarget); + } else { + gen_op_save_btarget64(btarget >> 32, (uint32_t)btarget); + } +#else + gen_op_save_btarget(btarget); +#endif +} + static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) { #if defined MIPS_DEBUG_DISAS @@ -604,7 +643,7 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) } #endif if (do_save_pc && ctx->pc != ctx->saved_pc) { - gen_op_save_pc(ctx->pc); + gen_save_pc(ctx->pc); ctx->saved_pc = ctx->pc; } if (ctx->hflags != ctx->saved_hflags) { @@ -621,7 +660,7 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) /* bcond was already saved by the BL insn */ /* fall through */ case MIPS_HFLAG_B: - gen_op_save_btarget(ctx->btarget); + gen_save_btarget(ctx->btarget); break; } } @@ -946,7 +985,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, GEN_LOAD_IMM_TN(T1, uimm); break; case OPC_LUI: - GEN_LOAD_IMM_TN(T0, uimm << 16); + GEN_LOAD_IMM_TN(T0, imm << 16); break; case OPC_SLL: case OPC_SRA: @@ -1491,10 +1530,10 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) gen_op_goto_tb0(TBPARAM(tb)); else gen_op_goto_tb1(TBPARAM(tb)); - gen_op_save_pc(dest); + gen_save_pc(dest); gen_op_set_T0((long)tb + n); } else { - gen_op_save_pc(dest); + gen_save_pc(dest); gen_op_reset_T0(); } gen_op_exit_tb(); @@ -1556,7 +1595,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_J: case OPC_JAL: /* Jump to immediate */ - btarget = ((ctx->pc + 4) & (int32_t)0xF0000000) | offset; + btarget = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset; break; case OPC_JR: case OPC_JALR: @@ -1602,12 +1641,12 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, MIPS_DEBUG("bnever (NOP)"); return; case OPC_BLTZAL: /* 0 < 0 */ - gen_op_set_T0(ctx->pc + 8); + GEN_LOAD_IMM_TN(T0, ctx->pc + 8); gen_op_store_T0_gpr(31); MIPS_DEBUG("bnever and link"); return; case OPC_BLTZALL: /* 0 < 0 likely */ - gen_op_set_T0(ctx->pc + 8); + GEN_LOAD_IMM_TN(T0, ctx->pc + 8); gen_op_store_T0_gpr(31); /* Skip the instruction in the delay slot */ MIPS_DEBUG("bnever, link and skip"); @@ -1732,9 +1771,10 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, } MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx, blink, ctx->hflags, btarget); + ctx->btarget = btarget; if (blink > 0) { - gen_op_set_T0(ctx->pc + 8); + GEN_LOAD_IMM_TN(T0, ctx->pc + 8); gen_op_store_T0_gpr(blink); } } -- cgit v1.2.3 From c811cf2c0314e5154deb073dad07ca3f0e39b16c Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 17:09:41 +0000 Subject: Do not sign extend lwu, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2889 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index f9fc69c8e..602c071c5 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -63,7 +63,7 @@ void glue(op_lw, MEMSUFFIX) (void) void glue(op_lwu, MEMSUFFIX) (void) { - T0 = glue(ldl, MEMSUFFIX)(T0); + T0 = (uint32_t)glue(ldl, MEMSUFFIX)(T0); RETURN(); } -- cgit v1.2.3 From 12a4b2aa1d1aa9626990748544a30fed5af35f54 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 17:36:30 +0000 Subject: Fix ddivu for 32bit hosts, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2890 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9092ffc39..3d99d06fd 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -237,16 +237,16 @@ void do_ddiv (void) } } +#if TARGET_LONG_BITS > HOST_LONG_BITS void do_ddivu (void) { if (T1 != 0) { - /* XXX: lldivu? */ - lldiv_t res = lldiv(T0, T1); - env->LO = (uint64_t)res.quot; - env->HI = (uint64_t)res.rem; + env->LO = T0 / T1; + env->HI = T0 % T1; } } #endif +#endif /* TARGET_MIPS64 */ #if defined(CONFIG_USER_ONLY) void do_mfc0_random (void) -- cgit v1.2.3 From 85aa199ad7755880060d0481dc1c762c372a1799 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 20:07:13 +0000 Subject: Revert last change, this workaround is long obsolete. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2891 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cf9399756..abefe856b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -953,7 +953,7 @@ static long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, return ret; } -static long do_socketcall(int num, target_phys_addr_t vptr) +static long do_socketcall(int num, target_ulong vptr) { long ret; const int n = sizeof(target_ulong); -- cgit v1.2.3 From 6e473128b61901441fa2889dfa2079881895a9f9 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 20:36:48 +0000 Subject: Handle PX/UX status flags correctly, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2892 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 1 + target-mips/helper.c | 3 +++ target-mips/op.c | 18 ++++++++++++++++++ target-mips/translate.c | 33 ++++++++++++++++++++++++++------- 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 9cddc174d..17ac4ac87 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -260,6 +260,7 @@ struct CPUMIPSState { #define MIPS_HFLAG_UM 0x0001 /* user mode */ #define MIPS_HFLAG_DM 0x0008 /* Debug mode */ #define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ +#define MIPS_HFLAG_64 0x0020 /* 64-bit instructions enabled */ #define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ /* If translation is interrupted between the branch instruction and * the delay slot, record what type of branch it is so that we can diff --git a/target-mips/helper.c b/target-mips/helper.c index 2dfaffc23..9da6212a5 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -370,6 +370,7 @@ void do_interrupt (CPUState *env) } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) @@ -395,6 +396,7 @@ void do_interrupt (CPUState *env) env->CP0_ErrorEPC = env->PC; } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -493,6 +495,7 @@ void do_interrupt (CPUState *env) env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; } env->hflags &= ~MIPS_HFLAG_BMASK; diff --git a/target-mips/op.c b/target-mips/op.c index f4598fb46..bc4d51a8f 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1358,6 +1358,12 @@ void op_mtc0_status (void) !(env->hflags & MIPS_HFLAG_DM) && (val & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; +#ifdef TARGET_MIPS64 + if ((env->hflags & MIPS_HFLAG_UM) && + !(val & (1 << CP0St_PX)) && + !(val & (1 << CP0St_UX))) + env->hflags &= ~MIPS_HFLAG_64; +#endif env->CP0_Status = (env->CP0_Status & ~mask) | val; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB2(do_mtc0_status_debug, old, val); @@ -2338,6 +2344,12 @@ void op_eret (void) !(env->hflags & MIPS_HFLAG_DM) && (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; +#ifdef TARGET_MIPS64 + if ((env->hflags & MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_PX)) && + !(env->CP0_Status & (1 << CP0St_UX))) + env->hflags &= ~MIPS_HFLAG_64; +#endif if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; @@ -2355,6 +2367,12 @@ void op_deret (void) !(env->hflags & MIPS_HFLAG_DM) && (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; +#ifdef TARGET_MIPS64 + if ((env->hflags & MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_PX)) && + !(env->CP0_Status & (1 << CP0St_UX))) + env->hflags &= ~MIPS_HFLAG_64; +#endif if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; diff --git a/target-mips/translate.c b/target-mips/translate.c index ffa5c4bc9..c0f2b8122 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -730,9 +730,9 @@ OP_ST_TABLE(dl); OP_ST_TABLE(dr); OP_LD_TABLE(ld); OP_ST_TABLE(cd); +OP_LD_TABLE(wu); #endif OP_LD_TABLE(w); -OP_LD_TABLE(wu); OP_LD_TABLE(wl); OP_LD_TABLE(wr); OP_ST_TABLE(w); @@ -773,6 +773,11 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, */ switch (opc) { #ifdef TARGET_MIPS64 + case OPC_LWU: + op_ldst(lwu); + GEN_STORE_TN_REG(rt, T0); + opn = "lwu"; + break; case OPC_LD: op_ldst(ld); GEN_STORE_TN_REG(rt, T0); @@ -823,11 +828,6 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, GEN_STORE_TN_REG(rt, T0); opn = "lw"; break; - case OPC_LWU: - op_ldst(lwu); - GEN_STORE_TN_REG(rt, T0); - opn = "lwu"; - break; case OPC_SW: GEN_LOAD_REG_TN(T1, rt); op_ldst(sw); @@ -5377,14 +5377,20 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_DSRL ... OPC_DSRA: case OPC_DSLL32: case OPC_DSRL32 ... OPC_DSRA32: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_arith_imm(ctx, op1, rd, rt, sa); break; case OPC_DSLLV: case OPC_DSRLV ... OPC_DSRAV: case OPC_DADD ... OPC_DSUBU: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_arith(ctx, op1, rd, rs, rt); break; case OPC_DMULT ... OPC_DDIVU: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_muldiv(ctx, op1, rs, rt); break; #endif @@ -5420,6 +5426,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; #ifdef TARGET_MIPS64 case OPC_DCLZ ... OPC_DCLO: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_cl(ctx, op1, rd, rs); break; #endif @@ -5491,9 +5499,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) #ifdef TARGET_MIPS64 case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_bitops(ctx, op1, rt, rs, sa, rd); break; case OPC_DBSHFL: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); op2 = MASK_DBSHFL(ctx->opcode); switch (op2) { case OPC_DSBH: @@ -5732,9 +5744,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_LD: case OPC_SCD: case OPC_SD: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_ldst(ctx, op, rt, rs, imm); break; case OPC_DADDI ... OPC_DADDIU: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); gen_arith_imm(ctx, op, rt, rs, imm); break; #endif @@ -6072,11 +6088,14 @@ void cpu_reset (CPUMIPSState *env) /* If the exception was raised from a delay slot, * come back to the jump. */ env->CP0_ErrorEPC = env->PC - 4; - env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_ErrorEPC = env->PC; } +#ifdef TARGET_MIPS64 + env->hflags = MIPS_HFLAG_64; +#else env->hflags = 0; +#endif env->PC = (int32_t)0xBFC00000; env->CP0_Wired = 0; /* SMP not implemented */ -- cgit v1.2.3 From 7b717336e2873fd6d9f178a12549eaa2367d14d0 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 21:01:02 +0000 Subject: SMBus support for MIPS Malta. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2893 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/acpi.c | 5 +---- hw/mips_malta.c | 17 +++++++++++++---- hw/pc.c | 2 +- vl.h | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Makefile.target b/Makefile.target index 45928f3c4..b8abf3e35 100644 --- a/Makefile.target +++ b/Makefile.target @@ -438,7 +438,7 @@ ifeq ($(TARGET_BASE_ARCH), mips) VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o -VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) +VL_OBJS+= piix_pci.o smbus_eeprom.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sparc) diff --git a/hw/acpi.c b/hw/acpi.c index de4002e92..ce3f7f2df 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -24,7 +24,6 @@ #define PM_FREQ 3579545 #define ACPI_DBG_IO_ADDR 0xb044 -#define SMB_IO_BASE 0xb100 typedef struct PIIX4PMState { PCIDevice dev; @@ -451,11 +450,10 @@ static int pm_load(QEMUFile* f,void* opaque,int version_id) return 0; } -i2c_bus *piix4_pm_init(PCIBus *bus, int devfn) +i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base) { PIIX4PMState *s; uint8_t *pci_conf; - uint32_t smb_io_base; s = (PIIX4PMState *)pci_register_device(bus, "PM", sizeof(PIIX4PMState), @@ -486,7 +484,6 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn) pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) | (serial_hds[1] != NULL ? 0x90 : 0); - smb_io_base = SMB_IO_BASE; pci_conf[0x90] = smb_io_base | 1; pci_conf[0x91] = smb_io_base >> 8; pci_conf[0xd2] = 0x09; diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 82ba80952..6339cc941 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -775,6 +775,10 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, int ret; mips_def_t *def; qemu_irq *i8259; + int piix4_devfn; + uint8_t *eeprom_buf; + i2c_bus *smbus; + int i; /* init CPUs */ if (cpu_model == NULL) { @@ -843,10 +847,15 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, pci_bus = pci_gt64120_init(i8259); /* Southbridge */ - piix4_init(pci_bus, 80); - pci_piix3_ide_init(pci_bus, bs_table, 81, i8259); - usb_uhci_init(pci_bus, 82); - piix4_pm_init(pci_bus, 83); + piix4_devfn = piix4_init(pci_bus, 80); + pci_piix3_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259); + usb_uhci_init(pci_bus, piix4_devfn + 2); + smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100); + eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ + for (i = 0; i < 8; i++) { + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); + } pit = pit_init(0x40, i8259[0]); DMA_init(0); diff --git a/hw/pc.c b/hw/pc.c index b91b64fae..1cd5d4cff 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -905,7 +905,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, i2c_bus *smbus; /* TODO: Populate SPD eeprom data. */ - smbus = piix4_pm_init(pci_bus, piix3_devfn + 3); + smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100); for (i = 0; i < 8; i++) { smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); } diff --git a/vl.h b/vl.h index 8fed8374d..21525fdc9 100644 --- a/vl.h +++ b/vl.h @@ -1132,7 +1132,7 @@ int pcspk_audio_init(AudioState *, qemu_irq *pic); /* acpi.c */ extern int acpi_enabled; -i2c_bus *piix4_pm_init(PCIBus *bus, int devfn); +i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base); void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); void acpi_bios_init(void); -- cgit v1.2.3 From 2b8bdefc3a35473e1d43c22e6201aad900dccad2 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 28 May 2007 21:35:23 +0000 Subject: Sync __target_cmsg_nxthdr implementation with kernel header. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2894 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall_defs.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 88f7a217b..a6129d89b 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -176,19 +176,14 @@ struct target_cmsghdr { static __inline__ struct target_cmsghdr * __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg) { - if (tswapl(__cmsg->cmsg_len) < sizeof (struct target_cmsghdr)) - /* The kernel header does this so there may be a reason. */ - return 0; - - __cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg - + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))); - if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) (unsigned long)tswapl(__mhdr->msg_control) - + tswapl(__mhdr->msg_controllen)) - || ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)) - > ((unsigned char *) (unsigned long) tswapl(__mhdr->msg_control) - + tswapl(__mhdr->msg_controllen)))) + struct target_cmsghdr *__ptr; + + __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg + + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))); + if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapl(__mhdr->msg_control)) + > tswapl(__mhdr->msg_controllen)) /* No more entries. */ - return 0; + return (struct target_cmsghdr *)0; return __cmsg; } -- cgit v1.2.3 From acf930aaa3763be08a41f2478b3e0b252f545cd0 Mon Sep 17 00:00:00 2001 From: pbrook Date: Tue, 29 May 2007 14:57:59 +0000 Subject: ColdFire EMAC support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2895 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 +- target-m68k/cpu.h | 19 +++ target-m68k/helper.c | 38 ++++- target-m68k/op.c | 417 ++++++++++++++++++++++++++++++++++++++++++++++++ target-m68k/qregs.def | 2 + target-m68k/translate.c | 286 +++++++++++++++++++++++++++++++++ 6 files changed, 763 insertions(+), 3 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index ea18b73ff..c3d99d418 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -196,7 +196,9 @@ static inline TranslationBlock *tb_find_fast(void) cs_base = 0; pc = env->PC; #elif defined(TARGET_M68K) - flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S); + flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */ + | (env->sr & SR_S) /* Bit 13 */ + | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */ cs_base = 0; pc = env->pc; #elif defined(TARGET_SH4) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index a81b91dff..acbb51690 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -71,6 +71,14 @@ typedef struct CPUM68KState { uint32_t fpsr; float_status fp_status; + uint64_t mactmp; + /* EMAC Hardware deals with 48-bit values composed of one 32-bit and + two 8-bit parts. We store a single 64-bit value and + rearrange/extend this when changing modes. */ + uint64_t macc[4]; + uint32_t macsr; + uint32_t mac_mask; + /* Temporary storage for DIV helpers. */ uint32_t div1; uint32_t div2; @@ -143,11 +151,22 @@ enum { #define SR_S 0x2000 #define SR_T 0x8000 +#define MACSR_PAV0 0x100 +#define MACSR_OMC 0x080 +#define MACSR_SU 0x040 +#define MACSR_FI 0x020 +#define MACSR_RT 0x010 +#define MACSR_N 0x008 +#define MACSR_Z 0x004 +#define MACSR_V 0x002 +#define MACSR_EV 0x001 + typedef struct m68k_def_t m68k_def_t; int cpu_m68k_set_model(CPUM68KState *env, const char * name); void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); +void m68k_set_macsr(CPUM68KState *env, uint32_t val); #define M68K_FPCR_PREC (1 << 6) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 12e3f7867..bdbc1de39 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -69,7 +69,6 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); m68k_set_feature(env, M68K_FEATURE_CF_FPU); - m68k_set_feature(env, M68K_FEATURE_CF_MAC); m68k_set_feature(env, M68K_FEATURE_CF_EMAC); break; case M68K_CPUID_ANY: @@ -77,7 +76,8 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); m68k_set_feature(env, M68K_FEATURE_CF_FPU); - m68k_set_feature(env, M68K_FEATURE_CF_MAC); + /* MAC and EMAC are mututally exclusive, so pick EMAC. + It's mostly backwards compatible. */ m68k_set_feature(env, M68K_FEATURE_CF_EMAC); m68k_set_feature(env, M68K_FEATURE_EXT_FULL); break; @@ -227,6 +227,40 @@ void helper_movec(CPUM68KState *env, int reg, uint32_t val) } } +void m68k_set_macsr(CPUM68KState *env, uint32_t val) +{ + uint32_t acc; + int8_t exthigh; + uint8_t extlow; + uint64_t regval; + int i; + if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { + for (i = 0; i < 4; i++) { + regval = env->macc[i]; + exthigh = regval >> 40; + if (env->macsr & MACSR_FI) { + acc = regval >> 8; + extlow = regval; + } else { + acc = regval; + extlow = regval >> 32; + } + if (env->macsr & MACSR_FI) { + regval = (((uint64_t)acc) << 8) | extlow; + regval |= ((int64_t)exthigh) << 40; + } else if (env->macsr & MACSR_SU) { + regval = acc | (((int64_t)extlow) << 32); + regval |= ((int64_t)exthigh) << 40; + } else { + regval = acc | (((uint64_t)extlow) << 32); + regval |= ((uint64_t)(uint8_t)exthigh) << 40; + } + env->macc[i] = regval; + } + } + env->macsr = val; +} + /* MMU */ /* TODO: This will need fixing once the MMU is implemented. */ diff --git a/target-m68k/op.c b/target-m68k/op.c index d483488be..febfe034c 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -285,6 +285,16 @@ OP(shr_cc) FORCE_RET(); } +OP(sar32) +{ + int32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + uint32_t result; + result = op2 >> op3; + set_op(PARAM1, result); + FORCE_RET(); +} + OP(sar_cc) { int32_t op1 = get_op(PARAM1); @@ -651,3 +661,410 @@ OP(movec) #define MEMSUFFIX _kernel #include "op_mem.h" #endif + +/* MAC unit. */ +/* TODO: The MAC instructions use 64-bit arithmetic fairly extensively. + This results in fairly large ops (and sometimes other issues) on 32-bit + hosts. Maybe move most of them into helpers. */ +OP(macmuls) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + int64_t product; + int64_t res; + + product = (uint64_t)op1 * op2; + res = (product << 24) >> 24; + if (res != product) { + env->macsr |= MACSR_V; + if (env->macsr & MACSR_OMC) { + /* Make sure the accumulate operation overflows. */ + if (product < 0) + res = ~(1ll << 50); + else + res = 1ll << 50; + } + } + env->mactmp = res; + FORCE_RET(); +} + +OP(macmulu) +{ + uint32_t op1 = get_op(PARAM1); + uint32_t op2 = get_op(PARAM2); + uint64_t product; + + product = (uint64_t)op1 * op2; + if (product & (0xffffffull << 40)) { + env->macsr |= MACSR_V; + if (env->macsr & MACSR_OMC) { + /* Make sure the accumulate operation overflows. */ + product = 1ll << 50; + } else { + product &= ((1ull << 40) - 1); + } + } + env->mactmp = product; + FORCE_RET(); +} + +OP(macmulf) +{ + int32_t op1 = get_op(PARAM1); + int32_t op2 = get_op(PARAM2); + uint64_t product; + uint32_t remainder; + + product = (uint64_t)op1 * op2; + if (env->macsr & MACSR_RT) { + remainder = product & 0xffffff; + product >>= 24; + if (remainder > 0x800000) + product++; + else if (remainder == 0x800000) + product += (product & 1); + } else { + product >>= 24; + } + env->mactmp = product; + FORCE_RET(); +} + +OP(macshl) +{ + env->mactmp <<= 1; +} + +OP(macshr) +{ + env->mactmp >>= 1; +} + +OP(macadd) +{ + int acc = PARAM1; + env->macc[acc] += env->mactmp; + FORCE_RET(); +} + +OP(macsub) +{ + int acc = PARAM1; + env->macc[acc] -= env->mactmp; + FORCE_RET(); +} + +OP(macsats) +{ + int acc = PARAM1; + int64_t sum; + int64_t result; + + sum = env->macc[acc]; + result = (sum << 16) >> 16; + if (result != sum) { + env->macsr |= MACSR_V; + } + if (env->macsr & MACSR_V) { + env->macsr |= MACSR_PAV0 << acc; + if (env->macsr & MACSR_OMC) { + /* The result is saturated to 32 bits, despite overflow occuring + at 48 bits. Seems weird, but that's what the hardware docs + say. */ + result = (result >> 63) ^ 0x7fffffff; + } + } + env->macc[acc] = result; + FORCE_RET(); +} + +OP(macsatu) +{ + int acc = PARAM1; + uint64_t sum; + + sum = env->macc[acc]; + if (sum & (0xffffull << 48)) { + env->macsr |= MACSR_V; + } + if (env->macsr & MACSR_V) { + env->macsr |= MACSR_PAV0 << acc; + if (env->macsr & MACSR_OMC) { + if (sum > (1ull << 53)) + sum = 0; + else + sum = (1ull << 48) - 1; + } else { + sum &= ((1ull << 48) - 1); + } + } + FORCE_RET(); +} + +OP(macsatf) +{ + int acc = PARAM1; + int64_t sum; + int64_t result; + + sum = env->macc[acc]; + result = (sum << 16) >> 16; + if (result != sum) { + env->macsr |= MACSR_V; + } + if (env->macsr & MACSR_V) { + env->macsr |= MACSR_PAV0 << acc; + if (env->macsr & MACSR_OMC) { + result = (result >> 63) ^ 0x7fffffffffffll; + } + } + env->macc[acc] = result; + FORCE_RET(); +} + +OP(mac_clear_flags) +{ + env->macsr &= ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV); +} + +OP(mac_set_flags) +{ + int acc = PARAM1; + uint64_t val; + val = env->macc[acc]; + if (val == 0) + env->macsr |= MACSR_Z; + else if (val & (1ull << 47)); + env->macsr |= MACSR_N; + if (env->macsr & (MACSR_PAV0 << acc)) { + env->macsr |= MACSR_V; + } + if (env->macsr & MACSR_FI) { + val = ((int64_t)val) >> 40; + if (val != 0 && val != -1) + env->macsr |= MACSR_EV; + } else if (env->macsr & MACSR_SU) { + val = ((int64_t)val) >> 32; + if (val != 0 && val != -1) + env->macsr |= MACSR_EV; + } else { + if ((val >> 32) != 0) + env->macsr |= MACSR_EV; + } + FORCE_RET(); +} + +OP(get_macf) +{ + int acc = PARAM2; + int64_t val; + int rem; + uint32_t result; + + val = env->macc[acc]; + if (env->macsr & MACSR_SU) { + /* 16-bit rounding. */ + rem = val & 0xffffff; + val = (val >> 24) & 0xffffu; + if (rem > 0x800000) + val++; + else if (rem == 0x800000) + val += (val & 1); + } else if (env->macsr & MACSR_RT) { + /* 32-bit rounding. */ + rem = val & 0xff; + val >>= 8; + if (rem > 0x80) + val++; + else if (rem == 0x80) + val += (val & 1); + } else { + /* No rounding. */ + val >>= 8; + } + if (env->macsr & MACSR_OMC) { + /* Saturate. */ + if (env->macsr & MACSR_SU) { + if (val != (uint16_t) val) { + result = ((val >> 63) ^ 0x7fff) & 0xffff; + } else { + result = val & 0xffff; + } + } else { + if (val != (uint32_t)val) { + result = ((uint32_t)(val >> 63) & 0x7fffffff); + } else { + result = (uint32_t)val; + } + } + } else { + /* No saturation. */ + if (env->macsr & MACSR_SU) { + result = val & 0xffff; + } else { + result = (uint32_t)val; + } + } + set_op(PARAM1, result); + FORCE_RET(); +} + +OP(get_maci) +{ + int acc = PARAM2; + set_op(PARAM1, (uint32_t)env->macc[acc]); + FORCE_RET(); +} + +OP(get_macs) +{ + int acc = PARAM2; + int64_t val = env->macc[acc]; + uint32_t result; + if (val == (int32_t)val) { + result = (int32_t)val; + } else { + result = (val >> 61) ^ 0x7fffffff; + } + set_op(PARAM1, result); + FORCE_RET(); +} + +OP(get_macu) +{ + int acc = PARAM2; + uint64_t val = env->macc[acc]; + uint32_t result; + if ((val >> 32) == 0) { + result = (uint32_t)val; + } else { + result = 0xffffffffu; + } + set_op(PARAM1, result); + FORCE_RET(); +} + +OP(clear_mac) +{ + int acc = PARAM1; + + env->macc[acc] = 0; + env->macsr &= ~(MACSR_PAV0 << acc); + FORCE_RET(); +} + +OP(move_mac) +{ + int dest = PARAM1; + int src = PARAM2; + uint32_t mask; + env->macc[dest] = env->macc[src]; + mask = MACSR_PAV0 << dest; + if (env->macsr & (MACSR_PAV0 << src)) + env->macsr |= mask; + else + env->macsr &= ~mask; + FORCE_RET(); +} + +OP(get_mac_extf) +{ + uint32_t val; + int acc = PARAM2; + val = env->macc[acc] & 0x00ff; + val = (env->macc[acc] >> 32) & 0xff00; + val |= (env->macc[acc + 1] << 16) & 0x00ff0000; + val |= (env->macc[acc + 1] >> 16) & 0xff000000; + set_op(PARAM1, val); + FORCE_RET(); +} + +OP(get_mac_exti) +{ + uint32_t val; + int acc = PARAM2; + val = (env->macc[acc] >> 32) & 0xffff; + val |= (env->macc[acc + 1] >> 16) & 0xffff0000; + set_op(PARAM1, val); + FORCE_RET(); +} + +OP(set_macf) +{ + int acc = PARAM2; + int32_t val = get_op(PARAM1); + env->macc[acc] = ((int64_t)val) << 8; + env->macsr &= ~(MACSR_PAV0 << acc); + FORCE_RET(); +} + +OP(set_macs) +{ + int acc = PARAM2; + int32_t val = get_op(PARAM1); + env->macc[acc] = val; + env->macsr &= ~(MACSR_PAV0 << acc); + FORCE_RET(); +} + +OP(set_macu) +{ + int acc = PARAM2; + uint32_t val = get_op(PARAM1); + env->macc[acc] = val; + env->macsr &= ~(MACSR_PAV0 << acc); + FORCE_RET(); +} + +OP(set_mac_extf) +{ + int acc = PARAM2; + int32_t val = get_op(PARAM1); + int64_t res; + int32_t tmp; + res = env->macc[acc] & 0xffffffff00ull; + tmp = (int16_t)(val & 0xff00); + res |= ((int64_t)tmp) << 32; + res |= val & 0xff; + env->macc[acc] = res; + res = env->macc[acc + 1] & 0xffffffff00ull; + tmp = (val & 0xff000000); + res |= ((int64_t)tmp) << 16; + res |= (val >> 16) & 0xff; + env->macc[acc + 1] = res; +} + +OP(set_mac_exts) +{ + int acc = PARAM2; + int32_t val = get_op(PARAM1); + int64_t res; + int32_t tmp; + res = (uint32_t)env->macc[acc]; + tmp = (int16_t)val; + res |= ((int64_t)tmp) << 32; + env->macc[acc] = res; + res = (uint32_t)env->macc[acc + 1]; + tmp = val & 0xffff0000; + res |= (int64_t)tmp << 16; + env->macc[acc + 1] = res; +} + +OP(set_mac_extu) +{ + int acc = PARAM2; + int32_t val = get_op(PARAM1); + uint64_t res; + res = (uint32_t)env->macc[acc]; + res |= ((uint64_t)(val & 0xffff)) << 32; + env->macc[acc] = res; + res = (uint32_t)env->macc[acc + 1]; + res |= (uint64_t)(val & 0xffff0000) << 16; + env->macc[acc + 1] = res; +} + +OP(set_macsr) +{ + m68k_set_macsr(env, get_op(PARAM1)); +} diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def index 08e7e8515..bf568a514 100644 --- a/target-m68k/qregs.def +++ b/target-m68k/qregs.def @@ -33,3 +33,5 @@ DEFO32(CC_X, cc_x) DEFO32(DIV1, div1) DEFO32(DIV2, div2) DEFO32(EXCEPTION, exception_index) +DEFO32(MACSR, macsr) +DEFO32(MAC_MASK, mac_mask) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 7c9176027..1d32e8f0f 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2433,6 +2433,279 @@ DISAS_INSN(fsave) qemu_assert(0, "FSAVE not implemented"); } +static inline int gen_mac_extract_word(DisasContext *s, int val, int upper) +{ + int tmp = gen_new_qreg(QMODE_I32); + if (s->env->macsr & MACSR_FI) { + if (upper) + gen_op_and32(tmp, val, gen_im32(0xffff0000)); + else + gen_op_shl32(tmp, val, gen_im32(16)); + } else if (s->env->macsr & MACSR_SU) { + if (upper) + gen_op_sar32(tmp, val, gen_im32(16)); + else + gen_op_ext16s32(tmp, val); + } else { + if (upper) + gen_op_shr32(tmp, val, gen_im32(16)); + else + gen_op_ext16u32(tmp, val); + } + return tmp; +} + +DISAS_INSN(mac) +{ + int rx; + int ry; + uint16_t ext; + int acc; + int l1; + int tmp; + int addr; + int loadval; + int dual; + int saved_flags = -1; + + ext = lduw_code(s->pc); + s->pc += 2; + + acc = ((insn >> 7) & 1) | ((ext >> 3) & 2); + dual = ((insn & 0x30) != 0 && (ext & 3) != 0); + if (insn & 0x30) { + /* MAC with load. */ + tmp = gen_lea(s, insn, OS_LONG); + addr = gen_new_qreg(QMODE_I32); + gen_op_and32(addr, tmp, QREG_MAC_MASK); + /* Load the value now to ensure correct exception behavior. + Perform writeback after reading the MAC inputs. */ + loadval = gen_load(s, OS_LONG, addr, 0); + + acc ^= 1; + rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12); + ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0); + } else { + loadval = addr = -1; + rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9); + ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); + } + + gen_op_mac_clear_flags(); + l1 = -1; + if ((s->env->macsr & MACSR_OMC) != 0 && !dual) { + /* Skip the multiply if we know we will ignore it. */ + l1 = gen_new_label(); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_MACSR, gen_im32(1 << (acc + 8))); + gen_op_jmp_nz32(tmp, l1); + } + + if ((ext & 0x0800) == 0) { + /* Word. */ + rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0); + ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0); + } + if (s->env->macsr & MACSR_FI) { + gen_op_macmulf(rx, ry); + } else { + if (s->env->macsr & MACSR_SU) + gen_op_macmuls(rx, ry); + else + gen_op_macmulu(rx, ry); + switch ((ext >> 9) & 3) { + case 1: + gen_op_macshl(); + break; + case 3: + gen_op_macshr(); + break; + } + } + + if (dual) { + /* Save the overflow flag from the multiply. */ + saved_flags = gen_new_qreg(QMODE_I32); + gen_op_mov32(saved_flags, QREG_MACSR); + } + + if ((s->env->macsr & MACSR_OMC) != 0 && dual) { + /* Skip the accumulate if the value is already saturated. */ + l1 = gen_new_label(); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc)); + gen_op_jmp_nz32(tmp, l1); + } + + if (insn & 0x100) + gen_op_macsub(acc); + else + gen_op_macadd(acc); + + if (s->env->macsr & MACSR_FI) + gen_op_macsatf(acc); + else if (s->env->macsr & MACSR_SU) + gen_op_macsats(acc); + else + gen_op_macsatu(acc); + + if (l1 != -1) + gen_set_label(l1); + + if (dual) { + /* Dual accumulate variant. */ + acc = (ext >> 2) & 3; + /* Restore the overflow flag from the multiplier. */ + gen_op_mov32(QREG_MACSR, saved_flags); + if ((s->env->macsr & MACSR_OMC) != 0) { + /* Skip the accumulate if the value is already saturated. */ + l1 = gen_new_label(); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc)); + gen_op_jmp_nz32(tmp, l1); + } + if (ext & 2) + gen_op_macsub(acc); + else + gen_op_macadd(acc); + if (s->env->macsr & MACSR_FI) + gen_op_macsatf(acc); + else if (s->env->macsr & MACSR_SU) + gen_op_macsats(acc); + else + gen_op_macsatu(acc); + if (l1 != -1) + gen_set_label(l1); + } + gen_op_mac_set_flags(acc); + + if (insn & 0x30) { + int rw; + rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9); + gen_op_mov32(rw, loadval); + /* FIXME: Should address writeback happen with the masked or + unmasked value? */ + switch ((insn >> 3) & 7) { + case 3: /* Post-increment. */ + gen_op_add32(AREG(insn, 0), addr, gen_im32(4)); + break; + case 4: /* Pre-decrement. */ + gen_op_mov32(AREG(insn, 0), addr); + } + } +} + +DISAS_INSN(from_mac) +{ + int rx; + int acc; + + rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); + acc = (insn >> 9) & 3; + if (s->env->macsr & MACSR_FI) { + gen_op_get_macf(rx, acc); + } else if ((s->env->macsr & MACSR_OMC) == 0) { + gen_op_get_maci(rx, acc); + } else if (s->env->macsr & MACSR_SU) { + gen_op_get_macs(rx, acc); + } else { + gen_op_get_macu(rx, acc); + } + if (insn & 0x40) + gen_op_clear_mac(acc); +} + +DISAS_INSN(move_mac) +{ + int src; + int dest; + src = insn & 3; + dest = (insn >> 9) & 3; + gen_op_move_mac(dest, src); + gen_op_mac_clear_flags(); + gen_op_mac_set_flags(dest); +} + +DISAS_INSN(from_macsr) +{ + int reg; + + reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); + gen_op_mov32(reg, QREG_MACSR); +} + +DISAS_INSN(from_mask) +{ + int reg; + reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); + gen_op_mov32(reg, QREG_MAC_MASK); +} + +DISAS_INSN(from_mext) +{ + int reg; + int acc; + reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); + acc = (insn & 0x400) ? 2 : 0; + if (s->env->macsr & MACSR_FI) + gen_op_get_mac_extf(reg, acc); + else + gen_op_get_mac_exti(reg, acc); +} + +DISAS_INSN(macsr_to_ccr) +{ + gen_op_mov32(QREG_CC_X, gen_im32(0)); + gen_op_and32(QREG_CC_DEST, QREG_MACSR, gen_im32(0xf)); + s->cc_op = CC_OP_FLAGS; +} + +DISAS_INSN(to_mac) +{ + int acc; + int val; + acc = (insn >>9) & 3; + SRC_EA(val, OS_LONG, 0, NULL); + if (s->env->macsr & MACSR_FI) { + gen_op_set_macf(val, acc); + } else if (s->env->macsr & MACSR_SU) { + gen_op_set_macs(val, acc); + } else { + gen_op_set_macu(val, acc); + } + gen_op_mac_clear_flags(); + gen_op_mac_set_flags(acc); +} + +DISAS_INSN(to_macsr) +{ + int val; + SRC_EA(val, OS_LONG, 0, NULL); + gen_op_set_macsr(val); + gen_lookup_tb(s); +} + +DISAS_INSN(to_mask) +{ + int val; + SRC_EA(val, OS_LONG, 0, NULL); + gen_op_or32(QREG_MAC_MASK, val, gen_im32(0xffff0000)); +} + +DISAS_INSN(to_mext) +{ + int val; + int acc; + SRC_EA(val, OS_LONG, 0, NULL); + acc = (insn & 0x400) ? 2 : 0; + if (s->env->macsr & MACSR_FI) + gen_op_set_mac_extf(val, acc); + else if (s->env->macsr & MACSR_SU) + gen_op_set_mac_exts(val, acc); + else + gen_op_set_mac_extu(val, acc); +} + static disas_proc opcode_table[65536]; static void @@ -2545,7 +2818,20 @@ void register_m68k_insns (CPUM68KState *env) INSN(addsub, 9000, f000, CF_ISA_A); INSN(subx, 9180, f1f8, CF_ISA_A); INSN(suba, 91c0, f1c0, CF_ISA_A); + INSN(undef_mac, a000, f000, CF_ISA_A); + INSN(mac, a000, f100, CF_EMAC); + INSN(from_mac, a180, f9b0, CF_EMAC); + INSN(move_mac, a110, f9fc, CF_EMAC); + INSN(from_macsr,a980, f9f0, CF_EMAC); + INSN(from_mask, ad80, fff0, CF_EMAC); + INSN(from_mext, ab80, fbf0, CF_EMAC); + INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC); + INSN(to_mac, a100, f9c0, CF_EMAC); + INSN(to_macsr, a900, ffc0, CF_EMAC); + INSN(to_mext, ab00, fbc0, CF_EMAC); + INSN(to_mask, ad00, ffc0, CF_EMAC); + INSN(mov3q, a140, f1c0, CF_ISA_B); INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */ INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */ -- cgit v1.2.3 From 5e755519ac9d867f7da13f58a9d0c262db82e14c Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 29 May 2007 16:52:57 +0000 Subject: Don't check the FPU state for each FPU instruction, use hflags to handle this per-tb. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2896 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 8 +- target-mips/fop_template.c | 4 +- target-mips/op.c | 46 +++-------- target-mips/translate.c | 194 +++++++++++++++++++++++++-------------------- 4 files changed, 126 insertions(+), 126 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 17ac4ac87..2736614cd 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -258,9 +258,11 @@ struct CPUMIPSState { #define MIPS_HFLAG_TMASK 0x007F #define MIPS_HFLAG_MODE 0x001F /* execution modes */ #define MIPS_HFLAG_UM 0x0001 /* user mode */ -#define MIPS_HFLAG_DM 0x0008 /* Debug mode */ -#define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ -#define MIPS_HFLAG_64 0x0020 /* 64-bit instructions enabled */ +#define MIPS_HFLAG_DM 0x0002 /* Debug mode */ +#define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */ +#define MIPS_HFLAG_64 0x0008 /* 64-bit instructions enabled */ +#define MIPS_HFLAG_FPU 0x0010 /* FPU enabled */ +#define MIPS_HFLAG_F64 0x0020 /* 64-bit FPU enabled */ #define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ /* If translation is interrupted between the branch instruction and * the delay slot, record what type of branch it is so that we can diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index bb288f11e..0f1595ff8 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -49,7 +49,7 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) #define OP_DLOAD_FREG(treg, tregname, FREG) \ void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ - if (env->CP0_Status & (1 << CP0St_FR)) \ + if (env->hflags & MIPS_HFLAG_F64) \ treg = env->fpr[FREG].fd; \ else \ treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ @@ -60,7 +60,7 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) #define OP_DSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ - if (env->CP0_Status & (1 << CP0St_FR)) \ + if (env->hflags & MIPS_HFLAG_F64) \ env->fpr[FREG].fd = treg; \ else { \ env->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ diff --git a/target-mips/op.c b/target-mips/op.c index bc4d51a8f..a65977af4 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1349,8 +1349,7 @@ void op_mtc0_status (void) uint32_t val, old; uint32_t mask = env->Status_rw_bitmask; - /* No reverse endianness, no MDMX/DSP, no 64bit ops - implemented. */ + /* No reverse endianness, no MDMX/DSP implemented. */ val = T0 & mask; old = env->CP0_Status; if (!(val & (1 << CP0St_EXL)) && @@ -1364,6 +1363,14 @@ void op_mtc0_status (void) !(val & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif + if (val & (1 << CP0St_CU1)) + env->hflags |= MIPS_HFLAG_FPU; + else + env->hflags &= ~MIPS_HFLAG_FPU; + if (val & (1 << CP0St_FR)) + env->hflags |= MIPS_HFLAG_F64; + else + env->hflags &= ~MIPS_HFLAG_F64; env->CP0_Status = (env->CP0_Status & ~mask) | val; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB2(do_mtc0_status_debug, old, val); @@ -1606,41 +1613,6 @@ void op_cp0_enabled(void) RETURN(); } -void op_cp1_enabled(void) -{ - if (!(env->CP0_Status & (1 << CP0St_CU1))) { - CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1); - } - RETURN(); -} - -void op_cp1_64bitmode(void) -{ - if (!(env->CP0_Status & (1 << CP0St_FR))) { - CALL_FROM_TB1(do_raise_exception, EXCP_RI); - } - RETURN(); -} - -/* - * Verify if floating point register is valid; an operation is not defined - * if bit 0 of any register specification is set and the FR bit in the - * Status register equals zero, since the register numbers specify an - * even-odd pair of adjacent coprocessor general registers. When the FR bit - * in the Status register equals one, both even and odd register numbers - * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. - * - * Multiple 64 bit wide registers can be checked by calling - * gen_op_cp1_registers(freg1 | freg2 | ... | fregN); - */ -void op_cp1_registers(void) -{ - if (!(env->CP0_Status & (1 << CP0St_FR)) && (PARAM1 & 1)) { - CALL_FROM_TB1(do_raise_exception, EXCP_RI); - } - RETURN(); -} - void op_cfc1 (void) { switch (T1) { diff --git a/target-mips/translate.c b/target-mips/translate.c index c0f2b8122..e092439cf 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -703,6 +703,35 @@ static inline void generate_exception (DisasContext *ctx, int excp) generate_exception_err (ctx, excp, 0); } +static inline void check_cp1_enabled(DisasContext *ctx) +{ + if (!(ctx->hflags & MIPS_HFLAG_FPU)) + generate_exception_err(ctx, EXCP_CpU, 1); +} + +static inline void check_cp1_64bitmode(DisasContext *ctx) +{ + if (!(ctx->hflags & MIPS_HFLAG_F64)) + generate_exception(ctx, EXCP_RI); +} + +/* + * Verify if floating point register is valid; an operation is not defined + * if bit 0 of any register specification is set and the FR bit in the + * Status register equals zero, since the register numbers specify an + * even-odd pair of adjacent coprocessor general registers. When the FR bit + * in the Status register equals one, both even and odd register numbers + * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. + * + * Multiple 64 bit wide registers can be checked by calling + * gen_op_cp1_registers(freg1 | freg2 | ... | fregN); + */ +void check_cp1_registers(DisasContext *ctx, int regs) +{ + if (!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1)) + generate_exception(ctx, EXCP_RI); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -4243,8 +4272,8 @@ GEN_MOVCF(s); GEN_MOVCF(ps); #undef GEN_MOVCF -static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, - int fs, int fd, int cc) +static void gen_farith (DisasContext *ctx, uint32_t op1, + int ft, int fs, int fd, int cc) { const char *opn = "farith"; const char *condnames[] = { @@ -4344,28 +4373,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "neg.s"; break; case FOP(8, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_roundl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.s"; break; case FOP(9, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_truncl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.s"; break; case FOP(10, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_ceill_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.s"; break; case FOP(11, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_floorl_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4432,7 +4461,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "rsqrt.s"; break; case FOP(28, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT2, fd); gen_op_float_recip2_s(); @@ -4440,21 +4469,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "recip2.s"; break; case FOP(29, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_recip1_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "recip1.s"; break; case FOP(30, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_rsqrt1_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "rsqrt1.s"; break; case FOP(31, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT2, fd); gen_op_float_rsqrt2_s(); @@ -4462,7 +4491,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "rsqrt2.s"; break; case FOP(33, 16): - gen_op_cp1_registers(fd); + check_cp1_registers(ctx, fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4475,14 +4504,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.w.s"; break; case FOP(37, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.l.s"; break; case FOP(38, 16): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT1, fs); GEN_LOAD_FREG_FTN(WT0, ft); gen_op_float_cvtps_s(); @@ -4508,7 +4537,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); if (ctx->opcode & (1 << 6)) { - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); gen_cmpabs_s(func-48, cc); opn = condnames_abs[func-48]; } else { @@ -4517,7 +4546,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, } break; case FOP(0, 17): - gen_op_cp1_registers(fs | ft | fd); + check_cp1_registers(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_add_d(); @@ -4526,7 +4555,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(1, 17): - gen_op_cp1_registers(fs | ft | fd); + check_cp1_registers(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_sub_d(); @@ -4535,7 +4564,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(2, 17): - gen_op_cp1_registers(fs | ft | fd); + check_cp1_registers(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_mul_d(); @@ -4544,7 +4573,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(3, 17): - gen_op_cp1_registers(fs | ft | fd); + check_cp1_registers(ctx, fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_div_d(); @@ -4553,84 +4582,84 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(4, 17): - gen_op_cp1_registers(fs | fd); + check_cp1_registers(ctx, fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_sqrt_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "sqrt.d"; break; case FOP(5, 17): - gen_op_cp1_registers(fs | fd); + check_cp1_registers(ctx, fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_abs_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "abs.d"; break; case FOP(6, 17): - gen_op_cp1_registers(fs | fd); + check_cp1_registers(ctx, fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_mov_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "mov.d"; break; case FOP(7, 17): - gen_op_cp1_registers(fs | fd); + check_cp1_registers(ctx, fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_chs_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "neg.d"; break; case FOP(8, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.d"; break; case FOP(9, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.d"; break; case FOP(10, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceill_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.d"; break; case FOP(11, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "floor.l.d"; break; case FOP(12, 17): - gen_op_cp1_registers(fs); + check_cp1_registers(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "round.w.d"; break; case FOP(13, 17): - gen_op_cp1_registers(fs); + check_cp1_registers(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "trunc.w.d"; break; case FOP(14, 17): - gen_op_cp1_registers(fs); + check_cp1_registers(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceilw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "ceil.w.d"; break; case FOP(15, 17): - gen_op_cp1_registers(fs); + check_cp1_registers(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorw_d(); GEN_STORE_FTN_FREG(fd, WT2); @@ -4661,21 +4690,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.d"; break; case FOP(21, 17): - gen_op_cp1_registers(fs | fd); + check_cp1_registers(ctx, fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_recip_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "recip.d"; break; case FOP(22, 17): - gen_op_cp1_registers(fs | fd); + check_cp1_registers(ctx, fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_rsqrt_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "rsqrt.d"; break; case FOP(28, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT2, ft); gen_op_float_recip2_d(); @@ -4683,21 +4712,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "recip2.d"; break; case FOP(29, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_recip1_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "recip1.d"; break; case FOP(30, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_rsqrt1_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "rsqrt1.d"; break; case FOP(31, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT2, ft); gen_op_float_rsqrt2_d(); @@ -4723,31 +4752,31 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); if (ctx->opcode & (1 << 6)) { - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); gen_cmpabs_d(func-48, cc); opn = condnames_abs[func-48]; } else { - gen_op_cp1_registers(fs | ft); + check_cp1_registers(ctx, fs | ft); gen_cmp_d(func-48, cc); opn = condnames[func-48]; } break; case FOP(32, 17): - gen_op_cp1_registers(fs); + check_cp1_registers(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.d"; break; case FOP(36, 17): - gen_op_cp1_registers(fs); + check_cp1_registers(ctx, fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.w.d"; break; case FOP(37, 17): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtl_d(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4760,21 +4789,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.s.w"; break; case FOP(33, 20): - gen_op_cp1_registers(fd); + check_cp1_registers(ctx, fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_w(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.d.w"; break; case FOP(32, 21): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_l(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.l"; break; case FOP(33, 21): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtd_l(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4782,7 +4811,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, break; case FOP(38, 20): case FOP(38, 21): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtps_pw(); @@ -4791,7 +4820,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.ps.pw"; break; case FOP(0, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4802,7 +4831,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "add.ps"; break; case FOP(1, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4813,7 +4842,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "sub.ps"; break; case FOP(2, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4824,7 +4853,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mul.ps"; break; case FOP(5, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_abs_ps(); @@ -4833,7 +4862,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "abs.ps"; break; case FOP(6, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_mov_ps(); @@ -4842,7 +4871,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mov.ps"; break; case FOP(7, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_chs_ps(); @@ -4851,7 +4880,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "neg.ps"; break; case FOP(17, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); @@ -4863,7 +4892,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movcf.ps"; break; case FOP(18, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); @@ -4875,7 +4904,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movz.ps"; break; case FOP(19, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_REG_TN(T0, ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); @@ -4887,7 +4916,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.ps"; break; case FOP(24, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, ft); GEN_LOAD_FREG_FTN(WTH0, ft); GEN_LOAD_FREG_FTN(WT1, fs); @@ -4898,7 +4927,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "addr.ps"; break; case FOP(26, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, ft); GEN_LOAD_FREG_FTN(WTH0, ft); GEN_LOAD_FREG_FTN(WT1, fs); @@ -4909,7 +4938,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mulr.ps"; break; case FOP(28, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT2, fd); @@ -4920,7 +4949,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "recip2.ps"; break; case FOP(29, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_recip1_ps(); @@ -4929,7 +4958,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "recip1.ps"; break; case FOP(30, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_rsqrt1_ps(); @@ -4938,7 +4967,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "rsqrt1.ps"; break; case FOP(31, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT2, fd); @@ -4949,14 +4978,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "rsqrt2.ps"; break; case FOP(32, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvts_pu(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pu"; break; case FOP(36, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtpw_ps(); @@ -4965,14 +4994,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.pw.ps"; break; case FOP(40, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvts_pl(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pl"; break; case FOP(44, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pll_ps(); @@ -4980,7 +5009,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pll.ps"; break; case FOP(45, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_plu_ps(); @@ -4988,7 +5017,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "plu.ps"; break; case FOP(46, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pul_ps(); @@ -4996,7 +5025,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pul.ps"; break; case FOP(47, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_puu_ps(); @@ -5019,7 +5048,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 22): case FOP(62, 22): case FOP(63, 22): - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5051,14 +5080,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, } /* Coprocessor 3 (FPU) */ -static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, - int fs, int base, int index) +static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, + int fd, int fs, int base, int index) { const char *opn = "extended float load/store"; int store = 0; /* All of those work only on 64bit FPUs. */ - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); if (base == 0) { if (index == 0) gen_op_reset_T0(); @@ -5117,13 +5146,13 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd, regnames[index], regnames[base]); } -static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, - int fr, int fs, int ft) +static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + int fd, int fr, int fs, int ft) { const char *opn = "flt3_arith"; /* All of those work only on 64bit FPUs. */ - gen_op_cp1_64bitmode(); + check_cp1_64bitmode(ctx); switch (opc) { case OPC_ALNV_PS: GEN_LOAD_REG_TN(T0, fr); @@ -5363,7 +5392,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_MOVCI: if (env->CP0_Config1 & (1 << CP0C1_FP)) { save_cpu_state(ctx, 1); - gen_op_cp1_enabled(); + check_cp1_enabled(ctx); gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, (ctx->opcode >> 16) & 1); } else { @@ -5634,7 +5663,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_SDC1: if (env->CP0_Config1 & (1 << CP0C1_FP)) { save_cpu_state(ctx, 1); - gen_op_cp1_enabled(); + check_cp1_enabled(ctx); gen_flt_ldst(ctx, op, rt, rs, imm); } else { generate_exception_err(ctx, EXCP_CpU, 1); @@ -5644,7 +5673,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_CP1: if (env->CP0_Config1 & (1 << CP0C1_FP)) { save_cpu_state(ctx, 1); - gen_op_cp1_enabled(); + check_cp1_enabled(ctx); op1 = MASK_CP1(ctx->opcode); switch (op1) { case OPC_MFC1: @@ -5696,7 +5725,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_CP3: if (env->CP0_Config1 & (1 << CP0C1_FP)) { save_cpu_state(ctx, 1); - gen_op_cp1_enabled(); + check_cp1_enabled(ctx); op1 = MASK_CP3(ctx->opcode); switch (op1) { case OPC_LWXC1: @@ -5960,7 +5989,7 @@ void fpu_dump_state(CPUState *env, FILE *f, int flags) { int i; - int is_fpu64 = !!(env->CP0_Status & (1 << CP0St_FR)); + int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); #define printfpr(fp) \ do { \ @@ -6038,7 +6067,6 @@ void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { - uint32_t c0_status; int i; cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", @@ -6051,13 +6079,11 @@ void cpu_dump_state (CPUState *env, FILE *f, cpu_fprintf(f, "\n"); } - c0_status = env->CP0_Status; - cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", - c0_status, env->CP0_Cause, env->CP0_EPC); + env->CP0_Status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n", env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); - if (c0_status & (1 << CP0St_CU1)) + if (env->hflags & MIPS_HFLAG_FPU) fpu_dump_state(env, f, cpu_fprintf, flags); #if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags); -- cgit v1.2.3 From 78749ba859684748366b5de630ad41bd1b2d60a2 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 29 May 2007 18:55:34 +0000 Subject: Fix usermode check, thanks Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2897 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 2736614cd..36c58ec1e 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -256,7 +256,7 @@ struct CPUMIPSState { uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ #define MIPS_HFLAG_TMASK 0x007F -#define MIPS_HFLAG_MODE 0x001F /* execution modes */ +#define MIPS_HFLAG_MODE 0x0007 /* execution modes */ #define MIPS_HFLAG_UM 0x0001 /* user mode */ #define MIPS_HFLAG_DM 0x0002 /* Debug mode */ #define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */ -- cgit v1.2.3 From 49e9fba27138adb4ca52385f6ecc63b0ff0d3546 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 30 May 2007 17:25:06 +0000 Subject: Fix the bug introduced by subpage code preventing PC boot git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2898 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exec.c b/exec.c index 321d8a566..61d8f61ab 100644 --- a/exec.c +++ b/exec.c @@ -1922,7 +1922,7 @@ static void *subpage_init (target_phys_addr_t base, uint32_t *phys, need_subpage = 1; \ } \ \ - if (end_addr - addr > TARGET_PAGE_SIZE) \ + if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \ end_addr2 = TARGET_PAGE_SIZE - 1; \ else { \ end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \ @@ -1944,9 +1944,9 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long orig_size = size; void *subpage; - end_addr = start_addr + (target_phys_addr_t)size; size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; - for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { + end_addr = start_addr + (target_phys_addr_t)size; + for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { p = phys_page_find(addr >> TARGET_PAGE_BITS); if (p && p->phys_offset != IO_MEM_UNASSIGNED) { unsigned long orig_memory = p->phys_offset; -- cgit v1.2.3 From fdf41d225e8c90f2822b4c706552e005837218a5 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 30 May 2007 18:54:40 +0000 Subject: Replace target_ulong with target_phys_addr_t git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2899 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apb_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 627fd9bc0..38c56a2d4 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -206,13 +206,13 @@ static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level) qemu_set_irq(pic[irq_num], level); } -PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, +PCIBus *pci_apb_init(target_phys_addr_t special_base, + target_phys_addr_t mem_base, qemu_irq *pic) { APBState *s; PCIDevice *d; int pci_mem_config, pci_mem_data, apb_config, pci_ioport; - PCIDevice *apb; PCIBus *secondary; s = qemu_mallocz(sizeof(APBState)); -- cgit v1.2.3 From 51b2772f28f51b04e10e6e51f411f7246e1159d9 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 30 May 2007 20:46:02 +0000 Subject: Fix CPU (re-)selection on reset. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2900 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 1 + hw/mips_pica61.c | 1 + hw/mips_r4k.c | 1 + target-mips/cpu.h | 5 ++++- target-mips/translate_init.c | 8 +++++--- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 6339cc941..f775c2f58 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -748,6 +748,7 @@ static void main_cpu_reset(void *opaque) { CPUState *env = opaque; cpu_reset(env); + cpu_mips_register(env, NULL); /* The bootload does not need to be rewritten as it is located in a read only location. The kernel location and the arguments table diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 40ea8b5a6..5bb340535 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -51,6 +51,7 @@ static void main_cpu_reset(void *opaque) { CPUState *env = opaque; cpu_reset(env); + cpu_mips_register(env, NULL); } static diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index d600dbbb0..2208922a7 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -128,6 +128,7 @@ static void main_cpu_reset(void *opaque) { CPUState *env = opaque; cpu_reset(env); + cpu_mips_register(env, NULL); if (env->kernel_filename) load_kernel (env, env->ram_size, env->kernel_filename, diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 36c58ec1e..9fa0ca8c6 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -48,6 +48,8 @@ struct r4k_tlb_t { target_ulong PFN[2]; }; +typedef struct mips_def_t mips_def_t; + typedef struct CPUMIPSState CPUMIPSState; struct CPUMIPSState { /* General integer registers */ @@ -295,6 +297,8 @@ struct CPUMIPSState { const char *kernel_cmdline; const char *initrd_filename; + mips_def_t *cpu_model; + struct QEMUTimer *timer; /* Internal timer */ }; @@ -308,7 +312,6 @@ void r4k_do_tlbwi (void); void r4k_do_tlbwr (void); void r4k_do_tlbp (void); void r4k_do_tlbr (void); -typedef struct mips_def_t mips_def_t; int mips_find_by_name (const unsigned char *name, mips_def_t **def); void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); int cpu_mips_register (CPUMIPSState *env, mips_def_t *def); diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 7d60f19b2..e14b7348c 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -206,13 +206,15 @@ static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def) int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) { + if (!def) + def = env->cpu_model; if (!def) cpu_abort(env, "Unable to find MIPS CPU definition\n"); + env->cpu_model = def; env->CP0_PRid = def->CP0_PRid; -#ifdef TARGET_WORDS_BIGENDIAN - env->CP0_Config0 = def->CP0_Config0 | (1 << CP0C0_BE); -#else env->CP0_Config0 = def->CP0_Config0; +#ifdef TARGET_WORDS_BIGENDIAN + env->CP0_Config0 |= (1 << CP0C0_BE); #endif env->CP0_Config1 = def->CP0_Config1; env->CP0_Config2 = def->CP0_Config2; -- cgit v1.2.3 From 471ea271435cb87a158fc473fb1cd7a45d2fc4d3 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 30 May 2007 21:30:06 +0000 Subject: Fix typo in comment. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2901 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index f775c2f58..359238d2b 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -558,9 +558,9 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t p = (uint32_t *) (phys_ram_base + bios_offset + 0x580); stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */ stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */ - stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, a0, low(ENVP_ADDR) */ + stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */ stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ - stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */ + stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */ stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */ -- cgit v1.2.3 From 924b2c07cdfaba9ac408fc5fa77da75a570f9dc5 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 31 May 2007 16:17:52 +0000 Subject: Add proper float*_is_nan prototypes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2902 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat.h | 5 ++++- target-mips/op_helper.c | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 21100c0d0..f344d2ea5 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -242,8 +242,8 @@ int float32_le_quiet( float32, float32 STATUS_PARAM ); int float32_lt_quiet( float32, float32 STATUS_PARAM ); int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); +int float32_is_nan( float32 ); int float32_is_signaling_nan( float32 ); -int float64_is_nan( float64 a ); INLINE float32 float32_abs(float32 a) { @@ -293,6 +293,7 @@ int float64_le_quiet( float64, float64 STATUS_PARAM ); int float64_lt_quiet( float64, float64 STATUS_PARAM ); int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); +int float64_is_nan( float64 a ); int float64_is_signaling_nan( float64 ); INLINE float64 float64_abs(float64 a) @@ -336,6 +337,7 @@ int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_nan( floatx80 ); int floatx80_is_signaling_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) @@ -383,6 +385,7 @@ int float128_lt( float128, float128 STATUS_PARAM ); int float128_eq_signaling( float128, float128 STATUS_PARAM ); int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_is_nan( float128 ); int float128_is_signaling_nan( float128 ); INLINE float128 float128_abs(float128 a) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 3d99d06fd..da2864597 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1147,7 +1147,6 @@ void do_cmpabs_s_ ## op (long cc) \ flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) { - extern flag float32_is_nan(float32 a); if (float32_is_signaling_nan(a) || float32_is_signaling_nan(b) || (sig && (float32_is_nan(a) || float32_is_nan(b)))) { -- cgit v1.2.3 From 33ac7f1630d8655b92b6a53d59886fca2b64da10 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 31 May 2007 16:18:58 +0000 Subject: Don't kill the registered irqs on reset. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2903 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 9fa0ca8c6..6dff8ef55 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -284,10 +284,8 @@ struct CPUMIPSState { int CCRes; /* Cycle count resolution/divisor */ int Status_rw_bitmask; /* Read/write bits in CP0_Status */ -#if defined(CONFIG_USER_ONLY) +#ifdef CONFIG_USER_ONLY target_ulong tls_value; -#else - void *irq[8]; #endif CPU_COMMON @@ -298,6 +296,9 @@ struct CPUMIPSState { const char *initrd_filename; mips_def_t *cpu_model; +#ifndef CONFIG_USER_ONLY + void *irq[8]; +#endif struct QEMUTimer *timer; /* Internal timer */ }; -- cgit v1.2.3 From 278d070272537a8ff1a3052cea0b20a66d8a8e95 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 31 May 2007 23:42:46 +0000 Subject: Simplify code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2904 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index e092439cf..08b760ba7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5843,7 +5843,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) { - DisasContext ctx, *ctxp = &ctx; + DisasContext ctx; target_ulong pc_start; uint16_t *gen_opc_end; int j, lj = -1; @@ -5884,7 +5884,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == ctx.pc) { - save_cpu_state(ctxp, 1); + save_cpu_state(&ctx, 1); ctx.bstate = BS_BRANCH; gen_op_debug(); goto done_generating; @@ -5918,7 +5918,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #endif } if (env->singlestep_enabled) { - save_cpu_state(ctxp, ctx.bstate == BS_NONE); + save_cpu_state(&ctx, ctx.bstate == BS_NONE); gen_op_debug(); } else { switch (ctx.bstate) { @@ -5927,7 +5927,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_NONE: - save_cpu_state(ctxp, 0); + save_cpu_state(&ctx, 0); gen_goto_tb(&ctx, 0, ctx.pc); break; case BS_EXCP: -- cgit v1.2.3 From a7037b2950629ab1a305a7f5c6909e749d72b5d0 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 11:47:24 +0000 Subject: Allow again FPU for usermode emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2905 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index e14b7348c..ac62fad60 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -225,7 +225,12 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CCRes = def->CCRes; env->Status_rw_bitmask = def->Status_rw_bitmask; env->fcr0 = def->CP1_fcr0; -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY + if (env->CP0_Config1 & (1 << CP0C1_FP)) + env->hflags |= MIPS_HFLAG_FPU; + if (env->fcr0 & (1 << FCR0_F64)) + env->hflags |= MIPS_HFLAG_F64; +#else switch ((env->CP0_Config0 >> CP0C0_MT) & 3) { case 0: no_mmu_init(env, def); -- cgit v1.2.3 From e35846583b6aaa4ac7f6ac90139d0952f2dee2d8 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 11:49:38 +0000 Subject: Fix struct stat mapping for MIPS, by Stuart Anderson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2906 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index abefe856b..c80f329c2 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3108,9 +3108,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, do_stat: if (!is_error(ret)) { struct target_stat *target_st; - + lock_user_struct(target_st, arg2, 0); +#if defined(TARGET_MIPS) + target_st->st_dev = tswap32(st.st_dev); +#else target_st->st_dev = tswap16(st.st_dev); +#endif target_st->st_ino = tswapl(st.st_ino); #if defined(TARGET_PPC) || defined(TARGET_MIPS) target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */ @@ -3121,8 +3125,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, target_st->st_uid = tswap16(st.st_uid); target_st->st_gid = tswap16(st.st_gid); #endif +#if defined(TARGET_MIPS) + /* If this is the same on PPC, then just merge w/ the above ifdef */ + target_st->st_nlink = tswapl(st.st_nlink); + target_st->st_rdev = tswapl(st.st_rdev); +#else target_st->st_nlink = tswap16(st.st_nlink); target_st->st_rdev = tswap16(st.st_rdev); +#endif target_st->st_size = tswapl(st.st_size); target_st->st_blksize = tswapl(st.st_blksize); target_st->st_blocks = tswapl(st.st_blocks); -- cgit v1.2.3 From c12ab05ca5b8d214c880872f23cc4bc155183c25 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 11:50:36 +0000 Subject: Patch for pipe() result handling, by Stuart Anderson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2907 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c80f329c2..64cd5da21 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2338,8 +2338,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, int host_pipe[2]; ret = get_errno(pipe(host_pipe)); if (!is_error(ret)) { +#if defined(TARGET_MIPS) + ((CPUMIPSState*)cpu_env)->gpr[3] = host_pipe[1]; + ret = host_pipe[0]; +#else tput32(arg1, host_pipe[0]); tput32(arg1 + 4, host_pipe[1]); +#endif } } break; -- cgit v1.2.3 From 637947f19dd2d72a0ecb2dfd6c946b8ffeabe765 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 12:09:19 +0000 Subject: linux-user errno mapping, by Stuart Anderson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2908 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/errno_defs.h | 142 ++++++++++++++++++++++++++++++++ linux-user/mips/syscall.h | 203 ++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 109 ++++++++++++++++++++++++- linux-user/syscall_defs.h | 2 + 4 files changed, 455 insertions(+), 1 deletion(-) create mode 100644 linux-user/errno_defs.h diff --git a/linux-user/errno_defs.h b/linux-user/errno_defs.h new file mode 100644 index 000000000..209c1870f --- /dev/null +++ b/linux-user/errno_defs.h @@ -0,0 +1,142 @@ +/* + * Target definitions of errnos. These may be overridden by an + * architecture specific header if needed. + * + * Taken from asm-generic/errno-base.h and asm-generic/errno.h + */ +#define TARGET_EPERM 1 /* Operation not permitted */ +#define TARGET_ENOENT 2 /* No such file or directory */ +#define TARGET_ESRCH 3 /* No such process */ +#define TARGET_EINTR 4 /* Interrupted system call */ +#define TARGET_EIO 5 /* I/O error */ +#define TARGET_ENXIO 6 /* No such device or address */ +#define TARGET_E2BIG 7 /* Argument list too long */ +#define TARGET_ENOEXEC 8 /* TARGET_Exec format error */ +#define TARGET_EBADF 9 /* Bad file number */ +#define TARGET_ECHILD 10 /* No child processes */ +#define TARGET_EAGAIN 11 /* Try again */ +#define TARGET_ENOMEM 12 /* Out of memory */ +#define TARGET_EACCES 13 /* Permission denied */ +#define TARGET_EFAULT 14 /* Bad address */ +#define TARGET_ENOTBLK 15 /* Block device required */ +#define TARGET_EBUSY 16 /* Device or resource busy */ +#define TARGET_EEXIST 17 /* File exists */ +#define TARGET_EXDEV 18 /* Cross-device link */ +#define TARGET_ENODEV 19 /* No such device */ +#define TARGET_ENOTDIR 20 /* Not a directory */ +#define TARGET_EISDIR 21 /* Is a directory */ +#define TARGET_EINVAL 22 /* Invalid argument */ +#define TARGET_ENFILE 23 /* File table overflow */ +#define TARGET_EMFILE 24 /* Too many open files */ +#define TARGET_ENOTTY 25 /* Not a typewriter */ +#define TARGET_ETXTBSY 26 /* Text file busy */ +#define TARGET_EFBIG 27 /* File too large */ +#define TARGET_ENOSPC 28 /* No space left on device */ +#define TARGET_ESPIPE 29 /* Illegal seek */ +#define TARGET_EROFS 30 /* Read-only file system */ +#define TARGET_EMLINK 31 /* Too many links */ +#define TARGET_EPIPE 32 /* Broken pipe */ +#define TARGET_EDOM 33 /* Math argument out of domain of func */ +#define TARGET_ERANGE 34 /* Math result not representable */ + +#define TARGET_EDEADLK 35 /* Resource deadlock would occur */ +#define TARGET_ENAMETOOLONG 36 /* File name too long */ +#define TARGET_ENOLCK 37 /* No record locks available */ +#define TARGET_ENOSYS 38 /* Function not implemented */ +#define TARGET_ENOTEMPTY 39 /* Directory not empty */ +#define TARGET_ELOOP 40 /* Too many symbolic links encountered */ + +#define TARGET_ENOMSG 42 /* No message of desired type */ +#define TARGET_EIDRM 43 /* Identifier removed */ +#define TARGET_ECHRNG 44 /* Channel number out of range */ +#define TARGET_EL2NSYNC 45 /* Level 2 not synchronized */ +#define TARGET_EL3HLT 46 /* Level 3 halted */ +#define TARGET_EL3RST 47 /* Level 3 reset */ +#define TARGET_ELNRNG 48 /* Link number out of range */ +#define TARGET_EUNATCH 49 /* Protocol driver not attached */ +#define TARGET_ENOCSI 50 /* No CSI structure available */ +#define TARGET_EL2HLT 51 /* Level 2 halted */ +#define TARGET_EBADE 52 /* Invalid exchange */ +#define TARGET_EBADR 53 /* Invalid request descriptor */ +#define TARGET_EXFULL 54 /* TARGET_Exchange full */ +#define TARGET_ENOANO 55 /* No anode */ +#define TARGET_EBADRQC 56 /* Invalid request code */ +#define TARGET_EBADSLT 57 /* Invalid slot */ + +#define TARGET_EBFONT 59 /* Bad font file format */ +#define TARGET_ENOSTR 60 /* Device not a stream */ +#define TARGET_ENODATA 61 /* No data available */ +#define TARGET_ETIME 62 /* Timer expired */ +#define TARGET_ENOSR 63 /* Out of streams resources */ +#define TARGET_ENONET 64 /* Machine is not on the network */ +#define TARGET_ENOPKG 65 /* Package not installed */ +#define TARGET_EREMOTE 66 /* Object is remote */ +#define TARGET_ENOLINK 67 /* Link has been severed */ +#define TARGET_EADV 68 /* Advertise error */ +#define TARGET_ESRMNT 69 /* Srmount error */ +#define TARGET_ECOMM 70 /* Communication error on send */ +#define TARGET_EPROTO 71 /* Protocol error */ +#define TARGET_EMULTIHOP 72 /* Multihop attempted */ +#define TARGET_EDOTDOT 73 /* RFS specific error */ +#define TARGET_EBADMSG 74 /* Not a data message */ +#define TARGET_EOVERFLOW 75 /* Value too large for defined data type */ +#define TARGET_ENOTUNIQ 76 /* Name not unique on network */ +#define TARGET_EBADFD 77 /* File descriptor in bad state */ +#define TARGET_EREMCHG 78 /* Remote address changed */ +#define TARGET_ELIBACC 79 /* Can not access a needed shared library */ +#define TARGET_ELIBBAD 80 /* Accessing a corrupted shared library */ +#define TARGET_ELIBSCN 81 /* .lib section in a.out corrupted */ +#define TARGET_ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define TARGET_ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define TARGET_EILSEQ 84 /* Illegal byte sequence */ +#define TARGET_ERESTART 85 /* Interrupted system call should be restarted */ +#define TARGET_ESTRPIPE 86 /* Streams pipe error */ +#define TARGET_EUSERS 87 /* Too many users */ +#define TARGET_ENOTSOCK 88 /* Socket operation on non-socket */ +#define TARGET_EDESTADDRREQ 89 /* Destination address required */ +#define TARGET_EMSGSIZE 90 /* Message too long */ +#define TARGET_EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define TARGET_ENOPROTOOPT 92 /* Protocol not available */ +#define TARGET_EPROTONOSUPPORT 93 /* Protocol not supported */ +#define TARGET_ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define TARGET_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define TARGET_EPFNOSUPPORT 96 /* Protocol family not supported */ +#define TARGET_EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define TARGET_EADDRINUSE 98 /* Address already in use */ +#define TARGET_EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define TARGET_ENETDOWN 100 /* Network is down */ +#define TARGET_ENETUNREACH 101 /* Network is unreachable */ +#define TARGET_ENETRESET 102 /* Network dropped connection because of reset */ +#define TARGET_ECONNABORTED 103 /* Software caused connection abort */ +#define TARGET_ECONNRESET 104 /* Connection reset by peer */ +#define TARGET_ENOBUFS 105 /* No buffer space available */ +#define TARGET_EISCONN 106 /* Transport endpoint is already connected */ +#define TARGET_ENOTCONN 107 /* Transport endpoint is not connected */ +#define TARGET_ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define TARGET_ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define TARGET_ETIMEDOUT 110 /* Connection timed out */ +#define TARGET_ECONNREFUSED 111 /* Connection refused */ +#define TARGET_EHOSTDOWN 112 /* Host is down */ +#define TARGET_EHOSTUNREACH 113 /* No route to host */ +#define TARGET_EALREADY 114 /* Operation already in progress */ +#define TARGET_EINPROGRESS 115 /* Operation now in progress */ +#define TARGET_ESTALE 116 /* Stale NFS file handle */ +#define TARGET_EUCLEAN 117 /* Structure needs cleaning */ +#define TARGET_ENOTNAM 118 /* Not a XENIX named type file */ +#define TARGET_ENAVAIL 119 /* No XENIX semaphores available */ +#define TARGET_EISNAM 120 /* Is a named type file */ +#define TARGET_EREMOTEIO 121 /* Remote I/O error */ +#define TARGET_EDQUOT 122 /* Quota exceeded */ + +#define TARGET_ENOMEDIUM 123 /* No medium found */ +#define TARGET_EMEDIUMTYPE 124 /* Wrong medium type */ +#define TARGET_ECANCELED 125 /* Operation Canceled */ +#define TARGET_ENOKEY 126 /* Required key not available */ +#define TARGET_EKEYEXPIRED 127 /* Key has expired */ +#define TARGET_EKEYREVOKED 128 /* Key has been revoked */ +#define TARGET_EKEYREJECTED 129 /* Key was rejected by service */ + +/* for robust mutexes */ +#define TARGET_EOWNERDEAD 130 /* Owner died */ +#define TARGET_ENOTRECOVERABLE 131 /* State not recoverable */ + diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 4b3c7d625..140729f00 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -20,4 +20,207 @@ struct target_pt_regs { target_ulong cp0_epc; }; +/* Target errno definitions taken from asm-mips/errno.h */ +#undef TARGET_ENOMSG +#define TARGET_ENOMSG 35 /* Identifier removed */ +#undef TARGET_EIDRM +#define TARGET_EIDRM 36 /* Identifier removed */ +#undef TARGET_ECHRNG +#define TARGET_ECHRNG 37 /* Channel number out of range */ +#undef TARGET_EL2NSYNC +#define TARGET_EL2NSYNC 38 /* Level 2 not synchronized */ +#undef TARGET_EL3HLT +#define TARGET_EL3HLT 39 /* Level 3 halted */ +#undef TARGET_EL3RST +#define TARGET_EL3RST 40 /* Level 3 reset */ +#undef TARGET_ELNRNG +#define TARGET_ELNRNG 41 /* Link number out of range */ +#undef TARGET_EUNATCH +#define TARGET_EUNATCH 42 /* Protocol driver not attached */ +#undef TARGET_ENOCSI +#define TARGET_ENOCSI 43 /* No CSI structure available */ +#undef TARGET_EL2HLT +#define TARGET_EL2HLT 44 /* Level 2 halted */ +#undef TARGET_EDEADLK +#define TARGET_EDEADLK 45 /* Resource deadlock would occur */ +#undef TARGET_ENOLCK +#define TARGET_ENOLCK 46 /* No record locks available */ +#undef TARGET_EBADE +#define TARGET_EBADE 50 /* Invalid exchange */ +#undef TARGET_EBADR +#define TARGET_EBADR 51 /* Invalid request descriptor */ +#undef TARGET_EXFULL +#define TARGET_EXFULL 52 /* TARGET_Exchange full */ +#undef TARGET_ENOANO +#define TARGET_ENOANO 53 /* No anode */ +#undef TARGET_EBADRQC +#define TARGET_EBADRQC 54 /* Invalid request code */ +#undef TARGET_EBADSLT +#define TARGET_EBADSLT 55 /* Invalid slot */ +#undef TARGET_EDEADLOCK +#define TARGET_EDEADLOCK 56 /* File locking deadlock error */ +#undef TARGET_EBFONT +#define TARGET_EBFONT 59 /* Bad font file format */ +#undef TARGET_ENOSTR +#define TARGET_ENOSTR 60 /* Device not a stream */ +#undef TARGET_ENODATA +#define TARGET_ENODATA 61 /* No data available */ +#undef TARGET_ETIME +#define TARGET_ETIME 62 /* Timer expired */ +#undef TARGET_ENOSR +#define TARGET_ENOSR 63 /* Out of streams resources */ +#undef TARGET_ENONET +#define TARGET_ENONET 64 /* Machine is not on the network */ +#undef TARGET_ENOPKG +#define TARGET_ENOPKG 65 /* Package not installed */ +#undef TARGET_EREMOTE +#define TARGET_EREMOTE 66 /* Object is remote */ +#undef TARGET_ENOLINK +#define TARGET_ENOLINK 67 /* Link has been severed */ +#undef TARGET_EADV +#define TARGET_EADV 68 /* Advertise error */ +#undef TARGET_ESRMNT +#define TARGET_ESRMNT 69 /* Srmount error */ +#undef TARGET_ECOMM +#define TARGET_ECOMM 70 /* Communication error on send */ +#undef TARGET_EPROTO +#define TARGET_EPROTO 71 /* Protocol error */ +#undef TARGET_EDOTDOT +#define TARGET_EDOTDOT 73 /* RFS specific error */ +#undef TARGET_EMULTIHOP +#define TARGET_EMULTIHOP 74 /* Multihop attempted */ +#undef TARGET_EBADMSG +#define TARGET_EBADMSG 77 /* Not a data message */ +#undef TARGET_ENAMETOOLONG +#define TARGET_ENAMETOOLONG 78 /* File name too long */ +#undef TARGET_EOVERFLOW +#define TARGET_EOVERFLOW 79 /* Value too large for defined data type */ +#undef TARGET_ENOTUNIQ +#define TARGET_ENOTUNIQ 80 /* Name not unique on network */ +#undef TARGET_EBADFD +#define TARGET_EBADFD 81 /* File descriptor in bad state */ +#undef TARGET_EREMCHG +#define TARGET_EREMCHG 82 /* Remote address changed */ +#undef TARGET_ELIBACC +#define TARGET_ELIBACC 83 /* Can not access a needed shared library */ +#undef TARGET_ELIBBAD +#define TARGET_ELIBBAD 84 /* Accessing a corrupted shared library */ +#undef TARGET_ELIBSCN +#define TARGET_ELIBSCN 85 /* .lib section in a.out corrupted */ +#undef TARGET_ELIBMAX +#define TARGET_ELIBMAX 86 /* Attempting to link in too many shared libraries */ +#undef TARGET_ELIBEXEC +#define TARGET_ELIBEXEC 87 /* Cannot exec a shared library directly */ +#undef TARGET_EILSEQ +#define TARGET_EILSEQ 88 /* Illegal byte sequence */ +#undef TARGET_ENOSYS +#define TARGET_ENOSYS 89 /* Function not implemented */ +#undef TARGET_ELOOP +#define TARGET_ELOOP 90 /* Too many symbolic links encountered */ +#undef TARGET_ERESTART +#define TARGET_ERESTART 91 /* Interrupted system call should be restarted */ +#undef TARGET_ESTRPIPE +#define TARGET_ESTRPIPE 92 /* Streams pipe error */ +#undef TARGET_ENOTEMPTY +#define TARGET_ENOTEMPTY 93 /* Directory not empty */ +#undef TARGET_EUSERS +#define TARGET_EUSERS 94 /* Too many users */ +#undef TARGET_ENOTSOCK +#define TARGET_ENOTSOCK 95 /* Socket operation on non-socket */ +#undef TARGET_EDESTADDRREQ +#define TARGET_EDESTADDRREQ 96 /* Destination address required */ +#undef TARGET_EMSGSIZE +#define TARGET_EMSGSIZE 97 /* Message too long */ +#undef TARGET_EPROTOTYPE +#define TARGET_EPROTOTYPE 98 /* Protocol wrong type for socket */ +#undef TARGET_ENOPROTOOPT +#define TARGET_ENOPROTOOPT 99 /* Protocol not available */ +#undef TARGET_EPROTONOSUPPORT +#define TARGET_EPROTONOSUPPORT 120 /* Protocol not supported */ +#undef TARGET_ESOCKTNOSUPPORT +#define TARGET_ESOCKTNOSUPPORT 121 /* Socket type not supported */ +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ +#undef TARGET_EPFNOSUPPORT +#define TARGET_EPFNOSUPPORT 123 /* Protocol family not supported */ +#undef TARGET_EAFNOSUPPORT +#define TARGET_EAFNOSUPPORT 124 /* Address family not supported by protocol */ +#undef TARGET_EADDRINUSE +#define TARGET_EADDRINUSE 125 /* Address already in use */ +#undef TARGET_EADDRNOTAVAIL +#define TARGET_EADDRNOTAVAIL 126 /* Cannot assign requested address */ +#undef TARGET_ENETDOWN +#define TARGET_ENETDOWN 127 /* Network is down */ +#undef TARGET_ENETUNREACH +#define TARGET_ENETUNREACH 128 /* Network is unreachable */ +#undef TARGET_ENETRESET +#define TARGET_ENETRESET 129 /* Network dropped connection because of reset */ +#undef TARGET_ECONNABORTED +#define TARGET_ECONNABORTED 130 /* Software caused connection abort */ +#undef TARGET_ECONNRESET +#define TARGET_ECONNRESET 131 /* Connection reset by peer */ +#undef TARGET_ENOBUFS +#define TARGET_ENOBUFS 132 /* No buffer space available */ +#undef TARGET_EISCONN +#define TARGET_EISCONN 133 /* Transport endpoint is already connected */ +#undef TARGET_ENOTCONN +#define TARGET_ENOTCONN 134 /* Transport endpoint is not connected */ +#undef TARGET_EUCLEAN +#define TARGET_EUCLEAN 135 /* Structure needs cleaning */ +#undef TARGET_ENOTNAM +#define TARGET_ENOTNAM 137 /* Not a XENIX named type file */ +#undef TARGET_ENAVAIL +#define TARGET_ENAVAIL 138 /* No XENIX semaphores available */ +#undef TARGET_EISNAM +#define TARGET_EISNAM 139 /* Is a named type file */ +#undef TARGET_EREMOTEIO +#define TARGET_EREMOTEIO 140 /* Remote I/O error */ +#undef TARGET_EINIT +#define TARGET_EINIT 141 /* Reserved */ +#undef TARGET_EREMDEV +#define TARGET_EREMDEV 142 /* TARGET_Error 142 */ +#undef TARGET_ESHUTDOWN +#define TARGET_ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ +#undef TARGET_ETOOMANYREFS +#define TARGET_ETOOMANYREFS 144 /* Too many references: cannot splice */ +#undef TARGET_ETIMEDOUT +#define TARGET_ETIMEDOUT 145 /* Connection timed out */ +#undef TARGET_ECONNREFUSED +#define TARGET_ECONNREFUSED 146 /* Connection refused */ +#undef TARGET_EHOSTDOWN +#define TARGET_EHOSTDOWN 147 /* Host is down */ +#undef TARGET_EHOSTUNREACH +#define TARGET_EHOSTUNREACH 148 /* No route to host */ +#undef TARGET_EALREADY +#define TARGET_EALREADY 149 /* Operation already in progress */ +#undef TARGET_EINPROGRESS +#define TARGET_EINPROGRESS 150 /* Operation now in progress */ +#undef TARGET_ESTALE +#define TARGET_ESTALE 151 /* Stale NFS file handle */ +#undef TARGET_ECANCELED +#define TARGET_ECANCELED 158 /* AIO operation canceled */ +/* + * These error are Linux extensions. + */ +#undef TARGET_ENOMEDIUM +#define TARGET_ENOMEDIUM 159 /* No medium found */ +#undef TARGET_EMEDIUMTYPE +#define TARGET_EMEDIUMTYPE 160 /* Wrong medium type */ +#undef TARGET_ENOKEY +#define TARGET_ENOKEY 161 /* Required key not available */ +#undef TARGET_EKEYEXPIRED +#define TARGET_EKEYEXPIRED 162 /* Key has expired */ +#undef TARGET_EKEYREVOKED +#define TARGET_EKEYREVOKED 163 /* Key has been revoked */ +#undef TARGET_EKEYREJECTED +#define TARGET_EKEYREJECTED 164 /* Key was rejected by service */ + +/* for robust mutexes */ +#undef TARGET_EOWNERDEAD +#define TARGET_EOWNERDEAD 165 /* Owner died */ +#undef TARGET_ENOTRECOVERABLE +#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ + + + #define UNAME_MACHINE "mips" diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 64cd5da21..1ec81ce5b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -181,10 +181,117 @@ extern int setresgid(gid_t, gid_t, gid_t); extern int getresgid(gid_t *, gid_t *, gid_t *); extern int setgroups(int, gid_t *); +/* + * This list is the union of errno values overidden in asm-/errno.h + * minus the errnos that are not actually generic to all archs. + */ +static uint16_t host_to_target_errno_table[1200] = { + [EIDRM] = TARGET_EIDRM, + [ECHRNG] = TARGET_ECHRNG, + [EL2NSYNC] = TARGET_EL2NSYNC, + [EL3HLT] = TARGET_EL3HLT, + [EL3RST] = TARGET_EL3RST, + [ELNRNG] = TARGET_ELNRNG, + [EUNATCH] = TARGET_EUNATCH, + [ENOCSI] = TARGET_ENOCSI, + [EL2HLT] = TARGET_EL2HLT, + [EDEADLK] = TARGET_EDEADLK, + [ENOLCK] = TARGET_ENOLCK, + [EBADE] = TARGET_EBADE, + [EBADR] = TARGET_EBADR, + [EXFULL] = TARGET_EXFULL, + [ENOANO] = TARGET_ENOANO, + [EBADRQC] = TARGET_EBADRQC, + [EBADSLT] = TARGET_EBADSLT, + [EBFONT] = TARGET_EBFONT, + [ENOSTR] = TARGET_ENOSTR, + [ENODATA] = TARGET_ENODATA, + [ETIME] = TARGET_ETIME, + [ENOSR] = TARGET_ENOSR, + [ENONET] = TARGET_ENONET, + [ENOPKG] = TARGET_ENOPKG, + [EREMOTE] = TARGET_EREMOTE, + [ENOLINK] = TARGET_ENOLINK, + [EADV] = TARGET_EADV, + [ESRMNT] = TARGET_ESRMNT, + [ECOMM] = TARGET_ECOMM, + [EPROTO] = TARGET_EPROTO, + [EDOTDOT] = TARGET_EDOTDOT, + [EMULTIHOP] = TARGET_EMULTIHOP, + [EBADMSG] = TARGET_EBADMSG, + [ENAMETOOLONG] = TARGET_ENAMETOOLONG, + [EOVERFLOW] = TARGET_EOVERFLOW, + [ENOTUNIQ] = TARGET_ENOTUNIQ, + [EBADFD] = TARGET_EBADFD, + [EREMCHG] = TARGET_EREMCHG, + [ELIBACC] = TARGET_ELIBACC, + [ELIBBAD] = TARGET_ELIBBAD, + [ELIBSCN] = TARGET_ELIBSCN, + [ELIBMAX] = TARGET_ELIBMAX, + [ELIBEXEC] = TARGET_ELIBEXEC, + [EILSEQ] = TARGET_EILSEQ, + [ENOSYS] = TARGET_ENOSYS, + [ELOOP] = TARGET_ELOOP, + [ERESTART] = TARGET_ERESTART, + [ESTRPIPE] = TARGET_ESTRPIPE, + [ENOTEMPTY] = TARGET_ENOTEMPTY, + [EUSERS] = TARGET_EUSERS, + [ENOTSOCK] = TARGET_ENOTSOCK, + [EDESTADDRREQ] = TARGET_EDESTADDRREQ, + [EMSGSIZE] = TARGET_EMSGSIZE, + [EPROTOTYPE] = TARGET_EPROTOTYPE, + [ENOPROTOOPT] = TARGET_ENOPROTOOPT, + [EPROTONOSUPPORT] = TARGET_EPROTONOSUPPORT, + [ESOCKTNOSUPPORT] = TARGET_ESOCKTNOSUPPORT, + [EOPNOTSUPP] = TARGET_EOPNOTSUPP, + [EPFNOSUPPORT] = TARGET_EPFNOSUPPORT, + [EAFNOSUPPORT] = TARGET_EAFNOSUPPORT, + [EADDRINUSE] = TARGET_EADDRINUSE, + [EADDRNOTAVAIL] = TARGET_EADDRNOTAVAIL, + [ENETDOWN] = TARGET_ENETDOWN, + [ENETUNREACH] = TARGET_ENETUNREACH, + [ENETRESET] = TARGET_ENETRESET, + [ECONNABORTED] = TARGET_ECONNABORTED, + [ECONNRESET] = TARGET_ECONNRESET, + [ENOBUFS] = TARGET_ENOBUFS, + [EISCONN] = TARGET_EISCONN, + [ENOTCONN] = TARGET_ENOTCONN, + [EUCLEAN] = TARGET_EUCLEAN, + [ENOTNAM] = TARGET_ENOTNAM, + [ENAVAIL] = TARGET_ENAVAIL, + [EISNAM] = TARGET_EISNAM, + [EREMOTEIO] = TARGET_EREMOTEIO, + [ESHUTDOWN] = TARGET_ESHUTDOWN, + [ETOOMANYREFS] = TARGET_ETOOMANYREFS, + [ETIMEDOUT] = TARGET_ETIMEDOUT, + [ECONNREFUSED] = TARGET_ECONNREFUSED, + [EHOSTDOWN] = TARGET_EHOSTDOWN, + [EHOSTUNREACH] = TARGET_EHOSTUNREACH, + [EALREADY] = TARGET_EALREADY, + [EINPROGRESS] = TARGET_EINPROGRESS, + [ESTALE] = TARGET_ESTALE, + [ECANCELED] = TARGET_ECANCELED, + [ENOMEDIUM] = TARGET_ENOMEDIUM, + [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE, + [ENOKEY] = TARGET_ENOKEY, + [EKEYEXPIRED] = TARGET_EKEYEXPIRED, + [EKEYREVOKED] = TARGET_EKEYREVOKED, + [EKEYREJECTED] = TARGET_EKEYREJECTED, + [EOWNERDEAD] = TARGET_EOWNERDEAD, + [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE, + }; + +static inline int host_to_target_errno(int err) +{ + if(host_to_target_errno_table[err]) + return host_to_target_errno_table[err]; + return err; +} + static inline long get_errno(long ret) { if (ret == -1) - return -errno; + return -host_to_target_errno(errno); else return ret; } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index a6129d89b..5ae95b291 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1616,3 +1616,5 @@ struct target_sysinfo { }; #include "socket.h" + +#include "errno_defs.h" -- cgit v1.2.3 From 2052caa7af288e1ea9739d321c4c9c89e9395666 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 13:18:19 +0000 Subject: GDB stub for MIPS64, by Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2909 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 80 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index fd20c9ca7..d346ad94f 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -549,41 +549,41 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) ptr = mem_buf; for (i = 0; i < 32; i++) { - *(uint32_t *)ptr = tswapl(env->gpr[i]); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->gpr[i]); + ptr += sizeof(target_ulong); } - *(uint32_t *)ptr = tswapl(env->CP0_Status); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->CP0_Status); + ptr += sizeof(target_ulong); - *(uint32_t *)ptr = tswapl(env->LO); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->LO); + ptr += sizeof(target_ulong); - *(uint32_t *)ptr = tswapl(env->HI); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->HI); + ptr += sizeof(target_ulong); - *(uint32_t *)ptr = tswapl(env->CP0_BadVAddr); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr); + ptr += sizeof(target_ulong); - *(uint32_t *)ptr = tswapl(env->CP0_Cause); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->CP0_Cause); + ptr += sizeof(target_ulong); - *(uint32_t *)ptr = tswapl(env->PC); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->PC); + ptr += sizeof(target_ulong); if (env->CP0_Config1 & (1 << CP0C1_FP)) { for (i = 0; i < 32; i++) { - *(uint32_t *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]); + ptr += sizeof(target_ulong); } - *(uint32_t *)ptr = tswapl(env->fcr31); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->fcr31); + ptr += sizeof(target_ulong); - *(uint32_t *)ptr = tswapl(env->fcr0); - ptr += 4; + *(target_ulong *)ptr = tswapl(env->fcr0); + ptr += sizeof(target_ulong); } /* 32 FP registers, fsr, fir, fp. Not yet implemented. */ @@ -611,41 +611,41 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) ptr = mem_buf; for (i = 0; i < 32; i++) { - env->gpr[i] = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->gpr[i] = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); } - env->CP0_Status = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->CP0_Status = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); - env->LO = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->LO = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); - env->HI = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->HI = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); - env->CP0_BadVAddr = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); - env->CP0_Cause = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->CP0_Cause = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); - env->PC = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->PC = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); if (env->CP0_Config1 & (1 << CP0C1_FP)) { for (i = 0; i < 32; i++) { - env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); } - env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF; - ptr += 4; + env->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF; + ptr += sizeof(target_ulong); - env->fcr0 = tswapl(*(uint32_t *)ptr); - ptr += 4; + env->fcr0 = tswapl(*(target_ulong *)ptr); + ptr += sizeof(target_ulong); /* set rounding mode */ RESTORE_ROUNDING_MODE; -- cgit v1.2.3 From c9c1a064579c51d0133803895da1b7a971191f9a Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 14:58:56 +0000 Subject: Add support for 5Kc/5Kf/20Kc, based on a patch by Aurelien Jarno. Note that the F64 flag isn't usable on any of those (and the R4000), so all our 64bit FPU goodness goes out of the window until a shadow capability flag is implemented. :-( git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2910 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 2 +- target-mips/translate_init.c | 52 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 359238d2b..1164df1a9 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -784,7 +784,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, /* init CPUs */ if (cpu_model == NULL) { #ifdef TARGET_MIPS64 - cpu_model = "R4000"; + cpu_model = "20Kc"; #else cpu_model = "24Kf"; #endif diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index ac62fad60..d793c9a70 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -146,9 +146,57 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 16, .CCRes = 2, .Status_rw_bitmask = 0x3678FFFF, - .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + /* XXX: The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */ + .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), + }, + { + .name = "5Kc", + .CP0_PRid = 0x00018100, + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT), + .CP0_Config1 = MIPS_CONFIG1 | (31 << CP0C1_MMU) | + (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) | + (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, + .Status_rw_bitmask = 0x3278FFFF, + }, + { + .name = "5Kf", + .CP0_PRid = 0x00018100, + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) | + (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) | + (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, + .Status_rw_bitmask = 0x3678FFFF, + /* XXX: The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */ + .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) | + (0x81 << FCR0_PRID) | (0x0 << FCR0_REV), + }, + { + .name = "20Kc", + .CP0_PRid = 0x00018200, + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) | (1 << CP0C0_VI), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) | + (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) | + (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, + .Status_rw_bitmask = 0x36FBFFFF, + /* XXX: The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */ + .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) | (1 << FCR0_D) | (1 << FCR0_S) | - (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), + (0x82 << FCR0_PRID) | (0x0 << FCR0_REV), }, #endif }; -- cgit v1.2.3 From c13af1ef6cb71eea91047fe7a19a7ea6d49125ae Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 15:18:04 +0000 Subject: Update TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2911 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index a5842ff27..988a90262 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -7,16 +7,16 @@ General - Missing per-CPU instruction decoding, currently all implemented instructions are regarded as valid - Applications running on top of a emulated Linux segfault sometimes - when the Qemu FPU emulation is disabled. Also gdb inside the emulated - system does not work. Both problems are caused by insufficient - handling of self-modifying code. -- Floating point exception emulation is incomplete. + when the Qemu FPU emulation is disabled, the tb misses a flush + in that case. +- gdb breakpoints inside the emulated system work only due to a hack + which disassembles over the end of the current tb. +- Floating point results of ceil/floor/round are wrong for IEEE cornercases. +- recip/rsqrt FPU instructions are not implemented MIPS64 ------ -- No 64bit TLB support -- 64bit FPU not fully implemented -- 64bit mul/div handling broken +- 64bit FPU enable flag not handled correctly "Generic" 4Kc system emulation ------------------------------ -- cgit v1.2.3 From 0aac653cdda6a2be1998119d5346a43ce1ac6270 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 1 Jun 2007 16:44:42 +0000 Subject: Update Sparc dependencies git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2912 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index b8abf3e35..224474ba7 100644 --- a/Makefile.target +++ b/Makefile.target @@ -602,8 +602,10 @@ 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 +helper.o: cpu.h exec-all.h +op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h exec.h cpu.h +op_helper.o: exec.h softmmu_template.h cpu.h +translate.o: cpu.h exec-all.h disas.h endif ifeq ($(TARGET_BASE_ARCH), ppc) -- cgit v1.2.3 From d8bdf5fa1317c58a3079b1a899a7c2dc5e7753ef Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 1 Jun 2007 16:45:59 +0000 Subject: Sparc64 linux-user build fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2913 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index dc1c04deb..11134cf12 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1143,16 +1143,24 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, #ifdef TARGET_SPARC64 void do_tick_set_count(void *opaque, uint64_t count) { +#if !defined(CONFIG_USER_ONLY) ptimer_set_count(opaque, -count); +#endif } uint64_t do_tick_get_count(void *opaque) { +#if !defined(CONFIG_USER_ONLY) return -ptimer_get_count(opaque); +#else + return 0; +#endif } void do_tick_set_limit(void *opaque, uint64_t limit) { +#if !defined(CONFIG_USER_ONLY) ptimer_set_limit(opaque, -limit, 0); +#endif } #endif -- cgit v1.2.3 From 92b72cbcd5d73c7a832a7964cbfbcc3110992f2d Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 1 Jun 2007 16:56:47 +0000 Subject: Enable 36-bit physical address space also on 32-bit hosts git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2914 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 215862931..198ba54e1 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -13,6 +13,8 @@ #define TARGET_PAGE_BITS 12 /* XXX */ #endif +#define TARGET_PHYS_ADDR_BITS 64 + #include "cpu-defs.h" #include "softfloat.h" -- cgit v1.2.3 From 97e7df27cfed973532d125125c9152ddffadbf64 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 1 Jun 2007 16:58:29 +0000 Subject: Force display update on palette change or loadvm git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2915 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/tcx.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/tcx.c b/hw/tcx.c index 80d60baae..bfcb386f7 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -44,6 +44,8 @@ typedef struct TCXState { static void tcx_screen_dump(void *opaque, const char *filename); static void tcx24_screen_dump(void *opaque, const char *filename); +static void tcx_invalidate_display(void *opaque); +static void tcx24_invalidate_display(void *opaque); /* XXX: unify with vga draw line functions */ static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) @@ -86,6 +88,10 @@ static void update_palette_entries(TCXState *s, int start, int end) break; } } + if (s->depth == 24) + tcx24_invalidate_display(s); + else + tcx_invalidate_display(s); } static void tcx_draw_line32(TCXState *s1, uint8_t *d, @@ -391,7 +397,10 @@ static int tcx_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->dac_index); qemu_get_8s(f, &s->dac_state); update_palette_entries(s, 0, 256); - tcx_invalidate_display(s); + if (s->depth == 24) + tcx24_invalidate_display(s); + else + tcx_invalidate_display(s); return 0; } -- cgit v1.2.3 From d88bbf9500bf44b1123a474dbd46bc1114993fa8 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 1 Jun 2007 16:59:44 +0000 Subject: Constification git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2916 c046a42c-6fe2-441c-8c8c-71466251a162 --- sparc-dis.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sparc-dis.c b/sparc-dis.c index f04f135df..2c5921af5 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -2206,7 +2206,7 @@ sparc_decode_asi_v8 (int value) /* Handle membar masks. */ -static arg membar_table[] = +static const arg membar_table[] = { { 0x40, "#Sync" }, { 0x20, "#MemIssue" }, @@ -2238,7 +2238,7 @@ sparc_decode_membar (value) /* Handle prefetch args. */ -static arg prefetch_table[] = +static const arg prefetch_table[] = { { 0, "#n_reads" }, { 1, "#one_read" }, @@ -2269,7 +2269,7 @@ sparc_decode_prefetch (value) /* Handle sparclet coprocessor registers. */ -static arg sparclet_cpreg_table[] = +static const arg sparclet_cpreg_table[] = { { 0, "%ccsr" }, { 1, "%ccfr" }, @@ -2320,7 +2320,7 @@ static const struct sparc_opcode **sorted_opcodes; /* It is important that we only look at insn code bits as that is how the opcode table is hashed. OPCODE_BITS is a table of valid bits for each of the main types (0,1,2,3). */ -static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 }; +static const int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 }; #define HASH_INSN(INSN) \ ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19)) struct opcode_hash { @@ -2340,7 +2340,7 @@ static int compute_arch_mask PARAMS ((unsigned long)); ((((int)(value)) << ((8 * sizeof (int)) - bits)) \ >> ((8 * sizeof (int)) - bits) ) -static char *reg_names[] = +static const char * const reg_names[] = { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", @@ -2361,7 +2361,7 @@ static char *reg_names[] = /* These are ordered according to there register number in rdpr and wrpr insns. */ -static char *v9_priv_reg_names[] = +static const char * const v9_priv_reg_names[] = { "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl", "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin", @@ -2371,7 +2371,7 @@ static char *v9_priv_reg_names[] = /* These are ordered according to there register number in rd and wr insns (-16). */ -static char *v9a_asr_reg_names[] = +static const char * const v9a_asr_reg_names[] = { "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint", "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr" -- cgit v1.2.3 From 5b9693dcda3e6c19429a29f948ba3618f826f6cb Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 1 Jun 2007 17:03:05 +0000 Subject: Forgot to update vl.h during latest Sparc64 target_ulong fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2917 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.h b/vl.h index 21525fdc9..b881668fd 100644 --- a/vl.h +++ b/vl.h @@ -851,7 +851,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic); PCIBus *pci_pmac_init(qemu_irq *pic); /* apb_pci.c */ -PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, +PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base, qemu_irq *pic); PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview); -- cgit v1.2.3 From 8487327a1dabd9ce8899d0e1af151b334980c575 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 17:47:07 +0000 Subject: Make sure hflags are updated for CP0_Status changes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2918 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 50 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 08b760ba7..7ea7886ec 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2627,25 +2627,32 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) switch (sel) { case 0: gen_op_mtc0_status(); + /* BS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; rn = "Status"; break; case 1: gen_op_mtc0_intctl(); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: gen_op_mtc0_srsctl(); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: gen_op_mtc0_srsmap(); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "SRSMap"; break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 13: switch (sel) { @@ -2781,29 +2788,40 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) switch (sel) { case 0: gen_op_mtc0_debug(); /* EJTAG support */ + /* BS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; rn = "Debug"; break; case 1: // gen_op_mtc0_tracecontrol(); /* PDtrace support */ rn = "TraceControl"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; // break; case 2: // gen_op_mtc0_tracecontrol2(); /* PDtrace support */ rn = "TraceControl2"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; // break; case 3: + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; // gen_op_mtc0_usertracedata(); /* PDtrace support */ rn = "UserTraceData"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; // break; case 4: // gen_op_mtc0_debug(); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "TraceBPC"; // break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 24: switch (sel) { @@ -3704,25 +3722,32 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) switch (sel) { case 0: gen_op_mtc0_status(); + /* BS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; rn = "Status"; break; case 1: gen_op_mtc0_intctl(); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: gen_op_mtc0_srsctl(); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: gen_op_mtc0_srsmap(); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "SRSMap"; break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 13: switch (sel) { @@ -3849,29 +3874,38 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) switch (sel) { case 0: gen_op_mtc0_debug(); /* EJTAG support */ + /* BS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; rn = "Debug"; break; case 1: // gen_op_mtc0_tracecontrol(); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "TraceControl"; // break; case 2: // gen_op_mtc0_tracecontrol2(); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "TraceControl2"; // break; case 3: // gen_op_mtc0_usertracedata(); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "UserTraceData"; // break; case 4: // gen_op_mtc0_debug(); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; rn = "TraceBPC"; // break; default: goto die; } - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; break; case 24: switch (sel) { -- cgit v1.2.3 From 1e3d0552f561429ed8236f71857f28c1903e5774 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 21:57:32 +0000 Subject: Update some comments, 64bit FPU support is functional regardless of funny non-standard fcr0 bits on earlier CPUs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2919 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 2 +- target-mips/translate_init.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index 988a90262..2ff95df99 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -16,7 +16,7 @@ General MIPS64 ------ -- 64bit FPU enable flag not handled correctly +- Only lighly tested but apparently functional as of 2007-05-31. "Generic" 4Kc system emulation ------------------------------ diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index d793c9a70..bbfa63b30 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -146,7 +146,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 16, .CCRes = 2, .Status_rw_bitmask = 0x3678FFFF, - /* XXX: The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */ + /* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */ .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), }, { @@ -176,7 +176,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3678FFFF, - /* XXX: The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */ + /* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */ .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) | (0x81 << FCR0_PRID) | (0x0 << FCR0_REV), }, @@ -193,7 +193,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x36FBFFFF, - /* XXX: The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */ + /* The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */ .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) | (1 << FCR0_D) | (1 << FCR0_S) | (0x82 << FCR0_PRID) | (0x0 << FCR0_REV), @@ -279,6 +279,10 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) if (env->fcr0 & (1 << FCR0_F64)) env->hflags |= MIPS_HFLAG_F64; #else + /* There are more full-featured MMU variants in older MIPS CPUs, + R3000, R6000 and R8000 come to mind. If we ever support them, + this check will need to look up a different place than those + newfangled config registers. */ switch ((env->CP0_Config0 >> CP0C0_MT) & 3) { case 0: no_mmu_init(env, def); @@ -290,7 +294,6 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) fixed_mmu_init(env, def); break; default: - /* Older CPUs like the R3000 may need nonstandard handling here. */ cpu_abort(env, "MMU type not supported\n"); } env->CP0_Random = env->nb_tlb - 1; -- cgit v1.2.3 From 2538deb29249094e73a7f294cc4a2741fd1b9bb9 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 1 Jun 2007 23:50:45 +0000 Subject: Delete leftover Status FPU flag check. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2920 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 259173bb8..fd96ea2c0 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2016,9 +2016,6 @@ int main(int argc, char **argv) env->gpr[i] = regs->regs[i]; } env->PC = regs->cp0_epc; - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - env->CP0_Status |= (1 << CP0St_CU1); - } } #elif defined(TARGET_SH4) { -- cgit v1.2.3 From 3a95e3a7d9a6fd7610fe483778ff7016d23be5ec Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 2 Jun 2007 00:25:12 +0000 Subject: Check for R2 instructions, and throw RI if we don't emulate R2. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2921 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 68 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 7ea7886ec..b5a8b5b0a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -732,6 +732,14 @@ void check_cp1_registers(DisasContext *ctx, int regs) generate_exception(ctx, EXCP_RI); } +/* This code generates a "reserved instruction" exception if the + CPU is not a MIPS R2 (or higher) CPU. */ +static inline void check_mips_r2(CPUState *env, DisasContext *ctx) +{ + if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) < (1 << CP0C0_AR)) + generate_exception(ctx, EXCP_RI); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -1866,7 +1874,7 @@ fail: } /* CP0 (MMU and control) */ -static void gen_mfc0 (DisasContext *ctx, int reg, int sel) +static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -2000,6 +2008,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) rn = "PageMask"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_pagegrain(); rn = "PageGrain"; break; @@ -2040,6 +2049,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: + check_mips_r2(env, ctx); gen_op_mfc0_hwrena(); rn = "HWREna"; break; @@ -2096,14 +2106,17 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) rn = "Status"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_intctl(); rn = "IntCtl"; break; case 2: + check_mips_r2(env, ctx); gen_op_mfc0_srsctl(); rn = "SRSCtl"; break; case 3: + check_mips_r2(env, ctx); gen_op_mfc0_srsmap(); rn = "SRSMap"; break; @@ -2138,6 +2151,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_ebase(); rn = "EBase"; break; @@ -2402,7 +2416,7 @@ die: generate_exception(ctx, EXCP_RI); } -static void gen_mtc0 (DisasContext *ctx, int reg, int sel) +static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -2536,6 +2550,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) rn = "PageMask"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_pagegrain(); rn = "PageGrain"; break; @@ -2576,6 +2591,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: + check_mips_r2(env, ctx); gen_op_mtc0_hwrena(); rn = "HWREna"; break; @@ -2633,18 +2649,21 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) rn = "Status"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_intctl(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: + check_mips_r2(env, ctx); gen_op_mtc0_srsctl(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: + check_mips_r2(env, ctx); gen_op_mtc0_srsmap(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -2683,6 +2702,7 @@ static void gen_mtc0 (DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_ebase(); rn = "EBase"; break; @@ -2970,7 +2990,7 @@ die: } #ifdef TARGET_MIPS64 -static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) +static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -3104,6 +3124,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) rn = "PageMask"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_pagegrain(); rn = "PageGrain"; break; @@ -3144,6 +3165,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: + check_mips_r2(env, ctx); gen_op_mfc0_hwrena(); rn = "HWREna"; break; @@ -3200,14 +3222,17 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) rn = "Status"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_intctl(); rn = "IntCtl"; break; case 2: + check_mips_r2(env, ctx); gen_op_mfc0_srsctl(); rn = "SRSCtl"; break; case 3: + check_mips_r2(env, ctx); gen_op_mfc0_srsmap(); /* shadow registers */ rn = "SRSMap"; break; @@ -3242,6 +3267,7 @@ static void gen_dmfc0 (DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: + check_mips_r2(env, ctx); gen_op_mfc0_ebase(); rn = "EBase"; break; @@ -3497,7 +3523,7 @@ die: generate_exception(ctx, EXCP_RI); } -static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) +static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -3631,6 +3657,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "PageMask"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_pagegrain(); rn = "PageGrain"; break; @@ -3671,6 +3698,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: + check_mips_r2(env, ctx); gen_op_mtc0_hwrena(); rn = "HWREna"; break; @@ -3728,18 +3756,21 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "Status"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_intctl(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: + check_mips_r2(env, ctx); gen_op_mtc0_srsctl(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: + check_mips_r2(env, ctx); gen_op_mtc0_srsmap(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -3778,6 +3809,7 @@ static void gen_dmtc0 (DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: + check_mips_r2(env, ctx); gen_op_mtc0_ebase(); rn = "EBase"; break; @@ -4064,13 +4096,13 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int /* Treat as NOP */ return; } - gen_mfc0(ctx, rd, ctx->opcode & 0x7); + gen_mfc0(env, ctx, rd, ctx->opcode & 0x7); gen_op_store_T0_gpr(rt); opn = "mfc0"; break; case OPC_MTC0: GEN_LOAD_REG_TN(T0, rt); - gen_mtc0(ctx, rd, ctx->opcode & 0x7); + gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; break; #ifdef TARGET_MIPS64 @@ -4079,13 +4111,13 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int /* Treat as NOP */ return; } - gen_dmfc0(ctx, rd, ctx->opcode & 0x7); + gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7); gen_op_store_T0_gpr(rt); opn = "dmfc0"; break; case OPC_DMTC0: GEN_LOAD_REG_TN(T0, rt); - gen_dmtc0(ctx, rd, ctx->opcode & 0x7); + gen_dmtc0(env,ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; break; #endif @@ -5501,6 +5533,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_SPECIAL3: + check_mips_r2(env, ctx); op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { case OPC_EXT: @@ -5604,6 +5637,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_trap(ctx, op1, rs, -1, imm); break; case OPC_SYNCI: + check_mips_r2(env, ctx); /* treat as noop */ break; default: /* Invalid */ @@ -5629,6 +5663,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); break; case OPC_MFMC0: + check_mips_r2(env, ctx); op2 = MASK_MFMC0(ctx->opcode); switch (op2) { case OPC_DI: @@ -5650,14 +5685,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case OPC_RDPGPR: case OPC_WRPGPR: - if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) { - /* Shadow registers not implemented. */ - GEN_LOAD_REG_TN(T0, rt); - GEN_STORE_TN_REG(rd, T0); - } else { - MIPS_INVAL("shadow register move"); - generate_exception(ctx, EXCP_RI); - } + check_mips_r2(env, ctx); + /* Shadow registers not implemented. */ + GEN_LOAD_REG_TN(T0, rt); + GEN_STORE_TN_REG(rd, T0); break; default: MIPS_INVAL("cp0"); @@ -5710,6 +5741,9 @@ static void decode_opc (CPUState *env, DisasContext *ctx) check_cp1_enabled(ctx); op1 = MASK_CP1(ctx->opcode); switch (op1) { + case OPC_MFHC1: + case OPC_MTHC1: + check_mips_r2(env, ctx); case OPC_MFC1: case OPC_CFC1: case OPC_MTC1: @@ -5718,8 +5752,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_DMFC1: case OPC_DMTC1: #endif - case OPC_MFHC1: - case OPC_MTHC1: gen_cp1(ctx, op1, rt, rd); break; case OPC_BC1: -- cgit v1.2.3 From caf8fe8c32596480b2e2809f29061f4a386de7ae Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 2 Jun 2007 17:59:59 +0000 Subject: Clear SR_M on a hardware interrupt. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2922 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/op_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index f5593eca0..8086238db 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -148,6 +148,7 @@ void do_interrupt(int is_hw) env->sr |= SR_S; if (is_hw) { env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); + env->sr &= ~SR_M; } /* Jump to vector. */ env->pc = ldl_kernel(env->vbr + vector); -- cgit v1.2.3 From 62ea5b0bd38471ef114ca2e2dd7507a778701cd3 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 3 Jun 2007 10:44:47 +0000 Subject: Leave running timer alone if not reloading. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2923 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ptimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ptimer.c b/hw/ptimer.c index feabefed9..2abf285af 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -149,7 +149,7 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) s->limit = limit; if (reload) s->delta = limit; - if (s->enabled) { + if (s->enabled && reload) { s->next_event = qemu_get_clock(vm_clock); ptimer_reload(s); } -- cgit v1.2.3 From 20dcee9483361ee0621cf6d68d271ecde686fd9c Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 3 Jun 2007 11:13:39 +0000 Subject: MCF5208 emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2924 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/an5206.c | 4 +- hw/mcf5206.c | 289 ++------------------------------------------- hw/mcf5208.c | 285 ++++++++++++++++++++++++++++++++++++++++++++ hw/mcf_intc.c | 156 ++++++++++++++++++++++++ hw/mcf_uart.c | 306 ++++++++++++++++++++++++++++++++++++++++++++++++ target-m68k/cpu.h | 13 ++ target-m68k/helper.c | 26 +++- target-m68k/op.c | 7 ++ target-m68k/op_helper.c | 18 +-- target-m68k/translate.c | 9 +- vl.c | 1 + vl.h | 13 ++ 13 files changed, 833 insertions(+), 296 deletions(-) create mode 100644 hw/mcf5208.c create mode 100644 hw/mcf_intc.c create mode 100644 hw/mcf_uart.c diff --git a/Makefile.target b/Makefile.target index 224474ba7..1d1dacfb0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -467,7 +467,7 @@ ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o endif ifeq ($(TARGET_BASE_ARCH), m68k) -VL_OBJS+= an5206.o mcf5206.o ptimer.o +VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o VL_OBJS+= m68k-semi.o endif ifdef CONFIG_GDBSTUB diff --git a/hw/an5206.c b/hw/an5206.c index 1306d1964..379f48e78 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -40,7 +40,9 @@ static void an5206_init(int ram_size, int vga_ram_size, int boot_device, env = cpu_init(); if (!cpu_model) cpu_model = "m5206"; - cpu_m68k_set_model(env, cpu_model); + if (cpu_m68k_set_model(env, cpu_model)) { + cpu_abort(env, "Unable to find m68k CPU definition\n"); + } /* Initialize CPU registers. */ env->vbr = 0; diff --git a/hw/mcf5206.c b/hw/mcf5206.c index 0da791293..ce4676bdf 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -139,285 +139,12 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq) return s; } -/* UART */ - -typedef struct { - uint8_t mr[2]; - uint8_t sr; - uint8_t isr; - uint8_t imr; - uint8_t bg1; - uint8_t bg2; - uint8_t fifo[4]; - uint8_t tb; - int current_mr; - int fifo_len; - int tx_enabled; - int rx_enabled; - qemu_irq irq; - CharDriverState *chr; -} m5206_uart_state; - -/* UART Status Register bits. */ -#define M5206_UART_RxRDY 0x01 -#define M5206_UART_FFULL 0x02 -#define M5206_UART_TxRDY 0x04 -#define M5206_UART_TxEMP 0x08 -#define M5206_UART_OE 0x10 -#define M5206_UART_PE 0x20 -#define M5206_UART_FE 0x40 -#define M5206_UART_RB 0x80 - -/* Interrupt flags. */ -#define M5206_UART_TxINT 0x01 -#define M5206_UART_RxINT 0x02 -#define M5206_UART_DBINT 0x04 -#define M5206_UART_COSINT 0x80 - -/* UMR1 flags. */ -#define M5206_UART_BC0 0x01 -#define M5206_UART_BC1 0x02 -#define M5206_UART_PT 0x04 -#define M5206_UART_PM0 0x08 -#define M5206_UART_PM1 0x10 -#define M5206_UART_ERR 0x20 -#define M5206_UART_RxIRQ 0x40 -#define M5206_UART_RxRTS 0x80 - -static void m5206_uart_update(m5206_uart_state *s) -{ - s->isr &= ~(M5206_UART_TxINT | M5206_UART_RxINT); - if (s->sr & M5206_UART_TxRDY) - s->isr |= M5206_UART_TxINT; - if ((s->sr & ((s->mr[0] & M5206_UART_RxIRQ) - ? M5206_UART_FFULL : M5206_UART_RxRDY)) != 0) - s->isr |= M5206_UART_RxINT; - - qemu_set_irq(s->irq, (s->isr & s->imr) != 0); -} - -static uint32_t m5206_uart_read(m5206_uart_state *s, uint32_t addr) -{ - switch (addr) { - case 0x00: - return s->mr[s->current_mr]; - case 0x04: - return s->sr; - case 0x0c: - { - uint8_t val; - int i; - - if (s->fifo_len == 0) - return 0; - - val = s->fifo[0]; - s->fifo_len--; - for (i = 0; i < s->fifo_len; i++) - s->fifo[i] = s->fifo[i + 1]; - s->sr &= ~M5206_UART_FFULL; - if (s->fifo_len == 0) - s->sr &= ~M5206_UART_RxRDY; - m5206_uart_update(s); - return val; - } - case 0x10: - /* TODO: Implement IPCR. */ - return 0; - case 0x14: - return s->isr; - case 0x18: - return s->bg1; - case 0x1c: - return s->bg2; - default: - return 0; - } -} - -/* Update TxRDY flag and set data if present and enabled. */ -static void m5206_uart_do_tx(m5206_uart_state *s) -{ - if (s->tx_enabled && (s->sr & M5206_UART_TxEMP) == 0) { - if (s->chr) - qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1); - s->sr |= M5206_UART_TxEMP; - } - if (s->tx_enabled) { - s->sr |= M5206_UART_TxRDY; - } else { - s->sr &= ~M5206_UART_TxRDY; - } -} - -static void m5206_do_command(m5206_uart_state *s, uint8_t cmd) -{ - /* Misc command. */ - switch ((cmd >> 4) & 3) { - case 0: /* No-op. */ - break; - case 1: /* Reset mode register pointer. */ - s->current_mr = 0; - break; - case 2: /* Reset receiver. */ - s->rx_enabled = 0; - s->fifo_len = 0; - s->sr &= ~(M5206_UART_RxRDY | M5206_UART_FFULL); - break; - case 3: /* Reset transmitter. */ - s->tx_enabled = 0; - s->sr |= M5206_UART_TxEMP; - s->sr &= ~M5206_UART_TxRDY; - break; - case 4: /* Reset error status. */ - break; - case 5: /* Reset break-change interrupt. */ - s->isr &= ~M5206_UART_DBINT; - break; - case 6: /* Start break. */ - case 7: /* Stop break. */ - break; - } - - /* Transmitter command. */ - switch ((cmd >> 2) & 3) { - case 0: /* No-op. */ - break; - case 1: /* Enable. */ - s->tx_enabled = 1; - m5206_uart_do_tx(s); - break; - case 2: /* Disable. */ - s->tx_enabled = 0; - m5206_uart_do_tx(s); - break; - case 3: /* Reserved. */ - fprintf(stderr, "m5206_uart: Bad TX command\n"); - break; - } - - /* Receiver command. */ - switch (cmd & 3) { - case 0: /* No-op. */ - break; - case 1: /* Enable. */ - s->rx_enabled = 1; - break; - case 2: - s->rx_enabled = 0; - break; - case 3: /* Reserved. */ - fprintf(stderr, "m5206_uart: Bad RX command\n"); - break; - } -} - -static void m5206_uart_write(m5206_uart_state *s, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x00: - s->mr[s->current_mr] = val; - s->current_mr = 1; - break; - case 0x04: - /* CSR is ignored. */ - break; - case 0x08: /* Command Register. */ - m5206_do_command(s, val); - break; - case 0x0c: /* Transmit Buffer. */ - s->sr &= ~M5206_UART_TxEMP; - s->tb = val; - m5206_uart_do_tx(s); - break; - case 0x10: - /* ACR is ignored. */ - break; - case 0x14: - s->imr = val; - break; - default: - break; - } - m5206_uart_update(s); -} - -static void m5206_uart_reset(m5206_uart_state *s) -{ - s->fifo_len = 0; - s->mr[0] = 0; - s->mr[1] = 0; - s->sr = M5206_UART_TxEMP; - s->tx_enabled = 0; - s->rx_enabled = 0; - s->isr = 0; - s->imr = 0; -} - -static void m5206_uart_push_byte(m5206_uart_state *s, uint8_t data) -{ - /* Break events overwrite the last byte if the fifo is full. */ - if (s->fifo_len == 4) - s->fifo_len--; - - s->fifo[s->fifo_len] = data; - s->fifo_len++; - s->sr |= M5206_UART_RxRDY; - if (s->fifo_len == 4) - s->sr |= M5206_UART_FFULL; - - m5206_uart_update(s); -} - -static void m5206_uart_event(void *opaque, int event) -{ - m5206_uart_state *s = (m5206_uart_state *)opaque; - - switch (event) { - case CHR_EVENT_BREAK: - s->isr |= M5206_UART_DBINT; - m5206_uart_push_byte(s, 0); - break; - default: - break; - } -} - -static int m5206_uart_can_receive(void *opaque) -{ - m5206_uart_state *s = (m5206_uart_state *)opaque; - - return s->rx_enabled && (s->sr & M5206_UART_FFULL) == 0; -} - -static void m5206_uart_receive(void *opaque, const uint8_t *buf, int size) -{ - m5206_uart_state *s = (m5206_uart_state *)opaque; - - m5206_uart_push_byte(s, buf[0]); -} - -static m5206_uart_state *m5206_uart_init(qemu_irq irq, CharDriverState *chr) -{ - m5206_uart_state *s; - - s = qemu_mallocz(sizeof(m5206_uart_state)); - s->chr = chr; - s->irq = irq; - if (chr) { - qemu_chr_add_handlers(chr, m5206_uart_can_receive, m5206_uart_receive, - m5206_uart_event, s); - } - m5206_uart_reset(s); - return s; -} - /* System Integration Module. */ typedef struct { CPUState *env; m5206_timer_state *timer[2]; - m5206_uart_state *uart[2]; + void *uart[2]; uint8_t scr; uint8_t icr[14]; uint16_t imr; /* 1 == interrupt is masked. */ @@ -540,9 +267,9 @@ static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset) } else if (offset >= 0x120 && offset < 0x140) { return m5206_timer_read(s->timer[1], offset - 0x120); } else if (offset >= 0x140 && offset < 0x160) { - return m5206_uart_read(s->uart[0], offset - 0x140); + return mcf_uart_read(s->uart[0], offset - 0x140); } else if (offset >= 0x180 && offset < 0x1a0) { - return m5206_uart_read(s->uart[1], offset - 0x180); + return mcf_uart_read(s->uart[1], offset - 0x180); } switch (offset) { case 0x03: return s->scr; @@ -580,10 +307,10 @@ static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, m5206_timer_write(s->timer[1], offset - 0x120, value); return; } else if (offset >= 0x140 && offset < 0x160) { - m5206_uart_write(s->uart[0], offset - 0x140, value); + mcf_uart_write(s->uart[0], offset - 0x140, value); return; } else if (offset >= 0x180 && offset < 0x1a0) { - m5206_uart_write(s->uart[1], offset - 0x180, value); + mcf_uart_write(s->uart[1], offset - 0x180, value); return; } switch (offset) { @@ -798,13 +525,13 @@ qemu_irq *mcf5206_init(uint32_t base, CPUState *env) s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state)); iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn, m5206_mbar_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); s->timer[0] = m5206_timer_init(pic[9]); s->timer[1] = m5206_timer_init(pic[10]); - s->uart[0] = m5206_uart_init(pic[12], serial_hds[0]); - s->uart[1] = m5206_uart_init(pic[13], serial_hds[1]); + s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]); + s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]); s->env = env; m5206_mbar_reset(s); diff --git a/hw/mcf5208.c b/hw/mcf5208.c new file mode 100644 index 000000000..49108e092 --- /dev/null +++ b/hw/mcf5208.c @@ -0,0 +1,285 @@ +/* + * Motorola ColdFire MCF5208 SoC emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GPL + */ +#include "vl.h" + +#define SYS_FREQ 66000000 + +#define PCSR_EN 0x0001 +#define PCSR_RLD 0x0002 +#define PCSR_PIF 0x0004 +#define PCSR_PIE 0x0008 +#define PCSR_OVW 0x0010 +#define PCSR_DBG 0x0020 +#define PCSR_DOZE 0x0040 +#define PCSR_PRE_SHIFT 8 +#define PCSR_PRE_MASK 0x0f00 + +typedef struct { + qemu_irq irq; + ptimer_state *timer; + uint16_t pcsr; + uint16_t pmr; + uint16_t pcntr; +} m5208_timer_state; + +static void m5208_timer_update(m5208_timer_state *s) +{ + if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF)) + qemu_irq_raise(s->irq); + else + qemu_irq_lower(s->irq); +} + +static void m5208_timer_write(m5208_timer_state *s, int offset, + uint32_t value) +{ + int prescale; + int limit; + switch (offset) { + case 0: + /* The PIF bit is set-to-clear. */ + if (value & PCSR_PIF) { + s->pcsr &= ~PCSR_PIF; + value &= ~PCSR_PIF; + } + /* Avoid frobbing the timer if we're just twiddling IRQ bits. */ + if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) { + s->pcsr = value; + m5208_timer_update(s); + return; + } + + if (s->pcsr & PCSR_EN) + ptimer_stop(s->timer); + + s->pcsr = value; + + prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT); + ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale); + if (s->pcsr & PCSR_RLD) + limit = 0xffff; + else + limit = s->pmr; + ptimer_set_limit(s->timer, limit, 0); + + if (s->pcsr & PCSR_EN) + ptimer_run(s->timer, 0); + break; + case 2: + s->pmr = value; + s->pcsr &= ~PCSR_PIF; + if (s->pcsr & PCSR_RLD) + value = 0xffff; + ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW); + break; + case 4: + break; + default: + /* Should never happen. */ + abort(); + } + m5208_timer_update(s); +} + +static void m5208_timer_trigger(void *opaque) +{ + m5208_timer_state *s = (m5208_timer_state *)opaque; + s->pcsr |= PCSR_PIF; + m5208_timer_update(s); +} + +typedef struct { + m5208_timer_state timer[2]; +} m5208_sys_state; + +static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr) +{ + m5208_sys_state *s = (m5208_sys_state *)opaque; + switch (addr) { + /* PIT0 */ + case 0xfc080000: + return s->timer[0].pcsr; + case 0xfc080002: + return s->timer[0].pmr; + case 0xfc080004: + return ptimer_get_count(s->timer[0].timer); + /* PIT1 */ + case 0xfc084000: + return s->timer[1].pcsr; + case 0xfc084002: + return s->timer[1].pmr; + case 0xfc084004: + return ptimer_get_count(s->timer[1].timer); + + /* SDRAM Controller. */ + case 0xfc0a8110: /* SDCS0 */ + { + int n; + for (n = 0; n < 32; n++) { + if (ram_size < (2u << n)) + break; + } + return (n - 1) | 0x40000000; + } + case 0xfc0a8114: /* SDCS1 */ + return 0; + + default: + cpu_abort(cpu_single_env, "m5208_sys_read: Bad offset 0x%x\n", + (int)addr); + return 0; + } +} + +static void m5208_sys_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + m5208_sys_state *s = (m5208_sys_state *)opaque; + switch (addr) { + /* PIT0 */ + case 0xfc080000: + case 0xfc080002: + case 0xfc080004: + m5208_timer_write(&s->timer[0], addr & 0xf, value); + return; + /* PIT1 */ + case 0xfc084000: + case 0xfc084002: + case 0xfc084004: + m5208_timer_write(&s->timer[1], addr & 0xf, value); + return; + default: + cpu_abort(cpu_single_env, "m5208_sys_write: Bad offset 0x%x\n", + (int)addr); + break; + } +} + +static CPUReadMemoryFunc *m5208_sys_readfn[] = { + m5208_sys_read, + m5208_sys_read, + m5208_sys_read +}; + +static CPUWriteMemoryFunc *m5208_sys_writefn[] = { + m5208_sys_write, + m5208_sys_write, + m5208_sys_write +}; + +static void mcf5208_sys_init(qemu_irq *pic) +{ + int iomemtype; + m5208_sys_state *s; + QEMUBH *bh; + int i; + + s = (m5208_sys_state *)qemu_mallocz(sizeof(m5208_sys_state)); + iomemtype = cpu_register_io_memory(0, m5208_sys_readfn, + m5208_sys_writefn, s); + /* SDRAMC. */ + cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype); + /* Timers. */ + for (i = 0; i < 2; i++) { + bh = qemu_bh_new(m5208_timer_trigger, &s->timer[i]); + s->timer[i].timer = ptimer_init(bh); + cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000, + iomemtype); + s->timer[i].irq = pic[4 + i]; + } +} + +static void mcf5208evb_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env; + int kernel_size; + uint64_t elf_entry; + target_ulong entry; + qemu_irq *pic; + + env = cpu_init(); + if (!cpu_model) + cpu_model = "m5208"; + if (cpu_m68k_set_model(env, cpu_model)) { + cpu_abort(env, "Unable to find m68k CPU definition\n"); + } + + /* Initialize CPU registers. */ + env->vbr = 0; + /* TODO: Configure BARs. */ + + /* DRAM at 0x20000000 */ + cpu_register_physical_memory(0x40000000, ram_size, + qemu_ram_alloc(ram_size) | IO_MEM_RAM); + + /* Internal SRAM. */ + cpu_register_physical_memory(0x80000000, 16384, + qemu_ram_alloc(16384) | IO_MEM_RAM); + + /* Internal peripherals. */ + pic = mcf_intc_init(0xfc048000, env); + + mcf_uart_mm_init(0xfc060000, pic[26], serial_hds[0]); + mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]); + mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]); + + mcf5208_sys_init(pic); + + /* 0xfc000000 SCM. */ + /* 0xfc004000 XBS. */ + /* 0xfc008000 FlexBus CS. */ + /* 0xfc030000 FEC. */ + /* 0xfc040000 SCM + Power management. */ + /* 0xfc044000 eDMA. */ + /* 0xfc048000 INTC. */ + /* 0xfc058000 I2C. */ + /* 0xfc05c000 QSPI. */ + /* 0xfc060000 UART0. */ + /* 0xfc064000 UART0. */ + /* 0xfc068000 UART0. */ + /* 0xfc070000 DMA timers. */ + /* 0xfc080000 PIT0. */ + /* 0xfc084000 PIT1. */ + /* 0xfc088000 EPORT. */ + /* 0xfc08c000 Watchdog. */ + /* 0xfc090000 clock module. */ + /* 0xfc0a0000 CCM + reset. */ + /* 0xfc0a4000 GPIO. */ + /* 0xfc0a8000 SDRAM controller. */ + + /* Load kernel. */ + if (!kernel_filename) { + fprintf(stderr, "Kernel image must be specified\n"); + exit(1); + } + + kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uboot(kernel_filename, &entry, NULL); + } + if (kernel_size < 0) { + kernel_size = load_image(kernel_filename, phys_ram_base); + entry = 0x20000000; + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + env->pc = entry; +} + +QEMUMachine mcf5208evb_machine = { + "mcf5208evb", + "MCF5206EVB", + mcf5208evb_init, +}; diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c new file mode 100644 index 000000000..5bdebf8bb --- /dev/null +++ b/hw/mcf_intc.c @@ -0,0 +1,156 @@ +/* + * ColdFire Interrupt Controller emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GPL + */ +#include "vl.h" + +typedef struct { + uint64_t ipr; + uint64_t imr; + uint64_t ifr; + uint64_t enabled; + uint8_t icr[64]; + CPUState *env; + int active_vector; +} mcf_intc_state; + +static void mcf_intc_update(mcf_intc_state *s) +{ + uint64_t active; + int i; + int best; + int best_level; + + active = (s->ipr | s->ifr) & s->enabled & ~s->imr; + best_level = 0; + best = 64; + if (active) { + for (i = 0; i < 64; i++) { + if ((active & 1) != 0 && s->icr[i] >= best_level) { + best_level = s->icr[i]; + best = i; + } + active >>= 1; + } + } + s->active_vector = ((best == 64) ? 24 : (best + 64)); + m68k_set_irq_level(s->env, best_level, s->active_vector); +} + +static uint32_t mcf_intc_read(void *opaque, target_phys_addr_t addr) +{ + int offset; + mcf_intc_state *s = (mcf_intc_state *)opaque; + offset = addr & 0xff; + if (offset >= 0x40 && offset < 0x80) { + return s->icr[offset - 0x40]; + } + switch (offset) { + case 0x00: + return (uint32_t)(s->ipr >> 32); + case 0x04: + return (uint32_t)s->ipr; + case 0x08: + return (uint32_t)(s->imr >> 32); + case 0x0c: + return (uint32_t)s->imr; + case 0x10: + return (uint32_t)(s->ifr >> 32); + case 0x14: + return (uint32_t)s->ifr; + case 0xe0: /* SWIACK. */ + return s->active_vector; + case 0xe1: case 0xe2: case 0xe3: case 0xe4: + case 0xe5: case 0xe6: case 0xe7: + /* LnIACK */ + cpu_abort(cpu_single_env, "mcf_intc_read: LnIACK not implemented\n"); + default: + return 0; + } +} + +static void mcf_intc_write(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + int offset; + mcf_intc_state *s = (mcf_intc_state *)opaque; + offset = addr & 0xff; + if (offset >= 0x40 && offset < 0x80) { + int n = offset - 0x40; + s->icr[n] = val; + if (val == 0) + s->enabled &= ~(1ull << n); + else + s->enabled |= (1ull << n); + mcf_intc_update(s); + return; + } + switch (offset) { + case 0x00: case 0x04: + /* Ignore IPR writes. */ + return; + case 0x08: + s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32); + break; + case 0x0c: + s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val; + break; + default: + cpu_abort(cpu_single_env, "mcf_intc_write: Bad write offset %d\n", + offset); + break; + } + mcf_intc_update(s); +} + +static void mcf_intc_set_irq(void *opaque, int irq, int level) +{ + mcf_intc_state *s = (mcf_intc_state *)opaque; + if (irq >= 64) + return; + if (level) + s->ipr |= 1ull << irq; + else + s->ipr &= ~(1ull << irq); + mcf_intc_update(s); +} + +static void mcf_intc_reset(mcf_intc_state *s) +{ + s->imr = ~0ull; + s->ipr = 0; + s->ifr = 0; + s->enabled = 0; + memset(s->icr, 0, 64); + s->active_vector = 24; +} + +static CPUReadMemoryFunc *mcf_intc_readfn[] = { + mcf_intc_read, + mcf_intc_read, + mcf_intc_read +}; + +static CPUWriteMemoryFunc *mcf_intc_writefn[] = { + mcf_intc_write, + mcf_intc_write, + mcf_intc_write +}; + +qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env) +{ + mcf_intc_state *s; + int iomemtype; + + s = qemu_mallocz(sizeof(mcf_intc_state)); + s->env = env; + mcf_intc_reset(s); + + iomemtype = cpu_register_io_memory(0, mcf_intc_readfn, + mcf_intc_writefn, s); + cpu_register_physical_memory(base, 0x100, iomemtype); + + return qemu_allocate_irqs(mcf_intc_set_irq, s, 64); +} diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c new file mode 100644 index 000000000..fcdfc4453 --- /dev/null +++ b/hw/mcf_uart.c @@ -0,0 +1,306 @@ +/* + * ColdFire UART emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GPL + */ +#include "vl.h" + +typedef struct { + uint8_t mr[2]; + uint8_t sr; + uint8_t isr; + uint8_t imr; + uint8_t bg1; + uint8_t bg2; + uint8_t fifo[4]; + uint8_t tb; + int current_mr; + int fifo_len; + int tx_enabled; + int rx_enabled; + qemu_irq irq; + CharDriverState *chr; +} mcf_uart_state; + +/* UART Status Register bits. */ +#define MCF_UART_RxRDY 0x01 +#define MCF_UART_FFULL 0x02 +#define MCF_UART_TxRDY 0x04 +#define MCF_UART_TxEMP 0x08 +#define MCF_UART_OE 0x10 +#define MCF_UART_PE 0x20 +#define MCF_UART_FE 0x40 +#define MCF_UART_RB 0x80 + +/* Interrupt flags. */ +#define MCF_UART_TxINT 0x01 +#define MCF_UART_RxINT 0x02 +#define MCF_UART_DBINT 0x04 +#define MCF_UART_COSINT 0x80 + +/* UMR1 flags. */ +#define MCF_UART_BC0 0x01 +#define MCF_UART_BC1 0x02 +#define MCF_UART_PT 0x04 +#define MCF_UART_PM0 0x08 +#define MCF_UART_PM1 0x10 +#define MCF_UART_ERR 0x20 +#define MCF_UART_RxIRQ 0x40 +#define MCF_UART_RxRTS 0x80 + +static void mcf_uart_update(mcf_uart_state *s) +{ + s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT); + if (s->sr & MCF_UART_TxRDY) + s->isr |= MCF_UART_TxINT; + if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ) + ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0) + s->isr |= MCF_UART_RxINT; + + qemu_set_irq(s->irq, (s->isr & s->imr) != 0); +} + +uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr) +{ + mcf_uart_state *s = (mcf_uart_state *)opaque; + switch (addr & 0x3f) { + case 0x00: + return s->mr[s->current_mr]; + case 0x04: + return s->sr; + case 0x0c: + { + uint8_t val; + int i; + + if (s->fifo_len == 0) + return 0; + + val = s->fifo[0]; + s->fifo_len--; + for (i = 0; i < s->fifo_len; i++) + s->fifo[i] = s->fifo[i + 1]; + s->sr &= ~MCF_UART_FFULL; + if (s->fifo_len == 0) + s->sr &= ~MCF_UART_RxRDY; + mcf_uart_update(s); + return val; + } + case 0x10: + /* TODO: Implement IPCR. */ + return 0; + case 0x14: + return s->isr; + case 0x18: + return s->bg1; + case 0x1c: + return s->bg2; + default: + return 0; + } +} + +/* Update TxRDY flag and set data if present and enabled. */ +static void mcf_uart_do_tx(mcf_uart_state *s) +{ + if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { + if (s->chr) + qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1); + s->sr |= MCF_UART_TxEMP; + } + if (s->tx_enabled) { + s->sr |= MCF_UART_TxRDY; + } else { + s->sr &= ~MCF_UART_TxRDY; + } +} + +static void mcf_do_command(mcf_uart_state *s, uint8_t cmd) +{ + /* Misc command. */ + switch ((cmd >> 4) & 3) { + case 0: /* No-op. */ + break; + case 1: /* Reset mode register pointer. */ + s->current_mr = 0; + break; + case 2: /* Reset receiver. */ + s->rx_enabled = 0; + s->fifo_len = 0; + s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL); + break; + case 3: /* Reset transmitter. */ + s->tx_enabled = 0; + s->sr |= MCF_UART_TxEMP; + s->sr &= ~MCF_UART_TxRDY; + break; + case 4: /* Reset error status. */ + break; + case 5: /* Reset break-change interrupt. */ + s->isr &= ~MCF_UART_DBINT; + break; + case 6: /* Start break. */ + case 7: /* Stop break. */ + break; + } + + /* Transmitter command. */ + switch ((cmd >> 2) & 3) { + case 0: /* No-op. */ + break; + case 1: /* Enable. */ + s->tx_enabled = 1; + mcf_uart_do_tx(s); + break; + case 2: /* Disable. */ + s->tx_enabled = 0; + mcf_uart_do_tx(s); + break; + case 3: /* Reserved. */ + fprintf(stderr, "mcf_uart: Bad TX command\n"); + break; + } + + /* Receiver command. */ + switch (cmd & 3) { + case 0: /* No-op. */ + break; + case 1: /* Enable. */ + s->rx_enabled = 1; + break; + case 2: + s->rx_enabled = 0; + break; + case 3: /* Reserved. */ + fprintf(stderr, "mcf_uart: Bad RX command\n"); + break; + } +} + +void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + mcf_uart_state *s = (mcf_uart_state *)opaque; + switch (addr & 0x3f) { + case 0x00: + s->mr[s->current_mr] = val; + s->current_mr = 1; + break; + case 0x04: + /* CSR is ignored. */ + break; + case 0x08: /* Command Register. */ + mcf_do_command(s, val); + break; + case 0x0c: /* Transmit Buffer. */ + s->sr &= ~MCF_UART_TxEMP; + s->tb = val; + mcf_uart_do_tx(s); + break; + case 0x10: + /* ACR is ignored. */ + break; + case 0x14: + s->imr = val; + break; + default: + break; + } + mcf_uart_update(s); +} + +static void mcf_uart_reset(mcf_uart_state *s) +{ + s->fifo_len = 0; + s->mr[0] = 0; + s->mr[1] = 0; + s->sr = MCF_UART_TxEMP; + s->tx_enabled = 0; + s->rx_enabled = 0; + s->isr = 0; + s->imr = 0; +} + +static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data) +{ + /* Break events overwrite the last byte if the fifo is full. */ + if (s->fifo_len == 4) + s->fifo_len--; + + s->fifo[s->fifo_len] = data; + s->fifo_len++; + s->sr |= MCF_UART_RxRDY; + if (s->fifo_len == 4) + s->sr |= MCF_UART_FFULL; + + mcf_uart_update(s); +} + +static void mcf_uart_event(void *opaque, int event) +{ + mcf_uart_state *s = (mcf_uart_state *)opaque; + + switch (event) { + case CHR_EVENT_BREAK: + s->isr |= MCF_UART_DBINT; + mcf_uart_push_byte(s, 0); + break; + default: + break; + } +} + +static int mcf_uart_can_receive(void *opaque) +{ + mcf_uart_state *s = (mcf_uart_state *)opaque; + + return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0; +} + +static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) +{ + mcf_uart_state *s = (mcf_uart_state *)opaque; + + mcf_uart_push_byte(s, buf[0]); +} + +void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) +{ + mcf_uart_state *s; + + s = qemu_mallocz(sizeof(mcf_uart_state)); + s->chr = chr; + s->irq = irq; + if (chr) { + qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, + mcf_uart_event, s); + } + mcf_uart_reset(s); + return s; +} + + +static CPUReadMemoryFunc *mcf_uart_readfn[] = { + mcf_uart_read, + mcf_uart_read, + mcf_uart_read +}; + +static CPUWriteMemoryFunc *mcf_uart_writefn[] = { + mcf_uart_write, + mcf_uart_write, + mcf_uart_write +}; + +void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq, + CharDriverState *chr) +{ + mcf_uart_state *s; + int iomemtype; + + s = mcf_uart_init(irq, chr); + iomemtype = cpu_register_io_memory(0, mcf_uart_readfn, + mcf_uart_writefn, s); + cpu_register_physical_memory(base, 0x40, iomemtype); +} diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index acbb51690..6f29d5e5c 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -59,6 +59,10 @@ typedef struct CPUM68KState { uint32_t pc; uint32_t sr; + /* SSP and USP. The current_sp is stored in aregs[7], the other here. */ + int current_sp; + uint32_t sp[2]; + /* Condition flags. */ uint32_t cc_op; uint32_t cc_dest; @@ -92,6 +96,7 @@ typedef struct CPUM68KState { uint32_t vbr; uint32_t mbar; uint32_t rambar0; + uint32_t cacr; uint32_t features; @@ -151,6 +156,12 @@ enum { #define SR_S 0x2000 #define SR_T 0x8000 +#define M68K_SSP 0 +#define M68K_USP 1 + +/* CACR fields are implementation defined, but some bits are common. */ +#define M68K_CACR_EUSP 0x10 + #define MACSR_PAV0 0x100 #define MACSR_OMC 0x080 #define MACSR_SU 0x040 @@ -167,6 +178,7 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name); void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); void m68k_set_macsr(CPUM68KState *env, uint32_t val); +void m68k_switch_sp(CPUM68KState *env); #define M68K_FPCR_PREC (1 << 6) @@ -179,6 +191,7 @@ enum m68k_features { M68K_FEATURE_CF_FPU, M68K_FEATURE_CF_MAC, M68K_FEATURE_CF_EMAC, + M68K_FEATURE_USP, M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */ M68K_FEATURE_WORD_INDEX /* word sized address index registers. */ }; diff --git a/target-m68k/helper.c b/target-m68k/helper.c index bdbc1de39..bb213a760 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -28,6 +28,7 @@ enum m68k_cpuid { M68K_CPUID_M5206, + M68K_CPUID_M5208, M68K_CPUID_CFV4E, M68K_CPUID_ANY, }; @@ -39,6 +40,7 @@ struct m68k_def_t { static m68k_def_t m68k_cpu_defs[] = { {"m5206", M68K_CPUID_M5206}, + {"m5208", M68K_CPUID_M5208}, {"cfv4e", M68K_CPUID_CFV4E}, {"any", M68K_CPUID_ANY}, {NULL, 0}, @@ -64,12 +66,18 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) case M68K_CPUID_M5206: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); break; + case M68K_CPUID_M5208: + m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); + m68k_set_feature(env, M68K_FEATURE_CF_EMAC); + m68k_set_feature(env, M68K_FEATURE_USP); + break; case M68K_CPUID_CFV4E: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); m68k_set_feature(env, M68K_FEATURE_CF_FPU); m68k_set_feature(env, M68K_FEATURE_CF_EMAC); + m68k_set_feature(env, M68K_FEATURE_USP); break; case M68K_CPUID_ANY: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); @@ -79,6 +87,7 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) /* MAC and EMAC are mututally exclusive, so pick EMAC. It's mostly backwards compatible. */ m68k_set_feature(env, M68K_FEATURE_CF_EMAC); + m68k_set_feature(env, M68K_FEATURE_USP); m68k_set_feature(env, M68K_FEATURE_EXT_FULL); break; } @@ -215,7 +224,11 @@ void helper_movec(CPUM68KState *env, int reg, uint32_t val) { switch (reg) { case 0x02: /* CACR */ - /* Ignored. */ + env->cacr = val; + m68k_switch_sp(env); + break; + case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */ + /* TODO: Implement Access Control Registers. */ break; case 0x801: /* VBR */ env->vbr = val; @@ -261,6 +274,17 @@ void m68k_set_macsr(CPUM68KState *env, uint32_t val) env->macsr = val; } +void m68k_switch_sp(CPUM68KState *env) +{ + int new_sp; + + env->sp[env->current_sp] = env->aregs[7]; + new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) + ? M68K_SSP : M68K_USP; + env->aregs[7] = env->sp[new_sp]; + env->current_sp = new_sp; +} + /* MMU */ /* TODO: This will need fixing once the MMU is implemented. */ diff --git a/target-m68k/op.c b/target-m68k/op.c index febfe034c..932c99435 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -478,6 +478,13 @@ OP(fp_result) FORCE_RET(); } +OP(set_sr) +{ + env->sr = get_op(PARAM1); + m68k_switch_sp(env); + FORCE_RET(); +} + OP(jmp) { GOTO_LABEL_PARAM(1); diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 8086238db..4c423ca98 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -87,6 +87,7 @@ static void do_rte(void) env->pc = ldl_kernel(sp + 4); sp |= (fmt >> 28) & 3; env->sr = fmt & 0xffff; + m68k_switch_sp(env); env->aregs[7] = sp + 8; } @@ -128,9 +129,6 @@ void do_interrupt(int is_hw) } } - /* TODO: Implement USP. */ - sp = env->aregs[7]; - vector = env->exception_index << 2; fmt |= 0x40000000; @@ -138,6 +136,15 @@ void do_interrupt(int is_hw) fmt |= vector << 16; fmt |= env->sr; + env->sr |= SR_S; + if (is_hw) { + env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); + env->sr &= ~SR_M; + } + m68k_switch_sp(env); + + sp = env->aregs[7]; + /* ??? This could cause MMU faults. */ sp &= ~3; sp -= 4; @@ -145,11 +152,6 @@ void do_interrupt(int is_hw) sp -= 4; stl_kernel(sp, fmt); env->aregs[7] = sp; - env->sr |= SR_S; - if (is_hw) { - env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); - env->sr &= ~SR_M; - } /* Jump to vector. */ env->pc = ldl_kernel(env->vbr + vector); } diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 1d32e8f0f..da3e72a47 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1345,7 +1345,7 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) gen_op_logic_cc(gen_im32(val & 0xf)); gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4)); if (!ccr_only) { - gen_op_mov32(QREG_SR, gen_im32(val & 0xff00)); + gen_op_set_sr(gen_im32(val & 0xff00)); } } @@ -1365,7 +1365,7 @@ static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only) gen_op_and32(src1, src1, gen_im32(1)); gen_op_update_xflag_tst(src1); if (!ccr_only) { - gen_op_and32(QREG_SR, reg, gen_im32(0xff00)); + gen_op_set_sr(reg); } } else if ((insn & 0x3f) == 0x3c) @@ -2797,8 +2797,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(trap, 4e40, fff0, CF_ISA_A); INSN(link, 4e50, fff8, CF_ISA_A); INSN(unlk, 4e58, fff8, CF_ISA_A); - INSN(move_to_usp, 4e60, fff8, CF_ISA_B); - INSN(move_from_usp, 4e68, fff8, CF_ISA_B); + INSN(move_to_usp, 4e60, fff8, USP); + INSN(move_from_usp, 4e68, fff8, USP); INSN(nop, 4e71, ffff, CF_ISA_A); INSN(stop, 4e72, ffff, CF_ISA_A); INSN(rte, 4e73, ffff, CF_ISA_A); @@ -3261,6 +3261,7 @@ void cpu_reset(CPUM68KState *env) #if !defined (CONFIG_USER_ONLY) env->sr = 0x2700; #endif + m68k_switch_sp(env); /* ??? FP regs should be initialized to NaN. */ env->cc_op = CC_OP_FLAGS; /* TODO: We should set PC from the interrupt vector. */ diff --git a/vl.c b/vl.c index c949a4752..513ab4649 100644 --- a/vl.c +++ b/vl.c @@ -6972,6 +6972,7 @@ void register_machines(void) #elif defined(TARGET_ALPHA) /* XXX: TODO */ #elif defined(TARGET_M68K) + qemu_register_machine(&mcf5208evb_machine); qemu_register_machine(&an5206_machine); #else #error unsupported CPU diff --git a/vl.h b/vl.h index b881668fd..916daf391 100644 --- a/vl.h +++ b/vl.h @@ -1593,12 +1593,25 @@ void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); #include "hw/pxa.h" +/* mcf_uart.c */ +uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr); +void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val); +void *mcf_uart_init(qemu_irq irq, CharDriverState *chr); +void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq, + CharDriverState *chr); + +/* mcf_intc.c */ +qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env); + /* mcf5206.c */ qemu_irq *mcf5206_init(uint32_t base, CPUState *env); /* an5206.c */ extern QEMUMachine an5206_machine; +/* mcf5208.c */ +extern QEMUMachine mcf5208evb_machine; + #include "gdbstub.h" #endif /* defined(QEMU_TOOL) */ -- cgit v1.2.3 From d315c8886b72b6ff8abfd43471449ac59da1f35a Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 3 Jun 2007 12:35:08 +0000 Subject: Improve ColdFire CPU selection. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2925 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/cpu.h | 12 +++++++++--- target-m68k/helper.c | 9 +++++++-- target-m68k/translate.c | 25 +++++++++++++++++++------ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 6f29d5e5c..2d43354e2 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -184,14 +184,20 @@ void m68k_switch_sp(CPUM68KState *env); void do_m68k_semihosting(CPUM68KState *env, int nr); +/* There are 4 ColdFire core ISA revisions: A, A+, B and C. + Each feature covers the subset of instructions common to the + ISA revisions mentioned. */ + enum m68k_features { M68K_FEATURE_CF_ISA_A, - M68K_FEATURE_CF_ISA_B, - M68K_FEATURE_CF_ISA_C, + M68K_FEATURE_CF_ISA_B, /* (ISA B or C). */ + M68K_FEATURE_CF_ISA_APLUSC, /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C). */ + M68K_FEATURE_BRAL, /* Long unconditional branch. (ISA A+ or B). */ M68K_FEATURE_CF_FPU, M68K_FEATURE_CF_MAC, M68K_FEATURE_CF_EMAC, - M68K_FEATURE_USP, + M68K_FEATURE_CF_EMAC_B, /* Revision B EMAC (dual accumulate). */ + M68K_FEATURE_USP, /* User Stack Pointer. (ISA A+, B or C). */ M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */ M68K_FEATURE_WORD_INDEX /* word sized address index registers. */ }; diff --git a/target-m68k/helper.c b/target-m68k/helper.c index bb213a760..13305220a 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -68,13 +68,15 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) break; case M68K_CPUID_M5208: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); + m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC); + m68k_set_feature(env, M68K_FEATURE_BRAL); m68k_set_feature(env, M68K_FEATURE_CF_EMAC); m68k_set_feature(env, M68K_FEATURE_USP); break; case M68K_CPUID_CFV4E: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); - m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); + m68k_set_feature(env, M68K_FEATURE_BRAL); m68k_set_feature(env, M68K_FEATURE_CF_FPU); m68k_set_feature(env, M68K_FEATURE_CF_EMAC); m68k_set_feature(env, M68K_FEATURE_USP); @@ -82,13 +84,16 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) case M68K_CPUID_ANY: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); - m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); + m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC); + m68k_set_feature(env, M68K_FEATURE_BRAL); m68k_set_feature(env, M68K_FEATURE_CF_FPU); /* MAC and EMAC are mututally exclusive, so pick EMAC. It's mostly backwards compatible. */ m68k_set_feature(env, M68K_FEATURE_CF_EMAC); + m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B); m68k_set_feature(env, M68K_FEATURE_USP); m68k_set_feature(env, M68K_FEATURE_EXT_FULL); + m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); break; } diff --git a/target-m68k/translate.c b/target-m68k/translate.c index da3e72a47..1c0e43135 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2473,6 +2473,10 @@ DISAS_INSN(mac) acc = ((insn >> 7) & 1) | ((ext >> 3) & 2); dual = ((insn & 0x30) != 0 && (ext & 3) != 0); + if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) { + disas_undef(s, insn); + return; + } if (insn & 0x30) { /* MAC with load. */ tmp = gen_lea(s, insn, OS_LONG); @@ -2745,20 +2749,21 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) Later insn override earlier ones. */ void register_m68k_insns (CPUM68KState *env) { -#define INSN(name, opcode, mask, feature) \ +#define INSN(name, opcode, mask, feature) do { \ if (m68k_feature(env, M68K_FEATURE_##feature)) \ - register_opcode(disas_##name, 0x##opcode, 0x##mask) + register_opcode(disas_##name, 0x##opcode, 0x##mask); \ + } while(0) INSN(undef, 0000, 0000, CF_ISA_A); INSN(arith_im, 0080, fff8, CF_ISA_A); - INSN(bitrev, 00c0, fff8, CF_ISA_C); + INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC); INSN(bitop_reg, 0100, f1c0, CF_ISA_A); INSN(bitop_reg, 0140, f1c0, CF_ISA_A); INSN(bitop_reg, 0180, f1c0, CF_ISA_A); INSN(bitop_reg, 01c0, f1c0, CF_ISA_A); INSN(arith_im, 0280, fff8, CF_ISA_A); - INSN(byterev, 02c0, fff8, CF_ISA_A); + INSN(byterev, 02c0, fff8, CF_ISA_APLUSC); INSN(arith_im, 0480, fff8, CF_ISA_A); - INSN(ff1, 04c0, fff8, CF_ISA_C); + INSN(ff1, 04c0, fff8, CF_ISA_APLUSC); INSN(arith_im, 0680, fff8, CF_ISA_A); INSN(bitop_im, 0800, ffc0, CF_ISA_A); INSN(bitop_im, 0840, ffc0, CF_ISA_A); @@ -2769,7 +2774,7 @@ void register_m68k_insns (CPUM68KState *env) INSN(move, 1000, f000, CF_ISA_A); INSN(move, 2000, f000, CF_ISA_A); INSN(move, 3000, f000, CF_ISA_A); - INSN(strldsr, 40e7, ffff, CF_ISA_A); + INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC); INSN(negx, 4080, fff8, CF_ISA_A); INSN(move_from_sr, 40c0, fff8, CF_ISA_A); INSN(lea, 41c0, f1c0, CF_ISA_A); @@ -2810,7 +2815,15 @@ void register_m68k_insns (CPUM68KState *env) INSN(scc, 50c0, f0f8, CF_ISA_A); INSN(addsubq, 5080, f1c0, CF_ISA_A); INSN(tpf, 51f8, fff8, CF_ISA_A); + + /* Branch instructions. */ INSN(branch, 6000, f000, CF_ISA_A); + /* Disable long branch instructions, then add back the ones we want. */ + INSN(undef, 60ff, f0ff, CF_ISA_A); /* All long branches. */ + INSN(branch, 60ff, f0ff, CF_ISA_B); + INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */ + INSN(branch, 60ff, ffff, BRAL); + INSN(moveq, 7000, f100, CF_ISA_A); INSN(mvzs, 7100, f100, CF_ISA_B); INSN(or, 8000, f000, CF_ISA_A); -- cgit v1.2.3 From 6d9db39cd9c31084ab782f6ffd2d67e606fb0802 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 3 Jun 2007 12:54:38 +0000 Subject: MCF5208 timer fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2926 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mcf5208.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 49108e092..886688f28 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -62,9 +62,9 @@ static void m5208_timer_write(m5208_timer_state *s, int offset, prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT); ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale); if (s->pcsr & PCSR_RLD) - limit = 0xffff; - else limit = s->pmr; + else + limit = 0xffff; ptimer_set_limit(s->timer, limit, 0); if (s->pcsr & PCSR_EN) @@ -73,9 +73,12 @@ static void m5208_timer_write(m5208_timer_state *s, int offset, case 2: s->pmr = value; s->pcsr &= ~PCSR_PIF; - if (s->pcsr & PCSR_RLD) - value = 0xffff; - ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW); + if ((s->pcsr & PCSR_RLD) == 0) { + if (s->pcsr & PCSR_OVW) + ptimer_set_count(s->timer, value); + } else { + ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW); + } break; case 4: break; -- cgit v1.2.3 From e91c8a778349982eb49fd319ab6506911e2d837e Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 13:35:16 +0000 Subject: Spelling fixes, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2927 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/mmap.c | 2 +- disas.c | 2 +- exec.c | 2 +- hw/cirrus_vga.c | 2 +- hw/cuda.c | 4 ++-- hw/ne2000.c | 6 +++--- hw/scsi-disk.c | 2 +- hw/vga.c | 2 +- linux-user/elfload.c | 4 ++-- sdl.c | 3 ++- target-i386/translate.c | 2 +- 11 files changed, 16 insertions(+), 15 deletions(-) diff --git a/darwin-user/mmap.c b/darwin-user/mmap.c index ada613d36..b4055abe1 100644 --- a/darwin-user/mmap.c +++ b/darwin-user/mmap.c @@ -199,7 +199,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot, if (!(flags & MAP_FIXED)) { #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) - /* tell the kenel to search at the same place as i386 */ + /* tell the kernel to search at the same place as i386 */ if (host_start == 0) { host_start = last_start; last_start += HOST_PAGE_ALIGN(len); diff --git a/disas.c b/disas.c index fd14f682a..2642c778d 100644 --- a/disas.c +++ b/disas.c @@ -134,7 +134,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info) } #endif -/* Disassemble this for me please... (debugging). 'flags' has teh following +/* Disassemble this for me please... (debugging). 'flags' has the following values: i386 - nonzero means 16 bit code arm - nonzero means thumb code diff --git a/exec.c b/exec.c index 61d8f61ab..0e415a5e9 100644 --- a/exec.c +++ b/exec.c @@ -1220,7 +1220,7 @@ CPULogItem cpu_log_items[] = { { CPU_LOG_EXEC, "exec", "show trace before each executed TB (lots of logs)" }, { CPU_LOG_TB_CPU, "cpu", - "show CPU state before bloc translation" }, + "show CPU state before block translation" }, #ifdef TARGET_I386 { CPU_LOG_PCALL, "pcall", "show protected mode far calls/returns/exceptions" }, diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 2cbafe174..e5b0cfb65 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2784,7 +2784,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0x09: case 0x0c: case 0x0d: - case 0x12: /* veritcal display end */ + case 0x12: /* vertical display end */ s->cr[s->cr_index] = val; break; diff --git a/hw/cuda.c b/hw/cuda.c index c29045078..dc143e205 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -445,9 +445,9 @@ static void cuda_update(CUDAState *s) cuda_update_irq(s); } else { if (!(s->last_b & TIP)) { - /* handle end of host to cuda transfert */ + /* handle end of host to cuda transfer */ packet_received = (s->data_out_index > 0); - /* always an IRQ at the end of transfert */ + /* always an IRQ at the end of transfer */ s->ifr |= SR_INT; cuda_update_irq(s); } diff --git a/hw/ne2000.c b/hw/ne2000.c index 1830ab548..1625c5538 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -325,7 +325,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->cmd = val; if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */ s->isr &= ~ENISR_RESET; - /* test specific case: zero length transfert */ + /* test specific case: zero length transfer */ if ((val & (E8390_RREAD | E8390_RWRITE)) && s->rcnt == 0) { s->isr |= ENISR_RDC; @@ -340,7 +340,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (index + s->tcnt <= NE2000_PMEM_END) { qemu_send_packet(s->vc, s->mem + index, s->tcnt); } - /* signal end of transfert */ + /* signal end of transfer */ s->tsr = ENTSR_PTX; s->isr |= ENISR_TX; s->cmd &= ~E8390_TRANS; @@ -550,7 +550,7 @@ static inline void ne2000_dma_update(NE2000State *s, int len) if (s->rcnt <= len) { s->rcnt = 0; - /* signal end of transfert */ + /* signal end of transfer */ s->isr |= ENISR_RDC; ne2000_update_irq(s); } else { diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 92f745726..384c098a0 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -489,7 +489,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) is_write = 1; break; case 0x35: - DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len); + DPRINTF("Synchronise cache (sector %d, count %d)\n", lba, len); bdrv_flush(s->bdrv); break; case 0x43: diff --git a/hw/vga.c b/hw/vga.c index 9dbbfe237..8661d00d3 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -346,7 +346,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0x09: case 0x0c: case 0x0d: - case 0x12: /* veritcal display end */ + case 0x12: /* vertical display end */ s->cr[s->cr_index] = val; break; default: diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c1306929c..c0845fe65 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -799,7 +799,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, #endif if (interp_elf_ex->e_type == ET_DYN) { - /* in order to avoid harcoding the interpreter load + /* in order to avoid hardcoding the interpreter load address in qemu, we allocate a big enough memory zone */ error = target_mmap(0, INTERP_MAP_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANON, @@ -1191,7 +1191,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, base, as well as whatever program they might try to exec. This is because the brk will follow the loader, and is not movable. */ /* NOTE: for qemu, we do a big mmap to get enough space - without harcoding any address */ + without hardcoding any address */ error = target_mmap(0, ET_DYN_MAP_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); diff --git a/sdl.c b/sdl.c index 6c30db146..dc11937cf 100644 --- a/sdl.c +++ b/sdl.c @@ -407,7 +407,8 @@ static void sdl_refresh(DisplayState *ds) case SDLK_END: keysym = QEMU_KEY_END; break; case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break; case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break; - case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break; case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break; + case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break; + case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break; default: break; } } diff --git a/target-i386/translate.c b/target-i386/translate.c index e36e03d82..96e72c9dd 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6431,7 +6431,7 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) opc_ptr = opc_buf + opc_buf_len; /* live_flags contains the flags needed by the next instructions - in the code. At the end of the bloc, we consider that all the + in the code. At the end of the block, we consider that all the flags are live. */ live_flags = CC_OSZAPC; while (opc_ptr > opc_buf) { -- cgit v1.2.3 From 4be456f1265f6c3e971920cdf567c070f2fb65d2 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 13:41:28 +0000 Subject: Documentation spelling fixes, by Mark Glines. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2928 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 41 +++++++++++++++++++++-------------------- qemu-img.texi | 2 +- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 3a4481b8e..ce77b8a00 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -368,7 +368,7 @@ for a list of available devices for your target. @item -net user[,vlan=n][,hostname=name] Use the user mode network stack which requires no administrator -priviledge to run. @option{hostname=name} can be used to specify the client +privilege to run. @option{hostname=name} can be used to specify the client hostname reported by the builtin DHCP server. @item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file] @@ -423,7 +423,8 @@ correct multicast setup for these hosts). @item mcast support is compatible with User Mode Linux (argument @option{eth@var{N}=mcast}), see @url{http://user-mode-linux.sf.net}. -@item Use @option{fd=h} to specify an already opened UDP multicast socket. +@item +Use @option{fd=h} to specify an already opened UDP multicast socket. @end enumerate Example: @@ -576,7 +577,7 @@ name pipe @var{filename} @item COMn [Windows only] Use host serial port @var{n} @item udp:[remote_host]:remote_port[@@[src_ip]:src_port] -This implements UDP Net Console. When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}. When not using a specifed @var{src_port} a random port is automatically chosen. +This implements UDP Net Console. When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}. When not using a specified @var{src_port} a random port is automatically chosen. If you just want a simple readonly console you can use @code{netcat} or @code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as: @@ -609,7 +610,7 @@ the TCP Net Console is sent to @var{host} at the @var{port}. If you use the @var{server} option QEMU will wait for a client socket application to connect to the port before continuing, unless the @code{nowait} option was specified. The @code{nodelay} option disables the Nagle buffering -algoritm. If @var{host} is omitted, 0.0.0.0 is assumed. Only +algorithm. If @var{host} is omitted, 0.0.0.0 is assumed. Only one TCP connection at a time is accepted. You can use @code{telnet} to connect to the corresponding character device. @table @code @@ -692,7 +693,7 @@ Output log in /tmp/qemu.log Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= @var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS translation mode (@var{t}=none, lba or auto). Usually QEMU can guess -all thoses parameters. This option is useful for old MS-DOS disk +all those parameters. This option is useful for old MS-DOS disk images. @item -L path @@ -929,7 +930,7 @@ data. Its syntax is: @option{/@{count@}@{format@}@{size@}} is the number of items to be dumped. @item format -can be x (hexa), d (signed decimal), u (unsigned decimal), o (octal), +can be x (hex), d (signed decimal), u (unsigned decimal), o (octal), c (char) or i (asm instruction). @item size @@ -1118,7 +1119,7 @@ devices. We describe here the usage for QEMU version >= 0.8.3. @subsubsection Linux On Linux, you can directly use the host device filename instead of a -disk image filename provided you have enough proviledge to access +disk image filename provided you have enough privileges to access it. For example, use @file{/dev/cdrom} to access to the CDROM or @file{/dev/fd0} for the floppy. @@ -1145,7 +1146,7 @@ line option or modify the device permissions accordingly). @table @code @item CD -The prefered syntax is the drive letter (e.g. @file{d:}). The +The preferred syntax is the drive letter (e.g. @file{d:}). The alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is supported as an alias to the first CDROM drive. @@ -1209,11 +1210,11 @@ What you should @emph{never} do: @node pcsys_network @section Network emulation -QEMU can simulate several networks cards (PCI or ISA cards on the PC +QEMU can simulate several network cards (PCI or ISA cards on the PC target) and can connect them to an arbitrary number of Virtual Local Area Networks (VLANs). Host TAP devices can be connected to any QEMU VLAN. VLAN can be connected between separate instances of QEMU to -simulate large networks. For simpler usage, a non priviledged user mode +simulate large networks. For simpler usage, a non privileged user mode network stack can replace the TAP device to have a basic network connection. @@ -1253,7 +1254,7 @@ so download OpenVPN from : @url{http://openvpn.net/}. By using the option @option{-net user} (default configuration if no @option{-net} option is specified), QEMU uses a completely user mode -network stack (you don't need root priviledge to use the virtual +network stack (you don't need root privilege to use the virtual network). The virtual network configuration is the following: @example @@ -1276,7 +1277,7 @@ the address 10.0.2.2 and verify that you got an address in the range 10.0.2.x from the QEMU virtual DHCP server. Note that @code{ping} is not supported reliably to the internet as it -would require root priviledges. It means you can only ping the local +would require root privileges. It means you can only ping the local router (10.0.2.2). When using the built-in TFTP server, the router is also the TFTP @@ -1465,7 +1466,7 @@ cannot simulate exactly. When using a 2.6 guest Linux kernel, verify that the 4G/4G patch is not activated because QEMU is slower with this patch. The QEMU Accelerator Module is also much slower in this case. Earlier Fedora -Core 3 Linux kernel (< 2.6.9-1.724_FC3) were known to incorporte this +Core 3 Linux kernel (< 2.6.9-1.724_FC3) were known to incorporate this patch by default. Newer kernels don't have it. @subsection Windows @@ -1547,7 +1548,7 @@ problem. QEMU is a generic emulator and it emulates many non PC machines. Most of the options are similar to the PC emulator. The -differences are mentionned in the following sections. +differences are mentioned in the following sections. @menu * QEMU PowerPC System emulator:: @@ -1760,8 +1761,8 @@ PL050 KMI with PS/2 keyboard and mouse. @item PCI host bridge. Note the emulated PCI bridge only provides access to PCI memory space. It does not provide access to PCI IO space. -This means some devices (eg. ne2k_pci NIC) are not useable, and others -(eg. rtl8139 NIC) are only useable when the guest drivers use the memory +This means some devices (eg. ne2k_pci NIC) are not usable, and others +(eg. rtl8139 NIC) are only usable when the guest drivers use the memory mapped control registers. @item PCI OHCI USB controller. @@ -1859,9 +1860,9 @@ The following OS are supported in user space emulation: @itemize @minus @item -Linux (refered as qemu-linux-user) +Linux (referred as qemu-linux-user) @item -Mac OS X/Darwin (refered as qemu-darwin-user) +Mac OS X/Darwin (referred as qemu-darwin-user) @end itemize @node Linux User space emulator @@ -2119,7 +2120,7 @@ in particular on x86 ones, @emph{gcc 4.x is not supported}. If your Linux distribution includes a gcc 4.x compiler, you can usually install an older version (it is invoked by @code{gcc32} or @code{gcc34}). The QEMU configure script automatically probes for -these older versions so that usally you don't have to do anything. +these older versions so that usually you don't have to do anything. @node Windows @section Windows @@ -2171,7 +2172,7 @@ Configure QEMU for Windows cross compilation: ./configure --enable-mingw32 @end example If necessary, you can change the cross-prefix according to the prefix -choosen for the MinGW tools with --cross-prefix. You can also use +chosen for the MinGW tools with --cross-prefix. You can also use --prefix to set the Win32 install path. @item You can install QEMU in the installation directory by typing diff --git a/qemu-img.texi b/qemu-img.texi index 1f01dce16..bf49ec99d 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -89,7 +89,7 @@ Commit the changes recorded in @var{filename} in its base image. @item convert [-c] [-e] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename} Convert the disk image @var{filename} to disk image @var{output_filename} -using format @var{output_fmt}. It can be optionnaly encrypted +using format @var{output_fmt}. It can be optionally encrypted (@code{-e} option) or compressed (@code{-c} option). Only the format @code{qcow} supports encryption or compression. The -- cgit v1.2.3 From 3eb6b04433a337068eb90030c07d43012a28a54f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 14:26:27 +0000 Subject: Semaphore structure mapping, by Stuart Anderson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2929 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/alpha/syscall.h | 74 ---------------- linux-user/i386/syscall.h | 76 ----------------- linux-user/ppc/syscall.h | 76 ----------------- linux-user/syscall.c | 206 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 203 insertions(+), 229 deletions(-) diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h index def680e5a..643581788 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/syscall.h @@ -38,78 +38,4 @@ struct target_pt_regs { target_ulong unique; }; -#define TARGET_SEMOP 1 -#define TARGET_SEMGET 2 -#define TARGET_SEMCTL 3 -#define TARGET_MSGSND 11 -#define TARGET_MSGRCV 12 -#define TARGET_MSGGET 13 -#define TARGET_MSGCTL 14 -#define TARGET_SHMAT 21 -#define TARGET_SHMDT 22 -#define TARGET_SHMGET 23 -#define TARGET_SHMCTL 24 - -struct target_msgbuf { - int mtype; - char mtext[1]; -}; - -struct target_ipc_kludge { - unsigned int msgp; /* Really (struct msgbuf *) */ - int msgtyp; -}; - -struct target_ipc_perm { - int key; - unsigned short uid; - unsigned short gid; - unsigned short cuid; - unsigned short cgid; - unsigned short mode; - unsigned short seq; -}; - -struct target_msqid_ds { - struct target_ipc_perm msg_perm; - unsigned int msg_first; /* really struct target_msg* */ - unsigned int msg_last; /* really struct target_msg* */ - unsigned int msg_stime; /* really target_time_t */ - unsigned int msg_rtime; /* really target_time_t */ - unsigned int msg_ctime; /* really target_time_t */ - unsigned int wwait; /* really struct wait_queue* */ - unsigned int rwait; /* really struct wait_queue* */ - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - unsigned short msg_lspid; - unsigned short msg_lrpid; -}; - -struct target_shmid_ds { - struct target_ipc_perm shm_perm; - int shm_segsz; - unsigned int shm_atime; /* really target_time_t */ - unsigned int shm_dtime; /* really target_time_t */ - unsigned int shm_ctime; /* really target_time_t */ - unsigned short shm_cpid; - unsigned short shm_lpid; - short shm_nattch; - unsigned short shm_npages; - unsigned long *shm_pages; - void *attaches; /* really struct shm_desc * */ -}; - -#define TARGET_IPC_RMID 0 -#define TARGET_IPC_SET 1 -#define TARGET_IPC_STAT 2 - -union target_semun { - int val; - unsigned int buf; /* really struct semid_ds * */ - unsigned int array; /* really unsigned short * */ - unsigned int __buf; /* really struct seminfo * */ - unsigned int __pad; /* really void* */ -}; - #define UNAME_MACHINE "alpha" diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index cc0942b81..6e288b804 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -142,80 +142,4 @@ struct target_vm86plus_struct { struct target_vm86plus_info_struct vm86plus; }; -/* ipcs */ - -#define TARGET_SEMOP 1 -#define TARGET_SEMGET 2 -#define TARGET_SEMCTL 3 -#define TARGET_MSGSND 11 -#define TARGET_MSGRCV 12 -#define TARGET_MSGGET 13 -#define TARGET_MSGCTL 14 -#define TARGET_SHMAT 21 -#define TARGET_SHMDT 22 -#define TARGET_SHMGET 23 -#define TARGET_SHMCTL 24 - -struct target_msgbuf { - int mtype; - char mtext[1]; -}; - -struct target_ipc_kludge { - unsigned int msgp; /* Really (struct msgbuf *) */ - int msgtyp; -}; - -struct target_ipc_perm { - int key; - unsigned short uid; - unsigned short gid; - unsigned short cuid; - unsigned short cgid; - unsigned short mode; - unsigned short seq; -}; - -struct target_msqid_ds { - struct target_ipc_perm msg_perm; - unsigned int msg_first; /* really struct target_msg* */ - unsigned int msg_last; /* really struct target_msg* */ - unsigned int msg_stime; /* really target_time_t */ - unsigned int msg_rtime; /* really target_time_t */ - unsigned int msg_ctime; /* really target_time_t */ - unsigned int wwait; /* really struct wait_queue* */ - unsigned int rwait; /* really struct wait_queue* */ - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - unsigned short msg_lspid; - unsigned short msg_lrpid; -}; - -struct target_shmid_ds { - struct target_ipc_perm shm_perm; - int shm_segsz; - unsigned int shm_atime; /* really target_time_t */ - unsigned int shm_dtime; /* really target_time_t */ - unsigned int shm_ctime; /* really target_time_t */ - unsigned short shm_cpid; - unsigned short shm_lpid; - short shm_nattch; - unsigned short shm_npages; - unsigned long *shm_pages; - void *attaches; /* really struct shm_desc * */ -}; - -#define TARGET_IPC_RMID 0 -#define TARGET_IPC_SET 1 -#define TARGET_IPC_STAT 2 - -union target_semun { - int val; - unsigned int buf; /* really struct semid_ds * */ - unsigned int array; /* really unsigned short * */ - unsigned int __buf; /* really struct seminfo * */ - unsigned int __pad; /* really void* */ -}; - #define UNAME_MACHINE "i686" diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index eea8a7c9a..d150af44c 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -51,80 +51,4 @@ struct target_revectored_struct { * flags masks */ -/* ipcs */ - -#define TARGET_SEMOP 1 -#define TARGET_SEMGET 2 -#define TARGET_SEMCTL 3 -#define TARGET_MSGSND 11 -#define TARGET_MSGRCV 12 -#define TARGET_MSGGET 13 -#define TARGET_MSGCTL 14 -#define TARGET_SHMAT 21 -#define TARGET_SHMDT 22 -#define TARGET_SHMGET 23 -#define TARGET_SHMCTL 24 - -struct target_msgbuf { - int mtype; - char mtext[1]; -}; - -struct target_ipc_kludge { - unsigned int msgp; /* Really (struct msgbuf *) */ - int msgtyp; -}; - -struct target_ipc_perm { - int key; - unsigned short uid; - unsigned short gid; - unsigned short cuid; - unsigned short cgid; - unsigned short mode; - unsigned short seq; -}; - -struct target_msqid_ds { - struct target_ipc_perm msg_perm; - unsigned int msg_first; /* really struct target_msg* */ - unsigned int msg_last; /* really struct target_msg* */ - unsigned int msg_stime; /* really target_time_t */ - unsigned int msg_rtime; /* really target_time_t */ - unsigned int msg_ctime; /* really target_time_t */ - unsigned int wwait; /* really struct wait_queue* */ - unsigned int rwait; /* really struct wait_queue* */ - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - unsigned short msg_lspid; - unsigned short msg_lrpid; -}; - -struct target_shmid_ds { - struct target_ipc_perm shm_perm; - int shm_segsz; - unsigned int shm_atime; /* really target_time_t */ - unsigned int shm_dtime; /* really target_time_t */ - unsigned int shm_ctime; /* really target_time_t */ - unsigned short shm_cpid; - unsigned short shm_lpid; - short shm_nattch; - unsigned short shm_npages; - unsigned long *shm_pages; - void *attaches; /* really struct shm_desc * */ -}; - -#define TARGET_IPC_RMID 0 -#define TARGET_IPC_SET 1 -#define TARGET_IPC_STAT 2 - -union target_semun { - int val; - unsigned int buf; /* really struct semid_ds * */ - unsigned int array; /* really unsigned short * */ - unsigned int __buf; /* really struct seminfo * */ - unsigned int __pad; /* really void* */ -}; - #define UNAME_MACHINE "ppc" diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1ec81ce5b..5d6bf8e94 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1230,12 +1230,213 @@ static struct shm_region { uint32_t size; } shm_regions[N_SHM_REGIONS]; +struct target_ipc_perm +{ + target_long __key; + target_ulong uid; + target_ulong gid; + target_ulong cuid; + target_ulong cgid; + unsigned short int mode; + unsigned short int __pad1; + unsigned short int __seq; + unsigned short int __pad2; + target_ulong __unused1; + target_ulong __unused2; +}; + +struct target_semid_ds +{ + struct target_ipc_perm sem_perm; + target_ulong sem_otime; + target_ulong __unused1; + target_ulong sem_ctime; + target_ulong __unused2; + target_ulong sem_nsems; + target_ulong __unused3; + target_ulong __unused4; +}; + +static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, + target_ulong target_addr) +{ + struct target_ipc_perm *target_ip; + struct target_semid_ds *target_sd; + + lock_user_struct(target_sd, target_addr, 1); + target_ip=&(target_sd->sem_perm); + host_ip->__key = tswapl(target_ip->__key); + host_ip->uid = tswapl(target_ip->uid); + host_ip->gid = tswapl(target_ip->gid); + host_ip->cuid = tswapl(target_ip->cuid); + host_ip->cgid = tswapl(target_ip->cgid); + host_ip->mode = tswapl(target_ip->mode); + unlock_user_struct(target_sd, target_addr, 0); +} + +static inline void host_to_target_ipc_perm(target_ulong target_addr, + struct ipc_perm *host_ip) +{ + struct target_ipc_perm *target_ip; + struct target_semid_ds *target_sd; + + lock_user_struct(target_sd, target_addr, 0); + target_ip = &(target_sd->sem_perm); + target_ip->__key = tswapl(host_ip->__key); + target_ip->uid = tswapl(host_ip->uid); + target_ip->gid = tswapl(host_ip->gid); + target_ip->cuid = tswapl(host_ip->cuid); + target_ip->cgid = tswapl(host_ip->cgid); + target_ip->mode = tswapl(host_ip->mode); + unlock_user_struct(target_sd, target_addr, 1); +} + +static inline void target_to_host_semid_ds(struct semid_ds *host_sd, + target_ulong target_addr) +{ + struct target_semid_ds *target_sd; + + lock_user_struct(target_sd, target_addr, 1); + target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr); + host_sd->sem_nsems = tswapl(target_sd->sem_nsems); + host_sd->sem_otime = tswapl(target_sd->sem_otime); + host_sd->sem_ctime = tswapl(target_sd->sem_ctime); + unlock_user_struct(target_sd, target_addr, 0); +} + +static inline void host_to_target_semid_ds(target_ulong target_addr, + struct semid_ds *host_sd) +{ + struct target_semid_ds *target_sd; + + lock_user_struct(target_sd, target_addr, 0); + host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)); + target_sd->sem_nsems = tswapl(host_sd->sem_nsems); + target_sd->sem_otime = tswapl(host_sd->sem_otime); + target_sd->sem_ctime = tswapl(host_sd->sem_ctime); + unlock_user_struct(target_sd, target_addr, 1); +} + union semun { int val; - struct senid_ds *buf; + struct semid_ds *buf; unsigned short *array; }; +union target_semun { + int val; + target_long buf; + unsigned short int *array; +}; + +static inline void target_to_host_semun(unsigned long cmd, + union semun *host_su, + target_ulong target_addr, + struct semid_ds *ds) +{ + union target_semun *target_su; + + switch( cmd ) { + case IPC_STAT: + case IPC_SET: + lock_user_struct(target_su, target_addr, 1); + target_to_host_semid_ds(ds,target_su->buf); + host_su->buf = ds; + unlock_user_struct(target_su, target_addr, 0); + break; + case GETVAL: + case SETVAL: + lock_user_struct(target_su, target_addr, 1); + host_su->val = tswapl(target_su->val); + unlock_user_struct(target_su, target_addr, 0); + break; + case GETALL: + case SETALL: + lock_user_struct(target_su, target_addr, 1); + *host_su->array = tswap16(*target_su->array); + unlock_user_struct(target_su, target_addr, 0); + break; + default: + gemu_log("semun operation not fully supported: %d\n", (int)cmd); + } +} + +static inline void host_to_target_semun(unsigned long cmd, + target_ulong target_addr, + union semun *host_su, + struct semid_ds *ds) +{ + union target_semun *target_su; + + switch( cmd ) { + case IPC_STAT: + case IPC_SET: + lock_user_struct(target_su, target_addr, 0); + host_to_target_semid_ds(target_su->buf,ds); + unlock_user_struct(target_su, target_addr, 1); + break; + case GETVAL: + case SETVAL: + lock_user_struct(target_su, target_addr, 0); + target_su->val = tswapl(host_su->val); + unlock_user_struct(target_su, target_addr, 1); + break; + case GETALL: + case SETALL: + lock_user_struct(target_su, target_addr, 0); + *target_su->array = tswap16(*host_su->array); + unlock_user_struct(target_su, target_addr, 1); + break; + default: + gemu_log("semun operation not fully supported: %d\n", (int)cmd); + } +} + +static inline long do_semctl(long first, long second, long third, long ptr) +{ + union semun arg; + struct semid_ds dsarg; + int cmd = third&0xff; + long ret = 0; + + switch( cmd ) { + case GETVAL: + target_to_host_semun(cmd,&arg,ptr,&dsarg); + ret = get_errno(semctl(first, second, cmd, arg)); + host_to_target_semun(cmd,ptr,&arg,&dsarg); + break; + case SETVAL: + target_to_host_semun(cmd,&arg,ptr,&dsarg); + ret = get_errno(semctl(first, second, cmd, arg)); + host_to_target_semun(cmd,ptr,&arg,&dsarg); + break; + case GETALL: + target_to_host_semun(cmd,&arg,ptr,&dsarg); + ret = get_errno(semctl(first, second, cmd, arg)); + host_to_target_semun(cmd,ptr,&arg,&dsarg); + break; + case SETALL: + target_to_host_semun(cmd,&arg,ptr,&dsarg); + ret = get_errno(semctl(first, second, cmd, arg)); + host_to_target_semun(cmd,ptr,&arg,&dsarg); + break; + case IPC_STAT: + target_to_host_semun(cmd,&arg,ptr,&dsarg); + ret = get_errno(semctl(first, second, cmd, arg)); + host_to_target_semun(cmd,ptr,&arg,&dsarg); + break; + case IPC_SET: + target_to_host_semun(cmd,&arg,ptr,&dsarg); + ret = get_errno(semctl(first, second, cmd, arg)); + host_to_target_semun(cmd,ptr,&arg,&dsarg); + break; + default: + ret = get_errno(semctl(first, second, cmd, arg)); + } + + return ret; +} + /* ??? This only works with linear mappings. */ static long do_ipc(long call, long first, long second, long third, long ptr, long fifth) @@ -1259,8 +1460,7 @@ static long do_ipc(long call, long first, long second, long third, break; case IPCOP_semctl: - ret = get_errno(semctl(first, second, third, ((union semun*)ptr)->val)); - + ret = do_semctl(first, second, third, ptr); break; case IPCOP_semtimedop: -- cgit v1.2.3 From 1bc012f65a9b269ec373ca7586032c205d112d8a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 14:27:49 +0000 Subject: IPC message translation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2930 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 12 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5d6bf8e94..e380bc763 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1437,6 +1437,117 @@ static inline long do_semctl(long first, long second, long third, long ptr) return ret; } +struct target_msqid_ds +{ + struct target_ipc_perm msg_perm; + target_ulong msg_stime; + target_ulong __unused1; + target_ulong msg_rtime; + target_ulong __unused2; + target_ulong msg_ctime; + target_ulong __unused3; + target_ulong __msg_cbytes; + target_ulong msg_qnum; + target_ulong msg_qbytes; + target_ulong msg_lspid; + target_ulong msg_lrpid; + target_ulong __unused4; + target_ulong __unused5; +}; + +static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, + target_ulong target_addr) +{ + struct target_msqid_ds *target_md; + + lock_user_struct(target_md, target_addr, 1); + target_to_host_ipc_perm(&(host_md->msg_perm),target_addr); + host_md->msg_stime = tswapl(target_md->msg_stime); + host_md->msg_rtime = tswapl(target_md->msg_rtime); + host_md->msg_ctime = tswapl(target_md->msg_ctime); + host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes); + host_md->msg_qnum = tswapl(target_md->msg_qnum); + host_md->msg_qbytes = tswapl(target_md->msg_qbytes); + host_md->msg_lspid = tswapl(target_md->msg_lspid); + host_md->msg_lrpid = tswapl(target_md->msg_lrpid); + unlock_user_struct(target_md, target_addr, 0); +} + +static inline void host_to_target_msqid_ds(target_ulong target_addr, + struct msqid_ds *host_md) +{ + struct target_msqid_ds *target_md; + + lock_user_struct(target_md, target_addr, 0); + host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)); + target_md->msg_stime = tswapl(host_md->msg_stime); + target_md->msg_rtime = tswapl(host_md->msg_rtime); + target_md->msg_ctime = tswapl(host_md->msg_ctime); + target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes); + target_md->msg_qnum = tswapl(host_md->msg_qnum); + target_md->msg_qbytes = tswapl(host_md->msg_qbytes); + target_md->msg_lspid = tswapl(host_md->msg_lspid); + target_md->msg_lrpid = tswapl(host_md->msg_lrpid); + unlock_user_struct(target_md, target_addr, 1); +} + +static inline long do_msgctl(long first, long second, long ptr) +{ + struct msqid_ds dsarg; + int cmd = second&0xff; + long ret = 0; + switch( cmd ) { + case IPC_STAT: + case IPC_SET: + target_to_host_msqid_ds(&dsarg,ptr); + ret = get_errno(msgctl(first, cmd, &dsarg)); + host_to_target_msqid_ds(ptr,&dsarg); + default: + ret = get_errno(msgctl(first, cmd, &dsarg)); + } + return ret; +} + +struct target_msgbuf { + target_ulong mtype; + char mtext[1]; +}; + +static inline long do_msgsnd(long msqid, long msgp, long msgsz, long msgflg) +{ + struct target_msgbuf *target_mb; + struct msgbuf *host_mb; + long ret = 0; + + lock_user_struct(target_mb,msgp,0); + host_mb = malloc(msgsz+sizeof(long)); + host_mb->mtype = tswapl(target_mb->mtype); + memcpy(host_mb->mtext,target_mb->mtext,msgsz); + ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg)); + free(host_mb); + unlock_user_struct(target_mb, msgp, 0); + + return ret; +} + +static inline long do_msgrcv(long msqid, long msgp, long msgsz, long msgtype, long msgflg) +{ + struct target_msgbuf *target_mb; + struct msgbuf *host_mb; + long ret = 0; + + lock_user_struct(target_mb, msgp, 0); + host_mb = malloc(msgsz+sizeof(long)); + ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg)); + if (ret > 0) + memcpy(target_mb->mtext, host_mb->mtext, ret); + target_mb->mtype = tswapl(host_mb->mtype); + free(host_mb); + unlock_user_struct(target_mb, msgp, 0); + + return ret; +} + /* ??? This only works with linear mappings. */ static long do_ipc(long call, long first, long second, long third, long ptr, long fifth) @@ -1473,27 +1584,27 @@ static long do_ipc(long call, long first, long second, long third, break; case IPCOP_msgsnd: - ret = get_errno(msgsnd(first, (struct msgbuf *) ptr, second, third)); + ret = do_msgsnd(first, ptr, second, third); break; case IPCOP_msgctl: - ret = get_errno(msgctl(first, second, (struct msqid_ds *) ptr)); + ret = do_msgctl(first, second, ptr); break; case IPCOP_msgrcv: - { - struct ipc_kludge - { - void *__unbounded msgp; - long int msgtyp; - }; + { + struct ipc_kludge + { + void *__unbounded msgp; + long int msgtyp; + }; - struct ipc_kludge *foo = (struct ipc_kludge *) ptr; - struct msgbuf *msgp = (struct msgbuf *) foo->msgp; + struct ipc_kludge *foo = (struct ipc_kludge *) ptr; + struct msgbuf *msgp = (struct msgbuf *) foo->msgp; - ret = get_errno(msgrcv(first, msgp, second, 0, third)); + ret = do_msgrcv(first, (long)msgp, second, 0, third); - } + } break; case IPCOP_shmat: -- cgit v1.2.3 From 187337f8b0ec0813dd3876d1efe37d415fb81c2e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 3 Jun 2007 15:19:33 +0000 Subject: Fix off-by-one memory region sizes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2931 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_gic.c | 4 ++-- hw/arm_sysctl.c | 2 +- hw/arm_timer.c | 4 ++-- hw/integratorcp.c | 6 +++--- hw/pl011.c | 2 +- hw/pl050.c | 2 +- hw/pl080.c | 2 +- hw/pl110.c | 2 +- hw/pl181.c | 2 +- hw/pl190.c | 2 +- hw/pxa2xx.c | 24 ++++++++++++------------ hw/pxa2xx_dma.c | 2 +- hw/pxa2xx_gpio.c | 2 +- hw/pxa2xx_lcd.c | 2 +- hw/pxa2xx_mmci.c | 2 +- hw/pxa2xx_pcmcia.c | 6 +++--- hw/pxa2xx_pic.c | 2 +- hw/pxa2xx_timer.c | 2 +- hw/spitz.c | 4 ++-- hw/usb-ohci.c | 2 +- hw/versatilepb.c | 2 +- 21 files changed, 39 insertions(+), 39 deletions(-) diff --git a/hw/arm_gic.c b/hw/arm_gic.c index eee5b7c72..250efad36 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -532,10 +532,10 @@ qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq) if (base != 0xffffffff) { iomemtype = cpu_register_io_memory(0, gic_cpu_readfn, gic_cpu_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); iomemtype = cpu_register_io_memory(0, gic_dist_readfn, gic_dist_writefn, s); - cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype); + cpu_register_physical_memory(base + 0x1000, 0x00001000, iomemtype); s->base = base; } else { s->base = 0; diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 90ea76e71..600889d38 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -202,7 +202,7 @@ void arm_sysctl_init(uint32_t base, uint32_t sys_id) s->sys_id = sys_id; iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn, arm_sysctl_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); /* ??? Save/restore. */ } diff --git a/hw/arm_timer.c b/hw/arm_timer.c index f98de1ff6..c0a0aa986 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -233,7 +233,7 @@ void sp804_init(uint32_t base, qemu_irq irq) s->timer[1] = arm_timer_init(1000000, qi[1]); iomemtype = cpu_register_io_memory(0, sp804_readfn, sp804_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); /* ??? Save/restore. */ } @@ -301,7 +301,7 @@ void icp_pit_init(uint32_t base, qemu_irq *pic, int irq) iomemtype = cpu_register_io_memory(0, icp_pit_readfn, icp_pit_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); /* ??? Save/restore. */ } diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 6572af8ec..119a4402a 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -257,7 +257,7 @@ static void integratorcm_init(int memsz, uint32_t flash_offset) iomemtype = cpu_register_io_memory(0, integratorcm_readfn, integratorcm_writefn, s); - cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype); + cpu_register_physical_memory(0x10000000, 0x00800000, iomemtype); integratorcm_do_remap(s, 1); /* ??? Save/restore. */ } @@ -390,7 +390,7 @@ static qemu_irq *icp_pic_init(uint32_t base, s->parent_fiq = parent_fiq; iomemtype = cpu_register_io_memory(0, icp_pic_readfn, icp_pic_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); + cpu_register_physical_memory(base, 0x00800000, iomemtype); /* ??? Save/restore. */ return qi; } @@ -454,7 +454,7 @@ static void icp_control_init(uint32_t base) s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state)); iomemtype = cpu_register_io_memory(0, icp_control_readfn, icp_control_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); + cpu_register_physical_memory(base, 0x00800000, iomemtype); s->base = base; /* ??? Save/restore. */ } diff --git a/hw/pl011.c b/hw/pl011.c index 29e551ad8..64b753019 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -232,7 +232,7 @@ void pl011_init(uint32_t base, qemu_irq irq, s = (pl011_state *)qemu_mallocz(sizeof(pl011_state)); iomemtype = cpu_register_io_memory(0, pl011_readfn, pl011_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); s->base = base; s->irq = irq; s->chr = chr; diff --git a/hw/pl050.c b/hw/pl050.c index 40274e1d8..521c9e611 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -131,7 +131,7 @@ void pl050_init(uint32_t base, qemu_irq irq, int is_mouse) s = (pl050_state *)qemu_mallocz(sizeof(pl050_state)); iomemtype = cpu_register_io_memory(0, pl050_readfn, pl050_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); s->base = base; s->irq = irq; s->is_mouse = is_mouse; diff --git a/hw/pl080.c b/hw/pl080.c index aab1cacb9..bc1a975d6 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -332,7 +332,7 @@ void *pl080_init(uint32_t base, qemu_irq irq, int nchannels) s = (pl080_state *)qemu_mallocz(sizeof(pl080_state)); iomemtype = cpu_register_io_memory(0, pl080_readfn, pl080_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); s->base = base; s->irq = irq; s->nchannels = nchannels; diff --git a/hw/pl110.c b/hw/pl110.c index 92a7e0bb6..7340d4b4a 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -407,7 +407,7 @@ void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, s = (pl110_state *)qemu_mallocz(sizeof(pl110_state)); iomemtype = cpu_register_io_memory(0, pl110_readfn, pl110_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); s->base = base; s->ds = ds; s->versatile = versatile; diff --git a/hw/pl181.c b/hw/pl181.c index cf731cce9..c0b89f775 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -432,7 +432,7 @@ void pl181_init(uint32_t base, BlockDriverState *bd, s = (pl181_state *)qemu_mallocz(sizeof(pl181_state)); iomemtype = cpu_register_io_memory(0, pl181_readfn, pl181_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); s->base = base; s->card = sd_init(bd); s->irq[0] = irq0; diff --git a/hw/pl190.c b/hw/pl190.c index 64385b89d..e36c4480f 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -239,7 +239,7 @@ qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq) s = (pl190_state *)qemu_mallocz(sizeof(pl190_state)); iomemtype = cpu_register_io_memory(0, pl190_readfn, pl190_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); qi = qemu_allocate_irqs(pl190_set_irq, s, 32); s->base = base; s->irq = irq; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 2f3a63a7b..1a7d4a741 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1725,7 +1725,7 @@ static struct pxa2xx_i2s_s *pxa2xx_i2s_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, pxa2xx_i2s_readfn, pxa2xx_i2s_writefn, s); - cpu_register_physical_memory(s->base & 0xfff00000, 0xfffff, iomemtype); + cpu_register_physical_memory(s->base & 0xfff00000, 0x100000, iomemtype); register_savevm("pxa2xx_i2s", base, 0, pxa2xx_i2s_save, pxa2xx_i2s_load, s); @@ -1988,7 +1988,7 @@ static struct pxa2xx_fir_s *pxa2xx_fir_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, pxa2xx_fir_readfn, pxa2xx_fir_writefn, s); - cpu_register_physical_memory(s->base, 0xfff, iomemtype); + cpu_register_physical_memory(s->base, 0x1000, iomemtype); if (chr) qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, @@ -2061,7 +2061,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->clkcfg = 0x00000009; /* Turbo mode active */ iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, pxa2xx_cm_writefn, s); - cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype); + cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); register_savevm("pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -2072,13 +2072,13 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn, pxa2xx_mm_writefn, s); - cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype); + cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); s->pm_base = 0x40f00000; iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, pxa2xx_pm_writefn, s); - cpu_register_physical_memory(s->pm_base, 0xff, iomemtype); + cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); for (i = 0; pxa27x_ssp[i].io_base; i ++); @@ -2093,7 +2093,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn, pxa2xx_ssp_writefn, &ssp[i]); - cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); + cpu_register_physical_memory(ssp[i].base, 0x1000, iomemtype); register_savevm("pxa2xx_ssp", i, 0, pxa2xx_ssp_save, pxa2xx_ssp_load, s); } @@ -2108,7 +2108,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->rtc_base = 0x40900000; iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, pxa2xx_rtc_writefn, s); - cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype); + cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype); pxa2xx_rtc_init(s); register_savevm("pxa2xx_rtc", 0, 0, pxa2xx_rtc_save, pxa2xx_rtc_load, s); @@ -2170,7 +2170,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->clkcfg = 0x00000009; /* Turbo mode active */ iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, pxa2xx_cm_writefn, s); - cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype); + cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); register_savevm("pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); @@ -2181,13 +2181,13 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn, pxa2xx_mm_writefn, s); - cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype); + cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); s->pm_base = 0x40f00000; iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, pxa2xx_pm_writefn, s); - cpu_register_physical_memory(s->pm_base, 0xff, iomemtype); + cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); for (i = 0; pxa255_ssp[i].io_base; i ++); @@ -2202,7 +2202,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn, pxa2xx_ssp_writefn, &ssp[i]); - cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype); + cpu_register_physical_memory(ssp[i].base, 0x1000, iomemtype); register_savevm("pxa2xx_ssp", i, 0, pxa2xx_ssp_save, pxa2xx_ssp_load, s); } @@ -2217,7 +2217,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->rtc_base = 0x40900000; iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, pxa2xx_rtc_writefn, s); - cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype); + cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype); pxa2xx_rtc_init(s); register_savevm("pxa2xx_rtc", 0, 0, pxa2xx_rtc_save, pxa2xx_rtc_load, s); diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 1a79c8d9a..53bce2e46 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -508,7 +508,7 @@ static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, pxa2xx_dma_readfn, pxa2xx_dma_writefn, s); - cpu_register_physical_memory(base, 0x0000ffff, iomemtype); + cpu_register_physical_memory(base, 0x00010000, iomemtype); register_savevm("pxa2xx_dma", 0, 0, pxa2xx_dma_save, pxa2xx_dma_load, s); diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 0e32329ed..b3db97490 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -308,7 +308,7 @@ struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn, pxa2xx_gpio_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); register_savevm("pxa2xx_gpio", 0, 0, pxa2xx_gpio_save, pxa2xx_gpio_load, s); diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 232effdb1..effeaa384 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -1026,7 +1026,7 @@ struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, iomemtype = cpu_register_io_memory(0, pxa2xx_lcdc_readfn, pxa2xx_lcdc_writefn, s); - cpu_register_physical_memory(base, 0x000fffff, iomemtype); + cpu_register_physical_memory(base, 0x00100000, iomemtype); graphic_console_init(ds, pxa2xx_update_display, pxa2xx_invalidate_display, pxa2xx_screen_dump, s); diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 2081b54db..ed548dbad 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -534,7 +534,7 @@ struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, pxa2xx_mmci_readfn, pxa2xx_mmci_writefn, s); - cpu_register_physical_memory(base, 0x000fffff, iomemtype); + cpu_register_physical_memory(base, 0x00100000, iomemtype); /* Instantiate the actual storage */ s->card = sd_init(sd_bdrv); diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index 586fd8c95..f1399f467 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -149,7 +149,7 @@ struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base) s->io_base = base | 0x00000000; iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_io_readfn, pxa2xx_pcmcia_io_writefn, s); - cpu_register_physical_memory(s->io_base, 0x03ffffff, iomemtype); + cpu_register_physical_memory(s->io_base, 0x04000000, iomemtype); /* Then next 64 MB is reserved */ @@ -157,13 +157,13 @@ struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base) s->attr_base = base | 0x08000000; iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_attr_readfn, pxa2xx_pcmcia_attr_writefn, s); - cpu_register_physical_memory(s->attr_base, 0x03ffffff, iomemtype); + cpu_register_physical_memory(s->attr_base, 0x04000000, iomemtype); /* Socket Common Memory Space */ s->common_base = base | 0x0c000000; iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_common_readfn, pxa2xx_pcmcia_common_writefn, s); - cpu_register_physical_memory(s->common_base, 0x03ffffff, iomemtype); + cpu_register_physical_memory(s->common_base, 0x04000000, iomemtype); if (base == 0x30000000) s->slot.slot_string = "PXA PC Card Socket 1"; diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index 77e0b6cef..c9012e8db 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -306,7 +306,7 @@ qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env) /* Enable IC memory-mapped registers access. */ iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn, pxa2xx_pic_writefn, s); - cpu_register_physical_memory(base, 0x000fffff, iomemtype); + cpu_register_physical_memory(base, 0x00100000, iomemtype); /* Enable IC coprocessor access. */ cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s); diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 284f53040..982420502 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -458,7 +458,7 @@ static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn, pxa2xx_timer_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); register_savevm("pxa2xx_timer", 0, 0, pxa2xx_timer_save, pxa2xx_timer_load, s); diff --git a/hw/spitz.c b/hw/spitz.c index 171dba2e9..590e1fc08 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -705,7 +705,7 @@ static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, iomemtype = cpu_register_io_memory(0, scoop_readfn, scoop_writefn, &s[0]); - cpu_register_physical_memory(s[0].target_base, 0xfff, iomemtype); + cpu_register_physical_memory(s[0].target_base, 0x1000, iomemtype); register_savevm("scoop", 0, 0, scoop_save, scoop_load, &s[0]); if (count < 2) @@ -713,7 +713,7 @@ static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, iomemtype = cpu_register_io_memory(0, scoop_readfn, scoop_writefn, &s[1]); - cpu_register_physical_memory(s[1].target_base, 0xfff, iomemtype); + cpu_register_physical_memory(s[1].target_base, 0x1000, iomemtype); register_savevm("scoop", 1, 0, scoop_save, scoop_load, &s[1]); return s; diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 680857956..99e072f87 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1345,5 +1345,5 @@ void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, OHCI_TYPE_PXA, "OHCI USB"); ohci->mem_base = base; - cpu_register_physical_memory(ohci->mem_base, 0xfff, ohci->mem); + cpu_register_physical_memory(ohci->mem_base, 0x1000, ohci->mem); } diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 5b1774a64..1cbd25b18 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -140,7 +140,7 @@ static qemu_irq *vpb_sic_init(uint32_t base, qemu_irq *parent, int irq) s->irq = irq; iomemtype = cpu_register_io_memory(0, vpb_sic_readfn, vpb_sic_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); + cpu_register_physical_memory(base, 0x00001000, iomemtype); /* ??? Save/restore. */ return qi; } -- cgit v1.2.3 From 6b078dfd60f160b038c60d8c2d290feec1b49548 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 15:31:32 +0000 Subject: Add __mips__to mmap specialcase. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2932 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index cbaa7ce2c..bfecb7a54 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -157,7 +157,7 @@ long target_mmap(target_ulong start, target_ulong len, int prot, target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; long host_start; #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ - defined(__ia64) + defined(__ia64) || defined(__mips__) static target_ulong last_start = 0x40000000; #elif defined(__CYGWIN__) /* Cygwin doesn't have a whole lot of address space. */ @@ -202,8 +202,8 @@ long target_mmap(target_ulong start, target_ulong len, int prot, if (!(flags & MAP_FIXED)) { #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ - defined(__ia64) || defined(__CYGWIN__) - /* tell the kenel to search at the same place as i386 */ + defined(__ia64) || defined(__mips__) || defined(__CYGWIN__) + /* tell the kernel to search at the same place as i386 */ if (real_start == 0) { real_start = last_start; last_start += HOST_PAGE_ALIGN(len); -- cgit v1.2.3 From 0458df244461788b4502698ac690824c6ed1381f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 15:33:32 +0000 Subject: Fix typo in comment. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2933 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/linuxload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 2d20c000d..34fa10d7c 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -1,4 +1,4 @@ -/* Code for loading Linux executables. Mostly linux kenrel code. */ +/* Code for loading Linux executables. Mostly linux kernel code. */ #include #include -- cgit v1.2.3 From fe834d041df9a14bcd965a3d2a2dc455c27b410e Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 17:08:32 +0000 Subject: Proper target format for qOffsets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2934 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index d346ad94f..2ec2f33f8 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -908,8 +908,11 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) if (strncmp(p, "Offsets", 7) == 0) { TaskState *ts = env->opaque; - sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset, - ts->info->data_offset, ts->info->data_offset); + sprintf(buf, + "Text=" TARGET_FMT_lx ";Data=" TARGET_FMT_lx ";Bss=" TARGET_FMT_lx, + ts->info->code_offset, + ts->info->data_offset, + ts->info->data_offset); put_packet(s, buf); break; } -- cgit v1.2.3 From 08ab123c2dba80cf6b7f0df563af14a7d902f759 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 17:10:43 +0000 Subject: Avoid compiler warning. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2935 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 08e0624db..77e3b4ec8 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -232,10 +232,12 @@ GEN_ST(l_c); GEN_LD(q_l); GEN_ST(q_c); +#if 0 /* currently unused */ GEN_LD(f); GEN_ST(f); GEN_LD(g); GEN_ST(g); +#endif /* 0 */ GEN_LD(s); GEN_ST(s); GEN_LD(t); -- cgit v1.2.3 From bfed01fc79cb2da1c6ca700bb0ce9238ce2974c7 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 17:44:37 +0000 Subject: Clean up of some target specifics in exec.c/cpu-exec.c. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2936 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 69 +++++-------------------------------------------- target-alpha/exec.h | 10 +++++++ target-arm/exec.h | 14 ++++++++++ target-i386/exec.h | 13 ++++++++++ target-i386/helper.c | 8 ------ target-m68k/exec.h | 10 +++++++ target-mips/exec.h | 27 +++++++++++++------ target-mips/op_helper.c | 4 --- target-ppc/exec.h | 10 +++++++ target-ppc/op_helper.c | 4 --- target-sh4/op_helper.c | 5 ---- target-sparc/exec.h | 10 +++++++ 12 files changed, 92 insertions(+), 92 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index c3d99d418..51cd2fae2 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -40,14 +40,14 @@ int tb_invalidated_flag; //#define DEBUG_EXEC //#define DEBUG_SIGNAL -#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K) || \ - defined(TARGET_ALPHA) -/* XXX: unify with i386 target */ void cpu_loop_exit(void) { + /* NOTE: the register at this point must be saved by hand because + longjmp restore them */ + regs_to_env(); longjmp(env->jmp_env, 1); } -#endif + #if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K)) #define reg_T2 #endif @@ -249,65 +249,8 @@ int cpu_exec(CPUState *env1) 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)) { - 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. We use EXITTB to silently wake CPU without causing an - actual interrupt. */ - 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; - } - } -#elif defined(TARGET_ALPHA) || defined(TARGET_M68K) - if (env1->halted) { - if (env1->interrupt_request & CPU_INTERRUPT_HARD) { - env1->halted = 0; - } else { - return EXCP_HALTED; - } - } -#endif + if (cpu_halted(env1) == EXCP_HALTED) + return EXCP_HALTED; cpu_single_env = env1; diff --git a/target-alpha/exec.h b/target-alpha/exec.h index f109160a5..32c27c735 100644 --- a/target-alpha/exec.h +++ b/target-alpha/exec.h @@ -79,4 +79,14 @@ int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); void do_interrupt (CPUState *env); +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + #endif /* !defined (__ALPHA_EXEC_H__) */ diff --git a/target-arm/exec.h b/target-arm/exec.h index d99dfa5f0..b25c7e2d4 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -48,6 +48,20 @@ static inline void regs_to_env(void) int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + /* An interrupt wakes the CPU even if the I and F CPSR bits are + set. We use EXITTB to silently wake CPU without causing an + actual interrupt. */ + if (env->interrupt_request & + (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" #endif diff --git a/target-i386/exec.h b/target-i386/exec.h index 377f7bd28..f1cf2b923 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -575,3 +575,16 @@ static inline void regs_to_env(void) env->regs[R_EDI] = EDI; #endif } + +static inline int cpu_halted(CPUState *env) { + /* handle exit of HALTED state */ + if (env->hflags & HF_HALTED_MASK) + return 0; + /* disable halt condition */ + if ((env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) { + env->hflags &= ~HF_HALTED_MASK; + return 0; + } + return EXCP_HALTED; +} diff --git a/target-i386/helper.c b/target-i386/helper.c index ef4b77e88..951fdc573 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -106,14 +106,6 @@ void cpu_unlock(void) spin_unlock(&global_cpu_lock); } -void cpu_loop_exit(void) -{ - /* NOTE: the register at this point must be saved by hand because - longjmp restore them */ - regs_to_env(); - longjmp(env->jmp_env, 1); -} - /* return non zero if error */ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, int selector) diff --git a/target-m68k/exec.h b/target-m68k/exec.h index 254f5581f..331844b41 100644 --- a/target-m68k/exec.h +++ b/target-m68k/exec.h @@ -49,3 +49,13 @@ float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1); void helper_movec(CPUM68KState *env, int reg, uint32_t val); void cpu_loop_exit(void); + +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} diff --git a/target-mips/exec.h b/target-mips/exec.h index 6d004102b..5b0c83384 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -56,14 +56,6 @@ register target_ulong T2 asm(AREG3); #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -static inline void env_to_regs(void) -{ -} - -static inline void regs_to_env(void) -{ -} - #ifdef TARGET_MIPS64 #if TARGET_LONG_BITS > HOST_LONG_BITS void do_dsll (void); @@ -240,4 +232,23 @@ FOP_PROTO(le) FOP_PROTO(ngt) #undef FOP_PROTO +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + if (env->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index da2864597..c169beb55 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -24,10 +24,6 @@ /*****************************************************************************/ /* Exceptions processing helpers */ -void cpu_loop_exit(void) -{ - longjmp(env->jmp_env, 1); -} void do_raise_exception_err (uint32_t exception, int error_code) { diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 4f5abe906..ee5183eb7 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -122,4 +122,14 @@ static inline void regs_to_env(void) int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + if (env->msr[MSR_EE] && (env->interrupt_request & CPU_INTERRUPT_HARD)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + #endif /* !defined (__PPC_H__) */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index ee46253c7..63180b61e 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -40,10 +40,6 @@ /*****************************************************************************/ /* Exceptions processing helpers */ -void cpu_loop_exit (void) -{ - longjmp(env->jmp_env, 1); -} void do_raise_exception_err (uint32_t exception, int error_code) { diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index f02fa588f..bf39921b4 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -20,11 +20,6 @@ #include #include "exec.h" -void cpu_loop_exit(void) -{ - longjmp(env->jmp_env, 1); -} - void do_raise_exception(void) { cpu_loop_exit(); diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 8a9fa89ec..0305a0498 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -115,4 +115,14 @@ static inline void regs_to_env(void) int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + if ((env->interrupt_request & CPU_INTERRUPT_HARD) && (env->psret != 0)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + #endif -- cgit v1.2.3 From ecb644f409b9bff0b72b0be8001b7d323b817392 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 18:45:53 +0000 Subject: Some more regs_to_env/envs_to_regs cleanup. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2937 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 51cd2fae2..4320f61e1 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -263,28 +263,27 @@ int cpu_exec(CPUState *env1) asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); #endif -#if defined(TARGET_I386) env_to_regs(); +#if defined(TARGET_I386) /* 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_ALPHA) +#elif defined(TARGET_ARM) +#elif defined(TARGET_PPC) #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) /* XXXXX */ -#elif defined(TARGET_ALPHA) - env_to_regs(); #else #error unsupported target CPU #endif @@ -522,32 +521,9 @@ int cpu_exec(CPUState *env1) } #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 + regs_to_env(); +#if defined(TARGET_I386) 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); -- cgit v1.2.3 From 50a518e3287f8838de3ff5854fe26bb542920c54 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 18:52:15 +0000 Subject: Add comment. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2938 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu-exec.c b/cpu-exec.c index 4320f61e1..4f7f215c0 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -710,7 +710,7 @@ int cpu_exec(CPUState *env1) cpu_loop_exit(); } #endif - } + } /* for(;;) */ } else { env_to_regs(); } -- cgit v1.2.3 From a8fcf883d9a15c88938d6bddbbb262091d79435f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 19:16:42 +0000 Subject: One day we might support MIPS16... git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2939 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/disas.c b/disas.c index 2642c778d..071642639 100644 --- a/disas.c +++ b/disas.c @@ -308,8 +308,8 @@ const char *lookup_symbol(target_ulong orig_addr) continue; addr = sym[i].st_value; -#ifdef TARGET_ARM - /* The bottom address bit marks a Thumb symbol. */ +#if defined(TARGET_ARM) || defined (TARGET_MIPS) + /* The bottom address bit marks a Thumb or MIPS16 symbol. */ addr &= ~(target_ulong)1; #endif if (orig_addr >= addr -- cgit v1.2.3 From 9467d44c4d5d9a2f1e0b4e3e0239320cbf81c1d2 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 21:02:38 +0000 Subject: Move target-specific defines to the target directories. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2940 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 71 ------------------------------------------------------ target-alpha/cpu.h | 6 +++++ target-arm/cpu.h | 7 ++++++ target-i386/cpu.h | 7 ++++++ target-m68k/cpu.h | 7 ++++++ target-mips/cpu.h | 6 +++++ target-ppc/cpu.h | 6 +++++ target-sh4/cpu.h | 6 +++++ target-sparc/cpu.h | 6 +++++ 9 files changed, 51 insertions(+), 71 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 5db290356..289d660f1 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -692,77 +692,6 @@ 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 - -#elif defined(TARGET_ALPHA) -#define CPUState CPUAlphaState -#define cpu_init cpu_alpha_init -#define cpu_exec cpu_alpha_exec -#define cpu_gen_code cpu_alpha_gen_code -#define cpu_signal_handler cpu_alpha_signal_handler - -#else - -#error unsupported target CPU - -#endif - -#endif /* SINGLE_CPU_DEFINES */ - CPUState *cpu_copy(CPUState *env); void cpu_dump_state(CPUState *env, FILE *f, diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 729d5876e..c79c5680a 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -300,6 +300,12 @@ struct CPUAlphaState { pal_handler_t *pal_handler; }; +#define CPUState CPUAlphaState +#define cpu_init cpu_alpha_init +#define cpu_exec cpu_alpha_exec +#define cpu_gen_code cpu_alpha_gen_code +#define cpu_signal_handler cpu_alpha_signal_handler + #include "cpu-all.h" enum { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 472380762..80727bb8a 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -285,6 +285,13 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, architecture revisions. Maybe an a configure option to disable them. */ #define TARGET_PAGE_BITS 10 #endif + +#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 + #include "cpu-all.h" #endif diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2b4295ae1..3a82426b8 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -661,6 +661,13 @@ static inline int cpu_get_time_fast(void) #endif #define TARGET_PAGE_BITS 12 + +#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 + #include "cpu-all.h" #endif /* CPU_I386_H */ diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 2d43354e2..b0e725d4a 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -216,6 +216,13 @@ void register_m68k_insns (CPUM68KState *env); /* Smallest TLB entry size is 1k. */ #define TARGET_PAGE_BITS 10 #endif + +#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 + #include "cpu-all.h" #endif diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 6dff8ef55..7650be48c 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -317,6 +317,12 @@ int mips_find_by_name (const unsigned char *name, mips_def_t **def); void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); int cpu_mips_register (CPUMIPSState *env, mips_def_t *def); +#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 + #include "cpu-all.h" /* Memory access type : diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index a25d30a62..6b627f26b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -899,6 +899,12 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address); int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp); int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); +#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 + #include "cpu-all.h" /*****************************************************************************/ diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index e844d690e..00ee06268 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -126,6 +126,12 @@ int cpu_sh4_signal_handler(int host_signum, void *pinfo, #include "softfloat.h" +#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 + #include "cpu-all.h" /* Memory access type */ diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 198ba54e1..9229ad4a7 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -302,6 +302,12 @@ void do_tick_set_count(void *opaque, uint64_t count); uint64_t do_tick_get_count(void *opaque); void do_tick_set_limit(void *opaque, uint64_t limit); +#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 + #include "cpu-all.h" #endif -- cgit v1.2.3 From d0bdf2a28b7a73f02fd8025ab885c50c84def702 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 3 Jun 2007 22:54:40 +0000 Subject: Fix typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2941 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index f1cf2b923..f6d05e035 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -578,7 +578,7 @@ static inline void regs_to_env(void) static inline int cpu_halted(CPUState *env) { /* handle exit of HALTED state */ - if (env->hflags & HF_HALTED_MASK) + if (!(env->hflags & HF_HALTED_MASK)) return 0; /* disable halt condition */ if ((env->interrupt_request & CPU_INTERRUPT_HARD) && -- cgit v1.2.3 From 7e049b8a19e934a8b4a8807d5d2452e0749eac6c Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 4 Jun 2007 00:31:01 +0000 Subject: ColdFire Ethernet support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2942 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/mcf5208.c | 19 ++- hw/mcf_fec.c | 456 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-doc.texi | 2 +- vl.h | 3 + 5 files changed, 479 insertions(+), 3 deletions(-) create mode 100644 hw/mcf_fec.c diff --git a/Makefile.target b/Makefile.target index 1d1dacfb0..2be5e90ac 100644 --- a/Makefile.target +++ b/Makefile.target @@ -467,7 +467,7 @@ ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o endif ifeq ($(TARGET_BASE_ARCH), m68k) -VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o +VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o VL_OBJS+= m68k-semi.o endif ifdef CONFIG_GDBSTUB diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 886688f28..8068f7861 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -236,10 +236,27 @@ static void mcf5208evb_init(int ram_size, int vga_ram_size, int boot_device, mcf5208_sys_init(pic); + if (nb_nics > 1) { + fprintf(stderr, "Too many NICs\n"); + exit(1); + } + if (nd_table[0].vlan) { + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "mcf_fec") == 0) { + mcf_fec_init(&nd_table[0], 0xfc030000, pic + 36); + } else if (strcmp(nd_table[0].model, "?") == 0) { + fprintf(stderr, "qemu: Supported NICs: mcf_fec\n"); + exit (1); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } + } + /* 0xfc000000 SCM. */ /* 0xfc004000 XBS. */ /* 0xfc008000 FlexBus CS. */ - /* 0xfc030000 FEC. */ + /* 0xfc030000 FEC. */ /* 0xfc040000 SCM + Power management. */ /* 0xfc044000 eDMA. */ /* 0xfc048000 INTC. */ diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c new file mode 100644 index 000000000..3787c23ae --- /dev/null +++ b/hw/mcf_fec.c @@ -0,0 +1,456 @@ +/* + * ColdFire Fast Ethernet Controller emulation. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GPL + */ +#include "vl.h" +/* For crc32 */ +#include + +//#define DEBUG_FEC 1 + +#ifdef DEBUG_FEC +#define DPRINTF(fmt, args...) \ +do { printf("mcf_fec: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +#define FEC_MAX_FRAME_SIZE 2032 + +typedef struct { + qemu_irq *irq; + VLANClientState *vc; + uint32_t irq_state; + uint32_t eir; + uint32_t eimr; + int rx_enabled; + uint32_t rx_descriptor; + uint32_t tx_descriptor; + uint32_t ecr; + uint32_t mmfr; + uint32_t mscr; + uint32_t rcr; + uint32_t tcr; + uint32_t tfwr; + uint32_t rfsr; + uint32_t erdsr; + uint32_t etdsr; + uint32_t emrbr; + uint8_t macaddr[6]; +} mcf_fec_state; + +#define FEC_INT_HB 0x80000000 +#define FEC_INT_BABR 0x40000000 +#define FEC_INT_BABT 0x20000000 +#define FEC_INT_GRA 0x10000000 +#define FEC_INT_TXF 0x08000000 +#define FEC_INT_TXB 0x04000000 +#define FEC_INT_RXF 0x02000000 +#define FEC_INT_RXB 0x01000000 +#define FEC_INT_MII 0x00800000 +#define FEC_INT_EB 0x00400000 +#define FEC_INT_LC 0x00200000 +#define FEC_INT_RL 0x00100000 +#define FEC_INT_UN 0x00080000 + +#define FEC_EN 2 +#define FEC_RESET 1 + +/* Map interrupt flags onto IRQ lines. */ +#define FEC_NUM_IRQ 13 +static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = { + FEC_INT_TXF, + FEC_INT_TXB, + FEC_INT_UN, + FEC_INT_RL, + FEC_INT_RXF, + FEC_INT_RXB, + FEC_INT_MII, + FEC_INT_LC, + FEC_INT_HB, + FEC_INT_GRA, + FEC_INT_EB, + FEC_INT_BABT, + FEC_INT_BABR +}; + +/* Buffer Descriptor. */ +typedef struct { + uint16_t flags; + uint16_t length; + uint32_t data; +} mcf_fec_bd; + +#define FEC_BD_R 0x8000 +#define FEC_BD_E 0x8000 +#define FEC_BD_O1 0x4000 +#define FEC_BD_W 0x2000 +#define FEC_BD_O2 0x1000 +#define FEC_BD_L 0x0800 +#define FEC_BD_TC 0x0400 +#define FEC_BD_ABC 0x0200 +#define FEC_BD_M 0x0100 +#define FEC_BD_BC 0x0080 +#define FEC_BD_MC 0x0040 +#define FEC_BD_LG 0x0020 +#define FEC_BD_NO 0x0010 +#define FEC_BD_CR 0x0004 +#define FEC_BD_OV 0x0002 +#define FEC_BD_TR 0x0001 + +static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr) +{ + cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd)); + be16_to_cpus(&bd->flags); + be16_to_cpus(&bd->length); + be32_to_cpus(&bd->data); +} + +static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr) +{ + mcf_fec_bd tmp; + tmp.flags = cpu_to_be16(bd->flags); + tmp.length = cpu_to_be16(bd->length); + tmp.data = cpu_to_be32(bd->data); + cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp)); +} + +static void mcf_fec_update(mcf_fec_state *s) +{ + uint32_t active; + uint32_t changed; + uint32_t mask; + int i; + + active = s->eir & s->eimr; + changed = active ^s->irq_state; + for (i = 0; i < FEC_NUM_IRQ; i++) { + mask = mcf_fec_irq_map[i]; + if (changed & mask) { + DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0); + qemu_set_irq(s->irq[i], (active & mask) != 0); + } + } + s->irq_state = active; +} + +static void mcf_fec_do_tx(mcf_fec_state *s) +{ + uint32_t addr; + mcf_fec_bd bd; + int frame_size; + int len; + uint8_t frame[FEC_MAX_FRAME_SIZE]; + uint8_t *ptr; + + DPRINTF("do_tx\n"); + ptr = frame; + frame_size = 0; + addr = s->tx_descriptor; + while (1) { + mcf_fec_read_bd(&bd, addr); + DPRINTF("tx_bd %x flags %04x len %d data %08x\n", + addr, bd.flags, bd.length, bd.data); + if ((bd.flags & FEC_BD_R) == 0) { + /* Run out of descriptors to transmit. */ + break; + } + len = bd.length; + if (frame_size + len > FEC_MAX_FRAME_SIZE) { + len = FEC_MAX_FRAME_SIZE - frame_size; + s->eir |= FEC_INT_BABT; + } + cpu_physical_memory_read(bd.data, ptr, len); + ptr += len; + frame_size += len; + if (bd.flags & FEC_BD_L) { + /* Last buffer in frame. */ + DPRINTF("Sending packet\n"); + qemu_send_packet(s->vc, frame, len); + ptr = frame; + frame_size = 0; + s->eir |= FEC_INT_TXF; + } + s->eir |= FEC_INT_TXB; + bd.flags &= ~FEC_BD_R; + /* Write back the modified descriptor. */ + mcf_fec_write_bd(&bd, addr); + /* Advance to the next descriptor. */ + if ((bd.flags & FEC_BD_W) != 0) { + addr = s->etdsr; + } else { + addr += 8; + } + } + s->tx_descriptor = addr; +} + +static int mcf_fec_enable_rx(mcf_fec_state *s) +{ + mcf_fec_bd bd; + + mcf_fec_read_bd(&bd, s->rx_descriptor); + s->rx_enabled = ((bd.flags & FEC_BD_E) != 0); + if (!s->rx_enabled) + DPRINTF("RX buffer full\n"); +} + +static void mcf_fec_reset(mcf_fec_state *s) +{ + s->eir = 0; + s->eimr = 0; + s->rx_enabled = 0; + s->ecr = 0; + s->mscr = 0; + s->rcr = 0x05ee0001; + s->tcr = 0; + s->tfwr = 0; + s->rfsr = 0x500; +} + +static uint32_t mcf_fec_read(void *opaque, target_phys_addr_t addr) +{ + mcf_fec_state *s = (mcf_fec_state *)opaque; + switch (addr & 0x3ff) { + case 0x004: return s->eir; + case 0x008: return s->eimr; + case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */ + case 0x014: return 0; /* TDAR */ + case 0x024: return s->ecr; + case 0x040: return s->mmfr; + case 0x044: return s->mscr; + case 0x064: return 0; /* MIBC */ + case 0x084: return s->rcr; + case 0x0c4: return s->tcr; + case 0x0e4: /* PALR */ + return (s->macaddr[0] << 24) | (s->macaddr[1] << 16) + | (s->macaddr[2] << 8) | s->macaddr[3]; + break; + case 0x0e8: /* PAUR */ + return (s->macaddr[4] << 24) | (s->macaddr[5] << 16) | 0x8808; + case 0x0ec: return 0x10000; /* OPD */ + case 0x118: return 0; + case 0x11c: return 0; + case 0x120: return 0; + case 0x124: return 0; + case 0x144: return s->tfwr; + case 0x14c: return 0x600; + case 0x150: return s->rfsr; + case 0x180: return s->erdsr; + case 0x184: return s->etdsr; + case 0x188: return s->emrbr; + default: + cpu_abort(cpu_single_env, "mcf_fec_read: Bad address 0x%x\n", + (int)addr); + return 0; + } +} + +void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + mcf_fec_state *s = (mcf_fec_state *)opaque; + switch (addr & 0x3ff) { + case 0x004: + s->eir &= ~value; + break; + case 0x008: + s->eimr = value; + break; + case 0x010: /* RDAR */ + if ((s->ecr & FEC_EN) && !s->rx_enabled) { + DPRINTF("RX enable\n"); + mcf_fec_enable_rx(s); + } + break; + case 0x014: /* TDAR */ + if (s->ecr & FEC_EN) { + mcf_fec_do_tx(s); + } + break; + case 0x024: + s->ecr = value; + if (value & FEC_RESET) { + DPRINTF("Reset\n"); + mcf_fec_reset(s); + } + if ((s->ecr & FEC_EN) == 0) { + s->rx_enabled = 0; + } + break; + case 0x040: + /* TODO: Implement MII. */ + s->mmfr = value; + break; + case 0x044: + s->mscr = value & 0xfe; + break; + case 0x064: + /* TODO: Implement MIB. */ + break; + case 0x084: + s->rcr = value & 0x07ff003f; + /* TODO: Implement LOOP mode. */ + break; + case 0x0c4: /* TCR */ + /* We transmit immediately, so raise GRA immediately. */ + s->tcr = value; + if (value & 1) + s->eir |= FEC_INT_GRA; + break; + case 0x0e4: /* PALR */ + s->macaddr[0] = value >> 24; + s->macaddr[1] = value >> 16; + s->macaddr[2] = value >> 8; + s->macaddr[3] = value; + break; + case 0x0e8: /* PAUR */ + s->macaddr[4] = value >> 24; + s->macaddr[5] = value >> 16; + break; + case 0x0ec: + /* OPD */ + break; + case 0x118: + case 0x11c: + case 0x120: + case 0x124: + /* TODO: implement MAC hash filtering. */ + break; + case 0x144: + s->tfwr = value & 3; + break; + case 0x14c: + /* FRBR writes ignored. */ + break; + case 0x150: + s->rfsr = (value & 0x3fc) | 0x400; + break; + case 0x180: + s->erdsr = value & ~3; + s->rx_descriptor = s->erdsr; + break; + case 0x184: + s->etdsr = value & ~3; + s->tx_descriptor = s->etdsr; + break; + case 0x188: + s->emrbr = value & 0x7f0; + break; + default: + cpu_abort(cpu_single_env, "mcf_fec_write Bad address 0x%x\n", + (int)addr); + } + mcf_fec_update(s); +} + +static int mcf_fec_can_receive(void *opaque) +{ + mcf_fec_state *s = (mcf_fec_state *)opaque; + return s->rx_enabled; +} + +static void mcf_fec_receive(void *opaque, const uint8_t *buf, int size) +{ + mcf_fec_state *s = (mcf_fec_state *)opaque; + mcf_fec_bd bd; + uint32_t flags = 0; + uint32_t addr; + uint32_t crc; + uint32_t buf_addr; + uint8_t *crc_ptr; + unsigned int buf_len; + + DPRINTF("do_rx len %d\n", size); + if (!s->rx_enabled) { + fprintf(stderr, "mcf_fec_receive: Unexpected packet\n"); + } + /* 4 bytes for the CRC. */ + size += 4; + crc = cpu_to_be32(crc32(~0, buf, size)); + crc_ptr = (uint8_t *)&crc; + /* Huge frames are truncted. */ + if (size > FEC_MAX_FRAME_SIZE) { + size = FEC_MAX_FRAME_SIZE; + flags |= FEC_BD_TR | FEC_BD_LG; + } + /* Frames larger than the user limit just set error flags. */ + if (size > (s->rcr >> 16)) { + flags |= FEC_BD_LG; + } + addr = s->rx_descriptor; + while (size > 0) { + mcf_fec_read_bd(&bd, addr); + if ((bd.flags & FEC_BD_E) == 0) { + /* No descriptors available. Bail out. */ + /* FIXME: This is wrong. We should probably either save the + remainder for when more RX buffers are available, or + flag an error. */ + fprintf(stderr, "mcf_fec: Lost end of frame\n"); + break; + } + buf_len = (size <= s->emrbr) ? size: s->emrbr; + bd.length = buf_len; + size -= buf_len; + DPRINTF("rx_bd %x length %d\n", addr, bd.length); + /* The last 4 bytes are the CRC. */ + if (size < 4) + buf_len += size - 4; + buf_addr = bd.data; + cpu_physical_memory_write(buf_addr, buf, buf_len); + buf += buf_len; + if (size < 4) { + cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size); + crc_ptr += 4 - size; + } + bd.flags &= ~FEC_BD_E; + if (size == 0) { + /* Last buffer in frame. */ + bd.flags |= flags | FEC_BD_L; + DPRINTF("rx frame flags %04x\n", bd.flags); + s->eir |= FEC_INT_RXF; + } else { + s->eir |= FEC_INT_RXB; + } + mcf_fec_write_bd(&bd, addr); + /* Advance to the next descriptor. */ + if ((bd.flags & FEC_BD_W) != 0) { + addr = s->erdsr; + } else { + addr += 8; + } + } + s->rx_descriptor = addr; + mcf_fec_enable_rx(s); + mcf_fec_update(s); +} + +static CPUReadMemoryFunc *mcf_fec_readfn[] = { + mcf_fec_read, + mcf_fec_read, + mcf_fec_read +}; + +static CPUWriteMemoryFunc *mcf_fec_writefn[] = { + mcf_fec_write, + mcf_fec_write, + mcf_fec_write +}; + +void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) +{ + mcf_fec_state *s; + int iomemtype; + + s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state)); + s->irq = irq; + iomemtype = cpu_register_io_memory(0, mcf_fec_readfn, + mcf_fec_writefn, s); + cpu_register_physical_memory(base, 0x400, iomemtype); + + s->vc = qemu_new_vlan_client(nd->vlan, mcf_fec_receive, + mcf_fec_can_receive, s); + memcpy(s->macaddr, nd->macaddr, 6); +} diff --git a/qemu-doc.texi b/qemu-doc.texi index ce77b8a00..cb05aa58c 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -362,7 +362,7 @@ Qemu can emulate several different models of network card. Valid values for @var{type} are @code{i82551}, @code{i82557b}, @code{i82559er}, @code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139}, -@code{smc91c111} and @code{lance}. +@code{smc91c111}, @code{lance} and @code{mcf_fec}. Not all devices are supported on all targets. Use -net nic,model=? for a list of available devices for your target. diff --git a/vl.h b/vl.h index 916daf391..c779541bd 100644 --- a/vl.h +++ b/vl.h @@ -1603,6 +1603,9 @@ void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq, /* mcf_intc.c */ qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env); +/* mcf_fec.c */ +void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq); + /* mcf5206.c */ qemu_irq *mcf5206_init(uint32_t base, CPUState *env); -- cgit v1.2.3 From 707e011bbca026e8073563428ab545aa2b3ac20c Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 4 Jun 2007 00:50:06 +0000 Subject: Add documentation for new ColdFire board. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2943 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index cb05aa58c..267509e0a 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -81,6 +81,7 @@ For system emulation, the following hardware targets are supported: @item ARM Versatile baseboard (ARM926E) @item ARM RealView Emulation baseboard (ARM926EJ-S) @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) +@item Freescale MCF5208EVB (ColdFire V2). @item Arnewsh MCF5206 evaluation board (ColdFire V2). @end itemize @@ -1835,7 +1836,19 @@ information is available in the QEMU mailing-list archive. Use the executable @file{qemu-system-m68k} to simulate a ColdFire machine. The emulator is able to boot a uClinux kernel. -The following devices are emulated: + +The M5208EVB emulation includes the following devices: + +@itemize @minus +@item +MCF5208 ColdFire V2 Microprocessor (ISA A+ with EMAC). +@item +Three Two on-chip UARTs. +@item +Fast Ethernet Controller (FEC) +@end itemize + +The AN5206 emulation includes the following devices: @itemize @minus @item -- cgit v1.2.3 From b6dc7ebbeaa46d54414de6e5ee86fd4a173ff273 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 4 Jun 2007 18:29:37 +0000 Subject: Take advantage of subpage support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2944 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 1164df1a9..fc84f7ca0 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -236,17 +236,7 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr) val = s->brk; break; - /* UART Registers */ - case 0x00900: - case 0x00908: - case 0x00910: - case 0x00918: - case 0x00920: - case 0x00928: - case 0x00930: - case 0x00938: - val = serial_mm_readb(s->uart, addr); - break; + /* UART Registers are handled directly by the serial device */ /* GPOUT Register */ case 0x00a00: @@ -348,17 +338,7 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr, s->brk = val & 0xff; break; - /* UART Registers */ - case 0x00900: - case 0x00908: - case 0x00910: - case 0x00918: - case 0x00920: - case 0x00928: - case 0x00930: - case 0x00938: - serial_mm_writeb(s->uart, addr, val); - break; + /* UART Registers are handled directly by the serial device */ /* GPOUT Register */ case 0x00a00: @@ -430,7 +410,8 @@ MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env) malta = cpu_register_io_memory(0, malta_fpga_read, malta_fpga_write, s); - cpu_register_physical_memory(base, 0x100000, malta); + cpu_register_physical_memory(base, 0x900, malta); + cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta); s->display = qemu_chr_open("vc"); qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n"); @@ -445,7 +426,7 @@ MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env) uart_chr = qemu_chr_open("vc"); qemu_chr_printf(uart_chr, "CBUS UART\r\n"); - s->uart = serial_mm_init(base, 3, env->irq[2], uart_chr, 0); + s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1); malta_fpga_reset(s); qemu_register_reset(malta_fpga_reset, s); -- cgit v1.2.3 From afcc3cdfc4f6291ae6cb803339c794029bf6c99a Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Jun 2007 16:26:14 +0000 Subject: Use the correct PCI IDs for Malta. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2945 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 39 +++++++++++++++++++++++++++++++++++++++ hw/mips_malta.c | 4 ++-- hw/pc.c | 2 +- hw/usb-uhci.c | 38 +++++++++++++++++++++++++++++++++++++- hw/usb.h | 3 ++- vl.h | 2 ++ 6 files changed, 83 insertions(+), 5 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 03875ce9a..c4fabe6a6 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -376,6 +376,7 @@ typedef struct IDEState { #define IDE_TYPE_PIIX3 0 #define IDE_TYPE_CMD646 1 +#define IDE_TYPE_PIIX4 2 /* CMD646 specific */ #define MRDMODE 0x71 @@ -2875,6 +2876,44 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); } +/* hd_table must contain 4 block drivers */ +/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */ +void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, + qemu_irq *pic) +{ + PCIIDEState *d; + uint8_t *pci_conf; + + /* register a function 1 of PIIX4 */ + d = (PCIIDEState *)pci_register_device(bus, "PIIX4 IDE", + sizeof(PCIIDEState), + devfn, + NULL, NULL); + d->type = IDE_TYPE_PIIX4; + + pci_conf = d->dev.config; + pci_conf[0x00] = 0x86; // Intel + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x11; + pci_conf[0x03] = 0x71; + pci_conf[0x09] = 0x80; // legacy ATA mode + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE + pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage + pci_conf[0x0e] = 0x00; // header_type + + piix3_reset(d); + + pci_register_io_region((PCIDevice *)d, 4, 0x10, + PCI_ADDRESS_SPACE_IO, bmdma_map); + + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]); + ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]); + ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); + ide_init_ioport(&d->ide_if[2], 0x170, 0x376); + + register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d); +} + /***********************************************************/ /* MacIO based PowerPC IDE */ diff --git a/hw/mips_malta.c b/hw/mips_malta.c index fc84f7ca0..9786023c3 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -830,8 +830,8 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, /* Southbridge */ piix4_devfn = piix4_init(pci_bus, 80); - pci_piix3_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259); - usb_uhci_init(pci_bus, piix4_devfn + 2); + pci_piix4_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259); + usb_uhci_piix4_init(pci_bus, piix4_devfn + 2); smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100); eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ for (i = 0; i < 8; i++) { diff --git a/hw/pc.c b/hw/pc.c index 1cd5d4cff..d38018679 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -897,7 +897,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, cmos_init(ram_size, boot_device, bs_table); if (pci_enabled && usb_enabled) { - usb_uhci_init(pci_bus, piix3_devfn + 2); + usb_uhci_piix3_init(pci_bus, piix3_devfn + 2); } if (pci_enabled && acpi_enabled) { diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 638b199c4..3936fe03f 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -783,7 +783,7 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } -void usb_uhci_init(PCIBus *bus, int devfn) +void usb_uhci_piix3_init(PCIBus *bus, int devfn) { UHCIState *s; uint8_t *pci_conf; @@ -817,3 +817,39 @@ void usb_uhci_init(PCIBus *bus, int devfn) pci_register_io_region(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); } + +void usb_uhci_piix4_init(PCIBus *bus, int devfn) +{ + UHCIState *s; + uint8_t *pci_conf; + int i; + + s = (UHCIState *)pci_register_device(bus, + "USB-UHCI", sizeof(UHCIState), + devfn, NULL, NULL); + pci_conf = s->dev.config; + pci_conf[0x00] = 0x86; + pci_conf[0x01] = 0x80; + pci_conf[0x02] = 0x12; + pci_conf[0x03] = 0x71; + pci_conf[0x08] = 0x01; // revision number + pci_conf[0x09] = 0x00; + pci_conf[0x0a] = 0x03; + pci_conf[0x0b] = 0x0c; + pci_conf[0x0e] = 0x00; // header_type + pci_conf[0x3d] = 4; // interrupt pin 3 + pci_conf[0x60] = 0x10; // release number + + for(i = 0; i < NB_PORTS; i++) { + qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); + } + s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); + + uhci_reset(s); + + /* Use region 4 for consistency with real hardware. BSD guests seem + to rely on this. */ + pci_register_io_region(&s->dev, 4, 0x20, + PCI_ADDRESS_SPACE_IO, uhci_map); +} + diff --git a/hw/usb.h b/hw/usb.h index 02a7355e6..66662affe 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -203,7 +203,8 @@ void usb_packet_complete(USBPacket *p); USBDevice *usb_hub_init(int nb_ports); /* usb-uhci.c */ -void usb_uhci_init(PCIBus *bus, int devfn); +void usb_uhci_piix3_init(PCIBus *bus, int devfn); +void usb_uhci_piix4_init(PCIBus *bus, int devfn); /* usb-ohci.c */ void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn); diff --git a/vl.h b/vl.h index c779541bd..976af60e8 100644 --- a/vl.h +++ b/vl.h @@ -983,6 +983,8 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, int secondary_ide_enabled); void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, qemu_irq *pic); +void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, + qemu_irq *pic); int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq); /* cdrom.c */ -- cgit v1.2.3 From e918ee04e96dd2d8809cf9d78c14a4d900001211 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Jun 2007 16:28:07 +0000 Subject: Big endian byte swap for serial mmapped interface. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2946 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/serial.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index e0ff3a72c..088886258 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -384,30 +384,44 @@ void serial_mm_writeb (void *opaque, uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr) { SerialState *s = opaque; + uint32_t val; - return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF; + val = serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF; +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; } void serial_mm_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { SerialState *s = opaque; - +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap16(value); +#endif serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF); } uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr) { SerialState *s = opaque; + uint32_t val; - return serial_ioport_read(s, (addr - s->base) >> s->it_shift); + val = serial_ioport_read(s, (addr - s->base) >> s->it_shift); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; } void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { SerialState *s = opaque; - +#ifdef TARGET_WORDS_BIGENDIAN + value = bswap32(value); +#endif serial_ioport_write(s, (addr - s->base) >> s->it_shift, value); } -- cgit v1.2.3 From 5066b9f199ac13f5d62ce6e03a59bbbce7e8a5ce Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Jun 2007 16:52:12 +0000 Subject: Malta has no ISA bus. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2947 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 9786023c3..d8e939104 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -451,17 +451,8 @@ static void audio_init (PCIBus *pci_bus) s = AUD_init (); if (s) { for (c = soundhw; c->name; ++c) { - if (c->enabled) { - if (c->isa) { - fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name); - exit(1); - } - else { - if (pci_bus) { - c->init.init_pci (pci_bus, s); - } - } - } + if (c->enabled) + c->init.init_pci (pci_bus, s); } } } -- cgit v1.2.3 From acdf72bbaca6be56765a92122b17a7ce201d5f68 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Jun 2007 16:54:26 +0000 Subject: Fix formatting. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2948 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index d8e939104..21eb75faf 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -671,7 +671,7 @@ static int64_t load_kernel (CPUState *env) &kernel_entry, &kernel_low, &kernel_high) < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", env->kernel_filename); - exit(1); + exit(1); } /* load initrd */ -- cgit v1.2.3 From 070ce5edc39df04ffed2b002da27e69859ee01b7 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 6 Jun 2007 17:19:24 +0000 Subject: Make the Malta bootloader handling a bit more transparent. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2949 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 21eb75faf..f113e5611 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -778,9 +778,23 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x1fc00000LL, BIOS_SIZE, bios_offset | IO_MEM_ROM); - /* Load a BIOS image except if a kernel image has been specified. In - the later case, just write a small bootloader to the flash - location. */ + /* FPGA */ + malta_fpga = malta_fpga_init(0x1f000000LL, env); + + /* Load a BIOS image unless a kernel image has been specified. */ + if (!kernel_filename) { + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + bios_offset); + if (ret < 0 || ret > BIOS_SIZE) { + fprintf(stderr, + "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", + buf); + exit(1); + } + } + + /* If a kernel image has been specified, write a small bootloader + to the flash location. */ if (kernel_filename) { env->ram_size = ram_size; env->kernel_filename = kernel_filename; @@ -789,14 +803,6 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, kernel_entry = load_kernel(env); env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); write_bootloader(env, bios_offset, kernel_entry); - } else { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - ret = load_image(buf, phys_ram_base + bios_offset); - if (ret < 0 || ret > BIOS_SIZE) { - fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", - buf); - exit(1); - } } /* Board ID = 0x420 (Malta Board with CoreLV) @@ -809,9 +815,6 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, cpu_mips_clock_init(env); cpu_mips_irqctrl_init(); - /* FPGA */ - malta_fpga = malta_fpga_init(0x1f000000LL, env); - /* Interrupt controller */ /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ i8259 = i8259_init(env->irq[2]); -- cgit v1.2.3 From 3187ef0390b049ee75bf806f13f6e5004e382c03 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 12:17:52 +0000 Subject: Fix firmware word endianness for Malta. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2950 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index f113e5611..7336b7b05 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -791,6 +791,18 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, buf); exit(1); } + /* In little endian mode the 32bit words in the bios are swapped, + a neat trick which allows bi-endian firmware. */ +#ifndef TARGET_WORDS_BIGENDIAN + { + uint32_t *addr; + for (addr = (uint32_t *)(phys_ram_base + bios_offset); + addr < (uint32_t *)(phys_ram_base + bios_offset + ret); + addr++) { + *addr = bswap32(*addr); + } + } +#endif } /* If a kernel image has been specified, write a small bootloader -- cgit v1.2.3 From d4a4d056eacb34265481d888c67f5667fc9be8ca Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 12:30:16 +0000 Subject: Fix PCI irq mapping on Malta. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2951 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 3a0e8b153..cbfc9df11 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -504,10 +504,10 @@ static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num) return 3; /* AMD 79C973 Ethernet */ case 11: - return 0; + return 1; /* Crystal 4281 Sound */ case 12: - return 0; + return 2; /* PCI slot 1 to 4 */ case 18 ... 21: return ((slot - 18) + irq_num) & 0x03; -- cgit v1.2.3 From 9566782b65ec4c7f97cfbc49b8d2d50c686ebbe6 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 12:32:29 +0000 Subject: Fix comment. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2952 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_pica61.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 5bb340535..2925b69cc 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -1,5 +1,5 @@ /* - * QEMU Malta board support + * QEMU Acer Pica Machine support * * Copyright (c) 2007 Herv Poussineau * -- cgit v1.2.3 From 05b4ff435717e6b8355f6cd73ea17f2d9eaa9a55 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 17:00:37 +0000 Subject: Implement some more Gallileo registers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2953 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 336 insertions(+), 17 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index cbfc9df11..9f030263d 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -23,9 +23,18 @@ */ #include "vl.h" + typedef target_phys_addr_t pci_addr_t; #include "pci_host.h" +//#define DEBUG + +#ifdef DEBUG +#define dprintf(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + #define GT_REGS (0x1000 >> 2) /* CPU Configuration */ @@ -45,8 +54,6 @@ typedef target_phys_addr_t pci_addr_t; #define GT_PCI0IOHD (0x050 >> 2) #define GT_PCI0M0LD (0x058 >> 2) #define GT_PCI0M0HD (0x060 >> 2) -#define GT_ISD (0x068 >> 2) - #define GT_PCI0M1LD (0x080 >> 2) #define GT_PCI0M1HD (0x088 >> 2) #define GT_PCI1IOLD (0x090 >> 2) @@ -55,8 +62,7 @@ typedef target_phys_addr_t pci_addr_t; #define GT_PCI1M0HD (0x0a8 >> 2) #define GT_PCI1M1LD (0x0b0 >> 2) #define GT_PCI1M1HD (0x0b8 >> 2) -#define GT_PCI1M1LD (0x0b0 >> 2) -#define GT_PCI1M1HD (0x0b8 >> 2) +#define GT_ISD (0x068 >> 2) #define GT_SCS10AR (0x0d0 >> 2) #define GT_SCS32AR (0x0d8 >> 2) @@ -330,6 +336,45 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, /* Read-only registers, do nothing */ break; + /* SDRAM and Device Address Decode */ + case GT_SCS0LD: + case GT_SCS0HD: + case GT_SCS1LD: + case GT_SCS1HD: + case GT_SCS2LD: + case GT_SCS2HD: + case GT_SCS3LD: + case GT_SCS3HD: + case GT_CS0LD: + case GT_CS0HD: + case GT_CS1LD: + case GT_CS1HD: + case GT_CS2LD: + case GT_CS2HD: + case GT_CS3LD: + case GT_CS3HD: + case GT_BOOTLD: + case GT_BOOTHD: + case GT_ADERR: + /* SDRAM Configuration */ + case GT_SDRAM_CFG: + case GT_SDRAM_OPMODE: + case GT_SDRAM_BM: + case GT_SDRAM_ADDRDECODE: + /* Accept and ignore SDRAM interleave configuration */ + s->regs[saddr] = val; + break; + + /* Device Parameters */ + case GT_DEV_B0: + case GT_DEV_B1: + case GT_DEV_B2: + case GT_DEV_B3: + case GT_DEV_BOOT: + /* Not implemented */ + dprintf ("Unimplemented device register offset 0x%x\n", saddr << 2); + break; + /* ECC */ case GT_ECC_ERRDATALO: case GT_ECC_ERRDATAHI: @@ -339,16 +384,131 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, /* Read-only registers, do nothing */ break; + /* DMA Record */ + case GT_DMA0_CNT: + case GT_DMA1_CNT: + case GT_DMA2_CNT: + case GT_DMA3_CNT: + case GT_DMA0_SA: + case GT_DMA1_SA: + case GT_DMA2_SA: + case GT_DMA3_SA: + case GT_DMA0_DA: + case GT_DMA1_DA: + case GT_DMA2_DA: + case GT_DMA3_DA: + case GT_DMA0_NEXT: + case GT_DMA1_NEXT: + case GT_DMA2_NEXT: + case GT_DMA3_NEXT: + case GT_DMA0_CUR: + case GT_DMA1_CUR: + case GT_DMA2_CUR: + case GT_DMA3_CUR: + /* Not implemented */ + dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2); + break; + + /* DMA Channel Control */ + case GT_DMA0_CTRL: + case GT_DMA1_CTRL: + case GT_DMA2_CTRL: + case GT_DMA3_CTRL: + /* Not implemented */ + dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2); + break; + + /* DMA Arbiter */ + case GT_DMA_ARB: + /* Not implemented */ + dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2); + break; + + /* Timer/Counter */ + case GT_TC0: + case GT_TC1: + case GT_TC2: + case GT_TC3: + case GT_TC_CONTROL: + /* Not implemented */ + dprintf ("Unimplemented timer register offset 0x%x\n", saddr << 2); + break; + /* PCI Internal */ case GT_PCI0_CMD: case GT_PCI1_CMD: s->regs[saddr] = val & 0x0401fc0f; break; + case GT_PCI0_TOR: + case GT_PCI0_BS_SCS10: + case GT_PCI0_BS_SCS32: + case GT_PCI0_BS_CS20: + case GT_PCI0_BS_CS3BT: + case GT_PCI1_IACK: + case GT_PCI0_IACK: + case GT_PCI0_BARE: + case GT_PCI0_PREFMBR: + case GT_PCI0_SCS10_BAR: + case GT_PCI0_SCS32_BAR: + case GT_PCI0_CS20_BAR: + case GT_PCI0_CS3BT_BAR: + case GT_PCI0_SSCS10_BAR: + case GT_PCI0_SSCS32_BAR: + case GT_PCI0_SCS3BT_BAR: + case GT_PCI1_TOR: + case GT_PCI1_BS_SCS10: + case GT_PCI1_BS_SCS32: + case GT_PCI1_BS_CS20: + case GT_PCI1_BS_CS3BT: + case GT_PCI1_BARE: + case GT_PCI1_PREFMBR: + case GT_PCI1_SCS10_BAR: + case GT_PCI1_SCS32_BAR: + case GT_PCI1_CS20_BAR: + case GT_PCI1_CS3BT_BAR: + case GT_PCI1_SSCS10_BAR: + case GT_PCI1_SSCS32_BAR: + case GT_PCI1_SCS3BT_BAR: + case GT_PCI1_CFGADDR: + case GT_PCI1_CFGDATA: + /* not implemented */ + break; case GT_PCI0_CFGADDR: s->pci->config_reg = val & 0x80fffffc; break; case GT_PCI0_CFGDATA: - pci_host_data_writel(s->pci, 0, val); + if (s->pci->config_reg & (1u << 31)) + pci_host_data_writel(s->pci, 0, val); + break; + + /* Interrupts */ + case GT_INTRCAUSE: + /* not really implemented */ + s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe)); + s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe); + dprintf("INTRCAUSE %x\n", val); + break; + case GT_INTRMASK: + s->regs[saddr] = val & 0x3c3ffffe; + dprintf("INTRMASK %x\n", val); + break; + case GT_PCI0_ICMASK: + s->regs[saddr] = val & 0x03fffffe; + dprintf("ICMASK %x\n", val); + break; + case GT_PCI0_SERR0MASK: + s->regs[saddr] = val & 0x0000003f; + dprintf("SERR0MASK %x\n", val); + break; + + /* Reserved when only PCI_0 is configured. */ + case GT_HINTRCAUSE: + case GT_CPU_INTSEL: + case GT_PCI0_INTSEL: + case GT_HINTRMASK: + case GT_PCI0_HICMASK: + case GT_PCI1_SERR1MASK: + /* not implemented */ break; /* SDRAM Parameters */ @@ -362,9 +522,7 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, break; default: -#if 0 - printf ("gt64120_writel: Bad register offset 0x%x\n", (int)addr); -#endif + dprintf ("Bad register offset 0x%x\n", (int)addr); break; } } @@ -420,6 +578,18 @@ static uint32_t gt64120_readl (void *opaque, break; case GT_CPU: + case GT_SCS10LD: + case GT_SCS10HD: + case GT_SCS32LD: + case GT_SCS32HD: + case GT_CS20LD: + case GT_CS20HD: + case GT_CS3BOOTLD: + case GT_CS3BOOTHD: + case GT_SCS10AR: + case GT_SCS32AR: + case GT_CS20R: + case GT_CS3BOOTR: case GT_PCI0IOLD: case GT_PCI0M0LD: case GT_PCI0M1LD: @@ -432,14 +602,13 @@ static uint32_t gt64120_readl (void *opaque, case GT_PCI1IOHD: case GT_PCI1M0HD: case GT_PCI1M1HD: - case GT_PCI0_CMD: - case GT_PCI1_CMD: case GT_PCI0IOREMAP: case GT_PCI0M0REMAP: case GT_PCI0M1REMAP: case GT_PCI1IOREMAP: case GT_PCI1M0REMAP: case GT_PCI1M1REMAP: + case GT_ISD: val = s->regs[saddr]; break; case GT_PCI0_IACK: @@ -447,6 +616,37 @@ static uint32_t gt64120_readl (void *opaque, val = pic_read_irq(isa_pic); break; + /* SDRAM and Device Address Decode */ + case GT_SCS0LD: + case GT_SCS0HD: + case GT_SCS1LD: + case GT_SCS1HD: + case GT_SCS2LD: + case GT_SCS2HD: + case GT_SCS3LD: + case GT_SCS3HD: + case GT_CS0LD: + case GT_CS0HD: + case GT_CS1LD: + case GT_CS1HD: + case GT_CS2LD: + case GT_CS2HD: + case GT_CS3LD: + case GT_CS3HD: + case GT_BOOTLD: + case GT_BOOTHD: + case GT_ADERR: + val = s->regs[saddr]; + break; + + /* SDRAM Configuration */ + case GT_SDRAM_CFG: + case GT_SDRAM_OPMODE: + case GT_SDRAM_BM: + case GT_SDRAM_ADDRDECODE: + val = s->regs[saddr]; + break; + /* SDRAM Parameters */ case GT_SDRAM_B0: case GT_SDRAM_B1: @@ -457,27 +657,146 @@ static uint32_t gt64120_readl (void *opaque, val = s->regs[saddr]; break; + /* Device Parameters */ + case GT_DEV_B0: + case GT_DEV_B1: + case GT_DEV_B2: + case GT_DEV_B3: + case GT_DEV_BOOT: + val = s->regs[saddr]; + break; + + /* DMA Record */ + case GT_DMA0_CNT: + case GT_DMA1_CNT: + case GT_DMA2_CNT: + case GT_DMA3_CNT: + case GT_DMA0_SA: + case GT_DMA1_SA: + case GT_DMA2_SA: + case GT_DMA3_SA: + case GT_DMA0_DA: + case GT_DMA1_DA: + case GT_DMA2_DA: + case GT_DMA3_DA: + case GT_DMA0_NEXT: + case GT_DMA1_NEXT: + case GT_DMA2_NEXT: + case GT_DMA3_NEXT: + case GT_DMA0_CUR: + case GT_DMA1_CUR: + case GT_DMA2_CUR: + case GT_DMA3_CUR: + val = s->regs[saddr]; + break; + + /* DMA Channel Control */ + case GT_DMA0_CTRL: + case GT_DMA1_CTRL: + case GT_DMA2_CTRL: + case GT_DMA3_CTRL: + val = s->regs[saddr]; + break; + + /* DMA Arbiter */ + case GT_DMA_ARB: + val = s->regs[saddr]; + break; + + /* Timer/Counter */ + case GT_TC0: + case GT_TC1: + case GT_TC2: + case GT_TC3: + case GT_TC_CONTROL: + val = s->regs[saddr]; + break; + /* PCI Internal */ case GT_PCI0_CFGADDR: val = s->pci->config_reg; break; case GT_PCI0_CFGDATA: - val = pci_host_data_readl(s->pci, 0); + if (!(s->pci->config_reg & (1u << 31))) + val = 0xffffffff; + else + val = pci_data_read(s->pci->bus, s->pci->config_reg, 4); + break; + + case GT_PCI0_CMD: + case GT_PCI0_TOR: + case GT_PCI0_BS_SCS10: + case GT_PCI0_BS_SCS32: + case GT_PCI0_BS_CS20: + case GT_PCI0_BS_CS3BT: + case GT_PCI1_IACK: + case GT_PCI0_BARE: + case GT_PCI0_PREFMBR: + case GT_PCI0_SCS10_BAR: + case GT_PCI0_SCS32_BAR: + case GT_PCI0_CS20_BAR: + case GT_PCI0_CS3BT_BAR: + case GT_PCI0_SSCS10_BAR: + case GT_PCI0_SSCS32_BAR: + case GT_PCI0_SCS3BT_BAR: + case GT_PCI1_CMD: + case GT_PCI1_TOR: + case GT_PCI1_BS_SCS10: + case GT_PCI1_BS_SCS32: + case GT_PCI1_BS_CS20: + case GT_PCI1_BS_CS3BT: + case GT_PCI1_BARE: + case GT_PCI1_PREFMBR: + case GT_PCI1_SCS10_BAR: + case GT_PCI1_SCS32_BAR: + case GT_PCI1_CS20_BAR: + case GT_PCI1_CS3BT_BAR: + case GT_PCI1_SSCS10_BAR: + case GT_PCI1_SSCS32_BAR: + case GT_PCI1_SCS3BT_BAR: + case GT_PCI1_CFGADDR: + case GT_PCI1_CFGDATA: + val = s->regs[saddr]; + break; + + /* Interrupts */ + case GT_INTRCAUSE: + val = s->regs[saddr]; + dprintf("INTRCAUSE %x\n", val); + break; + case GT_INTRMASK: + val = s->regs[saddr]; + dprintf("INTRMASK %x\n", val); + break; + case GT_PCI0_ICMASK: + val = s->regs[saddr]; + dprintf("ICMASK %x\n", val); + break; + case GT_PCI0_SERR0MASK: + val = s->regs[saddr]; + dprintf("SERR0MASK %x\n", val); + break; + + /* Reserved when only PCI_0 is configured. */ + case GT_HINTRCAUSE: + case GT_CPU_INTSEL: + case GT_PCI0_INTSEL: + case GT_HINTRMASK: + case GT_PCI0_HICMASK: + case GT_PCI1_SERR1MASK: + val = s->regs[saddr]; break; default: val = s->regs[saddr]; -#if 0 - printf ("gt64120_readl: Bad register offset 0x%x\n", (int)addr); -#endif + dprintf ("Bad register offset 0x%x\n", (int)addr); break; } #ifdef TARGET_WORDS_BIGENDIAN - return bswap32(val); -#else - return val; + val = bswap32(val); #endif + return val; } static CPUWriteMemoryFunc *gt64120_write[] = { -- cgit v1.2.3 From 1823082ccc32394fe2788b6b545fd080d60bb7e7 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 17:31:35 +0000 Subject: PCI device saving for GT64xxx. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2954 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 9f030263d..76472df39 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -945,6 +945,25 @@ static void gt64120_write_config(PCIDevice *d, uint32_t address, uint32_t val, pci_default_write_config(d, address, val, len); } +static void gt64120_save(QEMUFile* f, void *opaque) +{ + PCIDevice *d = opaque; + pci_device_save(d, f); +} + +static int gt64120_load(QEMUFile* f, void *opaque, int version_id) +{ + PCIDevice *d = opaque; + int ret; + + if (version_id != 1) + return -EINVAL; + ret = pci_device_load(d, f); + if (ret < 0) + return ret; + return 0; +} + PCIBus *pci_gt64120_init(qemu_irq *pic) { GT64120State *s; @@ -988,5 +1007,7 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) d->config[0x27] = 0x14; d->config[0x3D] = 0x01; + register_savevm("GT64120 PCI Bus", 0, 1, gt64120_save, gt64120_load, d); + return s->pci->bus; } -- cgit v1.2.3 From 0f78cf0c442549e32c877ce37b4201af03e19a43 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 17:38:50 +0000 Subject: Fix some Malta PCI config bits. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2955 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 76472df39..f36e24abf 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -984,26 +984,30 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), 0, gt64120_read_config, gt64120_write_config); + /* FIXME: Malta specific hw assumptions ahead */ + d->config[0x00] = 0xab; // vendor_id d->config[0x01] = 0x11; d->config[0x02] = 0x20; // device_id d->config[0x03] = 0x46; - d->config[0x04] = 0x06; + + d->config[0x04] = 0x00; d->config[0x05] = 0x00; d->config[0x06] = 0x80; - d->config[0x07] = 0xa2; + d->config[0x07] = 0x02; + d->config[0x08] = 0x10; d->config[0x09] = 0x00; - d->config[0x0A] = 0x80; - d->config[0x0B] = 0x05; - d->config[0x0C] = 0x08; - d->config[0x0D] = 0x40; - d->config[0x0E] = 0x00; - d->config[0x0F] = 0x00; - d->config[0x17] = 0x08; + d->config[0x0A] = 0x00; + d->config[0x0B] = 0x06; + + d->config[0x10] = 0x08; + d->config[0x14] = 0x08; + d->config[0x17] = 0x01; d->config[0x1B] = 0x1c; d->config[0x1F] = 0x1f; d->config[0x23] = 0x14; + d->config[0x24] = 0x01; d->config[0x27] = 0x14; d->config[0x3D] = 0x01; -- cgit v1.2.3 From 30b6f3a866ba4cec86b86ddd22cf3fba3f23ea1d Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 18:09:57 +0000 Subject: Initialize more GT64xxx registers on reset. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2956 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 113 insertions(+), 11 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index f36e24abf..a9589c0b4 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -865,19 +865,31 @@ void gt64120_reset(void *opaque) { GT64120State *s = opaque; + /* FIXME: Malta specific hw assumptions ahead */ + /* CPU Configuration */ #ifdef TARGET_WORDS_BIGENDIAN s->regs[GT_CPU] = 0x00000000; #else s->regs[GT_CPU] = 0x00001000; #endif - s->regs[GT_MULTI] = 0x00000000; + s->regs[GT_MULTI] = 0x00000003; + + /* CPU Address decode */ + s->regs[GT_SCS10LD] = 0x00000000; + s->regs[GT_SCS10HD] = 0x00000007; + s->regs[GT_SCS32LD] = 0x00000008; + s->regs[GT_SCS32HD] = 0x0000000f; + s->regs[GT_CS20LD] = 0x000000e0; + s->regs[GT_CS20HD] = 0x00000070; + s->regs[GT_CS3BOOTLD] = 0x000000f8; + s->regs[GT_CS3BOOTHD] = 0x0000007f; - /* CPU Address decode FIXME: not complete*/ s->regs[GT_PCI0IOLD] = 0x00000080; s->regs[GT_PCI0IOHD] = 0x0000000f; s->regs[GT_PCI0M0LD] = 0x00000090; s->regs[GT_PCI0M0HD] = 0x0000001f; + s->regs[GT_ISD] = 0x000000a0; s->regs[GT_PCI0M1LD] = 0x00000790; s->regs[GT_PCI0M1HD] = 0x0000001f; s->regs[GT_PCI1IOLD] = 0x00000100; @@ -886,6 +898,12 @@ void gt64120_reset(void *opaque) s->regs[GT_PCI1M0HD] = 0x0000001f; s->regs[GT_PCI1M1LD] = 0x00000120; s->regs[GT_PCI1M1HD] = 0x0000002f; + + s->regs[GT_SCS10AR] = 0x00000000; + s->regs[GT_SCS32AR] = 0x00000008; + s->regs[GT_CS20R] = 0x000000e0; + s->regs[GT_CS3BOOTR] = 0x000000f8; + s->regs[GT_PCI0IOREMAP] = 0x00000080; s->regs[GT_PCI0M0REMAP] = 0x00000090; s->regs[GT_PCI0M1REMAP] = 0x00000790; @@ -900,6 +918,43 @@ void gt64120_reset(void *opaque) s->regs[GT_CPUERR_DATAHI] = 0xffffffff; s->regs[GT_CPUERR_PARITY] = 0x000000ff; + /* CPU Sync Barrier */ + s->regs[GT_PCI0SYNC] = 0x00000000; + s->regs[GT_PCI1SYNC] = 0x00000000; + + /* SDRAM and Device Address Decode */ + s->regs[GT_SCS0LD] = 0x00000000; + s->regs[GT_SCS0HD] = 0x00000007; + s->regs[GT_SCS1LD] = 0x00000008; + s->regs[GT_SCS1HD] = 0x0000000f; + s->regs[GT_SCS2LD] = 0x00000010; + s->regs[GT_SCS2HD] = 0x00000017; + s->regs[GT_SCS3LD] = 0x00000018; + s->regs[GT_SCS3HD] = 0x0000001f; + s->regs[GT_CS0LD] = 0x000000c0; + s->regs[GT_CS0HD] = 0x000000c7; + s->regs[GT_CS1LD] = 0x000000c8; + s->regs[GT_CS1HD] = 0x000000cf; + s->regs[GT_CS2LD] = 0x000000d0; + s->regs[GT_CS2HD] = 0x000000df; + s->regs[GT_CS3LD] = 0x000000f0; + s->regs[GT_CS3HD] = 0x000000fb; + s->regs[GT_BOOTLD] = 0x000000fc; + s->regs[GT_BOOTHD] = 0x000000ff; + s->regs[GT_ADERR] = 0xffffffff; + + /* SDRAM Configuration */ + s->regs[GT_SDRAM_CFG] = 0x00000200; + s->regs[GT_SDRAM_OPMODE] = 0x00000000; + s->regs[GT_SDRAM_BM] = 0x00000007; + s->regs[GT_SDRAM_ADDRDECODE] = 0x00000002; + + /* SDRAM Parameters */ + s->regs[GT_SDRAM_B0] = 0x00000005; + s->regs[GT_SDRAM_B1] = 0x00000005; + s->regs[GT_SDRAM_B2] = 0x00000005; + s->regs[GT_SDRAM_B3] = 0x00000005; + /* ECC */ s->regs[GT_ECC_ERRDATALO] = 0x00000000; s->regs[GT_ECC_ERRDATAHI] = 0x00000000; @@ -907,22 +962,69 @@ void gt64120_reset(void *opaque) s->regs[GT_ECC_CALC] = 0x00000000; s->regs[GT_ECC_ERRADDR] = 0x00000000; - /* SDRAM Parameters */ - s->regs[GT_SDRAM_B0] = 0x00000005; - s->regs[GT_SDRAM_B1] = 0x00000005; - s->regs[GT_SDRAM_B2] = 0x00000005; - s->regs[GT_SDRAM_B3] = 0x00000005; + /* Device Parameters */ + s->regs[GT_DEV_B0] = 0x386fffff; + s->regs[GT_DEV_B1] = 0x386fffff; + s->regs[GT_DEV_B2] = 0x386fffff; + s->regs[GT_DEV_B3] = 0x386fffff; + s->regs[GT_DEV_BOOT] = 0x146fffff; - /* PCI Internal FIXME: not complete*/ + /* DMA registers are all zeroed at reset */ + + /* Timer/Counter */ + s->regs[GT_TC0] = 0xffffffff; + s->regs[GT_TC1] = 0x00ffffff; + s->regs[GT_TC2] = 0x00ffffff; + s->regs[GT_TC3] = 0x00ffffff; + s->regs[GT_TC_CONTROL] = 0x00000000; + + /* PCI Internal */ #ifdef TARGET_WORDS_BIGENDIAN s->regs[GT_PCI0_CMD] = 0x00000000; - s->regs[GT_PCI1_CMD] = 0x00000000; #else s->regs[GT_PCI0_CMD] = 0x00010001; - s->regs[GT_PCI1_CMD] = 0x00010001; #endif - s->regs[GT_PCI0_IACK] = 0x00000000; + s->regs[GT_PCI0_TOR] = 0x0000070f; + s->regs[GT_PCI0_BS_SCS10] = 0x00fff000; + s->regs[GT_PCI0_BS_SCS32] = 0x00fff000; + s->regs[GT_PCI0_BS_CS20] = 0x01fff000; + s->regs[GT_PCI0_BS_CS3BT] = 0x00fff000; s->regs[GT_PCI1_IACK] = 0x00000000; + s->regs[GT_PCI0_IACK] = 0x00000000; + s->regs[GT_PCI0_BARE] = 0x0000000f; + s->regs[GT_PCI0_PREFMBR] = 0x00000040; + s->regs[GT_PCI0_SCS10_BAR] = 0x00000000; + s->regs[GT_PCI0_SCS32_BAR] = 0x01000000; + s->regs[GT_PCI0_CS20_BAR] = 0x1c000000; + s->regs[GT_PCI0_CS3BT_BAR] = 0x1f000000; + s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000; + s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000; + s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000; +#ifdef TARGET_WORDS_BIGENDIAN + s->regs[GT_PCI1_CMD] = 0x00000000; +#else + s->regs[GT_PCI1_CMD] = 0x00010001; +#endif + s->regs[GT_PCI1_TOR] = 0x0000070f; + s->regs[GT_PCI1_BS_SCS10] = 0x00fff000; + s->regs[GT_PCI1_BS_SCS32] = 0x00fff000; + s->regs[GT_PCI1_BS_CS20] = 0x01fff000; + s->regs[GT_PCI1_BS_CS3BT] = 0x00fff000; + s->regs[GT_PCI1_BARE] = 0x0000000f; + s->regs[GT_PCI1_PREFMBR] = 0x00000040; + s->regs[GT_PCI1_SCS10_BAR] = 0x00000000; + s->regs[GT_PCI1_SCS32_BAR] = 0x01000000; + s->regs[GT_PCI1_CS20_BAR] = 0x1c000000; + s->regs[GT_PCI1_CS3BT_BAR] = 0x1f000000; + s->regs[GT_PCI1_SSCS10_BAR] = 0x00000000; + s->regs[GT_PCI1_SSCS32_BAR] = 0x01000000; + s->regs[GT_PCI1_SCS3BT_BAR] = 0x1f000000; + s->regs[GT_PCI1_CFGADDR] = 0x00000000; + s->regs[GT_PCI1_CFGDATA] = 0x00000000; + s->regs[GT_PCI0_CFGADDR] = 0x00000000; + s->regs[GT_PCI0_CFGDATA] = 0x00000000; + + /* Interrupt registers are all zeroed at reset */ gt64120_pci_mapping(s); } -- cgit v1.2.3 From f00cb701b051427895d9c807126518c5b2208b5d Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 19:45:43 +0000 Subject: Unbreak PCI config register, noticed by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2957 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index a9589c0b4..f75f8af21 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -720,7 +720,7 @@ static uint32_t gt64120_readl (void *opaque, if (!(s->pci->config_reg & (1u << 31))) val = 0xffffffff; else - val = pci_data_read(s->pci->bus, s->pci->config_reg, 4); + val = pci_host_data_readl(s->pci, 0); break; case GT_PCI0_CMD: -- cgit v1.2.3 From 0fa7f157309dedfd715179241a70b43739a45fb1 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 7 Jun 2007 21:07:11 +0000 Subject: Fix code formatting, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2958 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/parallel.c | 326 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 163 insertions(+), 163 deletions(-) diff --git a/hw/parallel.c b/hw/parallel.c index c927ddd96..e8e533bc7 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -91,29 +91,29 @@ parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val) addr &= 7; switch(addr) { case PARA_REG_DATA: - s->dataw = val; - parallel_update_irq(s); + s->dataw = val; + parallel_update_irq(s); break; case PARA_REG_CTR: - if ((val & PARA_CTR_INIT) == 0 ) { - s->status = PARA_STS_BUSY; - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_ONLINE; - s->status |= PARA_STS_ERROR; - } - else if (val & PARA_CTR_SELECT) { - if (val & PARA_CTR_STROBE) { - s->status &= ~PARA_STS_BUSY; - if ((s->control & PARA_CTR_STROBE) == 0) - qemu_chr_write(s->chr, &s->dataw, 1); - } else { - if (s->control & PARA_CTR_INTEN) { - s->irq_pending = 1; - } - } - } - parallel_update_irq(s); - s->control = val; + if ((val & PARA_CTR_INIT) == 0 ) { + s->status = PARA_STS_BUSY; + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_ONLINE; + s->status |= PARA_STS_ERROR; + } + else if (val & PARA_CTR_SELECT) { + if (val & PARA_CTR_STROBE) { + s->status &= ~PARA_STS_BUSY; + if ((s->control & PARA_CTR_STROBE) == 0) + qemu_chr_write(s->chr, &s->dataw, 1); + } else { + if (s->control & PARA_CTR_INTEN) { + s->irq_pending = 1; + } + } + } + parallel_update_irq(s); + s->control = val; break; } } @@ -132,52 +132,52 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val) switch(addr) { case PARA_REG_DATA: if (s->dataw == val) - return; - pdebug("wd%02x\n", val); - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm); - s->dataw = val; + return; + pdebug("wd%02x\n", val); + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm); + s->dataw = val; break; case PARA_REG_STS: - pdebug("ws%02x\n", val); - if (val & PARA_STS_TMOUT) - s->epp_timeout = 0; - break; + pdebug("ws%02x\n", val); + if (val & PARA_STS_TMOUT) + s->epp_timeout = 0; + break; case PARA_REG_CTR: val |= 0xc0; if (s->control == val) - return; - pdebug("wc%02x\n", val); - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm); - s->control = val; + return; + pdebug("wc%02x\n", val); + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm); + s->control = val; break; case PARA_REG_EPP_ADDR: - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) - /* Controls not correct for EPP address cycle, so do nothing */ - pdebug("wa%02x s\n", val); - else { - struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; - if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) { - s->epp_timeout = 1; - pdebug("wa%02x t\n", val); - } - else - pdebug("wa%02x\n", val); - } - break; + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) + /* Controls not correct for EPP address cycle, so do nothing */ + pdebug("wa%02x s\n", val); + else { + struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; + if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) { + s->epp_timeout = 1; + pdebug("wa%02x t\n", val); + } + else + pdebug("wa%02x\n", val); + } + break; case PARA_REG_EPP_DATA: - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("we%02x s\n", val); - else { - struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; - if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) { - s->epp_timeout = 1; - pdebug("we%02x t\n", val); - } - else - pdebug("we%02x\n", val); - } - break; + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("we%02x s\n", val); + else { + struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; + if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) { + s->epp_timeout = 1; + pdebug("we%02x t\n", val); + } + else + pdebug("we%02x\n", val); + } + break; } } @@ -188,20 +188,20 @@ parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val) uint16_t eppdata = cpu_to_le16(val); int err; struct ParallelIOArg ioarg = { - .buffer = &eppdata, .count = sizeof(eppdata) + .buffer = &eppdata, .count = sizeof(eppdata) }; if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) { - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("we%04x s\n", val); - return; + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("we%04x s\n", val); + return; } err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); if (err) { - s->epp_timeout = 1; - pdebug("we%04x t\n", val); + s->epp_timeout = 1; + pdebug("we%04x t\n", val); } else - pdebug("we%04x\n", val); + pdebug("we%04x\n", val); } static void @@ -211,20 +211,20 @@ parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val) uint32_t eppdata = cpu_to_le32(val); int err; struct ParallelIOArg ioarg = { - .buffer = &eppdata, .count = sizeof(eppdata) + .buffer = &eppdata, .count = sizeof(eppdata) }; if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) { - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("we%08x s\n", val); - return; + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("we%08x s\n", val); + return; } err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); if (err) { - s->epp_timeout = 1; - pdebug("we%08x t\n", val); + s->epp_timeout = 1; + pdebug("we%08x t\n", val); } else - pdebug("we%08x\n", val); + pdebug("we%08x\n", val); } static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr) @@ -235,25 +235,25 @@ static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr) addr &= 7; switch(addr) { case PARA_REG_DATA: - if (s->control & PARA_CTR_DIR) - ret = s->datar; - else - ret = s->dataw; + if (s->control & PARA_CTR_DIR) + ret = s->datar; + else + ret = s->dataw; break; case PARA_REG_STS: - ret = s->status; - s->irq_pending = 0; - if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { - /* XXX Fixme: wait 5 microseconds */ - if (s->status & PARA_STS_ACK) - s->status &= ~PARA_STS_ACK; - else { - /* XXX Fixme: wait 5 microseconds */ - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_BUSY; - } - } - parallel_update_irq(s); + ret = s->status; + s->irq_pending = 0; + if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { + /* XXX Fixme: wait 5 microseconds */ + if (s->status & PARA_STS_ACK) + s->status &= ~PARA_STS_ACK; + else { + /* XXX Fixme: wait 5 microseconds */ + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_BUSY; + } + } + parallel_update_irq(s); break; case PARA_REG_CTR: ret = s->control; @@ -270,63 +270,63 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr) addr &= 7; switch(addr) { case PARA_REG_DATA: - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret); - if (s->last_read_offset != addr || s->datar != ret) - pdebug("rd%02x\n", ret); + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret); + if (s->last_read_offset != addr || s->datar != ret) + pdebug("rd%02x\n", ret); s->datar = ret; break; case PARA_REG_STS: - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret); - ret &= ~PARA_STS_TMOUT; - if (s->epp_timeout) - ret |= PARA_STS_TMOUT; - if (s->last_read_offset != addr || s->status != ret) - pdebug("rs%02x\n", ret); - s->status = ret; + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret); + ret &= ~PARA_STS_TMOUT; + if (s->epp_timeout) + ret |= PARA_STS_TMOUT; + if (s->last_read_offset != addr || s->status != ret) + pdebug("rs%02x\n", ret); + s->status = ret; break; case PARA_REG_CTR: /* s->control has some bits fixed to 1. It is zero only when - it has not been yet written to. */ - if (s->control == 0) { - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret); - if (s->last_read_offset != addr) - pdebug("rc%02x\n", ret); - s->control = ret; - } - else { - ret = s->control; - if (s->last_read_offset != addr) - pdebug("rc%02x\n", ret); - } + it has not been yet written to. */ + if (s->control == 0) { + qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret); + if (s->last_read_offset != addr) + pdebug("rc%02x\n", ret); + s->control = ret; + } + else { + ret = s->control; + if (s->last_read_offset != addr) + pdebug("rc%02x\n", ret); + } break; case PARA_REG_EPP_ADDR: - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) - /* Controls not correct for EPP addr cycle, so do nothing */ - pdebug("ra%02x s\n", ret); - else { - struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; - if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) { - s->epp_timeout = 1; - pdebug("ra%02x t\n", ret); - } - else - pdebug("ra%02x\n", ret); - } - break; + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) + /* Controls not correct for EPP addr cycle, so do nothing */ + pdebug("ra%02x s\n", ret); + else { + struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; + if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) { + s->epp_timeout = 1; + pdebug("ra%02x t\n", ret); + } + else + pdebug("ra%02x\n", ret); + } + break; case PARA_REG_EPP_DATA: - if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("re%02x s\n", ret); - else { - struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; - if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) { - s->epp_timeout = 1; - pdebug("re%02x t\n", ret); - } - else - pdebug("re%02x\n", ret); - } - break; + if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("re%02x s\n", ret); + else { + struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; + if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) { + s->epp_timeout = 1; + pdebug("re%02x t\n", ret); + } + else + pdebug("re%02x\n", ret); + } + break; } s->last_read_offset = addr; return ret; @@ -340,22 +340,22 @@ parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr) uint16_t eppdata = ~0; int err; struct ParallelIOArg ioarg = { - .buffer = &eppdata, .count = sizeof(eppdata) + .buffer = &eppdata, .count = sizeof(eppdata) }; if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) { - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("re%04x s\n", eppdata); - return eppdata; + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("re%04x s\n", eppdata); + return eppdata; } err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); ret = le16_to_cpu(eppdata); if (err) { - s->epp_timeout = 1; - pdebug("re%04x t\n", ret); + s->epp_timeout = 1; + pdebug("re%04x t\n", ret); } else - pdebug("re%04x\n", ret); + pdebug("re%04x\n", ret); return ret; } @@ -367,22 +367,22 @@ parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr) uint32_t eppdata = ~0U; int err; struct ParallelIOArg ioarg = { - .buffer = &eppdata, .count = sizeof(eppdata) + .buffer = &eppdata, .count = sizeof(eppdata) }; if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) { - /* Controls not correct for EPP data cycle, so do nothing */ - pdebug("re%08x s\n", eppdata); - return eppdata; + /* Controls not correct for EPP data cycle, so do nothing */ + pdebug("re%08x s\n", eppdata); + return eppdata; } err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); ret = le32_to_cpu(eppdata); if (err) { - s->epp_timeout = 1; - pdebug("re%08x t\n", ret); + s->epp_timeout = 1; + pdebug("re%08x t\n", ret); } else - pdebug("re%08x\n", ret); + pdebug("re%08x\n", ret); return ret; } @@ -426,22 +426,22 @@ ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr) if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) { s->hw_driver = 1; - s->status = dummy; + s->status = dummy; } if (s->hw_driver) { - register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s); - register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s); - register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s); - register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s); - register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s); - register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s); - register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s); - register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s); + register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s); + register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s); + register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s); + register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s); + register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s); + register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s); + register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s); + register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s); } else { - register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s); - register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s); + register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s); + register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s); } return s; } -- cgit v1.2.3 From 29b3a6627e57585a156fb753c7781b4b1646a934 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 7 Jun 2007 23:09:47 +0000 Subject: Windows build fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2959 c046a42c-6fe2-441c-8c8c-71466251a162 --- m68k-semi.c | 10 ++++++++-- osdep.c | 24 ++++++++++++++++++++++++ osdep.h | 11 +++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/m68k-semi.c b/m68k-semi.c index 27bdce8e2..73224f181 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -116,8 +116,14 @@ static void translate_stat(CPUState *env, target_ulong addr, struct stat *s) p->gdb_st_gid = cpu_to_be32(s->st_gid); p->gdb_st_rdev = cpu_to_be32(s->st_rdev); p->gdb_st_size = cpu_to_be64(s->st_size); +#ifdef _WIN32 + /* Windows stat is missing some fields. */ + p->gdb_st_blksize = 0; + p->gdb_st_blocks = 0; +#else p->gdb_st_blksize = cpu_to_be64(s->st_blksize); p->gdb_st_blocks = cpu_to_be64(s->st_blocks); +#endif p->gdb_st_atime = cpu_to_be32(s->st_atime); p->gdb_st_mtime = cpu_to_be32(s->st_mtime); p->gdb_st_ctime = cpu_to_be32(s->st_ctime); @@ -281,9 +287,9 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), ARG(1)); return; } else { - struct timeval tv; + qemu_timeval tv; struct gdb_timeval *p; - result = gettimeofday(&tv, NULL); + result = qemu_gettimeofday(&tv); if (result != 0) { p = lock_user(ARG(0), sizeof(struct gdb_timeval), 0); p->tv_sec = cpu_to_be32(tv.tv_sec); diff --git a/osdep.c b/osdep.c index ccc1d70bb..c24906c99 100644 --- a/osdep.c +++ b/osdep.c @@ -264,3 +264,27 @@ int qemu_create_pidfile(const char *filename) #endif return 0; } + +#ifdef _WIN32 + +/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ +#define _W32_FT_OFFSET (116444736000000000ULL) + +int qemu_gettimeofday(qemu_timeval *tp) +{ + union { + unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ + FILETIME ft; + } _now; + + if(tp) + { + GetSystemTimeAsFileTime (&_now.ft); + tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL ); + tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL); + } + /* Always return 0 as per Open Group Base Specifications Issue 6. + Do not set errno on error. */ + return 0; +} +#endif /* _WIN32 */ diff --git a/osdep.h b/osdep.h index 68d29d74e..50686d593 100644 --- a/osdep.h +++ b/osdep.h @@ -17,4 +17,15 @@ void *get_mmap_addr(unsigned long size); int qemu_create_pidfile(const char *filename); +#ifdef _WIN32 +typedef struct { + long tv_sec; + long tv_usec; +} qemu_timeval; +int qemu_gettimeofday(qemu_timeval *tp); +#else +typedef struct timeval qemu_timeval; +#define qemu_gettimeofday(tp) gettimeofday(tp, NULL); +#endif /* !_WIN32 */ + #endif -- cgit v1.2.3 From 4fdcd8d43e97dbfbd0e3045b5675f323eb5dd916 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 7 Jun 2007 23:24:56 +0000 Subject: Fix return type. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2960 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mcf_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 3787c23ae..d4613dda2 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -188,7 +188,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s) s->tx_descriptor = addr; } -static int mcf_fec_enable_rx(mcf_fec_state *s) +static void mcf_fec_enable_rx(mcf_fec_state *s) { mcf_fec_bd bd; -- cgit v1.2.3 From 740733bb939963e77dacda0367eb807dea1c4faf Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 8 Jun 2007 01:57:56 +0000 Subject: Don't refresh a graphical screen when it isn't displayed, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2961 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 45 ++++++++++----------------------------------- vl.h | 1 + 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/vl.c b/vl.c index 513ab4649..4f9c44389 100644 --- a/vl.c +++ b/vl.c @@ -153,7 +153,6 @@ int ram_size; int pit_min_timer_count = 0; int nb_nics; NICInfo nd_table[MAX_NICS]; -QEMUTimer *gui_timer; int vm_running; int rtc_utc = 1; int cirrus_vga_enabled = 1; @@ -4480,32 +4479,6 @@ void pcmcia_info(void) "Empty"); } -/***********************************************************/ -/* dumb display */ - -static void dumb_update(DisplayState *ds, int x, int y, int w, int h) -{ -} - -static void dumb_resize(DisplayState *ds, int w, int h) -{ -} - -static void dumb_refresh(DisplayState *ds) -{ - vga_hw_update(); -} - -void dumb_display_init(DisplayState *ds) -{ - ds->data = NULL; - ds->linesize = 0; - ds->depth = 0; - ds->dpy_update = dumb_update; - ds->dpy_resize = dumb_resize; - ds->dpy_refresh = dumb_refresh; -} - /***********************************************************/ /* I/O handling */ @@ -6198,8 +6171,9 @@ QEMUMachine *find_machine(const char *name) void gui_update(void *opaque) { - display_state.dpy_refresh(&display_state); - qemu_mod_timer(gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock)); + DisplayState *ds = opaque; + ds->dpy_refresh(ds); + qemu_mod_timer(ds->gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock)); } struct vm_change_state_entry { @@ -7899,17 +7873,16 @@ int main(int argc, char **argv) init_ioports(); /* terminal init */ + memset(&display_state, 0, sizeof(display_state)); if (nographic) { - dumb_display_init(ds); + /* nothing to do */ } else if (vnc_display != NULL) { - vnc_display_init(ds, vnc_display); + vnc_display_init(ds, vnc_display); } else { #if defined(CONFIG_SDL) sdl_display_init(ds, full_screen, no_frame); #elif defined(CONFIG_COCOA) cocoa_display_init(ds, full_screen); -#else - dumb_display_init(ds); #endif } @@ -7977,8 +7950,10 @@ int main(int argc, char **argv) } } - gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); - qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); + if (display_state.dpy_refresh) { + display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state); + qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock)); + } #ifdef CONFIG_GDBSTUB if (use_gdbstub) { diff --git a/vl.h b/vl.h index 976af60e8..7d82bd111 100644 --- a/vl.h +++ b/vl.h @@ -914,6 +914,7 @@ struct DisplayState { int width; int height; void *opaque; + QEMUTimer *gui_timer; void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); void (*dpy_resize)(struct DisplayState *s, int w, int h); -- cgit v1.2.3 From 71db710f7ee00cf324153bbc203e6dad8c99850b Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 8 Jun 2007 16:45:23 +0000 Subject: Fix incorrect target_ulong use in hw devices git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2962 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dma.c | 4 ++-- hw/ds1225y.c | 4 ++-- hw/pckbd.c | 4 ++-- hw/pflash_cfi02.c | 22 +++++++++++----------- hw/ppc405.h | 13 ++++++++----- hw/ppc405_boards.c | 4 ++-- hw/ppc405_uc.c | 25 ++++++++++++++----------- hw/serial.c | 4 ++-- vl.h | 11 ++++++----- 9 files changed, 49 insertions(+), 42 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index ea13eae49..2e8608cfc 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -383,7 +383,7 @@ void DMA_register_channel (int nchan, int DMA_read_memory (int nchan, void *buf, int pos, int len) { struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3]; - target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; + target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; if (r->mode & 0x20) { int i; @@ -405,7 +405,7 @@ int DMA_read_memory (int nchan, void *buf, int pos, int len) int DMA_write_memory (int nchan, void *buf, int pos, int len) { struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3]; - target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; + target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; if (r->mode & 0x20) { int i; diff --git a/hw/ds1225y.c b/hw/ds1225y.c index 48d6636b3..7851096fa 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -33,7 +33,7 @@ typedef enum struct ds1225y_t { - target_ulong mem_base; + target_phys_addr_t mem_base; uint32_t capacity; const char *filename; QEMUFile *file; @@ -99,7 +99,7 @@ static CPUWriteMemoryFunc *nvram_none[] = { }; /* Initialisation routine */ -ds1225y_t *ds1225y_init(target_ulong mem_base, const char *filename) +ds1225y_t *ds1225y_init(target_phys_addr_t mem_base, const char *filename) { ds1225y_t *s; int mem_index1, mem_index2; diff --git a/hw/pckbd.c b/hw/pckbd.c index de508b309..8f2466d80 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -421,8 +421,8 @@ static CPUWriteMemoryFunc *kbd_mm_write[] = { &kbd_mm_writeb, }; -void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, - int it_shift) +void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, + target_phys_addr_t base, int it_shift) { KBDState *s = &kbd_state; int s_io_memory; diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 76e4a1d9b..f98d11438 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -50,9 +50,9 @@ do { \ struct pflash_t { BlockDriverState *bs; - target_ulong base; - target_ulong sector_len; - target_ulong total_len; + target_phys_addr_t base; + uint32_t sector_len; + uint32_t total_len; int width; int wcycle; /* if 0, the flash is read normally */ int bypass; @@ -85,9 +85,9 @@ static void pflash_timer (void *opaque) pfl->cmd = 0; } -static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width) +static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width) { - target_ulong boff; + uint32_t boff; uint32_t ret; uint8_t *p; @@ -199,10 +199,10 @@ static void pflash_update(pflash_t *pfl, int offset, } } -static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, +static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, int width) { - target_ulong boff; + uint32_t boff; uint8_t *p; uint8_t cmd; @@ -219,7 +219,7 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__, offset, value, width, pfl->wcycle); if (pfl->wcycle == 0) - offset -= (target_ulong)(long)pfl->storage; + offset -= (uint32_t)(long)pfl->storage; else offset -= pfl->base; @@ -521,14 +521,14 @@ static int ctz32 (uint32_t n) return ret; } -pflash_t *pflash_register (target_ulong base, ram_addr_t off, +pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, BlockDriverState *bs, - target_ulong sector_len, int nb_blocs, int width, + uint32_t sector_len, int nb_blocs, int width, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3) { pflash_t *pfl; - target_long total_len; + int32_t total_len; total_len = sector_len * nb_blocs; /* XXX: to be fixed */ diff --git a/hw/ppc405.h b/hw/ppc405.h index c491ed55e..b2624c386 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -83,7 +83,8 @@ qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, uint32_t dcr_base, int has_ssr, int has_vr); /* SDRAM controller */ void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, - target_ulong *ram_bases, target_ulong *ram_sizes, + target_phys_addr_t *ram_bases, + target_phys_addr_t *ram_sizes, int do_init); /* Peripheral controller */ void ppc405_ebc_init (CPUState *env); @@ -107,15 +108,17 @@ void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio, /* Memory access layer */ void ppc405_mal_init (CPUState *env, qemu_irq irqs[4]); /* PowerPC 405 microcontrollers */ -CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], +CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4], + target_phys_addr_t ram_sizes[4], uint32_t sysclk, qemu_irq **picp, ram_addr_t *offsetp, int do_init); -CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], +CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2], + target_phys_addr_t ram_sizes[2], uint32_t sysclk, qemu_irq **picp, ram_addr_t *offsetp, int do_init); /* IBM STBxxx microcontrollers */ -CPUState *ppc_stb025_init (target_ulong ram_bases[2], - target_ulong ram_sizes[2], +CPUState *ppc_stb025_init (target_phys_addr_t ram_bases[2], + target_phys_addr_t ram_sizes[2], uint32_t sysclk, qemu_irq **picp, ram_addr_t *offsetp); diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 2e2ca0e74..b0be417d3 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -184,7 +184,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, CPUPPCState *env; qemu_irq *pic; ram_addr_t sram_offset, bios_offset, bdloc; - target_ulong ram_bases[2], ram_sizes[2]; + target_phys_addr_t ram_bases[2], ram_sizes[2]; target_ulong sram_size, bios_size; //int phy_addr = 0; //static int phy_addr = 1; @@ -506,7 +506,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, CPUPPCState *env; qemu_irq *pic; ram_addr_t bios_offset; - target_ulong ram_bases[2], ram_sizes[2]; + target_phys_addr_t ram_bases[2], ram_sizes[2]; target_ulong bios_size; target_ulong kernel_base, kernel_size, initrd_base, initrd_size; int linux_boot; diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index e06165d52..384eb0d3e 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -903,8 +903,8 @@ typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; struct ppc4xx_sdram_t { uint32_t addr; int nbanks; - target_ulong ram_bases[4]; - target_ulong ram_sizes[4]; + target_phys_addr_t ram_bases[4]; + target_phys_addr_t ram_sizes[4]; uint32_t besr0; uint32_t besr1; uint32_t bear; @@ -924,7 +924,7 @@ enum { SDRAM0_CFGDATA = 0x011, }; -static uint32_t sdram_bcr (target_ulong ram_base, target_ulong ram_size) +static uint32_t sdram_bcr (target_phys_addr_t ram_base, target_phys_addr_t ram_size) { uint32_t bcr; @@ -960,7 +960,7 @@ static uint32_t sdram_bcr (target_ulong ram_base, target_ulong ram_size) return bcr; } -static inline target_ulong sdram_base (uint32_t bcr) +static inline target_phys_addr_t sdram_base (uint32_t bcr) { return bcr & 0xFF800000; } @@ -1206,7 +1206,8 @@ static void sdram_reset (void *opaque) } void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, - target_ulong *ram_bases, target_ulong *ram_sizes, + target_phys_addr_t *ram_bases, + target_phys_addr_t *ram_sizes, int do_init) { ppc4xx_sdram_t *sdram; @@ -1215,10 +1216,10 @@ void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, if (sdram != NULL) { sdram->irq = irq; sdram->nbanks = nbanks; - memset(sdram->ram_bases, 0, 4 * sizeof(target_ulong)); - memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(target_ulong)); - memset(sdram->ram_sizes, 0, 4 * sizeof(target_ulong)); - memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(target_ulong)); + memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t)); + memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(target_phys_addr_t)); + memset(sdram->ram_sizes, 0, 4 * sizeof(target_phys_addr_t)); + memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(target_phys_addr_t)); sdram_reset(sdram); qemu_register_reset(&sdram_reset, sdram); ppc_dcr_register(env, SDRAM0_CFGADDR, @@ -3017,7 +3018,8 @@ static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7], } } -CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4], +CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4], + target_phys_addr_t ram_sizes[4], uint32_t sysclk, qemu_irq **picp, ram_addr_t *offsetp, int do_init) { @@ -3365,7 +3367,8 @@ static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8], } } -CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2], +CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2], + target_phys_addr_t ram_sizes[2], uint32_t sysclk, qemu_irq **picp, ram_addr_t *offsetp, int do_init) { diff --git a/hw/serial.c b/hw/serial.c index 088886258..5513007d1 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -86,7 +86,7 @@ struct SerialState { qemu_irq irq; CharDriverState *chr; int last_break_enable; - target_ulong base; + target_phys_addr_t base; int it_shift; }; @@ -437,7 +437,7 @@ static CPUWriteMemoryFunc *serial_mm_write[] = { &serial_mm_writel, }; -SerialState *serial_mm_init (target_ulong base, int it_shift, +SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr, int ioregister) { diff --git a/vl.h b/vl.h index 7d82bd111..0ff5109f0 100644 --- a/vl.h +++ b/vl.h @@ -994,7 +994,7 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); /* ds1225y.c */ typedef struct ds1225y_t ds1225y_t; -ds1225y_t *ds1225y_init(target_ulong mem_base, const char *filename); +ds1225y_t *ds1225y_init(target_phys_addr_t mem_base, const char *filename); /* es1370.c */ int es1370_init (PCIBus *bus, AudioState *s); @@ -1059,7 +1059,8 @@ void *vmmouse_init(void *m); /* pckbd.c */ void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); -void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, int it_shift); +void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, + target_phys_addr_t base, int it_shift); /* mc146818rtc.c */ @@ -1074,7 +1075,7 @@ void rtc_set_date(RTCState *s, const struct tm *tm); typedef struct SerialState SerialState; SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr); -SerialState *serial_mm_init (target_ulong base, int it_shift, +SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr, int ioregister); uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr); @@ -1485,9 +1486,9 @@ int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); extern BlockDriverState *pflash_table[MAX_PFLASH]; typedef struct pflash_t pflash_t; -pflash_t *pflash_register (target_ulong base, ram_addr_t off, +pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, BlockDriverState *bs, - target_ulong sector_len, int nb_blocs, int width, + uint32_t sector_len, int nb_blocs, int width, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); -- cgit v1.2.3 From 70cf0b63f106e6de33326b47c485d0624831f237 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 9 Jun 2007 12:29:32 +0000 Subject: R5k has PX implemented. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2963 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index bbfa63b30..c5b27330b 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -161,7 +161,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FFFF, + .Status_rw_bitmask = 0x32F8FFFF, }, { .name = "5Kf", @@ -175,7 +175,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3678FFFF, + .Status_rw_bitmask = 0x36F8FFFF, /* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */ .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) | (0x81 << FCR0_PRID) | (0x0 << FCR0_REV), -- cgit v1.2.3 From 6361cdb630afa036dcff8586735c38d1aca55a7c Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 9 Jun 2007 14:07:54 +0000 Subject: ARM PL181 MMCI fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2964 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl181.c | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/hw/pl181.c b/hw/pl181.c index c0b89f775..912465971 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -36,9 +36,14 @@ typedef struct { uint32_t datacnt; uint32_t status; uint32_t mask[2]; - uint32_t fifocnt; int fifo_pos; int fifo_len; + /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives + while it is reading the FIFO. We hack around this be defering + subsequent transfers until after the driver polls the status word. + http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1 + */ + int linux_hack; uint32_t fifo[PL181_FIFO_LEN]; qemu_irq irq[2]; } pl181_state; @@ -182,7 +187,8 @@ static void pl181_fifo_run(pl181_state *s) int is_read; is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0; - if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))) { + if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card)) + && !s->linux_hack) { limit = is_read ? PL181_FIFO_LEN : 0; n = 0; value = 0; @@ -217,7 +223,7 @@ static void pl181_fifo_run(pl181_state *s) s->status |= PL181_STATUS_DATABLOCKEND; DPRINTF("Transfer Complete\n"); } - if (s->datacnt == 0 && s->fifocnt == 0) { + if (s->datacnt == 0 && s->fifo_len == 0) { s->datactrl &= ~PL181_DATA_ENABLE; DPRINTF("Data engine idle\n"); } else { @@ -252,6 +258,7 @@ static void pl181_fifo_run(pl181_state *s) static uint32_t pl181_read(void *opaque, target_phys_addr_t offset) { pl181_state *s = (pl181_state *)opaque; + uint32_t tmp; offset -= s->base; if (offset >= 0xfe0 && offset < 0x1000) { @@ -285,24 +292,42 @@ static uint32_t pl181_read(void *opaque, target_phys_addr_t offset) case 0x30: /* DataCnt */ return s->datacnt; case 0x34: /* Status */ - return s->status; + tmp = s->status; + if (s->linux_hack) { + s->linux_hack = 0; + pl181_fifo_run(s); + pl181_update(s); + } + return tmp; case 0x3c: /* Mask0 */ return s->mask[0]; case 0x40: /* Mask1 */ return s->mask[1]; case 0x48: /* FifoCnt */ - return s->fifocnt; + /* The documentation is somewhat vague about exactly what FifoCnt + does. On real hardware it appears to be when decrememnted + when a word is transfered between the FIFO and the serial + data engine. DataCnt is decremented after each byte is + transfered between the serial engine and the card. + We don't emulate this level of detail, so both can be the same. */ + tmp = (s->datacnt + 3) >> 2; + if (s->linux_hack) { + s->linux_hack = 0; + pl181_fifo_run(s); + pl181_update(s); + } + return tmp; case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ case 0x90: case 0x94: case 0x98: case 0x9c: case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: case 0xb4: case 0xb8: case 0xbc: - if (s->fifocnt == 0) { + if (s->fifo_len == 0) { fprintf(stderr, "pl181: Unexpected FIFO read\n"); return 0; } else { uint32_t value; - s->fifocnt--; value = pl181_fifo_pop(s); + s->linux_hack = 1; pl181_fifo_run(s); pl181_update(s); return value; @@ -356,7 +381,6 @@ static void pl181_write(void *opaque, target_phys_addr_t offset, s->datactrl = value & 0xff; if (value & PL181_DATA_ENABLE) { s->datacnt = s->datalength; - s->fifocnt = (s->datalength + 3) >> 2; pl181_fifo_run(s); } break; @@ -373,10 +397,9 @@ static void pl181_write(void *opaque, target_phys_addr_t offset, case 0x90: case 0x94: case 0x98: case 0x9c: case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: case 0xb4: case 0xb8: case 0xbc: - if (s->fifocnt == 0) { + if (s->datacnt == 0) { fprintf(stderr, "pl181: Unexpected FIFO write\n"); } else { - s->fifocnt--; pl181_fifo_push(s, value); pl181_fifo_run(s); } @@ -418,9 +441,9 @@ static void pl181_reset(void *opaque) s->datactrl = 0; s->datacnt = 0; s->status = 0; + s->linux_hack = 0; s->mask[0] = 0; s->mask[1] = 0; - s->fifocnt = 0; } void pl181_init(uint32_t base, BlockDriverState *bd, -- cgit v1.2.3 From 33d9cc8a9691157fd99b681a5122f734522fc63a Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 9 Jun 2007 14:44:00 +0000 Subject: ARM GDB semihosting fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2965 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm-semi.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/arm-semi.c b/arm-semi.c index 56d8d4bf4..aaad1c99f 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -117,14 +117,21 @@ static inline uint32_t set_swi_errno(CPUState *env, uint32_t code) static target_ulong arm_semi_syscall_len; +#if !defined(CONFIG_USER_ONLY) +static target_ulong syscall_err; +#endif + static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err) { #ifdef CONFIG_USER_ONLY TaskState *ts = env->opaque; #endif + if (ret == (target_ulong)-1) { #ifdef CONFIG_USER_ONLY ts->swi_errno = err; +#else + syscall_err = err; #endif env->regs[0] = ret; } else { @@ -144,6 +151,20 @@ static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err) } } +static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err) +{ + /* The size is always stored in big-endian order, extract + the value. We assume the size always fit in 32 bits. */ + uint32_t size; + cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0); + env->regs[0] = be32_to_cpu(size); +#ifdef CONFIG_USER_ONLY + ((TaskState *)env->opaque)->swi_errno = err; +#else + syscall_err = err; +#endif +} + #define ARG(n) tget32(args + (n) * 4) #define SET_ARG(n, val) tput32(args + (n) * 4,val) uint32_t do_arm_semihosting(CPUState *env) @@ -173,8 +194,8 @@ uint32_t do_arm_semihosting(CPUState *env) return STDOUT_FILENO; } if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), (int)ARG(2), - gdb_open_modeflags[ARG(1)]); + gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), + (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]); return env->regs[0]; } else { ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); @@ -252,7 +273,7 @@ uint32_t do_arm_semihosting(CPUState *env) } case SYS_SEEK: if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "fseek,%x,%x,0", ARG(0), ARG(1)); + gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1)); return env->regs[0]; } else { ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); @@ -262,8 +283,9 @@ uint32_t do_arm_semihosting(CPUState *env) } case SYS_FLEN: if (use_gdb_syscalls()) { - /* TODO: Use stat syscall. */ - return -1; + gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x", + ARG(0), env->regs[13]-64); + return env->regs[0]; } else { struct stat buf; ret = set_swi_errno(ts, fstat(ARG(0), &buf)); @@ -276,7 +298,7 @@ uint32_t do_arm_semihosting(CPUState *env) return -1; case SYS_REMOVE: if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)); + gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1); ret = env->regs[0]; } else { s = lock_user_string(ARG(0)); @@ -287,7 +309,7 @@ uint32_t do_arm_semihosting(CPUState *env) case SYS_RENAME: if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "rename,%s,%s", - ARG(0), (int)ARG(1), ARG(2), (int)ARG(3)); + ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1); return env->regs[0]; } else { char *s2; @@ -304,7 +326,7 @@ uint32_t do_arm_semihosting(CPUState *env) return set_swi_errno(ts, time(NULL)); case SYS_SYSTEM: if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)); + gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1); return env->regs[0]; } else { s = lock_user_string(ARG(0)); @@ -315,7 +337,7 @@ uint32_t do_arm_semihosting(CPUState *env) #ifdef CONFIG_USER_ONLY return ts->swi_errno; #else - return 0; + return syscall_err; #endif case SYS_GET_CMDLINE: #ifdef CONFIG_USER_ONLY -- cgit v1.2.3 From 87ee166914e2d886b982a8d9e55c16b09a09a180 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 9 Jun 2007 15:44:26 +0000 Subject: Don't try to use "vt" output in nographic mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2966 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 7336b7b05..36b5f43e6 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -42,7 +42,7 @@ #define ENVP_NB_ENTRIES 16 #define ENVP_ENTRY_SIZE 256 - +extern int nographic; extern FILE *logfile; typedef struct { @@ -67,16 +67,18 @@ static void malta_fpga_update_display(void *opaque) int i; MaltaFPGAState *s = opaque; - for (i = 7 ; i >= 0 ; i--) { - if (s->leds & (1 << i)) - leds_text[i] = '#'; - else - leds_text[i] = ' '; - } - leds_text[8] = '\0'; + if (!nographic) { + for (i = 7 ; i >= 0 ; i--) { + if (s->leds & (1 << i)) + leds_text[i] = '#'; + else + leds_text[i] = ' '; + } + leds_text[8] = '\0'; - qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); - qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); + qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); + qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); + } } /* @@ -413,20 +415,22 @@ MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env) cpu_register_physical_memory(base, 0x900, malta); cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta); - s->display = qemu_chr_open("vc"); - qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n"); - qemu_chr_printf(s->display, "+--------+\r\n"); - qemu_chr_printf(s->display, "+ +\r\n"); - qemu_chr_printf(s->display, "+--------+\r\n"); - qemu_chr_printf(s->display, "\n"); - qemu_chr_printf(s->display, "Malta ASCII\r\n"); - qemu_chr_printf(s->display, "+--------+\r\n"); - qemu_chr_printf(s->display, "+ +\r\n"); - qemu_chr_printf(s->display, "+--------+\r\n"); - - uart_chr = qemu_chr_open("vc"); - qemu_chr_printf(uart_chr, "CBUS UART\r\n"); - s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1); + if (!nographic) { + s->display = qemu_chr_open("vc"); + qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "+ +\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "\n"); + qemu_chr_printf(s->display, "Malta ASCII\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "+ +\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + + uart_chr = qemu_chr_open("vc"); + qemu_chr_printf(uart_chr, "CBUS UART\r\n"); + s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1); + } malta_fpga_reset(s); qemu_register_reset(malta_fpga_reset, s); -- cgit v1.2.3 From 0cf5c6771b216793d1fe57d25864d842570f32f6 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 9 Jun 2007 20:48:46 +0000 Subject: M68K status register fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2967 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/op.c | 7 ++----- target-m68k/op_helper.c | 4 ++-- target-m68k/translate.c | 3 ++- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/target-m68k/op.c b/target-m68k/op.c index 932c99435..466fdc234 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -338,10 +338,7 @@ OP(ext16s32) OP(flush_flags) { - int cc_op = PARAM1; - if (cc_op == CC_OP_DYNAMIC) - cc_op = env->cc_op; - cpu_m68k_flush_flags(env, cc_op); + cpu_m68k_flush_flags(env, env->cc_op); FORCE_RET(); } @@ -480,7 +477,7 @@ OP(fp_result) OP(set_sr) { - env->sr = get_op(PARAM1); + env->sr = get_op(PARAM1) & 0xffff; m68k_switch_sp(env); FORCE_RET(); } diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 4c423ca98..39cd5d703 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -131,6 +131,8 @@ void do_interrupt(int is_hw) vector = env->exception_index << 2; + sp = env->aregs[7]; + fmt |= 0x40000000; fmt |= (sp & 3) << 28; fmt |= vector << 16; @@ -143,8 +145,6 @@ void do_interrupt(int is_hw) } m68k_switch_sp(env); - sp = env->aregs[7]; - /* ??? This could cause MMU faults. */ sp &= ~3; sp -= 4; diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 1c0e43135..ad8faadc0 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -345,7 +345,8 @@ static inline void gen_flush_flags(DisasContext *s) { if (s->cc_op == CC_OP_FLAGS) return; - gen_op_flush_flags(s->cc_op); + gen_flush_cc_op(s); + gen_op_flush_flags(); s->cc_op = CC_OP_FLAGS; } -- cgit v1.2.3 From 06d92f40a120eca9ba431be5a190186cb8f3fab3 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 9 Jun 2007 20:50:01 +0000 Subject: Workaround dyngen problems with m68k conditional branch ops. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2968 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/op-hacks.h | 25 +++++++++++++++++++++++++ target-m68k/op.c | 29 +++++++++++++++-------------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/target-m68k/op-hacks.h b/target-m68k/op-hacks.h index 01a158d83..7bf345c2c 100644 --- a/target-m68k/op-hacks.h +++ b/target-m68k/op-hacks.h @@ -103,3 +103,28 @@ static inline void gen_op_goto_tb(int dummy, int n, long tb) gen_op_goto_tb1(TBPARAM(tb)); } } + +static inline void gen_op_jmp_z32(int val, int label) +{ + gen_op_set_T0_z32(val); + gen_op_jmp_T0(label); +} + +static inline void gen_op_jmp_nz32(int val, int label) +{ + gen_op_set_T0_nz32(val); + gen_op_jmp_T0(label); +} + +static inline void gen_op_jmp_s32(int val, int label) +{ + gen_op_set_T0_s32(val); + gen_op_jmp_T0(label); +} + +static inline void gen_op_jmp_ns32(int val, int label) +{ + gen_op_set_T0_ns32(val); + gen_op_jmp_T0(label); +} + diff --git a/target-m68k/op.c b/target-m68k/op.c index 466fdc234..e5e39c2fd 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -487,37 +487,38 @@ OP(jmp) GOTO_LABEL_PARAM(1); } -/* These ops involve a function call, which probably requires a stack frame - and breaks things on some hosts. */ -OP(jmp_z32) +OP(set_T0_z32) { uint32_t arg = get_op(PARAM1); - if (arg == 0) - GOTO_LABEL_PARAM(2); + T0 = (arg == 0); FORCE_RET(); } -OP(jmp_nz32) +OP(set_T0_nz32) { uint32_t arg = get_op(PARAM1); - if (arg != 0) - GOTO_LABEL_PARAM(2); + T0 = (arg != 0); FORCE_RET(); } -OP(jmp_s32) +OP(set_T0_s32) { int32_t arg = get_op(PARAM1); - if (arg < 0) - GOTO_LABEL_PARAM(2); + T0 = (arg > 0); FORCE_RET(); } -OP(jmp_ns32) +OP(set_T0_ns32) { int32_t arg = get_op(PARAM1); - if (arg >= 0) - GOTO_LABEL_PARAM(2); + T0 = (arg >= 0); + FORCE_RET(); +} + +OP(jmp_T0) +{ + if (T0) + GOTO_LABEL_PARAM(1); FORCE_RET(); } -- cgit v1.2.3 From c9bac22c7d2405d5d243717f4a6b2e85a99e62fe Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 9 Jun 2007 21:30:14 +0000 Subject: M68K watchpoint hacks. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2969 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/translate.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index ad8faadc0..9fa46029a 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -51,6 +51,7 @@ typedef struct DisasContext { uint32_t fpcr; struct TranslationBlock *tb; int singlestep_enabled; + int is_mem; } DisasContext; #define DISAS_JUMP_NEXT 4 @@ -129,6 +130,7 @@ typedef void (*disas_proc)(DisasContext *, uint16_t); static inline int gen_load(DisasContext * s, int opsize, int addr, int sign) { int tmp; + s->is_mem = 1; switch(opsize) { case OS_BYTE: tmp = gen_new_qreg(QMODE_I32); @@ -166,6 +168,7 @@ static inline int gen_load(DisasContext * s, int opsize, int addr, int sign) /* Generate a store. */ static inline void gen_store(DisasContext *s, int opsize, int addr, int val) { + s->is_mem = 1; switch(opsize) { case OS_BYTE: gen_st(s, 8, addr, val); @@ -2205,6 +2208,7 @@ DISAS_INSN(fpu) dest = QREG_F0; while (mask) { if (ext & mask) { + s->is_mem = 1; if (ext & (1 << 13)) { /* store */ gen_st(s, f64, addr, dest); @@ -3169,6 +3173,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, dc->singlestep_enabled = env->singlestep_enabled; dc->fpcr = env->fpcr; dc->user = (env->sr & SR_S) == 0; + dc->is_mem = 0; nb_gen_labels = 0; lj = -1; do { @@ -3199,6 +3204,12 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, last_cc_op = dc->cc_op; dc->insn_pc = dc->pc; disas_m68k_insn(env, dc); + + /* Terminate the TB on memory ops if watchpoints are present. */ + /* FIXME: This should be replacd by the deterministic execution + * IRQ raising bits. */ + if (dc->is_mem && env->nb_watchpoints) + break; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && (pc_offset) < (TARGET_PAGE_SIZE - 32)); -- cgit v1.2.3 From 7a774c875b9995d9b40201f09a78efc73ad4c818 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 10 Jun 2007 13:53:18 +0000 Subject: Use the same offset for all STR and STM instructions that store r15, as specified in ARM ARM (patch from Chris McNett). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2970 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 364f4eadb..246839d1f 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2837,8 +2837,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } else { /* store */ if (i == 15) { - /* special case: r15 = PC + 12 */ - val = (long)s->pc + 8; + /* special case: r15 = PC + 8 */ + val = (long)s->pc + 4; gen_op_movl_TN_im[0](val); } else if (user) { gen_op_movl_T0_user(i); -- cgit v1.2.3 From 924edcae75a8b06c88896d998c9cb6c3160b7a55 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 10 Jun 2007 14:07:13 +0000 Subject: Flush the debug log when qemu Aborts (patch by Herve Poussineau) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2971 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/exec.c b/exec.c index 0e415a5e9..c782e5b6b 100644 --- a/exec.c +++ b/exec.c @@ -1286,6 +1286,10 @@ void cpu_abort(CPUState *env, const char *fmt, ...) cpu_dump_state(env, stderr, fprintf, 0); #endif va_end(ap); + if (logfile) { + fflush(logfile); + fclose(logfile); + } abort(); } -- cgit v1.2.3 From 2a1086d91c19cc058f74fb2913e05f262f37cdc7 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 10 Jun 2007 15:08:43 +0000 Subject: More PCI mapping/remapping for Gallileo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2972 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++------ hw/mips_malta.c | 9 ++ 2 files changed, 321 insertions(+), 32 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index f75f8af21..818e91351 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -222,34 +222,217 @@ typedef target_phys_addr_t pci_addr_t; #define GT_PCI0_HICMASK (0xca4 >> 2) #define GT_PCI1_SERR1MASK (0xca8 >> 2) +#define PCI_MAPPING_ENTRY(regname) \ + target_phys_addr_t regname ##_start; \ + target_phys_addr_t regname ##_length; \ + int regname ##_handle + +#define PCI_REMAPPING_ENTRY(regname) \ + target_phys_addr_t regname ##_start; \ + target_phys_addr_t regname ##_length; \ + target_phys_addr_t regname ##_offset; \ + int regname ##_handle typedef PCIHostState GT64120PCIState; typedef struct GT64120State { GT64120PCIState *pci; uint32_t regs[GT_REGS]; - target_phys_addr_t PCI0IO_start; - target_phys_addr_t PCI0IO_length; + PCI_MAPPING_ENTRY(SCS10); + PCI_REMAPPING_ENTRY(SCS10AR); + PCI_MAPPING_ENTRY(SCS32); + PCI_REMAPPING_ENTRY(SCS32AR); + PCI_MAPPING_ENTRY(CS20); + PCI_REMAPPING_ENTRY(CS20R); + PCI_MAPPING_ENTRY(CS3BOOT); + PCI_REMAPPING_ENTRY(CS3BOOTR); + PCI_MAPPING_ENTRY(PCI0IO); + PCI_REMAPPING_ENTRY(PCI0IOREMAP); + PCI_MAPPING_ENTRY(PCI0M0); + PCI_REMAPPING_ENTRY(PCI0M0REMAP); + PCI_MAPPING_ENTRY(PCI0M1); + PCI_REMAPPING_ENTRY(PCI0M1REMAP); + PCI_MAPPING_ENTRY(PCI1IO); + PCI_REMAPPING_ENTRY(PCI1IOREMAP); + PCI_MAPPING_ENTRY(PCI1M0); + PCI_REMAPPING_ENTRY(PCI1M0REMAP); + PCI_MAPPING_ENTRY(PCI1M1); + PCI_REMAPPING_ENTRY(PCI1M1REMAP); + PCI_MAPPING_ENTRY(ISD); } GT64120State; -static void gt64120_pci_mapping(GT64120State *s) +/* Adjust range to avoid touching space which isn't mappable via PCI */ +/* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000 + 0x1fc00000 - 0x1fd00000 */ +static void check_reserved_space (target_phys_addr_t *start, + target_phys_addr_t *length) { - /* Update IO mapping */ - if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD]) - { - /* Unmap old IO address */ - if (s->PCI0IO_length) - { - cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED); - } - /* Map new IO address */ - s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21; - s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; - isa_mem_base = s->PCI0IO_start; - isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length); - } + target_phys_addr_t begin = *start; + target_phys_addr_t end = *start + *length; + + if (end >= 0x1e000000LL && end < 0x1f100000LL) + end = 0x1e000000LL; + if (begin >= 0x1e000000LL && begin < 0x1f100000LL) + begin = 0x1f100000LL; + if (end >= 0x1fc00000LL && end < 0x1fd00000LL) + end = 0x1fc00000LL; + if (begin >= 0x1fc00000LL && begin < 0x1fd00000LL) + begin = 0x1fd00000LL; + /* XXX: This is broken when a reserved range splits the requested range */ + if (end >= 0x1f100000LL && begin < 0x1e000000LL) + end = 0x1e000000LL; + if (end >= 0x1fd00000LL && begin < 0x1fc00000LL) + end = 0x1fc00000LL; + + *start = begin; + *length = end - begin; +} + +/* XXX: cpu_register_physical_memory isn't really suited for dynamic mappings + since it doesn't layer several mappings over the same address range. + This should keep track of mappings as set of 2 MB pages / 20 mappings. */ + +#define BUILD_UPDATE_PCI_MAPPING(reg, remap) \ +static void gt64120_## reg ##_mapping(GT64120State *s) \ +{ \ + target_phys_addr_t start = s->regs[GT_## reg ##LD] << 21; \ + target_phys_addr_t length = ((s->regs[GT_## reg ##HD] + 1) - \ + (s->regs[GT_## reg ##LD] & 0x7f)) << 21; \ + \ + /* Unmap old address */ \ + if (s->remap ##_length) \ + cpu_register_physical_memory(s->remap ##_start, \ + s->remap ##_length, \ + IO_MEM_UNASSIGNED); \ + s->remap ##_length = 0; \ + if (s->reg ##_length) \ + cpu_register_physical_memory(s->reg ##_start, \ + s->reg ##_length, \ + IO_MEM_UNASSIGNED); \ + \ + if ((s->regs[GT_## reg ##LD] & 0x7f) <= s->regs[GT_## reg ##HD]) \ + { \ + check_reserved_space(&start, &length); \ + /* Map new address */ \ +dprintf("PCI " # reg ": %x@%x -> %x@%x, %x\n", s->reg ##_length, s->reg ##_start, length, start, s->reg ##_handle); \ + s->reg ##_start = start; \ + s->reg ##_length = length; \ + cpu_register_physical_memory(s->reg ##_start, \ + s->reg ##_length, \ + s->reg ##_handle); \ + } else \ +dprintf("PCI " # reg ": %x@%x disabled, %x\n", s->reg ##_length, s->reg ##_start, s->reg ##_handle); \ +} \ + \ +static void gt64120_## remap ##_mapping(GT64120State *s) \ +{ \ + /* XXX: range calculation is broken */ \ + target_phys_addr_t start = (s->reg ## _start & ~(0x7ff << 21)) | \ + (s->regs[GT_## remap] << 21); \ + target_phys_addr_t length = s->reg ##_length; \ + \ + if (s->remap ##_length) \ + cpu_register_physical_memory(s->remap ##_start, \ + s->remap ##_length, \ + IO_MEM_UNASSIGNED); \ + check_reserved_space(&start, &length); \ + s->remap ##_start = start; \ + s->remap ##_length = length; \ + s->remap ##_offset = s->reg ##_start - start; \ +dprintf("PCI " # remap ": %x@%x +> %x@%x, %x\n", s->reg ##_length, s->reg ##_start, length, start, s->remap ##_handle); \ + cpu_register_physical_memory(s->remap ##_start, \ + s->remap ##_length, \ + s->remap ##_handle); \ +} + +BUILD_UPDATE_PCI_MAPPING(SCS10, SCS10AR) +BUILD_UPDATE_PCI_MAPPING(SCS32, SCS32AR) +BUILD_UPDATE_PCI_MAPPING(CS20, CS20R) +BUILD_UPDATE_PCI_MAPPING(CS3BOOT, CS3BOOTR) +BUILD_UPDATE_PCI_MAPPING(PCI0IO, PCI0IOREMAP) +BUILD_UPDATE_PCI_MAPPING(PCI0M0, PCI0M0REMAP) +BUILD_UPDATE_PCI_MAPPING(PCI0M1, PCI0M1REMAP) +BUILD_UPDATE_PCI_MAPPING(PCI1IO, PCI1IOREMAP) +BUILD_UPDATE_PCI_MAPPING(PCI1M0, PCI1M0REMAP) +BUILD_UPDATE_PCI_MAPPING(PCI1M1, PCI1M1REMAP) + +static void gt64120_isd_mapping(GT64120State *s) +{ + if (s->ISD_length) + cpu_register_physical_memory(s->ISD_start, s->ISD_length, + IO_MEM_UNASSIGNED); +dprintf("PCI ISD: %x@%x -> %x@%x, %x\n", s->ISD_length, s->ISD_start, 0x1000, s->regs[GT_ISD] << 21, s->ISD_handle); + s->ISD_start = s->regs[GT_ISD] << 21; + s->ISD_length = 0x1000; + cpu_register_physical_memory(s->ISD_start, s->ISD_length, s->ISD_handle); +} + +static void gt64120_mmio_writeb (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + cpu_outb(NULL, addr & 0xffff, val); +} + +static void gt64120_mmio_writew (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + cpu_outw(NULL, addr & 0xffff, val); +} + +static void gt64120_mmio_writel (void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + cpu_outl(NULL, addr & 0xffff, val); +} + +static uint32_t gt64120_mmio_readb (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inb(NULL, addr & 0xffff); + return val; } +static uint32_t gt64120_mmio_readw (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inw(NULL, addr & 0xffff); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap16(val); +#endif + return val; +} + +static uint32_t gt64120_mmio_readl (void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = cpu_inl(NULL, addr & 0xffff); +#ifdef TARGET_WORDS_BIGENDIAN + val = bswap32(val); +#endif + return val; +} + +static CPUWriteMemoryFunc *gt64120_mmio_write[] = { + >64120_mmio_writeb, + >64120_mmio_writew, + >64120_mmio_writel, +}; + +static CPUReadMemoryFunc *gt64120_mmio_read[] = { + >64120_mmio_readb, + >64120_mmio_readw, + >64120_mmio_readl, +}; + static void gt64120_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { @@ -272,53 +455,142 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, break; /* CPU Address Decode */ + case GT_SCS10LD: + s->regs[GT_SCS10LD] = val & 0x00007fff; + s->regs[GT_SCS10AR] = val & 0x000007ff; + gt64120_SCS10_mapping(s); + break; + case GT_SCS32LD: + s->regs[GT_SCS32LD] = val & 0x00007fff; + s->regs[GT_SCS32AR] = val & 0x000007ff; +// +// gt64120_SCS32_mapping(s); + break; + case GT_CS20LD: + s->regs[GT_CS20LD] = val & 0x00007fff; + s->regs[GT_CS20R] = val & 0x000007ff; + gt64120_CS20_mapping(s); + break; + case GT_CS3BOOTLD: + s->regs[GT_CS3BOOTLD] = val & 0x00007fff; + s->regs[GT_CS3BOOTR] = val & 0x000007ff; + gt64120_CS3BOOT_mapping(s); + break; + case GT_SCS10HD: + s->regs[saddr] = val & 0x0000007f; + gt64120_SCS10_mapping(s); + break; + case GT_SCS32HD: + s->regs[saddr] = val & 0x0000007f; +// +// gt64120_SCS32_mapping(s); + break; + case GT_CS20HD: + s->regs[saddr] = val & 0x0000007f; + gt64120_CS20_mapping(s); + break; + case GT_CS3BOOTHD: + s->regs[saddr] = val & 0x0000007f; + gt64120_CS3BOOT_mapping(s); + break; case GT_PCI0IOLD: s->regs[GT_PCI0IOLD] = val & 0x00007fff; s->regs[GT_PCI0IOREMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); + gt64120_PCI0IO_mapping(s); break; case GT_PCI0M0LD: s->regs[GT_PCI0M0LD] = val & 0x00007fff; s->regs[GT_PCI0M0REMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); + gt64120_PCI0M0_mapping(s); break; case GT_PCI0M1LD: s->regs[GT_PCI0M1LD] = val & 0x00007fff; s->regs[GT_PCI0M1REMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); + gt64120_PCI0M1_mapping(s); break; case GT_PCI1IOLD: s->regs[GT_PCI1IOLD] = val & 0x00007fff; s->regs[GT_PCI1IOREMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); + gt64120_PCI1IO_mapping(s); break; case GT_PCI1M0LD: s->regs[GT_PCI1M0LD] = val & 0x00007fff; s->regs[GT_PCI1M0REMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); + gt64120_PCI1M1_mapping(s); break; case GT_PCI1M1LD: s->regs[GT_PCI1M1LD] = val & 0x00007fff; s->regs[GT_PCI1M1REMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); + gt64120_PCI1M1_mapping(s); break; case GT_PCI0IOHD: + s->regs[saddr] = val & 0x0000007f; + gt64120_PCI0IO_mapping(s); + break; case GT_PCI0M0HD: + s->regs[saddr] = val & 0x0000007f; + gt64120_PCI0M0_mapping(s); + break; case GT_PCI0M1HD: + s->regs[saddr] = val & 0x0000007f; + gt64120_PCI0M1_mapping(s); + break; case GT_PCI1IOHD: + s->regs[saddr] = val & 0x0000007f; + gt64120_PCI1IO_mapping(s); + break; case GT_PCI1M0HD: + s->regs[saddr] = val & 0x0000007f; + gt64120_PCI1M0_mapping(s); + break; case GT_PCI1M1HD: s->regs[saddr] = val & 0x0000007f; - gt64120_pci_mapping(s); + gt64120_PCI1M1_mapping(s); + break; + case GT_ISD: + s->regs[saddr] = val & 0x00007fff; + gt64120_isd_mapping(s); + break; + + case GT_SCS10AR: + s->regs[saddr] = val & 0x000007ff; + gt64120_SCS10AR_mapping(s); + break; + case GT_SCS32AR: + s->regs[saddr] = val & 0x000007ff; + gt64120_SCS32AR_mapping(s); + break; + case GT_CS20R: + s->regs[saddr] = val & 0x000007ff; + gt64120_CS20R_mapping(s); + break; + case GT_CS3BOOTR: + s->regs[saddr] = val & 0x000007ff; + gt64120_CS3BOOTR_mapping(s); break; case GT_PCI0IOREMAP: + s->regs[saddr] = val & 0x000007ff; + gt64120_PCI0IOREMAP_mapping(s); + break; case GT_PCI0M0REMAP: + s->regs[saddr] = val & 0x000007ff; + gt64120_PCI0M0REMAP_mapping(s); + break; case GT_PCI0M1REMAP: + s->regs[saddr] = val & 0x000007ff; + gt64120_PCI0M1REMAP_mapping(s); + break; case GT_PCI1IOREMAP: + s->regs[saddr] = val & 0x000007ff; + gt64120_PCI1IOREMAP_mapping(s); + break; case GT_PCI1M0REMAP: + s->regs[saddr] = val & 0x000007ff; + gt64120_PCI1M0REMAP_mapping(s); + break; case GT_PCI1M1REMAP: s->regs[saddr] = val & 0x000007ff; - gt64120_pci_mapping(s); + gt64120_PCI1M1REMAP_mapping(s); break; /* CPU Error Report */ @@ -1026,7 +1298,17 @@ void gt64120_reset(void *opaque) /* Interrupt registers are all zeroed at reset */ - gt64120_pci_mapping(s); + gt64120_isd_mapping(s); + gt64120_SCS10_mapping(s); +// gt64120_SCS32_mapping(s); + gt64120_CS20_mapping(s); + gt64120_CS3BOOT_mapping(s); + gt64120_PCI0IO_mapping(s); + gt64120_PCI0M0_mapping(s); + gt64120_PCI0M1_mapping(s); + gt64120_PCI1IO_mapping(s); + gt64120_PCI1M0_mapping(s); + gt64120_PCI1M1_mapping(s); } static uint32_t gt64120_read_config(PCIDevice *d, uint32_t address, int len) @@ -1070,18 +1352,16 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) { GT64120State *s; PCIDevice *d; - int gt64120; s = qemu_mallocz(sizeof(GT64120State)); s->pci = qemu_mallocz(sizeof(GT64120PCIState)); - gt64120_reset(s); - s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq, pic, 144, 4); - gt64120 = cpu_register_io_memory(0, gt64120_read, - gt64120_write, s); - cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120); + s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s); + s->PCI0IO_handle = cpu_register_io_memory(0, gt64120_mmio_read, + gt64120_mmio_write, s); + gt64120_reset(s); d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), 0, gt64120_read_config, gt64120_write_config); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 36b5f43e6..aa00d382b 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -543,6 +543,15 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ /* Load BAR registers as done by YAMON */ + stl_raw(p++, 0x3c09b400); /* lui t1, 0xb400 */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c08df00); /* lui t0, 0xdf00 */ +#else + stl_raw(p++, 0x340800df); /* ori t0, r0, 0x00df */ +#endif + stl_raw(p++, 0xad280068); /* sw t0, 0x0068(t1) */ + stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */ #ifdef TARGET_WORDS_BIGENDIAN -- cgit v1.2.3 From 9447084492da7ca69ce0c16a35971157f690e631 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 10 Jun 2007 16:06:20 +0000 Subject: Merge TCX and VGA pixel operations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2973 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++++ hw/tcx.c | 22 +--------------------- hw/vga.c | 26 +------------------------- 3 files changed, 6 insertions(+), 46 deletions(-) diff --git a/Makefile.target b/Makefile.target index 2be5e90ac..819479f04 100644 --- a/Makefile.target +++ b/Makefile.target @@ -592,6 +592,10 @@ cpu-exec.o: cpu-exec.c signal.o: signal.c $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< +vga.o: pixel_ops.h + +tcx.o: pixel_ops.h + 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 diff --git a/hw/tcx.c b/hw/tcx.c index bfcb386f7..2c65a0568 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include "pixel_ops.h" #define MAXX 1024 #define MAXY 768 @@ -47,27 +48,6 @@ static void tcx24_screen_dump(void *opaque, const char *filename); static void tcx_invalidate_display(void *opaque); static void tcx24_invalidate_display(void *opaque); -/* XXX: unify with vga draw line functions */ -static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); -} - -static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); -} - -static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); -} - -static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} - static void update_palette_entries(TCXState *s, int start, int end) { int i; diff --git a/hw/vga.c b/hw/vga.c index 8661d00d3..028a48305 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -23,6 +23,7 @@ */ #include "vl.h" #include "vga_int.h" +#include "pixel_ops.h" //#define DEBUG_VGA //#define DEBUG_VGA_MEM @@ -812,31 +813,6 @@ typedef void vga_draw_glyph9_func(uint8_t *d, int linesize, typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, const uint8_t *s, int width); -static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); -} - -static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); -} - -static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); -} - -static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} - -static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b) -{ - return (b << 16) | (g << 8) | r; -} - #define DEPTH 8 #include "vga_template.h" -- cgit v1.2.3 From b29169d2654776e749de91d65c720003ab4a2e66 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 10 Jun 2007 16:07:38 +0000 Subject: Attempt to fix incorrect colours on some BGR displays git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2974 c046a42c-6fe2-441c-8c8c-71466251a162 --- cocoa.m | 7 ++++++- hw/tcx.c | 15 ++++++++++++--- hw/vga.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- sdl.c | 2 +- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/cocoa.m b/cocoa.m index 9551affa3..501fb705b 100644 --- a/cocoa.m +++ b/cocoa.m @@ -164,7 +164,12 @@ static void cocoa_resize(DisplayState *ds, int w, int h) ds->depth = device_bpp; ds->width = w; ds->height = h; - +#ifdef __LITTLE_ENDIAN__ + ds->bgr = 1; +#else + ds->bgr = 0; +#endif + current_ds = *ds; } diff --git a/hw/tcx.c b/hw/tcx.c index 2c65a0568..675c74d9f 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -58,13 +58,22 @@ static void update_palette_entries(TCXState *s, int start, int end) s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]); break; case 15: - s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]); + if (s->ds->bgr) + s->palette[i] = rgb_to_pixel15bgr(s->r[i], s->g[i], s->b[i]); + else + s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]); break; case 16: - s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); + if (s->ds->bgr) + s->palette[i] = rgb_to_pixel16bgr(s->r[i], s->g[i], s->b[i]); + else + s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); break; case 32: - s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); + if (s->ds->bgr) + s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]); + else + s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); break; } } diff --git a/hw/vga.c b/hw/vga.c index 028a48305..efae5c722 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -846,6 +846,15 @@ static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned return col; } +static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g, + unsigned int b) +{ + unsigned int col; + col = rgb_to_pixel15bgr(r, g, b); + col |= col << 16; + return col; +} + static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b) { unsigned int col; @@ -854,6 +863,15 @@ static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned return col; } +static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g, + unsigned int b) +{ + unsigned int col; + col = rgb_to_pixel16bgr(r, g, b); + col |= col << 16; + return col; +} + static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b) { unsigned int col; @@ -974,7 +992,7 @@ static int update_basic_params(VGAState *s) return full_update; } -#define NB_DEPTHS 5 +#define NB_DEPTHS 7 static inline int get_depth_index(DisplayState *s) { @@ -983,9 +1001,15 @@ static inline int get_depth_index(DisplayState *s) case 8: return 0; case 15: - return 1; + if (s->bgr) + return 5; + else + return 1; case 16: - return 2; + if (s->bgr) + return 6; + else + return 2; case 32: if (s->bgr) return 4; @@ -1000,6 +1024,8 @@ static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = { vga_draw_glyph8_16, vga_draw_glyph8_32, vga_draw_glyph8_32, + vga_draw_glyph8_16, + vga_draw_glyph8_16, }; static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = { @@ -1008,6 +1034,8 @@ static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = { vga_draw_glyph16_16, vga_draw_glyph16_32, vga_draw_glyph16_32, + vga_draw_glyph16_16, + vga_draw_glyph16_16, }; static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { @@ -1016,6 +1044,8 @@ static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { vga_draw_glyph9_16, vga_draw_glyph9_32, vga_draw_glyph9_32, + vga_draw_glyph9_16, + vga_draw_glyph9_16, }; static const uint8_t cursor_glyph[32 * 4] = { @@ -1236,60 +1266,80 @@ static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = { vga_draw_line2_16, vga_draw_line2_32, vga_draw_line2_32, + vga_draw_line2_16, + vga_draw_line2_16, vga_draw_line2d2_8, vga_draw_line2d2_16, vga_draw_line2d2_16, vga_draw_line2d2_32, vga_draw_line2d2_32, + vga_draw_line2d2_16, + vga_draw_line2d2_16, vga_draw_line4_8, vga_draw_line4_16, vga_draw_line4_16, vga_draw_line4_32, vga_draw_line4_32, + vga_draw_line4_16, + vga_draw_line4_16, vga_draw_line4d2_8, vga_draw_line4d2_16, vga_draw_line4d2_16, vga_draw_line4d2_32, vga_draw_line4d2_32, + vga_draw_line4d2_16, + vga_draw_line4d2_16, vga_draw_line8d2_8, vga_draw_line8d2_16, vga_draw_line8d2_16, vga_draw_line8d2_32, vga_draw_line8d2_32, + vga_draw_line8d2_16, + vga_draw_line8d2_16, vga_draw_line8_8, vga_draw_line8_16, vga_draw_line8_16, vga_draw_line8_32, vga_draw_line8_32, + vga_draw_line8_16, + vga_draw_line8_16, vga_draw_line15_8, vga_draw_line15_15, vga_draw_line15_16, vga_draw_line15_32, vga_draw_line15_32bgr, + vga_draw_line15_15bgr, + vga_draw_line15_16bgr, vga_draw_line16_8, vga_draw_line16_15, vga_draw_line16_16, vga_draw_line16_32, vga_draw_line16_32bgr, + vga_draw_line16_15bgr, + vga_draw_line16_16bgr, vga_draw_line24_8, vga_draw_line24_15, vga_draw_line24_16, vga_draw_line24_32, vga_draw_line24_32bgr, + vga_draw_line24_15bgr, + vga_draw_line24_16bgr, vga_draw_line32_8, vga_draw_line32_15, vga_draw_line32_16, vga_draw_line32_32, vga_draw_line32_32bgr, + vga_draw_line32_15bgr, + vga_draw_line32_16bgr, }; typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b); @@ -1300,6 +1350,8 @@ static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = { rgb_to_pixel16_dup, rgb_to_pixel32_dup, rgb_to_pixel32bgr_dup, + rgb_to_pixel15bgr_dup, + rgb_to_pixel16bgr_dup, }; static int vga_get_bpp(VGAState *s) diff --git a/sdl.c b/sdl.c index dc11937cf..326935a78 100644 --- a/sdl.c +++ b/sdl.c @@ -87,7 +87,7 @@ static void sdl_resize(DisplayState *ds, int w, int h) ds->data = screen->pixels; ds->linesize = screen->pitch; ds->depth = screen->format->BitsPerPixel; - if (ds->depth == 32 && screen->format->Rshift == 0) { + if (screen->format->Bshift > screen->format->Rshift) { ds->bgr = 1; } else { ds->bgr = 0; -- cgit v1.2.3 From ece096bbdc09f7cce3afc755e9d8030a119086f1 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 10 Jun 2007 16:35:21 +0000 Subject: Add hw/pixel_ops.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2975 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pixel_ops.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 hw/pixel_ops.h diff --git a/hw/pixel_ops.h b/hw/pixel_ops.h new file mode 100644 index 000000000..5334f1dbf --- /dev/null +++ b/hw/pixel_ops.h @@ -0,0 +1,41 @@ +static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); +} + +static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); +} + +static inline unsigned int rgb_to_pixel15bgr(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3); +} + +static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); +} + +static inline unsigned int rgb_to_pixel16bgr(unsigned int r, unsigned int g, + unsigned int b) +{ + return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3); +} + +static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, + unsigned int b) +{ + return (r << 16) | (g << 8) | b; +} + +static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, + unsigned int b) +{ + return (b << 16) | (g << 8) | r; +} -- cgit v1.2.3 From a2502b58b3e5aaff036e15d31f2bac72d21648db Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 10 Jun 2007 17:01:00 +0000 Subject: Fix patch splitting lossage in vga.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2976 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vga.c | 8 ++++++++ qemu-doc.texi | 15 +++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index efae5c722..b2c6bc8c0 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -819,6 +819,14 @@ typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, #define DEPTH 15 #include "vga_template.h" +#define BGR_FORMAT +#define DEPTH 15 +#include "vga_template.h" + +#define DEPTH 16 +#include "vga_template.h" + +#define BGR_FORMAT #define DEPTH 16 #include "vga_template.h" diff --git a/qemu-doc.texi b/qemu-doc.texi index 267509e0a..65a6b38ba 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1629,7 +1629,7 @@ More information is available at @section Sparc32 System emulator invocation Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5 -(sun4m architecture). The emulation is somewhat complete. +or SparcStation 10 (sun4m architecture). The emulation is somewhat complete. QEMU emulates the following sun4m peripherals: @@ -1649,6 +1649,8 @@ and power/reset logic ESP SCSI controller with hard disk and CD-ROM support @item Floppy drive +@item +CS4231 sound device (only on SS-5, not working yet) @end itemize The number of peripherals is fixed in the architecture. @@ -1664,13 +1666,14 @@ Solaris kernels don't work. @c man begin OPTIONS -The following options are specific to the Sparc emulation: +The following options are specific to the Sparc32 emulation: @table @option -@item -g WxH +@item -g WxHx[xDEPTH] -Set the initial TCX graphic mode. The default is 1024x768. +Set the initial TCX graphic mode. The default is 1024x768x8, currently +the only other possible mode is 1024x768x24. @item -prom-env string @@ -1681,6 +1684,10 @@ qemu-system-sparc -prom-env 'auto-boot?=false' \ -prom-env 'boot-device=sd(0,2,0):d' -prom-env 'boot-args=linux single' @end example +@item -M [SS-5|SS-10] + +Set the emulated machine type. Default is SS-5. + @end table @c man end -- cgit v1.2.3 From f6d2a316d222953a25e357e141e374ef4d837079 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 10 Jun 2007 19:21:04 +0000 Subject: Wacom PenPartner tablet (virtual USB device). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2977 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + hw/usb-wacom.c | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/usb.h | 3 + qemu-doc.texi | 4 + vl.c | 2 + 5 files changed, 422 insertions(+) create mode 100644 hw/usb-wacom.c diff --git a/Makefile.target b/Makefile.target index 819479f04..67e7bd3cf 100644 --- a/Makefile.target +++ b/Makefile.target @@ -409,6 +409,7 @@ 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 +VL_OBJS+= usb-wacom.o # EEPROM emulation VL_OBJS += eeprom93xx.o diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c new file mode 100644 index 000000000..0acafaa88 --- /dev/null +++ b/hw/usb-wacom.c @@ -0,0 +1,412 @@ +/* + * Wacom PenPartner USB tablet emulation. + * + * Copyright (c) 2006 Openedhand Ltd. + * Author: Andrzej Zaborowski + * + * Based on hw/usb-hid.c: + * Copyright (c) 2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* Interface requests */ +#define WACOM_GET_REPORT 0x2101 +#define WACOM_SET_REPORT 0x2109 + +/* HID interface requests */ +#define HID_GET_REPORT 0xa101 +#define HID_GET_IDLE 0xa102 +#define HID_GET_PROTOCOL 0xa103 +#define HID_SET_IDLE 0x210a +#define HID_SET_PROTOCOL 0x210b + +typedef struct USBWacomState { + USBDevice dev; + QEMUPutMouseEntry *eh_entry; + int dx, dy, dz, buttons_state; + int x, y; + int mouse_grabbed; + enum { + WACOM_MODE_HID = 1, + WACOM_MODE_WACOM = 2, + } mode; +} USBWacomState; + +static const uint8_t qemu_wacom_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + 0x01, /* u8 bDescriptorType; Device */ + 0x10, 0x10, /* u16 bcdUSB; v1.10 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x08, /* u8 bMaxPacketSize0; 8 Bytes */ + + 0x6a, 0x05, /* u16 idVendor; */ + 0x00, 0x00, /* u16 idProduct; */ + 0x10, 0x42, /* u16 bcdDevice */ + + 0x01, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x00, /* u8 iSerialNumber; */ + 0x01, /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_wacom_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + 0x02, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0x80, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 40, /* u8 MaxPower; */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + 0x04, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; HID */ + 0x01, /* u8 if_bInterfaceSubClass; Boot */ + 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ + 0x00, /* u8 if_iInterface; */ + + /* HID descriptor */ + 0x09, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; */ + 0x01, 0x10, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + 0x22, /* u8 type; Report */ + 0x6e, 0x00, /* u16 len */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + 0x05, /* u8 ep_bDescriptorType; Endpoint */ + 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x0a, /* u8 ep_bInterval; */ +}; + +static void usb_mouse_event(void *opaque, + int dx1, int dy1, int dz1, int buttons_state) +{ + USBWacomState *s = opaque; + + s->dx += dx1; + s->dy += dy1; + s->dz += dz1; + s->buttons_state = buttons_state; +} + +static void usb_wacom_event(void *opaque, + int x, int y, int dz, int buttons_state) +{ + USBWacomState *s = opaque; + + s->x = x; + s->y = y; + s->dz += dz; + s->buttons_state = buttons_state; +} + +static inline int int_clamp(int val, int vmin, int vmax) +{ + if (val < vmin) + return vmin; + else if (val > vmax) + return vmax; + else + return val; +} + +static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len) +{ + int dx, dy, dz, b, l; + + if (!s->mouse_grabbed) { + s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0, + "QEMU PenPartner tablet"); + s->mouse_grabbed = 1; + } + + dx = int_clamp(s->dx, -128, 127); + dy = int_clamp(s->dy, -128, 127); + dz = int_clamp(s->dz, -128, 127); + + s->dx -= dx; + s->dy -= dy; + s->dz -= dz; + + b = 0; + if (s->buttons_state & MOUSE_EVENT_LBUTTON) + b |= 0x01; + if (s->buttons_state & MOUSE_EVENT_RBUTTON) + b |= 0x02; + if (s->buttons_state & MOUSE_EVENT_MBUTTON) + b |= 0x04; + + buf[0] = b; + buf[1] = dx; + buf[2] = dy; + l = 3; + if (len >= 4) { + buf[3] = dz; + l = 4; + } + return l; +} + +static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len) +{ + int b; + + if (!s->mouse_grabbed) { + s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1, + "QEMU PenPartner tablet"); + s->mouse_grabbed = 1; + } + + b = 0; + if (s->buttons_state & MOUSE_EVENT_LBUTTON) + b |= 0x01; + if (s->buttons_state & MOUSE_EVENT_RBUTTON) + b |= 0x02; + if (s->buttons_state & MOUSE_EVENT_MBUTTON) + b |= 0x04; + + if (len < 7) + return 0; + + buf[0] = s->mode; + buf[5] = 0x00; + if (b) { + buf[1] = s->x & 0xff; + buf[2] = s->x >> 8; + buf[3] = s->y & 0xff; + buf[4] = s->y >> 8; + buf[6] = 0; + } else { + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + buf[4] = 0; + buf[6] = (unsigned char) -127; + } + + return 7; +} + +static void usb_wacom_handle_reset(USBDevice *dev) +{ + USBWacomState *s = (USBWacomState *) dev; + + s->dx = 0; + s->dy = 0; + s->dz = 0; + s->x = 0; + s->y = 0; + s->buttons_state = 0; + s->mode = WACOM_MODE_HID; +} + +static int usb_wacom_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + USBWacomState *s = (USBWacomState *) dev; + int ret = 0; + + switch (request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (1 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch (value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_wacom_dev_descriptor, + sizeof(qemu_wacom_dev_descriptor)); + ret = sizeof(qemu_wacom_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_wacom_config_descriptor, + sizeof(qemu_wacom_config_descriptor)); + ret = sizeof(qemu_wacom_config_descriptor); + break; + case USB_DT_STRING: + switch (value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* serial number */ + ret = set_usb_string(data, "1"); + break; + case 2: + ret = set_usb_string(data, "Wacom PenPartner"); + break; + case 3: + /* vendor description */ + ret = set_usb_string(data, "QEMU " QEMU_VERSION); + break; + case 4: + ret = set_usb_string(data, "Wacom Tablet"); + break; + case 5: + ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + case WACOM_SET_REPORT: + qemu_remove_mouse_event_handler(s->eh_entry); + s->mouse_grabbed = 0; + s->mode = data[0]; + ret = 0; + break; + case WACOM_GET_REPORT: + data[0] = 0; + data[1] = s->mode; + ret = 2; + break; + /* USB HID requests */ + case HID_GET_REPORT: + if (s->mode == WACOM_MODE_HID) + ret = usb_mouse_poll(s, data, length); + else if (s->mode == WACOM_MODE_WACOM) + ret = usb_wacom_poll(s, data, length); + break; + case HID_SET_IDLE: + ret = 0; + break; + default: + fail: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p) +{ + USBWacomState *s = (USBWacomState *) dev; + int ret = 0; + + switch (p->pid) { + case USB_TOKEN_IN: + if (p->devep == 1) { + if (s->mode == WACOM_MODE_HID) + ret = usb_mouse_poll(s, p->data, p->len); + else if (s->mode == WACOM_MODE_WACOM) + ret = usb_wacom_poll(s, p->data, p->len); + break; + } + /* Fall through. */ + case USB_TOKEN_OUT: + default: + ret = USB_RET_STALL; + break; + } + return ret; +} + +static void usb_wacom_handle_destroy(USBDevice *dev) +{ + USBWacomState *s = (USBWacomState *) dev; + + qemu_remove_mouse_event_handler(s->eh_entry); + qemu_free(s); +} + +USBDevice *usb_wacom_init(void) +{ + USBWacomState *s; + + s = qemu_mallocz(sizeof(USBWacomState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_wacom_handle_reset; + s->dev.handle_control = usb_wacom_handle_control; + s->dev.handle_data = usb_wacom_handle_data; + s->dev.handle_destroy = usb_wacom_handle_destroy; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), + "QEMU PenPartner Tablet"); + + return (USBDevice *) s; +} diff --git a/hw/usb.h b/hw/usb.h index 66662affe..ba00a0d59 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -221,3 +221,6 @@ USBDevice *usb_tablet_init(void); /* usb-msd.c */ USBDevice *usb_msd_init(const char *filename); + +/* usb-wacom.c */ +USBDevice *usb_wacom_init(void); diff --git a/qemu-doc.texi b/qemu-doc.texi index 65a6b38ba..562a533ab 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1358,6 +1358,10 @@ Pass through the host device identified by @var{bus.addr} @item @code{host:vendor_id:product_id} Pass through the host device identified by @var{vendor_id:product_id} (Linux only) +@item @code{wacom-tablet} +Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet} +above but it can be used with the tslib library because in addition to touch +coordinates it reports touch pressure. @end table @node host_usb_devices diff --git a/vl.c b/vl.c index 4f9c44389..2c05100a9 100644 --- a/vl.c +++ b/vl.c @@ -4321,6 +4321,8 @@ static int usb_device_add(const char *devname) dev = usb_tablet_init(); } else if (strstart(devname, "disk:", &p)) { dev = usb_msd_init(p); + } else if (!strcmp(devname, "wacom-tablet")) { + dev = usb_wacom_init(); } else { return -1; } -- cgit v1.2.3 From 2f2ecb83d7a52cc7239b33f3f9adc4a299dbeebe Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 10 Jun 2007 20:26:38 +0000 Subject: Fix Sparc64 prefetcha op git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2978 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 8dbe3370f..1993a4c89 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2802,9 +2802,9 @@ static void disas_sparc_insn(DisasContext * dc) } #endif } - if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || \ - (xop > 0x17 && xop <= 0x1d ) || \ - (xop > 0x2c && xop <= 0x33) || xop == 0x1f) { + if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || + (xop > 0x17 && xop <= 0x1d ) || + (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) { switch (xop) { case 0x0: /* load word */ gen_op_ldst(ld); -- cgit v1.2.3 From 39524770b2a71f394b7e121def846608fc3e8f54 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 11 Jun 2007 18:59:35 +0000 Subject: Fix "blx lr" (Lauro Venancio). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2979 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 246839d1f..3ce93f89b 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2325,9 +2325,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) /* branch link/exchange thumb (blx) */ val = (uint32_t)s->pc; - gen_op_movl_T0_im(val); - gen_movl_reg_T0(s, 14); + gen_op_movl_T1_im(val); gen_movl_T0_reg(s, rm); + gen_movl_reg_T1(s, 14); gen_bx(s); break; case 0x5: /* saturating add/subtract */ -- cgit v1.2.3 From bd04c6feb96fd750ab5d495523ad478f9c90db71 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 12 Jun 2007 12:43:47 +0000 Subject: Change 20Kc PRID to a later version. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2980 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index c5b27330b..e576ef865 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -182,7 +182,9 @@ static mips_def_t mips_defs[] = }, { .name = "20Kc", - .CP0_PRid = 0x00018200, + /* We emulate a later version of the 20Kc, earlier ones had a broken + WAIT instruction. */ + .CP0_PRid = 0x000182a0, .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) | (1 << CP0C0_VI), .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) | (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) | -- cgit v1.2.3 From 9414cc6fd35eb08721fc96de17c52b1b0535ba3a Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 12 Jun 2007 21:06:52 +0000 Subject: Revert the Gallileo PCI mapping patch, it conflicts with the supposedly "generic" PC-style implementation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2981 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 344 ++++++-------------------------------------------------- hw/mips_malta.c | 9 -- 2 files changed, 32 insertions(+), 321 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 818e91351..f75f8af21 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -222,217 +222,34 @@ typedef target_phys_addr_t pci_addr_t; #define GT_PCI0_HICMASK (0xca4 >> 2) #define GT_PCI1_SERR1MASK (0xca8 >> 2) -#define PCI_MAPPING_ENTRY(regname) \ - target_phys_addr_t regname ##_start; \ - target_phys_addr_t regname ##_length; \ - int regname ##_handle - -#define PCI_REMAPPING_ENTRY(regname) \ - target_phys_addr_t regname ##_start; \ - target_phys_addr_t regname ##_length; \ - target_phys_addr_t regname ##_offset; \ - int regname ##_handle typedef PCIHostState GT64120PCIState; typedef struct GT64120State { GT64120PCIState *pci; uint32_t regs[GT_REGS]; - PCI_MAPPING_ENTRY(SCS10); - PCI_REMAPPING_ENTRY(SCS10AR); - PCI_MAPPING_ENTRY(SCS32); - PCI_REMAPPING_ENTRY(SCS32AR); - PCI_MAPPING_ENTRY(CS20); - PCI_REMAPPING_ENTRY(CS20R); - PCI_MAPPING_ENTRY(CS3BOOT); - PCI_REMAPPING_ENTRY(CS3BOOTR); - PCI_MAPPING_ENTRY(PCI0IO); - PCI_REMAPPING_ENTRY(PCI0IOREMAP); - PCI_MAPPING_ENTRY(PCI0M0); - PCI_REMAPPING_ENTRY(PCI0M0REMAP); - PCI_MAPPING_ENTRY(PCI0M1); - PCI_REMAPPING_ENTRY(PCI0M1REMAP); - PCI_MAPPING_ENTRY(PCI1IO); - PCI_REMAPPING_ENTRY(PCI1IOREMAP); - PCI_MAPPING_ENTRY(PCI1M0); - PCI_REMAPPING_ENTRY(PCI1M0REMAP); - PCI_MAPPING_ENTRY(PCI1M1); - PCI_REMAPPING_ENTRY(PCI1M1REMAP); - PCI_MAPPING_ENTRY(ISD); + target_phys_addr_t PCI0IO_start; + target_phys_addr_t PCI0IO_length; } GT64120State; -/* Adjust range to avoid touching space which isn't mappable via PCI */ -/* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000 - 0x1fc00000 - 0x1fd00000 */ -static void check_reserved_space (target_phys_addr_t *start, - target_phys_addr_t *length) -{ - target_phys_addr_t begin = *start; - target_phys_addr_t end = *start + *length; - - if (end >= 0x1e000000LL && end < 0x1f100000LL) - end = 0x1e000000LL; - if (begin >= 0x1e000000LL && begin < 0x1f100000LL) - begin = 0x1f100000LL; - if (end >= 0x1fc00000LL && end < 0x1fd00000LL) - end = 0x1fc00000LL; - if (begin >= 0x1fc00000LL && begin < 0x1fd00000LL) - begin = 0x1fd00000LL; - /* XXX: This is broken when a reserved range splits the requested range */ - if (end >= 0x1f100000LL && begin < 0x1e000000LL) - end = 0x1e000000LL; - if (end >= 0x1fd00000LL && begin < 0x1fc00000LL) - end = 0x1fc00000LL; - - *start = begin; - *length = end - begin; -} - -/* XXX: cpu_register_physical_memory isn't really suited for dynamic mappings - since it doesn't layer several mappings over the same address range. - This should keep track of mappings as set of 2 MB pages / 20 mappings. */ - -#define BUILD_UPDATE_PCI_MAPPING(reg, remap) \ -static void gt64120_## reg ##_mapping(GT64120State *s) \ -{ \ - target_phys_addr_t start = s->regs[GT_## reg ##LD] << 21; \ - target_phys_addr_t length = ((s->regs[GT_## reg ##HD] + 1) - \ - (s->regs[GT_## reg ##LD] & 0x7f)) << 21; \ - \ - /* Unmap old address */ \ - if (s->remap ##_length) \ - cpu_register_physical_memory(s->remap ##_start, \ - s->remap ##_length, \ - IO_MEM_UNASSIGNED); \ - s->remap ##_length = 0; \ - if (s->reg ##_length) \ - cpu_register_physical_memory(s->reg ##_start, \ - s->reg ##_length, \ - IO_MEM_UNASSIGNED); \ - \ - if ((s->regs[GT_## reg ##LD] & 0x7f) <= s->regs[GT_## reg ##HD]) \ - { \ - check_reserved_space(&start, &length); \ - /* Map new address */ \ -dprintf("PCI " # reg ": %x@%x -> %x@%x, %x\n", s->reg ##_length, s->reg ##_start, length, start, s->reg ##_handle); \ - s->reg ##_start = start; \ - s->reg ##_length = length; \ - cpu_register_physical_memory(s->reg ##_start, \ - s->reg ##_length, \ - s->reg ##_handle); \ - } else \ -dprintf("PCI " # reg ": %x@%x disabled, %x\n", s->reg ##_length, s->reg ##_start, s->reg ##_handle); \ -} \ - \ -static void gt64120_## remap ##_mapping(GT64120State *s) \ -{ \ - /* XXX: range calculation is broken */ \ - target_phys_addr_t start = (s->reg ## _start & ~(0x7ff << 21)) | \ - (s->regs[GT_## remap] << 21); \ - target_phys_addr_t length = s->reg ##_length; \ - \ - if (s->remap ##_length) \ - cpu_register_physical_memory(s->remap ##_start, \ - s->remap ##_length, \ - IO_MEM_UNASSIGNED); \ - check_reserved_space(&start, &length); \ - s->remap ##_start = start; \ - s->remap ##_length = length; \ - s->remap ##_offset = s->reg ##_start - start; \ -dprintf("PCI " # remap ": %x@%x +> %x@%x, %x\n", s->reg ##_length, s->reg ##_start, length, start, s->remap ##_handle); \ - cpu_register_physical_memory(s->remap ##_start, \ - s->remap ##_length, \ - s->remap ##_handle); \ -} - -BUILD_UPDATE_PCI_MAPPING(SCS10, SCS10AR) -BUILD_UPDATE_PCI_MAPPING(SCS32, SCS32AR) -BUILD_UPDATE_PCI_MAPPING(CS20, CS20R) -BUILD_UPDATE_PCI_MAPPING(CS3BOOT, CS3BOOTR) -BUILD_UPDATE_PCI_MAPPING(PCI0IO, PCI0IOREMAP) -BUILD_UPDATE_PCI_MAPPING(PCI0M0, PCI0M0REMAP) -BUILD_UPDATE_PCI_MAPPING(PCI0M1, PCI0M1REMAP) -BUILD_UPDATE_PCI_MAPPING(PCI1IO, PCI1IOREMAP) -BUILD_UPDATE_PCI_MAPPING(PCI1M0, PCI1M0REMAP) -BUILD_UPDATE_PCI_MAPPING(PCI1M1, PCI1M1REMAP) - -static void gt64120_isd_mapping(GT64120State *s) -{ - if (s->ISD_length) - cpu_register_physical_memory(s->ISD_start, s->ISD_length, - IO_MEM_UNASSIGNED); -dprintf("PCI ISD: %x@%x -> %x@%x, %x\n", s->ISD_length, s->ISD_start, 0x1000, s->regs[GT_ISD] << 21, s->ISD_handle); - s->ISD_start = s->regs[GT_ISD] << 21; - s->ISD_length = 0x1000; - cpu_register_physical_memory(s->ISD_start, s->ISD_length, s->ISD_handle); -} - -static void gt64120_mmio_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) +static void gt64120_pci_mapping(GT64120State *s) { - cpu_outb(NULL, addr & 0xffff, val); -} - -static void gt64120_mmio_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - cpu_outw(NULL, addr & 0xffff, val); -} - -static void gt64120_mmio_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - cpu_outl(NULL, addr & 0xffff, val); -} - -static uint32_t gt64120_mmio_readb (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inb(NULL, addr & 0xffff); - return val; -} - -static uint32_t gt64120_mmio_readw (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inw(NULL, addr & 0xffff); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t gt64120_mmio_readl (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inl(NULL, addr & 0xffff); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; + /* Update IO mapping */ + if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD]) + { + /* Unmap old IO address */ + if (s->PCI0IO_length) + { + cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED); + } + /* Map new IO address */ + s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21; + s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21; + isa_mem_base = s->PCI0IO_start; + isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length); + } } -static CPUWriteMemoryFunc *gt64120_mmio_write[] = { - >64120_mmio_writeb, - >64120_mmio_writew, - >64120_mmio_writel, -}; - -static CPUReadMemoryFunc *gt64120_mmio_read[] = { - >64120_mmio_readb, - >64120_mmio_readw, - >64120_mmio_readl, -}; - static void gt64120_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { @@ -455,142 +272,53 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, break; /* CPU Address Decode */ - case GT_SCS10LD: - s->regs[GT_SCS10LD] = val & 0x00007fff; - s->regs[GT_SCS10AR] = val & 0x000007ff; - gt64120_SCS10_mapping(s); - break; - case GT_SCS32LD: - s->regs[GT_SCS32LD] = val & 0x00007fff; - s->regs[GT_SCS32AR] = val & 0x000007ff; -// -// gt64120_SCS32_mapping(s); - break; - case GT_CS20LD: - s->regs[GT_CS20LD] = val & 0x00007fff; - s->regs[GT_CS20R] = val & 0x000007ff; - gt64120_CS20_mapping(s); - break; - case GT_CS3BOOTLD: - s->regs[GT_CS3BOOTLD] = val & 0x00007fff; - s->regs[GT_CS3BOOTR] = val & 0x000007ff; - gt64120_CS3BOOT_mapping(s); - break; - case GT_SCS10HD: - s->regs[saddr] = val & 0x0000007f; - gt64120_SCS10_mapping(s); - break; - case GT_SCS32HD: - s->regs[saddr] = val & 0x0000007f; -// -// gt64120_SCS32_mapping(s); - break; - case GT_CS20HD: - s->regs[saddr] = val & 0x0000007f; - gt64120_CS20_mapping(s); - break; - case GT_CS3BOOTHD: - s->regs[saddr] = val & 0x0000007f; - gt64120_CS3BOOT_mapping(s); - break; case GT_PCI0IOLD: s->regs[GT_PCI0IOLD] = val & 0x00007fff; s->regs[GT_PCI0IOREMAP] = val & 0x000007ff; - gt64120_PCI0IO_mapping(s); + gt64120_pci_mapping(s); break; case GT_PCI0M0LD: s->regs[GT_PCI0M0LD] = val & 0x00007fff; s->regs[GT_PCI0M0REMAP] = val & 0x000007ff; - gt64120_PCI0M0_mapping(s); + gt64120_pci_mapping(s); break; case GT_PCI0M1LD: s->regs[GT_PCI0M1LD] = val & 0x00007fff; s->regs[GT_PCI0M1REMAP] = val & 0x000007ff; - gt64120_PCI0M1_mapping(s); + gt64120_pci_mapping(s); break; case GT_PCI1IOLD: s->regs[GT_PCI1IOLD] = val & 0x00007fff; s->regs[GT_PCI1IOREMAP] = val & 0x000007ff; - gt64120_PCI1IO_mapping(s); + gt64120_pci_mapping(s); break; case GT_PCI1M0LD: s->regs[GT_PCI1M0LD] = val & 0x00007fff; s->regs[GT_PCI1M0REMAP] = val & 0x000007ff; - gt64120_PCI1M1_mapping(s); + gt64120_pci_mapping(s); break; case GT_PCI1M1LD: s->regs[GT_PCI1M1LD] = val & 0x00007fff; s->regs[GT_PCI1M1REMAP] = val & 0x000007ff; - gt64120_PCI1M1_mapping(s); + gt64120_pci_mapping(s); break; case GT_PCI0IOHD: - s->regs[saddr] = val & 0x0000007f; - gt64120_PCI0IO_mapping(s); - break; case GT_PCI0M0HD: - s->regs[saddr] = val & 0x0000007f; - gt64120_PCI0M0_mapping(s); - break; case GT_PCI0M1HD: - s->regs[saddr] = val & 0x0000007f; - gt64120_PCI0M1_mapping(s); - break; case GT_PCI1IOHD: - s->regs[saddr] = val & 0x0000007f; - gt64120_PCI1IO_mapping(s); - break; case GT_PCI1M0HD: - s->regs[saddr] = val & 0x0000007f; - gt64120_PCI1M0_mapping(s); - break; case GT_PCI1M1HD: s->regs[saddr] = val & 0x0000007f; - gt64120_PCI1M1_mapping(s); - break; - case GT_ISD: - s->regs[saddr] = val & 0x00007fff; - gt64120_isd_mapping(s); - break; - - case GT_SCS10AR: - s->regs[saddr] = val & 0x000007ff; - gt64120_SCS10AR_mapping(s); - break; - case GT_SCS32AR: - s->regs[saddr] = val & 0x000007ff; - gt64120_SCS32AR_mapping(s); - break; - case GT_CS20R: - s->regs[saddr] = val & 0x000007ff; - gt64120_CS20R_mapping(s); - break; - case GT_CS3BOOTR: - s->regs[saddr] = val & 0x000007ff; - gt64120_CS3BOOTR_mapping(s); + gt64120_pci_mapping(s); break; case GT_PCI0IOREMAP: - s->regs[saddr] = val & 0x000007ff; - gt64120_PCI0IOREMAP_mapping(s); - break; case GT_PCI0M0REMAP: - s->regs[saddr] = val & 0x000007ff; - gt64120_PCI0M0REMAP_mapping(s); - break; case GT_PCI0M1REMAP: - s->regs[saddr] = val & 0x000007ff; - gt64120_PCI0M1REMAP_mapping(s); - break; case GT_PCI1IOREMAP: - s->regs[saddr] = val & 0x000007ff; - gt64120_PCI1IOREMAP_mapping(s); - break; case GT_PCI1M0REMAP: - s->regs[saddr] = val & 0x000007ff; - gt64120_PCI1M0REMAP_mapping(s); - break; case GT_PCI1M1REMAP: s->regs[saddr] = val & 0x000007ff; - gt64120_PCI1M1REMAP_mapping(s); + gt64120_pci_mapping(s); break; /* CPU Error Report */ @@ -1298,17 +1026,7 @@ void gt64120_reset(void *opaque) /* Interrupt registers are all zeroed at reset */ - gt64120_isd_mapping(s); - gt64120_SCS10_mapping(s); -// gt64120_SCS32_mapping(s); - gt64120_CS20_mapping(s); - gt64120_CS3BOOT_mapping(s); - gt64120_PCI0IO_mapping(s); - gt64120_PCI0M0_mapping(s); - gt64120_PCI0M1_mapping(s); - gt64120_PCI1IO_mapping(s); - gt64120_PCI1M0_mapping(s); - gt64120_PCI1M1_mapping(s); + gt64120_pci_mapping(s); } static uint32_t gt64120_read_config(PCIDevice *d, uint32_t address, int len) @@ -1352,16 +1070,18 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) { GT64120State *s; PCIDevice *d; + int gt64120; s = qemu_mallocz(sizeof(GT64120State)); s->pci = qemu_mallocz(sizeof(GT64120PCIState)); + gt64120_reset(s); + s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq, pic, 144, 4); - s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s); - s->PCI0IO_handle = cpu_register_io_memory(0, gt64120_mmio_read, - gt64120_mmio_write, s); - gt64120_reset(s); + gt64120 = cpu_register_io_memory(0, gt64120_read, + gt64120_write, s); + cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120); d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), 0, gt64120_read_config, gt64120_write_config); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index aa00d382b..36b5f43e6 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -543,15 +543,6 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ /* Load BAR registers as done by YAMON */ - stl_raw(p++, 0x3c09b400); /* lui t1, 0xb400 */ - -#ifdef TARGET_WORDS_BIGENDIAN - stl_raw(p++, 0x3c08df00); /* lui t0, 0xdf00 */ -#else - stl_raw(p++, 0x340800df); /* ori t0, r0, 0x00df */ -#endif - stl_raw(p++, 0xad280068); /* sw t0, 0x0068(t1) */ - stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */ #ifdef TARGET_WORDS_BIGENDIAN -- cgit v1.2.3 From 85b2d44057c2519f3878d0772b55b44f9280d085 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 12 Jun 2007 21:22:16 +0000 Subject: Fix alpha user build failure. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2982 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/alpha/termbits.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/linux-user/alpha/termbits.h b/linux-user/alpha/termbits.h index a30c2a982..86d0982e6 100644 --- a/linux-user/alpha/termbits.h +++ b/linux-user/alpha/termbits.h @@ -1,17 +1,17 @@ -typedef unsigned char cc_t; -typedef unsigned int speed_t; -typedef unsigned int tcflag_t; +typedef unsigned char target_cc_t; +typedef unsigned int target_speed_t; +typedef unsigned int target_tcflag_t; #define TARGET_NCCS 19 struct target_termios { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_cc[TARGET_NCCS]; /* control characters */ - cc_t c_line; /* line discipline (== c_cc[19]) */ - speed_t c_ispeed; /* input speed */ - speed_t c_ospeed; /* output speed */ + target_tcflag_t c_iflag; /* input mode flags */ + target_tcflag_t c_oflag; /* output mode flags */ + target_tcflag_t c_cflag; /* control mode flags */ + target_tcflag_t c_lflag; /* local mode flags */ + target_cc_t c_cc[TARGET_NCCS]; /* control characters */ + target_cc_t c_line; /* line discipline (== c_cc[19]) */ + target_speed_t c_ispeed; /* input speed */ + target_speed_t c_ospeed; /* output speed */ }; /* c_cc characters */ -- cgit v1.2.3 From e27f01ef248ce63b2dc6591c28a275526d2dbc16 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 13 Jun 2007 22:36:30 +0000 Subject: Use pixel_ops.h in PXA LCD screen drawing. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2983 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pixel_ops.h | 12 ++++++++++++ hw/pxa2xx_lcd.c | 31 +------------------------------ 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/hw/pixel_ops.h b/hw/pixel_ops.h index 5334f1dbf..d390adfd1 100644 --- a/hw/pixel_ops.h +++ b/hw/pixel_ops.h @@ -28,6 +28,18 @@ static inline unsigned int rgb_to_pixel16bgr(unsigned int r, unsigned int g, return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3); } +static inline unsigned int rgb_to_pixel24(unsigned int r, unsigned int g, + unsigned int b) +{ + return (r << 16) | (g << 8) | b; +} + +static inline unsigned int rgb_to_pixel24bgr(unsigned int r, unsigned int g, + unsigned int b) +{ + return (b << 16) | (g << 8) | r; +} + static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned int b) { diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index effeaa384..2c1096389 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -8,6 +8,7 @@ */ #include "vl.h" +#include "pixel_ops.h" typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int); @@ -575,36 +576,6 @@ static CPUWriteMemoryFunc *pxa2xx_lcdc_writefn[] = { pxa2xx_lcdc_write }; -static inline -uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); -} - -static inline -uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); -} - -static inline -uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); -} - -static inline -uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} - -static inline -uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} - /* Load new palette for a given DMA channel, convert to internal format */ static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp) { -- cgit v1.2.3 From ffb04fcf089865952592f1f8855c2848d4514a89 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 17 Jun 2007 15:32:30 +0000 Subject: Allow relative paths for the interpreter prefix in linux-user emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2984 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/path.c | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/linux-user/path.c b/linux-user/path.c index 76809705a..7da0a8b27 100644 --- a/linux-user/path.c +++ b/linux-user/path.c @@ -92,23 +92,6 @@ static void set_parents(struct pathelem *child, struct pathelem *parent) set_parents(child->entries[i], child); } -void init_paths(const char *prefix) -{ - if (prefix[0] != '/' || - prefix[0] == '\0' || - !strcmp(prefix, "/")) - return; - - base = new_entry("", NULL, prefix+1); - base = add_dir_maybe(base); - if (base->num_entries == 0) { - free (base); - base = NULL; - } else { - set_parents(base, base); - } -} - /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ static const char * follow_path(const struct pathelem *cursor, const char *name) @@ -135,6 +118,35 @@ follow_path(const struct pathelem *cursor, const char *name) return NULL; } +void init_paths(const char *prefix) +{ + char pref_buf[PATH_MAX]; + + if (prefix[0] == '\0' || + !strcmp(prefix, "/")) + return; + + if (prefix[0] != '/') { + char *cwd = get_current_dir_name(); + if (!cwd) + abort(); + strcpy(pref_buf, cwd); + strcat(pref_buf, "/"); + strcat(pref_buf, prefix); + free(cwd); + } else + strcpy(pref_buf,prefix + 1); + + base = new_entry("", NULL, pref_buf); + base = add_dir_maybe(base); + if (base->num_entries == 0) { + free (base); + base = NULL; + } else { + set_parents(base, base); + } +} + /* Look for path in emulation dir, otherwise return name. */ const char *path(const char *name) { -- cgit v1.2.3 From b12b6a188e50c3bad1f866bb7f8cdb42a8b0d56c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 17 Jun 2007 16:38:39 +0000 Subject: Option to drop LD_PRELOAD from emulated environment, by Lauri Leukkunen. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2985 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index fd96ea2c0..7df24c5a7 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1666,11 +1666,12 @@ void usage(void) "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] [-cpu model] program [arguments...]\n" "Linux CPU emulator (compiled for %s emulation)\n" "\n" - "-h print this help\n" - "-g port wait gdb connection to port\n" - "-L path set the elf interpreter prefix (default=%s)\n" - "-s size set the stack size in bytes (default=%ld)\n" - "-cpu model select CPU (-cpu ? for list)\n" + "-h print this help\n" + "-g port wait gdb connection to port\n" + "-L path set the elf interpreter prefix (default=%s)\n" + "-s size set the stack size in bytes (default=%ld)\n" + "-cpu model select CPU (-cpu ? for list)\n" + "-drop-ld-preload drop LD_PRELOAD for target process\n" "\n" "debug options:\n" #ifdef USE_CODE_COPY @@ -1702,7 +1703,9 @@ int main(int argc, char **argv) int optind; const char *r; int gdbstub_port = 0; - + int drop_ld_preload = 0, environ_count = 0; + char **target_environ, **wrk, **dst; + if (argc <= 1) usage(); @@ -1774,6 +1777,8 @@ int main(int argc, char **argv) #endif _exit(1); } + } else if (!strcmp(r, "drop-ld-preload")) { + drop_ld_preload = 1; } else #ifdef USE_CODE_COPY if (!strcmp(r, "no-code-copy")) { @@ -1802,11 +1807,31 @@ int main(int argc, char **argv) env = cpu_init(); global_env = env; - if (loader_exec(filename, argv+optind, environ, regs, info) != 0) { - printf("Error loading %s\n", filename); - _exit(1); + wrk = environ; + while (*(wrk++)) + environ_count++; + + target_environ = malloc((environ_count + 1) * sizeof(char *)); + if (!target_environ) + abort(); + for (wrk = environ, dst = target_environ; *wrk; wrk++) { + if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11)) + continue; + *(dst++) = strdup(*wrk); + } + dst = NULL; /* NULL terminate target_environ */ + + if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) { + printf("Error loading %s\n", filename); + _exit(1); + } + + for (wrk = target_environ; *wrk; wrk++) { + free(*wrk); } + free(target_environ); + if (loglevel) { page_dump(logfile); -- cgit v1.2.3 From e56869531a8e031bc928250c1071e13e030f37f3 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 17 Jun 2007 16:41:04 +0000 Subject: Remove cscope.* files on 'make clean', by George G. Davis. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2986 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 73d4cf382..0665cd912 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ dyngen$(EXESUF): dyngen.c 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 *~ */*~ + rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS cscope.* *.pod *~ */*~ $(MAKE) -C tests clean for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ -- cgit v1.2.3 From 630530a6529bc3da9ab8aead7053dc753cb9ac77 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 18 Jun 2007 15:01:30 +0000 Subject: Fix a race condition and non-leaf imagesgrowing in VMDK chains, by Igor Lvovsky. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2987 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vmdk.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 117 insertions(+), 32 deletions(-) diff --git a/block-vmdk.c b/block-vmdk.c index 28df8ae46..e595eabe5 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -75,8 +75,25 @@ typedef struct BDRVVmdkState { unsigned int cluster_sectors; uint32_t parent_cid; + int is_parent; } BDRVVmdkState; +typedef struct VmdkMetaData { + uint32_t offset; + unsigned int l1_index; + unsigned int l2_index; + unsigned int l2_offset; + int valid; +} VmdkMetaData; + +typedef struct ActiveBDRVState{ + BlockDriverState *hd; // active image handler + uint64_t cluster_offset; // current write offset +}ActiveBDRVState; + +static ActiveBDRVState activeBDRV; + + static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) { uint32_t magic; @@ -305,7 +322,7 @@ static void vmdk_parent_close(BlockDriverState *bs) bdrv_close(bs->backing_hd); } - +int parent_open = 0; static int vmdk_parent_open(BlockDriverState *bs, const char * filename) { BDRVVmdkState *s = bs->opaque; @@ -339,8 +356,10 @@ static int vmdk_parent_open(BlockDriverState *bs, const char * filename) bdrv_close(s->hd); return -1; } - if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0) + parent_open = 1; + if (bdrv_open(s->hd->backing_hd, parent_img_name, BDRV_O_RDONLY) < 0) goto failure; + parent_open = 0; } return 0; @@ -352,6 +371,11 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) uint32_t magic; int l1_size, i, ret; + if (parent_open) + // Parent must be opened as RO. + flags = BDRV_O_RDONLY; + fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename); + ret = bdrv_file_open(&s->hd, filename, flags); if (ret < 0) return ret; @@ -387,6 +411,11 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9; s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9; + if (parent_open) + s->is_parent = 1; + else + s->is_parent = 0; + // try to open parent images, if exist if (vmdk_parent_open(bs, filename) != 0) goto fail; @@ -430,7 +459,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) return -1; } -static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate); +static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, + uint64_t offset, int allocate); static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, uint64_t offset, int allocate) @@ -446,27 +476,55 @@ static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, if (!vmdk_is_cid_valid(bs)) return -1; - parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, allocate); - if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != - ps->cluster_sectors*512) - return -1; - if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, sizeof(whole_grain)) != - sizeof(whole_grain)) + parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, NULL, offset, allocate); + + if (parent_cluster_offset) { + BDRVVmdkState *act_s = activeBDRV.hd->opaque; + + if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512) + return -1; + + //Write grain only into the active image + if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain)) + return -1; + } + } + return 0; +} + +static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data) +{ + BDRVVmdkState *s = bs->opaque; + + /* update L2 table */ + if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), + &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) + return -1; + /* update backup L2 table */ + if (s->l1_backup_table_offset != 0) { + m_data->l2_offset = s->l1_backup_table[m_data->l1_index]; + if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), + &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) return -1; } + return 0; } -static uint64_t get_cluster_offset(BlockDriverState *bs, +static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, 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; + uint32_t min_count, *l2_table, tmp = 0; uint64_t cluster_offset; - + int status; + + if (m_data) + m_data->valid = 0; + l1_index = (offset >> 9) / s->l1_entry_sectors; if (l1_index >= s->l1_size) return 0; @@ -504,32 +562,45 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, found: l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size; cluster_offset = le32_to_cpu(l2_table[l2_index]); + if (!cluster_offset) { struct stat file_buf; if (!allocate) return 0; - stat(s->hd->filename, &file_buf); - cluster_offset = file_buf.st_size; - bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9)); - - cluster_offset >>= 9; - /* update L2 table */ - tmp = cpu_to_le32(cluster_offset); - l2_table[l2_index] = tmp; - if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), - &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]; - if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), - &tmp, sizeof(tmp)) != sizeof(tmp)) + // Avoid the L2 tables update for the images that have snapshots. + if (!s->is_parent) { + status = stat(s->hd->filename, &file_buf); + if (status == -1) { + fprintf(stderr, "(VMDK) Fail file stat: filename =%s size=0x%lx errno=%s\n", + s->hd->filename, (uint64_t)file_buf.st_size, strerror(errno)); return 0; + } + cluster_offset = file_buf.st_size; + bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9)); + + cluster_offset >>= 9; + tmp = cpu_to_le32(cluster_offset); + l2_table[l2_index] = tmp; + // Save the active image state + activeBDRV.cluster_offset = cluster_offset; + activeBDRV.hd = bs; } - + /* First of all we write grain itself, to avoid race condition + * that may to corrupt the image. + * This problem may occur because of insufficient space on host disk + * or inappropriate VM shutdown. + */ if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1) return 0; + + if (m_data) { + m_data->offset = tmp; + m_data->l1_index = l1_index; + m_data->l2_index = l2_index; + m_data->l2_offset = l2_offset; + m_data->valid = 1; + } } cluster_offset <<= 9; return cluster_offset; @@ -542,7 +613,7 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, int index_in_cluster, n; uint64_t cluster_offset; - cluster_offset = get_cluster_offset(bs, sector_num << 9, 0); + cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0); index_in_cluster = sector_num % s->cluster_sectors; n = s->cluster_sectors - index_in_cluster; if (n > nb_sectors) @@ -559,7 +630,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, uint64_t cluster_offset; while (nb_sectors > 0) { - cluster_offset = get_cluster_offset(bs, sector_num << 9, 0); + cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0); index_in_cluster = sector_num % s->cluster_sectors; n = s->cluster_sectors - index_in_cluster; if (n > nb_sectors) @@ -590,20 +661,34 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVVmdkState *s = bs->opaque; + VmdkMetaData m_data; int index_in_cluster, n; uint64_t cluster_offset; static int cid_update = 0; + if (sector_num > bs->total_sectors) { + fprintf(stderr, + "(VMDK) Wrong offset: sector_num=0x%lx total_sectors=0x%lx\n", + sector_num, bs->total_sectors); + return -1; + } + 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); + cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1); if (!cluster_offset) return -1; + if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) return -1; + if (m_data.valid) { + /* update L2 tables */ + if (vmdk_L2update(bs, &m_data) == -1) + return -1; + } nb_sectors -= n; sector_num += n; buf += n * 512; -- cgit v1.2.3 From d60532ca8f551d226b2a1cab46fb4d6611ee0ea8 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 18 Jun 2007 18:55:46 +0000 Subject: Add parallel memory mapped interface, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2988 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_pica61.c | 7 ++-- hw/parallel.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++----- vl.h | 1 + 3 files changed, 95 insertions(+), 13 deletions(-) diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 2925b69cc..17c7a0f17 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -151,11 +151,8 @@ void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device, serial_mm_init(serial_base[i], 0, i8259[serial_irq[i]], serial_hds[i], 1); } } - for (i = 0; i < MAX_PARALLEL_PORTS; i++) { - if (parallel_hds[i]) { - /* FIXME: memory mapped! parallel_init(0x80008000, i8259[17], parallel_hds[i]); */ - } - } + /* Parallel port */ + if (parallel_hds[0]) parallel_mm_init(0x80008000, 0, i8259[1], parallel_hds[0]); /* Sound card */ /* FIXME: missing Jazz sound, IRQ 18 */ diff --git a/hw/parallel.c b/hw/parallel.c index e8e533bc7..f05daf3c3 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -71,6 +71,9 @@ struct ParallelState { int hw_driver; int epp_timeout; uint32_t last_read_offset; /* For debugging */ + /* Memory-mapped interface */ + target_phys_addr_t base; + int it_shift; }; static void parallel_update_irq(ParallelState *s) @@ -400,15 +403,8 @@ static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr) return ret; } -/* If fd is zero, it means that the parallel device uses the console */ -ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr) +static void parallel_reset(ParallelState *s, qemu_irq irq, CharDriverState *chr) { - ParallelState *s; - uint8_t dummy; - - s = qemu_mallocz(sizeof(ParallelState)); - if (!s) - return NULL; s->datar = ~0; s->dataw = ~0; s->status = PARA_STS_BUSY; @@ -423,6 +419,18 @@ ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr) s->hw_driver = 0; s->epp_timeout = 0; s->last_read_offset = ~0U; +} + +/* If fd is zero, it means that the parallel device uses the console */ +ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr) +{ + ParallelState *s; + uint8_t dummy; + + s = qemu_mallocz(sizeof(ParallelState)); + if (!s) + return NULL; + parallel_reset(s, irq, chr); if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) { s->hw_driver = 1; @@ -445,3 +453,79 @@ ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr) } return s; } + +/* Memory mapped interface */ +uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr) +{ + ParallelState *s = opaque; + + return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift) & 0xFF; +} + +void parallel_mm_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ParallelState *s = opaque; + + parallel_ioport_write_sw(s, (addr - s->base) >> s->it_shift, value & 0xFF); +} + +uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr) +{ + ParallelState *s = opaque; + + return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift) & 0xFFFF; +} + +void parallel_mm_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ParallelState *s = opaque; + + parallel_ioport_write_sw(s, (addr - s->base) >> s->it_shift, value & 0xFFFF); +} + +uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr) +{ + ParallelState *s = opaque; + + return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift); +} + +void parallel_mm_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + ParallelState *s = opaque; + + parallel_ioport_write_sw(s, (addr - s->base) >> s->it_shift, value); +} + +static CPUReadMemoryFunc *parallel_mm_read_sw[] = { + ¶llel_mm_readb, + ¶llel_mm_readw, + ¶llel_mm_readl, +}; + +static CPUWriteMemoryFunc *parallel_mm_write_sw[] = { + ¶llel_mm_writeb, + ¶llel_mm_writew, + ¶llel_mm_writel, +}; + +/* If fd is zero, it means that the parallel device uses the console */ +ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr) +{ + ParallelState *s; + int io_sw; + + s = qemu_mallocz(sizeof(ParallelState)); + if (!s) + return NULL; + parallel_reset(s, irq, chr); + s->base = base; + s->it_shift = it_shift; + + io_sw = cpu_register_io_memory(0, parallel_mm_read_sw, parallel_mm_write_sw, s); + cpu_register_physical_memory(base, 8 << it_shift, io_sw); + return s; +} diff --git a/vl.h b/vl.h index 0ff5109f0..40d724d85 100644 --- a/vl.h +++ b/vl.h @@ -1089,6 +1089,7 @@ void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value); typedef struct ParallelState ParallelState; ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr); +ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr); /* i8259.c */ -- cgit v1.2.3 From 731345e17b8a34f88eeb75c582f19e9790e7d834 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 21 Jun 2007 17:56:50 +0000 Subject: Unpause the emulation after shutdown request on SDL close, so that it can take effect. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2989 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdl.c b/sdl.c index 326935a78..5e70ac08b 100644 --- a/sdl.c +++ b/sdl.c @@ -451,7 +451,8 @@ static void sdl_refresh(DisplayState *ds) break; case SDL_QUIT: if (!no_quit) { - qemu_system_shutdown_request(); + qemu_system_shutdown_request(); + vm_start(); /* In case we're paused */ } break; case SDL_MOUSEMOTION: -- cgit v1.2.3 From 3780e197e4e32f0e6341bdc9a1943d0842b48ec6 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Jun 2007 21:08:02 +0000 Subject: Add alternate grab key, by Michael Mohr. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2990 c046a42c-6fe2-441c-8c8c-71466251a162 --- sdl.c | 24 +++++++++++++++++++----- vl.c | 7 +++++++ vl.h | 1 + 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/sdl.c b/sdl.c index 5e70ac08b..16e4df633 100644 --- a/sdl.c +++ b/sdl.c @@ -223,8 +223,12 @@ static void sdl_update_caption(void) if (!vm_running) status = " [Stopped]"; - else if (gui_grab) - status = " - Press Ctrl-Alt to exit grab"; + else if (gui_grab) { + if (!alt_grab) + status = " - Press Ctrl-Alt to exit grab"; + else + status = " - Press Ctrl-Alt-Shift to exit grab"; + } if (qemu_name) snprintf(buf, sizeof(buf), "QEMU (%s)%s", qemu_name, status); @@ -357,8 +361,13 @@ static void sdl_refresh(DisplayState *ds) case SDL_KEYDOWN: case SDL_KEYUP: if (ev->type == SDL_KEYDOWN) { - mod_state = (SDL_GetModState() & gui_grab_code) == - gui_grab_code; + if (!alt_grab) { + mod_state = (SDL_GetModState() & gui_grab_code) == + gui_grab_code; + } else { + mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) == + (gui_grab_code | KMOD_LSHIFT); + } gui_key_modifier_pressed = mod_state; if (gui_key_modifier_pressed) { int keycode; @@ -419,7 +428,12 @@ static void sdl_refresh(DisplayState *ds) } } } else if (ev->type == SDL_KEYUP) { - mod_state = (ev->key.keysym.mod & gui_grab_code); + if (!alt_grab) { + mod_state = (ev->key.keysym.mod & gui_grab_code); + } else { + mod_state = (ev->key.keysym.mod & + (gui_grab_code | KMOD_LSHIFT)); + } if (!mod_state) { if (gui_key_modifier_pressed) { gui_key_modifier_pressed = 0; diff --git a/vl.c b/vl.c index 2c05100a9..b26d7541b 100644 --- a/vl.c +++ b/vl.c @@ -196,6 +196,7 @@ int nb_option_roms; int semihosting_enabled = 0; int autostart = 1; const char *qemu_name; +int alt_grab = 0; #ifdef TARGET_SPARC unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; @@ -6553,6 +6554,7 @@ void help(void) "-snapshot write to temporary files instead of disk image files\n" #ifdef CONFIG_SDL "-no-frame open SDL window without a frame and window decorations\n" + "-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n" "-no-quit disable SDL window close capability\n" #endif #ifdef TARGET_I386 @@ -6736,6 +6738,7 @@ enum { QEMU_OPTION_loadvm, QEMU_OPTION_full_screen, QEMU_OPTION_no_frame, + QEMU_OPTION_alt_grab, QEMU_OPTION_no_quit, QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, @@ -6829,6 +6832,7 @@ const QEMUOption qemu_options[] = { { "full-screen", 0, QEMU_OPTION_full_screen }, #ifdef CONFIG_SDL { "no-frame", 0, QEMU_OPTION_no_frame }, + { "alt-grab", 0, QEMU_OPTION_alt_grab }, { "no-quit", 0, QEMU_OPTION_no_quit }, #endif { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, @@ -7544,6 +7548,9 @@ int main(int argc, char **argv) case QEMU_OPTION_no_frame: no_frame = 1; break; + case QEMU_OPTION_alt_grab: + alt_grab = 1; + break; case QEMU_OPTION_no_quit: no_quit = 1; break; diff --git a/vl.h b/vl.h index 40d724d85..1ab6411bc 100644 --- a/vl.h +++ b/vl.h @@ -156,6 +156,7 @@ extern int graphic_depth; extern const char *keyboard_layout; extern int kqemu_allowed; extern int win2k_install_hack; +extern int alt_grab; extern int usb_enabled; extern int smp_cpus; extern int cursor_hide; -- cgit v1.2.3 From 71455574f7e4119f21238d8018c024b81040474d Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Jun 2007 21:45:30 +0000 Subject: Implement tgkill, by Alexander Graf. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2991 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/i386/syscall_nr.h | 1 + linux-user/syscall.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index 9fa6be96a..6fe967d3c 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -271,4 +271,5 @@ #define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) #define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) +#define TARGET_NR_tgkill 270 #define TARGET_NR_utimes 271 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e380bc763..e39263400 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -144,6 +144,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo #define __NR_sys_syslog __NR_syslog +#define __NR_sys_tgkill __NR_tgkill #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek @@ -164,6 +165,7 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) +_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) #endif @@ -4604,6 +4606,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #endif +#ifdef TARGET_NR_tgkill + case TARGET_NR_tgkill: + ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3)); + break; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -- cgit v1.2.3 From 4f2b1fe82109e08a83913a44f074d8eb3214fd64 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Jun 2007 21:57:12 +0000 Subject: Implement set_robust_list, by Alexander Graf. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2992 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/i386/syscall_nr.h | 2 ++ linux-user/syscall.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index 6fe967d3c..75fb55953 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -273,3 +273,5 @@ #define TARGET_NR_tgkill 270 #define TARGET_NR_utimes 271 + +#define TARGET_NR_set_robust_list 311 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e39263400..9ee735231 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4612,10 +4612,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #endif +#ifdef TARGET_NR_set_robust_list + case TARGET_NR_set_robust_list: + goto unimplemented_nowarn; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) +#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list) unimplemented_nowarn: #endif ret = -ENOSYS; -- cgit v1.2.3 From d6eb40f6509657a03842daffbb4bd7a54c9f4ffb Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Jun 2007 22:55:02 +0000 Subject: Hack to keep wine happy, by Alexander Graf. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2993 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 7df24c5a7..fe2cc5817 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1933,6 +1933,8 @@ int main(int argc, char **argv) cpu_x86_load_seg(env, R_FS, __USER_DS); cpu_x86_load_seg(env, R_GS, __USER_DS); + /* This hack makes Wine work... */ + env->segs[R_FS].selector = 0; #elif defined(TARGET_ARM) { int i; -- cgit v1.2.3 From 2ff897905470e5fb7ca4edccceee01109a968c30 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Jun 2007 23:34:19 +0000 Subject: Fix segfault in -nographic mode, by Stefen Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2994 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index b26d7541b..271233a2f 100644 --- a/vl.c +++ b/vl.c @@ -4482,6 +4482,34 @@ void pcmcia_info(void) "Empty"); } +/***********************************************************/ +/* dumb display */ + +static void dumb_update(DisplayState *ds, int x, int y, int w, int h) +{ +} + +static void dumb_resize(DisplayState *ds, int w, int h) +{ +} + +static void dumb_refresh(DisplayState *ds) +{ +#if defined(CONFIG_SDL) + vga_hw_update(); +#endif +} + +static void dumb_display_init(DisplayState *ds) +{ + ds->data = NULL; + ds->linesize = 0; + ds->depth = 0; + ds->dpy_update = dumb_update; + ds->dpy_resize = dumb_resize; + ds->dpy_refresh = dumb_refresh; +} + /***********************************************************/ /* I/O handling */ @@ -7884,7 +7912,8 @@ int main(int argc, char **argv) /* terminal init */ memset(&display_state, 0, sizeof(display_state)); if (nographic) { - /* nothing to do */ + /* nearly nothing to do */ + dumb_display_init(ds); } else if (vnc_display != NULL) { vnc_display_init(ds, vnc_display); } else { -- cgit v1.2.3 From 07cf0ba03b8dfec541c09e765283c417539fb618 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 21 Jun 2007 23:38:12 +0000 Subject: Revert workaround for -nographic segfault. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2995 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 51 +++++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 36b5f43e6..bc892ed81 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -42,7 +42,6 @@ #define ENVP_NB_ENTRIES 16 #define ENVP_ENTRY_SIZE 256 -extern int nographic; extern FILE *logfile; typedef struct { @@ -67,18 +66,16 @@ static void malta_fpga_update_display(void *opaque) int i; MaltaFPGAState *s = opaque; - if (!nographic) { - for (i = 7 ; i >= 0 ; i--) { - if (s->leds & (1 << i)) - leds_text[i] = '#'; - else - leds_text[i] = ' '; - } - leds_text[8] = '\0'; - - qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); - qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); + for (i = 7 ; i >= 0 ; i--) { + if (s->leds & (1 << i)) + leds_text[i] = '#'; + else + leds_text[i] = ' '; } + leds_text[8] = '\0'; + + qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text); + qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text); } /* @@ -415,22 +412,20 @@ MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env) cpu_register_physical_memory(base, 0x900, malta); cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta); - if (!nographic) { - s->display = qemu_chr_open("vc"); - qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n"); - qemu_chr_printf(s->display, "+--------+\r\n"); - qemu_chr_printf(s->display, "+ +\r\n"); - qemu_chr_printf(s->display, "+--------+\r\n"); - qemu_chr_printf(s->display, "\n"); - qemu_chr_printf(s->display, "Malta ASCII\r\n"); - qemu_chr_printf(s->display, "+--------+\r\n"); - qemu_chr_printf(s->display, "+ +\r\n"); - qemu_chr_printf(s->display, "+--------+\r\n"); - - uart_chr = qemu_chr_open("vc"); - qemu_chr_printf(uart_chr, "CBUS UART\r\n"); - s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1); - } + s->display = qemu_chr_open("vc"); + qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "+ +\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "\n"); + qemu_chr_printf(s->display, "Malta ASCII\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + qemu_chr_printf(s->display, "+ +\r\n"); + qemu_chr_printf(s->display, "+--------+\r\n"); + + uart_chr = qemu_chr_open("vc"); + qemu_chr_printf(uart_chr, "CBUS UART\r\n"); + s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1); malta_fpga_reset(s); qemu_register_reset(malta_fpga_reset, s); -- cgit v1.2.3 From 47b2d338d982c9e26b2af6b51c1cc0da7cbd2b60 Mon Sep 17 00:00:00 2001 From: balrog Date: Fri, 22 Jun 2007 08:16:00 +0000 Subject: Add USB HID keyboard. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2996 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hid.c | 389 +++++++++++++++++++++++++++++++++++++++++++++++++++------- hw/usb.h | 1 + qemu-doc.texi | 2 + vl.c | 4 +- 4 files changed, 350 insertions(+), 46 deletions(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 720c4d280..43fc47e9c 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -2,6 +2,7 @@ * QEMU USB HID devices * * Copyright (c) 2005 Fabrice Bellard + * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,21 +28,44 @@ #define GET_REPORT 0xa101 #define GET_IDLE 0xa102 #define GET_PROTOCOL 0xa103 +#define SET_REPORT 0x2109 #define SET_IDLE 0x210a #define SET_PROTOCOL 0x210b -#define USB_MOUSE 1 -#define USB_TABLET 2 +/* HID descriptor types */ +#define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHY 0x23 + +#define USB_MOUSE 1 +#define USB_TABLET 2 +#define USB_KEYBOARD 3 typedef struct USBMouseState { - USBDevice dev; int dx, dy, dz, buttons_state; int x, y; - int kind; int mouse_grabbed; QEMUPutMouseEntry *eh_entry; } USBMouseState; +typedef struct USBKeyboardState { + uint16_t modifiers; + uint8_t leds; + uint8_t key[16]; + int keys; +} USBKeyboardState; + +typedef struct USBHIDState { + USBDevice dev; + union { + USBMouseState ptr; + USBKeyboardState kbd; + }; + int kind; + int protocol; + int idle; +} USBHIDState; + /* mostly the same values as the Bochs USB Mouse device */ static const uint8_t qemu_mouse_dev_descriptor[] = { 0x12, /* u8 bLength; */ @@ -98,7 +122,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = { 0x03, /* u8 if_bInterfaceClass; */ 0x01, /* u8 if_bInterfaceSubClass; */ 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x05, /* u8 if_iInterface; */ + 0x07, /* u8 if_iInterface; */ /* HID descriptor */ 0x09, /* u8 bLength; */ @@ -125,7 +149,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = { 0x22, 0x00, /* u16 wTotalLength; */ 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ - 0x04, /* u8 iConfiguration; */ + 0x05, /* u8 iConfiguration; */ 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, @@ -153,7 +177,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = { 0x03, /* u8 if_bInterfaceClass; */ 0x01, /* u8 if_bInterfaceSubClass; */ 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x05, /* u8 if_iInterface; */ + 0x07, /* u8 if_iInterface; */ /* HID descriptor */ 0x09, /* u8 bLength; */ @@ -173,6 +197,61 @@ static const uint8_t qemu_tablet_config_descriptor[] = { 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ }; +static const uint8_t qemu_keyboard_config_descriptor[] = { + /* one configuration */ + 0x09, /* u8 bLength; */ + USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */ + 0x22, 0x00, /* u16 wTotalLength; */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x06, /* u8 iConfiguration; */ + 0xa0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 0x32, /* u8 MaxPower; */ + + /* USB 1.1: + * USB 2.0, single TT organization (mandatory): + * one interface, protocol 0 + * + * USB 2.0, multiple TT organization (optional): + * two interfaces, protocols 1 (like single TT) + * and 2 (multiple TT mode) ... config is + * sometimes settable + * NOT IMPLEMENTED + */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x01, /* u8 if_bNumEndpoints; */ + 0x03, /* u8 if_bInterfaceClass; HID */ + 0x01, /* u8 if_bInterfaceSubClass; Boot */ + 0x01, /* u8 if_bInterfaceProtocol; Keyboard */ + 0x07, /* u8 if_iInterface; */ + + /* HID descriptor */ + 0x09, /* u8 bLength; */ + USB_DT_HID, /* u8 bDescriptorType; */ + 0x11, 0x01, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + USB_DT_REPORT, /* u8 type; Report */ + 0x3f, 0x00, /* u16 len */ + + /* one endpoint (status change endpoint) */ + 0x07, /* u8 ep_bLength; */ + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */ + USB_DIR_IN | 0x01, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* u8 ep_bmAttributes; Interrupt */ + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ +}; + static const uint8_t qemu_mouse_hid_report_descriptor[] = { 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, @@ -223,6 +302,83 @@ static const uint8_t qemu_tablet_hid_report_descriptor[] = { 0xC0, /* End Collection */ }; +static const uint8_t qemu_keyboard_hid_report_descriptor[] = { + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x06, /* Usage (Keyboard) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x75, 0x01, /* Report Size (1) */ + 0x95, 0x08, /* Report Count (8) */ + 0x05, 0x07, /* Usage Page (Key Codes) */ + 0x19, 0xe0, /* Usage Minimum (224) */ + 0x29, 0xe7, /* Usage Maximum (231) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x08, /* Report Size (8) */ + 0x81, 0x01, /* Input (Constant) */ + 0x95, 0x05, /* Report Count (5) */ + 0x75, 0x01, /* Report Size (1) */ + 0x05, 0x08, /* Usage Page (LEDs) */ + 0x19, 0x01, /* Usage Minimum (1) */ + 0x29, 0x05, /* Usage Maximum (5) */ + 0x91, 0x02, /* Output (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x03, /* Report Size (3) */ + 0x91, 0x01, /* Output (Constant) */ + 0x95, 0x06, /* Report Count (6) */ + 0x75, 0x08, /* Report Size (8) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0xff, /* Logical Maximum (255) */ + 0x05, 0x07, /* Usage Page (Key Codes) */ + 0x19, 0x00, /* Usage Minimum (0) */ + 0x29, 0xff, /* Usage Maximum (255) */ + 0x81, 0x00, /* Input (Data, Array) */ + 0xc0, /* End Collection */ +}; + +#define USB_HID_USAGE_ERROR_ROLLOVER 0x01 +#define USB_HID_USAGE_POSTFAIL 0x02 +#define USB_HID_USAGE_ERROR_UNDEFINED 0x03 + +/* Indices are QEMU keycodes, values are from HID Usage Table. Indices + * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ +static const uint8_t usb_hid_usage_keys[0x100] = { + 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, + 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, + 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, + 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, + 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, + 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, + 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, + 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, + 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, + 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, + 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, + 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, + 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, + 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + static void usb_mouse_event(void *opaque, int dx1, int dy1, int dz1, int buttons_state) { @@ -245,6 +401,51 @@ static void usb_tablet_event(void *opaque, s->buttons_state = buttons_state; } +static void usb_keyboard_event(void *opaque, int keycode) +{ + USBKeyboardState *s = opaque; + uint8_t hid_code, key; + int i; + + key = keycode & 0x7f; + hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))]; + s->modifiers &= ~(1 << 8); + + switch (hid_code) { + case 0x00: + return; + + case 0xe0: + if (s->modifiers & (1 << 9)) { + s->modifiers ^= 3 << 8; + return; + } + case 0xe1 ... 0xe7: + if (keycode & (1 << 7)) { + s->modifiers &= ~(1 << (hid_code & 0x0f)); + return; + } + case 0xe8 ... 0xef: + s->modifiers |= 1 << (hid_code & 0x0f); + return; + } + + if (keycode & (1 << 7)) { + for (i = s->keys - 1; i >= 0; i --) + if (s->key[i] == hid_code) { + s->key[i] = s->key[-- s->keys]; + s->key[s->keys] = 0x00; + return; + } + } else { + for (i = s->keys - 1; i >= 0; i --) + if (s->key[i] == hid_code) + return; + if (s->keys < sizeof(s->key)) + s->key[s->keys ++] = hid_code; + } +} + static inline int int_clamp(int val, int vmin, int vmax) { if (val < vmin) @@ -326,22 +527,59 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) return l; } +static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len) +{ + if (len < 2) + return 0; + + buf[0] = s->modifiers & 0xff; + buf[1] = 0; + if (s->keys > 6) + memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); + else + memcpy(buf + 2, s->key, MIN(8, len) - 2); + + return MIN(8, len); +} + +static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len) +{ + if (len > 0) { + /* 0x01: Num Lock LED + * 0x02: Caps Lock LED + * 0x04: Scroll Lock LED + * 0x08: Compose LED + * 0x10: Kana LED */ + s->leds = buf[0]; + } + return 0; +} + static void usb_mouse_handle_reset(USBDevice *dev) { - USBMouseState *s = (USBMouseState *)dev; - - s->dx = 0; - s->dy = 0; - s->dz = 0; - s->x = 0; - s->y = 0; - s->buttons_state = 0; + USBHIDState *s = (USBHIDState *)dev; + + s->ptr.dx = 0; + s->ptr.dy = 0; + s->ptr.dz = 0; + s->ptr.x = 0; + s->ptr.y = 0; + s->ptr.buttons_state = 0; + s->protocol = 1; +} + +static void usb_keyboard_handle_reset(USBDevice *dev) +{ + USBHIDState *s = (USBHIDState *)dev; + + qemu_add_kbd_event_handler(usb_keyboard_event, &s->kbd); + s->protocol = 1; } -static int usb_mouse_handle_control(USBDevice *dev, int request, int value, +static int usb_hid_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { - USBMouseState *s = (USBMouseState *)dev; + USBHIDState *s = (USBHIDState *)dev; int ret = 0; switch(request) { @@ -387,7 +625,11 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, memcpy(data, qemu_tablet_config_descriptor, sizeof(qemu_tablet_config_descriptor)); ret = sizeof(qemu_tablet_config_descriptor); - } + } else if (s->kind == USB_KEYBOARD) { + memcpy(data, qemu_keyboard_config_descriptor, + sizeof(qemu_keyboard_config_descriptor)); + ret = sizeof(qemu_keyboard_config_descriptor); + } break; case USB_DT_STRING: switch(value & 0xff) { @@ -405,10 +647,7 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, break; case 2: /* product description */ - if (s->kind == USB_MOUSE) - ret = set_usb_string(data, "QEMU USB Mouse"); - else if (s->kind == USB_TABLET) - ret = set_usb_string(data, "QEMU USB Tablet"); + ret = set_usb_string(data, s->dev.devname); break; case 3: /* vendor description */ @@ -418,6 +657,12 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, ret = set_usb_string(data, "HID Mouse"); break; case 5: + ret = set_usb_string(data, "HID Tablet"); + break; + case 6: + ret = set_usb_string(data, "HID Keyboard"); + break; + case 7: ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); break; default: @@ -454,19 +699,48 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, memcpy(data, qemu_tablet_hid_report_descriptor, sizeof(qemu_tablet_hid_report_descriptor)); ret = sizeof(qemu_tablet_hid_report_descriptor); - } - break; + } else if (s->kind == USB_KEYBOARD) { + memcpy(data, qemu_keyboard_hid_report_descriptor, + sizeof(qemu_keyboard_hid_report_descriptor)); + ret = sizeof(qemu_keyboard_hid_report_descriptor); + } + break; default: goto fail; } break; case GET_REPORT: if (s->kind == USB_MOUSE) - ret = usb_mouse_poll(s, data, length); + ret = usb_mouse_poll(&s->ptr, data, length); else if (s->kind == USB_TABLET) - ret = usb_tablet_poll(s, data, length); + ret = usb_tablet_poll(&s->ptr, data, length); + else if (s->kind == USB_KEYBOARD) + ret = usb_keyboard_poll(&s->kbd, data, length); + break; + case SET_REPORT: + if (s->kind == USB_KEYBOARD) + ret = usb_keyboard_write(&s->kbd, data, length); + else + goto fail; + break; + case GET_PROTOCOL: + if (s->kind != USB_KEYBOARD) + goto fail; + ret = 1; + data[0] = s->protocol; + break; + case SET_PROTOCOL: + if (s->kind != USB_KEYBOARD) + goto fail; + ret = 0; + s->protocol = value; + break; + case GET_IDLE: + ret = 1; + data[0] = s->idle; break; case SET_IDLE: + s->idle = value; ret = 0; break; default: @@ -477,18 +751,20 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, return ret; } -static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) +static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) { - USBMouseState *s = (USBMouseState *)dev; + USBHIDState *s = (USBHIDState *)dev; int ret = 0; switch(p->pid) { case USB_TOKEN_IN: if (p->devep == 1) { - if (s->kind == USB_MOUSE) - ret = usb_mouse_poll(s, p->data, p->len); - else if (s->kind == USB_TABLET) - ret = usb_tablet_poll(s, p->data, p->len); + if (s->kind == USB_MOUSE) + ret = usb_mouse_poll(&s->ptr, p->data, p->len); + else if (s->kind == USB_TABLET) + ret = usb_tablet_poll(&s->ptr, p->data, p->len); + else if (s->kind == USB_KEYBOARD) + ret = usb_keyboard_poll(&s->kbd, p->data, p->len); } else { goto fail; } @@ -502,28 +778,30 @@ static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) return ret; } -static void usb_mouse_handle_destroy(USBDevice *dev) +static void usb_hid_handle_destroy(USBDevice *dev) { - USBMouseState *s = (USBMouseState *)dev; + USBHIDState *s = (USBHIDState *)dev; - qemu_remove_mouse_event_handler(s->eh_entry); + if (s->kind != USB_KEYBOARD) + qemu_remove_mouse_event_handler(s->ptr.eh_entry); + /* TODO: else */ qemu_free(s); } USBDevice *usb_tablet_init(void) { - USBMouseState *s; + USBHIDState *s; - s = qemu_mallocz(sizeof(USBMouseState)); + s = qemu_mallocz(sizeof(USBHIDState)); if (!s) return NULL; s->dev.speed = USB_SPEED_FULL; s->dev.handle_packet = usb_generic_handle_packet; s->dev.handle_reset = usb_mouse_handle_reset; - s->dev.handle_control = usb_mouse_handle_control; - s->dev.handle_data = usb_mouse_handle_data; - s->dev.handle_destroy = usb_mouse_handle_destroy; + s->dev.handle_control = usb_hid_handle_control; + s->dev.handle_data = usb_hid_handle_data; + s->dev.handle_destroy = usb_hid_handle_destroy; s->kind = USB_TABLET; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); @@ -533,21 +811,42 @@ USBDevice *usb_tablet_init(void) USBDevice *usb_mouse_init(void) { - USBMouseState *s; + USBHIDState *s; - s = qemu_mallocz(sizeof(USBMouseState)); + s = qemu_mallocz(sizeof(USBHIDState)); if (!s) return NULL; s->dev.speed = USB_SPEED_FULL; s->dev.handle_packet = usb_generic_handle_packet; s->dev.handle_reset = usb_mouse_handle_reset; - s->dev.handle_control = usb_mouse_handle_control; - s->dev.handle_data = usb_mouse_handle_data; - s->dev.handle_destroy = usb_mouse_handle_destroy; + s->dev.handle_control = usb_hid_handle_control; + s->dev.handle_data = usb_hid_handle_data; + s->dev.handle_destroy = usb_hid_handle_destroy; s->kind = USB_MOUSE; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); return (USBDevice *)s; } + +USBDevice *usb_keyboard_init(void) +{ + USBHIDState *s; + + s = qemu_mallocz(sizeof(USBHIDState)); + if (!s) + return NULL; + s->dev.speed = USB_SPEED_FULL; + s->dev.handle_packet = usb_generic_handle_packet; + + s->dev.handle_reset = usb_keyboard_handle_reset; + s->dev.handle_control = usb_hid_handle_control; + s->dev.handle_data = usb_hid_handle_data; + s->dev.handle_destroy = usb_hid_handle_destroy; + s->kind = USB_KEYBOARD; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard"); + + return (USBDevice *) s; +} diff --git a/hw/usb.h b/hw/usb.h index ba00a0d59..868118acb 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -218,6 +218,7 @@ void usb_host_info(void); /* usb-hid.c */ USBDevice *usb_mouse_init(void); USBDevice *usb_tablet_init(void); +USBDevice *usb_keyboard_init(void); /* usb-msd.c */ USBDevice *usb_msd_init(const char *filename); diff --git a/qemu-doc.texi b/qemu-doc.texi index 562a533ab..cc530d659 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1362,6 +1362,8 @@ Pass through the host device identified by @var{vendor_id:product_id} Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet} above but it can be used with the tslib library because in addition to touch coordinates it reports touch pressure. +@item @code{keyboard} +Standard USB keyboard. Will override the PS/2 keyboard (if present). @end table @node host_usb_devices diff --git a/vl.c b/vl.c index 271233a2f..91b1c5a5b 100644 --- a/vl.c +++ b/vl.c @@ -4319,7 +4319,9 @@ static int usb_device_add(const char *devname) } else if (!strcmp(devname, "mouse")) { dev = usb_mouse_init(); } else if (!strcmp(devname, "tablet")) { - dev = usb_tablet_init(); + dev = usb_tablet_init(); + } else if (!strcmp(devname, "keyboard")) { + dev = usb_keyboard_init(); } else if (strstart(devname, "disk:", &p)) { dev = usb_msd_init(p); } else if (!strcmp(devname, "wacom-tablet")) { -- cgit v1.2.3 From 8b6e0729aa1965e3db366887ca47ec3c96f0ab2a Mon Sep 17 00:00:00 2001 From: balrog Date: Fri, 22 Jun 2007 08:23:44 +0000 Subject: Use HAS_ARG instead of numeric value (patch by Balazs Attila-Mihaly). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2997 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vl.c b/vl.c index 91b1c5a5b..89a2a1731 100644 --- a/vl.c +++ b/vl.c @@ -6854,10 +6854,10 @@ const QEMUOption qemu_options[] = { #endif { "localtime", 0, QEMU_OPTION_localtime }, { "std-vga", 0, QEMU_OPTION_std_vga }, - { "echr", 1, QEMU_OPTION_echr }, - { "monitor", 1, QEMU_OPTION_monitor }, - { "serial", 1, QEMU_OPTION_serial }, - { "parallel", 1, QEMU_OPTION_parallel }, + { "echr", HAS_ARG, QEMU_OPTION_echr }, + { "monitor", HAS_ARG, QEMU_OPTION_monitor }, + { "serial", HAS_ARG, QEMU_OPTION_serial }, + { "parallel", HAS_ARG, QEMU_OPTION_parallel }, { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, { "full-screen", 0, QEMU_OPTION_full_screen }, #ifdef CONFIG_SDL -- cgit v1.2.3 From d10927f86bd2458fd154fc5a8b529d7e54846c14 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 10:11:48 +0000 Subject: Add missing cpu_halted function, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2998 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/cpu.h | 1 + target-sh4/exec.h | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 00ee06268..4f25b6caf 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -114,6 +114,7 @@ typedef struct CPUSH4State { jmp_buf jmp_env; int user_mode_only; int interrupt_request; + int halted; int exception_index; CPU_COMMON tlb_t utlb[UTLB_SIZE]; /* unified translation table */ tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ diff --git a/target-sh4/exec.h b/target-sh4/exec.h index 356330030..84f29319e 100644 --- a/target-sh4/exec.h +++ b/target-sh4/exec.h @@ -36,6 +36,16 @@ register uint32_t T1 asm(AREG2); #include "cpu.h" #include "exec-all.h" +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} + #ifndef CONFIG_USER_ONLY #include "softmmu_exec.h" #endif -- cgit v1.2.3 From 4c909d14c26bcdc1f62f2d6943bf640381f6b0dc Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 10:12:54 +0000 Subject: Set FD bit in SR to emulate kernel behaviour, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2999 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index c70288ebf..40d726695 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -125,7 +125,7 @@ void cpu_dump_state(CPUState * env, FILE * f, void cpu_sh4_reset(CPUSH4State * env) { #if defined(CONFIG_USER_ONLY) - env->sr = 0x00000000; + env->sr = SR_FD; /* FD - kernel does lazy fpu context switch */ #else env->sr = 0x700000F0; /* MD, RB, BL, I3-I0 */ #endif -- cgit v1.2.3 From 072ae847f9ac50392f618b7bcf01184b31f49a8f Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 10:13:51 +0000 Subject: Setup stack properly, fixes wrong argc value problem, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3000 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c0845fe65..f844eff50 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -325,7 +325,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i { /* Check other registers XXXXX */ regs->pc = infop->entry; - regs->regs[15] = infop->start_stack - 16 * 4; + regs->regs[15] = infop->start_stack; } #define USE_ELF_CORE_DUMP -- cgit v1.2.3 From 6db45e6519fee264ef3bbe88f50233f23640b403 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 10:15:10 +0000 Subject: Use correct data structures for stat syscalls, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3001 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall_defs.h | 61 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 5ae95b291..0e39a2e77 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -869,7 +869,7 @@ struct target_winsize { #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ #endif -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) +#if defined(TARGET_I386) || defined(TARGET_ARM) struct target_stat { unsigned short st_dev; unsigned short __pad1; @@ -1242,6 +1242,65 @@ struct target_stat64 { target_long __unused[3]; }; +#elif defined(TARGET_SH4) + +struct target_stat { + target_ulong st_dev; + target_ulong st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + target_ulong st_rdev; + target_ulong st_size; + target_ulong st_blksize; + target_ulong st_blocks; + target_ulong target_st_atime; + target_ulong target_st_atime_nsec; + target_ulong target_st_mtime; + target_ulong target_st_mtime_nsec; + target_ulong target_st_ctime; + target_ulong target_st_ctime_nsec; + target_ulong __unused4; + target_ulong __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct target_stat64 { + unsigned long long st_dev; + unsigned char __pad0[4]; + +#define TARGET_STAT64_HAS_BROKEN_ST_INO 1 + target_ulong __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + target_ulong st_uid; + target_ulong st_gid; + + unsigned long long st_rdev; + unsigned char __pad3[4]; + + long long st_size; + target_ulong st_blksize; + + unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ + + target_ulong target_st_atime; + target_ulong target_st_atime_nsec; + + target_ulong target_st_mtime; + target_ulong target_st_mtime_nsec; + + target_ulong target_st_ctime; + target_ulong target_st_ctime_nsec; + + unsigned long long st_ino; +}; + #else #error unsupported CPU #endif -- cgit v1.2.3 From ea6cf6be8e078cbe87f0e3fe226e3afdd92505e0 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 11:12:01 +0000 Subject: Emulate more fpu opcodes, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3002 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/cpu.h | 1 + target-sh4/op.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++ target-sh4/translate.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 183 insertions(+), 1 deletion(-) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 4f25b6caf..5290dd264 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -99,6 +99,7 @@ typedef struct CPUSH4State { /* temporary float registers */ float32 ft0, ft1; float64 dt0, dt1; + float_status fp_status; /* Those belong to the specific unit (SH7750) but are handled here */ uint32_t mmucr; /* MMU control register */ diff --git a/target-sh4/op.c b/target-sh4/op.c index 1b52e8103..f45c2f467 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -509,6 +509,9 @@ void OPPROTO op_##store##_##target##_T0 (void) \ void OPPROTO op_lds_T0_fpscr(void) { env->fpscr = T0 & 0x003fffff; + env->fp_status.float_rounding_mode = T0 & 0x01 ? + float_round_to_zero : float_round_nearest_even; + RETURN(); } @@ -705,6 +708,18 @@ void OPPROTO op_fmov_drN_DT0(void) RETURN(); } +void OPPROTO op_fmov_frN_FT1(void) +{ + FT1 = *(float32 *)&env->fregs[PARAM1]; + RETURN(); +} + +void OPPROTO op_fmov_drN_DT1(void) +{ + DT1 = *(float64 *)&env->fregs[PARAM1]; + RETURN(); +} + void OPPROTO op_fmov_FT0_frN(void) { *(float32 *)&env->fregs[PARAM1] = FT0; @@ -717,6 +732,84 @@ void OPPROTO op_fmov_DT0_drN(void) RETURN(); } +void OPPROTO op_fadd_FT(void) +{ + FT0 = float32_add(FT0, FT1, &env->fp_status); + RETURN(); +} + +void OPPROTO op_fadd_DT(void) +{ + DT0 = float64_add(DT0, DT1, &env->fp_status); + RETURN(); +} + +void OPPROTO op_fsub_FT(void) +{ + FT0 = float32_sub(FT0, FT1, &env->fp_status); + RETURN(); +} + +void OPPROTO op_fsub_DT(void) +{ + DT0 = float64_sub(DT0, DT1, &env->fp_status); + RETURN(); +} + +void OPPROTO op_fmul_FT(void) +{ + FT0 = float32_mul(FT0, FT1, &env->fp_status); + RETURN(); +} + +void OPPROTO op_fmul_DT(void) +{ + DT0 = float64_mul(DT0, DT1, &env->fp_status); + RETURN(); +} + +void OPPROTO op_fdiv_FT(void) +{ + FT0 = float32_div(FT0, FT1, &env->fp_status); + RETURN(); +} + +void OPPROTO op_fdiv_DT(void) +{ + DT0 = float64_div(DT0, DT1, &env->fp_status); + RETURN(); +} + +void OPPROTO op_float_FT(void) +{ + FT0 = int32_to_float32(env->fpul, &env->fp_status); + RETURN(); +} + +void OPPROTO op_float_DT(void) +{ + DT0 = int32_to_float64(env->fpul, &env->fp_status); + RETURN(); +} + +void OPPROTO op_ftrc_FT(void) +{ + env->fpul = float32_to_int32_round_to_zero(FT0, &env->fp_status); + RETURN(); +} + +void OPPROTO op_ftrc_DT(void) +{ + env->fpul = float64_to_int32_round_to_zero(DT0, &env->fp_status); + RETURN(); +} + +void OPPROTO op_fmov_T0_frN(void) +{ + *(unsigned int *)&env->fregs[PARAM1] = T0; + RETURN(); +} + void OPPROTO op_dec1_rN(void) { env->gregs[PARAM1] -= 1; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 40d726695..2d554e03d 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -131,7 +131,13 @@ void cpu_sh4_reset(CPUSH4State * env) #endif env->vbr = 0; env->pc = 0xA0000000; - env->fpscr = 0x00040001; +#if defined(CONFIG_USER_ONLY) + env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */ + env->fp_status.float_rounding_mode = float_round_nearest_even; /* ?! */ +#else + env->fpscr = 0x00040001; /* CPU reset value according to SH4 manual */ + env->fp_status.float_rounding_mode = float_round_to_zero; +#endif env->mmucr = 0; } @@ -238,6 +244,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) #define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x)) #define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe)) #define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x)) +#define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */ #define CHECK_NOT_DELAY_SLOT \ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ @@ -768,6 +775,49 @@ void decode_opc(DisasContext * ctx) gen_op_stfl_FT0_T1(ctx); } return; + case 0xf000: /* fadd Rm,Rn */ + case 0xf001: /* fsub Rm,Rn */ + case 0xf002: /* fmul Rm,Rn */ + case 0xf003: /* fdiv Rm,Rn */ + case 0xf004: /* fcmp/eq Rm,Rn */ + case 0xf005: /* fcmp/gt Rm,Rn */ + if (ctx->fpscr & FPSCR_PR) { + if (ctx->opcode & 0x0110) + break; /* illegal instruction */ + gen_op_fmov_drN_DT1(DREG(B7_4)); + gen_op_fmov_drN_DT0(DREG(B11_8)); + } + else { + gen_op_fmov_frN_FT1(FREG(B7_4)); + gen_op_fmov_frN_FT0(FREG(B11_8)); + } + + switch (ctx->opcode & 0xf00f) { + case 0xf000: /* fadd Rm,Rn */ + ctx->fpscr & FPSCR_PR ? gen_op_fadd_DT() : gen_op_fadd_FT(); + break; + case 0xf001: /* fsub Rm,Rn */ + ctx->fpscr & FPSCR_PR ? gen_op_fsub_DT() : gen_op_fsub_FT(); + break; + case 0xf002: /* fmul Rm,Rn */ + ctx->fpscr & FPSCR_PR ? gen_op_fmul_DT() : gen_op_fmul_FT(); + break; + case 0xf003: /* fdiv Rm,Rn */ + ctx->fpscr & FPSCR_PR ? gen_op_fdiv_DT() : gen_op_fdiv_FT(); + break; + case 0xf004: /* fcmp/eq Rm,Rn */ + return; + case 0xf005: /* fcmp/gt Rm,Rn */ + return; + } + + if (ctx->fpscr & FPSCR_PR) { + gen_op_fmov_DT0_drN(DREG(B11_8)); + } + else { + gen_op_fmov_FT0_frN(FREG(B11_8)); + } + return; } switch (ctx->opcode & 0xff00) { @@ -1079,6 +1129,44 @@ void decode_opc(DisasContext * ctx) gen_op_fmov_frN_FT0(FREG(B11_8)); gen_op_movl_FT0_fpul(); return; + case 0xf02d: /* float FPUL,FRn/DRn */ + if (ctx->fpscr & FPSCR_PR) { + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + gen_op_float_DT(); + gen_op_fmov_DT0_drN(DREG(B11_8)); + } + else { + gen_op_float_FT(); + gen_op_fmov_FT0_frN(FREG(B11_8)); + } + return; + case 0xf03d: /* ftrc FRm/DRm,FPUL */ + if (ctx->fpscr & FPSCR_PR) { + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + gen_op_fmov_drN_DT0(DREG(B11_8)); + gen_op_ftrc_DT(); + } + else { + gen_op_fmov_frN_FT0(FREG(B11_8)); + gen_op_ftrc_FT(); + } + return; + case 0xf08d: /* fldi0 FRn */ + if (!(ctx->fpscr & FPSCR_PR)) { + gen_op_movl_imm_T0(0); + gen_op_fmov_T0_frN(FREG(B11_8)); + return; + } + break; + case 0xf09d: /* fldi1 FRn */ + if (!(ctx->fpscr & FPSCR_PR)) { + gen_op_movl_imm_T0(0x3f800000); + gen_op_fmov_T0_frN(FREG(B11_8)); + return; + } + break; } fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", -- cgit v1.2.3 From e3d8a9858ee1669c72a2ee58ead0d2d973eb4ab6 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 11:43:07 +0000 Subject: Use DREG() instead of XREG() wherever possible, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3003 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 2d554e03d..5b35cf228 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -654,8 +654,8 @@ void decode_opc(DisasContext * ctx) } else if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0110) break; /* illegal instruction */ - gen_op_fmov_drN_DT0(XREG(B7_4)); - gen_op_fmov_DT0_drN(XREG(B11_8)); + gen_op_fmov_drN_DT0(DREG(B7_4)); + gen_op_fmov_DT0_drN(DREG(B11_8)); } else { gen_op_fmov_frN_FT0(FREG(B7_4)); gen_op_fmov_FT0_frN(FREG(B11_8)); @@ -669,7 +669,7 @@ void decode_opc(DisasContext * ctx) } else if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0010) break; /* illegal instruction */ - gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_fmov_drN_DT0(DREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stfq_DT0_T1(ctx); } else { @@ -688,7 +688,7 @@ void decode_opc(DisasContext * ctx) break; /* illegal instruction */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(XREG(B11_8)); + gen_op_fmov_DT0_drN(DREG(B11_8)); } else { gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfl_T0_FT0(ctx); @@ -706,7 +706,7 @@ void decode_opc(DisasContext * ctx) break; /* illegal instruction */ gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(XREG(B11_8)); + gen_op_fmov_DT0_drN(DREG(B11_8)); gen_op_inc8_rN(REG(B7_4)); } else { gen_op_movl_rN_T0(REG(B7_4)); @@ -725,7 +725,7 @@ void decode_opc(DisasContext * ctx) if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_dec8_rN(REG(B11_8)); - gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_fmov_drN_DT0(DREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_stfq_DT0_T1(ctx); } else { @@ -747,7 +747,7 @@ void decode_opc(DisasContext * ctx) gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(XREG(B11_8)); + gen_op_fmov_DT0_drN(DREG(B11_8)); } else { gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); @@ -764,7 +764,7 @@ void decode_opc(DisasContext * ctx) } else if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0010) break; /* illegal instruction */ - gen_op_fmov_drN_DT0(XREG(B7_4)); + gen_op_fmov_drN_DT0(DREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); gen_op_add_rN_T1(REG(0)); gen_op_stfq_DT0_T1(ctx); -- cgit v1.2.3 From e67888a7da3d2fcea87dadf723ba18f8e577734a Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 11:44:41 +0000 Subject: Document FPSCR usage, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3004 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 5b35cf228..b90d9b573 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -647,7 +647,7 @@ void decode_opc(DisasContext * ctx) gen_op_movl_rN_T0(REG(B7_4)); gen_op_xor_T0_rN(REG(B11_8)); return; - case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn */ + case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_PR) { gen_op_fmov_drN_DT0(XREG(B7_4)); gen_op_fmov_DT0_drN(XREG(B11_8)); @@ -661,7 +661,7 @@ void decode_opc(DisasContext * ctx) gen_op_fmov_FT0_frN(FREG(B11_8)); } return; - case 0xf00a: /* fmov {F,D,X}Rm,@Rn */ + case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_PR) { gen_op_fmov_drN_DT0(XREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); @@ -678,7 +678,7 @@ void decode_opc(DisasContext * ctx) gen_op_stfl_FT0_T1(ctx); } return; - case 0xf008: /* fmov @Rm,{F,D,X}Rn */ + case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_PR) { gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfq_T0_DT0(ctx); @@ -695,7 +695,7 @@ void decode_opc(DisasContext * ctx) gen_op_fmov_FT0_frN(FREG(B11_8)); } return; - case 0xf009: /* fmov @Rm+,{F,D,X}Rn */ + case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_PR) { gen_op_movl_rN_T0(REG(B7_4)); gen_op_ldfq_T0_DT0(ctx); @@ -715,7 +715,7 @@ void decode_opc(DisasContext * ctx) gen_op_inc4_rN(REG(B7_4)); } return; - case 0xf00b: /* fmov {F,D,X}Rm,@-Rn */ + case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_PR) { gen_op_dec8_rN(REG(B11_8)); gen_op_fmov_drN_DT0(XREG(B7_4)); @@ -735,7 +735,7 @@ void decode_opc(DisasContext * ctx) gen_op_stfl_FT0_T1(ctx); } return; - case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm */ + case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_PR) { gen_op_movl_rN_T0(REG(B7_4)); gen_op_add_rN_T0(REG(0)); @@ -755,7 +755,7 @@ void decode_opc(DisasContext * ctx) gen_op_fmov_FT0_frN(FREG(B11_8)); } return; - case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) */ + case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */ if (ctx->fpscr & FPSCR_PR) { gen_op_fmov_drN_DT0(XREG(B7_4)); gen_op_movl_rN_T1(REG(B11_8)); @@ -775,12 +775,12 @@ void decode_opc(DisasContext * ctx) gen_op_stfl_FT0_T1(ctx); } return; - case 0xf000: /* fadd Rm,Rn */ - case 0xf001: /* fsub Rm,Rn */ - case 0xf002: /* fmul Rm,Rn */ - case 0xf003: /* fdiv Rm,Rn */ - case 0xf004: /* fcmp/eq Rm,Rn */ - case 0xf005: /* fcmp/gt Rm,Rn */ + case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ + case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ + case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ + case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */ + case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ + case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ if (ctx->fpscr & FPSCR_PR) { if (ctx->opcode & 0x0110) break; /* illegal instruction */ @@ -1121,15 +1121,15 @@ void decode_opc(DisasContext * ctx) case 0x401b: /* tas.b @Rn */ gen_op_tasb_rN(REG(B11_8)); return; - case 0xf00d: /* fsts FPUL,FRn */ + case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */ gen_op_movl_fpul_FT0(); gen_op_fmov_FT0_frN(FREG(B11_8)); return; - case 0xf01d: /* flds FRm.FPUL */ + case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */ gen_op_fmov_frN_FT0(FREG(B11_8)); gen_op_movl_FT0_fpul(); return; - case 0xf02d: /* float FPUL,FRn/DRn */ + case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */ if (ctx->fpscr & FPSCR_PR) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ @@ -1141,7 +1141,7 @@ void decode_opc(DisasContext * ctx) gen_op_fmov_FT0_frN(FREG(B11_8)); } return; - case 0xf03d: /* ftrc FRm/DRm,FPUL */ + case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ if (ctx->fpscr & FPSCR_PR) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ @@ -1153,14 +1153,14 @@ void decode_opc(DisasContext * ctx) gen_op_ftrc_FT(); } return; - case 0xf08d: /* fldi0 FRn */ + case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */ if (!(ctx->fpscr & FPSCR_PR)) { gen_op_movl_imm_T0(0); gen_op_fmov_T0_frN(FREG(B11_8)); return; } break; - case 0xf09d: /* fldi1 FRn */ + case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */ if (!(ctx->fpscr & FPSCR_PR)) { gen_op_movl_imm_T0(0x3f800000); gen_op_fmov_T0_frN(FREG(B11_8)); -- cgit v1.2.3 From 022a22c7e1c8bc5521c521ab9cbecfa893b610c4 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 11:47:05 +0000 Subject: Ignore PR flag in FPSCR when performing fmov, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3005 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 45 +++++++-------------------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index b90d9b573..b7be352d0 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -648,10 +648,7 @@ void decode_opc(DisasContext * ctx) gen_op_xor_T0_rN(REG(B11_8)); return; case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_PR) { - gen_op_fmov_drN_DT0(XREG(B7_4)); - gen_op_fmov_DT0_drN(XREG(B11_8)); - } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0110) break; /* illegal instruction */ gen_op_fmov_drN_DT0(DREG(B7_4)); @@ -662,11 +659,7 @@ void decode_opc(DisasContext * ctx) } return; case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_PR) { - gen_op_fmov_drN_DT0(XREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stfq_DT0_T1(ctx); - } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0010) break; /* illegal instruction */ gen_op_fmov_drN_DT0(DREG(B7_4)); @@ -679,11 +672,7 @@ void decode_opc(DisasContext * ctx) } return; case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_PR) { - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(XREG(B11_8)); - } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_movl_rN_T0(REG(B7_4)); @@ -696,12 +685,7 @@ void decode_opc(DisasContext * ctx) } return; case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_PR) { - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(XREG(B11_8)); - gen_op_inc8_rN(REG(B7_4)); - } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_movl_rN_T0(REG(B7_4)); @@ -716,12 +700,7 @@ void decode_opc(DisasContext * ctx) } return; case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_PR) { - gen_op_dec8_rN(REG(B11_8)); - gen_op_fmov_drN_DT0(XREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_stfq_DT0_T1(ctx); - } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_dec8_rN(REG(B11_8)); @@ -736,12 +715,7 @@ void decode_opc(DisasContext * ctx) } return; case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_PR) { - gen_op_movl_rN_T0(REG(B7_4)); - gen_op_add_rN_T0(REG(0)); - gen_op_ldfq_T0_DT0(ctx); - gen_op_fmov_DT0_drN(XREG(B11_8)); - } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0100) break; /* illegal instruction */ gen_op_movl_rN_T0(REG(B7_4)); @@ -756,12 +730,7 @@ void decode_opc(DisasContext * ctx) } return; case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */ - if (ctx->fpscr & FPSCR_PR) { - gen_op_fmov_drN_DT0(XREG(B7_4)); - gen_op_movl_rN_T1(REG(B11_8)); - gen_op_add_rN_T1(REG(0)); - gen_op_stfq_DT0_T1(ctx); - } else if (ctx->fpscr & FPSCR_SZ) { + if (ctx->fpscr & FPSCR_SZ) { if (ctx->opcode & 0x0010) break; /* illegal instruction */ gen_op_fmov_drN_DT0(DREG(B7_4)); -- cgit v1.2.3 From 7bfd934a13636a7bb611dd282959efde28d92faf Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 11:50:17 +0000 Subject: Fix write to K0 bits in Config0, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3006 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op.c b/target-mips/op.c index a65977af4..66e27e298 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1433,7 +1433,7 @@ void op_mtc0_ebase (void) void op_mtc0_config0 (void) { - env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (T0 & 0x00000001); + env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (T0 & 0x00000007); RETURN(); } -- cgit v1.2.3 From 17044c06b846e84191534a8a8f8bdc56a2b2e619 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 22 Jun 2007 23:50:19 +0000 Subject: Allow emulation of 32bit targets in the MIPS64 capable qemu version. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3007 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index e576ef865..5d25e5746 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -77,7 +77,6 @@ struct mips_def_t { /* MIPS CPU definitions */ static mips_def_t mips_defs[] = { -#ifndef TARGET_MIPS64 { .name = "4Kc", .CP0_PRid = 0x00018000, @@ -135,7 +134,7 @@ static mips_def_t mips_defs[] = .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), }, -#else +#ifdef TARGET_MIPS64 { .name = "R4000", .CP0_PRid = 0x00000400, -- cgit v1.2.3 From 35cc6f8b971e7a5698efb79e908ecaa282ee91cf Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Jun 2007 16:01:57 +0000 Subject: Return success for -M '?' query option. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3008 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 89a2a1731..88f417752 100644 --- a/vl.c +++ b/vl.c @@ -6705,7 +6705,7 @@ void help(void) #endif DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); - exit(1); + exit(strcmp(optarg, "?")); } #define HAS_ARG 0x0001 -- cgit v1.2.3 From 0cfec834c5d532f32d29b8dc804cb4daeb1ed64a Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Jun 2007 16:02:43 +0000 Subject: Spelling fixes, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3009 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 2 +- qemu-img.c | 2 +- target-ppc/cpu.h | 2 +- target-ppc/op.c | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/monitor.c b/monitor.c index 370bdfe98..a8db87040 100644 --- a/monitor.c +++ b/monitor.c @@ -784,7 +784,7 @@ static const KeyDef key_defs[] = { { 0xb5, "kp_divide" }, { 0x37, "kp_multiply" }, - { 0x4a, "kp_substract" }, + { 0x4a, "kp_subtract" }, { 0x4e, "kp_add" }, { 0x9c, "kp_enter" }, { 0x53, "kp_decimal" }, diff --git a/qemu-img.c b/qemu-img.c index 6b470a150..e7d190b1e 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -297,7 +297,7 @@ static int img_create(int argc, char **argv) drv = bdrv_find_format(fmt); if (!drv) error("Unknown file format '%s'", fmt); - printf("Formating '%s', fmt=%s", + printf("Formatting '%s', fmt=%s", filename, fmt); if (encrypted) printf(", encrypted"); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6b627f26b..57e46620b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1326,7 +1326,7 @@ enum { EXCP_FP_ZX = 0x03, /* FP divide by zero */ EXCP_FP_XX = 0x04, /* FP inexact */ EXCP_FP_VXNAN = 0x05, /* FP invalid SNaN op */ - EXCP_FP_VXISI = 0x06, /* FP invalid infinite substraction */ + EXCP_FP_VXISI = 0x06, /* FP invalid infinite subtraction */ EXCP_FP_VXIDI = 0x07, /* FP invalid infinite divide */ EXCP_FP_VXZDZ = 0x08, /* FP invalid zero divide */ EXCP_FP_VXIMZ = 0x09, /* FP invalid infinite * zero */ diff --git a/target-ppc/op.c b/target-ppc/op.c index 019594c13..546f12a86 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1025,7 +1025,7 @@ void OPPROTO op_nego_64 (void) } #endif -/* substract from */ +/* subtract from */ PPC_OP(subf) { T0 = T1 - T0; @@ -1058,7 +1058,7 @@ void OPPROTO op_check_subfo_64 (void) } #endif -/* substract from carrying */ +/* subtract from carrying */ void OPPROTO op_check_subfc (void) { if (likely((uint32_t)T0 > (uint32_t)T1)) { @@ -1081,7 +1081,7 @@ void OPPROTO op_check_subfc_64 (void) } #endif -/* substract from extended */ +/* subtract from extended */ void OPPROTO op_subfe (void) { do_subfe(); @@ -1096,7 +1096,7 @@ void OPPROTO op_subfe_64 (void) } #endif -/* substract from immediate carrying */ +/* subtract from immediate carrying */ void OPPROTO op_subfic (void) { T0 = (int32_t)PARAM1 + ~T0 + 1; @@ -1121,7 +1121,7 @@ void OPPROTO op_subfic_64 (void) } #endif -/* substract from minus one extended */ +/* subtract from minus one extended */ void OPPROTO op_subfme (void) { T0 = ~T0 + xer_ca - 1; @@ -1154,7 +1154,7 @@ void OPPROTO op_subfmeo_64 (void) } #endif -/* substract from zero extended */ +/* subtract from zero extended */ void OPPROTO op_subfze (void) { T1 = ~T0; -- cgit v1.2.3 From 5c40d2bd4836636b762906bf1516c30b0ed5d74c Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Jun 2007 16:03:36 +0000 Subject: Kfreebsd config, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3010 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 6 ++++++ vl.c | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 793d9d156..b9504a528 100755 --- a/configure +++ b/configure @@ -112,6 +112,12 @@ OS_CFLAGS="-mno-cygwin" MINGW32*) mingw32="yes" ;; +GNU/kFreeBSD) +oss="yes" +if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then + kqemu="yes" +fi +;; FreeBSD) bsd="yes" oss="yes" diff --git a/vl.c b/vl.c index 88f417752..4def8abfe 100644 --- a/vl.c +++ b/vl.c @@ -47,6 +47,8 @@ #ifndef __APPLE__ #include #endif +#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) +#include #else #ifndef __sun__ #include @@ -3451,7 +3453,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan, int fd) return s; } -#ifdef _BSD +#if defined (_BSD) || defined (__FreeBSD_kernel__) static int tap_open(char *ifname, int ifname_size) { int fd; -- cgit v1.2.3 From e034e2c39aee1800101812045690e0575abb428b Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Jun 2007 18:04:12 +0000 Subject: Handle MIPS64 SEGBITS value correctly. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3011 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 2 ++ target-mips/helper.c | 25 ++++++++++++------------- target-mips/op.c | 5 +++-- target-mips/op_helper.c | 2 +- target-mips/translate_init.c | 14 ++++++++++++++ 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 7650be48c..f5f35e122 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -102,6 +102,8 @@ struct CPUMIPSState { uint32_t nb_tlb; uint32_t tlb_in_use; + uint32_t SEGBITS; + target_ulong SEGMask; int (*map_address) (CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type); void (*do_tlbwi) (void); void (*do_tlbwr) (void); diff --git a/target-mips/helper.c b/target-mips/helper.c index 9da6212a5..87a6a334e 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -77,7 +77,7 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong tag = address & ~mask; target_ulong VPN = tlb->VPN & ~mask; #ifdef TARGET_MIPS64 - tag &= 0xC00000FFFFFFFFFFULL; + tag &= env->SEGMask; #endif /* Check ASID, virtual page number & size */ @@ -140,18 +140,17 @@ static int get_physical_address (CPUState *env, target_ulong *physical, /* XXX: Assuming : - PABITS = 36 (correct for MIPS64R1) - - SEGBITS = 40 */ } else if (address < 0x3FFFFFFFFFFFFFFFULL) { /* xuseg */ - if (UX && address < 0x000000FFFFFFFFFFULL) { + if (UX && address < (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret = env->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } } else if (address < 0x7FFFFFFFFFFFFFFFULL) { /* xsseg */ - if (SX && address < 0x400000FFFFFFFFFFULL) { + if (SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret = env->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; @@ -159,9 +158,9 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else if (address < 0xBFFFFFFFFFFFFFFFULL) { /* xkphys */ /* XXX: check supervisor mode */ - if (KX && (address & 0x03FFFFFFFFFFFFFFULL) < 0X0000000FFFFFFFFFULL) + if (KX && (address & 0x07FFFFFFFFFFFFFFULL) < 0X0000000FFFFFFFFFULL) { - *physical = address & 0X000000FFFFFFFFFFULL; + *physical = address & 0X0000000FFFFFFFFFULL; *prot = PAGE_READ | PAGE_WRITE; } else { ret = TLBRET_BADADDR; @@ -169,7 +168,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else if (address < 0xFFFFFFFF7FFFFFFFULL) { /* xkseg */ /* XXX: check supervisor mode */ - if (KX && address < 0xC00000FF7FFFFFFFULL) { + if (KX && address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { ret = env->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; @@ -303,10 +302,10 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->CP0_EntryHi = (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); #ifdef TARGET_MIPS64 - env->CP0_EntryHi &= 0xc00000ffffffffffULL; - env->CP0_XContext = (env->CP0_XContext & 0xfffffffe00000000ULL) | - ((address >> 31) & 0x0000000180000000ULL) | - ((address >> 9) & 0x000000007ffffff0ULL); + env->CP0_EntryHi &= env->SEGMask; + env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) | + ((address & 0xC00000000000ULL) >> (env->SEGBITS - 9)) | + ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9); #endif env->exception_index = exception; env->error_code = error_code; @@ -555,7 +554,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) if (tlb->V0) { addr = tlb->VPN & ~mask; #ifdef TARGET_MIPS64 - if (addr >= 0xC00000FF80000000ULL) { + if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) { addr |= 0x3FFFFF0000000000ULL; } #endif @@ -568,7 +567,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) if (tlb->V1) { addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); #ifdef TARGET_MIPS64 - if (addr >= 0xC00000FF80000000ULL) { + if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) { addr |= 0x3FFFFF0000000000ULL; } #endif diff --git a/target-mips/op.c b/target-mips/op.c index 66e27e298..715c35504 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1328,7 +1328,7 @@ void op_mtc0_entryhi (void) /* 1k pages not implemented */ val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF); #ifdef TARGET_MIPS64 - val = T0 & 0xC00000FFFFFFFFFFULL; + val &= env->SEGMask; #endif old = env->CP0_EntryHi; env->CP0_EntryHi = val; @@ -1526,7 +1526,8 @@ void op_mtc0_desave (void) #ifdef TARGET_MIPS64 void op_mtc0_xcontext (void) { - env->CP0_XContext = (env->CP0_XContext & 0x1ffffffffULL) | (T0 & ~0x1ffffffffULL); + target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; + env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask); RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index c169beb55..e4f267670 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -374,7 +374,7 @@ static void r4k_fill_tlb (int idx) tlb = &env->mmu.r4k.tlb[idx]; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); #ifdef TARGET_MIPS64 - tlb->VPN &= 0xC00000FFFFFFFFFFULL; + tlb->VPN &= env->SEGMask; #endif tlb->ASID = env->CP0_EntryHi & 0xFF; tlb->PageMask = env->CP0_PageMask; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 5d25e5746..687e3e52e 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -71,6 +71,7 @@ struct mips_def_t { int32_t CCRes; int32_t Status_rw_bitmask; int32_t CP1_fcr0; + int32_t SEGBITS; }; /*****************************************************************************/ @@ -87,6 +88,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3278FF17, + .SEGBITS = 32, }, { .name = "4KEcR1", @@ -98,6 +100,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3278FF17, + .SEGBITS = 32, }, { .name = "4KEc", @@ -109,6 +112,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3278FF17, + .SEGBITS = 32, }, { .name = "24Kc", @@ -120,6 +124,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3278FF17, + .SEGBITS = 32, }, { .name = "24Kf", @@ -133,6 +138,7 @@ static mips_def_t mips_defs[] = .Status_rw_bitmask = 0x3678FF17, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), + .SEGBITS = 32, }, #ifdef TARGET_MIPS64 { @@ -147,6 +153,7 @@ static mips_def_t mips_defs[] = .Status_rw_bitmask = 0x3678FFFF, /* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */ .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), + .SEGBITS = 40, }, { .name = "5Kc", @@ -161,6 +168,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x32F8FFFF, + .SEGBITS = 42, }, { .name = "5Kf", @@ -178,6 +186,7 @@ static mips_def_t mips_defs[] = /* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */ .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) | (0x81 << FCR0_PRID) | (0x0 << FCR0_REV), + .SEGBITS = 42, }, { .name = "20Kc", @@ -198,6 +207,7 @@ static mips_def_t mips_defs[] = .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) | (1 << FCR0_D) | (1 << FCR0_S) | (0x82 << FCR0_PRID) | (0x0 << FCR0_REV), + .SEGBITS = 40, }, #endif }; @@ -274,6 +284,10 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CCRes = def->CCRes; env->Status_rw_bitmask = def->Status_rw_bitmask; env->fcr0 = def->CP1_fcr0; +#ifdef TARGET_MIPS64 + env->SEGBITS = def->SEGBITS; + env->SEGMask = (3ULL << 62) | ((1ULL << def->SEGBITS) - 1); +#endif #ifdef CONFIG_USER_ONLY if (env->CP0_Config1 & (1 << CP0C1_FP)) env->hflags |= MIPS_HFLAG_FPU; -- cgit v1.2.3 From b6d7c3db4fd7b375e649b35c2d0722ef00f8fb35 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 23 Jun 2007 18:21:26 +0000 Subject: Fix division by zero handling, by Joris van Rantwijk. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3012 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 96e72c9dd..393db0d65 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5327,8 +5327,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (CODE64(s)) goto illegal_op; val = ldub_code(s->pc++); - gen_op_aam(val); - s->cc_op = CC_OP_LOGICB; + if (val == 0) { + gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base); + } else { + gen_op_aam(val); + s->cc_op = CC_OP_LOGICB; + } break; case 0xd5: /* aad */ if (CODE64(s)) -- cgit v1.2.3 From 610c3c8afd99f4f118b12ede39ee8d62ee44a446 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 24 Jun 2007 12:09:48 +0000 Subject: Reset ARM cp15.c1_sys to default values. Fix XScale cp15 accesses. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3013 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/cpu.h | 1 + target-arm/helper.c | 21 +++++++++++++++++---- vl.c | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 80727bb8a..1c748e258 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -83,6 +83,7 @@ typedef struct CPUARMState { uint32_t c0_cachetype; uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ + uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ uint32_t c2_base; /* MMU translation table base. */ uint32_t c2_data; /* MPU data cachable bits. */ uint32_t c2_insn; /* MPU instruction cachable bits. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index e8a216975..61f810906 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -18,16 +18,19 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_VFP); env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00090078; break; case ARM_CPUID_ARM946: set_feature(env, ARM_FEATURE_MPU); env->cp15.c0_cachetype = 0x0f004006; + env->cp15.c1_sys = 0x00000078; break; case ARM_CPUID_ARM1026: set_feature(env, ARM_FEATURE_VFP); set_feature(env, ARM_FEATURE_AUXCR); env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0; env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00090078; break; case ARM_CPUID_PXA250: case ARM_CPUID_PXA255: @@ -37,6 +40,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_XSCALE); /* JTAG_ID is ((id << 28) | 0x09265013) */ env->cp15.c0_cachetype = 0xd172172; + env->cp15.c1_sys = 0x00000078; break; case ARM_CPUID_PXA270_A0: case ARM_CPUID_PXA270_A1: @@ -49,6 +53,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) set_feature(env, ARM_FEATURE_IWMMXT); env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q'; env->cp15.c0_cachetype = 0xd172172; + env->cp15.c1_sys = 0x00000078; break; default: cpu_abort(env, "Bad CPU ID: %x\n", id); @@ -637,6 +642,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) crm = insn & 0xf; switch ((insn >> 16) & 0xf) { case 0: /* ID codes. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + break; goto bad_reg; case 1: /* System configuration. */ switch (op2) { @@ -648,12 +655,14 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) tlb_flush(env, 1); break; case 1: - /* XScale doesn't implement AUX CR (P-Bit) but allows - * writing with zero and reading. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + env->cp15.c1_xscaleauxcr = val; break; + } goto bad_reg; case 2: + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto bad_reg; env->cp15.c1_coproc = val; /* ??? Is this safe when called from within a TB? */ tb_flush(env); @@ -835,6 +844,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 1: /* Cache Type. */ return env->cp15.c0_cachetype; case 2: /* TCM status. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto bad_reg; return 0; } case 1: /* System configuration. */ @@ -845,9 +856,11 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) if (arm_feature(env, ARM_FEATURE_AUXCR)) return 1; if (arm_feature(env, ARM_FEATURE_XSCALE)) - return 0; + return env->cp15.c1_xscaleauxcr; goto bad_reg; case 2: /* Coprocessor access register. */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) + goto bad_reg; return env->cp15.c1_coproc; default: goto bad_reg; diff --git a/vl.c b/vl.c index 4def8abfe..22ded6bf0 100644 --- a/vl.c +++ b/vl.c @@ -5717,6 +5717,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32(f, env->cp15.c0_cachetype); qemu_put_be32(f, env->cp15.c1_sys); qemu_put_be32(f, env->cp15.c1_coproc); + qemu_put_be32(f, env->cp15.c1_xscaleauxcr); qemu_put_be32(f, env->cp15.c2_base); qemu_put_be32(f, env->cp15.c2_data); qemu_put_be32(f, env->cp15.c2_insn); @@ -5788,6 +5789,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) env->cp15.c0_cachetype = qemu_get_be32(f); env->cp15.c1_sys = qemu_get_be32(f); env->cp15.c1_coproc = qemu_get_be32(f); + env->cp15.c1_xscaleauxcr = qemu_get_be32(f); env->cp15.c2_base = qemu_get_be32(f); env->cp15.c2_data = qemu_get_be32(f); env->cp15.c2_insn = qemu_get_be32(f); -- cgit v1.2.3 From 611d7189e7dc58cdd8e770924677161f72149922 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 24 Jun 2007 13:45:36 +0000 Subject: Make touchscreen calibration values better match the HW. Invert WM8750 GPIO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3014 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ads7846.c | 13 +++++++------ hw/spitz.c | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/hw/ads7846.c b/hw/ads7846.c index 8eeb143b1..2f891b125 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -30,10 +30,10 @@ struct ads7846_state_s { #define CB_A2 (1 << 6) #define CB_START (1 << 7) -#define X_AXIS_DMAX 3680 -#define X_AXIS_MIN 150 -#define Y_AXIS_DMAX 3640 -#define Y_AXIS_MIN 190 +#define X_AXIS_DMAX 3470 +#define X_AXIS_MIN 290 +#define Y_AXIS_DMAX 3450 +#define Y_AXIS_MIN 200 #define ADS_VBAT 2000 #define ADS_VAUX 2000 @@ -95,10 +95,11 @@ static void ads7846_ts_event(void *opaque, struct ads7846_state_s *s = opaque; if (buttons_state) { - s->input[1] = ADS_YPOS(x, y); + x = 0x7fff - x; + s->input[1] = ADS_XPOS(x, y); s->input[3] = ADS_Z1POS(x, y); s->input[4] = ADS_Z2POS(x, y); - s->input[5] = ADS_XPOS(x, y); + s->input[5] = ADS_YPOS(x, y); } if (s->pressure == !buttons_state) { diff --git a/hw/spitz.c b/hw/spitz.c index 590e1fc08..c6fb598f4 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -919,8 +919,8 @@ static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu) /* Wm8750 and Max7310 on I2C */ #define AKITA_MAX_ADDR 0x18 -#define SPITZ_WM_ADDRL 0x1a -#define SPITZ_WM_ADDRH 0x1b +#define SPITZ_WM_ADDRL 0x1b +#define SPITZ_WM_ADDRH 0x1a #define SPITZ_GPIO_WM 5 -- cgit v1.2.3 From 31211df14dd887cd9976722dd527a4b592dd5a07 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 25 Jun 2007 10:57:10 +0000 Subject: Add a 7 segments + led display, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3015 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + hw/jazz_led.c | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/mips_pica61.c | 3 + vl.h | 3 + 4 files changed, 310 insertions(+) create mode 100644 hw/jazz_led.c diff --git a/Makefile.target b/Makefile.target index 67e7bd3cf..01d254975 100644 --- a/Makefile.target +++ b/Makefile.target @@ -438,6 +438,7 @@ endif ifeq ($(TARGET_BASE_ARCH), mips) VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o +VL_OBJS+= jazz_led.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o VL_OBJS+= piix_pci.o smbus_eeprom.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) CPPFLAGS += -DHAS_AUDIO diff --git a/hw/jazz_led.c b/hw/jazz_led.c new file mode 100644 index 000000000..6f741735e --- /dev/null +++ b/hw/jazz_led.c @@ -0,0 +1,303 @@ +/* + * QEMU JAZZ LED emulator. + * + * Copyright (c) 2007 Herv Poussineau + * + * 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 "pixel_ops.h" + +//#define DEBUG_LED + +typedef enum { + REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2, +} screen_state_t; + +typedef struct LedState { + target_phys_addr_t base; + uint8_t segments; + DisplayState *ds; + screen_state_t state; +} LedState; + +static uint32_t led_readb(void *opaque, target_phys_addr_t addr) +{ + LedState *s = opaque; + int relative_addr = addr - s->base; + uint32_t val; + + switch (relative_addr) { + case 0: + val = s->segments; + break; + default: +#ifdef DEBUG_LED + printf("jazz led: invalid read [0x%x]\n", relative_addr); +#endif + val = 0; + } + + return val; +} + +static uint32_t led_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = led_readb(opaque, addr) << 8; + v |= led_readb(opaque, addr + 1); +#else + v = led_readb(opaque, addr); + v |= led_readb(opaque, addr + 1) << 8; +#endif + return v; +} + +static uint32_t led_readl(void *opaque, target_phys_addr_t addr) +{ + uint32_t v; +#ifdef TARGET_WORDS_BIGENDIAN + v = led_readb(opaque, addr) << 24; + v |= led_readb(opaque, addr + 1) << 16; + v |= led_readb(opaque, addr + 2) << 8; + v |= led_readb(opaque, addr + 3); +#else + v = led_readb(opaque, addr); + v |= led_readb(opaque, addr + 1) << 8; + v |= led_readb(opaque, addr + 2) << 16; + v |= led_readb(opaque, addr + 3) << 24; +#endif + return v; +} + +static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + LedState *s = opaque; + int relative_addr = addr - s->base; + + switch (relative_addr) { + case 0: + s->segments = val; + s->state |= REDRAW_SEGMENTS; + break; + default: +#ifdef DEBUG_LED + printf("jazz led: invalid write of 0x%02x at [0x%x]\n", val, relative_addr); +#endif + break; + } +} + +static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + led_writeb(opaque, addr, (val >> 8) & 0xff); + led_writeb(opaque, addr + 1, val & 0xff); +#else + led_writeb(opaque, addr, val & 0xff); + led_writeb(opaque, addr + 1, (val >> 8) & 0xff); +#endif +} + +static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ +#ifdef TARGET_WORDS_BIGENDIAN + led_writeb(opaque, addr, (val >> 24) & 0xff); + led_writeb(opaque, addr + 1, (val >> 16) & 0xff); + led_writeb(opaque, addr + 2, (val >> 8) & 0xff); + led_writeb(opaque, addr + 3, val & 0xff); +#else + led_writeb(opaque, addr, val & 0xff); + led_writeb(opaque, addr + 1, (val >> 8) & 0xff); + led_writeb(opaque, addr + 2, (val >> 16) & 0xff); + led_writeb(opaque, addr + 3, (val >> 24) & 0xff); +#endif +} + +static CPUReadMemoryFunc *led_read[3] = { + led_readb, + led_readw, + led_readl, +}; + +static CPUWriteMemoryFunc *led_write[3] = { + led_writeb, + led_writew, + led_writel, +}; + +/***********************************************************/ +/* jazz_led display */ + +static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color) +{ + uint8_t *d; + int x, bpp; + + bpp = (ds->depth + 7) >> 3; + d = ds->data + ds->linesize * posy + bpp * posx1; + switch(bpp) { + case 1: + for (x = posx1; x <= posx2; x++) { + *((uint8_t *)d) = color; + d++; + } + break; + case 2: + for (x = posx1; x <= posx2; x++) { + *((uint16_t *)d) = color; + d += 2; + } + break; + case 4: + for (x = posx1; x <= posx2; x++) { + *((uint32_t *)d) = color; + d += 4; + } + break; + } +} + +static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color) +{ + uint8_t *d; + int y, bpp; + + bpp = (ds->depth + 7) >> 3; + d = ds->data + ds->linesize * posy1 + bpp * posx; + switch(bpp) { + case 1: + for (y = posy1; y <= posy2; y++) { + *((uint8_t *)d) = color; + d += ds->linesize; + } + break; + case 2: + for (y = posy1; y <= posy2; y++) { + *((uint16_t *)d) = color; + d += ds->linesize; + } + break; + case 4: + for (y = posy1; y <= posy2; y++) { + *((uint32_t *)d) = color; + d += ds->linesize; + } + break; + } +} + +static void jazz_led_update_display(void *opaque) +{ + LedState *s = opaque; + DisplayState *ds = s->ds; + uint8_t *d1; + uint32_t color_segment, color_led; + int y, bpp; + + if (s->state & REDRAW_BACKGROUND) { + /* clear screen */ + bpp = (ds->depth + 7) >> 3; + d1 = ds->data; + for (y = 0; y < ds->height; y++) { + memset(d1, 0x00, ds->width * bpp); + d1 += ds->linesize; + } + } + + if (s->state & REDRAW_SEGMENTS) { + /* set colors according to bpp */ + switch (ds->depth) { + case 8: + color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa); + color_led = rgb_to_pixel8(0x00, 0xff, 0x00); + break; + case 15: + color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa); + color_led = rgb_to_pixel15(0x00, 0xff, 0x00); + break; + case 16: + color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa); + color_led = rgb_to_pixel16(0x00, 0xff, 0x00); + case 24: + color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa); + color_led = rgb_to_pixel24(0x00, 0xff, 0x00); + break; + case 32: + color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa); + color_led = rgb_to_pixel32(0x00, 0xff, 0x00); + break; + default: + return; + } + + /* display segments */ + draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0); + draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0); + draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0); + draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0); + draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0); + draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0); + draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0); + + /* display led */ + if (!(s->segments & 0x01)) + color_led = 0; /* black */ + draw_horizontal_line(ds, 68, 50, 50, color_led); + draw_horizontal_line(ds, 69, 49, 51, color_led); + draw_horizontal_line(ds, 70, 48, 52, color_led); + draw_horizontal_line(ds, 71, 49, 51, color_led); + draw_horizontal_line(ds, 72, 50, 50, color_led); + } + + s->state = REDRAW_NONE; + dpy_update(ds, 0, 0, ds->width, ds->height); +} + +static void jazz_led_invalidate_display(void *opaque) +{ + LedState *s = opaque; + s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND; +} + +static void jazz_led_screen_dump(void *opaque, const char *filename) +{ + printf("jazz_led_screen_dump() not implemented\n"); +} + +void jazz_led_init(DisplayState *ds, target_phys_addr_t base) +{ + LedState *s; + int io; + + s = qemu_mallocz(sizeof(LedState)); + if (!s) + return; + + s->base = base; + s->ds = ds; + s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; + + io = cpu_register_io_memory(0, led_read, led_write, s); + cpu_register_physical_memory(s->base, 1, io); + + graphic_console_init(ds, jazz_led_update_display, jazz_led_invalidate_display, jazz_led_screen_dump, s); +} diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 17c7a0f17..2c4415017 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -168,6 +168,9 @@ void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device, * but let's do with what Qemu currenly emulates... */ isa_vga_mm_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0x40000000, 0x60000000, 0); + + /* LED indicator */ + jazz_led_init(ds, 0x8000f000); } QEMUMachine mips_pica61_machine = { diff --git a/vl.h b/vl.h index 1ab6411bc..4a072a90a 100644 --- a/vl.h +++ b/vl.h @@ -1128,6 +1128,9 @@ int pit_get_initial_count(PITState *pit, int channel); int pit_get_mode(PITState *pit, int channel); int pit_get_out(PITState *pit, int channel, int64_t current_time); +/* jazz_led.c */ +extern void jazz_led_init(DisplayState *ds, target_phys_addr_t base); + /* pcspk.c */ void pcspk_init(PITState *); int pcspk_audio_init(AudioState *, qemu_irq *pic); -- cgit v1.2.3 From 33fa11d4b53dcda0f71929a60d60e51ad46e926d Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 25 Jun 2007 11:36:50 +0000 Subject: Implement ^W in readline.c, by Michal Hanselmann. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3016 c046a42c-6fe2-441c-8c8c-71466251a162 --- readline.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/readline.c b/readline.c index cbe33dbdd..25572dd02 100644 --- a/readline.c +++ b/readline.c @@ -156,6 +156,45 @@ static void term_backspace(void) } } +static void term_backword(void) +{ + int start; + + if (term_cmd_buf_index == 0 || term_cmd_buf_index > term_cmd_buf_size) { + return; + } + + start = term_cmd_buf_index - 1; + + /* find first word (backwards) */ + while (start > 0) { + if (!isspace(term_cmd_buf[start])) { + break; + } + + --start; + } + + /* find first space (backwards) */ + while (start > 0) { + if (isspace(term_cmd_buf[start])) { + ++start; + break; + } + + --start; + } + + /* remove word */ + if (start < term_cmd_buf_index) { + memmove(term_cmd_buf + start, + term_cmd_buf + term_cmd_buf_index, + term_cmd_buf_size - term_cmd_buf_index); + term_cmd_buf_size -= term_cmd_buf_index - start; + term_cmd_buf_index = start; + } +} + static void term_bol(void) { term_cmd_buf_index = 0; @@ -338,6 +377,10 @@ void readline_handle_byte(int ch) /* NOTE: readline_start can be called here */ term_readline_func(term_readline_opaque, term_cmd_buf); break; + case 23: + /* ^W */ + term_backword(); + break; case 27: term_esc_state = IS_ESC; break; -- cgit v1.2.3 From 1cd548eeee110dd1eff11e4434b2cf71c429405e Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 25 Jun 2007 11:41:37 +0000 Subject: Update Changelog. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3017 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog b/Changelog index bddbe1564..d289df79b 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,9 @@ - MIPS 64-bit FPU support (Thiemo Seufer) - Xscale PDA emulation (Andrzei Zaborowski) - ColdFire system emulation (Paul Brook) + - Improved SH4 support (Magnus Damm) + - MIPS64 support (Aurelien Jarno, Thiemo Seufer) + - Preliminary Alpha guest support (J. Mayer) version 0.9.0: -- cgit v1.2.3 From aec62507bb6a14b02575f40ec84f617b935043d3 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 25 Jun 2007 11:48:07 +0000 Subject: Enable serial (tty) support on Solaris host, by Marion Hakanson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3018 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/vl.c b/vl.c index 22ded6bf0..172b5ab15 100644 --- a/vl.c +++ b/vl.c @@ -1764,17 +1764,19 @@ static CharDriverState *qemu_chr_open_stdio(void) return chr; } -#if defined(__linux__) +#if defined(__linux__) || defined(__sun__) static CharDriverState *qemu_chr_open_pty(void) { struct termios tty; char slave_name[1024]; int master_fd, slave_fd; +#if defined(__linux__) /* Not satisfying */ if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { return NULL; } +#endif /* Disabling local echo and line-buffered output */ tcgetattr (master_fd, &tty); @@ -1921,7 +1923,14 @@ static CharDriverState *qemu_chr_open_tty(const char *filename) qemu_chr_reset(chr); return chr; } +#else /* ! __linux__ && ! __sun__ */ +static CharDriverState *qemu_chr_open_pty(void) +{ + return NULL; +} +#endif /* __linux__ || __sun__ */ +#if defined(__linux__) typedef struct { int fd; int mode; @@ -2064,17 +2073,10 @@ static CharDriverState *qemu_chr_open_pp(const char *filename) return chr; } +#endif /* __linux__ */ -#else -static CharDriverState *qemu_chr_open_pty(void) -{ - return NULL; -} -#endif - -#endif /* !defined(_WIN32) */ +#else /* _WIN32 */ -#ifdef _WIN32 typedef struct { int max_size; HANDLE hcom, hrecv, hsend; @@ -2440,7 +2442,7 @@ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) return qemu_chr_open_win_file(fd_out); } -#endif +#endif /* !_WIN32 */ /***********************************************************/ /* UDP Net console */ @@ -2954,16 +2956,15 @@ CharDriverState *qemu_chr_open(const char *filename) } else if (!strcmp(filename, "stdio")) { return qemu_chr_open_stdio(); } else -#endif #if defined(__linux__) if (strstart(filename, "/dev/parport", NULL)) { return qemu_chr_open_pp(filename); } else +#endif if (strstart(filename, "/dev/", NULL)) { return qemu_chr_open_tty(filename); } else -#endif -#ifdef _WIN32 +#else /* !_WIN32 */ if (strstart(filename, "COM", NULL)) { return qemu_chr_open_win(filename); } else -- cgit v1.2.3 From 0ae045ae439ad83692ad039a554f7d62acf9de5c Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 25 Jun 2007 13:47:44 +0000 Subject: Insufficient input validation in NE2000 card, written by Tavis Ormandy, contributed by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3019 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ne2000.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/ne2000.c b/hw/ne2000.c index 1625c5538..6d5aa56e1 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -224,7 +224,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) { NE2000State *s = opaque; uint8_t *p; - int total_len, next, avail, len, index, mcast_idx; + unsigned int total_len, next, avail, len, index, mcast_idx; uint8_t buf1[60]; static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -293,7 +293,10 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) /* write packet data */ while (size > 0) { - avail = s->stop - index; + if (index <= s->stop) + avail = s->stop - index; + else + avail = 0; len = size; if (len > avail) len = avail; -- cgit v1.2.3 From e04ea3dc1a6997aa0d2eb8b21170b81f9151d37d Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 25 Jun 2007 13:53:11 +0000 Subject: Handle endianness of double floats, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3020 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/cpu.h | 2 +- target-sh4/op.c | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 5290dd264..9fc0edae2 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -80,7 +80,7 @@ typedef struct tlb_t { typedef struct CPUSH4State { uint32_t flags; /* general execution flags */ uint32_t gregs[24]; /* general registers */ - uint32_t fregs[32]; /* floating point registers */ + float32 fregs[32]; /* floating point registers */ uint32_t sr; /* status register */ uint32_t ssr; /* saved status register */ uint32_t spc; /* saved program counter */ diff --git a/target-sh4/op.c b/target-sh4/op.c index f45c2f467..34e271524 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -698,37 +698,49 @@ void OPPROTO op_movl_imm_rN(void) void OPPROTO op_fmov_frN_FT0(void) { - FT0 = *(float32 *)&env->fregs[PARAM1]; + FT0 = env->fregs[PARAM1]; RETURN(); } void OPPROTO op_fmov_drN_DT0(void) { - DT0 = *(float64 *)&env->fregs[PARAM1]; + CPU_DoubleU d; + + d.l.upper = *(uint32_t *)&env->fregs[PARAM1]; + d.l.lower = *(uint32_t *)&env->fregs[PARAM1 + 1]; + DT0 = d.d; RETURN(); } void OPPROTO op_fmov_frN_FT1(void) { - FT1 = *(float32 *)&env->fregs[PARAM1]; + FT1 = env->fregs[PARAM1]; RETURN(); } void OPPROTO op_fmov_drN_DT1(void) { - DT1 = *(float64 *)&env->fregs[PARAM1]; + CPU_DoubleU d; + + d.l.upper = *(uint32_t *)&env->fregs[PARAM1]; + d.l.lower = *(uint32_t *)&env->fregs[PARAM1 + 1]; + DT1 = d.d; RETURN(); } void OPPROTO op_fmov_FT0_frN(void) { - *(float32 *)&env->fregs[PARAM1] = FT0; + env->fregs[PARAM1] = FT0; RETURN(); } void OPPROTO op_fmov_DT0_drN(void) { - *(float64 *)&env->fregs[PARAM1] = DT0; + CPU_DoubleU d; + + d.d = DT0; + *(uint32_t *)&env->fregs[PARAM1] = d.l.upper; + *(uint32_t *)&env->fregs[PARAM1 + 1] = d.l.lower; RETURN(); } -- cgit v1.2.3 From 996ba2ccf59891a8abe188c073eab3bae1c93b90 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 25 Jun 2007 17:34:33 +0000 Subject: MIPS64 improvements, based on a patch by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3021 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 6 +++--- target-mips/op.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 87a6a334e..c1a7792f7 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -130,11 +130,11 @@ static int get_physical_address (CPUState *env, target_ulong *physical, if (address <= (int32_t)0x7FFFFFFFUL) { /* useg */ - if (!(env->CP0_Status & (1 << CP0St_ERL) && user_mode)) { - ret = env->map_address(env, physical, prot, address, rw, access_type); - } else { + if (env->CP0_Status & (1 << CP0St_ERL)) { *physical = address & 0xFFFFFFFF; *prot = PAGE_READ | PAGE_WRITE; + } else { + ret = env->map_address(env, physical, prot, address, rw, access_type); } #ifdef TARGET_MIPS64 /* diff --git a/target-mips/op.c b/target-mips/op.c index 715c35504..4aa63e346 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -297,7 +297,7 @@ void op_addr_add (void) with Status_UX = 0 should be casted to 32-bit and sign extended. See the MIPS64 PRA manual, section 4.10. */ #ifdef TARGET_MIPS64 - if ((env->CP0_Status & (1 << CP0St_UM)) && + if ((env->hflags & MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_UX))) T0 = (int64_t)(int32_t)(T0 + T1); else @@ -1608,7 +1608,7 @@ void op_dmfc0_errorepc (void) void op_cp0_enabled(void) { if (!(env->CP0_Status & (1 << CP0St_CU0)) && - (env->hflags & MIPS_HFLAG_UM)) { + (env->hflags & MIPS_HFLAG_UM)) { CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 0); } RETURN(); -- cgit v1.2.3 From 46525e1fbe3fc18b8f3d8e567b955b8c66f0c28c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 25 Jun 2007 19:52:58 +0000 Subject: Drop unused parameters git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3022 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 1993a4c89..110b804c7 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -598,7 +598,8 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, } } -static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2) +static inline void gen_branch2(DisasContext *dc, target_ulong pc1, + target_ulong pc2) { int l1; @@ -612,7 +613,8 @@ static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, targ gen_goto_tb(dc, 1, pc2, pc2 + 4); } -static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2) +static inline void gen_branch_a(DisasContext *dc, target_ulong pc1, + target_ulong pc2) { int l1; @@ -626,12 +628,13 @@ static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, tar gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8); } -static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc) +static inline void gen_branch(DisasContext *dc, target_ulong pc, + target_ulong npc) { gen_goto_tb(dc, 0, pc, npc); } -static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2) +static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2) { int l1, l2; @@ -651,7 +654,7 @@ static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, targe static inline void flush_T2(DisasContext * dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); dc->npc = DYNAMIC_PC; } } @@ -659,7 +662,7 @@ static inline void flush_T2(DisasContext * dc) static inline void save_npc(DisasContext * dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); dc->npc = DYNAMIC_PC; } else if (dc->npc != DYNAMIC_PC) { gen_movl_npc_im(dc->npc); @@ -675,7 +678,7 @@ static inline void save_state(DisasContext * dc) static inline void gen_mov_pc_npc(DisasContext * dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]); gen_op_mov_pc_npc(); dc->pc = DYNAMIC_PC; } else if (dc->npc == DYNAMIC_PC) { @@ -861,7 +864,7 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) flush_T2(dc); gen_cond[cc][cond](); if (a) { - gen_branch_a(dc, (long)dc->tb, target, dc->npc); + gen_branch_a(dc, target, dc->npc); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -900,7 +903,7 @@ static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) flush_T2(dc); gen_fcond[cc][cond](); if (a) { - gen_branch_a(dc, (long)dc->tb, target, dc->npc); + gen_branch_a(dc, target, dc->npc); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -921,7 +924,7 @@ static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn) flush_T2(dc); gen_cond_reg(cond); if (a) { - gen_branch_a(dc, (long)dc->tb, target, dc->npc); + gen_branch_a(dc, target, dc->npc); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -3123,7 +3126,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_next_insn(); } else if (dc->npc == JUMP_PC) { /* we can do a static jump */ - gen_branch2(dc, (long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]); + gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1]); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -3249,7 +3252,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, if (dc->pc != DYNAMIC_PC && (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { /* static PC and NPC: we can use direct chaining */ - gen_branch(dc, (long)tb, dc->pc, dc->npc); + gen_branch(dc, dc->pc, dc->npc); } else { if (dc->pc != DYNAMIC_PC) gen_jmp_im(dc->pc); -- cgit v1.2.3 From b3ceef24f4fee8d5ed96b8c4a5d3e80c0a651f0b Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 25 Jun 2007 19:56:13 +0000 Subject: Rename variables and rearrange code to please gcc -Wshadow checks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3023 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 14 +++++++------- hw/sun4m.c | 45 ++++++++++++++++++++++++--------------------- hw/tcx.c | 2 +- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 0a2c87330..36dbdcf16 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -354,7 +354,7 @@ static void slavio_serial_update_parameters(ChannelState *s) static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { - SerialState *ser = opaque; + SerialState *serial = opaque; ChannelState *s; uint32_t saddr; int newreg, channel; @@ -362,7 +362,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint val &= 0xff; saddr = (addr & 3) >> 1; channel = (addr & SERIAL_MAXADDR) >> 2; - s = &ser->chn[channel]; + s = &serial->chn[channel]; switch (saddr) { case 0: SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff); @@ -407,13 +407,13 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint default: break; case 0x40: - slavio_serial_reset_chn(&ser->chn[1]); + slavio_serial_reset_chn(&serial->chn[1]); return; case 0x80: - slavio_serial_reset_chn(&ser->chn[0]); + slavio_serial_reset_chn(&serial->chn[0]); return; case 0xc0: - slavio_serial_reset(ser); + slavio_serial_reset(serial); return; } break; @@ -446,7 +446,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) { - SerialState *ser = opaque; + SerialState *serial = opaque; ChannelState *s; uint32_t saddr; uint32_t ret; @@ -454,7 +454,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) saddr = (addr & 3) >> 1; channel = (addr & SERIAL_MAXADDR) >> 2; - s = &ser->chn[channel]; + s = &serial->chn[channel]; switch (saddr) { case 0: SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]); diff --git a/hw/sun4m.c b/hw/sun4m.c index 2f7f22e4c..eb69ef8e5 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -154,8 +154,6 @@ static void nvram_finish_partition (m48t59_t *nvram, uint32_t start, m48t59_write(nvram, start + 1, sum & 0xff); } -static m48t59_t *nvram; - extern int nographic; static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, @@ -292,13 +290,13 @@ static void secondary_cpu_reset(void *opaque) env->halted = 1; } -static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, - DisplayState *ds, const char *cpu_model) +static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, + DisplayState *ds, const char *cpu_model) { CPUState *env, *envs[MAX_CPUS]; unsigned int i; - void *iommu, *espdma, *ledma, *main_esp; + void *iommu, *espdma, *ledma, *main_esp, *nvram; const sparc_def_t *def; qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; @@ -328,7 +326,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); + cpu_register_physical_memory(0, RAM_size, 0); iommu = iommu_init(hwdef->iommu_base); slavio_intctl = slavio_intctl_init(hwdef->intctl_base, @@ -347,7 +345,7 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); exit (1); } - tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size, + tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size, hwdef->vram_size, graphic_width, graphic_height, graphic_depth); if (nd_table[0].model == NULL @@ -388,13 +386,16 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size, slavio_irq[hwdef->me_irq]); if (hwdef->cs_base != (target_phys_addr_t)-1) cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); + + return nvram; } -static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, +static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, - int machine_id) + int machine_id, + void *nvram) { int ret, linux_boot; char buf[1024]; @@ -403,7 +404,7 @@ static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, linux_boot = (kernel_filename != NULL); - prom_offset = ram_size + vram_size; + prom_offset = RAM_size + vram_size; cpu_register_physical_memory(PROM_ADDR, (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); @@ -451,7 +452,7 @@ static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device, } } nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, - boot_device, ram_size, kernel_size, graphic_width, + boot_device, RAM_size, kernel_size, graphic_width, graphic_height, graphic_depth, machine_id); } @@ -524,46 +525,48 @@ static const struct hwdef hwdefs[] = { }, }; -static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds, +static void sun4m_common_init(int RAM_size, int boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, unsigned int machine, int max_ram) { - if ((unsigned int)ram_size > (unsigned int)max_ram) { + void *nvram; + + if ((unsigned int)RAM_size > (unsigned int)max_ram) { fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", - (unsigned int)ram_size / (1024 * 1024), + (unsigned int)RAM_size / (1024 * 1024), (unsigned int)max_ram / (1024 * 1024)); exit(1); } - sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model); + nvram = sun4m_hw_init(&hwdefs[machine], RAM_size, ds, cpu_model); - sun4m_load_kernel(hwdefs[machine].vram_size, ram_size, boot_device, + sun4m_load_kernel(hwdefs[machine].vram_size, RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, - hwdefs[machine].machine_id); + hwdefs[machine].machine_id, nvram); } /* SPARCstation 5 hardware initialisation */ -static void ss5_init(int ram_size, int vga_ram_size, int boot_device, +static void ss5_init(int RAM_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { if (cpu_model == NULL) cpu_model = "Fujitsu MB86904"; - sun4m_common_init(ram_size, boot_device, ds, kernel_filename, + sun4m_common_init(RAM_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 0, 0x10000000); } /* SPARCstation 10 hardware initialisation */ -static void ss10_init(int ram_size, int vga_ram_size, int boot_device, +static void ss10_init(int RAM_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { if (cpu_model == NULL) cpu_model = "TI SuperSparc II"; - sun4m_common_init(ram_size, boot_device, ds, kernel_filename, + sun4m_common_init(RAM_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 1, PROM_ADDR); // XXX prom overlap, actually first 4GB ok } diff --git a/hw/tcx.c b/hw/tcx.c index 675c74d9f..10ae987fc 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -180,7 +180,7 @@ static void tcx_update_display(void *opaque) ram_addr_t page, page_min, page_max; int y, y_start, dd, ds; uint8_t *d, *s; - void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width); + void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); if (ts->ds->depth == 0) return; -- cgit v1.2.3 From 88fe8a41f2abbee28948626a4e6426d17f0498bf Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 26 Jun 2007 08:35:18 +0000 Subject: DR6 single step exception status bit, by Juergen Keil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3024 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 1 + target-i386/helper.c | 6 ++++++ target-i386/op.c | 5 +++++ target-i386/translate.c | 2 +- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/target-i386/exec.h b/target-i386/exec.h index f6d05e035..f48462aaa 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -190,6 +190,7 @@ void helper_divq_EAX_T0(void); void helper_idivq_EAX_T0(void); void helper_bswapq_T0(void); void helper_cmpxchg8b(void); +void helper_single_step(void); void helper_cpuid(void); void helper_enter_level(int level, int data32); void helper_enter64_level(int level, int data64); diff --git a/target-i386/helper.c b/target-i386/helper.c index 951fdc573..3c051b9ea 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1622,6 +1622,12 @@ void helper_cmpxchg8b(void) CC_SRC = eflags; } +void helper_single_step() +{ + env->dr[6] |= 0x4000; + raise_exception(EXCP01_SSTP); +} + void helper_cpuid(void) { uint32_t index; diff --git a/target-i386/op.c b/target-i386/op.c index a8cfce271..ea8aec6b5 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -730,6 +730,11 @@ void OPPROTO op_cmpxchg8b(void) helper_cmpxchg8b(); } +void OPPROTO op_single_step(void) +{ + helper_single_step(); +} + void OPPROTO op_movl_T0_0(void) { T0 = 0; diff --git a/target-i386/translate.c b/target-i386/translate.c index 393db0d65..15bfef5cb 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2277,7 +2277,7 @@ static void gen_eob(DisasContext *s) if (s->singlestep_enabled) { gen_op_debug(); } else if (s->tf) { - gen_op_raise_exception(EXCP01_SSTP); + gen_op_single_step(); } else { gen_op_movl_T0_0(); gen_op_exit_tb(); -- cgit v1.2.3 From d79acba420196a07f94b8d789972de7ff776f548 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 26 Jun 2007 20:01:13 +0000 Subject: Fix writes to pages containing watchpoints for the RAM not at 0x0 cases. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3025 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 2 +- exec.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index a19fef72d..ac96b0ab5 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -141,7 +141,7 @@ typedef struct CPUTLBEntry { \ struct { \ target_ulong vaddr; \ - int is_ram; \ + target_phys_addr_t addend; \ } watchpoint[MAX_WATCHPOINTS]; \ int nb_watchpoints; \ int watchpoint_hit; \ diff --git a/exec.c b/exec.c index c782e5b6b..5fbeb8dce 100644 --- a/exec.c +++ b/exec.c @@ -1626,17 +1626,18 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, for (i = 0; i < env->nb_watchpoints; i++) { if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) { if (address & ~TARGET_PAGE_MASK) { - env->watchpoint[i].is_ram = 0; + env->watchpoint[i].addend = 0; address = vaddr | io_mem_watch; } else { - env->watchpoint[i].is_ram = 1; + env->watchpoint[i].addend = pd - paddr + + (unsigned long) phys_ram_base; /* TODO: Figure out how to make read watchpoints coexist with code. */ pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD; } } } - + index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); addend -= vaddr; te = &env->tlb_table[is_user][index]; @@ -2178,7 +2179,7 @@ static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr) /* Generate a debug exception if a watchpoint has been hit. Returns the real physical address of the access. addr will be a host - address in the is_ram case. */ + address in case of a RAM location. */ static target_ulong check_watchpoint(target_phys_addr_t addr) { CPUState *env = cpu_single_env; @@ -2190,8 +2191,7 @@ static target_ulong check_watchpoint(target_phys_addr_t addr) for (i = 0; i < env->nb_watchpoints; i++) { watch = env->watchpoint[i].vaddr; if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) { - if (env->watchpoint[i].is_ram) - retaddr = addr - (unsigned long)phys_ram_base; + retaddr = addr - env->watchpoint[i].addend; if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) { cpu_single_env->watchpoint_hit = i + 1; cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG); -- cgit v1.2.3 From 8dfdb87c8d675b846e12c8066922525e22bcfc50 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 26 Jun 2007 20:26:03 +0000 Subject: Implement recip1/recip2/rsqrt1/rsqrt2. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3026 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 230 +++++++++++++++++++++++++++++------------------- target-mips/translate.c | 6 +- 2 files changed, 143 insertions(+), 93 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index e4f267670..94782252e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -597,6 +597,13 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) /* Complex FPU operations which may need stack space. */ +#define FLOAT_SIGN32 (1 << 31) +#define FLOAT_SIGN64 (1ULL << 63) +#define FLOAT_ONE32 (0x3f8 << 20) +#define FLOAT_ONE64 (0x3ffULL << 52) +#define FLOAT_TWO32 (1 << 30) +#define FLOAT_TWO64 (1ULL << 62) + /* convert MIPS rounding mode in FCR31 to IEEE library */ unsigned int ieee_rm[] = { float_round_nearest_even, @@ -912,58 +919,78 @@ FLOAT_OP(floorw, s) WT2 = 0x7fffffff; } -/* unary operations, MIPS specific, s and d */ -#define FLOAT_UNOP(name) \ -FLOAT_OP(name, d) \ -{ \ - set_float_exception_flags(0, &env->fp_status); \ -/* XXX: not implemented */ \ -/* FDT2 = float64_ ## name (FDT0, &env->fp_status);*/ \ -do_raise_exception(EXCP_RI); \ - update_fcr31(); \ -} \ -FLOAT_OP(name, s) \ -{ \ - set_float_exception_flags(0, &env->fp_status); \ -/* XXX: not implemented */ \ -/* FST2 = float32_ ## name (FST0, &env->fp_status);*/ \ -do_raise_exception(EXCP_RI); \ - update_fcr31(); \ +/* MIPS specific unary operations */ +FLOAT_OP(recip, d) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(recip, s) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); + update_fcr31(); } -FLOAT_UNOP(rsqrt) -FLOAT_UNOP(recip) -#undef FLOAT_UNOP -/* unary operations, MIPS specific, s, d and ps */ -#define FLOAT_UNOP(name) \ -FLOAT_OP(name, d) \ -{ \ - set_float_exception_flags(0, &env->fp_status); \ -/* XXX: not implemented */ \ -/* FDT2 = float64_ ## name (FDT0, &env->fp_status);*/ \ -do_raise_exception(EXCP_RI); \ - update_fcr31(); \ -} \ -FLOAT_OP(name, s) \ -{ \ - set_float_exception_flags(0, &env->fp_status); \ -/* XXX: not implemented */ \ -/* FST2 = float32_ ## name (FST0, &env->fp_status);*/ \ -do_raise_exception(EXCP_RI); \ - update_fcr31(); \ -} \ -FLOAT_OP(name, ps) \ -{ \ - set_float_exception_flags(0, &env->fp_status); \ -/* XXX: not implemented */ \ -/* FST2 = float32_ ## name (FST0, &env->fp_status);*/ \ -/* FSTH2 = float32_ ## name (FSTH0, &env->fp_status);*/ \ -do_raise_exception(EXCP_RI); \ - update_fcr31(); \ +FLOAT_OP(rsqrt, d) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = float64_sqrt(FDT0, &env->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(rsqrt, s) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_sqrt(FST0, &env->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); + update_fcr31(); +} + +FLOAT_OP(recip1, d) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(recip1, s) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(recip1, ps) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); + FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fp_status); + update_fcr31(); +} + +FLOAT_OP(rsqrt1, d) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = float64_sqrt(FDT0, &env->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(rsqrt1, s) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_sqrt(FST0, &env->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(rsqrt1, ps) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_sqrt(FST0, &env->fp_status); + FSTH2 = float32_sqrt(FSTH0, &env->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); + FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fp_status); + update_fcr31(); } -FLOAT_UNOP(rsqrt1) -FLOAT_UNOP(recip1) -#undef FLOAT_UNOP /* binary operations */ #define FLOAT_BINOP(name) \ @@ -976,7 +1003,7 @@ FLOAT_OP(name, d) \ FDT2 = 0x7ff7ffffffffffffULL; \ else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ if ((env->fcr31 & 0x3) == 0) \ - FDT2 &= 0x8000000000000000ULL; \ + FDT2 &= FLOAT_SIGN64; \ } \ } \ FLOAT_OP(name, s) \ @@ -988,7 +1015,7 @@ FLOAT_OP(name, s) \ FST2 = 0x7fbfffff; \ else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ if ((env->fcr31 & 0x3) == 0) \ - FST2 &= 0x80000000ULL; \ + FST2 &= FLOAT_SIGN32; \ } \ } \ FLOAT_OP(name, ps) \ @@ -1002,8 +1029,8 @@ FLOAT_OP(name, ps) \ FSTH2 = 0x7fbfffff; \ } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ if ((env->fcr31 & 0x3) == 0) { \ - FST2 &= 0x80000000ULL; \ - FSTH2 &= 0x80000000ULL; \ + FST2 &= FLOAT_SIGN32; \ + FSTH2 &= FLOAT_SIGN32; \ } \ } \ } @@ -1013,36 +1040,58 @@ FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP -/* binary operations, MIPS specific */ -#define FLOAT_BINOP(name) \ -FLOAT_OP(name, d) \ -{ \ - set_float_exception_flags(0, &env->fp_status); \ -/* XXX: not implemented */ \ -/* FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);*/ \ -do_raise_exception(EXCP_RI); \ - update_fcr31(); \ -} \ -FLOAT_OP(name, s) \ -{ \ - set_float_exception_flags(0, &env->fp_status); \ -/* XXX: not implemented */ \ -/* FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/ \ -do_raise_exception(EXCP_RI); \ - update_fcr31(); \ -} \ -FLOAT_OP(name, ps) \ -{ \ - set_float_exception_flags(0, &env->fp_status); \ -/* XXX: not implemented */ \ -/* FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/ \ -/* FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status);*/ \ -do_raise_exception(EXCP_RI); \ - update_fcr31(); \ +/* MIPS specific binary operations */ +FLOAT_OP(recip2, d) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = float64_mul(FDT0, FDT2, &env->fp_status); + FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status) ^ FLOAT_SIGN64; + update_fcr31(); +} +FLOAT_OP(recip2, s) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; + update_fcr31(); +} +FLOAT_OP(recip2, ps) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fp_status); + FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; + FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; + update_fcr31(); +} + +FLOAT_OP(rsqrt2, d) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = float64_mul(FDT0, FDT2, &env->fp_status); + FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status); + FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fp_status) ^ FLOAT_SIGN64; + update_fcr31(); +} +FLOAT_OP(rsqrt2, s) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status); + FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; + update_fcr31(); +} +FLOAT_OP(rsqrt2, ps) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fp_status); + FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status); + FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status); + FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; + FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; + update_fcr31(); } -FLOAT_BINOP(rsqrt2) -FLOAT_BINOP(recip2) -#undef FLOAT_BINOP FLOAT_OP(addr, ps) { @@ -1060,6 +1109,7 @@ FLOAT_OP(mulr, ps) update_fcr31(); } +/* compare operations */ #define FOP_COND_D(op, cond) \ void do_cmp_d_ ## op (long cc) \ { \ @@ -1073,8 +1123,8 @@ void do_cmp_d_ ## op (long cc) \ void do_cmpabs_d_ ## op (long cc) \ { \ int c; \ - FDT0 &= ~(1ULL << 63); \ - FDT1 &= ~(1ULL << 63); \ + FDT0 &= ~FLOAT_SIGN64; \ + FDT1 &= ~FLOAT_SIGN64; \ c = cond; \ update_fcr31(); \ if (c) \ @@ -1131,8 +1181,8 @@ void do_cmp_s_ ## op (long cc) \ void do_cmpabs_s_ ## op (long cc) \ { \ int c; \ - FST0 &= ~(1 << 31); \ - FST1 &= ~(1 << 31); \ + FST0 &= ~FLOAT_SIGN32; \ + FST1 &= ~FLOAT_SIGN32; \ c = cond; \ update_fcr31(); \ if (c) \ @@ -1194,10 +1244,10 @@ void do_cmp_ps_ ## op (long cc) \ void do_cmpabs_ps_ ## op (long cc) \ { \ int cl, ch; \ - FST0 &= ~(1 << 31); \ - FSTH0 &= ~(1 << 31); \ - FST1 &= ~(1 << 31); \ - FSTH1 &= ~(1 << 31); \ + FST0 &= ~FLOAT_SIGN32; \ + FSTH0 &= ~FLOAT_SIGN32; \ + FST1 &= ~FLOAT_SIGN32; \ + FSTH1 &= ~FLOAT_SIGN32; \ cl = condl; \ ch = condh; \ update_fcr31(); \ diff --git a/target-mips/translate.c b/target-mips/translate.c index b5a8b5b0a..7f5141c33 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4551,7 +4551,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, case FOP(31, 16): check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); + GEN_LOAD_FREG_FTN(WT2, ft); gen_op_float_rsqrt2_s(); GEN_STORE_FTN_FREG(fd, WT2); opn = "rsqrt2.s"; @@ -5036,8 +5036,8 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); - GEN_LOAD_FREG_FTN(WT2, fd); - GEN_LOAD_FREG_FTN(WTH2, fd); + GEN_LOAD_FREG_FTN(WT2, ft); + GEN_LOAD_FREG_FTN(WTH2, ft); gen_op_float_rsqrt2_ps(); GEN_STORE_FTN_FREG(fd, WT2); GEN_STORE_FTN_FREG(fd, WTH2); -- cgit v1.2.3 From 403f14ef1e6f481d9b833e53846c421cf76607e3 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 27 Jun 2007 11:12:42 +0000 Subject: Fix environ termination, by Andreas Schwab. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3027 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index fe2cc5817..8d24a1fc1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1819,7 +1819,7 @@ int main(int argc, char **argv) continue; *(dst++) = strdup(*wrk); } - dst = NULL; /* NULL terminate target_environ */ + *dst = NULL; /* NULL terminate target_environ */ if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) { printf("Error loading %s\n", filename); -- cgit v1.2.3 From e3b60f1d9e1f73e75095e885af66473400bef8aa Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 27 Jun 2007 19:01:46 +0000 Subject: Fix computation for ceil, floor and round instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3028 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 94782252e..2b100a289 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -783,6 +783,7 @@ FLOAT_OP(roundl, d) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); DT2 = float64_round_to_int(FDT0, &env->fp_status); + DT2 = float64_to_int64(DT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -791,7 +792,8 @@ FLOAT_OP(roundl, d) FLOAT_OP(roundl, s) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + DT2 = float32_to_int64(WT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -800,7 +802,10 @@ FLOAT_OP(roundl, s) FLOAT_OP(roundw, d) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); +// ??? + env->fp_status.float_exception_flags &= ~float_flag_inexact; + WT2 = float64_to_int32(DT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -810,6 +815,7 @@ FLOAT_OP(roundw, s) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); WT2 = float32_round_to_int(FST0, &env->fp_status); + WT2 = float32_to_int32(WT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -849,6 +855,7 @@ FLOAT_OP(ceill, d) { set_float_rounding_mode(float_round_up, &env->fp_status); DT2 = float64_round_to_int(FDT0, &env->fp_status); + DT2 = float64_to_int64(DT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -857,7 +864,8 @@ FLOAT_OP(ceill, d) FLOAT_OP(ceill, s) { set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + DT2 = float32_to_int64(WT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -866,7 +874,10 @@ FLOAT_OP(ceill, s) FLOAT_OP(ceilw, d) { set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); +// ??? + env->fp_status.float_exception_flags &= ~float_flag_inexact; + WT2 = float64_to_int32(DT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -876,6 +887,7 @@ FLOAT_OP(ceilw, s) { set_float_rounding_mode(float_round_up, &env->fp_status); WT2 = float32_round_to_int(FST0, &env->fp_status); + WT2 = float32_to_int32(WT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -886,6 +898,7 @@ FLOAT_OP(floorl, d) { set_float_rounding_mode(float_round_down, &env->fp_status); DT2 = float64_round_to_int(FDT0, &env->fp_status); + DT2 = float64_to_int64(DT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -894,7 +907,8 @@ FLOAT_OP(floorl, d) FLOAT_OP(floorl, s) { set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + DT2 = float32_to_int64(WT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -903,7 +917,10 @@ FLOAT_OP(floorl, s) FLOAT_OP(floorw, d) { set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); +// ??? + env->fp_status.float_exception_flags &= ~float_flag_inexact; + WT2 = float64_to_int32(DT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -913,6 +930,7 @@ FLOAT_OP(floorw, s) { set_float_rounding_mode(float_round_down, &env->fp_status); WT2 = float32_round_to_int(FST0, &env->fp_status); + WT2 = float32_to_int32(WT2, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) -- cgit v1.2.3 From 175087965268c2792cf6bbb524dbccaadcf1fca4 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 28 Jun 2007 07:28:22 +0000 Subject: Update Sparc32 and Sparc64 OpenBIOS image to SVN revision 157. Changes: r150: Try to fix system reset for SMP and SS-10 cases r151: Fix obp_dumb_memalloc r152: Fix mapping more than 2G memory r153: Get a real memory allocator for Sparc, based on PPC ofmem r154: Update totavail when memory is allocated by dumb memory allocator r155: Fix pop_fstr_copy memory leaks - console one prevented Debian 3.1r1 from installing in console=prom mode - fixing this also needed the real malloc/free r156: Hack for building on CIFS directory r157: Allow boot start PC to be different from virtual location (boot mode) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3029 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 3 +-- pc-bios/openbios-sparc32 | Bin 272948 -> 272948 bytes pc-bios/openbios-sparc64 | Bin 410216 -> 475784 bytes 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index ba1568e57..2c50783b7 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,8 +14,7 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 image is built from SVN version 149 and Sparc64 - image from version 125. + The included Sparc32 and Sparc64 images are built from SVN version 157. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 62cc5eb7b..4296ee8c6 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 1bf14bd3c..ace1dae29 100644 Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ -- cgit v1.2.3 From ea6e4fe2dd3594d04c03ddb0befc1c4a82ab4e83 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 28 Jun 2007 14:05:38 +0000 Subject: Fix segfault when printing the help text, spotted by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3030 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vl.c b/vl.c index 172b5ab15..6006e1be4 100644 --- a/vl.c +++ b/vl.c @@ -6568,7 +6568,7 @@ int main_loop(void) return ret; } -void help(void) +static void help(const char *optarg) { printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" @@ -7450,12 +7450,12 @@ int main(int argc, char **argv) break; #endif case QEMU_OPTION_h: - help(); + help(optarg); break; case QEMU_OPTION_m: ram_size = atoi(optarg) * 1024 * 1024; if (ram_size <= 0) - help(); + help(optarg); if (ram_size > PHYS_RAM_MAX_SIZE) { fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", PHYS_RAM_MAX_SIZE / (1024 * 1024)); @@ -7741,7 +7741,7 @@ int main(int argc, char **argv) hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') - help(); + help(""); /* boot to floppy or the default cd if no hard disk defined yet */ if (hd_filename[0] == '\0' && boot_device == 'c') { -- cgit v1.2.3 From 5e4ef64cfd8cfcd8eb76c70a0d837f06ca8c5467 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 28 Jun 2007 14:07:05 +0000 Subject: Simplify round/ceil/floor implementation, spotted by Fabrice Bellard. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3031 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 2b100a289..477b80d51 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -782,8 +782,7 @@ FLOAT_OP(cvtw, d) FLOAT_OP(roundl, d) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - DT2 = float64_to_int64(DT2, &env->fp_status); + DT2 = float64_to_int64(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -792,8 +791,7 @@ FLOAT_OP(roundl, d) FLOAT_OP(roundl, s) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - DT2 = float32_to_int64(WT2, &env->fp_status); + DT2 = float32_to_int64(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -802,10 +800,7 @@ FLOAT_OP(roundl, s) FLOAT_OP(roundw, d) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); -// ??? - env->fp_status.float_exception_flags &= ~float_flag_inexact; - WT2 = float64_to_int32(DT2, &env->fp_status); + WT2 = float64_to_int32(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -814,8 +809,7 @@ FLOAT_OP(roundw, d) FLOAT_OP(roundw, s) { set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - WT2 = float32_to_int32(WT2, &env->fp_status); + WT2 = float32_to_int32(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -854,8 +848,7 @@ FLOAT_OP(truncw, s) FLOAT_OP(ceill, d) { set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - DT2 = float64_to_int64(DT2, &env->fp_status); + DT2 = float64_to_int64(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -864,8 +857,7 @@ FLOAT_OP(ceill, d) FLOAT_OP(ceill, s) { set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - DT2 = float32_to_int64(WT2, &env->fp_status); + DT2 = float32_to_int64(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -874,10 +866,7 @@ FLOAT_OP(ceill, s) FLOAT_OP(ceilw, d) { set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); -// ??? - env->fp_status.float_exception_flags &= ~float_flag_inexact; - WT2 = float64_to_int32(DT2, &env->fp_status); + WT2 = float64_to_int32(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -886,8 +875,7 @@ FLOAT_OP(ceilw, d) FLOAT_OP(ceilw, s) { set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - WT2 = float32_to_int32(WT2, &env->fp_status); + WT2 = float32_to_int32(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -897,8 +885,7 @@ FLOAT_OP(ceilw, s) FLOAT_OP(floorl, d) { set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - DT2 = float64_to_int64(DT2, &env->fp_status); + DT2 = float64_to_int64(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -907,8 +894,7 @@ FLOAT_OP(floorl, d) FLOAT_OP(floorl, s) { set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - DT2 = float32_to_int64(WT2, &env->fp_status); + DT2 = float32_to_int64(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -917,10 +903,7 @@ FLOAT_OP(floorl, s) FLOAT_OP(floorw, d) { set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); -// ??? - env->fp_status.float_exception_flags &= ~float_flag_inexact; - WT2 = float64_to_int32(DT2, &env->fp_status); + WT2 = float64_to_int32(FDT0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) @@ -929,8 +912,7 @@ FLOAT_OP(floorw, d) FLOAT_OP(floorw, s) { set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - WT2 = float32_to_int32(WT2, &env->fp_status); + WT2 = float32_to_int32(FST0, &env->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) -- cgit v1.2.3 From 3fda388a1c19bef4aa8615d91693260e74564bd8 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 28 Jun 2007 15:14:49 +0000 Subject: Limit the use of qemu_chr_open_tty to __linux__ and __sun__, by Andreas Faerber. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3032 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 6006e1be4..778d159c0 100644 --- a/vl.c +++ b/vl.c @@ -2961,9 +2961,11 @@ CharDriverState *qemu_chr_open(const char *filename) return qemu_chr_open_pp(filename); } else #endif +#if defined(__linux__) || defined(__sun__) if (strstart(filename, "/dev/", NULL)) { return qemu_chr_open_tty(filename); - } else + } else +#endif #else /* !_WIN32 */ if (strstart(filename, "COM", NULL)) { return qemu_chr_open_win(filename); -- cgit v1.2.3 From 5a84a5dd0b6b7009cdf3d95523579addb00b66c8 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 28 Jun 2007 15:28:18 +0000 Subject: Fix Lance on 32-bit hosts git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3033 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index 3fffd44fb..7f7c2de37 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -2011,16 +2011,39 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) #if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure +static void lance_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ +#ifdef PCNET_DEBUG_IO + printf("lance_mem_writew addr=" TARGET_FMT_plx " val=0x%04x\n", addr, + val & 0xffff); +#endif + pcnet_ioport_writew(opaque, addr & 7, val & 0xffff); +} + +static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) +{ + uint32_t val; + + val = pcnet_ioport_readw(opaque, addr & 7); +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr, + val & 0xffff); +#endif + + return val & 0xffff; +} + static CPUReadMemoryFunc *lance_mem_read[3] = { - (CPUReadMemoryFunc *)&pcnet_ioport_readw, - (CPUReadMemoryFunc *)&pcnet_ioport_readw, - (CPUReadMemoryFunc *)&pcnet_ioport_readw, + lance_mem_readw, + lance_mem_readw, + lance_mem_readw, }; static CPUWriteMemoryFunc *lance_mem_write[3] = { - (CPUWriteMemoryFunc *)&pcnet_ioport_writew, - (CPUWriteMemoryFunc *)&pcnet_ioport_writew, - (CPUWriteMemoryFunc *)&pcnet_ioport_writew, + lance_mem_writew, + lance_mem_writew, + lance_mem_writew, }; void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, -- cgit v1.2.3 From 15f8220829f9a3e8911c81d1cdf662769987e37f Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 29 Jun 2007 23:26:08 +0000 Subject: Sanitize exit codes of help queries, this time for real. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3034 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vl.c b/vl.c index 778d159c0..78c8babc6 100644 --- a/vl.c +++ b/vl.c @@ -6570,7 +6570,7 @@ int main_loop(void) return ret; } -static void help(const char *optarg) +static void help(int exitcode) { printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" @@ -6712,7 +6712,7 @@ static void help(const char *optarg) #endif DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); - exit(strcmp(optarg, "?")); + exit(exitcode); } #define HAS_ARG 0x0001 @@ -7283,12 +7283,12 @@ int main(int argc, char **argv) m->name, m->desc, m == first_machine ? " (default)" : ""); } - exit(1); + exit(*optarg != '?'); } break; case QEMU_OPTION_cpu: /* hw initialization will check this */ - if (optarg[0] == '?') { + if (*optarg == '?') { #if defined(TARGET_PPC) ppc_cpu_list(stdout, &fprintf); #elif defined(TARGET_ARM) @@ -7298,7 +7298,7 @@ int main(int argc, char **argv) #elif defined(TARGET_SPARC) sparc_cpu_list(stdout, &fprintf); #endif - exit(1); + exit(0); } else { cpu_model = optarg; } @@ -7452,12 +7452,12 @@ int main(int argc, char **argv) break; #endif case QEMU_OPTION_h: - help(optarg); + help(0); break; case QEMU_OPTION_m: ram_size = atoi(optarg) * 1024 * 1024; if (ram_size <= 0) - help(optarg); + help(1); if (ram_size > PHYS_RAM_MAX_SIZE) { fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n", PHYS_RAM_MAX_SIZE / (1024 * 1024)); @@ -7743,7 +7743,7 @@ int main(int argc, char **argv) hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') - help(""); + help(1); /* boot to floppy or the default cd if no hard disk defined yet */ if (hd_filename[0] == '\0' && boot_device == 'c') { -- cgit v1.2.3 From e735b91cd44e5dafb83ed4158a4c6721c0b289aa Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 30 Jun 2007 13:53:24 +0000 Subject: Allow changing log filename. Close logfile when logging is disabled. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3035 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 13 ++++++++++++- monitor.c | 7 +++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 5fbeb8dce..5ed63de68 100644 --- a/exec.c +++ b/exec.c @@ -152,6 +152,7 @@ static int io_mem_watch; char *logfilename = "/tmp/qemu.log"; FILE *logfile; int loglevel; +static int log_append = 0; /* statistics */ static int tlb_flush_count; @@ -1160,7 +1161,7 @@ void cpu_set_log(int log_flags) { loglevel = log_flags; if (loglevel && !logfile) { - logfile = fopen(logfilename, "w"); + logfile = fopen(logfilename, log_append ? "wa" : "w"); if (!logfile) { perror(logfilename); _exit(1); @@ -1174,12 +1175,22 @@ void cpu_set_log(int log_flags) #else setvbuf(logfile, NULL, _IOLBF, 0); #endif + log_append = 1; + } + if (!loglevel && logfile) { + fclose(logfile); + logfile = NULL; } } void cpu_set_log_filename(const char *filename) { logfilename = strdup(filename); + if (logfile) { + fclose(logfile); + logfile = NULL; + } + cpu_set_log(loglevel); } /* mask must never be zero, except for A20 change call */ diff --git a/monitor.c b/monitor.c index a8db87040..ed31d5031 100644 --- a/monitor.c +++ b/monitor.c @@ -406,6 +406,11 @@ static void do_screen_dump(const char *filename) vga_hw_screen_dump(filename); } +static void do_logfile(const char *filename) +{ + cpu_set_log_filename(filename); +} + static void do_log(const char *items) { int mask; @@ -1213,6 +1218,8 @@ static term_cmd_t term_cmds[] = { "device filename", "change a removable medium" }, { "screendump", "F", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, + { "logfile", "s", do_logfile, + "filename", "output logs to 'filename'" }, { "log", "s", do_log, "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, { "savevm", "s?", do_savevm, -- cgit v1.2.3 From 64075cd76a1d78f37e4e436bd1e7d2376f6bd7c9 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 30 Jun 2007 14:07:13 +0000 Subject: PL110 versatile register hack fix (Adam Lackorzynski). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3036 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl110.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/pl110.c b/hw/pl110.c index 7340d4b4a..9df77c46c 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -302,8 +302,12 @@ static uint32_t pl110_read(void *opaque, target_phys_addr_t offset) case 5: /* LCDLPBASE */ return s->lpbase; case 6: /* LCDIMSC */ + if (s->versatile) + return s->cr; return s->int_mask; case 7: /* LCDControl */ + if (s->versatile) + return s->int_mask; return s->cr; case 8: /* LCDRIS */ return s->int_status; -- cgit v1.2.3 From 7e1543c23b34fa590b636d26b94b7a8e8673569d Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 30 Jun 2007 17:32:17 +0000 Subject: ARM PL031 RTC emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3037 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/integratorcp.c | 1 + hw/pl031.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/realview.c | 4 +- hw/versatilepb.c | 3 + vl.h | 3 + 6 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 hw/pl031.c diff --git a/Makefile.target b/Makefile.target index 01d254975..67689cfef 100644 --- a/Makefile.target +++ b/Makefile.target @@ -456,7 +456,7 @@ 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 pl181.o pl190.o +VL_OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o VL_OBJS+= versatile_pci.o sd.o ptimer.o VL_OBJS+= arm_gic.o realview.o arm_sysctl.o VL_OBJS+= arm-semi.o diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 119a4402a..93d980a38 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -490,6 +490,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, cpu_pic[ARM_PIC_CPU_FIQ]); icp_pic_init(0xca000000, pic[26], NULL); icp_pit_init(0x13000000, pic, 5); + pl031_init(0x15000000, pic[8]); pl011_init(0x16000000, pic[1], serial_hds[0]); pl011_init(0x17000000, pic[2], serial_hds[1]); icp_control_init(0xcb000000); diff --git a/hw/pl031.c b/hw/pl031.c new file mode 100644 index 000000000..7e8098ba5 --- /dev/null +++ b/hw/pl031.c @@ -0,0 +1,219 @@ +/* + * ARM AMBA PrimeCell PL031 RTC + * + * Copyright (c) 2007 CodeSourcery + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include"vl.h" + +//#define DEBUG_PL031 + +#ifdef DEBUG_PL031 +#define DPRINTF(fmt, args...) \ +do { printf("pl031: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#endif + +#define RTC_DR 0x00 /* Data read register */ +#define RTC_MR 0x04 /* Match register */ +#define RTC_LR 0x08 /* Data load register */ +#define RTC_CR 0x0c /* Control register */ +#define RTC_IMSC 0x10 /* Interrupt mask and set register */ +#define RTC_RIS 0x14 /* Raw interrupt status register */ +#define RTC_MIS 0x18 /* Masked interrupt status register */ +#define RTC_ICR 0x1c /* Interrupt clear register */ + +typedef struct { + QEMUTimer *timer; + qemu_irq irq; + uint32_t base; + + uint64_t start_time; + uint32_t tick_offset; + + uint32_t mr; + uint32_t lr; + uint32_t cr; + uint32_t im; + uint32_t is; +} pl031_state; + +static const unsigned char pl031_id[] = { + 0x31, 0x10, 0x14, 0x00, /* Device ID */ + 0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */ +}; + +static void pl031_update(pl031_state *s) +{ + qemu_set_irq(s->irq, s->is & s->im); +} + +static void pl031_interrupt(void * opaque) +{ + pl031_state *s = (pl031_state *)opaque; + + s->im = 1; + DPRINTF("Alarm raised\n"); + pl031_update(s); +} + +static uint32_t pl031_get_count(pl031_state *s) +{ + /* This assumes qemu_get_clock returns the time since the machine was + created. */ + return s->tick_offset + qemu_get_clock(vm_clock) / ticks_per_sec; +} + +static void pl031_set_alarm(pl031_state *s) +{ + int64_t now; + uint32_t ticks; + + now = qemu_get_clock(vm_clock); + ticks = s->tick_offset + now / ticks_per_sec; + + /* The timer wraps around. This subtraction also wraps in the same way, + and gives correct results when alarm < now_ticks. */ + ticks = s->mr - ticks; + DPRINTF("Alarm set in %ud ticks\n", ticks); + if (ticks == 0) { + qemu_del_timer(s->timer); + pl031_interrupt(s); + } else { + qemu_mod_timer(s->timer, now + (int64_t)ticks * ticks_per_sec); + } +} + +static uint32_t pl031_read(void *opaque, target_phys_addr_t offset) +{ + pl031_state *s = (pl031_state *)opaque; + + offset -= s->base; + + if (offset >= 0xfe0 && offset < 0x1000) + return pl031_id[(offset - 0xfe0) >> 2]; + + switch (offset) { + case RTC_DR: + return pl031_get_count(s); + case RTC_MR: + return s->mr; + case RTC_IMSC: + return s->im; + case RTC_RIS: + return s->is; + case RTC_LR: + return s->lr; + case RTC_CR: + /* RTC is permanently enabled. */ + return 1; + case RTC_MIS: + return s->is & s->im; + case RTC_ICR: + fprintf(stderr, "qemu: pl031_read: Unexpected offset 0x%x\n", + (int)offset); + break; + default: + cpu_abort(cpu_single_env, "pl031_read: Bad offset 0x%x\n", + (int)offset); + break; + } + + return 0; +} + +static void pl031_write(void * opaque, target_phys_addr_t offset, + uint32_t value) +{ + pl031_state *s = (pl031_state *)opaque; + + offset -= s->base; + + switch (offset) { + case RTC_LR: + s->tick_offset += value - pl031_get_count(s); + pl031_set_alarm(s); + break; + case RTC_MR: + s->mr = value; + pl031_set_alarm(s); + break; + case RTC_IMSC: + s->im = value & 1; + DPRINTF("Interrupt mask %d\n", s->im); + pl031_update(s); + break; + case RTC_ICR: + /* The PL031 documentation (DDI0224B) states that the interupt is + cleared when bit 0 of the written value is set. However the + arm926e documentation (DDI0287B) states that the interrupt is + cleared when any value is written. */ + DPRINTF("Interrupt cleared"); + s->is = 0; + pl031_update(s); + break; + case RTC_CR: + /* Written value is ignored. */ + break; + + case RTC_DR: + case RTC_MIS: + case RTC_RIS: + fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n", + (int)offset); + break; + + default: + cpu_abort(cpu_single_env, "pl031_write: Bad offset 0x%x\n", + (int)offset); + break; + } +} + +static CPUWriteMemoryFunc * pl031_writefn[] = { + pl031_write, + pl031_write, + pl031_write +}; + +static CPUReadMemoryFunc * pl031_readfn[] = { + pl031_read, + pl031_read, + pl031_read +}; + +void pl031_init(uint32_t base, qemu_irq irq) +{ + int iomemtype; + pl031_state *s; + time_t ti; + struct tm *tm; + + s = qemu_mallocz(sizeof(pl031_state)); + if (!s) + cpu_abort(cpu_single_env, "pl031_init: Out of memory\n"); + + iomemtype = cpu_register_io_memory(0, pl031_readfn, pl031_writefn, s); + if (iomemtype == -1) + cpu_abort(cpu_single_env, "pl031_init: Can't register I/O memory\n"); + + cpu_register_physical_memory(base, 0x00001000, iomemtype); + + s->base = base; + s->irq = irq; + /* ??? We assume vm_clock is zero at this point. */ + time(&ti); + if (rtc_utc) + tm = gmtime(&ti); + else + tm = localtime(&ti); + s->tick_offset = mktime(tm); + + s->timer = qemu_new_timer(vm_clock, pl031_interrupt, s); +} diff --git a/hw/realview.c b/hw/realview.c index 4f4858990..1ca02d5e2 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -57,6 +57,8 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, pl181_init(0x10005000, sd_bdrv, pic[17], pic[18]); + pl031_init(0x10017000, pic[10]); + pci_bus = pci_vpb_init(pic, 48, 1); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); @@ -102,7 +104,7 @@ static void realview_init(int ram_size, int vga_ram_size, int boot_device, /* 0x10014000 GPIO 1. */ /* 0x10015000 GPIO 2. */ /* 0x10016000 Reserved. */ - /* 0x10017000 RTC. */ + /* 0x10017000 RTC. */ /* 0x10018000 DMC. */ /* 0x10019000 PCI controller config. */ /* 0x10020000 CLCD. */ diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 1cbd25b18..f0142adc5 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -223,6 +223,9 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, pl181_init(0x1000b000, NULL, sic, 23, 2); #endif + /* Add PL031 Real Time Clock. */ + pl031_init(0x101e8000,pic[10]); + /* Memory map for Versatile/PB: */ /* 0x10000000 System registers. */ /* 0x10001000 PCI controller config registers. */ diff --git a/vl.h b/vl.h index 4a072a90a..85014cd15 100644 --- a/vl.h +++ b/vl.h @@ -1429,6 +1429,9 @@ void ps2_mouse_fake_event(void *opaque); /* smc91c111.c */ void smc91c111_init(NICInfo *, uint32_t, qemu_irq); +/* pl031.c */ +void pl031_init(uint32_t base, qemu_irq irq); + /* pl110.c */ void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int); -- cgit v1.2.3 From 11fcfab4b0d7349aa3b00e3205f3b0805396b680 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 1 Jul 2007 18:21:11 +0000 Subject: Fix bogus fopen mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3038 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 5ed63de68..4ccee2246 100644 --- a/exec.c +++ b/exec.c @@ -1161,7 +1161,7 @@ void cpu_set_log(int log_flags) { loglevel = log_flags; if (loglevel && !logfile) { - logfile = fopen(logfilename, log_append ? "wa" : "w"); + logfile = fopen(logfilename, log_append ? "a" : "w"); if (!logfile) { perror(logfilename); _exit(1); -- cgit v1.2.3 From 45669e0048cfbb99f07fe35270a5dbc7d7ad5cd6 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 2 Jul 2007 13:20:17 +0000 Subject: gdb stub support and loadvm should work together, patch by Jason Wessel git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3039 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 78c8babc6..c556aa60d 100644 --- a/vl.c +++ b/vl.c @@ -8011,8 +8011,9 @@ int main(int argc, char **argv) gdbstub_port); exit(1); } - } else + } #endif + if (loadvm) do_loadvm(loadvm); -- cgit v1.2.3 From fbd1711dac75e19b2ec316aa094d064826ff7408 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 2 Jul 2007 13:31:53 +0000 Subject: Fix qemu_can_send_packet(), makes DHCP with multiple nics work - patch by Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3040 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index c556aa60d..1539908d3 100644 --- a/vl.c +++ b/vl.c @@ -3195,11 +3195,11 @@ int qemu_can_send_packet(VLANClientState *vc1) for(vc = vlan->first_client; vc != NULL; vc = vc->next) { if (vc != vc1) { - if (vc->fd_can_read && !vc->fd_can_read(vc->opaque)) - return 0; + if (vc->fd_can_read && vc->fd_can_read(vc->opaque)) + return 1; } } - return 1; + return 0; } void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) -- cgit v1.2.3 From 2657c6633280f6ed9b1b5e75a6c60f069b39f702 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 2 Jul 2007 13:38:46 +0000 Subject: E100 savevm/loadvm support, patch by Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3041 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/eepro100.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index bb570675a..c39d36483 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1571,10 +1571,9 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size) static int nic_load(QEMUFile * f, void *opaque, int version_id) { EEPRO100State *s = (EEPRO100State *) opaque; + int i; int ret; - missing("NIC load"); - if (version_id > 3) return -EINVAL; @@ -1608,14 +1607,61 @@ static int nic_load(QEMUFile * f, void *opaque, int version_id) qemu_get_buffer(f, s->mult, 8); qemu_get_buffer(f, s->mem, sizeof(s->mem)); + /* Restore all members of struct between scv_stat and mem */ + qemu_get_8s(f, &s->scb_stat); + qemu_get_8s(f, &s->int_stat); + for (i = 0; i < 3; i++) + qemu_get_be32s(f, &s->region[i]); + qemu_get_buffer(f, s->macaddr, 6); + for (i = 0; i < 19; i++) + qemu_get_be32s(f, &s->statcounter[i]); + for (i = 0; i < 32; i++) + qemu_get_be16s(f, &s->mdimem[i]); + /* The eeprom should be saved and restored by its own routines */ + qemu_get_be32s(f, &s->device); + qemu_get_be32s(f, &s->pointer); + qemu_get_be32s(f, &s->cu_base); + qemu_get_be32s(f, &s->cu_offset); + qemu_get_be32s(f, &s->ru_base); + qemu_get_be32s(f, &s->ru_offset); + qemu_get_be32s(f, &s->statsaddr); + /* Restore epro100_stats_t statistics */ + qemu_get_be32s(f, &s->statistics.tx_good_frames); + qemu_get_be32s(f, &s->statistics.tx_max_collisions); + qemu_get_be32s(f, &s->statistics.tx_late_collisions); + qemu_get_be32s(f, &s->statistics.tx_underruns); + qemu_get_be32s(f, &s->statistics.tx_lost_crs); + qemu_get_be32s(f, &s->statistics.tx_deferred); + qemu_get_be32s(f, &s->statistics.tx_single_collisions); + qemu_get_be32s(f, &s->statistics.tx_multiple_collisions); + qemu_get_be32s(f, &s->statistics.tx_total_collisions); + qemu_get_be32s(f, &s->statistics.rx_good_frames); + qemu_get_be32s(f, &s->statistics.rx_crc_errors); + qemu_get_be32s(f, &s->statistics.rx_alignment_errors); + qemu_get_be32s(f, &s->statistics.rx_resource_errors); + qemu_get_be32s(f, &s->statistics.rx_overrun_errors); + qemu_get_be32s(f, &s->statistics.rx_cdt_errors); + qemu_get_be32s(f, &s->statistics.rx_short_frame_errors); + qemu_get_be32s(f, &s->statistics.fc_xmt_pause); + qemu_get_be32s(f, &s->statistics.fc_rcv_pause); + qemu_get_be32s(f, &s->statistics.fc_rcv_unsupported); + qemu_get_be16s(f, &s->statistics.xmt_tco_frames); + qemu_get_be16s(f, &s->statistics.rcv_tco_frames); + qemu_get_be32s(f, &s->statistics.complete); +#if 0 + qemu_get_be16s(f, &s->status); +#endif + + /* Configuration bytes. */ + qemu_get_buffer(f, s->configuration, sizeof(s->configuration)); + return 0; } static void nic_save(QEMUFile * f, void *opaque) { EEPRO100State *s = (EEPRO100State *) opaque; - - missing("NIC save"); + int i; if (s->pci_dev) pci_device_save(s->pci_dev, f); @@ -1639,6 +1685,54 @@ static void nic_save(QEMUFile * f, void *opaque) qemu_put_8s(f, &s->curpag); qemu_put_buffer(f, s->mult, 8); qemu_put_buffer(f, s->mem, sizeof(s->mem)); + + /* Save all members of struct between scv_stat and mem */ + qemu_put_8s(f, &s->scb_stat); + qemu_put_8s(f, &s->int_stat); + for (i = 0; i < 3; i++) + qemu_put_be32s(f, &s->region[i]); + qemu_put_buffer(f, s->macaddr, 6); + for (i = 0; i < 19; i++) + qemu_put_be32s(f, &s->statcounter[i]); + for (i = 0; i < 32; i++) + qemu_put_be16s(f, &s->mdimem[i]); + /* The eeprom should be saved and restored by its own routines */ + qemu_put_be32s(f, &s->device); + qemu_put_be32s(f, &s->pointer); + qemu_put_be32s(f, &s->cu_base); + qemu_put_be32s(f, &s->cu_offset); + qemu_put_be32s(f, &s->ru_base); + qemu_put_be32s(f, &s->ru_offset); + qemu_put_be32s(f, &s->statsaddr); + /* Save epro100_stats_t statistics */ + qemu_put_be32s(f, &s->statistics.tx_good_frames); + qemu_put_be32s(f, &s->statistics.tx_max_collisions); + qemu_put_be32s(f, &s->statistics.tx_late_collisions); + qemu_put_be32s(f, &s->statistics.tx_underruns); + qemu_put_be32s(f, &s->statistics.tx_lost_crs); + qemu_put_be32s(f, &s->statistics.tx_deferred); + qemu_put_be32s(f, &s->statistics.tx_single_collisions); + qemu_put_be32s(f, &s->statistics.tx_multiple_collisions); + qemu_put_be32s(f, &s->statistics.tx_total_collisions); + qemu_put_be32s(f, &s->statistics.rx_good_frames); + qemu_put_be32s(f, &s->statistics.rx_crc_errors); + qemu_put_be32s(f, &s->statistics.rx_alignment_errors); + qemu_put_be32s(f, &s->statistics.rx_resource_errors); + qemu_put_be32s(f, &s->statistics.rx_overrun_errors); + qemu_put_be32s(f, &s->statistics.rx_cdt_errors); + qemu_put_be32s(f, &s->statistics.rx_short_frame_errors); + qemu_put_be32s(f, &s->statistics.fc_xmt_pause); + qemu_put_be32s(f, &s->statistics.fc_rcv_pause); + qemu_put_be32s(f, &s->statistics.fc_rcv_unsupported); + qemu_put_be16s(f, &s->statistics.xmt_tco_frames); + qemu_put_be16s(f, &s->statistics.rcv_tco_frames); + qemu_put_be32s(f, &s->statistics.complete); +#if 0 + qemu_put_be16s(f, &s->status); +#endif + + /* Configuration bytes. */ + qemu_put_buffer(f, s->configuration, sizeof(s->configuration)); } static void nic_init(PCIBus * bus, NICInfo * nd, -- cgit v1.2.3 From 6d8aa3bfed71ef1a09290e9bcdf741e37e9f7a06 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 2 Jul 2007 14:06:26 +0000 Subject: Remove unaligned accesses in ia64_apply_fixes(). Make sure that the static variables are not optimized away in GOTO_TB. (patch by Andreas Schwab) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3042 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.h | 11 ++++++----- exec-all.h | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dyngen.h b/dyngen.h index 48e40192c..86dd3d619 100644 --- a/dyngen.h +++ b/dyngen.h @@ -392,7 +392,8 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp, 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; + uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start; + uint64_t *vp; struct ia64_fixup *fixup; unsigned int offset = 0; struct fdesc { @@ -429,12 +430,12 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp, /* 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) + for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp) + if (*vp == fixup->value) break; - if (vp == gen_code_ptr) { + if (vp == (uint64_t *) gen_code_ptr) { /* Nope, we need to put the value in the GOT: */ - *(uint64_t *) vp = fixup->value; + *vp = fixup->value; gen_code_ptr += 8; } ia64_imm22(fixup->addr, (long) vp - gp); diff --git a/exec-all.h b/exec-all.h index dbfe45761..8ea057b79 100644 --- a/exec-all.h +++ b/exec-all.h @@ -346,8 +346,8 @@ do {\ cache flushing, but slower because of indirect jump) */ #define GOTO_TB(opname, tbparam, n)\ do {\ - static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\ - static void __attribute__((unused)) *__op_label ## n \ + static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\ + static void __attribute__((used)) *__op_label ## n \ __asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\ goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ label ## n: ;\ -- cgit v1.2.3 From aeb30be60a92148e38d47f79b6f566a47a8a6cbd Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 2 Jul 2007 15:03:13 +0000 Subject: Retry interrupted open() calls (proposed by Yigael Felishman). Linux open(2) doesn't list EINTR, but FreeBSD's open(2) does. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3043 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/vl.c b/vl.c index 1539908d3..0d059f40f 100644 --- a/vl.c +++ b/vl.c @@ -204,6 +204,8 @@ unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; #endif +#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) + /***********************************************************/ /* x86 ISA bus support */ @@ -1029,7 +1031,7 @@ static int rtc_fd; static int start_rtc_timer(void) { - rtc_fd = open("/dev/rtc", O_RDONLY); + TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); if (rtc_fd < 0) return -1; if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { @@ -1640,7 +1642,7 @@ static CharDriverState *qemu_chr_open_file_out(const char *file_out) { int fd_out; - fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666); + TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); if (fd_out < 0) return NULL; return qemu_chr_open_fd(-1, fd_out); @@ -1653,14 +1655,14 @@ static CharDriverState *qemu_chr_open_pipe(const char *filename) snprintf(filename_in, 256, "%s.in", filename); snprintf(filename_out, 256, "%s.out", filename); - fd_in = open(filename_in, O_RDWR | O_BINARY); - fd_out = open(filename_out, O_RDWR | O_BINARY); + TFR(fd_in = open(filename_in, O_RDWR | O_BINARY)); + TFR(fd_out = open(filename_out, O_RDWR | O_BINARY)); if (fd_in < 0 || fd_out < 0) { if (fd_in >= 0) close(fd_in); if (fd_out >= 0) close(fd_out); - fd_in = fd_out = open(filename, O_RDWR | O_BINARY); + TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY)); if (fd_in < 0) return NULL; } @@ -1911,14 +1913,14 @@ static CharDriverState *qemu_chr_open_tty(const char *filename) CharDriverState *chr; int fd; - fd = open(filename, O_RDWR | O_NONBLOCK); - if (fd < 0) - return NULL; + TFR(fd = open(filename, O_RDWR | O_NONBLOCK)); fcntl(fd, F_SETFL, O_NONBLOCK); tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd); - if (!chr) + if (!chr) { + close(fd); return NULL; + } chr->chr_ioctl = tty_serial_ioctl; qemu_chr_reset(chr); return chr; @@ -2041,7 +2043,7 @@ static CharDriverState *qemu_chr_open_pp(const char *filename) ParallelCharDriver *drv; int fd; - fd = open(filename, O_RDWR); + TFR(fd = open(filename, O_RDWR)); if (fd < 0) return NULL; @@ -3463,7 +3465,7 @@ static int tap_open(char *ifname, int ifname_size) char *dev; struct stat s; - fd = open("/dev/tap", O_RDWR); + TFR(fd = open("/dev/tap", O_RDWR)); if (fd < 0) { fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n"); return -1; @@ -3507,12 +3509,14 @@ int tap_alloc(char *dev) if( ip_fd ) close(ip_fd); - if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){ + TFR(ip_fd = open("/dev/udp", O_RDWR, 0)); + if (ip_fd < 0) { syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)"); return -1; } - if( (tap_fd = open("/dev/tap", O_RDWR, 0)) < 0){ + TFR(tap_fd = open("/dev/tap", O_RDWR, 0)); + if (tap_fd < 0) { syslog(LOG_ERR, "Can't open /dev/tap"); return -1; } @@ -3525,7 +3529,8 @@ int tap_alloc(char *dev) if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) syslog (LOG_ERR, "Can't assign new interface"); - if( (if_fd = open("/dev/tap", O_RDWR, 0)) < 0){ + TFR(if_fd = open("/dev/tap", O_RDWR, 0)); + if (if_fd < 0) { syslog(LOG_ERR, "Can't open /dev/tap (2)"); return -1; } @@ -3557,7 +3562,8 @@ int tap_alloc(char *dev) if (ioctl (ip_fd, I_PUSH, "arp") < 0) syslog (LOG_ERR, "Can't push ARP module (3)\n"); /* Open arp_fd */ - if ((arp_fd = open ("/dev/tap", O_RDWR, 0)) < 0) + TFR(arp_fd = open ("/dev/tap", O_RDWR, 0)); + if (arp_fd < 0) syslog (LOG_ERR, "Can't open %s\n", "/dev/tap"); /* Set ifname to arp */ @@ -3613,7 +3619,7 @@ static int tap_open(char *ifname, int ifname_size) struct ifreq ifr; int fd, ret; - fd = open("/dev/net/tun", O_RDWR); + TFR(fd = open("/dev/net/tun", O_RDWR)); if (fd < 0) { fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); return -1; @@ -3649,7 +3655,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, pstrcpy(ifname, sizeof(ifname), ifname1); else ifname[0] = '\0'; - fd = tap_open(ifname, sizeof(ifname)); + TFR(fd = tap_open(ifname, sizeof(ifname))); if (fd < 0) return -1; @@ -8038,7 +8044,7 @@ int main(int argc, char **argv) if (len != 1) exit(1); - fd = open("/dev/null", O_RDWR); + TFR(fd = open("/dev/null", O_RDWR)); if (fd == -1) exit(1); -- cgit v1.2.3 From fda77c2d65d15ed35b01f60be37a17e2cd83bfe3 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 3 Jul 2007 09:55:03 +0000 Subject: Fix loadvm git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3044 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 2 +- hw/tcx.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/iommu.c b/hw/iommu.c index 082451f98..77d8b817e 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -259,7 +259,7 @@ static int iommu_load(QEMUFile *f, void *opaque, int version_id) return -EINVAL; for (i = 0; i < IOMMU_NREGS; i++) - qemu_put_be32s(f, &s->regs[i]); + qemu_get_be32s(f, &s->regs[i]); qemu_get_be64s(f, &s->iostart); return 0; diff --git a/hw/tcx.c b/hw/tcx.c index 10ae987fc..c334f0923 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -354,9 +354,6 @@ static void tcx_save(QEMUFile *f, void *opaque) { TCXState *s = opaque; - qemu_put_be32s(f, (uint32_t *)&s->vram); - qemu_put_be32s(f, (uint32_t *)&s->vram24); - qemu_put_be32s(f, (uint32_t *)&s->cplane); qemu_put_be16s(f, (uint16_t *)&s->height); qemu_put_be16s(f, (uint16_t *)&s->width); qemu_put_be16s(f, (uint16_t *)&s->depth); @@ -370,13 +367,16 @@ static void tcx_save(QEMUFile *f, void *opaque) static int tcx_load(QEMUFile *f, void *opaque, int version_id) { TCXState *s = opaque; - - if (version_id != 3) + uint32_t dummy; + + if (version_id != 3 && version_id != 4) return -EINVAL; - qemu_get_be32s(f, (uint32_t *)&s->vram); - qemu_get_be32s(f, (uint32_t *)&s->vram24); - qemu_get_be32s(f, (uint32_t *)&s->cplane); + if (version_id == 3) { + qemu_get_be32s(f, (uint32_t *)&dummy); + qemu_get_be32s(f, (uint32_t *)&dummy); + qemu_get_be32s(f, (uint32_t *)&dummy); + } qemu_get_be16s(f, (uint16_t *)&s->height); qemu_get_be16s(f, (uint16_t *)&s->width); qemu_get_be16s(f, (uint16_t *)&s->depth); @@ -546,7 +546,7 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24, dummy_memory); - register_savevm("tcx", addr, 3, tcx_save, tcx_load, s); + register_savevm("tcx", addr, 4, tcx_save, tcx_load, s); qemu_register_reset(tcx_reset, s); tcx_reset(s); dpy_resize(s->ds, width, height); -- cgit v1.2.3 From 46d38ba89d37561a6fbf58a7ff567d0931b7c602 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 4 Jul 2007 20:22:35 +0000 Subject: Fix Sparc64 movr git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3045 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 110b804c7..c69ffd9af 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -84,7 +84,7 @@ enum { GET_FIELD(X, 31 - (TO), 31 - (FROM)) #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) -#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), 32 - ((b) - (a) + 1)) +#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1)) #ifdef TARGET_SPARC64 #define DFPREG(r) (((r & 1) << 6) | (r & 0x1e)) @@ -2226,7 +2226,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T0(rs1); gen_cond_reg(cond); if (IS_IMM) { /* immediate */ - rs2 = GET_FIELD_SPs(insn, 0, 10); + rs2 = GET_FIELD_SPs(insn, 0, 9); gen_movl_simm_T1(rs2); } else { -- cgit v1.2.3 From 0774bed18046c4f01a2cd64185d57b57fc06fb2f Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 5 Jul 2007 13:23:29 +0000 Subject: Fix 64 bit ELF file symbol lookup git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3046 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index f844eff50..2a7bd703c 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -893,6 +893,11 @@ static void load_symbols(struct elfhdr *hdr, int fd) struct elf_shdr sechdr, symtab, strtab; char *strings; struct syminfo *s; +#if (ELF_CLASS == ELFCLASS64) + // Disas uses 32 bit symbols + struct elf32_sym *syms32 = NULL; + struct elf_sym *sym; +#endif lseek(fd, hdr->e_shoff, SEEK_SET); for (i = 0; i < hdr->e_shnum; i++) { @@ -920,6 +925,10 @@ static void load_symbols(struct elfhdr *hdr, int fd) /* Now know where the strtab and symtab are. Snarf them. */ s = malloc(sizeof(*s)); s->disas_symtab = malloc(symtab.sh_size); +#if (ELF_CLASS == ELFCLASS64) + syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym) + * sizeof(struct elf32_sym)); +#endif s->disas_strtab = strings = malloc(strtab.sh_size); if (!s->disas_symtab || !s->disas_strtab) return; @@ -928,11 +937,25 @@ static void load_symbols(struct elfhdr *hdr, int fd) if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) return; + for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) { #ifdef BSWAP_NEEDED - for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); #endif +#if (ELF_CLASS == ELFCLASS64) + sym = s->disas_symtab + sizeof(struct elf_sym)*i; + syms32[i].st_name = sym->st_name; + syms32[i].st_info = sym->st_info; + syms32[i].st_other = sym->st_other; + syms32[i].st_shndx = sym->st_shndx; + syms32[i].st_value = sym->st_value & 0xffffffff; + syms32[i].st_size = sym->st_size & 0xffffffff; +#endif + } +#if (ELF_CLASS == ELFCLASS64) + free(s->disas_symtab); + s->disas_symtab = syms32; +#endif lseek(fd, strtab.sh_offset, SEEK_SET); if (read(fd, strings, strtab.sh_size) != strtab.sh_size) return; -- cgit v1.2.3 From 33b3780262ce300ea5fdd16a62a7661455af05f1 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 7 Jul 2007 20:44:35 +0000 Subject: Fix Sparc64 page size git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3047 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 9229ad4a7..7fbc19d14 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -10,7 +10,7 @@ #else #define TARGET_LONG_BITS 64 #define TARGET_FPREGS 64 -#define TARGET_PAGE_BITS 12 /* XXX */ +#define TARGET_PAGE_BITS 13 /* 8k */ #endif #define TARGET_PHYS_ADDR_BITS 64 -- cgit v1.2.3 From 4c1de73d15a31336366d9d38249611956a4e2803 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 7 Jul 2007 20:45:44 +0000 Subject: Page align brk result like real Linux git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3048 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9ee735231..6cad6d92f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -308,7 +308,7 @@ static target_ulong target_original_brk; void target_set_brk(target_ulong new_brk) { - target_original_brk = target_brk = new_brk; + target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); } long do_brk(target_ulong new_brk) -- cgit v1.2.3 From 7f84a7291b19aa5679ef58fdad0a81df4b8a6af0 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 7 Jul 2007 20:46:41 +0000 Subject: Deliver page faults to program git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3049 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 8d24a1fc1..32fa43d47 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -620,7 +620,20 @@ void cpu_loop (CPUSPARCState *env) case TT_FILL: /* window underflow */ restore_window(env); break; - // XXX + case TT_TFAULT: + case TT_DFAULT: + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + if (trapnr == TT_DFAULT) + info._sifields._sigfault._addr = env->dmmuregs[4]; + else + info._sifields._sigfault._addr = env->tpc[env->tl]; + queue_signal(info.si_signo, &info); + } + break; #endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ -- cgit v1.2.3 From 6ef905f69cbeb03e8fe204d8aaa354d77f13a7d7 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 7 Jul 2007 20:48:42 +0000 Subject: Fix wrong number of clean/saveable windows, match Linux startup register values git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3050 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 1 + target-sparc/translate.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 7fbc19d14..a3d762f7f 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -89,6 +89,7 @@ #if defined(TARGET_SPARC64) #define PS_IG (1<<11) #define PS_MG (1<<10) +#define PS_RMO (1<<7) #define PS_RED (1<<5) #define PS_PEF (1<<4) #define PS_AM (1<<3) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index c69ffd9af..a2f3d5bd3 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3315,8 +3315,10 @@ void cpu_reset(CPUSPARCState *env) #if defined(CONFIG_USER_ONLY) env->user_mode_only = 1; #ifdef TARGET_SPARC64 - env->cleanwin = NWINDOWS - 1; - env->cansave = NWINDOWS - 1; + env->cleanwin = NWINDOWS - 2; + env->cansave = NWINDOWS - 2; + env->pstate = PS_RMO | PS_PEF | PS_IE; + env->asi = 0x82; // Primary no-fault #endif #else env->psret = 0; -- cgit v1.2.3 From dc011987f266878ad29009e4fdbc27f666ab31d2 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 7 Jul 2007 20:50:33 +0000 Subject: Use unsigned 32-bit load for ld/lduw git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3051 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_mem.h | 5 +++++ target-sparc/translate.c | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index f5dbd2605..a175d0d59 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -103,6 +103,11 @@ void OPPROTO glue(op_casx, MEMSUFFIX)(void) T2 = tmp; } +void OPPROTO glue(op_lduw, MEMSUFFIX)(void) +{ + T1 = (uint64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff); +} + void OPPROTO glue(op_ldsw, MEMSUFFIX)(void) { T1 = (int64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index a2f3d5bd3..074ed21fd 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -470,6 +470,7 @@ OP_LD_TABLE(ldf); OP_LD_TABLE(lddf); #ifdef TARGET_SPARC64 +OP_LD_TABLE(lduw); OP_LD_TABLE(ldsw); OP_LD_TABLE(ldx); OP_LD_TABLE(stx); @@ -2810,7 +2811,11 @@ static void disas_sparc_insn(DisasContext * dc) (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) { switch (xop) { case 0x0: /* load word */ +#ifndef TARGET_SPARC64 gen_op_ldst(ld); +#else + gen_op_ldst(lduw); +#endif break; case 0x1: /* load unsigned byte */ gen_op_ldst(ldub); @@ -2844,8 +2849,10 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#endif gen_op_lda(insn, 1, 4, 0); +#else + gen_op_lduwa(insn, 1, 4, 0); +#endif break; case 0x11: /* load unsigned byte alternate */ #ifndef TARGET_SPARC64 @@ -2926,6 +2933,7 @@ static void disas_sparc_insn(DisasContext * dc) (void) &gen_op_ldfa; (void) &gen_op_lddfa; #else + (void) &gen_op_lda; #if !defined(CONFIG_USER_ONLY) (void) &gen_op_cas; (void) &gen_op_casx; -- cgit v1.2.3 From 17d996e1f1de8057b3bb88b753e65735a6d8f191 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 7 Jul 2007 20:53:22 +0000 Subject: Report normalised CWP values to userland and GDB, not internal representation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3052 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 14 ++++++++++++-- target-sparc/cpu.h | 10 ++++++++-- target-sparc/op.c | 4 ++-- target-sparc/op_helper.c | 6 +++--- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 2ec2f33f8..06cf30200 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -383,7 +383,10 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) } registers[64] = tswapl(env->pc); registers[65] = tswapl(env->npc); - registers[66] = tswapl(env->tstate[env->tl]); + registers[66] = tswapl(((uint64_t)GET_CCR(env) << 32) | + ((env->asi & 0xff) << 24) | + ((env->pstate & 0xfff) << 8) | + GET_CWP64(env)); registers[67] = tswapl(env->fsr); registers[68] = tswapl(env->fprs); registers[69] = tswapl(env->y); @@ -427,7 +430,14 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } env->pc = tswapl(registers[64]); env->npc = tswapl(registers[65]); - env->tstate[env->tl] = tswapl(registers[66]); + { + uint64_t tmp = tswapl(registers[66]); + + PUT_CCR(env, tmp >> 32); + env->asi = (tmp >> 24) & 0xff; + env->pstate = (tmp >> 8) & 0xfff; + PUT_CWP64(env, tmp & 0xff); + } env->fsr = tswapl(registers[67]); env->fprs = tswapl(registers[68]); env->y = tswapl(registers[69]); diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index a3d762f7f..06b5865e2 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -288,11 +288,17 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); } while (0) #ifdef TARGET_SPARC64 -#define GET_CCR(env) ((env->xcc << 4) | (env->psr & PSR_ICC)) +#define GET_CCR(env) (((env->xcc >> 20) << 4) | ((env->psr & PSR_ICC) >> 20)) #define PUT_CCR(env, val) do { int _tmp = val; \ - env->xcc = _tmp >> 4; \ + env->xcc = (_tmp >> 4) << 20; \ env->psr = (_tmp & 0xf) << 20; \ } while (0) +#define GET_CWP64(env) (NWINDOWS - 1 - (env)->cwp) +#define PUT_CWP64(env, val) do { \ + env->cwp = NWINDOWS - 1 - ((val) & 0xff); \ + cpu_set_cwp(env, env->cwp); \ + } while(0) + #endif int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); diff --git a/target-sparc/op.c b/target-sparc/op.c index c0aee8f4a..4ab066779 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1184,12 +1184,12 @@ void OPPROTO op_wrpstate(void) // order. void OPPROTO op_rdcwp(void) { - T0 = NWINDOWS - 1 - env->cwp; + T0 = GET_CWP64(env); } void OPPROTO op_wrcwp(void) { - env->cwp = NWINDOWS - 1 - T0; + PUT_CWP64(env, T0); } /* XXX: use another pointer for %iN registers to avoid slow wrapping diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 11134cf12..cd9372716 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -871,7 +871,7 @@ void do_done(void) PUT_CCR(env, env->tstate[env->tl] >> 32); env->asi = (env->tstate[env->tl] >> 24) & 0xff; env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; - set_cwp(env->tstate[env->tl] & 0xff); + PUT_CWP64(env, env->tstate[env->tl] & 0xff); } void do_retry(void) @@ -882,7 +882,7 @@ void do_retry(void) PUT_CCR(env, env->tstate[env->tl] >> 32); env->asi = (env->tstate[env->tl] >> 24) & 0xff; env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; - set_cwp(env->tstate[env->tl] & 0xff); + PUT_CWP64(env, env->tstate[env->tl] & 0xff); } #endif @@ -952,7 +952,7 @@ void do_interrupt(int intno) } #endif env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | - ((env->pstate & 0xfff) << 8) | (env->cwp & 0xff); + ((env->pstate & 0xfff) << 8) | GET_CWP64(env); env->tpc[env->tl] = env->pc; env->tnpc[env->tl] = env->npc; env->tt[env->tl] = intno; -- cgit v1.2.3 From 1b8dd648bdccefa8ba1b05416e65e9b3a278b0e6 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 8 Jul 2007 10:08:24 +0000 Subject: Fix Sparc64 stat system call git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3053 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 9 ++++++++- linux-user/syscall_defs.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6cad6d92f..52806bb20 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3535,7 +3535,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct target_stat *target_st; lock_user_struct(target_st, arg2, 0); -#if defined(TARGET_MIPS) +#if defined(TARGET_MIPS) || defined(TARGET_SPARC64) target_st->st_dev = tswap32(st.st_dev); #else target_st->st_dev = tswap16(st.st_dev); @@ -3545,6 +3545,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */ target_st->st_uid = tswap32(st.st_uid); target_st->st_gid = tswap32(st.st_gid); +#elif defined(TARGET_SPARC64) + target_st->st_mode = tswap32(st.st_mode); + target_st->st_uid = tswap32(st.st_uid); + target_st->st_gid = tswap32(st.st_gid); #else target_st->st_mode = tswap16(st.st_mode); target_st->st_uid = tswap16(st.st_uid); @@ -3554,6 +3558,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, /* If this is the same on PPC, then just merge w/ the above ifdef */ target_st->st_nlink = tswapl(st.st_nlink); target_st->st_rdev = tswapl(st.st_rdev); +#elif defined(TARGET_SPARC64) + target_st->st_nlink = tswap32(st.st_nlink); + target_st->st_rdev = tswap32(st.st_rdev); #else target_st->st_nlink = tswap16(st.st_nlink); target_st->st_rdev = tswap16(st.st_rdev); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 0e39a2e77..7b4122fed 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -962,6 +962,57 @@ struct target_eabi_stat64 { } __attribute__ ((packed)); #endif +#elif defined(TARGET_SPARC64) +struct target_stat { + unsigned int st_dev; + target_ulong st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned int st_rdev; + target_long st_size; + target_long target_st_atime; + target_long target_st_mtime; + target_long target_st_ctime; + target_long st_blksize; + target_long st_blocks; + target_ulong __unused4[2]; +}; + +struct target_stat64 { + unsigned char __pad0[6]; + unsigned short st_dev; + + uint64_t st_ino; + uint64_t st_nlink; + + unsigned int st_mode; + + unsigned int st_uid; + unsigned int st_gid; + + unsigned char __pad2[6]; + unsigned short st_rdev; + + int64_t st_size; + int64_t st_blksize; + + unsigned char __pad4[4]; + unsigned int st_blocks; + + target_ulong target_st_atime; + target_ulong __unused1; + + target_ulong target_st_mtime; + target_ulong __unused2; + + target_ulong target_st_ctime; + target_ulong __unused3; + + target_ulong __unused4[3]; +}; + #elif defined(TARGET_SPARC) struct target_stat { -- cgit v1.2.3 From 1ad21e69696d585f0cf70e3207f74757fe296b92 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 8 Jul 2007 19:48:40 +0000 Subject: Save state in Sparc64 return op git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3054 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 074ed21fd..3c183c6d5 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2651,6 +2651,7 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef TARGET_SPARC64 } else if (xop == 0x39) { /* V9 return */ rs1 = GET_FIELD(insn, 13, 17); + save_state(dc); gen_movl_reg_T0(rs1); if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); -- cgit v1.2.3 From 8f1f22f6abc7af1e5ecc8d83698514999e0284e4 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 8 Jul 2007 19:51:24 +0000 Subject: Fix retry and done ops, trap handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3055 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 6 ++---- target-sparc/op_helper.c | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 06b5865e2..600b37ba5 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -294,10 +294,8 @@ void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); env->psr = (_tmp & 0xf) << 20; \ } while (0) #define GET_CWP64(env) (NWINDOWS - 1 - (env)->cwp) -#define PUT_CWP64(env, val) do { \ - env->cwp = NWINDOWS - 1 - ((val) & 0xff); \ - cpu_set_cwp(env, env->cwp); \ - } while(0) +#define PUT_CWP64(env, val) \ + cpu_set_cwp(env, NWINDOWS - 1 - ((val) & (NWINDOWS - 1))) #endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index cd9372716..21b1178a9 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -845,12 +845,11 @@ static inline uint64_t *get_gregset(uint64_t pstate) } } -void do_wrpstate() +static inline void change_pstate(uint64_t new_pstate) { - uint64_t new_pstate, pstate_regs, new_pstate_regs; + uint64_t pstate_regs, new_pstate_regs; uint64_t *src, *dst; - new_pstate = T0 & 0xf3f; pstate_regs = env->pstate & 0xc01; new_pstate_regs = new_pstate & 0xc01; if (new_pstate_regs != pstate_regs) { @@ -863,6 +862,11 @@ void do_wrpstate() env->pstate = new_pstate; } +void do_wrpstate(void) +{ + change_pstate(T0 & 0xf3f); +} + void do_done(void) { env->tl--; @@ -870,7 +874,7 @@ void do_done(void) env->npc = env->tnpc[env->tl] + 4; PUT_CCR(env, env->tstate[env->tl] >> 32); env->asi = (env->tstate[env->tl] >> 24) & 0xff; - env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; + change_pstate((env->tstate[env->tl] >> 8) & 0xf3f); PUT_CWP64(env, env->tstate[env->tl] & 0xff); } @@ -881,7 +885,7 @@ void do_retry(void) env->npc = env->tnpc[env->tl]; PUT_CCR(env, env->tstate[env->tl] >> 32); env->asi = (env->tstate[env->tl] >> 24) & 0xff; - env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; + change_pstate((env->tstate[env->tl] >> 8) & 0xf3f); PUT_CWP64(env, env->tstate[env->tl] & 0xff); } #endif @@ -952,11 +956,18 @@ void do_interrupt(int intno) } #endif env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | - ((env->pstate & 0xfff) << 8) | GET_CWP64(env); + ((env->pstate & 0xf3f) << 8) | GET_CWP64(env); env->tpc[env->tl] = env->pc; env->tnpc[env->tl] = env->npc; env->tt[env->tl] = intno; - env->pstate = PS_PEF | PS_PRIV | PS_AG; + change_pstate(PS_PEF | PS_PRIV | PS_AG); + + if (intno == TT_CLRWIN) + set_cwp((env->cwp - 1) & (NWINDOWS - 1)); + else if ((intno & 0x1c0) == TT_SPILL) + set_cwp((env->cwp - env->cansave - 2) & (NWINDOWS - 1)); + else if ((intno & 0x1c0) == TT_FILL) + set_cwp((env->cwp + 1) & (NWINDOWS - 1)); env->tbr &= ~0x7fffULL; env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); if (env->tl < MAXTL - 1) { -- cgit v1.2.3 From 24d4de45c22170ff2ce3eaad9bf88e0dac3e9c57 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 10:24:28 +0000 Subject: Documentation update for MIPS. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3056 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 80 ++++++++++++++++++++++++++++++++++++++++++++-------------- qemu-tech.texi | 26 +++++++++++++++++++ 2 files changed, 87 insertions(+), 19 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index cc530d659..e42aad8aa 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1559,11 +1559,11 @@ differences are mentioned in the following sections. @menu * QEMU PowerPC System emulator:: -* Sparc32 System emulator invocation:: -* Sparc64 System emulator invocation:: -* MIPS System emulator invocation:: -* ARM System emulator invocation:: -* ColdFire System emulator invocation:: +* Sparc32 System emulator:: +* Sparc64 System emulator:: +* MIPS System emulator:: +* ARM System emulator:: +* ColdFire System emulator:: @end menu @node QEMU PowerPC System emulator @@ -1631,8 +1631,8 @@ Set the initial VGA graphic mode. The default is 800x600x15. More information is available at @url{http://perso.magic.fr/l_indien/qemu-ppc/}. -@node Sparc32 System emulator invocation -@section Sparc32 System emulator invocation +@node Sparc32 System emulator +@section Sparc32 System emulator Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5 or SparcStation 10 (sun4m architecture). The emulation is somewhat complete. @@ -1698,8 +1698,8 @@ Set the emulated machine type. Default is SS-5. @c man end -@node Sparc64 System emulator invocation -@section Sparc64 System emulator invocation +@node Sparc64 System emulator +@section Sparc64 System emulator Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine. The emulator is not usable for anything yet. @@ -1717,26 +1717,68 @@ Non Volatile RAM M48T59 PC-compatible serial ports @end itemize -@node MIPS System emulator invocation -@section MIPS System emulator invocation +@node MIPS System emulator +@section MIPS System emulator Use the executable @file{qemu-system-mips} to simulate a MIPS machine. -The emulator is able to boot a Linux kernel and to run a Linux Debian -installation from NFS. The following devices are emulated: +Three different machine types are emulated: + +@itemize @minus +@item +A generic ISA PC-like machine "mips" +@item +The MIPS Malta prototype board "malta" +@item +An ACER Pica "pica61" +@end itemize + +The generic emulation is supported by Debian 'Etch' and is able to +install Debian into a virtual disk image. The following devices are +emulated: @itemize @minus @item -MIPS R4K CPU +MIPS 24Kf CPU @item PC style serial port @item +PC style IDE disk +@item NE2000 network card @end itemize -More information is available in the QEMU mailing-list archive. +The Malta emulation supports the following devices: + +@itemize @minus +@item +Core board with MIPS 24Kf CPU and Galilleo system controller +@item +PIIX4 PCI/USB/SMbus controller +@item +The Multi-I/O chip's serial device +@item +PCnet32 PCI network card +@item +Malta FPGA serial device +@item +Cirrus VGA graphics card +@end itemize + +The ACER Pica emulation supports: + +@itemize @minus +@item +MIPS R4000 CPU +@item +PC-style IRQ and DMA controllers +@item +PC Keyboard +@item +IDE controller +@end itemize -@node ARM System emulator invocation -@section ARM System emulator invocation +@node ARM System emulator +@section ARM System emulator Use the executable @file{qemu-system-arm} to simulate a ARM machine. The ARM Integrator/CP board is emulated with the following @@ -1844,8 +1886,8 @@ WM8750 audio CODEC on I@math{^2}C and I@math{^2}S busses A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. -@node ColdFire System emulator invocation -@section ColdFire System emulator invocation +@node ColdFire System emulator +@section ColdFire System emulator Use the executable @file{qemu-system-m68k} to simulate a ColdFire machine. The emulator is able to boot a uClinux kernel. diff --git a/qemu-tech.texi b/qemu-tech.texi index fc72ff1b6..45949547e 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -35,6 +35,7 @@ * intro_features:: Features * intro_x86_emulation:: x86 emulation * intro_arm_emulation:: ARM emulation +* intro_mips_emulation:: MIPS emulation * intro_ppc_emulation:: PowerPC emulation * intro_sparc_emulation:: SPARC emulation @end menu @@ -152,6 +153,31 @@ maximum performances. @end itemize +@node intro_mips_emulation +@section MIPS emulation + +@itemize + +@item The system emulation allows full MIPS32/MIPS64 Release 2 emulation, +including privileged instructions, FPU and MMU, in both little and big +endian modes. + +@item The Linux userland emulation can run many 32 bit MIPS Linux binaries. + +@end itemize + +Current QEMU limitations: + +@itemize + +@item Self-modifying code is not always handled correctly. + +@item 64 bit userland emulation is not implemented. + +@item The system emulation is not complete enough to run real firmware. + +@end itemize + @node intro_ppc_emulation @section PowerPC emulation -- cgit v1.2.3 From 475d91106dc8553ec1f54f47c0a4565c358e559f Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 10:25:04 +0000 Subject: Update TODO list. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3057 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index 2ff95df99..784c95507 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -11,8 +11,6 @@ General in that case. - gdb breakpoints inside the emulated system work only due to a hack which disassembles over the end of the current tb. -- Floating point results of ceil/floor/round are wrong for IEEE cornercases. -- recip/rsqrt FPU instructions are not implemented MIPS64 ------ -- cgit v1.2.3 From 81442192975a7badff6c8abcd7c800ef4c552470 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 10:25:58 +0000 Subject: Silence compiler warnings. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3058 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vmdk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block-vmdk.c b/block-vmdk.c index e595eabe5..0d3a804c4 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -572,7 +572,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, if (!s->is_parent) { status = stat(s->hd->filename, &file_buf); if (status == -1) { - fprintf(stderr, "(VMDK) Fail file stat: filename =%s size=0x%lx errno=%s\n", + fprintf(stderr, "(VMDK) Fail file stat: filename =%s size=0x%llx errno=%s\n", s->hd->filename, (uint64_t)file_buf.st_size, strerror(errno)); return 0; } @@ -668,7 +668,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, if (sector_num > bs->total_sectors) { fprintf(stderr, - "(VMDK) Wrong offset: sector_num=0x%lx total_sectors=0x%lx\n", + "(VMDK) Wrong offset: sector_num=0x%llx total_sectors=0x%llx\n", sector_num, bs->total_sectors); return -1; } -- cgit v1.2.3 From 3c4c9f9f51599845fba61240aba0f38485df7c14 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 10:36:47 +0000 Subject: Fix PPCEMB for 32bit hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3059 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 +- target-ppc/exec.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 57e46620b..435b838c3 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -693,7 +693,7 @@ struct CPUPPCState { /* temporary fixed-point registers * used to emulate 64 bits target on 32 bits hosts */ - target_ulong t0, t1, t2; + ppc_gpr_t t0, t1, t2; #endif ppc_avr_t t0_avr, t1_avr, t2_avr; diff --git a/target-ppc/exec.h b/target-ppc/exec.h index ee5183eb7..69807ad5e 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -43,15 +43,15 @@ register unsigned long T1 asm(AREG2); register unsigned long T2 asm(AREG3); #endif /* We may, sometime, need 64 bits registers on 32 bits target */ -#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) || (HOST_LONG_BITS == 64) -#define T0_64 T0 -#define T1_64 T1 -#define T2_64 T2 -#else +#if TARGET_GPR_BITS > HOST_LONG_BITS /* no registers can be used */ #define T0_64 (env->t0) #define T1_64 (env->t1) #define T2_64 (env->t2) +#else +#define T0_64 T0 +#define T1_64 T1 +#define T2_64 T2 #endif /* Provision for Altivec */ #define T0_avr (env->t0_avr) -- cgit v1.2.3 From 6ea4a6c875a2c0902fc19d560ef33228daa88603 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 11 Jul 2007 16:43:30 +0000 Subject: More alignment checks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3060 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 17 ++++++--- target-sparc/translate.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 4ab066779..f1f6ccefc 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1518,10 +1518,7 @@ void OPPROTO op_movl_npc_im(void) void OPPROTO op_movl_npc_T0(void) { - if (T0 & 0x3) - raise_exception(TT_UNALIGNED); - else - env->npc = T0; + env->npc = T0; } void OPPROTO op_mov_pc_npc(void) @@ -2368,3 +2365,15 @@ VIS_CMPOP(op_fcmple, FCMPLE) VIS_CMPOP(op_fcmpne, FCMPNE) #endif + +#define CHECK_ALIGN_OP(align) \ + void OPPROTO op_check_align_T0_ ## align (void) \ + { \ + if (T0 & align) \ + raise_exception(TT_UNALIGNED); \ + FORCE_RET(); \ + } + +CHECK_ALIGN_OP(1) +CHECK_ALIGN_OP(3) +CHECK_ALIGN_OP(7) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 3c183c6d5..2b42ffd34 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -346,6 +346,13 @@ GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); +#ifdef ALIGN_7_BUGS_FIXED +#else +#ifndef CONFIG_USER_ONLY +#define gen_op_check_align_T0_7() +#endif +#endif + #ifdef TARGET_SPARC64 // 'a' versions allowed to user depending on asi #if defined(CONFIG_USER_ONLY) @@ -2676,6 +2683,7 @@ static void disas_sparc_insn(DisasContext * dc) } gen_op_restore(); gen_mov_pc_npc(dc); + gen_op_check_align_T0_3(); gen_op_movl_npc_T0(); dc->npc = DYNAMIC_PC; goto jmp_insn; @@ -2720,6 +2728,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T1_reg(rd); } gen_mov_pc_npc(dc); + gen_op_check_align_T0_3(); gen_op_movl_npc_T0(); dc->npc = DYNAMIC_PC; } @@ -2730,6 +2739,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; gen_mov_pc_npc(dc); + gen_op_check_align_T0_3(); gen_op_movl_npc_T0(); dc->npc = DYNAMIC_PC; gen_op_rett(); @@ -2812,6 +2822,9 @@ static void disas_sparc_insn(DisasContext * dc) (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) { switch (xop) { case 0x0: /* load word */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif #ifndef TARGET_SPARC64 gen_op_ldst(ld); #else @@ -2822,9 +2835,13 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(ldub); break; case 0x2: /* load unsigned halfword */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_1(); +#endif gen_op_ldst(lduh); break; case 0x3: /* load double word */ + gen_op_check_align_T0_7(); if (rd & 1) goto illegal_insn; gen_op_ldst(ldd); @@ -2834,12 +2851,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(ldsb); break; case 0xa: /* load signed halfword */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_1(); +#endif gen_op_ldst(ldsh); break; case 0xd: /* ldstub -- XXX: should be atomically */ gen_op_ldst(ldstub); break; case 0x0f: /* swap register with memory. Also atomically */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_movl_reg_T1(rd); gen_op_ldst(swap); break; @@ -2850,8 +2873,14 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_lda(insn, 1, 4, 0); #else +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_lduwa(insn, 1, 4, 0); #endif break; @@ -2870,6 +2899,9 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; +#endif +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_1(); #endif gen_op_lduha(insn, 1, 2, 0); break; @@ -2882,6 +2914,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif if (rd & 1) goto illegal_insn; + gen_op_check_align_T0_7(); gen_op_ldda(insn, 1, 8, 0); gen_movl_T0_reg(rd + 1); break; @@ -2900,6 +2933,9 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; +#endif +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_1(); #endif gen_op_ldsha(insn, 1, 2 ,1); break; @@ -2920,6 +2956,9 @@ static void disas_sparc_insn(DisasContext * dc) goto priv_insn; #endif gen_movl_reg_T1(rd); +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_swapa(insn, 1, 4, 0); break; @@ -2943,23 +2982,35 @@ static void disas_sparc_insn(DisasContext * dc) #endif #ifdef TARGET_SPARC64 case 0x08: /* V9 ldsw */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_ldst(ldsw); break; case 0x0b: /* V9 ldx */ + gen_op_check_align_T0_7(); gen_op_ldst(ldx); break; case 0x18: /* V9 ldswa */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_ldswa(insn, 1, 4, 1); break; case 0x1b: /* V9 ldxa */ + gen_op_check_align_T0_7(); gen_op_ldxa(insn, 1, 8, 0); break; case 0x2d: /* V9 prefetch, no effect */ goto skip_move; case 0x30: /* V9 ldfa */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_ldfa(insn, 1, 8, 0); // XXX break; case 0x33: /* V9 lddfa */ + gen_op_check_align_T0_7(); gen_op_lddfa(insn, 1, 8, 0); // XXX break; @@ -2980,16 +3031,23 @@ static void disas_sparc_insn(DisasContext * dc) goto jmp_insn; switch (xop) { case 0x20: /* load fpreg */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_ldst(ldf); gen_op_store_FT0_fpr(rd); break; case 0x21: /* load fsr */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_ldst(ldf); gen_op_ldfsr(); break; case 0x22: /* load quad fpreg */ goto nfpu_insn; case 0x23: /* load double fpreg */ + gen_op_check_align_T0_7(); gen_op_ldst(lddf); gen_op_store_DT0_fpr(DFPREG(rd)); break; @@ -3001,17 +3059,24 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T1(rd); switch (xop) { case 0x4: +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_ldst(st); break; case 0x5: gen_op_ldst(stb); break; case 0x6: +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_1(); +#endif gen_op_ldst(sth); break; case 0x7: if (rd & 1) goto illegal_insn; + gen_op_check_align_T0_7(); flush_T2(dc); gen_movl_reg_T2(rd + 1); gen_op_ldst(std); @@ -3023,6 +3088,9 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; +#endif +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); #endif gen_op_sta(insn, 0, 4, 0); break; @@ -3041,6 +3109,9 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; +#endif +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_1(); #endif gen_op_stha(insn, 0, 2, 0); break; @@ -3053,6 +3124,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif if (rd & 1) goto illegal_insn; + gen_op_check_align_T0_7(); flush_T2(dc); gen_movl_reg_T2(rd + 1); gen_op_stda(insn, 0, 8, 0); @@ -3060,9 +3132,11 @@ static void disas_sparc_insn(DisasContext * dc) #endif #ifdef TARGET_SPARC64 case 0x0e: /* V9 stx */ + gen_op_check_align_T0_7(); gen_op_ldst(stx); break; case 0x1e: /* V9 stxa */ + gen_op_check_align_T0_7(); gen_op_stxa(insn, 0, 8, 0); // XXX break; #endif @@ -3074,10 +3148,16 @@ static void disas_sparc_insn(DisasContext * dc) goto jmp_insn; switch (xop) { case 0x24: +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_load_fpr_FT0(rd); gen_op_ldst(stf); break; case 0x25: /* stfsr, V9 stxfsr */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_stfsr(); gen_op_ldst(stf); break; @@ -3090,6 +3170,7 @@ static void disas_sparc_insn(DisasContext * dc) goto nfq_insn; #endif case 0x27: + gen_op_check_align_T0_7(); gen_op_load_fpr_DT0(DFPREG(rd)); gen_op_ldst(stdf); break; @@ -3100,15 +3181,23 @@ static void disas_sparc_insn(DisasContext * dc) switch (xop) { #ifdef TARGET_SPARC64 case 0x34: /* V9 stfa */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_stfa(insn, 0, 0, 0); // XXX break; case 0x37: /* V9 stdfa */ + gen_op_check_align_T0_7(); gen_op_stdfa(insn, 0, 0, 0); // XXX break; case 0x3c: /* V9 casa */ +#ifdef CONFIG_USER_ONLY + gen_op_check_align_T0_3(); +#endif gen_op_casa(insn, 0, 4, 0); // XXX break; case 0x3e: /* V9 casxa */ + gen_op_check_align_T0_7(); gen_op_casxa(insn, 0, 8, 0); // XXX break; case 0x36: /* V9 stqfa */ -- cgit v1.2.3 From a0a8793ebcca7f2ad071b3f95dec3c3dfe44354a Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 16:44:32 +0000 Subject: Impement Galilleo ISD register. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3061 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++--------- hw/mips_malta.c | 9 +++++++ 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index f75f8af21..d9f629647 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -225,13 +225,63 @@ typedef target_phys_addr_t pci_addr_t; typedef PCIHostState GT64120PCIState; +#define PCI_MAPPING_ENTRY(regname) \ + target_phys_addr_t regname ##_start; \ + target_phys_addr_t regname ##_length; \ + int regname ##_handle + typedef struct GT64120State { GT64120PCIState *pci; uint32_t regs[GT_REGS]; - target_phys_addr_t PCI0IO_start; - target_phys_addr_t PCI0IO_length; + PCI_MAPPING_ENTRY(PCI0IO); + PCI_MAPPING_ENTRY(ISD); } GT64120State; +/* Adjust range to avoid touching space which isn't mappable via PCI */ +/* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000 + 0x1fc00000 - 0x1fd00000 */ +static void check_reserved_space (target_phys_addr_t *start, + target_phys_addr_t *length) +{ + target_phys_addr_t begin = *start; + target_phys_addr_t end = *start + *length; + + if (end >= 0x1e000000LL && end < 0x1f100000LL) + end = 0x1e000000LL; + if (begin >= 0x1e000000LL && begin < 0x1f100000LL) + begin = 0x1f100000LL; + if (end >= 0x1fc00000LL && end < 0x1fd00000LL) + end = 0x1fc00000LL; + if (begin >= 0x1fc00000LL && begin < 0x1fd00000LL) + begin = 0x1fd00000LL; + /* XXX: This is broken when a reserved range splits the requested range */ + if (end >= 0x1f100000LL && begin < 0x1e000000LL) + end = 0x1e000000LL; + if (end >= 0x1fd00000LL && begin < 0x1fc00000LL) + end = 0x1fc00000LL; + + *start = begin; + *length = end - begin; +} + +static void gt64120_isd_mapping(GT64120State *s) +{ + target_phys_addr_t start = s->regs[GT_ISD] << 21; + target_phys_addr_t length = 0x1000; + + if (s->ISD_length) + cpu_register_physical_memory(s->ISD_start, s->ISD_length, + IO_MEM_UNASSIGNED); + check_reserved_space(&start, &length); + length = 0x1000; + /* Map new address */ + dprintf("ISD: %x@%x -> %x@%x, %x\n", s->ISD_length, s->ISD_start, + length, start, s->ISD_handle); + s->ISD_start = start; + s->ISD_length = length; + cpu_register_physical_memory(s->ISD_start, s->ISD_length, s->ISD_handle); +} + static void gt64120_pci_mapping(GT64120State *s) { /* Update IO mapping */ @@ -311,6 +361,11 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, s->regs[saddr] = val & 0x0000007f; gt64120_pci_mapping(s); break; + case GT_ISD: + s->regs[saddr] = val & 0x00007fff; + gt64120_isd_mapping(s); + break; + case GT_PCI0IOREMAP: case GT_PCI0M0REMAP: case GT_PCI0M1REMAP: @@ -1026,6 +1081,7 @@ void gt64120_reset(void *opaque) /* Interrupt registers are all zeroed at reset */ + gt64120_isd_mapping(s); gt64120_pci_mapping(s); } @@ -1070,27 +1126,21 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) { GT64120State *s; PCIDevice *d; - int gt64120; s = qemu_mallocz(sizeof(GT64120State)); s->pci = qemu_mallocz(sizeof(GT64120PCIState)); - gt64120_reset(s); s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq, pic, 144, 4); - - gt64120 = cpu_register_io_memory(0, gt64120_read, - gt64120_write, s); - cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120); - + s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s); d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), 0, gt64120_read_config, gt64120_write_config); /* FIXME: Malta specific hw assumptions ahead */ - d->config[0x00] = 0xab; // vendor_id + d->config[0x00] = 0xab; /* vendor_id */ d->config[0x01] = 0x11; - d->config[0x02] = 0x20; // device_id + d->config[0x02] = 0x20; /* device_id */ d->config[0x03] = 0x46; d->config[0x04] = 0x00; @@ -1113,6 +1163,8 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) d->config[0x27] = 0x14; d->config[0x3D] = 0x01; + gt64120_reset(s); + register_savevm("GT64120 PCI Bus", 0, 1, gt64120_save, gt64120_load, d); return s->pci->bus; diff --git a/hw/mips_malta.c b/hw/mips_malta.c index bc892ed81..ed23052b9 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -538,6 +538,15 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ /* Load BAR registers as done by YAMON */ + stl_raw(p++, 0x3c09b400); /* lui t1, 0xb400 */ + +#ifdef TARGET_WORDS_BIGENDIAN + stl_raw(p++, 0x3c08df00); /* lui t0, 0xdf00 */ +#else + stl_raw(p++, 0x340800df); /* ori t0, r0, 0x00df */ +#endif + stl_raw(p++, 0xad280068); /* sw t0, 0x0068(t1) */ + stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */ #ifdef TARGET_WORDS_BIGENDIAN -- cgit v1.2.3 From f19e918d70482789e5b47743e7d849ecaaee9920 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 11 Jul 2007 19:51:37 +0000 Subject: Sparc64 update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3062 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4u.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hw/sun4u.c b/hw/sun4u.c index a7b9ad8f0..4be94fa91 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -29,6 +29,7 @@ #define INITRD_LOAD_ADDR 0x00300000 #define PROM_SIZE_MAX (512 * 1024) #define PROM_ADDR 0x1fff0000000ULL +#define PROM_VADDR 0x000ffd00000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL #define APB_MEM_BASE 0x1ff00000000ULL #define VGA_BASE (APB_MEM_BASE + 0x400000ULL) @@ -244,7 +245,7 @@ int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, // OpenBIOS nvram variables // Variable partition - start = 252; + start = 256; m48t59_write(nvram, start, 0x70); NVRAM_set_string(nvram, start + 4, "system", 12); @@ -313,6 +314,10 @@ void hstick_irq(void *opaque) cpu_interrupt(env, CPU_INTERRUPT_TIMER); } +static void dummy_cpu_set_irq(void *opaque, int irq, int level) +{ +} + static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 14, 15 }; @@ -340,6 +345,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, PCIBus *pci_bus; const sparc_def_t *def; QEMUBH *bh; + qemu_irq *irq; linux_boot = (kernel_filename != NULL); @@ -377,7 +383,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - ret = load_elf(buf, 0, NULL, NULL, NULL); + ret = load_elf(buf, PROM_ADDR - PROM_VADDR, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -441,7 +447,9 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, pci_nic_init(pci_bus, &nd_table[i], -1); } - pci_cmd646_ide_init(pci_bus, bs_table, 1); + irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32); + // XXX pci_cmd646_ide_init(pci_bus, bs_table, 1); + pci_piix3_ide_init(pci_bus, bs_table, -1, irq); /* FIXME: wire up interrupts. */ i8042_init(NULL/*1*/, NULL/*12*/, 0x60); floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table); -- cgit v1.2.3 From 0b64d00880cf973ad849f97ce6666517883a27e5 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 21:43:14 +0000 Subject: Spelling fix, spotted by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3063 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index e42aad8aa..0f33f7823 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1751,7 +1751,7 @@ The Malta emulation supports the following devices: @itemize @minus @item -Core board with MIPS 24Kf CPU and Galilleo system controller +Core board with MIPS 24Kf CPU and Galileo system controller @item PIIX4 PCI/USB/SMbus controller @item -- cgit v1.2.3 From bb433bef5ad177ff95c2c18afe4957bd987687be Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 22:45:45 +0000 Subject: Remove superfluous gt64xxx_pci_mapping calls. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3064 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index d9f629647..b027ce849 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -330,36 +330,33 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, case GT_PCI0M0LD: s->regs[GT_PCI0M0LD] = val & 0x00007fff; s->regs[GT_PCI0M0REMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); break; case GT_PCI0M1LD: s->regs[GT_PCI0M1LD] = val & 0x00007fff; s->regs[GT_PCI0M1REMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); break; case GT_PCI1IOLD: s->regs[GT_PCI1IOLD] = val & 0x00007fff; s->regs[GT_PCI1IOREMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); break; case GT_PCI1M0LD: s->regs[GT_PCI1M0LD] = val & 0x00007fff; s->regs[GT_PCI1M0REMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); break; case GT_PCI1M1LD: s->regs[GT_PCI1M1LD] = val & 0x00007fff; s->regs[GT_PCI1M1REMAP] = val & 0x000007ff; - gt64120_pci_mapping(s); break; case GT_PCI0IOHD: + s->regs[saddr] = val & 0x0000007f; + gt64120_pci_mapping(s); + break; case GT_PCI0M0HD: case GT_PCI0M1HD: case GT_PCI1IOHD: case GT_PCI1M0HD: case GT_PCI1M1HD: s->regs[saddr] = val & 0x0000007f; - gt64120_pci_mapping(s); break; case GT_ISD: s->regs[saddr] = val & 0x00007fff; @@ -373,7 +370,6 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, case GT_PCI1M0REMAP: case GT_PCI1M1REMAP: s->regs[saddr] = val & 0x000007ff; - gt64120_pci_mapping(s); break; /* CPU Error Report */ -- cgit v1.2.3 From 4a1a170759e7036dd597e1db3bd2a7688760d6d3 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 22:47:56 +0000 Subject: Reduce variable shadowing, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3065 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 132 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/dyngen.c b/dyngen.c index 4ed48227e..d3db4d725 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1845,7 +1845,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* patch relocations */ #if defined(HOST_I386) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -1868,18 +1868,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; } - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), 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); + reloc_offset, relname, 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); + reloc_offset, relname, reloc_offset, addend); break; default: error("unsupported i386 relocation (%d)", type); @@ -1902,11 +1902,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, switch(type) { case DIR32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + reloc_offset, relname, 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); + reloc_offset, relname, reloc_offset, addend); break; default: error("unsupported i386 relocation (%d)", type); @@ -1919,7 +1919,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_X86_64) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -1927,22 +1927,22 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), 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); + reloc_offset, relname, addend); break; case R_X86_64_32S: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", - reloc_offset, name, addend); + reloc_offset, relname, 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); + reloc_offset, relname, reloc_offset, addend); break; default: error("unsupported X86_64 relocation (%d)", type); @@ -1953,7 +1953,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #elif defined(HOST_PPC) { #ifdef CONFIG_FORMAT_ELF - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -1974,30 +1974,30 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; } - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), 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); + reloc_offset, relname, addend); break; case R_PPC_ADDR16_LO: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", - reloc_offset, name, addend); + reloc_offset, relname, addend); break; case R_PPC_ADDR16_HI: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", - reloc_offset, name, addend); + reloc_offset, relname, addend); break; case R_PPC_ADDR16_HA: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", - reloc_offset, name, addend); + reloc_offset, relname, 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); + reloc_offset, reloc_offset, relname, reloc_offset, addend); break; default: error("unsupported powerpc relocation (%d)", type); @@ -2055,7 +2055,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); + relname, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type); continue; /* dunno how to handle without final_sym_name */ } @@ -2067,7 +2067,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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 ); + slide, slide, relname, 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", @@ -2096,7 +2096,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_S390) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2104,22 +2104,22 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), 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); + reloc_offset, relname, addend); break; case R_390_16: fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + reloc_offset, relname, addend); break; case R_390_8: fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + reloc_offset, relname, addend); break; default: error("unsupported s390 relocation (%d)", type); @@ -2187,7 +2187,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { unsigned long sym_idx; long code_offset; - char name[256]; + char relname[256]; int type; long addend; @@ -2210,7 +2210,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, n, code_offset); continue; } - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF64_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { @@ -2218,19 +2218,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, fprintf(outfile, " ia64_imm64(gen_code_ptr + %ld, " "%s + %ld);\n", - code_offset, name, addend); + code_offset, relname, 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, + code_offset, relname, 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); + " %s + %ld);\n", code_offset, relname, addend); break; case R_IA64_PCREL21B: @@ -2239,7 +2239,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " 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, relname, addend, code_offset & ~0xfUL); } else { fprintf(outfile, @@ -2260,7 +2260,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2268,14 +2268,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); + get_reloc_expr(relname, sizeof(relname), 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); + reloc_offset, relname, addend); break; case R_SPARC_HI22: fprintf(outfile, @@ -2283,7 +2283,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffff) " " | (((%s + %d) >> 10) & 0x3fffff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_LO10: fprintf(outfile, @@ -2291,7 +2291,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_WDISP30: fprintf(outfile, @@ -2300,7 +2300,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " & ~0x3fffffff) " " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffffff);\n", - reloc_offset, reloc_offset, name, addend, + reloc_offset, reloc_offset, relname, addend, reloc_offset); break; case R_SPARC_WDISP22: @@ -2312,7 +2312,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " & 0x3fffff);\n", rel->r_offset - start_offset, rel->r_offset - start_offset, - name, addend, + relname, addend, rel->r_offset - start_offset); break; default: @@ -2323,7 +2323,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC64) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2331,14 +2331,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); + get_reloc_expr(relname, sizeof(relname), 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); + reloc_offset, relname, addend); break; case R_SPARC_HI22: fprintf(outfile, @@ -2346,7 +2346,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffff) " " | (((%s + %d) >> 10) & 0x3fffff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_LO10: fprintf(outfile, @@ -2354,7 +2354,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_OLO10: addend += ELF64_R_TYPE_DATA (rel->r_info); @@ -2363,7 +2363,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_WDISP30: fprintf(outfile, @@ -2372,7 +2372,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " & ~0x3fffffff) " " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffffff);\n", - reloc_offset, reloc_offset, name, addend, + reloc_offset, reloc_offset, relname, addend, reloc_offset); break; case R_SPARC_WDISP22: @@ -2382,7 +2382,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " & ~0x3fffff) " " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffff);\n", - reloc_offset, reloc_offset, name, addend, + reloc_offset, reloc_offset, relname, addend, reloc_offset); break; case R_SPARC_HH22: @@ -2391,7 +2391,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x00000000) " " | (((%s + %d) >> 42) & 0x00000000);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_LM22: @@ -2400,7 +2400,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x00000000) " " | (((%s + %d) >> 10) & 0x00000000);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_HM10: @@ -2409,18 +2409,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x00000000) " " | ((((%s + %d) >> 32 & 0x3ff)) & 0x00000000);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; default: - error("unsupported sparc64 relocation (%d) for symbol %s", type, name); + error("unsupported sparc64 relocation (%d) for symbol %s", type, relname); } } } } #elif defined(HOST_ARM) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2455,7 +2455,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, fprintf(outfile, " *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode); } - arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end, + arm_emit_ldr_info(relname, start_offset, outfile, p_start, p_end, relocs, nb_relocs); for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { @@ -2465,20 +2465,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* the compiler leave some unnecessary references to the code */ if (sym_name[0] == '\0') continue; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), 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); + reloc_offset, relname, 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); + reloc_offset, addend, relname); break; default: error("unsupported arm relocation (%d)", type); @@ -2488,7 +2488,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_M68K) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2498,7 +2498,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); + get_reloc_expr(relname, sizeof(relname), 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; @@ -2506,12 +2506,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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 ); + reloc_offset, relname, 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); + reloc_offset, relname, reloc_offset, /*sym->st_value+*/ addend); break; default: error("unsupported m68k relocation (%d)", type); @@ -2523,7 +2523,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2532,7 +2532,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* the compiler leave some unnecessary references to the code */ if (sym_name[0] == '\0') continue; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = get32((uint32_t *)(text + rel->r_offset)); reloc_offset = rel->r_offset - start_offset; @@ -2545,7 +2545,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "(0x%x & ~0x3fffff) " "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) " " & 0x3fffff);\n", - reloc_offset, addend, addend, name, reloc_offset); + reloc_offset, addend, addend, relname, reloc_offset); break; case R_MIPS_HI16: fprintf(outfile, " /* R_MIPS_HI16 RELOC, offset 0x%x, name %s */\n", @@ -2555,7 +2555,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + 0x%x)) " " & ~0xffff) " " | (((%s - 0x8000) >> 16) & 0xffff);\n", - reloc_offset, reloc_offset, name); + reloc_offset, reloc_offset, relname); break; case R_MIPS_LO16: fprintf(outfile, " /* R_MIPS_LO16 RELOC, offset 0x%x, name %s */\n", @@ -2565,7 +2565,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + 0x%x)) " " & ~0xffff) " " | (%s & 0xffff);\n", - reloc_offset, reloc_offset, name); + reloc_offset, reloc_offset, relname); break; case R_MIPS_PC16: fprintf(outfile, " /* R_MIPS_PC16 RELOC, offset 0x%x, name %s */\n", @@ -2575,7 +2575,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "(0x%x & ~0xffff) " "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) " " & 0xffff);\n", - reloc_offset, addend, addend, name, reloc_offset); + reloc_offset, addend, addend, relname, reloc_offset); break; case R_MIPS_GOT16: case R_MIPS_CALL16: @@ -2586,7 +2586,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + 0x%x)) " " & ~0xffff) " " | (((%s - 0x8000) >> 16) & 0xffff);\n", - reloc_offset, reloc_offset, name); + reloc_offset, reloc_offset, relname); break; default: error("unsupported MIPS relocation (%d)", type); -- cgit v1.2.3 From aa1f17c18d3778b10a93b858c10c075ee023487a Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 22:48:58 +0000 Subject: Spelling fixes, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3066 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 2 +- dis-asm.h | 2 +- gdbstub.c | 6 +++--- hw/i2c.h | 2 +- hw/ide.c | 2 +- hw/pl011.c | 6 +++--- hw/pl181.c | 4 ++-- hw/rtl8139.c | 2 +- hw/usb.c | 2 +- linux-user/signal.c | 2 +- m68k-dis.c | 2 +- target-i386/cpu.h | 2 +- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/block-raw.c b/block-raw.c index 29882e1f7..e9e502768 100644 --- a/block-raw.c +++ b/block-raw.c @@ -1295,7 +1295,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) #if 0 /***********************************************/ -/* removable device additionnal commands */ +/* removable device additional commands */ static int raw_is_inserted(BlockDriverState *bs) { diff --git a/dis-asm.h b/dis-asm.h index 2b2f1d1de..ad08cc5d6 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -421,7 +421,7 @@ extern int generic_symbol_at_address /* 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. */ + GDB which must initialize these things separately. */ #define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ (INFO).fprintf_func = (FPRINTF_FUNC), \ diff --git a/gdbstub.c b/gdbstub.c index 06cf30200..2ac8c5712 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1248,12 +1248,12 @@ int gdbserver_start(int port) return 0; } #else -static int gdb_chr_can_recieve(void *opaque) +static int gdb_chr_can_receive(void *opaque) { return 1; } -static void gdb_chr_recieve(void *opaque, const uint8_t *buf, int size) +static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size) { GDBState *s = opaque; int i; @@ -1304,7 +1304,7 @@ int gdbserver_start(const char *port) } s->env = first_cpu; /* XXX: allow to change CPU */ s->chr = chr; - qemu_chr_add_handlers(chr, gdb_chr_can_recieve, gdb_chr_recieve, + qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, gdb_chr_event, s); qemu_add_vm_stop_handler(gdb_vm_stopped, s); return 0; diff --git a/hw/i2c.h b/hw/i2c.h index 17e52e7e8..9330ae852 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -10,7 +10,7 @@ enum i2c_event { I2C_START_RECV, I2C_START_SEND, I2C_FINISH, - I2C_NACK /* Masker NACKed a recieve byte. */ + I2C_NACK /* Masker NACKed a receive byte. */ }; typedef struct i2c_slave i2c_slave; diff --git a/hw/ide.c b/hw/ide.c index c4fabe6a6..9acb02a85 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1567,7 +1567,7 @@ static void ide_atapi_cmd(IDEState *s) buf[1] = 0x80; /* removable */ buf[2] = 0x00; /* ISO */ buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ - buf[4] = 31; /* additionnal length */ + buf[4] = 31; /* additional length */ buf[5] = 0; /* reserved */ buf[6] = 0; /* reserved */ buf[7] = 0; /* reserved */ diff --git a/hw/pl011.c b/hw/pl011.c index 64b753019..149a85e54 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -176,7 +176,7 @@ static void pl011_write(void *opaque, target_phys_addr_t offset, } } -static int pl011_can_recieve(void *opaque) +static int pl011_can_receive(void *opaque) { pl011_state *s = (pl011_state *)opaque; @@ -186,7 +186,7 @@ static int pl011_can_recieve(void *opaque) return s->read_count < 1; } -static void pl011_recieve(void *opaque, const uint8_t *buf, int size) +static void pl011_receive(void *opaque, const uint8_t *buf, int size) { pl011_state *s = (pl011_state *)opaque; int slot; @@ -241,7 +241,7 @@ void pl011_init(uint32_t base, qemu_irq irq, s->cr = 0x300; s->flags = 0x90; if (chr){ - qemu_chr_add_handlers(chr, pl011_can_recieve, pl011_recieve, + qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive, pl011_event, s); } /* ??? Save/restore. */ diff --git a/hw/pl181.c b/hw/pl181.c index 912465971..62ccad9e4 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -160,7 +160,7 @@ static void pl181_send_command(pl181_state *s) s->response[2] = RWORD(8); s->response[3] = RWORD(12) & ~1; } - DPRINTF("Response recieved\n"); + DPRINTF("Response received\n"); s->status |= PL181_STATUS_CMDRESPEND; #undef RWORD } else { @@ -174,7 +174,7 @@ error: s->status |= PL181_STATUS_CMDTIMEOUT; } -/* Transfer data between teh card and the FIFO. This is complicated by +/* Transfer data between the card and the FIFO. This is complicated by the FIFO holding 32-bit words and the card taking data in single byte chunks. FIFO bytes are transferred in little-endian order. */ diff --git a/hw/rtl8139.c b/hw/rtl8139.c index d1e60e829..705bddb4e 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -790,7 +790,7 @@ static int rtl8139_can_receive(void *opaque) RTL8139State *s = opaque; int avail; - /* Recieve (drop) packets if card is disabled. */ + /* Receive (drop) packets if card is disabled. */ if (!s->clock_enabled) return 1; if (!rtl8139_receiver_enabled(s)) diff --git a/hw/usb.c b/hw/usb.c index efbc6dbe9..17cb8df36 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -140,7 +140,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p) s->setup_state = SETUP_STATE_IDLE; /* transfer OK */ } else { - /* ignore additionnal output */ + /* ignore additional output */ } break; case SETUP_STATE_DATA: diff --git a/linux-user/signal.c b/linux-user/signal.c index 5b1334a1c..6dcb9dc53 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -244,7 +244,7 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) } /* XXX: we support only POSIX RT signals are used. */ -/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */ +/* XXX: find a solution for 64 bit (additional malloced data is needed) */ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) { info->si_signo = tswap32(tinfo->si_signo); diff --git a/m68k-dis.c b/m68k-dis.c index dd195582e..ef0f89c74 100644 --- a/m68k-dis.c +++ b/m68k-dis.c @@ -560,7 +560,7 @@ static char *const reg_names[] = }; /* Name of register halves for MAC/EMAC. - Seperate from reg_names since 'spu', 'fpl' look weird. */ + Separate from reg_names since 'spu', 'fpl' look weird. */ static char *const reg_half_names[] = { "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 3a82426b8..6d764f535 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -121,7 +121,7 @@ #define VIP_MASK 0x00100000 #define ID_MASK 0x00200000 -/* hidden flags - used internally by qemu to represent additionnal cpu +/* hidden flags - used internally by qemu to represent additional cpu states. Only the CPL, INHIBIT_IRQ and HALTED are not redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring with eflags. */ -- cgit v1.2.3 From 37a4c5392d9590e9ec1fc4a78b23f308c179e619 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 22:50:53 +0000 Subject: Spelling fix, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3067 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/fdc.c b/hw/fdc.c index ca2d32072..4f04b729f 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1268,7 +1268,7 @@ static void fdctrl_format_sector (fdctrl_t *fdctrl) memset(fdctrl->fifo, 0, FD_SECTOR_LEN); if (cur_drv->bs == NULL || bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { - FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv)); + FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); } else { if (cur_drv->sect == cur_drv->last_sect) { -- cgit v1.2.3 From af3a9031061251fbbee2c1f06b876c3732cfee71 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 23:14:59 +0000 Subject: New features for QEMU text console, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3068 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--------------- qemu-doc.texi | 11 +++++++++-- vl.c | 8 +++++--- vl.h | 2 +- 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/console.c b/console.c index a53b30177..f4b8dc58e 100644 --- a/console.c +++ b/console.c @@ -104,10 +104,16 @@ int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) return len1; } +typedef enum { + GRAPHIC_CONSOLE, + TEXT_CONSOLE, + TEXT_CONSOLE_FIXED_SIZE +} console_type_t; + /* ??? This is mis-named. It is used for both text and graphical consoles. */ struct TextConsole { - int text_console; /* true if text console */ + console_type_t console_type; DisplayState *ds; /* Graphic console state. */ vga_hw_update_ptr hw_update; @@ -587,7 +593,7 @@ static void console_scroll(int ydelta) int i, y1; s = active_console; - if (!s || !s->text_console) + if (!s || (s->console_type == GRAPHIC_CONSOLE)) return; if (ydelta > 0) { @@ -990,13 +996,17 @@ void console_select(unsigned int index) s = consoles[index]; if (s) { active_console = s; - if (s->text_console) { + if (s->console_type != GRAPHIC_CONSOLE) { if (s->g_width != s->ds->width || s->g_height != s->ds->height) { + if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) { + dpy_resize(s->ds, s->g_width, s->g_height); + } else { s->g_width = s->ds->width; s->g_height = s->ds->height; text_console_resize(s); } + } console_refresh(s); } else { vga_hw_invalidate(); @@ -1062,7 +1072,7 @@ void kbd_put_keysym(int keysym) int c; s = active_console; - if (!s || !s->text_console) + if (!s || (s->console_type == GRAPHIC_CONSOLE)) return; switch(keysym) { @@ -1104,7 +1114,7 @@ void kbd_put_keysym(int keysym) } } -static TextConsole *new_console(DisplayState *ds, int text) +static TextConsole *new_console(DisplayState *ds, console_type_t console_type) { TextConsole *s; int i; @@ -1115,16 +1125,18 @@ static TextConsole *new_console(DisplayState *ds, int text) if (!s) { return NULL; } - if (!active_console || (active_console->text_console && !text)) + if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) && + (console_type == GRAPHIC_CONSOLE))) { active_console = s; + } s->ds = ds; - s->text_console = text; - if (text) { + s->console_type = console_type; + if (console_type != GRAPHIC_CONSOLE) { 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) + if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE) break; consoles[i] = consoles[i - 1]; } @@ -1140,7 +1152,7 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, { TextConsole *s; - s = new_console(ds, 0); + s = new_console(ds, GRAPHIC_CONSOLE); if (!s) return NULL; s->hw_update = update; @@ -1152,20 +1164,22 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, int is_graphic_console(void) { - return !active_console->text_console; + return active_console->console_type == GRAPHIC_CONSOLE; } -CharDriverState *text_console_init(DisplayState *ds) +CharDriverState *text_console_init(DisplayState *ds, const char *p) { CharDriverState *chr; TextConsole *s; int i,j; + unsigned width; + unsigned height; static int color_inited; chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; - s = new_console(ds, 1); + s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE); if (!s) { free(chr); return NULL; @@ -1193,8 +1207,25 @@ CharDriverState *text_console_init(DisplayState *ds) s->total_height = DEFAULT_BACKSCROLL; s->x = 0; s->y = 0; - s->g_width = s->ds->width; - s->g_height = s->ds->height; + width = s->ds->width; + height = s->ds->height; + if (p != 0) { + width = strtoul(p, (char **)&p, 10); + if (*p == 'C') { + p++; + width *= FONT_WIDTH; + } + if (*p == 'x') { + p++; + height = strtoul(p, (char **)&p, 10); + if (*p == 'C') { + p++; + height *= FONT_HEIGHT; + } + } + } + s->g_width = width; + s->g_height = height; /* Set text attribute defaults */ s->t_attrib_default.bold = 0; diff --git a/qemu-doc.texi b/qemu-doc.texi index 0f33f7823..67b78cdcd 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -555,8 +555,15 @@ Use @code{-serial none} to disable all serial ports. Available character devices are: @table @code -@item vc -Virtual console +@item vc[:WxH] +Virtual console. Optionally, a width and height can be given in pixel with +@example +vc:800x600 +@end example +It is also possible to specify width or height in characters: +@example +vc:80Cx24C +@end example @item pty [Linux only] Pseudo TTY (a new PTY is automatically allocated) @item none diff --git a/vl.c b/vl.c index 0d059f40f..497a1e5fa 100644 --- a/vl.c +++ b/vl.c @@ -2923,7 +2923,9 @@ CharDriverState *qemu_chr_open(const char *filename) const char *p; if (!strcmp(filename, "vc")) { - return text_console_init(&display_state); + return text_console_init(&display_state, 0); + } else if (strstart(filename, "vc:", &p)) { + return text_console_init(&display_state, p); } else if (!strcmp(filename, "null")) { return qemu_chr_open_null(); } else @@ -7970,7 +7972,7 @@ int main(int argc, char **argv) devname); exit(1); } - if (!strcmp(devname, "vc")) + if (strstart(devname, "vc", 0)) qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i); } } @@ -7984,7 +7986,7 @@ int main(int argc, char **argv) devname); exit(1); } - if (!strcmp(devname, "vc")) + if (strstart(devname, "vc", 0)) qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); } } diff --git a/vl.h b/vl.h index 85014cd15..6627bcef0 100644 --- a/vl.h +++ b/vl.h @@ -351,7 +351,7 @@ void vga_hw_invalidate(void); void vga_hw_screen_dump(const char *filename); int is_graphic_console(void); -CharDriverState *text_console_init(DisplayState *ds); +CharDriverState *text_console_init(DisplayState *ds, const char *p); void console_select(unsigned int index); /* serial ports */ -- cgit v1.2.3 From e784ba70e016eed3203e403256f87b34dd6ef48b Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 23:23:15 +0000 Subject: Ensure signals are properly masked for new SDL Audio threads, by Andrzej Zaborowski. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3069 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/sdlaudio.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index f2a6896a5..11edab08d 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -25,6 +25,13 @@ #include #include "vl.h" +#ifndef _WIN32 +#ifdef __sun__ +#define _POSIX_PTHREAD_SEMANTICS 1 +#endif +#include +#endif + #define AUDIO_CAP "sdl" #include "audio_int.h" @@ -177,11 +184,22 @@ static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess) static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) { int status; +#ifndef _WIN32 + sigset_t new, old; + + /* Make sure potential threads created by SDL don't hog signals. */ + sigfillset (&new); + pthread_sigmask (SIG_BLOCK, &new, &old); +#endif status = SDL_OpenAudio (req, obt); if (status) { sdl_logerr ("SDL_OpenAudio failed\n"); } + +#ifndef _WIN32 + pthread_sigmask (SIG_SETMASK, &old, 0); +#endif return status; } -- cgit v1.2.3 From 20b40c6a55c5d3a86edf70f6061b656822dddbd6 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 11 Jul 2007 23:39:45 +0000 Subject: Display SDL configuration error, idea by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3070 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/configure b/configure index b9504a528..a24331d74 100755 --- a/configure +++ b/configure @@ -553,7 +553,7 @@ cat > $TMPC << EOF 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 +if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /tmp/qemu-$$-sdl-config.log ; then _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` if test "$_sdlversion" -lt 121 ; then sdl_too_old=yes @@ -688,6 +688,11 @@ 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 [ -s /tmp/qemu-$$-sdl-config.log ]; then + echo "The error log from compiling the libSDL test is: " + cat /tmp/qemu-$$-sdl-config.log +fi +rm -f /tmp/qemu-$$-sdl-config.log #if test "$sdl_static" = "no"; then # echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output" #fi -- cgit v1.2.3 From 5b2849688ee81998ea9f3c6bd341a3277a0226c4 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 00:18:52 +0000 Subject: Disable dead code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3071 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 51332ff4b..60e3a36f1 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -270,7 +270,8 @@ static void spr_write_sdr1 (void *opaque, int sprn) /* 64 bits PowerPC specific SPRs */ /* ASR */ -#if defined(TARGET_PPC64) +/* Currently unused */ +#if 0 && defined(TARGET_PPC64) static void spr_read_asr (void *opaque, int sprn) { gen_op_load_asr(); -- cgit v1.2.3 From 069b0bda7273634af02a68b86940b8509c13e1eb Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 00:27:15 +0000 Subject: Nicer script formatting, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3072 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 84 +++++++++++++++++++++++++++++---------------------------------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/configure b/configure index a24331d74..43541c6ee 100755 --- a/configure +++ b/configure @@ -536,58 +536,52 @@ EOF 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 + 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 #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> /tmp/qemu-$$-sdl-config.log ; then + _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` + if test "$_sdlversion" -lt 121 ; then + sdl_too_old=yes + else + if test "$cocoa" = "no" ; then + sdl=yes + fi + fi -if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /tmp/qemu-$$-sdl-config.log ; then -_sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` -if test "$_sdlversion" -lt 121 ; then -sdl_too_old=yes -else - if test "$cocoa" = "no" ; then - sdl=yes - fi -fi - -# static link with sdl ? -if test "$sdl" = "yes" ; then -aa="no" -`$sdl_config --static-libs 2>/dev/null | grep \\\-laa > /dev/null` && aa="yes" -sdl_static_libs=`$sdl_config --static-libs 2>/dev/null` -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 - + # static link with sdl ? + if test "$sdl" = "yes" ; then + aa="no" + `$sdl_config --static-libs 2>/dev/null | grep \\\-laa > /dev/null` && aa="yes" + sdl_static_libs=`$sdl_config --static-libs 2>/dev/null` + 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 else - # Make sure to disable cocoa if sdl was set - if test "$sdl" = "yes" ; then - cocoa="no" - coreaudio="no" - fi + # Make sure to disable cocoa if sdl was set + if test "$sdl" = "yes" ; then + cocoa="no" + coreaudio="no" + fi fi # -z $sdl ########################################## -- cgit v1.2.3 From b1f452387e27060fdf69f1979335336c52c4e58c Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 09:03:30 +0000 Subject: More documentation bits, from Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3073 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 ++ qemu-tech.texi | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 67b78cdcd..c75d9e09a 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1164,6 +1164,8 @@ change or eject media. @item Hard disks Hard disks can be used with the syntax: @file{\\.\PhysicalDriveN} where @var{N} is the drive number (0 is the first hard disk). +@file{/dev/hda} is supported as an alias to the first hard disk +drive @file{\\.\PhysicalDrive0}. WARNING: unless you know what you do, it is better to only make READ-ONLY accesses to the hard disk otherwise you may corrupt your diff --git a/qemu-tech.texi b/qemu-tech.texi index 45949547e..c3b5bd504 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -176,6 +176,8 @@ Current QEMU limitations: @item The system emulation is not complete enough to run real firmware. +@item The watchpoint debug facility is not implemented. + @end itemize @node intro_ppc_emulation @@ -575,7 +577,7 @@ The TwoOStwo PC virtualizer. @chapter Regression Tests In the directory @file{tests/}, various interesting testing programs -are available. There are used for regression testing. +are available. They are used for regression testing. @menu * test-i386:: -- cgit v1.2.3 From db8d7dd17bff97aa6311c81a2940012b4c7681d9 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 09:29:18 +0000 Subject: Fix configure for cygwin, by Tristan Gingold. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3074 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- configure | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile.target b/Makefile.target index 67689cfef..18b7949c6 100644 --- a/Makefile.target +++ b/Makefile.target @@ -494,7 +494,7 @@ tcp_subr.o tcp_timer.o udp.o bootp.o debug.o tftp.o VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS)) endif -VL_LDFLAGS= +VL_LDFLAGS=$(VL_OS_LDFLAGS) VL_LIBS=$(AIOLIBS) # specific flags are needed for non soft mmu emulator ifdef CONFIG_STATIC diff --git a/configure b/configure index 43541c6ee..62e0b0c51 100755 --- a/configure +++ b/configure @@ -108,9 +108,16 @@ case $targetos in CYGWIN*) mingw32="yes" OS_CFLAGS="-mno-cygwin" +VL_OS_LDFLAGS="-mno-cygwin" +if [ "$cpu" = "i386" ] ; then + kqemu="yes" +fi ;; MINGW32*) mingw32="yes" +if [ "$cpu" = "i386" ] ; then + kqemu="yes" +fi ;; GNU/kFreeBSD) oss="yes" @@ -390,9 +397,6 @@ 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 @@ -713,6 +717,7 @@ echo "AR=$ar" >> $config_mak echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak echo "OS_CFLAGS=$OS_CFLAGS" >> $config_mak echo "OS_LDFLAGS=$OS_LDFLAGS" >> $config_mak +echo "VL_OS_LDFLAGS=$VL_OS_LDFLAGS" >> $config_mak echo "ARCH_CFLAGS=$ARCH_CFLAGS" >> $config_mak echo "ARCH_LDFLAGS=$ARCH_LDFLAGS" >> $config_mak echo "CFLAGS=$CFLAGS" >> $config_mak -- cgit v1.2.3 From 8fac5803a968b77fd59a2857f99e0894cc0a5b76 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 10:05:07 +0000 Subject: Improve handling of gdb's single-step / continue arguments. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3075 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 2ac8c5712..4aafcaa10 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -773,7 +773,9 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_ARM) env->regs[15] = addr; #elif defined (TARGET_SH4) - env->pc = addr; + env->pc = addr; +#elif defined (TARGET_MIPS) + env->PC = addr; #endif } #ifdef CONFIG_USER_ONLY @@ -784,7 +786,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) return RS_IDLE; case 's': if (*p != '\0') { - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); #if defined(TARGET_I386) env->eip = addr; #elif defined (TARGET_PPC) @@ -795,7 +797,9 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_ARM) env->regs[15] = addr; #elif defined (TARGET_SH4) - env->pc = addr; + env->pc = addr; +#elif defined (TARGET_MIPS) + env->PC = addr; #endif } cpu_single_step(env, 1); -- cgit v1.2.3 From fe8f096b16bf2328ec615d4314f06cd5545f32e5 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 10:59:21 +0000 Subject: Spelling fix, by Stuart Brady. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3076 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 32 ++++++++++++++++---------------- audio/audio.c | 8 ++++---- audio/audio_int.h | 4 ++-- hw/pxa2xx.c | 4 ++-- linux-user/syscall.c | 2 +- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 3f9ffdbbc..a573a380a 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -50,11 +50,11 @@ static struct { unsigned int period_size_out; unsigned int threshold; - int buffer_size_in_overriden; - int period_size_in_overriden; + int buffer_size_in_overridden; + int period_size_in_overridden; - int buffer_size_out_overriden; - int period_size_out_overriden; + int buffer_size_out_overridden; + int period_size_out_overridden; int verbose; } conf = { #define DEFAULT_BUFFER_SIZE 1024 @@ -75,10 +75,10 @@ static struct { .period_size_in = DEFAULT_PERIOD_SIZE * 4, .buffer_size_out = DEFAULT_BUFFER_SIZE, .period_size_out = DEFAULT_PERIOD_SIZE, - .buffer_size_in_overriden = 0, - .buffer_size_out_overriden = 0, - .period_size_in_overriden = 0, - .period_size_out_overriden = 0, + .buffer_size_in_overridden = 0, + .buffer_size_out_overridden = 0, + .period_size_in_overridden = 0, + .period_size_out_overridden = 0, #endif .threshold = 0, .verbose = 0 @@ -414,8 +414,8 @@ static int alsa_open (int in, struct alsa_params_req *req, } else { if (period_size < minval) { - if ((in && conf.period_size_in_overriden) - || (!in && conf.period_size_out_overriden)) { + if ((in && conf.period_size_in_overridden) + || (!in && conf.period_size_out_overridden)) { dolog ("%s period size(%d) is less " "than minmal period size(%ld)\n", typ, @@ -450,8 +450,8 @@ static int alsa_open (int in, struct alsa_params_req *req, } else { if (buffer_size < minval) { - if ((in && conf.buffer_size_in_overriden) - || (!in && conf.buffer_size_out_overriden)) { + if ((in && conf.buffer_size_in_overridden) + || (!in && conf.buffer_size_out_overridden)) { dolog ( "%s buffer size(%d) is less " "than minimal buffer size(%ld)\n", @@ -945,16 +945,16 @@ static struct audio_option alsa_options[] = { {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out, "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0}, {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out, - "DAC period size", &conf.period_size_out_overriden, 0}, + "DAC period size", &conf.period_size_out_overridden, 0}, {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out, - "DAC buffer size", &conf.buffer_size_out_overriden, 0}, + "DAC buffer size", &conf.buffer_size_out_overridden, 0}, {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in, "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0}, {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in, - "ADC period size", &conf.period_size_in_overriden, 0}, + "ADC period size", &conf.period_size_in_overridden, 0}, {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in, - "ADC buffer size", &conf.buffer_size_in_overriden, 0}, + "ADC buffer size", &conf.buffer_size_in_overridden, 0}, {"THRESHOLD", AUD_OPT_INT, &conf.threshold, "(undocumented)", NULL, 0}, diff --git a/audio/audio.c b/audio/audio.c index 5d3c7f15f..4248c1401 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -386,7 +386,7 @@ static void audio_print_options (const char *prefix, const char *state = "default"; printf (" %s_%s: ", uprefix, opt->name); - if (opt->overridenp && *opt->overridenp) { + if (opt->overriddenp && *opt->overriddenp) { state = "current"; } @@ -516,10 +516,10 @@ static void audio_process_options (const char *prefix, break; } - if (!opt->overridenp) { - opt->overridenp = &opt->overriden; + if (!opt->overriddenp) { + opt->overriddenp = &opt->overridden; } - *opt->overridenp = !def; + *opt->overriddenp = !def; qemu_free (optname); } } diff --git a/audio/audio_int.h b/audio/audio_int.h index 1a15d4ced..cd22a3088 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -44,8 +44,8 @@ struct audio_option { audio_option_tag_e tag; void *valp; const char *descr; - int *overridenp; - int overriden; + int *overriddenp; + int overridden; }; struct audio_callback { diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 1a7d4a741..3d55c0197 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2118,7 +2118,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); /* GPIO1 resets the processor */ - /* The handler can be overriden by board-specific code */ + /* The handler can be overridden by board-specific code */ pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s); return s; } @@ -2227,7 +2227,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); /* GPIO1 resets the processor */ - /* The handler can be overriden by board-specific code */ + /* The handler can be overridden by board-specific code */ pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s); return s; } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 52806bb20..d61838eda 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -184,7 +184,7 @@ extern int getresgid(gid_t *, gid_t *, gid_t *); extern int setgroups(int, gid_t *); /* - * This list is the union of errno values overidden in asm-/errno.h + * This list is the union of errno values overridden in asm-/errno.h * minus the errnos that are not actually generic to all archs. */ static uint16_t host_to_target_errno_table[1200] = { -- cgit v1.2.3 From 7f7f7c846345550634e1d4b91c9c5f475edfd9ed Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 11:02:46 +0000 Subject: Sigio fd passing, by Alexander Graf. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3077 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/signal.c b/linux-user/signal.c index 6dcb9dc53..eea73470f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -207,6 +207,8 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, /* should never come here, but who knows. The information for the target is irrelevant */ tinfo->_sifields._sigfault._addr = 0; + } else if (sig == SIGIO) { + tinfo->_sifields._sigpoll._fd = info->si_fd; } else if (sig >= TARGET_SIGRTMIN) { tinfo->_sifields._rt._pid = info->si_pid; tinfo->_sifields._rt._uid = info->si_uid; @@ -228,6 +230,8 @@ static void tswap_siginfo(target_siginfo_t *tinfo, sig == SIGBUS || sig == SIGTRAP) { tinfo->_sifields._sigfault._addr = tswapl(info->_sifields._sigfault._addr); + } else if (sig == SIGIO) { + tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd); } else if (sig >= TARGET_SIGRTMIN) { tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); -- cgit v1.2.3 From 4cae1d16396f4a2827d5cafaaf232698588ade55 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 11:06:53 +0000 Subject: Tkill support, by Stuart Anderson. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3078 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d61838eda..1d010f745 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -145,6 +145,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo #define __NR_sys_syslog __NR_syslog #define __NR_sys_tgkill __NR_tgkill +#define __NR_sys_tkill __NR_tkill #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek @@ -165,7 +166,12 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) +#ifdef TARGET_NR_tgkill _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) +#endif +#ifdef TARGET_NR_tkill +_syscall2(int,sys_tkill,int,tid,int,sig) +#endif #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) #endif @@ -4613,6 +4619,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #endif +#ifdef TARGET_NR_tkill + case TARGET_NR_tkill: + ret = get_errno(sys_tkill((int)arg1, (int)arg2)); + break; +#endif + #ifdef TARGET_NR_tgkill case TARGET_NR_tgkill: ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3)); -- cgit v1.2.3 From c19dbb9426a34a8e8cfdc5c285e8562ff3fe4f7a Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 12 Jul 2007 11:32:22 +0000 Subject: Fix crash in set registers in PPC gdb-stub, by Jason Wessel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3079 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index e3700b5f2..84e6c3935 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1493,10 +1493,12 @@ void do_store_msr (CPUPPCState *env, target_ulong value) break; } if (enter_pm) { - /* power save: exit cpu loop */ - env->halted = 1; - env->exception_index = EXCP_HLT; - cpu_loop_exit(); + if (likely(!env->halted)) { + /* power save: exit cpu loop */ + env->halted = 1; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); + } } } -- cgit v1.2.3 From b67838393679b0504c9ab0e7d53e0a26bb42c6a3 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 13 Jul 2007 18:40:46 +0000 Subject: Delete mention of /dev/hda as an alias t o \\PysicalDrive0. Currently this isn't true, and we probably don't want to make it true by grabbing namespace which might be used by cygwin. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3080 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 -- 1 file changed, 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index c75d9e09a..67b78cdcd 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1164,8 +1164,6 @@ change or eject media. @item Hard disks Hard disks can be used with the syntax: @file{\\.\PhysicalDriveN} where @var{N} is the drive number (0 is the first hard disk). -@file{/dev/hda} is supported as an alias to the first hard disk -drive @file{\\.\PhysicalDrive0}. WARNING: unless you know what you do, it is better to only make READ-ONLY accesses to the hard disk otherwise you may corrupt your -- cgit v1.2.3 From a029baa4065c9a08c7118a8f96edf84e7d3fcfe1 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 15 Jul 2007 16:56:08 +0000 Subject: Restore OS X build (plus code reformatting). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3081 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 167 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 83 insertions(+), 84 deletions(-) diff --git a/dyngen.c b/dyngen.c index d3db4d725..a07884ae6 100644 --- a/dyngen.c +++ b/dyngen.c @@ -2005,91 +2005,90 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } #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", - relname, 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, relname, 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); + 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_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); - } - } + 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 -- cgit v1.2.3 From 4ce6f8de1aa07cd0587f100200f949a2defdf5cb Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 20 Jul 2007 15:54:27 +0000 Subject: Fix statfs(64) syscall wrapper, by Andreas Schwab. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3082 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 6 ++++-- linux-user/syscall_defs.h | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1d010f745..a4add6494 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3352,7 +3352,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, put_user(stfs.f_bavail, &target_stfs->f_bavail); put_user(stfs.f_files, &target_stfs->f_files); put_user(stfs.f_ffree, &target_stfs->f_ffree); - put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid); + put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); + put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); put_user(stfs.f_namelen, &target_stfs->f_namelen); unlock_user_struct(target_stfs, arg2, 1); } @@ -3378,7 +3379,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, put_user(stfs.f_bavail, &target_stfs->f_bavail); put_user(stfs.f_files, &target_stfs->f_files); put_user(stfs.f_ffree, &target_stfs->f_ffree); - put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid); + put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); + put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); put_user(stfs.f_namelen, &target_stfs->f_namelen); unlock_user_struct(target_stfs, arg3, 0); } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 7b4122fed..31e1b3290 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1356,6 +1356,10 @@ struct target_stat64 { #error unsupported CPU #endif +typedef struct { + int val[2]; +} target_fsid_t; + #ifdef TARGET_MIPS struct target_statfs { target_long f_type; @@ -1368,7 +1372,7 @@ struct target_statfs { target_long f_bavail; /* Linux specials */ - int f_fsid; + target_fsid_t f_fsid; target_long f_namelen; target_long f_spare[6]; }; @@ -1383,7 +1387,7 @@ struct target_statfs64 { uint64_t f_files; uint64_t f_ffree; uint64_t f_bavail; - int f_fsid; + target_fsid_t f_fsid; uint32_t f_namelen; uint32_t f_spare[6]; }; @@ -1396,7 +1400,7 @@ struct target_statfs { uint32_t f_bavail; uint32_t f_files; uint32_t f_ffree; - int f_fsid; + target_fsid_t f_fsid; uint32_t f_namelen; uint32_t f_frsize; uint32_t f_spare[5]; @@ -1410,7 +1414,7 @@ struct target_statfs64 { uint64_t f_bavail; uint64_t f_files; uint64_t f_ffree; - int f_fsid; + target_fsid_t f_fsid; uint32_t f_namelen; uint32_t f_frsize; uint32_t f_spare[5]; -- cgit v1.2.3 From aa268ea622a1e0443ee816c0eb09da928efef5eb Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 22 Jul 2007 18:16:42 +0000 Subject: Thumb shifter carry flag fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3083 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/op.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/op.c b/target-arm/op.c index d7ac6de06..771f9c470 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -819,7 +819,7 @@ void OPPROTO op_shll_T0_im_thumb(void) int shift; shift = PARAM1; if (shift != 0) { - env->CF = (T1 >> (32 - shift)) & 1; + env->CF = (T0 >> (32 - shift)) & 1; T0 = T0 << shift; } env->NZF = T0; @@ -832,7 +832,7 @@ void OPPROTO op_shrl_T0_im_thumb(void) shift = PARAM1; if (shift == 0) { - env->CF = ((uint32_t)shift) >> 31; + env->CF = ((uint32_t)T0) >> 31; T0 = 0; } else { env->CF = (T0 >> (shift - 1)) & 1; -- cgit v1.2.3 From b7fe5db7e57d6cd58fa59da80257f698bab7dc70 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 23 Jul 2007 15:37:46 +0000 Subject: Restore build on older Linux hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3084 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a4add6494..e23a684e7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -281,12 +281,24 @@ static uint16_t host_to_target_errno_table[1200] = { [ECANCELED] = TARGET_ECANCELED, [ENOMEDIUM] = TARGET_ENOMEDIUM, [EMEDIUMTYPE] = TARGET_EMEDIUMTYPE, +#ifdef ENOKEY [ENOKEY] = TARGET_ENOKEY, +#endif +#ifdef EKEYEXPIRED [EKEYEXPIRED] = TARGET_EKEYEXPIRED, +#endif +#ifdef EKEYREVOKED [EKEYREVOKED] = TARGET_EKEYREVOKED, +#endif +#ifdef EKEYREJECTED [EKEYREJECTED] = TARGET_EKEYREJECTED, +#endif +#ifdef EOWNERDEAD [EOWNERDEAD] = TARGET_EOWNERDEAD, +#endif +#ifdef ENOTRECOVERABLE [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE, +#endif }; static inline int host_to_target_errno(int err) -- cgit v1.2.3 From 82d179781bcd81b37e0213085087e1dbf1f6b7f9 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 24 Jul 2007 01:07:44 +0000 Subject: Various reg offset shift typos. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3085 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx.c | 6 +++--- target-arm/cpu.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 3d55c0197..a1c54b988 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -280,7 +280,7 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, case 1: /* Idle */ - if (!(s->cm_regs[CCCR] & (1 << 31))) { /* CPDIS */ + if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ cpu_interrupt(s->env, CPU_INTERRUPT_HALT); break; } @@ -2057,7 +2057,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds); s->cm_base = 0x41300000; - s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ + s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ s->clkcfg = 0x00000009; /* Turbo mode active */ iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, pxa2xx_cm_writefn, s); @@ -2166,7 +2166,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds); s->cm_base = 0x41300000; - s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */ + s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ s->clkcfg = 0x00000009; /* Turbo mode active */ iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, pxa2xx_cm_writefn, s); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 1c748e258..5bd40ffbc 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -283,7 +283,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #else /* The ARM MMU allows 1k pages. */ /* ??? Linux doesn't actually use these, and they're deprecated in recent - architecture revisions. Maybe an a configure option to disable them. */ + architecture revisions. Maybe a configure option to disable them. */ #define TARGET_PAGE_BITS 10 #endif -- cgit v1.2.3 From 73221b12ea55ae916b550e56d70743221ca3c886 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 25 Jul 2007 16:50:37 +0000 Subject: Fix memory corruption after OHCI reset, by Ed Swierk. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3086 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-ohci.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 99e072f87..2d5af7da0 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -120,6 +120,8 @@ struct ohci_hcca { uint32_t done; }; +static void ohci_bus_stop(OHCIState *ohci); + /* Bitfields for the first word of an Endpoint Desciptor. */ #define OHCI_ED_FA_SHIFT 0 #define OHCI_ED_FA_MASK (0x7f<ctl = 0; ohci->old_ctl = 0; ohci->status = 0; @@ -833,6 +837,7 @@ static void ohci_bus_stop(OHCIState *ohci) { if (ohci->eof_timer) qemu_del_timer(ohci->eof_timer); + ohci->eof_timer = NULL; } /* Sets a flag in a port status register but only set it if the port is @@ -918,6 +923,7 @@ static void ohci_set_ctl(OHCIState *ohci, uint32_t val) dprintf("usb-ohci: %s: USB Resume\n", ohci->name); break; case OHCI_USB_RESET: + ohci_reset(ohci); dprintf("usb-ohci: %s: USB Reset\n", ohci->name); break; } @@ -1291,6 +1297,7 @@ static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn, } ohci->async_td = 0; + qemu_register_reset(ohci_reset, ohci); ohci_reset(ohci); } -- cgit v1.2.3 From d4af3de224fbb4677744e9d0661a6296fca791ba Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 26 Jul 2007 20:41:46 +0000 Subject: gcc32 may well be a 4.x version for a 32bit target, so add an additional check, hopefully not too strict. Probe also gcc-3.3.6 to make Gentoo users happy. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3087 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 62e0b0c51..7709c975f 100755 --- a/configure +++ b/configure @@ -23,7 +23,7 @@ static="no" cross_prefix="" cc="gcc" gcc3_search="yes" -gcc3_list="gcc-3.4 gcc34 gcc-3.3 gcc33 gcc-3.2 gcc32" +gcc3_list="gcc-3.4 gcc34 gcc-3.3.6 gcc-3.3 gcc33 gcc-3.2 gcc32" host_cc="gcc" ar="ar" make="make" @@ -413,7 +413,7 @@ EOF if test "$gcc3_search" = "yes" ; then echo "Looking for gcc 3.x" for compat_cc in $gcc3_list ; do - if "$cross_prefix$compat_cc" --version > /dev/null 2>&1 ; then + if "$cross_prefix$compat_cc" --version 2> /dev/null | fgrep '(GCC) 3.' > /dev/null 2>&1 ; then echo "Found \"$compat_cc\"" cc="$cross_prefix$compat_cc" found_compat_cc="yes" -- cgit v1.2.3 From 59c0149bc6b4e29c6605e943d4c30686c2bed589 Mon Sep 17 00:00:00 2001 From: balrog Date: Fri, 27 Jul 2007 21:49:15 +0000 Subject: Update TNF bit in I2C status register, original patch by Juergen Lock. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3088 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index a1c54b988..6109fc13e 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1530,6 +1530,8 @@ static inline void pxa2xx_i2s_update(struct pxa2xx_i2s_s *i2s) pxa2xx_dma_request(i2s->dma, PXA2XX_TX_RQ_I2S, tfs); i2s->status &= 0xe0; + if (i2s->fifo_len < 16 || !i2s->enable) + i2s->status |= 1 << 0; /* TNF */ if (i2s->rx_len) i2s->status |= 1 << 1; /* RNE */ if (i2s->enable) -- cgit v1.2.3 From 2b8f2d4165de7095b58927138458b8d30775891e Mon Sep 17 00:00:00 2001 From: balrog Date: Fri, 27 Jul 2007 22:08:46 +0000 Subject: Optionally setup old style linux bootparams for -kernel, by Juergen Lock. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3089 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_boot.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- vl.c | 11 +++++++++ vl.h | 1 + 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index ed3ec5830..ccc9ecbf6 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -76,6 +76,77 @@ static void set_kernel_args(uint32_t ram_size, int initrd_size, stl_raw(p++, 0); } +static void set_kernel_args_old(uint32_t ram_size, int initrd_size, + const char *kernel_cmdline, + target_phys_addr_t loader_start) +{ + uint32_t *p; + unsigned char *s; + + /* see linux/include/asm-arm/setup.h */ + p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR); + /* page_size */ + stl_raw(p++, 4096); + /* nr_pages */ + stl_raw(p++, ram_size / 4096); + /* ramdisk_size */ + stl_raw(p++, 0); +#define FLAG_READONLY 1 +#define FLAG_RDLOAD 4 +#define FLAG_RDPROMPT 8 + /* flags */ + stl_raw(p++, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT); + /* rootdev */ + stl_raw(p++, (31 << 8) | 0); /* /dev/mtdblock0 */ + /* video_num_cols */ + stl_raw(p++, 0); + /* video_num_rows */ + stl_raw(p++, 0); + /* video_x */ + stl_raw(p++, 0); + /* video_y */ + stl_raw(p++, 0); + /* memc_control_reg */ + stl_raw(p++, 0); + /* unsigned char sounddefault */ + /* unsigned char adfsdrives */ + /* unsigned char bytes_per_char_h */ + /* unsigned char bytes_per_char_v */ + stl_raw(p++, 0); + /* pages_in_bank[4] */ + stl_raw(p++, 0); + stl_raw(p++, 0); + stl_raw(p++, 0); + stl_raw(p++, 0); + /* pages_in_vram */ + stl_raw(p++, 0); + /* initrd_start */ + if (initrd_size) + stl_raw(p++, loader_start + INITRD_LOAD_ADDR); + else + stl_raw(p++, 0); + /* initrd_size */ + stl_raw(p++, initrd_size); + /* rd_start */ + stl_raw(p++, 0); + /* system_rev */ + stl_raw(p++, 0); + /* system_serial_low */ + stl_raw(p++, 0); + /* system_serial_high */ + stl_raw(p++, 0); + /* mem_fclk_21285 */ + stl_raw(p++, 0); + /* zero unused fields */ + memset(p, 0, 256 + 1024 - + (p - ((uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR)))); + s = phys_ram_base + KERNEL_ARGS_ADDR + 256 + 1024; + if (kernel_cmdline) + strcpy (s, kernel_cmdline); + else + stb_raw(s, 0); +} + void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, int board_id, target_phys_addr_t loader_start) @@ -140,6 +211,11 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) stl_raw(phys_ram_base + (n * 4), bootloader[n]); - set_kernel_args(ram_size, initrd_size, kernel_cmdline, loader_start); + if (old_param) + set_kernel_args_old(ram_size, initrd_size, + kernel_cmdline, loader_start); + else + set_kernel_args(ram_size, initrd_size, + kernel_cmdline, loader_start); } } diff --git a/vl.c b/vl.c index 497a1e5fa..dc2297ecf 100644 --- a/vl.c +++ b/vl.c @@ -197,6 +197,9 @@ const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; int autostart = 1; +#ifdef TARGET_ARM +int old_param = 0; +#endif const char *qemu_name; int alt_grab = 0; #ifdef TARGET_SPARC @@ -6801,6 +6804,7 @@ enum { QEMU_OPTION_semihosting, QEMU_OPTION_name, QEMU_OPTION_prom_env, + QEMU_OPTION_old_param, }; typedef struct QEMUOption { @@ -6901,6 +6905,9 @@ const QEMUOption qemu_options[] = { { "name", HAS_ARG, QEMU_OPTION_name }, #if defined(TARGET_SPARC) { "prom-env", HAS_ARG, QEMU_OPTION_prom_env }, +#endif +#if defined(TARGET_ARM) + { "old-param", 0, QEMU_OPTION_old_param }, #endif { NULL }, }; @@ -7675,6 +7682,10 @@ int main(int argc, char **argv) prom_envs[nb_prom_envs] = optarg; nb_prom_envs++; break; +#endif +#ifdef TARGET_ARM + case QEMU_OPTION_old_param: + old_param = 1; #endif } } diff --git a/vl.h b/vl.h index 6627bcef0..d943e7f48 100644 --- a/vl.h +++ b/vl.h @@ -164,6 +164,7 @@ extern int graphic_rotate; extern int no_quit; extern int semihosting_enabled; extern int autostart; +extern int old_param; extern const char *bootp_filename; #define MAX_OPTION_ROMS 16 -- cgit v1.2.3 From a5236105dbf7b971715f1ac55f52f716081a0632 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 29 Jul 2007 17:34:59 +0000 Subject: Word-reads from spitz NAND controller, patch by Juergen Lock. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3090 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/spitz.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/spitz.c b/hw/spitz.c index c6fb598f4..eaea2e976 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -78,6 +78,18 @@ static uint32_t sl_readb(void *opaque, target_phys_addr_t addr) return 0; } +static uint32_t sl_readl(void *opaque, target_phys_addr_t addr) +{ + struct sl_nand_s *s = (struct sl_nand_s *) opaque; + addr -= s->target_base; + + if (addr == FLASH_FLASHIO) + return ecc_digest(&s->ecc, nand_getio(s->nand)) | + (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16); + + return sl_readb(opaque, addr); +} + static void sl_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) { @@ -139,7 +151,7 @@ static void sl_flash_register(struct pxa2xx_state_s *cpu, int size) CPUReadMemoryFunc *sl_readfn[] = { sl_readb, sl_readb, - sl_readb, + sl_readl, }; CPUWriteMemoryFunc *sl_writefn[] = { sl_writeb, -- cgit v1.2.3 From c3d2689d88159291ef8af338b5f01cfbe5551d2c Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 29 Jul 2007 17:57:26 +0000 Subject: Basic OMAP310 support. Basic Palm Tungsten|E machine emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3091 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + cpu-all.h | 3 +- hw/omap.c | 2914 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/omap.h | 581 ++++++++++ hw/omap1_clk.c | 745 +++++++++++++ hw/omap_lcd_template.h | 172 +++ hw/omap_lcdc.c | 499 +++++++++ hw/palm.c | 140 +++ target-arm/cpu.h | 9 +- target-arm/helper.c | 76 +- vl.c | 1 + vl.h | 5 + 12 files changed, 5143 insertions(+), 3 deletions(-) create mode 100644 hw/omap.c create mode 100644 hw/omap.h create mode 100644 hw/omap1_clk.c create mode 100644 hw/omap_lcd_template.h create mode 100644 hw/omap_lcdc.c create mode 100644 hw/palm.c diff --git a/Makefile.target b/Makefile.target index 18b7949c6..f99573d1d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -463,6 +463,7 @@ VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o +VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o palm.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) diff --git a/cpu-all.h b/cpu-all.h index 289d660f1..54d5dc36a 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -702,7 +702,8 @@ void cpu_dump_statistics (CPUState *env, FILE *f, int flags); void cpu_abort(CPUState *env, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); + __attribute__ ((__format__ (__printf__, 2, 3))) + __attribute__ ((__noreturn__)); extern CPUState *first_cpu; extern CPUState *cpu_single_env; extern int code_copy_enabled; diff --git a/hw/omap.c b/hw/omap.c new file mode 100644 index 000000000..fe4f9c40f --- /dev/null +++ b/hw/omap.c @@ -0,0 +1,2914 @@ +/* + * TI OMAP processors emulation. + * + * Copyright (C) 2006-2007 Andrzej Zaborowski + * + * 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 "vl.h" +#include "arm_pic.h" + +/* Should signal the TCMI */ +static uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) +{ + OMAP_16B_REG(addr); + return 0; +} + +static void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + OMAP_16B_REG(addr); +} + +static uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr) +{ + OMAP_32B_REG(addr); + return 0; +} + +static void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + OMAP_32B_REG(addr); +} + +#define likely +#define unlikely + +/* Interrupt Handlers */ +struct omap_intr_handler_s { + qemu_irq *pins; + qemu_irq *parent_pic; + target_phys_addr_t base; + + /* state */ + uint32_t irqs; + uint32_t mask; + uint32_t sens_edge; + uint32_t fiq; + int priority[32]; + uint32_t new_irq_agr; + uint32_t new_fiq_agr; + int sir_irq; + int sir_fiq; + int stats[32]; +}; + +static void omap_inth_update(struct omap_intr_handler_s *s) +{ + uint32_t irq = s->new_irq_agr & s->irqs & ~s->mask & ~s->fiq; + uint32_t fiq = s->new_fiq_agr & s->irqs & ~s->mask & s->fiq; + + qemu_set_irq(s->parent_pic[ARM_PIC_CPU_IRQ], irq); + if (irq) + s->new_irq_agr = 0; + + qemu_set_irq(s->parent_pic[ARM_PIC_CPU_FIQ], fiq); + if (fiq) + s->new_fiq_agr = 0; +} + +static void omap_inth_sir_update(struct omap_intr_handler_s *s) +{ + int i, intr_irq, intr_fiq, p_irq, p_fiq, p, f; + uint32_t level = s->irqs & ~s->mask; + + intr_irq = 0; + intr_fiq = 0; + p_irq = -1; + p_fiq = -1; + /* Find the interrupt line with the highest dynamic priority */ + for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, level >>= f) { + p = s->priority[i]; + if (s->fiq & (1 << i)) { + if (p > p_fiq) { + p_fiq = p; + intr_fiq = i; + } + } else { + if (p > p_irq) { + p_irq = p; + intr_irq = i; + } + } + + f = ffs(level >> 1); + } + + s->sir_irq = intr_irq; + s->sir_fiq = intr_fiq; +} + +#define INT_FALLING_EDGE 0 +#define INT_LOW_LEVEL 1 + +static void omap_set_intr(void *opaque, int irq, int req) +{ + struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; + uint32_t rise; + + if (req) { + rise = ~ih->irqs & (1 << irq); + ih->irqs |= rise; + ih->stats[irq] ++; + } else { + rise = ih->sens_edge & ih->irqs & (1 << irq); + ih->irqs &= ~rise; + } + + if (rise & ~ih->mask) { + omap_inth_sir_update(ih); + + omap_inth_update(ih); + } +} + +static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + int i, offset = addr - s->base; + + switch (offset) { + case 0x00: /* ITR */ + return s->irqs; + + case 0x04: /* MIR */ + return s->mask; + + case 0x10: /* SIR_IRQ_CODE */ + i = s->sir_irq; + if (((s->sens_edge >> i) & 1) == INT_FALLING_EDGE && i) { + s->irqs &= ~(1 << i); + omap_inth_sir_update(s); + omap_inth_update(s); + } + return i; + + case 0x14: /* SIR_FIQ_CODE */ + i = s->sir_fiq; + if (((s->sens_edge >> i) & 1) == INT_FALLING_EDGE && i) { + s->irqs &= ~(1 << i); + omap_inth_sir_update(s); + omap_inth_update(s); + } + return i; + + case 0x18: /* CONTROL_REG */ + return 0; + + case 0x1c: /* ILR0 */ + case 0x20: /* ILR1 */ + case 0x24: /* ILR2 */ + case 0x28: /* ILR3 */ + case 0x2c: /* ILR4 */ + case 0x30: /* ILR5 */ + case 0x34: /* ILR6 */ + case 0x38: /* ILR7 */ + case 0x3c: /* ILR8 */ + case 0x40: /* ILR9 */ + case 0x44: /* ILR10 */ + case 0x48: /* ILR11 */ + case 0x4c: /* ILR12 */ + case 0x50: /* ILR13 */ + case 0x54: /* ILR14 */ + case 0x58: /* ILR15 */ + case 0x5c: /* ILR16 */ + case 0x60: /* ILR17 */ + case 0x64: /* ILR18 */ + case 0x68: /* ILR19 */ + case 0x6c: /* ILR20 */ + case 0x70: /* ILR21 */ + case 0x74: /* ILR22 */ + case 0x78: /* ILR23 */ + case 0x7c: /* ILR24 */ + case 0x80: /* ILR25 */ + case 0x84: /* ILR26 */ + case 0x88: /* ILR27 */ + case 0x8c: /* ILR28 */ + case 0x90: /* ILR29 */ + case 0x94: /* ILR30 */ + case 0x98: /* ILR31 */ + i = (offset - 0x1c) >> 2; + return (s->priority[i] << 2) | + (((s->sens_edge >> i) & 1) << 1) | + ((s->fiq >> i) & 1); + + case 0x9c: /* ISR */ + return 0x00000000; + + default: + OMAP_BAD_REG(addr); + break; + } + return 0; +} + +static void omap_inth_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; + int i, offset = addr - s->base; + + switch (offset) { + case 0x00: /* ITR */ + s->irqs &= value; + omap_inth_sir_update(s); + omap_inth_update(s); + return; + + case 0x04: /* MIR */ + s->mask = value; + omap_inth_sir_update(s); + omap_inth_update(s); + return; + + case 0x10: /* SIR_IRQ_CODE */ + case 0x14: /* SIR_FIQ_CODE */ + OMAP_RO_REG(addr); + break; + + case 0x18: /* CONTROL_REG */ + if (value & 2) + s->new_fiq_agr = ~0; + if (value & 1) + s->new_irq_agr = ~0; + omap_inth_update(s); + return; + + case 0x1c: /* ILR0 */ + case 0x20: /* ILR1 */ + case 0x24: /* ILR2 */ + case 0x28: /* ILR3 */ + case 0x2c: /* ILR4 */ + case 0x30: /* ILR5 */ + case 0x34: /* ILR6 */ + case 0x38: /* ILR7 */ + case 0x3c: /* ILR8 */ + case 0x40: /* ILR9 */ + case 0x44: /* ILR10 */ + case 0x48: /* ILR11 */ + case 0x4c: /* ILR12 */ + case 0x50: /* ILR13 */ + case 0x54: /* ILR14 */ + case 0x58: /* ILR15 */ + case 0x5c: /* ILR16 */ + case 0x60: /* ILR17 */ + case 0x64: /* ILR18 */ + case 0x68: /* ILR19 */ + case 0x6c: /* ILR20 */ + case 0x70: /* ILR21 */ + case 0x74: /* ILR22 */ + case 0x78: /* ILR23 */ + case 0x7c: /* ILR24 */ + case 0x80: /* ILR25 */ + case 0x84: /* ILR26 */ + case 0x88: /* ILR27 */ + case 0x8c: /* ILR28 */ + case 0x90: /* ILR29 */ + case 0x94: /* ILR30 */ + case 0x98: /* ILR31 */ + i = (offset - 0x1c) >> 2; + s->priority[i] = (value >> 2) & 0x1f; + s->sens_edge &= ~(1 << i); + s->sens_edge |= ((value >> 1) & 1) << i; + s->fiq &= ~(1 << i); + s->fiq |= (value & 1) << i; + return; + + case 0x9c: /* ISR */ + for (i = 0; i < 32; i ++) + if (value & (1 << i)) { + omap_set_intr(s, i, 1); + return; + } + return; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_inth_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_inth_read, +}; + +static CPUWriteMemoryFunc *omap_inth_writefn[] = { + omap_inth_write, + omap_inth_write, + omap_inth_write, +}; + +static void omap_inth_reset(struct omap_intr_handler_s *s) +{ + s->irqs = 0x00000000; + s->mask = 0xffffffff; + s->sens_edge = 0x00000000; + s->fiq = 0x00000000; + memset(s->priority, 0, sizeof(s->priority)); + s->new_irq_agr = ~0; + s->new_fiq_agr = ~0; + s->sir_irq = 0; + s->sir_fiq = 0; + + omap_inth_update(s); +} + +struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, + unsigned long size, qemu_irq parent[2], omap_clk clk) +{ + int iomemtype; + struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) + qemu_mallocz(sizeof(struct omap_intr_handler_s)); + + s->parent_pic = parent; + s->base = base; + s->pins = qemu_allocate_irqs(omap_set_intr, s, 32); + omap_inth_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_inth_readfn, + omap_inth_writefn, s); + cpu_register_physical_memory(s->base, size, iomemtype); + + return s; +} + +/* OMAP1 DMA module */ +typedef enum { + constant = 0, + post_incremented, + single_index, + double_index, +} omap_dma_addressing_t; + +struct omap_dma_channel_s { + int burst[2]; + int pack[2]; + enum omap_dma_port port[2]; + target_phys_addr_t addr[2]; + omap_dma_addressing_t mode[2]; + int data_type; + int end_prog; + int repeat; + int auto_init; + int priority; + int fs; + int sync; + int running; + int interrupts; + int status; + int signalled; + int post_sync; + int transfer; + uint16_t elements; + uint16_t frames; + uint16_t frame_index; + uint16_t element_index; + uint16_t cpc; + + struct omap_dma_reg_set_s { + target_phys_addr_t src, dest; + int frame; + int element; + int frame_delta[2]; + int elem_delta[2]; + int frames; + int elements; + } active_set; +}; + +struct omap_dma_s { + qemu_irq *ih; + QEMUTimer *tm; + struct omap_mpu_state_s *mpu; + target_phys_addr_t base; + omap_clk clk; + int64_t delay; + + uint16_t gcr; + int run_count; + + int chans; + struct omap_dma_channel_s ch[16]; + struct omap_dma_lcd_channel_s lcd_ch; +}; + +static void omap_dma_interrupts_update(struct omap_dma_s *s) +{ + /* First three interrupts are shared between two channels each. */ + qemu_set_irq(s->ih[OMAP_INT_DMA_CH0_6], + (s->ch[0].status | s->ch[6].status) & 0x3f); + qemu_set_irq(s->ih[OMAP_INT_DMA_CH1_7], + (s->ch[1].status | s->ch[7].status) & 0x3f); + qemu_set_irq(s->ih[OMAP_INT_DMA_CH2_8], + (s->ch[2].status | s->ch[8].status) & 0x3f); + qemu_set_irq(s->ih[OMAP_INT_DMA_CH3], + (s->ch[3].status) & 0x3f); + qemu_set_irq(s->ih[OMAP_INT_DMA_CH4], + (s->ch[4].status) & 0x3f); + qemu_set_irq(s->ih[OMAP_INT_DMA_CH5], + (s->ch[5].status) & 0x3f); +} + +static void omap_dma_channel_load(struct omap_dma_s *s, int ch) +{ + struct omap_dma_reg_set_s *a = &s->ch[ch].active_set; + int i; + + /* + * TODO: verify address ranges and alignment + * TODO: port endianness + */ + + a->src = s->ch[ch].addr[0]; + a->dest = s->ch[ch].addr[1]; + a->frames = s->ch[ch].frames; + a->elements = s->ch[ch].elements; + a->frame = 0; + a->element = 0; + + if (unlikely(!s->ch[ch].elements || !s->ch[ch].frames)) { + printf("%s: bad DMA request\n", __FUNCTION__); + return; + } + + for (i = 0; i < 2; i ++) + switch (s->ch[ch].mode[i]) { + case constant: + a->elem_delta[i] = 0; + a->frame_delta[i] = 0; + break; + case post_incremented: + a->elem_delta[i] = s->ch[ch].data_type; + a->frame_delta[i] = 0; + break; + case single_index: + a->elem_delta[i] = s->ch[ch].data_type + + s->ch[ch].element_index - 1; + if (s->ch[ch].element_index > 0x7fff) + a->elem_delta[i] -= 0x10000; + a->frame_delta[i] = 0; + break; + case double_index: + a->elem_delta[i] = s->ch[ch].data_type + + s->ch[ch].element_index - 1; + if (s->ch[ch].element_index > 0x7fff) + a->elem_delta[i] -= 0x10000; + a->frame_delta[i] = s->ch[ch].frame_index - + s->ch[ch].element_index; + if (s->ch[ch].frame_index > 0x7fff) + a->frame_delta[i] -= 0x10000; + break; + default: + break; + } +} + +static inline void omap_dma_request_run(struct omap_dma_s *s, + int channel, int request) +{ +next_channel: + if (request > 0) + for (; channel < 9; channel ++) + if (s->ch[channel].sync == request && s->ch[channel].running) + break; + if (channel >= 9) + return; + + if (s->ch[channel].transfer) { + if (request > 0) { + s->ch[channel ++].post_sync = request; + goto next_channel; + } + s->ch[channel].status |= 0x02; /* Synchronisation drop */ + omap_dma_interrupts_update(s); + return; + } + + if (!s->ch[channel].signalled) + s->run_count ++; + s->ch[channel].signalled = 1; + + if (request > 0) + s->ch[channel].status |= 0x40; /* External request */ + + if (s->delay) + qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); + + if (request > 0) { + channel ++; + goto next_channel; + } +} + +static inline void omap_dma_request_stop(struct omap_dma_s *s, int channel) +{ + if (s->ch[channel].signalled) + s->run_count --; + s->ch[channel].signalled = 0; + + if (!s->run_count) + qemu_del_timer(s->tm); +} + +static void omap_dma_channel_run(struct omap_dma_s *s) +{ + int ch; + uint16_t status; + uint8_t value[4]; + struct omap_dma_port_if_s *src_p, *dest_p; + struct omap_dma_reg_set_s *a; + + for (ch = 0; ch < 9; ch ++) { + a = &s->ch[ch].active_set; + + src_p = &s->mpu->port[s->ch[ch].port[0]]; + dest_p = &s->mpu->port[s->ch[ch].port[1]]; + if (s->ch[ch].signalled && (!src_p->addr_valid(s->mpu, a->src) || + !dest_p->addr_valid(s->mpu, a->dest))) { +#if 0 + /* Bus time-out */ + if (s->ch[ch].interrupts & 0x01) + s->ch[ch].status |= 0x01; + omap_dma_request_stop(s, ch); + continue; +#endif + printf("%s: Bus time-out in DMA%i operation\n", __FUNCTION__, ch); + } + + status = s->ch[ch].status; + while (status == s->ch[ch].status && s->ch[ch].signalled) { + /* Transfer a single element */ + s->ch[ch].transfer = 1; + cpu_physical_memory_read(a->src, value, s->ch[ch].data_type); + cpu_physical_memory_write(a->dest, value, s->ch[ch].data_type); + s->ch[ch].transfer = 0; + + a->src += a->elem_delta[0]; + a->dest += a->elem_delta[1]; + a->element ++; + + /* Check interrupt conditions */ + if (a->element == a->elements) { + a->element = 0; + a->src += a->frame_delta[0]; + a->dest += a->frame_delta[1]; + a->frame ++; + + if (a->frame == a->frames) { + if (!s->ch[ch].repeat || !s->ch[ch].auto_init) + s->ch[ch].running = 0; + + if (s->ch[ch].auto_init && + (s->ch[ch].repeat || + s->ch[ch].end_prog)) + omap_dma_channel_load(s, ch); + + if (s->ch[ch].interrupts & 0x20) + s->ch[ch].status |= 0x20; + + if (!s->ch[ch].sync) + omap_dma_request_stop(s, ch); + } + + if (s->ch[ch].interrupts & 0x08) + s->ch[ch].status |= 0x08; + + if (s->ch[ch].sync && s->ch[ch].fs) { + s->ch[ch].status &= ~0x40; + omap_dma_request_stop(s, ch); + } + } + + if (a->element == 1 && a->frame == a->frames - 1) + if (s->ch[ch].interrupts & 0x10) + s->ch[ch].status |= 0x10; + + if (a->element == (a->elements >> 1)) + if (s->ch[ch].interrupts & 0x04) + s->ch[ch].status |= 0x04; + + if (s->ch[ch].sync && !s->ch[ch].fs) { + s->ch[ch].status &= ~0x40; + omap_dma_request_stop(s, ch); + } + + /* + * Process requests made while the element was + * being transferred. + */ + if (s->ch[ch].post_sync) { + omap_dma_request_run(s, 0, s->ch[ch].post_sync); + s->ch[ch].post_sync = 0; + } + +#if 0 + break; +#endif + } + + s->ch[ch].cpc = a->dest & 0x0000ffff; + } + + omap_dma_interrupts_update(s); + if (s->run_count && s->delay) + qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); +} + +static int omap_dma_ch_reg_read(struct omap_dma_s *s, + int ch, int reg, uint16_t *value) { + switch (reg) { + case 0x00: /* SYS_DMA_CSDP_CH0 */ + *value = (s->ch[ch].burst[1] << 14) | + (s->ch[ch].pack[1] << 13) | + (s->ch[ch].port[1] << 9) | + (s->ch[ch].burst[0] << 7) | + (s->ch[ch].pack[0] << 6) | + (s->ch[ch].port[0] << 2) | + (s->ch[ch].data_type >> 1); + break; + + case 0x02: /* SYS_DMA_CCR_CH0 */ + *value = (s->ch[ch].mode[1] << 14) | + (s->ch[ch].mode[0] << 12) | + (s->ch[ch].end_prog << 11) | + (s->ch[ch].repeat << 9) | + (s->ch[ch].auto_init << 8) | + (s->ch[ch].running << 7) | + (s->ch[ch].priority << 6) | + (s->ch[ch].fs << 5) | s->ch[ch].sync; + break; + + case 0x04: /* SYS_DMA_CICR_CH0 */ + *value = s->ch[ch].interrupts; + break; + + case 0x06: /* SYS_DMA_CSR_CH0 */ + /* FIXME: shared CSR for channels sharing the interrupts */ + *value = s->ch[ch].status; + s->ch[ch].status &= 0x40; + omap_dma_interrupts_update(s); + break; + + case 0x08: /* SYS_DMA_CSSA_L_CH0 */ + *value = s->ch[ch].addr[0] & 0x0000ffff; + break; + + case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ + *value = s->ch[ch].addr[0] >> 16; + break; + + case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ + *value = s->ch[ch].addr[1] & 0x0000ffff; + break; + + case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ + *value = s->ch[ch].addr[1] >> 16; + break; + + case 0x10: /* SYS_DMA_CEN_CH0 */ + *value = s->ch[ch].elements; + break; + + case 0x12: /* SYS_DMA_CFN_CH0 */ + *value = s->ch[ch].frames; + break; + + case 0x14: /* SYS_DMA_CFI_CH0 */ + *value = s->ch[ch].frame_index; + break; + + case 0x16: /* SYS_DMA_CEI_CH0 */ + *value = s->ch[ch].element_index; + break; + + case 0x18: /* SYS_DMA_CPC_CH0 */ + *value = s->ch[ch].cpc; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_ch_reg_write(struct omap_dma_s *s, + int ch, int reg, uint16_t value) { + switch (reg) { + case 0x00: /* SYS_DMA_CSDP_CH0 */ + s->ch[ch].burst[1] = (value & 0xc000) >> 14; + s->ch[ch].pack[1] = (value & 0x2000) >> 13; + s->ch[ch].port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9); + s->ch[ch].burst[0] = (value & 0x0180) >> 7; + s->ch[ch].pack[0] = (value & 0x0040) >> 6; + s->ch[ch].port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2); + s->ch[ch].data_type = (1 << (value & 3)); + if (s->ch[ch].port[0] >= omap_dma_port_last) + printf("%s: invalid DMA port %i\n", __FUNCTION__, + s->ch[ch].port[0]); + if (s->ch[ch].port[1] >= omap_dma_port_last) + printf("%s: invalid DMA port %i\n", __FUNCTION__, + s->ch[ch].port[1]); + if ((value & 3) == 3) + printf("%s: bad data_type for DMA channel %i\n", __FUNCTION__, ch); + break; + + case 0x02: /* SYS_DMA_CCR_CH0 */ + s->ch[ch].mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); + s->ch[ch].mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); + s->ch[ch].end_prog = (value & 0x0800) >> 11; + s->ch[ch].repeat = (value & 0x0200) >> 9; + s->ch[ch].auto_init = (value & 0x0100) >> 8; + s->ch[ch].priority = (value & 0x0040) >> 6; + s->ch[ch].fs = (value & 0x0020) >> 5; + s->ch[ch].sync = value & 0x001f; + if (value & 0x0080) { + if (s->ch[ch].running) { + if (!s->ch[ch].signalled && + s->ch[ch].auto_init && s->ch[ch].end_prog) + omap_dma_channel_load(s, ch); + } else { + s->ch[ch].running = 1; + omap_dma_channel_load(s, ch); + } + if (!s->ch[ch].sync) + omap_dma_request_run(s, ch, 0); + } else { + s->ch[ch].running = 0; + omap_dma_request_stop(s, ch); + } + break; + + case 0x04: /* SYS_DMA_CICR_CH0 */ + s->ch[ch].interrupts = value & 0x003f; + break; + + case 0x06: /* SYS_DMA_CSR_CH0 */ + return 1; + + case 0x08: /* SYS_DMA_CSSA_L_CH0 */ + s->ch[ch].addr[0] &= 0xffff0000; + s->ch[ch].addr[0] |= value; + break; + + case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ + s->ch[ch].addr[0] &= 0x0000ffff; + s->ch[ch].addr[0] |= value << 16; + break; + + case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ + s->ch[ch].addr[1] &= 0xffff0000; + s->ch[ch].addr[1] |= value; + break; + + case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ + s->ch[ch].addr[1] &= 0x0000ffff; + s->ch[ch].addr[1] |= value << 16; + break; + + case 0x10: /* SYS_DMA_CEN_CH0 */ + s->ch[ch].elements = value & 0xffff; + break; + + case 0x12: /* SYS_DMA_CFN_CH0 */ + s->ch[ch].frames = value & 0xffff; + break; + + case 0x14: /* SYS_DMA_CFI_CH0 */ + s->ch[ch].frame_index = value & 0xffff; + break; + + case 0x16: /* SYS_DMA_CEI_CH0 */ + s->ch[ch].element_index = value & 0xffff; + break; + + case 0x18: /* SYS_DMA_CPC_CH0 */ + return 1; + + default: + OMAP_BAD_REG((unsigned long) reg); + } + return 0; +} + +static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int i, reg, ch, offset = addr - s->base; + uint16_t ret; + + switch (offset) { + case 0x000 ... 0x2fe: + reg = offset & 0x3f; + ch = (offset >> 6) & 0x0f; + if (omap_dma_ch_reg_read(s, ch, reg, &ret)) + break; + return ret; + + case 0x300: /* SYS_DMA_LCD_CTRL */ + i = s->lcd_ch.condition; + s->lcd_ch.condition = 0; + qemu_irq_lower(s->lcd_ch.irq); + return ((s->lcd_ch.src == imif) << 6) | (i << 3) | + (s->lcd_ch.interrupts << 1) | s->lcd_ch.dual; + + case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ + return s->lcd_ch.src_f1_top & 0xffff; + + case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ + return s->lcd_ch.src_f1_top >> 16; + + case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ + return s->lcd_ch.src_f1_bottom & 0xffff; + + case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ + return s->lcd_ch.src_f1_bottom >> 16; + + case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ + return s->lcd_ch.src_f2_top & 0xffff; + + case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ + return s->lcd_ch.src_f2_top >> 16; + + case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ + return s->lcd_ch.src_f2_bottom & 0xffff; + + case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ + return s->lcd_ch.src_f2_bottom >> 16; + + case 0x400: /* SYS_DMA_GCR */ + return s->gcr; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_dma_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int reg, ch, offset = addr - s->base; + + switch (offset) { + case 0x000 ... 0x2fe: + reg = offset & 0x3f; + ch = (offset >> 6) & 0x0f; + if (omap_dma_ch_reg_write(s, ch, reg, value)) + OMAP_RO_REG(addr); + break; + + case 0x300: /* SYS_DMA_LCD_CTRL */ + s->lcd_ch.src = (value & 0x40) ? imif : emiff; + s->lcd_ch.condition = 0; + /* Assume no bus errors and thus no BUS_ERROR irq bits. */ + s->lcd_ch.interrupts = (value >> 1) & 1; + s->lcd_ch.dual = value & 1; + break; + + case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ + s->lcd_ch.src_f1_top &= 0xffff0000; + s->lcd_ch.src_f1_top |= 0x0000ffff & value; + break; + + case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ + s->lcd_ch.src_f1_top &= 0x0000ffff; + s->lcd_ch.src_f1_top |= value << 16; + break; + + case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ + s->lcd_ch.src_f1_bottom &= 0xffff0000; + s->lcd_ch.src_f1_bottom |= 0x0000ffff & value; + break; + + case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ + s->lcd_ch.src_f1_bottom &= 0x0000ffff; + s->lcd_ch.src_f1_bottom |= value << 16; + break; + + case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ + s->lcd_ch.src_f2_top &= 0xffff0000; + s->lcd_ch.src_f2_top |= 0x0000ffff & value; + break; + + case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ + s->lcd_ch.src_f2_top &= 0x0000ffff; + s->lcd_ch.src_f2_top |= value << 16; + break; + + case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ + s->lcd_ch.src_f2_bottom &= 0xffff0000; + s->lcd_ch.src_f2_bottom |= 0x0000ffff & value; + break; + + case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ + s->lcd_ch.src_f2_bottom &= 0x0000ffff; + s->lcd_ch.src_f2_bottom |= value << 16; + break; + + case 0x400: /* SYS_DMA_GCR */ + s->gcr = value & 0x000c; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_dma_readfn[] = { + omap_badwidth_read16, + omap_dma_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_dma_writefn[] = { + omap_badwidth_write16, + omap_dma_write, + omap_badwidth_write16, +}; + +static void omap_dma_request(void *opaque, int drq, int req) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + /* All the request pins are edge triggered. */ + if (req) + omap_dma_request_run(s, 0, drq); +} + +static void omap_dma_clk_update(void *opaque, int line, int on) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + + if (on) { + s->delay = ticks_per_sec >> 5; + if (s->run_count) + qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); + } else { + s->delay = 0; + qemu_del_timer(s->tm); + } +} + +static void omap_dma_reset(struct omap_dma_s *s) +{ + int i; + + qemu_del_timer(s->tm); + s->gcr = 0x0004; + s->run_count = 0; + s->lcd_ch.src = emiff; + s->lcd_ch.condition = 0; + s->lcd_ch.interrupts = 0; + s->lcd_ch.dual = 0; + memset(s->ch, 0, sizeof(s->ch)); + for (i = 0; i < s->chans; i ++) + s->ch[i].interrupts = 0x0003; +} + +struct omap_dma_s *omap_dma_init(target_phys_addr_t base, + qemu_irq pic[], struct omap_mpu_state_s *mpu, omap_clk clk) +{ + int iomemtype; + struct omap_dma_s *s = (struct omap_dma_s *) + qemu_mallocz(sizeof(struct omap_dma_s)); + + s->ih = pic; + s->base = base; + s->chans = 9; + s->mpu = mpu; + s->clk = clk; + s->lcd_ch.irq = pic[OMAP_INT_DMA_LCD]; + s->lcd_ch.mpu = mpu; + s->tm = qemu_new_timer(vm_clock, (QEMUTimerCB *) omap_dma_channel_run, s); + omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); + mpu->drq = qemu_allocate_irqs(omap_dma_request, s, 32); + omap_dma_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_dma_readfn, + omap_dma_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +/* DMA ports */ +int omap_validate_emiff_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= OMAP_EMIFF_BASE && addr < OMAP_EMIFF_BASE + s->sdram_size; +} + +int omap_validate_emifs_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= OMAP_EMIFS_BASE && addr < OMAP_EMIFF_BASE; +} + +int omap_validate_imif_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= OMAP_IMIF_BASE && addr < OMAP_IMIF_BASE + s->sram_size; +} + +int omap_validate_tipb_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= 0xfffb0000 && addr < 0xffff0000; +} + +int omap_validate_local_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= OMAP_LOCALBUS_BASE && addr < OMAP_LOCALBUS_BASE + 0x1000000; +} + +int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, + target_phys_addr_t addr) +{ + return addr >= 0xe1010000 && addr < 0xe1020004; +} + +/* MPU OS timers */ +struct omap_mpu_timer_s { + qemu_irq irq; + omap_clk clk; + target_phys_addr_t base; + uint32_t val; + int64_t time; + QEMUTimer *timer; + int64_t rate; + int it_ena; + + int enable; + int ptv; + int ar; + int st; + uint32_t reset_val; +}; + +static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer) +{ + uint64_t distance = qemu_get_clock(vm_clock) - timer->time; + + if (timer->st && timer->enable && timer->rate) + return timer->val - muldiv64(distance >> (timer->ptv + 1), + timer->rate, ticks_per_sec); + else + return timer->val; +} + +static inline void omap_timer_sync(struct omap_mpu_timer_s *timer) +{ + timer->val = omap_timer_read(timer); + timer->time = qemu_get_clock(vm_clock); +} + +static inline void omap_timer_update(struct omap_mpu_timer_s *timer) +{ + int64_t expires; + + if (timer->enable && timer->st && timer->rate) { + timer->val = timer->reset_val; /* Should skip this on clk enable */ + expires = timer->time + muldiv64(timer->val << (timer->ptv + 1), + ticks_per_sec, timer->rate); + qemu_mod_timer(timer->timer, expires); + } else + qemu_del_timer(timer->timer); +} + +static void omap_timer_tick(void *opaque) +{ + struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; + omap_timer_sync(timer); + + if (!timer->ar) { + timer->val = 0; + timer->st = 0; + } + + if (timer->it_ena) + qemu_irq_raise(timer->irq); + omap_timer_update(timer); +} + +static void omap_timer_clk_update(void *opaque, int line, int on) +{ + struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque; + + omap_timer_sync(timer); + timer->rate = on ? omap_clk_getrate(timer->clk) : 0; + omap_timer_update(timer); +} + +static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) +{ + omap_clk_adduser(timer->clk, + qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]); + timer->rate = omap_clk_getrate(timer->clk); +} + +static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* CNTL_TIMER */ + return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st; + + case 0x04: /* LOAD_TIM */ + break; + + case 0x08: /* READ_TIM */ + return omap_timer_read(s); + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* CNTL_TIMER */ + omap_timer_sync(s); + s->enable = (value >> 5) & 1; + s->ptv = (value >> 2) & 7; + s->ar = (value >> 1) & 1; + s->st = value & 1; + omap_timer_update(s); + return; + + case 0x04: /* LOAD_TIM */ + s->reset_val = value; + return; + + case 0x08: /* READ_TIM */ + OMAP_RO_REG(addr); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_mpu_timer_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_mpu_timer_read, +}; + +static CPUWriteMemoryFunc *omap_mpu_timer_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_mpu_timer_write, +}; + +static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) +{ + qemu_del_timer(s->timer); + s->enable = 0; + s->reset_val = 31337; + s->val = 0; + s->ptv = 0; + s->ar = 0; + s->st = 0; + s->it_ena = 1; +} + +struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk) +{ + int iomemtype; + struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) + qemu_mallocz(sizeof(struct omap_mpu_timer_s)); + + s->irq = irq; + s->clk = clk; + s->base = base; + s->timer = qemu_new_timer(vm_clock, omap_timer_tick, s); + omap_mpu_timer_reset(s); + omap_timer_clk_setup(s); + + iomemtype = cpu_register_io_memory(0, omap_mpu_timer_readfn, + omap_mpu_timer_writefn, s); + cpu_register_physical_memory(s->base, 0x100, iomemtype); + + return s; +} + +/* Watchdog timer */ +struct omap_watchdog_timer_s { + struct omap_mpu_timer_s timer; + uint8_t last_wr; + int mode; + int free; + int reset; +}; + +static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + int offset = addr - s->timer.base; + + switch (offset) { + case 0x00: /* CNTL_TIMER */ + return (s->timer.ptv << 9) | (s->timer.ar << 8) | + (s->timer.st << 7) | (s->free << 1); + + case 0x04: /* READ_TIMER */ + return omap_timer_read(&s->timer); + + case 0x08: /* TIMER_MODE */ + return s->mode << 15; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; + int offset = addr - s->timer.base; + + switch (offset) { + case 0x00: /* CNTL_TIMER */ + omap_timer_sync(&s->timer); + s->timer.ptv = (value >> 9) & 7; + s->timer.ar = (value >> 8) & 1; + s->timer.st = (value >> 7) & 1; + s->free = (value >> 1) & 1; + omap_timer_update(&s->timer); + break; + + case 0x04: /* LOAD_TIMER */ + s->timer.reset_val = value & 0xffff; + break; + + case 0x08: /* TIMER_MODE */ + if (!s->mode && ((value >> 15) & 1)) + omap_clk_get(s->timer.clk); + s->mode |= (value >> 15) & 1; + if (s->last_wr == 0xf5) { + if ((value & 0xff) == 0xa0) { + s->mode = 0; + omap_clk_put(s->timer.clk); + } else { + /* XXX: on T|E hardware somehow this has no effect, + * on Zire 71 it works as specified. */ + s->reset = 1; + qemu_system_reset_request(); + } + } + s->last_wr = value & 0xff; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_wd_timer_readfn[] = { + omap_badwidth_read16, + omap_wd_timer_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_wd_timer_writefn[] = { + omap_badwidth_write16, + omap_wd_timer_write, + omap_badwidth_write16, +}; + +static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) +{ + qemu_del_timer(s->timer.timer); + if (!s->mode) + omap_clk_get(s->timer.clk); + s->mode = 1; + s->free = 1; + s->reset = 0; + s->timer.enable = 1; + s->timer.it_ena = 1; + s->timer.reset_val = 0xffff; + s->timer.val = 0; + s->timer.st = 0; + s->timer.ptv = 0; + s->timer.ar = 0; + omap_timer_update(&s->timer); +} + +struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk) +{ + int iomemtype; + struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) + qemu_mallocz(sizeof(struct omap_watchdog_timer_s)); + + s->timer.irq = irq; + s->timer.clk = clk; + s->timer.base = base; + s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer); + omap_wd_timer_reset(s); + omap_timer_clk_setup(&s->timer); + + iomemtype = cpu_register_io_memory(0, omap_wd_timer_readfn, + omap_wd_timer_writefn, s); + cpu_register_physical_memory(s->timer.base, 0x100, iomemtype); + + return s; +} + +/* 32-kHz timer */ +struct omap_32khz_timer_s { + struct omap_mpu_timer_s timer; +}; + +static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; + int offset = addr - s->timer.base; + + switch (offset) { + case 0x00: /* TVR */ + return s->timer.reset_val; + + case 0x04: /* TCR */ + return omap_timer_read(&s->timer); + + case 0x08: /* CR */ + return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st; + + default: + break; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_os_timer_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; + int offset = addr - s->timer.base; + + switch (offset) { + case 0x00: /* TVR */ + s->timer.reset_val = value & 0x00ffffff; + break; + + case 0x04: /* TCR */ + OMAP_RO_REG(addr); + break; + + case 0x08: /* CR */ + s->timer.ar = (value >> 3) & 1; + s->timer.it_ena = (value >> 2) & 1; + if (s->timer.st != (value & 1) || (value & 2)) { + omap_timer_sync(&s->timer); + s->timer.enable = value & 1; + s->timer.st = value & 1; + omap_timer_update(&s->timer); + } + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_os_timer_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_os_timer_read, +}; + +static CPUWriteMemoryFunc *omap_os_timer_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_os_timer_write, +}; + +static void omap_os_timer_reset(struct omap_32khz_timer_s *s) +{ + qemu_del_timer(s->timer.timer); + s->timer.enable = 0; + s->timer.it_ena = 0; + s->timer.reset_val = 0x00ffffff; + s->timer.val = 0; + s->timer.st = 0; + s->timer.ptv = 0; + s->timer.ar = 1; +} + +struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk) +{ + int iomemtype; + struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) + qemu_mallocz(sizeof(struct omap_32khz_timer_s)); + + s->timer.irq = irq; + s->timer.clk = clk; + s->timer.base = base; + s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer); + omap_os_timer_reset(s); + omap_timer_clk_setup(&s->timer); + + iomemtype = cpu_register_io_memory(0, omap_os_timer_readfn, + omap_os_timer_writefn, s); + cpu_register_physical_memory(s->timer.base, 0x800, iomemtype); + + return s; +} + +/* Ultra Low-Power Device Module */ +static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->ulpd_pm_base; + uint16_t ret; + + switch (offset) { + case 0x14: /* IT_STATUS */ + ret = s->ulpd_pm_regs[offset >> 2]; + s->ulpd_pm_regs[offset >> 2] = 0; + qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]); + return ret; + + case 0x18: /* Reserved */ + case 0x1c: /* Reserved */ + case 0x20: /* Reserved */ + case 0x28: /* Reserved */ + case 0x2c: /* Reserved */ + OMAP_BAD_REG(addr); + case 0x00: /* COUNTER_32_LSB */ + case 0x04: /* COUNTER_32_MSB */ + case 0x08: /* COUNTER_HIGH_FREQ_LSB */ + case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ + case 0x10: /* GAUGING_CTRL */ + case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ + case 0x30: /* CLOCK_CTRL */ + case 0x34: /* SOFT_REQ */ + case 0x38: /* COUNTER_32_FIQ */ + case 0x3c: /* DPLL_CTRL */ + case 0x40: /* STATUS_REQ */ + /* XXX: check clk::usecount state for every clock */ + case 0x48: /* LOCL_TIME */ + case 0x4c: /* APLL_CTRL */ + case 0x50: /* POWER_CTRL */ + return s->ulpd_pm_regs[offset >> 2]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + if (diff & (1 << 4)) /* USB_MCLK_EN */ + omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1); + if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ + omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1); +} + +static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ + omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1); + if (diff & (1 << 1)) /* SOFT_COM_REQ */ + omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1); + if (diff & (1 << 2)) /* SOFT_SDW_REQ */ + omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1); + if (diff & (1 << 3)) /* SOFT_USB_REQ */ + omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1); +} + +static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->ulpd_pm_base; + int64_t now, ticks; + int div, mult; + static const int bypass_div[4] = { 1, 2, 4, 4 }; + uint16_t diff; + + switch (offset) { + case 0x00: /* COUNTER_32_LSB */ + case 0x04: /* COUNTER_32_MSB */ + case 0x08: /* COUNTER_HIGH_FREQ_LSB */ + case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ + case 0x14: /* IT_STATUS */ + case 0x40: /* STATUS_REQ */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* GAUGING_CTRL */ + /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ + if ((s->ulpd_pm_regs[offset >> 2] ^ value) & 1) { + now = qemu_get_clock(vm_clock); + + if (value & 1) + s->ulpd_gauge_start = now; + else { + now -= s->ulpd_gauge_start; + + /* 32-kHz ticks */ + ticks = muldiv64(now, 32768, ticks_per_sec); + s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; + s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; + if (ticks >> 32) /* OVERFLOW_32K */ + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; + + /* High frequency ticks */ + ticks = muldiv64(now, 12000000, ticks_per_sec); + s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; + s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; + if (ticks >> 32) /* OVERFLOW_HI_FREQ */ + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1; + + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ + qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]); + } + } + s->ulpd_pm_regs[offset >> 2] = value; + break; + + case 0x18: /* Reserved */ + case 0x1c: /* Reserved */ + case 0x20: /* Reserved */ + case 0x28: /* Reserved */ + case 0x2c: /* Reserved */ + OMAP_BAD_REG(addr); + case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ + case 0x38: /* COUNTER_32_FIQ */ + case 0x48: /* LOCL_TIME */ + case 0x50: /* POWER_CTRL */ + s->ulpd_pm_regs[offset >> 2] = value; + break; + + case 0x30: /* CLOCK_CTRL */ + diff = s->ulpd_pm_regs[offset >> 2] ^ value; + s->ulpd_pm_regs[offset >> 2] = value & 0x3f; + omap_ulpd_clk_update(s, diff, value); + break; + + case 0x34: /* SOFT_REQ */ + diff = s->ulpd_pm_regs[offset >> 2] ^ value; + s->ulpd_pm_regs[offset >> 2] = value & 0x1f; + omap_ulpd_req_update(s, diff, value); + break; + + case 0x3c: /* DPLL_CTRL */ + /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is + * omitted altogether, probably a typo. */ + /* This register has identical semantics with DPLL(1:3) control + * registers, see omap_dpll_write() */ + diff = s->ulpd_pm_regs[offset >> 2] & value; + s->ulpd_pm_regs[offset >> 2] = value & 0x2fff; + if (diff & (0x3ff << 2)) { + if (value & (1 << 4)) { /* PLL_ENABLE */ + div = ((value >> 5) & 3) + 1; /* PLL_DIV */ + mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ + } else { + div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ + mult = 1; + } + omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult); + } + + /* Enter the desired mode. */ + s->ulpd_pm_regs[offset >> 2] = + (s->ulpd_pm_regs[offset >> 2] & 0xfffe) | + ((s->ulpd_pm_regs[offset >> 2] >> 4) & 1); + + /* Act as if the lock is restored. */ + s->ulpd_pm_regs[offset >> 2] |= 2; + break; + + case 0x4c: /* APLL_CTRL */ + diff = s->ulpd_pm_regs[offset >> 2] & value; + s->ulpd_pm_regs[offset >> 2] = value & 0xf; + if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */ + omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s, + (value & (1 << 0)) ? "apll" : "dpll4")); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_ulpd_pm_readfn[] = { + omap_badwidth_read16, + omap_ulpd_pm_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_ulpd_pm_writefn[] = { + omap_badwidth_write16, + omap_ulpd_pm_write, + omap_badwidth_write16, +}; + +static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) +{ + mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x18 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x1c >> 2] = 0x01; + mpu->ulpd_pm_regs[0x20 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff; + mpu->ulpd_pm_regs[0x28 >> 2] = 0x01; + mpu->ulpd_pm_regs[0x2c >> 2] = 0x01; + omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000); + mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000; + omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000); + mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000; + mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001; + mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211; + mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */ + mpu->ulpd_pm_regs[0x48 >> 2] = 0x960; + mpu->ulpd_pm_regs[0x4c >> 2] = 0x08; + mpu->ulpd_pm_regs[0x50 >> 2] = 0x08; + omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4); + omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4")); +} + +static void omap_ulpd_pm_init(target_phys_addr_t base, + struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_ulpd_pm_readfn, + omap_ulpd_pm_writefn, mpu); + + mpu->ulpd_pm_base = base; + cpu_register_physical_memory(mpu->ulpd_pm_base, 0x800, iomemtype); + omap_ulpd_pm_reset(mpu); +} + +/* OMAP Pin Configuration */ +static uint32_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->pin_cfg_base; + + switch (offset) { + case 0x00: /* FUNC_MUX_CTRL_0 */ + case 0x04: /* FUNC_MUX_CTRL_1 */ + case 0x08: /* FUNC_MUX_CTRL_2 */ + return s->func_mux_ctrl[offset >> 2]; + + case 0x0c: /* COMP_MODE_CTRL_0 */ + return s->comp_mode_ctrl[0]; + + case 0x10: /* FUNC_MUX_CTRL_3 */ + case 0x14: /* FUNC_MUX_CTRL_4 */ + case 0x18: /* FUNC_MUX_CTRL_5 */ + case 0x1c: /* FUNC_MUX_CTRL_6 */ + case 0x20: /* FUNC_MUX_CTRL_7 */ + case 0x24: /* FUNC_MUX_CTRL_8 */ + case 0x28: /* FUNC_MUX_CTRL_9 */ + case 0x2c: /* FUNC_MUX_CTRL_A */ + case 0x30: /* FUNC_MUX_CTRL_B */ + case 0x34: /* FUNC_MUX_CTRL_C */ + case 0x38: /* FUNC_MUX_CTRL_D */ + return s->func_mux_ctrl[(offset >> 2) - 1]; + + case 0x40: /* PULL_DWN_CTRL_0 */ + case 0x44: /* PULL_DWN_CTRL_1 */ + case 0x48: /* PULL_DWN_CTRL_2 */ + case 0x4c: /* PULL_DWN_CTRL_3 */ + return s->pull_dwn_ctrl[(offset & 0xf) >> 2]; + + case 0x50: /* GATE_INH_CTRL_0 */ + return s->gate_inh_ctrl[0]; + + case 0x60: /* VOLTAGE_CTRL_0 */ + return s->voltage_ctrl[0]; + + case 0x70: /* TEST_DBG_CTRL_0 */ + return s->test_dbg_ctrl[0]; + + case 0x80: /* MOD_CONF_CTRL_0 */ + return s->mod_conf_ctrl[0]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (s->compat1509) { + if (diff & (1 << 9)) /* BLUETOOTH */ + omap_clk_onoff(omap_findclk(s, "bt_mclk_out"), + (~value >> 9) & 1); + if (diff & (1 << 7)) /* USB.CLKO */ + omap_clk_onoff(omap_findclk(s, "usb.clko"), + (value >> 7) & 1); + } +} + +static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (s->compat1509) { + if (diff & (1 << 31)) /* MCBSP3_CLK_HIZ_DI */ + omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"), + (value >> 31) & 1); + if (diff & (1 << 1)) /* CLK32K */ + omap_clk_onoff(omap_findclk(s, "clk32k_out"), + (~value >> 1) & 1); + } +} + +static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, + uint32_t diff, uint32_t value) +{ + if (diff & (1 << 31)) /* CONF_MOD_UART3_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart3_ck"), + omap_findclk(s, ((value >> 31) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart2_ck"), + omap_findclk(s, ((value >> 30) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */ + omap_clk_reparent(omap_findclk(s, "uart1_ck"), + omap_findclk(s, ((value >> 29) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */ + omap_clk_reparent(omap_findclk(s, "mmc_ck"), + omap_findclk(s, ((value >> 23) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */ + omap_clk_reparent(omap_findclk(s, "com_mclk_out"), + omap_findclk(s, ((value >> 12) & 1) ? + "ck_48m" : "armper_ck")); + if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */ + omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1); +} + +static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->pin_cfg_base; + uint32_t diff; + + switch (offset) { + case 0x00: /* FUNC_MUX_CTRL_0 */ + diff = s->func_mux_ctrl[offset >> 2] ^ value; + s->func_mux_ctrl[offset >> 2] = value; + omap_pin_funcmux0_update(s, diff, value); + return; + + case 0x04: /* FUNC_MUX_CTRL_1 */ + diff = s->func_mux_ctrl[offset >> 2] ^ value; + s->func_mux_ctrl[offset >> 2] = value; + omap_pin_funcmux1_update(s, diff, value); + return; + + case 0x08: /* FUNC_MUX_CTRL_2 */ + s->func_mux_ctrl[offset >> 2] = value; + return; + + case 0x0c: /* COMP_MODE_CTRL_0 */ + s->comp_mode_ctrl[0] = value; + s->compat1509 = (value != 0x0000eaef); + omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]); + omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]); + return; + + case 0x10: /* FUNC_MUX_CTRL_3 */ + case 0x14: /* FUNC_MUX_CTRL_4 */ + case 0x18: /* FUNC_MUX_CTRL_5 */ + case 0x1c: /* FUNC_MUX_CTRL_6 */ + case 0x20: /* FUNC_MUX_CTRL_7 */ + case 0x24: /* FUNC_MUX_CTRL_8 */ + case 0x28: /* FUNC_MUX_CTRL_9 */ + case 0x2c: /* FUNC_MUX_CTRL_A */ + case 0x30: /* FUNC_MUX_CTRL_B */ + case 0x34: /* FUNC_MUX_CTRL_C */ + case 0x38: /* FUNC_MUX_CTRL_D */ + s->func_mux_ctrl[(offset >> 2) - 1] = value; + return; + + case 0x40: /* PULL_DWN_CTRL_0 */ + case 0x44: /* PULL_DWN_CTRL_1 */ + case 0x48: /* PULL_DWN_CTRL_2 */ + case 0x4c: /* PULL_DWN_CTRL_3 */ + s->pull_dwn_ctrl[(offset & 0xf) >> 2] = value; + return; + + case 0x50: /* GATE_INH_CTRL_0 */ + s->gate_inh_ctrl[0] = value; + return; + + case 0x60: /* VOLTAGE_CTRL_0 */ + s->voltage_ctrl[0] = value; + return; + + case 0x70: /* TEST_DBG_CTRL_0 */ + s->test_dbg_ctrl[0] = value; + return; + + case 0x80: /* MOD_CONF_CTRL_0 */ + diff = s->mod_conf_ctrl[0] ^ value; + s->mod_conf_ctrl[0] = value; + omap_pin_modconf1_update(s, diff, value); + return; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_pin_cfg_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_pin_cfg_read, +}; + +static CPUWriteMemoryFunc *omap_pin_cfg_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_pin_cfg_write, +}; + +static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) +{ + /* Start in Compatibility Mode. */ + mpu->compat1509 = 1; + omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0); + omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0); + omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0); + memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl)); + memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl)); + memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl)); + memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl)); + memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl)); + memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl)); + memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl)); +} + +static void omap_pin_cfg_init(target_phys_addr_t base, + struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_pin_cfg_readfn, + omap_pin_cfg_writefn, mpu); + + mpu->pin_cfg_base = base; + cpu_register_physical_memory(mpu->pin_cfg_base, 0x800, iomemtype); + omap_pin_cfg_reset(mpu); +} + +/* Device Identification, Die Identification */ +static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + switch (addr) { + case 0xfffe1800: /* DIE_ID_LSB */ + return 0xc9581f0e; + case 0xfffe1804: /* DIE_ID_MSB */ + return 0xa8858bfa; + + case 0xfffe2000: /* PRODUCT_ID_LSB */ + return 0x00aaaafc; + case 0xfffe2004: /* PRODUCT_ID_MSB */ + return 0xcafeb574; + + case 0xfffed400: /* JTAG_ID_LSB */ + switch (s->mpu_model) { + case omap310: + return 0x03310315; + case omap1510: + return 0x03310115; + } + break; + + case 0xfffed404: /* JTAG_ID_MSB */ + switch (s->mpu_model) { + case omap310: + return 0xfb57402f; + case omap1510: + return 0xfb47002f; + } + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_id_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + OMAP_BAD_REG(addr); +} + +static CPUReadMemoryFunc *omap_id_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_id_read, +}; + +static CPUWriteMemoryFunc *omap_id_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_id_write, +}; + +static void omap_id_init(struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_id_readfn, + omap_id_writefn, mpu); + cpu_register_physical_memory(0xfffe1800, 0x800, iomemtype); + cpu_register_physical_memory(0xfffed400, 0x100, iomemtype); + if (!cpu_is_omap15xx(mpu)) + cpu_register_physical_memory(0xfffe2000, 0x800, iomemtype); +} + +/* MPUI Control (Dummy) */ +static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->mpui_base; + + switch (offset) { + case 0x00: /* CTRL */ + return s->mpui_ctrl; + case 0x04: /* DEBUG_ADDR */ + return 0x01ffffff; + case 0x08: /* DEBUG_DATA */ + return 0xffffffff; + case 0x0c: /* DEBUG_FLAG */ + return 0x00000800; + case 0x10: /* STATUS */ + return 0x00000000; + + /* Not in OMAP310 */ + case 0x14: /* DSP_STATUS */ + case 0x18: /* DSP_BOOT_CONFIG */ + return 0x00000000; + case 0x1c: /* DSP_MPUI_CONFIG */ + return 0x0000ffff; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpui_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->mpui_base; + + switch (offset) { + case 0x00: /* CTRL */ + s->mpui_ctrl = value & 0x007fffff; + break; + + case 0x04: /* DEBUG_ADDR */ + case 0x08: /* DEBUG_DATA */ + case 0x0c: /* DEBUG_FLAG */ + case 0x10: /* STATUS */ + /* Not in OMAP310 */ + case 0x14: /* DSP_STATUS */ + OMAP_RO_REG(addr); + case 0x18: /* DSP_BOOT_CONFIG */ + case 0x1c: /* DSP_MPUI_CONFIG */ + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_mpui_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_mpui_read, +}; + +static CPUWriteMemoryFunc *omap_mpui_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_mpui_write, +}; + +static void omap_mpui_reset(struct omap_mpu_state_s *s) +{ + s->mpui_ctrl = 0x0003ff1b; +} + +static void omap_mpui_init(target_phys_addr_t base, + struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_mpui_readfn, + omap_mpui_writefn, mpu); + + mpu->mpui_base = base; + cpu_register_physical_memory(mpu->mpui_base, 0x100, iomemtype); + + omap_mpui_reset(mpu); +} + +/* TIPB Bridges */ +struct omap_tipb_bridge_s { + target_phys_addr_t base; + qemu_irq abort; + + int width_intr; + uint16_t control; + uint16_t alloc; + uint16_t buffer; + uint16_t enh_control; +}; + +static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* TIPB_CNTL */ + return s->control; + case 0x04: /* TIPB_BUS_ALLOC */ + return s->alloc; + case 0x08: /* MPU_TIPB_CNTL */ + return s->buffer; + case 0x0c: /* ENHANCED_TIPB_CNTL */ + return s->enh_control; + case 0x10: /* ADDRESS_DBG */ + case 0x14: /* DATA_DEBUG_LOW */ + case 0x18: /* DATA_DEBUG_HIGH */ + return 0xffff; + case 0x1c: /* DEBUG_CNTR_SIG */ + return 0x00f8; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* TIPB_CNTL */ + s->control = value & 0xffff; + break; + + case 0x04: /* TIPB_BUS_ALLOC */ + s->alloc = value & 0x003f; + break; + + case 0x08: /* MPU_TIPB_CNTL */ + s->buffer = value & 0x0003; + break; + + case 0x0c: /* ENHANCED_TIPB_CNTL */ + s->width_intr = !(value & 2); + s->enh_control = value & 0x000f; + break; + + case 0x10: /* ADDRESS_DBG */ + case 0x14: /* DATA_DEBUG_LOW */ + case 0x18: /* DATA_DEBUG_HIGH */ + case 0x1c: /* DEBUG_CNTR_SIG */ + OMAP_RO_REG(addr); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_tipb_bridge_readfn[] = { + omap_badwidth_read16, + omap_tipb_bridge_read, + omap_tipb_bridge_read, +}; + +static CPUWriteMemoryFunc *omap_tipb_bridge_writefn[] = { + omap_badwidth_write16, + omap_tipb_bridge_write, + omap_tipb_bridge_write, +}; + +static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) +{ + s->control = 0xffff; + s->alloc = 0x0009; + s->buffer = 0x0000; + s->enh_control = 0x000f; +} + +struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base, + qemu_irq abort_irq, omap_clk clk) +{ + int iomemtype; + struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) + qemu_mallocz(sizeof(struct omap_tipb_bridge_s)); + + s->abort = abort_irq; + s->base = base; + omap_tipb_bridge_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_tipb_bridge_readfn, + omap_tipb_bridge_writefn, s); + cpu_register_physical_memory(s->base, 0x100, iomemtype); + + return s; +} + +/* Dummy Traffic Controller's Memory Interface */ +static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->tcmi_base; + uint32_t ret; + + switch (offset) { + case 0xfffecc00: /* IMIF_PRIO */ + case 0xfffecc04: /* EMIFS_PRIO */ + case 0xfffecc08: /* EMIFF_PRIO */ + case 0xfffecc0c: /* EMIFS_CONFIG */ + case 0xfffecc10: /* EMIFS_CS0_CONFIG */ + case 0xfffecc14: /* EMIFS_CS1_CONFIG */ + case 0xfffecc18: /* EMIFS_CS2_CONFIG */ + case 0xfffecc1c: /* EMIFS_CS3_CONFIG */ + case 0xfffecc24: /* EMIFF_MRS */ + case 0xfffecc28: /* TIMEOUT1 */ + case 0xfffecc2c: /* TIMEOUT2 */ + case 0xfffecc30: /* TIMEOUT3 */ + case 0xfffecc3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0xfffecc40: /* EMIFS_CFG_DYN_WAIT */ + return s->tcmi_regs[offset >> 2]; + + case 0xfffecc20: /* EMIFF_SDRAM_CONFIG */ + ret = s->tcmi_regs[offset >> 2]; + s->tcmi_regs[offset >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ + /* XXX: We can try using the VGA_DIRTY flag for this */ + return ret; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_tcmi_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->tcmi_base; + + switch (offset) { + case 0xfffecc00: /* IMIF_PRIO */ + case 0xfffecc04: /* EMIFS_PRIO */ + case 0xfffecc08: /* EMIFF_PRIO */ + case 0xfffecc10: /* EMIFS_CS0_CONFIG */ + case 0xfffecc14: /* EMIFS_CS1_CONFIG */ + case 0xfffecc18: /* EMIFS_CS2_CONFIG */ + case 0xfffecc1c: /* EMIFS_CS3_CONFIG */ + case 0xfffecc20: /* EMIFF_SDRAM_CONFIG */ + case 0xfffecc24: /* EMIFF_MRS */ + case 0xfffecc28: /* TIMEOUT1 */ + case 0xfffecc2c: /* TIMEOUT2 */ + case 0xfffecc30: /* TIMEOUT3 */ + case 0xfffecc3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0xfffecc40: /* EMIFS_CFG_DYN_WAIT */ + s->tcmi_regs[offset >> 2] = value; + break; + case 0xfffecc0c: /* EMIFS_CONFIG */ + s->tcmi_regs[offset >> 2] = (value & 0xf) | (1 << 4); + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_tcmi_readfn[] = { + omap_badwidth_read32, + omap_badwidth_read32, + omap_tcmi_read, +}; + +static CPUWriteMemoryFunc *omap_tcmi_writefn[] = { + omap_badwidth_write32, + omap_badwidth_write32, + omap_tcmi_write, +}; + +static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) +{ + mpu->tcmi_regs[0x00 >> 2] = 0x00000000; + mpu->tcmi_regs[0x04 >> 2] = 0x00000000; + mpu->tcmi_regs[0x08 >> 2] = 0x00000000; + mpu->tcmi_regs[0x0c >> 2] = 0x00000010; + mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb; + mpu->tcmi_regs[0x20 >> 2] = 0x00618800; + mpu->tcmi_regs[0x24 >> 2] = 0x00000037; + mpu->tcmi_regs[0x28 >> 2] = 0x00000000; + mpu->tcmi_regs[0x2c >> 2] = 0x00000000; + mpu->tcmi_regs[0x30 >> 2] = 0x00000000; + mpu->tcmi_regs[0x3c >> 2] = 0x00000003; + mpu->tcmi_regs[0x40 >> 2] = 0x00000000; +} + +static void omap_tcmi_init(target_phys_addr_t base, + struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_tcmi_readfn, + omap_tcmi_writefn, mpu); + + mpu->tcmi_base = base; + cpu_register_physical_memory(mpu->tcmi_base, 0x100, iomemtype); + omap_tcmi_reset(mpu); +} + +/* Digital phase-locked loops control */ +static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr) +{ + struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + int offset = addr - s->base; + + if (offset == 0x00) /* CTL_REG */ + return s->mode; + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_dpll_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; + uint16_t diff; + int offset = addr - s->base; + static const int bypass_div[4] = { 1, 2, 4, 4 }; + int div, mult; + + if (offset == 0x00) { /* CTL_REG */ + /* See omap_ulpd_pm_write() too */ + diff = s->mode & value; + s->mode = value & 0x2fff; + if (diff & (0x3ff << 2)) { + if (value & (1 << 4)) { /* PLL_ENABLE */ + div = ((value >> 5) & 3) + 1; /* PLL_DIV */ + mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ + } else { + div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ + mult = 1; + } + omap_clk_setrate(s->dpll, div, mult); + } + + /* Enter the desired mode. */ + s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1); + + /* Act as if the lock is restored. */ + s->mode |= 2; + } else { + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_dpll_readfn[] = { + omap_badwidth_read16, + omap_dpll_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_dpll_writefn[] = { + omap_badwidth_write16, + omap_dpll_write, + omap_badwidth_write16, +}; + +static void omap_dpll_reset(struct dpll_ctl_s *s) +{ + s->mode = 0x2002; + omap_clk_setrate(s->dpll, 1, 1); +} + +static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base, + omap_clk clk) +{ + int iomemtype = cpu_register_io_memory(0, omap_dpll_readfn, + omap_dpll_writefn, s); + + s->base = base; + s->dpll = clk; + omap_dpll_reset(s); + + cpu_register_physical_memory(s->base, 0x100, iomemtype); +} + +/* UARTs */ +struct omap_uart_s { + SerialState *serial; /* TODO */ +}; + +static void omap_uart_reset(struct omap_uart_s *s) +{ +} + +struct omap_uart_s *omap_uart_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk, CharDriverState *chr) +{ + struct omap_uart_s *s = (struct omap_uart_s *) + qemu_mallocz(sizeof(struct omap_uart_s)); + if (chr) + s->serial = serial_mm_init(base, 2, irq, chr, 1); + return s; +} + +/* MPU Clock/Reset/Power Mode Control */ +static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->clkm.mpu_base; + + switch (offset) { + case 0x00: /* ARM_CKCTL */ + return s->clkm.arm_ckctl; + + case 0x04: /* ARM_IDLECT1 */ + return s->clkm.arm_idlect1; + + case 0x08: /* ARM_IDLECT2 */ + return s->clkm.arm_idlect2; + + case 0x0c: /* ARM_EWUPCT */ + return s->clkm.arm_ewupct; + + case 0x10: /* ARM_RSTCT1 */ + return s->clkm.arm_rstct1; + + case 0x14: /* ARM_RSTCT2 */ + return s->clkm.arm_rstct2; + + case 0x18: /* ARM_SYSST */ + return (s->clkm.clocking_scheme < 11) | s->clkm.cold_start; + + case 0x1c: /* ARM_CKOUT1 */ + return s->clkm.arm_ckout1; + + case 0x20: /* ARM_CKOUT2 */ + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */ + if (value & (1 << 14)) + /* Reserved */; + else { + clk = omap_findclk(s, "arminth_ck"); + omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); + } + } + if (diff & (1 << 12)) { /* ARM_TIMXO */ + clk = omap_findclk(s, "armtim_ck"); + if (value & (1 << 12)) + omap_clk_reparent(clk, omap_findclk(s, "clkin")); + else + omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); + } + /* XXX: en_dspck */ + if (diff & (3 << 10)) { /* DSPMMUDIV */ + clk = omap_findclk(s, "dspmmu_ck"); + omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1); + } + if (diff & (3 << 8)) { /* TCDIV */ + clk = omap_findclk(s, "tc_ck"); + omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1); + } + if (diff & (3 << 6)) { /* DSPDIV */ + clk = omap_findclk(s, "dsp_ck"); + omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1); + } + if (diff & (3 << 4)) { /* ARMDIV */ + clk = omap_findclk(s, "arm_ck"); + omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1); + } + if (diff & (3 << 2)) { /* LCDDIV */ + clk = omap_findclk(s, "lcd_ck"); + omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1); + } + if (diff & (3 << 0)) { /* PERDIV */ + clk = omap_findclk(s, "armper_ck"); + omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1); + } +} + +static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (value & (1 << 11)) /* SETARM_IDLE */ + cpu_interrupt(s->env, CPU_INTERRUPT_HALT); + if (!(value & (1 << 10))) /* WKUP_MODE */ + qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */ + +#define SET_CANIDLE(clock, bit) \ + if (diff & (1 << bit)) { \ + clk = omap_findclk(s, clock); \ + omap_clk_canidle(clk, (value >> bit) & 1); \ + } + SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */ + SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */ + SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */ + SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */ + SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */ + SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */ + SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */ + SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */ +} + +static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + +#define SET_ONOFF(clock, bit) \ + if (diff & (1 << bit)) { \ + clk = omap_findclk(s, clock); \ + omap_clk_onoff(clk, (value >> bit) & 1); \ + } + SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */ + SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */ + SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */ + SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */ + SET_ONOFF("lb_ck", 4) /* EN_LBCK */ + SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */ + SET_ONOFF("mpui_ck", 6) /* EN_APICK */ + SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */ + SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */ + SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */ + SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */ +} + +static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + if (diff & (3 << 4)) { /* TCLKOUT */ + clk = omap_findclk(s, "tclk_out"); + switch ((value >> 4) & 3) { + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen3")); + omap_clk_onoff(clk, 1); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); + omap_clk_onoff(clk, 1); + break; + default: + omap_clk_onoff(clk, 0); + } + } + if (diff & (3 << 2)) { /* DCLKOUT */ + clk = omap_findclk(s, "dclk_out"); + switch ((value >> 2) & 3) { + case 0: + omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck")); + break; + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen2")); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "dsp_ck")); + break; + case 3: + omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); + break; + } + } + if (diff & (3 << 0)) { /* ACLKOUT */ + clk = omap_findclk(s, "aclk_out"); + switch ((value >> 0) & 3) { + case 1: + omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); + omap_clk_onoff(clk, 1); + break; + case 2: + omap_clk_reparent(clk, omap_findclk(s, "arm_ck")); + omap_clk_onoff(clk, 1); + break; + case 3: + omap_clk_reparent(clk, omap_findclk(s, "ck_ref14")); + omap_clk_onoff(clk, 1); + break; + default: + omap_clk_onoff(clk, 0); + } + } +} + +static void omap_clkm_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->clkm.mpu_base; + uint16_t diff; + omap_clk clk; + static const char *clkschemename[8] = { + "fully synchronous", "fully asynchronous", "synchronous scalable", + "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4", + }; + + switch (offset) { + case 0x00: /* ARM_CKCTL */ + diff = s->clkm.arm_ckctl ^ value; + s->clkm.arm_ckctl = value & 0x7fff; + omap_clkm_ckctl_update(s, diff, value); + return; + + case 0x04: /* ARM_IDLECT1 */ + diff = s->clkm.arm_idlect1 ^ value; + s->clkm.arm_idlect1 = value & 0x0fff; + omap_clkm_idlect1_update(s, diff, value); + return; + + case 0x08: /* ARM_IDLECT2 */ + diff = s->clkm.arm_idlect2 ^ value; + s->clkm.arm_idlect2 = value & 0x07ff; + omap_clkm_idlect2_update(s, diff, value); + return; + + case 0x0c: /* ARM_EWUPCT */ + diff = s->clkm.arm_ewupct ^ value; + s->clkm.arm_ewupct = value & 0x003f; + return; + + case 0x10: /* ARM_RSTCT1 */ + diff = s->clkm.arm_rstct1 ^ value; + s->clkm.arm_rstct1 = value & 0x0007; + if (value & 9) { + qemu_system_reset_request(); + s->clkm.cold_start = 0xa; + } + if (diff & ~value & 4) { /* DSP_RST */ + omap_mpui_reset(s); + omap_tipb_bridge_reset(s->private_tipb); + omap_tipb_bridge_reset(s->public_tipb); + } + if (diff & 2) { /* DSP_EN */ + clk = omap_findclk(s, "dsp_ck"); + omap_clk_canidle(clk, (~value >> 1) & 1); + } + return; + + case 0x14: /* ARM_RSTCT2 */ + s->clkm.arm_rstct2 = value & 0x0001; + return; + + case 0x18: /* ARM_SYSST */ + if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) { + s->clkm.clocking_scheme = (value >> 11) & 7; + printf("%s: clocking scheme set to %s\n", __FUNCTION__, + clkschemename[s->clkm.clocking_scheme]); + } + s->clkm.cold_start &= value & 0x3f; + return; + + case 0x1c: /* ARM_CKOUT1 */ + diff = s->clkm.arm_ckout1 ^ value; + s->clkm.arm_ckout1 = value & 0x003f; + omap_clkm_ckout1_update(s, diff, value); + return; + + case 0x20: /* ARM_CKOUT2 */ + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_clkm_readfn[] = { + omap_badwidth_read16, + omap_clkm_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_clkm_writefn[] = { + omap_badwidth_write16, + omap_clkm_write, + omap_badwidth_write16, +}; + +static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->clkm.dsp_base; + + switch (offset) { + case 0x04: /* DSP_IDLECT1 */ + return s->clkm.dsp_idlect1; + + case 0x08: /* DSP_IDLECT2 */ + return s->clkm.dsp_idlect2; + + case 0x14: /* DSP_RSTCT2 */ + return s->clkm.dsp_rstct2; + + case 0x18: /* DSP_SYSST */ + return (s->clkm.clocking_scheme < 11) | s->clkm.cold_start | + (s->env->halted << 6); /* Quite useless... */ + } + + OMAP_BAD_REG(addr); + return 0; +} + +static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */ +} + +static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, + uint16_t diff, uint16_t value) +{ + omap_clk clk; + + SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ +} + +static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->clkm.dsp_base; + uint16_t diff; + + switch (offset) { + case 0x04: /* DSP_IDLECT1 */ + diff = s->clkm.dsp_idlect1 ^ value; + s->clkm.dsp_idlect1 = value & 0x01f7; + omap_clkdsp_idlect1_update(s, diff, value); + break; + + case 0x08: /* DSP_IDLECT2 */ + s->clkm.dsp_idlect2 = value & 0x0037; + diff = s->clkm.dsp_idlect1 ^ value; + omap_clkdsp_idlect2_update(s, diff, value); + break; + + case 0x14: /* DSP_RSTCT2 */ + s->clkm.dsp_rstct2 = value & 0x0001; + break; + + case 0x18: /* DSP_SYSST */ + s->clkm.cold_start &= value & 0x3f; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_clkdsp_readfn[] = { + omap_badwidth_read16, + omap_clkdsp_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_clkdsp_writefn[] = { + omap_badwidth_write16, + omap_clkdsp_write, + omap_badwidth_write16, +}; + +static void omap_clkm_reset(struct omap_mpu_state_s *s) +{ + if (s->wdt && s->wdt->reset) + s->clkm.cold_start = 0x6; + s->clkm.clocking_scheme = 0; + omap_clkm_ckctl_update(s, ~0, 0x3000); + s->clkm.arm_ckctl = 0x3000; + omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 & 0x0400, 0x0400); + s->clkm.arm_idlect1 = 0x0400; + omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 & 0x0100, 0x0100); + s->clkm.arm_idlect2 = 0x0100; + s->clkm.arm_ewupct = 0x003f; + s->clkm.arm_rstct1 = 0x0000; + s->clkm.arm_rstct2 = 0x0000; + s->clkm.arm_ckout1 = 0x0015; + s->clkm.dpll1_mode = 0x2002; + omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040); + s->clkm.dsp_idlect1 = 0x0040; + omap_clkdsp_idlect2_update(s, ~0, 0x0000); + s->clkm.dsp_idlect2 = 0x0000; + s->clkm.dsp_rstct2 = 0x0000; +} + +static void omap_clkm_init(target_phys_addr_t mpu_base, + target_phys_addr_t dsp_base, struct omap_mpu_state_s *s) +{ + int iomemtype[2] = { + cpu_register_io_memory(0, omap_clkm_readfn, omap_clkm_writefn, s), + cpu_register_io_memory(0, omap_clkdsp_readfn, omap_clkdsp_writefn, s), + }; + + s->clkm.mpu_base = mpu_base; + s->clkm.dsp_base = dsp_base; + s->clkm.cold_start = 0x3a; + omap_clkm_reset(s); + + cpu_register_physical_memory(s->clkm.mpu_base, 0x100, iomemtype[0]); + cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]); +} + +/* General chip reset */ +static void omap_mpu_reset(void *opaque) +{ + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + + omap_clkm_reset(mpu); + omap_inth_reset(mpu->ih[0]); + omap_inth_reset(mpu->ih[1]); + omap_dma_reset(mpu->dma); + omap_mpu_timer_reset(mpu->timer[0]); + omap_mpu_timer_reset(mpu->timer[1]); + omap_mpu_timer_reset(mpu->timer[2]); + omap_wd_timer_reset(mpu->wdt); + omap_os_timer_reset(mpu->os_timer); + omap_lcdc_reset(mpu->lcd); + omap_ulpd_pm_reset(mpu); + omap_pin_cfg_reset(mpu); + omap_mpui_reset(mpu); + omap_tipb_bridge_reset(mpu->private_tipb); + omap_tipb_bridge_reset(mpu->public_tipb); + omap_dpll_reset(&mpu->dpll[0]); + omap_dpll_reset(&mpu->dpll[1]); + omap_dpll_reset(&mpu->dpll[2]); + omap_uart_reset(mpu->uart1); + omap_uart_reset(mpu->uart2); + omap_uart_reset(mpu->uart3); + cpu_reset(mpu->env); +} + +static void omap_mpu_wakeup(void *opaque, int irq, int req) +{ + struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + + cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); +} + +struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, + DisplayState *ds, const char *core) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) + qemu_mallocz(sizeof(struct omap_mpu_state_s)); + ram_addr_t imif_base, emiff_base; + + /* Core */ + s->mpu_model = omap310; + s->env = cpu_init(); + s->sdram_size = sdram_size; + s->sram_size = OMAP15XX_SRAM_SIZE; + + cpu_arm_set_model(s->env, core ?: "ti925t"); + + /* Clocks */ + omap_clk_init(s); + + /* Memory-mapped stuff */ + cpu_register_physical_memory(OMAP_EMIFF_BASE, s->sdram_size, + (emiff_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM); + cpu_register_physical_memory(OMAP_IMIF_BASE, s->sram_size, + (imif_base = qemu_ram_alloc(s->sram_size)) | IO_MEM_RAM); + + omap_clkm_init(0xfffece00, 0xe1008000, s); + + s->ih[0] = omap_inth_init(0xfffecb00, 0x100, + arm_pic_init_cpu(s->env), + omap_findclk(s, "arminth_ck")); + s->ih[1] = omap_inth_init(0xfffe0000, 0x800, + &s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ], + omap_findclk(s, "arminth_ck")); + s->irq[0] = s->ih[0]->pins; + s->irq[1] = s->ih[1]->pins; + + s->dma = omap_dma_init(0xfffed800, s->irq[0], s, + omap_findclk(s, "dma_ck")); + s->port[emiff ].addr_valid = omap_validate_emiff_addr; + s->port[emifs ].addr_valid = omap_validate_emifs_addr; + s->port[imif ].addr_valid = omap_validate_imif_addr; + s->port[tipb ].addr_valid = omap_validate_tipb_addr; + s->port[local ].addr_valid = omap_validate_local_addr; + s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr; + + s->timer[0] = omap_mpu_timer_init(0xfffec500, + s->irq[0][OMAP_INT_TIMER1], + omap_findclk(s, "mputim_ck")); + s->timer[1] = omap_mpu_timer_init(0xfffec600, + s->irq[0][OMAP_INT_TIMER2], + omap_findclk(s, "mputim_ck")); + s->timer[2] = omap_mpu_timer_init(0xfffec700, + s->irq[0][OMAP_INT_TIMER3], + omap_findclk(s, "mputim_ck")); + + s->wdt = omap_wd_timer_init(0xfffec800, + s->irq[0][OMAP_INT_WD_TIMER], + omap_findclk(s, "armwdt_ck")); + + s->os_timer = omap_os_timer_init(0xfffb9000, + s->irq[1][OMAP_INT_OS_TIMER], + omap_findclk(s, "clk32-kHz")); + + s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL], + &s->dma->lcd_ch, ds, imif_base, emiff_base, + omap_findclk(s, "lcd_ck")); + + omap_ulpd_pm_init(0xfffe0800, s); + omap_pin_cfg_init(0xfffe1000, s); + omap_id_init(s); + + omap_mpui_init(0xfffec900, s); + + s->private_tipb = omap_tipb_bridge_init(0xfffeca00, + s->irq[0][OMAP_INT_BRIDGE_PRIV], + omap_findclk(s, "tipb_ck")); + s->public_tipb = omap_tipb_bridge_init(0xfffed300, + s->irq[0][OMAP_INT_BRIDGE_PUB], + omap_findclk(s, "tipb_ck")); + + omap_tcmi_init(0xfffecc00, s); + + s->uart1 = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], + omap_findclk(s, "uart1_ck"), + serial_hds[0]); + s->uart2 = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2], + omap_findclk(s, "uart2_ck"), + serial_hds[0] ? serial_hds[1] : 0); + s->uart3 = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3], + omap_findclk(s, "uart3_ck"), + serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0); + + omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1")); + omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); + omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); + + qemu_register_reset(omap_mpu_reset, s); + s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; + + return s; +} diff --git a/hw/omap.h b/hw/omap.h new file mode 100644 index 000000000..e30d38cbf --- /dev/null +++ b/hw/omap.h @@ -0,0 +1,581 @@ +/* + * Texas Instruments OMAP processors. + * + * Copyright (C) 2006-2007 Andrzej Zaborowski + * + * 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 + */ +#ifndef hw_omap_h +# define hw_omap_h "omap.h" + +# define OMAP_EMIFS_BASE 0x00000000 +# define OMAP_CS0_BASE 0x00000000 +# define OMAP_CS1_BASE 0x04000000 +# define OMAP_CS2_BASE 0x08000000 +# define OMAP_CS3_BASE 0x0c000000 +# define OMAP_EMIFF_BASE 0x10000000 +# define OMAP_IMIF_BASE 0x20000000 +# define OMAP_LOCALBUS_BASE 0x30000000 +# define OMAP_MPUI_BASE 0xe1000000 + +# define OMAP730_SRAM_SIZE 0x00032000 +# define OMAP15XX_SRAM_SIZE 0x00030000 +# define OMAP16XX_SRAM_SIZE 0x00004000 +# define OMAP1611_SRAM_SIZE 0x0003e800 +# define OMAP_CS0_SIZE 0x04000000 +# define OMAP_CS1_SIZE 0x04000000 +# define OMAP_CS2_SIZE 0x04000000 +# define OMAP_CS3_SIZE 0x04000000 + +/* omap1_clk.c */ +struct omap_mpu_state_s; +typedef struct clk *omap_clk; +omap_clk omap_findclk(struct omap_mpu_state_s *mpu, const char *name); +void omap_clk_init(struct omap_mpu_state_s *mpu); +void omap_clk_adduser(struct clk *clk, qemu_irq user); +void omap_clk_get(omap_clk clk); +void omap_clk_put(omap_clk clk); +void omap_clk_onoff(omap_clk clk, int on); +void omap_clk_canidle(omap_clk clk, int can); +void omap_clk_setrate(omap_clk clk, int divide, int multiply); +int64_t omap_clk_getrate(omap_clk clk); +void omap_clk_reparent(omap_clk clk, omap_clk parent); + +/* omap.c */ +struct omap_intr_handler_s; +struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, + unsigned long size, qemu_irq parent[2], omap_clk clk); + +/* + * Common IRQ numbers for level 1 interrupt handler + * See /usr/include/asm-arm/arch-omap/irqs.h in Linux. + */ +# define OMAP_INT_CAMERA 1 +# define OMAP_INT_FIQ 3 +# define OMAP_INT_RTDX 6 +# define OMAP_INT_DSP_MMU_ABORT 7 +# define OMAP_INT_HOST 8 +# define OMAP_INT_ABORT 9 +# define OMAP_INT_BRIDGE_PRIV 13 +# define OMAP_INT_GPIO_BANK1 14 +# define OMAP_INT_UART3 15 +# define OMAP_INT_TIMER3 16 +# define OMAP_INT_DMA_CH0_6 19 +# define OMAP_INT_DMA_CH1_7 20 +# define OMAP_INT_DMA_CH2_8 21 +# define OMAP_INT_DMA_CH3 22 +# define OMAP_INT_DMA_CH4 23 +# define OMAP_INT_DMA_CH5 24 +# define OMAP_INT_DMA_LCD 25 +# define OMAP_INT_TIMER1 26 +# define OMAP_INT_WD_TIMER 27 +# define OMAP_INT_BRIDGE_PUB 28 +# define OMAP_INT_TIMER2 30 +# define OMAP_INT_LCD_CTRL 31 + +/* + * Common OMAP-15xx IRQ numbers for level 1 interrupt handler + */ +# define OMAP_INT_15XX_IH2_IRQ 0 +# define OMAP_INT_15XX_LB_MMU 17 +# define OMAP_INT_15XX_LOCAL_BUS 29 + +/* + * OMAP-1510 specific IRQ numbers for level 1 interrupt handler + */ +# define OMAP_INT_1510_SPI_TX 4 +# define OMAP_INT_1510_SPI_RX 5 +# define OMAP_INT_1510_DSP_MAILBOX1 10 +# define OMAP_INT_1510_DSP_MAILBOX2 11 + +/* + * OMAP-310 specific IRQ numbers for level 1 interrupt handler + */ +# define OMAP_INT_310_McBSP2_TX 4 +# define OMAP_INT_310_McBSP2_RX 5 +# define OMAP_INT_310_HSB_MAILBOX1 12 +# define OMAP_INT_310_HSAB_MMU 18 + +/* + * OMAP-1610 specific IRQ numbers for level 1 interrupt handler + */ +# define OMAP_INT_1610_IH2_IRQ 0 +# define OMAP_INT_1610_IH2_FIQ 2 +# define OMAP_INT_1610_McBSP2_TX 4 +# define OMAP_INT_1610_McBSP2_RX 5 +# define OMAP_INT_1610_DSP_MAILBOX1 10 +# define OMAP_INT_1610_DSP_MAILBOX2 11 +# define OMAP_INT_1610_LCD_LINE 12 +# define OMAP_INT_1610_GPTIMER1 17 +# define OMAP_INT_1610_GPTIMER2 18 +# define OMAP_INT_1610_SSR_FIFO_0 29 + +/* + * OMAP-730 specific IRQ numbers for level 1 interrupt handler + */ +# define OMAP_INT_730_IH2_FIQ 0 +# define OMAP_INT_730_IH2_IRQ 1 +# define OMAP_INT_730_USB_NON_ISO 2 +# define OMAP_INT_730_USB_ISO 3 +# define OMAP_INT_730_ICR 4 +# define OMAP_INT_730_EAC 5 +# define OMAP_INT_730_GPIO_BANK1 6 +# define OMAP_INT_730_GPIO_BANK2 7 +# define OMAP_INT_730_GPIO_BANK3 8 +# define OMAP_INT_730_McBSP2TX 10 +# define OMAP_INT_730_McBSP2RX 11 +# define OMAP_INT_730_McBSP2RX_OVF 12 +# define OMAP_INT_730_LCD_LINE 14 +# define OMAP_INT_730_GSM_PROTECT 15 +# define OMAP_INT_730_TIMER3 16 +# define OMAP_INT_730_GPIO_BANK5 17 +# define OMAP_INT_730_GPIO_BANK6 18 +# define OMAP_INT_730_SPGIO_WR 29 + +/* + * Common IRQ numbers for level 2 interrupt handler + */ +# define OMAP_INT_KEYBOARD 1 +# define OMAP_INT_uWireTX 2 +# define OMAP_INT_uWireRX 3 +# define OMAP_INT_I2C 4 +# define OMAP_INT_MPUIO 5 +# define OMAP_INT_USB_HHC_1 6 +# define OMAP_INT_McBSP3TX 10 +# define OMAP_INT_McBSP3RX 11 +# define OMAP_INT_McBSP1TX 12 +# define OMAP_INT_McBSP1RX 13 +# define OMAP_INT_UART1 14 +# define OMAP_INT_UART2 15 +# define OMAP_INT_USB_W2FC 20 +# define OMAP_INT_1WIRE 21 +# define OMAP_INT_OS_TIMER 22 +# define OMAP_INT_MMC 23 +# define OMAP_INT_GAUGE_32K 24 +# define OMAP_INT_RTC_TIMER 25 +# define OMAP_INT_RTC_ALARM 26 +# define OMAP_INT_DSP_MMU 28 + +/* + * OMAP-1510 specific IRQ numbers for level 2 interrupt handler + */ +# define OMAP_INT_1510_BT_MCSI1TX 16 +# define OMAP_INT_1510_BT_MCSI1RX 17 +# define OMAP_INT_1510_SoSSI_MATCH 19 +# define OMAP_INT_1510_MEM_STICK 27 +# define OMAP_INT_1510_COM_SPI_RO 31 + +/* + * OMAP-310 specific IRQ numbers for level 2 interrupt handler + */ +# define OMAP_INT_310_FAC 0 +# define OMAP_INT_310_USB_HHC_2 7 +# define OMAP_INT_310_MCSI1_FE 16 +# define OMAP_INT_310_MCSI2_FE 17 +# define OMAP_INT_310_USB_W2FC_ISO 29 +# define OMAP_INT_310_USB_W2FC_NON_ISO 30 +# define OMAP_INT_310_McBSP2RX_OF 31 + +/* + * OMAP-1610 specific IRQ numbers for level 2 interrupt handler + */ +# define OMAP_INT_1610_FAC 0 +# define OMAP_INT_1610_USB_HHC_2 7 +# define OMAP_INT_1610_USB_OTG 8 +# define OMAP_INT_1610_SoSSI 9 +# define OMAP_INT_1610_BT_MCSI1TX 16 +# define OMAP_INT_1610_BT_MCSI1RX 17 +# define OMAP_INT_1610_SoSSI_MATCH 19 +# define OMAP_INT_1610_MEM_STICK 27 +# define OMAP_INT_1610_McBSP2RX_OF 31 +# define OMAP_INT_1610_STI 32 +# define OMAP_INT_1610_STI_WAKEUP 33 +# define OMAP_INT_1610_GPTIMER3 34 +# define OMAP_INT_1610_GPTIMER4 35 +# define OMAP_INT_1610_GPTIMER5 36 +# define OMAP_INT_1610_GPTIMER6 37 +# define OMAP_INT_1610_GPTIMER7 38 +# define OMAP_INT_1610_GPTIMER8 39 +# define OMAP_INT_1610_GPIO_BANK2 40 +# define OMAP_INT_1610_GPIO_BANK3 41 +# define OMAP_INT_1610_MMC2 42 +# define OMAP_INT_1610_CF 43 +# define OMAP_INT_1610_WAKE_UP_REQ 46 +# define OMAP_INT_1610_GPIO_BANK4 48 +# define OMAP_INT_1610_SPI 49 +# define OMAP_INT_1610_DMA_CH6 53 +# define OMAP_INT_1610_DMA_CH7 54 +# define OMAP_INT_1610_DMA_CH8 55 +# define OMAP_INT_1610_DMA_CH9 56 +# define OMAP_INT_1610_DMA_CH10 57 +# define OMAP_INT_1610_DMA_CH11 58 +# define OMAP_INT_1610_DMA_CH12 59 +# define OMAP_INT_1610_DMA_CH13 60 +# define OMAP_INT_1610_DMA_CH14 61 +# define OMAP_INT_1610_DMA_CH15 62 +# define OMAP_INT_1610_NAND 63 + +/* + * OMAP-730 specific IRQ numbers for level 2 interrupt handler + */ +# define OMAP_INT_730_HW_ERRORS 0 +# define OMAP_INT_730_NFIQ_PWR_FAIL 1 +# define OMAP_INT_730_CFCD 2 +# define OMAP_INT_730_CFIREQ 3 +# define OMAP_INT_730_I2C 4 +# define OMAP_INT_730_PCC 5 +# define OMAP_INT_730_MPU_EXT_NIRQ 6 +# define OMAP_INT_730_SPI_100K_1 7 +# define OMAP_INT_730_SYREN_SPI 8 +# define OMAP_INT_730_VLYNQ 9 +# define OMAP_INT_730_GPIO_BANK4 10 +# define OMAP_INT_730_McBSP1TX 11 +# define OMAP_INT_730_McBSP1RX 12 +# define OMAP_INT_730_McBSP1RX_OF 13 +# define OMAP_INT_730_UART_MODEM_IRDA_2 14 +# define OMAP_INT_730_UART_MODEM_1 15 +# define OMAP_INT_730_MCSI 16 +# define OMAP_INT_730_uWireTX 17 +# define OMAP_INT_730_uWireRX 18 +# define OMAP_INT_730_SMC_CD 19 +# define OMAP_INT_730_SMC_IREQ 20 +# define OMAP_INT_730_HDQ_1WIRE 21 +# define OMAP_INT_730_TIMER32K 22 +# define OMAP_INT_730_MMC_SDIO 23 +# define OMAP_INT_730_UPLD 24 +# define OMAP_INT_730_USB_HHC_1 27 +# define OMAP_INT_730_USB_HHC_2 28 +# define OMAP_INT_730_USB_GENI 29 +# define OMAP_INT_730_USB_OTG 30 +# define OMAP_INT_730_CAMERA_IF 31 +# define OMAP_INT_730_RNG 32 +# define OMAP_INT_730_DUAL_MODE_TIMER 33 +# define OMAP_INT_730_DBB_RF_EN 34 +# define OMAP_INT_730_MPUIO_KEYPAD 35 +# define OMAP_INT_730_SHA1_MD5 36 +# define OMAP_INT_730_SPI_100K_2 37 +# define OMAP_INT_730_RNG_IDLE 38 +# define OMAP_INT_730_MPUIO 39 +# define OMAP_INT_730_LLPC_LCD_CTRL_OFF 40 +# define OMAP_INT_730_LLPC_OE_FALLING 41 +# define OMAP_INT_730_LLPC_OE_RISING 42 +# define OMAP_INT_730_LLPC_VSYNC 43 +# define OMAP_INT_730_WAKE_UP_REQ 46 +# define OMAP_INT_730_DMA_CH6 53 +# define OMAP_INT_730_DMA_CH7 54 +# define OMAP_INT_730_DMA_CH8 55 +# define OMAP_INT_730_DMA_CH9 56 +# define OMAP_INT_730_DMA_CH10 57 +# define OMAP_INT_730_DMA_CH11 58 +# define OMAP_INT_730_DMA_CH12 59 +# define OMAP_INT_730_DMA_CH13 60 +# define OMAP_INT_730_DMA_CH14 61 +# define OMAP_INT_730_DMA_CH15 62 +# define OMAP_INT_730_NAND 63 + +/* + * OMAP-24xx common IRQ numbers + */ +# define OMAP_INT_24XX_SYS_NIRQ 7 +# define OMAP_INT_24XX_SDMA_IRQ0 12 +# define OMAP_INT_24XX_SDMA_IRQ1 13 +# define OMAP_INT_24XX_SDMA_IRQ2 14 +# define OMAP_INT_24XX_SDMA_IRQ3 15 +# define OMAP_INT_24XX_CAM_IRQ 24 +# define OMAP_INT_24XX_DSS_IRQ 25 +# define OMAP_INT_24XX_MAIL_U0_MPU 26 +# define OMAP_INT_24XX_DSP_UMA 27 +# define OMAP_INT_24XX_DSP_MMU 28 +# define OMAP_INT_24XX_GPIO_BANK1 29 +# define OMAP_INT_24XX_GPIO_BANK2 30 +# define OMAP_INT_24XX_GPIO_BANK3 31 +# define OMAP_INT_24XX_GPIO_BANK4 32 +# define OMAP_INT_24XX_GPIO_BANK5 33 +# define OMAP_INT_24XX_MAIL_U3_MPU 34 +# define OMAP_INT_24XX_GPTIMER1 37 +# define OMAP_INT_24XX_GPTIMER2 38 +# define OMAP_INT_24XX_GPTIMER3 39 +# define OMAP_INT_24XX_GPTIMER4 40 +# define OMAP_INT_24XX_GPTIMER5 41 +# define OMAP_INT_24XX_GPTIMER6 42 +# define OMAP_INT_24XX_GPTIMER7 43 +# define OMAP_INT_24XX_GPTIMER8 44 +# define OMAP_INT_24XX_GPTIMER9 45 +# define OMAP_INT_24XX_GPTIMER10 46 +# define OMAP_INT_24XX_GPTIMER11 47 +# define OMAP_INT_24XX_GPTIMER12 48 +# define OMAP_INT_24XX_MCBSP1_IRQ_TX 59 +# define OMAP_INT_24XX_MCBSP1_IRQ_RX 60 +# define OMAP_INT_24XX_MCBSP2_IRQ_TX 62 +# define OMAP_INT_24XX_MCBSP2_IRQ_RX 63 +# define OMAP_INT_24XX_UART1_IRQ 72 +# define OMAP_INT_24XX_UART2_IRQ 73 +# define OMAP_INT_24XX_UART3_IRQ 74 +# define OMAP_INT_24XX_USB_IRQ_GEN 75 +# define OMAP_INT_24XX_USB_IRQ_NISO 76 +# define OMAP_INT_24XX_USB_IRQ_ISO 77 +# define OMAP_INT_24XX_USB_IRQ_HGEN 78 +# define OMAP_INT_24XX_USB_IRQ_HSOF 79 +# define OMAP_INT_24XX_USB_IRQ_OTG 80 +# define OMAP_INT_24XX_MMC_IRQ 83 +# define OMAP_INT_243X_HS_USB_MC 92 +# define OMAP_INT_243X_HS_USB_DMA 93 +# define OMAP_INT_243X_CARKIT 94 + +struct omap_dma_s; +struct omap_dma_s *omap_dma_init(target_phys_addr_t base, + qemu_irq pic[], struct omap_mpu_state_s *mpu, omap_clk clk); + +enum omap_dma_port { + emiff = 0, + emifs, + imif, + tipb, + local, + tipb_mpui, + omap_dma_port_last, +}; + +struct omap_dma_lcd_channel_s { + enum omap_dma_port src; + target_phys_addr_t src_f1_top; + target_phys_addr_t src_f1_bottom; + target_phys_addr_t src_f2_top; + target_phys_addr_t src_f2_bottom; + /* Destination port is fixed. */ + int interrupts; + int condition; + int dual; + + int current_frame; + ram_addr_t phys_framebuffer[2]; + qemu_irq irq; + struct omap_mpu_state_s *mpu; +}; + +/* + * DMA request numbers for OMAP1 + * See /usr/include/asm-arm/arch-omap/dma.h in Linux. + */ +# define OMAP_DMA_NO_DEVICE 0 +# define OMAP_DMA_MCSI1_TX 1 +# define OMAP_DMA_MCSI1_RX 2 +# define OMAP_DMA_I2C_RX 3 +# define OMAP_DMA_I2C_TX 4 +# define OMAP_DMA_EXT_NDMA_REQ0 5 +# define OMAP_DMA_EXT_NDMA_REQ1 6 +# define OMAP_DMA_UWIRE_TX 7 +# define OMAP_DMA_MCBSP1_TX 8 +# define OMAP_DMA_MCBSP1_RX 9 +# define OMAP_DMA_MCBSP3_TX 10 +# define OMAP_DMA_MCBSP3_RX 11 +# define OMAP_DMA_UART1_TX 12 +# define OMAP_DMA_UART1_RX 13 +# define OMAP_DMA_UART2_TX 14 +# define OMAP_DMA_UART2_RX 15 +# define OMAP_DMA_MCBSP2_TX 16 +# define OMAP_DMA_MCBSP2_RX 17 +# define OMAP_DMA_UART3_TX 18 +# define OMAP_DMA_UART3_RX 19 +# define OMAP_DMA_CAMERA_IF_RX 20 +# define OMAP_DMA_MMC_TX 21 +# define OMAP_DMA_MMC_RX 22 +# define OMAP_DMA_NAND 23 /* Not in OMAP310 */ +# define OMAP_DMA_IRQ_LCD_LINE 24 /* Not in OMAP310 */ +# define OMAP_DMA_MEMORY_STICK 25 /* Not in OMAP310 */ +# define OMAP_DMA_USB_W2FC_RX0 26 +# define OMAP_DMA_USB_W2FC_RX1 27 +# define OMAP_DMA_USB_W2FC_RX2 28 +# define OMAP_DMA_USB_W2FC_TX0 29 +# define OMAP_DMA_USB_W2FC_TX1 30 +# define OMAP_DMA_USB_W2FC_TX2 31 + +/* These are only for 1610 */ +# define OMAP_DMA_CRYPTO_DES_IN 32 +# define OMAP_DMA_SPI_TX 33 +# define OMAP_DMA_SPI_RX 34 +# define OMAP_DMA_CRYPTO_HASH 35 +# define OMAP_DMA_CCP_ATTN 36 +# define OMAP_DMA_CCP_FIFO_NOT_EMPTY 37 +# define OMAP_DMA_CMT_APE_TX_CHAN_0 38 +# define OMAP_DMA_CMT_APE_RV_CHAN_0 39 +# define OMAP_DMA_CMT_APE_TX_CHAN_1 40 +# define OMAP_DMA_CMT_APE_RV_CHAN_1 41 +# define OMAP_DMA_CMT_APE_TX_CHAN_2 42 +# define OMAP_DMA_CMT_APE_RV_CHAN_2 43 +# define OMAP_DMA_CMT_APE_TX_CHAN_3 44 +# define OMAP_DMA_CMT_APE_RV_CHAN_3 45 +# define OMAP_DMA_CMT_APE_TX_CHAN_4 46 +# define OMAP_DMA_CMT_APE_RV_CHAN_4 47 +# define OMAP_DMA_CMT_APE_TX_CHAN_5 48 +# define OMAP_DMA_CMT_APE_RV_CHAN_5 49 +# define OMAP_DMA_CMT_APE_TX_CHAN_6 50 +# define OMAP_DMA_CMT_APE_RV_CHAN_6 51 +# define OMAP_DMA_CMT_APE_TX_CHAN_7 52 +# define OMAP_DMA_CMT_APE_RV_CHAN_7 53 +# define OMAP_DMA_MMC2_TX 54 +# define OMAP_DMA_MMC2_RX 55 +# define OMAP_DMA_CRYPTO_DES_OUT 56 + +struct omap_mpu_timer_s; +struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk); + +struct omap_watchdog_timer_s; +struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk); + +struct omap_32khz_timer_s; +struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk); + +struct omap_tipb_bridge_s; +struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base, + qemu_irq abort_irq, omap_clk clk); + +struct omap_uart_s; +struct omap_uart_s *omap_uart_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk, CharDriverState *chr); + +/* omap_lcdc.c */ +struct omap_lcd_panel_s; +void omap_lcdc_reset(struct omap_lcd_panel_s *s); +struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, + struct omap_dma_lcd_channel_s *dma, DisplayState *ds, + ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk); + +# define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) +# define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) +# define cpu_is_omap15xx(cpu) \ + (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu)) +# define cpu_class_omap1(cpu) 1 + +struct omap_mpu_state_s { + enum omap1_mpu_model { + omap310, + omap1510, + } mpu_model; + + CPUState *env; + + qemu_irq *irq[2]; + qemu_irq *drq; + + qemu_irq wakeup; + + struct omap_dma_port_if_s { + uint32_t (*read[3])(struct omap_mpu_state_s *s, + target_phys_addr_t offset); + void (*write[3])(struct omap_mpu_state_s *s, + target_phys_addr_t offset, uint32_t value); + int (*addr_valid)(struct omap_mpu_state_s *s, + target_phys_addr_t addr); + } port[omap_dma_port_last]; + + unsigned long sdram_size; + unsigned long sram_size; + + /* MPUI-TIPB peripherals */ + struct omap_uart_s *uart3; + + /* MPU public TIPB peripherals */ + struct omap_32khz_timer_s *os_timer; + + struct omap_uart_s *uart1; + struct omap_uart_s *uart2; + + /* MPU private TIPB peripherals */ + struct omap_intr_handler_s *ih[2]; + + struct omap_dma_s *dma; + + struct omap_mpu_timer_s *timer[3]; + struct omap_watchdog_timer_s *wdt; + + struct omap_lcd_panel_s *lcd; + + target_phys_addr_t ulpd_pm_base; + uint32_t ulpd_pm_regs[21]; + int64_t ulpd_gauge_start; + + target_phys_addr_t pin_cfg_base; + uint32_t func_mux_ctrl[14]; + uint32_t comp_mode_ctrl[1]; + uint32_t pull_dwn_ctrl[4]; + uint32_t gate_inh_ctrl[1]; + uint32_t voltage_ctrl[1]; + uint32_t test_dbg_ctrl[1]; + uint32_t mod_conf_ctrl[1]; + int compat1509; + + uint32_t mpui_ctrl; + target_phys_addr_t mpui_base; + + struct omap_tipb_bridge_s *private_tipb; + struct omap_tipb_bridge_s *public_tipb; + + target_phys_addr_t tcmi_base; + uint32_t tcmi_regs[17]; + + struct dpll_ctl_s { + target_phys_addr_t base; + uint16_t mode; + omap_clk dpll; + } dpll[3]; + + omap_clk clks; + struct { + target_phys_addr_t mpu_base; + target_phys_addr_t dsp_base; + + int cold_start; + int clocking_scheme; + uint16_t arm_ckctl; + uint16_t arm_idlect1; + uint16_t arm_idlect2; + uint16_t arm_ewupct; + uint16_t arm_rstct1; + uint16_t arm_rstct2; + uint16_t arm_ckout1; + int dpll1_mode; + uint16_t dsp_idlect1; + uint16_t dsp_idlect2; + uint16_t dsp_rstct2; + } clkm; +} *omap310_mpu_init(unsigned long sdram_size, + DisplayState *ds, const char *core); + +# if TARGET_PHYS_ADDR_BITS == 32 +# define OMAP_FMT_plx "%#08x" +# elif TARGET_PHYS_ADDR_BITS == 64 +# define OMAP_FMT_plx "%#08" PRIx64 +# else +# error TARGET_PHYS_ADDR_BITS undefined +# endif + +# define OMAP_BAD_REG(paddr) \ + printf("%s: Bad register " OMAP_FMT_plx "\n", __FUNCTION__, paddr) +# define OMAP_RO_REG(paddr) \ + printf("%s: Read-only register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) +# define OMAP_16B_REG(paddr) \ + printf("%s: 16-bit register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) +# define OMAP_32B_REG(paddr) \ + printf("%s: 32-bit register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) + +#endif /* hw_omap_h */ diff --git a/hw/omap1_clk.c b/hw/omap1_clk.c new file mode 100644 index 000000000..7888e4155 --- /dev/null +++ b/hw/omap1_clk.c @@ -0,0 +1,745 @@ +/* + * OMAP clocks. + * + * Copyright (C) 2006-2007 Andrzej Zaborowski + * + * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux. + * + * 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 "vl.h" + +struct clk { + const char *name; + const char *alias; + struct clk *parent; + struct clk *child1; + struct clk *sibling; +#define ALWAYS_ENABLED (1 << 0) +#define CLOCK_IN_OMAP310 (1 << 10) +#define CLOCK_IN_OMAP730 (1 << 11) +#define CLOCK_IN_OMAP1510 (1 << 12) +#define CLOCK_IN_OMAP16XX (1 << 13) + uint32_t flags; + int id; + + int running; /* Is currently ticking */ + int enabled; /* Is enabled, regardless of its input clk */ + unsigned long rate; /* Current rate (if .running) */ + unsigned int divisor; /* Rate relative to input (if .enabled) */ + unsigned int multiplier; /* Rate relative to input (if .enabled) */ + qemu_irq users[16]; /* Who to notify on change */ + int usecount; /* Automatically idle when unused */ +}; + +static struct clk xtal_osc12m = { + .name = "xtal_osc_12m", + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk xtal_osc32k = { + .name = "xtal_osc_32k", + .rate = 32768, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk ck_ref = { + .name = "ck_ref", + .alias = "clkin", + .parent = &xtal_osc12m, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +/* If a dpll is disabled it becomes a bypass, child clocks don't stop */ +static struct clk dpll1 = { + .name = "dpll1", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk dpll2 = { + .name = "dpll2", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk dpll3 = { + .name = "dpll3", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk dpll4 = { + .name = "dpll4", + .parent = &ck_ref, + .multiplier = 4, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk apll = { + .name = "apll", + .parent = &ck_ref, + .multiplier = 48, + .divisor = 12, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk ck_48m = { + .name = "ck_48m", + .parent = &dpll4, /* either dpll4 or apll */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk ck_dpll1out = { + .name = "ck_dpll1out", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk sossi_ck = { + .name = "ck_sossi", + .parent = &ck_dpll1out, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk clkm1 = { + .name = "clkm1", + .alias = "ck_gen1", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk clkm2 = { + .name = "clkm2", + .alias = "ck_gen2", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk clkm3 = { + .name = "clkm3", + .alias = "ck_gen3", + .parent = &dpll1, /* either dpll1 or ck_ref */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arm_ck = { + .name = "arm_ck", + .alias = "mpu_ck", + .parent = &clkm1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk armper_ck = { + .name = "armper_ck", + .alias = "mpuper_ck", + .parent = &clkm1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk arm_gpio_ck = { + .name = "arm_gpio_ck", + .alias = "mpu_gpio_ck", + .parent = &clkm1, + .divisor = 1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk armxor_ck = { + .name = "armxor_ck", + .alias = "mpuxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk armtim_ck = { + .name = "armtim_ck", + .alias = "mputim_ck", + .parent = &ck_ref, /* either CLKIN or DPLL1 */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk armwdt_ck = { + .name = "armwdt_ck", + .alias = "mpuwd_ck", + .parent = &clkm1, + .divisor = 14, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arminth_ck16xx = { + .name = "arminth_ck", + .parent = &arm_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + /* Note: On 16xx the frequency can be divided by 2 by programming + * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 + * + * 1510 version is in TC clocks. + */ +}; + +static struct clk dsp_ck = { + .name = "dsp_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dspmmu_ck = { + .name = "dspmmu_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + ALWAYS_ENABLED, +}; + +static struct clk dspper_ck = { + .name = "dspper_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dspxor_ck = { + .name = "dspxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk dsptim_ck = { + .name = "dsptim_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk tc_ck = { + .name = "tc_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk arminth_ck15xx = { + .name = "arminth_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + /* Note: On 1510 the frequency follows TC_CK + * + * 16xx version is in MPU clocks. + */ +}; + +static struct clk tipb_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "tipb_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk l3_ocpi_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "l3_ocpi_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk tc1_ck = { + .name = "tc1_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk tc2_ck = { + .name = "tc2_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk dma_ck = { + /* No-idle controlled by "tc_ck" */ + .name = "dma_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk dma_lcdfree_ck = { + .name = "dma_lcdfree_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk api_ck = { + .name = "api_ck", + .alias = "mpui_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk lb_ck = { + .name = "lb_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk lbfree_ck = { + .name = "lbfree_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk rhea1_ck = { + .name = "rhea1_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk rhea2_ck = { + .name = "rhea2_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, +}; + +static struct clk lcd_ck_16xx = { + .name = "lcd_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730, +}; + +static struct clk lcd_ck_1510 = { + .name = "lcd_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk uart1_1510 = { + .name = "uart1_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk uart1_16xx = { + .name = "uart1_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk uart2_ck = { + .name = "uart2_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, +}; + +static struct clk uart3_1510 = { + .name = "uart3_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck,/* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, +}; + +static struct clk uart3_16xx = { + .name = "uart3_ck", + /* Direct from ULPD, no real parent */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */ + .name = "usb_clk0", + .alias = "usb.clko", + /* Direct from ULPD, no parent */ + .rate = 6000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk usb_hhc_ck1510 = { + .name = "usb_hhc_ck", + /* Direct from ULPD, no parent */ + .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + +static struct clk usb_hhc_ck16xx = { + .name = "usb_hhc_ck", + /* Direct from ULPD, no parent */ + .rate = 48000000, + /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk usb_dc_ck = { + .name = "usb_dc_ck", + /* Direct from ULPD, no parent */ + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk mclk_1510 = { + .name = "mclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510, +}; + +static struct clk bclk_310 = { + .name = "bt_mclk_out", /* Alias midi_mclk_out? */ + .parent = &armper_ck, + .flags = CLOCK_IN_OMAP310, +}; + +static struct clk mclk_310 = { + .name = "com_mclk_out", + .parent = &armper_ck, + .flags = CLOCK_IN_OMAP310, +}; + +static struct clk mclk_16xx = { + .name = "mclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk bclk_1510 = { + .name = "bclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510, +}; + +static struct clk bclk_16xx = { + .name = "bclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk mmc1_ck = { + .name = "mmc_ck", + .id = 1, + /* Functional clock is direct from ULPD, interface clock is ARMPER */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 48000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, +}; + +static struct clk mmc2_ck = { + .name = "mmc_ck", + .id = 2, + /* Functional clock is direct from ULPD, interface clock is ARMPER */ + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, +}; + +static struct clk cam_mclk = { + .name = "cam.mclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .rate = 12000000, +}; + +static struct clk cam_exclk = { + .name = "cam.exclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + /* Either 12M from cam.mclk or 48M from dpll4 */ + .parent = &cam_mclk, +}; + +static struct clk cam_lclk = { + .name = "cam.lclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, +}; + +static struct clk i2c_fck = { + .name = "i2c_fck", + .id = 1, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + ALWAYS_ENABLED, + .parent = &armxor_ck, +}; + +static struct clk i2c_ick = { + .name = "i2c_ick", + .id = 1, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + .parent = &armper_ck, +}; + +static struct clk clk32k = { + .name = "clk32-kHz", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + ALWAYS_ENABLED, + .parent = &xtal_osc32k, +}; + +static struct clk *onchip_clks[] = { + /* non-ULPD clocks */ + &xtal_osc12m, + &xtal_osc32k, + &ck_ref, + &dpll1, + &dpll2, + &dpll3, + &dpll4, + &apll, + &ck_48m, + /* CK_GEN1 clocks */ + &clkm1, + &ck_dpll1out, + &sossi_ck, + &arm_ck, + &armper_ck, + &arm_gpio_ck, + &armxor_ck, + &armtim_ck, + &armwdt_ck, + &arminth_ck15xx, &arminth_ck16xx, + /* CK_GEN2 clocks */ + &clkm2, + &dsp_ck, + &dspmmu_ck, + &dspper_ck, + &dspxor_ck, + &dsptim_ck, + /* CK_GEN3 clocks */ + &clkm3, + &tc_ck, + &tipb_ck, + &l3_ocpi_ck, + &tc1_ck, + &tc2_ck, + &dma_ck, + &dma_lcdfree_ck, + &api_ck, + &lb_ck, + &lbfree_ck, + &rhea1_ck, + &rhea2_ck, + &lcd_ck_16xx, + &lcd_ck_1510, + /* ULPD clocks */ + &uart1_1510, + &uart1_16xx, + &uart2_ck, + &uart3_1510, + &uart3_16xx, + &usb_clk0, + &usb_hhc_ck1510, &usb_hhc_ck16xx, + &usb_dc_ck, + &mclk_1510, &mclk_16xx, &mclk_310, + &bclk_1510, &bclk_16xx, &bclk_310, + &mmc1_ck, + &mmc2_ck, + &cam_mclk, + &cam_exclk, + &cam_lclk, + &clk32k, + /* Virtual clocks */ + &i2c_fck, + &i2c_ick, + 0 +}; + +void omap_clk_adduser(struct clk *clk, qemu_irq user) +{ + qemu_irq *i; + + for (i = clk->users; *i; i ++); + *i = user; +} + +/* If a clock is allowed to idle, it is disabled automatically when + * all of clock domains using it are disabled. */ +int omap_clk_is_idle(struct clk *clk) +{ + struct clk *chld; + + if (!clk->enabled && (!clk->usecount || !(clk->flags && ALWAYS_ENABLED))) + return 1; + if (clk->usecount) + return 0; + + for (chld = clk->child1; chld; chld = chld->sibling) + if (!omap_clk_is_idle(chld)) + return 0; + return 1; +} + +struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name) +{ + struct clk *i; + + for (i = mpu->clks; i->name; i ++) + if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name))) + return i; + cpu_abort(mpu->env, "%s: %s not found\n", __FUNCTION__, name); +} + +void omap_clk_get(struct clk *clk) +{ + clk->usecount ++; +} + +void omap_clk_put(struct clk *clk) +{ + if (!(clk->usecount --)) + cpu_abort(cpu_single_env, "%s: %s is not in use\n", + __FUNCTION__, clk->name); +} + +static void omap_clk_update(struct clk *clk) +{ + int parent, running; + qemu_irq *user; + struct clk *i; + + if (clk->parent) + parent = clk->parent->running; + else + parent = 1; + + running = parent && (clk->enabled || + ((clk->flags & ALWAYS_ENABLED) && clk->usecount)); + if (clk->running != running) { + clk->running = running; + for (user = clk->users; *user; user ++) + qemu_set_irq(*user, running); + for (i = clk->child1; i; i = i->sibling) + omap_clk_update(i); + } +} + +static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate, + unsigned long int div, unsigned long int mult) +{ + struct clk *i; + qemu_irq *user; + + clk->rate = muldiv64(rate, mult, div); + if (clk->running) + for (user = clk->users; *user; user ++) + qemu_irq_raise(*user); + for (i = clk->child1; i; i = i->sibling) + omap_clk_rate_update_full(i, rate, + div * i->divisor, mult * i->multiplier); +} + +static void omap_clk_rate_update(struct clk *clk) +{ + struct clk *i; + unsigned long int div, mult = div = 1; + + for (i = clk; i->parent; i = i->parent) { + div *= i->divisor; + mult *= i->multiplier; + } + + omap_clk_rate_update_full(clk, i->rate, div, mult); +} + +void omap_clk_reparent(struct clk *clk, struct clk *parent) +{ + struct clk **p; + + if (clk->parent) { + for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling); + *p = clk->sibling; + } + + clk->parent = parent; + if (parent) { + clk->sibling = parent->child1; + parent->child1 = clk; + omap_clk_update(clk); + omap_clk_rate_update(clk); + } else + clk->sibling = 0; +} + +void omap_clk_onoff(struct clk *clk, int on) +{ + clk->enabled = on; + omap_clk_update(clk); +} + +void omap_clk_canidle(struct clk *clk, int can) +{ + if (can) + omap_clk_put(clk); + else + omap_clk_get(clk); +} + +void omap_clk_setrate(struct clk *clk, int divide, int multiply) +{ + clk->divisor = divide; + clk->multiplier = multiply; + omap_clk_rate_update(clk); +} + +int64_t omap_clk_getrate(omap_clk clk) +{ + return clk->rate; +} + +void omap_clk_init(struct omap_mpu_state_s *mpu) +{ + struct clk **i, *j, *k; + int count; + int flag; + + if (cpu_is_omap310(mpu)) + flag = CLOCK_IN_OMAP310; + else if (cpu_is_omap1510(mpu)) + flag = CLOCK_IN_OMAP1510; + else + return; + + for (i = onchip_clks, count = 0; *i; i ++) + if ((*i)->flags & flag) + count ++; + mpu->clks = (struct clk *) qemu_mallocz(sizeof(struct clk) * (count + 1)); + for (i = onchip_clks, j = mpu->clks; *i; i ++) + if ((*i)->flags & flag) { + memcpy(j, *i, sizeof(struct clk)); + for (k = mpu->clks; k < j; k ++) + if (j->parent && !strcmp(j->parent->name, k->name)) { + j->parent = k; + j->sibling = k->child1; + k->child1 = j; + } else if (k->parent && !strcmp(k->parent->name, j->name)) { + k->parent = j; + k->sibling = j->child1; + j->child1 = k; + } + j->divisor = j->divisor ?: 1; + j->multiplier = j->multiplier ?: 1; + j ++; + } +} diff --git a/hw/omap_lcd_template.h b/hw/omap_lcd_template.h new file mode 100644 index 000000000..cdfa5620f --- /dev/null +++ b/hw/omap_lcd_template.h @@ -0,0 +1,172 @@ +/* + * QEMU OMAP LCD Emulator templates + * + * Copyright (c) 2006 Andrzej Zaborowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + */ + +#if DEPTH == 8 +# define BPP 1 +# define PIXEL_TYPE uint8_t +#elif DEPTH == 15 || DEPTH == 16 +# define BPP 2 +# define PIXEL_TYPE uint16_t +#elif DEPTH == 32 +# define BPP 4 +# define PIXEL_TYPE uint32_t +#else +# error unsupport depth +#endif + +/* + * 2-bit colour + */ +static void glue(draw_line2_, DEPTH)( + uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +{ + uint8_t v, r, g, b; + + do { + v = ldub_raw((void *) s); + r = (pal[v & 3] >> 4) & 0xf0; + g = pal[v & 3] & 0xf0; + b = (pal[v & 3] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + d += BPP; + v >>= 2; + r = (pal[v & 3] >> 4) & 0xf0; + g = pal[v & 3] & 0xf0; + b = (pal[v & 3] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + d += BPP; + v >>= 2; + r = (pal[v & 3] >> 4) & 0xf0; + g = pal[v & 3] & 0xf0; + b = (pal[v & 3] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + d += BPP; + v >>= 2; + r = (pal[v & 3] >> 4) & 0xf0; + g = pal[v & 3] & 0xf0; + b = (pal[v & 3] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + d += BPP; + s ++; + width -= 4; + } while (width > 0); +} + +/* + * 4-bit colour + */ +static void glue(draw_line4_, DEPTH)( + uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +{ + uint8_t v, r, g, b; + + do { + v = ldub_raw((void *) s); + r = (pal[v & 0xf] >> 4) & 0xf0; + g = pal[v & 0xf] & 0xf0; + b = (pal[v & 0xf] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + d += BPP; + v >>= 4; + r = (pal[v & 0xf] >> 4) & 0xf0; + g = pal[v & 0xf] & 0xf0; + b = (pal[v & 0xf] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + d += BPP; + s ++; + width -= 2; + } while (width > 0); +} + +/* + * 8-bit colour + */ +static void glue(draw_line8_, DEPTH)( + uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +{ + uint8_t v, r, g, b; + + do { + v = ldub_raw((void *) s); + r = (pal[v] >> 4) & 0xf0; + g = pal[v] & 0xf0; + b = (pal[v] << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + s ++; + d += BPP; + } while (-- width != 0); +} + +/* + * 12-bit colour + */ +static void glue(draw_line12_, DEPTH)( + uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +{ + uint16_t v; + uint8_t r, g, b; + + do { + v = lduw_raw((void *) s); + r = (v >> 4) & 0xf0; + g = v & 0xf0; + b = (v << 4) & 0xf0; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + s += 2; + d += BPP; + } while (-- width != 0); +} + +/* + * 16-bit colour + */ +static void glue(draw_line16_, DEPTH)( + uint8_t *d, const uint8_t *s, int width, const uint16_t *pal) +{ +#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + memcpy(d, s, width * 2); +#else + uint16_t v; + uint8_t r, g, b; + + do { + v = lduw_raw((void *) s); + r = (v >> 8) & 0xf8; + g = (v >> 3) & 0xfc; + b = (v << 3) & 0xf8; + ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b); + s += 2; + d += BPP; + } while (-- width != 0); +#endif +} + +#undef DEPTH +#undef BPP +#undef PIXEL_TYPE diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c new file mode 100644 index 000000000..543d1f2bd --- /dev/null +++ b/hw/omap_lcdc.c @@ -0,0 +1,499 @@ +/* + * OMAP LCD controller. + * + * Copyright (C) 2006-2007 Andrzej Zaborowski + * + * 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 "vl.h" + +struct omap_lcd_panel_s { + target_phys_addr_t base; + qemu_irq irq; + DisplayState *state; + ram_addr_t imif_base; + ram_addr_t emiff_base; + + int plm; + int tft; + int mono; + int enable; + int width; + int height; + int interrupts; + uint32_t timing[3]; + uint32_t subpanel; + uint32_t ctrl; + + struct omap_dma_lcd_channel_s *dma; + uint16_t palette[256]; + int palette_done; + int frame_done; + int invalidate; + int sync_error; +}; + +static void omap_lcd_interrupts(struct omap_lcd_panel_s *s) +{ + if (s->frame_done && (s->interrupts & 1)) { + qemu_irq_raise(s->irq); + return; + } + + if (s->palette_done && (s->interrupts & 2)) { + qemu_irq_raise(s->irq); + return; + } + + if (s->sync_error) { + qemu_irq_raise(s->irq); + return; + } + + qemu_irq_lower(s->irq); +} + +#include "pixel_ops.h" + +typedef void draw_line_func( + uint8_t *d, const uint8_t *s, int width, const uint16_t *pal); + +#define DEPTH 8 +#include "omap_lcd_template.h" +#define DEPTH 15 +#include "omap_lcd_template.h" +#define DEPTH 16 +#include "omap_lcd_template.h" +#define DEPTH 32 +#include "omap_lcd_template.h" + +static draw_line_func *draw_line_table2[33] = { + [0 ... 32] = 0, + [8] = draw_line2_8, + [15] = draw_line2_15, + [16] = draw_line2_16, + [32] = draw_line2_32, +}, *draw_line_table4[33] = { + [0 ... 32] = 0, + [8] = draw_line4_8, + [15] = draw_line4_15, + [16] = draw_line4_16, + [32] = draw_line4_32, +}, *draw_line_table8[33] = { + [0 ... 32] = 0, + [8] = draw_line8_8, + [15] = draw_line8_15, + [16] = draw_line8_16, + [32] = draw_line8_32, +}, *draw_line_table12[33] = { + [0 ... 32] = 0, + [8] = draw_line12_8, + [15] = draw_line12_15, + [16] = draw_line12_16, + [32] = draw_line12_32, +}, *draw_line_table16[33] = { + [0 ... 32] = 0, + [8] = draw_line16_8, + [15] = draw_line16_15, + [16] = draw_line16_16, + [32] = draw_line16_32, +}; + +void omap_update_display(void *opaque) +{ + struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; + draw_line_func *draw_line; + int size, dirty[2], minline, maxline, height; + int line, width, linesize, step, bpp, frame_offset; + ram_addr_t frame_base, scanline, newline, x; + uint8_t *s, *d; + + if (!omap_lcd || omap_lcd->plm == 1 || + !omap_lcd->enable || !omap_lcd->state->depth) + return; + + frame_offset = 0; + if (omap_lcd->plm != 2) { + memcpy(omap_lcd->palette, phys_ram_base + + omap_lcd->dma->phys_framebuffer[ + omap_lcd->dma->current_frame], 0x200); + switch (omap_lcd->palette[0] >> 12 & 7) { + case 3 ... 7: + frame_offset += 0x200; + break; + default: + frame_offset += 0x20; + } + } + + /* Colour depth */ + switch ((omap_lcd->palette[0] >> 12) & 7) { + case 1: + draw_line = draw_line_table2[omap_lcd->state->depth]; + bpp = 2; + break; + + case 2: + draw_line = draw_line_table4[omap_lcd->state->depth]; + bpp = 4; + break; + + case 3: + draw_line = draw_line_table8[omap_lcd->state->depth]; + bpp = 8; + break; + + case 4 ... 7: + if (!omap_lcd->tft) + draw_line = draw_line_table12[omap_lcd->state->depth]; + else + draw_line = draw_line_table16[omap_lcd->state->depth]; + bpp = 16; + break; + + default: + /* Unsupported at the moment. */ + return; + } + + /* Resolution */ + width = omap_lcd->width; + if (width != omap_lcd->state->width || + omap_lcd->height != omap_lcd->state->height) { + dpy_resize(omap_lcd->state, + omap_lcd->width, omap_lcd->height); + omap_lcd->invalidate = 1; + } + + if (omap_lcd->dma->current_frame == 0) + size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top; + else + size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top; + + if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) { + omap_lcd->sync_error = 1; + omap_lcd_interrupts(omap_lcd); + omap_lcd->enable = 0; + return; + } + + /* Content */ + frame_base = omap_lcd->dma->phys_framebuffer[ + omap_lcd->dma->current_frame] + frame_offset; + omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame; + if (omap_lcd->dma->interrupts & 1) + qemu_irq_raise(omap_lcd->dma->irq); + if (omap_lcd->dma->dual) + omap_lcd->dma->current_frame ^= 1; + + if (!omap_lcd->state->depth) + return; + + line = 0; + height = omap_lcd->height; + if (omap_lcd->subpanel & (1 << 31)) { + if (omap_lcd->subpanel & (1 << 29)) + line = (omap_lcd->subpanel >> 16) & 0x3ff; + else + height = (omap_lcd->subpanel >> 16) & 0x3ff; + /* TODO: fill the rest of the panel with DPD */ + } + step = width * bpp >> 3; + scanline = frame_base + step * line; + s = (uint8_t *) (phys_ram_base + scanline); + d = omap_lcd->state->data; + linesize = omap_lcd->state->linesize; + + dirty[0] = dirty[1] = + cpu_physical_memory_get_dirty(scanline, VGA_DIRTY_FLAG); + minline = height; + maxline = line; + for (; line < height; line ++) { + newline = scanline + step; + for (x = scanline + TARGET_PAGE_SIZE; x < newline; + x += TARGET_PAGE_SIZE) { + dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG); + dirty[0] |= dirty[1]; + } + if (dirty[0] || omap_lcd->invalidate) { + draw_line(d, s, width, omap_lcd->palette); + if (line < minline) + minline = line; + maxline = line + 1; + } + scanline = newline; + dirty[0] = dirty[1]; + s += step; + d += linesize; + } + + if (maxline >= minline) { + dpy_update(omap_lcd->state, 0, minline, width, maxline); + cpu_physical_memory_reset_dirty(frame_base + step * minline, + frame_base + step * maxline, VGA_DIRTY_FLAG); + } +} + +static int ppm_save(const char *filename, uint8_t *data, + int w, int h, int linesize) +{ + FILE *f; + uint8_t *d, *d1; + unsigned int v; + int y, x, bpp; + + f = fopen(filename, "wb"); + if (!f) + return -1; + fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); + d1 = data; + bpp = linesize / w; + for (y = 0; y < h; y ++) { + d = d1; + for (x = 0; x < w; x ++) { + v = *(uint32_t *) d; + switch (bpp) { + case 2: + fputc((v >> 8) & 0xf8, f); + fputc((v >> 3) & 0xfc, f); + fputc((v << 3) & 0xf8, f); + break; + case 3: + case 4: + default: + fputc((v >> 16) & 0xff, f); + fputc((v >> 8) & 0xff, f); + fputc((v) & 0xff, f); + break; + } + d += bpp; + } + d1 += linesize; + } + fclose(f); + return 0; +} + +void omap_screen_dump(void *opaque, const char *filename) { + struct omap_lcd_panel_s *omap_lcd = opaque; + omap_update_display(opaque); + if (omap_lcd && omap_lcd->state->data) + ppm_save(filename, omap_lcd->state->data, + omap_lcd->width, omap_lcd->height, + omap_lcd->state->linesize); +} + +void omap_invalidate_display(void *opaque) { + struct omap_lcd_panel_s *omap_lcd = opaque; + omap_lcd->invalidate = 1; +} + +void omap_lcd_update(struct omap_lcd_panel_s *s) { + if (!s->enable) { + s->dma->current_frame = -1; + s->sync_error = 0; + if (s->plm != 1) + s->frame_done = 1; + omap_lcd_interrupts(s); + return; + } + + if (s->dma->current_frame == -1) { + s->frame_done = 0; + s->palette_done = 0; + s->dma->current_frame = 0; + } + + if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu, + s->dma->src_f1_top) || + !s->dma->mpu->port[ + s->dma->src].addr_valid(s->dma->mpu, + s->dma->src_f1_bottom) || + (s->dma->dual && + (!s->dma->mpu->port[ + s->dma->src].addr_valid(s->dma->mpu, + s->dma->src_f2_top) || + !s->dma->mpu->port[ + s->dma->src].addr_valid(s->dma->mpu, + s->dma->src_f2_bottom)))) { + s->dma->condition |= 1 << 2; + if (s->dma->interrupts & (1 << 1)) + qemu_irq_raise(s->dma->irq); + s->enable = 0; + return; + } + + if (s->dma->src == imif) { + /* Framebuffers are in SRAM */ + s->dma->phys_framebuffer[0] = s->imif_base + + s->dma->src_f1_top - OMAP_IMIF_BASE; + + s->dma->phys_framebuffer[1] = s->imif_base + + s->dma->src_f2_top - OMAP_IMIF_BASE; + } else { + /* Framebuffers are in RAM */ + s->dma->phys_framebuffer[0] = s->emiff_base + + s->dma->src_f1_top - OMAP_EMIFF_BASE; + + s->dma->phys_framebuffer[1] = s->emiff_base + + s->dma->src_f2_top - OMAP_EMIFF_BASE; + } + + if (s->plm != 2 && !s->palette_done) { + memcpy(s->palette, phys_ram_base + + s->dma->phys_framebuffer[s->dma->current_frame], 0x200); + s->palette_done = 1; + omap_lcd_interrupts(s); + } +} + +static uint32_t omap_lcdc_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* LCD_CONTROL */ + return (s->tft << 23) | (s->plm << 20) | + (s->tft << 7) | (s->interrupts << 3) | + (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34; + + case 0x04: /* LCD_TIMING0 */ + return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f; + + case 0x08: /* LCD_TIMING1 */ + return (s->timing[1] << 10) | (s->height - 1); + + case 0x0c: /* LCD_TIMING2 */ + return s->timing[2] | 0xfc000000; + + case 0x10: /* LCD_STATUS */ + return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done; + + case 0x14: /* LCD_SUBPANEL */ + return s->subpanel; + + default: + break; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_lcdc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* LCD_CONTROL */ + s->plm = (value >> 20) & 3; + s->tft = (value >> 7) & 1; + s->interrupts = (value >> 3) & 3; + s->mono = (value >> 1) & 1; + s->ctrl = value & 0x01cff300; + if (s->enable != (value & 1)) { + s->enable = value & 1; + omap_lcd_update(s); + } + break; + + case 0x04: /* LCD_TIMING0 */ + s->timing[0] = value >> 10; + s->width = (value & 0x3ff) + 1; + break; + + case 0x08: /* LCD_TIMING1 */ + s->timing[1] = value >> 10; + s->height = (value & 0x3ff) + 1; + break; + + case 0x0c: /* LCD_TIMING2 */ + s->timing[2] = value; + break; + + case 0x10: /* LCD_STATUS */ + break; + + case 0x14: /* LCD_SUBPANEL */ + s->subpanel = value & 0xa1ffffff; + break; + + default: + OMAP_BAD_REG(addr); + } +} + +static CPUReadMemoryFunc *omap_lcdc_readfn[] = { + omap_lcdc_read, + omap_lcdc_read, + omap_lcdc_read, +}; + +static CPUWriteMemoryFunc *omap_lcdc_writefn[] = { + omap_lcdc_write, + omap_lcdc_write, + omap_lcdc_write, +}; + +void omap_lcdc_reset(struct omap_lcd_panel_s *s) +{ + s->dma->current_frame = -1; + s->plm = 0; + s->tft = 0; + s->mono = 0; + s->enable = 0; + s->width = 0; + s->height = 0; + s->interrupts = 0; + s->timing[0] = 0; + s->timing[1] = 0; + s->timing[2] = 0; + s->subpanel = 0; + s->palette_done = 0; + s->frame_done = 0; + s->sync_error = 0; + s->invalidate = 1; + s->subpanel = 0; + s->ctrl = 0; +} + +struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, + struct omap_dma_lcd_channel_s *dma, DisplayState *ds, + ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk) +{ + int iomemtype; + struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) + qemu_mallocz(sizeof(struct omap_lcd_panel_s)); + + s->irq = irq; + s->dma = dma; + s->base = base; + s->state = ds; + s->imif_base = imif_base; + s->emiff_base = emiff_base; + omap_lcdc_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_lcdc_readfn, + omap_lcdc_writefn, s); + cpu_register_physical_memory(s->base, 0x100, iomemtype); + + graphic_console_init(ds, omap_update_display, + omap_invalidate_display, omap_screen_dump, s); + + return s; +} diff --git a/hw/palm.c b/hw/palm.c new file mode 100644 index 000000000..623fcd648 --- /dev/null +++ b/hw/palm.c @@ -0,0 +1,140 @@ +/* + * PalmOne's (TM) PDAs. + * + * Copyright (C) 2006-2007 Andrzej Zaborowski + * + * 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 "vl.h" + +static uint32_t static_readb(void *opaque, target_phys_addr_t offset) +{ + uint32_t *val = (uint32_t *) opaque; + return *val >> ((offset & 3) << 3); +} + +static uint32_t static_readh(void *opaque, target_phys_addr_t offset) { + uint32_t *val = (uint32_t *) opaque; + return *val >> ((offset & 1) << 3); +} + +static uint32_t static_readw(void *opaque, target_phys_addr_t offset) { + uint32_t *val = (uint32_t *) opaque; + return *val >> ((offset & 0) << 3); +} + +static void static_write(void *opaque, target_phys_addr_t offset, + uint32_t value) { +#ifdef SPY + printf("%s: value %08lx written at " PA_FMT "\n", + __FUNCTION__, value, offset); +#endif +} + +static CPUReadMemoryFunc *static_readfn[] = { + static_readb, + static_readh, + static_readw, +}; + +static CPUWriteMemoryFunc *static_writefn[] = { + static_write, + static_write, + static_write, +}; + +/* Palm Tunsgten|E support */ +static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) +{ +} + +static void palmte_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + struct omap_mpu_state_s *cpu; + int flash_size = 0x00800000; + int sdram_size = 0x02000000; + int io; + static uint32_t cs0val = 0xffffffff; + static uint32_t cs1val = 0x0000e1a0; + static uint32_t cs2val = 0x0000e1a0; + static uint32_t cs3val = 0xe1a0e1a0; + ram_addr_t phys_flash; + int rom_size, rom_loaded = 0; + + if (ram_size < flash_size + sdram_size + OMAP15XX_SRAM_SIZE) { + fprintf(stderr, "This architecture uses %i bytes of memory\n", + flash_size + sdram_size + OMAP15XX_SRAM_SIZE); + exit(1); + } + + cpu = omap310_mpu_init(sdram_size, ds, cpu_model); + + /* External Flash (EMIFS) */ + cpu_register_physical_memory(OMAP_CS0_BASE, flash_size, + (phys_flash = qemu_ram_alloc(flash_size)) | IO_MEM_ROM); + + io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs0val); + cpu_register_physical_memory(OMAP_CS0_BASE + flash_size, + OMAP_CS0_SIZE - flash_size, io); + io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs1val); + cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io); + io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs2val); + cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io); + io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs3val); + cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io); + + palmte_microwire_setup(cpu); + + /* Setup initial (reset) machine state */ + if (nb_option_roms) { + rom_size = get_image_size(option_rom[0]); + if (rom_size > flash_size) + fprintf(stderr, "%s: ROM image too big (%x > %x)\n", + __FUNCTION__, rom_size, flash_size); + else if (rom_size > 0 && load_image(option_rom[0], + phys_ram_base + phys_flash) > 0) { + rom_loaded = 1; + cpu->env->regs[15] = 0x00000000; + } else + fprintf(stderr, "%s: error loading '%s'\n", + __FUNCTION__, option_rom[0]); + } + + if (!rom_loaded && !kernel_filename) { + fprintf(stderr, "Kernel or ROM image must be specified\n"); + exit(1); + } + + /* Load the kernel. */ + if (kernel_filename) { + /* Start at bootloader. */ + cpu->env->regs[15] = OMAP_EMIFF_BASE; + + arm_load_kernel(cpu->env, sdram_size, kernel_filename, kernel_cmdline, + initrd_filename, 0x331, OMAP_EMIFF_BASE); + } + + dpy_resize(ds, 320, 320); +} + +QEMUMachine palmte_machine = { + "cheetah", + "Palm Tungsten|E aka. Cheetah PDA (OMAP310)", + palmte_init, +}; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 5bd40ffbc..ef203c331 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -99,6 +99,10 @@ typedef struct CPUARMState { uint32_t c13_fcse; /* FCSE PID. */ uint32_t c13_context; /* Context ID. */ uint32_t c15_cpar; /* XScale Coprocessor Access Register */ + uint32_t c15_ticonfig; /* TI925T configuration byte. */ + uint32_t c15_i_max; /* Maximum D-cache dirty line index. */ + uint32_t c15_i_min; /* Minimum D-cache dirty line index. */ + uint32_t c15_threadid; /* TI debugger thread-ID. */ } cp15; /* Coprocessor IO used by peripherals */ @@ -247,7 +251,8 @@ enum arm_features { ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */ - ARM_FEATURE_MPU /* Only has Memory Protection Unit, not full MMU. */ + ARM_FEATURE_MPU, /* Only has Memory Protection Unit, not full MMU. */ + ARM_FEATURE_OMAPCP /* OMAP specific CP15 ops handling. */ }; static inline int arm_feature(CPUARMState *env, int feature) @@ -265,6 +270,8 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define ARM_CPUID_ARM1026 0x4106a262 #define ARM_CPUID_ARM926 0x41069265 #define ARM_CPUID_ARM946 0x41059461 +#define ARM_CPUID_TI915T 0x54029152 +#define ARM_CPUID_TI925T 0x54029252 #define ARM_CPUID_PXA250 0x69052100 #define ARM_CPUID_PXA255 0x69052d00 #define ARM_CPUID_PXA260 0x69052903 diff --git a/target-arm/helper.c b/target-arm/helper.c index 61f810906..260a04aa0 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -32,6 +32,15 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cachetype = 0x1dd20d2; env->cp15.c1_sys = 0x00090078; break; + case ARM_CPUID_TI915T: + case ARM_CPUID_TI925T: + set_feature(env, ARM_FEATURE_OMAPCP); + env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */ + env->cp15.c0_cachetype = 0x5109149; + env->cp15.c1_sys = 0x00000070; + env->cp15.c15_i_max = 0x000; + env->cp15.c15_i_min = 0xff0; + break; case ARM_CPUID_PXA250: case ARM_CPUID_PXA255: case ARM_CPUID_PXA260: @@ -101,6 +110,7 @@ static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_ARM926, "arm926"}, { ARM_CPUID_ARM946, "arm946"}, { ARM_CPUID_ARM1026, "arm1026"}, + { ARM_CPUID_TI925T, "ti925t" }, { ARM_CPUID_PXA250, "pxa250" }, { ARM_CPUID_PXA255, "pxa255" }, { ARM_CPUID_PXA260, "pxa260" }, @@ -644,8 +654,12 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 0: /* ID codes. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) break; + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + break; goto bad_reg; case 1: /* System configuration. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; switch (op2) { case 0: if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0) @@ -693,6 +707,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 4: /* Reserved. */ goto bad_reg; case 5: /* MMU Fault status / MPU access permission. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; switch (op2) { case 0: if (arm_feature(env, ARM_FEATURE_MPU)) @@ -724,6 +740,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) goto bad_reg; env->cp15.c6_region[crm] = val; } else { + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; switch (op2) { case 0: env->cp15.c6_data = val; @@ -737,6 +755,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) } break; case 7: /* Cache control. */ + env->cp15.c15_i_max = 0x000; + env->cp15.c15_i_min = 0xff0; /* No cache, so nothing to do. */ break; case 8: /* MMU TLB control. */ @@ -763,6 +783,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) } break; case 9: + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + break; switch (crm) { case 0: /* Cache lockdown. */ switch (op2) { @@ -823,6 +845,31 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) } goto bad_reg; } + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { + switch (crm) { + case 0: + break; + case 1: /* Set TI925T configuration. */ + env->cp15.c15_ticonfig = val & 0xe7; + env->cp15.c0_cpuid = (val & (1 << 5)) ? /* OS_TYPE bit */ + ARM_CPUID_TI915T : ARM_CPUID_TI925T; + break; + case 2: /* Set I_max. */ + env->cp15.c15_i_max = val; + break; + case 3: /* Set I_min. */ + env->cp15.c15_i_min = val; + break; + case 4: /* Set thread-ID. */ + env->cp15.c15_threadid = val & 0xffff; + break; + case 8: /* Wait-for-interrupt (deprecated). */ + cpu_interrupt(env, CPU_INTERRUPT_HALT); + break; + default: + goto bad_reg; + } + } break; } return; @@ -834,8 +881,10 @@ bad_reg: uint32_t helper_get_cp15(CPUState *env, uint32_t insn) { uint32_t op2; + uint32_t crm; op2 = (insn >> 5) & 7; + crm = insn & 0xf; switch ((insn >> 16) & 0xf) { case 0: /* ID codes. */ switch (op2) { @@ -849,6 +898,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) return 0; } case 1: /* System configuration. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; switch (op2) { case 0: /* Control register. */ return env->cp15.c1_sys; @@ -885,6 +936,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 4: /* Reserved. */ goto bad_reg; case 5: /* MMU Fault status / MPU access permission. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; switch (op2) { case 0: if (arm_feature(env, ARM_FEATURE_MPU)) @@ -913,6 +966,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) goto bad_reg; return env->cp15.c6_region[n]; } else { + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + op2 = 0; switch (op2) { case 0: return env->cp15.c6_data; @@ -933,6 +988,8 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 8: /* MMU TLB control. */ goto bad_reg; case 9: /* Cache lockdown. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + return 0; switch (op2) { case 0: return env->cp15.c9_data; @@ -960,11 +1017,28 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) goto bad_reg; case 15: /* Implementation specific. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { - if (op2 == 0 && (insn & 0xf) == 1) + if (op2 == 0 && crm == 1) return env->cp15.c15_cpar; goto bad_reg; } + if (arm_feature(env, ARM_FEATURE_OMAPCP)) { + switch (crm) { + case 0: + return 0; + case 1: /* Read TI925T configuration. */ + return env->cp15.c15_ticonfig; + case 2: /* Read I_max. */ + return env->cp15.c15_i_max; + case 3: /* Read I_min. */ + return env->cp15.c15_i_min; + case 4: /* Read thread-ID. */ + return env->cp15.c15_threadid; + case 8: /* TI925T_status */ + return 0; + } + goto bad_reg; + } return 0; } bad_reg: diff --git a/vl.c b/vl.c index dc2297ecf..4ff234132 100644 --- a/vl.c +++ b/vl.c @@ -6999,6 +6999,7 @@ void register_machines(void) qemu_register_machine(&spitzpda_machine); qemu_register_machine(&borzoipda_machine); qemu_register_machine(&terrierpda_machine); + qemu_register_machine(&palmte_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); #elif defined(TARGET_ALPHA) diff --git a/vl.h b/vl.h index d943e7f48..242b4bc3d 100644 --- a/vl.h +++ b/vl.h @@ -1417,6 +1417,9 @@ extern QEMUMachine spitzpda_machine; extern QEMUMachine borzoipda_machine; extern QEMUMachine terrierpda_machine; +/* palm.c */ +extern QEMUMachine palmte_machine; + /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); @@ -1606,6 +1609,8 @@ void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); #include "hw/pxa.h" +#include "hw/omap.h" + /* mcf_uart.c */ uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr); void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val); -- cgit v1.2.3 From ae5d8053a124508650140fc72cccf9f2bd131871 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 29 Jul 2007 22:11:46 +0000 Subject: Fix MIPS cache configuration, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3092 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 687e3e52e..85d5032a2 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -28,15 +28,11 @@ (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) | \ (0x2 << CP0C0_K0)) -/* Have config2, 64 sets Icache, 16 bytes Icache line, - 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache, - no coprocessor2 attached, no MDMX support attached, +/* Have config2, no coprocessor2 attached, no MDMX support attached, no performance counters, watch registers present, no code compression, EJTAG present, no FPU */ #define MIPS_CONFIG1 \ ((1 << CP0C1_M) | \ - (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \ - (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \ (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \ (0 << CP0C1_FP)) @@ -82,7 +78,9 @@ static mips_def_t mips_defs[] = .name = "4Kc", .CP0_PRid = 0x00018000, .CP0_Config0 = MIPS_CONFIG0, - .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU), + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -94,7 +92,9 @@ static mips_def_t mips_defs[] = .name = "4KEcR1", .CP0_PRid = 0x00018400, .CP0_Config0 = MIPS_CONFIG0, - .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU), + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -106,7 +106,9 @@ static mips_def_t mips_defs[] = .name = "4KEc", .CP0_PRid = 0x00019000, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), - .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU), + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -118,7 +120,9 @@ static mips_def_t mips_defs[] = .name = "24Kc", .CP0_PRid = 0x00019300, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), - .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU), + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -130,7 +134,9 @@ static mips_def_t mips_defs[] = .name = "24Kf", .CP0_PRid = 0x00019300, .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), - .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, @@ -145,7 +151,9 @@ static mips_def_t mips_defs[] = .name = "R4000", .CP0_PRid = 0x00000400, .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT), - .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 16, -- cgit v1.2.3 From 330c4d61a65801b994e7498163cec3ca74c4ece4 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 29 Jul 2007 22:21:45 +0000 Subject: Fix XScale MMU's extended small pages. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3093 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 260a04aa0..8132d0caf 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -516,16 +516,16 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, ap = (desc >> (4 + ((address >> 13) & 6))) & 3; break; case 3: /* 1k page. */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - else { - if (type == 1) { + if (type == 1) { + if (arm_feature(env, ARM_FEATURE_XSCALE)) + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + else { /* Page translation fault. */ code = 7; goto do_fault; } + } else phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); - } ap = (desc >> 4) & 3; break; default: -- cgit v1.2.3 From 724d3a8f2932f90e3527752f4b59f3607ceeb863 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 30 Jul 2007 23:54:51 +0000 Subject: Re-add clearing of the APP_CMD flag that somehow got lost. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3094 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sd.c | 5 +++-- hw/sd.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/sd.c b/hw/sd.c index 799c94533..7974564ec 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -1151,9 +1151,10 @@ int sd_do_command(SDState *sd, struct sd_request_s *req, return 0; } - if (last_status & APP_CMD) + if (last_status & APP_CMD) { rtype = sd_app_command(sd, *req); - else + sd->card_status &= ~APP_CMD; + } else rtype = sd_normal_command(sd, *req); sd->current_cmd = req->cmd; diff --git a/hw/sd.h b/hw/sd.h index cc05dbf17..2851e729f 100644 --- a/hw/sd.h +++ b/hw/sd.h @@ -56,8 +56,8 @@ typedef enum { sd_none = -1, sd_bc = 0, /* broadcast -- no response */ - sd_bcr, /* broadcast with response */ - sd_ac, /* addressed -- no data transfer */ + sd_bcr, /* broadcast with response */ + sd_ac, /* addressed -- no data transfer */ sd_adtc, /* addressed with data transfer */ } sd_cmd_type_t; -- cgit v1.2.3 From cfa0b71dd84977b9378a9100b759739ef9220ac6 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 31 Jul 2007 01:42:29 +0000 Subject: Fix OMAP pic handling of simultaneous interrupts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3095 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index fe4f9c40f..0684a2de2 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -70,16 +70,20 @@ struct omap_intr_handler_s { static void omap_inth_update(struct omap_intr_handler_s *s) { - uint32_t irq = s->new_irq_agr & s->irqs & ~s->mask & ~s->fiq; - uint32_t fiq = s->new_fiq_agr & s->irqs & ~s->mask & s->fiq; + uint32_t irq = s->irqs & ~s->mask & ~s->fiq; + uint32_t fiq = s->irqs & ~s->mask & s->fiq; - qemu_set_irq(s->parent_pic[ARM_PIC_CPU_IRQ], irq); - if (irq) - s->new_irq_agr = 0; + if (s->new_irq_agr || !irq) { + qemu_set_irq(s->parent_pic[ARM_PIC_CPU_IRQ], irq); + if (irq) + s->new_irq_agr = 0; + } - qemu_set_irq(s->parent_pic[ARM_PIC_CPU_FIQ], fiq); - if (fiq) - s->new_fiq_agr = 0; + if (s->new_fiq_agr || !irq) { + qemu_set_irq(s->parent_pic[ARM_PIC_CPU_FIQ], fiq); + if (fiq) + s->new_fiq_agr = 0; + } } static void omap_inth_sir_update(struct omap_intr_handler_s *s) @@ -124,7 +128,7 @@ static void omap_set_intr(void *opaque, int irq, int req) if (req) { rise = ~ih->irqs & (1 << irq); ih->irqs |= rise; - ih->stats[irq] ++; + ih->stats[irq] += !!rise; } else { rise = ih->sens_edge & ih->irqs & (1 << irq); ih->irqs &= ~rise; -- cgit v1.2.3 From 1af2b62d123ae5601eb44786faf3be17aed1b2b2 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 31 Jul 2007 01:43:17 +0000 Subject: OMAP DMA input signals must be level-triggered. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3096 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index 0684a2de2..d524e82cd 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -403,6 +403,7 @@ struct omap_dma_s { target_phys_addr_t base; omap_clk clk; int64_t delay; + uint32_t drq; uint16_t gcr; int run_count; @@ -511,7 +512,7 @@ next_channel: if (request > 0) s->ch[channel].status |= 0x40; /* External request */ - if (s->delay) + if (s->delay && !qemu_timer_pending(s->tm)) qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); if (request > 0) { @@ -593,7 +594,8 @@ static void omap_dma_channel_run(struct omap_dma_s *s) if (s->ch[ch].interrupts & 0x08) s->ch[ch].status |= 0x08; - if (s->ch[ch].sync && s->ch[ch].fs) { + if (s->ch[ch].sync && s->ch[ch].fs && + !(s->drq & (1 << s->ch[ch].sync))) { s->ch[ch].status &= ~0x40; omap_dma_request_stop(s, ch); } @@ -607,7 +609,8 @@ static void omap_dma_channel_run(struct omap_dma_s *s) if (s->ch[ch].interrupts & 0x04) s->ch[ch].status |= 0x04; - if (s->ch[ch].sync && !s->ch[ch].fs) { + if (s->ch[ch].sync && !s->ch[ch].fs && + !(s->drq & (1 << s->ch[ch].sync))) { s->ch[ch].status &= ~0x40; omap_dma_request_stop(s, ch); } @@ -750,7 +753,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, s->ch[ch].running = 1; omap_dma_channel_load(s, ch); } - if (!s->ch[ch].sync) + if (!s->ch[ch].sync || (s->drq & (1 << s->ch[ch].sync))) omap_dma_request_run(s, ch, 0); } else { s->ch[ch].running = 0; @@ -949,9 +952,14 @@ static CPUWriteMemoryFunc *omap_dma_writefn[] = { static void omap_dma_request(void *opaque, int drq, int req) { struct omap_dma_s *s = (struct omap_dma_s *) opaque; - /* All the request pins are edge triggered. */ - if (req) - omap_dma_request_run(s, 0, drq); + /* The request pins are level triggered. */ + if (req) { + if (~s->drq & (1 << drq)) { + s->drq |= 1 << drq; + omap_dma_request_run(s, 0, drq); + } + } else + s->drq &= ~(1 << drq); } static void omap_dma_clk_update(void *opaque, int line, int on) @@ -974,6 +982,7 @@ static void omap_dma_reset(struct omap_dma_s *s) qemu_del_timer(s->tm); s->gcr = 0x0004; + s->drq = 0x00000000; s->run_count = 0; s->lcd_ch.src = emiff; s->lcd_ch.condition = 0; @@ -1002,6 +1011,7 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); mpu->drq = qemu_allocate_irqs(omap_dma_request, s, 32); omap_dma_reset(s); + omap_dma_clk_update(s, 0, 1); iomemtype = cpu_register_io_memory(0, omap_dma_readfn, omap_dma_writefn, s); -- cgit v1.2.3 From b30bb3a2e8ebb138494eca055bab75a4ac9c0a26 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 31 Jul 2007 01:45:35 +0000 Subject: Add OMAP MMC/SD host controller. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3097 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/omap.c | 12 +- hw/omap.h | 17 +- hw/omap_mmc.c | 531 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 556 insertions(+), 6 deletions(-) create mode 100644 hw/omap_mmc.c diff --git a/Makefile.target b/Makefile.target index f99573d1d..e2c751751 100644 --- a/Makefile.target +++ b/Makefile.target @@ -463,7 +463,7 @@ VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o -VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o palm.o +VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) diff --git a/hw/omap.c b/hw/omap.c index d524e82cd..e56e663a1 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -22,25 +22,25 @@ #include "arm_pic.h" /* Should signal the TCMI */ -static uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) +uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) { OMAP_16B_REG(addr); return 0; } -static void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, +void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, uint32_t value) { OMAP_16B_REG(addr); } -static uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr) +uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr) { OMAP_32B_REG(addr); return 0; } -static void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, +void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, uint32_t value) { OMAP_32B_REG(addr); @@ -2816,6 +2816,7 @@ static void omap_mpu_reset(void *opaque) omap_uart_reset(mpu->uart1); omap_uart_reset(mpu->uart2); omap_uart_reset(mpu->uart3); + omap_mmc_reset(mpu->mmc); cpu_reset(mpu->env); } @@ -2921,6 +2922,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); + s->mmc = omap_mmc_init(0xfffb7800, s->irq[1][OMAP_INT_OQN], + &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck")); + qemu_register_reset(omap_mpu_reset, s); s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; diff --git a/hw/omap.h b/hw/omap.h index e30d38cbf..16e764ba0 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -163,7 +163,7 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, # define OMAP_INT_USB_W2FC 20 # define OMAP_INT_1WIRE 21 # define OMAP_INT_OS_TIMER 22 -# define OMAP_INT_MMC 23 +# define OMAP_INT_OQN 23 # define OMAP_INT_GAUGE_32K 24 # define OMAP_INT_RTC_TIMER 25 # define OMAP_INT_RTC_ALARM 26 @@ -457,6 +457,12 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, struct omap_dma_lcd_channel_s *dma, DisplayState *ds, ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk); +/* omap_mmc.c */ +struct omap_mmc_s; +struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, + qemu_irq irq, qemu_irq dma[], omap_clk clk); +void omap_mmc_reset(struct omap_mmc_s *s); + # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) # define cpu_is_omap15xx(cpu) \ @@ -497,6 +503,8 @@ struct omap_mpu_state_s { struct omap_uart_s *uart1; struct omap_uart_s *uart2; + struct omap_mmc_s *mmc; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; @@ -566,6 +574,13 @@ struct omap_mpu_state_s { # error TARGET_PHYS_ADDR_BITS undefined # endif +uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr); +void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, + uint32_t value); +uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr); +void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, + uint32_t value); + # define OMAP_BAD_REG(paddr) \ printf("%s: Bad register " OMAP_FMT_plx "\n", __FUNCTION__, paddr) # define OMAP_RO_REG(paddr) \ diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c new file mode 100644 index 000000000..aa77660f2 --- /dev/null +++ b/hw/omap_mmc.c @@ -0,0 +1,531 @@ +/* + * OMAP on-chip MMC/SD host emulation. + * + * Copyright (C) 2006-2007 Andrzej Zaborowski + * + * 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 "vl.h" +#include "sd.h" + +struct omap_mmc_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq *dma; + omap_clk clk; + SDState *card; + uint16_t last_cmd; + uint16_t sdio; + uint16_t rsp[8]; + uint32_t arg; + int dw; + int mode; + int enable; + uint16_t status; + uint16_t mask; + uint8_t cto; + uint16_t dto; + uint16_t fifo[32]; + int fifo_start; + int fifo_len; + uint16_t blen; + uint16_t blen_counter; + uint16_t nblk; + uint16_t nblk_counter; + int tx_dma; + int rx_dma; + int af_level; + int ae_level; + + int ddir; + int transfer; +}; + +static void omap_mmc_interrupts_update(struct omap_mmc_s *s) +{ + qemu_set_irq(s->irq, !!(s->status & s->mask)); +} + +static void omap_mmc_fifolevel_update(struct omap_mmc_s *host) +{ + if (!host->transfer && !host->fifo_len) { + host->status &= 0xf3ff; + return; + } + + if (host->fifo_len > host->af_level && host->ddir) { + if (host->rx_dma) { + host->status &= 0xfbff; + qemu_irq_raise(host->dma[1]); + } else + host->status |= 0x0400; + } else { + host->status &= 0xfbff; + qemu_irq_lower(host->dma[1]); + } + + if (host->fifo_len < host->ae_level && !host->ddir) { + if (host->tx_dma) { + host->status &= 0xf7ff; + qemu_irq_raise(host->dma[0]); + } else + host->status |= 0x0800; + } else { + qemu_irq_lower(host->dma[0]); + host->status &= 0xf7ff; + } +} + +typedef enum { + sd_nore = 0, /* no response */ + sd_r1, /* normal response command */ + sd_r2, /* CID, CSD registers */ + sd_r3, /* OCR register */ + sd_r6 = 6, /* Published RCA response */ + sd_r1b = -1, +} sd_rsp_type_t; + +static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir, + sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init) +{ + uint32_t rspstatus, mask; + int rsplen, timeout; + struct sd_request_s request; + uint8_t response[16]; + + if (resptype == sd_r1 && busy) + resptype = sd_r1b; + + if (type == sd_adtc) { + host->fifo_start = 0; + host->fifo_len = 0; + host->transfer = 1; + host->ddir = dir; + } else + host->transfer = 0; + timeout = 0; + mask = 0; + rspstatus = 0; + + request.cmd = cmd; + request.arg = host->arg; + request.crc = 0; /* FIXME */ + + rsplen = sd_do_command(host->card, &request, response); + + /* TODO: validate CRCs */ + switch (resptype) { + case sd_nore: + rsplen = 0; + break; + + case sd_r1: + case sd_r1b: + if (rsplen < 4) { + timeout = 1; + break; + } + rsplen = 4; + + mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR | + ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION | + LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND | + CARD_ECC_FAILED | CC_ERROR | SD_ERROR | + CID_CSD_OVERWRITE; + if (host->sdio & (1 << 13)) + mask |= AKE_SEQ_ERROR; + rspstatus = (response[0] << 24) | (response[1] << 16) | + (response[2] << 8) | (response[3] << 0); + break; + + case sd_r2: + if (rsplen < 16) { + timeout = 1; + break; + } + rsplen = 16; + break; + + case sd_r3: + if (rsplen < 4) { + timeout = 1; + break; + } + rsplen = 4; + + rspstatus = (response[0] << 24) | (response[1] << 16) | + (response[2] << 8) | (response[3] << 0); + if (rspstatus & 0x80000000) + host->status &= 0xe000; + else + host->status |= 0x1000; + break; + + case sd_r6: + if (rsplen < 4) { + timeout = 1; + break; + } + rsplen = 4; + + mask = 0xe000 | AKE_SEQ_ERROR; + rspstatus = (response[2] << 8) | (response[3] << 0); + } + + if (rspstatus & mask) + host->status |= 0x4000; + else + host->status &= 0xb000; + + if (rsplen) + for (rsplen = 0; rsplen < 8; rsplen ++) + host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] | + (response[(rsplen << 1) | 0] << 8); + + if (timeout) + host->status |= 0x0080; + else if (cmd == 12) + host->status |= 0x0005; /* Makes it more real */ + else + host->status |= 0x0001; +} + +static void omap_mmc_transfer(struct omap_mmc_s *host) +{ + uint8_t value; + + if (!host->transfer) + return; + + while (1) { + if (host->ddir) { + if (host->fifo_len > host->af_level) + break; + + value = sd_read_data(host->card); + host->fifo[(host->fifo_start + host->fifo_len) & 31] = value; + if (-- host->blen_counter) { + value = sd_read_data(host->card); + host->fifo[(host->fifo_start + host->fifo_len) & 31] |= + value << 8; + host->blen_counter --; + } + + host->fifo_len ++; + } else { + if (!host->fifo_len) + break; + + value = host->fifo[host->fifo_start] & 0xff; + sd_write_data(host->card, value); + if (-- host->blen_counter) { + value = host->fifo[host->fifo_start] >> 8; + sd_write_data(host->card, value); + host->blen_counter --; + } + + host->fifo_start ++; + host->fifo_len --; + host->fifo_start &= 31; + } + + if (host->blen_counter == 0) { + host->nblk_counter --; + host->blen_counter = host->blen; + + if (host->nblk_counter == 0) { + host->nblk_counter = host->nblk; + host->transfer = 0; + host->status |= 0x0008; + break; + } + } + } +} + +static void omap_mmc_update(void *opaque) +{ + struct omap_mmc_s *s = opaque; + omap_mmc_transfer(s); + omap_mmc_fifolevel_update(s); + omap_mmc_interrupts_update(s); +} + +static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset) +{ + uint16_t i; + struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; + offset -= s->base; + + switch (offset) { + case 0x00: /* MMC_CMD */ + return s->last_cmd; + + case 0x04: /* MMC_ARGL */ + return s->arg & 0x0000ffff; + + case 0x08: /* MMC_ARGH */ + return s->arg >> 16; + + case 0x0c: /* MMC_CON */ + return (s->dw << 15) | (s->mode << 12) | (s->enable << 11); + + case 0x10: /* MMC_STAT */ + return s->status; + + case 0x14: /* MMC_IE */ + return s->mask; + + case 0x18: /* MMC_CTO */ + return s->cto; + + case 0x1c: /* MMC_DTO */ + return s->dto; + + case 0x20: /* MMC_DATA */ + /* TODO: support 8-bit access */ + i = s->fifo[s->fifo_start]; + if (s->fifo_len == 0) { + printf("MMC: FIFO underrun\n"); + return i; + } + s->fifo_start ++; + s->fifo_len --; + s->fifo_start &= 31; + omap_mmc_transfer(s); + omap_mmc_fifolevel_update(s); + omap_mmc_interrupts_update(s); + return i; + + case 0x24: /* MMC_BLEN */ + return s->blen_counter; + + case 0x28: /* MMC_NBLK */ + return s->nblk_counter; + + case 0x2c: /* MMC_BUF */ + return (s->rx_dma << 15) | (s->af_level << 8) | + (s->tx_dma << 7) | s->ae_level; + + case 0x30: /* MMC_SPI */ + return 0x0000; + case 0x34: /* MMC_SDIO */ + return s->sdio; + case 0x38: /* MMC_SYST */ + return 0x0000; + + case 0x3c: /* MMC_REV */ + return 0x0001; + + case 0x40: /* MMC_RSP0 */ + case 0x44: /* MMC_RSP1 */ + case 0x48: /* MMC_RSP2 */ + case 0x4c: /* MMC_RSP3 */ + case 0x50: /* MMC_RSP4 */ + case 0x54: /* MMC_RSP5 */ + case 0x58: /* MMC_RSP6 */ + case 0x5c: /* MMC_RSP7 */ + return s->rsp[(offset - 0x40) >> 2]; + } + + OMAP_BAD_REG(offset); + return 0; +} + +static void omap_mmc_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + int i; + struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; + offset -= s->base; + + switch (offset) { + case 0x00: /* MMC_CMD */ + if (!s->enable) + break; + + s->last_cmd = value; + for (i = 0; i < 8; i ++) + s->rsp[i] = 0x0000; + omap_mmc_command(s, value & 63, (value >> 15) & 1, + (sd_cmd_type_t) ((value >> 12) & 3), + (value >> 11) & 1, + (sd_rsp_type_t) ((value >> 8) & 7), + (value >> 7) & 1); + omap_mmc_update(s); + break; + + case 0x04: /* MMC_ARGL */ + s->arg &= 0xffff0000; + s->arg |= 0x0000ffff & value; + break; + + case 0x08: /* MMC_ARGH */ + s->arg &= 0x0000ffff; + s->arg |= value << 16; + break; + + case 0x0c: /* MMC_CON */ + s->dw = (value >> 15) & 1; + s->mode = (value >> 12) & 3; + s->enable = (value >> 11) & 1; + if (s->mode != 0) + printf("SD mode %i unimplemented!\n", s->mode); + if (s->dw != 0) + printf("4-bit SD bus enabled\n"); + break; + + case 0x10: /* MMC_STAT */ + s->status &= ~value; + omap_mmc_interrupts_update(s); + break; + + case 0x14: /* MMC_IE */ + s->mask = value; + omap_mmc_interrupts_update(s); + break; + + case 0x18: /* MMC_CTO */ + s->cto = value & 0xff; + if (s->cto > 0xfd) + printf("MMC: CTO of 0xff and 0xfe cannot be used!\n"); + break; + + case 0x1c: /* MMC_DTO */ + s->dto = value & 0xffff; + break; + + case 0x20: /* MMC_DATA */ + /* TODO: support 8-bit access */ + if (s->fifo_len == 32) + break; + s->fifo[(s->fifo_start + s->fifo_len) & 31] = value; + s->fifo_len ++; + omap_mmc_transfer(s); + omap_mmc_fifolevel_update(s); + omap_mmc_interrupts_update(s); + break; + + case 0x24: /* MMC_BLEN */ + s->blen = (value & 0x07ff) + 1; + s->blen_counter = s->blen; + break; + + case 0x28: /* MMC_NBLK */ + s->nblk = (value & 0x07ff) + 1; + s->nblk_counter = s->nblk; + s->blen_counter = s->blen; + break; + + case 0x2c: /* MMC_BUF */ + s->rx_dma = (value >> 15) & 1; + s->af_level = (value >> 8) & 0x1f; + s->tx_dma = (value >> 7) & 1; + s->ae_level = value & 0x1f; + + if (s->rx_dma) + s->status &= 0xfbff; + if (s->tx_dma) + s->status &= 0xf7ff; + omap_mmc_fifolevel_update(s); + omap_mmc_interrupts_update(s); + break; + + /* SPI, SDIO and TEST modes unimplemented */ + case 0x30: /* MMC_SPI */ + break; + case 0x34: /* MMC_SDIO */ + s->sdio = value & 0x2020; + break; + case 0x38: /* MMC_SYST */ + break; + + case 0x3c: /* MMC_REV */ + case 0x40: /* MMC_RSP0 */ + case 0x44: /* MMC_RSP1 */ + case 0x48: /* MMC_RSP2 */ + case 0x4c: /* MMC_RSP3 */ + case 0x50: /* MMC_RSP4 */ + case 0x54: /* MMC_RSP5 */ + case 0x58: /* MMC_RSP6 */ + case 0x5c: /* MMC_RSP7 */ + OMAP_RO_REG(offset); + break; + + default: + OMAP_BAD_REG(offset); + } +} + +static CPUReadMemoryFunc *omap_mmc_readfn[] = { + omap_badwidth_read16, + omap_mmc_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_mmc_writefn[] = { + omap_badwidth_write16, + omap_mmc_write, + omap_badwidth_write16, +}; + +void omap_mmc_reset(struct omap_mmc_s *host) +{ + host->last_cmd = 0; + memset(host->rsp, 0, sizeof(host->rsp)); + host->arg = 0; + host->dw = 0; + host->mode = 0; + host->enable = 0; + host->status = 0; + host->mask = 0; + host->cto = 0; + host->dto = 0; + host->fifo_len = 0; + host->blen = 0; + host->blen_counter = 0; + host->nblk = 0; + host->nblk_counter = 0; + host->tx_dma = 0; + host->rx_dma = 0; + host->ae_level = 0x00; + host->af_level = 0x1f; + host->transfer = 0; +} + +struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, + qemu_irq irq, qemu_irq dma[], omap_clk clk) +{ + int iomemtype; + struct omap_mmc_s *s = (struct omap_mmc_s *) + qemu_mallocz(sizeof(struct omap_mmc_s)); + + s->irq = irq; + s->base = base; + s->dma = dma; + s->clk = clk; + + iomemtype = cpu_register_io_memory(0, omap_mmc_readfn, + omap_mmc_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + /* Instantiate the storage */ + s->card = sd_init(sd_bdrv); + + return s; +} + +/* TODO: insertion and read-only handlers */ -- cgit v1.2.3 From 15d9ca0f9baa9f10f2b3e3e3d8554a802a3ab0ff Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 31 Jul 2007 23:07:32 +0000 Subject: A variant of move-if-change, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3098 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/configure b/configure index 7709c975f..705f6de03 100755 --- a/configure +++ b/configure @@ -699,6 +699,8 @@ config_h="config-host.h" #echo "Creating $config_mak and $config_h" +test -f $config_h && mv $config_h ${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 @@ -867,6 +869,8 @@ fi echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h +test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h + for target in $target_list; do target_dir="$target" config_mak=$target_dir/config.mak @@ -915,6 +919,8 @@ fi #echo "Creating $config_mak, $config_h and $target_dir/Makefile" +test -f $config_h && mv $config_h ${config_h}~ + mkdir -p $target_dir mkdir -p $target_dir/fpu if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then @@ -1074,6 +1080,8 @@ if test "$cocoa" = "yes" ; then echo "CONFIG_COCOA=yes" >> $config_mak fi +test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h + done # for target in $targets # build tree in object directory if source path is different from current one -- cgit v1.2.3 From a2cce02c48cb9fda5dff3f6a8505380af7d392ff Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 31 Jul 2007 23:09:18 +0000 Subject: Initialize old_exception, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3099 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index cbf17caa1..8ce542583 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -155,6 +155,8 @@ void cpu_reset(CPUX86State *env) tlb_flush(env, 1); + env->old_exception = -1; + /* init to reset state */ #ifdef CONFIG_SOFTMMU -- cgit v1.2.3 From 2bb081f7a0ffafb226f29c0a11f55d388d833c7e Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 31 Jul 2007 23:12:09 +0000 Subject: Fix i8259 initialization, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3100 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i8259.c b/hw/i8259.c index 4b25df3b9..506377079 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -351,7 +351,7 @@ static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case 1: s->irq_base = val & 0xf8; - s->init_state = s->single_mode && s->init4 ? 3 : 2; + s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2; break; case 2: if (s->init4) { -- cgit v1.2.3 From 96cf2df87cf9e3c39b147ee85b2e90d3620bdd41 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 31 Jul 2007 23:26:00 +0000 Subject: Cirrus transparent BITBLT (w/o color expand), by Hitoshi Osada. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3101 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cirrus_vga.c | 80 +++++++++++++++++++++++++++++++++++------ hw/cirrus_vga_rop.h | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 10 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index e5b0cfb65..d8633c988 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -402,7 +402,54 @@ static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = { cirrus_bitblt_rop_bkwd_notsrc_or_dst, cirrus_bitblt_rop_bkwd_notsrc_and_notdst, }; - + +#define TRANSP_ROP(name) {\ + name ## _8,\ + name ## _16,\ + } +#define TRANSP_NOP(func) {\ + func,\ + func,\ + } + +static const cirrus_bitblt_rop_t cirrus_fwd_transp_rop[16][2] = { + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_0), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_dst), + TRANSP_NOP(cirrus_bitblt_rop_nop), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_notdst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notdst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_1), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_xor_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_notdst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_notxor_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_notdst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_dst), + TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_notdst), +}; + +static const cirrus_bitblt_rop_t cirrus_bkwd_transp_rop[16][2] = { + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_0), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_dst), + TRANSP_NOP(cirrus_bitblt_rop_nop), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_notdst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notdst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_1), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_xor_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_notdst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_notxor_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_notdst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_dst), + TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_notdst), +}; + #define ROP2(name) {\ name ## _8,\ name ## _16,\ @@ -950,15 +997,28 @@ static void cirrus_bitblt_start(CirrusVGAState * s) s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; } } else { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { - s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; - s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; - s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]]; - } else { - s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]]; - } - } - + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { + if (s->cirrus_blt_pixelwidth > 2) { + printf("src transparent without colorexpand must be 8bpp or 16bpp\n"); + goto bitblt_ignore; + } + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } else { + s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; + } + } else { + if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { + s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; + s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; + s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]]; + } else { + s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]]; + } + } + } // setup bitblt engine. if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) { if (!cirrus_bitblt_cputovideo(s)) diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h index c54f1258b..fbee6edeb 100644 --- a/hw/cirrus_vga_rop.h +++ b/hw/cirrus_vga_rop.h @@ -62,6 +62,108 @@ glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s, } } +static void +glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s, + uint8_t *dst,const uint8_t *src, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) +{ + int x,y; + uint8_t p; + dstpitch -= bltwidth; + srcpitch -= bltwidth; + for (y = 0; y < bltheight; y++) { + for (x = 0; x < bltwidth; x++) { + p = *dst; + ROP_OP(p, *src); + if (p != s->gr[0x34]) *dst = p; + dst++; + src++; + } + dst += dstpitch; + src += srcpitch; + } +} + +static void +glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s, + uint8_t *dst,const uint8_t *src, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) +{ + int x,y; + uint8_t p; + dstpitch += bltwidth; + srcpitch += bltwidth; + for (y = 0; y < bltheight; y++) { + for (x = 0; x < bltwidth; x++) { + p = *dst; + ROP_OP(p, *src); + if (p != s->gr[0x34]) *dst = p; + dst--; + src--; + } + dst += dstpitch; + src += srcpitch; + } +} + +static void +glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s, + uint8_t *dst,const uint8_t *src, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) +{ + int x,y; + uint8_t p1, p2; + dstpitch -= bltwidth; + srcpitch -= bltwidth; + for (y = 0; y < bltheight; y++) { + for (x = 0; x < bltwidth; x+=2) { + p1 = *dst; + p2 = *(dst+1); + ROP_OP(p1, *src); + ROP_OP(p2, *(src+1)); + if ((p1 != s->gr[0x34]) || (p2 != s->gr[0x35])) { + *dst = p1; + *(dst+1) = p2; + } + dst+=2; + src+=2; + } + dst += dstpitch; + src += srcpitch; + } +} + +static void +glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s, + uint8_t *dst,const uint8_t *src, + int dstpitch,int srcpitch, + int bltwidth,int bltheight) +{ + int x,y; + uint8_t p1, p2; + dstpitch += bltwidth; + srcpitch += bltwidth; + for (y = 0; y < bltheight; y++) { + for (x = 0; x < bltwidth; x+=2) { + p1 = *(dst-1); + p2 = *dst; + ROP_OP(p1, *(src-1)); + ROP_OP(p2, *src); + if ((p1 != s->gr[0x34]) || (p2 != s->gr[0x35])) { + *(dst-1) = p1; + *dst = p2; + } + dst-=2; + src-=2; + } + dst += dstpitch; + src += srcpitch; + } +} + #define DEPTH 8 #include "cirrus_vga_rop2.h" -- cgit v1.2.3 From 6ada7453aa628cb6ed58e1cfd3119c90382ad017 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 31 Jul 2007 23:28:53 +0000 Subject: Parallels disk image support, by Alex Beregszaszi. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3102 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile | 2 +- Makefile.target | 2 +- block-parallels.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ block.c | 1 + vl.h | 1 + 6 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 block-parallels.c diff --git a/Changelog b/Changelog index d289df79b..fd2b5c692 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,7 @@ - Improved SH4 support (Magnus Damm) - MIPS64 support (Aurelien Jarno, Thiemo Seufer) - Preliminary Alpha guest support (J. Mayer) + - Read-only support for Parallels disk images (Alex Beregszaszi) version 0.9.0: diff --git a/Makefile b/Makefile index 0665cd912..36f11d27b 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ subdir-%: dyngen$(EXESUF) 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 +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 block-parallels.c $(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS) dyngen$(EXESUF): dyngen.c diff --git a/Makefile.target b/Makefile.target index e2c751751..6ffa6651e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -367,7 +367,7 @@ 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+=host-utils.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 +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 block-parallels.o VL_OBJS+=irq.o ifdef CONFIG_WIN32 VL_OBJS+=tap-win32.o diff --git a/block-parallels.c b/block-parallels.c new file mode 100644 index 000000000..b0fb99cee --- /dev/null +++ b/block-parallels.c @@ -0,0 +1,176 @@ +/* + * Block driver for Parallels disk image format + * + * Copyright (c) 2007 Alex Beregszaszi + * + * This code is based on comparing different disk images created by Parallels. + * + * 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 "WithoutFreeSpace" +#define HEADER_VERSION 2 +#define HEADER_SIZE 64 + +// always little-endian +struct parallels_header { + char magic[16]; // "WithoutFreeSpace" + uint32_t version; + uint32_t heads; + uint32_t cylinders; + uint32_t tracks; + uint32_t catalog_entries; + uint32_t nb_sectors; + char padding[24]; +} __attribute__((packed)); + +typedef struct BDRVParallelsState { + int fd; + + uint32_t *catalog_bitmap; + int catalog_size; + + int tracks; +} BDRVParallelsState; + +static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + const struct parallels_header *ph = (const void *)buf; + + if (buf_size < HEADER_SIZE) + return 0; + + if (!memcmp(ph->magic, HEADER_MAGIC, 16) && + (le32_to_cpu(ph->version) == HEADER_VERSION)) + return 100; + + return 0; +} + +static int parallels_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVParallelsState *s = bs->opaque; + int fd, i; + struct parallels_header ph; + + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); + if (fd < 0) { + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) + return -1; + } + + bs->read_only = 1; // no write support yet + + s->fd = fd; + + if (read(fd, &ph, sizeof(ph)) != sizeof(ph)) + goto fail; + + if (memcmp(ph.magic, HEADER_MAGIC, 16) || + (le32_to_cpu(ph.version) != HEADER_VERSION)) { + goto fail; + } + + bs->total_sectors = le32_to_cpu(ph.nb_sectors); + + if (lseek(s->fd, 64, SEEK_SET) != 64) + goto fail; + + s->tracks = le32_to_cpu(ph.tracks); + + s->catalog_size = le32_to_cpu(ph.catalog_entries); + 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]); + + return 0; +fail: + if (s->catalog_bitmap) + qemu_free(s->catalog_bitmap); + close(fd); + return -1; +} + +static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) +{ + BDRVParallelsState *s = bs->opaque; + uint32_t index, offset, position; + + index = sector_num / s->tracks; + offset = sector_num % s->tracks; + + // not allocated + if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0)) + return -1; + + position = (s->catalog_bitmap[index] + offset) * 512; + +// fprintf(stderr, "sector: %llx index=%x offset=%x pointer=%x position=%x\n", +// sector_num, index, offset, s->catalog_bitmap[index], position); + + if (lseek(s->fd, position, SEEK_SET) != position) + return -1; + + return 0; +} + +static int parallels_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVParallelsState *s = bs->opaque; + + while (nb_sectors > 0) { + if (!seek_to_sector(bs, sector_num)) { + if (read(s->fd, buf, 512) != 512) + return -1; + } else + memset(buf, 0, 512); + nb_sectors--; + sector_num++; + buf += 512; + } + return 0; +} + +static void parallels_close(BlockDriverState *bs) +{ + BDRVParallelsState *s = bs->opaque; + qemu_free(s->catalog_bitmap); + close(s->fd); +} + +BlockDriver bdrv_parallels = { + "parallels", + sizeof(BDRVParallelsState), + parallels_probe, + parallels_open, + parallels_read, + NULL, + parallels_close, +}; diff --git a/block.c b/block.c index 82bbf60d2..269a39746 100644 --- a/block.c +++ b/block.c @@ -1241,6 +1241,7 @@ void bdrv_init(void) bdrv_register(&bdrv_vpc); bdrv_register(&bdrv_vvfat); bdrv_register(&bdrv_qcow2); + bdrv_register(&bdrv_parallels); } void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb, diff --git a/vl.h b/vl.h index 242b4bc3d..997b63d17 100644 --- a/vl.h +++ b/vl.h @@ -570,6 +570,7 @@ extern BlockDriver bdrv_bochs; extern BlockDriver bdrv_vpc; extern BlockDriver bdrv_vvfat; extern BlockDriver bdrv_qcow2; +extern BlockDriver bdrv_parallels; typedef struct BlockDriverInfo { /* in bytes, 0 if irrelevant */ -- cgit v1.2.3 From 24bc1cbc7b1c774ba09b3517fba4a37293498a00 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 31 Jul 2007 23:32:11 +0000 Subject: Implement ACPI specs 3.0, 4.7.2.5, by Michael Hanselmann. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3103 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/acpi.c b/hw/acpi.c index ce3f7f2df..871a737f3 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -54,6 +54,9 @@ typedef struct PIIX4PMState { #define SUS_EN (1 << 13) +#define ACPI_ENABLE 0xf1 +#define ACPI_DISABLE 0xf0 + #define SMBHSTSTS 0x00 #define SMBHSTCNT 0x02 #define SMBHSTCMD 0x03 @@ -216,6 +219,14 @@ static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val) #endif if (addr == 0) { s->apmc = val; + + /* ACPI specs 3.0, 4.7.2.5 */ + if (val == ACPI_ENABLE) { + s->pmcntrl |= SCI_EN; + } else if (val == ACPI_DISABLE) { + s->pmcntrl &= ~SCI_EN; + } + if (s->dev.config[0x5b] & (1 << 1)) { cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); } -- cgit v1.2.3 From 8f860bb83cb872461ebac017232604b1dc2d2604 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 31 Jul 2007 23:44:21 +0000 Subject: s390 disassembler support, by Ulrich Hecht. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3104 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 + dis-asm.h | 3 + disas.c | 2 + s390-dis.c | 1711 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1719 insertions(+) create mode 100644 s390-dis.c diff --git a/Makefile.target b/Makefile.target index 6ffa6651e..915b8a97b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -347,6 +347,9 @@ endif ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4) LIBOBJS+=sh4-dis.o endif +ifeq ($(findstring s390, $(TARGET_ARCH) $(ARCH)),s390) +LIBOBJS+=s390-dis.o +endif ifdef CONFIG_GDBSTUB OBJS+=gdbstub.o diff --git a/dis-asm.h b/dis-asm.h index ad08cc5d6..8fb5f6dbb 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -202,6 +202,8 @@ enum bfd_architecture bfd_arch_mn10300, /* Matsushita MN10300 */ bfd_arch_last }; +#define bfd_mach_s390_31 31 +#define bfd_mach_s390_64 64 typedef struct symbol_cache_entry { @@ -379,6 +381,7 @@ 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*)); extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_s390 PARAMS ((bfd_vma, disassemble_info*)); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/disas.c b/disas.c index 071642639..1bf5bc8f3 100644 --- a/disas.c +++ b/disas.c @@ -269,6 +269,8 @@ void disas(FILE *out, void *code, unsigned long size) print_insn = print_insn_little_mips; #elif defined(__m68k__) print_insn = print_insn_m68k; +#elif defined(__s390__) + print_insn = print_insn_s390; #else fprintf(out, "0x%lx: Asm output not supported on this arch\n", (long) code); diff --git a/s390-dis.c b/s390-dis.c new file mode 100644 index 000000000..af7d9964e --- /dev/null +++ b/s390-dis.c @@ -0,0 +1,1711 @@ +/* s390-dis.c -- Disassemble S390 instructions + Copyright 2000, 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of the GNU opcodes library. + + This library 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 3, or (at your option) + any later version. + + It 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 file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include +#include "dis-asm.h" + +/* s390.h -- Header file for S390 opcode table + Copyright 2000, 2001, 2003 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of BFD, the Binary File Descriptor library. + + 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., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef S390_H +#define S390_H + +/* List of instruction sets variations. */ + +enum s390_opcode_mode_val + { + S390_OPCODE_ESA = 0, + S390_OPCODE_ZARCH + }; + +enum s390_opcode_cpu_val + { + S390_OPCODE_G5 = 0, + S390_OPCODE_G6, + S390_OPCODE_Z900, + S390_OPCODE_Z990, + S390_OPCODE_Z9_109, + S390_OPCODE_Z9_EC + }; + +/* The opcode table is an array of struct s390_opcode. */ + +struct s390_opcode + { + /* The opcode name. */ + const char * name; + + /* The opcode itself. Those bits which will be filled in with + operands are zeroes. */ + unsigned char opcode[6]; + + /* 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 char mask[6]; + + /* The opcode length in bytes. */ + int oplen; + + /* 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[6]; + + /* Bitmask of execution modes this opcode is available for. */ + unsigned int modes; + + /* First cpu this opcode is available for. */ + enum s390_opcode_cpu_val min_cpu; + }; + +/* 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 s390_opcode s390_opcodes[]; +extern const int s390_num_opcodes; + +/* A opcode format table for the .insn pseudo mnemonic. */ +extern const struct s390_opcode s390_opformats[]; +extern const int s390_num_opformats; + +/* Values defined for the flags field of a struct powerpc_opcode. */ + +/* The operands table is an array of struct s390_operand. */ + +struct s390_operand + { + /* The number of bits in the operand. */ + int bits; + + /* How far the operand is left shifted in the instruction. */ + int shift; + + /* One bit syntax flags. */ + unsigned long flags; + }; + +/* Elements in the table are retrieved by indexing with values from + the operands field of the powerpc_opcodes table. */ + +extern const struct s390_operand s390_operands[]; + +/* Values defined for the flags field of a struct s390_operand. */ + +/* This operand names a register. The disassembler uses this to print + register names with a leading 'r'. */ +#define S390_OPERAND_GPR 0x1 + +/* This operand names a floating point register. The disassembler + prints these with a leading 'f'. */ +#define S390_OPERAND_FPR 0x2 + +/* This operand names an access register. The disassembler + prints these with a leading 'a'. */ +#define S390_OPERAND_AR 0x4 + +/* This operand names a control register. The disassembler + prints these with a leading 'c'. */ +#define S390_OPERAND_CR 0x8 + +/* This operand is a displacement. */ +#define S390_OPERAND_DISP 0x10 + +/* This operand names a base register. */ +#define S390_OPERAND_BASE 0x20 + +/* This operand names an index register, it can be skipped. */ +#define S390_OPERAND_INDEX 0x40 + +/* This operand is a relative branch displacement. The disassembler + prints these symbolically if possible. */ +#define S390_OPERAND_PCREL 0x80 + +/* This operand takes signed values. */ +#define S390_OPERAND_SIGNED 0x100 + +/* This operand is a length. */ +#define S390_OPERAND_LENGTH 0x200 + +/* This operand is optional. Only a single operand at the end of + the instruction may be optional. */ +#define S390_OPERAND_OPTIONAL 0x400 + + #endif /* S390_H */ + + +static int init_flag = 0; +static int opc_index[256]; +static int current_arch_mask = 0; + +/* Set up index table for first opcode byte. */ + +static void +init_disasm (struct disassemble_info *info) +{ + const struct s390_opcode *opcode; + const struct s390_opcode *opcode_end; + + memset (opc_index, 0, sizeof (opc_index)); + opcode_end = s390_opcodes + s390_num_opcodes; + for (opcode = s390_opcodes; opcode < opcode_end; opcode++) + { + opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes; + while ((opcode < opcode_end) && + (opcode[1].opcode[0] == opcode->opcode[0])) + opcode++; + } +// switch (info->mach) +// { +// case bfd_mach_s390_31: + current_arch_mask = 1 << S390_OPCODE_ESA; +// break; +// case bfd_mach_s390_64: +// current_arch_mask = 1 << S390_OPCODE_ZARCH; +// break; +// default: +// abort (); +// } + init_flag = 1; +} + +/* Extracts an operand value from an instruction. */ + +static inline unsigned int +s390_extract_operand (unsigned char *insn, const struct s390_operand *operand) +{ + unsigned int val; + int bits; + + /* Extract fragments of the operand byte for byte. */ + insn += operand->shift / 8; + bits = (operand->shift & 7) + operand->bits; + val = 0; + do + { + val <<= 8; + val |= (unsigned int) *insn++; + bits -= 8; + } + while (bits > 0); + val >>= -bits; + val &= ((1U << (operand->bits - 1)) << 1) - 1; + + /* Check for special long displacement case. */ + if (operand->bits == 20 && operand->shift == 20) + val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; + + /* Sign extend value if the operand is signed or pc relative. */ + if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL)) + && (val & (1U << (operand->bits - 1)))) + val |= (-1U << (operand->bits - 1)) << 1; + + /* Double value if the operand is pc relative. */ + if (operand->flags & S390_OPERAND_PCREL) + val <<= 1; + + /* Length x in an instructions has real length x + 1. */ + if (operand->flags & S390_OPERAND_LENGTH) + val++; + return val; +} + +/* Print a S390 instruction. */ + +int +print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) +{ + bfd_byte buffer[6]; + const struct s390_opcode *opcode; + const struct s390_opcode *opcode_end; + unsigned int value; + int status, opsize, bufsize; + char separator; + + if (init_flag == 0) + init_disasm (info); + + /* The output looks better if we put 6 bytes on a line. */ + info->bytes_per_line = 6; + + /* Every S390 instruction is max 6 bytes long. */ + memset (buffer, 0, 6); + status = (*info->read_memory_func) (memaddr, buffer, 6, info); + if (status != 0) + { + for (bufsize = 0; bufsize < 6; bufsize++) + if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0) + break; + if (bufsize <= 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + /* Opsize calculation looks strange but it works + 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes, + 11xxxxxx -> 6 bytes. */ + opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; + status = opsize > bufsize; + } + else + { + bufsize = 6; + opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; + } + + if (status == 0) + { + /* Find the first match in the opcode table. */ + opcode_end = s390_opcodes + s390_num_opcodes; + for (opcode = s390_opcodes + opc_index[(int) buffer[0]]; + (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]); + opcode++) + { + const struct s390_operand *operand; + const unsigned char *opindex; + + /* Check architecture. */ + if (!(opcode->modes & current_arch_mask)) + continue; + /* Check signature of the opcode. */ + if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1] + || (buffer[2] & opcode->mask[2]) != opcode->opcode[2] + || (buffer[3] & opcode->mask[3]) != opcode->opcode[3] + || (buffer[4] & opcode->mask[4]) != opcode->opcode[4] + || (buffer[5] & opcode->mask[5]) != opcode->opcode[5]) + continue; + + /* The instruction is valid. */ + if (opcode->operands[0] != 0) + (*info->fprintf_func) (info->stream, "%s\t", opcode->name); + else + (*info->fprintf_func) (info->stream, "%s", opcode->name); + + /* Extract the operands. */ + separator = 0; + for (opindex = opcode->operands; *opindex != 0; opindex++) + { + unsigned int value; + + operand = s390_operands + *opindex; + value = s390_extract_operand (buffer, operand); + + if ((operand->flags & S390_OPERAND_INDEX) && value == 0) + continue; + if ((operand->flags & S390_OPERAND_BASE) && + value == 0 && separator == '(') + { + separator = ','; + continue; + } + + if (separator) + (*info->fprintf_func) (info->stream, "%c", separator); + + if (operand->flags & S390_OPERAND_GPR) + (*info->fprintf_func) (info->stream, "%%r%i", value); + else if (operand->flags & S390_OPERAND_FPR) + (*info->fprintf_func) (info->stream, "%%f%i", value); + else if (operand->flags & S390_OPERAND_AR) + (*info->fprintf_func) (info->stream, "%%a%i", value); + else if (operand->flags & S390_OPERAND_CR) + (*info->fprintf_func) (info->stream, "%%c%i", value); + else if (operand->flags & S390_OPERAND_PCREL) + (*info->print_address_func) (memaddr + (int) value, info); + else if (operand->flags & S390_OPERAND_SIGNED) + (*info->fprintf_func) (info->stream, "%i", (int) value); + else + (*info->fprintf_func) (info->stream, "%u", value); + + if (operand->flags & S390_OPERAND_DISP) + { + separator = '('; + } + else if (operand->flags & S390_OPERAND_BASE) + { + (*info->fprintf_func) (info->stream, ")"); + separator = ','; + } + else + separator = ','; + } + + /* Found instruction, printed it, return its size. */ + return opsize; + } + /* No matching instruction found, fall through to hex print. */ + } + + if (bufsize >= 4) + { + value = (unsigned int) buffer[0]; + value = (value << 8) + (unsigned int) buffer[1]; + value = (value << 8) + (unsigned int) buffer[2]; + value = (value << 8) + (unsigned int) buffer[3]; + (*info->fprintf_func) (info->stream, ".long\t0x%08x", value); + return 4; + } + else if (bufsize >= 2) + { + value = (unsigned int) buffer[0]; + value = (value << 8) + (unsigned int) buffer[1]; + (*info->fprintf_func) (info->stream, ".short\t0x%04x", value); + return 2; + } + else + { + value = (unsigned int) buffer[0]; + (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value); + return 1; + } +} +/* s390-opc.c -- S390 opcode list + Copyright 2000, 2001, 2003, 2007 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + This file is part of the GNU opcodes library. + + This library 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 3, or (at your option) + any later version. + + It 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 file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include + +/* This file holds the S390 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 section. + + This file also holds the operand table. All knowledge about + inserting operands into instructions and vice-versa is kept in this + file. */ + +/* The operands table. + The fields are bits, shift, insert, extract, flags. */ + +const struct s390_operand s390_operands[] = +{ +#define UNUSED 0 + { 0, 0, 0 }, /* Indicates the end of the operand list */ + +#define R_8 1 /* GPR starting at position 8 */ + { 4, 8, S390_OPERAND_GPR }, +#define R_12 2 /* GPR starting at position 12 */ + { 4, 12, S390_OPERAND_GPR }, +#define R_16 3 /* GPR starting at position 16 */ + { 4, 16, S390_OPERAND_GPR }, +#define R_20 4 /* GPR starting at position 20 */ + { 4, 20, S390_OPERAND_GPR }, +#define R_24 5 /* GPR starting at position 24 */ + { 4, 24, S390_OPERAND_GPR }, +#define R_28 6 /* GPR starting at position 28 */ + { 4, 28, S390_OPERAND_GPR }, +#define R_32 7 /* GPR starting at position 32 */ + { 4, 32, S390_OPERAND_GPR }, + +#define F_8 8 /* FPR starting at position 8 */ + { 4, 8, S390_OPERAND_FPR }, +#define F_12 9 /* FPR starting at position 12 */ + { 4, 12, S390_OPERAND_FPR }, +#define F_16 10 /* FPR starting at position 16 */ + { 4, 16, S390_OPERAND_FPR }, +#define F_20 11 /* FPR starting at position 16 */ + { 4, 16, S390_OPERAND_FPR }, +#define F_24 12 /* FPR starting at position 24 */ + { 4, 24, S390_OPERAND_FPR }, +#define F_28 13 /* FPR starting at position 28 */ + { 4, 28, S390_OPERAND_FPR }, +#define F_32 14 /* FPR starting at position 32 */ + { 4, 32, S390_OPERAND_FPR }, + +#define A_8 15 /* Access reg. starting at position 8 */ + { 4, 8, S390_OPERAND_AR }, +#define A_12 16 /* Access reg. starting at position 12 */ + { 4, 12, S390_OPERAND_AR }, +#define A_24 17 /* Access reg. starting at position 24 */ + { 4, 24, S390_OPERAND_AR }, +#define A_28 18 /* Access reg. starting at position 28 */ + { 4, 28, S390_OPERAND_AR }, + +#define C_8 19 /* Control reg. starting at position 8 */ + { 4, 8, S390_OPERAND_CR }, +#define C_12 20 /* Control reg. starting at position 12 */ + { 4, 12, S390_OPERAND_CR }, + +#define B_16 21 /* Base register starting at position 16 */ + { 4, 16, S390_OPERAND_BASE|S390_OPERAND_GPR }, +#define B_32 22 /* Base register starting at position 32 */ + { 4, 32, S390_OPERAND_BASE|S390_OPERAND_GPR }, + +#define X_12 23 /* Index register starting at position 12 */ + { 4, 12, S390_OPERAND_INDEX|S390_OPERAND_GPR }, + +#define D_20 24 /* Displacement starting at position 20 */ + { 12, 20, S390_OPERAND_DISP }, +#define D_36 25 /* Displacement starting at position 36 */ + { 12, 36, S390_OPERAND_DISP }, +#define D20_20 26 /* 20 bit displacement starting at 20 */ + { 20, 20, S390_OPERAND_DISP|S390_OPERAND_SIGNED }, + +#define L4_8 27 /* 4 bit length starting at position 8 */ + { 4, 8, S390_OPERAND_LENGTH }, +#define L4_12 28 /* 4 bit length starting at position 12 */ + { 4, 12, S390_OPERAND_LENGTH }, +#define L8_8 29 /* 8 bit length starting at position 8 */ + { 8, 8, S390_OPERAND_LENGTH }, + +#define U4_8 30 /* 4 bit unsigned value starting at 8 */ + { 4, 8, 0 }, +#define U4_12 31 /* 4 bit unsigned value starting at 12 */ + { 4, 12, 0 }, +#define U4_16 32 /* 4 bit unsigned value starting at 16 */ + { 4, 16, 0 }, +#define U4_20 33 /* 4 bit unsigned value starting at 20 */ + { 4, 20, 0 }, +#define U8_8 34 /* 8 bit unsigned value starting at 8 */ + { 8, 8, 0 }, +#define U8_16 35 /* 8 bit unsigned value starting at 16 */ + { 8, 16, 0 }, +#define I16_16 36 /* 16 bit signed value starting at 16 */ + { 16, 16, S390_OPERAND_SIGNED }, +#define U16_16 37 /* 16 bit unsigned value starting at 16 */ + { 16, 16, 0 }, +#define J16_16 38 /* PC relative jump offset at 16 */ + { 16, 16, S390_OPERAND_PCREL }, +#define J32_16 39 /* PC relative long offset at 16 */ + { 32, 16, S390_OPERAND_PCREL }, +#define I32_16 40 /* 32 bit signed value starting at 16 */ + { 32, 16, S390_OPERAND_SIGNED }, +#define U32_16 41 /* 32 bit unsigned value starting at 16 */ + { 32, 16, 0 }, +#define M_16 42 /* 4 bit optional mask starting at 16 */ + { 4, 16, S390_OPERAND_OPTIONAL }, +#define RO_28 43 /* optional GPR starting at position 28 */ + { 4, 28, (S390_OPERAND_GPR | S390_OPERAND_OPTIONAL) } + +}; + + +/* Macros used to form opcodes. */ + +/* 8/16/48 bit opcodes. */ +#define OP8(x) { x, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define OP16(x) { x >> 8, x & 255, 0x00, 0x00, 0x00, 0x00 } +#define OP48(x) { x >> 40, (x >> 32) & 255, (x >> 24) & 255, \ + (x >> 16) & 255, (x >> 8) & 255, x & 255} + +/* The new format of the INSTR_x_y and MASK_x_y defines is based + on the following rules: + 1) the middle part of the definition (x in INSTR_x_y) is the official + names of the instruction format that you can find in the principals + of operation. + 2) the last part of the definition (y in INSTR_x_y) gives you an idea + which operands the binary represenation of the instruction has. + The meanings of the letters in y are: + a - access register + c - control register + d - displacement, 12 bit + f - floating pointer register + i - signed integer, 4, 8, 16 or 32 bit + l - length, 4 or 8 bit + p - pc relative + r - general purpose register + u - unsigned integer, 4, 8, 16 or 32 bit + m - mode field, 4 bit + 0 - operand skipped. + The order of the letters reflects the layout of the format in + storage and not the order of the paramaters of the instructions. + The use of the letters is not a 100% match with the PoP but it is + quite close. + + For example the instruction "mvo" is defined in the PoP as follows: + + MVO D1(L1,B1),D2(L2,B2) [SS] + + -------------------------------------- + | 'F1' | L1 | L2 | B1 | D1 | B2 | D2 | + -------------------------------------- + 0 8 12 16 20 32 36 + + The instruction format is: INSTR_SS_LLRDRD / MASK_SS_LLRDRD. */ + +#define INSTR_E 2, { 0,0,0,0,0,0 } /* e.g. pr */ +#define INSTR_RIE_RRP 6, { R_8,R_12,J16_16,0,0,0 } /* e.g. brxhg */ +#define INSTR_RIL_0P 6, { J32_16,0,0,0,0 } /* e.g. jg */ +#define INSTR_RIL_RP 6, { R_8,J32_16,0,0,0,0 } /* e.g. brasl */ +#define INSTR_RIL_UP 6, { U4_8,J32_16,0,0,0,0 } /* e.g. brcl */ +#define INSTR_RIL_RI 6, { R_8,I32_16,0,0,0,0 } /* e.g. afi */ +#define INSTR_RIL_RU 6, { R_8,U32_16,0,0,0,0 } /* e.g. alfi */ +#define INSTR_RI_0P 4, { J16_16,0,0,0,0,0 } /* e.g. j */ +#define INSTR_RI_RI 4, { R_8,I16_16,0,0,0,0 } /* e.g. ahi */ +#define INSTR_RI_RP 4, { R_8,J16_16,0,0,0,0 } /* e.g. brct */ +#define INSTR_RI_RU 4, { R_8,U16_16,0,0,0,0 } /* e.g. tml */ +#define INSTR_RI_UP 4, { U4_8,J16_16,0,0,0,0 } /* e.g. brc */ +#define INSTR_RRE_00 4, { 0,0,0,0,0,0 } /* e.g. palb */ +#define INSTR_RRE_0R 4, { R_28,0,0,0,0,0 } /* e.g. tb */ +#define INSTR_RRE_AA 4, { A_24,A_28,0,0,0,0 } /* e.g. cpya */ +#define INSTR_RRE_AR 4, { A_24,R_28,0,0,0,0 } /* e.g. sar */ +#define INSTR_RRE_F0 4, { F_24,0,0,0,0,0 } /* e.g. sqer */ +#define INSTR_RRE_FF 4, { F_24,F_28,0,0,0,0 } /* e.g. debr */ +#define INSTR_RRE_R0 4, { R_24,0,0,0,0,0 } /* e.g. ipm */ +#define INSTR_RRE_RA 4, { R_24,A_28,0,0,0,0 } /* e.g. ear */ +#define INSTR_RRE_RF 4, { R_24,F_28,0,0,0,0 } /* e.g. cefbr */ +#define INSTR_RRE_RR 4, { R_24,R_28,0,0,0,0 } /* e.g. lura */ +#define INSTR_RRE_FR 4, { F_24,R_28,0,0,0,0 } /* e.g. ldgr */ +/* Actually efpc and sfpc do not take an optional operand. + This is just a workaround for existing code e.g. glibc. */ +#define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 } /* efpc, sfpc */ +#define INSTR_RRF_F0FF 4, { F_16,F_24,F_28,0,0,0 } /* e.g. madbr */ +#define INSTR_RRF_F0FF2 4, { F_24,F_16,F_28,0,0,0 } /* e.g. cpsdr */ +#define INSTR_RRF_F0FR 4, { F_24,F_16,R_28,0,0,0 } /* e.g. iedtr */ +#define INSTR_RRF_FUFF 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. didbr */ +#define INSTR_RRF_RURR 4, { R_24,R_28,R_16,U4_20,0,0 } /* e.g. .insn */ +#define INSTR_RRF_R0RR 4, { R_24,R_28,R_16,0,0,0 } /* e.g. idte */ +#define INSTR_RRF_U0FF 4, { F_24,U4_16,F_28,0,0,0 } /* e.g. fixr */ +#define INSTR_RRF_U0RF 4, { R_24,U4_16,F_28,0,0,0 } /* e.g. cfebr */ +#define INSTR_RRF_UUFF 4, { F_24,U4_16,F_28,U4_20,0,0 } /* e.g. fidtr */ +#define INSTR_RRF_0UFF 4, { F_24,F_28,U4_20,0,0,0 } /* e.g. ldetr */ +#define INSTR_RRF_FFFU 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. qadtr */ +#define INSTR_RRF_M0RR 4, { R_24,R_28,M_16,0,0,0 } /* e.g. sske */ +#define INSTR_RR_0R 2, { R_12, 0,0,0,0,0 } /* e.g. br */ +#define INSTR_RR_FF 2, { F_8,F_12,0,0,0,0 } /* e.g. adr */ +#define INSTR_RR_R0 2, { R_8, 0,0,0,0,0 } /* e.g. spm */ +#define INSTR_RR_RR 2, { R_8,R_12,0,0,0,0 } /* e.g. lr */ +#define INSTR_RR_U0 2, { U8_8, 0,0,0,0,0 } /* e.g. svc */ +#define INSTR_RR_UR 2, { U4_8,R_12,0,0,0,0 } /* e.g. bcr */ +#define INSTR_RRR_F0FF 4, { F_24,F_28,F_16,0,0,0 } /* e.g. ddtr */ +#define INSTR_RSE_RRRD 6, { R_8,R_12,D_20,B_16,0,0 } /* e.g. lmh */ +#define INSTR_RSE_CCRD 6, { C_8,C_12,D_20,B_16,0,0 } /* e.g. lmh */ +#define INSTR_RSE_RURD 6, { R_8,U4_12,D_20,B_16,0,0 } /* e.g. icmh */ +#define INSTR_RSL_R0RD 6, { R_8,D_20,B_16,0,0,0 } /* e.g. tp */ +#define INSTR_RSI_RRP 4, { R_8,R_12,J16_16,0,0,0 } /* e.g. brxh */ +#define INSTR_RSY_RRRD 6, { R_8,R_12,D20_20,B_16,0,0 } /* e.g. stmy */ +#define INSTR_RSY_RURD 6, { R_8,U4_12,D20_20,B_16,0,0 } /* e.g. icmh */ +#define INSTR_RSY_AARD 6, { A_8,A_12,D20_20,B_16,0,0 } /* e.g. lamy */ +#define INSTR_RSY_CCRD 6, { C_8,C_12,D20_20,B_16,0,0 } /* e.g. lamy */ +#define INSTR_RS_AARD 4, { A_8,A_12,D_20,B_16,0,0 } /* e.g. lam */ +#define INSTR_RS_CCRD 4, { C_8,C_12,D_20,B_16,0,0 } /* e.g. lctl */ +#define INSTR_RS_R0RD 4, { R_8,D_20,B_16,0,0,0 } /* e.g. sll */ +#define INSTR_RS_RRRD 4, { R_8,R_12,D_20,B_16,0,0 } /* e.g. cs */ +#define INSTR_RS_RURD 4, { R_8,U4_12,D_20,B_16,0,0 } /* e.g. icm */ +#define INSTR_RXE_FRRD 6, { F_8,D_20,X_12,B_16,0,0 } /* e.g. axbr */ +#define INSTR_RXE_RRRD 6, { R_8,D_20,X_12,B_16,0,0 } /* e.g. lg */ +#define INSTR_RXF_FRRDF 6, { F_32,F_8,D_20,X_12,B_16,0 } /* e.g. madb */ +#define INSTR_RXF_RRRDR 6, { R_32,R_8,D_20,X_12,B_16,0 } /* e.g. .insn */ +#define INSTR_RXY_RRRD 6, { R_8,D20_20,X_12,B_16,0,0 } /* e.g. ly */ +#define INSTR_RXY_FRRD 6, { F_8,D20_20,X_12,B_16,0,0 } /* e.g. ley */ +#define INSTR_RX_0RRD 4, { D_20,X_12,B_16,0,0,0 } /* e.g. be */ +#define INSTR_RX_FRRD 4, { F_8,D_20,X_12,B_16,0,0 } /* e.g. ae */ +#define INSTR_RX_RRRD 4, { R_8,D_20,X_12,B_16,0,0 } /* e.g. l */ +#define INSTR_RX_URRD 4, { U4_8,D_20,X_12,B_16,0,0 } /* e.g. bc */ +#define INSTR_SI_URD 4, { D_20,B_16,U8_8,0,0,0 } /* e.g. cli */ +#define INSTR_SIY_URD 6, { D20_20,B_16,U8_8,0,0,0 } /* e.g. tmy */ +#define INSTR_SSE_RDRD 6, { D_20,B_16,D_36,B_32,0,0 } /* e.g. mvsdk */ +#define INSTR_SS_L0RDRD 6, { D_20,L8_8,B_16,D_36,B_32,0 } /* e.g. mvc */ +#define INSTR_SS_L2RDRD 6, { D_20,B_16,D_36,L8_8,B_32,0 } /* e.g. pka */ +#define INSTR_SS_LIRDRD 6, { D_20,L4_8,B_16,D_36,B_32,U4_12 } /* e.g. srp */ +#define INSTR_SS_LLRDRD 6, { D_20,L4_8,B_16,D_36,L4_12,B_32 } /* e.g. pack */ +#define INSTR_SS_RRRDRD 6, { D_20,R_8,B_16,D_36,B_32,R_12 } /* e.g. mvck */ +#define INSTR_SS_RRRDRD2 6, { R_8,D_20,B_16,R_12,D_36,B_32 } /* e.g. plo */ +#define INSTR_SS_RRRDRD3 6, { R_8,R_12,D_20,B_16,D_36,B_32 } /* e.g. lmd */ +#define INSTR_S_00 4, { 0,0,0,0,0,0 } /* e.g. hsch */ +#define INSTR_S_RD 4, { D_20,B_16,0,0,0,0 } /* e.g. lpsw */ +#define INSTR_SSF_RRDRD 6, { D_20,B_16,D_36,B_32,R_8,0 } /* e.g. mvcos */ + +#define MASK_E { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIE_RRP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RIL_0P { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_UP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RI { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RIL_RU { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_0P { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RI { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_RU { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RI_UP { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRE_00 { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } +#define MASK_RRE_0R { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 } +#define MASK_RRE_AA { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_AR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_F0 { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 } +#define MASK_RRE_FF { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_R0 { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 } +#define MASK_RRE_RA { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RF { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_FR { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRE_RR_OPT { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FF2 { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_F0FR { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_FUFF { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_RURR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_R0RR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_U0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_U0RF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RRF_UUFF { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_0UFF { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 } +#define MASK_RRF_FFFU { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRF_M0RR { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RR_0R { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_FF { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_R0 { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_RR { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_U0 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RR_UR { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RRR_F0FF { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 } +#define MASK_RSE_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSE_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSE_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSL_R0RD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSI_RRP { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_AARD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_R0RD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RS_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RSY_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_RURD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_AARD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RSY_CCRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXE_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXE_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXF_FRRDF { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXF_RRRDR { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXY_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RXY_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_RX_0RRD { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_FRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_RRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_RX_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SI_URD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SIY_URD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define MASK_SSE_RDRD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_L0RDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_L2RDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_LIRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_LLRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD2 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SS_RRRDRD3 { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define MASK_S_00 { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 } +#define MASK_S_RD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } +#define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } + +/* The opcode formats table (blueprints for .insn pseudo mnemonic). */ + +const struct s390_opcode s390_opformats[] = + { + { "e", OP8(0x00LL), MASK_E, INSTR_E, 3, 0 }, + { "ri", OP8(0x00LL), MASK_RI_RI, INSTR_RI_RI, 3, 0 }, + { "rie", OP8(0x00LL), MASK_RIE_RRP, INSTR_RIE_RRP, 3, 0 }, + { "ril", OP8(0x00LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 0 }, + { "rilu", OP8(0x00LL), MASK_RIL_RU, INSTR_RIL_RU, 3, 0 }, + { "rr", OP8(0x00LL), MASK_RR_RR, INSTR_RR_RR, 3, 0 }, + { "rre", OP8(0x00LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0 }, + { "rrf", OP8(0x00LL), MASK_RRF_RURR, INSTR_RRF_RURR, 3, 0 }, + { "rs", OP8(0x00LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0 }, + { "rse", OP8(0x00LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0 }, + { "rsi", OP8(0x00LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0 }, + { "rsy", OP8(0x00LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3 }, + { "rx", OP8(0x00LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0 }, + { "rxe", OP8(0x00LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 0 }, + { "rxf", OP8(0x00LL), MASK_RXF_RRRDR, INSTR_RXF_RRRDR,3, 0 }, + { "rxy", OP8(0x00LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3 }, + { "s", OP8(0x00LL), MASK_S_RD, INSTR_S_RD, 3, 0 }, + { "si", OP8(0x00LL), MASK_SI_URD, INSTR_SI_URD, 3, 0 }, + { "siy", OP8(0x00LL), MASK_SIY_URD, INSTR_SIY_URD, 3, 3 }, + { "ss", OP8(0x00LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD,3, 0 }, + { "sse", OP8(0x00LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0 }, + { "ssf", OP8(0x00LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD,3, 0 }, +}; + +const int s390_num_opformats = + sizeof (s390_opformats) / sizeof (s390_opformats[0]); + +/* The opcode table. This file was generated by s390-mkopc. + + 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 disassembler reads the table in order and prints the first + instruction which matches. */ + +const struct s390_opcode s390_opcodes[] = + { + { "dp", OP8(0xfdLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "mp", OP8(0xfcLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "sp", OP8(0xfbLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "ap", OP8(0xfaLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "cp", OP8(0xf9LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "zap", OP8(0xf8LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "unpk", OP8(0xf3LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "pack", OP8(0xf2LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "mvo", OP8(0xf1LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0}, + { "srp", OP8(0xf0LL), MASK_SS_LIRDRD, INSTR_SS_LIRDRD, 3, 0}, + { "lmd", OP8(0xefLL), MASK_SS_RRRDRD3, INSTR_SS_RRRDRD3, 2, 2}, + { "plo", OP8(0xeeLL), MASK_SS_RRRDRD2, INSTR_SS_RRRDRD2, 3, 0}, + { "stdy", OP48(0xed0000000067LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "stey", OP48(0xed0000000066LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "ldy", OP48(0xed0000000065LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "ley", OP48(0xed0000000064LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3}, + { "tgxt", OP48(0xed0000000059LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcxt", OP48(0xed0000000058LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tgdt", OP48(0xed0000000055LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcdt", OP48(0xed0000000054LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tget", OP48(0xed0000000051LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "tcet", OP48(0xed0000000050LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5}, + { "srxt", OP48(0xed0000000049LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "slxt", OP48(0xed0000000048LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "srdt", OP48(0xed0000000041LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "sldt", OP48(0xed0000000040LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5}, + { "msd", OP48(0xed000000003fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "mad", OP48(0xed000000003eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "myh", OP48(0xed000000003dLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mayh", OP48(0xed000000003cLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "my", OP48(0xed000000003bLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "may", OP48(0xed000000003aLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "myl", OP48(0xed0000000039LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mayl", OP48(0xed0000000038LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4}, + { "mee", OP48(0xed0000000037LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqe", OP48(0xed0000000034LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mse", OP48(0xed000000002fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "mae", OP48(0xed000000002eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3}, + { "lxe", OP48(0xed0000000026LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxd", OP48(0xed0000000025LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lde", OP48(0xed0000000024LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "msdb", OP48(0xed000000001fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "madb", OP48(0xed000000001eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "ddb", OP48(0xed000000001dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mdb", OP48(0xed000000001cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sdb", OP48(0xed000000001bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "adb", OP48(0xed000000001aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "cdb", OP48(0xed0000000019LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "kdb", OP48(0xed0000000018LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "meeb", OP48(0xed0000000017LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqdb", OP48(0xed0000000015LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "sqeb", OP48(0xed0000000014LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tcxb", OP48(0xed0000000012LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tcdb", OP48(0xed0000000011LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "tceb", OP48(0xed0000000010LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mseb", OP48(0xed000000000fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "maeb", OP48(0xed000000000eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0}, + { "deb", OP48(0xed000000000dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mdeb", OP48(0xed000000000cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "seb", OP48(0xed000000000bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "aeb", OP48(0xed000000000aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "ceb", OP48(0xed0000000009LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "keb", OP48(0xed0000000008LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "mxdb", OP48(0xed0000000007LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxeb", OP48(0xed0000000006LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "lxdb", OP48(0xed0000000005LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, + { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, + { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, + { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0}, + { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, + { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, + { "lmy", OP48(0xeb0000000098LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmh", OP48(0xeb0000000096LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmh", OP48(0xeb0000000096LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "stmy", OP48(0xeb0000000090LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "clclu", OP48(0xeb000000008fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "mvclu", OP48(0xeb000000008eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3}, + { "mvclu", OP48(0xeb000000008eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0}, + { "icmy", OP48(0xeb0000000081LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "icmh", OP48(0xeb0000000080LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "icmh", OP48(0xeb0000000080LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "xiy", OP48(0xeb0000000057LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "oiy", OP48(0xeb0000000056LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "cliy", OP48(0xeb0000000055LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "niy", OP48(0xeb0000000054LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "mviy", OP48(0xeb0000000052LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "tmy", OP48(0xeb0000000051LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3}, + { "bxleg", OP48(0xeb0000000045LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "bxleg", OP48(0xeb0000000045LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "bxhg", OP48(0xeb0000000044LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "bxhg", OP48(0xeb0000000044LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "cdsg", OP48(0xeb000000003eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "cdsg", OP48(0xeb000000003eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "cdsy", OP48(0xeb0000000031LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "csg", OP48(0xeb0000000030LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "csg", OP48(0xeb0000000030LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "lctlg", OP48(0xeb000000002fLL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3}, + { "lctlg", OP48(0xeb000000002fLL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2}, + { "stcmy", OP48(0xeb000000002dLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "stcmh", OP48(0xeb000000002cLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "stcmh", OP48(0xeb000000002cLL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "stmh", OP48(0xeb0000000026LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "stmh", OP48(0xeb0000000026LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "stctg", OP48(0xeb0000000025LL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3}, + { "stctg", OP48(0xeb0000000025LL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2}, + { "stmg", OP48(0xeb0000000024LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "stmg", OP48(0xeb0000000024LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "clmy", OP48(0xeb0000000021LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "clmh", OP48(0xeb0000000020LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3}, + { "clmh", OP48(0xeb0000000020LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2}, + { "rll", OP48(0xeb000000001dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3}, + { "rll", OP48(0xeb000000001dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 2}, + { "rllg", OP48(0xeb000000001cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "rllg", OP48(0xeb000000001cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "csy", OP48(0xeb0000000014LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "tracg", OP48(0xeb000000000fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "tracg", OP48(0xeb000000000fLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "sllg", OP48(0xeb000000000dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "sllg", OP48(0xeb000000000dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "srlg", OP48(0xeb000000000cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "srlg", OP48(0xeb000000000cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "slag", OP48(0xeb000000000bLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "slag", OP48(0xeb000000000bLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "srag", OP48(0xeb000000000aLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, + { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, + { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0}, + { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvcdk", OP16(0xe50fLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "mvcsk", OP16(0xe50eLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2}, + { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, + { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "alc", OP48(0xe30000000098LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "dl", OP48(0xe30000000097LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "dl", OP48(0xe30000000097LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "ml", OP48(0xe30000000096LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "ml", OP48(0xe30000000096LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "llh", OP48(0xe30000000095LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "llc", OP48(0xe30000000094LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "llgh", OP48(0xe30000000091LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgh", OP48(0xe30000000091LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgc", OP48(0xe30000000090LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgc", OP48(0xe30000000090LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lpq", OP48(0xe3000000008fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lpq", OP48(0xe3000000008fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "stpq", OP48(0xe3000000008eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stpq", OP48(0xe3000000008eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slbg", OP48(0xe30000000089LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slbg", OP48(0xe30000000089LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "alcg", OP48(0xe30000000088LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "alcg", OP48(0xe30000000088LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "dlg", OP48(0xe30000000087LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dlg", OP48(0xe30000000087LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "mlg", OP48(0xe30000000086LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "mlg", OP48(0xe30000000086LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "xg", OP48(0xe30000000082LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "xg", OP48(0xe30000000082LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "og", OP48(0xe30000000081LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "og", OP48(0xe30000000081LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ng", OP48(0xe30000000080LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ng", OP48(0xe30000000080LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "shy", OP48(0xe3000000007bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ahy", OP48(0xe3000000007aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "chy", OP48(0xe30000000079LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lhy", OP48(0xe30000000078LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgb", OP48(0xe30000000077LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lb", OP48(0xe30000000076LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "icy", OP48(0xe30000000073LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stcy", OP48(0xe30000000072LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lay", OP48(0xe30000000071LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sthy", OP48(0xe30000000070LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sly", OP48(0xe3000000005fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "aly", OP48(0xe3000000005eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sy", OP48(0xe3000000005bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ay", OP48(0xe3000000005aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cy", OP48(0xe30000000059LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ly", OP48(0xe30000000058LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "xy", OP48(0xe30000000057LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "oy", OP48(0xe30000000056LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cly", OP48(0xe30000000055LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ny", OP48(0xe30000000054LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msy", OP48(0xe30000000051LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sty", OP48(0xe30000000050LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "bctg", OP48(0xe30000000046LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "bctg", OP48(0xe30000000046LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "strvh", OP48(0xe3000000003fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "strvh", OP48(0xe3000000003fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "strv", OP48(0xe3000000003eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "strv", OP48(0xe3000000003eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "clgf", OP48(0xe30000000031LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "clgf", OP48(0xe30000000031LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cgf", OP48(0xe30000000030LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cgf", OP48(0xe30000000030LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "strvg", OP48(0xe3000000002fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "strvg", OP48(0xe3000000002fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvdg", OP48(0xe3000000002eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cvdg", OP48(0xe3000000002eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvdy", OP48(0xe30000000026LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stg", OP48(0xe30000000024LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "stg", OP48(0xe30000000024LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "clg", OP48(0xe30000000021LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "clg", OP48(0xe30000000021LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cg", OP48(0xe30000000020LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cg", OP48(0xe30000000020LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lrvh", OP48(0xe3000000001fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "lrvh", OP48(0xe3000000001fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "lrv", OP48(0xe3000000001eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, + { "lrv", OP48(0xe3000000001eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, + { "dsgf", OP48(0xe3000000001dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dsgf", OP48(0xe3000000001dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "msgf", OP48(0xe3000000001cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msgf", OP48(0xe3000000001cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slgf", OP48(0xe3000000001bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slgf", OP48(0xe3000000001bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "algf", OP48(0xe3000000001aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "algf", OP48(0xe3000000001aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "sgf", OP48(0xe30000000019LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sgf", OP48(0xe30000000019LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "agf", OP48(0xe30000000018LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "agf", OP48(0xe30000000018LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgt", OP48(0xe30000000017LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgt", OP48(0xe30000000017LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "llgf", OP48(0xe30000000016LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "llgf", OP48(0xe30000000016LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lgh", OP48(0xe30000000015LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgh", OP48(0xe30000000015LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lgf", OP48(0xe30000000014LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lgf", OP48(0xe30000000014LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lray", OP48(0xe30000000013LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lt", OP48(0xe30000000012LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "lrvg", OP48(0xe3000000000fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lrvg", OP48(0xe3000000000fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvbg", OP48(0xe3000000000eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "cvbg", OP48(0xe3000000000eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "dsg", OP48(0xe3000000000dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "dsg", OP48(0xe3000000000dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "msg", OP48(0xe3000000000cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "msg", OP48(0xe3000000000cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "slg", OP48(0xe3000000000bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "slg", OP48(0xe3000000000bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "alg", OP48(0xe3000000000aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "alg", OP48(0xe3000000000aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "sg", OP48(0xe30000000009LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "sg", OP48(0xe30000000009LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ag", OP48(0xe30000000008LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "ag", OP48(0xe30000000008LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "cvby", OP48(0xe30000000006LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lg", OP48(0xe30000000004LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lg", OP48(0xe30000000004LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, + { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, + { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, + { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "ed", OP8(0xdeLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "trt", OP8(0xddLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "tr", OP8(0xdcLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvcs", OP8(0xdbLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "mvcp", OP8(0xdaLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "mvck", OP8(0xd9LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0}, + { "xc", OP8(0xd7LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "oc", OP8(0xd6LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "clc", OP8(0xd5LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "nc", OP8(0xd4LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvz", OP8(0xd3LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvc", OP8(0xd2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "mvn", OP8(0xd1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, + { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, + { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, + { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4}, + { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "cgfi", OP16(0xc20cLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "alfi", OP16(0xc20bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "algfi", OP16(0xc20aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "afi", OP16(0xc209LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "agfi", OP16(0xc208LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "slfi", OP16(0xc205LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "slgfi", OP16(0xc204LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "jg", OP16(0xc0f4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgno", OP16(0xc0e4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnh", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnp", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgle", OP16(0xc0c4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnl", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnm", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jghe", OP16(0xc0a4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnlh", OP16(0xc094LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jge", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgz", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgne", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnz", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jglh", OP16(0xc064LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnhe", OP16(0xc054LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgl", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgm", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgnle", OP16(0xc034LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgh", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgp", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "jgo", OP16(0xc014LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2}, + { "llilf", OP16(0xc00fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "llihf", OP16(0xc00eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "oilf", OP16(0xc00dLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "oihf", OP16(0xc00cLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "nilf", OP16(0xc00bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "nihf", OP16(0xc00aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "iilf", OP16(0xc009LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "iihf", OP16(0xc008LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "xilf", OP16(0xc007LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "xihf", OP16(0xc006LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, + { "brasl", OP16(0xc005LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2}, + { "brcl", OP16(0xc004LL), MASK_RIL_UP, INSTR_RIL_UP, 3, 2}, + { "lgfi", OP16(0xc001LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, + { "larl", OP16(0xc000LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2}, + { "icm", OP8(0xbfLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "stcm", OP8(0xbeLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "clm", OP8(0xbdLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0}, + { "cds", OP8(0xbbLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "cs", OP8(0xbaLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "cu42", OP16(0xb9b3LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu41", OP16(0xb9b2LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu24", OP16(0xb9b1LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cu14", OP16(0xb9b0LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "lptea", OP16(0xb9aaLL), MASK_RRF_RURR, INSTR_RRF_RURR, 2, 4}, + { "esea", OP16(0xb99dLL), MASK_RRE_R0, INSTR_RRE_R0, 2, 2}, + { "slbr", OP16(0xb999LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "alcr", OP16(0xb998LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "dlr", OP16(0xb997LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "mlr", OP16(0xb996LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "llhr", OP16(0xb995LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "llcr", OP16(0xb994LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "troo", OP16(0xb993LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "troo", OP16(0xb993LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trot", OP16(0xb992LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trot", OP16(0xb992LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trto", OP16(0xb991LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trto", OP16(0xb991LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "trtt", OP16(0xb990LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4}, + { "trtt", OP16(0xb990LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "idte", OP16(0xb98eLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 2, 3}, + { "epsw", OP16(0xb98dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "cspg", OP16(0xb98aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 3}, + { "slbgr", OP16(0xb989LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "alcgr", OP16(0xb988LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "dlgr", OP16(0xb987LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "mlgr", OP16(0xb986LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llghr", OP16(0xb985LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "llgcr", OP16(0xb984LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "flogr", OP16(0xb983LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "xgr", OP16(0xb982LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ogr", OP16(0xb981LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ngr", OP16(0xb980LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "bctgr", OP16(0xb946LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "klmd", OP16(0xb93fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "kimd", OP16(0xb93eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "clgfr", OP16(0xb931LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cgfr", OP16(0xb930LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "kmc", OP16(0xb92fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "km", OP16(0xb92eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "lhr", OP16(0xb927LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lbr", OP16(0xb926LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "sturg", OP16(0xb925LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "clgr", OP16(0xb921LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cgr", OP16(0xb920LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lrvr", OP16(0xb91fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2}, + { "kmac", OP16(0xb91eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3}, + { "dsgfr", OP16(0xb91dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "msgfr", OP16(0xb91cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "slgfr", OP16(0xb91bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "algfr", OP16(0xb91aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "sgfr", OP16(0xb919LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "agfr", OP16(0xb918LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llgtr", OP16(0xb917LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "llgfr", OP16(0xb916LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lgfr", OP16(0xb914LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lcgfr", OP16(0xb913LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ltgfr", OP16(0xb912LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lngfr", OP16(0xb911LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lpgfr", OP16(0xb910LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lrvgr", OP16(0xb90fLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "eregg", OP16(0xb90eLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "dsgr", OP16(0xb90dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "msgr", OP16(0xb90cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "slgr", OP16(0xb90bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "algr", OP16(0xb90aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "sgr", OP16(0xb909LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "agr", OP16(0xb908LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lghr", OP16(0xb907LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lgbr", OP16(0xb906LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4}, + { "lurag", OP16(0xb905LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lgr", OP16(0xb904LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lcgr", OP16(0xb903LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, + { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, + { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "iextr", OP16(0xb3feLL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5}, + { "qaxtr", OP16(0xb3fdLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "cextr", OP16(0xb3fcLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cxstr", OP16(0xb3fbLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cxutr", OP16(0xb3faLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cxgtr", OP16(0xb3f9LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "rrdtr", OP16(0xb3f7LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "iedtr", OP16(0xb3f6LL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5}, + { "qadtr", OP16(0xb3f5LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, + { "cedtr", OP16(0xb3f4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cdstr", OP16(0xb3f3LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cdutr", OP16(0xb3f2LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cdgtr", OP16(0xb3f1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "esxtr", OP16(0xb3efLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "eextr", OP16(0xb3edLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cxtr", OP16(0xb3ecLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "csxtr", OP16(0xb3ebLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cuxtr", OP16(0xb3eaLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgxtr", OP16(0xb3e9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5}, + { "kxtr", OP16(0xb3e8LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "esdtr", OP16(0xb3e7LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "eedtr", OP16(0xb3e5LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cdtr", OP16(0xb3e4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "csdtr", OP16(0xb3e3LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cudtr", OP16(0xb3e2LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgdtr", OP16(0xb3e1LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5}, + { "kdtr", OP16(0xb3e0LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "fixtr", OP16(0xb3dfLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ltxtr", OP16(0xb3deLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "ldxtr", OP16(0xb3ddLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "lxdtr", OP16(0xb3dcLL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5}, + { "sxtr", OP16(0xb3dbLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "axtr", OP16(0xb3daLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "dxtr", OP16(0xb3d9LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "mxtr", OP16(0xb3d8LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "fidtr", OP16(0xb3d7LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ltdtr", OP16(0xb3d6LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "ledtr", OP16(0xb3d5LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5}, + { "ldetr", OP16(0xb3d4LL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5}, + { "sdtr", OP16(0xb3d3LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "adtr", OP16(0xb3d2LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "ddtr", OP16(0xb3d1LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "mdtr", OP16(0xb3d0LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5}, + { "lgdr", OP16(0xb3cdLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5}, + { "cgxr", OP16(0xb3caLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgdr", OP16(0xb3c9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cger", OP16(0xb3c8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxgr", OP16(0xb3c6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cdgr", OP16(0xb3c5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cegr", OP16(0xb3c4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "ldgr", OP16(0xb3c1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5}, + { "cfxr", OP16(0xb3baLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cfdr", OP16(0xb3b9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cfer", OP16(0xb3b8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxfr", OP16(0xb3b6LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cdfr", OP16(0xb3b5LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cefr", OP16(0xb3b4LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cgxbr", OP16(0xb3aaLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgdbr", OP16(0xb3a9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cgebr", OP16(0xb3a8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2}, + { "cxgbr", OP16(0xb3a6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cdgbr", OP16(0xb3a5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cegbr", OP16(0xb3a4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, + { "cfxbr", OP16(0xb39aLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cfdbr", OP16(0xb399LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cfebr", OP16(0xb398LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0}, + { "cxfbr", OP16(0xb396LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cdfbr", OP16(0xb395LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "cefbr", OP16(0xb394LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0}, + { "efpc", OP16(0xb38cLL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0}, + { "sfasr", OP16(0xb385LL), MASK_RRE_R0, INSTR_RRE_R0, 2, 5}, + { "sfpc", OP16(0xb384LL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0}, + { "fidr", OP16(0xb37fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "fier", OP16(0xb377LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lzxr", OP16(0xb376LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lzdr", OP16(0xb375LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lzer", OP16(0xb374LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "lcdfr", OP16(0xb373LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cpsdr", OP16(0xb372LL), MASK_RRF_F0FF2, INSTR_RRF_F0FF2, 2, 5}, + { "lndfr", OP16(0xb371LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "lpdfr", OP16(0xb370LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5}, + { "cxr", OP16(0xb369LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fixr", OP16(0xb367LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lexr", OP16(0xb366LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxr", OP16(0xb365LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "lcxr", OP16(0xb363LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltxr", OP16(0xb362LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnxr", OP16(0xb361LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpxr", OP16(0xb360LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fidbr", OP16(0xb35fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "didbr", OP16(0xb35bLL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0}, + { "thdr", OP16(0xb359LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "thder", OP16(0xb358LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "fiebr", OP16(0xb357LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "diebr", OP16(0xb353LL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0}, + { "tbdr", OP16(0xb351LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "tbedr", OP16(0xb350LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "dxbr", OP16(0xb34dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mxbr", OP16(0xb34cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sxbr", OP16(0xb34bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "axbr", OP16(0xb34aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cxbr", OP16(0xb349LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kxbr", OP16(0xb348LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "fixbr", OP16(0xb347LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0}, + { "lexbr", OP16(0xb346LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ldxbr", OP16(0xb345LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ledbr", OP16(0xb344LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcxbr", OP16(0xb343LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltxbr", OP16(0xb342LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnxbr", OP16(0xb341LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpxbr", OP16(0xb340LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msdr", OP16(0xb33fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "madr", OP16(0xb33eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "myhr", OP16(0xb33dLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mayhr", OP16(0xb33cLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "myr", OP16(0xb33bLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mayr", OP16(0xb33aLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "mylr", OP16(0xb339LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "maylr", OP16(0xb338LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4}, + { "meer", OP16(0xb337LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqxr", OP16(0xb336LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mser", OP16(0xb32fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "maer", OP16(0xb32eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3}, + { "lxer", OP16(0xb326LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxdr", OP16(0xb325LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lder", OP16(0xb324LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msdbr", OP16(0xb31fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "madbr", OP16(0xb31eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "ddbr", OP16(0xb31dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mdbr", OP16(0xb31cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sdbr", OP16(0xb31bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "adbr", OP16(0xb31aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cdbr", OP16(0xb319LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kdbr", OP16(0xb318LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "meebr", OP16(0xb317LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqxbr", OP16(0xb316LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqdbr", OP16(0xb315LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sqebr", OP16(0xb314LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcdbr", OP16(0xb313LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltdbr", OP16(0xb312LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lndbr", OP16(0xb311LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpdbr", OP16(0xb310LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "msebr", OP16(0xb30fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "maebr", OP16(0xb30eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0}, + { "debr", OP16(0xb30dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mdebr", OP16(0xb30cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "sebr", OP16(0xb30bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "aebr", OP16(0xb30aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "cebr", OP16(0xb309LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "kebr", OP16(0xb308LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "mxdbr", OP16(0xb307LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxebr", OP16(0xb306LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lxdbr", OP16(0xb305LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ldebr", OP16(0xb304LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lcebr", OP16(0xb303LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, + { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5}, + { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5}, + { "lpswe", OP16(0xb2b2LL), MASK_S_RD, INSTR_S_RD, 2, 2}, + { "stfl", OP16(0xb2b1LL), MASK_S_RD, INSTR_S_RD, 3, 2}, + { "stfle", OP16(0xb2b0LL), MASK_S_RD, INSTR_S_RD, 2, 4}, + { "cu12", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cutfu", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cutfu", OP16(0xb2a7LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cu21", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cuutf", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "cuutf", OP16(0xb2a6LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "tre", OP16(0xb2a5LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "lfpc", OP16(0xb29dLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stfpc", OP16(0xb29cLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "srnm", OP16(0xb299LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stsi", OP16(0xb27dLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stckf", OP16(0xb27cLL), MASK_S_RD, INSTR_S_RD, 2, 4}, + { "sacf", OP16(0xb279LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stcke", OP16(0xb278LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "rp", OP16(0xb277LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "xsch", OP16(0xb276LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "siga", OP16(0xb274LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "srst", OP16(0xb25eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "clst", OP16(0xb25dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bsa", OP16(0xb25aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bsg", OP16(0xb258LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cuse", OP16(0xb257LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "mvst", OP16(0xb255LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "mvpg", OP16(0xb254LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "msr", OP16(0xb252LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "csp", OP16(0xb250LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ear", OP16(0xb24fLL), MASK_RRE_RA, INSTR_RRE_RA, 3, 0}, + { "sar", OP16(0xb24eLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0}, + { "cpya", OP16(0xb24dLL), MASK_RRE_AA, INSTR_RRE_AA, 3, 0}, + { "tar", OP16(0xb24cLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0}, + { "lura", OP16(0xb24bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "esta", OP16(0xb24aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ereg", OP16(0xb249LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "palb", OP16(0xb248LL), MASK_RRE_00, INSTR_RRE_00, 3, 0}, + { "msta", OP16(0xb247LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "stura", OP16(0xb246LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "sqer", OP16(0xb245LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "sqdr", OP16(0xb244LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "cksm", OP16(0xb241LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "bakr", OP16(0xb240LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "schm", OP16(0xb23cLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "rchp", OP16(0xb23bLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "stcps", OP16(0xb23aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stcrw", OP16(0xb239LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "rsch", OP16(0xb238LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "sal", OP16(0xb237LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "tpi", OP16(0xb236LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "tsch", OP16(0xb235LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stsch", OP16(0xb234LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ssch", OP16(0xb233LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "msch", OP16(0xb232LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "hsch", OP16(0xb231LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "csch", OP16(0xb230LL), MASK_S_00, INSTR_S_00, 3, 0}, + { "pgout", OP16(0xb22fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "pgin", OP16(0xb22eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "dxr", OP16(0xb22dLL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0}, + { "tb", OP16(0xb22cLL), MASK_RRE_0R, INSTR_RRE_0R, 3, 0}, + { "sske", OP16(0xb22bLL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4}, + { "sske", OP16(0xb22bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "rrbe", OP16(0xb22aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "iske", OP16(0xb229LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "pt", OP16(0xb228LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "esar", OP16(0xb227LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "epar", OP16(0xb226LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ssar", OP16(0xb225LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "iac", OP16(0xb224LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ivsk", OP16(0xb223LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "ipm", OP16(0xb222LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0}, + { "ipte", OP16(0xb221LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0}, + { "cfc", OP16(0xb21aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sac", OP16(0xb219LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "pc", OP16(0xb218LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sie", OP16(0xb214LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stap", OP16(0xb212LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stpx", OP16(0xb211LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "spx", OP16(0xb210LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ptlb", OP16(0xb20dLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "ipk", OP16(0xb20bLL), MASK_S_00, INSTR_S_00, 3, 0}, + { "spka", OP16(0xb20aLL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stpt", OP16(0xb209LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "spt", OP16(0xb208LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stckc", OP16(0xb207LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sckc", OP16(0xb206LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stck", OP16(0xb205LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "sck", OP16(0xb204LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "stidp", OP16(0xb202LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "lra", OP8(0xb1LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "mc", OP8(0xafLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "sigp", OP8(0xaeLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "stosm", OP8(0xadLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "stnsm", OP8(0xacLL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "clcle", OP8(0xa9LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "mvcle", OP8(0xa8LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "j", OP16(0xa7f4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jno", OP16(0xa7e4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnh", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnp", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jle", OP16(0xa7c4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnl", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnm", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jhe", OP16(0xa7a4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnlh", OP16(0xa794LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "je", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jz", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jne", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnz", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jlh", OP16(0xa764LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnhe", OP16(0xa754LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jl", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jm", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jnle", OP16(0xa734LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jh", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jp", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "jo", OP16(0xa714LL), MASK_RI_0P, INSTR_RI_0P, 3, 0}, + { "cghi", OP16(0xa70fLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "chi", OP16(0xa70eLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "mghi", OP16(0xa70dLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "mhi", OP16(0xa70cLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "aghi", OP16(0xa70bLL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "ahi", OP16(0xa70aLL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "lghi", OP16(0xa709LL), MASK_RI_RI, INSTR_RI_RI, 2, 2}, + { "lhi", OP16(0xa708LL), MASK_RI_RI, INSTR_RI_RI, 3, 0}, + { "brctg", OP16(0xa707LL), MASK_RI_RP, INSTR_RI_RP, 2, 2}, + { "brct", OP16(0xa706LL), MASK_RI_RP, INSTR_RI_RP, 3, 0}, + { "bras", OP16(0xa705LL), MASK_RI_RP, INSTR_RI_RP, 3, 0}, + { "brc", OP16(0xa704LL), MASK_RI_UP, INSTR_RI_UP, 3, 0}, + { "tmhl", OP16(0xa703LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "tmhh", OP16(0xa702LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "tml", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmll", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "tmlh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0}, + { "llill", OP16(0xa50fLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llilh", OP16(0xa50eLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llihl", OP16(0xa50dLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "llihh", OP16(0xa50cLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oill", OP16(0xa50bLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oilh", OP16(0xa50aLL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oihl", OP16(0xa509LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "oihh", OP16(0xa508LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nill", OP16(0xa507LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nilh", OP16(0xa506LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nihl", OP16(0xa505LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "nihh", OP16(0xa504LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iill", OP16(0xa503LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iilh", OP16(0xa502LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iihl", OP16(0xa501LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "iihh", OP16(0xa500LL), MASK_RI_RU, INSTR_RI_RU, 2, 2}, + { "stam", OP8(0x9bLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0}, + { "lam", OP8(0x9aLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0}, + { "trace", OP8(0x99LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "lm", OP8(0x98LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "xi", OP8(0x97LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "oi", OP8(0x96LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "cli", OP8(0x95LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "ni", OP8(0x94LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "ts", OP8(0x93LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "mvi", OP8(0x92LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "tm", OP8(0x91LL), MASK_SI_URD, INSTR_SI_URD, 3, 0}, + { "stm", OP8(0x90LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "slda", OP8(0x8fLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srda", OP8(0x8eLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sldl", OP8(0x8dLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srdl", OP8(0x8cLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sla", OP8(0x8bLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sra", OP8(0x8aLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "sll", OP8(0x89LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "srl", OP8(0x88LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0}, + { "bxle", OP8(0x87LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "bxh", OP8(0x86LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "brxle", OP8(0x85LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0}, + { "brxh", OP8(0x84LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0}, + { "diag", OP8(0x83LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0}, + { "lpsw", OP8(0x82LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "ssm", OP8(0x80LL), MASK_S_RD, INSTR_S_RD, 3, 0}, + { "su", OP8(0x7fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "au", OP8(0x7eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "de", OP8(0x7dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "me", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "mde", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "se", OP8(0x7bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ae", OP8(0x7aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ce", OP8(0x79LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "le", OP8(0x78LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ms", OP8(0x71LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ste", OP8(0x70LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sw", OP8(0x6fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "aw", OP8(0x6eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "dd", OP8(0x6dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "md", OP8(0x6cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sd", OP8(0x6bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ad", OP8(0x6aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "cd", OP8(0x69LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "ld", OP8(0x68LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "mxd", OP8(0x67LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "std", OP8(0x60LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0}, + { "sl", OP8(0x5fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "al", OP8(0x5eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "d", OP8(0x5dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "m", OP8(0x5cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "s", OP8(0x5bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "a", OP8(0x5aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "c", OP8(0x59LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "l", OP8(0x58LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "x", OP8(0x57LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "o", OP8(0x56LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cl", OP8(0x55LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "n", OP8(0x54LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "lae", OP8(0x51LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "st", OP8(0x50LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cvb", OP8(0x4fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "cvd", OP8(0x4eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "bas", OP8(0x4dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "mh", OP8(0x4cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sh", OP8(0x4bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ah", OP8(0x4aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ch", OP8(0x49LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "lh", OP8(0x48LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "b", OP16(0x47f0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bno", OP16(0x47e0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnh", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnp", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "ble", OP16(0x47c0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnl", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnm", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bhe", OP16(0x47a0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnlh", OP16(0x4790LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "be", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bz", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bne", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnz", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "blh", OP16(0x4760LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnhe", OP16(0x4750LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bl", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bm", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bnle", OP16(0x4730LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bh", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bp", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bo", OP16(0x4710LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bc", OP8(0x47LL), MASK_RX_URRD, INSTR_RX_URRD, 3, 0}, + { "nop", OP16(0x4700LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0}, + { "bct", OP8(0x46LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "bal", OP8(0x45LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ex", OP8(0x44LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "ic", OP8(0x43LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "stc", OP8(0x42LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "la", OP8(0x41LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sth", OP8(0x40LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0}, + { "sur", OP8(0x3fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "aur", OP8(0x3eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "der", OP8(0x3dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mer", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mder", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ser", OP8(0x3bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "aer", OP8(0x3aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "cer", OP8(0x39LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ler", OP8(0x38LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "sxr", OP8(0x37LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "axr", OP8(0x36LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lrer", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ledr", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "her", OP8(0x34LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lcer", OP8(0x33LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lter", OP8(0x32LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lner", OP8(0x31LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lper", OP8(0x30LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "swr", OP8(0x2fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "awr", OP8(0x2eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ddr", OP8(0x2dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mdr", OP8(0x2cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "sdr", OP8(0x2bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "adr", OP8(0x2aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "cdr", OP8(0x29LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ldr", OP8(0x28LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mxdr", OP8(0x27LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "mxr", OP8(0x26LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lrdr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ldxr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "hdr", OP8(0x24LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lcdr", OP8(0x23LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "ltdr", OP8(0x22LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lndr", OP8(0x21LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "lpdr", OP8(0x20LL), MASK_RR_FF, INSTR_RR_FF, 3, 0}, + { "slr", OP8(0x1fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "alr", OP8(0x1eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "dr", OP8(0x1dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "mr", OP8(0x1cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "sr", OP8(0x1bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "ar", OP8(0x1aLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "cr", OP8(0x19LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lr", OP8(0x18LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "xr", OP8(0x17LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "or", OP8(0x16LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "clr", OP8(0x15LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "nr", OP8(0x14LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lcr", OP8(0x13LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "ltr", OP8(0x12LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lnr", OP8(0x11LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "lpr", OP8(0x10LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "clcl", OP8(0x0fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "mvcl", OP8(0x0eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "basr", OP8(0x0dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "bassm", OP8(0x0cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "bsm", OP8(0x0bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "svc", OP8(0x0aLL), MASK_RR_U0, INSTR_RR_U0, 3, 0}, + { "br", OP16(0x07f0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnor", OP16(0x07e0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnhr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnpr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bler", OP16(0x07c0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnlr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnmr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bher", OP16(0x07a0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnlhr", OP16(0x0790LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "ber", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bzr", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bner", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnzr", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "blhr", OP16(0x0760LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnher", OP16(0x0750LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "blr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bmr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bnler", OP16(0x0730LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bhr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bpr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bor", OP16(0x0710LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bcr", OP8(0x07LL), MASK_RR_UR, INSTR_RR_UR, 3, 0}, + { "nopr", OP16(0x0700LL), MASK_RR_0R, INSTR_RR_0R, 3, 0}, + { "bctr", OP8(0x06LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "balr", OP8(0x05LL), MASK_RR_RR, INSTR_RR_RR, 3, 0}, + { "spm", OP8(0x04LL), MASK_RR_R0, INSTR_RR_R0, 3, 0}, + { "trap2", OP16(0x01ffLL), MASK_E, INSTR_E, 3, 0}, + { "sam64", OP16(0x010eLL), MASK_E, INSTR_E, 2, 2}, + { "sam31", OP16(0x010dLL), MASK_E, INSTR_E, 3, 2}, + { "sam24", OP16(0x010cLL), MASK_E, INSTR_E, 3, 2}, + { "tam", OP16(0x010bLL), MASK_E, INSTR_E, 3, 2}, + { "pfpo", OP16(0x010aLL), MASK_E, INSTR_E, 2, 5}, + { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0}, + { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0}, + { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0} +}; + +const int s390_num_opcodes = + sizeof (s390_opcodes) / sizeof (s390_opcodes[0]); + -- cgit v1.2.3 From 9bbc5cc8295670fd3f80fbdbc7fdddcecb403880 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 31 Jul 2007 23:46:55 +0000 Subject: Fiddly dyngen bits for s390 host support, by Ulrich Hecht. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3105 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen-exec.h | 2 +- exec-all.h | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 9f5fcc6ce..75d27ce16 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -254,7 +254,7 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n) #elif defined(__s390__) #define EXIT_TB() asm volatile ("br %r14") -#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n) +#define GOTO_LABEL_PARAM(n) asm volatile ("bras %r7,8; .long " ASM_NAME(__op_gen_label) #n "; l %r7, 0(%r7); br %r7") #elif defined(__alpha__) #define EXIT_TB() asm volatile ("ret") #elif defined(__ia64__) diff --git a/exec-all.h b/exec-all.h index 8ea057b79..31914ee2f 100644 --- a/exec-all.h +++ b/exec-all.h @@ -340,6 +340,24 @@ do {\ "1:\n");\ } while (0) +#elif defined(__s390__) +/* GCC spills R13, so we have to restore it before branching away */ + +#define GOTO_TB(opname, tbparam, n)\ +do {\ + static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\ + static void __attribute__((used)) *__op_label ## n \ + __asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\ + __asm__ __volatile__ ( \ + "l %%r13,52(%%r15)\n" \ + "br %0\n" \ + : : "r" (((TranslationBlock*)tbparam)->tb_next[n]));\ + \ + for(;*((int*)0);); /* just to keep GCC busy */ \ +label ## n: ;\ +dummy_label ## n: ;\ +} while(0) + #else /* jump to next block operations (more portable code, does not need -- cgit v1.2.3 From 0e7b8a9f0147e6833244331935e2ff895f96a8f8 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 1 Aug 2007 00:09:31 +0000 Subject: Also match s390x. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3106 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 705f6de03..0f959b7d0 100755 --- a/configure +++ b/configure @@ -53,7 +53,7 @@ case "$cpu" in mips64) cpu="mips64" ;; - s390) + s390*) cpu="s390" ;; sparc|sun4[cdmuv]) -- cgit v1.2.3 From 2e23213f26fc747b3a4de3c87906bfd3399e95fa Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 1 Aug 2007 02:31:54 +0000 Subject: Special-case iWMMXt register transfer insns, which are in ARM LDC2/STC2 class. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3107 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 8 +++++--- target-arm/translate.c | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 8132d0caf..f1b170d03 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -838,9 +838,11 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 15: /* Implementation specific. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { if (op2 == 0 && crm == 1) { - /* Changes cp0 to cp13 behavior, so needs a TB flush. */ - tb_flush(env); - env->cp15.c15_cpar = (val & 0x3fff) | 2; + if (env->cp15.c15_cpar != (val & 0x3fff)) { + /* Changes cp0 to cp13 behavior, so needs a TB flush. */ + tb_flush(env); + env->cp15.c15_cpar = val & 0x3fff; + } break; } goto bad_reg; diff --git a/target-arm/translate.c b/target-arm/translate.c index 3ce93f89b..799aef2f1 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2230,6 +2230,13 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_movl_T0_im(val); gen_bx(s); return; + } else if ((insn & 0x0e000f00) == 0x0c000100) { + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + /* iWMMXt register transfer. */ + if (env->cp15.c15_cpar & (1 << 1)) + if (!disas_iwmmxt_insn(env, s, insn)) + return; + } } else if ((insn & 0x0fe00000) == 0x0c400000) { /* Coprocessor double register transfer. */ } else if ((insn & 0x0f000010) == 0x0e000010) { -- cgit v1.2.3 From bf5ee2487b707d586ff4ac1de43c815a1b1634d4 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 1 Aug 2007 02:41:33 +0000 Subject: Move Spitz microdrive from first to second PCMCIA slot where it belongs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3108 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/spitz.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/spitz.c b/hw/spitz.c index eaea2e976..540e1b206 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -924,7 +924,7 @@ static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu) if (bs && bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) { md = dscm1xxxx_init(bs); - pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); + pxa2xx_pcmcia_attach(cpu->pcmcia[1], md); } } @@ -1210,10 +1210,10 @@ static void spitz_common_init(int ram_size, int vga_ram_size, spitz_akita_i2c_setup(cpu); if (model == terrier) - /* A 6.0 GB microdrive is permanently sitting in CF slot 0. */ + /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */ spitz_microdrive_attach(cpu); else if (model != akita) - /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ + /* A 4.0 GB microdrive is permanently sitting in CF slot 1. */ spitz_microdrive_attach(cpu); /* Setup initial (reset) machine state */ -- cgit v1.2.3 From ccf1d14a1e37abe1f0da162c00a8941963b47a4c Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 1 Aug 2007 13:10:29 +0000 Subject: Fix rtl8139 checksum calculation, by Tim Deegan. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3109 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/rtl8139.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 705bddb4e..210af449f 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -53,9 +53,8 @@ /* debug RTL8139 card C+ mode only */ //#define DEBUG_RTL8139CP 1 -/* RTL8139 provides frame CRC with received packet, this feature seems to be - ignored by most drivers, disabled by default */ -//#define RTL8139_CALCULATE_RXCRC 1 +/* Calculate CRCs properly on Rx packets */ +#define RTL8139_CALCULATE_RXCRC 1 /* Uncomment to enable on-board timer interrupts */ //#define RTL8139_ONBOARD_TIMER 1 @@ -747,7 +746,7 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize); /* write packet data */ - if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s)) + if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s))) { DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped)); @@ -1023,7 +1022,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d /* write checksum */ #if defined (RTL8139_CALCULATE_RXCRC) - val = cpu_to_le32(crc32(~0, buf, size)); + val = cpu_to_le32(crc32(0, buf, size)); #else val = 0; #endif @@ -1129,7 +1128,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d /* write checksum */ #if defined (RTL8139_CALCULATE_RXCRC) - val = cpu_to_le32(crc32(~0, buf, size)); + val = cpu_to_le32(crc32(0, buf, size)); #else val = 0; #endif -- cgit v1.2.3 From 327ac2e797ed57d7231d44c77a7473d62efe0989 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 4 Aug 2007 10:50:30 +0000 Subject: Fix Sparc32 interrupt handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3110 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 3 +++ hw/slavio_intctl.c | 55 +++++++++++++++++++++++------------------------------- hw/sun4m.c | 37 +++++++++++++++++++++++++----------- target-sparc/cpu.h | 4 +++- 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 4f7f215c0..543ec09ef 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -461,6 +461,9 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_HARD; do_interrupt(env->interrupt_index); env->interrupt_index = 0; +#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) + cpu_check_irqs(env); +#endif #if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index acde370e5..9550c0064 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -104,6 +104,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint val |= 80000000; val &= 0xfffe0000; s->intreg_pending[cpu] &= ~val; + slavio_check_interrupts(s); DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); break; case 2: // set softint @@ -175,10 +176,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin val &= ~0x4fb2007f; s->intregm_disabled |= val; s->intregm_pending &= ~val; + slavio_check_interrupts(s); DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); break; case 4: s->target_cpu = val & (MAX_CPUS - 1); + slavio_check_interrupts(s); DPRINTF("Set master irq cpu %d\n", s->target_cpu); break; default: @@ -227,53 +230,36 @@ void slavio_irq_info(void *opaque) #endif } -static void raise_pil(SLAVIO_INTCTLState *s, unsigned int pil, - unsigned int cpu) -{ - qemu_irq irq; - unsigned int oldmax; - - irq = s->cpu_irqs[cpu][pil]; - -#ifdef DEBUG_IRQ_COUNT - s->irq_count[pil]++; -#endif - oldmax = s->pil_out[cpu]; - if (oldmax > 0 && oldmax != pil) - qemu_irq_lower(s->cpu_irqs[cpu][oldmax]); - s->pil_out[cpu] = pil; - if (pil > 0) - qemu_irq_raise(irq); - DPRINTF("cpu %d pil %d\n", cpu, pil); -} - static void slavio_check_interrupts(void *opaque) { SLAVIO_INTCTLState *s = opaque; - uint32_t pending = s->intregm_pending; - unsigned int i, j, max = 0; + uint32_t pending = s->intregm_pending, pil_pending; + unsigned int i, j; pending &= ~s->intregm_disabled; DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); for (i = 0; i < MAX_CPUS; i++) { - max = 0; + pil_pending = 0; if (pending && !(s->intregm_disabled & 0x80000000) && (i == s->target_cpu)) { for (j = 0; j < 32; j++) { - if (pending & (1 << j)) { - if (max < s->intbit_to_level[j]) - max = s->intbit_to_level[j]; - } + if (pending & (1 << j)) + pil_pending |= 1 << s->intbit_to_level[j]; } } - for (j = 17; j < 32; j++) { - if (s->intreg_pending[i] & (1 << j)) { - if (max < j - 16) - max = j - 16; + pil_pending |= (s->intreg_pending[i] >> 16) & 0xfffe; + + for (j = 0; j < MAX_PILS; j++) { + if (pil_pending & (1 << j)) { + if (!(s->pil_out[i] & (1 << j))) + qemu_irq_raise(s->cpu_irqs[i][j]); + } else { + if (s->pil_out[i] & (1 << j)) + qemu_irq_lower(s->cpu_irqs[i][j]); } } - raise_pil(s, max, i); + s->pil_out[i] = pil_pending; } } @@ -291,6 +277,9 @@ static void slavio_set_irq(void *opaque, int irq, int level) level); if (pil > 0) { if (level) { +#ifdef DEBUG_IRQ_COUNT + s->irq_count[pil]++; +#endif s->intregm_pending |= mask; s->intreg_pending[s->target_cpu] |= 1 << pil; } else { @@ -342,6 +331,7 @@ static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->intregm_pending); qemu_get_be32s(f, &s->intregm_disabled); qemu_get_be32s(f, &s->target_cpu); + slavio_check_interrupts(s); return 0; } @@ -356,6 +346,7 @@ static void slavio_intctl_reset(void *opaque) s->intregm_disabled = ~0xffb2007f; s->intregm_pending = 0; s->target_cpu = 0; + slavio_check_interrupts(s); } void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, diff --git a/hw/sun4m.c b/hw/sun4m.c index eb69ef8e5..597481267 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -240,26 +240,41 @@ void irq_info() slavio_irq_info(slavio_intctl); } +void cpu_check_irqs(CPUState *env) +{ + if (env->pil_in && (env->interrupt_index == 0 || + (env->interrupt_index & ~15) == TT_EXTINT)) { + unsigned int i; + + for (i = 15; i > 0; i--) { + if (env->pil_in & (1 << i)) { + int old_interrupt = env->interrupt_index; + + env->interrupt_index = TT_EXTINT | i; + if (old_interrupt != env->interrupt_index) + cpu_interrupt(env, CPU_INTERRUPT_HARD); + break; + } + } + } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + static void cpu_set_irq(void *opaque, int irq, int level) { CPUState *env = opaque; if (level) { DPRINTF("Raise CPU IRQ %d\n", irq); - env->halted = 0; - - if (env->interrupt_index == 0 || - ((env->interrupt_index & ~15) == TT_EXTINT && - (env->interrupt_index & 15) < irq)) { - env->interrupt_index = TT_EXTINT | irq; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - DPRINTF("Not triggered, pending exception %d\n", - env->interrupt_index); - } + env->pil_in |= 1 << irq; + cpu_check_irqs(env); } else { DPRINTF("Lower CPU IRQ %d\n", irq); + env->pil_in &= ~(1 << irq); + cpu_check_irqs(env); } } diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 600b37ba5..e469f041a 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -181,7 +181,8 @@ typedef struct CPUSPARCState { int psrs; /* supervisor mode (extracted from PSR) */ int psrps; /* previous supervisor mode */ int psret; /* enable traps */ - uint32_t psrpil; /* interrupt level */ + uint32_t psrpil; /* interrupt blocking level */ + uint32_t pil_in; /* incoming interrupt level bitmap */ int psref; /* enable fpu */ target_ulong version; jmp_buf jmp_env; @@ -306,6 +307,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, void do_tick_set_count(void *opaque, uint64_t count); uint64_t do_tick_get_count(void *opaque); void do_tick_set_limit(void *opaque, uint64_t limit); +void cpu_check_irqs(CPUSPARCState *env); #define CPUState CPUSPARCState #define cpu_init cpu_sparc_init -- cgit v1.2.3 From 36cbaae5cc21fbd0a12fbb256e941c485bcf0ced Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 4 Aug 2007 10:56:25 +0000 Subject: Use UTC/localtime flag in M48Txx git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3111 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index cda28c2f6..053acb5c0 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -80,7 +80,10 @@ static void get_time (m48t59_t *NVRAM, struct tm *tm) #ifdef _WIN32 memcpy(tm,localtime(&t),sizeof(*tm)); #else - localtime_r (&t, tm) ; + if (rtc_utc) + gmtime_r (&t, tm); + else + localtime_r (&t, tm) ; #endif } @@ -146,7 +149,10 @@ static void get_alarm (m48t59_t *NVRAM, struct tm *tm) #ifdef _WIN32 memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm)); #else - localtime_r (&NVRAM->alarm, tm); + if (rtc_utc) + gmtime_r (&NVRAM->alarm, tm); + else + localtime_r (&NVRAM->alarm, tm); #endif } -- cgit v1.2.3 From 1569fc29ef60fa1972115860b420fb40d238fac5 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 5 Aug 2007 17:47:16 +0000 Subject: Fix Slavio interrupt controller debugging output git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3112 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 9550c0064..993c3196c 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -84,7 +84,7 @@ static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) ret = 0; break; } - DPRINTF("read cpu %d reg 0x%x = %x\n", addr, ret); + DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, ret); return ret; } @@ -97,7 +97,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; saddr = (addr & INTCTL_MAXADDR) >> 2; - DPRINTF("write cpu %d reg 0x%x = %x\n", cpu, addr, val); + DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, val); switch (saddr) { case 1: // clear pending softints if (val & 0x4000) @@ -151,7 +151,7 @@ static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) ret = 0; break; } - DPRINTF("read system reg 0x%x = %x\n", addr, ret); + DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret); return ret; } @@ -162,7 +162,7 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin uint32_t saddr; saddr = (addr & INTCTLM_MASK) >> 2; - DPRINTF("write system reg 0x%x = %x\n", addr, val); + DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val); switch (saddr) { case 2: // clear (enable) // Force clear unused bits -- cgit v1.2.3 From 8a93e02a93eb8aae626dc169780226ab115edbf1 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 6 Aug 2007 13:19:15 +0000 Subject: Ensure string is properly terminated. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3113 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gdbstub.c b/gdbstub.c index 4aafcaa10..48c0c56c8 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1032,6 +1032,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...) *(p++) = *(fmt++); } } + *p = 0; va_end(va); put_packet(s, buf); #ifdef CONFIG_USER_ONLY -- cgit v1.2.3 From 981a2e99064ad52abf070d9e8d2a649535f0dd43 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 11 Aug 2007 07:49:55 +0000 Subject: Improve iommu debugging, use register names git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3114 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/hw/iommu.c b/hw/iommu.c index 77d8b817e..2330c8faa 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -100,7 +100,7 @@ static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) saddr = (addr - s->addr) >> 2; switch (saddr) { default: - DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]); + DPRINTF("read reg[%d] = %x\n", (int)saddr, s->regs[saddr]); return s->regs[saddr]; break; } @@ -113,7 +113,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val target_phys_addr_t saddr; saddr = (addr - s->addr) >> 2; - DPRINTF("write reg[%d] = %x\n", saddr, val); + DPRINTF("write reg[%d] = %x\n", (int)saddr, val); switch (saddr) { case IOMMU_CTRL: switch (val & IOMMU_CTRL_RNGE) { @@ -143,7 +143,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val s->iostart = 0xffffffff80000000ULL; break; } - DPRINTF("iostart = %llx\n", s->iostart); + DPRINTF("iostart = " TARGET_FMT_plx "\n", s->iostart); s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION); break; case IOMMU_BASE: @@ -188,12 +188,19 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) { - uint32_t iopte; + uint32_t iopte, ret; +#ifdef DEBUG_IOMMU + target_phys_addr_t pa = addr; +#endif - iopte = s->regs[1] << 4; + iopte = s->regs[IOMMU_BASE] << 4; addr &= ~s->iostart; iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; - return ldl_phys(iopte); + ret = ldl_phys(iopte); + DPRINTF("get flags addr " TARGET_FMT_plx " => pte %x, *ptes = %x\n", pa, + iopte, ret); + + return ret; } static target_phys_addr_t iommu_translate_pa(IOMMUState *s, @@ -271,7 +278,7 @@ static void iommu_reset(void *opaque) memset(s->regs, 0, IOMMU_NREGS * 4); s->iostart = 0; - s->regs[0] = IOMMU_VERSION; + s->regs[IOMMU_CTRL] = IOMMU_VERSION; } void *iommu_init(target_phys_addr_t addr) -- cgit v1.2.3 From 225d4be7099f0cfdf5c85b4e4be1fa1e5169543c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 11 Aug 2007 07:52:09 +0000 Subject: Log invalid accesses (no faults generated yet) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3115 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/hw/iommu.c b/hw/iommu.c index 2330c8faa..f87c79c67 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -59,6 +59,20 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define IOMMU_PGFLUSH (0x0018 >> 2) #define IOMMU_PGFLUSH_MASK 0xffffffff +#define IOMMU_AFSR (0x1000 >> 2) +#define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */ +#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after transaction */ +#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than 12.8 us. */ +#define IOMMU_AFSR_BE 0x10000000 /* Write access received error acknowledge */ +#define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */ +#define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */ +#define IOMMU_AFSR_RESV 0x00f00000 /* Reserved, forced to 0x8 by hardware */ +#define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */ +#define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */ +#define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */ + +#define IOMMU_AFAR (0x1004 >> 2) + #define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */ #define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */ #define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */ @@ -218,6 +232,16 @@ static target_phys_addr_t iommu_translate_pa(IOMMUState *s, return pa; } +static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, int is_write) +{ + DPRINTF("bad addr " TARGET_FMT_plx "\n", addr); + s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | (8 << 20) | + IOMMU_AFSR_FAV; + if (!is_write) + s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD; + s->regs[IOMMU_AFAR] = addr; +} + void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { @@ -231,12 +255,16 @@ void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, if (l > len) l = len; flags = iommu_page_get_flags(opaque, page); - if (!(flags & IOPTE_VALID)) + if (!(flags & IOPTE_VALID)) { + iommu_bad_addr(opaque, page, is_write); return; + } phys_addr = iommu_translate_pa(opaque, addr, flags); if (is_write) { - if (!(flags & IOPTE_WRITE)) + if (!(flags & IOPTE_WRITE)) { + iommu_bad_addr(opaque, page, is_write); return; + } cpu_physical_memory_write(phys_addr, buf, len); } else { cpu_physical_memory_read(phys_addr, buf, len); -- cgit v1.2.3 From 96c4f569846dccf552dbf5ca059a734eb51d3aae Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 11 Aug 2007 07:54:26 +0000 Subject: Generate interrupts and update state even if output is disabled (OpenBSD) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3116 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 36dbdcf16..86e661ccd 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -427,17 +427,17 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint break; case 1: SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val); + s->tx = val; if (s->wregs[5] & 8) { // tx enabled - s->tx = val; if (s->chr) qemu_chr_write(s->chr, &s->tx, 1); else if (s->type == kbd) { handle_kbd_command(s, val); } - s->rregs[0] |= 4; // Tx buffer empty - s->rregs[1] |= 1; // All sent - set_txint(s); } + s->rregs[0] |= 4; // Tx buffer empty + s->rregs[1] |= 1; // All sent + set_txint(s); break; default: break; -- cgit v1.2.3 From 74ec60481386396bb45e63a412cdb121e17d7b30 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 11 Aug 2007 07:58:41 +0000 Subject: Enable Selection command (NetBSD) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3117 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/esp.c b/hw/esp.c index 5a7e4ac6b..613d6ae2d 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -464,6 +464,9 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) DPRINTF("Set ATN & stop (%2.2x)\n", val); handle_satn_stop(s); break; + case 0x44: + DPRINTF("Enable selection (%2.2x)\n", val); + break; default: DPRINTF("Unhandled ESP command (%2.2x)\n", val); break; -- cgit v1.2.3 From 2e4a88cba26ff6a2da9058e9b491a88105b0160f Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 11 Aug 2007 08:16:00 +0000 Subject: r158: Fix wrong number of clean/saveable windows r159: Revert previous patch r160: Fix nvram size, arch_init hack r161: Fix Sparc64 insw and outsw r162: Fix read only location write attempt r163: Change virtual address below 4G Map first 16M of RAM Execute a kernel if loaded by Qemu r164: Make client interface 64 bits wide on Sparc64 r165: NVRAM support (temporary location) r166: Fix mapping of a single byte area, fix reset and poweroff r167: Maximally align allocations r168: Enable all interrupt sources for NetBSD r169: Fix NetBSD property problems git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3118 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 2 +- pc-bios/openbios-sparc32 | Bin 272948 -> 272948 bytes pc-bios/openbios-sparc64 | Bin 475784 -> 475784 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/README b/pc-bios/README index 2c50783b7..9839fac7e 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,7 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 and Sparc64 images are built from SVN version 157. + The included Sparc32 and Sparc64 images are built from SVN revision 169. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 4296ee8c6..8bd024da6 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index ace1dae29..57b129ff7 100644 Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ -- cgit v1.2.3 From 52da07d1af1884d6140cd68e0d5770f918439645 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 14 Aug 2007 23:39:33 +0000 Subject: MIPS disassembler update. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3119 c046a42c-6fe2-441c-8c8c-71466251a162 --- mips-dis.c | 601 ++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 437 insertions(+), 164 deletions(-) diff --git a/mips-dis.c b/mips-dis.c index a29884f3d..ff4d61c1e 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -2758,102 +2758,91 @@ int bfd_mips_num_opcodes = MIPS_NUM_OPCODES; /* Mips instructions are at maximum this many bytes long. */ #define INSNLEN 4 -static void set_default_mips_dis_options - PARAMS ((struct disassemble_info *)); -static void parse_mips_dis_option - PARAMS ((const char *, unsigned int)); -static void parse_mips_dis_options - PARAMS ((const char *)); -static int _print_insn_mips - PARAMS ((bfd_vma, struct disassemble_info *, enum bfd_endian)); -static int print_insn_mips - PARAMS ((bfd_vma, unsigned long int, struct disassemble_info *)); -static void print_insn_args - PARAMS ((const char *, unsigned long, bfd_vma, struct disassemble_info *)); -#if 0 -static int print_insn_mips16 - PARAMS ((bfd_vma, struct disassemble_info *)); -#endif -#if 0 -static int is_newabi - PARAMS ((Elf32_Ehdr *)); -#endif -#if 0 -static void print_mips16_insn_arg - PARAMS ((int, const struct mips_opcode *, int, bfd_boolean, int, bfd_vma, - struct disassemble_info *)); -#endif /* FIXME: These should be shared with gdb somehow. */ -struct mips_cp0sel_name { - unsigned int cp0reg; - unsigned int sel; - const char * const name; +struct mips_cp0sel_name +{ + unsigned int cp0reg; + unsigned int sel; + const char * const name; }; -/* The mips16 register names. */ -static const char * const mips16_reg_names[] = { - "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3" +/* The mips16 registers. */ +static const unsigned int mips16_to_32_reg_map[] = +{ + 16, 17, 2, 3, 4, 5, 6, 7 }; -static const char * const mips_gpr_names_numeric[32] = { +#define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]] + + +static const char * const mips_gpr_names_numeric[32] = +{ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" }; -static const char * const mips_gpr_names_oldabi[32] = { +static const char * const mips_gpr_names_oldabi[32] = +{ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" }; -static const char * const mips_gpr_names_newabi[32] = { +static const char * const mips_gpr_names_newabi[32] = +{ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" }; -static const char * const mips_fpr_names_numeric[32] = { +static const char * const mips_fpr_names_numeric[32] = +{ "$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" }; -static const char * const mips_fpr_names_32[32] = { +static const char * const mips_fpr_names_32[32] = +{ "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f", "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f", "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f", "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f" }; -static const char * const mips_fpr_names_n32[32] = { +static const char * const mips_fpr_names_n32[32] = +{ "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9", "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13" }; -static const char * const mips_fpr_names_64[32] = { +static const char * const mips_fpr_names_64[32] = +{ "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11", "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" }; -static const char * const mips_cp0_names_numeric[32] = { +static const char * const mips_cp0_names_numeric[32] = +{ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" }; -static const char * const mips_cp0_names_mips3264[32] = { +static const char * const mips_cp0_names_mips3264[32] = +{ "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", "c0_context", "c0_pagemask", "c0_wired", "$7", "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", @@ -2864,7 +2853,35 @@ static const char * const mips_cp0_names_mips3264[32] = { "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", }; -static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = { +static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = +{ + { 4, 1, "c0_contextconfig" }, + { 0, 1, "c0_mvpcontrol" }, + { 0, 2, "c0_mvpconf0" }, + { 0, 3, "c0_mvpconf1" }, + { 1, 1, "c0_vpecontrol" }, + { 1, 2, "c0_vpeconf0" }, + { 1, 3, "c0_vpeconf1" }, + { 1, 4, "c0_yqmask" }, + { 1, 5, "c0_vpeschedule" }, + { 1, 6, "c0_vpeschefback" }, + { 2, 1, "c0_tcstatus" }, + { 2, 2, "c0_tcbind" }, + { 2, 3, "c0_tcrestart" }, + { 2, 4, "c0_tchalt" }, + { 2, 5, "c0_tccontext" }, + { 2, 6, "c0_tcschedule" }, + { 2, 7, "c0_tcschefback" }, + { 5, 1, "c0_pagegrain" }, + { 6, 1, "c0_srsconf0" }, + { 6, 2, "c0_srsconf1" }, + { 6, 3, "c0_srsconf2" }, + { 6, 4, "c0_srsconf3" }, + { 6, 5, "c0_srsconf4" }, + { 12, 1, "c0_intctl" }, + { 12, 2, "c0_srsctl" }, + { 12, 3, "c0_srsmap" }, + { 15, 1, "c0_ebase" }, { 16, 1, "c0_config1" }, { 16, 2, "c0_config2" }, { 16, 3, "c0_config3" }, @@ -2882,6 +2899,10 @@ static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = { { 19, 5, "c0_watchhi,5" }, { 19, 6, "c0_watchhi,6" }, { 19, 7, "c0_watchhi,7" }, + { 23, 1, "c0_tracecontrol" }, + { 23, 2, "c0_tracecontrol2" }, + { 23, 3, "c0_usertracedata" }, + { 23, 4, "c0_tracebpc" }, { 25, 1, "c0_perfcnt,1" }, { 25, 2, "c0_perfcnt,2" }, { 25, 3, "c0_perfcnt,3" }, @@ -2893,10 +2914,23 @@ static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = { { 27, 2, "c0_cacheerr,2" }, { 27, 3, "c0_cacheerr,3" }, { 28, 1, "c0_datalo" }, - { 29, 1, "c0_datahi" } + { 28, 2, "c0_taglo1" }, + { 28, 3, "c0_datalo1" }, + { 28, 4, "c0_taglo2" }, + { 28, 5, "c0_datalo2" }, + { 28, 6, "c0_taglo3" }, + { 28, 7, "c0_datalo3" }, + { 29, 1, "c0_datahi" }, + { 29, 2, "c0_taghi1" }, + { 29, 3, "c0_datahi1" }, + { 29, 4, "c0_taghi2" }, + { 29, 5, "c0_datahi2" }, + { 29, 6, "c0_taghi3" }, + { 29, 7, "c0_datahi3" }, }; -static const char * const mips_cp0_names_mips3264r2[32] = { +static const char * const mips_cp0_names_mips3264r2[32] = +{ "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena", "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", @@ -2907,7 +2941,8 @@ static const char * const mips_cp0_names_mips3264r2[32] = { "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave", }; -static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = { +static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = +{ { 4, 1, "c0_contextconfig" }, { 5, 1, "c0_pagegrain" }, { 12, 1, "c0_intctl" }, @@ -2962,7 +2997,8 @@ static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = { }; /* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods. */ -static const char * const mips_cp0_names_sb1[32] = { +static const char * const mips_cp0_names_sb1[32] = +{ "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", "c0_context", "c0_pagemask", "c0_wired", "$7", "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare", @@ -2973,7 +3009,8 @@ static const char * const mips_cp0_names_sb1[32] = { "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave", }; -static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = { +static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = +{ { 16, 1, "c0_config1" }, { 18, 1, "c0_watchlo,1" }, { 19, 1, "c0_watchhi,1" }, @@ -2997,14 +3034,16 @@ static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = { { 29, 3, "c0_datahi_d" }, }; -static const char * const mips_hwr_names_numeric[32] = { +static const char * const mips_hwr_names_numeric[32] = +{ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" }; -static const char * const mips_hwr_names_mips3264r2[32] = { +static const char * const mips_hwr_names_mips3264r2[32] = +{ "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", @@ -3012,20 +3051,23 @@ static const char * const mips_hwr_names_mips3264r2[32] = { "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" }; -struct mips_abi_choice { +struct mips_abi_choice +{ const char *name; const char * const *gpr_names; const char * const *fpr_names; }; -struct mips_abi_choice mips_abi_choices[] = { +struct mips_abi_choice mips_abi_choices[] = +{ { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric }, { "32", mips_gpr_names_oldabi, mips_fpr_names_32 }, { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 }, { "64", mips_gpr_names_newabi, mips_fpr_names_64 }, }; -struct mips_arch_choice { +struct mips_arch_choice +{ const char *name; int bfd_mach_valid; unsigned long bfd_mach; @@ -3054,6 +3096,7 @@ struct mips_arch_choice { #define bfd_mach_mips6000 6000 #define bfd_mach_mips7000 7000 #define bfd_mach_mips8000 8000 +#define bfd_mach_mips9000 9000 #define bfd_mach_mips10000 10000 #define bfd_mach_mips12000 12000 #define bfd_mach_mips16 16 @@ -3066,7 +3109,8 @@ struct mips_arch_choice { #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) -const struct mips_arch_choice mips_arch_choices[] = { +const struct mips_arch_choice mips_arch_choices[] = +{ { "numeric", 0, 0, 0, 0, mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric }, @@ -3119,13 +3163,14 @@ const struct mips_arch_choice mips_arch_choices[] = { MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95), page 1. */ { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32, - ISA_MIPS32 | INSN_MIPS16, + ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS, mips_cp0_names_mips3264, mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264), mips_hwr_names_numeric }, { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2, - ISA_MIPS32R2 | INSN_MIPS16, + (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2 + | INSN_MIPS3D | INSN_MT), mips_cp0_names_mips3264r2, mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), mips_hwr_names_mips3264r2 }, @@ -3138,7 +3183,8 @@ const struct mips_arch_choice mips_arch_choices[] = { mips_hwr_names_numeric }, { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2, - ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX, + (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2 + | INSN_DSP64 | INSN_MT | INSN_MDMX), mips_cp0_names_mips3264r2, mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), mips_hwr_names_mips3264r2 }, @@ -3167,53 +3213,39 @@ static const struct mips_cp0sel_name *mips_cp0sel_names; static int mips_cp0sel_names_len; static const char * const *mips_hwr_names; -static const struct mips_abi_choice *choose_abi_by_name - PARAMS ((const char *, unsigned int)); -static const struct mips_arch_choice *choose_arch_by_name - PARAMS ((const char *, unsigned int)); -static const struct mips_arch_choice *choose_arch_by_number - PARAMS ((unsigned long)); -static const struct mips_cp0sel_name *lookup_mips_cp0sel_name - PARAMS ((const struct mips_cp0sel_name *, unsigned int, unsigned int, - unsigned int)); +/* Other options */ +static int no_aliases; /* If set disassemble as most general inst. */ static const struct mips_abi_choice * -choose_abi_by_name (name, namelen) - const char *name; - unsigned int namelen; +choose_abi_by_name (const char *name, unsigned int namelen) { const struct mips_abi_choice *c; unsigned int i; for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++) - { - if (strncmp (mips_abi_choices[i].name, name, namelen) == 0 - && strlen (mips_abi_choices[i].name) == namelen) - c = &mips_abi_choices[i]; - } + if (strncmp (mips_abi_choices[i].name, name, namelen) == 0 + && strlen (mips_abi_choices[i].name) == namelen) + c = &mips_abi_choices[i]; + return c; } static const struct mips_arch_choice * -choose_arch_by_name (name, namelen) - const char *name; - unsigned int namelen; +choose_arch_by_name (const char *name, unsigned int namelen) { const struct mips_arch_choice *c = NULL; unsigned int i; for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) - { - if (strncmp (mips_arch_choices[i].name, name, namelen) == 0 - && strlen (mips_arch_choices[i].name) == namelen) - c = &mips_arch_choices[i]; - } + if (strncmp (mips_arch_choices[i].name, name, namelen) == 0 + && strlen (mips_arch_choices[i].name) == namelen) + c = &mips_arch_choices[i]; + return c; } static const struct mips_arch_choice * -choose_arch_by_number (mach) - unsigned long mach; +choose_arch_by_number (unsigned long mach) { static unsigned long hint_bfd_mach; static const struct mips_arch_choice *hint_arch_choice; @@ -3241,8 +3273,7 @@ choose_arch_by_number (mach) } void -set_default_mips_dis_options (info) - struct disassemble_info *info; +set_default_mips_dis_options (struct disassemble_info *info) { const struct mips_arch_choice *chosen_arch; @@ -3256,6 +3287,7 @@ set_default_mips_dis_options (info) mips_cp0sel_names = NULL; mips_cp0sel_names_len = 0; mips_hwr_names = mips_hwr_names_numeric; + no_aliases = 0; /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */ #if 0 @@ -3383,9 +3415,8 @@ parse_mips_dis_option (option, len) /* Invalid option. */ } -void -parse_mips_dis_options (options) - const char *options; +static void +parse_mips_dis_options (const char *options) { const char *option_end; @@ -3415,9 +3446,10 @@ parse_mips_dis_options (options) } static const struct mips_cp0sel_name * -lookup_mips_cp0sel_name(names, len, cp0reg, sel) - const struct mips_cp0sel_name *names; - unsigned int len, cp0reg, sel; +lookup_mips_cp0sel_name (const struct mips_cp0sel_name *names, + unsigned int len, + unsigned int cp0reg, + unsigned int sel) { unsigned int i; @@ -3430,11 +3462,11 @@ lookup_mips_cp0sel_name(names, len, cp0reg, sel) /* Print insn arguments for 32/64-bit code. */ static void -print_insn_args (d, l, pc, info) - const char *d; - register unsigned long int l; - bfd_vma pc; - struct disassemble_info *info; +print_insn_args (const char *d, + register unsigned long int l, + bfd_vma pc, + struct disassemble_info *info, + const struct mips_opcode *opp) { int op, delta; unsigned int lsb, msb, msbd; @@ -3468,12 +3500,32 @@ print_insn_args (d, l, pc, info) lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT; (*info->fprintf_func) (info->stream, "0x%x", lsb); break; - + case 'B': msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB; (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); break; + case '1': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI1) & OP_MASK_UDI1); + break; + + case '2': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI2) & OP_MASK_UDI2); + break; + + case '3': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI3) & OP_MASK_UDI3); + break; + + case '4': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_UDI4) & OP_MASK_UDI4); + break; + case 'C': case 'H': msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; @@ -3517,6 +3569,34 @@ print_insn_args (d, l, pc, info) (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); break; + case 't': /* Coprocessor 0 reg name */ + (*info->fprintf_func) (info->stream, "%s", + mips_cp0_names[(l >> OP_SH_RT) & + OP_MASK_RT]); + break; + + case 'T': /* Coprocessor 0 reg name */ + { + const struct mips_cp0sel_name *n; + unsigned int cp0reg, sel; + + cp0reg = (l >> OP_SH_RT) & OP_MASK_RT; + sel = (l >> OP_SH_SEL) & OP_MASK_SEL; + + /* CP0 register including 'sel' code for mftc0, to be + printed textually if known. If not known, print both + CP0 register name and sel numerically since CP0 register + with sel 0 may have a name unrelated to register being + printed. */ + n = lookup_mips_cp0sel_name(mips_cp0sel_names, + mips_cp0sel_names_len, cp0reg, sel); + if (n != NULL) + (*info->fprintf_func) (info->stream, "%s", n->name); + else + (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel); + break; + } + default: /* xgettext:c-format */ (*info->fprintf_func) (info->stream, @@ -3526,6 +3606,98 @@ print_insn_args (d, l, pc, info) } break; + case '2': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_BP) & OP_MASK_BP); + break; + + case '3': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_SA3) & OP_MASK_SA3); + break; + + case '4': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_SA4) & OP_MASK_SA4); + break; + + case '5': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_IMM8) & OP_MASK_IMM8); + break; + + case '6': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_RS) & OP_MASK_RS); + break; + + case '7': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_DSPACC) & OP_MASK_DSPACC); + break; + + case '8': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_WRDSP) & OP_MASK_WRDSP); + break; + + case '9': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S); + break; + + case '0': /* dsp 6-bit signed immediate in bit 20 */ + delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT); + if (delta & 0x20) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case ':': /* dsp 7-bit signed immediate in bit 19 */ + delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7); + if (delta & 0x40) /* test sign bit */ + delta |= ~OP_MASK_DSPSFT_7; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '\'': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_RDDSP) & OP_MASK_RDDSP); + break; + + case '@': /* dsp 10-bit signed immediate in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) /* test sign bit */ + delta |= ~OP_MASK_IMM10; + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '!': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_MT_U) & OP_MASK_MT_U); + break; + + case '$': + (*info->fprintf_func) (info->stream, "%ld", + (l >> OP_SH_MT_H) & OP_MASK_MT_H); + break; + + case '*': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T); + break; + + case '&': + (*info->fprintf_func) (info->stream, "$ac%ld", + (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D); + break; + + case 'g': + /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2. */ + (*info->fprintf_func) (info->stream, "$%ld", + (l >> OP_SH_RD) & OP_MASK_RD); + break; + case 's': case 'b': case 'r': @@ -3542,7 +3714,7 @@ print_insn_args (d, l, pc, info) case 'i': case 'u': - (*info->fprintf_func) (info->stream, "0x%x", + (*info->fprintf_func) (info->stream, "0x%lx", (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE); break; @@ -3570,6 +3742,10 @@ print_insn_args (d, l, pc, info) case 'a': info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff) | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)); + /* For gdb disassembler, force odd address on jalx. */ + if (info->flavour == bfd_target_unknown_flavour + && strcmp (opp->name, "jalx") == 0) + info->target |= 1; (*info->print_address_func) (info->target, info); break; @@ -3616,32 +3792,33 @@ print_insn_args (d, l, pc, info) break; case '<': - (*info->fprintf_func) (info->stream, "0x%x", + (*info->fprintf_func) (info->stream, "0x%lx", (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); break; case 'c': - (*info->fprintf_func) (info->stream, "0x%x", + (*info->fprintf_func) (info->stream, "0x%lx", (l >> OP_SH_CODE) & OP_MASK_CODE); break; case 'q': - (*info->fprintf_func) (info->stream, "0x%x", + (*info->fprintf_func) (info->stream, "0x%lx", (l >> OP_SH_CODE2) & OP_MASK_CODE2); break; case 'C': - (*info->fprintf_func) (info->stream, "0x%x", + (*info->fprintf_func) (info->stream, "0x%lx", (l >> OP_SH_COPZ) & OP_MASK_COPZ); break; case 'B': - (*info->fprintf_func) (info->stream, "0x%x", + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_CODE20) & OP_MASK_CODE20); break; case 'J': - (*info->fprintf_func) (info->stream, "0x%x", + (*info->fprintf_func) (info->stream, "0x%lx", (l >> OP_SH_CODE19) & OP_MASK_CODE19); break; @@ -3675,7 +3852,7 @@ print_insn_args (d, l, pc, info) 'T' format. Therefore, until we gain understanding of cp2 register names, we can simply print the register numbers. */ - (*info->fprintf_func) (info->stream, "$%d", + (*info->fprintf_func) (info->stream, "$%ld", (l >> OP_SH_RT) & OP_MASK_RT); break; @@ -3689,7 +3866,7 @@ print_insn_args (d, l, pc, info) (*info->fprintf_func) (info->stream, "%s", mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]); else - (*info->fprintf_func) (info->stream, "$%d", + (*info->fprintf_func) (info->stream, "$%ld", (l >> OP_SH_RD) & OP_MASK_RD); break; @@ -3699,79 +3876,83 @@ print_insn_args (d, l, pc, info) break; case 'N': - (*info->fprintf_func) (info->stream, "$fcc%d", + (*info->fprintf_func) (info->stream, + ((opp->pinfo & (FP_D | FP_S)) != 0 + ? "$fcc%ld" : "$cc%ld"), (l >> OP_SH_BCC) & OP_MASK_BCC); break; case 'M': - (*info->fprintf_func) (info->stream, "$fcc%d", + (*info->fprintf_func) (info->stream, "$fcc%ld", (l >> OP_SH_CCC) & OP_MASK_CCC); break; case 'P': - (*info->fprintf_func) (info->stream, "%d", + (*info->fprintf_func) (info->stream, "%ld", (l >> OP_SH_PERFREG) & OP_MASK_PERFREG); break; case 'e': - (*info->fprintf_func) (info->stream, "%d", + (*info->fprintf_func) (info->stream, "%ld", (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE); break; case '%': - (*info->fprintf_func) (info->stream, "%d", + (*info->fprintf_func) (info->stream, "%ld", (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN); break; case 'H': - (*info->fprintf_func) (info->stream, "%d", + (*info->fprintf_func) (info->stream, "%ld", (l >> OP_SH_SEL) & OP_MASK_SEL); break; case 'O': - (*info->fprintf_func) (info->stream, "%d", + (*info->fprintf_func) (info->stream, "%ld", (l >> OP_SH_ALN) & OP_MASK_ALN); break; case 'Q': { unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL; + if ((vsel & 0x10) == 0) { int fmt; + vsel &= 0x0f; for (fmt = 0; fmt < 3; fmt++, vsel >>= 1) if ((vsel & 1) == 0) break; - (*info->fprintf_func) (info->stream, "$v%d[%d]", + (*info->fprintf_func) (info->stream, "$v%ld[%d]", (l >> OP_SH_FT) & OP_MASK_FT, vsel >> 1); } else if ((vsel & 0x08) == 0) { - (*info->fprintf_func) (info->stream, "$v%d", + (*info->fprintf_func) (info->stream, "$v%ld", (l >> OP_SH_FT) & OP_MASK_FT); } else { - (*info->fprintf_func) (info->stream, "0x%x", + (*info->fprintf_func) (info->stream, "0x%lx", (l >> OP_SH_FT) & OP_MASK_FT); } } break; case 'X': - (*info->fprintf_func) (info->stream, "$v%d", + (*info->fprintf_func) (info->stream, "$v%ld", (l >> OP_SH_FD) & OP_MASK_FD); break; case 'Y': - (*info->fprintf_func) (info->stream, "$v%d", + (*info->fprintf_func) (info->stream, "$v%ld", (l >> OP_SH_FS) & OP_MASK_FS); break; case 'Z': - (*info->fprintf_func) (info->stream, "$v%d", + (*info->fprintf_func) (info->stream, "$v%ld", (l >> OP_SH_FT) & OP_MASK_FT); break; @@ -3809,12 +3990,11 @@ is_newabi (header) this is little-endian code. */ static int -print_insn_mips (memaddr, word, info) - bfd_vma memaddr; - unsigned long int word; - struct disassemble_info *info; +print_insn_mips (bfd_vma memaddr, + unsigned long int word, + struct disassemble_info *info) { - register const struct mips_opcode *op; + const struct mips_opcode *op; static bfd_boolean init = 0; static const struct mips_opcode *mips_hash[OP_MASK_OP + 1]; @@ -3827,7 +4007,8 @@ print_insn_mips (memaddr, word, info) { for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++) { - if (op->pinfo == INSN_MACRO) + if (op->pinfo == INSN_MACRO + || (no_aliases && (op->pinfo2 & INSN2_ALIAS))) continue; if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) { @@ -3854,9 +4035,11 @@ print_insn_mips (memaddr, word, info) { for (; op < &mips_opcodes[NUMOPCODES]; op++) { - if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match) + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (word & op->mask) == op->match) { - register const char *d; + const char *d; /* We always allow to disassemble the jalx instruction. */ if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor) @@ -3891,7 +4074,7 @@ print_insn_mips (memaddr, word, info) if (d != NULL && *d != '\0') { (*info->fprintf_func) (info->stream, "\t"); - print_insn_args (d, word, memaddr, info); + print_insn_args (d, word, memaddr, info, op); } return INSNLEN; @@ -3901,7 +4084,7 @@ print_insn_mips (memaddr, word, info) /* Handle undefined instructions. */ info->insn_type = dis_noninsn; - (*info->fprintf_func) (info->stream, "0x%x", word); + (*info->fprintf_func) (info->stream, "0x%lx", word); return INSNLEN; } @@ -3912,10 +4095,9 @@ print_insn_mips (memaddr, word, info) this works. Otherwise, we need a clue. Sometimes. */ static int -_print_insn_mips (memaddr, info, endianness) - bfd_vma memaddr; - struct disassemble_info *info; - enum bfd_endian endianness; +_print_insn_mips (bfd_vma memaddr, + struct disassemble_info *info, + enum bfd_endian endianness) { bfd_byte buffer[INSNLEN]; int status; @@ -3961,17 +4143,13 @@ _print_insn_mips (memaddr, info, endianness) } int -print_insn_big_mips (memaddr, info) - bfd_vma memaddr; - struct disassemble_info *info; +print_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info) { return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG); } int -print_insn_little_mips (memaddr, info) - bfd_vma memaddr; - struct disassemble_info *info; +print_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info) { return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE); } @@ -3979,9 +4157,7 @@ print_insn_little_mips (memaddr, info) /* Disassemble mips16 instructions. */ #if 0 static int -print_insn_mips16 (memaddr, info) - bfd_vma memaddr; - struct disassemble_info *info; +print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) { int status; bfd_byte buffer[2]; @@ -4054,7 +4230,9 @@ print_insn_mips16 (memaddr, info) opend = mips16_opcodes + bfd_mips16_num_opcodes; for (op = mips16_opcodes; op < opend; op++) { - if (op->pinfo != INSN_MACRO && (insn & op->mask) == op->match) + if (op->pinfo != INSN_MACRO + && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) + && (insn & op->mask) == op->match) { const char *s; @@ -4135,14 +4313,13 @@ print_insn_mips16 (memaddr, info) /* Disassemble an operand for a mips16 instruction. */ static void -print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) - char type; - const struct mips_opcode *op; - int l; - bfd_boolean use_extend; - int extend; - bfd_vma memaddr; - struct disassemble_info *info; +print_mips16_insn_arg (char type, + const struct mips_opcode *op, + int l, + bfd_boolean use_extend, + int extend, + bfd_vma memaddr, + struct disassemble_info *info) { switch (type) { @@ -4155,27 +4332,27 @@ print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) case 'y': case 'w': (*info->fprintf_func) (info->stream, "%s", - mips16_reg_names[((l >> MIPS16OP_SH_RY) - & MIPS16OP_MASK_RY)]); + mips16_reg_names(((l >> MIPS16OP_SH_RY) + & MIPS16OP_MASK_RY))); break; case 'x': case 'v': (*info->fprintf_func) (info->stream, "%s", - mips16_reg_names[((l >> MIPS16OP_SH_RX) - & MIPS16OP_MASK_RX)]); + mips16_reg_names(((l >> MIPS16OP_SH_RX) + & MIPS16OP_MASK_RX))); break; case 'z': (*info->fprintf_func) (info->stream, "%s", - mips16_reg_names[((l >> MIPS16OP_SH_RZ) - & MIPS16OP_MASK_RZ)]); + mips16_reg_names(((l >> MIPS16OP_SH_RZ) + & MIPS16OP_MASK_RZ))); break; case 'Z': (*info->fprintf_func) (info->stream, "%s", - mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z) - & MIPS16OP_MASK_MOVE32Z)]); + mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z) + & MIPS16OP_MASK_MOVE32Z))); break; case '0': @@ -4457,15 +4634,26 @@ print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) } } info->target = (baseaddr & ~((1 << shift) - 1)) + immed; + if (pcrel && branch + && info->flavour == bfd_target_unknown_flavour) + /* For gdb disassembler, maintain odd address. */ + info->target |= 1; (*info->print_address_func) (info->target, info); } } break; case 'a': - if (! use_extend) - extend = 0; - l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); + { + int jalx = l & 0x400; + + if (! use_extend) + extend = 0; + l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); + if (!jalx && info->flavour == bfd_target_unknown_flavour) + /* For gdb disassembler, maintain odd address. */ + l |= 1; + } info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l; (*info->print_address_func) (info->target, info); info->insn_type = dis_jsr; @@ -4528,6 +4716,92 @@ print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) } break; + case 'm': + case 'M': + /* MIPS16e save/restore. */ + { + int need_comma = 0; + int amask, args, statics; + int nsreg, smask; + int framesz; + int i, j; + + l = l & 0x7f; + if (use_extend) + l |= extend << 16; + + amask = (l >> 16) & 0xf; + if (amask == MIPS16_ALL_ARGS) + { + args = 4; + statics = 0; + } + else if (amask == MIPS16_ALL_STATICS) + { + args = 0; + statics = 4; + } + else + { + args = amask >> 2; + statics = amask & 3; + } + + if (args > 0) { + (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]); + if (args > 1) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[4 + args - 1]); + need_comma = 1; + } + + framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8; + if (framesz == 0 && !use_extend) + framesz = 128; + + (*info->fprintf_func) (info->stream, "%s%d", + need_comma ? "," : "", + framesz); + + if (l & 0x40) /* $ra */ + (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]); + + nsreg = (l >> 24) & 0x7; + smask = 0; + if (l & 0x20) /* $s0 */ + smask |= 1 << 0; + if (l & 0x10) /* $s1 */ + smask |= 1 << 1; + if (nsreg > 0) /* $s2-$s8 */ + smask |= ((1 << nsreg) - 1) << 2; + + /* Find first set static reg bit. */ + for (i = 0; i < 9; i++) + { + if (smask & (1 << i)) + { + (*info->fprintf_func) (info->stream, ",%s", + mips_gpr_names[i == 8 ? 30 : (16 + i)]); + /* Skip over string of set bits. */ + for (j = i; smask & (2 << j); j++) + continue; + if (j > i) + (*info->fprintf_func) (info->stream, "-%s", + mips_gpr_names[j == 8 ? 30 : (16 + j)]); + i = j + 1; + } + } + + /* Statics $ax - $a3. */ + if (statics == 1) + (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]); + else if (statics > 0) + (*info->fprintf_func) (info->stream, ",%s-%s", + mips_gpr_names[7 - statics + 1], + mips_gpr_names[7]); + } + break; + default: /* xgettext:c-format */ (*info->fprintf_func) @@ -4540,8 +4814,7 @@ print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) #endif void -print_mips_disassembler_options (stream) - FILE *stream; +print_mips_disassembler_options (FILE *stream) { unsigned int i; -- cgit v1.2.3 From 2d069bab6ad7f8c74e49715f7c534e8e799c9855 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 16 Aug 2007 19:56:27 +0000 Subject: Use qemu_irq for a reset signal between DMA and ESP/Lance git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3120 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 11 +++++++++-- hw/pcnet.c | 11 +++++++++-- hw/sparc32_dma.c | 20 +++++++------------- hw/sun4m.c | 13 +++++++++---- vl.h | 8 +++----- 5 files changed, 37 insertions(+), 26 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index 613d6ae2d..10d4cadf2 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -344,6 +344,12 @@ static void esp_reset(void *opaque) s->do_cmd = 0; } +static void parent_esp_reset(void *opaque, int irq, int level) +{ + if (level) + esp_reset(opaque); +} + static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) { ESPState *s = opaque; @@ -569,7 +575,7 @@ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id) } void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, - void *dma_opaque, qemu_irq irq) + void *dma_opaque, qemu_irq irq, qemu_irq *reset) { ESPState *s; int esp_io_memory; @@ -581,7 +587,6 @@ void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, s->bd = bd; s->irq = irq; s->dma_opaque = dma_opaque; - sparc32_dma_set_reset_data(dma_opaque, esp_reset, s); esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); cpu_register_physical_memory(espaddr, ESP_SIZE, esp_io_memory); @@ -591,5 +596,7 @@ void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, register_savevm("esp", espaddr, 3, esp_save, esp_load, s); qemu_register_reset(esp_reset, s); + *reset = *qemu_allocate_irqs(parent_esp_reset, s, 1); + return s; } diff --git a/hw/pcnet.c b/hw/pcnet.c index 7f7c2de37..a086e6712 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -2011,6 +2011,12 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) #if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure +static void parent_lance_reset(void *opaque, int irq, int level) +{ + if (level) + pcnet_h_reset(opaque); +} + static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { @@ -2047,7 +2053,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { }; void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, - qemu_irq irq) + qemu_irq irq, qemu_irq *reset) { PCNetState *d; int lance_io_memory; @@ -2060,7 +2066,8 @@ void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); d->dma_opaque = dma_opaque; - sparc32_dma_set_reset_data(dma_opaque, pcnet_h_reset, d); + + *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1); cpu_register_physical_memory(leaddr, 4, lance_io_memory); diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index f26b4bec7..1946ce279 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -58,9 +58,9 @@ typedef struct DMAState DMAState; struct DMAState { uint32_t dmaregs[DMA_REGS]; qemu_irq irq; - void *iommu, *dev_opaque; - void (*dev_reset)(void *dev_opaque); + void *iommu; qemu_irq *pic; + qemu_irq dev_reset; }; /* Note: on sparc, the lance 16 bit bus is swapped */ @@ -178,7 +178,8 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) qemu_irq_lower(s->irq); } if (val & DMA_RESET) { - s->dev_reset(s->dev_opaque); + qemu_irq_raise(s->dev_reset); + qemu_irq_lower(s->dev_reset); } else if (val & DMA_DRAIN_FIFO) { val &= ~DMA_DRAIN_FIFO; } else if (val == 0) @@ -238,7 +239,7 @@ static int dma_load(QEMUFile *f, void *opaque, int version_id) } void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, - void *iommu, qemu_irq **dev_irq) + void *iommu, qemu_irq **dev_irq, qemu_irq **reset) { DMAState *s; int dma_io_memory; @@ -257,14 +258,7 @@ void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, qemu_register_reset(dma_reset, s); *dev_irq = qemu_allocate_irqs(dma_set_irq, s, 1); - return s; -} - -void sparc32_dma_set_reset_data(void *opaque, void (*dev_reset)(void *opaque), - void *dev_opaque) -{ - DMAState *s = opaque; + *reset = &s->dev_reset; - s->dev_reset = dev_reset; - s->dev_opaque = dev_opaque; + return s; } diff --git a/hw/sun4m.c b/hw/sun4m.c index 597481267..dba6f3878 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -315,6 +315,7 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, const sparc_def_t *def; qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; + qemu_irq *esp_reset, *le_reset; /* init CPUs */ sparc_find_by_name(cpu_model, &def); @@ -352,9 +353,11 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, hwdef->clock_irq); espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq], - iommu, &espdma_irq); + iommu, &espdma_irq, &esp_reset); + ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, - slavio_irq[hwdef->le_irq], iommu, &ledma_irq); + slavio_irq[hwdef->le_irq], iommu, &ledma_irq, + &le_reset); if (graphic_depth != 8 && graphic_depth != 24) { fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth); @@ -365,7 +368,7 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq); + lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset); } else if (strcmp(nd_table[0].model, "?") == 0) { fprintf(stderr, "qemu: Supported NICs: lance\n"); exit (1); @@ -389,7 +392,9 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], serial_hds[1], serial_hds[0]); fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table); - main_esp = esp_init(bs_table, hwdef->esp_base, espdma, *espdma_irq); + + main_esp = esp_init(bs_table, hwdef->esp_base, espdma, *espdma_irq, + esp_reset); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { diff --git a/vl.h b/vl.h index 997b63d17..b05ea119a 100644 --- a/vl.h +++ b/vl.h @@ -1054,7 +1054,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, - qemu_irq irq); + qemu_irq irq, qemu_irq *reset); /* vmmouse.c */ void *vmmouse_init(void *m); @@ -1273,19 +1273,17 @@ void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, - void *dma_opaque, qemu_irq irq); + void *dma_opaque, qemu_irq irq, qemu_irq *reset); /* sparc32_dma.c */ void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, - void *iommu, qemu_irq **dev_irq); + void *iommu, qemu_irq **dev_irq, qemu_irq **reset); void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void espdma_memory_read(void *opaque, uint8_t *buf, int len); void espdma_memory_write(void *opaque, uint8_t *buf, int len); -void sparc32_dma_set_reset_data(void *opaque, void (*dev_reset)(void *opaque), - void *dev_opaque); /* cs4231.c */ void cs_init(target_phys_addr_t base, int irq, void *intctl); -- cgit v1.2.3 From 9b5207aabb8262cec0ebb0b0a01ed26662337fe6 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 16 Aug 2007 19:57:27 +0000 Subject: Remove old leftovers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3121 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sparc32_dma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 1946ce279..d2fe57686 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -59,7 +59,6 @@ struct DMAState { uint32_t dmaregs[DMA_REGS]; qemu_irq irq; void *iommu; - qemu_irq *pic; qemu_irq dev_reset; }; @@ -119,12 +118,12 @@ static void dma_set_irq(void *opaque, int irq, int level) { DMAState *s = opaque; if (level) { - DPRINTF("Raise ESP IRQ\n"); + DPRINTF("Raise IRQ\n"); s->dmaregs[0] |= DMA_INTR; qemu_irq_raise(s->irq); } else { s->dmaregs[0] &= ~DMA_INTR; - DPRINTF("Lower ESP IRQ\n"); + DPRINTF("Lower IRQ\n"); qemu_irq_lower(s->irq); } } -- cgit v1.2.3 From 7f27bae69d4e4bd05bf3eafedce74a41d7fc35e8 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 18 Aug 2007 13:08:30 +0000 Subject: Remove obsolete comment. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3122 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pcnet.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index a086e6712..ed263edea 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -35,8 +35,6 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */ -/* TODO: remove little endian host assumptions */ - #include "vl.h" //#define PCNET_DEBUG -- cgit v1.2.3 From c0009975ca00b279071973ab22ff9798fee650ab Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 19 Aug 2007 21:43:54 +0000 Subject: Darwin-user: Compile fix for ppc targets, by Pierre d'Herbemont. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3123 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/darwin-user/main.c b/darwin-user/main.c index 78cf864c1..fd62fc1b8 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -150,6 +150,21 @@ void cpu_ppc_store_decr (CPUState *env, uint32_t value) /* TO FIX */ } +void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tbu( env, value ); +} + +uint32_t cpu_ppc601_load_rtcu (CPUState *env) +{ + cpu_ppc_load_tbu(env); +} + +uint32_t cpu_ppc601_load_rtcl (CPUState *env) +{ + return cpu_ppc_load_tbl(env) & 0x3FFFFF80; +} + void cpu_loop(CPUPPCState *env) { int trapnr; -- cgit v1.2.3 From 7603d1568e121f74b03dabc8f86c7c9b88723075 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 19 Aug 2007 21:46:53 +0000 Subject: Fix bugs in the ATAPI cdrom driver, by Brandon Philips. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3124 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index 9acb02a85..e84c4d67f 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -671,7 +671,8 @@ static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, s->end_transfer_func = end_transfer_func; s->data_ptr = buf; s->data_end = buf + size; - s->status |= DRQ_STAT; + if (!(s->status & ERR_STAT)) + s->status |= DRQ_STAT; } static void ide_transfer_stop(IDEState *s) @@ -1969,6 +1970,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* overlapping commands not supported */ if (s->feature & 0x02) goto abort_cmd; + s->status = READY_STAT; s->atapi_dma = s->feature & 1; s->nsector = 1; ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, -- cgit v1.2.3 From c89940133c02810197c405814439b0d529e5d551 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 19 Aug 2007 21:56:03 +0000 Subject: Rework alarm timer infrastrucure, by Luca Tettamanti. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3125 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 289 +++++++++++++++++++++++++++++++++++++++++++------------------------ vl.h | 1 - 2 files changed, 186 insertions(+), 104 deletions(-) diff --git a/vl.c b/vl.c index 4ff234132..ae05b8f6a 100644 --- a/vl.c +++ b/vl.c @@ -781,19 +781,59 @@ struct QEMUTimer { struct QEMUTimer *next; }; -QEMUClock *rt_clock; -QEMUClock *vm_clock; +struct qemu_alarm_timer { + char const *name; + + int (*start)(struct qemu_alarm_timer *t); + void (*stop)(struct qemu_alarm_timer *t); + void *priv; +}; + +static struct qemu_alarm_timer *alarm_timer; -static QEMUTimer *active_timers[2]; #ifdef _WIN32 -static MMRESULT timerID; -static HANDLE host_alarm = NULL; -static unsigned int period = 1; + +struct qemu_alarm_win32 { + MMRESULT timerId; + HANDLE host_alarm; + unsigned int period; +} alarm_win32_data = {0, NULL, -1}; + +static int win32_start_timer(struct qemu_alarm_timer *t); +static void win32_stop_timer(struct qemu_alarm_timer *t); + #else -/* frequency of the times() clock tick */ -static int timer_freq; + +static int unix_start_timer(struct qemu_alarm_timer *t); +static void unix_stop_timer(struct qemu_alarm_timer *t); + +#ifdef __linux__ + +static int rtc_start_timer(struct qemu_alarm_timer *t); +static void rtc_stop_timer(struct qemu_alarm_timer *t); + #endif +#endif /* _WIN32 */ + +static struct qemu_alarm_timer alarm_timers[] = { +#ifdef __linux__ + /* RTC - if available - is preferred */ + {"rtc", rtc_start_timer, rtc_stop_timer, NULL}, +#endif +#ifndef _WIN32 + {"unix", unix_start_timer, unix_stop_timer, NULL}, +#else + {"win32", win32_start_timer, win32_stop_timer, &alarm_win32_data}, +#endif + {NULL, } +}; + +QEMUClock *rt_clock; +QEMUClock *vm_clock; + +static QEMUTimer *active_timers[2]; + QEMUClock *qemu_new_clock(int type) { QEMUClock *clock; @@ -1009,7 +1049,8 @@ static void host_alarm_handler(int host_signum) qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { #ifdef _WIN32 - SetEvent(host_alarm); + struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; + SetEvent(data->host_alarm); #endif CPUState *env = cpu_single_env; if (env) { @@ -1030,10 +1071,27 @@ static void host_alarm_handler(int host_signum) #define RTC_FREQ 1024 -static int rtc_fd; +static void enable_sigio_timer(int fd) +{ + struct sigaction act; -static int start_rtc_timer(void) + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = 0; +#if defined (TARGET_I386) && defined(USE_CODE_COPY) + act.sa_flags |= SA_ONSTACK; +#endif + act.sa_handler = host_alarm_handler; + + sigaction(SIGIO, &act, NULL); + fcntl(fd, F_SETFL, O_ASYNC); + fcntl(fd, F_SETOWN, getpid()); +} + +static int rtc_start_timer(struct qemu_alarm_timer *t) { + int rtc_fd; + TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); if (rtc_fd < 0) return -1; @@ -1048,117 +1106,142 @@ static int start_rtc_timer(void) close(rtc_fd); return -1; } - pit_min_timer_count = PIT_FREQ / RTC_FREQ; + + enable_sigio_timer(rtc_fd); + + t->priv = (void *)rtc_fd; + return 0; } -#else - -static int start_rtc_timer(void) +static void rtc_stop_timer(struct qemu_alarm_timer *t) { - return -1; + int rtc_fd = (int)t->priv; + + close(rtc_fd); } #endif /* !defined(__linux__) */ -#endif /* !defined(_WIN32) */ +static int unix_start_timer(struct qemu_alarm_timer *t) +{ + struct sigaction act; + struct itimerval itv; + int err; -static void init_timer_alarm(void) + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = 0; +#if defined(TARGET_I386) && defined(USE_CODE_COPY) + act.sa_flags |= SA_ONSTACK; +#endif + act.sa_handler = host_alarm_handler; + + sigaction(SIGALRM, &act, NULL); + + itv.it_interval.tv_sec = 0; + /* for i386 kernel 2.6 to get 1 ms */ + itv.it_interval.tv_usec = 999; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 10 * 1000; + + err = setitimer(ITIMER_REAL, &itv, NULL); + if (err) + return -1; + + return 0; +} + +static void unix_stop_timer(struct qemu_alarm_timer *t) { + struct itimerval itv; + + memset(&itv, 0, sizeof(itv)); + setitimer(ITIMER_REAL, &itv, NULL); +} + +#endif /* !defined(_WIN32) */ + #ifdef _WIN32 - { - int count=0; - TIMECAPS tc; - - ZeroMemory(&tc, sizeof(TIMECAPS)); - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - if (period < tc.wPeriodMin) - period = tc.wPeriodMin; - timeBeginPeriod(period); - timerID = timeSetEvent(1, // interval (ms) - period, // resolution - host_alarm_handler, // function - (DWORD)&count, // user parameter - TIME_PERIODIC | TIME_CALLBACK_FUNCTION); - if( !timerID ) { - perror("failed timer alarm"); - exit(1); - } - host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!host_alarm) { - perror("failed CreateEvent"); - exit(1); - } - qemu_add_wait_object(host_alarm, NULL, NULL); + +static int win32_start_timer(struct qemu_alarm_timer *t) +{ + TIMECAPS tc; + struct qemu_alarm_win32 *data = t->priv; + + data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!data->host_alarm) { + perror("Failed CreateEvent"); + return -1 } - pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; -#else - { - struct sigaction act; - struct itimerval itv; - - /* get times() syscall frequency */ - timer_freq = sysconf(_SC_CLK_TCK); - - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; -#endif - act.sa_handler = host_alarm_handler; - sigaction(SIGALRM, &act, NULL); - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */ - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 10 * 1000; - setitimer(ITIMER_REAL, &itv, NULL); - /* we probe the tick duration of the kernel to inform the user if - the emulated kernel requested a too high timer frequency */ - getitimer(ITIMER_REAL, &itv); + memset(&tc, 0, sizeof(tc)); + timeGetDevCaps(&tc, sizeof(tc)); -#if defined(__linux__) - /* XXX: force /dev/rtc usage because even 2.6 kernels may not - have timers with 1 ms resolution. The correct solution will - be to use the POSIX real time timers available in recent - 2.6 kernels */ - if (itv.it_interval.tv_usec > 1000 || 1) { - /* try to use /dev/rtc to have a faster timer */ - if (start_rtc_timer() < 0) - goto use_itimer; - /* disable itimer */ - itv.it_interval.tv_sec = 0; - itv.it_interval.tv_usec = 0; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 0; - setitimer(ITIMER_REAL, &itv, NULL); - - /* use the RTC */ - sigaction(SIGIO, &act, NULL); - fcntl(rtc_fd, F_SETFL, O_ASYNC); - fcntl(rtc_fd, F_SETOWN, getpid()); - } else -#endif /* defined(__linux__) */ - { - use_itimer: - pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * - PIT_FREQ) / 1000000; - } + if (data->period < tc.wPeriodMin) + data->period = tc.wPeriodMin; + + timeBeginPeriod(data->period); + + data->timerId = timeSetEvent(1, // interval (ms) + data->period, // resolution + host_alarm_handler, // function + (DWORD)t, // parameter + TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + + if (!data->timerId) { + perror("Failed to initialize win32 alarm timer"); + + timeEndPeriod(data->period); + CloseHandle(data->host_alarm); + return -1; } -#endif + + qemu_add_wait_object(data->host_alarm, NULL, NULL); + + return 0; } -void quit_timers(void) +static void win32_stop_timer(struct qemu_alarm_timer *t) { -#ifdef _WIN32 - timeKillEvent(timerID); - timeEndPeriod(period); - if (host_alarm) { - CloseHandle(host_alarm); - host_alarm = NULL; + struct qemu_alarm_win32 *data = t->priv; + + timeKillEvent(data->timerId); + timeEndPeriod(data->period); + + CloseHandle(data->host_alarm); +} + +#endif /* _WIN32 */ + +static void init_timer_alarm(void) +{ + struct qemu_alarm_timer *t; + int i, err = -1; + + for (i = 0; alarm_timers[i].name; i++) { + t = &alarm_timers[i]; + + printf("trying %s...\n", t->name); + + err = t->start(t); + if (!err) + break; } -#endif + + if (err) { + fprintf(stderr, "Unable to find any suitable alarm timer.\n"); + fprintf(stderr, "Terminating\n"); + exit(1); + } + + alarm_timer = t; +} + +void quit_timers(void) +{ + alarm_timer->stop(alarm_timer); + alarm_timer = NULL; } /***********************************************************/ diff --git a/vl.h b/vl.h index b05ea119a..e12b6f3e7 100644 --- a/vl.h +++ b/vl.h @@ -447,7 +447,6 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); int qemu_timer_pending(QEMUTimer *ts); extern int64_t ticks_per_sec; -extern int pit_min_timer_count; int64_t cpu_get_ticks(void); void cpu_enable_ticks(void); -- cgit v1.2.3 From c40ec5a966eab19e75c98ee779145875d362b515 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 19 Aug 2007 22:09:40 +0000 Subject: Add -clock option, by Luca Tettamanti. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3126 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index ae05b8f6a..686bc3b65 100644 --- a/vl.c +++ b/vl.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #else @@ -809,6 +810,9 @@ static void unix_stop_timer(struct qemu_alarm_timer *t); #ifdef __linux__ +static int hpet_start_timer(struct qemu_alarm_timer *t); +static void hpet_stop_timer(struct qemu_alarm_timer *t); + static int rtc_start_timer(struct qemu_alarm_timer *t); static void rtc_stop_timer(struct qemu_alarm_timer *t); @@ -818,7 +822,9 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t); static struct qemu_alarm_timer alarm_timers[] = { #ifdef __linux__ - /* RTC - if available - is preferred */ + /* HPET - if available - is preferred */ + {"hpet", hpet_start_timer, hpet_stop_timer, NULL}, + /* ...otherwise try RTC */ {"rtc", rtc_start_timer, rtc_stop_timer, NULL}, #endif #ifndef _WIN32 @@ -1088,6 +1094,55 @@ static void enable_sigio_timer(int fd) fcntl(fd, F_SETOWN, getpid()); } +static int hpet_start_timer(struct qemu_alarm_timer *t) +{ + struct hpet_info info; + int r, fd; + + fd = open("/dev/hpet", O_RDONLY); + if (fd < 0) + return -1; + + /* Set frequency */ + r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ); + if (r < 0) { + fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n" + "error, but for better emulation accuracy type:\n" + "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n"); + goto fail; + } + + /* Check capabilities */ + r = ioctl(fd, HPET_INFO, &info); + if (r < 0) + goto fail; + + /* Enable periodic mode */ + r = ioctl(fd, HPET_EPI, 0); + if (info.hi_flags && (r < 0)) + goto fail; + + /* Enable interrupt */ + r = ioctl(fd, HPET_IE_ON, 0); + if (r < 0) + goto fail; + + enable_sigio_timer(fd); + t->priv = (void *)fd; + + return 0; +fail: + close(fd); + return -1; +} + +static void hpet_stop_timer(struct qemu_alarm_timer *t) +{ + int fd = (int)t->priv; + + close(fd); +} + static int rtc_start_timer(struct qemu_alarm_timer *t) { int rtc_fd; -- cgit v1.2.3 From c396a7f0f0416e62201faf83520e4710f60d62c5 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 20 Aug 2007 15:42:22 +0000 Subject: Windows build fix, spotted by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3127 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 686bc3b65..29595a2d6 100644 --- a/vl.c +++ b/vl.c @@ -1227,7 +1227,7 @@ static int win32_start_timer(struct qemu_alarm_timer *t) data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); if (!data->host_alarm) { perror("Failed CreateEvent"); - return -1 + return -1; } memset(&tc, 0, sizeof(tc)); -- cgit v1.2.3 From fcdc2129931c3bf6fe36a7a4ed35cdffb894c9c5 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 23 Aug 2007 20:22:22 +0000 Subject: Suppress int<->pointer compiler warnings. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3128 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vl.c b/vl.c index 29595a2d6..bfdf5204f 100644 --- a/vl.c +++ b/vl.c @@ -1128,7 +1128,7 @@ static int hpet_start_timer(struct qemu_alarm_timer *t) goto fail; enable_sigio_timer(fd); - t->priv = (void *)fd; + t->priv = (void *)(long)fd; return 0; fail: @@ -1138,7 +1138,7 @@ fail: static void hpet_stop_timer(struct qemu_alarm_timer *t) { - int fd = (int)t->priv; + int fd = (long)t->priv; close(fd); } @@ -1164,14 +1164,14 @@ static int rtc_start_timer(struct qemu_alarm_timer *t) enable_sigio_timer(rtc_fd); - t->priv = (void *)rtc_fd; + t->priv = (void *)(long)rtc_fd; return 0; } static void rtc_stop_timer(struct qemu_alarm_timer *t) { - int rtc_fd = (int)t->priv; + int rtc_fd = (long)t->priv; close(rtc_fd); } -- cgit v1.2.3 From f3dcfadac7ecb89a44c1c91d6dc1858ab517d102 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 24 Aug 2007 01:26:02 +0000 Subject: Implement -clock selection, by Luca Tettamanti. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3129 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/vl.c b/vl.c index bfdf5204f..a5c1ce64e 100644 --- a/vl.c +++ b/vl.c @@ -835,6 +835,71 @@ static struct qemu_alarm_timer alarm_timers[] = { {NULL, } }; +static void show_available_alarms() +{ + int i; + + printf("Available alarm timers, in order of precedence:\n"); + for (i = 0; alarm_timers[i].name; i++) + printf("%s\n", alarm_timers[i].name); +} + +static void configure_alarms(char const *opt) +{ + int i; + int cur = 0; + int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1; + char *arg; + char *name; + + if (!strcmp(opt, "help")) { + show_available_alarms(); + exit(0); + } + + arg = strdup(opt); + + /* Reorder the array */ + name = strtok(arg, ","); + while (name) { + struct qemu_alarm_timer tmp; + + for (i = 0; i < count; i++) { + if (!strcmp(alarm_timers[i].name, name)) + break; + } + + if (i == count) { + fprintf(stderr, "Unknown clock %s\n", name); + goto next; + } + + if (i < cur) + /* Ignore */ + goto next; + + /* Swap */ + tmp = alarm_timers[i]; + alarm_timers[i] = alarm_timers[cur]; + alarm_timers[cur] = tmp; + + cur++; +next: + name = strtok(NULL, ","); + } + + free(arg); + + if (cur) { + /* Disable remaining timers */ + for (i = cur; i < count; i++) + alarm_timers[i].name = NULL; + } + + /* debug */ + show_available_alarms(); +} + QEMUClock *rt_clock; QEMUClock *vm_clock; @@ -6846,6 +6911,8 @@ static void help(int exitcode) #ifdef TARGET_SPARC "-prom-env variable=value set OpenBIOS nvram variables\n" #endif + "-clock force the use of the given methods for timer alarm.\n" + " To see what timers are available use -clock help\n" "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -6943,6 +7010,7 @@ enum { QEMU_OPTION_name, QEMU_OPTION_prom_env, QEMU_OPTION_old_param, + QEMU_OPTION_clock, }; typedef struct QEMUOption { @@ -7047,6 +7115,7 @@ const QEMUOption qemu_options[] = { #if defined(TARGET_ARM) { "old-param", 0, QEMU_OPTION_old_param }, #endif + { "clock", HAS_ARG, QEMU_OPTION_clock }, { NULL }, }; @@ -7826,6 +7895,9 @@ int main(int argc, char **argv) case QEMU_OPTION_old_param: old_param = 1; #endif + case QEMU_OPTION_clock: + configure_alarms(optarg); + break; } } } -- cgit v1.2.3 From efe75411ec7113294810ca7abc52ac400505e96d Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 24 Aug 2007 01:36:32 +0000 Subject: Add support for dynamic ticks, by Luca Tettamanti and Dan Kenigsberg. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3130 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 177 insertions(+), 8 deletions(-) diff --git a/vl.c b/vl.c index a5c1ce64e..cfeea7269 100644 --- a/vl.c +++ b/vl.c @@ -784,12 +784,32 @@ struct QEMUTimer { struct qemu_alarm_timer { char const *name; + unsigned int flags; int (*start)(struct qemu_alarm_timer *t); void (*stop)(struct qemu_alarm_timer *t); + void (*rearm)(struct qemu_alarm_timer *t); void *priv; }; +#define ALARM_FLAG_DYNTICKS 0x1 + +static inline int alarm_has_dynticks(struct qemu_alarm_timer *t) +{ + return t->flags & ALARM_FLAG_DYNTICKS; +} + +static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) +{ + if (!alarm_has_dynticks(t)) + return; + + t->rearm(t); +} + +/* TODO: MIN_TIMER_REARM_US should be optimized */ +#define MIN_TIMER_REARM_US 250 + static struct qemu_alarm_timer *alarm_timer; #ifdef _WIN32 @@ -802,12 +822,17 @@ struct qemu_alarm_win32 { static int win32_start_timer(struct qemu_alarm_timer *t); static void win32_stop_timer(struct qemu_alarm_timer *t); +static void win32_rearm_timer(struct qemu_alarm_timer *t); #else static int unix_start_timer(struct qemu_alarm_timer *t); static void unix_stop_timer(struct qemu_alarm_timer *t); +static int dynticks_start_timer(struct qemu_alarm_timer *t); +static void dynticks_stop_timer(struct qemu_alarm_timer *t); +static void dynticks_rearm_timer(struct qemu_alarm_timer *t); + #ifdef __linux__ static int hpet_start_timer(struct qemu_alarm_timer *t); @@ -816,21 +841,26 @@ static void hpet_stop_timer(struct qemu_alarm_timer *t); static int rtc_start_timer(struct qemu_alarm_timer *t); static void rtc_stop_timer(struct qemu_alarm_timer *t); -#endif +#endif /* __linux__ */ #endif /* _WIN32 */ static struct qemu_alarm_timer alarm_timers[] = { +#ifndef _WIN32 + {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer, + dynticks_stop_timer, dynticks_rearm_timer, NULL}, #ifdef __linux__ /* HPET - if available - is preferred */ - {"hpet", hpet_start_timer, hpet_stop_timer, NULL}, + {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL}, /* ...otherwise try RTC */ - {"rtc", rtc_start_timer, rtc_stop_timer, NULL}, + {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL}, #endif -#ifndef _WIN32 - {"unix", unix_start_timer, unix_stop_timer, NULL}, + {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL}, #else - {"win32", win32_start_timer, win32_stop_timer, &alarm_win32_data}, + {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer, + win32_stop_timer, win32_rearm_timer, &alarm_win32_data}, + {"win32", 0, win32_start_timer, + win32_stop_timer, NULL, &alarm_win32_data}, #endif {NULL, } }; @@ -949,6 +979,8 @@ void qemu_del_timer(QEMUTimer *ts) } pt = &t->next; } + + qemu_rearm_alarm_timer(alarm_timer); } /* modify the current timer so that it will be fired when current_time @@ -1008,6 +1040,7 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); } + qemu_rearm_alarm_timer(alarm_timer); } int64_t qemu_get_clock(QEMUClock *clock) @@ -1115,7 +1148,8 @@ static void host_alarm_handler(int host_signum) last_clock = ti; } #endif - if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], + if (alarm_has_dynticks(alarm_timer) || + qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { @@ -1136,6 +1170,30 @@ static void host_alarm_handler(int host_signum) } } +static uint64_t qemu_next_deadline(void) +{ + int64_t nearest_delta_us = ULLONG_MAX; + int64_t vmdelta_us; + + if (active_timers[QEMU_TIMER_REALTIME]) + nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - + qemu_get_clock(rt_clock))*1000; + + if (active_timers[QEMU_TIMER_VIRTUAL]) { + /* round up */ + vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - + qemu_get_clock(vm_clock)+999)/1000; + if (vmdelta_us < nearest_delta_us) + nearest_delta_us = vmdelta_us; + } + + /* Avoid arming the timer to negative, zero, or too low values */ + if (nearest_delta_us <= MIN_TIMER_REARM_US) + nearest_delta_us = MIN_TIMER_REARM_US; + + return nearest_delta_us; +} + #ifndef _WIN32 #if defined(__linux__) @@ -1243,6 +1301,80 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t) #endif /* !defined(__linux__) */ +static int dynticks_start_timer(struct qemu_alarm_timer *t) +{ + struct sigevent ev; + timer_t host_timer; + struct sigaction act; + + sigfillset(&act.sa_mask); + act.sa_flags = 0; +#if defined(TARGET_I386) && defined(USE_CODE_COPY) + act.sa_flags |= SA_ONSTACK; +#endif + act.sa_handler = host_alarm_handler; + + sigaction(SIGALRM, &act, NULL); + + ev.sigev_value.sival_int = 0; + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGALRM; + + if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { + perror("timer_create"); + + /* disable dynticks */ + fprintf(stderr, "Dynamic Ticks disabled\n"); + + return -1; + } + + t->priv = (void *)host_timer; + + return 0; +} + +static void dynticks_stop_timer(struct qemu_alarm_timer *t) +{ + timer_t host_timer = (timer_t)t->priv; + + timer_delete(host_timer); +} + +static void dynticks_rearm_timer(struct qemu_alarm_timer *t) +{ + timer_t host_timer = (timer_t)t->priv; + struct itimerspec timeout; + int64_t nearest_delta_us = INT64_MAX; + int64_t current_us; + + if (!active_timers[QEMU_TIMER_REALTIME] && + !active_timers[QEMU_TIMER_VIRTUAL]) + return; + + nearest_delta_us = qemu_next_deadline(); + + /* check whether a timer is already running */ + if (timer_gettime(host_timer, &timeout)) { + perror("gettime"); + fprintf(stderr, "Internal timer error: aborting\n"); + exit(1); + } + current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; + if (current_us && current_us <= nearest_delta_us) + return; + + timeout.it_interval.tv_sec = 0; + timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ + timeout.it_value.tv_sec = nearest_delta_us / 1000000; + timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000; + if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { + perror("settime"); + fprintf(stderr, "Internal timer error: aborting\n"); + exit(1); + } +} + static int unix_start_timer(struct qemu_alarm_timer *t) { struct sigaction act; @@ -1288,6 +1420,7 @@ static int win32_start_timer(struct qemu_alarm_timer *t) { TIMECAPS tc; struct qemu_alarm_win32 *data = t->priv; + UINT flags; data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); if (!data->host_alarm) { @@ -1303,11 +1436,17 @@ static int win32_start_timer(struct qemu_alarm_timer *t) timeBeginPeriod(data->period); + flags = TIME_CALLBACK_FUNCTION; + if (alarm_has_dynticks(t)) + flags |= TIME_ONESHOT; + else + flags |= TIME_PERIODIC; + data->timerId = timeSetEvent(1, // interval (ms) data->period, // resolution host_alarm_handler, // function (DWORD)t, // parameter - TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + flags); if (!data->timerId) { perror("Failed to initialize win32 alarm timer"); @@ -1332,6 +1471,35 @@ static void win32_stop_timer(struct qemu_alarm_timer *t) CloseHandle(data->host_alarm); } +static void win32_rearm_timer(struct qemu_alarm_timer *t) +{ + struct qemu_alarm_win32 *data = t->priv; + uint64_t nearest_delta_us; + + if (!active_timers[QEMU_TIMER_REALTIME] && + !active_timers[QEMU_TIMER_VIRTUAL]) + return; + + nearest_delta_us = qemu_next_deadline(); + nearest_delta_us /= 1000; + + timeKillEvent(data->timerId); + + data->timerId = timeSetEvent(1, + data->period, + host_alarm_handler, + (DWORD)t, + TIME_ONESHOT | TIME_PERIODIC); + + if (!data->timerId) { + perror("Failed to re-arm win32 alarm timer"); + + timeEndPeriod(data->period); + CloseHandle(data->host_alarm); + exit(1); + } +} + #endif /* _WIN32 */ static void init_timer_alarm(void) @@ -6490,6 +6658,7 @@ void vm_start(void) cpu_enable_ticks(); vm_running = 1; vm_state_notify(1); + qemu_rearm_alarm_timer(alarm_timer); } } -- cgit v1.2.3 From 70f23b776a22e341443e8ae015627a4e041d662b Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 24 Aug 2007 01:46:56 +0000 Subject: De-noise startup. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3131 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/vl.c b/vl.c index cfeea7269..9bcffc013 100644 --- a/vl.c +++ b/vl.c @@ -1510,8 +1510,6 @@ static void init_timer_alarm(void) for (i = 0; alarm_timers[i].name; i++) { t = &alarm_timers[i]; - printf("trying %s...\n", t->name); - err = t->start(t); if (!err) break; -- cgit v1.2.3 From 6ab43fdc31e25b114eec1f3ee25264b5f6a1a0f3 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:34:19 +0000 Subject: Avoid SEGV in IOHandler dispatch, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3132 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/vl.c b/vl.c index 9bcffc013..9009ce588 100644 --- a/vl.c +++ b/vl.c @@ -6823,12 +6823,10 @@ void main_loop_wait(int timeout) IOHandlerRecord **pioh; for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { - if (ioh->deleted) - continue; - if (FD_ISSET(ioh->fd, &rfds)) { + if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) { ioh->fd_read(ioh->opaque); } - if (FD_ISSET(ioh->fd, &wfds)) { + if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) { ioh->fd_write(ioh->opaque); } } -- cgit v1.2.3 From 71cab5ca0d9f10cf9f07eaf3033687bf85459d52 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:35:38 +0000 Subject: Refactor VNC server setup API, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3133 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 4 ++- vl.h | 4 ++- vnc.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 82 insertions(+), 29 deletions(-) diff --git a/vl.c b/vl.c index 9009ce588..3c8070e34 100644 --- a/vl.c +++ b/vl.c @@ -8319,7 +8319,9 @@ int main(int argc, char **argv) /* nearly nothing to do */ dumb_display_init(ds); } else if (vnc_display != NULL) { - vnc_display_init(ds, vnc_display); + vnc_display_init(ds); + if (vnc_display_open(ds, vnc_display) < 0) + exit(1); } else { #if defined(CONFIG_SDL) sdl_display_init(ds, full_screen, no_frame); diff --git a/vl.h b/vl.h index e12b6f3e7..53e822fd9 100644 --- a/vl.h +++ b/vl.h @@ -967,7 +967,9 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); void cocoa_display_init(DisplayState *ds, int full_screen); /* vnc.c */ -void vnc_display_init(DisplayState *ds, const char *display); +void vnc_display_init(DisplayState *ds); +void vnc_display_close(DisplayState *ds); +int vnc_display_open(DisplayState *ds, const char *display); void do_info_vnc(void); /* x_keymap.c */ diff --git a/vnc.c b/vnc.c index 70d30d9d8..f47b5b96b 100644 --- a/vnc.c +++ b/vnc.c @@ -73,7 +73,7 @@ struct VncState int last_x; int last_y; - const char *display; + char *display; Buffer output; Buffer input; @@ -1169,16 +1169,8 @@ static void vnc_listen_read(void *opaque) extern int parse_host_port(struct sockaddr_in *saddr, const char *str); -void vnc_display_init(DisplayState *ds, const char *arg) +void vnc_display_init(DisplayState *ds) { - struct sockaddr *addr; - struct sockaddr_in iaddr; -#ifndef _WIN32 - struct sockaddr_un uaddr; -#endif - int reuse_addr, ret; - socklen_t addrlen; - const char *p; VncState *vs; vs = qemu_mallocz(sizeof(VncState)); @@ -1187,7 +1179,7 @@ void vnc_display_init(DisplayState *ds, const char *arg) ds->opaque = vs; vnc_state = vs; - vs->display = arg; + vs->display = NULL; vs->lsock = -1; vs->csock = -1; @@ -1212,7 +1204,49 @@ void vnc_display_init(DisplayState *ds, const char *arg) memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); vnc_dpy_resize(vs->ds, 640, 400); +} + +void vnc_display_close(DisplayState *ds) +{ + VncState *vs = (VncState *)ds->opaque; + + if (vs->display) { + qemu_free(vs->display); + vs->display = NULL; + } + if (vs->lsock != -1) { + qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL); + close(vs->lsock); + vs->lsock = -1; + } + if (vs->csock != -1) { + qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); + closesocket(vs->csock); + vs->csock = -1; + buffer_reset(&vs->input); + buffer_reset(&vs->output); + vs->need_update = 0; + } +} + +int vnc_display_open(DisplayState *ds, const char *arg) +{ + struct sockaddr *addr; + struct sockaddr_in iaddr; +#ifndef _WIN32 + struct sockaddr_un uaddr; +#endif + int reuse_addr, ret; + socklen_t addrlen; + const char *p; + VncState *vs = (VncState *)ds->opaque; + + vnc_display_close(ds); + if (strcmp(arg, "none") == 0) + return 0; + if (!(vs->display = strdup(arg))) + return -1; #ifndef _WIN32 if (strstart(arg, "unix:", &p)) { addr = (struct sockaddr *)&uaddr; @@ -1221,7 +1255,9 @@ void vnc_display_init(DisplayState *ds, const char *arg) vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0); if (vs->lsock == -1) { fprintf(stderr, "Could not create socket\n"); - exit(1); + free(vs->display); + vs->display = NULL; + return -1; } uaddr.sun_family = AF_UNIX; @@ -1235,40 +1271,53 @@ void vnc_display_init(DisplayState *ds, const char *arg) addr = (struct sockaddr *)&iaddr; addrlen = sizeof(iaddr); - vs->lsock = socket(PF_INET, SOCK_STREAM, 0); - if (vs->lsock == -1) { - fprintf(stderr, "Could not create socket\n"); - exit(1); - } - if (parse_host_port(&iaddr, arg) < 0) { fprintf(stderr, "Could not parse VNC address\n"); - exit(1); + free(vs->display); + vs->display = NULL; + return -1; } - + iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900); + vs->lsock = socket(PF_INET, SOCK_STREAM, 0); + if (vs->lsock == -1) { + fprintf(stderr, "Could not create socket\n"); + free(vs->display); + vs->display = NULL; + return -1; + } + reuse_addr = 1; ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_addr, sizeof(reuse_addr)); if (ret == -1) { fprintf(stderr, "setsockopt() failed\n"); - exit(1); + close(vs->lsock); + vs->lsock = -1; + free(vs->display); + vs->display = NULL; + return -1; } } if (bind(vs->lsock, addr, addrlen) == -1) { fprintf(stderr, "bind() failed\n"); - exit(1); + close(vs->lsock); + vs->lsock = -1; + free(vs->display); + vs->display = NULL; + return -1; } if (listen(vs->lsock, 1) == -1) { fprintf(stderr, "listen() failed\n"); - exit(1); + close(vs->lsock); + vs->lsock = -1; + free(vs->display); + vs->display = NULL; + return -1; } - ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); - if (ret == -1) { - exit(1); - } + return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); } -- cgit v1.2.3 From e25a5822ca2dfd229471cc5d02458956b1bf0fa8 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:36:20 +0000 Subject: Extend monitor 'change' command for VNC, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3134 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 17 ++++++++++++++++- vnc.c | 4 ++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index ed31d5031..65668fda0 100644 --- a/monitor.c +++ b/monitor.c @@ -386,7 +386,7 @@ static void do_eject(int force, const char *filename) eject_device(bs, force); } -static void do_change(const char *device, const char *filename) +static void do_change_block(const char *device, const char *filename) { BlockDriverState *bs; @@ -401,6 +401,21 @@ static void do_change(const char *device, const char *filename) qemu_key_check(bs, filename); } +static void do_change_vnc(const char *target) +{ + if (vnc_display_open(NULL, target) < 0) + term_printf("could not start VNC server on %s\n", target); +} + +static void do_change(const char *device, const char *target) +{ + if (strcmp(device, "vnc") == 0) { + do_change_vnc(target); + } else { + do_change_block(device, target); + } +} + static void do_screen_dump(const char *filename) { vga_hw_screen_dump(filename); diff --git a/vnc.c b/vnc.c index f47b5b96b..a5ed107e9 100644 --- a/vnc.c +++ b/vnc.c @@ -1208,7 +1208,7 @@ void vnc_display_init(DisplayState *ds) void vnc_display_close(DisplayState *ds) { - VncState *vs = (VncState *)ds->opaque; + VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; if (vs->display) { qemu_free(vs->display); @@ -1239,7 +1239,7 @@ int vnc_display_open(DisplayState *ds, const char *arg) int reuse_addr, ret; socklen_t addrlen; const char *p; - VncState *vs = (VncState *)ds->opaque; + VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; vnc_display_close(ds); if (strcmp(arg, "none") == 0) -- cgit v1.2.3 From 7084851534c834f00652f90a9da5e4032bd22130 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:37:05 +0000 Subject: VNC password authentication, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3135 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- monitor.c | 13 +++- vl.h | 1 + vnc.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 239 insertions(+), 17 deletions(-) diff --git a/Makefile.target b/Makefile.target index 915b8a97b..1f8f55f86 100644 --- a/Makefile.target +++ b/Makefile.target @@ -482,7 +482,7 @@ endif ifdef CONFIG_SDL VL_OBJS+=sdl.o x_keymap.o endif -VL_OBJS+=vnc.o +VL_OBJS+=vnc.o d3des.o ifdef CONFIG_COCOA VL_OBJS+=cocoa.o COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit @@ -543,7 +543,7 @@ cocoa.o: cocoa.m 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 +vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< sdlaudio.o: sdlaudio.c diff --git a/monitor.c b/monitor.c index 65668fda0..3b9408b55 100644 --- a/monitor.c +++ b/monitor.c @@ -403,8 +403,17 @@ static void do_change_block(const char *device, const char *filename) static void do_change_vnc(const char *target) { - if (vnc_display_open(NULL, target) < 0) - term_printf("could not start VNC server on %s\n", target); + if (strcmp(target, "passwd") == 0 || + strcmp(target, "password") == 0) { + char password[9]; + monitor_readline("Password: ", 1, password, sizeof(password)-1); + password[sizeof(password)-1] = '\0'; + if (vnc_display_password(NULL, password) < 0) + term_printf("could not set VNC server password\n"); + } else { + if (vnc_display_open(NULL, target) < 0) + term_printf("could not start VNC server on %s\n", target); + } } static void do_change(const char *device, const char *target) diff --git a/vl.h b/vl.h index 53e822fd9..e72df0e69 100644 --- a/vl.h +++ b/vl.h @@ -970,6 +970,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen); void vnc_display_init(DisplayState *ds); void vnc_display_close(DisplayState *ds); int vnc_display_open(DisplayState *ds, const char *display); +int vnc_display_password(DisplayState *ds, const char *password); void do_info_vnc(void); /* x_keymap.c */ diff --git a/vnc.c b/vnc.c index a5ed107e9..742ce9f24 100644 --- a/vnc.c +++ b/vnc.c @@ -30,6 +30,15 @@ #include "vnc_keysym.h" #include "keymaps.c" +#include "d3des.h" + +// #define _VNC_DEBUG + +#ifdef _VNC_DEBUG +#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define VNC_DEBUG(fmt, ...) do { } while (0) +#endif typedef struct Buffer { @@ -54,6 +63,20 @@ typedef void VncSendHextileTile(VncState *vs, #define VNC_MAX_HEIGHT 2048 #define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32)) +#define VNC_AUTH_CHALLENGE_SIZE 16 + +enum { + VNC_AUTH_INVALID = 0, + VNC_AUTH_NONE = 1, + VNC_AUTH_VNC = 2, + VNC_AUTH_RA2 = 5, + VNC_AUTH_RA2NE = 6, + VNC_AUTH_TIGHT = 16, + VNC_AUTH_ULTRA = 17, + VNC_AUTH_TLS = 18, + VNC_AUTH_VENCRYPT = 19 +}; + struct VncState { QEMUTimer *timer; @@ -73,7 +96,13 @@ struct VncState int last_x; int last_y; + int major; + int minor; + char *display; + char *password; + int auth; + char challenge[VNC_AUTH_CHALLENGE_SIZE]; Buffer output; Buffer input; @@ -1125,23 +1154,171 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) return 0; } +static void make_challenge(VncState *vs) +{ + int i; + + srand(time(NULL)+getpid()+getpid()*987654+rand()); + + for (i = 0 ; i < sizeof(vs->challenge) ; i++) + vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0)); +} + +static int protocol_client_auth_vnc(VncState *vs, char *data, size_t len) +{ + char response[VNC_AUTH_CHALLENGE_SIZE]; + int i, j, pwlen; + char key[8]; + + if (!vs->password || !vs->password[0]) { + VNC_DEBUG("No password configured on server"); + vnc_write_u32(vs, 1); /* Reject auth */ + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_flush(vs); + vnc_client_error(vs); + return 0; + } + + memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE); + + /* Calculate the expected challenge response */ + pwlen = strlen(vs->password); + for (i=0; ipassword[i] : 0; + deskey(key, EN0); + for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8) + des(response+j, response+j); + + /* Compare expected vs actual challenge response */ + if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) { + VNC_DEBUG("Client challenge reponse did not match\n"); + vnc_write_u32(vs, 1); /* Reject auth */ + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_flush(vs); + vnc_client_error(vs); + } else { + VNC_DEBUG("Accepting VNC challenge response\n"); + vnc_write_u32(vs, 0); /* Accept auth */ + vnc_flush(vs); + + vnc_read_when(vs, protocol_client_init, 1); + } + return 0; +} + +static int start_auth_vnc(VncState *vs) +{ + make_challenge(vs); + /* Send client a 'random' challenge */ + vnc_write(vs, vs->challenge, sizeof(vs->challenge)); + vnc_flush(vs); + + vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge)); + return 0; +} + +static int protocol_client_auth(VncState *vs, char *data, size_t len) +{ + /* We only advertise 1 auth scheme at a time, so client + * must pick the one we sent. Verify this */ + if (data[0] != vs->auth) { /* Reject auth */ + VNC_DEBUG("Reject auth %d\n", (int)data[0]); + vnc_write_u32(vs, 1); + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_client_error(vs); + } else { /* Accept requested auth */ + VNC_DEBUG("Client requested auth %d\n", (int)data[0]); + switch (vs->auth) { + case VNC_AUTH_NONE: + VNC_DEBUG("Accept auth none\n"); + vnc_write_u32(vs, 0); /* Accept auth completion */ + vnc_read_when(vs, protocol_client_init, 1); + break; + + case VNC_AUTH_VNC: + VNC_DEBUG("Start VNC auth\n"); + return start_auth_vnc(vs); + + default: /* Should not be possible, but just in case */ + VNC_DEBUG("Reject auth %d\n", vs->auth); + vnc_write_u8(vs, 1); + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_client_error(vs); + } + } + return 0; +} + static int protocol_version(VncState *vs, char *version, size_t len) { char local[13]; - int maj, min; memcpy(local, version, 12); local[12] = 0; - if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) { + if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) { + VNC_DEBUG("Malformed protocol version %s\n", local); vnc_client_error(vs); return 0; } - - vnc_write_u32(vs, 1); /* None */ - vnc_flush(vs); - - vnc_read_when(vs, protocol_client_init, 1); + VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor); + if (vs->major != 3 || + (vs->minor != 3 && + vs->minor != 5 && + vs->minor != 7 && + vs->minor != 8)) { + VNC_DEBUG("Unsupported client version\n"); + vnc_write_u32(vs, VNC_AUTH_INVALID); + vnc_flush(vs); + vnc_client_error(vs); + return 0; + } + /* Some broken client report v3.5 which spec requires to be treated + * as equivalent to v3.3 by servers + */ + if (vs->minor == 5) + vs->minor = 3; + + if (vs->minor == 3) { + if (vs->auth == VNC_AUTH_NONE) { + VNC_DEBUG("Tell client auth none\n"); + vnc_write_u32(vs, vs->auth); + vnc_flush(vs); + vnc_read_when(vs, protocol_client_init, 1); + } else if (vs->auth == VNC_AUTH_VNC) { + VNC_DEBUG("Tell client VNC auth\n"); + vnc_write_u32(vs, vs->auth); + vnc_flush(vs); + start_auth_vnc(vs); + } else { + VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth); + vnc_write_u32(vs, VNC_AUTH_INVALID); + vnc_flush(vs); + vnc_client_error(vs); + } + } else { + VNC_DEBUG("Telling client we support auth %d\n", vs->auth); + vnc_write_u8(vs, 1); /* num auth */ + vnc_write_u8(vs, vs->auth); + vnc_read_when(vs, protocol_client_auth, 1); + vnc_flush(vs); + } return 0; } @@ -1156,7 +1333,7 @@ static void vnc_listen_read(void *opaque) if (vs->csock != -1) { socket_set_nonblock(vs->csock); qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); - vnc_write(vs, "RFB 003.003\n", 12); + vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height); @@ -1180,6 +1357,7 @@ void vnc_display_init(DisplayState *ds) ds->opaque = vs; vnc_state = vs; vs->display = NULL; + vs->password = NULL; vs->lsock = -1; vs->csock = -1; @@ -1227,9 +1405,26 @@ void vnc_display_close(DisplayState *ds) buffer_reset(&vs->output); vs->need_update = 0; } + vs->auth = VNC_AUTH_INVALID; +} + +int vnc_display_password(DisplayState *ds, const char *password) +{ + VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; + + if (vs->password) { + qemu_free(vs->password); + vs->password = NULL; + } + if (password && password[0]) { + if (!(vs->password = qemu_strdup(password))) + return -1; + } + + return 0; } -int vnc_display_open(DisplayState *ds, const char *arg) +int vnc_display_open(DisplayState *ds, const char *display) { struct sockaddr *addr; struct sockaddr_in iaddr; @@ -1240,15 +1435,32 @@ int vnc_display_open(DisplayState *ds, const char *arg) socklen_t addrlen; const char *p; VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; + const char *options; + int password = 0; vnc_display_close(ds); - if (strcmp(arg, "none") == 0) + if (strcmp(display, "none") == 0) return 0; - if (!(vs->display = strdup(arg))) + if (!(vs->display = strdup(display))) return -1; + + options = display; + while ((options = strchr(options, ','))) { + options++; + if (strncmp(options, "password", 8) == 0) + password = 1; /* Require password auth */ + } + + if (password) { + VNC_DEBUG("Initializing VNC server with password auth\n"); + vs->auth = VNC_AUTH_VNC; + } else { + VNC_DEBUG("Initializing VNC server with no auth\n"); + vs->auth = VNC_AUTH_NONE; + } #ifndef _WIN32 - if (strstart(arg, "unix:", &p)) { + if (strstart(display, "unix:", &p)) { addr = (struct sockaddr *)&uaddr; addrlen = sizeof(uaddr); @@ -1271,7 +1483,7 @@ int vnc_display_open(DisplayState *ds, const char *arg) addr = (struct sockaddr *)&iaddr; addrlen = sizeof(iaddr); - if (parse_host_port(&iaddr, arg) < 0) { + if (parse_host_port(&iaddr, display) < 0) { fprintf(stderr, "Could not parse VNC address\n"); free(vs->display); vs->display = NULL; -- cgit v1.2.3 From 8d5d2d4c478c6a853b7334f06253ab73410e9322 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:37:51 +0000 Subject: VeNCrypt basic TLS support, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3136 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 5 + configure | 25 ++++ vnc.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 426 insertions(+), 8 deletions(-) diff --git a/Makefile.target b/Makefile.target index 1f8f55f86..d1204d678 100644 --- a/Makefile.target +++ b/Makefile.target @@ -405,6 +405,11 @@ SOUND_HW += fmopl.o adlib.o endif AUDIODRV+= wavcapture.o +ifdef CONFIG_VNC_TLS +CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS) +LIBS += $(CONFIG_VNC_TLS_LIBS) +endif + VL_OBJS += i2c.o smbus.o # SCSI layer diff --git a/configure b/configure index 0f959b7d0..7ee710a8b 100755 --- a/configure +++ b/configure @@ -89,6 +89,7 @@ alsa="no" fmod="no" fmod_lib="" fmod_inc="" +vnc_tls="yes" bsd="no" linux="no" kqemu="no" @@ -252,6 +253,8 @@ for opt do ;; --fmod-inc=*) fmod_inc="$optarg" ;; + --disable-vnc-tls) vnc_tls="no" + ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; linux_user="no" ;; --disable-slirp) slirp="no" @@ -362,6 +365,7 @@ echo " --enable-coreaudio enable Coreaudio audio driver" echo " --enable-alsa enable ALSA audio driver" echo " --enable-fmod enable FMOD audio driver" echo " --enable-dsound enable DirectSound audio driver" +echo " --disable-vnc-tls disable TLS encryption for VNC server" echo " --enable-system enable all system emulation targets" echo " --disable-system disable all system emulation targets" echo " --enable-linux-user enable all linux usermode emulation targets" @@ -588,6 +592,16 @@ else fi fi # -z $sdl +########################################## +# VNC TLS detection +if test "$vnc_tls" = "yes" ; then + `pkg-config gnutls` || vnc_tls="no" +fi +if test "$vnc_tls" = "yes" ; then + vnc_tls_cflags=`pkg-config --cflags gnutls` + vnc_tls_libs=`pkg-config --libs gnutls` +fi + ########################################## # alsa sound support libraries @@ -675,6 +689,11 @@ else fi echo "FMOD support $fmod $fmod_support" echo "OSS support $oss" +echo "VNC TLS support $vnc_tls" +if test "$vnc_tls" = "yes" ; then + echo " TLS CFLAGS $vnc_tls_cflags" + echo " TLS LIBS $vnc_tls_libs" +fi if test -n "$sparc_cpu"; then echo "Target Sparc Arch $sparc_cpu" fi @@ -847,6 +866,12 @@ if test "$fmod" = "yes" ; then echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak echo "#define CONFIG_FMOD 1" >> $config_h fi +if test "$vnc_tls" = "yes" ; then + echo "CONFIG_VNC_TLS=yes" >> $config_mak + echo "CONFIG_VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_mak + echo "CONFIG_VNC_TLS_LIBS=$vnc_tls_libs" >> $config_mak + echo "#define CONFIG_VNC_TLS 1" >> $config_h +fi qemu_version=`head $source_path/VERSION` echo "VERSION=$qemu_version" >>$config_mak echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h diff --git a/vnc.c b/vnc.c index 742ce9f24..b1f62cac7 100644 --- a/vnc.c +++ b/vnc.c @@ -32,14 +32,27 @@ #include "keymaps.c" #include "d3des.h" -// #define _VNC_DEBUG +#if CONFIG_VNC_TLS +#include +#include +#endif /* CONFIG_VNC_TLS */ -#ifdef _VNC_DEBUG +// #define _VNC_DEBUG 1 + +#if _VNC_DEBUG #define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) + +#if CONFIG_VNC_TLS && _VNC_DEBUG >= 2 +/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */ +static void vnc_debug_gnutls_log(int level, const char* str) { + VNC_DEBUG("%d %s", level, str); +} +#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */ #else #define VNC_DEBUG(fmt, ...) do { } while (0) #endif + typedef struct Buffer { size_t capacity; @@ -77,6 +90,23 @@ enum { VNC_AUTH_VENCRYPT = 19 }; +#if CONFIG_VNC_TLS +enum { + VNC_WIREMODE_CLEAR, + VNC_WIREMODE_TLS, +}; + +enum { + VNC_AUTH_VENCRYPT_PLAIN = 256, + VNC_AUTH_VENCRYPT_TLSNONE = 257, + VNC_AUTH_VENCRYPT_TLSVNC = 258, + VNC_AUTH_VENCRYPT_TLSPLAIN = 259, + VNC_AUTH_VENCRYPT_X509NONE = 260, + VNC_AUTH_VENCRYPT_X509VNC = 261, + VNC_AUTH_VENCRYPT_X509PLAIN = 262, +}; +#endif /* CONFIG_VNC_TLS */ + struct VncState { QEMUTimer *timer; @@ -102,8 +132,16 @@ struct VncState char *display; char *password; int auth; +#if CONFIG_VNC_TLS + int subauth; +#endif char challenge[VNC_AUTH_CHALLENGE_SIZE]; +#if CONFIG_VNC_TLS + int wiremode; + gnutls_session_t tls_session; +#endif + Buffer output; Buffer input; kbd_layout_t *kbd_layout; @@ -579,12 +617,20 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno) if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN)) return 0; + VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0); qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); closesocket(vs->csock); vs->csock = -1; buffer_reset(&vs->input); buffer_reset(&vs->output); vs->need_update = 0; +#if CONFIG_VNC_TLS + if (vs->tls_session) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + } + vs->wiremode = VNC_WIREMODE_CLEAR; +#endif /* CONFIG_VNC_TLS */ return 0; } return ret; @@ -600,7 +646,19 @@ static void vnc_client_write(void *opaque) long ret; VncState *vs = opaque; - ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); +#if CONFIG_VNC_TLS + if (vs->tls_session) { + ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset); + if (ret < 0) { + if (ret == GNUTLS_E_AGAIN) + errno = EAGAIN; + else + errno = EIO; + ret = -1; + } + } else +#endif /* CONFIG_VNC_TLS */ + ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0); ret = vnc_client_io_error(vs, ret, socket_error()); if (!ret) return; @@ -626,7 +684,19 @@ static void vnc_client_read(void *opaque) buffer_reserve(&vs->input, 4096); - ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); +#if CONFIG_VNC_TLS + if (vs->tls_session) { + ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096); + if (ret < 0) { + if (ret == GNUTLS_E_AGAIN) + errno = EAGAIN; + else + errno = EIO; + ret = -1; + } + } else +#endif /* CONFIG_VNC_TLS */ + ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); ret = vnc_client_io_error(vs, ret, socket_error()); if (!ret) return; @@ -721,6 +791,41 @@ static uint32_t read_u32(uint8_t *data, size_t offset) (data[offset + 2] << 8) | data[offset + 3]); } +#if CONFIG_VNC_TLS +ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, + const void *data, + size_t len) { + struct VncState *vs = (struct VncState *)transport; + int ret; + + retry: + ret = send(vs->csock, data, len, 0); + if (ret < 0) { + if (errno == EINTR) + goto retry; + return -1; + } + return ret; +} + + +ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, + void *data, + size_t len) { + struct VncState *vs = (struct VncState *)transport; + int ret; + + retry: + ret = recv(vs->csock, data, len, 0); + if (ret < 0) { + if (errno == EINTR) + goto retry; + return -1; + } + return ret; +} +#endif /* CONFIG_VNC_TLS */ + static void client_cut_text(VncState *vs, size_t len, char *text) { } @@ -1225,6 +1330,243 @@ static int start_auth_vnc(VncState *vs) return 0; } + +#if CONFIG_VNC_TLS +#define DH_BITS 1024 +static gnutls_dh_params_t dh_params; + +static int vnc_tls_initialize(void) +{ + static int tlsinitialized = 0; + + if (tlsinitialized) + return 1; + + if (gnutls_global_init () < 0) + return 0; + + /* XXX ought to re-generate diffie-hellmen params periodically */ + if (gnutls_dh_params_init (&dh_params) < 0) + return 0; + if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) + return 0; + +#if _VNC_DEBUG == 2 + gnutls_global_set_log_level(10); + gnutls_global_set_log_function(vnc_debug_gnutls_log); +#endif + + tlsinitialized = 1; + + return 1; +} + +static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) +{ + gnutls_anon_server_credentials anon_cred; + int ret; + + if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) { + VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); + return NULL; + } + + gnutls_anon_set_server_dh_params(anon_cred, dh_params); + + return anon_cred; +} + + +static int start_auth_vencrypt_subauth(VncState *vs) +{ + switch (vs->subauth) { + case VNC_AUTH_VENCRYPT_TLSNONE: + VNC_DEBUG("Accept TLS auth none\n"); + vnc_write_u32(vs, 0); /* Accept auth completion */ + vnc_read_when(vs, protocol_client_init, 1); + break; + + case VNC_AUTH_VENCRYPT_TLSVNC: + VNC_DEBUG("Start TLS auth VNC\n"); + return start_auth_vnc(vs); + + default: /* Should not be possible, but just in case */ + VNC_DEBUG("Reject auth %d\n", vs->auth); + vnc_write_u8(vs, 1); + if (vs->minor >= 8) { + static const char err[] = "Unsupported authentication type"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_client_error(vs); + } + + return 0; +} + +static void vnc_handshake_io(void *opaque); + +static int vnc_continue_handshake(struct VncState *vs) { + int ret; + + if ((ret = gnutls_handshake(vs->tls_session)) < 0) { + if (!gnutls_error_is_fatal(ret)) { + VNC_DEBUG("Handshake interrupted (blocking)\n"); + if (!gnutls_record_get_direction(vs->tls_session)) + qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs); + else + qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs); + return 0; + } + VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret)); + vnc_client_error(vs); + return -1; + } + + VNC_DEBUG("Handshake done, switching to TLS data mode\n"); + vs->wiremode = VNC_WIREMODE_TLS; + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); + + return start_auth_vencrypt_subauth(vs); +} + +static void vnc_handshake_io(void *opaque) { + struct VncState *vs = (struct VncState *)opaque; + + VNC_DEBUG("Handshake IO continue\n"); + vnc_continue_handshake(vs); +} + +static int vnc_start_tls(struct VncState *vs) { + static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; + static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; + static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; + gnutls_anon_server_credentials anon_cred = NULL; + + VNC_DEBUG("Do TLS setup\n"); + if (vnc_tls_initialize() < 0) { + VNC_DEBUG("Failed to init TLS\n"); + vnc_client_error(vs); + return -1; + } + if (vs->tls_session == NULL) { + if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) { + vnc_client_error(vs); + return -1; + } + + if (gnutls_set_default_priority(vs->tls_session) < 0) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + vnc_client_error(vs); + return -1; + } + + if (gnutls_kx_set_priority(vs->tls_session, kx_anon) < 0) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + vnc_client_error(vs); + return -1; + } + + if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + vnc_client_error(vs); + return -1; + } + + if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + vnc_client_error(vs); + return -1; + } + + anon_cred = vnc_tls_initialize_anon_cred(); + if (!anon_cred) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + vnc_client_error(vs); + return -1; + } + if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + gnutls_anon_free_server_credentials(anon_cred); + vnc_client_error(vs); + return -1; + } + + gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs); + gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push); + gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull); + } + + VNC_DEBUG("Start TLS handshake process\n"); + return vnc_continue_handshake(vs); +} + +static int protocol_client_vencrypt_auth(VncState *vs, char *data, size_t len) +{ + int auth = read_u32(data, 0); + + if (auth != vs->subauth) { + VNC_DEBUG("Rejecting auth %d\n", auth); + vnc_write_u8(vs, 0); /* Reject auth */ + vnc_flush(vs); + vnc_client_error(vs); + } else { + VNC_DEBUG("Accepting auth %d, starting handshake\n", auth); + vnc_write_u8(vs, 1); /* Accept auth */ + vnc_flush(vs); + + if (vnc_start_tls(vs) < 0) { + VNC_DEBUG("Failed to complete TLS\n"); + return 0; + } + + if (vs->wiremode == VNC_WIREMODE_TLS) { + VNC_DEBUG("Starting VeNCrypt subauth\n"); + return start_auth_vencrypt_subauth(vs); + } else { + VNC_DEBUG("TLS handshake blocked\n"); + return 0; + } + } + return 0; +} + +static int protocol_client_vencrypt_init(VncState *vs, char *data, size_t len) +{ + if (data[0] != 0 || + data[1] != 2) { + VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); + vnc_write_u8(vs, 1); /* Reject version */ + vnc_flush(vs); + vnc_client_error(vs); + } else { + VNC_DEBUG("Sending allowed auth %d\n", vs->subauth); + vnc_write_u8(vs, 0); /* Accept version */ + vnc_write_u8(vs, 1); /* Number of sub-auths */ + vnc_write_u32(vs, vs->subauth); /* The supported auth */ + vnc_flush(vs); + vnc_read_when(vs, protocol_client_vencrypt_auth, 4); + } + return 0; +} + +static int start_auth_vencrypt(VncState *vs) +{ + /* Send VeNCrypt version 0.2 */ + vnc_write_u8(vs, 0); + vnc_write_u8(vs, 2); + + vnc_read_when(vs, protocol_client_vencrypt_init, 2); + return 0; +} +#endif /* CONFIG_VNC_TLS */ + static int protocol_client_auth(VncState *vs, char *data, size_t len) { /* We only advertise 1 auth scheme at a time, so client @@ -1251,6 +1593,12 @@ static int protocol_client_auth(VncState *vs, char *data, size_t len) VNC_DEBUG("Start VNC auth\n"); return start_auth_vnc(vs); +#if CONFIG_VNC_TLS + case VNC_AUTH_VENCRYPT: + VNC_DEBUG("Accept VeNCrypt auth\n");; + return start_auth_vencrypt(vs); +#endif /* CONFIG_VNC_TLS */ + default: /* Should not be possible, but just in case */ VNC_DEBUG("Reject auth %d\n", vs->auth); vnc_write_u8(vs, 1); @@ -1331,6 +1679,7 @@ static void vnc_listen_read(void *opaque) vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (vs->csock != -1) { + VNC_DEBUG("New client on socket %d\n", vs->csock); socket_set_nonblock(vs->csock); qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); vnc_write(vs, "RFB 003.008\n", 12); @@ -1404,8 +1753,18 @@ void vnc_display_close(DisplayState *ds) buffer_reset(&vs->input); buffer_reset(&vs->output); vs->need_update = 0; +#if CONFIG_VNC_TLS + if (vs->tls_session) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + } + vs->wiremode = VNC_WIREMODE_CLEAR; +#endif /* CONFIG_VNC_TLS */ } vs->auth = VNC_AUTH_INVALID; +#if CONFIG_VNC_TLS + vs->subauth = VNC_AUTH_INVALID; +#endif } int vnc_display_password(DisplayState *ds, const char *password) @@ -1437,6 +1796,9 @@ int vnc_display_open(DisplayState *ds, const char *display) VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; const char *options; int password = 0; +#if CONFIG_VNC_TLS + int tls = 0; +#endif vnc_display_close(ds); if (strcmp(display, "none") == 0) @@ -1450,14 +1812,40 @@ int vnc_display_open(DisplayState *ds, const char *display) options++; if (strncmp(options, "password", 8) == 0) password = 1; /* Require password auth */ +#if CONFIG_VNC_TLS + else if (strncmp(options, "tls", 3) == 0) + tls = 1; /* Require TLS */ +#endif } if (password) { - VNC_DEBUG("Initializing VNC server with password auth\n"); - vs->auth = VNC_AUTH_VNC; +#if CONFIG_VNC_TLS + if (tls) { + VNC_DEBUG("Initializing VNC server with TLS password auth\n"); + vs->auth = VNC_AUTH_VENCRYPT; + vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; + } else { +#endif + VNC_DEBUG("Initializing VNC server with password auth\n"); + vs->auth = VNC_AUTH_VNC; +#if CONFIG_VNC_TLS + vs->subauth = VNC_AUTH_INVALID; + } +#endif } else { - VNC_DEBUG("Initializing VNC server with no auth\n"); - vs->auth = VNC_AUTH_NONE; +#if CONFIG_VNC_TLS + if (tls) { + VNC_DEBUG("Initializing VNC server with TLS no auth\n"); + vs->auth = VNC_AUTH_VENCRYPT; + vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; + } else { +#endif + VNC_DEBUG("Initializing VNC server with no auth\n"); + vs->auth = VNC_AUTH_NONE; +#if CONFIG_VNC_TLS + vs->subauth = VNC_AUTH_INVALID; + } +#endif } #ifndef _WIN32 if (strstart(display, "unix:", &p)) { -- cgit v1.2.3 From 3a702699b26ba5116c153457d552c577383a9fa1 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:38:36 +0000 Subject: x509 certificate for server, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3137 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 107 insertions(+), 20 deletions(-) diff --git a/vnc.c b/vnc.c index b1f62cac7..901251988 100644 --- a/vnc.c +++ b/vnc.c @@ -105,6 +105,14 @@ enum { VNC_AUTH_VENCRYPT_X509VNC = 261, VNC_AUTH_VENCRYPT_X509PLAIN = 262, }; + +#if CONFIG_VNC_TLS +#define X509_CA_CERT_FILE "ca-cert.pem" +#define X509_CA_CRL_FILE "ca-crl.pem" +#define X509_SERVER_KEY_FILE "server-key.pem" +#define X509_SERVER_CERT_FILE "server-cert.pem" +#endif + #endif /* CONFIG_VNC_TLS */ struct VncState @@ -1377,16 +1385,60 @@ static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) } +static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(void) +{ + gnutls_certificate_credentials_t x509_cred; + int ret; + struct stat st; + + if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { + VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); + return NULL; + } + if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, X509_CA_CERT_FILE, GNUTLS_X509_FMT_PEM)) < 0) { + VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); + gnutls_certificate_free_credentials(x509_cred); + return NULL; + } + + if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, X509_SERVER_CERT_FILE, + X509_SERVER_KEY_FILE, + GNUTLS_X509_FMT_PEM)) < 0) { + VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); + gnutls_certificate_free_credentials(x509_cred); + return NULL; + } + + if (stat(X509_CA_CRL_FILE, &st) < 0) { + if (errno != ENOENT) { + gnutls_certificate_free_credentials(x509_cred); + return NULL; + } + } else { + if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, X509_CA_CRL_FILE, GNUTLS_X509_FMT_PEM)) < 0) { + VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); + gnutls_certificate_free_credentials(x509_cred); + return NULL; + } + } + + gnutls_certificate_set_dh_params (x509_cred, dh_params); + + return x509_cred; +} + static int start_auth_vencrypt_subauth(VncState *vs) { switch (vs->subauth) { case VNC_AUTH_VENCRYPT_TLSNONE: + case VNC_AUTH_VENCRYPT_X509NONE: VNC_DEBUG("Accept TLS auth none\n"); vnc_write_u32(vs, 0); /* Accept auth completion */ vnc_read_when(vs, protocol_client_init, 1); break; case VNC_AUTH_VENCRYPT_TLSVNC: + case VNC_AUTH_VENCRYPT_X509VNC: VNC_DEBUG("Start TLS auth VNC\n"); return start_auth_vnc(vs); @@ -1437,11 +1489,17 @@ static void vnc_handshake_io(void *opaque) { vnc_continue_handshake(vs); } +#define NEED_X509_AUTH(vs) \ + ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ + (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ + (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN) + + static int vnc_start_tls(struct VncState *vs) { static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 }; static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0}; - gnutls_anon_server_credentials anon_cred = NULL; + static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0}; VNC_DEBUG("Do TLS setup\n"); if (vnc_tls_initialize() < 0) { @@ -1462,7 +1520,7 @@ static int vnc_start_tls(struct VncState *vs) { return -1; } - if (gnutls_kx_set_priority(vs->tls_session, kx_anon) < 0) { + if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; vnc_client_error(vs); @@ -1483,19 +1541,36 @@ static int vnc_start_tls(struct VncState *vs) { return -1; } - anon_cred = vnc_tls_initialize_anon_cred(); - if (!anon_cred) { - gnutls_deinit(vs->tls_session); - vs->tls_session = NULL; - vnc_client_error(vs); - return -1; - } - if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { - gnutls_deinit(vs->tls_session); - vs->tls_session = NULL; - gnutls_anon_free_server_credentials(anon_cred); - vnc_client_error(vs); - return -1; + if (NEED_X509_AUTH(vs)) { + gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(); + if (!x509_cred) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + vnc_client_error(vs); + return -1; + } + if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + gnutls_certificate_free_credentials(x509_cred); + vnc_client_error(vs); + return -1; + } + } else { + gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); + if (!anon_cred) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + vnc_client_error(vs); + return -1; + } + if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) { + gnutls_deinit(vs->tls_session); + vs->tls_session = NULL; + gnutls_anon_free_server_credentials(anon_cred); + vnc_client_error(vs); + return -1; + } } gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs); @@ -1797,7 +1872,7 @@ int vnc_display_open(DisplayState *ds, const char *display) const char *options; int password = 0; #if CONFIG_VNC_TLS - int tls = 0; + int tls = 0, x509 = 0; #endif vnc_display_close(ds); @@ -1815,15 +1890,22 @@ int vnc_display_open(DisplayState *ds, const char *display) #if CONFIG_VNC_TLS else if (strncmp(options, "tls", 3) == 0) tls = 1; /* Require TLS */ + else if (strncmp(options, "x509", 4) == 0) + x509 = 1; /* Require x509 certificates */ #endif } if (password) { #if CONFIG_VNC_TLS if (tls) { - VNC_DEBUG("Initializing VNC server with TLS password auth\n"); vs->auth = VNC_AUTH_VENCRYPT; - vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; + if (x509) { + VNC_DEBUG("Initializing VNC server with x509 password auth\n"); + vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; + } else { + VNC_DEBUG("Initializing VNC server with TLS password auth\n"); + vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; + } } else { #endif VNC_DEBUG("Initializing VNC server with password auth\n"); @@ -1835,9 +1917,14 @@ int vnc_display_open(DisplayState *ds, const char *display) } else { #if CONFIG_VNC_TLS if (tls) { - VNC_DEBUG("Initializing VNC server with TLS no auth\n"); vs->auth = VNC_AUTH_VENCRYPT; - vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; + if (x509) { + VNC_DEBUG("Initializing VNC server with x509 no auth\n"); + vs->subauth = VNC_AUTH_VENCRYPT_X509NONE; + } else { + VNC_DEBUG("Initializing VNC server with TLS no auth\n"); + vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; + } } else { #endif VNC_DEBUG("Initializing VNC server with no auth\n"); -- cgit v1.2.3 From 469b15c68d0b9b00f5d2ab2a16ef5bcf46ca368f Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:39:10 +0000 Subject: x509 client certificate verification, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3138 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/vnc.c b/vnc.c index 901251988..3508a84e2 100644 --- a/vnc.c +++ b/vnc.c @@ -142,6 +142,7 @@ struct VncState int auth; #if CONFIG_VNC_TLS int subauth; + int x509verify; #endif char challenge[VNC_AUTH_CHALLENGE_SIZE]; @@ -1427,6 +1428,85 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(void) return x509_cred; } +static int vnc_validate_certificate(struct VncState *vs) +{ + int ret; + unsigned int status; + const gnutls_datum_t *certs; + unsigned int nCerts, i; + time_t now; + + VNC_DEBUG("Validating client certificate\n"); + if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) { + VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret)); + return -1; + } + + if ((now = time(NULL)) == ((time_t)-1)) { + return -1; + } + + if (status != 0) { + if (status & GNUTLS_CERT_INVALID) + VNC_DEBUG("The certificate is not trusted.\n"); + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + VNC_DEBUG("The certificate hasn't got a known issuer.\n"); + + if (status & GNUTLS_CERT_REVOKED) + VNC_DEBUG("The certificate has been revoked.\n"); + + if (status & GNUTLS_CERT_INSECURE_ALGORITHM) + VNC_DEBUG("The certificate uses an insecure algorithm\n"); + + return -1; + } else { + VNC_DEBUG("Certificate is valid!\n"); + } + + /* Only support x509 for now */ + if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509) + return -1; + + if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts))) + return -1; + + for (i = 0 ; i < nCerts ; i++) { + gnutls_x509_crt_t cert; + VNC_DEBUG ("Checking certificate chain %d\n", i); + if (gnutls_x509_crt_init (&cert) < 0) + return -1; + + if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) { + gnutls_x509_crt_deinit (cert); + return -1; + } + + if (gnutls_x509_crt_get_expiration_time (cert) < now) { + VNC_DEBUG("The certificate has expired\n"); + gnutls_x509_crt_deinit (cert); + return -1; + } + + if (gnutls_x509_crt_get_activation_time (cert) > now) { + VNC_DEBUG("The certificate is not yet activated\n"); + gnutls_x509_crt_deinit (cert); + return -1; + } + + if (gnutls_x509_crt_get_activation_time (cert) > now) { + VNC_DEBUG("The certificate is not yet activated\n"); + gnutls_x509_crt_deinit (cert); + return -1; + } + + gnutls_x509_crt_deinit (cert); + } + + return 0; +} + + static int start_auth_vencrypt_subauth(VncState *vs) { switch (vs->subauth) { @@ -1475,6 +1555,16 @@ static int vnc_continue_handshake(struct VncState *vs) { return -1; } + if (vs->x509verify) { + if (vnc_validate_certificate(vs) < 0) { + VNC_DEBUG("Client verification failed\n"); + vnc_client_error(vs); + return -1; + } else { + VNC_DEBUG("Client verification passed\n"); + } + } + VNC_DEBUG("Handshake done, switching to TLS data mode\n"); vs->wiremode = VNC_WIREMODE_TLS; qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); @@ -1556,6 +1646,11 @@ static int vnc_start_tls(struct VncState *vs) { vnc_client_error(vs); return -1; } + if (vs->x509verify) { + VNC_DEBUG("Requesting a client certificate\n"); + gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST); + } + } else { gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); if (!anon_cred) { @@ -1839,6 +1934,7 @@ void vnc_display_close(DisplayState *ds) vs->auth = VNC_AUTH_INVALID; #if CONFIG_VNC_TLS vs->subauth = VNC_AUTH_INVALID; + vs->x509verify = 0; #endif } @@ -1885,14 +1981,18 @@ int vnc_display_open(DisplayState *ds, const char *display) options = display; while ((options = strchr(options, ','))) { options++; - if (strncmp(options, "password", 8) == 0) + if (strncmp(options, "password", 8) == 0) { password = 1; /* Require password auth */ #if CONFIG_VNC_TLS - else if (strncmp(options, "tls", 3) == 0) + } else if (strncmp(options, "tls", 3) == 0) { tls = 1; /* Require TLS */ - else if (strncmp(options, "x509", 4) == 0) + } else if (strncmp(options, "x509verify", 10) == 0) { + x509 = 1; /* Require x509 certificates... */ + vs->x509verify = 1;/* ...and verify client certs */ + } else if (strncmp(options, "x509", 4) == 0) { x509 = 1; /* Require x509 certificates */ #endif + } } if (password) { -- cgit v1.2.3 From 6f43024c90ec6de51e31193ebf6e6ea3b776652a Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:39:57 +0000 Subject: Custom location for x509 cert paths, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3139 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 16 deletions(-) diff --git a/vnc.c b/vnc.c index 3508a84e2..64906980c 100644 --- a/vnc.c +++ b/vnc.c @@ -143,6 +143,11 @@ struct VncState #if CONFIG_VNC_TLS int subauth; int x509verify; + + char *x509cacert; + char *x509cacrl; + char *x509cert; + char *x509key; #endif char challenge[VNC_AUTH_CHALLENGE_SIZE]; @@ -1386,37 +1391,49 @@ static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) } -static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(void) +static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs) { gnutls_certificate_credentials_t x509_cred; int ret; - struct stat st; + + if (!vs->x509cacert) { + VNC_DEBUG("No CA x509 certificate specified\n"); + return NULL; + } + if (!vs->x509cert) { + VNC_DEBUG("No server x509 certificate specified\n"); + return NULL; + } + if (!vs->x509key) { + VNC_DEBUG("No server private key specified\n"); + return NULL; + } if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) { VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret)); return NULL; } - if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, X509_CA_CERT_FILE, GNUTLS_X509_FMT_PEM)) < 0) { + if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, + vs->x509cacert, + GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; } - if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, X509_SERVER_CERT_FILE, - X509_SERVER_KEY_FILE, + if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, + vs->x509cert, + vs->x509key, GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; } - if (stat(X509_CA_CRL_FILE, &st) < 0) { - if (errno != ENOENT) { - gnutls_certificate_free_credentials(x509_cred); - return NULL; - } - } else { - if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, X509_CA_CRL_FILE, GNUTLS_X509_FMT_PEM)) < 0) { + if (vs->x509cacrl) { + if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, + vs->x509cacrl, + GNUTLS_X509_FMT_PEM)) < 0) { VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); gnutls_certificate_free_credentials(x509_cred); return NULL; @@ -1632,7 +1649,7 @@ static int vnc_start_tls(struct VncState *vs) { } if (NEED_X509_AUTH(vs)) { - gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(); + gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs); if (!x509_cred) { gnutls_deinit(vs->tls_session); vs->tls_session = NULL; @@ -1903,6 +1920,63 @@ void vnc_display_init(DisplayState *ds) vnc_dpy_resize(vs->ds, 640, 400); } +#if CONFIG_VNC_TLS +static int vnc_set_x509_credential(VncState *vs, + const char *certdir, + const char *filename, + char **cred, + int ignoreMissing) +{ + struct stat sb; + + if (*cred) { + qemu_free(*cred); + *cred = NULL; + } + + if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2))) + return -1; + + strcpy(*cred, certdir); + strcat(*cred, "/"); + strcat(*cred, filename); + + VNC_DEBUG("Check %s\n", *cred); + if (stat(*cred, &sb) < 0) { + qemu_free(*cred); + *cred = NULL; + if (ignoreMissing && errno == ENOENT) + return 0; + return -1; + } + + return 0; +} + +static int vnc_set_x509_credential_dir(VncState *vs, + const char *certdir) +{ + if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0) + goto cleanup; + if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0) + goto cleanup; + if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0) + goto cleanup; + if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0) + goto cleanup; + + return 0; + + cleanup: + qemu_free(vs->x509cacert); + qemu_free(vs->x509cacrl); + qemu_free(vs->x509cert); + qemu_free(vs->x509key); + vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL; + return -1; +} +#endif /* CONFIG_VNC_TLS */ + void vnc_display_close(DisplayState *ds) { VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; @@ -1986,11 +2060,36 @@ int vnc_display_open(DisplayState *ds, const char *display) #if CONFIG_VNC_TLS } else if (strncmp(options, "tls", 3) == 0) { tls = 1; /* Require TLS */ - } else if (strncmp(options, "x509verify", 10) == 0) { - x509 = 1; /* Require x509 certificates... */ - vs->x509verify = 1;/* ...and verify client certs */ } else if (strncmp(options, "x509", 4) == 0) { + char *start, *end; x509 = 1; /* Require x509 certificates */ + if (strncmp(options, "x509verify", 10) == 0) + vs->x509verify = 1; /* ...and verify client certs */ + + /* Now check for 'x509=/some/path' postfix + * and use that to setup x509 certificate/key paths */ + start = strchr(options, '='); + end = strchr(options, ','); + if (start && (!end || (start < end))) { + int len = end ? end-(start+1) : strlen(start+1); + char *path = qemu_malloc(len+1); + strncpy(path, start+1, len); + path[len] = '\0'; + VNC_DEBUG("Trying certificate path '%s'\n", path); + if (vnc_set_x509_credential_dir(vs, path) < 0) { + fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path); + qemu_free(path); + qemu_free(vs->display); + vs->display = NULL; + return -1; + } + qemu_free(path); + } else { + fprintf(stderr, "No certificate path provided\n"); + qemu_free(vs->display); + vs->display = NULL; + return -1; + } #endif } } -- cgit v1.2.3 From f858dcaeba3aacf364a29f7dc2840ff19a1cc31d Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 01:40:37 +0000 Subject: Document all VNC authentication options, by Daniel P. Berrange. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3140 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 403 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 351 insertions(+), 52 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 67b78cdcd..c49e221cb 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -129,6 +129,7 @@ Download the experimental binary installer at * pcsys_network:: Network emulation * direct_linux_boot:: Direct Linux Boot * pcsys_usb:: USB emulation +* vnc_security:: VNC security * gdb_usage:: GDB usage * pcsys_os_specific:: Target OS specific information @end menu @@ -243,53 +244,6 @@ Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255 CPUs are supported. -@item -nographic - -Normally, QEMU uses SDL to display the VGA output. With this option, -you can totally disable graphical output so that QEMU is a simple -command line application. The emulated serial port is redirected on -the console. Therefore, you can still use QEMU to debug a Linux kernel -with a serial console. - -@item -no-frame - -Do not use decorations for SDL windows and start them using the whole -available screen space. This makes the using QEMU in a dedicated desktop -workspace more convenient. - -@item -vnc display - -Normally, QEMU uses SDL to display the VGA output. With this option, -you can have QEMU listen on VNC display @var{display} and redirect the VGA -display over the VNC session. It is very useful to enable the usb -tablet device when using this option (option @option{-usbdevice -tablet}). When using the VNC display, you must use the @option{-k} -option to set the keyboard layout if you are not using en-us. - -@var{display} may be in the form @var{interface:d}, in which case connections -will only be allowed from @var{interface} on display @var{d}. Optionally, -@var{interface} can be omitted. @var{display} can also be in the form -@var{unix:path} where @var{path} is the location of a unix socket to listen for -connections on. - - -@item -k language - -Use keyboard layout @var{language} (for example @code{fr} for -French). This option is only needed where it is not easy to get raw PC -keycodes (e.g. on Macs, with some X11 servers or with a VNC -display). You don't normally need to use it on PC/Linux or PC/Windows -hosts. - -The available layouts are: -@example -ar de-ch es fo fr-ca hu ja mk no pt-br sv -da en-gb et fr fr-ch is lt nl pl ru th -de en-us fi fr-be hr it lv nl-be pt sl tr -@end example - -The default is @code{en-us}. - @item -audio-help Will show the audio subsystem help: list of drivers, tunable @@ -312,9 +266,6 @@ Set the real time clock to local time (the default is to UTC time). This option is needed to have correct date in MS-DOS or Windows. -@item -full-screen -Start in full screen. - @item -pidfile file Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. @@ -340,6 +291,117 @@ caption. The name will also be used for the VNC server. @end table +Display options: +@table @option + +@item -nographic + +Normally, QEMU uses SDL to display the VGA output. With this option, +you can totally disable graphical output so that QEMU is a simple +command line application. The emulated serial port is redirected on +the console. Therefore, you can still use QEMU to debug a Linux kernel +with a serial console. + +@item -no-frame + +Do not use decorations for SDL windows and start them using the whole +available screen space. This makes the using QEMU in a dedicated desktop +workspace more convenient. + +@item -full-screen +Start in full screen. + +@item -vnc display[,option[,option[,...]]] + +Normally, QEMU uses SDL to display the VGA output. With this option, +you can have QEMU listen on VNC display @var{display} and redirect the VGA +display over the VNC session. It is very useful to enable the usb +tablet device when using this option (option @option{-usbdevice +tablet}). When using the VNC display, you must use the @option{-k} +parameter to set the keyboard layout if you are not using en-us. Valid +syntax for the @var{display} is + +@table @code + +@item @var{interface:d} + +TCP connections will only be allowed from @var{interface} on display @var{d}. +By convention the TCP port is 5900+@var{d}. Optionally, @var{interface} can +be omitted in which case the server will bind to all interfaces. + +@item @var{unix:path} + +Connections will be allowed over UNIX domain sockets where @var{path} is the +location of a unix socket to listen for connections on. + +@item @var{none} + +VNC is initialized by not started. The monitor @code{change} command can be used +to later start the VNC server. + +@end table + +Following the @var{display} value there may be one or more @var{option} flags +separated by commas. Valid options are + +@table @code + +@item @var{password} + +Require that password based authentication is used for client connections. +The password must be set separately using the @code{change} command in the +@ref{pcsys_monitor} + +@item @var{tls} + +Require that client use TLS when communicating with the VNC server. This +uses anonymous TLS credentials so is susceptible to a man-in-the-middle +attack. It is recommended that this option be combined with either the +@var{x509} or @var{x509verify} options. + +@item @var{x509=/path/to/certificate/dir} + +Valid if @var{tls} is specified. Require that x509 credentials are used +for negotiating the TLS session. The server will send its x509 certificate +to the client. It is recommended that a password be set on the VNC server +to provide authentication of the client when this is used. The path following +this option specifies where the x509 certificates are to be loaded from. +See the @ref{vnc_security} section for details on generating certificates. + +@item @var{x509verify=/path/to/certificate/dir} + +Valid if @var{tls} is specified. Require that x509 credentials are used +for negotiating the TLS session. The server will send its x509 certificate +to the client, and request that the client send its own x509 certificate. +The server will validate the client's certificate against the CA certificate, +and reject clients when validation fails. If the certificate authority is +trusted, this is a sufficient authentication mechanism. You may still wish +to set a password on the VNC server as a second authentication layer. The +path following this option specifies where the x509 certificates are to +be loaded from. See the @ref{vnc_security} section for details on generating +certificates. + +@end table + +@item -k language + +Use keyboard layout @var{language} (for example @code{fr} for +French). This option is only needed where it is not easy to get raw PC +keycodes (e.g. on Macs, with some X11 servers or with a VNC +display). You don't normally need to use it on PC/Linux or PC/Windows +hosts. + +The available layouts are: +@example +ar de-ch es fo fr-ca hu ja mk no pt-br sv +da en-gb et fr fr-ch is lt nl pl ru th +de en-us fi fr-be hr it lv nl-be pt sl tr +@end example + +The default is @code{en-us}. + +@end table + USB options: @table @option @@ -862,8 +924,38 @@ Quit the emulator. @item eject [-f] device Eject a removable medium (use -f to force it). -@item change device filename -Change a removable medium. +@item change device setting + +Change the configuration of a device + +@table @option +@item change @var{diskdevice} @var{filename} +Change the medium for a removable disk device to point to @var{filename}. eg + +@example +(qemu) change cdrom /path/to/some.iso +@end example + +@item change vnc @var{display,options} +Change the configuration of the VNC server. The valid syntax for @var{display} +and @var{options} are described at @ref{sec_invocation}. eg + +@example +(qemu) change vnc localhost:1 +@end example + +@item change vnc password + +Change the password associated with the VNC server. The monitor will prompt for +the new password to be entered. VNC passwords are only significant upto 8 letters. +eg. + +@example +(qemu) change vnc password +Password: ******** +@end example + +@end table @item screendump filename Save screen into PPM image @var{filename}. @@ -1421,6 +1513,213 @@ plugged. You can use the option @option{-usbdevice} to do the same. When relaunching QEMU, you may have to unplug and plug again the USB device to make it work again (this is a bug). +@node vnc_security +@section VNC security + +The VNC server capability provides access to the graphical console +of the guest VM across the network. This has a number of security +considerations depending on the deployment scenarios. + +@menu +* vnc_sec_none:: +* vnc_sec_password:: +* vnc_sec_certificate:: +* vnc_sec_certificate_verify:: +* vnc_sec_certificate_pw:: +* vnc_generate_cert:: +@end menu +@node vnc_sec_none +@subsection Without passwords + +The simplest VNC server setup does not include any form of authentication. +For this setup it is recommended to restrict it to listen on a UNIX domain +socket only. For example + +@example +qemu [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc +@end example + +This ensures that only users on local box with read/write access to that +path can access the VNC server. To securely access the VNC server from a +remote machine, a combination of netcat+ssh can be used to provide a secure +tunnel. + +@node vnc_sec_password +@subsection With passwords + +The VNC protocol has limited support for password based authentication. Since +the protocol limits passwords to 8 characters it should not be considered +to provide high security. The password can be fairly easily brute-forced by +a client making repeat connections. For this reason, a VNC server using password +authentication should be restricted to only listen on the loopback interface +or UNIX domain sockets. Password ayuthentication is requested with the @code{password} +option, and then once QEMU is running the password is set with the monitor. Until +the monitor is used to set the password all clients will be rejected. + +@example +qemu [...OPTIONS...] -vnc :1,password -monitor stdio +(qemu) change vnc password +Password: ******** +(qemu) +@end example + +@node vnc_sec_certificate +@subsection With x509 certificates + +The QEMU VNC server also implements the VeNCrypt extension allowing use of +TLS for encryption of the session, and x509 certificates for authentication. +The use of x509 certificates is strongly recommended, because TLS on its +own is susceptible to man-in-the-middle attacks. Basic x509 certificate +support provides a secure session, but no authentication. This allows any +client to connect, and provides an encrypted session. + +@example +qemu [...OPTIONS...] -vnc :1,tls,x509=/etc/pki/qemu -monitor stdio +@end example + +In the above example @code{/etc/pki/qemu} should contain at least three files, +@code{ca-cert.pem}, @code{server-cert.pem} and @code{server-key.pem}. Unprivileged +users will want to use a private directory, for example @code{$HOME/.pki/qemu}. +NB the @code{server-key.pem} file should be protected with file mode 0600 to +only be readable by the user owning it. + +@node vnc_sec_certificate_verify +@subsection With x509 certificates and client verification + +Certificates can also provide a means to authenticate the client connecting. +The server will request that the client provide a certificate, which it will +then validate against the CA certificate. This is a good choice if deploying +in an environment with a private internal certificate authority. + +@example +qemu [...OPTIONS...] -vnc :1,tls,x509verify=/etc/pki/qemu -monitor stdio +@end example + + +@node vnc_sec_certificate_pw +@subsection With x509 certificates, client verification and passwords + +Finally, the previous method can be combined with VNC password authentication +to provide two layers of authentication for clients. + +@example +qemu [...OPTIONS...] -vnc :1,password,tls,x509verify=/etc/pki/qemu -monitor stdio +(qemu) change vnc password +Password: ******** +(qemu) +@end example + +@node vnc_generate_cert +@subsection Generating certificates for VNC + +The GNU TLS packages provides a command called @code{certtool} which can +be used to generate certificates and keys in PEM format. At a minimum it +is neccessary to setup a certificate authority, and issue certificates to +each server. If using certificates for authentication, then each client +will also need to be issued a certificate. The recommendation is for the +server to keep its certificates in either @code{/etc/pki/qemu} or for +unprivileged users in @code{$HOME/.pki/qemu}. + +@menu +* vnc_generate_ca:: +* vnc_generate_server:: +* vnc_generate_client:: +@end menu +@node vnc_generate_ca +@subsubsection Setup the Certificate Authority + +This step only needs to be performed once per organization / organizational +unit. First the CA needs a private key. This key must be kept VERY secret +and secure. If this key is compromised the entire trust chain of the certificates +issued with it is lost. + +@example +# certtool --generate-privkey > ca-key.pem +@end example + +A CA needs to have a public certificate. For simplicity it can be a self-signed +certificate, or one issue by a commercial certificate issuing authority. To +generate a self-signed certificate requires one core piece of information, the +name of the organization. + +@example +# cat > ca.info < server.info < server-key.pem +# certtool --generate-certificate \ + --load-ca-certificate ca-cert.pem \ + --load-ca-privkey ca-key.pem \ + --load-privkey server server-key.pem \ + --template server.info \ + --outfile server-cert.pem +@end example + +The @code{server-key.pem} and @code{server-cert.pem} files should now be securely copied +to the server for which they were generated. The @code{server-key.pem} is security +sensitive and should be kept protected with file mode 0600 to prevent disclosure. + +@node vnc_generate_client +@subsubsection Issuing client certificates + +If the QEMU VNC server is to use the @code{x509verify} option to validate client +certificates as its authentication mechanism, each client also needs to be issued +a certificate. The client certificate contains enough metadata to uniquely identify +the client, typically organization, state, city, building, etc. On the host holding +the secure CA private key: + +@example +# cat > client.info < client-key.pem +# certtool --generate-certificate \ + --load-ca-certificate ca-cert.pem \ + --load-ca-privkey ca-key.pem \ + --load-privkey client-key.pem \ + --template client.info \ + --outfile client-cert.pem +@end example + +The @code{client-key.pem} and @code{client-cert.pem} files should now be securely +copied to the client for which they were generated. + @node gdb_usage @section GDB usage -- cgit v1.2.3 From 6fd27407ec8f4934681be39d4fa557dda1254692 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 25 Aug 2007 02:09:50 +0000 Subject: Actually add d3des implementation files. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3141 c046a42c-6fe2-441c-8c8c-71466251a162 --- d3des.c | 434 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ d3des.h | 51 ++++++++ 2 files changed, 485 insertions(+) create mode 100644 d3des.c create mode 100644 d3des.h diff --git a/d3des.c b/d3des.c new file mode 100644 index 000000000..eaca58165 --- /dev/null +++ b/d3des.c @@ -0,0 +1,434 @@ +/* + * This is D3DES (V5.09) by Richard Outerbridge with the double and + * triple-length support removed for use in VNC. Also the bytebit[] array + * has been reversed so that the most significant bit in each byte of the + * key is ignored, not the least significant. + * + * These changes are: + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This software 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. + */ + +/* D3DES (V5.09) - + * + * A portable, public domain, version of the Data Encryption Standard. + * + * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge. + * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation + * code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis + * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau, + * for humouring me on. + * + * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge. + * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992. + */ + +#include "d3des.h" + +static void scrunch(unsigned char *, unsigned long *); +static void unscrun(unsigned long *, unsigned char *); +static void desfunc(unsigned long *, unsigned long *); +static void cookey(unsigned long *); + +static unsigned long KnL[32] = { 0L }; + +static unsigned short bytebit[8] = { + 01, 02, 04, 010, 020, 040, 0100, 0200 }; + +static unsigned long bigbyte[24] = { + 0x800000L, 0x400000L, 0x200000L, 0x100000L, + 0x80000L, 0x40000L, 0x20000L, 0x10000L, + 0x8000L, 0x4000L, 0x2000L, 0x1000L, + 0x800L, 0x400L, 0x200L, 0x100L, + 0x80L, 0x40L, 0x20L, 0x10L, + 0x8L, 0x4L, 0x2L, 0x1L }; + +/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */ + +static unsigned char pc1[56] = { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 }; + +static unsigned char totrot[16] = { + 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 }; + +static unsigned char pc2[48] = { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; + +void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */ +unsigned char *key; +int edf; +{ + register int i, j, l, m, n; + unsigned char pc1m[56], pcr[56]; + unsigned long kn[32]; + + for ( j = 0; j < 56; j++ ) { + l = pc1[j]; + m = l & 07; + pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; + } + for( i = 0; i < 16; i++ ) { + if( edf == DE1 ) m = (15 - i) << 1; + else m = i << 1; + n = m + 1; + kn[m] = kn[n] = 0L; + for( j = 0; j < 28; j++ ) { + l = j + totrot[i]; + if( l < 28 ) pcr[j] = pc1m[l]; + else pcr[j] = pc1m[l - 28]; + } + for( j = 28; j < 56; j++ ) { + l = j + totrot[i]; + if( l < 56 ) pcr[j] = pc1m[l]; + else pcr[j] = pc1m[l - 28]; + } + for( j = 0; j < 24; j++ ) { + if( pcr[pc2[j]] ) kn[m] |= bigbyte[j]; + if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j]; + } + } + cookey(kn); + return; + } + +static void cookey(raw1) +register unsigned long *raw1; +{ + register unsigned long *cook, *raw0; + unsigned long dough[32]; + register int i; + + cook = dough; + for( i = 0; i < 16; i++, raw1++ ) { + raw0 = raw1++; + *cook = (*raw0 & 0x00fc0000L) << 6; + *cook |= (*raw0 & 0x00000fc0L) << 10; + *cook |= (*raw1 & 0x00fc0000L) >> 10; + *cook++ |= (*raw1 & 0x00000fc0L) >> 6; + *cook = (*raw0 & 0x0003f000L) << 12; + *cook |= (*raw0 & 0x0000003fL) << 16; + *cook |= (*raw1 & 0x0003f000L) >> 4; + *cook++ |= (*raw1 & 0x0000003fL); + } + usekey(dough); + return; + } + +void cpkey(into) +register unsigned long *into; +{ + register unsigned long *from, *endp; + + from = KnL, endp = &KnL[32]; + while( from < endp ) *into++ = *from++; + return; + } + +void usekey(from) +register unsigned long *from; +{ + register unsigned long *to, *endp; + + to = KnL, endp = &KnL[32]; + while( to < endp ) *to++ = *from++; + return; + } + +void des(inblock, outblock) +unsigned char *inblock, *outblock; +{ + unsigned long work[2]; + + scrunch(inblock, work); + desfunc(work, KnL); + unscrun(work, outblock); + return; + } + +static void scrunch(outof, into) +register unsigned char *outof; +register unsigned long *into; +{ + *into = (*outof++ & 0xffL) << 24; + *into |= (*outof++ & 0xffL) << 16; + *into |= (*outof++ & 0xffL) << 8; + *into++ |= (*outof++ & 0xffL); + *into = (*outof++ & 0xffL) << 24; + *into |= (*outof++ & 0xffL) << 16; + *into |= (*outof++ & 0xffL) << 8; + *into |= (*outof & 0xffL); + return; + } + +static void unscrun(outof, into) +register unsigned long *outof; +register unsigned char *into; +{ + *into++ = (unsigned char)((*outof >> 24) & 0xffL); + *into++ = (unsigned char)((*outof >> 16) & 0xffL); + *into++ = (unsigned char)((*outof >> 8) & 0xffL); + *into++ = (unsigned char)(*outof++ & 0xffL); + *into++ = (unsigned char)((*outof >> 24) & 0xffL); + *into++ = (unsigned char)((*outof >> 16) & 0xffL); + *into++ = (unsigned char)((*outof >> 8) & 0xffL); + *into = (unsigned char)(*outof & 0xffL); + return; + } + +static unsigned long SP1[64] = { + 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, + 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, + 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, + 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, + 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, + 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, + 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, + 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, + 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, + 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, + 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, + 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, + 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, + 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L }; + +static unsigned long SP2[64] = { + 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, + 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, + 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, + 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, + 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, + 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, + 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, + 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, + 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, + 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, + 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, + 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, + 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, + 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, + 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, + 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L }; + +static unsigned long SP3[64] = { + 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, + 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, + 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, + 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, + 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, + 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, + 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, + 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, + 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, + 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, + 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, + 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, + 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, + 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, + 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, + 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L }; + +static unsigned long SP4[64] = { + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, + 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, + 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, + 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, + 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, + 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, + 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, + 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, + 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L }; + +static unsigned long SP5[64] = { + 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, + 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, + 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, + 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, + 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, + 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, + 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, + 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, + 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, + 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, + 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, + 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, + 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, + 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, + 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, + 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L }; + +static unsigned long SP6[64] = { + 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, + 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, + 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, + 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, + 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, + 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, + 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, + 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, + 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, + 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, + 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, + 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, + 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, + 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L }; + +static unsigned long SP7[64] = { + 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, + 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, + 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, + 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, + 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, + 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, + 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, + 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, + 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, + 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, + 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, + 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, + 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, + 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, + 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, + 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L }; + +static unsigned long SP8[64] = { + 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, + 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, + 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, + 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, + 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, + 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, + 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, + 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, + 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, + 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, + 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, + 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, + 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, + 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, + 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, + 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L }; + +static void desfunc(block, keys) +register unsigned long *block, *keys; +{ + register unsigned long fval, work, right, leftt; + register int round; + + leftt = block[0]; + right = block[1]; + work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; + right ^= work; + leftt ^= (work << 4); + work = ((leftt >> 16) ^ right) & 0x0000ffffL; + right ^= work; + leftt ^= (work << 16); + work = ((right >> 2) ^ leftt) & 0x33333333L; + leftt ^= work; + right ^= (work << 2); + work = ((right >> 8) ^ leftt) & 0x00ff00ffL; + leftt ^= work; + right ^= (work << 8); + right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL; + work = (leftt ^ right) & 0xaaaaaaaaL; + leftt ^= work; + right ^= work; + leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; + + for( round = 0; round < 8; round++ ) { + work = (right << 28) | (right >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = right ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + leftt ^= fval; + work = (leftt << 28) | (leftt >> 4); + work ^= *keys++; + fval = SP7[ work & 0x3fL]; + fval |= SP5[(work >> 8) & 0x3fL]; + fval |= SP3[(work >> 16) & 0x3fL]; + fval |= SP1[(work >> 24) & 0x3fL]; + work = leftt ^ *keys++; + fval |= SP8[ work & 0x3fL]; + fval |= SP6[(work >> 8) & 0x3fL]; + fval |= SP4[(work >> 16) & 0x3fL]; + fval |= SP2[(work >> 24) & 0x3fL]; + right ^= fval; + } + + right = (right << 31) | (right >> 1); + work = (leftt ^ right) & 0xaaaaaaaaL; + leftt ^= work; + right ^= work; + leftt = (leftt << 31) | (leftt >> 1); + work = ((leftt >> 8) ^ right) & 0x00ff00ffL; + right ^= work; + leftt ^= (work << 8); + work = ((leftt >> 2) ^ right) & 0x33333333L; + right ^= work; + leftt ^= (work << 2); + work = ((right >> 16) ^ leftt) & 0x0000ffffL; + leftt ^= work; + right ^= (work << 16); + work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; + leftt ^= work; + right ^= (work << 4); + *block++ = right; + *block = leftt; + return; + } + +/* Validation sets: + * + * Single-length key, single-length plaintext - + * Key : 0123 4567 89ab cdef + * Plain : 0123 4567 89ab cde7 + * Cipher : c957 4425 6a5e d31d + * + * Double-length key, single-length plaintext - + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 + * Plain : 0123 4567 89ab cde7 + * Cipher : 7f1d 0a77 826b 8aff + * + * Double-length key, double-length plaintext - + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 + * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff + * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7 + * + * Triple-length key, single-length plaintext - + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 + * Plain : 0123 4567 89ab cde7 + * Cipher : de0b 7c06 ae5e 0ed5 + * + * Triple-length key, double-length plaintext - + * Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567 + * Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff + * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5 + * + * d3des V5.0a rwo 9208.07 18:44 Graven Imagery + **********************************************************************/ diff --git a/d3des.h b/d3des.h new file mode 100644 index 000000000..ea3da44ce --- /dev/null +++ b/d3des.h @@ -0,0 +1,51 @@ +/* + * This is D3DES (V5.09) by Richard Outerbridge with the double and + * triple-length support removed for use in VNC. + * + * These changes are: + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This software 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. + */ + +/* d3des.h - + * + * Headers and defines for d3des.c + * Graven Imagery, 1992. + * + * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge + * (GEnie : OUTER; CIS : [71755,204]) + */ + +#define EN0 0 /* MODE == encrypt */ +#define DE1 1 /* MODE == decrypt */ + +extern void deskey(unsigned char *, int); +/* hexkey[8] MODE + * Sets the internal key register according to the hexadecimal + * key contained in the 8 bytes of hexkey, according to the DES, + * for encryption or decryption according to MODE. + */ + +extern void usekey(unsigned long *); +/* cookedkey[32] + * Loads the internal key register with the data in cookedkey. + */ + +extern void cpkey(unsigned long *); +/* cookedkey[32] + * Copies the contents of the internal key register into the storage + * located at &cookedkey[0]. + */ + +extern void des(unsigned char *, unsigned char *); +/* from[8] to[8] + * Encrypts/Decrypts (according to the key currently loaded in the + * internal key register) one block of eight bytes at address 'from' + * into the block at address 'to'. They can be the same. + */ + +/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery + ********************************************************************/ -- cgit v1.2.3 From 231c658672dac7a6b776433bab42bb04727fb919 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:29:15 +0000 Subject: Make dynticks conditional on __linux__. Spotted by Andreas Faerber. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3142 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index 3c8070e34..00de846d9 100644 --- a/vl.c +++ b/vl.c @@ -829,12 +829,12 @@ static void win32_rearm_timer(struct qemu_alarm_timer *t); static int unix_start_timer(struct qemu_alarm_timer *t); static void unix_stop_timer(struct qemu_alarm_timer *t); +#ifdef __linux__ + static int dynticks_start_timer(struct qemu_alarm_timer *t); static void dynticks_stop_timer(struct qemu_alarm_timer *t); static void dynticks_rearm_timer(struct qemu_alarm_timer *t); -#ifdef __linux__ - static int hpet_start_timer(struct qemu_alarm_timer *t); static void hpet_stop_timer(struct qemu_alarm_timer *t); @@ -847,9 +847,9 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t); static struct qemu_alarm_timer alarm_timers[] = { #ifndef _WIN32 +#ifdef __linux__ {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer, dynticks_stop_timer, dynticks_rearm_timer, NULL}, -#ifdef __linux__ /* HPET - if available - is preferred */ {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL}, /* ...otherwise try RTC */ @@ -1299,8 +1299,6 @@ static void rtc_stop_timer(struct qemu_alarm_timer *t) close(rtc_fd); } -#endif /* !defined(__linux__) */ - static int dynticks_start_timer(struct qemu_alarm_timer *t) { struct sigevent ev; @@ -1375,6 +1373,8 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) } } +#endif /* !defined(__linux__) */ + static int unix_start_timer(struct qemu_alarm_timer *t) { struct sigaction act; -- cgit v1.2.3 From 70744b3ab889cd0d16992e1ad13fbde157c416ba Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:31:30 +0000 Subject: Fix typo in comment, by Andreas Faerber. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3143 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 00de846d9..53b46259a 100644 --- a/vl.c +++ b/vl.c @@ -1373,7 +1373,7 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) } } -#endif /* !defined(__linux__) */ +#endif /* defined(__linux__) */ static int unix_start_timer(struct qemu_alarm_timer *t) { -- cgit v1.2.3 From be0164f2e0af7968c6cba02085f3f54ef8683e91 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:33:08 +0000 Subject: Set apic instance number for savevm, by Ari Kivity. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3144 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/apic.c b/hw/apic.c index f964360c8..d503d45f2 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -832,7 +832,7 @@ int apic_init(CPUState *env) } s->timer = qemu_new_timer(vm_clock, apic_timer, s); - register_savevm("apic", 0, 2, apic_save, apic_load, s); + register_savevm("apic", s->id, 2, apic_save, apic_load, s); qemu_register_reset(apic_reset, s); local_apics[s->id] = s; -- cgit v1.2.3 From c92843b5dfc1e8f7baace9b7a4eac3e3231ac73e Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:33:53 +0000 Subject: Reset buffer pointers after CR/LF, by Jim Paris. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3145 c046a42c-6fe2-441c-8c8c-71466251a162 --- readline.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readline.c b/readline.c index 25572dd02..577881a19 100644 --- a/readline.c +++ b/readline.c @@ -374,6 +374,10 @@ void readline_handle_byte(int ch) if (!term_is_password) term_hist_add(term_cmd_buf); term_printf("\n"); + term_cmd_buf_index = 0; + term_cmd_buf_size = 0; + term_last_cmd_buf_index = 0; + term_last_cmd_buf_size = 0; /* NOTE: readline_start can be called here */ term_readline_func(term_readline_opaque, term_cmd_buf); break; -- cgit v1.2.3 From 3ddf0b5cde7c741258487710c40f7318fdcd0f18 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:37:23 +0000 Subject: Disable 64-bit instructions on 32-bit CPU, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3146 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 9 ++++++--- target-mips/op.c | 15 +++++++++------ target-mips/translate.c | 16 ++++++++-------- target-mips/translate_init.c | 16 +++++++++------- 4 files changed, 32 insertions(+), 24 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index c1a7792f7..1c8370470 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -369,7 +369,8 @@ void do_interrupt (CPUState *env) } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; - env->hflags |= MIPS_HFLAG_64; + if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) @@ -395,7 +396,8 @@ void do_interrupt (CPUState *env) env->CP0_ErrorEPC = env->PC; } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - env->hflags |= MIPS_HFLAG_64; + if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -494,7 +496,8 @@ void do_interrupt (CPUState *env) env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); - env->hflags |= MIPS_HFLAG_64; + if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; } env->hflags &= ~MIPS_HFLAG_BMASK; diff --git a/target-mips/op.c b/target-mips/op.c index 4aa63e346..12498d033 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1358,9 +1358,10 @@ void op_mtc0_status (void) (val & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; #ifdef TARGET_MIPS64 - if ((env->hflags & MIPS_HFLAG_UM) && + if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) || + ((env->hflags & MIPS_HFLAG_UM) && !(val & (1 << CP0St_PX)) && - !(val & (1 << CP0St_UX))) + !(val & (1 << CP0St_UX)))) env->hflags &= ~MIPS_HFLAG_64; #endif if (val & (1 << CP0St_CU1)) @@ -2318,9 +2319,10 @@ void op_eret (void) (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; #ifdef TARGET_MIPS64 - if ((env->hflags & MIPS_HFLAG_UM) && + if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) || + ((env->hflags & MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_PX)) && - !(env->CP0_Status & (1 << CP0St_UX))) + !(env->CP0_Status & (1 << CP0St_UX)))) env->hflags &= ~MIPS_HFLAG_64; #endif if (loglevel & CPU_LOG_EXEC) @@ -2341,9 +2343,10 @@ void op_deret (void) (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; #ifdef TARGET_MIPS64 - if ((env->hflags & MIPS_HFLAG_UM) && + if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) || + ((env->hflags & MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_PX)) && - !(env->CP0_Status & (1 << CP0St_UX))) + !(env->CP0_Status & (1 << CP0St_UX)))) env->hflags &= ~MIPS_HFLAG_64; #endif if (loglevel & CPU_LOG_EXEC) diff --git a/target-mips/translate.c b/target-mips/translate.c index 7f5141c33..07dca1459 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2225,6 +2225,8 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) switch (sel) { case 0: #ifdef TARGET_MIPS64 + if (!(ctx->hflags & MIPS_HFLAG_64)) + goto die; gen_op_mfc0_xcontext(); rn = "XContext"; break; @@ -2781,6 +2783,8 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) switch (sel) { case 0: #ifdef TARGET_MIPS64 + if (!(ctx->hflags & MIPS_HFLAG_64)) + goto die; gen_op_mtc0_xcontext(); rn = "XContext"; break; @@ -3331,11 +3335,9 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: -#ifdef TARGET_MIPS64 gen_op_dmfc0_xcontext(); rn = "XContext"; break; -#endif default: goto die; } @@ -3878,11 +3880,9 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: -#ifdef TARGET_MIPS64 gen_op_mtc0_xcontext(); rn = "XContext"; break; -#endif default: goto die; } @@ -4107,6 +4107,8 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; #ifdef TARGET_MIPS64 case OPC_DMFC0: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); if (rt == 0) { /* Treat as NOP */ return; @@ -4116,6 +4118,8 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int opn = "dmfc0"; break; case OPC_DMTC0: + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); GEN_LOAD_REG_TN(T0, rt); gen_dmtc0(env,ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; @@ -6183,11 +6187,7 @@ void cpu_reset (CPUMIPSState *env) } else { env->CP0_ErrorEPC = env->PC; } -#ifdef TARGET_MIPS64 - env->hflags = MIPS_HFLAG_64; -#else env->hflags = 0; -#endif env->PC = (int32_t)0xBFC00000; env->CP0_Wired = 0; /* SMP not implemented */ diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 85d5032a2..d327312e5 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -86,7 +86,6 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3278FF17, - .SEGBITS = 32, }, { .name = "4KEcR1", @@ -100,7 +99,6 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3278FF17, - .SEGBITS = 32, }, { .name = "4KEc", @@ -114,7 +112,6 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3278FF17, - .SEGBITS = 32, }, { .name = "24Kc", @@ -128,7 +125,6 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .Status_rw_bitmask = 0x3278FF17, - .SEGBITS = 32, }, { .name = "24Kf", @@ -144,7 +140,6 @@ static mips_def_t mips_defs[] = .Status_rw_bitmask = 0x3678FF17, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), - .SEGBITS = 32, }, #ifdef TARGET_MIPS64 { @@ -293,8 +288,15 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->Status_rw_bitmask = def->Status_rw_bitmask; env->fcr0 = def->CP1_fcr0; #ifdef TARGET_MIPS64 - env->SEGBITS = def->SEGBITS; - env->SEGMask = (3ULL << 62) | ((1ULL << def->SEGBITS) - 1); + if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) + { + env->hflags |= MIPS_HFLAG_64; + env->SEGBITS = def->SEGBITS; + env->SEGMask = (3ULL << 62) | ((1ULL << def->SEGBITS) - 1); + } else { + env->SEGBITS = 32; + env->SEGMask = 0xFFFFFFFF; + } #endif #ifdef CONFIG_USER_ONLY if (env->CP0_Config1 & (1 << CP0C1_FP)) -- cgit v1.2.3 From f0c596cb3d704a349a8ed27237363f124f001878 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:42:20 +0000 Subject: Last AIO patch, by Vladimir N. Oleynik. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3147 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 54 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index e84c4d67f..4a7fa8b6d 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -864,10 +864,44 @@ static void ide_sector_write_timer_cb(void *opaque) ide_set_irq(s); } +static void ide_sector_write_aio_cb(void *opaque, int ret) +{ + BMDMAState *bm = opaque; + IDEState *s = bm->ide_if; + +#ifdef TARGET_I386 + if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { + /* It seems there is a bug in the Windows 2000 installer HDD + IDE driver which fills the disk with empty logs when the + IDE write IRQ comes too early. This hack tries to correct + that at the expense of slower write performances. Use this + option _only_ to install Windows 2000. You must disable it + for normal use. */ + qemu_mod_timer(s->sector_write_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); + } else +#endif + { + ide_set_irq(s); + } + bm->aiocb = NULL; +} + static void ide_sector_write(IDEState *s) { + BMDMAState *bm; int64_t sector_num; - int ret, n, n1; + int n, n1; + + s->io_buffer_index = 0; + s->io_buffer_size = 0; + bm = s->bmdma; + if(bm == NULL) { + bm = qemu_mallocz(sizeof(BMDMAState)); + s->bmdma = bm; + } + bm->ide_if = s; + bm->dma_cb = ide_sector_write_aio_cb; s->status = READY_STAT | SEEK_STAT; sector_num = ide_get_sector(s); @@ -877,7 +911,6 @@ static void ide_sector_write(IDEState *s) n = s->nsector; if (n > s->req_nb_sectors) n = s->req_nb_sectors; - ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); s->nsector -= n; if (s->nsector == 0) { /* no more sectors to write */ @@ -890,21 +923,8 @@ static void ide_sector_write(IDEState *s) } ide_set_sector(s, sector_num + n); -#ifdef TARGET_I386 - if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { - /* It seems there is a bug in the Windows 2000 installer HDD - IDE driver which fills the disk with empty logs when the - IDE write IRQ comes too early. This hack tries to correct - that at the expense of slower write performances. Use this - option _only_ to install Windows 2000. You must disable it - for normal use. */ - qemu_mod_timer(s->sector_write_timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); - } else -#endif - { - ide_set_irq(s); - } + bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, + ide_sector_write_aio_cb, bm); } /* XXX: handle errors */ -- cgit v1.2.3 From 4ed59aa51880914f49d1995d924835d9d0767b1f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:45:23 +0000 Subject: Replace tabs by 8 spaces. No code change, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3148 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vmmouse.c | 104 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/hw/vmmouse.c b/hw/vmmouse.c index cc783008d..c10c26e2d 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -77,21 +77,21 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_ int buttons = 0; if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4)) - return; + return; DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n", - x, y, dz, buttons_state); + x, y, dz, buttons_state); if ((buttons_state & MOUSE_EVENT_LBUTTON)) - buttons |= 0x20; + buttons |= 0x20; if ((buttons_state & MOUSE_EVENT_RBUTTON)) - buttons |= 0x10; + buttons |= 0x10; if ((buttons_state & MOUSE_EVENT_MBUTTON)) - buttons |= 0x08; + buttons |= 0x08; if (s->absolute) { - x <<= 1; - y <<= 1; + x <<= 1; + y <<= 1; } s->queue[s->nb_queue++] = buttons; @@ -107,13 +107,13 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_ static void vmmouse_update_handler(VMMouseState *s) { if (s->entry) { - qemu_remove_mouse_event_handler(s->entry); - s->entry = NULL; + qemu_remove_mouse_event_handler(s->entry); + s->entry = NULL; } if (s->status == 0) - s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event, - s, s->absolute, - "vmmouse"); + s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event, + s, s->absolute, + "vmmouse"); } static void vmmouse_read_id(VMMouseState *s) @@ -121,7 +121,7 @@ static void vmmouse_read_id(VMMouseState *s) DPRINTF("vmmouse_read_id()\n"); if (s->nb_queue == VMMOUSE_QUEUE_SIZE) - return; + return; s->queue[s->nb_queue++] = VMMOUSE_VERSION; s->status = 0; @@ -156,18 +156,18 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size) DPRINTF("vmmouse_data(%d)\n", size); if (size == 0 || size > 6 || size > s->nb_queue) { - printf("vmmouse: driver requested too much data %d\n", size); - s->status = 0xffff; - vmmouse_update_handler(s); - return; + printf("vmmouse: driver requested too much data %d\n", size); + s->status = 0xffff; + vmmouse_update_handler(s); + return; } for (i = 0; i < size; i++) - data[i] = s->queue[i]; + data[i] = s->queue[i]; s->nb_queue -= size; if (s->nb_queue) - memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue); + memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue); } static void vmmouse_get_data(uint32_t *data) @@ -179,7 +179,7 @@ static void vmmouse_get_data(uint32_t *data) data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI]; DPRINTF("get_data = {%x, %x, %x, %x, %x, %x}\n", - data[0], data[1], data[2], data[3], data[4], data[5]); + data[0], data[1], data[2], data[3], data[4], data[5]); } static void vmmouse_set_data(const uint32_t *data) @@ -187,7 +187,7 @@ static void vmmouse_set_data(const uint32_t *data) CPUState *env = cpu_single_env; DPRINTF("set_data = {%x, %x, %x, %x, %x, %x}\n", - data[0], data[1], data[2], data[3], data[4], data[5]); + data[0], data[1], data[2], data[3], data[4], data[5]); env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1]; env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3]; @@ -202,42 +202,42 @@ static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr) vmmouse_get_data(data); if (data[0] != VMMOUSE_MAGIC) - goto error; + goto error; command = data[2] & 0xFFFF; switch (command) { case VMMOUSE_GETVERSION: - data[0] = vmmouse_get_version(s, &data[1]); - break; + data[0] = vmmouse_get_version(s, &data[1]); + break; case VMMOUSE_STATUS: - data[0] = vmmouse_get_status(s); - break; + data[0] = vmmouse_get_status(s); + break; case VMMOUSE_COMMAND: - switch (data[1]) { - case VMMOUSE_DISABLE: - vmmouse_disable(s); - break; - case VMMOUSE_READ_ID: - vmmouse_read_id(s); - break; - case VMMOUSE_REQUEST_RELATIVE: - vmmouse_request_relative(s); - break; - case VMMOUSE_REQUEST_ABSOLUTE: - vmmouse_request_absolute(s); - break; - default: - printf("vmmouse: unknown command %x\n", data[1]); - break; - } - break; + switch (data[1]) { + case VMMOUSE_DISABLE: + vmmouse_disable(s); + break; + case VMMOUSE_READ_ID: + vmmouse_read_id(s); + break; + case VMMOUSE_REQUEST_RELATIVE: + vmmouse_request_relative(s); + break; + case VMMOUSE_REQUEST_ABSOLUTE: + vmmouse_request_absolute(s); + break; + default: + printf("vmmouse: unknown command %x\n", data[1]); + break; + } + break; case VMMOUSE_DATA: - vmmouse_data(s, data, data[1]); - break; + vmmouse_data(s, data, data[1]); + break; default: - printf("vmmouse: unknown command %x\n", command); - break; + printf("vmmouse: unknown command %x\n", command); + break; } error: @@ -252,7 +252,7 @@ static void vmmouse_save(QEMUFile *f, void *opaque) qemu_put_be32(f, VMMOUSE_QUEUE_SIZE); for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++) - qemu_put_be32s(f, &s->queue[i]); + qemu_put_be32s(f, &s->queue[i]); qemu_put_be16s(f, &s->nb_queue); qemu_put_be16s(f, &s->status); qemu_put_8s(f, &s->absolute); @@ -267,9 +267,9 @@ static int vmmouse_load(QEMUFile *f, void *opaque, int version_id) return -EINVAL; if (qemu_get_be32(f) != VMMOUSE_QUEUE_SIZE) - return -EINVAL; + return -EINVAL; for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++) - qemu_get_be32s(f, &s->queue[i]); + qemu_get_be32s(f, &s->queue[i]); qemu_get_be16s(f, &s->nb_queue); qemu_get_be16s(f, &s->status); qemu_get_8s(f, &s->absolute); @@ -287,7 +287,7 @@ void *vmmouse_init(void *m) s = qemu_mallocz(sizeof(VMMouseState)); if (!s) - return NULL; + return NULL; s->status = 0xffff; s->ps2_mouse = m; -- cgit v1.2.3 From 591a6d627995ce00b0db8d7360ad4032eeb77b9c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:46:00 +0000 Subject: Add a generic framework for VMware communication port, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3149 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- vl.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index d1204d678..7cfe52d77 100644 --- a/Makefile.target +++ b/Makefile.target @@ -433,7 +433,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) 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 smbus_eeprom.o vmmouse.o vmware_vga.o +VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o vmport.o vmware_vga.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif ifeq ($(TARGET_BASE_ARCH), ppc) diff --git a/vl.h b/vl.h index e72df0e69..819908b22 100644 --- a/vl.h +++ b/vl.h @@ -1061,6 +1061,12 @@ void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, /* vmmouse.c */ void *vmmouse_init(void *m); +/* vmport.c */ +#ifdef TARGET_I386 +void vmport_init(CPUState *env); +void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque); +#endif + /* pckbd.c */ void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); -- cgit v1.2.3 From 93342807901077d49c098b7b4d5897674d8c17c7 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:46:38 +0000 Subject: Use the framework for the VMware mouse emulation, by Herve Poussineau. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3150 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 1 + hw/vmmouse.c | 18 +++--------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index d38018679..495f6c033 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -692,6 +692,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (pci_enabled) { apic_init(env); } + vmport_init(env); } /* allocate RAM */ diff --git a/hw/vmmouse.c b/hw/vmmouse.c index c10c26e2d..52c8e0c78 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -39,7 +39,6 @@ #define VMMOUSE_QUEUE_SIZE 1024 -#define VMMOUSE_MAGIC 0x564D5868 #define VMMOUSE_VERSION 0x3442554a #ifdef DEBUG_VMMOUSE @@ -58,13 +57,6 @@ typedef struct _VMMouseState void *ps2_mouse; } VMMouseState; -static uint32_t vmmouse_get_version(VMMouseState *s, uint32_t *magic) -{ - DPRINTF("vmmouse_get_version(%x)\n", *magic); - *magic = VMMOUSE_MAGIC; - return VMMOUSE_VERSION; -} - static uint32_t vmmouse_get_status(VMMouseState *s) { DPRINTF("vmmouse_get_status()\n"); @@ -201,15 +193,10 @@ static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr) uint16_t command; vmmouse_get_data(data); - if (data[0] != VMMOUSE_MAGIC) - goto error; command = data[2] & 0xFFFF; switch (command) { - case VMMOUSE_GETVERSION: - data[0] = vmmouse_get_version(s, &data[1]); - break; case VMMOUSE_STATUS: data[0] = vmmouse_get_status(s); break; @@ -240,7 +227,6 @@ static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr) break; } -error: vmmouse_set_data(data); return data[0]; } @@ -292,7 +278,9 @@ void *vmmouse_init(void *m) s->status = 0xffff; s->ps2_mouse = m; - register_ioport_read(0x5658, 1, 4, vmmouse_ioport_read, s); + vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s); + vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s); + vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s); register_savevm("vmmouse", 0, 0, vmmouse_save, vmmouse_load, s); return s; -- cgit v1.2.3 From 0975c30454de8e64d62d6a9360d7180f2e8d4e10 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:48:12 +0000 Subject: Add file missed in last commit. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3151 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vmport.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 hw/vmport.c diff --git a/hw/vmport.c b/hw/vmport.c new file mode 100644 index 000000000..e477fe88c --- /dev/null +++ b/hw/vmport.c @@ -0,0 +1,96 @@ +/* + * QEMU VMPort emulation + * + * Copyright (C) 2007 Herv Poussineau + * + * 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 "cpu-all.h" + +#define VMPORT_CMD_GETVERSION 0x0a +#define VMPORT_CMD_GETRAMSIZE 0x14 + +#define VMPORT_ENTRIES 0x2c +#define VMPORT_MAGIC 0x564D5868 + +typedef struct _VMPortState +{ + CPUState *env; + IOPortReadFunc *func[VMPORT_ENTRIES]; + void *opaque[VMPORT_ENTRIES]; +} VMPortState; + +static VMPortState port_state; + +void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque) +{ + if (command >= VMPORT_ENTRIES) + return; + + port_state.func[command] = func; + port_state.opaque[command] = opaque; +} + +static uint32_t vmport_ioport_read(void *opaque, uint32_t addr) +{ + VMPortState *s = opaque; + unsigned char command; + target_ulong eax; + + eax = s->env->regs[R_EAX]; + if (eax != VMPORT_MAGIC) + return eax; + + command = s->env->regs[R_ECX]; + if (command >= VMPORT_ENTRIES) + return eax; + if (!s->func[command]) + { + printf("vmport: unknown command %x\n", command); + return eax; + } + + return s->func[command](s->opaque[command], addr); +} + +static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) +{ + CPUState *env = opaque; + env->regs[R_EBX] = VMPORT_MAGIC; + return 6; +} + +static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) +{ + CPUState *env = opaque; + env->regs[R_EBX] = 0x1177; + return ram_size; +} + +void vmport_init(CPUState *env) +{ + port_state.env = env; + + register_ioport_read(0x5658, 1, 4, vmport_ioport_read, &port_state); + + /* Register some generic port commands */ + vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, env); + vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, env); +} -- cgit v1.2.3 From 8c2cc7cecbb720e5be9db72dab17f659e5dbfe22 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:48:48 +0000 Subject: SH4 mov.b fix, by Vince Weaver. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3152 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index b7be352d0..67ef8395e 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -879,10 +879,10 @@ void decode_opc(DisasContext * ctx) gen_op_stw_T0_T1(ctx); return; case 0x8400: /* mov.b @(disp,Rn),R0 */ - gen_op_movl_rN_T0(REG(0)); - gen_op_movl_rN_T1(REG(B7_4)); - gen_op_addl_imm_T1(B3_0); - gen_op_stb_T0_T1(ctx); + gen_op_movl_rN_T0(REG(B7_4)); + gen_op_addl_imm_T0(B3_0); + gen_op_ldb_T0_T0(ctx); + gen_op_movl_T0_rN(REG(0)); return; case 0x8500: /* mov.w @(disp,Rn),R0 */ gen_op_movl_rN_T0(REG(B7_4)); -- cgit v1.2.3 From bea6030dcfcbb1bfc7489b2eee2705c0a39ebc1a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:50:07 +0000 Subject: arm_gic.c error message fix, by Adam Lackorzynski. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3153 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm_gic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 250efad36..58d840415 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -460,7 +460,7 @@ static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset) case 0x18: /* Highest Pending Interrupt */ return s->current_pending; default: - cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "gic_cpu_read: Bad offset %x\n", offset); return 0; } } @@ -484,7 +484,7 @@ static void gic_cpu_write(void *opaque, target_phys_addr_t offset, case 0x10: /* End Of Interrupt */ return gic_complete_irq(s, value & 0x3ff); default: - cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "gic_cpu_write: Bad offset %x\n", offset); return; } gic_update(s); -- cgit v1.2.3 From 44486a89f0103ac9b39bfe8160adf83757d97450 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 26 Aug 2007 17:51:39 +0000 Subject: Let qemu work with latest bochsbios, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3154 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 3 +++ vl.c | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/pc.c b/hw/pc.c index 495f6c033..7d86f32d5 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -197,6 +197,9 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table case 'd': rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */ break; + case 'n': + rtc_set_memory(s, 0x3d, 0x04); /* Network boot */ + break; } /* floppy type */ diff --git a/vl.c b/vl.c index 53b46259a..3074d93c2 100644 --- a/vl.c +++ b/vl.c @@ -8203,7 +8203,6 @@ int main(int argc, char **argv) fprintf(stderr, "No valid PXE rom found for network device\n"); exit(1); } - boot_device = 'c'; /* to prevent confusion by the BIOS */ } #endif -- cgit v1.2.3 From 606b41e7020db7634fe90d069d2c019770c74b45 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 28 Aug 2007 22:21:40 +0000 Subject: Build fix for older GCCs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3155 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 3074d93c2..d6f7e8d78 100644 --- a/vl.c +++ b/vl.c @@ -1172,7 +1172,7 @@ static void host_alarm_handler(int host_signum) static uint64_t qemu_next_deadline(void) { - int64_t nearest_delta_us = ULLONG_MAX; + int64_t nearest_delta_us = ULONG_LONG_MAX; int64_t vmdelta_us; if (active_timers[QEMU_TIMER_REALTIME]) -- cgit v1.2.3 From ead9360e2fbcaae10a8ca3d8bfed885422205dca Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 6 Sep 2007 00:18:15 +0000 Subject: Partial support for 34K multithreading, not functional yet. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3156 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- gdbstub.c | 34 +- hw/mips_r4k.c | 2 +- hw/mips_timer.c | 2 +- linux-user/main.c | 24 +- linux-user/signal.c | 36 +- linux-user/syscall.c | 7 +- monitor.c | 4 + target-mips/cpu.h | 239 +++++++++-- target-mips/exec.h | 39 +- target-mips/fop_template.c | 20 +- target-mips/helper.c | 57 +-- target-mips/op.c | 875 +++++++++++++++++++++++++++++++++++---- target-mips/op_helper.c | 605 ++++++++++++++------------- target-mips/op_template.c | 23 +- target-mips/translate.c | 949 ++++++++++++++++++++++++++++++++----------- target-mips/translate_init.c | 211 +++++++--- translate-all.c | 2 +- 18 files changed, 2305 insertions(+), 826 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 543ec09ef..4f1cee616 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -194,7 +194,7 @@ static inline TranslationBlock *tb_find_fast(void) #elif defined(TARGET_MIPS) flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK); cs_base = 0; - pc = env->PC; + pc = env->PC[env->current_tc]; #elif defined(TARGET_M68K) flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */ | (env->sr & SR_S) /* Bit 13 */ diff --git a/gdbstub.c b/gdbstub.c index 48c0c56c8..37347da0b 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -559,17 +559,17 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) ptr = mem_buf; for (i = 0; i < 32; i++) { - *(target_ulong *)ptr = tswapl(env->gpr[i]); + *(target_ulong *)ptr = tswapl(env->gpr[i][env->current_tc]); ptr += sizeof(target_ulong); } *(target_ulong *)ptr = tswapl(env->CP0_Status); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->LO); + *(target_ulong *)ptr = tswapl(env->LO[0][env->current_tc]); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->HI); + *(target_ulong *)ptr = tswapl(env->HI[0][env->current_tc]); ptr += sizeof(target_ulong); *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr); @@ -578,21 +578,21 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) *(target_ulong *)ptr = tswapl(env->CP0_Cause); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->PC); + *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]); ptr += sizeof(target_ulong); if (env->CP0_Config1 & (1 << CP0C1_FP)) { for (i = 0; i < 32; i++) { - *(target_ulong *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]); + *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].fs[FP_ENDIAN_IDX]); ptr += sizeof(target_ulong); } - *(target_ulong *)ptr = tswapl(env->fcr31); + *(target_ulong *)ptr = tswapl(env->fpu->fcr31); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->fcr0); + *(target_ulong *)ptr = tswapl(env->fpu->fcr0); ptr += sizeof(target_ulong); } @@ -611,7 +611,7 @@ static unsigned int ieee_rm[] = float_round_down }; #define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) + set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status) static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { @@ -621,17 +621,17 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) ptr = mem_buf; for (i = 0; i < 32; i++) { - env->gpr[i] = tswapl(*(target_ulong *)ptr); + env->gpr[i][env->current_tc] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); } env->CP0_Status = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->LO = tswapl(*(target_ulong *)ptr); + env->LO[0][env->current_tc] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->HI = tswapl(*(target_ulong *)ptr); + env->HI[0][env->current_tc] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr); @@ -640,21 +640,21 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) env->CP0_Cause = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); - env->PC = tswapl(*(target_ulong *)ptr); + env->PC[env->current_tc] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); if (env->CP0_Config1 & (1 << CP0C1_FP)) { for (i = 0; i < 32; i++) { - env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); + env->fpu->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); } - env->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF; + env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF; ptr += sizeof(target_ulong); - env->fcr0 = tswapl(*(target_ulong *)ptr); + env->fpu->fcr0 = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); /* set rounding mode */ @@ -775,7 +775,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_SH4) env->pc = addr; #elif defined (TARGET_MIPS) - env->PC = addr; + env->PC[env->current_tc] = addr; #endif } #ifdef CONFIG_USER_ONLY @@ -799,7 +799,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) #elif defined (TARGET_SH4) env->pc = addr; #elif defined (TARGET_MIPS) - env->PC = addr; + env->PC[env->current_tc] = addr; #endif } cpu_single_step(env, 1); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 2208922a7..82782273b 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -77,7 +77,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) entry = (int32_t)entry; - env->PC = entry; + env->PC[env->current_tc] = entry; } else { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 6a517e184..2fe5e29c5 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -10,7 +10,7 @@ uint32_t cpu_mips_get_random (CPUState *env) static uint32_t seed = 0; uint32_t idx; seed = seed * 314159 + 1; - idx = (seed >> 16) % (env->nb_tlb - env->CP0_Wired) + env->CP0_Wired; + idx = (seed >> 16) % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired; return idx; } diff --git a/linux-user/main.c b/linux-user/main.c index 32fa43d47..edcb68b8d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1374,8 +1374,8 @@ void cpu_loop(CPUMIPSState *env) trapnr = cpu_mips_exec(env); switch(trapnr) { case EXCP_SYSCALL: - syscall_num = env->gpr[2] - 4000; - env->PC += 4; + syscall_num = env->gpr[2][env->current_tc] - 4000; + env->PC[env->current_tc] += 4; if (syscall_num >= sizeof(mips_syscall_args)) { ret = -ENOSYS; } else { @@ -1384,7 +1384,7 @@ void cpu_loop(CPUMIPSState *env) target_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; nb_args = mips_syscall_args[syscall_num]; - sp_reg = env->gpr[29]; + sp_reg = env->gpr[29][env->current_tc]; switch (nb_args) { /* these arguments are taken from the stack */ case 8: arg8 = tgetl(sp_reg + 28); @@ -1394,18 +1394,20 @@ void cpu_loop(CPUMIPSState *env) default: break; } - ret = do_syscall(env, env->gpr[2], - env->gpr[4], env->gpr[5], - env->gpr[6], env->gpr[7], + ret = do_syscall(env, env->gpr[2][env->current_tc], + env->gpr[4][env->current_tc], + env->gpr[5][env->current_tc], + env->gpr[6][env->current_tc], + env->gpr[7][env->current_tc], arg5, arg6/*, arg7, arg8*/); } if ((unsigned int)ret >= (unsigned int)(-1133)) { - env->gpr[7] = 1; /* error flag */ + env->gpr[7][env->current_tc] = 1; /* error flag */ ret = -ret; } else { - env->gpr[7] = 0; /* error flag */ + env->gpr[7][env->current_tc] = 0; /* error flag */ } - env->gpr[2] = ret; + env->gpr[2][env->current_tc] = ret; break; case EXCP_TLBL: case EXCP_TLBS: @@ -2053,9 +2055,9 @@ int main(int argc, char **argv) cpu_mips_register(env, def); for(i = 0; i < 32; i++) { - env->gpr[i] = regs->regs[i]; + env->gpr[i][env->current_tc] = regs->regs[i]; } - env->PC = regs->cp0_epc; + env->PC[env->current_tc] = regs->cp0_epc; } #elif defined(TARGET_SH4) { diff --git a/linux-user/signal.c b/linux-user/signal.c index eea73470f..f73d50516 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1686,10 +1686,10 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) { int err = 0; - err |= __put_user(regs->PC, &sc->sc_pc); + err |= __put_user(regs->PC[regs->current_tc], &sc->sc_pc); -#define save_gp_reg(i) do { \ - err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \ +#define save_gp_reg(i) do { \ + err |= __put_user(regs->gpr[i][regs->current_tc], &sc->sc_regs[i]); \ } while(0) __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); @@ -1702,8 +1702,8 @@ setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) save_gp_reg(31); #undef save_gp_reg - err |= __put_user(regs->HI, &sc->sc_mdhi); - err |= __put_user(regs->LO, &sc->sc_mdlo); + err |= __put_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi); + err |= __put_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo); /* Not used yet, but might be useful if we ever have DSP suppport */ #if 0 @@ -1763,11 +1763,11 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) err |= __get_user(regs->CP0_EPC, &sc->sc_pc); - err |= __get_user(regs->HI, &sc->sc_mdhi); - err |= __get_user(regs->LO, &sc->sc_mdlo); + err |= __get_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi); + err |= __get_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo); -#define restore_gp_reg(i) do { \ - err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \ +#define restore_gp_reg(i) do { \ + err |= __get_user(regs->gpr[i][regs->current_tc], &sc->sc_regs[i]); \ } while(0) restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); @@ -1833,7 +1833,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) unsigned long sp; /* Default to using normal stack */ - sp = regs->gpr[29]; + sp = regs->gpr[29][regs->current_tc]; /* * FPU emulator may have it's own trampoline active just @@ -1881,15 +1881,15 @@ static void setup_frame(int sig, struct emulated_sigaction * ka, * $25 and PC point to the signal handler, $29 points to the * struct sigframe. */ - regs->gpr[ 4] = sig; - regs->gpr[ 5] = 0; - regs->gpr[ 6] = h2g(&frame->sf_sc); - regs->gpr[29] = h2g(frame); - regs->gpr[31] = h2g(frame->sf_code); + regs->gpr[ 4][regs->current_tc] = sig; + regs->gpr[ 5][regs->current_tc] = 0; + regs->gpr[ 6][regs->current_tc] = h2g(&frame->sf_sc); + regs->gpr[29][regs->current_tc] = h2g(frame); + regs->gpr[31][regs->current_tc] = h2g(frame->sf_code); /* The original kernel code sets CP0_EPC to the handler * since it returns to userland using eret * we cannot do this here, and we must set PC directly */ - regs->PC = regs->gpr[25] = ka->sa._sa_handler; + regs->PC[regs->current_tc] = regs->gpr[25][regs->current_tc] = ka->sa._sa_handler; return; give_sigsegv: @@ -1907,7 +1907,7 @@ long do_sigreturn(CPUState *regs) #if defined(DEBUG_SIGNAL) fprintf(stderr, "do_sigreturn\n"); #endif - frame = (struct sigframe *) regs->gpr[29]; + frame = (struct sigframe *) regs->gpr[29][regs->current_tc]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -1934,7 +1934,7 @@ long do_sigreturn(CPUState *regs) /* Unreached */ #endif - regs->PC = regs->CP0_EPC; + regs->PC[regs->current_tc] = regs->CP0_EPC; /* I am not sure this is right, but it seems to work * maybe a problem with nested signals ? */ regs->CP0_EPC = 0; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e23a684e7..cd956aa1a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2189,8 +2189,8 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) /* ??? is this sufficient? */ #elif defined(TARGET_MIPS) if (!newsp) - newsp = env->gpr[29]; - new_env->gpr[29] = newsp; + newsp = env->gpr[29][env->current_tc]; + new_env->gpr[29][env->current_tc] = newsp; #elif defined(TARGET_PPC) if (!newsp) newsp = env->gpr[1]; @@ -2777,7 +2777,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(pipe(host_pipe)); if (!is_error(ret)) { #if defined(TARGET_MIPS) - ((CPUMIPSState*)cpu_env)->gpr[3] = host_pipe[1]; + CPUMIPSState *env = (CPUMIPSState*)cpu_env; + env->gpr[3][env->current_tc] = host_pipe[1]; ret = host_pipe[0]; #else tput32(arg1, host_pipe[0]); diff --git a/monitor.c b/monitor.c index 3b9408b55..9ff63130d 100644 --- a/monitor.c +++ b/monitor.c @@ -309,6 +309,10 @@ static void do_info_cpus(void) term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc); if (env->halted) term_printf(" (halted)"); +#elif defined(TARGET_MIPS) + term_printf(" PC=0x" TARGET_FMT_lx, env->PC[env->current_tc]); + if (env->halted) + term_printf(" (halted)"); #endif term_printf("\n"); } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f5f35e122..f8b4b1858 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -17,21 +17,7 @@ typedef unsigned char uint_fast8_t; typedef unsigned int uint_fast16_t; #endif -typedef union fpr_t fpr_t; -union fpr_t { - float64 fd; /* ieee double precision */ - float32 fs[2];/* ieee single precision */ - uint64_t d; /* binary double fixed-point */ - uint32_t w[2]; /* binary single fixed-point */ -}; -/* define FP_ENDIAN_IDX to access the same location - * in the fpr_t union regardless of the host endianess - */ -#if defined(WORDS_BIGENDIAN) -# define FP_ENDIAN_IDX 1 -#else -# define FP_ENDIAN_IDX 0 -#endif +struct CPUMIPSState; typedef struct r4k_tlb_t r4k_tlb_t; struct r4k_tlb_t { @@ -48,20 +34,40 @@ struct r4k_tlb_t { target_ulong PFN[2]; }; -typedef struct mips_def_t mips_def_t; +typedef struct CPUMIPSTLBContext CPUMIPSTLBContext; +struct CPUMIPSTLBContext { + uint32_t nb_tlb; + uint32_t tlb_in_use; + int (*map_address) (struct CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type); + void (*do_tlbwi) (void); + void (*do_tlbwr) (void); + void (*do_tlbp) (void); + void (*do_tlbr) (void); + union { + struct { + r4k_tlb_t tlb[MIPS_TLB_MAX]; + } r4k; + } mmu; +}; -typedef struct CPUMIPSState CPUMIPSState; -struct CPUMIPSState { - /* General integer registers */ - target_ulong gpr[32]; - /* Special registers */ - target_ulong PC; -#if TARGET_LONG_BITS > HOST_LONG_BITS - target_ulong t0; - target_ulong t1; - target_ulong t2; +typedef union fpr_t fpr_t; +union fpr_t { + float64 fd; /* ieee double precision */ + float32 fs[2];/* ieee single precision */ + uint64_t d; /* binary double fixed-point */ + uint32_t w[2]; /* binary single fixed-point */ +}; +/* define FP_ENDIAN_IDX to access the same location + * in the fpr_t union regardless of the host endianess + */ +#if defined(WORDS_BIGENDIAN) +# define FP_ENDIAN_IDX 1 +#else +# define FP_ENDIAN_IDX 0 #endif - target_ulong HI, LO; + +typedef struct CPUMIPSFPUContext CPUMIPSFPUContext; +struct CPUMIPSFPUContext { /* Floating point registers */ fpr_t fpr[32]; #ifndef USE_HOST_FLOAT_REGS @@ -99,30 +105,161 @@ struct CPUMIPSState { #define FP_DIV0 8 #define FP_INVALID 16 #define FP_UNIMPLEMENTED 32 +}; + +typedef struct CPUMIPSMVPContext CPUMIPSMVPContext; +struct CPUMIPSMVPContext { + int32_t CP0_MVPControl; +#define CP0MVPCo_CPA 3 +#define CP0MVPCo_STLB 2 +#define CP0MVPCo_VPC 1 +#define CP0MVPCo_EVP 0 + int32_t CP0_MVPConf0; +#define CP0MVPC0_M 31 +#define CP0MVPC0_TLBS 29 +#define CP0MVPC0_GS 28 +#define CP0MVPC0_PCP 27 +#define CP0MVPC0_PTLBE 16 +#define CP0MVPC0_TCA 15 +#define CP0MVPC0_PVPE 10 +#define CP0MVPC0_PTC 0 + int32_t CP0_MVPConf1; +#define CP0MVPC1_CIM 31 +#define CP0MVPC1_CIF 30 +#define CP0MVPC1_PCX 20 +#define CP0MVPC1_PCP2 10 +#define CP0MVPC1_PCP1 0 +}; + +typedef struct mips_def_t mips_def_t; + +#define MIPS_SHADOW_SET_MAX 16 +#define MIPS_TC_MAX 5 +#define MIPS_DSP_ACC 4 + +typedef struct CPUMIPSState CPUMIPSState; +struct CPUMIPSState { + /* General integer registers */ + target_ulong gpr[32][MIPS_SHADOW_SET_MAX]; + /* Special registers */ + target_ulong PC[MIPS_TC_MAX]; +#if TARGET_LONG_BITS > HOST_LONG_BITS + target_ulong t0; + target_ulong t1; + target_ulong t2; +#endif + target_ulong HI[MIPS_DSP_ACC][MIPS_TC_MAX]; + target_ulong LO[MIPS_DSP_ACC][MIPS_TC_MAX]; + target_ulong ACX[MIPS_DSP_ACC][MIPS_TC_MAX]; + target_ulong DSPControl[MIPS_TC_MAX]; + + CPUMIPSMVPContext *mvp; + CPUMIPSTLBContext *tlb; + CPUMIPSFPUContext *fpu; + uint32_t current_tc; - uint32_t nb_tlb; - uint32_t tlb_in_use; uint32_t SEGBITS; target_ulong SEGMask; - int (*map_address) (CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type); - void (*do_tlbwi) (void); - void (*do_tlbwr) (void); - void (*do_tlbp) (void); - void (*do_tlbr) (void); - union { - struct { - r4k_tlb_t tlb[MIPS_TLB_MAX]; - } r4k; - } mmu; int32_t CP0_Index; + /* CP0_MVP* are per MVP registers. */ int32_t CP0_Random; + int32_t CP0_VPEControl; +#define CP0VPECo_YSI 21 +#define CP0VPECo_GSI 20 +#define CP0VPECo_EXCPT 16 +#define CP0VPECo_TE 15 +#define CP0VPECo_TargTC 0 + int32_t CP0_VPEConf0; +#define CP0VPEC0_M 31 +#define CP0VPEC0_XTC 21 +#define CP0VPEC0_TCS 19 +#define CP0VPEC0_SCS 18 +#define CP0VPEC0_DSC 17 +#define CP0VPEC0_ICS 16 +#define CP0VPEC0_MVP 1 +#define CP0VPEC0_VPA 0 + int32_t CP0_VPEConf1; +#define CP0VPEC1_NCX 20 +#define CP0VPEC1_NCP2 10 +#define CP0VPEC1_NCP1 0 + target_ulong CP0_YQMask; + target_ulong CP0_VPESchedule; + target_ulong CP0_VPEScheFBack; + int32_t CP0_VPEOpt; +#define CP0VPEOpt_IWX7 15 +#define CP0VPEOpt_IWX6 14 +#define CP0VPEOpt_IWX5 13 +#define CP0VPEOpt_IWX4 12 +#define CP0VPEOpt_IWX3 11 +#define CP0VPEOpt_IWX2 10 +#define CP0VPEOpt_IWX1 9 +#define CP0VPEOpt_IWX0 8 +#define CP0VPEOpt_DWX7 7 +#define CP0VPEOpt_DWX6 6 +#define CP0VPEOpt_DWX5 5 +#define CP0VPEOpt_DWX4 4 +#define CP0VPEOpt_DWX3 3 +#define CP0VPEOpt_DWX2 2 +#define CP0VPEOpt_DWX1 1 +#define CP0VPEOpt_DWX0 0 target_ulong CP0_EntryLo0; + int32_t CP0_TCStatus[MIPS_TC_MAX]; +#define CP0TCSt_TCU3 31 +#define CP0TCSt_TCU2 30 +#define CP0TCSt_TCU1 29 +#define CP0TCSt_TCU0 28 +#define CP0TCSt_TMX 27 +#define CP0TCSt_RNST 23 +#define CP0TCSt_TDS 21 +#define CP0TCSt_DT 20 +#define CP0TCSt_DA 15 +#define CP0TCSt_A 13 +#define CP0TCSt_TKSU 11 +#define CP0TCSt_IXMT 10 +#define CP0TCSt_TASID 0 + int32_t CP0_TCBind[MIPS_TC_MAX]; +#define CP0TCBd_CurTC 21 +#define CP0TCBd_TBE 17 +#define CP0TCBd_CurVPE 0 + target_ulong CP0_TCHalt[MIPS_TC_MAX]; + target_ulong CP0_TCContext[MIPS_TC_MAX]; + target_ulong CP0_TCSchedule[MIPS_TC_MAX]; + target_ulong CP0_TCScheFBack[MIPS_TC_MAX]; target_ulong CP0_EntryLo1; target_ulong CP0_Context; int32_t CP0_PageMask; int32_t CP0_PageGrain; int32_t CP0_Wired; + int32_t CP0_SRSConf0_rw_bitmask; + int32_t CP0_SRSConf0; +#define CP0SRSC0_M 31 +#define CP0SRSC0_SRS3 20 +#define CP0SRSC0_SRS2 10 +#define CP0SRSC0_SRS1 0 + int32_t CP0_SRSConf1_rw_bitmask; + int32_t CP0_SRSConf1; +#define CP0SRSC1_M 31 +#define CP0SRSC1_SRS6 20 +#define CP0SRSC1_SRS5 10 +#define CP0SRSC1_SRS4 0 + int32_t CP0_SRSConf2_rw_bitmask; + int32_t CP0_SRSConf2; +#define CP0SRSC2_M 31 +#define CP0SRSC2_SRS9 20 +#define CP0SRSC2_SRS8 10 +#define CP0SRSC2_SRS7 0 + int32_t CP0_SRSConf3_rw_bitmask; + int32_t CP0_SRSConf3; +#define CP0SRSC3_M 31 +#define CP0SRSC3_SRS12 20 +#define CP0SRSC3_SRS11 10 +#define CP0SRSC3_SRS10 0 + int32_t CP0_SRSConf4_rw_bitmask; + int32_t CP0_SRSConf4; +#define CP0SRSC4_SRS15 20 +#define CP0SRSC4_SRS14 10 +#define CP0SRSC4_SRS13 0 int32_t CP0_HWREna; target_ulong CP0_BadVAddr; int32_t CP0_Count; @@ -152,8 +289,24 @@ struct CPUMIPSState { #define CP0St_EXL 1 #define CP0St_IE 0 int32_t CP0_IntCtl; +#define CP0IntCtl_IPTI 29 +#define CP0IntCtl_IPPC1 26 +#define CP0IntCtl_VS 5 int32_t CP0_SRSCtl; +#define CP0SRSCtl_HSS 26 +#define CP0SRSCtl_EICSS 18 +#define CP0SRSCtl_ESS 12 +#define CP0SRSCtl_PSS 6 +#define CP0SRSCtl_CSS 0 int32_t CP0_SRSMap; +#define CP0SRSMap_SSV7 28 +#define CP0SRSMap_SSV6 24 +#define CP0SRSMap_SSV5 20 +#define CP0SRSMap_SSV4 16 +#define CP0SRSMap_SSV3 12 +#define CP0SRSMap_SSV2 8 +#define CP0SRSMap_SSV1 4 +#define CP0SRSMap_SSV0 0 int32_t CP0_Cause; #define CP0Ca_BD 31 #define CP0Ca_TI 30 @@ -219,13 +372,14 @@ struct CPUMIPSState { #define CP0C3_TL 0 int32_t CP0_Config6; int32_t CP0_Config7; + /* XXX: Maybe make LLAddr per-TC? */ target_ulong CP0_LLAddr; target_ulong CP0_WatchLo[8]; int32_t CP0_WatchHi[8]; target_ulong CP0_XContext; int32_t CP0_Framemask; int32_t CP0_Debug; -#define CPDB_DBD 31 +#define CP0DB_DBD 31 #define CP0DB_DM 30 #define CP0DB_LSNM 28 #define CP0DB_Doze 27 @@ -243,6 +397,7 @@ struct CPUMIPSState { #define CP0DB_DDBL 2 #define CP0DB_DBp 1 #define CP0DB_DSS 0 + int32_t CP0_Debug_tcstatus[MIPS_TC_MAX]; target_ulong CP0_DEPC; int32_t CP0_Performance0; int32_t CP0_TagLo; @@ -284,7 +439,8 @@ struct CPUMIPSState { int SYNCI_Step; /* Address step size for SYNCI */ int CCRes; /* Cycle count resolution/divisor */ - int Status_rw_bitmask; /* Read/write bits in CP0_Status */ + uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */ + uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */ #ifdef CONFIG_USER_ONLY target_ulong tls_value; @@ -376,6 +532,7 @@ enum { EXCP_TLBS, EXCP_DBE, EXCP_DDBL, + EXCP_THREAD, EXCP_MTCP0 = 0x104, /* mtmsr instruction: */ /* may change privilege level */ EXCP_BRANCH = 0x108, /* branch instruction */ diff --git a/target-mips/exec.h b/target-mips/exec.h index 5b0c83384..53c4189a5 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -23,24 +23,24 @@ register target_ulong T2 asm(AREG3); #if defined (USE_HOST_FLOAT_REGS) #error "implement me." #else -#define FDT0 (env->ft0.fd) -#define FDT1 (env->ft1.fd) -#define FDT2 (env->ft2.fd) -#define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) -#define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) -#define FST2 (env->ft2.fs[FP_ENDIAN_IDX]) -#define FSTH0 (env->ft0.fs[!FP_ENDIAN_IDX]) -#define FSTH1 (env->ft1.fs[!FP_ENDIAN_IDX]) -#define FSTH2 (env->ft2.fs[!FP_ENDIAN_IDX]) -#define DT0 (env->ft0.d) -#define DT1 (env->ft1.d) -#define DT2 (env->ft2.d) -#define WT0 (env->ft0.w[FP_ENDIAN_IDX]) -#define WT1 (env->ft1.w[FP_ENDIAN_IDX]) -#define WT2 (env->ft2.w[FP_ENDIAN_IDX]) -#define WTH0 (env->ft0.w[!FP_ENDIAN_IDX]) -#define WTH1 (env->ft1.w[!FP_ENDIAN_IDX]) -#define WTH2 (env->ft2.w[!FP_ENDIAN_IDX]) +#define FDT0 (env->fpu->ft0.fd) +#define FDT1 (env->fpu->ft1.fd) +#define FDT2 (env->fpu->ft2.fd) +#define FST0 (env->fpu->ft0.fs[FP_ENDIAN_IDX]) +#define FST1 (env->fpu->ft1.fs[FP_ENDIAN_IDX]) +#define FST2 (env->fpu->ft2.fs[FP_ENDIAN_IDX]) +#define FSTH0 (env->fpu->ft0.fs[!FP_ENDIAN_IDX]) +#define FSTH1 (env->fpu->ft1.fs[!FP_ENDIAN_IDX]) +#define FSTH2 (env->fpu->ft2.fs[!FP_ENDIAN_IDX]) +#define DT0 (env->fpu->ft0.d) +#define DT1 (env->fpu->ft1.d) +#define DT2 (env->fpu->ft2.d) +#define WT0 (env->fpu->ft0.w[FP_ENDIAN_IDX]) +#define WT1 (env->fpu->ft1.w[FP_ENDIAN_IDX]) +#define WT2 (env->fpu->ft2.w[FP_ENDIAN_IDX]) +#define WTH0 (env->fpu->ft0.w[!FP_ENDIAN_IDX]) +#define WTH1 (env->fpu->ft1.w[!FP_ENDIAN_IDX]) +#define WTH2 (env->fpu->ft2.w[!FP_ENDIAN_IDX]) #endif #if defined (DEBUG_OP) @@ -157,7 +157,8 @@ void cpu_mips_update_irq (CPUState *env); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); -void do_ctc1 (void); +void do_cfc1 (int reg); +void do_ctc1 (int reg); #define FOP_PROTO(op) \ void do_float_ ## op ## _s(void); \ diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index 0f1595ff8..bbdcb2890 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -24,14 +24,14 @@ #define OP_WLOAD_FREG(treg, tregname, FREG) \ void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ - treg = env->fpr[FREG].fs[FP_ENDIAN_IDX]; \ + treg = env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX]; \ RETURN(); \ } #define OP_WSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ - env->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \ RETURN(); \ } @@ -50,10 +50,10 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ if (env->hflags & MIPS_HFLAG_F64) \ - treg = env->fpr[FREG].fd; \ + treg = env->fpu->fpr[FREG].fd; \ else \ - treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ - env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \ + treg = (uint64_t)(env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ + env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \ RETURN(); \ } @@ -61,10 +61,10 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ if (env->hflags & MIPS_HFLAG_F64) \ - env->fpr[FREG].fd = treg; \ + env->fpu->fpr[FREG].fd = treg; \ else { \ - env->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ - env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ + env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \ } \ RETURN(); \ } @@ -81,14 +81,14 @@ OP_DSTORE_FREG(DT2, DT2_fpr, FREG) #define OP_PSLOAD_FREG(treg, tregname, FREG) \ void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ - treg = env->fpr[FREG].fs[!FP_ENDIAN_IDX]; \ + treg = env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX]; \ RETURN(); \ } #define OP_PSSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ - env->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \ RETURN(); \ } diff --git a/target-mips/helper.c b/target-mips/helper.c index 1c8370470..6d0be1015 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -70,8 +70,8 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, uint8_t ASID = env->CP0_EntryHi & 0xFF; int i; - for (i = 0; i < env->tlb_in_use; i++) { - r4k_tlb_t *tlb = &env->mmu.r4k.tlb[i]; + for (i = 0; i < env->tlb->tlb_in_use; i++) { + r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); target_ulong tag = address & ~mask; @@ -134,7 +134,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, *physical = address & 0xFFFFFFFF; *prot = PAGE_READ | PAGE_WRITE; } else { - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } #ifdef TARGET_MIPS64 /* @@ -144,14 +144,14 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else if (address < 0x3FFFFFFFFFFFFFFFULL) { /* xuseg */ if (UX && address < (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } } else if (address < 0x7FFFFFFFFFFFFFFFULL) { /* xsseg */ if (SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } @@ -169,7 +169,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, /* xkseg */ /* XXX: check supervisor mode */ if (KX && address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } @@ -186,12 +186,12 @@ static int get_physical_address (CPUState *env, target_ulong *physical, *prot = PAGE_READ | PAGE_WRITE; } else if (address < (int32_t)0xE0000000UL) { /* kseg2 */ - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { /* kseg3 */ /* XXX: check supervisor mode */ /* XXX: debug segment is not emulated */ - ret = env->map_address(env, physical, prot, address, rw, access_type); + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } #if 0 if (logfile) { @@ -238,7 +238,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, cpu_dump_state(env, logfile, fprintf, 0); #endif fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d is_user %d smmu %d\n", - __func__, env->PC, address, rw, is_user, is_softmmu); + __func__, env->PC[env->current_tc], address, rw, is_user, is_softmmu); } rw &= 1; @@ -328,7 +328,7 @@ void do_interrupt (CPUState *env) if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n", - __func__, env->PC, env->CP0_EPC, cause, env->exception_index); + __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index); } if (env->exception_index == EXCP_EXT_INTERRUPT && (env->hflags & MIPS_HFLAG_DM)) @@ -342,7 +342,7 @@ void do_interrupt (CPUState *env) * (but we assume the pc has always been updated during * code translation). */ - env->CP0_DEPC = env->PC; + env->CP0_DEPC = env->PC[env->current_tc]; goto enter_debug_mode; case EXCP_DINT: env->CP0_Debug |= 1 << CP0DB_DINT; @@ -362,10 +362,10 @@ void do_interrupt (CPUState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_DEPC = env->PC - 4; + env->CP0_DEPC = env->PC[env->current_tc] - 4; env->hflags &= ~MIPS_HFLAG_BMASK; } else { - env->CP0_DEPC = env->PC; + env->CP0_DEPC = env->PC[env->current_tc]; } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; @@ -375,7 +375,7 @@ void do_interrupt (CPUState *env) /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); - env->PC = (int32_t)0xBFC00480; + env->PC[env->current_tc] = (int32_t)0xBFC00480; break; case EXCP_RESET: cpu_reset(env); @@ -390,10 +390,10 @@ void do_interrupt (CPUState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_ErrorEPC = env->PC - 4; + env->CP0_ErrorEPC = env->PC[env->current_tc] - 4; env->hflags &= ~MIPS_HFLAG_BMASK; } else { - env->CP0_ErrorEPC = env->PC; + env->CP0_ErrorEPC = env->PC[env->current_tc]; } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) @@ -401,7 +401,7 @@ void do_interrupt (CPUState *env) env->hflags &= ~MIPS_HFLAG_UM; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); - env->PC = (int32_t)0xBFC00000; + env->PC[env->current_tc] = (int32_t)0xBFC00000; break; case EXCP_MCHECK: cause = 24; @@ -471,6 +471,9 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBS: cause = 3; + goto set_EPC; + case EXCP_THREAD: + cause = 25; if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { #ifdef TARGET_MIPS64 int R = env->CP0_BadVAddr >> 62; @@ -489,10 +492,10 @@ void do_interrupt (CPUState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_EPC = env->PC - 4; + env->CP0_EPC = env->PC[env->current_tc] - 4; env->CP0_Cause |= (1 << CP0Ca_BD); } else { - env->CP0_EPC = env->PC; + env->CP0_EPC = env->PC[env->current_tc]; env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); @@ -502,11 +505,11 @@ void do_interrupt (CPUState *env) } env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { - env->PC = (int32_t)0xBFC00200; + env->PC[env->current_tc] = (int32_t)0xBFC00200; } else { - env->PC = (int32_t)(env->CP0_EBase & ~0x3ff); + env->PC[env->current_tc] = (int32_t)(env->CP0_EBase & ~0x3ff); } - env->PC += offset; + env->PC[env->current_tc] += offset; env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); break; default: @@ -520,7 +523,7 @@ void do_interrupt (CPUState *env) if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) { fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n" " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", - __func__, env->PC, env->CP0_EPC, cause, env->exception_index, + __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index, env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, env->CP0_DEPC); } @@ -536,19 +539,19 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) uint8_t ASID = env->CP0_EntryHi & 0xFF; target_ulong mask; - tlb = &env->mmu.r4k.tlb[idx]; + tlb = &env->tlb->mmu.r4k.tlb[idx]; /* The qemu TLB is flushed when the ASID changes, so no need to flush these entries again. */ if (tlb->G == 0 && tlb->ASID != ASID) { return; } - if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) { + if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) { /* For tlbwr, we can shadow the discarded entry into a new (fake) TLB entry, as long as the guest can not tell that it's there. */ - env->mmu.r4k.tlb[env->tlb_in_use] = *tlb; - env->tlb_in_use++; + env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb; + env->tlb->tlb_in_use++; return; } diff --git a/target-mips/op.c b/target-mips/op.c index 12498d033..3f52f59d3 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -254,25 +254,25 @@ void op_dup_T0 (void) void op_load_HI (void) { - T0 = env->HI; + T0 = env->HI[PARAM1][env->current_tc]; RETURN(); } void op_store_HI (void) { - env->HI = T0; + env->HI[PARAM1][env->current_tc] = T0; RETURN(); } void op_load_LO (void) { - T0 = env->LO; + T0 = env->LO[PARAM1][env->current_tc]; RETURN(); } void op_store_LO (void) { - env->LO = T0; + env->LO[PARAM1][env->current_tc] = T0; RETURN(); } @@ -363,8 +363,8 @@ void op_div (void) void op_div (void) { if (T1 != 0) { - env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); - env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); + env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); + env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); } RETURN(); } @@ -373,8 +373,8 @@ void op_div (void) void op_divu (void) { if (T1 != 0) { - env->LO = (int32_t)((uint32_t)T0 / (uint32_t)T1); - env->HI = (int32_t)((uint32_t)T0 % (uint32_t)T1); + env->LO[0][env->current_tc] = (int32_t)((uint32_t)T0 / (uint32_t)T1); + env->HI[0][env->current_tc] = (int32_t)((uint32_t)T0 % (uint32_t)T1); } RETURN(); } @@ -442,8 +442,8 @@ void op_ddivu (void) void op_ddivu (void) { if (T1 != 0) { - env->LO = T0 / T1; - env->HI = T0 % T1; + env->LO[0][env->current_tc] = T0 / T1; + env->HI[0][env->current_tc] = T0 % T1; } RETURN(); } @@ -814,13 +814,14 @@ void op_msubu (void) static inline uint64_t get_HILO (void) { - return ((uint64_t)env->HI << 32) | ((uint64_t)(uint32_t)env->LO); + return ((uint64_t)env->HI[0][env->current_tc] << 32) | + ((uint64_t)(uint32_t)env->LO[0][env->current_tc]); } static inline void set_HILO (uint64_t HILO) { - env->LO = (int32_t)(HILO & 0xFFFFFFFF); - env->HI = (int32_t)(HILO >> 32); + env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF); + env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); } void op_mult (void) @@ -875,13 +876,13 @@ void op_msubu (void) #ifdef TARGET_MIPS64 void op_dmult (void) { - CALL_FROM_TB4(muls64, &(env->HI), &(env->LO), T0, T1); + CALL_FROM_TB4(muls64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1); RETURN(); } void op_dmultu (void) { - CALL_FROM_TB4(mulu64, &(env->HI), &(env->LO), T0, T1); + CALL_FROM_TB4(mulu64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1); RETURN(); } #endif @@ -890,27 +891,27 @@ void op_dmultu (void) void op_movn (void) { if (T1 != 0) - env->gpr[PARAM1] = T0; + env->gpr[PARAM1][env->current_tc] = T0; RETURN(); } void op_movz (void) { if (T1 == 0) - env->gpr[PARAM1] = T0; + env->gpr[PARAM1][env->current_tc] = T0; RETURN(); } void op_movf (void) { - if (!(env->fcr31 & PARAM1)) + if (!(env->fpu->fcr31 & PARAM1)) T0 = T1; RETURN(); } void op_movt (void) { - if (env->fcr31 & PARAM1) + if (env->fpu->fcr31 & PARAM1) T0 = T1; RETURN(); } @@ -966,7 +967,7 @@ void op_restore_breg_target (void) void op_breg (void) { - env->PC = T2; + env->PC[env->current_tc] = T2; RETURN(); } @@ -1017,18 +1018,176 @@ void op_mfc0_index (void) RETURN(); } +void op_mfc0_mvpcontrol (void) +{ + T0 = env->mvp->CP0_MVPControl; + RETURN(); +} + +void op_mfc0_mvpconf0 (void) +{ + T0 = env->mvp->CP0_MVPConf0; + RETURN(); +} + +void op_mfc0_mvpconf1 (void) +{ + T0 = env->mvp->CP0_MVPConf1; + RETURN(); +} + void op_mfc0_random (void) { CALL_FROM_TB0(do_mfc0_random); RETURN(); } +void op_mfc0_vpecontrol (void) +{ + T0 = env->CP0_VPEControl; + RETURN(); +} + +void op_mfc0_vpeconf0 (void) +{ + T0 = env->CP0_VPEConf0; + RETURN(); +} + +void op_mfc0_vpeconf1 (void) +{ + T0 = env->CP0_VPEConf1; + RETURN(); +} + +void op_mfc0_yqmask (void) +{ + T0 = env->CP0_YQMask; + RETURN(); +} + +void op_mfc0_vpeschedule (void) +{ + T0 = env->CP0_VPESchedule; + RETURN(); +} + +void op_mfc0_vpeschefback (void) +{ + T0 = env->CP0_VPEScheFBack; + RETURN(); +} + +void op_mfc0_vpeopt (void) +{ + T0 = env->CP0_VPEOpt; + RETURN(); +} + void op_mfc0_entrylo0 (void) { T0 = (int32_t)env->CP0_EntryLo0; RETURN(); } +void op_mfc0_tcstatus (void) +{ + T0 = env->CP0_TCStatus[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcstatus(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCStatus[other_tc]; + RETURN(); +} + +void op_mfc0_tcbind (void) +{ + T0 = env->CP0_TCBind[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcbind(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCBind[other_tc]; + RETURN(); +} + +void op_mfc0_tcrestart (void) +{ + T0 = env->PC[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcrestart(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->PC[other_tc]; + RETURN(); +} + +void op_mfc0_tchalt (void) +{ + T0 = env->CP0_TCHalt[env->current_tc]; + RETURN(); +} + +void op_mftc0_tchalt(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCHalt[other_tc]; + RETURN(); +} + +void op_mfc0_tccontext (void) +{ + T0 = env->CP0_TCContext[env->current_tc]; + RETURN(); +} + +void op_mftc0_tccontext(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCContext[other_tc]; + RETURN(); +} + +void op_mfc0_tcschedule (void) +{ + T0 = env->CP0_TCSchedule[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcschedule(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCSchedule[other_tc]; + RETURN(); +} + +void op_mfc0_tcschefback (void) +{ + T0 = env->CP0_TCScheFBack[env->current_tc]; + RETURN(); +} + +void op_mftc0_tcschefback(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->CP0_TCScheFBack[other_tc]; + RETURN(); +} + void op_mfc0_entrylo1 (void) { T0 = (int32_t)env->CP0_EntryLo1; @@ -1059,6 +1218,36 @@ void op_mfc0_wired (void) RETURN(); } +void op_mfc0_srsconf0 (void) +{ + T0 = env->CP0_SRSConf0; + RETURN(); +} + +void op_mfc0_srsconf1 (void) +{ + T0 = env->CP0_SRSConf1; + RETURN(); +} + +void op_mfc0_srsconf2 (void) +{ + T0 = env->CP0_SRSConf2; + RETURN(); +} + +void op_mfc0_srsconf3 (void) +{ + T0 = env->CP0_SRSConf3; + RETURN(); +} + +void op_mfc0_srsconf4 (void) +{ + T0 = env->CP0_SRSConf4; + RETURN(); +} + void op_mfc0_hwrena (void) { T0 = env->CP0_HWREna; @@ -1083,6 +1272,14 @@ void op_mfc0_entryhi (void) RETURN(); } +void op_mftc0_entryhi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff); + RETURN(); +} + void op_mfc0_compare (void) { T0 = env->CP0_Compare; @@ -1095,6 +1292,18 @@ void op_mfc0_status (void) RETURN(); } +void op_mftc0_status(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t tcstatus = env->CP0_TCStatus[other_tc]; + + T0 = env->CP0_Status & ~0xf1000018; + T0 |= tcstatus & (0xf << CP0TCSt_TCU0); + T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); + T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_R0); + RETURN(); +} + void op_mfc0_intctl (void) { T0 = env->CP0_IntCtl; @@ -1211,6 +1420,17 @@ void op_mfc0_debug (void) RETURN(); } +void op_mftc0_debug(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + /* XXX: Might be wrong, check with EJTAG spec. */ + T0 = (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | + (env->CP0_Debug_tcstatus[other_tc] & + ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); + RETURN(); +} + void op_mfc0_depc (void) { T0 = (int32_t)env->CP0_DEPC; @@ -1261,7 +1481,105 @@ void op_mfc0_desave (void) void op_mtc0_index (void) { - env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->nb_tlb); + env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->tlb->nb_tlb); + RETURN(); +} + +void op_mtc0_mvpcontrol (void) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) + mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) | + (1 << CP0MVPCo_EVP); + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0MVPCo_STLB); + newval = (env->mvp->CP0_MVPControl & ~mask) | (T0 & mask); + + // TODO: Enable/disable shared TLB, enable/disable VPEs. + + env->mvp->CP0_MVPControl = newval; + RETURN(); +} + +void op_mtc0_vpecontrol (void) +{ + uint32_t mask; + uint32_t newval; + + mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) | + (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC); + newval = (env->CP0_VPEControl & ~mask) | (T0 & mask); + + /* Yield scheduler intercept not implemented. */ + /* Gating storage scheduler intercept not implemented. */ + + // TODO: Enable/disable TCs. + + env->CP0_VPEControl = newval; + RETURN(); +} + +void op_mtc0_vpeconf0 (void) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) { + if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) + mask |= (0xff << CP0VPEC0_XTC); + mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); + } + newval = (env->CP0_VPEConf0 & ~mask) | (T0 & mask); + + // TODO: TC exclusive handling due to ERL/EXL. + + env->CP0_VPEConf0 = newval; + RETURN(); +} + +void op_mtc0_vpeconf1 (void) +{ + uint32_t mask = 0; + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) | + (0xff << CP0VPEC1_NCP1); + newval = (env->CP0_VPEConf1 & ~mask) | (T0 & mask); + + /* UDI not implemented. */ + /* CP2 not implemented. */ + + // TODO: Handle FPU (CP1) binding. + + env->CP0_VPEConf1 = newval; + RETURN(); +} + +void op_mtc0_yqmask (void) +{ + /* Yield qualifier inputs not implemented. */ + env->CP0_YQMask = 0x00000000; + RETURN(); +} + +void op_mtc0_vpeschedule (void) +{ + env->CP0_VPESchedule = T0; + RETURN(); +} + +void op_mtc0_vpeschefback (void) +{ + env->CP0_VPEScheFBack = T0; + RETURN(); +} + +void op_mtc0_vpeopt (void) +{ + env->CP0_VPEOpt = T0 & 0x0000ffff; RETURN(); } @@ -1273,6 +1591,135 @@ void op_mtc0_entrylo0 (void) RETURN(); } +void op_mtc0_tcstatus (void) +{ + uint32_t mask = env->CP0_TCStatus_rw_bitmask; + uint32_t newval; + + newval = (env->CP0_TCStatus[env->current_tc] & ~mask) | (T0 & mask); + + // TODO: Sync with CP0_Status. + + env->CP0_TCStatus[env->current_tc] = newval; + RETURN(); +} + +void op_mttc0_tcstatus (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + // TODO: Sync with CP0_Status. + + env->CP0_TCStatus[other_tc] = T0; + RETURN(); +} + +void op_mtc0_tcbind (void) +{ + uint32_t mask = (1 << CP0TCBd_TBE); + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0TCBd_CurVPE); + newval = (env->CP0_TCBind[env->current_tc] & ~mask) | (T0 & mask); + env->CP0_TCBind[env->current_tc] = newval; + RETURN(); +} + +void op_mttc0_tcbind (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t mask = (1 << CP0TCBd_TBE); + uint32_t newval; + + if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0TCBd_CurVPE); + newval = (env->CP0_TCBind[other_tc] & ~mask) | (T0 & mask); + env->CP0_TCBind[other_tc] = newval; + RETURN(); +} + +void op_mtc0_tcrestart (void) +{ + env->PC[env->current_tc] = T0; + env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS); + env->CP0_LLAddr = 0ULL; + /* MIPS16 not implemented. */ + RETURN(); +} + +void op_mttc0_tcrestart (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->PC[other_tc] = T0; + env->CP0_TCStatus[other_tc] &= ~(1 << CP0TCSt_TDS); + env->CP0_LLAddr = 0ULL; + /* MIPS16 not implemented. */ + RETURN(); +} + +void op_mtc0_tchalt (void) +{ + env->CP0_TCHalt[env->current_tc] = T0 & 0x1; + + // TODO: Halt TC / Restart (if allocated+active) TC. + + RETURN(); +} + +void op_mttc0_tchalt (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + // TODO: Halt TC / Restart (if allocated+active) TC. + + env->CP0_TCHalt[other_tc] = T0; + RETURN(); +} + +void op_mtc0_tccontext (void) +{ + env->CP0_TCContext[env->current_tc] = T0; + RETURN(); +} + +void op_mttc0_tccontext (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->CP0_TCContext[other_tc] = T0; + RETURN(); +} + +void op_mtc0_tcschedule (void) +{ + env->CP0_TCSchedule[env->current_tc] = T0; + RETURN(); +} + +void op_mttc0_tcschedule (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->CP0_TCSchedule[other_tc] = T0; + RETURN(); +} + +void op_mtc0_tcschefback (void) +{ + env->CP0_TCScheFBack[env->current_tc] = T0; + RETURN(); +} + +void op_mttc0_tcschefback (void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->CP0_TCScheFBack[other_tc] = T0; + RETURN(); +} + void op_mtc0_entrylo1 (void) { /* Large physaddr not implemented */ @@ -1305,7 +1752,37 @@ void op_mtc0_pagegrain (void) void op_mtc0_wired (void) { - env->CP0_Wired = T0 % env->nb_tlb; + env->CP0_Wired = T0 % env->tlb->nb_tlb; + RETURN(); +} + +void op_mtc0_srsconf0 (void) +{ + env->CP0_SRSConf0 |= T0 & env->CP0_SRSConf0_rw_bitmask; + RETURN(); +} + +void op_mtc0_srsconf1 (void) +{ + env->CP0_SRSConf1 |= T0 & env->CP0_SRSConf1_rw_bitmask; + RETURN(); +} + +void op_mtc0_srsconf2 (void) +{ + env->CP0_SRSConf2 |= T0 & env->CP0_SRSConf2_rw_bitmask; + RETURN(); +} + +void op_mtc0_srsconf3 (void) +{ + env->CP0_SRSConf3 |= T0 & env->CP0_SRSConf3_rw_bitmask; + RETURN(); +} + +void op_mtc0_srsconf4 (void) +{ + env->CP0_SRSConf4 |= T0 & env->CP0_SRSConf4_rw_bitmask; RETURN(); } @@ -1332,12 +1809,25 @@ void op_mtc0_entryhi (void) #endif old = env->CP0_EntryHi; env->CP0_EntryHi = val; + if (env->CP0_Config3 & (1 << CP0C3_MT)) { + uint32_t tcst = env->CP0_TCStatus[env->current_tc] & ~0xff; + env->CP0_TCStatus[env->current_tc] = tcst | (val & 0xff); + } /* If the ASID changes, flush qemu's TLB. */ if ((old & 0xFF) != (val & 0xFF)) CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1); RETURN(); } +void op_mttc0_entryhi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (T0 & ~0xff); + env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (T0 & 0xff); + RETURN(); +} + void op_mtc0_compare (void) { CALL_FROM_TB2(cpu_mips_store_compare, env, T0); @@ -1347,9 +1837,8 @@ void op_mtc0_compare (void) void op_mtc0_status (void) { uint32_t val, old; - uint32_t mask = env->Status_rw_bitmask; + uint32_t mask = env->CP0_Status_rw_bitmask; - /* No reverse endianness, no MDMX/DSP implemented. */ val = T0 & mask; old = env->CP0_Status; if (!(val & (1 << CP0St_EXL)) && @@ -1379,6 +1868,19 @@ void op_mtc0_status (void) RETURN(); } +void op_mttc0_status(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t tcstatus = env->CP0_TCStatus[other_tc]; + + env->CP0_Status = T0 & ~0xf1000018; + tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (T0 & (0xf << CP0St_CU0)); + tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((T0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); + tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_R0)) << (CP0TCSt_TKSU - CP0St_R0)); + env->CP0_TCStatus[other_tc] = tcstatus; + RETURN(); +} + void op_mtc0_intctl (void) { /* vectored interrupts not implemented, timer on int 7, @@ -1389,15 +1891,14 @@ void op_mtc0_intctl (void) void op_mtc0_srsctl (void) { - /* shadow registers not implemented */ - env->CP0_SRSCtl = 0; + uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); + env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (T0 & mask); RETURN(); } void op_mtc0_srsmap (void) { - /* shadow registers not implemented */ - env->CP0_SRSMap = 0; + env->CP0_SRSMap = T0; RETURN(); } @@ -1460,6 +1961,13 @@ void op_mtc0_watchhi (void) RETURN(); } +void op_mtc0_xcontext (void) +{ + target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; + env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask); + RETURN(); +} + void op_mtc0_framemask (void) { env->CP0_Framemask = T0; /* XXX */ @@ -1476,6 +1984,17 @@ void op_mtc0_debug (void) RETURN(); } +void op_mttc0_debug(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + /* XXX: Might be wrong, check with EJTAG spec. */ + env->CP0_Debug_tcstatus[other_tc] = T0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); + env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | + (T0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); + RETURN(); +} + void op_mtc0_depc (void) { env->CP0_DEPC = T0; @@ -1525,10 +2044,21 @@ void op_mtc0_desave (void) } #ifdef TARGET_MIPS64 -void op_mtc0_xcontext (void) +void op_dmfc0_yqmask (void) { - target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; - env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask); + T0 = env->CP0_YQMask; + RETURN(); +} + +void op_dmfc0_vpeschedule (void) +{ + T0 = env->CP0_VPESchedule; + RETURN(); +} + +void op_dmfc0_vpeschefback (void) +{ + T0 = env->CP0_VPEScheFBack; RETURN(); } @@ -1538,6 +2068,36 @@ void op_dmfc0_entrylo0 (void) RETURN(); } +void op_dmfc0_tcrestart (void) +{ + T0 = env->PC[env->current_tc]; + RETURN(); +} + +void op_dmfc0_tchalt (void) +{ + T0 = env->CP0_TCHalt[env->current_tc]; + RETURN(); +} + +void op_dmfc0_tccontext (void) +{ + T0 = env->CP0_TCContext[env->current_tc]; + RETURN(); +} + +void op_dmfc0_tcschedule (void) +{ + T0 = env->CP0_TCSchedule[env->current_tc]; + RETURN(); +} + +void op_dmfc0_tcschefback (void) +{ + T0 = env->CP0_TCScheFBack[env->current_tc]; + RETURN(); +} + void op_dmfc0_entrylo1 (void) { T0 = env->CP0_EntryLo1; @@ -1599,6 +2159,157 @@ void op_dmfc0_errorepc (void) } #endif /* TARGET_MIPS64 */ +/* MIPS MT functions */ +void op_mftgpr(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->gpr[PARAM1][other_tc]; + RETURN(); +} + +void op_mftlo(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->LO[PARAM1][other_tc]; + RETURN(); +} + +void op_mfthi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->HI[PARAM1][other_tc]; + RETURN(); +} + +void op_mftacx(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->ACX[PARAM1][other_tc]; + RETURN(); +} + +void op_mftdsp(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->DSPControl[other_tc]; + RETURN(); +} + +void op_mttgpr(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->gpr[PARAM1][other_tc]; + RETURN(); +} + +void op_mttlo(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->LO[PARAM1][other_tc]; + RETURN(); +} + +void op_mtthi(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->HI[PARAM1][other_tc]; + RETURN(); +} + +void op_mttacx(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->ACX[PARAM1][other_tc]; + RETURN(); +} + +void op_mttdsp(void) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + T0 = env->DSPControl[other_tc]; + RETURN(); +} + + +void op_dmt(void) +{ + // TODO + T0 = 0; + // rt = T0 + RETURN(); +} + +void op_emt(void) +{ + // TODO + T0 = 0; + // rt = T0 + RETURN(); +} + +void op_dvpe(void) +{ + // TODO + T0 = 0; + // rt = T0 + RETURN(); +} + +void op_evpe(void) +{ + // TODO + T0 = 0; + // rt = T0 + RETURN(); +} + +void op_fork(void) +{ + // T0 = rt, T1 = rs + T0 = 0; + // TODO: store to TC register + RETURN(); +} + +void op_yield(void) +{ + if (T0 < 0) { + /* No scheduling policy implemented. */ + if (T0 != -2) { + if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) && + env->CP0_TCStatus[env->current_tc] & (1 << CP0TCSt_DT)) { + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; + CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); + } + } + } else if (T0 == 0) { + if (0 /* TODO: TC underflow */) { + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); + } else { + // TODO: Deallocate TC + } + } else if (T0 > 0) { + /* Yield qualifier inputs not implemented. */ + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; + CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); + } + T0 = env->CP0_YQMask; + RETURN(); +} + /* CP1 functions */ #if 0 # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env) @@ -1617,30 +2328,14 @@ void op_cp0_enabled(void) void op_cfc1 (void) { - switch (T1) { - case 0: - T0 = (int32_t)env->fcr0; - break; - case 25: - T0 = ((env->fcr31 >> 24) & 0xfe) | ((env->fcr31 >> 23) & 0x1); - break; - case 26: - T0 = env->fcr31 & 0x0003f07c; - break; - case 28: - T0 = (env->fcr31 & 0x00000f83) | ((env->fcr31 >> 22) & 0x4); - break; - default: - T0 = (int32_t)env->fcr31; - break; - } + CALL_FROM_TB1(do_cfc1, PARAM1); DEBUG_FPU_STATE(); RETURN(); } void op_ctc1 (void) { - CALL_FROM_TB0(do_ctc1); + CALL_FROM_TB1(do_ctc1, PARAM1); DEBUG_FPU_STATE(); RETURN(); } @@ -1842,21 +2537,21 @@ FLOAT_ROUNDOP(floor, w, s) FLOAT_OP(movf, d) { - if (!(env->fcr31 & PARAM1)) + if (!(env->fpu->fcr31 & PARAM1)) DT2 = DT0; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(movf, s) { - if (!(env->fcr31 & PARAM1)) + if (!(env->fpu->fcr31 & PARAM1)) WT2 = WT0; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(movf, ps) { - if (!(env->fcr31 & PARAM1)) { + if (!(env->fpu->fcr31 & PARAM1)) { WT2 = WT0; WTH2 = WTH0; } @@ -1865,21 +2560,21 @@ FLOAT_OP(movf, ps) } FLOAT_OP(movt, d) { - if (env->fcr31 & PARAM1) + if (env->fpu->fcr31 & PARAM1) DT2 = DT0; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(movt, s) { - if (env->fcr31 & PARAM1) + if (env->fpu->fcr31 & PARAM1) WT2 = WT0; DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(movt, ps) { - if (env->fcr31 & PARAM1) { + if (env->fpu->fcr31 & PARAM1) { WT2 = WT0; WTH2 = WTH0; } @@ -1997,24 +2692,24 @@ FLOAT_HOP(mulr) #define FLOAT_TERNOP(name1, name2) \ FLOAT_OP(name1 ## name2, d) \ { \ - FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \ - FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \ + FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ + FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name1 ## name2, s) \ { \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name1 ## name2, ps) \ { \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ - FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ - FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ + FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ + FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } @@ -2026,26 +2721,26 @@ FLOAT_TERNOP(mul, sub) #define FLOAT_NTERNOP(name1, name2) \ FLOAT_OP(n ## name1 ## name2, d) \ { \ - FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \ - FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \ + FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ + FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ FDT2 ^= 1ULL << 63; \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(n ## name1 ## name2, s) \ { \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ FST2 ^= 1 << 31; \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(n ## name1 ## name2, ps) \ { \ - FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \ - FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \ - FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \ - FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \ + FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ + FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ + FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ + FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ FST2 ^= 1 << 31; \ FSTH2 ^= 1 << 31; \ DEBUG_FPU_STATE(); \ @@ -2059,13 +2754,13 @@ FLOAT_NTERNOP(mul, sub) #define FLOAT_UNOP(name) \ FLOAT_OP(name, d) \ { \ - FDT2 = float64_ ## name(FDT0, &env->fp_status); \ + FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name, s) \ { \ - FST2 = float32_ ## name(FST0, &env->fp_status); \ + FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ RETURN(); \ } @@ -2141,9 +2836,9 @@ FLOAT_OP(alnv, ps) #ifdef CONFIG_SOFTFLOAT #define clear_invalid() do { \ - int flags = get_float_exception_flags(&env->fp_status); \ + int flags = get_float_exception_flags(&env->fpu->fp_status); \ flags &= ~float_flag_invalid; \ - set_float_exception_flags(flags, &env->fp_status); \ + set_float_exception_flags(flags, &env->fpu->fp_status); \ } while(0) #else #define clear_invalid() do { } while(0) @@ -2190,63 +2885,63 @@ CMP_OPS(ngt) void op_bc1f (void) { - T0 = !!(~GET_FP_COND(env) & (0x1 << PARAM1)); + T0 = !!(~GET_FP_COND(env->fpu) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1any2f (void) { - T0 = !!(~GET_FP_COND(env) & (0x3 << PARAM1)); + T0 = !!(~GET_FP_COND(env->fpu) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1any4f (void) { - T0 = !!(~GET_FP_COND(env) & (0xf << PARAM1)); + T0 = !!(~GET_FP_COND(env->fpu) & (0xf << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1t (void) { - T0 = !!(GET_FP_COND(env) & (0x1 << PARAM1)); + T0 = !!(GET_FP_COND(env->fpu) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1any2t (void) { - T0 = !!(GET_FP_COND(env) & (0x3 << PARAM1)); + T0 = !!(GET_FP_COND(env->fpu) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1any4t (void) { - T0 = !!(GET_FP_COND(env) & (0xf << PARAM1)); + T0 = !!(GET_FP_COND(env->fpu) & (0xf << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_tlbwi (void) { - CALL_FROM_TB0(env->do_tlbwi); + CALL_FROM_TB0(env->tlb->do_tlbwi); RETURN(); } void op_tlbwr (void) { - CALL_FROM_TB0(env->do_tlbwr); + CALL_FROM_TB0(env->tlb->do_tlbwr); RETURN(); } void op_tlbp (void) { - CALL_FROM_TB0(env->do_tlbp); + CALL_FROM_TB0(env->tlb->do_tlbp); RETURN(); } void op_tlbr (void) { - CALL_FROM_TB0(env->do_tlbr); + CALL_FROM_TB0(env->tlb->do_tlbr); RETURN(); } @@ -2307,10 +3002,10 @@ void op_eret (void) if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_pre_eret); if (env->CP0_Status & (1 << CP0St_ERL)) { - env->PC = env->CP0_ErrorEPC; + env->PC[env->current_tc] = env->CP0_ErrorEPC; env->CP0_Status &= ~(1 << CP0St_ERL); } else { - env->PC = env->CP0_EPC; + env->PC[env->current_tc] = env->CP0_EPC; env->CP0_Status &= ~(1 << CP0St_EXL); } if (!(env->CP0_Status & (1 << CP0St_EXL)) && @@ -2335,7 +3030,7 @@ void op_deret (void) { if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_pre_eret); - env->PC = env->CP0_DEPC; + env->PC[env->current_tc] = env->CP0_DEPC; env->hflags |= MIPS_HFLAG_DM; if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && @@ -2407,14 +3102,14 @@ void op_save_state (void) void op_save_pc (void) { - env->PC = PARAM1; + env->PC[env->current_tc] = PARAM1; RETURN(); } #ifdef TARGET_MIPS64 void op_save_pc64 (void) { - env->PC = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; + env->PC[env->current_tc] = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; RETURN(); } #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 477b80d51..c87317a44 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -160,13 +160,13 @@ void do_drotrv (void) #if TARGET_LONG_BITS > HOST_LONG_BITS static inline uint64_t get_HILO (void) { - return (env->HI << 32) | (uint32_t)env->LO; + return (env->HI[0][env->current_tc] << 32) | (uint32_t)env->LO[0][env->current_tc]; } static inline void set_HILO (uint64_t HILO) { - env->LO = (int32_t)HILO; - env->HI = (int32_t)(HILO >> 32); + env->LO[0][env->current_tc] = (int32_t)HILO; + env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); } void do_mult (void) @@ -217,8 +217,8 @@ void do_div (void) { /* 64bit datatypes because we may see overflow/underflow. */ if (T1 != 0) { - env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); - env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); + env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); + env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); } } #endif @@ -228,8 +228,8 @@ void do_ddiv (void) { if (T1 != 0) { lldiv_t res = lldiv((int64_t)T0, (int64_t)T1); - env->LO = res.quot; - env->HI = res.rem; + env->LO[0][env->current_tc] = res.quot; + env->HI[0][env->current_tc] = res.rem; } } @@ -237,8 +237,8 @@ void do_ddiv (void) void do_ddivu (void) { if (T1 != 0) { - env->LO = T0 / T1; - env->HI = T0 % T1; + env->LO[0][env->current_tc] = T0 / T1; + env->HI[0][env->current_tc] = T0 % T1; } } #endif @@ -316,10 +316,10 @@ void do_mtc0_status_irqraise_debug(void) void fpu_handle_exception(void) { #ifdef CONFIG_SOFTFLOAT - int flags = get_float_exception_flags(&env->fp_status); + int flags = get_float_exception_flags(&env->fpu->fp_status); unsigned int cpuflags = 0, enable, cause = 0; - enable = GET_FP_ENABLE(env->fcr31); + enable = GET_FP_ENABLE(env->fpu->fcr31); /* determine current flags */ if (flags & float_flag_invalid) { @@ -342,11 +342,11 @@ void fpu_handle_exception(void) cpuflags |= FP_INEXACT; cause |= FP_INEXACT & enable; } - SET_FP_FLAGS(env->fcr31, cpuflags); - SET_FP_CAUSE(env->fcr31, cause); + SET_FP_FLAGS(env->fpu->fcr31, cpuflags); + SET_FP_CAUSE(env->fpu->fcr31, cause); #else - SET_FP_FLAGS(env->fcr31, 0); - SET_FP_CAUSE(env->fcr31, 0); + SET_FP_FLAGS(env->fpu->fcr31, 0); + SET_FP_CAUSE(env->fpu->fcr31, 0); #endif } @@ -355,14 +355,14 @@ void cpu_mips_tlb_flush (CPUState *env, int flush_global) { /* Flush qemu's TLB and discard all shadowed entries. */ tlb_flush (env, flush_global); - env->tlb_in_use = env->nb_tlb; + env->tlb->tlb_in_use = env->tlb->nb_tlb; } static void r4k_mips_tlb_flush_extra (CPUState *env, int first) { /* Discard entries from env->tlb[first] onwards. */ - while (env->tlb_in_use > first) { - r4k_invalidate_tlb(env, --env->tlb_in_use, 0); + while (env->tlb->tlb_in_use > first) { + r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0); } } @@ -371,7 +371,7 @@ static void r4k_fill_tlb (int idx) r4k_tlb_t *tlb; /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ - tlb = &env->mmu.r4k.tlb[idx]; + tlb = &env->tlb->mmu.r4k.tlb[idx]; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); #ifdef TARGET_MIPS64 tlb->VPN &= env->SEGMask; @@ -394,10 +394,10 @@ void r4k_do_tlbwi (void) /* Discard cached TLB entries. We could avoid doing this if the tlbwi is just upgrading access permissions on the current entry; that might be a further win. */ - r4k_mips_tlb_flush_extra (env, env->nb_tlb); + r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb); - r4k_invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0); - r4k_fill_tlb(env->CP0_Index % env->nb_tlb); + r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0); + r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb); } void r4k_do_tlbwr (void) @@ -418,8 +418,8 @@ void r4k_do_tlbp (void) int i; ASID = env->CP0_EntryHi & 0xFF; - for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->mmu.r4k.tlb[i]; + for (i = 0; i < env->tlb->nb_tlb; i++) { + tlb = &env->tlb->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); tag = env->CP0_EntryHi & ~mask; @@ -431,10 +431,10 @@ void r4k_do_tlbp (void) break; } } - if (i == env->nb_tlb) { + if (i == env->tlb->nb_tlb) { /* No match. Discard any shadow entries, if any of them match. */ - for (i = env->nb_tlb; i < env->tlb_in_use; i++) { - tlb = &env->mmu.r4k.tlb[i]; + for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) { + tlb = &env->tlb->mmu.r4k.tlb[i]; /* 1k pages are not supported. */ mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); tag = env->CP0_EntryHi & ~mask; @@ -456,13 +456,13 @@ void r4k_do_tlbr (void) uint8_t ASID; ASID = env->CP0_EntryHi & 0xFF; - tlb = &env->mmu.r4k.tlb[env->CP0_Index % env->nb_tlb]; + tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb]; /* If this will change the current ASID, flush qemu's TLB. */ if (ASID != tlb->ASID) cpu_mips_tlb_flush (env, 1); - r4k_mips_tlb_flush_extra(env, env->nb_tlb); + r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb); env->CP0_EntryHi = tlb->VPN | tlb->ASID; env->CP0_PageMask = tlb->PageMask; @@ -491,7 +491,7 @@ void dump_sc (void) void debug_pre_eret (void) { fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->PC, env->CP0_EPC); + env->PC[env->current_tc], env->CP0_EPC); if (env->CP0_Status & (1 << CP0St_ERL)) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); if (env->hflags & MIPS_HFLAG_DM) @@ -502,7 +502,7 @@ void debug_pre_eret (void) void debug_post_eret (void) { fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->PC, env->CP0_EPC); + env->PC[env->current_tc], env->CP0_EPC); if (env->CP0_Status & (1 << CP0St_ERL)) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); if (env->hflags & MIPS_HFLAG_DM) @@ -518,21 +518,21 @@ void do_pmon (int function) function /= 2; switch (function) { case 2: /* TODO: char inbyte(int waitflag); */ - if (env->gpr[4] == 0) - env->gpr[2] = -1; + if (env->gpr[4][env->current_tc] == 0) + env->gpr[2][env->current_tc] = -1; /* Fall through */ case 11: /* TODO: char inbyte (void); */ - env->gpr[2] = -1; + env->gpr[2][env->current_tc] = -1; break; case 3: case 12: - printf("%c", (char)(env->gpr[4] & 0xFF)); + printf("%c", (char)(env->gpr[4][env->current_tc] & 0xFF)); break; case 17: break; case 158: { - unsigned char *fmt = (void *)(unsigned long)env->gpr[4]; + unsigned char *fmt = (void *)(unsigned long)env->gpr[4][env->current_tc]; printf("%s", fmt); } break; @@ -613,40 +613,61 @@ unsigned int ieee_rm[] = { }; #define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) + set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status) -void do_ctc1 (void) +void do_cfc1 (int reg) { - switch(T1) { + switch (reg) { + case 0: + T0 = (int32_t)env->fpu->fcr0; + break; + case 25: + T0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1); + break; + case 26: + T0 = env->fpu->fcr31 & 0x0003f07c; + break; + case 28: + T0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4); + break; + default: + T0 = (int32_t)env->fpu->fcr31; + break; + } +} + +void do_ctc1 (int reg) +{ + switch(reg) { case 25: if (T0 & 0xffffff00) return; - env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | + env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | ((T0 & 0x1) << 23); break; case 26: if (T0 & 0x007c0000) return; - env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); + env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); break; case 28: if (T0 & 0x007c0000) return; - env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | + env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | ((T0 & 0x4) << 22); break; case 31: if (T0 & 0x007c0000) return; - env->fcr31 = T0; + env->fpu->fcr31 = T0; break; default: return; } /* set rounding mode */ RESTORE_ROUNDING_MODE; - set_float_exception_flags(0, &env->fp_status); - if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31)) + set_float_exception_flags(0, &env->fpu->fp_status); + if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31)) do_raise_exception(EXCP_FPE); } @@ -670,325 +691,325 @@ inline char mips_ex_to_ieee(char xcpt) inline void update_fcr31(void) { - int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status)); + int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status)); - SET_FP_CAUSE(env->fcr31, tmp); - if (GET_FP_ENABLE(env->fcr31) & tmp) + SET_FP_CAUSE(env->fpu->fcr31, tmp); + if (GET_FP_ENABLE(env->fpu->fcr31) & tmp) do_raise_exception(EXCP_FPE); else - UPDATE_FP_FLAGS(env->fcr31, tmp); + UPDATE_FP_FLAGS(env->fpu->fcr31, tmp); } #define FLOAT_OP(name, p) void do_float_##name##_##p(void) FLOAT_OP(cvtd, s) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float32_to_float64(FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float32_to_float64(FST0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvtd, w) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = int32_to_float64(WT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = int32_to_float64(WT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvtd, l) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = int64_to_float64(DT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = int64_to_float64(DT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvtl, d) { - set_float_exception_flags(0, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(cvtl, s) { - set_float_exception_flags(0, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + DT2 = float32_to_int64(FST0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(cvtps, pw) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int32_to_float32(WT0, &env->fp_status); - FSTH2 = int32_to_float32(WTH0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = int32_to_float32(WT0, &env->fpu->fp_status); + FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvtpw, ps) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); - WTH2 = float32_to_int32(FSTH0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); + WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(cvts, d) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float64_to_float32(FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float64_to_float32(FDT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvts, w) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int32_to_float32(WT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = int32_to_float32(WT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvts, l) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int64_to_float32(DT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = int64_to_float32(DT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(cvts, pl) { - set_float_exception_flags(0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); WT2 = WT0; update_fcr31(); } FLOAT_OP(cvts, pu) { - set_float_exception_flags(0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); WT2 = WTH0; update_fcr31(); } FLOAT_OP(cvtw, s) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(cvtw, d) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(roundl, d) { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); + DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(roundl, s) { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); + set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); + DT2 = float32_to_int64(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(roundw, d) { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); + WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(roundw, s) { - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); + set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(truncl, d) { - DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); + DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(truncl, s) { - DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); + DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(truncw, d) { - WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); + WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(truncw, s) { - WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); + WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status); update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(ceill, d) { - set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_up, &env->fpu->fp_status); + DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(ceill, s) { - set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); + set_float_rounding_mode(float_round_up, &env->fpu->fp_status); + DT2 = float32_to_int64(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(ceilw, d) { - set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_up, &env->fpu->fp_status); + WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(ceilw, s) { - set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); + set_float_rounding_mode(float_round_up, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(floorl, d) { - set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_down, &env->fpu->fp_status); + DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(floorl, s) { - set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); + set_float_rounding_mode(float_round_down, &env->fpu->fp_status); + DT2 = float32_to_int64(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) DT2 = 0x7fffffffffffffffULL; } FLOAT_OP(floorw, d) { - set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); + set_float_rounding_mode(float_round_down, &env->fpu->fp_status); + WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } FLOAT_OP(floorw, s) { - set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); + set_float_rounding_mode(float_round_down, &env->fpu->fp_status); + WT2 = float32_to_int32(FST0, &env->fpu->fp_status); RESTORE_ROUNDING_MODE; update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) WT2 = 0x7fffffff; } /* MIPS specific unary operations */ FLOAT_OP(recip, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(recip, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_sqrt(FDT0, &env->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_sqrt(FST0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_sqrt(FST0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(recip1, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(recip1, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(recip1, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST0, &env->fp_status); - FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status); + FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt1, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_sqrt(FDT0, &env->fp_status); - FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status); + FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt1, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_sqrt(FST0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_sqrt(FST0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(rsqrt1, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_sqrt(FST0, &env->fp_status); - FSTH2 = float32_sqrt(FSTH0, &env->fp_status); - FST2 = float32_div(FLOAT_ONE32, FST2, &env->fp_status); - FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_sqrt(FST0, &env->fpu->fp_status); + FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status); + FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status); + FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status); update_fcr31(); } @@ -996,41 +1017,41 @@ FLOAT_OP(rsqrt1, ps) #define FLOAT_BINOP(name) \ FLOAT_OP(name, d) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ - update_fcr31(); \ - if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) \ - FDT2 = 0x7ff7ffffffffffffULL; \ - else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ - if ((env->fcr31 & 0x3) == 0) \ - FDT2 &= FLOAT_SIGN64; \ + set_float_exception_flags(0, &env->fpu->fp_status); \ + FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status); \ + update_fcr31(); \ + if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ + FDT2 = 0x7ff7ffffffffffffULL; \ + else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ + if ((env->fpu->fcr31 & 0x3) == 0) \ + FDT2 &= FLOAT_SIGN64; \ } \ } \ FLOAT_OP(name, s) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - update_fcr31(); \ - if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) \ - FST2 = 0x7fbfffff; \ - else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ - if ((env->fcr31 & 0x3) == 0) \ - FST2 &= FLOAT_SIGN32; \ + set_float_exception_flags(0, &env->fpu->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \ + update_fcr31(); \ + if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ + FST2 = 0x7fbfffff; \ + else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ + if ((env->fpu->fcr31 & 0x3) == 0) \ + FST2 &= FLOAT_SIGN32; \ } \ } \ FLOAT_OP(name, ps) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ + set_float_exception_flags(0, &env->fpu->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \ + FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \ update_fcr31(); \ - if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) { \ - FST2 = 0x7fbfffff; \ - FSTH2 = 0x7fbfffff; \ - } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) { \ - if ((env->fcr31 & 0x3) == 0) { \ - FST2 &= FLOAT_SIGN32; \ - FSTH2 &= FLOAT_SIGN32; \ + if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \ + FST2 = 0x7fbfffff; \ + FSTH2 = 0x7fbfffff; \ + } else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ + if ((env->fpu->fcr31 & 0x3) == 0) { \ + FST2 &= FLOAT_SIGN32; \ + FSTH2 &= FLOAT_SIGN32; \ } \ } \ } @@ -1043,69 +1064,69 @@ FLOAT_BINOP(div) /* MIPS specific binary operations */ FLOAT_OP(recip2, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_mul(FDT0, FDT2, &env->fp_status); - FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status) ^ FLOAT_SIGN64; + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status); + FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status) ^ FLOAT_SIGN64; update_fcr31(); } FLOAT_OP(recip2, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; update_fcr31(); } FLOAT_OP(recip2, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fp_status); - FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; - FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status) ^ FLOAT_SIGN32; + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); + FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; + FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; update_fcr31(); } FLOAT_OP(rsqrt2, d) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float64_mul(FDT0, FDT2, &env->fp_status); - FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fp_status); - FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fp_status) ^ FLOAT_SIGN64; + set_float_exception_flags(0, &env->fpu->fp_status); + FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status); + FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status); + FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status) ^ FLOAT_SIGN64; update_fcr31(); } FLOAT_OP(rsqrt2, s) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status); - FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status); + FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; update_fcr31(); } FLOAT_OP(rsqrt2, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul(FST0, FST2, &env->fp_status); - FSTH2 = float32_mul(FSTH0, FSTH2, &env->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fp_status); - FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fp_status); - FST2 = float32_div(FST2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; - FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fp_status) ^ FLOAT_SIGN32; + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); + FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status); + FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status); + FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status); + FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; + FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; update_fcr31(); } FLOAT_OP(addr, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_add (FST0, FSTH0, &env->fp_status); - FSTH2 = float32_add (FST1, FSTH1, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status); + FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status); update_fcr31(); } FLOAT_OP(mulr, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_mul (FST0, FSTH0, &env->fp_status); - FSTH2 = float32_mul (FST1, FSTH1, &env->fp_status); + set_float_exception_flags(0, &env->fpu->fp_status); + FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status); + FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status); update_fcr31(); } @@ -1116,9 +1137,9 @@ void do_cmp_d_ ## op (long cc) \ int c = cond; \ update_fcr31(); \ if (c) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ } \ void do_cmpabs_d_ ## op (long cc) \ { \ @@ -1128,9 +1149,9 @@ void do_cmpabs_d_ ## op (long cc) \ c = cond; \ update_fcr31(); \ if (c) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ } int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) @@ -1149,24 +1170,24 @@ int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0)) -FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)) -FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0)) +FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)) +FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0)) -FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status)) -FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0)) +FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)) +FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_eq(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_lt(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status)) +FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) || float64_le(FDT0, FDT1, &env->fpu->fp_status)) #define FOP_COND_S(op, cond) \ void do_cmp_s_ ## op (long cc) \ @@ -1174,9 +1195,9 @@ void do_cmp_s_ ## op (long cc) \ int c = cond; \ update_fcr31(); \ if (c) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ } \ void do_cmpabs_s_ ## op (long cc) \ { \ @@ -1186,9 +1207,9 @@ void do_cmpabs_s_ ## op (long cc) \ c = cond; \ update_fcr31(); \ if (c) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ } flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) @@ -1207,24 +1228,24 @@ flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0)) -FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status)) -FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) -FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0)) +FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)) +FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0)) -FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status)) -FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) -FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0)) +FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)) +FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status)) +FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status)) #define FOP_COND_PS(op, condl, condh) \ void do_cmp_ps_ ## op (long cc) \ @@ -1233,13 +1254,13 @@ void do_cmp_ps_ ## op (long cc) \ int ch = condh; \ update_fcr31(); \ if (cl) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ if (ch) \ - SET_FP_COND(cc + 1, env); \ + SET_FP_COND(cc + 1, env->fpu); \ else \ - CLEAR_FP_COND(cc + 1, env); \ + CLEAR_FP_COND(cc + 1, env->fpu); \ } \ void do_cmpabs_ps_ ## op (long cc) \ { \ @@ -1252,48 +1273,48 @@ void do_cmpabs_ps_ ## op (long cc) \ ch = condh; \ update_fcr31(); \ if (cl) \ - SET_FP_COND(cc, env); \ + SET_FP_COND(cc, env->fpu); \ else \ - CLEAR_FP_COND(cc, env); \ + CLEAR_FP_COND(cc, env->fpu); \ if (ch) \ - SET_FP_COND(cc + 1, env); \ + SET_FP_COND(cc + 1, env->fpu); \ else \ - CLEAR_FP_COND(cc + 1, env); \ + CLEAR_FP_COND(cc + 1, env->fpu); \ } /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0), - (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0)) -FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)) -FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0), + (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0)) +FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)) +FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) /* NOTE: the comma operator will make "cond" to eval to false, * but float*_is_unordered() is still called. */ -FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0), - (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0)) -FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)) -FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0), + (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0)) +FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)) +FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_eq(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_lt(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) +FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) || float32_le(FST0, FST1, &env->fpu->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) || float32_le(FSTH0, FSTH1, &env->fpu->fp_status)) diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 8236acc18..41d954c1d 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -21,31 +21,44 @@ #if defined(REG) void glue(op_load_gpr_T0_gpr, REG) (void) { - T0 = env->gpr[REG]; + T0 = env->gpr[REG][env->current_tc]; RETURN(); } void glue(op_store_T0_gpr_gpr, REG) (void) { - env->gpr[REG] = T0; + env->gpr[REG][env->current_tc] = T0; RETURN(); } void glue(op_load_gpr_T1_gpr, REG) (void) { - T1 = env->gpr[REG]; + T1 = env->gpr[REG][env->current_tc]; RETURN(); } void glue(op_store_T1_gpr_gpr, REG) (void) { - env->gpr[REG] = T1; + env->gpr[REG][env->current_tc] = T1; RETURN(); } void glue(op_load_gpr_T2_gpr, REG) (void) { - T2 = env->gpr[REG]; + T2 = env->gpr[REG][env->current_tc]; + RETURN(); +} + + +void glue(op_load_srsgpr_T0_gpr, REG) (void) +{ + T0 = env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf]; + RETURN(); +} + +void glue(op_store_T0_srsgpr_gpr, REG) (void) +{ + env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf] = T0; RETURN(); } #endif diff --git a/target-mips/translate.c b/target-mips/translate.c index 07dca1459..c87f2c987 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -266,6 +266,8 @@ enum { OPC_DINSM = 0x05 | OPC_SPECIAL3, OPC_DINSU = 0x06 | OPC_SPECIAL3, OPC_DINS = 0x07 | OPC_SPECIAL3, + OPC_FORK = 0x08 | OPC_SPECIAL3, + OPC_YIELD = 0x09 | OPC_SPECIAL3, OPC_BSHFL = 0x20 | OPC_SPECIAL3, OPC_DBSHFL = 0x24 | OPC_SPECIAL3, OPC_RDHWR = 0x3B | OPC_SPECIAL3, @@ -296,8 +298,10 @@ enum { OPC_DMFC0 = (0x01 << 21) | OPC_CP0, OPC_MTC0 = (0x04 << 21) | OPC_CP0, OPC_DMTC0 = (0x05 << 21) | OPC_CP0, + OPC_MFTR = (0x08 << 21) | OPC_CP0, OPC_RDPGPR = (0x0A << 21) | OPC_CP0, OPC_MFMC0 = (0x0B << 21) | OPC_CP0, + OPC_MTTR = (0x0C << 21) | OPC_CP0, OPC_WRPGPR = (0x0E << 21) | OPC_CP0, OPC_C0 = (0x10 << 21) | OPC_CP0, OPC_C0_FIRST = (0x10 << 21) | OPC_CP0, @@ -308,6 +312,10 @@ enum { #define MASK_MFMC0(op) MASK_CP0(op) | (op & 0xFFFF) enum { + OPC_DMT = 0x01 | (0 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0, + OPC_EMT = 0x01 | (1 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0, + OPC_DVPE = 0x01 | (0 << 5) | OPC_MFMC0, + OPC_EVPE = 0x01 | (1 << 5) | OPC_MFMC0, OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0, OPC_EI = (1 << 5) | (0x0C << 11) | OPC_MFMC0, }; @@ -441,6 +449,10 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr); GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr); GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr); +/* Moves to/from shadow registers */ +GEN32(gen_op_load_srsgpr_T0, gen_op_load_srsgpr_T0_gpr); +GEN32(gen_op_store_T0_srsgpr, gen_op_store_T0_srsgpr_gpr); + static const char *fregnames[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", @@ -569,6 +581,15 @@ do { \ } \ } while (0) +#define GEN_LOAD_SRSREG_TN(Tn, Rn) \ +do { \ + if (Rn == 0) { \ + glue(gen_op_reset_, Tn)(); \ + } else { \ + glue(gen_op_load_srsgpr_, Tn)(Rn); \ + } \ +} while (0) + #ifdef TARGET_MIPS64 #define GEN_LOAD_IMM_TN(Tn, Imm) \ do { \ @@ -598,6 +619,13 @@ do { \ } \ } while (0) +#define GEN_STORE_TN_SRSREG(Rn, Tn) \ +do { \ + if (Rn != 0) { \ + glue(glue(gen_op_store_, Tn),_srsgpr)(Rn); \ + } \ +} while (0) + #define GEN_LOAD_FREG_FTN(FTn, Fn) \ do { \ glue(gen_op_load_fpr_, FTn)(Fn); \ @@ -740,6 +768,14 @@ static inline void check_mips_r2(CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); } +/* This code generates a "reserved instruction" exception if the + CPU is not MIPS MT capable. */ +static inline void check_mips_mt(CPUState *env, DisasContext *ctx) +{ + if (!(env->CP0_Config3 & (1 << CP0C3_MT))) + generate_exception(ctx, EXCP_RI); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -806,8 +842,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { #ifdef TARGET_MIPS64 case OPC_LWU: @@ -958,8 +993,7 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { case OPC_LWC1: op_ldst(lwc1); @@ -997,9 +1031,8 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, const char *opn = "imm arith"; if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) { - /* if no destination, treat it as a NOP - * For addi, we must generate the overflow exception when needed. - */ + /* If no destination, treat it as a NOP. + For addi, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); return; } @@ -1175,9 +1208,8 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB && opc != OPC_DADD && opc != OPC_DSUB) { - /* if no destination, treat it as a NOP - * For add & sub, we must generate the overflow exception when needed. - */ + /* If no destination, treat it as a NOP. + For add & sub, we must generate the overflow exception when needed. */ MIPS_DEBUG("NOP"); return; } @@ -1324,29 +1356,29 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) const char *opn = "hilo"; if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { - /* Treat as a NOP */ + /* Treat as NOP. */ MIPS_DEBUG("NOP"); return; } switch (opc) { case OPC_MFHI: - gen_op_load_HI(); + gen_op_load_HI(0); GEN_STORE_TN_REG(reg, T0); opn = "mfhi"; break; case OPC_MFLO: - gen_op_load_LO(); + gen_op_load_LO(0); GEN_STORE_TN_REG(reg, T0); opn = "mflo"; break; case OPC_MTHI: GEN_LOAD_REG_TN(T0, reg); - gen_op_store_HI(); + gen_op_store_HI(0); opn = "mthi"; break; case OPC_MTLO: GEN_LOAD_REG_TN(T0, reg); - gen_op_store_LO(); + gen_op_store_LO(0); opn = "mtlo"; break; default: @@ -1428,7 +1460,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, { const char *opn = "CLx"; if (rd == 0) { - /* Treat as a NOP */ + /* Treat as NOP. */ MIPS_DEBUG("NOP"); return; } @@ -1514,7 +1546,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, case OPC_TLTIU: /* r0 < 0 unsigned */ case OPC_TNE: /* rs != rs */ case OPC_TNEI: /* r0 != 0 */ - /* Never trap: treat as NOP */ + /* Never trap: treat as NOP. */ return; default: MIPS_INVAL("trap"); @@ -1674,7 +1706,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BNE: /* rx != rx */ case OPC_BGTZ: /* 0 > 0 */ case OPC_BLTZ: /* 0 < 0 */ - /* Treated as NOP */ + /* Treat as NOP. */ MIPS_DEBUG("bnever (NOP)"); return; case OPC_BLTZAL: /* 0 < 0 */ @@ -1886,17 +1918,20 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mfc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mfc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf0(); rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mfc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf1(); rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -1908,33 +1943,40 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mfc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mfc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mfc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mfc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mfc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mfc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mfc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -1946,33 +1988,40 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mfc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mfc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mfc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mfc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mfc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mfc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mfc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -2023,25 +2072,25 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mfc0_srsconf0(); /* shadow registers */ + gen_op_mfc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mfc0_srsconf1(); /* shadow registers */ + gen_op_mfc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mfc0_srsconf2(); /* shadow registers */ + gen_op_mfc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mfc0_srsconf3(); /* shadow registers */ + gen_op_mfc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mfc0_srsconf4(); /* shadow registers */ + gen_op_mfc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -2430,17 +2479,20 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mtc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mtc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mtc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -2452,33 +2504,40 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mtc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mtc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mtc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mtc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mtc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mtc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mtc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -2490,33 +2549,40 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mtc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mtc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mtc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mtc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mtc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mtc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mtc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -2567,25 +2633,25 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mtc0_srsconf0(); /* shadow registers */ + gen_op_mtc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mtc0_srsconf1(); /* shadow registers */ + gen_op_mtc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mtc0_srsconf2(); /* shadow registers */ + gen_op_mtc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mtc0_srsconf3(); /* shadow registers */ + gen_op_mtc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mtc0_srsconf4(); /* shadow registers */ + gen_op_mtc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -3006,17 +3072,20 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_dmfc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_dmfc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf0(); rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_dmfc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_mvpconf1(); rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -3028,33 +3097,40 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_dmfc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_dmfc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_dmfc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_dmfc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_dmfc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_dmfc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_dmfc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -3066,33 +3142,40 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_dmfc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_dmfc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mfc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_dmfc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_dmfc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_dmfc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_dmfc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_dmfc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_dmfc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -3143,25 +3226,25 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_dmfc0_srsconf0(); /* shadow registers */ + gen_op_mfc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_dmfc0_srsconf1(); /* shadow registers */ + gen_op_mfc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_dmfc0_srsconf2(); /* shadow registers */ + gen_op_mfc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_dmfc0_srsconf3(); /* shadow registers */ + gen_op_mfc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_dmfc0_srsconf4(); /* shadow registers */ + gen_op_mfc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -3237,7 +3320,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) break; case 3: check_mips_r2(env, ctx); - gen_op_mfc0_srsmap(); /* shadow registers */ + gen_op_mfc0_srsmap(); rn = "SRSMap"; break; default: @@ -3537,17 +3620,20 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: -// gen_op_mtc0_mvpcontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_mvpcontrol(); rn = "MVPControl"; -// break; + break; case 2: -// gen_op_mtc0_mvpconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf0"; -// break; + break; case 3: -// gen_op_mtc0_mvpconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + /* ignored */ rn = "MVPConf1"; -// break; + break; default: goto die; } @@ -3559,33 +3645,40 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: -// gen_op_mtc0_vpecontrol(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpecontrol(); rn = "VPEControl"; -// break; + break; case 2: -// gen_op_mtc0_vpeconf0(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf0(); rn = "VPEConf0"; -// break; + break; case 3: -// gen_op_mtc0_vpeconf1(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeconf1(); rn = "VPEConf1"; -// break; + break; case 4: -// gen_op_mtc0_YQMask(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_yqmask(); rn = "YQMask"; -// break; + break; case 5: -// gen_op_mtc0_vpeschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschedule(); rn = "VPESchedule"; -// break; + break; case 6: -// gen_op_mtc0_vpeschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeschefback(); rn = "VPEScheFBack"; -// break; + break; case 7: -// gen_op_mtc0_vpeopt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_vpeopt(); rn = "VPEOpt"; -// break; + break; default: goto die; } @@ -3597,33 +3690,40 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: -// gen_op_mtc0_tcstatus(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcstatus(); rn = "TCStatus"; -// break; + break; case 2: -// gen_op_mtc0_tcbind(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcbind(); rn = "TCBind"; -// break; + break; case 3: -// gen_op_mtc0_tcrestart(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcrestart(); rn = "TCRestart"; -// break; + break; case 4: -// gen_op_mtc0_tchalt(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tchalt(); rn = "TCHalt"; -// break; + break; case 5: -// gen_op_mtc0_tccontext(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tccontext(); rn = "TCContext"; -// break; + break; case 6: -// gen_op_mtc0_tcschedule(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschedule(); rn = "TCSchedule"; -// break; + break; case 7: -// gen_op_mtc0_tcschefback(); /* MT ASE */ + check_mips_mt(env, ctx); + gen_op_mtc0_tcschefback(); rn = "TCScheFBack"; -// break; + break; default: goto die; } @@ -3674,25 +3774,25 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: -// gen_op_mtc0_srsconf0(); /* shadow registers */ + gen_op_mtc0_srsconf0(); rn = "SRSConf0"; -// break; + break; case 2: -// gen_op_mtc0_srsconf1(); /* shadow registers */ + gen_op_mtc0_srsconf1(); rn = "SRSConf1"; -// break; + break; case 3: -// gen_op_mtc0_srsconf2(); /* shadow registers */ + gen_op_mtc0_srsconf2(); rn = "SRSConf2"; -// break; + break; case 4: -// gen_op_mtc0_srsconf3(); /* shadow registers */ + gen_op_mtc0_srsconf3(); rn = "SRSConf3"; -// break; + break; case 5: -// gen_op_mtc0_srsconf4(); /* shadow registers */ + gen_op_mtc0_srsconf4(); rn = "SRSConf4"; -// break; + break; default: goto die; } @@ -4086,6 +4186,334 @@ die: } #endif /* TARGET_MIPS64 */ +static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, + int u, int sel, int h) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && + ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != + (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) + gen_op_set_T0(-1); + else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > + (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) + gen_op_set_T0(-1); + else if (u == 0) { + switch (rt) { + case 2: + switch (sel) { + case 1: + gen_op_mftc0_tcstatus(); + break; + case 2: + gen_op_mftc0_tcbind(); + break; + case 3: + gen_op_mftc0_tcrestart(); + break; + case 4: + gen_op_mftc0_tchalt(); + break; + case 5: + gen_op_mftc0_tccontext(); + break; + case 6: + gen_op_mftc0_tcschedule(); + break; + case 7: + gen_op_mftc0_tcschefback(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + break; + case 10: + switch (sel) { + case 0: + gen_op_mftc0_entryhi(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + case 12: + switch (sel) { + case 0: + gen_op_mftc0_status(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + case 23: + switch (sel) { + case 0: + gen_op_mftc0_debug(); + break; + default: + gen_mfc0(env, ctx, rt, sel); + break; + } + break; + default: + gen_mfc0(env, ctx, rt, sel); + } + } else switch (sel) { + /* GPR registers. */ + case 0: + gen_op_mftgpr(rt); + break; + /* Auxiliary CPU registers */ + case 1: + switch (rt) { + case 0: + gen_op_mftlo(0); + break; + case 1: + gen_op_mfthi(0); + break; + case 2: + gen_op_mftacx(0); + break; + case 4: + gen_op_mftlo(1); + break; + case 5: + gen_op_mfthi(1); + break; + case 6: + gen_op_mftacx(1); + break; + case 8: + gen_op_mftlo(2); + break; + case 9: + gen_op_mfthi(2); + break; + case 10: + gen_op_mftacx(2); + break; + case 12: + gen_op_mftlo(3); + break; + case 13: + gen_op_mfthi(3); + break; + case 14: + gen_op_mftacx(3); + break; + case 16: + gen_op_mftdsp(); + break; + default: + goto die; + } + break; + /* Floating point (COP1). */ + case 2: + /* XXX: For now we support only a single FPU context. */ + if (h == 0) { + GEN_LOAD_FREG_FTN(WT0, rt); + gen_op_mfc1(); + } else { + GEN_LOAD_FREG_FTN(WTH0, rt); + gen_op_mfhc1(); + } + break; + case 3: + /* XXX: For now we support only a single FPU context. */ + gen_op_cfc1(rt); + break; + /* COP2: Not implemented. */ + case 4: + case 5: + /* fall through */ + default: + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", + rt, u, sel, h); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n", + rt, u, sel, h); + } +#endif + generate_exception(ctx, EXCP_RI); +} + +static void gen_mttr(CPUState *env, DisasContext *ctx, int rd, + int u, int sel, int h) +{ + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + + if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 && + ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) != + (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE)))) + /* NOP */ ; + else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) > + (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC))) + /* NOP */ ; + else if (u == 0) { + switch (rd) { + case 2: + switch (sel) { + case 1: + gen_op_mttc0_tcstatus(); + break; + case 2: + gen_op_mttc0_tcbind(); + break; + case 3: + gen_op_mttc0_tcrestart(); + break; + case 4: + gen_op_mttc0_tchalt(); + break; + case 5: + gen_op_mttc0_tccontext(); + break; + case 6: + gen_op_mttc0_tcschedule(); + break; + case 7: + gen_op_mttc0_tcschefback(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + break; + case 10: + switch (sel) { + case 0: + gen_op_mttc0_entryhi(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + case 12: + switch (sel) { + case 0: + gen_op_mttc0_status(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + case 23: + switch (sel) { + case 0: + gen_op_mttc0_debug(); + break; + default: + gen_mtc0(env, ctx, rd, sel); + break; + } + break; + default: + gen_mtc0(env, ctx, rd, sel); + } + } else switch (sel) { + /* GPR registers. */ + case 0: + gen_op_mttgpr(rd); + break; + /* Auxiliary CPU registers */ + case 1: + switch (rd) { + case 0: + gen_op_mttlo(0); + break; + case 1: + gen_op_mtthi(0); + break; + case 2: + gen_op_mttacx(0); + break; + case 4: + gen_op_mttlo(1); + break; + case 5: + gen_op_mtthi(1); + break; + case 6: + gen_op_mttacx(1); + break; + case 8: + gen_op_mttlo(2); + break; + case 9: + gen_op_mtthi(2); + break; + case 10: + gen_op_mttacx(2); + break; + case 12: + gen_op_mttlo(3); + break; + case 13: + gen_op_mtthi(3); + break; + case 14: + gen_op_mttacx(3); + break; + case 16: + gen_op_mttdsp(); + break; + default: + goto die; + } + break; + /* Floating point (COP1). */ + case 2: + /* XXX: For now we support only a single FPU context. */ + if (h == 0) { + gen_op_mtc1(); + GEN_STORE_FTN_FREG(rd, WT0); + } else { + gen_op_mthc1(); + GEN_STORE_FTN_FREG(rd, WTH0); + } + break; + case 3: + /* XXX: For now we support only a single FPU context. */ + gen_op_ctc1(rd); + break; + /* COP2: Not implemented. */ + case 4: + case 5: + /* fall through */ + default: + goto die; + } +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", + rd, u, sel, h); + } +#endif + return; + +die: +#if defined MIPS_DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n", + rd, u, sel, h); + } +#endif + generate_exception(ctx, EXCP_RI); +} + static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rd) { const char *opn = "ldst"; @@ -4093,7 +4521,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int switch (opc) { case OPC_MFC0: if (rt == 0) { - /* Treat as NOP */ + /* Treat as NOP. */ return; } gen_mfc0(env, ctx, rd, ctx->opcode & 0x7); @@ -4110,7 +4538,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int if (!(ctx->hflags & MIPS_HFLAG_64)) generate_exception(ctx, EXCP_RI); if (rt == 0) { - /* Treat as NOP */ + /* Treat as NOP. */ return; } gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7); @@ -4121,31 +4549,49 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int if (!(ctx->hflags & MIPS_HFLAG_64)) generate_exception(ctx, EXCP_RI); GEN_LOAD_REG_TN(T0, rt); - gen_dmtc0(env,ctx, rd, ctx->opcode & 0x7); + gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; break; #endif + case OPC_MFTR: + check_mips_mt(env, ctx); + if (rd == 0) { + /* Treat as NOP. */ + return; + } + gen_mftr(env, ctx, rt, (ctx->opcode >> 5) & 1, + ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); + gen_op_store_T0_gpr(rd); + opn = "mftr"; + break; + case OPC_MTTR: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rt); + gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1, + ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); + opn = "mttr"; + break; case OPC_TLBWI: opn = "tlbwi"; - if (!env->do_tlbwi) + if (!env->tlb->do_tlbwi) goto die; gen_op_tlbwi(); break; case OPC_TLBWR: opn = "tlbwr"; - if (!env->do_tlbwr) + if (!env->tlb->do_tlbwr) goto die; gen_op_tlbwr(); break; case OPC_TLBP: opn = "tlbp"; - if (!env->do_tlbp) + if (!env->tlb->do_tlbp) goto die; gen_op_tlbp(); break; case OPC_TLBR: opn = "tlbr"; - if (!env->do_tlbr) + if (!env->tlb->do_tlbr) goto die; gen_op_tlbr(); break; @@ -4263,15 +4709,13 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "mtc1"; break; case OPC_CFC1: - GEN_LOAD_IMM_TN(T1, fs); - gen_op_cfc1(); + gen_op_cfc1(fs); GEN_STORE_TN_REG(rt, T0); opn = "cfc1"; break; case OPC_CTC1: - GEN_LOAD_IMM_TN(T1, fs); GEN_LOAD_REG_TN(T0, rt); - gen_op_ctc1(); + gen_op_ctc1(fs); opn = "ctc1"; break; case OPC_DMFC1: @@ -5171,8 +5615,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual - * memory access - */ + memory access. */ switch (opc) { case OPC_LWXC1: op_ldst(lwc1); @@ -5456,7 +5899,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) #endif break; case OPC_SYNC: - /* Treat as a noop. */ + /* Treat as NOP. */ break; case OPC_MOVCI: @@ -5521,7 +5964,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } else { generate_exception(ctx, EXCP_DBp); } - /* Treat as a noop */ + /* Treat as NOP. */ break; #ifdef TARGET_MIPS64 case OPC_DCLZ ... OPC_DCLO: @@ -5586,7 +6029,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case 29: #if defined (CONFIG_USER_ONLY) - gen_op_tls_value (); + gen_op_tls_value(); break; #endif default: /* Invalid */ @@ -5596,6 +6039,18 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } GEN_STORE_TN_REG(rt, T0); break; + case OPC_FORK: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_TN(T1, rs); + gen_op_fork(); + break; + case OPC_YIELD: + check_mips_mt(env, ctx); + GEN_LOAD_REG_TN(T0, rs); + gen_op_yield(); + GEN_STORE_TN_REG(rd, T0); + break; #ifdef TARGET_MIPS64 case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: @@ -5642,7 +6097,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case OPC_SYNCI: check_mips_r2(env, ctx); - /* treat as noop */ + /* Treat as NOP. */ break; default: /* Invalid */ MIPS_INVAL("regimm"); @@ -5657,6 +6112,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) switch (op1) { case OPC_MFC0: case OPC_MTC0: + case OPC_MFTR: + case OPC_MTTR: #ifdef TARGET_MIPS64 case OPC_DMFC0: case OPC_DMTC0: @@ -5670,6 +6127,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx) check_mips_r2(env, ctx); op2 = MASK_MFMC0(ctx->opcode); switch (op2) { + case OPC_DMT: + check_mips_mt(env, ctx); + gen_op_dmt(); + break; + case OPC_EMT: + check_mips_mt(env, ctx); + gen_op_emt(); + break; + case OPC_DVPE: + check_mips_mt(env, ctx); + gen_op_dvpe(); + break; + case OPC_EVPE: + check_mips_mt(env, ctx); + gen_op_evpe(); + break; case OPC_DI: gen_op_di(); /* Stop translation as we may have switched the execution mode */ @@ -5688,11 +6161,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) GEN_STORE_TN_REG(rt, T0); break; case OPC_RDPGPR: + check_mips_r2(env, ctx); + GEN_LOAD_SRSREG_TN(T0, rt); + GEN_STORE_TN_REG(rd, T0); + break; case OPC_WRPGPR: check_mips_r2(env, ctx); - /* Shadow registers not implemented. */ GEN_LOAD_REG_TN(T0, rt); - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_TN_SRSREG(rd, T0); break; default: MIPS_INVAL("cp0"); @@ -5719,10 +6195,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_ldst(ctx, op, rt, rs, imm); break; case OPC_CACHE: - /* Treat as a noop */ + /* Treat as NOP. */ break; case OPC_PREF: - /* Treat as a noop */ + /* Treat as NOP. */ break; /* Floating point (COP1). */ @@ -5807,7 +6283,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_flt3_ldst(ctx, op1, sa, rd, rs, rt); break; case OPC_PREFX: - /* treat as noop */ + /* Treat as NOP. */ break; case OPC_ALNV_PS: case OPC_MADD_S: @@ -6079,13 +6555,14 @@ void fpu_dump_state(CPUState *env, FILE *f, fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n", - env->fcr0, env->fcr31, is_fpu64, env->fp_status, get_float_exception_flags(&env->fp_status)); - fpu_fprintf(f, "FT0: "); printfpr(&env->ft0); - fpu_fprintf(f, "FT1: "); printfpr(&env->ft1); - fpu_fprintf(f, "FT2: "); printfpr(&env->ft2); + env->fpu->fcr0, env->fpu->fcr31, is_fpu64, env->fpu->fp_status, + get_float_exception_flags(&env->fpu->fp_status)); + fpu_fprintf(f, "FT0: "); printfpr(&env->fpu->ft0); + fpu_fprintf(f, "FT1: "); printfpr(&env->fpu->ft1); + fpu_fprintf(f, "FT2: "); printfpr(&env->fpu->ft2); for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { fpu_fprintf(f, "%3s: ", fregnames[i]); - printfpr(&env->fpr[i]); + printfpr(&env->fpu->fpr[i]); } #undef printfpr @@ -6095,7 +6572,7 @@ void dump_fpu (CPUState *env) { if (loglevel) { fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); + env->PC[env->current_tc], env->HI[0][env->current_tc], env->LO[0][env->current_tc], env->hflags, env->btarget, env->bcond); fpu_dump_state(env, logfile, fprintf, 0); } } @@ -6112,18 +6589,18 @@ void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, { int i; - if (!SIGN_EXT_P(env->PC)) - cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC); - if (!SIGN_EXT_P(env->HI)) - cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI); - if (!SIGN_EXT_P(env->LO)) - cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO); + if (!SIGN_EXT_P(env->PC[env->current_tc])) + cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC[env->current_tc]); + if (!SIGN_EXT_P(env->HI[env->current_tc])) + cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[env->current_tc]); + if (!SIGN_EXT_P(env->LO[env->current_tc])) + cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[env->current_tc]); if (!SIGN_EXT_P(env->btarget)) cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget); for (i = 0; i < 32; i++) { - if (!SIGN_EXT_P(env->gpr[i])) - cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i]); + if (!SIGN_EXT_P(env->gpr[i][env->current_tc])) + cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i][env->current_tc]); } if (!SIGN_EXT_P(env->CP0_EPC)) @@ -6140,11 +6617,11 @@ void cpu_dump_state (CPUState *env, FILE *f, int i; cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", - env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond); + env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { if ((i & 3) == 0) cpu_fprintf(f, "GPR%02d:", i); - cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i]); + cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i][env->current_tc]); if ((i & 3) == 3) cpu_fprintf(f, "\n"); } @@ -6183,12 +6660,12 @@ void cpu_reset (CPUMIPSState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, * come back to the jump. */ - env->CP0_ErrorEPC = env->PC - 4; + env->CP0_ErrorEPC = env->PC[env->current_tc] - 4; } else { - env->CP0_ErrorEPC = env->PC; + env->CP0_ErrorEPC = env->PC[env->current_tc]; } env->hflags = 0; - env->PC = (int32_t)0xBFC00000; + env->PC[env->current_tc] = (int32_t)0xBFC00000; env->CP0_Wired = 0; /* SMP not implemented */ env->CP0_EBase = 0x80000000; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index d327312e5..a9e931264 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -43,11 +43,11 @@ /* No config4, no DSP ASE, no large physaddr, no external interrupt controller, no vectored interupts, - no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */ + no 1kb pages, no SmartMIPS ASE, no trace logic */ #define MIPS_CONFIG3 \ ((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \ - (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL)) + (0 << CP0C3_SM) | (0 << CP0C3_TL)) /* Define a implementation number of 1. Define a major version 1, minor version 0. */ @@ -65,9 +65,21 @@ struct mips_def_t { int32_t CP0_Config7; int32_t SYNCI_Step; int32_t CCRes; - int32_t Status_rw_bitmask; + int32_t CP0_Status_rw_bitmask; + int32_t CP0_TCStatus_rw_bitmask; + int32_t CP0_SRSCtl; int32_t CP1_fcr0; int32_t SEGBITS; + int32_t CP0_SRSConf0_rw_bitmask; + int32_t CP0_SRSConf0; + int32_t CP0_SRSConf1_rw_bitmask; + int32_t CP0_SRSConf1; + int32_t CP0_SRSConf2_rw_bitmask; + int32_t CP0_SRSConf2; + int32_t CP0_SRSConf3_rw_bitmask; + int32_t CP0_SRSConf3; + int32_t CP0_SRSConf4_rw_bitmask; + int32_t CP0_SRSConf4; }; /*****************************************************************************/ @@ -85,7 +97,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FF17, + .CP0_Status_rw_bitmask = 0x1278FF17, }, { .name = "4KEcR1", @@ -98,7 +110,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FF17, + .CP0_Status_rw_bitmask = 0x1278FF17, }, { .name = "4KEc", @@ -108,10 +120,10 @@ static mips_def_t mips_defs[] = (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3, + .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FF17, + .CP0_Status_rw_bitmask = 0x1278FF17, }, { .name = "24Kc", @@ -121,10 +133,11 @@ static mips_def_t mips_defs[] = (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3, + .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3278FF17, + /* No DSP implemented. */ + .CP0_Status_rw_bitmask = 0x1278FF17, }, { .name = "24Kf", @@ -134,13 +147,53 @@ static mips_def_t mips_defs[] = (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3, + .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt), .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x3678FF17, + /* No DSP implemented. */ + .CP0_Status_rw_bitmask = 0x3678FF17, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), }, + { + .name = "34Kf", + .CP0_PRid = 0x00019500, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt) | (1 << CP0C3_MT), + .SYNCI_Step = 32, + .CCRes = 2, + /* No DSP implemented. */ + .CP0_Status_rw_bitmask = 0x3678FF17, + /* No DSP implemented. */ + .CP0_TCStatus_rw_bitmask = (0 << CP0TCSt_TCU3) | (0 << CP0TCSt_TCU2) | + (1 << CP0TCSt_TCU1) | (1 << CP0TCSt_TCU0) | + (0 << CP0TCSt_TMX) | (1 << CP0TCSt_DT) | + (1 << CP0TCSt_DA) | (1 << CP0TCSt_A) | + (0x3 << CP0TCSt_TKSU) | (1 << CP0TCSt_IXMT) | + (0xff << CP0TCSt_TASID), + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + (1 << FCR0_D) | (1 << FCR0_S) | (0x95 << FCR0_PRID), + .CP0_SRSCtl = (0xf << CP0SRSCtl_HSS), + .CP0_SRSConf0_rw_bitmask = 0x3fffffff, + .CP0_SRSConf0 = (1 << CP0SRSC0_M) | (0x3fe << CP0SRSC0_SRS3) | + (0x3fe << CP0SRSC0_SRS2) | (0x3fe << CP0SRSC0_SRS1), + .CP0_SRSConf1_rw_bitmask = 0x3fffffff, + .CP0_SRSConf1 = (1 << CP0SRSC1_M) | (0x3fe << CP0SRSC1_SRS6) | + (0x3fe << CP0SRSC1_SRS5) | (0x3fe << CP0SRSC1_SRS4), + .CP0_SRSConf2_rw_bitmask = 0x3fffffff, + .CP0_SRSConf2 = (1 << CP0SRSC2_M) | (0x3fe << CP0SRSC2_SRS9) | + (0x3fe << CP0SRSC2_SRS8) | (0x3fe << CP0SRSC2_SRS7), + .CP0_SRSConf3_rw_bitmask = 0x3fffffff, + .CP0_SRSConf3 = (1 << CP0SRSC3_M) | (0x3fe << CP0SRSC3_SRS12) | + (0x3fe << CP0SRSC3_SRS11) | (0x3fe << CP0SRSC3_SRS10), + .CP0_SRSConf4_rw_bitmask = 0x3fffffff, + .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) | + (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13), + }, #ifdef TARGET_MIPS64 { .name = "R4000", @@ -153,7 +206,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 16, .CCRes = 2, - .Status_rw_bitmask = 0x3678FFFF, + .CP0_Status_rw_bitmask = 0x3678FFFF, /* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */ .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), .SEGBITS = 40, @@ -170,7 +223,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x32F8FFFF, + .CP0_Status_rw_bitmask = 0x32F8FFFF, .SEGBITS = 42, }, { @@ -185,7 +238,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x36F8FFFF, + .CP0_Status_rw_bitmask = 0x36F8FFFF, /* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */ .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) | (0x81 << FCR0_PRID) | (0x0 << FCR0_REV), @@ -205,7 +258,7 @@ static mips_def_t mips_defs[] = .CP0_Config3 = MIPS_CONFIG3, .SYNCI_Step = 32, .CCRes = 2, - .Status_rw_bitmask = 0x36FBFFFF, + .CP0_Status_rw_bitmask = 0x36FBFFFF, /* The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */ .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) | (1 << FCR0_D) | (1 << FCR0_S) | @@ -245,27 +298,88 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) #ifndef CONFIG_USER_ONLY static void no_mmu_init (CPUMIPSState *env, mips_def_t *def) { - env->nb_tlb = 1; - env->map_address = &no_mmu_map_address; + env->tlb->nb_tlb = 1; + env->tlb->map_address = &no_mmu_map_address; } static void fixed_mmu_init (CPUMIPSState *env, mips_def_t *def) { - env->nb_tlb = 1; - env->map_address = &fixed_mmu_map_address; + env->tlb->nb_tlb = 1; + env->tlb->map_address = &fixed_mmu_map_address; } static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def) { - env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); - env->map_address = &r4k_map_address; - env->do_tlbwi = r4k_do_tlbwi; - env->do_tlbwr = r4k_do_tlbwr; - env->do_tlbp = r4k_do_tlbp; - env->do_tlbr = r4k_do_tlbr; + env->tlb->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); + env->tlb->map_address = &r4k_map_address; + env->tlb->do_tlbwi = r4k_do_tlbwi; + env->tlb->do_tlbwr = r4k_do_tlbwr; + env->tlb->do_tlbp = r4k_do_tlbp; + env->tlb->do_tlbr = r4k_do_tlbr; +} + +static void mmu_init (CPUMIPSState *env, mips_def_t *def) +{ + env->tlb = qemu_mallocz(sizeof(CPUMIPSTLBContext)); + + /* There are more full-featured MMU variants in older MIPS CPUs, + R3000, R6000 and R8000 come to mind. If we ever support them, + this check will need to look up a different place than those + newfangled config registers. */ + switch ((env->CP0_Config0 >> CP0C0_MT) & 3) { + case 0: + no_mmu_init(env, def); + break; + case 1: + r4k_mmu_init(env, def); + break; + case 3: + fixed_mmu_init(env, def); + break; + default: + cpu_abort(env, "MMU type not supported\n"); + } + env->CP0_Random = env->tlb->nb_tlb - 1; + env->tlb->tlb_in_use = env->tlb->nb_tlb; } #endif /* CONFIG_USER_ONLY */ +static void fpu_init (CPUMIPSState *env, mips_def_t *def) +{ + env->fpu = qemu_mallocz(sizeof(CPUMIPSFPUContext)); + + env->fpu->fcr0 = def->CP1_fcr0; +#ifdef CONFIG_USER_ONLY + if (env->CP0_Config1 & (1 << CP0C1_FP)) + env->hflags |= MIPS_HFLAG_FPU; + if (env->fpu->fcr0 & (1 << FCR0_F64)) + env->hflags |= MIPS_HFLAG_F64; +#endif +} + +static void mvp_init (CPUMIPSState *env, mips_def_t *def) +{ + env->mvp = qemu_mallocz(sizeof(CPUMIPSMVPContext)); + + /* MVPConf1 implemented, TLB sharable, no gating storage support, + programmable cache partitioning implemented, number of allocatable + and sharable TLB entries, MVP has allocatable TCs, 2 VPEs + implemented, 5 TCs implemented. */ + env->mvp->CP0_MVPConf0 = (1 << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) | + (0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) | + (env->tlb->nb_tlb << CP0MVPC0_PTLBE) | +// TODO: actually do 2 VPEs. +// (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) | +// (0x04 << CP0MVPC0_PTC); + (1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) | + (0x04 << CP0MVPC0_PTC); + /* Allocatable CP1 have media extensions, allocatable CP1 have FP support, + no UDI implemented, no CP2 implemented, 1 CP1 implemented. */ + env->mvp->CP0_MVPConf1 = (1 << CP0MVPC1_CIM) | (1 << CP0MVPC1_CIF) | + (0x0 << CP0MVPC1_PCX) | (0x0 << CP0MVPC1_PCP2) | + (0x1 << CP0MVPC1_PCP1); +} + int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) { if (!def) @@ -285,8 +399,9 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_Config7 = def->CP0_Config7; env->SYNCI_Step = def->SYNCI_Step; env->CCRes = def->CCRes; - env->Status_rw_bitmask = def->Status_rw_bitmask; - env->fcr0 = def->CP1_fcr0; + env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask; + env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask; + env->CP0_SRSCtl = def->CP0_SRSCtl; #ifdef TARGET_MIPS64 if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) { @@ -298,31 +413,21 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->SEGMask = 0xFFFFFFFF; } #endif -#ifdef CONFIG_USER_ONLY - if (env->CP0_Config1 & (1 << CP0C1_FP)) - env->hflags |= MIPS_HFLAG_FPU; - if (env->fcr0 & (1 << FCR0_F64)) - env->hflags |= MIPS_HFLAG_F64; -#else - /* There are more full-featured MMU variants in older MIPS CPUs, - R3000, R6000 and R8000 come to mind. If we ever support them, - this check will need to look up a different place than those - newfangled config registers. */ - switch ((env->CP0_Config0 >> CP0C0_MT) & 3) { - case 0: - no_mmu_init(env, def); - break; - case 1: - r4k_mmu_init(env, def); - break; - case 3: - fixed_mmu_init(env, def); - break; - default: - cpu_abort(env, "MMU type not supported\n"); - } - env->CP0_Random = env->nb_tlb - 1; - env->tlb_in_use = env->nb_tlb; -#endif /* CONFIG_USER_ONLY */ + env->CP0_SRSConf0_rw_bitmask = def->CP0_SRSConf0_rw_bitmask; + env->CP0_SRSConf0 = def->CP0_SRSConf0; + env->CP0_SRSConf1_rw_bitmask = def->CP0_SRSConf1_rw_bitmask; + env->CP0_SRSConf1 = def->CP0_SRSConf1; + env->CP0_SRSConf2_rw_bitmask = def->CP0_SRSConf2_rw_bitmask; + env->CP0_SRSConf2 = def->CP0_SRSConf2; + env->CP0_SRSConf3_rw_bitmask = def->CP0_SRSConf3_rw_bitmask; + env->CP0_SRSConf3 = def->CP0_SRSConf3; + env->CP0_SRSConf4_rw_bitmask = def->CP0_SRSConf4_rw_bitmask; + env->CP0_SRSConf4 = def->CP0_SRSConf4; + +#ifndef CONFIG_USER_ONLY + mmu_init(env, def); +#endif + fpu_init(env, def); + mvp_init(env, def); return 0; } diff --git a/translate-all.c b/translate-all.c index 491b3b3d3..bd5286f2a 100644 --- a/translate-all.c +++ b/translate-all.c @@ -305,7 +305,7 @@ int cpu_restore_state(TranslationBlock *tb, #elif defined(TARGET_M68K) env->pc = gen_opc_pc[j]; #elif defined(TARGET_MIPS) - env->PC = gen_opc_pc[j]; + env->PC[env->current_tc] = gen_opc_pc[j]; env->hflags &= ~MIPS_HFLAG_BMASK; env->hflags |= gen_opc_hflags[j]; #elif defined(TARGET_ALPHA) -- cgit v1.2.3 From 117b3ae6e6d27ea31e85ffe1820437d91269ed4e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 9 Sep 2007 21:16:01 +0000 Subject: Implement HID idle mode (avoids flooding guest with useless updates). Fix UHCI NACK bug. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3157 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hid.c | 40 +++++++++++++++++++++++++++++----------- hw/usb-uhci.c | 5 ++++- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 43fc47e9c..f119735a0 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -64,6 +64,7 @@ typedef struct USBHIDState { int kind; int protocol; int idle; + int changed; } USBHIDState; /* mostly the same values as the Bochs USB Mouse device */ @@ -382,28 +383,33 @@ static const uint8_t usb_hid_usage_keys[0x100] = { static void usb_mouse_event(void *opaque, int dx1, int dy1, int dz1, int buttons_state) { - USBMouseState *s = opaque; + USBHIDState *hs = opaque; + USBMouseState *s = &hs->ptr; s->dx += dx1; s->dy += dy1; s->dz += dz1; s->buttons_state = buttons_state; + hs->changed = 1; } static void usb_tablet_event(void *opaque, int x, int y, int dz, int buttons_state) { - USBMouseState *s = opaque; + USBHIDState *hs = opaque; + USBMouseState *s = &hs->ptr; s->x = x; s->y = y; s->dz += dz; s->buttons_state = buttons_state; + hs->changed = 1; } static void usb_keyboard_event(void *opaque, int keycode) { - USBKeyboardState *s = opaque; + USBHIDState *hs = opaque; + USBKeyboardState *s = &hs->kbd; uint8_t hid_code, key; int i; @@ -411,6 +417,8 @@ static void usb_keyboard_event(void *opaque, int keycode) hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))]; s->modifiers &= ~(1 << 8); + hs->changed = 1; + switch (hid_code) { case 0x00: return; @@ -456,12 +464,13 @@ static inline int int_clamp(int val, int vmin, int vmax) return val; } -static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) +static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) { int dx, dy, dz, b, l; + USBMouseState *s = &hs->ptr; if (!s->mouse_grabbed) { - s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, + s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs, 0, "QEMU USB Mouse"); s->mouse_grabbed = 1; } @@ -493,12 +502,13 @@ static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len) return l; } -static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) +static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len) { int dz, b, l; + USBMouseState *s = &hs->ptr; if (!s->mouse_grabbed) { - s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, s, + s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs, 1, "QEMU USB Tablet"); s->mouse_grabbed = 1; } @@ -711,9 +721,9 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, break; case GET_REPORT: if (s->kind == USB_MOUSE) - ret = usb_mouse_poll(&s->ptr, data, length); + ret = usb_mouse_poll(s, data, length); else if (s->kind == USB_TABLET) - ret = usb_tablet_poll(&s->ptr, data, length); + ret = usb_tablet_poll(s, data, length); else if (s->kind == USB_KEYBOARD) ret = usb_keyboard_poll(&s->kbd, data, length); break; @@ -759,10 +769,14 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) switch(p->pid) { case USB_TOKEN_IN: if (p->devep == 1) { + /* TODO: Implement finite idle delays. */ + if (!(s->changed || s->idle)) + return USB_RET_NAK; + s->changed = 0; if (s->kind == USB_MOUSE) - ret = usb_mouse_poll(&s->ptr, p->data, p->len); + ret = usb_mouse_poll(s, p->data, p->len); else if (s->kind == USB_TABLET) - ret = usb_tablet_poll(&s->ptr, p->data, p->len); + ret = usb_tablet_poll(s, p->data, p->len); else if (s->kind == USB_KEYBOARD) ret = usb_keyboard_poll(&s->kbd, p->data, p->len); } else { @@ -803,6 +817,8 @@ USBDevice *usb_tablet_init(void) s->dev.handle_data = usb_hid_handle_data; s->dev.handle_destroy = usb_hid_handle_destroy; s->kind = USB_TABLET; + /* Force poll routine to be run and grab input the first time. */ + s->changed = 1; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); @@ -824,6 +840,8 @@ USBDevice *usb_mouse_init(void) s->dev.handle_data = usb_hid_handle_data; s->dev.handle_destroy = usb_hid_handle_destroy; s->kind = USB_MOUSE; + /* Force poll routine to be run and grab input the first time. */ + s->changed = 1; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 3936fe03f..f4f260877 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -526,7 +526,10 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) td->ctrl &= ~TD_CTRL_ACTIVE; if (ret >= 0) { td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); - td->ctrl &= ~TD_CTRL_ACTIVE; + /* The NAK bit may have been set by a previous frame, so clear it + here. The docs are somewhat unclear, but win2k relies on this + behavior. */ + td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK); if (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) && len < max_len) { -- cgit v1.2.3 From 49140a7748a6e8095cd93f2f58e33a9a8c78167b Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 10 Sep 2007 00:07:46 +0000 Subject: Fix VMDK 2GB bug, by Filip Navara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3158 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vmdk.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/block-vmdk.c b/block-vmdk.c index 0d3a804c4..35b6646d4 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -520,7 +520,6 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, int min_index, i, j; uint32_t min_count, *l2_table, tmp = 0; uint64_t cluster_offset; - int status; if (m_data) m_data->valid = 0; @@ -564,19 +563,11 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, cluster_offset = le32_to_cpu(l2_table[l2_index]); if (!cluster_offset) { - struct stat file_buf; - if (!allocate) return 0; // Avoid the L2 tables update for the images that have snapshots. if (!s->is_parent) { - status = stat(s->hd->filename, &file_buf); - if (status == -1) { - fprintf(stderr, "(VMDK) Fail file stat: filename =%s size=0x%llx errno=%s\n", - s->hd->filename, (uint64_t)file_buf.st_size, strerror(errno)); - return 0; - } - cluster_offset = file_buf.st_size; + cluster_offset = bdrv_getlength(s->hd); bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9)); cluster_offset >>= 9; -- cgit v1.2.3 From 408e7837aa64e57dc3377753448b5047946f0c50 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 10 Sep 2007 00:10:04 +0000 Subject: Fix the reported xlevel for Intel CPU, by Filip Navara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3159 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 8ce542583..327d54bbe 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -114,7 +114,7 @@ CPUX86State *cpu_x86_init(void) env->cpuid_ext_features = CPUID_EXT_SSE3; env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP; env->cpuid_features |= CPUID_APIC; - env->cpuid_xlevel = 0; + env->cpuid_xlevel = 0x80000006; { const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION; int c, len, i; -- cgit v1.2.3 From ce62e5ba096920a82b47c9ba62f35573bd61f546 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 11 Sep 2007 10:04:58 +0000 Subject: Fix tb->size mishandling, by Daniel Jacobowitz. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3160 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/translate.c | 1 - target-arm/translate.c | 1 - target-m68k/translate.c | 1 - target-mips/translate.c | 8 +++----- target-ppc/translate.c | 1 - target-sh4/translate.c | 1 - target-sparc/translate.c | 1 - 7 files changed, 3 insertions(+), 11 deletions(-) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 77e3b4ec8..9ed53be28 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -2047,7 +2047,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; - tb->size = 0; } else { tb->size = ctx.pc - pc_start; } diff --git a/target-arm/translate.c b/target-arm/translate.c index 799aef2f1..590959c2f 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3656,7 +3656,6 @@ static inline int gen_intermediate_code_internal(CPUState *env, lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; - tb->size = 0; } else { tb->size = dc->pc - pc_start; } diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 9fa46029a..8adc9c366 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3260,7 +3260,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; - tb->size = 0; } else { tb->size = dc->pc - pc_start; } diff --git a/target-mips/translate.c b/target-mips/translate.c index c87f2c987..d7bb20af3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5882,10 +5882,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_SYSCALL); break; case OPC_BREAK: - /* XXX: Hack to work around wrong handling of self-modifying code. */ - ctx->pc += 4; - save_cpu_state(ctx, 1); - ctx->pc -= 4; generate_exception(ctx, EXCP_BREAK); break; case OPC_SPIM: @@ -6433,6 +6429,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, save_cpu_state(&ctx, 1); ctx.bstate = BS_BRANCH; gen_op_debug(); + /* Include the breakpoint location or the tb won't + * be flushed when it must be. */ + ctx.pc += 4; goto done_generating; } } @@ -6493,7 +6492,6 @@ done_generating: lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; - tb->size = 0; } else { tb->size = ctx.pc - pc_start; } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e5064c082..40a1176c8 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5878,7 +5878,6 @@ static inline int gen_intermediate_code_internal (CPUState *env, lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; - tb->size = 0; } else { tb->size = ctx.nip - pc_start; } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 67ef8395e..5842c29d3 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1242,7 +1242,6 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, ii++; while (ii <= i) gen_opc_instr_start[ii++] = 0; - tb->size = 0; } else { tb->size = ctx.pc - pc_start; } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 2b42ffd34..54b861a84 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3365,7 +3365,6 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; - tb->size = 0; #if 0 if (loglevel > 0) { page_dump(logfile); -- cgit v1.2.3 From d14049eaec8d9c4349ae21eb276b70de995fdf68 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 02:20:40 +0000 Subject: Partial IDE DVD emulation, by Filip Navara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3161 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 4a7fa8b6d..3ff90c4de 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -261,6 +261,7 @@ * older drives only. */ #define GPCMD_GET_MEDIA_STATUS 0xda +#define GPCMD_MODE_SENSE_6 0x1a /* Mode page codes for mode sense/set */ #define GPMODE_R_W_ERROR_PAGE 0x01 @@ -1329,10 +1330,14 @@ static void ide_atapi_cmd(IDEState *s) ASC_MEDIUM_NOT_PRESENT); } break; + case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: { int action, code; - max_len = ube16_to_cpu(packet + 7); + if (packet[0] == GPCMD_MODE_SENSE_10) + max_len = ube16_to_cpu(packet + 7); + else + max_len = packet[4]; action = packet[2] >> 6; code = packet[2] & 0x3f; switch(action) { @@ -1368,7 +1373,7 @@ static void ide_atapi_cmd(IDEState *s) buf[8] = 0x2a; buf[9] = 0x12; - buf[10] = 0x00; + buf[10] = 0x08; buf[11] = 0x00; buf[12] = 0x70; @@ -1582,6 +1587,50 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 8, 8); } break; + case GPCMD_READ_DVD_STRUCTURE: + { + int media = packet[1]; + int layer = packet[6]; + int format = packet[2]; + int64_t total_sectors; + + if (media != 0 || layer != 0) + { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + } + + switch (format) { + case 0: + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + + memset(buf, 0, 2052); + + buf[4] = 1; // DVD-ROM, part version 1 + buf[5] = 0xf; // 120mm disc, maximum rate unspecified + buf[6] = 0; // one layer, embossed data + buf[7] = 0; + + cpu_to_ube32(buf + 8, 0); + cpu_to_ube32(buf + 12, total_sectors - 1); + cpu_to_ube32(buf + 16, total_sectors - 1); + + cpu_to_be16wu((uint16_t *)buf, 2048 + 4); + + ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4); + break; + + default: + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + } + break; + case GPCMD_SET_SPEED: + ide_atapi_cmd_ok(s); + break; case GPCMD_INQUIRY: max_len = packet[4]; buf[0] = 0x05; /* CD-ROM */ @@ -1597,6 +1646,29 @@ static void ide_atapi_cmd(IDEState *s) padstr8(buf + 32, 4, QEMU_VERSION); ide_atapi_cmd_reply(s, 36, max_len); break; + case GPCMD_GET_CONFIGURATION: + { + int64_t total_sectors; + + /* only feature 0 is supported */ + if (packet[2] != 0 || packet[3] != 0) { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); + break; + } + memset(buf, 0, 32); + bdrv_get_geometry(s->bs, &total_sectors); + buf[3] = 16; + buf[7] = total_sectors <= 1433600 ? 0x08 : 0x10; /* current profile */ + buf[10] = 0x10 | 0x1; + buf[11] = 0x08; /* size of profile list */ + buf[13] = 0x10; /* DVD-ROM profile */ + buf[14] = buf[7] == 0x10; /* (in)active */ + buf[17] = 0x08; /* CD-ROM profile */ + buf[18] = buf[7] == 0x08; /* (in)active */ + ide_atapi_cmd_reply(s, 32, 32); + break; + } default: ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE); -- cgit v1.2.3 From d8134d91d9b7f9f1c7cd0d8acf33df2c25629907 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 02:21:28 +0000 Subject: Intel cache info, by Filip Navara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3162 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 3c051b9ea..64c3a6132 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1657,10 +1657,10 @@ void helper_cpuid(void) break; case 2: /* cache info: needed for Pentium Pro compatibility */ - EAX = 0x410601; + EAX = 1; EBX = 0; ECX = 0; - EDX = 0; + EDX = 0x2c307d; break; case 0x80000000: EAX = env->cpuid_xlevel; -- cgit v1.2.3 From bde7600cea714af15126d5964a04ac4c48c580c9 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 02:22:37 +0000 Subject: Improved EEPRO 100 emulation, by Filip Navara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3163 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/eepro100.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/eepro100.c b/hw/eepro100.c index c39d36483..ad81cbf49 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1256,6 +1256,10 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val) eepro100_interrupt(s, 0); break; case SCBPort + 3: + case 24: + case 25: + case 26: + case 27: logout("addr=%s val=0x%02x\n", regname(addr), val); break; case SCBeeprom: -- cgit v1.2.3 From 1870a74c88461cf6003e290ba9485fa6bf9ed881 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 03:24:53 +0000 Subject: Stop the compiler from using section anchors. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3164 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.target b/Makefile.target index 7cfe52d77..9aa9f8602 100644 --- a/Makefile.target +++ b/Makefile.target @@ -97,6 +97,7 @@ OP_CFLAGS+=$(call cc-option, -fno-crossjumping, "") OP_CFLAGS+=$(call cc-option, -fno-align-labels, "") OP_CFLAGS+=$(call cc-option, -fno-align-jumps, "") OP_CFLAGS+=$(call cc-option, -fno-align-functions, $(call cc-option, -malign-functions=0, "")) +OP_CFLAGS+=$(call cc-option, -fno-section-anchors, "") ifeq ($(ARCH),i386) HELPER_CFLAGS+=-fomit-frame-pointer -- cgit v1.2.3 From c3e88d8c4f5bfbb83d7e3c1a6251eefa78ad485a Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 12:28:42 +0000 Subject: Allow more IDE power management, by Ben Guthro. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3165 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 3ff90c4de..4e17db3f0 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1986,6 +1986,8 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) case 0x67: /* NOP */ case 0x96: /* NOP */ case 0x9a: /* NOP */ + case 0x42: /* enable Automatic Acoustic Mode */ + case 0xc2: /* disable Automatic Acoustic Mode */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s); break; @@ -2024,13 +2026,17 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->status = READY_STAT; ide_set_irq(s); break; - case WIN_STANDBYNOW1: + case WIN_STANDBY: + case WIN_STANDBY2: + case WIN_STANDBYNOW1: case WIN_STANDBYNOW2: case WIN_IDLEIMMEDIATE: case CFA_IDLEIMMEDIATE: case WIN_SETIDLE1: case WIN_SETIDLE2: - s->status = READY_STAT; + case WIN_SLEEPNOW1: + case WIN_SLEEPNOW2: + s->status = READY_STAT; ide_set_irq(s); break; /* ATAPI commands */ -- cgit v1.2.3 From 8c05dbf9b68cc8444573116063582e01a0442b0b Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 12:29:23 +0000 Subject: Enhance raw io reliability, by Ben Guthro. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3166 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/block-raw.c b/block-raw.c index e9e502768..ab5bec27e 100644 --- a/block-raw.c +++ b/block-raw.c @@ -59,6 +59,13 @@ //#define DEBUG_FLOPPY +#define DEBUG_BLOCK +#if defined(DEBUG_BLOCK) && !defined(QEMU_TOOL) +#define DEBUG_BLOCK_PRINT(formatCstr, args...) fprintf(logfile, formatCstr, ##args); fflush(logfile) +#else +#define DEBUG_BLOCK_PRINT(formatCstr, args...) +#endif + #define FTYPE_FILE 0 #define FTYPE_CD 1 #define FTYPE_FD 2 @@ -70,6 +77,7 @@ typedef struct BDRVRawState { int fd; int type; + unsigned int lseek_err_cnt; #if defined(__linux__) /* linux floppy specific */ int fd_open_flags; @@ -87,6 +95,8 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) BDRVRawState *s = bs->opaque; int fd, open_flags, ret; + s->lseek_err_cnt = 0; + open_flags = O_BINARY; if ((flags & BDRV_O_ACCESS) == O_RDWR) { open_flags |= O_RDWR; @@ -137,8 +147,45 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, if (ret < 0) return ret; - lseek(s->fd, offset, SEEK_SET); + if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { + ++(s->lseek_err_cnt); + if(s->lseek_err_cnt <= 10) { + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] lseek failed : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, errno, strerror(errno)); + } + return -1; + } + s->lseek_err_cnt=0; + ret = read(s->fd, buf, count); + if (ret == count) + goto label__raw_read__success; + + DEBUG_BLOCK_PRINT("raw_read(%d:%s, %lld, %p, %d) [%lld] read failed %d : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, ret, errno, strerror(errno)); + + /* Try harder for CDrom. */ + if (bs->type == BDRV_TYPE_CDROM) { + lseek(s->fd, offset, SEEK_SET); + ret = read(s->fd, buf, count); + if (ret == count) + goto label__raw_read__success; + lseek(s->fd, offset, SEEK_SET); + ret = read(s->fd, buf, count); + if (ret == count) + goto label__raw_read__success; + + DEBUG_BLOCK_PRINT("raw_read(%d:%s, %lld, %p, %d) [%lld] retry read failed %d : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, ret, errno, strerror(errno)); + } + + return -1; + +label__raw_read__success: + return ret; } @@ -152,8 +199,29 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, if (ret < 0) return ret; - lseek(s->fd, offset, SEEK_SET); + if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { + ++(s->lseek_err_cnt); + if(s->lseek_err_cnt) { + DEBUG_BLOCK_PRINT("raw_write(%d:%s, %lld, %p, %d) [%lld] lseek failed : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, errno, strerror(errno)); + } + return -1; + } + s->lseek_err_cnt = 0; + ret = write(s->fd, buf, count); + if (ret == count) + goto label__raw_write__success; + + DEBUG_BLOCK_PRINT("raw_write(%d:%s, %lld, %p, %d) [%lld] write failed %d : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, ret, errno, strerror(errno)); + + return -1; + +label__raw_write__success: + return ret; } -- cgit v1.2.3 From cb4b976b82749b29ca6731d47e3a3237b32f9497 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 12:39:35 +0000 Subject: Move network related includes to vl.c to help SLIRP-less builds. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3167 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/libslirp.h | 8 -------- vl.c | 6 +++++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/slirp/libslirp.h b/slirp/libslirp.h index a9260afeb..b46d1758e 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -1,14 +1,6 @@ #ifndef _LIBSLIRP_H #define _LIBSLIRP_H -#ifdef _WIN32 -#include -int inet_aton(const char *cp, struct in_addr *ia); -#else -#include -#include -#endif - #ifdef __cplusplus extern "C" { #endif diff --git a/vl.c b/vl.c index d6f7e8d78..7313f77e0 100644 --- a/vl.c +++ b/vl.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #ifdef _BSD #include #ifndef __APPLE__ @@ -63,7 +65,6 @@ #include #include #include -#include #include #include #include @@ -76,6 +77,9 @@ #include #endif #endif +#else +#include +int inet_aton(const char *cp, struct in_addr *ia); #endif #if defined(CONFIG_SLIRP) -- cgit v1.2.3 From b7ffa3b1d25f2c68e851dc65fbfd97762f6c1748 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 12:40:37 +0000 Subject: Emulate spinning floppy disk, by Jan Jezabek. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3168 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/fdc.c b/hw/fdc.c index 4f04b729f..98a3c3131 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1843,5 +1843,13 @@ enqueue: static void fdctrl_result_timer(void *opaque) { fdctrl_t *fdctrl = opaque; + fdrive_t *cur_drv = get_cur_drv(fdctrl); + /* Pretend we are spinning. + * This is needed for Coherent, which uses READ ID to check for + * sector interleaving. + */ + if (cur_drv->last_sect != 0) { + cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1; + } fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } -- cgit v1.2.3 From baa7666c74e7495c0982afe2a566aabcd4dbe1ac Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 13 Sep 2007 12:41:42 +0000 Subject: Fix infinite loop in VNC support, by Marc Bevand. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3169 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vnc.c b/vnc.c index 64906980c..75e4fc968 100644 --- a/vnc.c +++ b/vnc.c @@ -1195,8 +1195,11 @@ static int protocol_client_msg(VncState *vs, char *data, size_t len) if (len == 1) return 8; - if (len == 8) - return 8 + read_u32(data, 4); + if (len == 8) { + uint32_t dlen = read_u32(data, 4); + if (dlen > 0) + return 8 + dlen; + } client_cut_text(vs, read_u32(data, 4), data + 8); break; -- cgit v1.2.3 From 3257d2b64f9df45ef7cbe85282da404584a06dfc Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 14 Sep 2007 22:22:13 +0000 Subject: Less magic constants, by Filip Navara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3170 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/eepro100.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/eepro100.c b/hw/eepro100.c index ad81cbf49..36b09252b 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -140,6 +140,7 @@ enum speedo_offsets { SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ SCBCtrlMDI = 16, /* MDI interface control. */ SCBEarlyRx = 20, /* Early receive byte count. */ + SCBFlow = 24, }; /* A speedo3 transmit buffer descriptor with two buffers... */ @@ -1256,10 +1257,10 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val) eepro100_interrupt(s, 0); break; case SCBPort + 3: - case 24: - case 25: - case 26: - case 27: + case SCBFlow: + case SCBFlow + 1: + case SCBFlow + 2: + case SCBFlow + 3: logout("addr=%s val=0x%02x\n", regname(addr), val); break; case SCBeeprom: -- cgit v1.2.3 From fe4d8f67eef57df9cf3ed9d6a855408af35c7080 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Sep 2007 19:53:43 +0000 Subject: Use UINT64_MAX instead of ULONG_LONG_MAX, suggested by Andreas Schwab. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3171 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 7313f77e0..5f7779af2 100644 --- a/vl.c +++ b/vl.c @@ -1176,7 +1176,7 @@ static void host_alarm_handler(int host_signum) static uint64_t qemu_next_deadline(void) { - int64_t nearest_delta_us = ULONG_LONG_MAX; + int64_t nearest_delta_us = UINT64_MAX; int64_t vmdelta_us; if (active_timers[QEMU_TIMER_REALTIME]) -- cgit v1.2.3 From bd494f4cbd4187dda8cc8f4739763f24a31a4c8b Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Sep 2007 20:03:23 +0000 Subject: Add a local copy of hpet.h. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3172 c046a42c-6fe2-441c-8c8c-71466251a162 --- hpet.h | 22 ++++++++++++++++++++++ vl.c | 7 ++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 hpet.h diff --git a/hpet.h b/hpet.h new file mode 100644 index 000000000..754051a44 --- /dev/null +++ b/hpet.h @@ -0,0 +1,22 @@ +#ifndef __HPET__ +#define __HPET__ 1 + + + +struct hpet_info { + unsigned long hi_ireqfreq; /* Hz */ + unsigned long hi_flags; /* information */ + unsigned short hi_hpet; + unsigned short hi_timer; +}; + +#define HPET_INFO_PERIODIC 0x0001 /* timer is periodic */ + +#define HPET_IE_ON _IO('h', 0x01) /* interrupt on */ +#define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */ +#define HPET_INFO _IOR('h', 0x03, struct hpet_info) +#define HPET_EPI _IO('h', 0x04) /* enable periodic */ +#define HPET_DPI _IO('h', 0x05) /* disable periodic */ +#define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */ + +#endif /* !__HPET__ */ diff --git a/vl.c b/vl.c index 5f7779af2..57e5d6027 100644 --- a/vl.c +++ b/vl.c @@ -58,7 +58,12 @@ #include #include #include -#include + +/* For the benefit of older linux systems which don't supply it, + we use a local copy of hpet.h. */ +/* #include */ +#include "hpet.h" + #include #include #else -- cgit v1.2.3 From 5fafdf24ef2c090c164d4dc89684b3f379dbdd87 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Sep 2007 21:08:06 +0000 Subject: find -type f | xargs sed -i 's/[\t ]$//g' # on most files git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3173 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 16 +- Makefile | 4 +- Makefile.target | 12 +- TODO | 2 +- aes.c | 8 +- alpha-dis.c | 2 +- arm-dis.c | 160 ++++++++--------- arm-semi.c | 8 +- block-bochs.c | 34 ++-- block-cloop.c | 16 +- block-cow.c | 32 ++-- block-dmg.c | 14 +- block-qcow.c | 114 ++++++------- block-qcow2.c | 258 ++++++++++++++-------------- block-raw.c | 70 ++++---- block-vmdk.c | 36 ++-- block-vpc.c | 20 +-- block-vvfat.c | 70 ++++---- block.c | 96 +++++------ block_int.h | 26 +-- bswap.h | 4 +- cocoa.m | 214 +++++++++++------------ configure | 6 +- console.c | 56 +++--- cpu-all.h | 40 ++--- cpu-defs.h | 14 +- cpu-exec.c | 148 ++++++++-------- cutils.c | 4 +- darwin-user/syscall.c | 4 +- dis-asm.h | 10 +- disas.c | 12 +- dyngen-exec.h | 2 +- dyngen.c | 230 ++++++++++++------------- dyngen.h | 18 +- elf.h | 2 +- elf_ops.h | 10 +- exec-all.h | 54 +++--- exec.c | 208 +++++++++++----------- fpu/softfloat-native.c | 4 +- gdbstub.c | 12 +- hw/acpi.c | 16 +- hw/adb.c | 24 +-- hw/alpha_palcode.c | 8 +- hw/an5206.c | 2 +- hw/apb_pci.c | 4 +- hw/apic.c | 40 ++--- hw/arm_boot.c | 6 +- hw/arm_gic.c | 4 +- hw/arm_pic.c | 2 +- hw/arm_pic.h | 2 +- hw/arm_sysctl.c | 2 +- hw/arm_timer.c | 2 +- hw/cdrom.c | 22 +-- hw/cirrus_vga.c | 92 +++++----- hw/cirrus_vga_rop.h | 4 +- hw/cirrus_vga_rop2.h | 30 ++-- hw/cuda.c | 48 +++--- hw/eepro100.c | 4 +- hw/esp.c | 6 +- hw/fdc.c | 18 +- hw/grackle_pci.c | 14 +- hw/gt64xxx.c | 14 +- hw/heathrow_pic.c | 8 +- hw/i2c.c | 2 +- hw/i8254.c | 16 +- hw/i8259.c | 28 +-- hw/ide.c | 150 ++++++++-------- hw/integratorcp.c | 2 +- hw/iommu.c | 8 +- hw/irq.c | 4 +- hw/isa_mmio.c | 2 +- hw/jazz_led.c | 4 +- hw/lsi53c895a.c | 8 +- hw/m48t59.c | 24 +-- hw/mc146818rtc.c | 32 ++-- hw/mcf5206.c | 6 +- hw/mcf5208.c | 2 +- hw/mcf_fec.c | 2 +- hw/mcf_intc.c | 2 +- hw/mcf_uart.c | 2 +- hw/mips_malta.c | 4 +- hw/mips_r4k.c | 2 +- hw/nand.c | 4 +- hw/ne2000.c | 62 +++---- hw/omap.h | 2 +- hw/omap_lcd_template.h | 16 +- hw/openpic.c | 26 +-- hw/parallel.c | 6 +- hw/pc.c | 66 +++---- hw/pci.c | 42 ++--- hw/pci_host.h | 2 +- hw/pckbd.c | 10 +- hw/pcnet.c | 148 ++++++++-------- hw/pflash_cfi02.c | 14 +- hw/piix_pci.c | 14 +- hw/pl011.c | 6 +- hw/pl050.c | 2 +- hw/pl080.c | 4 +- hw/pl110.c | 6 +- hw/pl110_template.h | 4 +- hw/pl181.c | 4 +- hw/pl190.c | 2 +- hw/ppc.c | 6 +- hw/ppc405.h | 4 +- hw/ppc405_boards.c | 26 +-- hw/ppc405_uc.c | 8 +- hw/ppc_chrp.c | 52 +++--- hw/ppc_prep.c | 6 +- hw/prep_pci.c | 8 +- hw/ps2.c | 14 +- hw/ptimer.c | 2 +- hw/pxa2xx_gpio.c | 2 +- hw/pxa2xx_template.h | 2 +- hw/realview.c | 2 +- hw/rtl8139.c | 52 +++--- hw/sd.c | 2 +- hw/sd.h | 2 +- hw/serial.c | 14 +- hw/sh7750.c | 4 +- hw/sh7750_regs.h | 40 ++--- hw/shix.c | 6 +- hw/slavio_intctl.c | 8 +- hw/slavio_misc.c | 4 +- hw/slavio_serial.c | 10 +- hw/slavio_timer.c | 6 +- hw/smbus.c | 2 +- hw/smbus.h | 4 +- hw/smbus_eeprom.c | 6 +- hw/smc91c111.c | 4 +- hw/sparc32_dma.c | 4 +- hw/sun4m.c | 14 +- hw/sun4u.c | 14 +- hw/tcx.c | 18 +- hw/unin_pci.c | 10 +- hw/usb-hid.c | 44 ++--- hw/usb-hub.c | 22 +-- hw/usb-msd.c | 12 +- hw/usb-uhci.c | 52 +++--- hw/usb-wacom.c | 6 +- hw/usb.c | 8 +- hw/usb.h | 10 +- hw/versatile_pci.c | 2 +- hw/versatilepb.c | 2 +- hw/vga.c | 174 +++++++++---------- hw/vga_int.h | 26 +-- hw/vga_template.h | 82 ++++----- hw/vmmouse.c | 4 +- keymaps.c | 4 +- keymaps/common | 2 +- keymaps/de-ch | 18 +- keymaps/et | 10 +- keymaps/fr | 2 +- keymaps/is | 20 +-- keymaps/modifiers | 6 +- keymaps/nl | 2 +- keymaps/sv | 8 +- kqemu.c | 74 ++++---- kqemu.h | 6 +- linux-user/alpha/syscall_nr.h | 4 +- linux-user/elfload.c | 54 +++--- linux-user/flat.h | 2 +- linux-user/flatload.c | 24 +-- linux-user/linuxload.c | 4 +- linux-user/m68k-sim.c | 2 +- linux-user/main.c | 110 ++++++------ linux-user/mmap.c | 48 +++--- linux-user/ppc/syscall.h | 2 +- linux-user/ppc64/syscall.h | 8 +- linux-user/qemu.h | 10 +- linux-user/sh4/termbits.h | 10 +- linux-user/signal.c | 90 +++++----- linux-user/sparc/termbits.h | 2 +- linux-user/sparc64/termbits.h | 2 +- linux-user/syscall.c | 168 +++++++++--------- linux-user/syscall_defs.h | 46 ++--- linux-user/syscall_types.h | 12 +- linux-user/vm86.c | 32 ++-- linux-user/x86_64/syscall_nr.h | 2 +- loader.c | 6 +- m68k-dis.c | 16 +- m68k-semi.c | 4 +- mips-dis.c | 8 +- monitor.c | 140 +++++++-------- osdep.c | 26 +-- ppc-dis.c | 4 +- qemu-doc.texi | 142 +++++++-------- qemu-img.c | 44 ++--- qemu-img.texi | 14 +- qemu-tech.texi | 50 +++--- readline.c | 8 +- s390-dis.c | 2 +- sdl.c | 14 +- sh4-dis.c | 12 +- slirp/COPYRIGHT | 2 +- slirp/bootp.c | 26 +-- slirp/cksum.c | 14 +- slirp/debug.c | 66 +++---- slirp/debug.h | 4 +- slirp/if.c | 60 +++---- slirp/if.h | 8 +- slirp/ip_icmp.c | 30 ++-- slirp/ip_input.c | 30 ++-- slirp/ip_output.c | 14 +- slirp/libslirp.h | 6 +- slirp/main.h | 4 +- slirp/mbuf.c | 32 ++-- slirp/mbuf.h | 6 +- slirp/misc.c | 172 +++++++++---------- slirp/misc.h | 4 +- slirp/sbuf.c | 32 ++-- slirp/sbuf.h | 4 +- slirp/slirp.c | 112 ++++++------ slirp/socket.c | 144 ++++++++-------- slirp/socket.h | 14 +- slirp/tcp_input.c | 166 +++++++++--------- slirp/tcp_output.c | 46 ++--- slirp/tcp_subr.c | 294 ++++++++++++++++---------------- slirp/tcp_timer.c | 22 +-- slirp/tftp.c | 44 ++--- slirp/tftp.h | 4 +- slirp/udp.c | 140 +++++++-------- slirp/udp.h | 2 +- softmmu-semi.h | 2 +- softmmu_header.h | 30 ++-- softmmu_template.h | 34 ++-- sparc-dis.c | 34 ++-- tap-win32.c | 52 +++--- target-alpha/cpu.h | 6 +- target-alpha/exec.h | 2 +- target-alpha/helper.c | 8 +- target-alpha/op.c | 2 +- target-alpha/op_helper.c | 2 +- target-alpha/op_helper.h | 2 +- target-alpha/op_helper_mem.h | 2 +- target-alpha/op_mem.h | 2 +- target-alpha/op_template.h | 2 +- target-alpha/translate.c | 18 +- target-arm/cpu.h | 12 +- target-arm/exec.h | 2 +- target-arm/helper.c | 2 +- target-arm/nwfpe/double_cpdo.c | 12 +- target-arm/nwfpe/extended_cpdo.c | 22 +-- target-arm/nwfpe/fpa11.c | 60 +++---- target-arm/nwfpe/fpa11.h | 2 +- target-arm/nwfpe/fpa11_cpdo.c | 32 ++-- target-arm/nwfpe/fpa11_cpdt.c | 62 +++---- target-arm/nwfpe/fpa11_cprt.c | 48 +++--- target-arm/nwfpe/fpopcode.c | 22 +-- target-arm/nwfpe/fpopcode.h | 18 +- target-arm/nwfpe/fpsr.h | 4 +- target-arm/nwfpe/single_cpdo.c | 10 +- target-arm/op.c | 10 +- target-arm/op_helper.c | 2 +- target-arm/op_iwmmxt.c | 6 +- target-arm/op_template.h | 2 +- target-arm/translate.c | 40 ++--- target-i386/cpu.h | 30 ++-- target-i386/exec.h | 16 +- target-i386/helper.c | 288 +++++++++++++++---------------- target-i386/helper2.c | 166 +++++++++--------- target-i386/op.c | 28 +-- target-i386/opreg_template.h | 2 +- target-i386/ops_sse.h | 6 +- target-i386/ops_template.h | 6 +- target-i386/ops_template_mem.h | 12 +- target-i386/translate-copy.c | 78 ++++----- target-i386/translate.c | 250 +++++++++++++-------------- target-m68k/cpu.h | 8 +- target-m68k/exec.h | 2 +- target-m68k/helper.c | 10 +- target-m68k/op.c | 6 +- target-m68k/op_helper.c | 2 +- target-m68k/translate.c | 14 +- target-mips/exec.h | 4 +- target-mips/fop_template.c | 4 +- target-mips/helper.c | 6 +- target-mips/op.c | 2 +- target-mips/op_helper.c | 16 +- target-mips/op_mem.c | 2 +- target-mips/op_template.c | 2 +- target-mips/translate.c | 12 +- target-ppc/cpu.h | 6 +- target-ppc/exec.h | 2 +- target-ppc/helper.c | 16 +- target-ppc/mfrom_table.c | 152 ++++++++--------- target-ppc/mfrom_table_gen.c | 2 +- target-ppc/op.c | 2 +- target-ppc/op_helper.c | 10 +- target-ppc/op_helper.h | 2 +- target-ppc/op_mem.h | 2 +- target-ppc/op_template.h | 2 +- target-ppc/translate.c | 26 +-- target-ppc/translate_init.c | 6 +- target-sh4/README.sh4 | 2 +- target-sh4/cpu.h | 4 +- target-sh4/exec.h | 2 +- target-sh4/helper.c | 2 +- target-sh4/op.c | 2 +- target-sh4/op_helper.c | 2 +- target-sh4/op_mem.c | 2 +- target-sh4/translate.c | 2 +- target-sparc/cpu.h | 2 +- target-sparc/fop_template.h | 2 +- target-sparc/helper.c | 4 +- target-sparc/op.c | 20 +-- target-sparc/op_helper.c | 28 +-- target-sparc/op_template.h | 2 +- target-sparc/translate.c | 14 +- tests/hello-arm.c | 2 +- tests/linux-test.c | 36 ++-- tests/qruncom.c | 30 ++-- tests/runcom.c | 10 +- tests/test-i386-code16.S | 10 +- tests/test-i386-muldiv.h | 16 +- tests/test-i386-vm86.S | 25 ++- tests/test-i386.c | 124 +++++++------- tests/test_path.c | 2 +- texi2pod.pl | 2 +- thunk.c | 20 +-- thunk.h | 8 +- translate-all.c | 26 +-- translate-op.c | 2 +- usb-linux.c | 62 +++---- vl.c | 360 +++++++++++++++++++-------------------- vl.h | 102 +++++------ vnc.c | 38 ++--- vnchextile.h | 4 +- 327 files changed, 4736 insertions(+), 4737 deletions(-) diff --git a/Changelog b/Changelog index fd2b5c692..f87f8a1e3 100644 --- a/Changelog +++ b/Changelog @@ -86,7 +86,7 @@ version 0.8.0: (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) @@ -135,7 +135,7 @@ version 0.6.1: - Mac OS X port (Pierre d'Herbemont) - Virtual console support - Better monitor line edition - - New block device layer + - 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) @@ -201,7 +201,7 @@ version 0.5.5: - 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) @@ -228,7 +228,7 @@ version 0.5.3: - added accurate CR0.MP/ME/TS emulation - fixed DMA memory write access (Win95 boot floppy fix) - graphical x86 linux loader - - command line monitor + - command line monitor - generic removable device support - support of CD-ROM change - multiple network interface support @@ -266,7 +266,7 @@ version 0.5.2: - eflags optimisation fix for string operations version 0.5.1: - + - float access fixes when using soft mmu - PC emulation support on PowerPC - A20 support @@ -281,7 +281,7 @@ version 0.5.1: - 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 @@ -319,7 +319,7 @@ version 0.4.2: - 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. @@ -405,7 +405,7 @@ version 0.1.3: - added bound, cmpxchg8b, cpuid instructions - added 16 bit addressing support/override for string operations - poll() fix - + version 0.1.2: - compile fixes diff --git a/Makefile b/Makefile index 36f11d27b..a52671588 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ dyngen$(EXESUF): dyngen.c 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 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 cscope.* *.pod *~ */*~ $(MAKE) -C tests clean for d in $(TARGET_DIRS); do \ @@ -89,7 +89,7 @@ endif test speed test2: all $(MAKE) -C tests $@ -TAGS: +TAGS: etags *.[ch] tests/*.[ch] cscope: diff --git a/Makefile.target b/Makefile.target index 9aa9f8602..bbcd33daa 100644 --- a/Makefile.target +++ b/Makefile.target @@ -269,7 +269,7 @@ OBJS+= libqemu.a # cpu emulator library LIBOBJS=exec.o kqemu.o translate-op.o translate-all.o cpu-exec.o\ - translate.o op.o + translate.o op.o ifdef CONFIG_SOFTFLOAT LIBOBJS+=fpu/softfloat.o else @@ -317,7 +317,7 @@ LIBOBJS+= op_helper.o helper.o alpha_palcode.o endif # NOTE: the disassembler code is only needed for debugging -LIBOBJS+=disas.o +LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) USE_I386_DIS=y endif @@ -483,7 +483,7 @@ VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o VL_OBJS+= m68k-semi.o endif ifdef CONFIG_GDBSTUB -VL_OBJS+=gdbstub.o +VL_OBJS+=gdbstub.o endif ifdef CONFIG_SDL VL_OBJS+=sdl.o x_keymap.o @@ -511,7 +511,7 @@ ifdef CONFIG_STATIC VL_LDFLAGS+=-static endif ifndef CONFIG_SOFTMMU -VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld +VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld endif ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 @@ -561,7 +561,7 @@ depend: $(SRCS) vldepend: $(VL_OBJS:.o=.c) $(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend -# libqemu +# libqemu libqemu.a: $(LIBOBJS) rm -f $@ @@ -665,7 +665,7 @@ $(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h clean: rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o -install: all +install: all ifneq ($(PROGS),) $(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)" endif diff --git a/TODO b/TODO index 516ea87bf..178a071bf 100644 --- a/TODO +++ b/TODO @@ -16,7 +16,7 @@ short term: - do not resize vga if invalid size. - avoid looping if only exceptions - TLB code protection support for PPC -- see openMosix Doc +- 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 diff --git a/aes.c b/aes.c index cd4484ff9..0a45c0b6c 100644 --- a/aes.c +++ b/aes.c @@ -1,5 +1,5 @@ /** - * + * * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project. */ /* @@ -1267,7 +1267,7 @@ void AES_decrypt(const unsigned char *in, unsigned char *out, 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 char *ivec, const int enc) { unsigned long n; @@ -1294,7 +1294,7 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, 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); @@ -1312,6 +1312,6 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, for(n=0; n < len; ++n) out[n] = tmp[n] ^ ivec[n]; memcpy(ivec, tmp, AES_BLOCK_SIZE); - } + } } } diff --git a/alpha-dis.c b/alpha-dis.c index 81a55e9c0..c6af1aa75 100644 --- a/alpha-dis.c +++ b/alpha-dis.c @@ -374,7 +374,7 @@ const struct alpha_operand alpha_operands[] = /* The signed "23-bit" aligned displacement of Branch format insns */ #define BDISP (MDISP + 1) - { 21, 0, BFD_RELOC_23_PCREL_S2, + { 21, 0, BFD_RELOC_23_PCREL_S2, AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp }, /* The 26-bit PALcode function */ diff --git a/arm-dis.c b/arm-dis.c index 1e027efc7..7032f9508 100644 --- a/arm-dis.c +++ b/arm-dis.c @@ -4,17 +4,17 @@ Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modification by James G. Smith (jsmith@cygnus.co.uk) -This file is part of libopcodes. +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. +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. +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 @@ -34,7 +34,7 @@ struct thumb_opcode }; /* format of the assembler string : - + %% % %d print the bitfield in decimal %x print the bitfield in hex @@ -104,7 +104,7 @@ static struct arm_opcode arm_opcodes[] = {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"}, @@ -116,7 +116,7 @@ static struct arm_opcode arm_opcodes[] = {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. */ + /* 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"}, @@ -303,7 +303,7 @@ static struct arm_opcode arm_opcodes[] = {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"}, + {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"}, @@ -571,7 +571,7 @@ 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[] = +static char * arm_shift[] = {"lsl", "lsr", "asr", "ror"}; /* Forward declarations. */ @@ -621,14 +621,14 @@ arm_decode_shift (given, func, stream) 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) @@ -636,10 +636,10 @@ arm_decode_shift (given, func, stream) func (stream, ", rrx"); return; } - + amount = 32; } - + func (stream, ", %s #%d", arm_shift[shift], amount); } else @@ -666,7 +666,7 @@ print_insn_arm1 (pc, info, given) if ((given & insn->mask) == insn->value) { char * c; - + for (c = insn->assembler; *c; c++) { if (*c == '%') @@ -682,14 +682,14 @@ print_insn_arm1 (pc, info, given) && ((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); @@ -710,13 +710,13 @@ print_insn_arm1 (pc, info, given) /* ie ignore the offset. */ offset = pc + 8; } - + func (stream, "\t; "); info->print_address_func (offset, info); } else { - func (stream, "[%s", + func (stream, "[%s", arm_regnames[(given >> 16) & 0xf]); if ((given & 0x01000000) != 0) { @@ -736,7 +736,7 @@ print_insn_arm1 (pc, info, given) arm_decode_shift (given, func, stream); } - func (stream, "]%s", + func (stream, "]%s", ((given & 0x00200000) != 0) ? "!" : ""); } else @@ -748,13 +748,13 @@ print_insn_arm1 (pc, info, given) func (stream, "], %s#%d", (((given & 0x00800000) == 0) ? "-" : ""), offset); - else + else func (stream, "]"); } else { func (stream, "], %s", - (((given & 0x00800000) == 0) + (((given & 0x00800000) == 0) ? "-" : "")); arm_decode_shift (given, func, stream); } @@ -767,18 +767,18 @@ print_insn_arm1 (pc, info, given) { /* 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", + func (stream, "[%s", arm_regnames[(given >> 16) & 0xf]); if ((given & 0x01000000) != 0) { @@ -801,7 +801,7 @@ print_insn_arm1 (pc, info, given) arm_regnames[given & 0xf]); } - func (stream, "]%s", + func (stream, "]%s", ((given & 0x00200000) != 0) ? "!" : ""); } else @@ -815,7 +815,7 @@ print_insn_arm1 (pc, info, given) func (stream, "], %s#%d", (((given & 0x00800000) == 0) ? "-" : ""), offset); - else + else func (stream, "]"); } else @@ -829,7 +829,7 @@ print_insn_arm1 (pc, info, given) } } break; - + case 'b': (*info->print_address_func) (BDISP (given) * 4 + pc + 8, info); @@ -911,7 +911,7 @@ print_insn_arm1 (pc, info, given) { bfd_vma address; bfd_vma offset = 0; - + if (given & 0x00800000) /* Is signed, hi bits should be ones. */ offset = (-1) ^ 0x00ffffff; @@ -920,7 +920,7 @@ print_insn_arm1 (pc, info, given) offset += given & 0x00ffffff; offset <<= 2; address = offset + pc + 8; - + if (given & 0x01000000) /* H bit allows addressing to 2-byte boundaries. */ address += 2; @@ -976,7 +976,7 @@ print_insn_arm1 (pc, info, given) func (stream, "3"); } break; - + case 'P': switch (given & 0x00080080) { @@ -1028,7 +1028,7 @@ print_insn_arm1 (pc, info, given) } break; - case '0': case '1': case '2': case '3': case '4': + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int bitstart = *c++ - '0'; @@ -1040,44 +1040,44 @@ print_insn_arm1 (pc, info, given) { 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) @@ -1089,20 +1089,20 @@ print_insn_arm1 (pc, info, given) 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]); @@ -1163,7 +1163,7 @@ print_insn_arm1 (pc, info, given) } break; - + default: abort (); } @@ -1252,7 +1252,7 @@ print_insn_thumb (pc, info, given) if (!*c) /* Check for empty (not NULL) assembler string. */ { long offset; - + info->bytes_per_chunk = 4; info->bytes_per_line = 4; @@ -1274,16 +1274,16 @@ print_insn_thumb (pc, info, given) { 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 '%': @@ -1293,11 +1293,11 @@ print_insn_thumb (pc, info, given) case 'S': { long reg; - + reg = (given >> 3) & 0x7; if (given & (1 << 6)) reg += 8; - + func (stream, "%s", arm_regnames[reg]); } break; @@ -1305,11 +1305,11 @@ print_insn_thumb (pc, info, given) case 'D': { long reg; - + reg = given & 0x7; if (given & (1 << 7)) reg += 8; - + func (stream, "%s", arm_regnames[reg]); } break; @@ -1331,9 +1331,9 @@ print_insn_thumb (pc, info, given) { 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++) @@ -1365,12 +1365,12 @@ print_insn_thumb (pc, info, given) break; - case '0': case '1': case '2': case '3': case '4': + 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'; @@ -1379,7 +1379,7 @@ print_insn_thumb (pc, info, given) case '-': { long reg; - + c++; while (*c >= '0' && *c <= '9') bitend = (bitend * 10) + *c++ - '0'; @@ -1478,11 +1478,11 @@ parse_arm_disassembler_option (option) { if (option == NULL) return; - + if (strneq (option, "reg-names-", 10)) { int i; - + option += 10; for (i = NUM_ARM_REGNAMES; i--;) @@ -1491,7 +1491,7 @@ parse_arm_disassembler_option (option) regname_selected = i; break; } - + if (i < 0) fprintf (stderr, _("Unrecognised register name set: %s\n"), option); } @@ -1501,7 +1501,7 @@ parse_arm_disassembler_option (option) force_thumb = 0; else fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); - + return; } @@ -1512,7 +1512,7 @@ parse_disassembler_options (options) char * options; { char * space; - + if (options == NULL) return; @@ -1550,25 +1550,25 @@ print_insn_arm (pc, info) 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 @@ -1580,15 +1580,15 @@ print_insn_arm (pc, info) { 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; @@ -1599,17 +1599,17 @@ print_insn_arm (pc, 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 @@ -1621,13 +1621,13 @@ print_insn_arm (pc, info) 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) @@ -1635,7 +1635,7 @@ print_insn_arm (pc, info) info->memory_error_func (status, pc + 4, info); return -1; } - + given |= (b[0] << 24) | (b[1] << 16); } else @@ -1644,7 +1644,7 @@ print_insn_arm (pc, info) 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 @@ -1668,7 +1668,7 @@ print_arm_disassembler_options (FILE * stream) 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, diff --git a/arm-semi.c b/arm-semi.c index aaad1c99f..86b1e9f57 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -1,6 +1,6 @@ /* * Arm "Angel" semihosting syscalls - * + * * Copyright (c) 2005, 2007 CodeSourcery. * Written by Paul Brook. * @@ -194,7 +194,7 @@ uint32_t do_arm_semihosting(CPUState *env) return STDOUT_FILENO; } if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), + gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]); return env->regs[0]; } else { @@ -283,7 +283,7 @@ uint32_t do_arm_semihosting(CPUState *env) } case SYS_FLEN: if (use_gdb_syscalls()) { - gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x", + gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x", ARG(0), env->regs[13]-64); return env->regs[0]; } else { @@ -401,7 +401,7 @@ uint32_t do_arm_semihosting(CPUState *env) } ts->heap_limit = limit; } - + ptr = lock_user(ARG(0), 16, 0); ptr[0] = tswap32(ts->heap_base); ptr[1] = tswap32(ts->heap_limit); diff --git a/block-bochs.c b/block-bochs.c index 35e2a6cf0..ca95ae84e 100644 --- a/block-bochs.c +++ b/block-bochs.c @@ -1,9 +1,9 @@ /* * 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 @@ -44,7 +44,7 @@ struct bochs_header_v1 { char subtype[16]; // "Undoable" / "Volatile" / "Growing" uint32_t version; uint32_t header; // size of header - + union { struct { uint32_t catalog; // num of entries @@ -64,7 +64,7 @@ struct bochs_header { char subtype[16]; // "Undoable" / "Volatile" / "Growing" uint32_t version; uint32_t header; // size of header - + union { struct { uint32_t catalog; // num of entries @@ -83,9 +83,9 @@ typedef struct BDRVBochsState { uint32_t *catalog_bitmap; int catalog_size; - + int data_offset; - + int bitmap_blocks; int extent_blocks; int extent_size; @@ -94,7 +94,7 @@ typedef struct 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; @@ -121,9 +121,9 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) if (fd < 0) return -1; } - + bs->read_only = 1; // no write support yet - + s->fd = fd; if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) { @@ -161,7 +161,7 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) 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; @@ -180,7 +180,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) // 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", @@ -191,17 +191,17 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) 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", @@ -210,11 +210,11 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) } lseek(s->fd, block_offset, SEEK_SET); - + return 0; } -static int bochs_read(BlockDriverState *bs, int64_t sector_num, +static int bochs_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVBochsState *s = bs->opaque; diff --git a/block-cloop.c b/block-cloop.c index f51c32d1b..4dfe766b7 100644 --- a/block-cloop.c +++ b/block-cloop.c @@ -1,8 +1,8 @@ /* * 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 @@ -96,7 +96,7 @@ 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; @@ -107,12 +107,12 @@ 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) + if (ret != bytes) return -1; - + s->zstream.next_in = s->compressed_block; s->zstream.avail_in = bytes; s->zstream.next_out = s->uncompressed_block; @@ -123,13 +123,13 @@ static inline int cloop_read_block(BDRVCloopState *s,int block_num) 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, +static int cloop_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVCloopState *s = bs->opaque; diff --git a/block-cow.c b/block-cow.c index 07c8a7bf1..8880c1cb6 100644 --- a/block-cow.c +++ b/block-cow.c @@ -1,8 +1,8 @@ /* * 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 @@ -56,7 +56,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) if (buf_size >= sizeof(struct cow_header_v2) && be32_to_cpu(cow_header->magic) == COW_MAGIC && - be32_to_cpu(cow_header->version) == COW_VERSION) + be32_to_cpu(cow_header->version) == COW_VERSION) return 100; else return 0; @@ -85,18 +85,18 @@ static int cow_open(BlockDriverState *bs, const char *filename, int flags) 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), + 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, + 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) @@ -143,24 +143,24 @@ static inline int is_changed(uint8_t *bitmap, return changed; } -static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num, +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, +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) + if (ret != n * 512) return -1; } else { if (bs->backing_hd) { @@ -179,15 +179,15 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num, return 0; } -static int cow_write(BlockDriverState *bs, int64_t sector_num, +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) + if (ret != nb_sectors * 512) return -1; for (i = 0; i < nb_sectors; i++) cow_set_bit(s->cow_bitmap, sector_num + i); @@ -211,7 +211,7 @@ static int cow_create(const char *filename, int64_t image_sectors, if (flags) return -ENOTSUP; - cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); if (cow_fd < 0) return -1; diff --git a/block-dmg.c b/block-dmg.c index a883a23f8..a46b80199 100644 --- a/block-dmg.c +++ b/block-dmg.c @@ -1,8 +1,8 @@ /* * 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 @@ -28,7 +28,7 @@ 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, @@ -86,7 +86,7 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) 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: @@ -167,7 +167,7 @@ dmg_close: goto dmg_close; s->current_chunk = s->n_chunks; - + return 0; } @@ -227,7 +227,7 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) 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; @@ -253,7 +253,7 @@ static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) return 0; } -static int dmg_read(BlockDriverState *bs, int64_t sector_num, +static int dmg_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVDMGState *s = bs->opaque; diff --git a/block-qcow.c b/block-qcow.c index d5333b379..208e35cca 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -1,8 +1,8 @@ /* * 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 @@ -80,10 +80,10 @@ 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) + be32_to_cpu(cow_header->version) == QCOW_VERSION) return 100; else return 0; @@ -108,7 +108,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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) @@ -134,7 +134,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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)) != + 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++) { @@ -151,7 +151,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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; @@ -177,7 +177,7 @@ 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) @@ -231,7 +231,7 @@ static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num, 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, + AES_cbc_encrypt(in_buf, out_buf, 512, key, ivec.b, enc); sector_num++; in_buf += 512; @@ -248,7 +248,7 @@ static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num, * * 2 to allocate a compressed cluster of size * 'compressed_size'. 'compressed_size' must be > 0 and < - * cluster_size + * cluster_size * * return 0 if not allocated. */ @@ -262,7 +262,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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; @@ -276,7 +276,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* 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), + if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp)) return 0; new_l2_table = 1; @@ -309,7 +309,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, s->l2_size * sizeof(uint64_t)) return 0; } else { - if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != s->l2_size * sizeof(uint64_t)) return 0; } @@ -318,7 +318,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, found: l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); cluster_offset = be64_to_cpu(l2_table[l2_index]); - if (!cluster_offset || + if (!cluster_offset || ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) { if (!allocate) return 0; @@ -331,54 +331,54 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, if (decompress_cluster(s, cluster_offset) < 0) return 0; cluster_offset = bdrv_getlength(s->hd); - cluster_offset = (cluster_offset + s->cluster_size - 1) & + 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) != + 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) & + 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 && + 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, + 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, + if (bdrv_pwrite(s->hd, cluster_offset + i * 512, s->cluster_data, 512) != 512) return -1; } } } } else { - cluster_offset |= QCOW_OFLAG_COMPRESSED | + 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, + 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, +static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { BDRVQcowState *s = bs->opaque; @@ -420,7 +420,7 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, inflateEnd(strm); return 0; } - + static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) { int ret, csize; @@ -431,7 +431,7 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) 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) + if (ret != csize) return -1; if (decompress_buffer(s->cluster_cache, s->cluster_size, s->cluster_data, csize) < 0) { @@ -444,13 +444,13 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) #if 0 -static int qcow_read(BlockDriverState *bs, int64_t sector_num, +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); @@ -472,10 +472,10 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, 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) + if (ret != n * 512) return -1; if (s->crypt_method) { - encrypt_sectors(s, sector_num, buf, buf, n, 0, + encrypt_sectors(s, sector_num, buf, buf, n, 0, &s->aes_decrypt_key); } } @@ -487,32 +487,32 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, } #endif -static int qcow_write(BlockDriverState *bs, int64_t sector_num, +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, + 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, + 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) + if (ret != n * 512) return -1; nb_sectors -= n; sector_num += n; @@ -529,7 +529,7 @@ typedef struct QCowAIOCB { int nb_sectors; int n; uint64_t cluster_offset; - uint8_t *cluster_data; + uint8_t *cluster_data; BlockDriverAIOCB *hd_aiocb; } QCowAIOCB; @@ -556,8 +556,8 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* nothing to do */ } else { if (s->crypt_method) { - encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, - acb->n, 0, + encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, + acb->n, 0, &s->aes_decrypt_key); } } @@ -572,9 +572,9 @@ static void qcow_aio_read_cb(void *opaque, int ret) qemu_aio_release(acb); return; } - + /* prepare next AIO request */ - acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, + 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; @@ -597,7 +597,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* add AIO support for compressed blocks ? */ if (decompress_cluster(s, acb->cluster_offset) < 0) goto fail; - memcpy(acb->buf, + memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512, 512 * acb->n); goto redo; } else { @@ -606,7 +606,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) goto fail; } acb->hd_aiocb = bdrv_aio_read(s->hd, - (acb->cluster_offset >> 9) + index_in_cluster, + (acb->cluster_offset >> 9) + index_in_cluster, acb->buf, acb->n, qcow_aio_read_cb, acb); if (acb->hd_aiocb == NULL) goto fail; @@ -627,7 +627,7 @@ static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs, acb->buf = buf; acb->nb_sectors = nb_sectors; acb->n = 0; - acb->cluster_offset = 0; + acb->cluster_offset = 0; qcow_aio_read_cb(acb, 0); return &acb->common; @@ -661,13 +661,13 @@ static void qcow_aio_write_cb(void *opaque, int ret) 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, + 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; @@ -681,15 +681,15 @@ static void qcow_aio_write_cb(void *opaque, int ret) goto fail; } } - encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, + 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, + (cluster_offset >> 9) + index_in_cluster, + src_buf, acb->n, qcow_aio_write_cb, acb); if (acb->hd_aiocb == NULL) goto fail; @@ -701,7 +701,7 @@ static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs, { BDRVQcowState *s = bs->opaque; QCowAIOCB *acb; - + s->cluster_cache_offset = -1; /* disable compressed cache */ acb = qemu_aio_get(bs, cb, opaque); @@ -712,7 +712,7 @@ static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs, acb->buf = (uint8_t *)buf; acb->nb_sectors = nb_sectors; acb->n = 0; - + qcow_aio_write_cb(acb, 0); return &acb->common; } @@ -774,7 +774,7 @@ static int qcow_create(const char *filename, int64_t total_size, } else { header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); } - + /* write all the data */ write(fd, &header, sizeof(header)); if (backing_file) { @@ -811,7 +811,7 @@ static int qcow_make_empty(BlockDriverState *bs) /* 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, +static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVQcowState *s = bs->opaque; @@ -830,7 +830,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, /* best compression, small window, no zlib header */ memset(&strm, 0, sizeof(strm)); ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, - Z_DEFLATED, -12, + Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY); if (ret != 0) { qemu_free(out_buf); @@ -856,7 +856,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, /* 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, + 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) { @@ -864,7 +864,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return -1; } } - + qemu_free(out_buf); return 0; } diff --git a/block-qcow2.c b/block-qcow2.c index 273359c28..2df061544 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -1,8 +1,8 @@ /* * 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 @@ -34,10 +34,10 @@ - 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 + - 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. + 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. @@ -45,7 +45,7 @@ //#define DEBUG_ALLOC //#define DEBUG_ALLOC2 - + #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) #define QCOW_VERSION 2 @@ -152,22 +152,22 @@ typedef struct BDRVQcowState { } BDRVQcowState; static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); -static int qcow_read(BlockDriverState *bs, int64_t sector_num, +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, +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, +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, +static void free_clusters(BlockDriverState *bs, int64_t offset, int64_t size); #ifdef DEBUG_ALLOC static void check_refcounts(BlockDriverState *bs); @@ -176,10 +176,10 @@ static void check_refcounts(BlockDriverState *bs); 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) + be32_to_cpu(cow_header->version) == QCOW_VERSION) return 100; else return 0; @@ -209,11 +209,11 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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 || + if (header.size <= 1 || + header.cluster_bits < 9 || header.cluster_bits > 16) goto fail; if (header.crypt_method > QCOW_CRYPT_AES) @@ -231,7 +231,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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 = + s->refcount_table_size = header.refcount_table_clusters << (s->cluster_bits - 3); s->snapshots_offset = header.snapshots_offset; @@ -249,7 +249,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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)) != + 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++) { @@ -267,7 +267,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) if (!s->cluster_data) goto fail; s->cluster_cache_offset = -1; - + if (refcount_init(bs) < 0) goto fail; @@ -304,7 +304,7 @@ 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) @@ -358,7 +358,7 @@ static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num, 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, + AES_cbc_encrypt(in_buf, out_buf, 512, key, ivec.b, enc); sector_num++; in_buf += 512; @@ -379,12 +379,12 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect, if (ret < 0) return ret; if (s->crypt_method) { - encrypt_sectors(s, start_sect + n_start, - s->cluster_data, + 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, + ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start, s->cluster_data, n); if (ret < 0) return ret; @@ -451,7 +451,7 @@ static int grow_l1_table(BlockDriverState *bs, int min_size) /* 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); @@ -459,7 +459,7 @@ static int grow_l1_table(BlockDriverState *bs, int min_size) 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), @@ -489,7 +489,7 @@ static int grow_l1_table(BlockDriverState *bs, int min_size) * * 2 to allocate a compressed cluster of size * 'compressed_size'. 'compressed_size' must be > 0 and < - * cluster_size + * cluster_size * * return 0 if not allocated. */ @@ -501,7 +501,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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 */ @@ -521,7 +521,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* 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), + 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); @@ -530,12 +530,12 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, if (old_l2_offset == 0) { memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); } else { - if (bdrv_pread(s->hd, old_l2_offset, + 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, + if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != s->l2_size * sizeof(uint64_t)) return 0; @@ -563,7 +563,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* 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)) != + if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != s->l2_size * sizeof(uint64_t)) return 0; } @@ -581,7 +581,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* free the cluster */ if (cluster_offset & QCOW_OFLAG_COMPRESSED) { int nb_csectors; - nb_csectors = ((cluster_offset >> s->csize_shift) & + nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1; free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511, nb_csectors * 512); @@ -600,7 +600,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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); @@ -615,22 +615,22 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, } else { int nb_csectors; cluster_offset = alloc_bytes(bs, compressed_size); - nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - + nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - (cluster_offset >> 9); - cluster_offset |= QCOW_OFLAG_COMPRESSED | + 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, + 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, +static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { BDRVQcowState *s = bs->opaque; @@ -672,7 +672,7 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, inflateEnd(strm); return 0; } - + static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) { int ret, csize, nb_csectors, sector_offset; @@ -697,7 +697,7 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) } /* handle reading after the end of the backing file */ -static int backing_read1(BlockDriverState *bs, +static int backing_read1(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { int n1; @@ -711,13 +711,13 @@ static int backing_read1(BlockDriverState *bs, return n1; } -static int qcow_read(BlockDriverState *bs, int64_t sector_num, +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); @@ -742,10 +742,10 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, 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) + if (ret != n * 512) return -1; if (s->crypt_method) { - encrypt_sectors(s, sector_num, buf, buf, n, 0, + encrypt_sectors(s, sector_num, buf, buf, n, 0, &s->aes_decrypt_key); } } @@ -756,32 +756,32 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, return 0; } -static int qcow_write(BlockDriverState *bs, int64_t sector_num, +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, + 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, + 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) + if (ret != n * 512) return -1; nb_sectors -= n; sector_num += n; @@ -798,7 +798,7 @@ typedef struct QCowAIOCB { int nb_sectors; int n; uint64_t cluster_offset; - uint8_t *cluster_data; + uint8_t *cluster_data; BlockDriverAIOCB *hd_aiocb; } QCowAIOCB; @@ -825,8 +825,8 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* nothing to do */ } else { if (s->crypt_method) { - encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, - acb->n, 0, + encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, + acb->n, 0, &s->aes_decrypt_key); } } @@ -841,9 +841,9 @@ static void qcow_aio_read_cb(void *opaque, int ret) qemu_aio_release(acb); return; } - + /* prepare next AIO request */ - acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, + 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; @@ -853,10 +853,10 @@ static void qcow_aio_read_cb(void *opaque, int ret) if (!acb->cluster_offset) { if (bs->backing_hd) { /* read from the base image */ - n1 = backing_read1(bs->backing_hd, acb->sector_num, + 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->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; @@ -872,7 +872,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* add AIO support for compressed blocks ? */ if (decompress_cluster(s, acb->cluster_offset) < 0) goto fail; - memcpy(acb->buf, + memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512, 512 * acb->n); goto redo; } else { @@ -881,7 +881,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) goto fail; } acb->hd_aiocb = bdrv_aio_read(s->hd, - (acb->cluster_offset >> 9) + index_in_cluster, + (acb->cluster_offset >> 9) + index_in_cluster, acb->buf, acb->n, qcow_aio_read_cb, acb); if (acb->hd_aiocb == NULL) goto fail; @@ -948,13 +948,13 @@ static void qcow_aio_write_cb(void *opaque, int ret) 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, + 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; @@ -968,15 +968,15 @@ static void qcow_aio_write_cb(void *opaque, int ret) goto fail; } } - encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, + 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, + (cluster_offset >> 9) + index_in_cluster, + src_buf, acb->n, qcow_aio_write_cb, acb); if (acb->hd_aiocb == NULL) goto fail; @@ -988,13 +988,13 @@ static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs, { 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; } @@ -1038,7 +1038,7 @@ static void create_refcount_update(QCowCreateState *s, start = offset & ~(s->cluster_size - 1); last = (offset + size - 1) & ~(s->cluster_size - 1); - for(cluster_offset = start; cluster_offset <= last; + 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); @@ -1054,7 +1054,7 @@ static int qcow_create(const char *filename, int64_t total_size, 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); @@ -1096,7 +1096,7 @@ static int qcow_create(const char *filename, int64_t total_size, 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); @@ -1111,7 +1111,7 @@ static int qcow_create(const char *filename, int64_t total_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) { @@ -1124,7 +1124,7 @@ static int qcow_create(const char *filename, int64_t total_size, } 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); @@ -1153,7 +1153,7 @@ static int qcow_make_empty(BlockDriverState *bs) ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length); if (ret < 0) return ret; - + l2_cache_reset(bs); #endif return 0; @@ -1161,7 +1161,7 @@ static int qcow_make_empty(BlockDriverState *bs) /* 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, +static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVQcowState *s = bs->opaque; @@ -1189,7 +1189,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, /* best compression, small window, no zlib header */ memset(&strm, 0, sizeof(strm)); ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, - Z_DEFLATED, -12, + Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY); if (ret != 0) { qemu_free(out_buf); @@ -1215,7 +1215,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, /* 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, + 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) { @@ -1223,7 +1223,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return -1; } } - + qemu_free(out_buf); return 0; } @@ -1238,7 +1238,7 @@ 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 << + bdi->vm_state_offset = (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits); return 0; } @@ -1247,7 +1247,7 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) /* snapshot support */ /* update the refcounts of snapshots and the copied flag */ -static int update_snapshot_refcount(BlockDriverState *bs, +static int update_snapshot_refcount(BlockDriverState *bs, int64_t l1_table_offset, int l1_size, int addend) @@ -1256,7 +1256,7 @@ static int update_snapshot_refcount(BlockDriverState *bs, 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; @@ -1268,7 +1268,7 @@ static int update_snapshot_refcount(BlockDriverState *bs, if (!l1_table) goto fail; l1_allocated = 1; - if (bdrv_pread(s->hd, l1_table_offset, + if (bdrv_pread(s->hd, l1_table_offset, l1_table, l1_size2) != l1_size2) goto fail; for(i = 0;i < l1_size; i++) @@ -1278,7 +1278,7 @@ static int update_snapshot_refcount(BlockDriverState *bs, 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) @@ -1298,13 +1298,13 @@ static int update_snapshot_refcount(BlockDriverState *bs, old_offset = offset; offset &= ~QCOW_OFLAG_COPIED; if (offset & QCOW_OFLAG_COMPRESSED) { - nb_csectors = ((offset >> s->csize_shift) & + 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; + refcount = 2; } else { if (addend != 0) { refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend); @@ -1323,7 +1323,7 @@ static int update_snapshot_refcount(BlockDriverState *bs, } } if (l2_modified) { - if (bdrv_pwrite(s->hd, + if (bdrv_pwrite(s->hd, l2_offset, l2_table, l2_size) != l2_size) goto fail; } @@ -1345,7 +1345,7 @@ static int update_snapshot_refcount(BlockDriverState *bs, 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, + if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, l1_size2) != l1_size2) goto fail; for(i = 0; i < l1_size; i++) @@ -1455,7 +1455,7 @@ static int qcow_write_snapshots(BlockDriverState *bs) 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)); @@ -1465,7 +1465,7 @@ static int qcow_write_snapshots(BlockDriverState *bs) 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); @@ -1533,7 +1533,7 @@ 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; @@ -1545,14 +1545,14 @@ static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name) } /* if no id is provided, a new one is constructed */ -static int qcow_snapshot_create(BlockDriverState *bs, +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') { @@ -1590,7 +1590,7 @@ static int qcow_snapshot_create(BlockDriverState *bs, 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)) != + l1_table, s->l1_size * sizeof(uint64_t)) != (s->l1_size * sizeof(uint64_t))) goto fail; qemu_free(l1_table); @@ -1616,7 +1616,7 @@ static int qcow_snapshot_create(BlockDriverState *bs, } /* copy the snapshot 'snapshot_name' into the current disk image */ -static int qcow_snapshot_goto(BlockDriverState *bs, +static int qcow_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) { BDRVQcowState *s = bs->opaque; @@ -1637,7 +1637,7 @@ static int qcow_snapshot_goto(BlockDriverState *bs, 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, + 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, @@ -1663,7 +1663,7 @@ 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; @@ -1693,7 +1693,7 @@ static int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) return 0; } -static int qcow_snapshot_list(BlockDriverState *bs, +static int qcow_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) { BDRVQcowState *s = bs->opaque; @@ -1731,7 +1731,7 @@ 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; @@ -1760,12 +1760,12 @@ static void refcount_close(BlockDriverState *bs) } -static int load_refcount_block(BlockDriverState *bs, +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, + ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache, s->cluster_size); if (ret != s->cluster_size) return -EIO; @@ -1790,7 +1790,7 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index) if (load_refcount_block(bs, refcount_block_offset) < 0) return 1; } - block_index = cluster_index & + block_index = cluster_index & ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); return be16_to_cpu(s->refcount_block_cache[block_index]); } @@ -1812,7 +1812,7 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size) } #ifdef DEBUG_ALLOC2 printf("alloc_clusters: size=%lld -> %lld\n", - size, + size, (s->free_cluster_index - nb_clusters) << s->cluster_bits); #endif return (s->free_cluster_index - nb_clusters) << s->cluster_bits; @@ -1839,13 +1839,13 @@ 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 - + free_in_cluster = s->cluster_size - (s->free_byte_offset & (s->cluster_size - 1)); if (size <= free_in_cluster) { /* enough space in current cluster */ @@ -1872,7 +1872,7 @@ static int64_t alloc_bytes(BlockDriverState *bs, int size) return offset; } -static void free_clusters(BlockDriverState *bs, +static void free_clusters(BlockDriverState *bs, int64_t offset, int64_t size) { update_refcount(bs, offset, size, -1); @@ -1912,14 +1912,14 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) new_table = qemu_mallocz(new_table_size2); if (!new_table) return -ENOMEM; - memcpy(new_table, s->refcount_table, + 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) + if (ret != new_table_size2) goto fail; for(i = 0; i < s->refcount_table_size; i++) be64_to_cpus(&new_table[i]); @@ -1950,7 +1950,7 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) /* addend must be 1 or -1 */ /* XXX: cache several refcount block clusters ? */ -static int update_cluster_refcount(BlockDriverState *bs, +static int update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index, int addend) { @@ -1980,8 +1980,8 @@ static int update_cluster_refcount(BlockDriverState *bs, 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), + ret = bdrv_pwrite(s->hd, s->refcount_table_offset + + refcount_table_index * sizeof(uint64_t), &data64, sizeof(data64)); if (ret != sizeof(data64)) return -EINVAL; @@ -1996,7 +1996,7 @@ static int update_cluster_refcount(BlockDriverState *bs, } } /* we can update the count and save it */ - block_index = cluster_index & + block_index = cluster_index & ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); refcount = be16_to_cpu(s->refcount_block_cache[block_index]); refcount += addend; @@ -2006,50 +2006,50 @@ static int update_cluster_refcount(BlockDriverState *bs, 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), + 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, +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", + 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; + 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, +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; + 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) { @@ -2062,8 +2062,8 @@ static void inc_refcounts(BlockDriverState *bs, } } -static int check_refcounts_l1(BlockDriverState *bs, - uint16_t *refcount_table, +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) @@ -2081,12 +2081,12 @@ static int check_refcounts_l1(BlockDriverState *bs, l1_table = qemu_malloc(l1_size2); if (!l1_table) goto fail; - if (bdrv_pread(s->hd, l1_table_offset, + 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) @@ -2113,10 +2113,10 @@ static int check_refcounts_l1(BlockDriverState *bs, offset >> s->cluster_bits); offset &= ~QCOW_OFLAG_COPIED; } - nb_csectors = ((offset >> s->csize_shift) & + nb_csectors = ((offset >> s->csize_shift) & s->csize_mask) + 1; offset &= s->cluster_offset_mask; - inc_refcounts(bs, refcount_table, + inc_refcounts(bs, refcount_table, refcount_table_size, offset & ~511, nb_csectors * 512); } else { @@ -2128,13 +2128,13 @@ static int check_refcounts_l1(BlockDriverState *bs, } } offset &= ~QCOW_OFLAG_COPIED; - inc_refcounts(bs, refcount_table, + inc_refcounts(bs, refcount_table, refcount_table_size, offset, s->cluster_size); } } } - inc_refcounts(bs, refcount_table, + inc_refcounts(bs, refcount_table, refcount_table_size, l2_offset, s->cluster_size); @@ -2165,7 +2165,7 @@ static void check_refcounts(BlockDriverState *bs) /* 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); @@ -2180,7 +2180,7 @@ static void check_refcounts(BlockDriverState *bs) /* refcount data */ inc_refcounts(bs, refcount_table, nb_clusters, - s->refcount_table_offset, + s->refcount_table_offset, s->refcount_table_size * sizeof(uint64_t)); for(i = 0; i < s->refcount_table_size; i++) { int64_t offset; diff --git a/block-raw.c b/block-raw.c index ab5bec27e..aaebbeb49 100644 --- a/block-raw.c +++ b/block-raw.c @@ -1,8 +1,8 @@ /* * 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 @@ -137,12 +137,12 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) #endif */ -static int raw_pread(BlockDriverState *bs, int64_t offset, +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; @@ -189,12 +189,12 @@ label__raw_read__success: return ret; } -static int raw_pwrite(BlockDriverState *bs, int64_t offset, +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; @@ -259,7 +259,7 @@ 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; @@ -401,7 +401,7 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, if (aio_read(&acb->aiocb) < 0) { qemu_aio_release(acb); return NULL; - } + } return &acb->common; } @@ -417,7 +417,7 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, if (aio_write(&acb->aiocb) < 0) { qemu_aio_release(acb); return NULL; - } + } return &acb->common; } @@ -522,7 +522,7 @@ static int raw_create(const char *filename, int64_t total_size, if (flags || backing_file) return -ENOTSUP; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); if (fd < 0) return -EIO; @@ -547,7 +547,7 @@ BlockDriver bdrv_raw = { raw_close, raw_create, raw_flush, - + .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, @@ -568,7 +568,7 @@ static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFI kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) { - kern_return_t kernResult; + kern_return_t kernResult; mach_port_t masterPort; CFMutableDictionaryRef classesToMatch; @@ -576,8 +576,8 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) if ( KERN_SUCCESS != kernResult ) { printf( "IOMasterPort returned %d\n", kernResult ); } - - classesToMatch = IOServiceMatching( kIOCDMediaClass ); + + classesToMatch = IOServiceMatching( kIOCDMediaClass ); if ( classesToMatch == NULL ) { printf( "IOServiceMatching returned a NULL dictionary.\n" ); } else { @@ -588,7 +588,7 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) { printf( "IOServiceGetMatchingServices returned %d\n", kernResult ); } - + return kernResult; } @@ -614,7 +614,7 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma } IOObjectRelease( nextMedia ); } - + return kernResult; } @@ -631,10 +631,10 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) 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 */ @@ -646,7 +646,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) } filename = bsdPath; } - + if ( mediaIterator ) IOObjectRelease( mediaIterator ); } @@ -704,7 +704,7 @@ static int fd_open(BlockDriverState *bs) if (s->type != FTYPE_FD) return 0; last_media_present = (s->fd >= 0); - if (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; @@ -713,7 +713,7 @@ static int fd_open(BlockDriverState *bs) #endif } if (s->fd < 0) { - if (s->fd_got_error && + 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"); @@ -883,7 +883,7 @@ BlockDriver bdrv_host_device = { raw_close, NULL, raw_flush, - + .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, @@ -979,7 +979,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) #else overlapped = FILE_FLAG_OVERLAPPED; #endif - s->hfile = CreateFile(filename, access_flags, + s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, create_flags, overlapped, NULL); if (s->hfile == INVALID_HANDLE_VALUE) { @@ -992,14 +992,14 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) return 0; } -static int raw_pread(BlockDriverState *bs, int64_t offset, +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; @@ -1014,14 +1014,14 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, return ret_count; } -static int raw_pwrite(BlockDriverState *bs, int64_t offset, +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; @@ -1171,7 +1171,7 @@ static int64_t raw_getlength(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; LARGE_INTEGER l; - ULARGE_INTEGER available, total, total_free; + ULARGE_INTEGER available, total, total_free; DISK_GEOMETRY dg; DWORD count; BOOL status; @@ -1209,7 +1209,7 @@ static int raw_create(const char *filename, int64_t total_size, if (flags || backing_file) return -ENOTSUP; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); if (fd < 0) return -EIO; @@ -1256,7 +1256,7 @@ BlockDriver bdrv_raw = { raw_close, raw_create, raw_flush, - + #if 0 .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, @@ -1335,7 +1335,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) } } s->type = find_device_type(bs, filename); - + if ((flags & BDRV_O_ACCESS) == O_RDWR) { access_flags = GENERIC_READ | GENERIC_WRITE; } else { @@ -1348,7 +1348,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) #else overlapped = FILE_FLAG_OVERLAPPED; #endif - s->hfile = CreateFile(filename, access_flags, + s->hfile = CreateFile(filename, access_flags, FILE_SHARE_READ, NULL, create_flags, overlapped, NULL); if (s->hfile == INVALID_HANDLE_VALUE) { @@ -1382,10 +1382,10 @@ static int raw_eject(BlockDriverState *bs, int eject_flag) if (s->type == FTYPE_FILE) return -ENOTSUP; if (eject_flag) { - DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, + DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &lpBytesReturned, NULL); } else { - DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, + DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, &lpBytesReturned, NULL); } } @@ -1406,7 +1406,7 @@ BlockDriver bdrv_host_device = { raw_close, NULL, raw_flush, - + #if 0 .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, diff --git a/block-vmdk.c b/block-vmdk.c index 35b6646d4..197fb5a62 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -1,9 +1,9 @@ /* * 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 @@ -110,16 +110,16 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) #define CHECK_CID 1 -#define SECTOR_SIZE 512 +#define SECTOR_SIZE 512 #define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each -#define HEADER_SIZE 512 // first sector of 512 bytes +#define HEADER_SIZE 512 // first sector of 512 bytes static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) { BDRVVmdkState *s = bs->opaque; char desc[DESC_SIZE]; uint32_t cid; - char *p_name, *cid_str; + char *p_name, *cid_str; size_t cid_str_size; /* the descriptor offset = 0x200 */ @@ -187,7 +187,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) { int snp_fd, p_fd; uint32_t p_cid; - char *p_name, *gd_buf, *rgd_buf; + char *p_name, *gd_buf, *rgd_buf; const char *real_filename, *temp_str; VMDK4Header header; uint32_t gde_entries, gd_size; @@ -271,7 +271,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE; if (!gt_size) goto fail; - gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde + gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde gd_size = gde_entries * sizeof(uint32_t); /* write RGD */ @@ -308,7 +308,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) fail_gd: qemu_free(gd_buf); - fail_rgd: + fail_rgd: qemu_free(rgd_buf); fail: close(p_fd); @@ -326,7 +326,7 @@ int parent_open = 0; static int vmdk_parent_open(BlockDriverState *bs, const char * filename) { BDRVVmdkState *s = bs->opaque; - char *p_name; + char *p_name; char desc[DESC_SIZE]; char parent_img_name[1024]; @@ -341,7 +341,7 @@ static int vmdk_parent_open(BlockDriverState *bs, const char * filename) p_name += sizeof("parentFileNameHint") + 1; if ((end_name = strchr(p_name,'\"')) == 0) return -1; - + strncpy(s->hd->backing_file, p_name, end_name - p_name); if (stat(s->hd->backing_file, &file_buf) != 0) { path_combine(parent_img_name, sizeof(parent_img_name), @@ -406,7 +406,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) 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_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; @@ -552,7 +552,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, } } l2_table = s->l2_cache + (min_index * s->l2_size); - if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != + if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != s->l2_size * sizeof(uint32_t)) return 0; @@ -597,7 +597,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, return cluster_offset; } -static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, +static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { BDRVVmdkState *s = bs->opaque; @@ -613,7 +613,7 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, return (cluster_offset != 0); } -static int vmdk_read(BlockDriverState *bs, int64_t sector_num, +static int vmdk_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVVmdkState *s = bs->opaque; @@ -648,7 +648,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, return 0; } -static int vmdk_write(BlockDriverState *bs, int64_t sector_num, +static int vmdk_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BDRVVmdkState *s = bs->opaque; @@ -761,8 +761,8 @@ static int vmdk_create(const char *filename, int64_t total_size, header.check_bytes[1] = 0x20; header.check_bytes[2] = 0xd; header.check_bytes[3] = 0xa; - - /* write all the data */ + + /* write all the data */ write(fd, &magic, sizeof(magic)); write(fd, &header, sizeof(header)); @@ -773,7 +773,7 @@ static int vmdk_create(const char *filename, int64_t total_size, 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; diff --git a/block-vpc.c b/block-vpc.c index 4d228c5b6..d9a4b9254 100644 --- a/block-vpc.c +++ b/block-vpc.c @@ -1,8 +1,8 @@ /* * 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 @@ -65,7 +65,7 @@ struct vpc_subheader { typedef struct BDRVVPCState { int fd; - + int pagetable_entries; uint32_t *pagetable; @@ -74,7 +74,7 @@ typedef struct BDRVVPCState { uint8_t *pageentry_u8; uint32_t *pageentry_u32; uint16_t *pageentry_u16; - + uint64_t last_bitmap; #endif } BDRVVPCState; @@ -97,7 +97,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags) return -1; bs->read_only = 1; // no write support yet - + s->fd = fd; if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE) @@ -153,13 +153,13 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) 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); @@ -172,7 +172,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) 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); @@ -184,7 +184,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) 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) @@ -196,7 +196,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) return 0; } -static int vpc_read(BlockDriverState *bs, int64_t sector_num, +static int vpc_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVVPCState *s = bs->opaque; diff --git a/block-vvfat.c b/block-vvfat.c index 48a52e311..3d3d6cfd0 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -1,9 +1,9 @@ /* 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 @@ -38,7 +38,7 @@ /* 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 + 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 */ @@ -153,7 +153,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun index_to<0 || index_to>=array->next || index_from<0 || index_from>=array->next) return -1; - + if(index_to==index_from) return 0; @@ -167,7 +167,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun memmove(to+is*count,to,from-to); else memmove(from,from+is*count,to-from); - + memcpy(to,buf,is*count); free(buf); @@ -319,10 +319,10 @@ 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; @@ -332,7 +332,7 @@ typedef struct BDRVVVFATState { 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 */ @@ -358,7 +358,7 @@ static void init_mbr(BDRVVVFATState* s) 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; @@ -478,7 +478,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry) for(i=0;i<11;i++) chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) +(unsigned char)entry->name[i]; - + return chksum; } @@ -554,7 +554,7 @@ static inline void init_fat(BDRVVVFATState* s) 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; @@ -579,10 +579,10 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, memcpy(entry->name,filename,strlen(filename)); return entry; } - + entry_long=create_long_filename(s,filename); - - i = strlen(filename); + + i = strlen(filename); for(j = i - 1; j>0 && filename[j]!='.';j--); if (j > 0) i = (j > 8 ? 8 : j); @@ -592,7 +592,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, 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]; @@ -618,7 +618,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, if(entry1==entry) /* no dupe found */ break; - /* use all 8 characters of name */ + /* use all 8 characters of name */ if(entry->name[7]==' ') { int j; for(j=6;j>0 && entry->name[j]==' ';j--) @@ -675,11 +675,11 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) 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 */ + /* actually read the directory, and allocate the mappings */ while((entry=readdir(dir))) { unsigned int length=strlen(dirname)+2+strlen(entry->d_name); char* buffer; @@ -690,7 +690,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) if(first_cluster == 0 && (is_dotdot || is_dot)) continue; - + buffer=(char*)malloc(length); assert(buffer); snprintf(buffer,length,"%s/%s",dirname,entry->d_name); @@ -765,7 +765,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) 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) @@ -774,7 +774,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index); set_begin_of_direntry(direntry, mapping->begin); - + return 0; } @@ -825,7 +825,7 @@ static int init_directories(BDRVVVFATState* s, */ 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)); @@ -857,7 +857,7 @@ static int init_directories(BDRVVVFATState* s, for (i = 0, cluster = 0; i < s->mapping.next; i++) { int j; - /* MS-DOS expects the FAT to be 0 for the root directory + /* 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); @@ -987,7 +987,7 @@ DLOG(if (stderr == NULL) { s->qcow_filename = NULL; s->fat2 = NULL; s->downcase_short_names = 1; - + if (!strstart(dirname, "fat:", NULL)) return -1; @@ -1076,7 +1076,7 @@ static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num assert(index1<=index2); DLOG(mapping=array_get(&(s->mapping),index1); assert(mapping->begin<=cluster_num); - assert(index2 >= s->mapping.next || + assert(index2 >= s->mapping.next || ((mapping = array_get(&(s->mapping),index2)) && mapping->end>cluster_num))); } @@ -1239,7 +1239,7 @@ static void print_mapping(const mapping_t* mapping) } #endif -static int vvfat_read(BlockDriverState *bs, int64_t sector_num, +static int vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BDRVVVFATState *s = bs->opaque; @@ -1674,7 +1674,7 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, } /* - * This function looks at the modified data (qcow). + * 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. */ @@ -1709,7 +1709,7 @@ static int check_directory_consistency(BDRVVVFATState *s, } else /* new directory */ schedule_mkdir(s, cluster_num, strdup(path)); - + lfn_init(&lfn); do { int i; @@ -2049,7 +2049,7 @@ static int commit_mappings(BDRVVVFATState* s, } next_mapping->dir_index = mapping->dir_index; - next_mapping->first_mapping_index = + next_mapping->first_mapping_index = mapping->first_mapping_index < 0 ? array_index(&(s->mapping), mapping) : mapping->first_mapping_index; @@ -2069,7 +2069,7 @@ static int commit_mappings(BDRVVVFATState* s, mapping = next_mapping; } - + cluster = c1; } @@ -2555,7 +2555,7 @@ static int do_commit(BDRVVVFATState* s) return ret; } - /* copy FAT (with bdrv_read) */ + /* copy FAT (with bdrv_read) */ memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat); /* recurse direntries from root (using bs->bdrv_read) */ @@ -2597,10 +2597,10 @@ DLOG(checkpoint()); return do_commit(s); } -static int vvfat_write(BlockDriverState *bs, int64_t sector_num, +static int vvfat_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - BDRVVVFATState *s = bs->opaque; + BDRVVVFATState *s = bs->opaque; int i, ret; DLOG(checkpoint()); @@ -2639,7 +2639,7 @@ DLOG(checkpoint()); begin = sector_num; if (end > sector_num + nb_sectors) end = sector_num + nb_sectors; - dir_index = mapping->dir_index + + dir_index = mapping->dir_index + 0x10 * (begin - mapping->begin * s->sectors_per_cluster); direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num)); @@ -2698,7 +2698,7 @@ static int vvfat_is_allocated(BlockDriverState *bs, *n = nb_sectors; else if (*n < 0) return 0; - return 1; + return 1; } static int write_target_commit(BlockDriverState *bs, int64_t sector_num, diff --git a/block.c b/block.c index 269a39746..c9f4bafda 100644 --- a/block.c +++ b/block.c @@ -1,8 +1,8 @@ /* * 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 @@ -48,7 +48,7 @@ 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, +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); @@ -167,7 +167,7 @@ BlockDriver *bdrv_find_format(const char *format_name) return NULL; } -int bdrv_create(BlockDriver *drv, +int bdrv_create(BlockDriver *drv, const char *filename, int64_t size_in_sectors, const char *backing_file, int flags) { @@ -180,7 +180,7 @@ int bdrv_create(BlockDriver *drv, void get_tmp_filename(char *filename, int size) { char temp_dir[MAX_PATH]; - + GetTempPath(MAX_PATH, temp_dir); GetTempFileName(temp_dir, "qem", 0, filename); } @@ -202,10 +202,10 @@ static int is_windows_drive_prefix(const char *filename) (filename[0] >= 'A' && filename[0] <= 'Z')) && filename[1] == ':'); } - + static int is_windows_drive(const char *filename) { - if (is_windows_drive_prefix(filename) && + if (is_windows_drive_prefix(filename) && filename[2] == '\0') return 1; if (strstart(filename, "\\\\.\\", NULL) || @@ -236,7 +236,7 @@ static BlockDriver *find_protocol(const char *filename) memcpy(protocol, filename, len); protocol[len] = '\0'; for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { - if (drv1->protocol_name && + if (drv1->protocol_name && !strcmp(drv1->protocol_name, protocol)) return drv1; } @@ -251,7 +251,7 @@ static BlockDriver *find_image_format(const char *filename) 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)) @@ -262,13 +262,13 @@ static BlockDriver *find_image_format(const char *filename) #else { struct stat st; - if (stat(filename, &st) >= 0 && + 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) @@ -324,7 +324,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, int ret, open_flags; char tmp_filename[PATH_MAX]; char backing_filename[PATH_MAX]; - + bs->read_only = 0; bs->is_temporary = 0; bs->encrypted = 0; @@ -332,7 +332,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, 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 */ @@ -347,10 +347,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, } 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, + if (bdrv_create(&bdrv_qcow2, tmp_filename, total_size, backing_filename, 0) < 0) { return -1; } @@ -494,7 +494,7 @@ int bdrv_commit(BlockDriverState *bs) } /* return < 0 if error. See bdrv_write() for the return codes */ -int bdrv_read(BlockDriverState *bs, int64_t sector_num, +int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { BlockDriver *drv = bs->drv; @@ -525,13 +525,13 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, } } -/* Return < 0 if error. Important errors are: +/* 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, +int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BlockDriver *drv = bs->drv; @@ -540,7 +540,7 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, if (bs->read_only) return -EACCES; if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); + memcpy(bs->boot_sector_data, buf, 512); } if (drv->bdrv_pwrite) { int ret, len; @@ -557,7 +557,7 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, } } -static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, +static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, uint8_t *buf, int count1) { uint8_t tmp_buf[SECTOR_SIZE]; @@ -601,7 +601,7 @@ static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, return count1; } -static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, +static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, const uint8_t *buf, int count1) { uint8_t tmp_buf[SECTOR_SIZE]; @@ -650,9 +650,9 @@ static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, } /** - * Read with byte offsets (needed only for file protocols) + * Read with byte offsets (needed only for file protocols) */ -int bdrv_pread(BlockDriverState *bs, int64_t offset, +int bdrv_pread(BlockDriverState *bs, int64_t offset, void *buf1, int count1) { BlockDriver *drv = bs->drv; @@ -664,10 +664,10 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, return drv->bdrv_pread(bs, offset, buf1, count1); } -/** - * Write with byte offsets (needed only for file protocols) +/** + * Write with byte offsets (needed only for file protocols) */ -int bdrv_pwrite(BlockDriverState *bs, int64_t offset, +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, const void *buf1, int count1) { BlockDriver *drv = bs->drv; @@ -729,7 +729,7 @@ void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) memset(bs->boot_sector_data + size, 0, 512 - size); } -void bdrv_set_geometry_hint(BlockDriverState *bs, +void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs) { bs->cyls = cyls; @@ -749,7 +749,7 @@ void bdrv_set_translation_hint(BlockDriverState *bs, int translation) bs->translation = translation; } -void bdrv_get_geometry_hint(BlockDriverState *bs, +void bdrv_get_geometry_hint(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs) { *pcyls = bs->cyls; @@ -778,7 +778,7 @@ int bdrv_is_read_only(BlockDriverState *bs) } /* XXX: no longer used */ -void bdrv_set_change_cb(BlockDriverState *bs, +void bdrv_set_change_cb(BlockDriverState *bs, void (*change_cb)(void *opaque), void *opaque) { bs->change_cb = change_cb; @@ -816,7 +816,7 @@ void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) } } -void bdrv_iterate_format(void (*it)(void *opaque, const char *name), +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque) { BlockDriver *drv; @@ -899,7 +899,7 @@ void bdrv_info(void) } } -void bdrv_get_backing_filename(BlockDriverState *bs, +void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size) { if (!bs->backing_hd) { @@ -909,7 +909,7 @@ void bdrv_get_backing_filename(BlockDriverState *bs, } } -int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, +int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { BlockDriver *drv = bs->drv; @@ -919,7 +919,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, 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; @@ -934,7 +934,7 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) /**************************************************************/ /* handling of snapshots */ -int bdrv_snapshot_create(BlockDriverState *bs, +int bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) { BlockDriver *drv = bs->drv; @@ -945,7 +945,7 @@ int bdrv_snapshot_create(BlockDriverState *bs, return drv->bdrv_snapshot_create(bs, sn_info); } -int bdrv_snapshot_goto(BlockDriverState *bs, +int bdrv_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) { BlockDriver *drv = bs->drv; @@ -966,7 +966,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) return drv->bdrv_snapshot_delete(bs, snapshot_id); } -int bdrv_snapshot_list(BlockDriverState *bs, +int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info) { BlockDriver *drv = bs->drv; @@ -991,12 +991,12 @@ char *get_human_readable_size(char *buf, int buf_size, int64_t size) base = 1024; for(i = 0; i < NB_SUFFIXES; i++) { if (size < (10 * base)) { - snprintf(buf, buf_size, "%0.1f%c", + 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", + snprintf(buf, buf_size, "%" PRId64 "%c", ((size + (base >> 1)) / base), suffixes[i]); break; @@ -1019,8 +1019,8 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) int64_t secs; if (!sn) { - snprintf(buf, buf_size, - "%-10s%-20s%7s%20s%15s", + snprintf(buf, buf_size, + "%-10s%-20s%7s%20s%15s", "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); } else { ti = sn->date_sec; @@ -1038,10 +1038,10 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) "%02d:%02d:%02d.%03d", (int)(secs / 3600), (int)((secs / 60) % 60), - (int)(secs % 60), + (int)(secs % 60), (int)((sn->vm_clock_nsec / 1000000) % 1000)); snprintf(buf, buf_size, - "%-10s%-20s%7s%20s%15s", + "%-10s%-20s%7s%20s%15s", sn->id_str, sn->name, get_human_readable_size(buf1, sizeof(buf1), sn->vm_state_size), date_buf, @@ -1062,7 +1062,7 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, 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); @@ -1085,7 +1085,7 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, if (bs->read_only) return NULL; if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); + memcpy(bs->boot_sector_data, buf, 512); } return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); @@ -1184,7 +1184,7 @@ static void bdrv_rw_em_cb(void *opaque, int ret) #define NOT_DONE 0x7fffffff -static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, +static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { int async_ret; @@ -1192,7 +1192,7 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, async_ret = NOT_DONE; qemu_aio_wait_start(); - acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, + acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, bdrv_rw_em_cb, &async_ret); if (acb == NULL) { qemu_aio_wait_end(); @@ -1213,7 +1213,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, async_ret = NOT_DONE; qemu_aio_wait_start(); - acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, + acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, bdrv_rw_em_cb, &async_ret); if (acb == NULL) { qemu_aio_wait_end(); @@ -1293,7 +1293,7 @@ int bdrv_is_inserted(BlockDriverState *bs) /** * Return TRUE if the media changed since the last call to this - * function. It is currently only used for floppy disks + * function. It is currently only used for floppy disks */ int bdrv_media_changed(BlockDriverState *bs) { diff --git a/block_int.h b/block_int.h index 25f6717b5..e8fff77a0 100644 --- a/block_int.h +++ b/block_int.h @@ -1,8 +1,8 @@ /* * 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 @@ -29,12 +29,12 @@ struct BlockDriver { 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, + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); - int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, + 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, + 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, @@ -52,21 +52,21 @@ struct BlockDriver { int aiocb_size; const char *protocol_name; - int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, + int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, uint8_t *buf, int count); - int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset, + 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, + int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); - int (*bdrv_snapshot_create)(BlockDriverState *bs, + int (*bdrv_snapshot_create)(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); - int (*bdrv_snapshot_goto)(BlockDriverState *bs, + 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, + int (*bdrv_snapshot_list)(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); @@ -75,7 +75,7 @@ struct BlockDriver { 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; }; @@ -107,7 +107,7 @@ struct BlockDriverState { /* 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; diff --git a/bswap.h b/bswap.h index 37fb04ed9..970c1bbe3 100644 --- a/bswap.h +++ b/bswap.h @@ -48,12 +48,12 @@ static inline uint16_t bswap16(uint16_t x) return bswap_16(x); } -static inline uint32_t bswap32(uint32_t x) +static inline uint32_t bswap32(uint32_t x) { return bswap_32(x); } -static inline uint64_t bswap64(uint64_t x) +static inline uint64_t bswap64(uint64_t x) { return bswap_64(x); } diff --git a/cocoa.m b/cocoa.m index 501fb705b..a46db984a 100644 --- a/cocoa.m +++ b/cocoa.m @@ -1,9 +1,9 @@ /* * 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 @@ -23,7 +23,7 @@ * THE SOFTWARE. */ /* - Todo : x miniaturize window + Todo : x miniaturize window x center the window - save window position - handle keyboard event @@ -84,7 +84,7 @@ static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) MacSetRectRgn (temp, x, y, x + w, y + h); MacUnionRgn (dirty, temp, dirty); - + /* Flush the dirty region */ QDFlushPortBuffer ( [ qd_view qdPort ], dirty ); DisposeRgn (dirty); @@ -102,9 +102,9 @@ static void cocoa_resize(DisplayState *ds, int w, int h) 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) { @@ -119,44 +119,44 @@ static void cocoa_resize(DisplayState *ds, int w, int h) 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 - + { + 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; @@ -310,38 +310,38 @@ int keymap[] = 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 + 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 */ }; @@ -366,10 +366,10 @@ static void cocoa_refresh(DisplayState *ds) NSDate *distantPast; NSEvent *event; NSAutoreleasePool *pool; - + pool = [ [ NSAutoreleasePool alloc ] init ]; distantPast = [ NSDate distantPast ]; - + vga_hw_update(); do { @@ -415,8 +415,8 @@ static void cocoa_refresh(DisplayState *ds) case NSKeyDown: { - int keycode = cocoa_keycode_to_qemu([event keyCode]); - + int keycode = cocoa_keycode_to_qemu([event keyCode]); + /* handle command Key Combos */ if ([event modifierFlags] & NSCommandKeyMask) { switch ([event keyCode]) { @@ -427,7 +427,7 @@ static void cocoa_refresh(DisplayState *ds) return; } } - + /* handle control + alt Key Combos */ if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { switch (keycode) { @@ -482,10 +482,10 @@ static void cocoa_refresh(DisplayState *ds) } } break; - + case NSKeyUp: { - int keycode = cocoa_keycode_to_qemu([event keyCode]); + int keycode = cocoa_keycode_to_qemu([event keyCode]); if (is_graphic_console()) { if (keycode & 0x80) kbd_put_keycode(0xe0); @@ -493,7 +493,7 @@ static void cocoa_refresh(DisplayState *ds) } } break; - + case NSMouseMoved: if (grab) { int dx = [event deltaX]; @@ -503,11 +503,11 @@ static void cocoa_refresh(DisplayState *ds) 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; @@ -519,7 +519,7 @@ static void cocoa_refresh(DisplayState *ds) [NSApp sendEvent: event]; } break; - + case NSLeftMouseDragged: if (grab) { int dx = [event deltaX]; @@ -534,7 +534,7 @@ static void cocoa_refresh(DisplayState *ds) kbd_mouse_event(dx, dy, dz, buttons); } break; - + case NSLeftMouseUp: if (grab) { kbd_mouse_event(0, 0, 0, 0); @@ -546,18 +546,18 @@ static void cocoa_refresh(DisplayState *ds) //[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]; @@ -568,7 +568,7 @@ static void cocoa_refresh(DisplayState *ds) kbd_mouse_event(dx, dy, dz, buttons); } break; - + case NSRightMouseUp: if (grab) { kbd_mouse_event(0, 0, 0, 0); @@ -576,7 +576,7 @@ static void cocoa_refresh(DisplayState *ds) [NSApp sendEvent: event]; } break; - + case NSOtherMouseDragged: if (grab) { int dx = [event deltaX]; @@ -587,7 +587,7 @@ static void cocoa_refresh(DisplayState *ds) kbd_mouse_event(dx, dy, dz, buttons); } break; - + case NSOtherMouseDown: if (grab) { int buttons = 0; @@ -597,7 +597,7 @@ static void cocoa_refresh(DisplayState *ds) [NSApp sendEvent:event]; } break; - + case NSOtherMouseUp: if (grab) { kbd_mouse_event(0, 0, 0, 0); @@ -605,14 +605,14 @@ static void cocoa_refresh(DisplayState *ds) [NSApp sendEvent: event]; } break; - + case NSScrollWheel: if (grab) { int dz = [event deltaY]; kbd_mouse_event(0, 0, -dz, 0); } break; - + default: [NSApp sendEvent:event]; } } @@ -625,7 +625,7 @@ static void cocoa_refresh(DisplayState *ds) ------------------------------------------------------ */ -static void cocoa_cleanup(void) +static void cocoa_cleanup(void) { } @@ -641,9 +641,9 @@ 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); } @@ -661,17 +661,17 @@ void cocoa_display_init(DisplayState *ds, int full_screen) ------------------------------------------------------ */ 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; } } @@ -680,32 +680,32 @@ static void QZ_SetPortAlphaOpaque () @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 + 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 ]; } @@ -742,13 +742,13 @@ static void QZ_SetPortAlphaOpaque () 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]; @@ -774,20 +774,20 @@ static void QZ_SetPortAlphaOpaque () { 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]; } } @@ -827,10 +827,10 @@ static void setApplicationMenu(void) 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:@""]; @@ -850,7 +850,7 @@ static void setApplicationMenu(void) 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]; @@ -872,17 +872,17 @@ static void setupWindowMenu(void) 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]; @@ -896,14 +896,14 @@ 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(); @@ -912,10 +912,10 @@ static void CustomApplicationMain(void) /* 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]; } diff --git a/configure b/configure index 7ee710a8b..49bf8b6fc 100755 --- a/configure +++ b/configure @@ -403,7 +403,7 @@ if test "$mingw32" = "yes" ; then oss="no" fi -# Check for gcc4, error if pre-gcc4 +# Check for gcc4, error if pre-gcc4 if test "$check_gcc" = "yes" ; then cat > $TMPC <> 16) & 0xff; g = (rgba >> 8) & 0xff; b = (rgba) & 0xff; - color = (rgb_to_index[r] * 6 * 6) + - (rgb_to_index[g] * 6) + + color = (rgb_to_index[r] * 6 * 6) + + (rgb_to_index[g] * 6) + (rgb_to_index[b]); break; #endif @@ -205,14 +205,14 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) return color; } -static void vga_fill_rect (DisplayState *ds, +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 + + d1 = ds->data + ds->linesize * posy + bpp * posx; for (y = 0; y < height; y++) { d = d1; @@ -250,9 +250,9 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, bpp = (ds->depth + 7) >> 3; wb = w * bpp; if (yd <= ys) { - s = ds->data + + s = ds->data + ds->linesize * ys + bpp * xs; - d = ds->data + + d = ds->data + ds->linesize * yd + bpp * xd; for (y = 0; y < h; y++) { memmove(d, s, wb); @@ -260,9 +260,9 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, s += ds->linesize; } } else { - s = ds->data + + s = ds->data + ds->linesize * (ys + h - 1) + bpp * xs; - d = ds->data + + d = ds->data + ds->linesize * (yd + h - 1) + bpp * xd; for (y = 0; y < h; y++) { memmove(d, s, wb); @@ -405,7 +405,7 @@ static void console_print_text_attributes(TextAttributes *t_attrib, char ch) } #endif -static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, +static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, TextAttributes *t_attrib) { uint8_t *d; @@ -428,7 +428,7 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, } bpp = (ds->depth + 7) >> 3; - d = ds->data + + d = ds->data + ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH; linesize = ds->linesize; font_ptr = vgafont16 + FONT_HEIGHT * ch; @@ -525,9 +525,9 @@ static void update_xy(TextConsole *s, int x, int y) y2 += s->total_height; if (y2 < s->height) { c = &s->cells[y1 * s->width + x]; - vga_putcharxy(s->ds, x, y2, c->ch, + vga_putcharxy(s->ds, x, y2, c->ch, &(c->t_attrib)); - dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, + dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, FONT_WIDTH, FONT_HEIGHT); } } @@ -556,7 +556,7 @@ static void console_show_cursor(TextConsole *s, int show) } else { vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib)); } - dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT, + dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT, FONT_WIDTH, FONT_HEIGHT); } } @@ -567,7 +567,7 @@ static void console_refresh(TextConsole *s) TextCell *c; int x, y, y1; - if (s != active_console) + if (s != active_console) return; vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, @@ -576,7 +576,7 @@ static void console_refresh(TextConsole *s) 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, + vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib)); c++; } @@ -591,7 +591,7 @@ static void console_scroll(int ydelta) { TextConsole *s; int i, y1; - + s = active_console; if (!s || (s->console_type == GRAPHIC_CONSOLE)) return; @@ -646,13 +646,13 @@ static void console_put_lf(TextConsole *s) c++; } if (s == active_console && s->y_displayed == s->y_base) { - vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, - s->width * FONT_WIDTH, + 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, + s->width * FONT_WIDTH, FONT_HEIGHT, color_table[0][s->t_attrib_default.bgcol]); - dpy_update(s->ds, 0, 0, + dpy_update(s->ds, 0, 0, s->width * FONT_WIDTH, s->height * FONT_HEIGHT); } } @@ -781,7 +781,7 @@ static void console_putchar(TextConsole *s, int ch) console_put_lf(s); break; case '\b': /* backspace */ - if (s->x > 0) + if (s->x > 0) s->x--; break; case '\t': /* tabspace */ @@ -832,7 +832,7 @@ static void console_putchar(TextConsole *s, int ch) 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] = s->esc_params[s->nb_esc_params] * 10 + ch - '0'; } } else { @@ -1047,7 +1047,7 @@ static void kbd_send_chars(void *opaque) TextConsole *s = opaque; int len; uint8_t buf[16]; - + len = qemu_chr_can_read(s->chr); if (len > s->out_fifo.count) len = s->out_fifo.count; @@ -1192,12 +1192,12 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p) 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, + color_table[j][i] = col_expand(s->ds, vga_get_color(s->ds, color_table_rgb[j][i])); } } diff --git a/cpu-all.h b/cpu-all.h index 54d5dc36a..5c3003088 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -1,6 +1,6 @@ /* * defines common to all virtual CPUs - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -24,16 +24,16 @@ #define WORDS_ALIGNED #endif -/* some important defines: - * +/* 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 */ @@ -147,7 +147,7 @@ typedef union { * type is: * (empty): integer access * f : float access - * + * * sign is: * (empty): for floats or 32 bit size * u : unsigned @@ -158,7 +158,7 @@ typedef union { * 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) @@ -621,7 +621,7 @@ static inline void stfq_be_p(void *ptr, float64 v) #define stfq_raw(p, v) stfq_p(saddr((p)), v) -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) /* if user mode, no other memory access functions */ #define ldub(p) ldub_raw(p) @@ -685,7 +685,7 @@ extern unsigned long qemu_host_page_mask; #define PAGE_VALID 0x0008 /* original state of the write flag (used when tracking self-modifying code */ -#define PAGE_WRITE_ORG 0x0010 +#define PAGE_WRITE_ORG 0x0010 void page_dump(FILE *f); int page_get_flags(target_ulong address); @@ -694,7 +694,7 @@ void page_unprotect_range(target_ulong data, target_ulong data_size); CPUState *cpu_copy(CPUState *env); -void cpu_dump_state(CPUState *env, FILE *f, +void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags); void cpu_dump_statistics (CPUState *env, FILE *f, @@ -732,7 +732,7 @@ void cpu_reset(CPUState *s); if no page found. */ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr); -#define CPU_LOG_TB_OUT_ASM (1 << 0) +#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) @@ -793,7 +793,7 @@ extern uint8_t *phys_ram_dirty; 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, +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); @@ -808,12 +808,12 @@ 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, +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, +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); @@ -829,9 +829,9 @@ 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, +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, +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write); #define VGA_DIRTY_FLAG 0x01 @@ -843,7 +843,7 @@ 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, +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; @@ -866,14 +866,14 @@ void dump_exec_info(FILE *f, #if defined(__powerpc__) -static inline uint32_t get_tbl(void) +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) +static inline uint32_t get_tbu(void) { uint32_t tbl; asm volatile("mftbu %0" : "=r" (tbl)); diff --git a/cpu-defs.h b/cpu-defs.h index ac96b0ab5..e474152d5 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -1,6 +1,6 @@ /* * common defines for all CPUs - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -29,7 +29,7 @@ #error TARGET_LONG_BITS must be defined before including this header #endif -#ifndef TARGET_PHYS_ADDR_BITS +#ifndef TARGET_PHYS_ADDR_BITS #if TARGET_LONG_BITS >= HOST_LONG_BITS #define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS #else @@ -97,17 +97,17 @@ typedef unsigned long ram_addr_t; #define CPU_TLB_SIZE (1 << CPU_TLB_BITS) typedef struct CPUTLBEntry { - /* bit 31 to TARGET_PAGE_BITS : virtual address + /* 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; + 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; + target_phys_addr_t addend; } CPUTLBEntry; /* Alpha has 4 different running levels */ diff --git a/cpu-exec.c b/cpu-exec.c index 4f1cee616..5326edf09 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -1,6 +1,6 @@ /* * i386 emulator main execution loop - * + * * Copyright (c) 2003-2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -55,7 +55,7 @@ void cpu_loop_exit(void) /* 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) +void cpu_resume_from_signal(CPUState *env1, void *puc) { #if !defined(CONFIG_SOFTMMU) struct ucontext *uc = puc; @@ -84,13 +84,13 @@ static TranslationBlock *tb_find_slow(target_ulong pc, 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; @@ -101,13 +101,13 @@ static TranslationBlock *tb_find_slow(target_ulong pc, tb = *ptb1; if (!tb) goto not_found; - if (tb->pc == pc && + if (tb->pc == pc && tb->page_addr[0] == phys_page1 && - tb->cs_base == cs_base && + 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) + + 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) @@ -135,7 +135,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc, 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; @@ -143,7 +143,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc, 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; @@ -252,7 +252,7 @@ int cpu_exec(CPUState *env1) if (cpu_halted(env1) == EXCP_HALTED) return EXCP_HALTED; - cpu_single_env = env1; + cpu_single_env = env1; /* first we save global registers */ #define SAVE_HOST_REGS 1 @@ -304,9 +304,9 @@ int cpu_exec(CPUState *env1) 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, + do_interrupt_user(env->exception_index, + env->exception_is_int, + env->error_code, env->exception_next_eip); #endif ret = env->exception_index; @@ -316,9 +316,9 @@ int cpu_exec(CPUState *env1) /* 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, + do_interrupt(env->exception_index, + env->exception_is_int, + env->error_code, env->exception_next_eip, 0); /* successfully delivered */ env->old_exception = -1; @@ -339,7 +339,7 @@ int cpu_exec(CPUState *env1) #endif } env->exception_index = -1; - } + } #ifdef USE_KQEMU if (kqemu_is_ok(env) && env->interrupt_request == 0) { int ret; @@ -369,9 +369,9 @@ int cpu_exec(CPUState *env1) T0 = 0; /* force lookup of first TB */ for(;;) { #if defined(__sparc__) && !defined(HOST_SOLARIS) - /* g1 can be modified by some libc? functions */ + /* g1 can be modified by some libc? functions */ tmp_T0 = T0; -#endif +#endif interrupt_request = env->interrupt_request; if (__builtin_expect(interrupt_request, 0)) { if (interrupt_request & CPU_INTERRUPT_DEBUG) { @@ -399,7 +399,7 @@ int cpu_exec(CPUState *env1) T0 = 0; #endif } else if ((interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK) && + (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; env->interrupt_request &= ~CPU_INTERRUPT_HARD; @@ -551,7 +551,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_ALPHA) cpu_dump_state(env, logfile, fprintf, 0); #else -#error unsupported target CPU +#error unsupported target CPU #endif } #endif @@ -565,7 +565,7 @@ int cpu_exec(CPUState *env1) #endif #if defined(__sparc__) && !defined(HOST_SOLARIS) T0 = tmp_T0; -#endif +#endif /* see if we can patch the calling TB. When the TB spans two pages, we cannot safely do a direct jump. */ @@ -576,7 +576,7 @@ int cpu_exec(CPUState *env1) #endif tb->page_addr[1] == -1 #if defined(TARGET_I386) && defined(USE_CODE_COPY) - && (tb->cflags & CF_CODE_COPY) == + && (tb->cflags & CF_CODE_COPY) == (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY) #endif ) { @@ -584,7 +584,7 @@ int cpu_exec(CPUState *env1) tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb); #if defined(USE_CODE_COPY) /* propagates the FP use info */ - ((TranslationBlock *)(T0 & ~3))->cflags |= + ((TranslationBlock *)(T0 & ~3))->cflags |= (tb->cflags & CF_FP_USED); #endif spin_unlock(&tb_lock); @@ -598,7 +598,7 @@ int cpu_exec(CPUState *env1) __asm__ __volatile__("call %0\n\t" "mov %%o7,%%i0" : /* no outputs */ - : "r" (gen_func) + : "r" (gen_func) : "i0", "i1", "i2", "i3", "i4", "i5", "o0", "o1", "o2", "o3", "o4", "o5", "l0", "l1", "l2", "l3", "l4", "l5", @@ -755,7 +755,7 @@ int cpu_exec(CPUState *env1) #include "hostregs_helper.h" /* fail safe : never use cpu_single_env outside cpu_exec() */ - cpu_single_env = NULL; + cpu_single_env = NULL; return ret; } @@ -782,7 +782,7 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) env = s; if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg_reg, selector, + cpu_x86_load_seg_cache(env, seg_reg, selector, (selector << 4), 0xffff, 0); } else { load_seg(seg_reg, selector); @@ -796,7 +796,7 @@ void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) saved_env = env; env = s; - + helper_fsave((target_ulong)ptr, data32); env = saved_env; @@ -808,7 +808,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) saved_env = env; env = s; - + helper_frstor((target_ulong)ptr, data32); env = saved_env; @@ -825,7 +825,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) 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, + int is_write, sigset_t *old_set, void *puc) { TranslationBlock *tb; @@ -834,7 +834,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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", + 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 */ @@ -843,7 +843,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_x86_handle_mmu_fault(env, address, is_write, + 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 */ @@ -858,7 +858,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } if (ret == 1) { #if 0 - printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", + 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 @@ -885,7 +885,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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", + 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 */ @@ -921,7 +921,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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", + 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 */ @@ -953,11 +953,11 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { 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", + 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 */ @@ -981,7 +981,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } if (ret == 1) { #if 0 - printf("PF exception: NIP=0x%08x error=0x%x %p\n", + 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 @@ -1007,7 +1007,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, 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", + 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 */ @@ -1042,11 +1042,11 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { 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", + 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 */ @@ -1070,7 +1070,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } if (ret == 1) { #if 0 - printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n", + printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n", env->PC, env->error_code, tb); #endif /* we restore the process signal mask as the sigreturn should @@ -1092,11 +1092,11 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { 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", + 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 */ @@ -1119,7 +1119,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, cpu_restore_state(tb, env, pc, puc); } #if 0 - printf("PF exception: NIP=0x%08x error=0x%x %p\n", + 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 @@ -1137,11 +1137,11 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { 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", + 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 */ @@ -1164,7 +1164,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, cpu_restore_state(tb, env, pc, puc); } #if 0 - printf("PF exception: NIP=0x%08x error=0x%x %p\n", + 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 @@ -1193,7 +1193,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, #endif #if defined(USE_CODE_COPY) -static void cpu_send_trap(unsigned long pc, int trap, +static void cpu_send_trap(unsigned long pc, int trap, struct ucontext *uc) { TranslationBlock *tb; @@ -1212,7 +1212,7 @@ static void cpu_send_trap(unsigned long pc, int trap, } #endif -int cpu_signal_handler(int host_signum, void *pinfo, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; @@ -1235,8 +1235,8 @@ int cpu_signal_handler(int host_signum, void *pinfo, return 1; } else #endif - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - trapno == 0xe ? + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + trapno == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0, &uc->uc_sigmask, puc); } @@ -1251,8 +1251,8 @@ int cpu_signal_handler(int host_signum, void *pinfo, 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 ? + 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); } @@ -1308,7 +1308,7 @@ typedef struct ucontext SIGCONTEXT; # define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */ #endif /* __APPLE__ */ -int cpu_signal_handler(int host_signum, void *pinfo, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; @@ -1326,13 +1326,13 @@ int cpu_signal_handler(int host_signum, void *pinfo, if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) is_write = 1; #endif - return handle_cpu_signal(pc, (unsigned long)info->si_addr, + 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, void *pinfo, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; @@ -1357,12 +1357,12 @@ int cpu_signal_handler(int host_signum, void *pinfo, is_write = 1; } - return handle_cpu_signal(pc, (unsigned long)info->si_addr, + 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, void *pinfo, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; @@ -1371,7 +1371,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, 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 */ @@ -1390,42 +1390,42 @@ int cpu_signal_handler(int host_signum, void *pinfo, break; } } - return handle_cpu_signal(pc, (unsigned long)info->si_addr, + return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, sigmask, NULL); } #elif defined(__arm__) -int cpu_signal_handler(int host_signum, void *pinfo, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; 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, + 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, void *pinfo, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; 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, + return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, &uc->uc_sigmask, puc); } @@ -1466,34 +1466,34 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc) #elif defined(__s390__) -int cpu_signal_handler(int host_signum, void *pinfo, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; 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, + return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, &uc->uc_sigmask, puc); } #elif defined(__mips__) -int cpu_signal_handler(int host_signum, void *pinfo, +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; struct ucontext *uc = puc; greg_t pc = uc->uc_mcontext.pc; int is_write; - + /* XXX: compute is_write */ is_write = 0; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, + return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, &uc->uc_sigmask, puc); } diff --git a/cutils.c b/cutils.c index 352c47e21..074b5acd4 100644 --- a/cutils.c +++ b/cutils.c @@ -1,6 +1,6 @@ /* * 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 @@ -45,7 +45,7 @@ char *pstrcat(char *buf, int buf_size, const char *s) { int len; len = strlen(buf); - if (len < buf_size) + if (len < buf_size) pstrcpy(buf + len, buf_size - len, s); return buf; } diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c index ab3a7c15d..1d65a369d 100644 --- a/darwin-user/syscall.c +++ b/darwin-user/syscall.c @@ -1336,7 +1336,7 @@ static inline long bswap_syctl(int * mib, int count, void *buf, int size) if(!(sysctl = sysctl->childs)) break; } - + if(ret->childs) qerror("we shouldn't have a directory element\n"); @@ -1375,7 +1375,7 @@ long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, vo //bswap_syctl(name, namelen, newp, newlen); tswap32s((uint32_t*)oldlenp); } - + if(name) /* Sometimes sysctl is called with no arg1, ignore */ ret = get_errno(sysctl(name, namelen, oldp, oldlenp, newp, newlen)); diff --git a/dis-asm.h b/dis-asm.h index 8fb5f6dbb..1659f2f95 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -44,7 +44,7 @@ enum bfd_flavour { enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; -enum bfd_architecture +enum bfd_architecture { bfd_arch_unknown, /* File arch not known */ bfd_arch_obscure, /* Arch known, not one of these */ @@ -67,14 +67,14 @@ enum bfd_architecture #define bfd_mach_mcf5249 16 #define bfd_mach_mcf547x 17 #define bfd_mach_mcf548x 18 - bfd_arch_vax, /* DEC Vax */ + bfd_arch_vax, /* DEC Vax */ bfd_arch_i960, /* Intel 960 */ /* The order of the following is important. - lower number indicates a machine type that + 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 + incompatible with all other machines except "core". */ #define bfd_mach_i960_core 1 @@ -228,7 +228,7 @@ enum dis_insn_type { dis_dref2 /* Two data references in instruction */ }; -/* This struct is passed into the instruction decoding routine, +/* 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 diff --git a/disas.c b/disas.c index 1bf5bc8f3..5048150b1 100644 --- a/disas.c +++ b/disas.c @@ -137,7 +137,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info) /* Disassemble this for me please... (debugging). 'flags' has the following values: i386 - nonzero means 16 bit code - arm - nonzero means thumb code + arm - nonzero means thumb code ppc - nonzero means little endian other targets - unused */ @@ -162,7 +162,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #if defined(TARGET_I386) if (flags == 2) disasm_info.mach = bfd_mach_x86_64; - else if (flags == 1) + else if (flags == 1) disasm_info.mach = bfd_mach_i386_i8086; else disasm_info.mach = bfd_mach_i386_i386; @@ -176,7 +176,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) print_insn = print_insn_sparc; #ifdef TARGET_SPARC64 disasm_info.mach = bfd_mach_sparc_v9b; -#endif +#endif #elif defined(TARGET_PPC) if (flags) disasm_info.endian = BFD_ENDIAN_LITTLE; @@ -261,7 +261,7 @@ void disas(FILE *out, void *code, unsigned long size) #if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) disasm_info.mach = bfd_mach_sparc_v9b; #endif -#elif defined(__arm__) +#elif defined(__arm__) print_insn = print_insn_arm; #elif defined(__MIPSEB__) print_insn = print_insn_big_mips; @@ -298,7 +298,7 @@ const char *lookup_symbol(target_ulong orig_addr) 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++) { @@ -377,7 +377,7 @@ void monitor_disas(CPUState *env, #if defined(TARGET_I386) if (flags == 2) disasm_info.mach = bfd_mach_x86_64; - else if (flags == 1) + else if (flags == 1) disasm_info.mach = bfd_mach_i386_i8086; else disasm_info.mach = bfd_mach_i386_i386; diff --git a/dyngen-exec.h b/dyngen-exec.h index 75d27ce16..37c593e29 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -209,7 +209,7 @@ extern int printf(const char *, ...); /* the symbols are considered non exported so a br immediate is generated */ #define __hidden __attribute__((visibility("hidden"))) #else -#define __hidden +#define __hidden #endif #if defined(__alpha__) diff --git a/dyngen.c b/dyngen.c index a07884ae6..a8bc201f5 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1,6 +1,6 @@ /* * Generic Dynamic compiler generator - * + * * Copyright (c) 2003 Fabrice Bellard * * The COFF object format support was extracted from Kazu's QEMU port @@ -204,11 +204,11 @@ typedef uint32_t host_ulong; struct nlist_extended { union { - char *n_name; - long n_strx; + char *n_name; + long n_strx; } n_un; - unsigned char n_type; - unsigned char n_sect; + unsigned char n_type; + unsigned char n_sect; short st_desc; unsigned long st_value; unsigned long st_size; @@ -372,10 +372,10 @@ int elf_must_swap(struct elfhdr *h) } swaptest; swaptest.i = 1; - return (h->e_ident[EI_DATA] == ELFDATA2MSB) != + 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 */ @@ -428,7 +428,7 @@ void elf_swap_rel(ELF_RELOC *rel) #endif } -struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, +struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, const char *name) { int i; @@ -453,7 +453,7 @@ int find_reloc(int sh_index) for(i = 0; i < ehdr.e_shnum; i++) { sec = &shdr[i]; - if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) + if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) return i; } return 0; @@ -483,11 +483,11 @@ int load_object(const char *filename) ElfW(Sym) *sym; char *shstr; ELF_RELOC *rel; - + fd = open(filename, O_RDONLY); - if (fd < 0) + 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"); @@ -524,7 +524,7 @@ int load_object(const char *filename) /* 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) @@ -569,7 +569,7 @@ int load_object(const char *filename) 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++) { @@ -609,7 +609,7 @@ 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++) { @@ -643,7 +643,7 @@ char *name_for_dotdata(struct coff_rel *rel) 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; } @@ -701,15 +701,15 @@ int load_object(const char *filename) uint32_t *n_strtab; EXE_SYM *sym; EXE_RELOC *rel; - - fd = open(filename, O_RDONLY + + fd = open(filename, O_RDONLY #ifdef _WIN32 | O_BINARY #endif ); - if (fd < 0) + 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"); @@ -722,11 +722,11 @@ int load_object(const char *filename) /* 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]; @@ -747,7 +747,7 @@ int load_object(const char *filename) 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++) @@ -757,8 +757,8 @@ int load_object(const char *filename) 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); - + 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++) { @@ -805,12 +805,12 @@ int load_object(const char *filename) } 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); @@ -818,7 +818,7 @@ int load_object(const char *filename) /* set coff relocation */ relocs = malloc(sizeof(struct coff_rel) * nb_relocs); - for (i = 0, ext_rel = coff_relocs, rel = relocs; i < 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; @@ -847,7 +847,7 @@ uint8_t **sdata; /* relocs */ struct relocation_info *relocs; - + /* symbols */ EXE_SYM *symtab; struct nlist *symtab_std; @@ -867,10 +867,10 @@ static inline char *find_str_by_index(int index) 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]=='_') @@ -880,7 +880,7 @@ static char *get_sym_name(EXE_SYM *sym) } /* find a section index given its segname, sectname */ -static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname, +static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname, const char *sectname) { int i; @@ -896,7 +896,7 @@ static int find_mach_sec_index(struct section *section_hdr, int shnum, const cha } /* find a section header given its segname, sectname */ -struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname, +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); @@ -909,7 +909,7 @@ struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const 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) @@ -926,7 +926,7 @@ static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned 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) && @@ -945,35 +945,35 @@ static const char * find_sym_with_value_and_sec_number( int value, int sectnum, } } -/* - * Find symbol name given a (virtual) address, and a section which is of type +/* + * 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; @@ -998,24 +998,24 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide) 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 ) + 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; @@ -1041,14 +1041,14 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide) 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; } @@ -1080,11 +1080,11 @@ int load_object(const char *filename) unsigned int i, j; EXE_SYM *sym; struct nlist *syment; - + fd = open(filename, O_RDONLY); - if (fd < 0) + 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"); @@ -1093,13 +1093,13 @@ int load_object(const char *filename) 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); insects); 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"); @@ -1170,20 +1170,20 @@ int load_object(const char *filename) 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)) @@ -1201,7 +1201,7 @@ int load_object(const char *filename) 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; @@ -1286,9 +1286,9 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, 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; @@ -1331,25 +1331,25 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, if (spare > max_pool - offset) spare = max_pool - offset; if ((offset & 3) !=0) - error("%s:%04x: pc offset must be 32 bit aligned", + 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) || + if (pc_offset <= (p - p_start) || pc_offset >= (p_end - p_start)) - error("%s:%04x: pc offset must point inside the function code", + 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", + 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", + 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"); @@ -1432,7 +1432,7 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, #define MAX_ARGS 3 /* generate op code */ -void gen_code(const char *name, host_ulong offset, host_ulong size, +void gen_code(const char *name, host_ulong offset, host_ulong size, FILE *outfile, int gen_switch) { int copy_size = 0; @@ -1478,7 +1478,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } copy_size = len; } -#endif +#endif #elif defined(HOST_PPC) { uint8_t *p; @@ -1510,7 +1510,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #endif if (get32((uint32_t *)p) != 0x6bfa8001) error("ret expected at the end of %s", name); - copy_size = p - p_start; + copy_size = p - p_start; } #elif defined(HOST_IA64) { @@ -1611,14 +1611,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } 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) @@ -1639,7 +1639,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, p_start -= 4; start_offset -= 4; } - copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, + copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, relocs, nb_relocs); } #elif defined(HOST_M68K) @@ -1650,7 +1650,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, error("empty code for %s", name); // remove NOP's, probably added for alignment while ((get16((uint16_t *)p) == 0x4e71) && - (p>p_start)) + (p>p_start)) p -= 2; if (get16((uint16_t *)p) != 0x4e75) error("rts expected at the end of %s", name); @@ -1700,7 +1700,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } - + nb_args = 0; while (nb_args < MAX_ARGS && args_present[nb_args]) nb_args++; @@ -1737,7 +1737,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, sym_name = get_rel_sym_name(rel); if(!sym_name) continue; - if (*sym_name && + if (*sym_name && !strstart(sym_name, "__op_param", NULL) && !strstart(sym_name, "__op_jmp", NULL) && !strstart(sym_name, "__op_gen_label", NULL)) { @@ -1784,7 +1784,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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 @@ -1816,7 +1816,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* try to find a matching relocation */ reloc_shndx = find_reloc(sym->st_shndx); if (reloc_shndx) { - nb_relocs1 = shdr[reloc_shndx].sh_size / + 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++) { @@ -1828,7 +1828,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } -#endif +#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)); @@ -1874,11 +1874,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, type = ELF32_R_TYPE(rel->r_info); switch(type) { case R_386_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, addend); break; case R_386_PC32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", reloc_offset, relname, reloc_offset, addend); break; default: @@ -1901,11 +1901,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, type = rel->r_type; switch(type) { case DIR32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, addend); break; case DISP32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", reloc_offset, relname, reloc_offset, addend); break; default: @@ -1933,15 +1933,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", reloc_offset, relname, addend); break; case R_X86_64_32S: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", reloc_offset, relname, addend); break; case R_X86_64_PC32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", reloc_offset, relname, reloc_offset, addend); break; default: @@ -1973,30 +1973,30 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, n, reloc_offset); continue; } - + get_reloc_expr(relname, sizeof(relname), 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", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, addend); break; case R_PPC_ADDR16_LO: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", reloc_offset, relname, addend); break; case R_PPC_ADDR16_HI: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", reloc_offset, relname, addend); break; case R_PPC_ADDR16_HA: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", reloc_offset, relname, 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", + 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, relname, reloc_offset, addend); break; default: @@ -2036,7 +2036,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, slide = offset - start_offset; - if (!(offset >= start_offset && offset < start_offset + size)) + if (!(offset >= start_offset && offset < start_offset + size)) continue; /* not in our range */ sym_name = get_reloc_name(rel, &sslide); @@ -2058,7 +2058,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; /* dunno how to handle without final_sym_name */ } - get_reloc_expr(final_sym_name, sizeof(final_sym_name), + get_reloc_expr(final_sym_name, sizeof(final_sym_name), sym_name); switch(type) { case PPC_RELOC_BR24: @@ -2074,15 +2074,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } break; case PPC_RELOC_HI16: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n", + 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", + 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", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n", slide, final_sym_name, sslide); break; default: @@ -2109,15 +2109,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, reloc_offset = rel->r_offset - start_offset; switch(type) { case R_390_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, addend); break; case R_390_16: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, addend); break; case R_390_8: - fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", + fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, addend); break; default: @@ -2273,7 +2273,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, reloc_offset = rel->r_offset - start_offset; switch(type) { case R_SPARC_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, addend); break; case R_SPARC_HI22: @@ -2470,13 +2470,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, reloc_offset = rel->r_offset - start_offset; switch(type) { case R_ARM_ABS32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, 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", + fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", reloc_offset, addend, relname); break; default: @@ -2504,12 +2504,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n", reloc_offset, relname, 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", + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n", reloc_offset, relname, reloc_offset, /*sym->st_value+*/ addend); break; default: @@ -2652,7 +2652,7 @@ int gen_file(FILE *outfile, int out_type) gen_code(name, sym->st_value, sym->st_size, outfile, 0); } } - + } else { /* generate big code generation switch */ @@ -2695,7 +2695,7 @@ fprintf(outfile, 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. ] @@ -2782,7 +2782,7 @@ fprintf(outfile, " opc_ptr = opc_buf;\n" " opparam_ptr = opparam_buf;\n"); - /* Generate prologue, if needed. */ + /* Generate prologue, if needed. */ fprintf(outfile, " for(;;) {\n"); @@ -2808,7 +2808,7 @@ fprintf(outfile, name = get_sym_name(sym); if (strstart(name, OP_PREFIX, NULL)) { #if 0 - printf("%4d: %s pos=0x%08x len=%d\n", + 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) @@ -2850,7 +2850,7 @@ fprintf(outfile, "plt_target, plt_offset);\n }\n"); #endif -/* generate some code patching */ +/* generate some code patching */ #ifdef HOST_ARM fprintf(outfile, "if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n" diff --git a/dyngen.h b/dyngen.h index 86dd3d619..7ac17baf3 100644 --- a/dyngen.h +++ b/dyngen.h @@ -1,6 +1,6 @@ /* * dyngen helpers - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -51,7 +51,7 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) 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"); } @@ -148,8 +148,8 @@ static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val) } 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, + LDREntry *ldr_start, LDREntry *ldr_end, + uint32_t *data_start, uint32_t *data_end, int gen_jmp) { LDREntry *le; @@ -158,7 +158,7 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, uint8_t *data_ptr; uint32_t insn; uint32_t mask; - + data_size = (data_end - data_start) << 2; if (gen_jmp) { @@ -169,17 +169,17 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, 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 - + 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"); diff --git a/elf.h b/elf.h index e6ccfebed..0c03f032a 100644 --- a/elf.h +++ b/elf.h @@ -1045,7 +1045,7 @@ typedef struct elf64_phdr { #define SHN_COMMON 0xfff2 #define SHN_HIRESERVE 0xffff #define SHN_MIPS_ACCOMON 0xff00 - + typedef struct elf32_shdr { Elf32_Word sh_name; Elf32_Word sh_type; diff --git a/elf_ops.h b/elf_ops.h index 3fdde8128..96cd8fdbf 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -49,7 +49,7 @@ static void glue(bswap_sym, SZ)(struct elf_sym *sym) bswap16s(&sym->st_shndx); } -static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, +static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, int n, int type) { int i; @@ -71,17 +71,17 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) int nsyms, i; char *str = NULL; - shdr_table = load_at(fd, ehdr->e_shoff, + shdr_table = load_at(fd, ehdr->e_shoff, sizeof(struct elf_shdr) * ehdr->e_shnum); if (!shdr_table) return -1; - + if (must_swab) { for (i = 0; i < ehdr->e_shnum; i++) { glue(bswap_shdr, SZ)(shdr_table + i); } } - + symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); if (!symtab) goto fail; @@ -176,7 +176,7 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, glue(bswap_phdr, SZ)(ph); } } - + total_size = 0; for(i = 0; i < ehdr.e_phnum; i++) { ph = &phdr[i]; diff --git a/exec-all.h b/exec-all.h index 31914ee2f..ade888ae3 100644 --- a/exec-all.h +++ b/exec-all.h @@ -1,6 +1,6 @@ /* * internal execution defines for qemu - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -68,7 +68,7 @@ typedef void (GenOpFunc)(void); typedef void (GenOpFunc1)(long); typedef void (GenOpFunc2)(long, long); typedef void (GenOpFunc3)(long, long, long); - + #if defined(TARGET_I386) void optimize_flags_init(void); @@ -86,27 +86,27 @@ int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, int max_code_size, int *gen_code_size_ptr); -int cpu_restore_state(struct TranslationBlock *tb, +int cpu_restore_state(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb, int max_code_size, int *gen_code_size_ptr); -int cpu_restore_state_copy(struct TranslationBlock *tb, +int cpu_restore_state_copy(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); void cpu_resume_from_signal(CPUState *env1, void *puc); void cpu_exec_init(CPUState *env); int page_unprotect(target_ulong address, unsigned long pc, void *puc); -void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, +void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, int is_cpu_write_access); void tb_invalidate_page_range(target_ulong start, target_ulong end); void tlb_flush_page(CPUState *env, target_ulong addr); void tlb_flush(CPUState *env, int flush_global); -int tlb_set_page_exec(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, int is_user, int is_softmmu); -static inline int tlb_set_page(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, +static inline int tlb_set_page(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, int is_user, int is_softmmu) { if (prot & PAGE_READ) @@ -156,7 +156,7 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr, #define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE) -#if defined(__powerpc__) +#if defined(__powerpc__) #define USE_DIRECT_JUMP #endif #if defined(__i386__) && !defined(_WIN32) @@ -177,11 +177,11 @@ typedef struct TranslationBlock { uint8_t *tc_ptr; /* pointer to the translated code */ /* next matching tb for physical address. */ - struct TranslationBlock *phys_hash_next; + struct TranslationBlock *phys_hash_next; /* first and second physical page containing code. The lower bit of the pointer tells the index in page_next[] */ - struct TranslationBlock *page_next[2]; - target_ulong page_addr[2]; + struct TranslationBlock *page_next[2]; + target_ulong page_addr[2]; /* the following data are used to directly call another TB from the code of this one. */ @@ -195,7 +195,7 @@ typedef struct TranslationBlock { the two least significant bits of the pointers to tell what is the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 = jmp_first */ - struct TranslationBlock *jmp_next[2]; + struct TranslationBlock *jmp_next[2]; struct TranslationBlock *jmp_first; } TranslationBlock; @@ -221,7 +221,7 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc) TranslationBlock *tb_alloc(target_ulong pc); void tb_flush(CPUState *env); -void tb_link_phys(TranslationBlock *tb, +void tb_link_phys(TranslationBlock *tb, target_ulong phys_pc, target_ulong phys_page2); extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; @@ -257,7 +257,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr } #endif -static inline void tb_set_jmp_target(TranslationBlock *tb, +static inline void tb_set_jmp_target(TranslationBlock *tb, int n, unsigned long addr) { unsigned long offset; @@ -272,7 +272,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, #else /* set the jump target */ -static inline void tb_set_jmp_target(TranslationBlock *tb, +static inline void tb_set_jmp_target(TranslationBlock *tb, int n, unsigned long addr) { tb->tb_next[n] = addr; @@ -280,14 +280,14 @@ static inline void tb_set_jmp_target(TranslationBlock *tb, #endif -static inline void tb_add_jump(TranslationBlock *tb, int n, +static inline void tb_add_jump(TranslationBlock *tb, int n, TranslationBlock *tb_next) { /* NOTE: this test is only needed for thread safety */ if (!tb->jmp_next[n]) { /* patch the native jump address */ tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); - + /* add in TB jmp circular list */ tb->jmp_next[n] = tb_next->jmp_first; tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); @@ -398,7 +398,7 @@ static inline int testandset (int *p) static inline int testandset (int *p) { long int readval = 0; - + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" : "+m" (*p), "+a" (readval) : "r" (1) @@ -409,7 +409,7 @@ static inline int testandset (int *p) static inline int testandset (int *p) { long int readval = 0; - + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" : "+m" (*p), "+a" (readval) : "r" (1) @@ -424,7 +424,7 @@ static inline int testandset (int *p) __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" " jl 0b" : "=&d" (ret) - : "r" (1), "a" (p), "0" (*p) + : "r" (1), "a" (p), "0" (*p) : "cc", "memory" ); return ret; } @@ -464,7 +464,7 @@ static inline int testandset (int *spinlock) __asm__ __volatile__("swp %0, %1, [%2]" : "=r"(ret) : "0"(1), "r"(spinlock)); - + return ret; } #elif defined(__mc68000) @@ -549,7 +549,7 @@ extern int tb_invalidated_flag; #if !defined(CONFIG_USER_ONLY) -void tlb_fill(target_ulong addr, int is_write, int is_user, +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr); #define ACCESS_TYPE 3 @@ -607,7 +607,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) #else #error unimplemented CPU #endif - if (__builtin_expect(env->tlb_table[is_user][index].addr_code != + if (__builtin_expect(env->tlb_table[is_user][index].addr_code != (addr & TARGET_PAGE_MASK), 0)) { ldub_code(addr); } @@ -638,11 +638,11 @@ void kqemu_record_dump(void); static inline int kqemu_is_ok(CPUState *env) { return(env->kqemu_enabled && - (env->cr[0] & CR0_PE_MASK) && + (env->cr[0] & CR0_PE_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK) && (env->eflags & IF_MASK) && !(env->eflags & VM_MASK) && - (env->kqemu_enabled == 2 || + (env->kqemu_enabled == 2 || ((env->hflags & HF_CPL_MASK) == 3 && (env->eflags & IOPL_MASK) != IOPL_MASK))); } diff --git a/exec.c b/exec.c index 4ccee2246..e7ce28d4b 100644 --- a/exec.c +++ b/exec.c @@ -1,6 +1,6 @@ /* * virtual page mapping and translated block handling - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -44,8 +44,8 @@ //#define DEBUG_UNASSIGNED /* make various TB consistency checks */ -//#define DEBUG_TB_CHECK -//#define DEBUG_TLB_CHECK +//#define DEBUG_TB_CHECK +//#define DEBUG_TLB_CHECK //#define DEBUG_IOPORT //#define DEBUG_SUBPAGE @@ -95,7 +95,7 @@ static ram_addr_t phys_ram_alloc_offset = 0; CPUState *first_cpu; /* current CPU in the current thread. It is only valid inside cpu_exec() */ -CPUState *cpu_single_env; +CPUState *cpu_single_env; typedef struct PageDesc { /* list of TBs intersecting this ram page */ @@ -175,10 +175,10 @@ static void page_init(void) { SYSTEM_INFO system_info; DWORD old_protect; - + GetSystemInfo(&system_info); qemu_real_host_page_size = system_info.dwPageSize; - + VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer), PAGE_EXECUTE_READWRITE, &old_protect); } @@ -189,12 +189,12 @@ static void page_init(void) start = (unsigned long)code_gen_buffer; start &= ~(qemu_real_host_page_size - 1); - + end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer); end += qemu_real_host_page_size - 1; end &= ~(qemu_real_host_page_size - 1); - - mprotect((void *)start, end - start, + + mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC); } #endif @@ -280,7 +280,7 @@ static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) #if !defined(CONFIG_USER_ONLY) static void tlb_protect_code(ram_addr_t ram_addr); -static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, +static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, target_ulong vaddr); #endif @@ -339,13 +339,13 @@ void tb_flush(CPUState *env1) { CPUState *env; #if defined(DEBUG_FLUSH) - printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", - code_gen_ptr - code_gen_buffer, - nb_tbs, + printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", + code_gen_ptr - code_gen_buffer, + nb_tbs, nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); #endif nb_tbs = 0; - + for(env = first_cpu; env != NULL; env = env->next_cpu) { memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); } @@ -382,7 +382,7 @@ static void tb_page_check(void) { TranslationBlock *tb; int i, flags1, flags2; - + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) { for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { flags1 = page_get_flags(tb->pc); @@ -491,11 +491,11 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad unsigned int h, n1; target_ulong phys_pc; TranslationBlock *tb1, *tb2; - + /* remove the TB from the hash list */ phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); h = tb_phys_hash_func(phys_pc); - tb_remove(&tb_phys_hash[h], tb, + tb_remove(&tb_phys_hash[h], tb, offsetof(TranslationBlock, phys_hash_next)); /* remove the TB from the page list */ @@ -571,7 +571,7 @@ static void build_page_bitmap(PageDesc *p) { int n, tb_start, tb_end; TranslationBlock *tb; - + p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8); if (!p->code_bitmap) return; @@ -600,7 +600,7 @@ static void build_page_bitmap(PageDesc *p) #ifdef TARGET_HAS_PRECISE_SMC -static void tb_gen_code(CPUState *env, +static void tb_gen_code(CPUState *env, target_ulong pc, target_ulong cs_base, int flags, int cflags) { @@ -624,7 +624,7 @@ static void tb_gen_code(CPUState *env, tb->cflags = cflags; 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; @@ -634,13 +634,13 @@ static void tb_gen_code(CPUState *env, tb_link_phys(tb, phys_pc, phys_page2); } #endif - + /* invalidate all TBs which intersect with the target physical page starting in range [start;end[. NOTE: start and end must refer to the same physical page. 'is_cpu_write_access' should be true if called from a real cpu write access: the virtual CPU will exit the current TB if code is modified inside this TB. */ -void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, +void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, int is_cpu_write_access) { int n, current_tb_modified, current_tb_not_found, current_flags; @@ -651,9 +651,9 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, target_ulong current_pc, current_cs_base; p = page_find(start >> TARGET_PAGE_BITS); - if (!p) + if (!p) return; - if (!p->code_bitmap && + if (!p->code_bitmap && ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD && is_cpu_write_access) { /* build code bitmap */ @@ -700,9 +700,9 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, that the modification is after the current PC, but it would require a specialized function to partially restore the CPU state */ - + current_tb_modified = 1; - cpu_restore_state(current_tb, env, + cpu_restore_state(current_tb, env, env->mem_write_pc, NULL); #if defined(TARGET_I386) current_flags = env->hflags; @@ -745,7 +745,7 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, modifying the memory. It will ensure that it cannot modify itself */ env->current_tb = NULL; - tb_gen_code(env, current_pc, current_cs_base, current_flags, + tb_gen_code(env, current_pc, current_cs_base, current_flags, CF_SINGLE_INSN); cpu_resume_from_signal(env, NULL); } @@ -760,15 +760,15 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) #if 0 if (1) { if (loglevel) { - fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", - cpu_single_env->mem_write_vaddr, len, - cpu_single_env->eip, + fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", + cpu_single_env->mem_write_vaddr, len, + cpu_single_env->eip, cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); } } #endif p = page_find(start >> TARGET_PAGE_BITS); - if (!p) + if (!p) return; if (p->code_bitmap) { offset = start & ~TARGET_PAGE_MASK; @@ -782,7 +782,7 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) } #if !defined(CONFIG_SOFTMMU) -static void tb_invalidate_phys_page(target_ulong addr, +static void tb_invalidate_phys_page(target_ulong addr, unsigned long pc, void *puc) { int n, current_flags, current_tb_modified; @@ -795,7 +795,7 @@ static void tb_invalidate_phys_page(target_ulong addr, addr &= TARGET_PAGE_MASK; p = page_find(addr >> TARGET_PAGE_BITS); - if (!p) + if (!p) return; tb = p->first_tb; current_tb_modified = 0; @@ -819,7 +819,7 @@ static void tb_invalidate_phys_page(target_ulong addr, that the modification is after the current PC, but it would require a specialized function to partially restore the CPU state */ - + current_tb_modified = 1; cpu_restore_state(current_tb, env, pc, puc); #if defined(TARGET_I386) @@ -842,7 +842,7 @@ static void tb_invalidate_phys_page(target_ulong addr, modifying the memory. It will ensure that it cannot modify itself */ env->current_tb = NULL; - tb_gen_code(env, current_pc, current_cs_base, current_flags, + tb_gen_code(env, current_pc, current_cs_base, current_flags, CF_SINGLE_INSN); cpu_resume_from_signal(env, puc); } @@ -851,7 +851,7 @@ static void tb_invalidate_phys_page(target_ulong addr, #endif /* add the tb in the target page and protect it if necessary */ -static inline void tb_alloc_page(TranslationBlock *tb, +static inline void tb_alloc_page(TranslationBlock *tb, unsigned int n, target_ulong page_addr) { PageDesc *p; @@ -886,10 +886,10 @@ static inline void tb_alloc_page(TranslationBlock *tb, p2->flags &= ~PAGE_WRITE; page_get_flags(addr); } - mprotect(g2h(page_addr), qemu_host_page_size, + mprotect(g2h(page_addr), qemu_host_page_size, (prot & PAGE_BITS) & ~PAGE_WRITE); #ifdef DEBUG_TB_INVALIDATE - printf("protecting code page: 0x%08lx\n", + printf("protecting code page: 0x%08lx\n", page_addr); #endif } @@ -911,7 +911,7 @@ TranslationBlock *tb_alloc(target_ulong pc) { TranslationBlock *tb; - if (nb_tbs >= CODE_GEN_MAX_BLOCKS || + if (nb_tbs >= CODE_GEN_MAX_BLOCKS || (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) return NULL; tb = &tbs[nb_tbs++]; @@ -922,7 +922,7 @@ TranslationBlock *tb_alloc(target_ulong pc) /* add a new TB and link it to the physical page tables. phys_page2 is (-1) to indicate that only one page contains the TB. */ -void tb_link_phys(TranslationBlock *tb, +void tb_link_phys(TranslationBlock *tb, target_ulong phys_pc, target_ulong phys_page2) { unsigned int h; @@ -988,7 +988,7 @@ TranslationBlock *tb_find_pc(unsigned long tc_ptr) } else { m_min = m + 1; } - } + } return &tbs[m_max]; } @@ -1024,7 +1024,7 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) } *ptb = tb->jmp_next[n]; tb->jmp_next[n] = NULL; - + /* suppress the jump to next tb in generated code */ tb_reset_jump(tb, n); @@ -1103,7 +1103,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) { #if defined(TARGET_HAS_ICE) int i; - + for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) return 0; @@ -1112,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) if (env->nb_breakpoints >= MAX_BREAKPOINTS) return -1; env->breakpoints[env->nb_breakpoints++] = pc; - + breakpoint_invalidate(env, pc); return 0; #else @@ -1216,11 +1216,11 @@ void cpu_reset_interrupt(CPUState *env, int mask) } CPULogItem cpu_log_items[] = { - { CPU_LOG_TB_OUT_ASM, "out_asm", + { CPU_LOG_TB_OUT_ASM, "out_asm", "show generated host assembly code for each compiled TB" }, { CPU_LOG_TB_IN_ASM, "in_asm", "show target assembly code for each compiled TB" }, - { CPU_LOG_TB_OP, "op", + { CPU_LOG_TB_OP, "op", "show micro ops for each compiled TB (only usable if 'in_asm' used)" }, #ifdef TARGET_I386 { CPU_LOG_TB_OP_OPT, "op_opt", @@ -1249,7 +1249,7 @@ static int cmp1(const char *s1, int n, const char *s2) return 0; return memcmp(s1, s2, n) == 0; } - + /* takes a comma separated list of log masks. Return 0 if error. */ int cpu_str_to_log_mask(const char *str) { @@ -1365,11 +1365,11 @@ void tlb_flush(CPUState *env, int flush_global) static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) { - if (addr == (tlb_entry->addr_read & + if (addr == (tlb_entry->addr_read & (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || - addr == (tlb_entry->addr_write & + addr == (tlb_entry->addr_write & (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || - addr == (tlb_entry->addr_code & + addr == (tlb_entry->addr_code & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { tlb_entry->addr_read = -1; tlb_entry->addr_write = -1; @@ -1423,20 +1423,20 @@ void tlb_flush_page(CPUState *env, target_ulong addr) can be detected */ static void tlb_protect_code(ram_addr_t ram_addr) { - cpu_physical_memory_reset_dirty(ram_addr, + cpu_physical_memory_reset_dirty(ram_addr, ram_addr + TARGET_PAGE_SIZE, CODE_DIRTY_FLAG); } /* update the TLB so that writes in physical page 'phys_addr' are no longer tested for self modifying code */ -static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, +static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, target_ulong vaddr) { phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG; } -static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, +static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, unsigned long start, unsigned long length) { unsigned long addr; @@ -1514,7 +1514,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, p->phys_addr >= start && p->phys_addr < end && (p->prot & PROT_WRITE)) { if (addr < MMAP_AREA_END) { - mprotect((void *)addr, TARGET_PAGE_SIZE, + mprotect((void *)addr, TARGET_PAGE_SIZE, p->prot & ~PROT_WRITE); } } @@ -1532,7 +1532,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) ram_addr_t ram_addr; if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { - ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + + ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend - (unsigned long)phys_ram_base; if (!cpu_physical_memory_is_dirty(ram_addr)) { tlb_entry->addr_write |= IO_MEM_NOTDIRTY; @@ -1558,7 +1558,7 @@ void cpu_tlb_update_dirty(CPUState *env) #endif } -static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, +static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, unsigned long start) { unsigned long addr; @@ -1593,8 +1593,8 @@ static inline void tlb_set_dirty(CPUState *env, is permitted. Return 0 if OK or 2 if the page could not be mapped (can only happen in non SOFTMMU mode for I/O pages or pages conflicting with the host address space). */ -int tlb_set_page_exec(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, int is_user, int is_softmmu) { PhysPageDesc *p; @@ -1619,7 +1619,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, ret = 0; #if !defined(CONFIG_SOFTMMU) - if (is_softmmu) + if (is_softmmu) #endif { if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { @@ -1664,12 +1664,12 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, te->addr_code = -1; } if (prot & PAGE_WRITE) { - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || (pd & IO_MEM_ROMD)) { /* write access calls the I/O callback */ - te->addr_write = vaddr | + te->addr_write = vaddr | (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD)); - } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd)) { te->addr_write = vaddr | IO_MEM_NOTDIRTY; } else { @@ -1693,17 +1693,17 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, ret = 2; } else { if (prot & PROT_WRITE) { - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || #if defined(TARGET_HAS_SMC) || 1 first_tb || #endif - ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && + ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd))) { /* ROM: we do as if code was inside */ /* if code is present, we only map as read only and save the original mapping */ VirtPageDesc *vp; - + vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1); vp->phys_addr = pd; vp->prot = prot; @@ -1711,7 +1711,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, prot &= ~PAGE_WRITE; } } - map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, + map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK)); if (map_addr == MAP_FAILED) { cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", @@ -1749,7 +1749,7 @@ int page_unprotect(target_ulong addr, unsigned long pc, void *puc) if (!(vp->prot & PAGE_WRITE)) return 0; #if defined(DEBUG_TLB) - printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", + printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", addr, vp->phys_addr, vp->prot); #endif if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0) @@ -1775,8 +1775,8 @@ void tlb_flush_page(CPUState *env, target_ulong addr) { } -int tlb_set_page_exec(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, int is_user, int is_softmmu) { return 0; @@ -1808,7 +1808,7 @@ void page_dump(FILE *f) end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); if (start != -1) { fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", - start, end, end - start, + start, end, end - start, prot & PAGE_READ ? 'r' : '-', prot & PAGE_WRITE ? 'w' : '-', prot & PAGE_EXEC ? 'x' : '-'); @@ -1852,7 +1852,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) p = page_find_alloc(addr >> TARGET_PAGE_BITS); /* if the write protection is set, then we invalidate the code inside */ - if (!(p->flags & PAGE_WRITE) && + if (!(p->flags & PAGE_WRITE) && (flags & PAGE_WRITE) && p->first_tb) { tb_invalidate_phys_page(addr, 0, NULL); @@ -1887,7 +1887,7 @@ int page_unprotect(target_ulong address, unsigned long pc, void *puc) if (prot & PAGE_WRITE_ORG) { pindex = (address - host_start) >> TARGET_PAGE_BITS; if (!(p1[pindex].flags & PAGE_WRITE)) { - mprotect((void *)g2h(host_start), qemu_host_page_size, + mprotect((void *)g2h(host_start), qemu_host_page_size, (prot & PAGE_BITS) | PAGE_WRITE); p1[pindex].flags |= PAGE_WRITE; /* and since the content will be modified, we must invalidate @@ -1950,7 +1950,7 @@ static void *subpage_init (target_phys_addr_t base, uint32_t *phys, /* register physical memory. 'size' must be a multiple of the target page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an io memory page */ -void cpu_register_physical_memory(target_phys_addr_t start_addr, +void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long size, unsigned long phys_offset) { @@ -2008,7 +2008,7 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, } } } - + /* since each CPU stores ram addresses in its TLB cache, we must reset the modified entries */ /* XXX: slow ! */ @@ -2033,7 +2033,7 @@ ram_addr_t qemu_ram_alloc(unsigned int size) { ram_addr_t addr; if ((phys_ram_alloc_offset + size) >= phys_ram_size) { - fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n", + fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n", size, phys_ram_size); abort(); } @@ -2448,7 +2448,7 @@ CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index) /* physical memory access (slow version, mainly for debug) */ #if defined(CONFIG_USER_ONLY) -void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { int l, flags; @@ -2483,7 +2483,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } #else -void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { int l, io_index; @@ -2492,7 +2492,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, target_phys_addr_t page; unsigned long pd; PhysPageDesc *p; - + while (len > 0) { page = addr & TARGET_PAGE_MASK; l = (page + TARGET_PAGE_SIZE) - addr; @@ -2504,7 +2504,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } else { pd = p->phys_offset; } - + if (is_write) { if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); @@ -2536,12 +2536,12 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); /* set dirty bit */ - phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= (0xff & ~CODE_DIRTY_FLAG); } } } else { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); @@ -2563,7 +2563,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } else { /* RAM case */ - ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); memcpy(buf, ptr, l); } @@ -2575,7 +2575,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } /* used for ROM loading : can write in RAM and ROM */ -void cpu_physical_memory_write_rom(target_phys_addr_t addr, +void cpu_physical_memory_write_rom(target_phys_addr_t addr, const uint8_t *buf, int len) { int l; @@ -2583,7 +2583,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, target_phys_addr_t page; unsigned long pd; PhysPageDesc *p; - + while (len > 0) { page = addr & TARGET_PAGE_MASK; l = (page + TARGET_PAGE_SIZE) - addr; @@ -2595,7 +2595,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { @@ -2629,15 +2629,15 @@ uint32_t ldl_phys(target_phys_addr_t addr) } else { pd = p->phys_offset; } - - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); } else { /* RAM case */ - ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); val = ldl_p(ptr); } @@ -2659,7 +2659,7 @@ uint64_t ldq_phys(target_phys_addr_t addr) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { /* I/O case */ @@ -2673,7 +2673,7 @@ uint64_t ldq_phys(target_phys_addr_t addr) #endif } else { /* RAM case */ - ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); val = ldq_p(ptr); } @@ -2712,12 +2712,12 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); } else { - ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); stl_p(ptr, val); } @@ -2736,7 +2736,7 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); #ifdef TARGET_WORDS_BIGENDIAN @@ -2747,7 +2747,7 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32); #endif } else { - ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); stq_p(ptr, val); } @@ -2767,7 +2767,7 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); @@ -2811,7 +2811,7 @@ void stq_phys(target_phys_addr_t addr, uint64_t val) #endif /* virtual memory access for debug */ -int cpu_memory_rw_debug(CPUState *env, target_ulong addr, +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write) { int l; @@ -2827,7 +2827,7 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), + cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), buf, l, is_write); len -= l; buf += l; @@ -2842,7 +2842,7 @@ void dump_exec_info(FILE *f, int i, target_code_size, max_target_code_size; int direct_jmp_count, direct_jmp2_count, cross_page; TranslationBlock *tb; - + target_code_size = 0; max_target_code_size = 0; cross_page = 0; @@ -2864,17 +2864,17 @@ void dump_exec_info(FILE *f, } /* XXX: avoid using doubles ? */ cpu_fprintf(f, "TB count %d\n", nb_tbs); - cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", + cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", nb_tbs ? target_code_size / nb_tbs : 0, max_target_code_size); - cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n", + cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n", nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0, target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0); - cpu_fprintf(f, "cross page TB count %d (%d%%)\n", - cross_page, + cpu_fprintf(f, "cross page TB count %d (%d%%)\n", + cross_page, nb_tbs ? (cross_page * 100) / nb_tbs : 0); cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n", - direct_jmp_count, + direct_jmp_count, nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0, direct_jmp2_count, nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0); @@ -2883,7 +2883,7 @@ void dump_exec_info(FILE *f, cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); } -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _cmmu #define GETPC() NULL diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 9994f6d27..e58551f33 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -59,7 +59,7 @@ double qemu_rint(double x) double y = 4503599627370496.0; if (fabs(x) >= y) return x; - if (x < 0) + if (x < 0) y = -y; y = (x + y) - y; if (y == 0.0) @@ -131,7 +131,7 @@ static inline int long_to_int32(long a) #else static inline int long_to_int32(long a) { - if (a != (int32_t)a) + if (a != (int32_t)a) a = 0x80000000; return a; } diff --git a/gdbstub.c b/gdbstub.c index 37347da0b..dc10357ea 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1,6 +1,6 @@ /* * gdb server stub - * + * * Copyright (c) 2003-2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -252,7 +252,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) registers[41] = 0; /* foseg */ registers[42] = 0; /* fooff */ registers[43] = 0; /* fop */ - + for(i = 0; i < 16; i++) tswapls(®isters[i]); for(i = 36; i < 44; i++) @@ -543,7 +543,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) /* F0-F7. The 68881/68040 have 12-bit extended precision registers. ColdFire has 8-bit double precision registers. */ for (i = 0; i < 8; i++) { - u.l.upper = tswap32(*(uint32_t *)ptr); + u.l.upper = tswap32(*(uint32_t *)ptr); u.l.lower = tswap32(*(uint32_t *)ptr); env->fregs[i] = u.d; } @@ -748,7 +748,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) uint8_t mem_buf[2000]; uint32_t *registers; target_ulong addr, len; - + #ifdef DEBUG_GDB printf("command='%s'\n", line_buf); #endif @@ -1073,7 +1073,7 @@ static void gdb_read_byte(GDBState *s, int ch) /* when the CPU is running, we cannot do anything except stop it when receiving a char */ vm_stop(EXCP_INTERRUPT); - } else + } else #endif { switch(s->state) { @@ -1201,7 +1201,7 @@ static void gdb_accept(void *opaque) /* set short latency */ val = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); - + s = &gdbserver_state; memset (s, 0, sizeof (GDBState)); s->env = first_cpu; /* XXX: allow to change CPU */ diff --git a/hw/acpi.c b/hw/acpi.c index 871a737f3..add8cc838 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -1,8 +1,8 @@ /* * ACPI implementation - * + * * Copyright (c) 2006 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 version 2 as published by the Free Software Foundation. @@ -87,9 +87,9 @@ static void pm_update_sci(PIIX4PMState *s) { int sci_level, pmsts; int64_t expire_time; - + pmsts = get_pmsts(s); - sci_level = (((pmsts & s->pmen) & + sci_level = (((pmsts & s->pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); qemu_set_irq(s->dev.irq[0], sci_level); /* schedule a timer interruption if needed */ @@ -239,7 +239,7 @@ static uint32_t pm_smi_readb(void *opaque, uint32_t addr) { PIIX4PMState *s = opaque; uint32_t val; - + addr &= 1; if (addr == 0) { val = s->apmc; @@ -413,7 +413,7 @@ static void pm_io_space_update(PIIX4PMState *s) } } -static void pm_write_config(PCIDevice *d, +static void pm_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { pci_default_write_config(d, address, val, len); @@ -480,9 +480,9 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base) pci_conf[0x0b] = 0x06; // bridge device pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 0x01; // interrupt pin 1 - + pci_conf[0x40] = 0x01; /* PM io base read only bit */ - + register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s); register_ioport_read(0xb2, 2, 1, pm_smi_readb, s); diff --git a/hw/adb.c b/hw/adb.c index 3f664a9c5..756c07906 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -1,8 +1,8 @@ /* * QEMU ADB support - * + * * Copyright (c) 2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -96,9 +96,9 @@ int adb_poll(ADBBusState *s, uint8_t *obuf) return olen; } -ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceRequest *devreq, - ADBDeviceReset *devreset, +ADBDevice *adb_register_device(ADBBusState *s, int devaddr, + ADBDeviceRequest *devreq, + ADBDeviceReset *devreset, void *opaque) { ADBDevice *d; @@ -299,31 +299,31 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) if (s->last_buttons_state == s->buttons_state && s->dx == 0 && s->dy == 0) return 0; - + dx = s->dx; if (dx < -63) dx = -63; else if (dx > 63) dx = 63; - + dy = s->dy; if (dy < -63) dy = -63; else if (dy > 63) dy = 63; - + s->dx -= dx; s->dy -= dy; s->last_buttons_state = s->buttons_state; - + dx &= 0x7f; dy &= 0x7f; - + if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) dy |= 0x80; if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) dx |= 0x80; - + obuf[0] = dy; obuf[1] = dx; return 2; @@ -334,7 +334,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, { MouseState *s = d->opaque; int cmd, reg, olen; - + if ((buf[0] & 0x0f) == ADB_FLUSH) { /* flush mouse fifo */ s->buttons_state = s->last_buttons_state; diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c index 0fe9d969f..8df7d8904 100644 --- a/hw/alpha_palcode.c +++ b/hw/alpha_palcode.c @@ -1,6 +1,6 @@ /* * Alpha emulation - PALcode emulation for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -62,7 +62,7 @@ static void update_itb () mtpr(TB_TAG); mtpr(TB_CTL); /* This commits the TB update */ - mtpr(ITB_PTE); + mtpr(ITB_PTE); } static void update_dtb (); @@ -937,7 +937,7 @@ static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot, } } *paddr = (pfn << page_bits) | (vaddr & page_mask); - + return 0; } @@ -998,7 +998,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, if (env->user_mode_only) { ret = 2; - } else { + } else { ret = virtual_to_physical(env, &physical, &zbits, &prot, address, is_user, rw); } diff --git a/hw/an5206.c b/hw/an5206.c index 379f48e78..94ecccb3e 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -1,4 +1,4 @@ -/* +/* * Arnewsh 5206 ColdFire system emulation. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 38c56a2d4..1de335384 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -2,7 +2,7 @@ * QEMU Ultrasparc APB PCI host * * 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 @@ -233,7 +233,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom - d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice), + d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice), 0, NULL, NULL); d->config[0x00] = 0x8e; // vendor_id : Sun d->config[0x01] = 0x10; diff --git a/hw/apic.c b/hw/apic.c index d503d45f2..bbe44fa7d 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -1,6 +1,6 @@ /* * APIC support - * + * * Copyright (c) 2004-2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -182,7 +182,7 @@ static inline void reset_bit(uint32_t *tab, int index) }\ } -static void apic_bus_deliver(const uint32_t *deliver_bitmask, +static void apic_bus_deliver(const uint32_t *deliver_bitmask, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode) @@ -219,10 +219,10 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, case APIC_DM_INIT: /* normal INIT IPI sent to processors */ - foreach_apic(apic_iter, deliver_bitmask, + foreach_apic(apic_iter, deliver_bitmask, apic_init_ipi(apic_iter) ); return; - + case APIC_DM_EXTINT: /* handled in I/O APIC code */ break; @@ -231,7 +231,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, return; } - foreach_apic(apic_iter, deliver_bitmask, + foreach_apic(apic_iter, deliver_bitmask, apic_set_irq(apic_iter, vector_num, trigger_mode) ); } @@ -241,7 +241,7 @@ void cpu_set_apic_base(CPUState *env, uint64_t val) #ifdef DEBUG_APIC printf("cpu_set_apic_base: %016" PRIx64 "\n", val); #endif - s->apicbase = (val & 0xfffff000) | + s->apicbase = (val & 0xfffff000) | (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); /* if disabled, cannot be enabled again */ if (!(val & MSR_IA32_APICBASE_ENABLE)) { @@ -407,7 +407,7 @@ static void apic_startup(APICState *s, int vector_num) if (!(env->hflags & HF_HALTED_MASK)) return; env->eip = 0; - cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, + cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, 0xffff, 0); env->hflags &= ~HF_HALTED_MASK; } @@ -443,7 +443,7 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, int trig_mode = (s->icr[0] >> 15) & 1; int level = (s->icr[0] >> 14) & 1; if (level == 0 && trig_mode == 1) { - foreach_apic(apic_iter, deliver_bitmask, + foreach_apic(apic_iter, deliver_bitmask, apic_iter->arb_id = apic_iter->id ); return; } @@ -451,7 +451,7 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, break; case APIC_DM_SIPI: - foreach_apic(apic_iter, deliver_bitmask, + foreach_apic(apic_iter, deliver_bitmask, apic_startup(apic_iter, vector_num) ); return; } @@ -471,7 +471,7 @@ int apic_get_interrupt(CPUState *env) return -1; if (!(s->spurious_vec & APIC_SV_ENABLE)) return -1; - + /* XXX: spurious IRQ handling */ intno = get_highest_priority_int(s->irr); if (intno < 0) @@ -488,7 +488,7 @@ static uint32_t apic_get_current_count(APICState *s) { int64_t d; uint32_t val; - d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> + d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { /* periodic */ @@ -505,9 +505,9 @@ static uint32_t apic_get_current_count(APICState *s) static void apic_timer_update(APICState *s, int64_t current_time) { int64_t next_time, d; - + if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { - d = (current_time - s->initial_count_load_time) >> + d = (current_time - s->initial_count_load_time) >> s->count_shift; if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1); @@ -818,14 +818,14 @@ int apic_init(CPUState *env) s->id = last_apic_id++; env->cpuid_apic_id = s->id; s->cpu_env = env; - s->apicbase = 0xfee00000 | + s->apicbase = 0xfee00000 | (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; /* XXX: mapping more APICs at the same memory location */ if (apic_io_memory == 0) { /* NOTE: the APIC is directly connected to the CPU - it is not on the global memory bus. */ - apic_io_memory = cpu_register_io_memory(0, apic_mem_read, + apic_io_memory = cpu_register_io_memory(0, apic_mem_read, apic_mem_write, NULL); cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory); @@ -834,7 +834,7 @@ int apic_init(CPUState *env) register_savevm("apic", s->id, 2, apic_save, apic_load, s); qemu_register_reset(apic_reset, s); - + local_apics[s->id] = s; return 0; } @@ -868,9 +868,9 @@ static void ioapic_service(IOAPICState *s) vector = pic_read_irq(isa_pic); else vector = entry & 0xff; - + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); - apic_bus_deliver(deliver_bitmask, delivery_mode, + apic_bus_deliver(deliver_bitmask, delivery_mode, vector, polarity, trig_mode); } } @@ -1036,12 +1036,12 @@ IOAPICState *ioapic_init(void) ioapic_reset(s); s->id = last_apic_id++; - io_memory = cpu_register_io_memory(0, ioapic_mem_read, + io_memory = cpu_register_io_memory(0, ioapic_mem_read, ioapic_mem_write, s); cpu_register_physical_memory(0xfec00000, 0x1000, io_memory); register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s); qemu_register_reset(ioapic_reset, s); - + return s; } diff --git a/hw/arm_boot.c b/hw/arm_boot.c index ccc9ecbf6..7a99b4175 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -1,4 +1,4 @@ -/* +/* * ARM kernel loader. * * Copyright (c) 2006 CodeSourcery. @@ -30,8 +30,8 @@ static void main_cpu_reset(void *opaque) cpu_reset(env); if (env->kernel_filename) - arm_load_kernel(env, env->ram_size, env->kernel_filename, - env->kernel_cmdline, env->initrd_filename, + arm_load_kernel(env, env->ram_size, env->kernel_filename, + env->kernel_cmdline, env->initrd_filename, env->board_id, env->loader_start); } diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 58d840415..8cd7182cf 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -1,4 +1,4 @@ -/* +/* * ARM AMBA Generic/Distributed Interrupt Controller * * Copyright (c) 2006 CodeSourcery. @@ -115,7 +115,7 @@ static void gic_set_irq(void *opaque, int irq, int level) gic_state *s = (gic_state *)opaque; /* The first external input line is internal interrupt 32. */ irq += 32; - if (level == GIC_TEST_LEVEL(irq)) + if (level == GIC_TEST_LEVEL(irq)) return; if (level) { diff --git a/hw/arm_pic.c b/hw/arm_pic.c index dcc1198e4..7f4a694d9 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -1,4 +1,4 @@ -/* +/* * Generic ARM Programmable Interrupt Controller support. * * Copyright (c) 2006 CodeSourcery. diff --git a/hw/arm_pic.h b/hw/arm_pic.h index 6c5ed1758..1eba2baab 100644 --- a/hw/arm_pic.h +++ b/hw/arm_pic.h @@ -1,4 +1,4 @@ -/* +/* * Generic ARM Programmable Interrupt Controller support. * * Copyright (c) 2006 CodeSourcery. diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 600889d38..468a494db 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -1,4 +1,4 @@ -/* +/* * Status and system control registers for ARM RealView/Versatile boards. * * Copyright (c) 2006 CodeSourcery. diff --git a/hw/arm_timer.c b/hw/arm_timer.c index c0a0aa986..3df386af4 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -1,4 +1,4 @@ -/* +/* * ARM PrimeCell Timer modules. * * Copyright (c) 2005-2006 CodeSourcery. diff --git a/hw/cdrom.c b/hw/cdrom.c index a43b41790..18c7e31c6 100644 --- a/hw/cdrom.c +++ b/hw/cdrom.c @@ -1,8 +1,8 @@ /* * QEMU ATAPI CD-ROM Emulator - * + * * 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 @@ -41,7 +41,7 @@ int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) { uint8_t *q; int len; - + if (start_track > 1 && start_track != 0xaa) return -1; q = buf + 2; @@ -85,7 +85,7 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) { uint8_t *q; int len; - + q = buf + 2; *q++ = 1; /* first session */ *q++ = 1; /* last session */ @@ -101,7 +101,7 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) *q++ = 1; /* first track */ *q++ = 0x00; /* disk type */ *q++ = 0x00; - + *q++ = 1; /* session number */ *q++ = 0x14; /* data track */ *q++ = 0; /* track number */ @@ -113,7 +113,7 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) *q++ = 1; /* last track */ *q++ = 0x00; *q++ = 0x00; - + *q++ = 1; /* session number */ *q++ = 0x14; /* data track */ *q++ = 0; /* track number */ @@ -138,14 +138,14 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) *q++ = 0; /* sec */ *q++ = 0; /* frame */ if (msf) { - *q++ = 0; + *q++ = 0; lba_to_msf(q, 0); q += 3; } else { - *q++ = 0; - *q++ = 0; - *q++ = 0; - *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; } len = q - buf; diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index d8633c988..febac441e 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -1,9 +1,9 @@ /* * QEMU Cirrus CLGD 54xx VGA Emulator. - * + * * Copyright (c) 2004 Fabrice Bellard * Copyright (c) 2004 Makoto Suzuki (suzu) - * + * * 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 @@ -275,7 +275,7 @@ typedef struct PCICirrusVGAState { } PCICirrusVGAState; static uint8_t rop_to_index[256]; - + /*************************************** * * prototypes. @@ -590,7 +590,7 @@ static inline void cirrus_bitblt_fgcol(CirrusVGAState *s) s->cirrus_blt_fgcol = le16_to_cpu(color); break; case 3: - s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 | + s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) | (s->gr[0x13] << 16); break; default: @@ -614,7 +614,7 @@ static inline void cirrus_bitblt_bgcol(CirrusVGAState *s) s->cirrus_blt_bgcol = le16_to_cpu(color); break; case 3: - s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 | + s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8) | (s->gr[0x12] << 16); break; default: @@ -653,7 +653,7 @@ static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, dst = s->vram_ptr + s->cirrus_blt_dstaddr; (*s->cirrus_rop) (s, dst, src, - s->cirrus_blt_dstpitch, 0, + s->cirrus_blt_dstpitch, 0, s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_width, @@ -668,7 +668,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) cirrus_fill_t rop_func; rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, + rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, s->cirrus_blt_dstpitch, s->cirrus_blt_width, s->cirrus_blt_height); cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, @@ -687,7 +687,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) { return cirrus_bitblt_common_patterncopy(s, - s->vram_ptr + + s->vram_ptr + (s->cirrus_blt_srcaddr & ~7)); } @@ -788,7 +788,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) { int copy_count; uint8_t *end_ptr; - + if (s->cirrus_srccounter > 0) { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf); @@ -854,7 +854,7 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s) } else { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth; - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) s->cirrus_blt_srcpitch = ((w + 31) >> 5); else s->cirrus_blt_srcpitch = ((w + 7) >> 3); @@ -913,7 +913,7 @@ static void cirrus_bitblt_start(CirrusVGAState * s) #ifdef DEBUG_BITBLT printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", - blt_rop, + blt_rop, s->cirrus_blt_mode, s->cirrus_blt_modeext, s->cirrus_blt_width, @@ -957,16 +957,16 @@ static void cirrus_bitblt_start(CirrusVGAState * s) } if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) && - (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST | + (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST | CIRRUS_BLTMODE_TRANSPARENTCOMP | - CIRRUS_BLTMODE_PATTERNCOPY | - CIRRUS_BLTMODE_COLOREXPAND)) == + CIRRUS_BLTMODE_PATTERNCOPY | + CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) { cirrus_bitblt_fgcol(s); cirrus_bitblt_solidfill(s, blt_rop); } else { - if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND | - CIRRUS_BLTMODE_PATTERNCOPY)) == + if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND | + CIRRUS_BLTMODE_PATTERNCOPY)) == CIRRUS_BLTMODE_COLOREXPAND) { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { @@ -1059,7 +1059,7 @@ static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value) * ***************************************/ -static void cirrus_get_offsets(VGAState *s1, +static void cirrus_get_offsets(VGAState *s1, uint32_t *pline_offset, uint32_t *pstart_addr, uint32_t *pline_compare) @@ -1079,7 +1079,7 @@ static void cirrus_get_offsets(VGAState *s1, | ((s->cr[0x1d] & 0x80) << 12); *pstart_addr = start_addr; - line_compare = s->cr[0x18] | + line_compare = s->cr[0x18] | ((s->cr[0x07] & 0x10) << 4) | ((s->cr[0x09] & 0x40) << 3); *pline_compare = line_compare; @@ -1148,10 +1148,10 @@ static int cirrus_get_bpp(VGAState *s1) static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight) { int width, height; - + width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | ((s->cr[0x07] & 0x40) << 3); height = (height + 1); /* interlace support */ @@ -2036,7 +2036,7 @@ static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr) return v; } -static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, +static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t mem_value) { CirrusVGAState *s = opaque; @@ -2147,7 +2147,7 @@ static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = { static inline void invalidate_cursor1(CirrusVGAState *s) { if (s->last_hw_cursor_size) { - vga_invalidate_scanlines((VGAState *)s, + vga_invalidate_scanlines((VGAState *)s, s->last_hw_cursor_y + s->last_hw_cursor_y_start, s->last_hw_cursor_y + s->last_hw_cursor_y_end); } @@ -2223,7 +2223,7 @@ static void cirrus_cursor_invalidate(VGAState *s1) s->last_hw_cursor_y != s->hw_cursor_y) { invalidate_cursor1(s); - + s->last_hw_cursor_size = size; s->last_hw_cursor_x = s->hw_cursor_x; s->last_hw_cursor_y = s->hw_cursor_y; @@ -2240,8 +2240,8 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) unsigned int color0, color1; const uint8_t *palette, *src; uint32_t content; - - if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW)) + + if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW)) return; /* fast test to see if the cursor intersects with the scan line */ if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { @@ -2252,7 +2252,7 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) if (scr_y < s->hw_cursor_y || scr_y >= (s->hw_cursor_y + h)) return; - + src = s->vram_ptr + s->real_vram_size - 16 * 1024; if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { src += (s->sr[0x13] & 0x3c) * 256; @@ -2282,11 +2282,11 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) x2 = s->last_scr_width; w = x2 - x1; palette = s->cirrus_hidden_palette; - color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]), - c6_to_8(palette[0x0 * 3 + 1]), + color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]), + c6_to_8(palette[0x0 * 3 + 1]), c6_to_8(palette[0x0 * 3 + 2])); - color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]), - c6_to_8(palette[0xf * 3 + 1]), + color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]), + c6_to_8(palette[0xf * 3 + 1]), c6_to_8(palette[0xf * 3 + 2])); bpp = ((s->ds->depth + 7) >> 3); d1 += x1 * bpp; @@ -2321,7 +2321,7 @@ static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr) addr &= s->cirrus_addr_mask; - if (((s->sr[0x17] & 0x44) == 0x44) && + if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { /* memory-mapped I/O */ ret = cirrus_mmio_blt_read(s, addr & 0xff); @@ -2379,8 +2379,8 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr, unsigned mode; addr &= s->cirrus_addr_mask; - - if (((s->sr[0x17] & 0x44) == 0x44) && + + if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { /* memory-mapped I/O */ cirrus_mmio_blt_write(s, addr & 0xff, val); @@ -2600,7 +2600,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s) } else if (s->gr[0x0B] & 0x02) { goto generic_io; } - + mode = s->gr[0x05] & 0x7; if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { s->cirrus_linear_write[0] = cirrus_linear_mem_writeb; @@ -3110,9 +3110,9 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); - vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read, + vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read, cirrus_vga_mem_write, s); - cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, + cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, vga_io_memory); s->sr[0x06] = 0x0f; @@ -3134,7 +3134,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) } else { s->sr[0x1F] = 0x22; // MemClock s->sr[0x0F] = CIRRUS_MEMSIZE_2M; - if (is_pci) + if (is_pci) s->sr[0x17] = CIRRUS_BUSTYPE_PCI; else s->sr[0x17] = CIRRUS_BUSTYPE_ISA; @@ -3184,14 +3184,14 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) * ***************************************/ -void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, +void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { CirrusVGAState *s; s = qemu_mallocz(sizeof(CirrusVGAState)); - - vga_common_init((VGAState *)s, + + vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0); /* XXX ISA-LFB support */ @@ -3224,19 +3224,19 @@ static void cirrus_pci_mmio_map(PCIDevice *d, int region_num, s->cirrus_mmio_io_addr); } -void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, +void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { PCICirrusVGAState *d; uint8_t *pci_conf; CirrusVGAState *s; int device_id; - + device_id = CIRRUS_ID_CLGD5446; /* setup PCI configuration registers */ - d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA", - sizeof(PCICirrusVGAState), + d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA", + sizeof(PCICirrusVGAState), -1, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff); @@ -3250,7 +3250,7 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, /* setup VGA */ s = &d->cirrus_vga; - vga_common_init((VGAState *)s, + vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, device_id, 1); diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h index fbee6edeb..3d6a1fef1 100644 --- a/hw/cirrus_vga_rop.h +++ b/hw/cirrus_vga_rop.h @@ -1,8 +1,8 @@ /* * QEMU Cirrus CLGD 54xx VGA Emulator. - * + * * Copyright (c) 2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h index da11d0f5e..91f0db83d 100644 --- a/hw/cirrus_vga_rop2.h +++ b/hw/cirrus_vga_rop2.h @@ -1,8 +1,8 @@ /* * QEMU Cirrus CLGD 54xx VGA Emulator. - * + * * Copyright (c) 2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -34,13 +34,13 @@ #define PUTPIXEL() ROP_OP(((uint32_t *)d)[0], col) #else #error unsupported DEPTH -#endif +#endif static void glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, + const uint8_t * src, + int dstpitch, int srcpitch, int bltwidth, int bltheight) { uint8_t *d; @@ -94,8 +94,8 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, + const uint8_t * src, + int dstpitch, int srcpitch, int bltwidth, int bltheight) { uint8_t *d; @@ -143,8 +143,8 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, + const uint8_t * src, + int dstpitch, int srcpitch, int bltwidth, int bltheight) { uint32_t colors[2]; @@ -179,8 +179,8 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, + const uint8_t * src, + int dstpitch, int srcpitch, int bltwidth, int bltheight) { uint8_t *d; @@ -223,8 +223,8 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) static void glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, + const uint8_t * src, + int dstpitch, int srcpitch, int bltwidth, int bltheight) { uint32_t colors[2]; @@ -254,10 +254,10 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) } } -static void +static void glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH) (CirrusVGAState *s, - uint8_t *dst, int dst_pitch, + uint8_t *dst, int dst_pitch, int width, int height) { uint8_t *d, *d1; diff --git a/hw/cuda.c b/hw/cuda.c index dc143e205..75ceea1e4 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -1,8 +1,8 @@ /* * QEMU CUDA support - * + * * Copyright (c) 2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -94,7 +94,7 @@ #define RTC_OFFSET 2082844800 typedef struct CUDATimer { - int index; + int index; uint16_t latch; uint16_t counter_value; /* counter value at load time */ int64_t load_time; @@ -116,10 +116,10 @@ typedef struct CUDAState { uint8_t anh; /* A-side data, no handshake */ CUDATimer timers[2]; - + uint8_t last_b; /* last value of B register */ uint8_t last_acr; /* last value of B register */ - + int data_in_size; int data_in_index; int data_out_index; @@ -135,9 +135,9 @@ static CUDAState cuda_state; ADBBusState adb_bus; static void cuda_update(CUDAState *s); -static void cuda_receive_packet_from_host(CUDAState *s, +static void cuda_receive_packet_from_host(CUDAState *s, const uint8_t *data, int len); -static void cuda_timer_update(CUDAState *s, CUDATimer *ti, +static void cuda_timer_update(CUDAState *s, CUDATimer *ti, int64_t current_time); static void cuda_update_irq(CUDAState *s) @@ -154,7 +154,7 @@ static unsigned int get_counter(CUDATimer *s) int64_t d; unsigned int counter; - d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, + d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); if (s->index == 0) { /* the timer goes down from latch to -1 (period of latch + 2) */ @@ -162,7 +162,7 @@ static unsigned int get_counter(CUDATimer *s) counter = (s->counter_value - d) & 0xffff; } else { counter = (d - (s->counter_value + 1)) % (s->latch + 2); - counter = (s->latch - counter) & 0xffff; + counter = (s->latch - counter) & 0xffff; } } else { counter = (s->counter_value - d) & 0xffff; @@ -187,16 +187,16 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) unsigned int counter; /* current counter value */ - d = muldiv64(current_time - s->load_time, + d = muldiv64(current_time - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); /* the timer goes down from latch to -1 (period of latch + 2) */ if (d <= (s->counter_value + 1)) { counter = (s->counter_value - d) & 0xffff; } else { counter = (d - (s->counter_value + 1)) % (s->latch + 2); - counter = (s->latch - counter) & 0xffff; + counter = (s->latch - counter) & 0xffff; } - + /* Note: we consider the irq is raised on 0 */ if (counter == 0xffff) { next_time = d + s->latch + 1; @@ -207,18 +207,18 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) } #if 0 #ifdef DEBUG_CUDA - printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", + printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", s->latch, d, next_time - d); #endif #endif - next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + + next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + s->load_time; if (next_time <= current_time) next_time = current_time + 1; return next_time; } -static void cuda_timer_update(CUDAState *s, CUDATimer *ti, +static void cuda_timer_update(CUDAState *s, CUDATimer *ti, int64_t current_time) { if (!ti->timer) @@ -296,7 +296,7 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) break; case 13: val = s->ifr; - if (s->ifr & s->ier) + if (s->ifr & s->ier) val |= 0x80; break; case 14: @@ -317,7 +317,7 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { CUDAState *s = opaque; - + addr = (addr >> 9) & 0xf; #ifdef DEBUG_CUDA printf("cuda: write: reg=0x%x val=%02x\n", addr, val); @@ -470,7 +470,7 @@ static void cuda_update(CUDAState *s) } } -static void cuda_send_packet_to_host(CUDAState *s, +static void cuda_send_packet_to_host(CUDAState *s, const uint8_t *data, int len) { #ifdef DEBUG_CUDA_PACKET @@ -502,12 +502,12 @@ static void cuda_adb_poll(void *opaque) obuf[1] = 0x40; /* polled data */ cuda_send_packet_to_host(s, obuf, olen + 2); } - qemu_mod_timer(s->adb_poll_timer, - qemu_get_clock(vm_clock) + + qemu_mod_timer(s->adb_poll_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / CUDA_ADB_POLL_FREQ)); } -static void cuda_receive_packet(CUDAState *s, +static void cuda_receive_packet(CUDAState *s, const uint8_t *data, int len) { uint8_t obuf[16]; @@ -519,8 +519,8 @@ static void cuda_receive_packet(CUDAState *s, if (autopoll != s->autopoll) { s->autopoll = autopoll; if (autopoll) { - qemu_mod_timer(s->adb_poll_timer, - qemu_get_clock(vm_clock) + + qemu_mod_timer(s->adb_poll_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / CUDA_ADB_POLL_FREQ)); } else { qemu_del_timer(s->adb_poll_timer); @@ -562,7 +562,7 @@ static void cuda_receive_packet(CUDAState *s, } } -static void cuda_receive_packet_from_host(CUDAState *s, +static void cuda_receive_packet_from_host(CUDAState *s, const uint8_t *data, int len) { #ifdef DEBUG_CUDA_PACKET diff --git a/hw/eepro100.c b/hw/eepro100.c index 36b09252b..975aeb172 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1618,7 +1618,7 @@ static int nic_load(QEMUFile * f, void *opaque, int version_id) for (i = 0; i < 3; i++) qemu_get_be32s(f, &s->region[i]); qemu_get_buffer(f, s->macaddr, 6); - for (i = 0; i < 19; i++) + for (i = 0; i < 19; i++) qemu_get_be32s(f, &s->statcounter[i]); for (i = 0; i < 32; i++) qemu_get_be16s(f, &s->mdimem[i]); @@ -1697,7 +1697,7 @@ static void nic_save(QEMUFile * f, void *opaque) for (i = 0; i < 3; i++) qemu_put_be32s(f, &s->region[i]); qemu_put_buffer(f, s->macaddr, 6); - for (i = 0; i < 19; i++) + for (i = 0; i < 19; i++) qemu_put_be32s(f, &s->statcounter[i]); for (i = 0; i < 32; i++) qemu_put_be16s(f, &s->mdimem[i]); diff --git a/hw/esp.c b/hw/esp.c index 10d4cadf2..0d22ce35e 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -1,8 +1,8 @@ /* * QEMU ESP/NCR53C9x emulation - * + * * Copyright (c) 2005-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 @@ -531,7 +531,7 @@ static void esp_save(QEMUFile *f, void *opaque) static int esp_load(QEMUFile *f, void *opaque, int version_id) { ESPState *s = opaque; - + if (version_id != 3) return -EINVAL; // Cannot emulate 2 diff --git a/hw/fdc.c b/hw/fdc.c index 98a3c3131..dcd1d46b4 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1,8 +1,8 @@ /* * QEMU Floppy disk emulator (Intel 82078) - * + * * Copyright (c) 2003, 2007 Jocelyn Mayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -217,7 +217,7 @@ static fd_format_t fd_formats[] = { { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", }, { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", }, { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", }, - /* 320 kB 5"1/4 floppy disks */ + /* 320 kB 5"1/4 floppy disks */ { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", }, { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", }, /* 360 kB must match 5"1/4 better than 3"1/2... */ @@ -467,7 +467,7 @@ static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg) return fdctrl_read(opaque, (uint32_t)reg); } -static void fdctrl_write_mem (void *opaque, +static void fdctrl_write_mem (void *opaque, target_phys_addr_t reg, uint32_t value) { fdctrl_write(opaque, (uint32_t)reg, value); @@ -578,7 +578,7 @@ static void fdctrl_external_reset(void *opaque) fdctrl_reset(s, 0); } -fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, +fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, target_phys_addr_t io_base, BlockDriverState **fds) { @@ -590,7 +590,7 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, fdctrl = qemu_mallocz(sizeof(fdctrl_t)); if (!fdctrl) return NULL; - fdctrl->result_timer = qemu_new_timer(vm_clock, + fdctrl->result_timer = qemu_new_timer(vm_clock, fdctrl_result_timer, fdctrl); fdctrl->version = 0x90; /* Intel 82078 controller */ @@ -842,7 +842,7 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) static int fdctrl_media_changed(fdrive_t *drv) { int ret; - if (!drv->bs) + if (!drv->bs) return 0; ret = bdrv_media_changed(drv->bs); if (ret) { @@ -1141,7 +1141,7 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, cur_drv->sect = 1; if (FD_MULTI_TRACK(fdctrl->data_state)) { if (cur_drv->head == 0 && - (cur_drv->flags & FDISK_DBL_SIDES) != 0) { + (cur_drv->flags & FDISK_DBL_SIDES) != 0) { cur_drv->head = 1; } else { cur_drv->head = 0; @@ -1732,7 +1732,7 @@ enqueue: FLOPPY_DPRINTF("treat READ_ID command\n"); /* XXX: should set main status register to busy */ cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; - qemu_mod_timer(fdctrl->result_timer, + qemu_mod_timer(fdctrl->result_timer, qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); break; case 0x4C: diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 74d4efccc..a2f938c7c 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -2,7 +2,7 @@ * QEMU Grackle (heathrow PPC) PCI host * * 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 @@ -95,13 +95,13 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq, pic, 0, 0); - pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, + pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, pci_grackle_config_write, s); pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, pci_grackle_write, s); cpu_register_physical_memory(base, 0x1000, pci_mem_config); cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); - d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice), + d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice), 0, NULL, NULL); d->config[0x00] = 0x57; // vendor_id d->config[0x01] = 0x10; @@ -118,12 +118,12 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) d->config[0x1a] = 0x00; // subordinate_bus d->config[0x1c] = 0x00; d->config[0x1d] = 0x00; - + d->config[0x20] = 0x00; // memory_base d->config[0x21] = 0x00; d->config[0x22] = 0x01; // memory_limit d->config[0x23] = 0x00; - + d->config[0x24] = 0x00; // prefetchable_memory_base d->config[0x25] = 0x00; d->config[0x26] = 0x00; // prefetchable_memory_limit @@ -145,12 +145,12 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) d->config[0x1a] = 0x1; // subordinate_bus d->config[0x1c] = 0x10; // io_base d->config[0x1d] = 0x20; // io_limit - + d->config[0x20] = 0x80; // memory_base d->config[0x21] = 0x80; d->config[0x22] = 0x90; // memory_limit d->config[0x23] = 0x80; - + d->config[0x24] = 0x00; // prefetchable_memory_base d->config[0x25] = 0x84; d->config[0x26] = 0x00; // prefetchable_memory_limit diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index b027ce849..26821e8c0 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -2,7 +2,7 @@ * QEMU GT64120 PCI host * * Copyright (c) 2006,2007 Aurelien Jarno - * + * * 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 @@ -287,10 +287,10 @@ static void gt64120_pci_mapping(GT64120State *s) /* Update IO mapping */ if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD]) { - /* Unmap old IO address */ + /* Unmap old IO address */ if (s->PCI0IO_length) { - cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED); + cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED); } /* Map new IO address */ s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21; @@ -604,7 +604,7 @@ static uint32_t gt64120_readl (void *opaque, case GT_CPUERR_DATAHI: case GT_CPUERR_PARITY: /* Emulated memory has no error, always return the initial - values */ + values */ val = s->regs[saddr]; break; @@ -614,7 +614,7 @@ static uint32_t gt64120_readl (void *opaque, /* Reading those register should empty all FIFO on the PCI bus, which are not emulated. The return value should be a random value that should be ignored. */ - val = 0xc000ffee; + val = 0xc000ffee; break; /* ECC */ @@ -624,7 +624,7 @@ static uint32_t gt64120_readl (void *opaque, case GT_ECC_CALC: case GT_ECC_ERRADDR: /* Emulated memory has no error, always return the initial - values */ + values */ val = s->regs[saddr]; break; @@ -663,7 +663,7 @@ static uint32_t gt64120_readl (void *opaque, val = s->regs[saddr]; break; case GT_PCI0_IACK: - /* Read the IRQ number */ + /* Read the IRQ number */ val = pic_read_irq(isa_pic); break; diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index c0edaea77..a31d24b20 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -1,8 +1,8 @@ /* * Heathrow PIC support (standard PowerMac PIC) - * + * * Copyright (c) 2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -88,7 +88,7 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) HeathrowPIC *pic; unsigned int n; uint32_t value; - + n = ((addr & 0xfff) - 0x10) >> 4; if (n >= 2) { value = 0; @@ -159,7 +159,7 @@ static void heathrow_pic_set_irq(void *opaque, int num, int level) qemu_irq *heathrow_pic_init(int *pmem_index) { HeathrowPICS *s; - + s = qemu_mallocz(sizeof(HeathrowPICS)); s->pics[0].level_triggered = 0; s->pics[1].level_triggered = 0x1ff00000; diff --git a/hw/i2c.c b/hw/i2c.c index 3fc073332..f0d117c14 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -1,4 +1,4 @@ -/* +/* * QEMU I2C bus interface. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/i8254.c b/hw/i8254.c index f0b41d75c..db8a1b97f 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -1,8 +1,8 @@ /* * QEMU 8253/8254 interval timer emulation - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -121,7 +121,7 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time) } /* return -1 if no transition will occur. */ -static int64_t pit_get_next_transition_time(PITChannelState *s, +static int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time) { uint64_t d, next_time, base; @@ -147,7 +147,7 @@ static int64_t pit_get_next_transition_time(PITChannelState *s, case 3: base = (d / s->count) * s->count; period2 = ((s->count + 1) >> 1); - if ((d - base) < period2) + if ((d - base) < period2) next_time = base + period2; else next_time = base + s->count; @@ -309,7 +309,7 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr) PITState *pit = opaque; int ret, count; PITChannelState *s; - + addr &= 3; s = &pit->channels[addr]; if (s->status_latched) { @@ -369,7 +369,7 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) qemu_set_irq(s->irq, irq_level); #ifdef DEBUG_PIT printf("irq_level=%d next_delay=%f\n", - irq_level, + irq_level, (double)(expire_time - current_time) / ticks_per_sec); #endif s->next_transition_time = expire_time; @@ -391,7 +391,7 @@ static void pit_save(QEMUFile *f, void *opaque) PITState *pit = opaque; PITChannelState *s; int i; - + for(i = 0; i < 3; i++) { s = &pit->channels[i]; qemu_put_be32s(f, &s->count); @@ -419,7 +419,7 @@ static int pit_load(QEMUFile *f, void *opaque, int version_id) PITState *pit = opaque; PITChannelState *s; int i; - + if (version_id != 1) return -EINVAL; diff --git a/hw/i8259.c b/hw/i8259.c index 506377079..09aabe223 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -1,8 +1,8 @@ /* * QEMU 8259 interrupt controller emulation - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -152,10 +152,10 @@ void pic_update_irq(PicState2 *s) { int i; for(i = 0; i < 2; i++) { - printf("pic%d: imr=%x irr=%x padd=%d\n", - i, s->pics[i].imr, s->pics[i].irr, + printf("pic%d: imr=%x irr=%x padd=%d\n", + i, s->pics[i].imr, s->pics[i].irr, s->pics[i].priority_add); - + } } printf("pic: cpu_interrupt\n"); @@ -243,10 +243,10 @@ int pic_read_irq(PicState2 *s) intno = s->pics[0].irq_base + irq; } pic_update_irq(s); - + #ifdef DEBUG_IRQ_LATENCY - printf("IRQ%d latency=%0.3fus\n", - irq, + printf("IRQ%d latency=%0.3fus\n", + irq, (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec); #endif #if defined(DEBUG_PIC) @@ -429,7 +429,7 @@ uint32_t pic_intack_read(PicState2 *s) ret = pic_poll_read(&s->pics[1], 0x80) + 8; /* Prepare for ISR read */ s->pics[0].read_reg_select = 1; - + return ret; } @@ -448,7 +448,7 @@ static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1) static void pic_save(QEMUFile *f, void *opaque) { PicState *s = opaque; - + qemu_put_8s(f, &s->last_irr); qemu_put_8s(f, &s->irr); qemu_put_8s(f, &s->imr); @@ -470,7 +470,7 @@ static void pic_save(QEMUFile *f, void *opaque) static int pic_load(QEMUFile *f, void *opaque, int version_id) { PicState *s = opaque; - + if (version_id != 1) return -EINVAL; @@ -510,15 +510,15 @@ void pic_info(void) { int i; PicState *s; - + if (!isa_pic) return; for(i=0;i<2;i++) { s = &isa_pic->pics[i]; term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", - i, s->irr, s->imr, s->isr, s->priority_add, - s->irq_base, s->read_reg_select, s->elcr, + i, s->irr, s->imr, s->isr, s->priority_add, + s->irq_base, s->read_reg_select, s->elcr, s->special_fully_nested_mode); } } diff --git a/hw/ide.c b/hw/ide.c index 4e17db3f0..c3b0e11e8 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1,9 +1,9 @@ /* * QEMU IDE disk and CD-ROM Emulator - * + * * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2006 Openedhand Ltd. - * + * * 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 @@ -156,7 +156,7 @@ #define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ #define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ #define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ -#define WIN_GETMEDIASTATUS 0xDA +#define WIN_GETMEDIASTATUS 0xDA #define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */ #define WIN_POSTBOOT 0xDC #define WIN_PREBOOT 0xDD @@ -248,12 +248,12 @@ #define GPCMD_VERIFY_10 0x2f #define GPCMD_WRITE_10 0x2a #define GPCMD_WRITE_AND_VERIFY_10 0x2e -/* This is listed as optional in ATAPI 2.6, but is (curiously) +/* This is listed as optional in ATAPI 2.6, but is (curiously) * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji * Table 377 as an MMC command for SCSi devices though... Most ATAPI * drives support it. */ #define GPCMD_SET_SPEED 0xbb -/* This seems to be a SCSI specific CD-ROM opcode +/* This seems to be a SCSI specific CD-ROM opcode * to play data at track/index */ #define GPCMD_PLAYAUDIO_TI 0x48 /* @@ -339,7 +339,7 @@ typedef struct IDEState { /* set for lba48 access */ uint8_t lba48; /* depends on bit 4 in select, only meaningful for drive 0 */ - struct IDEState *cur_drive; + struct IDEState *cur_drive; BlockDriverState *bs; /* ATAPI specific */ uint8_t sense_key; @@ -392,7 +392,7 @@ typedef struct BMDMAState { uint8_t cmd; uint8_t status; uint32_t addr; - + struct PCIIDEState *pci_dev; /* current transfer state */ uint32_t cur_addr; @@ -457,11 +457,11 @@ static void ide_identify(IDEState *s) memset(s->io_buffer, 0, 512); p = (uint16_t *)s->io_buffer; put_le16(p + 0, 0x0040); - put_le16(p + 1, s->cylinders); + put_le16(p + 1, s->cylinders); put_le16(p + 3, s->heads); put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ put_le16(p + 5, 512); /* XXX: retired, remove ? */ - put_le16(p + 6, s->sectors); + put_le16(p + 6, s->sectors); snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ put_le16(p + 20, 3); /* XXX: retired, remove ? */ @@ -469,7 +469,7 @@ static void ide_identify(IDEState *s) put_le16(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ -#if MAX_MULT_SECTORS > 1 +#if MAX_MULT_SECTORS > 1 put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); #endif put_le16(p + 48, 1); /* dword I/O */ @@ -666,7 +666,7 @@ static inline void ide_set_irq(IDEState *s) } /* prepare data transfer and tell what to do after */ -static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, +static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, EndTransferFunc *end_transfer_func) { s->end_transfer_func = end_transfer_func; @@ -771,7 +771,7 @@ static int dma_buf_rw(BMDMAState *bm, int is_write) for(;;) { l = s->io_buffer_size - s->io_buffer_index; - if (l <= 0) + if (l <= 0) break; if (bm->cur_prd_len == 0) { /* end of table (with a fail safe of one page) */ @@ -793,10 +793,10 @@ static int dma_buf_rw(BMDMAState *bm, int is_write) l = bm->cur_prd_len; if (l > 0) { if (is_write) { - cpu_physical_memory_write(bm->cur_prd_addr, + cpu_physical_memory_write(bm->cur_prd_addr, s->io_buffer + s->io_buffer_index, l); } else { - cpu_physical_memory_read(bm->cur_prd_addr, + cpu_physical_memory_read(bm->cur_prd_addr, s->io_buffer + s->io_buffer_index, l); } bm->cur_prd_addr += l; @@ -847,7 +847,7 @@ static void ide_read_dma_cb(void *opaque, int ret) #ifdef DEBUG_AIO printf("aio_read: sector_num=%lld n=%d\n", sector_num, n); #endif - bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n, + bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n, ide_read_dma_cb, bm); } @@ -923,7 +923,7 @@ static void ide_sector_write(IDEState *s) ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); } ide_set_sector(s, sector_num + n); - + bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, ide_sector_write_aio_cb, bm); } @@ -969,7 +969,7 @@ static void ide_write_dma_cb(void *opaque, int ret) #ifdef DEBUG_AIO printf("aio_write: sector_num=%lld n=%d\n", sector_num, n); #endif - bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, + bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, ide_write_dma_cb, bm); } @@ -1051,7 +1051,7 @@ static void cd_data_to_raw(uint8_t *buf, int lba) memset(buf, 0, 288); } -static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, +static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, int sector_size) { int ret; @@ -1077,10 +1077,10 @@ static void ide_atapi_io_error(IDEState *s, int ret) { /* XXX: handle more errors */ if (ret == -ENOMEDIUM) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } else { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); } } @@ -1090,7 +1090,7 @@ static void ide_atapi_cmd_reply_end(IDEState *s) { int byte_count_limit, size, ret; #ifdef DEBUG_IDE_ATAPI - printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", + printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", s->packet_transfer_size, s->elementary_transfer_size, s->io_buffer_index); @@ -1122,7 +1122,7 @@ static void ide_atapi_cmd_reply_end(IDEState *s) size = s->cd_sector_size - s->io_buffer_index; if (size > s->elementary_transfer_size) size = s->elementary_transfer_size; - ide_transfer_start(s, s->io_buffer + s->io_buffer_index, + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, size, ide_atapi_cmd_reply_end); s->packet_transfer_size -= size; s->elementary_transfer_size -= size; @@ -1151,7 +1151,7 @@ static void ide_atapi_cmd_reply_end(IDEState *s) if (size > (s->cd_sector_size - s->io_buffer_index)) size = (s->cd_sector_size - s->io_buffer_index); } - ide_transfer_start(s, s->io_buffer + s->io_buffer_index, + ide_transfer_start(s, s->io_buffer + s->io_buffer_index, size, ide_atapi_cmd_reply_end); s->packet_transfer_size -= size; s->elementary_transfer_size -= size; @@ -1246,7 +1246,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) bm->aiocb = NULL; return; } - + s->io_buffer_index = 0; if (s->cd_sector_size == 2352) { n = 1; @@ -1262,12 +1262,12 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) #ifdef DEBUG_AIO printf("aio_read_cd: lba=%u n=%d\n", s->lba, n); #endif - bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, - s->io_buffer + data_offset, n * 4, + bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, + s->io_buffer + data_offset, n * 4, ide_atapi_cmd_read_dma_cb, bm); if (!bm->aiocb) { /* Note: media not present is the most likely case */ - ide_atapi_cmd_error(s, SENSE_NOT_READY, + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); goto eot; } @@ -1289,7 +1289,7 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, ide_dma_start(s, ide_atapi_cmd_read_dma_cb); } -static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, +static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, int sector_size) { #ifdef DEBUG_IDE_ATAPI @@ -1326,7 +1326,7 @@ static void ide_atapi_cmd(IDEState *s) if (bdrv_is_inserted(s->bs)) { ide_atapi_cmd_ok(s); } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } break; @@ -1375,7 +1375,7 @@ static void ide_atapi_cmd(IDEState *s) buf[9] = 0x12; buf[10] = 0x08; buf[11] = 0x00; - + buf[12] = 0x70; buf[13] = 3 << 5; buf[14] = (1 << 0) | (1 << 3) | (1 << 5); @@ -1403,7 +1403,7 @@ static void ide_atapi_cmd(IDEState *s) goto error_cmd; default: case 3: /* saved values */ - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_SAVING_PARAMETERS_NOT_SUPPORTED); break; } @@ -1423,7 +1423,7 @@ static void ide_atapi_cmd(IDEState *s) bdrv_set_locked(s->bs, packet[4] & 1); ide_atapi_cmd_ok(s); } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); } break; @@ -1469,7 +1469,7 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_read(s, lba, nb_sectors, 2352); break; default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); break; } @@ -1483,13 +1483,13 @@ static void ide_atapi_cmd(IDEState *s) bdrv_get_geometry(s->bs, &total_sectors); total_sectors >>= 2; if (total_sectors <= 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } lba = ube32_to_cpu(packet + 2); if (lba >= total_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); break; } @@ -1501,7 +1501,7 @@ static void ide_atapi_cmd(IDEState *s) int start, eject; start = packet[4] & 1; eject = (packet[4] >> 1) & 1; - + if (eject && !start) { /* eject the disk */ bdrv_eject(s->bs, 1); @@ -1533,7 +1533,7 @@ static void ide_atapi_cmd(IDEState *s) bdrv_get_geometry(s->bs, &total_sectors); total_sectors >>= 2; if (total_sectors <= 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } @@ -1564,7 +1564,7 @@ static void ide_atapi_cmd(IDEState *s) break; default: error_cmd: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); break; } @@ -1577,7 +1577,7 @@ static void ide_atapi_cmd(IDEState *s) bdrv_get_geometry(s->bs, &total_sectors); total_sectors >>= 2; if (total_sectors <= 0) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, + ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } @@ -1670,7 +1670,7 @@ static void ide_atapi_cmd(IDEState *s) break; } default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE); break; } @@ -1838,7 +1838,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) #endif s = ide_if->cur_drive; /* ignore commands to non existant slave */ - if (s != ide_if && !s->bs) + if (s != ide_if && !s->bs) break; switch(val) { @@ -1892,7 +1892,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) lba48 = 1; case WIN_READ: case WIN_READ_ONCE: - if (!s->bs) + if (!s->bs) goto abort_cmd; ide_cmd_lba48_transform(s, lba48); s->req_nb_sectors = 1; @@ -1940,7 +1940,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) lba48 = 1; case WIN_READDMA: case WIN_READDMA_ONCE: - if (!s->bs) + if (!s->bs) goto abort_cmd; ide_cmd_lba48_transform(s, lba48); ide_sector_read_dma(s); @@ -1949,7 +1949,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) lba48 = 1; case WIN_WRITEDMA: case WIN_WRITEDMA_ONCE: - if (!s->bs) + if (!s->bs) goto abort_cmd; ide_cmd_lba48_transform(s, lba48); ide_sector_write_dma(s); @@ -2071,7 +2071,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->status = READY_STAT; s->atapi_dma = s->feature & 1; s->nsector = 1; - ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, + ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, ide_atapi_cmd); break; /* CF-ATA commands */ @@ -2330,7 +2330,7 @@ static uint32_t ide_data_readl(void *opaque, uint32_t addr) IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; int ret; - + p = s->data_ptr; ret = cpu_to_le32(*(uint32_t *)p); p += 4; @@ -2381,7 +2381,7 @@ struct partition { } __attribute__((packed)); /* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ -static int guess_disk_lchs(IDEState *s, +static int guess_disk_lchs(IDEState *s, int *pcylinders, int *pheads, int *psectors) { uint8_t buf[512]; @@ -2412,7 +2412,7 @@ static int guess_disk_lchs(IDEState *s, *psectors = sectors; *pcylinders = cylinders; #if 0 - printf("guessed geometry: LCHS=%d %d %d\n", + printf("guessed geometry: LCHS=%d %d %d\n", cylinders, heads, sectors); #endif return 0; @@ -2495,7 +2495,7 @@ static void ide_init2(IDEState *ide_state, } s->drive_serial = drive_serial++; s->irq = irq; - s->sector_write_timer = qemu_new_timer(vm_clock, + s->sector_write_timer = qemu_new_timer(vm_clock, ide_sector_write_timer_cb, s); ide_reset(s); } @@ -2509,7 +2509,7 @@ static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2) register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state); register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state); } - + /* data ports */ register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state); register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state); @@ -2584,7 +2584,7 @@ void isa_ide_init(int iobase, int iobase2, qemu_irq irq, ide_state = qemu_mallocz(sizeof(IDEState) * 2); if (!ide_state) return; - + ide_init2(ide_state, hd0, hd1, irq); ide_init_ioport(ide_state, iobase, iobase2); } @@ -2594,7 +2594,7 @@ void isa_ide_init(int iobase, int iobase2, qemu_irq irq, static void cmd646_update_irq(PCIIDEState *d); -static void ide_map(PCIDevice *pci_dev, int region_num, +static void ide_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCIIDEState *d = (PCIIDEState *)pci_dev; @@ -2671,9 +2671,9 @@ static uint32_t bmdma_readb(void *opaque, uint32_t addr) BMDMAState *bm = opaque; PCIIDEState *pci_dev; uint32_t val; - + switch(addr & 3) { - case 0: + case 0: val = bm->cmd; break; case 1: @@ -2719,7 +2719,7 @@ static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val) case 1: pci_dev = bm->pci_dev; if (pci_dev->type == IDE_TYPE_CMD646) { - pci_dev->dev.config[MRDMODE] = + pci_dev->dev.config[MRDMODE] = (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30); cmd646_update_irq(pci_dev); } @@ -2760,7 +2760,7 @@ static void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val) bm->cur_addr = bm->addr; } -static void bmdma_map(PCIDevice *pci_dev, int region_num, +static void bmdma_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCIIDEState *d = (PCIIDEState *)pci_dev; @@ -2818,9 +2818,9 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, int i; qemu_irq *irq; - d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE", + d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE", sizeof(PCIIDEState), - -1, + -1, NULL, NULL); d->type = IDE_TYPE_CMD646; pci_conf = d->dev.config; @@ -2830,30 +2830,30 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, pci_conf[0x03] = 0x06; pci_conf[0x08] = 0x07; // IDE controller revision - pci_conf[0x09] = 0x8f; + pci_conf[0x09] = 0x8f; pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage pci_conf[0x0e] = 0x00; // header_type - + if (secondary_ide_enabled) { /* XXX: if not enabled, really disable the seconday IDE controller */ pci_conf[0x51] = 0x80; /* enable IDE1 */ } - pci_register_io_region((PCIDevice *)d, 0, 0x8, + pci_register_io_region((PCIDevice *)d, 0, 0x8, PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 1, 0x4, + pci_register_io_region((PCIDevice *)d, 1, 0x4, PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 2, 0x8, + pci_register_io_region((PCIDevice *)d, 2, 0x8, PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 3, 0x4, + pci_register_io_region((PCIDevice *)d, 3, 0x4, PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 4, 0x10, + pci_register_io_region((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, bmdma_map); pci_conf[0x3d] = 0x01; // interrupt on pin 1 - + for(i = 0; i < 4; i++) d->ide_if[i].pci_dev = (PCIDevice *)d; @@ -2945,9 +2945,9 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, { PCIIDEState *d; uint8_t *pci_conf; - + /* register a function 1 of PIIX3 */ - d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", + d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", sizeof(PCIIDEState), devfn, NULL, NULL); @@ -2965,7 +2965,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, piix3_reset(d); - pci_register_io_region((PCIDevice *)d, 4, 0x10, + pci_register_io_region((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, bmdma_map); ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]); @@ -3021,7 +3021,7 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, static void pmac_ide_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) { - addr = (addr & 0xFFF) >> 4; + addr = (addr & 0xFFF) >> 4; switch (addr) { case 1 ... 7: ide_ioport_write(opaque, addr, val); @@ -3058,7 +3058,7 @@ static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr) static void pmac_ide_writew (void *opaque, target_phys_addr_t addr, uint32_t val) { - addr = (addr & 0xFFF) >> 4; + addr = (addr & 0xFFF) >> 4; #ifdef TARGET_WORDS_BIGENDIAN val = bswap16(val); #endif @@ -3071,7 +3071,7 @@ static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) { uint16_t retval; - addr = (addr & 0xFFF) >> 4; + addr = (addr & 0xFFF) >> 4; if (addr == 0) { retval = ide_data_readw(opaque, 0); } else { @@ -3086,7 +3086,7 @@ static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) static void pmac_ide_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { - addr = (addr & 0xFFF) >> 4; + addr = (addr & 0xFFF) >> 4; #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif @@ -3099,7 +3099,7 @@ static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr) { uint32_t retval; - addr = (addr & 0xFFF) >> 4; + addr = (addr & 0xFFF) >> 4; if (addr == 0) { retval = ide_data_readl(opaque, 0); } else { @@ -3133,7 +3133,7 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq) ide_if = qemu_mallocz(sizeof(IDEState) * 2); ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq); - + pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, pmac_ide_write, &ide_if[0]); return pmac_ide_memory; diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 93d980a38..83c6208cf 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -1,4 +1,4 @@ -/* +/* * ARM Integrator CP System emulation. * * Copyright (c) 2005-2007 CodeSourcery. diff --git a/hw/iommu.c b/hw/iommu.c index f87c79c67..bd52454bb 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -2,7 +2,7 @@ * QEMU SPARC iommu emulation * * Copyright (c) 2003-2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -279,7 +279,7 @@ static void iommu_save(QEMUFile *f, void *opaque) { IOMMUState *s = opaque; int i; - + for (i = 0; i < IOMMU_NREGS; i++) qemu_put_be32s(f, &s->regs[i]); qemu_put_be64s(f, &s->iostart); @@ -289,7 +289,7 @@ static int iommu_load(QEMUFile *f, void *opaque, int version_id) { IOMMUState *s = opaque; int i; - + if (version_id != 2) return -EINVAL; @@ -322,7 +322,7 @@ void *iommu_init(target_phys_addr_t addr) iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); - + register_savevm("iommu", addr, 2, iommu_save, iommu_load, s); qemu_register_reset(iommu_reset, s); return s; diff --git a/hw/irq.c b/hw/irq.c index 4bc8d80de..e46ee603c 100644 --- a/hw/irq.c +++ b/hw/irq.c @@ -1,8 +1,8 @@ /* * QEMU IRQ/GPIO common code. - * + * * Copyright (c) 2007 CodeSourcery. - * + * * 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 diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c index 070f6f587..4e7914e6b 100644 --- a/hw/isa_mmio.c +++ b/hw/isa_mmio.c @@ -2,7 +2,7 @@ * Memory mapped access to ISA IO space. * * 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 diff --git a/hw/jazz_led.c b/hw/jazz_led.c index 6f741735e..1c7c176ed 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -1,8 +1,8 @@ /* * QEMU JAZZ LED emulator. - * + * * Copyright (c) 2007 Herv Poussineau - * + * * 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 diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 19bf2a195..e9866baac 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1,4 +1,4 @@ -/* +/* * QEMU LSI53C895A SCSI Host Bus Adapter emulation * * Copyright (c) 2006 CodeSourcery. @@ -1773,7 +1773,7 @@ static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val) lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff); } -static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num, +static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { LSIState *s = (LSIState *)pci_dev; @@ -1788,7 +1788,7 @@ static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 256, 4, lsi_io_readl, s); } -static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num, +static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { LSIState *s = (LSIState *)pci_dev; @@ -1798,7 +1798,7 @@ static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr); } -static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num, +static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { LSIState *s = (LSIState *)pci_dev; diff --git a/hw/m48t59.c b/hw/m48t59.c index 053acb5c0..e097a7cb1 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -1,8 +1,8 @@ /* * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms - * + * * Copyright (c) 2003-2005, 2007 Jocelyn Mayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -90,7 +90,7 @@ static void get_time (m48t59_t *NVRAM, struct tm *tm) static void set_time (m48t59_t *NVRAM, struct tm *tm) { time_t now, new_time; - + new_time = mktime(tm); now = time(NULL); NVRAM->time_offset = new_time - now; @@ -104,7 +104,7 @@ static void alarm_cb (void *opaque) m48t59_t *NVRAM = opaque; qemu_set_irq(NVRAM->IRQ, 1); - if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && + if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && (NVRAM->buffer[0x1FF4] & 0x80) == 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 && (NVRAM->buffer[0x1FF2] & 0x80) == 0) { @@ -208,7 +208,7 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) if (addr > 0x1FF8 && addr < 0x2000) NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); - if (NVRAM->type == 8 && + if (NVRAM->type == 8 && (addr >= 0x1ff0 && addr <= 0x1ff7)) goto do_write; switch (addr) { @@ -364,7 +364,7 @@ uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) struct tm tm; uint32_t retval = 0xFF; - if (NVRAM->type == 8 && + if (NVRAM->type == 8 && (addr >= 0x1ff0 && addr <= 0x1ff7)) goto do_read; switch (addr) { @@ -430,7 +430,7 @@ uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) case 0x1FFF: /* year */ get_time(NVRAM, &tm); - if (NVRAM->type == 8) + if (NVRAM->type == 8) retval = toBCD(tm.tm_year - 68); // Base year is 1968 else retval = toBCD(tm.tm_year); @@ -510,7 +510,7 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t59_t *NVRAM = opaque; - + addr -= NVRAM->mem_base; m48t59_write(NVRAM, addr, value & 0xff); } @@ -518,7 +518,7 @@ static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t59_t *NVRAM = opaque; - + addr -= NVRAM->mem_base; m48t59_write(NVRAM, addr, (value >> 8) & 0xff); m48t59_write(NVRAM, addr + 1, value & 0xff); @@ -527,7 +527,7 @@ static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t59_t *NVRAM = opaque; - + addr -= NVRAM->mem_base; m48t59_write(NVRAM, addr, (value >> 24) & 0xff); m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff); @@ -539,7 +539,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) { m48t59_t *NVRAM = opaque; uint32_t retval; - + addr -= NVRAM->mem_base; retval = m48t59_read(NVRAM, addr); return retval; @@ -549,7 +549,7 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) { m48t59_t *NVRAM = opaque; uint32_t retval; - + addr -= NVRAM->mem_base; retval = m48t59_read(NVRAM, addr) << 8; retval |= m48t59_read(NVRAM, addr + 1); diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index e30791f8a..8d0da95d8 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -1,8 +1,8 @@ /* * QEMU MC146818 RTC emulation - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -75,7 +75,7 @@ static void rtc_timer_update(RTCState *s, int64_t current_time) int64_t cur_clock, next_irq_clock; period_code = s->cmos_data[RTC_REG_A] & 0x0f; - if (period_code != 0 && + if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { if (period_code <= 2) period_code += 7; @@ -110,7 +110,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) #ifdef DEBUG_CMOS printf("cmos: write index=0x%02x val=0x%02x\n", s->cmos_index, data); -#endif +#endif switch(s->cmos_index) { case RTC_SECONDS_ALARM: case RTC_MINUTES_ALARM: @@ -221,8 +221,8 @@ static void rtc_copy_date(RTCState *s) /* month is between 0 and 11. */ static int get_days_in_month(int month, int year) { - static const int days_tab[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + static const int days_tab[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int d; if ((unsigned )month >= 12) @@ -253,7 +253,7 @@ static void rtc_next_second(struct tm *tm) tm->tm_wday++; if ((unsigned)tm->tm_wday >= 7) tm->tm_wday = 0; - days_in_month = get_days_in_month(tm->tm_mon, + days_in_month = get_days_in_month(tm->tm_mon, tm->tm_year + 1900); tm->tm_mday++; if (tm->tm_mday < 1) { @@ -283,7 +283,7 @@ static void rtc_update_second(void *opaque) qemu_mod_timer(s->second_timer, s->next_second_time); } else { rtc_next_second(&s->current_tm); - + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { /* update in progress bit */ s->cmos_data[RTC_REG_A] |= REG_A_UIP; @@ -293,7 +293,7 @@ static void rtc_update_second(void *opaque) delay = (ticks_per_sec * 1) / 100; if (delay < 1) delay = 1; - qemu_mod_timer(s->second_timer2, + qemu_mod_timer(s->second_timer2, s->next_second_time + delay); } } @@ -315,14 +315,14 @@ static void rtc_update_second2(void *opaque) ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) { - s->cmos_data[RTC_REG_C] |= 0xa0; + s->cmos_data[RTC_REG_C] |= 0xa0; qemu_irq_raise(s->irq); } } /* update ended interrupt */ if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { - s->cmos_data[RTC_REG_C] |= 0x90; + s->cmos_data[RTC_REG_C] |= 0x90; qemu_irq_raise(s->irq); } @@ -356,7 +356,7 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; qemu_irq_lower(s->irq); - s->cmos_data[RTC_REG_C] = 0x00; + s->cmos_data[RTC_REG_C] = 0x00; break; default: ret = s->cmos_data[s->cmos_index]; @@ -411,7 +411,7 @@ static void rtc_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, s->cmos_data, 128); qemu_put_8s(f, &s->cmos_index); - + qemu_put_be32s(f, &s->current_tm.tm_sec); qemu_put_be32s(f, &s->current_tm.tm_min); qemu_put_be32s(f, &s->current_tm.tm_hour); @@ -471,11 +471,11 @@ RTCState *rtc_init(int base, qemu_irq irq) rtc_set_date_from_host(s); - s->periodic_timer = qemu_new_timer(vm_clock, + s->periodic_timer = qemu_new_timer(vm_clock, rtc_periodic_timer, s); - s->second_timer = qemu_new_timer(vm_clock, + s->second_timer = qemu_new_timer(vm_clock, rtc_update_second, s); - s->second_timer2 = qemu_new_timer(vm_clock, + s->second_timer2 = qemu_new_timer(vm_clock, rtc_update_second2, s); s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100; diff --git a/hw/mcf5206.c b/hw/mcf5206.c index ce4676bdf..32117ae52 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -1,4 +1,4 @@ -/* +/* * Motorola ColdFire MCF5206 SoC embedded peripheral emulation. * * Copyright (c) 2007 CodeSourcery. @@ -58,7 +58,7 @@ static void m5206_timer_recalibrate(m5206_timer_state *s) prescale *= 16; if (mode == 3 || mode == 0) - cpu_abort(cpu_single_env, + cpu_abort(cpu_single_env, "m5206_timer: mode %d not implemented\n", mode); if ((s->tmr & TMR_FRR) == 0) cpu_abort(cpu_single_env, @@ -354,7 +354,7 @@ static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, /* Internal peripherals use a variety of register widths. This lookup table allows a single routine to handle all of them. */ -static const int m5206_mbar_width[] = +static const int m5206_mbar_width[] = { /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 8068f7861..993a68694 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -1,4 +1,4 @@ -/* +/* * Motorola ColdFire MCF5208 SoC emulation. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index d4613dda2..a21810806 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -1,4 +1,4 @@ -/* +/* * ColdFire Fast Ethernet Controller emulation. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index 5bdebf8bb..e469c3119 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -1,4 +1,4 @@ -/* +/* * ColdFire Interrupt Controller emulation. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c index fcdfc4453..ab0f54f4d 100644 --- a/hw/mcf_uart.c +++ b/hw/mcf_uart.c @@ -1,4 +1,4 @@ -/* +/* * ColdFire UART emulation. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/mips_malta.c b/hw/mips_malta.c index ed23052b9..ab4d3fdd4 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -510,9 +510,9 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x00000000); /* nop */ /* YAMON service vector */ - stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */ + stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */ stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c); /* print_count: */ - stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */ + stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */ stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800); /* flush_cache: */ stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808); /* print: */ stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800); /* reg_cpu_isr: */ diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 82782273b..5769ade96 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -221,7 +221,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, } } - isa_vga_init(ds, phys_ram_base + ram_size, ram_size, + isa_vga_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size); if (nd_table[0].vlan) { diff --git a/hw/nand.c b/hw/nand.c index 8e39acd6e..118d04ea3 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -323,7 +323,7 @@ static int nand_iid = 0; * * CE, WP and R/B are active low. */ -void nand_setpins(struct nand_flash_s *s, +void nand_setpins(struct nand_flash_s *s, int cle, int ale, int ce, int wp, int gnd) { s->cle = cle; @@ -416,7 +416,7 @@ void nand_setio(struct nand_flash_s *s, uint8_t value) uint8_t nand_getio(struct nand_flash_s *s) { int offset; - + /* Allow sequential reading */ if (!s->iolen && s->cmd == NAND_CMD_READ0) { offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset; diff --git a/hw/ne2000.c b/hw/ne2000.c index 6d5aa56e1..a5e033126 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -1,8 +1,8 @@ /* * QEMU NE2000 emulation - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -212,7 +212,7 @@ static int ne2000_buffer_full(NE2000State *s) static int ne2000_can_receive(void *opaque) { NE2000State *s = opaque; - + if (s->cmd & E8390_STOP) return 1; return !ne2000_buffer_full(s); @@ -226,16 +226,16 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) uint8_t *p; unsigned int total_len, next, avail, len, index, mcast_idx; uint8_t buf1[60]; - static const uint8_t broadcast_macaddr[6] = + static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - + #if defined(DEBUG_NE2000) printf("NE2000: received len=%d\n", size); #endif if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) return; - + /* XXX: check this */ if (s->rxcr & 0x10) { /* promiscuous: receive all */ @@ -252,10 +252,10 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) return; } else if (s->mem[0] == buf[0] && - s->mem[2] == buf[1] && - s->mem[4] == buf[2] && - s->mem[6] == buf[3] && - s->mem[8] == buf[4] && + s->mem[2] == buf[1] && + s->mem[4] == buf[2] && + s->mem[6] == buf[3] && + s->mem[8] == buf[4] && s->mem[10] == buf[5]) { /* match */ } else { @@ -336,7 +336,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) } if (val & E8390_TRANS) { index = (s->tpsr << 8); - /* XXX: next 2 lines are a hack to make netware 3.11 work */ + /* XXX: next 2 lines are a hack to make netware 3.11 work */ if (index >= NE2000_PMEM_END) index -= NE2000_PMEM_SIZE; /* fail safe: check range on the transmitted length */ @@ -346,7 +346,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) /* signal end of transfer */ s->tsr = ENTSR_PTX; s->isr |= ENISR_TX; - s->cmd &= ~E8390_TRANS; + s->cmd &= ~E8390_TRANS; ne2000_update_irq(s); } } @@ -482,30 +482,30 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) return ret; } -static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, +static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, uint32_t val) { - if (addr < 32 || + if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { s->mem[addr] = val; } } -static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, +static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, uint32_t val) { addr &= ~1; /* XXX: check exact behaviour if not even */ - if (addr < 32 || + if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { *(uint16_t *)(s->mem + addr) = cpu_to_le16(val); } } -static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, +static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, uint32_t val) { addr &= ~1; /* XXX: check exact behaviour if not even */ - if (addr < 32 || + if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { cpu_to_le32wu((uint32_t *)(s->mem + addr), val); } @@ -513,7 +513,7 @@ static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr) { - if (addr < 32 || + if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { return s->mem[addr]; } else { @@ -524,7 +524,7 @@ static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr) static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr) { addr &= ~1; /* XXX: check exact behaviour if not even */ - if (addr < 32 || + if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { return le16_to_cpu(*(uint16_t *)(s->mem + addr)); } else { @@ -535,7 +535,7 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr) static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr) { addr &= ~1; /* XXX: check exact behaviour if not even */ - if (addr < 32 || + if (addr < 32 || (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { return le32_to_cpupu((uint32_t *)(s->mem + addr)); } else { @@ -718,11 +718,11 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) { NE2000State *s; - + s = qemu_mallocz(sizeof(NE2000State)); if (!s) return; - + register_ioport_write(base, 16, 1, ne2000_ioport_write, s); register_ioport_read(base, 16, 1, ne2000_ioport_read, s); @@ -749,7 +749,7 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) s->macaddr[3], s->macaddr[4], s->macaddr[5]); - + register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); } @@ -761,7 +761,7 @@ typedef struct PCINE2000State { NE2000State ne2000; } PCINE2000State; -static void ne2000_map(PCIDevice *pci_dev, int region_num, +static void ne2000_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCINE2000State *d = (PCINE2000State *)pci_dev; @@ -786,22 +786,22 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) PCINE2000State *d; NE2000State *s; uint8_t *pci_conf; - + d = (PCINE2000State *)pci_register_device(bus, "NE2000", sizeof(PCINE2000State), - devfn, + devfn, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0xec; // Realtek 8029 pci_conf[0x01] = 0x10; pci_conf[0x02] = 0x29; pci_conf[0x03] = 0x80; - pci_conf[0x0a] = 0x00; // ethernet network controller + pci_conf[0x0a] = 0x00; // ethernet network controller pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 1; // interrupt pin 0 - - pci_register_io_region(&d->dev, 0, 0x100, + + pci_register_io_region(&d->dev, 0, 0x100, PCI_ADDRESS_SPACE_IO, ne2000_map); s = &d->ne2000; s->irq = d->dev.irq[0]; @@ -819,7 +819,7 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) s->macaddr[3], s->macaddr[4], s->macaddr[5]); - + /* XXX: instance number ? */ register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s); } diff --git a/hw/omap.h b/hw/omap.h index 16e764ba0..96cd3affd 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -483,7 +483,7 @@ struct omap_mpu_state_s { qemu_irq wakeup; struct omap_dma_port_if_s { - uint32_t (*read[3])(struct omap_mpu_state_s *s, + uint32_t (*read[3])(struct omap_mpu_state_s *s, target_phys_addr_t offset); void (*write[3])(struct omap_mpu_state_s *s, target_phys_addr_t offset, uint32_t value); diff --git a/hw/omap_lcd_template.h b/hw/omap_lcd_template.h index cdfa5620f..4e84fa1d9 100644 --- a/hw/omap_lcd_template.h +++ b/hw/omap_lcd_template.h @@ -29,18 +29,18 @@ #if DEPTH == 8 # define BPP 1 -# define PIXEL_TYPE uint8_t +# define PIXEL_TYPE uint8_t #elif DEPTH == 15 || DEPTH == 16 # define BPP 2 -# define PIXEL_TYPE uint16_t +# define PIXEL_TYPE uint16_t #elif DEPTH == 32 # define BPP 4 -# define PIXEL_TYPE uint32_t +# define PIXEL_TYPE uint32_t #else # error unsupport depth #endif -/* +/* * 2-bit colour */ static void glue(draw_line2_, DEPTH)( @@ -78,7 +78,7 @@ static void glue(draw_line2_, DEPTH)( } while (width > 0); } -/* +/* * 4-bit colour */ static void glue(draw_line4_, DEPTH)( @@ -104,7 +104,7 @@ static void glue(draw_line4_, DEPTH)( } while (width > 0); } -/* +/* * 8-bit colour */ static void glue(draw_line8_, DEPTH)( @@ -123,7 +123,7 @@ static void glue(draw_line8_, DEPTH)( } while (-- width != 0); } -/* +/* * 12-bit colour */ static void glue(draw_line12_, DEPTH)( @@ -143,7 +143,7 @@ static void glue(draw_line12_, DEPTH)( } while (-- width != 0); } -/* +/* * 16-bit colour */ static void glue(draw_line16_, DEPTH)( diff --git a/hw/openpic.c b/hw/openpic.c index d52eb751e..bd5282870 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -1,8 +1,8 @@ /* * OpenPIC emulation - * + * * Copyright (c) 2004 Jocelyn Mayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -30,7 +30,7 @@ * - Motorola Harrier programmer manuel * * Serial interrupts, as implemented in Raven chipset are not supported yet. - * + * */ #include "vl.h" @@ -224,7 +224,7 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) priority = -1; for (i = 0; i < MAX_IRQ; i++) { if (IRQ_testbit(q, i)) { - DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", + DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", i, IPVP_PRIORITY(opp->src[i].ipvp), priority); if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { next = i; @@ -350,7 +350,7 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) IRQ_src_t *src; src = &opp->src[n_IRQ]; - DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", + DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", n_IRQ, level, src->ipvp); if (test_bit(&src->ipvp, IPVP_SENSE)) { /* level-sensitive irq */ @@ -438,11 +438,11 @@ static inline void write_IRQreg (openpic_t *opp, int n_IRQ, /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ipvp = + opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000) | (val & 0x800F00FF); openpic_update_irq(opp, n_IRQ); - DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", + DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, opp->src[n_IRQ].ipvp); break; case IRQ_IDE: @@ -475,7 +475,7 @@ static uint32_t read_doorbell_register (openpic_t *opp, return retval; } - + static void write_doorbell_register (penpic_t *opp, int n_dbl, uint32_t offset, uint32_t value) { @@ -831,7 +831,7 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) IRQ_dst_t *dst; uint32_t retval; int idx, n_IRQ; - + DPRINTF("%s: addr %08x\n", __func__, addr); retval = 0xFFFFFFFF; if (addr & 0xF) @@ -971,7 +971,7 @@ static CPUReadMemoryFunc *openpic_read[] = { &openpic_readl, }; -static void openpic_map(PCIDevice *pci_dev, int region_num, +static void openpic_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { openpic_t *opp; @@ -1005,7 +1005,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, openpic_t *opp; uint8_t *pci_conf; int i, m; - + /* XXX: for now, only one CPU is supported */ if (nb_cpus != 1) return NULL; @@ -1023,7 +1023,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, pci_conf[0x0b] = 0x08; pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 0x00; // no interrupt pin - + /* Register I/O spaces */ pci_register_io_region((PCIDevice *)opp, 0, 0x40000, PCI_ADDRESS_SPACE_MEM, &openpic_map); @@ -1032,7 +1032,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, } opp->mem_index = cpu_register_io_memory(0, openpic_read, openpic_write, opp); - + // isu_base &= 0xFFFC0000; opp->nb_cpus = nb_cpus; /* Set IRQ types */ diff --git a/hw/parallel.c b/hw/parallel.c index f05daf3c3..9558c3f17 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -1,9 +1,9 @@ /* * QEMU Parallel PORT emulation - * + * * Copyright (c) 2003-2005 Fabrice Bellard * Copyright (c) 2007 Marko Kohtala - * + * * 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 @@ -88,7 +88,7 @@ static void parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val) { ParallelState *s = opaque; - + pdebug("write addr=0x%02x val=0x%02x\n", addr, val); addr &= 7; diff --git a/hw/pc.c b/hw/pc.c index 7d86f32d5..a4ce37e36 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1,8 +1,8 @@ /* * QEMU PC System Emulator - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -65,7 +65,7 @@ uint64_t cpu_get_tsc(CPUX86State *env) #if USE_KQEMU if (env->kqemu_enabled) { return cpu_get_real_ticks(); - } else + } else #endif { return cpu_get_ticks(); @@ -89,7 +89,7 @@ int cpu_get_pic_interrupt(CPUState *env) if (intno >= 0) { /* set irq request if a PIC irq is still pending */ /* XXX: improve that */ - pic_update_irq(isa_pic); + pic_update_irq(isa_pic); return intno; } /* read the irq from the PIC */ @@ -134,7 +134,7 @@ static int cmos_get_fd_drive_type(int fd0) return val; } -static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) +static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) { RTCState *s = rtc_state; int cylinders, heads, sectors; @@ -182,7 +182,7 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table val = 65535; rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); - + switch(boot_device) { case 'a': case 'b': @@ -199,7 +199,7 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table break; case 'n': rtc_set_memory(s, 0x3d, 0x04); /* Network boot */ - break; + break; } /* floppy type */ @@ -209,7 +209,7 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1); rtc_set_memory(s, 0x10, val); - + val = 0; nb = 0; if (fd0 < 3) @@ -235,7 +235,7 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0)); if (hd_table[0]) cmos_init_hd(0x19, 0x1b, hd_table[0]); - if (hd_table[1]) + if (hd_table[1]) cmos_init_hd(0x1a, 0x24, hd_table[1]); val = 0; @@ -294,7 +294,7 @@ void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) { static const char shutdown_str[8] = "Shutdown"; static int shutdown_index = 0; - + switch(addr) { /* Bochs BIOS messages */ case 0x400: @@ -404,7 +404,7 @@ static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); } -int load_kernel(const char *filename, uint8_t *addr, +int load_kernel(const char *filename, uint8_t *addr, uint8_t *real_addr) { int fd, size; @@ -420,7 +420,7 @@ int load_kernel(const char *filename, uint8_t *addr, setup_sects = real_addr[0x1F1]; if (!setup_sects) setup_sects = 4; - if (read(fd, real_addr + 512, setup_sects * 512) != + if (read(fd, real_addr + 512, setup_sects * 512) != setup_sects * 512) goto fail; @@ -708,7 +708,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, /* BIOS load */ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); bios_size = get_image_size(buf); - if (bios_size <= 0 || + if (bios_size <= 0 || (bios_size % 65536) != 0) { goto bios_error; } @@ -727,7 +727,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); } vga_bios_size = get_image_size(buf); - if (vga_bios_size <= 0 || vga_bios_size > 65536) + if (vga_bios_size <= 0 || vga_bios_size > 65536) goto vga_bios_error; vga_bios_offset = qemu_ram_alloc(65536); @@ -739,17 +739,17 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } /* setup basic memory access */ - cpu_register_physical_memory(0xc0000, 0x10000, + cpu_register_physical_memory(0xc0000, 0x10000, vga_bios_offset | IO_MEM_ROM); /* map the last 128KB of the BIOS in ISA space */ isa_bios_size = bios_size; if (isa_bios_size > (128 * 1024)) isa_bios_size = 128 * 1024; - cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, + cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, IO_MEM_UNASSIGNED); - cpu_register_physical_memory(0x100000 - isa_bios_size, - isa_bios_size, + cpu_register_physical_memory(0x100000 - isa_bios_size, + isa_bios_size, (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); { @@ -760,7 +760,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, for (i = 0; i < nb_option_roms; i++) { size = get_image_size(option_rom[i]); if (size < 0) { - fprintf(stderr, "Could not load option rom '%s'\n", + fprintf(stderr, "Could not load option rom '%s'\n", option_rom[i]); exit(1); } @@ -781,9 +781,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } /* map all the bios at the top of memory */ - cpu_register_physical_memory((uint32_t)(-bios_size), + cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); - + bochs_bios_init(); if (linux_boot) @@ -807,11 +807,11 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (cirrus_vga_enabled) { if (pci_enabled) { - pci_cirrus_vga_init(pci_bus, - ds, phys_ram_base + vga_ram_addr, + pci_cirrus_vga_init(pci_bus, + ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); } else { - isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr, + isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); } } else if (vmsvga_enabled) { @@ -822,10 +822,10 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); } else { if (pci_enabled) { - pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, + pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size, 0, 0); } else { - isa_vga_init(ds, phys_ram_base + vga_ram_addr, + isa_vga_init(ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); } } @@ -914,7 +914,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); } } - + if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); } @@ -938,9 +938,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -952,9 +952,9 @@ static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, } static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/pci.c b/hw/pci.c index c7ea31469..55cdaa499 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -2,7 +2,7 @@ * QEMU PCI bus manager * * 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 @@ -96,16 +96,16 @@ int pci_device_load(PCIDevice *s, QEMUFile *f) } /* -1 for devfn means auto assign */ -PCIDevice *pci_register_device(PCIBus *bus, const char *name, +PCIDevice *pci_register_device(PCIBus *bus, const char *name, int instance_size, int devfn, - PCIConfigReadFunc *config_read, + PCIConfigReadFunc *config_read, PCIConfigWriteFunc *config_write) { PCIDevice *pci_dev; if (pci_irq_index >= PCI_DEVICES_MAX) return NULL; - + if (devfn < 0) { for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { if (!bus->devices[devfn]) @@ -134,8 +134,8 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, return pci_dev; } -void pci_register_io_region(PCIDevice *pci_dev, int region_num, - uint32_t size, int type, +void pci_register_io_region(PCIDevice *pci_dev, int region_num, + uint32_t size, int type, PCIMapIORegionFunc *map_func) { PCIIORegion *r; @@ -166,7 +166,7 @@ static void pci_update_mappings(PCIDevice *d) PCIIORegion *r; int cmd, i; uint32_t last_addr, new_addr, config_ofs; - + cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND)); for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; @@ -178,7 +178,7 @@ static void pci_update_mappings(PCIDevice *d) if (r->size != 0) { if (r->type & PCI_ADDRESS_SPACE_IO) { if (cmd & PCI_COMMAND_IO) { - new_addr = le32_to_cpu(*(uint32_t *)(d->config + + new_addr = le32_to_cpu(*(uint32_t *)(d->config + config_ofs)); new_addr = new_addr & ~(r->size - 1); last_addr = new_addr + r->size - 1; @@ -192,7 +192,7 @@ static void pci_update_mappings(PCIDevice *d) } } else { if (cmd & PCI_COMMAND_MEMORY) { - new_addr = le32_to_cpu(*(uint32_t *)(d->config + + new_addr = le32_to_cpu(*(uint32_t *)(d->config + config_ofs)); /* the ROM slot has a specific enable bit */ if (i == PCI_ROM_SLOT && !(new_addr & 1)) @@ -227,7 +227,7 @@ static void pci_update_mappings(PCIDevice *d) } } else { cpu_register_physical_memory(pci_to_cpu_addr(r->addr), - r->size, + r->size, IO_MEM_UNASSIGNED); } } @@ -240,7 +240,7 @@ static void pci_update_mappings(PCIDevice *d) } } -uint32_t pci_default_read_config(PCIDevice *d, +uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len) { uint32_t val; @@ -266,13 +266,13 @@ uint32_t pci_default_read_config(PCIDevice *d, return val; } -void pci_default_write_config(PCIDevice *d, +void pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { int can_write, i; uint32_t end, addr; - if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || + if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || (address >= 0x30 && address < 0x34))) { PCIIORegion *r; int reg; @@ -367,7 +367,7 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) PCIBus *s = opaque; PCIDevice *pci_dev; int config_addr, bus_num; - + #if defined(DEBUG_PCI) && 0 printf("pci_data_write: addr=%08x val=%08x len=%d\n", addr, val, len); @@ -440,7 +440,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level) PCIDevice *pci_dev = (PCIDevice *)opaque; PCIBus *bus; int change; - + change = level - pci_dev->irq_state[irq_num]; if (!change) return; @@ -465,7 +465,7 @@ typedef struct { const char *desc; } pci_class_desc; -static pci_class_desc pci_class_descriptions[] = +static pci_class_desc pci_class_descriptions[] = { { 0x0100, "SCSI controller"}, { 0x0101, "IDE controller"}, @@ -538,10 +538,10 @@ static void pci_info_device(PCIDevice *d) if (r->size != 0) { term_printf(" BAR%d: ", i); if (r->type & PCI_ADDRESS_SPACE_IO) { - term_printf("I/O at 0x%04x [0x%04x].\n", + term_printf("I/O at 0x%04x [0x%04x].\n", r->addr, r->addr + r->size - 1); } else { - term_printf("32 bit memory at 0x%08x [0x%08x].\n", + term_printf("32 bit memory at 0x%08x [0x%08x].\n", r->addr, r->addr + r->size - 1); } } @@ -556,7 +556,7 @@ void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d)) PCIBus *bus = first_bus; PCIDevice *d; int devfn; - + while (bus && bus->bus_num != bus_num) bus = bus->next; if (bus) { @@ -603,7 +603,7 @@ typedef struct { PCIBus *bus; } PCIBridge; -void pci_bridge_write_config(PCIDevice *d, +void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { PCIBridge *s = (PCIBridge *)d; @@ -624,7 +624,7 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, pci_map_irq_fn map_irq, const char *name) { PCIBridge *s; - s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge), + s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge), devfn, NULL, pci_bridge_write_config); s->dev.config[0x00] = id >> 16; s->dev.config[0x01] = id >> 24; diff --git a/hw/pci_host.h b/hw/pci_host.h index 708dae25e..49a0c59d5 100644 --- a/hw/pci_host.h +++ b/hw/pci_host.h @@ -2,7 +2,7 @@ * QEMU Common PCI Host bridge configuration data space access routines. * * 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 diff --git a/hw/pckbd.c b/hw/pckbd.c index 8f2466d80..9b036a676 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -1,8 +1,8 @@ /* * QEMU PC keyboard emulation - * + * * Copyright (c) 2003 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -148,7 +148,7 @@ static void kbd_update_irq(KBDState *s) if (s->mode & KBD_MODE_MOUSE_INT) irq_mouse_level = 1; } else { - if ((s->mode & KBD_MODE_KBD_INT) && + if ((s->mode & KBD_MODE_KBD_INT) && !(s->mode & KBD_MODE_DISABLE_KBD)) irq_kbd_level = 1; } @@ -338,7 +338,7 @@ static void kbd_reset(void *opaque) static void kbd_save(QEMUFile* f, void* opaque) { KBDState *s = (KBDState*)opaque; - + qemu_put_8s(f, &s->write_cmd); qemu_put_8s(f, &s->status); qemu_put_8s(f, &s->mode); @@ -348,7 +348,7 @@ static void kbd_save(QEMUFile* f, void* opaque) static int kbd_load(QEMUFile* f, void* opaque, int version_id) { KBDState *s = (KBDState*)opaque; - + if (version_id != 3) return -EINVAL; qemu_get_8s(f, &s->write_cmd); diff --git a/hw/pcnet.c b/hw/pcnet.c index ed263edea..11e8fe997 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1,8 +1,8 @@ /* * QEMU AMD PC-Net II (Am79C970A) emulation - * + * * Copyright (c) 2004 Antony T Curtis - * + * * 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 @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - + /* This software was written to be compatible with the specification: * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 */ - + /* * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also * produced as NCR89C100. See @@ -652,10 +652,10 @@ static const uint32_t crctab[256] = { static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) { struct qemu_ether_header *hdr = (void *)buf; - uint8_t padr[6] = { + uint8_t padr[6] = { s->csr[12] & 0xff, s->csr[12] >> 8, s->csr[13] & 0xff, s->csr[13] >> 8, - s->csr[14] & 0xff, s->csr[14] >> 8 + s->csr[14] & 0xff, s->csr[14] >> 8 }; int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6); #ifdef PCNET_DEBUG_MATCH @@ -683,13 +683,13 @@ static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) { struct qemu_ether_header *hdr = (void *)buf; - if ((*(hdr->ether_dhost)&0x01) && + if ((*(hdr->ether_dhost)&0x01) && ((uint64_t *)&s->csr[8])[0] != 0LL) { - uint8_t ladr[8] = { + uint8_t ladr[8] = { s->csr[8] & 0xff, s->csr[8] >> 8, s->csr[9] & 0xff, s->csr[9] >> 8, - s->csr[10] & 0xff, s->csr[10] >> 8, - s->csr[11] & 0xff, s->csr[11] >> 8 + s->csr[10] & 0xff, s->csr[10] >> 8, + s->csr[11] & 0xff, s->csr[11] >> 8 }; int index = lnc_mchash(hdr->ether_dhost) >> 26; return !!(ladr[index >> 3] & (1 << (index & 7))); @@ -697,7 +697,7 @@ static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) return 0; } -static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) +static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) { while (idx < 1) idx += CSR_RCVRL(s); return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8)); @@ -705,8 +705,8 @@ static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time) { - int64_t next_time = current_time + - muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), + int64_t next_time = current_time + + muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), ticks_per_sec, 33000000L); if (next_time <= current_time) next_time = current_time + 1; @@ -731,7 +731,7 @@ static void pcnet_s_reset(PCNetState *s) s->rdra = 0; s->tdra = 0; s->rap = 0; - + s->bcr[BCR_BSBC] &= ~0x0080; s->csr[0] = 0x0004; @@ -770,7 +770,7 @@ static void pcnet_update_irq(PCNetState *s) { int isr = 0; s->csr[0] &= ~0x0080; - + #if 1 if (((s->csr[0] & ~s->csr[3]) & 0x5f00) || (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) || @@ -790,11 +790,11 @@ static void pcnet_update_irq(PCNetState *s) (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */) #endif { - + isr = CSR_INEA(s); s->csr[0] |= 0x0080; } - + if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */ s->csr[4] &= ~0x0080; s->csr[4] |= 0x0040; @@ -806,7 +806,7 @@ static void pcnet_update_irq(PCNetState *s) } #if 1 - if (((s->csr[5]>>1) & s->csr[5]) & 0x0500) + if (((s->csr[5]>>1) & s->csr[5]) & 0x0500) #else if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ || (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ ) @@ -834,7 +834,7 @@ static void pcnet_init(PCNetState *s) #ifdef PCNET_DEBUG printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); #endif - + if (BCR_SSIZE32(s)) { struct pcnet_initblk32 initblk; s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), @@ -893,12 +893,12 @@ static void pcnet_init(PCNetState *s) CSR_XMTRC(s) = CSR_XMTRL(s); #ifdef PCNET_DEBUG - printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", + printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", BCR_SSIZE32(s), s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s)); #endif - s->csr[0] |= 0x0101; + s->csr[0] |= 0x0101; s->csr[0] &= ~0x0004; /* clear STOP bit */ } @@ -910,7 +910,7 @@ static void pcnet_start(PCNetState *s) if (!CSR_DTX(s)) s->csr[0] |= 0x0010; /* set TXON */ - + if (!CSR_DRX(s)) s->csr[0] |= 0x0020; /* set RXON */ @@ -940,15 +940,15 @@ static void pcnet_rdte_poll(PCNetState *s) target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); #else - target_phys_addr_t crda = s->rdra + + target_phys_addr_t crda = s->rdra + (CSR_RCVRL(s) - CSR_RCVRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8 ); int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; - target_phys_addr_t nrda = s->rdra + + target_phys_addr_t nrda = s->rdra + (CSR_RCVRL(s) - nrdc) * (BCR_SWSTYLE(s) ? 16 : 8 ); int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; - target_phys_addr_t nnrd = s->rdra + + target_phys_addr_t nnrd = s->rdra + (CSR_RCVRL(s) - nnrc) * (BCR_SWSTYLE(s) ? 16 : 8 ); #endif @@ -976,7 +976,7 @@ static void pcnet_rdte_poll(PCNetState *s) #endif } } - + if (CSR_CRDA(s)) { struct pcnet_RMD rmd; RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); @@ -991,7 +991,7 @@ static void pcnet_rdte_poll(PCNetState *s) } else { CSR_CRBC(s) = CSR_CRST(s) = 0; } - + if (CSR_NRDA(s)) { struct pcnet_RMD rmd; RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); @@ -1007,7 +1007,7 @@ static int pcnet_tdte_poll(PCNetState *s) { s->csr[34] = s->csr[35] = 0; if (s->tdra) { - target_phys_addr_t cxda = s->tdra + + target_phys_addr_t cxda = s->tdra + (CSR_XMTRL(s) - CSR_XMTRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8); int bad = 0; @@ -1030,14 +1030,14 @@ static int pcnet_tdte_poll(PCNetState *s) if (CSR_CXDA(s)) { struct pcnet_TMD tmd; - TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT); CSR_CXST(s) = tmd.status; } else { CSR_CXBC(s) = CSR_CXST(s) = 0; } - + return !!(CSR_CXST(s) & 0x8000); } @@ -1046,7 +1046,7 @@ static int pcnet_can_receive(void *opaque) PCNetState *s = opaque; if (CSR_STOP(s) || CSR_SPND(s)) return 0; - + if (s->recv_pos > 0) return 0; @@ -1076,8 +1076,8 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) size = MIN_BUF_SIZE; } - if (CSR_PROM(s) - || (is_padr=padr_match(s, buf, size)) + if (CSR_PROM(s) + || (is_padr=padr_match(s, buf, size)) || (is_bcast=padr_bcast(s, buf, size)) || (is_ladr=ladr_match(s, buf, size))) { @@ -1093,10 +1093,10 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) nrda = s->rdra + (CSR_RCVRL(s) - rcvrc) * (BCR_SWSTYLE(s) ? 16 : 8 ); - RMDLOAD(&rmd, PHYSADDR(s,nrda)); + RMDLOAD(&rmd, PHYSADDR(s,nrda)); if (GET_FIELD(rmd.status, RMDS, OWN)) { #ifdef PCNET_DEBUG_RMD - printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", + printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", rcvrc, CSR_RCVRC(s)); #endif CSR_RCVRC(s) = rcvrc; @@ -1119,7 +1119,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) int pktcount = 0; memcpy(src, buf, size); - + #if 1 /* no need to compute the CRC */ src[size] = 0; @@ -1136,7 +1136,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) while (size < 46) { src[size++] = 0; } - + while (p != &src[size]) { CRC(fcs, *p++); } @@ -1178,7 +1178,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) PCNET_RECV_STORE(); } } - } + } } #undef PCNET_RECV_STORE @@ -1198,27 +1198,27 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) s->csr[0] |= 0x0400; #ifdef PCNET_DEBUG - printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", + printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount); #endif #ifdef PCNET_DEBUG_RMD PRINT_RMD(&rmd); -#endif +#endif while (pktcount--) { if (CSR_RCVRC(s) <= 1) CSR_RCVRC(s) = CSR_RCVRL(s); else - CSR_RCVRC(s)--; + CSR_RCVRC(s)--; } - + pcnet_rdte_poll(s); - } + } } pcnet_poll(s); - pcnet_update_irq(s); + pcnet_update_irq(s); } static void pcnet_transmit(PCNetState *s) @@ -1226,7 +1226,7 @@ static void pcnet_transmit(PCNetState *s) target_phys_addr_t xmit_cxda = 0; int count = CSR_XMTRL(s)-1; s->xmit_pos = -1; - + if (!CSR_TXON(s)) { s->csr[0] &= ~0x0008; return; @@ -1285,7 +1285,7 @@ static void pcnet_transmit(PCNetState *s) if (count--) goto txagain; - } else + } else if (s->xmit_pos >= 0) { struct pcnet_TMD tmd; TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); @@ -1311,7 +1311,7 @@ static void pcnet_poll(PCNetState *s) pcnet_rdte_poll(s); } - if (CSR_TDMD(s) || + if (CSR_TDMD(s) || (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) { /* prevent recursion */ @@ -1332,7 +1332,7 @@ static void pcnet_poll_timer(void *opaque) pcnet_transmit(s); } - pcnet_update_irq(s); + pcnet_update_irq(s); if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { uint64_t now = qemu_get_clock(vm_clock) * 33; @@ -1346,7 +1346,7 @@ static void pcnet_poll_timer(void *opaque) } else CSR_POLL(s) = t; } - qemu_mod_timer(s->poll_timer, + qemu_mod_timer(s->poll_timer, pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock))); } } @@ -1379,7 +1379,7 @@ static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value) if (!CSR_STRT(s) && (val & 2)) pcnet_start(s); - if (CSR_TDMD(s)) + if (CSR_TDMD(s)) pcnet_transmit(s); return; @@ -1434,11 +1434,11 @@ static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value) case 3: break; case 4: - s->csr[4] &= ~(val & 0x026a); + s->csr[4] &= ~(val & 0x026a); val &= ~0x026a; val |= s->csr[4] & 0x026a; break; case 5: - s->csr[5] &= ~(val & 0x0a90); + s->csr[5] &= ~(val & 0x0a90); val &= ~0x0a90; val |= s->csr[5] & 0x0a90; break; case 16: @@ -1592,11 +1592,11 @@ static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) PCNetState *s = opaque; #ifdef PCNET_DEBUG printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); -#endif +#endif /* Check APROMWE bit to enable write access */ if (pcnet_bcr_readw(s,2) & 0x80) s->prom[addr & 15] = val; -} +} static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) { @@ -1685,7 +1685,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080); #ifdef PCNET_DEBUG_IO printf("device switched into dword i/o mode\n"); -#endif +#endif } pcnet_update_irq(s); } @@ -1695,7 +1695,7 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) PCNetState *s = opaque; uint32_t val = -1; pcnet_poll_timer(s); - if (BCR_DWIO(s)) { + if (BCR_DWIO(s)) { switch (addr & 0x0f) { case 0x00: /* RDP */ val = pcnet_csr_readw(s, s->rap); @@ -1719,7 +1719,7 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) return val; } -static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, +static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCNetState *d = (PCNetState *)pci_dev; @@ -1730,7 +1730,7 @@ static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); - + register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); @@ -1747,7 +1747,7 @@ static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t va pcnet_aprom_writeb(d, addr & 0x0f, val); } -static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) +static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) { PCNetState *d = opaque; uint32_t val = -1; @@ -1774,7 +1774,7 @@ static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t va } } -static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) +static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) { PCNetState *d = opaque; uint32_t val = -1; @@ -1809,7 +1809,7 @@ static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t va } } -static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) +static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) { PCNetState *d = opaque; uint32_t val; @@ -1931,7 +1931,7 @@ static CPUReadMemoryFunc *pcnet_mmio_read[] = { (CPUReadMemoryFunc *)&pcnet_mmio_readl }; -static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, +static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCNetState *d = (PCNetState *)pci_dev; @@ -1961,28 +1961,28 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) uint8_t *pci_conf; #if 0 - printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", + printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); #endif d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), devfn, NULL, NULL); - + pci_conf = d->dev.config; - + *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022); - *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); - *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); + *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); + *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); pci_conf[0x08] = 0x10; pci_conf[0x09] = 0x00; - pci_conf[0x0a] = 0x00; // ethernet network controller + pci_conf[0x0a] = 0x00; // ethernet network controller pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; // header_type - + *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); - + pci_conf[0x3d] = 1; // interrupt pin 0 pci_conf[0x3e] = 0x06; pci_conf[0x3f] = 0xff; @@ -1991,12 +1991,12 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) d->mmio_index = cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); - pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, + pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); - - pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, + + pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); - + d->irq = d->dev.irq[0]; d->phys_mem_read = pci_physical_memory_read; d->phys_mem_write = pci_physical_memory_write; diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index f98d11438..2545bcbc3 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -1,6 +1,6 @@ /* * CFI parallel flash with AMD command set emulation - * + * * Copyright (c) 2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -185,7 +185,7 @@ static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width) } /* update flash content on disk */ -static void pflash_update(pflash_t *pfl, int offset, +static void pflash_update(pflash_t *pfl, int offset, int size) { int offset_end; @@ -194,7 +194,7 @@ static void pflash_update(pflash_t *pfl, int offset, /* round to sectors */ offset = offset >> 9; offset_end = (offset_end + 511) >> 9; - bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), + bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), offset_end - offset); } } @@ -222,7 +222,7 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, offset -= (uint32_t)(long)pfl->storage; else offset -= pfl->base; - + DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__, offset, value, width); /* Set the device in I/O access mode */ @@ -369,7 +369,7 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, pfl->status = 0x00; pflash_update(pfl, 0, pfl->total_len); /* Let's wait 5 seconds before chip erase is done */ - qemu_mod_timer(pfl->timer, + qemu_mod_timer(pfl->timer, qemu_get_clock(vm_clock) + (ticks_per_sec * 5)); break; case 0x30: @@ -382,7 +382,7 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, pflash_update(pfl, offset, pfl->sector_len); pfl->status = 0x00; /* Let's wait 1/2 second before sector erase is done */ - qemu_mod_timer(pfl->timer, + qemu_mod_timer(pfl->timer, qemu_get_clock(vm_clock) + (ticks_per_sec / 2)); break; default: @@ -524,7 +524,7 @@ static int ctz32 (uint32_t n) pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, BlockDriverState *bs, uint32_t sector_len, int nb_blocs, int width, - uint16_t id0, uint16_t id1, + uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3) { pflash_t *pfl; diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 095698c9d..8c00f0d13 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -2,7 +2,7 @@ * QEMU i440FX/PIIX3 PCI Bridge Emulation * * 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 @@ -63,19 +63,19 @@ static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r) switch(r) { case 3: /* RAM */ - cpu_register_physical_memory(start, end - start, + cpu_register_physical_memory(start, end - start, start); break; case 1: /* ROM (XXX: not quite correct) */ - cpu_register_physical_memory(start, end - start, + cpu_register_physical_memory(start, end - start, start | IO_MEM_ROM); break; case 2: case 0: /* XXX: should distinguish read/write cases */ for(addr = start; addr < end; addr += 4096) { - cpu_register_physical_memory(addr, 4096, + cpu_register_physical_memory(addr, 4096, isa_page_descs[(addr - 0xa0000) >> 12]); } break; @@ -97,7 +97,7 @@ static void i440fx_update_memory_mappings(PCIDevice *d) cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000); } else { for(addr = 0xa0000; addr < 0xc0000; addr += 4096) { - cpu_register_physical_memory(addr, 4096, + cpu_register_physical_memory(addr, 4096, isa_page_descs[(addr - 0xa0000) >> 12]); } } @@ -124,7 +124,7 @@ void i440fx_init_memory_mappings(PCIDevice *d) } } -static void i440fx_write_config(PCIDevice *d, +static void i440fx_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { /* XXX: implement SMRAM.D_LOCK */ @@ -175,7 +175,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); - d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, + d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, NULL, i440fx_write_config); d->config[0x00] = 0x86; // vendor_id diff --git a/hw/pl011.c b/hw/pl011.c index 149a85e54..e66741b7a 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -1,4 +1,4 @@ -/* +/* * Arm PrimeCell PL011 UART * * Copyright (c) 2006 CodeSourcery. @@ -44,7 +44,7 @@ static const unsigned char pl011_id[] = static void pl011_update(pl011_state *s) { uint32_t flags; - + flags = s->int_level & s->int_enabled; qemu_set_irq(s->irq, flags != 0); } @@ -240,7 +240,7 @@ void pl011_init(uint32_t base, qemu_irq irq, s->ifl = 0x12; s->cr = 0x300; s->flags = 0x90; - if (chr){ + if (chr){ qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive, pl011_event, s); } diff --git a/hw/pl050.c b/hw/pl050.c index 521c9e611..b3a27976c 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -1,4 +1,4 @@ -/* +/* * Arm PrimeCell PL050 Keyboard / Mouse Interface * * Copyright (c) 2006-2007 CodeSourcery. diff --git a/hw/pl080.c b/hw/pl080.c index bc1a975d6..b24cfbaf0 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -1,4 +1,4 @@ -/* +/* * Arm PrimeCell PL080/PL081 DMA controller * * Copyright (c) 2006 CodeSourcery. @@ -111,7 +111,7 @@ again: continue; flow = (ch->conf >> 11) & 7; if (flow >= 4) { - cpu_abort(cpu_single_env, + cpu_abort(cpu_single_env, "pl080_run: Peripheral flow control not implemented\n"); } src_id = (ch->conf >> 1) & 0x1f; diff --git a/hw/pl110.c b/hw/pl110.c index 9df77c46c..349426456 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -1,4 +1,4 @@ -/* +/* * Arm PrimeCell PL110 Color LCD Controller * * Copyright (c) 2005-2006 CodeSourcery. @@ -117,7 +117,7 @@ static void pl110_update_display(void *opaque) if (!pl110_enabled(s)) return; - + switch (s->ds->depth) { case 0: return; @@ -151,7 +151,7 @@ static void pl110_update_display(void *opaque) fn = fntable[s->bpp + 12]; else fn = fntable[s->bpp]; - + src_width = s->cols; switch (s->bpp) { case BPP_1: diff --git a/hw/pl110_template.h b/hw/pl110_template.h index ed533aca1..f7cb1f495 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -1,4 +1,4 @@ -/* +/* * Arm PrimeCell PL110 Color LCD Controller * * Copyright (c) 2005 CodeSourcery, LLC. @@ -15,7 +15,7 @@ #define COPY_PIXEL(to, from) *(to++) = from #elif BITS == 15 || BITS == 16 #define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2; -#elif BITS == 24 +#elif BITS == 24 #define COPY_PIXEL(to, from) \ *(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16 #elif BITS == 32 diff --git a/hw/pl181.c b/hw/pl181.c index 62ccad9e4..b450e580a 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -1,4 +1,4 @@ -/* +/* * Arm PrimeCell PL181 MultiMedia Card Interface * * Copyright (c) 2007 CodeSourcery. @@ -177,7 +177,7 @@ error: /* Transfer data between the card and the FIFO. This is complicated by the FIFO holding 32-bit words and the card taking data in single byte chunks. FIFO bytes are transferred in little-endian order. */ - + static void pl181_fifo_run(pl181_state *s) { uint32_t bits; diff --git a/hw/pl190.c b/hw/pl190.c index e36c4480f..23494d8e1 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -1,4 +1,4 @@ -/* +/* * Arm PrimeCell PL190 Vector Interrupt Controller * * Copyright (c) 2006 CodeSourcery. diff --git a/hw/ppc.c b/hw/ppc.c index b4748f66e..a90124325 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -1,8 +1,8 @@ /* * QEMU generic PowerPC hardware System Emulator - * + * * Copyright (c) 2003-2007 Jocelyn Mayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -623,7 +623,7 @@ struct ppcemb_timer_t { uint64_t wdt_next; /* Tick for next WDT interrupt */ struct QEMUTimer *wdt_timer; }; - + /* Fixed interval timer */ static void cpu_4xx_fit_cb (void *opaque) { diff --git a/hw/ppc405.h b/hw/ppc405.h index b2624c386..b3f3b3d80 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -1,8 +1,8 @@ /* * QEMU PowerPC 405 shared definitions - * + * * Copyright (c) 2007 Jocelyn Mayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index b0be417d3..cfb592efe 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -1,8 +1,8 @@ /* * QEMU PowerPC 405 evaluation boards emulation - * + * * Copyright (c) 2007 Jocelyn Mayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -172,9 +172,9 @@ static void ref405ep_fpga_init (uint32_t base) } static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, + DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, + const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -243,7 +243,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, exit(1); } bios_size = (bios_size + 0xfff) & ~0xfff; - cpu_register_physical_memory((uint32_t)(-bios_size), + cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); } bios_offset += bios_size; @@ -294,7 +294,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, /* now we can load the kernel */ kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } @@ -310,7 +310,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } @@ -495,9 +495,9 @@ static void taihu_cpld_init (uint32_t base) } static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, + DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, + const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -511,7 +511,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, target_ulong kernel_base, kernel_size, initrd_base, initrd_size; int linux_boot; int fl_idx, fl_sectors; - + /* RAM is soldered to the board so the size cannot be changed */ ram_bases[0] = 0x00000000; ram_sizes[0] = 0x04000000; @@ -556,7 +556,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, exit(1); } bios_size = (bios_size + 0xfff) & ~0xfff; - cpu_register_physical_memory((uint32_t)(-bios_size), + cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); } bios_offset += bios_size; @@ -592,7 +592,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, /* now we can load the kernel */ kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } @@ -603,7 +603,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, phys_ram_base + initrd_base); if (initrd_size < 0) { fprintf(stderr, - "qemu: could not load initial ram disk '%s'\n", + "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 384eb0d3e..1a6a666ec 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -1,8 +1,8 @@ /* * QEMU PowerPC 405 embedded processors emulation - * + * * Copyright (c) 2007 Jocelyn Mayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -2212,7 +2212,7 @@ static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt) } mask = mask >> 1; } - + } static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) @@ -2228,7 +2228,7 @@ static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) qemu_irq_lower(gpt->irqs[i]); mask = mask >> 1; } - + } static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index a8114fa2e..e5a6313a4 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -1,8 +1,8 @@ /* * QEMU PPC CHRP/PMAC hardware System Emulator - * + * * Copyright (c) 2004-2007 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 @@ -129,16 +129,16 @@ static MacIONVRAMState *macio_nvram_init(void) s = qemu_mallocz(sizeof(MacIONVRAMState)); if (!s) return NULL; - macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read, + macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read, macio_nvram_write, s); return s; } -static void macio_map(PCIDevice *pci_dev, int region_num, +static void macio_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { if (heathrow_pic_mem_index >= 0) { - cpu_register_physical_memory(addr + 0x00000, 0x1000, + cpu_register_physical_memory(addr + 0x00000, 0x1000, heathrow_pic_mem_index); } cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index); @@ -148,7 +148,7 @@ static void macio_map(PCIDevice *pci_dev, int region_num, if (ide1_mem_index >= 0) cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); if (openpic_mem_index >= 0) { - cpu_register_physical_memory(addr + 0x40000, 0x40000, + cpu_register_physical_memory(addr + 0x40000, 0x40000, openpic_mem_index); } if (macio_nvram_mem_index >= 0) @@ -173,10 +173,10 @@ static void macio_init(PCIBus *bus, int device_id) d->config[0x0e] = 0x00; // header_type d->config[0x3d] = 0x01; // interrupt on pin 1 - + dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL); - pci_register_io_region(d, 0, 0x80000, + pci_register_io_region(d, 0, 0x80000, PCI_ADDRESS_SPACE_MEM, macio_map); } @@ -208,7 +208,7 @@ static int vga_osi_call(CPUState *env) { static int vga_vbl_enabled; int linesize; - + // printf("osi_call R5=%d\n", env->gpr[5]); /* same handler as PearPC, coming from the original MOL video @@ -229,7 +229,7 @@ static int vga_osi_call(CPUState *env) break; } } - env->gpr[3] = 0; + env->gpr[3] = 0; env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */ env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */ env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */ @@ -255,7 +255,7 @@ static int vga_osi_call(CPUState *env) break; case 64: /* get color */ /* R6 = index */ - env->gpr[3] = 0; + env->gpr[3] = 0; break; case 116: /* set hwcursor */ /* R6 = x, R7 = y, R8 = visible, R9 = data */ @@ -280,14 +280,14 @@ static uint8_t nvram_chksum(const uint8_t *buf, int n) void pmac_format_nvram_partition(uint8_t *buf, int len) { char partition_name[12] = "wwwwwwwwwwww"; - + buf[0] = 0x7f; /* free partition magic */ buf[1] = 0; /* checksum */ buf[2] = len >> 8; buf[3] = len; memcpy(buf + 4, partition_name, 12); buf[1] = nvram_chksum(buf, 16); -} +} /* PowerPC CHRP hardware initialisation */ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, @@ -355,7 +355,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, bios_size = (bios_size + 0xfff) & ~0xfff; cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); - + /* allocate and load VGA BIOS */ vga_bios_offset = bios_offset + bios_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); @@ -371,12 +371,12 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, phys_ram_base[vga_bios_offset + 1] = 'D'; phys_ram_base[vga_bios_offset + 2] = 'R'; phys_ram_base[vga_bios_offset + 3] = 'V'; - cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4), + cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4), vga_bios_size); vga_bios_size += 8; } vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff; - + if (linux_boot) { kernel_base = KERNEL_LOAD_ADDR; /* now we can load the kernel */ @@ -427,24 +427,24 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* XXX: suppress that */ dummy_irq = i8259_init(NULL); - + /* XXX: use Mac Serial port */ serial_init(0x3f8, dummy_irq[4], serial_hds[0]); - + for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) nd_table[i].model = "ne2k_pci"; pci_nic_init(pci_bus, &nd_table[i], -1); } - + pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); /* cuda also initialize ADB */ cuda_mem_index = cuda_init(pic[0x12]); - + adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - + { MacIONVRAMState *nvr; nvr = macio_nvram_init(); @@ -534,14 +534,14 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, #endif /* cuda also initialize ADB */ cuda_mem_index = cuda_init(pic[0x19]); - + adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - + macio_init(pci_bus, 0x0022); - + nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59); - + arch_name = "MAC99"; } @@ -578,7 +578,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 0); } - + static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 4b9d9d13f..d1075d9b1 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -1,8 +1,8 @@ /* * QEMU PPC PREP hardware System Emulator - * + * * Copyright (c) 2003-2007 Jocelyn Mayer - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -612,7 +612,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); /* init basic PC hardware */ - pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, + pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, 0, 0); // openpic = openpic_init(0x00000000, 0xF0000000, 1); // pit = pit_init(0x40, i8259[0]); diff --git a/hw/prep_pci.c b/hw/prep_pci.c index be62b8953..f384e4215 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -2,7 +2,7 @@ * QEMU PREP PCI host * * 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 @@ -147,12 +147,12 @@ PCIBus *pci_prep_init(qemu_irq *pic) register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); - PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, + PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, PPC_PCIIO_write, s); cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); - /* PCI host bridge */ - d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven", + /* PCI host bridge */ + d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven", sizeof(PCIDevice), 0, NULL, NULL); d->config[0x00] = 0x57; // vendor_id : Motorola d->config[0x01] = 0x10; diff --git a/hw/ps2.c b/hw/ps2.c index 2d87f1f12..233ff540d 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -1,8 +1,8 @@ /* * QEMU PS/2 keyboard/mouse emulation - * + * * Copyright (c) 2003 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -146,7 +146,7 @@ uint32_t ps2_read_data(void *opaque) PS2State *s = (PS2State *)opaque; PS2Queue *q; int val, index; - + q = &s->queue; if (q->count == 0) { /* NOTE: if no data left, we return the last keyboard one @@ -294,7 +294,7 @@ static void ps2_mouse_send_packet(PS2MouseState *s) s->mouse_dz -= dz1; } -static void ps2_mouse_event(void *opaque, +static void ps2_mouse_event(void *opaque, int dx, int dy, int dz, int buttons_state) { PS2MouseState *s = opaque; @@ -311,7 +311,7 @@ static void ps2_mouse_event(void *opaque, s->mouse_buttons == buttons_state) return; s->mouse_buttons = buttons_state; - + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) { for(;;) { @@ -434,12 +434,12 @@ void ps2_write_mouse(void *opaque, int val) s->mouse_detect_state = 0; break; case 2: - if (val == 80) + if (val == 80) s->mouse_type = 3; /* IMPS/2 */ s->mouse_detect_state = 0; break; case 3: - if (val == 80) + if (val == 80) s->mouse_type = 4; /* IMEX */ s->mouse_detect_state = 0; break; diff --git a/hw/ptimer.c b/hw/ptimer.c index 2abf285af..d81503adc 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -1,4 +1,4 @@ -/* +/* * General purpose implementation of a simple periodic countdown timer. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index b3db97490..85aeb50cc 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -53,7 +53,7 @@ static struct { } pxa2xx_gpio_regs[0x200] = { [0 ... 0x1ff] = { GPIO_NONE, 0 }, #define PXA2XX_REG(reg, a0, a1, a2, a3) \ - [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 }, + [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 }, PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100) PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118) diff --git a/hw/pxa2xx_template.h b/hw/pxa2xx_template.h index 341be12e5..ad3799df2 100644 --- a/hw/pxa2xx_template.h +++ b/hw/pxa2xx_template.h @@ -14,7 +14,7 @@ # define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to) #elif BITS == 15 || BITS == 16 # define COPY_PIXEL(to, from) *(uint16_t *) to = from; SKIP_PIXEL(to) -#elif BITS == 24 +#elif BITS == 24 # define COPY_PIXEL(to, from) \ *(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to) #elif BITS == 32 diff --git a/hw/realview.c b/hw/realview.c index 1ca02d5e2..375f78acd 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -1,4 +1,4 @@ -/* +/* * ARM RealView Baseboard System emulation. * * Copyright (c) 2006-2007 CodeSourcery. diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 210af449f..097ad473e 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -1,8 +1,8 @@ /** * QEMU RTL8139 emulation - * + * * Copyright (c) 2006 Igor Kovalenko - * + * * 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 @@ -20,13 +20,13 @@ * 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. - + * Modifications: * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver) - * + * * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver * HW revision ID changes for FreeBSD driver - * + * * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver * Corrected packet transfer reassembly routine for 8139C+ mode * Rearranged debugging print statements @@ -305,11 +305,11 @@ enum CSCRBits { CSCR_LinkDownCmd = 0x0f3c0, */ enum CSCRBits { - CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */ + CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */ CSCR_LD = 1<<9, /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/ CSCR_HEART_BIT = 1<<8, /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/ CSCR_JBEN = 1<<7, /* 1 = enable jabber function. 0 = disable jabber function, def 1*/ - CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/ + CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/ CSCR_F_Connect = 1<<5, /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/ CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/ CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/ @@ -813,7 +813,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d uint32_t packet_header = 0; uint8_t buf1[60]; - static const uint8_t broadcast_macaddr[6] = + static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; DEBUG_PRINT((">>> RTL8139: received len=%d\n", size)); @@ -890,10 +890,10 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d ++s->tally_counters.RxOkMul; } else if (s->phys[0] == buf[0] && - s->phys[1] == buf[1] && - s->phys[2] == buf[2] && - s->phys[3] == buf[3] && - s->phys[4] == buf[4] && + s->phys[1] == buf[1] && + s->phys[2] == buf[2] && + s->phys[3] == buf[3] && + s->phys[4] == buf[4] && s->phys[5] == buf[5]) { /* match */ if (!(s->RxConfig & AcceptMyPhys)) @@ -1225,7 +1225,7 @@ static void rtl8139_reset(RTL8139State *s) s->Config3 = 0x1; /* fast back-to-back compatible */ s->Config5 = 0x0; - s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; + s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; s->CpCmd = 0x0; /* reset C+ mode */ @@ -2420,17 +2420,17 @@ static uint16_t rtl8139_TSAD_read(RTL8139State *s) |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0) |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0) |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0) - + |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0) |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0) |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0) |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0) - + |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0) |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0) |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0) |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ; - + DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret)); @@ -3315,7 +3315,7 @@ typedef struct PCIRTL8139State { RTL8139State rtl8139; } PCIRTL8139State; -static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num, +static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCIRTL8139State *d = (PCIRTL8139State *)pci_dev; @@ -3324,7 +3324,7 @@ static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr); } -static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num, +static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCIRTL8139State *d = (PCIRTL8139State *)pci_dev; @@ -3354,7 +3354,7 @@ static CPUWriteMemoryFunc *rtl8139_mmio_write[3] = { static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time) { - int64_t next_time = current_time + + int64_t next_time = current_time + muldiv64(1, ticks_per_sec, PCI_FREQUENCY); if (next_time <= current_time) next_time = current_time + 1; @@ -3400,7 +3400,7 @@ static void rtl8139_timer(void *opaque) rtl8139_update_irq(s); } - qemu_mod_timer(s->timer, + qemu_mod_timer(s->timer, rtl8139_get_next_tctr_time(s,curr_time)); } #endif /* RTL8139_ONBOARD_TIMER */ @@ -3410,10 +3410,10 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) PCIRTL8139State *d; RTL8139State *s; uint8_t *pci_conf; - + d = (PCIRTL8139State *)pci_register_device(bus, "RTL8139", sizeof(PCIRTL8139State), - devfn, + devfn, NULL, NULL); pci_conf = d->dev.config; pci_conf[0x00] = 0xec; /* Realtek 8139 */ @@ -3434,10 +3434,10 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) s->rtl8139_mmio_io_addr = cpu_register_io_memory(0, rtl8139_mmio_read, rtl8139_mmio_write, s); - pci_register_io_region(&d->dev, 0, 0x100, + pci_register_io_region(&d->dev, 0, 0x100, PCI_ADDRESS_SPACE_IO, rtl8139_ioport_map); - pci_register_io_region(&d->dev, 1, 0x100, + pci_register_io_region(&d->dev, 1, 0x100, PCI_ADDRESS_SPACE_MEM, rtl8139_mmio_map); s->pci_dev = (PCIDevice *)d; @@ -3458,14 +3458,14 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) s->cplus_txbuffer = NULL; s->cplus_txbuffer_len = 0; s->cplus_txbuffer_offset = 0; - + /* XXX: instance number ? */ register_savevm("rtl8139", 0, 3, rtl8139_save, rtl8139_load, s); #if RTL8139_ONBOARD_TIMER s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); - qemu_mod_timer(s->timer, + qemu_mod_timer(s->timer, rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock))); #endif /* RTL8139_ONBOARD_TIMER */ } diff --git a/hw/sd.c b/hw/sd.c index 7974564ec..d59c4bf56 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -1,4 +1,4 @@ -/* +/* * SD Memory Card emulation as defined in the "SD Memory Card Physical * layer specification, Version 1.10." * diff --git a/hw/sd.h b/hw/sd.h index 2851e729f..ab20064fe 100644 --- a/hw/sd.h +++ b/hw/sd.h @@ -1,4 +1,4 @@ -/* +/* * SD Memory Card emulation. Mostly correct for MMC too. * * Copyright (c) 2006 Andrzej Zaborowski diff --git a/hw/serial.c b/hw/serial.c index 5513007d1..ac3995b94 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -1,8 +1,8 @@ /* * QEMU 16450 UART emulation - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -119,7 +119,7 @@ static void serial_update_parameters(SerialState *s) } else { parity = 'N'; } - if (s->lcr & 0x04) + if (s->lcr & 0x04) stop_bits = 2; else stop_bits = 1; @@ -133,7 +133,7 @@ static void serial_update_parameters(SerialState *s) ssp.stop_bits = stop_bits; qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); #if 0 - printf("speed=%d parity=%c data=%d stop=%d\n", + printf("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits); #endif } @@ -142,7 +142,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) { SerialState *s = opaque; unsigned char ch; - + addr &= 7; #ifdef DEBUG_SERIAL printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); @@ -187,7 +187,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) break_enable = (val >> 6) & 1; if (break_enable != s->last_break_enable) { s->last_break_enable = break_enable; - qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, &break_enable); } } @@ -215,7 +215,7 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) default: case 0: if (s->lcr & UART_LCR_DLAB) { - ret = s->divider & 0xff; + ret = s->divider & 0xff; } else { ret = s->rbr; s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); diff --git a/hw/sh7750.c b/hw/sh7750.c index 164ce7162..dcba14e1a 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -1,8 +1,8 @@ /* * SH7750 device - * + * * Copyright (c) 2005 Samuel Tardieu - * + * * 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 diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h index 44ae95be2..6b18ad2e1 100644 --- a/hw/sh7750_regs.h +++ b/hw/sh7750_regs.h @@ -12,26 +12,26 @@ * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. - * + * * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp */ #ifndef __SH7750_REGS_H__ #define __SH7750_REGS_H__ -/* - * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and +/* + * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and * in 0x1f000000 - 0x1fffffff (area 7 address) */ -#define SH7750_P4_BASE 0xff000000 /* Accessable only in +#define SH7750_P4_BASE 0xff000000 /* Accessable only in priveleged mode */ #define SH7750_A7_BASE 0x1f000000 /* Accessable only using TLB */ #define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs)) #define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs)) -/* - * MMU Registers +/* + * MMU Registers */ /* Page Table Entry High register - PTEH */ @@ -61,9 +61,9 @@ #define SH7750_PTEL_PR_RWPO 0x00000020 /* read-write in priv mode */ #define SH7750_PTEL_PR_ROPU 0x00000040 /* read-only in priv or user mode */ #define SH7750_PTEL_PR_RWPU 0x00000060 /* read-write in priv or user mode */ -#define SH7750_PTEL_C 0x00000008 /* Cacheability +#define SH7750_PTEL_C 0x00000008 /* Cacheability (0 - page not cacheable) */ -#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been +#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been performed to a page) */ #define SH7750_PTEL_SH 0x00000002 /* Share Status bit (1 - page are shared by processes) */ @@ -130,12 +130,12 @@ #define SH7750_CCR_A7 SH7750_A7_REG32(SH7750_CCR_REGOFS) #define SH7750_CCR_IIX 0x00008000 /* IC index enable bit */ -#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit: +#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit: set it to clear IC */ #define SH7750_CCR_ICE 0x00000100 /* IC enable bit */ #define SH7750_CCR_OIX 0x00000080 /* OC index enable bit */ -#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit - if you set OCE = 0, +#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit + if you set OCE = 0, you should set ORA = 0 */ #define SH7750_CCR_OCI 0x00000008 /* OC invalidation bit */ #define SH7750_CCR_CB 0x00000004 /* Copy-back bit for P1 area */ @@ -254,7 +254,7 @@ /* Peripheral Module Interrupts - Memory Refresh Unit (REF) */ #define SH7750_EVT_REF_RCMI 0x580 /* Compare-match Interrupt */ -#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow +#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow interrupt */ /* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */ @@ -331,7 +331,7 @@ #define SH7750_FRQCR SH7750_P4_REG32(SH7750_FRQCR_REGOFS) #define SH7750_FRQCR_A7 SH7750_A7_REG32(SH7750_FRQCR_REGOFS) -#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable +#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable 0 - CKIO pin goes to HiZ/pullup 1 - Clock is output from CKIO */ #define SH7750_FRQCR_PLL1EN 0x0400 /* PLL circuit 1 enable */ @@ -643,7 +643,7 @@ #define SH7750_BCR1_BREQEN 0x00080000 /* BREQ Enable: 0 - External requests are not accepted - 1 - External requests are + 1 - External requests are accepted */ #define SH7750_BCR1_PSHR 0x00040000 /* Partial Sharing Bit: 0 - Master Mode @@ -877,7 +877,7 @@ #define SH7750_MCR_TCAS_1 0x00000000 /* 1 */ #define SH7750_MCR_TCAS_2 0x00800000 /* 2 */ -#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period +#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period SDRAM: minimum number of cycles until the next bank active cmd is output after precharging */ @@ -1148,7 +1148,7 @@ #define SH7750_CHCR_DSA_AMEM16 0x0E000000 /* 16-bit attribute memory space */ #define SH7750_CHCR_DTC 0x01000000 /* Destination Address Wait Control - Select, specifies CS5 or CS6 + Select, specifies CS5 or CS6 space wait control for PCMCIA access */ @@ -1186,8 +1186,8 @@ Address Mode (External Addr Space -> External Device) */ #define SH7750_CHCR_RS_ER_SA_ED_TO_EA 0x300 /* External Request, Single - Address Mode, (External - Device -> External Addr + Address Mode, (External + Device -> External Addr Space) */ #define SH7750_CHCR_RS_AR_EA_TO_EA 0x400 /* Auto-Request (External Addr Space -> External Addr Space) */ @@ -1195,7 +1195,7 @@ #define SH7750_CHCR_RS_AR_EA_TO_OCP 0x500 /* Auto-Request (External Addr Space -> On-chip Peripheral Module) */ -#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip +#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip Peripheral Module -> External Addr Space */ #define SH7750_CHCR_RS_SCITX_EA_TO_SC 0x800 /* SCI Transmit-Data-Empty intr @@ -1596,7 +1596,7 @@ #define SH7750_IPRC_HUDI_S 0 -/* +/* * User Break Controller registers */ #define SH7750_BARA 0x200000 /* Break address regiser A */ diff --git a/hw/shix.c b/hw/shix.c index 000fd6af4..e668426c8 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -1,8 +1,8 @@ /* * SHIX 2.0 board description - * + * * Copyright (c) 2005 Samuel Tardieu - * + * * 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 @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -/* +/* Shix 2.0 board by Alexis Polti, described at http://perso.enst.fr/~polti/realisations/shix20/ diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 993c3196c..98cac6ed7 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -1,8 +1,8 @@ /* * QEMU Sparc SLAVIO interrupt controller emulation - * + * * Copyright (c) 2003-2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -40,7 +40,7 @@ do { printf("IRQ: " fmt , ##args); } while (0) * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt * * There is a system master controller and one for each cpu. - * + * */ #define MAX_CPUS 16 @@ -308,7 +308,7 @@ static void slavio_intctl_save(QEMUFile *f, void *opaque) { SLAVIO_INTCTLState *s = opaque; int i; - + for (i = 0; i < MAX_CPUS; i++) { qemu_put_be32s(f, &s->intreg_pending[i]); } diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index e8a4ea4d4..34072c623 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -1,8 +1,8 @@ /* * QEMU Sparc SLAVIO aux io port emulation - * + * * Copyright (c) 2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 86e661ccd..990f5c7ed 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -1,8 +1,8 @@ /* * QEMU Sparc SLAVIO serial port emulation - * + * * Copyright (c) 2003-2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -35,7 +35,7 @@ * This is the serial port, mouse and keyboard part of chip STP2001 * (Slave I/O), also produced as NCR89C105. See * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * + * * The serial ports implement full AMD AM8530 or Zilog Z8530 chips, * mouse and keyboard ports don't implement all functions and they are * only asynchronous. There is no DMA. @@ -136,7 +136,7 @@ static uint32_t get_queue(void *opaque) ChannelState *s = opaque; SERIOQueue *q = &s->queue; int val; - + if (q->count == 0) { return 0; } else { @@ -662,7 +662,7 @@ static void handle_kbd_command(ChannelState *s, int val) } } -static void sunmouse_event(void *opaque, +static void sunmouse_event(void *opaque, int dx, int dy, int dz, int buttons_state) { ChannelState *s = opaque; diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 2ade17788..c9a3a563e 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -2,7 +2,7 @@ * QEMU Sparc SLAVIO timer controller emulation * * Copyright (c) 2003-2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -38,7 +38,7 @@ do { printf("TIMER: " fmt , ##args); } while (0) * This is the timer/counter part of chip STP2001 (Slave I/O), also * produced as NCR89C105. See * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * + * * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 * are zero. Bit 31 is 1 when count has been reached. * @@ -210,7 +210,7 @@ static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) { SLAVIO_TIMERState *s = opaque; uint32_t tmp; - + if (version_id != 2) return -EINVAL; diff --git a/hw/smbus.c b/hw/smbus.c index 5189d51df..103e9177b 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -1,4 +1,4 @@ -/* +/* * QEMU SMBus device emulation. * * Copyright (c) 2007 CodeSourcery. diff --git a/hw/smbus.h b/hw/smbus.h index 36977731e..0d35bb68a 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -1,8 +1,8 @@ /* * QEMU SMBus API - * + * * Copyright (c) 2007 Arastra, Inc. - * + * * 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 diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 699bd5417..5b8637d44 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -1,8 +1,8 @@ /* * QEMU SMBus EEPROM device - * + * * Copyright (c) 2007 Arastra, Inc. - * + * * 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 @@ -94,7 +94,7 @@ static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf) { SMBusEEPROMDevice *eeprom; - + eeprom = (SMBusEEPROMDevice *)smbus_device_init(bus, addr, sizeof(SMBusEEPROMDevice)); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index d90ab32f6..a6a11e0f2 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -1,4 +1,4 @@ -/* +/* * SMSC 91C111 Ethernet interface emulation * * Copyright (c) 2005 CodeSourcery, LLC. @@ -649,7 +649,7 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) /* Pad short packets. */ if (size < 64) { int pad; - + if (size & 1) *(p++) = buf[size - 1]; pad = 64 - size; diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index d2fe57686..3c80fd67f 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -63,7 +63,7 @@ struct DMAState { }; /* Note: on sparc, the lance 16 bit bus is swapped */ -void ledma_memory_read(void *opaque, target_phys_addr_t addr, +void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap) { DMAState *s = opaque; @@ -84,7 +84,7 @@ void ledma_memory_read(void *opaque, target_phys_addr_t addr, } } -void ledma_memory_write(void *opaque, target_phys_addr_t addr, +void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap) { DMAState *s = opaque; diff --git a/hw/sun4m.c b/hw/sun4m.c index dba6f3878..4da4138d9 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -1,8 +1,8 @@ /* * QEMU Sun4m System Emulator - * + * * Copyright (c) 2003-2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -425,14 +425,14 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, linux_boot = (kernel_filename != NULL); prom_offset = RAM_size + vram_size; - cpu_register_physical_memory(PROM_ADDR, - (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, + cpu_register_physical_memory(PROM_ADDR, + (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); ret = load_elf(buf, 0, NULL, NULL, NULL); if (ret < 0) { - fprintf(stderr, "qemu: could not load prom '%s'\n", + fprintf(stderr, "qemu: could not load prom '%s'\n", buf); exit(1); } @@ -445,7 +445,7 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, if (kernel_size < 0) kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } @@ -455,7 +455,7 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, if (initrd_filename) { initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } diff --git a/hw/sun4u.c b/hw/sun4u.c index 4be94fa91..0e9e72e35 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -1,8 +1,8 @@ /* * QEMU Sun4u System Emulator - * + * * Copyright (c) 2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -378,14 +378,14 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0, ram_size, 0); prom_offset = ram_size + vga_ram_size; - cpu_register_physical_memory(PROM_ADDR, - (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, + cpu_register_physical_memory(PROM_ADDR, + (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); ret = load_elf(buf, PROM_ADDR - PROM_VADDR, NULL, NULL, NULL); if (ret < 0) { - fprintf(stderr, "qemu: could not load prom '%s'\n", + fprintf(stderr, "qemu: could not load prom '%s'\n", buf); exit(1); } @@ -400,7 +400,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, if (kernel_size < 0) kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } @@ -409,7 +409,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, if (initrd_filename) { initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } diff --git a/hw/tcx.c b/hw/tcx.c index c334f0923..72c9bcd59 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -1,8 +1,8 @@ /* * QEMU TCX Frame buffer - * + * * Copyright (c) 2003-2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -83,7 +83,7 @@ static void update_palette_entries(TCXState *s, int start, int end) tcx_invalidate_display(s); } -static void tcx_draw_line32(TCXState *s1, uint8_t *d, +static void tcx_draw_line32(TCXState *s1, uint8_t *d, const uint8_t *s, int width) { int x; @@ -96,7 +96,7 @@ static void tcx_draw_line32(TCXState *s1, uint8_t *d, } } -static void tcx_draw_line16(TCXState *s1, uint8_t *d, +static void tcx_draw_line16(TCXState *s1, uint8_t *d, const uint8_t *s, int width) { int x; @@ -109,7 +109,7 @@ static void tcx_draw_line16(TCXState *s1, uint8_t *d, } } -static void tcx_draw_line8(TCXState *s1, uint8_t *d, +static void tcx_draw_line8(TCXState *s1, uint8_t *d, const uint8_t *s, int width) { int x; @@ -208,7 +208,7 @@ static void tcx_update_display(void *opaque) case 0: return; } - + for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { if (y_start < 0) @@ -232,7 +232,7 @@ static void tcx_update_display(void *opaque) } else { if (y_start >= 0) { /* flush to display */ - dpy_update(ts->ds, 0, y_start, + dpy_update(ts->ds, 0, y_start, ts->width, y - y_start); y_start = -1; } @@ -242,7 +242,7 @@ static void tcx_update_display(void *opaque) } if (y_start >= 0) { /* flush to display */ - dpy_update(ts->ds, 0, y_start, + dpy_update(ts->ds, 0, y_start, ts->width, y - y_start); } /* reset modified pages */ @@ -353,7 +353,7 @@ static void tcx24_invalidate_display(void *opaque) static void tcx_save(QEMUFile *f, void *opaque) { TCXState *s = opaque; - + qemu_put_be16s(f, (uint16_t *)&s->height); qemu_put_be16s(f, (uint16_t *)&s->width); qemu_put_be16s(f, (uint16_t *)&s->depth); diff --git a/hw/unin_pci.c b/hw/unin_pci.c index f32d19522..8728f119c 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -2,7 +2,7 @@ * QEMU Uninorth PCI host (for all Mac99 and newer machines) * * 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 @@ -163,13 +163,13 @@ PCIBus *pci_pmac_init(qemu_irq *pic) s->bus = pci_register_bus(pci_unin_set_irq, pci_unin_map_irq, pic, 11 << 3, 4); - pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, + pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, pci_unin_main_config_write, s); pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, pci_unin_main_write, s); cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); - d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice), + d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice), 11 << 3, NULL, NULL); d->config[0x00] = 0x6b; // vendor_id : Apple d->config[0x01] = 0x10; @@ -217,7 +217,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic) #if 0 // XXX: not needed for now /* Uninorth AGP bus */ s = &pci_bridge[1]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, pci_unin_config_write, s); pci_mem_data = cpu_register_io_memory(0, pci_unin_read, pci_unin_write, s); @@ -242,7 +242,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic) #if 0 // XXX: not needed for now /* Uninorth internal bus */ s = &pci_bridge[2]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, pci_unin_config_write, s); pci_mem_data = cpu_register_io_memory(0, pci_unin_read, pci_unin_write, s); diff --git a/hw/usb-hid.c b/hw/usb-hid.c index f119735a0..e3b94d0d8 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -1,9 +1,9 @@ /* * QEMU USB HID devices - * + * * Copyright (c) 2005 Fabrice Bellard * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) - * + * * 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 @@ -96,13 +96,13 @@ static const uint8_t qemu_mouse_config_descriptor[] = { 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x04, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; + 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 50, /* u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -124,7 +124,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = { 0x01, /* u8 if_bInterfaceSubClass; */ 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x07, /* u8 if_iInterface; */ - + /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ @@ -151,13 +151,13 @@ static const uint8_t qemu_tablet_config_descriptor[] = { 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x05, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; + 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 50, /* u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -206,7 +206,7 @@ static const uint8_t qemu_keyboard_config_descriptor[] = { 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x06, /* u8 iConfiguration; */ - 0xa0, /* u8 bmAttributes; + 0xa0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, @@ -254,11 +254,11 @@ static const uint8_t qemu_keyboard_config_descriptor[] = { }; static const uint8_t qemu_mouse_hid_report_descriptor[] = { - 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, + 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, - 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, + 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, - 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, + 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, 0xC0, 0xC0, }; @@ -474,7 +474,7 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) 0, "QEMU USB Mouse"); s->mouse_grabbed = 1; } - + dx = int_clamp(s->dx, -128, 127); dy = int_clamp(s->dy, -128, 127); dz = int_clamp(s->dz, -128, 127); @@ -482,7 +482,7 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) s->dx -= dx; s->dy -= dy; s->dz -= dz; - + b = 0; if (s->buttons_state & MOUSE_EVENT_LBUTTON) b |= 0x01; @@ -490,7 +490,7 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) b |= 0x02; if (s->buttons_state & MOUSE_EVENT_MBUTTON) b |= 0x04; - + buf[0] = b; buf[1] = dx; buf[2] = dy; @@ -512,7 +512,7 @@ static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len) 1, "QEMU USB Tablet"); s->mouse_grabbed = 1; } - + dz = int_clamp(s->dz, -128, 127); s->dz -= dz; @@ -622,21 +622,21 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch(value >> 8) { case USB_DT_DEVICE: - memcpy(data, qemu_mouse_dev_descriptor, + memcpy(data, qemu_mouse_dev_descriptor, sizeof(qemu_mouse_dev_descriptor)); ret = sizeof(qemu_mouse_dev_descriptor); break; case USB_DT_CONFIG: if (s->kind == USB_MOUSE) { - memcpy(data, qemu_mouse_config_descriptor, + memcpy(data, qemu_mouse_config_descriptor, sizeof(qemu_mouse_config_descriptor)); ret = sizeof(qemu_mouse_config_descriptor); } else if (s->kind == USB_TABLET) { - memcpy(data, qemu_tablet_config_descriptor, + memcpy(data, qemu_tablet_config_descriptor, sizeof(qemu_tablet_config_descriptor)); ret = sizeof(qemu_tablet_config_descriptor); } else if (s->kind == USB_KEYBOARD) { - memcpy(data, qemu_keyboard_config_descriptor, + memcpy(data, qemu_keyboard_config_descriptor, sizeof(qemu_keyboard_config_descriptor)); ret = sizeof(qemu_keyboard_config_descriptor); } @@ -702,15 +702,15 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value, switch(value >> 8) { case 0x22: if (s->kind == USB_MOUSE) { - memcpy(data, qemu_mouse_hid_report_descriptor, + memcpy(data, qemu_mouse_hid_report_descriptor, sizeof(qemu_mouse_hid_report_descriptor)); ret = sizeof(qemu_mouse_hid_report_descriptor); } else if (s->kind == USB_TABLET) { - memcpy(data, qemu_tablet_hid_report_descriptor, + memcpy(data, qemu_tablet_hid_report_descriptor, sizeof(qemu_tablet_hid_report_descriptor)); ret = sizeof(qemu_tablet_hid_report_descriptor); } else if (s->kind == USB_KEYBOARD) { - memcpy(data, qemu_keyboard_hid_report_descriptor, + memcpy(data, qemu_keyboard_hid_report_descriptor, sizeof(qemu_keyboard_hid_report_descriptor)); ret = sizeof(qemu_keyboard_hid_report_descriptor); } diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 651dac210..bfdd5f973 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -2,7 +2,7 @@ * QEMU USB HUB emulation * * Copyright (c) 2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -112,13 +112,13 @@ static const uint8_t qemu_hub_config_descriptor[] = { 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x00, /* u8 iConfiguration; */ - 0xc0, /* u8 bmAttributes; + 0xc0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 0x00, /* u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -140,7 +140,7 @@ static const uint8_t qemu_hub_config_descriptor[] = { 0x00, /* u8 if_bInterfaceSubClass; */ 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x00, /* u8 if_iInterface; */ - + /* one endpoint (status change endpoint) */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ @@ -167,11 +167,11 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) { USBHubState *s = port1->opaque; USBHubPort *port = &s->ports[port1->index]; - + if (dev) { if (port->port.dev) usb_attach(port1, NULL); - + port->wPortStatus |= PORT_STAT_CONNECTION; port->wPortChange |= PORT_STAT_C_CONNECTION; if (dev->speed == USB_SPEED_LOW) @@ -244,12 +244,12 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch(value >> 8) { case USB_DT_DEVICE: - memcpy(data, qemu_hub_dev_descriptor, + memcpy(data, qemu_hub_dev_descriptor, sizeof(qemu_hub_dev_descriptor)); ret = sizeof(qemu_hub_dev_descriptor); break; case USB_DT_CONFIG: - memcpy(data, qemu_hub_config_descriptor, + memcpy(data, qemu_hub_config_descriptor, sizeof(qemu_hub_config_descriptor)); /* status change endpoint size based on number @@ -401,7 +401,7 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value, case GetHubDescriptor: { unsigned int n, limit, var_hub_size = 0; - memcpy(data, qemu_hub_hub_descriptor, + memcpy(data, qemu_hub_hub_descriptor, sizeof(qemu_hub_hub_descriptor)); data[2] = s->nb_ports; @@ -504,8 +504,8 @@ static int usb_hub_handle_packet(USBDevice *dev, USBPacket *p) if (dev->state == USB_STATE_DEFAULT && dev->addr != 0 && p->devaddr != dev->addr && - (p->pid == USB_TOKEN_SETUP || - p->pid == USB_TOKEN_OUT || + (p->pid == USB_TOKEN_SETUP || + p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_IN)) { /* broadcast the packet to the devices */ return usb_hub_broadcast_packet(s, p); diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 08fc5c335..f4289165b 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -1,4 +1,4 @@ -/* +/* * USB Mass Storage Device emulation * * Copyright (c) 2006 CodeSourcery. @@ -93,13 +93,13 @@ static const uint8_t qemu_msd_config_descriptor[] = { 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x00, /* u8 iConfiguration; */ - 0xc0, /* u8 bmAttributes; + 0xc0, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, 4..0: resvd */ 0x00, /* u8 MaxPower; */ - + /* one interface */ 0x09, /* u8 if_bLength; */ 0x04, /* u8 if_bDescriptorType; Interface */ @@ -110,7 +110,7 @@ static const uint8_t qemu_msd_config_descriptor[] = { 0x06, /* u8 if_bInterfaceSubClass; SCSI */ 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */ 0x00, /* u8 if_iInterface; */ - + /* Bulk-In endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ @@ -259,12 +259,12 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch(value >> 8) { case USB_DT_DEVICE: - memcpy(data, qemu_msd_dev_descriptor, + memcpy(data, qemu_msd_dev_descriptor, sizeof(qemu_msd_dev_descriptor)); ret = sizeof(qemu_msd_dev_descriptor); break; case USB_DT_CONFIG: - memcpy(data, qemu_msd_config_descriptor, + memcpy(data, qemu_msd_config_descriptor, sizeof(qemu_msd_config_descriptor)); ret = sizeof(qemu_msd_config_descriptor); break; diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index f4f260877..cd04ad19e 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1,8 +1,8 @@ /* * USB UHCI controller emulation - * + * * Copyright (c) 2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -84,7 +84,7 @@ typedef struct UHCIState { /* For simplicity of implementation we only allow a single pending USB request. This means all usb traffic on this controller is effectively suspended until that transfer completes. When the transfer completes - the next transfer from that queue will be processed. However + the next transfer from that queue will be processed. However other queues will not be processed until the next frame. The solution is to allow multiple pending requests. */ uint32_t async_qh; @@ -149,7 +149,7 @@ static void uhci_reset(UHCIState *s) static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) { UHCIState *s = opaque; - + addr &= 0x1f; switch(addr) { case 0x0c: @@ -178,7 +178,7 @@ static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) { UHCIState *s = opaque; - + addr &= 0x1f; #ifdef DEBUG printf("uhci writew port=0x%04x val=0x%04x\n", addr, val); @@ -243,7 +243,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) dev = port->port.dev; if (dev) { /* port reset */ - if ( (val & UHCI_PORT_RESET) && + if ( (val & UHCI_PORT_RESET) && !(port->ctrl & UHCI_PORT_RESET) ) { usb_send_msg(dev, USB_MSG_RESET); } @@ -280,7 +280,7 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) UHCIPort *port; int n; n = (addr >> 1) & 7; - if (n >= NB_PORTS) + if (n >= NB_PORTS) goto read_default; port = &s->ports[n]; val = port->ctrl; @@ -458,7 +458,7 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) if (td->ctrl & TD_CTRL_IOC) { *int_mask |= 0x01; } - + if (!(td->ctrl & TD_CTRL_ACTIVE)) return 1; @@ -530,7 +530,7 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) here. The docs are somewhat unclear, but win2k relies on this behavior. */ td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK); - if (pid == USB_TOKEN_IN && + if (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) && len < max_len) { *int_mask |= 0x02; @@ -555,7 +555,7 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) uhci_update_irq(s); } } - td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | + td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | (err << TD_CTRL_ERROR_SHIFT); return 1; case USB_RET_NAK: @@ -597,7 +597,7 @@ static void uhci_async_complete_packet(USBPacket * packet, void *opaque) le32_to_cpus(&qh.el_link); /* Re-process the queue containing the async packet. */ while (1) { - cpu_physical_memory_read(qh.el_link & ~0xf, + cpu_physical_memory_read(qh.el_link & ~0xf, (uint8_t *)&td, sizeof(td)); le32_to_cpus(&td.link); le32_to_cpus(&td.ctrl); @@ -608,8 +608,8 @@ static void uhci_async_complete_packet(USBPacket * packet, void *opaque) /* update the status bits of the TD */ if (old_td_ctrl != td.ctrl) { val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((qh.el_link & ~0xf) + 4, - (const uint8_t *)&val, + cpu_physical_memory_write((qh.el_link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); } if (ret < 0) @@ -621,8 +621,8 @@ static void uhci_async_complete_packet(USBPacket * packet, void *opaque) /* update qh element link */ qh.el_link = td.link; val = cpu_to_le32(qh.el_link); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); if (!(qh.el_link & 4)) break; @@ -690,7 +690,7 @@ static void uhci_frame_timer(void *opaque) /* TD */ if (--cnt == 0) break; - cpu_physical_memory_read(qh.el_link & ~0xf, + cpu_physical_memory_read(qh.el_link & ~0xf, (uint8_t *)&td, sizeof(td)); le32_to_cpus(&td.link); le32_to_cpus(&td.ctrl); @@ -701,8 +701,8 @@ static void uhci_frame_timer(void *opaque) /* update the status bits of the TD */ if (old_td_ctrl != td.ctrl) { val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((qh.el_link & ~0xf) + 4, - (const uint8_t *)&val, + cpu_physical_memory_write((qh.el_link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); } if (ret < 0) @@ -713,8 +713,8 @@ static void uhci_frame_timer(void *opaque) /* update qh element link */ qh.el_link = td.link; val = cpu_to_le32(qh.el_link); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); if (qh.el_link & 4) { /* depth first */ @@ -740,8 +740,8 @@ static void uhci_frame_timer(void *opaque) /* update the status bits of the TD */ if (old_td_ctrl != td.ctrl) { val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); } if (ret < 0) @@ -768,12 +768,12 @@ static void uhci_frame_timer(void *opaque) s->async_qh = 0; } /* prepare the timer for the next frame */ - expire_time = qemu_get_clock(vm_clock) + + expire_time = qemu_get_clock(vm_clock) + (ticks_per_sec / FRAME_TIMER_FREQ); qemu_mod_timer(s->frame_timer, expire_time); } -static void uhci_map(PCIDevice *pci_dev, int region_num, +static void uhci_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { UHCIState *s = (UHCIState *)pci_dev; @@ -807,7 +807,7 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn) pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 4; // interrupt pin 3 pci_conf[0x60] = 0x10; // release number - + for(i = 0; i < NB_PORTS; i++) { qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); } @@ -817,7 +817,7 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn) /* Use region 4 for consistency with real hardware. BSD guests seem to rely on this. */ - pci_register_io_region(&s->dev, 4, 0x20, + pci_register_io_region(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); } diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index 0acafaa88..99b8f9eb7 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -78,7 +78,7 @@ static const uint8_t qemu_wacom_config_descriptor[] = { 0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bConfigurationValue; */ 0x00, /* u8 iConfiguration; */ - 0x80, /* u8 bmAttributes; + 0x80, /* u8 bmAttributes; Bit 7: must be set, 6: Self-powered, 5: Remote wakeup, @@ -272,12 +272,12 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value, case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch (value >> 8) { case USB_DT_DEVICE: - memcpy(data, qemu_wacom_dev_descriptor, + memcpy(data, qemu_wacom_dev_descriptor, sizeof(qemu_wacom_dev_descriptor)); ret = sizeof(qemu_wacom_dev_descriptor); break; case USB_DT_CONFIG: - memcpy(data, qemu_wacom_config_descriptor, + memcpy(data, qemu_wacom_config_descriptor, sizeof(qemu_wacom_config_descriptor)); ret = sizeof(qemu_wacom_config_descriptor); break; diff --git a/hw/usb.c b/hw/usb.c index 17cb8df36..75e5a808d 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -2,7 +2,7 @@ * QEMU USB emulation * * Copyright (c) 2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -31,7 +31,7 @@ void usb_attach(USBPort *port, USBDevice *dev) /**********************/ /* generic USB device helpers (you are not forced to use them when writing your USB device driver, but they help handling the - protocol) + protocol) */ #define SETUP_STATE_IDLE 0 @@ -66,7 +66,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p) s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; s->setup_index = 0; if (s->setup_buf[0] & USB_DIR_IN) { - ret = s->handle_control(s, + ret = s->handle_control(s, (s->setup_buf[0] << 8) | s->setup_buf[1], (s->setup_buf[3] << 8) | s->setup_buf[2], (s->setup_buf[5] << 8) | s->setup_buf[4], @@ -93,7 +93,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p) case SETUP_STATE_ACK: if (!(s->setup_buf[0] & USB_DIR_IN)) { s->setup_state = SETUP_STATE_IDLE; - ret = s->handle_control(s, + ret = s->handle_control(s, (s->setup_buf[0] << 8) | s->setup_buf[1], (s->setup_buf[3] << 8) | s->setup_buf[2], (s->setup_buf[5] << 8) | s->setup_buf[4], diff --git a/hw/usb.h b/hw/usb.h index 868118acb..17832cf37 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -1,8 +1,8 @@ /* * QEMU USB API - * + * * Copyright (c) 2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -30,7 +30,7 @@ #define USB_MSG_DETACH 0x101 #define USB_MSG_RESET 0x102 -#define USB_RET_NODEV (-1) +#define USB_RET_NODEV (-1) #define USB_RET_NAK (-2) #define USB_RET_STALL (-3) #define USB_RET_BABBLE (-4) @@ -119,7 +119,7 @@ struct USBDevice { void (*handle_destroy)(USBDevice *dev); int speed; - + /* The following fields are used by the generic USB device layer. They are here just to avoid creating a new structure for them. */ @@ -129,7 +129,7 @@ struct USBDevice { int (*handle_data)(USBDevice *dev, USBPacket *p); uint8_t addr; char devname[32]; - + int state; uint8_t setup_buf[8]; uint8_t data_buf[1024]; diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 98a2f4fb1..68f18ef3f 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -1,4 +1,4 @@ -/* +/* * ARM Versatile/PB PCI host controller * * Copyright (c) 2006 CodeSourcery. diff --git a/hw/versatilepb.c b/hw/versatilepb.c index f0142adc5..2e3dedd81 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -1,4 +1,4 @@ -/* +/* * ARM Versatile Platform/Application Baseboard System emulation. * * Copyright (c) 2005-2007 CodeSourcery. diff --git a/hw/vga.c b/hw/vga.c index b2c6bc8c0..de74764e5 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1,8 +1,8 @@ /* * QEMU VGA Emulator. - * + * * 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 @@ -166,7 +166,7 @@ static uint32_t vga_ioport_read(void *opaque, uint32_t addr) break; case 0x3c1: index = s->ar_index & 0x1f; - if (index < 21) + if (index < 21) val = s->ar[index]; else val = 0; @@ -390,11 +390,11 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) val = VBE_DISPI_MAX_BPP; break; default: - val = s->vbe_regs[s->vbe_index]; + val = s->vbe_regs[s->vbe_index]; break; } } else { - val = s->vbe_regs[s->vbe_index]; + val = s->vbe_regs[s->vbe_index]; } } else { val = 0; @@ -442,7 +442,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) case VBE_DISPI_INDEX_BPP: if (val == 0) val = 8; - if (val == 4 || val == 8 || val == 15 || + if (val == 4 || val == 8 || val == 15 || val == 16 || val == 24 || val == 32) { s->vbe_regs[s->vbe_index] = val; } @@ -461,26 +461,26 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { int h, shift_control; - s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = + s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = s->vbe_regs[VBE_DISPI_INDEX_XRES]; - s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = + s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = s->vbe_regs[VBE_DISPI_INDEX_YRES]; s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; - + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1; else - s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * + s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); s->vbe_start_addr = 0; /* clear the screen (should be done in BIOS) */ if (!(val & VBE_DISPI_NOCLEARMEM)) { - memset(s->vram_ptr, 0, + memset(s->vram_ptr, 0, s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); } - + /* we initialize the VGA graphic mode (should be done in BIOS) */ s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */ @@ -491,13 +491,13 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) /* height (only meaningful if < 1024) */ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; s->cr[0x12] = h; - s->cr[0x07] = (s->cr[0x07] & ~0x42) | + s->cr[0x07] = (s->cr[0x07] & ~0x42) | ((h >> 7) & 0x02) | ((h >> 3) & 0x40); /* line compare to 1023 */ s->cr[0x18] = 0xff; s->cr[0x07] |= 0x10; s->cr[0x09] |= 0x40; - + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { shift_control = 0; s->sr[0x01] &= ~8; /* no double line */ @@ -562,7 +562,7 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) VGAState *s = opaque; int memory_map_mode, plane; uint32_t ret; - + /* convert to VGA memory offset */ memory_map_mode = (s->gr[6] >> 2) & 3; addr &= 0x1ffff; @@ -586,7 +586,7 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) return 0xff; break; } - + if (s->sr[4] & 0x08) { /* chain 4 mode : simplest access */ ret = s->vram_ptr[addr]; @@ -676,7 +676,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) return; break; } - + if (s->sr[4] & 0x08) { /* chain 4 mode : simplest access */ plane = addr & 3; @@ -767,11 +767,11 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) mask = s->sr[2]; s->plane_updated |= mask; /* only used to detect font change */ write_mask = mask16[mask]; - ((uint32_t *)s->vram_ptr)[addr] = - (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | + ((uint32_t *)s->vram_ptr)[addr] = + (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | (val & write_mask); #ifdef DEBUG_VGA_MEM - printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", + printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", addr * 4, write_mask, val); #endif cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2)); @@ -808,9 +808,9 @@ typedef void vga_draw_glyph8_func(uint8_t *d, int linesize, const uint8_t *font_ptr, int h, uint32_t fgcol, uint32_t bgcol); typedef void vga_draw_glyph9_func(uint8_t *d, int linesize, - const uint8_t *font_ptr, int h, + const uint8_t *font_ptr, int h, uint32_t fgcol, uint32_t bgcol, int dup9); -typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, +typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, const uint8_t *s, int width); #define DEPTH 8 @@ -909,8 +909,8 @@ static int update_palette16(VGAState *s) else v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); v = v * 3; - col = s->rgb_to_pixel(c6_to_8(s->palette[v]), - c6_to_8(s->palette[v + 1]), + col = s->rgb_to_pixel(c6_to_8(s->palette[v]), + c6_to_8(s->palette[v + 1]), c6_to_8(s->palette[v + 2])); if (col != palette[i]) { full_update = 1; @@ -931,12 +931,12 @@ static int update_palette256(VGAState *s) v = 0; for(i = 0; i < 256; i++) { if (s->dac_8bit) { - col = s->rgb_to_pixel(s->palette[v], - s->palette[v + 1], + col = s->rgb_to_pixel(s->palette[v], + s->palette[v + 1], s->palette[v + 2]); } else { - col = s->rgb_to_pixel(c6_to_8(s->palette[v]), - c6_to_8(s->palette[v + 1]), + col = s->rgb_to_pixel(c6_to_8(s->palette[v]), + c6_to_8(s->palette[v + 1]), c6_to_8(s->palette[v + 2])); } if (col != palette[i]) { @@ -948,8 +948,8 @@ static int update_palette256(VGAState *s) return full_update; } -static void vga_get_offsets(VGAState *s, - uint32_t *pline_offset, +static void vga_get_offsets(VGAState *s, + uint32_t *pline_offset, uint32_t *pstart_addr, uint32_t *pline_compare) { @@ -961,7 +961,7 @@ static void vga_get_offsets(VGAState *s, line_compare = 65535; } else #endif - { + { /* compute line_offset in bytes */ line_offset = s->cr[0x13]; line_offset <<= 3; @@ -970,7 +970,7 @@ static void vga_get_offsets(VGAState *s, start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); /* line compare */ - line_compare = s->cr[0x18] | + line_compare = s->cr[0x18] | ((s->cr[0x07] & 0x10) << 4) | ((s->cr[0x09] & 0x40) << 3); } @@ -984,7 +984,7 @@ static int update_basic_params(VGAState *s) { int full_update; uint32_t start_addr, line_offset, line_compare; - + full_update = 0; s->get_offsets(s, &line_offset, &start_addr, &line_compare); @@ -1055,7 +1055,7 @@ static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { vga_draw_glyph9_16, vga_draw_glyph9_16, }; - + static const uint8_t cursor_glyph[32 * 4] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -1073,13 +1073,13 @@ static const uint8_t cursor_glyph[32 * 4] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; +}; -/* - * Text mode update +/* + * Text mode update * Missing: * - double scan - * - double width + * - double width * - underline * - flashing */ @@ -1098,7 +1098,7 @@ static void vga_draw_text(VGAState *s, int full_update) full_update |= update_palette16(s); palette = s->last_palette; - + /* compute font data address (in plane 2) */ v = s->sr[3]; offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; @@ -1138,8 +1138,8 @@ static void vga_draw_text(VGAState *s, int full_update) /* ugly hack for CGA 160x100x16 - explain me the logic */ height = 100; } else { - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | ((s->cr[0x07] & 0x40) << 3); height = (height + 1) / cheight; } @@ -1174,14 +1174,14 @@ static void vga_draw_text(VGAState *s, int full_update) s->cursor_end = s->cr[0xb]; } cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; - + depth_index = get_depth_index(s->ds); if (cw == 16) vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; else vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; - + dest = s->ds->data; linesize = s->ds->linesize; ch_attr_ptr = s->last_ch_attr; @@ -1210,13 +1210,13 @@ static void vga_draw_text(VGAState *s, int full_update) bgcol = palette[cattr >> 4]; fgcol = palette[cattr & 0x0f]; if (cw != 9) { - vga_draw_glyph8(d1, linesize, + vga_draw_glyph8(d1, linesize, font_ptr, cheight, fgcol, bgcol); } else { dup9 = 0; if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04)) dup9 = 1; - vga_draw_glyph9(d1, linesize, + vga_draw_glyph9(d1, linesize, font_ptr, cheight, fgcol, bgcol, dup9); } if (src == cursor_ptr && @@ -1232,10 +1232,10 @@ static void vga_draw_text(VGAState *s, int full_update) h = line_last - line_start + 1; d = d1 + linesize * line_start; if (cw != 9) { - vga_draw_glyph8(d, linesize, + vga_draw_glyph8(d, linesize, cursor_glyph, h, fgcol, bgcol); } else { - vga_draw_glyph9(d, linesize, + vga_draw_glyph9(d, linesize, cursor_glyph, h, fgcol, bgcol, 1); } } @@ -1246,7 +1246,7 @@ static void vga_draw_text(VGAState *s, int full_update) ch_attr_ptr++; } if (cx_max != -1) { - dpy_update(s->ds, cx_min * cw, cy * cheight, + dpy_update(s->ds, cx_min * cw, cy * cheight, (cx_max - cx_min + 1) * cw, cheight); } dest += linesize * cheight; @@ -1368,7 +1368,7 @@ static int vga_get_bpp(VGAState *s) #ifdef CONFIG_BOCHS_VBE if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; - } else + } else #endif { ret = 0; @@ -1379,17 +1379,17 @@ static int vga_get_bpp(VGAState *s) static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight) { int width, height; - + #ifdef CONFIG_BOCHS_VBE if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; - } else + } else #endif { width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | + height = s->cr[0x12] | + ((s->cr[0x07] & 0x02) << 7) | ((s->cr[0x07] & 0x40) << 3); height = (height + 1); } @@ -1409,7 +1409,7 @@ void vga_invalidate_scanlines(VGAState *s, int y1, int y2) } } -/* +/* * graphic modes */ static void vga_draw_graphic(VGAState *s, int full_update) @@ -1420,7 +1420,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) uint8_t *d; uint32_t v, addr1, addr; vga_draw_line_func *vga_draw_line; - + full_update |= update_basic_params(s); s->get_resolution(s, &width, &height); @@ -1442,7 +1442,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) s->shift_control = shift_control; s->double_scan = double_scan; } - + if (shift_control == 0) { full_update |= update_palette16(s); if (s->sr[0x01] & 8) { @@ -1497,7 +1497,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) } if (s->cursor_invalidate) s->cursor_invalidate(s); - + line_offset = s->line_offset; #if 0 printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", @@ -1524,12 +1524,12 @@ static void vga_draw_graphic(VGAState *s, int full_update) } page0 = s->vram_offset + (addr & TARGET_PAGE_MASK); page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK); - update = full_update | + update = full_update | cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) | cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG); if ((page1 - page0) > TARGET_PAGE_SIZE) { /* if wide line, can use another page */ - update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, + update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, VGA_DIRTY_FLAG); } /* explicit invalidation for the hardware cursor */ @@ -1547,7 +1547,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) } else { if (y_start >= 0) { /* flush to display */ - dpy_update(s->ds, 0, y_start, + dpy_update(s->ds, 0, y_start, disp_width, y - y_start); y_start = -1; } @@ -1568,7 +1568,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) } if (y_start >= 0) { /* flush to display */ - dpy_update(s->ds, 0, y_start, + dpy_update(s->ds, 0, y_start, disp_width, y - y_start); } /* reset modified pages */ @@ -1588,7 +1588,7 @@ static void vga_draw_blank(VGAState *s, int full_update) return; if (s->last_scr_width <= 0 || s->last_scr_height <= 0) return; - if (s->ds->depth == 8) + if (s->ds->depth == 8) val = s->rgb_to_pixel(0, 0, 0); else val = 0; @@ -1598,13 +1598,13 @@ static void vga_draw_blank(VGAState *s, int full_update) memset(d, val, w); d += s->ds->linesize; } - dpy_update(s->ds, 0, 0, + dpy_update(s->ds, 0, 0, s->last_scr_width, s->last_scr_height); } #define GMODE_TEXT 0 #define GMODE_GRAPH 1 -#define GMODE_BLANK 2 +#define GMODE_BLANK 2 static void vga_update_display(void *opaque) { @@ -1614,9 +1614,9 @@ static void vga_update_display(void *opaque) if (s->ds->depth == 0) { /* nothing to do */ } else { - s->rgb_to_pixel = + s->rgb_to_pixel = rgb_to_pixel_dup_table[get_depth_index(s->ds)]; - + full_update = 0; if (!(s->ar_index & 0x20)) { graphic_mode = GMODE_BLANK; @@ -1646,7 +1646,7 @@ static void vga_update_display(void *opaque) static void vga_invalidate_display(void *opaque) { VGAState *s = (VGAState *)opaque; - + s->last_width = -1; s->last_height = -1; } @@ -1775,7 +1775,7 @@ typedef struct PCIVGAState { VGAState vga_state; } PCIVGAState; -static void vga_map(PCIDevice *pci_dev, int region_num, +static void vga_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type) { PCIVGAState *d = (PCIVGAState *)pci_dev; @@ -1787,7 +1787,7 @@ static void vga_map(PCIDevice *pci_dev, int region_num, } } -void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, +void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { int i, j, v, b; @@ -1866,7 +1866,7 @@ void vga_init(VGAState *s) register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s); register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s); - register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); + register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); #else register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s); register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s); @@ -1877,7 +1877,7 @@ void vga_init(VGAState *s) #endif /* CONFIG_BOCHS_VBE */ vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); - cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, + cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, vga_io_memory); } @@ -1956,7 +1956,7 @@ static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base, cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory); } -int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, +int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size) { VGAState *s; @@ -1972,7 +1972,7 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, #ifdef CONFIG_BOCHS_VBE /* XXX: use optimized standard vga accesses */ - cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, + cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, vga_ram_size, vga_ram_offset); #endif return 0; @@ -2002,39 +2002,39 @@ int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, return 0; } -int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, +int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size, unsigned long vga_bios_offset, int vga_bios_size) { PCIVGAState *d; VGAState *s; uint8_t *pci_conf; - - d = (PCIVGAState *)pci_register_device(bus, "VGA", + + d = (PCIVGAState *)pci_register_device(bus, "VGA", sizeof(PCIVGAState), -1, NULL, NULL); if (!d) return -1; s = &d->vga_state; - + vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); vga_init(s); graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); s->pci_dev = &d->dev; - + pci_conf = d->dev.config; pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID) pci_conf[0x01] = 0x12; pci_conf[0x02] = 0x11; pci_conf[0x03] = 0x11; - pci_conf[0x0a] = 0x00; // VGA controller + pci_conf[0x0a] = 0x00; // VGA controller pci_conf[0x0b] = 0x03; pci_conf[0x0e] = 0x00; // header_type - + /* XXX: vga_ram_size must be a power of two */ - pci_register_io_region(&d->dev, 0, vga_ram_size, + pci_register_io_region(&d->dev, 0, vga_ram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); if (vga_bios_size != 0) { unsigned int bios_total_size; @@ -2044,7 +2044,7 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, bios_total_size = 1; while (bios_total_size < vga_bios_size) bios_total_size <<= 1; - pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size, + pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); } return 0; @@ -2055,7 +2055,7 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, static int vga_save_w, vga_save_h; -static void vga_save_dpy_update(DisplayState *s, +static void vga_save_dpy_update(DisplayState *s, int x, int y, int w, int h) { } @@ -2072,7 +2072,7 @@ static void vga_save_dpy_refresh(DisplayState *s) { } -int ppm_save(const char *filename, uint8_t *data, +int ppm_save(const char *filename, uint8_t *data, int w, int h, int linesize) { FILE *f; @@ -2107,7 +2107,7 @@ static void vga_screen_dump(void *opaque, const char *filename) { VGAState *s = (VGAState *)opaque; DisplayState *saved_ds, ds1, *ds = &ds1; - + /* XXX: this is a little hackish */ vga_invalidate_display(s); saved_ds = s->ds; @@ -2121,9 +2121,9 @@ static void vga_screen_dump(void *opaque, const char *filename) s->ds = ds; s->graphic_mode = -1; vga_update_display(s); - + if (ds->data) { - ppm_save(filename, ds->data, vga_save_w, vga_save_h, + ppm_save(filename, ds->data, vga_save_w, vga_save_h, s->ds->linesize); qemu_free(ds->data); } diff --git a/hw/vga_int.h b/hw/vga_int.h index 2a4e9b981..3eb4e29dc 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -1,8 +1,8 @@ /* * QEMU internal VGA defines. - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -45,20 +45,20 @@ #define VBE_DISPI_INDEX_X_OFFSET 0x8 #define VBE_DISPI_INDEX_Y_OFFSET 0x9 #define VBE_DISPI_INDEX_NB 0xa - + #define VBE_DISPI_ID0 0xB0C0 #define VBE_DISPI_ID1 0xB0C1 #define VBE_DISPI_ID2 0xB0C2 #define VBE_DISPI_ID3 0xB0C3 #define VBE_DISPI_ID4 0xB0C4 - + #define VBE_DISPI_DISABLED 0x00 #define VBE_DISPI_ENABLED 0x01 #define VBE_DISPI_GETCAPS 0x02 #define VBE_DISPI_8BIT_DAC 0x20 #define VBE_DISPI_LFB_ENABLED 0x40 #define VBE_DISPI_NOCLEARMEM 0x80 - + #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 #ifdef CONFIG_BOCHS_VBE @@ -160,25 +160,25 @@ static inline int c6_to_8(int v) return (v << 2) | (b << 1) | b; } -void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, +void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); void vga_init(VGAState *s); uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr); void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val); void vga_invalidate_scanlines(VGAState *s, int y1, int y2); -int ppm_save(const char *filename, uint8_t *data, +int ppm_save(const char *filename, uint8_t *data, int w, int h, int linesize); -void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1, - int poffset, int w, +void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1, + int poffset, int w, unsigned int color0, unsigned int color1, unsigned int color_xor); -void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1, - int poffset, int w, +void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1, + int poffset, int w, unsigned int color0, unsigned int color1, unsigned int color_xor); -void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1, - int poffset, int w, +void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1, + int poffset, int w, unsigned int color0, unsigned int color1, unsigned int color_xor); diff --git a/hw/vga_template.h b/hw/vga_template.h index e7e8cb853..41f6e25f2 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -1,8 +1,8 @@ /* * QEMU VGA Emulator templates - * + * * 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 @@ -24,13 +24,13 @@ #if DEPTH == 8 #define BPP 1 -#define PIXEL_TYPE uint8_t +#define PIXEL_TYPE uint8_t #elif DEPTH == 15 || DEPTH == 16 #define BPP 2 -#define PIXEL_TYPE uint16_t +#define PIXEL_TYPE uint16_t #elif DEPTH == 32 #define BPP 4 -#define PIXEL_TYPE uint32_t +#define PIXEL_TYPE uint32_t #else #error unsupport depth #endif @@ -43,9 +43,9 @@ #if DEPTH != 15 && !defined(BGR_FORMAT) -static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, +static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, uint32_t font_data, - uint32_t xorcol, + uint32_t xorcol, uint32_t bgcol) { #if BPP == 1 @@ -73,7 +73,7 @@ static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, uint32_t fgcol, uint32_t bgcol) { uint32_t font_data, xorcol; - + xorcol = bgcol ^ fgcol; do { font_data = font_ptr[0]; @@ -88,15 +88,15 @@ static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize, uint32_t fgcol, uint32_t bgcol) { uint32_t font_data, xorcol; - + xorcol = bgcol ^ fgcol; do { font_data = font_ptr[0]; - glue(vga_draw_glyph_line_, DEPTH)(d, - expand4to8[font_data >> 4], + glue(vga_draw_glyph_line_, DEPTH)(d, + expand4to8[font_data >> 4], xorcol, bgcol); - glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP, - expand4to8[font_data & 0x0f], + glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP, + expand4to8[font_data & 0x0f], xorcol, bgcol); font_ptr += 4; d += linesize; @@ -104,11 +104,11 @@ static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize, } static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, - const uint8_t *font_ptr, int h, + const uint8_t *font_ptr, int h, uint32_t fgcol, uint32_t bgcol, int dup9) { uint32_t font_data, xorcol, v; - + xorcol = bgcol ^ fgcol; do { font_data = font_ptr[0]; @@ -120,7 +120,7 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, ((uint8_t *)d)[8] = v >> (24 * (1 - BIG)); else ((uint8_t *)d)[8] = bgcol; - + #elif BPP == 2 cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol); cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol); @@ -151,10 +151,10 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, } while (--h); } -/* +/* * 4 color mode */ -static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { uint32_t plane_mask, *palette, data, v; @@ -193,10 +193,10 @@ static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, ((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v) #endif -/* +/* * 4 color mode, dup2 horizontal */ -static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { uint32_t plane_mask, *palette, data, v; @@ -226,10 +226,10 @@ static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d, } } -/* +/* * 16 color mode */ -static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { uint32_t plane_mask, data, v, *palette; @@ -258,10 +258,10 @@ static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, } } -/* +/* * 16 color mode, dup2 horizontal */ -static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { uint32_t plane_mask, data, v, *palette; @@ -290,12 +290,12 @@ static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d, } } -/* +/* * 256 color mode, double pixels * * XXX: add plane_mask support (never used in standard VGA modes) */ -static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { uint32_t *palette; @@ -313,12 +313,12 @@ static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d, } } -/* +/* * standard 256 color mode * * XXX: add plane_mask support (never used in standard VGA modes) */ -static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { uint32_t *palette; @@ -340,10 +340,10 @@ static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, } } -void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, - const uint8_t *src1, +void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, + const uint8_t *src1, int poffset, int w, - unsigned int color0, + unsigned int color0, unsigned int color1, unsigned int color_xor) { @@ -411,10 +411,10 @@ void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, /* XXX: optimize */ -/* +/* * 15 bit color */ -static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { #if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) @@ -433,13 +433,13 @@ static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d, s += 2; d += BPP; } while (--w != 0); -#endif +#endif } -/* +/* * 16 bit color */ -static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { #if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) @@ -458,13 +458,13 @@ static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d, s += 2; d += BPP; } while (--w != 0); -#endif +#endif } -/* +/* * 24 bit color */ -static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { int w; @@ -487,10 +487,10 @@ static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d, } while (--w != 0); } -/* +/* * 32 bit color */ -static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d, +static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d, const uint8_t *s, int width) { #if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT) diff --git a/hw/vmmouse.c b/hw/vmmouse.c index 52c8e0c78..3c4f6671b 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -1,8 +1,8 @@ /* * QEMU VMMouse emulation - * + * * Copyright (C) 2007 Anthony Liguori - * + * * 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 diff --git a/keymaps.c b/keymaps.c index bd893288a..f0f8c103d 100644 --- a/keymaps.c +++ b/keymaps.c @@ -1,8 +1,8 @@ /* * QEMU keysym to keycode conversion using rdesktop keymaps - * + * * Copyright (c) 2004 Johannes 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 diff --git a/keymaps/common b/keymaps/common index 0b53f1c25..adc56c77d 100644 --- a/keymaps/common +++ b/keymaps/common @@ -82,7 +82,7 @@ F12 0x58 localstate # Printscreen, Scrollock and Pause # Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37), -# but (0xe0, 0x37) seems to work. +# but (0xe0, 0x37) seems to work. Print 0xb7 localstate Sys_Req 0xb7 localstate Execute 0xb7 localstate diff --git a/keymaps/de-ch b/keymaps/de-ch index f83837b44..852f8b8db 100644 --- a/keymaps/de-ch +++ b/keymaps/de-ch @@ -1,5 +1,5 @@ -# rdesktop Swiss-German (de-ch) keymap file -# 2003-06-03 by noldi@tristar.ch +# rdesktop Swiss-German (de-ch) keymap file +# 2003-06-03 by noldi@tristar.ch # include common map 0x00000807 @@ -40,7 +40,7 @@ bar 0x08 altgr # Scan Code 9 parenleft 0x09 shift cent 0x09 altgr -# +# # Scan Code 10 parenright 0x0a shift # @@ -49,7 +49,7 @@ equal 0x0b shift braceright 0x0b altgr inhibit # # Scan Code 12 -apostrophe 0x0c +apostrophe 0x0c question 0x0c shift dead_acute 0x0c altgr # @@ -68,10 +68,10 @@ z 0x15 addupper udiaeresis 0x1a egrave 0x1a shift bracketleft 0x1a altgr -# +# # Scan Code 28 dead_diaeresis 0x1b -exclam 0x1b shift +exclam 0x1b shift bracketright 0x1b altgr # # Scan Code 40 @@ -93,17 +93,17 @@ backslash 0x56 altgr # # Scan Code 46 y 0x2c addupper -# +# # Scan Code 53 comma 0x33 semicolon 0x33 shift -# +# # Scan Code 54 period 0x34 colon 0x34 shift # # Scan Code 55 -minus 0x35 +minus 0x35 underscore 0x35 shift # # Suppress Windows unsupported AltGr keys diff --git a/keymaps/et b/keymaps/et index b5a73fef7..3252e31c3 100644 --- a/keymaps/et +++ b/keymaps/et @@ -50,9 +50,9 @@ dead_grave 0xd shift # QWERTY first row # EuroSign 0x12 altgr -udiaeresis 0x1a +udiaeresis 0x1a Udiaeresis 0x1a shift -otilde 0x1b +otilde 0x1b Otilde 0x1b shift section 0x1b altgr @@ -61,9 +61,9 @@ section 0x1b altgr # scaron 0x1f altgr Scaron 0x1f altgr shift -odiaeresis 0x27 +odiaeresis 0x27 Odiaeresis 0x27 shift -adiaeresis 0x28 +adiaeresis 0x28 Adiaeresis 0x28 shift asciicircum 0x28 altgr apostrophe 0x2b @@ -72,7 +72,7 @@ onehalf 0x2b altgr # # QWERTY third row # -less 0x56 +less 0x56 greater 0x56 shift bar 0x56 altgr zcaron 0x2c altgr diff --git a/keymaps/fr b/keymaps/fr index cbb45910f..ba5a176c3 100644 --- a/keymaps/fr +++ b/keymaps/fr @@ -97,7 +97,7 @@ Ooblique 0x18 shift altgr thorn 0x19 altgr THORN 0x19 shift altgr -dead_circumflex 0x1a +dead_circumflex 0x1a dead_diaeresis 0x1a shift dead_abovering 0x1a shift altgr diff --git a/keymaps/is b/keymaps/is index 8fde40f19..d512cf666 100644 --- a/keymaps/is +++ b/keymaps/is @@ -1,6 +1,6 @@ -# 2004-03-16 Halldr Gumundsson and Morten Lange +# 2004-03-16 Halldr Gumundsson and Morten Lange # Keyboard definition file for the Icelandic keyboard -# to be used in rdesktop 1.3.x ( See rdesktop.org) +# to be used in rdesktop 1.3.x ( See rdesktop.org) # generated from XKB map de, and changed manually # Location for example /usr/local/share/rdesktop/keymaps/is include common @@ -71,8 +71,8 @@ Ooblique 0x18 shift altgr #Udiaeresis 0x1a shift #dead_diaeresis 0x1a altgr #dead_abovering 0x1a shift altgr -eth 0x1a -ETH 0x1a shift +eth 0x1a +ETH 0x1a shift apostrophe 0x1b question 0x1b shift #plus 0x1b @@ -84,9 +84,9 @@ asciitilde 0x1b altgr #ae 0x1e altgr #AE 0x1e shift altgr #eth 0x20 altgr -#eth 0x20 +#eth 0x20 #ETH 0x20 shift altgr -#ETH 0x20 shift +#ETH 0x20 shift dstroke 0x21 altgr ordfeminine 0x21 shift altgr eng 0x22 altgr @@ -96,8 +96,8 @@ Hstroke 0x23 shift altgr kra 0x25 altgr #adiaeresis 0x27 #Adiaeresis 0x27 shift -ae 0x27 -AE 0x27 shift +ae 0x27 +AE 0x27 shift dead_doubleacute 0x27 altgr #adiaeresis 0x28 #Adiaeresis 0x28 shift @@ -133,8 +133,8 @@ periodcentered 0x34 altgr division 0x34 shift altgr #minus 0x35 #underscore 0x35 shift -thorn 0x35 -THORN 0x35 shift +thorn 0x35 +THORN 0x35 shift dead_belowdot 0x35 altgr dead_abovedot 0x35 shift altgr diff --git a/keymaps/modifiers b/keymaps/modifiers index d8b019f04..84a04d651 100644 --- a/keymaps/modifiers +++ b/keymaps/modifiers @@ -8,10 +8,10 @@ Alt_L 0x38 Control_R 0x9d Control_L 0x1d -# Translate Super to Windows keys. -# This is hardcoded. See documentation for details. +# Translate Super to Windows keys. +# This is hardcoded. See documentation for details. Super_R 0xdb Super_L 0xdc -# Translate Menu to the Windows Application key. +# Translate Menu to the Windows Application key. Menu 0xdd diff --git a/keymaps/nl b/keymaps/nl index bc823bd2f..4f0fe3df7 100644 --- a/keymaps/nl +++ b/keymaps/nl @@ -45,7 +45,7 @@ less 0x2b greater 0x2b shift guillemotleft 0x2c altgr guillemotright 0x2d altgr -copyright 0x2e altgr +copyright 0x2e altgr mu 0x32 altgr comma 0x33 semicolon 0x33 shift diff --git a/keymaps/sv b/keymaps/sv index 736d637b3..9905a48db 100644 --- a/keymaps/sv +++ b/keymaps/sv @@ -50,18 +50,18 @@ dead_grave 0xd shift # QWERTY first row # EuroSign 0x12 altgr -aring 0x1a +aring 0x1a Aring 0x1a shift -dead_diaeresis 0x1b +dead_diaeresis 0x1b dead_circumflex 0x1b shift dead_tilde 0x1b altgr # # QWERTY second row # -odiaeresis 0x27 +odiaeresis 0x27 Odiaeresis 0x27 shift -adiaeresis 0x28 +adiaeresis 0x28 Adiaeresis 0x28 shift apostrophe 0x2b asterisk 0x2b shift diff --git a/kqemu.c b/kqemu.c index c6b2e6950..7df69309b 100644 --- a/kqemu.c +++ b/kqemu.c @@ -1,6 +1,6 @@ /* * KQEMU support - * + * * Copyright (c) 2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -129,9 +129,9 @@ static void kqemu_update_cpuid(CPUState *env) target cpus because they are important for user code. Strictly speaking, only SSE really matters because the OS must support it if the user code uses it. */ - critical_features_mask = - CPUID_CMOV | CPUID_CX8 | - CPUID_FXSR | CPUID_MMX | CPUID_SSE | + critical_features_mask = + CPUID_CMOV | CPUID_CX8 | + CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_SEP; ext_features_mask = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR; if (!is_cpuid_supported()) { @@ -194,17 +194,17 @@ int kqemu_init(CPUState *env) goto fail; } - pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * + pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * sizeof(unsigned long)); if (!pages_to_flush) goto fail; - ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE * + ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE * sizeof(unsigned long)); if (!ram_pages_to_update) goto fail; - modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES * + modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES * sizeof(unsigned long)); if (!modified_ram_pages) goto fail; @@ -286,7 +286,7 @@ static void kqemu_reset_modified_ram_pages(void) { int i; unsigned long page_index; - + for(i = 0; i < nb_modified_ram_pages; i++) { page_index = modified_ram_pages[i] >> TARGET_PAGE_BITS; modified_ram_pages_table[page_index] = 0; @@ -312,12 +312,12 @@ void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr) if (nb_modified_ram_pages >= KQEMU_MAX_MODIFIED_RAM_PAGES) { /* flush */ #ifdef _WIN32 - ret = DeviceIoControl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, - &nb_modified_ram_pages, + ret = DeviceIoControl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, + &nb_modified_ram_pages, sizeof(nb_modified_ram_pages), NULL, 0, &temp, NULL); #else - ret = ioctl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, + ret = ioctl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, &nb_modified_ram_pages); #endif kqemu_reset_modified_ram_pages(); @@ -364,7 +364,7 @@ static void restore_native_fp_frstor(CPUState *env) { int fptag, i, j; struct fpstate fp1, *fp = &fp1; - + fp->fpuc = env->fpuc; fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; fptag = 0; @@ -384,7 +384,7 @@ static void restore_native_fp_frstor(CPUState *env) } asm volatile ("frstor %0" : "=m" (*fp)); } - + static void save_native_fp_fsave(CPUState *env) { int fptag, i, j; @@ -470,7 +470,7 @@ static int do_syscall(CPUState *env, struct kqemu_cpu_state *kenv) { int selector; - + selector = (env->star >> 32) & 0xffff; #ifdef __x86_64__ if (env->hflags & HF_LMA_MASK) { @@ -482,12 +482,12 @@ static int do_syscall(CPUState *env, code64 = env->hflags & HF_CS64_MASK; cpu_x86_set_cpl(env, 0); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | @@ -497,18 +497,18 @@ static int do_syscall(CPUState *env, env->eip = env->lstar; else env->eip = env->cstar; - } else + } else #endif { env->regs[R_ECX] = (uint32_t)kenv->next_eip; - + cpu_x86_set_cpl(env, 0); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | @@ -605,7 +605,7 @@ void kqemu_record_dump(void) } } qsort(pr, nb_pc_records, sizeof(PCRecord *), pc_rec_cmp); - + f = fopen("/tmp/kqemu.stats", "w"); if (!f) { perror("/tmp/kqemu.stats"); @@ -616,9 +616,9 @@ void kqemu_record_dump(void) for(i = 0; i < nb_pc_records; i++) { r = pr[i]; sum += r->count; - fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n", - r->pc, - r->count, + fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n", + r->pc, + r->count, (double)r->count / (double)total * 100.0, (double)sum / (double)total * 100.0); } @@ -697,7 +697,7 @@ int kqemu_cpu_exec(CPUState *env) kenv->nb_ram_pages_to_update = nb_ram_pages_to_update; #endif nb_ram_pages_to_update = 0; - + #if KQEMU_VERSION >= 0x010300 kenv->nb_modified_ram_pages = nb_modified_ram_pages; #endif @@ -789,7 +789,7 @@ int kqemu_cpu_exec(CPUState *env) { unsigned int new_hflags; #ifdef TARGET_X86_64 - if ((env->hflags & HF_LMA_MASK) && + if ((env->hflags & HF_LMA_MASK) && (env->segs[R_CS].flags & DESC_L_MASK)) { /* long mode */ new_hflags = HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK; @@ -801,7 +801,7 @@ int kqemu_cpu_exec(CPUState *env) >> (DESC_B_SHIFT - HF_CS32_SHIFT); new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) >> (DESC_B_SHIFT - HF_SS32_SHIFT); - if (!(env->cr[0] & CR0_PE_MASK) || + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK) || !(env->hflags & HF_CS32_MASK)) { /* XXX: try to avoid this test. The problem comes from the @@ -811,13 +811,13 @@ int kqemu_cpu_exec(CPUState *env) translate-i386.c. */ new_hflags |= HF_ADDSEG_MASK; } else { - new_hflags |= ((env->segs[R_DS].base | + new_hflags |= ((env->segs[R_DS].base | env->segs[R_ES].base | - env->segs[R_SS].base) != 0) << + env->segs[R_SS].base) != 0) << HF_ADDSEG_SHIFT; } } - env->hflags = (env->hflags & + env->hflags = (env->hflags & ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) | new_hflags; } @@ -828,7 +828,7 @@ int kqemu_cpu_exec(CPUState *env) env->hflags |= HF_OSFXSR_MASK; else env->hflags &= ~HF_OSFXSR_MASK; - + #ifdef DEBUG if (loglevel & CPU_LOG_INT) { fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret); @@ -837,7 +837,7 @@ int kqemu_cpu_exec(CPUState *env) if (ret == KQEMU_RET_SYSCALL) { /* syscall instruction */ return do_syscall(env, kenv); - } else + } else if ((ret & 0xff00) == KQEMU_RET_INT) { env->exception_index = ret & 0xff; env->error_code = 0; @@ -848,7 +848,7 @@ int kqemu_cpu_exec(CPUState *env) #endif #ifdef DEBUG if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "kqemu: interrupt v=%02x:\n", + fprintf(logfile, "kqemu: interrupt v=%02x:\n", env->exception_index); cpu_dump_state(env, logfile, fprintf, 0); } @@ -880,7 +880,7 @@ int kqemu_cpu_exec(CPUState *env) } #endif return 0; - } else if (ret == KQEMU_RET_SOFTMMU) { + } else if (ret == KQEMU_RET_SOFTMMU) { #ifdef CONFIG_PROFILER { unsigned long pc = env->eip + env->segs[R_CS].base; @@ -904,7 +904,7 @@ int kqemu_cpu_exec(CPUState *env) void kqemu_cpu_interrupt(CPUState *env) { #if defined(_WIN32) && KQEMU_VERSION >= 0x010101 - /* cancelling the I/O request causes KQEMU to finish executing the + /* cancelling the I/O request causes KQEMU to finish executing the current block and successfully returning. */ CancelIo(kqemu_fd); #endif diff --git a/kqemu.h b/kqemu.h index 892e33593..7b43057e3 100644 --- a/kqemu.h +++ b/kqemu.h @@ -1,8 +1,8 @@ /* * KQEMU header - * + * * 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 @@ -91,7 +91,7 @@ struct kqemu_cpu_state { long retval; /* number of ram_dirty entries to update */ - unsigned int nb_ram_pages_to_update; + unsigned int nb_ram_pages_to_update; #define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512 #define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1) diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h index b39b6d8df..139a4cfcb 100644 --- a/linux-user/alpha/syscall_nr.h +++ b/linux-user/alpha/syscall_nr.h @@ -161,7 +161,7 @@ #define TARGET_NR_osf_fstatfs 161 #define TARGET_NR_osf_asynch_daemon 163 /* not implemented */ -#define TARGET_NR_osf_getfh 164 /* not implemented */ +#define TARGET_NR_osf_getfh 164 /* not implemented */ #define TARGET_NR_osf_getdomainname 165 #define TARGET_NR_setdomainname 166 @@ -329,7 +329,7 @@ #define TARGET_NR_lremovexattr 392 #define TARGET_NR_fremovexattr 393 #define TARGET_NR_futex 394 -#define TARGET_NR_sched_setaffinity 395 +#define TARGET_NR_sched_setaffinity 395 #define TARGET_NR_sched_getaffinity 396 #define TARGET_NR_tuxcall 397 #define TARGET_NR_io_setup 398 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 2a7bd703c..a3d8649ba 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -577,7 +577,7 @@ unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, size = x86_stack_size; if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; - error = target_mmap(0, + error = target_mmap(0, size + qemu_host_page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, @@ -637,7 +637,7 @@ static void padzero(unsigned long elf_bss, unsigned long last_bss) size must be known */ if (qemu_real_host_page_size < qemu_host_page_size) { unsigned long end_addr, end_addr1; - end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & + end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & ~(qemu_real_host_page_size - 1); end_addr = HOST_PAGE_ALIGN(elf_bss); if (end_addr1 < end_addr) { @@ -695,7 +695,7 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, size *= n; if (size & 15) sp -= 16 - (size & 15); - + #define NEW_AUX_ENT(id, val) do { \ sp -= n; tputl(sp, val); \ sp -= n; tputl(sp, id); \ @@ -718,7 +718,7 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO - /* + /* * ARCH_DLINFO must come last so platform specific code can enforce * special alignment requirements on the AUXV if necessary (eg. PPC). */ @@ -743,7 +743,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, unsigned long last_bss, elf_bss; unsigned long error; int i; - + elf_bss = 0; last_bss = 0; error = 0; @@ -752,24 +752,24 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, bswap_ehdr(interp_elf_ex); #endif /* First of all, some simple consistency checks */ - if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine)) { return ~0UL; } - + /* Now read in all of the header information */ - + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) return ~0UL; - - elf_phdata = (struct elf_phdr *) + + elf_phdata = (struct elf_phdr *) malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); if (!elf_phdata) return ~0UL; - + /* * If the size of this structure has changed, then punt, since * we will be doing the wrong thing. @@ -802,7 +802,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, /* in order to avoid hardcoding the interpreter load address in qemu, we allocate a big enough memory zone */ error = target_mmap(0, INTERP_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, + PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); if (error == -1) { perror("mmap"); @@ -833,7 +833,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, elf_type, interpreter_fd, eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); - + if (error == -1) { /* Real error */ close(interpreter_fd); @@ -860,7 +860,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; if (k > last_bss) last_bss = k; } - + /* Now use mmap to map the library into memory. */ close(interpreter_fd); @@ -932,7 +932,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) s->disas_strtab = strings = malloc(strtab.sh_size); if (!s->disas_symtab || !s->disas_strtab) return; - + lseek(fd, symtab.sh_offset, SEEK_SET); if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) return; @@ -1019,7 +1019,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); if(retval > 0) { - retval = read(bprm->fd, (char *) elf_phdata, + retval = read(bprm->fd, (char *) elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum); } @@ -1078,7 +1078,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, if(retval < 0) { perror("load_elf_binary2"); exit(-1); - } + } /* If the program interpreter is one of these two, then assume an iBCS2 image. Otherwise assume @@ -1199,10 +1199,10 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, int elf_prot = 0; int elf_flags = 0; unsigned long error; - + if (elf_ppnt->p_type != PT_LOAD) continue; - + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; @@ -1216,7 +1216,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* NOTE: for qemu, we do a big mmap to get enough space without hardcoding any address */ error = target_mmap(0, ET_DYN_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, + PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); if (error == -1) { perror("mmap"); @@ -1224,14 +1224,14 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); } - + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), (elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), elf_prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), bprm->fd, - (elf_ppnt->p_offset - + (elf_ppnt->p_offset - TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); if (error == -1) { perror("mmap"); @@ -1242,7 +1242,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); #endif - + if (!load_addr_set) { load_addr_set = 1; load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; @@ -1254,14 +1254,14 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } } k = elf_ppnt->p_vaddr; - if (k < start_code) + if (k < start_code) start_code = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if (k > elf_bss) + if (k > elf_bss) elf_bss = k; if ((elf_ppnt->p_flags & PF_X) && end_code < k) end_code = k; - if (end_data < k) + if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if (k > elf_brk) elf_brk = k; diff --git a/linux-user/flat.h b/linux-user/flat.h index 6d52b1ffe..1fdba514c 100644 --- a/linux-user/flat.h +++ b/linux-user/flat.h @@ -38,7 +38,7 @@ struct flat_hdr { target_ulong reloc_start; /* Offset of relocation records from beginning of file */ target_ulong reloc_count; /* Number of relocation records */ - target_ulong flags; + target_ulong flags; target_ulong build_date; /* When the program/library was built */ target_ulong filler[5]; /* Reservered, set to zero */ }; diff --git a/linux-user/flatload.c b/linux-user/flatload.c index bf10d7968..8e3bf73a6 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -359,7 +359,7 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl) "(address %p, currently %x) into segment %s\n", offset, ptr, (int)*ptr, segment[reloc_type]); #endif - + switch (reloc_type) { case OLD_FLAT_RELOC_TYPE_TEXT: *ptr += libinfo->start_code; @@ -376,7 +376,7 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl) break; } DBG_FLT("Relocation became %x\n", (int)*ptr); -} +} /****************************************************************************/ @@ -416,7 +416,7 @@ static int load_flat_file(struct linux_binprm * bprm, rev, (int) FLAT_VERSION); return -ENOEXEC; } - + /* Don't allow old format executables to use shared libraries */ if (rev == OLD_FLAT_VERSION && id != 0) { fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n"); @@ -463,7 +463,7 @@ static int load_flat_file(struct linux_binprm * bprm, textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC, MAP_PRIVATE, bprm->fd, 0); - if (textpos == -1) { + if (textpos == -1) { fprintf(stderr, "Unable to mmap process text\n"); return -1; } @@ -484,7 +484,7 @@ static int load_flat_file(struct linux_binprm * bprm, fpos = ntohl(hdr->data_start); #ifdef CONFIG_BINFMT_ZFLAT if (flags & FLAT_FLAG_GZDATA) { - result = decompress_exec(bprm, fpos, (char *) datapos, + result = decompress_exec(bprm, fpos, (char *) datapos, data_len + (relocs * sizeof(target_ulong))) } else #endif @@ -581,7 +581,7 @@ static int load_flat_file(struct linux_binprm * bprm, libinfo[id].loaded = 1; libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos; libinfo[id].build_date = ntohl(hdr->build_date); - + /* * We just load the allocations into some temporary memory to * help simplify all this mumbo jumbo @@ -662,7 +662,7 @@ static int load_flat_file(struct linux_binprm * bprm, old_reloc(&libinfo[0], relval); } } - + /* zero the BSS. */ memset((void*)(datapos + data_len), 0, bss_len); @@ -732,11 +732,11 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, stack_len += (bprm->argc + 1) * 4; /* the argv array */ stack_len += (bprm->envc + 1) * 4; /* the envp array */ - + res = load_flat_file(bprm, libinfo, 0, &stack_len); if (res > (unsigned long)-4096) return res; - + /* Update data segment pointers for all libraries */ for (i=0; ienvc, bprm->argc, sp, p, 1); - + /* Fake some return addresses to ensure the call chain will * initialise library in order for us. We are required to call * lib 1 first, then 2, ... and finally the main program (id 0). @@ -784,7 +784,7 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } } #endif - + /* Stash our initial stack pointer into the mm structure */ info->start_code = libinfo[0].start_code; info->end_code = libinfo[0].start_code = libinfo[0].text_len; @@ -798,6 +798,6 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n", (int)info->entry, (int)info->start_stack); - + return 0; } diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 34fa10d7c..8c29f8087 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -140,7 +140,7 @@ target_ulong loader_build_argptr(int envc, int argc, target_ulong sp, return sp; } -int loader_exec(const char * filename, char ** argv, char ** envp, +int loader_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop) { struct linux_binprm bprm; @@ -182,7 +182,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, return -1; } } - + if(retval>=0) { /* success. Initialize important registers */ do_init_thread(regs, infop); diff --git a/linux-user/m68k-sim.c b/linux-user/m68k-sim.c index 667808e8c..aab82dd7e 100644 --- a/linux-user/m68k-sim.c +++ b/linux-user/m68k-sim.c @@ -1,6 +1,6 @@ /* * m68k simulator syscall interface - * + * * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook. * * This program is free software; you can redistribute it and/or modify diff --git a/linux-user/main.c b/linux-user/main.c index edcb68b8d..e75bb8432 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1,6 +1,6 @@ /* * qemu user main - * + * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify @@ -131,7 +131,7 @@ uint64_t cpu_get_tsc(CPUX86State *env) return cpu_get_real_ticks(); } -static void write_dt(void *ptr, unsigned long addr, unsigned long limit, +static void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags) { unsigned int e1, e2; @@ -144,7 +144,7 @@ static void write_dt(void *ptr, unsigned long addr, unsigned long limit, p[1] = tswapl(e2); } -static void set_gate(void *ptr, unsigned int type, unsigned int dpl, +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, unsigned long addr, unsigned int sel) { unsigned int e1, e2; @@ -176,8 +176,8 @@ void cpu_loop(CPUX86State *env) switch(trapnr) { case 0x80: /* linux syscall */ - env->regs[R_EAX] = do_syscall(env, - env->regs[R_EAX], + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], @@ -293,7 +293,7 @@ void cpu_loop(CPUX86State *env) break; default: pc = env->segs[R_CS].base + env->eip; - fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", + fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", (long)pc, trapnr); abort(); } @@ -331,7 +331,7 @@ void cpu_loop(CPUARMState *env) unsigned int n, insn; target_siginfo_t info; uint32_t addr; - + for(;;) { trapnr = cpu_arm_exec(env); switch(trapnr) { @@ -343,7 +343,7 @@ void cpu_loop(CPUARMState *env) /* we handle the FPU emulation here, as Linux */ /* we get the opcode */ opcode = tget32(env->regs[15]); - + if (EmulateAll(opcode, &ts->fpa, env) == 0) { info.si_signo = SIGILL; info.si_errno = 0; @@ -395,8 +395,8 @@ void cpu_loop(CPUARMState *env) n -= ARM_SYSCALL_BASE; env->eabi = 0; } - env->regs[0] = do_syscall(env, - n, + env->regs[0] = do_syscall(env, + n, env->regs[0], env->regs[1], env->regs[2], @@ -443,7 +443,7 @@ void cpu_loop(CPUARMState *env) break; default: error: - fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); abort(); @@ -475,10 +475,10 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1) { unsigned int i; target_ulong sp_ptr; - + sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #if defined(DEBUG_WIN) - printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", + printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", (int)sp_ptr, cwp1); #endif for(i = 0; i < 16; i++) { @@ -506,15 +506,15 @@ static void restore_window(CPUSPARCState *env) { unsigned int new_wim, i, cwp1; target_ulong sp_ptr; - + new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & ((1LL << NWINDOWS) - 1); - + /* restore the invalid window */ cwp1 = (env->cwp + 1) & (NWINDOWS - 1); sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #if defined(DEBUG_WIN) - printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", + printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", (int)sp_ptr, cwp1); #endif for(i = 0; i < 16; i++) { @@ -555,20 +555,20 @@ void cpu_loop (CPUSPARCState *env) { int trapnr, ret; target_siginfo_t info; - + while (1) { trapnr = cpu_sparc_exec (env); - + switch (trapnr) { #ifndef TARGET_SPARC64 - case 0x88: + case 0x88: case 0x90: #else case 0x16d: #endif ret = do_syscall (env, env->gregs[1], - env->regwptr[0], env->regwptr[1], - env->regwptr[2], env->regwptr[3], + env->regwptr[0], env->regwptr[1], + env->regwptr[2], env->regwptr[3], env->regwptr[4], env->regwptr[5]); if ((unsigned int)ret >= (unsigned int)(-515)) { #ifdef TARGET_SPARC64 @@ -670,17 +670,17 @@ static inline uint64_t cpu_ppc_get_tb (CPUState *env) /* TO FIX */ return 0; } - + uint32_t cpu_ppc_load_tbl (CPUState *env) { return cpu_ppc_get_tb(env) & 0xFFFFFFFF; } - + uint32_t cpu_ppc_load_tbu (CPUState *env) { return cpu_ppc_get_tb(env) >> 32; } - + static void cpu_ppc_store_tb (CPUState *env, uint64_t value) { /* TO FIX */ @@ -690,7 +690,7 @@ void cpu_ppc_store_tbu (CPUState *env, uint32_t value) { cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); } - + void cpu_ppc_store_tbl (CPUState *env, uint32_t value) { cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); @@ -717,7 +717,7 @@ void cpu_loop(CPUPPCState *env) target_siginfo_t info; int trapnr; uint32_t ret; - + for(;;) { trapnr = cpu_ppc_exec(env); if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && @@ -1026,7 +1026,7 @@ void cpu_loop(CPUPPCState *env) } break; default: - fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); if (loglevel) { fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " @@ -1437,7 +1437,7 @@ void cpu_loop(CPUMIPSState *env) break; default: // error: - fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); abort(); @@ -1452,19 +1452,19 @@ void cpu_loop (CPUState *env) { int trapnr, ret; target_siginfo_t info; - + while (1) { trapnr = cpu_sh4_exec (env); - + switch (trapnr) { case 0x160: - ret = do_syscall(env, - env->gregs[3], - env->gregs[4], - env->gregs[5], - env->gregs[6], - env->gregs[7], - env->gregs[0], + ret = do_syscall(env, + env->gregs[3], + env->gregs[4], + env->gregs[5], + env->gregs[6], + env->gregs[7], + env->gregs[0], 0); env->gregs[0] = ret; env->pc += 2; @@ -1501,7 +1501,7 @@ void cpu_loop(CPUM68KState *env) unsigned int n; target_siginfo_t info; TaskState *ts = env->opaque; - + for(;;) { trapnr = cpu_m68k_exec(env); switch(trapnr) { @@ -1537,8 +1537,8 @@ void cpu_loop(CPUM68KState *env) ts->sim_syscalls = 0; n = env->dregs[0]; env->pc += 2; - env->dregs[0] = do_syscall(env, - n, + env->dregs[0] = do_syscall(env, + n, env->dregs[1], env->dregs[2], env->dregs[3], @@ -1575,7 +1575,7 @@ void cpu_loop(CPUM68KState *env) } break; default: - fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); abort(); @@ -1590,10 +1590,10 @@ void cpu_loop (CPUState *env) { int trapnr; target_siginfo_t info; - + while (1) { trapnr = cpu_alpha_exec (env); - + switch (trapnr) { case EXCP_RESET: fprintf(stderr, "Reset requested. Exit\n"); @@ -1608,7 +1608,7 @@ void cpu_loop (CPUState *env) exit(1); break; case EXCP_HW_INTERRUPT: - fprintf(stderr, "External interrupt. Exit\n"); + fprintf(stderr, "External interrupt. Exit\n"); exit(1); break; case EXCP_DFAULT: @@ -1695,7 +1695,7 @@ void usage(void) "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n", TARGET_ARCH, - interp_prefix, + interp_prefix, x86_stack_size, DEBUG_LOGFILE); _exit(1); @@ -1745,7 +1745,7 @@ int main(int argc, char **argv) if (optind >= argc) break; - + r = argv[optind++]; mask = cpu_str_to_log_mask(r); if (!mask) { @@ -1794,11 +1794,11 @@ int main(int argc, char **argv) } } else if (!strcmp(r, "drop-ld-preload")) { drop_ld_preload = 1; - } else + } else #ifdef USE_CODE_COPY if (!strcmp(r, "no-code-copy")) { code_copy_enabled = 0; - } else + } else #endif { usage(); @@ -1821,7 +1821,7 @@ int main(int argc, char **argv) qemu_host_page_size */ env = cpu_init(); global_env = env; - + wrk = environ; while (*(wrk++)) environ_count++; @@ -1844,12 +1844,12 @@ int main(int argc, char **argv) for (wrk = target_environ; *wrk; wrk++) { free(*wrk); } - + free(target_environ); if (loglevel) { page_dump(logfile); - + fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); @@ -1870,7 +1870,7 @@ int main(int argc, char **argv) ts->used = 1; ts->info = info; env->user_mode_only = 1; - + #if defined(TARGET_I386) cpu_x86_set_cpl(env, 3); @@ -1883,7 +1883,7 @@ int main(int argc, char **argv) /* flags setup : we activate the IRQs by default as in user mode */ env->eflags |= IF_MASK; - + /* linux register setup */ #if defined(TARGET_X86_64) env->regs[R_EAX] = regs->rax; @@ -1936,10 +1936,10 @@ int main(int argc, char **argv) env->gdt.base = h2g(gdt_table); env->gdt.limit = sizeof(gdt_table) - 1; write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); cpu_x86_load_seg(env, R_CS, __USER_CS); cpu_x86_load_seg(env, R_DS, __USER_DS); diff --git a/linux-user/mmap.c b/linux-user/mmap.c index bfecb7a54..3eb930e7b 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -1,6 +1,6 @@ /* * mmap support for qemu - * + * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify @@ -52,7 +52,7 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) return -EINVAL; if (len == 0) return 0; - + host_start = start & qemu_host_page_mask; host_end = HOST_PAGE_ALIGN(end); if (start > host_start) { @@ -77,13 +77,13 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } - ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, + ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, prot1 & PAGE_BITS); if (ret != 0) return ret; host_end -= qemu_host_page_size; } - + /* handle the pages in the middle */ if (host_start < host_end) { ret = mprotect(g2h(host_start), host_end - host_start, prot); @@ -95,8 +95,8 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) } /* map an incomplete host page */ -static int mmap_frag(target_ulong real_start, - target_ulong start, target_ulong end, +static int mmap_frag(target_ulong real_start, + target_ulong start, target_ulong end, int prot, int flags, int fd, target_ulong offset) { target_ulong real_end, ret, addr; @@ -112,10 +112,10 @@ static int mmap_frag(target_ulong real_start, if (addr < start || addr >= end) prot1 |= page_get_flags(addr); } - + if (prot1 == 0) { /* no page was there, so we allocate one */ - ret = (long)mmap(host_start, qemu_host_page_size, prot, + ret = (long)mmap(host_start, qemu_host_page_size, prot, flags | MAP_ANONYMOUS, -1, 0); if (ret == -1) return ret; @@ -134,10 +134,10 @@ static int mmap_frag(target_ulong real_start, /* adjust protection to be able to read */ if (!(prot1 & PROT_WRITE)) mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); - + /* read the corresponding file data */ pread(fd, g2h(start), end - start, offset); - + /* put final protection */ if (prot_new != (prot1 | PROT_WRITE)) mprotect(host_start, qemu_host_page_size, prot_new); @@ -151,7 +151,7 @@ static int mmap_frag(target_ulong real_start, } /* NOTE: all the constants are the HOST ones */ -long target_mmap(target_ulong start, target_ulong len, int prot, +long target_mmap(target_ulong start, target_ulong len, int prot, int flags, int fd, target_ulong offset) { target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; @@ -167,7 +167,7 @@ long target_mmap(target_ulong start, target_ulong len, int prot, #ifdef DEBUG_MMAP { printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", - start, len, + start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', prot & PROT_EXEC ? 'x' : '-'); @@ -216,7 +216,7 @@ long target_mmap(target_ulong start, target_ulong len, int prot, /* ??? This needs fixing for remapping. */ abort(); host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; - real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, + real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (real_start == -1) return real_start; @@ -238,13 +238,13 @@ abort(); if (host_start == -1) return host_start; /* update start so that it points to the file position at 'offset' */ - if (!(flags & MAP_ANONYMOUS)) + if (!(flags & MAP_ANONYMOUS)) host_start += offset - host_offset; start = h2g(host_start); goto the_end1; } } - + if (start & ~TARGET_PAGE_MASK) { errno = EINVAL; return -1; @@ -263,8 +263,8 @@ abort(); errno = EINVAL; return -1; } - retaddr = target_mmap(start, len, prot | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + retaddr = target_mmap(start, len, prot | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (retaddr == -1) return retaddr; @@ -295,15 +295,15 @@ abort(); } /* handle the end of the mapping */ if (end < real_end) { - ret = mmap_frag(real_end - qemu_host_page_size, + ret = mmap_frag(real_end - qemu_host_page_size, real_end - qemu_host_page_size, real_end, - prot, flags, fd, + prot, flags, fd, offset + real_end - qemu_host_page_size - start); if (ret == -1) return ret; real_end -= qemu_host_page_size; } - + /* map the middle (easier) */ if (real_start < real_end) { unsigned long offset1; @@ -311,7 +311,7 @@ abort(); offset1 = 0; else offset1 = offset + real_start - start; - ret = (long)mmap(g2h(real_start), real_end - real_start, + ret = (long)mmap(g2h(real_start), real_end - real_start, prot, flags, fd, offset1); if (ret == -1) return ret; @@ -367,7 +367,7 @@ int target_munmap(target_ulong start, target_ulong len) if (prot != 0) real_end -= qemu_host_page_size; } - + /* unmap what we can */ if (real_start < real_end) { ret = munmap((void *)real_start, real_end - real_start); @@ -381,7 +381,7 @@ int target_munmap(target_ulong start, target_ulong len) /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED blocks which have been allocated starting on a host page */ -long target_mremap(target_ulong old_addr, target_ulong old_size, +long target_mremap(target_ulong old_addr, target_ulong old_size, target_ulong new_size, unsigned long flags, target_ulong new_addr) { @@ -410,7 +410,7 @@ int target_msync(target_ulong start, target_ulong len, int flags) return -EINVAL; if (end == start) return 0; - + start &= qemu_host_page_mask; return msync(g2h(start), end - start, flags); } diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index d150af44c..bf6b21b2f 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -1,6 +1,6 @@ /* * PPC emulation for qemu: syscall definitions. - * + * * Copyright (c) 2003 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/linux-user/ppc64/syscall.h b/linux-user/ppc64/syscall.h index eea8a7c9a..692061641 100644 --- a/linux-user/ppc64/syscall.h +++ b/linux-user/ppc64/syscall.h @@ -1,6 +1,6 @@ /* * PPC emulation for qemu: syscall definitions. - * + * * Copyright (c) 2003 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -55,8 +55,8 @@ struct target_revectored_struct { #define TARGET_SEMOP 1 #define TARGET_SEMGET 2 -#define TARGET_SEMCTL 3 -#define TARGET_MSGSND 11 +#define TARGET_SEMCTL 3 +#define TARGET_MSGSND 11 #define TARGET_MSGRCV 12 #define TARGET_MSGGET 13 #define TARGET_MSGCTL 14 @@ -73,7 +73,7 @@ struct target_msgbuf { struct target_ipc_kludge { unsigned int msgp; /* Really (struct msgbuf *) */ int msgtyp; -}; +}; struct target_ipc_perm { int key; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 076145e1a..011b41ea7 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -97,7 +97,7 @@ extern const char *qemu_uname_release; #define MAX_ARG_PAGES 32 /* - * This structure is used to hold the arguments that are + * This structure is used to hold the arguments that are * used when loading binaries. */ struct linux_binprm { @@ -115,7 +115,7 @@ struct linux_binprm { void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); target_ulong loader_build_argptr(int envc, int argc, target_ulong sp, target_ulong stringp, int push_ptr); -int loader_exec(const char * filename, char ** argv, char ** envp, +int loader_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, @@ -128,7 +128,7 @@ void memcpy_to_target(target_ulong dest, const void *src, void target_set_brk(target_ulong new_brk); long do_brk(target_ulong new_brk); void syscall_init(void); -long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, +long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); extern CPUState *global_env; @@ -158,10 +158,10 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr); /* mmap.c */ int target_mprotect(target_ulong start, target_ulong len, int prot); -long target_mmap(target_ulong start, target_ulong len, int prot, +long target_mmap(target_ulong start, target_ulong len, int prot, int flags, int fd, target_ulong offset); int target_munmap(target_ulong start, target_ulong len); -long target_mremap(target_ulong old_addr, target_ulong old_size, +long target_mremap(target_ulong old_addr, target_ulong old_size, target_ulong new_size, unsigned long flags, target_ulong new_addr); int target_msync(target_ulong start, target_ulong len, int flags); diff --git a/linux-user/sh4/termbits.h b/linux-user/sh4/termbits.h index 6dd5845bc..2ff774f6b 100644 --- a/linux-user/sh4/termbits.h +++ b/linux-user/sh4/termbits.h @@ -245,7 +245,7 @@ struct target_termios { ndbreak() */ #define TARGET_TIOCSBRK TARGET_IO('T', 39) /* 0x5427 */ /* BSD compatibility */ #define TARGET_TIOCCBRK TARGET_IO('T', 40) /* 0x5428 */ /* BSD compatibility */ -#define TARGET_TIOCGSID TARGET_IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session +#define TARGET_TIOCGSID TARGET_IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session ID of FD */ #define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-m ux device) */ @@ -263,12 +263,12 @@ ebugging only */ tus register */ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ # define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -#define TARGET_TIOCSERGETMULTI TARGET_IOR('T', 90, int) /* 0x545A +#define TARGET_TIOCSERGETMULTI TARGET_IOR('T', 90, int) /* 0x545A */ /* Get multiport config */ -#define TARGET_TIOCSERSETMULTI TARGET_IOW('T', 91, int) /* 0x545B +#define TARGET_TIOCSERSETMULTI TARGET_IOW('T', 91, int) /* 0x545B */ /* Set multiport config */ -#define TARGET_TIOCMIWAIT TARGET_IO('T', 92) /* 0x545C */ /* wait for a change on +#define TARGET_TIOCMIWAIT TARGET_IO('T', 92) /* 0x545C */ /* wait for a change on serial input line(s) */ -#define TARGET_TIOCGICOUNT TARGET_IOR('T', 93, int) /* 0x545D */ /* read +#define TARGET_TIOCGICOUNT TARGET_IOR('T', 93, int) /* 0x545D */ /* read serial port inline interrupt counts */ diff --git a/linux-user/signal.c b/linux-user/signal.c index f73d50516..73b6dadc9 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1,6 +1,6 @@ /* * Emulation of Linux signals - * + * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify @@ -50,7 +50,7 @@ static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ static struct sigqueue *first_free; /* first free siginfo queue entry */ static int signal_pending; /* non zero if a signal may be pending */ -static void host_signal_handler(int host_signum, siginfo_t *info, +static void host_signal_handler(int host_signum, siginfo_t *info, void *puc); static uint8_t host_to_target_signal_table[65] = { @@ -102,17 +102,17 @@ static inline int target_to_host_signal(int sig) return target_to_host_signal_table[sig]; } -static void host_to_target_sigset_internal(target_sigset_t *d, +static void host_to_target_sigset_internal(target_sigset_t *d, const sigset_t *s) { int i; unsigned long sigmask; uint32_t target_sigmask; - + sigmask = ((unsigned long *)s)[0]; target_sigmask = 0; for(i = 0; i < 32; i++) { - if (sigmask & (1 << i)) + if (sigmask & (1 << i)) target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1); } #if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 @@ -147,7 +147,7 @@ void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) target_sigmask = s->sig[0]; sigmask = 0; for(i = 0; i < 32; i++) { - if (target_sigmask & (1 << i)) + if (target_sigmask & (1 << i)) sigmask |= 1 << (target_to_host_signal(i + 1) - 1); } #if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 @@ -171,8 +171,8 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) s1.sig[i] = tswapl(s->sig[i]); target_to_host_sigset_internal(d, &s1); } - -void host_to_target_old_sigset(target_ulong *old_sigset, + +void host_to_target_old_sigset(target_ulong *old_sigset, const sigset_t *sigset) { target_sigset_t d; @@ -180,7 +180,7 @@ void host_to_target_old_sigset(target_ulong *old_sigset, *old_sigset = d.sig[0]; } -void target_to_host_old_sigset(sigset_t *sigset, +void target_to_host_old_sigset(sigset_t *sigset, const target_ulong *old_sigset) { target_sigset_t d; @@ -194,7 +194,7 @@ void target_to_host_old_sigset(sigset_t *sigset, /* siginfo conversion */ -static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, +static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) { int sig; @@ -202,7 +202,7 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, tinfo->si_signo = sig; tinfo->si_errno = 0; tinfo->si_code = 0; - if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS || sig == SIGTRAP) { /* should never come here, but who knows. The information for the target is irrelevant */ @@ -213,12 +213,12 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, tinfo->_sifields._rt._pid = info->si_pid; tinfo->_sifields._rt._uid = info->si_uid; /* XXX: potential problem if 64 bit */ - tinfo->_sifields._rt._sigval.sival_ptr = + tinfo->_sifields._rt._sigval.sival_ptr = (target_ulong)info->si_value.sival_ptr; } } -static void tswap_siginfo(target_siginfo_t *tinfo, +static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) { int sig; @@ -226,16 +226,16 @@ static void tswap_siginfo(target_siginfo_t *tinfo, tinfo->si_signo = tswap32(sig); tinfo->si_errno = tswap32(info->si_errno); tinfo->si_code = tswap32(info->si_code); - if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS || sig == SIGTRAP) { - tinfo->_sifields._sigfault._addr = + tinfo->_sifields._sigfault._addr = tswapl(info->_sifields._sigfault._addr); } else if (sig == SIGIO) { tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd); } else if (sig >= TARGET_SIGRTMIN) { tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); - tinfo->_sifields._rt._sigval.sival_ptr = + tinfo->_sifields._rt._sigval.sival_ptr = tswapl(info->_sifields._rt._sigval.sival_ptr); } } @@ -256,7 +256,7 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) info->si_code = tswap32(tinfo->si_code); info->si_pid = tswap32(tinfo->_sifields._rt._pid); info->si_uid = tswap32(tinfo->_sifields._rt._uid); - info->si_value.sival_ptr = + info->si_value.sival_ptr = (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); } @@ -274,7 +274,7 @@ void signal_init(void) j = host_to_target_signal_table[i]; target_to_host_signal_table[j] = i; } - + /* set all host signal handlers. ALL signals are blocked during the handlers to serialize them. */ sigfillset(&act.sa_mask); @@ -283,11 +283,11 @@ void signal_init(void) for(i = 1; i < NSIG; i++) { sigaction(i, &act, NULL); } - + memset(sigact_table, 0, sizeof(sigact_table)); first_free = &sigqueue_table[0]; - for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) + for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) sigqueue_table[i].next = &sigqueue_table[i + 1]; sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; } @@ -314,7 +314,7 @@ void __attribute((noreturn)) force_sig(int sig) { int host_sig; host_sig = target_to_host_signal(sig); - fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", + fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", sig, strsignal(host_sig)); #if 1 _exit(-host_sig); @@ -339,15 +339,15 @@ int queue_signal(int sig, target_siginfo_t *info) target_ulong handler; #if defined(DEBUG_SIGNAL) - fprintf(stderr, "queue_signal: sig=%d\n", + fprintf(stderr, "queue_signal: sig=%d\n", sig); #endif k = &sigact_table[sig - 1]; handler = k->sa._sa_handler; if (handler == TARGET_SIG_DFL) { /* default handler : ignore some signal. The other are fatal */ - if (sig != TARGET_SIGCHLD && - sig != TARGET_SIGURG && + if (sig != TARGET_SIGCHLD && + sig != TARGET_SIGURG && sig != TARGET_SIGWINCH) { force_sig(sig); } else { @@ -388,7 +388,7 @@ int queue_signal(int sig, target_siginfo_t *info) } } -static void host_signal_handler(int host_signum, siginfo_t *info, +static void host_signal_handler(int host_signum, siginfo_t *info, void *puc) { int sig; @@ -396,7 +396,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, /* the CPU emulator uses some host signals to detect exceptions, we we forward to it some signals */ - if (host_signum == SIGSEGV || host_signum == SIGBUS + if (host_signum == SIGSEGV || host_signum == SIGBUS #if defined(TARGET_I386) && defined(USE_CODE_COPY) || host_signum == SIGFPE #endif @@ -430,7 +430,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, return -EINVAL; k = &sigact_table[sig - 1]; #if defined(DEBUG_SIGNAL) - fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n", + fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n", sig, (int)act, (int)oact); #endif if (oact) { @@ -476,7 +476,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define offsetof(type, field) ((size_t) &((type *)0)->field) #endif -static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, +static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, const target_siginfo_t *info) { tswap_siginfo(tinfo, info); @@ -648,7 +648,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) } /* This is the legacy signal stack switching. */ - else + else #endif if ((env->segs[R_SS].selector & 0xffff) != __USER_DS && !(ka->sa.sa_flags & TARGET_SA_RESTORER) && @@ -723,7 +723,7 @@ give_sigsegv: force_sig(TARGET_SIGSEGV /* , current */); } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUX86State *env) { @@ -817,7 +817,7 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax) cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3); cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3); - + { unsigned int tmpflags; tmpflags = ldl(&sc->eflags); @@ -865,7 +865,7 @@ long do_sigreturn(CPUX86State *env) target_to_host_sigset_internal(&set, &target_set); sigprocmask(SIG_SETMASK, &set, NULL); - + /* restore registers */ if (restore_sigcontext(env, &frame->sc, &eax)) goto badframe; @@ -889,7 +889,7 @@ long do_rt_sigreturn(CPUX86State *env) #endif target_to_host_sigset(&set, &frame->uc.tuc_sigmask); sigprocmask(SIG_SETMASK, &set, NULL); - + if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) goto badframe; @@ -1127,7 +1127,7 @@ static void setup_frame(int usig, struct emulated_sigaction *ka, // return err; } -static void setup_rt_frame(int usig, struct emulated_sigaction *ka, +static void setup_rt_frame(int usig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -1547,7 +1547,7 @@ restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu) } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -1851,7 +1851,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) return g2h((sp - frame_size) & ~7); } -static void setup_frame(int sig, struct emulated_sigaction * ka, +static void setup_frame(int sig, struct emulated_sigaction * ka, target_sigset_t *set, CPUState *regs) { struct sigframe *frame; @@ -1894,7 +1894,7 @@ static void setup_frame(int sig, struct emulated_sigaction * ka, give_sigsegv: force_sig(TARGET_SIGSEGV/*, current*/); - return; + return; } long do_sigreturn(CPUState *regs) @@ -1933,7 +1933,7 @@ long do_sigreturn(CPUState *regs) :"r" (®s)); /* Unreached */ #endif - + regs->PC[regs->current_tc] = regs->CP0_EPC; /* I am not sure this is right, but it seems to work * maybe a problem with nested signals ? */ @@ -1945,7 +1945,7 @@ badframe: return 0; } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -1966,7 +1966,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, fprintf(stderr, "setup_frame: not implemented\n"); } -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { @@ -1995,7 +1995,7 @@ void process_pending_signals(void *cpu_env) target_sigset_t target_old_set; struct emulated_sigaction *k; struct sigqueue *q; - + if (!signal_pending) return; @@ -2018,7 +2018,7 @@ void process_pending_signals(void *cpu_env) k->first = q->next; if (!k->first) k->pending = 0; - + sig = gdb_handlesig (cpu_env, sig); if (!sig) { fprintf (stderr, "Lost signal\n"); @@ -2028,8 +2028,8 @@ void process_pending_signals(void *cpu_env) handler = k->sa._sa_handler; if (handler == TARGET_SIG_DFL) { /* default handler : ignore some signal. The other are fatal */ - if (sig != TARGET_SIGCHLD && - sig != TARGET_SIGURG && + if (sig != TARGET_SIGCHLD && + sig != TARGET_SIGURG && sig != TARGET_SIGWINCH) { force_sig(sig); } @@ -2044,7 +2044,7 @@ void process_pending_signals(void *cpu_env) blocked during the handler */ if (!(k->sa.sa_flags & TARGET_SA_NODEFER)) sigaddset(&set, target_to_host_signal(sig)); - + /* block signals in the handler using Linux */ sigprocmask(SIG_BLOCK, &set, &old_set); /* save the previous blocked signal state to restore it at the diff --git a/linux-user/sparc/termbits.h b/linux-user/sparc/termbits.h index cad45b292..3ec8e97c7 100644 --- a/linux-user/sparc/termbits.h +++ b/linux-user/sparc/termbits.h @@ -182,7 +182,7 @@ struct target_termios { #define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios) #define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios) -/* Note that all the ioctls that are not available in Linux have a +/* Note that all the ioctls that are not available in Linux have a * double underscore on the front to: a) avoid some programs to * thing we support some ioctls under Linux (autoconfiguration stuff) */ diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h index cad45b292..3ec8e97c7 100644 --- a/linux-user/sparc64/termbits.h +++ b/linux-user/sparc64/termbits.h @@ -182,7 +182,7 @@ struct target_termios { #define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios) #define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios) -/* Note that all the ioctls that are not available in Linux have a +/* Note that all the ioctls that are not available in Linux have a * double underscore on the front to: a) avoid some programs to * thing we support some ioctls under Linux (autoconfiguration stuff) */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cd956aa1a..a92449077 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1,6 +1,6 @@ /* * Linux syscalls - * + * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify @@ -339,7 +339,7 @@ long do_brk(target_ulong new_brk) return target_brk; if (new_brk < target_original_brk) return -ENOMEM; - + brk_page = HOST_PAGE_ALIGN(target_brk); /* If the new brk is less than this, set it and we're done... */ @@ -350,7 +350,7 @@ long do_brk(target_ulong new_brk) /* We need to allocate more memory after the brk... */ new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); - mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, + mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); if (is_error(mapped_addr)) { @@ -361,7 +361,7 @@ long do_brk(target_ulong new_brk) } } -static inline fd_set *target_to_host_fds(fd_set *fds, +static inline fd_set *target_to_host_fds(fd_set *fds, target_long *target_fds, int n) { #if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) @@ -383,7 +383,7 @@ static inline fd_set *target_to_host_fds(fd_set *fds, #endif } -static inline void host_to_target_fds(target_long *target_fds, +static inline void host_to_target_fds(target_long *target_fds, fd_set *fds, int n) { #if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) @@ -472,8 +472,8 @@ static inline void host_to_target_timeval(target_ulong target_addr, } -static long do_select(long n, - target_ulong rfd_p, target_ulong wfd_p, +static long do_select(long n, + target_ulong rfd_p, target_ulong wfd_p, target_ulong efd_p, target_ulong target_tv) { fd_set rfds, wfds, efds; @@ -504,7 +504,7 @@ static long do_select(long n, target_efds = NULL; efds_ptr = NULL; } - + if (target_tv) { target_to_host_timeval(&tv, target_tv); tv_ptr = &tv; @@ -569,7 +569,7 @@ static inline void target_to_host_cmsg(struct msghdr *msgh, void *data = CMSG_DATA(cmsg); void *target_data = TARGET_CMSG_DATA(target_cmsg); - int len = tswapl(target_cmsg->cmsg_len) + int len = tswapl(target_cmsg->cmsg_len) - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr)); space += CMSG_SPACE(len); @@ -646,17 +646,17 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, msgh->msg_controllen = tswapl(space); } -static long do_setsockopt(int sockfd, int level, int optname, +static long do_setsockopt(int sockfd, int level, int optname, target_ulong optval, socklen_t optlen) { int val, ret; - + switch(level) { case SOL_TCP: /* TCP options all take an 'int' value. */ if (optlen < sizeof(uint32_t)) return -EINVAL; - + val = tget32(optval); ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; @@ -766,7 +766,7 @@ static long do_setsockopt(int sockfd, int level, int optname, return ret; } -static long do_getsockopt(int sockfd, int level, int optname, +static long do_getsockopt(int sockfd, int level, int optname, target_ulong optval, target_ulong optlen) { int len, lv, val, ret; @@ -916,7 +916,7 @@ static long do_bind(int sockfd, target_ulong target_addr, socklen_t addrlen) { void *addr = alloca(addrlen); - + target_to_host_sockaddr(addr, target_addr, addrlen); return get_errno(bind(sockfd, addr, addrlen)); } @@ -925,7 +925,7 @@ static long do_connect(int sockfd, target_ulong target_addr, socklen_t addrlen) { void *addr = alloca(addrlen); - + target_to_host_sockaddr(addr, target_addr, addrlen); return get_errno(connect(sockfd, addr, addrlen)); } @@ -953,14 +953,14 @@ static long do_sendrecvmsg(int fd, target_ulong target_msg, msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); msg.msg_control = alloca(msg.msg_controllen); msg.msg_flags = tswap32(msgp->msg_flags); - + count = tswapl(msgp->msg_iovlen); vec = alloca(count * sizeof(struct iovec)); target_vec = tswapl(msgp->msg_iov); lock_iovec(vec, target_vec, count, send); msg.msg_iovlen = count; msg.msg_iov = vec; - + if (send) { target_to_host_cmsg(&msg, msgp); ret = get_errno(sendmsg(fd, &msg, flags)); @@ -1209,7 +1209,7 @@ static long do_socketcall(int num, target_ulong vptr) target_msg = tgetl(vptr + n); flags = tgetl(vptr + 2 * n); - ret = do_sendrecvmsg(fd, target_msg, flags, + ret = do_sendrecvmsg(fd, target_msg, flags, (num == SOCKOP_sendmsg)); } break; @@ -1634,7 +1634,7 @@ static long do_ipc(long call, long first, long second, long third, break; raddr = ret; /* find out the length of the shared memory segment */ - + ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); if (is_error(ret)) { /* can't get length, bail out */ @@ -1908,51 +1908,51 @@ static void target_to_host_termios (void *dst, const void *src) { struct host_termios *host = dst; const struct target_termios *target = src; - - host->c_iflag = + + host->c_iflag = target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl); - host->c_oflag = + host->c_oflag = target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl); - host->c_cflag = + host->c_cflag = target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl); - host->c_lflag = + host->c_lflag = target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl); host->c_line = target->c_line; - - host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; - host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; - host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; - host->c_cc[VKILL] = target->c_cc[TARGET_VKILL]; - host->c_cc[VEOF] = target->c_cc[TARGET_VEOF]; - host->c_cc[VTIME] = target->c_cc[TARGET_VTIME]; - host->c_cc[VMIN] = target->c_cc[TARGET_VMIN]; - host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC]; - host->c_cc[VSTART] = target->c_cc[TARGET_VSTART]; - host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP]; - host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP]; - host->c_cc[VEOL] = target->c_cc[TARGET_VEOL]; - host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT]; - host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD]; - host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE]; - host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT]; - host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2]; + + host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; + host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; + host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; + host->c_cc[VKILL] = target->c_cc[TARGET_VKILL]; + host->c_cc[VEOF] = target->c_cc[TARGET_VEOF]; + host->c_cc[VTIME] = target->c_cc[TARGET_VTIME]; + host->c_cc[VMIN] = target->c_cc[TARGET_VMIN]; + host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC]; + host->c_cc[VSTART] = target->c_cc[TARGET_VSTART]; + host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP]; + host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP]; + host->c_cc[VEOL] = target->c_cc[TARGET_VEOL]; + host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT]; + host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD]; + host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE]; + host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT]; + host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2]; } - + static void host_to_target_termios (void *dst, const void *src) { struct target_termios *target = dst; const struct host_termios *host = src; - target->c_iflag = + target->c_iflag = tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl)); - target->c_oflag = + target->c_oflag = tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl)); - target->c_cflag = + target->c_cflag = tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl)); - target->c_lflag = + target->c_lflag = tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl)); target->c_line = host->c_line; - + target->c_cc[TARGET_VINTR] = host->c_cc[VINTR]; target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT]; target->c_cc[TARGET_VERASE] = host->c_cc[VERASE]; @@ -2033,7 +2033,7 @@ static int read_ldt(target_ulong ptr, unsigned long bytecount) } /* XXX: add locking support */ -static int write_ldt(CPUX86State *env, +static int write_ldt(CPUX86State *env, target_ulong ptr, unsigned long bytecount, int oldmode) { struct target_modify_ldt_ldt_s ldt_info; @@ -2050,7 +2050,7 @@ static int write_ldt(CPUX86State *env, ldt_info.limit = tswap32(target_ldt_info->limit); ldt_info.flags = tswap32(target_ldt_info->flags); unlock_user_struct(target_ldt_info, ptr, 0); - + if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) return -EINVAL; seg_32bit = ldt_info.flags & 1; @@ -2091,7 +2091,7 @@ static int write_ldt(CPUX86State *env, goto install; } } - + entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | (ldt_info.limit & 0x0ffff); entry_2 = (ldt_info.base_addr & 0xff000000) | @@ -2118,7 +2118,7 @@ install: int do_modify_ldt(CPUX86State *env, int func, target_ulong ptr, unsigned long bytecount) { int ret = -ENOSYS; - + switch (func) { case 0: ret = read_ldt(ptr, bytecount); @@ -2153,7 +2153,7 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) TaskState *ts; uint8_t *new_stack; CPUState *new_env; - + if (flags & CLONE_VM) { ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); memset(ts, 0, sizeof(TaskState)); @@ -2195,7 +2195,7 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) if (!newsp) newsp = env->gpr[1]; new_env->gpr[1] = newsp; - { + { int i; for (i = 7; i < 32; i++) new_env->gpr[i] = 0; @@ -2261,7 +2261,7 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) unlock_user_struct(target_fl, arg, 1); } break; - + case TARGET_F_SETLK: case TARGET_F_SETLKW: lock_user_struct(target_fl, arg, 1); @@ -2273,7 +2273,7 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) unlock_user_struct(target_fl, arg, 0); ret = fcntl(fd, cmd, &fl); break; - + case TARGET_F_GETLK64: lock_user_struct(target_fl64, arg, 1); fl64.l_type = tswap16(target_fl64->l_type) >> 1; @@ -2363,8 +2363,8 @@ void syscall_init(void) const argtype *arg_type; int size; -#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); -#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); +#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); +#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); #include "syscall_types.h" #undef STRUCT #undef STRUCT_SPECIAL @@ -2377,20 +2377,20 @@ void syscall_init(void) TARGET_IOC_SIZEMASK) { arg_type = ie->arg_type; if (arg_type[0] != TYPE_PTR) { - fprintf(stderr, "cannot patch size for ioctl 0x%x\n", + fprintf(stderr, "cannot patch size for ioctl 0x%x\n", ie->target_cmd); exit(1); } arg_type++; size = thunk_type_size(arg_type, 0); - ie->target_cmd = (ie->target_cmd & + ie->target_cmd = (ie->target_cmd & ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) | (size << TARGET_IOC_SIZESHIFT); } /* automatic consistency check if same arch */ #if defined(__i386__) && defined(TARGET_I386) if (ie->target_cmd != ie->host_cmd) { - fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n", + fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n", ie->target_cmd, ie->host_cmd); } #endif @@ -2459,14 +2459,14 @@ static inline void host_to_target_timespec(target_ulong target_addr, unlock_user_struct(target_ts, target_addr, 1); } -long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, +long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { long ret; struct stat st; struct statfs stfs; void *p; - + #ifdef DEBUG gemu_log("syscall %d", num); #endif @@ -2978,7 +2978,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { int how = arg1; sigset_t set, oldset, *set_ptr; - + if (arg2) { switch(how) { case TARGET_SIG_BLOCK: @@ -3015,7 +3015,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { int how = arg1; sigset_t set, oldset, *set_ptr; - + if (arg2) { switch(how) { case TARGET_SIG_BLOCK: @@ -3096,7 +3096,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, sigset_t set; struct timespec uts, *puts; siginfo_t uinfo; - + p = lock_user(arg1, sizeof(target_sigset_t), 1); target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); @@ -3157,7 +3157,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, int resource = arg1; struct target_rlimit *target_rlim; struct rlimit rlim; - + ret = get_errno(getrlimit(resource, &rlim)); if (!is_error(ret)) { lock_user_struct(target_rlim, arg2, 0); @@ -3265,13 +3265,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, v5 = tswapl(v[4]); v6 = tswapl(v[5]); unlock_user(v, arg1, 0); - ret = get_errno(target_mmap(v1, v2, v3, + ret = get_errno(target_mmap(v1, v2, v3, target_to_host_bitmask(v4, mmap_flags_tbl), v5, v6)); } #else - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), arg5, arg6)); #endif @@ -3284,8 +3284,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #else #define MMAP_SHIFT TARGET_PAGE_BITS #endif - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), arg5, arg6 << MMAP_SHIFT)); break; @@ -3355,7 +3355,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, convert_statfs: if (!is_error(ret)) { struct target_statfs *target_stfs; - + lock_user_struct(target_stfs, arg2, 0); /* ??? put_user is probably wrong. */ put_user(stfs.f_type, &target_stfs->f_type); @@ -3382,7 +3382,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, convert_statfs64: if (!is_error(ret)) { struct target_statfs64 *target_stfs; - + lock_user_struct(target_stfs, arg3, 0); /* ??? put_user is probably wrong. */ put_user(stfs.f_type, &target_stfs->f_type); @@ -3509,9 +3509,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, if (arg2) { pvalue = &value; - target_to_host_timeval(&pvalue->it_interval, + target_to_host_timeval(&pvalue->it_interval, arg2); - target_to_host_timeval(&pvalue->it_value, + target_to_host_timeval(&pvalue->it_value, arg2 + sizeof(struct target_timeval)); } else { pvalue = NULL; @@ -3528,7 +3528,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getitimer: { struct itimerval value; - + ret = get_errno(getitimer(arg1, &value)); if (!is_error(ret) && arg2) { host_to_target_timeval(arg2, @@ -3697,7 +3697,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, /* no need to transcode because we use the linux syscall */ { struct new_utsname * buf; - + lock_user_struct(buf, arg1, 0); ret = get_errno(sys_uname(buf)); if (!is_error(ret)) { @@ -3784,7 +3784,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, dirp = malloc(count); if (!dirp) return -ENOMEM; - + ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { struct dirent *de; @@ -4232,8 +4232,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #ifdef TARGET_NR_setresuid case TARGET_NR_setresuid: - ret = get_errno(setresuid(low2highuid(arg1), - low2highuid(arg2), + ret = get_errno(setresuid(low2highuid(arg1), + low2highuid(arg2), low2highuid(arg3))); break; #endif @@ -4252,8 +4252,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif #ifdef TARGET_NR_getresgid case TARGET_NR_setresgid: - ret = get_errno(setresgid(low2highgid(arg1), - low2highgid(arg2), + ret = get_errno(setresgid(low2highgid(arg1), + low2highgid(arg2), low2highgid(arg3))); break; #endif @@ -4352,7 +4352,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, uint32_t *target_grouplist; gid_t *grouplist; int i; - + grouplist = alloca(gidsetsize * sizeof(gid_t)); target_grouplist = lock_user(arg2, gidsetsize * 4, 1); for(i = 0;i < gidsetsize; i++) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 31e1b3290..01f456328 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -281,9 +281,9 @@ static inline void target_siginitset(target_sigset_t *d, target_ulong set) void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); void target_to_host_sigset(sigset_t *d, const target_sigset_t *s); -void host_to_target_old_sigset(target_ulong *old_sigset, +void host_to_target_old_sigset(target_ulong *old_sigset, const sigset_t *sigset); -void target_to_host_old_sigset(sigset_t *sigset, +void target_to_host_old_sigset(sigset_t *sigset, const target_ulong *old_sigset); struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, @@ -709,59 +709,59 @@ struct target_pollfd { #define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ /* cdrom commands */ -#define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */ +#define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */ #define TARGET_CDROMRESUME 0x5302 /* Resume paused Audio Operation */ #define TARGET_CDROMPLAYMSF 0x5303 /* Play Audio MSF (struct cdrom_msf) */ -#define TARGET_CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index +#define TARGET_CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index (struct cdrom_ti) */ -#define TARGET_CDROMREADTOCHDR 0x5305 /* Read TOC header +#define TARGET_CDROMREADTOCHDR 0x5305 /* Read TOC header (struct cdrom_tochdr) */ -#define TARGET_CDROMREADTOCENTRY 0x5306 /* Read TOC entry +#define TARGET_CDROMREADTOCENTRY 0x5306 /* Read TOC entry (struct cdrom_tocentry) */ #define TARGET_CDROMSTOP 0x5307 /* Stop the cdrom drive */ #define TARGET_CDROMSTART 0x5308 /* Start the cdrom drive */ #define TARGET_CDROMEJECT 0x5309 /* Ejects the cdrom media */ -#define TARGET_CDROMVOLCTRL 0x530a /* Control output volume +#define TARGET_CDROMVOLCTRL 0x530a /* Control output volume (struct cdrom_volctrl) */ -#define TARGET_CDROMSUBCHNL 0x530b /* Read subchannel data +#define TARGET_CDROMSUBCHNL 0x530b /* Read subchannel data (struct cdrom_subchnl) */ -#define TARGET_CDROMREADMODE2 0x530c /* Read TARGET_CDROM mode 2 data (2336 Bytes) +#define TARGET_CDROMREADMODE2 0x530c /* Read TARGET_CDROM mode 2 data (2336 Bytes) (struct cdrom_read) */ #define TARGET_CDROMREADMODE1 0x530d /* Read TARGET_CDROM mode 1 data (2048 Bytes) (struct cdrom_read) */ #define TARGET_CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ #define TARGET_CDROMEJECT_SW 0x530f /* enable(1)/disable(0) auto-ejecting */ -#define TARGET_CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session - address of multi session disks +#define TARGET_CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session + address of multi session disks (struct cdrom_multisession) */ -#define TARGET_CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code" +#define TARGET_CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code" if available (struct cdrom_mcn) */ -#define TARGET_CDROM_GET_UPC TARGET_CDROM_GET_MCN /* This one is depricated, +#define TARGET_CDROM_GET_UPC TARGET_CDROM_GET_MCN /* This one is depricated, but here anyway for compatability */ #define TARGET_CDROMRESET 0x5312 /* hard-reset the drive */ -#define TARGET_CDROMVOLREAD 0x5313 /* Get the drive's volume setting +#define TARGET_CDROMVOLREAD 0x5313 /* Get the drive's volume setting (struct cdrom_volctrl) */ #define TARGET_CDROMREADRAW 0x5314 /* read data in raw mode (2352 Bytes) (struct cdrom_read) */ -/* +/* * These ioctls are used only used in aztcd.c and optcd.c */ #define TARGET_CDROMREADCOOKED 0x5315 /* read data in cooked mode */ #define TARGET_CDROMSEEK 0x5316 /* seek msf address */ - + /* - * This ioctl is only used by the scsi-cd driver. + * This ioctl is only used by the scsi-cd driver. It is for playing audio in logical block addressing mode. */ #define TARGET_CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */ -/* +/* * These ioctls are only used in optcd.c */ #define TARGET_CDROMREADALL 0x5318 /* read all 2646 bytes */ -/* - * These ioctls are (now) only in ide-cd.c for controlling +/* + * These ioctls are (now) only in ide-cd.c for controlling * drive spindown time. They should be implemented in the * Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10, * GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE... @@ -770,7 +770,7 @@ struct target_pollfd { #define TARGET_CDROMGETSPINDOWN 0x531d #define TARGET_CDROMSETSPINDOWN 0x531e -/* +/* * These ioctls are implemented through the uniform CD-ROM driver * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM * drivers are eventually ported to the uniform CD-ROM driver interface. @@ -1285,7 +1285,7 @@ struct target_stat64 { unsigned int __pad0; target_ulong target_st_atime; - target_ulong target_st_atime_nsec; + target_ulong target_st_atime_nsec; target_ulong target_st_mtime; target_ulong target_st_mtime_nsec; target_ulong target_st_ctime; @@ -1347,7 +1347,7 @@ struct target_stat64 { target_ulong target_st_mtime_nsec; target_ulong target_st_ctime; - target_ulong target_st_ctime_nsec; + target_ulong target_st_ctime_nsec; unsigned long long st_ino; }; diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 308da4857..2fd00f103 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -5,7 +5,7 @@ STRUCT(winsize, STRUCT(serial_multiport_struct, TYPE_INT, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, - TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, + TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, MK_ARRAY(TYPE_INT, 32)) STRUCT(serial_icounter_struct, @@ -15,12 +15,12 @@ STRUCT(sockaddr, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14)) STRUCT(rtentry, - TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), - TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID, + TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), + TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID, TYPE_ULONG, TYPE_ULONG, TYPE_SHORT) STRUCT(ifmap, - TYPE_ULONG, TYPE_ULONG, TYPE_SHORT, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, + TYPE_ULONG, TYPE_ULONG, TYPE_SHORT, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, /* Spare 3 bytes */ TYPE_CHAR, TYPE_CHAR, TYPE_CHAR) @@ -28,7 +28,7 @@ STRUCT(ifmap, STRUCT(sockaddr_ifreq, MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_sockaddr)) - + STRUCT(short_ifreq, MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_SHORT) @@ -49,7 +49,7 @@ STRUCT(ifconf, TYPE_INT, TYPE_PTRVOID) STRUCT(arpreq, - MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr), + MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr), MK_ARRAY(TYPE_CHAR, 16)) STRUCT(arpreq_old, diff --git a/linux-user/vm86.c b/linux-user/vm86.c index b28eea60d..be71c2cd4 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -1,6 +1,6 @@ /* * vm86 linux syscall support - * + * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify @@ -85,7 +85,7 @@ void save_v86_state(CPUX86State *env) target_v86->regs.eflags = tswap32(env->eflags); unlock_user_struct(target_v86, ts->target_v86, 1); #ifdef DEBUG_VM86 - fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n", + fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n", env->eflags, env->segs[R_CS].selector, env->eip); #endif @@ -123,7 +123,7 @@ static inline void return_to_32bit(CPUX86State *env, int retval) static inline int set_IF(CPUX86State *env) { TaskState *ts = env->opaque; - + ts->v86flags |= VIF_MASK; if (ts->v86flags & VIP_MASK) { return_to_32bit(env, TARGET_VM86_STI); @@ -202,7 +202,7 @@ static void do_int(CPUX86State *env, int intno) goto cannot_handle; if (is_revectored(intno, &ts->vm86plus.int_revectored)) goto cannot_handle; - if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, + if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, &ts->vm86plus.int21_revectored)) goto cannot_handle; int_ptr = (uint32_t *)(intno << 2); @@ -210,7 +210,7 @@ static void do_int(CPUX86State *env, int intno) if ((segoffs >> 16) == TARGET_BIOSSEG) goto cannot_handle; #if defined(DEBUG_VM86) - fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", + fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", intno, segoffs >> 16, segoffs & 0xffff); #endif /* save old state */ @@ -264,7 +264,7 @@ void handle_vm86_fault(CPUX86State *env) csp = (uint8_t *)(env->segs[R_CS].selector << 4); ip = env->eip & 0xffff; pc = csp + ip; - + ssp = (uint8_t *)(env->segs[R_SS].selector << 4); sp = env->regs[R_ESP] & 0xffff; @@ -330,7 +330,7 @@ void handle_vm86_fault(CPUX86State *env) ADD16(ip, 1); env->eip = ip; if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) { - if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >> + if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >> (intno &7)) & 1) { return_to_32bit(env, TARGET_VM86_INTx + (intno << 8)); return; @@ -362,12 +362,12 @@ void handle_vm86_fault(CPUX86State *env) return; } VM86_FAULT_RETURN; - + case 0xfa: /* cli */ env->eip = ip; clear_IF(env); VM86_FAULT_RETURN; - + case 0xfb: /* sti */ env->eip = ip; if (set_IF(env)) @@ -386,7 +386,7 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) TaskState *ts = env->opaque; struct target_vm86plus_struct * target_v86; int ret; - + switch (subfunction) { case TARGET_VM86_REQUEST_IRQ: case TARGET_VM86_FREE_IRQ: @@ -427,7 +427,7 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) lock_user_struct(target_v86, vm86_addr, 1); /* build vm86 CPU state */ ts->v86flags = tswap32(target_v86->regs.eflags); - env->eflags = (env->eflags & ~SAFE_MASK) | + env->eflags = (env->eflags & ~SAFE_MASK) | (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type); @@ -462,17 +462,17 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); ret = tswap32(target_v86->regs.eax); /* eax will be restored at the end of the syscall */ - memcpy(&ts->vm86plus.int_revectored, + memcpy(&ts->vm86plus.int_revectored, &target_v86->int_revectored, 32); - memcpy(&ts->vm86plus.int21_revectored, + memcpy(&ts->vm86plus.int21_revectored, &target_v86->int21_revectored, 32); ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags); - memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, + memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, target_v86->vm86plus.vm86dbg_intxxtab, 32); unlock_user_struct(target_v86, vm86_addr, 0); - + #ifdef DEBUG_VM86 - fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", + fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS].selector, env->eip); #endif /* now the virtual CPU is ready for vm86 execution ! */ diff --git a/linux-user/x86_64/syscall_nr.h b/linux-user/x86_64/syscall_nr.h index e1a8ca20b..c58de2bc5 100644 --- a/linux-user/x86_64/syscall_nr.h +++ b/linux-user/x86_64/syscall_nr.h @@ -181,7 +181,7 @@ #define TARGET_NR_nfsservctl 180 #define TARGET_NR_getpmsg 181 /* reserved for LiS/STREAMS */ #define TARGET_NR_putpmsg 182 /* reserved for LiS/STREAMS */ -#define TARGET_NR_afs_syscall 183 /* reserved for AFS */ +#define TARGET_NR_afs_syscall 183 /* reserved for AFS */ #define TARGET_NR_tuxcall 184 /* reserved for tux */ #define TARGET_NR_security 185 #define TARGET_NR_gettid 186 diff --git a/loader.c b/loader.c index 2e4fecc34..aba3ae262 100644 --- a/loader.c +++ b/loader.c @@ -1,8 +1,8 @@ /* * QEMU Executable loader - * + * * 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 @@ -261,7 +261,7 @@ static void bswap_uboot_header(uboot_image_header_t *hdr) /* Load a U-Boot image. */ int load_uboot(const char *filename, target_ulong *ep, int *is_linux) { - + int fd; int size; uboot_image_header_t h; diff --git a/m68k-dis.c b/m68k-dis.c index ef0f89c74..90d0bedb7 100644 --- a/m68k-dis.c +++ b/m68k-dis.c @@ -2378,7 +2378,7 @@ const struct m68k_opcode m68k_opcodes[] = {"eor", 4, one(0005174), one(0177777), "#wSs", m68000up }, {"eor", 4, one(0005100), one(0177700), "#w$s", m68000up }, {"eor", 2, one(0130500), one(0170700), "Dd$s", m68000up }, - + {"exg", 2, one(0140500), one(0170770), "DdDs", m68000up }, {"exg", 2, one(0140510), one(0170770), "AdAs", m68000up }, {"exg", 2, one(0140610), one(0170770), "DdAs", m68000up }, @@ -4011,13 +4011,13 @@ const struct m68k_opcode m68k_opcodes[] = {"roxrl", 2, one(0160260), one(0170770), "DdDs", m68000up }, {"rtd", 4, one(0047164), one(0177777), "#w", m68010up }, - + {"rte", 2, one(0047163), one(0177777), "", m68000up | mcfisa_a }, - + {"rtm", 2, one(0003300), one(0177760), "Rs", m68020 }, - + {"rtr", 2, one(0047167), one(0177777), "", m68000up }, - + {"rts", 2, one(0047165), one(0177777), "", m68000up | mcfisa_a }, {"satsl", 2, one(0046200), one(0177770), "Ds", mcfisa_b }, @@ -4561,12 +4561,12 @@ floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from) zero can it be zero, and then it must be zero. */ unsigned long exponent, int_bit; const unsigned char *ufrom = (const unsigned char *) from; - + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len); int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->man_start, 1); - + if ((exponent == 0) != (int_bit == 0)) return 0; else @@ -4699,7 +4699,7 @@ get_field (const unsigned char *data, enum floatformat_byteorders order, } return result; } - + #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif diff --git a/m68k-semi.c b/m68k-semi.c index 73224f181..fc033a163 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -1,6 +1,6 @@ /* * m68k/ColdFire Semihosting syscall interface - * + * * Copyright (c) 2005-2007 CodeSourcery. * * This program is free software; you can redistribute it and/or modify @@ -231,7 +231,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) } case HOSTED_RENAME: if (use_gdb_syscalls()) { - gdb_do_syscall(m68k_semi_cb, "rename,%s,%s", + gdb_do_syscall(m68k_semi_cb, "rename,%s,%s", ARG(0), (int)ARG(1), ARG(2), (int)ARG(3)); return; } else { diff --git a/mips-dis.c b/mips-dis.c index ff4d61c1e..4331a8c55 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -392,10 +392,10 @@ struct mips_opcode "l" 32 bit floating point constant in .lit4 MDMX instruction operands (note that while these use the FP register - fields, they accept both $fN and $vN names for the registers): + fields, they accept both $fN and $vN names for the registers): "O" MDMX alignment offset (OP_*_ALN) "Q" MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT) - "X" MDMX destination register (OP_*_FD) + "X" MDMX destination register (OP_*_FD) "Y" MDMX source register (OP_*_FS) "Z" MDMX source register (OP_*_FT) @@ -1214,7 +1214,7 @@ extern const int bfd_mips16_num_opcodes; Because of the lookup algorithm used, entries with the same opcode name must be contiguous. - + Many instructions are short hand for other instructions (i.e., The jal instruction is short for jalr ). */ @@ -3558,7 +3558,7 @@ print_insn_args (const char *d, lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32; (*info->fprintf_func) (info->stream, "0x%x", lsb); break; - + case 'F': msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32; (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1); diff --git a/monitor.c b/monitor.c index 9ff63130d..6876e7a6f 100644 --- a/monitor.c +++ b/monitor.c @@ -1,8 +1,8 @@ /* * QEMU monitor - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -34,7 +34,7 @@ /* * Supported types: - * + * * 'F' filename * 'B' block device name * 's' string (accept optional quote) @@ -206,7 +206,7 @@ static void do_commit(const char *device) all_devices = !strcmp(device, "all"); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { - if (all_devices || + if (all_devices || !strcmp(bdrv_get_device_name(bs_table[i]), device)) bdrv_commit(bs_table[i]); } @@ -223,7 +223,7 @@ static void do_info(const char *item) if (!item) goto help; for(cmd = info_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(item, cmd->name)) + if (compare_cmd(item, cmd->name)) goto found; } help: @@ -281,7 +281,7 @@ static void do_info_registers(void) cpu_dump_state(env, NULL, monitor_fprintf, X86_DUMP_FPU); #else - cpu_dump_state(env, NULL, monitor_fprintf, + cpu_dump_state(env, NULL, monitor_fprintf, 0); #endif } @@ -294,7 +294,7 @@ static void do_info_cpus(void) mon_get_cpu(); for(env = first_cpu; env != NULL; env = env->next_cpu) { - term_printf("%c CPU #%d:", + term_printf("%c CPU #%d:", (env == mon_cpu) ? '*' : ' ', env->cpu_index); #if defined(TARGET_I386) @@ -333,7 +333,7 @@ static void do_info_history (void) { int i; const char *str; - + i = 0; for(;;) { str = readline_get_history(i); @@ -442,7 +442,7 @@ static void do_logfile(const char *filename) static void do_log(const char *items) { int mask; - + if (!strcmp(items, "none")) { mask = 0; } else { @@ -505,7 +505,7 @@ static void term_printc(int c) term_printf("'"); } -static void memory_dump(int count, int format, int wsize, +static void memory_dump(int count, int format, int wsize, target_ulong addr, int is_physical) { CPUState *env; @@ -529,7 +529,7 @@ static void memory_dump(int count, int format, int wsize, flags = 0; if (env) { #ifdef TARGET_X86_64 - if ((env->efer & MSR_EFER_LMA) && + if ((env->efer & MSR_EFER_LMA) && (env->segs[R_CS].flags & DESC_L_MASK)) flags = 2; else @@ -581,7 +581,7 @@ static void memory_dump(int count, int format, int wsize, break; cpu_memory_rw_debug(env, addr, buf, l, 0); } - i = 0; + i = 0; while (i < l) { switch(wsize) { default: @@ -630,7 +630,7 @@ static void memory_dump(int count, int format, int wsize, #define GET_TLONG(h, l) (l) #endif -static void do_memory_dump(int count, int format, int size, +static void do_memory_dump(int count, int format, int size, uint32_t addrh, uint32_t addrl) { target_long addr = GET_TLONG(addrh, addrl); @@ -690,7 +690,7 @@ static void do_print(int count, int format, int size, unsigned int valh, unsigne term_printf("\n"); } -static void do_memory_save(unsigned int valh, unsigned int vall, +static void do_memory_save(unsigned int valh, unsigned int vall, uint32_t size, const char *filename) { FILE *f; @@ -744,7 +744,7 @@ typedef struct { static const KeyDef key_defs[] = { { 0x2a, "shift" }, { 0x36, "shift_r" }, - + { 0x38, "alt" }, { 0xb8, "alt_r" }, { 0x1d, "ctrl" }, @@ -799,7 +799,7 @@ static const KeyDef key_defs[] = { { 0x30, "b" }, { 0x31, "n" }, { 0x32, "m" }, - + { 0x39, "spc" }, { 0x3a, "caps_lock" }, { 0x3b, "f1" }, @@ -832,7 +832,7 @@ static const KeyDef key_defs[] = { { 0x47, "kp_7" }, { 0x48, "kp_8" }, { 0x49, "kp_9" }, - + { 0x56, "<" }, { 0x57, "f11" }, @@ -879,7 +879,7 @@ static void do_send_key(const char *string) uint8_t keycodes[16]; const char *p; int nb_keycodes, keycode, i; - + nb_keycodes = 0; p = string; while (*p != '\0') { @@ -919,14 +919,14 @@ static void do_send_key(const char *string) static int mouse_button_state; -static void do_mouse_move(const char *dx_str, const char *dy_str, +static void do_mouse_move(const char *dx_str, const char *dy_str, const char *dz_str) { int dx, dy, dz; dx = strtol(dx_str, NULL, 0); dy = strtol(dy_str, NULL, 0); dz = 0; - if (dz_str) + if (dz_str) dz = strtol(dz_str, NULL, 0); kbd_mouse_event(dx, dy, dz, mouse_button_state); } @@ -980,7 +980,7 @@ static void do_system_powerdown(void) #if defined(TARGET_I386) static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask) { - term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n", + term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n", addr, pte & mask, pte & PG_GLOBAL_MASK ? 'G' : '-', @@ -1016,12 +1016,12 @@ static void tlb_info(void) print_pte((l1 << 22), pde, ~((1 << 20) - 1)); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, (uint8_t *)&pte, 4); pte = le32_to_cpu(pte); if (pte & PG_PRESENT_MASK) { - print_pte((l1 << 22) + (l2 << 12), - pte & ~PG_PSE_MASK, + print_pte((l1 << 22) + (l2 << 12), + pte & ~PG_PSE_MASK, ~0xfff); } } @@ -1030,7 +1030,7 @@ static void tlb_info(void) } } -static void mem_print(uint32_t *pstart, int *plast_prot, +static void mem_print(uint32_t *pstart, int *plast_prot, uint32_t end, int prot) { int prot1; @@ -1038,7 +1038,7 @@ static void mem_print(uint32_t *pstart, int *plast_prot, if (prot != prot1) { if (*pstart != -1) { term_printf("%08x-%08x %08x %c%c%c\n", - *pstart, end, end - *pstart, + *pstart, end, end - *pstart, prot1 & PG_USER_MASK ? 'u' : '-', 'r', prot1 & PG_RW_MASK ? 'w' : '-'); @@ -1078,7 +1078,7 @@ static void mem_info(void) mem_print(&start, &last_prot, end, prot); } else { for(l2 = 0; l2 < 1024; l2++) { - cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, + cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, (uint8_t *)&pte, 4); pte = le32_to_cpu(pte); end = (l1 << 22) + (l2 << 12); @@ -1126,7 +1126,7 @@ static void do_info_kqemu(void) #else term_printf("kqemu support: not compiled\n"); #endif -} +} #ifdef CONFIG_PROFILER @@ -1232,9 +1232,9 @@ static void do_wav_capture (const char *path, #endif static term_cmd_t term_cmds[] = { - { "help|?", "s?", do_help, + { "help|?", "s?", do_help, "[cmd]", "show the help" }, - { "commit", "s", do_commit, + { "commit", "s", do_commit, "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" }, { "info", "s?", do_info, "subcommand", "show various information about the system state" }, @@ -1244,52 +1244,52 @@ static term_cmd_t term_cmds[] = { "[-f] device", "eject a removable medium (use -f to force it)" }, { "change", "BF", do_change, "device filename", "change a removable medium" }, - { "screendump", "F", do_screen_dump, + { "screendump", "F", do_screen_dump, "filename", "save screen into PPM image 'filename'" }, { "logfile", "s", do_logfile, "filename", "output logs to 'filename'" }, { "log", "s", do_log, - "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, + "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, { "savevm", "s?", do_savevm, - "tag|id", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" }, + "tag|id", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" }, { "loadvm", "s", do_loadvm, - "tag|id", "restore a VM snapshot from its tag or id" }, + "tag|id", "restore a VM snapshot from its tag or id" }, { "delvm", "s", do_delvm, - "tag|id", "delete a VM snapshot from its tag or id" }, - { "stop", "", do_stop, + "tag|id", "delete a VM snapshot from its tag or id" }, + { "stop", "", do_stop, "", "stop emulation", }, - { "c|cont", "", do_cont, + { "c|cont", "", do_cont, "", "resume emulation", }, #ifdef CONFIG_GDBSTUB - { "gdbserver", "s?", do_gdbserver, + { "gdbserver", "s?", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, #endif - { "x", "/l", do_memory_dump, + { "x", "/l", do_memory_dump, "/fmt addr", "virtual memory dump starting at 'addr'", }, - { "xp", "/l", do_physical_memory_dump, + { "xp", "/l", do_physical_memory_dump, "/fmt addr", "physical memory dump starting at 'addr'", }, - { "p|print", "/l", do_print, + { "p|print", "/l", do_print, "/fmt expr", "print expression value (use $reg for CPU register access)", }, - { "i", "/ii.", do_ioport_read, + { "i", "/ii.", do_ioport_read, "/fmt addr", "I/O port read" }, - { "sendkey", "s", do_send_key, + { "sendkey", "s", do_send_key, "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" }, - { "system_reset", "", do_system_reset, + { "system_reset", "", do_system_reset, "", "reset the system" }, - { "system_powerdown", "", do_system_powerdown, + { "system_powerdown", "", do_system_powerdown, "", "send system power down event" }, - { "sum", "ii", do_sum, + { "sum", "ii", do_sum, "addr size", "compute the checksum of a memory region" }, { "usb_add", "s", do_usb_add, "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, { "usb_del", "s", do_usb_del, "device", "remove USB device 'bus.addr'" }, - { "cpu", "i", do_cpu_set, + { "cpu", "i", do_cpu_set, "index", "set the default CPU" }, - { "mouse_move", "sss?", do_mouse_move, + { "mouse_move", "sss?", do_mouse_move, "dx dy [dz]", "send mouse move events" }, - { "mouse_button", "i", do_mouse_button, + { "mouse_button", "i", do_mouse_button, "state", "change mouse button state (1=L, 2=M, 4=R)" }, { "mouse_set", "i", do_mouse_set, "index", "set which mouse device receives events" }, @@ -1300,9 +1300,9 @@ static term_cmd_t term_cmds[] = { #endif { "stopcapture", "i", do_stop_capture, "capture index", "stop capture" }, - { "memsave", "lis", do_memory_save, + { "memsave", "lis", do_memory_save, "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", }, - { NULL, NULL, }, + { NULL, NULL, }, }; static term_cmd_t info_cmds[] = { @@ -1678,7 +1678,7 @@ static MonitorDef monitor_defs[] = { { NULL }, }; -static void expr_error(const char *fmt) +static void expr_error(const char *fmt) { term_printf(fmt); term_printf("\n"); @@ -1769,7 +1769,7 @@ static target_long expr_unary(void) case '$': { char buf[128], *q; - + pch++; q = buf; while ((*pch >= 'a' && *pch <= 'z') || @@ -1786,7 +1786,7 @@ static target_long expr_unary(void) ret = get_monitor_def(&n, buf); if (ret == -1) expr_error("unknown register"); - else if (ret == -2) + else if (ret == -2) expr_error("no cpu defined"); } break; @@ -1816,7 +1816,7 @@ static target_long expr_prod(void) { target_long val, val2; int op; - + val = expr_unary(); for(;;) { op = *pch; @@ -1831,7 +1831,7 @@ static target_long expr_prod(void) break; case '/': case '%': - if (val2 == 0) + if (val2 == 0) expr_error("division by zero"); if (op == '/') val /= val2; @@ -1989,7 +1989,7 @@ static void monitor_handle_command(const char *cmdline) #ifdef DEBUG term_printf("command='%s'\n", cmdline); #endif - + /* extract the command name */ p = cmdline; q = cmdname; @@ -2005,10 +2005,10 @@ static void monitor_handle_command(const char *cmdline) len = sizeof(cmdname) - 1; memcpy(cmdname, pstart, len); cmdname[len] = '\0'; - + /* find the command */ for(cmd = term_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(cmdname, cmd->name)) + if (compare_cmd(cmdname, cmd->name)) goto found; } term_printf("unknown command: '%s'\n", cmdname); @@ -2017,7 +2017,7 @@ static void monitor_handle_command(const char *cmdline) for(i = 0; i < MAX_ARGS; i++) str_allocated[i] = NULL; - + /* parse the parameters */ typestr = cmd->args_type; nb_args = 0; @@ -2033,8 +2033,8 @@ static void monitor_handle_command(const char *cmdline) { int ret; char *str; - - while (isspace(*p)) + + while (isspace(*p)) p++; if (*typestr == '?') { typestr++; @@ -2074,7 +2074,7 @@ static void monitor_handle_command(const char *cmdline) case '/': { int count, format, size; - + while (isspace(*p)) p++; if (*p == '/') { @@ -2155,7 +2155,7 @@ static void monitor_handle_command(const char *cmdline) case 'l': { target_long val; - while (isspace(*p)) + while (isspace(*p)) p++; if (*typestr == '?' || *typestr == '.') { if (*typestr == '?') { @@ -2166,7 +2166,7 @@ static void monitor_handle_command(const char *cmdline) } else { if (*p == '.') { p++; - while (isspace(*p)) + while (isspace(*p)) p++; has_arg = 1; } else { @@ -2207,17 +2207,17 @@ static void monitor_handle_command(const char *cmdline) { int has_option; /* option */ - + c = *typestr++; if (c == '\0') goto bad_type; - while (isspace(*p)) + while (isspace(*p)) p++; has_option = 0; if (*p == '-') { p++; if (*p != c) { - term_printf("%s: unsupported option -%c\n", + term_printf("%s: unsupported option -%c\n", cmdname, *p); goto fail; } @@ -2239,7 +2239,7 @@ static void monitor_handle_command(const char *cmdline) while (isspace(*p)) p++; if (*p != '\0') { - term_printf("%s: extraneous characters at the end of line\n", + term_printf("%s: extraneous characters at the end of line\n", cmdname); goto fail; } @@ -2314,7 +2314,7 @@ static void file_completion(const char *input) int input_path_len; const char *p; - p = strrchr(input, '/'); + p = strrchr(input, '/'); if (!p) { input_path_len = 0; pstrcpy(file_prefix, sizeof(file_prefix), input); diff --git a/osdep.c b/osdep.c index c24906c99..0eaf2badb 100644 --- a/osdep.c +++ b/osdep.c @@ -1,8 +1,8 @@ /* * QEMU low level functions - * + * * 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 @@ -114,7 +114,7 @@ void *kqemu_vmalloc(size_t size) free_space = (int64_t)stfs.f_bavail * stfs.f_bsize; if ((ram_size + 8192 * 1024) >= free_space) { ram_mb = (ram_size / (1024 * 1024)); - fprintf(stderr, + fprintf(stderr, "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n", tmpdir, ram_mb); if (strcmp(tmpdir, "/dev/shm") == 0) { @@ -123,7 +123,7 @@ void *kqemu_vmalloc(size_t size) "mount -t tmpfs -o size=%dm none /dev/shm\n", ram_mb + 16); } else { - fprintf(stderr, + fprintf(stderr, "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n" "QEMU_TMPDIR environment variable to set another directory where the QEMU\n" "temporary RAM file will be opened.\n"); @@ -132,20 +132,20 @@ void *kqemu_vmalloc(size_t size) exit(1); } } - snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", + snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", tmpdir); phys_ram_fd = mkstemp(phys_ram_file); if (phys_ram_fd < 0) { - fprintf(stderr, + fprintf(stderr, "warning: could not create temporary file in '%s'.\n" "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n" "Using '/tmp' as fallback.\n", tmpdir); - snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", + snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", "/tmp"); phys_ram_fd = mkstemp(phys_ram_file); if (phys_ram_fd < 0) { - fprintf(stderr, "Could not create temporary memory file '%s'\n", + fprintf(stderr, "Could not create temporary memory file '%s'\n", phys_ram_file); exit(1); } @@ -154,9 +154,9 @@ void *kqemu_vmalloc(size_t size) } size = (size + 4095) & ~4095; ftruncate(phys_ram_fd, phys_ram_size + size); - ptr = mmap(NULL, - size, - PROT_WRITE | PROT_READ, MAP_SHARED, + ptr = mmap(NULL, + size, + PROT_WRITE | PROT_READ, MAP_SHARED, phys_ram_fd, phys_ram_size); if (ptr == MAP_FAILED) { fprintf(stderr, "Could not map physical memory\n"); @@ -242,7 +242,7 @@ int qemu_create_pidfile(const char *filename) BOOL ret; /* Open for writing with no sharing. */ - file = CreateFile(filename, GENERIC_WRITE, 0, NULL, + file = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file == INVALID_HANDLE_VALUE) @@ -257,7 +257,7 @@ int qemu_create_pidfile(const char *filename) /* Write PID to file. */ len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); - ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len, + ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len, &overlap, NULL); if (ret == 0) return -1; diff --git a/ppc-dis.c b/ppc-dis.c index f6fad8861..f9ae53e1d 100644 --- a/ppc-dis.c +++ b/ppc-dis.c @@ -646,7 +646,7 @@ const struct powerpc_operand powerpc_operands[] = same. */ /*ARGSUSED*/ -static unsigned long +static unsigned long insert_bat (insn, value, errmsg) uint32_t insn; int32_t value; @@ -1122,7 +1122,7 @@ insert_ras (insn, value, errmsg) extraction function just checks that the fields are the same. */ /*ARGSUSED*/ -static unsigned long +static unsigned long insert_rbs (insn, value, errmsg) uint32_t insn; int32_t value; diff --git a/qemu-doc.texi b/qemu-doc.texi index c49e221cb..249fd0525 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -50,13 +50,13 @@ QEMU has two operating modes: @itemize @minus -@item +@item Full system emulation. In this mode, QEMU emulates a full system (for example a PC), including one or several processors and various peripherals. It can be used to launch different Operating Systems without rebooting the PC or to debug system code. -@item +@item User mode emulation. In this mode, QEMU can launch processes compiled for one CPU on another CPU. It can be used to launch the Wine Windows API emulator (@url{http://www.winehq.org}) or @@ -65,7 +65,7 @@ to ease cross-compilation and cross-debugging. @end itemize QEMU can run without an host kernel driver and yet gives acceptable -performance. +performance. For system emulation, the following hardware targets are supported: @itemize @@ -143,18 +143,18 @@ The QEMU PC System emulator simulates the following peripherals: @itemize @minus -@item +@item i440FX host PCI bridge and PIIX3 PCI to ISA bridge @item Cirrus CLGD 5446 PCI VGA card or dummy VGA card with Bochs VESA extensions (hardware level, including all non standard modes). @item PS/2 mouse and keyboard -@item +@item 2 PCI IDE interfaces with hard disk and CD-ROM support @item Floppy disk -@item +@item PCI/ISA PCI network adapters @item Serial ports @@ -476,12 +476,12 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \ @item -net socket[,vlan=n][,fd=h][,mcast=maddr:port] Create a VLAN @var{n} shared with another QEMU virtual -machines using a UDP multicast socket, effectively making a bus for +machines using a UDP multicast socket, effectively making a bus for every QEMU with same multicast address @var{maddr} and @var{port}. NOTES: @enumerate -@item -Several QEMU can be running on different hosts and share same bus (assuming +@item +Several QEMU can be running on different hosts and share same bus (assuming correct multicast setup for these hosts). @item mcast support is compatible with User Mode Linux (argument @option{eth@var{N}=mcast}), see @@ -591,10 +591,10 @@ for easier testing of various kernels. @table @option -@item -kernel bzImage +@item -kernel bzImage Use @var{bzImage} as kernel image. -@item -append cmdline +@item -append cmdline Use @var{cmdline} as kernel command line @item -initrd file @@ -751,13 +751,13 @@ character to Control-t. @end table @item -s -Wait gdb connection to port 1234 (@pxref{gdb_usage}). +Wait gdb connection to port 1234 (@pxref{gdb_usage}). @item -p port Change gdb connection port. @var{port} can be either a decimal number to specify a TCP port, or a host device (same devices as the serial port). @item -S Do not start CPU at startup (you must type 'c' in the monitor). -@item -d +@item -d Output log in /tmp/qemu.log @item -hdachs c,h,s,[,t] Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= @@ -832,9 +832,9 @@ During emulation, if you are using the @option{-nographic} option, use @table @key @item Ctrl-a h Print this help -@item Ctrl-a x +@item Ctrl-a x Exit emulator -@item Ctrl-a s +@item Ctrl-a s Save disk data back to file (if -snapshot) @item Ctrl-a t toggle console timestamps @@ -872,7 +872,7 @@ emulator. You can use it to: Remove or insert removable media images (such as CD-ROM or floppies) -@item +@item Freeze/unfreeze the Virtual Machine (VM) and save or restore its state from a disk file. @@ -889,10 +889,10 @@ The following commands are available: @item help or ? [cmd] Show the help for all commands or just for command @var{cmd}. -@item commit +@item commit Commit changes to the disk images (if -snapshot is used) -@item info subcommand +@item info subcommand show various information about the system state @table @option @@ -1026,7 +1026,7 @@ Physical memory dump starting at @var{addr}. data. Its syntax is: @option{/@{count@}@{format@}@{size@}} @table @var -@item count +@item count is the number of items to be dumped. @item format @@ -1040,11 +1040,11 @@ respectively select 16 or 32 bit code instruction size. @end table -Examples: +Examples: @itemize @item Dump 10 instructions at the current instruction pointer: -@example +@example (qemu) x/10i $eip 0x90107063: ret 0x90107064: sti @@ -1060,7 +1060,7 @@ Dump 10 instructions at the current instruction pointer: @item Dump 80 16 bit values at the start of the video memory. -@smallexample +@smallexample (qemu) xp/80hx 0xb8000 0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42 0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41 @@ -1197,10 +1197,10 @@ but they are deleted as soon as you exit QEMU. VM snapshots currently have the following known limitations: @itemize -@item +@item They cannot cope with removable devices if they are removed or inserted after a snapshot is done. -@item +@item A few device drivers still have incomplete snapshot support so their state is not saved or restored properly (in particular USB). @end itemize @@ -1266,7 +1266,7 @@ modifications are written in a temporary file). @subsubsection Mac OS X -@file{/dev/cdrom} is an alias to the first CDROM. +@file{/dev/cdrom} is an alias to the first CDROM. Currently there is no specific code to handle removable media, so it is better to use the @code{change} or @code{eject} monitor commands to @@ -1278,7 +1278,7 @@ change or eject media. QEMU can automatically create a virtual FAT disk image from a directory tree. In order to use it, just type: -@example +@example qemu linux.img -hdb fat:/my_directory @end example @@ -1288,14 +1288,14 @@ them via SAMBA or NFS. The default access is @emph{read-only}. Floppies can be emulated with the @code{:floppy:} option: -@example +@example qemu linux.img -fda fat:floppy:/my_directory @end example A read/write support is available for testing (beta stage) with the @code{:rw:} option: -@example +@example qemu linux.img -fda fat:floppy:rw:/my_directory @end example @@ -1363,7 +1363,7 @@ network). The virtual network configuration is the following: | (10.0.2.2) | ----> DNS server (10.0.2.3) - | + | ----> SMB server (10.0.2.4) @end example @@ -1473,7 +1473,7 @@ using it. USB devices requiring real time streaming (i.e. USB Video Cameras) are not supported yet. @enumerate -@item If you use an early Linux 2.4 kernel, verify that no Linux driver +@item If you use an early Linux 2.4 kernel, verify that no Linux driver is actually using the USB device. A simple way to do that is simply to disable the corresponding kernel module by renaming it from @file{mydriver.o} to @file{mydriver.o.disabled}. @@ -1490,7 +1490,7 @@ chown -R myuid /proc/bus/usb @end example @item Launch QEMU and do in the monitor: -@example +@example info usbhost Device 1.2, speed 480 Mb/s Class 00: USB device 1234:5678, USB DISK @@ -1499,7 +1499,7 @@ You should see the list of the devices you can use (Never try to use hubs, it won't work). @item Add the device in QEMU by using: -@example +@example usb_add host:1234:5678 @end example @@ -1826,7 +1826,7 @@ Bartlett): go to the Control Panel => Add/Remove Hardware & Next => Add/Troubleshoot a device => Add a new device & Next => No, select the hardware from a list & Next => NT Apm/Legacy Support & Next => Next (again) a few times. Now the driver is installed and Windows 2000 now -correctly instructs QEMU to shutdown at the appropriate moment. +correctly instructs QEMU to shutdown at the appropriate moment. @subsubsection Share a directory between Unix and Windows @@ -1881,13 +1881,13 @@ or PowerMac PowerPC system. QEMU emulates the following PowerMac peripherals: @itemize @minus -@item -UniNorth PCI Bridge +@item +UniNorth PCI Bridge @item PCI VGA compatible card with VESA Bochs Extensions -@item +@item 2 PMAC IDE interfaces with hard disk and CD-ROM support -@item +@item NE2000 PCI adapters @item Non Volatile RAM @@ -1898,15 +1898,15 @@ VIA-CUDA with ADB keyboard and mouse. QEMU emulates the following PREP peripherals: @itemize @minus -@item +@item PCI Bridge @item PCI VGA compatible card with VESA Bochs Extensions -@item +@item 2 IDE interfaces with hard disk and CD-ROM support @item Floppy disk -@item +@item NE2000 network adapters @item Serial port @@ -1925,13 +1925,13 @@ The following options are specific to the PowerPC emulation: @table @option -@item -g WxH[xDEPTH] +@item -g WxH[xDEPTH] Set the initial VGA graphic mode. The default is 800x600x15. @end table -@c man end +@c man end More information is available at @@ -1950,7 +1950,7 @@ QEMU emulates the following sun4m peripherals: IOMMU @item TCX Frame buffer -@item +@item Lance (Am7990) Ethernet @item Non Volatile RAM M48T08 @@ -2002,7 +2002,7 @@ Set the emulated machine type. Default is SS-5. @end table -@c man end +@c man end @node Sparc64 System emulator @section Sparc64 System emulator @@ -2014,7 +2014,7 @@ QEMU emulates the following sun4u peripherals: @itemize @minus @item -UltraSparc IIi APB PCI Bridge +UltraSparc IIi APB PCI Bridge @item PCI VGA compatible card with VESA Bochs Extensions @item @@ -2043,7 +2043,7 @@ install Debian into a virtual disk image. The following devices are emulated: @itemize @minus -@item +@item MIPS 24Kf CPU @item PC style serial port @@ -2095,7 +2095,7 @@ devices: ARM926E, ARM1026E or ARM946E CPU @item Two PL011 UARTs -@item +@item SMC 91c111 Ethernet adapter @item PL110 LCD controller @@ -2114,7 +2114,7 @@ ARM926E CPU PL190 Vectored Interrupt Controller @item Four PL011 UARTs -@item +@item SMC 91c111 Ethernet adapter @item PL110 LCD controller @@ -2143,7 +2143,7 @@ ARM926E CPU ARM AMBA Generic/Distributed Interrupt Controller @item Four PL011 UARTs -@item +@item SMC 91c111 Ethernet adapter @item PL110 LCD controller @@ -2201,7 +2201,7 @@ The emulator is able to boot a uClinux kernel. The M5208EVB emulation includes the following devices: @itemize @minus -@item +@item MCF5208 ColdFire V2 Microprocessor (ISA A+ with EMAC). @item Three Two on-chip UARTs. @@ -2212,14 +2212,14 @@ Fast Ethernet Controller (FEC) The AN5206 emulation includes the following devices: @itemize @minus -@item +@item MCF5206 ColdFire V2 Microprocessor. @item Two on-chip UARTs. @end itemize -@node QEMU User space emulator -@chapter QEMU User space emulator +@node QEMU User space emulator +@chapter QEMU User space emulator @menu * Supported Operating Systems :: @@ -2253,14 +2253,14 @@ Mac OS X/Darwin (referred as qemu-darwin-user) @subsection Quick Start In order to launch a Linux process, QEMU needs the process executable -itself and all the target (x86) dynamic libraries used by it. +itself and all the target (x86) dynamic libraries used by it. @itemize @item On x86, you can just try to launch any process by using the native libraries: -@example +@example qemu-i386 -L / /bin/ls @end example @@ -2270,7 +2270,7 @@ qemu-i386 -L / /bin/ls @item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources): -@example +@example qemu-i386 -L / qemu-i386 -L / /bin/ls @end example @@ -2279,7 +2279,7 @@ qemu-i386 -L / qemu-i386 -L / /bin/ls @code{LD_LIBRARY_PATH} is not set: @example -unset LD_LIBRARY_PATH +unset LD_LIBRARY_PATH @end example Then you can launch the precompiled @file{ls} x86 executable: @@ -2314,7 +2314,7 @@ qemu-i386 /usr/local/qemu-i386/bin/ls-i386 @end example @item Download the binary x86 Wine install -(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page). +(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page). @item Configure Wine on your account. Look at the provided script @file{/usr/local/qemu-i386/@/bin/wine-conf.sh}. Your previous @@ -2339,7 +2339,7 @@ usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] @table @option @item -h Print the help -@item -L path +@item -L path Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) @item -s size Set the x86 stack size in bytes (default=524288) @@ -2405,20 +2405,20 @@ CD or compile them by hand. @item On x86, you can just try to launch any process by using the native libraries: -@example +@example qemu-i386 /bin/ls @end example or to run the ppc version of the executable: -@example +@example qemu-ppc /bin/ls @end example @item On ppc, you'll have to tell qemu where your x86 libraries (and dynamic linker) are installed: -@example +@example qemu-i386 -L /opt/x86_root/ /bin/ls @end example @@ -2437,7 +2437,7 @@ usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] @table @option @item -h Print the help -@item -L path +@item -L path Set the library root path (default=/) @item -s size Set the stack size in bytes (default=524288) @@ -2504,7 +2504,7 @@ these older versions so that usually you don't have to do anything. @url{http://www.mingw.org/}. You can find detailed installation instructions in the download section and the FAQ. -@item Download +@item Download the MinGW development library of SDL 1.2.x (@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from @url{http://www.libsdl.org}. Unpack it in a temporary place, and @@ -2513,14 +2513,14 @@ directory. Edit the @file{sdl-config} script so that it gives the correct SDL directory when invoked. @item Extract the current version of QEMU. - + @item Start the MSYS shell (file @file{msys.bat}). -@item Change to the QEMU directory. Launch @file{./configure} and +@item Change to the QEMU directory. Launch @file{./configure} and @file{make}. If you have problems using SDL, verify that @file{sdl-config} can be launched from the MSYS command line. -@item You can install QEMU in @file{Program Files/Qemu} by typing +@item You can install QEMU in @file{Program Files/Qemu} by typing @file{make install}. Don't forget to copy @file{SDL.dll} in @file{Program Files/Qemu}. @@ -2534,13 +2534,13 @@ correct SDL directory when invoked. Install the MinGW cross compilation tools available at @url{http://www.mingw.org/}. -@item +@item Install the Win32 version of SDL (@url{http://www.libsdl.org}) by unpacking @file{i386-mingw32msvc.tar.gz}. Set up the PATH environment variable so that @file{i386-mingw32msvc-sdl-config} can be launched by the QEMU configuration script. -@item +@item Configure QEMU for Windows cross compilation: @example ./configure --enable-mingw32 @@ -2549,9 +2549,9 @@ If necessary, you can change the cross-prefix according to the prefix chosen for the MinGW tools with --cross-prefix. You can also use --prefix to set the Win32 install path. -@item You can install QEMU in the installation directory by typing +@item You can install QEMU in the installation directory by typing @file{make install}. Don't forget to copy @file{SDL.dll} in the -installation directory. +installation directory. @end itemize diff --git a/qemu-img.c b/qemu-img.c index e7d190b1e..6712f81fd 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1,8 +1,8 @@ /* * QEMU disk image utility - * + * * Copyright (c) 2003-2007 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 @@ -75,7 +75,7 @@ void term_print_filename(const char *filename) term_printf(filename); } -void __attribute__((noreturn)) error(const char *fmt, ...) +void __attribute__((noreturn)) error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -166,7 +166,7 @@ static void term_init(void) tty.c_cflag |= CS8; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; - + tcsetattr (0, TCSANOW, &tty); atexit(term_exit); @@ -248,7 +248,7 @@ static int img_create(int argc, char **argv) int64_t size; const char *p; BlockDriver *drv; - + encrypted = 0; for(;;) { c = getopt(argc, argv, "b:f:he"); @@ -269,7 +269,7 @@ static int img_create(int argc, char **argv) break; } } - if (optind >= argc) + if (optind >= argc) help(); filename = argv[optind++]; size = 0; @@ -338,7 +338,7 @@ static int img_commit(int argc, char **argv) break; } } - if (optind >= argc) + if (optind >= argc) help(); filename = argv[optind++]; @@ -446,13 +446,13 @@ static int img_convert(int argc, char **argv) break; } } - if (optind >= argc) + if (optind >= argc) help(); filename = argv[optind++]; - if (optind >= argc) + if (optind >= argc) help(); out_filename = argv[optind++]; - + bs = bdrv_new_open(filename, fmt); drv = bdrv_find_format(out_fmt); @@ -473,7 +473,7 @@ static int img_convert(int argc, char **argv) error("Error while formatting '%s'", out_filename); } } - + out_bs = bdrv_new_open(out_filename, out_fmt); if (compress) { @@ -492,12 +492,12 @@ static int img_convert(int argc, char **argv) n = cluster_sectors; else n = nb_sectors; - if (bdrv_read(bs, sector_num, buf, n) < 0) + if (bdrv_read(bs, sector_num, buf, n) < 0) error("error while reading"); if (n < cluster_sectors) memset(buf + n * 512, 0, cluster_size - n * 512); if (is_not_zero(buf, cluster_size)) { - if (bdrv_write_compressed(out_bs, sector_num, buf, + if (bdrv_write_compressed(out_bs, sector_num, buf, cluster_sectors) != 0) error("error while compressing sector %" PRId64, sector_num); @@ -516,7 +516,7 @@ static int img_convert(int argc, char **argv) n = (IO_BUF_SIZE / 512); else n = nb_sectors; - if (bdrv_read(bs, sector_num, buf, n) < 0) + if (bdrv_read(bs, sector_num, buf, n) < 0) error("error while reading"); /* NOTE: at the same time we convert, we do not write zero sectors to have a chance to compress the image. Ideally, we @@ -524,7 +524,7 @@ static int img_convert(int argc, char **argv) buf1 = buf; while (n > 0) { if (is_allocated_sectors(buf1, n, &n1)) { - if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) + if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) error("error while writing"); } sector_num += n1; @@ -554,7 +554,7 @@ static int64_t get_allocated_file_size(const char *filename) return (((int64_t) high) << 32) + low; } - if (_stati64(filename, &st) < 0) + if (_stati64(filename, &st) < 0) return -1; return st.st_size; } @@ -562,7 +562,7 @@ static int64_t get_allocated_file_size(const char *filename) static int64_t get_allocated_file_size(const char *filename) { struct stat st; - if (stat(filename, &st) < 0) + if (stat(filename, &st) < 0) return -1; return (int64_t)st.st_blocks * 512; } @@ -612,7 +612,7 @@ static int img_info(int argc, char **argv) break; } } - if (optind >= argc) + if (optind >= argc) help(); filename = argv[optind++]; @@ -636,26 +636,26 @@ static int img_info(int argc, char **argv) if (allocated_size < 0) sprintf(dsize_buf, "unavailable"); else - get_human_readable_size(dsize_buf, sizeof(dsize_buf), + get_human_readable_size(dsize_buf, sizeof(dsize_buf), allocated_size); printf("image: %s\n" "file format: %s\n" "virtual size: %s (%" PRId64 " bytes)\n" "disk size: %s\n", - filename, fmt_name, size_buf, + filename, fmt_name, size_buf, (total_sectors * 512), dsize_buf); if (bdrv_is_encrypted(bs)) printf("encrypted: yes\n"); if (bdrv_get_info(bs, &bdi) >= 0) { - if (bdi.cluster_size != 0) + if (bdi.cluster_size != 0) printf("cluster_size: %d\n", bdi.cluster_size); } bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); if (backing_filename[0] != '\0') { path_combine(backing_filename2, sizeof(backing_filename2), filename, backing_filename); - printf("backing file: %s (actual path: %s)\n", + printf("backing file: %s (actual path: %s)\n", backing_filename, backing_filename2); } diff --git a/qemu-img.texi b/qemu-img.texi index bf49ec99d..5b99dff0a 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -18,11 +18,11 @@ Command parameters: @table @var @item filename is a disk image filename -@item base_image +@item base_image is the read-only disk image which is used as base for a copy on write image; the copy on write image only stores the modified data -@item fmt +@item fmt is the disk image format. It is guessed automatically in most cases. The following formats are supported: @table @code @@ -53,19 +53,19 @@ Linux Compressed Loop image, useful only to reuse directly compressed CD-ROM images present for example in the Knoppix CD-ROMs. @end table -@item size +@item size is the disk image size in kilobytes. Optional suffixes @code{M} -(megabyte) and @code{G} (gigabyte) are supported +(megabyte) and @code{G} (gigabyte) are supported @item output_filename -is the destination disk image filename +is the destination disk image filename @item output_fmt is the destination format @item -c indicates that target image must be compressed (qcow format only) -@item -e +@item -e indicates that the target image must be encrypted (qcow format only) @end table @@ -75,7 +75,7 @@ Command description: @item create [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] Create the new disk image @var{filename} of size @var{size} and format -@var{fmt}. +@var{fmt}. If @var{base_image} is specified, then the image will record only the differences from @var{base_image}. No size needs to be specified in diff --git a/qemu-tech.texi b/qemu-tech.texi index c3b5bd504..242bbb641 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -50,13 +50,13 @@ QEMU has two operating modes: @itemize @minus -@item +@item Full system emulation. In this mode, QEMU emulates a full system (usually a PC), including a processor and various peripherals. It can be used to launch an different Operating System without rebooting the PC or to debug system code. -@item +@item User mode emulation (Linux host only). In this mode, QEMU can launch Linux processes compiled for one CPU on another CPU. It can be used to launch the Wine Windows API emulator (@url{http://www.winehq.org}) or @@ -69,7 +69,7 @@ easy to use. QEMU generic features: -@itemize +@itemize @item User space only or full system emulation. @@ -81,23 +81,23 @@ QEMU generic features: @item Precise exceptions support. -@item The virtual CPU is a library (@code{libqemu}) which can be used +@item The virtual CPU is a library (@code{libqemu}) which can be used in other projects (look at @file{qemu/tests/qruncom.c} to have an example of user mode @code{libqemu} usage). @end itemize QEMU user mode emulation features: -@itemize +@itemize @item Generic Linux system call converter, including most ioctls. @item clone() emulation using native CPU clone() to use Linux scheduler for threads. -@item Accurate signal handling by remapping host signals to target signals. +@item Accurate signal handling by remapping host signals to target signals. @end itemize QEMU full system emulation features: -@itemize +@itemize @item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU. @end itemize @@ -106,23 +106,23 @@ QEMU full system emulation features: QEMU x86 target features: -@itemize +@itemize -@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. +@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU. @item Support of host page sizes bigger than 4KB in user mode emulation. @item QEMU can emulate itself on x86. -@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}. +@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}. It can be used to test other x86 virtual CPUs. @end itemize Current QEMU limitations: -@itemize +@itemize @item No SSE/MMX support (yet). @@ -130,11 +130,11 @@ Current QEMU limitations: @item IPC syscalls are missing. -@item The x86 segment limits and access rights are not tested at every +@item The x86 segment limits and access rights are not tested at every memory access (yet). Hopefully, very few OSes seem to rely on that for normal use. -@item On non x86 host CPUs, @code{double}s are used instead of the non standard +@item On non x86 host CPUs, @code{double}s are used instead of the non standard 10 byte @code{long double}s of x86 for floating point emulation to get maximum performances. @@ -185,7 +185,7 @@ Current QEMU limitations: @itemize -@item Full PowerPC 32 bit emulation, including privileged instructions, +@item Full PowerPC 32 bit emulation, including privileged instructions, FPU and MMU. @item Can run most PowerPC Linux binaries. @@ -207,7 +207,7 @@ instructions, FPU and I/D MMU, but misses most VIS instructions. Current QEMU limitations: -@itemize +@itemize @item IPC syscalls are missing. @@ -306,7 +306,7 @@ to generate a dynamic code generator which concatenates the simple instructions to build a function (see @file{op.h:dyngen_code()}). In essence, the process is similar to [1], but more work is done at -compile time. +compile time. A key idea to get optimal performances is that constant parameters can be passed to the simple operations. For that purpose, dummy ELF @@ -398,7 +398,7 @@ translated code in the page and enables write accesses to the page. Correct translated code invalidation is done efficiently by maintaining a linked list of every translated block contained in a given page. Other -linked lists are also maintained to undo direct block chaining. +linked lists are also maintained to undo direct block chaining. Although the overhead of doing @code{mprotect()} calls is important, most MSDOS programs can be emulated at reasonnable speed with QEMU and @@ -418,7 +418,7 @@ only data is modified in the page. @section Exception support longjmp() is used when an exception such as division by zero is -encountered. +encountered. The host SIGSEGV and SIGBUS signal handlers are used to get invalid memory accesses. The exact CPU state can be retrieved because all the @@ -446,7 +446,7 @@ speed up the translation. In order to avoid flushing the translated code each time the MMU mappings change, QEMU uses a physically indexed translation cache. It -means that each basic block is indexed with its physical address. +means that each basic block is indexed with its physical address. When MMU mappings change, only the chaining of the basic blocks is reset (i.e. a basic block can no longer jump directly to another one). @@ -525,7 +525,7 @@ relocated at load time. @table @asis -@item [1] +@item [1] @url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio Riccardi. @@ -552,23 +552,23 @@ Chernoff and Ray Hookway. Willows Software. @item [7] -@url{http://user-mode-linux.sourceforge.net/}, +@url{http://user-mode-linux.sourceforge.net/}, The User-mode Linux Kernel. @item [8] -@url{http://www.plex86.org/}, +@url{http://www.plex86.org/}, The new Plex86 project. @item [9] -@url{http://www.vmware.com/}, +@url{http://www.vmware.com/}, The VMWare PC virtualizer. @item [10] -@url{http://www.microsoft.com/windowsxp/virtualpc/}, +@url{http://www.microsoft.com/windowsxp/virtualpc/}, The VirtualPC PC virtualizer. @item [11] -@url{http://www.twoostwo.org/}, +@url{http://www.twoostwo.org/}, The TwoOStwo PC virtualizer. @end table diff --git a/readline.c b/readline.c index 577881a19..5f163afa7 100644 --- a/readline.c +++ b/readline.c @@ -1,8 +1,8 @@ /* * QEMU readline utility - * + * * Copyright (c) 2003-2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -221,7 +221,7 @@ static void term_up_char(void) } term_hist_entry--; if (term_hist_entry >= 0) { - pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), + pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), term_history[term_hist_entry]); term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); } @@ -304,7 +304,7 @@ static void term_completion(void) char *cmdline; nb_completions = 0; - + cmdline = qemu_malloc(term_cmd_buf_index + 1); if (!cmdline) return; diff --git a/s390-dis.c b/s390-dis.c index af7d9964e..b325b08c2 100644 --- a/s390-dis.c +++ b/s390-dis.c @@ -569,7 +569,7 @@ const struct s390_operand s390_operands[] = quite close. For example the instruction "mvo" is defined in the PoP as follows: - + MVO D1(L1,B1),D2(L2,B2) [SS] -------------------------------------- diff --git a/sdl.c b/sdl.c index 16e4df633..2233711fd 100644 --- a/sdl.c +++ b/sdl.c @@ -1,8 +1,8 @@ /* * QEMU SDL display 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 @@ -345,7 +345,7 @@ static void sdl_refresh(DisplayState *ds) { SDL_Event ev1, *ev = &ev1; int mod_state; - + if (last_vm_running != vm_running) { last_vm_running = vm_running; sdl_update_caption(); @@ -377,7 +377,7 @@ static void sdl_refresh(DisplayState *ds) toggle_full_screen(ds); gui_keysym = 1; break; - case 0x02 ... 0x0a: /* '1' to '9' keys */ + case 0x02 ... 0x0a: /* '1' to '9' keys */ /* Reset the modifiers sent to the current console */ reset_keys(); console_select(keycode - 0x02); @@ -460,7 +460,7 @@ static void sdl_refresh(DisplayState *ds) } } } - if (is_graphic_console() && !gui_keysym) + if (is_graphic_console() && !gui_keysym) sdl_process_key(&ev->key); break; case SDL_QUIT: @@ -494,7 +494,7 @@ static void sdl_refresh(DisplayState *ds) } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) { dz = 1; } -#endif +#endif sdl_send_mouse_event(dz); } } @@ -578,7 +578,7 @@ static void sdl_mouse_define(int width, int height, int bpp, SDL_SetCursor(guest_sprite); } -static void sdl_cleanup(void) +static void sdl_cleanup(void) { if (guest_sprite) SDL_FreeCursor(guest_sprite); diff --git a/sh4-dis.c b/sh4-dis.c index 5f45e5ed2..164ce4ffe 100644 --- a/sh4-dis.c +++ b/sh4-dis.c @@ -483,7 +483,7 @@ const sh_opcode_info sh_table[] = /* 0100nnnn10111010 lds ,Y1 */{"lds",{A_REG_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, /* 0100nnnn01011010 lds ,FPUL */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}, arch_sh2e_up}, - + /* 0100nnnn01101010 lds ,FPSCR */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}, arch_sh2e_up}, /* 0100nnnn00000110 lds.l @+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}, arch_sh1_up}, @@ -505,7 +505,7 @@ const sh_opcode_info sh_table[] = /* 0100nnnn10110110 lds.l @+,Y1 */{"lds.l",{A_INC_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_6}, arch_sh_dsp_up}, /* 0100nnnn01010110 lds.l @+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}, arch_sh2e_up}, - + /* 0100nnnn01100110 lds.l @+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}, arch_sh2e_up}, /* 0000000000111000 ldtlb */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}, arch_sh3_up}, @@ -758,7 +758,7 @@ const sh_opcode_info sh_table[] = /* 0000nnnn10111010 sts Y1, */{"sts",{A_Y1,A_REG_N},{HEX_0,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, /* 0000nnnn01011010 sts FPUL, */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}, arch_sh2e_up}, - + /* 0000nnnn01101010 sts FPSCR, */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh2e_up}, /* 0100nnnn00000010 sts.l MACH,@-*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}, arch_sh1_up}, @@ -780,7 +780,7 @@ const sh_opcode_info sh_table[] = /* 0100nnnn10110110 sts.l Y1,@- */{"sts.l",{A_Y1,A_DEC_N},{HEX_4,REG_N,HEX_B,HEX_2}, arch_sh_dsp_up}, /* 0100nnnn01010010 sts.l FPUL,@-*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}, arch_sh2e_up}, - + /* 0100nnnn01100010 sts.l FPSCR,@-*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh2e_up}, /* 0011nnnnmmmm1000 sub , */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}, arch_sh1_up}, @@ -1155,7 +1155,7 @@ const sh_opcode_info sh_table[] = /* 0011nnnnmmmm0001 1001dddddddddddd movu.w @(,), */ {"movu.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_9,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32}, -{ 0, {0}, {0}, 0 } +{ 0, {0}, {0}, 0 } }; #endif @@ -1293,7 +1293,7 @@ print_insn_ddt (insn, info) while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3) || op->nibbles[3] != (unsigned) (insn & 0xf)) op++; - + print_movxy (op, (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0) + 2 * is_movy diff --git a/slirp/COPYRIGHT b/slirp/COPYRIGHT index 2e868624f..3f331ee07 100644 --- a/slirp/COPYRIGHT +++ b/slirp/COPYRIGHT @@ -16,7 +16,7 @@ The copyright terms and conditions: ---BEGIN--- Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/slirp/bootp.c b/slirp/bootp.c index 9d243a705..ebefa08b4 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -1,8 +1,8 @@ /* * QEMU BOOTP/DHCP server - * + * * 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 @@ -89,7 +89,7 @@ static void dhcp_decode(const uint8_t *buf, int size, const uint8_t *p, *p_end; int len, tag; - *pmsg_type = 0; + *pmsg_type = 0; p = buf; p_end = buf + size; @@ -101,7 +101,7 @@ static void dhcp_decode(const uint8_t *buf, int size, while (p < p_end) { tag = p[0]; if (tag == RFC1533_PAD) { - p++; + p++; } else if (tag == RFC1533_END) { break; } else { @@ -137,16 +137,16 @@ static void bootp_reply(struct bootp_t *bp) /* extract exact DHCP msg type */ dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type); - + if (dhcp_msg_type == 0) dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ - - if (dhcp_msg_type != DHCPDISCOVER && + + if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST) return; /* XXX: this is a hack to get the client mac address */ memcpy(client_ethaddr, bp->bp_hwaddr, 6); - + if ((m = m_get()) == NULL) return; m->m_data += if_maxlinkhdr; @@ -203,7 +203,7 @@ static void bootp_reply(struct bootp_t *bp) *q++ = 1; *q++ = DHCPACK; } - + if (dhcp_msg_type == DHCPDISCOVER || dhcp_msg_type == DHCPREQUEST) { *q++ = RFC2132_SRV_ID; @@ -217,12 +217,12 @@ static void bootp_reply(struct bootp_t *bp) *q++ = 0xff; *q++ = 0xff; *q++ = 0x00; - + *q++ = RFC1533_GATEWAY; *q++ = 4; memcpy(q, &saddr.sin_addr, 4); q += 4; - + *q++ = RFC1533_DNS; *q++ = 4; dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); @@ -244,8 +244,8 @@ static void bootp_reply(struct bootp_t *bp) } } *q++ = RFC1533_END; - - m->m_len = sizeof(struct bootp_t) - + + m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); } diff --git a/slirp/cksum.c b/slirp/cksum.c index f8f7512b6..ee7e8644a 100644 --- a/slirp/cksum.c +++ b/slirp/cksum.c @@ -41,7 +41,7 @@ * * This routine is very heavily used in the network * code and should be modified for each CPU to be as fast as possible. - * + * * XXX Since we will never span more than 1 mbuf, we can optimise this */ @@ -63,13 +63,13 @@ int cksum(struct mbuf *m, int len) u_int16_t s[2]; u_int32_t l; } l_util; - + if (m->m_len == 0) goto cont; w = mtod(m, u_int16_t *); - + mlen = m->m_len; - + if (len < mlen) mlen = len; len -= mlen; @@ -107,7 +107,7 @@ int cksum(struct mbuf *m, int len) while ((mlen -= 2) >= 0) { sum += *w++; } - + if (byte_swapped) { REDUCE; sum <<= 8; @@ -117,11 +117,11 @@ int cksum(struct mbuf *m, int len) sum += s_util.s; mlen = 0; } else - + mlen = -1; } else if (mlen == -1) s_util.c[0] = *(u_int8_t *)w; - + cont: #ifdef DEBUG if (len) { diff --git a/slirp/debug.c b/slirp/debug.c index d3d8c5796..607b0e76e 100644 --- a/slirp/debug.c +++ b/slirp/debug.c @@ -1,8 +1,8 @@ /* * Copyright (c) 1995 Danny Gasparovski. * Portions copyright (c) 2000 Kelly Price. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -18,7 +18,7 @@ int slirp_debug = 0; extern char *strerror _P((int)); -/* Carry over one item from main.c so that the tty's restored. +/* Carry over one item from main.c so that the tty's restored. * Only done when the tty being used is /dev/tty --RedWolf */ extern struct termios slirp_tty_settings; extern int slirp_tty_restore; @@ -32,7 +32,7 @@ debug_init(file, dbg) /* Close the old debugging file */ if (dfd) fclose(dfd); - + dfd = fopen(file,"w"); if (dfd != NULL) { #if 0 @@ -58,7 +58,7 @@ dump_packet(dat, n) { u_char *pptr = (u_char *)dat; int j,k; - + n /= 16; n++; DEBUG_MISC((dfd, "PACKET DUMPED: \n")); @@ -74,7 +74,7 @@ dump_packet(dat, n) #if 0 /* * Statistic routines - * + * * These will print statistics to the screen, the debug file (dfd), or * a buffer, depending on "type", so that the stats can be sent over * the link as well. @@ -86,9 +86,9 @@ ttystats(ttyp) { struct slirp_ifstats *is = &ttyp->ifstats; char buff[512]; - + lprint(" \r\n"); - + if (if_comp & IF_COMPRESS) strcpy(buff, "on"); else if (if_comp & IF_NOCOMPRESS) @@ -123,7 +123,7 @@ void allttystats() { struct ttys *ttyp; - + for (ttyp = ttys; ttyp; ttyp = ttyp->next) ttystats(ttyp); } @@ -132,7 +132,7 @@ allttystats() void ipstats() { - lprint(" \r\n"); + lprint(" \r\n"); lprint("IP stats:\r\n"); lprint(" %6d total packets received (%d were unaligned)\r\n", @@ -158,9 +158,9 @@ void vjstats() { lprint(" \r\n"); - + lprint("VJ compression stats:\r\n"); - + lprint(" %6d outbound packets (%d compressed)\r\n", comp_s.sls_packets, comp_s.sls_compressed); lprint(" %6d searches for connection stats (%d misses)\r\n", @@ -178,7 +178,7 @@ tcpstats() lprint(" \r\n"); lprint("TCP stats:\r\n"); - + lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal); lprint(" %6d data packets (%d bytes)\r\n", tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte); @@ -191,8 +191,8 @@ tcpstats() lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup); lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); - - lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); + + lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); lprint(" %6d acks (for %d bytes)\r\n", tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); @@ -201,7 +201,7 @@ tcpstats() tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte); lprint(" %6d completely duplicate packets (%d bytes)\r\n", tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte); - + lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n", tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte); lprint(" %6d out-of-order packets (%d bytes)\r\n", @@ -214,7 +214,7 @@ tcpstats() lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum); lprint(" %6d discarded for bad header offset fields\r\n", tcpstat.tcps_rcvbadoff); - + lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt); lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts); lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects); @@ -233,8 +233,8 @@ tcpstats() lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack); lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat); lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss); - - + + /* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */ /* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */ @@ -272,18 +272,18 @@ mbufstats() { struct mbuf *m; int i; - + lprint(" \r\n"); - + lprint("Mbuf stats:\r\n"); lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max); - + i = 0; for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next) i++; lprint(" %6d mbufs on free list\r\n", i); - + i = 0; for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) i++; @@ -299,12 +299,12 @@ sockstats() struct socket *so; lprint(" \r\n"); - + lprint( "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); - - for (so = tcb.so_next; so != &tcb; so = so->so_next) { + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); while (n < 17) buff[n++] = ' '; @@ -316,9 +316,9 @@ sockstats() inet_ntoa(so->so_faddr), ntohs(so->so_fport), so->so_rcv.sb_cc, so->so_snd.sb_cc); } - + for (so = udb.so_next; so != &udb; so = so->so_next) { - + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); while (n < 17) buff[n++] = ' '; @@ -338,7 +338,7 @@ slirp_exit(exit_status) int exit_status; { struct ttys *ttyp; - + DEBUG_CALL("slirp_exit"); DEBUG_ARG("exit_status = %d", exit_status); @@ -347,7 +347,7 @@ slirp_exit(exit_status) if (!dfd) debug_init("slirp_stats", 0xf); lprint_arg = (char **)&dfd; - + ipstats(); tcpstats(); udpstats(); @@ -357,17 +357,17 @@ slirp_exit(exit_status) allttystats(); vjstats(); } - + for (ttyp = ttys; ttyp; ttyp = ttyp->next) tty_detached(ttyp, 1); - + if (slirp_forked) { /* Menendez time */ if (kill(getppid(), SIGQUIT) < 0) lprint("Couldn't kill parent process %ld!\n", (long) getppid()); } - + /* Restore the terminal if we gotta */ if(slirp_tty_restore) tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */ diff --git a/slirp/debug.h b/slirp/debug.h index 6e8444dab..fa62cb9fe 100644 --- a/slirp/debug.h +++ b/slirp/debug.h @@ -1,7 +1,7 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ diff --git a/slirp/if.c b/slirp/if.c index 94132ca88..6834c3396 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -77,12 +77,12 @@ writen(fd, bptr, n) { int ret; int total; - + /* This should succeed most of the time */ ret = send(fd, bptr, n,0); if (ret == n || ret <= 0) return ret; - + /* Didn't write everything, go into the loop */ total = ret; while (n > total) { @@ -97,7 +97,7 @@ writen(fd, bptr, n) /* * if_input - read() the tty, do "top level" processing (ie: check for any escapes), * and pass onto (*ttyp->if_input) - * + * * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet. */ #define INBUFF_SIZE 2048 /* XXX */ @@ -107,14 +107,14 @@ if_input(ttyp) { u_char if_inbuff[INBUFF_SIZE]; int if_n; - + DEBUG_CALL("if_input"); DEBUG_ARG("ttyp = %lx", (long)ttyp); - + if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0); - + DEBUG_MISC((dfd, " read %d bytes\n", if_n)); - + if (if_n <= 0) { if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) { if (ttyp->up) @@ -138,19 +138,19 @@ if_input(ttyp) } } ttyp->ones = ttyp->zeros = 0; - + (*ttyp->if_input)(ttyp, if_inbuff, if_n); } -#endif - +#endif + /* * if_output: Queue packet into an output queue. - * There are 2 output queue's, if_fastq and if_batchq. + * There are 2 output queue's, if_fastq and if_batchq. * Each output queue is a doubly linked list of double linked lists * of mbufs, each list belonging to one "session" (socket). This * way, we can output packets fairly by sending one packet from each * session, instead of all the packets from one session, then all packets - * from the next session, etc. Packets on the if_fastq get absolute + * from the next session, etc. Packets on the if_fastq get absolute * priority, but if one session hogs the link, it gets "downgraded" * to the batchq until it runs out of packets, then it'll return * to the fastq (eg. if the user does an ls -alR in a telnet session, @@ -163,11 +163,11 @@ if_output(so, ifm) { struct mbuf *ifq; int on_fastq = 1; - + DEBUG_CALL("if_output"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("ifm = %lx", (long)ifm); - + /* * First remove the mbuf from m_usedlist, * since we're gonna use m_next and m_prev ourselves @@ -177,9 +177,9 @@ if_output(so, ifm) remque(ifm); ifm->m_flags &= ~M_USEDLIST; } - + /* - * See if there's already a batchq list for this session. + * See if there's already a batchq list for this session. * This can include an interactive session, which should go on fastq, * but gets too greedy... hence it'll be downgraded from fastq to batchq. * We mustn't put this packet back on the fastq (or we'll send it out of order) @@ -193,7 +193,7 @@ if_output(so, ifm) goto diddit; } } - + /* No match, check which queue to put it on */ if (so && (so->so_iptos & IPTOS_LOWDELAY)) { ifq = if_fastq.ifq_prev; @@ -209,15 +209,15 @@ if_output(so, ifm) } } else ifq = if_batchq.ifq_prev; - + /* Create a new doubly linked list for this session */ ifm->ifq_so = so; ifs_init(ifm); insque(ifm, ifq); - + diddit: ++if_queued; - + if (so) { /* Update *_queued */ so->so_queued++; @@ -229,12 +229,12 @@ diddit: * have been sent over the link * (XXX These are arbitrary numbers, probably not optimal..) */ - if (on_fastq && ((so->so_nqueued >= 6) && + if (on_fastq && ((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) { - + /* Remove from current queue... */ remque(ifm->ifs_next); - + /* ...And insert in the new. That'll teach ya! */ insque(ifm->ifs_next, &if_batchq); } @@ -267,12 +267,12 @@ void if_start(void) { struct mbuf *ifm, *ifqt; - + DEBUG_CALL("if_start"); - + if (if_queued == 0) return; /* Nothing to do */ - + again: /* check if we can really output */ if (!slirp_can_output()) @@ -290,7 +290,7 @@ if_start(void) ifm = next_m; else ifm = if_batchq.ifq_next; - + /* Set which packet to send on next iteration */ next_m = ifm->ifq_next; } @@ -298,20 +298,20 @@ if_start(void) ifqt = ifm->ifq_prev; remque(ifm); --if_queued; - + /* If there are more packets for this session, re-queue them */ if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { insque(ifm->ifs_next, ifqt); ifs_remque(ifm); } - + /* Update so_queued */ if (ifm->ifq_so) { if (--ifm->ifq_so->so_queued == 0) /* If there's no more queued, reset nqueued */ ifm->ifq_so->so_nqueued = 0; } - + /* Encapsulate the packet for sending */ if_encap(ifm->m_data, ifm->m_len); diff --git a/slirp/if.h b/slirp/if.h index 5d96a9034..bf24174a6 100644 --- a/slirp/if.h +++ b/slirp/if.h @@ -1,7 +1,7 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -39,11 +39,11 @@ struct slirp_ifstats { u_int in_bytes; /* Input bytes */ u_int in_errpkts; /* Input Error Packets */ u_int in_errbytes; /* Input Error Bytes */ - + u_int bytes_saved; /* Number of bytes that compression "saved" */ /* ie: number of bytes that didn't need to be sent over the link * because of compression */ - + u_int in_mbad; /* Bad incoming packets */ }; diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index b67a37359..b24eae9b7 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -63,7 +63,7 @@ static int icmp_flush[19] = { /* INFO (15) */ 0, /* INFO REPLY (16) */ 0, /* ADDR MASK (17) */ 0, -/* ADDR MASK REPLY (18) */ 0 +/* ADDR MASK REPLY (18) */ 0 }; /* @@ -78,13 +78,13 @@ icmp_input(m, hlen) register struct ip *ip=mtod(m, struct ip *); int icmplen=ip->ip_len; /* int code; */ - + DEBUG_CALL("icmp_input"); DEBUG_ARG("m = %lx", (long )m); DEBUG_ARG("m_len = %d", m->m_len); icmpstat.icps_received++; - + /* * Locate icmp structure in mbuf, and check * that its not corrupted and of at least minimum length. @@ -105,7 +105,7 @@ icmp_input(m, hlen) } m->m_len += hlen; m->m_data -= hlen; - + /* icmpstat.icps_inhist[icp->icmp_type]++; */ /* code = icp->icmp_code; */ @@ -121,7 +121,7 @@ icmp_input(m, hlen) struct sockaddr_in addr; if ((so = socreate()) == NULL) goto freeit; if(udp_attach(so) == -1) { - DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", + DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", errno,strerror(errno))); sofree(so); m_free(m); @@ -135,7 +135,7 @@ icmp_input(m, hlen) so->so_iptos = ip->ip_tos; so->so_type = IPPROTO_ICMP; so->so_state = SS_ISFCONNECTED; - + /* Send the packet */ addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { @@ -157,7 +157,7 @@ icmp_input(m, hlen) (struct sockaddr *)&addr, sizeof(addr)) == -1) { DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", errno,strerror(errno))); - icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); udp_detach(so); } } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ @@ -173,7 +173,7 @@ icmp_input(m, hlen) icmpstat.icps_notsupp++; m_freem(m); break; - + default: icmpstat.icps_badtype++; m_freem(m); @@ -199,7 +199,7 @@ end_error: * mbuf *msrc is used as a template, but is NOT m_free()'d. * It is reported as the bad ip packet. The header should * be fully correct and in host byte order. - * ICMP fragmentation is illegal. All machines must accept 576 bytes in one + * ICMP fragmentation is illegal. All machines must accept 576 bytes in one * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 */ @@ -226,7 +226,7 @@ icmp_error(msrc, type, code, minsize, message) /* check msrc */ if(!msrc) goto end_error; ip = mtod(msrc, struct ip *); -#if DEBUG +#if DEBUG { char bufa[20], bufb[20]; strcpy(bufa, inet_ntoa(ip->ip_src)); strcpy(bufb, inet_ntoa(ip->ip_dst)); @@ -258,9 +258,9 @@ icmp_error(msrc, type, code, minsize, message) /* make the header of the reply packet */ ip = mtod(m, struct ip *); hlen= sizeof(struct ip ); /* no options in reply */ - + /* fill in icmp */ - m->m_data += hlen; + m->m_data += hlen; m->m_len -= hlen; icp = mtod(m, struct icmp *); @@ -269,7 +269,7 @@ icmp_error(msrc, type, code, minsize, message) else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ s_ip_len=ICMP_MAXDATALEN; - m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ + m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ /* min. size = 8+sizeof(struct ip)+8 */ @@ -304,7 +304,7 @@ icmp_error(msrc, type, code, minsize, message) /* fill in ip */ ip->ip_hl = hlen >> 2; ip->ip_len = m->m_len; - + ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ ip->ip_ttl = MAXTTL; @@ -313,7 +313,7 @@ icmp_error(msrc, type, code, minsize, message) ip->ip_src = alias_addr; (void ) ip_output((struct socket *)NULL, m); - + icmpstat.icps_reflect++; end_error: diff --git a/slirp/ip_input.c b/slirp/ip_input.c index 4f5bfd9a5..a7d6e3181 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -37,7 +37,7 @@ /* * Changes and additions relating to SLiRP are * Copyright (c) 1995 Danny Gasparovski. - * + * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -73,20 +73,20 @@ ip_input(m) { register struct ip *ip; int hlen; - + DEBUG_CALL("ip_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m_len = %d", m->m_len); ipstat.ips_total++; - + if (m->m_len < sizeof (struct ip)) { ipstat.ips_toosmall++; return; } - + ip = mtod(m, struct ip *); - + if (ip->ip_v != IPVERSION) { ipstat.ips_badvers++; goto bad; @@ -99,8 +99,8 @@ ip_input(m) } /* keep ip header intact for ICMP reply - * ip->ip_sum = cksum(m, hlen); - * if (ip->ip_sum) { + * ip->ip_sum = cksum(m, hlen); + * if (ip->ip_sum) { */ if(cksum(m,hlen)) { ipstat.ips_badsum++; @@ -154,7 +154,7 @@ ip_input(m) * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) - * + * * XXX This should fail, don't fragment yet */ if (ip->ip_off &~ IP_DF) { @@ -181,7 +181,7 @@ ip_input(m) ip->ip_len -= hlen; if (ip->ip_off & IP_MF) ((struct ipasfrag *)ip)->ipf_mff |= 1; - else + else ((struct ipasfrag *)ip)->ipf_mff &= ~1; ip->ip_off <<= 3; @@ -244,7 +244,7 @@ ip_reass(ip, fp) register struct ipasfrag *q; int hlen = ip->ip_hl << 2; int i, next; - + DEBUG_CALL("ip_reass"); DEBUG_ARG("ip = %lx", (long)ip); DEBUG_ARG("fp = %lx", (long)fp); @@ -275,7 +275,7 @@ ip_reass(ip, fp) q = (struct ipasfrag *)fp; goto insert; } - + /* * Find a segment which begins after this one does. */ @@ -369,7 +369,7 @@ insert: ip = (struct ipasfrag *)(m->m_ext + delta); } - /* DEBUG_ARG("ip = %lx", (long)ip); + /* DEBUG_ARG("ip = %lx", (long)ip); * ip=(struct ipasfrag *)m->m_data; */ ip->ip_len = next; @@ -446,9 +446,9 @@ void ip_slowtimo() { register struct ipq *fp; - + DEBUG_CALL("ip_slowtimo"); - + fp = (struct ipq *) ipq.next; if (fp == 0) return; @@ -692,6 +692,6 @@ ip_stripoptions(m, mopt) i = m->m_len - (sizeof (struct ip) + olen); memcpy(opts, opts + olen, (unsigned)i); m->m_len -= olen; - + ip->ip_hl = sizeof(struct ip) >> 2; } diff --git a/slirp/ip_output.c b/slirp/ip_output.c index f3dc9b70e..b80b038cd 100644 --- a/slirp/ip_output.c +++ b/slirp/ip_output.c @@ -65,7 +65,7 @@ ip_output(so, m0) DEBUG_CALL("ip_output"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m0 = %lx", (long)m0); - + /* We do no options */ /* if (opt) { * m = ip_insertoptions(m, opt, &len); @@ -92,7 +92,7 @@ ip_output(so, m0) * goto bad; * } */ - + /* * If small enough for interface, can just send directly. */ @@ -115,7 +115,7 @@ ip_output(so, m0) ipstat.ips_cantfrag++; goto bad; } - + len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ if (len < 8) { error = -1; @@ -143,7 +143,7 @@ ip_output(so, m0) m->m_data += if_maxlinkhdr; mhip = mtod(m, struct ip *); *mhip = *ip; - + /* No options */ /* if (hlen > sizeof (struct ip)) { * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); @@ -156,15 +156,15 @@ ip_output(so, m0) mhip->ip_off |= IP_MF; if (off + len >= (u_int16_t)ip->ip_len) len = (u_int16_t)ip->ip_len - off; - else + else mhip->ip_off |= IP_MF; mhip->ip_len = htons((u_int16_t)(len + mhlen)); - + if (m_copy(m, m0, off, len) < 0) { error = -1; goto sendorfree; } - + mhip->ip_off = htons((u_int16_t)mhip->ip_off); mhip->ip_sum = 0; mhip->ip_sum = cksum(m, mhlen); diff --git a/slirp/libslirp.h b/slirp/libslirp.h index b46d1758e..639f5f222 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -7,7 +7,7 @@ extern "C" { void slirp_init(void); -void slirp_select_fill(int *pnfds, +void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); @@ -18,9 +18,9 @@ void slirp_input(const uint8_t *pkt, int pkt_len); int slirp_can_output(void); void slirp_output(const uint8_t *pkt, int pkt_len); -int slirp_redir(int is_udp, int host_port, +int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port); -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, +int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, int guest_port); extern const char *tftp_prefix; diff --git a/slirp/main.h b/slirp/main.h index 181b6ae88..9cd87584e 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -1,7 +1,7 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ diff --git a/slirp/mbuf.c b/slirp/mbuf.c index 3769bafd2..bcf71bc61 100644 --- a/slirp/mbuf.c +++ b/slirp/mbuf.c @@ -40,14 +40,14 @@ msize_init() * Find a nice value for msize * XXX if_maxlinkhdr already in mtu */ - msize = (if_mtu>if_mru?if_mtu:if_mru) + + msize = (if_mtu>if_mru?if_mtu:if_mru) + if_maxlinkhdr + sizeof(struct m_hdr ) + 6; } /* * Get an mbuf from the free list, if there are none * malloc one - * + * * Because fragmentation can occur if we alloc new mbufs and * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, * which tells m_free to actually free() it @@ -57,9 +57,9 @@ m_get() { register struct mbuf *m; int flags = 0; - + DEBUG_CALL("m_get"); - + if (m_freelist.m_next == &m_freelist) { m = (struct mbuf *)malloc(msize); if (m == NULL) goto end_error; @@ -72,11 +72,11 @@ m_get() m = m_freelist.m_next; remque(m); } - + /* Insert it in the used list */ insque(m,&m_usedlist); m->m_flags = (flags | M_USEDLIST); - + /* Initialise it */ m->m_size = msize - sizeof(struct m_hdr); m->m_data = m->m_dat; @@ -92,15 +92,15 @@ void m_free(m) struct mbuf *m; { - + DEBUG_CALL("m_free"); DEBUG_ARG("m = %lx", (long )m); - + if(m) { /* Remove from m_usedlist */ if (m->m_flags & M_USEDLIST) remque(m); - + /* If it's M_EXT, free() it */ if (m->m_flags & M_EXT) free(m->m_ext); @@ -132,7 +132,7 @@ m_cat(m, n) */ if (M_FREEROOM(m) < n->m_len) m_inc(m,m->m_size+MINCSIZE); - + memcpy(m->m_data+m->m_len, n->m_data, n->m_len); m->m_len += n->m_len; @@ -156,7 +156,7 @@ m_inc(m, size) m->m_ext = (char *)realloc(m->m_ext,size); /* if (m->m_ext == NULL) * return (struct mbuf *)NULL; - */ + */ m->m_data = m->m_ext + datasize; } else { char *dat; @@ -166,12 +166,12 @@ m_inc(m, size) * return (struct mbuf *)NULL; */ memcpy(dat, m->m_dat, m->m_size); - + m->m_ext = dat; m->m_data = m->m_ext + datasize; m->m_flags |= M_EXT; } - + m->m_size = size; } @@ -224,7 +224,7 @@ dtom(dat) void *dat; { struct mbuf *m; - + DEBUG_CALL("dtom"); DEBUG_ARG("dat = %lx", (long )dat); @@ -238,9 +238,9 @@ dtom(dat) return m; } } - + DEBUG_ERROR((dfd, "dtom failed")); - + return (struct mbuf *)0; } diff --git a/slirp/mbuf.h b/slirp/mbuf.h index 8cc292bbf..1e8f7a8e4 100644 --- a/slirp/mbuf.h +++ b/slirp/mbuf.h @@ -69,12 +69,12 @@ struct m_hdr { int mh_size; /* Size of data */ struct socket *mh_so; - + caddr_t mh_data; /* Location of data */ int mh_len; /* Amount of data in this mbuf */ }; -/* +/* * How much room is in the mbuf, from m_data to the end of the mbuf */ #define M_ROOM(m) ((m->m_flags & M_EXT)? \ @@ -126,7 +126,7 @@ struct mbuf { struct mbstat { int mbs_alloced; /* Number of mbufs allocated */ - + }; extern struct mbstat mbstat; diff --git a/slirp/misc.c b/slirp/misc.c index 2c42fd15b..db4444ef3 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * + * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -31,7 +31,7 @@ show_x(buff, inso) if (x_display) lprint("X Redir: Redirecting to display %d\r\n", x_display); } - + return CFG_OK; } @@ -47,7 +47,7 @@ redir_x(inaddr, start_port, display, screen) int screen; { int i; - + if (x_port >= 0) { lprint("X Redir: X already being redirected.\r\n"); show_x(0, 0); @@ -89,7 +89,7 @@ getouraddr() { char buff[256]; struct hostent *he = NULL; - + if (gethostname(buff,256) == 0) he = gethostbyname(buff); if (he) @@ -172,13 +172,13 @@ add_exec(ex_ptr, do_pty, exec, addr, port) int port; { struct ex_list *tmp_ptr; - + /* First, check if the port is "bound" */ for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr) return -1; } - + tmp_ptr = *ex_ptr; *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); (*ex_ptr)->ex_fport = port; @@ -233,7 +233,7 @@ slirp_openpty(amaster, aslave) #ifdef HAVE_GRANTPT char *ptr; - + if ((master = open("/dev/ptmx", O_RDWR)) < 0 || grantpt(master) < 0 || unlockpt(master) < 0 || @@ -241,7 +241,7 @@ slirp_openpty(amaster, aslave) close(master); return -1; } - + if ((slave = open(ptr, O_RDWR)) < 0 || ioctl(slave, I_PUSH, "ptem") < 0 || ioctl(slave, I_PUSH, "ldterm") < 0 || @@ -250,16 +250,16 @@ slirp_openpty(amaster, aslave) close(slave); return -1; } - + *amaster = master; *aslave = slave; return 0; - + #else - + static char line[] = "/dev/ptyXX"; register const char *cp1, *cp2; - + for (cp1 = "pqrsPQRS"; *cp1; cp1++) { line[8] = *cp1; for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { @@ -296,7 +296,7 @@ slirp_openpty(amaster, aslave) * process, which connects to this socket, after which we * exec the wanted program. If something (strange) happens, * the accept() call could block us forever. - * + * * do_pty = 0 Fork/exec inetd style * do_pty = 1 Fork/exec using slirp.telnetd * do_ptr = 2 Fork/exec using pty @@ -320,12 +320,12 @@ fork_exec(so, ex, do_pty) char *bptr; char *curarg; int c, i, ret; - + DEBUG_CALL("fork_exec"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("ex = %lx", (long)ex); DEBUG_ARG("do_pty = %lx", (long)do_pty); - + if (do_pty == 2) { if (slirp_openpty(&master, &s) == -1) { lprint("Error: openpty failed: %s\n", strerror(errno)); @@ -335,17 +335,17 @@ fork_exec(so, ex, do_pty) addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; - + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || listen(s, 1) < 0) { lprint("Error: inet socket: %s\n", strerror(errno)); closesocket(s); - + return 0; } } - + switch(fork()) { case -1: lprint("Error: fork failed: %s\n", strerror(errno)); @@ -353,7 +353,7 @@ fork_exec(so, ex, do_pty) if (do_pty == 2) close(master); return 0; - + case 0: /* Set the DISPLAY */ if (do_pty == 2) { @@ -375,7 +375,7 @@ fork_exec(so, ex, do_pty) ret = connect(s, (struct sockaddr *)&addr, addrlen); } while (ret < 0 && errno == EINTR); } - + #if 0 if (x_port >= 0) { #ifdef HAVE_SETENV @@ -386,13 +386,13 @@ fork_exec(so, ex, do_pty) putenv(buff); #endif } -#endif +#endif dup2(s, 0); dup2(s, 1); dup2(s, 2); for (s = 3; s <= 255; s++) close(s); - + i = 0; bptr = strdup(ex); /* No need to free() this */ if (do_pty == 1) { @@ -410,21 +410,21 @@ fork_exec(so, ex, do_pty) *bptr++ = (char)0; argv[i++] = strdup(curarg); } while (c); - + argv[i] = 0; execvp(argv[0], argv); - + /* Ooops, failed, let's tell the user why */ { char buff[256]; - - sprintf(buff, "Error: execvp of %s failed: %s\n", + + sprintf(buff, "Error: execvp of %s failed: %s\n", argv[0], strerror(errno)); write(2, buff, strlen(buff)+1); } close(0); close(1); close(2); /* XXX */ exit(1); - + default: if (do_pty == 2) { close(s); @@ -447,13 +447,13 @@ fork_exec(so, ex, do_pty) setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); } fd_nonblock(so->s); - + /* Append the telnet options now */ if (so->so_m != 0 && do_pty == 1) { sbappend(so, so->so_m); so->so_m = 0; } - + return 1; } } @@ -465,10 +465,10 @@ strdup(str) const char *str; { char *bptr; - + bptr = (char *)malloc(strlen(str)+1); strcpy(bptr, str); - + return bptr; } #endif @@ -484,7 +484,7 @@ snooze_hup(num) #endif struct sockaddr_in sock_in; char buff[256]; - + ret = -1; if (slirp_socket_passwd) { s = socket(AF_INET, SOCK_STREAM, 0); @@ -514,29 +514,29 @@ snooze_hup(num) #endif slirp_exit(0); } - - + + void snooze() { sigset_t s; int i; - + /* Don't need our data anymore */ /* XXX This makes SunOS barf */ /* brk(0); */ - + /* Close all fd's */ for (i = 255; i >= 0; i--) close(i); - + signal(SIGQUIT, slirp_exit); signal(SIGHUP, snooze_hup); sigemptyset(&s); - + /* Wait for any signal */ sigsuspend(&s); - + /* Just in case ... */ exit(255); } @@ -549,16 +549,16 @@ relay(s) int n; fd_set readfds; struct ttys *ttyp; - + /* Don't need our data anymore */ /* XXX This makes SunOS barf */ /* brk(0); */ - + signal(SIGQUIT, slirp_exit); signal(SIGHUP, slirp_exit); signal(SIGINT, slirp_exit); signal(SIGTERM, slirp_exit); - + /* Fudge to get term_raw and term_restore to work */ if (NULL == (ttyp = tty_attach (0, slirp_tty))) { lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); @@ -567,18 +567,18 @@ relay(s) ttyp->fd = 0; ttyp->flags |= TTY_CTTY; term_raw(ttyp); - + while (1) { FD_ZERO(&readfds); - + FD_SET(0, &readfds); FD_SET(s, &readfds); - + n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); - + if (n <= 0) slirp_exit(0); - + if (FD_ISSET(0, &readfds)) { n = read(0, buf, 8192); if (n <= 0) @@ -587,7 +587,7 @@ relay(s) if (n <= 0) slirp_exit(0); } - + if (FD_ISSET(s, &readfds)) { n = read(s, buf, 8192); if (n <= 0) @@ -597,7 +597,7 @@ relay(s) slirp_exit(0); } } - + /* Just in case.... */ exit(1); } @@ -614,7 +614,7 @@ lprint(va_alist) va_dcl #endif { va_list args; - + #ifdef __STDC__ va_start(args, format); #else @@ -631,33 +631,33 @@ lprint(va_alist) va_dcl int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; int deltap = lprint_ptr - lprint_sb->sb_data; - + lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, lprint_sb->sb_datalen + TCP_SNDSPACE); - + /* Adjust all values */ lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; lprint_ptr = lprint_sb->sb_data + deltap; - + lprint_sb->sb_datalen += TCP_SNDSPACE; } } -#endif +#endif if (lprint_print) lprint_ptr += (*lprint_print)(*lprint_arg, format, args); - + /* Check if they want output to be logged to file as well */ if (lfd) { - /* + /* * Remove \r's * otherwise you'll get ^M all over the file */ int len = strlen(format); char *bptr1, *bptr2; - + bptr1 = bptr2 = strdup(format); - + while (len--) { if (*bptr1 == '\r') memcpy(bptr1, bptr1+1, len+1); @@ -680,12 +680,12 @@ add_emu(buff) char *buff3 = buff4; struct emu_t *emup; struct socket *so; - + if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { lprint("Error: Bad arguments\r\n"); return; } - + if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { lport = 0; if (sscanf(buff1, "%d", &fport) != 1) { @@ -693,7 +693,7 @@ add_emu(buff) return; } } - + if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { buff3 = 0; if (sscanf(buff2, "%256s", buff1) != 1) { @@ -701,7 +701,7 @@ add_emu(buff) return; } } - + if (buff3) { if (strcmp(buff3, "lowdelay") == 0) tos = IPTOS_LOWDELAY; @@ -712,7 +712,7 @@ add_emu(buff) return; } } - + if (strcmp(buff1, "ftp") == 0) emu = EMU_FTP; else if (strcmp(buff1, "irc") == 0) @@ -723,7 +723,7 @@ add_emu(buff) lprint("Error: Unknown service\r\n"); return; } - + /* First, check that it isn't already emulated */ for (emup = tcpemu; emup; emup = emup->next) { if (emup->lport == lport && emup->fport == fport) { @@ -731,7 +731,7 @@ add_emu(buff) return; } } - + /* link it */ emup = (struct emu_t *)malloc(sizeof (struct emu_t)); emup->lport = (u_int16_t)lport; @@ -740,7 +740,7 @@ add_emu(buff) emup->emu = emu; emup->next = tcpemu; tcpemu = emup; - + /* And finally, mark all current sessions, if any, as being emulated */ for (so = tcb.so_next; so != &tcb; so = so->so_next) { if ((lport && lport == ntohs(so->so_lport)) || @@ -751,7 +751,7 @@ add_emu(buff) so->so_iptos = tos; } } - + lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); } @@ -803,12 +803,12 @@ u_sleep(usec) { struct timeval t; fd_set fdset; - + FD_ZERO(&fdset); - + t.tv_sec = 0; t.tv_usec = usec * 1000; - + select(0, &fdset, &fdset, &fdset, &t); } @@ -822,11 +822,11 @@ fd_nonblock(fd) { #ifdef FIONBIO int opt = 1; - + ioctlsocket(fd, FIONBIO, &opt); #else int opt; - + opt = fcntl(fd, F_GETFL, 0); opt |= O_NONBLOCK; fcntl(fd, F_SETFL, opt); @@ -839,11 +839,11 @@ fd_block(fd) { #ifdef FIONBIO int opt = 0; - + ioctlsocket(fd, FIONBIO, &opt); #else int opt; - + opt = fcntl(fd, F_GETFL, 0); opt &= ~O_NONBLOCK; fcntl(fd, F_SETFL, opt); @@ -867,10 +867,10 @@ rsh_exec(so,ns, user, host, args) int fd0[2]; int s; char buff[256]; - + DEBUG_CALL("rsh_exec"); DEBUG_ARG("so = %lx", (long)so); - + if (pipe(fd)<0) { lprint("Error: pipe failed: %s\n", strerror(errno)); return 0; @@ -891,7 +891,7 @@ rsh_exec(so,ns, user, host, args) return 0; } #endif - + switch(fork()) { case -1: lprint("Error: fork failed: %s\n", strerror(errno)); @@ -900,11 +900,11 @@ rsh_exec(so,ns, user, host, args) close(fd0[0]); close(fd0[1]); return 0; - + case 0: close(fd[0]); close(fd0[0]); - + /* Set the DISPLAY */ if (x_port >= 0) { #ifdef HAVE_SETENV @@ -915,29 +915,29 @@ rsh_exec(so,ns, user, host, args) putenv(buff); #endif } - + dup2(fd0[1], 0); dup2(fd0[1], 1); dup2(fd[1], 2); for (s = 3; s <= 255; s++) close(s); - + execlp("rsh","rsh","-l", user, host, args, NULL); - + /* Ooops, failed, let's tell the user why */ - - sprintf(buff, "Error: execlp of %s failed: %s\n", + + sprintf(buff, "Error: execlp of %s failed: %s\n", "rsh", strerror(errno)); write(2, buff, strlen(buff)+1); close(0); close(1); close(2); /* XXX */ exit(1); - + default: close(fd[1]); close(fd0[1]); ns->s=fd[0]; so->s=fd0[0]; - + return 1; } } diff --git a/slirp/misc.h b/slirp/misc.h index 8e6a606c9..6484a8126 100644 --- a/slirp/misc.h +++ b/slirp/misc.h @@ -1,7 +1,7 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ diff --git a/slirp/sbuf.c b/slirp/sbuf.c index d6726c94d..e6b5bb670 100644 --- a/slirp/sbuf.c +++ b/slirp/sbuf.c @@ -1,7 +1,7 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -9,7 +9,7 @@ /* Done as a macro in socket.h */ /* int - * sbspace(struct sockbuff *sb) + * sbspace(struct sockbuff *sb) * { * return SB_DATALEN - sb->sb_cc; * } @@ -25,11 +25,11 @@ sbfree(sb) void sbdrop(sb, num) struct sbuf *sb; - int num; + int num; { - /* + /* * We can only drop how much we have - * This should never succeed + * This should never succeed */ if(num > sb->sb_cc) num = sb->sb_cc; @@ -37,7 +37,7 @@ sbdrop(sb, num) sb->sb_rptr += num; if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) sb->sb_rptr -= sb->sb_datalen; - + } void @@ -77,18 +77,18 @@ sbappend(so, m) struct mbuf *m; { int ret = 0; - + DEBUG_CALL("sbappend"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m->m_len = %d", m->m_len); - + /* Shouldn't happen, but... e.g. foreign host closes connection */ if (m->m_len <= 0) { m_free(m); return; } - + /* * If there is urgent data, call sosendoob * if not all was sent, sowrite will take care of the rest @@ -100,16 +100,16 @@ sbappend(so, m) sosendoob(so); return; } - + /* * We only write if there's nothing in the buffer, * ottherwise it'll arrive out of order, and hence corrupt */ if (!so->so_rcv.sb_cc) ret = send(so->s, m->m_data, m->m_len, 0); - + if (ret <= 0) { - /* + /* * Nothing was written * It's possible that the socket has closed, but * we don't need to check because if it has closed, @@ -139,7 +139,7 @@ sbappendsb(sb, m) struct mbuf *m; { int len, n, nn; - + len = m->m_len; if (sb->sb_wptr < sb->sb_rptr) { @@ -180,7 +180,7 @@ sbcopy(sb, off, len, to) char *to; { char *from; - + from = sb->sb_rptr + off; if (from >= sb->sb_data + sb->sb_datalen) from -= sb->sb_datalen; @@ -198,4 +198,4 @@ sbcopy(sb, off, len, to) memcpy(to+off,sb->sb_data,len); } } - + diff --git a/slirp/sbuf.h b/slirp/sbuf.h index 161e0bb76..89c4eb2f1 100644 --- a/slirp/sbuf.h +++ b/slirp/sbuf.h @@ -1,7 +1,7 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ diff --git a/slirp/slirp.c b/slirp/slirp.c index 6ba753e73..12093bf50 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -12,7 +12,7 @@ struct in_addr special_addr; /* virtual address alias for host */ struct in_addr alias_addr; -const uint8_t special_ethaddr[6] = { +const uint8_t special_ethaddr[6] = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 }; @@ -38,10 +38,10 @@ static int get_dns_addr(struct in_addr *pdns_addr) DWORD ret; IP_ADDR_STRING *pIPAddr; struct in_addr tmp_addr; - + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); BufLen = sizeof(FIXED_INFO); - + if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { if (FixedInfo) { GlobalFree(FixedInfo); @@ -49,7 +49,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) } FixedInfo = GlobalAlloc(GPTR, BufLen); } - + if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); if (FixedInfo) { @@ -58,14 +58,14 @@ static int get_dns_addr(struct in_addr *pdns_addr) } return -1; } - + pIPAddr = &(FixedInfo->DnsServerList); inet_aton(pIPAddr->IpAddress.String, &tmp_addr); *pdns_addr = tmp_addr; #if 0 printf( "DNS Servers:\n" ); printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String ); - + pIPAddr = FixedInfo -> DnsServerList.Next; while ( pIPAddr ) { printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String ); @@ -88,7 +88,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) FILE *f; int found = 0; struct in_addr tmp_addr; - + f = fopen("/etc/resolv.conf", "r"); if (!f) return -1; @@ -130,7 +130,7 @@ void slirp_cleanup(void) void slirp_init(void) { // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); - + #ifdef _WIN32 { WSADATA Data; @@ -180,16 +180,16 @@ static void updtime(void) static void updtime(void) { gettimeofday(&tt, 0); - + curtime = (u_int)tt.tv_sec * (u_int)1000; curtime += (u_int)tt.tv_usec / (u_int)1000; - + if ((tt.tv_usec % 1000) >= 500) curtime++; } #endif -void slirp_select_fill(int *pnfds, +void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds) { struct socket *so, *so_next; @@ -201,36 +201,36 @@ void slirp_select_fill(int *pnfds, global_readfds = NULL; global_writefds = NULL; global_xfds = NULL; - + nfds = *pnfds; /* * First, TCP sockets */ do_slowtimo = 0; if (link_up) { - /* + /* * *_slowtimo needs calling if there are IP fragments * in the fragment queue, or there are TCP connections active */ do_slowtimo = ((tcb.so_next != &tcb) || ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); - + for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; - + /* * See if we need a tcp_fasttimo */ if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) time_fasttimo = curtime; /* Flag when we want a fasttimo */ - + /* * NOFDREF can include still connecting to local-host, * newly socreated() sockets etc. Don't want to select these. */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; - + /* * Set for reading sockets which are accepting */ @@ -239,7 +239,7 @@ void slirp_select_fill(int *pnfds, UPD_NFDS(so->s); continue; } - + /* * Set for writing sockets which are connecting */ @@ -248,7 +248,7 @@ void slirp_select_fill(int *pnfds, UPD_NFDS(so->s); continue; } - + /* * Set for writing if we are connected, can send more, and * we have something to send @@ -257,7 +257,7 @@ void slirp_select_fill(int *pnfds, FD_SET(so->s, writefds); UPD_NFDS(so->s); } - + /* * Set for reading (and urgent data) if we are connected, can * receive more, and we have room for it XXX /2 ? @@ -268,13 +268,13 @@ void slirp_select_fill(int *pnfds, UPD_NFDS(so->s); } } - + /* * UDP sockets */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; - + /* * See if it's timed out */ @@ -285,7 +285,7 @@ void slirp_select_fill(int *pnfds, } else do_slowtimo = 1; /* Let socket expire */ } - + /* * When UDP packets are received from over the * link, they're sendto()'d straight away, so @@ -302,12 +302,12 @@ void slirp_select_fill(int *pnfds, } } } - + /* * Setup timeout to use minimum CPU usage, especially when idle */ - - /* + + /* * First, see the timeout needed by *timo */ timeout.tv_sec = 0; @@ -324,20 +324,20 @@ void slirp_select_fill(int *pnfds, timeout.tv_usec = 0; else if (timeout.tv_usec > 510000) timeout.tv_usec = 510000; - + /* Can only fasttimo if we also slowtimo */ if (time_fasttimo) { tmp_time = (200 - (curtime - time_fasttimo)) * 1000; if (tmp_time < 0) tmp_time = 0; - + /* Choose the smallest of the 2 */ if (tmp_time < timeout.tv_usec) timeout.tv_usec = (u_int)tmp_time; } } *pnfds = nfds; -} +} void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) { @@ -350,9 +350,9 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) /* Update time */ updtime(); - + /* - * See if anything has timed out + * See if anything has timed out */ if (link_up) { if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) { @@ -365,7 +365,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) last_slowtimo = curtime; } } - + /* * Check sockets */ @@ -375,14 +375,14 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) */ for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; - + /* * FD_ISSET is meaningless on these sockets * (and they can crash the program) */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; - + /* * Check for URG data * This will soread as well, so no need to @@ -402,12 +402,12 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) continue; } /* else */ ret = soread(so); - + /* Output it if we read something */ if (ret > 0) tcp_output(sototcpcb(so)); } - + /* * Check sockets for writing */ @@ -418,19 +418,19 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) if (so->so_state & SS_ISFCONNECTING) { /* Connected */ so->so_state &= ~SS_ISFCONNECTING; - + ret = send(so->s, &ret, 0, 0); if (ret < 0) { /* XXXXX Must fix, zero bytes is a NOP */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; - + /* else failed */ so->so_state = SS_NOFDREF; } /* else so->so_state &= ~SS_ISFCONNECTING; */ - + /* * Continue tcp_input */ @@ -439,13 +439,13 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) } else ret = sowrite(so); /* - * XXXXX If we wrote something (a lot), there + * XXXXX If we wrote something (a lot), there * could be a need for a window update. * In the worst case, the remote will send * a window probe to get things going again */ } - + /* * Probe a still-connecting, non-blocking socket * to check if it's still alive @@ -453,16 +453,16 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) #ifdef PROBE_CONN if (so->so_state & SS_ISFCONNECTING) { ret = recv(so->s, (char *)&ret, 0,0); - + if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* Still connecting, continue */ - + /* else failed */ so->so_state = SS_NOFDREF; - + /* tcp_input will take care of it */ } else { ret = send(so->s, &ret, 0,0); @@ -475,13 +475,13 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) so->so_state = SS_NOFDREF; } else so->so_state &= ~SS_ISFCONNECTING; - + } tcp_input((struct mbuf *)NULL, sizeof(struct ip),so); } /* SS_ISFCONNECTING */ #endif } - + /* * Now UDP sockets. * Incoming packets are sent straight away, they're not buffered. @@ -489,13 +489,13 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; - + if (so->s != -1 && FD_ISSET(so->s, readfds)) { sorecvfrom(so); } } } - + /* * See if we can start outputting */ @@ -521,7 +521,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) #define ARPOP_REQUEST 1 /* ARP request */ #define ARPOP_REPLY 2 /* ARP reply */ -struct ethhdr +struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ @@ -559,7 +559,7 @@ void arp_input(const uint8_t *pkt, int pkt_len) switch(ar_op) { case ARPOP_REQUEST: if (!memcmp(ah->ar_tip, &special_addr, 3)) { - if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) + if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) goto arp_ok; for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_addr == ah->ar_tip[3]) @@ -600,7 +600,7 @@ void slirp_input(const uint8_t *pkt, int pkt_len) if (pkt_len < ETH_HLEN) return; - + proto = ntohs(*(uint16_t *)(pkt + 12)); switch(proto) { case ETH_P_ARP: @@ -642,24 +642,24 @@ void if_encap(const uint8_t *ip_data, int ip_data_len) slirp_output(buf, ip_data_len + ETH_HLEN); } -int slirp_redir(int is_udp, int host_port, +int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port) { if (is_udp) { - if (!udp_listen(htons(host_port), guest_addr.s_addr, + if (!udp_listen(htons(host_port), guest_addr.s_addr, htons(guest_port), 0)) return -1; } else { - if (!solisten(htons(host_port), guest_addr.s_addr, + if (!solisten(htons(host_port), guest_addr.s_addr, htons(guest_port), 0)) return -1; } return 0; } -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, +int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, int guest_port) { - return add_exec(&exec_list, do_pty, (char *)args, + return add_exec(&exec_list, do_pty, (char *)args, addr_low_byte, htons(guest_port)); } diff --git a/slirp/socket.c b/slirp/socket.c index 0ae1f8701..141bcb262 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -1,7 +1,7 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -29,19 +29,19 @@ solookup(head, laddr, lport, faddr, fport) u_int fport; { struct socket *so; - + for (so = head->so_next; so != head; so = so->so_next) { - if (so->so_lport == lport && + if (so->so_lport == lport && so->so_laddr.s_addr == laddr.s_addr && so->so_faddr.s_addr == faddr.s_addr && so->so_fport == fport) break; } - + if (so == head) return (struct socket *)NULL; return so; - + } /* @@ -53,7 +53,7 @@ struct socket * socreate() { struct socket *so; - + so = (struct socket *)malloc(sizeof(struct socket)); if(so) { memset(so, 0, sizeof(struct socket)); @@ -78,10 +78,10 @@ sofree(so) tcp_last_so = &tcb; else if (so == udp_last_so) udp_last_so = &udb; - + m_free(so->so_m); - - if(so->so_next && so->so_prev) + + if(so->so_next && so->so_prev) remque(so); /* crashes if so is not in a queue */ free(so); @@ -101,17 +101,17 @@ soread(so) int len = sb->sb_datalen - sb->sb_cc; struct iovec iov[2]; int mss = so->so_tcpcb->t_maxseg; - + DEBUG_CALL("soread"); DEBUG_ARG("so = %lx", (long )so); - - /* + + /* * No need to check if there's enough room to read. * soread wouldn't have been called if there weren't */ - + len = sb->sb_datalen - sb->sb_cc; - + iov[0].iov_base = sb->sb_wptr; if (sb->sb_wptr < sb->sb_rptr) { iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; @@ -150,13 +150,13 @@ soread(so) n = 1; } } - + #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #else nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); -#endif +#endif if (nn <= 0) { if (nn < 0 && (errno == EINTR || errno == EAGAIN)) return 0; @@ -167,7 +167,7 @@ soread(so) return -1; } } - + #ifndef HAVE_READV /* * If there was no error, try and read the second time round @@ -184,10 +184,10 @@ soread(so) if (ret > 0) nn += ret; } - + DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #endif - + /* Update fields */ sb->sb_cc += nn; sb->sb_wptr += nn; @@ -195,10 +195,10 @@ soread(so) sb->sb_wptr -= sb->sb_datalen; return nn; } - + /* * Get urgent data - * + * * When the socket is created, we set it SO_OOBINLINE, * so when OOB data arrives, we soread() it and everything * in the send buffer is sent as urgent data @@ -211,13 +211,13 @@ sorecvoob(so) DEBUG_CALL("sorecvoob"); DEBUG_ARG("so = %lx", (long)so); - + /* * We take a guess at how much urgent data has arrived. * In most situations, when urgent data arrives, the next * read() should get all the urgent data. This guess will * be wrong however if more data arrives just after the - * urgent data, or the read() doesn't return all the + * urgent data, or the read() doesn't return all the * urgent data. */ soread(so); @@ -237,24 +237,24 @@ sosendoob(so) { struct sbuf *sb = &so->so_rcv; char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ - + int n, len; - + DEBUG_CALL("sosendoob"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); - + if (so->so_urgc > 2048) so->so_urgc = 2048; /* XXXX */ - + if (sb->sb_rptr < sb->sb_wptr) { /* We can send it directly */ n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ so->so_urgc -= n; - + DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); } else { - /* + /* * Since there's no sendv or sendtov like writev, * we must copy all data to a linear buffer then * send it all @@ -274,20 +274,20 @@ sosendoob(so) #ifdef DEBUG if (n != len) DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); -#endif +#endif DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); } - + sb->sb_cc -= n; sb->sb_rptr += n; if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_rptr -= sb->sb_datalen; - + return n; } /* - * Write data from so_rcv to so's socket, + * Write data from so_rcv to so's socket, * updating all sbuf field as necessary */ int @@ -298,10 +298,10 @@ sowrite(so) struct sbuf *sb = &so->so_rcv; int len = sb->sb_cc; struct iovec iov[2]; - + DEBUG_CALL("sowrite"); DEBUG_ARG("so = %lx", (long)so); - + if (so->so_urgc) { sosendoob(so); if (sb->sb_cc == 0) @@ -312,9 +312,9 @@ sowrite(so) * No need to check if there's something to write, * sowrite wouldn't have been called otherwise */ - + len = sb->sb_cc; - + iov[0].iov_base = sb->sb_rptr; if (sb->sb_rptr < sb->sb_wptr) { iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; @@ -337,7 +337,7 @@ sowrite(so) #ifdef HAVE_READV nn = writev(so->s, (const struct iovec *)iov, n); - + DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #else nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); @@ -345,7 +345,7 @@ sowrite(so) /* This should never happen, but people tell me it does *shrug* */ if (nn < 0 && (errno == EAGAIN || errno == EINTR)) return 0; - + if (nn <= 0) { DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n", so->so_state, errno)); @@ -353,7 +353,7 @@ sowrite(so) tcp_sockclosed(sototcpcb(so)); return -1; } - + #ifndef HAVE_READV if (n == 2 && nn == iov[0].iov_len) { int ret; @@ -363,20 +363,20 @@ sowrite(so) } DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #endif - + /* Update sbuf */ sb->sb_cc -= nn; sb->sb_rptr += nn; if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_rptr -= sb->sb_datalen; - + /* * If in DRAIN mode, and there's no more data, set * it CANTSENDMORE */ if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) sofcantsendmore(so); - + return nn; } @@ -389,24 +389,24 @@ sorecvfrom(so) { struct sockaddr_in addr; int addrlen = sizeof(struct sockaddr_in); - + DEBUG_CALL("sorecvfrom"); DEBUG_ARG("so = %lx", (long)so); - + if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ char buff[256]; int len; - - len = recvfrom(so->s, buff, 256, 0, + + len = recvfrom(so->s, buff, 256, 0, (struct sockaddr *)&addr, &addrlen); /* XXX Check if reply is "correct"? */ - + if(len == -1 || len == 0) { u_char code=ICMP_UNREACH_PORT; if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; - + DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", errno,strerror(errno))); icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); @@ -422,32 +422,32 @@ sorecvfrom(so) if (!(m = m_get())) return; m->m_data += if_maxlinkhdr; - - /* + + /* * XXX Shouldn't FIONREAD packets destined for port 53, * but I don't know the max packet size for DNS lookups */ len = M_FREEROOM(m); /* if (so->so_fport != htons(53)) { */ ioctlsocket(so->s, FIONREAD, &n); - + if (n > len) { n = (m->m_data - m->m_dat) + m->m_len + n + 1; m_inc(m, n); len = M_FREEROOM(m); } /* } */ - + m->m_len = recvfrom(so->s, m->m_data, len, 0, (struct sockaddr *)&addr, &addrlen); - DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", + DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", m->m_len, errno,strerror(errno))); if(m->m_len<0) { u_char code=ICMP_UNREACH_PORT; if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; - + DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); m_free(m); @@ -470,8 +470,8 @@ sorecvfrom(so) * m->m_len = 0; * } */ - - /* + + /* * If this packet was destined for CTL_ADDR, * make it look like that's where it came from, done by udp_output */ @@ -494,7 +494,7 @@ sosendto(so, m) DEBUG_CALL("sosendto"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); - + addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ @@ -512,13 +512,13 @@ sosendto(so, m) addr.sin_port = so->so_fport; DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); - + /* Don't care what port we get */ ret = sendto(so->s, m->m_data, m->m_len, 0, (struct sockaddr *)&addr, sizeof (struct sockaddr)); if (ret < 0) return -1; - + /* * Kill the socket if there's no reply in 4 minutes, * but only if it's an expirable socket @@ -548,39 +548,39 @@ solisten(port, laddr, lport, flags) DEBUG_ARG("laddr = %x", laddr); DEBUG_ARG("lport = %d", lport); DEBUG_ARG("flags = %x", flags); - + if ((so = socreate()) == NULL) { /* free(so); Not sofree() ??? free(NULL) == NOP */ return NULL; } - + /* Don't tcp_attach... we don't need so_snd nor so_rcv */ if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { free(so); return NULL; } insque(so,&tcb); - - /* + + /* * SS_FACCEPTONCE sockets must time out. */ if (flags & SS_FACCEPTONCE) so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; - + so->so_state = (SS_FACCEPTCONN|flags); so->so_lport = lport; /* Kept in network format */ so->so_laddr.s_addr = laddr; /* Ditto */ - + addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = port; - + if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (listen(s,1) < 0)) { int tmperrno = errno; /* Don't clobber the real reason we failed */ - + close(s); sofree(so); /* Restore the real errno */ @@ -592,7 +592,7 @@ solisten(port, laddr, lport, flags) return NULL; } setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); - + getsockname(s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) @@ -604,7 +604,7 @@ solisten(port, laddr, lport, flags) return so; } -/* +/* * Data is available in so_rcv * Just write() the data to the socket * XXX not yet... @@ -616,7 +616,7 @@ sorwakeup(so) /* sowrite(so); */ /* FD_CLR(so->s,&writefds); */ } - + /* * Data has been freed in so_snd * We have room for a read() if we want to diff --git a/slirp/socket.h b/slirp/socket.h index d05354c8c..901e8423e 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -1,7 +1,7 @@ /* * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -33,21 +33,21 @@ struct socket { struct in_addr so_laddr; /* local host table entry */ u_int16_t so_fport; /* foreign port */ u_int16_t so_lport; /* local port */ - + u_int8_t so_iptos; /* Type of service */ u_int8_t so_emu; /* Is the socket emulated? */ - + u_char so_type; /* Type of socket, UDP or TCP */ int so_state; /* internal state flags SS_*, below */ - + struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ u_int so_expire; /* When the socket will expire */ - + int so_queued; /* Number of packets queued from this socket */ int so_nqueued; /* Number of packets queued in a row * Used to determine when to "downgrade" a session * from fastq to batchq */ - + struct sbuf so_rcv; /* Receive buffer */ struct sbuf so_snd; /* Send buffer */ void * extra; /* Extra pointer */ diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index c01516101..da35c4398 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -37,8 +37,8 @@ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -122,7 +122,7 @@ tcp_reass(tp, ti, m) register struct tcpiphdr *q; struct socket *so = tp->t_socket; int flags; - + /* * Call with ti==0 after become established to * force pre-ESTABLISHED data up to user socket. @@ -254,15 +254,15 @@ tcp_input(m, iphlen, inso) /* int ts_present = 0; */ DEBUG_CALL("tcp_input"); - DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", + DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", (long )m, iphlen, (long )inso )); - + /* * If called with m == 0, then we're continuing the connect */ if (m == NULL) { so = inso; - + /* Re-set a few variables */ tp = sototcpcb(so); m = so->so_m; @@ -270,11 +270,11 @@ tcp_input(m, iphlen, inso) ti = so->so_ti; tiwin = ti->ti_win; tiflags = ti->ti_flags; - + goto cont_conn; } - - + + tcpstat.tcps_rcvtotal++; /* * Get IP and TCP header together in first mbuf. @@ -286,14 +286,14 @@ tcp_input(m, iphlen, inso) iphlen=sizeof(struct ip ); } /* XXX Check if too short */ - + /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ ip=mtod(m, struct ip *); - save_ip = *ip; + save_ip = *ip; save_ip.ip_len+= iphlen; /* @@ -305,7 +305,7 @@ tcp_input(m, iphlen, inso) ti->ti_len = htons((u_int16_t)tlen); len = sizeof(struct ip ) + tlen; /* keep checksum for ICMP reply - * ti->ti_sum = cksum(m, len); + * ti->ti_sum = cksum(m, len); * if (ti->ti_sum) { */ if(cksum(m, len)) { tcpstat.tcps_rcvbadsum++; @@ -327,7 +327,7 @@ tcp_input(m, iphlen, inso) optlen = off - sizeof (struct tcphdr); optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr); - /* + /* * Do quick retrieval of timestamp options ("options * prediction?"). If timestamp is the only option and it's * formatted as recommended in RFC 1323 appendix A, we @@ -347,7 +347,7 @@ tcp_input(m, iphlen, inso) */ } tiflags = ti->ti_flags; - + /* * Convert TCP protocol specific fields to host format. */ @@ -361,7 +361,7 @@ tcp_input(m, iphlen, inso) */ m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); - + /* * Locate pcb for segment. */ @@ -385,8 +385,8 @@ findso: * but should either do a listen or a connect soon. * * state == CLOSED means we've done socreate() but haven't - * attached it to a protocol yet... - * + * attached it to a protocol yet... + * * XXX If a TCB does not exist, and the TH_SYN flag is * the only flag set, then create a session, mark it * as if it was LISTENING, and continue... @@ -394,32 +394,32 @@ findso: if (so == 0) { if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN) goto dropwithreset; - + if ((so = socreate()) == NULL) goto dropwithreset; if (tcp_attach(so) < 0) { free(so); /* Not sofree (if it failed, it's not insqued) */ goto dropwithreset; } - + sbreserve(&so->so_snd, tcp_sndspace); sbreserve(&so->so_rcv, tcp_rcvspace); - + /* tcp_last_so = so; */ /* XXX ? */ /* tp = sototcpcb(so); */ - + so->so_laddr = ti->ti_src; so->so_lport = ti->ti_sport; so->so_faddr = ti->ti_dst; so->so_fport = ti->ti_dport; - + if ((so->so_iptos = tcp_tos(so)) == 0) so->so_iptos = ((struct ip *)ti)->ip_tos; - + tp = sototcpcb(so); tp->t_state = TCPS_LISTEN; } - + /* * If this is a still-connecting socket, this probably * a retransmit of the SYN. Whether it's a retransmit SYN @@ -429,13 +429,13 @@ findso: goto drop; tp = sototcpcb(so); - + /* XXX Should never fail */ if (tp == 0) goto dropwithreset; if (tp->t_state == TCPS_CLOSED) goto drop; - + /* Unscale the window into a 32-bit value. */ /* if ((tiflags & TH_SYN) == 0) * tiwin = ti->ti_win << tp->snd_scale; @@ -458,11 +458,11 @@ findso: * else do it below (after getting remote address). */ if (optp && tp->t_state != TCPS_LISTEN) - tcp_dooptions(tp, (u_char *)optp, optlen, ti); + tcp_dooptions(tp, (u_char *)optp, optlen, ti); /* , */ /* &ts_present, &ts_val, &ts_ecr); */ - /* + /* * Header prediction: check for the two common cases * of a uni-directional data xfer. If the packet has * no control flags, is in-sequence, the window didn't @@ -486,7 +486,7 @@ findso: ti->ti_seq == tp->rcv_nxt && tiwin && tiwin == tp->snd_wnd && tp->snd_nxt == tp->snd_max) { - /* + /* * If last ACK falls within this segment's sequence numbers, * record the timestamp. */ @@ -506,7 +506,7 @@ findso: ++tcpstat.tcps_predack; /* if (ts_present) * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); - * else + * else */ if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp, tp->t_rtt); @@ -531,14 +531,14 @@ findso: else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - /* + /* * There's room in so_snd, sowwakup will read() * from the socket if we can */ /* if (so->so_snd.sb_flags & SB_NOTIFY) * sowwakeup(so); */ - /* + /* * This is called because sowwakeup might have * put data into so_snd. Since we don't so sowwakeup, * we don't need this.. XXX??? @@ -567,22 +567,22 @@ findso: if (tcp_emu(so,m)) sbappend(so, m); } else sbappend(so, m); - - /* + + /* * XXX This is called when data arrives. Later, check * if we can actually write() to the socket * XXX Need to check? It's be NON_BLOCKING */ /* sorwakeup(so); */ - + /* * If this is a short packet, then ACK now - with Nagel * congestion avoidance sender won't send more until * he gets an ACK. - * + * * It is better to not delay acks at all to maximize * TCP throughput. See RFC 2581. - */ + */ tp->t_flags |= TF_ACKNOW; tcp_output(tp); return; @@ -624,12 +624,12 @@ findso: goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; - + /* * This has way too many gotos... * But a bit of spaghetti code never hurt anybody :) */ - + /* * If this is destined for the control address, then flag to * tcp_ctl once connected, otherwise connect @@ -641,13 +641,13 @@ findso: if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) { /* Command or exec adress */ so->so_state |= SS_CTL; - } else + } else #endif { /* May be an add exec */ struct ex_list *ex_ptr; for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { - if(ex_ptr->ex_fport == so->so_fport && + if(ex_ptr->ex_fport == so->so_fport && lastbyte == ex_ptr->ex_addr) { so->so_state |= SS_CTL; break; @@ -658,12 +658,12 @@ findso: } /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ } - + if (so->so_emu & EMU_NOCONNECT) { so->so_emu &= ~EMU_NOCONNECT; goto cont_input; } - + if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { u_char code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", @@ -671,7 +671,7 @@ findso: if(errno == ECONNREFUSED) { /* ACK the SYN, send RST to refuse the connection */ tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0, - TH_RST|TH_ACK); + TH_RST|TH_ACK); } else { if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; HTONL(ti->ti_seq); /* restore tcp header */ @@ -699,25 +699,25 @@ findso: } return; - cont_conn: - /* m==NULL + cont_conn: + /* m==NULL * Check if the connect succeeded */ if (so->so_state & SS_NOFDREF) { tp = tcp_close(tp); goto dropwithreset; } - cont_input: + cont_input: tcp_template(tp); - + if (optp) tcp_dooptions(tp, (u_char *)optp, optlen, ti); /* , */ /* &ts_present, &ts_val, &ts_ecr); */ - + if (iss) tp->iss = iss; - else + else tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tp->irs = ti->ti_seq; @@ -729,7 +729,7 @@ findso: tcpstat.tcps_accepts++; goto trimthenstep6; } /* case TCPS_LISTEN */ - + /* * If the state is SYN_SENT: * if seg contains an ACK, but not for our SYN, drop the input. @@ -770,7 +770,7 @@ findso: tcpstat.tcps_connects++; soisfconnected(so); tp->t_state = TCPS_ESTABLISHED; - + /* Do window scaling on this connection? */ /* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == * (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -811,10 +811,10 @@ trimthenstep6: /* * States other than LISTEN or SYN_SENT. * First check timestamp, if present. - * Then check that at least some bytes of segment are within + * Then check that at least some bytes of segment are within * receive window. If segment begins before rcv_nxt, * drop leading data (and SYN); if nothing left, just ack. - * + * * RFC 1323 PAWS: If we have a timestamp reply on this segment * and it's less than ts_recent, drop it. */ @@ -849,7 +849,7 @@ trimthenstep6: if (tiflags & TH_SYN) { tiflags &= ~TH_SYN; ti->ti_seq++; - if (ti->ti_urp > 1) + if (ti->ti_urp > 1) ti->ti_urp--; else tiflags &= ~TH_URG; @@ -866,7 +866,7 @@ trimthenstep6: * of sequence; drop it. */ tiflags &= ~TH_FIN; - + /* * Send an ACK to resynchronize and drop any data. * But keep on processing for RST or ACK. @@ -1017,12 +1017,12 @@ trimthenstep6: goto dropwithreset; tcpstat.tcps_connects++; tp->t_state = TCPS_ESTABLISHED; - /* - * The sent SYN is ack'ed with our sequence number +1 - * The first data byte already in the buffer will get + /* + * The sent SYN is ack'ed with our sequence number +1 + * The first data byte already in the buffer will get * lost if no correction is made. This is only needed for * SS_CTL since the buffer is empty otherwise. - * tp->snd_una++; or: + * tp->snd_una++; or: */ tp->snd_una=ti->ti_ack; if (so->so_state & SS_CTL) { @@ -1040,7 +1040,7 @@ trimthenstep6: } else { soisfconnected(so); } - + /* Do window scaling? */ /* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == * (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1094,7 +1094,7 @@ trimthenstep6: * the new ssthresh). * * Dup acks mean that packets have left the - * network (they're now cached at the receiver) + * network (they're now cached at the receiver) * so bump cwnd by the amount in the receiver * to keep a constant cwnd packets in the * network. @@ -1159,7 +1159,7 @@ trimthenstep6: /* if (ts_present) * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); * else - */ + */ if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp,tp->t_rtt); @@ -1200,7 +1200,7 @@ trimthenstep6: } /* * XXX sowwakup is called when data is acked and there's room for - * for more data... it should read() the socket + * for more data... it should read() the socket */ /* if (so->so_snd.sb_flags & SB_NOTIFY) * sowwakeup(so); @@ -1278,7 +1278,7 @@ step6: * Don't look at window if no ACK: TAC's send garbage on first SYN. */ if ((tiflags & TH_ACK) && - (SEQ_LT(tp->snd_wl1, ti->ti_seq) || + (SEQ_LT(tp->snd_wl1, ti->ti_seq) || (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { /* keep track of pure window updates */ @@ -1313,14 +1313,14 @@ step6: * If this segment advances the known urgent pointer, * then mark the data stream. This should not happen * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since - * a FIN has been received from the remote side. + * a FIN has been received from the remote side. * In these states we ignore the URG. * * According to RFC961 (Assigned Protocols), * the urgent pointer points to the last octet * of urgent data. We continue, however, * to consider it to indicate the first octet - * of data past the urgent section as the original + * of data past the urgent section as the original * spec states (in one of two places). */ if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { @@ -1328,7 +1328,7 @@ step6: so->so_urgc = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt); /* -1; */ tp->rcv_up = ti->ti_seq + ti->ti_urp; - + } } else /* @@ -1379,7 +1379,7 @@ dodata: */ /* sofcantrcvmore(so); */ sofwdrain(so); - + tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; } @@ -1393,7 +1393,7 @@ dodata: case TCPS_ESTABLISHED: if(so->so_emu == EMU_CTL) /* no shutdown on socket */ tp->t_state = TCPS_LAST_ACK; - else + else tp->t_state = TCPS_CLOSE_WAIT; break; @@ -1407,7 +1407,7 @@ dodata: /* * In FIN_WAIT_2 state enter the TIME_WAIT state, - * starting the time-wait timer, turning off the other + * starting the time-wait timer, turning off the other * standard timers. */ case TCPS_FIN_WAIT_2: @@ -1430,7 +1430,7 @@ dodata: * If this is a small packet, then ACK now - with Nagel * congestion avoidance sender won't send more until * he gets an ACK. - * + * * See above. */ /* if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) { @@ -1547,7 +1547,7 @@ tcp_dooptions(tp, cp, cnt, ti) * memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr)); * NTOHL(*ts_ecr); * - */ /* + */ /* * * A timestamp received in a SYN makes * * it ok to send timestamp requests and replies. * */ @@ -1578,7 +1578,7 @@ tcp_pulloutofband(so, ti, m) register struct mbuf *m; { int cnt = ti->ti_urp - 1; - + while (cnt >= 0) { if (m->m_len > cnt) { char *cp = mtod(m, caddr_t) + cnt; @@ -1615,7 +1615,7 @@ tcp_xmit_timer(tp, rtt) DEBUG_CALL("tcp_xmit_timer"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("rtt = %d", rtt); - + tcpstat.tcps_rttupdated++; if (tp->t_srtt != 0) { /* @@ -1644,7 +1644,7 @@ tcp_xmit_timer(tp, rtt) if ((tp->t_rttvar += delta) <= 0) tp->t_rttvar = 1; } else { - /* + /* * No rtt measurement yet - use the unsmoothed rtt. * Set the variance to half the rtt (so our first * retransmit happens at 3*rtt). @@ -1668,7 +1668,7 @@ tcp_xmit_timer(tp, rtt) */ TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ - + /* * We received an ack for a packet that wasn't retransmitted; * it is probably safe to discard any error indications we've @@ -1702,24 +1702,24 @@ tcp_mss(tp, offer) { struct socket *so = tp->t_socket; int mss; - + DEBUG_CALL("tcp_mss"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("offer = %d", offer); - + mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr); if (offer) mss = min(mss, offer); mss = max(mss, 32); if (mss < tp->t_maxseg || offer != 0) tp->t_maxseg = mss; - + tp->snd_cwnd = mss; - + sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0)); sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0)); - + DEBUG_MISC((dfd, " returning mss = %d\n", mss)); - + return mss; } diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c index b79bcf127..b4be123dc 100644 --- a/slirp/tcp_output.c +++ b/slirp/tcp_output.c @@ -37,8 +37,8 @@ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -57,7 +57,7 @@ char *tcpstates[] = { u_char tcp_outflags[TCP_NSTATES] = { TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, - TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, + TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK, }; @@ -79,10 +79,10 @@ tcp_output(tp) u_char opt[MAX_TCPOPTLEN]; unsigned optlen, hdrlen; int idle, sendalot; - + DEBUG_CALL("tcp_output"); DEBUG_ARG("tp = %lx", (long )tp); - + /* * Determine length of data that should be transmitted, * and flags that will be used. @@ -103,9 +103,9 @@ again: win = min(tp->snd_wnd, tp->snd_cwnd); flags = tcp_outflags[tp->t_state]; - + DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags)); - + /* * If in persist timeout with window of 0, send 1 byte. * Otherwise, if window is small but nonzero @@ -158,7 +158,7 @@ again: tp->snd_nxt = tp->snd_una; } } - + if (len > tp->t_maxseg) { len = tp->t_maxseg; sendalot = 1; @@ -200,7 +200,7 @@ again: * window, then want to send a window update to peer. */ if (win > 0) { - /* + /* * "adv" is the amount we can increase the window, * taking into account that we are limited by * TCP_MAXWIN << tp->rcv_scale. @@ -264,7 +264,7 @@ again: * No reason to send a segment, just return. */ tcpstat.tcps_didnuttin++; - + return (0); send: @@ -302,9 +302,9 @@ send: */ } } - + /* - * Send a timestamp and echo-reply if this is a SYN and our side + * Send a timestamp and echo-reply if this is a SYN and our side * wants to use timestamps (TF_REQ_TSTMP is set) or both our side * and our peer have sent timestamps in our SYN's. */ @@ -322,7 +322,7 @@ send: * } */ hdrlen += optlen; - + /* * Adjust data length if insertion of options will * bump the packet length beyond the t_maxseg length. @@ -356,8 +356,8 @@ send: } m->m_data += if_maxlinkhdr; m->m_len = hdrlen; - - /* + + /* * This will always succeed, since we make sure our mbufs * are big enough to hold one MSS packet + header + ... etc. */ @@ -401,7 +401,7 @@ send: } ti = mtod(m, struct tcpiphdr *); - + memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); /* @@ -409,7 +409,7 @@ send: * window for use in delaying messages about window sizes. * If resending a FIN, be sure not to use a new sequence number. */ - if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && + if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && tp->snd_nxt == tp->snd_max) tp->snd_nxt--; /* @@ -446,10 +446,10 @@ send: if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) win = (long)(tp->rcv_adv - tp->rcv_nxt); ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); - + if (SEQ_GT(tp->snd_up, tp->snd_una)) { ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); -#ifdef notdef +#ifdef notdef if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); #endif @@ -531,14 +531,14 @@ send: * the template, but need a way to checksum without them. */ m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ - + { - + ((struct ip *)ti)->ip_len = m->m_len; ((struct ip *)ti)->ip_ttl = ip_defttl; ((struct ip *)ti)->ip_tos = so->so_iptos; - + /* #if BSD >= 43 */ /* Don't do IP options... */ /* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, @@ -547,7 +547,7 @@ send: error = ip_output(so, m); /* #else - * error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, + * error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, * so->so_options & SO_DONTROUTE); * #endif */ diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 2526bffc6..547a7f679 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -37,8 +37,8 @@ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -60,11 +60,11 @@ tcp_init() { tcp_iss = 1; /* wrong */ tcb.so_next = tcb.so_prev = &tcb; - + /* tcp_rcvspace = our Window we advertise to the remote */ tcp_rcvspace = TCP_RCVSPACE; tcp_sndspace = TCP_SNDSPACE; - + /* Make sure tcp_sndspace is at least 2*MSS */ if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); @@ -92,7 +92,7 @@ tcp_template(tp) n->ti_dst = so->so_laddr; n->ti_sport = so->so_fport; n->ti_dport = so->so_lport; - + n->ti_seq = 0; n->ti_ack = 0; n->ti_x2 = 0; @@ -134,7 +134,7 @@ tcp_respond(tp, ti, m, ack, seq, flags) DEBUG_ARG("ack = %u", ack); DEBUG_ARG("seq = %u", seq); DEBUG_ARG("flags = %x", flags); - + if (tp) win = sbspace(&tp->t_socket->so_rcv); if (m == 0) { @@ -150,12 +150,12 @@ tcp_respond(tp, ti, m, ack, seq, flags) ti = mtod(m, struct tcpiphdr *); flags = TH_ACK; } else { - /* + /* * ti points into m so the next line is just making * the mbuf point to ti */ m->m_data = (caddr_t)ti; - + m->m_len = sizeof (struct tcpiphdr); tlen = 0; #define xchg(a,b,type) { type t; t=a; a=b; b=t; } @@ -183,11 +183,11 @@ tcp_respond(tp, ti, m, ack, seq, flags) ti->ti_sum = cksum(m, tlen); ((struct ip *)ti)->ip_len = tlen; - if(flags & TH_RST) + if(flags & TH_RST) ((struct ip *)ti)->ip_ttl = MAXTTL; - else + else ((struct ip *)ti)->ip_ttl = ip_defttl; - + (void) ip_output((struct socket *)0, m); } @@ -201,18 +201,18 @@ tcp_newtcpcb(so) struct socket *so; { register struct tcpcb *tp; - + tp = (struct tcpcb *)malloc(sizeof(*tp)); if (tp == NULL) return ((struct tcpcb *)0); - + memset((char *) tp, 0, sizeof(struct tcpcb)); tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; tp->t_maxseg = tcp_mssdflt; - + tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; tp->t_socket = so; - + /* * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives @@ -222,14 +222,14 @@ tcp_newtcpcb(so) tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; tp->t_rttmin = TCPTV_MIN; - TCPT_RANGESET(tp->t_rxtcur, + TCPT_RANGESET(tp->t_rxtcur, ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, TCPTV_MIN, TCPTV_REXMTMAX); tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->t_state = TCPS_CLOSED; - + so->so_tcpcb = tp; return (tp); @@ -240,7 +240,7 @@ tcp_newtcpcb(so) * the specified error. If connection is synchronized, * then send a RST to peer. */ -struct tcpcb *tcp_drop(struct tcpcb *tp, int err) +struct tcpcb *tcp_drop(struct tcpcb *tp, int err) { /* tcp_drop(tp, errno) register struct tcpcb *tp; @@ -251,7 +251,7 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err) DEBUG_CALL("tcp_drop"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("errno = %d", errno); - + if (TCPS_HAVERCVDSYN(tp->t_state)) { tp->t_state = TCPS_CLOSED; (void) tcp_output(tp); @@ -281,7 +281,7 @@ tcp_close(tp) DEBUG_CALL("tcp_close"); DEBUG_ARG("tp = %lx", (long )tp); - + /* free the reassembly queue, if any */ t = (struct tcpiphdr *) tp->seg_next; while (t != (struct tcpiphdr *)tp) { @@ -356,7 +356,7 @@ tcp_sockclosed(tp) DEBUG_CALL("tcp_sockclosed"); DEBUG_ARG("tp = %lx", (long)tp); - + switch (tp->t_state) { case TCPS_CLOSED: @@ -382,21 +382,21 @@ tcp_sockclosed(tp) tcp_output(tp); } -/* +/* * Connect to a host on the Internet * Called by tcp_input * Only do a connect, the tcp fields will be set in tcp_input * return 0 if there's a result of the connect, * else return -1 means we're still connecting * The return value is almost always -1 since the socket is - * nonblocking. Connect returns after the SYN is sent, and does + * nonblocking. Connect returns after the SYN is sent, and does * not wait for ACK+SYN. */ int tcp_fconnect(so) struct socket *so; { int ret=0; - + DEBUG_CALL("tcp_fconnect"); DEBUG_ARG("so = %lx", (long )so); @@ -409,7 +409,7 @@ int tcp_fconnect(so) setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); opt = 1; setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); - + addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ @@ -425,13 +425,13 @@ int tcp_fconnect(so) } else addr.sin_addr = so->so_faddr; addr.sin_port = so->so_fport; - + DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " - "addr.sin_addr.s_addr=%.16s\n", + "addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); /* We don't care what port we get */ ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); - + /* * If it's not in progress, it failed, so we just return 0, * without clearing SS_NOFDREF @@ -444,16 +444,16 @@ int tcp_fconnect(so) /* * Accept the socket and connect to the local-host - * + * * We have a problem. The correct thing to do would be * to first connect to the local-host, and only if the * connection is accepted, then do an accept() here. - * But, a) we need to know who's trying to connect + * But, a) we need to know who's trying to connect * to the socket to be able to SYN the local-host, and * b) we are already connected to the foreign host by * the time it gets to accept(), so... We simply accept * here and SYN the local-host. - */ + */ void tcp_connect(inso) struct socket *inso; @@ -466,7 +466,7 @@ tcp_connect(inso) DEBUG_CALL("tcp_connect"); DEBUG_ARG("inso = %lx", (long)inso); - + /* * If it's an SS_ACCEPTONCE socket, no need to socreate() * another socket, just use the accept() socket. @@ -487,7 +487,7 @@ tcp_connect(inso) so->so_laddr = inso->so_laddr; so->so_lport = inso->so_lport; } - + (void) tcp_mss(sototcpcb(so), 0); if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { @@ -501,13 +501,13 @@ tcp_connect(inso) setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); opt = 1; setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int)); - + so->so_fport = addr.sin_port; so->so_faddr = addr.sin_addr; /* Translate connections from localhost to the real hostname */ if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) so->so_faddr = alias_addr; - + /* Close the accept() socket, set right state */ if (inso->so_state & SS_FACCEPTONCE) { closesocket(so->s); /* If we only accept once, close the accept() socket */ @@ -515,12 +515,12 @@ tcp_connect(inso) /* if it's not FACCEPTONCE, it's already NOFDREF */ } so->s = s; - + so->so_iptos = tcp_tos(so); tp = sototcpcb(so); tcp_template(tp); - + /* Compute window scaling to request. */ /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) @@ -529,10 +529,10 @@ tcp_connect(inso) /* soisconnecting(so); */ /* NOFDREF used instead */ tcpstat.tcps_connattempt++; - + tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tp->iss = tcp_iss; + tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tcp_sendseqinit(tp); tcp_output(tp); @@ -547,7 +547,7 @@ tcp_attach(so) { if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) return -1; - + insque(so, &tcb); return 0; @@ -573,7 +573,7 @@ struct tos_t tcptos[] = { }; struct emu_t *tcpemu = 0; - + /* * Return TOS according to the above table */ @@ -583,7 +583,7 @@ tcp_tos(so) { int i = 0; struct emu_t *emup; - + while(tcptos[i].tos) { if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { @@ -592,7 +592,7 @@ tcp_tos(so) } i++; } - + /* Nope, lets see if there's a user-added one */ for (emup = tcpemu; emup; emup = emup->next) { if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || @@ -601,7 +601,7 @@ tcp_tos(so) return emup->tos; } } - + return 0; } @@ -612,23 +612,23 @@ int do_echo = -1; * This includes ftp (the data connection is * initiated by the server) and IRC (DCC CHAT and * DCC SEND) for now - * + * * NOTE: It's possible to crash SLiRP by sending it * unstandard strings to emulate... if this is a problem, * more checks are needed here * * XXX Assumes the whole command came in one packet - * + * * XXX Some ftp clients will have their TOS set to * LOWDELAY and so Nagel will kick in. Because of this, * we'll get the first letter, followed by the rest, so * we simply scan for ORT instead of PORT... * DCC doesn't have this problem because there's other stuff * in the packet before the DCC command. - * - * Return 1 if the mbuf m is still valid and should be + * + * Return 1 if the mbuf m is still valid and should be * sbappend()ed - * + * * NOTE: if you return 0 you MUST m_free() the mbuf! */ int @@ -641,25 +641,25 @@ tcp_emu(so, m) u_int32_t laddr; u_int lport; char *bptr; - + DEBUG_CALL("tcp_emu"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); - + switch(so->so_emu) { int x, i; - + case EMU_IDENT: /* * Identification protocol as per rfc-1413 */ - + { struct socket *tmpso; struct sockaddr_in addr; int addrlen = sizeof(struct sockaddr_in); struct sbuf *so_rcv = &so->so_rcv; - + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; @@ -688,7 +688,7 @@ tcp_emu(so, m) m_free(m); return 0; } - + #if 0 case EMU_RLOGIN: /* @@ -703,7 +703,7 @@ tcp_emu(so, m) char term[100]; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; - + /* First check if they have a priveladged port, or too much data has arrived */ if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { @@ -714,13 +714,13 @@ tcp_emu(so, m) m_free(m); return 0; } - + /* Append the current data */ memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m_free(m); - + /* * Check if we have all the initial options, * and build argument list to rlogin while we're here @@ -752,10 +752,10 @@ tcp_emu(so, m) } } } - + if (n != 4) return 0; - + /* We have it, set our term variable and fork_exec() */ #ifdef HAVE_SETENV setenv("TERM", term, 1); @@ -765,15 +765,15 @@ tcp_emu(so, m) fork_exec(so, args, 2); term[0] = 0; so->so_emu = 0; - + /* And finally, send the client a 0 character */ so_snd->sb_wptr[0] = 0; so_snd->sb_wptr++; so_snd->sb_cc++; - + return 0; } - + case EMU_RSH: /* * rsh emulation @@ -787,7 +787,7 @@ tcp_emu(so, m) char *args; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; - + /* First check if they have a priveladged port, or too much data has arrived */ if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { @@ -798,13 +798,13 @@ tcp_emu(so, m) m_free(m); return 0; } - + /* Append the current data */ memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m_free(m); - + /* * Check if we have all the initial options, * and build argument list to rlogin while we're here @@ -840,15 +840,15 @@ tcp_emu(so, m) ns->so_faddr=so->so_faddr; ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */ - if (ns->so_faddr.s_addr == 0 || + if (ns->so_faddr.s_addr == 0 || ns->so_faddr.s_addr == loopback_addr.s_addr) ns->so_faddr = alias_addr; ns->so_iptos = tcp_tos(ns); tp = sototcpcb(ns); - + tcp_template(tp); - + /* Compute window scaling to request. */ /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) @@ -858,10 +858,10 @@ tcp_emu(so, m) /*soisfconnecting(ns);*/ tcpstat.tcps_connattempt++; - + tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tp->iss = tcp_iss; + tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tcp_sendseqinit(tp); tcp_output(tp); @@ -877,19 +877,19 @@ tcp_emu(so, m) } } } - + if (n != 4) return 0; - + rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); so->so_emu = 0; so->extra=NULL; - + /* And finally, send the client a 0 character */ so_snd->sb_wptr[0] = 0; so_snd->sb_wptr++; so_snd->sb_cc++; - + return 0; } @@ -898,7 +898,7 @@ tcp_emu(so, m) int num; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; - + /* * If there is binary data here, we save it in so->so_m */ @@ -913,16 +913,16 @@ tcp_emu(so, m) } } } /* if(so->so_m==NULL) */ - + /* * Append the line */ sbappendsb(so_rcv, m); - + /* To avoid going over the edge of the buffer, we reset it */ if (so_snd->sb_cc == 0) so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; - + /* * A bit of a hack: * If the first packet we get here is 1 byte long, then it @@ -941,13 +941,13 @@ tcp_emu(so, m) tcp_output(sototcpcb(so)); /* XXX */ } else m_free(m); - + num = 0; while (num < so->so_rcv.sb_cc) { if (*(so->so_rcv.sb_rptr + num) == '\n' || *(so->so_rcv.sb_rptr + num) == '\r') { int n; - + *(so_rcv->sb_rptr + num) = 0; if (ctl_password && !ctl_password_ok) { /* Need a password */ @@ -984,38 +984,38 @@ do_prompt: } return 0; } -#endif +#endif case EMU_FTP: /* ftp */ *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { /* * Need to emulate the PORT command - */ - x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", + */ + x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; - + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); lport = htons((n5 << 8) | (n6)); - + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) return 1; - + n6 = ntohs(so->so_fport); - + n5 = (n6 >> 8) & 0xff; n6 &= 0xff; - + laddr = ntohl(so->so_faddr.s_addr); - + n1 = ((laddr >> 24) & 0xff); n2 = ((laddr >> 16) & 0xff); n3 = ((laddr >> 8) & 0xff); n4 = (laddr & 0xff); - + m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", + m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); return 1; } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { @@ -1026,34 +1026,34 @@ do_prompt: &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; - + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); lport = htons((n5 << 8) | (n6)); - + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) return 1; - + n6 = ntohs(so->so_fport); - + n5 = (n6 >> 8) & 0xff; n6 &= 0xff; - + laddr = ntohl(so->so_faddr.s_addr); - + n1 = ((laddr >> 24) & 0xff); n2 = ((laddr >> 16) & 0xff); n3 = ((laddr >> 8) & 0xff); n4 = (laddr & 0xff); - + m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); - + return 1; } - + return 1; - + case EMU_KSH: /* * The kshell (Kerberos rsh) and shell services both pass @@ -1072,7 +1072,7 @@ do_prompt: (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; return 1; - + case EMU_IRC: /* * Need to emulate DCC CHAT, DCC SEND and DCC MOVE @@ -1080,12 +1080,12 @@ do_prompt: *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) return 1; - + /* The %256s is for the broken mIRC */ if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; - + m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", (unsigned long)ntohl(so->so_faddr.s_addr), @@ -1093,15 +1093,15 @@ do_prompt: } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; - + m->m_len = bptr - m->m_data; /* Adjust length */ - m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", + m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), n1, 1); } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; - + m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), @@ -1110,7 +1110,7 @@ do_prompt: return 1; case EMU_REALAUDIO: - /* + /* * RealAudio emulation - JP. We must try to parse the incoming * data and try to find the two characters that contain the * port number. Then we redirect an udp port and replace the @@ -1118,45 +1118,45 @@ do_prompt: * * The 1.0 beta versions of the player are not supported * any more. - * + * * A typical packet for player version 1.0 (release version): - * - * 0000:50 4E 41 00 05 + * + * 0000:50 4E 41 00 05 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .......glc..P * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB - * + * * Now the port number 0x1BD7 is found at offset 0x04 of the * Now the port number 0x1BD7 is found at offset 0x04 of the * second packet. This time we received five bytes first and * then the rest. You never know how many bytes you get. * * A typical packet for player version 2.0 (beta): - * + * * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA............ * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxc..Win2.0.0 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B - * + * * Port number 0x1BC1 is found at offset 0x0d. - * + * * This is just a horrible switch statement. Variable ra tells * us where we're going. */ - + bptr = m->m_data; while (bptr < m->m_data + m->m_len) { u_short p; static int ra = 0; - char ra_tbl[4]; - + char ra_tbl[4]; + ra_tbl[0] = 0x50; ra_tbl[1] = 0x4e; ra_tbl[2] = 0x41; ra_tbl[3] = 0; - + switch (ra) { case 0: case 2: @@ -1166,7 +1166,7 @@ do_prompt: continue; } break; - + case 1: /* * We may get 0x50 several times, ignore them @@ -1180,15 +1180,15 @@ do_prompt: continue; } break; - - case 4: - /* + + case 4: + /* * skip version number */ bptr++; break; - - case 5: + + case 5: /* * The difference between versions 1.0 and * 2.0 is here. For future versions of @@ -1198,19 +1198,19 @@ do_prompt: bptr += 8; else bptr += 4; - break; - + break; + case 6: /* This is the field containing the port * number that RA-player is listening to. */ - lport = (((u_char*)bptr)[0] << 8) + lport = (((u_char*)bptr)[0] << 8) + ((u_char *)bptr)[1]; - if (lport < 6970) + if (lport < 6970) lport += 256; /* don't know why */ if (lport < 6970 || lport > 7170) return 1; /* failed */ - + /* try to get udp port between 6970 - 7170 */ for (p = 6970; p < 7071; p++) { if (udp_listen( htons(p), @@ -1224,17 +1224,17 @@ do_prompt: p = 0; *(u_char *)bptr++ = (p >> 8) & 0xff; *(u_char *)bptr++ = p & 0xff; - ra = 0; + ra = 0; return 1; /* port redirected, we're done */ - break; - + break; + default: - ra = 0; + ra = 0; } ra++; } - return 1; - + return 1; + default: /* Ooops, not emulated, won't call tcp_emu again */ so->so_emu = 0; @@ -1256,10 +1256,10 @@ tcp_ctl(so) struct ex_list *ex_ptr; int do_pty; // struct socket *tmpso; - + DEBUG_CALL("tcp_ctl"); DEBUG_ARG("so = %lx", (long )so); - + #if 0 /* * Check if they're authorised @@ -1269,12 +1269,12 @@ tcp_ctl(so) sb->sb_wptr += sb->sb_cc; return 0; } -#endif +#endif command = (ntohl(so->so_faddr.s_addr) & 0xff); - + switch(command) { default: /* Check for exec's */ - + /* * Check if it's pty_exec */ @@ -1285,12 +1285,12 @@ tcp_ctl(so) goto do_exec; } } - + /* * Nothing bound.. */ /* tcp_fconnect(so); */ - + /* FALLTHROUGH */ case CTL_ALIAS: sb->sb_cc = sprintf(sb->sb_wptr, @@ -1301,12 +1301,12 @@ tcp_ctl(so) do_exec: DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); return(fork_exec(so, ex_ptr->ex_exec, do_pty)); - + #if 0 case CTL_CMD: for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { - if (tmpso->so_emu == EMU_CTL && - !(tmpso->so_tcpcb? + if (tmpso->so_emu == EMU_CTL && + !(tmpso->so_tcpcb? (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK)) :0)) { /* Ooops, control connection already active */ diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c index d3146db58..044c2b8f7 100644 --- a/slirp/tcp_timer.c +++ b/slirp/tcp_timer.c @@ -54,7 +54,7 @@ tcp_fasttimo() register struct tcpcb *tp; DEBUG_CALL("tcp_fasttimo"); - + so = tcb.so_next; if (so) for (; so != &tcb; so = so->so_next) @@ -80,7 +80,7 @@ tcp_slowtimo() register int i; DEBUG_CALL("tcp_slowtimo"); - + tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; /* * Search through tcb's and update active timers. @@ -139,9 +139,9 @@ tcp_timers(tp, timer) int timer; { register int rexmt; - + DEBUG_CALL("tcp_timers"); - + switch (timer) { /* @@ -164,12 +164,12 @@ tcp_timers(tp, timer) * to a longer retransmit interval and retransmit one segment. */ case TCPT_REXMT: - + /* * XXXXX If a packet has timed out, then remove all the queued * packets for that session. */ - + if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { /* * This is a hack to suit our terminal server here at the uni of canberra @@ -178,14 +178,14 @@ tcp_timers(tp, timer) * keep retransmitting it, it'll keep eating the zeroes, so we keep * retransmitting, and eventually the connection dies... * (this only happens on incoming data) - * + * * So, if we were gonna drop the connection from too many retransmits, * don't... instead halve the t_maxseg, which might break up the NULLs and * let them through - * + * * *sigh* */ - + tp->t_maxseg >>= 1; if (tp->t_maxseg < 32) { /* @@ -197,7 +197,7 @@ tcp_timers(tp, timer) /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ return (tp); /* XXX */ } - + /* * Set rxtshift to 6, which is still at the maximum * backoff time @@ -240,7 +240,7 @@ tcp_timers(tp, timer) * size increase exponentially with time. If the * window is larger than the path can handle, this * exponential growth results in dropped packet(s) - * almost immediately. To get more time between + * almost immediately. To get more time between * drops but still "push" the network to take advantage * of improving conditions, we switch from exponential * to linear window opening at some threshold size. diff --git a/slirp/tftp.c b/slirp/tftp.c index 96d00e62c..f16530db6 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -1,8 +1,8 @@ /* * tftp.c - a simple, read-only tftp server for qemu - * + * * Copyright (c) 2004 Magnus Damm - * + * * 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 @@ -27,10 +27,10 @@ struct tftp_session { int in_use; unsigned char filename[TFTP_FILENAME_MAX]; - + struct in_addr client_ip; u_int16_t client_port; - + int timestamp; }; @@ -127,7 +127,7 @@ static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, return bytes_read; } -static int tftp_send_oack(struct tftp_session *spt, +static int tftp_send_oack(struct tftp_session *spt, const char *key, uint32_t value, struct tftp_t *recv_tp) { @@ -146,18 +146,18 @@ static int tftp_send_oack(struct tftp_session *spt, m->m_data += if_maxlinkhdr; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); - + tp->tp_op = htons(TFTP_OACK); n += sprintf(tp->x.tp_buf + n, "%s", key) + 1; n += sprintf(tp->x.tp_buf + n, "%u", value) + 1; saddr.sin_addr = recv_tp->ip.ip_dst; saddr.sin_port = recv_tp->udp.uh_dport; - + daddr.sin_addr = spt->client_ip; daddr.sin_port = spt->client_port; - m->m_len = sizeof(struct tftp_t) - 514 + n - + m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); @@ -166,7 +166,7 @@ static int tftp_send_oack(struct tftp_session *spt, -static int tftp_send_error(struct tftp_session *spt, +static int tftp_send_error(struct tftp_session *spt, u_int16_t errorcode, const char *msg, struct tftp_t *recv_tp) { @@ -186,7 +186,7 @@ static int tftp_send_error(struct tftp_session *spt, m->m_data += if_maxlinkhdr; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); - + tp->tp_op = htons(TFTP_ERROR); tp->x.tp_error.tp_error_code = htons(errorcode); strcpy(tp->x.tp_error.tp_msg, msg); @@ -199,7 +199,7 @@ static int tftp_send_error(struct tftp_session *spt, nobytes = 2; - m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - + m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); @@ -209,7 +209,7 @@ static int tftp_send_error(struct tftp_session *spt, return 0; } -static int tftp_send_data(struct tftp_session *spt, +static int tftp_send_data(struct tftp_session *spt, u_int16_t block_nr, struct tftp_t *recv_tp) { @@ -233,7 +233,7 @@ static int tftp_send_data(struct tftp_session *spt, m->m_data += if_maxlinkhdr; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); - + tp->tp_op = htons(TFTP_DATA); tp->x.tp_data.tp_block_nr = htons(block_nr); @@ -255,7 +255,7 @@ static int tftp_send_data(struct tftp_session *spt, return -1; } - m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - + m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); @@ -297,23 +297,23 @@ static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) else { return; } - + if (src[k] == '\0') { break; } } - + if (k >= n) { return; } - + k++; - + /* check mode */ if ((n - k) < 6) { return; } - + if (memcmp(&src[k], "octet\0", 6) != 0) { tftp_send_error(spt, 4, "Unsupported transfer mode", tp); return; @@ -338,7 +338,7 @@ static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) } /* check if the file exists */ - + if (tftp_read_data(spt, 0, spt->filename, 0) < 0) { tftp_send_error(spt, 1, "File not found", tp); return; @@ -399,8 +399,8 @@ static void tftp_handle_ack(struct tftp_t *tp, int pktlen) return; } - if (tftp_send_data(&tftp_sessions[s], - ntohs(tp->x.tp_data.tp_block_nr) + 1, + if (tftp_send_data(&tftp_sessions[s], + ntohs(tp->x.tp_data.tp_block_nr) + 1, tp) < 0) { return; } diff --git a/slirp/tftp.h b/slirp/tftp.h index 603f22bfd..8f2675e07 100644 --- a/slirp/tftp.h +++ b/slirp/tftp.h @@ -18,11 +18,11 @@ struct tftp_t { struct udphdr udp; u_int16_t tp_op; union { - struct { + struct { u_int16_t tp_block_nr; u_int8_t tp_buf[512]; } tp_data; - struct { + struct { u_int16_t tp_error_code; u_int8_t tp_msg[512]; } tp_error; diff --git a/slirp/udp.c b/slirp/udp.c index 8cf4cbd31..2504d119a 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -37,8 +37,8 @@ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. - * - * Please read the file COPYRIGHT for the + * + * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ @@ -66,8 +66,8 @@ udp_init() { udb.so_next = udb.so_prev = &udb; } -/* m->m_data points at ip packet header - * m->m_len length ip packet +/* m->m_data points at ip packet header + * m->m_len length ip packet * ip->ip_len length data (IPDU) */ void @@ -79,13 +79,13 @@ udp_input(m, iphlen) register struct udphdr *uh; /* struct mbuf *opts = 0;*/ int len; - struct ip save_ip; + struct ip save_ip; struct socket *so; - + DEBUG_CALL("udp_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("iphlen = %d", iphlen); - + udpstat.udps_ipackets++; /* @@ -119,12 +119,12 @@ udp_input(m, iphlen) m_adj(m, len - ip->ip_len); ip->ip_len = len; } - + /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ - save_ip = *ip; + save_ip = *ip; save_ip.ip_len+= iphlen; /* tcp_input subtracts this */ /* @@ -136,8 +136,8 @@ udp_input(m, iphlen) ((struct ipovly *)ip)->ih_x1 = 0; ((struct ipovly *)ip)->ih_len = uh->uh_ulen; /* keep uh_sum for ICMP reply - * uh->uh_sum = cksum(m, len + sizeof (struct ip)); - * if (uh->uh_sum) { + * uh->uh_sum = cksum(m, len + sizeof (struct ip)); + * if (uh->uh_sum) { */ if(cksum(m, len + sizeof(struct ip))) { udpstat.udps_badsum++; @@ -168,7 +168,7 @@ udp_input(m, iphlen) if (so->so_lport != uh->uh_sport || so->so_laddr.s_addr != ip->ip_src.s_addr) { struct socket *tmp; - + for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { if (tmp->so_lport == uh->uh_sport && tmp->so_laddr.s_addr == ip->ip_src.s_addr) { @@ -185,7 +185,7 @@ udp_input(m, iphlen) udp_last_so = so; } } - + if (so == NULL) { /* * If there's no socket for this packet, @@ -193,22 +193,22 @@ udp_input(m, iphlen) */ if ((so = socreate()) == NULL) goto bad; if(udp_attach(so) == -1) { - DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", + DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", errno,strerror(errno))); sofree(so); goto bad; } - + /* * Setup fields */ /* udp_last_so = so; */ so->so_laddr = ip->ip_src; so->so_lport = uh->uh_sport; - + if ((so->so_iptos = udp_tos(so)) == 0) so->so_iptos = ip->ip_tos; - + /* * XXXXX Here, check if it's in udpexec_list, * and if it is, do the fork_exec() etc. @@ -233,7 +233,7 @@ udp_input(m, iphlen) m->m_data -= iphlen; *ip=save_ip; DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); - icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); } m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ @@ -251,7 +251,7 @@ bad: return; } -int udp_output2(struct socket *so, struct mbuf *m, +int udp_output2(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, struct sockaddr_in *daddr, int iptos) { @@ -269,7 +269,7 @@ int udp_output2(struct socket *so, struct mbuf *m, */ m->m_data -= sizeof(struct udpiphdr); m->m_len += sizeof(struct udpiphdr); - + /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. @@ -298,15 +298,15 @@ int udp_output2(struct socket *so, struct mbuf *m, ((struct ip *)ui)->ip_ttl = ip_defttl; ((struct ip *)ui)->ip_tos = iptos; - + udpstat.udps_opackets++; - + error = ip_output(so, m); - + return (error); } -int udp_output(struct socket *so, struct mbuf *m, +int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *addr) { @@ -320,7 +320,7 @@ int udp_output(struct socket *so, struct mbuf *m, } daddr.sin_addr = so->so_laddr; daddr.sin_port = so->so_lport; - + return udp_output2(so, m, &saddr, &daddr, so->so_iptos); } @@ -329,7 +329,7 @@ udp_attach(so) struct socket *so; { struct sockaddr_in addr; - + if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { /* * Here, we bind() the socket. Although not really needed @@ -380,7 +380,7 @@ udp_tos(so) struct socket *so; { int i = 0; - + while(udptos[i].tos) { if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { @@ -389,7 +389,7 @@ udp_tos(so) } i++; } - + return 0; } @@ -412,17 +412,17 @@ udp_emu(so, m) CTL_MSG *nmsg; char buff[sizeof(CTL_MSG)]; u_char type; - + struct talk_request { struct talk_request *next; struct socket *udp_so; struct socket *tcp_so; } *req; - - static struct talk_request *req_tbl = 0; - + + static struct talk_request *req_tbl = 0; + #endif - + struct cu_header { uint16_t d_family; // destination family uint16_t d_port; // destination port @@ -449,7 +449,7 @@ struct cu_header { */ if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) return; - + #define IS_OLD (so->so_emu == EMU_TALK) #define COPY_MSG(dest, src) { dest->type = src->type; \ @@ -472,7 +472,7 @@ struct cu_header { OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD); - } else { /* new talk */ + } else { /* new talk */ omsg = (CTL_MSG_OLD *) buff; nmsg = mtod(m, CTL_MSG *); type = nmsg->type; @@ -480,10 +480,10 @@ struct cu_header { OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); } - - if (type == LOOK_UP) + + if (type == LOOK_UP) return; /* for LOOK_UP this is enough */ - + if (IS_OLD) { /* make a copy of the message */ COPY_MSG(nmsg, omsg); nmsg->vers = 1; @@ -502,75 +502,75 @@ struct cu_header { * ports, 517 and 518. This is why we have two copies * of the message, one in old talk and one in new talk * format. - */ + */ if (type == ANNOUNCE) { int s; u_short temp_port; - + for(req = req_tbl; req; req = req->next) if (so == req->udp_so) break; /* found it */ - + if (!req) { /* no entry for so, create new */ req = (struct talk_request *) malloc(sizeof(struct talk_request)); req->udp_so = so; - req->tcp_so = solisten(0, - OTOSIN(omsg, addr)->sin_addr.s_addr, + req->tcp_so = solisten(0, + OTOSIN(omsg, addr)->sin_addr.s_addr, OTOSIN(omsg, addr)->sin_port, SS_FACCEPTONCE); req->next = req_tbl; req_tbl = req; - } - + } + /* replace port number in addr field */ addrlen = sizeof(addr); - getsockname(req->tcp_so->s, + getsockname(req->tcp_so->s, (struct sockaddr *) &addr, - &addrlen); + &addrlen); OTOSIN(omsg, addr)->sin_port = addr.sin_port; OTOSIN(omsg, addr)->sin_addr = our_addr; OTOSIN(nmsg, addr)->sin_port = addr.sin_port; - OTOSIN(nmsg, addr)->sin_addr = our_addr; - + OTOSIN(nmsg, addr)->sin_addr = our_addr; + /* send LEAVE_INVITEs */ temp_port = OTOSIN(omsg, ctl_addr)->sin_port; OTOSIN(omsg, ctl_addr)->sin_port = 0; OTOSIN(nmsg, ctl_addr)->sin_port = 0; - omsg->type = nmsg->type = LEAVE_INVITE; - + omsg->type = nmsg->type = LEAVE_INVITE; + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); addr.sin_addr = our_addr; addr.sin_family = AF_INET; addr.sin_port = htons(517); - sendto(s, (char *)omsg, sizeof(*omsg), 0, + sendto(s, (char *)omsg, sizeof(*omsg), 0, (struct sockaddr *)&addr, sizeof(addr)); addr.sin_port = htons(518); sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *) &addr, sizeof(addr)); closesocket(s) ; - omsg->type = nmsg->type = ANNOUNCE; + omsg->type = nmsg->type = ANNOUNCE; OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; } - - /* + + /* * If it is a DELETE message, we send a copy to the * local daemons. Then we delete the entry corresponding * to our socket from the request table. */ - + if (type == DELETE) { struct talk_request *temp_req, *req_next; int s; u_short temp_port; - + temp_port = OTOSIN(omsg, ctl_addr)->sin_port; OTOSIN(omsg, ctl_addr)->sin_port = 0; OTOSIN(nmsg, ctl_addr)->sin_port = 0; - + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); addr.sin_addr = our_addr; addr.sin_family = AF_INET; @@ -581,7 +581,7 @@ struct cu_header { sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *)&addr, sizeof(addr)); closesocket(s); - + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; @@ -604,18 +604,18 @@ struct cu_header { } } } - - return; + + return; #endif - - case EMU_CUSEEME: + case EMU_CUSEEME: + /* * Cu-SeeMe emulation. * Hopefully the packet is more that 16 bytes long. We don't * do any other tests, just replace the address and port * fields. - */ + */ if (m->m_len >= sizeof (*cu_head)) { if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) return; @@ -623,7 +623,7 @@ struct cu_header { cu_head->s_port = addr.sin_port; cu_head->so_addr = our_addr.s_addr; } - + return; } } @@ -638,7 +638,7 @@ udp_listen(port, laddr, lport, flags) struct sockaddr_in addr; struct socket *so; int addrlen = sizeof(struct sockaddr_in), opt = 1; - + if ((so = socreate()) == NULL) { free(so); return NULL; @@ -657,20 +657,20 @@ udp_listen(port, laddr, lport, flags) } setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); /* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ - + getsockname(so->s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) so->so_faddr = alias_addr; else so->so_faddr = addr.sin_addr; - + so->so_lport = lport; so->so_laddr.s_addr = laddr; if (flags != SS_FACCEPTONCE) so->so_expire = 0; - + so->so_state = SS_ISFCONNECTED; - + return so; } diff --git a/slirp/udp.h b/slirp/udp.h index 24c11bbf7..67da6cd73 100644 --- a/slirp/udp.h +++ b/slirp/udp.h @@ -104,7 +104,7 @@ void udp_detach _P((struct socket *)); u_int8_t udp_tos _P((struct socket *)); void udp_emu _P((struct socket *, struct mbuf *)); struct socket * udp_listen _P((u_int, u_int32_t, u_int, int)); -int udp_output2(struct socket *so, struct mbuf *m, +int udp_output2(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, struct sockaddr_in *daddr, int iptos); #endif diff --git a/softmmu-semi.h b/softmmu-semi.h index a5b897645..13c528bb8 100644 --- a/softmmu-semi.h +++ b/softmmu-semi.h @@ -1,4 +1,4 @@ -/* +/* * Helper routines to provide target memory access for semihosting * syscalls in system emulation mode. * diff --git a/softmmu_header.h b/softmmu_header.h index 317288448..768b87781 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -1,6 +1,6 @@ /* * Software MMU support - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -151,9 +151,9 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) #endif "2:\n" : "=r" (res) - : "r" (ptr), - "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), + : "r" (ptr), + "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)), "i" (CPU_MEM_INDEX), @@ -198,9 +198,9 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) #endif "2:\n" : "=r" (res) - : "r" (ptr), - "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), + : "r" (ptr), + "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)), "i" (CPU_MEM_INDEX), @@ -246,13 +246,13 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE #error unsupported size #endif "2:\n" - : - : "r" (ptr), + : + : "r" (ptr), /* NOTE: 'q' would be needed as constraint, but we could not use it with T1 ! */ - "r" (v), - "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), - "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), + "r" (v), + "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), + "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)), "i" (CPU_MEM_INDEX), @@ -275,7 +275,7 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != + if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user); } else { @@ -296,7 +296,7 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != + if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user); } else { @@ -321,7 +321,7 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_table[is_user][index].addr_write != + if (__builtin_expect(env->tlb_table[is_user][index].addr_write != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user); } else { diff --git a/softmmu_template.h b/softmmu_template.h index 1c12c4241..00492e8b5 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -1,6 +1,6 @@ /* * Software MMU support - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -47,10 +47,10 @@ #define ADDR_READ addr_read #endif -static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user, void *retaddr); -static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, +static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, target_ulong tlb_addr) { DATA_TYPE res; @@ -83,7 +83,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, target_ulong tlb_addr; target_phys_addr_t physaddr; void *retaddr; - + /* test if there is match for unaligned or IO access */ /* XXX: could done more in memory macro in a non portable way */ index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); @@ -103,7 +103,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, #ifdef ALIGNED_ONLY do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); #endif - res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, + res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, is_user, retaddr); } else { /* unaligned/aligned access in the same page */ @@ -129,7 +129,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, } /* handle all unaligned cases */ -static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int is_user, void *retaddr) { @@ -153,9 +153,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, /* slow unaligned access (it spans two pages) */ addr1 = addr & ~(DATA_SIZE - 1); addr2 = addr1 + DATA_SIZE; - res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, + res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, is_user, retaddr); - res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, + res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, is_user, retaddr); shift = (addr & (DATA_SIZE - 1)) * 8; #ifdef TARGET_WORDS_BIGENDIAN @@ -178,12 +178,12 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, #ifndef SOFTMMU_CODE_ACCESS -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, - DATA_TYPE val, +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, + DATA_TYPE val, int is_user, void *retaddr); -static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, +static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, DATA_TYPE val, target_ulong tlb_addr, void *retaddr) @@ -209,7 +209,7 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, #endif } -void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, +void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, int is_user) { @@ -217,7 +217,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, target_ulong tlb_addr; void *retaddr; int index; - + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_table[is_user][index].addr_write; @@ -235,7 +235,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, #ifdef ALIGNED_ONLY do_unaligned_access(addr, 1, is_user, retaddr); #endif - glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, + glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, is_user, retaddr); } else { /* aligned/unaligned access in the same page */ @@ -260,7 +260,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, } /* handles all unaligned cases */ -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, int is_user, void *retaddr) @@ -284,10 +284,10 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, /* XXX: not efficient, but simple */ for(i = 0;i < DATA_SIZE; i++) { #ifdef TARGET_WORDS_BIGENDIAN - glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), + glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), is_user, retaddr); #else - glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), + glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), is_user, retaddr); #endif } diff --git a/sparc-dis.c b/sparc-dis.c index 2c5921af5..28fab962c 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -359,7 +359,7 @@ sparc_opcode_lookup_arch (name) #define FBFCC(x) (((x)&0x3)<<20) /* v9 */ /* The order of the opcodes in the table is significant: - + * The assembler requires that all instances of the same mnemonic must be consecutive. If they aren't, the assembler will bomb at runtime. @@ -2341,16 +2341,16 @@ static int compute_arch_mask PARAMS ((unsigned long)); >> ((8 * sizeof (int)) - bits) ) static const char * const reg_names[] = -{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", - "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", - "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", - "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", +{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", + "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", + "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", + "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", - "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", - "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", + "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", + "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63", /* psr, wim, tbr, fpsr, cpsr are v8 only. */ @@ -2566,7 +2566,7 @@ print_insn_sparc (memaddr, info) /* Nonzero means that we have found a plus sign in the args field of the opcode table. */ int found_plus = 0; - + /* Nonzero means we have an annulled branch. */ int is_annulled = 0; @@ -2621,7 +2621,7 @@ print_insn_sparc (memaddr, info) } /* while there are comma started args */ (*info->fprintf_func) (stream, " "); - + switch (*s) { case '+': @@ -2722,7 +2722,7 @@ print_insn_sparc (memaddr, info) not before it. */ if (found_plus) imm_added_to_rs1 = 1; - + if (imm <= 9) (*info->fprintf_func) (stream, "%d", imm); else @@ -2806,7 +2806,7 @@ print_insn_sparc (memaddr, info) case 'o': (*info->fprintf_func) (stream, "%%asi"); break; - + case 'W': (*info->fprintf_func) (stream, "%%tick"); break; @@ -2859,15 +2859,15 @@ print_insn_sparc (memaddr, info) (*info->fprintf_func) (stream, "%d", X_RD (insn)); break; } - + case 'M': (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn)); break; - + case 'm': (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn)); break; - + case 'L': info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4; (*info->print_address_func) (info->target, info); @@ -2999,7 +2999,7 @@ print_insn_sparc (memaddr, info) && X_RD (prev_insn) == X_RS1 (insn)) { (*info->fprintf_func) (stream, "\t! "); - info->target = + info->target = ((unsigned) 0xFFFFFFFF & ((int) X_IMM22 (prev_insn) << 10)); if (imm_added_to_rs1) diff --git a/tap-win32.c b/tap-win32.c index d84a622d3..8384952c6 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -110,7 +110,7 @@ typedef struct tap_win32_overlapped { static tap_win32_overlapped_t tap_overlapped; -static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped) +static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped) { tun_buffer_t* buffer = NULL; WaitForSingleObject(overlapped->free_list_semaphore, INFINITE); @@ -132,18 +132,18 @@ static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tu ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL); } -static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block) +static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block) { tun_buffer_t* buffer = NULL; DWORD result, timeout = block ? INFINITE : 0L; // Non-blocking call - result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout); + result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout); - switch (result) - { + switch (result) + { // The semaphore object was signaled. - case WAIT_OBJECT_0: + case WAIT_OBJECT_0: EnterCriticalSection(&overlapped->output_queue_cs); buffer = overlapped->output_queue_front; @@ -154,18 +154,18 @@ static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const } LeaveCriticalSection(&overlapped->output_queue_cs); - break; + break; // Semaphore was nonsignaled, so a time-out occurred. - case WAIT_TIMEOUT: + case WAIT_TIMEOUT: // Cannot open another window. - break; + break; } return buffer; } -static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped) +static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped) { return get_buffer_from_output_queue(overlapped, 0); } @@ -332,7 +332,7 @@ static int get_device_guid( return -1; } - snprintf(connection_string, + snprintf(connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name); @@ -343,7 +343,7 @@ static int get_device_guid( 0, KEY_READ, &connection_key); - + if (status == ERROR_SUCCESS) { len = sizeof (name_data); status = RegQueryValueEx( @@ -416,7 +416,7 @@ static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, InitializeCriticalSection(&overlapped->output_queue_cs); InitializeCriticalSection(&overlapped->free_list_cs); - overlapped->output_queue_semaphore = CreateSemaphore( + overlapped->output_queue_semaphore = CreateSemaphore( NULL, // default security attributes 0, // initial count TUN_MAX_BUFFER_COUNT, // maximum count @@ -426,7 +426,7 @@ static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, fprintf(stderr, "error creating output queue semaphore!\n"); } - overlapped->free_list_semaphore = CreateSemaphore( + overlapped->free_list_semaphore = CreateSemaphore( NULL, // default security attributes TUN_MAX_BUFFER_COUNT, // initial count TUN_MAX_BUFFER_COUNT, // maximum count @@ -452,7 +452,7 @@ static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, fprintf(stderr, "error creating tap_semaphore.\n"); } -static int tap_win32_write(tap_win32_overlapped_t *overlapped, +static int tap_win32_write(tap_win32_overlapped_t *overlapped, const void *buffer, unsigned long size) { unsigned long write_size; @@ -467,18 +467,18 @@ static int tap_win32_write(tap_win32_overlapped_t *overlapped, result = WriteFile(overlapped->handle, buffer, size, &write_size, &overlapped->write_overlapped); - - if (!result) { + + if (!result) { switch (error = GetLastError()) - { - case ERROR_IO_PENDING: + { + case ERROR_IO_PENDING: #ifndef TUN_ASYNCHRONOUS_WRITES WaitForSingleObject(overlapped->write_event, INFINITE); #endif break; default: return -1; - } + } } return 0; @@ -539,7 +539,7 @@ static DWORD WINAPI tap_win32_thread_entry(LPVOID param) return 0; } -static int tap_win32_read(tap_win32_overlapped_t *overlapped, +static int tap_win32_read(tap_win32_overlapped_t *overlapped, uint8_t **pbuf, int max_size) { int size = 0; @@ -557,14 +557,14 @@ static int tap_win32_read(tap_win32_overlapped_t *overlapped, return size; } -static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, - char* pbuf) +static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, + char* pbuf) { tun_buffer_t* buffer = (tun_buffer_t*)pbuf; put_buffer_on_free_list(overlapped, buffer); } -static int tap_win32_open(tap_win32_overlapped_t **phandle, +static int tap_win32_open(tap_win32_overlapped_t **phandle, const char *prefered_name) { char device_path[256]; @@ -660,7 +660,7 @@ static void tap_win32_send(void *opaque) int tap_win32_init(VLANState *vlan, const char *ifname) { TAPState *s; - + s = qemu_mallocz(sizeof(TAPState)); if (!s) return -1; @@ -670,7 +670,7 @@ int tap_win32_init(VLANState *vlan, const char *ifname) } s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s); - + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s", ifname); diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index c79c5680a..b219ad38b 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -1,6 +1,6 @@ /* * Alpha emulation cpu definitions for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -276,7 +276,7 @@ struct CPUAlphaState { #if TARGET_LONG_BITS > HOST_LONG_BITS /* temporary fixed-point registers * used to emulate 64 bits target on 32 bits hosts - */ + */ target_ulong t0, t1, t2; #endif /* */ @@ -393,7 +393,7 @@ int cpu_alpha_exec(CPUAlphaState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -int cpu_alpha_signal_handler(int host_signum, void *pinfo, +int cpu_alpha_signal_handler(int host_signum, void *pinfo, void *puc); int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); diff --git a/target-alpha/exec.h b/target-alpha/exec.h index 32c27c735..80f358ca3 100644 --- a/target-alpha/exec.h +++ b/target-alpha/exec.h @@ -1,6 +1,6 @@ /* * Alpha emulation cpu run-time definitions for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 98200d9fb..4ec5967ff 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -1,6 +1,6 @@ /* * Alpha emulation cpu helpers for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -25,7 +25,7 @@ #include "cpu.h" #include "exec-all.h" -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) @@ -35,7 +35,7 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, else env->exception_index = EXCP_DFAULT; env->ipr[IPR_EXC_ADDR] = address; - + return 1; } @@ -407,7 +407,7 @@ void do_interrupt (CPUState *env) } #endif -void cpu_dump_state (CPUState *env, FILE *f, +void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { diff --git a/target-alpha/op.c b/target-alpha/op.c index 8a22c5c08..529a66de0 100644 --- a/target-alpha/op.c +++ b/target-alpha/op.c @@ -1,6 +1,6 @@ /* * Alpha emulation cpu micro-operations for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 746665a42..deac6c259 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -1,6 +1,6 @@ /* * Alpha emulation cpu micro-operations helpers for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-alpha/op_helper.h b/target-alpha/op_helper.h index fb55eff37..806a30d4a 100644 --- a/target-alpha/op_helper.h +++ b/target-alpha/op_helper.h @@ -1,6 +1,6 @@ /* * Alpha emulation cpu micro-operations helpers definitions for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-alpha/op_helper_mem.h b/target-alpha/op_helper_mem.h index 7ab5718b9..09c39bb80 100644 --- a/target-alpha/op_helper_mem.h +++ b/target-alpha/op_helper_mem.h @@ -1,6 +1,6 @@ /* * Alpha emulation cpu micro-operations helpers for memory accesses for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-alpha/op_mem.h b/target-alpha/op_mem.h index 9f017a2af..922d0d4de 100644 --- a/target-alpha/op_mem.h +++ b/target-alpha/op_mem.h @@ -1,6 +1,6 @@ /* * Alpha emulation cpu micro-operations for memory accesses for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-alpha/op_template.h b/target-alpha/op_template.h index e96303ba3..db15bb891 100644 --- a/target-alpha/op_template.h +++ b/target-alpha/op_template.h @@ -1,6 +1,6 @@ /* * Alpha emulation cpu micro-operations templates for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 9ed53be28..6a7da5adf 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -1,6 +1,6 @@ /* * Alpha emulation cpu translation for qemu. - * + * * Copyright (c) 2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -562,49 +562,49 @@ static void gen_s4addl (void) { gen_op_s4(); gen_op_addl(); -} +} static void gen_s4subl (void) { gen_op_s4(); gen_op_subl(); -} +} static void gen_s8addl (void) { gen_op_s8(); gen_op_addl(); -} +} static void gen_s8subl (void) { gen_op_s8(); gen_op_subl(); -} +} static void gen_s4addq (void) { gen_op_s4(); gen_op_addq(); -} +} static void gen_s4subq (void) { gen_op_s4(); gen_op_subq(); -} +} static void gen_s8addq (void) { gen_op_s8(); gen_op_addq(); -} +} static void gen_s8subq (void) { gen_op_s8(); gen_op_subq(); -} +} static void gen_amask (void) { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index ef203c331..19ce68b4f 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1,6 +1,6 @@ /* * ARM virtual CPU header - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -64,11 +64,11 @@ typedef struct CPUARMState { uint32_t banked_spsr[6]; uint32_t banked_r13[6]; uint32_t banked_r14[6]; - + /* These hold r8-r12. */ uint32_t usr_regs[5]; uint32_t fiq_regs[5]; - + /* cpsr flag cache for faster execution */ uint32_t CF; /* 0 or 1 */ uint32_t VF; /* V is the bit 31. All other bits are undefined */ @@ -134,7 +134,7 @@ typedef struct CPUARMState { /* Temporary variables if we don't have spare fp regs. */ float32 tmp0s, tmp1s; float64 tmp0d, tmp1d; - + float_status fp_status; } vfp; @@ -171,7 +171,7 @@ void switch_mode(CPUARMState *, int); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -int cpu_arm_signal_handler(int host_signum, void *pinfo, +int cpu_arm_signal_handler(int host_signum, void *pinfo, void *puc); #define CPSR_M (0x1f) @@ -193,7 +193,7 @@ static inline uint32_t cpsr_read(CPUARMState *env) { int ZF; ZF = (env->NZF == 0); - return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) | (env->thumb << 5); } diff --git a/target-arm/exec.h b/target-arm/exec.h index b25c7e2d4..9da19150b 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -1,6 +1,6 @@ /* * ARM execution defines - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or diff --git a/target-arm/helper.c b/target-arm/helper.c index f1b170d03..01573a238 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -161,7 +161,7 @@ void cpu_arm_close(CPUARMState *env) free(env); } -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) void do_interrupt (CPUState *env) { diff --git a/target-arm/nwfpe/double_cpdo.c b/target-arm/nwfpe/double_cpdo.c index 944083a43..afc86aa41 100644 --- a/target-arm/nwfpe/double_cpdo.c +++ b/target-arm/nwfpe/double_cpdo.c @@ -42,14 +42,14 @@ unsigned int DoubleCPDO(const unsigned int opcode) unsigned int Fd, Fm, Fn, nRc = 1; //printk("DoubleCPDO(0x%08x)\n",opcode); - + Fm = getFm(opcode); if (CONSTANT_FM(opcode)) { rFm = getDoubleConstant(Fm); } else - { + { switch (fpa11->fType[Fm]) { case typeSingle: @@ -85,7 +85,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) case typeDouble: rFn = fpa11->fpreg[Fn].fDouble; break; - + default: return 0; } } @@ -220,7 +220,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) case NRM_CODE: break; - + default: { nRc = 0; @@ -286,11 +286,11 @@ return rFm; float64 float64_pow(float64 rFn,float64 rFm) { - return float64_exp(float64_mul(rFm,float64_ln(rFn))); + return float64_exp(float64_mul(rFm,float64_ln(rFn))); } float64 float64_pol(float64 rFn,float64 rFm) { - return float64_arctan(float64_div(rFn,rFm)); + return float64_arctan(float64_div(rFn,rFm)); } #endif diff --git a/target-arm/nwfpe/extended_cpdo.c b/target-arm/nwfpe/extended_cpdo.c index f5ef62311..caacdf228 100644 --- a/target-arm/nwfpe/extended_cpdo.c +++ b/target-arm/nwfpe/extended_cpdo.c @@ -42,14 +42,14 @@ unsigned int ExtendedCPDO(const unsigned int opcode) unsigned int Fd, Fm, Fn, nRc = 1; //printk("ExtendedCPDO(0x%08x)\n",opcode); - + Fm = getFm(opcode); if (CONSTANT_FM(opcode)) { rFm = getExtendedConstant(Fm); } else - { + { switch (fpa11->fType[Fm]) { case typeSingle: @@ -59,15 +59,15 @@ unsigned int ExtendedCPDO(const unsigned int opcode) case typeDouble: rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; - + case typeExtended: rFm = fpa11->fpreg[Fm].fExtended; break; - + default: return 0; } } - + if (!MONADIC_INSTRUCTION(opcode)) { Fn = getFn(opcode); @@ -80,11 +80,11 @@ unsigned int ExtendedCPDO(const unsigned int opcode) case typeDouble: rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; - + case typeExtended: rFn = fpa11->fpreg[Fn].fExtended; break; - + default: return 0; } } @@ -204,13 +204,13 @@ unsigned int ExtendedCPDO(const unsigned int opcode) case NRM_CODE: break; - + default: { nRc = 0; } } - + if (0 != nRc) fpa11->fType[Fd] = typeExtended; return nRc; } @@ -263,11 +263,11 @@ floatx80 floatx80_arccos(floatx80 rFm) floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) { - return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); + return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); } floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) { - return floatx80_arctan(floatx80_div(rFn,rFm)); + return floatx80_arctan(floatx80_div(rFn,rFm)); } #endif diff --git a/target-arm/nwfpe/fpa11.c b/target-arm/nwfpe/fpa11.c index a8141e7e5..7fe6ed3f9 100644 --- a/target-arm/nwfpe/fpa11.c +++ b/target-arm/nwfpe/fpa11.c @@ -43,16 +43,16 @@ void resetFPA11(void) { int i; FPA11 *fpa11 = GET_FPA11(); - + /* initialize the register type array */ for (i=0;i<=7;i++) { fpa11->fType[i] = typeNone; } - + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ fpa11->fpsr = FP_EMULATOR | BIT_AC; - + /* FPCR: set SB, AB and DA bits, clear all others */ #if MAINTAIN_FPCR fpa11->fpcr = MASK_RESET; @@ -66,36 +66,36 @@ void SetRoundingMode(const unsigned int opcode) #if MAINTAIN_FPCR fpa11->fpcr &= ~MASK_ROUNDING_MODE; -#endif +#endif switch (opcode & MASK_ROUNDING_MODE) { default: case ROUND_TO_NEAREST: rounding_mode = float_round_nearest_even; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_NEAREST; -#endif +#endif break; - + case ROUND_TO_PLUS_INFINITY: rounding_mode = float_round_up; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; -#endif +#endif break; - + case ROUND_TO_MINUS_INFINITY: rounding_mode = float_round_down; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; -#endif +#endif break; - + case ROUND_TO_ZERO: rounding_mode = float_round_to_zero; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_ZERO; -#endif +#endif break; } set_float_rounding_mode(rounding_mode, &fpa11->fp_status); @@ -107,30 +107,30 @@ void SetRoundingPrecision(const unsigned int opcode) FPA11 *fpa11 = GET_FPA11(); #if MAINTAIN_FPCR fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; -#endif +#endif switch (opcode & MASK_ROUNDING_PRECISION) { case ROUND_SINGLE: rounding_precision = 32; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_SINGLE; -#endif +#endif break; - + case ROUND_DOUBLE: rounding_precision = 64; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_DOUBLE; -#endif +#endif break; - + case ROUND_EXTENDED: rounding_precision = 80; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_EXTENDED; -#endif +#endif break; - + default: rounding_precision = 80; } set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status); @@ -142,12 +142,12 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) { unsigned int nRc = 0; // unsigned long flags; - FPA11 *fpa11; + FPA11 *fpa11; // save_flags(flags); sti(); qemufpa=qfpa; user_registers=qregs; - + #if 0 fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", opcode, qregs[REG_PC]); @@ -222,14 +222,14 @@ unsigned int EmulateAll1(unsigned int opcode) } } break; - - case 0xe: + + case 0xe: if (opcode & 0x10) return EmulateCPDO(opcode); else return EmulateCPRT(opcode); break; - + default: return 0; } } diff --git a/target-arm/nwfpe/fpa11.h b/target-arm/nwfpe/fpa11.h index 8751696de..f1fdfbdda 100644 --- a/target-arm/nwfpe/fpa11.h +++ b/target-arm/nwfpe/fpa11.h @@ -1,7 +1,7 @@ /* NetWinder Floating Point Emulator (c) Rebel.com, 1998-1999 - + Direct questions, comments to Scott Bambrough This program is free software; you can redistribute it and/or modify diff --git a/target-arm/nwfpe/fpa11_cpdo.c b/target-arm/nwfpe/fpa11_cpdo.c index cc8aa87c6..3d5cc9310 100644 --- a/target-arm/nwfpe/fpa11_cpdo.c +++ b/target-arm/nwfpe/fpa11_cpdo.c @@ -30,26 +30,26 @@ unsigned int EmulateCPDO(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); unsigned int Fd, nType, nDest, nRc = 1; - + //printk("EmulateCPDO(0x%08x)\n",opcode); /* Get the destination size. If not valid let Linux perform an invalid instruction trap. */ nDest = getDestinationSize(opcode); if (typeNone == nDest) return 0; - + SetRoundingMode(opcode); - + /* Compare the size of the operands in Fn and Fm. Choose the largest size and perform operations in that size, - in order to make use of all the precision of the operands. - If Fm is a constant, we just grab a constant of a size + in order to make use of all the precision of the operands. + If Fm is a constant, we just grab a constant of a size matching the size of the operand in Fn. */ if (MONADIC_INSTRUCTION(opcode)) nType = nDest; else nType = fpa11->fType[getFn(opcode)]; - + if (!CONSTANT_FM(opcode)) { register unsigned int Fm = getFm(opcode); @@ -79,39 +79,39 @@ unsigned int EmulateCPDO(const unsigned int opcode) case typeSingle: { if (typeDouble == nType) - fpa11->fpreg[Fd].fSingle = + fpa11->fpreg[Fd].fSingle = float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); else - fpa11->fpreg[Fd].fSingle = + fpa11->fpreg[Fd].fSingle = floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); } break; - + case typeDouble: { if (typeSingle == nType) - fpa11->fpreg[Fd].fDouble = + fpa11->fpreg[Fd].fDouble = float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); else - fpa11->fpreg[Fd].fDouble = + fpa11->fpreg[Fd].fDouble = floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); } break; - + case typeExtended: { if (typeSingle == nType) - fpa11->fpreg[Fd].fExtended = + fpa11->fpreg[Fd].fExtended = float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); else - fpa11->fpreg[Fd].fExtended = + fpa11->fpreg[Fd].fExtended = float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); } break; } - + fpa11->fType[Fd] = nDest; } - + return nRc; } diff --git a/target-arm/nwfpe/fpa11_cpdt.c b/target-arm/nwfpe/fpa11_cpdt.c index 914a86fbc..e1a67c71c 100644 --- a/target-arm/nwfpe/fpa11_cpdt.c +++ b/target-arm/nwfpe/fpa11_cpdt.c @@ -52,7 +52,7 @@ void loadDouble(const unsigned int Fn,const unsigned int *pMem) p[0] = tget32(addr + 4); p[1] = tget32(addr); /* sign & exponent */ #endif -} +} static inline void loadExtended(const unsigned int Fn,const unsigned int *pMem) @@ -65,7 +65,7 @@ void loadExtended(const unsigned int Fn,const unsigned int *pMem) p[0] = tget32(addr); /* sign & exponent */ p[1] = tget32(addr + 8); /* ls bits */ p[2] = tget32(addr + 4); /* ms bits */ -} +} static inline void loadMultiple(const unsigned int Fn,const unsigned int *pMem) @@ -78,7 +78,7 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) p = (unsigned int*)&(fpa11->fpreg[Fn]); x = tget32(addr); fpa11->fType[Fn] = (x >> 14) & 0x00000003; - + switch (fpa11->fType[Fn]) { case typeSingle: @@ -88,13 +88,13 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) p[1] = tget32(addr + 4); /* double msw */ p[2] = 0; /* empty */ } - break; - + break; + case typeExtended: { p[1] = tget32(addr + 8); p[2] = tget32(addr + 4); /* msw */ - p[0] = (x & 0x80003fff); + p[0] = (x & 0x80003fff); } break; } @@ -107,22 +107,22 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem) FPA11 *fpa11 = GET_FPA11(); float32 val; register unsigned int *p = (unsigned int*)&val; - + switch (fpa11->fType[Fn]) { - case typeDouble: + case typeDouble: val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; - case typeExtended: + case typeExtended: val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); break; default: val = fpa11->fpreg[Fn].fSingle; } - + tput32(addr, p[0]); -} +} static inline void storeDouble(const unsigned int Fn,unsigned int *pMem) @@ -134,7 +134,7 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem) switch (fpa11->fType[Fn]) { - case typeSingle: + case typeSingle: val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; @@ -151,7 +151,7 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem) tput32(addr, p[1]); /* msw */ tput32(addr + 4, p[0]); /* lsw */ #endif -} +} static inline void storeExtended(const unsigned int Fn,unsigned int *pMem) @@ -160,24 +160,24 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem) FPA11 *fpa11 = GET_FPA11(); floatx80 val; register unsigned int *p = (unsigned int*)&val; - + switch (fpa11->fType[Fn]) { - case typeSingle: + case typeSingle: val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; - case typeDouble: + case typeDouble: val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; default: val = fpa11->fpreg[Fn].fExtended; } - + tput32(addr, p[0]); /* sign & exp */ tput32(addr + 8, p[1]); tput32(addr + 4, p[2]); /* msw */ -} +} static inline void storeMultiple(const unsigned int Fn,unsigned int *pMem) @@ -185,10 +185,10 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem) target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); register unsigned int nType, *p; - + p = (unsigned int*)&(fpa11->fpreg[Fn]); nType = fpa11->fType[Fn]; - + switch (nType) { case typeSingle: @@ -198,8 +198,8 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem) tput32(addr + 4, p[1]); /* double msw */ tput32(addr, nType << 14); } - break; - + break; + case typeExtended: { tput32(addr + 4, p[2]); /* msw */ @@ -239,7 +239,7 @@ unsigned int PerformLDF(const unsigned int opcode) case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; default: nRc = 0; } - + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return nRc; } @@ -248,10 +248,10 @@ unsigned int PerformSTF(const unsigned int opcode) { unsigned int *pBase, *pAddress, *pFinal, nRc = 1, write_back = WRITE_BACK(opcode); - + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); SetRoundingMode(ROUND_TO_NEAREST); - + pBase = (unsigned int*)readRegister(getRn(opcode)); if (REG_PC == getRn(opcode)) { @@ -274,7 +274,7 @@ unsigned int PerformSTF(const unsigned int opcode) case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; default: nRc = 0; } - + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return nRc; } @@ -315,14 +315,14 @@ unsigned int PerformSFM(const unsigned int opcode) { unsigned int i, Fd, *pBase, *pAddress, *pFinal, write_back = WRITE_BACK(opcode); - + pBase = (unsigned int*)readRegister(getRn(opcode)); if (REG_PC == getRn(opcode)) { pBase += 2; write_back = 0; } - + pFinal = pBase; if (BIT_UP_SET(opcode)) pFinal += getOffset(opcode); @@ -349,7 +349,7 @@ unsigned int EmulateCPDT(const unsigned int opcode) unsigned int nRc = 0; //printk("EmulateCPDT(0x%08x)\n",opcode); - + if (LDF_OP(opcode)) { nRc = PerformLDF(opcode); @@ -361,7 +361,7 @@ unsigned int EmulateCPDT(const unsigned int opcode) else if (STF_OP(opcode)) { nRc = PerformSTF(opcode); - } + } else if (SFM_OP(opcode)) { nRc = PerformSFM(opcode); @@ -370,7 +370,7 @@ unsigned int EmulateCPDT(const unsigned int opcode) { nRc = 0; } - + return nRc; } #endif diff --git a/target-arm/nwfpe/fpa11_cprt.c b/target-arm/nwfpe/fpa11_cprt.c index 3be9b42a9..68c4ff192 100644 --- a/target-arm/nwfpe/fpa11_cprt.c +++ b/target-arm/nwfpe/fpa11_cprt.c @@ -55,7 +55,7 @@ unsigned int EmulateCPRT(const unsigned int opcode) { case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; - + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; @@ -67,14 +67,14 @@ unsigned int EmulateCPRT(const unsigned int opcode) default: nRc = 0; } - + return nRc; } unsigned int PerformFLT(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); - + unsigned int nRc = 1; SetRoundingMode(opcode); @@ -95,7 +95,7 @@ unsigned int PerformFLT(const unsigned int opcode) int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status); } break; - + case ROUND_EXTENDED: { fpa11->fType[getFn(opcode)] = typeExtended; @@ -103,10 +103,10 @@ unsigned int PerformFLT(const unsigned int opcode) int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status); } break; - + default: nRc = 0; } - + return nRc; } @@ -115,7 +115,7 @@ unsigned int PerformFIX(const unsigned int opcode) FPA11 *fpa11 = GET_FPA11(); unsigned int nRc = 1; unsigned int Fn = getFm(opcode); - + SetRoundingMode(opcode); switch (fpa11->fType[Fn]) @@ -134,21 +134,21 @@ unsigned int PerformFIX(const unsigned int opcode) float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status)); } break; - + case typeExtended: { writeRegister(getRd(opcode), floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status)); } break; - + default: nRc = 0; } - + return nRc; } - + static unsigned int __inline__ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) { @@ -160,7 +160,7 @@ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) { flags |= CC_NEGATIVE; } - + /* test for equal condition */ if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) { @@ -172,13 +172,13 @@ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) { flags |= CC_CARRY; } - + writeConditionCodes(flags); return 1; } /* This instruction sets the flags N, Z, C, V in the FPSR. */ - + static unsigned int PerformComparison(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); @@ -200,27 +200,27 @@ static unsigned int PerformComparison(const unsigned int opcode) comparison (cheaper than an 80-bit one). */ switch (fpa11->fType[Fn]) { - case typeSingle: + case typeSingle: //printk("single.\n"); if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) goto unordered; rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; - case typeDouble: + case typeDouble: //printk("double.\n"); if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) goto unordered; rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; - - case typeExtended: + + case typeExtended: //printk("extended.\n"); if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) goto unordered; rFn = fpa11->fpreg[Fn].fExtended; break; - + default: return 0; } @@ -236,27 +236,27 @@ static unsigned int PerformComparison(const unsigned int opcode) //printk("Fm = r%d which contains a ",Fm); switch (fpa11->fType[Fm]) { - case typeSingle: + case typeSingle: //printk("single.\n"); if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) goto unordered; rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); break; - case typeDouble: + case typeDouble: //printk("double.\n"); if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) goto unordered; rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; - - case typeExtended: + + case typeExtended: //printk("extended.\n"); if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) goto unordered; rFm = fpa11->fpreg[Fm].fExtended; break; - + default: return 0; } } diff --git a/target-arm/nwfpe/fpopcode.c b/target-arm/nwfpe/fpopcode.c index d29e913f4..efee406fb 100644 --- a/target-arm/nwfpe/fpopcode.c +++ b/target-arm/nwfpe/fpopcode.c @@ -35,7 +35,7 @@ const floatx80 floatx80Constant[] = { { 0xa000000000000000ULL, 0x4001}, /* extended 5.0 */ { 0x8000000000000000ULL, 0x3ffe}, /* extended 0.5 */ { 0xa000000000000000ULL, 0x4002} /* extended 10.0 */ -}; +}; const float64 float64Constant[] = { 0x0000000000000000ULL, /* double 0.0 */ @@ -46,7 +46,7 @@ const float64 float64Constant[] = { 0x4014000000000000ULL, /* double 5.0 */ 0x3fe0000000000000ULL, /* double 0.5 */ 0x4024000000000000ULL /* double 10.0 */ -}; +}; const float32 float32Constant[] = { 0x00000000, /* single 0.0 */ @@ -57,12 +57,12 @@ const float32 float32Constant[] = { 0x40a00000, /* single 5.0 */ 0x3f000000, /* single 0.5 */ 0x41200000 /* single 10.0 */ -}; +}; unsigned int getTransferLength(const unsigned int opcode) { unsigned int nRc; - + switch (opcode & MASK_TRANSFER_LENGTH) { case 0x00000000: nRc = 1; break; /* single precision */ @@ -70,14 +70,14 @@ unsigned int getTransferLength(const unsigned int opcode) case 0x00400000: nRc = 3; break; /* extended precision */ default: nRc = 0; } - + return(nRc); } unsigned int getRegisterCount(const unsigned int opcode) { unsigned int nRc; - + switch (opcode & MASK_REGISTER_COUNT) { case 0x00000000: nRc = 4; break; @@ -86,14 +86,14 @@ unsigned int getRegisterCount(const unsigned int opcode) case 0x00408000: nRc = 3; break; default: nRc = 0; } - + return(nRc); } unsigned int getRoundingPrecision(const unsigned int opcode) { unsigned int nRc; - + switch (opcode & MASK_ROUNDING_PRECISION) { case 0x00000000: nRc = 1; break; @@ -101,14 +101,14 @@ unsigned int getRoundingPrecision(const unsigned int opcode) case 0x00080000: nRc = 3; break; default: nRc = 0; } - + return(nRc); } unsigned int getDestinationSize(const unsigned int opcode) { unsigned int nRc; - + switch (opcode & MASK_DESTINATION_SIZE) { case 0x00000000: nRc = typeSingle; break; @@ -116,7 +116,7 @@ unsigned int getDestinationSize(const unsigned int opcode) case 0x00080000: nRc = typeExtended; break; default: nRc = typeNone; } - + return(nRc); } diff --git a/target-arm/nwfpe/fpopcode.h b/target-arm/nwfpe/fpopcode.h index 13c741926..e16e47af6 100644 --- a/target-arm/nwfpe/fpopcode.h +++ b/target-arm/nwfpe/fpopcode.h @@ -24,18 +24,18 @@ /* ARM Floating Point Instruction Classes -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT |c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO |c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT |c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons -| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | CPDT data transfer instructions LDF, STF, LFM, SFM - + CPDO dyadic arithmetic instructions ADF, MUF, SUF, RSF, DVF, RDF, POW, RPW, RMF, FML, FDV, FRD, POL @@ -43,7 +43,7 @@ CPDO dyadic arithmetic instructions CPDO monadic arithmetic instructions MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN, URD, NRM - + CPRT joint arithmetic/data transfer instructions FIX (arithmetic followed by load/store) FLT (load/store followed by arithmetic) @@ -57,7 +57,7 @@ U up/down bit: 0 = stack grows down, 1 = stack grows up W write back bit: 1 = update base register (Rn) L load/store bit: 0 = store, 1 = load Rn base register -Rd destination/source register +Rd destination/source register Fd floating point destination register Fn floating point source register Fm floating point source register or floating point constant @@ -370,19 +370,19 @@ static inline const floatx80 getExtendedConstant(const unsigned int nIndex) { extern const floatx80 floatx80Constant[]; return floatx80Constant[nIndex]; -} +} static inline const float64 getDoubleConstant(const unsigned int nIndex) { extern const float64 float64Constant[]; return float64Constant[nIndex]; -} +} static inline const float32 getSingleConstant(const unsigned int nIndex) { extern const float32 float32Constant[]; return float32Constant[nIndex]; -} +} extern unsigned int getRegisterCount(const unsigned int opcode); extern unsigned int getDestinationSize(const unsigned int opcode); diff --git a/target-arm/nwfpe/fpsr.h b/target-arm/nwfpe/fpsr.h index 6dafb0f52..0c665431e 100644 --- a/target-arm/nwfpe/fpsr.h +++ b/target-arm/nwfpe/fpsr.h @@ -30,7 +30,7 @@ one byte. EXCEPTION TRAP ENABLE BYTE SYSTEM CONTROL BYTE CUMULATIVE EXCEPTION FLAGS BYTE - + The FPCR is a 32 bit register consisting of bit flags. */ @@ -43,7 +43,7 @@ typedef unsigned int FPCR; /* type for floating point control register */ #define MASK_SYSID 0xff000000 #define BIT_HARDWARE 0x80000000 -#define FP_EMULATOR 0x01000000 /* System ID for emulator */ +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ #define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ /* EXCEPTION TRAP ENABLE BYTE diff --git a/target-arm/nwfpe/single_cpdo.c b/target-arm/nwfpe/single_cpdo.c index 7dd2620f2..4f2ca6ade 100644 --- a/target-arm/nwfpe/single_cpdo.c +++ b/target-arm/nwfpe/single_cpdo.c @@ -47,13 +47,13 @@ unsigned int SingleCPDO(const unsigned int opcode) rFm = getSingleConstant(Fm); } else - { + { switch (fpa11->fType[Fm]) { case typeSingle: rFm = fpa11->fpreg[Fm].fSingle; break; - + default: return 0; } } @@ -186,7 +186,7 @@ unsigned int SingleCPDO(const unsigned int opcode) case NRM_CODE: break; - + default: { nRc = 0; @@ -245,11 +245,11 @@ float32 float32_tan(float32 rFm) float32 float32_pow(float32 rFn,float32 rFm) { - return float32_exp(float32_mul(rFm,float32_ln(rFn))); + return float32_exp(float32_mul(rFm,float32_ln(rFn))); } float32 float32_pol(float32 rFn,float32 rFm) { - return float32_arctan(float32_div(rFn,rFm)); + return float32_arctan(float32_div(rFn,rFm)); } #endif diff --git a/target-arm/op.c b/target-arm/op.c index 771f9c470..b28217318 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -1,6 +1,6 @@ /* * ARM micro operations - * + * * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2005 CodeSourcery, LLC * @@ -774,7 +774,7 @@ void OPPROTO op_addl_T0_T1_saturate(void) } else T0 = res; - + FORCE_RET(); } @@ -792,7 +792,7 @@ void OPPROTO op_subl_T0_T1_saturate(void) } else T0 = res; - + FORCE_RET(); } @@ -1127,7 +1127,7 @@ void OPPROTO op_vfp_msr(void) void OPPROTO op_vfp_mrrd(void) { CPU_DoubleU u; - + u.d = FT0d; T0 = u.l.lower; T1 = u.l.upper; @@ -1136,7 +1136,7 @@ void OPPROTO op_vfp_mrrd(void) void OPPROTO op_vfp_mdrr(void) { CPU_DoubleU u; - + u.l.lower = T0; u.l.upper = T1; FT0d = u.d; diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index af5c61d0b..c861bf7e4 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -1,6 +1,6 @@ /* * ARM helper routines - * + * * Copyright (c) 2005 CodeSourcery, LLC * * This library is free software; you can redistribute it and/or diff --git a/target-arm/op_iwmmxt.c b/target-arm/op_iwmmxt.c index 0639f3703..40ae10d29 100644 --- a/target-arm/op_iwmmxt.c +++ b/target-arm/op_iwmmxt.c @@ -1,6 +1,6 @@ /* * iwMMXt micro operations for XScale. - * + * * Copyright (c) 2007 OpenedHand, Ltd. * Written by Andrzej Zaborowski * @@ -146,7 +146,7 @@ void OPPROTO op_iwmmxt_muluw_M0_wRn(void) void OPPROTO op_iwmmxt_macsw_M0_wRn(void) { #define MACS(SHR) ( \ - EXTEND16((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff)) + EXTEND16((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff)) M0 = (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48)); #undef MACS } @@ -155,7 +155,7 @@ void OPPROTO op_iwmmxt_macuw_M0_wRn(void) { #define MACU(SHR) ( \ (uint32_t) ((M0 >> SHR) & 0xffff) * \ - (uint32_t) ((M1 >> SHR) & 0xffff)) + (uint32_t) ((M1 >> SHR) & 0xffff)) M0 = MACU(0) + MACU(16) + MACU(32) + MACU(48); #undef MACU } diff --git a/target-arm/op_template.h b/target-arm/op_template.h index fb2add15d..33d53c05a 100644 --- a/target-arm/op_template.h +++ b/target-arm/op_template.h @@ -1,7 +1,7 @@ /* * ARM micro operations (templates for various register related * operations) - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or diff --git a/target-arm/translate.c b/target-arm/translate.c index 590959c2f..a6647d4f7 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1,6 +1,6 @@ /* * ARM translation - * + * * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2005 CodeSourcery, LLC * Copyright (c) 2007 OpenedHand, Ltd. @@ -116,7 +116,7 @@ const uint8_t table_logic_cc[16] = { 1, /* bic */ 1, /* mvn */ }; - + static GenOpFunc1 *gen_shift_T1_im[4] = { gen_op_shll_T1_im, gen_op_shrl_T1_im, @@ -390,7 +390,7 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, int extra) { int val, rm; - + if (insn & (1 << 22)) { /* immediate */ val = (insn & 0xf) | ((insn >> 4) & 0xf0); @@ -1784,7 +1784,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) delta_m = 0; delta_d = 0; bank_mask = 0; - + if (veclen > 0) { if (dp) bank_mask = 0xc; @@ -2205,10 +2205,10 @@ static void gen_exception_return(DisasContext *s) static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; - + insn = ldl_code(s->pc); s->pc += 4; - + cond = insn >> 28; if (cond == 0xf){ /* Unconditional instructions. */ @@ -2403,7 +2403,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) (insn & 0x00000090) != 0x90) || ((insn & 0x0e000000) == (1 << 25))) { int set_cc, logic_cc, shiftop; - + op1 = (insn >> 21) & 0xf; set_cc = (insn >> 20) & 1; logic_cc = table_logic_cc[op1] & set_cc; @@ -2594,14 +2594,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_movl_T1_reg(s, rn); gen_op_addl_T0_T1(); } - if (insn & (1 << 20)) + if (insn & (1 << 20)) gen_op_logic_T0_cc(); gen_movl_reg_T0(s, rd); } else { /* 64 bit mul */ gen_movl_T0_reg(s, rs); gen_movl_T1_reg(s, rm); - if (insn & (1 << 22)) + if (insn & (1 << 22)) gen_op_imull_T0_T1(); else gen_op_mull_T0_T1(); @@ -2612,7 +2612,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_addq_lo_T0_T1(rn); gen_op_addq_lo_T0_T1(rd); } - if (insn & (1 << 20)) + if (insn & (1 << 20)) gen_op_logicq_cc(); gen_movl_reg_T0(s, rn); gen_movl_reg_T1(s, rd); @@ -2626,7 +2626,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } else { /* SWP instruction */ rm = (insn) & 0xf; - + gen_movl_T0_reg(s, rm); gen_movl_T1_reg(s, rn); if (insn & (1 << 22)) { @@ -2799,7 +2799,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } rn = (insn >> 16) & 0xf; gen_movl_T1_reg(s, rn); - + /* compute total size */ loaded_base = 0; n = 0; @@ -2897,7 +2897,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0xb: { int32_t offset; - + /* branch (and link) */ val = (int32_t)s->pc; if (insn & (1 << 24)) { @@ -3500,7 +3500,7 @@ static void disas_thumb_insn(DisasContext *s) val = (uint32_t)s->pc + 2; gen_op_movl_T1_im(val | 1); gen_movl_reg_T1(s, 14); - + val += offset << 1; if (insn & (1 << 12)) { /* bl */ @@ -3523,8 +3523,8 @@ undef: /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ -static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, int search_pc) { DisasContext dc1, *dc = &dc1; @@ -3532,10 +3532,10 @@ static inline int gen_intermediate_code_internal(CPUState *env, int j, lj; target_ulong pc_start; uint32_t next_page_start; - + /* generate intermediate code */ pc_start = tb->pc; - + dc->tb = tb; gen_opc_ptr = gen_opc_buf; @@ -3676,7 +3676,7 @@ static const char *cpu_mode_names[16] = { "usr", "fiq", "irq", "svc", "???", "???", "???", "abt", "???", "???", "???", "und", "???", "???", "???", "sys" }; -void cpu_dump_state(CPUState *env, FILE *f, +void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { @@ -3708,7 +3708,7 @@ void cpu_dump_state(CPUState *env, FILE *f, psr & (1 << 30) ? 'Z' : '-', psr & (1 << 29) ? 'C' : '-', psr & (1 << 28) ? 'V' : '-', - psr & CPSR_T ? 'T' : 'A', + psr & CPSR_T ? 'T' : 'A', cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); for (i = 0; i < 16; i++) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 6d764f535..6cf2c487b 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1,6 +1,6 @@ /* * i386 virtual CPU header - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -116,7 +116,7 @@ #define NT_MASK 0x00004000 #define RF_MASK 0x00010000 #define VM_MASK 0x00020000 -#define AC_MASK 0x00040000 +#define AC_MASK 0x00040000 #define VIF_MASK 0x00080000 #define VIP_MASK 0x00100000 #define ID_MASK 0x00200000 @@ -476,7 +476,7 @@ typedef struct CPUX86State { int i32; int64_t i64; } fp_convert; - + float_status sse_status; uint32_t mxcsr; XMMReg xmm_regs[CPU_NB_REGS]; @@ -504,7 +504,7 @@ typedef struct CPUX86State { uint32_t saved_esp; int native_fp_regs; /* if true, the FPU state is in the native CPU regs */ #endif - + /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; @@ -513,7 +513,7 @@ typedef struct CPUX86State { target_ulong exception_next_eip; target_ulong dr[8]; /* debug registers */ uint32_t smbase; - int interrupt_request; + int interrupt_request; int user_mode_only; /* user mode only simulation */ int old_exception; /* exception in flight */ @@ -531,7 +531,7 @@ typedef struct CPUX86State { uint32_t cpuid_model[12]; uint32_t cpuid_ext2_features; uint32_t cpuid_apic_id; - + #ifdef USE_KQEMU int kqemu_enabled; int last_io_time; @@ -550,15 +550,15 @@ void cpu_set_ferr(CPUX86State *s); /* this function must always be used to load data in the segment cache: it synchronizes the hflags with the segment cache values */ -static inline void cpu_x86_load_seg_cache(CPUX86State *env, +static inline void cpu_x86_load_seg_cache(CPUX86State *env, int seg_reg, unsigned int selector, target_ulong base, - unsigned int limit, + unsigned int limit, unsigned int flags) { SegmentCache *sc; unsigned int new_hflags; - + sc = &env->segs[seg_reg]; sc->selector = selector; sc->base = base; @@ -573,7 +573,7 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, /* long mode */ env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK; env->hflags &= ~(HF_ADDSEG_MASK); - } else + } else #endif { /* legacy / compatibility case */ @@ -587,7 +587,7 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, >> (DESC_B_SHIFT - HF_SS32_SHIFT); if (env->hflags & HF_CS64_MASK) { /* zero base assumed for DS, ES and SS in long mode */ - } else if (!(env->cr[0] & CR0_PE_MASK) || + } else if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK) || !(env->hflags & HF_CS32_MASK)) { /* XXX: try to avoid this test. The problem comes from the @@ -597,12 +597,12 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, translate-i386.c. */ new_hflags |= HF_ADDSEG_MASK; } else { - new_hflags |= ((env->segs[R_DS].base | + new_hflags |= ((env->segs[R_DS].base | env->segs[R_ES].base | - env->segs[R_SS].base) != 0) << + env->segs[R_SS].base) != 0) << HF_ADDSEG_SHIFT; } - env->hflags = (env->hflags & + env->hflags = (env->hflags & ~(HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags; } } @@ -630,7 +630,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -int cpu_x86_signal_handler(int host_signum, void *pinfo, +int cpu_x86_signal_handler(int host_signum, void *pinfo, void *puc); void cpu_x86_set_a20(CPUX86State *env, int a20_state); diff --git a/target-i386/exec.h b/target-i386/exec.h index f48462aaa..a3ab9b439 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -1,5 +1,5 @@ /* - * i386 execution defines + * i386 execution defines * * Copyright (c) 2003 Fabrice Bellard * @@ -162,17 +162,17 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr); -int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, +int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write, int is_user, int is_softmmu); -void tlb_fill(target_ulong addr, int is_write, int is_user, +void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); -void do_interrupt(int intno, int is_int, int error_code, +void do_interrupt(int intno, int is_int, int error_code, target_ulong next_eip, int is_hw); -void do_interrupt_user(int intno, int is_int, int error_code, +void do_interrupt_user(int intno, int is_int, int error_code, target_ulong next_eip); -void raise_interrupt(int intno, int is_int, int error_code, +void raise_interrupt(int intno, int is_int, int error_code, int next_eip_addend); void raise_exception_err(int exception_index, int error_code); void raise_exception(int exception_index); @@ -443,7 +443,7 @@ static inline CPU86_LDouble helper_fldt(target_ulong ptr) static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) { CPU86_LDoubleU temp; - + temp.d = f; stq(ptr, temp.l.lower); stw(ptr + 8, temp.l.upper); @@ -517,7 +517,7 @@ static inline void load_eflags(int eflags, int update_mask) { CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); DF = 1 - (2 * ((eflags >> 10) & 1)); - env->eflags = (env->eflags & ~update_mask) | + env->eflags = (env->eflags & ~update_mask) | (eflags & update_mask); } diff --git a/target-i386/helper.c b/target-i386/helper.c index 64c3a6132..447f4d891 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1,6 +1,6 @@ /* * i386 helpers - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -67,7 +67,7 @@ const uint8_t parity_table[256] = { /* modulo 17 table */ const uint8_t rclw_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, @@ -75,9 +75,9 @@ const uint8_t rclw_table[32] = { /* modulo 9 table */ const uint8_t rclb_table[32] = { - 0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 0, 1, 2, 3, 4, 5, + 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, }; @@ -91,7 +91,7 @@ const CPU86_LDouble f15rk[7] = 1.44269504088896340739L, /*l2e*/ 3.32192809488736234781L, /*l2t*/ }; - + /* thread support */ spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; @@ -126,7 +126,7 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, *e2_ptr = ldl_kernel(ptr + 4); return 0; } - + static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) { unsigned int limit; @@ -152,15 +152,15 @@ static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t static inline void load_seg_vm(int seg, int selector) { selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg, selector, + cpu_x86_load_seg_cache(env, seg, selector, (selector << 4), 0xffff, 0); } -static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, +static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, uint32_t *esp_ptr, int dpl) { int type, index, shift; - + #if 0 { int i; @@ -231,12 +231,12 @@ static void tss_load_seg(int seg_reg, int selector) } if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); - cpu_x86_load_seg_cache(env, seg_reg, selector, + cpu_x86_load_seg_cache(env, seg_reg, selector, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); } else { - if (seg_reg == R_SS || seg_reg == R_CS) + if (seg_reg == R_SS || seg_reg == R_CS) raise_exception_err(EXCP0A_TSS, selector & 0xfffc); } } @@ -246,7 +246,7 @@ static void tss_load_seg(int seg_reg, int selector) #define SWITCH_TSS_CALL 2 /* XXX: restore CPU state in registers (PowerPC case) */ -static void switch_tss(int tss_selector, +static void switch_tss(int tss_selector, uint32_t e1, uint32_t e2, int source, uint32_t next_eip) { @@ -290,7 +290,7 @@ static void switch_tss(int tss_selector, tss_limit_max = 43; tss_limit = get_seg_limit(e1, e2); tss_base = get_seg_base(e1, e2); - if ((tss_selector & 4) != 0 || + if ((tss_selector & 4) != 0 || tss_limit < tss_limit_max) raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; @@ -325,7 +325,7 @@ static void switch_tss(int tss_selector, new_segs[R_GS] = 0; new_trap = 0; } - + /* NOTE: we must avoid memory exceptions during the task switch, so we make dummy accesses before */ /* XXX: it can still fail in some cases, so a bigger hack is @@ -335,7 +335,7 @@ static void switch_tss(int tss_selector, v2 = ldub_kernel(env->tr.base + old_tss_limit_max); stb_kernel(env->tr.base, v1); stb_kernel(env->tr.base + old_tss_limit_max, v2); - + /* clear busy bit (it is restartable) */ if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { target_ulong ptr; @@ -348,7 +348,7 @@ static void switch_tss(int tss_selector, old_eflags = compute_eflags(); if (source == SWITCH_TSS_IRET) old_eflags &= ~NT_MASK; - + /* save the current state in the old TSS */ if (type & 8) { /* 32 bit */ @@ -379,7 +379,7 @@ static void switch_tss(int tss_selector, for(i = 0; i < 4; i++) stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); } - + /* now if an exception occurs, it will occurs in the next task context */ @@ -406,15 +406,15 @@ static void switch_tss(int tss_selector, env->tr.base = tss_base; env->tr.limit = tss_limit; env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; - + if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { cpu_x86_update_cr3(env, new_cr3); } - + /* load all registers without an exception, then reload them with possible exception */ env->eip = new_eip; - eflags_mask = TF_MASK | AC_MASK | ID_MASK | + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; if (!(type & 8)) eflags_mask &= 0xffff; @@ -429,7 +429,7 @@ static void switch_tss(int tss_selector, ESI = new_regs[6]; EDI = new_regs[7]; if (new_eflags & VM_MASK) { - for(i = 0; i < 6; i++) + for(i = 0; i < 6; i++) load_seg_vm(i, new_segs[i]); /* in vm86, CPL is always 3 */ cpu_x86_set_cpl(env, 3); @@ -440,7 +440,7 @@ static void switch_tss(int tss_selector, for(i = 0; i < 6; i++) cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); } - + env->ldt.selector = new_ldt & ~4; env->ldt.base = 0; env->ldt.limit = 0; @@ -464,7 +464,7 @@ static void switch_tss(int tss_selector, raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); load_seg_cache_raw_dt(&env->ldt, e1, e2); } - + /* load the segments */ if (!(new_eflags & VM_MASK)) { tss_load_seg(R_CS, new_segs[R_CS]); @@ -474,7 +474,7 @@ static void switch_tss(int tss_selector, tss_load_seg(R_FS, new_segs[R_FS]); tss_load_seg(R_GS, new_segs[R_GS]); } - + /* check that EIP is in the CS segment limits */ if (new_eip > env->segs[R_CS].limit) { /* XXX: different exception if CALL ? */ @@ -486,7 +486,7 @@ static void switch_tss(int tss_selector, static inline void check_io(int addr, int size) { int io_offset, val, mask; - + /* TSS must be a valid 32 bit one */ if (!(env->tr.flags & DESC_P_MASK) || ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || @@ -760,7 +760,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, PUSHW(ssp, esp, sp_mask, error_code); } } - + if (new_stack) { if (env->eflags & VM_MASK) { cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); @@ -769,13 +769,13 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0); } ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, + cpu_x86_load_seg_cache(env, R_SS, ss, ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); } SET_ESP(esp, sp_mask); selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, + cpu_x86_load_seg_cache(env, R_CS, selector, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); @@ -806,9 +806,9 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, static inline target_ulong get_rsp_from_tss(int level) { int index; - + #if 0 - printf("TR: base=" TARGET_FMT_lx " limit=%x\n", + printf("TR: base=" TARGET_FMT_lx " limit=%x\n", env->tr.base, env->tr.limit); #endif @@ -926,7 +926,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, if (has_error_code) { PUSHQ(esp, error_code); } - + if (new_stack) { ss = 0 | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); @@ -934,7 +934,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, ESP = esp; selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, + cpu_x86_load_seg_cache(env, R_CS, selector, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); @@ -963,16 +963,16 @@ void helper_syscall(int next_eip_addend) ECX = env->eip + next_eip_addend; env->regs[11] = compute_eflags(); - + code64 = env->hflags & HF_CS64_MASK; cpu_x86_set_cpl(env, 0); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | @@ -982,18 +982,18 @@ void helper_syscall(int next_eip_addend) env->eip = env->lstar; else env->eip = env->cstar; - } else + } else #endif { ECX = (uint32_t)(env->eip + next_eip_addend); - + cpu_x86_set_cpl(env, 0); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | @@ -1018,39 +1018,39 @@ void helper_sysret(int dflag) #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { if (dflag == 2) { - cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, + 0, 0xffffffff, DESC_G_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); env->eip = ECX; } else { - cpu_x86_load_seg_cache(env, R_CS, selector | 3, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, selector | 3, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); env->eip = (uint32_t)ECX; } - cpu_x86_load_seg_cache(env, R_SS, selector + 8, + cpu_x86_load_seg_cache(env, R_SS, selector + 8, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); - load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | + load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); cpu_x86_set_cpl(env, 3); - } else + } else #endif { - cpu_x86_load_seg_cache(env, R_CS, selector | 3, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, selector | 3, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); env->eip = (uint32_t)ECX; - cpu_x86_load_seg_cache(env, R_SS, selector + 8, + cpu_x86_load_seg_cache(env, R_SS, selector + 8, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | @@ -1096,7 +1096,7 @@ static void do_interrupt_real(int intno, int is_int, int error_code, PUSHW(ssp, esp, 0xffff, compute_eflags()); PUSHW(ssp, esp, 0xffff, old_cs); PUSHW(ssp, esp, 0xffff, old_eip); - + /* update processor state */ ESP = (ESP & ~0xffff) | (esp & 0xffff); env->eip = offset; @@ -1106,7 +1106,7 @@ static void do_interrupt_real(int intno, int is_int, int error_code, } /* fake user mode interrupt */ -void do_interrupt_user(int intno, int is_int, int error_code, +void do_interrupt_user(int intno, int is_int, int error_code, target_ulong next_eip) { SegmentCache *dt; @@ -1117,7 +1117,7 @@ void do_interrupt_user(int intno, int is_int, int error_code, dt = &env->idt; ptr = dt->base + (intno * 8); e2 = ldl_kernel(ptr + 4); - + dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ @@ -1134,9 +1134,9 @@ void do_interrupt_user(int intno, int is_int, int error_code, /* * Begin execution of an interruption. is_int is TRUE if coming from * the int instruction. next_eip is the EIP value AFTER the interrupt - * instruction. It is only relevant if is_int is TRUE. + * instruction. It is only relevant if is_int is TRUE. */ -void do_interrupt(int intno, int is_int, int error_code, +void do_interrupt(int intno, int is_int, int error_code, target_ulong next_eip, int is_hw) { if (loglevel & CPU_LOG_INT) { @@ -1222,9 +1222,9 @@ int check_exception(int intno, int *error_code) * Signal an interruption. It is executed in the main CPU loop. * is_int is TRUE if coming from the int instruction. next_eip is the * EIP value AFTER the interrupt instruction. It is only relevant if - * is_int is TRUE. + * is_int is TRUE. */ -void raise_interrupt(int intno, int is_int, int error_code, +void raise_interrupt(int intno, int is_int, int error_code, int next_eip_addend) { if (!is_int) @@ -1263,7 +1263,7 @@ void raise_exception(int exception_index) /* SMM support */ -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) void do_smm_enter(void) { @@ -1296,7 +1296,7 @@ void do_smm_enter(void) cpu_smm_update(env); sm_state = env->smbase + 0x8000; - + #ifdef TARGET_X86_64 for(i = 0; i < 6; i++) { dt = &env->segs[i]; @@ -1314,7 +1314,7 @@ void do_smm_enter(void) stq_phys(sm_state + 0x7e78, env->ldt.base); stl_phys(sm_state + 0x7e74, env->ldt.limit); stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); - + stq_phys(sm_state + 0x7e88, env->idt.base); stl_phys(sm_state + 0x7e84, env->idt.limit); @@ -1322,7 +1322,7 @@ void do_smm_enter(void) stq_phys(sm_state + 0x7e98, env->tr.base); stl_phys(sm_state + 0x7e94, env->tr.limit); stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); - + stq_phys(sm_state + 0x7ed0, env->efer); stq_phys(sm_state + 0x7ff8, EAX); @@ -1333,7 +1333,7 @@ void do_smm_enter(void) stq_phys(sm_state + 0x7fd0, EBP); stq_phys(sm_state + 0x7fc8, ESI); stq_phys(sm_state + 0x7fc0, EDI); - for(i = 8; i < 16; i++) + for(i = 8; i < 16; i++) stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]); stq_phys(sm_state + 0x7f78, env->eip); stl_phys(sm_state + 0x7f70, compute_eflags()); @@ -1361,17 +1361,17 @@ void do_smm_enter(void) stl_phys(sm_state + 0x7fd0, EAX); stl_phys(sm_state + 0x7fcc, env->dr[6]); stl_phys(sm_state + 0x7fc8, env->dr[7]); - + stl_phys(sm_state + 0x7fc4, env->tr.selector); stl_phys(sm_state + 0x7f64, env->tr.base); stl_phys(sm_state + 0x7f60, env->tr.limit); stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); - + stl_phys(sm_state + 0x7fc0, env->ldt.selector); stl_phys(sm_state + 0x7f80, env->ldt.base); stl_phys(sm_state + 0x7f7c, env->ldt.limit); stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); - + stl_phys(sm_state + 0x7f74, env->gdt.base); stl_phys(sm_state + 0x7f70, env->gdt.limit); @@ -1409,8 +1409,8 @@ void do_smm_enter(void) cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0); cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0); cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); - - cpu_x86_update_cr0(env, + + cpu_x86_update_cr0(env, env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); cpu_x86_update_cr4(env, 0); env->dr[7] = 0x00000400; @@ -1433,7 +1433,7 @@ void helper_rsm(void) for(i = 0; i < 6; i++) { offset = 0x7e00 + i * 16; - cpu_x86_load_seg_cache(env, i, + cpu_x86_load_seg_cache(env, i, lduw_phys(sm_state + offset), ldq_phys(sm_state + offset + 8), ldl_phys(sm_state + offset + 4), @@ -1447,7 +1447,7 @@ void helper_rsm(void) env->ldt.base = ldq_phys(sm_state + 0x7e78); env->ldt.limit = ldl_phys(sm_state + 0x7e74); env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8; - + env->idt.base = ldq_phys(sm_state + 0x7e88); env->idt.limit = ldl_phys(sm_state + 0x7e84); @@ -1455,7 +1455,7 @@ void helper_rsm(void) env->tr.base = ldq_phys(sm_state + 0x7e98); env->tr.limit = ldl_phys(sm_state + 0x7e94); env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8; - + EAX = ldq_phys(sm_state + 0x7ff8); ECX = ldq_phys(sm_state + 0x7ff0); EDX = ldq_phys(sm_state + 0x7fe8); @@ -1464,10 +1464,10 @@ void helper_rsm(void) EBP = ldq_phys(sm_state + 0x7fd0); ESI = ldq_phys(sm_state + 0x7fc8); EDI = ldq_phys(sm_state + 0x7fc0); - for(i = 8; i < 16; i++) + for(i = 8; i < 16; i++) env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8); env->eip = ldq_phys(sm_state + 0x7f78); - load_eflags(ldl_phys(sm_state + 0x7f70), + load_eflags(ldl_phys(sm_state + 0x7f70), ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); env->dr[6] = ldl_phys(sm_state + 0x7f68); env->dr[7] = ldl_phys(sm_state + 0x7f60); @@ -1483,7 +1483,7 @@ void helper_rsm(void) #else cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc)); cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8)); - load_eflags(ldl_phys(sm_state + 0x7ff4), + load_eflags(ldl_phys(sm_state + 0x7ff4), ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); env->eip = ldl_phys(sm_state + 0x7ff0); EDI = ldl_phys(sm_state + 0x7fec); @@ -1496,17 +1496,17 @@ void helper_rsm(void) EAX = ldl_phys(sm_state + 0x7fd0); env->dr[6] = ldl_phys(sm_state + 0x7fcc); env->dr[7] = ldl_phys(sm_state + 0x7fc8); - + env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff; env->tr.base = ldl_phys(sm_state + 0x7f64); env->tr.limit = ldl_phys(sm_state + 0x7f60); env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8; - + env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff; env->ldt.base = ldl_phys(sm_state + 0x7f80); env->ldt.limit = ldl_phys(sm_state + 0x7f7c); env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8; - + env->gdt.base = ldl_phys(sm_state + 0x7f74); env->gdt.limit = ldl_phys(sm_state + 0x7f70); @@ -1518,7 +1518,7 @@ void helper_rsm(void) offset = 0x7f84 + i * 12; else offset = 0x7f2c + (i - 3) * 12; - cpu_x86_load_seg_cache(env, i, + cpu_x86_load_seg_cache(env, i, ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff, ldl_phys(sm_state + offset + 8), ldl_phys(sm_state + offset + 4), @@ -1564,7 +1564,7 @@ void helper_divl_EAX_T0(void) { unsigned int den, r; uint64_t num, q; - + num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); den = T0; if (den == 0) { @@ -1586,7 +1586,7 @@ void helper_idivl_EAX_T0(void) { int den, r; int64_t num, q; - + num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); den = T0; if (den == 0) { @@ -1632,16 +1632,16 @@ void helper_cpuid(void) { uint32_t index; index = (uint32_t)EAX; - + /* test if maximum index reached */ if (index & 0x80000000) { - if (index > env->cpuid_xlevel) + if (index > env->cpuid_xlevel) index = env->cpuid_level; } else { - if (index > env->cpuid_level) + if (index > env->cpuid_level) index = env->cpuid_level; } - + switch(index) { case 0: EAX = env->cpuid_level; @@ -1783,7 +1783,7 @@ void helper_lldt_T0(void) uint32_t e1, e2; int index, entry_limit; target_ulong ptr; - + selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) { /* XXX: NULL selector case: invalid LDT */ @@ -1798,7 +1798,7 @@ void helper_lldt_T0(void) if (env->hflags & HF_LMA_MASK) entry_limit = 15; else -#endif +#endif entry_limit = 7; if ((index + entry_limit) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); @@ -1831,7 +1831,7 @@ void helper_ltr_T0(void) uint32_t e1, e2; int index, type, entry_limit; target_ulong ptr; - + selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) { /* NULL selector case: invalid TR */ @@ -1847,7 +1847,7 @@ void helper_ltr_T0(void) if (env->hflags & HF_LMA_MASK) entry_limit = 15; else -#endif +#endif entry_limit = 7; if ((index + entry_limit) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); @@ -1855,7 +1855,7 @@ void helper_ltr_T0(void) e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); type = (e2 >> DESC_TYPE_SHIFT) & 0xf; - if ((e2 & DESC_S_MASK) || + if ((e2 & DESC_S_MASK) || (type != 1 && type != 9)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) @@ -1869,7 +1869,7 @@ void helper_ltr_T0(void) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); load_seg_cache_raw_dt(&env->tr, e1, e2); env->tr.base |= (target_ulong)e3 << 32; - } else + } else #endif { load_seg_cache_raw_dt(&env->tr, e1, e2); @@ -1901,7 +1901,7 @@ void load_seg(int seg_reg, int selector) raise_exception_err(EXCP0D_GPF, 0); cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); } else { - + if (selector & 0x4) dt = &env->ldt; else @@ -1912,7 +1912,7 @@ void load_seg(int seg_reg, int selector) ptr = dt->base + index; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); - + if (!(e2 & DESC_S_MASK)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); rpl = selector & 3; @@ -1927,10 +1927,10 @@ void load_seg(int seg_reg, int selector) /* must be readable segment */ if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - + if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { /* if not conforming code, test rights */ - if (dpl < cpl || dpl < rpl) + if (dpl < cpl || dpl < rpl) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); } } @@ -1948,12 +1948,12 @@ void load_seg(int seg_reg, int selector) stl_kernel(ptr + 4, e2); } - cpu_x86_load_seg_cache(env, seg_reg, selector, + cpu_x86_load_seg_cache(env, seg_reg, selector, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); #if 0 - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", + fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", selector, (unsigned long)sc->base, sc->limit, sc->flags); #endif } @@ -1965,7 +1965,7 @@ void helper_ljmp_protected_T0_T1(int next_eip_addend) int new_cs, gate_cs, type; uint32_t e1, e2, cpl, dpl, rpl, limit; target_ulong new_eip, next_eip; - + new_cs = T0; new_eip = T1; if ((new_cs & 0xfffc) == 0) @@ -1992,7 +1992,7 @@ void helper_ljmp_protected_T0_T1(int next_eip_addend) if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); limit = get_seg_limit(e1, e2); - if (new_eip > limit && + if (new_eip > limit && !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, @@ -2028,10 +2028,10 @@ void helper_ljmp_protected_T0_T1(int next_eip_addend) raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; /* must be code segment */ - if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != + if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != (DESC_S_MASK | DESC_CS_MASK))) raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); - if (((e2 & DESC_C_MASK) && (dpl > cpl)) || + if (((e2 & DESC_C_MASK) && (dpl > cpl)) || (!(e2 & DESC_C_MASK) && (dpl != cpl))) raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); if (!(e2 & DESC_P_MASK)) @@ -2084,7 +2084,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; uint32_t val, limit, old_sp_mask; target_ulong ssp, old_ssp, next_eip, new_eip; - + new_cs = T0; new_eip = T1; next_eip = env->eip + next_eip_addend; @@ -2135,10 +2135,10 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) /* from this point, not restartable */ ESP = rsp; cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, - get_seg_base(e1, e2), + get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); EIP = new_eip; - } else + } else #endif { sp = ESP; @@ -2151,7 +2151,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); PUSHW(ssp, sp, sp_mask, next_eip); } - + limit = get_seg_limit(e1, e2); if (new_eip > limit) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -2210,7 +2210,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) get_ss_esp_from_tss(&ss, &sp, dpl); #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_PCALL) - fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", + fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", ss, sp, param_count, ESP); #endif if ((ss & 0xfffc) == 0) @@ -2228,12 +2228,12 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - + // push_size = ((param_count * 2) + 8) << shift; old_sp_mask = get_sp_mask(env->segs[R_SS].flags); old_ssp = env->segs[R_SS].base; - + sp_mask = get_sp_mask(ss_e2); ssp = get_seg_base(ss_e1, ss_e2); if (shift) { @@ -2273,14 +2273,14 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) if (new_stack) { ss = (ss & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_SS, ss, + cpu_x86_load_seg_cache(env, R_SS, ss, ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); } selector = (selector & ~3) | dpl; - cpu_x86_load_seg_cache(env, R_CS, selector, + cpu_x86_load_seg_cache(env, R_CS, selector, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); @@ -2338,7 +2338,7 @@ static inline void validate_seg(int seg_reg, int cpl) /* XXX: on x86_64, we do not want to nullify FS and GS because they may still contain a valid base. I would be interested to know how a real x86_64 CPU behaves */ - if ((seg_reg == R_FS || seg_reg == R_GS) && + if ((seg_reg == R_FS || seg_reg == R_GS) && (env->segs[seg_reg].selector & 0xfffc) == 0) return; @@ -2360,7 +2360,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) uint32_t e1, e2, ss_e1, ss_e2; int cpl, dpl, rpl, eflags_mask, iopl; target_ulong ssp, sp, new_eip, new_esp, sp_mask; - + #ifdef TARGET_X86_64 if (shift == 2) sp_mask = -1; @@ -2412,7 +2412,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) !(e2 & DESC_CS_MASK)) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); cpl = env->hflags & HF_CPL_MASK; - rpl = new_cs & 3; + rpl = new_cs & 3; if (rpl < cpl) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; @@ -2425,12 +2425,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) } if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - + sp += addend; - if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || + if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || ((env->hflags & HF_CS64_MASK) && !is_iret))) { /* return to same priledge level */ - cpu_x86_load_seg_cache(env, R_CS, new_cs, + cpu_x86_load_seg_cache(env, R_CS, new_cs, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); @@ -2464,13 +2464,13 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) /* NULL ss is allowed in long mode if cpl != 3*/ /* XXX: test CS64 ? */ if ((env->hflags & HF_LMA_MASK) && rpl != 3) { - cpu_x86_load_seg_cache(env, R_SS, new_ss, + cpu_x86_load_seg_cache(env, R_SS, new_ss, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */ - } else + } else #endif { raise_exception_err(EXCP0D_GPF, 0); @@ -2489,13 +2489,13 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); - cpu_x86_load_seg_cache(env, R_SS, new_ss, + cpu_x86_load_seg_cache(env, R_SS, new_ss, get_seg_base(ss_e1, ss_e2), get_seg_limit(ss_e1, ss_e2), ss_e2); } - cpu_x86_load_seg_cache(env, R_CS, new_cs, + cpu_x86_load_seg_cache(env, R_CS, new_cs, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); @@ -2539,9 +2539,9 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) POPL(ssp, sp, sp_mask, new_ds); POPL(ssp, sp, sp_mask, new_fs); POPL(ssp, sp, sp_mask, new_gs); - + /* modify processor state */ - load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | + load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); load_seg_vm(R_CS, new_cs & 0xffff); cpu_x86_set_cpl(env, 3); @@ -2559,7 +2559,7 @@ void helper_iret_protected(int shift, int next_eip) { int tss_selector, type; uint32_t e1, e2; - + /* specific case for TSS */ if (env->eflags & NT_MASK) { #ifdef TARGET_X86_64 @@ -2606,12 +2606,12 @@ void helper_sysenter(void) } env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); cpu_x86_set_cpl(env, 0); - cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, + cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | @@ -2629,12 +2629,12 @@ void helper_sysexit(void) raise_exception_err(EXCP0D_GPF, 0); } cpu_x86_set_cpl(env, 3); - cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, - 0, 0xffffffff, + cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, + 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, + cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | @@ -2651,7 +2651,7 @@ void helper_sysexit(void) void helper_movl_crN_T0(int reg) { -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) switch(reg) { case 0: cpu_x86_update_cr0(env, T0); @@ -2695,7 +2695,7 @@ void helper_rdtsc(void) EDX = (uint32_t)(val >> 32); } -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) void helper_wrmsr(void) { } @@ -2735,7 +2735,7 @@ void helper_wrmsr(void) update_mask |= MSR_EFER_FFXSR; if (env->cpuid_ext2_features & CPUID_EXT2_NX) update_mask |= MSR_EFER_NXE; - env->efer = (env->efer & ~update_mask) | + env->efer = (env->efer & ~update_mask) | (val & update_mask); } break; @@ -2767,7 +2767,7 @@ void helper_wrmsr(void) #endif default: /* XXX: exception ? */ - break; + break; } } @@ -2819,7 +2819,7 @@ void helper_rdmsr(void) default: /* XXX: exception ? */ val = 0; - break; + break; } EAX = (uint32_t)(val); EDX = (uint32_t)(val >> 32); @@ -3006,7 +3006,7 @@ void fpu_set_exception(int mask) CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b) { - if (b == 0.0) + if (b == 0.0) fpu_set_exception(FPUS_ZE); return a / b; } @@ -3015,8 +3015,8 @@ void fpu_raise_exception(void) { if (env->cr[0] & CR0_NE_MASK) { raise_exception(EXCP10_COPR); - } -#if !defined(CONFIG_USER_ONLY) + } +#if !defined(CONFIG_USER_ONLY) else { cpu_set_ferr(env); } @@ -3080,13 +3080,13 @@ void helper_f2xm1(void) void helper_fyl2x(void) { CPU86_LDouble fptemp; - + fptemp = ST0; if (fptemp>0.0){ fptemp = log(fptemp)/log(2.0); /* log2(ST) */ ST1 *= fptemp; fpop(); - } else { + } else { env->fpus &= (~0x4700); env->fpus |= 0x400; } @@ -3250,7 +3250,7 @@ void helper_fyl2xp1(void) fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ ST1 *= fptemp; fpop(); - } else { + } else { env->fpus &= (~0x4700); env->fpus |= 0x400; } @@ -3261,7 +3261,7 @@ void helper_fsqrt(void) CPU86_LDouble fptemp; fptemp = ST0; - if (fptemp<0.0) { + if (fptemp<0.0) { env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ env->fpus |= 0x400; } @@ -3291,7 +3291,7 @@ void helper_frndint(void) void helper_fscale(void) { - ST0 = ldexp (ST0, (int)(ST1)); + ST0 = ldexp (ST0, (int)(ST1)); } void helper_fsin(void) @@ -3490,7 +3490,7 @@ void helper_fxsave(target_ulong ptr, int data64) helper_fstt(tmp, addr); addr += 16; } - + if (env->cr[4] & CR4_OSFXSR_MASK) { /* XXX: finish it */ stl(ptr + 0x18, env->mxcsr); /* mxcsr */ @@ -3823,7 +3823,7 @@ void update_fp_status(void) #endif } -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu #define GETPC() (__builtin_return_address(0)) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 327d54bbe..8b61cf874 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -1,6 +1,6 @@ /* * i386 helpers (without register variable usage) - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -75,7 +75,7 @@ CPUX86State *cpu_x86_init(void) ldt.seg_not_present = 0; ldt.useable = 1; modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - + asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); } #endif @@ -173,19 +173,19 @@ void cpu_reset(CPUX86State *env) env->ldt.flags = DESC_P_MASK; env->tr.limit = 0xffff; env->tr.flags = DESC_P_MASK; - - cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0); + + cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0); cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, 0); cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, 0); cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, 0); cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, 0); cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0); - + env->eip = 0xfff0; env->regs[R_EDX] = 0x600; /* indicate P6 processor */ - + env->eflags = 0x2; - + /* FPU init */ for(i = 0;i < 8; i++) env->fptags[i] = 1; @@ -257,7 +257,7 @@ static const char *cc_op_str[] = { "SARQ", }; -void cpu_dump_state(CPUState *env, FILE *f, +void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { @@ -268,28 +268,28 @@ void cpu_dump_state(CPUState *env, FILE *f, eflags = env->eflags; #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { - cpu_fprintf(f, + cpu_fprintf(f, "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n" "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP], - env->regs[R_ESP], - env->regs[8], - env->regs[9], - env->regs[10], - env->regs[11], - env->regs[12], - env->regs[13], - env->regs[14], - env->regs[15], + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP], + env->regs[R_ESP], + env->regs[8], + env->regs[9], + env->regs[10], + env->regs[11], + env->regs[12], + env->regs[13], + env->regs[14], + env->regs[15], env->eip, eflags, eflags & DF_MASK ? 'D' : '-', eflags & CC_O ? 'O' : '-', @@ -298,25 +298,25 @@ void cpu_dump_state(CPUState *env, FILE *f, eflags & CC_A ? 'A' : '-', eflags & CC_P ? 'P' : '-', eflags & CC_C ? 'C' : '-', - env->hflags & HF_CPL_MASK, + env->hflags & HF_CPL_MASK, (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, (env->a20_mask >> 20) & 1, (env->hflags >> HF_SMM_SHIFT) & 1, (env->hflags >> HF_HALTED_SHIFT) & 1); - } else + } else #endif { cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", - (uint32_t)env->regs[R_EAX], - (uint32_t)env->regs[R_EBX], - (uint32_t)env->regs[R_ECX], - (uint32_t)env->regs[R_EDX], - (uint32_t)env->regs[R_ESI], - (uint32_t)env->regs[R_EDI], - (uint32_t)env->regs[R_EBP], - (uint32_t)env->regs[R_ESP], + (uint32_t)env->regs[R_EAX], + (uint32_t)env->regs[R_EBX], + (uint32_t)env->regs[R_ECX], + (uint32_t)env->regs[R_EDX], + (uint32_t)env->regs[R_ESI], + (uint32_t)env->regs[R_EDI], + (uint32_t)env->regs[R_EBP], + (uint32_t)env->regs[R_ESP], (uint32_t)env->eip, eflags, eflags & DF_MASK ? 'D' : '-', eflags & CC_O ? 'O' : '-', @@ -325,7 +325,7 @@ void cpu_dump_state(CPUState *env, FILE *f, eflags & CC_A ? 'A' : '-', eflags & CC_P ? 'P' : '-', eflags & CC_C ? 'C' : '-', - env->hflags & HF_CPL_MASK, + env->hflags & HF_CPL_MASK, (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, (env->a20_mask >> 20) & 1, (env->hflags >> HF_SMM_SHIFT) & 1, @@ -358,9 +358,9 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n", env->idt.base, env->idt.limit); cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n", - (uint32_t)env->cr[0], - env->cr[2], - env->cr[3], + (uint32_t)env->cr[0], + env->cr[2], + env->cr[3], (uint32_t)env->cr[4]); } else #endif @@ -389,9 +389,9 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "IDT= %08x %08x\n", (uint32_t)env->idt.base, env->idt.limit); cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n", - (uint32_t)env->cr[0], - (uint32_t)env->cr[2], - (uint32_t)env->cr[3], + (uint32_t)env->cr[0], + (uint32_t)env->cr[2], + (uint32_t)env->cr[3], (uint32_t)env->cr[4]); } if (flags & X86_DUMP_CCOP) { @@ -402,13 +402,13 @@ void cpu_dump_state(CPUState *env, FILE *f, #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n", - env->cc_src, env->cc_dst, + env->cc_src, env->cc_dst, cc_op_name); - } else + } else #endif { cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", - (uint32_t)env->cc_src, (uint32_t)env->cc_dst, + (uint32_t)env->cc_src, (uint32_t)env->cc_dst, cc_op_name); } } @@ -445,13 +445,13 @@ void cpu_dump_state(CPUState *env, FILE *f, else cpu_fprintf(f, " "); } - if (env->hflags & HF_CS64_MASK) + if (env->hflags & HF_CS64_MASK) nb = 16; else nb = 8; for(i=0;ixmm_regs[i].XMM_L(3), env->xmm_regs[i].XMM_L(2), env->xmm_regs[i].XMM_L(1), @@ -516,7 +516,7 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) } #endif env->cr[0] = new_cr0 | CR0_ET_MASK; - + /* update PE flag in hidden flags */ pe_state = (env->cr[0] & CR0_PE_MASK); env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); @@ -566,9 +566,9 @@ void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr) tlb_flush_page(env, addr); } -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) -int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, +int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write, int is_user, int is_softmmu) { /* user mode only emulation */ @@ -590,12 +590,12 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) #define PHYS_ADDR_MASK 0xfffff000 /* return value: - -1 = cannot handle fault - 0 = nothing more to do + -1 = cannot handle fault + 0 = nothing more to do 1 = generate PF fault 2 = soft MMU activation required for this block */ -int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, +int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write1, int is_user, int is_softmmu) { uint64_t ptep, pte; @@ -603,13 +603,13 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int error_code, is_dirty, prot, page_size, ret, is_write; unsigned long paddr, page_offset; target_ulong vaddr, virt_addr; - + #if defined(DEBUG_MMU) - printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", + printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", addr, is_write1, is_user, env->eip); #endif is_write = is_write1 & 1; - + if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr; virt_addr = addr & TARGET_PAGE_MASK; @@ -635,8 +635,8 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, env->exception_index = EXCP0D_GPF; return 1; } - - pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & + + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; pml4e = ldq_phys(pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { @@ -652,7 +652,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, stl_phys_notdirty(pml4e_addr, pml4e); } ptep = pml4e ^ PG_NX_MASK; - pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) & + pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; pdpe = ldq_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { @@ -672,7 +672,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, #endif { /* XXX: load them when cr3 is loaded ? */ - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & env->a20_mask; pdpe = ldq_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { @@ -706,8 +706,8 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, if (is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } else { - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } is_dirty = is_write && !(pde & PG_DIRTY_MASK); @@ -718,7 +718,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, stl_phys_notdirty(pde_addr, pde); } /* align to page_size */ - pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff); + pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff); virt_addr = addr & ~(page_size - 1); } else { /* 4 KB page */ @@ -741,7 +741,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, ptep &= pte ^ PG_NX_MASK; ptep ^= PG_NX_MASK; if ((ptep & PG_NX_MASK) && is_write1 == 2) - goto do_fault_protect; + goto do_fault_protect; if (is_user) { if (!(ptep & PG_USER_MASK)) goto do_fault_protect; @@ -749,7 +749,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, goto do_fault_protect; } else { if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) + is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } is_dirty = is_write && !(pte & PG_DIRTY_MASK); @@ -767,7 +767,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, uint32_t pde; /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask; pde = ldl_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) { @@ -783,8 +783,8 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, if (is_write && !(pde & PG_RW_MASK)) goto do_fault_protect; } else { - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(pde & PG_RW_MASK)) + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(pde & PG_RW_MASK)) goto do_fault_protect; } is_dirty = is_write && !(pde & PG_DIRTY_MASK); @@ -794,7 +794,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, pde |= PG_DIRTY_MASK; stl_phys_notdirty(pde_addr, pde); } - + pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ ptep = pte; virt_addr = addr & ~(page_size - 1); @@ -805,7 +805,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, } /* page directory entry */ - pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; pte = ldl_phys(pte_addr); if (!(pte & PG_PRESENT_MASK)) { @@ -821,7 +821,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, goto do_fault_protect; } else { if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) + is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } is_dirty = is_write && !(pte & PG_DIRTY_MASK); @@ -859,7 +859,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); paddr = (pte & TARGET_PAGE_MASK) + page_offset; vaddr = virt_addr + page_offset; - + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; do_fault_protect: @@ -869,8 +869,8 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, error_code |= (is_write << PG_ERROR_W_BIT); if (is_user) error_code |= PG_ERROR_U_MASK; - if (is_write1 == 2 && - (env->efer & MSR_EFER_NXE) && + if (is_write1 == 2 && + (env->efer & MSR_EFER_NXE) && (env->cr[4] & CR4_PAE_MASK)) error_code |= PG_ERROR_I_D_MASK; env->error_code = error_code; @@ -897,22 +897,22 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) sext = (int64_t)addr >> 47; if (sext != 0 && sext != -1) return -1; - - pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & + + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; pml4e = ldl_phys(pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) return -1; - - pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & + + pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; pdpe = ldl_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) return -1; - } else + } else #endif { - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & env->a20_mask; pdpe = ldl_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) @@ -944,7 +944,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) /* page directory entry */ pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask; pde = ldl_phys(pde_addr); - if (!(pde & PG_PRESENT_MASK)) + if (!(pde & PG_PRESENT_MASK)) return -1; if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { pte = pde & ~0x003ff000; /* align to 4MB */ @@ -987,7 +987,7 @@ void restore_native_fp_state(CPUState *env) { int fptag, i, j; struct fpstate fp1, *fp = &fp1; - + fp->fpuc = env->fpuc; fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; fptag = 0; @@ -1008,7 +1008,7 @@ void restore_native_fp_state(CPUState *env) asm volatile ("frstor %0" : "=m" (*fp)); env->native_fp_regs = 1; } - + void save_native_fp_state(CPUState *env) { int fptag, i, j; diff --git a/target-i386/op.c b/target-i386/op.c index ea8aec6b5..a790aebb1 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1,6 +1,6 @@ /* * i386 micro operations - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -521,7 +521,7 @@ typedef union UREG64 { __p.l.v1 = PARAM1;\ __p.l.v0 = PARAM2;\ __p.q;\ -}) +}) void OPPROTO op_movq_T0_im64(void) { @@ -1149,7 +1149,7 @@ void OPPROTO op_movl_seg_T0_vm(void) { int selector; SegmentCache *sc; - + selector = T0 & 0xffff; /* env->segs[] access */ sc = (SegmentCache *)((char *)env + PARAM1); @@ -1193,14 +1193,14 @@ void OPPROTO op_arpl(void) } FORCE_RET(); } - + void OPPROTO op_arpl_update(void) { int eflags; eflags = cc_table[CC_OP].compute_all(); CC_SRC = (eflags & ~CC_Z) | T1; } - + /* T0: segment, T1:eip */ void OPPROTO op_ljmp_protected_T0_T1(void) { @@ -1248,7 +1248,7 @@ void OPPROTO op_movl_crN_T0(void) helper_movl_crN_T0(PARAM1); } -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) void OPPROTO op_movtl_T0_cr8(void) { T0 = cpu_get_apic_tpr(env); @@ -1591,23 +1591,23 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, - + [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb }, [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw }, [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl }, - + [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, - + [CC_OP_INCB] = { compute_all_incb, compute_c_incl }, [CC_OP_INCW] = { compute_all_incw, compute_c_incl }, [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, - + [CC_OP_DECB] = { compute_all_decb, compute_c_incl }, [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, - + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, @@ -1624,11 +1624,11 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq }, [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq }, - + [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq }, - + [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq }, - + [CC_OP_INCQ] = { compute_all_incq, compute_c_incl }, [CC_OP_DECQ] = { compute_all_decq, compute_c_incl }, diff --git a/target-i386/opreg_template.h b/target-i386/opreg_template.h index 648063650..eae4139d1 100644 --- a/target-i386/opreg_template.h +++ b/target-i386/opreg_template.h @@ -1,7 +1,7 @@ /* * i386 micro operations (templates for various register related * operations) - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index df1527c55..b6ca9a3d7 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -1,6 +1,6 @@ /* * MMX/SSE/SSE2/PNI support - * + * * Copyright (c) 2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -1213,7 +1213,7 @@ void OPPROTO glue(op_pinsrw, SUFFIX) (void) { Reg *d = (Reg *)((char *)env + PARAM1); int pos = PARAM2; - + d->W(pos) = T0; } @@ -1221,7 +1221,7 @@ void OPPROTO glue(op_pextrw, SUFFIX) (void) { Reg *s = (Reg *)((char *)env + PARAM1); int pos = PARAM2; - + T0 = s->W(pos); } diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index 373b77a24..e2bc1cfc4 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -1,7 +1,7 @@ /* * i386 micro operations (included several times to generate * different operand sizes) - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -239,7 +239,7 @@ static int glue(compute_all_sar, SUFFIX)(void) zf = ((DATA_TYPE)CC_DST == 0) << 6; sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; /* of is defined if shift count == 1 */ - of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; + of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } @@ -502,7 +502,7 @@ void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) { int count; target_long res; - + res = T0 & DATA_MASK; if (res != 0) { count = 0; diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h index 9f72a8c96..ae17d8e3c 100644 --- a/target-i386/ops_template_mem.h +++ b/target-i386/ops_template_mem.h @@ -1,7 +1,7 @@ /* * i386 micro operations (included several times to generate * different operand sizes) - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -84,8 +84,8 @@ void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) /* gcc 3.2 workaround. This is really a bug in gcc. */ asm volatile("" : : "r" (T0)); #endif - CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | (T0 & CC_C); CC_OP = CC_OP_EFLAGS; } @@ -109,7 +109,7 @@ void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) asm volatile("" : : "r" (T0)); #endif CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | ((T0 >> (DATA_BITS - 1)) & CC_C); CC_OP = CC_OP_EFLAGS; } @@ -168,7 +168,7 @@ void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | ((src >> (DATA_BITS - count)) & CC_C); CC_OP = CC_OP_EFLAGS; } @@ -199,7 +199,7 @@ void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) glue(st, MEM_SUFFIX)(A0, T0); #endif CC_SRC = (eflags & ~(CC_C | CC_O)) | - (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | + (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | ((src >> (count - 1)) & CC_C); CC_OP = CC_OP_EFLAGS; } diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index cf8bd5ab3..8b8d26795 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -1,6 +1,6 @@ /* * i386 on i386 translation - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -42,7 +42,7 @@ extern char exec_loop; enum { OT_BYTE = 0, OT_WORD, - OT_LONG, + OT_LONG, OT_QUAD, }; @@ -63,7 +63,7 @@ typedef struct DisasContext { /* code output */ uint8_t *gen_code_ptr; uint8_t *gen_code_start; - + /* current block context */ target_ulong cs_base; /* base of CS segment */ int pe; /* protected mode */ @@ -105,22 +105,22 @@ static inline void gjmp(DisasContext *s, long val) gl(s, val - (long)(s->gen_code_ptr + 4)); } -static inline void gen_movl_addr_im(DisasContext *s, +static inline void gen_movl_addr_im(DisasContext *s, uint32_t addr, uint32_t val) { gb(s, CPU_SEG); /* seg movl im, addr */ - gb(s, 0xc7); + gb(s, 0xc7); gb(s, 0x05); gl(s, addr); gl(s, val); } -static inline void gen_movw_addr_im(DisasContext *s, +static inline void gen_movw_addr_im(DisasContext *s, uint32_t addr, uint32_t val) { gb(s, CPU_SEG); /* seg movl im, addr */ - gb(s, 0x66); - gb(s, 0xc7); + gb(s, 0x66); + gb(s, 0xc7); gb(s, 0x05); gl(s, addr); gw(s, val); @@ -155,7 +155,7 @@ static void gen_jcc(DisasContext *s, int op, gb(s, 0xe9); /* jmp */ tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start; gl(s, 0); - + tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); @@ -194,7 +194,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) base = rm; index = 0; scale = 0; - + if (base == 4) { havesib = 1; code = ldub_code(s->pc++); @@ -222,7 +222,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) s->pc += 4; break; } - + } else { switch (mod) { case 0: @@ -248,7 +248,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) static inline void parse_modrm(DisasContext *s, int modrm) { if ((modrm & 0xc0) != 0xc0) - gen_lea_modrm(s, modrm); + gen_lea_modrm(s, modrm); } static inline uint32_t insn_get(DisasContext *s, int ot) @@ -351,7 +351,7 @@ static int disas_insn(DisasContext *s) /* extended op code */ b = ldub_code(s->pc++) | 0x100; goto reswitch; - + /**************************/ /* arith & logic */ case 0x00 ... 0x05: @@ -370,7 +370,7 @@ static int disas_insn(DisasContext *s) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - + switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub_code(s->pc++); @@ -396,7 +396,7 @@ static int disas_insn(DisasContext *s) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - + modrm = ldub_code(s->pc++); parse_modrm(s, modrm); @@ -475,8 +475,8 @@ static int disas_insn(DisasContext *s) break; case 2: /* call Ev */ /* XXX: optimize and handle MEM exceptions specifically - fs movl %eax, regs[0] - movl Ev, %eax + fs movl %eax, regs[0] + movl Ev, %eax pushl next_eip fs movl %eax, eip */ @@ -485,8 +485,8 @@ static int disas_insn(DisasContext *s) goto unsupported_op; case 4: /* jmp Ev */ /* XXX: optimize and handle MEM exceptions specifically - fs movl %eax, regs[0] - movl Ev, %eax + fs movl %eax, regs[0] + movl Ev, %eax fs movl %eax, eip */ goto unsupported_op; @@ -506,7 +506,7 @@ static int disas_insn(DisasContext *s) ot = dflag ? OT_LONG : OT_WORD; insn_get(s, ot); break; - + case 0x98: /* CWDE/CBW */ break; case 0x99: /* CDQ/CWD */ @@ -526,8 +526,8 @@ static int disas_insn(DisasContext *s) break; case 0x84: /* test Ev, Gv */ - case 0x85: - + case 0x85: + case 0x1c0: case 0x1c1: /* xadd Ev, Gv */ @@ -583,7 +583,7 @@ static int disas_insn(DisasContext *s) goto illegal_op; parse_modrm(s, modrm); break; - + /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ @@ -654,7 +654,7 @@ static int disas_insn(DisasContext *s) goto unsupported_op; /************************/ /* floats */ - case 0xd8 ... 0xdf: + case 0xd8 ... 0xdf: #if 1 /* currently not stable enough */ goto unsupported_op; @@ -850,7 +850,7 @@ static int disas_insn(DisasContext *s) goto illegal_op; parse_modrm(s, modrm); break; - + case 0xa0: /* mov EAX, Ov */ case 0xa1: case 0xa2: /* mov Ov, EAX */ @@ -888,14 +888,14 @@ static int disas_insn(DisasContext *s) parse_modrm(s, modrm); ldub_code(s->pc++); break; - + /************************/ /* string ops */ case 0xa4: /* movsS */ case 0xa5: break; - + case 0xaa: /* stosS */ case 0xab: break; @@ -955,7 +955,7 @@ static int disas_insn(DisasContext *s) case 0xc3: /* ret */ gb(s, CPU_SEG); - if (!s->dflag) + if (!s->dflag) gb(s, 0x66); /* d16 */ gb(s, 0x8f); /* pop addr */ gb(s, 0x05); @@ -1011,7 +1011,7 @@ static int disas_insn(DisasContext *s) if (dflag) { val = insn_get(s, OT_LONG); } else { - val = (int16_t)insn_get(s, OT_WORD); + val = (int16_t)insn_get(s, OT_WORD); } do_jcc: next_eip = s->pc - s->cs_base; @@ -1071,7 +1071,7 @@ static int disas_insn(DisasContext *s) case 0x90: /* nop */ break; case 0x9b: /* fwait */ - if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == + if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == (HF_MP_MASK | HF_TS_MASK)) { goto unsupported_op; } @@ -1171,7 +1171,7 @@ static int disas_insn(DisasContext *s) #define GEN_CODE_MAX_INSN_SIZE 512 static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, + TranslationBlock *tb, uint8_t *gen_code_ptr, int *gen_code_size_ptr, int search_pc, @@ -1186,14 +1186,14 @@ static inline int gen_intermediate_code_internal(CPUState *env, env->singlestep_enabled) return -1; flags = tb->flags; - if (flags & (HF_TF_MASK | HF_ADDSEG_MASK | + if (flags & (HF_TF_MASK | HF_ADDSEG_MASK | HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK)) return -1; if (!(flags & HF_SS32_MASK)) return -1; if (tb->cflags & CF_SINGLE_INSN) return -1; - gen_code_end = gen_code_ptr + + gen_code_end = gen_code_ptr + GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE; dc->gen_code_ptr = gen_code_ptr; dc->gen_code_start = gen_code_ptr; @@ -1244,11 +1244,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, break; } } - + #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); - fprintf(logfile, "IN: COPY: %s fpu=%d\n", + fprintf(logfile, "IN: COPY: %s fpu=%d\n", lookup_symbol(pc_start), tb->cflags & CF_TB_FP_USED ? 1 : 0); target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32); @@ -1279,14 +1279,14 @@ int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb, tb->tb_jmp_offset[2] = 0xffff; tb->tb_jmp_offset[3] = 0xffff; #endif - return gen_intermediate_code_internal(env, tb, + return gen_intermediate_code_internal(env, tb, tb->tc_ptr, gen_code_size_ptr, 0, NULL); } static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE]; -int cpu_restore_state_copy(TranslationBlock *tb, +int cpu_restore_state_copy(TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc) { @@ -1297,14 +1297,14 @@ int cpu_restore_state_copy(TranslationBlock *tb, if (searched_pc < (unsigned long)tb->tc_ptr) return -1; searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf; - ret = gen_intermediate_code_internal(env, tb, + ret = gen_intermediate_code_internal(env, tb, dummy_gen_code_buf, NULL, 1, (uint8_t *)searched_pc); if (ret < 0) return ret; /* restore all the CPU state from the CPU context from the signal. The FPU context stays in the host CPU. */ - + env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX]; env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX]; env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX]; diff --git a/target-i386/translate.c b/target-i386/translate.c index 15bfef5cb..946a43097 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1,6 +1,6 @@ /* * i386 translation - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -109,24 +109,24 @@ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num); /* i386 arith/logic operations */ enum { - OP_ADDL, - OP_ORL, - OP_ADCL, + OP_ADDL, + OP_ORL, + OP_ADCL, OP_SBBL, - OP_ANDL, - OP_SUBL, - OP_XORL, + OP_ANDL, + OP_SUBL, + OP_XORL, OP_CMPL, }; /* i386 shift ops */ enum { - OP_ROL, - OP_ROR, - OP_RCL, - OP_RCR, - OP_SHL, - OP_SHR, + OP_ROL, + OP_ROR, + OP_RCL, + OP_RCR, + OP_SHL, + OP_SHR, OP_SHL1, /* undocumented */ OP_SAR = 7, }; @@ -144,7 +144,7 @@ enum { enum { OT_BYTE = 0, OT_WORD, - OT_LONG, + OT_LONG, OT_QUAD, }; @@ -333,7 +333,7 @@ static GenOpFunc *gen_op_mov_reg_A0[NB_OP_SIZES - 1][CPU_NB_REGS] = { #endif }; -static GenOpFunc *gen_op_mov_TN_reg[NB_OP_SIZES][2][CPU_NB_REGS] = +static GenOpFunc *gen_op_mov_TN_reg[NB_OP_SIZES][2][CPU_NB_REGS] = { [OT_BYTE] = { { @@ -878,7 +878,7 @@ static GenOpFunc1 *gen_op_jnz_ecx[3] = { gen_op_jnz_ecxl, X86_64_ONLY(gen_op_jnz_ecxq), }; - + static GenOpFunc1 *gen_op_jz_ecx[3] = { gen_op_jz_ecxw, gen_op_jz_ecxl, @@ -966,7 +966,7 @@ static inline void gen_movs(DisasContext *s, int ot) if (s->aflag == 2) { gen_op_addq_ESI_T0(); gen_op_addq_EDI_T0(); - } else + } else #endif if (s->aflag) { gen_op_addl_ESI_T0(); @@ -1009,7 +1009,7 @@ static inline void gen_stos(DisasContext *s, int ot) #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_addq_EDI_T0(); - } else + } else #endif if (s->aflag) { gen_op_addl_EDI_T0(); @@ -1027,7 +1027,7 @@ static inline void gen_lods(DisasContext *s, int ot) #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_addq_ESI_T0(); - } else + } else #endif if (s->aflag) { gen_op_addl_ESI_T0(); @@ -1046,7 +1046,7 @@ static inline void gen_scas(DisasContext *s, int ot) #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_addq_EDI_T0(); - } else + } else #endif if (s->aflag) { gen_op_addl_EDI_T0(); @@ -1067,7 +1067,7 @@ static inline void gen_cmps(DisasContext *s, int ot) if (s->aflag == 2) { gen_op_addq_ESI_T0(); gen_op_addq_EDI_T0(); - } else + } else #endif if (s->aflag) { gen_op_addl_ESI_T0(); @@ -1089,7 +1089,7 @@ static inline void gen_ins(DisasContext *s, int ot) #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_addq_EDI_T0(); - } else + } else #endif if (s->aflag) { gen_op_addl_EDI_T0(); @@ -1107,7 +1107,7 @@ static inline void gen_outs(DisasContext *s, int ot) #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_addq_ESI_T0(); - } else + } else #endif if (s->aflag) { gen_op_addl_ESI_T0(); @@ -1318,7 +1318,7 @@ static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { static void gen_op(DisasContext *s1, int op, int ot, int d) { GenOpFunc *gen_update_cc; - + if (d != OR_TMP0) { gen_op_mov_TN_reg[ot][0][d](); } else { @@ -1408,7 +1408,7 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) /* for zero counts, flags are not updated, so must do it dynamically */ if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); - + if (d != OR_TMP0) gen_op_shift_T0_T1_cc[ot][op](); else @@ -1448,7 +1448,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ base = rm; index = 0; scale = 0; - + if (base == 4) { havesib = 1; code = ldub_code(s->pc++); @@ -1480,7 +1480,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ s->pc += 4; break; } - + if (base >= 0) { /* for correct popl handling with esp */ if (base == 4 && s->popl_esp_hack) @@ -1494,7 +1494,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ else gen_op_addq_A0_im64(disp >> 32, disp); } - } else + } else #endif { gen_op_movl_A0_reg[base](); @@ -1508,7 +1508,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ gen_op_movq_A0_im(disp); else gen_op_movq_A0_im64(disp >> 32, disp); - } else + } else #endif { gen_op_movl_A0_im(disp); @@ -1519,7 +1519,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_addq_A0_reg_sN[scale][index](); - } else + } else #endif { gen_op_addl_A0_reg_sN[scale][index](); @@ -1535,7 +1535,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base)); - } else + } else #endif { gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); @@ -1627,12 +1627,12 @@ static void gen_nop_modrm(DisasContext *s, int modrm) if (s->aflag) { base = rm; - + if (base == 4) { code = ldub_code(s->pc++); base = (code & 7); } - + switch (mod) { case 0: if (base == 5) { @@ -1681,7 +1681,7 @@ static void gen_add_A0_ds_seg(DisasContext *s) #ifdef TARGET_X86_64 if (CODE64(s)) { gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base)); - } else + } else #endif { gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); @@ -1776,7 +1776,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip) } } -static inline void gen_jcc(DisasContext *s, int b, +static inline void gen_jcc(DisasContext *s, int b, target_ulong val, target_ulong next_eip) { TranslationBlock *tb; @@ -1787,7 +1787,7 @@ static inline void gen_jcc(DisasContext *s, int b, inv = b & 1; jcc_op = (b >> 1) & 7; - + if (s->jmp_opt) { switch(s->cc_op) { /* we optimize the cmp/jcc case */ @@ -1797,7 +1797,7 @@ static inline void gen_jcc(DisasContext *s, int b, case CC_OP_SUBQ: func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; break; - + /* some jumps are easy to compute */ case CC_OP_ADDB: case CC_OP_ADDW: @@ -1864,7 +1864,7 @@ static inline void gen_jcc(DisasContext *s, int b, gen_setcc_slow[jcc_op](); func = gen_op_jnz_T0_label; } - + if (inv) { tmp = val; val = next_eip; @@ -1922,7 +1922,7 @@ static void gen_setcc(DisasContext *s, int b) if (!func) goto slow_jcc; break; - + /* some jumps are easy to compute */ case CC_OP_ADDB: case CC_OP_ADDW: @@ -2001,7 +2001,7 @@ static inline void gen_stack_update(DisasContext *s, int addend) if (CODE64(s)) { if (addend == 8) gen_op_addq_ESP_8(); - else + else gen_op_addq_ESP_im(addend); } else #endif @@ -2010,7 +2010,7 @@ static inline void gen_stack_update(DisasContext *s, int addend) gen_op_addl_ESP_2(); else if (addend == 4) gen_op_addl_ESP_4(); - else + else gen_op_addl_ESP_im(addend); } else { if (addend == 2) @@ -2036,7 +2036,7 @@ static void gen_push_T0(DisasContext *s) gen_op_st_T0_A0[OT_WORD + s->mem_index](); } gen_op_movq_ESP_A0(); - } else + } else #endif { gen_op_movl_A0_reg[R_ESP](); @@ -2077,7 +2077,7 @@ static void gen_push_T1(DisasContext *s) gen_op_st_T0_A0[OT_WORD + s->mem_index](); } gen_op_movq_ESP_A0(); - } else + } else #endif { gen_op_movl_A0_reg[R_ESP](); @@ -2094,7 +2094,7 @@ static void gen_push_T1(DisasContext *s) gen_op_addl_A0_SS(); } gen_op_st_T1_A0[s->dflag + 1 + s->mem_index](); - + if (s->ss32 && !s->addseg) gen_op_movl_ESP_A0(); else @@ -2109,7 +2109,7 @@ static void gen_pop_T0(DisasContext *s) if (CODE64(s)) { gen_op_movq_A0_reg[R_ESP](); gen_op_ld_T0_A0[(s->dflag ? OT_QUAD : OT_WORD) + s->mem_index](); - } else + } else #endif { gen_op_movl_A0_reg[R_ESP](); @@ -2196,7 +2196,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) if (CODE64(s)) { ot = s->dflag ? OT_QUAD : OT_WORD; opsize = 1 << ot; - + gen_op_movl_A0_ESP(); gen_op_addq_A0_im(-opsize); gen_op_movl_T1_A0(); @@ -2210,12 +2210,12 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_mov_reg_T1[ot][R_EBP](); gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); gen_op_mov_reg_T1[OT_QUAD][R_ESP](); - } else + } else #endif { ot = s->dflag + OT_WORD; opsize = 2 << s->dflag; - + gen_op_movl_A0_ESP(); gen_op_addl_A0_im(-opsize); if (!s->ss32) @@ -2246,7 +2246,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) /* an interrupt is different from an exception because of the privilege checks */ -static void gen_interrupt(DisasContext *s, int intno, +static void gen_interrupt(DisasContext *s, int intno, target_ulong cur_eip, target_ulong next_eip) { if (s->cc_op != CC_OP_DYNAMIC) @@ -2309,7 +2309,7 @@ static void gen_jmp(DisasContext *s, target_ulong eip) static void gen_movtl_T0_im(target_ulong val) { -#ifdef TARGET_X86_64 +#ifdef TARGET_X86_64 if ((int32_t)val == val) { gen_op_movl_T0_im(val); } else { @@ -2322,7 +2322,7 @@ static void gen_movtl_T0_im(target_ulong val) static void gen_movtl_T1_im(target_ulong val) { -#ifdef TARGET_X86_64 +#ifdef TARGET_X86_64 if ((int32_t)val == val) { gen_op_movl_T1_im(val); } else { @@ -2410,7 +2410,7 @@ static GenOpFunc2 *sse_op_table1[256][4] = { [0x57] = { gen_op_pxor_xmm, gen_op_pxor_xmm }, /* xorps, xorpd */ [0x58] = SSE_FOP(add), [0x59] = SSE_FOP(mul), - [0x5a] = { gen_op_cvtps2pd, gen_op_cvtpd2ps, + [0x5a] = { gen_op_cvtps2pd, gen_op_cvtpd2ps, gen_op_cvtss2sd, gen_op_cvtsd2ss }, [0x5b] = { gen_op_cvtdq2ps, gen_op_cvtps2dq, gen_op_cvttps2dq }, [0x5c] = SSE_FOP(sub), @@ -2438,9 +2438,9 @@ static GenOpFunc2 *sse_op_table1[256][4] = { [0x6d] = { NULL, gen_op_punpckhqdq_xmm }, [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */ [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */ - [0x70] = { (GenOpFunc2 *)gen_op_pshufw_mmx, - (GenOpFunc2 *)gen_op_pshufd_xmm, - (GenOpFunc2 *)gen_op_pshufhw_xmm, + [0x70] = { (GenOpFunc2 *)gen_op_pshufw_mmx, + (GenOpFunc2 *)gen_op_pshufd_xmm, + (GenOpFunc2 *)gen_op_pshufhw_xmm, (GenOpFunc2 *)gen_op_pshuflw_xmm }, [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */ [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */ @@ -2522,7 +2522,7 @@ static GenOpFunc1 *sse_op_table3[4 * 3] = { gen_op_cvtsi2sd, X86_64_ONLY(gen_op_cvtsq2ss), X86_64_ONLY(gen_op_cvtsq2sd), - + gen_op_cvttss2si, gen_op_cvttsd2si, X86_64_ONLY(gen_op_cvttss2sq), @@ -2533,7 +2533,7 @@ static GenOpFunc1 *sse_op_table3[4 * 3] = { X86_64_ONLY(gen_op_cvtss2sq), X86_64_ONLY(gen_op_cvtsd2sq), }; - + static GenOpFunc2 *sse_op_table4[8][4] = { SSE_FOP(cmpeq), SSE_FOP(cmplt), @@ -2544,7 +2544,7 @@ static GenOpFunc2 *sse_op_table4[8][4] = { SSE_FOP(cmpnle), SSE_FOP(cmpord), }; - + static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) { int b1, op1_offset, op2_offset, is_xmm, val, ot; @@ -2553,16 +2553,16 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) GenOpFunc3 *sse_op3; b &= 0xff; - if (s->prefix & PREFIX_DATA) + if (s->prefix & PREFIX_DATA) b1 = 1; - else if (s->prefix & PREFIX_REPZ) + else if (s->prefix & PREFIX_REPZ) b1 = 2; - else if (s->prefix & PREFIX_REPNZ) + else if (s->prefix & PREFIX_REPNZ) b1 = 3; else b1 = 0; sse_op2 = sse_op_table1[b][b1]; - if (!sse_op2) + if (!sse_op2) goto illegal_op; if (b <= 0x5f || b == 0xc6 || b == 0xc2) { is_xmm = 1; @@ -2606,7 +2606,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) b |= (b1 << 8); switch(b) { case 0x0e7: /* movntq */ - if (mod == 3) + if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx)); @@ -2625,7 +2625,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) if (s->dflag == 2) { gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0); gen_op_movq_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); - } else + } else #endif { gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); @@ -2637,7 +2637,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) if (s->dflag == 2) { gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0); gen_op_movq_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg])); - } else + } else #endif { gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0); @@ -2770,7 +2770,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) if (s->dflag == 2) { gen_op_movq_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1); - } else + } else #endif { gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx)); @@ -2782,7 +2782,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) if (s->dflag == 2) { gen_op_movq_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg])); gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1); - } else + } else #endif { gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg])); @@ -2982,12 +2982,12 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) rm = (modrm & 7) | REX_B(s); op2_offset = offsetof(CPUX86State,xmm_regs[rm]); } - sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 + + sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 + (b & 1) * 4](op2_offset); gen_op_mov_reg_T0[ot][reg](); break; case 0xc4: /* pinsrw */ - case 0x1c4: + case 0x1c4: s->rip_offset = 1; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); val = ldub_code(s->pc++); @@ -3000,7 +3000,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) } break; case 0xc5: /* pextrw */ - case 0x1c5: + case 0x1c5: if (mod != 3) goto illegal_op; val = ldub_code(s->pc++); @@ -3062,12 +3062,12 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) switch(b) { case 0xf7: /* maskmov : we must prepare A0 */ - if (mod != 3) + if (mod != 3) goto illegal_op; #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_movq_A0_reg[R_EDI](); - } else + } else #endif { gen_op_movl_A0_reg[R_EDI](); @@ -3164,7 +3164,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) #ifdef TARGET_X86_64 s->rex_x = 0; s->rex_b = 0; - x86_64_hregs = 0; + x86_64_hregs = 0; #endif s->rip_offset = 0; /* for relative ip address */ next_byte: @@ -3225,7 +3225,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } if (!(prefixes & PREFIX_ADR)) aflag = 2; - } else + } else #endif { switch (b) { @@ -3285,7 +3285,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /* extended op code */ b = ldub_code(s->pc++) | 0x100; goto reswitch; - + /**************************/ /* arith & logic */ case 0x00 ... 0x05: @@ -3305,7 +3305,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_BYTE; else ot = dflag + OT_WORD; - + switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub_code(s->pc++); @@ -3364,12 +3364,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_BYTE; else ot = dflag + OT_WORD; - + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); op = (modrm >> 3) & 7; - + if (mod != 3) { if (b == 0x83) s->rip_offset = 1; @@ -3656,7 +3656,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0x84: /* test Ev, Gv */ - case 0x85: + case 0x85: if ((b & 1) == 0) ot = OT_BYTE; else @@ -3666,13 +3666,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; - + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_TN_reg[ot][1][reg](); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; - + case 0xa8: /* test eAX, Iv */ case 0xa9: if ((b & 1) == 0) @@ -3686,7 +3686,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; - + case 0x98: /* CWDE/CBW */ #ifdef TARGET_X86_64 if (dflag == 2) { @@ -3804,7 +3804,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_cmpxchg8b(); s->cc_op = CC_OP_EFLAGS; break; - + /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ @@ -3955,7 +3955,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; - + /* generate a generic store */ gen_ldst_modrm(s, modrm, ot, reg, 1); break; @@ -3986,7 +3986,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_WORD + dflag; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; - + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_reg_T0[ot][reg](); break; @@ -4038,7 +4038,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); - + if (mod == 3) { gen_op_mov_TN_reg[ot][0][rm](); switch(ot | (b & 8)) { @@ -4084,7 +4084,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) s->addseg = val; gen_op_mov_reg_A0[ot - OT_WORD][reg](); break; - + case 0xa0: /* mov EAX, Ov */ case 0xa1: case 0xa2: /* mov Ov, EAX */ @@ -4104,7 +4104,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_movq_A0_im(offset_addr); else gen_op_movq_A0_im64(offset_addr >> 32, offset_addr); - } else + } else #endif { if (s->aflag) { @@ -4129,7 +4129,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->aflag == 2) { gen_op_movq_A0_reg[R_EBX](); gen_op_addq_A0_AL(); - } else + } else #endif { gen_op_movl_A0_reg[R_EBX](); @@ -4156,7 +4156,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) reg = (b & 7) | REX_B(s); gen_movtl_T0_im(tmp); gen_op_mov_reg_T0[OT_QUAD][reg](); - } else + } else #endif { ot = dflag ? OT_LONG : OT_WORD; @@ -4239,7 +4239,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_eob(s); } break; - + /************************/ /* shifts */ case 0xc0: @@ -4252,11 +4252,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_BYTE; else ot = dflag + OT_WORD; - + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; - + if (mod != 3) { if (shift == 2) { s->rip_offset = 1; @@ -4310,7 +4310,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; - + if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T0_A0[ot + s->mem_index](); @@ -4318,7 +4318,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_mov_TN_reg[ot][0][rm](); } gen_op_mov_TN_reg[ot][1][reg](); - + if (shift) { val = ldub_code(s->pc++); if (ot == OT_QUAD) @@ -4351,7 +4351,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /************************/ /* floats */ - case 0xd8 ... 0xdf: + case 0xd8 ... 0xdf: if (s->flags & (HF_EM_MASK | HF_TS_MASK)) { /* if CR0.EM or CR0.TS are set, generate an FPU exception */ /* XXX: what to do if illegal op ? */ @@ -4389,7 +4389,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_fild_FT0_A0(); break; } - + gen_op_fp_arith_ST0_FT0[op1](); if (op1 == 3) { /* fcomp needs pop */ @@ -4646,7 +4646,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ { int op1; - + op1 = op & 7; if (op >= 0x20) { gen_op_fp_arith_STN_ST0[op1](opreg); @@ -4716,7 +4716,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0x28: /* ffree sti */ gen_op_ffree_STN(opreg); - break; + break; case 0x2a: /* fst sti */ gen_op_fmov_STN_ST0(opreg); break; @@ -4816,7 +4816,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_movs(s, ot); } break; - + case 0xaa: /* stosS */ case 0xab: if ((b & 1) == 0) @@ -5042,13 +5042,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0x9a: /* lcall im */ { unsigned int selector, offset; - + if (CODE64(s)) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); - + gen_op_movl_T0_im(selector); gen_op_movl_T1_imu(offset); } @@ -5072,7 +5072,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); - + gen_op_movl_T0_im(selector); gen_op_movl_T1_imu(offset); } @@ -5091,7 +5091,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (dflag) { tval = (int32_t)insn_get(s, OT_LONG); } else { - tval = (int16_t)insn_get(s, OT_WORD); + tval = (int16_t)insn_get(s, OT_WORD); } do_jcc: next_eip = s->pc - s->cs_base; @@ -5121,7 +5121,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); break; - + /************************/ /* flags */ case 0x9c: /* pushf */ @@ -5350,7 +5350,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; break; case 0x9b: /* fwait */ - if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == + if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == (HF_MP_MASK | HF_TS_MASK)) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); } else { @@ -5366,7 +5366,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0xcd: /* int N */ val = ldub_code(s->pc++); if (s->vm86 && s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); } @@ -5451,7 +5451,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_mov_TN_reg[OT_QUAD][0][reg](); gen_op_bswapq_T0(); gen_op_mov_reg_T0[OT_QUAD][reg](); - } else + } else #endif { gen_op_mov_TN_reg[OT_LONG][0][reg](); @@ -5481,7 +5481,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) tval += next_eip; if (s->dflag == 0) tval &= 0xffff; - + l1 = gen_new_label(); l2 = gen_new_label(); b &= 3; @@ -5681,7 +5681,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->aflag == 2) { gen_op_movq_A0_reg[R_EBX](); gen_op_addq_A0_AL(); - } else + } else #endif { gen_op_movl_A0_reg[R_EBX](); @@ -5766,7 +5766,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase)); gen_op_movtl_env_T1(offsetof(CPUX86State,segs[R_GS].base)); gen_op_movtl_env_T0(offsetof(CPUX86State,kernelgsbase)); - } else + } else #endif { goto illegal_op; @@ -5802,7 +5802,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); - + if (mod == 3) { gen_op_mov_TN_reg[OT_LONG][0][rm](); /* sign extend */ @@ -5818,7 +5818,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } gen_op_mov_reg_T0[d_ot][reg](); } - } else + } else #endif { if (!s->pe || s->vm86) @@ -5913,7 +5913,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) if (reg == 8) gen_op_movtl_T0_cr8(); else @@ -5984,7 +5984,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) op = (modrm >> 3) & 7; switch(op) { case 0: /* fxsave */ - if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || (s->flags & HF_EM_MASK)) goto illegal_op; if (s->flags & HF_TS_MASK) { @@ -5995,7 +5995,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_fxsave_A0((s->dflag == 2)); break; case 1: /* fxrstor */ - if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || (s->flags & HF_EM_MASK)) goto illegal_op; if (s->flags & HF_TS_MASK) { @@ -6088,14 +6088,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) #define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P) /* flags read by an operation */ -static uint16_t opc_read_flags[NB_OPS] = { +static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_aas] = CC_A, [INDEX_op_aaa] = CC_A, [INDEX_op_das] = CC_A | CC_C, [INDEX_op_daa] = CC_A | CC_C, /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_update_inc_cc] = CC_C, + [INDEX_op_update_inc_cc] = CC_C, [INDEX_op_into] = CC_O, @@ -6221,13 +6221,13 @@ static uint16_t opc_read_flags[NB_OPS] = { }; /* flags written by an operation */ -static uint16_t opc_write_flags[NB_OPS] = { +static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_update2_cc] = CC_OSZAPC, [INDEX_op_update1_cc] = CC_OSZAPC, [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_update_neg_cc] = CC_OSZAPC, /* subtle: due to the incl/decl implementation, C is used */ - [INDEX_op_update_inc_cc] = CC_OSZAPC, + [INDEX_op_update_inc_cc] = CC_OSZAPC, [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_mulb_AL_T0] = CC_OSZAPC, @@ -6372,7 +6372,7 @@ static uint16_t opc_write_flags[NB_OPS] = { }; /* simpler form of an operation if no flags need to be generated */ -static uint16_t opc_simpler[NB_OPS] = { +static uint16_t opc_simpler[NB_OPS] = { [INDEX_op_update2_cc] = INDEX_op_nop, [INDEX_op_update1_cc] = INDEX_op_nop, [INDEX_op_update_neg_cc] = INDEX_op_nop, @@ -6456,7 +6456,7 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, + TranslationBlock *tb, int search_pc) { DisasContext dc1, *dc = &dc1; @@ -6465,7 +6465,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, int flags, j, lj, cflags; target_ulong pc_start; target_ulong cs_base; - + /* generate intermediate code */ pc_start = tb->pc; cs_base = tb->cs_base; @@ -6551,7 +6551,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear the flag and abort the translation to give the irqs a change to be happen */ - if (dc->tf || dc->singlestep_enabled || + if (dc->tf || dc->singlestep_enabled || (flags & HF_INHIBIT_IRQ_MASK) || (cflags & CF_SINGLE_INSN)) { gen_jmp_im(pc_ptr - dc->cs_base); @@ -6574,7 +6574,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, while (lj <= j) gen_opc_instr_start[lj++] = 0; } - + #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index b0e725d4a..5a0222dfb 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -1,6 +1,6 @@ /* * m68k virtual CPU header - * + * * Copyright (c) 2005-2007 CodeSourcery * Written by Paul Brook * @@ -86,7 +86,7 @@ typedef struct CPUM68KState { /* Temporary storage for DIV helpers. */ uint32_t div1; uint32_t div2; - + /* MMU status. */ struct { uint32_t ar; @@ -125,7 +125,7 @@ void do_interrupt(int is_hw); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -int cpu_m68k_signal_handler(int host_signum, void *pinfo, +int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); void cpu_m68k_flush_flags(CPUM68KState *, int); @@ -213,7 +213,7 @@ void register_m68k_insns (CPUM68KState *env); /* Linux uses 8k pages. */ #define TARGET_PAGE_BITS 13 #else -/* Smallest TLB entry size is 1k. */ +/* Smallest TLB entry size is 1k. */ #define TARGET_PAGE_BITS 10 #endif diff --git a/target-m68k/exec.h b/target-m68k/exec.h index 331844b41..dc5bf5e60 100644 --- a/target-m68k/exec.h +++ b/target-m68k/exec.h @@ -1,6 +1,6 @@ /* * m68k execution defines - * + * * Copyright (c) 2005-2006 CodeSourcery * Written by Paul Brook * diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 13305220a..423a0e00a 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -1,6 +1,6 @@ /* * m68k op helpers - * + * * Copyright (c) 2006-2007 CodeSourcery * Written by Paul Brook * @@ -39,11 +39,11 @@ struct m68k_def_t { }; static m68k_def_t m68k_cpu_defs[] = { - {"m5206", M68K_CPUID_M5206}, - {"m5208", M68K_CPUID_M5208}, + {"m5206", M68K_CPUID_M5206}, + {"m5208", M68K_CPUID_M5208}, {"cfv4e", M68K_CPUID_CFV4E}, {"any", M68K_CPUID_ANY}, - {NULL, 0}, + {NULL, 0}, }; static void m68k_set_feature(CPUM68KState *env, int feature) @@ -298,7 +298,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return addr; } -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) diff --git a/target-m68k/op.c b/target-m68k/op.c index e5e39c2fd..b52a957b3 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -1,6 +1,6 @@ /* * m68k micro operations - * + * * Copyright (c) 2006-2007 CodeSourcery * Written by Paul Brook * @@ -349,7 +349,7 @@ OP(divu) uint32_t quot; uint32_t rem; uint32_t flags; - + num = env->div1; den = env->div2; /* ??? This needs to make sure the throwing location is accurate. */ @@ -380,7 +380,7 @@ OP(divs) int32_t quot; int32_t rem; int32_t flags; - + num = env->div1; den = env->div2; if (den == 0) diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 39cd5d703..70b7aec0e 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -1,6 +1,6 @@ /* * M68K helper routines - * + * * Copyright (c) 2007 CodeSourcery * * This library is free software; you can redistribute it and/or diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 8adc9c366..978fb2ce8 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1,6 +1,6 @@ /* * m68k translation - * + * * Copyright (c) 2005-2007 CodeSourcery * Written by Paul Brook * @@ -1639,7 +1639,7 @@ DISAS_INSN(branch) uint32_t base; int op; int l1; - + base = s->pc; op = (insn >> 8) & 0xf; offset = (int8_t)insn; @@ -2190,7 +2190,7 @@ DISAS_INSN(fpu) } DEST_EA(insn, OS_LONG, res, NULL); break; - case 6: /* fmovem */ + case 6: /* fmovem */ case 7: { int addr; @@ -2323,7 +2323,7 @@ DISAS_INSN(fpu) tmp = gen_new_qreg(QMODE_F32); gen_op_f64_to_f32(tmp, res); gen_op_f32_to_f64(res, tmp); - } + } gen_op_fp_result(res); if (dest) { gen_op_movf64(dest, res); @@ -3065,7 +3065,7 @@ static void expand_op_addx_cc(qOP *qop) int arg0 = qop->args[0]; int arg1 = qop->args[1]; int l1, l2; - + gen_op_add32 (arg0, arg0, arg1); l1 = gen_new_label(); l2 = gen_new_label(); @@ -3159,7 +3159,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, /* generate intermediate code */ pc_start = tb->pc; - + dc->tb = tb; gen_opc_ptr = gen_opc_buf; @@ -3311,7 +3311,7 @@ void cpu_m68k_close(CPUM68KState *env) free(env); } -void cpu_dump_state(CPUState *env, FILE *f, +void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { diff --git a/target-mips/exec.h b/target-mips/exec.h index 53c4189a5..5b8577eaf 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -96,7 +96,7 @@ void do_mtc0_entryhi(uint32_t in); void do_mtc0_status_debug(uint32_t old, uint32_t val); void do_mtc0_status_irqraise_debug(void); void dump_fpu(CPUState *env); -void fpu_dump_state(CPUState *env, FILE *f, +void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), int flags); void dump_sc (void); @@ -145,7 +145,7 @@ void do_raise_exception (uint32_t exception); void do_raise_exception_direct_err (uint32_t exception, int error_code); void do_raise_exception_direct (uint32_t exception); -void cpu_dump_state(CPUState *env, FILE *f, +void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags); void cpu_mips_irqctrl_init (void); diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index bbdcb2890..25b2ca7a5 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -1,7 +1,7 @@ /* - * MIPS emulation micro-operations templates for floating point reg + * MIPS emulation micro-operations templates for floating point reg * load & store for qemu. - * + * * Copyright (c) 2006 Marius Groeger * * This library is free software; you can redistribute it and/or diff --git a/target-mips/helper.c b/target-mips/helper.c index 6d0be1015..9a503456b 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -1,6 +1,6 @@ /* * MIPS emulation helpers for qemu. - * + * * Copyright (c) 2004-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -203,7 +203,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, return ret; } -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; @@ -293,7 +293,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /* TLB match but 'D' bit is cleared */ exception = EXCP_LTLBL; break; - + } /* Raise exception */ env->CP0_BadVAddr = address; diff --git a/target-mips/op.c b/target-mips/op.c index 3f52f59d3..8d4c7d4af 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1,6 +1,6 @@ /* * MIPS emulation micro-operations for qemu. - * + * * Copyright (c) 2004-2005 Jocelyn Mayer * Copyright (c) 2006 Marius Groeger (FPU operations) * Copyright (c) 2007 Thiemo Seufer (64-bit FPU support) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index c87317a44..9d2f99e66 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1,6 +1,6 @@ /* * MIPS emulation helpers for qemu. - * + * * Copyright (c) 2004-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -244,7 +244,7 @@ void do_ddivu (void) #endif #endif /* TARGET_MIPS64 */ -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) void do_mfc0_random (void) { cpu_abort(env, "mfc0 random\n"); @@ -321,25 +321,25 @@ void fpu_handle_exception(void) enable = GET_FP_ENABLE(env->fpu->fcr31); - /* determine current flags */ + /* determine current flags */ if (flags & float_flag_invalid) { cpuflags |= FP_INVALID; cause |= FP_INVALID & enable; } if (flags & float_flag_divbyzero) { - cpuflags |= FP_DIV0; + cpuflags |= FP_DIV0; cause |= FP_DIV0 & enable; } if (flags & float_flag_overflow) { - cpuflags |= FP_OVERFLOW; + cpuflags |= FP_OVERFLOW; cause |= FP_OVERFLOW & enable; } if (flags & float_flag_underflow) { - cpuflags |= FP_UNDERFLOW; + cpuflags |= FP_UNDERFLOW; cause |= FP_UNDERFLOW & enable; } if (flags & float_flag_inexact) { - cpuflags |= FP_INEXACT; + cpuflags |= FP_INEXACT; cause |= FP_INEXACT & enable; } SET_FP_FLAGS(env->fpu->fcr31, cpuflags); @@ -539,7 +539,7 @@ void do_pmon (int function) } } -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr); diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 602c071c5..19241f143 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -1,6 +1,6 @@ /* * MIPS emulation memory micro-operations for qemu. - * + * * Copyright (c) 2004-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 41d954c1d..f3a05ade6 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -1,6 +1,6 @@ /* * MIPS emulation micro-operations templates for reg load & store for qemu. - * + * * Copyright (c) 2004-2005 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-mips/translate.c b/target-mips/translate.c index d7bb20af3..ee15193c2 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1,6 +1,6 @@ /* * MIPS32 emulation for qemu: main translation routines. - * + * * Copyright (c) 2004-2005 Jocelyn Mayer * Copyright (c) 2006 Marius Groeger (FPU operations) * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) @@ -6514,7 +6514,7 @@ done_generating: fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags); } #endif - + return 0; } @@ -6528,7 +6528,7 @@ int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } -void fpu_dump_state(CPUState *env, FILE *f, +void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { @@ -6568,7 +6568,7 @@ void fpu_dump_state(CPUState *env, FILE *f, void dump_fpu (CPUState *env) { - if (loglevel) { + if (loglevel) { fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", env->PC[env->current_tc], env->HI[0][env->current_tc], env->LO[0][env->current_tc], env->hflags, env->btarget, env->bcond); fpu_dump_state(env, logfile, fprintf, 0); @@ -6608,12 +6608,12 @@ void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, } #endif -void cpu_dump_state (CPUState *env, FILE *f, +void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { int i; - + cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 435b838c3..0b9c68cf0 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1,6 +1,6 @@ /* * PowerPC emulation cpu definitions for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -692,7 +692,7 @@ struct CPUPPCState { #if TARGET_GPR_BITS > HOST_LONG_BITS /* temporary fixed-point registers * used to emulate 64 bits target on 32 bits hosts - */ + */ ppc_gpr_t t0, t1, t2; #endif ppc_avr_t t0_avr, t1_avr, t2_avr; @@ -828,7 +828,7 @@ void cpu_ppc_close(CPUPPCState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -int cpu_ppc_signal_handler(int host_signum, void *pinfo, +int cpu_ppc_signal_handler(int host_signum, void *pinfo, void *puc); void do_interrupt (CPUPPCState *env); diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 69807ad5e..ae424515b 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -1,6 +1,6 @@ /* * PowerPC emulation definitions for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 84e6c3935..05a7368ad 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1,6 +1,6 @@ /* * PowerPC emulation helpers for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -255,7 +255,7 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, tlb = &env->tlb[nr].tlb6; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX + fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX " PTE1 " ADDRX "\n", nr, env->nb_tlb, EPN, pte0, pte1); } #endif @@ -383,7 +383,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, bl = (*BATu & 0x00001FFC) << 15; #if defined (DEBUG_BATS) if (loglevel != 0) { - fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX + fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX " BATl 0x" ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); @@ -452,7 +452,7 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw) pte1 = ldl_phys(base + (i * 8) + 4); #if defined (DEBUG_MMU) if (loglevel > 0) { - fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX + fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", base + (i * 8), pte0, pte1, pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem); @@ -528,7 +528,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; if ((sr & 0x80000000) == 0) { #if defined (DEBUG_MMU) - if (loglevel > 0) + if (loglevel > 0) fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n", ctx->key, sr & 0x10000000); #endif @@ -709,7 +709,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ppcemb_tlb_t *tlb; target_phys_addr_t raddr; int i, ret, zsel, zpr; - + ret = -1; raddr = -1; for (i = 0; i < env->nb_tlb; i++) { @@ -808,7 +808,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, " %d %d\n", __func__, address, raddr, ctx->prot, ret); } - + return ret; } @@ -825,7 +825,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw) { int in_plb, ret; - + ctx->raddr = eaddr; ctx->prot = PAGE_READ; ret = 0; diff --git a/target-ppc/mfrom_table.c b/target-ppc/mfrom_table.c index 4c2717318..6a1fa375c 100644 --- a/target-ppc/mfrom_table.c +++ b/target-ppc/mfrom_table.c @@ -1,79 +1,79 @@ static const uint8_t mfrom_ROM_table[602] = { - 77, 77, 76, 76, 75, 75, 74, 74, - 73, 73, 72, 72, 71, 71, 70, 70, - 69, 69, 68, 68, 68, 67, 67, 66, - 66, 65, 65, 64, 64, 64, 63, 63, - 62, 62, 61, 61, 61, 60, 60, 59, - 59, 58, 58, 58, 57, 57, 56, 56, - 56, 55, 55, 54, 54, 54, 53, 53, - 53, 52, 52, 51, 51, 51, 50, 50, - 50, 49, 49, 49, 48, 48, 47, 47, - 47, 46, 46, 46, 45, 45, 45, 44, - 44, 44, 43, 43, 43, 42, 42, 42, - 42, 41, 41, 41, 40, 40, 40, 39, - 39, 39, 39, 38, 38, 38, 37, 37, - 37, 37, 36, 36, 36, 35, 35, 35, - 35, 34, 34, 34, 34, 33, 33, 33, - 33, 32, 32, 32, 32, 31, 31, 31, - 31, 30, 30, 30, 30, 29, 29, 29, - 29, 28, 28, 28, 28, 28, 27, 27, - 27, 27, 26, 26, 26, 26, 26, 25, - 25, 25, 25, 25, 24, 24, 24, 24, - 24, 23, 23, 23, 23, 23, 23, 22, - 22, 22, 22, 22, 21, 21, 21, 21, - 21, 21, 20, 20, 20, 20, 20, 20, - 19, 19, 19, 19, 19, 19, 19, 18, - 18, 18, 18, 18, 18, 17, 17, 17, - 17, 17, 17, 17, 16, 16, 16, 16, - 16, 16, 16, 16, 15, 15, 15, 15, - 15, 15, 15, 15, 14, 14, 14, 14, - 14, 14, 14, 14, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, + 77, 77, 76, 76, 75, 75, 74, 74, + 73, 73, 72, 72, 71, 71, 70, 70, + 69, 69, 68, 68, 68, 67, 67, 66, + 66, 65, 65, 64, 64, 64, 63, 63, + 62, 62, 61, 61, 61, 60, 60, 59, + 59, 58, 58, 58, 57, 57, 56, 56, + 56, 55, 55, 54, 54, 54, 53, 53, + 53, 52, 52, 51, 51, 51, 50, 50, + 50, 49, 49, 49, 48, 48, 47, 47, + 47, 46, 46, 46, 45, 45, 45, 44, + 44, 44, 43, 43, 43, 42, 42, 42, + 42, 41, 41, 41, 40, 40, 40, 39, + 39, 39, 39, 38, 38, 38, 37, 37, + 37, 37, 36, 36, 36, 35, 35, 35, + 35, 34, 34, 34, 34, 33, 33, 33, + 33, 32, 32, 32, 32, 31, 31, 31, + 31, 30, 30, 30, 30, 29, 29, 29, + 29, 28, 28, 28, 28, 28, 27, 27, + 27, 27, 26, 26, 26, 26, 26, 25, + 25, 25, 25, 25, 24, 24, 24, 24, + 24, 23, 23, 23, 23, 23, 23, 22, + 22, 22, 22, 22, 21, 21, 21, 21, + 21, 21, 20, 20, 20, 20, 20, 20, + 19, 19, 19, 19, 19, 19, 19, 18, + 18, 18, 18, 18, 18, 17, 17, 17, + 17, 17, 17, 17, 16, 16, 16, 16, + 16, 16, 16, 16, 15, 15, 15, 15, + 15, 15, 15, 15, 14, 14, 14, 14, + 14, 14, 14, 14, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, }; diff --git a/target-ppc/mfrom_table_gen.c b/target-ppc/mfrom_table_gen.c index ab4b1cc0b..8c67d4444 100644 --- a/target-ppc/mfrom_table_gen.c +++ b/target-ppc/mfrom_table_gen.c @@ -8,7 +8,7 @@ int main (void) double d; uint8_t n; int i; - + printf("static const uint8_t mfrom_ROM_table[602] =\n{\n "); for (i = 0; i < 602; i++) { /* Extremly decomposed: diff --git a/target-ppc/op.c b/target-ppc/op.c index 546f12a86..61517c1c6 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1,6 +1,6 @@ /* * PowerPC emulation micro-operations for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 63180b61e..c65d5696b 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1,6 +1,6 @@ /* * PowerPC emulation helpers for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -231,7 +231,7 @@ static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) b0 = b; b1 = b >> 32; - + v = (uint64_t)a0 * (uint64_t)b0; *plow = v; *phigh = 0; @@ -1270,7 +1270,7 @@ void do_rfmci (void) void do_load_dcr (void) { target_ulong val; - + if (unlikely(env->dcr_env == NULL)) { if (loglevel != 0) { fprintf(logfile, "No DCR environment\n"); @@ -2554,7 +2554,7 @@ void do_4xx_tlbwe_hi (void) if (loglevel != 0) { fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, - (int)T0, tlb->RPN, tlb->EPN, tlb->size, + (int)T0, tlb->RPN, tlb->EPN, tlb->size, tlb->prot & PAGE_READ ? 'r' : '-', tlb->prot & PAGE_WRITE ? 'w' : '-', tlb->prot & PAGE_EXEC ? 'x' : '-', @@ -2596,7 +2596,7 @@ void do_4xx_tlbwe_lo (void) if (loglevel != 0) { fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, - (int)T0, tlb->RPN, tlb->EPN, tlb->size, + (int)T0, tlb->RPN, tlb->EPN, tlb->size, tlb->prot & PAGE_READ ? 'r' : '-', tlb->prot & PAGE_WRITE ? 'w' : '-', tlb->prot & PAGE_EXEC ? 'x' : '-', diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 82307d44f..33f053f96 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -1,6 +1,6 @@ /* * PowerPC emulation helpers header for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 612d120a5..fb62dbb2b 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -1,6 +1,6 @@ /* * PowerPC emulation micro-operations for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 4487a879c..cfb86d3cb 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -1,6 +1,6 @@ /* * PowerPC emulation micro-operations for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 40a1176c8..4419b20e8 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1,6 +1,6 @@ /* * PowerPC emulation for qemu: main translation routines. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -1147,7 +1147,7 @@ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { uint32_t mb, me, sh; - + sh = SH(ctx->opcode); mb = MB(ctx->opcode); me = ME(ctx->opcode); @@ -1676,7 +1676,7 @@ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) { uint8_t crb; - + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; @@ -1693,7 +1693,7 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) { uint8_t crb; - + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; @@ -2287,7 +2287,7 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) { /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); gen_op_load_xer_bc(); op_ldsts(stsw, rS(ctx->opcode)); @@ -2775,7 +2775,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) else #endif gen_op_test_ctr_false(mask); - break; + break; case 2: #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -2815,17 +2815,17 @@ static inline void gen_bcond(DisasContext *ctx, int type) } GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_IM); } GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_CTR); } GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_LR); } @@ -2968,7 +2968,7 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC) { uint32_t crm, crn; - + if (likely(ctx->opcode & 0x00100000)) { crm = CRM(ctx->opcode); if (likely((crm ^ (crm - 1)) == 0)) { @@ -3058,7 +3058,7 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB) GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) { uint32_t crm, crn; - + gen_op_load_gpr_T0(rS(ctx->opcode)); crm = CRM(ctx->opcode); if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) { @@ -5585,7 +5585,7 @@ static inline uint32_t load_xer (CPUState *env) (xer_cmp << XER_CMP); } -void cpu_dump_state(CPUState *env, FILE *f, +void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { @@ -5753,7 +5753,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, if (unlikely(env->nb_breakpoints > 0)) { for (j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == ctx.nip) { - gen_update_nip(&ctx, ctx.nip); + gen_update_nip(&ctx, ctx.nip); gen_op_debug(); break; } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 60e3a36f1..79a6ab6d4 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1,6 +1,6 @@ /* * PowerPC CPU initialization for qemu. - * + * * Copyright (c) 2003-2007 Jocelyn Mayer * * This library is free software; you can redistribute it and/or @@ -2142,7 +2142,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); break; - + case CPU_PPC_G2: /* PowerPC G2 family */ case CPU_PPC_G2H4: case CPU_PPC_G2gp: @@ -2577,7 +2577,7 @@ static int register_ind_insn (opc_handler_t **ppc_opcodes, return ret; } -static int register_dblind_insn (opc_handler_t **ppc_opcodes, +static int register_dblind_insn (opc_handler_t **ppc_opcodes, unsigned char idx1, unsigned char idx2, unsigned char idx3, opc_handler_t *handler) { diff --git a/target-sh4/README.sh4 b/target-sh4/README.sh4 index 2edda9f04..647a345a8 100644 --- a/target-sh4/README.sh4 +++ b/target-sh4/README.sh4 @@ -141,7 +141,7 @@ if __name__ == '__main__': import sys denand (open (sys.argv[1], 'rb'), open (sys.argv[2], 'wb')) - + Style isssues ------------- diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 9fc0edae2..add6a47b1 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -1,6 +1,6 @@ /* * SH4 emulation - * + * * Copyright (c) 2005 Samuel Tardieu * * This library is free software; you can redistribute it and/or @@ -123,7 +123,7 @@ typedef struct CPUSH4State { CPUSH4State *cpu_sh4_init(void); int cpu_sh4_exec(CPUSH4State * s); -int cpu_sh4_signal_handler(int host_signum, void *pinfo, +int cpu_sh4_signal_handler(int host_signum, void *pinfo, void *puc); #include "softfloat.h" diff --git a/target-sh4/exec.h b/target-sh4/exec.h index 84f29319e..a606fd186 100644 --- a/target-sh4/exec.h +++ b/target-sh4/exec.h @@ -1,6 +1,6 @@ /* * SH4 emulation - * + * * Copyright (c) 2005 Samuel Tardieu * * This library is free software; you can redistribute it and/or diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 1063ece2d..a5af5ba15 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -1,6 +1,6 @@ /* * SH4 emulation - * + * * Copyright (c) 2005 Samuel Tardieu * * This library is free software; you can redistribute it and/or diff --git a/target-sh4/op.c b/target-sh4/op.c index 34e271524..0902fca35 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -1,6 +1,6 @@ /* * SH4 emulation - * + * * Copyright (c) 2005 Samuel Tardieu * * This library is free software; you can redistribute it and/or diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index bf39921b4..292e9b30d 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -1,6 +1,6 @@ /* * SH4 emulation - * + * * Copyright (c) 2005 Samuel Tardieu * * This library is free software; you can redistribute it and/or diff --git a/target-sh4/op_mem.c b/target-sh4/op_mem.c index ca39abf96..b59871c20 100644 --- a/target-sh4/op_mem.c +++ b/target-sh4/op_mem.c @@ -1,6 +1,6 @@ /* * SH4 emulation - * + * * Copyright (c) 2005 Samuel Tardieu * * This library is free software; you can redistribute it and/or diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 5842c29d3..fe3d0e945 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1,6 +1,6 @@ /* * SH4 translation - * + * * Copyright (c) 2005 Samuel Tardieu * * This library is free software; you can redistribute it and/or diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e469f041a..7e985e955 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -36,7 +36,7 @@ #define TT_PRIV_INSN 0x03 #define TT_NFPU_INSN 0x04 #define TT_WIN_OVF 0x05 -#define TT_WIN_UNF 0x06 +#define TT_WIN_UNF 0x06 #define TT_UNALIGNED 0x07 #define TT_FP_EXCP 0x08 #define TT_DFAULT 0x09 diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h index 74988f7df..0598b3020 100644 --- a/target-sparc/fop_template.h +++ b/target-sparc/fop_template.h @@ -1,7 +1,7 @@ /* * SPARC micro operations (templates for various register related * operations) - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or diff --git a/target-sparc/helper.c b/target-sparc/helper.c index da81562fc..af4a8b00a 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -1,6 +1,6 @@ /* * sparc helpers - * + * * Copyright (c) 2003-2005 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -46,7 +46,7 @@ void cpu_unlock(void) spin_unlock(&global_cpu_lock); } -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) diff --git a/target-sparc/op.c b/target-sparc/op.c index f1f6ccefc..834173097 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -287,7 +287,7 @@ typedef union UREG64 { __p.l.v1 = PARAM1;\ __p.l.v0 = PARAM2;\ __p.q;\ -}) +}) void OPPROTO op_movq_T0_im64(void) { @@ -1065,7 +1065,7 @@ void OPPROTO op_rett(void) void OPPROTO op_save(void) { uint32_t cwp; - cwp = (env->cwp - 1) & (NWINDOWS - 1); + cwp = (env->cwp - 1) & (NWINDOWS - 1); if (env->wim & (1 << cwp)) { raise_exception(TT_WIN_OVF); } @@ -1076,7 +1076,7 @@ void OPPROTO op_save(void) void OPPROTO op_restore(void) { uint32_t cwp; - cwp = (env->cwp + 1) & (NWINDOWS - 1); + cwp = (env->cwp + 1) & (NWINDOWS - 1); if (env->wim & (1 << cwp)) { raise_exception(TT_WIN_UNF); } @@ -1197,9 +1197,9 @@ void OPPROTO op_wrcwp(void) void OPPROTO op_save(void) { uint32_t cwp; - cwp = (env->cwp - 1) & (NWINDOWS - 1); + cwp = (env->cwp - 1) & (NWINDOWS - 1); if (env->cansave == 0) { - raise_exception(TT_SPILL | (env->otherwin != 0 ? + raise_exception(TT_SPILL | (env->otherwin != 0 ? (TT_WOTHER | ((env->wstate & 0x38) >> 1)): ((env->wstate & 0x7) << 2))); } else { @@ -1218,9 +1218,9 @@ void OPPROTO op_save(void) void OPPROTO op_restore(void) { uint32_t cwp; - cwp = (env->cwp + 1) & (NWINDOWS - 1); + cwp = (env->cwp + 1) & (NWINDOWS - 1); if (env->canrestore == 0) { - raise_exception(TT_FILL | (env->otherwin != 0 ? + raise_exception(TT_FILL | (env->otherwin != 0 ? (TT_WOTHER | ((env->wstate & 0x38) >> 1)): ((env->wstate & 0x7) << 2))); } else { @@ -1285,7 +1285,7 @@ void OPPROTO op_eval_be(void) void OPPROTO op_eval_ble(void) { target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); - + T2 = Z | (N ^ V); } @@ -1373,7 +1373,7 @@ void OPPROTO op_eval_xbe(void) void OPPROTO op_eval_xble(void) { target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); - + T2 = Z | (N ^ V); } @@ -1802,7 +1802,7 @@ void OPPROTO op_mov_cc(void) void OPPROTO op_flushw(void) { if (env->cansave != NWINDOWS - 2) { - raise_exception(TT_SPILL | (env->otherwin != 0 ? + raise_exception(TT_SPILL | (env->otherwin != 0 ? (TT_WOTHER | ((env->wstate & 0x38) >> 1)): ((env->wstate & 0x7) << 2))); } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 21b1178a9..65a6ff2f3 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -9,7 +9,7 @@ void raise_exception(int tt) { env->exception_index = tt; cpu_loop_exit(); -} +} void check_ieee_exceptions() { @@ -137,7 +137,7 @@ GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); #endif -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) void helper_ld_asi(int asi, int size, int sign) { } @@ -173,7 +173,7 @@ void helper_ld_asi(int asi, int size, int sign) case 4: /* read MMU regs */ { int reg = (T0 >> 8) & 0xf; - + ret = env->mmuregs[reg]; if (reg == 3) /* Fault status cleared on read */ env->mmuregs[reg] = 0; @@ -291,7 +291,7 @@ void helper_st_asi(int asi, int size, int sign) { int reg = (T0 >> 8) & 0xf; uint32_t oldreg; - + oldreg = env->mmuregs[reg]; switch(reg) { case 0: @@ -342,7 +342,7 @@ void helper_st_asi(int asi, int size, int sign) // copy 32 bytes unsigned int i; uint32_t src = T1 & ~3, dst = T0 & ~3, temp; - + for (i = 0; i < 32; i += 4, src += 4, dst += 4) { temp = ldl_kernel(src); stl_kernel(dst, temp); @@ -489,7 +489,7 @@ void helper_ld_asi(int asi, int size, int sign) case 0x56: // I-MMU tag read { unsigned int i; - + for (i = 0; i < 64; i++) { // Valid, ctx match, vaddr match if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && @@ -510,7 +510,7 @@ void helper_ld_asi(int asi, int size, int sign) case 0x5e: // D-MMU tag read { unsigned int i; - + for (i = 0; i < 64; i++) { // Valid, ctx match, vaddr match if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && @@ -605,7 +605,7 @@ void helper_st_asi(int asi, int size, int sign) { int reg = (T0 >> 3) & 0xf; uint64_t oldreg; - + oldreg = env->immuregs[reg]; switch(reg) { case 0: // RO @@ -672,7 +672,7 @@ void helper_st_asi(int asi, int size, int sign) { int reg = (T0 >> 3) & 0xf; uint64_t oldreg; - + oldreg = env->dmmuregs[reg]; switch(reg) { case 0: // RO @@ -768,7 +768,7 @@ void helper_rett() raise_exception(TT_ILL_INSN); env->psret = 1; - cwp = (env->cwp + 1) & (NWINDOWS - 1); + cwp = (env->cwp + 1) & (NWINDOWS - 1); if (env->wim & (1 << cwp)) { raise_exception(TT_WIN_UNF); } @@ -949,7 +949,7 @@ void do_interrupt(int intno) count++; } #endif -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) if (env->tl == MAXTL) { cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); return; @@ -1010,14 +1010,14 @@ void do_interrupt(int intno) count++; } #endif -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) if (env->psret == 0) { cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); return; } #endif env->psret = 0; - cwp = (env->cwp - 1) & (NWINDOWS - 1); + cwp = (env->cwp - 1) & (NWINDOWS - 1); set_cwp(cwp); env->regwptr[9] = env->pc; env->regwptr[10] = env->npc; @@ -1030,7 +1030,7 @@ void do_interrupt(int intno) } #endif -#if !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) static void do_unaligned_access(target_ulong addr, int is_write, int is_user, void *retaddr); diff --git a/target-sparc/op_template.h b/target-sparc/op_template.h index ecf65fd70..f92061534 100644 --- a/target-sparc/op_template.h +++ b/target-sparc/op_template.h @@ -1,7 +1,7 @@ /* * SPARC micro operations (templates for various register related * operations) - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 54b861a84..84f69fcab 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -580,7 +580,7 @@ static inline void gen_movl_npc_im(target_ulong npc) #endif } -static inline void gen_goto_tb(DisasContext *s, int tb_num, +static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc, target_ulong npc) { TranslationBlock *tb; @@ -849,11 +849,11 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; - + if (cond == 0x0) { /* unconditional not taken */ if (a) { - dc->pc = dc->npc + 4; + dc->pc = dc->npc + 4; dc->npc = dc->pc + 4; } else { dc->pc = dc->npc; @@ -1019,7 +1019,7 @@ static void disas_sparc_insn(DisasContext * dc) } case 0x3: /* V9 BPr */ { - target = GET_FIELD_SP(insn, 0, 13) | + target = GET_FIELD_SP(insn, 0, 13) | (GET_FIELD_SP(insn, 20, 21) << 14); target = sign_extend(target, 16); target <<= 2; @@ -3347,7 +3347,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, exit_gen_loop: if (!dc->is_br) { - if (dc->pc != DYNAMIC_PC && + if (dc->pc != DYNAMIC_PC && (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { /* static PC and NPC: we can use direct chaining */ gen_branch(dc, dc->pc, dc->npc); @@ -3530,7 +3530,7 @@ int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def) #define GET_FLAG(a,b) ((env->psr & a)?b:'-') -void cpu_dump_state(CPUState *env, FILE *f, +void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { @@ -3574,7 +3574,7 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), - env->psrs?'S':'-', env->psrps?'P':'-', + env->psrs?'S':'-', env->psrps?'P':'-', env->psret?'E':'-', env->wim); #endif cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env)); diff --git a/tests/hello-arm.c b/tests/hello-arm.c index f84e6cb36..e2759a1c7 100644 --- a/tests/hello-arm.c +++ b/tests/hello-arm.c @@ -83,7 +83,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ : "r0","r1","r2","r3","lr"); \ __syscall_return(type,__res); \ } - + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ diff --git a/tests/linux-test.c b/tests/linux-test.c index 6ca902965..31daa9f2b 100644 --- a/tests/linux-test.c +++ b/tests/linux-test.c @@ -1,6 +1,6 @@ /* * linux and CPU test - * + * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify @@ -58,7 +58,7 @@ void error1(const char *filename, int line, const char *fmt, ...) int __chk_error(const char *filename, int line, int ret) { if (ret < 0) { - error1(filename, line, "%m (ret=%d, errno=%d)", + error1(filename, line, "%m (ret=%d, errno=%d)", ret, errno); } return ret; @@ -93,11 +93,11 @@ void test_file(void) if (getcwd(cur_dir, sizeof(cur_dir)) == NULL) error("getcwd"); - + chk_error(mkdir(TESTPATH, 0755)); - + chk_error(chdir(TESTPATH)); - + /* open/read/write/close/readv/writev/lseek */ fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644)); @@ -124,7 +124,7 @@ void test_file(void) error("read"); if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0) error("memcmp"); - + #define FOFFSET 16 ret = chk_error(lseek(fd, FOFFSET, SEEK_SET)); if (ret != 16) @@ -138,7 +138,7 @@ void test_file(void) error("readv"); if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0) error("memcmp"); - + chk_error(close(fd)); /* access */ @@ -171,18 +171,18 @@ void test_file(void) chk_error(ftruncate(fd, 50)); chk_error(fstat(fd, &st)); chk_error(close(fd)); - + if (st.st_size != 50) error("stat size"); if (!S_ISREG(st.st_mode)) error("stat mode"); - + /* symlink/lstat */ chk_error(symlink("file2", "file3")); chk_error(lstat("file3", &st)); if (!S_ISLNK(st.st_mode)) error("stat mode"); - + /* getdents */ dir = opendir(TESTPATH); if (!dir) @@ -241,7 +241,7 @@ void test_time(void) ti = tv2.tv_sec - tv.tv_sec; if (ti >= 2) error("gettimeofday"); - + chk_error(getrusage(RUSAGE_SELF, &rusg1)); for(i = 0;i < 10000; i++); chk_error(getrusage(RUSAGE_SELF, &rusg2)); @@ -272,7 +272,7 @@ char *pstrcat(char *buf, int buf_size, const char *s) { int len; len = strlen(buf); - if (len < buf_size) + if (len < buf_size) pstrcpy(buf + len, buf_size - len, s); return buf; } @@ -327,7 +327,7 @@ void test_socket(void) chk_error(getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &val, &len)); if (val != SOCK_STREAM) error("getsockopt"); - + pid = chk_error(fork()); if (pid == 0) { client_fd = client_socket(); @@ -419,11 +419,11 @@ void test_clone(void) int pid1, pid2, status1, status2; stack1 = malloc(STACK_SIZE); - pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE, + pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1")); stack2 = malloc(STACK_SIZE); - pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE, + pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2")); while (waitpid(pid1, &status1, 0) != pid1); @@ -465,7 +465,7 @@ void test_signal(void) sigemptyset(&act.sa_mask); act.sa_flags = 0; chk_error(sigaction(SIGALRM, &act, NULL)); - + it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 10 * 1000; it.it_value.tv_sec = 0; @@ -475,7 +475,7 @@ void test_signal(void) if (oit.it_value.tv_sec != it.it_value.tv_sec || oit.it_value.tv_usec != it.it_value.tv_usec) error("itimer"); - + while (alarm_count < 5) { usleep(10 * 1000); } @@ -498,7 +498,7 @@ void test_signal(void) if (setjmp(jmp_env) == 0) { *(uint8_t *)0 = 0; } - + act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = 0; diff --git a/tests/qruncom.c b/tests/qruncom.c index 421e6a99f..9d8f16bfd 100644 --- a/tests/qruncom.c +++ b/tests/qruncom.c @@ -59,7 +59,7 @@ uint64_t cpu_get_tsc(CPUState *env) return 0; } -static void set_gate(void *ptr, unsigned int type, unsigned int dpl, +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, unsigned long addr, unsigned int sel) { unsigned int e1, e2; @@ -141,7 +141,7 @@ static inline void pushw(CPUState *env, int val) *(uint16_t *)seg_to_linear(env->segs[R_SS].selector, env->regs[R_ESP]) = val; } -static void host_segv_handler(int host_signum, siginfo_t *info, +static void host_segv_handler(int host_signum, siginfo_t *info, void *puc) { if (cpu_signal_handler(host_signum, info, puc)) { @@ -160,9 +160,9 @@ int main(int argc, char **argv) if (argc != 2) usage(); filename = argv[1]; - - vm86_mem = mmap((void *)0x00000000, 0x110000, - PROT_WRITE | PROT_READ | PROT_EXEC, + + vm86_mem = mmap((void *)0x00000000, 0x110000, + PROT_WRITE | PROT_READ | PROT_EXEC, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); if (vm86_mem == MAP_FAILED) { perror("mmap"); @@ -185,7 +185,7 @@ int main(int argc, char **argv) /* install exception handler for CPU emulator */ { struct sigaction act; - + sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; // act.sa_flags |= SA_ONSTACK; @@ -218,23 +218,23 @@ int main(int argc, char **argv) /* flags setup : we activate the IRQs by default as in user mode. We also activate the VM86 flag to run DOS code */ env->eflags |= IF_MASK | VM_MASK; - + /* init basic registers */ env->eip = 0x100; env->regs[R_ESP] = 0xfffe; seg = (COM_BASE_ADDR - 0x100) >> 4; - cpu_x86_load_seg_cache(env, R_CS, seg, + cpu_x86_load_seg_cache(env, R_CS, seg, (seg << 4), 0xffff, 0); - cpu_x86_load_seg_cache(env, R_SS, seg, + cpu_x86_load_seg_cache(env, R_SS, seg, (seg << 4), 0xffff, 0); - cpu_x86_load_seg_cache(env, R_DS, seg, + cpu_x86_load_seg_cache(env, R_DS, seg, (seg << 4), 0xffff, 0); - cpu_x86_load_seg_cache(env, R_ES, seg, + cpu_x86_load_seg_cache(env, R_ES, seg, (seg << 4), 0xffff, 0); - cpu_x86_load_seg_cache(env, R_FS, seg, + cpu_x86_load_seg_cache(env, R_FS, seg, (seg << 4), 0xffff, 0); - cpu_x86_load_seg_cache(env, R_GS, seg, + cpu_x86_load_seg_cache(env, R_GS, seg, (seg << 4), 0xffff, 0); /* exception support */ @@ -260,7 +260,7 @@ int main(int argc, char **argv) set_idt(17, 0); set_idt(18, 0); set_idt(19, 0); - + /* put return code */ *seg_to_linear(env->segs[R_CS].selector, 0) = 0xb4; /* mov ah, $0 */ *seg_to_linear(env->segs[R_CS].selector, 1) = 0x00; @@ -275,7 +275,7 @@ int main(int argc, char **argv) env->regs[R_EDI] = 0xfffe; /* inform the emulator of the mmaped memory */ - page_set_flags(0x00000000, 0x110000, + page_set_flags(0x00000000, 0x110000, PAGE_WRITE | PAGE_READ | PAGE_EXEC | PAGE_VALID); for(;;) { diff --git a/tests/runcom.c b/tests/runcom.c index 43deeca09..94d3a39ff 100644 --- a/tests/runcom.c +++ b/tests/runcom.c @@ -51,7 +51,7 @@ static inline void pushw(struct vm86_regs *r, int val) void dump_regs(struct vm86_regs *r) { - fprintf(stderr, + fprintf(stderr, "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n" "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n" "EIP=%08lx EFL=%08lx\n" @@ -80,9 +80,9 @@ int main(int argc, char **argv) if (argc != 2) usage(); filename = argv[1]; - - vm86_mem = mmap((void *)0x00000000, 0x110000, - PROT_WRITE | PROT_READ | PROT_EXEC, + + vm86_mem = mmap((void *)0x00000000, 0x110000, + PROT_WRITE | PROT_READ | PROT_EXEC, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); if (vm86_mem == MAP_FAILED) { perror("mmap"); @@ -147,7 +147,7 @@ int main(int argc, char **argv) case VM86_INTx: { int int_num, ah; - + int_num = VM86_ARG(ret); if (int_num != 0x21) goto unknown_int; diff --git a/tests/test-i386-code16.S b/tests/test-i386-code16.S index e400e73fd..6692fe5e7 100644 --- a/tests/test-i386-code16.S +++ b/tests/test-i386-code16.S @@ -7,7 +7,7 @@ CS_SEG = 0xf code16_start: .globl code16_func1 - + /* basic test */ code16_func1 = . - code16_start mov $1, %eax @@ -24,7 +24,7 @@ code16_func2 = . - code16_start pop %ax data32 lret -/* test various jmp opcodes */ +/* test various jmp opcodes */ .globl code16_func3 code16_func3 = . - code16_start jmp 1f @@ -36,9 +36,9 @@ code16_func3 = . - code16_start jz 2f add $2, %ax 2: - + call myfunc - + lcall $CS_SEG, $(myfunc2 - code16_start) ljmp $CS_SEG, $(myjmp1 - code16_start) @@ -50,7 +50,7 @@ myjmp1_next: myjmp2_next: data32 lret - + myfunc2_addr: .short myfunc2 - code16_start .short CS_SEG diff --git a/tests/test-i386-muldiv.h b/tests/test-i386-muldiv.h index fd0d99134..015f59e15 100644 --- a/tests/test-i386-muldiv.h +++ b/tests/test-i386-muldiv.h @@ -1,5 +1,5 @@ -void glue(glue(test_, OP), b)(long op0, long op1) +void glue(glue(test_, OP), b)(long op0, long op1) { long res, s1, s0, flags; s0 = op0; @@ -8,7 +8,7 @@ void glue(glue(test_, OP), b)(long op0, long op1) flags = 0; asm ("push %4\n\t" "popf\n\t" - stringify(OP)"b %b2\n\t" + stringify(OP)"b %b2\n\t" "pushf\n\t" "pop %1\n\t" : "=a" (res), "=g" (flags) @@ -17,7 +17,7 @@ void glue(glue(test_, OP), b)(long op0, long op1) stringify(OP) "b", s0, s1, res, flags & CC_MASK); } -void glue(glue(test_, OP), w)(long op0h, long op0, long op1) +void glue(glue(test_, OP), w)(long op0h, long op0, long op1) { long res, s1, flags, resh; s1 = op1; @@ -26,7 +26,7 @@ void glue(glue(test_, OP), w)(long op0h, long op0, long op1) flags = 0; asm ("push %5\n\t" "popf\n\t" - stringify(OP) "w %w3\n\t" + stringify(OP) "w %w3\n\t" "pushf\n\t" "pop %1\n\t" : "=a" (res), "=g" (flags), "=d" (resh) @@ -35,7 +35,7 @@ void glue(glue(test_, OP), w)(long op0h, long op0, long op1) stringify(OP) "w", op0h, op0, s1, resh, res, flags & CC_MASK); } -void glue(glue(test_, OP), l)(long op0h, long op0, long op1) +void glue(glue(test_, OP), l)(long op0h, long op0, long op1) { long res, s1, flags, resh; s1 = op1; @@ -44,7 +44,7 @@ void glue(glue(test_, OP), l)(long op0h, long op0, long op1) flags = 0; asm ("push %5\n\t" "popf\n\t" - stringify(OP) "l %k3\n\t" + stringify(OP) "l %k3\n\t" "pushf\n\t" "pop %1\n\t" : "=a" (res), "=g" (flags), "=d" (resh) @@ -54,7 +54,7 @@ void glue(glue(test_, OP), l)(long op0h, long op0, long op1) } #if defined(__x86_64__) -void glue(glue(test_, OP), q)(long op0h, long op0, long op1) +void glue(glue(test_, OP), q)(long op0h, long op0, long op1) { long res, s1, flags, resh; s1 = op1; @@ -63,7 +63,7 @@ void glue(glue(test_, OP), q)(long op0h, long op0, long op1) flags = 0; asm ("push %5\n\t" "popf\n\t" - stringify(OP) "q %3\n\t" + stringify(OP) "q %3\n\t" "pushf\n\t" "pop %1\n\t" : "=a" (res), "=g" (flags), "=d" (resh) diff --git a/tests/test-i386-vm86.S b/tests/test-i386-vm86.S index a972f1b81..8575ae7ca 100644 --- a/tests/test-i386-vm86.S +++ b/tests/test-i386-vm86.S @@ -14,7 +14,7 @@ vm86_code_start: movw %ax, %es es movw $GET_OFFSET(int90_test), 0x90 * 4 es movw %cs, 0x90 * 4 + 2 - + /* launch int 0x90 */ int $0x90 @@ -24,23 +24,23 @@ vm86_code_start: movb $0x09, %ah int $0x21 - pushf + pushf popw %dx movb $0xff, %ah int $0x21 cli - pushf + pushf popw %dx movb $0xff, %ah int $0x21 - sti - pushfl + sti + pushfl popl %edx movb $0xff, %ah int $0x21 - + #if 0 movw $GET_OFFSET(IF_msg1), %dx movb $0x09, %ah @@ -54,11 +54,11 @@ vm86_code_start: cli #endif - pushf + pushf popw %dx movb $0xff, %ah int $0x21 - + pushfl movw %sp, %bx orw $0x200, (%bx) @@ -73,7 +73,7 @@ vm86_code_start: int $0x21 int90_test: - pushf + pushf pop %dx movb $0xff, %ah int $0x21 @@ -82,15 +82,15 @@ int90_test: movw 4(%bx), %dx movb $0xff, %ah int $0x21 - + movw $GET_OFFSET(int90_msg), %dx movb $0x09, %ah int $0x21 iret - + int90_msg: .string "INT90 started\n$" - + hello_world: .string "Hello VM86 world\n$" @@ -101,4 +101,3 @@ IF_msg1: .string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$" vm86_code_end: - \ No newline at end of file diff --git a/tests/test-i386.c b/tests/test-i386.c index 267391575..fbc6be639 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1,6 +1,6 @@ /* * x86 CPU test - * + * * Copyright (c) 2003 Fabrice Bellard * * This program is free software; you can redistribute it and/or modify @@ -470,7 +470,7 @@ void test_jcc(void) #define OP imul #include "test-i386-muldiv.h" -void test_imulw2(long op0, long op1) +void test_imulw2(long op0, long op1) { long res, s1, s0, flags; s0 = op0; @@ -479,7 +479,7 @@ void test_imulw2(long op0, long op1) flags = 0; asm volatile ("push %4\n\t" "popf\n\t" - "imulw %w2, %w0\n\t" + "imulw %w2, %w0\n\t" "pushf\n\t" "pop %1\n\t" : "=q" (res), "=g" (flags) @@ -488,7 +488,7 @@ void test_imulw2(long op0, long op1) "imulw", s0, s1, res, flags & CC_MASK); } -void test_imull2(long op0, long op1) +void test_imull2(long op0, long op1) { long res, s1, s0, flags; s0 = op0; @@ -497,7 +497,7 @@ void test_imull2(long op0, long op1) flags = 0; asm volatile ("push %4\n\t" "popf\n\t" - "imull %k2, %k0\n\t" + "imull %k2, %k0\n\t" "pushf\n\t" "pop %1\n\t" : "=q" (res), "=g" (flags) @@ -507,7 +507,7 @@ void test_imull2(long op0, long op1) } #if defined(__x86_64__) -void test_imulq2(long op0, long op1) +void test_imulq2(long op0, long op1) { long res, s1, s0, flags; s0 = op0; @@ -516,7 +516,7 @@ void test_imulq2(long op0, long op1) flags = 0; asm volatile ("push %4\n\t" "popf\n\t" - "imulq %2, %0\n\t" + "imulq %2, %0\n\t" "pushf\n\t" "pop %1\n\t" : "=q" (res), "=g" (flags) @@ -739,7 +739,7 @@ void fpu_clear_exceptions(void) uint32_t ignored[4]; long double fpregs[8]; } float_env32; - + asm volatile ("fnstenv %0\n" : : "m" (float_env32)); float_env32.fpus &= ~0x7f; asm volatile ("fldenv %0\n" : : "m" (float_env32)); @@ -758,14 +758,14 @@ void test_fcmp(double a, double b) "fstsw %%ax\n" : "=a" (fpus) : "t" (a), "u" (b)); - printf("fcom(%f %f)=%04lx \n", + printf("fcom(%f %f)=%04lx \n", a, b, fpus & (0x4500 | FPUS_EMASK)); fpu_clear_exceptions(); asm("fucom %2\n" "fstsw %%ax\n" : "=a" (fpus) : "t" (a), "u" (b)); - printf("fucom(%f %f)=%04lx\n", + printf("fucom(%f %f)=%04lx\n", a, b, fpus & (0x4500 | FPUS_EMASK)); if (TEST_FCOMI) { /* test f(u)comi instruction */ @@ -776,7 +776,7 @@ void test_fcmp(double a, double b) "pop %0\n" : "=r" (eflags), "=a" (fpus) : "t" (a), "u" (b)); - printf("fcomi(%f %f)=%04lx %02lx\n", + printf("fcomi(%f %f)=%04lx %02lx\n", a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); fpu_clear_exceptions(); asm("fucomi %3, %2\n" @@ -785,7 +785,7 @@ void test_fcmp(double a, double b) "pop %0\n" : "=r" (eflags), "=a" (fpus) : "t" (a), "u" (b)); - printf("fucomi(%f %f)=%04lx %02lx\n", + printf("fucomi(%f %f)=%04lx %02lx\n", a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C)); } fpu_clear_exceptions(); @@ -813,7 +813,7 @@ void test_fcvt(double a) printf("(float)%f = %f\n", a, fa); printf("(long double)%f = %Lf\n", a, la); printf("a=" FMT64X "\n", *(uint64_t *)&a); - printf("la=" FMT64X " %04x\n", *(uint64_t *)&la, + printf("la=" FMT64X " %04x\n", *(uint64_t *)&la, *(unsigned short *)((char *)(&la) + 8)); /* test all roundings */ @@ -855,7 +855,7 @@ void test_fbcd(double a) asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st"); asm("fbld %1" : "=t" (b) : "m" (bcd[0])); - printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", + printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b); } @@ -1041,7 +1041,7 @@ void test_bcd(void) TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A)); TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A)); TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A)); - + TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A)); TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A)); TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A)); @@ -1157,12 +1157,12 @@ void test_xchg(void) else op1 = op0; op2 = 0x6532432432434; - asm("cmpxchg8b %1\n" + asm("cmpxchg8b %1\n" "pushf\n" "pop %2\n" : "=A" (op0), "=m" (op1), "=g" (eflags) : "0" (op0), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32))); - printf("cmpxchg8b: op0=" FMT64X " op1=" FMT64X " CC=%02lx\n", + printf("cmpxchg8b: op0=" FMT64X " op1=" FMT64X " CC=%02lx\n", op0, op1, eflags & CC_Z); } } @@ -1276,9 +1276,9 @@ void test_segs(void) segoff.seg = MK_SEL(2); segoff.offset = 0xabcdef12; - asm volatile("lfs %2, %0\n\t" + asm volatile("lfs %2, %0\n\t" "movl %%fs, %1\n\t" - : "=r" (res), "=g" (res2) + : "=r" (res), "=g" (res2) : "m" (segoff)); printf("FS:reg = %04x:%08x\n", res2, res); @@ -1317,15 +1317,15 @@ void test_code16(void) modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ /* call the first function */ - asm volatile ("lcall %1, %2" + asm volatile ("lcall %1, %2" : "=a" (res) : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc"); printf("func1() = 0x%08x\n", res); - asm volatile ("lcall %2, %3" + asm volatile ("lcall %2, %3" : "=a" (res), "=c" (res2) : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc"); printf("func2() = 0x%08x spdec=%d\n", res, res2); - asm volatile ("lcall %1, %2" + asm volatile ("lcall %1, %2" : "=a" (res) : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc"); printf("func3() = 0x%08x\n", res); @@ -1373,7 +1373,7 @@ void test_misc(void) asm volatile ("mov %%cs, %0" : "=r" (cs_sel)); asm volatile ("push %1\n" - "call func_lret\n" + "call func_lret\n" : "=a" (res) : "r" (cs_sel) : "memory", "cc"); printf("func_lret=" FMTLX "\n", res); @@ -1381,11 +1381,11 @@ void test_misc(void) /* NOTE: we assume that &func_lret < 4GB */ desc.offset = (long)&func_lret; desc.seg = cs_sel; - + asm volatile ("xor %%rax, %%rax\n" "rex64 lcall %1\n" : "=a" (res) - : "m" (desc) + : "m" (desc) : "memory", "cc"); printf("func_lret2=" FMTLX "\n", res); @@ -1400,12 +1400,12 @@ void test_misc(void) printf("func_lret3=" FMTLX "\n", res); } #else - asm volatile ("push %%cs ; call %1" + asm volatile ("push %%cs ; call %1" : "=a" (res) : "m" (func_lret): "memory", "cc"); printf("func_lret=" FMTLX "\n", res); - asm volatile ("pushf ; push %%cs ; call %1" + asm volatile ("pushf ; push %%cs ; call %1" : "=a" (res) : "m" (func_iret): "memory", "cc"); printf("func_iret=" FMTLX "\n", res); @@ -1472,7 +1472,7 @@ void test_string(void) TEST_STRING(stos, ""); TEST_STRING(stos, "rep "); TEST_STRING(lods, ""); /* to verify stos */ - TEST_STRING(lods, "rep "); + TEST_STRING(lods, "rep "); TEST_STRING(movs, ""); TEST_STRING(movs, "rep "); TEST_STRING(lods, ""); /* to verify stos */ @@ -1526,8 +1526,8 @@ void test_vm86(void) uint8_t *vm86_mem; int seg, ret; - vm86_mem = mmap((void *)0x00000000, 0x110000, - PROT_WRITE | PROT_READ | PROT_EXEC, + vm86_mem = mmap((void *)0x00000000, 0x110000, + PROT_WRITE | PROT_READ | PROT_EXEC, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); if (vm86_mem == MAP_FAILED) { printf("ERROR: could not map vm86 memory"); @@ -1550,7 +1550,7 @@ void test_vm86(void) /* move code to proper address. We use the same layout as a .com dos program. */ - memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP, + memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP, &vm86_code_start, &vm86_code_end - &vm86_code_start); /* mark int 0x21 as being emulated */ @@ -1562,7 +1562,7 @@ void test_vm86(void) case VM86_INTx: { int int_num, ah, v; - + int_num = VM86_ARG(ret); if (int_num != 0x21) goto unknown_int; @@ -1665,7 +1665,7 @@ void test_exceptions(void) { struct sigaction act; volatile int val; - + act.sa_sigaction = sig_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO | SA_NODEFER; @@ -1718,7 +1718,7 @@ void test_exceptions(void) ldt.seg_not_present = 1; ldt.useable = 1; modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - + if (setjmp(jmp_env) == 0) { /* segment not present */ asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); @@ -1743,7 +1743,7 @@ void test_exceptions(void) /* read from an invalid address */ v1 = *(char *)0x1234; } - + /* test illegal instruction reporting */ printf("UD2 exception:\n"); if (setjmp(jmp_env) == 0) { @@ -1755,7 +1755,7 @@ void test_exceptions(void) /* now execute an invalid instruction */ asm volatile("lock nop"); } - + printf("INT exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("int $0xfd"); @@ -1827,7 +1827,7 @@ void test_exceptions(void) asm volatile ("pushf\n" "orl $0x00100, (%%esp)\n" "popf\n" - "movl $0xabcd, %0\n" + "movl $0xabcd, %0\n" "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory"); } printf("val=0x%x\n", val); @@ -1858,7 +1858,7 @@ void test_single_step(void) asm volatile ("pushf\n" "orl $0x00100, (%%esp)\n" "popf\n" - "movl $0xabcd, %0\n" + "movl $0xabcd, %0\n" /* jmp test */ "movl $3, %%ecx\n" @@ -1884,13 +1884,13 @@ void test_single_step(void) "rep cmpsb\n" "movl $4, %%ecx\n" "rep cmpsb\n" - + /* getpid() syscall: single step should skip one instruction */ "movl $20, %%eax\n" "int $0x80\n" "movl $0, %%eax\n" - + /* when modifying SS, trace is not done on the next instruction */ "movl %%ss, %%ecx\n" @@ -1906,12 +1906,12 @@ void test_single_step(void) "popl %%ss\n" "addl $1, %0\n" "movl $1, %%eax\n" - + "pushf\n" "andl $~0x00100, (%%esp)\n" "popf\n" - : "=m" (val) - : + : "=m" (val) + : : "cc", "memory", "eax", "ecx", "esi", "edi"); printf("val=%d\n", val); for(i = 0; i < 4; i++) @@ -2282,14 +2282,14 @@ void test_fxsave(void) " fxrstor %0\n" " fxsave %1\n" " fninit\n" - : "=m" (*(uint32_t *)fp2), "=m" (*(uint32_t *)fp) + : "=m" (*(uint32_t *)fp2), "=m" (*(uint32_t *)fp) : "m" (a), "m" (b)); printf("fpuc=%04x\n", fp->fpuc); printf("fpus=%04x\n", fp->fpus); printf("fptag=%04x\n", fp->fptag); for(i = 0; i < 3; i++) { printf("ST%d: " FMT64X " %04x\n", - i, + i, *(uint64_t *)&fp->fpregs1[i * 16], *(uint16_t *)&fp->fpregs1[i * 16 + 8]); } @@ -2301,7 +2301,7 @@ void test_fxsave(void) #endif for(i = 0; i < nb_xmm; i++) { printf("xmm%d: " FMT64X "" FMT64X "\n", - i, + i, *(uint64_t *)&fp->xmm_regs[i * 16], *(uint64_t *)&fp->xmm_regs[i * 16 + 8]); } @@ -2341,7 +2341,7 @@ void test_sse(void) MMX_OP2(pmulhuw); MMX_OP2(pmulhw); - + MMX_OP2(psubsb); MMX_OP2(psubsw); MMX_OP2(pminsw); @@ -2380,7 +2380,7 @@ void test_sse(void) asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "y" (a.q[0])); printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); - + asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); @@ -2392,21 +2392,21 @@ void test_sse(void) a.q[1] = test_values[0][1]; b.q[0] = test_values[1][0]; b.q[1] = test_values[1][1]; - asm volatile("maskmovq %1, %0" : + asm volatile("maskmovq %1, %0" : : "y" (a.q[0]), "y" (b.q[0]), "D" (&r) - : "memory"); - printf("%-9s: r=" FMT64X " a=" FMT64X " b=" FMT64X "\n", - "maskmov", - r.q[0], - a.q[0], + : "memory"); + printf("%-9s: r=" FMT64X " a=" FMT64X " b=" FMT64X "\n", + "maskmov", + r.q[0], + a.q[0], b.q[0]); - asm volatile("maskmovdqu %1, %0" : + asm volatile("maskmovdqu %1, %0" : : "x" (a.dq), "x" (b.dq), "D" (&r) - : "memory"); - printf("%-9s: r=" FMT64X "" FMT64X " a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X "\n", - "maskmov", - r.q[1], r.q[0], - a.q[1], a.q[0], + : "memory"); + printf("%-9s: r=" FMT64X "" FMT64X " a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X "\n", + "maskmov", + r.q[1], r.q[0], + a.q[1], a.q[0], b.q[1], b.q[0]); } @@ -2506,8 +2506,8 @@ void test_sse(void) SSE_OPS(cmpnlt); SSE_OPS(cmpnle); SSE_OPS(cmpord); - - + + a.d[0] = 2.7; a.d[1] = -3.4; b.d[0] = 45.7; diff --git a/tests/test_path.c b/tests/test_path.c index a9b52de37..7d6e83176 100644 --- a/tests/test_path.c +++ b/tests/test_path.c @@ -149,4 +149,4 @@ int main(int argc, char *argv[]) } return 0; } - + diff --git a/texi2pod.pl b/texi2pod.pl index 176627e9b..112d44974 100755 --- a/texi2pod.pl +++ b/texi2pod.pl @@ -229,7 +229,7 @@ while(<$inf>) { $inf = gensym(); # Try cwd and $ibase. - open($inf, "<" . $1) + open($inf, "<" . $1) or open($inf, "<" . $ibase . "/" . $1) or die "cannot open $1 or $ibase/$1: $!\n"; next; diff --git a/thunk.c b/thunk.c index bc9bd2881..a99d20ea0 100644 --- a/thunk.c +++ b/thunk.c @@ -1,6 +1,6 @@ /* * Generic thunking code to convert data between host and target CPU - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -64,7 +64,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types) int nb_fields, offset, max_align, align, size, i, j; se = struct_entries + id; - + /* first we count the number of fields */ type_ptr = types; nb_fields = 0; @@ -76,7 +76,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types) se->nb_fields = nb_fields; se->name = name; #ifdef DEBUG - printf("struct %s: id=%d nb_fields=%d\n", + printf("struct %s: id=%d nb_fields=%d\n", se->name, id, se->nb_fields); #endif /* now we can alloc the data */ @@ -100,7 +100,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types) se->size[i] = offset; se->align[i] = max_align; #ifdef DEBUG - printf("%s: size=%d align=%d\n", + printf("%s: size=%d align=%d\n", i == THUNK_HOST ? "host" : "target", offset, max_align); #endif } @@ -116,7 +116,7 @@ void thunk_register_struct_direct(int id, const char *name, StructEntry *se1) /* now we can define the main conversion functions */ -const argtype *thunk_convert(void *dst, const void *src, +const argtype *thunk_convert(void *dst, const void *src, const argtype *type_ptr, int to_host) { int type; @@ -182,7 +182,7 @@ const argtype *thunk_convert(void *dst, const void *src, uint8_t *d; const argtype *field_types; const int *dst_offsets, *src_offsets; - + se = struct_entries + *type_ptr++; if (se->convert[0] != NULL) { /* specific conversion is needed */ @@ -195,8 +195,8 @@ const argtype *thunk_convert(void *dst, const void *src, d = dst; s = src; for(i = 0;i < se->nb_fields; i++) { - field_types = thunk_convert(d + dst_offsets[i], - s + src_offsets[i], + field_types = thunk_convert(d + dst_offsets[i], + s + src_offsets[i], field_types, to_host); } } @@ -214,7 +214,7 @@ const argtype *thunk_convert(void *dst, const void *src, /* Utility function: Table-driven functions to translate bitmasks * between X86 and Alpha formats... */ -unsigned int target_to_host_bitmask(unsigned int x86_mask, +unsigned int target_to_host_bitmask(unsigned int x86_mask, bitmask_transtbl * trans_tbl) { bitmask_transtbl * btp; @@ -228,7 +228,7 @@ unsigned int target_to_host_bitmask(unsigned int x86_mask, return(alpha_mask); } -unsigned int host_to_target_bitmask(unsigned int alpha_mask, +unsigned int host_to_target_bitmask(unsigned int alpha_mask, bitmask_transtbl * trans_tbl) { bitmask_transtbl * btp; diff --git a/thunk.h b/thunk.h index 42fd96f3a..7811df397 100644 --- a/thunk.h +++ b/thunk.h @@ -1,6 +1,6 @@ /* * Generic thunking code to convert data between host and target CPU - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -69,7 +69,7 @@ typedef struct bitmask_transtbl { void thunk_register_struct(int id, const char *name, const argtype *types); void thunk_register_struct_direct(int id, const char *name, StructEntry *se1); -const argtype *thunk_convert(void *dst, const void *src, +const argtype *thunk_convert(void *dst, const void *src, const argtype *type_ptr, int to_host); #ifndef NO_THUNK_TYPE_SIZE @@ -150,9 +150,9 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host) #endif /* NO_THUNK_TYPE_SIZE */ -unsigned int target_to_host_bitmask(unsigned int x86_mask, +unsigned int target_to_host_bitmask(unsigned int x86_mask, bitmask_transtbl * trans_tbl); -unsigned int host_to_target_bitmask(unsigned int alpha_mask, +unsigned int host_to_target_bitmask(unsigned int alpha_mask, bitmask_transtbl * trans_tbl); #endif diff --git a/translate-all.c b/translate-all.c index bd5286f2a..108411d55 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1,6 +1,6 @@ /* * Host code generation - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -89,7 +89,7 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) for(;;) { c = *opc_ptr++; n = op_nb_args[c]; - fprintf(logfile, "0x%04x: %s", + fprintf(logfile, "0x%04x: %s", (int)(opc_ptr - opc_buf - 1), op_str[c]); for(i = 0; i < n; i++) { fprintf(logfile, " 0x%x", opparam_ptr[i]); @@ -110,11 +110,11 @@ static void dyngen_labels(long *gen_labels, int nb_gen_labels, uint8_t *gen_code_ptr; int c, i; unsigned long gen_code_addr[OPC_BUF_SIZE]; - + if (nb_gen_labels == 0) return; /* compute the address of each op code */ - + gen_code_ptr = gen_code_buf; i = 0; for(;;) { @@ -125,7 +125,7 @@ static void dyngen_labels(long *gen_labels, int nb_gen_labels, gen_code_ptr += opc_copy_size[c]; i++; } - + /* compute the address of each label */ for(i = 0; i < nb_gen_labels; i++) { gen_labels[i] = gen_code_addr[gen_labels[i]]; @@ -133,7 +133,7 @@ static void dyngen_labels(long *gen_labels, int nb_gen_labels, } /* return non zero if the very first instruction is invalid so that - the virtual CPU can trigger an exception. + the virtual CPU can trigger an exception. '*gen_code_size_ptr' contains the size of the generated code (host code). @@ -185,9 +185,9 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, return 0; } -/* The cpu state corresponding to 'searched_pc' is restored. +/* The cpu state corresponding to 'searched_pc' is restored. */ -int cpu_restore_state(TranslationBlock *tb, +int cpu_restore_state(TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc) { @@ -202,7 +202,7 @@ int cpu_restore_state(TranslationBlock *tb, #endif if (gen_intermediate_code_pc(env, tb) < 0) return -1; - + /* find opc index corresponding to search_pc */ tc_ptr = (unsigned long)tb->tc_ptr; if (searched_pc < tc_ptr) @@ -234,8 +234,8 @@ int cpu_restore_state(TranslationBlock *tb, fprintf(logfile, "0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]); } } - fprintf(logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", - searched_pc, j, gen_opc_pc[j] - tb->cs_base, + fprintf(logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", + searched_pc, j, gen_opc_pc[j] - tb->cs_base, (uint32_t)tb->cs_base); } #endif @@ -256,7 +256,7 @@ int cpu_restore_state(TranslationBlock *tb, } else if (npc == 2) { target_ulong t2 = (target_ulong)puc; /* jump PC: use T2 and the jump targets of the translation */ - if (t2) + if (t2) env->npc = gen_opc_jump_pc[0]; else env->npc = gen_opc_jump_pc[1]; @@ -279,7 +279,7 @@ int cpu_restore_state(TranslationBlock *tb, case INDEX_op_ ## op ## _user:\ case INDEX_op_ ## op ## _kernel #endif - + CASE3(stfd): CASE3(stfs): CASE3(lfd): diff --git a/translate-op.c b/translate-op.c index fddac70c4..37c61e1b7 100644 --- a/translate-op.c +++ b/translate-op.c @@ -1,6 +1,6 @@ /* * Host code generation - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or diff --git a/usb-linux.c b/usb-linux.c index 50386eaf6..ce2a5d9ff 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -2,7 +2,7 @@ * Linux host USB redirector * * Copyright (c) 2005 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -41,9 +41,9 @@ struct usb_ctrltransfer { }; typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id, - int vendor_id, int product_id, + int vendor_id, int product_id, const char *product_name, int speed); -static int usb_host_find_device(int *pbus_num, int *paddr, +static int usb_host_find_device(int *pbus_num, int *paddr, char *product_name, int product_name_size, const char *devname); @@ -65,7 +65,7 @@ static void usb_host_handle_reset(USBDevice *dev) done by the host OS */ ioctl(s->fd, USBDEVFS_RESET); #endif -} +} static void usb_host_handle_destroy(USBDevice *dev) { @@ -157,12 +157,12 @@ USBDevice *usb_host_device_open(const char *devname) int bus_num, addr; char product_name[PRODUCT_NAME_SZ]; - if (usb_host_find_device(&bus_num, &addr, + if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name), - devname) < 0) + devname) < 0) return NULL; - - snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", + + snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", bus_num, addr); fd = open(buf, O_RDWR); if (fd < 0) { @@ -176,7 +176,7 @@ USBDevice *usb_host_device_open(const char *devname) perror("read descr"); goto fail; } - + i = 0; dev_descr_len = descr[0]; if (dev_descr_len > descr_len) @@ -228,7 +228,7 @@ USBDevice *usb_host_device_open(const char *devname) #ifdef DEBUG printf("host USB device %d.%d grabbed\n", bus_num, addr); -#endif +#endif dev = qemu_mallocz(sizeof(USBHostDevice)); if (!dev) @@ -256,7 +256,7 @@ USBDevice *usb_host_device_open(const char *devname) } static int get_tag_value(char *buf, int buf_size, - const char *str, const char *tag, + const char *str, const char *tag, const char *stopchars) { const char *p; @@ -285,7 +285,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) int bus_num, addr, speed, device_count, class_id, product_id, vendor_id; int ret; char product_name[512]; - + f = fopen(USBDEVFS_PATH "/devices", "r"); if (!f) { term_printf("Could not open %s\n", USBDEVFS_PATH "/devices"); @@ -302,7 +302,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) if (line[0] == 'T' && line[1] == ':') { if (device_count && (vendor_id || product_id)) { /* New device. Add the previously discovered device. */ - ret = func(opaque, bus_num, addr, class_id, vendor_id, + ret = func(opaque, bus_num, addr, class_id, vendor_id, product_id, product_name, speed); if (ret) goto the_end; @@ -346,7 +346,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) } if (device_count && (vendor_id || product_id)) { /* Add the last device. */ - ret = func(opaque, bus_num, addr, class_id, vendor_id, + ret = func(opaque, bus_num, addr, class_id, vendor_id, product_id, product_name, speed); } the_end: @@ -362,9 +362,9 @@ typedef struct FindDeviceState { char product_name[PRODUCT_NAME_SZ]; } FindDeviceState; -static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, +static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, int class_id, - int vendor_id, int product_id, + int vendor_id, int product_id, const char *product_name, int speed) { FindDeviceState *s = opaque; @@ -381,10 +381,10 @@ static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, } } -/* the syntax is : - 'bus.addr' (decimal numbers) or +/* the syntax is : + 'bus.addr' (decimal numbers) or 'vendor_id:product_id' (hexa numbers) */ -static int usb_host_find_device(int *pbus_num, int *paddr, +static int usb_host_find_device(int *pbus_num, int *paddr, char *product_name, int product_name_size, const char *devname) { @@ -454,31 +454,31 @@ static const char *usb_class_str(uint8_t class) } void usb_info_device(int bus_num, int addr, int class_id, - int vendor_id, int product_id, + int vendor_id, int product_id, const char *product_name, int speed) { const char *class_str, *speed_str; switch(speed) { - case USB_SPEED_LOW: - speed_str = "1.5"; + case USB_SPEED_LOW: + speed_str = "1.5"; break; - case USB_SPEED_FULL: - speed_str = "12"; + case USB_SPEED_FULL: + speed_str = "12"; break; - case USB_SPEED_HIGH: - speed_str = "480"; + case USB_SPEED_HIGH: + speed_str = "480"; break; default: - speed_str = "?"; + speed_str = "?"; break; } - term_printf(" Device %d.%d, speed %s Mb/s\n", + term_printf(" Device %d.%d, speed %s Mb/s\n", bus_num, addr, speed_str); class_str = usb_class_str(class_id); - if (class_str) + if (class_str) term_printf(" %s:", class_str); else term_printf(" Class %02x:", class_id); @@ -488,9 +488,9 @@ void usb_info_device(int bus_num, int addr, int class_id, term_printf("\n"); } -static int usb_host_info_device(void *opaque, int bus_num, int addr, +static int usb_host_info_device(void *opaque, int bus_num, int addr, int class_id, - int vendor_id, int product_id, + int vendor_id, int product_id, const char *product_name, int speed) { diff --git a/vl.c b/vl.c index 57e5d6027..cea4871be 100644 --- a/vl.c +++ b/vl.c @@ -1,8 +1,8 @@ /* * QEMU System Emulator - * + * * Copyright (c) 2003-2007 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 @@ -287,7 +287,7 @@ void init_ioports(void) } /* size is the word size in byte */ -int register_ioport_read(int start, int length, int size, +int register_ioport_read(int start, int length, int size, IOPortReadFunc *func, void *opaque) { int i, bsize; @@ -312,7 +312,7 @@ int register_ioport_read(int start, int length, int size, } /* size is the word size in byte */ -int register_ioport_write(int start, int length, int size, +int register_ioport_write(int start, int length, int size, IOPortWriteFunc *func, void *opaque) { int i, bsize; @@ -358,7 +358,7 @@ void cpu_outb(CPUState *env, int addr, int val) #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outb: %04x %02x\n", addr, val); -#endif +#endif ioport_write_table[0][addr](ioport_opaque[addr], addr, val); #ifdef USE_KQEMU if (env) @@ -371,7 +371,7 @@ void cpu_outw(CPUState *env, int addr, int val) #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outw: %04x %04x\n", addr, val); -#endif +#endif ioport_write_table[1][addr](ioport_opaque[addr], addr, val); #ifdef USE_KQEMU if (env) @@ -634,7 +634,7 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) uint32_t high, low; #else uint32_t low, high; -#endif +#endif } l; } u, res; uint64_t rl, rh; @@ -700,7 +700,7 @@ static int64_t get_clock(void) struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec * 1000000000LL + ts.tv_nsec; - } else + } else #endif { /* XXX: using gettimeofday leads to problems if the date @@ -774,7 +774,7 @@ void cpu_disable_ticks(void) /***********************************************************/ /* timers */ - + #define QEMU_TIMER_REALTIME 0 #define QEMU_TIMER_VIRTUAL 1 @@ -1008,7 +1008,7 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) t = *pt; if (!t) break; - if (t->expire_time > expire_time) + if (t->expire_time > expire_time) break; pt = &t->next; } @@ -1037,7 +1037,7 @@ static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) { QEMUTimer *ts; - + for(;;) { ts = *ptimer_head; if (!ts || ts->expire_time > current_time) @@ -1045,7 +1045,7 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) /* remove timer from the list before calling the callback */ *ptimer_head = ts->next; ts->next = NULL; - + /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); } @@ -1122,7 +1122,7 @@ static int timer_load(QEMUFile *f, void *opaque, int version_id) } #ifdef _WIN32 -void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, +void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) #else static void host_alarm_handler(int host_signum) @@ -1606,8 +1606,8 @@ void qemu_chr_send_event(CharDriverState *s, int event) s->chr_send_event(s, event); } -void qemu_chr_add_handlers(CharDriverState *s, - IOCanRWHandler *fd_can_read, +void qemu_chr_add_handlers(CharDriverState *s, + IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, IOEventHandler *fd_event, void *opaque) @@ -1619,7 +1619,7 @@ void qemu_chr_add_handlers(CharDriverState *s, if (s->chr_update_read_handler) s->chr_update_read_handler(s); } - + static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { return len; @@ -1874,7 +1874,7 @@ static int socket_init(void) static int send_all(int fd, const uint8_t *buf, int len1) { int ret, len; - + len = len1; while (len > 0) { ret = send(fd, buf, len, 0); @@ -1964,7 +1964,7 @@ static void fd_chr_read(void *opaque) FDCharDriver *s = chr->opaque; int size, len; uint8_t buf[1024]; - + len = sizeof(buf); if (len > s->max_size) len = s->max_size; @@ -1988,7 +1988,7 @@ static void fd_chr_update_read_handler(CharDriverState *chr) if (s->fd_in >= 0) { if (nographic && s->fd_in == 0) { } else { - qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, + qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, fd_chr_read, NULL, chr); } } @@ -2125,7 +2125,7 @@ static void term_init(void) tty.c_cflag |= CS8; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; - + tcsetattr (0, TCSANOW, &tty); atexit(term_exit); @@ -2153,14 +2153,14 @@ static CharDriverState *qemu_chr_open_pty(void) struct termios tty; char slave_name[1024]; int master_fd, slave_fd; - + #if defined(__linux__) /* Not satisfying */ if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { return NULL; } #endif - + /* Disabling local echo and line-buffered output */ tcgetattr (master_fd, &tty); tty.c_lflag &= ~(ECHO|ICANON|ISIG); @@ -2172,14 +2172,14 @@ static CharDriverState *qemu_chr_open_pty(void) return qemu_chr_open_fd(master_fd, master_fd); } -static void tty_serial_init(int fd, int speed, +static void tty_serial_init(int fd, int speed, int parity, int data_bits, int stop_bits) { struct termios tty; speed_t spd; #if 0 - printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", + printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits); #endif tcgetattr (fd, &tty); @@ -2260,19 +2260,19 @@ static void tty_serial_init(int fd, int speed, } if (stop_bits == 2) tty.c_cflag |= CSTOPB; - + tcsetattr (fd, TCSANOW, &tty); } static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) { FDCharDriver *s = chr->opaque; - + switch(cmd) { case CHR_IOCTL_SERIAL_SET_PARAMS: { QEMUSerialSetParams *ssp = arg; - tty_serial_init(s->fd_in, ssp->speed, ssp->parity, + tty_serial_init(s->fd_in, ssp->speed, ssp->parity, ssp->data_bits, ssp->stop_bits); } break; @@ -2506,7 +2506,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename) COMSTAT comstat; DWORD size; DWORD err; - + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); if (!s->hsend) { fprintf(stderr, "Failed CreateEvent\n"); @@ -2525,12 +2525,12 @@ static int win_chr_init(CharDriverState *chr, const char *filename) s->hcom = NULL; goto fail; } - + if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { fprintf(stderr, "Failed SetupComm\n"); goto fail; } - + ZeroMemory(&comcfg, sizeof(COMMCONFIG)); size = sizeof(COMMCONFIG); GetDefaultCommConfig(filename, &comcfg, &size); @@ -2552,7 +2552,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename) fprintf(stderr, "Failed SetCommTimeouts\n"); goto fail; } - + if (!ClearCommError(s->hcom, &err, &comstat)) { fprintf(stderr, "Failed ClearCommError\n"); goto fail; @@ -2613,7 +2613,7 @@ static void win_chr_readfile(CharDriverState *chr) int ret, err; uint8_t buf[1024]; DWORD size; - + ZeroMemory(&s->orecv, sizeof(s->orecv)); s->orecv.hEvent = s->hrecv; ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); @@ -2637,7 +2637,7 @@ static void win_chr_read(CharDriverState *chr) s->len = s->max_size; if (s->len == 0) return; - + win_chr_readfile(chr); } @@ -2647,7 +2647,7 @@ static int win_chr_poll(void *opaque) WinCharState *s = chr->opaque; COMSTAT status; DWORD comerr; - + ClearCommError(s->hcom, &comerr, &status); if (status.cbInQue > 0) { s->len = status.cbInQue; @@ -2662,7 +2662,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename) { CharDriverState *chr; WinCharState *s; - + chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; @@ -2707,7 +2707,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) int ret; DWORD size; char openname[256]; - + s->fpipe = TRUE; s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -2720,7 +2720,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) fprintf(stderr, "Failed CreateEvent\n"); goto fail; } - + snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename); s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | @@ -2779,7 +2779,7 @@ static CharDriverState *qemu_chr_open_win_pipe(const char *filename) chr->opaque = s; chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; - + if (win_chr_pipe_init(chr, filename) < 0) { free(s); free(chr); @@ -2817,7 +2817,7 @@ static CharDriverState *qemu_chr_open_win_con(const char *filename) static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) { HANDLE fd_out; - + fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fd_out == INVALID_HANDLE_VALUE) @@ -3149,7 +3149,7 @@ static void tcp_chr_close(CharDriverState *chr) qemu_free(s); } -static CharDriverState *qemu_chr_open_tcp(const char *host_str, +static CharDriverState *qemu_chr_open_tcp(const char *host_str, int is_telnet, int is_unix) { @@ -3212,8 +3212,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, else #endif fd = socket(PF_INET, SOCK_STREAM, 0); - - if (fd < 0) + + if (fd < 0) goto fail; if (!is_waitconnect) @@ -3243,7 +3243,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); } - + ret = bind(fd, addr, addrlen); if (ret < 0) goto fail; @@ -3283,7 +3283,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, else qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr); } - + if (is_listen && is_waitconnect) { printf("QEMU waiting for connection on: %s\n", host_str); tcp_chr_accept(chr); @@ -3309,7 +3309,7 @@ CharDriverState *qemu_chr_open(const char *filename) return text_console_init(&display_state, p); } else if (!strcmp(filename, "null")) { return qemu_chr_open_null(); - } else + } else if (strstart(filename, "tcp:", &p)) { return qemu_chr_open_tcp(p, 0, 0); } else @@ -3340,11 +3340,11 @@ CharDriverState *qemu_chr_open(const char *filename) return qemu_chr_open_pty(); } else if (!strcmp(filename, "stdio")) { return qemu_chr_open_stdio(); - } else + } else #if defined(__linux__) if (strstart(filename, "/dev/parport", NULL)) { return qemu_chr_open_pp(filename); - } else + } else #endif #if defined(__linux__) || defined(__sun__) if (strstart(filename, "/dev/", NULL)) { @@ -3411,10 +3411,10 @@ static int parse_macaddr(uint8_t *macaddr, const char *p) for(i = 0; i < 6; i++) { macaddr[i] = strtol(p, (char **)&p, 16); if (i == 5) { - if (*p != '\0') + if (*p != '\0') return -1; } else { - if (*p != ':') + if (*p != ':') return -1; p++; } @@ -3641,7 +3641,7 @@ static int net_slirp_init(VLANState *vlan) slirp_inited = 1; slirp_init(); } - slirp_vc = qemu_new_vlan_client(vlan, + slirp_vc = qemu_new_vlan_client(vlan, slirp_receive, NULL, NULL); snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector"); return 0; @@ -3654,7 +3654,7 @@ static void net_slirp_redir(const char *redir_str) const char *p; struct in_addr guest_addr; int host_port, guest_port; - + if (!slirp_inited) { slirp_inited = 1; slirp_init(); @@ -3684,11 +3684,11 @@ static void net_slirp_redir(const char *redir_str) } if (!inet_aton(buf, &guest_addr)) goto fail; - + guest_port = strtol(p, &r, 0); if (r == p) goto fail; - + if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { fprintf(stderr, "qemu: could not set up redirection\n"); exit(1); @@ -3698,7 +3698,7 @@ static void net_slirp_redir(const char *redir_str) fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n"); exit(1); } - + #ifndef _WIN32 char smb_dir[1024]; @@ -3717,7 +3717,7 @@ static void smb_exit(void) break; if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) { - snprintf(filename, sizeof(filename), "%s/%s", + snprintf(filename, sizeof(filename), "%s/%s", smb_dir, de->d_name); unlink(filename); } @@ -3745,13 +3745,13 @@ void net_slirp_smb(const char *exported_dir) exit(1); } snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf"); - + f = fopen(smb_conf, "w"); if (!f) { fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf); exit(1); } - fprintf(f, + fprintf(f, "[global]\n" "private dir=%s\n" "smb ports=0\n" @@ -3777,7 +3777,7 @@ void net_slirp_smb(const char *exported_dir) snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", SMBD_COMMAND, smb_conf); - + slirp_add_exec(0, smb_cmdline, 4, 139); } @@ -3863,10 +3863,10 @@ static int tap_open(char *ifname, int ifname_size) } #elif defined(__sun__) #define TUNNEWPPA (('T'<<16) | 0x0001) -/* - * Allocate TAP device, returns opened fd. +/* + * Allocate TAP device, returns opened fd. * Stores dev name in the first arg(must be large enough). - */ + */ int tap_alloc(char *dev) { int tap_fd, if_fd, ppa = -1; @@ -3883,8 +3883,8 @@ int tap_alloc(char *dev) memset(&ifr, 0x0, sizeof(ifr)); if( *dev ){ - ptr = dev; - while( *ptr && !isdigit((int)*ptr) ) ptr++; + ptr = dev; + while( *ptr && !isdigit((int)*ptr) ) ptr++; ppa = atoi(ptr); } @@ -4001,7 +4001,7 @@ static int tap_open(char *ifname, int ifname_size) { struct ifreq ifr; int fd, ret; - + TFR(fd = open("/dev/net/tun", O_RDWR)); if (fd < 0) { fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); @@ -4076,7 +4076,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, s = net_tap_fd_init(vlan, fd); if (!s) return -1; - snprintf(s->vc->info_str, sizeof(s->vc->info_str), + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s setup_script=%s", ifname, setup_script); return 0; } @@ -4113,7 +4113,7 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, int size) static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) { NetSocketState *s = opaque; - sendto(s->fd, buf, size, 0, + sendto(s->fd, buf, size, 0, (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); } @@ -4127,7 +4127,7 @@ static void net_socket_send(void *opaque) size = recv(s->fd, buf1, sizeof(buf1), 0); if (size < 0) { err = socket_error(); - if (err != EWOULDBLOCK) + if (err != EWOULDBLOCK) goto eoc; } else if (size == 0) { /* end of connection */ @@ -4179,7 +4179,7 @@ static void net_socket_send_dgram(void *opaque) int size; size = recv(s->fd, s->buf, sizeof(s->buf), 0); - if (size < 0) + if (size < 0) return; if (size == 0) { /* end of connection */ @@ -4196,7 +4196,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) int val, ret; if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n", - inet_ntoa(mcastaddr->sin_addr), + inet_ntoa(mcastaddr->sin_addr), (int)ntohl(mcastaddr->sin_addr.s_addr)); return -1; @@ -4208,7 +4208,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) } val = 1; - ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); if (ret < 0) { perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); @@ -4220,12 +4220,12 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) perror("bind"); goto fail; } - + /* Add host to multicast group */ imr.imr_multiaddr = mcastaddr->sin_addr; imr.imr_interface.s_addr = htonl(INADDR_ANY); - ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imr, sizeof(struct ip_mreq)); if (ret < 0) { perror("setsockopt(IP_ADD_MEMBERSHIP)"); @@ -4234,7 +4234,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) /* Force mcast msgs to loopback (eg. several QEMUs in same host */ val = 1; - ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const char *)&val, sizeof(val)); if (ret < 0) { perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); @@ -4244,12 +4244,12 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) socket_set_nonblock(fd); return fd; fail: - if (fd >= 0) + if (fd >= 0) closesocket(fd); return -1; } -static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, +static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, int is_connected) { struct sockaddr_in saddr; @@ -4258,7 +4258,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, NetSocketState *s; /* fd passed: multicast: "learn" dgram_dst address from bound address and save it - * Because this may be "shared" socket from a "master" process, datagrams would be recv() + * Because this may be "shared" socket from a "master" process, datagrams would be recv() * by ONLY ONE process: we must "clone" this dgram socket --jjo */ @@ -4280,7 +4280,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, /* clone newfd to fd, close newfd */ dup2(newfd, fd); close(newfd); - + } else { fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", fd, strerror(errno)); @@ -4300,7 +4300,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, if (is_connected) s->dgram_dst=saddr; snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: fd=%d (%s mcast=%s:%d)", + "socket: fd=%d (%s mcast=%s:%d)", fd, is_connected? "cloned" : "", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return s; @@ -4312,7 +4312,7 @@ static void net_socket_connect(void *opaque) qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); } -static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, +static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, int is_connected) { NetSocketState *s; @@ -4320,7 +4320,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, if (!s) return NULL; s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, + s->vc = qemu_new_vlan_client(vlan, net_socket_receive, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "socket: fd=%d", fd); @@ -4332,7 +4332,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, return s; } -static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, +static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, int is_connected) { int so_type=-1, optlen=sizeof(so_type); @@ -4356,7 +4356,7 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, static void net_socket_accept(void *opaque) { - NetSocketListenState *s = opaque; + NetSocketListenState *s = opaque; NetSocketState *s1; struct sockaddr_in saddr; socklen_t len; @@ -4371,12 +4371,12 @@ static void net_socket_accept(void *opaque) break; } } - s1 = net_socket_fd_init(s->vlan, fd, 1); + s1 = net_socket_fd_init(s->vlan, fd, 1); if (!s1) { closesocket(fd); } else { snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), - "socket: connection from %s:%d", + "socket: connection from %s:%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); } } @@ -4389,7 +4389,7 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str) if (parse_host_port(&saddr, host_str) < 0) return -1; - + s = qemu_mallocz(sizeof(NetSocketListenState)); if (!s) return -1; @@ -4404,7 +4404,7 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str) /* allow fast reuse */ val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { perror("bind"); @@ -4463,7 +4463,7 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str) if (!s) return -1; snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: connect to %s:%d", + "socket: connect to %s:%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; } @@ -4487,9 +4487,9 @@ static int net_socket_mcast_init(VLANState *vlan, const char *host_str) return -1; s->dgram_dst = saddr; - + snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "socket: mcast=%s:%d", + "socket: mcast=%s:%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; @@ -4666,7 +4666,7 @@ static int net_client_init(const char *str) if (ret < 0) { fprintf(stderr, "Could not initialize device '%s'\n", device); } - + return ret; } @@ -4760,7 +4760,7 @@ static int usb_device_del(const char *devname) return -1; p = strchr(devname, '.'); - if (!p) + if (!p) return -1; bus_num = strtoul(devname, NULL, 0); addr = strtoul(p + 1, NULL, 0); @@ -4790,7 +4790,7 @@ void do_usb_add(const char *devname) { int ret; ret = usb_device_add(devname); - if (ret < 0) + if (ret < 0) term_printf("Could not add USB device '%s'\n", devname); } @@ -4798,7 +4798,7 @@ void do_usb_del(const char *devname) { int ret; ret = usb_device_del(devname); - if (ret < 0) + if (ret < 0) term_printf("Could not remove USB device '%s'\n", devname); } @@ -4818,20 +4818,20 @@ void usb_info(void) if (!dev) continue; switch(dev->speed) { - case USB_SPEED_LOW: - speed_str = "1.5"; + case USB_SPEED_LOW: + speed_str = "1.5"; break; - case USB_SPEED_FULL: - speed_str = "12"; + case USB_SPEED_FULL: + speed_str = "12"; break; - case USB_SPEED_HIGH: - speed_str = "480"; + case USB_SPEED_HIGH: + speed_str = "480"; break; default: - speed_str = "?"; + speed_str = "?"; break; } - term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n", + term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n", 0, dev->addr, speed_str, dev->devname); } } @@ -4927,10 +4927,10 @@ static IOHandlerRecord *first_io_handler; /* XXX: fd_read_poll should be suppressed, but an API change is necessary in the character devices to suppress fd_can_read(). */ -int qemu_set_fd_handler2(int fd, - IOCanRWHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, +int qemu_set_fd_handler2(int fd, + IOCanRWHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, void *opaque) { IOHandlerRecord **pioh, *ioh; @@ -4968,9 +4968,9 @@ int qemu_set_fd_handler2(int fd, return 0; } -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, void *opaque) { return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); @@ -5024,7 +5024,7 @@ typedef struct WaitObjects { } WaitObjects; static WaitObjects wait_objects = {0}; - + int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) { WaitObjects *w = &wait_objects; @@ -5051,7 +5051,7 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) w->events[i] = w->events[i + 1]; w->func[i] = w->func[i + 1]; w->opaque[i] = w->opaque[i + 1]; - } + } } if (found) w->num--; @@ -5125,7 +5125,7 @@ void qemu_fflush(QEMUFile *f) fseek(f->outfile, f->buf_offset, SEEK_SET); fwrite(f->buf, 1, f->buf_index, f->outfile); } else { - bdrv_pwrite(f->bs, f->base_offset + f->buf_offset, + bdrv_pwrite(f->bs, f->base_offset + f->buf_offset, f->buf, f->buf_index); } f->buf_offset += f->buf_index; @@ -5145,7 +5145,7 @@ static void qemu_fill_buffer(QEMUFile *f) if (len < 0) len = 0; } else { - len = bdrv_pread(f->bs, f->base_offset + f->buf_offset, + len = bdrv_pread(f->bs, f->base_offset + f->buf_offset, f->buf, IO_BUF_SIZE); if (len < 0) len = 0; @@ -5305,8 +5305,8 @@ typedef struct SaveStateEntry { static SaveStateEntry *first_se; -int register_savevm(const char *idstr, - int instance_id, +int register_savevm(const char *idstr, + int instance_id, int version_id, SaveStateHandler *save_state, LoadStateHandler *load_state, @@ -5359,7 +5359,7 @@ int qemu_savevm_state(QEMUFile *f) /* record size: filled later */ len_pos = qemu_ftell(f); qemu_put_be32(f, 0); - + se->save_state(f, se->opaque); /* fill record size */ @@ -5383,7 +5383,7 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id) SaveStateEntry *se; for(se = first_se; se != NULL; se = se->next) { - if (!strcmp(se->idstr, idstr) && + if (!strcmp(se->idstr, idstr) && instance_id == se->instance_id) return se; } @@ -5397,7 +5397,7 @@ int qemu_loadvm_state(QEMUFile *f) int64_t total_len, end_pos, cur_pos; unsigned int v; char idstr[256]; - + v = qemu_get_be32(f); if (v != QEMU_VM_FILE_MAGIC) goto fail; @@ -5419,18 +5419,18 @@ int qemu_loadvm_state(QEMUFile *f) version_id = qemu_get_be32(f); record_len = qemu_get_be32(f); #if 0 - printf("idstr=%s instance=0x%x version=%d len=%d\n", + printf("idstr=%s instance=0x%x version=%d len=%d\n", idstr, instance_id, version_id, record_len); #endif cur_pos = qemu_ftell(f); se = find_se(idstr, instance_id); if (!se) { - fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", + fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", instance_id, idstr); } else { ret = se->load_state(f, se->opaque, version_id); if (ret < 0) { - fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", + fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", instance_id, idstr); } } @@ -5481,7 +5481,7 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, { QEMUSnapshotInfo *sn_tab, *sn; int nb_sns, i, ret; - + ret = -ENOENT; nb_sns = bdrv_snapshot_list(bs, &sn_tab); if (nb_sns < 0) @@ -5523,7 +5523,7 @@ void do_savevm(const char *name) saved_vm_running = vm_running; vm_stop(0); - + must_delete = 0; if (name) { ret = bdrv_snapshot_find(bs, old_sn, name); @@ -5551,13 +5551,13 @@ void do_savevm(const char *name) sn->date_nsec = tv.tv_usec * 1000; #endif sn->vm_clock_nsec = qemu_get_clock(vm_clock); - + if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { term_printf("Device %s does not support VM state snapshots\n", bdrv_get_device_name(bs)); goto the_end; } - + /* save the VM state */ f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1); if (!f) { @@ -5571,7 +5571,7 @@ void do_savevm(const char *name) term_printf("Error %d while writing VM\n", ret); goto the_end; } - + /* create the snapshots */ for(i = 0; i < MAX_DISKS; i++) { @@ -5610,7 +5610,7 @@ void do_loadvm(const char *name) term_printf("No block device supports snapshots\n"); return; } - + /* Flush all IO requests so they don't interfere with the new state. */ qemu_aio_flush(); @@ -5650,7 +5650,7 @@ void do_loadvm(const char *name) bdrv_get_device_name(bs)); return; } - + /* restore the VM state */ f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0); if (!f) { @@ -5677,7 +5677,7 @@ void do_delvm(const char *name) term_printf("No block device supports snapshots\n"); return; } - + for(i = 0; i <= MAX_DISKS; i++) { bs1 = bs_table[i]; if (bdrv_has_snapshot(bs1)) { @@ -5757,14 +5757,14 @@ void cpu_save(QEMUFile *f, void *opaque) uint16_t fptag, fpus, fpuc, fpregs_format; uint32_t hflags; int i; - + for(i = 0; i < CPU_NB_REGS; i++) qemu_put_betls(f, &env->regs[i]); qemu_put_betls(f, &env->eip); qemu_put_betls(f, &env->eflags); hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ qemu_put_be32s(f, &hflags); - + /* FPU */ fpuc = env->fpuc; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; @@ -5772,7 +5772,7 @@ void cpu_save(QEMUFile *f, void *opaque) for(i = 0; i < 8; i++) { fptag |= ((!env->fptags[i]) << i); } - + qemu_put_be16s(f, &fpuc); qemu_put_be16s(f, &fpus); qemu_put_be16s(f, &fptag); @@ -5783,7 +5783,7 @@ void cpu_save(QEMUFile *f, void *opaque) fpregs_format = 1; #endif qemu_put_be16s(f, &fpregs_format); - + for(i = 0; i < 8; i++) { #ifdef USE_X86LDOUBLE { @@ -5810,16 +5810,16 @@ void cpu_save(QEMUFile *f, void *opaque) cpu_put_seg(f, &env->tr); cpu_put_seg(f, &env->gdt); cpu_put_seg(f, &env->idt); - + qemu_put_be32s(f, &env->sysenter_cs); qemu_put_be32s(f, &env->sysenter_esp); qemu_put_be32s(f, &env->sysenter_eip); - + qemu_put_betls(f, &env->cr[0]); qemu_put_betls(f, &env->cr[2]); qemu_put_betls(f, &env->cr[3]); qemu_put_betls(f, &env->cr[4]); - + for(i = 0; i < 8; i++) qemu_put_betls(f, &env->dr[i]); @@ -5887,7 +5887,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be16s(f, &fpus); qemu_get_be16s(f, &fptag); qemu_get_be16s(f, &fpregs_format); - + /* NOTE: we cannot always restore the FPU state if the image come from a host with a different 'USE_X86LDOUBLE' define. We guess if we are in an MMX state to restore correctly in that case. */ @@ -5895,7 +5895,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) for(i = 0; i < 8; i++) { uint64_t mant; uint16_t exp; - + switch(fpregs_format) { case 0: mant = qemu_get_be64(f); @@ -5926,7 +5926,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) } #else env->fpregs[i].mmx.MMX_Q(0) = mant; -#endif +#endif break; default: return -EINVAL; @@ -5941,23 +5941,23 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) for(i = 0; i < 8; i++) { env->fptags[i] = (fptag >> i) & 1; } - + for(i = 0; i < 6; i++) cpu_get_seg(f, &env->segs[i]); cpu_get_seg(f, &env->ldt); cpu_get_seg(f, &env->tr); cpu_get_seg(f, &env->gdt); cpu_get_seg(f, &env->idt); - + qemu_get_be32s(f, &env->sysenter_cs); qemu_get_be32s(f, &env->sysenter_esp); qemu_get_be32s(f, &env->sysenter_eip); - + qemu_get_betls(f, &env->cr[0]); qemu_get_betls(f, &env->cr[2]); qemu_get_betls(f, &env->cr[3]); qemu_get_betls(f, &env->cr[4]); - + for(i = 0; i < 8; i++) qemu_get_betls(f, &env->dr[i]); @@ -5978,7 +5978,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be64s(f, &env->fmask); qemu_get_be64s(f, &env->kernelgsbase); #endif - if (version_id >= 4) + if (version_id >= 4) qemu_get_be32s(f, &env->smbase); /* XXX: compute hflags from scratch, except for CPL and IIF */ @@ -6288,7 +6288,7 @@ static int ram_compress_open(RamCompressState *s, QEMUFile *f) memset(s, 0, sizeof(*s)); s->f = f; ret = deflateInit2(&s->zstream, 1, - Z_DEFLATED, 15, + Z_DEFLATED, 15, 9, Z_DEFAULT_STRATEGY); if (ret != Z_OK) return -1; @@ -6399,7 +6399,7 @@ static void ram_save(QEMUFile *f, void *opaque) int i; RamCompressState s1, *s = &s1; uint8_t buf[10]; - + qemu_put_be32(f, phys_ram_size); if (ram_compress_open(s, f) < 0) return; @@ -6414,7 +6414,7 @@ static void ram_save(QEMUFile *f, void *opaque) sector_num = -1; for(j = 0; j < MAX_DISKS; j++) { if (bs_table[j]) { - sector_num = bdrv_hash_find(bs_table[j], + sector_num = bdrv_hash_find(bs_table[j], phys_ram_base + i, BDRV_HASH_BLOCK_SIZE); if (sector_num >= 0) break; @@ -6426,7 +6426,7 @@ static void ram_save(QEMUFile *f, void *opaque) buf[1] = j; cpu_to_be64wu((uint64_t *)(buf + 2), sector_num); ram_compress_buf(s, buf, 10); - } else + } else #endif { // normal_compress: @@ -6462,7 +6462,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) fprintf(stderr, "Error while reading ram block address=0x%08x", i); goto error; } - } else + } else #if 0 if (buf[0] == 1) { int bs_index; @@ -6475,13 +6475,13 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) fprintf(stderr, "Invalid block device index %d\n", bs_index); goto error; } - if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i, + if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE / 512) < 0) { - fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n", + fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n", bs_index, sector_num); goto error; } - } else + } else #endif { error: @@ -6669,7 +6669,7 @@ void vm_start(void) } } -void vm_stop(int reason) +void vm_stop(int reason) { if (vm_running) { cpu_disable_ticks(); @@ -6766,15 +6766,15 @@ void main_loop_wait(int timeout) if (ret == 0) { int err; WaitObjects *w = &wait_objects; - + ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout); if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { if (w->func[ret - WAIT_OBJECT_0]) w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); - - /* Check for additional signaled events */ + + /* Check for additional signaled events */ for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) { - + /* Check if event is signaled */ ret2 = WaitForSingleObject(w->events[i], 0); if(ret2 == WAIT_OBJECT_0) { @@ -6784,8 +6784,8 @@ void main_loop_wait(int timeout) } else { err = GetLastError(); fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err); - } - } + } + } } else if (ret == WAIT_TIMEOUT) { } else { err = GetLastError(); @@ -6815,7 +6815,7 @@ void main_loop_wait(int timeout) nfds = ioh->fd; } } - + tv.tv_sec = 0; #ifdef _WIN32 tv.tv_usec = 0; @@ -6847,7 +6847,7 @@ void main_loop_wait(int timeout) if (ioh->deleted) { *pioh = ioh->next; qemu_free(ioh); - } else + } else pioh = &ioh->next; } } @@ -6864,20 +6864,20 @@ void main_loop_wait(int timeout) qemu_aio_poll(); if (vm_running) { - qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], + qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)); /* run dma transfers, if any */ DMA_run(); } /* real time timers */ - qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], + qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock)); /* Check bottom-halves last in case any of the earlier events triggered them. */ qemu_bh_poll(); - + } static CPUState *cur_cpu; @@ -7620,19 +7620,19 @@ int main(int argc, char **argv) for(i = 1; i < MAX_SERIAL_PORTS; i++) serial_devices[i][0] = '\0'; serial_device_index = 0; - + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc"); for(i = 1; i < MAX_PARALLEL_PORTS; i++) parallel_devices[i][0] = '\0'; parallel_device_index = 0; - + usb_devices_index = 0; - + nb_net_clients = 0; nb_nics = 0; /* default mac address of the first network interface */ - + optind = 1; for(;;) { if (optind >= argc) @@ -7650,7 +7650,7 @@ int main(int argc, char **argv) popt = qemu_options; for(;;) { if (!popt->name) { - fprintf(stderr, "%s: invalid option -- '%s'\n", + fprintf(stderr, "%s: invalid option -- '%s'\n", argv[0], r); exit(1); } @@ -7677,7 +7677,7 @@ int main(int argc, char **argv) printf("Supported machines are:\n"); for(m = first_machine; m != NULL; m = m->next) { printf("%-10s %s%s\n", - m->name, m->desc, + m->name, m->desc, m == first_machine ? " (default)" : ""); } exit(*optarg != '?'); @@ -7789,7 +7789,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_boot: boot_device = optarg[0]; - if (boot_device != 'a' && + if (boot_device != 'a' && #if defined(TARGET_SPARC) || defined(TARGET_I386) // Network boot boot_device != 'n' && @@ -7836,7 +7836,7 @@ int main(int argc, char **argv) break; #endif case QEMU_OPTION_redir: - net_slirp_redir(optarg); + net_slirp_redir(optarg); break; #endif #ifdef HAS_AUDIO @@ -7865,7 +7865,7 @@ int main(int argc, char **argv) { int mask; CPULogItem *item; - + mask = cpu_str_to_log_mask(optarg); if (!mask) { printf("Log items (comma separated):\n"); @@ -7929,7 +7929,7 @@ int main(int argc, char **argv) if (*p == 'x') { p++; depth = strtol(p, (char **)&p, 10); - if (depth != 8 && depth != 15 && depth != 16 && + if (depth != 8 && depth != 15 && depth != 16 && depth != 24 && depth != 32) goto graphic_error; } else if (*p == '\0') { @@ -7937,7 +7937,7 @@ int main(int argc, char **argv) } else { goto graphic_error; } - + graphic_width = w; graphic_height = h; graphic_depth = depth; @@ -7959,7 +7959,7 @@ int main(int argc, char **argv) fprintf(stderr, "qemu: too many serial ports\n"); exit(1); } - pstrcpy(serial_devices[serial_device_index], + pstrcpy(serial_devices[serial_device_index], sizeof(serial_devices[0]), optarg); serial_device_index++; break; @@ -7968,7 +7968,7 @@ int main(int argc, char **argv) fprintf(stderr, "qemu: too many parallel ports\n"); exit(1); } - pstrcpy(parallel_devices[parallel_device_index], + pstrcpy(parallel_devices[parallel_device_index], sizeof(parallel_devices[0]), optarg); parallel_device_index++; break; @@ -8144,7 +8144,7 @@ int main(int argc, char **argv) if (!linux_boot && boot_device != 'n' && - hd_filename[0] == '\0' && + hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') help(1); @@ -8158,7 +8158,7 @@ int main(int argc, char **argv) } setvbuf(stdout, NULL, _IOLBF, 0); - + init_timers(); init_timer_alarm(); qemu_aio_init(); @@ -8365,7 +8365,7 @@ int main(int argc, char **argv) if (devname[0] != '\0' && strcmp(devname, "none")) { serial_hds[i] = qemu_chr_open(devname); if (!serial_hds[i]) { - fprintf(stderr, "qemu: could not open serial device '%s'\n", + fprintf(stderr, "qemu: could not open serial device '%s'\n", devname); exit(1); } @@ -8379,7 +8379,7 @@ int main(int argc, char **argv) if (devname[0] != '\0' && strcmp(devname, "none")) { parallel_hds[i] = qemu_chr_open(devname); if (!parallel_hds[i]) { - fprintf(stderr, "qemu: could not open parallel device '%s'\n", + fprintf(stderr, "qemu: could not open parallel device '%s'\n", devname); exit(1); } diff --git a/vl.h b/vl.h index 819908b22..f8d12a393 100644 --- a/vl.h +++ b/vl.h @@ -1,8 +1,8 @@ /* * QEMU System Emulator header - * + * * Copyright (c) 2003 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -248,13 +248,13 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); typedef int IOCanRWHandler(void *opaque); typedef void IOHandler(void *opaque); -int qemu_set_fd_handler2(int fd, - IOCanRWHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, +int qemu_set_fd_handler2(int fd, + IOCanRWHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, void *opaque); int qemu_set_fd_handler(int fd, - IOHandler *fd_read, + IOHandler *fd_read, IOHandler *fd_write, void *opaque); @@ -324,8 +324,8 @@ CharDriverState *qemu_chr_open(const char *filename); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); void qemu_chr_send_event(CharDriverState *s, int event); -void qemu_chr_add_handlers(CharDriverState *s, - IOCanRWHandler *fd_can_read, +void qemu_chr_add_handlers(CharDriverState *s, + IOCanRWHandler *fd_can_read, IOReadHandler *fd_read, IOEventHandler *fd_event, void *opaque); @@ -528,8 +528,8 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); typedef void SaveStateHandler(QEMUFile *f, void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); -int register_savevm(const char *idstr, - int instance_id, +int register_savevm(const char *idstr, + int instance_id, int version_id, SaveStateHandler *save_state, LoadStateHandler *load_state, @@ -573,9 +573,9 @@ extern BlockDriver bdrv_parallels; typedef struct BlockDriverInfo { /* in bytes, 0 if irrelevant */ - int cluster_size; + int cluster_size; /* offset at which the VM state can be saved (0 if not possible) */ - int64_t vm_state_offset; + int64_t vm_state_offset; } BlockDriverInfo; typedef struct QEMUSnapshotInfo { @@ -601,7 +601,7 @@ typedef struct QEMUSnapshotInfo { void bdrv_init(void); BlockDriver *bdrv_find_format(const char *format_name); -int bdrv_create(BlockDriver *drv, +int bdrv_create(BlockDriver *drv, const char *filename, int64_t size_in_sectors, const char *backing_file, int flags); BlockDriverState *bdrv_new(const char *device_name); @@ -611,13 +611,13 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags); int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, BlockDriver *drv); void bdrv_close(BlockDriverState *bs); -int bdrv_read(BlockDriverState *bs, int64_t sector_num, +int bdrv_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); -int bdrv_write(BlockDriverState *bs, int64_t sector_num, +int bdrv_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); -int bdrv_pread(BlockDriverState *bs, int64_t offset, +int bdrv_pread(BlockDriverState *bs, int64_t offset, void *buf, int count); -int bdrv_pwrite(BlockDriverState *bs, int64_t offset, +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, const void *buf, int count); int bdrv_truncate(BlockDriverState *bs, int64_t offset); int64_t bdrv_getlength(BlockDriverState *bs); @@ -657,11 +657,11 @@ void bdrv_flush(BlockDriverState *bs); #define BIOS_ATA_TRANSLATION_LARGE 3 #define BIOS_ATA_TRANSLATION_RECHS 4 -void bdrv_set_geometry_hint(BlockDriverState *bs, +void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs); void bdrv_set_type_hint(BlockDriverState *bs, int type); void bdrv_set_translation_hint(BlockDriverState *bs, int translation); -void bdrv_get_geometry_hint(BlockDriverState *bs, +void bdrv_get_geometry_hint(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs); int bdrv_get_type_hint(BlockDriverState *bs); int bdrv_get_translation_hint(BlockDriverState *bs); @@ -672,7 +672,7 @@ int bdrv_media_changed(BlockDriverState *bs); int bdrv_is_locked(BlockDriverState *bs); void bdrv_set_locked(BlockDriverState *bs, int locked); void bdrv_eject(BlockDriverState *bs, int eject_flag); -void bdrv_set_change_cb(BlockDriverState *bs, +void bdrv_set_change_cb(BlockDriverState *bs, void (*change_cb)(void *opaque), void *opaque); void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); void bdrv_info(void); @@ -680,21 +680,21 @@ BlockDriverState *bdrv_find(const char *name); void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); int bdrv_is_encrypted(BlockDriverState *bs); int bdrv_set_key(BlockDriverState *bs, const char *key); -void bdrv_iterate_format(void (*it)(void *opaque, const char *name), +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque); const char *bdrv_get_device_name(BlockDriverState *bs); -int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, +int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); -void bdrv_get_backing_filename(BlockDriverState *bs, +void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size); -int bdrv_snapshot_create(BlockDriverState *bs, +int bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); -int bdrv_snapshot_goto(BlockDriverState *bs, +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, +int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); @@ -706,7 +706,7 @@ void path_combine(char *dest, int dest_size, #ifndef QEMU_TOOL -typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, +typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -740,9 +740,9 @@ extern target_phys_addr_t isa_mem_base; typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); -int register_ioport_read(int start, int length, int size, +int register_ioport_read(int start, int length, int size, IOPortReadFunc *func, void *opaque); -int register_ioport_write(int start, int length, int size, +int register_ioport_write(int start, int length, int size, IOPortWriteFunc *func, void *opaque); void isa_unassign_ioport(int start, int length); @@ -755,11 +755,11 @@ extern target_phys_addr_t pci_mem_base; typedef struct PCIBus PCIBus; typedef struct PCIDevice PCIDevice; -typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, uint32_t address, uint32_t data, int len); -typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, uint32_t address, int len); -typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type); #define PCI_ADDRESS_SPACE_MEM 0x00 @@ -798,7 +798,7 @@ struct PCIDevice { int devfn; char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; - + /* do not access the following fields */ PCIConfigReadFunc *config_read; PCIConfigWriteFunc *config_write; @@ -814,16 +814,16 @@ struct PCIDevice { PCIDevice *pci_register_device(PCIBus *bus, const char *name, int instance_size, int devfn, - PCIConfigReadFunc *config_read, + PCIConfigReadFunc *config_read, PCIConfigWriteFunc *config_write); -void pci_register_io_region(PCIDevice *pci_dev, int region_num, - uint32_t size, int type, +void pci_register_io_region(PCIDevice *pci_dev, int region_num, + uint32_t size, int type, PCIMapIORegionFunc *map_func); -uint32_t pci_default_read_config(PCIDevice *d, +uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len); -void pci_default_write_config(PCIDevice *d, +void pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len); void pci_device_save(PCIDevice *s, QEMUFile *f); int pci_device_load(PCIDevice *s, QEMUFile *f); @@ -940,9 +940,9 @@ static inline void dpy_resize(DisplayState *s, int w, int h) s->dpy_resize(s, w, h); } -int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, +int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); -int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, +int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size, unsigned long vga_bios_offset, int vga_bios_size); int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, @@ -951,9 +951,9 @@ int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, int it_shift); /* cirrus_vga.c */ -void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, +void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); -void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, +void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); /* vmware_vga.c */ @@ -1032,7 +1032,7 @@ extern BlockDriverState *fd_table[MAX_FD]; typedef struct fdctrl_t fdctrl_t; -fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, +fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, target_phys_addr_t io_base, BlockDriverState **fds); int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); @@ -1286,9 +1286,9 @@ void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, /* sparc32_dma.c */ void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, void *iommu, qemu_irq **dev_irq, qemu_irq **reset); -void ledma_memory_read(void *opaque, target_phys_addr_t addr, +void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); -void ledma_memory_write(void *opaque, target_phys_addr_t addr, +void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void espdma_memory_read(void *opaque, uint8_t *buf, int len); void espdma_memory_write(void *opaque, uint8_t *buf, int len); @@ -1354,9 +1354,9 @@ int adb_request(ADBBusState *s, uint8_t *buf_out, const uint8_t *buf, int len); int adb_poll(ADBBusState *s, uint8_t *buf_out); -ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceRequest *devreq, - ADBDeviceReset *devreset, +ADBDevice *adb_register_device(ADBBusState *s, int devaddr, + ADBDeviceRequest *devreq, + ADBDeviceReset *devreset, void *opaque); void adb_kbd_init(ADBBusState *bus); void adb_mouse_init(ADBBusState *bus); @@ -1508,14 +1508,14 @@ typedef struct pflash_t pflash_t; pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, BlockDriverState *bs, uint32_t sector_len, int nb_blocs, int width, - uint16_t id0, uint16_t id1, + uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); /* nand.c */ struct nand_flash_s; struct nand_flash_s *nand_init(int manf_id, int chip_id); void nand_done(struct nand_flash_s *s); -void nand_setpins(struct nand_flash_s *s, +void nand_setpins(struct nand_flash_s *s, int cle, int ale, int ce, int wp, int gnd); void nand_getpins(struct nand_flash_s *s, int *rb); void nand_setio(struct nand_flash_s *s, uint8_t value); diff --git a/vnc.c b/vnc.c index 75e4fc968..65bde67f6 100644 --- a/vnc.c +++ b/vnc.c @@ -1,9 +1,9 @@ /* * QEMU VNC display driver - * + * * Copyright (C) 2006 Anthony Liguori * 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 @@ -68,7 +68,7 @@ typedef void VncWritePixels(VncState *vs, void *data, int size); typedef void VncSendHextileTile(VncState *vs, int x, int y, int w, int h, - uint32_t *last_bg, + uint32_t *last_bg, uint32_t *last_fg, int *has_bg, int *has_fg); @@ -226,7 +226,7 @@ static inline void vnc_set_bits(uint32_t *d, int n, int nb_words) d[j++] = -1; n -= 32; } - if (n > 0) + if (n > 0) d[j++] = (1 << n) - 1; while (j < nb_words) d[j++] = 0; @@ -237,7 +237,7 @@ static inline int vnc_get_bit(const uint32_t *d, int k) return (d[k >> 5] >> (k & 0x1f)) & 1; } -static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2, +static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2, int nb_words) { int i; @@ -314,8 +314,8 @@ static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) r = (v >> vs->red_shift1) & vs->red_max; g = (v >> vs->green_shift1) & vs->green_max; b = (v >> vs->blue_shift1) & vs->blue_max; - v = (r << vs->red_shift) | - (g << vs->green_shift) | + v = (r << vs->red_shift) | + (g << vs->green_shift) | (b << vs->blue_shift); switch(vs->pix_bpp) { case 1: @@ -409,7 +409,7 @@ static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, i has_fg = has_bg = 0; for (j = y; j < (y + h); j += 16) { for (i = x; i < (x + w); i += 16) { - vs->send_hextile_tile(vs, i, j, + vs->send_hextile_tile(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), &last_bg32, &last_fg32, &has_bg, &has_fg); } @@ -912,7 +912,7 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) int keycode; keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); - + /* QEMU console switch */ switch(keycode) { case 0x2a: /* Left Shift */ @@ -926,7 +926,7 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) else vs->modifiers_state[keycode] = 0; break; - case 0x02 ... 0x0a: /* '1' to '9' keys */ + case 0x02 ... 0x0a: /* '1' to '9' keys */ if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) { /* Reset the modifiers sent to the current console */ reset_keys(vs); @@ -1015,7 +1015,7 @@ static void framebuffer_update_request(VncState *vs, int incremental, char *old_row = vs->old_data + y_position * vs->ds->linesize; for (i = 0; i < h; i++) { - vnc_set_bits(vs->dirty_row[y_position + i], + vnc_set_bits(vs->dirty_row[y_position + i], (vs->ds->width / 16), VNC_DIRTY_WORDS); memset(old_row, 42, vs->ds->width * vs->depth); old_row += vs->ds->linesize; @@ -1087,29 +1087,29 @@ static void set_pixel_format(VncState *vs, vnc_client_error(vs); return; } - if (bits_per_pixel == 32 && + if (bits_per_pixel == 32 && host_big_endian_flag == big_endian_flag && red_max == 0xff && green_max == 0xff && blue_max == 0xff && red_shift == 16 && green_shift == 8 && blue_shift == 0) { vs->depth = 4; vs->write_pixels = vnc_write_pixels_copy; vs->send_hextile_tile = send_hextile_tile_32; - } else - if (bits_per_pixel == 16 && + } else + if (bits_per_pixel == 16 && host_big_endian_flag == big_endian_flag && red_max == 31 && green_max == 63 && blue_max == 31 && red_shift == 11 && green_shift == 5 && blue_shift == 0) { vs->depth = 2; vs->write_pixels = vnc_write_pixels_copy; vs->send_hextile_tile = send_hextile_tile_16; - } else - if (bits_per_pixel == 8 && + } else + if (bits_per_pixel == 8 && red_max == 7 && green_max == 7 && blue_max == 3 && red_shift == 5 && green_shift == 2 && blue_shift == 0) { vs->depth = 1; vs->write_pixels = vnc_write_pixels_copy; vs->send_hextile_tile = send_hextile_tile_8; - } else + } else { /* generic and slower case */ if (bits_per_pixel != 8 && @@ -1208,7 +1208,7 @@ static int protocol_client_msg(VncState *vs, char *data, size_t len) vnc_client_error(vs); break; } - + vnc_read_when(vs, protocol_client_msg, 1); return 0; } @@ -1259,7 +1259,7 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) vs->send_hextile_tile = send_hextile_tile_8; } vs->write_pixels = vnc_write_pixels_copy; - + vnc_write(vs, pad, 3); /* padding */ if (qemu_name) diff --git a/vnchextile.h b/vnchextile.h index aa575b7df..35dcc5727 100644 --- a/vnchextile.h +++ b/vnchextile.h @@ -9,7 +9,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, int x, int y, int w, int h, - uint32_t *last_bg32, + uint32_t *last_bg32, uint32_t *last_fg32, int *has_bg, int *has_fg) { @@ -86,7 +86,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, flags |= 0x08; irow = (pixel_t *)row; - + for (j = 0; j < h; j++) { int min_x = -1; for (i = 0; i < w; i++) { -- cgit v1.2.3 From 3ae43202754711808ea5186e327bfd0533dd88fc Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Sep 2007 21:39:48 +0000 Subject: Add some missing checks for host syscalls. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3174 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a92449077..943955d97 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -161,15 +161,17 @@ static int gettid(void) { _syscall1(int,sys_uname,struct new_utsname *,buf) _syscall2(int,sys_getcwd1,char *,buf,size_t,size) _syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); +#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); +#endif _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) -#ifdef TARGET_NR_tgkill +#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) #endif -#ifdef TARGET_NR_tkill +#if defined(TARGET_NR_tkill) && defined(__NR_tkill) _syscall2(int,sys_tkill,int,tid,int,sig) #endif #ifdef __NR_exit_group @@ -3845,7 +3847,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, } #endif break; -#ifdef TARGET_NR_getdents64 +#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) case TARGET_NR_getdents64: { struct dirent64 *dirp; @@ -4634,13 +4636,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, break; #endif -#ifdef TARGET_NR_tkill +#if defined(TARGET_NR_tkill) && defined(__NR_tkill) case TARGET_NR_tkill: ret = get_errno(sys_tkill((int)arg1, (int)arg2)); break; #endif -#ifdef TARGET_NR_tgkill +#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) case TARGET_NR_tgkill: ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3)); break; -- cgit v1.2.3 From ec36ba14748e140dda237ba22ad3135e360b0d9f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Sep 2007 21:59:02 +0000 Subject: vmdk compatibility level 6 images, by Soren Hansen. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3175 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-qcow.c | 2 +- block-qcow2.c | 2 +- block-vmdk.c | 4 ++-- block_int.h | 4 ++++ qemu-img.c | 49 ++++++++++++++++++++++++++++++------------------- qemu-img.texi | 8 +++++--- 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/block-qcow.c b/block-qcow.c index 208e35cca..1f44355b2 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -769,7 +769,7 @@ static int qcow_create(const char *filename, int64_t total_size, l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift; header.l1_table_offset = cpu_to_be64(header_size); - if (flags) { + if (flags & BLOCK_FLAG_ENCRYPT) { header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); } else { header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); diff --git a/block-qcow2.c b/block-qcow2.c index 2df061544..fca1d03c4 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -1076,7 +1076,7 @@ static int qcow_create(const char *filename, int64_t total_size, s->cluster_size = 1 << s->cluster_bits; header.cluster_bits = cpu_to_be32(s->cluster_bits); header_size = (header_size + 7) & ~7; - if (flags) { + if (flags & BLOCK_FLAG_ENCRYPT) { header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); } else { header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); diff --git a/block-vmdk.c b/block-vmdk.c index 197fb5a62..436241c79 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -712,7 +712,7 @@ static int vmdk_create(const char *filename, int64_t total_size, "# The Disk Data Base \n" "#DDB\n" "\n" - "ddb.virtualHWVersion = \"4\"\n" + "ddb.virtualHWVersion = \"%d\"\n" "ddb.geometry.cylinders = \"%lu\"\n" "ddb.geometry.heads = \"16\"\n" "ddb.geometry.sectors = \"63\"\n" @@ -789,7 +789,7 @@ static int vmdk_create(const char *filename, int64_t total_size, 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)); + real_filename, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16)); /* write the descriptor */ lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET); diff --git a/block_int.h b/block_int.h index e8fff77a0..356594145 100644 --- a/block_int.h +++ b/block_int.h @@ -24,6 +24,10 @@ #ifndef BLOCK_INT_H #define BLOCK_INT_H +#define BLOCK_FLAG_ENCRYPT 1 +#define BLOCK_FLAG_COMPRESS 2 +#define BLOCK_FLAG_COMPAT6 4 + struct BlockDriver { const char *format_name; int instance_size; diff --git a/qemu-img.c b/qemu-img.c index 6712f81fd..aa3d719a8 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include "block_int.h" #ifdef _WIN32 #include @@ -98,9 +99,9 @@ void help(void) "QEMU disk image utility\n" "\n" "Command syntax:\n" - " create [-e] [-b base_image] [-f fmt] filename [size]\n" + " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" " commit [-f fmt] filename\n" - " convert [-c] [-e] [-f fmt] filename [-O output_fmt] output_filename\n" + " convert [-c] [-e] [-6] [-f fmt] filename [-O output_fmt] output_filename\n" " info [-f fmt] filename\n" "\n" "Command parameters:\n" @@ -114,6 +115,7 @@ void help(void) " 'output_fmt' is the destination format\n" " '-c' indicates that target image must be compressed (qcow format only)\n" " '-e' indicates that the target image must be encrypted (qcow format only)\n" + " '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n" ); printf("\nSupported format:"); bdrv_iterate_format(format_print, NULL); @@ -241,7 +243,7 @@ static BlockDriverState *bdrv_new_open(const char *filename, static int img_create(int argc, char **argv) { - int c, ret, encrypted; + int c, ret, flags; const char *fmt = "raw"; const char *filename; const char *base_filename = NULL; @@ -249,9 +251,9 @@ static int img_create(int argc, char **argv) const char *p; BlockDriver *drv; - encrypted = 0; + flags = 0; for(;;) { - c = getopt(argc, argv, "b:f:he"); + c = getopt(argc, argv, "b:f:he6"); if (c == -1) break; switch(c) { @@ -265,8 +267,11 @@ static int img_create(int argc, char **argv) fmt = optarg; break; case 'e': - encrypted = 1; + flags |= BLOCK_FLAG_ENCRYPT; break; + case '6': + flags |= BLOCK_FLAG_COMPAT6; + break; } } if (optind >= argc) @@ -299,14 +304,16 @@ static int img_create(int argc, char **argv) error("Unknown file format '%s'", fmt); printf("Formatting '%s', fmt=%s", filename, fmt); - if (encrypted) + if (flags & BLOCK_FLAG_ENCRYPT) printf(", encrypted"); + if (flags & BLOCK_FLAG_COMPAT6) + printf(", compatibility level=6"); if (base_filename) { printf(", backing_file=%s", base_filename); } printf(", size=%" PRId64 " kB\n", (int64_t) (size / 1024)); - ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted); + ret = bdrv_create(drv, filename, size / 512, base_filename, flags); if (ret < 0) { if (ret == -ENOTSUP) { error("Formatting or formatting option not supported for file format '%s'", fmt); @@ -411,7 +418,7 @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum) static int img_convert(int argc, char **argv) { - int c, ret, n, n1, compress, cluster_size, cluster_sectors, encrypt; + int c, ret, n, n1, flags, cluster_size, cluster_sectors; const char *filename, *fmt, *out_fmt, *out_filename; BlockDriver *drv; BlockDriverState *bs, *out_bs; @@ -422,10 +429,9 @@ static int img_convert(int argc, char **argv) fmt = NULL; out_fmt = "raw"; - compress = 0; - encrypt = 0; + flags = 0; for(;;) { - c = getopt(argc, argv, "f:O:hce"); + c = getopt(argc, argv, "f:O:hce6"); if (c == -1) break; switch(c) { @@ -439,10 +445,13 @@ static int img_convert(int argc, char **argv) out_fmt = optarg; break; case 'c': - compress = 1; + flags |= BLOCK_FLAG_COMPRESS; break; case 'e': - encrypt = 1; + flags |= BLOCK_FLAG_ENCRYPT; + break; + case '6': + flags |= BLOCK_FLAG_COMPAT6; break; } } @@ -458,14 +467,16 @@ static int img_convert(int argc, char **argv) drv = bdrv_find_format(out_fmt); if (!drv) error("Unknown file format '%s'", out_fmt); - if (compress && drv != &bdrv_qcow && drv != &bdrv_qcow2) + if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2) error("Compression not supported for this file format"); - if (encrypt && drv != &bdrv_qcow && drv != &bdrv_qcow2) + if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2) error("Encryption not supported for this file format"); - if (compress && encrypt) + if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_vmdk) + error("Alternative compatibility level not supported for this file format"); + if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS) error("Compression and encryption not supported at the same time"); bdrv_get_geometry(bs, &total_sectors); - ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt); + ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags); if (ret < 0) { if (ret == -ENOTSUP) { error("Formatting not supported for file format '%s'", fmt); @@ -476,7 +487,7 @@ static int img_convert(int argc, char **argv) out_bs = bdrv_new_open(out_filename, out_fmt); - if (compress) { + if (flags && BLOCK_FLAG_COMPRESS) { if (bdrv_get_info(out_bs, &bdi) < 0) error("could not get block driver info"); cluster_size = bdi.cluster_size; diff --git a/qemu-img.texi b/qemu-img.texi index 5b99dff0a..89f912df9 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -8,9 +8,9 @@ usage: qemu-img command [command options] The following commands are supported: @table @option -@item create [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] +@item create [-e] [-6] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] @item commit [-f @var{fmt}] @var{filename} -@item convert [-c] [-e] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename} +@item convert [-c] [-e] [-6] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename} @item info [-f @var{fmt}] @var{filename} @end table @@ -67,12 +67,14 @@ is the destination disk image filename indicates that target image must be compressed (qcow format only) @item -e indicates that the target image must be encrypted (qcow format only) +@item -6 +indicates that the target image must use compatibility level 6 (vmdk format only) @end table Command description: @table @option -@item create [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] +@item create [-6] [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] Create the new disk image @var{filename} of size @var{size} and format @var{fmt}. -- cgit v1.2.3 From ef18c8839e85341cc63467f92c35f981858a6fe5 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Sep 2007 22:12:39 +0000 Subject: Solaris x86_64 configure patch, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3176 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/configure b/configure index 49bf8b6fc..7b8ac31dc 100755 --- a/configure +++ b/configure @@ -155,6 +155,12 @@ SunOS) install="ginstall" needs_libsunmath="no" solarisrev=`uname -r | cut -f2 -d.` + # have to select again, because `uname -m` returns i86pc + # even on an x86_64 box. + solariscpu=`isainfo -k` + if test "${solariscpu}" = "amd64" ; then + cpu="x86_64" + fi if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then if test "$solarisrev" -le 9 ; then if test -f /opt/SUNWspro/prod/lib/libsunmath.so.1; then @@ -333,6 +339,16 @@ case $cpu in ;; esac +if [ "$solaris" = "yes" -a "$cpu" = "x86_64" ] ; then + CFLAGS="${CFLAGS} -m64" + OS_CFLAGS="${OS_CFLAGS} -m64" +fi + +if [ "$solaris" = "yes" -a "$cpu" = "i386" ] ; then + CFLAGS="${CFLAGS} -m32" + OS_CFLAGS="${OS_CFLAGS} -m32" +fi + if test x"$show_help" = x"yes" ; then cat << EOF -- cgit v1.2.3 From 3b46e6242767a2c770c0aba0a6595e9511623c92 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 17 Sep 2007 08:09:54 +0000 Subject: find -type f | xargs sed -i 's/[\t ]*$//g' # Yes, again. Note the star in the regex. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3177 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 10 +-- aes.c | 4 +- arm-dis.c | 128 +++++++++++++------------- arm-semi.c | 2 +- block-bochs.c | 28 +++--- block-cloop.c | 4 +- block-cow.c | 8 +- block-dmg.c | 6 +- block-qcow.c | 30 +++---- block-qcow2.c | 68 +++++++------- block-raw.c | 30 +++---- block-vmdk.c | 12 +-- block-vpc.c | 10 +-- block-vvfat.c | 34 +++---- block.c | 22 ++--- block_int.h | 4 +- cocoa.m | 190 +++++++++++++++++++-------------------- console.c | 8 +- cpu-exec.c | 36 ++++---- darwin-user/syscall.c | 4 +- dis-asm.h | 2 +- disas.c | 4 +- dyngen.c | 86 +++++++++--------- dyngen.h | 6 +- elf_ops.h | 6 +- exec-all.h | 10 +-- exec.c | 56 ++++++------ gdbstub.c | 6 +- hw/acpi.c | 8 +- hw/adb.c | 14 +-- hw/alpha_palcode.c | 2 +- hw/apic.c | 12 +-- hw/cdrom.c | 8 +- hw/cirrus_vga.c | 20 ++--- hw/cirrus_vga_rop2.h | 2 +- hw/cuda.c | 8 +- hw/esp.c | 2 +- hw/grackle_pci.c | 8 +- hw/gt64xxx.c | 4 +- hw/heathrow_pic.c | 4 +- hw/i8254.c | 6 +- hw/i8259.c | 12 +-- hw/ide.c | 28 +++--- hw/iommu.c | 6 +- hw/m48t59.c | 12 +-- hw/mc146818rtc.c | 6 +- hw/mips_malta.c | 4 +- hw/ne2000.c | 26 +++--- hw/openpic.c | 10 +-- hw/parallel.c | 2 +- hw/pc.c | 10 +-- hw/pci.c | 10 +-- hw/pckbd.c | 4 +- hw/pcnet.c | 70 +++++++-------- hw/pflash_cfi02.c | 2 +- hw/pl011.c | 2 +- hw/pl110.c | 4 +- hw/pl181.c | 2 +- hw/ppc.c | 2 +- hw/ppc405_boards.c | 2 +- hw/ppc405_uc.c | 4 +- hw/ppc_chrp.c | 32 +++---- hw/ps2.c | 4 +- hw/rtl8139.c | 18 ++-- hw/serial.c | 2 +- hw/slavio_intctl.c | 2 +- hw/slavio_serial.c | 2 +- hw/slavio_timer.c | 2 +- hw/smbus_eeprom.c | 2 +- hw/smc91c111.c | 2 +- hw/tcx.c | 4 +- hw/usb-hid.c | 14 +-- hw/usb-hub.c | 8 +- hw/usb-msd.c | 4 +- hw/usb-uhci.c | 8 +- hw/usb.h | 4 +- hw/vga.c | 50 +++++------ hw/vga_int.h | 6 +- hw/vga_template.h | 12 +-- kqemu.c | 14 +-- linux-user/alpha/syscall_nr.h | 2 +- linux-user/elfload.c | 12 +-- linux-user/flat.h | 2 +- linux-user/flatload.c | 18 ++-- linux-user/linuxload.c | 2 +- linux-user/main.c | 44 ++++----- linux-user/mmap.c | 18 ++-- linux-user/signal.c | 18 ++-- linux-user/syscall.c | 78 ++++++++-------- linux-user/syscall_defs.h | 4 +- linux-user/syscall_types.h | 2 +- linux-user/vm86.c | 12 +-- loader.c | 2 +- m68k-dis.c | 16 ++-- mips-dis.c | 2 +- monitor.c | 28 +++--- qemu-doc.texi | 16 ++-- qemu-img.c | 8 +- readline.c | 2 +- s390-dis.c | 2 +- sdl.c | 4 +- sh4-dis.c | 8 +- slirp/bootp.c | 16 ++-- slirp/cksum.c | 2 +- slirp/debug.c | 12 +-- slirp/if.c | 8 +- slirp/ip_icmp.c | 18 ++-- slirp/ip_output.c | 6 +- slirp/mbuf.c | 4 +- slirp/misc.c | 60 ++++++------- slirp/sbuf.c | 4 +- slirp/slirp.c | 68 +++++++------- slirp/socket.c | 22 ++--- slirp/socket.h | 8 +- slirp/tcp_input.c | 52 +++++------ slirp/tcp_output.c | 8 +- slirp/tcp_subr.c | 166 +++++++++++++++++----------------- slirp/tcp_timer.c | 8 +- slirp/tftp.c | 24 ++--- slirp/udp.c | 56 ++++++------ softmmu_template.h | 4 +- sparc-dis.c | 14 +-- tap-win32.c | 8 +- target-alpha/helper.c | 2 +- target-arm/cpu.h | 6 +- target-arm/nwfpe/double_cpdo.c | 8 +- target-arm/nwfpe/extended_cpdo.c | 18 ++-- target-arm/nwfpe/fpa11.c | 56 ++++++------ target-arm/nwfpe/fpa11.h | 2 +- target-arm/nwfpe/fpa11_cpdo.c | 16 ++-- target-arm/nwfpe/fpa11_cpdt.c | 46 +++++----- target-arm/nwfpe/fpa11_cprt.c | 36 ++++---- target-arm/nwfpe/fpopcode.c | 22 ++--- target-arm/nwfpe/fpopcode.h | 6 +- target-arm/nwfpe/single_cpdo.c | 6 +- target-arm/op.c | 8 +- target-arm/translate.c | 24 ++--- target-i386/cpu.h | 8 +- target-i386/exec.h | 2 +- target-i386/helper.c | 112 +++++++++++------------ target-i386/helper2.c | 28 +++--- target-i386/op.c | 22 ++--- target-i386/ops_sse.h | 4 +- target-i386/ops_template.h | 2 +- target-i386/translate-copy.c | 34 +++---- target-i386/translate.c | 94 +++++++++---------- target-m68k/cpu.h | 2 +- target-m68k/op.c | 4 +- target-m68k/translate.c | 6 +- target-mips/helper.c | 2 +- target-mips/op_helper.c | 8 +- target-mips/translate.c | 4 +- target-ppc/helper.c | 6 +- target-ppc/mfrom_table_gen.c | 2 +- target-ppc/op_helper.c | 4 +- target-ppc/translate.c | 18 ++-- target-ppc/translate_init.c | 2 +- target-sh4/README.sh4 | 2 +- target-sparc/op.c | 4 +- target-sparc/op_helper.c | 16 ++-- tests/hello-arm.c | 2 +- tests/linux-test.c | 26 +++--- tests/qruncom.c | 8 +- tests/runcom.c | 4 +- tests/test-i386-code16.S | 10 +-- tests/test-i386-vm86.S | 12 +-- tests/test-i386.c | 30 +++---- thunk.c | 4 +- translate-all.c | 10 +-- usb-linux.c | 8 +- vl.c | 166 +++++++++++++++++----------------- vl.h | 2 +- vnc.c | 2 +- 173 files changed, 1557 insertions(+), 1557 deletions(-) diff --git a/Changelog b/Changelog index f87f8a1e3..21e35985d 100644 --- a/Changelog +++ b/Changelog @@ -86,7 +86,7 @@ version 0.8.0: (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) @@ -201,7 +201,7 @@ version 0.5.5: - 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) @@ -266,7 +266,7 @@ version 0.5.2: - eflags optimisation fix for string operations version 0.5.1: - + - float access fixes when using soft mmu - PC emulation support on PowerPC - A20 support @@ -281,7 +281,7 @@ version 0.5.1: - 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 @@ -319,7 +319,7 @@ version 0.4.2: - 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. diff --git a/aes.c b/aes.c index 0a45c0b6c..40ed109d3 100644 --- a/aes.c +++ b/aes.c @@ -1294,7 +1294,7 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, 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); @@ -1312,6 +1312,6 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, for(n=0; n < len; ++n) out[n] = tmp[n] ^ ivec[n]; memcpy(ivec, tmp, AES_BLOCK_SIZE); - } + } } } diff --git a/arm-dis.c b/arm-dis.c index 7032f9508..11f580b2f 100644 --- a/arm-dis.c +++ b/arm-dis.c @@ -34,7 +34,7 @@ struct thumb_opcode }; /* format of the assembler string : - + %% % %d print the bitfield in decimal %x print the bitfield in hex @@ -104,7 +104,7 @@ static struct arm_opcode arm_opcodes[] = {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"}, @@ -116,7 +116,7 @@ static struct arm_opcode arm_opcodes[] = {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. */ + /* 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"}, @@ -621,14 +621,14 @@ arm_decode_shift (given, func, stream) 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) @@ -636,10 +636,10 @@ arm_decode_shift (given, func, stream) func (stream, ", rrx"); return; } - + amount = 32; } - + func (stream, ", %s #%d", arm_shift[shift], amount); } else @@ -666,7 +666,7 @@ print_insn_arm1 (pc, info, given) if ((given & insn->mask) == insn->value) { char * c; - + for (c = insn->assembler; *c; c++) { if (*c == '%') @@ -682,14 +682,14 @@ print_insn_arm1 (pc, info, given) && ((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); @@ -710,7 +710,7 @@ print_insn_arm1 (pc, info, given) /* ie ignore the offset. */ offset = pc + 8; } - + func (stream, "\t; "); info->print_address_func (offset, info); } @@ -767,12 +767,12 @@ print_insn_arm1 (pc, info, given) { /* 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); } @@ -829,7 +829,7 @@ print_insn_arm1 (pc, info, given) } } break; - + case 'b': (*info->print_address_func) (BDISP (given) * 4 + pc + 8, info); @@ -911,7 +911,7 @@ print_insn_arm1 (pc, info, given) { bfd_vma address; bfd_vma offset = 0; - + if (given & 0x00800000) /* Is signed, hi bits should be ones. */ offset = (-1) ^ 0x00ffffff; @@ -920,7 +920,7 @@ print_insn_arm1 (pc, info, given) offset += given & 0x00ffffff; offset <<= 2; address = offset + pc + 8; - + if (given & 0x01000000) /* H bit allows addressing to 2-byte boundaries. */ address += 2; @@ -976,7 +976,7 @@ print_insn_arm1 (pc, info, given) func (stream, "3"); } break; - + case 'P': switch (given & 0x00080080) { @@ -1040,44 +1040,44 @@ print_insn_arm1 (pc, info, given) { 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) @@ -1089,20 +1089,20 @@ print_insn_arm1 (pc, info, given) 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]); @@ -1163,7 +1163,7 @@ print_insn_arm1 (pc, info, given) } break; - + default: abort (); } @@ -1252,7 +1252,7 @@ print_insn_thumb (pc, info, given) if (!*c) /* Check for empty (not NULL) assembler string. */ { long offset; - + info->bytes_per_chunk = 4; info->bytes_per_line = 4; @@ -1274,16 +1274,16 @@ print_insn_thumb (pc, info, given) { 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 '%': @@ -1293,11 +1293,11 @@ print_insn_thumb (pc, info, given) case 'S': { long reg; - + reg = (given >> 3) & 0x7; if (given & (1 << 6)) reg += 8; - + func (stream, "%s", arm_regnames[reg]); } break; @@ -1305,11 +1305,11 @@ print_insn_thumb (pc, info, given) case 'D': { long reg; - + reg = given & 0x7; if (given & (1 << 7)) reg += 8; - + func (stream, "%s", arm_regnames[reg]); } break; @@ -1331,9 +1331,9 @@ print_insn_thumb (pc, info, given) { 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++) @@ -1370,7 +1370,7 @@ print_insn_thumb (pc, info, given) { int bitstart = *c++ - '0'; int bitend = 0; - + while (*c >= '0' && *c <= '9') bitstart = (bitstart * 10) + *c++ - '0'; @@ -1379,7 +1379,7 @@ print_insn_thumb (pc, info, given) case '-': { long reg; - + c++; while (*c >= '0' && *c <= '9') bitend = (bitend * 10) + *c++ - '0'; @@ -1478,7 +1478,7 @@ parse_arm_disassembler_option (option) { if (option == NULL) return; - + if (strneq (option, "reg-names-", 10)) { int i; @@ -1491,7 +1491,7 @@ parse_arm_disassembler_option (option) regname_selected = i; break; } - + if (i < 0) fprintf (stderr, _("Unrecognised register name set: %s\n"), option); } @@ -1501,7 +1501,7 @@ parse_arm_disassembler_option (option) force_thumb = 0; else fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); - + return; } @@ -1512,7 +1512,7 @@ parse_disassembler_options (options) char * options; { char * space; - + if (options == NULL) return; @@ -1550,25 +1550,25 @@ print_insn_arm (pc, info) 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 @@ -1580,15 +1580,15 @@ print_insn_arm (pc, info) { 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; @@ -1599,17 +1599,17 @@ print_insn_arm (pc, 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 @@ -1621,13 +1621,13 @@ print_insn_arm (pc, info) 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) @@ -1635,7 +1635,7 @@ print_insn_arm (pc, info) info->memory_error_func (status, pc + 4, info); return -1; } - + given |= (b[0] << 24) | (b[1] << 16); } else @@ -1644,7 +1644,7 @@ print_insn_arm (pc, info) 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 @@ -1668,7 +1668,7 @@ print_arm_disassembler_options (FILE * stream) 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, diff --git a/arm-semi.c b/arm-semi.c index 86b1e9f57..ff7a343bc 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -401,7 +401,7 @@ uint32_t do_arm_semihosting(CPUState *env) } ts->heap_limit = limit; } - + ptr = lock_user(ARG(0), 16, 0); ptr[0] = tswap32(ts->heap_base); ptr[1] = tswap32(ts->heap_limit); diff --git a/block-bochs.c b/block-bochs.c index ca95ae84e..9baea9b6f 100644 --- a/block-bochs.c +++ b/block-bochs.c @@ -44,7 +44,7 @@ struct bochs_header_v1 { char subtype[16]; // "Undoable" / "Volatile" / "Growing" uint32_t version; uint32_t header; // size of header - + union { struct { uint32_t catalog; // num of entries @@ -64,7 +64,7 @@ struct bochs_header { char subtype[16]; // "Undoable" / "Volatile" / "Growing" uint32_t version; uint32_t header; // size of header - + union { struct { uint32_t catalog; // num of entries @@ -83,9 +83,9 @@ typedef struct BDRVBochsState { uint32_t *catalog_bitmap; int catalog_size; - + int data_offset; - + int bitmap_blocks; int extent_blocks; int extent_size; @@ -94,7 +94,7 @@ typedef struct 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; @@ -121,9 +121,9 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) if (fd < 0) return -1; } - + bs->read_only = 1; // no write support yet - + s->fd = fd; if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) { @@ -161,7 +161,7 @@ static int bochs_open(BlockDriverState *bs, const char *filename, int flags) 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; @@ -180,7 +180,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) // 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", @@ -191,17 +191,17 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) 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", @@ -210,7 +210,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) } lseek(s->fd, block_offset, SEEK_SET); - + return 0; } diff --git a/block-cloop.c b/block-cloop.c index 4dfe766b7..0c9ddb381 100644 --- a/block-cloop.c +++ b/block-cloop.c @@ -96,7 +96,7 @@ 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; @@ -107,7 +107,7 @@ 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) diff --git a/block-cow.c b/block-cow.c index 8880c1cb6..47a91e5ac 100644 --- a/block-cow.c +++ b/block-cow.c @@ -85,14 +85,14 @@ static int cow_open(BlockDriverState *bs, const char *filename, int flags) 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), @@ -155,7 +155,7 @@ static int cow_read(BlockDriverState *bs, int64_t sector_num, { 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); @@ -184,7 +184,7 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num, { 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) diff --git a/block-dmg.c b/block-dmg.c index a46b80199..681f4dc71 100644 --- a/block-dmg.c +++ b/block-dmg.c @@ -28,7 +28,7 @@ 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, @@ -86,7 +86,7 @@ static int dmg_open(BlockDriverState *bs, const char *filename, int flags) 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: @@ -167,7 +167,7 @@ dmg_close: goto dmg_close; s->current_chunk = s->n_chunks; - + return 0; } diff --git a/block-qcow.c b/block-qcow.c index 1f44355b2..9a0bca0e7 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -80,7 +80,7 @@ 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) @@ -108,7 +108,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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) @@ -151,7 +151,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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; @@ -177,7 +177,7 @@ 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) @@ -262,7 +262,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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; @@ -420,7 +420,7 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, inflateEnd(strm); return 0; } - + static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) { int ret, csize; @@ -450,7 +450,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, 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); @@ -493,7 +493,7 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, 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; @@ -572,7 +572,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) qemu_aio_release(acb); return; } - + /* prepare next AIO request */ acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 0, 0, 0, 0); @@ -627,7 +627,7 @@ static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs, acb->buf = buf; acb->nb_sectors = nb_sectors; acb->n = 0; - acb->cluster_offset = 0; + acb->cluster_offset = 0; qcow_aio_read_cb(acb, 0); return &acb->common; @@ -661,7 +661,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) 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) @@ -701,7 +701,7 @@ static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs, { BDRVQcowState *s = bs->opaque; QCowAIOCB *acb; - + s->cluster_cache_offset = -1; /* disable compressed cache */ acb = qemu_aio_get(bs, cb, opaque); @@ -712,7 +712,7 @@ static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs, acb->buf = (uint8_t *)buf; acb->nb_sectors = nb_sectors; acb->n = 0; - + qcow_aio_write_cb(acb, 0); return &acb->common; } @@ -774,7 +774,7 @@ static int qcow_create(const char *filename, int64_t total_size, } else { header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); } - + /* write all the data */ write(fd, &header, sizeof(header)); if (backing_file) { @@ -864,7 +864,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return -1; } } - + qemu_free(out_buf); return 0; } diff --git a/block-qcow2.c b/block-qcow2.c index fca1d03c4..b74fe348e 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -37,7 +37,7 @@ - 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. + 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. @@ -176,7 +176,7 @@ static void check_refcounts(BlockDriverState *bs); 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) @@ -209,7 +209,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) 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 || @@ -267,7 +267,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) if (!s->cluster_data) goto fail; s->cluster_cache_offset = -1; - + if (refcount_init(bs) < 0) goto fail; @@ -304,7 +304,7 @@ 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) @@ -451,7 +451,7 @@ static int grow_l1_table(BlockDriverState *bs, int min_size) /* 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); @@ -459,7 +459,7 @@ static int grow_l1_table(BlockDriverState *bs, int min_size) 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), @@ -501,7 +501,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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 */ @@ -600,7 +600,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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); @@ -672,7 +672,7 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, inflateEnd(strm); return 0; } - + static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) { int ret, csize, nb_csectors, sector_offset; @@ -717,7 +717,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, 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); @@ -762,7 +762,7 @@ static int qcow_write(BlockDriverState *bs, int64_t sector_num, 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; @@ -841,7 +841,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) qemu_aio_release(acb); return; } - + /* prepare next AIO request */ acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 0, 0, 0, 0); @@ -948,7 +948,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) 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) @@ -988,13 +988,13 @@ static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs, { 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; } @@ -1054,7 +1054,7 @@ static int qcow_create(const char *filename, int64_t total_size, 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); @@ -1096,7 +1096,7 @@ static int qcow_create(const char *filename, int64_t total_size, 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); @@ -1111,7 +1111,7 @@ static int qcow_create(const char *filename, int64_t total_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) { @@ -1124,7 +1124,7 @@ static int qcow_create(const char *filename, int64_t total_size, } 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); @@ -1153,7 +1153,7 @@ static int qcow_make_empty(BlockDriverState *bs) ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length); if (ret < 0) return ret; - + l2_cache_reset(bs); #endif return 0; @@ -1223,7 +1223,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return -1; } } - + qemu_free(out_buf); return 0; } @@ -1256,7 +1256,7 @@ static int update_snapshot_refcount(BlockDriverState *bs, 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; @@ -1278,7 +1278,7 @@ static int update_snapshot_refcount(BlockDriverState *bs, 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) @@ -1455,7 +1455,7 @@ static int qcow_write_snapshots(BlockDriverState *bs) 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)); @@ -1465,7 +1465,7 @@ static int qcow_write_snapshots(BlockDriverState *bs) 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); @@ -1533,7 +1533,7 @@ 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; @@ -1552,7 +1552,7 @@ static int qcow_snapshot_create(BlockDriverState *bs, 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') { @@ -1663,7 +1663,7 @@ 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; @@ -1731,7 +1731,7 @@ 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; @@ -1839,7 +1839,7 @@ 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); @@ -2043,7 +2043,7 @@ static void inc_refcounts(BlockDriverState *bs, BDRVQcowState *s = bs->opaque; int64_t start, last, cluster_offset; int k; - + if (size <= 0) return; @@ -2086,7 +2086,7 @@ static int check_refcounts_l1(BlockDriverState *bs, 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) @@ -2165,7 +2165,7 @@ static void check_refcounts(BlockDriverState *bs) /* 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); diff --git a/block-raw.c b/block-raw.c index aaebbeb49..b7a3eb698 100644 --- a/block-raw.c +++ b/block-raw.c @@ -142,7 +142,7 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, { BDRVRawState *s = bs->opaque; int ret; - + ret = fd_open(bs); if (ret < 0) return ret; @@ -194,7 +194,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, { BDRVRawState *s = bs->opaque; int ret; - + ret = fd_open(bs); if (ret < 0) return ret; @@ -259,7 +259,7 @@ 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; @@ -547,7 +547,7 @@ BlockDriver bdrv_raw = { raw_close, raw_create, raw_flush, - + .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, @@ -576,7 +576,7 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) if ( KERN_SUCCESS != kernResult ) { printf( "IOMasterPort returned %d\n", kernResult ); } - + classesToMatch = IOServiceMatching( kIOCDMediaClass ); if ( classesToMatch == NULL ) { printf( "IOServiceMatching returned a NULL dictionary.\n" ); @@ -588,7 +588,7 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) { printf( "IOServiceGetMatchingServices returned %d\n", kernResult ); } - + return kernResult; } @@ -614,7 +614,7 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma } IOObjectRelease( nextMedia ); } - + return kernResult; } @@ -634,7 +634,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) kernResult = FindEjectableCDMedia( &mediaIterator ); kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); - + if ( bsdPath[ 0 ] != '\0' ) { strcat(bsdPath,"s0"); /* some CDs don't have a partition 0 */ @@ -646,7 +646,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) } filename = bsdPath; } - + if ( mediaIterator ) IOObjectRelease( mediaIterator ); } @@ -883,7 +883,7 @@ BlockDriver bdrv_host_device = { raw_close, NULL, raw_flush, - + .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, .bdrv_aio_cancel = raw_aio_cancel, @@ -999,7 +999,7 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, OVERLAPPED ov; DWORD ret_count; int ret; - + memset(&ov, 0, sizeof(ov)); ov.Offset = offset; ov.OffsetHigh = offset >> 32; @@ -1021,7 +1021,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, OVERLAPPED ov; DWORD ret_count; int ret; - + memset(&ov, 0, sizeof(ov)); ov.Offset = offset; ov.OffsetHigh = offset >> 32; @@ -1256,7 +1256,7 @@ BlockDriver bdrv_raw = { raw_close, raw_create, raw_flush, - + #if 0 .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, @@ -1335,7 +1335,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) } } s->type = find_device_type(bs, filename); - + if ((flags & BDRV_O_ACCESS) == O_RDWR) { access_flags = GENERIC_READ | GENERIC_WRITE; } else { @@ -1406,7 +1406,7 @@ BlockDriver bdrv_host_device = { raw_close, NULL, raw_flush, - + #if 0 .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, diff --git a/block-vmdk.c b/block-vmdk.c index 436241c79..02335f7af 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -110,7 +110,7 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) #define CHECK_CID 1 -#define SECTOR_SIZE 512 +#define SECTOR_SIZE 512 #define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each #define HEADER_SIZE 512 // first sector of 512 bytes @@ -308,7 +308,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file) fail_gd: qemu_free(gd_buf); - fail_rgd: + fail_rgd: qemu_free(rgd_buf); fail: close(p_fd); @@ -341,7 +341,7 @@ static int vmdk_parent_open(BlockDriverState *bs, const char * filename) p_name += sizeof("parentFileNameHint") + 1; if ((end_name = strchr(p_name,'\"')) == 0) return -1; - + strncpy(s->hd->backing_file, p_name, end_name - p_name); if (stat(s->hd->backing_file, &file_buf) != 0) { path_combine(parent_img_name, sizeof(parent_img_name), @@ -761,8 +761,8 @@ static int vmdk_create(const char *filename, int64_t total_size, header.check_bytes[1] = 0x20; header.check_bytes[2] = 0xd; header.check_bytes[3] = 0xa; - - /* write all the data */ + + /* write all the data */ write(fd, &magic, sizeof(magic)); write(fd, &header, sizeof(header)); @@ -773,7 +773,7 @@ static int vmdk_create(const char *filename, int64_t total_size, 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; diff --git a/block-vpc.c b/block-vpc.c index d9a4b9254..be74c290d 100644 --- a/block-vpc.c +++ b/block-vpc.c @@ -65,7 +65,7 @@ struct vpc_subheader { typedef struct BDRVVPCState { int fd; - + int pagetable_entries; uint32_t *pagetable; @@ -74,7 +74,7 @@ typedef struct BDRVVPCState { uint8_t *pageentry_u8; uint32_t *pageentry_u32; uint16_t *pageentry_u16; - + uint64_t last_bitmap; #endif } BDRVVPCState; @@ -97,7 +97,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags) return -1; bs->read_only = 1; // no write support yet - + s->fd = fd; if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE) @@ -153,13 +153,13 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) 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); diff --git a/block-vvfat.c b/block-vvfat.c index 3d3d6cfd0..b2aa52c28 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -153,7 +153,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun index_to<0 || index_to>=array->next || index_from<0 || index_from>=array->next) return -1; - + if(index_to==index_from) return 0; @@ -167,7 +167,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun memmove(to+is*count,to,from-to); else memmove(from,from+is*count,to-from); - + memcpy(to,buf,is*count); free(buf); @@ -319,10 +319,10 @@ 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; @@ -332,7 +332,7 @@ typedef struct BDRVVVFATState { 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 */ @@ -358,7 +358,7 @@ static void init_mbr(BDRVVVFATState* s) 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; @@ -478,7 +478,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry) for(i=0;i<11;i++) chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) +(unsigned char)entry->name[i]; - + return chksum; } @@ -554,7 +554,7 @@ static inline void init_fat(BDRVVVFATState* s) 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; @@ -579,9 +579,9 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, 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) @@ -592,7 +592,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, 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]; @@ -675,7 +675,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) mapping->end = mapping->begin; return -1; } - + i = mapping->info.dir.first_dir_index = first_cluster == 0 ? 0 : s->directory.next; @@ -774,7 +774,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index); set_begin_of_direntry(direntry, mapping->begin); - + return 0; } @@ -825,7 +825,7 @@ static int init_directories(BDRVVVFATState* s, */ 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)); @@ -987,7 +987,7 @@ DLOG(if (stderr == NULL) { s->qcow_filename = NULL; s->fat2 = NULL; s->downcase_short_names = 1; - + if (!strstart(dirname, "fat:", NULL)) return -1; @@ -1709,7 +1709,7 @@ static int check_directory_consistency(BDRVVVFATState *s, } else /* new directory */ schedule_mkdir(s, cluster_num, strdup(path)); - + lfn_init(&lfn); do { int i; @@ -2069,7 +2069,7 @@ static int commit_mappings(BDRVVVFATState* s, mapping = next_mapping; } - + cluster = c1; } diff --git a/block.c b/block.c index c9f4bafda..3c7039947 100644 --- a/block.c +++ b/block.c @@ -180,7 +180,7 @@ int bdrv_create(BlockDriver *drv, void get_tmp_filename(char *filename, int size) { char temp_dir[MAX_PATH]; - + GetTempPath(MAX_PATH, temp_dir); GetTempFileName(temp_dir, "qem", 0, filename); } @@ -202,7 +202,7 @@ static int is_windows_drive_prefix(const char *filename) (filename[0] >= 'A' && filename[0] <= 'Z')) && filename[1] == ':'); } - + static int is_windows_drive(const char *filename) { if (is_windows_drive_prefix(filename) && @@ -251,7 +251,7 @@ static BlockDriver *find_image_format(const char *filename) 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)) @@ -268,7 +268,7 @@ static BlockDriver *find_image_format(const char *filename) } } #endif - + drv = find_protocol(filename); /* no need to test disk image formats for vvfat */ if (drv == &bdrv_vvfat) @@ -324,7 +324,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, int ret, open_flags; char tmp_filename[PATH_MAX]; char backing_filename[PATH_MAX]; - + bs->read_only = 0; bs->is_temporary = 0; bs->encrypted = 0; @@ -332,7 +332,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, 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 */ @@ -347,7 +347,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, } 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, @@ -540,7 +540,7 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, if (bs->read_only) return -EACCES; if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); + memcpy(bs->boot_sector_data, buf, 512); } if (drv->bdrv_pwrite) { int ret, len; @@ -919,7 +919,7 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, 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; @@ -1062,7 +1062,7 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, 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); @@ -1085,7 +1085,7 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, if (bs->read_only) return NULL; if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); + memcpy(bs->boot_sector_data, buf, 512); } return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); diff --git a/block_int.h b/block_int.h index 356594145..b034023e0 100644 --- a/block_int.h +++ b/block_int.h @@ -79,7 +79,7 @@ struct BlockDriver { 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; }; @@ -111,7 +111,7 @@ struct BlockDriverState { /* 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; diff --git a/cocoa.m b/cocoa.m index a46db984a..84f943c5b 100644 --- a/cocoa.m +++ b/cocoa.m @@ -84,7 +84,7 @@ static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) MacSetRectRgn (temp, x, y, x + w, y + h); MacUnionRgn (dirty, temp, dirty); - + /* Flush the dirty region */ QDFlushPortBuffer ( [ qd_view qdPort ], dirty ); DisposeRgn (dirty); @@ -102,9 +102,9 @@ static void cocoa_resize(DisplayState *ds, int w, int h) 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) { @@ -119,33 +119,33 @@ static void cocoa_resize(DisplayState *ds, int w, int h) 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 ] ) ); @@ -154,9 +154,9 @@ static void cocoa_resize(DisplayState *ds, int w, int h) { 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; @@ -310,38 +310,38 @@ int keymap[] = 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 + 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 + 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 + 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 + 232 // 0xe8 E0, 68 WWW Stop 231 // 0xe7 E0, 67 WWW Refresh - 230 // 0xe6 E0, 66 WWW Favorites + 230 // 0xe6 E0, 66 WWW Favorites */ }; @@ -366,10 +366,10 @@ static void cocoa_refresh(DisplayState *ds) NSDate *distantPast; NSEvent *event; NSAutoreleasePool *pool; - + pool = [ [ NSAutoreleasePool alloc ] init ]; distantPast = [ NSDate distantPast ]; - + vga_hw_update(); do { @@ -415,8 +415,8 @@ static void cocoa_refresh(DisplayState *ds) case NSKeyDown: { - int keycode = cocoa_keycode_to_qemu([event keyCode]); - + int keycode = cocoa_keycode_to_qemu([event keyCode]); + /* handle command Key Combos */ if ([event modifierFlags] & NSCommandKeyMask) { switch ([event keyCode]) { @@ -427,7 +427,7 @@ static void cocoa_refresh(DisplayState *ds) return; } } - + /* handle control + alt Key Combos */ if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { switch (keycode) { @@ -482,10 +482,10 @@ static void cocoa_refresh(DisplayState *ds) } } break; - + case NSKeyUp: { - int keycode = cocoa_keycode_to_qemu([event keyCode]); + int keycode = cocoa_keycode_to_qemu([event keyCode]); if (is_graphic_console()) { if (keycode & 0x80) kbd_put_keycode(0xe0); @@ -493,7 +493,7 @@ static void cocoa_refresh(DisplayState *ds) } } break; - + case NSMouseMoved: if (grab) { int dx = [event deltaX]; @@ -503,11 +503,11 @@ static void cocoa_refresh(DisplayState *ds) 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; @@ -519,7 +519,7 @@ static void cocoa_refresh(DisplayState *ds) [NSApp sendEvent: event]; } break; - + case NSLeftMouseDragged: if (grab) { int dx = [event deltaX]; @@ -534,7 +534,7 @@ static void cocoa_refresh(DisplayState *ds) kbd_mouse_event(dx, dy, dz, buttons); } break; - + case NSLeftMouseUp: if (grab) { kbd_mouse_event(0, 0, 0, 0); @@ -546,18 +546,18 @@ static void cocoa_refresh(DisplayState *ds) //[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]; @@ -568,7 +568,7 @@ static void cocoa_refresh(DisplayState *ds) kbd_mouse_event(dx, dy, dz, buttons); } break; - + case NSRightMouseUp: if (grab) { kbd_mouse_event(0, 0, 0, 0); @@ -576,7 +576,7 @@ static void cocoa_refresh(DisplayState *ds) [NSApp sendEvent: event]; } break; - + case NSOtherMouseDragged: if (grab) { int dx = [event deltaX]; @@ -587,7 +587,7 @@ static void cocoa_refresh(DisplayState *ds) kbd_mouse_event(dx, dy, dz, buttons); } break; - + case NSOtherMouseDown: if (grab) { int buttons = 0; @@ -597,7 +597,7 @@ static void cocoa_refresh(DisplayState *ds) [NSApp sendEvent:event]; } break; - + case NSOtherMouseUp: if (grab) { kbd_mouse_event(0, 0, 0, 0); @@ -605,14 +605,14 @@ static void cocoa_refresh(DisplayState *ds) [NSApp sendEvent: event]; } break; - + case NSScrollWheel: if (grab) { int dz = [event deltaY]; kbd_mouse_event(0, 0, -dz, 0); } break; - + default: [NSApp sendEvent:event]; } } @@ -641,9 +641,9 @@ 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); } @@ -661,17 +661,17 @@ void cocoa_display_init(DisplayState *ds, int full_screen) ------------------------------------------------------ */ 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; } } @@ -680,32 +680,32 @@ static void QZ_SetPortAlphaOpaque () @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 ]; } @@ -742,13 +742,13 @@ static void QZ_SetPortAlphaOpaque () 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]; @@ -774,20 +774,20 @@ static void QZ_SetPortAlphaOpaque () { 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]; } } @@ -827,10 +827,10 @@ static void setApplicationMenu(void) 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:@""]; @@ -850,7 +850,7 @@ static void setApplicationMenu(void) 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]; @@ -872,17 +872,17 @@ static void setupWindowMenu(void) 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]; @@ -896,14 +896,14 @@ 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(); @@ -912,10 +912,10 @@ static void CustomApplicationMain(void) /* 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]; } diff --git a/console.c b/console.c index 35dc603c9..ff725c2e6 100644 --- a/console.c +++ b/console.c @@ -210,7 +210,7 @@ static void vga_fill_rect (DisplayState *ds, { uint8_t *d, *d1; int x, y, bpp; - + bpp = (ds->depth + 7) >> 3; d1 = ds->data + ds->linesize * posy + bpp * posx; @@ -591,7 +591,7 @@ static void console_scroll(int ydelta) { TextConsole *s; int i, y1; - + s = active_console; if (!s || (s->console_type == GRAPHIC_CONSOLE)) return; @@ -1047,7 +1047,7 @@ static void kbd_send_chars(void *opaque) TextConsole *s = opaque; int len; uint8_t buf[16]; - + len = qemu_chr_can_read(s->chr); if (len > s->out_fifo.count) len = s->out_fifo.count; @@ -1192,7 +1192,7 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p) 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++) { diff --git a/cpu-exec.c b/cpu-exec.c index 5326edf09..d04294763 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -84,13 +84,13 @@ static TranslationBlock *tb_find_slow(target_ulong pc, 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; @@ -135,7 +135,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc, 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; @@ -143,7 +143,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc, 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; @@ -371,7 +371,7 @@ int cpu_exec(CPUState *env1) #if defined(__sparc__) && !defined(HOST_SOLARIS) /* g1 can be modified by some libc? functions */ tmp_T0 = T0; -#endif +#endif interrupt_request = env->interrupt_request; if (__builtin_expect(interrupt_request, 0)) { if (interrupt_request & CPU_INTERRUPT_DEBUG) { @@ -565,7 +565,7 @@ int cpu_exec(CPUState *env1) #endif #if defined(__sparc__) && !defined(HOST_SOLARIS) T0 = tmp_T0; -#endif +#endif /* see if we can patch the calling TB. When the TB spans two pages, we cannot safely do a direct jump. */ @@ -796,7 +796,7 @@ void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) saved_env = env; env = s; - + helper_fsave((target_ulong)ptr, data32); env = saved_env; @@ -808,7 +808,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) saved_env = env; env = s; - + helper_frstor((target_ulong)ptr, data32); env = saved_env; @@ -953,7 +953,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { TranslationBlock *tb; int ret; - + if (cpu_single_env) env = cpu_single_env; /* XXX: find a correct solution for multithread */ #if defined(DEBUG_SIGNAL) @@ -1042,7 +1042,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { TranslationBlock *tb; int ret; - + if (cpu_single_env) env = cpu_single_env; /* XXX: find a correct solution for multithread */ #if defined(DEBUG_SIGNAL) @@ -1092,7 +1092,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { TranslationBlock *tb; int ret; - + if (cpu_single_env) env = cpu_single_env; /* XXX: find a correct solution for multithread */ #if defined(DEBUG_SIGNAL) @@ -1137,7 +1137,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, { TranslationBlock *tb; int ret; - + if (cpu_single_env) env = cpu_single_env; /* XXX: find a correct solution for multithread */ #if defined(DEBUG_SIGNAL) @@ -1371,7 +1371,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, 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 */ @@ -1403,7 +1403,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, struct ucontext *uc = puc; unsigned long pc; int is_write; - + pc = uc->uc_mcontext.gregs[R15]; /* XXX: compute is_write */ is_write = 0; @@ -1421,7 +1421,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, struct ucontext *uc = puc; unsigned long pc; int is_write; - + pc = uc->uc_mcontext.gregs[16]; /* XXX: compute is_write */ is_write = 0; @@ -1473,7 +1473,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, struct ucontext *uc = puc; unsigned long pc; int is_write; - + pc = uc->uc_mcontext.psw.addr; /* XXX: compute is_write */ is_write = 0; @@ -1490,7 +1490,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, struct ucontext *uc = puc; greg_t pc = uc->uc_mcontext.pc; int is_write; - + /* XXX: compute is_write */ is_write = 0; return handle_cpu_signal(pc, (unsigned long)info->si_addr, diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c index 1d65a369d..f17e59101 100644 --- a/darwin-user/syscall.c +++ b/darwin-user/syscall.c @@ -1336,7 +1336,7 @@ static inline long bswap_syctl(int * mib, int count, void *buf, int size) if(!(sysctl = sysctl->childs)) break; } - + if(ret->childs) qerror("we shouldn't have a directory element\n"); @@ -1375,7 +1375,7 @@ long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, vo //bswap_syctl(name, namelen, newp, newlen); tswap32s((uint32_t*)oldlenp); } - + if(name) /* Sometimes sysctl is called with no arg1, ignore */ ret = get_errno(sysctl(name, namelen, oldp, oldlenp, newp, newlen)); diff --git a/dis-asm.h b/dis-asm.h index 1659f2f95..bacd9c46b 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -67,7 +67,7 @@ enum bfd_architecture #define bfd_mach_mcf5249 16 #define bfd_mach_mcf547x 17 #define bfd_mach_mcf548x 18 - bfd_arch_vax, /* DEC Vax */ + bfd_arch_vax, /* DEC Vax */ bfd_arch_i960, /* Intel 960 */ /* The order of the following is important. lower number indicates a machine type that diff --git a/disas.c b/disas.c index 5048150b1..d90329659 100644 --- a/disas.c +++ b/disas.c @@ -176,7 +176,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) print_insn = print_insn_sparc; #ifdef TARGET_SPARC64 disasm_info.mach = bfd_mach_sparc_v9b; -#endif +#endif #elif defined(TARGET_PPC) if (flags) disasm_info.endian = BFD_ENDIAN_LITTLE; @@ -298,7 +298,7 @@ const char *lookup_symbol(target_ulong orig_addr) 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++) { diff --git a/dyngen.c b/dyngen.c index a8bc201f5..f136e02c2 100644 --- a/dyngen.c +++ b/dyngen.c @@ -375,7 +375,7 @@ int elf_must_swap(struct elfhdr *h) 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 */ @@ -483,11 +483,11 @@ int load_object(const char *filename) 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"); @@ -524,7 +524,7 @@ int load_object(const char *filename) /* 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) @@ -569,7 +569,7 @@ int load_object(const char *filename) 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++) { @@ -609,7 +609,7 @@ 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++) { @@ -643,7 +643,7 @@ char *name_for_dotdata(struct coff_rel *rel) 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; } @@ -709,7 +709,7 @@ int load_object(const char *filename) ); 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"); @@ -726,7 +726,7 @@ int load_object(const char *filename) /* 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]; @@ -747,7 +747,7 @@ int load_object(const char *filename) 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++) @@ -758,7 +758,7 @@ int load_object(const char *filename) 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++) { @@ -805,12 +805,12 @@ int load_object(const char *filename) } 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); @@ -870,7 +870,7 @@ static char *get_sym_name(EXE_SYM *sym) if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */ return "debug"; - + if(!name) return name; if(name[0]=='_') @@ -953,23 +953,23 @@ static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec { 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]; @@ -1015,7 +1015,7 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide) /* 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; @@ -1041,7 +1041,7 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide) 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]); @@ -1080,11 +1080,11 @@ int load_object(const char *filename) 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"); @@ -1093,13 +1093,13 @@ int load_object(const char *filename) 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); insects); 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); @@ -1159,10 +1159,10 @@ int load_object(const char *filename) /* 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"); @@ -1178,12 +1178,12 @@ int load_object(const char *filename) 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)) @@ -1286,9 +1286,9 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, 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; @@ -1478,7 +1478,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } copy_size = len; } -#endif +#endif #elif defined(HOST_PPC) { uint8_t *p; @@ -1510,7 +1510,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #endif if (get32((uint32_t *)p) != 0x6bfa8001) error("ret expected at the end of %s", name); - copy_size = p - p_start; + copy_size = p - p_start; } #elif defined(HOST_IA64) { @@ -1611,14 +1611,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } 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) @@ -1700,7 +1700,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } - + nb_args = 0; while (nb_args < MAX_ARGS && args_present[nb_args]) nb_args++; @@ -1784,7 +1784,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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 @@ -1828,7 +1828,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } -#endif +#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)); @@ -1973,7 +1973,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, n, reloc_offset); continue; } - + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; @@ -2652,7 +2652,7 @@ int gen_file(FILE *outfile, int out_type) gen_code(name, sym->st_value, sym->st_size, outfile, 0); } } - + } else { /* generate big code generation switch */ @@ -2695,7 +2695,7 @@ fprintf(outfile, 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. ] diff --git a/dyngen.h b/dyngen.h index 7ac17baf3..266b9e972 100644 --- a/dyngen.h +++ b/dyngen.h @@ -51,7 +51,7 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop) 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"); } @@ -169,12 +169,12 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, 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; diff --git a/elf_ops.h b/elf_ops.h index 96cd8fdbf..75cbdedda 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -75,13 +75,13 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) sizeof(struct elf_shdr) * ehdr->e_shnum); if (!shdr_table) return -1; - + if (must_swab) { for (i = 0; i < ehdr->e_shnum; i++) { glue(bswap_shdr, SZ)(shdr_table + i); } } - + symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); if (!symtab) goto fail; @@ -176,7 +176,7 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, glue(bswap_phdr, SZ)(ph); } } - + total_size = 0; for(i = 0; i < ehdr.e_phnum; i++) { ph = &phdr[i]; diff --git a/exec-all.h b/exec-all.h index ade888ae3..434605d8d 100644 --- a/exec-all.h +++ b/exec-all.h @@ -68,7 +68,7 @@ typedef void (GenOpFunc)(void); typedef void (GenOpFunc1)(long); typedef void (GenOpFunc2)(long, long); typedef void (GenOpFunc3)(long, long, long); - + #if defined(TARGET_I386) void optimize_flags_init(void); @@ -287,7 +287,7 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, if (!tb->jmp_next[n]) { /* patch the native jump address */ tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr); - + /* add in TB jmp circular list */ tb->jmp_next[n] = tb_next->jmp_first; tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n)); @@ -398,7 +398,7 @@ static inline int testandset (int *p) static inline int testandset (int *p) { long int readval = 0; - + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" : "+m" (*p), "+a" (readval) : "r" (1) @@ -409,7 +409,7 @@ static inline int testandset (int *p) static inline int testandset (int *p) { long int readval = 0; - + __asm__ __volatile__ ("lock; cmpxchgl %2, %0" : "+m" (*p), "+a" (readval) : "r" (1) @@ -464,7 +464,7 @@ static inline int testandset (int *spinlock) __asm__ __volatile__("swp %0, %1, [%2]" : "=r"(ret) : "0"(1), "r"(spinlock)); - + return ret; } #elif defined(__mc68000) diff --git a/exec.c b/exec.c index e7ce28d4b..5c716b320 100644 --- a/exec.c +++ b/exec.c @@ -175,10 +175,10 @@ static void page_init(void) { SYSTEM_INFO system_info; DWORD old_protect; - + GetSystemInfo(&system_info); qemu_real_host_page_size = system_info.dwPageSize; - + VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer), PAGE_EXECUTE_READWRITE, &old_protect); } @@ -189,11 +189,11 @@ static void page_init(void) start = (unsigned long)code_gen_buffer; start &= ~(qemu_real_host_page_size - 1); - + end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer); end += qemu_real_host_page_size - 1; end &= ~(qemu_real_host_page_size - 1); - + mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC); } @@ -345,7 +345,7 @@ void tb_flush(CPUState *env1) nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); #endif nb_tbs = 0; - + for(env = first_cpu; env != NULL; env = env->next_cpu) { memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); } @@ -382,7 +382,7 @@ static void tb_page_check(void) { TranslationBlock *tb; int i, flags1, flags2; - + for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) { for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { flags1 = page_get_flags(tb->pc); @@ -491,7 +491,7 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad unsigned int h, n1; target_ulong phys_pc; TranslationBlock *tb1, *tb2; - + /* remove the TB from the hash list */ phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); h = tb_phys_hash_func(phys_pc); @@ -571,7 +571,7 @@ static void build_page_bitmap(PageDesc *p) { int n, tb_start, tb_end; TranslationBlock *tb; - + p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8); if (!p->code_bitmap) return; @@ -624,7 +624,7 @@ static void tb_gen_code(CPUState *env, tb->cflags = cflags; 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; @@ -634,7 +634,7 @@ static void tb_gen_code(CPUState *env, tb_link_phys(tb, phys_pc, phys_page2); } #endif - + /* invalidate all TBs which intersect with the target physical page starting in range [start;end[. NOTE: start and end must refer to the same physical page. 'is_cpu_write_access' should be true if called @@ -700,7 +700,7 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, that the modification is after the current PC, but it would require a specialized function to partially restore the CPU state */ - + current_tb_modified = 1; cpu_restore_state(current_tb, env, env->mem_write_pc, NULL); @@ -819,7 +819,7 @@ static void tb_invalidate_phys_page(target_ulong addr, that the modification is after the current PC, but it would require a specialized function to partially restore the CPU state */ - + current_tb_modified = 1; cpu_restore_state(current_tb, env, pc, puc); #if defined(TARGET_I386) @@ -1024,7 +1024,7 @@ static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) } *ptb = tb->jmp_next[n]; tb->jmp_next[n] = NULL; - + /* suppress the jump to next tb in generated code */ tb_reset_jump(tb, n); @@ -1103,7 +1103,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) { #if defined(TARGET_HAS_ICE) int i; - + for(i = 0; i < env->nb_breakpoints; i++) { if (env->breakpoints[i] == pc) return 0; @@ -1112,7 +1112,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc) if (env->nb_breakpoints >= MAX_BREAKPOINTS) return -1; env->breakpoints[env->nb_breakpoints++] = pc; - + breakpoint_invalidate(env, pc); return 0; #else @@ -1249,7 +1249,7 @@ static int cmp1(const char *s1, int n, const char *s2) return 0; return memcmp(s1, s2, n) == 0; } - + /* takes a comma separated list of log masks. Return 0 if error. */ int cpu_str_to_log_mask(const char *str) { @@ -1703,7 +1703,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, /* if code is present, we only map as read only and save the original mapping */ VirtPageDesc *vp; - + vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1); vp->phys_addr = pd; vp->prot = prot; @@ -2008,7 +2008,7 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, } } } - + /* since each CPU stores ram addresses in its TLB cache, we must reset the modified entries */ /* XXX: slow ! */ @@ -2492,7 +2492,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, target_phys_addr_t page; unsigned long pd; PhysPageDesc *p; - + while (len > 0) { page = addr & TARGET_PAGE_MASK; l = (page + TARGET_PAGE_SIZE) - addr; @@ -2504,7 +2504,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } else { pd = p->phys_offset; } - + if (is_write) { if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); @@ -2583,7 +2583,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, target_phys_addr_t page; unsigned long pd; PhysPageDesc *p; - + while (len > 0) { page = addr & TARGET_PAGE_MASK; l = (page + TARGET_PAGE_SIZE) - addr; @@ -2595,7 +2595,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { @@ -2629,7 +2629,7 @@ uint32_t ldl_phys(target_phys_addr_t addr) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { /* I/O case */ @@ -2659,7 +2659,7 @@ uint64_t ldq_phys(target_phys_addr_t addr) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { /* I/O case */ @@ -2712,7 +2712,7 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); @@ -2736,7 +2736,7 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); #ifdef TARGET_WORDS_BIGENDIAN @@ -2767,7 +2767,7 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) } else { pd = p->phys_offset; } - + if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); @@ -2842,7 +2842,7 @@ void dump_exec_info(FILE *f, int i, target_code_size, max_target_code_size; int direct_jmp_count, direct_jmp2_count, cross_page; TranslationBlock *tb; - + target_code_size = 0; max_target_code_size = 0; cross_page = 0; diff --git a/gdbstub.c b/gdbstub.c index dc10357ea..28f9b440c 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -252,7 +252,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) registers[41] = 0; /* foseg */ registers[42] = 0; /* fooff */ registers[43] = 0; /* fop */ - + for(i = 0; i < 16; i++) tswapls(®isters[i]); for(i = 36; i < 44; i++) @@ -748,7 +748,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) uint8_t mem_buf[2000]; uint32_t *registers; target_ulong addr, len; - + #ifdef DEBUG_GDB printf("command='%s'\n", line_buf); #endif @@ -1201,7 +1201,7 @@ static void gdb_accept(void *opaque) /* set short latency */ val = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); - + s = &gdbserver_state; memset (s, 0, sizeof (GDBState)); s->env = first_cpu; /* XXX: allow to change CPU */ diff --git a/hw/acpi.c b/hw/acpi.c index add8cc838..37fadaab6 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -87,7 +87,7 @@ static void pm_update_sci(PIIX4PMState *s) { int sci_level, pmsts; int64_t expire_time; - + pmsts = get_pmsts(s); sci_level = (((pmsts & s->pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); @@ -239,7 +239,7 @@ static uint32_t pm_smi_readb(void *opaque, uint32_t addr) { PIIX4PMState *s = opaque; uint32_t val; - + addr &= 1; if (addr == 0) { val = s->apmc; @@ -480,9 +480,9 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base) pci_conf[0x0b] = 0x06; // bridge device pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 0x01; // interrupt pin 1 - + pci_conf[0x40] = 0x01; /* PM io base read only bit */ - + register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s); register_ioport_read(0xb2, 2, 1, pm_smi_readb, s); diff --git a/hw/adb.c b/hw/adb.c index 756c07906..1e43792b5 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -299,31 +299,31 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) if (s->last_buttons_state == s->buttons_state && s->dx == 0 && s->dy == 0) return 0; - + dx = s->dx; if (dx < -63) dx = -63; else if (dx > 63) dx = 63; - + dy = s->dy; if (dy < -63) dy = -63; else if (dy > 63) dy = 63; - + s->dx -= dx; s->dy -= dy; s->last_buttons_state = s->buttons_state; - + dx &= 0x7f; dy &= 0x7f; - + if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) dy |= 0x80; if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) dx |= 0x80; - + obuf[0] = dy; obuf[1] = dx; return 2; @@ -334,7 +334,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, { MouseState *s = d->opaque; int cmd, reg, olen; - + if ((buf[0] & 0x0f) == ADB_FLUSH) { /* flush mouse fifo */ s->buttons_state = s->last_buttons_state; diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c index 8df7d8904..da2d9ad06 100644 --- a/hw/alpha_palcode.c +++ b/hw/alpha_palcode.c @@ -937,7 +937,7 @@ static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot, } } *paddr = (pfn << page_bits) | (vaddr & page_mask); - + return 0; } diff --git a/hw/apic.c b/hw/apic.c index bbe44fa7d..9e0f4762f 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -222,7 +222,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, foreach_apic(apic_iter, deliver_bitmask, apic_init_ipi(apic_iter) ); return; - + case APIC_DM_EXTINT: /* handled in I/O APIC code */ break; @@ -471,7 +471,7 @@ int apic_get_interrupt(CPUState *env) return -1; if (!(s->spurious_vec & APIC_SV_ENABLE)) return -1; - + /* XXX: spurious IRQ handling */ intno = get_highest_priority_int(s->irr); if (intno < 0) @@ -505,7 +505,7 @@ static uint32_t apic_get_current_count(APICState *s) static void apic_timer_update(APICState *s, int64_t current_time) { int64_t next_time, d; - + if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { d = (current_time - s->initial_count_load_time) >> s->count_shift; @@ -834,7 +834,7 @@ int apic_init(CPUState *env) register_savevm("apic", s->id, 2, apic_save, apic_load, s); qemu_register_reset(apic_reset, s); - + local_apics[s->id] = s; return 0; } @@ -868,7 +868,7 @@ static void ioapic_service(IOAPICState *s) vector = pic_read_irq(isa_pic); else vector = entry & 0xff; - + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); apic_bus_deliver(deliver_bitmask, delivery_mode, vector, polarity, trig_mode); @@ -1042,6 +1042,6 @@ IOAPICState *ioapic_init(void) register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s); qemu_register_reset(ioapic_reset, s); - + return s; } diff --git a/hw/cdrom.c b/hw/cdrom.c index 18c7e31c6..4f1fce18f 100644 --- a/hw/cdrom.c +++ b/hw/cdrom.c @@ -41,7 +41,7 @@ int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track) { uint8_t *q; int len; - + if (start_track > 1 && start_track != 0xaa) return -1; q = buf + 2; @@ -85,7 +85,7 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) { uint8_t *q; int len; - + q = buf + 2; *q++ = 1; /* first session */ *q++ = 1; /* last session */ @@ -101,7 +101,7 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) *q++ = 1; /* first track */ *q++ = 0x00; /* disk type */ *q++ = 0x00; - + *q++ = 1; /* session number */ *q++ = 0x14; /* data track */ *q++ = 0; /* track number */ @@ -113,7 +113,7 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num) *q++ = 1; /* last track */ *q++ = 0x00; *q++ = 0x00; - + *q++ = 1; /* session number */ *q++ = 0x14; /* data track */ *q++ = 0; /* track number */ diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index febac441e..85bf4a21f 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -275,7 +275,7 @@ typedef struct PCICirrusVGAState { } PCICirrusVGAState; static uint8_t rop_to_index[256]; - + /*************************************** * * prototypes. @@ -788,7 +788,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) { int copy_count; uint8_t *end_ptr; - + if (s->cirrus_srccounter > 0) { if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf); @@ -1148,7 +1148,7 @@ static int cirrus_get_bpp(VGAState *s1) static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight) { int width, height; - + width = (s->cr[0x01] + 1) * 8; height = s->cr[0x12] | ((s->cr[0x07] & 0x02) << 7) | @@ -2223,7 +2223,7 @@ static void cirrus_cursor_invalidate(VGAState *s1) s->last_hw_cursor_y != s->hw_cursor_y) { invalidate_cursor1(s); - + s->last_hw_cursor_size = size; s->last_hw_cursor_x = s->hw_cursor_x; s->last_hw_cursor_y = s->hw_cursor_y; @@ -2240,7 +2240,7 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) unsigned int color0, color1; const uint8_t *palette, *src; uint32_t content; - + if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW)) return; /* fast test to see if the cursor intersects with the scan line */ @@ -2252,7 +2252,7 @@ static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) if (scr_y < s->hw_cursor_y || scr_y >= (s->hw_cursor_y + h)) return; - + src = s->vram_ptr + s->real_vram_size - 16 * 1024; if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { src += (s->sr[0x13] & 0x3c) * 256; @@ -2379,7 +2379,7 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr, unsigned mode; addr &= s->cirrus_addr_mask; - + if (((s->sr[0x17] & 0x44) == 0x44) && ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { /* memory-mapped I/O */ @@ -2600,7 +2600,7 @@ static void cirrus_update_memory_access(CirrusVGAState *s) } else if (s->gr[0x0B] & 0x02) { goto generic_io; } - + mode = s->gr[0x05] & 0x7; if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { s->cirrus_linear_write[0] = cirrus_linear_mem_writeb; @@ -3190,7 +3190,7 @@ void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, CirrusVGAState *s; s = qemu_mallocz(sizeof(CirrusVGAState)); - + vga_common_init((VGAState *)s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0); @@ -3231,7 +3231,7 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, uint8_t *pci_conf; CirrusVGAState *s; int device_id; - + device_id = CIRRUS_ID_CLGD5446; /* setup PCI configuration registers */ diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h index 91f0db83d..137681ed1 100644 --- a/hw/cirrus_vga_rop2.h +++ b/hw/cirrus_vga_rop2.h @@ -34,7 +34,7 @@ #define PUTPIXEL() ROP_OP(((uint32_t *)d)[0], col) #else #error unsupported DEPTH -#endif +#endif static void glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) diff --git a/hw/cuda.c b/hw/cuda.c index 75ceea1e4..7312bbddc 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -116,10 +116,10 @@ typedef struct CUDAState { uint8_t anh; /* A-side data, no handshake */ CUDATimer timers[2]; - + uint8_t last_b; /* last value of B register */ uint8_t last_acr; /* last value of B register */ - + int data_in_size; int data_in_index; int data_out_index; @@ -196,7 +196,7 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) counter = (d - (s->counter_value + 1)) % (s->latch + 2); counter = (s->latch - counter) & 0xffff; } - + /* Note: we consider the irq is raised on 0 */ if (counter == 0xffff) { next_time = d + s->latch + 1; @@ -317,7 +317,7 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { CUDAState *s = opaque; - + addr = (addr >> 9) & 0xf; #ifdef DEBUG_CUDA printf("cuda: write: reg=0x%x val=%02x\n", addr, val); diff --git a/hw/esp.c b/hw/esp.c index 0d22ce35e..943a159e0 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -531,7 +531,7 @@ static void esp_save(QEMUFile *f, void *opaque) static int esp_load(QEMUFile *f, void *opaque, int version_id) { ESPState *s = opaque; - + if (version_id != 3) return -EINVAL; // Cannot emulate 2 diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index a2f938c7c..fb4605166 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -118,12 +118,12 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) d->config[0x1a] = 0x00; // subordinate_bus d->config[0x1c] = 0x00; d->config[0x1d] = 0x00; - + d->config[0x20] = 0x00; // memory_base d->config[0x21] = 0x00; d->config[0x22] = 0x01; // memory_limit d->config[0x23] = 0x00; - + d->config[0x24] = 0x00; // prefetchable_memory_base d->config[0x25] = 0x00; d->config[0x26] = 0x00; // prefetchable_memory_limit @@ -145,12 +145,12 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) d->config[0x1a] = 0x1; // subordinate_bus d->config[0x1c] = 0x10; // io_base d->config[0x1d] = 0x20; // io_limit - + d->config[0x20] = 0x80; // memory_base d->config[0x21] = 0x80; d->config[0x22] = 0x90; // memory_limit d->config[0x23] = 0x80; - + d->config[0x24] = 0x00; // prefetchable_memory_base d->config[0x25] = 0x84; d->config[0x26] = 0x00; // prefetchable_memory_limit diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 26821e8c0..fbebbbe6e 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -287,10 +287,10 @@ static void gt64120_pci_mapping(GT64120State *s) /* Update IO mapping */ if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD]) { - /* Unmap old IO address */ + /* Unmap old IO address */ if (s->PCI0IO_length) { - cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED); + cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED); } /* Map new IO address */ s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21; diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index a31d24b20..96eb6565f 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -88,7 +88,7 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) HeathrowPIC *pic; unsigned int n; uint32_t value; - + n = ((addr & 0xfff) - 0x10) >> 4; if (n >= 2) { value = 0; @@ -159,7 +159,7 @@ static void heathrow_pic_set_irq(void *opaque, int num, int level) qemu_irq *heathrow_pic_init(int *pmem_index) { HeathrowPICS *s; - + s = qemu_mallocz(sizeof(HeathrowPICS)); s->pics[0].level_triggered = 0; s->pics[1].level_triggered = 0x1ff00000; diff --git a/hw/i8254.c b/hw/i8254.c index db8a1b97f..54407de4d 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -309,7 +309,7 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr) PITState *pit = opaque; int ret, count; PITChannelState *s; - + addr &= 3; s = &pit->channels[addr]; if (s->status_latched) { @@ -391,7 +391,7 @@ static void pit_save(QEMUFile *f, void *opaque) PITState *pit = opaque; PITChannelState *s; int i; - + for(i = 0; i < 3; i++) { s = &pit->channels[i]; qemu_put_be32s(f, &s->count); @@ -419,7 +419,7 @@ static int pit_load(QEMUFile *f, void *opaque, int version_id) PITState *pit = opaque; PITChannelState *s; int i; - + if (version_id != 1) return -EINVAL; diff --git a/hw/i8259.c b/hw/i8259.c index 09aabe223..7c94d8d84 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -155,7 +155,7 @@ void pic_update_irq(PicState2 *s) printf("pic%d: imr=%x irr=%x padd=%d\n", i, s->pics[i].imr, s->pics[i].irr, s->pics[i].priority_add); - + } } printf("pic: cpu_interrupt\n"); @@ -243,7 +243,7 @@ int pic_read_irq(PicState2 *s) intno = s->pics[0].irq_base + irq; } pic_update_irq(s); - + #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", irq, @@ -429,7 +429,7 @@ uint32_t pic_intack_read(PicState2 *s) ret = pic_poll_read(&s->pics[1], 0x80) + 8; /* Prepare for ISR read */ s->pics[0].read_reg_select = 1; - + return ret; } @@ -448,7 +448,7 @@ static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1) static void pic_save(QEMUFile *f, void *opaque) { PicState *s = opaque; - + qemu_put_8s(f, &s->last_irr); qemu_put_8s(f, &s->irr); qemu_put_8s(f, &s->imr); @@ -470,7 +470,7 @@ static void pic_save(QEMUFile *f, void *opaque) static int pic_load(QEMUFile *f, void *opaque, int version_id) { PicState *s = opaque; - + if (version_id != 1) return -EINVAL; @@ -510,7 +510,7 @@ void pic_info(void) { int i; PicState *s; - + if (!isa_pic) return; diff --git a/hw/ide.c b/hw/ide.c index c3b0e11e8..329d053e1 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -392,7 +392,7 @@ typedef struct BMDMAState { uint8_t cmd; uint8_t status; uint32_t addr; - + struct PCIIDEState *pci_dev; /* current transfer state */ uint32_t cur_addr; @@ -469,7 +469,7 @@ static void ide_identify(IDEState *s) put_le16(p + 22, 4); /* ecc bytes */ padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ -#if MAX_MULT_SECTORS > 1 +#if MAX_MULT_SECTORS > 1 put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); #endif put_le16(p + 48, 1); /* dword I/O */ @@ -923,7 +923,7 @@ static void ide_sector_write(IDEState *s) ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); } ide_set_sector(s, sector_num + n); - + bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, ide_sector_write_aio_cb, bm); } @@ -1246,7 +1246,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) bm->aiocb = NULL; return; } - + s->io_buffer_index = 0; if (s->cd_sector_size == 2352) { n = 1; @@ -1375,7 +1375,7 @@ static void ide_atapi_cmd(IDEState *s) buf[9] = 0x12; buf[10] = 0x08; buf[11] = 0x00; - + buf[12] = 0x70; buf[13] = 3 << 5; buf[14] = (1 << 0) | (1 << 3) | (1 << 5); @@ -1501,7 +1501,7 @@ static void ide_atapi_cmd(IDEState *s) int start, eject; start = packet[4] & 1; eject = (packet[4] >> 1) & 1; - + if (eject && !start) { /* eject the disk */ bdrv_eject(s->bs, 1); @@ -2330,7 +2330,7 @@ static uint32_t ide_data_readl(void *opaque, uint32_t addr) IDEState *s = ((IDEState *)opaque)->cur_drive; uint8_t *p; int ret; - + p = s->data_ptr; ret = cpu_to_le32(*(uint32_t *)p); p += 4; @@ -2509,7 +2509,7 @@ static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2) register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state); register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state); } - + /* data ports */ register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state); register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state); @@ -2584,7 +2584,7 @@ void isa_ide_init(int iobase, int iobase2, qemu_irq irq, ide_state = qemu_mallocz(sizeof(IDEState) * 2); if (!ide_state) return; - + ide_init2(ide_state, hd0, hd1, irq); ide_init_ioport(ide_state, iobase, iobase2); } @@ -2671,7 +2671,7 @@ static uint32_t bmdma_readb(void *opaque, uint32_t addr) BMDMAState *bm = opaque; PCIIDEState *pci_dev; uint32_t val; - + switch(addr & 3) { case 0: val = bm->cmd; @@ -2835,7 +2835,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage pci_conf[0x0e] = 0x00; // header_type - + if (secondary_ide_enabled) { /* XXX: if not enabled, really disable the seconday IDE controller */ pci_conf[0x51] = 0x80; /* enable IDE1 */ @@ -2853,7 +2853,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, PCI_ADDRESS_SPACE_IO, bmdma_map); pci_conf[0x3d] = 0x01; // interrupt on pin 1 - + for(i = 0; i < 4; i++) d->ide_if[i].pci_dev = (PCIDevice *)d; @@ -2945,7 +2945,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, { PCIIDEState *d; uint8_t *pci_conf; - + /* register a function 1 of PIIX3 */ d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", sizeof(PCIIDEState), @@ -3133,7 +3133,7 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq) ide_if = qemu_mallocz(sizeof(IDEState) * 2); ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq); - + pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, pmac_ide_write, &ide_if[0]); return pmac_ide_memory; diff --git a/hw/iommu.c b/hw/iommu.c index bd52454bb..c36178cdc 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -279,7 +279,7 @@ static void iommu_save(QEMUFile *f, void *opaque) { IOMMUState *s = opaque; int i; - + for (i = 0; i < IOMMU_NREGS; i++) qemu_put_be32s(f, &s->regs[i]); qemu_put_be64s(f, &s->iostart); @@ -289,7 +289,7 @@ static int iommu_load(QEMUFile *f, void *opaque, int version_id) { IOMMUState *s = opaque; int i; - + if (version_id != 2) return -EINVAL; @@ -322,7 +322,7 @@ void *iommu_init(target_phys_addr_t addr) iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); - + register_savevm("iommu", addr, 2, iommu_save, iommu_load, s); qemu_register_reset(iommu_reset, s); return s; diff --git a/hw/m48t59.c b/hw/m48t59.c index e097a7cb1..c2c0decc8 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -90,7 +90,7 @@ static void get_time (m48t59_t *NVRAM, struct tm *tm) static void set_time (m48t59_t *NVRAM, struct tm *tm) { time_t now, new_time; - + new_time = mktime(tm); now = time(NULL); NVRAM->time_offset = new_time - now; @@ -510,7 +510,7 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t59_t *NVRAM = opaque; - + addr -= NVRAM->mem_base; m48t59_write(NVRAM, addr, value & 0xff); } @@ -518,7 +518,7 @@ static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t59_t *NVRAM = opaque; - + addr -= NVRAM->mem_base; m48t59_write(NVRAM, addr, (value >> 8) & 0xff); m48t59_write(NVRAM, addr + 1, value & 0xff); @@ -527,7 +527,7 @@ static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { m48t59_t *NVRAM = opaque; - + addr -= NVRAM->mem_base; m48t59_write(NVRAM, addr, (value >> 24) & 0xff); m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff); @@ -539,7 +539,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) { m48t59_t *NVRAM = opaque; uint32_t retval; - + addr -= NVRAM->mem_base; retval = m48t59_read(NVRAM, addr); return retval; @@ -549,7 +549,7 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) { m48t59_t *NVRAM = opaque; uint32_t retval; - + addr -= NVRAM->mem_base; retval = m48t59_read(NVRAM, addr) << 8; retval |= m48t59_read(NVRAM, addr + 1); diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 8d0da95d8..789ebd3f6 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -110,7 +110,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) #ifdef DEBUG_CMOS printf("cmos: write index=0x%02x val=0x%02x\n", s->cmos_index, data); -#endif +#endif switch(s->cmos_index) { case RTC_SECONDS_ALARM: case RTC_MINUTES_ALARM: @@ -283,7 +283,7 @@ static void rtc_update_second(void *opaque) qemu_mod_timer(s->second_timer, s->next_second_time); } else { rtc_next_second(&s->current_tm); - + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { /* update in progress bit */ s->cmos_data[RTC_REG_A] |= REG_A_UIP; @@ -411,7 +411,7 @@ static void rtc_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, s->cmos_data, 128); qemu_put_8s(f, &s->cmos_index); - + qemu_put_be32s(f, &s->current_tm.tm_sec); qemu_put_be32s(f, &s->current_tm.tm_min); qemu_put_be32s(f, &s->current_tm.tm_hour); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index ab4d3fdd4..3b37596d1 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -510,9 +510,9 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x00000000); /* nop */ /* YAMON service vector */ - stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */ + stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */ stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c); /* print_count: */ - stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */ + stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */ stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800); /* flush_cache: */ stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808); /* print: */ stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800); /* reg_cpu_isr: */ diff --git a/hw/ne2000.c b/hw/ne2000.c index a5e033126..689216c6a 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -212,7 +212,7 @@ static int ne2000_buffer_full(NE2000State *s) static int ne2000_can_receive(void *opaque) { NE2000State *s = opaque; - + if (s->cmd & E8390_STOP) return 1; return !ne2000_buffer_full(s); @@ -228,14 +228,14 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) uint8_t buf1[60]; static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - + #if defined(DEBUG_NE2000) printf("NE2000: received len=%d\n", size); #endif if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) return; - + /* XXX: check this */ if (s->rxcr & 0x10) { /* promiscuous: receive all */ @@ -252,10 +252,10 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) return; } else if (s->mem[0] == buf[0] && - s->mem[2] == buf[1] && - s->mem[4] == buf[2] && - s->mem[6] == buf[3] && - s->mem[8] == buf[4] && + s->mem[2] == buf[1] && + s->mem[4] == buf[2] && + s->mem[6] == buf[3] && + s->mem[8] == buf[4] && s->mem[10] == buf[5]) { /* match */ } else { @@ -718,11 +718,11 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) { NE2000State *s; - + s = qemu_mallocz(sizeof(NE2000State)); if (!s) return; - + register_ioport_write(base, 16, 1, ne2000_ioport_write, s); register_ioport_read(base, 16, 1, ne2000_ioport_read, s); @@ -749,7 +749,7 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) s->macaddr[3], s->macaddr[4], s->macaddr[5]); - + register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); } @@ -786,7 +786,7 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) PCINE2000State *d; NE2000State *s; uint8_t *pci_conf; - + d = (PCINE2000State *)pci_register_device(bus, "NE2000", sizeof(PCINE2000State), devfn, @@ -800,7 +800,7 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 1; // interrupt pin 0 - + pci_register_io_region(&d->dev, 0, 0x100, PCI_ADDRESS_SPACE_IO, ne2000_map); s = &d->ne2000; @@ -819,7 +819,7 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) s->macaddr[3], s->macaddr[4], s->macaddr[5]); - + /* XXX: instance number ? */ register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s); } diff --git a/hw/openpic.c b/hw/openpic.c index bd5282870..54830c31b 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -475,7 +475,7 @@ static uint32_t read_doorbell_register (openpic_t *opp, return retval; } - + static void write_doorbell_register (penpic_t *opp, int n_dbl, uint32_t offset, uint32_t value) { @@ -831,7 +831,7 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) IRQ_dst_t *dst; uint32_t retval; int idx, n_IRQ; - + DPRINTF("%s: addr %08x\n", __func__, addr); retval = 0xFFFFFFFF; if (addr & 0xF) @@ -1005,7 +1005,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, openpic_t *opp; uint8_t *pci_conf; int i, m; - + /* XXX: for now, only one CPU is supported */ if (nb_cpus != 1) return NULL; @@ -1023,7 +1023,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, pci_conf[0x0b] = 0x08; pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 0x00; // no interrupt pin - + /* Register I/O spaces */ pci_register_io_region((PCIDevice *)opp, 0, 0x40000, PCI_ADDRESS_SPACE_MEM, &openpic_map); @@ -1032,7 +1032,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, } opp->mem_index = cpu_register_io_memory(0, openpic_read, openpic_write, opp); - + // isu_base &= 0xFFFC0000; opp->nb_cpus = nb_cpus; /* Set IRQ types */ diff --git a/hw/parallel.c b/hw/parallel.c index 9558c3f17..bda3f3a20 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -88,7 +88,7 @@ static void parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val) { ParallelState *s = opaque; - + pdebug("write addr=0x%02x val=0x%02x\n", addr, val); addr &= 7; diff --git a/hw/pc.c b/hw/pc.c index a4ce37e36..ace0cee1f 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -182,7 +182,7 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table val = 65535; rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); - + switch(boot_device) { case 'a': case 'b': @@ -209,7 +209,7 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1); rtc_set_memory(s, 0x10, val); - + val = 0; nb = 0; if (fd0 < 3) @@ -294,7 +294,7 @@ void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) { static const char shutdown_str[8] = "Shutdown"; static int shutdown_index = 0; - + switch(addr) { /* Bochs BIOS messages */ case 0x400: @@ -783,7 +783,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, /* map all the bios at the top of memory */ cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); - + bochs_bios_init(); if (linux_boot) @@ -914,7 +914,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); } } - + if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); } diff --git a/hw/pci.c b/hw/pci.c index 55cdaa499..7e8adc463 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -105,7 +105,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, if (pci_irq_index >= PCI_DEVICES_MAX) return NULL; - + if (devfn < 0) { for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { if (!bus->devices[devfn]) @@ -166,7 +166,7 @@ static void pci_update_mappings(PCIDevice *d) PCIIORegion *r; int cmd, i; uint32_t last_addr, new_addr, config_ofs; - + cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND)); for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; @@ -367,7 +367,7 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) PCIBus *s = opaque; PCIDevice *pci_dev; int config_addr, bus_num; - + #if defined(DEBUG_PCI) && 0 printf("pci_data_write: addr=%08x val=%08x len=%d\n", addr, val, len); @@ -440,7 +440,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level) PCIDevice *pci_dev = (PCIDevice *)opaque; PCIBus *bus; int change; - + change = level - pci_dev->irq_state[irq_num]; if (!change) return; @@ -556,7 +556,7 @@ void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d)) PCIBus *bus = first_bus; PCIDevice *d; int devfn; - + while (bus && bus->bus_num != bus_num) bus = bus->next; if (bus) { diff --git a/hw/pckbd.c b/hw/pckbd.c index 9b036a676..ff4916d21 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -338,7 +338,7 @@ static void kbd_reset(void *opaque) static void kbd_save(QEMUFile* f, void* opaque) { KBDState *s = (KBDState*)opaque; - + qemu_put_8s(f, &s->write_cmd); qemu_put_8s(f, &s->status); qemu_put_8s(f, &s->mode); @@ -348,7 +348,7 @@ static void kbd_save(QEMUFile* f, void* opaque) static int kbd_load(QEMUFile* f, void* opaque, int version_id) { KBDState *s = (KBDState*)opaque; - + if (version_id != 3) return -EINVAL; qemu_get_8s(f, &s->write_cmd); diff --git a/hw/pcnet.c b/hw/pcnet.c index 11e8fe997..71a05da8d 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -731,7 +731,7 @@ static void pcnet_s_reset(PCNetState *s) s->rdra = 0; s->tdra = 0; s->rap = 0; - + s->bcr[BCR_BSBC] &= ~0x0080; s->csr[0] = 0x0004; @@ -770,7 +770,7 @@ static void pcnet_update_irq(PCNetState *s) { int isr = 0; s->csr[0] &= ~0x0080; - + #if 1 if (((s->csr[0] & ~s->csr[3]) & 0x5f00) || (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) || @@ -790,11 +790,11 @@ static void pcnet_update_irq(PCNetState *s) (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */) #endif { - + isr = CSR_INEA(s); s->csr[0] |= 0x0080; } - + if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */ s->csr[4] &= ~0x0080; s->csr[4] |= 0x0040; @@ -834,7 +834,7 @@ static void pcnet_init(PCNetState *s) #ifdef PCNET_DEBUG printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); #endif - + if (BCR_SSIZE32(s)) { struct pcnet_initblk32 initblk; s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), @@ -898,7 +898,7 @@ static void pcnet_init(PCNetState *s) s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s)); #endif - s->csr[0] |= 0x0101; + s->csr[0] |= 0x0101; s->csr[0] &= ~0x0004; /* clear STOP bit */ } @@ -910,7 +910,7 @@ static void pcnet_start(PCNetState *s) if (!CSR_DTX(s)) s->csr[0] |= 0x0010; /* set TXON */ - + if (!CSR_DRX(s)) s->csr[0] |= 0x0020; /* set RXON */ @@ -976,7 +976,7 @@ static void pcnet_rdte_poll(PCNetState *s) #endif } } - + if (CSR_CRDA(s)) { struct pcnet_RMD rmd; RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); @@ -991,7 +991,7 @@ static void pcnet_rdte_poll(PCNetState *s) } else { CSR_CRBC(s) = CSR_CRST(s) = 0; } - + if (CSR_NRDA(s)) { struct pcnet_RMD rmd; RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); @@ -1030,14 +1030,14 @@ static int pcnet_tdte_poll(PCNetState *s) if (CSR_CXDA(s)) { struct pcnet_TMD tmd; - TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); + TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT); CSR_CXST(s) = tmd.status; } else { CSR_CXBC(s) = CSR_CXST(s) = 0; } - + return !!(CSR_CXST(s) & 0x8000); } @@ -1046,7 +1046,7 @@ static int pcnet_can_receive(void *opaque) PCNetState *s = opaque; if (CSR_STOP(s) || CSR_SPND(s)) return 0; - + if (s->recv_pos > 0) return 0; @@ -1093,7 +1093,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) nrda = s->rdra + (CSR_RCVRL(s) - rcvrc) * (BCR_SWSTYLE(s) ? 16 : 8 ); - RMDLOAD(&rmd, PHYSADDR(s,nrda)); + RMDLOAD(&rmd, PHYSADDR(s,nrda)); if (GET_FIELD(rmd.status, RMDS, OWN)) { #ifdef PCNET_DEBUG_RMD printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", @@ -1119,7 +1119,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) int pktcount = 0; memcpy(src, buf, size); - + #if 1 /* no need to compute the CRC */ src[size] = 0; @@ -1136,7 +1136,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) while (size < 46) { src[size++] = 0; } - + while (p != &src[size]) { CRC(fcs, *p++); } @@ -1178,7 +1178,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) PCNET_RECV_STORE(); } } - } + } } #undef PCNET_RECV_STORE @@ -1203,22 +1203,22 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) #endif #ifdef PCNET_DEBUG_RMD PRINT_RMD(&rmd); -#endif +#endif while (pktcount--) { if (CSR_RCVRC(s) <= 1) CSR_RCVRC(s) = CSR_RCVRL(s); else - CSR_RCVRC(s)--; + CSR_RCVRC(s)--; } - + pcnet_rdte_poll(s); - } + } } pcnet_poll(s); - pcnet_update_irq(s); + pcnet_update_irq(s); } static void pcnet_transmit(PCNetState *s) @@ -1226,7 +1226,7 @@ static void pcnet_transmit(PCNetState *s) target_phys_addr_t xmit_cxda = 0; int count = CSR_XMTRL(s)-1; s->xmit_pos = -1; - + if (!CSR_TXON(s)) { s->csr[0] &= ~0x0008; return; @@ -1332,7 +1332,7 @@ static void pcnet_poll_timer(void *opaque) pcnet_transmit(s); } - pcnet_update_irq(s); + pcnet_update_irq(s); if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { uint64_t now = qemu_get_clock(vm_clock) * 33; @@ -1592,11 +1592,11 @@ static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) PCNetState *s = opaque; #ifdef PCNET_DEBUG printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); -#endif +#endif /* Check APROMWE bit to enable write access */ if (pcnet_bcr_readw(s,2) & 0x80) s->prom[addr & 15] = val; -} +} static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) { @@ -1685,7 +1685,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080); #ifdef PCNET_DEBUG_IO printf("device switched into dword i/o mode\n"); -#endif +#endif } pcnet_update_irq(s); } @@ -1695,7 +1695,7 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) PCNetState *s = opaque; uint32_t val = -1; pcnet_poll_timer(s); - if (BCR_DWIO(s)) { + if (BCR_DWIO(s)) { switch (addr & 0x0f) { case 0x00: /* RDP */ val = pcnet_csr_readw(s, s->rap); @@ -1730,7 +1730,7 @@ static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); - + register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); @@ -1967,11 +1967,11 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), devfn, NULL, NULL); - + pci_conf = d->dev.config; - + *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022); - *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); + *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); pci_conf[0x08] = 0x10; @@ -1979,10 +1979,10 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) pci_conf[0x0a] = 0x00; // ethernet network controller pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; // header_type - + *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); - + pci_conf[0x3d] = 1; // interrupt pin 0 pci_conf[0x3e] = 0x06; pci_conf[0x3f] = 0xff; @@ -1993,10 +1993,10 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); - + pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); - + d->irq = d->dev.irq[0]; d->phys_mem_read = pci_physical_memory_read; d->phys_mem_write = pci_physical_memory_write; diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 2545bcbc3..08f88900f 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -222,7 +222,7 @@ static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value, offset -= (uint32_t)(long)pfl->storage; else offset -= pfl->base; - + DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__, offset, value, width); /* Set the device in I/O access mode */ diff --git a/hw/pl011.c b/hw/pl011.c index e66741b7a..94ed6994d 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -44,7 +44,7 @@ static const unsigned char pl011_id[] = static void pl011_update(pl011_state *s) { uint32_t flags; - + flags = s->int_level & s->int_enabled; qemu_set_irq(s->irq, flags != 0); } diff --git a/hw/pl110.c b/hw/pl110.c index 349426456..061ec7aba 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -117,7 +117,7 @@ static void pl110_update_display(void *opaque) if (!pl110_enabled(s)) return; - + switch (s->ds->depth) { case 0: return; @@ -151,7 +151,7 @@ static void pl110_update_display(void *opaque) fn = fntable[s->bpp + 12]; else fn = fntable[s->bpp]; - + src_width = s->cols; switch (s->bpp) { case BPP_1: diff --git a/hw/pl181.c b/hw/pl181.c index b450e580a..a905cbb21 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -177,7 +177,7 @@ error: /* Transfer data between the card and the FIFO. This is complicated by the FIFO holding 32-bit words and the card taking data in single byte chunks. FIFO bytes are transferred in little-endian order. */ - + static void pl181_fifo_run(pl181_state *s) { uint32_t bits; diff --git a/hw/ppc.c b/hw/ppc.c index a90124325..d0eb7a476 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -623,7 +623,7 @@ struct ppcemb_timer_t { uint64_t wdt_next; /* Tick for next WDT interrupt */ struct QEMUTimer *wdt_timer; }; - + /* Fixed interval timer */ static void cpu_4xx_fit_cb (void *opaque) { diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index cfb592efe..69655d84c 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -511,7 +511,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, target_ulong kernel_base, kernel_size, initrd_base, initrd_size; int linux_boot; int fl_idx, fl_sectors; - + /* RAM is soldered to the board so the size cannot be changed */ ram_bases[0] = 0x00000000; ram_sizes[0] = 0x04000000; diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 1a6a666ec..dd1350850 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -2212,7 +2212,7 @@ static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt) } mask = mask >> 1; } - + } static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) @@ -2228,7 +2228,7 @@ static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) qemu_irq_lower(gpt->irqs[i]); mask = mask >> 1; } - + } static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index e5a6313a4..a5e67e024 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -173,7 +173,7 @@ static void macio_init(PCIBus *bus, int device_id) d->config[0x0e] = 0x00; // header_type d->config[0x3d] = 0x01; // interrupt on pin 1 - + dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL); pci_register_io_region(d, 0, 0x80000, @@ -208,7 +208,7 @@ static int vga_osi_call(CPUState *env) { static int vga_vbl_enabled; int linesize; - + // printf("osi_call R5=%d\n", env->gpr[5]); /* same handler as PearPC, coming from the original MOL video @@ -280,14 +280,14 @@ static uint8_t nvram_chksum(const uint8_t *buf, int n) void pmac_format_nvram_partition(uint8_t *buf, int len) { char partition_name[12] = "wwwwwwwwwwww"; - + buf[0] = 0x7f; /* free partition magic */ buf[1] = 0; /* checksum */ buf[2] = len >> 8; buf[3] = len; memcpy(buf + 4, partition_name, 12); buf[1] = nvram_chksum(buf, 16); -} +} /* PowerPC CHRP hardware initialisation */ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, @@ -355,7 +355,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, bios_size = (bios_size + 0xfff) & ~0xfff; cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); - + /* allocate and load VGA BIOS */ vga_bios_offset = bios_offset + bios_size; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); @@ -376,7 +376,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, vga_bios_size += 8; } vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff; - + if (linux_boot) { kernel_base = KERNEL_LOAD_ADDR; /* now we can load the kernel */ @@ -427,24 +427,24 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* XXX: suppress that */ dummy_irq = i8259_init(NULL); - + /* XXX: use Mac Serial port */ serial_init(0x3f8, dummy_irq[4], serial_hds[0]); - + for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) nd_table[i].model = "ne2k_pci"; pci_nic_init(pci_bus, &nd_table[i], -1); } - + pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); /* cuda also initialize ADB */ cuda_mem_index = cuda_init(pic[0x12]); - + adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - + { MacIONVRAMState *nvr; nvr = macio_nvram_init(); @@ -534,14 +534,14 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, #endif /* cuda also initialize ADB */ cuda_mem_index = cuda_init(pic[0x19]); - + adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - + macio_init(pci_bus, 0x0022); - + nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59); - + arch_name = "MAC99"; } @@ -578,7 +578,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 0); } - + static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, diff --git a/hw/ps2.c b/hw/ps2.c index 233ff540d..5367df10c 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -146,7 +146,7 @@ uint32_t ps2_read_data(void *opaque) PS2State *s = (PS2State *)opaque; PS2Queue *q; int val, index; - + q = &s->queue; if (q->count == 0) { /* NOTE: if no data left, we return the last keyboard one @@ -311,7 +311,7 @@ static void ps2_mouse_event(void *opaque, s->mouse_buttons == buttons_state) return; s->mouse_buttons = buttons_state; - + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) { for(;;) { diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 097ad473e..a970eb3a9 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -890,10 +890,10 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d ++s->tally_counters.RxOkMul; } else if (s->phys[0] == buf[0] && - s->phys[1] == buf[1] && - s->phys[2] == buf[2] && - s->phys[3] == buf[3] && - s->phys[4] == buf[4] && + s->phys[1] == buf[1] && + s->phys[2] == buf[2] && + s->phys[3] == buf[3] && + s->phys[4] == buf[4] && s->phys[5] == buf[5]) { /* match */ if (!(s->RxConfig & AcceptMyPhys)) @@ -2420,17 +2420,17 @@ static uint16_t rtl8139_TSAD_read(RTL8139State *s) |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0) |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0) |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0) - + |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0) |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0) |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0) |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0) - + |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0) |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0) |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0) |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ; - + DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret)); @@ -3410,7 +3410,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) PCIRTL8139State *d; RTL8139State *s; uint8_t *pci_conf; - + d = (PCIRTL8139State *)pci_register_device(bus, "RTL8139", sizeof(PCIRTL8139State), devfn, @@ -3458,7 +3458,7 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) s->cplus_txbuffer = NULL; s->cplus_txbuffer_len = 0; s->cplus_txbuffer_offset = 0; - + /* XXX: instance number ? */ register_savevm("rtl8139", 0, 3, rtl8139_save, rtl8139_load, s); diff --git a/hw/serial.c b/hw/serial.c index ac3995b94..36a7cc4e3 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -142,7 +142,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) { SerialState *s = opaque; unsigned char ch; - + addr &= 7; #ifdef DEBUG_SERIAL printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 98cac6ed7..f604702f8 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -308,7 +308,7 @@ static void slavio_intctl_save(QEMUFile *f, void *opaque) { SLAVIO_INTCTLState *s = opaque; int i; - + for (i = 0; i < MAX_CPUS; i++) { qemu_put_be32s(f, &s->intreg_pending[i]); } diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 990f5c7ed..71529b12a 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -136,7 +136,7 @@ static uint32_t get_queue(void *opaque) ChannelState *s = opaque; SERIOQueue *q = &s->queue; int val; - + if (q->count == 0) { return 0; } else { diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index c9a3a563e..d3c75bf3a 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -210,7 +210,7 @@ static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) { SLAVIO_TIMERState *s = opaque; uint32_t tmp; - + if (version_id != 2) return -EINVAL; diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 5b8637d44..cf54c34c3 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -94,7 +94,7 @@ static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf) { SMBusEEPROMDevice *eeprom; - + eeprom = (SMBusEEPROMDevice *)smbus_device_init(bus, addr, sizeof(SMBusEEPROMDevice)); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index a6a11e0f2..b8d0cba5f 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -649,7 +649,7 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) /* Pad short packets. */ if (size < 64) { int pad; - + if (size & 1) *(p++) = buf[size - 1]; pad = 64 - size; diff --git a/hw/tcx.c b/hw/tcx.c index 72c9bcd59..9a72d6a6b 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -208,7 +208,7 @@ static void tcx_update_display(void *opaque) case 0: return; } - + for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { if (y_start < 0) @@ -353,7 +353,7 @@ static void tcx24_invalidate_display(void *opaque) static void tcx_save(QEMUFile *f, void *opaque) { TCXState *s = opaque; - + qemu_put_be16s(f, (uint16_t *)&s->height); qemu_put_be16s(f, (uint16_t *)&s->width); qemu_put_be16s(f, (uint16_t *)&s->depth); diff --git a/hw/usb-hid.c b/hw/usb-hid.c index e3b94d0d8..e0b2ba413 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -102,7 +102,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = { 5: Remote wakeup, 4..0: resvd */ 50, /* u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -124,7 +124,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = { 0x01, /* u8 if_bInterfaceSubClass; */ 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x07, /* u8 if_iInterface; */ - + /* HID descriptor */ 0x09, /* u8 bLength; */ 0x21, /* u8 bDescriptorType; */ @@ -157,7 +157,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = { 5: Remote wakeup, 4..0: resvd */ 50, /* u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -474,7 +474,7 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) 0, "QEMU USB Mouse"); s->mouse_grabbed = 1; } - + dx = int_clamp(s->dx, -128, 127); dy = int_clamp(s->dy, -128, 127); dz = int_clamp(s->dz, -128, 127); @@ -482,7 +482,7 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) s->dx -= dx; s->dy -= dy; s->dz -= dz; - + b = 0; if (s->buttons_state & MOUSE_EVENT_LBUTTON) b |= 0x01; @@ -490,7 +490,7 @@ static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len) b |= 0x02; if (s->buttons_state & MOUSE_EVENT_MBUTTON) b |= 0x04; - + buf[0] = b; buf[1] = dx; buf[2] = dy; @@ -512,7 +512,7 @@ static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len) 1, "QEMU USB Tablet"); s->mouse_grabbed = 1; } - + dz = int_clamp(s->dz, -128, 127); s->dz -= dz; diff --git a/hw/usb-hub.c b/hw/usb-hub.c index bfdd5f973..1dcac3ca6 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -118,7 +118,7 @@ static const uint8_t qemu_hub_config_descriptor[] = { 5: Remote wakeup, 4..0: resvd */ 0x00, /* u8 MaxPower; */ - + /* USB 1.1: * USB 2.0, single TT organization (mandatory): * one interface, protocol 0 @@ -140,7 +140,7 @@ static const uint8_t qemu_hub_config_descriptor[] = { 0x00, /* u8 if_bInterfaceSubClass; */ 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x00, /* u8 if_iInterface; */ - + /* one endpoint (status change endpoint) */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ @@ -167,11 +167,11 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) { USBHubState *s = port1->opaque; USBHubPort *port = &s->ports[port1->index]; - + if (dev) { if (port->port.dev) usb_attach(port1, NULL); - + port->wPortStatus |= PORT_STAT_CONNECTION; port->wPortChange |= PORT_STAT_C_CONNECTION; if (dev->speed == USB_SPEED_LOW) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index f4289165b..b1ad9ec09 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -99,7 +99,7 @@ static const uint8_t qemu_msd_config_descriptor[] = { 5: Remote wakeup, 4..0: resvd */ 0x00, /* u8 MaxPower; */ - + /* one interface */ 0x09, /* u8 if_bLength; */ 0x04, /* u8 if_bDescriptorType; Interface */ @@ -110,7 +110,7 @@ static const uint8_t qemu_msd_config_descriptor[] = { 0x06, /* u8 if_bInterfaceSubClass; SCSI */ 0x50, /* u8 if_bInterfaceProtocol; Bulk Only */ 0x00, /* u8 if_iInterface; */ - + /* Bulk-In endpoint */ 0x07, /* u8 ep_bLength; */ 0x05, /* u8 ep_bDescriptorType; Endpoint */ diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index cd04ad19e..58674098e 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -149,7 +149,7 @@ static void uhci_reset(UHCIState *s) static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) { UHCIState *s = opaque; - + addr &= 0x1f; switch(addr) { case 0x0c: @@ -178,7 +178,7 @@ static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) { UHCIState *s = opaque; - + addr &= 0x1f; #ifdef DEBUG printf("uhci writew port=0x%04x val=0x%04x\n", addr, val); @@ -458,7 +458,7 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) if (td->ctrl & TD_CTRL_IOC) { *int_mask |= 0x01; } - + if (!(td->ctrl & TD_CTRL_ACTIVE)) return 1; @@ -807,7 +807,7 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn) pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 4; // interrupt pin 3 pci_conf[0x60] = 0x10; // release number - + for(i = 0; i < NB_PORTS; i++) { qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); } diff --git a/hw/usb.h b/hw/usb.h index 17832cf37..c5d24f158 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -119,7 +119,7 @@ struct USBDevice { void (*handle_destroy)(USBDevice *dev); int speed; - + /* The following fields are used by the generic USB device layer. They are here just to avoid creating a new structure for them. */ @@ -129,7 +129,7 @@ struct USBDevice { int (*handle_data)(USBDevice *dev, USBPacket *p); uint8_t addr; char devname[32]; - + int state; uint8_t setup_buf[8]; uint8_t data_buf[1024]; diff --git a/hw/vga.c b/hw/vga.c index de74764e5..4c7d9fff3 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -467,7 +467,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->vbe_regs[VBE_DISPI_INDEX_YRES]; s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; - + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1; else @@ -480,7 +480,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) memset(s->vram_ptr, 0, s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); } - + /* we initialize the VGA graphic mode (should be done in BIOS) */ s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */ @@ -497,7 +497,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) s->cr[0x18] = 0xff; s->cr[0x07] |= 0x10; s->cr[0x09] |= 0x40; - + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { shift_control = 0; s->sr[0x01] &= ~8; /* no double line */ @@ -562,7 +562,7 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) VGAState *s = opaque; int memory_map_mode, plane; uint32_t ret; - + /* convert to VGA memory offset */ memory_map_mode = (s->gr[6] >> 2) & 3; addr &= 0x1ffff; @@ -586,7 +586,7 @@ uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) return 0xff; break; } - + if (s->sr[4] & 0x08) { /* chain 4 mode : simplest access */ ret = s->vram_ptr[addr]; @@ -676,7 +676,7 @@ void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) return; break; } - + if (s->sr[4] & 0x08) { /* chain 4 mode : simplest access */ plane = addr & 3; @@ -961,7 +961,7 @@ static void vga_get_offsets(VGAState *s, line_compare = 65535; } else #endif - { + { /* compute line_offset in bytes */ line_offset = s->cr[0x13]; line_offset <<= 3; @@ -984,7 +984,7 @@ static int update_basic_params(VGAState *s) { int full_update; uint32_t start_addr, line_offset, line_compare; - + full_update = 0; s->get_offsets(s, &line_offset, &start_addr, &line_compare); @@ -1055,7 +1055,7 @@ static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { vga_draw_glyph9_16, vga_draw_glyph9_16, }; - + static const uint8_t cursor_glyph[32 * 4] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -1073,7 +1073,7 @@ static const uint8_t cursor_glyph[32 * 4] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; +}; /* * Text mode update @@ -1098,7 +1098,7 @@ static void vga_draw_text(VGAState *s, int full_update) full_update |= update_palette16(s); palette = s->last_palette; - + /* compute font data address (in plane 2) */ v = s->sr[3]; offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; @@ -1174,14 +1174,14 @@ static void vga_draw_text(VGAState *s, int full_update) s->cursor_end = s->cr[0xb]; } cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; - + depth_index = get_depth_index(s->ds); if (cw == 16) vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; else vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; - + dest = s->ds->data; linesize = s->ds->linesize; ch_attr_ptr = s->last_ch_attr; @@ -1379,7 +1379,7 @@ static int vga_get_bpp(VGAState *s) static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight) { int width, height; - + #ifdef CONFIG_BOCHS_VBE if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; @@ -1420,7 +1420,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) uint8_t *d; uint32_t v, addr1, addr; vga_draw_line_func *vga_draw_line; - + full_update |= update_basic_params(s); s->get_resolution(s, &width, &height); @@ -1442,7 +1442,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) s->shift_control = shift_control; s->double_scan = double_scan; } - + if (shift_control == 0) { full_update |= update_palette16(s); if (s->sr[0x01] & 8) { @@ -1497,7 +1497,7 @@ static void vga_draw_graphic(VGAState *s, int full_update) } if (s->cursor_invalidate) s->cursor_invalidate(s); - + line_offset = s->line_offset; #if 0 printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", @@ -1616,7 +1616,7 @@ static void vga_update_display(void *opaque) } else { s->rgb_to_pixel = rgb_to_pixel_dup_table[get_depth_index(s->ds)]; - + full_update = 0; if (!(s->ar_index & 0x20)) { graphic_mode = GMODE_BLANK; @@ -1646,7 +1646,7 @@ static void vga_update_display(void *opaque) static void vga_invalidate_display(void *opaque) { VGAState *s = (VGAState *)opaque; - + s->last_width = -1; s->last_height = -1; } @@ -2009,21 +2009,21 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, PCIVGAState *d; VGAState *s; uint8_t *pci_conf; - + d = (PCIVGAState *)pci_register_device(bus, "VGA", sizeof(PCIVGAState), -1, NULL, NULL); if (!d) return -1; s = &d->vga_state; - + vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); vga_init(s); graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); s->pci_dev = &d->dev; - + pci_conf = d->dev.config; pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID) pci_conf[0x01] = 0x12; @@ -2032,7 +2032,7 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, pci_conf[0x0a] = 0x00; // VGA controller pci_conf[0x0b] = 0x03; pci_conf[0x0e] = 0x00; // header_type - + /* XXX: vga_ram_size must be a power of two */ pci_register_io_region(&d->dev, 0, vga_ram_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); @@ -2107,7 +2107,7 @@ static void vga_screen_dump(void *opaque, const char *filename) { VGAState *s = (VGAState *)opaque; DisplayState *saved_ds, ds1, *ds = &ds1; - + /* XXX: this is a little hackish */ vga_invalidate_display(s); saved_ds = s->ds; @@ -2121,7 +2121,7 @@ static void vga_screen_dump(void *opaque, const char *filename) s->ds = ds; s->graphic_mode = -1; vga_update_display(s); - + if (ds->data) { ppm_save(filename, ds->data, vga_save_w, vga_save_h, s->ds->linesize); diff --git a/hw/vga_int.h b/hw/vga_int.h index 3eb4e29dc..a94162d33 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -45,20 +45,20 @@ #define VBE_DISPI_INDEX_X_OFFSET 0x8 #define VBE_DISPI_INDEX_Y_OFFSET 0x9 #define VBE_DISPI_INDEX_NB 0xa - + #define VBE_DISPI_ID0 0xB0C0 #define VBE_DISPI_ID1 0xB0C1 #define VBE_DISPI_ID2 0xB0C2 #define VBE_DISPI_ID3 0xB0C3 #define VBE_DISPI_ID4 0xB0C4 - + #define VBE_DISPI_DISABLED 0x00 #define VBE_DISPI_ENABLED 0x01 #define VBE_DISPI_GETCAPS 0x02 #define VBE_DISPI_8BIT_DAC 0x20 #define VBE_DISPI_LFB_ENABLED 0x40 #define VBE_DISPI_NOCLEARMEM 0x80 - + #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 #ifdef CONFIG_BOCHS_VBE diff --git a/hw/vga_template.h b/hw/vga_template.h index 41f6e25f2..0bc2e8020 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -73,7 +73,7 @@ static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, uint32_t fgcol, uint32_t bgcol) { uint32_t font_data, xorcol; - + xorcol = bgcol ^ fgcol; do { font_data = font_ptr[0]; @@ -88,7 +88,7 @@ static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize, uint32_t fgcol, uint32_t bgcol) { uint32_t font_data, xorcol; - + xorcol = bgcol ^ fgcol; do { font_data = font_ptr[0]; @@ -108,7 +108,7 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, uint32_t fgcol, uint32_t bgcol, int dup9) { uint32_t font_data, xorcol, v; - + xorcol = bgcol ^ fgcol; do { font_data = font_ptr[0]; @@ -120,7 +120,7 @@ static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, ((uint8_t *)d)[8] = v >> (24 * (1 - BIG)); else ((uint8_t *)d)[8] = bgcol; - + #elif BPP == 2 cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol); cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol); @@ -433,7 +433,7 @@ static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d, s += 2; d += BPP; } while (--w != 0); -#endif +#endif } /* @@ -458,7 +458,7 @@ static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d, s += 2; d += BPP; } while (--w != 0); -#endif +#endif } /* diff --git a/kqemu.c b/kqemu.c index 7df69309b..9e2d1d627 100644 --- a/kqemu.c +++ b/kqemu.c @@ -286,7 +286,7 @@ static void kqemu_reset_modified_ram_pages(void) { int i; unsigned long page_index; - + for(i = 0; i < nb_modified_ram_pages; i++) { page_index = modified_ram_pages[i] >> TARGET_PAGE_BITS; modified_ram_pages_table[page_index] = 0; @@ -364,7 +364,7 @@ static void restore_native_fp_frstor(CPUState *env) { int fptag, i, j; struct fpstate fp1, *fp = &fp1; - + fp->fpuc = env->fpuc; fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; fptag = 0; @@ -470,7 +470,7 @@ static int do_syscall(CPUState *env, struct kqemu_cpu_state *kenv) { int selector; - + selector = (env->star >> 32) & 0xffff; #ifdef __x86_64__ if (env->hflags & HF_LMA_MASK) { @@ -501,7 +501,7 @@ static int do_syscall(CPUState *env, #endif { env->regs[R_ECX] = (uint32_t)kenv->next_eip; - + cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, @@ -605,7 +605,7 @@ void kqemu_record_dump(void) } } qsort(pr, nb_pc_records, sizeof(PCRecord *), pc_rec_cmp); - + f = fopen("/tmp/kqemu.stats", "w"); if (!f) { perror("/tmp/kqemu.stats"); @@ -697,7 +697,7 @@ int kqemu_cpu_exec(CPUState *env) kenv->nb_ram_pages_to_update = nb_ram_pages_to_update; #endif nb_ram_pages_to_update = 0; - + #if KQEMU_VERSION >= 0x010300 kenv->nb_modified_ram_pages = nb_modified_ram_pages; #endif @@ -828,7 +828,7 @@ int kqemu_cpu_exec(CPUState *env) env->hflags |= HF_OSFXSR_MASK; else env->hflags &= ~HF_OSFXSR_MASK; - + #ifdef DEBUG if (loglevel & CPU_LOG_INT) { fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret); diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h index 139a4cfcb..2c505a1da 100644 --- a/linux-user/alpha/syscall_nr.h +++ b/linux-user/alpha/syscall_nr.h @@ -329,7 +329,7 @@ #define TARGET_NR_lremovexattr 392 #define TARGET_NR_fremovexattr 393 #define TARGET_NR_futex 394 -#define TARGET_NR_sched_setaffinity 395 +#define TARGET_NR_sched_setaffinity 395 #define TARGET_NR_sched_getaffinity 396 #define TARGET_NR_tuxcall 397 #define TARGET_NR_io_setup 398 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index a3d8649ba..b87119e93 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -695,7 +695,7 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, size *= n; if (size & 15) sp -= 16 - (size & 15); - + #define NEW_AUX_ENT(id, val) do { \ sp -= n; tputl(sp, val); \ sp -= n; tputl(sp, id); \ @@ -833,7 +833,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, elf_type, interpreter_fd, eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); - + if (error == -1) { /* Real error */ close(interpreter_fd); @@ -1199,10 +1199,10 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, int elf_prot = 0; int elf_flags = 0; unsigned long error; - + if (elf_ppnt->p_type != PT_LOAD) continue; - + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; @@ -1224,7 +1224,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); } - + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), (elf_ppnt->p_filesz + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), @@ -1242,7 +1242,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); #endif - + if (!load_addr_set) { load_addr_set = 1; load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; diff --git a/linux-user/flat.h b/linux-user/flat.h index 1fdba514c..9b84c7292 100644 --- a/linux-user/flat.h +++ b/linux-user/flat.h @@ -38,7 +38,7 @@ struct flat_hdr { target_ulong reloc_start; /* Offset of relocation records from beginning of file */ target_ulong reloc_count; /* Number of relocation records */ - target_ulong flags; + target_ulong flags; target_ulong build_date; /* When the program/library was built */ target_ulong filler[5]; /* Reservered, set to zero */ }; diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 8e3bf73a6..db88e4b1c 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -376,7 +376,7 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl) break; } DBG_FLT("Relocation became %x\n", (int)*ptr); -} +} /****************************************************************************/ @@ -416,7 +416,7 @@ static int load_flat_file(struct linux_binprm * bprm, rev, (int) FLAT_VERSION); return -ENOEXEC; } - + /* Don't allow old format executables to use shared libraries */ if (rev == OLD_FLAT_VERSION && id != 0) { fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n"); @@ -581,7 +581,7 @@ static int load_flat_file(struct linux_binprm * bprm, libinfo[id].loaded = 1; libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos; libinfo[id].build_date = ntohl(hdr->build_date); - + /* * We just load the allocations into some temporary memory to * help simplify all this mumbo jumbo @@ -662,7 +662,7 @@ static int load_flat_file(struct linux_binprm * bprm, old_reloc(&libinfo[0], relval); } } - + /* zero the BSS. */ memset((void*)(datapos + data_len), 0, bss_len); @@ -732,11 +732,11 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, stack_len += (bprm->argc + 1) * 4; /* the argv array */ stack_len += (bprm->envc + 1) * 4; /* the envp array */ - + res = load_flat_file(bprm, libinfo, 0, &stack_len); if (res > (unsigned long)-4096) return res; - + /* Update data segment pointers for all libraries */ for (i=0; ienvc, bprm->argc, sp, p, 1); - + /* Fake some return addresses to ensure the call chain will * initialise library in order for us. We are required to call * lib 1 first, then 2, ... and finally the main program (id 0). @@ -784,7 +784,7 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } } #endif - + /* Stash our initial stack pointer into the mm structure */ info->start_code = libinfo[0].start_code; info->end_code = libinfo[0].start_code = libinfo[0].text_len; @@ -798,6 +798,6 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n", (int)info->entry, (int)info->start_stack); - + return 0; } diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 8c29f8087..0efbb76ce 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -182,7 +182,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, return -1; } } - + if(retval>=0) { /* success. Initialize important registers */ do_init_thread(regs, infop); diff --git a/linux-user/main.c b/linux-user/main.c index e75bb8432..18e0be181 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -331,7 +331,7 @@ void cpu_loop(CPUARMState *env) unsigned int n, insn; target_siginfo_t info; uint32_t addr; - + for(;;) { trapnr = cpu_arm_exec(env); switch(trapnr) { @@ -343,7 +343,7 @@ void cpu_loop(CPUARMState *env) /* we handle the FPU emulation here, as Linux */ /* we get the opcode */ opcode = tget32(env->regs[15]); - + if (EmulateAll(opcode, &ts->fpa, env) == 0) { info.si_signo = SIGILL; info.si_errno = 0; @@ -475,7 +475,7 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1) { unsigned int i; target_ulong sp_ptr; - + sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #if defined(DEBUG_WIN) printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", @@ -506,10 +506,10 @@ static void restore_window(CPUSPARCState *env) { unsigned int new_wim, i, cwp1; target_ulong sp_ptr; - + new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & ((1LL << NWINDOWS) - 1); - + /* restore the invalid window */ cwp1 = (env->cwp + 1) & (NWINDOWS - 1); sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; @@ -555,10 +555,10 @@ void cpu_loop (CPUSPARCState *env) { int trapnr, ret; target_siginfo_t info; - + while (1) { trapnr = cpu_sparc_exec (env); - + switch (trapnr) { #ifndef TARGET_SPARC64 case 0x88: @@ -670,17 +670,17 @@ static inline uint64_t cpu_ppc_get_tb (CPUState *env) /* TO FIX */ return 0; } - + uint32_t cpu_ppc_load_tbl (CPUState *env) { return cpu_ppc_get_tb(env) & 0xFFFFFFFF; } - + uint32_t cpu_ppc_load_tbu (CPUState *env) { return cpu_ppc_get_tb(env) >> 32; } - + static void cpu_ppc_store_tb (CPUState *env, uint64_t value) { /* TO FIX */ @@ -717,7 +717,7 @@ void cpu_loop(CPUPPCState *env) target_siginfo_t info; int trapnr; uint32_t ret; - + for(;;) { trapnr = cpu_ppc_exec(env); if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && @@ -1452,10 +1452,10 @@ void cpu_loop (CPUState *env) { int trapnr, ret; target_siginfo_t info; - + while (1) { trapnr = cpu_sh4_exec (env); - + switch (trapnr) { case 0x160: ret = do_syscall(env, @@ -1501,7 +1501,7 @@ void cpu_loop(CPUM68KState *env) unsigned int n; target_siginfo_t info; TaskState *ts = env->opaque; - + for(;;) { trapnr = cpu_m68k_exec(env); switch(trapnr) { @@ -1590,10 +1590,10 @@ void cpu_loop (CPUState *env) { int trapnr; target_siginfo_t info; - + while (1) { trapnr = cpu_alpha_exec (env); - + switch (trapnr) { case EXCP_RESET: fprintf(stderr, "Reset requested. Exit\n"); @@ -1745,7 +1745,7 @@ int main(int argc, char **argv) if (optind >= argc) break; - + r = argv[optind++]; mask = cpu_str_to_log_mask(r); if (!mask) { @@ -1821,7 +1821,7 @@ int main(int argc, char **argv) qemu_host_page_size */ env = cpu_init(); global_env = env; - + wrk = environ; while (*(wrk++)) environ_count++; @@ -1844,12 +1844,12 @@ int main(int argc, char **argv) for (wrk = target_environ; *wrk; wrk++) { free(*wrk); } - + free(target_environ); if (loglevel) { page_dump(logfile); - + fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); @@ -1870,7 +1870,7 @@ int main(int argc, char **argv) ts->used = 1; ts->info = info; env->user_mode_only = 1; - + #if defined(TARGET_I386) cpu_x86_set_cpl(env, 3); @@ -1883,7 +1883,7 @@ int main(int argc, char **argv) /* flags setup : we activate the IRQs by default as in user mode */ env->eflags |= IF_MASK; - + /* linux register setup */ #if defined(TARGET_X86_64) env->regs[R_EAX] = regs->rax; diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 3eb930e7b..28954f13f 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -52,7 +52,7 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) return -EINVAL; if (len == 0) return 0; - + host_start = start & qemu_host_page_mask; host_end = HOST_PAGE_ALIGN(end); if (start > host_start) { @@ -83,7 +83,7 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) return ret; host_end -= qemu_host_page_size; } - + /* handle the pages in the middle */ if (host_start < host_end) { ret = mprotect(g2h(host_start), host_end - host_start, prot); @@ -112,7 +112,7 @@ static int mmap_frag(target_ulong real_start, if (addr < start || addr >= end) prot1 |= page_get_flags(addr); } - + if (prot1 == 0) { /* no page was there, so we allocate one */ ret = (long)mmap(host_start, qemu_host_page_size, prot, @@ -134,10 +134,10 @@ static int mmap_frag(target_ulong real_start, /* adjust protection to be able to read */ if (!(prot1 & PROT_WRITE)) mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); - + /* read the corresponding file data */ pread(fd, g2h(start), end - start, offset); - + /* put final protection */ if (prot_new != (prot1 | PROT_WRITE)) mprotect(host_start, qemu_host_page_size, prot_new); @@ -244,7 +244,7 @@ abort(); goto the_end1; } } - + if (start & ~TARGET_PAGE_MASK) { errno = EINVAL; return -1; @@ -303,7 +303,7 @@ abort(); return ret; real_end -= qemu_host_page_size; } - + /* map the middle (easier) */ if (real_start < real_end) { unsigned long offset1; @@ -367,7 +367,7 @@ int target_munmap(target_ulong start, target_ulong len) if (prot != 0) real_end -= qemu_host_page_size; } - + /* unmap what we can */ if (real_start < real_end) { ret = munmap((void *)real_start, real_end - real_start); @@ -410,7 +410,7 @@ int target_msync(target_ulong start, target_ulong len, int flags) return -EINVAL; if (end == start) return 0; - + start &= qemu_host_page_mask; return msync(g2h(start), end - start, flags); } diff --git a/linux-user/signal.c b/linux-user/signal.c index 73b6dadc9..97f10957d 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -108,7 +108,7 @@ static void host_to_target_sigset_internal(target_sigset_t *d, int i; unsigned long sigmask; uint32_t target_sigmask; - + sigmask = ((unsigned long *)s)[0]; target_sigmask = 0; for(i = 0; i < 32; i++) { @@ -171,7 +171,7 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) s1.sig[i] = tswapl(s->sig[i]); target_to_host_sigset_internal(d, &s1); } - + void host_to_target_old_sigset(target_ulong *old_sigset, const sigset_t *sigset) { @@ -274,7 +274,7 @@ void signal_init(void) j = host_to_target_signal_table[i]; target_to_host_signal_table[j] = i; } - + /* set all host signal handlers. ALL signals are blocked during the handlers to serialize them. */ sigfillset(&act.sa_mask); @@ -283,7 +283,7 @@ void signal_init(void) for(i = 1; i < NSIG; i++) { sigaction(i, &act, NULL); } - + memset(sigact_table, 0, sizeof(sigact_table)); first_free = &sigqueue_table[0]; @@ -865,7 +865,7 @@ long do_sigreturn(CPUX86State *env) target_to_host_sigset_internal(&set, &target_set); sigprocmask(SIG_SETMASK, &set, NULL); - + /* restore registers */ if (restore_sigcontext(env, &frame->sc, &eax)) goto badframe; @@ -1933,7 +1933,7 @@ long do_sigreturn(CPUState *regs) :"r" (®s)); /* Unreached */ #endif - + regs->PC[regs->current_tc] = regs->CP0_EPC; /* I am not sure this is right, but it seems to work * maybe a problem with nested signals ? */ @@ -1995,7 +1995,7 @@ void process_pending_signals(void *cpu_env) target_sigset_t target_old_set; struct emulated_sigaction *k; struct sigqueue *q; - + if (!signal_pending) return; @@ -2018,7 +2018,7 @@ void process_pending_signals(void *cpu_env) k->first = q->next; if (!k->first) k->pending = 0; - + sig = gdb_handlesig (cpu_env, sig); if (!sig) { fprintf (stderr, "Lost signal\n"); @@ -2044,7 +2044,7 @@ void process_pending_signals(void *cpu_env) blocked during the handler */ if (!(k->sa.sa_flags & TARGET_SA_NODEFER)) sigaddset(&set, target_to_host_signal(sig)); - + /* block signals in the handler using Linux */ sigprocmask(SIG_BLOCK, &set, &old_set); /* save the previous blocked signal state to restore it at the diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 943955d97..d0b4e8292 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -341,7 +341,7 @@ long do_brk(target_ulong new_brk) return target_brk; if (new_brk < target_original_brk) return -ENOMEM; - + brk_page = HOST_PAGE_ALIGN(target_brk); /* If the new brk is less than this, set it and we're done... */ @@ -506,7 +506,7 @@ static long do_select(long n, target_efds = NULL; efds_ptr = NULL; } - + if (target_tv) { target_to_host_timeval(&tv, target_tv); tv_ptr = &tv; @@ -652,13 +652,13 @@ static long do_setsockopt(int sockfd, int level, int optname, target_ulong optval, socklen_t optlen) { int val, ret; - + switch(level) { case SOL_TCP: /* TCP options all take an 'int' value. */ if (optlen < sizeof(uint32_t)) return -EINVAL; - + val = tget32(optval); ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; @@ -918,7 +918,7 @@ static long do_bind(int sockfd, target_ulong target_addr, socklen_t addrlen) { void *addr = alloca(addrlen); - + target_to_host_sockaddr(addr, target_addr, addrlen); return get_errno(bind(sockfd, addr, addrlen)); } @@ -927,7 +927,7 @@ static long do_connect(int sockfd, target_ulong target_addr, socklen_t addrlen) { void *addr = alloca(addrlen); - + target_to_host_sockaddr(addr, target_addr, addrlen); return get_errno(connect(sockfd, addr, addrlen)); } @@ -955,14 +955,14 @@ static long do_sendrecvmsg(int fd, target_ulong target_msg, msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); msg.msg_control = alloca(msg.msg_controllen); msg.msg_flags = tswap32(msgp->msg_flags); - + count = tswapl(msgp->msg_iovlen); vec = alloca(count * sizeof(struct iovec)); target_vec = tswapl(msgp->msg_iov); lock_iovec(vec, target_vec, count, send); msg.msg_iovlen = count; msg.msg_iov = vec; - + if (send) { target_to_host_cmsg(&msg, msgp); ret = get_errno(sendmsg(fd, &msg, flags)); @@ -1636,7 +1636,7 @@ static long do_ipc(long call, long first, long second, long third, break; raddr = ret; /* find out the length of the shared memory segment */ - + ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); if (is_error(ret)) { /* can't get length, bail out */ @@ -1910,7 +1910,7 @@ static void target_to_host_termios (void *dst, const void *src) { struct host_termios *host = dst; const struct target_termios *target = src; - + host->c_iflag = target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl); host->c_oflag = @@ -1920,26 +1920,26 @@ static void target_to_host_termios (void *dst, const void *src) host->c_lflag = target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl); host->c_line = target->c_line; - + host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; - host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; + host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; host->c_cc[VKILL] = target->c_cc[TARGET_VKILL]; - host->c_cc[VEOF] = target->c_cc[TARGET_VEOF]; + host->c_cc[VEOF] = target->c_cc[TARGET_VEOF]; host->c_cc[VTIME] = target->c_cc[TARGET_VTIME]; - host->c_cc[VMIN] = target->c_cc[TARGET_VMIN]; + host->c_cc[VMIN] = target->c_cc[TARGET_VMIN]; host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC]; - host->c_cc[VSTART] = target->c_cc[TARGET_VSTART]; + host->c_cc[VSTART] = target->c_cc[TARGET_VSTART]; host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP]; host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP]; - host->c_cc[VEOL] = target->c_cc[TARGET_VEOL]; - host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT]; - host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD]; - host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE]; - host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT]; + host->c_cc[VEOL] = target->c_cc[TARGET_VEOL]; + host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT]; + host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD]; + host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE]; + host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT]; host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2]; } - + static void host_to_target_termios (void *dst, const void *src) { struct target_termios *target = dst; @@ -1954,7 +1954,7 @@ static void host_to_target_termios (void *dst, const void *src) target->c_lflag = tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl)); target->c_line = host->c_line; - + target->c_cc[TARGET_VINTR] = host->c_cc[VINTR]; target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT]; target->c_cc[TARGET_VERASE] = host->c_cc[VERASE]; @@ -2052,7 +2052,7 @@ static int write_ldt(CPUX86State *env, ldt_info.limit = tswap32(target_ldt_info->limit); ldt_info.flags = tswap32(target_ldt_info->flags); unlock_user_struct(target_ldt_info, ptr, 0); - + if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) return -EINVAL; seg_32bit = ldt_info.flags & 1; @@ -2093,7 +2093,7 @@ static int write_ldt(CPUX86State *env, goto install; } } - + entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | (ldt_info.limit & 0x0ffff); entry_2 = (ldt_info.base_addr & 0xff000000) | @@ -2120,7 +2120,7 @@ install: int do_modify_ldt(CPUX86State *env, int func, target_ulong ptr, unsigned long bytecount) { int ret = -ENOSYS; - + switch (func) { case 0: ret = read_ldt(ptr, bytecount); @@ -2155,7 +2155,7 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) TaskState *ts; uint8_t *new_stack; CPUState *new_env; - + if (flags & CLONE_VM) { ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); memset(ts, 0, sizeof(TaskState)); @@ -2263,7 +2263,7 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) unlock_user_struct(target_fl, arg, 1); } break; - + case TARGET_F_SETLK: case TARGET_F_SETLKW: lock_user_struct(target_fl, arg, 1); @@ -2275,7 +2275,7 @@ static long do_fcntl(int fd, int cmd, target_ulong arg) unlock_user_struct(target_fl, arg, 0); ret = fcntl(fd, cmd, &fl); break; - + case TARGET_F_GETLK64: lock_user_struct(target_fl64, arg, 1); fl64.l_type = tswap16(target_fl64->l_type) >> 1; @@ -2468,7 +2468,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, struct stat st; struct statfs stfs; void *p; - + #ifdef DEBUG gemu_log("syscall %d", num); #endif @@ -2980,7 +2980,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { int how = arg1; sigset_t set, oldset, *set_ptr; - + if (arg2) { switch(how) { case TARGET_SIG_BLOCK: @@ -3017,7 +3017,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { int how = arg1; sigset_t set, oldset, *set_ptr; - + if (arg2) { switch(how) { case TARGET_SIG_BLOCK: @@ -3098,7 +3098,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, sigset_t set; struct timespec uts, *puts; siginfo_t uinfo; - + p = lock_user(arg1, sizeof(target_sigset_t), 1); target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); @@ -3159,7 +3159,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, int resource = arg1; struct target_rlimit *target_rlim; struct rlimit rlim; - + ret = get_errno(getrlimit(resource, &rlim)); if (!is_error(ret)) { lock_user_struct(target_rlim, arg2, 0); @@ -3357,7 +3357,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, convert_statfs: if (!is_error(ret)) { struct target_statfs *target_stfs; - + lock_user_struct(target_stfs, arg2, 0); /* ??? put_user is probably wrong. */ put_user(stfs.f_type, &target_stfs->f_type); @@ -3384,7 +3384,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, convert_statfs64: if (!is_error(ret)) { struct target_statfs64 *target_stfs; - + lock_user_struct(target_stfs, arg3, 0); /* ??? put_user is probably wrong. */ put_user(stfs.f_type, &target_stfs->f_type); @@ -3530,7 +3530,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getitimer: { struct itimerval value; - + ret = get_errno(getitimer(arg1, &value)); if (!is_error(ret) && arg2) { host_to_target_timeval(arg2, @@ -3699,7 +3699,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, /* no need to transcode because we use the linux syscall */ { struct new_utsname * buf; - + lock_user_struct(buf, arg1, 0); ret = get_errno(sys_uname(buf)); if (!is_error(ret)) { @@ -3786,7 +3786,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, dirp = malloc(count); if (!dirp) return -ENOMEM; - + ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { struct dirent *de; @@ -4354,7 +4354,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, uint32_t *target_grouplist; gid_t *grouplist; int i; - + grouplist = alloca(gidsetsize * sizeof(gid_t)); target_grouplist = lock_user(arg2, gidsetsize * 4, 1); for(i = 0;i < gidsetsize; i++) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 01f456328..14a379937 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -748,9 +748,9 @@ struct target_pollfd { */ #define TARGET_CDROMREADCOOKED 0x5315 /* read data in cooked mode */ #define TARGET_CDROMSEEK 0x5316 /* seek msf address */ - + /* - * This ioctl is only used by the scsi-cd driver. + * This ioctl is only used by the scsi-cd driver. It is for playing audio in logical block addressing mode. */ #define TARGET_CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */ diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 2fd00f103..f73aabc1d 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -28,7 +28,7 @@ STRUCT(ifmap, STRUCT(sockaddr_ifreq, MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_sockaddr)) - + STRUCT(short_ifreq, MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_SHORT) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index be71c2cd4..9639114fc 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -123,7 +123,7 @@ static inline void return_to_32bit(CPUX86State *env, int retval) static inline int set_IF(CPUX86State *env) { TaskState *ts = env->opaque; - + ts->v86flags |= VIF_MASK; if (ts->v86flags & VIP_MASK) { return_to_32bit(env, TARGET_VM86_STI); @@ -264,7 +264,7 @@ void handle_vm86_fault(CPUX86State *env) csp = (uint8_t *)(env->segs[R_CS].selector << 4); ip = env->eip & 0xffff; pc = csp + ip; - + ssp = (uint8_t *)(env->segs[R_SS].selector << 4); sp = env->regs[R_ESP] & 0xffff; @@ -362,12 +362,12 @@ void handle_vm86_fault(CPUX86State *env) return; } VM86_FAULT_RETURN; - + case 0xfa: /* cli */ env->eip = ip; clear_IF(env); VM86_FAULT_RETURN; - + case 0xfb: /* sti */ env->eip = ip; if (set_IF(env)) @@ -386,7 +386,7 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) TaskState *ts = env->opaque; struct target_vm86plus_struct * target_v86; int ret; - + switch (subfunction) { case TARGET_VM86_REQUEST_IRQ: case TARGET_VM86_FREE_IRQ: @@ -470,7 +470,7 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, target_v86->vm86plus.vm86dbg_intxxtab, 32); unlock_user_struct(target_v86, vm86_addr, 0); - + #ifdef DEBUG_VM86 fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS].selector, env->eip); diff --git a/loader.c b/loader.c index aba3ae262..40bcaf620 100644 --- a/loader.c +++ b/loader.c @@ -261,7 +261,7 @@ static void bswap_uboot_header(uboot_image_header_t *hdr) /* Load a U-Boot image. */ int load_uboot(const char *filename, target_ulong *ep, int *is_linux) { - + int fd; int size; uboot_image_header_t h; diff --git a/m68k-dis.c b/m68k-dis.c index 90d0bedb7..10b8d5ba5 100644 --- a/m68k-dis.c +++ b/m68k-dis.c @@ -2378,7 +2378,7 @@ const struct m68k_opcode m68k_opcodes[] = {"eor", 4, one(0005174), one(0177777), "#wSs", m68000up }, {"eor", 4, one(0005100), one(0177700), "#w$s", m68000up }, {"eor", 2, one(0130500), one(0170700), "Dd$s", m68000up }, - + {"exg", 2, one(0140500), one(0170770), "DdDs", m68000up }, {"exg", 2, one(0140510), one(0170770), "AdAs", m68000up }, {"exg", 2, one(0140610), one(0170770), "DdAs", m68000up }, @@ -4011,13 +4011,13 @@ const struct m68k_opcode m68k_opcodes[] = {"roxrl", 2, one(0160260), one(0170770), "DdDs", m68000up }, {"rtd", 4, one(0047164), one(0177777), "#w", m68010up }, - + {"rte", 2, one(0047163), one(0177777), "", m68000up | mcfisa_a }, - + {"rtm", 2, one(0003300), one(0177760), "Rs", m68020 }, - + {"rtr", 2, one(0047167), one(0177777), "", m68000up }, - + {"rts", 2, one(0047165), one(0177777), "", m68000up | mcfisa_a }, {"satsl", 2, one(0046200), one(0177770), "Ds", mcfisa_b }, @@ -4561,12 +4561,12 @@ floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from) zero can it be zero, and then it must be zero. */ unsigned long exponent, int_bit; const unsigned char *ufrom = (const unsigned char *) from; - + exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len); int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->man_start, 1); - + if ((exponent == 0) != (int_bit == 0)) return 0; else @@ -4699,7 +4699,7 @@ get_field (const unsigned char *data, enum floatformat_byteorders order, } return result; } - + #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif diff --git a/mips-dis.c b/mips-dis.c index 4331a8c55..7cf0793c4 100644 --- a/mips-dis.c +++ b/mips-dis.c @@ -392,7 +392,7 @@ struct mips_opcode "l" 32 bit floating point constant in .lit4 MDMX instruction operands (note that while these use the FP register - fields, they accept both $fN and $vN names for the registers): + fields, they accept both $fN and $vN names for the registers): "O" MDMX alignment offset (OP_*_ALN) "Q" MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT) "X" MDMX destination register (OP_*_FD) diff --git a/monitor.c b/monitor.c index 6876e7a6f..1c061f53a 100644 --- a/monitor.c +++ b/monitor.c @@ -333,7 +333,7 @@ static void do_info_history (void) { int i; const char *str; - + i = 0; for(;;) { str = readline_get_history(i); @@ -442,7 +442,7 @@ static void do_logfile(const char *filename) static void do_log(const char *items) { int mask; - + if (!strcmp(items, "none")) { mask = 0; } else { @@ -744,7 +744,7 @@ typedef struct { static const KeyDef key_defs[] = { { 0x2a, "shift" }, { 0x36, "shift_r" }, - + { 0x38, "alt" }, { 0xb8, "alt_r" }, { 0x1d, "ctrl" }, @@ -799,7 +799,7 @@ static const KeyDef key_defs[] = { { 0x30, "b" }, { 0x31, "n" }, { 0x32, "m" }, - + { 0x39, "spc" }, { 0x3a, "caps_lock" }, { 0x3b, "f1" }, @@ -832,7 +832,7 @@ static const KeyDef key_defs[] = { { 0x47, "kp_7" }, { 0x48, "kp_8" }, { 0x49, "kp_9" }, - + { 0x56, "<" }, { 0x57, "f11" }, @@ -879,7 +879,7 @@ static void do_send_key(const char *string) uint8_t keycodes[16]; const char *p; int nb_keycodes, keycode, i; - + nb_keycodes = 0; p = string; while (*p != '\0') { @@ -1769,7 +1769,7 @@ static target_long expr_unary(void) case '$': { char buf[128], *q; - + pch++; q = buf; while ((*pch >= 'a' && *pch <= 'z') || @@ -1816,7 +1816,7 @@ static target_long expr_prod(void) { target_long val, val2; int op; - + val = expr_unary(); for(;;) { op = *pch; @@ -1989,7 +1989,7 @@ static void monitor_handle_command(const char *cmdline) #ifdef DEBUG term_printf("command='%s'\n", cmdline); #endif - + /* extract the command name */ p = cmdline; q = cmdname; @@ -2005,7 +2005,7 @@ static void monitor_handle_command(const char *cmdline) len = sizeof(cmdname) - 1; memcpy(cmdname, pstart, len); cmdname[len] = '\0'; - + /* find the command */ for(cmd = term_cmds; cmd->name != NULL; cmd++) { if (compare_cmd(cmdname, cmd->name)) @@ -2017,7 +2017,7 @@ static void monitor_handle_command(const char *cmdline) for(i = 0; i < MAX_ARGS; i++) str_allocated[i] = NULL; - + /* parse the parameters */ typestr = cmd->args_type; nb_args = 0; @@ -2033,7 +2033,7 @@ static void monitor_handle_command(const char *cmdline) { int ret; char *str; - + while (isspace(*p)) p++; if (*typestr == '?') { @@ -2074,7 +2074,7 @@ static void monitor_handle_command(const char *cmdline) case '/': { int count, format, size; - + while (isspace(*p)) p++; if (*p == '/') { @@ -2207,7 +2207,7 @@ static void monitor_handle_command(const char *cmdline) { int has_option; /* option */ - + c = *typestr++; if (c == '\0') goto bad_type; diff --git a/qemu-doc.texi b/qemu-doc.texi index 249fd0525..c3a529ba9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -757,7 +757,7 @@ Change gdb connection port. @var{port} can be either a decimal number to specify a TCP port, or a host device (same devices as the serial port). @item -S Do not start CPU at startup (you must type 'c' in the monitor). -@item -d +@item -d Output log in /tmp/qemu.log @item -hdachs c,h,s,[,t] Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= @@ -832,9 +832,9 @@ During emulation, if you are using the @option{-nographic} option, use @table @key @item Ctrl-a h Print this help -@item Ctrl-a x +@item Ctrl-a x Exit emulator -@item Ctrl-a s +@item Ctrl-a s Save disk data back to file (if -snapshot) @item Ctrl-a t toggle console timestamps @@ -889,7 +889,7 @@ The following commands are available: @item help or ? [cmd] Show the help for all commands or just for command @var{cmd}. -@item commit +@item commit Commit changes to the disk images (if -snapshot is used) @item info subcommand @@ -1363,7 +1363,7 @@ network). The virtual network configuration is the following: | (10.0.2.2) | ----> DNS server (10.0.2.3) - | + | ----> SMB server (10.0.2.4) @end example @@ -1925,7 +1925,7 @@ The following options are specific to the PowerPC emulation: @table @option -@item -g WxH[xDEPTH] +@item -g WxH[xDEPTH] Set the initial VGA graphic mode. The default is 800x600x15. @@ -2339,7 +2339,7 @@ usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] @table @option @item -h Print the help -@item -L path +@item -L path Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) @item -s size Set the x86 stack size in bytes (default=524288) @@ -2437,7 +2437,7 @@ usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...] @table @option @item -h Print the help -@item -L path +@item -L path Set the library root path (default=/) @item -s size Set the stack size in bytes (default=524288) diff --git a/qemu-img.c b/qemu-img.c index aa3d719a8..d0210825c 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -168,7 +168,7 @@ static void term_init(void) tty.c_cflag |= CS8; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; - + tcsetattr (0, TCSANOW, &tty); atexit(term_exit); @@ -250,7 +250,7 @@ static int img_create(int argc, char **argv) int64_t size; const char *p; BlockDriver *drv; - + flags = 0; for(;;) { c = getopt(argc, argv, "b:f:he6"); @@ -461,7 +461,7 @@ static int img_convert(int argc, char **argv) if (optind >= argc) help(); out_filename = argv[optind++]; - + bs = bdrv_new_open(filename, fmt); drv = bdrv_find_format(out_fmt); @@ -484,7 +484,7 @@ static int img_convert(int argc, char **argv) error("Error while formatting '%s'", out_filename); } } - + out_bs = bdrv_new_open(out_filename, out_fmt); if (flags && BLOCK_FLAG_COMPRESS) { diff --git a/readline.c b/readline.c index 5f163afa7..d424a90a1 100644 --- a/readline.c +++ b/readline.c @@ -304,7 +304,7 @@ static void term_completion(void) char *cmdline; nb_completions = 0; - + cmdline = qemu_malloc(term_cmd_buf_index + 1); if (!cmdline) return; diff --git a/s390-dis.c b/s390-dis.c index b325b08c2..6e2558bf0 100644 --- a/s390-dis.c +++ b/s390-dis.c @@ -569,7 +569,7 @@ const struct s390_operand s390_operands[] = quite close. For example the instruction "mvo" is defined in the PoP as follows: - + MVO D1(L1,B1),D2(L2,B2) [SS] -------------------------------------- diff --git a/sdl.c b/sdl.c index 2233711fd..cac1a0365 100644 --- a/sdl.c +++ b/sdl.c @@ -345,7 +345,7 @@ static void sdl_refresh(DisplayState *ds) { SDL_Event ev1, *ev = &ev1; int mod_state; - + if (last_vm_running != vm_running) { last_vm_running = vm_running; sdl_update_caption(); @@ -494,7 +494,7 @@ static void sdl_refresh(DisplayState *ds) } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) { dz = 1; } -#endif +#endif sdl_send_mouse_event(dz); } } diff --git a/sh4-dis.c b/sh4-dis.c index 164ce4ffe..a1d56c59c 100644 --- a/sh4-dis.c +++ b/sh4-dis.c @@ -483,7 +483,7 @@ const sh_opcode_info sh_table[] = /* 0100nnnn10111010 lds ,Y1 */{"lds",{A_REG_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, /* 0100nnnn01011010 lds ,FPUL */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}, arch_sh2e_up}, - + /* 0100nnnn01101010 lds ,FPSCR */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}, arch_sh2e_up}, /* 0100nnnn00000110 lds.l @+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}, arch_sh1_up}, @@ -505,7 +505,7 @@ const sh_opcode_info sh_table[] = /* 0100nnnn10110110 lds.l @+,Y1 */{"lds.l",{A_INC_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_6}, arch_sh_dsp_up}, /* 0100nnnn01010110 lds.l @+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}, arch_sh2e_up}, - + /* 0100nnnn01100110 lds.l @+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}, arch_sh2e_up}, /* 0000000000111000 ldtlb */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}, arch_sh3_up}, @@ -758,7 +758,7 @@ const sh_opcode_info sh_table[] = /* 0000nnnn10111010 sts Y1, */{"sts",{A_Y1,A_REG_N},{HEX_0,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up}, /* 0000nnnn01011010 sts FPUL, */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}, arch_sh2e_up}, - + /* 0000nnnn01101010 sts FPSCR, */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh2e_up}, /* 0100nnnn00000010 sts.l MACH,@-*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}, arch_sh1_up}, @@ -780,7 +780,7 @@ const sh_opcode_info sh_table[] = /* 0100nnnn10110110 sts.l Y1,@- */{"sts.l",{A_Y1,A_DEC_N},{HEX_4,REG_N,HEX_B,HEX_2}, arch_sh_dsp_up}, /* 0100nnnn01010010 sts.l FPUL,@-*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}, arch_sh2e_up}, - + /* 0100nnnn01100010 sts.l FPSCR,@-*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh2e_up}, /* 0011nnnnmmmm1000 sub , */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}, arch_sh1_up}, diff --git a/slirp/bootp.c b/slirp/bootp.c index ebefa08b4..9f2635bf3 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -89,7 +89,7 @@ static void dhcp_decode(const uint8_t *buf, int size, const uint8_t *p, *p_end; int len, tag; - *pmsg_type = 0; + *pmsg_type = 0; p = buf; p_end = buf + size; @@ -137,16 +137,16 @@ static void bootp_reply(struct bootp_t *bp) /* extract exact DHCP msg type */ dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type); - + if (dhcp_msg_type == 0) dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ - + if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST) return; /* XXX: this is a hack to get the client mac address */ memcpy(client_ethaddr, bp->bp_hwaddr, 6); - + if ((m = m_get()) == NULL) return; m->m_data += if_maxlinkhdr; @@ -203,7 +203,7 @@ static void bootp_reply(struct bootp_t *bp) *q++ = 1; *q++ = DHCPACK; } - + if (dhcp_msg_type == DHCPDISCOVER || dhcp_msg_type == DHCPREQUEST) { *q++ = RFC2132_SRV_ID; @@ -217,12 +217,12 @@ static void bootp_reply(struct bootp_t *bp) *q++ = 0xff; *q++ = 0xff; *q++ = 0x00; - + *q++ = RFC1533_GATEWAY; *q++ = 4; memcpy(q, &saddr.sin_addr, 4); q += 4; - + *q++ = RFC1533_DNS; *q++ = 4; dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); @@ -244,7 +244,7 @@ static void bootp_reply(struct bootp_t *bp) } } *q++ = RFC1533_END; - + m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); diff --git a/slirp/cksum.c b/slirp/cksum.c index ee7e8644a..b98373b51 100644 --- a/slirp/cksum.c +++ b/slirp/cksum.c @@ -117,7 +117,7 @@ int cksum(struct mbuf *m, int len) sum += s_util.s; mlen = 0; } else - + mlen = -1; } else if (mlen == -1) s_util.c[0] = *(u_int8_t *)w; diff --git a/slirp/debug.c b/slirp/debug.c index 607b0e76e..e31244550 100644 --- a/slirp/debug.c +++ b/slirp/debug.c @@ -192,7 +192,7 @@ tcpstats() lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); - lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); + lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); lprint(" %6d acks (for %d bytes)\r\n", tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); @@ -302,9 +302,9 @@ sockstats() lprint( "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); - + for (so = tcb.so_next; so != &tcb; so = so->so_next) { - + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); while (n < 17) buff[n++] = ' '; @@ -316,9 +316,9 @@ sockstats() inet_ntoa(so->so_faddr), ntohs(so->so_fport), so->so_rcv.sb_cc, so->so_snd.sb_cc); } - + for (so = udb.so_next; so != &udb; so = so->so_next) { - + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); while (n < 17) buff[n++] = ' '; @@ -347,7 +347,7 @@ slirp_exit(exit_status) if (!dfd) debug_init("slirp_stats", 0xf); lprint_arg = (char **)&dfd; - + ipstats(); tcpstats(); udpstats(); diff --git a/slirp/if.c b/slirp/if.c index 6834c3396..6d72fa72f 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -179,7 +179,7 @@ if_output(so, ifm) } /* - * See if there's already a batchq list for this session. + * See if there's already a batchq list for this session. * This can include an interactive session, which should go on fastq, * but gets too greedy... hence it'll be downgraded from fastq to batchq. * We mustn't put this packet back on the fastq (or we'll send it out of order) @@ -231,10 +231,10 @@ diddit: */ if (on_fastq && ((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) { - + /* Remove from current queue... */ remque(ifm->ifs_next); - + /* ...And insert in the new. That'll teach ya! */ insque(ifm->ifs_next, &if_batchq); } @@ -290,7 +290,7 @@ if_start(void) ifm = next_m; else ifm = if_batchq.ifq_next; - + /* Set which packet to send on next iteration */ next_m = ifm->ifq_next; } diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index b24eae9b7..ae5a32118 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -105,7 +105,7 @@ icmp_input(m, hlen) } m->m_len += hlen; m->m_data -= hlen; - + /* icmpstat.icps_inhist[icp->icmp_type]++; */ /* code = icp->icmp_code; */ @@ -135,7 +135,7 @@ icmp_input(m, hlen) so->so_iptos = ip->ip_tos; so->so_type = IPPROTO_ICMP; so->so_state = SS_ISFCONNECTED; - + /* Send the packet */ addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { @@ -173,7 +173,7 @@ icmp_input(m, hlen) icmpstat.icps_notsupp++; m_freem(m); break; - + default: icmpstat.icps_badtype++; m_freem(m); @@ -226,7 +226,7 @@ icmp_error(msrc, type, code, minsize, message) /* check msrc */ if(!msrc) goto end_error; ip = mtod(msrc, struct ip *); -#if DEBUG +#if DEBUG { char bufa[20], bufb[20]; strcpy(bufa, inet_ntoa(ip->ip_src)); strcpy(bufb, inet_ntoa(ip->ip_dst)); @@ -258,9 +258,9 @@ icmp_error(msrc, type, code, minsize, message) /* make the header of the reply packet */ ip = mtod(m, struct ip *); hlen= sizeof(struct ip ); /* no options in reply */ - + /* fill in icmp */ - m->m_data += hlen; + m->m_data += hlen; m->m_len -= hlen; icp = mtod(m, struct icmp *); @@ -269,7 +269,7 @@ icmp_error(msrc, type, code, minsize, message) else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ s_ip_len=ICMP_MAXDATALEN; - m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ + m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ /* min. size = 8+sizeof(struct ip)+8 */ @@ -304,7 +304,7 @@ icmp_error(msrc, type, code, minsize, message) /* fill in ip */ ip->ip_hl = hlen >> 2; ip->ip_len = m->m_len; - + ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ ip->ip_ttl = MAXTTL; @@ -313,7 +313,7 @@ icmp_error(msrc, type, code, minsize, message) ip->ip_src = alias_addr; (void ) ip_output((struct socket *)NULL, m); - + icmpstat.icps_reflect++; end_error: diff --git a/slirp/ip_output.c b/slirp/ip_output.c index b80b038cd..b1a848402 100644 --- a/slirp/ip_output.c +++ b/slirp/ip_output.c @@ -143,7 +143,7 @@ ip_output(so, m0) m->m_data += if_maxlinkhdr; mhip = mtod(m, struct ip *); *mhip = *ip; - + /* No options */ /* if (hlen > sizeof (struct ip)) { * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); @@ -159,12 +159,12 @@ ip_output(so, m0) else mhip->ip_off |= IP_MF; mhip->ip_len = htons((u_int16_t)(len + mhlen)); - + if (m_copy(m, m0, off, len) < 0) { error = -1; goto sendorfree; } - + mhip->ip_off = htons((u_int16_t)mhip->ip_off); mhip->ip_sum = 0; mhip->ip_sum = cksum(m, mhlen); diff --git a/slirp/mbuf.c b/slirp/mbuf.c index bcf71bc61..392aea826 100644 --- a/slirp/mbuf.c +++ b/slirp/mbuf.c @@ -156,7 +156,7 @@ m_inc(m, size) m->m_ext = (char *)realloc(m->m_ext,size); /* if (m->m_ext == NULL) * return (struct mbuf *)NULL; - */ + */ m->m_data = m->m_ext + datasize; } else { char *dat; @@ -166,7 +166,7 @@ m_inc(m, size) * return (struct mbuf *)NULL; */ memcpy(dat, m->m_dat, m->m_size); - + m->m_ext = dat; m->m_data = m->m_ext + datasize; m->m_flags |= M_EXT; diff --git a/slirp/misc.c b/slirp/misc.c index db4444ef3..a41dd769b 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -335,13 +335,13 @@ fork_exec(so, ex, do_pty) addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; - + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || listen(s, 1) < 0) { lprint("Error: inet socket: %s\n", strerror(errno)); closesocket(s); - + return 0; } } @@ -353,7 +353,7 @@ fork_exec(so, ex, do_pty) if (do_pty == 2) close(master); return 0; - + case 0: /* Set the DISPLAY */ if (do_pty == 2) { @@ -375,7 +375,7 @@ fork_exec(so, ex, do_pty) ret = connect(s, (struct sockaddr *)&addr, addrlen); } while (ret < 0 && errno == EINTR); } - + #if 0 if (x_port >= 0) { #ifdef HAVE_SETENV @@ -392,7 +392,7 @@ fork_exec(so, ex, do_pty) dup2(s, 2); for (s = 3; s <= 255; s++) close(s); - + i = 0; bptr = strdup(ex); /* No need to free() this */ if (do_pty == 1) { @@ -410,21 +410,21 @@ fork_exec(so, ex, do_pty) *bptr++ = (char)0; argv[i++] = strdup(curarg); } while (c); - + argv[i] = 0; execvp(argv[0], argv); - + /* Ooops, failed, let's tell the user why */ { char buff[256]; - + sprintf(buff, "Error: execvp of %s failed: %s\n", argv[0], strerror(errno)); write(2, buff, strlen(buff)+1); } close(0); close(1); close(2); /* XXX */ exit(1); - + default: if (do_pty == 2) { close(s); @@ -447,13 +447,13 @@ fork_exec(so, ex, do_pty) setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); } fd_nonblock(so->s); - + /* Append the telnet options now */ if (so->so_m != 0 && do_pty == 1) { sbappend(so, so->so_m); so->so_m = 0; } - + return 1; } } @@ -570,15 +570,15 @@ relay(s) while (1) { FD_ZERO(&readfds); - + FD_SET(0, &readfds); FD_SET(s, &readfds); - + n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); - + if (n <= 0) slirp_exit(0); - + if (FD_ISSET(0, &readfds)) { n = read(0, buf, 8192); if (n <= 0) @@ -587,7 +587,7 @@ relay(s) if (n <= 0) slirp_exit(0); } - + if (FD_ISSET(s, &readfds)) { n = read(s, buf, 8192); if (n <= 0) @@ -614,7 +614,7 @@ lprint(va_alist) va_dcl #endif { va_list args; - + #ifdef __STDC__ va_start(args, format); #else @@ -631,15 +631,15 @@ lprint(va_alist) va_dcl int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; int deltap = lprint_ptr - lprint_sb->sb_data; - + lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, lprint_sb->sb_datalen + TCP_SNDSPACE); - + /* Adjust all values */ lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; lprint_ptr = lprint_sb->sb_data + deltap; - + lprint_sb->sb_datalen += TCP_SNDSPACE; } } @@ -655,9 +655,9 @@ lprint(va_alist) va_dcl */ int len = strlen(format); char *bptr1, *bptr2; - + bptr1 = bptr2 = strdup(format); - + while (len--) { if (*bptr1 == '\r') memcpy(bptr1, bptr1+1, len+1); @@ -900,11 +900,11 @@ rsh_exec(so,ns, user, host, args) close(fd0[0]); close(fd0[1]); return 0; - + case 0: close(fd[0]); close(fd0[0]); - + /* Set the DISPLAY */ if (x_port >= 0) { #ifdef HAVE_SETENV @@ -915,29 +915,29 @@ rsh_exec(so,ns, user, host, args) putenv(buff); #endif } - + dup2(fd0[1], 0); dup2(fd0[1], 1); dup2(fd[1], 2); for (s = 3; s <= 255; s++) close(s); - + execlp("rsh","rsh","-l", user, host, args, NULL); - + /* Ooops, failed, let's tell the user why */ - + sprintf(buff, "Error: execlp of %s failed: %s\n", "rsh", strerror(errno)); write(2, buff, strlen(buff)+1); close(0); close(1); close(2); /* XXX */ exit(1); - + default: close(fd[1]); close(fd0[1]); ns->s=fd[0]; so->s=fd0[0]; - + return 1; } } diff --git a/slirp/sbuf.c b/slirp/sbuf.c index e6b5bb670..209064b1a 100644 --- a/slirp/sbuf.c +++ b/slirp/sbuf.c @@ -37,7 +37,7 @@ sbdrop(sb, num) sb->sb_rptr += num; if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) sb->sb_rptr -= sb->sb_datalen; - + } void @@ -198,4 +198,4 @@ sbcopy(sb, off, len, to) memcpy(to+off,sb->sb_data,len); } } - + diff --git a/slirp/slirp.c b/slirp/slirp.c index 12093bf50..f535db12b 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -38,10 +38,10 @@ static int get_dns_addr(struct in_addr *pdns_addr) DWORD ret; IP_ADDR_STRING *pIPAddr; struct in_addr tmp_addr; - + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); BufLen = sizeof(FIXED_INFO); - + if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { if (FixedInfo) { GlobalFree(FixedInfo); @@ -58,14 +58,14 @@ static int get_dns_addr(struct in_addr *pdns_addr) } return -1; } - + pIPAddr = &(FixedInfo->DnsServerList); inet_aton(pIPAddr->IpAddress.String, &tmp_addr); *pdns_addr = tmp_addr; #if 0 printf( "DNS Servers:\n" ); printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String ); - + pIPAddr = FixedInfo -> DnsServerList.Next; while ( pIPAddr ) { printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String ); @@ -88,7 +88,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) FILE *f; int found = 0; struct in_addr tmp_addr; - + f = fopen("/etc/resolv.conf", "r"); if (!f) return -1; @@ -130,7 +130,7 @@ void slirp_cleanup(void) void slirp_init(void) { // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); - + #ifdef _WIN32 { WSADATA Data; @@ -201,7 +201,7 @@ void slirp_select_fill(int *pnfds, global_readfds = NULL; global_writefds = NULL; global_xfds = NULL; - + nfds = *pnfds; /* * First, TCP sockets @@ -214,23 +214,23 @@ void slirp_select_fill(int *pnfds, */ do_slowtimo = ((tcb.so_next != &tcb) || ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); - + for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; - + /* * See if we need a tcp_fasttimo */ if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) time_fasttimo = curtime; /* Flag when we want a fasttimo */ - + /* * NOFDREF can include still connecting to local-host, * newly socreated() sockets etc. Don't want to select these. */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; - + /* * Set for reading sockets which are accepting */ @@ -239,7 +239,7 @@ void slirp_select_fill(int *pnfds, UPD_NFDS(so->s); continue; } - + /* * Set for writing sockets which are connecting */ @@ -248,7 +248,7 @@ void slirp_select_fill(int *pnfds, UPD_NFDS(so->s); continue; } - + /* * Set for writing if we are connected, can send more, and * we have something to send @@ -257,7 +257,7 @@ void slirp_select_fill(int *pnfds, FD_SET(so->s, writefds); UPD_NFDS(so->s); } - + /* * Set for reading (and urgent data) if we are connected, can * receive more, and we have room for it XXX /2 ? @@ -268,13 +268,13 @@ void slirp_select_fill(int *pnfds, UPD_NFDS(so->s); } } - + /* * UDP sockets */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; - + /* * See if it's timed out */ @@ -285,7 +285,7 @@ void slirp_select_fill(int *pnfds, } else do_slowtimo = 1; /* Let socket expire */ } - + /* * When UDP packets are received from over the * link, they're sendto()'d straight away, so @@ -324,13 +324,13 @@ void slirp_select_fill(int *pnfds, timeout.tv_usec = 0; else if (timeout.tv_usec > 510000) timeout.tv_usec = 510000; - + /* Can only fasttimo if we also slowtimo */ if (time_fasttimo) { tmp_time = (200 - (curtime - time_fasttimo)) * 1000; if (tmp_time < 0) tmp_time = 0; - + /* Choose the smallest of the 2 */ if (tmp_time < timeout.tv_usec) timeout.tv_usec = (u_int)tmp_time; @@ -375,14 +375,14 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) */ for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; - + /* * FD_ISSET is meaningless on these sockets * (and they can crash the program) */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; - + /* * Check for URG data * This will soread as well, so no need to @@ -402,12 +402,12 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) continue; } /* else */ ret = soread(so); - + /* Output it if we read something */ if (ret > 0) tcp_output(sototcpcb(so)); } - + /* * Check sockets for writing */ @@ -418,19 +418,19 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) if (so->so_state & SS_ISFCONNECTING) { /* Connected */ so->so_state &= ~SS_ISFCONNECTING; - + ret = send(so->s, &ret, 0, 0); if (ret < 0) { /* XXXXX Must fix, zero bytes is a NOP */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; - + /* else failed */ so->so_state = SS_NOFDREF; } /* else so->so_state &= ~SS_ISFCONNECTING; */ - + /* * Continue tcp_input */ @@ -445,7 +445,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) * a window probe to get things going again */ } - + /* * Probe a still-connecting, non-blocking socket * to check if it's still alive @@ -453,16 +453,16 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) #ifdef PROBE_CONN if (so->so_state & SS_ISFCONNECTING) { ret = recv(so->s, (char *)&ret, 0,0); - + if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* Still connecting, continue */ - + /* else failed */ so->so_state = SS_NOFDREF; - + /* tcp_input will take care of it */ } else { ret = send(so->s, &ret, 0,0); @@ -475,13 +475,13 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) so->so_state = SS_NOFDREF; } else so->so_state &= ~SS_ISFCONNECTING; - + } tcp_input((struct mbuf *)NULL, sizeof(struct ip),so); } /* SS_ISFCONNECTING */ #endif } - + /* * Now UDP sockets. * Incoming packets are sent straight away, they're not buffered. @@ -489,7 +489,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; - + if (so->s != -1 && FD_ISSET(so->s, readfds)) { sorecvfrom(so); } @@ -600,7 +600,7 @@ void slirp_input(const uint8_t *pkt, int pkt_len) if (pkt_len < ETH_HLEN) return; - + proto = ntohs(*(uint16_t *)(pkt + 12)); switch(proto) { case ETH_P_ARP: diff --git a/slirp/socket.c b/slirp/socket.c index 141bcb262..7e07cf894 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -251,7 +251,7 @@ sosendoob(so) /* We can send it directly */ n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ so->so_urgc -= n; - + DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); } else { /* @@ -274,7 +274,7 @@ sosendoob(so) #ifdef DEBUG if (n != len) DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); -#endif +#endif DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); } @@ -396,17 +396,17 @@ sorecvfrom(so) if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ char buff[256]; int len; - + len = recvfrom(so->s, buff, 256, 0, (struct sockaddr *)&addr, &addrlen); /* XXX Check if reply is "correct"? */ - + if(len == -1 || len == 0) { u_char code=ICMP_UNREACH_PORT; if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; - + DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", errno,strerror(errno))); icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); @@ -422,7 +422,7 @@ sorecvfrom(so) if (!(m = m_get())) return; m->m_data += if_maxlinkhdr; - + /* * XXX Shouldn't FIONREAD packets destined for port 53, * but I don't know the max packet size for DNS lookups @@ -430,14 +430,14 @@ sorecvfrom(so) len = M_FREEROOM(m); /* if (so->so_fport != htons(53)) { */ ioctlsocket(so->s, FIONREAD, &n); - + if (n > len) { n = (m->m_data - m->m_dat) + m->m_len + n + 1; m_inc(m, n); len = M_FREEROOM(m); } /* } */ - + m->m_len = recvfrom(so->s, m->m_data, len, 0, (struct sockaddr *)&addr, &addrlen); DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", @@ -447,7 +447,7 @@ sorecvfrom(so) if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; - + DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); m_free(m); @@ -470,7 +470,7 @@ sorecvfrom(so) * m->m_len = 0; * } */ - + /* * If this packet was destined for CTL_ADDR, * make it look like that's where it came from, done by udp_output @@ -580,7 +580,7 @@ solisten(port, laddr, lport, flags) (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (listen(s,1) < 0)) { int tmperrno = errno; /* Don't clobber the real reason we failed */ - + close(s); sofree(so); /* Restore the real errno */ diff --git a/slirp/socket.h b/slirp/socket.h index 901e8423e..99cc17f32 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -33,16 +33,16 @@ struct socket { struct in_addr so_laddr; /* local host table entry */ u_int16_t so_fport; /* foreign port */ u_int16_t so_lport; /* local port */ - + u_int8_t so_iptos; /* Type of service */ u_int8_t so_emu; /* Is the socket emulated? */ - + u_char so_type; /* Type of socket, UDP or TCP */ int so_state; /* internal state flags SS_*, below */ - + struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ u_int so_expire; /* When the socket will expire */ - + int so_queued; /* Number of packets queued from this socket */ int so_nqueued; /* Number of packets queued in a row * Used to determine when to "downgrade" a session diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index da35c4398..04f655312 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -262,7 +262,7 @@ tcp_input(m, iphlen, inso) */ if (m == NULL) { so = inso; - + /* Re-set a few variables */ tp = sototcpcb(so); m = so->so_m; @@ -270,7 +270,7 @@ tcp_input(m, iphlen, inso) ti = so->so_ti; tiwin = ti->ti_win; tiflags = ti->ti_flags; - + goto cont_conn; } @@ -394,32 +394,32 @@ findso: if (so == 0) { if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN) goto dropwithreset; - + if ((so = socreate()) == NULL) goto dropwithreset; if (tcp_attach(so) < 0) { free(so); /* Not sofree (if it failed, it's not insqued) */ goto dropwithreset; } - + sbreserve(&so->so_snd, tcp_sndspace); sbreserve(&so->so_rcv, tcp_rcvspace); - + /* tcp_last_so = so; */ /* XXX ? */ /* tp = sototcpcb(so); */ - + so->so_laddr = ti->ti_src; so->so_lport = ti->ti_sport; so->so_faddr = ti->ti_dst; so->so_fport = ti->ti_dport; - + if ((so->so_iptos = tcp_tos(so)) == 0) so->so_iptos = ((struct ip *)ti)->ip_tos; - + tp = sototcpcb(so); tp->t_state = TCPS_LISTEN; } - + /* * If this is a still-connecting socket, this probably * a retransmit of the SYN. Whether it's a retransmit SYN @@ -567,14 +567,14 @@ findso: if (tcp_emu(so,m)) sbappend(so, m); } else sbappend(so, m); - + /* * XXX This is called when data arrives. Later, check * if we can actually write() to the socket * XXX Need to check? It's be NON_BLOCKING */ /* sorwakeup(so); */ - + /* * If this is a short packet, then ACK now - with Nagel * congestion avoidance sender won't send more until @@ -624,12 +624,12 @@ findso: goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; - + /* * This has way too many gotos... * But a bit of spaghetti code never hurt anybody :) */ - + /* * If this is destined for the control address, then flag to * tcp_ctl once connected, otherwise connect @@ -658,12 +658,12 @@ findso: } /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ } - + if (so->so_emu & EMU_NOCONNECT) { so->so_emu &= ~EMU_NOCONNECT; goto cont_input; } - + if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { u_char code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", @@ -699,7 +699,7 @@ findso: } return; - cont_conn: + cont_conn: /* m==NULL * Check if the connect succeeded */ @@ -707,14 +707,14 @@ findso: tp = tcp_close(tp); goto dropwithreset; } - cont_input: + cont_input: tcp_template(tp); - + if (optp) tcp_dooptions(tp, (u_char *)optp, optlen, ti); /* , */ /* &ts_present, &ts_val, &ts_ecr); */ - + if (iss) tp->iss = iss; else @@ -770,7 +770,7 @@ findso: tcpstat.tcps_connects++; soisfconnected(so); tp->t_state = TCPS_ESTABLISHED; - + /* Do window scaling on this connection? */ /* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == * (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -866,7 +866,7 @@ trimthenstep6: * of sequence; drop it. */ tiflags &= ~TH_FIN; - + /* * Send an ACK to resynchronize and drop any data. * But keep on processing for RST or ACK. @@ -1022,7 +1022,7 @@ trimthenstep6: * The first data byte already in the buffer will get * lost if no correction is made. This is only needed for * SS_CTL since the buffer is empty otherwise. - * tp->snd_una++; or: + * tp->snd_una++; or: */ tp->snd_una=ti->ti_ack; if (so->so_state & SS_CTL) { @@ -1040,7 +1040,7 @@ trimthenstep6: } else { soisfconnected(so); } - + /* Do window scaling? */ /* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == * (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1159,7 +1159,7 @@ trimthenstep6: /* if (ts_present) * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); * else - */ + */ if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp,tp->t_rtt); @@ -1328,7 +1328,7 @@ step6: so->so_urgc = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt); /* -1; */ tp->rcv_up = ti->ti_seq + ti->ti_urp; - + } } else /* @@ -1379,7 +1379,7 @@ dodata: */ /* sofcantrcvmore(so); */ sofwdrain(so); - + tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; } diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c index b4be123dc..3eddfd38e 100644 --- a/slirp/tcp_output.c +++ b/slirp/tcp_output.c @@ -356,7 +356,7 @@ send: } m->m_data += if_maxlinkhdr; m->m_len = hdrlen; - + /* * This will always succeed, since we make sure our mbufs * are big enough to hold one MSS packet + header + ... etc. @@ -449,7 +449,7 @@ send: if (SEQ_GT(tp->snd_up, tp->snd_una)) { ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); -#ifdef notdef +#ifdef notdef if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); #endif @@ -533,12 +533,12 @@ send: m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ { - + ((struct ip *)ti)->ip_len = m->m_len; ((struct ip *)ti)->ip_ttl = ip_defttl; ((struct ip *)ti)->ip_tos = so->so_iptos; - + /* #if BSD >= 43 */ /* Don't do IP options... */ /* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 547a7f679..3814ec19b 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -155,7 +155,7 @@ tcp_respond(tp, ti, m, ack, seq, flags) * the mbuf point to ti */ m->m_data = (caddr_t)ti; - + m->m_len = sizeof (struct tcpiphdr); tlen = 0; #define xchg(a,b,type) { type t; t=a; a=b; b=t; } @@ -396,7 +396,7 @@ int tcp_fconnect(so) struct socket *so; { int ret=0; - + DEBUG_CALL("tcp_fconnect"); DEBUG_ARG("so = %lx", (long )so); @@ -409,7 +409,7 @@ int tcp_fconnect(so) setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); opt = 1; setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); - + addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ @@ -425,13 +425,13 @@ int tcp_fconnect(so) } else addr.sin_addr = so->so_faddr; addr.sin_port = so->so_fport; - + DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " "addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); /* We don't care what port we get */ ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); - + /* * If it's not in progress, it failed, so we just return 0, * without clearing SS_NOFDREF @@ -573,7 +573,7 @@ struct tos_t tcptos[] = { }; struct emu_t *tcpemu = 0; - + /* * Return TOS according to the above table */ @@ -618,7 +618,7 @@ int do_echo = -1; * more checks are needed here * * XXX Assumes the whole command came in one packet - * + * * XXX Some ftp clients will have their TOS set to * LOWDELAY and so Nagel will kick in. Because of this, * we'll get the first letter, followed by the rest, so @@ -648,18 +648,18 @@ tcp_emu(so, m) switch(so->so_emu) { int x, i; - + case EMU_IDENT: /* * Identification protocol as per rfc-1413 */ - + { struct socket *tmpso; struct sockaddr_in addr; int addrlen = sizeof(struct sockaddr_in); struct sbuf *so_rcv = &so->so_rcv; - + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; @@ -688,7 +688,7 @@ tcp_emu(so, m) m_free(m); return 0; } - + #if 0 case EMU_RLOGIN: /* @@ -703,7 +703,7 @@ tcp_emu(so, m) char term[100]; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; - + /* First check if they have a priveladged port, or too much data has arrived */ if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { @@ -714,13 +714,13 @@ tcp_emu(so, m) m_free(m); return 0; } - + /* Append the current data */ memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m_free(m); - + /* * Check if we have all the initial options, * and build argument list to rlogin while we're here @@ -752,10 +752,10 @@ tcp_emu(so, m) } } } - + if (n != 4) return 0; - + /* We have it, set our term variable and fork_exec() */ #ifdef HAVE_SETENV setenv("TERM", term, 1); @@ -765,15 +765,15 @@ tcp_emu(so, m) fork_exec(so, args, 2); term[0] = 0; so->so_emu = 0; - + /* And finally, send the client a 0 character */ so_snd->sb_wptr[0] = 0; so_snd->sb_wptr++; so_snd->sb_cc++; - + return 0; } - + case EMU_RSH: /* * rsh emulation @@ -787,7 +787,7 @@ tcp_emu(so, m) char *args; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; - + /* First check if they have a priveladged port, or too much data has arrived */ if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { @@ -798,13 +798,13 @@ tcp_emu(so, m) m_free(m); return 0; } - + /* Append the current data */ memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m_free(m); - + /* * Check if we have all the initial options, * and build argument list to rlogin while we're here @@ -846,9 +846,9 @@ tcp_emu(so, m) ns->so_iptos = tcp_tos(ns); tp = sototcpcb(ns); - + tcp_template(tp); - + /* Compute window scaling to request. */ /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) @@ -858,7 +858,7 @@ tcp_emu(so, m) /*soisfconnecting(ns);*/ tcpstat.tcps_connattempt++; - + tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tp->iss = tcp_iss; @@ -877,19 +877,19 @@ tcp_emu(so, m) } } } - + if (n != 4) return 0; - + rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); so->so_emu = 0; so->extra=NULL; - + /* And finally, send the client a 0 character */ so_snd->sb_wptr[0] = 0; so_snd->sb_wptr++; so_snd->sb_cc++; - + return 0; } @@ -898,7 +898,7 @@ tcp_emu(so, m) int num; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; - + /* * If there is binary data here, we save it in so->so_m */ @@ -913,16 +913,16 @@ tcp_emu(so, m) } } } /* if(so->so_m==NULL) */ - + /* * Append the line */ sbappendsb(so_rcv, m); - + /* To avoid going over the edge of the buffer, we reset it */ if (so_snd->sb_cc == 0) so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; - + /* * A bit of a hack: * If the first packet we get here is 1 byte long, then it @@ -941,13 +941,13 @@ tcp_emu(so, m) tcp_output(sototcpcb(so)); /* XXX */ } else m_free(m); - + num = 0; while (num < so->so_rcv.sb_cc) { if (*(so->so_rcv.sb_rptr + num) == '\n' || *(so->so_rcv.sb_rptr + num) == '\r') { int n; - + *(so_rcv->sb_rptr + num) = 0; if (ctl_password && !ctl_password_ok) { /* Need a password */ @@ -984,36 +984,36 @@ do_prompt: } return 0; } -#endif +#endif case EMU_FTP: /* ftp */ *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { /* * Need to emulate the PORT command - */ + */ x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; - + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); lport = htons((n5 << 8) | (n6)); - + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) return 1; - + n6 = ntohs(so->so_fport); - + n5 = (n6 >> 8) & 0xff; n6 &= 0xff; - + laddr = ntohl(so->so_faddr.s_addr); - + n1 = ((laddr >> 24) & 0xff); n2 = ((laddr >> 16) & 0xff); n3 = ((laddr >> 8) & 0xff); n4 = (laddr & 0xff); - + m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); @@ -1026,34 +1026,34 @@ do_prompt: &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; - + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); lport = htons((n5 << 8) | (n6)); - + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) return 1; - + n6 = ntohs(so->so_fport); - + n5 = (n6 >> 8) & 0xff; n6 &= 0xff; - + laddr = ntohl(so->so_faddr.s_addr); - + n1 = ((laddr >> 24) & 0xff); n2 = ((laddr >> 16) & 0xff); n3 = ((laddr >> 8) & 0xff); n4 = (laddr & 0xff); - + m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); - + return 1; } - + return 1; - + case EMU_KSH: /* * The kshell (Kerberos rsh) and shell services both pass @@ -1072,7 +1072,7 @@ do_prompt: (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; return 1; - + case EMU_IRC: /* * Need to emulate DCC CHAT, DCC SEND and DCC MOVE @@ -1080,12 +1080,12 @@ do_prompt: *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) return 1; - + /* The %256s is for the broken mIRC */ if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; - + m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", (unsigned long)ntohl(so->so_faddr.s_addr), @@ -1093,7 +1093,7 @@ do_prompt: } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; - + m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), @@ -1101,7 +1101,7 @@ do_prompt: } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; - + m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), @@ -1120,43 +1120,43 @@ do_prompt: * any more. * * A typical packet for player version 1.0 (release version): - * + * * 0000:50 4E 41 00 05 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .......glc..P * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB - * + * * Now the port number 0x1BD7 is found at offset 0x04 of the * Now the port number 0x1BD7 is found at offset 0x04 of the * second packet. This time we received five bytes first and * then the rest. You never know how many bytes you get. * * A typical packet for player version 2.0 (beta): - * + * * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA............ * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxc..Win2.0.0 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B - * + * * Port number 0x1BC1 is found at offset 0x0d. - * + * * This is just a horrible switch statement. Variable ra tells * us where we're going. */ - + bptr = m->m_data; while (bptr < m->m_data + m->m_len) { u_short p; static int ra = 0; char ra_tbl[4]; - + ra_tbl[0] = 0x50; ra_tbl[1] = 0x4e; ra_tbl[2] = 0x41; ra_tbl[3] = 0; - + switch (ra) { case 0: case 2: @@ -1166,7 +1166,7 @@ do_prompt: continue; } break; - + case 1: /* * We may get 0x50 several times, ignore them @@ -1180,14 +1180,14 @@ do_prompt: continue; } break; - + case 4: /* * skip version number */ bptr++; break; - + case 5: /* * The difference between versions 1.0 and @@ -1198,19 +1198,19 @@ do_prompt: bptr += 8; else bptr += 4; - break; - + break; + case 6: /* This is the field containing the port * number that RA-player is listening to. */ lport = (((u_char*)bptr)[0] << 8) + ((u_char *)bptr)[1]; - if (lport < 6970) + if (lport < 6970) lport += 256; /* don't know why */ if (lport < 6970 || lport > 7170) return 1; /* failed */ - + /* try to get udp port between 6970 - 7170 */ for (p = 6970; p < 7071; p++) { if (udp_listen( htons(p), @@ -1226,15 +1226,15 @@ do_prompt: *(u_char *)bptr++ = p & 0xff; ra = 0; return 1; /* port redirected, we're done */ - break; - + break; + default: - ra = 0; + ra = 0; } ra++; } - return 1; - + return 1; + default: /* Ooops, not emulated, won't call tcp_emu again */ so->so_emu = 0; @@ -1274,7 +1274,7 @@ tcp_ctl(so) switch(command) { default: /* Check for exec's */ - + /* * Check if it's pty_exec */ @@ -1285,12 +1285,12 @@ tcp_ctl(so) goto do_exec; } } - + /* * Nothing bound.. */ /* tcp_fconnect(so); */ - + /* FALLTHROUGH */ case CTL_ALIAS: sb->sb_cc = sprintf(sb->sb_wptr, @@ -1301,7 +1301,7 @@ tcp_ctl(so) do_exec: DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); return(fork_exec(so, ex_ptr->ex_exec, do_pty)); - + #if 0 case CTL_CMD: for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c index 044c2b8f7..cc1bd50c0 100644 --- a/slirp/tcp_timer.c +++ b/slirp/tcp_timer.c @@ -164,12 +164,12 @@ tcp_timers(tp, timer) * to a longer retransmit interval and retransmit one segment. */ case TCPT_REXMT: - + /* * XXXXX If a packet has timed out, then remove all the queued * packets for that session. */ - + if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { /* * This is a hack to suit our terminal server here at the uni of canberra @@ -185,7 +185,7 @@ tcp_timers(tp, timer) * * *sigh* */ - + tp->t_maxseg >>= 1; if (tp->t_maxseg < 32) { /* @@ -197,7 +197,7 @@ tcp_timers(tp, timer) /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ return (tp); /* XXX */ } - + /* * Set rxtshift to 6, which is still at the maximum * backoff time diff --git a/slirp/tftp.c b/slirp/tftp.c index f16530db6..2b2bf2c5a 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -27,10 +27,10 @@ struct tftp_session { int in_use; unsigned char filename[TFTP_FILENAME_MAX]; - + struct in_addr client_ip; u_int16_t client_port; - + int timestamp; }; @@ -146,14 +146,14 @@ static int tftp_send_oack(struct tftp_session *spt, m->m_data += if_maxlinkhdr; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); - + tp->tp_op = htons(TFTP_OACK); n += sprintf(tp->x.tp_buf + n, "%s", key) + 1; n += sprintf(tp->x.tp_buf + n, "%u", value) + 1; saddr.sin_addr = recv_tp->ip.ip_dst; saddr.sin_port = recv_tp->udp.uh_dport; - + daddr.sin_addr = spt->client_ip; daddr.sin_port = spt->client_port; @@ -186,7 +186,7 @@ static int tftp_send_error(struct tftp_session *spt, m->m_data += if_maxlinkhdr; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); - + tp->tp_op = htons(TFTP_ERROR); tp->x.tp_error.tp_error_code = htons(errorcode); strcpy(tp->x.tp_error.tp_msg, msg); @@ -233,7 +233,7 @@ static int tftp_send_data(struct tftp_session *spt, m->m_data += if_maxlinkhdr; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); - + tp->tp_op = htons(TFTP_DATA); tp->x.tp_data.tp_block_nr = htons(block_nr); @@ -297,23 +297,23 @@ static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) else { return; } - + if (src[k] == '\0') { break; } } - + if (k >= n) { return; } - + k++; - + /* check mode */ if ((n - k) < 6) { return; } - + if (memcmp(&src[k], "octet\0", 6) != 0) { tftp_send_error(spt, 4, "Unsupported transfer mode", tp); return; @@ -338,7 +338,7 @@ static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) } /* check if the file exists */ - + if (tftp_read_data(spt, 0, spt->filename, 0) < 0) { tftp_send_error(spt, 1, "File not found", tp); return; diff --git a/slirp/udp.c b/slirp/udp.c index 2504d119a..44900ff14 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -168,7 +168,7 @@ udp_input(m, iphlen) if (so->so_lport != uh->uh_sport || so->so_laddr.s_addr != ip->ip_src.s_addr) { struct socket *tmp; - + for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { if (tmp->so_lport == uh->uh_sport && tmp->so_laddr.s_addr == ip->ip_src.s_addr) { @@ -198,17 +198,17 @@ udp_input(m, iphlen) sofree(so); goto bad; } - + /* * Setup fields */ /* udp_last_so = so; */ so->so_laddr = ip->ip_src; so->so_lport = uh->uh_sport; - + if ((so->so_iptos = udp_tos(so)) == 0) so->so_iptos = ip->ip_tos; - + /* * XXXXX Here, check if it's in udpexec_list, * and if it is, do the fork_exec() etc. @@ -233,7 +233,7 @@ udp_input(m, iphlen) m->m_data -= iphlen; *ip=save_ip; DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); - icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); } m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ @@ -320,7 +320,7 @@ int udp_output(struct socket *so, struct mbuf *m, } daddr.sin_addr = so->so_laddr; daddr.sin_port = so->so_lport; - + return udp_output2(so, m, &saddr, &daddr, so->so_iptos); } @@ -449,7 +449,7 @@ struct cu_header { */ if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) return; - + #define IS_OLD (so->so_emu == EMU_TALK) #define COPY_MSG(dest, src) { dest->type = src->type; \ @@ -480,10 +480,10 @@ struct cu_header { OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); } - + if (type == LOOK_UP) return; /* for LOOK_UP this is enough */ - + if (IS_OLD) { /* make a copy of the message */ COPY_MSG(nmsg, omsg); nmsg->vers = 1; @@ -507,39 +507,39 @@ struct cu_header { if (type == ANNOUNCE) { int s; u_short temp_port; - + for(req = req_tbl; req; req = req->next) if (so == req->udp_so) break; /* found it */ - + if (!req) { /* no entry for so, create new */ req = (struct talk_request *) malloc(sizeof(struct talk_request)); req->udp_so = so; - req->tcp_so = solisten(0, + req->tcp_so = solisten(0, OTOSIN(omsg, addr)->sin_addr.s_addr, OTOSIN(omsg, addr)->sin_port, SS_FACCEPTONCE); req->next = req_tbl; req_tbl = req; - } - + } + /* replace port number in addr field */ addrlen = sizeof(addr); getsockname(req->tcp_so->s, (struct sockaddr *) &addr, - &addrlen); + &addrlen); OTOSIN(omsg, addr)->sin_port = addr.sin_port; OTOSIN(omsg, addr)->sin_addr = our_addr; OTOSIN(nmsg, addr)->sin_port = addr.sin_port; - OTOSIN(nmsg, addr)->sin_addr = our_addr; - + OTOSIN(nmsg, addr)->sin_addr = our_addr; + /* send LEAVE_INVITEs */ temp_port = OTOSIN(omsg, ctl_addr)->sin_port; OTOSIN(omsg, ctl_addr)->sin_port = 0; OTOSIN(nmsg, ctl_addr)->sin_port = 0; - omsg->type = nmsg->type = LEAVE_INVITE; - + omsg->type = nmsg->type = LEAVE_INVITE; + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); addr.sin_addr = our_addr; addr.sin_family = AF_INET; @@ -555,22 +555,22 @@ struct cu_header { OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; } - + /* * If it is a DELETE message, we send a copy to the * local daemons. Then we delete the entry corresponding * to our socket from the request table. */ - + if (type == DELETE) { struct talk_request *temp_req, *req_next; int s; u_short temp_port; - + temp_port = OTOSIN(omsg, ctl_addr)->sin_port; OTOSIN(omsg, ctl_addr)->sin_port = 0; OTOSIN(nmsg, ctl_addr)->sin_port = 0; - + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); addr.sin_addr = our_addr; addr.sin_family = AF_INET; @@ -581,7 +581,7 @@ struct cu_header { sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *)&addr, sizeof(addr)); closesocket(s); - + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; @@ -604,10 +604,10 @@ struct cu_header { } } } - - return; + + return; #endif - + case EMU_CUSEEME: /* @@ -623,7 +623,7 @@ struct cu_header { cu_head->s_port = addr.sin_port; cu_head->so_addr = our_addr.s_addr; } - + return; } } diff --git a/softmmu_template.h b/softmmu_template.h index 00492e8b5..ce6e4bd07 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -83,7 +83,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, target_ulong tlb_addr; target_phys_addr_t physaddr; void *retaddr; - + /* test if there is match for unaligned or IO access */ /* XXX: could done more in memory macro in a non portable way */ index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); @@ -217,7 +217,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, target_ulong tlb_addr; void *retaddr; int index; - + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: tlb_addr = env->tlb_table[is_user][index].addr_write; diff --git a/sparc-dis.c b/sparc-dis.c index 28fab962c..4d2020fcd 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -2566,7 +2566,7 @@ print_insn_sparc (memaddr, info) /* Nonzero means that we have found a plus sign in the args field of the opcode table. */ int found_plus = 0; - + /* Nonzero means we have an annulled branch. */ int is_annulled = 0; @@ -2621,7 +2621,7 @@ print_insn_sparc (memaddr, info) } /* while there are comma started args */ (*info->fprintf_func) (stream, " "); - + switch (*s) { case '+': @@ -2722,7 +2722,7 @@ print_insn_sparc (memaddr, info) not before it. */ if (found_plus) imm_added_to_rs1 = 1; - + if (imm <= 9) (*info->fprintf_func) (stream, "%d", imm); else @@ -2806,7 +2806,7 @@ print_insn_sparc (memaddr, info) case 'o': (*info->fprintf_func) (stream, "%%asi"); break; - + case 'W': (*info->fprintf_func) (stream, "%%tick"); break; @@ -2859,15 +2859,15 @@ print_insn_sparc (memaddr, info) (*info->fprintf_func) (stream, "%d", X_RD (insn)); break; } - + case 'M': (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn)); break; - + case 'm': (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn)); break; - + case 'L': info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4; (*info->print_address_func) (info->target, info); diff --git a/tap-win32.c b/tap-win32.c index 8384952c6..c900b4b76 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -343,7 +343,7 @@ static int get_device_guid( 0, KEY_READ, &connection_key); - + if (status == ERROR_SUCCESS) { len = sizeof (name_data); status = RegQueryValueEx( @@ -467,7 +467,7 @@ static int tap_win32_write(tap_win32_overlapped_t *overlapped, result = WriteFile(overlapped->handle, buffer, size, &write_size, &overlapped->write_overlapped); - + if (!result) { switch (error = GetLastError()) { @@ -660,7 +660,7 @@ static void tap_win32_send(void *opaque) int tap_win32_init(VLANState *vlan, const char *ifname) { TAPState *s; - + s = qemu_mallocz(sizeof(TAPState)); if (!s) return -1; @@ -670,7 +670,7 @@ int tap_win32_init(VLANState *vlan, const char *ifname) } s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s); - + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s", ifname); diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 4ec5967ff..72cae49cf 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -35,7 +35,7 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, else env->exception_index = EXCP_DFAULT; env->ipr[IPR_EXC_ADDR] = address; - + return 1; } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 19ce68b4f..76fdbb26b 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -64,11 +64,11 @@ typedef struct CPUARMState { uint32_t banked_spsr[6]; uint32_t banked_r13[6]; uint32_t banked_r14[6]; - + /* These hold r8-r12. */ uint32_t usr_regs[5]; uint32_t fiq_regs[5]; - + /* cpsr flag cache for faster execution */ uint32_t CF; /* 0 or 1 */ uint32_t VF; /* V is the bit 31. All other bits are undefined */ @@ -134,7 +134,7 @@ typedef struct CPUARMState { /* Temporary variables if we don't have spare fp regs. */ float32 tmp0s, tmp1s; float64 tmp0d, tmp1d; - + float_status fp_status; } vfp; diff --git a/target-arm/nwfpe/double_cpdo.c b/target-arm/nwfpe/double_cpdo.c index afc86aa41..dbd496ea6 100644 --- a/target-arm/nwfpe/double_cpdo.c +++ b/target-arm/nwfpe/double_cpdo.c @@ -42,14 +42,14 @@ unsigned int DoubleCPDO(const unsigned int opcode) unsigned int Fd, Fm, Fn, nRc = 1; //printk("DoubleCPDO(0x%08x)\n",opcode); - + Fm = getFm(opcode); if (CONSTANT_FM(opcode)) { rFm = getDoubleConstant(Fm); } else - { + { switch (fpa11->fType[Fm]) { case typeSingle: @@ -85,7 +85,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) case typeDouble: rFn = fpa11->fpreg[Fn].fDouble; break; - + default: return 0; } } @@ -220,7 +220,7 @@ unsigned int DoubleCPDO(const unsigned int opcode) case NRM_CODE: break; - + default: { nRc = 0; diff --git a/target-arm/nwfpe/extended_cpdo.c b/target-arm/nwfpe/extended_cpdo.c index caacdf228..05e32b073 100644 --- a/target-arm/nwfpe/extended_cpdo.c +++ b/target-arm/nwfpe/extended_cpdo.c @@ -42,14 +42,14 @@ unsigned int ExtendedCPDO(const unsigned int opcode) unsigned int Fd, Fm, Fn, nRc = 1; //printk("ExtendedCPDO(0x%08x)\n",opcode); - + Fm = getFm(opcode); if (CONSTANT_FM(opcode)) { rFm = getExtendedConstant(Fm); } else - { + { switch (fpa11->fType[Fm]) { case typeSingle: @@ -59,15 +59,15 @@ unsigned int ExtendedCPDO(const unsigned int opcode) case typeDouble: rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; - + case typeExtended: rFm = fpa11->fpreg[Fm].fExtended; break; - + default: return 0; } } - + if (!MONADIC_INSTRUCTION(opcode)) { Fn = getFn(opcode); @@ -80,11 +80,11 @@ unsigned int ExtendedCPDO(const unsigned int opcode) case typeDouble: rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; - + case typeExtended: rFn = fpa11->fpreg[Fn].fExtended; break; - + default: return 0; } } @@ -204,13 +204,13 @@ unsigned int ExtendedCPDO(const unsigned int opcode) case NRM_CODE: break; - + default: { nRc = 0; } } - + if (0 != nRc) fpa11->fType[Fd] = typeExtended; return nRc; } diff --git a/target-arm/nwfpe/fpa11.c b/target-arm/nwfpe/fpa11.c index 7fe6ed3f9..6b435002e 100644 --- a/target-arm/nwfpe/fpa11.c +++ b/target-arm/nwfpe/fpa11.c @@ -43,16 +43,16 @@ void resetFPA11(void) { int i; FPA11 *fpa11 = GET_FPA11(); - + /* initialize the register type array */ for (i=0;i<=7;i++) { fpa11->fType[i] = typeNone; } - + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ fpa11->fpsr = FP_EMULATOR | BIT_AC; - + /* FPCR: set SB, AB and DA bits, clear all others */ #if MAINTAIN_FPCR fpa11->fpcr = MASK_RESET; @@ -66,36 +66,36 @@ void SetRoundingMode(const unsigned int opcode) #if MAINTAIN_FPCR fpa11->fpcr &= ~MASK_ROUNDING_MODE; -#endif +#endif switch (opcode & MASK_ROUNDING_MODE) { default: case ROUND_TO_NEAREST: rounding_mode = float_round_nearest_even; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_NEAREST; -#endif +#endif break; - + case ROUND_TO_PLUS_INFINITY: rounding_mode = float_round_up; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; -#endif +#endif break; - + case ROUND_TO_MINUS_INFINITY: rounding_mode = float_round_down; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; -#endif +#endif break; - + case ROUND_TO_ZERO: rounding_mode = float_round_to_zero; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_TO_ZERO; -#endif +#endif break; } set_float_rounding_mode(rounding_mode, &fpa11->fp_status); @@ -107,30 +107,30 @@ void SetRoundingPrecision(const unsigned int opcode) FPA11 *fpa11 = GET_FPA11(); #if MAINTAIN_FPCR fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; -#endif +#endif switch (opcode & MASK_ROUNDING_PRECISION) { case ROUND_SINGLE: rounding_precision = 32; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_SINGLE; -#endif +#endif break; - + case ROUND_DOUBLE: rounding_precision = 64; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_DOUBLE; -#endif +#endif break; - + case ROUND_EXTENDED: rounding_precision = 80; -#if MAINTAIN_FPCR +#if MAINTAIN_FPCR fpa11->fpcr |= ROUND_EXTENDED; -#endif +#endif break; - + default: rounding_precision = 80; } set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status); @@ -147,7 +147,7 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) qemufpa=qfpa; user_registers=qregs; - + #if 0 fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", opcode, qregs[REG_PC]); @@ -222,14 +222,14 @@ unsigned int EmulateAll1(unsigned int opcode) } } break; - + case 0xe: if (opcode & 0x10) return EmulateCPDO(opcode); else return EmulateCPRT(opcode); break; - + default: return 0; } } diff --git a/target-arm/nwfpe/fpa11.h b/target-arm/nwfpe/fpa11.h index f1fdfbdda..4fc0b3b88 100644 --- a/target-arm/nwfpe/fpa11.h +++ b/target-arm/nwfpe/fpa11.h @@ -1,7 +1,7 @@ /* NetWinder Floating Point Emulator (c) Rebel.com, 1998-1999 - + Direct questions, comments to Scott Bambrough This program is free software; you can redistribute it and/or modify diff --git a/target-arm/nwfpe/fpa11_cpdo.c b/target-arm/nwfpe/fpa11_cpdo.c index 3d5cc9310..777963728 100644 --- a/target-arm/nwfpe/fpa11_cpdo.c +++ b/target-arm/nwfpe/fpa11_cpdo.c @@ -30,16 +30,16 @@ unsigned int EmulateCPDO(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); unsigned int Fd, nType, nDest, nRc = 1; - + //printk("EmulateCPDO(0x%08x)\n",opcode); /* Get the destination size. If not valid let Linux perform an invalid instruction trap. */ nDest = getDestinationSize(opcode); if (typeNone == nDest) return 0; - + SetRoundingMode(opcode); - + /* Compare the size of the operands in Fn and Fm. Choose the largest size and perform operations in that size, in order to make use of all the precision of the operands. @@ -49,7 +49,7 @@ unsigned int EmulateCPDO(const unsigned int opcode) nType = nDest; else nType = fpa11->fType[getFn(opcode)]; - + if (!CONSTANT_FM(opcode)) { register unsigned int Fm = getFm(opcode); @@ -86,7 +86,7 @@ unsigned int EmulateCPDO(const unsigned int opcode) floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); } break; - + case typeDouble: { if (typeSingle == nType) @@ -97,7 +97,7 @@ unsigned int EmulateCPDO(const unsigned int opcode) floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); } break; - + case typeExtended: { if (typeSingle == nType) @@ -109,9 +109,9 @@ unsigned int EmulateCPDO(const unsigned int opcode) } break; } - + fpa11->fType[Fd] = nDest; } - + return nRc; } diff --git a/target-arm/nwfpe/fpa11_cpdt.c b/target-arm/nwfpe/fpa11_cpdt.c index e1a67c71c..cae2922e0 100644 --- a/target-arm/nwfpe/fpa11_cpdt.c +++ b/target-arm/nwfpe/fpa11_cpdt.c @@ -52,7 +52,7 @@ void loadDouble(const unsigned int Fn,const unsigned int *pMem) p[0] = tget32(addr + 4); p[1] = tget32(addr); /* sign & exponent */ #endif -} +} static inline void loadExtended(const unsigned int Fn,const unsigned int *pMem) @@ -65,7 +65,7 @@ void loadExtended(const unsigned int Fn,const unsigned int *pMem) p[0] = tget32(addr); /* sign & exponent */ p[1] = tget32(addr + 8); /* ls bits */ p[2] = tget32(addr + 4); /* ms bits */ -} +} static inline void loadMultiple(const unsigned int Fn,const unsigned int *pMem) @@ -78,7 +78,7 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) p = (unsigned int*)&(fpa11->fpreg[Fn]); x = tget32(addr); fpa11->fType[Fn] = (x >> 14) & 0x00000003; - + switch (fpa11->fType[Fn]) { case typeSingle: @@ -89,12 +89,12 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) p[2] = 0; /* empty */ } break; - + case typeExtended: { p[1] = tget32(addr + 8); p[2] = tget32(addr + 4); /* msw */ - p[0] = (x & 0x80003fff); + p[0] = (x & 0x80003fff); } break; } @@ -107,7 +107,7 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem) FPA11 *fpa11 = GET_FPA11(); float32 val; register unsigned int *p = (unsigned int*)&val; - + switch (fpa11->fType[Fn]) { case typeDouble: @@ -120,9 +120,9 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fSingle; } - + tput32(addr, p[0]); -} +} static inline void storeDouble(const unsigned int Fn,unsigned int *pMem) @@ -151,7 +151,7 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem) tput32(addr, p[1]); /* msw */ tput32(addr + 4, p[0]); /* lsw */ #endif -} +} static inline void storeExtended(const unsigned int Fn,unsigned int *pMem) @@ -160,7 +160,7 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem) FPA11 *fpa11 = GET_FPA11(); floatx80 val; register unsigned int *p = (unsigned int*)&val; - + switch (fpa11->fType[Fn]) { case typeSingle: @@ -173,11 +173,11 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fExtended; } - + tput32(addr, p[0]); /* sign & exp */ tput32(addr + 8, p[1]); tput32(addr + 4, p[2]); /* msw */ -} +} static inline void storeMultiple(const unsigned int Fn,unsigned int *pMem) @@ -185,10 +185,10 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem) target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); register unsigned int nType, *p; - + p = (unsigned int*)&(fpa11->fpreg[Fn]); nType = fpa11->fType[Fn]; - + switch (nType) { case typeSingle: @@ -199,7 +199,7 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem) tput32(addr, nType << 14); } break; - + case typeExtended: { tput32(addr + 4, p[2]); /* msw */ @@ -239,7 +239,7 @@ unsigned int PerformLDF(const unsigned int opcode) case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; default: nRc = 0; } - + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return nRc; } @@ -248,10 +248,10 @@ unsigned int PerformSTF(const unsigned int opcode) { unsigned int *pBase, *pAddress, *pFinal, nRc = 1, write_back = WRITE_BACK(opcode); - + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); SetRoundingMode(ROUND_TO_NEAREST); - + pBase = (unsigned int*)readRegister(getRn(opcode)); if (REG_PC == getRn(opcode)) { @@ -274,7 +274,7 @@ unsigned int PerformSTF(const unsigned int opcode) case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; default: nRc = 0; } - + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); return nRc; } @@ -315,14 +315,14 @@ unsigned int PerformSFM(const unsigned int opcode) { unsigned int i, Fd, *pBase, *pAddress, *pFinal, write_back = WRITE_BACK(opcode); - + pBase = (unsigned int*)readRegister(getRn(opcode)); if (REG_PC == getRn(opcode)) { pBase += 2; write_back = 0; } - + pFinal = pBase; if (BIT_UP_SET(opcode)) pFinal += getOffset(opcode); @@ -349,7 +349,7 @@ unsigned int EmulateCPDT(const unsigned int opcode) unsigned int nRc = 0; //printk("EmulateCPDT(0x%08x)\n",opcode); - + if (LDF_OP(opcode)) { nRc = PerformLDF(opcode); @@ -370,7 +370,7 @@ unsigned int EmulateCPDT(const unsigned int opcode) { nRc = 0; } - + return nRc; } #endif diff --git a/target-arm/nwfpe/fpa11_cprt.c b/target-arm/nwfpe/fpa11_cprt.c index 68c4ff192..04eae8c6f 100644 --- a/target-arm/nwfpe/fpa11_cprt.c +++ b/target-arm/nwfpe/fpa11_cprt.c @@ -55,7 +55,7 @@ unsigned int EmulateCPRT(const unsigned int opcode) { case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; - + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; @@ -67,14 +67,14 @@ unsigned int EmulateCPRT(const unsigned int opcode) default: nRc = 0; } - + return nRc; } unsigned int PerformFLT(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); - + unsigned int nRc = 1; SetRoundingMode(opcode); @@ -95,7 +95,7 @@ unsigned int PerformFLT(const unsigned int opcode) int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status); } break; - + case ROUND_EXTENDED: { fpa11->fType[getFn(opcode)] = typeExtended; @@ -103,10 +103,10 @@ unsigned int PerformFLT(const unsigned int opcode) int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status); } break; - + default: nRc = 0; } - + return nRc; } @@ -115,7 +115,7 @@ unsigned int PerformFIX(const unsigned int opcode) FPA11 *fpa11 = GET_FPA11(); unsigned int nRc = 1; unsigned int Fn = getFm(opcode); - + SetRoundingMode(opcode); switch (fpa11->fType[Fn]) @@ -134,21 +134,21 @@ unsigned int PerformFIX(const unsigned int opcode) float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status)); } break; - + case typeExtended: { writeRegister(getRd(opcode), floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status)); } break; - + default: nRc = 0; } - + return nRc; } - + static unsigned int __inline__ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) { @@ -160,7 +160,7 @@ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) { flags |= CC_NEGATIVE; } - + /* test for equal condition */ if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) { @@ -172,13 +172,13 @@ PerformComparisonOperation(floatx80 Fn, floatx80 Fm) { flags |= CC_CARRY; } - + writeConditionCodes(flags); return 1; } /* This instruction sets the flags N, Z, C, V in the FPSR. */ - + static unsigned int PerformComparison(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); @@ -213,14 +213,14 @@ static unsigned int PerformComparison(const unsigned int opcode) goto unordered; rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; - + case typeExtended: //printk("extended.\n"); if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) goto unordered; rFn = fpa11->fpreg[Fn].fExtended; break; - + default: return 0; } @@ -249,14 +249,14 @@ static unsigned int PerformComparison(const unsigned int opcode) goto unordered; rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; - + case typeExtended: //printk("extended.\n"); if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) goto unordered; rFm = fpa11->fpreg[Fm].fExtended; break; - + default: return 0; } } diff --git a/target-arm/nwfpe/fpopcode.c b/target-arm/nwfpe/fpopcode.c index efee406fb..a733a1d1d 100644 --- a/target-arm/nwfpe/fpopcode.c +++ b/target-arm/nwfpe/fpopcode.c @@ -35,7 +35,7 @@ const floatx80 floatx80Constant[] = { { 0xa000000000000000ULL, 0x4001}, /* extended 5.0 */ { 0x8000000000000000ULL, 0x3ffe}, /* extended 0.5 */ { 0xa000000000000000ULL, 0x4002} /* extended 10.0 */ -}; +}; const float64 float64Constant[] = { 0x0000000000000000ULL, /* double 0.0 */ @@ -46,7 +46,7 @@ const float64 float64Constant[] = { 0x4014000000000000ULL, /* double 5.0 */ 0x3fe0000000000000ULL, /* double 0.5 */ 0x4024000000000000ULL /* double 10.0 */ -}; +}; const float32 float32Constant[] = { 0x00000000, /* single 0.0 */ @@ -57,12 +57,12 @@ const float32 float32Constant[] = { 0x40a00000, /* single 5.0 */ 0x3f000000, /* single 0.5 */ 0x41200000 /* single 10.0 */ -}; +}; unsigned int getTransferLength(const unsigned int opcode) { unsigned int nRc; - + switch (opcode & MASK_TRANSFER_LENGTH) { case 0x00000000: nRc = 1; break; /* single precision */ @@ -70,14 +70,14 @@ unsigned int getTransferLength(const unsigned int opcode) case 0x00400000: nRc = 3; break; /* extended precision */ default: nRc = 0; } - + return(nRc); } unsigned int getRegisterCount(const unsigned int opcode) { unsigned int nRc; - + switch (opcode & MASK_REGISTER_COUNT) { case 0x00000000: nRc = 4; break; @@ -86,14 +86,14 @@ unsigned int getRegisterCount(const unsigned int opcode) case 0x00408000: nRc = 3; break; default: nRc = 0; } - + return(nRc); } unsigned int getRoundingPrecision(const unsigned int opcode) { unsigned int nRc; - + switch (opcode & MASK_ROUNDING_PRECISION) { case 0x00000000: nRc = 1; break; @@ -101,14 +101,14 @@ unsigned int getRoundingPrecision(const unsigned int opcode) case 0x00080000: nRc = 3; break; default: nRc = 0; } - + return(nRc); } unsigned int getDestinationSize(const unsigned int opcode) { unsigned int nRc; - + switch (opcode & MASK_DESTINATION_SIZE) { case 0x00000000: nRc = typeSingle; break; @@ -116,7 +116,7 @@ unsigned int getDestinationSize(const unsigned int opcode) case 0x00080000: nRc = typeExtended; break; default: nRc = typeNone; } - + return(nRc); } diff --git a/target-arm/nwfpe/fpopcode.h b/target-arm/nwfpe/fpopcode.h index e16e47af6..6c51067b6 100644 --- a/target-arm/nwfpe/fpopcode.h +++ b/target-arm/nwfpe/fpopcode.h @@ -35,7 +35,7 @@ ARM Floating Point Instruction Classes CPDT data transfer instructions LDF, STF, LFM, SFM - + CPDO dyadic arithmetic instructions ADF, MUF, SUF, RSF, DVF, RDF, POW, RPW, RMF, FML, FDV, FRD, POL @@ -43,7 +43,7 @@ CPDO dyadic arithmetic instructions CPDO monadic arithmetic instructions MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN, URD, NRM - + CPRT joint arithmetic/data transfer instructions FIX (arithmetic followed by load/store) FLT (load/store followed by arithmetic) @@ -57,7 +57,7 @@ U up/down bit: 0 = stack grows down, 1 = stack grows up W write back bit: 1 = update base register (Rn) L load/store bit: 0 = store, 1 = load Rn base register -Rd destination/source register +Rd destination/source register Fd floating point destination register Fn floating point source register Fm floating point source register or floating point constant diff --git a/target-arm/nwfpe/single_cpdo.c b/target-arm/nwfpe/single_cpdo.c index 4f2ca6ade..1482f4712 100644 --- a/target-arm/nwfpe/single_cpdo.c +++ b/target-arm/nwfpe/single_cpdo.c @@ -47,13 +47,13 @@ unsigned int SingleCPDO(const unsigned int opcode) rFm = getSingleConstant(Fm); } else - { + { switch (fpa11->fType[Fm]) { case typeSingle: rFm = fpa11->fpreg[Fm].fSingle; break; - + default: return 0; } } @@ -186,7 +186,7 @@ unsigned int SingleCPDO(const unsigned int opcode) case NRM_CODE: break; - + default: { nRc = 0; diff --git a/target-arm/op.c b/target-arm/op.c index b28217318..e8a536c1a 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -774,7 +774,7 @@ void OPPROTO op_addl_T0_T1_saturate(void) } else T0 = res; - + FORCE_RET(); } @@ -792,7 +792,7 @@ void OPPROTO op_subl_T0_T1_saturate(void) } else T0 = res; - + FORCE_RET(); } @@ -1127,7 +1127,7 @@ void OPPROTO op_vfp_msr(void) void OPPROTO op_vfp_mrrd(void) { CPU_DoubleU u; - + u.d = FT0d; T0 = u.l.lower; T1 = u.l.upper; @@ -1136,7 +1136,7 @@ void OPPROTO op_vfp_mrrd(void) void OPPROTO op_vfp_mdrr(void) { CPU_DoubleU u; - + u.l.lower = T0; u.l.upper = T1; FT0d = u.d; diff --git a/target-arm/translate.c b/target-arm/translate.c index a6647d4f7..bb01f2f34 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -116,7 +116,7 @@ const uint8_t table_logic_cc[16] = { 1, /* bic */ 1, /* mvn */ }; - + static GenOpFunc1 *gen_shift_T1_im[4] = { gen_op_shll_T1_im, gen_op_shrl_T1_im, @@ -390,7 +390,7 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, int extra) { int val, rm; - + if (insn & (1 << 22)) { /* immediate */ val = (insn & 0xf) | ((insn >> 4) & 0xf0); @@ -1784,7 +1784,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) delta_m = 0; delta_d = 0; bank_mask = 0; - + if (veclen > 0) { if (dp) bank_mask = 0xc; @@ -2205,10 +2205,10 @@ static void gen_exception_return(DisasContext *s) static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; - + insn = ldl_code(s->pc); s->pc += 4; - + cond = insn >> 28; if (cond == 0xf){ /* Unconditional instructions. */ @@ -2403,7 +2403,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) (insn & 0x00000090) != 0x90) || ((insn & 0x0e000000) == (1 << 25))) { int set_cc, logic_cc, shiftop; - + op1 = (insn >> 21) & 0xf; set_cc = (insn >> 20) & 1; logic_cc = table_logic_cc[op1] & set_cc; @@ -2626,7 +2626,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } else { /* SWP instruction */ rm = (insn) & 0xf; - + gen_movl_T0_reg(s, rm); gen_movl_T1_reg(s, rn); if (insn & (1 << 22)) { @@ -2799,7 +2799,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } rn = (insn >> 16) & 0xf; gen_movl_T1_reg(s, rn); - + /* compute total size */ loaded_base = 0; n = 0; @@ -2897,7 +2897,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) case 0xb: { int32_t offset; - + /* branch (and link) */ val = (int32_t)s->pc; if (insn & (1 << 24)) { @@ -3500,7 +3500,7 @@ static void disas_thumb_insn(DisasContext *s) val = (uint32_t)s->pc + 2; gen_op_movl_T1_im(val | 1); gen_movl_reg_T1(s, 14); - + val += offset << 1; if (insn & (1 << 12)) { /* bl */ @@ -3532,10 +3532,10 @@ static inline int gen_intermediate_code_internal(CPUState *env, int j, lj; target_ulong pc_start; uint32_t next_page_start; - + /* generate intermediate code */ pc_start = tb->pc; - + dc->tb = tb; gen_opc_ptr = gen_opc_buf; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 6cf2c487b..9ae50ee6d 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -476,7 +476,7 @@ typedef struct CPUX86State { int i32; int64_t i64; } fp_convert; - + float_status sse_status; uint32_t mxcsr; XMMReg xmm_regs[CPU_NB_REGS]; @@ -504,7 +504,7 @@ typedef struct CPUX86State { uint32_t saved_esp; int native_fp_regs; /* if true, the FPU state is in the native CPU regs */ #endif - + /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; @@ -531,7 +531,7 @@ typedef struct CPUX86State { uint32_t cpuid_model[12]; uint32_t cpuid_ext2_features; uint32_t cpuid_apic_id; - + #ifdef USE_KQEMU int kqemu_enabled; int last_io_time; @@ -558,7 +558,7 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, { SegmentCache *sc; unsigned int new_hflags; - + sc = &env->segs[seg_reg]; sc->selector = selector; sc->base = base; diff --git a/target-i386/exec.h b/target-i386/exec.h index a3ab9b439..59c064923 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -443,7 +443,7 @@ static inline CPU86_LDouble helper_fldt(target_ulong ptr) static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) { CPU86_LDoubleU temp; - + temp.d = f; stq(ptr, temp.l.lower); stw(ptr + 8, temp.l.upper); diff --git a/target-i386/helper.c b/target-i386/helper.c index 447f4d891..43a8b9b57 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -91,7 +91,7 @@ const CPU86_LDouble f15rk[7] = 1.44269504088896340739L, /*l2e*/ 3.32192809488736234781L, /*l2t*/ }; - + /* thread support */ spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; @@ -126,7 +126,7 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, *e2_ptr = ldl_kernel(ptr + 4); return 0; } - + static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) { unsigned int limit; @@ -160,7 +160,7 @@ static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, uint32_t *esp_ptr, int dpl) { int type, index, shift; - + #if 0 { int i; @@ -325,7 +325,7 @@ static void switch_tss(int tss_selector, new_segs[R_GS] = 0; new_trap = 0; } - + /* NOTE: we must avoid memory exceptions during the task switch, so we make dummy accesses before */ /* XXX: it can still fail in some cases, so a bigger hack is @@ -335,7 +335,7 @@ static void switch_tss(int tss_selector, v2 = ldub_kernel(env->tr.base + old_tss_limit_max); stb_kernel(env->tr.base, v1); stb_kernel(env->tr.base + old_tss_limit_max, v2); - + /* clear busy bit (it is restartable) */ if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { target_ulong ptr; @@ -348,7 +348,7 @@ static void switch_tss(int tss_selector, old_eflags = compute_eflags(); if (source == SWITCH_TSS_IRET) old_eflags &= ~NT_MASK; - + /* save the current state in the old TSS */ if (type & 8) { /* 32 bit */ @@ -379,7 +379,7 @@ static void switch_tss(int tss_selector, for(i = 0; i < 4; i++) stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector); } - + /* now if an exception occurs, it will occurs in the next task context */ @@ -406,11 +406,11 @@ static void switch_tss(int tss_selector, env->tr.base = tss_base; env->tr.limit = tss_limit; env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; - + if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { cpu_x86_update_cr3(env, new_cr3); } - + /* load all registers without an exception, then reload them with possible exception */ env->eip = new_eip; @@ -440,7 +440,7 @@ static void switch_tss(int tss_selector, for(i = 0; i < 6; i++) cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); } - + env->ldt.selector = new_ldt & ~4; env->ldt.base = 0; env->ldt.limit = 0; @@ -464,7 +464,7 @@ static void switch_tss(int tss_selector, raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); load_seg_cache_raw_dt(&env->ldt, e1, e2); } - + /* load the segments */ if (!(new_eflags & VM_MASK)) { tss_load_seg(R_CS, new_segs[R_CS]); @@ -474,7 +474,7 @@ static void switch_tss(int tss_selector, tss_load_seg(R_FS, new_segs[R_FS]); tss_load_seg(R_GS, new_segs[R_GS]); } - + /* check that EIP is in the CS segment limits */ if (new_eip > env->segs[R_CS].limit) { /* XXX: different exception if CALL ? */ @@ -486,7 +486,7 @@ static void switch_tss(int tss_selector, static inline void check_io(int addr, int size) { int io_offset, val, mask; - + /* TSS must be a valid 32 bit one */ if (!(env->tr.flags & DESC_P_MASK) || ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || @@ -760,7 +760,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, PUSHW(ssp, esp, sp_mask, error_code); } } - + if (new_stack) { if (env->eflags & VM_MASK) { cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); @@ -806,7 +806,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, static inline target_ulong get_rsp_from_tss(int level) { int index; - + #if 0 printf("TR: base=" TARGET_FMT_lx " limit=%x\n", env->tr.base, env->tr.limit); @@ -926,7 +926,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, if (has_error_code) { PUSHQ(esp, error_code); } - + if (new_stack) { ss = 0 | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); @@ -963,7 +963,7 @@ void helper_syscall(int next_eip_addend) ECX = env->eip + next_eip_addend; env->regs[11] = compute_eflags(); - + code64 = env->hflags & HF_CS64_MASK; cpu_x86_set_cpl(env, 0); @@ -986,7 +986,7 @@ void helper_syscall(int next_eip_addend) #endif { ECX = (uint32_t)(env->eip + next_eip_addend); - + cpu_x86_set_cpl(env, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, @@ -1096,7 +1096,7 @@ static void do_interrupt_real(int intno, int is_int, int error_code, PUSHW(ssp, esp, 0xffff, compute_eflags()); PUSHW(ssp, esp, 0xffff, old_cs); PUSHW(ssp, esp, 0xffff, old_eip); - + /* update processor state */ ESP = (ESP & ~0xffff) | (esp & 0xffff); env->eip = offset; @@ -1117,7 +1117,7 @@ void do_interrupt_user(int intno, int is_int, int error_code, dt = &env->idt; ptr = dt->base + (intno * 8); e2 = ldl_kernel(ptr + 4); - + dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ @@ -1134,7 +1134,7 @@ void do_interrupt_user(int intno, int is_int, int error_code, /* * Begin execution of an interruption. is_int is TRUE if coming from * the int instruction. next_eip is the EIP value AFTER the interrupt - * instruction. It is only relevant if is_int is TRUE. + * instruction. It is only relevant if is_int is TRUE. */ void do_interrupt(int intno, int is_int, int error_code, target_ulong next_eip, int is_hw) @@ -1222,7 +1222,7 @@ int check_exception(int intno, int *error_code) * Signal an interruption. It is executed in the main CPU loop. * is_int is TRUE if coming from the int instruction. next_eip is the * EIP value AFTER the interrupt instruction. It is only relevant if - * is_int is TRUE. + * is_int is TRUE. */ void raise_interrupt(int intno, int is_int, int error_code, int next_eip_addend) @@ -1296,7 +1296,7 @@ void do_smm_enter(void) cpu_smm_update(env); sm_state = env->smbase + 0x8000; - + #ifdef TARGET_X86_64 for(i = 0; i < 6; i++) { dt = &env->segs[i]; @@ -1314,7 +1314,7 @@ void do_smm_enter(void) stq_phys(sm_state + 0x7e78, env->ldt.base); stl_phys(sm_state + 0x7e74, env->ldt.limit); stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); - + stq_phys(sm_state + 0x7e88, env->idt.base); stl_phys(sm_state + 0x7e84, env->idt.limit); @@ -1322,7 +1322,7 @@ void do_smm_enter(void) stq_phys(sm_state + 0x7e98, env->tr.base); stl_phys(sm_state + 0x7e94, env->tr.limit); stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); - + stq_phys(sm_state + 0x7ed0, env->efer); stq_phys(sm_state + 0x7ff8, EAX); @@ -1361,17 +1361,17 @@ void do_smm_enter(void) stl_phys(sm_state + 0x7fd0, EAX); stl_phys(sm_state + 0x7fcc, env->dr[6]); stl_phys(sm_state + 0x7fc8, env->dr[7]); - + stl_phys(sm_state + 0x7fc4, env->tr.selector); stl_phys(sm_state + 0x7f64, env->tr.base); stl_phys(sm_state + 0x7f60, env->tr.limit); stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); - + stl_phys(sm_state + 0x7fc0, env->ldt.selector); stl_phys(sm_state + 0x7f80, env->ldt.base); stl_phys(sm_state + 0x7f7c, env->ldt.limit); stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); - + stl_phys(sm_state + 0x7f74, env->gdt.base); stl_phys(sm_state + 0x7f70, env->gdt.limit); @@ -1409,7 +1409,7 @@ void do_smm_enter(void) cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0); cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0); cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); - + cpu_x86_update_cr0(env, env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); cpu_x86_update_cr4(env, 0); @@ -1447,7 +1447,7 @@ void helper_rsm(void) env->ldt.base = ldq_phys(sm_state + 0x7e78); env->ldt.limit = ldl_phys(sm_state + 0x7e74); env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8; - + env->idt.base = ldq_phys(sm_state + 0x7e88); env->idt.limit = ldl_phys(sm_state + 0x7e84); @@ -1455,7 +1455,7 @@ void helper_rsm(void) env->tr.base = ldq_phys(sm_state + 0x7e98); env->tr.limit = ldl_phys(sm_state + 0x7e94); env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8; - + EAX = ldq_phys(sm_state + 0x7ff8); ECX = ldq_phys(sm_state + 0x7ff0); EDX = ldq_phys(sm_state + 0x7fe8); @@ -1496,17 +1496,17 @@ void helper_rsm(void) EAX = ldl_phys(sm_state + 0x7fd0); env->dr[6] = ldl_phys(sm_state + 0x7fcc); env->dr[7] = ldl_phys(sm_state + 0x7fc8); - + env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff; env->tr.base = ldl_phys(sm_state + 0x7f64); env->tr.limit = ldl_phys(sm_state + 0x7f60); env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8; - + env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff; env->ldt.base = ldl_phys(sm_state + 0x7f80); env->ldt.limit = ldl_phys(sm_state + 0x7f7c); env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8; - + env->gdt.base = ldl_phys(sm_state + 0x7f74); env->gdt.limit = ldl_phys(sm_state + 0x7f70); @@ -1564,7 +1564,7 @@ void helper_divl_EAX_T0(void) { unsigned int den, r; uint64_t num, q; - + num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); den = T0; if (den == 0) { @@ -1586,7 +1586,7 @@ void helper_idivl_EAX_T0(void) { int den, r; int64_t num, q; - + num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); den = T0; if (den == 0) { @@ -1632,7 +1632,7 @@ void helper_cpuid(void) { uint32_t index; index = (uint32_t)EAX; - + /* test if maximum index reached */ if (index & 0x80000000) { if (index > env->cpuid_xlevel) @@ -1641,7 +1641,7 @@ void helper_cpuid(void) if (index > env->cpuid_level) index = env->cpuid_level; } - + switch(index) { case 0: EAX = env->cpuid_level; @@ -1783,7 +1783,7 @@ void helper_lldt_T0(void) uint32_t e1, e2; int index, entry_limit; target_ulong ptr; - + selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) { /* XXX: NULL selector case: invalid LDT */ @@ -1798,7 +1798,7 @@ void helper_lldt_T0(void) if (env->hflags & HF_LMA_MASK) entry_limit = 15; else -#endif +#endif entry_limit = 7; if ((index + entry_limit) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); @@ -1831,7 +1831,7 @@ void helper_ltr_T0(void) uint32_t e1, e2; int index, type, entry_limit; target_ulong ptr; - + selector = T0 & 0xffff; if ((selector & 0xfffc) == 0) { /* NULL selector case: invalid TR */ @@ -1847,7 +1847,7 @@ void helper_ltr_T0(void) if (env->hflags & HF_LMA_MASK) entry_limit = 15; else -#endif +#endif entry_limit = 7; if ((index + entry_limit) > dt->limit) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); @@ -1901,7 +1901,7 @@ void load_seg(int seg_reg, int selector) raise_exception_err(EXCP0D_GPF, 0); cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); } else { - + if (selector & 0x4) dt = &env->ldt; else @@ -1912,7 +1912,7 @@ void load_seg(int seg_reg, int selector) ptr = dt->base + index; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); - + if (!(e2 & DESC_S_MASK)) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); rpl = selector & 3; @@ -1927,7 +1927,7 @@ void load_seg(int seg_reg, int selector) /* must be readable segment */ if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); - + if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { /* if not conforming code, test rights */ if (dpl < cpl || dpl < rpl) @@ -1965,7 +1965,7 @@ void helper_ljmp_protected_T0_T1(int next_eip_addend) int new_cs, gate_cs, type; uint32_t e1, e2, cpl, dpl, rpl, limit; target_ulong new_eip, next_eip; - + new_cs = T0; new_eip = T1; if ((new_cs & 0xfffc) == 0) @@ -2084,7 +2084,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; uint32_t val, limit, old_sp_mask; target_ulong ssp, old_ssp, next_eip, new_eip; - + new_cs = T0; new_eip = T1; next_eip = env->eip + next_eip_addend; @@ -2151,7 +2151,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); PUSHW(ssp, sp, sp_mask, next_eip); } - + limit = get_seg_limit(e1, e2); if (new_eip > limit) raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); @@ -2228,12 +2228,12 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); if (!(ss_e2 & DESC_P_MASK)) raise_exception_err(EXCP0A_TSS, ss & 0xfffc); - + // push_size = ((param_count * 2) + 8) << shift; old_sp_mask = get_sp_mask(env->segs[R_SS].flags); old_ssp = env->segs[R_SS].base; - + sp_mask = get_sp_mask(ss_e2); ssp = get_seg_base(ss_e1, ss_e2); if (shift) { @@ -2360,7 +2360,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) uint32_t e1, e2, ss_e1, ss_e2; int cpl, dpl, rpl, eflags_mask, iopl; target_ulong ssp, sp, new_eip, new_esp, sp_mask; - + #ifdef TARGET_X86_64 if (shift == 2) sp_mask = -1; @@ -2425,7 +2425,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) } if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); - + sp += addend; if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || ((env->hflags & HF_CS64_MASK) && !is_iret))) { @@ -2539,7 +2539,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) POPL(ssp, sp, sp_mask, new_ds); POPL(ssp, sp, sp_mask, new_fs); POPL(ssp, sp, sp_mask, new_gs); - + /* modify processor state */ load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); @@ -2559,7 +2559,7 @@ void helper_iret_protected(int shift, int next_eip) { int tss_selector, type; uint32_t e1, e2; - + /* specific case for TSS */ if (env->eflags & NT_MASK) { #ifdef TARGET_X86_64 @@ -3080,7 +3080,7 @@ void helper_f2xm1(void) void helper_fyl2x(void) { CPU86_LDouble fptemp; - + fptemp = ST0; if (fptemp>0.0){ fptemp = log(fptemp)/log(2.0); /* log2(ST) */ @@ -3490,7 +3490,7 @@ void helper_fxsave(target_ulong ptr, int data64) helper_fstt(tmp, addr); addr += 16; } - + if (env->cr[4] & CR4_OSFXSR_MASK) { /* XXX: finish it */ stl(ptr + 0x18, env->mxcsr); /* mxcsr */ diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 8b61cf874..715b289b3 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -75,7 +75,7 @@ CPUX86State *cpu_x86_init(void) ldt.seg_not_present = 0; ldt.useable = 1; modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - + asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); } #endif @@ -173,19 +173,19 @@ void cpu_reset(CPUX86State *env) env->ldt.flags = DESC_P_MASK; env->tr.limit = 0xffff; env->tr.flags = DESC_P_MASK; - + cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0); cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, 0); cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, 0); cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, 0); cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, 0); cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0); - + env->eip = 0xfff0; env->regs[R_EDX] = 0x600; /* indicate P6 processor */ - + env->eflags = 0x2; - + /* FPU init */ for(i = 0;i < 8; i++) env->fptags[i] = 1; @@ -516,7 +516,7 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) } #endif env->cr[0] = new_cr0 | CR0_ET_MASK; - + /* update PE flag in hidden flags */ pe_state = (env->cr[0] & CR0_PE_MASK); env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); @@ -603,13 +603,13 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int error_code, is_dirty, prot, page_size, ret, is_write; unsigned long paddr, page_offset; target_ulong vaddr, virt_addr; - + #if defined(DEBUG_MMU) printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", addr, is_write1, is_user, env->eip); #endif is_write = is_write1 & 1; - + if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr; virt_addr = addr & TARGET_PAGE_MASK; @@ -635,7 +635,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, env->exception_index = EXCP0D_GPF; return 1; } - + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; pml4e = ldq_phys(pml4e_addr); @@ -794,7 +794,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, pde |= PG_DIRTY_MASK; stl_phys_notdirty(pde_addr, pde); } - + pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ ptep = pte; virt_addr = addr & ~(page_size - 1); @@ -859,7 +859,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); paddr = (pte & TARGET_PAGE_MASK) + page_offset; vaddr = virt_addr + page_offset; - + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); return ret; do_fault_protect: @@ -897,13 +897,13 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) sext = (int64_t)addr >> 47; if (sext != 0 && sext != -1) return -1; - + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; pml4e = ldl_phys(pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) return -1; - + pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; pdpe = ldl_phys(pdpe_addr); @@ -987,7 +987,7 @@ void restore_native_fp_state(CPUState *env) { int fptag, i, j; struct fpstate fp1, *fp = &fp1; - + fp->fpuc = env->fpuc; fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; fptag = 0; diff --git a/target-i386/op.c b/target-i386/op.c index a790aebb1..9b4263ca7 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -1149,7 +1149,7 @@ void OPPROTO op_movl_seg_T0_vm(void) { int selector; SegmentCache *sc; - + selector = T0 & 0xffff; /* env->segs[] access */ sc = (SegmentCache *)((char *)env + PARAM1); @@ -1193,14 +1193,14 @@ void OPPROTO op_arpl(void) } FORCE_RET(); } - + void OPPROTO op_arpl_update(void) { int eflags; eflags = cc_table[CC_OP].compute_all(); CC_SRC = (eflags & ~CC_Z) | T1; } - + /* T0: segment, T1:eip */ void OPPROTO op_ljmp_protected_T0_T1(void) { @@ -1591,23 +1591,23 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, - + [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb }, [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw }, [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl }, - + [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, - + [CC_OP_INCB] = { compute_all_incb, compute_c_incl }, [CC_OP_INCW] = { compute_all_incw, compute_c_incl }, [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, - + [CC_OP_DECB] = { compute_all_decb, compute_c_incl }, [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, - + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, @@ -1624,11 +1624,11 @@ CCTable cc_table[CC_OP_NB] = { [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq }, [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq }, - + [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq }, - + [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq }, - + [CC_OP_INCQ] = { compute_all_incq, compute_c_incl }, [CC_OP_DECQ] = { compute_all_decq, compute_c_incl }, diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index b6ca9a3d7..82d1ec0a1 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -1213,7 +1213,7 @@ void OPPROTO glue(op_pinsrw, SUFFIX) (void) { Reg *d = (Reg *)((char *)env + PARAM1); int pos = PARAM2; - + d->W(pos) = T0; } @@ -1221,7 +1221,7 @@ void OPPROTO glue(op_pextrw, SUFFIX) (void) { Reg *s = (Reg *)((char *)env + PARAM1); int pos = PARAM2; - + T0 = s->W(pos); } diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index e2bc1cfc4..d1df07f9d 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -502,7 +502,7 @@ void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) { int count; target_long res; - + res = T0 & DATA_MASK; if (res != 0) { count = 0; diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index 8b8d26795..d68764360 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -63,7 +63,7 @@ typedef struct DisasContext { /* code output */ uint8_t *gen_code_ptr; uint8_t *gen_code_start; - + /* current block context */ target_ulong cs_base; /* base of CS segment */ int pe; /* protected mode */ @@ -155,7 +155,7 @@ static void gen_jcc(DisasContext *s, int op, gb(s, 0xe9); /* jmp */ tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start; gl(s, 0); - + tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); @@ -194,7 +194,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) base = rm; index = 0; scale = 0; - + if (base == 4) { havesib = 1; code = ldub_code(s->pc++); @@ -222,7 +222,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) s->pc += 4; break; } - + } else { switch (mod) { case 0: @@ -248,7 +248,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) static inline void parse_modrm(DisasContext *s, int modrm) { if ((modrm & 0xc0) != 0xc0) - gen_lea_modrm(s, modrm); + gen_lea_modrm(s, modrm); } static inline uint32_t insn_get(DisasContext *s, int ot) @@ -351,7 +351,7 @@ static int disas_insn(DisasContext *s) /* extended op code */ b = ldub_code(s->pc++) | 0x100; goto reswitch; - + /**************************/ /* arith & logic */ case 0x00 ... 0x05: @@ -370,7 +370,7 @@ static int disas_insn(DisasContext *s) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - + switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub_code(s->pc++); @@ -396,7 +396,7 @@ static int disas_insn(DisasContext *s) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - + modrm = ldub_code(s->pc++); parse_modrm(s, modrm); @@ -506,7 +506,7 @@ static int disas_insn(DisasContext *s) ot = dflag ? OT_LONG : OT_WORD; insn_get(s, ot); break; - + case 0x98: /* CWDE/CBW */ break; case 0x99: /* CDQ/CWD */ @@ -527,7 +527,7 @@ static int disas_insn(DisasContext *s) case 0x84: /* test Ev, Gv */ case 0x85: - + case 0x1c0: case 0x1c1: /* xadd Ev, Gv */ @@ -583,7 +583,7 @@ static int disas_insn(DisasContext *s) goto illegal_op; parse_modrm(s, modrm); break; - + /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ @@ -850,7 +850,7 @@ static int disas_insn(DisasContext *s) goto illegal_op; parse_modrm(s, modrm); break; - + case 0xa0: /* mov EAX, Ov */ case 0xa1: case 0xa2: /* mov Ov, EAX */ @@ -888,14 +888,14 @@ static int disas_insn(DisasContext *s) parse_modrm(s, modrm); ldub_code(s->pc++); break; - + /************************/ /* string ops */ case 0xa4: /* movsS */ case 0xa5: break; - + case 0xaa: /* stosS */ case 0xab: break; @@ -955,7 +955,7 @@ static int disas_insn(DisasContext *s) case 0xc3: /* ret */ gb(s, CPU_SEG); - if (!s->dflag) + if (!s->dflag) gb(s, 0x66); /* d16 */ gb(s, 0x8f); /* pop addr */ gb(s, 0x05); @@ -1244,7 +1244,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, break; } } - + #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); @@ -1304,7 +1304,7 @@ int cpu_restore_state_copy(TranslationBlock *tb, return ret; /* restore all the CPU state from the CPU context from the signal. The FPU context stays in the host CPU. */ - + env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX]; env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX]; env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX]; diff --git a/target-i386/translate.c b/target-i386/translate.c index 946a43097..35ba6319c 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -878,7 +878,7 @@ static GenOpFunc1 *gen_op_jnz_ecx[3] = { gen_op_jnz_ecxl, X86_64_ONLY(gen_op_jnz_ecxq), }; - + static GenOpFunc1 *gen_op_jz_ecx[3] = { gen_op_jz_ecxw, gen_op_jz_ecxl, @@ -1318,7 +1318,7 @@ static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { static void gen_op(DisasContext *s1, int op, int ot, int d) { GenOpFunc *gen_update_cc; - + if (d != OR_TMP0) { gen_op_mov_TN_reg[ot][0][d](); } else { @@ -1408,7 +1408,7 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) /* for zero counts, flags are not updated, so must do it dynamically */ if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); - + if (d != OR_TMP0) gen_op_shift_T0_T1_cc[ot][op](); else @@ -1448,7 +1448,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ base = rm; index = 0; scale = 0; - + if (base == 4) { havesib = 1; code = ldub_code(s->pc++); @@ -1480,7 +1480,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ s->pc += 4; break; } - + if (base >= 0) { /* for correct popl handling with esp */ if (base == 4 && s->popl_esp_hack) @@ -1627,12 +1627,12 @@ static void gen_nop_modrm(DisasContext *s, int modrm) if (s->aflag) { base = rm; - + if (base == 4) { code = ldub_code(s->pc++); base = (code & 7); } - + switch (mod) { case 0: if (base == 5) { @@ -1787,7 +1787,7 @@ static inline void gen_jcc(DisasContext *s, int b, inv = b & 1; jcc_op = (b >> 1) & 7; - + if (s->jmp_opt) { switch(s->cc_op) { /* we optimize the cmp/jcc case */ @@ -1797,7 +1797,7 @@ static inline void gen_jcc(DisasContext *s, int b, case CC_OP_SUBQ: func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; break; - + /* some jumps are easy to compute */ case CC_OP_ADDB: case CC_OP_ADDW: @@ -1864,7 +1864,7 @@ static inline void gen_jcc(DisasContext *s, int b, gen_setcc_slow[jcc_op](); func = gen_op_jnz_T0_label; } - + if (inv) { tmp = val; val = next_eip; @@ -1922,7 +1922,7 @@ static void gen_setcc(DisasContext *s, int b) if (!func) goto slow_jcc; break; - + /* some jumps are easy to compute */ case CC_OP_ADDB: case CC_OP_ADDW: @@ -2094,7 +2094,7 @@ static void gen_push_T1(DisasContext *s) gen_op_addl_A0_SS(); } gen_op_st_T1_A0[s->dflag + 1 + s->mem_index](); - + if (s->ss32 && !s->addseg) gen_op_movl_ESP_A0(); else @@ -2196,7 +2196,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) if (CODE64(s)) { ot = s->dflag ? OT_QUAD : OT_WORD; opsize = 1 << ot; - + gen_op_movl_A0_ESP(); gen_op_addq_A0_im(-opsize); gen_op_movl_T1_A0(); @@ -2215,7 +2215,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) { ot = s->dflag + OT_WORD; opsize = 2 << s->dflag; - + gen_op_movl_A0_ESP(); gen_op_addl_A0_im(-opsize); if (!s->ss32) @@ -2309,7 +2309,7 @@ static void gen_jmp(DisasContext *s, target_ulong eip) static void gen_movtl_T0_im(target_ulong val) { -#ifdef TARGET_X86_64 +#ifdef TARGET_X86_64 if ((int32_t)val == val) { gen_op_movl_T0_im(val); } else { @@ -2322,7 +2322,7 @@ static void gen_movtl_T0_im(target_ulong val) static void gen_movtl_T1_im(target_ulong val) { -#ifdef TARGET_X86_64 +#ifdef TARGET_X86_64 if ((int32_t)val == val) { gen_op_movl_T1_im(val); } else { @@ -2522,7 +2522,7 @@ static GenOpFunc1 *sse_op_table3[4 * 3] = { gen_op_cvtsi2sd, X86_64_ONLY(gen_op_cvtsq2ss), X86_64_ONLY(gen_op_cvtsq2sd), - + gen_op_cvttss2si, gen_op_cvttsd2si, X86_64_ONLY(gen_op_cvttss2sq), @@ -2533,7 +2533,7 @@ static GenOpFunc1 *sse_op_table3[4 * 3] = { X86_64_ONLY(gen_op_cvtss2sq), X86_64_ONLY(gen_op_cvtsd2sq), }; - + static GenOpFunc2 *sse_op_table4[8][4] = { SSE_FOP(cmpeq), SSE_FOP(cmplt), @@ -2544,7 +2544,7 @@ static GenOpFunc2 *sse_op_table4[8][4] = { SSE_FOP(cmpnle), SSE_FOP(cmpord), }; - + static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) { int b1, op1_offset, op2_offset, is_xmm, val, ot; @@ -3285,7 +3285,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /* extended op code */ b = ldub_code(s->pc++) | 0x100; goto reswitch; - + /**************************/ /* arith & logic */ case 0x00 ... 0x05: @@ -3305,7 +3305,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_BYTE; else ot = dflag + OT_WORD; - + switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub_code(s->pc++); @@ -3364,12 +3364,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_BYTE; else ot = dflag + OT_WORD; - + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); op = (modrm >> 3) & 7; - + if (mod != 3) { if (b == 0x83) s->rip_offset = 1; @@ -3666,13 +3666,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; - + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_TN_reg[ot][1][reg](); gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; - + case 0xa8: /* test eAX, Iv */ case 0xa9: if ((b & 1) == 0) @@ -3686,7 +3686,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_testl_T0_T1_cc(); s->cc_op = CC_OP_LOGICB + ot; break; - + case 0x98: /* CWDE/CBW */ #ifdef TARGET_X86_64 if (dflag == 2) { @@ -3804,7 +3804,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_cmpxchg8b(); s->cc_op = CC_OP_EFLAGS; break; - + /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ @@ -3955,7 +3955,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; - + /* generate a generic store */ gen_ldst_modrm(s, modrm, ot, reg, 1); break; @@ -3986,7 +3986,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_WORD + dflag; modrm = ldub_code(s->pc++); reg = ((modrm >> 3) & 7) | rex_r; - + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); gen_op_mov_reg_T0[ot][reg](); break; @@ -4038,7 +4038,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); - + if (mod == 3) { gen_op_mov_TN_reg[ot][0][rm](); switch(ot | (b & 8)) { @@ -4084,7 +4084,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) s->addseg = val; gen_op_mov_reg_A0[ot - OT_WORD][reg](); break; - + case 0xa0: /* mov EAX, Ov */ case 0xa1: case 0xa2: /* mov Ov, EAX */ @@ -4239,7 +4239,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_eob(s); } break; - + /************************/ /* shifts */ case 0xc0: @@ -4252,11 +4252,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_BYTE; else ot = dflag + OT_WORD; - + modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; - + if (mod != 3) { if (shift == 2) { s->rip_offset = 1; @@ -4310,7 +4310,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; - + if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T0_A0[ot + s->mem_index](); @@ -4318,7 +4318,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_mov_TN_reg[ot][0][rm](); } gen_op_mov_TN_reg[ot][1][reg](); - + if (shift) { val = ldub_code(s->pc++); if (ot == OT_QUAD) @@ -4389,7 +4389,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_fild_FT0_A0(); break; } - + gen_op_fp_arith_ST0_FT0[op1](); if (op1 == 3) { /* fcomp needs pop */ @@ -4646,7 +4646,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ { int op1; - + op1 = op & 7; if (op >= 0x20) { gen_op_fp_arith_STN_ST0[op1](opreg); @@ -4816,7 +4816,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_movs(s, ot); } break; - + case 0xaa: /* stosS */ case 0xab: if ((b & 1) == 0) @@ -5042,13 +5042,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0x9a: /* lcall im */ { unsigned int selector, offset; - + if (CODE64(s)) goto illegal_op; ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); - + gen_op_movl_T0_im(selector); gen_op_movl_T1_imu(offset); } @@ -5072,7 +5072,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = dflag ? OT_LONG : OT_WORD; offset = insn_get(s, ot); selector = insn_get(s, OT_WORD); - + gen_op_movl_T0_im(selector); gen_op_movl_T1_imu(offset); } @@ -5121,7 +5121,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); break; - + /************************/ /* flags */ case 0x9c: /* pushf */ @@ -5481,7 +5481,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) tval += next_eip; if (s->dflag == 0) tval &= 0xffff; - + l1 = gen_new_label(); l2 = gen_new_label(); b &= 3; @@ -5802,7 +5802,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) reg = ((modrm >> 3) & 7) | rex_r; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); - + if (mod == 3) { gen_op_mov_TN_reg[OT_LONG][0][rm](); /* sign extend */ @@ -6465,7 +6465,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, int flags, j, lj, cflags; target_ulong pc_start; target_ulong cs_base; - + /* generate intermediate code */ pc_start = tb->pc; cs_base = tb->cs_base; @@ -6574,7 +6574,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, while (lj <= j) gen_opc_instr_start[lj++] = 0; } - + #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 5a0222dfb..a34c13734 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -86,7 +86,7 @@ typedef struct CPUM68KState { /* Temporary storage for DIV helpers. */ uint32_t div1; uint32_t div2; - + /* MMU status. */ struct { uint32_t ar; diff --git a/target-m68k/op.c b/target-m68k/op.c index b52a957b3..8600f43f1 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -349,7 +349,7 @@ OP(divu) uint32_t quot; uint32_t rem; uint32_t flags; - + num = env->div1; den = env->div2; /* ??? This needs to make sure the throwing location is accurate. */ @@ -380,7 +380,7 @@ OP(divs) int32_t quot; int32_t rem; int32_t flags; - + num = env->div1; den = env->div2; if (den == 0) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 978fb2ce8..f6b4fad64 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1639,7 +1639,7 @@ DISAS_INSN(branch) uint32_t base; int op; int l1; - + base = s->pc; op = (insn >> 8) & 0xf; offset = (int8_t)insn; @@ -3065,7 +3065,7 @@ static void expand_op_addx_cc(qOP *qop) int arg0 = qop->args[0]; int arg1 = qop->args[1]; int l1, l2; - + gen_op_add32 (arg0, arg0, arg1); l1 = gen_new_label(); l2 = gen_new_label(); @@ -3159,7 +3159,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, /* generate intermediate code */ pc_start = tb->pc; - + dc->tb = tb; gen_opc_ptr = gen_opc_buf; diff --git a/target-mips/helper.c b/target-mips/helper.c index 9a503456b..6310d6848 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -293,7 +293,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /* TLB match but 'D' bit is cleared */ exception = EXCP_LTLBL; break; - + } /* Raise exception */ env->CP0_BadVAddr = address; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9d2f99e66..6405f8066 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -321,21 +321,21 @@ void fpu_handle_exception(void) enable = GET_FP_ENABLE(env->fpu->fcr31); - /* determine current flags */ + /* determine current flags */ if (flags & float_flag_invalid) { cpuflags |= FP_INVALID; cause |= FP_INVALID & enable; } if (flags & float_flag_divbyzero) { - cpuflags |= FP_DIV0; + cpuflags |= FP_DIV0; cause |= FP_DIV0 & enable; } if (flags & float_flag_overflow) { - cpuflags |= FP_OVERFLOW; + cpuflags |= FP_OVERFLOW; cause |= FP_OVERFLOW & enable; } if (flags & float_flag_underflow) { - cpuflags |= FP_UNDERFLOW; + cpuflags |= FP_UNDERFLOW; cause |= FP_UNDERFLOW & enable; } if (flags & float_flag_inexact) { diff --git a/target-mips/translate.c b/target-mips/translate.c index ee15193c2..8e6fe0e20 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -6514,7 +6514,7 @@ done_generating: fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags); } #endif - + return 0; } @@ -6613,7 +6613,7 @@ void cpu_dump_state (CPUState *env, FILE *f, int flags) { int i; - + cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n", env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond); for (i = 0; i < 32; i++) { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 05a7368ad..3e7b2dc96 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -709,7 +709,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ppcemb_tlb_t *tlb; target_phys_addr_t raddr; int i, ret, zsel, zpr; - + ret = -1; raddr = -1; for (i = 0; i < env->nb_tlb; i++) { @@ -808,7 +808,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, " %d %d\n", __func__, address, raddr, ctx->prot, ret); } - + return ret; } @@ -825,7 +825,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw) { int in_plb, ret; - + ctx->raddr = eaddr; ctx->prot = PAGE_READ; ret = 0; diff --git a/target-ppc/mfrom_table_gen.c b/target-ppc/mfrom_table_gen.c index 8c67d4444..4c06aa4e5 100644 --- a/target-ppc/mfrom_table_gen.c +++ b/target-ppc/mfrom_table_gen.c @@ -8,7 +8,7 @@ int main (void) double d; uint8_t n; int i; - + printf("static const uint8_t mfrom_ROM_table[602] =\n{\n "); for (i = 0; i < 602; i++) { /* Extremly decomposed: diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index c65d5696b..558a3dd70 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -231,7 +231,7 @@ static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) b0 = b; b1 = b >> 32; - + v = (uint64_t)a0 * (uint64_t)b0; *plow = v; *phigh = 0; @@ -1270,7 +1270,7 @@ void do_rfmci (void) void do_load_dcr (void) { target_ulong val; - + if (unlikely(env->dcr_env == NULL)) { if (loglevel != 0) { fprintf(logfile, "No DCR environment\n"); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4419b20e8..142b76f66 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1147,7 +1147,7 @@ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { uint32_t mb, me, sh; - + sh = SH(ctx->opcode); mb = MB(ctx->opcode); me = ME(ctx->opcode); @@ -1676,7 +1676,7 @@ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) { uint8_t crb; - + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; @@ -1693,7 +1693,7 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) { uint8_t crb; - + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; @@ -2775,7 +2775,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) else #endif gen_op_test_ctr_false(mask); - break; + break; case 2: #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -2815,17 +2815,17 @@ static inline void gen_bcond(DisasContext *ctx, int type) } GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_IM); } GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_CTR); } GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW) -{ +{ gen_bcond(ctx, BCOND_LR); } @@ -2968,7 +2968,7 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC) { uint32_t crm, crn; - + if (likely(ctx->opcode & 0x00100000)) { crm = CRM(ctx->opcode); if (likely((crm ^ (crm - 1)) == 0)) { @@ -3058,7 +3058,7 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB) GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) { uint32_t crm, crn; - + gen_op_load_gpr_T0(rS(ctx->opcode)); crm = CRM(ctx->opcode); if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) { diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 79a6ab6d4..da4712b8b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2142,7 +2142,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); break; - + case CPU_PPC_G2: /* PowerPC G2 family */ case CPU_PPC_G2H4: case CPU_PPC_G2gp: diff --git a/target-sh4/README.sh4 b/target-sh4/README.sh4 index 647a345a8..a92b6f38c 100644 --- a/target-sh4/README.sh4 +++ b/target-sh4/README.sh4 @@ -141,7 +141,7 @@ if __name__ == '__main__': import sys denand (open (sys.argv[1], 'rb'), open (sys.argv[2], 'wb')) - + Style isssues ------------- diff --git a/target-sparc/op.c b/target-sparc/op.c index 834173097..683de5ada 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1285,7 +1285,7 @@ void OPPROTO op_eval_be(void) void OPPROTO op_eval_ble(void) { target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF); - + T2 = Z | (N ^ V); } @@ -1373,7 +1373,7 @@ void OPPROTO op_eval_xbe(void) void OPPROTO op_eval_xble(void) { target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF); - + T2 = Z | (N ^ V); } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 65a6ff2f3..043a84966 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -9,7 +9,7 @@ void raise_exception(int tt) { env->exception_index = tt; cpu_loop_exit(); -} +} void check_ieee_exceptions() { @@ -173,7 +173,7 @@ void helper_ld_asi(int asi, int size, int sign) case 4: /* read MMU regs */ { int reg = (T0 >> 8) & 0xf; - + ret = env->mmuregs[reg]; if (reg == 3) /* Fault status cleared on read */ env->mmuregs[reg] = 0; @@ -291,7 +291,7 @@ void helper_st_asi(int asi, int size, int sign) { int reg = (T0 >> 8) & 0xf; uint32_t oldreg; - + oldreg = env->mmuregs[reg]; switch(reg) { case 0: @@ -342,7 +342,7 @@ void helper_st_asi(int asi, int size, int sign) // copy 32 bytes unsigned int i; uint32_t src = T1 & ~3, dst = T0 & ~3, temp; - + for (i = 0; i < 32; i += 4, src += 4, dst += 4) { temp = ldl_kernel(src); stl_kernel(dst, temp); @@ -489,7 +489,7 @@ void helper_ld_asi(int asi, int size, int sign) case 0x56: // I-MMU tag read { unsigned int i; - + for (i = 0; i < 64; i++) { // Valid, ctx match, vaddr match if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && @@ -510,7 +510,7 @@ void helper_ld_asi(int asi, int size, int sign) case 0x5e: // D-MMU tag read { unsigned int i; - + for (i = 0; i < 64; i++) { // Valid, ctx match, vaddr match if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && @@ -605,7 +605,7 @@ void helper_st_asi(int asi, int size, int sign) { int reg = (T0 >> 3) & 0xf; uint64_t oldreg; - + oldreg = env->immuregs[reg]; switch(reg) { case 0: // RO @@ -672,7 +672,7 @@ void helper_st_asi(int asi, int size, int sign) { int reg = (T0 >> 3) & 0xf; uint64_t oldreg; - + oldreg = env->dmmuregs[reg]; switch(reg) { case 0: // RO diff --git a/tests/hello-arm.c b/tests/hello-arm.c index e2759a1c7..e0daa7ad9 100644 --- a/tests/hello-arm.c +++ b/tests/hello-arm.c @@ -83,7 +83,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ : "r0","r1","r2","r3","lr"); \ __syscall_return(type,__res); \ } - + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ diff --git a/tests/linux-test.c b/tests/linux-test.c index 31daa9f2b..2f82defe0 100644 --- a/tests/linux-test.c +++ b/tests/linux-test.c @@ -93,11 +93,11 @@ void test_file(void) if (getcwd(cur_dir, sizeof(cur_dir)) == NULL) error("getcwd"); - + chk_error(mkdir(TESTPATH, 0755)); - + chk_error(chdir(TESTPATH)); - + /* open/read/write/close/readv/writev/lseek */ fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644)); @@ -124,7 +124,7 @@ void test_file(void) error("read"); if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0) error("memcmp"); - + #define FOFFSET 16 ret = chk_error(lseek(fd, FOFFSET, SEEK_SET)); if (ret != 16) @@ -138,7 +138,7 @@ void test_file(void) error("readv"); if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0) error("memcmp"); - + chk_error(close(fd)); /* access */ @@ -171,18 +171,18 @@ void test_file(void) chk_error(ftruncate(fd, 50)); chk_error(fstat(fd, &st)); chk_error(close(fd)); - + if (st.st_size != 50) error("stat size"); if (!S_ISREG(st.st_mode)) error("stat mode"); - + /* symlink/lstat */ chk_error(symlink("file2", "file3")); chk_error(lstat("file3", &st)); if (!S_ISLNK(st.st_mode)) error("stat mode"); - + /* getdents */ dir = opendir(TESTPATH); if (!dir) @@ -241,7 +241,7 @@ void test_time(void) ti = tv2.tv_sec - tv.tv_sec; if (ti >= 2) error("gettimeofday"); - + chk_error(getrusage(RUSAGE_SELF, &rusg1)); for(i = 0;i < 10000; i++); chk_error(getrusage(RUSAGE_SELF, &rusg2)); @@ -327,7 +327,7 @@ void test_socket(void) chk_error(getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &val, &len)); if (val != SOCK_STREAM) error("getsockopt"); - + pid = chk_error(fork()); if (pid == 0) { client_fd = client_socket(); @@ -465,7 +465,7 @@ void test_signal(void) sigemptyset(&act.sa_mask); act.sa_flags = 0; chk_error(sigaction(SIGALRM, &act, NULL)); - + it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 10 * 1000; it.it_value.tv_sec = 0; @@ -475,7 +475,7 @@ void test_signal(void) if (oit.it_value.tv_sec != it.it_value.tv_sec || oit.it_value.tv_usec != it.it_value.tv_usec) error("itimer"); - + while (alarm_count < 5) { usleep(10 * 1000); } @@ -498,7 +498,7 @@ void test_signal(void) if (setjmp(jmp_env) == 0) { *(uint8_t *)0 = 0; } - + act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = 0; diff --git a/tests/qruncom.c b/tests/qruncom.c index 9d8f16bfd..ad0d938ee 100644 --- a/tests/qruncom.c +++ b/tests/qruncom.c @@ -160,7 +160,7 @@ int main(int argc, char **argv) if (argc != 2) usage(); filename = argv[1]; - + vm86_mem = mmap((void *)0x00000000, 0x110000, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); @@ -185,7 +185,7 @@ int main(int argc, char **argv) /* install exception handler for CPU emulator */ { struct sigaction act; - + sigfillset(&act.sa_mask); act.sa_flags = SA_SIGINFO; // act.sa_flags |= SA_ONSTACK; @@ -218,7 +218,7 @@ int main(int argc, char **argv) /* flags setup : we activate the IRQs by default as in user mode. We also activate the VM86 flag to run DOS code */ env->eflags |= IF_MASK | VM_MASK; - + /* init basic registers */ env->eip = 0x100; env->regs[R_ESP] = 0xfffe; @@ -260,7 +260,7 @@ int main(int argc, char **argv) set_idt(17, 0); set_idt(18, 0); set_idt(19, 0); - + /* put return code */ *seg_to_linear(env->segs[R_CS].selector, 0) = 0xb4; /* mov ah, $0 */ *seg_to_linear(env->segs[R_CS].selector, 1) = 0x00; diff --git a/tests/runcom.c b/tests/runcom.c index 94d3a39ff..cbbaf313b 100644 --- a/tests/runcom.c +++ b/tests/runcom.c @@ -80,7 +80,7 @@ int main(int argc, char **argv) if (argc != 2) usage(); filename = argv[1]; - + vm86_mem = mmap((void *)0x00000000, 0x110000, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); @@ -147,7 +147,7 @@ int main(int argc, char **argv) case VM86_INTx: { int int_num, ah; - + int_num = VM86_ARG(ret); if (int_num != 0x21) goto unknown_int; diff --git a/tests/test-i386-code16.S b/tests/test-i386-code16.S index 6692fe5e7..8f51052ce 100644 --- a/tests/test-i386-code16.S +++ b/tests/test-i386-code16.S @@ -7,7 +7,7 @@ CS_SEG = 0xf code16_start: .globl code16_func1 - + /* basic test */ code16_func1 = . - code16_start mov $1, %eax @@ -24,7 +24,7 @@ code16_func2 = . - code16_start pop %ax data32 lret -/* test various jmp opcodes */ +/* test various jmp opcodes */ .globl code16_func3 code16_func3 = . - code16_start jmp 1f @@ -36,9 +36,9 @@ code16_func3 = . - code16_start jz 2f add $2, %ax 2: - + call myfunc - + lcall $CS_SEG, $(myfunc2 - code16_start) ljmp $CS_SEG, $(myjmp1 - code16_start) @@ -50,7 +50,7 @@ myjmp1_next: myjmp2_next: data32 lret - + myfunc2_addr: .short myfunc2 - code16_start .short CS_SEG diff --git a/tests/test-i386-vm86.S b/tests/test-i386-vm86.S index 8575ae7ca..3bb96c992 100644 --- a/tests/test-i386-vm86.S +++ b/tests/test-i386-vm86.S @@ -14,7 +14,7 @@ vm86_code_start: movw %ax, %es es movw $GET_OFFSET(int90_test), 0x90 * 4 es movw %cs, 0x90 * 4 + 2 - + /* launch int 0x90 */ int $0x90 @@ -35,12 +35,12 @@ vm86_code_start: movb $0xff, %ah int $0x21 - sti + sti pushfl popl %edx movb $0xff, %ah int $0x21 - + #if 0 movw $GET_OFFSET(IF_msg1), %dx movb $0x09, %ah @@ -58,7 +58,7 @@ vm86_code_start: popw %dx movb $0xff, %ah int $0x21 - + pushfl movw %sp, %bx orw $0x200, (%bx) @@ -82,12 +82,12 @@ int90_test: movw 4(%bx), %dx movb $0xff, %ah int $0x21 - + movw $GET_OFFSET(int90_msg), %dx movb $0x09, %ah int $0x21 iret - + int90_msg: .string "INT90 started\n$" diff --git a/tests/test-i386.c b/tests/test-i386.c index fbc6be639..2d4b0a0df 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -739,7 +739,7 @@ void fpu_clear_exceptions(void) uint32_t ignored[4]; long double fpregs[8]; } float_env32; - + asm volatile ("fnstenv %0\n" : : "m" (float_env32)); float_env32.fpus &= ~0x7f; asm volatile ("fldenv %0\n" : : "m" (float_env32)); @@ -1041,7 +1041,7 @@ void test_bcd(void) TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A)); TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A)); TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A)); - + TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A)); TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A)); TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A)); @@ -1381,7 +1381,7 @@ void test_misc(void) /* NOTE: we assume that &func_lret < 4GB */ desc.offset = (long)&func_lret; desc.seg = cs_sel; - + asm volatile ("xor %%rax, %%rax\n" "rex64 lcall %1\n" : "=a" (res) @@ -1562,7 +1562,7 @@ void test_vm86(void) case VM86_INTx: { int int_num, ah, v; - + int_num = VM86_ARG(ret); if (int_num != 0x21) goto unknown_int; @@ -1665,7 +1665,7 @@ void test_exceptions(void) { struct sigaction act; volatile int val; - + act.sa_sigaction = sig_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO | SA_NODEFER; @@ -1718,7 +1718,7 @@ void test_exceptions(void) ldt.seg_not_present = 1; ldt.useable = 1; modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - + if (setjmp(jmp_env) == 0) { /* segment not present */ asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); @@ -1743,7 +1743,7 @@ void test_exceptions(void) /* read from an invalid address */ v1 = *(char *)0x1234; } - + /* test illegal instruction reporting */ printf("UD2 exception:\n"); if (setjmp(jmp_env) == 0) { @@ -1755,7 +1755,7 @@ void test_exceptions(void) /* now execute an invalid instruction */ asm volatile("lock nop"); } - + printf("INT exception:\n"); if (setjmp(jmp_env) == 0) { asm volatile ("int $0xfd"); @@ -1884,13 +1884,13 @@ void test_single_step(void) "rep cmpsb\n" "movl $4, %%ecx\n" "rep cmpsb\n" - + /* getpid() syscall: single step should skip one instruction */ "movl $20, %%eax\n" "int $0x80\n" "movl $0, %%eax\n" - + /* when modifying SS, trace is not done on the next instruction */ "movl %%ss, %%ecx\n" @@ -1906,7 +1906,7 @@ void test_single_step(void) "popl %%ss\n" "addl $1, %0\n" "movl $1, %%eax\n" - + "pushf\n" "andl $~0x00100, (%%esp)\n" "popf\n" @@ -2341,7 +2341,7 @@ void test_sse(void) MMX_OP2(pmulhuw); MMX_OP2(pmulhw); - + MMX_OP2(psubsb); MMX_OP2(psubsw); MMX_OP2(pminsw); @@ -2380,7 +2380,7 @@ void test_sse(void) asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "y" (a.q[0])); printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); - + asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "x" (a.dq)); printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]); @@ -2506,8 +2506,8 @@ void test_sse(void) SSE_OPS(cmpnlt); SSE_OPS(cmpnle); SSE_OPS(cmpord); - - + + a.d[0] = 2.7; a.d[1] = -3.4; b.d[0] = 45.7; diff --git a/thunk.c b/thunk.c index a99d20ea0..dbeb2b1fc 100644 --- a/thunk.c +++ b/thunk.c @@ -64,7 +64,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types) int nb_fields, offset, max_align, align, size, i, j; se = struct_entries + id; - + /* first we count the number of fields */ type_ptr = types; nb_fields = 0; @@ -182,7 +182,7 @@ const argtype *thunk_convert(void *dst, const void *src, uint8_t *d; const argtype *field_types; const int *dst_offsets, *src_offsets; - + se = struct_entries + *type_ptr++; if (se->convert[0] != NULL) { /* specific conversion is needed */ diff --git a/translate-all.c b/translate-all.c index 108411d55..197c48c54 100644 --- a/translate-all.c +++ b/translate-all.c @@ -110,11 +110,11 @@ static void dyngen_labels(long *gen_labels, int nb_gen_labels, uint8_t *gen_code_ptr; int c, i; unsigned long gen_code_addr[OPC_BUF_SIZE]; - + if (nb_gen_labels == 0) return; /* compute the address of each op code */ - + gen_code_ptr = gen_code_buf; i = 0; for(;;) { @@ -125,7 +125,7 @@ static void dyngen_labels(long *gen_labels, int nb_gen_labels, gen_code_ptr += opc_copy_size[c]; i++; } - + /* compute the address of each label */ for(i = 0; i < nb_gen_labels; i++) { gen_labels[i] = gen_code_addr[gen_labels[i]]; @@ -202,7 +202,7 @@ int cpu_restore_state(TranslationBlock *tb, #endif if (gen_intermediate_code_pc(env, tb) < 0) return -1; - + /* find opc index corresponding to search_pc */ tc_ptr = (unsigned long)tb->tc_ptr; if (searched_pc < tc_ptr) @@ -279,7 +279,7 @@ int cpu_restore_state(TranslationBlock *tb, case INDEX_op_ ## op ## _user:\ case INDEX_op_ ## op ## _kernel #endif - + CASE3(stfd): CASE3(stfs): CASE3(lfd): diff --git a/usb-linux.c b/usb-linux.c index ce2a5d9ff..3a2330162 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -161,7 +161,7 @@ USBDevice *usb_host_device_open(const char *devname) product_name, sizeof(product_name), devname) < 0) return NULL; - + snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", bus_num, addr); fd = open(buf, O_RDWR); @@ -176,7 +176,7 @@ USBDevice *usb_host_device_open(const char *devname) perror("read descr"); goto fail; } - + i = 0; dev_descr_len = descr[0]; if (dev_descr_len > descr_len) @@ -228,7 +228,7 @@ USBDevice *usb_host_device_open(const char *devname) #ifdef DEBUG printf("host USB device %d.%d grabbed\n", bus_num, addr); -#endif +#endif dev = qemu_mallocz(sizeof(USBHostDevice)); if (!dev) @@ -285,7 +285,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) int bus_num, addr, speed, device_count, class_id, product_id, vendor_id; int ret; char product_name[512]; - + f = fopen(USBDEVFS_PATH "/devices", "r"); if (!f) { term_printf("Could not open %s\n", USBDEVFS_PATH "/devices"); diff --git a/vl.c b/vl.c index cea4871be..b01947fbb 100644 --- a/vl.c +++ b/vl.c @@ -358,7 +358,7 @@ void cpu_outb(CPUState *env, int addr, int val) #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outb: %04x %02x\n", addr, val); -#endif +#endif ioport_write_table[0][addr](ioport_opaque[addr], addr, val); #ifdef USE_KQEMU if (env) @@ -371,7 +371,7 @@ void cpu_outw(CPUState *env, int addr, int val) #ifdef DEBUG_IOPORT if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "outw: %04x %04x\n", addr, val); -#endif +#endif ioport_write_table[1][addr](ioport_opaque[addr], addr, val); #ifdef USE_KQEMU if (env) @@ -634,7 +634,7 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) uint32_t high, low; #else uint32_t low, high; -#endif +#endif } l; } u, res; uint64_t rl, rh; @@ -1037,7 +1037,7 @@ static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) { QEMUTimer *ts; - + for(;;) { ts = *ptimer_head; if (!ts || ts->expire_time > current_time) @@ -1045,7 +1045,7 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) /* remove timer from the list before calling the callback */ *ptimer_head = ts->next; ts->next = NULL; - + /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); } @@ -1619,7 +1619,7 @@ void qemu_chr_add_handlers(CharDriverState *s, if (s->chr_update_read_handler) s->chr_update_read_handler(s); } - + static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { return len; @@ -1874,7 +1874,7 @@ static int socket_init(void) static int send_all(int fd, const uint8_t *buf, int len1) { int ret, len; - + len = len1; while (len > 0) { ret = send(fd, buf, len, 0); @@ -1964,7 +1964,7 @@ static void fd_chr_read(void *opaque) FDCharDriver *s = chr->opaque; int size, len; uint8_t buf[1024]; - + len = sizeof(buf); if (len > s->max_size) len = s->max_size; @@ -2125,7 +2125,7 @@ static void term_init(void) tty.c_cflag |= CS8; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; - + tcsetattr (0, TCSANOW, &tty); atexit(term_exit); @@ -2153,14 +2153,14 @@ static CharDriverState *qemu_chr_open_pty(void) struct termios tty; char slave_name[1024]; int master_fd, slave_fd; - + #if defined(__linux__) /* Not satisfying */ if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) { return NULL; } #endif - + /* Disabling local echo and line-buffered output */ tcgetattr (master_fd, &tty); tty.c_lflag &= ~(ECHO|ICANON|ISIG); @@ -2260,14 +2260,14 @@ static void tty_serial_init(int fd, int speed, } if (stop_bits == 2) tty.c_cflag |= CSTOPB; - + tcsetattr (fd, TCSANOW, &tty); } static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) { FDCharDriver *s = chr->opaque; - + switch(cmd) { case CHR_IOCTL_SERIAL_SET_PARAMS: { @@ -2506,7 +2506,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename) COMSTAT comstat; DWORD size; DWORD err; - + s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); if (!s->hsend) { fprintf(stderr, "Failed CreateEvent\n"); @@ -2525,12 +2525,12 @@ static int win_chr_init(CharDriverState *chr, const char *filename) s->hcom = NULL; goto fail; } - + if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) { fprintf(stderr, "Failed SetupComm\n"); goto fail; } - + ZeroMemory(&comcfg, sizeof(COMMCONFIG)); size = sizeof(COMMCONFIG); GetDefaultCommConfig(filename, &comcfg, &size); @@ -2552,7 +2552,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename) fprintf(stderr, "Failed SetCommTimeouts\n"); goto fail; } - + if (!ClearCommError(s->hcom, &err, &comstat)) { fprintf(stderr, "Failed ClearCommError\n"); goto fail; @@ -2613,7 +2613,7 @@ static void win_chr_readfile(CharDriverState *chr) int ret, err; uint8_t buf[1024]; DWORD size; - + ZeroMemory(&s->orecv, sizeof(s->orecv)); s->orecv.hEvent = s->hrecv; ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); @@ -2637,7 +2637,7 @@ static void win_chr_read(CharDriverState *chr) s->len = s->max_size; if (s->len == 0) return; - + win_chr_readfile(chr); } @@ -2647,7 +2647,7 @@ static int win_chr_poll(void *opaque) WinCharState *s = chr->opaque; COMSTAT status; DWORD comerr; - + ClearCommError(s->hcom, &comerr, &status); if (status.cbInQue > 0) { s->len = status.cbInQue; @@ -2662,7 +2662,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename) { CharDriverState *chr; WinCharState *s; - + chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; @@ -2707,7 +2707,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) int ret; DWORD size; char openname[256]; - + s->fpipe = TRUE; s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -2720,7 +2720,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) fprintf(stderr, "Failed CreateEvent\n"); goto fail; } - + snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename); s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | @@ -2779,7 +2779,7 @@ static CharDriverState *qemu_chr_open_win_pipe(const char *filename) chr->opaque = s; chr->chr_write = win_chr_write; chr->chr_close = win_chr_close; - + if (win_chr_pipe_init(chr, filename) < 0) { free(s); free(chr); @@ -2817,7 +2817,7 @@ static CharDriverState *qemu_chr_open_win_con(const char *filename) static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) { HANDLE fd_out; - + fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fd_out == INVALID_HANDLE_VALUE) @@ -3243,7 +3243,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); } - + ret = bind(fd, addr, addrlen); if (ret < 0) goto fail; @@ -3283,7 +3283,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, else qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr); } - + if (is_listen && is_waitconnect) { printf("QEMU waiting for connection on: %s\n", host_str); tcp_chr_accept(chr); @@ -3654,7 +3654,7 @@ static void net_slirp_redir(const char *redir_str) const char *p; struct in_addr guest_addr; int host_port, guest_port; - + if (!slirp_inited) { slirp_inited = 1; slirp_init(); @@ -3684,11 +3684,11 @@ static void net_slirp_redir(const char *redir_str) } if (!inet_aton(buf, &guest_addr)) goto fail; - + guest_port = strtol(p, &r, 0); if (r == p) goto fail; - + if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { fprintf(stderr, "qemu: could not set up redirection\n"); exit(1); @@ -3698,7 +3698,7 @@ static void net_slirp_redir(const char *redir_str) fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n"); exit(1); } - + #ifndef _WIN32 char smb_dir[1024]; @@ -3745,7 +3745,7 @@ void net_slirp_smb(const char *exported_dir) exit(1); } snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf"); - + f = fopen(smb_conf, "w"); if (!f) { fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf); @@ -3777,7 +3777,7 @@ void net_slirp_smb(const char *exported_dir) snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", SMBD_COMMAND, smb_conf); - + slirp_add_exec(0, smb_cmdline, 4, 139); } @@ -3866,7 +3866,7 @@ static int tap_open(char *ifname, int ifname_size) /* * Allocate TAP device, returns opened fd. * Stores dev name in the first arg(must be large enough). - */ + */ int tap_alloc(char *dev) { int tap_fd, if_fd, ppa = -1; @@ -4001,7 +4001,7 @@ static int tap_open(char *ifname, int ifname_size) { struct ifreq ifr; int fd, ret; - + TFR(fd = open("/dev/net/tun", O_RDWR)); if (fd < 0) { fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n"); @@ -4220,7 +4220,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr) perror("bind"); goto fail; } - + /* Add host to multicast group */ imr.imr_multiaddr = mcastaddr->sin_addr; imr.imr_interface.s_addr = htonl(INADDR_ANY); @@ -4356,7 +4356,7 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, static void net_socket_accept(void *opaque) { - NetSocketListenState *s = opaque; + NetSocketListenState *s = opaque; NetSocketState *s1; struct sockaddr_in saddr; socklen_t len; @@ -4389,7 +4389,7 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str) if (parse_host_port(&saddr, host_str) < 0) return -1; - + s = qemu_mallocz(sizeof(NetSocketListenState)); if (!s) return -1; @@ -4404,7 +4404,7 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str) /* allow fast reuse */ val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { perror("bind"); @@ -4487,7 +4487,7 @@ static int net_socket_mcast_init(VLANState *vlan, const char *host_str) return -1; s->dgram_dst = saddr; - + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "socket: mcast=%s:%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); @@ -4666,7 +4666,7 @@ static int net_client_init(const char *str) if (ret < 0) { fprintf(stderr, "Could not initialize device '%s'\n", device); } - + return ret; } @@ -5024,7 +5024,7 @@ typedef struct WaitObjects { } WaitObjects; static WaitObjects wait_objects = {0}; - + int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) { WaitObjects *w = &wait_objects; @@ -5051,7 +5051,7 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) w->events[i] = w->events[i + 1]; w->func[i] = w->func[i + 1]; w->opaque[i] = w->opaque[i + 1]; - } + } } if (found) w->num--; @@ -5359,7 +5359,7 @@ int qemu_savevm_state(QEMUFile *f) /* record size: filled later */ len_pos = qemu_ftell(f); qemu_put_be32(f, 0); - + se->save_state(f, se->opaque); /* fill record size */ @@ -5397,7 +5397,7 @@ int qemu_loadvm_state(QEMUFile *f) int64_t total_len, end_pos, cur_pos; unsigned int v; char idstr[256]; - + v = qemu_get_be32(f); if (v != QEMU_VM_FILE_MAGIC) goto fail; @@ -5481,7 +5481,7 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, { QEMUSnapshotInfo *sn_tab, *sn; int nb_sns, i, ret; - + ret = -ENOENT; nb_sns = bdrv_snapshot_list(bs, &sn_tab); if (nb_sns < 0) @@ -5523,7 +5523,7 @@ void do_savevm(const char *name) saved_vm_running = vm_running; vm_stop(0); - + must_delete = 0; if (name) { ret = bdrv_snapshot_find(bs, old_sn, name); @@ -5551,13 +5551,13 @@ void do_savevm(const char *name) sn->date_nsec = tv.tv_usec * 1000; #endif sn->vm_clock_nsec = qemu_get_clock(vm_clock); - + if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) { term_printf("Device %s does not support VM state snapshots\n", bdrv_get_device_name(bs)); goto the_end; } - + /* save the VM state */ f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1); if (!f) { @@ -5571,7 +5571,7 @@ void do_savevm(const char *name) term_printf("Error %d while writing VM\n", ret); goto the_end; } - + /* create the snapshots */ for(i = 0; i < MAX_DISKS; i++) { @@ -5610,7 +5610,7 @@ void do_loadvm(const char *name) term_printf("No block device supports snapshots\n"); return; } - + /* Flush all IO requests so they don't interfere with the new state. */ qemu_aio_flush(); @@ -5650,7 +5650,7 @@ void do_loadvm(const char *name) bdrv_get_device_name(bs)); return; } - + /* restore the VM state */ f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0); if (!f) { @@ -5677,7 +5677,7 @@ void do_delvm(const char *name) term_printf("No block device supports snapshots\n"); return; } - + for(i = 0; i <= MAX_DISKS; i++) { bs1 = bs_table[i]; if (bdrv_has_snapshot(bs1)) { @@ -5757,14 +5757,14 @@ void cpu_save(QEMUFile *f, void *opaque) uint16_t fptag, fpus, fpuc, fpregs_format; uint32_t hflags; int i; - + for(i = 0; i < CPU_NB_REGS; i++) qemu_put_betls(f, &env->regs[i]); qemu_put_betls(f, &env->eip); qemu_put_betls(f, &env->eflags); hflags = env->hflags; /* XXX: suppress most of the redundant hflags */ qemu_put_be32s(f, &hflags); - + /* FPU */ fpuc = env->fpuc; fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; @@ -5772,7 +5772,7 @@ void cpu_save(QEMUFile *f, void *opaque) for(i = 0; i < 8; i++) { fptag |= ((!env->fptags[i]) << i); } - + qemu_put_be16s(f, &fpuc); qemu_put_be16s(f, &fpus); qemu_put_be16s(f, &fptag); @@ -5783,7 +5783,7 @@ void cpu_save(QEMUFile *f, void *opaque) fpregs_format = 1; #endif qemu_put_be16s(f, &fpregs_format); - + for(i = 0; i < 8; i++) { #ifdef USE_X86LDOUBLE { @@ -5810,16 +5810,16 @@ void cpu_save(QEMUFile *f, void *opaque) cpu_put_seg(f, &env->tr); cpu_put_seg(f, &env->gdt); cpu_put_seg(f, &env->idt); - + qemu_put_be32s(f, &env->sysenter_cs); qemu_put_be32s(f, &env->sysenter_esp); qemu_put_be32s(f, &env->sysenter_eip); - + qemu_put_betls(f, &env->cr[0]); qemu_put_betls(f, &env->cr[2]); qemu_put_betls(f, &env->cr[3]); qemu_put_betls(f, &env->cr[4]); - + for(i = 0; i < 8; i++) qemu_put_betls(f, &env->dr[i]); @@ -5887,7 +5887,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be16s(f, &fpus); qemu_get_be16s(f, &fptag); qemu_get_be16s(f, &fpregs_format); - + /* NOTE: we cannot always restore the FPU state if the image come from a host with a different 'USE_X86LDOUBLE' define. We guess if we are in an MMX state to restore correctly in that case. */ @@ -5895,7 +5895,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) for(i = 0; i < 8; i++) { uint64_t mant; uint16_t exp; - + switch(fpregs_format) { case 0: mant = qemu_get_be64(f); @@ -5926,7 +5926,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) } #else env->fpregs[i].mmx.MMX_Q(0) = mant; -#endif +#endif break; default: return -EINVAL; @@ -5941,23 +5941,23 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) for(i = 0; i < 8; i++) { env->fptags[i] = (fptag >> i) & 1; } - + for(i = 0; i < 6; i++) cpu_get_seg(f, &env->segs[i]); cpu_get_seg(f, &env->ldt); cpu_get_seg(f, &env->tr); cpu_get_seg(f, &env->gdt); cpu_get_seg(f, &env->idt); - + qemu_get_be32s(f, &env->sysenter_cs); qemu_get_be32s(f, &env->sysenter_esp); qemu_get_be32s(f, &env->sysenter_eip); - + qemu_get_betls(f, &env->cr[0]); qemu_get_betls(f, &env->cr[2]); qemu_get_betls(f, &env->cr[3]); qemu_get_betls(f, &env->cr[4]); - + for(i = 0; i < 8; i++) qemu_get_betls(f, &env->dr[i]); @@ -6399,7 +6399,7 @@ static void ram_save(QEMUFile *f, void *opaque) int i; RamCompressState s1, *s = &s1; uint8_t buf[10]; - + qemu_put_be32(f, phys_ram_size); if (ram_compress_open(s, f) < 0) return; @@ -6766,15 +6766,15 @@ void main_loop_wait(int timeout) if (ret == 0) { int err; WaitObjects *w = &wait_objects; - + ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout); if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { if (w->func[ret - WAIT_OBJECT_0]) w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); - + /* Check for additional signaled events */ for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) { - + /* Check if event is signaled */ ret2 = WaitForSingleObject(w->events[i], 0); if(ret2 == WAIT_OBJECT_0) { @@ -6784,8 +6784,8 @@ void main_loop_wait(int timeout) } else { err = GetLastError(); fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err); - } - } + } + } } else if (ret == WAIT_TIMEOUT) { } else { err = GetLastError(); @@ -6815,7 +6815,7 @@ void main_loop_wait(int timeout) nfds = ioh->fd; } } - + tv.tv_sec = 0; #ifdef _WIN32 tv.tv_usec = 0; @@ -6877,7 +6877,7 @@ void main_loop_wait(int timeout) /* Check bottom-halves last in case any of the earlier events triggered them. */ qemu_bh_poll(); - + } static CPUState *cur_cpu; @@ -7620,19 +7620,19 @@ int main(int argc, char **argv) for(i = 1; i < MAX_SERIAL_PORTS; i++) serial_devices[i][0] = '\0'; serial_device_index = 0; - + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc"); for(i = 1; i < MAX_PARALLEL_PORTS; i++) parallel_devices[i][0] = '\0'; parallel_device_index = 0; - + usb_devices_index = 0; - + nb_net_clients = 0; nb_nics = 0; /* default mac address of the first network interface */ - + optind = 1; for(;;) { if (optind >= argc) @@ -7836,7 +7836,7 @@ int main(int argc, char **argv) break; #endif case QEMU_OPTION_redir: - net_slirp_redir(optarg); + net_slirp_redir(optarg); break; #endif #ifdef HAS_AUDIO @@ -7865,7 +7865,7 @@ int main(int argc, char **argv) { int mask; CPULogItem *item; - + mask = cpu_str_to_log_mask(optarg); if (!mask) { printf("Log items (comma separated):\n"); @@ -7937,7 +7937,7 @@ int main(int argc, char **argv) } else { goto graphic_error; } - + graphic_width = w; graphic_height = h; graphic_depth = depth; @@ -8158,7 +8158,7 @@ int main(int argc, char **argv) } setvbuf(stdout, NULL, _IOLBF, 0); - + init_timers(); init_timer_alarm(); qemu_aio_init(); diff --git a/vl.h b/vl.h index f8d12a393..9e5418073 100644 --- a/vl.h +++ b/vl.h @@ -798,7 +798,7 @@ struct PCIDevice { int devfn; char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; - + /* do not access the following fields */ PCIConfigReadFunc *config_read; PCIConfigWriteFunc *config_write; diff --git a/vnc.c b/vnc.c index 65bde67f6..068da05c1 100644 --- a/vnc.c +++ b/vnc.c @@ -912,7 +912,7 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) int keycode; keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); - + /* QEMU console switch */ switch(keycode) { case 0x2a: /* Left Shift */ -- cgit v1.2.3 From 3608160206ed55c35be916df0f5d43dccc183513 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 17 Sep 2007 08:21:54 +0000 Subject: Coding style fixes in PowerPC related code (no functional change): - avoid useless blanks at EOL. - avoid tabs. - fix wrapping lines on 80 chars terminals. - add missing ';' at macros EOL to avoid confusing auto-identers. - fix identation. - Remove historical macros in micro-ops (PARAM, SPARAM, PPC_OP, regs) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3178 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405_uc.c | 11 +- hw/ppc_chrp.c | 37 +++--- hw/ppc_prep.c | 16 ++- target-ppc/cpu.h | 18 +-- target-ppc/exec.h | 11 +- target-ppc/helper.c | 26 ++-- target-ppc/op.c | 292 +++++++++++++++++++++----------------------- target-ppc/op_helper.c | 11 +- target-ppc/op_helper_mem.h | 2 +- target-ppc/op_mem.h | 50 ++++---- target-ppc/op_template.h | 42 +++---- target-ppc/translate.c | 21 ++-- target-ppc/translate_init.c | 4 +- 13 files changed, 274 insertions(+), 267 deletions(-) diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index dd1350850..4c5a65303 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -924,7 +924,8 @@ enum { SDRAM0_CFGDATA = 0x011, }; -static uint32_t sdram_bcr (target_phys_addr_t ram_base, target_phys_addr_t ram_size) +static uint32_t sdram_bcr (target_phys_addr_t ram_base, + target_phys_addr_t ram_size) { uint32_t bcr; @@ -1217,9 +1218,11 @@ void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, sdram->irq = irq; sdram->nbanks = nbanks; memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t)); - memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(target_phys_addr_t)); + memcpy(sdram->ram_bases, ram_bases, + nbanks * sizeof(target_phys_addr_t)); memset(sdram->ram_sizes, 0, 4 * sizeof(target_phys_addr_t)); - memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(target_phys_addr_t)); + memcpy(sdram->ram_sizes, ram_sizes, + nbanks * sizeof(target_phys_addr_t)); sdram_reset(sdram); qemu_register_reset(&sdram_reset, sdram); ppc_dcr_register(env, SDRAM0_CFGADDR, @@ -2212,7 +2215,6 @@ static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt) } mask = mask >> 1; } - } static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) @@ -2228,7 +2230,6 @@ static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt) qemu_irq_lower(gpt->irqs[i]); mask = mask >> 1; } - } static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index a5e67e024..dc115949f 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -46,22 +46,26 @@ static int macio_nvram_mem_index = -1; /* DBDMA: currently no op - should suffice right now */ -static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +static void dbdma_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) { printf("%s: 0x" PADDRX " <= 0x%08x\n", __func__, addr, value); } -static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +static void dbdma_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) { } -static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +static void dbdma_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) { } static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) { printf("%s: 0x" PADDRX " => 0x00000000\n", __func__, addr); + return 0; } @@ -92,7 +96,8 @@ typedef struct MacIONVRAMState { uint8_t data[0x2000]; } MacIONVRAMState; -static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +static void macio_nvram_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) { MacIONVRAMState *s = opaque; addr = (addr >> 4) & 0x1fff; @@ -108,6 +113,7 @@ static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr) addr = (addr >> 4) & 0x1fff; value = s->data[addr]; // printf("macio_nvram_readb %04x = %02x\n", addr, value); + return value; } @@ -123,7 +129,7 @@ static CPUReadMemoryFunc *macio_nvram_read[] = { &macio_nvram_readb, }; -static MacIONVRAMState *macio_nvram_init(void) +static MacIONVRAMState *macio_nvram_init (void) { MacIONVRAMState *s; s = qemu_mallocz(sizeof(MacIONVRAMState)); @@ -131,11 +137,12 @@ static MacIONVRAMState *macio_nvram_init(void) return NULL; macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read, macio_nvram_write, s); + return s; } -static void macio_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) +static void macio_map (PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) { if (heathrow_pic_mem_index >= 0) { cpu_register_physical_memory(addr + 0x00000, 0x1000, @@ -152,10 +159,11 @@ static void macio_map(PCIDevice *pci_dev, int region_num, openpic_mem_index); } if (macio_nvram_mem_index >= 0) - cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index); + cpu_register_physical_memory(addr + 0x60000, 0x20000, + macio_nvram_mem_index); } -static void macio_init(PCIBus *bus, int device_id) +static void macio_init (PCIBus *bus, int device_id) { PCIDevice *d; @@ -204,7 +212,8 @@ static CPUReadMemoryFunc *unin_read[] = { /* temporary frame buffer OSI calls for the video.x driver. The right solution is to modify the driver to use VGA PCI I/Os */ -static int vga_osi_call(CPUState *env) +/* XXX: to be removed. This is no way related to emulation */ +static int vga_osi_call (CPUState *env) { static int vga_vbl_enabled; int linesize; @@ -264,10 +273,11 @@ static int vga_osi_call(CPUState *env) fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]); break; } + return 1; /* osi_call handled */ } -static uint8_t nvram_chksum(const uint8_t *buf, int n) +static uint8_t nvram_chksum (const uint8_t *buf, int n) { int sum, i; sum = 0; @@ -277,7 +287,7 @@ static uint8_t nvram_chksum(const uint8_t *buf, int n) } /* set a free Mac OS NVRAM partition */ -void pmac_format_nvram_partition(uint8_t *buf, int len) +void pmac_format_nvram_partition (uint8_t *buf, int len) { char partition_name[12] = "wwwwwwwwwwww"; @@ -503,8 +513,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET]; break; default: - cpu_abort(env, - "Only bus model not supported on mac99 machine\n"); + cpu_abort(env, "Bus model not supported on mac99 machine\n"); exit(1); } } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index d1075d9b1..de0e9f098 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -76,7 +76,7 @@ static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; int speaker_data_on; int dummy_refresh_clock; -static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void speaker_ioport_write (void *opaque, uint32_t addr, uint32_t val) { #if 0 speaker_data_on = (val >> 1) & 1; @@ -110,7 +110,7 @@ static inline uint32_t _PPC_intack_read (target_phys_addr_t addr) if (addr == 0xBFFFFFF0) retval = pic_intack_read(isa_pic); - // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); + // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); return retval; } @@ -177,12 +177,14 @@ static struct { /* Error diagnostic */ } XCSR; -static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +static void PPC_XCSR_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) { printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); } -static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +static void PPC_XCSR_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) { #ifdef TARGET_WORDS_BIGENDIAN value = bswap16(value); @@ -190,7 +192,8 @@ static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t val printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); } -static void PPC_XCSR_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +static void PPC_XCSR_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) { #ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); @@ -664,7 +667,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); /* PowerPC control and status register group */ #if 0 - PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL); + PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, + NULL); cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 0b9c68cf0..1ff32fd43 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -822,18 +822,18 @@ struct mmu_ctx_t { }; /*****************************************************************************/ -CPUPPCState *cpu_ppc_init(void); -int cpu_ppc_exec(CPUPPCState *s); -void cpu_ppc_close(CPUPPCState *s); +CPUPPCState *cpu_ppc_init (void); +int cpu_ppc_exec (CPUPPCState *s); +void cpu_ppc_close (CPUPPCState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ -int cpu_ppc_signal_handler(int host_signum, void *pinfo, - void *puc); +int cpu_ppc_signal_handler (int host_signum, void *pinfo, + void *puc); void do_interrupt (CPUPPCState *env); void ppc_hw_interrupt (CPUPPCState *env); -void cpu_loop_exit(void); +void cpu_loop_exit (void); void dump_stack (CPUPPCState *env); @@ -891,7 +891,7 @@ void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void ppc_tlb_invalidate_all (CPUPPCState *env); -int ppcemb_tlb_search (CPUPPCState *env, target_ulong address); +int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid); #endif #endif @@ -915,12 +915,12 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define XER_OV 30 #define XER_CA 29 #define XER_CMP 8 -#define XER_BC 0 +#define XER_BC 0 #define xer_so env->xer[4] #define xer_ov env->xer[6] #define xer_ca env->xer[2] #define xer_cmp env->xer[1] -#define xer_bc env->xer[0] +#define xer_bc env->xer[0] /* SPR definitions */ #define SPR_MQ (0x000) diff --git a/target-ppc/exec.h b/target-ppc/exec.h index ae424515b..156693291 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -58,10 +58,6 @@ register unsigned long T2 asm(AREG3); #define T1_avr (env->t1_avr) #define T2_avr (env->t2_avr) -/* XXX: to clean: remove this mess */ -#define PARAM(n) ((uint32_t)PARAM##n) -#define SPARAM(n) ((int32_t)PARAM##n) - #define FT0 (env->ft0) #define FT1 (env->ft1) #define FT2 (env->ft2) @@ -111,18 +107,19 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1); void ppc4xx_tlb_invalidate_all (CPUState *env); -static inline void env_to_regs(void) +static inline void env_to_regs (void) { } -static inline void regs_to_env(void) +static inline void regs_to_env (void) { } int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); -static inline int cpu_halted(CPUState *env) { +static inline int cpu_halted (CPUState *env) +{ if (!env->halted) return 0; if (env->msr[MSR_EE] && (env->interrupt_request & CPU_INTERRUPT_HARD)) { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 3e7b2dc96..b88be5c9b 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -64,6 +64,7 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { return addr; } + #else /* Common routines used by software and hardware TLBs emulation */ static inline int pte_is_valid (target_ulong pte0) @@ -635,7 +636,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, /* Generic TLB check function for embedded PowerPC implementations */ static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, target_phys_addr_t *raddrp, - target_ulong address, int i) + target_ulong address, + uint32_t pid, int ext, int i) { target_ulong mask; @@ -649,22 +651,25 @@ static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " ADDRX " " ADDRX " %d\n", - __func__, i, address, (int)env->spr[SPR_40x_PID], - tlb->EPN, mask, (int)tlb->PID); + __func__, i, address, pid, tlb->EPN, mask, (int)tlb->PID); } /* Check PID */ - if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID]) + if (tlb->PID != 0 && tlb->PID != pid) return -1; /* Check effective address */ if ((address & mask) != tlb->EPN) return -1; *raddrp = (tlb->RPN & mask) | (address & ~mask); + if (ext) { + /* Extend the physical address to 36 bits */ + *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32; + } return 0; } /* Generic TLB search function for PowerPC embedded implementations */ -int ppcemb_tlb_search (CPUState *env, target_ulong address) +int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; @@ -674,7 +679,7 @@ int ppcemb_tlb_search (CPUState *env, target_ulong address) ret = -1; for (i = 0; i < 64; i++) { tlb = &env->tlb[i].tlbe; - if (ppcemb_tlb_check(env, tlb, &raddr, address, i) == 0) { + if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) { ret = i; break; } @@ -703,7 +708,7 @@ void ppc4xx_tlb_invalidate_all (CPUState *env) tlb_flush(env, 1); } -int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, +int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong address, int rw, int access_type) { ppcemb_tlb_t *tlb; @@ -714,7 +719,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, raddr = -1; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; - if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0) + if (ppcemb_tlb_check(env, tlb, &raddr, address, + env->spr[SPR_40x_PID], 0, i) < 0) continue; zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; @@ -890,7 +896,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, break; case PPC_FLAGS_MMU_SOFT_4xx: case PPC_FLAGS_MMU_403: - ret = mmu4xx_get_physical_address(env, ctx, eaddr, + ret = mmu40x_get_physical_address(env, ctx, eaddr, rw, access_type); break; case PPC_FLAGS_MMU_601: @@ -1536,7 +1542,7 @@ void ppc_hw_interrupt (CPUState *env) env->exception_index = -1; } #else /* defined (CONFIG_USER_ONLY) */ -static void dump_syscall(CPUState *env) +static void dump_syscall (CPUState *env) { fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n", diff --git a/target-ppc/op.c b/target-ppc/op.c index 61517c1c6..550ee002e 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -24,16 +24,6 @@ #include "exec.h" #include "op_helper.h" -/* XXX: this is to be suppressed */ -#define regs (env) - -#define FT0 (env->ft0) -#define FT1 (env->ft1) -#define FT2 (env->ft2) - -/* XXX: this is to be suppressed... */ -#define PPC_OP(name) void OPPROTO glue(op_, name)(void) - #define REG 0 #include "op_template.h" @@ -139,16 +129,16 @@ void OPPROTO op_print_mem_EA (void) /* PowerPC state maintenance operations */ /* set_Rc0 */ -PPC_OP(set_Rc0) +void OPPROTO op_set_Rc0 (void) { env->crf[0] = T0 | xer_ov; RETURN(); } /* Set Rc1 (for floating point arithmetic) */ -PPC_OP(set_Rc1) +void OPPROTO op_set_Rc1 (void) { - env->crf[1] = regs->fpscr[7]; + env->crf[1] = env->fpscr[7]; RETURN(); } @@ -159,7 +149,7 @@ void OPPROTO op_reset_T0 (void) RETURN(); } -PPC_OP(set_T0) +void OPPROTO op_set_T0 (void) { T0 = (uint32_t)PARAM1; RETURN(); @@ -173,7 +163,7 @@ void OPPROTO op_set_T0_64 (void) } #endif -PPC_OP(set_T1) +void OPPROTO op_set_T1 (void) { T1 = (uint32_t)PARAM1; RETURN(); @@ -188,9 +178,9 @@ void OPPROTO op_set_T1_64 (void) #endif #if 0 // unused -PPC_OP(set_T2) +void OPPROTO op_set_T2 (void) { - T2 = PARAM(1); + T2 = PARAM1; RETURN(); } #endif @@ -208,12 +198,12 @@ void OPPROTO op_move_T2_T0 (void) } /* Generate exceptions */ -PPC_OP(raise_exception_err) +void OPPROTO op_raise_exception_err (void) { - do_raise_exception_err(PARAM(1), PARAM(2)); + do_raise_exception_err(PARAM1, PARAM2); } -PPC_OP(update_nip) +void OPPROTO op_update_nip (void) { env->nip = (uint32_t)PARAM1; RETURN(); @@ -227,26 +217,26 @@ void OPPROTO op_update_nip_64 (void) } #endif -PPC_OP(debug) +void OPPROTO op_debug (void) { do_raise_exception(EXCP_DEBUG); } -PPC_OP(exit_tb) +void OPPROTO op_exit_tb (void) { EXIT_TB(); } /* Load/store special registers */ -PPC_OP(load_cr) +void OPPROTO op_load_cr (void) { do_load_cr(); RETURN(); } -PPC_OP(store_cr) +void OPPROTO op_store_cr (void) { - do_store_cr(PARAM(1)); + do_store_cr(PARAM1); RETURN(); } @@ -262,26 +252,26 @@ void OPPROTO op_store_cro (void) RETURN(); } -PPC_OP(load_xer_cr) +void OPPROTO op_load_xer_cr (void) { T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1); RETURN(); } -PPC_OP(clear_xer_ov) +void OPPROTO op_clear_xer_ov (void) { xer_so = 0; xer_ov = 0; RETURN(); } -PPC_OP(clear_xer_ca) +void OPPROTO op_clear_xer_ca (void) { xer_ca = 0; RETURN(); } -PPC_OP(load_xer_bc) +void OPPROTO op_load_xer_bc (void) { T1 = xer_bc; RETURN(); @@ -293,13 +283,13 @@ void OPPROTO op_store_xer_bc (void) RETURN(); } -PPC_OP(load_xer) +void OPPROTO op_load_xer (void) { do_load_xer(); RETURN(); } -PPC_OP(store_xer) +void OPPROTO op_store_xer (void) { do_store_xer(); RETURN(); @@ -307,25 +297,25 @@ PPC_OP(store_xer) #if !defined(CONFIG_USER_ONLY) /* Segment registers load and store */ -PPC_OP(load_sr) +void OPPROTO op_load_sr (void) { - T0 = regs->sr[T1]; + T0 = env->sr[T1]; RETURN(); } -PPC_OP(store_sr) +void OPPROTO op_store_sr (void) { do_store_sr(env, T1, T0); RETURN(); } -PPC_OP(load_sdr1) +void OPPROTO op_load_sdr1 (void) { - T0 = regs->sdr1; + T0 = env->sdr1; RETURN(); } -PPC_OP(store_sdr1) +void OPPROTO op_store_sdr1 (void) { do_store_sdr1(env, T0); RETURN(); @@ -345,13 +335,13 @@ void OPPROTO op_store_asr (void) } #endif -PPC_OP(load_msr) +void OPPROTO op_load_msr (void) { T0 = do_load_msr(env); RETURN(); } -PPC_OP(store_msr) +void OPPROTO op_store_msr (void) { do_store_msr(env, T0); RETURN(); @@ -397,70 +387,70 @@ void OPPROTO op_mask_spr (void) RETURN(); } -PPC_OP(load_lr) +void OPPROTO op_load_lr (void) { - T0 = regs->lr; + T0 = env->lr; RETURN(); } -PPC_OP(store_lr) +void OPPROTO op_store_lr (void) { - regs->lr = T0; + env->lr = T0; RETURN(); } -PPC_OP(load_ctr) +void OPPROTO op_load_ctr (void) { - T0 = regs->ctr; + T0 = env->ctr; RETURN(); } -PPC_OP(store_ctr) +void OPPROTO op_store_ctr (void) { - regs->ctr = T0; + env->ctr = T0; RETURN(); } -PPC_OP(load_tbl) +void OPPROTO op_load_tbl (void) { - T0 = cpu_ppc_load_tbl(regs); + T0 = cpu_ppc_load_tbl(env); RETURN(); } -PPC_OP(load_tbu) +void OPPROTO op_load_tbu (void) { - T0 = cpu_ppc_load_tbu(regs); + T0 = cpu_ppc_load_tbu(env); RETURN(); } #if !defined(CONFIG_USER_ONLY) -PPC_OP(store_tbl) +void OPPROTO op_store_tbl (void) { - cpu_ppc_store_tbl(regs, T0); + cpu_ppc_store_tbl(env, T0); RETURN(); } -PPC_OP(store_tbu) +void OPPROTO op_store_tbu (void) { - cpu_ppc_store_tbu(regs, T0); + cpu_ppc_store_tbu(env, T0); RETURN(); } -PPC_OP(load_decr) +void OPPROTO op_load_decr (void) { - T0 = cpu_ppc_load_decr(regs); + T0 = cpu_ppc_load_decr(env); RETURN(); } -PPC_OP(store_decr) +void OPPROTO op_store_decr (void) { - cpu_ppc_store_decr(regs, T0); + cpu_ppc_store_decr(env, T0); RETURN(); } -PPC_OP(load_ibat) +void OPPROTO op_load_ibat (void) { - T0 = regs->IBAT[PARAM(1)][PARAM(2)]; + T0 = env->IBAT[PARAM1][PARAM2]; RETURN(); } @@ -480,9 +470,9 @@ void OPPROTO op_store_ibatl (void) RETURN(); } -PPC_OP(load_dbat) +void OPPROTO op_load_dbat (void) { - T0 = regs->DBAT[PARAM(1)][PARAM(2)]; + T0 = env->DBAT[PARAM1][PARAM2]; RETURN(); } @@ -504,85 +494,85 @@ void OPPROTO op_store_dbatl (void) #endif /* !defined(CONFIG_USER_ONLY) */ /* FPSCR */ -PPC_OP(load_fpscr) +void OPPROTO op_load_fpscr (void) { do_load_fpscr(); RETURN(); } -PPC_OP(store_fpscr) +void OPPROTO op_store_fpscr (void) { do_store_fpscr(PARAM1); RETURN(); } -PPC_OP(reset_scrfx) +void OPPROTO op_reset_scrfx (void) { - regs->fpscr[7] &= ~0x8; + env->fpscr[7] &= ~0x8; RETURN(); } /* crf operations */ -PPC_OP(getbit_T0) +void OPPROTO op_getbit_T0 (void) { - T0 = (T0 >> PARAM(1)) & 1; + T0 = (T0 >> PARAM1) & 1; RETURN(); } -PPC_OP(getbit_T1) +void OPPROTO op_getbit_T1 (void) { - T1 = (T1 >> PARAM(1)) & 1; + T1 = (T1 >> PARAM1) & 1; RETURN(); } -PPC_OP(setcrfbit) +void OPPROTO op_setcrfbit (void) { - T1 = (T1 & PARAM(1)) | (T0 << PARAM(2)); + T1 = (T1 & PARAM1) | (T0 << PARAM2); RETURN(); } /* Branch */ -#define EIP regs->nip +#define EIP env->nip -PPC_OP(setlr) +void OPPROTO op_setlr (void) { - regs->lr = (uint32_t)PARAM1; + env->lr = (uint32_t)PARAM1; RETURN(); } #if defined (TARGET_PPC64) void OPPROTO op_setlr_64 (void) { - regs->lr = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; + env->lr = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; RETURN(); } #endif -PPC_OP(goto_tb0) +void OPPROTO op_goto_tb0 (void) { GOTO_TB(op_goto_tb0, PARAM1, 0); } -PPC_OP(goto_tb1) +void OPPROTO op_goto_tb1 (void) { GOTO_TB(op_goto_tb1, PARAM1, 1); } void OPPROTO op_b_T1 (void) { - regs->nip = (uint32_t)(T1 & ~3); + env->nip = (uint32_t)(T1 & ~3); RETURN(); } #if defined (TARGET_PPC64) void OPPROTO op_b_T1_64 (void) { - regs->nip = (uint64_t)(T1 & ~3); + env->nip = (uint64_t)(T1 & ~3); RETURN(); } #endif -PPC_OP(jz_T0) +void OPPROTO op_jz_T0 (void) { if (!T0) GOTO_LABEL_PARAM(1); @@ -592,9 +582,9 @@ PPC_OP(jz_T0) void OPPROTO op_btest_T1 (void) { if (T0) { - regs->nip = (uint32_t)(T1 & ~3); + env->nip = (uint32_t)(T1 & ~3); } else { - regs->nip = (uint32_t)PARAM1; + env->nip = (uint32_t)PARAM1; } RETURN(); } @@ -603,133 +593,133 @@ void OPPROTO op_btest_T1 (void) void OPPROTO op_btest_T1_64 (void) { if (T0) { - regs->nip = (uint64_t)(T1 & ~3); + env->nip = (uint64_t)(T1 & ~3); } else { - regs->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; + env->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; } RETURN(); } #endif -PPC_OP(movl_T1_ctr) +void OPPROTO op_movl_T1_ctr (void) { - T1 = regs->ctr; + T1 = env->ctr; RETURN(); } -PPC_OP(movl_T1_lr) +void OPPROTO op_movl_T1_lr (void) { - T1 = regs->lr; + T1 = env->lr; RETURN(); } /* tests with result in T0 */ void OPPROTO op_test_ctr (void) { - T0 = (uint32_t)regs->ctr; + T0 = (uint32_t)env->ctr; RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_test_ctr_64 (void) { - T0 = (uint64_t)regs->ctr; + T0 = (uint64_t)env->ctr; RETURN(); } #endif void OPPROTO op_test_ctr_true (void) { - T0 = ((uint32_t)regs->ctr != 0 && (T0 & PARAM1) != 0); + T0 = ((uint32_t)env->ctr != 0 && (T0 & PARAM1) != 0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_test_ctr_true_64 (void) { - T0 = ((uint64_t)regs->ctr != 0 && (T0 & PARAM1) != 0); + T0 = ((uint64_t)env->ctr != 0 && (T0 & PARAM1) != 0); RETURN(); } #endif void OPPROTO op_test_ctr_false (void) { - T0 = ((uint32_t)regs->ctr != 0 && (T0 & PARAM1) == 0); + T0 = ((uint32_t)env->ctr != 0 && (T0 & PARAM1) == 0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_test_ctr_false_64 (void) { - T0 = ((uint64_t)regs->ctr != 0 && (T0 & PARAM1) == 0); + T0 = ((uint64_t)env->ctr != 0 && (T0 & PARAM1) == 0); RETURN(); } #endif void OPPROTO op_test_ctrz (void) { - T0 = ((uint32_t)regs->ctr == 0); + T0 = ((uint32_t)env->ctr == 0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_test_ctrz_64 (void) { - T0 = ((uint64_t)regs->ctr == 0); + T0 = ((uint64_t)env->ctr == 0); RETURN(); } #endif void OPPROTO op_test_ctrz_true (void) { - T0 = ((uint32_t)regs->ctr == 0 && (T0 & PARAM1) != 0); + T0 = ((uint32_t)env->ctr == 0 && (T0 & PARAM1) != 0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_test_ctrz_true_64 (void) { - T0 = ((uint64_t)regs->ctr == 0 && (T0 & PARAM1) != 0); + T0 = ((uint64_t)env->ctr == 0 && (T0 & PARAM1) != 0); RETURN(); } #endif void OPPROTO op_test_ctrz_false (void) { - T0 = ((uint32_t)regs->ctr == 0 && (T0 & PARAM1) == 0); + T0 = ((uint32_t)env->ctr == 0 && (T0 & PARAM1) == 0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_test_ctrz_false_64 (void) { - T0 = ((uint64_t)regs->ctr == 0 && (T0 & PARAM1) == 0); + T0 = ((uint64_t)env->ctr == 0 && (T0 & PARAM1) == 0); RETURN(); } #endif -PPC_OP(test_true) +void OPPROTO op_test_true (void) { - T0 = (T0 & PARAM(1)); + T0 = (T0 & PARAM1); RETURN(); } -PPC_OP(test_false) +void OPPROTO op_test_false (void) { - T0 = ((T0 & PARAM(1)) == 0); + T0 = ((T0 & PARAM1) == 0); RETURN(); } /* CTR maintenance */ -PPC_OP(dec_ctr) +void OPPROTO op_dec_ctr (void) { - regs->ctr--; + env->ctr--; RETURN(); } /*** Integer arithmetic ***/ /* add */ -PPC_OP(add) +void OPPROTO op_add (void) { T0 += T1; RETURN(); @@ -800,9 +790,9 @@ void OPPROTO op_adde_64 (void) #endif /* add immediate */ -PPC_OP(addi) +void OPPROTO op_addi (void) { - T0 += (int32_t)PARAM(1); + T0 += (int32_t)PARAM1; RETURN(); } @@ -957,14 +947,14 @@ void OPPROTO op_mulhdu (void) #endif /* multiply low immediate */ -PPC_OP(mulli) +void OPPROTO op_mulli (void) { T0 = ((int32_t)T0 * (int32_t)PARAM1); RETURN(); } /* multiply low word */ -PPC_OP(mullw) +void OPPROTO op_mullw (void) { T0 = (int32_t)(T0 * T1); RETURN(); @@ -1026,7 +1016,7 @@ void OPPROTO op_nego_64 (void) #endif /* subtract from */ -PPC_OP(subf) +void OPPROTO op_subf (void) { T0 = T1 - T0; RETURN(); @@ -1329,14 +1319,14 @@ void OPPROTO op_popcntb_64 (void) /*** Integer logical ***/ /* and */ -PPC_OP(and) +void OPPROTO op_and (void) { T0 &= T1; RETURN(); } /* andc */ -PPC_OP(andc) +void OPPROTO op_andc (void) { T0 &= ~T1; RETURN(); @@ -1345,7 +1335,7 @@ PPC_OP(andc) /* andi. */ void OPPROTO op_andi_T0 (void) { - T0 &= PARAM(1); + T0 &= PARAM1; RETURN(); } @@ -1371,7 +1361,7 @@ void OPPROTO op_cntlzd (void) #endif /* eqv */ -PPC_OP(eqv) +void OPPROTO op_eqv (void) { T0 = ~(T0 ^ T1); RETURN(); @@ -1408,51 +1398,51 @@ void OPPROTO op_extsw (void) #endif /* nand */ -PPC_OP(nand) +void OPPROTO op_nand (void) { T0 = ~(T0 & T1); RETURN(); } /* nor */ -PPC_OP(nor) +void OPPROTO op_nor (void) { T0 = ~(T0 | T1); RETURN(); } /* or */ -PPC_OP(or) +void OPPROTO op_or (void) { T0 |= T1; RETURN(); } /* orc */ -PPC_OP(orc) +void OPPROTO op_orc (void) { T0 |= ~T1; RETURN(); } /* ori */ -PPC_OP(ori) +void OPPROTO op_ori (void) { - T0 |= PARAM(1); + T0 |= PARAM1; RETURN(); } /* xor */ -PPC_OP(xor) +void OPPROTO op_xor (void) { T0 ^= T1; RETURN(); } /* xori */ -PPC_OP(xori) +void OPPROTO op_xori (void) { - T0 ^= PARAM(1); + T0 ^= PARAM1; RETURN(); } @@ -1630,56 +1620,56 @@ void OPPROTO op_srli_T1_64 (void) /*** Floating-Point arithmetic ***/ /* fadd - fadd. */ -PPC_OP(fadd) +void OPPROTO op_fadd (void) { FT0 = float64_add(FT0, FT1, &env->fp_status); RETURN(); } /* fsub - fsub. */ -PPC_OP(fsub) +void OPPROTO op_fsub (void) { FT0 = float64_sub(FT0, FT1, &env->fp_status); RETURN(); } /* fmul - fmul. */ -PPC_OP(fmul) +void OPPROTO op_fmul (void) { FT0 = float64_mul(FT0, FT1, &env->fp_status); RETURN(); } /* fdiv - fdiv. */ -PPC_OP(fdiv) +void OPPROTO op_fdiv (void) { FT0 = float64_div(FT0, FT1, &env->fp_status); RETURN(); } /* fsqrt - fsqrt. */ -PPC_OP(fsqrt) +void OPPROTO op_fsqrt (void) { do_fsqrt(); RETURN(); } /* fres - fres. */ -PPC_OP(fres) +void OPPROTO op_fres (void) { do_fres(); RETURN(); } /* frsqrte - frsqrte. */ -PPC_OP(frsqrte) +void OPPROTO op_frsqrte (void) { do_frsqrte(); RETURN(); } /* fsel - fsel. */ -PPC_OP(fsel) +void OPPROTO op_fsel (void) { do_fsel(); RETURN(); @@ -1687,7 +1677,7 @@ PPC_OP(fsel) /*** Floating-Point multiply-and-add ***/ /* fmadd - fmadd. */ -PPC_OP(fmadd) +void OPPROTO op_fmadd (void) { #if USE_PRECISE_EMULATION do_fmadd(); @@ -1699,7 +1689,7 @@ PPC_OP(fmadd) } /* fmsub - fmsub. */ -PPC_OP(fmsub) +void OPPROTO op_fmsub (void) { #if USE_PRECISE_EMULATION do_fmsub(); @@ -1711,14 +1701,14 @@ PPC_OP(fmsub) } /* fnmadd - fnmadd. - fnmadds - fnmadds. */ -PPC_OP(fnmadd) +void OPPROTO op_fnmadd (void) { do_fnmadd(); RETURN(); } /* fnmsub - fnmsub. */ -PPC_OP(fnmsub) +void OPPROTO op_fnmsub (void) { do_fnmsub(); RETURN(); @@ -1726,21 +1716,21 @@ PPC_OP(fnmsub) /*** Floating-Point round & convert ***/ /* frsp - frsp. */ -PPC_OP(frsp) +void OPPROTO op_frsp (void) { FT0 = float64_to_float32(FT0, &env->fp_status); RETURN(); } /* fctiw - fctiw. */ -PPC_OP(fctiw) +void OPPROTO op_fctiw (void) { do_fctiw(); RETURN(); } /* fctiwz - fctiwz. */ -PPC_OP(fctiwz) +void OPPROTO op_fctiwz (void) { do_fctiwz(); RETURN(); @@ -1748,21 +1738,21 @@ PPC_OP(fctiwz) #if defined(TARGET_PPC64) /* fcfid - fcfid. */ -PPC_OP(fcfid) +void OPPROTO op_fcfid (void) { do_fcfid(); RETURN(); } /* fctid - fctid. */ -PPC_OP(fctid) +void OPPROTO op_fctid (void) { do_fctid(); RETURN(); } /* fctidz - fctidz. */ -PPC_OP(fctidz) +void OPPROTO op_fctidz (void) { do_fctidz(); RETURN(); @@ -1771,14 +1761,14 @@ PPC_OP(fctidz) /*** Floating-Point compare ***/ /* fcmpu */ -PPC_OP(fcmpu) +void OPPROTO op_fcmpu (void) { do_fcmpu(); RETURN(); } /* fcmpo */ -PPC_OP(fcmpo) +void OPPROTO op_fcmpo (void) { do_fcmpo(); RETURN(); @@ -1786,14 +1776,14 @@ PPC_OP(fcmpo) /*** Floating-point move ***/ /* fabs */ -PPC_OP(fabs) +void OPPROTO op_fabs (void) { FT0 = float64_abs(FT0); RETURN(); } /* fnabs */ -PPC_OP(fnabs) +void OPPROTO op_fnabs (void) { FT0 = float64_abs(FT0); FT0 = float64_chs(FT0); @@ -1801,7 +1791,7 @@ PPC_OP(fnabs) } /* fneg */ -PPC_OP(fneg) +void OPPROTO op_fneg (void) { FT0 = float64_chs(FT0); RETURN(); @@ -1871,7 +1861,7 @@ void OPPROTO op_td (void) #if !defined(CONFIG_USER_ONLY) /* tlbia */ -PPC_OP(tlbia) +void OPPROTO op_tlbia (void) { do_tlbia(); RETURN(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 558a3dd70..e584e1c65 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -88,7 +88,7 @@ void do_store_cr (uint32_t mask) { int i, sh; - for (i = 0, sh = 7; i < 8; i++, sh --) { + for (i = 0, sh = 7; i < 8; i++, sh--) { if (mask & (1 << sh)) env->crf[i] = (T0 >> (sh * 4)) & 0xFUL; } @@ -216,8 +216,8 @@ static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) static void neg128 (uint64_t *plow, uint64_t *phigh) { - *plow = ~ *plow; - *phigh = ~ *phigh; + *plow = ~*plow; + *phigh = ~*phigh; add128(plow, phigh, 1, 0); } @@ -258,6 +258,7 @@ void do_mul64 (uint64_t *plow, uint64_t *phigh) static void imul64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) { int sa, sb; + sa = (a < 0); if (sa) a = -a; @@ -2493,14 +2494,14 @@ void do_4xx_tlbre_hi (void) void do_4xx_tlbsx (void) { - T0 = ppcemb_tlb_search(env, T0); + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); } void do_4xx_tlbsx_ (void) { int tmp = xer_ov; - T0 = ppcemb_tlb_search(env, T0); + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); if (T0 != -1) tmp |= 0x02; env->crf[0] = tmp; diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index 49ec1c42f..1ca5971de 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -271,7 +271,7 @@ void glue(do_icbi_64, MEMSUFFIX) (void) } #endif -/* PPC 601 specific instructions (POWER bridge) */ +/* PowerPC 601 specific instructions (POWER bridge) */ // XXX: to be tested void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb) { diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index fb62dbb2b..c1039da2d 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -517,7 +517,7 @@ void OPPROTO glue(op_lwarx, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0); - regs->reserve = (uint32_t)T0; + env->reserve = (uint32_t)T0; } RETURN(); } @@ -529,7 +529,7 @@ void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0); - regs->reserve = (uint64_t)T0; + env->reserve = (uint64_t)T0; } RETURN(); } @@ -540,7 +540,7 @@ void OPPROTO glue(op_ldarx, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ldq, MEMSUFFIX)((uint32_t)T0); - regs->reserve = (uint32_t)T0; + env->reserve = (uint32_t)T0; } RETURN(); } @@ -551,7 +551,7 @@ void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ldq, MEMSUFFIX)((uint64_t)T0); - regs->reserve = (uint64_t)T0; + env->reserve = (uint64_t)T0; } RETURN(); } @@ -563,7 +563,7 @@ void OPPROTO glue(op_lwarx_le, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0); - regs->reserve = (uint32_t)T0; + env->reserve = (uint32_t)T0; } RETURN(); } @@ -575,7 +575,7 @@ void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0); - regs->reserve = (uint64_t)T0; + env->reserve = (uint64_t)T0; } RETURN(); } @@ -586,7 +586,7 @@ void OPPROTO glue(op_ldarx_le, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ld64r, MEMSUFFIX)((uint32_t)T0); - regs->reserve = (uint32_t)T0; + env->reserve = (uint32_t)T0; } RETURN(); } @@ -597,7 +597,7 @@ void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { T1 = glue(ld64r, MEMSUFFIX)((uint64_t)T0); - regs->reserve = (uint64_t)T0; + env->reserve = (uint64_t)T0; } RETURN(); } @@ -609,14 +609,14 @@ void OPPROTO glue(op_stwcx, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != (uint32_t)T0)) { + if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_ov; } else { glue(stl, MEMSUFFIX)((uint32_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = -1; + env->reserve = -1; RETURN(); } @@ -626,14 +626,14 @@ void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != (uint64_t)T0)) { + if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_ov; } else { glue(stl, MEMSUFFIX)((uint64_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = -1; + env->reserve = -1; RETURN(); } @@ -642,14 +642,14 @@ void OPPROTO glue(op_stdcx, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != (uint32_t)T0)) { + if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_ov; } else { glue(stq, MEMSUFFIX)((uint32_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = -1; + env->reserve = -1; RETURN(); } @@ -658,14 +658,14 @@ void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != (uint64_t)T0)) { + if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_ov; } else { glue(stq, MEMSUFFIX)((uint64_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = -1; + env->reserve = -1; RETURN(); } #endif @@ -675,14 +675,14 @@ void OPPROTO glue(op_stwcx_le, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != (uint32_t)T0)) { + if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_ov; } else { glue(st32r, MEMSUFFIX)((uint32_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = -1; + env->reserve = -1; RETURN(); } @@ -692,14 +692,14 @@ void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != (uint64_t)T0)) { + if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_ov; } else { glue(st32r, MEMSUFFIX)((uint64_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = -1; + env->reserve = -1; RETURN(); } @@ -708,14 +708,14 @@ void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != (uint32_t)T0)) { + if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_ov; } else { glue(st64r, MEMSUFFIX)((uint32_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = -1; + env->reserve = -1; RETURN(); } @@ -724,14 +724,14 @@ void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(EXCP_ALIGN); } else { - if (unlikely(regs->reserve != (uint64_t)T0)) { + if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_ov; } else { glue(st64r, MEMSUFFIX)((uint64_t)T0, T1); env->crf[0] = xer_ov | 0x02; } } - regs->reserve = -1; + env->reserve = -1; RETURN(); } #endif @@ -1095,7 +1095,7 @@ static inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, uint64_t data) } PPC_SPE_ST_OP(wwo, spe_stwwo); static inline void glue(spe_stwwo_le, MEMSUFFIX) (target_ulong EA, - uint64_t data) + uint64_t data) { glue(st32r, MEMSUFFIX)(EA, data); } diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index cfb86d3cb..d45062592 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -21,38 +21,38 @@ /* General purpose registers moves */ void OPPROTO glue(op_load_gpr_T0_gpr, REG) (void) { - T0 = regs->gpr[REG]; + T0 = env->gpr[REG]; RETURN(); } void OPPROTO glue(op_load_gpr_T1_gpr, REG) (void) { - T1 = regs->gpr[REG]; + T1 = env->gpr[REG]; RETURN(); } void OPPROTO glue(op_load_gpr_T2_gpr, REG) (void) { - T2 = regs->gpr[REG]; + T2 = env->gpr[REG]; RETURN(); } void OPPROTO glue(op_store_T0_gpr_gpr, REG) (void) { - regs->gpr[REG] = T0; + env->gpr[REG] = T0; RETURN(); } void OPPROTO glue(op_store_T1_gpr_gpr, REG) (void) { - regs->gpr[REG] = T1; + env->gpr[REG] = T1; RETURN(); } #if 0 // unused void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) { - regs->gpr[REG] = T2; + env->gpr[REG] = T2; RETURN(); } #endif @@ -60,40 +60,40 @@ void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) #if defined(TARGET_PPCEMB) void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void) { - T0_64 = regs->gpr[REG]; + T0_64 = env->gpr[REG]; RETURN(); } void OPPROTO glue(op_load_gpr64_T1_gpr, REG) (void) { - T1_64 = regs->gpr[REG]; + T1_64 = env->gpr[REG]; RETURN(); } #if 0 // unused void OPPROTO glue(op_load_gpr64_T2_gpr, REG) (void) { - T2_64 = regs->gpr[REG]; + T2_64 = env->gpr[REG]; RETURN(); } #endif void OPPROTO glue(op_store_T0_gpr64_gpr, REG) (void) { - regs->gpr[REG] = T0_64; + env->gpr[REG] = T0_64; RETURN(); } void OPPROTO glue(op_store_T1_gpr64_gpr, REG) (void) { - regs->gpr[REG] = T1_64; + env->gpr[REG] = T1_64; RETURN(); } #if 0 // unused void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) { - regs->gpr[REG] = T2_64; + env->gpr[REG] = T2_64; RETURN(); } #endif @@ -103,57 +103,57 @@ void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) /* Condition register moves */ void OPPROTO glue(op_load_crf_T0_crf, REG) (void) { - T0 = regs->crf[REG]; + T0 = env->crf[REG]; RETURN(); } void OPPROTO glue(op_load_crf_T1_crf, REG) (void) { - T1 = regs->crf[REG]; + T1 = env->crf[REG]; RETURN(); } void OPPROTO glue(op_store_T0_crf_crf, REG) (void) { - regs->crf[REG] = T0; + env->crf[REG] = T0; RETURN(); } void OPPROTO glue(op_store_T1_crf_crf, REG) (void) { - regs->crf[REG] = T1; + env->crf[REG] = T1; RETURN(); } /* Floating point condition and status register moves */ void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void) { - T0 = regs->fpscr[REG]; + T0 = env->fpscr[REG]; RETURN(); } #if REG == 0 void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void) { - regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9); + env->fpscr[REG] = (env->fpscr[REG] & 0x9) | (T0 & ~0x9); RETURN(); } void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void) { - regs->fpscr[REG] = (regs->fpscr[REG] & 0x9); + env->fpscr[REG] = (env->fpscr[REG] & 0x9); RETURN(); } #else void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void) { - regs->fpscr[REG] = T0; + env->fpscr[REG] = T0; RETURN(); } void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void) { - regs->fpscr[REG] = 0x0; + env->fpscr[REG] = 0x0; RETURN(); } #endif diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 142b76f66..11da03629 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -118,7 +118,7 @@ GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf); GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr); GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr); GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr); -static inline void gen_op_store_T0_fpscri(int n, uint8_t param) +static inline void gen_op_store_T0_fpscri (int n, uint8_t param) { gen_op_set_T0(param); gen_op_store_T0_fpscr(n); @@ -1312,7 +1312,7 @@ static inline void gen_rldcl (DisasContext *ctx, int mbn) mb = MB(ctx->opcode) | (mbn << 5); gen_rldnm(ctx, mb, 63); } -GEN_PPC64_R2(rldcl, 0x1E, 0x08) +GEN_PPC64_R2(rldcl, 0x1E, 0x08); /* rldcr - rldcr. */ static inline void gen_rldcr (DisasContext *ctx, int men) { @@ -1321,7 +1321,7 @@ static inline void gen_rldcr (DisasContext *ctx, int men) me = MB(ctx->opcode) | (men << 5); gen_rldnm(ctx, 0, me); } -GEN_PPC64_R2(rldcr, 0x1E, 0x09) +GEN_PPC64_R2(rldcr, 0x1E, 0x09); /* rldimi - rldimi. */ static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) { @@ -1355,7 +1355,7 @@ static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx); } -GEN_PPC64_R4(rldimi, 0x1E, 0x06) +GEN_PPC64_R4(rldimi, 0x1E, 0x06); #endif /*** Integer shift ***/ @@ -2601,8 +2601,7 @@ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) } /*** Branch ***/ - -static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +static inline void gen_goto_tb (DisasContext *ctx, int n, target_ulong dest) { TranslationBlock *tb; tb = ctx->tb; @@ -2669,7 +2668,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) #define BCOND_LR 1 #define BCOND_CTR 2 -static inline void gen_bcond(DisasContext *ctx, int type) +static inline void gen_bcond (DisasContext *ctx, int type) { target_ulong target = 0; target_ulong li; @@ -2806,7 +2805,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) #endif gen_op_btest_T1(ctx->nip); gen_op_reset_T0(); - no_test: + no_test: if (ctx->singlestep_enabled) gen_op_debug(); gen_op_exit_tb(); @@ -5585,9 +5584,9 @@ static inline uint32_t load_xer (CPUState *env) (xer_cmp << XER_CMP); } -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - int flags) +void cpu_dump_state (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) { #if defined(TARGET_PPC64) || 1 #define FILL "" diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index da4712b8b..131346d81 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2896,7 +2896,7 @@ static ppc_def_t ppc_defs[] = { .name = "Npe405H", .pvr = CPU_PPC_NPE405H, .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, + .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, .msr_mask = 0x00000000020EFF30ULL, }, @@ -3000,7 +3000,7 @@ static ppc_def_t ppc_defs[] = { .msr_mask = 0x00000000020EFF30ULL, }, #endif - /* Xilinx PowerPC 405 cores */ + /* Xilinx PowerPC 405 cores */ #if defined (TODO) { .name = "x2vp4", -- cgit v1.2.3 From 966439a67830239a6c520c5df6c55627b8153c8b Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 17 Sep 2007 09:51:40 +0000 Subject: PowerPC flags update/use fixes: - fix confusion between overflow/summary overflow, as reported by S Bansal. - reset carry in addic. optimized case (as it was already done in addic). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3179 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 18 +++++++++++++----- target-ppc/op_helper.c | 20 ++++++++++---------- target-ppc/op_mem.h | 32 ++++++++++++++++---------------- target-ppc/translate.c | 2 ++ 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 550ee002e..8ad222348 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -131,7 +131,7 @@ void OPPROTO op_print_mem_EA (void) /* set_Rc0 */ void OPPROTO op_set_Rc0 (void) { - env->crf[0] = T0 | xer_ov; + env->crf[0] = T0 | xer_so; RETURN(); } @@ -731,8 +731,8 @@ void OPPROTO op_check_addo (void) ((uint32_t)T2 ^ (uint32_t)T0) & (1UL << 31)))) { xer_ov = 0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } RETURN(); } @@ -744,8 +744,8 @@ void OPPROTO op_check_addo_64 (void) ((uint64_t)T2 ^ (uint64_t)T0) & (1ULL << 63)))) { xer_ov = 0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } RETURN(); } @@ -1028,8 +1028,8 @@ void OPPROTO op_check_subfo (void) ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)))) { xer_ov = 0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } RETURN(); } @@ -1041,8 +1041,8 @@ void OPPROTO op_check_subfo_64 (void) ((uint64_t)(~T2) ^ (uint64_t)T0) & (1ULL << 63)))) { xer_ov = 0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } RETURN(); } @@ -1196,6 +1196,7 @@ void OPPROTO op_cmp (void) } else { T0 = 0x02; } + T0 |= xer_so; RETURN(); } @@ -1209,6 +1210,7 @@ void OPPROTO op_cmp_64 (void) } else { T0 = 0x02; } + T0 |= xer_so; RETURN(); } #endif @@ -1223,6 +1225,7 @@ void OPPROTO op_cmpi (void) } else { T0 = 0x02; } + T0 |= xer_so; RETURN(); } @@ -1236,6 +1239,7 @@ void OPPROTO op_cmpi_64 (void) } else { T0 = 0x02; } + T0 |= xer_so; RETURN(); } #endif @@ -1250,6 +1254,7 @@ void OPPROTO op_cmpl (void) } else { T0 = 0x02; } + T0 |= xer_so; RETURN(); } @@ -1263,6 +1268,7 @@ void OPPROTO op_cmpl_64 (void) } else { T0 = 0x02; } + T0 |= xer_so; RETURN(); } #endif @@ -1277,6 +1283,7 @@ void OPPROTO op_cmpli (void) } else { T0 = 0x02; } + T0 |= xer_so; RETURN(); } @@ -1290,6 +1297,7 @@ void OPPROTO op_cmpli_64 (void) } else { T0 = 0x02; } + T0 |= xer_so; RETURN(); } #endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index e584e1c65..4afbfd84f 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -311,8 +311,8 @@ void do_addmeo (void) ((uint32_t)T1 ^ (uint32_t)T0) & (1UL << 31)))) { xer_ov = 0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } if (likely(T1 != 0)) xer_ca = 1; @@ -327,8 +327,8 @@ void do_addmeo_64 (void) ((uint64_t)T1 ^ (uint64_t)T0) & (1ULL << 63)))) { xer_ov = 0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } if (likely(T1 != 0)) xer_ca = 1; @@ -342,8 +342,8 @@ void do_divwo (void) xer_ov = 0; T0 = (int32_t)T0 / (int32_t)T1; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; T0 = (-1) * ((uint32_t)T0 >> 31); } } @@ -356,8 +356,8 @@ void do_divdo (void) xer_ov = 0; T0 = (int64_t)T0 / (int64_t)T1; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; T0 = (-1ULL) * ((uint64_t)T0 >> 63); } } @@ -369,8 +369,8 @@ void do_divwuo (void) xer_ov = 0; T0 = (uint32_t)T0 / (uint32_t)T1; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; T0 = 0; } } @@ -382,8 +382,8 @@ void do_divduo (void) xer_ov = 0; T0 = (uint64_t)T0 / (uint64_t)T1; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; T0 = 0; } } @@ -475,8 +475,8 @@ void do_subfmeo (void) (1UL << 31)))) { xer_ov = 0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } if (likely((uint32_t)T1 != UINT32_MAX)) xer_ca = 1; @@ -491,8 +491,8 @@ void do_subfmeo_64 (void) (1ULL << 63)))) { xer_ov = 0; } else { - xer_so = 1; xer_ov = 1; + xer_so = 1; } if (likely((uint64_t)T1 != UINT64_MAX)) xer_ca = 1; @@ -1073,8 +1073,8 @@ void do_POWER_dozo (void) T0 = T1 - T0; if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) & ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) { - xer_so = 1; xer_ov = 1; + xer_so = 1; } else { xer_ov = 0; } @@ -2499,7 +2499,7 @@ void do_4xx_tlbsx (void) void do_4xx_tlbsx_ (void) { - int tmp = xer_ov; + int tmp = xer_so; T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); if (T0 != -1) diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index c1039da2d..f1229859f 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -610,10 +610,10 @@ void OPPROTO glue(op_stwcx, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint32_t)T0)) { - env->crf[0] = xer_ov; + env->crf[0] = xer_so; } else { glue(stl, MEMSUFFIX)((uint32_t)T0, T1); - env->crf[0] = xer_ov | 0x02; + env->crf[0] = xer_so | 0x02; } } env->reserve = -1; @@ -627,10 +627,10 @@ void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint64_t)T0)) { - env->crf[0] = xer_ov; + env->crf[0] = xer_so; } else { glue(stl, MEMSUFFIX)((uint64_t)T0, T1); - env->crf[0] = xer_ov | 0x02; + env->crf[0] = xer_so | 0x02; } } env->reserve = -1; @@ -643,10 +643,10 @@ void OPPROTO glue(op_stdcx, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint32_t)T0)) { - env->crf[0] = xer_ov; + env->crf[0] = xer_so; } else { glue(stq, MEMSUFFIX)((uint32_t)T0, T1); - env->crf[0] = xer_ov | 0x02; + env->crf[0] = xer_so | 0x02; } } env->reserve = -1; @@ -659,10 +659,10 @@ void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint64_t)T0)) { - env->crf[0] = xer_ov; + env->crf[0] = xer_so; } else { glue(stq, MEMSUFFIX)((uint64_t)T0, T1); - env->crf[0] = xer_ov | 0x02; + env->crf[0] = xer_so | 0x02; } } env->reserve = -1; @@ -676,10 +676,10 @@ void OPPROTO glue(op_stwcx_le, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint32_t)T0)) { - env->crf[0] = xer_ov; + env->crf[0] = xer_so; } else { glue(st32r, MEMSUFFIX)((uint32_t)T0, T1); - env->crf[0] = xer_ov | 0x02; + env->crf[0] = xer_so | 0x02; } } env->reserve = -1; @@ -693,10 +693,10 @@ void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint64_t)T0)) { - env->crf[0] = xer_ov; + env->crf[0] = xer_so; } else { glue(st32r, MEMSUFFIX)((uint64_t)T0, T1); - env->crf[0] = xer_ov | 0x02; + env->crf[0] = xer_so | 0x02; } } env->reserve = -1; @@ -709,10 +709,10 @@ void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint32_t)T0)) { - env->crf[0] = xer_ov; + env->crf[0] = xer_so; } else { glue(st64r, MEMSUFFIX)((uint32_t)T0, T1); - env->crf[0] = xer_ov | 0x02; + env->crf[0] = xer_so | 0x02; } } env->reserve = -1; @@ -725,10 +725,10 @@ void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void) do_raise_exception(EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint64_t)T0)) { - env->crf[0] = xer_ov; + env->crf[0] = xer_so; } else { glue(st64r, MEMSUFFIX)((uint64_t)T0, T1); - env->crf[0] = xer_ov | 0x02; + env->crf[0] = xer_so | 0x02; } } env->reserve = -1; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 11da03629..6583a55de 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -802,6 +802,8 @@ GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) else #endif gen_op_check_addc(); + } else { + gen_op_clear_xer_ca(); } gen_op_store_T0_gpr(rD(ctx->opcode)); gen_set_Rc0(ctx); -- cgit v1.2.3 From 926acf8f73cab2c564bf23148d7ef049ef936e36 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 17 Sep 2007 17:27:00 +0000 Subject: Pass correct pointer to HID keyboard event handler, fixes regression from IDLE mode introduction. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3180 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index e0b2ba413..aebcf032c 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -582,7 +582,7 @@ static void usb_keyboard_handle_reset(USBDevice *dev) { USBHIDState *s = (USBHIDState *)dev; - qemu_add_kbd_event_handler(usb_keyboard_event, &s->kbd); + qemu_add_kbd_event_handler(usb_keyboard_event, s); s->protocol = 1; } -- cgit v1.2.3 From e2b577e5e548b58740ed5b1d9d12015cb7b233ff Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 17 Sep 2007 21:25:20 +0000 Subject: Prevent segfaulting when -clock is specified multiple times. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3181 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index b01947fbb..b2ebad968 100644 --- a/vl.c +++ b/vl.c @@ -903,7 +903,7 @@ static void configure_alarms(char const *opt) while (name) { struct qemu_alarm_timer tmp; - for (i = 0; i < count; i++) { + for (i = 0; i < count && alarm_timers[i].name; i++) { if (!strcmp(alarm_timers[i].name, name)) break; } -- cgit v1.2.3 From d9d7210c7dc2975f27e8d97e10f2ab3ff648d373 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 18 Sep 2007 11:17:30 +0000 Subject: Fix PowerPC 32 emulation on 64 bits hosts: we can use 64 bits registers but not pretend page is 1kB long As it seems most Linux programs assume page-size is 4kB, never allow 1kB pages for user-mode only emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3182 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1ff32fd43..75aefb051 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -23,19 +23,10 @@ #include "config.h" #include -#if !defined(TARGET_PPCEMB) -#if defined(TARGET_PPC64) || (HOST_LONG_BITS >= 64) -/* When using 64 bits temporary registers, - * we can use 64 bits GPR with no extra cost - */ -#define TARGET_PPCEMB -#endif -#endif - #if defined (TARGET_PPC64) typedef uint64_t ppc_gpr_t; -#define TARGET_LONG_BITS 64 #define TARGET_GPR_BITS 64 +#define TARGET_LONG_BITS 64 #define REGX "%016" PRIx64 #define TARGET_PAGE_BITS 12 #elif defined(TARGET_PPCEMB) @@ -43,15 +34,32 @@ typedef uint64_t ppc_gpr_t; #define TARGET_PHYS_ADDR_BITS 64 /* GPR are 64 bits: used by vector extension */ typedef uint64_t ppc_gpr_t; -#define TARGET_LONG_BITS 32 #define TARGET_GPR_BITS 64 +#define TARGET_LONG_BITS 32 #define REGX "%016" PRIx64 +#if defined(CONFIG_USER_ONLY) +/* It looks like a lot of Linux programs assume page size + * is 4kB long. This is evil, but we have to deal with it... + */ +#define TARGET_PAGE_BITS 12 +#else /* Pages can be 1 kB small */ #define TARGET_PAGE_BITS 10 +#endif +#else +#if (HOST_LONG_BITS >= 64) +/* When using 64 bits temporary registers, + * we can use 64 bits GPR with no extra cost + * It's even an optimization as it will prevent + * the compiler to do unuseful masking in the micro-ops. + */ +typedef uint64_t ppc_gpr_t; +#define TARGET_GPR_BITS 64 #else typedef uint32_t ppc_gpr_t; -#define TARGET_LONG_BITS 32 #define TARGET_GPR_BITS 32 +#endif +#define TARGET_LONG_BITS 32 #define REGX "%08" PRIx32 #define TARGET_PAGE_BITS 12 #endif -- cgit v1.2.3 From be58fc7cc7d0f8a606c70fdef7e2450175cb2888 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 18 Sep 2007 21:47:18 +0000 Subject: Always keep the bootinfo structure in the first 16 MB, as suggested by Andrew May. Fix compilation warnings introduced by variables types changes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3183 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405_uc.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 4c5a65303..e3cbb09a2 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -75,7 +75,10 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd) int i, n; /* We put the bd structure at the top of memory */ - bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t); + if (bd->bi_memsize >= 0x01000000UL) + bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t); + else + bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t); stl_raw(phys_ram_base + bdloc + 0x00, bd->bi_memstart); stl_raw(phys_ram_base + bdloc + 0x04, bd->bi_memsize); stl_raw(phys_ram_base + bdloc + 0x08, bd->bi_flashstart); @@ -952,7 +955,8 @@ static uint32_t sdram_bcr (target_phys_addr_t ram_base, bcr = 0x000C0000; break; default: - printf("%s: invalid RAM size " TARGET_FMT_ld "\n", __func__, ram_size); + printf("%s: invalid RAM size " TARGET_FMT_plx "\n", + __func__, ram_size); return 0x00000000; } bcr |= ram_base & 0xFF800000; @@ -985,8 +989,8 @@ static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled) if (*bcrp & 0x00000001) { /* Unmap RAM */ #ifdef DEBUG_SDRAM - printf("%s: unmap RAM area " ADDRX " " ADDRX "\n", __func__, - sdram_base(*bcrp), sdram_size(*bcrp)); + printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + __func__, sdram_base(*bcrp), sdram_size(*bcrp)); #endif cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp), IO_MEM_UNASSIGNED); @@ -994,8 +998,8 @@ static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled) *bcrp = bcr & 0xFFDEE001; if (enabled && (bcr & 0x00000001)) { #ifdef DEBUG_SDRAM - printf("%s: Map RAM area " ADDRX " " ADDRX "\n", __func__, - sdram_base(bcr), sdram_size(bcr)); + printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + __func__, sdram_base(bcr), sdram_size(bcr)); #endif cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr), sdram_base(bcr) | IO_MEM_RAM); @@ -1023,8 +1027,8 @@ static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) for (i = 0; i < sdram->nbanks; i++) { #ifdef DEBUG_SDRAM - printf("%s: Unmap RAM area " ADDRX " " ADDRX "\n", __func__, - sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); + printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); #endif cpu_register_physical_memory(sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]), -- cgit v1.2.3 From 7ec93196fae7d07a8ba7cf226a3daef2c3144acc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 18 Sep 2007 21:54:57 +0000 Subject: Fix invalid MAP_xxx flags for PowerPC targets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3184 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall_defs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 14a379937..07f4fd36c 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -865,9 +865,14 @@ struct target_winsize { #define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ #define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#if defined(TARGET_PPC) +#define TARGET_MAP_LOCKED 0x0080 /* pages are locked */ +#define TARGET_MAP_NORESERVE 0x0040 /* don't check for reservations */ +#else #define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ #endif +#endif #if defined(TARGET_I386) || defined(TARGET_ARM) struct target_stat { -- cgit v1.2.3 From 8b67546f65bb3de81ac4cbe02460ec99c0ec6229 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 19 Sep 2007 04:34:09 +0000 Subject: More PowerPC target cleanups: - remove unuseful historical macros and definitions - fix comments (bugs and cosmetics) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3185 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 23 ++++++++++----------- target-ppc/op_helper_mem.h | 50 +++++++++++++++++++++++----------------------- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 75aefb051..8b3fb0360 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -30,7 +30,7 @@ typedef uint64_t ppc_gpr_t; #define REGX "%016" PRIx64 #define TARGET_PAGE_BITS 12 #elif defined(TARGET_PPCEMB) -/* e500v2 have 36 bits physical address space */ +/* BookE have 36 bits physical address space */ #define TARGET_PHYS_ADDR_BITS 64 /* GPR are 64 bits: used by vector extension */ typedef uint64_t ppc_gpr_t; @@ -388,19 +388,19 @@ enum { PPC_64_BRIDGE = 0x0000000004000000ULL, /* BookE (embedded) PowerPC specification */ PPC_BOOKE = 0x0000000008000000ULL, - /* eieio */ + /* eieio */ PPC_MEM_EIEIO = 0x0000000010000000ULL, - /* e500 vector instructions */ + /* e500 vector instructions */ PPC_E500_VECTOR = 0x0000000020000000ULL, - /* PowerPC 4xx dedicated instructions */ + /* PowerPC 4xx dedicated instructions */ PPC_4xx_COMMON = 0x0000000040000000ULL, - /* PowerPC 2.03 specification extensions */ + /* PowerPC 2.03 specification extensions */ PPC_203 = 0x0000000080000000ULL, - /* PowerPC 2.03 SPE extension */ + /* PowerPC 2.03 SPE extension */ PPC_SPE = 0x0000000100000000ULL, - /* PowerPC 2.03 SPE floating-point extension */ + /* PowerPC 2.03 SPE floating-point extension */ PPC_SPEFPU = 0x0000000200000000ULL, - /* SLB management */ + /* SLB management */ PPC_SLBI = 0x0000000400000000ULL, }; @@ -917,8 +917,6 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); /*****************************************************************************/ /* Registers definitions */ -#define ugpr(n) (env->gpr[n]) - #define XER_SO 31 #define XER_OV 30 #define XER_CA 29 @@ -1315,7 +1313,6 @@ enum { /* may change privilege level */ #define EXCP_BRANCH 0x11001 /* branch instruction */ #define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */ -#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ */ /* Error codes */ enum { @@ -1350,8 +1347,8 @@ enum { EXCP_INVAL_FP = 0x04, /* Unimplemented mandatory fp instr */ /* Privileged instruction */ EXCP_PRIV = 0x30, - EXCP_PRIV_OPC = 0x01, - EXCP_PRIV_REG = 0x02, + EXCP_PRIV_OPC = 0x01, /* Privileged operation exception */ + EXCP_PRIV_REG = 0x02, /* Privileged register exception */ /* Trap */ EXCP_TRAP = 0x40, }; diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index 1ca5971de..e8cca09e9 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -37,7 +37,7 @@ static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, target_ulong data) void glue(do_lmw, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ldl, MEMSUFFIX)((uint32_t)T0); + env->gpr[dst] = glue(ldl, MEMSUFFIX)((uint32_t)T0); } } @@ -45,7 +45,7 @@ void glue(do_lmw, MEMSUFFIX) (int dst) void glue(do_lmw_64, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ldl, MEMSUFFIX)((uint64_t)T0); + env->gpr[dst] = glue(ldl, MEMSUFFIX)((uint64_t)T0); } } #endif @@ -53,7 +53,7 @@ void glue(do_lmw_64, MEMSUFFIX) (int dst) void glue(do_stmw, MEMSUFFIX) (int src) { for (; src < 32; src++, T0 += 4) { - glue(stl, MEMSUFFIX)((uint32_t)T0, ugpr(src)); + glue(stl, MEMSUFFIX)((uint32_t)T0, env->gpr[src]); } } @@ -61,7 +61,7 @@ void glue(do_stmw, MEMSUFFIX) (int src) void glue(do_stmw_64, MEMSUFFIX) (int src) { for (; src < 32; src++, T0 += 4) { - glue(stl, MEMSUFFIX)((uint64_t)T0, ugpr(src)); + glue(stl, MEMSUFFIX)((uint64_t)T0, env->gpr[src]); } } #endif @@ -69,7 +69,7 @@ void glue(do_stmw_64, MEMSUFFIX) (int src) void glue(do_lmw_le, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ld32r, MEMSUFFIX)((uint32_t)T0); + env->gpr[dst] = glue(ld32r, MEMSUFFIX)((uint32_t)T0); } } @@ -77,7 +77,7 @@ void glue(do_lmw_le, MEMSUFFIX) (int dst) void glue(do_lmw_le_64, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - ugpr(dst) = glue(ld32r, MEMSUFFIX)((uint64_t)T0); + env->gpr[dst] = glue(ld32r, MEMSUFFIX)((uint64_t)T0); } } #endif @@ -85,7 +85,7 @@ void glue(do_lmw_le_64, MEMSUFFIX) (int dst) void glue(do_stmw_le, MEMSUFFIX) (int src) { for (; src < 32; src++, T0 += 4) { - glue(st32r, MEMSUFFIX)((uint32_t)T0, ugpr(src)); + glue(st32r, MEMSUFFIX)((uint32_t)T0, env->gpr[src]); } } @@ -93,7 +93,7 @@ void glue(do_stmw_le, MEMSUFFIX) (int src) void glue(do_stmw_le_64, MEMSUFFIX) (int src) { for (; src < 32; src++, T0 += 4) { - glue(st32r, MEMSUFFIX)((uint64_t)T0, ugpr(src)); + glue(st32r, MEMSUFFIX)((uint64_t)T0, env->gpr[src]); } } #endif @@ -104,7 +104,7 @@ void glue(do_lsw, MEMSUFFIX) (int dst) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - ugpr(dst++) = glue(ldl, MEMSUFFIX)((uint32_t)T0); + env->gpr[dst++] = glue(ldl, MEMSUFFIX)((uint32_t)T0); if (unlikely(dst == 32)) dst = 0; } @@ -113,7 +113,7 @@ void glue(do_lsw, MEMSUFFIX) (int dst) for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh; } - ugpr(dst) = tmp; + env->gpr[dst] = tmp; } } @@ -124,7 +124,7 @@ void glue(do_lsw_64, MEMSUFFIX) (int dst) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - ugpr(dst++) = glue(ldl, MEMSUFFIX)((uint64_t)T0); + env->gpr[dst++] = glue(ldl, MEMSUFFIX)((uint64_t)T0); if (unlikely(dst == 32)) dst = 0; } @@ -133,7 +133,7 @@ void glue(do_lsw_64, MEMSUFFIX) (int dst) for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh; } - ugpr(dst) = tmp; + env->gpr[dst] = tmp; } } #endif @@ -143,13 +143,13 @@ void glue(do_stsw, MEMSUFFIX) (int src) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(stl, MEMSUFFIX)((uint32_t)T0, ugpr(src++)); + glue(stl, MEMSUFFIX)((uint32_t)T0, env->gpr[src++]); if (unlikely(src == 32)) src = 0; } if (unlikely(T1 != 0)) { for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) - glue(stb, MEMSUFFIX)((uint32_t)T0, (ugpr(src) >> sh) & 0xFF); + glue(stb, MEMSUFFIX)((uint32_t)T0, (env->gpr[src] >> sh) & 0xFF); } } @@ -159,13 +159,13 @@ void glue(do_stsw_64, MEMSUFFIX) (int src) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(stl, MEMSUFFIX)((uint64_t)T0, ugpr(src++)); + glue(stl, MEMSUFFIX)((uint64_t)T0, env->gpr[src++]); if (unlikely(src == 32)) src = 0; } if (unlikely(T1 != 0)) { for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) - glue(stb, MEMSUFFIX)((uint64_t)T0, (ugpr(src) >> sh) & 0xFF); + glue(stb, MEMSUFFIX)((uint64_t)T0, (env->gpr[src] >> sh) & 0xFF); } } #endif @@ -176,7 +176,7 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - ugpr(dst++) = glue(ld32r, MEMSUFFIX)((uint32_t)T0); + env->gpr[dst++] = glue(ld32r, MEMSUFFIX)((uint32_t)T0); if (unlikely(dst == 32)) dst = 0; } @@ -185,7 +185,7 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst) for (sh = 0; T1 > 0; T1--, T0++, sh += 8) { tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh; } - ugpr(dst) = tmp; + env->gpr[dst] = tmp; } } @@ -196,7 +196,7 @@ void glue(do_lsw_le_64, MEMSUFFIX) (int dst) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - ugpr(dst++) = glue(ld32r, MEMSUFFIX)((uint64_t)T0); + env->gpr[dst++] = glue(ld32r, MEMSUFFIX)((uint64_t)T0); if (unlikely(dst == 32)) dst = 0; } @@ -205,7 +205,7 @@ void glue(do_lsw_le_64, MEMSUFFIX) (int dst) for (sh = 0; T1 > 0; T1--, T0++, sh += 8) { tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh; } - ugpr(dst) = tmp; + env->gpr[dst] = tmp; } } #endif @@ -215,13 +215,13 @@ void glue(do_stsw_le, MEMSUFFIX) (int src) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(st32r, MEMSUFFIX)((uint32_t)T0, ugpr(src++)); + glue(st32r, MEMSUFFIX)((uint32_t)T0, env->gpr[src++]); if (unlikely(src == 32)) src = 0; } if (unlikely(T1 != 0)) { for (sh = 0; T1 > 0; T1--, T0++, sh += 8) - glue(stb, MEMSUFFIX)((uint32_t)T0, (ugpr(src) >> sh) & 0xFF); + glue(stb, MEMSUFFIX)((uint32_t)T0, (env->gpr[src] >> sh) & 0xFF); } } @@ -231,13 +231,13 @@ void glue(do_stsw_le_64, MEMSUFFIX) (int src) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(st32r, MEMSUFFIX)((uint64_t)T0, ugpr(src++)); + glue(st32r, MEMSUFFIX)((uint64_t)T0, env->gpr[src++]); if (unlikely(src == 32)) src = 0; } if (unlikely(T1 != 0)) { for (sh = 0; T1 > 0; T1--, T0++, sh += 8) - glue(stb, MEMSUFFIX)((uint64_t)T0, (ugpr(src) >> sh) & 0xFF); + glue(stb, MEMSUFFIX)((uint64_t)T0, (env->gpr[src] >> sh) & 0xFF); } } #endif @@ -283,7 +283,7 @@ void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb) c = glue(ldub, MEMSUFFIX)((uint32_t)T0++); /* ra (if not 0) and rb are never modified */ if (likely(reg != rb && (ra == 0 || reg != ra))) { - ugpr(reg) = (ugpr(reg) & ~(0xFF << d)) | (c << d); + env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d); } if (unlikely(c == T2)) break; -- cgit v1.2.3 From caa4039ced651551503b709b640bc6066b8eb2c2 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 19 Sep 2007 04:36:02 +0000 Subject: Code provision for PowerPC 64 MMU model support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3186 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 341 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 276 insertions(+), 65 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b88be5c9b..b6fc803b4 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -77,24 +77,62 @@ static inline void pte_invalidate (target_ulong *pte0) *pte0 &= ~0x80000000; } +#if defined(TARGET_PPC64) +static inline int pte64_is_valid (target_ulong pte0) +{ + return pte0 & 0x0000000000000001ULL ? 1 : 0; +} + +static inline void pte64_invalidate (target_ulong *pte0) +{ + *pte0 &= ~0x0000000000000001ULL; +} +#endif + #define PTE_PTEM_MASK 0x7FFFFFBF #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B) +#if defined(TARGET_PPC64) +#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL +#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) +#endif -static int pte_check (mmu_ctx_t *ctx, - target_ulong pte0, target_ulong pte1, int h, int rw) +static inline int _pte_check (mmu_ctx_t *ctx, int is_64b, + target_ulong pte0, target_ulong pte1, + int h, int rw) { - int access, ret; + target_ulong ptem, mmask; + int access, ret, pteh, ptev; access = 0; ret = -1; /* Check validity and table match */ - if (pte_is_valid(pte0) && (h == ((pte0 >> 6) & 1))) { +#if defined(TARGET_PPC64) + if (is_64b) { + ptev = pte64_is_valid(pte0); + pteh = (pte0 >> 1) & 1; + } else +#endif + { + ptev = pte_is_valid(pte0); + pteh = (pte0 >> 6) & 1; + } + if (ptev && h == pteh) { /* Check vsid & api */ - if ((pte0 & PTE_PTEM_MASK) == ctx->ptem) { +#if defined(TARGET_PPC64) + if (is_64b) { + ptem = pte0 & PTE64_PTEM_MASK; + mmask = PTE64_CHECK_MASK; + } else +#endif + { + ptem = pte0 & PTE_PTEM_MASK; + mmask = PTE_CHECK_MASK; + } + if (ptem == ctx->ptem) { if (ctx->raddr != (target_ulong)-1) { /* all matches should have equal RPN, WIMG & PP */ - if ((ctx->raddr & PTE_CHECK_MASK) != (pte1 & PTE_CHECK_MASK)) { - if (loglevel > 0) + if ((ctx->raddr & mmask) != (pte1 & mmask)) { + if (loglevel != 0) fprintf(logfile, "Bad RPN/WIMG/PP\n"); return -3; } @@ -143,6 +181,20 @@ static int pte_check (mmu_ctx_t *ctx, return ret; } +static int pte32_check (mmu_ctx_t *ctx, + target_ulong pte0, target_ulong pte1, int h, int rw) +{ + return _pte_check(ctx, 0, pte0, pte1, h, rw); +} + +#if defined(TARGET_PPC64) +static int pte64_check (mmu_ctx_t *ctx, + target_ulong pte0, target_ulong pte1, int h, int rw) +{ + return _pte_check(ctx, 1, pte0, pte1, h, rw); +} +#endif + static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p, int ret, int rw) { @@ -305,7 +357,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); } #endif - switch (pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) { + switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) { case -3: /* TLB inconsistency */ return -1; @@ -440,26 +492,36 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, } /* PTE table lookup */ -static int find_pte (mmu_ctx_t *ctx, int h, int rw) +static inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) { target_ulong base, pte0, pte1; int i, good = -1; - int ret; + int ret, r; ret = -1; /* No entry found */ base = ctx->pg_addr[h]; for (i = 0; i < 8; i++) { - pte0 = ldl_phys(base + (i * 8)); - pte1 = ldl_phys(base + (i * 8) + 4); +#if defined(TARGET_PPC64) + if (is_64b) { + pte0 = ldq_phys(base + (i * 16)); + pte1 = ldq_phys(base + (i * 16) + 8); + r = pte64_check(ctx, pte0, pte1, h, rw); + } else +#endif + { + pte0 = ldl_phys(base + (i * 8)); + pte1 = ldl_phys(base + (i * 8) + 4); + r = pte32_check(ctx, pte0, pte1, h, rw); + } #if defined (DEBUG_MMU) - if (loglevel > 0) { + if (loglevel != 0) { fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", base + (i * 8), pte0, pte1, - pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem); + (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem); } #endif - switch (pte_check(ctx, pte0, pte1, h, rw)) { + switch (r) { case -3: /* PTE inconsistency */ return -1; @@ -494,59 +556,183 @@ static int find_pte (mmu_ctx_t *ctx, int h, int rw) #endif /* Update page flags */ pte1 = ctx->raddr; - if (pte_update_flags(ctx, &pte1, ret, rw) == 1) - stl_phys_notdirty(base + (good * 8) + 4, pte1); + if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { +#if defined(TARGET_PPC64) + if (is_64b) { + stq_phys_notdirty(base + (good * 16) + 8, pte1); + } else +#endif + { + stl_phys_notdirty(base + (good * 8) + 4, pte1); + } + } } return ret; } +static int find_pte32 (mmu_ctx_t *ctx, int h, int rw) +{ + return _find_pte(ctx, 0, h, rw); +} + +#if defined(TARGET_PPC64) +static int find_pte64 (mmu_ctx_t *ctx, int h, int rw) +{ + return _find_pte(ctx, 1, h, rw); +} +#endif + +static inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw) +{ +#if defined(TARGET_PPC64) + if (PPC_MMU(env) == PPC_FLAGS_MMU_64B || + PPC_MMU(env) == PPC_FLAGS_MMU_64BRIDGE) + return find_pte64(ctx, h, rw); +#endif + + return find_pte32(ctx, h, rw); +} + static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, + int sdr_sh, target_phys_addr_t hash, target_phys_addr_t mask) { - return (sdr1 & 0xFFFF0000) | (hash & mask); + return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask); } +#if defined(TARGET_PPC64) +static int slb_lookup (CPUState *env, target_ulong eaddr, + target_ulong *vsid, target_ulong *page_mask, int *attr) +{ + target_phys_addr_t sr_base; + target_ulong mask; + uint64_t tmp64; + uint32_t tmp; + int n, ret; + int slb_nr; + + ret = -5; + sr_base = env->spr[SPR_ASR]; + mask = 0x0000000000000000ULL; /* Avoid gcc warning */ +#if 0 /* XXX: Fix this */ + slb_nr = env->slb_nr; +#else + slb_nr = 32; +#endif + for (n = 0; n < slb_nr; n++) { + tmp64 = ldq_phys(sr_base); + if (tmp64 & 0x0000000008000000ULL) { + /* SLB entry is valid */ + switch (tmp64 & 0x0000000006000000ULL) { + case 0x0000000000000000ULL: + /* 256 MB segment */ + mask = 0xFFFFFFFFF0000000ULL; + break; + case 0x0000000002000000ULL: + /* 1 TB segment */ + mask = 0xFFFF000000000000ULL; + break; + case 0x0000000004000000ULL: + case 0x0000000006000000ULL: + /* Reserved => segment is invalid */ + continue; + } + if ((eaddr & mask) == (tmp64 & mask)) { + /* SLB match */ + tmp = ldl_phys(sr_base + 8); + *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; + *page_mask = ~mask; + *attr = tmp & 0xFF; + ret = 0; + break; + } + } + sr_base += 12; + } + + return ret; +} +#endif /* defined(TARGET_PPC64) */ + /* Perform segment based translation */ static int get_segment (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int type) { - target_phys_addr_t sdr, hash, mask; - target_ulong sr, vsid, pgidx; - int ret = -1, ret2; - - sr = env->sr[eaddr >> 28]; -#if defined (DEBUG_MMU) - if (loglevel > 0) { - fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX " nip=0x" - ADDRX " lr=0x" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", - eaddr, eaddr >> 28, sr, env->nip, - env->lr, msr_ir, msr_dr, msr_pr, rw, type); - } + target_phys_addr_t sdr, hash, mask, sdr_mask; + target_ulong sr, vsid, vsid_mask, pgidx, page_mask; +#if defined(TARGET_PPC64) + int attr; #endif - ctx->key = (((sr & 0x20000000) && msr_pr == 1) || - ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; - if ((sr & 0x80000000) == 0) { + int ds, nx, vsid_sh, sdr_sh; + int ret, ret2; + +#if defined(TARGET_PPC64) + if (PPC_MMU(env) == PPC_FLAGS_MMU_64B) { + ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); + if (ret < 0) + return ret; + ctx->key = ((attr & 0x40) && msr_pr == 1) || + ((attr & 0x80) && msr_pr == 0) ? 1 : 0; + ds = 0; + nx = attr & 0x20 ? 1 : 0; + vsid_mask = 0x00003FFFFFFFFF80ULL; + vsid_sh = 7; + sdr_sh = 18; + sdr_mask = 0x3FF80; + } else +#endif /* defined(TARGET_PPC64) */ + { + sr = env->sr[eaddr >> 28]; + page_mask = 0x0FFFFFFF; + ctx->key = (((sr & 0x20000000) && msr_pr == 1) || + ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; + ds = sr & 0x80000000 ? 1 : 0; + nx = sr & 0x10000000 ? 1 : 0; + vsid = sr & 0x00FFFFFF; + vsid_mask = 0x01FFFFC0; + vsid_sh = 6; + sdr_sh = 16; + sdr_mask = 0xFFC0; #if defined (DEBUG_MMU) - if (loglevel > 0) + if (loglevel != 0) { + fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX + " nip=0x" ADDRX " lr=0x" ADDRX + " ir=%d dr=%d pr=%d %d t=%d\n", + eaddr, (int)(eaddr >> 28), sr, env->nip, + env->lr, msr_ir, msr_dr, msr_pr, rw, type); + } + if (!ds && loglevel != 0) { fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n", ctx->key, sr & 0x10000000); + } #endif + } + ret = -1; + if (!ds) { /* Check if instruction fetch is allowed, if needed */ - if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { + if (type != ACCESS_CODE || nx == 0) { /* Page address translation */ - pgidx = (eaddr >> TARGET_PAGE_BITS) & 0xFFFF; - vsid = sr & 0x00FFFFFF; - hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6; + pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS; + hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; /* Primary table address */ sdr = env->sdr1; - mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; - ctx->pg_addr[0] = get_pgaddr(sdr, hash, mask); + mask = ((sdr & 0x000001FF) << sdr_sh) | sdr_mask; + ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask); /* Secondary table address */ - hash = (~hash) & 0x01FFFFC0; - ctx->pg_addr[1] = get_pgaddr(sdr, hash, mask); - ctx->ptem = (vsid << 7) | (pgidx >> 10); + hash = (~hash) & vsid_mask; + ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask); +#if defined(TARGET_PPC64) + if (PPC_MMU(env) == PPC_FLAGS_MMU_64B || + PPC_MMU(env) == PPC_FLAGS_MMU_64BRIDGE) { + /* Only 5 bits of the page index are used in the AVPN */ + ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); + } else +#endif + { + ctx->ptem = (vsid << 7) | (pgidx >> 10); + } /* Initialize real address with an invalid value */ ctx->raddr = (target_ulong)-1; if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { @@ -562,7 +748,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } #endif /* Primary table lookup */ - ret = find_pte(ctx, 0, rw); + ret = find_pte(env, ctx, 0, rw); if (ret < 0) { /* Secondary table lookup */ #if defined (DEBUG_MMU) @@ -574,7 +760,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, (uint32_t)hash, ctx->pg_addr[1]); } #endif - ret2 = find_pte(ctx, 1, rw); + ret2 = find_pte(env, ctx, 1, rw); if (ret2 != -1) ret = ret2; } @@ -835,29 +1021,54 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, ctx->raddr = eaddr; ctx->prot = PAGE_READ; ret = 0; - if (unlikely(msr_pe != 0 && PPC_MMU(env) == PPC_FLAGS_MMU_403)) { - /* 403 family add some particular protections, - * using PBL/PBU registers for accesses with no translation. - */ - in_plb = - /* Check PLB validity */ - (env->pb[0] < env->pb[1] && - /* and address in plb area */ - eaddr >= env->pb[0] && eaddr < env->pb[1]) || - (env->pb[2] < env->pb[3] && - eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0; - if (in_plb ^ msr_px) { - /* Access in protected area */ - if (rw == 1) { - /* Access is not allowed */ - ret = -2; + switch (PPC_MMU(env)) { + case PPC_FLAGS_MMU_32B: + case PPC_FLAGS_MMU_SOFT_6xx: + case PPC_FLAGS_MMU_601: + case PPC_FLAGS_MMU_SOFT_4xx: + ctx->prot |= PAGE_WRITE; + break; +#if defined(TARGET_PPC64) + case PPC_FLAGS_MMU_64B: + case PPC_FLAGS_MMU_64BRIDGE: +#endif + /* Real address are 60 bits long */ + ctx->raddr &= 0x0FFFFFFFFFFFFFFFUL; + ctx->prot |= PAGE_WRITE; + break; + case PPC_FLAGS_MMU_403: + if (unlikely(msr_pe != 0)) { + /* 403 family add some particular protections, + * using PBL/PBU registers for accesses with no translation. + */ + in_plb = + /* Check PLB validity */ + (env->pb[0] < env->pb[1] && + /* and address in plb area */ + eaddr >= env->pb[0] && eaddr < env->pb[1]) || + (env->pb[2] < env->pb[3] && + eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0; + if (in_plb ^ msr_px) { + /* Access in protected area */ + if (rw == 1) { + /* Access is not allowed */ + ret = -2; + } + } else { + /* Read-write access is allowed */ + ctx->prot |= PAGE_WRITE; } - } else { - /* Read-write access is allowed */ - ctx->prot |= PAGE_WRITE; } - } else { + case PPC_FLAGS_MMU_BOOKE: ctx->prot |= PAGE_WRITE; + break; + case PPC_FLAGS_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "BookE FSL MMU model not implemented\n"); + break; + default: + cpu_abort(env, "Unknown or invalid MMU model\n"); + return -1; } return ret; -- cgit v1.2.3 From 0686970f8186d44776ec6bfae8af974fb1509c10 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 19 Sep 2007 04:46:57 +0000 Subject: Avoid Linux to stay stucked in an infinite loop when requesting a reboot. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3187 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/cuda.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/cuda.c b/hw/cuda.c index 7312bbddc..9a05aebb5 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -557,6 +557,12 @@ static void cuda_receive_packet(CUDAState *s, cuda_send_packet_to_host(s, obuf, 2); qemu_system_shutdown_request(); break; + case CUDA_RESET_SYSTEM: + obuf[0] = CUDA_PACKET; + obuf[1] = 0; + cuda_send_packet_to_host(s, obuf, 2); + qemu_system_reset_request(); + break; default: break; } -- cgit v1.2.3 From 1527c87eeeca43ad9e76ed9e394ace2ea03be49a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 19 Sep 2007 05:37:56 +0000 Subject: Improve PowerPC target implementation, using computed hflags as TB flags. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3188 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index d04294763..2d08626db 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -187,8 +187,7 @@ static inline TranslationBlock *tb_find_fast(void) 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); + flags = env->hflags; cs_base = 0; pc = env->nip; #elif defined(TARGET_MIPS) -- cgit v1.2.3 From 5eb7995e34ebf8cf9a3fc43ed2c7af93149d1b0d Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 19 Sep 2007 05:44:04 +0000 Subject: Code provision for PowerPC BookE MMU model support. Better MSR flags initialisation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3189 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 79 ++++++++++++++++++++++---- target-ppc/op.c | 48 ++++++++++++++++ target-ppc/op_helper.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++ target-ppc/op_helper.h | 12 ++++ target-ppc/translate.c | 93 ++++++++++++++++++++++++++++++- 5 files changed, 365 insertions(+), 14 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b6fc803b4..80315f6de 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1013,6 +1013,52 @@ void store_40x_sler (CPUPPCState *env, uint32_t val) env->spr[SPR_405_SLER] = val; } +int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, + target_ulong address, int rw, + int access_type) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + int i, prot, ret; + + ret = -1; + raddr = -1; + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb[i].tlbe; + if (ppcemb_tlb_check(env, tlb, &raddr, address, + env->spr[SPR_BOOKE_PID], 1, i) < 0) + continue; + if (msr_pr) + prot = tlb->prot & 0xF; + else + prot = (tlb->prot >> 4) & 0xF; + /* Check the address space */ + if (access_type == ACCESS_CODE) { + if (msr_is != (tlb->attr & 1)) + continue; + ctx->prot = prot; + if (prot & PAGE_EXEC) { + ret = 0; + break; + } + ret = -3; + } else { + if (msr_ds != (tlb->attr & 1)) + continue; + ctx->prot = prot; + if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) { + ret = 0; + break; + } + ret = -2; + } + } + if (ret >= 0) + ctx->raddr = raddr; + + return ret; +} + static int check_physical (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw) { @@ -1115,9 +1161,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, cpu_abort(env, "601 MMU model not implemented\n"); return -1; case PPC_FLAGS_MMU_BOOKE: - /* XXX: TODO */ - cpu_abort(env, "BookeE MMU model not implemented\n"); - return -1; + ret = mmubooke_get_physical_address(env, ctx, eaddr, + rw, access_type); + break; case PPC_FLAGS_MMU_BOOKE_FSL: /* XXX: TODO */ cpu_abort(env, "BookE FSL MMU model not implemented\n"); @@ -1950,7 +1996,7 @@ void do_interrupt (CPUState *env) cpu_abort(env, "Floating point assist exception " "is not implemented yet !\n"); goto store_next; - /* 64 bits PowerPC exceptions */ + /* 64 bits PowerPC exceptions */ case EXCP_DSEG: /* 0x0380 */ /* XXX: TODO */ cpu_abort(env, "Data segment exception is not implemented yet !\n"); @@ -2446,28 +2492,39 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr) void cpu_ppc_reset (void *opaque) { CPUPPCState *env; + int i; env = opaque; + /* XXX: some of those flags initialisation values could depend + * on the actual PowerPC implementation + */ + for (i = 0; i < 63; i++) + env->msr[i] = 0; +#if defined(TARGET_PPC64) + msr_hv = 0; /* Should be 1... */ +#endif + msr_ap = 0; /* TO BE CHECKED */ + msr_sa = 0; /* TO BE CHECKED */ + msr_ip = 0; /* TO BE CHECKED */ #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; msr_be = 1; -#endif - msr_fp = 1; /* Allow floating point exceptions */ - msr_me = 1; /* Allow machine check exceptions */ -#if defined(TARGET_PPC64) - msr_sf = 0; /* Boot in 32 bits mode */ - msr_cm = 0; #endif #if defined(CONFIG_USER_ONLY) + msr_fp = 1; /* Allow floating point exceptions */ msr_pr = 1; - tlb_flush(env, 1); #else env->nip = 0xFFFFFFFC; ppc_tlb_invalidate_all(env); #endif do_compute_hflags(env); env->reserve = -1; + /* Be sure no exception or interrupt is pending */ + env->pending_interrupts = 0; + env->exception_index = EXCP_NONE; + /* Flush all TLBs */ + tlb_flush(env, 1); } CPUPPCState *cpu_ppc_init (void) diff --git a/target-ppc/op.c b/target-ppc/op.c index 8ad222348..1e9bd2276 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2365,6 +2365,54 @@ void OPPROTO op_wrte (void) RETURN(); } +void OPPROTO op_booke_tlbre0 (void) +{ + do_booke_tlbre0(); + RETURN(); +} + +void OPPROTO op_booke_tlbre1 (void) +{ + do_booke_tlbre1(); + RETURN(); +} + +void OPPROTO op_booke_tlbre2 (void) +{ + do_booke_tlbre2(); + RETURN(); +} + +void OPPROTO op_booke_tlbsx (void) +{ + do_booke_tlbsx(); + RETURN(); +} + +void OPPROTO op_booke_tlbsx_ (void) +{ + do_booke_tlbsx_(); + RETURN(); +} + +void OPPROTO op_booke_tlbwe0 (void) +{ + do_booke_tlbwe0(); + RETURN(); +} + +void OPPROTO op_booke_tlbwe1 (void) +{ + do_booke_tlbwe1(); + RETURN(); +} + +void OPPROTO op_booke_tlbwe2 (void) +{ + do_booke_tlbwe2(); + RETURN(); +} + void OPPROTO op_4xx_tlbre_lo (void) { do_4xx_tlbre_lo(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 4afbfd84f..56f2a5519 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2605,4 +2605,151 @@ void do_4xx_tlbwe_lo (void) } #endif } + +/* BookE TLB management */ +void do_booke_tlbwe0 (void) +{ + ppcemb_tlb_t *tlb; + target_ulong EPN, size; + int do_flush_tlbs; + +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + } +#endif + do_flush_tlbs = 0; + T0 &= 0x3F; + tlb = &env->tlb[T0].tlbe; + EPN = T1 & 0xFFFFFC00; + if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) + do_flush_tlbs = 1; + tlb->EPN = EPN; + size = booke_tlb_to_page_size((T1 >> 4) & 0xF); + if ((tlb->prot & PAGE_VALID) && tlb->size < size) + do_flush_tlbs = 1; + tlb->size = size; + tlb->attr &= ~0x1; + tlb->attr |= (T1 >> 8) & 1; + if (T1 & 0x200) { + tlb->prot |= PAGE_VALID; + } else { + if (tlb->prot & PAGE_VALID) { + tlb->prot &= ~PAGE_VALID; + do_flush_tlbs = 1; + } + } + tlb->PID = env->spr[SPR_BOOKE_PID]; + if (do_flush_tlbs) + tlb_flush(env, 1); +} + +void do_booke_tlbwe1 (void) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t RPN; + +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + } +#endif + T0 &= 0x3F; + tlb = &env->tlb[T0].tlbe; + RPN = T1 & 0xFFFFFC0F; + if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) + tlb_flush(env, 1); + tlb->RPN = RPN; +} + +void do_booke_tlbwe2 (void) +{ + ppcemb_tlb_t *tlb; + +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + } +#endif + T0 &= 0x3F; + tlb = &env->tlb[T0].tlbe; + tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00); + tlb->prot = tlb->prot & PAGE_VALID; + if (T1 & 0x1) + tlb->prot |= PAGE_READ << 4; + if (T1 & 0x2) + tlb->prot |= PAGE_WRITE << 4; + if (T1 & 0x4) + tlb->prot |= PAGE_EXEC << 4; + if (T1 & 0x8) + tlb->prot |= PAGE_READ; + if (T1 & 0x10) + tlb->prot |= PAGE_WRITE; + if (T1 & 0x20) + tlb->prot |= PAGE_EXEC; +} + +void do_booke_tlbsx (void) +{ + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]); +} + +void do_booke_tlbsx_ (void) +{ + int tmp = xer_so; + + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]); + if (T0 != -1) + tmp |= 0x02; + env->crf[0] = tmp; +} + +void do_booke_tlbre0 (void) +{ + ppcemb_tlb_t *tlb; + int size; + + T0 &= 0x3F; + tlb = &env->tlb[T0].tlbe; + T0 = tlb->EPN; + size = booke_page_size_to_tlb(tlb->size); + if (size < 0 || size > 0xF) + size = 1; + T0 |= size << 4; + if (tlb->attr & 0x1) + T0 |= 0x100; + if (tlb->prot & PAGE_VALID) + T0 |= 0x200; + env->spr[SPR_BOOKE_PID] = tlb->PID; +} + +void do_booke_tlbre1 (void) +{ + ppcemb_tlb_t *tlb; + + T0 &= 0x3F; + tlb = &env->tlb[T0].tlbe; + T0 = tlb->RPN; +} + +void do_booke_tlbre2 (void) +{ + ppcemb_tlb_t *tlb; + + T0 &= 0x3F; + tlb = &env->tlb[T0].tlbe; + T0 = tlb->attr & ~0x1; + if (tlb->prot & (PAGE_READ << 4)) + T0 |= 0x1; + if (tlb->prot & (PAGE_WRITE << 4)) + T0 |= 0x2; + if (tlb->prot & (PAGE_EXEC << 4)) + T0 |= 0x4; + if (tlb->prot & PAGE_READ) + T0 |= 0x8; + if (tlb->prot & PAGE_WRITE) + T0 |= 0x10; + if (tlb->prot & PAGE_EXEC) + T0 |= 0x20; +} #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 33f053f96..5c412ef9c 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -156,6 +156,18 @@ void do_POWER_rfsvc (void); void do_op_602_mfrom (void); #endif +/* PowerPC BookE specific helpers */ +#if !defined(CONFIG_USER_ONLY) +void do_booke_tlbre0 (void); +void do_booke_tlbre1 (void); +void do_booke_tlbre2 (void); +void do_booke_tlbsx (void); +void do_booke_tlbsx_ (void); +void do_booke_tlbwe0 (void); +void do_booke_tlbwe1 (void); +void do_booke_tlbwe2 (void); +#endif + /* PowerPC 4xx specific helpers */ void do_405_check_ov (void); void do_405_check_sat (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6583a55de..21e70195d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4618,9 +4618,10 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE) RET_CHG_FLOW(ctx); #endif } + /* TLB management - PowerPC 405 implementation */ /* tlbre */ -GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) +GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4648,7 +4649,7 @@ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) } /* tlbsx - tlbsx. */ -GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) +GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4667,7 +4668,7 @@ GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) } /* tlbwe */ -GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) +GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4694,6 +4695,92 @@ GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) #endif } +/* TLB management - PowerPC BookE implementation */ +/* tlbre */ +GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + switch (rB(ctx->opcode)) { + case 0: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_booke_tlbre0(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + break; + case 1: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_booke_tlbre1(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + break; + case 2: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_booke_tlbre2(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + break; + default: + RET_INVAL(ctx); + break; + } +#endif +} + +/* tlbsx - tlbsx. */ +GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + if (Rc(ctx->opcode)) + gen_op_booke_tlbsx_(); + else + gen_op_booke_tlbsx(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* tlbwe */ +GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + switch (rB(ctx->opcode)) { + case 0: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_booke_tlbwe0(); + break; + case 1: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_booke_tlbwe1(); + break; + case 2: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_booke_tlbwe2(); + break; + default: + RET_INVAL(ctx); + break; + } +#endif +} + /* wrtee */ GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) { -- cgit v1.2.3 From 71c8b8fd7bdf6165e32cc9c9ed6d701d0ad6b3e0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 19 Sep 2007 05:46:03 +0000 Subject: TARGET_FMT_lu may also be useful. Fix compilation warnings. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3190 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 2 ++ target-ppc/cpu.h | 3 ++- target-ppc/op_helper.c | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index e474152d5..915877617 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -45,11 +45,13 @@ typedef int32_t target_long; typedef uint32_t target_ulong; #define TARGET_FMT_lx "%08x" #define TARGET_FMT_ld "%d" +#define TARGET_FMT_lu "%u" #elif TARGET_LONG_SIZE == 8 typedef int64_t target_long; typedef uint64_t target_ulong; #define TARGET_FMT_lx "%016" PRIx64 #define TARGET_FMT_ld "%" PRId64 +#define TARGET_FMT_lu "%" PRIu64 #else #error TARGET_LONG_SIZE undefined #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8b3fb0360..f36c97924 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -55,12 +55,13 @@ typedef uint64_t ppc_gpr_t; */ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 +#define REGX "%08" PRIx64 #else typedef uint32_t ppc_gpr_t; #define TARGET_GPR_BITS 32 +#define REGX "%08" PRIx32 #endif #define TARGET_LONG_BITS 32 -#define REGX "%08" PRIx32 #define TARGET_PAGE_BITS 12 #endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 56f2a5519..9e26deb9f 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2537,7 +2537,8 @@ void do_4xx_tlbwe_hi (void) * of the ppc or ppc64 one */ if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) { - cpu_abort(env, "TLB size %u < %u are not supported (%d)\n", + cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u " + "are not supported (%d)\n", tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7)); } tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); -- cgit v1.2.3 From ff937dbad1cf5ec787ed86c5e6e17503724e6d4c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 19 Sep 2007 05:49:13 +0000 Subject: More PowerPC registers definitions. Avoid duplicating code and, as a side effect, fix missing bits in MSR. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3191 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 63 ++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/monitor.c b/monitor.c index 1c061f53a..6e0c7ba53 100644 --- a/monitor.c +++ b/monitor.c @@ -1406,21 +1406,7 @@ static target_long monitor_get_msr (struct MonitorDef *md, int val) CPUState *env = mon_get_cpu(); if (!env) return 0; - return (env->msr[MSR_POW] << MSR_POW) | - (env->msr[MSR_ILE] << MSR_ILE) | - (env->msr[MSR_EE] << MSR_EE) | - (env->msr[MSR_PR] << MSR_PR) | - (env->msr[MSR_FP] << MSR_FP) | - (env->msr[MSR_ME] << MSR_ME) | - (env->msr[MSR_FE0] << MSR_FE0) | - (env->msr[MSR_SE] << MSR_SE) | - (env->msr[MSR_BE] << MSR_BE) | - (env->msr[MSR_FE1] << MSR_FE1) | - (env->msr[MSR_IP] << MSR_IP) | - (env->msr[MSR_IR] << MSR_IR) | - (env->msr[MSR_DR] << MSR_DR) | - (env->msr[MSR_RI] << MSR_RI) | - (env->msr[MSR_LE] << MSR_LE); + return do_load_msr(env); } static target_long monitor_get_xer (struct MonitorDef *md, int val) @@ -1428,10 +1414,7 @@ static target_long monitor_get_xer (struct MonitorDef *md, int val) CPUState *env = mon_get_cpu(); if (!env) return 0; - return (env->xer[XER_SO] << XER_SO) | - (env->xer[XER_OV] << XER_OV) | - (env->xer[XER_CA] << XER_CA) | - (env->xer[XER_BC] << XER_BC); + return ppc_load_xer(env); } static target_long monitor_get_decr (struct MonitorDef *md, int val) @@ -1515,6 +1498,7 @@ static MonitorDef monitor_defs[] = { SEG("gs", R_GS) { "pc", 0, monitor_get_pc, }, #elif defined(TARGET_PPC) + /* General purpose registers */ { "r0", offsetof(CPUState, gpr[0]) }, { "r1", offsetof(CPUState, gpr[1]) }, { "r2", offsetof(CPUState, gpr[2]) }, @@ -1547,15 +1531,56 @@ static MonitorDef monitor_defs[] = { { "r29", offsetof(CPUState, gpr[29]) }, { "r30", offsetof(CPUState, gpr[30]) }, { "r31", offsetof(CPUState, gpr[31]) }, + /* Floating point registers */ + { "f0", offsetof(CPUState, fpr[0]) }, + { "f1", offsetof(CPUState, fpr[1]) }, + { "f2", offsetof(CPUState, fpr[2]) }, + { "f3", offsetof(CPUState, fpr[3]) }, + { "f4", offsetof(CPUState, fpr[4]) }, + { "f5", offsetof(CPUState, fpr[5]) }, + { "f6", offsetof(CPUState, fpr[6]) }, + { "f7", offsetof(CPUState, fpr[7]) }, + { "f8", offsetof(CPUState, fpr[8]) }, + { "f9", offsetof(CPUState, fpr[9]) }, + { "f10", offsetof(CPUState, fpr[10]) }, + { "f11", offsetof(CPUState, fpr[11]) }, + { "f12", offsetof(CPUState, fpr[12]) }, + { "f13", offsetof(CPUState, fpr[13]) }, + { "f14", offsetof(CPUState, fpr[14]) }, + { "f15", offsetof(CPUState, fpr[15]) }, + { "f16", offsetof(CPUState, fpr[16]) }, + { "f17", offsetof(CPUState, fpr[17]) }, + { "f18", offsetof(CPUState, fpr[18]) }, + { "f19", offsetof(CPUState, fpr[19]) }, + { "f20", offsetof(CPUState, fpr[20]) }, + { "f21", offsetof(CPUState, fpr[21]) }, + { "f22", offsetof(CPUState, fpr[22]) }, + { "f23", offsetof(CPUState, fpr[23]) }, + { "f24", offsetof(CPUState, fpr[24]) }, + { "f25", offsetof(CPUState, fpr[25]) }, + { "f26", offsetof(CPUState, fpr[26]) }, + { "f27", offsetof(CPUState, fpr[27]) }, + { "f28", offsetof(CPUState, fpr[28]) }, + { "f29", offsetof(CPUState, fpr[29]) }, + { "f30", offsetof(CPUState, fpr[30]) }, + { "f31", offsetof(CPUState, fpr[31]) }, + { "fpscr", offsetof(CPUState, fpscr) }, + /* Next instruction pointer */ { "nip|pc", offsetof(CPUState, nip) }, { "lr", offsetof(CPUState, lr) }, { "ctr", offsetof(CPUState, ctr) }, { "decr", 0, &monitor_get_decr, }, { "ccr", 0, &monitor_get_ccr, }, + /* Machine state register */ { "msr", 0, &monitor_get_msr, }, { "xer", 0, &monitor_get_xer, }, { "tbu", 0, &monitor_get_tbu, }, { "tbl", 0, &monitor_get_tbl, }, +#if defined(TARGET_PPC64) + /* Address space register */ + { "asr", offsetof(CPUState, asr) }, +#endif + /* Segment registers */ { "sdr1", offsetof(CPUState, sdr1) }, { "sr0", offsetof(CPUState, sr[0]) }, { "sr1", offsetof(CPUState, sr[1]) }, -- cgit v1.2.3 From cbecba264bb870608ffbf7c9df8102116432a7df Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 20 Sep 2007 09:44:48 +0000 Subject: Move likely and unlikely macros in a common place (Aurelien Jarno). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3192 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 3 +++ target-alpha/cpu.h | 4 ---- target-ppc/cpu.h | 4 ---- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/exec-all.h b/exec-all.h index 434605d8d..39cb536ad 100644 --- a/exec-all.h +++ b/exec-all.h @@ -32,6 +32,9 @@ #define __builtin_expect(x, n) (x) #endif +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + #ifdef __i386__ #define REGPARM(n) __attribute((regparm(n))) #else diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index b219ad38b..3f517e67b 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -32,10 +32,6 @@ #include "softfloat.h" -/* XXX: put this in a common place */ -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) - #define TARGET_HAS_ICE 1 #define ELF_MACHINE EM_ALPHA diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f36c97924..3ca22e57b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -88,10 +88,6 @@ typedef uint32_t ppc_gpr_t; #define ICACHE_LINE_SIZE 32 #define DCACHE_LINE_SIZE 32 -/* XXX: put this in a common place */ -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) - /*****************************************************************************/ /* PVR definitions for most known PowerPC */ enum { -- cgit v1.2.3 From a50a6282d7d3b40a4c9aa64a174f2cae5dbb5472 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 20 Sep 2007 12:42:24 +0000 Subject: Use logfile only when loglevel is set (http://bugzilla.openmoko.org/cgi-bin/bugz illa/show_bug.cgi?id=886). raw_pread() and raw_pwrite() are expected to return number of bytes read. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3193 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/block-raw.c b/block-raw.c index b7a3eb698..7c6f9640b 100644 --- a/block-raw.c +++ b/block-raw.c @@ -61,7 +61,8 @@ #define DEBUG_BLOCK #if defined(DEBUG_BLOCK) && !defined(QEMU_TOOL) -#define DEBUG_BLOCK_PRINT(formatCstr, args...) fprintf(logfile, formatCstr, ##args); fflush(logfile) +#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ + { fprintf(stderr, formatCstr, ##args); fflush(stderr); } } while (0) #else #define DEBUG_BLOCK_PRINT(formatCstr, args...) #endif @@ -162,7 +163,7 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, if (ret == count) goto label__raw_read__success; - DEBUG_BLOCK_PRINT("raw_read(%d:%s, %lld, %p, %d) [%lld] read failed %d : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] read failed %d : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, ret, errno, strerror(errno)); @@ -177,13 +178,11 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, if (ret == count) goto label__raw_read__success; - DEBUG_BLOCK_PRINT("raw_read(%d:%s, %lld, %p, %d) [%lld] retry read failed %d : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] retry read failed %d : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, ret, errno, strerror(errno)); } - return -1; - label__raw_read__success: return ret; @@ -202,7 +201,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { ++(s->lseek_err_cnt); if(s->lseek_err_cnt) { - DEBUG_BLOCK_PRINT("raw_write(%d:%s, %lld, %p, %d) [%lld] lseek failed : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %lld, %p, %d) [%lld] lseek failed : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, errno, strerror(errno)); } @@ -214,12 +213,10 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, if (ret == count) goto label__raw_write__success; - DEBUG_BLOCK_PRINT("raw_write(%d:%s, %lld, %p, %d) [%lld] write failed %d : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %lld, %p, %d) [%lld] write failed %d : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, ret, errno, strerror(errno)); - return -1; - label__raw_write__success: return ret; -- cgit v1.2.3 From 2e03286b9ac5a27c32458a034f51deb3831dac77 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 20 Sep 2007 13:24:53 +0000 Subject: Make likely/unlikely accessible also in hw/. Revert the logfile->stderr change. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3194 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 2 +- exec-all.h | 2 ++ hw/omap.c | 3 --- vl.h | 9 +++++++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/block-raw.c b/block-raw.c index 7c6f9640b..05f830a3f 100644 --- a/block-raw.c +++ b/block-raw.c @@ -62,7 +62,7 @@ #define DEBUG_BLOCK #if defined(DEBUG_BLOCK) && !defined(QEMU_TOOL) #define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ - { fprintf(stderr, formatCstr, ##args); fflush(stderr); } } while (0) + { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0) #else #define DEBUG_BLOCK_PRINT(formatCstr, args...) #endif diff --git a/exec-all.h b/exec-all.h index 39cb536ad..ca5959742 100644 --- a/exec-all.h +++ b/exec-all.h @@ -28,12 +28,14 @@ #define tostring(s) #s #endif +#ifndef likely #if __GNUC__ < 3 #define __builtin_expect(x, n) (x) #endif #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) +#endif #ifdef __i386__ #define REGPARM(n) __attribute((regparm(n))) diff --git a/hw/omap.c b/hw/omap.c index e56e663a1..ccd8f4ef7 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -46,9 +46,6 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, OMAP_32B_REG(addr); } -#define likely -#define unlikely - /* Interrupt Handlers */ struct omap_intr_handler_s { qemu_irq *pins; diff --git a/vl.h b/vl.h index 9e5418073..d7e12ad90 100644 --- a/vl.h +++ b/vl.h @@ -93,6 +93,15 @@ static inline char *realpath(const char *path, char *resolved_path) #define tostring(s) #s #endif +#ifndef likely +#if __GNUC__ < 3 +#define __builtin_expect(x, n) (x) +#endif + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif -- cgit v1.2.3 From 0f8a249a0ba252d7ff61410791712ae9b3449063 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 20 Sep 2007 14:54:22 +0000 Subject: Detabify git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3195 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 52 +- target-sparc/helper.c | 504 ++++---- target-sparc/op.c | 306 ++--- target-sparc/op_helper.c | 616 +++++----- target-sparc/op_mem.h | 14 +- target-sparc/translate.c | 2932 +++++++++++++++++++++++----------------------- 6 files changed, 2212 insertions(+), 2212 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 7e985e955..6f0da43b8 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -22,9 +22,9 @@ #define TARGET_HAS_ICE 1 #if !defined(TARGET_SPARC64) -#define ELF_MACHINE EM_SPARC +#define ELF_MACHINE EM_SPARC #else -#define ELF_MACHINE EM_SPARCV9 +#define ELF_MACHINE EM_SPARCV9 #endif /*#define EXCP_INTERRUPT 0x100*/ @@ -143,8 +143,8 @@ #define FSR_FCC0 (1<<10) /* MMU */ -#define MMU_E (1<<0) -#define MMU_NF (1<<1) +#define MMU_E (1<<0) +#define MMU_NF (1<<1) #define PTE_ENTRYTYPE_MASK 3 #define PTE_ACCESS_MASK 0x1c @@ -152,8 +152,8 @@ #define PTE_PPN_SHIFT 7 #define PTE_ADDR_MASK 0xffffff00 -#define PG_ACCESSED_BIT 5 -#define PG_MODIFIED_BIT 6 +#define PG_ACCESSED_BIT 5 +#define PG_MODIFIED_BIT 6 #define PG_CACHE_BIT 7 #define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT) @@ -221,7 +221,7 @@ typedef struct CPUSPARCState { uint64_t tnpc[MAXTL]; uint64_t tstate[MAXTL]; uint32_t tt[MAXTL]; - uint32_t xcc; /* Extended integer condition codes */ + uint32_t xcc; /* Extended integer condition codes */ uint32_t asi; uint32_t pstate; uint32_t tl; @@ -245,12 +245,12 @@ typedef struct CPUSPARCState { } CPUSPARCState; #if defined(TARGET_SPARC64) #define GET_FSR32(env) (env->fsr & 0xcfc1ffff) -#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ - env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL); \ +#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \ + env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL); \ } while (0) #define GET_FSR64(env) (env->fsr & 0x3fcfc1ffffULL) -#define PUT_FSR64(env, val) do { uint64_t _tmp = val; \ - env->fsr = _tmp & 0x3fcfc1c3ffULL; \ +#define PUT_FSR64(env, val) do { uint64_t _tmp = val; \ + env->fsr = _tmp & 0x3fcfc1c3ffULL; \ } while (0) #else #define GET_FSR32(env) (env->fsr) @@ -268,31 +268,31 @@ void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def); #define GET_PSR(env) (env->version | (env->psr & PSR_ICC) | \ - (env->psref? PSR_EF : 0) | \ - (env->psrpil << 8) | \ - (env->psrs? PSR_S : 0) | \ - (env->psrps? PSR_PS : 0) | \ - (env->psret? PSR_ET : 0) | env->cwp) + (env->psref? PSR_EF : 0) | \ + (env->psrpil << 8) | \ + (env->psrs? PSR_S : 0) | \ + (env->psrps? PSR_PS : 0) | \ + (env->psret? PSR_ET : 0) | env->cwp) #ifndef NO_CPU_IO_DEFS void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); #endif -#define PUT_PSR(env, val) do { int _tmp = val; \ - env->psr = _tmp & PSR_ICC; \ - env->psref = (_tmp & PSR_EF)? 1 : 0; \ - env->psrpil = (_tmp & PSR_PIL) >> 8; \ - env->psrs = (_tmp & PSR_S)? 1 : 0; \ - env->psrps = (_tmp & PSR_PS)? 1 : 0; \ - env->psret = (_tmp & PSR_ET)? 1 : 0; \ +#define PUT_PSR(env, val) do { int _tmp = val; \ + env->psr = _tmp & PSR_ICC; \ + env->psref = (_tmp & PSR_EF)? 1 : 0; \ + env->psrpil = (_tmp & PSR_PIL) >> 8; \ + env->psrs = (_tmp & PSR_S)? 1 : 0; \ + env->psrps = (_tmp & PSR_PS)? 1 : 0; \ + env->psret = (_tmp & PSR_ET)? 1 : 0; \ cpu_set_cwp(env, _tmp & PSR_CWP); \ } while (0) #ifdef TARGET_SPARC64 #define GET_CCR(env) (((env->xcc >> 20) << 4) | ((env->psr & PSR_ICC) >> 20)) -#define PUT_CCR(env, val) do { int _tmp = val; \ - env->xcc = (_tmp >> 4) << 20; \ - env->psr = (_tmp & 0xf) << 20; \ +#define PUT_CCR(env, val) do { int _tmp = val; \ + env->xcc = (_tmp >> 4) << 20; \ + env->psr = (_tmp & 0xf) << 20; \ } while (0) #define GET_CWP64(env) (NWINDOWS - 1 - (env)->cwp) #define PUT_CWP64(env, val) \ diff --git a/target-sparc/helper.c b/target-sparc/helper.c index af4a8b00a..b78e5dfb8 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -99,8 +99,8 @@ static const int perm_table[2][8] = { }; int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int is_user) + int *access_index, target_ulong address, int rw, + int is_user) { int access_perms = 0; target_phys_addr_t pde_ptr; @@ -111,7 +111,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot virt_addr = address & TARGET_PAGE_MASK; if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ - *physical = address; + *physical = address; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return 0; } @@ -128,70 +128,70 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot switch (pde & PTE_ENTRYTYPE_MASK) { default: case 0: /* Invalid */ - return 1 << 2; + return 1 << 2; case 2: /* L0 PTE, maybe should not happen? */ case 3: /* Reserved */ return 4 << 2; case 1: /* L0 PDE */ - pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - return (1 << 8) | (1 << 2); - case 3: /* Reserved */ - return (1 << 8) | (4 << 2); - case 1: /* L1 PDE */ - pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + return (1 << 8) | (1 << 2); + case 3: /* Reserved */ + return (1 << 8) | (4 << 2); + case 1: /* L1 PDE */ + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - return (2 << 8) | (1 << 2); - case 3: /* Reserved */ - return (2 << 8) | (4 << 2); - case 1: /* L2 PDE */ - pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + return (2 << 8) | (1 << 2); + case 3: /* Reserved */ + return (2 << 8) | (4 << 2); + case 1: /* L2 PDE */ + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - return (3 << 8) | (1 << 2); - case 1: /* PDE, should not happen */ - case 3: /* Reserved */ - return (3 << 8) | (4 << 2); - case 2: /* L3 PTE */ - virt_addr = address & TARGET_PAGE_MASK; - page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1); - } - break; - case 2: /* L2 PTE */ - virt_addr = address & ~0x3ffff; - page_offset = address & 0x3ffff; - } - break; - case 2: /* L1 PTE */ - virt_addr = address & ~0xffffff; - page_offset = address & 0xffffff; - } + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + return (3 << 8) | (1 << 2); + case 1: /* PDE, should not happen */ + case 3: /* Reserved */ + return (3 << 8) | (4 << 2); + case 2: /* L3 PTE */ + virt_addr = address & TARGET_PAGE_MASK; + page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1); + } + break; + case 2: /* L2 PTE */ + virt_addr = address & ~0x3ffff; + page_offset = address & 0x3ffff; + } + break; + case 2: /* L1 PTE */ + virt_addr = address & ~0xffffff; + page_offset = address & 0xffffff; + } } /* update page modified and dirty bits */ is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); if (!(pde & PG_ACCESSED_MASK) || is_dirty) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_MODIFIED_MASK; + pde |= PG_ACCESSED_MASK; + if (is_dirty) + pde |= PG_MODIFIED_MASK; stl_phys_notdirty(pde_ptr, pde); } /* check access */ access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; error_code = access_table[*access_index][access_perms]; if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) - return error_code; + return error_code; /* the page can be put in the TLB */ *prot = perm_table[is_user][access_perms]; @@ -217,18 +217,18 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); if (error_code == 0) { - vaddr = address & TARGET_PAGE_MASK; - paddr &= TARGET_PAGE_MASK; + vaddr = address & TARGET_PAGE_MASK; + paddr &= TARGET_PAGE_MASK; #ifdef DEBUG_MMU - printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " + printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " TARGET_FMT_lx "\n", address, paddr, vaddr); #endif - ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); - return ret; + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); + return ret; } if (env->mmuregs[3]) /* Fault status register */ - env->mmuregs[3] = 1; /* overflow (not read before another fault) */ + env->mmuregs[3] = 1; /* overflow (not read before another fault) */ env->mmuregs[3] |= (access_index << 5) | error_code | 2; env->mmuregs[4] = address; /* Fault address register */ @@ -237,10 +237,10 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, // permissions. If no mapping is available, redirect accesses to // neverland. Fake/overridden mappings will be flushed when // switching to normal mode. - vaddr = address & TARGET_PAGE_MASK; + vaddr = address & TARGET_PAGE_MASK; prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); - return ret; + return ret; } else { if (rw & 2) env->exception_index = TT_TFAULT; @@ -265,50 +265,50 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) case 0: /* Invalid */ case 2: /* PTE, maybe should not happen? */ case 3: /* Reserved */ - return 0; + return 0; case 1: /* L1 PDE */ - if (mmulev == 3) - return pde; - pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); + if (mmulev == 3) + return pde; + pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 3: /* Reserved */ - return 0; - case 2: /* L1 PTE */ - return pde; - case 1: /* L2 PDE */ - if (mmulev == 2) - return pde; - pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L1 PTE */ + return pde; + case 1: /* L2 PDE */ + if (mmulev == 2) + return pde; + pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 3: /* Reserved */ - return 0; - case 2: /* L2 PTE */ - return pde; - case 1: /* L3 PDE */ - if (mmulev == 1) - return pde; - pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 3: /* Reserved */ + return 0; + case 2: /* L2 PTE */ + return pde; + case 1: /* L3 PDE */ + if (mmulev == 1) + return pde; + pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); pde = ldl_phys(pde_ptr); - switch (pde & PTE_ENTRYTYPE_MASK) { - default: - case 0: /* Invalid */ - case 1: /* PDE, should not happen */ - case 3: /* Reserved */ - return 0; - case 2: /* L3 PTE */ - return pde; - } - } - } + switch (pde & PTE_ENTRYTYPE_MASK) { + default: + case 0: /* Invalid */ + case 1: /* PDE, should not happen */ + case 3: /* Reserved */ + return 0; + case 2: /* L3 PTE */ + return pde; + } + } + } } return 0; } @@ -327,29 +327,29 @@ void dump_mmu(CPUState *env) printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n", (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { - pde = mmu_probe(env, va, 2); - if (pde) { - pa = cpu_get_phys_page_debug(env, va); - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx + pde = mmu_probe(env, va, 2); + if (pde) { + pa = cpu_get_phys_page_debug(env, va); + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", va, pa, pde); - for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { - pde = mmu_probe(env, va1, 1); - if (pde) { - pa = cpu_get_phys_page_debug(env, va1); - printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx + for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { + pde = mmu_probe(env, va1, 1); + if (pde) { + pa = cpu_get_phys_page_debug(env, va1); + printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde); - for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { - pde = mmu_probe(env, va2, 0); - if (pde) { - pa = cpu_get_phys_page_debug(env, va2); - printf(" VA: " TARGET_FMT_lx ", PA: " + for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { + pde = mmu_probe(env, va2, 0); + if (pde) { + pa = cpu_get_phys_page_debug(env, va2); + printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde); - } - } - } - } - } + } + } + } + } + } } printf("MMU dump ends\n"); } @@ -360,57 +360,57 @@ void dump_mmu(CPUState *env) * UltraSparc IIi I/DMMUs */ static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int is_user) + int *access_index, target_ulong address, int rw, + int is_user) { target_ulong mask; unsigned int i; if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ - *physical = address; - *prot = PAGE_READ | PAGE_WRITE; + *physical = address; + *prot = PAGE_READ | PAGE_WRITE; return 0; } for (i = 0; i < 64; i++) { - switch ((env->dtlb_tte[i] >> 61) & 3) { - default: - case 0x0: // 8k - mask = 0xffffffffffffe000ULL; - break; - case 0x1: // 64k - mask = 0xffffffffffff0000ULL; - break; - case 0x2: // 512k - mask = 0xfffffffffff80000ULL; - break; - case 0x3: // 4M - mask = 0xffffffffffc00000ULL; - break; - } - // ctx match, vaddr match? - if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) && - (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) { - // valid, access ok? - if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 || - ((env->dtlb_tte[i] & 0x4) && is_user) || - (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { - if (env->dmmuregs[3]) /* Fault status register */ - env->dmmuregs[3] = 2; /* overflow (not read before another fault) */ - env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1; - env->dmmuregs[4] = address; /* Fault address register */ - env->exception_index = TT_DFAULT; + switch ((env->dtlb_tte[i] >> 61) & 3) { + default: + case 0x0: // 8k + mask = 0xffffffffffffe000ULL; + break; + case 0x1: // 64k + mask = 0xffffffffffff0000ULL; + break; + case 0x2: // 512k + mask = 0xfffffffffff80000ULL; + break; + case 0x3: // 4M + mask = 0xffffffffffc00000ULL; + break; + } + // ctx match, vaddr match? + if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) && + (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) { + // valid, access ok? + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 || + ((env->dtlb_tte[i] & 0x4) && is_user) || + (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) { + if (env->dmmuregs[3]) /* Fault status register */ + env->dmmuregs[3] = 2; /* overflow (not read before another fault) */ + env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1; + env->dmmuregs[4] = address; /* Fault address register */ + env->exception_index = TT_DFAULT; #ifdef DEBUG_MMU - printf("DFAULT at 0x%" PRIx64 "\n", address); + printf("DFAULT at 0x%" PRIx64 "\n", address); #endif - return 1; - } - *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); - *prot = PAGE_READ; - if (env->dtlb_tte[i] & 0x2) - *prot |= PAGE_WRITE; - return 0; - } + return 1; + } + *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); + *prot = PAGE_READ; + if (env->dtlb_tte[i] & 0x2) + *prot |= PAGE_WRITE; + return 0; + } } #ifdef DEBUG_MMU printf("DMISS at 0x%" PRIx64 "\n", address); @@ -420,53 +420,53 @@ static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical } static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int is_user) + int *access_index, target_ulong address, int rw, + int is_user) { target_ulong mask; unsigned int i; if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */ - *physical = address; - *prot = PAGE_EXEC; + *physical = address; + *prot = PAGE_EXEC; return 0; } for (i = 0; i < 64; i++) { - switch ((env->itlb_tte[i] >> 61) & 3) { - default: - case 0x0: // 8k - mask = 0xffffffffffffe000ULL; - break; - case 0x1: // 64k - mask = 0xffffffffffff0000ULL; - break; - case 0x2: // 512k - mask = 0xfffffffffff80000ULL; - break; - case 0x3: // 4M - mask = 0xffffffffffc00000ULL; - break; - } - // ctx match, vaddr match? - if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) && - (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) { - // valid, access ok? - if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 || - ((env->itlb_tte[i] & 0x4) && is_user)) { - if (env->immuregs[3]) /* Fault status register */ - env->immuregs[3] = 2; /* overflow (not read before another fault) */ - env->immuregs[3] |= (is_user << 3) | 1; - env->exception_index = TT_TFAULT; + switch ((env->itlb_tte[i] >> 61) & 3) { + default: + case 0x0: // 8k + mask = 0xffffffffffffe000ULL; + break; + case 0x1: // 64k + mask = 0xffffffffffff0000ULL; + break; + case 0x2: // 512k + mask = 0xfffffffffff80000ULL; + break; + case 0x3: // 4M + mask = 0xffffffffffc00000ULL; + break; + } + // ctx match, vaddr match? + if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) && + (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) { + // valid, access ok? + if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 || + ((env->itlb_tte[i] & 0x4) && is_user)) { + if (env->immuregs[3]) /* Fault status register */ + env->immuregs[3] = 2; /* overflow (not read before another fault) */ + env->immuregs[3] |= (is_user << 3) | 1; + env->exception_index = TT_TFAULT; #ifdef DEBUG_MMU - printf("TFAULT at 0x%" PRIx64 "\n", address); + printf("TFAULT at 0x%" PRIx64 "\n", address); #endif - return 1; - } - *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); - *prot = PAGE_EXEC; - return 0; - } + return 1; + } + *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL); + *prot = PAGE_EXEC; + return 0; + } } #ifdef DEBUG_MMU printf("TMISS at 0x%" PRIx64 "\n", address); @@ -476,13 +476,13 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical } int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot, - int *access_index, target_ulong address, int rw, - int is_user) + int *access_index, target_ulong address, int rw, + int is_user) { if (rw == 2) - return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user); + return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user); else - return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user); + return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user); } /* Perform address translation */ @@ -495,13 +495,13 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); if (error_code == 0) { - virt_addr = address & TARGET_PAGE_MASK; - vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); + virt_addr = address & TARGET_PAGE_MASK; + vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); #ifdef DEBUG_MMU - printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr); + printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr); #endif - ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); - return ret; + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); + return ret; } // XXX return 1; @@ -515,67 +515,67 @@ void dump_mmu(CPUState *env) printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", env->dmmuregs[1], env->dmmuregs[2]); if ((env->lsu & DMMU_E) == 0) { - printf("DMMU disabled\n"); + printf("DMMU disabled\n"); } else { - printf("DMMU dump:\n"); - for (i = 0; i < 64; i++) { - switch ((env->dtlb_tte[i] >> 61) & 3) { - default: - case 0x0: - mask = " 8k"; - break; - case 0x1: - mask = " 64k"; - break; - case 0x2: - mask = "512k"; - break; - case 0x3: - mask = " 4M"; - break; - } - if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n", - env->dtlb_tag[i] & ~0x1fffULL, - env->dtlb_tte[i] & 0x1ffffffe000ULL, - mask, - env->dtlb_tte[i] & 0x4? "priv": "user", - env->dtlb_tte[i] & 0x2? "RW": "RO", - env->dtlb_tte[i] & 0x40? "locked": "unlocked", - env->dtlb_tag[i] & 0x1fffULL); - } - } + printf("DMMU dump:\n"); + for (i = 0; i < 64; i++) { + switch ((env->dtlb_tte[i] >> 61) & 3) { + default: + case 0x0: + mask = " 8k"; + break; + case 0x1: + mask = " 64k"; + break; + case 0x2: + mask = "512k"; + break; + case 0x3: + mask = " 4M"; + break; + } + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n", + env->dtlb_tag[i] & ~0x1fffULL, + env->dtlb_tte[i] & 0x1ffffffe000ULL, + mask, + env->dtlb_tte[i] & 0x4? "priv": "user", + env->dtlb_tte[i] & 0x2? "RW": "RO", + env->dtlb_tte[i] & 0x40? "locked": "unlocked", + env->dtlb_tag[i] & 0x1fffULL); + } + } } if ((env->lsu & IMMU_E) == 0) { - printf("IMMU disabled\n"); + printf("IMMU disabled\n"); } else { - printf("IMMU dump:\n"); - for (i = 0; i < 64; i++) { - switch ((env->itlb_tte[i] >> 61) & 3) { - default: - case 0x0: - mask = " 8k"; - break; - case 0x1: - mask = " 64k"; - break; - case 0x2: - mask = "512k"; - break; - case 0x3: - mask = " 4M"; - break; - } - if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n", - env->itlb_tag[i] & ~0x1fffULL, - env->itlb_tte[i] & 0x1ffffffe000ULL, - mask, - env->itlb_tte[i] & 0x4? "priv": "user", - env->itlb_tte[i] & 0x40? "locked": "unlocked", - env->itlb_tag[i] & 0x1fffULL); - } - } + printf("IMMU dump:\n"); + for (i = 0; i < 64; i++) { + switch ((env->itlb_tte[i] >> 61) & 3) { + default: + case 0x0: + mask = " 8k"; + break; + case 0x1: + mask = " 64k"; + break; + case 0x2: + mask = "512k"; + break; + case 0x3: + mask = " 4M"; + break; + } + if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { + printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n", + env->itlb_tag[i] & ~0x1fffULL, + env->itlb_tte[i] & 0x1ffffffe000ULL, + mask, + env->itlb_tte[i] & 0x4? "priv": "user", + env->itlb_tte[i] & 0x40? "locked": "unlocked", + env->itlb_tag[i] & 0x1fffULL); + } + } } } #endif /* DEBUG_MMU */ diff --git a/target-sparc/op.c b/target-sparc/op.c index 683de5ada..31bf5dd51 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -376,33 +376,33 @@ void OPPROTO op_add_T1_T0_cc(void) env->psr = 0; #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; env->xcc = 0; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; if (T0 < src1) - env->xcc |= PSR_CARRY; + env->xcc |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; + env->xcc |= PSR_OVF; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (T0 < src1) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; #endif FORCE_RET(); } @@ -448,26 +448,26 @@ void OPPROTO op_addx_T1_T0_cc(void) } #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; + env->xcc |= PSR_OVF; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; #endif FORCE_RET(); } @@ -481,37 +481,37 @@ void OPPROTO op_tadd_T1_T0_cc(void) env->psr = 0; #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; if ((src1 & 0x03) || (T1 & 0x03)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; env->xcc = 0; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; if (T0 < src1) - env->xcc |= PSR_CARRY; + env->xcc |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; + env->xcc |= PSR_OVF; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (T0 < src1) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; if ((src1 & 0x03) || (T1 & 0x03)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; #endif FORCE_RET(); } @@ -528,7 +528,7 @@ void OPPROTO op_tadd_T1_T0_ccTV(void) #ifdef TARGET_SPARC64 if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) raise_exception(TT_TOVF); #else if ((src1 & 0x03) || (T1 & 0x03)) @@ -538,26 +538,26 @@ void OPPROTO op_tadd_T1_T0_ccTV(void) env->psr = 0; #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; env->xcc = 0; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; if (T0 < src1) - env->xcc |= PSR_CARRY; + env->xcc |= PSR_CARRY; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (T0 < src1) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; #endif FORCE_RET(); } @@ -576,33 +576,33 @@ void OPPROTO op_sub_T1_T0_cc(void) env->psr = 0; #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; env->xcc = 0; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; if (src1 < T1) - env->xcc |= PSR_CARRY; + env->xcc |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; + env->xcc |= PSR_OVF; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (src1 < T1) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; #endif FORCE_RET(); } @@ -648,26 +648,26 @@ void OPPROTO op_subx_T1_T0_cc(void) } #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; + env->xcc |= PSR_OVF; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; #endif FORCE_RET(); } @@ -681,37 +681,37 @@ void OPPROTO op_tsub_T1_T0_cc(void) env->psr = 0; #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) - env->psr |= PSR_OVF; + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; if ((src1 & 0x03) || (T1 & 0x03)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; env->xcc = 0; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; if (src1 < T1) - env->xcc |= PSR_CARRY; + env->xcc |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) - env->xcc |= PSR_OVF; + env->xcc |= PSR_OVF; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (src1 < T1) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; if ((src1 & 0x03) || (T1 & 0x03)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; #endif FORCE_RET(); } @@ -728,7 +728,7 @@ void OPPROTO op_tsub_T1_T0_ccTV(void) #ifdef TARGET_SPARC64 if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & - ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) raise_exception(TT_TOVF); #else if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) @@ -738,26 +738,26 @@ void OPPROTO op_tsub_T1_T0_ccTV(void) env->psr = 0; #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; env->xcc = 0; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; if (src1 < T1) - env->xcc |= PSR_CARRY; + env->xcc |= PSR_CARRY; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (src1 < T1) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; #endif FORCE_RET(); } @@ -833,13 +833,13 @@ void OPPROTO op_mulscc_T1_T0(void) T0 += T1; env->psr = 0; if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (T0 < src1) - env->psr |= PSR_CARRY; + env->psr |= PSR_CARRY; if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; env->y = (b2 << 31) | (env->y >> 1); FORCE_RET(); } @@ -858,11 +858,11 @@ void OPPROTO op_udiv_T1_T0(void) x0 = x0 / x1; if (x0 > 0xffffffff) { - T0 = 0xffffffff; - T1 = 1; + T0 = 0xffffffff; + T1 = 1; } else { - T0 = x0; - T1 = 0; + T0 = x0; + T1 = 0; } FORCE_RET(); } @@ -881,11 +881,11 @@ void OPPROTO op_sdiv_T1_T0(void) x0 = x0 / x1; if ((int32_t) x0 != x0) { - T0 = x0 < 0? 0x80000000: 0x7fffffff; - T1 = 1; + T0 = x0 < 0? 0x80000000: 0x7fffffff; + T1 = 1; } else { - T0 = x0; - T1 = 0; + T0 = x0; + T1 = 0; } FORCE_RET(); } @@ -895,24 +895,24 @@ void OPPROTO op_div_cc(void) env->psr = 0; #ifdef TARGET_SPARC64 if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (T1) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; env->xcc = 0; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; if (T1) - env->psr |= PSR_OVF; + env->psr |= PSR_OVF; #endif FORCE_RET(); } @@ -939,9 +939,9 @@ void OPPROTO op_sdivx_T1_T0(void) raise_exception(TT_DIV_ZERO); } if (T0 == INT64_MIN && T1 == -1) - T0 = INT64_MIN; + T0 = INT64_MIN; else - T0 /= (target_long) T1; + T0 /= (target_long) T1; FORCE_RET(); } #endif @@ -951,20 +951,20 @@ void OPPROTO op_logic_T0_cc(void) env->psr = 0; #ifdef TARGET_SPARC64 if (!(T0 & 0xffffffff)) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; env->xcc = 0; if (!T0) - env->xcc |= PSR_ZERO; + env->xcc |= PSR_ZERO; if ((int64_t) T0 < 0) - env->xcc |= PSR_NEG; + env->xcc |= PSR_NEG; #else if (!T0) - env->psr |= PSR_ZERO; + env->psr |= PSR_ZERO; if ((int32_t) T0 < 0) - env->psr |= PSR_NEG; + env->psr |= PSR_NEG; #endif FORCE_RET(); } @@ -1200,17 +1200,17 @@ void OPPROTO op_save(void) cwp = (env->cwp - 1) & (NWINDOWS - 1); if (env->cansave == 0) { raise_exception(TT_SPILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); } else { - if (env->cleanwin - env->canrestore == 0) { - // XXX Clean windows without trap - raise_exception(TT_CLRWIN); - } else { - env->cansave--; - env->canrestore++; - set_cwp(cwp); - } + if (env->cleanwin - env->canrestore == 0) { + // XXX Clean windows without trap + raise_exception(TT_CLRWIN); + } else { + env->cansave--; + env->canrestore++; + set_cwp(cwp); + } } FORCE_RET(); } @@ -1221,12 +1221,12 @@ void OPPROTO op_restore(void) cwp = (env->cwp + 1) & (NWINDOWS - 1); if (env->canrestore == 0) { raise_exception(TT_FILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); } else { - env->cansave++; - env->canrestore--; - set_cwp(cwp); + env->cansave++; + env->canrestore--; + set_cwp(cwp); } FORCE_RET(); } @@ -1576,15 +1576,15 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void) #define F_BINOP(name) \ F_OP(name, s) \ { \ - set_float_exception_flags(0, &env->fp_status); \ + set_float_exception_flags(0, &env->fp_status); \ FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \ - check_ieee_exceptions(); \ + check_ieee_exceptions(); \ } \ F_OP(name, d) \ { \ - set_float_exception_flags(0, &env->fp_status); \ + set_float_exception_flags(0, &env->fp_status); \ DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ - check_ieee_exceptions(); \ + check_ieee_exceptions(); \ } F_BINOP(add); @@ -1784,27 +1784,27 @@ void OPPROTO op_fdtox(void) void OPPROTO op_fmovs_cc(void) { if (T2) - FT0 = FT1; + FT0 = FT1; } void OPPROTO op_fmovd_cc(void) { if (T2) - DT0 = DT1; + DT0 = DT1; } void OPPROTO op_mov_cc(void) { if (T2) - T0 = T1; + T0 = T1; } void OPPROTO op_flushw(void) { if (env->cansave != NWINDOWS - 2) { raise_exception(TT_SPILL | (env->otherwin != 0 ? - (TT_WOTHER | ((env->wstate & 0x38) >> 1)): - ((env->wstate & 0x7) << 2))); + (TT_WOTHER | ((env->wstate & 0x38) >> 1)): + ((env->wstate & 0x7) << 2))); } } @@ -1812,9 +1812,9 @@ void OPPROTO op_saved(void) { env->cansave++; if (env->otherwin == 0) - env->canrestore--; + env->canrestore--; else - env->otherwin--; + env->otherwin--; FORCE_RET(); } @@ -1822,11 +1822,11 @@ void OPPROTO op_restored(void) { env->canrestore++; if (env->cleanwin < NWINDOWS - 1) - env->cleanwin++; + env->cleanwin++; if (env->otherwin == 0) - env->cansave--; + env->cansave--; else - env->otherwin--; + env->otherwin--; FORCE_RET(); } diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 043a84966..98c4a1ba4 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -16,29 +16,29 @@ void check_ieee_exceptions() T0 = get_float_exception_flags(&env->fp_status); if (T0) { - /* Copy IEEE 754 flags into FSR */ - if (T0 & float_flag_invalid) - env->fsr |= FSR_NVC; - if (T0 & float_flag_overflow) - env->fsr |= FSR_OFC; - if (T0 & float_flag_underflow) - env->fsr |= FSR_UFC; - if (T0 & float_flag_divbyzero) - env->fsr |= FSR_DZC; - if (T0 & float_flag_inexact) - env->fsr |= FSR_NXC; - - if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) - { - /* Unmasked exception, generate a trap */ - env->fsr |= FSR_FTT_IEEE_EXCP; - raise_exception(TT_FP_EXCP); - } - else - { - /* Accumulate exceptions */ - env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; - } + /* Copy IEEE 754 flags into FSR */ + if (T0 & float_flag_invalid) + env->fsr |= FSR_NVC; + if (T0 & float_flag_overflow) + env->fsr |= FSR_OFC; + if (T0 & float_flag_underflow) + env->fsr |= FSR_UFC; + if (T0 & float_flag_divbyzero) + env->fsr |= FSR_DZC; + if (T0 & float_flag_inexact) + env->fsr |= FSR_NXC; + + if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) + { + /* Unmasked exception, generate a trap */ + env->fsr |= FSR_FTT_IEEE_EXCP; + raise_exception(TT_FP_EXCP); + } + else + { + /* Accumulate exceptions */ + env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; + } } } @@ -155,33 +155,33 @@ void helper_ld_asi(int asi, int size, int sign) case 2: /* SuperSparc MXCC registers */ break; case 3: /* MMU probe */ - { - int mmulev; - - mmulev = (T0 >> 8) & 15; - if (mmulev > 4) - ret = 0; - else { - ret = mmu_probe(env, T0, mmulev); - //bswap32s(&ret); - } + { + int mmulev; + + mmulev = (T0 >> 8) & 15; + if (mmulev > 4) + ret = 0; + else { + ret = mmu_probe(env, T0, mmulev); + //bswap32s(&ret); + } #ifdef DEBUG_MMU - printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); + printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); #endif - } - break; + } + break; case 4: /* read MMU regs */ - { - int reg = (T0 >> 8) & 0xf; + { + int reg = (T0 >> 8) & 0xf; - ret = env->mmuregs[reg]; - if (reg == 3) /* Fault status cleared on read */ - env->mmuregs[reg] = 0; + ret = env->mmuregs[reg]; + if (reg == 3) /* Fault status cleared on read */ + env->mmuregs[reg] = 0; #ifdef DEBUG_MMU - printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret); + printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret); #endif - } - break; + } + break; case 9: /* Supervisor code access */ switch(size) { case 1: @@ -218,11 +218,11 @@ void helper_ld_asi(int asi, int size, int sign) ret = ldl_phys(T0 & ~3); break; case 8: - ret = ldl_phys(T0 & ~3); - T0 = ldl_phys((T0 + 4) & ~3); - break; + ret = ldl_phys(T0 & ~3); + T0 = ldl_phys((T0 + 4) & ~3); + break; } - break; + break; case 0x2e: /* MMU passthrough, 0xexxxxxxxx */ case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */ switch(size) { @@ -244,14 +244,14 @@ void helper_ld_asi(int asi, int size, int sign) | ((target_phys_addr_t)(asi & 0xf) << 32)); T0 = ldl_phys((target_phys_addr_t)((T0 + 4) & ~3) | ((target_phys_addr_t)(asi & 0xf) << 32)); - break; + break; } - break; + break; case 0x21 ... 0x2d: /* MMU passthrough, unassigned */ default: do_unassigned_access(T0, 0, 0, 1); - ret = 0; - break; + ret = 0; + break; } T1 = ret; } @@ -262,48 +262,48 @@ void helper_st_asi(int asi, int size, int sign) case 2: /* SuperSparc MXCC registers */ break; case 3: /* MMU flush */ - { - int mmulev; + { + int mmulev; - mmulev = (T0 >> 8) & 15; + mmulev = (T0 >> 8) & 15; #ifdef DEBUG_MMU - printf("mmu flush level %d\n", mmulev); + printf("mmu flush level %d\n", mmulev); #endif - switch (mmulev) { - case 0: // flush page - tlb_flush_page(env, T0 & 0xfffff000); - break; - case 1: // flush segment (256k) - case 2: // flush region (16M) - case 3: // flush context (4G) - case 4: // flush entire - tlb_flush(env, 1); - break; - default: - break; - } + switch (mmulev) { + case 0: // flush page + tlb_flush_page(env, T0 & 0xfffff000); + break; + case 1: // flush segment (256k) + case 2: // flush region (16M) + case 3: // flush context (4G) + case 4: // flush entire + tlb_flush(env, 1); + break; + default: + break; + } #ifdef DEBUG_MMU - dump_mmu(env); + dump_mmu(env); #endif - return; - } + return; + } case 4: /* write MMU regs */ - { - int reg = (T0 >> 8) & 0xf; - uint32_t oldreg; + { + int reg = (T0 >> 8) & 0xf; + uint32_t oldreg; - oldreg = env->mmuregs[reg]; + oldreg = env->mmuregs[reg]; switch(reg) { case 0: - env->mmuregs[reg] &= ~(MMU_E | MMU_NF); - env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); - // Mappings generated during no-fault mode or MMU - // disabled mode are invalid in normal mode + env->mmuregs[reg] &= ~(MMU_E | MMU_NF); + env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); + // Mappings generated during no-fault mode or MMU + // disabled mode are invalid in normal mode if (oldreg != env->mmuregs[reg]) tlb_flush(env, 1); break; case 2: - env->mmuregs[reg] = T1; + env->mmuregs[reg] = T1; if (oldreg != env->mmuregs[reg]) { /* we flush when the MMU context changes because QEMU has no MMU context support */ @@ -314,17 +314,17 @@ void helper_st_asi(int asi, int size, int sign) case 4: break; default: - env->mmuregs[reg] = T1; + env->mmuregs[reg] = T1; break; } #ifdef DEBUG_MMU if (oldreg != env->mmuregs[reg]) { printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); } - dump_mmu(env); + dump_mmu(env); #endif - return; - } + return; + } case 0xc: /* I-cache tag */ case 0xd: /* I-cache data */ case 0xe: /* D-cache tag */ @@ -336,10 +336,10 @@ void helper_st_asi(int asi, int size, int sign) case 0x14: /* I/D-cache flush user */ break; case 0x17: /* Block copy, sta access */ - { - // value (T1) = src - // address (T0) = dst - // copy 32 bytes + { + // value (T1) = src + // address (T0) = dst + // copy 32 bytes unsigned int i; uint32_t src = T1 & ~3, dst = T0 & ~3, temp; @@ -347,13 +347,13 @@ void helper_st_asi(int asi, int size, int sign) temp = ldl_kernel(src); stl_kernel(dst, temp); } - } - return; + } + return; case 0x1f: /* Block fill, stda access */ - { - // value (T1, T2) - // address (T0) = dst - // fill 32 bytes + { + // value (T1, T2) + // address (T0) = dst + // fill 32 bytes unsigned int i; uint32_t dst = T0 & 7; uint64_t val; @@ -362,10 +362,10 @@ void helper_st_asi(int asi, int size, int sign) for (i = 0; i < 32; i += 8, dst += 8) stq_kernel(dst, val); - } - return; + } + return; case 0x20: /* MMU passthrough */ - { + { switch(size) { case 1: stb_phys(T0, T1); @@ -382,11 +382,11 @@ void helper_st_asi(int asi, int size, int sign) stl_phys((T0 + 4) & ~3, T2); break; } - } - return; + } + return; case 0x2e: /* MMU passthrough, 0xexxxxxxxx */ case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */ - { + { switch(size) { case 1: stb_phys((target_phys_addr_t)T0 @@ -408,8 +408,8 @@ void helper_st_asi(int asi, int size, int sign) | ((target_phys_addr_t)(asi & 0xf) << 32), T1); break; } - } - return; + } + return; case 0x31: /* Ross RT620 I-cache flush */ case 0x36: /* I-cache flash clear */ case 0x37: /* D-cache flash clear */ @@ -418,7 +418,7 @@ void helper_st_asi(int asi, int size, int sign) case 0x21 ... 0x2d: /* MMU passthrough, unassigned */ default: do_unassigned_access(T0, 1, 0, 1); - return; + return; } } @@ -429,12 +429,12 @@ void helper_ld_asi(int asi, int size, int sign) uint64_t ret = 0; if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) - raise_exception(TT_PRIV_ACT); + raise_exception(TT_PRIV_ACT); switch (asi) { case 0x14: // Bypass case 0x15: // Bypass, non-cacheable - { + { switch(size) { case 1: ret = ldub_phys(T0); @@ -450,8 +450,8 @@ void helper_ld_asi(int asi, int size, int sign) ret = ldq_phys(T0 & ~7); break; } - break; - } + break; + } case 0x04: // Nucleus case 0x0c: // Nucleus Little Endian (LE) case 0x10: // As if user primary @@ -469,58 +469,58 @@ void helper_ld_asi(int asi, int size, int sign) case 0x89: // Secondary LE case 0x8a: // Primary no-fault LE case 0x8b: // Secondary no-fault LE - // XXX - break; + // XXX + break; case 0x45: // LSU - ret = env->lsu; - break; + ret = env->lsu; + break; case 0x50: // I-MMU regs - { - int reg = (T0 >> 3) & 0xf; + { + int reg = (T0 >> 3) & 0xf; - ret = env->immuregs[reg]; - break; - } + ret = env->immuregs[reg]; + break; + } case 0x51: // I-MMU 8k TSB pointer case 0x52: // I-MMU 64k TSB pointer case 0x55: // I-MMU data access - // XXX - break; + // XXX + break; case 0x56: // I-MMU tag read - { - unsigned int i; - - for (i = 0; i < 64; i++) { - // Valid, ctx match, vaddr match - if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && - env->itlb_tag[i] == T0) { - ret = env->itlb_tag[i]; - break; - } - } - break; - } + { + unsigned int i; + + for (i = 0; i < 64; i++) { + // Valid, ctx match, vaddr match + if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && + env->itlb_tag[i] == T0) { + ret = env->itlb_tag[i]; + break; + } + } + break; + } case 0x58: // D-MMU regs - { - int reg = (T0 >> 3) & 0xf; + { + int reg = (T0 >> 3) & 0xf; - ret = env->dmmuregs[reg]; - break; - } + ret = env->dmmuregs[reg]; + break; + } case 0x5e: // D-MMU tag read - { - unsigned int i; - - for (i = 0; i < 64; i++) { - // Valid, ctx match, vaddr match - if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && - env->dtlb_tag[i] == T0) { - ret = env->dtlb_tag[i]; - break; - } - } - break; - } + { + unsigned int i; + + for (i = 0; i < 64; i++) { + // Valid, ctx match, vaddr match + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && + env->dtlb_tag[i] == T0) { + ret = env->dtlb_tag[i]; + break; + } + } + break; + } case 0x59: // D-MMU 8k TSB pointer case 0x5a: // D-MMU 64k TSB pointer case 0x5b: // D-MMU data pointer @@ -528,8 +528,8 @@ void helper_ld_asi(int asi, int size, int sign) case 0x48: // Interrupt dispatch, RO case 0x49: // Interrupt data receive case 0x7f: // Incoming interrupt vector, RO - // XXX - break; + // XXX + break; case 0x54: // I-MMU data in, WO case 0x57: // I-MMU demap, WO case 0x5c: // D-MMU data in, WO @@ -537,8 +537,8 @@ void helper_ld_asi(int asi, int size, int sign) case 0x77: // Interrupt vector, WO default: do_unassigned_access(T0, 0, 0, 1); - ret = 0; - break; + ret = 0; + break; } T1 = ret; } @@ -546,12 +546,12 @@ void helper_ld_asi(int asi, int size, int sign) void helper_st_asi(int asi, int size, int sign) { if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) - raise_exception(TT_PRIV_ACT); + raise_exception(TT_PRIV_ACT); switch(asi) { case 0x14: // Bypass case 0x15: // Bypass, non-cacheable - { + { switch(size) { case 1: stb_phys(T0, T1); @@ -567,8 +567,8 @@ void helper_st_asi(int asi, int size, int sign) stq_phys(T0 & ~7, T1); break; } - } - return; + } + return; case 0x04: // Nucleus case 0x0c: // Nucleus Little Endian (LE) case 0x10: // As if user primary @@ -582,31 +582,31 @@ void helper_st_asi(int asi, int size, int sign) case 0x4a: // UPA config case 0x88: // Primary LE case 0x89: // Secondary LE - // XXX - return; + // XXX + return; case 0x45: // LSU - { - uint64_t oldreg; - - oldreg = env->lsu; - env->lsu = T1 & (DMMU_E | IMMU_E); - // Mappings generated during D/I MMU disabled mode are - // invalid in normal mode - if (oldreg != env->lsu) { + { + uint64_t oldreg; + + oldreg = env->lsu; + env->lsu = T1 & (DMMU_E | IMMU_E); + // Mappings generated during D/I MMU disabled mode are + // invalid in normal mode + if (oldreg != env->lsu) { #ifdef DEBUG_MMU printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu); - dump_mmu(env); + dump_mmu(env); #endif - tlb_flush(env, 1); - } - return; - } + tlb_flush(env, 1); + } + return; + } case 0x50: // I-MMU regs - { - int reg = (T0 >> 3) & 0xf; - uint64_t oldreg; + { + int reg = (T0 >> 3) & 0xf; + uint64_t oldreg; - oldreg = env->immuregs[reg]; + oldreg = env->immuregs[reg]; switch(reg) { case 0: // RO case 4: @@ -617,73 +617,73 @@ void helper_st_asi(int asi, int size, int sign) case 8: return; case 3: // SFSR - if ((T1 & 1) == 0) - T1 = 0; // Clear SFSR + if ((T1 & 1) == 0) + T1 = 0; // Clear SFSR break; case 5: // TSB access case 6: // Tag access default: break; } - env->immuregs[reg] = T1; + env->immuregs[reg] = T1; #ifdef DEBUG_MMU if (oldreg != env->immuregs[reg]) { printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]); } - dump_mmu(env); + dump_mmu(env); #endif - return; - } + return; + } case 0x54: // I-MMU data in - { - unsigned int i; - - // Try finding an invalid entry - for (i = 0; i < 64; i++) { - if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) { - env->itlb_tag[i] = env->immuregs[6]; - env->itlb_tte[i] = T1; - return; - } - } - // Try finding an unlocked entry - for (i = 0; i < 64; i++) { - if ((env->itlb_tte[i] & 0x40) == 0) { - env->itlb_tag[i] = env->immuregs[6]; - env->itlb_tte[i] = T1; - return; - } - } - // error state? - return; - } + { + unsigned int i; + + // Try finding an invalid entry + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) { + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } + } + // Try finding an unlocked entry + for (i = 0; i < 64; i++) { + if ((env->itlb_tte[i] & 0x40) == 0) { + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } + } + // error state? + return; + } case 0x55: // I-MMU data access - { - unsigned int i = (T0 >> 3) & 0x3f; + { + unsigned int i = (T0 >> 3) & 0x3f; - env->itlb_tag[i] = env->immuregs[6]; - env->itlb_tte[i] = T1; - return; - } + env->itlb_tag[i] = env->immuregs[6]; + env->itlb_tte[i] = T1; + return; + } case 0x57: // I-MMU demap - // XXX - return; + // XXX + return; case 0x58: // D-MMU regs - { - int reg = (T0 >> 3) & 0xf; - uint64_t oldreg; + { + int reg = (T0 >> 3) & 0xf; + uint64_t oldreg; - oldreg = env->dmmuregs[reg]; + oldreg = env->dmmuregs[reg]; switch(reg) { case 0: // RO case 4: return; case 3: // SFSR - if ((T1 & 1) == 0) { - T1 = 0; // Clear SFSR, Fault address - env->dmmuregs[4] = 0; - } - env->dmmuregs[reg] = T1; + if ((T1 & 1) == 0) { + T1 = 0; // Clear SFSR, Fault address + env->dmmuregs[4] = 0; + } + env->dmmuregs[reg] = T1; break; case 1: // Primary context case 2: // Secondary context @@ -694,50 +694,50 @@ void helper_st_asi(int asi, int size, int sign) default: break; } - env->dmmuregs[reg] = T1; + env->dmmuregs[reg] = T1; #ifdef DEBUG_MMU if (oldreg != env->dmmuregs[reg]) { printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); } - dump_mmu(env); + dump_mmu(env); #endif - return; - } + return; + } case 0x5c: // D-MMU data in - { - unsigned int i; - - // Try finding an invalid entry - for (i = 0; i < 64; i++) { - if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) { - env->dtlb_tag[i] = env->dmmuregs[6]; - env->dtlb_tte[i] = T1; - return; - } - } - // Try finding an unlocked entry - for (i = 0; i < 64; i++) { - if ((env->dtlb_tte[i] & 0x40) == 0) { - env->dtlb_tag[i] = env->dmmuregs[6]; - env->dtlb_tte[i] = T1; - return; - } - } - // error state? - return; - } + { + unsigned int i; + + // Try finding an invalid entry + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) { + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } + } + // Try finding an unlocked entry + for (i = 0; i < 64; i++) { + if ((env->dtlb_tte[i] & 0x40) == 0) { + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } + } + // error state? + return; + } case 0x5d: // D-MMU data access - { - unsigned int i = (T0 >> 3) & 0x3f; + { + unsigned int i = (T0 >> 3) & 0x3f; - env->dtlb_tag[i] = env->dmmuregs[6]; - env->dtlb_tte[i] = T1; - return; - } + env->dtlb_tag[i] = env->dmmuregs[6]; + env->dtlb_tte[i] = T1; + return; + } case 0x5f: // D-MMU demap case 0x49: // Interrupt data receive - // XXX - return; + // XXX + return; case 0x51: // I-MMU 8k TSB pointer, RO case 0x52: // I-MMU 64k TSB pointer, RO case 0x56: // I-MMU tag read, RO @@ -753,7 +753,7 @@ void helper_st_asi(int asi, int size, int sign) case 0x8b: // Secondary no-fault LE, RO default: do_unassigned_access(T0, 1, 0, 1); - return; + return; } } #endif @@ -783,17 +783,17 @@ void helper_ldfsr(void) switch (env->fsr & FSR_RD_MASK) { case FSR_RD_NEAREST: rnd_mode = float_round_nearest_even; - break; + break; default: case FSR_RD_ZERO: rnd_mode = float_round_to_zero; - break; + break; case FSR_RD_POS: rnd_mode = float_round_up; - break; + break; case FSR_RD_NEG: rnd_mode = float_round_down; - break; + break; } set_float_rounding_mode(rnd_mode, &env->fp_status); } @@ -835,13 +835,13 @@ static inline uint64_t *get_gregset(uint64_t pstate) switch (pstate) { default: case 0: - return env->bgregs; + return env->bgregs; case PS_AG: - return env->agregs; + return env->agregs; case PS_MG: - return env->mgregs; + return env->mgregs; case PS_IG: - return env->igregs; + return env->igregs; } } @@ -853,11 +853,11 @@ static inline void change_pstate(uint64_t new_pstate) pstate_regs = env->pstate & 0xc01; new_pstate_regs = new_pstate & 0xc01; if (new_pstate_regs != pstate_regs) { - // Switch global register bank - src = get_gregset(new_pstate_regs); - dst = get_gregset(pstate_regs); - memcpy32(dst, env->gregs); - memcpy32(env->gregs, src); + // Switch global register bank + src = get_gregset(new_pstate_regs); + dst = get_gregset(pstate_regs); + memcpy32(dst, env->gregs); + memcpy32(env->gregs, src); } env->pstate = new_pstate; } @@ -927,36 +927,36 @@ void do_interrupt(int intno) { #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_INT) { - static int count; - fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n", + static int count; + fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n", count, intno, env->pc, env->npc, env->regwptr[6]); - cpu_dump_state(env, logfile, fprintf, 0); + cpu_dump_state(env, logfile, fprintf, 0); #if 0 - { - int i; - uint8_t *ptr; - - fprintf(logfile, " code="); - ptr = (uint8_t *)env->pc; - for(i = 0; i < 16; i++) { - fprintf(logfile, " %02x", ldub(ptr + i)); - } - fprintf(logfile, "\n"); - } + { + int i; + uint8_t *ptr; + + fprintf(logfile, " code="); + ptr = (uint8_t *)env->pc; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } #endif - count++; + count++; } #endif #if !defined(CONFIG_USER_ONLY) if (env->tl == MAXTL) { cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); - return; + return; } #endif env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | - ((env->pstate & 0xf3f) << 8) | GET_CWP64(env); + ((env->pstate & 0xf3f) << 8) | GET_CWP64(env); env->tpc[env->tl] = env->pc; env->tnpc[env->tl] = env->npc; env->tt[env->tl] = intno; @@ -971,11 +971,11 @@ void do_interrupt(int intno) env->tbr &= ~0x7fffULL; env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); if (env->tl < MAXTL - 1) { - env->tl++; + env->tl++; } else { - env->pstate |= PS_RED; - if (env->tl != MAXTL) - env->tl++; + env->pstate |= PS_RED; + if (env->tl != MAXTL) + env->tl++; } env->pc = env->tbr; env->npc = env->pc + 4; @@ -988,32 +988,32 @@ void do_interrupt(int intno) #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_INT) { - static int count; - fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", + static int count; + fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", count, intno, env->pc, env->npc, env->regwptr[6]); - cpu_dump_state(env, logfile, fprintf, 0); + cpu_dump_state(env, logfile, fprintf, 0); #if 0 - { - int i; - uint8_t *ptr; - - fprintf(logfile, " code="); - ptr = (uint8_t *)env->pc; - for(i = 0; i < 16; i++) { - fprintf(logfile, " %02x", ldub(ptr + i)); - } - fprintf(logfile, "\n"); - } + { + int i; + uint8_t *ptr; + + fprintf(logfile, " code="); + ptr = (uint8_t *)env->pc; + for(i = 0; i < 16; i++) { + fprintf(logfile, " %02x", ldub(ptr + i)); + } + fprintf(logfile, "\n"); + } #endif - count++; + count++; } #endif #if !defined(CONFIG_USER_ONLY) if (env->psret == 0) { cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); - return; + return; } #endif env->psret = 0; @@ -1106,7 +1106,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, saved_env = env; env = cpu_single_env; if (env->mmuregs[3]) /* Fault status register */ - env->mmuregs[3] = 1; /* overflow (not read before another fault) */ + env->mmuregs[3] = 1; /* overflow (not read before another fault) */ if (is_asi) env->mmuregs[3] |= 1 << 16; if (env->psrs) diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index a175d0d59..ae63181c7 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -2,13 +2,13 @@ #define SPARC_LD_OP(name, qp) \ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ { \ - T1 = (target_ulong)glue(qp, MEMSUFFIX)(T0); \ + T1 = (target_ulong)glue(qp, MEMSUFFIX)(T0); \ } -#define SPARC_LD_OP_S(name, qp) \ - void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ - { \ - T1 = (target_long)glue(qp, MEMSUFFIX)(T0); \ +#define SPARC_LD_OP_S(name, qp) \ + void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ + { \ + T1 = (target_long)glue(qp, MEMSUFFIX)(T0); \ } #define SPARC_ST_OP(name, op) \ @@ -85,7 +85,7 @@ void OPPROTO glue(op_cas, MEMSUFFIX)(void) tmp = glue(ldl, MEMSUFFIX)(T0); T2 &= 0xffffffffULL; if (tmp == (T1 & 0xffffffffULL)) { - glue(stl, MEMSUFFIX)(T0, T2); + glue(stl, MEMSUFFIX)(T0, T2); } T2 = tmp; } @@ -98,7 +98,7 @@ void OPPROTO glue(op_casx, MEMSUFFIX)(void) tmp = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32; tmp |= glue(ldl, MEMSUFFIX)(T0); if (tmp == T1) { - glue(stq, MEMSUFFIX)(T0, T2); + glue(stq, MEMSUFFIX)(T0, T2); } T2 = tmp; } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 84f69fcab..a52d6717a 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -45,8 +45,8 @@ according to jump_pc[T2] */ typedef struct DisasContext { - target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ - target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ + target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ + target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ int is_br; int mem_idx; @@ -359,57 +359,57 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); #define supervisor(dc) 0 #define hypervisor(dc) 0 #define gen_op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) \ +#define OP_LD_TABLE(width) \ static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ - { \ - int asi, offset; \ - \ - if (IS_IMM) { \ - offset = GET_FIELD(insn, 25, 31); \ - if (is_ld) \ - gen_op_ld_asi_reg(offset, size, sign); \ - else \ - gen_op_st_asi_reg(offset, size, sign); \ - return; \ - } \ - asi = GET_FIELD(insn, 19, 26); \ - switch (asi) { \ - case 0x80: /* Primary address space */ \ - gen_op_##width##_raw(); \ - break; \ - case 0x82: /* Primary address space, non-faulting load */ \ - gen_op_##width##_raw(); \ - break; \ - default: \ - break; \ - } \ + { \ + int asi, offset; \ + \ + if (IS_IMM) { \ + offset = GET_FIELD(insn, 25, 31); \ + if (is_ld) \ + gen_op_ld_asi_reg(offset, size, sign); \ + else \ + gen_op_st_asi_reg(offset, size, sign); \ + return; \ + } \ + asi = GET_FIELD(insn, 19, 26); \ + switch (asi) { \ + case 0x80: /* Primary address space */ \ + gen_op_##width##_raw(); \ + break; \ + case 0x82: /* Primary address space, non-faulting load */ \ + gen_op_##width##_raw(); \ + break; \ + default: \ + break; \ + } \ } #else #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() -#define OP_LD_TABLE(width) \ +#define OP_LD_TABLE(width) \ static GenOpFunc * const gen_op_##width[] = { \ - &gen_op_##width##_user, \ - &gen_op_##width##_kernel, \ - }; \ - \ + &gen_op_##width##_user, \ + &gen_op_##width##_kernel, \ + }; \ + \ static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ - { \ - int asi, offset; \ - \ - if (IS_IMM) { \ - offset = GET_FIELD(insn, 25, 31); \ - if (is_ld) \ - gen_op_ld_asi_reg(offset, size, sign); \ - else \ - gen_op_st_asi_reg(offset, size, sign); \ - return; \ - } \ - asi = GET_FIELD(insn, 19, 26); \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ + { \ + int asi, offset; \ + \ + if (IS_IMM) { \ + offset = GET_FIELD(insn, 25, 31); \ + if (is_ld) \ + gen_op_ld_asi_reg(offset, size, sign); \ + else \ + gen_op_st_asi_reg(offset, size, sign); \ + return; \ + } \ + asi = GET_FIELD(insn, 19, 26); \ + if (is_ld) \ + gen_op_ld_asi(asi, size, sign); \ + else \ + gen_op_st_asi(asi, size, sign); \ } #define supervisor(dc) (dc->mem_idx == 1) @@ -422,7 +422,7 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); #define supervisor(dc) 0 #else #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() -#define OP_LD_TABLE(width) \ +#define OP_LD_TABLE(width) \ static GenOpFunc * const gen_op_##width[] = { \ &gen_op_##width##_user, \ &gen_op_##width##_kernel, \ @@ -434,23 +434,23 @@ static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ \ asi = GET_FIELD(insn, 19, 26); \ switch (asi) { \ - case 10: /* User data access */ \ - gen_op_##width##_user(); \ - break; \ - case 11: /* Supervisor data access */ \ - gen_op_##width##_kernel(); \ - break; \ - case 0x20 ... 0x2f: /* MMU passthrough */ \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ - break; \ - default: \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ + case 10: /* User data access */ \ + gen_op_##width##_user(); \ + break; \ + case 11: /* Supervisor data access */ \ + gen_op_##width##_kernel(); \ + break; \ + case 0x20 ... 0x2f: /* MMU passthrough */ \ + if (is_ld) \ + gen_op_ld_asi(asi, size, sign); \ + else \ + gen_op_st_asi(asi, size, sign); \ + break; \ + default: \ + if (is_ld) \ + gen_op_ld_asi(asi, size, sign); \ + else \ + gen_op_st_asi(asi, size, sign); \ break; \ } \ } @@ -518,9 +518,9 @@ static inline void gen_movl_simm_T0(int32_t val) static inline void gen_movl_reg_TN(int reg, int t) { if (reg) - gen_op_movl_reg_TN[t][reg] (); + gen_op_movl_reg_TN[t][reg] (); else - gen_movl_imm_TN(t, 0); + gen_movl_imm_TN(t, 0); } static inline void gen_movl_reg_T0(int reg) @@ -541,7 +541,7 @@ static inline void gen_movl_reg_T2(int reg) static inline void gen_movl_TN_reg(int reg, int t) { if (reg) - gen_op_movl_TN_reg[t][reg] (); + gen_op_movl_TN_reg[t][reg] (); } static inline void gen_movl_T0_reg(int reg) @@ -699,118 +699,118 @@ static inline void gen_mov_pc_npc(DisasContext * dc) static GenOpFunc * const gen_cond[2][16] = { { - gen_op_eval_bn, - gen_op_eval_be, - gen_op_eval_ble, - gen_op_eval_bl, - gen_op_eval_bleu, - gen_op_eval_bcs, - gen_op_eval_bneg, - gen_op_eval_bvs, - gen_op_eval_ba, - gen_op_eval_bne, - gen_op_eval_bg, - gen_op_eval_bge, - gen_op_eval_bgu, - gen_op_eval_bcc, - gen_op_eval_bpos, - gen_op_eval_bvc, + gen_op_eval_bn, + gen_op_eval_be, + gen_op_eval_ble, + gen_op_eval_bl, + gen_op_eval_bleu, + gen_op_eval_bcs, + gen_op_eval_bneg, + gen_op_eval_bvs, + gen_op_eval_ba, + gen_op_eval_bne, + gen_op_eval_bg, + gen_op_eval_bge, + gen_op_eval_bgu, + gen_op_eval_bcc, + gen_op_eval_bpos, + gen_op_eval_bvc, }, { #ifdef TARGET_SPARC64 - gen_op_eval_bn, - gen_op_eval_xbe, - gen_op_eval_xble, - gen_op_eval_xbl, - gen_op_eval_xbleu, - gen_op_eval_xbcs, - gen_op_eval_xbneg, - gen_op_eval_xbvs, - gen_op_eval_ba, - gen_op_eval_xbne, - gen_op_eval_xbg, - gen_op_eval_xbge, - gen_op_eval_xbgu, - gen_op_eval_xbcc, - gen_op_eval_xbpos, - gen_op_eval_xbvc, + gen_op_eval_bn, + gen_op_eval_xbe, + gen_op_eval_xble, + gen_op_eval_xbl, + gen_op_eval_xbleu, + gen_op_eval_xbcs, + gen_op_eval_xbneg, + gen_op_eval_xbvs, + gen_op_eval_ba, + gen_op_eval_xbne, + gen_op_eval_xbg, + gen_op_eval_xbge, + gen_op_eval_xbgu, + gen_op_eval_xbcc, + gen_op_eval_xbpos, + gen_op_eval_xbvc, #endif }, }; static GenOpFunc * const gen_fcond[4][16] = { { - gen_op_eval_bn, - gen_op_eval_fbne, - gen_op_eval_fblg, - gen_op_eval_fbul, - gen_op_eval_fbl, - gen_op_eval_fbug, - gen_op_eval_fbg, - gen_op_eval_fbu, - gen_op_eval_ba, - gen_op_eval_fbe, - gen_op_eval_fbue, - gen_op_eval_fbge, - gen_op_eval_fbuge, - gen_op_eval_fble, - gen_op_eval_fbule, - gen_op_eval_fbo, + gen_op_eval_bn, + gen_op_eval_fbne, + gen_op_eval_fblg, + gen_op_eval_fbul, + gen_op_eval_fbl, + gen_op_eval_fbug, + gen_op_eval_fbg, + gen_op_eval_fbu, + gen_op_eval_ba, + gen_op_eval_fbe, + gen_op_eval_fbue, + gen_op_eval_fbge, + gen_op_eval_fbuge, + gen_op_eval_fble, + gen_op_eval_fbule, + gen_op_eval_fbo, }, #ifdef TARGET_SPARC64 { - gen_op_eval_bn, - gen_op_eval_fbne_fcc1, - gen_op_eval_fblg_fcc1, - gen_op_eval_fbul_fcc1, - gen_op_eval_fbl_fcc1, - gen_op_eval_fbug_fcc1, - gen_op_eval_fbg_fcc1, - gen_op_eval_fbu_fcc1, - gen_op_eval_ba, - gen_op_eval_fbe_fcc1, - gen_op_eval_fbue_fcc1, - gen_op_eval_fbge_fcc1, - gen_op_eval_fbuge_fcc1, - gen_op_eval_fble_fcc1, - gen_op_eval_fbule_fcc1, - gen_op_eval_fbo_fcc1, + gen_op_eval_bn, + gen_op_eval_fbne_fcc1, + gen_op_eval_fblg_fcc1, + gen_op_eval_fbul_fcc1, + gen_op_eval_fbl_fcc1, + gen_op_eval_fbug_fcc1, + gen_op_eval_fbg_fcc1, + gen_op_eval_fbu_fcc1, + gen_op_eval_ba, + gen_op_eval_fbe_fcc1, + gen_op_eval_fbue_fcc1, + gen_op_eval_fbge_fcc1, + gen_op_eval_fbuge_fcc1, + gen_op_eval_fble_fcc1, + gen_op_eval_fbule_fcc1, + gen_op_eval_fbo_fcc1, }, { - gen_op_eval_bn, - gen_op_eval_fbne_fcc2, - gen_op_eval_fblg_fcc2, - gen_op_eval_fbul_fcc2, - gen_op_eval_fbl_fcc2, - gen_op_eval_fbug_fcc2, - gen_op_eval_fbg_fcc2, - gen_op_eval_fbu_fcc2, - gen_op_eval_ba, - gen_op_eval_fbe_fcc2, - gen_op_eval_fbue_fcc2, - gen_op_eval_fbge_fcc2, - gen_op_eval_fbuge_fcc2, - gen_op_eval_fble_fcc2, - gen_op_eval_fbule_fcc2, - gen_op_eval_fbo_fcc2, + gen_op_eval_bn, + gen_op_eval_fbne_fcc2, + gen_op_eval_fblg_fcc2, + gen_op_eval_fbul_fcc2, + gen_op_eval_fbl_fcc2, + gen_op_eval_fbug_fcc2, + gen_op_eval_fbg_fcc2, + gen_op_eval_fbu_fcc2, + gen_op_eval_ba, + gen_op_eval_fbe_fcc2, + gen_op_eval_fbue_fcc2, + gen_op_eval_fbge_fcc2, + gen_op_eval_fbuge_fcc2, + gen_op_eval_fble_fcc2, + gen_op_eval_fbule_fcc2, + gen_op_eval_fbo_fcc2, }, { - gen_op_eval_bn, - gen_op_eval_fbne_fcc3, - gen_op_eval_fblg_fcc3, - gen_op_eval_fbul_fcc3, - gen_op_eval_fbl_fcc3, - gen_op_eval_fbug_fcc3, - gen_op_eval_fbg_fcc3, - gen_op_eval_fbu_fcc3, - gen_op_eval_ba, - gen_op_eval_fbe_fcc3, - gen_op_eval_fbue_fcc3, - gen_op_eval_fbge_fcc3, - gen_op_eval_fbuge_fcc3, - gen_op_eval_fble_fcc3, - gen_op_eval_fbule_fcc3, - gen_op_eval_fbo_fcc3, + gen_op_eval_bn, + gen_op_eval_fbne_fcc3, + gen_op_eval_fblg_fcc3, + gen_op_eval_fbul_fcc3, + gen_op_eval_fbl_fcc3, + gen_op_eval_fbug_fcc3, + gen_op_eval_fbg_fcc3, + gen_op_eval_fbu_fcc3, + gen_op_eval_ba, + gen_op_eval_fbe_fcc3, + gen_op_eval_fbue_fcc3, + gen_op_eval_fbge_fcc3, + gen_op_eval_fbuge_fcc3, + gen_op_eval_fble_fcc3, + gen_op_eval_fbule_fcc3, + gen_op_eval_fbo_fcc3, }, #else {}, {}, {}, @@ -820,27 +820,27 @@ static GenOpFunc * const gen_fcond[4][16] = { #ifdef TARGET_SPARC64 static void gen_cond_reg(int cond) { - switch (cond) { - case 0x1: - gen_op_eval_brz(); - break; - case 0x2: - gen_op_eval_brlez(); - break; - case 0x3: - gen_op_eval_brlz(); - break; - case 0x5: - gen_op_eval_brnz(); - break; - case 0x6: - gen_op_eval_brgz(); - break; + switch (cond) { + case 0x1: + gen_op_eval_brz(); + break; + case 0x2: + gen_op_eval_brlez(); + break; + case 0x3: + gen_op_eval_brlz(); + break; + case 0x5: + gen_op_eval_brnz(); + break; + case 0x6: + gen_op_eval_brgz(); + break; default: - case 0x7: - gen_op_eval_brgez(); - break; - } + case 0x7: + gen_op_eval_brgez(); + break; + } } #endif @@ -851,35 +851,35 @@ static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) target_ulong target = dc->pc + offset; if (cond == 0x0) { - /* unconditional not taken */ - if (a) { - dc->pc = dc->npc + 4; - dc->npc = dc->pc + 4; - } else { - dc->pc = dc->npc; - dc->npc = dc->pc + 4; - } + /* unconditional not taken */ + if (a) { + dc->pc = dc->npc + 4; + dc->npc = dc->pc + 4; + } else { + dc->pc = dc->npc; + dc->npc = dc->pc + 4; + } } else if (cond == 0x8) { - /* unconditional taken */ - if (a) { - dc->pc = target; - dc->npc = dc->pc + 4; - } else { - dc->pc = dc->npc; - dc->npc = target; - } + /* unconditional taken */ + if (a) { + dc->pc = target; + dc->npc = dc->pc + 4; + } else { + dc->pc = dc->npc; + dc->npc = target; + } } else { flush_T2(dc); gen_cond[cc][cond](); - if (a) { - gen_branch_a(dc, target, dc->npc); + if (a) { + gen_branch_a(dc, target, dc->npc); dc->is_br = 1; - } else { + } else { dc->pc = dc->npc; dc->jump_pc[0] = target; dc->jump_pc[1] = dc->npc + 4; dc->npc = JUMP_PC; - } + } } } @@ -890,35 +890,35 @@ static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) target_ulong target = dc->pc + offset; if (cond == 0x0) { - /* unconditional not taken */ - if (a) { - dc->pc = dc->npc + 4; - dc->npc = dc->pc + 4; - } else { - dc->pc = dc->npc; - dc->npc = dc->pc + 4; - } + /* unconditional not taken */ + if (a) { + dc->pc = dc->npc + 4; + dc->npc = dc->pc + 4; + } else { + dc->pc = dc->npc; + dc->npc = dc->pc + 4; + } } else if (cond == 0x8) { - /* unconditional taken */ - if (a) { - dc->pc = target; - dc->npc = dc->pc + 4; - } else { - dc->pc = dc->npc; - dc->npc = target; - } + /* unconditional taken */ + if (a) { + dc->pc = target; + dc->npc = dc->pc + 4; + } else { + dc->pc = dc->npc; + dc->npc = target; + } } else { flush_T2(dc); gen_fcond[cc][cond](); - if (a) { - gen_branch_a(dc, target, dc->npc); + if (a) { + gen_branch_a(dc, target, dc->npc); dc->is_br = 1; - } else { + } else { dc->pc = dc->npc; dc->jump_pc[0] = target; dc->jump_pc[1] = dc->npc + 4; dc->npc = JUMP_PC; - } + } } } @@ -932,13 +932,13 @@ static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn) flush_T2(dc); gen_cond_reg(cond); if (a) { - gen_branch_a(dc, target, dc->npc); - dc->is_br = 1; + gen_branch_a(dc, target, dc->npc); + dc->is_br = 1; } else { - dc->pc = dc->npc; - dc->jump_pc[0] = target; - dc->jump_pc[1] = dc->npc + 4; - dc->npc = JUMP_PC; + dc->pc = dc->npc; + dc->jump_pc[0] = target; + dc->jump_pc[1] = dc->npc + 4; + dc->npc = JUMP_PC; } } @@ -995,139 +995,139 @@ static void disas_sparc_insn(DisasContext * dc) rd = GET_FIELD(insn, 2, 6); switch (opc) { - case 0: /* branches/sethi */ - { - unsigned int xop = GET_FIELD(insn, 7, 9); - int32_t target; - switch (xop) { + case 0: /* branches/sethi */ + { + unsigned int xop = GET_FIELD(insn, 7, 9); + int32_t target; + switch (xop) { #ifdef TARGET_SPARC64 - case 0x1: /* V9 BPcc */ - { - int cc; - - target = GET_FIELD_SP(insn, 0, 18); - target = sign_extend(target, 18); - target <<= 2; - cc = GET_FIELD_SP(insn, 20, 21); - if (cc == 0) - do_branch(dc, target, insn, 0); - else if (cc == 2) - do_branch(dc, target, insn, 1); - else - goto illegal_insn; - goto jmp_insn; - } - case 0x3: /* V9 BPr */ - { - target = GET_FIELD_SP(insn, 0, 13) | + case 0x1: /* V9 BPcc */ + { + int cc; + + target = GET_FIELD_SP(insn, 0, 18); + target = sign_extend(target, 18); + target <<= 2; + cc = GET_FIELD_SP(insn, 20, 21); + if (cc == 0) + do_branch(dc, target, insn, 0); + else if (cc == 2) + do_branch(dc, target, insn, 1); + else + goto illegal_insn; + goto jmp_insn; + } + case 0x3: /* V9 BPr */ + { + target = GET_FIELD_SP(insn, 0, 13) | (GET_FIELD_SP(insn, 20, 21) << 14); - target = sign_extend(target, 16); - target <<= 2; - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - do_branch_reg(dc, target, insn); - goto jmp_insn; - } - case 0x5: /* V9 FBPcc */ - { - int cc = GET_FIELD_SP(insn, 20, 21); + target = sign_extend(target, 16); + target <<= 2; + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + do_branch_reg(dc, target, insn); + goto jmp_insn; + } + case 0x5: /* V9 FBPcc */ + { + int cc = GET_FIELD_SP(insn, 20, 21); if (gen_trap_ifnofpu(dc)) goto jmp_insn; - target = GET_FIELD_SP(insn, 0, 18); - target = sign_extend(target, 19); - target <<= 2; - do_fbranch(dc, target, insn, cc); - goto jmp_insn; - } + target = GET_FIELD_SP(insn, 0, 18); + target = sign_extend(target, 19); + target <<= 2; + do_fbranch(dc, target, insn, cc); + goto jmp_insn; + } #else - case 0x7: /* CBN+x */ - { - goto ncp_insn; - } -#endif - case 0x2: /* BN+x */ - { - target = GET_FIELD(insn, 10, 31); - target = sign_extend(target, 22); - target <<= 2; - do_branch(dc, target, insn, 0); - goto jmp_insn; - } - case 0x6: /* FBN+x */ - { + case 0x7: /* CBN+x */ + { + goto ncp_insn; + } +#endif + case 0x2: /* BN+x */ + { + target = GET_FIELD(insn, 10, 31); + target = sign_extend(target, 22); + target <<= 2; + do_branch(dc, target, insn, 0); + goto jmp_insn; + } + case 0x6: /* FBN+x */ + { if (gen_trap_ifnofpu(dc)) goto jmp_insn; - target = GET_FIELD(insn, 10, 31); - target = sign_extend(target, 22); - target <<= 2; - do_fbranch(dc, target, insn, 0); - goto jmp_insn; - } - case 0x4: /* SETHI */ + target = GET_FIELD(insn, 10, 31); + target = sign_extend(target, 22); + target <<= 2; + do_fbranch(dc, target, insn, 0); + goto jmp_insn; + } + case 0x4: /* SETHI */ #define OPTIM #if defined(OPTIM) - if (rd) { // nop + if (rd) { // nop #endif - uint32_t value = GET_FIELD(insn, 10, 31); - gen_movl_imm_T0(value << 10); - gen_movl_T0_reg(rd); + uint32_t value = GET_FIELD(insn, 10, 31); + gen_movl_imm_T0(value << 10); + gen_movl_T0_reg(rd); #if defined(OPTIM) - } + } #endif - break; - case 0x0: /* UNIMPL */ - default: + break; + case 0x0: /* UNIMPL */ + default: goto illegal_insn; - } - break; - } - break; + } + break; + } + break; case 1: - /*CALL*/ { - target_long target = GET_FIELDs(insn, 2, 31) << 2; + /*CALL*/ { + target_long target = GET_FIELDs(insn, 2, 31) << 2; #ifdef TARGET_SPARC64 - if (dc->pc == (uint32_t)dc->pc) { - gen_op_movl_T0_im(dc->pc); - } else { - gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); - } + if (dc->pc == (uint32_t)dc->pc) { + gen_op_movl_T0_im(dc->pc); + } else { + gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); + } #else - gen_op_movl_T0_im(dc->pc); + gen_op_movl_T0_im(dc->pc); #endif - gen_movl_T0_reg(15); - target += dc->pc; + gen_movl_T0_reg(15); + target += dc->pc; gen_mov_pc_npc(dc); - dc->npc = target; - } - goto jmp_insn; - case 2: /* FPU & Logical Operations */ - { - unsigned int xop = GET_FIELD(insn, 7, 12); - if (xop == 0x3a) { /* generate trap */ + dc->npc = target; + } + goto jmp_insn; + case 2: /* FPU & Logical Operations */ + { + unsigned int xop = GET_FIELD(insn, 7, 12); + if (xop == 0x3a) { /* generate trap */ int cond; rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); - if (IS_IMM) { - rs2 = GET_FIELD(insn, 25, 31); + if (IS_IMM) { + rs2 = GET_FIELD(insn, 25, 31); #if defined(OPTIM) - if (rs2 != 0) { + if (rs2 != 0) { #endif - gen_movl_simm_T1(rs2); - gen_op_add_T1_T0(); + gen_movl_simm_T1(rs2); + gen_op_add_T1_T0(); #if defined(OPTIM) - } + } #endif } else { rs2 = GET_FIELD(insn, 27, 31); #if defined(OPTIM) - if (rs2 != 0) { + if (rs2 != 0) { #endif - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); #if defined(OPTIM) - } + } #endif } cond = GET_FIELD(insn, 3, 6); @@ -1136,20 +1136,20 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_trap_T0(); } else if (cond != 0) { #ifdef TARGET_SPARC64 - /* V9 icc/xcc */ - int cc = GET_FIELD_SP(insn, 11, 12); - flush_T2(dc); + /* V9 icc/xcc */ + int cc = GET_FIELD_SP(insn, 11, 12); + flush_T2(dc); save_state(dc); - if (cc == 0) - gen_cond[0][cond](); - else if (cc == 2) - gen_cond[1][cond](); - else - goto illegal_insn; + if (cc == 0) + gen_cond[0][cond](); + else if (cc == 2) + gen_cond[1][cond](); + else + goto illegal_insn; #else - flush_T2(dc); + flush_T2(dc); save_state(dc); - gen_cond[0][cond](); + gen_cond[0][cond](); #endif gen_op_trapcc_T0(); } @@ -1176,56 +1176,56 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; #ifdef TARGET_SPARC64 - case 0x2: /* V9 rdccr */ + case 0x2: /* V9 rdccr */ gen_op_rdccr(); gen_movl_T0_reg(rd); break; - case 0x3: /* V9 rdasi */ - gen_op_movl_T0_env(offsetof(CPUSPARCState, asi)); + case 0x3: /* V9 rdasi */ + gen_op_movl_T0_env(offsetof(CPUSPARCState, asi)); gen_movl_T0_reg(rd); break; - case 0x4: /* V9 rdtick */ + case 0x4: /* V9 rdtick */ gen_op_rdtick(); gen_movl_T0_reg(rd); break; - case 0x5: /* V9 rdpc */ - if (dc->pc == (uint32_t)dc->pc) { - gen_op_movl_T0_im(dc->pc); - } else { - gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); - } - gen_movl_T0_reg(rd); - break; - case 0x6: /* V9 rdfprs */ - gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs)); + case 0x5: /* V9 rdpc */ + if (dc->pc == (uint32_t)dc->pc) { + gen_op_movl_T0_im(dc->pc); + } else { + gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); + } + gen_movl_T0_reg(rd); + break; + case 0x6: /* V9 rdfprs */ + gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs)); gen_movl_T0_reg(rd); break; case 0xf: /* V9 membar */ break; /* no effect */ - case 0x13: /* Graphics Status */ + case 0x13: /* Graphics Status */ if (gen_trap_ifnofpu(dc)) goto jmp_insn; - gen_op_movtl_T0_env(offsetof(CPUSPARCState, gsr)); + gen_op_movtl_T0_env(offsetof(CPUSPARCState, gsr)); gen_movl_T0_reg(rd); break; - case 0x17: /* Tick compare */ - gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr)); + case 0x17: /* Tick compare */ + gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr)); gen_movl_T0_reg(rd); break; - case 0x18: /* System tick */ + case 0x18: /* System tick */ gen_op_rdstick(); gen_movl_T0_reg(rd); break; - case 0x19: /* System tick compare */ - gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr)); + case 0x19: /* System tick compare */ + gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr)); gen_movl_T0_reg(rd); break; - case 0x10: /* Performance Control */ - case 0x11: /* Performance Instrumentation Counter */ - case 0x12: /* Dispatch Control */ - case 0x14: /* Softint set, WO */ - case 0x15: /* Softint clear, WO */ - case 0x16: /* Softint write */ + case 0x10: /* Performance Control */ + case 0x11: /* Performance Instrumentation Counter */ + case 0x12: /* Dispatch Control */ + case 0x14: /* Softint set, WO */ + case 0x15: /* Softint clear, WO */ + case 0x16: /* Softint write */ #endif default: goto illegal_insn; @@ -1233,8 +1233,8 @@ static void disas_sparc_insn(DisasContext * dc) #if !defined(CONFIG_USER_ONLY) } else if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */ #ifndef TARGET_SPARC64 - if (!supervisor(dc)) - goto priv_insn; + if (!supervisor(dc)) + goto priv_insn; gen_op_rdpsr(); #else if (!hypervisor(dc)) @@ -1266,56 +1266,56 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; } else if (xop == 0x2a) { /* rdwim / V9 rdpr */ - if (!supervisor(dc)) - goto priv_insn; + if (!supervisor(dc)) + goto priv_insn; #ifdef TARGET_SPARC64 rs1 = GET_FIELD(insn, 13, 17); - switch (rs1) { - case 0: // tpc - gen_op_rdtpc(); - break; - case 1: // tnpc - gen_op_rdtnpc(); - break; - case 2: // tstate - gen_op_rdtstate(); - break; - case 3: // tt - gen_op_rdtt(); - break; - case 4: // tick - gen_op_rdtick(); - break; - case 5: // tba - gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); - break; - case 6: // pstate - gen_op_rdpstate(); - break; - case 7: // tl - gen_op_movl_T0_env(offsetof(CPUSPARCState, tl)); - break; - case 8: // pil - gen_op_movl_T0_env(offsetof(CPUSPARCState, psrpil)); - break; - case 9: // cwp - gen_op_rdcwp(); - break; - case 10: // cansave - gen_op_movl_T0_env(offsetof(CPUSPARCState, cansave)); - break; - case 11: // canrestore - gen_op_movl_T0_env(offsetof(CPUSPARCState, canrestore)); - break; - case 12: // cleanwin - gen_op_movl_T0_env(offsetof(CPUSPARCState, cleanwin)); - break; - case 13: // otherwin - gen_op_movl_T0_env(offsetof(CPUSPARCState, otherwin)); - break; - case 14: // wstate - gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate)); - break; + switch (rs1) { + case 0: // tpc + gen_op_rdtpc(); + break; + case 1: // tnpc + gen_op_rdtnpc(); + break; + case 2: // tstate + gen_op_rdtstate(); + break; + case 3: // tt + gen_op_rdtt(); + break; + case 4: // tick + gen_op_rdtick(); + break; + case 5: // tba + gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); + break; + case 6: // pstate + gen_op_rdpstate(); + break; + case 7: // tl + gen_op_movl_T0_env(offsetof(CPUSPARCState, tl)); + break; + case 8: // pil + gen_op_movl_T0_env(offsetof(CPUSPARCState, psrpil)); + break; + case 9: // cwp + gen_op_rdcwp(); + break; + case 10: // cansave + gen_op_movl_T0_env(offsetof(CPUSPARCState, cansave)); + break; + case 11: // canrestore + gen_op_movl_T0_env(offsetof(CPUSPARCState, canrestore)); + break; + case 12: // cleanwin + gen_op_movl_T0_env(offsetof(CPUSPARCState, cleanwin)); + break; + case 13: // otherwin + gen_op_movl_T0_env(offsetof(CPUSPARCState, otherwin)); + break; + case 14: // wstate + gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate)); + break; case 16: // UA2005 gl gen_op_movl_T0_env(offsetof(CPUSPARCState, gl)); break; @@ -1324,506 +1324,506 @@ static void disas_sparc_insn(DisasContext * dc) goto priv_insn; gen_op_movl_T0_env(offsetof(CPUSPARCState, ssr)); break; - case 31: // ver - gen_op_movtl_T0_env(offsetof(CPUSPARCState, version)); - break; - case 15: // fq - default: - goto illegal_insn; - } + case 31: // ver + gen_op_movtl_T0_env(offsetof(CPUSPARCState, version)); + break; + case 15: // fq + default: + goto illegal_insn; + } #else - gen_op_movl_T0_env(offsetof(CPUSPARCState, wim)); + gen_op_movl_T0_env(offsetof(CPUSPARCState, wim)); #endif gen_movl_T0_reg(rd); break; } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ #ifdef TARGET_SPARC64 - gen_op_flushw(); + gen_op_flushw(); #else - if (!supervisor(dc)) - goto priv_insn; - gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); + if (!supervisor(dc)) + goto priv_insn; + gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); gen_movl_T0_reg(rd); #endif break; #endif - } else if (xop == 0x34) { /* FPU Operations */ + } else if (xop == 0x34) { /* FPU Operations */ if (gen_trap_ifnofpu(dc)) goto jmp_insn; - gen_op_clear_ieee_excp_and_FTT(); + gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); - rs2 = GET_FIELD(insn, 27, 31); - xop = GET_FIELD(insn, 18, 26); - switch (xop) { - case 0x1: /* fmovs */ - gen_op_load_fpr_FT0(rs2); - gen_op_store_FT0_fpr(rd); - break; - case 0x5: /* fnegs */ - gen_op_load_fpr_FT1(rs2); - gen_op_fnegs(); - gen_op_store_FT0_fpr(rd); - break; - case 0x9: /* fabss */ - gen_op_load_fpr_FT1(rs2); - gen_op_fabss(); - gen_op_store_FT0_fpr(rd); - break; - case 0x29: /* fsqrts */ - gen_op_load_fpr_FT1(rs2); - gen_op_fsqrts(); - gen_op_store_FT0_fpr(rd); - break; - case 0x2a: /* fsqrtd */ - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fsqrtd(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x2b: /* fsqrtq */ - goto nfpu_insn; - case 0x41: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fadds(); - gen_op_store_FT0_fpr(rd); - break; - case 0x42: - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_faddd(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x43: /* faddq */ - goto nfpu_insn; - case 0x45: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fsubs(); - gen_op_store_FT0_fpr(rd); - break; - case 0x46: - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fsubd(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x47: /* fsubq */ - goto nfpu_insn; - case 0x49: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fmuls(); - gen_op_store_FT0_fpr(rd); - break; - case 0x4a: - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fmuld(); - gen_op_store_DT0_fpr(rd); - break; - case 0x4b: /* fmulq */ - goto nfpu_insn; - case 0x4d: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fdivs(); - gen_op_store_FT0_fpr(rd); - break; - case 0x4e: - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdivd(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x4f: /* fdivq */ - goto nfpu_insn; - case 0x69: - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); - gen_op_fsmuld(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x6e: /* fdmulq */ - goto nfpu_insn; - case 0xc4: - gen_op_load_fpr_FT1(rs2); - gen_op_fitos(); - gen_op_store_FT0_fpr(rd); - break; - case 0xc6: - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdtos(); - gen_op_store_FT0_fpr(rd); - break; - case 0xc7: /* fqtos */ - goto nfpu_insn; - case 0xc8: - gen_op_load_fpr_FT1(rs2); - gen_op_fitod(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0xc9: - gen_op_load_fpr_FT1(rs2); - gen_op_fstod(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0xcb: /* fqtod */ - goto nfpu_insn; - case 0xcc: /* fitoq */ - goto nfpu_insn; - case 0xcd: /* fstoq */ - goto nfpu_insn; - case 0xce: /* fdtoq */ - goto nfpu_insn; - case 0xd1: - gen_op_load_fpr_FT1(rs2); - gen_op_fstoi(); - gen_op_store_FT0_fpr(rd); - break; - case 0xd2: - gen_op_load_fpr_DT1(rs2); - gen_op_fdtoi(); - gen_op_store_FT0_fpr(rd); - break; - case 0xd3: /* fqtoi */ - goto nfpu_insn; + rs2 = GET_FIELD(insn, 27, 31); + xop = GET_FIELD(insn, 18, 26); + switch (xop) { + case 0x1: /* fmovs */ + gen_op_load_fpr_FT0(rs2); + gen_op_store_FT0_fpr(rd); + break; + case 0x5: /* fnegs */ + gen_op_load_fpr_FT1(rs2); + gen_op_fnegs(); + gen_op_store_FT0_fpr(rd); + break; + case 0x9: /* fabss */ + gen_op_load_fpr_FT1(rs2); + gen_op_fabss(); + gen_op_store_FT0_fpr(rd); + break; + case 0x29: /* fsqrts */ + gen_op_load_fpr_FT1(rs2); + gen_op_fsqrts(); + gen_op_store_FT0_fpr(rd); + break; + case 0x2a: /* fsqrtd */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fsqrtd(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x2b: /* fsqrtq */ + goto nfpu_insn; + case 0x41: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fadds(); + gen_op_store_FT0_fpr(rd); + break; + case 0x42: + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_faddd(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x43: /* faddq */ + goto nfpu_insn; + case 0x45: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fsubs(); + gen_op_store_FT0_fpr(rd); + break; + case 0x46: + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fsubd(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x47: /* fsubq */ + goto nfpu_insn; + case 0x49: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fmuls(); + gen_op_store_FT0_fpr(rd); + break; + case 0x4a: + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fmuld(); + gen_op_store_DT0_fpr(rd); + break; + case 0x4b: /* fmulq */ + goto nfpu_insn; + case 0x4d: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fdivs(); + gen_op_store_FT0_fpr(rd); + break; + case 0x4e: + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fdivd(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x4f: /* fdivq */ + goto nfpu_insn; + case 0x69: + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); + gen_op_fsmuld(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x6e: /* fdmulq */ + goto nfpu_insn; + case 0xc4: + gen_op_load_fpr_FT1(rs2); + gen_op_fitos(); + gen_op_store_FT0_fpr(rd); + break; + case 0xc6: + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fdtos(); + gen_op_store_FT0_fpr(rd); + break; + case 0xc7: /* fqtos */ + goto nfpu_insn; + case 0xc8: + gen_op_load_fpr_FT1(rs2); + gen_op_fitod(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0xc9: + gen_op_load_fpr_FT1(rs2); + gen_op_fstod(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0xcb: /* fqtod */ + goto nfpu_insn; + case 0xcc: /* fitoq */ + goto nfpu_insn; + case 0xcd: /* fstoq */ + goto nfpu_insn; + case 0xce: /* fdtoq */ + goto nfpu_insn; + case 0xd1: + gen_op_load_fpr_FT1(rs2); + gen_op_fstoi(); + gen_op_store_FT0_fpr(rd); + break; + case 0xd2: + gen_op_load_fpr_DT1(rs2); + gen_op_fdtoi(); + gen_op_store_FT0_fpr(rd); + break; + case 0xd3: /* fqtoi */ + goto nfpu_insn; #ifdef TARGET_SPARC64 - case 0x2: /* V9 fmovd */ - gen_op_load_fpr_DT0(DFPREG(rs2)); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x6: /* V9 fnegd */ - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fnegd(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0xa: /* V9 fabsd */ - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fabsd(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x81: /* V9 fstox */ - gen_op_load_fpr_FT1(rs2); - gen_op_fstox(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x82: /* V9 fdtox */ - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fdtox(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x84: /* V9 fxtos */ - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fxtos(); - gen_op_store_FT0_fpr(rd); - break; - case 0x88: /* V9 fxtod */ - gen_op_load_fpr_DT1(DFPREG(rs2)); - gen_op_fxtod(); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - case 0x3: /* V9 fmovq */ - case 0x7: /* V9 fnegq */ - case 0xb: /* V9 fabsq */ - case 0x83: /* V9 fqtox */ - case 0x8c: /* V9 fxtoq */ - goto nfpu_insn; -#endif - default: - goto illegal_insn; - } - } else if (xop == 0x35) { /* FPU Operations */ + case 0x2: /* V9 fmovd */ + gen_op_load_fpr_DT0(DFPREG(rs2)); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x6: /* V9 fnegd */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fnegd(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0xa: /* V9 fabsd */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fabsd(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x81: /* V9 fstox */ + gen_op_load_fpr_FT1(rs2); + gen_op_fstox(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x82: /* V9 fdtox */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fdtox(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x84: /* V9 fxtos */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fxtos(); + gen_op_store_FT0_fpr(rd); + break; + case 0x88: /* V9 fxtod */ + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fxtod(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + case 0x3: /* V9 fmovq */ + case 0x7: /* V9 fnegq */ + case 0xb: /* V9 fabsq */ + case 0x83: /* V9 fqtox */ + case 0x8c: /* V9 fxtoq */ + goto nfpu_insn; +#endif + default: + goto illegal_insn; + } + } else if (xop == 0x35) { /* FPU Operations */ #ifdef TARGET_SPARC64 - int cond; + int cond; #endif if (gen_trap_ifnofpu(dc)) goto jmp_insn; - gen_op_clear_ieee_excp_and_FTT(); + gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); - rs2 = GET_FIELD(insn, 27, 31); - xop = GET_FIELD(insn, 18, 26); + rs2 = GET_FIELD(insn, 27, 31); + xop = GET_FIELD(insn, 18, 26); #ifdef TARGET_SPARC64 - if ((xop & 0x11f) == 0x005) { // V9 fmovsr - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - flush_T2(dc); - gen_cond_reg(cond); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); - break; - } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); - flush_T2(dc); - rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - gen_cond_reg(cond); - gen_op_fmovs_cc(); - gen_op_store_DT0_fpr(rd); - break; - } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr - goto nfpu_insn; - } -#endif - switch (xop) { + if ((xop & 0x11f) == 0x005) { // V9 fmovsr + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + flush_T2(dc); + gen_cond_reg(cond); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + gen_cond_reg(cond); + gen_op_fmovs_cc(); + gen_op_store_DT0_fpr(rd); + break; + } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr + goto nfpu_insn; + } +#endif + switch (xop) { #ifdef TARGET_SPARC64 - case 0x001: /* V9 fmovscc %fcc0 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_fcond[0][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); - break; - case 0x002: /* V9 fmovdcc %fcc0 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); - flush_T2(dc); - gen_fcond[0][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); - break; - case 0x003: /* V9 fmovqcc %fcc0 */ - goto nfpu_insn; - case 0x041: /* V9 fmovscc %fcc1 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_fcond[1][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); - break; - case 0x042: /* V9 fmovdcc %fcc1 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); - flush_T2(dc); - gen_fcond[1][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); - break; - case 0x043: /* V9 fmovqcc %fcc1 */ - goto nfpu_insn; - case 0x081: /* V9 fmovscc %fcc2 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_fcond[2][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); - break; - case 0x082: /* V9 fmovdcc %fcc2 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); - flush_T2(dc); - gen_fcond[2][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); - break; - case 0x083: /* V9 fmovqcc %fcc2 */ - goto nfpu_insn; - case 0x0c1: /* V9 fmovscc %fcc3 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_fcond[3][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); - break; - case 0x0c2: /* V9 fmovdcc %fcc3 */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); - flush_T2(dc); - gen_fcond[3][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); - break; - case 0x0c3: /* V9 fmovqcc %fcc3 */ - goto nfpu_insn; - case 0x101: /* V9 fmovscc %icc */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_cond[0][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); - break; - case 0x102: /* V9 fmovdcc %icc */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); - flush_T2(dc); - gen_cond[0][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); - break; - case 0x103: /* V9 fmovqcc %icc */ - goto nfpu_insn; - case 0x181: /* V9 fmovscc %xcc */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_FT0(rd); - gen_op_load_fpr_FT1(rs2); - flush_T2(dc); - gen_cond[1][cond](); - gen_op_fmovs_cc(); - gen_op_store_FT0_fpr(rd); - break; - case 0x182: /* V9 fmovdcc %xcc */ - cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); - flush_T2(dc); - gen_cond[1][cond](); - gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); - break; - case 0x183: /* V9 fmovqcc %xcc */ - goto nfpu_insn; -#endif - case 0x51: /* V9 %fcc */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); + case 0x001: /* V9 fmovscc %fcc0 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_fcond[0][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x002: /* V9 fmovdcc %fcc0 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_fcond[0][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x003: /* V9 fmovqcc %fcc0 */ + goto nfpu_insn; + case 0x041: /* V9 fmovscc %fcc1 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_fcond[1][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x042: /* V9 fmovdcc %fcc1 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_fcond[1][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x043: /* V9 fmovqcc %fcc1 */ + goto nfpu_insn; + case 0x081: /* V9 fmovscc %fcc2 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_fcond[2][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x082: /* V9 fmovdcc %fcc2 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_fcond[2][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x083: /* V9 fmovqcc %fcc2 */ + goto nfpu_insn; + case 0x0c1: /* V9 fmovscc %fcc3 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_fcond[3][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x0c2: /* V9 fmovdcc %fcc3 */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_fcond[3][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x0c3: /* V9 fmovqcc %fcc3 */ + goto nfpu_insn; + case 0x101: /* V9 fmovscc %icc */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_cond[0][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x102: /* V9 fmovdcc %icc */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_cond[0][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x103: /* V9 fmovqcc %icc */ + goto nfpu_insn; + case 0x181: /* V9 fmovscc %xcc */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_FT0(rd); + gen_op_load_fpr_FT1(rs2); + flush_T2(dc); + gen_cond[1][cond](); + gen_op_fmovs_cc(); + gen_op_store_FT0_fpr(rd); + break; + case 0x182: /* V9 fmovdcc %xcc */ + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_DT0(rd); + gen_op_load_fpr_DT1(rs2); + flush_T2(dc); + gen_cond[1][cond](); + gen_op_fmovd_cc(); + gen_op_store_DT0_fpr(rd); + break; + case 0x183: /* V9 fmovqcc %xcc */ + goto nfpu_insn; +#endif + case 0x51: /* V9 %fcc */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); #ifdef TARGET_SPARC64 - gen_fcmps[rd & 3](); + gen_fcmps[rd & 3](); #else - gen_op_fcmps(); + gen_op_fcmps(); #endif - break; - case 0x52: /* V9 %fcc */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); + break; + case 0x52: /* V9 %fcc */ + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); #ifdef TARGET_SPARC64 - gen_fcmpd[rd & 3](); + gen_fcmpd[rd & 3](); #else - gen_op_fcmpd(); -#endif - break; - case 0x53: /* fcmpq */ - goto nfpu_insn; - case 0x55: /* fcmpes, V9 %fcc */ - gen_op_load_fpr_FT0(rs1); - gen_op_load_fpr_FT1(rs2); + gen_op_fcmpd(); +#endif + break; + case 0x53: /* fcmpq */ + goto nfpu_insn; + case 0x55: /* fcmpes, V9 %fcc */ + gen_op_load_fpr_FT0(rs1); + gen_op_load_fpr_FT1(rs2); #ifdef TARGET_SPARC64 - gen_fcmpes[rd & 3](); + gen_fcmpes[rd & 3](); #else - gen_op_fcmpes(); + gen_op_fcmpes(); #endif - break; - case 0x56: /* fcmped, V9 %fcc */ - gen_op_load_fpr_DT0(DFPREG(rs1)); - gen_op_load_fpr_DT1(DFPREG(rs2)); + break; + case 0x56: /* fcmped, V9 %fcc */ + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); #ifdef TARGET_SPARC64 - gen_fcmped[rd & 3](); + gen_fcmped[rd & 3](); #else - gen_op_fcmped(); -#endif - break; - case 0x57: /* fcmpeq */ - goto nfpu_insn; - default: - goto illegal_insn; - } + gen_op_fcmped(); +#endif + break; + case 0x57: /* fcmpeq */ + goto nfpu_insn; + default: + goto illegal_insn; + } #if defined(OPTIM) - } else if (xop == 0x2) { - // clr/mov shortcut + } else if (xop == 0x2) { + // clr/mov shortcut rs1 = GET_FIELD(insn, 13, 17); - if (rs1 == 0) { - // or %g0, x, y -> mov T1, x; mov y, T1 - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELDs(insn, 19, 31); - gen_movl_simm_T1(rs2); - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_T1(rs2); - } - gen_movl_T1_reg(rd); - } else { - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ - // or x, #0, y -> mov T1, x; mov y, T1 - rs2 = GET_FIELDs(insn, 19, 31); - if (rs2 != 0) { - gen_movl_simm_T1(rs2); - gen_op_or_T1_T0(); - } - } else { /* register */ - // or x, %g0, y -> mov T1, x; mov y, T1 - rs2 = GET_FIELD(insn, 27, 31); - if (rs2 != 0) { - gen_movl_reg_T1(rs2); - gen_op_or_T1_T0(); - } - } - gen_movl_T0_reg(rd); - } + if (rs1 == 0) { + // or %g0, x, y -> mov T1, x; mov y, T1 + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); + gen_movl_simm_T1(rs2); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + gen_movl_T1_reg(rd); + } else { + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + // or x, #0, y -> mov T1, x; mov y, T1 + rs2 = GET_FIELDs(insn, 19, 31); + if (rs2 != 0) { + gen_movl_simm_T1(rs2); + gen_op_or_T1_T0(); + } + } else { /* register */ + // or x, %g0, y -> mov T1, x; mov y, T1 + rs2 = GET_FIELD(insn, 27, 31); + if (rs2 != 0) { + gen_movl_reg_T1(rs2); + gen_op_or_T1_T0(); + } + } + gen_movl_T0_reg(rd); + } #endif #ifdef TARGET_SPARC64 - } else if (xop == 0x25) { /* sll, V9 sllx */ + } else if (xop == 0x25) { /* sll, V9 sllx */ rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 20, 31); gen_movl_simm_T1(rs2); - } else { /* register */ + } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); } - if (insn & (1 << 12)) - gen_op_sllx(); - else - gen_op_sll(); - gen_movl_T0_reg(rd); - } else if (xop == 0x26) { /* srl, V9 srlx */ + if (insn & (1 << 12)) + gen_op_sllx(); + else + gen_op_sll(); + gen_movl_T0_reg(rd); + } else if (xop == 0x26) { /* srl, V9 srlx */ rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 20, 31); gen_movl_simm_T1(rs2); - } else { /* register */ + } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); } - if (insn & (1 << 12)) - gen_op_srlx(); - else - gen_op_srl(); - gen_movl_T0_reg(rd); - } else if (xop == 0x27) { /* sra, V9 srax */ + if (insn & (1 << 12)) + gen_op_srlx(); + else + gen_op_srl(); + gen_movl_T0_reg(rd); + } else if (xop == 0x27) { /* sra, V9 srax */ rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 20, 31); gen_movl_simm_T1(rs2); - } else { /* register */ + } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); } - if (insn & (1 << 12)) - gen_op_srax(); - else - gen_op_sra(); - gen_movl_T0_reg(rd); + if (insn & (1 << 12)) + gen_op_srax(); + else + gen_op_sra(); + gen_movl_T0_reg(rd); #endif } else if (xop < 0x36) { rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); gen_movl_simm_T1(rs2); - } else { /* register */ + } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); gen_movl_reg_T1(rs2); } @@ -1841,10 +1841,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_logic_T0_cc(); break; case 0x2: - gen_op_or_T1_T0(); - if (xop & 0x10) - gen_op_logic_T0_cc(); - break; + gen_op_or_T1_T0(); + if (xop & 0x10) + gen_op_logic_T0_cc(); + break; case 0x3: gen_op_xor_T1_T0(); if (xop & 0x10) @@ -1878,7 +1878,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_addx_T1_T0(); break; #ifdef TARGET_SPARC64 - case 0x9: /* V9 mulx */ + case 0x9: /* V9 mulx */ gen_op_mulx_T1_T0(); break; #endif @@ -1899,7 +1899,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_subx_T1_T0(); break; #ifdef TARGET_SPARC64 - case 0xd: /* V9 udivx */ + case 0xd: /* V9 udivx */ gen_op_udivx_T1_T0(); break; #endif @@ -1916,40 +1916,40 @@ static void disas_sparc_insn(DisasContext * dc) default: goto illegal_insn; } - gen_movl_T0_reg(rd); + gen_movl_T0_reg(rd); } else { switch (xop) { - case 0x20: /* taddcc */ - gen_op_tadd_T1_T0_cc(); - gen_movl_T0_reg(rd); - break; - case 0x21: /* tsubcc */ - gen_op_tsub_T1_T0_cc(); - gen_movl_T0_reg(rd); - break; - case 0x22: /* taddcctv */ - gen_op_tadd_T1_T0_ccTV(); - gen_movl_T0_reg(rd); - break; - case 0x23: /* tsubcctv */ - gen_op_tsub_T1_T0_ccTV(); - gen_movl_T0_reg(rd); - break; + case 0x20: /* taddcc */ + gen_op_tadd_T1_T0_cc(); + gen_movl_T0_reg(rd); + break; + case 0x21: /* tsubcc */ + gen_op_tsub_T1_T0_cc(); + gen_movl_T0_reg(rd); + break; + case 0x22: /* taddcctv */ + gen_op_tadd_T1_T0_ccTV(); + gen_movl_T0_reg(rd); + break; + case 0x23: /* tsubcctv */ + gen_op_tsub_T1_T0_ccTV(); + gen_movl_T0_reg(rd); + break; case 0x24: /* mulscc */ gen_op_mulscc_T1_T0(); gen_movl_T0_reg(rd); break; #ifndef TARGET_SPARC64 - case 0x25: /* sll */ - gen_op_sll(); + case 0x25: /* sll */ + gen_op_sll(); gen_movl_T0_reg(rd); break; case 0x26: /* srl */ - gen_op_srl(); + gen_op_srl(); gen_movl_T0_reg(rd); break; case 0x27: /* sra */ - gen_op_sra(); + gen_op_sra(); gen_movl_T0_reg(rd); break; #endif @@ -1957,8 +1957,8 @@ static void disas_sparc_insn(DisasContext * dc) { switch(rd) { case 0: /* wry */ - gen_op_xor_T1_T0(); - gen_op_movtl_env_T0(offsetof(CPUSPARCState, y)); + gen_op_xor_T1_T0(); + gen_op_movtl_env_T0(offsetof(CPUSPARCState, y)); break; #ifndef TARGET_SPARC64 case 0x01 ... 0x0f: /* undefined in the @@ -1971,62 +1971,62 @@ static void disas_sparc_insn(DisasContext * dc) microSPARC II */ break; #else - case 0x2: /* V9 wrccr */ + case 0x2: /* V9 wrccr */ gen_op_wrccr(); - break; - case 0x3: /* V9 wrasi */ - gen_op_movl_env_T0(offsetof(CPUSPARCState, asi)); - break; - case 0x6: /* V9 wrfprs */ - gen_op_xor_T1_T0(); - gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs)); + break; + case 0x3: /* V9 wrasi */ + gen_op_movl_env_T0(offsetof(CPUSPARCState, asi)); + break; + case 0x6: /* V9 wrfprs */ + gen_op_xor_T1_T0(); + gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs)); save_state(dc); gen_op_next_insn(); gen_op_movl_T0_0(); gen_op_exit_tb(); dc->is_br = 1; - break; - case 0xf: /* V9 sir, nop if user */ + break; + case 0xf: /* V9 sir, nop if user */ #if !defined(CONFIG_USER_ONLY) - if (supervisor(dc)) - gen_op_sir(); + if (supervisor(dc)) + gen_op_sir(); #endif - break; - case 0x13: /* Graphics Status */ + break; + case 0x13: /* Graphics Status */ if (gen_trap_ifnofpu(dc)) goto jmp_insn; - gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr)); - break; - case 0x17: /* Tick compare */ + gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr)); + break; + case 0x17: /* Tick compare */ #if !defined(CONFIG_USER_ONLY) - if (!supervisor(dc)) - goto illegal_insn; + if (!supervisor(dc)) + goto illegal_insn; #endif gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); gen_op_wrtick_cmpr(); - break; - case 0x18: /* System tick */ + break; + case 0x18: /* System tick */ #if !defined(CONFIG_USER_ONLY) - if (!supervisor(dc)) - goto illegal_insn; + if (!supervisor(dc)) + goto illegal_insn; #endif gen_op_wrstick(); - break; - case 0x19: /* System tick compare */ + break; + case 0x19: /* System tick compare */ #if !defined(CONFIG_USER_ONLY) - if (!supervisor(dc)) - goto illegal_insn; + if (!supervisor(dc)) + goto illegal_insn; #endif gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); gen_op_wrstick_cmpr(); - break; + break; - case 0x10: /* Performance Control */ - case 0x11: /* Performance Instrumentation Counter */ - case 0x12: /* Dispatch Control */ - case 0x14: /* Softint set */ - case 0x15: /* Softint clear */ - case 0x16: /* Softint write */ + case 0x10: /* Performance Control */ + case 0x11: /* Performance Instrumentation Counter */ + case 0x12: /* Dispatch Control */ + case 0x14: /* Softint set */ + case 0x15: /* Softint clear */ + case 0x16: /* Softint write */ #endif default: goto illegal_insn; @@ -2036,22 +2036,22 @@ static void disas_sparc_insn(DisasContext * dc) #if !defined(CONFIG_USER_ONLY) case 0x31: /* wrpsr, V9 saved, restored */ { - if (!supervisor(dc)) - goto priv_insn; + if (!supervisor(dc)) + goto priv_insn; #ifdef TARGET_SPARC64 - switch (rd) { - case 0: - gen_op_saved(); - break; - case 1: - gen_op_restored(); - break; + switch (rd) { + case 0: + gen_op_saved(); + break; + case 1: + gen_op_restored(); + break; case 2: /* UA2005 allclean */ case 3: /* UA2005 otherw */ case 4: /* UA2005 normalw */ case 5: /* UA2005 invalw */ // XXX - default: + default: goto illegal_insn; } #else @@ -2059,69 +2059,69 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_wrpsr(); save_state(dc); gen_op_next_insn(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); - dc->is_br = 1; + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; #endif } break; case 0x32: /* wrwim, V9 wrpr */ { - if (!supervisor(dc)) - goto priv_insn; + if (!supervisor(dc)) + goto priv_insn; gen_op_xor_T1_T0(); #ifdef TARGET_SPARC64 - switch (rd) { - case 0: // tpc - gen_op_wrtpc(); - break; - case 1: // tnpc - gen_op_wrtnpc(); - break; - case 2: // tstate - gen_op_wrtstate(); - break; - case 3: // tt - gen_op_wrtt(); - break; - case 4: // tick - gen_op_wrtick(); - break; - case 5: // tba - gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); - break; - case 6: // pstate - gen_op_wrpstate(); + switch (rd) { + case 0: // tpc + gen_op_wrtpc(); + break; + case 1: // tnpc + gen_op_wrtnpc(); + break; + case 2: // tstate + gen_op_wrtstate(); + break; + case 3: // tt + gen_op_wrtt(); + break; + case 4: // tick + gen_op_wrtick(); + break; + case 5: // tba + gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); + break; + case 6: // pstate + gen_op_wrpstate(); save_state(dc); gen_op_next_insn(); gen_op_movl_T0_0(); gen_op_exit_tb(); dc->is_br = 1; - break; - case 7: // tl - gen_op_movl_env_T0(offsetof(CPUSPARCState, tl)); - break; - case 8: // pil - gen_op_movl_env_T0(offsetof(CPUSPARCState, psrpil)); - break; - case 9: // cwp - gen_op_wrcwp(); - break; - case 10: // cansave - gen_op_movl_env_T0(offsetof(CPUSPARCState, cansave)); - break; - case 11: // canrestore - gen_op_movl_env_T0(offsetof(CPUSPARCState, canrestore)); - break; - case 12: // cleanwin - gen_op_movl_env_T0(offsetof(CPUSPARCState, cleanwin)); - break; - case 13: // otherwin - gen_op_movl_env_T0(offsetof(CPUSPARCState, otherwin)); - break; - case 14: // wstate - gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate)); - break; + break; + case 7: // tl + gen_op_movl_env_T0(offsetof(CPUSPARCState, tl)); + break; + case 8: // pil + gen_op_movl_env_T0(offsetof(CPUSPARCState, psrpil)); + break; + case 9: // cwp + gen_op_wrcwp(); + break; + case 10: // cansave + gen_op_movl_env_T0(offsetof(CPUSPARCState, cansave)); + break; + case 11: // canrestore + gen_op_movl_env_T0(offsetof(CPUSPARCState, canrestore)); + break; + case 12: // cleanwin + gen_op_movl_env_T0(offsetof(CPUSPARCState, cleanwin)); + break; + case 13: // otherwin + gen_op_movl_env_T0(offsetof(CPUSPARCState, otherwin)); + break; + case 14: // wstate + gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate)); + break; case 16: // UA2005 gl gen_op_movl_env_T0(offsetof(CPUSPARCState, gl)); break; @@ -2130,19 +2130,19 @@ static void disas_sparc_insn(DisasContext * dc) goto priv_insn; gen_op_movl_env_T0(offsetof(CPUSPARCState, ssr)); break; - default: - goto illegal_insn; - } + default: + goto illegal_insn; + } #else - gen_op_wrwim(); + gen_op_wrwim(); #endif } break; case 0x33: /* wrtbr, UA2005 wrhpr */ { #ifndef TARGET_SPARC64 - if (!supervisor(dc)) - goto priv_insn; + if (!supervisor(dc)) + goto priv_insn; gen_op_xor_T1_T0(); gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); #else @@ -2180,77 +2180,77 @@ static void disas_sparc_insn(DisasContext * dc) break; #endif #ifdef TARGET_SPARC64 - case 0x2c: /* V9 movcc */ - { - int cc = GET_FIELD_SP(insn, 11, 12); - int cond = GET_FIELD_SP(insn, 14, 17); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELD_SPs(insn, 0, 10); - gen_movl_simm_T1(rs2); - } - else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_T1(rs2); - } - gen_movl_reg_T0(rd); - flush_T2(dc); - if (insn & (1 << 18)) { - if (cc == 0) - gen_cond[0][cond](); - else if (cc == 2) - gen_cond[1][cond](); - else - goto illegal_insn; - } else { - gen_fcond[cc][cond](); - } - gen_op_mov_cc(); - gen_movl_T0_reg(rd); - break; - } - case 0x2d: /* V9 sdivx */ + case 0x2c: /* V9 movcc */ + { + int cc = GET_FIELD_SP(insn, 11, 12); + int cond = GET_FIELD_SP(insn, 14, 17); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELD_SPs(insn, 0, 10); + gen_movl_simm_T1(rs2); + } + else { + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_T1(rs2); + } + gen_movl_reg_T0(rd); + flush_T2(dc); + if (insn & (1 << 18)) { + if (cc == 0) + gen_cond[0][cond](); + else if (cc == 2) + gen_cond[1][cond](); + else + goto illegal_insn; + } else { + gen_fcond[cc][cond](); + } + gen_op_mov_cc(); + gen_movl_T0_reg(rd); + break; + } + case 0x2d: /* V9 sdivx */ gen_op_sdivx_T1_T0(); - gen_movl_T0_reg(rd); - break; - case 0x2e: /* V9 popc */ - { - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELD_SPs(insn, 0, 12); - gen_movl_simm_T1(rs2); - // XXX optimize: popc(constant) - } - else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_T1(rs2); - } - gen_op_popc(); - gen_movl_T0_reg(rd); - } - case 0x2f: /* V9 movr */ - { - int cond = GET_FIELD_SP(insn, 10, 12); - rs1 = GET_FIELD(insn, 13, 17); - flush_T2(dc); - gen_movl_reg_T0(rs1); - gen_cond_reg(cond); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELD_SPs(insn, 0, 9); - gen_movl_simm_T1(rs2); - } - else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_T1(rs2); - } - gen_movl_reg_T0(rd); - gen_op_mov_cc(); - gen_movl_T0_reg(rd); - break; - } -#endif - default: - goto illegal_insn; - } - } + gen_movl_T0_reg(rd); + break; + case 0x2e: /* V9 popc */ + { + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELD_SPs(insn, 0, 12); + gen_movl_simm_T1(rs2); + // XXX optimize: popc(constant) + } + else { + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_T1(rs2); + } + gen_op_popc(); + gen_movl_T0_reg(rd); + } + case 0x2f: /* V9 movr */ + { + int cond = GET_FIELD_SP(insn, 10, 12); + rs1 = GET_FIELD(insn, 13, 17); + flush_T2(dc); + gen_movl_reg_T0(rs1); + gen_cond_reg(cond); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELD_SPs(insn, 0, 9); + gen_movl_simm_T1(rs2); + } + else { + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_T1(rs2); + } + gen_movl_reg_T0(rd); + gen_op_mov_cc(); + gen_movl_T0_reg(rd); + break; + } +#endif + default: + goto illegal_insn; + } + } } else if (xop == 0x36) { /* UltraSparc shutdown, VIS, V8 CPop1 */ #ifdef TARGET_SPARC64 int opf = GET_FIELD_SP(insn, 5, 13); @@ -2647,75 +2647,75 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; } #else - goto ncp_insn; + goto ncp_insn; #endif } else if (xop == 0x37) { /* V8 CPop2, V9 impdep2 */ #ifdef TARGET_SPARC64 - goto illegal_insn; + goto illegal_insn; #else - goto ncp_insn; + goto ncp_insn; #endif #ifdef TARGET_SPARC64 - } else if (xop == 0x39) { /* V9 return */ + } else if (xop == 0x39) { /* V9 return */ rs1 = GET_FIELD(insn, 13, 17); save_state(dc); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELDs(insn, 19, 31); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); #if defined(OPTIM) - if (rs2) { + if (rs2) { #endif - gen_movl_simm_T1(rs2); - gen_op_add_T1_T0(); + gen_movl_simm_T1(rs2); + gen_op_add_T1_T0(); #if defined(OPTIM) - } + } #endif - } else { /* register */ + } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); #if defined(OPTIM) - if (rs2) { + if (rs2) { #endif - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); #if defined(OPTIM) - } + } #endif } - gen_op_restore(); - gen_mov_pc_npc(dc); + gen_op_restore(); + gen_mov_pc_npc(dc); gen_op_check_align_T0_3(); - gen_op_movl_npc_T0(); - dc->npc = DYNAMIC_PC; - goto jmp_insn; + gen_op_movl_npc_T0(); + dc->npc = DYNAMIC_PC; + goto jmp_insn; #endif - } else { + } else { rs1 = GET_FIELD(insn, 13, 17); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELDs(insn, 19, 31); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); #if defined(OPTIM) - if (rs2) { + if (rs2) { #endif - gen_movl_simm_T1(rs2); - gen_op_add_T1_T0(); + gen_movl_simm_T1(rs2); + gen_op_add_T1_T0(); #if defined(OPTIM) - } + } #endif - } else { /* register */ + } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); #if defined(OPTIM) - if (rs2) { + if (rs2) { #endif - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); #if defined(OPTIM) - } + } #endif } - switch (xop) { - case 0x38: /* jmpl */ - { - if (rd != 0) { + switch (xop) { + case 0x38: /* jmpl */ + { + if (rd != 0) { #ifdef TARGET_SPARC64 if (dc->pc == (uint32_t)dc->pc) { gen_op_movl_T1_im(dc->pc); @@ -2723,250 +2723,250 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_movq_T1_im64(dc->pc >> 32, dc->pc); } #else - gen_op_movl_T1_im(dc->pc); + gen_op_movl_T1_im(dc->pc); #endif - gen_movl_T1_reg(rd); - } + gen_movl_T1_reg(rd); + } gen_mov_pc_npc(dc); gen_op_check_align_T0_3(); - gen_op_movl_npc_T0(); - dc->npc = DYNAMIC_PC; - } - goto jmp_insn; + gen_op_movl_npc_T0(); + dc->npc = DYNAMIC_PC; + } + goto jmp_insn; #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) - case 0x39: /* rett, V9 return */ - { - if (!supervisor(dc)) - goto priv_insn; + case 0x39: /* rett, V9 return */ + { + if (!supervisor(dc)) + goto priv_insn; gen_mov_pc_npc(dc); gen_op_check_align_T0_3(); - gen_op_movl_npc_T0(); - dc->npc = DYNAMIC_PC; - gen_op_rett(); - } - goto jmp_insn; -#endif - case 0x3b: /* flush */ - gen_op_flush_T0(); - break; - case 0x3c: /* save */ - save_state(dc); - gen_op_save(); - gen_movl_T0_reg(rd); - break; - case 0x3d: /* restore */ - save_state(dc); - gen_op_restore(); - gen_movl_T0_reg(rd); - break; + gen_op_movl_npc_T0(); + dc->npc = DYNAMIC_PC; + gen_op_rett(); + } + goto jmp_insn; +#endif + case 0x3b: /* flush */ + gen_op_flush_T0(); + break; + case 0x3c: /* save */ + save_state(dc); + gen_op_save(); + gen_movl_T0_reg(rd); + break; + case 0x3d: /* restore */ + save_state(dc); + gen_op_restore(); + gen_movl_T0_reg(rd); + break; #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) - case 0x3e: /* V9 done/retry */ - { - switch (rd) { - case 0: - if (!supervisor(dc)) - goto priv_insn; - dc->npc = DYNAMIC_PC; - dc->pc = DYNAMIC_PC; - gen_op_done(); - goto jmp_insn; - case 1: - if (!supervisor(dc)) - goto priv_insn; - dc->npc = DYNAMIC_PC; - dc->pc = DYNAMIC_PC; - gen_op_retry(); - goto jmp_insn; - default: - goto illegal_insn; - } - } - break; -#endif - default: - goto illegal_insn; - } + case 0x3e: /* V9 done/retry */ + { + switch (rd) { + case 0: + if (!supervisor(dc)) + goto priv_insn; + dc->npc = DYNAMIC_PC; + dc->pc = DYNAMIC_PC; + gen_op_done(); + goto jmp_insn; + case 1: + if (!supervisor(dc)) + goto priv_insn; + dc->npc = DYNAMIC_PC; + dc->pc = DYNAMIC_PC; + gen_op_retry(); + goto jmp_insn; + default: + goto illegal_insn; + } + } + break; +#endif + default: + goto illegal_insn; + } } - break; - } - break; - case 3: /* load/store instructions */ - { - unsigned int xop = GET_FIELD(insn, 7, 12); - rs1 = GET_FIELD(insn, 13, 17); + break; + } + break; + case 3: /* load/store instructions */ + { + unsigned int xop = GET_FIELD(insn, 7, 12); + rs1 = GET_FIELD(insn, 13, 17); save_state(dc); - gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ - rs2 = GET_FIELDs(insn, 19, 31); + gen_movl_reg_T0(rs1); + if (IS_IMM) { /* immediate */ + rs2 = GET_FIELDs(insn, 19, 31); #if defined(OPTIM) - if (rs2 != 0) { + if (rs2 != 0) { #endif - gen_movl_simm_T1(rs2); - gen_op_add_T1_T0(); + gen_movl_simm_T1(rs2); + gen_op_add_T1_T0(); #if defined(OPTIM) - } + } #endif - } else { /* register */ - rs2 = GET_FIELD(insn, 27, 31); + } else { /* register */ + rs2 = GET_FIELD(insn, 27, 31); #if defined(OPTIM) - if (rs2 != 0) { + if (rs2 != 0) { #endif - gen_movl_reg_T1(rs2); - gen_op_add_T1_T0(); + gen_movl_reg_T1(rs2); + gen_op_add_T1_T0(); #if defined(OPTIM) - } + } #endif - } + } if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || (xop > 0x17 && xop <= 0x1d ) || (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) { - switch (xop) { - case 0x0: /* load word */ + switch (xop) { + case 0x0: /* load word */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif #ifndef TARGET_SPARC64 - gen_op_ldst(ld); + gen_op_ldst(ld); #else gen_op_ldst(lduw); #endif - break; - case 0x1: /* load unsigned byte */ - gen_op_ldst(ldub); - break; - case 0x2: /* load unsigned halfword */ + break; + case 0x1: /* load unsigned byte */ + gen_op_ldst(ldub); + break; + case 0x2: /* load unsigned halfword */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_ldst(lduh); - break; - case 0x3: /* load double word */ + gen_op_ldst(lduh); + break; + case 0x3: /* load double word */ gen_op_check_align_T0_7(); - if (rd & 1) + if (rd & 1) goto illegal_insn; - gen_op_ldst(ldd); - gen_movl_T0_reg(rd + 1); - break; - case 0x9: /* load signed byte */ - gen_op_ldst(ldsb); - break; - case 0xa: /* load signed halfword */ + gen_op_ldst(ldd); + gen_movl_T0_reg(rd + 1); + break; + case 0x9: /* load signed byte */ + gen_op_ldst(ldsb); + break; + case 0xa: /* load signed halfword */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_ldst(ldsh); - break; - case 0xd: /* ldstub -- XXX: should be atomically */ - gen_op_ldst(ldstub); - break; - case 0x0f: /* swap register with memory. Also atomically */ + gen_op_ldst(ldsh); + break; + case 0xd: /* ldstub -- XXX: should be atomically */ + gen_op_ldst(ldstub); + break; + case 0x0f: /* swap register with memory. Also atomically */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_movl_reg_T1(rd); - gen_op_ldst(swap); - break; + gen_movl_reg_T1(rd); + gen_op_ldst(swap); + break; #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - case 0x10: /* load word alternate */ + case 0x10: /* load word alternate */ #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_lda(insn, 1, 4, 0); + gen_op_lda(insn, 1, 4, 0); #else #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif gen_op_lduwa(insn, 1, 4, 0); #endif - break; - case 0x11: /* load unsigned byte alternate */ + break; + case 0x11: /* load unsigned byte alternate */ #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - gen_op_lduba(insn, 1, 1, 0); - break; - case 0x12: /* load unsigned halfword alternate */ + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; +#endif + gen_op_lduba(insn, 1, 1, 0); + break; + case 0x12: /* load unsigned halfword alternate */ #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #endif #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_lduha(insn, 1, 2, 0); - break; - case 0x13: /* load double word alternate */ + gen_op_lduha(insn, 1, 2, 0); + break; + case 0x13: /* load double word alternate */ #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #endif - if (rd & 1) + if (rd & 1) goto illegal_insn; gen_op_check_align_T0_7(); - gen_op_ldda(insn, 1, 8, 0); - gen_movl_T0_reg(rd + 1); - break; - case 0x19: /* load signed byte alternate */ + gen_op_ldda(insn, 1, 8, 0); + gen_movl_T0_reg(rd + 1); + break; + case 0x19: /* load signed byte alternate */ #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - gen_op_ldsba(insn, 1, 1, 1); - break; - case 0x1a: /* load signed halfword alternate */ + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; +#endif + gen_op_ldsba(insn, 1, 1, 1); + break; + case 0x1a: /* load signed halfword alternate */ #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #endif #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_ldsha(insn, 1, 2 ,1); - break; - case 0x1d: /* ldstuba -- XXX: should be atomically */ + gen_op_ldsha(insn, 1, 2 ,1); + break; + case 0x1d: /* ldstuba -- XXX: should be atomically */ #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; -#endif - gen_op_ldstuba(insn, 1, 1, 0); - break; - case 0x1f: /* swap reg with alt. memory. Also atomically */ + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; +#endif + gen_op_ldstuba(insn, 1, 1, 0); + break; + case 0x1f: /* swap reg with alt. memory. Also atomically */ #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #endif - gen_movl_reg_T1(rd); + gen_movl_reg_T1(rd); #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_swapa(insn, 1, 4, 0); - break; + gen_op_swapa(insn, 1, 4, 0); + break; #ifndef TARGET_SPARC64 - case 0x30: /* ldc */ - case 0x31: /* ldcsr */ - case 0x33: /* lddc */ - goto ncp_insn; + case 0x30: /* ldc */ + case 0x31: /* ldcsr */ + case 0x33: /* lddc */ + goto ncp_insn; /* avoid warnings */ (void) &gen_op_stfa; (void) &gen_op_stdfa; @@ -2975,260 +2975,260 @@ static void disas_sparc_insn(DisasContext * dc) #else (void) &gen_op_lda; #if !defined(CONFIG_USER_ONLY) - (void) &gen_op_cas; - (void) &gen_op_casx; + (void) &gen_op_cas; + (void) &gen_op_casx; #endif #endif #endif #ifdef TARGET_SPARC64 - case 0x08: /* V9 ldsw */ + case 0x08: /* V9 ldsw */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldst(ldsw); - break; - case 0x0b: /* V9 ldx */ + gen_op_ldst(ldsw); + break; + case 0x0b: /* V9 ldx */ gen_op_check_align_T0_7(); - gen_op_ldst(ldx); - break; - case 0x18: /* V9 ldswa */ + gen_op_ldst(ldx); + break; + case 0x18: /* V9 ldswa */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldswa(insn, 1, 4, 1); - break; - case 0x1b: /* V9 ldxa */ + gen_op_ldswa(insn, 1, 4, 1); + break; + case 0x1b: /* V9 ldxa */ gen_op_check_align_T0_7(); - gen_op_ldxa(insn, 1, 8, 0); - break; - case 0x2d: /* V9 prefetch, no effect */ - goto skip_move; - case 0x30: /* V9 ldfa */ + gen_op_ldxa(insn, 1, 8, 0); + break; + case 0x2d: /* V9 prefetch, no effect */ + goto skip_move; + case 0x30: /* V9 ldfa */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldfa(insn, 1, 8, 0); // XXX - break; - case 0x33: /* V9 lddfa */ + gen_op_ldfa(insn, 1, 8, 0); // XXX + break; + case 0x33: /* V9 lddfa */ gen_op_check_align_T0_7(); - gen_op_lddfa(insn, 1, 8, 0); // XXX - - break; - case 0x3d: /* V9 prefetcha, no effect */ - goto skip_move; - case 0x32: /* V9 ldqfa */ - goto nfpu_insn; -#endif - default: - goto illegal_insn; - } - gen_movl_T1_reg(rd); + gen_op_lddfa(insn, 1, 8, 0); // XXX + + break; + case 0x3d: /* V9 prefetcha, no effect */ + goto skip_move; + case 0x32: /* V9 ldqfa */ + goto nfpu_insn; +#endif + default: + goto illegal_insn; + } + gen_movl_T1_reg(rd); #ifdef TARGET_SPARC64 - skip_move: ; + skip_move: ; #endif - } else if (xop >= 0x20 && xop < 0x24) { + } else if (xop >= 0x20 && xop < 0x24) { if (gen_trap_ifnofpu(dc)) goto jmp_insn; - switch (xop) { - case 0x20: /* load fpreg */ + switch (xop) { + case 0x20: /* load fpreg */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldst(ldf); - gen_op_store_FT0_fpr(rd); - break; - case 0x21: /* load fsr */ + gen_op_ldst(ldf); + gen_op_store_FT0_fpr(rd); + break; + case 0x21: /* load fsr */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldst(ldf); - gen_op_ldfsr(); - break; - case 0x22: /* load quad fpreg */ - goto nfpu_insn; - case 0x23: /* load double fpreg */ + gen_op_ldst(ldf); + gen_op_ldfsr(); + break; + case 0x22: /* load quad fpreg */ + goto nfpu_insn; + case 0x23: /* load double fpreg */ gen_op_check_align_T0_7(); - gen_op_ldst(lddf); - gen_op_store_DT0_fpr(DFPREG(rd)); - break; - default: - goto illegal_insn; - } - } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \ - xop == 0xe || xop == 0x1e) { - gen_movl_reg_T1(rd); - switch (xop) { - case 0x4: + gen_op_ldst(lddf); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; + default: + goto illegal_insn; + } + } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \ + xop == 0xe || xop == 0x1e) { + gen_movl_reg_T1(rd); + switch (xop) { + case 0x4: #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldst(st); - break; - case 0x5: - gen_op_ldst(stb); - break; - case 0x6: + gen_op_ldst(st); + break; + case 0x5: + gen_op_ldst(stb); + break; + case 0x6: #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_ldst(sth); - break; - case 0x7: - if (rd & 1) + gen_op_ldst(sth); + break; + case 0x7: + if (rd & 1) goto illegal_insn; gen_op_check_align_T0_7(); flush_T2(dc); - gen_movl_reg_T2(rd + 1); - gen_op_ldst(std); - break; + gen_movl_reg_T2(rd + 1); + gen_op_ldst(std); + break; #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) - case 0x14: + case 0x14: #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #endif #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_sta(insn, 0, 4, 0); + gen_op_sta(insn, 0, 4, 0); break; - case 0x15: + case 0x15: #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #endif - gen_op_stba(insn, 0, 1, 0); + gen_op_stba(insn, 0, 1, 0); break; - case 0x16: + case 0x16: #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #endif #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_stha(insn, 0, 2, 0); + gen_op_stha(insn, 0, 2, 0); break; - case 0x17: + case 0x17: #ifndef TARGET_SPARC64 - if (IS_IMM) - goto illegal_insn; - if (!supervisor(dc)) - goto priv_insn; + if (IS_IMM) + goto illegal_insn; + if (!supervisor(dc)) + goto priv_insn; #endif - if (rd & 1) + if (rd & 1) goto illegal_insn; gen_op_check_align_T0_7(); flush_T2(dc); - gen_movl_reg_T2(rd + 1); - gen_op_stda(insn, 0, 8, 0); + gen_movl_reg_T2(rd + 1); + gen_op_stda(insn, 0, 8, 0); break; #endif #ifdef TARGET_SPARC64 - case 0x0e: /* V9 stx */ + case 0x0e: /* V9 stx */ gen_op_check_align_T0_7(); - gen_op_ldst(stx); - break; - case 0x1e: /* V9 stxa */ + gen_op_ldst(stx); + break; + case 0x1e: /* V9 stxa */ gen_op_check_align_T0_7(); - gen_op_stxa(insn, 0, 8, 0); // XXX - break; + gen_op_stxa(insn, 0, 8, 0); // XXX + break; #endif - default: - goto illegal_insn; - } - } else if (xop > 0x23 && xop < 0x28) { + default: + goto illegal_insn; + } + } else if (xop > 0x23 && xop < 0x28) { if (gen_trap_ifnofpu(dc)) goto jmp_insn; - switch (xop) { - case 0x24: + switch (xop) { + case 0x24: #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif gen_op_load_fpr_FT0(rd); - gen_op_ldst(stf); - break; - case 0x25: /* stfsr, V9 stxfsr */ + gen_op_ldst(stf); + break; + case 0x25: /* stfsr, V9 stxfsr */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_stfsr(); - gen_op_ldst(stf); - break; + gen_op_stfsr(); + gen_op_ldst(stf); + break; #if !defined(CONFIG_USER_ONLY) - case 0x26: /* stdfq */ - if (!supervisor(dc)) - goto priv_insn; - if (gen_trap_ifnofpu(dc)) - goto jmp_insn; - goto nfq_insn; -#endif - case 0x27: + case 0x26: /* stdfq */ + if (!supervisor(dc)) + goto priv_insn; + if (gen_trap_ifnofpu(dc)) + goto jmp_insn; + goto nfq_insn; +#endif + case 0x27: gen_op_check_align_T0_7(); gen_op_load_fpr_DT0(DFPREG(rd)); - gen_op_ldst(stdf); - break; - default: - goto illegal_insn; - } - } else if (xop > 0x33 && xop < 0x3f) { - switch (xop) { + gen_op_ldst(stdf); + break; + default: + goto illegal_insn; + } + } else if (xop > 0x33 && xop < 0x3f) { + switch (xop) { #ifdef TARGET_SPARC64 - case 0x34: /* V9 stfa */ + case 0x34: /* V9 stfa */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_stfa(insn, 0, 0, 0); // XXX - break; - case 0x37: /* V9 stdfa */ + gen_op_stfa(insn, 0, 0, 0); // XXX + break; + case 0x37: /* V9 stdfa */ gen_op_check_align_T0_7(); - gen_op_stdfa(insn, 0, 0, 0); // XXX - break; - case 0x3c: /* V9 casa */ + gen_op_stdfa(insn, 0, 0, 0); // XXX + break; + case 0x3c: /* V9 casa */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_casa(insn, 0, 4, 0); // XXX - break; - case 0x3e: /* V9 casxa */ + gen_op_casa(insn, 0, 4, 0); // XXX + break; + case 0x3e: /* V9 casxa */ gen_op_check_align_T0_7(); - gen_op_casxa(insn, 0, 8, 0); // XXX - break; - case 0x36: /* V9 stqfa */ - goto nfpu_insn; + gen_op_casxa(insn, 0, 8, 0); // XXX + break; + case 0x36: /* V9 stqfa */ + goto nfpu_insn; #else - case 0x34: /* stc */ - case 0x35: /* stcsr */ - case 0x36: /* stdcq */ - case 0x37: /* stdc */ - goto ncp_insn; -#endif - default: - goto illegal_insn; - } + case 0x34: /* stc */ + case 0x35: /* stcsr */ + case 0x36: /* stdcq */ + case 0x37: /* stdc */ + goto ncp_insn; +#endif + default: + goto illegal_insn; + } } - else - goto illegal_insn; - } - break; + else + goto illegal_insn; + } + break; } /* default case for non jump instructions */ if (dc->npc == DYNAMIC_PC) { - dc->pc = DYNAMIC_PC; - gen_op_next_insn(); + dc->pc = DYNAMIC_PC; + gen_op_next_insn(); } else if (dc->npc == JUMP_PC) { /* we can do a static jump */ gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1]); dc->is_br = 1; } else { - dc->pc = dc->npc; - dc->npc = dc->npc + 4; + dc->pc = dc->npc; + dc->npc = dc->npc + 4; } jmp_insn: return; @@ -3266,7 +3266,7 @@ static void disas_sparc_insn(DisasContext * dc) } static inline int gen_intermediate_code_internal(TranslationBlock * tb, - int spc, CPUSPARCState *env) + int spc, CPUSPARCState *env) { target_ulong pc_start, last_pc; uint16_t *gen_opc_end; @@ -3299,12 +3299,12 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == dc->pc) { - if (dc->pc != pc_start) - save_state(dc); + if (dc->pc != pc_start) + save_state(dc); gen_op_debug(); - gen_op_movl_T0_0(); - gen_op_exit_tb(); - dc->is_br = 1; + gen_op_movl_T0_0(); + gen_op_exit_tb(); + dc->is_br = 1; goto exit_gen_loop; } } @@ -3322,14 +3322,14 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, gen_opc_instr_start[lj] = 1; } } - last_pc = dc->pc; - disas_sparc_insn(dc); - - if (dc->is_br) - break; - /* if the next PC is different, we abort now */ - if (dc->pc != (last_pc + 4)) - break; + last_pc = dc->pc; + disas_sparc_insn(dc); + + if (dc->is_br) + break; + /* if the next PC is different, we abort now */ + if (dc->pc != (last_pc + 4)) + break; /* if we reach a page boundary, we stop generation so that the PC of a TT_TFAULT exception is always in the right page */ if ((dc->pc & (TARGET_PAGE_SIZE - 1)) == 0) @@ -3343,7 +3343,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, break; } } while ((gen_opc_ptr < gen_opc_end) && - (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); + (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); exit_gen_loop: if (!dc->is_br) { @@ -3377,10 +3377,10 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, } #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "--------------\n"); - fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0); - fprintf(logfile, "\n"); + fprintf(logfile, "--------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0); + fprintf(logfile, "\n"); if (loglevel & CPU_LOG_TB_OP) { fprintf(logfile, "OP:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); @@ -3438,7 +3438,7 @@ CPUSPARCState *cpu_sparc_init(void) env = qemu_mallocz(sizeof(CPUSPARCState)); if (!env) - return NULL; + return NULL; cpu_exec_init(env); cpu_reset(env); return (env); @@ -3539,22 +3539,22 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, env->npc); cpu_fprintf(f, "General Registers:\n"); for (i = 0; i < 4; i++) - cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); cpu_fprintf(f, "\n"); for (; i < 8; i++) - cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); + cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); cpu_fprintf(f, "\nCurrent Register Window:\n"); for (x = 0; x < 3; x++) { - for (i = 0; i < 4; i++) - cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", - (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, - env->regwptr[i + x * 8]); - cpu_fprintf(f, "\n"); - for (; i < 8; i++) - cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", - (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, - env->regwptr[i + x * 8]); - cpu_fprintf(f, "\n"); + for (i = 0; i < 4; i++) + cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", + (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, + env->regwptr[i + x * 8]); + cpu_fprintf(f, "\n"); + for (; i < 8; i++) + cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", + (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, + env->regwptr[i + x * 8]); + cpu_fprintf(f, "\n"); } cpu_fprintf(f, "\nFloating Point Registers:\n"); for (i = 0; i < 32; i++) { @@ -3566,16 +3566,16 @@ void cpu_dump_state(CPUState *env, FILE *f, } #ifdef TARGET_SPARC64 cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n", - env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs); + env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs); cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d cleanwin %d cwp %d\n", - env->cansave, env->canrestore, env->otherwin, env->wstate, - env->cleanwin, NWINDOWS - 1 - env->cwp); + env->cansave, env->canrestore, env->otherwin, env->wstate, + env->cleanwin, NWINDOWS - 1 - env->cwp); #else cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), - GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), - GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), - env->psrs?'S':'-', env->psrps?'P':'-', - env->psret?'E':'-', env->wim); + GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), + GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), + env->psrs?'S':'-', env->psrps?'P':'-', + env->psret?'E':'-', env->wim); #endif cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env)); } -- cgit v1.2.3 From d69d2ca9b4125e738dfc5eee908dfac12fc3f870 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 20 Sep 2007 15:21:32 +0000 Subject: Fix tadd op generation with GCC 4.x git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3196 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 31bf5dd51..f2168af9a 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -520,8 +520,11 @@ void OPPROTO op_tadd_T1_T0_ccTV(void) { target_ulong src1; - if ((T0 & 0x03) || (T1 & 0x03)) + if ((T0 & 0x03) || (T1 & 0x03)) { raise_exception(TT_TOVF); + FORCE_RET(); + return; + } src1 = T0; T0 += T1; -- cgit v1.2.3 From 5e3b100b65ea3af8e9a31507541e26d5e439e377 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 20 Sep 2007 16:01:51 +0000 Subject: Change ldl_phys to cpu_physical_memory_read, fix pte address git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3197 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/iommu.c b/hw/iommu.c index c36178cdc..c9b9db57d 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -202,7 +202,8 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = { static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) { - uint32_t iopte, ret; + uint32_t ret; + target_phys_addr_t iopte; #ifdef DEBUG_IOMMU target_phys_addr_t pa = addr; #endif @@ -210,9 +211,10 @@ static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) iopte = s->regs[IOMMU_BASE] << 4; addr &= ~s->iostart; iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; - ret = ldl_phys(iopte); - DPRINTF("get flags addr " TARGET_FMT_plx " => pte %x, *ptes = %x\n", pa, - iopte, ret); + cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4); + bswap32s(&ret); + DPRINTF("get flags addr " TARGET_FMT_plx " => pte " TARGET_FMT_plx + ", *pte = %x\n", pa, iopte, ret); return ret; } -- cgit v1.2.3 From c068688b03f4af8994ba0d7bd41a74c8f245453b Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 20 Sep 2007 22:47:42 +0000 Subject: Extend TB flags to 64 bits (Alexander Graf). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3198 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 ++-- exec-all.h | 2 +- target-i386/translate.c | 5 +++-- target-mips/translate.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 2d08626db..339505966 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -77,7 +77,7 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) static TranslationBlock *tb_find_slow(target_ulong pc, target_ulong cs_base, - unsigned int flags) + uint64_t flags) { TranslationBlock *tb, **ptb1; int code_gen_size; @@ -155,7 +155,7 @@ static inline TranslationBlock *tb_find_fast(void) { TranslationBlock *tb; target_ulong cs_base, pc; - unsigned int flags; + uint64_t flags; /* we record a subset of the CPU state. It will always be the same before a given translated block diff --git a/exec-all.h b/exec-all.h index ca5959742..f58aea534 100644 --- a/exec-all.h +++ b/exec-all.h @@ -171,7 +171,7 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr, typedef struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ - unsigned int flags; /* flags defining in which context the code was generated */ + uint64_t flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ uint16_t cflags; /* compile flags */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 35ba6319c..028cdac9a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -95,7 +95,7 @@ typedef struct DisasContext { int singlestep_enabled; /* "hardware" single step enabled */ int jmp_opt; /* use direct block chaining for direct jumps */ int mem_index; /* select memory access functions */ - int flags; /* all execution flags */ + uint64_t flags; /* all execution flags */ struct TranslationBlock *tb; int popl_esp_hack; /* for correct popl with esp base handling */ int rip_offset; /* only used in x86_64, but left for simplicity */ @@ -6462,7 +6462,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, DisasContext dc1, *dc = &dc1; target_ulong pc_ptr; uint16_t *gen_opc_end; - int flags, j, lj, cflags; + int j, lj, cflags; + uint64_t flags; target_ulong pc_start; target_ulong cs_base; diff --git a/target-mips/translate.c b/target-mips/translate.c index 8e6fe0e20..ddffc0f15 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -6403,7 +6403,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.tb = tb; ctx.bstate = BS_NONE; /* Restore delay slot state from the tb context. */ - ctx.hflags = tb->flags; + ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ restore_cpu_state(env, &ctx); #if defined(CONFIG_USER_ONLY) ctx.mem_idx = 0; -- cgit v1.2.3 From 4296f45902536506369cc9c9c329d6680fa3f1a9 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 21 Sep 2007 05:23:26 +0000 Subject: Make CPU hflags be a masked version of the PowerPC MSR. As a side effect, avoid potential bits shadowing in TB flags on 64 bits BookE. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3199 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 +- target-ppc/helper.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3ca22e57b..e2cf956b4 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -807,7 +807,7 @@ struct CPUPPCState { /* Those resources are used only in Qemu core */ jmp_buf jmp_env; int user_mode_only; /* user mode only simulation */ - uint32_t hflags; + target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ /* Power management */ int power_mode; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 80315f6de..534ad6b5d 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1776,13 +1776,14 @@ void ppc_store_msr_32 (CPUPPCState *env, uint32_t value) void do_compute_hflags (CPUPPCState *env) { /* Compute current hflags */ - env->hflags = (msr_cm << MSR_CM) | (msr_vr << MSR_VR) | + env->hflags = (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE); #if defined (TARGET_PPC64) - /* No care here: PowerPC 64 MSR_SF means the same as MSR_CM for BookE */ - env->hflags |= (msr_sf << (MSR_SF - 32)) | (msr_hv << (MSR_HV - 32)); + env->hflags |= msr_cm << MSR_CM; + env->hflags |= (uint64_t)msr_sf << MSR_SF; + env->hflags |= (uint64_t)msr_hv << MSR_HV; #endif } -- cgit v1.2.3 From a4bb6c3e87b8bfa5db94a4e231e211696e05b4f5 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 21 Sep 2007 05:28:33 +0000 Subject: Rework PowerPC 440 TLB management (thanks to Hollis Blanchard) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3200 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 40 ++-------- target-ppc/op_helper.c | 199 ++++++++++++++++++++++--------------------------- target-ppc/op_helper.h | 14 ++-- target-ppc/translate.c | 32 ++------ 4 files changed, 110 insertions(+), 175 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 1e9bd2276..593539bbf 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2365,51 +2365,27 @@ void OPPROTO op_wrte (void) RETURN(); } -void OPPROTO op_booke_tlbre0 (void) +void OPPROTO op_440_tlbre (void) { - do_booke_tlbre0(); + do_440_tlbre(PARAM1); RETURN(); } -void OPPROTO op_booke_tlbre1 (void) +void OPPROTO op_440_tlbsx (void) { - do_booke_tlbre1(); + do_440_tlbsx(); RETURN(); } -void OPPROTO op_booke_tlbre2 (void) +void OPPROTO op_440_tlbsx_ (void) { - do_booke_tlbre2(); + do_440_tlbsx_(); RETURN(); } -void OPPROTO op_booke_tlbsx (void) +void OPPROTO op_440_tlbwe (void) { - do_booke_tlbsx(); - RETURN(); -} - -void OPPROTO op_booke_tlbsx_ (void) -{ - do_booke_tlbsx_(); - RETURN(); -} - -void OPPROTO op_booke_tlbwe0 (void) -{ - do_booke_tlbwe0(); - RETURN(); -} - -void OPPROTO op_booke_tlbwe1 (void) -{ - do_booke_tlbwe1(); - RETURN(); -} - -void OPPROTO op_booke_tlbwe2 (void) -{ - do_booke_tlbwe2(); + do_440_tlbwe(PARAM1); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 9e26deb9f..07b336b54 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2607,95 +2607,79 @@ void do_4xx_tlbwe_lo (void) #endif } -/* BookE TLB management */ -void do_booke_tlbwe0 (void) +/* PowerPC 440 TLB management */ +void do_440_tlbwe (int word) { ppcemb_tlb_t *tlb; - target_ulong EPN, size; + target_ulong EPN, RPN, size; int do_flush_tlbs; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n", + __func__, word, T0, T1); } #endif do_flush_tlbs = 0; T0 &= 0x3F; tlb = &env->tlb[T0].tlbe; - EPN = T1 & 0xFFFFFC00; - if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) - do_flush_tlbs = 1; - tlb->EPN = EPN; - size = booke_tlb_to_page_size((T1 >> 4) & 0xF); - if ((tlb->prot & PAGE_VALID) && tlb->size < size) - do_flush_tlbs = 1; - tlb->size = size; - tlb->attr &= ~0x1; - tlb->attr |= (T1 >> 8) & 1; - if (T1 & 0x200) { - tlb->prot |= PAGE_VALID; - } else { - if (tlb->prot & PAGE_VALID) { - tlb->prot &= ~PAGE_VALID; + switch (word) { + default: + /* Just here to please gcc */ + case 0: + EPN = T1 & 0xFFFFFC00; + if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) do_flush_tlbs = 1; + tlb->EPN = EPN; + size = booke_tlb_to_page_size((T1 >> 4) & 0xF); + if ((tlb->prot & PAGE_VALID) && tlb->size < size) + do_flush_tlbs = 1; + tlb->size = size; + tlb->attr &= ~0x1; + tlb->attr |= (T1 >> 8) & 1; + if (T1 & 0x200) { + tlb->prot |= PAGE_VALID; + } else { + if (tlb->prot & PAGE_VALID) { + tlb->prot &= ~PAGE_VALID; + do_flush_tlbs = 1; + } } + tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF; + if (do_flush_tlbs) + tlb_flush(env, 1); + break; + case 1: + RPN = T1 & 0xFFFFFC0F; + if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) + tlb_flush(env, 1); + tlb->RPN = RPN; + break; + case 2: + tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00); + tlb->prot = tlb->prot & PAGE_VALID; + if (T1 & 0x1) + tlb->prot |= PAGE_READ << 4; + if (T1 & 0x2) + tlb->prot |= PAGE_WRITE << 4; + if (T1 & 0x4) + tlb->prot |= PAGE_EXEC << 4; + if (T1 & 0x8) + tlb->prot |= PAGE_READ; + if (T1 & 0x10) + tlb->prot |= PAGE_WRITE; + if (T1 & 0x20) + tlb->prot |= PAGE_EXEC; + break; } - tlb->PID = env->spr[SPR_BOOKE_PID]; - if (do_flush_tlbs) - tlb_flush(env, 1); -} - -void do_booke_tlbwe1 (void) -{ - ppcemb_tlb_t *tlb; - target_phys_addr_t RPN; - -#if defined (DEBUG_SOFTWARE_TLB) - if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); - } -#endif - T0 &= 0x3F; - tlb = &env->tlb[T0].tlbe; - RPN = T1 & 0xFFFFFC0F; - if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) - tlb_flush(env, 1); - tlb->RPN = RPN; -} - -void do_booke_tlbwe2 (void) -{ - ppcemb_tlb_t *tlb; - -#if defined (DEBUG_SOFTWARE_TLB) - if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); - } -#endif - T0 &= 0x3F; - tlb = &env->tlb[T0].tlbe; - tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00); - tlb->prot = tlb->prot & PAGE_VALID; - if (T1 & 0x1) - tlb->prot |= PAGE_READ << 4; - if (T1 & 0x2) - tlb->prot |= PAGE_WRITE << 4; - if (T1 & 0x4) - tlb->prot |= PAGE_EXEC << 4; - if (T1 & 0x8) - tlb->prot |= PAGE_READ; - if (T1 & 0x10) - tlb->prot |= PAGE_WRITE; - if (T1 & 0x20) - tlb->prot |= PAGE_EXEC; } -void do_booke_tlbsx (void) +void do_440_tlbsx (void) { T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]); } -void do_booke_tlbsx_ (void) +void do_440_tlbsx_ (void) { int tmp = xer_so; @@ -2705,52 +2689,47 @@ void do_booke_tlbsx_ (void) env->crf[0] = tmp; } -void do_booke_tlbre0 (void) +void do_440_tlbre (int word) { ppcemb_tlb_t *tlb; int size; T0 &= 0x3F; tlb = &env->tlb[T0].tlbe; - T0 = tlb->EPN; - size = booke_page_size_to_tlb(tlb->size); - if (size < 0 || size > 0xF) - size = 1; - T0 |= size << 4; - if (tlb->attr & 0x1) - T0 |= 0x100; - if (tlb->prot & PAGE_VALID) - T0 |= 0x200; - env->spr[SPR_BOOKE_PID] = tlb->PID; -} - -void do_booke_tlbre1 (void) -{ - ppcemb_tlb_t *tlb; - - T0 &= 0x3F; - tlb = &env->tlb[T0].tlbe; - T0 = tlb->RPN; -} - -void do_booke_tlbre2 (void) -{ - ppcemb_tlb_t *tlb; - - T0 &= 0x3F; - tlb = &env->tlb[T0].tlbe; - T0 = tlb->attr & ~0x1; - if (tlb->prot & (PAGE_READ << 4)) - T0 |= 0x1; - if (tlb->prot & (PAGE_WRITE << 4)) - T0 |= 0x2; - if (tlb->prot & (PAGE_EXEC << 4)) - T0 |= 0x4; - if (tlb->prot & PAGE_READ) - T0 |= 0x8; - if (tlb->prot & PAGE_WRITE) - T0 |= 0x10; - if (tlb->prot & PAGE_EXEC) - T0 |= 0x20; + switch (word) { + default: + /* Just here to please gcc */ + case 0: + T0 = tlb->EPN; + size = booke_page_size_to_tlb(tlb->size); + if (size < 0 || size > 0xF) + size = 1; + T0 |= size << 4; + if (tlb->attr & 0x1) + T0 |= 0x100; + if (tlb->prot & PAGE_VALID) + T0 |= 0x200; + env->spr[SPR_440_MMUCR] &= ~0x000000FF; + env->spr[SPR_440_MMUCR] |= tlb->PID; + break; + case 1: + T0 = tlb->RPN; + break; + case 2: + T0 = tlb->attr & ~0x1; + if (tlb->prot & (PAGE_READ << 4)) + T0 |= 0x1; + if (tlb->prot & (PAGE_WRITE << 4)) + T0 |= 0x2; + if (tlb->prot & (PAGE_EXEC << 4)) + T0 |= 0x4; + if (tlb->prot & PAGE_READ) + T0 |= 0x8; + if (tlb->prot & PAGE_WRITE) + T0 |= 0x10; + if (tlb->prot & PAGE_EXEC) + T0 |= 0x20; + break; + } } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 5c412ef9c..47f548e7b 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -156,16 +156,12 @@ void do_POWER_rfsvc (void); void do_op_602_mfrom (void); #endif -/* PowerPC BookE specific helpers */ +/* PowerPC 440 specific helpers */ #if !defined(CONFIG_USER_ONLY) -void do_booke_tlbre0 (void); -void do_booke_tlbre1 (void); -void do_booke_tlbre2 (void); -void do_booke_tlbsx (void); -void do_booke_tlbsx_ (void); -void do_booke_tlbwe0 (void); -void do_booke_tlbwe1 (void); -void do_booke_tlbwe2 (void); +void do_440_tlbre (int word); +void do_440_tlbsx (void); +void do_440_tlbsx_ (void); +void do_440_tlbwe (int word); #endif /* PowerPC 4xx specific helpers */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 21e70195d..db90f3f4d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4695,9 +4695,9 @@ GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) #endif } -/* TLB management - PowerPC BookE implementation */ +/* TLB management - PowerPC 440 implementation */ /* tlbre */ -GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) +GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4708,18 +4708,10 @@ GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) } switch (rB(ctx->opcode)) { case 0: - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_booke_tlbre0(); - gen_op_store_T0_gpr(rD(ctx->opcode)); - break; case 1: - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_booke_tlbre1(); - gen_op_store_T0_gpr(rD(ctx->opcode)); - break; case 2: gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_booke_tlbre2(); + gen_op_440_tlbre(rB(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); break; default: @@ -4730,7 +4722,7 @@ GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) } /* tlbsx - tlbsx. */ -GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) +GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4741,15 +4733,15 @@ GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) } gen_addr_reg_index(ctx); if (Rc(ctx->opcode)) - gen_op_booke_tlbsx_(); + gen_op_440_tlbsx_(); else - gen_op_booke_tlbsx(); + gen_op_440_tlbsx(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } /* tlbwe */ -GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) +GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4760,19 +4752,11 @@ GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) } switch (rB(ctx->opcode)) { case 0: - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); - gen_op_booke_tlbwe0(); - break; case 1: - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rS(ctx->opcode)); - gen_op_booke_tlbwe1(); - break; case 2: gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rS(ctx->opcode)); - gen_op_booke_tlbwe2(); + gen_op_440_tlbwe(rB(ctx->opcode)); break; default: RET_INVAL(ctx); -- cgit v1.2.3 From 2662a059aa2affddfbe42e78b11c802cf30a970f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 21 Sep 2007 05:50:37 +0000 Subject: More PowerPC definitions, from POWER 2.04 specifications and misc sources. Check that at least instructions set and SPRs are correct for PowerPC 401, 403, 405 and 440 cores. Implement PowerPC 401 MMU model (real-mode only). Improve INSNs and SPRs dump to ease parse with standard shell tools. Add more precise status for most PowerPC cores families. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3201 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/STATUS | 210 ++++++++++ target-ppc/cpu.h | 210 +++++++--- target-ppc/helper.c | 12 + target-ppc/translate.c | 97 +++-- target-ppc/translate_init.c | 979 ++++++++++++++++++++++++++++++++------------ 5 files changed, 1136 insertions(+), 372 deletions(-) diff --git a/target-ppc/STATUS b/target-ppc/STATUS index 662a4a156..190186562 100644 --- a/target-ppc/STATUS +++ b/target-ppc/STATUS @@ -4,6 +4,216 @@ The goal of this file is to provide a reference status to avoid regressions. =============================================================================== PowerPC core emulation status +32 bits PowerPC +PowerPC 601: +INSN +SPR +MMU +EXCP + +PowerPC 602: +INSN +SPR +MMU +EXCP + +PowerPC 603: +INSN OK +SPR OK +MMU OK +EXCP OK + +PowerPC 604: +INSN OK +SPR OK +MMU OK +EXCP OK + +PowerPC 740: +INSN OK +SPR OK +MMU OK +EXCP OK + +PowerPC 745: +INSN +SPR +MMU +EXCP + +PowerPC 750: +INSN OK +SPR OK +MMU OK +EXCP OK + +PowerPC 755: +INSN +SPR +MMU +EXCP + +PowerPC 7400: +INSN KO +SPR KO +MMU OK +EXCP OK + +PowerPC 7410: +INSN KO +SPR KO +MMU OK +EXCP OK + +PowerPC 7450: +INSN KO +SPR KO +MMU OK +EXCP OK + +PowerPC 7455: +INSN KO +SPR KO +MMU OK +EXCP OK + +PowerPC 7457: +INSN KO +SPR KO +MMU OK +EXCP OK + +PowerPC 7457A: +INSN KO +SPR KO +MMU OK +EXCP OK + +64 bits PowerPC +PowerPC 970: +INSN KO +SPR KO +MMU KO +EXCP KO + +PowerPC 620: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +PowerPC 630: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +PowerPC 631: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +POWER4: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +POWER4+: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +POWER5: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +POWER5+: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +POWER6: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +RS64: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +RS64-II: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +RS64-III: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +RS64-IV: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +Embedded PowerPC cores +PowerPC 401: +INSN OK +SPR OK +MMU OK +EXCP ? + +PowerPC 403: +INSN OK +SPR OK +MMU OK +EXCP ? + +PowerPC 405: +INSN OK +SPR OK +MMU OK +EXCP OK + +PowerPC 440: +INSN OK +SPR OK +MMU ? +EXCP ? + +PowerPC 460: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +Freescale (to be completed) ... + +Original POWER +POWER: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + +POWER2: (lack of precise informations) +INSN KO +SPR KO +MMU KO +EXCP KO + PowerPC CPU known to work (ie booting at least Linux 2.4): * main stream PowerPC cores - PowerPC 603 & derivatives diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e2cf956b4..f4c7a9467 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -94,11 +94,17 @@ enum { /* PowerPC 401 cores */ CPU_PPC_401A1 = 0x00210000, CPU_PPC_401B2 = 0x00220000, +#if 0 + CPU_PPC_401B3 = xxx, +#endif CPU_PPC_401C2 = 0x00230000, CPU_PPC_401D2 = 0x00240000, CPU_PPC_401E2 = 0x00250000, CPU_PPC_401F2 = 0x00260000, CPU_PPC_401G2 = 0x00270000, +#if 0 + CPU_PPC_401GF = xxx, +#endif #define CPU_PPC_401 CPU_PPC_401G2 CPU_PPC_IOP480 = 0x40100000, /* 401B2 ? */ CPU_PPC_COBRA = 0x10100000, /* IBM Processor for Network Resources */ @@ -107,19 +113,39 @@ enum { CPU_PPC_403GB = 0x00200100, CPU_PPC_403GC = 0x00200200, CPU_PPC_403GCX = 0x00201400, +#if 0 + CPU_PPC_403GP = xxx, +#endif #define CPU_PPC_403 CPU_PPC_403GCX /* PowerPC 405 cores */ +#if 0 + CPU_PPC_405A3 = xxx, +#endif +#if 0 + CPU_PPC_405A4 = xxx, +#endif +#if 0 + CPU_PPC_405B3 = xxx, +#endif + CPU_PPC_405D2 = 0x20010000, + CPU_PPC_405D4 = 0x41810000, CPU_PPC_405CR = 0x40110145, #define CPU_PPC_405GP CPU_PPC_405CR CPU_PPC_405EP = 0x51210950, +#if 0 + CPU_PPC_405EZ = xxx, +#endif CPU_PPC_405GPR = 0x50910951, - CPU_PPC_405D2 = 0x20010000, - CPU_PPC_405D4 = 0x41810000, +#if 0 + CPU_PPC_405LP = xxx, +#endif #define CPU_PPC_405 CPU_PPC_405D4 CPU_PPC_NPE405H = 0x414100C0, CPU_PPC_NPE405H2 = 0x41410140, CPU_PPC_NPE405L = 0x416100C0, - /* XXX: missing 405LP, LC77700 */ +#if 0 + CPU_PPC_LC77700 = xxx, +#endif /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */ #if 0 CPU_PPC_STB01000 = xxx, @@ -150,14 +176,22 @@ enum { CPU_PPC_440EP = 0x422218D3, #define CPU_PPC_440GR CPU_PPC_440EP CPU_PPC_440GP = 0x40120481, +#if 0 + CPU_PPC_440GRX = xxx, +#endif CPU_PPC_440GX = 0x51B21850, CPU_PPC_440GXc = 0x51B21892, CPU_PPC_440GXf = 0x51B21894, CPU_PPC_440SP = 0x53221850, CPU_PPC_440SP2 = 0x53221891, CPU_PPC_440SPE = 0x53421890, - /* XXX: missing 440GRX */ - /* PowerPC 460 cores - TODO */ + /* PowerPC 460 cores */ +#if 0 + CPU_PPC_464H90 = xxx, +#endif +#if 0 + CPU_PPC_464H90FP = xxx, +#endif /* PowerPC MPC 5xx cores */ CPU_PPC_5xx = 0x00020020, /* PowerPC MPC 8xx cores (aka PowerQUICC) */ @@ -197,14 +231,8 @@ enum { /* PowerPC 74x/75x cores (aka G3) */ CPU_PPC_74x = 0x00080000, CPU_PPC_740E = 0x00080100, - CPU_PPC_750E = 0x00080200, - CPU_PPC_755_10 = 0x00083100, - CPU_PPC_755_11 = 0x00083101, - CPU_PPC_755_20 = 0x00083200, - CPU_PPC_755D = 0x00083202, - CPU_PPC_755E = 0x00083203, -#define CPU_PPC_755 CPU_PPC_755E CPU_PPC_74xP = 0x10080000, + CPU_PPC_750E = 0x00080200, CPU_PPC_750CXE21 = 0x00082201, CPU_PPC_750CXE22 = 0x00082212, CPU_PPC_750CXE23 = 0x00082203, @@ -228,12 +256,20 @@ enum { CPU_PPC_750GL = 0x70020102, CPU_PPC_750L30 = 0x00088300, CPU_PPC_750L32 = 0x00088302, +#define CPU_PPC_750L CPU_PPC_750L32 CPU_PPC_750CL = 0x00087200, + CPU_PPC_755_10 = 0x00083100, + CPU_PPC_755_11 = 0x00083101, + CPU_PPC_755_20 = 0x00083200, + CPU_PPC_755D = 0x00083202, + CPU_PPC_755E = 0x00083203, +#define CPU_PPC_755 CPU_PPC_755E /* PowerPC 74xx cores (aka G4) */ CPU_PPC_7400 = 0x000C0100, CPU_PPC_7410C = 0x800C1102, CPU_PPC_7410D = 0x800C1103, CPU_PPC_7410E = 0x800C1104, +#define CPU_PPC_7410 CPU_PPC_7410E CPU_PPC_7441 = 0x80000210, CPU_PPC_7445 = 0x80010100, CPU_PPC_7447 = 0x80020100, @@ -257,6 +293,9 @@ enum { CPU_PPC_POWER4P = 0x00380000, CPU_PPC_POWER5 = 0x003A0000, CPU_PPC_POWER5P = 0x003B0000, +#if 0 + CPU_PPC_POWER6 = xxx, +#endif CPU_PPC_970 = 0x00390000, CPU_PPC_970FX10 = 0x00391100, CPU_PPC_970FX20 = 0x003C0200, @@ -399,59 +438,67 @@ enum { PPC_SPEFPU = 0x0000000200000000ULL, /* SLB management */ PPC_SLBI = 0x0000000400000000ULL, + /* PowerPC 40x ibct instructions */ + PPC_40x_ICBT = 0x0000000800000000ULL, }; /* CPU run-time flags (MMU and exception model) */ enum { - /* MMU model */ + /* MMU model */ PPC_FLAGS_MMU_MASK = 0x000000FF, - /* Standard 32 bits PowerPC MMU */ + /* Standard 32 bits PowerPC MMU */ PPC_FLAGS_MMU_32B = 0x00000000, - /* Standard 64 bits PowerPC MMU */ + /* Standard 64 bits PowerPC MMU */ PPC_FLAGS_MMU_64B = 0x00000001, - /* PowerPC 601 MMU */ + /* PowerPC 601 MMU */ PPC_FLAGS_MMU_601 = 0x00000002, /* PowerPC 6xx MMU with software TLB */ PPC_FLAGS_MMU_SOFT_6xx = 0x00000003, /* PowerPC 4xx MMU with software TLB */ PPC_FLAGS_MMU_SOFT_4xx = 0x00000004, - /* PowerPC 403 MMU */ + /* PowerPC 403 MMU */ PPC_FLAGS_MMU_403 = 0x00000005, - /* BookE FSL MMU model */ + /* BookE FSL MMU model */ PPC_FLAGS_MMU_BOOKE_FSL = 0x00000006, - /* BookE MMU model */ + /* BookE MMU model */ PPC_FLAGS_MMU_BOOKE = 0x00000007, - /* 64 bits "bridge" PowerPC MMU */ + /* 64 bits "bridge" PowerPC MMU */ PPC_FLAGS_MMU_64BRIDGE = 0x00000008, - /* Exception model */ + /* PowerPC 401 MMU (real mode only) */ + PPC_FLAGS_MMU_401 = 0x00000009, + /* Exception model */ PPC_FLAGS_EXCP_MASK = 0x0000FF00, /* Standard PowerPC exception model */ PPC_FLAGS_EXCP_STD = 0x00000000, - /* PowerPC 40x exception model */ + /* PowerPC 40x exception model */ PPC_FLAGS_EXCP_40x = 0x00000100, - /* PowerPC 601 exception model */ + /* PowerPC 601 exception model */ PPC_FLAGS_EXCP_601 = 0x00000200, - /* PowerPC 602 exception model */ + /* PowerPC 602 exception model */ PPC_FLAGS_EXCP_602 = 0x00000300, - /* PowerPC 603 exception model */ + /* PowerPC 603 exception model */ PPC_FLAGS_EXCP_603 = 0x00000400, - /* PowerPC 604 exception model */ + /* PowerPC 604 exception model */ PPC_FLAGS_EXCP_604 = 0x00000500, - /* PowerPC 7x0 exception model */ + /* PowerPC 7x0 exception model */ PPC_FLAGS_EXCP_7x0 = 0x00000600, - /* PowerPC 7x5 exception model */ + /* PowerPC 7x5 exception model */ PPC_FLAGS_EXCP_7x5 = 0x00000700, - /* PowerPC 74xx exception model */ + /* PowerPC 74xx exception model */ PPC_FLAGS_EXCP_74xx = 0x00000800, - /* PowerPC 970 exception model */ + /* PowerPC 970 exception model */ PPC_FLAGS_EXCP_970 = 0x00000900, - /* BookE exception model */ + /* BookE exception model */ PPC_FLAGS_EXCP_BOOKE = 0x00000A00, - /* Input pins model */ + /* Input pins model */ PPC_FLAGS_INPUT_MASK = 0x000F0000, + /* PowerPC 6xx bus */ PPC_FLAGS_INPUT_6xx = 0x00000000, + /* BookE bus */ PPC_FLAGS_INPUT_BookE = 0x00010000, + /* PowerPC 4xx bus */ PPC_FLAGS_INPUT_40x = 0x00020000, + /* PowerPC 970 bus */ PPC_FLAGS_INPUT_970 = 0x00030000, }; @@ -466,36 +513,40 @@ enum { #define PPC_FLAGS_TODO (0x00000000) /* PowerPC 40x instruction set */ -#define PPC_INSNS_EMB (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_EMB_COMMON) +#define PPC_INSNS_EMB (PPC_INSNS_BASE | PPC_EMB_COMMON) /* PowerPC 401 */ -#define PPC_INSNS_401 (PPC_INSNS_TODO) -#define PPC_FLAGS_401 (PPC_FLAGS_TODO) +#define PPC_INSNS_401 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define PPC_FLAGS_401 (PPC_FLAGS_MMU_401 | PPC_FLAGS_EXCP_40x | \ + PPC_FLAGS_INPUT_40x) /* PowerPC 403 */ #define PPC_INSNS_403 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIA | PPC_4xx_COMMON | PPC_40x_EXCP | \ - PPC_40x_SPEC) + PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | \ + PPC_40x_EXCP | PPC_40x_SPEC | PPC_40x_ICBT) #define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x | \ PPC_FLAGS_INPUT_40x) /* PowerPC 405 */ #define PPC_INSNS_405 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_CACHE_OPT | PPC_MEM_TLBIA | PPC_TB | \ - PPC_4xx_COMMON | PPC_40x_SPEC | PPC_40x_EXCP | \ - PPC_405_MAC) + PPC_CACHE_OPT | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_TB | PPC_4xx_COMMON | PPC_40x_SPEC | \ + PPC_40x_ICBT | PPC_40x_EXCP | PPC_405_MAC) #define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x | \ PPC_FLAGS_INPUT_40x) /* PowerPC 440 */ #define PPC_INSNS_440 (PPC_INSNS_EMB | PPC_CACHE_OPT | PPC_BOOKE | \ - PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) + PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC) #define PPC_FLAGS_440 (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE | \ PPC_FLAGS_INPUT_BookE) /* Generic BookE PowerPC */ -#define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \ - PPC_FLOAT | PPC_FLOAT_OPT | PPC_CACHE_OPT) +#define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_MEM_TLBSYNC | PPC_BOOKE | \ + PPC_MEM_EIEIO | PPC_FLOAT | PPC_FLOAT_OPT | \ + PPC_CACHE_OPT) #define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE | \ PPC_FLAGS_INPUT_BookE) /* e500 core */ -#define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \ - PPC_CACHE_OPT | PPC_E500_VECTOR) +#define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_MEM_TLBSYNC | PPC_BOOKE | \ + PPC_MEM_EIEIO | PPC_CACHE_OPT | PPC_E500_VECTOR) #define PPC_FLAGS_E500 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x | \ PPC_FLAGS_INPUT_BookE) /* Non-embedded PowerPC */ @@ -941,6 +992,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_SDR1 (0x019) #define SPR_SRR0 (0x01A) #define SPR_SRR1 (0x01B) +#define SPR_AMR (0x01D) #define SPR_BOOKE_PID (0x030) #define SPR_BOOKE_DECAR (0x036) #define SPR_BOOKE_CSRR0 (0x03A) @@ -951,6 +1003,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_8xx_EIE (0x050) #define SPR_8xx_EID (0x051) #define SPR_8xx_NRE (0x052) +#define SPR_CTRL (0x088) #define SPR_58x_CMPA (0x090) #define SPR_58x_CMPB (0x091) #define SPR_58x_CMPC (0x092) @@ -959,6 +1012,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_58x_DER (0x094) #define SPR_58x_COUNTA (0x096) #define SPR_58x_COUNTB (0x097) +#define SPR_UCTRL (0x098) #define SPR_58x_CMPE (0x098) #define SPR_58x_CMPF (0x099) #define SPR_58x_CMPG (0x09A) @@ -992,14 +1046,18 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_EAR (0x11A) #define SPR_TBL (0x11C) #define SPR_TBU (0x11D) +#define SPR_TBU40 (0x11E) #define SPR_SVR (0x11E) #define SPR_BOOKE_PIR (0x11E) #define SPR_PVR (0x11F) #define SPR_HSPRG0 (0x130) #define SPR_BOOKE_DBSR (0x130) #define SPR_HSPRG1 (0x131) +#define SPR_HDSISR (0x132) +#define SPR_HDAR (0x133) #define SPR_BOOKE_DBCR0 (0x134) #define SPR_IBCR (0x135) +#define SPR_PURR (0x135) #define SPR_BOOKE_DBCR1 (0x135) #define SPR_DBCR (0x136) #define SPR_HDEC (0x136) @@ -1039,7 +1097,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_BOOKE_IVOR13 (0x19D) #define SPR_BOOKE_IVOR14 (0x19E) #define SPR_BOOKE_IVOR15 (0x19F) -#define SPR_E500_SPEFSCR (0x200) +#define SPR_BOOKE_SPEFSCR (0x200) #define SPR_E500_BBEAR (0x201) #define SPR_E500_BBTAR (0x202) #define SPR_BOOKE_ATBL (0x20E) @@ -1105,29 +1163,62 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_BOOKE_TLB2CFG (0x2B2) #define SPR_BOOKE_TLB3CFG (0x2B3) #define SPR_BOOKE_EPR (0x2BE) +#define SPR_PERF0 (0x300) +#define SPR_PERF1 (0x301) +#define SPR_PERF2 (0x302) +#define SPR_PERF3 (0x303) +#define SPR_PERF4 (0x304) +#define SPR_PERF5 (0x305) +#define SPR_PERF6 (0x306) +#define SPR_PERF7 (0x307) +#define SPR_PERF8 (0x308) +#define SPR_PERF9 (0x309) +#define SPR_PERFA (0x30A) +#define SPR_PERFB (0x30B) +#define SPR_PERFC (0x30C) +#define SPR_PERFD (0x30D) +#define SPR_PERFE (0x30E) +#define SPR_PERFF (0x30F) +#define SPR_UPERF0 (0x310) +#define SPR_UPERF1 (0x311) +#define SPR_UPERF2 (0x312) +#define SPR_UPERF3 (0x313) +#define SPR_UPERF4 (0x314) +#define SPR_UPERF5 (0x315) +#define SPR_UPERF6 (0x316) +#define SPR_UPERF7 (0x317) +#define SPR_UPERF8 (0x318) +#define SPR_UPERF9 (0x319) +#define SPR_UPERFA (0x31A) +#define SPR_UPERFB (0x31B) +#define SPR_UPERFC (0x31C) +#define SPR_UPERFD (0x31D) +#define SPR_UPERFE (0x31E) +#define SPR_UPERFF (0x31F) #define SPR_440_INV0 (0x370) #define SPR_440_INV1 (0x371) #define SPR_440_INV2 (0x372) #define SPR_440_INV3 (0x373) -#define SPR_440_IVT0 (0x374) -#define SPR_440_IVT1 (0x375) -#define SPR_440_IVT2 (0x376) -#define SPR_440_IVT3 (0x377) +#define SPR_440_ITV0 (0x374) +#define SPR_440_ITV1 (0x375) +#define SPR_440_ITV2 (0x376) +#define SPR_440_ITV3 (0x377) +#define SPR_PPR (0x380) #define SPR_440_DNV0 (0x390) #define SPR_440_DNV1 (0x391) #define SPR_440_DNV2 (0x392) #define SPR_440_DNV3 (0x393) -#define SPR_440_DVT0 (0x394) -#define SPR_440_DVT1 (0x395) -#define SPR_440_DVT2 (0x396) -#define SPR_440_DVT3 (0x397) +#define SPR_440_DTV0 (0x394) +#define SPR_440_DTV1 (0x395) +#define SPR_440_DTV2 (0x396) +#define SPR_440_DTV3 (0x397) #define SPR_440_DVLIM (0x398) #define SPR_440_IVLIM (0x399) #define SPR_440_RSTCFG (0x39B) -#define SPR_BOOKE_DCBTRL (0x39C) -#define SPR_BOOKE_DCBTRH (0x39D) -#define SPR_BOOKE_ICBTRL (0x39E) -#define SPR_BOOKE_ICBTRH (0x39F) +#define SPR_BOOKE_DCDBTRL (0x39C) +#define SPR_BOOKE_DCDBTRH (0x39D) +#define SPR_BOOKE_ICDBTRL (0x39E) +#define SPR_BOOKE_ICDBTRH (0x39F) #define SPR_UMMCR0 (0x3A8) #define SPR_UPMC1 (0x3A9) #define SPR_UPMC2 (0x3AA) @@ -1166,7 +1257,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_DCMP (0x3D1) #define SPR_HASH1 (0x3D2) #define SPR_HASH2 (0x3D3) -#define SPR_BOOKE_ICBDR (0x3D3) +#define SPR_BOOKE_ICDBDR (0x3D3) #define SPR_IMISS (0x3D4) #define SPR_40x_ESR (0x3D4) #define SPR_ICMP (0x3D5) @@ -1204,6 +1295,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_40x_IAC2 (0x3F5) #define SPR_601_HID5 (0x3F5) #define SPR_40x_DAC1 (0x3F6) +#define SPR_DABRX (0x3F7) #define SPR_40x_DAC2 (0x3F7) #define SPR_BOOKE_MMUCFG (0x3F7) #define SPR_L2PM (0x3F8) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 534ad6b5d..e5d152d7e 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1072,6 +1072,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, case PPC_FLAGS_MMU_SOFT_6xx: case PPC_FLAGS_MMU_601: case PPC_FLAGS_MMU_SOFT_4xx: + case PPC_FLAGS_MMU_401: ctx->prot |= PAGE_WRITE; break; #if defined(TARGET_PPC64) @@ -1168,6 +1169,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, /* XXX: TODO */ cpu_abort(env, "BookE FSL MMU model not implemented\n"); return -1; + case PPC_FLAGS_MMU_401: + cpu_abort(env, "PowerPC 401 does not do any translation\n"); + return -1; default: cpu_abort(env, "Unknown or invalid MMU model\n"); return -1; @@ -1267,6 +1271,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; + case PPC_FLAGS_MMU_401: + cpu_abort(env, "PowerPC 401 should never raise any MMU " + "exceptions\n"); + return -1; default: cpu_abort(env, "Unknown or invalid MMU model\n"); return -1; @@ -1348,6 +1356,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; + case PPC_FLAGS_MMU_401: + cpu_abort(env, "PowerPC 401 should never raise any MMU " + "exceptions\n"); + return -1; default: cpu_abort(env, "Unknown or invalid MMU model\n"); return -1; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index db90f3f4d..9d6bf3206 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4221,12 +4221,14 @@ GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2) } /* BookE specific instructions */ +/* XXX: not implemented on 440 ? */ GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE) { /* XXX: TODO */ RET_INVAL(ctx); } +/* XXX: not implemented on 440 ? */ GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) @@ -4329,98 +4331,99 @@ static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3, } } -#define GEN_MAC_HANDLER(name, opc2, opc3) \ -GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC) \ +#define GEN_MAC_HANDLER(name, opc2, opc3, is_440) \ +GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, \ + is_440 ? PPC_440_SPEC : PPC_405_MAC) \ { \ gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode), \ rD(ctx->opcode), Rc(ctx->opcode)); \ } /* macchw - macchw. */ -GEN_MAC_HANDLER(macchw, 0x0C, 0x05); +GEN_MAC_HANDLER(macchw, 0x0C, 0x05, 0); /* macchwo - macchwo. */ -GEN_MAC_HANDLER(macchwo, 0x0C, 0x15); +GEN_MAC_HANDLER(macchwo, 0x0C, 0x15, 0); /* macchws - macchws. */ -GEN_MAC_HANDLER(macchws, 0x0C, 0x07); +GEN_MAC_HANDLER(macchws, 0x0C, 0x07, 0); /* macchwso - macchwso. */ -GEN_MAC_HANDLER(macchwso, 0x0C, 0x17); +GEN_MAC_HANDLER(macchwso, 0x0C, 0x17, 0); /* macchwsu - macchwsu. */ -GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06); +GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06, 0); /* macchwsuo - macchwsuo. */ -GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16); +GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16, 0); /* macchwu - macchwu. */ -GEN_MAC_HANDLER(macchwu, 0x0C, 0x04); +GEN_MAC_HANDLER(macchwu, 0x0C, 0x04, 0); /* macchwuo - macchwuo. */ -GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14); +GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14, 0); /* machhw - machhw. */ -GEN_MAC_HANDLER(machhw, 0x0C, 0x01); +GEN_MAC_HANDLER(machhw, 0x0C, 0x01, 0); /* machhwo - machhwo. */ -GEN_MAC_HANDLER(machhwo, 0x0C, 0x11); +GEN_MAC_HANDLER(machhwo, 0x0C, 0x11, 0); /* machhws - machhws. */ -GEN_MAC_HANDLER(machhws, 0x0C, 0x03); +GEN_MAC_HANDLER(machhws, 0x0C, 0x03, 0); /* machhwso - machhwso. */ -GEN_MAC_HANDLER(machhwso, 0x0C, 0x13); +GEN_MAC_HANDLER(machhwso, 0x0C, 0x13, 0); /* machhwsu - machhwsu. */ -GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02); +GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02, 0); /* machhwsuo - machhwsuo. */ -GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12); +GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12, 0); /* machhwu - machhwu. */ -GEN_MAC_HANDLER(machhwu, 0x0C, 0x00); +GEN_MAC_HANDLER(machhwu, 0x0C, 0x00, 0); /* machhwuo - machhwuo. */ -GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10); +GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10, 0); /* maclhw - maclhw. */ -GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D); +GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D, 0); /* maclhwo - maclhwo. */ -GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D); +GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D, 0); /* maclhws - maclhws. */ -GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F); +GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F, 0); /* maclhwso - maclhwso. */ -GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F); +GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F, 0); /* maclhwu - maclhwu. */ -GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C); +GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C, 0); /* maclhwuo - maclhwuo. */ -GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C); +GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C, 0); /* maclhwsu - maclhwsu. */ -GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E); +GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E, 0); /* maclhwsuo - maclhwsuo. */ -GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E); +GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E, 0); /* nmacchw - nmacchw. */ -GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05); +GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05, 0); /* nmacchwo - nmacchwo. */ -GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15); +GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15, 0); /* nmacchws - nmacchws. */ -GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07); +GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07, 0); /* nmacchwso - nmacchwso. */ -GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17); +GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17, 0); /* nmachhw - nmachhw. */ -GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01); +GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01, 0); /* nmachhwo - nmachhwo. */ -GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11); +GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11, 0); /* nmachhws - nmachhws. */ -GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03); +GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03, 1); /* nmachhwso - nmachhwso. */ -GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13); +GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13, 1); /* nmaclhw - nmaclhw. */ -GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D); +GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D, 1); /* nmaclhwo - nmaclhwo. */ -GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D); +GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D, 1); /* nmaclhws - nmaclhws. */ -GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F); +GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F, 1); /* nmaclhwso - nmaclhwso. */ -GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F); +GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F, 1); /* mulchw - mulchw. */ -GEN_MAC_HANDLER(mulchw, 0x08, 0x05); +GEN_MAC_HANDLER(mulchw, 0x08, 0x05, 0); /* mulchwu - mulchwu. */ -GEN_MAC_HANDLER(mulchwu, 0x08, 0x04); +GEN_MAC_HANDLER(mulchwu, 0x08, 0x04, 0); /* mulhhw - mulhhw. */ -GEN_MAC_HANDLER(mulhhw, 0x08, 0x01); +GEN_MAC_HANDLER(mulhhw, 0x08, 0x01, 0); /* mulhhwu - mulhhwu. */ -GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00); +GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00, 0); /* mullhw - mullhw. */ -GEN_MAC_HANDLER(mullhw, 0x08, 0x0D); +GEN_MAC_HANDLER(mullhw, 0x08, 0x0D, 0); /* mullhwu - mullhwu. */ -GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C); +GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C, 0); /* mfdcr */ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) @@ -4459,6 +4462,7 @@ GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) } /* mfdcrx */ +/* XXX: not implemented on 440 ? */ GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) @@ -4475,6 +4479,7 @@ GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE) } /* mtdcrx */ +/* XXX: not implemented on 440 ? */ GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) @@ -4521,7 +4526,7 @@ GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON) } /* icbt */ -GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC) +GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT) { /* interpreted as no-op */ /* XXX: specification say this is treated as a load by the MMU @@ -4589,6 +4594,7 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE) } /* BookE specific */ +/* XXX: not implemented on 440 ? */ GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) @@ -4604,6 +4610,7 @@ GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE) #endif } +/* XXX: not implemented on 440 ? */ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 131346d81..82270e659 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1123,6 +1123,7 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); +#if 0 spr_register(env, SPR_BOOKE_DSRR0, "DSRR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1139,6 +1140,7 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); +#endif /* Debug */ /* XXX : not implemented */ spr_register(env, SPR_BOOKE_IAC1, "IAC1", @@ -1277,6 +1279,7 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); +#if 0 spr_register(env, SPR_BOOKE_IVOR32, "IVOR32", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1301,6 +1304,7 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); +#endif spr_register(env, SPR_BOOKE_PID, "PID", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1469,22 +1473,22 @@ static void gen_spr_440 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_DVT0, "DVT0", + spr_register(env, SPR_440_DTV0, "DTV0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_DVT1, "DVT1", + spr_register(env, SPR_440_DTV1, "DTV1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_DVT2, "DVT2", + spr_register(env, SPR_440_DTV2, "DTV2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_DVT3, "DVT3", + spr_register(env, SPR_440_DTV3, "DTV3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -1514,22 +1518,22 @@ static void gen_spr_440 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_IVT0, "IVT0", + spr_register(env, SPR_440_ITV0, "ITV0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_IVT1, "IVT1", + spr_register(env, SPR_440_ITV1, "ITV1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_IVT2, "IVT2", + spr_register(env, SPR_440_ITV2, "ITV2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_IVT3, "IVT3", + spr_register(env, SPR_440_ITV3, "ITV3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -1540,27 +1544,27 @@ static void gen_spr_440 (CPUPPCState *env) 0x00000000); /* Cache debug */ /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DCBTRH, "DCBTRH", + spr_register(env, SPR_BOOKE_DCDBTRH, "DCDBTRH", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DCBTRL, "DCBTRL", + spr_register(env, SPR_BOOKE_DCDBTRL, "DCDBTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_ICBDR, "ICBDR", + spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_ICBTRH, "ICBTRH", + spr_register(env, SPR_BOOKE_ICDBTRH, "ICDBTRH", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_ICBTRL, "ICBTRL", + spr_register(env, SPR_BOOKE_ICDBTRL, "ICDBTRL", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); @@ -1605,7 +1609,7 @@ static void gen_spr_40x (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_ICBDR, "ICBDR", + spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); @@ -1614,15 +1618,6 @@ static void gen_spr_40x (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0xFFFFFFFF); - spr_register(env, SPR_40x_ZPR, "ZPR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* MMU */ - spr_register(env, SPR_40x_PID, "PID", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); /* Exception */ spr_register(env, SPR_40x_DEAR, "DEAR", SPR_NOACCESS, SPR_NOACCESS, @@ -1657,58 +1652,62 @@ static void gen_spr_40x (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_booke_tsr, 0x00000000); - /* Debug interface */ - /* XXX : not implemented */ - spr_register(env, SPR_40x_DAC1, "DAC1", +} + +/* SPR specific to PowerPC 405 implementation */ +static void gen_spr_405 (CPUPPCState *env) +{ + /* MMU */ + spr_register(env, SPR_40x_PID, "PID", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_40x_DAC2, "DAC2", + spr_register(env, SPR_4xx_CCR0, "CCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0x00000000); + 0x00700000); + /* Debug interface */ /* XXX : not implemented */ spr_register(env, SPR_40x_DBCR0, "DBCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_40x_dbcr0, 0x00000000); /* XXX : not implemented */ + spr_register(env, SPR_405_DBCR1, "DBCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_40x_DBSR, "DBSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_clear, /* Last reset was system reset */ 0x00000300); /* XXX : not implemented */ - spr_register(env, SPR_40x_IAC1, "IAC1", + spr_register(env, SPR_40x_DAC1, "DAC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_40x_IAC2, "IAC2", + spr_register(env, SPR_40x_DAC2, "DAC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); -} - -/* SPR specific to PowerPC 405 implementation */ -static void gen_spr_405 (CPUPPCState *env) -{ - spr_register(env, SPR_4xx_CCR0, "CCR0", + /* XXX : not implemented */ + spr_register(env, SPR_405_DVC1, "DVC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0x00700000); - /* Debug */ + 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_405_DBCR1, "DBCR1", + spr_register(env, SPR_405_DVC2, "DVC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_405_DVC1, "DVC1", + spr_register(env, SPR_40x_IAC1, "IAC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_405_DVC2, "DVC2", + spr_register(env, SPR_40x_IAC2, "IAC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -1727,6 +1726,10 @@ static void gen_spr_405 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_40x_sler, 0x00000000); + spr_register(env, SPR_40x_ZPR, "ZPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_405_SU0R, "SU0R", SPR_NOACCESS, SPR_NOACCESS, @@ -1799,10 +1802,76 @@ static void gen_spr_401_403 (CPUPPCState *env) 0x00000000); } +/* SPR specific to PowerPC 401 implementation */ +static void gen_spr_401 (CPUPPCState *env) +{ + /* Debug interface */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DBCR0, "DBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_40x_dbcr0, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DBSR, "DBSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_clear, + /* Last reset was system reset */ + 0x00000300); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC1, "DAC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC1, "IAC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Storage control */ + spr_register(env, SPR_405_SLER, "SLER", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_40x_sler, + 0x00000000); +} + /* SPR specific to PowerPC 403 implementation */ static void gen_spr_403 (CPUPPCState *env) { + /* Debug interface */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DBCR0, "DBCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_40x_dbcr0, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DBSR, "DBSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_clear, + /* Last reset was system reset */ + 0x00000300); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC1, "DAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC1, "IAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* MMU */ + spr_register(env, SPR_40x_PID, "PID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); spr_register(env, SPR_403_PBL1, "PBL1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_403_pbr, &spr_write_403_pbr, @@ -1819,14 +1888,7 @@ static void gen_spr_403 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_403_pbr, &spr_write_403_pbr, 0x00000000); - /* Debug */ - /* XXX : not implemented */ - spr_register(env, SPR_40x_DAC2, "DAC2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_40x_IAC2, "IAC2", + spr_register(env, SPR_40x_ZPR, "ZPR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -1843,23 +1905,40 @@ static void gen_spr_compress (CPUPPCState *env) } #endif -// XXX: TODO (64 bits PowerPC SPRs) +// XXX: TODO /* - * ASR => SPR 280 (64 bits) - * FPECR => SPR 1022 (?) - * VRSAVE => SPR 256 (Altivec) - * SCOMC => SPR 276 (64 bits ?) - * SCOMD => SPR 277 (64 bits ?) - * HSPRG0 => SPR 304 (hypervisor) - * HSPRG1 => SPR 305 (hypervisor) - * HDEC => SPR 310 (hypervisor) - * HIOR => SPR 311 (hypervisor) - * RMOR => SPR 312 (970) - * HRMOR => SPR 313 (hypervisor) - * HSRR0 => SPR 314 (hypervisor) - * HSRR1 => SPR 315 (hypervisor) - * LPCR => SPR 316 (970) - * LPIDR => SPR 317 (970) + * AMR => SPR 29 (Power 2.04) + * CTRL => SPR 136 (Power 2.04) + * CTRL => SPR 152 (Power 2.04) + * VRSAVE => SPR 256 (Altivec) + * SCOMC => SPR 276 (64 bits ?) + * SCOMD => SPR 277 (64 bits ?) + * ASR => SPR 280 (64 bits) + * TBU40 => SPR 286 (Power 2.04 hypv) + * HSPRG0 => SPR 304 (Power 2.04 hypv) + * HSPRG1 => SPR 305 (Power 2.04 hypv) + * HDSISR => SPR 306 (Power 2.04 hypv) + * HDAR => SPR 307 (Power 2.04 hypv) + * PURR => SPR 309 (Power 2.04 hypv) + * HDEC => SPR 310 (Power 2.04 hypv) + * HIOR => SPR 311 (hypv) + * RMOR => SPR 312 (970) + * HRMOR => SPR 313 (Power 2.04 hypv) + * HSRR0 => SPR 314 (Power 2.04 hypv) + * HSRR1 => SPR 315 (Power 2.04 hypv) + * LPCR => SPR 316 (970) + * LPIDR => SPR 317 (970) + * SPEFSCR => SPR 512 (Power 2.04 emb) + * ATBL => SPR 526 (Power 2.04 emb) + * ATBU => SPR 527 (Power 2.04 emb) + * EPR => SPR 702 (Power 2.04 emb) + * perf => 768-783 (Power 2.04) + * perf => 784-799 (Power 2.04) + * PPR => SPR 896 (Power 2.04) + * EPLC => SPR 947 (Power 2.04 emb) + * EPSC => SPR 948 (Power 2.04 emb) + * DABRX => 1015 (Power 2.04 hypv) + * FPECR => SPR 1022 (?) * ... and more (thermal management, performance counters, ...) */ @@ -1886,6 +1965,9 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) /* Embedded PowerPC from IBM */ case CPU_PPC_401A1: /* 401 A1 family */ case CPU_PPC_401B2: /* 401 B2 family */ +#if 0 + case CPU_PPC_401B3: /* 401 B3 family */ +#endif case CPU_PPC_401C2: /* 401 C2 family */ case CPU_PPC_401D2: /* 401 D2 family */ case CPU_PPC_401E2: /* 401 E2 family */ @@ -1896,6 +1978,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) gen_spr_generic(env); gen_spr_40x(env); gen_spr_401_403(env); + gen_spr_401(env); #if defined (TODO) /* XXX: optional ? */ gen_spr_compress(env); @@ -2413,7 +2496,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) #endif /* defined (TARGET_PPC64) */ #if defined (TODO) - /* POWER */ + /* POWER */ case CPU_POWER: /* POWER */ case CPU_POWER2: /* POWER2 */ break; @@ -2460,7 +2543,7 @@ static void dump_sprs (CPUPPCState *env) uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS; ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS; if (sw || sr || uw || ur) { - printf("%4d (%03x) %8s s%c%c u%c%c\n", + printf("SPR: %4d (%03x) %-8s s%c%c u%c%c\n", (i << 5) | j, (i << 5) | j, spr->name, sw ? 'w' : '-', sr ? 'r' : '-', uw ? 'w' : '-', ur ? 'r' : '-'); @@ -2678,15 +2761,15 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) if (opc1 != 0x00) { if (opc->opc3 == 0xFF) { if (opc->opc2 == 0xFF) { - printf(" %02x -- -- (%2d ----) : %s\n", + printf("INSN: %02x -- -- (%02d ----) : %s\n", opc->opc1, opc->opc1, opc->oname); } else { - printf(" %02x %02x -- (%2d %4d) : %s\n", + printf("INSN: %02x %02x -- (%02d %04d) : %s\n", opc->opc1, opc->opc2, opc->opc1, opc->opc2, opc->oname); } } else { - printf(" %02x %02x %02x (%2d %4d) : %s\n", + printf("INSN: %02x %02x %02x (%02d %04d) : %s\n", opc->opc1, opc->opc2, opc->opc3, opc->opc1, (opc->opc3 << 5) | opc->opc2, opc->oname); @@ -2724,15 +2807,98 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) /* PowerPC CPU definitions */ static ppc_def_t ppc_defs[] = { /* Embedded PowerPC */ -#if defined (TODO) - /* PowerPC 401 */ + /* Generic PowerPC 401 */ { .name = "401", .pvr = CPU_PPC_401, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_401, .flags = PPC_FLAGS_401, - .msr_mask = xxx, + .msr_mask = 0x000FD201, + }, + /* PowerPC 401A1 */ + { + .name = "401a1", + .pvr = CPU_PPC_401A1, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, + }, + /* PowerPC 401B2 */ + { + .name = "401b2", + .pvr = CPU_PPC_401B2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, + }, +#if defined (TODO) + /* PowerPC 401B3 */ + { + .name = "401b3", + .pvr = CPU_PPC_401B3, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, + }, +#endif + /* PowerPC 401C2 */ + { + .name = "401c2", + .pvr = CPU_PPC_401C2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, + }, + /* PowerPC 401D2 */ + { + .name = "401d2", + .pvr = CPU_PPC_401D2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, + }, + /* PowerPC 401E2 */ + { + .name = "401e2", + .pvr = CPU_PPC_401E2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, + }, + /* PowerPC 401F2 */ + { + .name = "401f2", + .pvr = CPU_PPC_401F2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, + }, + /* PowerPC 401G2 */ + { + .name = "401g2", + .pvr = CPU_PPC_401G2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, + }, +#if defined (TODO) + /* PowerPC 401G2 */ + { + .name = "401gf", + .pvr = CPU_PPC_401GF, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = 0x000FD201, }, #endif #if defined (TODO) @@ -2740,10 +2906,10 @@ static ppc_def_t ppc_defs[] = { { .name = "iop480", .pvr = CPU_PPC_IOP480, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_401, .flags = PPC_FLAGS_401, - .msr_mask = xxx, + .msr_mask = 0x000FD201, }, #endif #if defined (TODO) @@ -2751,62 +2917,63 @@ static ppc_def_t ppc_defs[] = { { .name = "Cobra", .pvr = CPU_PPC_COBRA, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_401, .flags = PPC_FLAGS_401, - .msr_mask = xxx, + .msr_mask = 0x000FD201, }, #endif -#if defined (TODO) /* Generic PowerPC 403 */ { .name = "403", .pvr = CPU_PPC_403, - .pvr_mask = 0xFFFFFF00, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, .msr_mask = 0x000000000007D23DULL, }, -#endif -#if defined (TODO) /* PowerPC 403 GA */ { .name = "403ga", .pvr = CPU_PPC_403GA, - .pvr_mask = 0xFFFFFF00, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, .msr_mask = 0x000000000007D23DULL, }, -#endif -#if defined (TODO) /* PowerPC 403 GB */ { .name = "403gb", .pvr = CPU_PPC_403GB, - .pvr_mask = 0xFFFFFF00, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, .msr_mask = 0x000000000007D23DULL, }, -#endif -#if defined (TODO) /* PowerPC 403 GC */ { .name = "403gc", .pvr = CPU_PPC_403GC, - .pvr_mask = 0xFFFFFF00, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, .msr_mask = 0x000000000007D23DULL, }, -#endif -#if defined (TODO) /* PowerPC 403 GCX */ { .name = "403gcx", .pvr = CPU_PPC_403GCX, - .pvr_mask = 0xFFFFFF00, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23DULL, + }, +#if defined (TODO) + /* PowerPC 403 GP */ + { + .name = "403gp", + .pvr = CPU_PPC_403GP, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_403, .flags = PPC_FLAGS_403, .msr_mask = 0x000000000007D23DULL, @@ -2816,45 +2983,27 @@ static ppc_def_t ppc_defs[] = { { .name = "405", .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - /* PowerPC 405 CR */ - { - .name = "405cr", - .pvr = CPU_PPC_405, .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, .msr_mask = 0x00000000020EFF30ULL, }, #if defined (TODO) - /* PowerPC 405 GP */ + /* PowerPC 405 A3 */ { - .name = "405gp", - .pvr = CPU_PPC_405, + .name = "405a3", + .pvr = CPU_PPC_405A3, .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, .msr_mask = 0x00000000020EFF30ULL, }, #endif - /* PowerPC 405 EP */ - { - .name = "405ep", - .pvr = CPU_PPC_405EP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000000ED630ULL, - }, #if defined (TODO) - /* PowerPC 405 EZ */ + /* PowerPC 405 A4 */ { - .name = "405ez", - .pvr = CPU_PPC_405EZ, + .name = "405a4", + .pvr = CPU_PPC_405A4, .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, @@ -2862,10 +3011,10 @@ static ppc_def_t ppc_defs[] = { }, #endif #if defined (TODO) - /* PowerPC 405 GPR */ + /* PowerPC 405 B3 */ { - .name = "405gpr", - .pvr = CPU_PPC_405GPR, + .name = "405b3", + .pvr = CPU_PPC_405B3, .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, @@ -2890,41 +3039,117 @@ static ppc_def_t ppc_defs[] = { .flags = PPC_FLAGS_405, .msr_mask = 0x00000000020EFF30ULL, }, -#if defined (TODO) - /* Npe405 H */ + /* PowerPC 405 CR */ { - .name = "Npe405H", - .pvr = CPU_PPC_NPE405H, + .name = "405cr", + .pvr = CPU_PPC_405CR, .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, .msr_mask = 0x00000000020EFF30ULL, }, -#endif -#if defined (TODO) - /* Npe405 L */ + /* PowerPC 405 GP */ { - .name = "Npe405L", - .pvr = CPU_PPC_NPE405L, + .name = "405gp", + .pvr = CPU_PPC_405GP, .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, .msr_mask = 0x00000000020EFF30ULL, }, -#endif -#if defined (TODO) - /* STB010000 */ + /* PowerPC 405 EP */ { - .name = "STB01000", - .pvr = CPU_PPC_STB01000, + .name = "405ep", + .pvr = CPU_PPC_405EP, .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_405, .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, + .msr_mask = 0x00000000000ED630ULL, }, -#endif #if defined (TODO) - /* STB01010 */ + /* PowerPC 405 EZ */ + { + .name = "405ez", + .pvr = CPU_PPC_405EZ, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 405 GPR */ + { + .name = "405gpr", + .pvr = CPU_PPC_405GPR, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 405 LP */ + { + .name = "405lp", + .pvr = CPU_PPC_405EZ, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30ULL, + }, +#endif + /* Npe405 H */ + { + .name = "Npe405H", + .pvr = CPU_PPC_NPE405H, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30ULL, + }, + /* Npe405 H2 */ + { + .name = "Npe405H2", + .pvr = CPU_PPC_NPE405H2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30ULL, + }, + /* Npe405 L */ + { + .name = "Npe405L", + .pvr = CPU_PPC_NPE405L, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30ULL, + }, +#if defined (TODO) + /* PowerPC LP777000 */ + { + .name = "lp777000", + .pvr = CPU_PPC_LP777000, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30ULL, + }, +#endif +#if defined (TODO) + /* STB010000 */ + { + .name = "STB01000", + .pvr = CPU_PPC_STB01000, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30ULL, + }, +#endif +#if defined (TODO) + /* STB01010 */ { .name = "STB01010", .pvr = CPU_PPC_STB01010, @@ -2978,7 +3203,7 @@ static ppc_def_t ppc_defs[] = { .msr_mask = 0x00000000020EFF30ULL, }, #endif -#if defined (TODO) +#if defined (TODO) || 1 /* STB25xx */ { .name = "STB25", @@ -3035,105 +3260,98 @@ static ppc_def_t ppc_defs[] = { .msr_mask = 0x00000000020EFF30ULL, }, #endif -#if defined (TODO) /* PowerPC 440 EP */ { .name = "440ep", .pvr = CPU_PPC_440EP, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif -#if defined (TODO) /* PowerPC 440 GR */ { .name = "440gr", .pvr = CPU_PPC_440GR, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif -#if defined (TODO) /* PowerPC 440 GP */ { .name = "440gp", .pvr = CPU_PPC_440GP, - .pvr_mask = 0xFFFFFF00, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif #if defined (TODO) + /* PowerPC 440 GRX */ + { + .name = "440grx", + .pvr = CPU_PPC_440GRX, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630ULL, + }, +#endif /* PowerPC 440 GX */ { .name = "440gx", .pvr = CPU_PPC_440GX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif -#if defined (TODO) /* PowerPC 440 GXc */ { .name = "440gxc", - .pvr = CPU_PPC_440GXC, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, + .pvr = CPU_PPC_440GXc, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif -#if defined (TODO) /* PowerPC 440 GXf */ { .name = "440gxf", - .pvr = CPU_PPC_440GXF, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, + .pvr = CPU_PPC_440GXf, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif -#if defined (TODO) /* PowerPC 440 SP */ { .name = "440sp", .pvr = CPU_PPC_440SP, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif -#if defined (TODO) /* PowerPC 440 SP2 */ { .name = "440sp2", .pvr = CPU_PPC_440SP2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif -#if defined (TODO) /* PowerPC 440 SPE */ { .name = "440spe", .pvr = CPU_PPC_440SPE, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_440, .flags = PPC_FLAGS_440, .msr_mask = 0x000000000006D630ULL, }, -#endif /* Fake generic BookE PowerPC */ { .name = "BookE", @@ -3157,7 +3375,7 @@ static ppc_def_t ppc_defs[] = { { .name = "601", .pvr = CPU_PPC_601, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_601, .flags = PPC_FLAGS_601, .msr_mask = 0x000000000000FD70ULL, @@ -3168,7 +3386,7 @@ static ppc_def_t ppc_defs[] = { { .name = "602", .pvr = CPU_PPC_602, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_602, .flags = PPC_FLAGS_602, .msr_mask = 0x0000000000C7FF73ULL, @@ -3258,7 +3476,7 @@ static ppc_def_t ppc_defs[] = { { .name = "G2", .pvr = CPU_PPC_G2, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, .msr_mask = 0x000000000006FFF2ULL, @@ -3266,7 +3484,7 @@ static ppc_def_t ppc_defs[] = { { .name = "G2h4", .pvr = CPU_PPC_G2H4, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, .msr_mask = 0x000000000006FFF2ULL, @@ -3274,7 +3492,7 @@ static ppc_def_t ppc_defs[] = { { .name = "G2gp", .pvr = CPU_PPC_G2gp, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, .msr_mask = 0x000000000006FFF2ULL, @@ -3282,7 +3500,7 @@ static ppc_def_t ppc_defs[] = { { .name = "G2ls", .pvr = CPU_PPC_G2ls, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, .msr_mask = 0x000000000006FFF2ULL, @@ -3290,7 +3508,7 @@ static ppc_def_t ppc_defs[] = { { /* Same as G2, with LE mode support */ .name = "G2le", .pvr = CPU_PPC_G2LE, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, .msr_mask = 0x000000000007FFF3ULL, @@ -3298,7 +3516,7 @@ static ppc_def_t ppc_defs[] = { { .name = "G2legp", .pvr = CPU_PPC_G2LEgp, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, .msr_mask = 0x000000000007FFF3ULL, @@ -3306,7 +3524,7 @@ static ppc_def_t ppc_defs[] = { { .name = "G2lels", .pvr = CPU_PPC_G2LEls, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_G2, .flags = PPC_FLAGS_G2, .msr_mask = 0x000000000007FFF3ULL, @@ -3365,45 +3583,15 @@ static ppc_def_t ppc_defs[] = { .flags = PPC_FLAGS_7x0, .msr_mask = 0x000000000007FF77ULL, }, -#if defined (TODO) - /* MPC745 (G3) */ - { - .name = "745", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, - { - .name = "Goldfinger", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, -#endif - /* MPC750 (G3) */ + /* 740E (G3) */ { - .name = "750", - .pvr = CPU_PPC_74x, + .name = "740e", + .pvr = CPU_PPC_740E, .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x0, .flags = PPC_FLAGS_7x0, .msr_mask = 0x000000000007FF77ULL, }, -#if defined (TODO) - /* MPC755 (G3) */ - { - .name = "755", - .pvr = CPU_PPC_755, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, -#endif /* MPC740P (G3) */ { .name = "740p", @@ -3421,17 +3609,45 @@ static ppc_def_t ppc_defs[] = { .flags = PPC_FLAGS_7x0, .msr_mask = 0x000000000007FF77ULL, }, +#if defined (TODO) + /* MPC745 (G3) */ + { + .name = "745", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77ULL, + }, + { + .name = "Goldfinger", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77ULL, + }, +#endif #if defined (TODO) /* MPC745P (G3) */ { .name = "745p", .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_7x5, .flags = PPC_FLAGS_7x5, .msr_mask = 0x000000000007FF77ULL, }, #endif + /* MPC750 (G3) */ + { + .name = "750", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77ULL, + }, /* MPC750P (G3) */ { .name = "750p", @@ -3441,17 +3657,15 @@ static ppc_def_t ppc_defs[] = { .flags = PPC_FLAGS_7x0, .msr_mask = 0x000000000007FF77ULL, }, -#if defined (TODO) - /* MPC755P (G3) */ + /* 750E (G3) */ { - .name = "755p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, + .name = "750e", + .pvr = CPU_PPC_750E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, .msr_mask = 0x000000000007FF77ULL, }, -#endif /* IBM 750CXe (G3 embedded) */ { .name = "750cxe", @@ -3461,6 +3675,15 @@ static ppc_def_t ppc_defs[] = { .flags = PPC_FLAGS_7x0, .msr_mask = 0x000000000007FF77ULL, }, + /* IBM 750CXr (G3 embedded) */ + { + .name = "750cxr", + .pvr = CPU_PPC_750CXR, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77ULL, + }, /* IBM 750FX (G3 embedded) */ { .name = "750fx", @@ -3470,6 +3693,15 @@ static ppc_def_t ppc_defs[] = { .flags = PPC_FLAGS_7x0, .msr_mask = 0x000000000007FF77ULL, }, + /* IBM 750FL (G3 embedded) */ + { + .name = "750fl", + .pvr = CPU_PPC_750FL, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77ULL, + }, /* IBM 750GX (G3 embedded) */ { .name = "750gx", @@ -3479,12 +3711,74 @@ static ppc_def_t ppc_defs[] = { .flags = PPC_FLAGS_7x0, .msr_mask = 0x000000000007FF77ULL, }, + /* IBM 750L (G3 embedded) */ + { + .name = "750l", + .pvr = CPU_PPC_750L, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77ULL, + }, + /* IBM 750CL (G3 embedded) */ + { + .name = "750cl", + .pvr = CPU_PPC_750CL, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77ULL, + }, +#if defined (TODO) + /* MPC755 (G3) */ + { + .name = "755", + .pvr = CPU_PPC_755, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77ULL, + }, +#endif +#if defined (TODO) + /* MPC755D (G3) */ + { + .name = "755d", + .pvr = CPU_PPC_755D, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77ULL, + }, +#endif +#if defined (TODO) + /* MPC755E (G3) */ + { + .name = "755e", + .pvr = CPU_PPC_755E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77ULL, + }, +#endif +#if defined (TODO) + /* MPC755P (G3) */ + { + .name = "755p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77ULL, + }, +#endif #if defined (TODO) /* generic G4 */ { .name = "G4", .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3495,7 +3789,7 @@ static ppc_def_t ppc_defs[] = { { .name = "7400", .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3503,7 +3797,7 @@ static ppc_def_t ppc_defs[] = { { .name = "Max", .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3514,7 +3808,7 @@ static ppc_def_t ppc_defs[] = { { .name = "7410", .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3522,22 +3816,73 @@ static ppc_def_t ppc_defs[] = { { .name = "Nitro", .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7441 (G4) */ + { + .name = "7441", + .pvr = CPU_PPC_7441, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7445 (G4) */ + { + .name = "7445", + .pvr = CPU_PPC_7445, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7447 (G4) */ + { + .name = "7447", + .pvr = CPU_PPC_7447, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7447A (G4) */ + { + .name = "7447A", + .pvr = CPU_PPC_7447A, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7448 (G4) */ + { + .name = "7448", + .pvr = CPU_PPC_7448, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, }, #endif - /* XXX: 7441 */ - /* XXX: 7445 */ - /* XXX: 7447 */ - /* XXX: 7447A */ #if defined (TODO) /* PowerPC 7450 (G4) */ { .name = "7450", .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3545,19 +3890,51 @@ static ppc_def_t ppc_defs[] = { { .name = "Vger", .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7450b (G4) */ + { + .name = "7450b", + .pvr = CPU_PPC_7450B, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7451 (G4) */ + { + .name = "7451", + .pvr = CPU_PPC_7451, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7451g (G4) */ + { + .name = "7451g", + .pvr = CPU_PPC_7451G, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, }, #endif - /* XXX: 7451 */ #if defined (TODO) /* PowerPC 7455 (G4) */ { .name = "7455", .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3565,7 +3942,29 @@ static ppc_def_t ppc_defs[] = { { .name = "Apollo 6", .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7455F (G4) */ + { + .name = "7455f", + .pvr = CPU_PPC_7455F, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7455G (G4) */ + { + .name = "7455g", + .pvr = CPU_PPC_7455G, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3576,7 +3975,7 @@ static ppc_def_t ppc_defs[] = { { .name = "7457", .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3584,7 +3983,7 @@ static ppc_def_t ppc_defs[] = { { .name = "Apollo 7", .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3595,7 +3994,7 @@ static ppc_def_t ppc_defs[] = { { .name = "7457A", .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3603,7 +4002,18 @@ static ppc_def_t ppc_defs[] = { { .name = "Apollo 7 PM", .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77ULL, + }, +#endif +#if defined (TODO) + /* PowerPC 7457C (G4) */ + { + .name = "7457c", + .pvr = CPU_PPC_7457C, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_74xx, .flags = PPC_FLAGS_74xx, .msr_mask = 0x000000000205FF77ULL, @@ -3616,7 +4026,7 @@ static ppc_def_t ppc_defs[] = { { .name = "620", .pvr = CPU_PPC_620, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_620, .flags = PPC_FLAGS_620, .msr_mask = 0x800000000005FF73ULL, @@ -3627,7 +4037,7 @@ static ppc_def_t ppc_defs[] = { { .name = "630", .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_630, .flags = PPC_FLAGS_630, .msr_mask = xxx, @@ -3635,7 +4045,7 @@ static ppc_def_t ppc_defs[] = { { .name = "POWER3", .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_630, .flags = PPC_FLAGS_630, .msr_mask = xxx, @@ -3646,7 +4056,7 @@ static ppc_def_t ppc_defs[] = { { .name = "631", .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_631, .flags = PPC_FLAGS_631, .msr_mask = xxx, @@ -3654,7 +4064,7 @@ static ppc_def_t ppc_defs[] = { { .name = "POWER3+", .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_631, .flags = PPC_FLAGS_631, .msr_mask = xxx, @@ -3665,7 +4075,7 @@ static ppc_def_t ppc_defs[] = { { .name = "POWER4", .pvr = CPU_PPC_POWER4, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_POWER4, .flags = PPC_FLAGS_POWER4, .msr_mask = xxx, @@ -3676,7 +4086,7 @@ static ppc_def_t ppc_defs[] = { { .name = "POWER4+", .pvr = CPU_PPC_POWER4P, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_POWER4, .flags = PPC_FLAGS_POWER4, .msr_mask = xxx, @@ -3687,7 +4097,7 @@ static ppc_def_t ppc_defs[] = { { .name = "POWER5", .pvr = CPU_PPC_POWER5, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_POWER5, .flags = PPC_FLAGS_POWER5, .msr_mask = xxx, @@ -3698,18 +4108,29 @@ static ppc_def_t ppc_defs[] = { { .name = "POWER5+", .pvr = CPU_PPC_POWER5P, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_POWER5, .flags = PPC_FLAGS_POWER5, .msr_mask = xxx, }, #endif +#if defined (TODO) + /* POWER6 */ + { + .name = "POWER6", + .pvr = CPU_PPC_POWER6, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_POWER6, + .flags = PPC_FLAGS_POWER6, + .msr_mask = xxx, + }, +#endif #if defined (TODO) /* PowerPC 970 */ { .name = "970", .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_970, .flags = PPC_FLAGS_970, .msr_mask = 0x900000000204FF36ULL, @@ -3720,12 +4141,34 @@ static ppc_def_t ppc_defs[] = { { .name = "970fx", .pvr = CPU_PPC_970FX, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_970FX, .flags = PPC_FLAGS_970FX, .msr_mask = 0x800000000204FF36ULL, }, #endif +#if defined (TODO) + /* PowerPC 970MP */ + { + .name = "970MP", + .pvr = CPU_PPC_970MP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_970, + .flags = PPC_FLAGS_970, + .msr_mask = 0x900000000204FF36ULL, + }, +#endif +#if defined (TODO) + /* PowerPC Cell */ + { + .name = "Cell", + .pvr = CPU_PPC_CELL, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_970, + .flags = PPC_FLAGS_970, + .msr_mask = 0x900000000204FF36ULL, + }, +#endif #if defined (TODO) /* RS64 (Apache/A35) */ /* This one seems to support the whole POWER2 instruction set @@ -3734,7 +4177,7 @@ static ppc_def_t ppc_defs[] = { { .name = "RS64", .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3742,7 +4185,7 @@ static ppc_def_t ppc_defs[] = { { .name = "Apache", .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3750,7 +4193,7 @@ static ppc_def_t ppc_defs[] = { { .name = "A35", .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3761,7 +4204,7 @@ static ppc_def_t ppc_defs[] = { { .name = "RS64-II", .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3769,7 +4212,7 @@ static ppc_def_t ppc_defs[] = { { .name = "NortStar", .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3777,7 +4220,7 @@ static ppc_def_t ppc_defs[] = { { .name = "A50", .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3788,7 +4231,7 @@ static ppc_def_t ppc_defs[] = { { .name = "RS64-III", .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3796,7 +4239,7 @@ static ppc_def_t ppc_defs[] = { { .name = "Pulsar", .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3807,7 +4250,7 @@ static ppc_def_t ppc_defs[] = { { .name = "RS64-IV", .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3815,7 +4258,7 @@ static ppc_def_t ppc_defs[] = { { .name = "IceStar", .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3823,7 +4266,7 @@ static ppc_def_t ppc_defs[] = { { .name = "IStar", .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3831,7 +4274,7 @@ static ppc_def_t ppc_defs[] = { { .name = "SStar", .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_RS64, .flags = PPC_FLAGS_RS64, .msr_mask = xxx, @@ -3843,7 +4286,7 @@ static ppc_def_t ppc_defs[] = { { .name = "POWER", .pvr = CPU_POWER, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_POWER, .flags = PPC_FLAGS_POWER, .msr_mask = xxx, @@ -3855,7 +4298,7 @@ static ppc_def_t ppc_defs[] = { { .name = "POWER2", .pvr = CPU_POWER2, - .pvr_mask = 0xFFFF0000, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_POWER, .flags = PPC_FLAGS_POWER, .msr_mask = xxx, @@ -3865,8 +4308,8 @@ static ppc_def_t ppc_defs[] = { #if defined (TODO) { .name = "ppc64", - .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFF0000, + .pvr = CPU_PPC_970FX, + .pvr_mask = 0xFFFFFFFF, .insns_flags = PPC_INSNS_PPC64, .flags = PPC_FLAGS_PPC64, .msr_mask = 0xA00000000204FF36ULL, -- cgit v1.2.3 From 928684128eed56b3c4f4d2300c9cd34d21d02b0c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 21 Sep 2007 06:09:39 +0000 Subject: Avoid compilation warnings on 64 bits hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3202 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 15 ++++++++++----- block-vmdk.c | 3 ++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/block-raw.c b/block-raw.c index 05f830a3f..2f2e19f9b 100644 --- a/block-raw.c +++ b/block-raw.c @@ -151,7 +151,8 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { ++(s->lseek_err_cnt); if(s->lseek_err_cnt <= 10) { - DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] lseek failed : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 + "] lseek failed : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, errno, strerror(errno)); } @@ -163,7 +164,8 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, if (ret == count) goto label__raw_read__success; - DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] read failed %d : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 + "] read failed %d : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, ret, errno, strerror(errno)); @@ -178,7 +180,8 @@ static int raw_pread(BlockDriverState *bs, int64_t offset, if (ret == count) goto label__raw_read__success; - DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %lld, %p, %d) [%lld] retry read failed %d : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 + "] retry read failed %d : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, ret, errno, strerror(errno)); } @@ -201,7 +204,8 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { ++(s->lseek_err_cnt); if(s->lseek_err_cnt) { - DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %lld, %p, %d) [%lld] lseek failed : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" + PRId64 "] lseek failed : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, errno, strerror(errno)); } @@ -213,7 +217,8 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, if (ret == count) goto label__raw_write__success; - DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %lld, %p, %d) [%lld] write failed %d : %d = %s\n", + DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 + "] write failed %d : %d = %s\n", s->fd, bs->filename, offset, buf, count, bs->total_sectors, ret, errno, strerror(errno)); diff --git a/block-vmdk.c b/block-vmdk.c index 02335f7af..ad2270034 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -659,7 +659,8 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, if (sector_num > bs->total_sectors) { fprintf(stderr, - "(VMDK) Wrong offset: sector_num=0x%llx total_sectors=0x%llx\n", + "(VMDK) Wrong offset: sector_num=0x%" PRIx64 + " total_sectors=0x%" PRIx64 "\n", sector_num, bs->total_sectors); return -1; } -- cgit v1.2.3 From 9706285b78800f85b18e17e47000a429e277051c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 21 Sep 2007 06:32:17 +0000 Subject: Avoid compilation warnings on 32 bits hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3203 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index e5d152d7e..061db8760 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -846,10 +846,12 @@ static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, if ((address & mask) != tlb->EPN) return -1; *raddrp = (tlb->RPN & mask) | (address & ~mask); +#if (TARGET_PHYS_ADDR_BITS >= 36) if (ext) { /* Extend the physical address to 36 bits */ *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32; } +#endif return 0; } @@ -1078,11 +1080,11 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, #if defined(TARGET_PPC64) case PPC_FLAGS_MMU_64B: case PPC_FLAGS_MMU_64BRIDGE: -#endif /* Real address are 60 bits long */ ctx->raddr &= 0x0FFFFFFFFFFFFFFFUL; ctx->prot |= PAGE_WRITE; break; +#endif case PPC_FLAGS_MMU_403: if (unlikely(msr_pe != 0)) { /* 403 family add some particular protections, -- cgit v1.2.3 From 43febf49523552ca678eacc2677d3bac58cda4c0 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 21 Sep 2007 19:09:35 +0000 Subject: Improve keyboard handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3204 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 71529b12a..b71bbb344 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -95,6 +95,7 @@ typedef struct ChannelState { uint8_t rx, tx, wregs[16], rregs[16]; SERIOQueue queue; CharDriverState *chr; + int e0_mode, led_mode; } ChannelState; struct SerialState { @@ -194,6 +195,7 @@ static void slavio_serial_reset_chn(ChannelState *s) s->rx = s->tx = 0; s->rxint = s->txint = 0; s->rxint_under_svc = s->txint_under_svc = 0; + s->e0_mode = s->led_mode = 0; clear_queue(s); } @@ -632,30 +634,59 @@ static const uint8_t keycodes[128] = { 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67, }; +static const uint8_t e0_keycodes[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112, + 113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + static void sunkbd_event(void *opaque, int ch) { ChannelState *s = opaque; int release = ch & 0x80; - ch = keycodes[ch & 0x7f]; - KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press"); + KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" : "press"); + if (ch == 0xe0) { + s->e0_mode = 1; + return; + } + if (s->e0_mode) { + s->e0_mode = 0; + ch = e0_keycodes[ch & 0x7f]; + } else { + ch = keycodes[ch & 0x7f]; + } + KBD_DPRINTF("Translated keycode %2.2x\n", ch); put_queue(s, ch | release); } static void handle_kbd_command(ChannelState *s, int val) { KBD_DPRINTF("Command %d\n", val); + if (s->led_mode) { // Ignore led byte + s->led_mode = 0; + return; + } switch (val) { case 1: // Reset, return type code clear_queue(s); put_queue(s, 0xff); put_queue(s, 4); // Type 4 + put_queue(s, 0x7f); break; + case 0xe: // Set leds + s->led_mode = 1; + break; case 7: // Query layout case 0xf: clear_queue(s); put_queue(s, 0xfe); - put_queue(s, 19); // XXX, layout? + put_queue(s, 0); // XXX, layout? break; default: break; -- cgit v1.2.3 From 81ad8ba242815e27f990e18778c7cdca2e7e7522 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 21 Sep 2007 19:10:53 +0000 Subject: Rework ASI instructions (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3205 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 2 +- target-sparc/op.c | 144 ++++++++++++++++- target-sparc/op_helper.c | 403 +++++++++++++++++++++++++++++++++++++++++++---- target-sparc/op_mem.h | 27 ---- target-sparc/translate.c | 355 ++++++++++++++++++++++++----------------- 5 files changed, 727 insertions(+), 204 deletions(-) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 0305a0498..35f4b5fd1 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -50,7 +50,7 @@ void cpu_unlock(void); void cpu_loop_exit(void); void helper_flush(target_ulong addr); void helper_ld_asi(int asi, int size, int sign); -void helper_st_asi(int asi, int size, int sign); +void helper_st_asi(int asi, int size); void helper_rett(void); void helper_ldfsr(void); void set_cwp(int new_cwp); diff --git a/target-sparc/op.c b/target-sparc/op.c index f2168af9a..bb084ee0d 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1862,10 +1862,126 @@ void OPPROTO op_ld_asi_reg() void OPPROTO op_st_asi_reg() { T0 += PARAM1; - helper_st_asi(env->asi, PARAM2, PARAM3); + helper_st_asi(env->asi, PARAM2); +} + +void OPPROTO op_ldstub_asi_reg() /* XXX: should be atomically */ +{ + target_ulong tmp; + + T0 += PARAM1; + helper_ld_asi(env->asi, 1, 0); + tmp = T1; + T1 = 0xff; + helper_st_asi(env->asi, 1); + T1 = tmp; +} + +void OPPROTO op_swap_asi_reg() /* XXX: should be atomically */ +{ + target_ulong tmp1, tmp2; + + T0 += PARAM1; + tmp1 = T1; + helper_ld_asi(env->asi, 4, 0); + tmp2 = T1; + T1 = tmp1; + helper_st_asi(env->asi, 4); + T1 = tmp2; +} + +void OPPROTO op_ldda_asi() +{ + helper_ld_asi(PARAM1, 8, 0); + T0 = T1 & 0xffffffffUL; + T1 >>= 32; +} + +void OPPROTO op_ldda_asi_reg() +{ + T0 += PARAM1; + helper_ld_asi(env->asi, 8, 0); + T0 = T1 & 0xffffffffUL; + T1 >>= 32; +} + +void OPPROTO op_stda_asi() +{ + T1 <<= 32; + T1 += T2 & 0xffffffffUL; + helper_st_asi(PARAM1, 8); +} + +void OPPROTO op_stda_asi_reg() +{ + T0 += PARAM1; + T1 <<= 32; + T1 += T2 & 0xffffffffUL; + helper_st_asi(env->asi, 8); +} + +void OPPROTO op_cas_asi() /* XXX: should be atomically */ +{ + target_ulong tmp; + + tmp = T1 & 0xffffffffUL; + helper_ld_asi(PARAM1, 4, 0); + if (tmp == T1) { + tmp = T1; + T1 = T2 & 0xffffffffUL; + helper_st_asi(PARAM1, 4); + T1 = tmp; + } + T1 &= 0xffffffffUL; +} + +void OPPROTO op_cas_asi_reg() /* XXX: should be atomically */ +{ + target_ulong tmp; + + T0 += PARAM1; + tmp = T1 & 0xffffffffUL; + helper_ld_asi(env->asi, 4, 0); + if (tmp == T1) { + tmp = T1; + T1 = T2 & 0xffffffffUL; + helper_st_asi(env->asi, 4); + T1 = tmp; + } + T1 &= 0xffffffffUL; +} + +void OPPROTO op_casx_asi() /* XXX: should be atomically */ +{ + target_ulong tmp; + + tmp = T1; + helper_ld_asi(PARAM1, 8, 0); + if (tmp == T1) { + tmp = T1; + T1 = T2; + helper_st_asi(PARAM1, 8); + T1 = tmp; + } +} + +void OPPROTO op_casx_asi_reg() /* XXX: should be atomically */ +{ + target_ulong tmp; + + T0 += PARAM1; + tmp = T1; + helper_ld_asi(env->asi, 8, 0); + if (tmp == T1) { + tmp = T1; + T1 = T2; + helper_st_asi(env->asi, 8); + T1 = tmp; + } } #endif +#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) void OPPROTO op_ld_asi() { helper_ld_asi(PARAM1, PARAM2, PARAM3); @@ -1873,9 +1989,33 @@ void OPPROTO op_ld_asi() void OPPROTO op_st_asi() { - helper_st_asi(PARAM1, PARAM2, PARAM3); + helper_st_asi(PARAM1, PARAM2); } +void OPPROTO op_ldstub_asi() /* XXX: should be atomically */ +{ + target_ulong tmp; + + helper_ld_asi(PARAM1, 1, 0); + tmp = T1; + T1 = 0xff; + helper_st_asi(PARAM1, 1); + T1 = tmp; +} + +void OPPROTO op_swap_asi() /* XXX: should be atomically */ +{ + target_ulong tmp1, tmp2; + + tmp1 = T1; + helper_ld_asi(PARAM1, 4, 0); + tmp2 = T1; + T1 = tmp1; + helper_st_asi(PARAM1, 4); + T1 = tmp2; +} +#endif + #ifdef TARGET_SPARC64 // This function uses non-native bit order #define GET_FIELD(X, FROM, TO) \ diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 98c4a1ba4..c168252d1 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -137,16 +137,8 @@ GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); #endif -#if defined(CONFIG_USER_ONLY) -void helper_ld_asi(int asi, int size, int sign) -{ -} - -void helper_st_asi(int asi, int size, int sign) -{ -} -#else #ifndef TARGET_SPARC64 +#ifndef CONFIG_USER_ONLY void helper_ld_asi(int asi, int size, int sign) { uint32_t ret = 0; @@ -200,6 +192,42 @@ void helper_ld_asi(int asi, int size, int sign) break; } break; + case 0xa: /* User data access */ + switch(size) { + case 1: + ret = ldub_user(T0); + break; + case 2: + ret = lduw_user(T0 & ~1); + break; + default: + case 4: + ret = ldl_user(T0 & ~3); + break; + case 8: + ret = ldl_user(T0 & ~3); + T0 = ldl_user((T0 + 4) & ~3); + break; + } + break; + case 0xb: /* Supervisor data access */ + switch(size) { + case 1: + ret = ldub_kernel(T0); + break; + case 2: + ret = lduw_kernel(T0 & ~1); + break; + default: + case 4: + ret = ldl_kernel(T0 & ~3); + break; + case 8: + ret = ldl_kernel(T0 & ~3); + T0 = ldl_kernel((T0 + 4) & ~3); + break; + } + break; case 0xc: /* I-cache tag */ case 0xd: /* I-cache data */ case 0xe: /* D-cache tag */ @@ -253,10 +281,22 @@ void helper_ld_asi(int asi, int size, int sign) ret = 0; break; } - T1 = ret; + if (sign) { + switch(size) { + case 1: + T1 = (int8_t) ret; + case 2: + T1 = (int16_t) ret; + default: + T1 = ret; + break; + } + } + else + T1 = ret; } -void helper_st_asi(int asi, int size, int sign) +void helper_st_asi(int asi, int size) { switch(asi) { case 2: /* SuperSparc MXCC registers */ @@ -325,6 +365,42 @@ void helper_st_asi(int asi, int size, int sign) #endif return; } + case 0xa: /* User data access */ + switch(size) { + case 1: + stb_user(T0, T1); + break; + case 2: + stw_user(T0 & ~1, T1); + break; + default: + case 4: + stl_user(T0 & ~3, T1); + break; + case 8: + stl_user(T0 & ~3, T1); + stl_user((T0 + 4) & ~3, T2); + break; + } + break; + case 0xb: /* Supervisor data access */ + switch(size) { + case 1: + stb_kernel(T0, T1); + break; + case 2: + stw_kernel(T0 & ~1, T1); + break; + default: + case 4: + stl_kernel(T0 & ~3, T1); + break; + case 8: + stl_kernel(T0 & ~3, T1); + stl_kernel((T0 + 4) & ~3, T2); + break; + } + break; case 0xc: /* I-cache tag */ case 0xd: /* I-cache data */ case 0xe: /* D-cache tag */ @@ -422,7 +498,146 @@ void helper_st_asi(int asi, int size, int sign) } } -#else +#endif /* CONFIG_USER_ONLY */ +#else /* TARGET_SPARC64 */ + +#ifdef CONFIG_USER_ONLY +void helper_ld_asi(int asi, int size, int sign) +{ + uint64_t ret = 0; + + if (asi < 0x80) + raise_exception(TT_PRIV_ACT); + + switch (asi) { + case 0x80: // Primary + case 0x82: // Primary no-fault + case 0x88: // Primary LE + case 0x8a: // Primary no-fault LE + { + switch(size) { + case 1: + ret = ldub_raw(T0); + break; + case 2: + ret = lduw_raw(T0 & ~1); + break; + case 4: + ret = ldl_raw(T0 & ~3); + break; + default: + case 8: + ret = ldq_raw(T0 & ~7); + break; + } + } + break; + case 0x81: // Secondary + case 0x83: // Secondary no-fault + case 0x89: // Secondary LE + case 0x8b: // Secondary no-fault LE + // XXX + break; + default: + break; + } + + /* Convert from little endian */ + switch (asi) { + case 0x88: // Primary LE + case 0x89: // Secondary LE + case 0x8a: // Primary no-fault LE + case 0x8b: // Secondary no-fault LE + switch(size) { + case 2: + ret = bswap16(ret); + case 4: + ret = bswap32(ret); + case 8: + ret = bswap64(ret); + default: + break; + } + default: + break; + } + + /* Convert to signed number */ + if (sign) { + switch(size) { + case 1: + ret = (int8_t) ret; + case 2: + ret = (int16_t) ret; + case 4: + ret = (int32_t) ret; + default: + break; + } + } + T1 = ret; +} + +void helper_st_asi(int asi, int size) +{ + if (asi < 0x80) + raise_exception(TT_PRIV_ACT); + + /* Convert to little endian */ + switch (asi) { + case 0x88: // Primary LE + case 0x89: // Secondary LE + switch(size) { + case 2: + T0 = bswap16(T0); + case 4: + T0 = bswap32(T0); + case 8: + T0 = bswap64(T0); + default: + break; + } + default: + break; + } + + switch(asi) { + case 0x80: // Primary + case 0x88: // Primary LE + { + switch(size) { + case 1: + stb_raw(T0, T1); + break; + case 2: + stw_raw(T0 & ~1, T1); + break; + case 4: + stl_raw(T0 & ~3, T1); + break; + case 8: + default: + stq_raw(T0 & ~7, T1); + break; + } + } + break; + case 0x81: // Secondary + case 0x89: // Secondary LE + // XXX + return; + + case 0x82: // Primary no-fault, RO + case 0x83: // Secondary no-fault, RO + case 0x8a: // Primary no-fault LE, RO + case 0x8b: // Secondary no-fault LE, RO + default: + do_unassigned_access(T0, 1, 0, 1); + return; + } +} + +#else /* CONFIG_USER_ONLY */ void helper_ld_asi(int asi, int size, int sign) { @@ -432,8 +647,50 @@ void helper_ld_asi(int asi, int size, int sign) raise_exception(TT_PRIV_ACT); switch (asi) { + case 0x10: // As if user primary + case 0x18: // As if user primary LE + case 0x80: // Primary + case 0x82: // Primary no-fault + case 0x88: // Primary LE + case 0x8a: // Primary no-fault LE + if ((asi & 0x80) && (env->pstate & PS_PRIV)) { + switch(size) { + case 1: + ret = ldub_kernel(T0); + break; + case 2: + ret = lduw_kernel(T0 & ~1); + break; + case 4: + ret = ldl_kernel(T0 & ~3); + break; + default: + case 8: + ret = ldq_kernel(T0 & ~7); + break; + } + } else { + switch(size) { + case 1: + ret = ldub_user(T0); + break; + case 2: + ret = lduw_user(T0 & ~1); + break; + case 4: + ret = ldl_user(T0 & ~3); + break; + default: + case 8: + ret = ldq_user(T0 & ~7); + break; + } + } + break; case 0x14: // Bypass case 0x15: // Bypass, non-cacheable + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE { switch(size) { case 1: @@ -454,20 +711,14 @@ void helper_ld_asi(int asi, int size, int sign) } case 0x04: // Nucleus case 0x0c: // Nucleus Little Endian (LE) - case 0x10: // As if user primary case 0x11: // As if user secondary - case 0x18: // As if user primary LE case 0x19: // As if user secondary LE - case 0x1c: // Bypass LE - case 0x1d: // Bypass, non-cacheable LE case 0x24: // Nucleus quad LDD 128 bit atomic case 0x2c: // Nucleus quad LDD 128 bit atomic case 0x4a: // UPA config - case 0x82: // Primary no-fault + case 0x81: // Secondary case 0x83: // Secondary no-fault - case 0x88: // Primary LE case 0x89: // Secondary LE - case 0x8a: // Primary no-fault LE case 0x8b: // Secondary no-fault LE // XXX break; @@ -540,17 +791,120 @@ void helper_ld_asi(int asi, int size, int sign) ret = 0; break; } + + /* Convert from little endian */ + switch (asi) { + case 0x0c: // Nucleus Little Endian (LE) + case 0x18: // As if user primary LE + case 0x19: // As if user secondary LE + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE + case 0x88: // Primary LE + case 0x89: // Secondary LE + case 0x8a: // Primary no-fault LE + case 0x8b: // Secondary no-fault LE + switch(size) { + case 2: + ret = bswap16(ret); + case 4: + ret = bswap32(ret); + case 8: + ret = bswap64(ret); + default: + break; + } + default: + break; + } + + /* Convert to signed number */ + if (sign) { + switch(size) { + case 1: + ret = (int8_t) ret; + case 2: + ret = (int16_t) ret; + case 4: + ret = (int32_t) ret; + default: + break; + } + } T1 = ret; } -void helper_st_asi(int asi, int size, int sign) +void helper_st_asi(int asi, int size) { if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) raise_exception(TT_PRIV_ACT); + /* Convert to little endian */ + switch (asi) { + case 0x0c: // Nucleus Little Endian (LE) + case 0x18: // As if user primary LE + case 0x19: // As if user secondary LE + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE + case 0x81: // Secondary + case 0x88: // Primary LE + case 0x89: // Secondary LE + switch(size) { + case 2: + T0 = bswap16(T0); + case 4: + T0 = bswap32(T0); + case 8: + T0 = bswap64(T0); + default: + break; + } + default: + break; + } + switch(asi) { + case 0x10: // As if user primary + case 0x18: // As if user primary LE + case 0x80: // Primary + case 0x88: // Primary LE + if ((asi & 0x80) && (env->pstate & PS_PRIV)) { + switch(size) { + case 1: + stb_kernel(T0, T1); + break; + case 2: + stw_kernel(T0 & ~1, T1); + break; + case 4: + stl_kernel(T0 & ~3, T1); + break; + case 8: + default: + stq_kernel(T0 & ~7, T1); + break; + } + } else { + switch(size) { + case 1: + stb_user(T0, T1); + break; + case 2: + stw_user(T0 & ~1, T1); + break; + case 4: + stl_user(T0 & ~3, T1); + break; + case 8: + default: + stq_user(T0 & ~7, T1); + break; + } + } + break; case 0x14: // Bypass case 0x15: // Bypass, non-cacheable + case 0x1c: // Bypass LE + case 0x1d: // Bypass, non-cacheable LE { switch(size) { case 1: @@ -571,16 +925,11 @@ void helper_st_asi(int asi, int size, int sign) return; case 0x04: // Nucleus case 0x0c: // Nucleus Little Endian (LE) - case 0x10: // As if user primary case 0x11: // As if user secondary - case 0x18: // As if user primary LE case 0x19: // As if user secondary LE - case 0x1c: // Bypass LE - case 0x1d: // Bypass, non-cacheable LE case 0x24: // Nucleus quad LDD 128 bit atomic case 0x2c: // Nucleus quad LDD 128 bit atomic case 0x4a: // UPA config - case 0x88: // Primary LE case 0x89: // Secondary LE // XXX return; @@ -756,8 +1105,8 @@ void helper_st_asi(int asi, int size, int sign) return; } } -#endif -#endif /* !CONFIG_USER_ONLY */ +#endif /* CONFIG_USER_ONLY */ +#endif /* TARGET_SPARC64 */ #ifndef TARGET_SPARC64 void helper_rett() diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index ae63181c7..c0cf043b3 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -76,33 +76,6 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (void) } #ifdef TARGET_SPARC64 -/* XXX: Should be Atomically */ -/* XXX: There are no cas[x] instructions, only cas[x]a */ -void OPPROTO glue(op_cas, MEMSUFFIX)(void) -{ - uint32_t tmp; - - tmp = glue(ldl, MEMSUFFIX)(T0); - T2 &= 0xffffffffULL; - if (tmp == (T1 & 0xffffffffULL)) { - glue(stl, MEMSUFFIX)(T0, T2); - } - T2 = tmp; -} - -void OPPROTO glue(op_casx, MEMSUFFIX)(void) -{ - uint64_t tmp; - - // XXX - tmp = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32; - tmp |= glue(ldl, MEMSUFFIX)(T0); - if (tmp == T1) { - glue(stq, MEMSUFFIX)(T0, T2); - } - T2 = tmp; -} - void OPPROTO glue(op_lduw, MEMSUFFIX)(void) { T1 = (uint64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index a52d6717a..d617b91e9 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -353,112 +353,27 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); #endif #endif -#ifdef TARGET_SPARC64 -// 'a' versions allowed to user depending on asi -#if defined(CONFIG_USER_ONLY) +/* moves */ +#ifdef CONFIG_USER_ONLY #define supervisor(dc) 0 +#ifdef TARGET_SPARC64 #define hypervisor(dc) 0 +#endif #define gen_op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) \ - static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ - { \ - int asi, offset; \ - \ - if (IS_IMM) { \ - offset = GET_FIELD(insn, 25, 31); \ - if (is_ld) \ - gen_op_ld_asi_reg(offset, size, sign); \ - else \ - gen_op_st_asi_reg(offset, size, sign); \ - return; \ - } \ - asi = GET_FIELD(insn, 19, 26); \ - switch (asi) { \ - case 0x80: /* Primary address space */ \ - gen_op_##width##_raw(); \ - break; \ - case 0x82: /* Primary address space, non-faulting load */ \ - gen_op_##width##_raw(); \ - break; \ - default: \ - break; \ - } \ - } - #else +#define supervisor(dc) (dc->mem_idx == 1) +#ifdef TARGET_SPARC64 +#define hypervisor(dc) (dc->mem_idx == 2) +#endif #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() #define OP_LD_TABLE(width) \ static GenOpFunc * const gen_op_##width[] = { \ &gen_op_##width##_user, \ &gen_op_##width##_kernel, \ - }; \ - \ - static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ - { \ - int asi, offset; \ - \ - if (IS_IMM) { \ - offset = GET_FIELD(insn, 25, 31); \ - if (is_ld) \ - gen_op_ld_asi_reg(offset, size, sign); \ - else \ - gen_op_st_asi_reg(offset, size, sign); \ - return; \ - } \ - asi = GET_FIELD(insn, 19, 26); \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ - } - -#define supervisor(dc) (dc->mem_idx == 1) -#define hypervisor(dc) (dc->mem_idx == 2) -#endif -#else -#if defined(CONFIG_USER_ONLY) -#define gen_op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) -#define supervisor(dc) 0 -#else -#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() -#define OP_LD_TABLE(width) \ -static GenOpFunc * const gen_op_##width[] = { \ - &gen_op_##width##_user, \ - &gen_op_##width##_kernel, \ -}; \ - \ -static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ -{ \ - int asi; \ - \ - asi = GET_FIELD(insn, 19, 26); \ - switch (asi) { \ - case 10: /* User data access */ \ - gen_op_##width##_user(); \ - break; \ - case 11: /* Supervisor data access */ \ - gen_op_##width##_kernel(); \ - break; \ - case 0x20 ... 0x2f: /* MMU passthrough */ \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ - break; \ - default: \ - if (is_ld) \ - gen_op_ld_asi(asi, size, sign); \ - else \ - gen_op_st_asi(asi, size, sign); \ - break; \ - } \ -} - -#define supervisor(dc) (dc->mem_idx == 1) -#endif + }; #endif +#ifndef CONFIG_USER_ONLY OP_LD_TABLE(ld); OP_LD_TABLE(st); OP_LD_TABLE(ldub); @@ -481,8 +396,164 @@ OP_LD_TABLE(lduw); OP_LD_TABLE(ldsw); OP_LD_TABLE(ldx); OP_LD_TABLE(stx); -OP_LD_TABLE(cas); -OP_LD_TABLE(casx); +#endif +#endif + +/* asi moves */ +#ifdef TARGET_SPARC64 +static inline void gen_ld_asi(int insn, int size, int sign) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_ld_asi_reg(offset, size, sign); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_ld_asi(asi, size, sign); + } +} + +static inline void gen_st_asi(int insn, int size) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_st_asi_reg(offset, size); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_st_asi(asi, size); + } +} + +static inline void gen_swap_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_swap_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_swap_asi(asi); + } +} + +static inline void gen_ldstub_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_ldstub_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_ldstub_asi(asi); + } +} + +static inline void gen_ldda_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_ldda_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_ldda_asi(asi); + } +} + +static inline void gen_stda_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_stda_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_stda_asi(asi); + } +} + +static inline void gen_cas_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_cas_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_cas_asi(asi); + } +} + +static inline void gen_casx_asi(int insn) +{ + int asi, offset; + + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_casx_asi_reg(offset); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_casx_asi(asi); + } +} + +#elif !defined(CONFIG_USER_ONLY) + +static inline void gen_ld_asi(int insn, int size, int sign) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_ld_asi(asi, size, sign); +} + +static inline void gen_st_asi(int insn, int size) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_st_asi(asi, size); +} + +static inline void gen_ldstub_asi(int insn) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_ldstub_asi(asi); +} + +static inline void gen_swap_asi(int insn) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_swap_asi(asi); +} + +static inline void gen_ldda_asi(int insn) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_ld_asi(asi, 8, 0); +} + +static inline void gen_stda_asi(int insn) +{ + int asi; + + asi = GET_FIELD(insn, 19, 26); + gen_op_st_asi(asi, 8); +} #endif static inline void gen_movl_imm_TN(int reg, uint32_t imm) @@ -2796,7 +2867,12 @@ static void disas_sparc_insn(DisasContext * dc) rs1 = GET_FIELD(insn, 13, 17); save_state(dc); gen_movl_reg_T0(rs1); - if (IS_IMM) { /* immediate */ + if (xop == 0x3c || xop == 0x3e) + { + rs2 = GET_FIELD(insn, 27, 31); + gen_movl_reg_T1(rs2); + } + else if (IS_IMM) { /* immediate */ rs2 = GET_FIELDs(insn, 19, 31); #if defined(OPTIM) if (rs2 != 0) { @@ -2873,16 +2949,10 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#ifdef CONFIG_USER_ONLY +#elif CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_lda(insn, 1, 4, 0); -#else -#ifdef CONFIG_USER_ONLY - gen_op_check_align_T0_3(); -#endif - gen_op_lduwa(insn, 1, 4, 0); -#endif + gen_ld_asi(insn, 4, 0); break; case 0x11: /* load unsigned byte alternate */ #ifndef TARGET_SPARC64 @@ -2891,7 +2961,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif - gen_op_lduba(insn, 1, 1, 0); + gen_ld_asi(insn, 1, 0); break; case 0x12: /* load unsigned halfword alternate */ #ifndef TARGET_SPARC64 @@ -2899,11 +2969,10 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#endif -#ifdef CONFIG_USER_ONLY +#elif CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_lduha(insn, 1, 2, 0); + gen_ld_asi(insn, 2, 0); break; case 0x13: /* load double word alternate */ #ifndef TARGET_SPARC64 @@ -2915,7 +2984,7 @@ static void disas_sparc_insn(DisasContext * dc) if (rd & 1) goto illegal_insn; gen_op_check_align_T0_7(); - gen_op_ldda(insn, 1, 8, 0); + gen_ldda_asi(insn); gen_movl_T0_reg(rd + 1); break; case 0x19: /* load signed byte alternate */ @@ -2925,7 +2994,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif - gen_op_ldsba(insn, 1, 1, 1); + gen_ld_asi(insn, 1, 1); break; case 0x1a: /* load signed halfword alternate */ #ifndef TARGET_SPARC64 @@ -2933,11 +3002,10 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#endif -#ifdef CONFIG_USER_ONLY +#elif CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_ldsha(insn, 1, 2 ,1); + gen_ld_asi(insn, 2, 1); break; case 0x1d: /* ldstuba -- XXX: should be atomically */ #ifndef TARGET_SPARC64 @@ -2946,7 +3014,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif - gen_op_ldstuba(insn, 1, 1, 0); + gen_ldstub_asi(insn); break; case 0x1f: /* swap reg with alt. memory. Also atomically */ #ifndef TARGET_SPARC64 @@ -2954,12 +3022,11 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#endif - gen_movl_reg_T1(rd); -#ifdef CONFIG_USER_ONLY +#elif CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_swapa(insn, 1, 4, 0); + gen_movl_reg_T1(rd); + gen_swap_asi(insn); break; #ifndef TARGET_SPARC64 @@ -2967,17 +3034,6 @@ static void disas_sparc_insn(DisasContext * dc) case 0x31: /* ldcsr */ case 0x33: /* lddc */ goto ncp_insn; - /* avoid warnings */ - (void) &gen_op_stfa; - (void) &gen_op_stdfa; - (void) &gen_op_ldfa; - (void) &gen_op_lddfa; -#else - (void) &gen_op_lda; -#if !defined(CONFIG_USER_ONLY) - (void) &gen_op_cas; - (void) &gen_op_casx; -#endif #endif #endif #ifdef TARGET_SPARC64 @@ -2995,11 +3051,11 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldswa(insn, 1, 4, 1); + gen_ld_asi(insn, 4, 1); break; case 0x1b: /* V9 ldxa */ gen_op_check_align_T0_7(); - gen_op_ldxa(insn, 1, 8, 0); + gen_ld_asi(insn, 8, 0); break; case 0x2d: /* V9 prefetch, no effect */ goto skip_move; @@ -3007,13 +3063,12 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_ldfa(insn, 1, 8, 0); // XXX - break; + gen_ld_asi(insn, 8, 0); // XXX + goto skip_move; case 0x33: /* V9 lddfa */ gen_op_check_align_T0_7(); - gen_op_lddfa(insn, 1, 8, 0); // XXX - - break; + gen_ld_asi(insn, 8, 0); // XXX + goto skip_move; case 0x3d: /* V9 prefetcha, no effect */ goto skip_move; case 0x32: /* V9 ldqfa */ @@ -3092,7 +3147,7 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_sta(insn, 0, 4, 0); + gen_st_asi(insn, 4); break; case 0x15: #ifndef TARGET_SPARC64 @@ -3101,7 +3156,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif - gen_op_stba(insn, 0, 1, 0); + gen_st_asi(insn, 1); break; case 0x16: #ifndef TARGET_SPARC64 @@ -3113,7 +3168,7 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); #endif - gen_op_stha(insn, 0, 2, 0); + gen_st_asi(insn, 2); break; case 0x17: #ifndef TARGET_SPARC64 @@ -3127,7 +3182,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_check_align_T0_7(); flush_T2(dc); gen_movl_reg_T2(rd + 1); - gen_op_stda(insn, 0, 8, 0); + gen_stda_asi(insn); break; #endif #ifdef TARGET_SPARC64 @@ -3137,7 +3192,7 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x1e: /* V9 stxa */ gen_op_check_align_T0_7(); - gen_op_stxa(insn, 0, 8, 0); // XXX + gen_st_asi(insn, 8); break; #endif default: @@ -3184,21 +3239,27 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_stfa(insn, 0, 0, 0); // XXX + gen_st_asi(insn, 0); // XXX break; case 0x37: /* V9 stdfa */ gen_op_check_align_T0_7(); - gen_op_stdfa(insn, 0, 0, 0); // XXX + gen_st_asi(insn, 0); // XXX break; case 0x3c: /* V9 casa */ #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_op_casa(insn, 0, 4, 0); // XXX + flush_T2(dc); + gen_movl_reg_T2(rd); + gen_cas_asi(insn); + gen_movl_T1_reg(rd); break; case 0x3e: /* V9 casxa */ gen_op_check_align_T0_7(); - gen_op_casxa(insn, 0, 8, 0); // XXX + flush_T2(dc); + gen_movl_reg_T2(rd); + gen_casx_asi(insn); + gen_movl_T1_reg(rd); break; case 0x36: /* V9 stqfa */ goto nfpu_insn; -- cgit v1.2.3 From 748e49932dfa9f293f60995ca67dd387e942ce05 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 22 Sep 2007 12:09:09 +0000 Subject: Fix breakage on big endian hosts (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3206 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/iommu.c b/hw/iommu.c index c9b9db57d..0ee8c718e 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -212,7 +212,7 @@ static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) addr &= ~s->iostart; iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4); - bswap32s(&ret); + tswap32s(&ret); DPRINTF("get flags addr " TARGET_FMT_plx " => pte " TARGET_FMT_plx ", *pte = %x\n", pa, iopte, ret); -- cgit v1.2.3 From c39e33380f5c3486eed06bb6a7fbc6221365555c Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 22 Sep 2007 16:49:14 +0000 Subject: Only build qemu-img with softmmu targets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3207 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 - configure | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a52671588..c7af33413 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,6 @@ BASE_LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS) CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS= -TOOLS=qemu-img$(EXESUF) ifdef CONFIG_STATIC BASE_LDFLAGS += -static endif diff --git a/configure b/configure index 7b8ac31dc..6288ac06c 100755 --- a/configure +++ b/configure @@ -910,6 +910,12 @@ fi echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h +tools= +if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then + tools="qemu-img\$(EXESUF) $tools" +fi +echo "TOOLS=$tools" >> $config_mak + test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h for target in $target_list; do -- cgit v1.2.3 From e32664fbd296e962ebb9a731c02e44bc5d1ce3ae Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 23 Sep 2007 11:40:57 +0000 Subject: Add missing break statements git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3208 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index c168252d1..21ae5dec2 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -285,8 +285,10 @@ void helper_ld_asi(int asi, int size, int sign) switch(size) { case 1: T1 = (int8_t) ret; + break; case 2: T1 = (int16_t) ret; + break; default: T1 = ret; break; @@ -551,10 +553,13 @@ void helper_ld_asi(int asi, int size, int sign) switch(size) { case 2: ret = bswap16(ret); + break; case 4: ret = bswap32(ret); + break; case 8: ret = bswap64(ret); + break; default: break; } @@ -567,10 +572,13 @@ void helper_ld_asi(int asi, int size, int sign) switch(size) { case 1: ret = (int8_t) ret; + break; case 2: ret = (int16_t) ret; + break; case 4: ret = (int32_t) ret; + break; default: break; } @@ -590,10 +598,13 @@ void helper_st_asi(int asi, int size) switch(size) { case 2: T0 = bswap16(T0); + break; case 4: T0 = bswap32(T0); + break; case 8: T0 = bswap64(T0); + break; default: break; } @@ -806,10 +817,13 @@ void helper_ld_asi(int asi, int size, int sign) switch(size) { case 2: ret = bswap16(ret); + break; case 4: ret = bswap32(ret); + break; case 8: ret = bswap64(ret); + break; default: break; } @@ -822,10 +836,13 @@ void helper_ld_asi(int asi, int size, int sign) switch(size) { case 1: ret = (int8_t) ret; + break; case 2: ret = (int16_t) ret; + break; case 4: ret = (int32_t) ret; + break; default: break; } @@ -851,10 +868,13 @@ void helper_st_asi(int asi, int size) switch(size) { case 2: T0 = bswap16(T0); + break; case 4: T0 = bswap32(T0); + break; case 8: T0 = bswap64(T0); + break; default: break; } -- cgit v1.2.3 From bbbb2f0af96dbf6706c90209ebb16dc5b87d32e1 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 23 Sep 2007 11:48:47 +0000 Subject: Fix Caps lock and Num lock handling git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3209 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index b71bbb344..1aa5e7a17 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -95,7 +95,7 @@ typedef struct ChannelState { uint8_t rx, tx, wregs[16], rregs[16]; SERIOQueue queue; CharDriverState *chr; - int e0_mode, led_mode; + int e0_mode, led_mode, caps_lock_mode, num_lock_mode; } ChannelState; struct SerialState { @@ -195,7 +195,7 @@ static void slavio_serial_reset_chn(ChannelState *s) s->rx = s->tx = 0; s->rxint = s->txint = 0; s->rxint_under_svc = s->txint_under_svc = 0; - s->e0_mode = s->led_mode = 0; + s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0; clear_queue(s); } @@ -651,9 +651,32 @@ static void sunkbd_event(void *opaque, int ch) int release = ch & 0x80; KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" : "press"); - if (ch == 0xe0) { + switch (ch) { + case 58: // Caps lock press + s->caps_lock_mode ^= 1; + if (s->caps_lock_mode == 2) + return; // Drop second press + break; + case 69: // Num lock press + s->num_lock_mode ^= 1; + if (s->num_lock_mode == 2) + return; // Drop second press + break; + case 186: // Caps lock release + s->caps_lock_mode ^= 2; + if (s->caps_lock_mode == 3) + return; // Drop first release + break; + case 197: // Num lock release + s->num_lock_mode ^= 2; + if (s->num_lock_mode == 3) + return; // Drop first release + break; + case 0xe0: s->e0_mode = 1; return; + default: + break; } if (s->e0_mode) { s->e0_mode = 0; -- cgit v1.2.3 From 0573fbfc3f1c616071c59caef22975d1280b1c5d Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 23 Sep 2007 15:28:04 +0000 Subject: SVM Support, by Alexander Graf. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3210 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + cpu-exec.c | 29 ++- exec.c | 5 + target-i386/cpu.h | 22 ++ target-i386/exec.h | 10 + target-i386/helper.c | 523 +++++++++++++++++++++++++++++++++++++++++++++++- target-i386/helper2.c | 15 +- target-i386/op.c | 88 +++++++- target-i386/translate.c | 243 +++++++++++++++++++++- 9 files changed, 921 insertions(+), 15 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 5c3003088..4e200928f 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -716,6 +716,7 @@ extern int code_copy_enabled; #define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */ #define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ +#define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */ void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); diff --git a/cpu-exec.c b/cpu-exec.c index 339505966..58737b3a4 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -163,6 +163,7 @@ static inline TranslationBlock *tb_find_fast(void) #if defined(TARGET_I386) flags = env->hflags; flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); + flags |= env->intercept; cs_base = env->segs[R_CS].base; pc = cs_base + env->eip; #elif defined(TARGET_ARM) @@ -372,7 +373,11 @@ int cpu_exec(CPUState *env1) tmp_T0 = T0; #endif interrupt_request = env->interrupt_request; - if (__builtin_expect(interrupt_request, 0)) { + if (__builtin_expect(interrupt_request, 0) +#if defined(TARGET_I386) + && env->hflags & HF_GIF_MASK +#endif + ) { if (interrupt_request & CPU_INTERRUPT_DEBUG) { env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; env->exception_index = EXCP_DEBUG; @@ -390,6 +395,7 @@ int cpu_exec(CPUState *env1) #if defined(TARGET_I386) if ((interrupt_request & CPU_INTERRUPT_SMI) && !(env->hflags & HF_SMM_MASK)) { + svm_check_intercept(SVM_EXIT_SMI); env->interrupt_request &= ~CPU_INTERRUPT_SMI; do_smm_enter(); #if defined(__sparc__) && !defined(HOST_SOLARIS) @@ -398,9 +404,10 @@ int cpu_exec(CPUState *env1) T0 = 0; #endif } else if ((interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK) && + (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; + svm_check_intercept(SVM_EXIT_INTR); env->interrupt_request &= ~CPU_INTERRUPT_HARD; intno = cpu_get_pic_interrupt(env); if (loglevel & CPU_LOG_TB_IN_ASM) { @@ -413,6 +420,24 @@ int cpu_exec(CPUState *env1) tmp_T0 = 0; #else T0 = 0; +#endif +#if !defined(CONFIG_USER_ONLY) + } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && + (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { + int intno; + /* FIXME: this should respect TPR */ + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), + ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); + intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno); + do_interrupt(intno, 0, 0, -1, 1); +#if defined(__sparc__) && !defined(HOST_SOLARIS) + tmp_T0 = 0; +#else + T0 = 0; +#endif #endif } #elif defined(TARGET_PPC) diff --git a/exec.c b/exec.c index 5c716b320..7d8ae3fd9 100644 --- a/exec.c +++ b/exec.c @@ -1292,6 +1292,11 @@ void cpu_abort(CPUState *env, const char *fmt, ...) vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); #ifdef TARGET_I386 + if(env->intercept & INTERCEPT_SVM_MASK) { + /* most probably the virtual machine should not + be shut down but rather caught by the VMM */ + vmexit(SVM_EXIT_SHUTDOWN, 0); + } cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); #else cpu_dump_state(env, stderr, fprintf, 0); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9ae50ee6d..2cc7d64e9 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -84,6 +84,7 @@ #define DESC_AVL_MASK (1 << 20) #define DESC_P_MASK (1 << 15) #define DESC_DPL_SHIFT 13 +#define DESC_DPL_MASK (1 << DESC_DPL_SHIFT) #define DESC_S_MASK (1 << 12) #define DESC_TYPE_SHIFT 8 #define DESC_A_MASK (1 << 8) @@ -149,6 +150,8 @@ #define HF_VM_SHIFT 17 /* must be same as eflags */ #define HF_HALTED_SHIFT 18 /* CPU halted */ #define HF_SMM_SHIFT 19 /* CPU in SMM mode */ +#define HF_GIF_SHIFT 20 /* if set CPU takes interrupts */ +#define HF_HIF_SHIFT 21 /* shadow copy of IF_MASK when in SVM */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) @@ -166,6 +169,8 @@ #define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT) #define HF_HALTED_MASK (1 << HF_HALTED_SHIFT) #define HF_SMM_MASK (1 << HF_SMM_SHIFT) +#define HF_GIF_MASK (1 << HF_GIF_SHIFT) +#define HF_HIF_MASK (1 << HF_HIF_SHIFT) #define CR0_PE_MASK (1 << 0) #define CR0_MP_MASK (1 << 1) @@ -249,6 +254,8 @@ #define MSR_GSBASE 0xc0000101 #define MSR_KERNELGSBASE 0xc0000102 +#define MSR_VM_HSAVE_PA 0xc0010117 + /* cpuid_features bits */ #define CPUID_FP87 (1 << 0) #define CPUID_VME (1 << 1) @@ -283,6 +290,8 @@ #define CPUID_EXT2_FFXSR (1 << 25) #define CPUID_EXT2_LM (1 << 29) +#define CPUID_EXT3_SVM (1 << 2) + #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 #define EXCP02_NMI 2 @@ -489,6 +498,16 @@ typedef struct CPUX86State { uint32_t sysenter_eip; uint64_t efer; uint64_t star; + + target_phys_addr_t vm_hsave; + target_phys_addr_t vm_vmcb; + uint64_t intercept; + uint16_t intercept_cr_read; + uint16_t intercept_cr_write; + uint16_t intercept_dr_read; + uint16_t intercept_dr_write; + uint32_t intercept_exceptions; + #ifdef TARGET_X86_64 target_ulong lstar; target_ulong cstar; @@ -530,6 +549,7 @@ typedef struct CPUX86State { uint32_t cpuid_xlevel; uint32_t cpuid_model[12]; uint32_t cpuid_ext2_features; + uint32_t cpuid_ext3_features; uint32_t cpuid_apic_id; #ifdef USE_KQEMU @@ -670,4 +690,6 @@ static inline int cpu_get_time_fast(void) #include "cpu-all.h" +#include "svm.h" + #endif /* CPU_I386_H */ diff --git a/target-i386/exec.h b/target-i386/exec.h index 59c064923..1cb73467b 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -502,6 +502,15 @@ void update_fp_status(void); void helper_hlt(void); void helper_monitor(void); void helper_mwait(void); +void helper_vmrun(target_ulong addr); +void helper_vmmcall(void); +void helper_vmload(target_ulong addr); +void helper_vmsave(target_ulong addr); +void helper_stgi(void); +void helper_clgi(void); +void helper_skinit(void); +void helper_invlpga(void); +void vmexit(uint64_t exit_code, uint64_t exit_info_1); extern const uint8_t parity_table[256]; extern const uint8_t rclw_table[32]; @@ -589,3 +598,4 @@ static inline int cpu_halted(CPUState *env) { } return EXCP_HALTED; } + diff --git a/target-i386/helper.c b/target-i386/helper.c index 43a8b9b57..40dc41f3a 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -594,7 +594,18 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, int has_error_code, new_stack, shift; uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; uint32_t old_eip, sp_mask; + int svm_should_check = 1; + if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { + next_eip = EIP; + svm_should_check = 0; + } + + if (svm_should_check + && (INTERCEPTEDl(_exceptions, 1 << intno) + && !is_int)) { + raise_interrupt(intno, is_int, error_code, 0); + } has_error_code = 0; if (!is_int && !is_hw) { switch(intno) { @@ -830,7 +841,17 @@ static void do_interrupt64(int intno, int is_int, int error_code, int has_error_code, new_stack; uint32_t e1, e2, e3, ss; target_ulong old_eip, esp, offset; + int svm_should_check = 1; + if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { + next_eip = EIP; + svm_should_check = 0; + } + if (svm_should_check + && INTERCEPTEDl(_exceptions, 1 << intno) + && !is_int) { + raise_interrupt(intno, is_int, error_code, 0); + } has_error_code = 0; if (!is_int && !is_hw) { switch(intno) { @@ -1077,7 +1098,17 @@ static void do_interrupt_real(int intno, int is_int, int error_code, int selector; uint32_t offset, esp; uint32_t old_cs, old_eip; + int svm_should_check = 1; + if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) { + next_eip = EIP; + svm_should_check = 0; + } + if (svm_should_check + && INTERCEPTEDl(_exceptions, 1 << intno) + && !is_int) { + raise_interrupt(intno, is_int, error_code, 0); + } /* real mode (simpler !) */ dt = &env->idt; if (intno * 4 + 3 > dt->limit) @@ -1227,8 +1258,10 @@ int check_exception(int intno, int *error_code) void raise_interrupt(int intno, int is_int, int error_code, int next_eip_addend) { - if (!is_int) + if (!is_int) { + svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); intno = check_exception(intno, &error_code); + } env->exception_index = intno; env->error_code = error_code; @@ -1671,7 +1704,7 @@ void helper_cpuid(void) case 0x80000001: EAX = env->cpuid_features; EBX = 0; - ECX = 0; + ECX = env->cpuid_ext3_features; EDX = env->cpuid_ext2_features; break; case 0x80000002: @@ -2745,6 +2778,9 @@ void helper_wrmsr(void) case MSR_PAT: env->pat = val; break; + case MSR_VM_HSAVE_PA: + env->vm_hsave = val; + break; #ifdef TARGET_X86_64 case MSR_LSTAR: env->lstar = val; @@ -2796,6 +2832,9 @@ void helper_rdmsr(void) case MSR_PAT: val = env->pat; break; + case MSR_VM_HSAVE_PA: + val = env->vm_hsave; + break; #ifdef TARGET_X86_64 case MSR_LSTAR: val = env->lstar; @@ -3877,3 +3916,483 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) } env = saved_env; } + + +/* Secure Virtual Machine helpers */ + +void helper_stgi(void) +{ + env->hflags |= HF_GIF_MASK; +} + +void helper_clgi(void) +{ + env->hflags &= ~HF_GIF_MASK; +} + +#if defined(CONFIG_USER_ONLY) + +void helper_vmrun(target_ulong addr) { } +void helper_vmmcall(void) { } +void helper_vmload(target_ulong addr) { } +void helper_vmsave(target_ulong addr) { } +void helper_skinit(void) { } +void helper_invlpga(void) { } +void vmexit(uint64_t exit_code, uint64_t exit_info_1) { } +int svm_check_intercept_param(uint32_t type, uint64_t param) +{ + return 0; +} + +#else + +static inline uint32_t +vmcb2cpu_attrib(uint16_t vmcb_attrib, uint32_t vmcb_base, uint32_t vmcb_limit) +{ + return ((vmcb_attrib & 0x00ff) << 8) /* Type, S, DPL, P */ + | ((vmcb_attrib & 0x0f00) << 12) /* AVL, L, DB, G */ + | ((vmcb_base >> 16) & 0xff) /* Base 23-16 */ + | (vmcb_base & 0xff000000) /* Base 31-24 */ + | (vmcb_limit & 0xf0000); /* Limit 19-16 */ +} + +static inline uint16_t cpu2vmcb_attrib(uint32_t cpu_attrib) +{ + return ((cpu_attrib >> 8) & 0xff) /* Type, S, DPL, P */ + | ((cpu_attrib & 0xf00000) >> 12); /* AVL, L, DB, G */ +} + +extern uint8_t *phys_ram_base; +void helper_vmrun(target_ulong addr) +{ + uint32_t event_inj; + uint32_t int_ctl; + + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr); + + env->vm_vmcb = addr; + regs_to_env(); + + /* save the current CPU state in the hsave page */ + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); + stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); + + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base); + stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); + + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8), env->cr[8]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]); + + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags()); + + SVM_SAVE_SEG(env->vm_hsave, segs[R_ES], es); + SVM_SAVE_SEG(env->vm_hsave, segs[R_CS], cs); + SVM_SAVE_SEG(env->vm_hsave, segs[R_SS], ss); + SVM_SAVE_SEG(env->vm_hsave, segs[R_DS], ds); + + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), EIP); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP); + stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX); + + /* load the interception bitmaps so we do not need to access the + vmcb in svm mode */ + /* We shift all the intercept bits so we can OR them with the TB + flags later on */ + env->intercept = (ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)) << INTERCEPT_INTR) | INTERCEPT_SVM_MASK; + env->intercept_cr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read)); + env->intercept_cr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write)); + env->intercept_dr_read = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read)); + env->intercept_dr_write = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write)); + env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions)); + + env->gdt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base)); + env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit)); + + env->idt.base = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base)); + env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit)); + + /* clear exit_info_2 so we behave like the real hardware */ + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0); + + cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0))); + cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4))); + cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3))); + env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2)); + int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); + if (int_ctl & V_INTR_MASKING_MASK) { + env->cr[8] = int_ctl & V_TPR_MASK; + if (env->eflags & IF_MASK) + env->hflags |= HF_HIF_MASK; + } + +#ifdef TARGET_X86_64 + env->efer = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)); + env->hflags &= ~HF_LMA_MASK; + if (env->efer & MSR_EFER_LMA) + env->hflags |= HF_LMA_MASK; +#endif + env->eflags = 0; + load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + CC_OP = CC_OP_EFLAGS; + CC_DST = 0xffffffff; + + SVM_LOAD_SEG(env->vm_vmcb, ES, es); + SVM_LOAD_SEG(env->vm_vmcb, CS, cs); + SVM_LOAD_SEG(env->vm_vmcb, SS, ss); + SVM_LOAD_SEG(env->vm_vmcb, DS, ds); + + EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip)); + env->eip = EIP; + ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp)); + EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax)); + env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7)); + env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6)); + cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl))); + + /* FIXME: guest state consistency checks */ + + switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) { + case TLB_CONTROL_DO_NOTHING: + break; + case TLB_CONTROL_FLUSH_ALL_ASID: + /* FIXME: this is not 100% correct but should work for now */ + tlb_flush(env, 1); + break; + } + + helper_stgi(); + + regs_to_env(); + + /* maybe we need to inject an event */ + event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); + if (event_inj & SVM_EVTINJ_VALID) { + uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK; + uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR; + uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID); + + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "Injecting(%#hx): ", valid_err); + /* FIXME: need to implement valid_err */ + switch (event_inj & SVM_EVTINJ_TYPE_MASK) { + case SVM_EVTINJ_TYPE_INTR: + env->exception_index = vector; + env->error_code = event_inj_err; + env->exception_is_int = 1; + env->exception_next_eip = -1; + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "INTR"); + break; + case SVM_EVTINJ_TYPE_NMI: + env->exception_index = vector; + env->error_code = event_inj_err; + env->exception_is_int = 1; + env->exception_next_eip = EIP; + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "NMI"); + break; + case SVM_EVTINJ_TYPE_EXEPT: + env->exception_index = vector; + env->error_code = event_inj_err; + env->exception_is_int = 0; + env->exception_next_eip = -1; + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "EXEPT"); + break; + case SVM_EVTINJ_TYPE_SOFT: + env->exception_index = vector; + env->error_code = event_inj_err; + env->exception_is_int = 1; + env->exception_next_eip = EIP; + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, "SOFT"); + break; + } + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code); + } + if (int_ctl & V_IRQ_MASK) + env->interrupt_request |= CPU_INTERRUPT_VIRQ; + + cpu_loop_exit(); +} + +void helper_vmmcall(void) +{ + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmmcall!\n"); +} + +void helper_vmload(target_ulong addr) +{ + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", + addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), + env->segs[R_FS].base); + + SVM_LOAD_SEG2(addr, segs[R_FS], fs); + SVM_LOAD_SEG2(addr, segs[R_GS], gs); + SVM_LOAD_SEG2(addr, tr, tr); + SVM_LOAD_SEG2(addr, ldt, ldtr); + +#ifdef TARGET_X86_64 + env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base)); + env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar)); + env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar)); + env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask)); +#endif + env->star = ldq_phys(addr + offsetof(struct vmcb, save.star)); + env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs)); + env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp)); + env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip)); +} + +void helper_vmsave(target_ulong addr) +{ + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", + addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)), + env->segs[R_FS].base); + + SVM_SAVE_SEG(addr, segs[R_FS], fs); + SVM_SAVE_SEG(addr, segs[R_GS], gs); + SVM_SAVE_SEG(addr, tr, tr); + SVM_SAVE_SEG(addr, ldt, ldtr); + +#ifdef TARGET_X86_64 + stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase); + stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar); + stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar); + stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask); +#endif + stq_phys(addr + offsetof(struct vmcb, save.star), env->star); + stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); + stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp); + stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip); +} + +void helper_skinit(void) +{ + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"skinit!\n"); +} + +void helper_invlpga(void) +{ + tlb_flush(env, 0); +} + +int svm_check_intercept_param(uint32_t type, uint64_t param) +{ + switch(type) { + case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: + if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) { + vmexit(type, param); + return 1; + } + break; + case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8: + if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) { + vmexit(type, param); + return 1; + } + break; + case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: + if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) { + vmexit(type, param); + return 1; + } + break; + case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8: + if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) { + vmexit(type, param); + return 1; + } + break; + case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16: + if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) { + vmexit(type, param); + return 1; + } + break; + case SVM_EXIT_IOIO: + if (INTERCEPTED(1ULL << INTERCEPT_IOIO_PROT)) { + /* FIXME: this should be read in at vmrun (faster this way?) */ + uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); + uint16_t port = (uint16_t) (param >> 16); + + if(ldub_phys(addr + port / 8) & (1 << (port % 8))) + vmexit(type, param); + } + break; + + case SVM_EXIT_MSR: + if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) { + /* FIXME: this should be read in at vmrun (faster this way?) */ + uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa)); + switch((uint32_t)ECX) { + case 0 ... 0x1fff: + T0 = (ECX * 2) % 8; + T1 = ECX / 8; + break; + case 0xc0000000 ... 0xc0001fff: + T0 = (8192 + ECX - 0xc0000000) * 2; + T1 = (T0 / 8); + T0 %= 8; + break; + case 0xc0010000 ... 0xc0011fff: + T0 = (16384 + ECX - 0xc0010000) * 2; + T1 = (T0 / 8); + T0 %= 8; + break; + default: + vmexit(type, param); + return 1; + } + if (ldub_phys(addr + T1) & ((1 << param) << T0)) + vmexit(type, param); + return 1; + } + break; + default: + if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) { + vmexit(type, param); + return 1; + } + break; + } + return 0; +} + +void vmexit(uint64_t exit_code, uint64_t exit_info_1) +{ + uint32_t int_ctl; + + if (loglevel & CPU_LOG_TB_IN_ASM) + fprintf(logfile,"vmexit(%016" PRIx64 ", %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", + exit_code, exit_info_1, + ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), + EIP); + + /* Save the VM state in the vmcb */ + SVM_SAVE_SEG(env->vm_vmcb, segs[R_ES], es); + SVM_SAVE_SEG(env->vm_vmcb, segs[R_CS], cs); + SVM_SAVE_SEG(env->vm_vmcb, segs[R_SS], ss); + SVM_SAVE_SEG(env->vm_vmcb, segs[R_DS], ds); + + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit); + + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit); + + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); + + if ((int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl))) & V_INTR_MASKING_MASK) { + int_ctl &= ~V_TPR_MASK; + int_ctl |= env->cr[8] & V_TPR_MASK; + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); + } + + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags()); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]); + stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK); + + /* Reload the host state from vm_hsave */ + env->hflags &= ~HF_HIF_MASK; + env->intercept = 0; + env->intercept_exceptions = 0; + env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + + env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base)); + env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit)); + + env->idt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base)); + env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit)); + + cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK); + cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4))); + cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3))); + if (int_ctl & V_INTR_MASKING_MASK) + env->cr[8] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8)); + /* we need to set the efer after the crs so the hidden flags get set properly */ +#ifdef TARGET_X86_64 + env->efer = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)); + env->hflags &= ~HF_LMA_MASK; + if (env->efer & MSR_EFER_LMA) + env->hflags |= HF_LMA_MASK; +#endif + + env->eflags = 0; + load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)), + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + CC_OP = CC_OP_EFLAGS; + + SVM_LOAD_SEG(env->vm_hsave, ES, es); + SVM_LOAD_SEG(env->vm_hsave, CS, cs); + SVM_LOAD_SEG(env->vm_hsave, SS, ss); + SVM_LOAD_SEG(env->vm_hsave, DS, ds); + + EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip)); + ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp)); + EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax)); + + env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6)); + env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7)); + + /* other setups */ + cpu_x86_set_cpl(env, 0); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code_hi), (uint32_t)(exit_code >> 32)); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1); + + helper_clgi(); + /* FIXME: Resets the current ASID register to zero (host ASID). */ + + /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */ + + /* Clears the TSC_OFFSET inside the processor. */ + + /* If the host is in PAE mode, the processor reloads the host's PDPEs + from the page table indicated the host's CR3. If the PDPEs contain + illegal state, the processor causes a shutdown. */ + + /* Forces CR0.PE = 1, RFLAGS.VM = 0. */ + env->cr[0] |= CR0_PE_MASK; + env->eflags &= ~VM_MASK; + + /* Disables all breakpoints in the host DR7 register. */ + + /* Checks the reloaded host state for consistency. */ + + /* If the host's rIP reloaded by #VMEXIT is outside the limit of the + host's code segment or non-canonical (in the case of long mode), a + #GP fault is delivered inside the host.) */ + + /* remove any pending exception */ + env->exception_index = -1; + env->error_code = 0; + env->old_exception = -1; + + regs_to_env(); + cpu_loop_exit(); +} + +#endif diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 715b289b3..541d83f92 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -27,6 +27,7 @@ #include "cpu.h" #include "exec-all.h" +#include "svm.h" //#define DEBUG_MMU @@ -111,10 +112,11 @@ CPUX86State *cpu_x86_init(void) CPUID_CX8 | CPUID_PGE | CPUID_CMOV | CPUID_PAT); env->pat = 0x0007040600070406ULL; + env->cpuid_ext3_features = CPUID_EXT3_SVM; env->cpuid_ext_features = CPUID_EXT_SSE3; env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP; env->cpuid_features |= CPUID_APIC; - env->cpuid_xlevel = 0x80000006; + env->cpuid_xlevel = 0x8000000e; { const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION; int c, len, i; @@ -131,7 +133,6 @@ CPUX86State *cpu_x86_init(void) /* currently not enabled for std i386 because not fully tested */ env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF); env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX; - env->cpuid_xlevel = 0x80000008; /* these features are needed for Win64 and aren't fully implemented */ env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA; @@ -162,6 +163,7 @@ void cpu_reset(CPUX86State *env) #ifdef CONFIG_SOFTMMU env->hflags |= HF_SOFTMMU_MASK; #endif + env->hflags |= HF_GIF_MASK; cpu_x86_update_cr0(env, 0x60000010); env->a20_mask = 0xffffffff; @@ -865,7 +867,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, do_fault_protect: error_code = PG_ERROR_P_MASK; do_fault: - env->cr[2] = addr; error_code |= (is_write << PG_ERROR_W_BIT); if (is_user) error_code |= PG_ERROR_U_MASK; @@ -873,8 +874,16 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, (env->efer & MSR_EFER_NXE) && (env->cr[4] & CR4_PAE_MASK)) error_code |= PG_ERROR_I_D_MASK; + if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) { + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr); + } else { + env->cr[2] = addr; + } env->error_code = error_code; env->exception_index = EXCP0E_PAGE; + /* the VMM will handle this */ + if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) + return 2; return 1; } diff --git a/target-i386/op.c b/target-i386/op.c index 9b4263ca7..7d8950e07 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -513,8 +513,6 @@ typedef union UREG64 { } UREG64; #endif -#ifdef TARGET_X86_64 - #define PARAMQ1 \ ({\ UREG64 __p;\ @@ -523,6 +521,8 @@ typedef union UREG64 { __p.q;\ }) +#ifdef TARGET_X86_64 + void OPPROTO op_movq_T0_im64(void) { T0 = PARAMQ1; @@ -1242,12 +1242,52 @@ void OPPROTO op_ltr_T0(void) helper_ltr_T0(); } -/* CR registers access */ +/* CR registers access. */ void OPPROTO op_movl_crN_T0(void) { helper_movl_crN_T0(PARAM1); } +/* These pseudo-opcodes check for SVM intercepts. */ +void OPPROTO op_svm_check_intercept(void) +{ + A0 = PARAM1 & PARAM2; + svm_check_intercept(PARAMQ1); +} + +void OPPROTO op_svm_check_intercept_param(void) +{ + A0 = PARAM1 & PARAM2; + svm_check_intercept_param(PARAMQ1, T1); +} + +void OPPROTO op_svm_vmexit(void) +{ + A0 = PARAM1 & PARAM2; + vmexit(PARAMQ1, T1); +} + +void OPPROTO op_geneflags(void) +{ + CC_SRC = cc_table[CC_OP].compute_all(); +} + +/* This pseudo-opcode checks for IO intercepts. */ +#if !defined(CONFIG_USER_ONLY) +void OPPROTO op_svm_check_intercept_io(void) +{ + A0 = PARAM1 & PARAM2; + /* PARAMQ1 = TYPE (0 = OUT, 1 = IN; 4 = STRING; 8 = REP) + T0 = PORT + T1 = next eip */ + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), T1); + /* ASIZE does not appear on real hw */ + svm_check_intercept_param(SVM_EXIT_IOIO, + (PARAMQ1 & ~SVM_IOIO_ASIZE_MASK) | + ((T0 & 0xffff) << 16)); +} +#endif + #if !defined(CONFIG_USER_ONLY) void OPPROTO op_movtl_T0_cr8(void) { @@ -2452,3 +2492,45 @@ void OPPROTO op_emms(void) #define SHIFT 1 #include "ops_sse.h" + +/* Secure Virtual Machine ops */ + +void OPPROTO op_vmrun(void) +{ + helper_vmrun(EAX); +} + +void OPPROTO op_vmmcall(void) +{ + helper_vmmcall(); +} + +void OPPROTO op_vmload(void) +{ + helper_vmload(EAX); +} + +void OPPROTO op_vmsave(void) +{ + helper_vmsave(EAX); +} + +void OPPROTO op_stgi(void) +{ + helper_stgi(); +} + +void OPPROTO op_clgi(void) +{ + helper_clgi(); +} + +void OPPROTO op_skinit(void) +{ + helper_skinit(); +} + +void OPPROTO op_invlpga(void) +{ + helper_invlpga(); +} diff --git a/target-i386/translate.c b/target-i386/translate.c index 028cdac9a..d62d563bd 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1995,6 +1995,98 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip) } } +#ifdef TARGET_X86_64 +#define SVM_movq_T1_im(x) gen_op_movq_T1_im64((x) >> 32, x) +#else +#define SVM_movq_T1_im(x) gen_op_movl_T1_im(x) +#endif + +static inline int +gen_svm_check_io(DisasContext *s, target_ulong pc_start, uint64_t type) +{ +#if !defined(CONFIG_USER_ONLY) + if(s->flags & (1ULL << INTERCEPT_IOIO_PROT)) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + SVM_movq_T1_im(s->pc - s->cs_base); + gen_jmp_im(pc_start - s->cs_base); + gen_op_geneflags(); + gen_op_svm_check_intercept_io((uint32_t)(type >> 32), (uint32_t)type); + s->cc_op = CC_OP_DYNAMIC; + /* FIXME: maybe we could move the io intercept vector to the TB as well + so we know if this is an EOB or not ... let's assume it's not + for now. */ + } +#endif + return 0; +} + +static inline int svm_is_rep(int prefixes) +{ + return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0); +} + +static inline int +gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, + uint64_t type, uint64_t param) +{ + if(!(s->flags & (INTERCEPT_SVM_MASK))) + /* no SVM activated */ + return 0; + switch(type) { + /* CRx and DRx reads/writes */ + case SVM_EXIT_READ_CR0 ... SVM_EXIT_EXCP_BASE - 1: + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(pc_start - s->cs_base); + SVM_movq_T1_im(param); + gen_op_geneflags(); + gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type); + /* this is a special case as we do not know if the interception occurs + so we assume there was none */ + return 0; + case SVM_EXIT_MSR: + if(s->flags & (1ULL << INTERCEPT_MSR_PROT)) { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(pc_start - s->cs_base); + SVM_movq_T1_im(param); + gen_op_geneflags(); + gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type); + /* this is a special case as we do not know if the interception occurs + so we assume there was none */ + return 0; + } + break; + default: + if(s->flags & (1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR))) { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_EFLAGS; + } + gen_jmp_im(pc_start - s->cs_base); + SVM_movq_T1_im(param); + gen_op_geneflags(); + gen_op_svm_vmexit(type >> 32, type); + /* we can optimize this one so TBs don't get longer + than up to vmexit */ + gen_eob(s); + return 1; + } + } + return 0; +} + +static inline int +gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type) +{ + return gen_svm_check_intercept_param(s, pc_start, type, 0); +} + static inline void gen_stack_update(DisasContext *s, int addend) { #ifdef TARGET_X86_64 @@ -4880,6 +4972,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) else ot = dflag ? OT_LONG : OT_WORD; gen_check_io(s, ot, 1, pc_start - s->cs_base); + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_andl_T0_ffff(); + if (gen_svm_check_io(s, pc_start, + SVM_IOIO_TYPE_MASK | (1 << (4+ot)) | + svm_is_rep(prefixes) | 4 | (1 << (7+s->aflag)))) + break; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { @@ -4893,6 +4991,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) else ot = dflag ? OT_LONG : OT_WORD; gen_check_io(s, ot, 1, pc_start - s->cs_base); + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_andl_T0_ffff(); + if (gen_svm_check_io(s, pc_start, + (1 << (4+ot)) | svm_is_rep(prefixes) | + 4 | (1 << (7+s->aflag)))) + break; if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { @@ -4902,6 +5006,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /************************/ /* port I/O */ + case 0xe4: case 0xe5: if ((b & 1) == 0) @@ -4911,6 +5016,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) val = ldub_code(s->pc++); gen_op_movl_T0_im(val); gen_check_io(s, ot, 0, pc_start - s->cs_base); + if (gen_svm_check_io(s, pc_start, + SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | + (1 << (4+ot)))) + break; gen_op_in[ot](); gen_op_mov_reg_T1[ot][R_EAX](); break; @@ -4923,6 +5032,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) val = ldub_code(s->pc++); gen_op_movl_T0_im(val); gen_check_io(s, ot, 0, pc_start - s->cs_base); + if (gen_svm_check_io(s, pc_start, svm_is_rep(prefixes) | + (1 << (4+ot)))) + break; gen_op_mov_TN_reg[ot][1][R_EAX](); gen_op_out[ot](); break; @@ -4935,6 +5047,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); gen_op_andl_T0_ffff(); gen_check_io(s, ot, 0, pc_start - s->cs_base); + if (gen_svm_check_io(s, pc_start, + SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | + (1 << (4+ot)))) + break; gen_op_in[ot](); gen_op_mov_reg_T1[ot][R_EAX](); break; @@ -4947,6 +5063,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); gen_op_andl_T0_ffff(); gen_check_io(s, ot, 0, pc_start - s->cs_base); + if (gen_svm_check_io(s, pc_start, + svm_is_rep(prefixes) | (1 << (4+ot)))) + break; gen_op_mov_TN_reg[ot][1][R_EAX](); gen_op_out[ot](); break; @@ -5004,6 +5123,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) val = 0; goto do_lret; case 0xcf: /* iret */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET)) + break; if (!s->pe) { /* real mode */ gen_op_iret_real(s->dflag); @@ -5125,6 +5246,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /************************/ /* flags */ case 0x9c: /* pushf */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF)) + break; if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -5135,6 +5258,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } break; case 0x9d: /* popf */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF)) + break; if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -5348,6 +5473,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /* XXX: correct lock test for all insn */ if (prefixes & PREFIX_LOCK) goto illegal_op; + if (prefixes & PREFIX_REPZ) { + gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE); + } break; case 0x9b: /* fwait */ if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == @@ -5361,10 +5489,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } break; case 0xcc: /* int3 */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) + break; gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); break; case 0xcd: /* int N */ val = ldub_code(s->pc++); + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) + break; if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { @@ -5374,12 +5506,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0xce: /* into */ if (CODE64(s)) goto illegal_op; + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT)) + break; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); gen_op_into(s->pc - pc_start); break; case 0xf1: /* icebp (undocumented, exits to external debugger) */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP)) + break; #if 1 gen_debug(s, pc_start - s->cs_base); #else @@ -5415,6 +5551,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_set_inhibit_irq(); /* give a chance to handle pending irqs */ gen_jmp_im(s->pc - s->cs_base); + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VINTR)) + break; gen_eob(s); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); @@ -5507,13 +5645,21 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (b & 2) + int retval = 0; + if (b & 2) { + retval = gen_svm_check_intercept_param(s, pc_start, SVM_EXIT_MSR, 0); gen_op_rdmsr(); - else + } else { + retval = gen_svm_check_intercept_param(s, pc_start, SVM_EXIT_MSR, 1); gen_op_wrmsr(); + } + if(retval) + gen_eob(s); } break; case 0x131: /* rdtsc */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_RDTSC)) + break; gen_jmp_im(pc_start - s->cs_base); gen_op_rdtsc(); break; @@ -5576,12 +5722,16 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; #endif case 0x1a2: /* cpuid */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_CPUID)) + break; gen_op_cpuid(); break; case 0xf4: /* hlt */ if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_HLT)) + break; if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(s->pc - s->cs_base); @@ -5597,6 +5747,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0: /* sldt */ if (!s->pe || s->vm86) goto illegal_op; + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ)) + break; gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); ot = OT_WORD; if (mod == 3) @@ -5609,6 +5761,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE)) + break; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_jmp_im(pc_start - s->cs_base); gen_op_lldt_T0(); @@ -5617,6 +5771,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 1: /* str */ if (!s->pe || s->vm86) goto illegal_op; + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ)) + break; gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); ot = OT_WORD; if (mod == 3) @@ -5629,6 +5785,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE)) + break; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_jmp_im(pc_start - s->cs_base); gen_op_ltr_T0(); @@ -5660,6 +5818,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0: /* sgdt */ if (mod == 3) goto illegal_op; + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ)) + break; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit)); gen_op_st_T0_A0[OT_WORD + s->mem_index](); @@ -5676,6 +5836,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) goto illegal_op; + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_MONITOR)) + break; gen_jmp_im(pc_start - s->cs_base); #ifdef TARGET_X86_64 if (s->aflag == 2) { @@ -5700,6 +5862,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_set_cc_op(s->cc_op); s->cc_op = CC_OP_DYNAMIC; } + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_MWAIT)) + break; gen_jmp_im(s->pc - s->cs_base); gen_op_mwait(); gen_eob(s); @@ -5708,6 +5872,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; } } else { /* sidt */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ)) + break; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit)); gen_op_st_T0_A0[OT_WORD + s->mem_index](); @@ -5720,11 +5886,63 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 2: /* lgdt */ case 3: /* lidt */ - if (mod == 3) - goto illegal_op; - if (s->cpl != 0) { + if (mod == 3) { + switch(rm) { + case 0: /* VMRUN */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMRUN)) + break; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(s->pc - s->cs_base); + gen_op_vmrun(); + s->cc_op = CC_OP_EFLAGS; + gen_eob(s); + break; + case 1: /* VMMCALL */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMMCALL)) + break; + /* FIXME: cause #UD if hflags & SVM */ + gen_op_vmmcall(); + break; + case 2: /* VMLOAD */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMLOAD)) + break; + gen_op_vmload(); + break; + case 3: /* VMSAVE */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMSAVE)) + break; + gen_op_vmsave(); + break; + case 4: /* STGI */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_STGI)) + break; + gen_op_stgi(); + break; + case 5: /* CLGI */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_CLGI)) + break; + gen_op_clgi(); + break; + case 6: /* SKINIT */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SKINIT)) + break; + gen_op_skinit(); + break; + case 7: /* INVLPGA */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVLPGA)) + break; + gen_op_invlpga(); + break; + default: + goto illegal_op; + } + } else if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { + if (gen_svm_check_intercept(s, pc_start, + op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE)) + break; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_ld_T1_A0[OT_WORD + s->mem_index](); gen_add_A0_im(s, 2); @@ -5741,6 +5959,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } break; case 4: /* smsw */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0)) + break; gen_op_movl_T0_env(offsetof(CPUX86State,cr[0])); gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); break; @@ -5748,6 +5968,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0)) + break; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); gen_op_lmsw_T0(); gen_jmp_im(s->pc - s->cs_base); @@ -5772,6 +5994,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; } } else { + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVLPG)) + break; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_invlpg_A0(); gen_jmp_im(s->pc - s->cs_base); @@ -5788,6 +6012,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVD)) + break; /* nothing to do */ } break; @@ -5908,11 +6134,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 4: case 8: if (b & 2) { + gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0 + reg); gen_op_mov_TN_reg[ot][0][rm](); gen_op_movl_crN_T0(reg); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { + gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0 + reg); #if !defined(CONFIG_USER_ONLY) if (reg == 8) gen_op_movtl_T0_cr8(); @@ -5945,11 +6173,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (reg == 4 || reg == 5 || reg >= 8) goto illegal_op; if (b & 2) { + gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg); gen_op_mov_TN_reg[ot][0][rm](); gen_op_movl_drN_T0(reg); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { + gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_DR0 + reg); gen_op_movtl_T0_env(offsetof(CPUX86State,dr[reg])); gen_op_mov_reg_T0[ot][rm](); } @@ -5959,6 +6189,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { + gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); gen_op_clts(); /* abort block because static cpu state changed */ gen_jmp_im(s->pc - s->cs_base); @@ -6050,6 +6281,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /* ignore for now */ break; case 0x1aa: /* rsm */ + if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM)) + break; if (!(s->flags & HF_SMM_MASK)) goto illegal_op; if (s->cc_op != CC_OP_DYNAMIC) { -- cgit v1.2.3 From 239fbd8623f627c1e6c0f2b41e2c5686c89d4aa6 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 23 Sep 2007 15:30:28 +0000 Subject: Add missing svm.h header, and add a Changelog entry. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3211 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + target-i386/svm.h | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 359 insertions(+) create mode 100644 target-i386/svm.h diff --git a/Changelog b/Changelog index 21e35985d..f61a58061 100644 --- a/Changelog +++ b/Changelog @@ -11,6 +11,7 @@ - MIPS64 support (Aurelien Jarno, Thiemo Seufer) - Preliminary Alpha guest support (J. Mayer) - Read-only support for Parallels disk images (Alex Beregszaszi) + - SVM (x86 virtualization) support (Alexander Graf) version 0.9.0: diff --git a/target-i386/svm.h b/target-i386/svm.h new file mode 100644 index 000000000..982d05487 --- /dev/null +++ b/target-i386/svm.h @@ -0,0 +1,358 @@ +#ifndef __SVM_H +#define __SVM_H + +enum { + /* We shift all the intercept bits so we can OR them with the + TB flags later on */ + INTERCEPT_INTR = HF_HIF_SHIFT, + INTERCEPT_NMI, + INTERCEPT_SMI, + INTERCEPT_INIT, + INTERCEPT_VINTR, + INTERCEPT_SELECTIVE_CR0, + INTERCEPT_STORE_IDTR, + INTERCEPT_STORE_GDTR, + INTERCEPT_STORE_LDTR, + INTERCEPT_STORE_TR, + INTERCEPT_LOAD_IDTR, + INTERCEPT_LOAD_GDTR, + INTERCEPT_LOAD_LDTR, + INTERCEPT_LOAD_TR, + INTERCEPT_RDTSC, + INTERCEPT_RDPMC, + INTERCEPT_PUSHF, + INTERCEPT_POPF, + INTERCEPT_CPUID, + INTERCEPT_RSM, + INTERCEPT_IRET, + INTERCEPT_INTn, + INTERCEPT_INVD, + INTERCEPT_PAUSE, + INTERCEPT_HLT, + INTERCEPT_INVLPG, + INTERCEPT_INVLPGA, + INTERCEPT_IOIO_PROT, + INTERCEPT_MSR_PROT, + INTERCEPT_TASK_SWITCH, + INTERCEPT_FERR_FREEZE, + INTERCEPT_SHUTDOWN, + INTERCEPT_VMRUN, + INTERCEPT_VMMCALL, + INTERCEPT_VMLOAD, + INTERCEPT_VMSAVE, + INTERCEPT_STGI, + INTERCEPT_CLGI, + INTERCEPT_SKINIT, + INTERCEPT_RDTSCP, + INTERCEPT_ICEBP, + INTERCEPT_WBINVD, +}; +/* This is not really an intercept but rather a placeholder to + show that we are in an SVM (just like a hidden flag, but keeps the + TBs clean) */ +#define INTERCEPT_SVM 63 +#define INTERCEPT_SVM_MASK (1ULL << INTERCEPT_SVM) + +struct __attribute__ ((__packed__)) vmcb_control_area { + uint16_t intercept_cr_read; + uint16_t intercept_cr_write; + uint16_t intercept_dr_read; + uint16_t intercept_dr_write; + uint32_t intercept_exceptions; + uint64_t intercept; + uint8_t reserved_1[44]; + uint64_t iopm_base_pa; + uint64_t msrpm_base_pa; + uint64_t tsc_offset; + uint32_t asid; + uint8_t tlb_ctl; + uint8_t reserved_2[3]; + uint32_t int_ctl; + uint32_t int_vector; + uint32_t int_state; + uint8_t reserved_3[4]; + uint32_t exit_code; + uint32_t exit_code_hi; + uint64_t exit_info_1; + uint64_t exit_info_2; + uint32_t exit_int_info; + uint32_t exit_int_info_err; + uint64_t nested_ctl; + uint8_t reserved_4[16]; + uint32_t event_inj; + uint32_t event_inj_err; + uint64_t nested_cr3; + uint64_t lbr_ctl; + uint8_t reserved_5[832]; +}; + + +#define TLB_CONTROL_DO_NOTHING 0 +#define TLB_CONTROL_FLUSH_ALL_ASID 1 + +#define V_TPR_MASK 0x0f + +#define V_IRQ_SHIFT 8 +#define V_IRQ_MASK (1 << V_IRQ_SHIFT) + +#define V_INTR_PRIO_SHIFT 16 +#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT) + +#define V_IGN_TPR_SHIFT 20 +#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT) + +#define V_INTR_MASKING_SHIFT 24 +#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) + +#define SVM_INTERRUPT_SHADOW_MASK 1 + +#define SVM_IOIO_STR_SHIFT 2 +#define SVM_IOIO_REP_SHIFT 3 +#define SVM_IOIO_SIZE_SHIFT 4 +#define SVM_IOIO_ASIZE_SHIFT 7 + +#define SVM_IOIO_TYPE_MASK 1 +#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT) +#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT) +#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT) +#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT) + +struct __attribute__ ((__packed__)) vmcb_seg { + uint16_t selector; + uint16_t attrib; + uint32_t limit; + uint64_t base; +}; + +struct __attribute__ ((__packed__)) vmcb_save_area { + struct vmcb_seg es; + struct vmcb_seg cs; + struct vmcb_seg ss; + struct vmcb_seg ds; + struct vmcb_seg fs; + struct vmcb_seg gs; + struct vmcb_seg gdtr; + struct vmcb_seg ldtr; + struct vmcb_seg idtr; + struct vmcb_seg tr; + uint8_t reserved_1[43]; + uint8_t cpl; + uint8_t reserved_2[4]; + uint64_t efer; + uint8_t reserved_3[112]; + uint64_t cr4; + uint64_t cr3; + uint64_t cr0; + uint64_t dr7; + uint64_t dr6; + uint64_t rflags; + uint64_t rip; + uint8_t reserved_4[88]; + uint64_t rsp; + uint8_t reserved_5[24]; + uint64_t rax; + uint64_t star; + uint64_t lstar; + uint64_t cstar; + uint64_t sfmask; + uint64_t kernel_gs_base; + uint64_t sysenter_cs; + uint64_t sysenter_esp; + uint64_t sysenter_eip; + uint64_t cr2; + /* qemu: cr8 added to reuse this as hsave */ + uint64_t cr8; + uint8_t reserved_6[32 - 8]; /* originally 32 */ + uint64_t g_pat; + uint64_t dbgctl; + uint64_t br_from; + uint64_t br_to; + uint64_t last_excp_from; + uint64_t last_excp_to; +}; + +struct __attribute__ ((__packed__)) vmcb { + struct vmcb_control_area control; + struct vmcb_save_area save; +}; + +#define SVM_CPUID_FEATURE_SHIFT 2 +#define SVM_CPUID_FUNC 0x8000000a + +#define MSR_EFER_SVME_MASK (1ULL << 12) + +#define SVM_SELECTOR_S_SHIFT 4 +#define SVM_SELECTOR_DPL_SHIFT 5 +#define SVM_SELECTOR_P_SHIFT 7 +#define SVM_SELECTOR_AVL_SHIFT 8 +#define SVM_SELECTOR_L_SHIFT 9 +#define SVM_SELECTOR_DB_SHIFT 10 +#define SVM_SELECTOR_G_SHIFT 11 + +#define SVM_SELECTOR_TYPE_MASK (0xf) +#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT) +#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT) +#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT) +#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT) +#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT) +#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT) +#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT) + +#define SVM_SELECTOR_WRITE_MASK (1 << 1) +#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK +#define SVM_SELECTOR_CODE_MASK (1 << 3) + +#define INTERCEPT_CR0_MASK 1 +#define INTERCEPT_CR3_MASK (1 << 3) +#define INTERCEPT_CR4_MASK (1 << 4) + +#define INTERCEPT_DR0_MASK 1 +#define INTERCEPT_DR1_MASK (1 << 1) +#define INTERCEPT_DR2_MASK (1 << 2) +#define INTERCEPT_DR3_MASK (1 << 3) +#define INTERCEPT_DR4_MASK (1 << 4) +#define INTERCEPT_DR5_MASK (1 << 5) +#define INTERCEPT_DR6_MASK (1 << 6) +#define INTERCEPT_DR7_MASK (1 << 7) + +#define SVM_EVTINJ_VEC_MASK 0xff + +#define SVM_EVTINJ_TYPE_SHIFT 8 +#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT) + +#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT) +#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT) + +#define SVM_EVTINJ_VALID (1 << 31) +#define SVM_EVTINJ_VALID_ERR (1 << 11) + +#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK + +#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR +#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI +#define SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT +#define SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT + +#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID +#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR + +#define SVM_EXIT_READ_CR0 0x000 +#define SVM_EXIT_READ_CR3 0x003 +#define SVM_EXIT_READ_CR4 0x004 +#define SVM_EXIT_READ_CR8 0x008 +#define SVM_EXIT_WRITE_CR0 0x010 +#define SVM_EXIT_WRITE_CR3 0x013 +#define SVM_EXIT_WRITE_CR4 0x014 +#define SVM_EXIT_WRITE_CR8 0x018 +#define SVM_EXIT_READ_DR0 0x020 +#define SVM_EXIT_READ_DR1 0x021 +#define SVM_EXIT_READ_DR2 0x022 +#define SVM_EXIT_READ_DR3 0x023 +#define SVM_EXIT_READ_DR4 0x024 +#define SVM_EXIT_READ_DR5 0x025 +#define SVM_EXIT_READ_DR6 0x026 +#define SVM_EXIT_READ_DR7 0x027 +#define SVM_EXIT_WRITE_DR0 0x030 +#define SVM_EXIT_WRITE_DR1 0x031 +#define SVM_EXIT_WRITE_DR2 0x032 +#define SVM_EXIT_WRITE_DR3 0x033 +#define SVM_EXIT_WRITE_DR4 0x034 +#define SVM_EXIT_WRITE_DR5 0x035 +#define SVM_EXIT_WRITE_DR6 0x036 +#define SVM_EXIT_WRITE_DR7 0x037 +#define SVM_EXIT_EXCP_BASE 0x040 +#define SVM_EXIT_INTR 0x060 +#define SVM_EXIT_NMI 0x061 +#define SVM_EXIT_SMI 0x062 +#define SVM_EXIT_INIT 0x063 +#define SVM_EXIT_VINTR 0x064 +#define SVM_EXIT_CR0_SEL_WRITE 0x065 +#define SVM_EXIT_IDTR_READ 0x066 +#define SVM_EXIT_GDTR_READ 0x067 +#define SVM_EXIT_LDTR_READ 0x068 +#define SVM_EXIT_TR_READ 0x069 +#define SVM_EXIT_IDTR_WRITE 0x06a +#define SVM_EXIT_GDTR_WRITE 0x06b +#define SVM_EXIT_LDTR_WRITE 0x06c +#define SVM_EXIT_TR_WRITE 0x06d +#define SVM_EXIT_RDTSC 0x06e +#define SVM_EXIT_RDPMC 0x06f +#define SVM_EXIT_PUSHF 0x070 +#define SVM_EXIT_POPF 0x071 +#define SVM_EXIT_CPUID 0x072 +#define SVM_EXIT_RSM 0x073 +#define SVM_EXIT_IRET 0x074 +#define SVM_EXIT_SWINT 0x075 +#define SVM_EXIT_INVD 0x076 +#define SVM_EXIT_PAUSE 0x077 +#define SVM_EXIT_HLT 0x078 +#define SVM_EXIT_INVLPG 0x079 +#define SVM_EXIT_INVLPGA 0x07a +#define SVM_EXIT_IOIO 0x07b +#define SVM_EXIT_MSR 0x07c +#define SVM_EXIT_TASK_SWITCH 0x07d +#define SVM_EXIT_FERR_FREEZE 0x07e +#define SVM_EXIT_SHUTDOWN 0x07f +#define SVM_EXIT_VMRUN 0x080 +#define SVM_EXIT_VMMCALL 0x081 +#define SVM_EXIT_VMLOAD 0x082 +#define SVM_EXIT_VMSAVE 0x083 +#define SVM_EXIT_STGI 0x084 +#define SVM_EXIT_CLGI 0x085 +#define SVM_EXIT_SKINIT 0x086 +#define SVM_EXIT_RDTSCP 0x087 +#define SVM_EXIT_ICEBP 0x088 +#define SVM_EXIT_WBINVD 0x089 +/* only included in documentation, maybe wrong */ +#define SVM_EXIT_MONITOR 0x08a +#define SVM_EXIT_MWAIT 0x08b +#define SVM_EXIT_NPF 0x400 + +#define SVM_EXIT_ERR -1 + +#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */ + +#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" +#define SVM_VMRUN ".byte 0x0f, 0x01, 0xd8" +#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb" +#define SVM_CLGI ".byte 0x0f, 0x01, 0xdd" +#define SVM_STGI ".byte 0x0f, 0x01, 0xdc" +#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf" + +/* function references */ + +void helper_stgi(); +void vmexit(uint64_t exit_code, uint64_t exit_info_1); +int svm_check_intercept_param(uint32_t type, uint64_t param); +static inline int svm_check_intercept(unsigned int type) { + return svm_check_intercept_param(type, 0); +} + + +#define INTERCEPTED(mask) (env->intercept & mask) +#define INTERCEPTEDw(var, mask) (env->intercept ## var & mask) +#define INTERCEPTEDl(var, mask) (env->intercept ## var & mask) + +#define SVM_LOAD_SEG(addr, seg_index, seg) \ + cpu_x86_load_seg_cache(env, \ + R_##seg_index, \ + lduw_phys(addr + offsetof(struct vmcb, save.seg.selector)),\ + ldq_phys(addr + offsetof(struct vmcb, save.seg.base)),\ + ldl_phys(addr + offsetof(struct vmcb, save.seg.limit)),\ + vmcb2cpu_attrib(lduw_phys(addr + offsetof(struct vmcb, save.seg.attrib)), ldq_phys(addr + offsetof(struct vmcb, save.seg.base)), ldl_phys(addr + offsetof(struct vmcb, save.seg.limit)))) + +#define SVM_LOAD_SEG2(addr, seg_qemu, seg_vmcb) \ + env->seg_qemu.selector = lduw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.selector)); \ + env->seg_qemu.base = ldq_phys(addr + offsetof(struct vmcb, save.seg_vmcb.base)); \ + env->seg_qemu.limit = ldl_phys(addr + offsetof(struct vmcb, save.seg_vmcb.limit)); \ + env->seg_qemu.flags = vmcb2cpu_attrib(lduw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.attrib)), env->seg_qemu.base, env->seg_qemu.limit) + +#define SVM_SAVE_SEG(addr, seg_qemu, seg_vmcb) \ + stw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.selector), env->seg_qemu.selector); \ + stq_phys(addr + offsetof(struct vmcb, save.seg_vmcb.base), env->seg_qemu.base); \ + stl_phys(addr + offsetof(struct vmcb, save.seg_vmcb.limit), env->seg_qemu.limit); \ + stw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.attrib), cpu2vmcb_attrib(env->seg_qemu.flags)) + +#endif -- cgit v1.2.3 From 2337fdc2088f6cf8455021315d9de17bb95af850 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 23 Sep 2007 17:54:29 +0000 Subject: Fix mips usermode emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3212 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index a9e931264..1a98973da 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -367,7 +367,10 @@ static void mvp_init (CPUMIPSState *env, mips_def_t *def) implemented, 5 TCs implemented. */ env->mvp->CP0_MVPConf0 = (1 << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) | (0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) | +#ifndef CONFIG_USER_ONLY + /* Usermode has no TLB support */ (env->tlb->nb_tlb << CP0MVPC0_PTLBE) | +#endif // TODO: actually do 2 VPEs. // (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) | // (0x04 << CP0MVPC0_PTC); -- cgit v1.2.3 From 2601c356b71ee69a91e51e5c95d2caae9bb90bd6 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 23 Sep 2007 17:55:00 +0000 Subject: Correct and update mips termbits.h. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3213 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mips/termbits.h | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/linux-user/mips/termbits.h b/linux-user/mips/termbits.h index fea7940a4..d3a6cf8f9 100644 --- a/linux-user/mips/termbits.h +++ b/linux-user/mips/termbits.h @@ -26,6 +26,7 @@ struct target_termios { #define TARGET_IXANY 0004000 #define TARGET_IXOFF 0010000 #define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 /* c_oflag bits */ #define TARGET_OPOST 0000001 @@ -92,12 +93,25 @@ struct target_termios { #define TARGET_HUPCL 0002000 #define TARGET_CLOCAL 0004000 #define TARGET_CBAUDEX 0010000 -#define TARGET_B57600 0010001 -#define TARGET_B115200 0010002 -#define TARGET_B230400 0010003 -#define TARGET_B460800 0010004 +#define TARGET_BOTHER 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 #define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -#define TARGET_CRTSCTS 020000000000 /* flow control */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ /* c_lflag bits */ #define TARGET_ISIG 0000001 @@ -108,32 +122,34 @@ struct target_termios { #define TARGET_ECHOK 0000040 #define TARGET_ECHONL 0000100 #define TARGET_NOFLSH 0000200 -#define TARGET_TOSTOP 0000400 +#define TARGET_IEXTEN 0000400 #define TARGET_ECHOCTL 0001000 #define TARGET_ECHOPRT 0002000 #define TARGET_ECHOKE 0004000 #define TARGET_FLUSHO 0010000 #define TARGET_PENDIN 0040000 -#define TARGET_IEXTEN 0100000 +#define TARGET_TOSTOP 0100000 +#define TARGET_ITOSTOP TARGET_TOSTOP /* c_cc character offsets */ #define TARGET_VINTR 0 #define TARGET_VQUIT 1 #define TARGET_VERASE 2 #define TARGET_VKILL 3 -#define TARGET_VEOF 4 +#define TARGET_VMIN 4 #define TARGET_VTIME 5 -#define TARGET_VMIN 6 +#define TARGET_VEOL2 6 #define TARGET_VSWTC 7 #define TARGET_VSTART 8 #define TARGET_VSTOP 9 #define TARGET_VSUSP 10 -#define TARGET_VEOL 11 +/* VDSUSP not supported */ #define TARGET_VREPRINT 12 #define TARGET_VDISCARD 13 #define TARGET_VWERASE 14 #define TARGET_VLNEXT 15 -#define TARGET_VEOL2 16 +#define TARGET_VEOF 16 +#define TARGET_VEOL 17 /* ioctls */ @@ -154,7 +170,7 @@ struct target_termios { #define TARGET_TIOCEXCL 0x740d /* set exclusive use of tty */ #define TARGET_TIOCNXCL 0x740e /* reset exclusive use of tty */ #define TARGET_TIOCOUTQ 0x7472 /* output queue size */ -#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */ +#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */ #define TARGET_TIOCMGET 0x741d /* get all modem bits */ #define TARGET_TIOCMBIS 0x741b /* bis modem bits */ #define TARGET_TIOCMBIC 0x741c /* bic modem bits */ -- cgit v1.2.3 From b9a02beda2301f91e2d90e329e9a9c0aae3fbb83 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 23 Sep 2007 18:07:05 +0000 Subject: Add new MIPS/Linux syscalls. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3214 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mips/syscall_nr.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h index f86f86a6e..f900ae23f 100644 --- a/linux-user/mips/syscall_nr.h +++ b/linux-user/mips/syscall_nr.h @@ -318,3 +318,8 @@ #define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 313) #define TARGET_NR_ioprio_set (TARGET_NR_Linux + 314) #define TARGET_NR_ioprio_get (TARGET_NR_Linux + 315) +#define TARGET_NR_utimensat (TARGET_NR_Linux + 316) +#define TARGET_NR_signalfd (TARGET_NR_Linux + 317) +#define TARGET_NR_timerfd (TARGET_NR_Linux + 318) +#define TARGET_NR_eventfd (TARGET_NR_Linux + 319) +#define TARGET_NR_fallocate (TARGET_NR_Linux + 320) -- cgit v1.2.3 From f05d35d26da3bcec318e23b943223f83d5e90add Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 23 Sep 2007 23:27:46 +0000 Subject: Sync termbits.h with current Linux kernel. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3215 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/termbits.h | 4 +++- linux-user/i386/termbits.h | 15 ++++++++++++++- linux-user/m68k/termbits.h | 15 ++++++++++++++- linux-user/ppc/termbits.h | 6 ++++-- linux-user/ppc64/termbits.h | 14 ++++++++------ linux-user/sparc/termbits.h | 1 + linux-user/sparc64/termbits.h | 1 + 7 files changed, 45 insertions(+), 11 deletions(-) diff --git a/linux-user/arm/termbits.h b/linux-user/arm/termbits.h index 36ead0895..f018c0758 100644 --- a/linux-user/arm/termbits.h +++ b/linux-user/arm/termbits.h @@ -27,6 +27,7 @@ struct target_termios { #define TARGET_IXANY 0004000 #define TARGET_IXOFF 0010000 #define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 /* c_oflag bits */ #define TARGET_OPOST 0000001 @@ -98,7 +99,8 @@ struct target_termios { #define TARGET_B230400 0010003 #define TARGET_B460800 0010004 #define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -#define TARGET_CRTSCTS 020000000000 /* flow control */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ /* c_lflag bits */ #define TARGET_ISIG 0000001 diff --git a/linux-user/i386/termbits.h b/linux-user/i386/termbits.h index adff80243..4acd2bda0 100644 --- a/linux-user/i386/termbits.h +++ b/linux-user/i386/termbits.h @@ -26,6 +26,7 @@ struct target_termios { #define TARGET_IXANY 0004000 #define TARGET_IXOFF 0010000 #define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 /* c_oflag bits */ #define TARGET_OPOST 0000001 @@ -96,8 +97,20 @@ struct target_termios { #define TARGET_B115200 0010002 #define TARGET_B230400 0010003 #define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 #define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -#define TARGET_CRTSCTS 020000000000 /* flow control */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ /* c_lflag bits */ #define TARGET_ISIG 0000001 diff --git a/linux-user/m68k/termbits.h b/linux-user/m68k/termbits.h index 36ead0895..1bce39d81 100644 --- a/linux-user/m68k/termbits.h +++ b/linux-user/m68k/termbits.h @@ -27,6 +27,7 @@ struct target_termios { #define TARGET_IXANY 0004000 #define TARGET_IXOFF 0010000 #define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 /* c_oflag bits */ #define TARGET_OPOST 0000001 @@ -97,8 +98,20 @@ struct target_termios { #define TARGET_B115200 0010002 #define TARGET_B230400 0010003 #define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 #define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -#define TARGET_CRTSCTS 020000000000 /* flow control */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ /* c_lflag bits */ #define TARGET_ISIG 0000001 diff --git a/linux-user/ppc/termbits.h b/linux-user/ppc/termbits.h index 7bf14eb5c..002de9564 100644 --- a/linux-user/ppc/termbits.h +++ b/linux-user/ppc/termbits.h @@ -47,6 +47,7 @@ struct target_termios { #define TARGET_IXANY 0004000 #define TARGET_IUCLC 0010000 #define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 /* c_oflag bits */ #define TARGET_OPOST 0000001 @@ -69,6 +70,7 @@ struct target_termios { #define TARGET_TAB1 00002000 #define TARGET_TAB2 00004000 #define TARGET_TAB3 00006000 +#define TARGET_XTABS 00006000 /* required by POSIX to == TAB3 */ #define TARGET_CRDLY 00030000 #define TARGET_CR0 00000000 #define TARGET_CR1 00010000 @@ -83,7 +85,6 @@ struct target_termios { #define TARGET_VTDLY 00200000 #define TARGET_VT0 00000000 #define TARGET_VT1 00200000 -#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ /* c_cflag bit meaning */ #define TARGET_CBAUD 0000377 @@ -135,7 +136,8 @@ struct target_termios { #define TARGET_HUPCL 00040000 #define TARGET_CLOCAL 00100000 -#define TARGET_CRTSCTS 020000000000 /* flow control */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ /* c_lflag bits */ #define TARGET_ISIG 0x00000080 diff --git a/linux-user/ppc64/termbits.h b/linux-user/ppc64/termbits.h index 7bf14eb5c..41537ed39 100644 --- a/linux-user/ppc64/termbits.h +++ b/linux-user/ppc64/termbits.h @@ -27,10 +27,10 @@ struct target_termios { #define TARGET_VWERASE 10 #define TARGET_VREPRINT 11 -#define TARGET_VSUSP 12 -#define TARGET_VSTART 13 -#define TARGET_VSTOP 14 -#define TARGET_VLNEXT 15 +#define TARGET_VSUSP 12 +#define TARGET_VSTART 13 +#define TARGET_VSTOP 14 +#define TARGET_VLNEXT 15 #define TARGET_VDISCARD 16 #define TARGET_IGNBRK 0000001 @@ -47,6 +47,7 @@ struct target_termios { #define TARGET_IXANY 0004000 #define TARGET_IUCLC 0010000 #define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 /* c_oflag bits */ #define TARGET_OPOST 0000001 @@ -69,6 +70,7 @@ struct target_termios { #define TARGET_TAB1 00002000 #define TARGET_TAB2 00004000 #define TARGET_TAB3 00006000 +#define TARGET_XTABS 00006000 /* required by POSIX to == TAB3 */ #define TARGET_CRDLY 00030000 #define TARGET_CR0 00000000 #define TARGET_CR1 00010000 @@ -83,7 +85,6 @@ struct target_termios { #define TARGET_VTDLY 00200000 #define TARGET_VT0 00000000 #define TARGET_VT1 00200000 -#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ /* c_cflag bit meaning */ #define TARGET_CBAUD 0000377 @@ -135,7 +136,8 @@ struct target_termios { #define TARGET_HUPCL 00040000 #define TARGET_CLOCAL 00100000 -#define TARGET_CRTSCTS 020000000000 /* flow control */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ /* c_lflag bits */ #define TARGET_ISIG 0x00000080 diff --git a/linux-user/sparc/termbits.h b/linux-user/sparc/termbits.h index 3ec8e97c7..ed9ab2455 100644 --- a/linux-user/sparc/termbits.h +++ b/linux-user/sparc/termbits.h @@ -51,6 +51,7 @@ struct target_termios { #define TARGET_IXANY 0x00000800 #define TARGET_IXOFF 0x00001000 #define TARGET_IMAXBEL 0x00002000 +#define TARGET_IUTF8 0x00004000 /* c_oflag bits */ #define TARGET_OPOST 0x00000001 diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h index 3ec8e97c7..ed9ab2455 100644 --- a/linux-user/sparc64/termbits.h +++ b/linux-user/sparc64/termbits.h @@ -51,6 +51,7 @@ struct target_termios { #define TARGET_IXANY 0x00000800 #define TARGET_IXOFF 0x00001000 #define TARGET_IMAXBEL 0x00002000 +#define TARGET_IUTF8 0x00004000 /* c_oflag bits */ #define TARGET_OPOST 0x00000001 -- cgit v1.2.3 From 8dd77cca03ac6325bda61dbdb8b8a2021fe524c3 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 00:11:26 +0000 Subject: Update Linux kernel syscall list. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3216 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/alpha/syscall_nr.h | 32 ++++++++++++++++++++++ linux-user/arm/syscall_nr.h | 31 +++++++++++++++++++++ linux-user/i386/syscall_nr.h | 58 ++++++++++++++++++++++++++++++++++++--- linux-user/m68k/syscall_nr.h | 39 +++++++++++++++++++++++++++ linux-user/ppc/syscall_nr.h | 55 +++++++++++++++++++++++++++++++++++++ linux-user/ppc64/syscall_nr.h | 55 +++++++++++++++++++++++++++++++++++++ linux-user/sh4/syscall_nr.h | 40 +++++++++++++++++++++++++-- linux-user/sparc/syscall_nr.h | 60 ++++++++++++++++++++++++++++++++++++++++- linux-user/sparc64/syscall_nr.h | 31 +++++++++++++++++++++ linux-user/x86_64/syscall_nr.h | 6 +++++ 10 files changed, 401 insertions(+), 6 deletions(-) diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h index 2c505a1da..d3c19cce4 100644 --- a/linux-user/alpha/syscall_nr.h +++ b/linux-user/alpha/syscall_nr.h @@ -379,3 +379,35 @@ #define TARGET_NR_inotify_init 444 #define TARGET_NR_inotify_add_watch 445 #define TARGET_NR_inotify_rm_watch 446 +#define TARGET_NR_fdatasync 447 +#define TARGET_NR_kexec_load 448 +#define TARGET_NR_migrate_pages 449 +#define TARGET_NR_openat 450 +#define TARGET_NR_mkdirat 451 +#define TARGET_NR_mknodat 452 +#define TARGET_NR_fchownat 453 +#define TARGET_NR_futimesat 454 +#define TARGET_NR_fstatat64 455 +#define TARGET_NR_unlinkat 456 +#define TARGET_NR_renameat 457 +#define TARGET_NR_linkat 458 +#define TARGET_NR_symlinkat 459 +#define TARGET_NR_readlinkat 460 +#define TARGET_NR_fchmodat 461 +#define TARGET_NR_faccessat 462 +#define TARGET_NR_pselect6 463 +#define TARGET_NR_ppoll 464 +#define TARGET_NR_unshare 465 +#define TARGET_NR_set_robust_list 466 +#define TARGET_NR_get_robust_list 467 +#define TARGET_NR_splice 468 +#define TARGET_NR_sync_file_range 469 +#define TARGET_NR_tee 470 +#define TARGET_NR_vmsplice 471 +#define TARGET_NR_move_pages 472 +#define TARGET_NR_getcpu 473 +#define TARGET_NR_epoll_pwait 474 +#define TARGET_NR_utimensat 475 +#define TARGET_NR_signalfd 476 +#define TARGET_NR_timerfd 477 +#define TARGET_NR_eventfd 478 diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index c48be982f..9ca3a5df3 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -325,3 +325,34 @@ #define TARGET_NR_mbind 319 #define TARGET_NR_get_mempolicy 320 #define TARGET_NR_set_mempolicy 321 +#define TARGET_NR_openat (322) +#define TARGET_NR_mkdirat (323) +#define TARGET_NR_mknodat (324) +#define TARGET_NR_fchownat (325) +#define TARGET_NR_futimesat (326) +#define TARGET_NR_fstatat64 (327) +#define TARGET_NR_unlinkat (328) +#define TARGET_NR_renameat (329) +#define TARGET_NR_linkat (330) +#define TARGET_NR_symlinkat (331) +#define TARGET_NR_readlinkat (332) +#define TARGET_NR_fchmodat (333) +#define TARGET_NR_faccessat (334) + /* 335 for pselect6 */ + /* 336 for ppoll */ +#define TARGET_NR_unshare (337) +#define TARGET_NR_set_robust_list (338) +#define TARGET_NR_get_robust_list (339) +#define TARGET_NR_splice (340) +#define TARGET_NR_arm_sync_file_range (341) +#define TARGET_NR_sync_file_range2 TARGET_NR_arm_sync_file_range +#define TARGET_NR_tee (342) +#define TARGET_NR_vmsplice (343) +#define TARGET_NR_move_pages (344) +#define TARGET_NR_getcpu (345) + /* 346 for epoll_pwait */ +#define TARGET_NR_kexec_load (347) +#define TARGET_NR_utimensat (348) +#define TARGET_NR_signalfd (349) +#define TARGET_NR_timerfd (350) +#define TARGET_NR_eventfd (351) diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index 75fb55953..62662ccc5 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -253,7 +253,7 @@ #define TARGET_NR_io_submit 248 #define TARGET_NR_io_cancel 249 #define TARGET_NR_fadvise64 250 - +/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */ #define TARGET_NR_exit_group 252 #define TARGET_NR_lookup_dcookie 253 #define TARGET_NR_epoll_create 254 @@ -270,8 +270,60 @@ #define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) #define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) #define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) - +#define TARGET_NR_statfs64 268 +#define TARGET_NR_fstatfs64 269 #define TARGET_NR_tgkill 270 #define TARGET_NR_utimes 271 - +#define TARGET_NR_fadvise64_64 272 +#define TARGET_NR_vserver 273 +#define TARGET_NR_mbind 274 +#define TARGET_NR_get_mempolicy 275 +#define TARGET_NR_set_mempolicy 276 +#define TARGET_NR_mq_open 277 +#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1) +#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2) +#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3) +#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4) +#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5) +#define TARGET_NR_kexec_load 283 +#define TARGET_NR_waitid 284 +/* #define TARGET_NR_sys_setaltroot 285 */ +#define TARGET_NR_add_key 286 +#define TARGET_NR_request_key 287 +#define TARGET_NR_keyctl 288 +#define TARGET_NR_ioprio_set 289 +#define TARGET_NR_ioprio_get 290 +#define TARGET_NR_inotify_init 291 +#define TARGET_NR_inotify_add_watch 292 +#define TARGET_NR_inotify_rm_watch 293 +#define TARGET_NR_migrate_pages 294 +#define TARGET_NR_openat 295 +#define TARGET_NR_mkdirat 296 +#define TARGET_NR_mknodat 297 +#define TARGET_NR_fchownat 298 +#define TARGET_NR_futimesat 299 +#define TARGET_NR_fstatat64 300 +#define TARGET_NR_unlinkat 301 +#define TARGET_NR_renameat 302 +#define TARGET_NR_linkat 303 +#define TARGET_NR_symlinkat 304 +#define TARGET_NR_readlinkat 305 +#define TARGET_NR_fchmodat 306 +#define TARGET_NR_faccessat 307 +#define TARGET_NR_pselect6 308 +#define TARGET_NR_ppoll 309 +#define TARGET_NR_unshare 310 #define TARGET_NR_set_robust_list 311 +#define TARGET_NR_get_robust_list 312 +#define TARGET_NR_splice 313 +#define TARGET_NR_sync_file_range 314 +#define TARGET_NR_tee 315 +#define TARGET_NR_vmsplice 316 +#define TARGET_NR_move_pages 317 +#define TARGET_NR_getcpu 318 +#define TARGET_NR_epoll_pwait 319 +#define TARGET_NR_utimensat 320 +#define TARGET_NR_signalfd 321 +#define TARGET_NR_timerfd 322 +#define TARGET_NR_eventfd 323 +#define TARGET_NR_fallocate 324 diff --git a/linux-user/m68k/syscall_nr.h b/linux-user/m68k/syscall_nr.h index a39535f5f..0a802f43b 100644 --- a/linux-user/m68k/syscall_nr.h +++ b/linux-user/m68k/syscall_nr.h @@ -281,3 +281,42 @@ #define TARGET_NR_add_key 279 #define TARGET_NR_request_key 280 #define TARGET_NR_keyctl 281 +#define TARGET_NR_ioprio_set 282 +#define TARGET_NR_ioprio_get 283 +#define TARGET_NR_inotify_init 284 +#define TARGET_NR_inotify_add_watch 285 +#define TARGET_NR_inotify_rm_watch 286 +#define TARGET_NR_migrate_pages 287 +#define TARGET_NR_openat 288 +#define TARGET_NR_mkdirat 289 +#define TARGET_NR_mknodat 290 +#define TARGET_NR_fchownat 291 +#define TARGET_NR_futimesat 292 +#define TARGET_NR_fstatat64 293 +#define TARGET_NR_unlinkat 294 +#define TARGET_NR_renameat 295 +#define TARGET_NR_linkat 296 +#define TARGET_NR_symlinkat 297 +#define TARGET_NR_readlinkat 298 +#define TARGET_NR_fchmodat 299 +#define TARGET_NR_faccessat 300 +#define TARGET_NR_pselect6 301 +#define TARGET_NR_ppoll 302 +#define TARGET_NR_unshare 303 +#define TARGET_NR_set_robust_list 304 +#define TARGET_NR_get_robust_list 305 +#define TARGET_NR_splice 306 +#define TARGET_NR_sync_file_range 307 +#define TARGET_NR_tee 308 +#define TARGET_NR_vmsplice 309 +#define TARGET_NR_move_pages 310 +#define TARGET_NR_sched_setaffinity 311 +#define TARGET_NR_sched_getaffinity 312 +#define TARGET_NR_kexec_load 313 +#define TARGET_NR_getcpu 314 +#define TARGET_NR_epoll_pwait 315 +#define TARGET_NR_utimensat 316 +#define TARGET_NR_signalfd 317 +#define TARGET_NR_timerfd 318 +#define TARGET_NR_eventfd 319 +#define TARGET_NR_fallocate 320 diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h index b97189a2e..1e5ced713 100644 --- a/linux-user/ppc/syscall_nr.h +++ b/linux-user/ppc/syscall_nr.h @@ -256,3 +256,58 @@ #define TARGET_NR_statfs64 252 #define TARGET_NR_fstatfs64 253 #define TARGET_NR_fadvise64_64 254 +#define TARGET_NR_rtas 255 +#define TARGET_NR_sys_debug_setcontext 256 +/* Number 257 is reserved for vserver */ +#define TARGET_NR_migrate_pages 258 +#define TARGET_NR_mbind 259 +#define TARGET_NR_get_mempolicy 260 +#define TARGET_NR_set_mempolicy 261 +#define TARGET_NR_mq_open 262 +#define TARGET_NR_mq_unlink 263 +#define TARGET_NR_mq_timedsend 264 +#define TARGET_NR_mq_timedreceive 265 +#define TARGET_NR_mq_notify 266 +#define TARGET_NR_mq_getsetattr 267 +#define TARGET_NR_kexec_load 268 +#define TARGET_NR_add_key 269 +#define TARGET_NR_request_key 270 +#define TARGET_NR_keyctl 271 +#define TARGET_NR_waitid 272 +#define TARGET_NR_ioprio_set 273 +#define TARGET_NR_ioprio_get 274 +#define TARGET_NR_inotify_init 275 +#define TARGET_NR_inotify_add_watch 276 +#define TARGET_NR_inotify_rm_watch 277 +#define TARGET_NR_spu_run 278 +#define TARGET_NR_spu_create 279 +#define TARGET_NR_pselect6 280 +#define TARGET_NR_ppoll 281 +#define TARGET_NR_unshare 282 +#define TARGET_NR_splice 283 +#define TARGET_NR_tee 284 +#define TARGET_NR_vmsplice 285 +#define TARGET_NR_openat 286 +#define TARGET_NR_mkdirat 287 +#define TARGET_NR_mknodat 288 +#define TARGET_NR_fchownat 289 +#define TARGET_NR_futimesat 290 +#define TARGET_NR_fstatat64 291 +#define TARGET_NR_unlinkat 292 +#define TARGET_NR_renameat 293 +#define TARGET_NR_linkat 294 +#define TARGET_NR_symlinkat 295 +#define TARGET_NR_readlinkat 296 +#define TARGET_NR_fchmodat 297 +#define TARGET_NR_faccessat 298 +#define TARGET_NR_get_robust_list 299 +#define TARGET_NR_set_robust_list 300 +#define TARGET_NR_move_pages 301 +#define TARGET_NR_getcpu 302 +#define TARGET_NR_epoll_pwait 303 +#define TARGET_NR_utimensat 304 +#define TARGET_NR_signalfd 305 +#define TARGET_NR_timerfd 306 +#define TARGET_NR_eventfd 307 +#define TARGET_NR_sync_file_range2 308 +#define TARGET_NR_fallocate 309 diff --git a/linux-user/ppc64/syscall_nr.h b/linux-user/ppc64/syscall_nr.h index b97189a2e..d78ce5394 100644 --- a/linux-user/ppc64/syscall_nr.h +++ b/linux-user/ppc64/syscall_nr.h @@ -256,3 +256,58 @@ #define TARGET_NR_statfs64 252 #define TARGET_NR_fstatfs64 253 #define TARGET_NR_fadvise64_64 254 +#define TARGET_NR_rtas 255 +#define TARGET_NR_sys_debug_setcontext 256 +/* Number 257 is reserved for vserver */ +#define TARGET_NR_migrate_pages 258 +#define TARGET_NR_mbind 259 +#define TARGET_NR_get_mempolicy 260 +#define TARGET_NR_set_mempolicy 261 +#define TARGET_NR_mq_open 262 +#define TARGET_NR_mq_unlink 263 +#define TARGET_NR_mq_timedsend 264 +#define TARGET_NR_mq_timedreceive 265 +#define TARGET_NR_mq_notify 266 +#define TARGET_NR_mq_getsetattr 267 +#define TARGET_NR_kexec_load 268 +#define TARGET_NR_add_key 269 +#define TARGET_NR_request_key 270 +#define TARGET_NR_keyctl 271 +#define TARGET_NR_waitid 272 +#define TARGET_NR_ioprio_set 273 +#define TARGET_NR_ioprio_get 274 +#define TARGET_NR_inotify_init 275 +#define TARGET_NR_inotify_add_watch 276 +#define TARGET_NR_inotify_rm_watch 277 +#define TARGET_NR_spu_run 278 +#define TARGET_NR_spu_create 279 +#define TARGET_NR_pselect6 280 +#define TARGET_NR_ppoll 281 +#define TARGET_NR_unshare 282 +#define TARGET_NR_splice 283 +#define TARGET_NR_tee 284 +#define TARGET_NR_vmsplice 285 +#define TARGET_NR_openat 286 +#define TARGET_NR_mkdirat 287 +#define TARGET_NR_mknodat 288 +#define TARGET_NR_fchownat 289 +#define TARGET_NR_futimesat 290 +#define TARGET_NR_newfstatat 291 +#define TARGET_NR_unlinkat 292 +#define TARGET_NR_renameat 293 +#define TARGET_NR_linkat 294 +#define TARGET_NR_symlinkat 295 +#define TARGET_NR_readlinkat 296 +#define TARGET_NR_fchmodat 297 +#define TARGET_NR_faccessat 298 +#define TARGET_NR_get_robust_list 299 +#define TARGET_NR_set_robust_list 300 +#define TARGET_NR_move_pages 301 +#define TARGET_NR_getcpu 302 +#define TARGET_NR_epoll_pwait 303 +#define TARGET_NR_utimensat 304 +#define TARGET_NR_signalfd 305 +#define TARGET_NR_timerfd 306 +#define TARGET_NR_eventfd 307 +#define TARGET_NR_sync_file_range2 308 +#define TARGET_NR_fallocate 309 diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h index c91ba1b3d..b29705c7a 100644 --- a/linux-user/sh4/syscall_nr.h +++ b/linux-user/sh4/syscall_nr.h @@ -226,6 +226,7 @@ #define TARGET_NR_fcntl64 221 /* 223 is unused */ #define TARGET_NR_gettid 224 +#define TARGET_NR_readahead 225 #define TARGET_NR_setxattr 226 #define TARGET_NR_lsetxattr 227 #define TARGET_NR_fsetxattr 228 @@ -288,5 +289,40 @@ #define TARGET_NR_add_key 285 #define TARGET_NR_request_key 286 #define TARGET_NR_keyctl 287 - -#define TARGET_NR_readahead 225 /* XXXXX */ +#define TARGET_NR_ioprio_set 288 +#define TARGET_NR_ioprio_get 289 +#define TARGET_NR_inotify_init 290 +#define TARGET_NR_inotify_add_watch 291 +#define TARGET_NR_inotify_rm_watch 292 +/* 293 is unused */ +#define TARGET_NR_migrate_pages 294 +#define TARGET_NR_openat 295 +#define TARGET_NR_mkdirat 296 +#define TARGET_NR_mknodat 297 +#define TARGET_NR_fchownat 298 +#define TARGET_NR_futimesat 299 +#define TARGET_NR_fstatat64 300 +#define TARGET_NR_unlinkat 301 +#define TARGET_NR_renameat 302 +#define TARGET_NR_linkat 303 +#define TARGET_NR_symlinkat 304 +#define TARGET_NR_readlinkat 305 +#define TARGET_NR_fchmodat 306 +#define TARGET_NR_faccessat 307 +#define TARGET_NR_pselect6 308 +#define TARGET_NR_ppoll 309 +#define TARGET_NR_unshare 310 +#define TARGET_NR_set_robust_list 311 +#define TARGET_NR_get_robust_list 312 +#define TARGET_NR_splice 313 +#define TARGET_NR_sync_file_range 314 +#define TARGET_NR_tee 315 +#define TARGET_NR_vmsplice 316 +#define TARGET_NR_move_pages 317 +#define TARGET_NR_getcpu 318 +#define TARGET_NR_epoll_pwait 319 +#define TARGET_NR_utimensat 320 +#define TARGET_NR_signalfd 321 +#define TARGET_NR_timerfd 322 +#define TARGET_NR_eventfd 323 +#define TARGET_NR_fallocate 324 diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index afb364f07..6419570dd 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -217,4 +217,62 @@ #define TARGET_NR_fdatasync 253 #define TARGET_NR_nfsservctl 254 #define TARGET_NR_aplib 255 -#define TARGET_NR__exit TARGET_NR_exit +#define TARGET_NR_clock_settime 256 +#define TARGET_NR_clock_gettime 257 +#define TARGET_NR_clock_getres 258 +#define TARGET_NR_clock_nanosleep 259 +#define TARGET_NR_sched_getaffinity 260 +#define TARGET_NR_sched_setaffinity 261 +#define TARGET_NR_timer_settime 262 +#define TARGET_NR_timer_gettime 263 +#define TARGET_NR_timer_getoverrun 264 +#define TARGET_NR_timer_delete 265 +#define TARGET_NR_timer_create 266 +/* #define TARGET_NR_vserver 267 Reserved for VSERVER */ +#define TARGET_NR_io_setup 268 +#define TARGET_NR_io_destroy 269 +#define TARGET_NR_io_submit 270 +#define TARGET_NR_io_cancel 271 +#define TARGET_NR_io_getevents 272 +#define TARGET_NR_mq_open 273 +#define TARGET_NR_mq_unlink 274 +#define TARGET_NR_mq_timedsend 275 +#define TARGET_NR_mq_timedreceive 276 +#define TARGET_NR_mq_notify 277 +#define TARGET_NR_mq_getsetattr 278 +#define TARGET_NR_waitid 279 +#define TARGET_NR_tee 280 +#define TARGET_NR_add_key 281 +#define TARGET_NR_request_key 282 +#define TARGET_NR_keyctl 283 +#define TARGET_NR_openat 284 +#define TARGET_NR_mkdirat 285 +#define TARGET_NR_mknodat 286 +#define TARGET_NR_fchownat 287 +#define TARGET_NR_futimesat 288 +#define TARGET_NR_fstatat64 289 +#define TARGET_NR_unlinkat 290 +#define TARGET_NR_renameat 291 +#define TARGET_NR_linkat 292 +#define TARGET_NR_symlinkat 293 +#define TARGET_NR_readlinkat 294 +#define TARGET_NR_fchmodat 295 +#define TARGET_NR_faccessat 296 +#define TARGET_NR_pselect6 297 +#define TARGET_NR_ppoll 298 +#define TARGET_NR_unshare 299 +#define TARGET_NR_set_robust_list 300 +#define TARGET_NR_get_robust_list 301 +#define TARGET_NR_migrate_pages 302 +#define TARGET_NR_mbind 303 +#define TARGET_NR_get_mempolicy 304 +#define TARGET_NR_set_mempolicy 305 +#define TARGET_NR_kexec_load 306 +#define TARGET_NR_move_pages 307 +#define TARGET_NR_getcpu 308 +#define TARGET_NR_epoll_pwait 309 +#define TARGET_NR_utimensat 310 +#define TARGET_NR_signalfd 311 +#define TARGET_NR_timerfd 312 +#define TARGET_NR_eventfd 313 +#define TARGET_NR_fallocate 314 diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h index 9274c85fc..53102945a 100644 --- a/linux-user/sparc64/syscall_nr.h +++ b/linux-user/sparc64/syscall_nr.h @@ -284,3 +284,34 @@ #define TARGET_NR_add_key 281 #define TARGET_NR_request_key 282 #define TARGET_NR_keyctl 283 +#define TARGET_NR_openat 284 +#define TARGET_NR_mkdirat 285 +#define TARGET_NR_mknodat 286 +#define TARGET_NR_fchownat 287 +#define TARGET_NR_futimesat 288 +#define TARGET_NR_fstatat64 289 +#define TARGET_NR_unlinkat 290 +#define TARGET_NR_renameat 291 +#define TARGET_NR_linkat 292 +#define TARGET_NR_symlinkat 293 +#define TARGET_NR_readlinkat 294 +#define TARGET_NR_fchmodat 295 +#define TARGET_NR_faccessat 296 +#define TARGET_NR_pselect6 297 +#define TARGET_NR_ppoll 298 +#define TARGET_NR_unshare 299 +#define TARGET_NR_set_robust_list 300 +#define TARGET_NR_get_robust_list 301 +#define TARGET_NR_migrate_pages 302 +#define TARGET_NR_mbind 303 +#define TARGET_NR_get_mempolicy 304 +#define TARGET_NR_set_mempolicy 305 +#define TARGET_NR_kexec_load 306 +#define TARGET_NR_move_pages 307 +#define TARGET_NR_getcpu 308 +#define TARGET_NR_epoll_pwait 309 +#define TARGET_NR_utimensat 310 +#define TARGET_NR_signalfd 311 +#define TARGET_NR_timerfd 312 +#define TARGET_NR_eventfd 313 +#define TARGET_NR_fallocate 314 diff --git a/linux-user/x86_64/syscall_nr.h b/linux-user/x86_64/syscall_nr.h index c58de2bc5..e6a4c27ea 100644 --- a/linux-user/x86_64/syscall_nr.h +++ b/linux-user/x86_64/syscall_nr.h @@ -278,3 +278,9 @@ #define TARGET_NR_sync_file_range 277 #define TARGET_NR_vmsplice 278 #define TARGET_NR_move_pages 279 +#define TARGET_NR_utimensat 280 +#define TARGET_NR_epoll_pwait 281 +#define TARGET_NR_signalfd 282 +#define TARGET_NR_timerfd 283 +#define TARGET_NR_eventfd 284 +#define TARGET_NR_fallocate 285 -- cgit v1.2.3 From 824248322670885c95213c81a20551ab2434228f Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:21:55 +0000 Subject: linux-user openat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3217 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index d0b4e8292..cde0dd324 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -142,6 +142,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 +#define __NR_sys_openat __NR_openat #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo #define __NR_sys_syslog __NR_syslog #define __NR_sys_tgkill __NR_tgkill @@ -166,6 +167,9 @@ _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); #endif _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); +#if defined(TARGET_NR_openat) && defined(__NR_openat) +_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode) +#endif _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) @@ -2500,6 +2504,24 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, arg3)); unlock_user(p, arg1, 0); break; +#if defined(TARGET_NR_openat) && defined(__NR_openat) + case TARGET_NR_openat: + if (!arg2) { + ret = -EFAULT; + goto fail; + } + p = lock_user_string(arg2); + if (!access_ok(VERIFY_READ, p, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_openat(arg1, + path(p), + target_to_host_bitmask(arg3, fcntl_flags_tbl), + arg4)); + if (p) + unlock_user(p, arg2, 0); + break; +#endif case TARGET_NR_close: ret = get_errno(close(arg1)); break; -- cgit v1.2.3 From 4472ad0dbd3a0ee26915f259c92e5dddecef060a Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:22:32 +0000 Subject: linux-user mkdirat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3218 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cde0dd324..c40d66d06 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -142,6 +142,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 +#define __NR_sys_mkdirat __NR_mkdirat #define __NR_sys_openat __NR_openat #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo #define __NR_sys_syslog __NR_syslog @@ -167,6 +168,9 @@ _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); #endif _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); +#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) +_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode) +#endif #if defined(TARGET_NR_openat) && defined(__NR_openat) _syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode) #endif @@ -2787,6 +2791,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(mkdir(p, arg2)); unlock_user(p, arg1, 0); break; +#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) + case TARGET_NR_mkdirat: + if (!arg2) { + ret = -EFAULT; + goto fail; + } + p = lock_user_string(arg2); + if (!access_ok(VERIFY_READ, p, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_mkdirat(arg1, p, arg3)); + if (p) + unlock_user(p, arg2, 0); + break; +#endif case TARGET_NR_rmdir: p = lock_user_string(arg1); ret = get_errno(rmdir(p)); -- cgit v1.2.3 From 75ac37a09b585cf3e6e3dd45575b1d8e693dddc5 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:23:05 +0000 Subject: linux-user mknodat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3219 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c40d66d06..aa3fb1972 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -143,6 +143,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 #define __NR_sys_mkdirat __NR_mkdirat +#define __NR_sys_mknodat __NR_mknodat #define __NR_sys_openat __NR_openat #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo #define __NR_sys_syslog __NR_syslog @@ -171,6 +172,10 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, #if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) _syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode) #endif +#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) +_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname, + mode_t,mode,dev_t,dev) +#endif #if defined(TARGET_NR_openat) && defined(__NR_openat) _syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode) #endif @@ -2643,6 +2648,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(mknod(p, arg2, arg3)); unlock_user(p, arg1, 0); break; +#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) + case TARGET_NR_mknodat: + if (!arg2) { + ret = -EFAULT; + goto fail; + } + p = lock_user_string(arg2); + if (!access_ok(VERIFY_READ, p, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); + if (p) + unlock_user(p, arg2, 0); + break; +#endif case TARGET_NR_chmod: p = lock_user_string(arg1); ret = get_errno(chmod(p, arg2)); -- cgit v1.2.3 From ccfa72b7dae809973f67dfd3d50795a311ecd7b7 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:23:34 +0000 Subject: linux-user fchownat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3220 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index aa3fb1972..07efda300 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -139,6 +139,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_uname __NR_uname +#define __NR_sys_fchownat __NR_fchownat #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 @@ -162,6 +163,10 @@ static int gettid(void) { } #endif _syscall1(int,sys_uname,struct new_utsname *,buf) +#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) +_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname, + uid_t,owner,gid_t,group,int,flags) +#endif _syscall2(int,sys_getcwd1,char *,buf,size_t,size) _syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) @@ -4293,6 +4298,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_fchown: ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3))); break; +#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) + case TARGET_NR_fchownat: + if (!arg2) { + ret = -EFAULT; + goto fail; + } + p = lock_user_string(arg2); + if (!access_ok(VERIFY_READ, p, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); + if (p) + unlock_user(p, arg2, 0); + break; +#endif #ifdef TARGET_NR_setresuid case TARGET_NR_setresuid: ret = get_errno(setresuid(low2highuid(arg1), -- cgit v1.2.3 From 8170f56baf6b146653246b8cbf7298fd228cbc75 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:24:11 +0000 Subject: linux-user unlinkat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3221 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 07efda300..9880549ec 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -150,6 +150,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_syslog __NR_syslog #define __NR_sys_tgkill __NR_tgkill #define __NR_sys_tkill __NR_tkill +#define __NR_sys_unlinkat __NR_unlinkat #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek @@ -198,6 +199,9 @@ _syscall1(int,exit_group,int,error_code) #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) _syscall1(int,set_tid_address,int *,tidptr) #endif +#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) +_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags) +#endif extern int personality(int); extern int flock(int, int); @@ -2577,6 +2581,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(unlink(p)); unlock_user(p, arg1, 0); break; +#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) + case TARGET_NR_unlinkat: + if (!arg2) { + ret = -EFAULT; + goto fail; + } + p = lock_user_string(arg2); + if (!access_ok(VERIFY_READ, p, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_unlinkat(arg1, p, arg3)); + if (p) + unlock_user(p, arg2, 0); + break; +#endif case TARGET_NR_execve: { char **argp, **envp; -- cgit v1.2.3 From 722183f69b1dc6c1c9f5f5c250622ca5a71cdb3e Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:24:37 +0000 Subject: linux-user renameat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3222 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9880549ec..eb5a39adc 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -146,6 +146,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_mkdirat __NR_mkdirat #define __NR_sys_mknodat __NR_mknodat #define __NR_sys_openat __NR_openat +#define __NR_sys_renameat __NR_renameat #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo #define __NR_sys_syslog __NR_syslog #define __NR_sys_tgkill __NR_tgkill @@ -185,6 +186,10 @@ _syscall4(int,sys_mknodat,int,dirfd,const char *,pathname, #if defined(TARGET_NR_openat) && defined(__NR_openat) _syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode) #endif +#if defined(TARGET_NR_renameat) && defined(__NR_renameat) +_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath, + int,newdirfd,const char *,newpath) +#endif _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) @@ -2830,6 +2835,28 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(p, arg1, 0); } break; +#if defined(TARGET_NR_renameat) && defined(__NR_renameat) + case TARGET_NR_renameat: + if (!arg2 || !arg4) { + ret = -EFAULT; + goto fail; + } + { + void *p2 = NULL; + p = lock_user_string(arg2); + p2 = lock_user_string(arg4); + if (!access_ok(VERIFY_READ, p, 1) + || !access_ok(VERIFY_READ, p2, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_renameat(arg1, p, arg3, p2)); + if (p2) + unlock_user(p2, arg4, 0); + if (p) + unlock_user(p, arg2, 0); + } + break; +#endif case TARGET_NR_mkdir: p = lock_user_string(arg1); ret = get_errno(mkdir(p, arg2)); -- cgit v1.2.3 From 64f0ce4c0d2c45ff69bfc09092649ee3674f6592 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:25:06 +0000 Subject: linux-user linkat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3223 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index eb5a39adc..427c094f6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -143,6 +143,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 +#define __NR_sys_linkat __NR_linkat #define __NR_sys_mkdirat __NR_mkdirat #define __NR_sys_mknodat __NR_mknodat #define __NR_sys_openat __NR_openat @@ -176,6 +177,10 @@ _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); #endif _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); +#if defined(TARGET_NR_linkat) && defined(__NR_linkat) +_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath, + int,newdirfd,const char *,newpath,int,flags) +#endif #if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) _syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode) #endif @@ -2581,6 +2586,28 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(p, arg1, 0); } break; +#if defined(TARGET_NR_linkat) && defined(__NR_linkat) + case TARGET_NR_linkat: + if (!arg2 || !arg4) { + ret = -EFAULT; + goto fail; + } + { + void * p2 = NULL; + p = lock_user_string(arg2); + p2 = lock_user_string(arg4); + if (!access_ok(VERIFY_READ, p, 1) + || !access_ok(VERIFY_READ, p2, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5)); + if (p2) + unlock_user(p, arg2, 0); + if (p) + unlock_user(p2, arg4, 0); + } + break; +#endif case TARGET_NR_unlink: p = lock_user_string(arg1); ret = get_errno(unlink(p)); -- cgit v1.2.3 From f0b6243d5d7c18efbfcc7e477ffb9b8f523e2fef Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:25:40 +0000 Subject: linux-user symlinkat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3224 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 427c094f6..c7e5edf01 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -149,6 +149,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_openat __NR_openat #define __NR_sys_renameat __NR_renameat #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo +#define __NR_sys_symlinkat __NR_symlinkat #define __NR_sys_syslog __NR_syslog #define __NR_sys_tgkill __NR_tgkill #define __NR_sys_tkill __NR_tkill @@ -196,6 +197,10 @@ _syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath, int,newdirfd,const char *,newpath) #endif _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) +#ifdef TARGET_NR_symlinkat +_syscall3(int,sys_symlinkat,const char *,oldpath, + int,newdirfd,const char *,newpath) +#endif _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) @@ -3361,6 +3366,28 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(p, arg1, 0); } break; +#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) + case TARGET_NR_symlinkat: + if (!arg1 || !arg3) { + ret = -EFAULT; + goto fail; + } + { + void *p2 = NULL; + p = lock_user_string(arg1); + p2 = lock_user_string(arg3); + if (!access_ok(VERIFY_READ, p, 1) + || !access_ok(VERIFY_READ, p2, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_symlinkat(p, arg2, p2)); + if (p2) + unlock_user(p2, arg3, 0); + if (p) + unlock_user(p, arg1, 0); + } + break; +#endif #ifdef TARGET_NR_oldlstat case TARGET_NR_oldlstat: goto unimplemented; -- cgit v1.2.3 From 5e0ccb18da28cc9fdac725ef41a7c174125b56ac Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:26:10 +0000 Subject: linux-user readlinkat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3225 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c7e5edf01..639191f8a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -147,6 +147,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_mkdirat __NR_mkdirat #define __NR_sys_mknodat __NR_mknodat #define __NR_sys_openat __NR_openat +#define __NR_sys_readlinkat __NR_readlinkat #define __NR_sys_renameat __NR_renameat #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo #define __NR_sys_symlinkat __NR_symlinkat @@ -192,6 +193,10 @@ _syscall4(int,sys_mknodat,int,dirfd,const char *,pathname, #if defined(TARGET_NR_openat) && defined(__NR_openat) _syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode) #endif +#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) +_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname, + char *,buf,size_t,bufsize) +#endif #if defined(TARGET_NR_renameat) && defined(__NR_renameat) _syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath, int,newdirfd,const char *,newpath) @@ -3402,6 +3407,28 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, unlock_user(p, arg1, 0); } break; +#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) + case TARGET_NR_readlinkat: + if (!arg2 || !arg3) { + ret = -EFAULT; + goto fail; + } + { + void *p2 = NULL; + p = lock_user_string(arg2); + p2 = lock_user(arg3, arg4, 0); + if (!access_ok(VERIFY_READ, p, 1) + || !access_ok(VERIFY_READ, p2, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4)); + if (p2) + unlock_user(p2, arg3, ret); + if (p) + unlock_user(p, arg2, 0); + } + break; +#endif #ifdef TARGET_NR_uselib case TARGET_NR_uselib: goto unimplemented; -- cgit v1.2.3 From 814d79771f67aa66e73d886bd6aaa553892558a8 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:26:51 +0000 Subject: linux-user fchmodat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3226 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 639191f8a..120b55b12 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -139,6 +139,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_uname __NR_uname +#define __NR_sys_fchmodat __NR_fchmodat #define __NR_sys_fchownat __NR_fchownat #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents @@ -168,6 +169,10 @@ static int gettid(void) { } #endif _syscall1(int,sys_uname,struct new_utsname *,buf) +#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) +_syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname, + mode_t,mode,int,flags) +#endif #if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) _syscall5(int,sys_fchownat,int,dirfd,const char *,pathname, uid_t,owner,gid_t,group,int,flags) @@ -3533,6 +3538,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_fchmod: ret = get_errno(fchmod(arg1, arg2)); break; +#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) + case TARGET_NR_fchmodat: + if (!arg2) { + ret = -EFAULT; + goto fail; + } + p = lock_user_string(arg2); + if (!access_ok(VERIFY_READ, p, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); + if (p) + unlock_user(p, arg2, 0); + break; +#endif case TARGET_NR_getpriority: ret = get_errno(getpriority(arg1, arg2)); break; -- cgit v1.2.3 From 92a34c10b595ae01ff55c385b9867363ac91e0eb Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 09:27:49 +0000 Subject: linux-user faccessat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3227 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 120b55b12..05f8596bc 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -139,6 +139,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_uname __NR_uname +#define __NR_sys_faccessat __NR_faccessat #define __NR_sys_fchmodat __NR_fchmodat #define __NR_sys_fchownat __NR_fchownat #define __NR_sys_getcwd1 __NR_getcwd @@ -169,6 +170,9 @@ static int gettid(void) { } #endif _syscall1(int,sys_uname,struct new_utsname *,buf) +#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) +_syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags) +#endif #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) _syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode,int,flags) @@ -2851,6 +2855,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, ret = get_errno(access(p, arg2)); unlock_user(p, arg1, 0); break; +#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) + case TARGET_NR_faccessat: + if (!arg2) { + ret = -EFAULT; + goto fail; + } + p = lock_user_string(arg2); + if (!access_ok(VERIFY_READ, p, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); + if (p) + unlock_user(p, arg2, 0); + break; +#endif #ifdef TARGET_NR_nice /* not on alpha */ case TARGET_NR_nice: ret = get_errno(nice(arg1)); -- cgit v1.2.3 From e189e7486867e36c35f99cbac27d503ce4e7c71d Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 24 Sep 2007 12:48:00 +0000 Subject: Per-CPU instruction decoding implementation, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3228 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 1 + target-mips/helper.c | 9 +- target-mips/mips-defs.h | 35 ++++++ target-mips/op.c | 17 ++- target-mips/translate.c | 257 ++++++++++++++++++++++++++++--------------- target-mips/translate_init.c | 14 ++- 6 files changed, 230 insertions(+), 103 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f8b4b1858..f8299ad60 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -441,6 +441,7 @@ struct CPUMIPSState { int CCRes; /* Cycle count resolution/divisor */ uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */ uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */ + int insn_flags; /* Supported instruction set */ #ifdef CONFIG_USER_ONLY target_ulong tls_value; diff --git a/target-mips/helper.c b/target-mips/helper.c index 6310d6848..d0e5b1d48 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -369,8 +369,7 @@ void do_interrupt (CPUState *env) } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; - if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) - env->hflags |= MIPS_HFLAG_64; + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) @@ -396,8 +395,7 @@ void do_interrupt (CPUState *env) env->CP0_ErrorEPC = env->PC[env->current_tc]; } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) - env->hflags |= MIPS_HFLAG_64; + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -499,8 +497,7 @@ void do_interrupt (CPUState *env) env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); - if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) - env->hflags |= MIPS_HFLAG_64; + env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; } env->hflags &= ~MIPS_HFLAG_BMASK; diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 6f012a964..a796c7e09 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -14,6 +14,41 @@ #define TARGET_LONG_BITS 32 #endif +/* Masks used to mark instructions to indicate which ISA level they + were introduced in. */ +#define ISA_MIPS1 0x00000001 +#define ISA_MIPS2 0x00000002 +#define ISA_MIPS3 0x00000004 +#define ISA_MIPS4 0x00000008 +#define ISA_MIPS5 0x00000010 +#define ISA_MIPS32 0x00000020 +#define ISA_MIPS32R2 0x00000040 +#define ISA_MIPS64 0x00000080 +#define ISA_MIPS64R2 0x00000100 + +/* MIPS ASE */ +#define ASE_MIPS16 0x00001000 +#define ASE_MIPS3D 0x00002000 +#define ASE_MDMX 0x00004000 +#define ASE_DSP 0x00008000 +#define ASE_DSPR2 0x00010000 + +/* Chip specific instructions. */ +/* Currently void */ + +/* MIPS CPU defines. */ +#define CPU_MIPS1 (ISA_MIPS1) +#define CPU_MIPS2 (CPU_MIPS1 | ISA_MIPS2) +#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3) +#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4) +#define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5) + +#define CPU_MIPS32 (CPU_MIPS2 | ISA_MIPS32) +#define CPU_MIPS64 (CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64) + +#define CPU_MIPS32R2 (CPU_MIPS32 | ISA_MIPS32R2) +#define CPU_MIPS64R2 (CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2) + /* Strictly follow the architecture standard: - Disallow "special" instruction handling for PMON/SPIM. Note that we still maintain Count/Compare to match the host clock. */ diff --git a/target-mips/op.c b/target-mips/op.c index 8d4c7d4af..dd9016337 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1847,10 +1847,9 @@ void op_mtc0_status (void) (val & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; #ifdef TARGET_MIPS64 - if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) || - ((env->hflags & MIPS_HFLAG_UM) && + if ((env->hflags & MIPS_HFLAG_UM) && !(val & (1 << CP0St_PX)) && - !(val & (1 << CP0St_UX)))) + !(val & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif if (val & (1 << CP0St_CU1)) @@ -1906,7 +1905,7 @@ void op_mtc0_cause (void) { uint32_t mask = 0x00C00300; - if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) + if (env->insn_flags & ISA_MIPS32R2) mask |= 1 << CP0Ca_DC; env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask); @@ -3014,10 +3013,9 @@ void op_eret (void) (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; #ifdef TARGET_MIPS64 - if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) || - ((env->hflags & MIPS_HFLAG_UM) && + if ((env->hflags & MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_PX)) && - !(env->CP0_Status & (1 << CP0St_UX)))) + !(env->CP0_Status & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif if (loglevel & CPU_LOG_EXEC) @@ -3038,10 +3036,9 @@ void op_deret (void) (env->CP0_Status & (1 << CP0St_UM))) env->hflags |= MIPS_HFLAG_UM; #ifdef TARGET_MIPS64 - if (!(env->CP0_Config0 & (0x3 << CP0C0_AT)) || - ((env->hflags & MIPS_HFLAG_UM) && + if ((env->hflags & MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_PX)) && - !(env->CP0_Status & (1 << CP0St_UX)))) + !(env->CP0_Status & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif if (loglevel & CPU_LOG_EXEC) diff --git a/target-mips/translate.c b/target-mips/translate.c index ddffc0f15..004b2f701 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -142,7 +142,7 @@ enum { OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */ OPC_SRA = 0x03 | OPC_SPECIAL, OPC_SLLV = 0x04 | OPC_SPECIAL, - OPC_SRLV = 0x06 | OPC_SPECIAL, + OPC_SRLV = 0x06 | OPC_SPECIAL, /* also ROTRV */ OPC_SRAV = 0x07 | OPC_SPECIAL, OPC_DSLLV = 0x14 | OPC_SPECIAL, OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */ @@ -761,10 +761,10 @@ void check_cp1_registers(DisasContext *ctx, int regs) } /* This code generates a "reserved instruction" exception if the - CPU is not a MIPS R2 (or higher) CPU. */ -static inline void check_mips_r2(CPUState *env, DisasContext *ctx) + CPU does not support the instruction set corresponding to flags. */ +static inline void check_insn(CPUState *env, DisasContext *ctx, int flags) { - if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) < (1 << CP0C0_AR)) + if (unlikely(!(env->insn_flags & flags))) generate_exception(ctx, EXCP_RI); } @@ -776,6 +776,14 @@ static inline void check_mips_mt(CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); } +/* This code generates a "reserved instruction" exception if 64-bit + instructions are not enabled. */ +static inline void check_mips_64(DisasContext *ctx) +{ + if (!(ctx->hflags & MIPS_HFLAG_64)) + generate_exception(ctx, EXCP_RI); +} + #if defined(CONFIG_USER_ONLY) #define op_ldst(name) gen_op_##name##_raw() #define OP_LD_TABLE(width) @@ -1024,8 +1032,8 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, } /* Arithmetic with immediate operand */ -static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, - int rs, int16_t imm) +static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, + int rt, int rs, int16_t imm) { target_ulong uimm; const char *opn = "imm arith"; @@ -1132,8 +1140,14 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, opn = "srl"; break; case 1: - gen_op_rotr(); - opn = "rotr"; + /* rotr is decoded as srl on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + gen_op_rotr(); + opn = "rotr"; + } else { + gen_op_srl(); + opn = "srl"; + } break; default: MIPS_INVAL("invalid srl flag"); @@ -1157,8 +1171,14 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, opn = "dsrl"; break; case 1: - gen_op_drotr(); - opn = "drotr"; + /* drotr is decoded as dsrl on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + gen_op_drotr(); + opn = "drotr"; + } else { + gen_op_dsrl(); + opn = "dsrl"; + } break; default: MIPS_INVAL("invalid dsrl flag"); @@ -1181,8 +1201,14 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, opn = "dsrl32"; break; case 1: - gen_op_drotr32(); - opn = "drotr32"; + /* drotr32 is decoded as dsrl32 on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + gen_op_drotr32(); + opn = "drotr32"; + } else { + gen_op_dsrl32(); + opn = "dsrl32"; + } break; default: MIPS_INVAL("invalid dsrl32 flag"); @@ -1201,7 +1227,7 @@ static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt, } /* Arithmetic */ -static void gen_arith (DisasContext *ctx, uint32_t opc, +static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { const char *opn = "arith"; @@ -1305,8 +1331,14 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, opn = "srlv"; break; case 1: - gen_op_rotrv(); - opn = "rotrv"; + /* rotrv is decoded as srlv on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + gen_op_rotrv(); + opn = "rotrv"; + } else { + gen_op_srlv(); + opn = "srlv"; + } break; default: MIPS_INVAL("invalid srlv flag"); @@ -1330,8 +1362,14 @@ static void gen_arith (DisasContext *ctx, uint32_t opc, opn = "dsrlv"; break; case 1: - gen_op_drotrv(); - opn = "drotrv"; + /* drotrv is decoded as dsrlv on non-R2 CPUs */ + if (env->insn_flags & ISA_MIPS32R2) { + gen_op_drotrv(); + opn = "drotrv"; + } else { + gen_op_dsrlv(); + opn = "dsrlv"; + } break; default: MIPS_INVAL("invalid dsrlv flag"); @@ -1910,6 +1948,9 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; + if (sel != 0) + check_insn(env, ctx, ISA_MIPS32); + switch (reg) { case 0: switch (sel) { @@ -2057,7 +2098,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "PageMask"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_pagegrain(); rn = "PageGrain"; break; @@ -2072,22 +2113,27 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf0(); rn = "SRSConf0"; break; case 2: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf1(); rn = "SRSConf1"; break; case 3: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf2(); rn = "SRSConf2"; break; case 4: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf3(); rn = "SRSConf3"; break; case 5: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf4(); rn = "SRSConf4"; break; @@ -2098,7 +2144,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_hwrena(); rn = "HWREna"; break; @@ -2155,17 +2201,17 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Status"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_intctl(); rn = "IntCtl"; break; case 2: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsctl(); rn = "SRSCtl"; break; case 3: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsmap(); rn = "SRSMap"; break; @@ -2200,7 +2246,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_ebase(); rn = "EBase"; break; @@ -2274,8 +2320,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) switch (sel) { case 0: #ifdef TARGET_MIPS64 - if (!(ctx->hflags & MIPS_HFLAG_64)) - goto die; + check_insn(env, ctx, ISA_MIPS3); gen_op_mfc0_xcontext(); rn = "XContext"; break; @@ -2471,6 +2516,9 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; + if (sel != 0) + check_insn(env, ctx, ISA_MIPS32); + switch (reg) { case 0: switch (sel) { @@ -2618,7 +2666,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "PageMask"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_pagegrain(); rn = "PageGrain"; break; @@ -2633,22 +2681,27 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf0(); rn = "SRSConf0"; break; case 2: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf1(); rn = "SRSConf1"; break; case 3: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf2(); rn = "SRSConf2"; break; case 4: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf3(); rn = "SRSConf3"; break; case 5: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf4(); rn = "SRSConf4"; break; @@ -2659,7 +2712,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_hwrena(); rn = "HWREna"; break; @@ -2717,21 +2770,21 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Status"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_intctl(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsctl(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsmap(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -2770,7 +2823,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_ebase(); rn = "EBase"; break; @@ -2849,8 +2902,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) switch (sel) { case 0: #ifdef TARGET_MIPS64 - if (!(ctx->hflags & MIPS_HFLAG_64)) - goto die; + check_insn(env, ctx, ISA_MIPS3); gen_op_mtc0_xcontext(); rn = "XContext"; break; @@ -3064,6 +3116,9 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; + if (sel != 0) + check_insn(env, ctx, ISA_MIPS64); + switch (reg) { case 0: switch (sel) { @@ -3211,7 +3266,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "PageMask"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_pagegrain(); rn = "PageGrain"; break; @@ -3226,22 +3281,27 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf0(); rn = "SRSConf0"; break; case 2: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf1(); rn = "SRSConf1"; break; case 3: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf2(); rn = "SRSConf2"; break; case 4: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf3(); rn = "SRSConf3"; break; case 5: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsconf4(); rn = "SRSConf4"; break; @@ -3252,7 +3312,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_hwrena(); rn = "HWREna"; break; @@ -3309,17 +3369,17 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Status"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_intctl(); rn = "IntCtl"; break; case 2: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsctl(); rn = "SRSCtl"; break; case 3: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_srsmap(); rn = "SRSMap"; break; @@ -3354,7 +3414,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mfc0_ebase(); rn = "EBase"; break; @@ -3418,6 +3478,7 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: + check_insn(env, ctx, ISA_MIPS3); gen_op_dmfc0_xcontext(); rn = "XContext"; break; @@ -3612,6 +3673,9 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; + if (sel != 0) + check_insn(env, ctx, ISA_MIPS64); + switch (reg) { case 0: switch (sel) { @@ -3759,7 +3823,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "PageMask"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_pagegrain(); rn = "PageGrain"; break; @@ -3774,22 +3838,27 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Wired"; break; case 1: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf0(); rn = "SRSConf0"; break; case 2: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf1(); rn = "SRSConf1"; break; case 3: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf2(); rn = "SRSConf2"; break; case 4: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf3(); rn = "SRSConf3"; break; case 5: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsconf4(); rn = "SRSConf4"; break; @@ -3800,7 +3869,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 7: switch (sel) { case 0: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_hwrena(); rn = "HWREna"; break; @@ -3858,21 +3927,21 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Status"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_intctl(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsctl(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_srsmap(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -3911,7 +3980,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "PRid"; break; case 1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); gen_op_mtc0_ebase(); rn = "EBase"; break; @@ -3980,6 +4049,7 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: + check_insn(env, ctx, ISA_MIPS3); gen_op_mtc0_xcontext(); rn = "XContext"; break; @@ -4535,8 +4605,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; #ifdef TARGET_MIPS64 case OPC_DMFC0: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); + check_insn(env, ctx, ISA_MIPS3); if (rt == 0) { /* Treat as NOP. */ return; @@ -4546,8 +4615,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int opn = "dmfc0"; break; case OPC_DMTC0: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); + check_insn(env, ctx, ISA_MIPS3); GEN_LOAD_REG_TN(T0, rt); gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; @@ -4597,11 +4665,13 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; case OPC_ERET: opn = "eret"; + check_insn(env, ctx, ISA_MIPS2); gen_op_eret(); ctx->bstate = BS_EXCP; break; case OPC_DERET: opn = "deret"; + check_insn(env, ctx, ISA_MIPS32); if (!(ctx->hflags & MIPS_HFLAG_DM)) { MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); @@ -4612,6 +4682,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; case OPC_WAIT: opn = "wait"; + check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32); /* If we get an exception, we want to restart at next instruction */ ctx->pc += 4; save_cpu_state(ctx, 1); @@ -4629,12 +4700,15 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int } /* CP1 Branches (before delay slot) */ -static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, +static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op, int32_t cc, int32_t offset) { target_ulong btarget; const char *opn = "cp1 cond branch"; + if (cc != 0) + check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); + btarget = ctx->pc + 4 + offset; switch (op) { @@ -5843,14 +5917,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx) switch (op1) { case OPC_SLL: /* Arithmetic with immediate */ case OPC_SRL ... OPC_SRA: - gen_arith_imm(ctx, op1, rd, rt, sa); + gen_arith_imm(env, ctx, op1, rd, rt, sa); break; + case OPC_MOVZ ... OPC_MOVN: + check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); case OPC_SLLV: /* Arithmetic */ case OPC_SRLV ... OPC_SRAV: - case OPC_MOVZ ... OPC_MOVN: case OPC_ADD ... OPC_NOR: case OPC_SLT ... OPC_SLTU: - gen_arith(ctx, op1, rd, rs, rt); + gen_arith(env, ctx, op1, rd, rs, rt); break; case OPC_MULT ... OPC_DIVU: gen_muldiv(ctx, op1, rs, rt); @@ -5899,6 +5974,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case OPC_MOVCI: + check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); if (env->CP0_Config1 & (1 << CP0C1_FP)) { save_cpu_state(ctx, 1); check_cp1_enabled(ctx); @@ -5915,20 +5991,20 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_DSRL ... OPC_DSRA: case OPC_DSLL32: case OPC_DSRL32 ... OPC_DSRA32: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); - gen_arith_imm(ctx, op1, rd, rt, sa); + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_arith_imm(env, ctx, op1, rd, rt, sa); break; case OPC_DSLLV: case OPC_DSRLV ... OPC_DSRAV: case OPC_DADD ... OPC_DSUBU: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); - gen_arith(ctx, op1, rd, rs, rt); + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_arith(env, ctx, op1, rd, rs, rt); break; case OPC_DMULT ... OPC_DDIVU: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); gen_muldiv(ctx, op1, rs, rt); break; #endif @@ -5943,18 +6019,21 @@ static void decode_opc (CPUState *env, DisasContext *ctx) switch (op1) { case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ case OPC_MSUB ... OPC_MSUBU: + check_insn(env, ctx, ISA_MIPS32); gen_muldiv(ctx, op1, rs, rt); break; case OPC_MUL: - gen_arith(ctx, op1, rd, rs, rt); + gen_arith(env, ctx, op1, rd, rs, rt); break; case OPC_CLZ ... OPC_CLO: + check_insn(env, ctx, ISA_MIPS32); gen_cl(ctx, op1, rd, rs); break; case OPC_SDBBP: /* XXX: not clear which exception should be raised * when in debug mode... */ + check_insn(env, ctx, ISA_MIPS32); if (!(ctx->hflags & MIPS_HFLAG_DM)) { generate_exception(ctx, EXCP_DBp); } else { @@ -5964,8 +6043,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; #ifdef TARGET_MIPS64 case OPC_DCLZ ... OPC_DCLO: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); + check_insn(env, ctx, ISA_MIPS64); + check_mips_64(ctx); gen_cl(ctx, op1, rd, rs); break; #endif @@ -5976,14 +6055,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_SPECIAL3: - check_mips_r2(env, ctx); op1 = MASK_SPECIAL3(ctx->opcode); switch (op1) { case OPC_EXT: case OPC_INS: + check_insn(env, ctx, ISA_MIPS32R2); gen_bitops(ctx, op1, rt, rs, sa, rd); break; case OPC_BSHFL: + check_insn(env, ctx, ISA_MIPS32R2); op2 = MASK_BSHFL(ctx->opcode); switch (op2) { case OPC_WSBH: @@ -6006,6 +6086,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) GEN_STORE_TN_REG(rd, T0); break; case OPC_RDHWR: + check_insn(env, ctx, ISA_MIPS32R2); switch (rd) { case 0: save_cpu_state(ctx, 1); @@ -6050,13 +6131,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) #ifdef TARGET_MIPS64 case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); + check_insn(env, ctx, ISA_MIPS64R2); + check_mips_64(ctx); gen_bitops(ctx, op1, rt, rs, sa, rd); break; case OPC_DBSHFL: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); + check_insn(env, ctx, ISA_MIPS64R2); + check_mips_64(ctx); op2 = MASK_DBSHFL(ctx->opcode); switch (op2) { case OPC_DSBH: @@ -6092,7 +6173,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_trap(ctx, op1, rs, -1, imm); break; case OPC_SYNCI: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); /* Treat as NOP. */ break; default: /* Invalid */ @@ -6120,7 +6201,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd); break; case OPC_MFMC0: - check_mips_r2(env, ctx); op2 = MASK_MFMC0(ctx->opcode); switch (op2) { case OPC_DMT: @@ -6140,11 +6220,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_op_evpe(); break; case OPC_DI: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_di(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; break; case OPC_EI: + check_insn(env, ctx, ISA_MIPS32R2); gen_op_ei(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -6157,12 +6239,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx) GEN_STORE_TN_REG(rt, T0); break; case OPC_RDPGPR: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); GEN_LOAD_SRSREG_TN(T0, rt); GEN_STORE_TN_REG(rd, T0); break; case OPC_WRPGPR: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); GEN_LOAD_REG_TN(T0, rt); GEN_STORE_TN_SRSREG(rd, T0); break; @@ -6173,7 +6255,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */ - gen_arith_imm(ctx, op, rt, rs, imm); + gen_arith_imm(env, ctx, op, rt, rs, imm); break; case OPC_J ... OPC_JAL: /* Jump */ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; @@ -6191,9 +6273,11 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_ldst(ctx, op, rt, rs, imm); break; case OPC_CACHE: + check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32); /* Treat as NOP. */ break; case OPC_PREF: + check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); /* Treat as NOP. */ break; @@ -6219,21 +6303,24 @@ static void decode_opc (CPUState *env, DisasContext *ctx) switch (op1) { case OPC_MFHC1: case OPC_MTHC1: - check_mips_r2(env, ctx); + check_insn(env, ctx, ISA_MIPS32R2); case OPC_MFC1: case OPC_CFC1: case OPC_MTC1: case OPC_CTC1: + gen_cp1(ctx, op1, rt, rd); + break; #ifdef TARGET_MIPS64 case OPC_DMFC1: case OPC_DMTC1: -#endif + check_insn(env, ctx, ISA_MIPS3); gen_cp1(ctx, op1, rt, rd); break; +#endif case OPC_BC1: case OPC_BC1ANY2: case OPC_BC1ANY4: - gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), + gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); return; case OPC_S_FMT: @@ -6315,24 +6402,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_LD: case OPC_SCD: case OPC_SD: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); gen_ldst(ctx, op, rt, rs, imm); break; case OPC_DADDI ... OPC_DADDIU: - if (!(ctx->hflags & MIPS_HFLAG_64)) - generate_exception(ctx, EXCP_RI); - gen_arith_imm(ctx, op, rt, rs, imm); + check_insn(env, ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_arith_imm(env, ctx, op, rt, rs, imm); break; #endif -#ifdef MIPS_HAS_MIPS16 case OPC_JALX: + check_insn(env, ctx, ASE_MIPS16); /* MIPS16: Not implemented. */ -#endif -#ifdef MIPS_HAS_MDMX case OPC_MDMX: + check_insn(env, ctx, ASE_MDMX); /* MDMX: Not implemented. */ -#endif default: /* Invalid */ MIPS_INVAL("major opcode"); generate_exception(ctx, EXCP_RI); diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 1a98973da..6bea0c4d1 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -80,6 +80,7 @@ struct mips_def_t { int32_t CP0_SRSConf3; int32_t CP0_SRSConf4_rw_bitmask; int32_t CP0_SRSConf4; + int insn_flags; }; /*****************************************************************************/ @@ -98,6 +99,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, + .insn_flags = CPU_MIPS32 | ASE_MIPS16, }, { .name = "4KEcR1", @@ -111,6 +113,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, + .insn_flags = CPU_MIPS32 | ASE_MIPS16, }, { .name = "4KEc", @@ -124,6 +127,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x1278FF17, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16, }, { .name = "24Kc", @@ -138,6 +142,7 @@ static mips_def_t mips_defs[] = .CCRes = 2, /* No DSP implemented. */ .CP0_Status_rw_bitmask = 0x1278FF17, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, }, { .name = "24Kf", @@ -154,6 +159,7 @@ static mips_def_t mips_defs[] = .CP0_Status_rw_bitmask = 0x3678FF17, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, }, { .name = "34Kf", @@ -193,6 +199,7 @@ static mips_def_t mips_defs[] = .CP0_SRSConf4_rw_bitmask = 0x3fffffff, .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) | (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13), + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, }, #ifdef TARGET_MIPS64 { @@ -210,6 +217,7 @@ static mips_def_t mips_defs[] = /* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */ .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV), .SEGBITS = 40, + .insn_flags = CPU_MIPS3, }, { .name = "5Kc", @@ -225,6 +233,7 @@ static mips_def_t mips_defs[] = .CCRes = 2, .CP0_Status_rw_bitmask = 0x32F8FFFF, .SEGBITS = 42, + .insn_flags = CPU_MIPS64, }, { .name = "5Kf", @@ -243,6 +252,7 @@ static mips_def_t mips_defs[] = .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) | (0x81 << FCR0_PRID) | (0x0 << FCR0_REV), .SEGBITS = 42, + .insn_flags = CPU_MIPS64, }, { .name = "20Kc", @@ -264,6 +274,7 @@ static mips_def_t mips_defs[] = (1 << FCR0_D) | (1 << FCR0_S) | (0x82 << FCR0_PRID) | (0x0 << FCR0_REV), .SEGBITS = 40, + .insn_flags = CPU_MIPS64 | ASE_MIPS3D, }, #endif }; @@ -406,7 +417,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask; env->CP0_SRSCtl = def->CP0_SRSCtl; #ifdef TARGET_MIPS64 - if ((env->CP0_Config0 & (0x3 << CP0C0_AT))) + if (def->insn_flags & ISA_MIPS3) { env->hflags |= MIPS_HFLAG_64; env->SEGBITS = def->SEGBITS; @@ -426,6 +437,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_SRSConf3 = def->CP0_SRSConf3; env->CP0_SRSConf4_rw_bitmask = def->CP0_SRSConf4_rw_bitmask; env->CP0_SRSConf4 = def->CP0_SRSConf4; + env->insn_flags = def->insn_flags; #ifndef CONFIG_USER_ONLY mmu_init(env, def); -- cgit v1.2.3 From 7743e588395535f1bc13f4f747069bae43935432 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 24 Sep 2007 18:39:04 +0000 Subject: Fix >4G physical memory dump for Sparc32 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3229 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/monitor.c b/monitor.c index 6e0c7ba53..867117360 100644 --- a/monitor.c +++ b/monitor.c @@ -506,7 +506,7 @@ static void term_printc(int c) } static void memory_dump(int count, int format, int wsize, - target_ulong addr, int is_physical) + target_phys_addr_t addr, int is_physical) { CPUState *env; int nb_per_line, l, line_size, i, max_digits, len; @@ -569,7 +569,10 @@ static void memory_dump(int count, int format, int wsize, } while (len > 0) { - term_printf(TARGET_FMT_lx ":", addr); + if (is_physical) + term_printf(TARGET_FMT_plx ":", addr); + else + term_printf(TARGET_FMT_lx ":", (target_ulong)addr); l = len; if (l > line_size) l = line_size; @@ -637,18 +640,24 @@ static void do_memory_dump(int count, int format, int size, memory_dump(count, format, size, addr, 0); } +#if TARGET_PHYS_ADDR_BITS > 32 +#define GET_TPHYSADDR(h, l) (((uint64_t)(h) << 32) | (l)) +#else +#define GET_TPHYSADDR(h, l) (l) +#endif + static void do_physical_memory_dump(int count, int format, int size, uint32_t addrh, uint32_t addrl) { - target_long addr = GET_TLONG(addrh, addrl); + target_phys_addr_t addr = GET_TPHYSADDR(addrh, addrl); memory_dump(count, format, size, addr, 1); } static void do_print(int count, int format, int size, unsigned int valh, unsigned int vall) { - target_long val = GET_TLONG(valh, vall); -#if TARGET_LONG_BITS == 32 + target_phys_addr_t val = GET_TPHYSADDR(valh, vall); +#if TARGET_PHYS_ADDR_BITS == 32 switch(format) { case 'o': term_printf("%#o", val); @@ -1752,11 +1761,11 @@ static void next(void) } } -static target_long expr_sum(void); +static target_phys_addr_t expr_sum(void); -static target_long expr_unary(void) +static target_phys_addr_t expr_unary(void) { - target_long n; + target_phys_addr_t n; char *p; int ret; @@ -1794,6 +1803,7 @@ static target_long expr_unary(void) case '$': { char buf[128], *q; + target_long reg; pch++; q = buf; @@ -1808,11 +1818,12 @@ static target_long expr_unary(void) while (isspace(*pch)) pch++; *q = 0; - ret = get_monitor_def(&n, buf); + ret = get_monitor_def(®, buf); if (ret == -1) expr_error("unknown register"); else if (ret == -2) expr_error("no cpu defined"); + n = reg; } break; case '\0': @@ -1820,7 +1831,7 @@ static target_long expr_unary(void) n = 0; break; default: -#if TARGET_LONG_BITS == 64 +#if TARGET_PHYS_ADDR_BITS > 32 n = strtoull(pch, &p, 0); #else n = strtoul(pch, &p, 0); @@ -1837,9 +1848,9 @@ static target_long expr_unary(void) } -static target_long expr_prod(void) +static target_phys_addr_t expr_prod(void) { - target_long val, val2; + target_phys_addr_t val, val2; int op; val = expr_unary(); @@ -1868,9 +1879,9 @@ static target_long expr_prod(void) return val; } -static target_long expr_logic(void) +static target_phys_addr_t expr_logic(void) { - target_long val, val2; + target_phys_addr_t val, val2; int op; val = expr_prod(); @@ -1896,9 +1907,9 @@ static target_long expr_logic(void) return val; } -static target_long expr_sum(void) +static target_phys_addr_t expr_sum(void) { - target_long val, val2; + target_phys_addr_t val, val2; int op; val = expr_logic(); @@ -1916,7 +1927,7 @@ static target_long expr_sum(void) return val; } -static int get_expr(target_long *pval, const char **pp) +static int get_expr(target_phys_addr_t *pval, const char **pp) { pch = *pp; if (setjmp(expr_env)) { @@ -2179,7 +2190,8 @@ static void monitor_handle_command(const char *cmdline) case 'i': case 'l': { - target_long val; + target_phys_addr_t val; + while (isspace(*p)) p++; if (*typestr == '?' || *typestr == '.') { @@ -2219,7 +2231,7 @@ static void monitor_handle_command(const char *cmdline) } else { if ((nb_args + 1) >= MAX_ARGS) goto error_args; -#if TARGET_LONG_BITS == 64 +#if TARGET_PHYS_ADDR_BITS > 32 args[nb_args++] = (void *)(long)((val >> 32) & 0xffffffff); #else args[nb_args++] = (void *)0; -- cgit v1.2.3 From 9437454a8427c1b32de4ab7a426615ea237e59c6 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 24 Sep 2007 18:41:27 +0000 Subject: Fix loading above 4G git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3230 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf_ops.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elf_ops.h b/elf_ops.h index 75cbdedda..fe2ef9ba9 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -145,8 +145,8 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; - elf_word low = 0, high = 0; - elf_word mem_size, addr; + elf_word mem_size; + target_phys_addr_t addr, low = 0, high = 0; uint8_t *data = NULL; if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) -- cgit v1.2.3 From 40ce0a9a8f498dc4c766f55760eea49b3f55069e Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 24 Sep 2007 19:44:09 +0000 Subject: CPU boot mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3231 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 5 +++-- hw/sun4m.c | 9 +++++---- target-sparc/cpu.h | 1 + target-sparc/helper.c | 7 +++++++ target-sparc/op_helper.c | 4 ++-- target-sparc/translate.c | 5 +++-- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 58737b3a4..8d9152040 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -181,8 +181,9 @@ static inline TranslationBlock *tb_find_fast(void) 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) + // FPU enable . MMU Boot . MMU enabled . MMU no-fault . Supervisor + flags = (env->psref << 4) | (((env->mmuregs[0] & MMU_BM) >> 14) << 3) + | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1) | env->psrs; #endif cs_base = env->npc; diff --git a/hw/sun4m.c b/hw/sun4m.c index 4da4138d9..a76c53b28 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -50,7 +50,8 @@ #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 #define PROM_SIZE_MAX (256 * 1024) -#define PROM_ADDR 0xffd00000 +#define PROM_PADDR 0xff0000000ULL +#define PROM_VADDR 0xffd00000 #define PROM_FILENAME "openbios-sparc32" #define MAX_CPUS 16 @@ -425,12 +426,12 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, linux_boot = (kernel_filename != NULL); prom_offset = RAM_size + vram_size; - cpu_register_physical_memory(PROM_ADDR, + cpu_register_physical_memory(PROM_PADDR, (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - ret = load_elf(buf, 0, NULL, NULL, NULL); + ret = load_elf(buf, PROM_PADDR - PROM_VADDR, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -588,7 +589,7 @@ static void ss10_init(int RAM_size, int vga_ram_size, int boot_device, cpu_model = "TI SuperSparc II"; sun4m_common_init(RAM_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, - 1, PROM_ADDR); // XXX prom overlap, actually first 4GB ok + 1, 0xffffffff); // XXX actually first 62GB ok } QEMUMachine ss5_machine = { diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 6f0da43b8..5c8c49ab6 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -145,6 +145,7 @@ /* MMU */ #define MMU_E (1<<0) #define MMU_NF (1<<1) +#define MMU_BM (1<<14) #define PTE_ENTRYTYPE_MASK 3 #define PTE_ACCESS_MASK 0x1c diff --git a/target-sparc/helper.c b/target-sparc/helper.c index b78e5dfb8..af8bc9694 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -110,7 +110,14 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot unsigned long page_offset; virt_addr = address & TARGET_PAGE_MASK; + if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ + // Boot mode: instruction fetches are taken from PROM + if (rw == 2 && (env->mmuregs[0] & MMU_BM)) { + *physical = 0xff0000000ULL | (address & 0x3ffffULL); + *prot = PAGE_READ | PAGE_EXEC; + return 0; + } *physical = address; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return 0; diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 21ae5dec2..eea4a6377 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -337,8 +337,8 @@ void helper_st_asi(int asi, int size) oldreg = env->mmuregs[reg]; switch(reg) { case 0: - env->mmuregs[reg] &= ~(MMU_E | MMU_NF); - env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); + env->mmuregs[reg] &= ~(MMU_E | MMU_NF | MMU_BM); + env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF | MMU_BM); // Mappings generated during no-fault mode or MMU // disabled mode are invalid in normal mode if (oldreg != env->mmuregs[reg]) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d617b91e9..d12a356c6 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3486,8 +3486,9 @@ void cpu_reset(CPUSPARCState *env) env->pstate = PS_PRIV; env->pc = 0x1fff0000000ULL; #else - env->pc = 0xffd00000; + env->pc = 0; env->mmuregs[0] &= ~(MMU_E | MMU_NF); + env->mmuregs[0] |= MMU_BM; #endif env->npc = env->pc + 4; #endif @@ -3584,7 +3585,7 @@ int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def) env->version = def->iu_version; env->fsr = def->fpu_version; #if !defined(TARGET_SPARC64) - env->mmuregs[0] = def->mmu_version; + env->mmuregs[0] |= def->mmu_version; #endif return 0; } -- cgit v1.2.3 From 9ff6755bf9f31a2aebcc1d780e4a2a3fa661cc01 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 25 Sep 2007 01:17:04 +0000 Subject: Move ECC calculation to a more appropriate place. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3232 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- ecc.h | 94 --------------------------------------------------------- hw/ecc.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 12 +++++++- 4 files changed, 102 insertions(+), 96 deletions(-) delete mode 100644 ecc.h create mode 100644 hw/ecc.c diff --git a/Makefile.target b/Makefile.target index bbcd33daa..6c2a4128c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -472,7 +472,7 @@ VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o -VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o +VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o ecc.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) diff --git a/ecc.h b/ecc.h deleted file mode 100644 index e8e39426f..000000000 --- a/ecc.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Calculate Error-correcting Codes. Used by NAND Flash controllers - * (not by NAND chips). - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski - * - * This code is licensed under the GNU GPL v2. - */ - -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, - 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, - 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, - 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, - 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, -}; - -/* Update ECC parity count. */ -static inline uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample) -{ - uint8_t idx = nand_ecc_precalc_table[sample]; - - s->cp ^= idx & 0x3f; - if (idx & 0x40) { - s->lp[0] ^= ~s->count; - s->lp[1] ^= s->count; - } - s->count ++; - - return sample; -} - -/* Reinitialise the counters. */ -static inline void ecc_reset(struct ecc_state_s *s) -{ - s->lp[0] = 0x0000; - s->lp[1] = 0x0000; - s->cp = 0x00; - s->count = 0; -} - -/* Save/restore */ -static inline void ecc_put(QEMUFile *f, struct ecc_state_s *s) -{ - qemu_put_8s(f, &s->cp); - qemu_put_be16s(f, &s->lp[0]); - qemu_put_be16s(f, &s->lp[1]); - qemu_put_be16s(f, &s->count); -} - -static inline void ecc_get(QEMUFile *f, struct ecc_state_s *s) -{ - qemu_get_8s(f, &s->cp); - qemu_get_be16s(f, &s->lp[0]); - qemu_get_be16s(f, &s->lp[1]); - qemu_get_be16s(f, &s->count); -} diff --git a/hw/ecc.c b/hw/ecc.c new file mode 100644 index 000000000..970ede806 --- /dev/null +++ b/hw/ecc.c @@ -0,0 +1,90 @@ +/* + * Calculate Error-correcting Codes. Used by NAND Flash controllers + * (not by NAND chips). + * + * Copyright (c) 2006 Openedhand Ltd. + * Written by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + */ + +#include "vl.h" + +/* + * 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, + 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, + 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, + 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, + 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, +}; + +/* Update ECC parity count. */ +uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample) +{ + uint8_t idx = nand_ecc_precalc_table[sample]; + + s->cp ^= idx & 0x3f; + if (idx & 0x40) { + s->lp[0] ^= ~s->count; + s->lp[1] ^= s->count; + } + s->count ++; + + return sample; +} + +/* Reinitialise the counters. */ +void ecc_reset(struct ecc_state_s *s) +{ + s->lp[0] = 0x0000; + s->lp[1] = 0x0000; + s->cp = 0x00; + s->count = 0; +} + +/* Save/restore */ +void ecc_put(QEMUFile *f, struct ecc_state_s *s) +{ + qemu_put_8s(f, &s->cp); + qemu_put_be16s(f, &s->lp[0]); + qemu_put_be16s(f, &s->lp[1]); + qemu_put_be16s(f, &s->count); +} + +void ecc_get(QEMUFile *f, struct ecc_state_s *s) +{ + qemu_get_8s(f, &s->cp); + qemu_get_be16s(f, &s->lp[0]); + qemu_get_be16s(f, &s->lp[1]); + qemu_get_be16s(f, &s->count); +} diff --git a/vl.h b/vl.h index d7e12ad90..b2dde5dd0 100644 --- a/vl.h +++ b/vl.h @@ -1539,7 +1539,17 @@ uint8_t nand_getio(struct nand_flash_s *s); #define NAND_MFR_HYNIX 0xad #define NAND_MFR_MICRON 0x2c -#include "ecc.h" +/* ecc.c */ +struct ecc_state_s { + uint8_t cp; /* Column parity */ + uint16_t lp[2]; /* Line parity */ + uint16_t count; +}; + +uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample); +void ecc_reset(struct ecc_state_s *s); +void ecc_put(QEMUFile *f, struct ecc_state_s *s); +void ecc_get(QEMUFile *f, struct ecc_state_s *s); /* GPIO */ typedef void (*gpio_handler_t)(int line, int level, void *opaque); -- cgit v1.2.3 From b427c72613ceb9097f68ab69a0bc152c7199615b Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 25 Sep 2007 14:45:23 +0000 Subject: Improve completion in monitor, by Pascal Terjan. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3233 c046a42c-6fe2-441c-8c8c-71466251a162 --- readline.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/readline.c b/readline.c index d424a90a1..de60cfcf5 100644 --- a/readline.c +++ b/readline.c @@ -300,7 +300,7 @@ void add_completion(const char *str) static void term_completion(void) { - int len, i, j, max_width, nb_cols; + int len, i, j, max_width, nb_cols, max_prefix; char *cmdline; nb_completions = 0; @@ -327,11 +327,26 @@ static void term_completion(void) } else { term_printf("\n"); max_width = 0; + max_prefix = 0; for(i = 0; i < nb_completions; i++) { len = strlen(completions[i]); + if (i==0) { + max_prefix = len; + } else { + if (len < max_prefix) + max_prefix = len; + for(j=0; j max_width) max_width = len; } + if (max_prefix > 0) + for(i = completion_index; i < max_prefix; i++) { + term_insert_char(completions[0][i]); + } max_width += 2; if (max_width < 10) max_width = 10; -- cgit v1.2.3 From b570094d9bb19e59618902d825da6d2899b8d295 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 25 Sep 2007 14:47:03 +0000 Subject: vvfat mbr fixes, by Ivan Kalvachev. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3234 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vvfat.c | 95 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/block-vvfat.c b/block-vvfat.c index b2aa52c28..3237c266c 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -242,21 +242,25 @@ typedef struct bootsector_t { uint8_t magic[2]; } __attribute__((packed)) bootsector_t; +typedef struct { + uint8_t head; + uint8_t sector; + uint8_t cylinder; +} mbr_chs_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; + mbr_chs_t start_CHS; + uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */ + mbr_chs_t end_CHS; uint32_t start_sector_long; - uint32_t end_sector_long; + uint32_t length_sector_long; } __attribute__((packed)) partition_t; typedef struct mbr_t { - uint8_t ignored[0x1be]; + uint8_t ignored[0x1b8]; + uint32_t nt_id; + uint8_t ignored2[2]; partition_t partition[4]; uint8_t magic[2]; } __attribute__((packed)) mbr_t; @@ -350,26 +354,57 @@ typedef struct BDRVVVFATState { int downcase_short_names; } BDRVVVFATState; +/* take the sector position spos and convert it to Cylinder/Head/Sector position + * if the position is outside the specified geometry, fill maximum value for CHS + * and return 1 to signal overflow. + */ +static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){ + int head,sector; + sector = spos % (bs->secs); spos/= bs->secs; + head = spos % (bs->heads); spos/= bs->heads; + if(spos >= bs->cyls){ + /* Overflow, + it happens if 32bit sector positions are used, while CHS is only 24bit. + Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */ + chs->head = 0xFF; + chs->sector = 0xFF; + chs->cylinder = 0xFF; + return 1; + } + chs->head = (uint8_t)head; + chs->sector = (uint8_t)( (sector+1) | ((spos>>8)<<6) ); + chs->cylinder = (uint8_t)spos; + return 0; +} 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]); + int lba; memset(s->first_sectors,0,512); + /* Win NT Disk Signature */ + real_mbr->nt_id= cpu_to_le32(0xbe1afdfa); + partition->attributes=0x80; /* bootable */ - partition->start_head=1; - partition->start_sector=1; - partition->start_cylinder=0; + + /* LBA is used when partition is outside the CHS geometry */ + lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1); + lba|= sector2CHS(s->bs, &partition->end_CHS, s->sector_count); + + /*LBA partitions are identified only by start/length_sector_long not by CHS*/ + partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1); + partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1); + /* 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); + /* DOS uses different types when partition is LBA, + probably to prevent older versions from using CHS on them */ + partition->fs_type= s->fat_type==12 ? 0x1: + s->fat_type==16 ? (lba?0xe:0x06): + /*fat_tyoe==32*/ (lba?0xc:0x0b); real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa; } @@ -973,10 +1008,9 @@ DLOG(if (stderr == NULL) { 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; + /* 504MB disk*/ + bs->cyls=1024; bs->heads=16; bs->secs=63; s->current_cluster=0xffffffff; @@ -991,12 +1025,6 @@ DLOG(if (stderr == NULL) { 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; @@ -1005,6 +1033,8 @@ DLOG(if (stderr == NULL) { bs->cyls = 80; bs->heads = 2; bs->secs = 36; } + s->sector_count=bs->cyls*bs->heads*bs->secs; + 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; @@ -1015,6 +1045,12 @@ DLOG(if (stderr == NULL) { s->sector_count=2880; } + if (strstr(dirname, ":rw:")) { + if (enable_write_target(s)) + return -1; + bs->read_only = 0; + } + i = strrchr(dirname, ':') - dirname; assert(i >= 3); if (dirname[i-2] == ':' && isalpha(dirname[i-1])) @@ -1024,11 +1060,12 @@ DLOG(if (stderr == NULL) { 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; + s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count; + if(s->first_sectors_number==0x40) init_mbr(s); -- cgit v1.2.3 From 387a8fe505dd733968a798c9d3b88fbdd5f93056 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 25 Sep 2007 14:49:47 +0000 Subject: Optimise instructions accessing CP0, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3235 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/cpu.h | 19 ++++++++++--------- target-mips/helper.c | 3 +++ target-mips/op.c | 41 ++++++++++++++++++++--------------------- target-mips/translate.c | 20 ++++++++++++++++---- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f8299ad60..569f9325b 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -414,24 +414,25 @@ struct CPUMIPSState { int user_mode_only; /* user mode only simulation */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x007F +#define MIPS_HFLAG_TMASK 0x00FF #define MIPS_HFLAG_MODE 0x0007 /* execution modes */ #define MIPS_HFLAG_UM 0x0001 /* user mode */ #define MIPS_HFLAG_DM 0x0002 /* Debug mode */ #define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */ #define MIPS_HFLAG_64 0x0008 /* 64-bit instructions enabled */ -#define MIPS_HFLAG_FPU 0x0010 /* FPU enabled */ -#define MIPS_HFLAG_F64 0x0020 /* 64-bit FPU enabled */ -#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ +#define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */ +#define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */ +#define MIPS_HFLAG_F64 0x0040 /* 64-bit FPU enabled */ +#define MIPS_HFLAG_RE 0x0080 /* Reversed endianness */ /* If translation is interrupted between the branch instruction and * the delay slot, record what type of branch it is so that we can * resume translation properly. It might be possible to reduce * this from three bits to two. */ -#define MIPS_HFLAG_BMASK 0x0380 -#define MIPS_HFLAG_B 0x0080 /* Unconditional branch */ -#define MIPS_HFLAG_BC 0x0100 /* Conditional branch */ -#define MIPS_HFLAG_BL 0x0180 /* Likely branch */ -#define MIPS_HFLAG_BR 0x0200 /* branch to register (can't link TB) */ +#define MIPS_HFLAG_BMASK 0x0700 +#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */ +#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */ +#define MIPS_HFLAG_BL 0x0300 /* Likely branch */ +#define MIPS_HFLAG_BR 0x0400 /* branch to register (can't link TB) */ target_ulong btarget; /* Jump / branch target */ int bcond; /* Branch condition (if needed) */ diff --git a/target-mips/helper.c b/target-mips/helper.c index d0e5b1d48..5c19a7ca4 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -371,6 +371,7 @@ void do_interrupt (CPUState *env) env->hflags |= MIPS_HFLAG_DM; env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; + env->hflags |= MIPS_HFLAG_CP0; /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -397,6 +398,7 @@ void do_interrupt (CPUState *env) env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; + env->hflags |= MIPS_HFLAG_CP0; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->PC[env->current_tc] = (int32_t)0xBFC00000; @@ -499,6 +501,7 @@ void do_interrupt (CPUState *env) env->CP0_Status |= (1 << CP0St_EXL); env->hflags |= MIPS_HFLAG_64; env->hflags &= ~MIPS_HFLAG_UM; + env->hflags |= MIPS_HFLAG_CP0; } env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { diff --git a/target-mips/op.c b/target-mips/op.c index dd9016337..b3536442e 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1852,6 +1852,10 @@ void op_mtc0_status (void) !(val & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif + if ((val & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) + env->hflags |= MIPS_HFLAG_CP0; + else + env->hflags &= ~MIPS_HFLAG_CP0; if (val & (1 << CP0St_CU1)) env->hflags |= MIPS_HFLAG_FPU; else @@ -2316,15 +2320,6 @@ void op_yield(void) # define DEBUG_FPU_STATE() do { } while(0) #endif -void op_cp0_enabled(void) -{ - if (!(env->CP0_Status & (1 << CP0St_CU0)) && - (env->hflags & MIPS_HFLAG_UM)) { - CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 0); - } - RETURN(); -} - void op_cfc1 (void) { CALL_FROM_TB1(do_cfc1, PARAM1); @@ -3018,6 +3013,10 @@ void op_eret (void) !(env->CP0_Status & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif + if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) + env->hflags |= MIPS_HFLAG_CP0; + else + env->hflags &= ~MIPS_HFLAG_CP0; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; @@ -3041,6 +3040,10 @@ void op_deret (void) !(env->CP0_Status & (1 << CP0St_UX))) env->hflags &= ~MIPS_HFLAG_64; #endif + if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) + env->hflags |= MIPS_HFLAG_CP0; + else + env->hflags &= ~MIPS_HFLAG_CP0; if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; @@ -3049,9 +3052,8 @@ void op_deret (void) void op_rdhwr_cpunum(void) { - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 0)) || - (env->CP0_Status & (1 << CP0St_CU0))) + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 0))) T0 = env->CP0_EBase & 0x3ff; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); @@ -3060,9 +3062,8 @@ void op_rdhwr_cpunum(void) void op_rdhwr_synci_step(void) { - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 1)) || - (env->CP0_Status & (1 << CP0St_CU0))) + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 1))) T0 = env->SYNCI_Step; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); @@ -3071,9 +3072,8 @@ void op_rdhwr_synci_step(void) void op_rdhwr_cc(void) { - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 2)) || - (env->CP0_Status & (1 << CP0St_CU0))) + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 2))) T0 = env->CP0_Count; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); @@ -3082,9 +3082,8 @@ void op_rdhwr_cc(void) void op_rdhwr_ccres(void) { - if (!(env->hflags & MIPS_HFLAG_UM) || - (env->CP0_HWREna & (1 << 3)) || - (env->CP0_Status & (1 << CP0St_CU0))) + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 3))) T0 = env->CCRes; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); diff --git a/target-mips/translate.c b/target-mips/translate.c index 004b2f701..c70480cc7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -731,6 +731,12 @@ static inline void generate_exception (DisasContext *ctx, int excp) generate_exception_err (ctx, excp, 0); } +static inline void check_cp0_enabled(DisasContext *ctx) +{ + if (!(ctx->hflags & MIPS_HFLAG_CP0)) + generate_exception_err(ctx, EXCP_CpU, 1); +} + static inline void check_cp1_enabled(DisasContext *ctx) { if (!(ctx->hflags & MIPS_HFLAG_FPU)) @@ -4600,6 +4606,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; case OPC_MTC0: GEN_LOAD_REG_TN(T0, rt); + save_cpu_state(ctx, 1); gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; break; @@ -4617,6 +4624,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int case OPC_DMTC0: check_insn(env, ctx, ISA_MIPS3); GEN_LOAD_REG_TN(T0, rt); + save_cpu_state(ctx, 1); gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; break; @@ -4666,6 +4674,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int case OPC_ERET: opn = "eret"; check_insn(env, ctx, ISA_MIPS2); + save_cpu_state(ctx, 1); gen_op_eret(); ctx->bstate = BS_EXCP; break; @@ -4676,6 +4685,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); } else { + save_cpu_state(ctx, 1); gen_op_deret(); ctx->bstate = BS_EXCP; } @@ -6183,8 +6193,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_CP0: - save_cpu_state(ctx, 1); - gen_op_cp0_enabled(); + check_cp0_enabled(ctx); op1 = MASK_CP0(ctx->opcode); switch (op1) { case OPC_MFC0: @@ -6221,12 +6230,14 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; case OPC_DI: check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); gen_op_di(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; break; case OPC_EI: check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); gen_op_ei(); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -6747,7 +6758,6 @@ void cpu_reset (CPUMIPSState *env) } else { env->CP0_ErrorEPC = env->PC[env->current_tc]; } - env->hflags = 0; env->PC[env->current_tc] = (int32_t)0xBFC00000; env->CP0_Wired = 0; /* SMP not implemented */ @@ -6771,8 +6781,10 @@ void cpu_reset (CPUMIPSState *env) #endif env->exception_index = EXCP_NONE; #if defined(CONFIG_USER_ONLY) - env->hflags |= MIPS_HFLAG_UM; + env->hflags = MIPS_HFLAG_UM; env->user_mode_only = 1; +#else + env->hflags = MIPS_HFLAG_CP0; #endif } -- cgit v1.2.3 From b51eaa8218f4bd9cfd9a10b7014676035289ef56 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 25 Sep 2007 16:09:22 +0000 Subject: Check if the hosts defines a symlinkat syscall. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3236 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 05f8596bc..645780e85 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -211,7 +211,7 @@ _syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath, int,newdirfd,const char *,newpath) #endif _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) -#ifdef TARGET_NR_symlinkat +#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) _syscall3(int,sys_symlinkat,const char *,oldpath, int,newdirfd,const char *,newpath) #endif -- cgit v1.2.3 From 42532189dfba7a5675225b7b3d6da3d80f8c2447 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 25 Sep 2007 16:53:15 +0000 Subject: Timer start/stop implementation, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3237 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_timer.c | 29 ++++++++++++++++++++++++----- target-mips/exec.h | 2 ++ target-mips/op.c | 13 ++++++++++--- target-mips/op_helper.c | 10 ++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 2fe5e29c5..b295bdbfe 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -17,9 +17,12 @@ uint32_t cpu_mips_get_random (CPUState *env) /* MIPS R4K timer */ uint32_t cpu_mips_get_count (CPUState *env) { - return env->CP0_Count + - (uint32_t)muldiv64(qemu_get_clock(vm_clock), - 100 * 1000 * 1000, ticks_per_sec); + if (env->CP0_Cause & (1 << CP0Ca_DC)) + return env->CP0_Count; + else + return env->CP0_Count + + (uint32_t)muldiv64(qemu_get_clock(vm_clock), + 100 * 1000 * 1000, ticks_per_sec); } void cpu_mips_store_count (CPUState *env, uint32_t count) @@ -63,7 +66,19 @@ void cpu_mips_store_compare (CPUState *env, uint32_t value) cpu_mips_update_count(env, cpu_mips_get_count(env)); if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) env->CP0_Cause &= ~(1 << CP0Ca_TI); - qemu_irq_lower(env->irq[7]); + qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); +} + +void cpu_mips_start_count(CPUState *env) +{ + cpu_mips_store_count(env, env->CP0_Count); +} + +void cpu_mips_stop_count(CPUState *env) +{ + /* Store the current value */ + env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock), + 100 * 1000 * 1000, ticks_per_sec); } static void mips_timer_cb (void *opaque) @@ -76,10 +91,14 @@ static void mips_timer_cb (void *opaque) fprintf(logfile, "%s\n", __func__); } #endif + + if (env->CP0_Cause & (1 << CP0Ca_DC)) + return; + cpu_mips_update_count(env, cpu_mips_get_count(env)); if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) env->CP0_Cause |= 1 << CP0Ca_TI; - qemu_irq_raise(env->irq[7]); + qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); } void cpu_mips_clock_init (CPUState *env) diff --git a/target-mips/exec.h b/target-mips/exec.h index 5b8577eaf..d5aadedb8 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -153,6 +153,8 @@ uint32_t cpu_mips_get_random (CPUState *env); uint32_t cpu_mips_get_count (CPUState *env); void cpu_mips_store_count (CPUState *env, uint32_t value); void cpu_mips_store_compare (CPUState *env, uint32_t value); +void cpu_mips_start_count(CPUState *env); +void cpu_mips_stop_count(CPUState *env); void cpu_mips_update_irq (CPUState *env); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); diff --git a/target-mips/op.c b/target-mips/op.c index b3536442e..b8c5ce8d5 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1886,9 +1886,8 @@ void op_mttc0_status(void) void op_mtc0_intctl (void) { - /* vectored interrupts not implemented, timer on int 7, - no performance counters. */ - env->CP0_IntCtl |= T0 & 0x000002e0; + /* vectored interrupts not implemented, no performance counters. */ + env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (T0 & 0x000002e0); RETURN(); } @@ -1908,12 +1907,20 @@ void op_mtc0_srsmap (void) void op_mtc0_cause (void) { uint32_t mask = 0x00C00300; + uint32_t old = env->CP0_Cause; if (env->insn_flags & ISA_MIPS32R2) mask |= 1 << CP0Ca_DC; env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask); + if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { + if (env->CP0_Cause & (1 << CP0Ca_DC)) + CALL_FROM_TB1(cpu_mips_stop_count, env); + else + CALL_FROM_TB1(cpu_mips_start_count, env); + } + /* Handle the software interrupt as an hardware one, as they are very similar */ if (T0 & CP0Ca_IP_mask) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 6405f8066..6b007a6be 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -265,6 +265,16 @@ void cpu_mips_store_compare(CPUState *env, uint32_t value) cpu_abort(env, "mtc0 compare\n"); } +void cpu_mips_start_count(CPUState *env) +{ + cpu_abort(env, "start count\n"); +} + +void cpu_mips_stop_count(CPUState *env) +{ + cpu_abort(env, "stop count\n"); +} + void cpu_mips_update_irq(CPUState *env) { cpu_abort(env, "mtc0 status / mtc0 cause\n"); -- cgit v1.2.3 From c2efc95d45fd4c76d4650a34a2a2676b87a93ac4 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 25 Sep 2007 17:28:42 +0000 Subject: Fix monitor expressions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3238 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/monitor.c b/monitor.c index 867117360..d1310a49b 100644 --- a/monitor.c +++ b/monitor.c @@ -1761,11 +1761,11 @@ static void next(void) } } -static target_phys_addr_t expr_sum(void); +static int64_t expr_sum(void); -static target_phys_addr_t expr_unary(void) +static int64_t expr_unary(void) { - target_phys_addr_t n; + int64_t n; char *p; int ret; @@ -1848,9 +1848,9 @@ static target_phys_addr_t expr_unary(void) } -static target_phys_addr_t expr_prod(void) +static int64_t expr_prod(void) { - target_phys_addr_t val, val2; + int64_t val, val2; int op; val = expr_unary(); @@ -1879,9 +1879,9 @@ static target_phys_addr_t expr_prod(void) return val; } -static target_phys_addr_t expr_logic(void) +static int64_t expr_logic(void) { - target_phys_addr_t val, val2; + int64_t val, val2; int op; val = expr_prod(); @@ -1907,9 +1907,9 @@ static target_phys_addr_t expr_logic(void) return val; } -static target_phys_addr_t expr_sum(void) +static int64_t expr_sum(void) { - target_phys_addr_t val, val2; + int64_t val, val2; int op; val = expr_logic(); @@ -1927,7 +1927,7 @@ static target_phys_addr_t expr_sum(void) return val; } -static int get_expr(target_phys_addr_t *pval, const char **pp) +static int get_expr(int64_t *pval, const char **pp) { pch = *pp; if (setjmp(expr_env)) { @@ -2190,7 +2190,7 @@ static void monitor_handle_command(const char *cmdline) case 'i': case 'l': { - target_phys_addr_t val; + int64_t val; while (isspace(*p)) p++; -- cgit v1.2.3 From eb296a0a03eebd2d73718d31cd0d8a8db0b804de Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 25 Sep 2007 17:30:09 +0000 Subject: Remove the target dependency introduced by previous patch git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3239 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf_ops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elf_ops.h b/elf_ops.h index fe2ef9ba9..173d12f05 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -146,7 +146,7 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; elf_word mem_size; - target_phys_addr_t addr, low = 0, high = 0; + uint64_t addr, low = 0, high = 0; uint8_t *data = NULL; if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) -- cgit v1.2.3 From 9007f0ef73771c2dd30e3092d6c06c4bc5ebfe0d Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 25 Sep 2007 17:50:37 +0000 Subject: linux-user utimensat() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3240 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 645780e85..bd66f905e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -157,6 +157,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_tgkill __NR_tgkill #define __NR_sys_tkill __NR_tkill #define __NR_sys_unlinkat __NR_unlinkat +#define __NR_sys_utimensat __NR_utimensat #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) #define __NR__llseek __NR_lseek @@ -231,6 +232,10 @@ _syscall1(int,set_tid_address,int *,tidptr) #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags) #endif +#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) +_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, + const struct timespec *,tsp,int,flags) +#endif extern int personality(int); extern int flock(int, int); @@ -4900,6 +4905,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, goto unimplemented_nowarn; #endif +#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) + case TARGET_NR_utimensat: + { + struct timespec ts[2]; + target_to_host_timespec(ts, arg3); + target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec)); + if (!arg2) + ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4)); + else { + p = lock_user_string(arg2); + if (!access_ok(VERIFY_READ, p, 1)) + ret = -EFAULT; + else + ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); + if (p) + unlock_user(p, arg2, 0); + } + } + break; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); -- cgit v1.2.3 From 324071035fd94538bc0f1ab316646cace30814fb Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 26 Sep 2007 23:01:49 +0000 Subject: Convert syscall arguments and return value from long to int or target_long. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3241 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 7 +- linux-user/syscall.c | 184 +++++++++++++++++++++++++++++---------------------- 2 files changed, 108 insertions(+), 83 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 011b41ea7..8c03ad190 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -126,10 +126,11 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, void memcpy_to_target(target_ulong dest, const void *src, unsigned long len); void target_set_brk(target_ulong new_brk); -long do_brk(target_ulong new_brk); +target_long do_brk(target_ulong new_brk); void syscall_init(void); -long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, - long arg4, long arg5, long arg6); +target_long do_syscall(void *cpu_env, int num, target_long arg1, + target_long arg2, target_long arg3, target_long arg4, + target_long arg5, target_long arg6); void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); extern CPUState *global_env; void cpu_loop(CPUState *env); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index bd66f905e..41d58da14 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -366,7 +366,7 @@ static inline int host_to_target_errno(int err) return err; } -static inline long get_errno(long ret) +static inline target_long get_errno(target_long ret) { if (ret == -1) return -host_to_target_errno(errno); @@ -374,9 +374,9 @@ static inline long get_errno(long ret) return ret; } -static inline int is_error(long ret) +static inline int is_error(target_long ret) { - return (unsigned long)ret >= (unsigned long)(-4096); + return (target_ulong)ret >= (target_ulong)(-4096); } static target_ulong target_brk; @@ -387,10 +387,10 @@ void target_set_brk(target_ulong new_brk) target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); } -long do_brk(target_ulong new_brk) +target_long do_brk(target_ulong new_brk) { target_ulong brk_page; - long mapped_addr; + target_long mapped_addr; int new_alloc_size; if (!new_brk) @@ -471,7 +471,7 @@ static inline void host_to_target_fds(target_long *target_fds, #define HOST_HZ 100 #endif -static inline long host_to_target_clock_t(long ticks) +static inline target_long host_to_target_clock_t(long ticks) { #if HOST_HZ == TARGET_HZ return ticks; @@ -530,15 +530,15 @@ static inline void host_to_target_timeval(target_ulong target_addr, } -static long do_select(long n, - target_ulong rfd_p, target_ulong wfd_p, - target_ulong efd_p, target_ulong target_tv) +static target_long do_select(int n, + target_ulong rfd_p, target_ulong wfd_p, + target_ulong efd_p, target_ulong target_tv) { fd_set rfds, wfds, efds; fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; target_long *target_rfds, *target_wfds, *target_efds; struct timeval tv, *tv_ptr; - long ret; + target_long ret; int ok; if (rfd_p) { @@ -704,10 +704,11 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, msgh->msg_controllen = tswapl(space); } -static long do_setsockopt(int sockfd, int level, int optname, - target_ulong optval, socklen_t optlen) +static target_long do_setsockopt(int sockfd, int level, int optname, + target_ulong optval, socklen_t optlen) { - int val, ret; + target_long ret; + int val; switch(level) { case SOL_TCP: @@ -824,10 +825,11 @@ static long do_setsockopt(int sockfd, int level, int optname, return ret; } -static long do_getsockopt(int sockfd, int level, int optname, - target_ulong optval, target_ulong optlen) +static target_long do_getsockopt(int sockfd, int level, int optname, + target_ulong optval, target_ulong optlen) { - int len, lv, val, ret; + target_long ret; + int len, lv, val; switch(level) { case TARGET_SOL_SOCKET: @@ -943,7 +945,7 @@ static void unlock_iovec(struct iovec *vec, target_ulong target_addr, unlock_user (target_vec, target_addr, 0); } -static long do_socket(int domain, int type, int protocol) +static target_long do_socket(int domain, int type, int protocol) { #if defined(TARGET_MIPS) switch(type) { @@ -970,8 +972,8 @@ static long do_socket(int domain, int type, int protocol) return get_errno(socket(domain, type, protocol)); } -static long do_bind(int sockfd, target_ulong target_addr, - socklen_t addrlen) +static target_long do_bind(int sockfd, target_ulong target_addr, + socklen_t addrlen) { void *addr = alloca(addrlen); @@ -979,8 +981,8 @@ static long do_bind(int sockfd, target_ulong target_addr, return get_errno(bind(sockfd, addr, addrlen)); } -static long do_connect(int sockfd, target_ulong target_addr, - socklen_t addrlen) +static target_long do_connect(int sockfd, target_ulong target_addr, + socklen_t addrlen) { void *addr = alloca(addrlen); @@ -988,10 +990,10 @@ static long do_connect(int sockfd, target_ulong target_addr, return get_errno(connect(sockfd, addr, addrlen)); } -static long do_sendrecvmsg(int fd, target_ulong target_msg, - int flags, int send) +static target_long do_sendrecvmsg(int fd, target_ulong target_msg, + int flags, int send) { - long ret; + target_long ret; struct target_msghdr *msgp; struct msghdr msg; int count; @@ -1031,12 +1033,12 @@ static long do_sendrecvmsg(int fd, target_ulong target_msg, return ret; } -static long do_accept(int fd, target_ulong target_addr, - target_ulong target_addrlen) +static target_long do_accept(int fd, target_ulong target_addr, + target_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); - long ret; + target_long ret; ret = get_errno(accept(fd, addr, &addrlen)); if (!is_error(ret)) { @@ -1046,12 +1048,12 @@ static long do_accept(int fd, target_ulong target_addr, return ret; } -static long do_getpeername(int fd, target_ulong target_addr, - target_ulong target_addrlen) +static target_long do_getpeername(int fd, target_ulong target_addr, + target_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); - long ret; + target_long ret; ret = get_errno(getpeername(fd, addr, &addrlen)); if (!is_error(ret)) { @@ -1061,12 +1063,12 @@ static long do_getpeername(int fd, target_ulong target_addr, return ret; } -static long do_getsockname(int fd, target_ulong target_addr, - target_ulong target_addrlen) +static target_long do_getsockname(int fd, target_ulong target_addr, + target_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); - long ret; + target_long ret; ret = get_errno(getsockname(fd, addr, &addrlen)); if (!is_error(ret)) { @@ -1076,11 +1078,11 @@ static long do_getsockname(int fd, target_ulong target_addr, return ret; } -static long do_socketpair(int domain, int type, int protocol, - target_ulong target_tab) +static target_long do_socketpair(int domain, int type, int protocol, + target_ulong target_tab) { int tab[2]; - long ret; + target_long ret; ret = get_errno(socketpair(domain, type, protocol, tab)); if (!is_error(ret)) { @@ -1090,12 +1092,12 @@ static long do_socketpair(int domain, int type, int protocol, return ret; } -static long do_sendto(int fd, target_ulong msg, size_t len, int flags, - target_ulong target_addr, socklen_t addrlen) +static target_long do_sendto(int fd, target_ulong msg, size_t len, int flags, + target_ulong target_addr, socklen_t addrlen) { void *addr; void *host_msg; - long ret; + target_long ret; host_msg = lock_user(msg, len, 1); if (target_addr) { @@ -1109,13 +1111,14 @@ static long do_sendto(int fd, target_ulong msg, size_t len, int flags, return ret; } -static long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, - target_ulong target_addr, target_ulong target_addrlen) +static target_long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, + target_ulong target_addr, + target_ulong target_addrlen) { socklen_t addrlen; void *addr; void *host_msg; - long ret; + target_long ret; host_msg = lock_user(msg, len, 0); if (target_addr) { @@ -1138,9 +1141,10 @@ static long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, return ret; } -static long do_socketcall(int num, target_ulong vptr) +#ifdef TARGET_NR_socketcall +static target_long do_socketcall(int num, target_ulong vptr) { - long ret; + target_long ret; const int n = sizeof(target_ulong); switch(num) { @@ -1300,7 +1304,9 @@ static long do_socketcall(int num, target_ulong vptr) } return ret; } +#endif +#ifdef TARGET_NR_ipc #define N_SHM_REGIONS 32 static struct shm_region { @@ -1407,7 +1413,7 @@ union target_semun { unsigned short int *array; }; -static inline void target_to_host_semun(unsigned long cmd, +static inline void target_to_host_semun(int cmd, union semun *host_su, target_ulong target_addr, struct semid_ds *ds) @@ -1439,7 +1445,7 @@ static inline void target_to_host_semun(unsigned long cmd, } } -static inline void host_to_target_semun(unsigned long cmd, +static inline void host_to_target_semun(int cmd, target_ulong target_addr, union semun *host_su, struct semid_ds *ds) @@ -1470,12 +1476,13 @@ static inline void host_to_target_semun(unsigned long cmd, } } -static inline long do_semctl(long first, long second, long third, long ptr) +static inline target_long do_semctl(int first, int second, int third, + target_long ptr) { union semun arg; struct semid_ds dsarg; int cmd = third&0xff; - long ret = 0; + target_long ret = 0; switch( cmd ) { case GETVAL: @@ -1534,7 +1541,7 @@ struct target_msqid_ds }; static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, - target_ulong target_addr) + target_ulong target_addr) { struct target_msqid_ds *target_md; @@ -1569,11 +1576,11 @@ static inline void host_to_target_msqid_ds(target_ulong target_addr, unlock_user_struct(target_md, target_addr, 1); } -static inline long do_msgctl(long first, long second, long ptr) +static inline target_long do_msgctl(int first, int second, target_long ptr) { struct msqid_ds dsarg; int cmd = second&0xff; - long ret = 0; + target_long ret = 0; switch( cmd ) { case IPC_STAT: case IPC_SET: @@ -1591,11 +1598,12 @@ struct target_msgbuf { char mtext[1]; }; -static inline long do_msgsnd(long msqid, long msgp, long msgsz, long msgflg) +static inline target_long do_msgsnd(int msqid, target_long msgp, + unsigned int msgsz, int msgflg) { struct target_msgbuf *target_mb; struct msgbuf *host_mb; - long ret = 0; + target_long ret = 0; lock_user_struct(target_mb,msgp,0); host_mb = malloc(msgsz+sizeof(long)); @@ -1608,11 +1616,13 @@ static inline long do_msgsnd(long msqid, long msgp, long msgsz, long msgflg) return ret; } -static inline long do_msgrcv(long msqid, long msgp, long msgsz, long msgtype, long msgflg) +static inline target_long do_msgrcv(int msqid, target_long msgp, + unsigned int msgsz, int msgtype, + int msgflg) { struct target_msgbuf *target_mb; struct msgbuf *host_mb; - long ret = 0; + target_long ret = 0; lock_user_struct(target_mb, msgp, 0); host_mb = malloc(msgsz+sizeof(long)); @@ -1627,11 +1637,12 @@ static inline long do_msgrcv(long msqid, long msgp, long msgsz, long msgtype, lo } /* ??? This only works with linear mappings. */ -static long do_ipc(long call, long first, long second, long third, - long ptr, long fifth) +static target_long do_ipc(unsigned int call, int first, + int second, int third, + target_long ptr, target_long fifth) { int version; - long ret = 0; + target_long ret = 0; unsigned long raddr; struct shmid_ds shm_info; int i; @@ -1653,7 +1664,7 @@ static long do_ipc(long call, long first, long second, long third, break; case IPCOP_semtimedop: - gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version); + gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); ret = -ENOSYS; break; @@ -1709,7 +1720,7 @@ static long do_ipc(long call, long first, long second, long third, break; } } - if (put_user(raddr, (uint32_t *)third)) + if (put_user(raddr, (target_ulong *)third)) return -EFAULT; ret = 0; break; @@ -1743,12 +1754,13 @@ static long do_ipc(long call, long first, long second, long third, break; default: unimplemented: - gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version); + gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); ret = -ENOSYS; break; } return ret; } +#endif /* kernel structure types definitions */ #define IFNAMSIZ 16 @@ -1789,11 +1801,11 @@ IOCTLEntry ioctl_entries[] = { }; /* ??? Implement proper locking for ioctls. */ -static long do_ioctl(long fd, long cmd, long arg) +static target_long do_ioctl(int fd, target_long cmd, target_long arg) { const IOCTLEntry *ie; const argtype *arg_type; - long ret; + target_long ret; uint8_t buf_temp[MAX_STRUCT_SIZE]; int target_size; void *argptr; @@ -1801,7 +1813,7 @@ static long do_ioctl(long fd, long cmd, long arg) ie = ioctl_entries; for(;;) { if (ie->target_cmd == 0) { - gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd); + gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd); return -ENOSYS; } if (ie->target_cmd == cmd) @@ -1810,7 +1822,7 @@ static long do_ioctl(long fd, long cmd, long arg) } arg_type = ie->arg_type; #if defined(DEBUG) - gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); + gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name); #endif switch(arg_type[0]) { case TYPE_NULL: @@ -1855,7 +1867,8 @@ static long do_ioctl(long fd, long cmd, long arg) } break; default: - gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]); + gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", + (long)cmd, arg_type[0]); ret = -ENOSYS; break; } @@ -2205,7 +2218,7 @@ static int clone_func(void *arg) return 0; } -int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) +int do_fork(CPUState *env, unsigned int flags, target_ulong newsp) { int ret; TaskState *ts; @@ -2291,13 +2304,13 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) return ret; } -static long do_fcntl(int fd, int cmd, target_ulong arg) +static target_long do_fcntl(int fd, int cmd, target_ulong arg) { struct flock fl; struct target_flock *target_fl; struct flock64 fl64; struct target_flock64 *target_fl64; - long ret; + target_long ret; switch(cmd) { case TARGET_F_GETLK: @@ -2456,6 +2469,7 @@ void syscall_init(void) } } +#if TARGET_LONG_BITS == 32 static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) { #ifdef TARGET_WORDS_BIG_ENDIAN @@ -2464,10 +2478,18 @@ static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) return ((uint64_t)word1 << 32) | word0; #endif } +#else /* TARGET_LONG_BITS == 32 */ +static inline uint64_t target_offset64(uint64_t word0, uint64_t word1) +{ + return word0; +} +#endif /* TARGET_LONG_BITS != 32 */ #ifdef TARGET_NR_truncate64 -static inline long target_truncate64(void *cpu_env, const char *arg1, - long arg2, long arg3, long arg4) +static inline target_long target_truncate64(void *cpu_env, const char *arg1, + target_long arg2, + target_long arg3, + target_long arg4) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) @@ -2481,8 +2503,10 @@ static inline long target_truncate64(void *cpu_env, const char *arg1, #endif #ifdef TARGET_NR_ftruncate64 -static inline long target_ftruncate64(void *cpu_env, long arg1, long arg2, - long arg3, long arg4) +static inline target_long target_ftruncate64(void *cpu_env, target_long arg1, + target_long arg2, + target_long arg3, + target_long arg4) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) @@ -2517,10 +2541,11 @@ static inline void host_to_target_timespec(target_ulong target_addr, unlock_user_struct(target_ts, target_addr, 1); } -long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, - long arg4, long arg5, long arg6) +target_long do_syscall(void *cpu_env, int num, target_long arg1, + target_long arg2, target_long arg3, target_long arg4, + target_long arg5, target_long arg6) { - long ret; + target_long ret; struct stat st; struct statfs stfs; void *p; @@ -4018,7 +4043,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, { struct target_dirent *target_dirp; struct dirent *dirp; - long count = arg3; + target_long count = arg3; dirp = malloc(count); if (!dirp) @@ -4060,7 +4085,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #else { struct dirent *dirp; - long count = arg3; + target_long count = arg3; dirp = lock_user(arg2, count, 0); ret = get_errno(sys_getdents(arg1, dirp, count)); @@ -4088,7 +4113,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, case TARGET_NR_getdents64: { struct dirent64 *dirp; - long count = arg3; + target_long count = arg3; dirp = lock_user(arg2, count, 0); ret = get_errno(sys_getdents64(arg1, dirp, count)); if (!is_error(ret)) { @@ -4941,4 +4966,3 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, #endif return ret; } - -- cgit v1.2.3 From fe253235b2b3c78587c049b8504c2ef2ea7b5ced Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 26 Sep 2007 23:50:39 +0000 Subject: Wrap a few often used tests with unlikely(), by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3242 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index c70480cc7..d4dfb2a6f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -733,19 +733,19 @@ static inline void generate_exception (DisasContext *ctx, int excp) static inline void check_cp0_enabled(DisasContext *ctx) { - if (!(ctx->hflags & MIPS_HFLAG_CP0)) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) generate_exception_err(ctx, EXCP_CpU, 1); } static inline void check_cp1_enabled(DisasContext *ctx) { - if (!(ctx->hflags & MIPS_HFLAG_FPU)) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU))) generate_exception_err(ctx, EXCP_CpU, 1); } static inline void check_cp1_64bitmode(DisasContext *ctx) { - if (!(ctx->hflags & MIPS_HFLAG_F64)) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64))) generate_exception(ctx, EXCP_RI); } @@ -762,7 +762,7 @@ static inline void check_cp1_64bitmode(DisasContext *ctx) */ void check_cp1_registers(DisasContext *ctx, int regs) { - if (!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1)) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1))) generate_exception(ctx, EXCP_RI); } @@ -778,7 +778,7 @@ static inline void check_insn(CPUState *env, DisasContext *ctx, int flags) CPU is not MIPS MT capable. */ static inline void check_mips_mt(CPUState *env, DisasContext *ctx) { - if (!(env->CP0_Config3 & (1 << CP0C3_MT))) + if (unlikely(!(env->CP0_Config3 & (1 << CP0C3_MT)))) generate_exception(ctx, EXCP_RI); } @@ -786,7 +786,7 @@ static inline void check_mips_mt(CPUState *env, DisasContext *ctx) instructions are not enabled. */ static inline void check_mips_64(DisasContext *ctx) { - if (!(ctx->hflags & MIPS_HFLAG_64)) + if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) generate_exception(ctx, EXCP_RI); } -- cgit v1.2.3 From 08fa4bab833f834e1511853dd2331fa3d6d5d469 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 26 Sep 2007 23:52:06 +0000 Subject: hflags computation cleanup, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3243 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 26 ++++++++++++++++++++++- target-mips/helper.c | 10 +++------ target-mips/op.c | 58 ++++------------------------------------------------ 3 files changed, 32 insertions(+), 62 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index d5aadedb8..9ff3f08b5 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -243,7 +243,8 @@ static inline void regs_to_env(void) { } -static inline int cpu_halted(CPUState *env) { +static inline int cpu_halted(CPUState *env) +{ if (!env->halted) return 0; if (env->interrupt_request & @@ -254,4 +255,27 @@ static inline int cpu_halted(CPUState *env) { return EXCP_HALTED; } +static inline void compute_hflags(CPUState *env) +{ + env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | + MIPS_HFLAG_FPU | MIPS_HFLAG_UM); + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & (1 << CP0St_UM))) + env->hflags |= MIPS_HFLAG_UM; +#ifdef TARGET_MIPS64 + if (!(env->hflags & MIPS_HFLAG_UM) || + (env->CP0_Status & (1 << CP0St_PX)) || + (env->CP0_Status & (1 << CP0St_UX))) + env->hflags |= MIPS_HFLAG_64; +#endif + if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) + env->hflags |= MIPS_HFLAG_CP0; + if (env->CP0_Status & (1 << CP0St_CU1)) + env->hflags |= MIPS_HFLAG_FPU; + if (env->CP0_Status & (1 << CP0St_FR)) + env->hflags |= MIPS_HFLAG_F64; +} + #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ diff --git a/target-mips/helper.c b/target-mips/helper.c index 5c19a7ca4..8e4233ed7 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -368,10 +368,8 @@ void do_interrupt (CPUState *env) env->CP0_DEPC = env->PC[env->current_tc]; } enter_debug_mode: - env->hflags |= MIPS_HFLAG_DM; - env->hflags |= MIPS_HFLAG_64; + env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; env->hflags &= ~MIPS_HFLAG_UM; - env->hflags |= MIPS_HFLAG_CP0; /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -396,9 +394,8 @@ void do_interrupt (CPUState *env) env->CP0_ErrorEPC = env->PC[env->current_tc]; } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - env->hflags |= MIPS_HFLAG_64; + env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; env->hflags &= ~MIPS_HFLAG_UM; - env->hflags |= MIPS_HFLAG_CP0; if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->PC[env->current_tc] = (int32_t)0xBFC00000; @@ -499,9 +496,8 @@ void do_interrupt (CPUState *env) env->CP0_Cause &= ~(1 << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); - env->hflags |= MIPS_HFLAG_64; + env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; env->hflags &= ~MIPS_HFLAG_UM; - env->hflags |= MIPS_HFLAG_CP0; } env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { diff --git a/target-mips/op.c b/target-mips/op.c index b8c5ce8d5..2f513aeb6 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1841,30 +1841,8 @@ void op_mtc0_status (void) val = T0 & mask; old = env->CP0_Status; - if (!(val & (1 << CP0St_EXL)) && - !(val & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM) && - (val & (1 << CP0St_UM))) - env->hflags |= MIPS_HFLAG_UM; -#ifdef TARGET_MIPS64 - if ((env->hflags & MIPS_HFLAG_UM) && - !(val & (1 << CP0St_PX)) && - !(val & (1 << CP0St_UX))) - env->hflags &= ~MIPS_HFLAG_64; -#endif - if ((val & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) - env->hflags |= MIPS_HFLAG_CP0; - else - env->hflags &= ~MIPS_HFLAG_CP0; - if (val & (1 << CP0St_CU1)) - env->hflags |= MIPS_HFLAG_FPU; - else - env->hflags &= ~MIPS_HFLAG_FPU; - if (val & (1 << CP0St_FR)) - env->hflags |= MIPS_HFLAG_F64; - else - env->hflags &= ~MIPS_HFLAG_F64; env->CP0_Status = (env->CP0_Status & ~mask) | val; + CALL_FROM_TB1(compute_hflags, env); if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB2(do_mtc0_status_debug, old, val); CALL_FROM_TB1(cpu_mips_update_irq, env); @@ -3009,21 +2987,7 @@ void op_eret (void) env->PC[env->current_tc] = env->CP0_EPC; env->CP0_Status &= ~(1 << CP0St_EXL); } - if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Status & (1 << CP0St_UM))) - env->hflags |= MIPS_HFLAG_UM; -#ifdef TARGET_MIPS64 - if ((env->hflags & MIPS_HFLAG_UM) && - !(env->CP0_Status & (1 << CP0St_PX)) && - !(env->CP0_Status & (1 << CP0St_UX))) - env->hflags &= ~MIPS_HFLAG_64; -#endif - if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) - env->hflags |= MIPS_HFLAG_CP0; - else - env->hflags &= ~MIPS_HFLAG_CP0; + CALL_FROM_TB1(compute_hflags, env); if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; @@ -3035,22 +2999,8 @@ void op_deret (void) if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_pre_eret); env->PC[env->current_tc] = env->CP0_DEPC; - env->hflags |= MIPS_HFLAG_DM; - if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Status & (1 << CP0St_UM))) - env->hflags |= MIPS_HFLAG_UM; -#ifdef TARGET_MIPS64 - if ((env->hflags & MIPS_HFLAG_UM) && - !(env->CP0_Status & (1 << CP0St_PX)) && - !(env->CP0_Status & (1 << CP0St_UX))) - env->hflags &= ~MIPS_HFLAG_64; -#endif - if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) - env->hflags |= MIPS_HFLAG_CP0; - else - env->hflags &= ~MIPS_HFLAG_CP0; + env->hflags &= MIPS_HFLAG_DM; + CALL_FROM_TB1(compute_hflags, env); if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; -- cgit v1.2.3 From a750fc0b9184a520d00d9e949160a0c6d3232ecd Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 26 Sep 2007 23:54:22 +0000 Subject: Great rework and cleanups to ease PowerPC implementations definitions. * cleanup cpu.h, removing definitions used only in translate.c/translate_init.c * add new flags to define instructions sets more precisely * various changes in MMU models definitions * add definitions for PowerPC 440/460 support (insns and SPRs). * add definitions for PowerPC 401/403 and 620 input pins model * Fix definitions for most PowerPC 401, 403, 405, 440, 601, 602, 603 and 7x0 * Preliminary support for PowerPC 74xx (aka G4) without altivec. * Code provision for other PowerPC support (7x5, 970, ...). * New SPR and PVR defined, from PowerPC 2.04 specification and other sources * Misc code bugs, error messages and styles fixes. * Update status files for PowerPC cores support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3244 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 7 +- linux-user/main.c | 17 +- target-ppc/STATUS | 653 +++-- target-ppc/cpu.h | 641 ++--- target-ppc/exec.h | 2 + target-ppc/helper.c | 287 ++- target-ppc/op.c | 2 +- target-ppc/op_helper.c | 93 +- target-ppc/op_helper.h | 2 +- target-ppc/translate.c | 323 ++- target-ppc/translate_init.c | 5734 ++++++++++++++++++++++++++----------------- 11 files changed, 4459 insertions(+), 3302 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index d0eb7a476..b3cf71b17 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -376,11 +376,11 @@ static void ppc405_set_irq (void *opaque, int pin, int level) /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: set the external IRQ state to %d\n", + fprintf(logfile, "%s: set the debug pin state to %d\n", __func__, level); } #endif - ppc_set_irq(env, EXCP_40x_DEBUG, level); + ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level); break; default: /* Unknown pin - do nothing */ @@ -904,6 +904,9 @@ struct ppc_dcrn_t { void *opaque; }; +/* XXX: on 460, DCR addresses are 32 bits wide, + * using DCRIPR to get the 22 upper bits of the DCR address + */ #define DCRN_NB 1024 struct ppc_dcr_t { ppc_dcrn_t dcrn[DCRN_NB]; diff --git a/linux-user/main.c b/linux-user/main.c index 18e0be181..b70c070c3 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -712,6 +712,17 @@ uint32_t cpu_ppc601_load_rtcl (CPUState *env) return cpu_ppc_load_tbl(env) & 0x3FFFFF80; } +/* XXX: to be fixed */ +int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp) +{ + return -1; +} + +int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val) +{ + return -1; +} + void cpu_loop(CPUPPCState *env) { target_siginfo_t info; @@ -761,7 +772,7 @@ void cpu_loop(CPUPPCState *env) case EXCP_MACHINE_CHECK: fprintf(stderr, "Machine check exeption... Stop emulation\n"); if (loglevel) - fprintf(logfile, "RESET asked... Stop emulation\n"); + fprintf(logfile, "Machine check exception. Stop emulation\n"); info.si_signo = TARGET_SIGBUS; info.si_errno = 0; info.si_code = TARGET_BUS_OBJERR; @@ -914,7 +925,7 @@ void cpu_loop(CPUPPCState *env) info.si_code = TARGET_ILL_ILLOPC; break; case EXCP_INVAL_LSWX: - info.si_code = TARGET_ILL_ILLOPN; + info.si_code = TARGET_ILL_ILLOPN; break; case EXCP_INVAL_SPR: info.si_code = TARGET_ILL_PRVREG; @@ -1003,7 +1014,7 @@ void cpu_loop(CPUPPCState *env) if (loglevel) fprintf(logfile, "Tried to go into supervisor mode !\n"); abort(); - } + } break; case EXCP_BRANCH: /* We stopped because of a jump... */ diff --git a/target-ppc/STATUS b/target-ppc/STATUS index 190186562..b4daa97af 100644 --- a/target-ppc/STATUS +++ b/target-ppc/STATUS @@ -4,267 +4,462 @@ The goal of this file is to provide a reference status to avoid regressions. =============================================================================== PowerPC core emulation status -32 bits PowerPC -PowerPC 601: -INSN -SPR -MMU -EXCP - -PowerPC 602: -INSN -SPR -MMU -EXCP - -PowerPC 603: -INSN OK -SPR OK -MMU OK -EXCP OK - -PowerPC 604: -INSN OK -SPR OK -MMU OK -EXCP OK - -PowerPC 740: -INSN OK -SPR OK -MMU OK -EXCP OK - -PowerPC 745: -INSN -SPR -MMU -EXCP - -PowerPC 750: -INSN OK -SPR OK -MMU OK -EXCP OK - -PowerPC 755: -INSN -SPR -MMU -EXCP +INSN: instruction set. + OK => all instructions are emulated + KO => some insns are missing or some should be removed + ? => unchecked +SPR: special purpose registers set + OK => all SPR registered (but some may be fake) + KO => some SPR are missing or should be removed + ? => uncheked +MSR: MSR bits definitions + OK => all MSR bits properly defined + KO => MSR definition is incorrect + ? => unchecked +IRQ: input signals definitions (mostly interrupts) + OK => input signals are properly defined + KO => input signals are not implemented (system emulation does not work) + ? => input signals definitions may be incorrect +MMU: MMU model implementation + OK => MMU model is implemented and Linux is able to boot + KO => MMU model not implemented or bugged + ? => MMU model not tested +EXCP: exceptions model implementation + OK => exception model is implemented and Linux is able to boot + KO => exception model not implemented or known to be buggy + ? => exception model may be incorrect or is untested -PowerPC 7400: -INSN KO -SPR KO -MMU OK -EXCP OK +Embedded PowerPC cores +*** +PowerPC 401: +INSN OK +SPR OK 401A1 +MSR OK +IRQ KO partially implemented +MMU OK +EXCP ? -PowerPC 7410: -INSN KO -SPR KO -MMU OK -EXCP OK - -PowerPC 7450: -INSN KO -SPR KO -MMU OK -EXCP OK - -PowerPC 7455: -INSN KO -SPR KO -MMU OK -EXCP OK - -PowerPC 7457: -INSN KO -SPR KO -MMU OK -EXCP OK - -PowerPC 7457A: -INSN KO -SPR KO -MMU OK -EXCP OK +PowerPC 401x2: +INSN OK +SPR OK 401B2 401C2 401D2 401E2 401F2 +MSR OK +IRQ KO partially implemented +MMU OK +EXCP ? -64 bits PowerPC -PowerPC 970: -INSN KO -SPR KO -MMU KO -EXCP KO - -PowerPC 620: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -PowerPC 630: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -PowerPC 631: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -POWER4: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -POWER4+: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -POWER5: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -POWER5+: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -POWER6: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -RS64: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -RS64-II: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -RS64-III: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO - -RS64-IV: (lack of precise informations) -INSN KO -SPR KO -MMU KO -EXCP KO +PowerPC IOP480: +INSN OK +SPR OK IOP480 +MSR OK +IRQ KO partially implemented +MMU OK +EXCP ? -Embedded PowerPC cores -PowerPC 401: -INSN OK -SPR OK -MMU OK -EXCP ? +To be checked: 401G2 401B3 Cobra +*** PowerPC 403: -INSN OK -SPR OK -MMU OK -EXCP ? +INSN OK +SPR OK 403GA 403GB +MMU OK +MSR OK +IRQ KO not implemented +EXCP ? +PowerPC 403GCX: +INSN OK +SPR OK 403GCX +MMU OK +MSR OK +IRQ KO not implemented +EXCP ? + +To be checked: 403GC + +*** PowerPC 405: -INSN OK -SPR OK -MMU OK -EXCP OK +Checked: 405CRa 405CRb 405CRc 405EP 405GPa 405GPb 405GPc 405GPd 405GPe 405GPR + Npe405H Npe405H2 Npe405L +INSN OK +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP OK +=> Linux 2.4 boots (at least 1 proprietary firmware). + +To be checked: 405D2 405D4 405EZ 405LP Npe4GS3 STB03 STB04 STB25 + x2vp4 x2vp7 x2vp20 x2vp50 + +XXX: find what is IBM e407b4 +*** PowerPC 440: +Checked: 440EPa 440EPb 440GXa 440GXb 440GXc 440GXf 440SP 440SP2 +INSN OK +SPR OK +MSR OK +IRQ KO not implemented +MMU ? +EXCP ? + +PowerPC 440GP: +Checked: 440GPb 440GPc +INSN OK +SPR OK +MSR OK +IRQ KO not implemented +MMU ? +EXCP ? + +PowerPC 440x4: +Checked: 440A4 440B4 440G4 440H4 INSN OK SPR OK +MSR OK +IRQ KO not implemented MMU ? EXCP ? -PowerPC 460: (lack of precise informations) +PowerPC 440x5: +Checked: 440A5 440F5 440G5 440H6 440GRa +INSN OK +SPR OK +MSR OK +IRQ KO not implemented +MMU ? +EXCP ? + +To be checked: 440EPx 440GRx 440SPE + +*** +PowerPC 460: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +PowerPC 460F: (disabled: lack of detailed specifications) INSN KO SPR KO +MSR KO +IRQ KO MMU KO EXCP KO -Freescale (to be completed) ... +*** +PowerPC e200: (not implemented) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO -Original POWER -POWER: (lack of precise informations) +*** +PowerPC e300: (not implemented) INSN KO SPR KO +MSR KO +IRQ KO MMU KO EXCP KO -POWER2: (lack of precise informations) +*** +PowerPC e500: (not implemented) INSN KO SPR KO +MSR KO +IRQ KO MMU KO EXCP KO -PowerPC CPU known to work (ie booting at least Linux 2.4): -* main stream PowerPC cores -- PowerPC 603 & derivatives -- PowerPC 604 & derivatives -- PowerPC 740 & derivatives -- PowerPC 750 & derivatives -- PowerPC 405 - -PowerPC that should work but are not supported by standard Linux kernel -(then remain mostly untested) -- PowerPC 745 -- PowerPC 755 - -Work in progress: -* embedded PowerPC cores -- BookE PowerPC -- e500 core (Freescale PowerQUICC) -* main stream PowerPC cores -- PowerPC 601 -- PowerPC 602 +*** +PowerPC e600: (not implemented) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO -TODO: -* embedded PowerPC cores -- PowerPC 401 -- PowerPC 403 -- PowerPC 440 -- PowerPC 460 -* main stream PowerPC cores -- PowerPC 7400 (aka G4) -- PowerPC 7410 -- PowerPC 7450 -- PowerPC 7455 -- PowerPC 7457 -- PowerPC 7457A -* original POWER -- POWER -- POWER2 -* 64 bits PowerPC cores -- PowerPC 620 -- PowerPC 630 (aka POWER3) -- PowerPC 631 (aka POWER3+) -- POWER4 -- POWER4+ -- POWER5 -- POWER5+ -- PowerPC 970 -* RS64 series -- RS64 -- RS64-II -- RS64-III -- RS64-IV +*** +32 bits PowerPC +PowerPC 601: (601 601v2) +INSN OK +SPR OK is HID15 only on 601v2 ? +MSR OK +IRQ KO not implemented +MMU ? +EXCP ? +Remarks: some instructions should have a specific behavior (not implemented) + +PowerPC 602: 602 +INSN OK +SPR OK +MSR OK +IRQ OK +MMU ? +EXCP ? at least timer and external interrupt are OK +Remarks: Linux crashes when entering user-mode. But it seems it does not + know about this CPU. As this CPU is close to 603e, it should be OK. + +PowerPC 603: (603) +INSN OK +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP OK +Remarks: Linux 2.4 boots and properly recognizes the CPU + +PowerPC 603e: (603e11) +INSN OK +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP OK +Remarks: Linux 2.4 boots and properly recognizes the CPU + +PowerPC G2: +INSN OK +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP OK +Remarks: Linux 2.4 boots, recognizes the CPU as a 82xx. + +PowerPC G2le: +INSN OK +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP OK +Remarks: Linux 2.4 does not boots. Same symptoms as 602. + +PowerPC 604: +INSN OK +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP OK +Remarks: Linux 2.4 boots and properly recognizes the CPU. + +PowerPC 7x0: +INSN OK +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP OK +Remarks: Linux 2.4 boots and properly recognizes the CPU. + +PowerPC 750fx: +INSN OK +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP OK +Remarks: Linux 2.4 boots but does not properly recognizes the CPU. + +PowerPC 7x5: +INSN ? +SPR ? +MSR ? +IRQ OK +MMU ? +EXCP OK +=> Linux 2.4 does not boot. + +PowerPC 7400: +INSN KO Altivec missing +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP ? Altivec, ... +=> Linux 2.4 boots and properly recognize the CPU. + +PowerPC 7410: +INSN KO Altivec missing +SPR OK +MSR OK +IRQ OK +MMU OK +EXCP ? Altivec, ... +=> Linux 2.4 boots and properly recognize the CPU. + Note that UM says tlbld & tlbli are implemented bus this may be a mistake + as TLB load are managed by the hardware and it does not implement the + needed registers. + +PowerPC 7441: +INSN KO Altivec missing + TLB load insns missing +SPR OK +MSR OK +IRQ OK +MMU KO not implemented +EXCP ? Altivec, ... + +PowerPC 7450/7451: +INSN KO Altivec missing + TLB load insns missing +SPR OK +MSR OK +IRQ OK +MMU KO not implemented +EXCP ? Altivec, ... + +PowerPC 7445/7447: +INSN KO Altivec missing + TLB load insns missing +SPR OK +MSR OK +IRQ OK +MMU KO not implemented +EXCP ? Altivec, ... + +PowerPC 7455/7457: +INSN KO Altivec missing + TLB load insns missing +SPR OK +MSR OK +IRQ OK +MMU KO not implemented +EXCP ? Altivec, ... + +64 bits PowerPC +PowerPC 620: (disabled) +INSN KO +SPR KO +MSR ? +IRQ KO +MMU KO +EXCP KO + +PowerPC 970: (disabled) +INSN KO Altivec missing and more +SPR KO +MSR ? +IRQ OK +MMU KO partially implemented +EXCP KO + +PowerPC 970FX: (disabled) +INSN KO Altivec missing and more +SPR KO +MSR ? +IRQ OK +MMU KO partially implemented +EXCP KO + +PowerPC 630: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +PowerPC 631: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +POWER4: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +POWER4+: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +POWER5: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +POWER5+: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +POWER6: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +RS64: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +RS64-II: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +RS64-III: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +RS64-IV: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +Original POWER +POWER: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO + +POWER2: (disabled: lack of detailed specifications) +INSN KO +SPR KO +MSR KO +IRQ KO +MMU KO +EXCP KO =============================================================================== PowerPC microcontrollers emulation status diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f4c7a9467..f1df741e1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -89,528 +89,89 @@ typedef uint32_t ppc_gpr_t; #define DCACHE_LINE_SIZE 32 /*****************************************************************************/ -/* PVR definitions for most known PowerPC */ +/* MMU model */ enum { - /* PowerPC 401 cores */ - CPU_PPC_401A1 = 0x00210000, - CPU_PPC_401B2 = 0x00220000, -#if 0 - CPU_PPC_401B3 = xxx, -#endif - CPU_PPC_401C2 = 0x00230000, - CPU_PPC_401D2 = 0x00240000, - CPU_PPC_401E2 = 0x00250000, - CPU_PPC_401F2 = 0x00260000, - CPU_PPC_401G2 = 0x00270000, -#if 0 - CPU_PPC_401GF = xxx, -#endif -#define CPU_PPC_401 CPU_PPC_401G2 - CPU_PPC_IOP480 = 0x40100000, /* 401B2 ? */ - CPU_PPC_COBRA = 0x10100000, /* IBM Processor for Network Resources */ - /* PowerPC 403 cores */ - CPU_PPC_403GA = 0x00200011, - CPU_PPC_403GB = 0x00200100, - CPU_PPC_403GC = 0x00200200, - CPU_PPC_403GCX = 0x00201400, -#if 0 - CPU_PPC_403GP = xxx, -#endif -#define CPU_PPC_403 CPU_PPC_403GCX - /* PowerPC 405 cores */ -#if 0 - CPU_PPC_405A3 = xxx, -#endif -#if 0 - CPU_PPC_405A4 = xxx, -#endif -#if 0 - CPU_PPC_405B3 = xxx, -#endif - CPU_PPC_405D2 = 0x20010000, - CPU_PPC_405D4 = 0x41810000, - CPU_PPC_405CR = 0x40110145, -#define CPU_PPC_405GP CPU_PPC_405CR - CPU_PPC_405EP = 0x51210950, -#if 0 - CPU_PPC_405EZ = xxx, -#endif - CPU_PPC_405GPR = 0x50910951, -#if 0 - CPU_PPC_405LP = xxx, -#endif -#define CPU_PPC_405 CPU_PPC_405D4 - CPU_PPC_NPE405H = 0x414100C0, - CPU_PPC_NPE405H2 = 0x41410140, - CPU_PPC_NPE405L = 0x416100C0, -#if 0 - CPU_PPC_LC77700 = xxx, -#endif - /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */ -#if 0 - CPU_PPC_STB01000 = xxx, -#endif -#if 0 - CPU_PPC_STB01010 = xxx, -#endif -#if 0 - CPU_PPC_STB0210 = xxx, -#endif - CPU_PPC_STB03 = 0x40310000, -#if 0 - CPU_PPC_STB043 = xxx, -#endif -#if 0 - CPU_PPC_STB045 = xxx, -#endif - CPU_PPC_STB25 = 0x51510950, -#if 0 - CPU_PPC_STB130 = xxx, -#endif - /* Xilinx cores */ - CPU_PPC_X2VP4 = 0x20010820, -#define CPU_PPC_X2VP7 CPU_PPC_X2VP4 - CPU_PPC_X2VP20 = 0x20010860, -#define CPU_PPC_X2VP50 CPU_PPC_X2VP20 - /* PowerPC 440 cores */ - CPU_PPC_440EP = 0x422218D3, -#define CPU_PPC_440GR CPU_PPC_440EP - CPU_PPC_440GP = 0x40120481, -#if 0 - CPU_PPC_440GRX = xxx, -#endif - CPU_PPC_440GX = 0x51B21850, - CPU_PPC_440GXc = 0x51B21892, - CPU_PPC_440GXf = 0x51B21894, - CPU_PPC_440SP = 0x53221850, - CPU_PPC_440SP2 = 0x53221891, - CPU_PPC_440SPE = 0x53421890, - /* PowerPC 460 cores */ -#if 0 - CPU_PPC_464H90 = xxx, -#endif -#if 0 - CPU_PPC_464H90FP = xxx, -#endif - /* PowerPC MPC 5xx cores */ - CPU_PPC_5xx = 0x00020020, - /* PowerPC MPC 8xx cores (aka PowerQUICC) */ - CPU_PPC_8xx = 0x00500000, - /* PowerPC MPC 8xxx cores (aka PowerQUICC-II) */ - CPU_PPC_82xx_HIP3 = 0x00810101, - CPU_PPC_82xx_HIP4 = 0x80811014, - CPU_PPC_827x = 0x80822013, - /* eCores */ - CPU_PPC_e200 = 0x81120000, - CPU_PPC_e500v110 = 0x80200010, - CPU_PPC_e500v120 = 0x80200020, - CPU_PPC_e500v210 = 0x80210010, - CPU_PPC_e500v220 = 0x80210020, -#define CPU_PPC_e500 CPU_PPC_e500v220 - CPU_PPC_e600 = 0x80040010, - /* PowerPC 6xx cores */ - CPU_PPC_601 = 0x00010001, - CPU_PPC_602 = 0x00050100, - CPU_PPC_603 = 0x00030100, - CPU_PPC_603E = 0x00060101, - CPU_PPC_603P = 0x00070000, - CPU_PPC_603E7v = 0x00070100, - CPU_PPC_603E7v2 = 0x00070201, - CPU_PPC_603E7 = 0x00070200, - CPU_PPC_603R = 0x00071201, - CPU_PPC_G2 = 0x00810011, - CPU_PPC_G2H4 = 0x80811010, - CPU_PPC_G2gp = 0x80821010, - CPU_PPC_G2ls = 0x90810010, - CPU_PPC_G2LE = 0x80820010, - CPU_PPC_G2LEgp = 0x80822010, - CPU_PPC_G2LEls = 0xA0822010, - CPU_PPC_604 = 0x00040000, - CPU_PPC_604E = 0x00090100, /* Also 2110 & 2120 */ - CPU_PPC_604R = 0x000a0101, - /* PowerPC 74x/75x cores (aka G3) */ - CPU_PPC_74x = 0x00080000, - CPU_PPC_740E = 0x00080100, - CPU_PPC_74xP = 0x10080000, - CPU_PPC_750E = 0x00080200, - CPU_PPC_750CXE21 = 0x00082201, - CPU_PPC_750CXE22 = 0x00082212, - CPU_PPC_750CXE23 = 0x00082203, - CPU_PPC_750CXE24 = 0x00082214, - CPU_PPC_750CXE24b = 0x00083214, - CPU_PPC_750CXE31 = 0x00083211, - CPU_PPC_750CXE31b = 0x00083311, -#define CPU_PPC_750CXE CPU_PPC_750CXE31b - CPU_PPC_750CXR = 0x00083410, - CPU_PPC_750FX10 = 0x70000100, - CPU_PPC_750FX20 = 0x70000200, - CPU_PPC_750FX21 = 0x70000201, - CPU_PPC_750FX22 = 0x70000202, - CPU_PPC_750FX23 = 0x70000203, -#define CPU_PPC_750FX CPU_PPC_750FX23 - CPU_PPC_750FL = 0x700A0203, - CPU_PPC_750GX10 = 0x70020100, - CPU_PPC_750GX11 = 0x70020101, - CPU_PPC_750GX12 = 0x70020102, -#define CPU_PPC_750GX CPU_PPC_750GX12 - CPU_PPC_750GL = 0x70020102, - CPU_PPC_750L30 = 0x00088300, - CPU_PPC_750L32 = 0x00088302, -#define CPU_PPC_750L CPU_PPC_750L32 - CPU_PPC_750CL = 0x00087200, - CPU_PPC_755_10 = 0x00083100, - CPU_PPC_755_11 = 0x00083101, - CPU_PPC_755_20 = 0x00083200, - CPU_PPC_755D = 0x00083202, - CPU_PPC_755E = 0x00083203, -#define CPU_PPC_755 CPU_PPC_755E - /* PowerPC 74xx cores (aka G4) */ - CPU_PPC_7400 = 0x000C0100, - CPU_PPC_7410C = 0x800C1102, - CPU_PPC_7410D = 0x800C1103, - CPU_PPC_7410E = 0x800C1104, -#define CPU_PPC_7410 CPU_PPC_7410E - CPU_PPC_7441 = 0x80000210, - CPU_PPC_7445 = 0x80010100, - CPU_PPC_7447 = 0x80020100, - CPU_PPC_7447A = 0x80030101, - CPU_PPC_7448 = 0x80040100, - CPU_PPC_7450 = 0x80000200, - CPU_PPC_7450b = 0x80000201, - CPU_PPC_7451 = 0x80000203, - CPU_PPC_7451G = 0x80000210, - CPU_PPC_7455 = 0x80010201, - CPU_PPC_7455F = 0x80010303, - CPU_PPC_7455G = 0x80010304, - CPU_PPC_7457 = 0x80020101, - CPU_PPC_7457C = 0x80020102, - CPU_PPC_7457A = 0x80030000, - /* 64 bits PowerPC */ - CPU_PPC_620 = 0x00140000, - CPU_PPC_630 = 0x00400000, - CPU_PPC_631 = 0x00410000, - CPU_PPC_POWER4 = 0x00350000, - CPU_PPC_POWER4P = 0x00380000, - CPU_PPC_POWER5 = 0x003A0000, - CPU_PPC_POWER5P = 0x003B0000, -#if 0 - CPU_PPC_POWER6 = xxx, -#endif - CPU_PPC_970 = 0x00390000, - CPU_PPC_970FX10 = 0x00391100, - CPU_PPC_970FX20 = 0x003C0200, - CPU_PPC_970FX21 = 0x003C0201, - CPU_PPC_970FX30 = 0x003C0300, - CPU_PPC_970FX31 = 0x003C0301, -#define CPU_PPC_970FX CPU_PPC_970FX31 - CPU_PPC_970MP10 = 0x00440100, - CPU_PPC_970MP11 = 0x00440101, -#define CPU_PPC_970MP CPU_PPC_970MP11 - CPU_PPC_CELL10 = 0x00700100, - CPU_PPC_CELL20 = 0x00700400, - CPU_PPC_CELL30 = 0x00700500, - CPU_PPC_CELL31 = 0x00700501, -#define CPU_PPC_CELL32 CPU_PPC_CELL31 -#define CPU_PPC_CELL CPU_PPC_CELL32 - CPU_PPC_RS64 = 0x00330000, - CPU_PPC_RS64II = 0x00340000, - CPU_PPC_RS64III = 0x00360000, - CPU_PPC_RS64IV = 0x00370000, - /* Original POWER */ - /* XXX: should be POWER (RIOS), RSC3308, RSC4608, - * POWER2 (RIOS2) & RSC2 (P2SC) here - */ -#if 0 - CPU_POWER = xxx, -#endif -#if 0 - CPU_POWER2 = xxx, -#endif -}; - -/* System version register (used on MPC 8xxx) */ -enum { - PPC_SVR_8540 = 0x80300000, - PPC_SVR_8541E = 0x807A0010, - PPC_SVR_8543v10 = 0x80320010, - PPC_SVR_8543v11 = 0x80320011, - PPC_SVR_8543v20 = 0x80320020, - PPC_SVR_8543Ev10 = 0x803A0010, - PPC_SVR_8543Ev11 = 0x803A0011, - PPC_SVR_8543Ev20 = 0x803A0020, - PPC_SVR_8545 = 0x80310220, - PPC_SVR_8545E = 0x80390220, - PPC_SVR_8547E = 0x80390120, - PPC_SCR_8548v10 = 0x80310010, - PPC_SCR_8548v11 = 0x80310011, - PPC_SCR_8548v20 = 0x80310020, - PPC_SVR_8548Ev10 = 0x80390010, - PPC_SVR_8548Ev11 = 0x80390011, - PPC_SVR_8548Ev20 = 0x80390020, - PPC_SVR_8555E = 0x80790010, - PPC_SVR_8560v10 = 0x80700010, - PPC_SVR_8560v20 = 0x80700020, + POWERPC_MMU_UNKNOWN = 0, + /* Standard 32 bits PowerPC MMU */ + POWERPC_MMU_32B, + /* Standard 64 bits PowerPC MMU */ + POWERPC_MMU_64B, + /* PowerPC 601 MMU */ + POWERPC_MMU_601, + /* PowerPC 6xx MMU with software TLB */ + POWERPC_MMU_SOFT_6xx, + /* PowerPC 74xx MMU with software TLB */ + POWERPC_MMU_SOFT_74xx, + /* PowerPC 4xx MMU with software TLB */ + POWERPC_MMU_SOFT_4xx, + /* PowerPC 4xx MMU with software TLB and zones protections */ + POWERPC_MMU_SOFT_4xx_Z, + /* PowerPC 4xx MMU in real mode only */ + POWERPC_MMU_REAL_4xx, + /* BookE MMU model */ + POWERPC_MMU_BOOKE, + /* BookE FSL MMU model */ + POWERPC_MMU_BOOKE_FSL, + /* 64 bits "bridge" PowerPC MMU */ + POWERPC_MMU_64BRIDGE, }; /*****************************************************************************/ -/* Instruction types */ -enum { - PPC_NONE = 0x00000000, - /* integer operations instructions */ - /* flow control instructions */ - /* virtual memory instructions */ - /* ld/st with reservation instructions */ - /* cache control instructions */ - /* spr/msr access instructions */ - PPC_INSNS_BASE = 0x0000000000000001ULL, -#define PPC_INTEGER PPC_INSNS_BASE -#define PPC_FLOW PPC_INSNS_BASE -#define PPC_MEM PPC_INSNS_BASE -#define PPC_RES PPC_INSNS_BASE -#define PPC_CACHE PPC_INSNS_BASE -#define PPC_MISC PPC_INSNS_BASE - /* floating point operations instructions */ - PPC_FLOAT = 0x0000000000000002ULL, - /* more floating point operations instructions */ - PPC_FLOAT_EXT = 0x0000000000000004ULL, - /* external control instructions */ - PPC_EXTERN = 0x0000000000000008ULL, - /* segment register access instructions */ - PPC_SEGMENT = 0x0000000000000010ULL, - /* Optional cache control instructions */ - PPC_CACHE_OPT = 0x0000000000000020ULL, - /* Optional floating point op instructions */ - PPC_FLOAT_OPT = 0x0000000000000040ULL, - /* Optional memory control instructions */ - PPC_MEM_TLBIA = 0x0000000000000080ULL, - PPC_MEM_TLBIE = 0x0000000000000100ULL, - PPC_MEM_TLBSYNC = 0x0000000000000200ULL, - /* eieio & sync */ - PPC_MEM_SYNC = 0x0000000000000400ULL, - /* PowerPC 6xx TLB management instructions */ - PPC_6xx_TLB = 0x0000000000000800ULL, - /* Altivec support */ - PPC_ALTIVEC = 0x0000000000001000ULL, - /* Time base support */ - PPC_TB = 0x0000000000002000ULL, - /* Embedded PowerPC dedicated instructions */ - PPC_EMB_COMMON = 0x0000000000004000ULL, - /* PowerPC 40x exception model */ - PPC_40x_EXCP = 0x0000000000008000ULL, - /* PowerPC 40x specific instructions */ - PPC_40x_SPEC = 0x0000000000010000ULL, - /* PowerPC 405 Mac instructions */ - PPC_405_MAC = 0x0000000000020000ULL, - /* PowerPC 440 specific instructions */ - PPC_440_SPEC = 0x0000000000040000ULL, - /* Specific extensions */ - /* Power-to-PowerPC bridge (601) */ - PPC_POWER_BR = 0x0000000000080000ULL, - /* PowerPC 602 specific */ - PPC_602_SPEC = 0x0000000000100000ULL, - /* Deprecated instructions */ - /* Original POWER instruction set */ - PPC_POWER = 0x0000000000200000ULL, - /* POWER2 instruction set extension */ - PPC_POWER2 = 0x0000000000400000ULL, - /* Power RTC support */ - PPC_POWER_RTC = 0x0000000000800000ULL, - /* 64 bits PowerPC instructions */ - /* 64 bits PowerPC instruction set */ - PPC_64B = 0x0000000001000000ULL, - /* 64 bits hypervisor extensions */ - PPC_64H = 0x0000000002000000ULL, - /* 64 bits PowerPC "bridge" features */ - PPC_64_BRIDGE = 0x0000000004000000ULL, - /* BookE (embedded) PowerPC specification */ - PPC_BOOKE = 0x0000000008000000ULL, - /* eieio */ - PPC_MEM_EIEIO = 0x0000000010000000ULL, - /* e500 vector instructions */ - PPC_E500_VECTOR = 0x0000000020000000ULL, - /* PowerPC 4xx dedicated instructions */ - PPC_4xx_COMMON = 0x0000000040000000ULL, - /* PowerPC 2.03 specification extensions */ - PPC_203 = 0x0000000080000000ULL, - /* PowerPC 2.03 SPE extension */ - PPC_SPE = 0x0000000100000000ULL, - /* PowerPC 2.03 SPE floating-point extension */ - PPC_SPEFPU = 0x0000000200000000ULL, - /* SLB management */ - PPC_SLBI = 0x0000000400000000ULL, - /* PowerPC 40x ibct instructions */ - PPC_40x_ICBT = 0x0000000800000000ULL, -}; - -/* CPU run-time flags (MMU and exception model) */ +/* Exception model */ enum { - /* MMU model */ - PPC_FLAGS_MMU_MASK = 0x000000FF, - /* Standard 32 bits PowerPC MMU */ - PPC_FLAGS_MMU_32B = 0x00000000, - /* Standard 64 bits PowerPC MMU */ - PPC_FLAGS_MMU_64B = 0x00000001, - /* PowerPC 601 MMU */ - PPC_FLAGS_MMU_601 = 0x00000002, - /* PowerPC 6xx MMU with software TLB */ - PPC_FLAGS_MMU_SOFT_6xx = 0x00000003, - /* PowerPC 4xx MMU with software TLB */ - PPC_FLAGS_MMU_SOFT_4xx = 0x00000004, - /* PowerPC 403 MMU */ - PPC_FLAGS_MMU_403 = 0x00000005, - /* BookE FSL MMU model */ - PPC_FLAGS_MMU_BOOKE_FSL = 0x00000006, - /* BookE MMU model */ - PPC_FLAGS_MMU_BOOKE = 0x00000007, - /* 64 bits "bridge" PowerPC MMU */ - PPC_FLAGS_MMU_64BRIDGE = 0x00000008, - /* PowerPC 401 MMU (real mode only) */ - PPC_FLAGS_MMU_401 = 0x00000009, - /* Exception model */ - PPC_FLAGS_EXCP_MASK = 0x0000FF00, + POWERPC_EXCP_UNKNOWN = 0, /* Standard PowerPC exception model */ - PPC_FLAGS_EXCP_STD = 0x00000000, + POWERPC_EXCP_STD, /* PowerPC 40x exception model */ - PPC_FLAGS_EXCP_40x = 0x00000100, + POWERPC_EXCP_40x, /* PowerPC 601 exception model */ - PPC_FLAGS_EXCP_601 = 0x00000200, + POWERPC_EXCP_601, /* PowerPC 602 exception model */ - PPC_FLAGS_EXCP_602 = 0x00000300, + POWERPC_EXCP_602, /* PowerPC 603 exception model */ - PPC_FLAGS_EXCP_603 = 0x00000400, + POWERPC_EXCP_603, + /* PowerPC 603e exception model */ + POWERPC_EXCP_603E, + /* PowerPC G2 exception model */ + POWERPC_EXCP_G2, /* PowerPC 604 exception model */ - PPC_FLAGS_EXCP_604 = 0x00000500, + POWERPC_EXCP_604, /* PowerPC 7x0 exception model */ - PPC_FLAGS_EXCP_7x0 = 0x00000600, + POWERPC_EXCP_7x0, /* PowerPC 7x5 exception model */ - PPC_FLAGS_EXCP_7x5 = 0x00000700, + POWERPC_EXCP_7x5, /* PowerPC 74xx exception model */ - PPC_FLAGS_EXCP_74xx = 0x00000800, + POWERPC_EXCP_74xx, /* PowerPC 970 exception model */ - PPC_FLAGS_EXCP_970 = 0x00000900, + POWERPC_EXCP_970, /* BookE exception model */ - PPC_FLAGS_EXCP_BOOKE = 0x00000A00, - /* Input pins model */ - PPC_FLAGS_INPUT_MASK = 0x000F0000, + POWERPC_EXCP_BOOKE, +}; + +/*****************************************************************************/ +/* Input pins model */ +enum { + PPC_FLAGS_INPUT_UNKNOWN = 0, /* PowerPC 6xx bus */ - PPC_FLAGS_INPUT_6xx = 0x00000000, + PPC_FLAGS_INPUT_6xx, /* BookE bus */ - PPC_FLAGS_INPUT_BookE = 0x00010000, - /* PowerPC 4xx bus */ - PPC_FLAGS_INPUT_40x = 0x00020000, + PPC_FLAGS_INPUT_BookE, + /* PowerPC 405 bus */ + PPC_FLAGS_INPUT_405, /* PowerPC 970 bus */ - PPC_FLAGS_INPUT_970 = 0x00030000, + PPC_FLAGS_INPUT_970, + /* PowerPC 401 bus */ + PPC_FLAGS_INPUT_401, }; -#define PPC_MMU(env) (env->flags & PPC_FLAGS_MMU_MASK) -#define PPC_EXCP(env) (env->flags & PPC_FLAGS_EXCP_MASK) -#define PPC_INPUT(env) (env->flags & PPC_FLAGS_INPUT_MASK) +#define PPC_INPUT(env) (env->bus_model) -/*****************************************************************************/ -/* Supported instruction set definitions */ -/* This generates an empty opcode table... */ -#define PPC_INSNS_TODO (PPC_NONE) -#define PPC_FLAGS_TODO (0x00000000) - -/* PowerPC 40x instruction set */ -#define PPC_INSNS_EMB (PPC_INSNS_BASE | PPC_EMB_COMMON) -/* PowerPC 401 */ -#define PPC_INSNS_401 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) -#define PPC_FLAGS_401 (PPC_FLAGS_MMU_401 | PPC_FLAGS_EXCP_40x | \ - PPC_FLAGS_INPUT_40x) -/* PowerPC 403 */ -#define PPC_INSNS_403 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | \ - PPC_40x_EXCP | PPC_40x_SPEC | PPC_40x_ICBT) -#define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x | \ - PPC_FLAGS_INPUT_40x) -/* PowerPC 405 */ -#define PPC_INSNS_405 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_CACHE_OPT | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_TB | PPC_4xx_COMMON | PPC_40x_SPEC | \ - PPC_40x_ICBT | PPC_40x_EXCP | PPC_405_MAC) -#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x | \ - PPC_FLAGS_INPUT_40x) -/* PowerPC 440 */ -#define PPC_INSNS_440 (PPC_INSNS_EMB | PPC_CACHE_OPT | PPC_BOOKE | \ - PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC) -#define PPC_FLAGS_440 (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE | \ - PPC_FLAGS_INPUT_BookE) -/* Generic BookE PowerPC */ -#define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_MEM_TLBSYNC | PPC_BOOKE | \ - PPC_MEM_EIEIO | PPC_FLOAT | PPC_FLOAT_OPT | \ - PPC_CACHE_OPT) -#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE | \ - PPC_FLAGS_INPUT_BookE) -/* e500 core */ -#define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_MEM_TLBSYNC | PPC_BOOKE | \ - PPC_MEM_EIEIO | PPC_CACHE_OPT | PPC_E500_VECTOR) -#define PPC_FLAGS_E500 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x | \ - PPC_FLAGS_INPUT_BookE) -/* Non-embedded PowerPC */ -#define PPC_INSNS_COMMON (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \ - PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE) -/* PowerPC 601 */ -#define PPC_INSNS_601 (PPC_INSNS_COMMON | PPC_EXTERN | PPC_POWER_BR) -#define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601 | \ - PPC_FLAGS_INPUT_6xx) -/* PowerPC 602 */ -#define PPC_INSNS_602 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ - PPC_MEM_TLBSYNC | PPC_TB | PPC_602_SPEC) -#define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602 | \ - PPC_FLAGS_INPUT_6xx) -/* PowerPC 603 */ -#define PPC_INSNS_603 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ - PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB) -#define PPC_FLAGS_603 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603 | \ - PPC_FLAGS_INPUT_6xx) -/* PowerPC G2 */ -#define PPC_INSNS_G2 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \ - PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB) -#define PPC_FLAGS_G2 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603 | \ - PPC_FLAGS_INPUT_6xx) -/* PowerPC 604 */ -#define PPC_INSNS_604 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ - PPC_MEM_TLBSYNC | PPC_TB) -#define PPC_FLAGS_604 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_604 | \ - PPC_FLAGS_INPUT_6xx) -/* PowerPC 740/750 (aka G3) */ -#define PPC_INSNS_7x0 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ - PPC_MEM_TLBSYNC | PPC_TB) -#define PPC_FLAGS_7x0 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_7x0 | \ - PPC_FLAGS_INPUT_6xx) -/* PowerPC 745/755 */ -#define PPC_INSNS_7x5 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \ - PPC_MEM_TLBSYNC | PPC_TB | PPC_6xx_TLB) -#define PPC_FLAGS_7x5 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_7x5 | \ - PPC_FLAGS_INPUT_6xx) -/* PowerPC 74xx (aka G4) */ -#define PPC_INSNS_74xx (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_ALTIVEC | \ - PPC_MEM_TLBSYNC | PPC_TB) -#define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx | \ - PPC_FLAGS_INPUT_6xx) -/* PowerPC 970 (aka G5) */ -#define PPC_INSNS_970 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_FLOAT_OPT | \ - PPC_ALTIVEC | PPC_MEM_TLBSYNC | PPC_TB | \ - PPC_64B | PPC_64_BRIDGE | PPC_SLBI) -#define PPC_FLAGS_970 (PPC_FLAGS_MMU_64BRIDGE | PPC_FLAGS_EXCP_970 | \ - PPC_FLAGS_INPUT_970) - -/* Default PowerPC will be 604/970 */ -#define PPC_INSNS_PPC32 PPC_INSNS_604 -#define PPC_FLAGS_PPC32 PPC_FLAGS_604 -#define PPC_INSNS_PPC64 PPC_INSNS_970 -#define PPC_FLAGS_PPC64 PPC_FLAGS_970 -#define PPC_INSNS_DEFAULT PPC_INSNS_604 -#define PPC_FLAGS_DEFAULT PPC_FLAGS_604 typedef struct ppc_def_t ppc_def_t; +typedef struct opc_handler_t opc_handler_t; /*****************************************************************************/ /* Types used to describe some PowerPC registers */ typedef struct CPUPPCState CPUPPCState; -typedef struct opc_handler_t opc_handler_t; typedef struct ppc_tb_t ppc_tb_t; typedef struct ppc_spr_t ppc_spr_t; typedef struct ppc_dcr_t ppc_dcr_t; @@ -832,7 +393,11 @@ struct CPUPPCState { /* Those resources are used during exception processing */ /* CPU model definition */ - uint64_t msr_mask; + target_ulong msr_mask; + uint8_t mmu_model; + uint8_t excp_model; + uint8_t bus_model; + uint8_t pad; uint32_t flags; int exception_index; @@ -985,7 +550,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_LR (0x008) #define SPR_CTR (0x009) #define SPR_DSISR (0x012) -#define SPR_DAR (0x013) +#define SPR_DAR (0x013) /* DAE for PowerPC 601 */ #define SPR_601_RTCU (0x014) #define SPR_601_RTCL (0x015) #define SPR_DECR (0x016) @@ -1203,6 +768,8 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_440_ITV1 (0x375) #define SPR_440_ITV2 (0x376) #define SPR_440_ITV3 (0x377) +#define SPR_440_CCR1 (0x378) +#define SPR_DCRIPR (0x37B) #define SPR_PPR (0x380) #define SPR_440_DNV0 (0x390) #define SPR_440_DNV1 (0x391) @@ -1219,38 +786,63 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_BOOKE_DCDBTRH (0x39D) #define SPR_BOOKE_ICDBTRL (0x39E) #define SPR_BOOKE_ICDBTRH (0x39F) +#define SPR_UMMCR2 (0x3A0) +#define SPR_UPMC5 (0x3A1) +#define SPR_UPMC6 (0x3A2) +#define SPR_UBAMR (0x3A7) #define SPR_UMMCR0 (0x3A8) #define SPR_UPMC1 (0x3A9) #define SPR_UPMC2 (0x3AA) -#define SPR_USIA (0x3AB) +#define SPR_USIAR (0x3AB) #define SPR_UMMCR1 (0x3AC) #define SPR_UPMC3 (0x3AD) #define SPR_UPMC4 (0x3AE) #define SPR_USDA (0x3AF) #define SPR_40x_ZPR (0x3B0) #define SPR_BOOKE_MAS7 (0x3B0) +#define SPR_620_PMR0 (0x3B0) +#define SPR_MMCR2 (0x3B0) +#define SPR_PMC5 (0x3B1) #define SPR_40x_PID (0x3B1) +#define SPR_620_PMR1 (0x3B1) +#define SPR_PMC6 (0x3B2) #define SPR_440_MMUCR (0x3B2) +#define SPR_620_PMR2 (0x3B2) #define SPR_4xx_CCR0 (0x3B3) #define SPR_BOOKE_EPLC (0x3B3) +#define SPR_620_PMR3 (0x3B3) #define SPR_405_IAC3 (0x3B4) #define SPR_BOOKE_EPSC (0x3B4) +#define SPR_620_PMR4 (0x3B4) #define SPR_405_IAC4 (0x3B5) +#define SPR_620_PMR5 (0x3B5) #define SPR_405_DVC1 (0x3B6) +#define SPR_620_PMR6 (0x3B6) #define SPR_405_DVC2 (0x3B7) +#define SPR_620_PMR7 (0x3B7) +#define SPR_BAMR (0x3B7) #define SPR_MMCR0 (0x3B8) +#define SPR_620_PMR8 (0x3B8) #define SPR_PMC1 (0x3B9) #define SPR_40x_SGR (0x3B9) +#define SPR_620_PMR9 (0x3B9) #define SPR_PMC2 (0x3BA) #define SPR_40x_DCWR (0x3BA) -#define SPR_SIA (0x3BB) +#define SPR_620_PMRA (0x3BA) +#define SPR_SIAR (0x3BB) #define SPR_405_SLER (0x3BB) +#define SPR_620_PMRB (0x3BB) #define SPR_MMCR1 (0x3BC) #define SPR_405_SU0R (0x3BC) +#define SPR_620_PMRC (0x3BC) +#define SPR_401_SKR (0x3BC) #define SPR_PMC3 (0x3BD) #define SPR_405_DBCR1 (0x3BD) +#define SPR_620_PMRD (0x3BD) #define SPR_PMC4 (0x3BE) +#define SPR_620_PMRE (0x3BE) #define SPR_SDA (0x3BF) +#define SPR_620_PMRF (0x3BF) #define SPR_403_VTBL (0x3CC) #define SPR_403_VTBU (0x3CD) #define SPR_DMISS (0x3D0) @@ -1258,18 +850,23 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_HASH1 (0x3D2) #define SPR_HASH2 (0x3D3) #define SPR_BOOKE_ICDBDR (0x3D3) +#define SPR_TLBMISS (0x3D4) #define SPR_IMISS (0x3D4) #define SPR_40x_ESR (0x3D4) +#define SPR_PTEHI (0x3D5) #define SPR_ICMP (0x3D5) #define SPR_40x_DEAR (0x3D5) +#define SPR_PTELO (0x3D6) #define SPR_RPA (0x3D6) #define SPR_40x_EVPR (0x3D6) +#define SPR_L3PM (0x3D7) #define SPR_403_CDBCR (0x3D7) +#define SPR_L3OHCR (0x3D8) #define SPR_TCR (0x3D8) #define SPR_40x_TSR (0x3D8) #define SPR_IBR (0x3DA) #define SPR_40x_TCR (0x3DA) -#define SPR_ESASR (0x3DB) +#define SPR_ESASRR (0x3DB) #define SPR_40x_PIT (0x3DB) #define SPR_403_TBL (0x3DC) #define SPR_403_TBU (0x3DD) @@ -1277,6 +874,10 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_40x_SRR2 (0x3DE) #define SPR_SER (0x3DF) #define SPR_40x_SRR3 (0x3DF) +#define SPR_L3ITCR0 (0x3E8) +#define SPR_L3ITCR1 (0x3E9) +#define SPR_L3ITCR2 (0x3EA) +#define SPR_L3ITCR3 (0x3EB) #define SPR_HID0 (0x3F0) #define SPR_40x_DBSR (0x3F0) #define SPR_HID1 (0x3F1) @@ -1284,9 +885,11 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_40x_DBCR0 (0x3F2) #define SPR_601_HID2 (0x3F2) #define SPR_E500_L1CSR0 (0x3F2) +#define SPR_ICTRL (0x3F3) #define SPR_HID2 (0x3F3) #define SPR_E500_L1CSR1 (0x3F3) #define SPR_440_DBDR (0x3F3) +#define SPR_LDSTDB (0x3F4) #define SPR_40x_IAC1 (0x3F4) #define SPR_BOOKE_MMUCSR0 (0x3F4) #define SPR_DABR (0x3F5) @@ -1295,12 +898,18 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_40x_IAC2 (0x3F5) #define SPR_601_HID5 (0x3F5) #define SPR_40x_DAC1 (0x3F6) +#define SPR_MSSCR0 (0x3F6) +#define SPR_MSSSR0 (0x3F7) #define SPR_DABRX (0x3F7) #define SPR_40x_DAC2 (0x3F7) #define SPR_BOOKE_MMUCFG (0x3F7) -#define SPR_L2PM (0x3F8) +#define SPR_LDSTCR (0x3F8) +#define SPR_L2PMCR (0x3F8) #define SPR_750_HID2 (0x3F8) +#define SPR_620_HID8 (0x3F8) #define SPR_L2CR (0x3F9) +#define SPR_620_HID9 (0x3F9) +#define SPR_L3CR (0x3FA) #define SPR_IABR2 (0x3FA) #define SPR_40x_DCCR (0x3FA) #define SPR_ICTC (0x3FB) @@ -1310,6 +919,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_SP (0x3FD) #define SPR_THRM2 (0x3FD) #define SPR_403_PBU1 (0x3FD) +#define SPR_604_HID13 (0x3FD) #define SPR_LT (0x3FE) #define SPR_THRM3 (0x3FE) #define SPR_FPECR (0x3FE) @@ -1317,6 +927,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_PIR (0x3FF) #define SPR_403_PBU2 (0x3FF) #define SPR_601_HID15 (0x3FF) +#define SPR_604_HID15 (0x3FF) #define SPR_E500_SVR (0x3FF) /*****************************************************************************/ @@ -1367,6 +978,11 @@ enum { #define EXCP_40x_DEBUG 0x2000 /* Debug exception */ /* 405 specific exceptions */ #define EXCP_405_APU 0x0F20 /* APU unavailable exception */ +/* 440 specific exceptions */ +#define EXCP_440_CRIT 0x0100 /* Critical interrupt */ +#define EXCP_440_SPEU 0x1600 /* SPE unavailable exception */ +#define EXCP_440_SPED 0x1700 /* SPE floating-point data exception */ +#define EXCP_440_SPER 0x1800 /* SPE floating-point round exception */ /* TLB assist exceptions (602/603) */ #define EXCP_I_TLBMISS 0x1000 /* Instruction TLB miss */ #define EXCP_DL_TLBMISS 0x1100 /* Data load TLB miss */ @@ -1377,7 +993,7 @@ enum { /* Altivec related exceptions */ #define EXCP_VPU 0x0F20 /* VPU unavailable exception */ /* 601 specific exceptions */ -#define EXCP_601_IO 0x0600 /* IO error exception */ +#define EXCP_601_IO 0x0A00 /* IO error exception */ #define EXCP_601_RUNM 0x2000 /* Run mode exception */ /* 602 specific exceptions */ #define EXCP_602_WATCHDOG 0x1500 /* Watchdog exception */ @@ -1467,6 +1083,15 @@ enum { PPCBookE_INPUT_CINT = 6, }; +enum { + /* PowerPC 401/403 input pins */ + PPC401_INPUT_RESET = 0, + PPC401_INPUT_CINT = 1, + PPC401_INPUT_INT = 2, + PPC401_INPUT_BERR = 3, + PPC401_INPUT_HALT = 4, +}; + enum { /* PowerPC 405 input pins */ PPC405_INPUT_RESET_CORE = 0, @@ -1478,6 +1103,18 @@ enum { PPC405_INPUT_DEBUG = 6, }; +enum { + /* PowerPC 620 (and probably others) input pins */ + PPC620_INPUT_HRESET = 0, + PPC620_INPUT_SRESET = 1, + PPC620_INPUT_CKSTP = 2, + PPC620_INPUT_TBEN = 3, + PPC620_INPUT_WAKEUP = 4, + PPC620_INPUT_MCP = 5, + PPC620_INPUT_SMI = 6, + PPC620_INPUT_INT = 7, +}; + enum { /* PowerPC 970 input pins */ PPC970_INPUT_HRESET = 0, diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 156693291..10a51e93c 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -106,6 +106,8 @@ void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1); void ppc4xx_tlb_invalidate_all (CPUState *env); +void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, + uint32_t pid); static inline void env_to_regs (void) { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 061db8760..f27a7f50a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -586,8 +586,8 @@ static int find_pte64 (mmu_ctx_t *ctx, int h, int rw) static inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw) { #if defined(TARGET_PPC64) - if (PPC_MMU(env) == PPC_FLAGS_MMU_64B || - PPC_MMU(env) == PPC_FLAGS_MMU_64BRIDGE) + if (env->mmu_model == POWERPC_MMU_64B || + env->mmu_model == POWERPC_MMU_64BRIDGE) return find_pte64(ctx, h, rw); #endif @@ -669,7 +669,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, int ret, ret2; #if defined(TARGET_PPC64) - if (PPC_MMU(env) == PPC_FLAGS_MMU_64B) { + if (env->mmu_model == POWERPC_MMU_64B) { ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); if (ret < 0) return ret; @@ -724,8 +724,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, hash = (~hash) & vsid_mask; ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask); #if defined(TARGET_PPC64) - if (PPC_MMU(env) == PPC_FLAGS_MMU_64B || - PPC_MMU(env) == PPC_FLAGS_MMU_64BRIDGE) { + if (env->mmu_model == POWERPC_MMU_64B || + env->mmu_model == POWERPC_MMU_64BRIDGE) { /* Only 5 bits of the page index are used in the AVPN */ ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); } else @@ -735,7 +735,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } /* Initialize real address with an invalid value */ ctx->raddr = (target_ulong)-1; - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { /* Software TLB search */ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); } else { @@ -865,7 +865,7 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) /* Default return value is no match */ ret = -1; - for (i = 0; i < 64; i++) { + for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) { ret = i; @@ -876,6 +876,26 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) return ret; } +void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, + uint32_t pid) +{ + ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + target_ulong page, end; + int i; + + for (i = 0; i < env->nb_tlb; i++) { + tlb = &env->tlb[i].tlbe; + if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { + end = tlb->EPN + tlb->size; + for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) + tlb_flush_page(env, page); + tlb->prot &= ~PAGE_VALID; + break; + } + } +} + /* Helpers specific to PowerPC 40x implementations */ void ppc4xx_tlb_invalidate_all (CPUState *env) { @@ -1069,23 +1089,23 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, ctx->raddr = eaddr; ctx->prot = PAGE_READ; ret = 0; - switch (PPC_MMU(env)) { - case PPC_FLAGS_MMU_32B: - case PPC_FLAGS_MMU_SOFT_6xx: - case PPC_FLAGS_MMU_601: - case PPC_FLAGS_MMU_SOFT_4xx: - case PPC_FLAGS_MMU_401: + switch (env->mmu_model) { + case POWERPC_MMU_32B: + case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_601: + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_REAL_4xx: ctx->prot |= PAGE_WRITE; break; #if defined(TARGET_PPC64) - case PPC_FLAGS_MMU_64B: - case PPC_FLAGS_MMU_64BRIDGE: + case POWERPC_MMU_64B: + case POWERPC_MMU_64BRIDGE: /* Real address are 60 bits long */ - ctx->raddr &= 0x0FFFFFFFFFFFFFFFUL; + ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; ctx->prot |= PAGE_WRITE; break; #endif - case PPC_FLAGS_MMU_403: + case POWERPC_MMU_SOFT_4xx_Z: if (unlikely(msr_pe != 0)) { /* 403 family add some particular protections, * using PBL/PBU registers for accesses with no translation. @@ -1108,10 +1128,10 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, ctx->prot |= PAGE_WRITE; } } - case PPC_FLAGS_MMU_BOOKE: + case POWERPC_MMU_BOOKE: ctx->prot |= PAGE_WRITE; break; - case PPC_FLAGS_MMU_BOOKE_FSL: + case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ cpu_abort(env, "BookE FSL MMU model not implemented\n"); break; @@ -1138,40 +1158,40 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, ret = check_physical(env, ctx, eaddr, rw); } else { ret = -1; - switch (PPC_MMU(env)) { - case PPC_FLAGS_MMU_32B: - case PPC_FLAGS_MMU_SOFT_6xx: + switch (env->mmu_model) { + case POWERPC_MMU_32B: + case POWERPC_MMU_SOFT_6xx: /* Try to find a BAT */ if (check_BATs) ret = get_bat(env, ctx, eaddr, rw, access_type); /* No break here */ #if defined(TARGET_PPC64) - case PPC_FLAGS_MMU_64B: - case PPC_FLAGS_MMU_64BRIDGE: + case POWERPC_MMU_64B: + case POWERPC_MMU_64BRIDGE: #endif if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ ret = get_segment(env, ctx, eaddr, rw, access_type); } break; - case PPC_FLAGS_MMU_SOFT_4xx: - case PPC_FLAGS_MMU_403: + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: ret = mmu40x_get_physical_address(env, ctx, eaddr, rw, access_type); break; - case PPC_FLAGS_MMU_601: + case POWERPC_MMU_601: /* XXX: TODO */ cpu_abort(env, "601 MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_BOOKE: + case POWERPC_MMU_BOOKE: ret = mmubooke_get_physical_address(env, ctx, eaddr, rw, access_type); break; - case PPC_FLAGS_MMU_BOOKE_FSL: + case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ cpu_abort(env, "BookE FSL MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_401: + case POWERPC_MMU_REAL_4xx: cpu_abort(env, "PowerPC 401 does not do any translation\n"); return -1; default: @@ -1234,46 +1254,46 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, switch (ret) { case -1: /* No matches in page tables or TLB */ - switch (PPC_MMU(env)) { - case PPC_FLAGS_MMU_SOFT_6xx: + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: exception = EXCP_I_TLBMISS; env->spr[SPR_IMISS] = address; env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; error_code = 1 << 18; goto tlb_miss; - case PPC_FLAGS_MMU_SOFT_4xx: - case PPC_FLAGS_MMU_403: + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: exception = EXCP_40x_ITLBMISS; error_code = 0; env->spr[SPR_40x_DEAR] = address; env->spr[SPR_40x_ESR] = 0x00000000; break; - case PPC_FLAGS_MMU_32B: + case POWERPC_MMU_32B: error_code = 0x40000000; break; #if defined(TARGET_PPC64) - case PPC_FLAGS_MMU_64B: + case POWERPC_MMU_64B: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_64BRIDGE: + case POWERPC_MMU_64BRIDGE: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; #endif - case PPC_FLAGS_MMU_601: + case POWERPC_MMU_601: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_BOOKE: + case POWERPC_MMU_BOOKE: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_BOOKE_FSL: + case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_401: + case POWERPC_MMU_REAL_4xx: cpu_abort(env, "PowerPC 401 should never raise any MMU " "exceptions\n"); return -1; @@ -1306,8 +1326,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, switch (ret) { case -1: /* No matches in page tables or TLB */ - switch (PPC_MMU(env)) { - case PPC_FLAGS_MMU_SOFT_6xx: + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: if (rw == 1) { exception = EXCP_DS_TLBMISS; error_code = 1 << 16; @@ -1323,8 +1343,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_HASH2] = ctx.pg_addr[1]; /* Do not alter DAR nor DSISR */ goto out; - case PPC_FLAGS_MMU_SOFT_4xx: - case PPC_FLAGS_MMU_403: + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: exception = EXCP_40x_DTLBMISS; error_code = 0; env->spr[SPR_40x_DEAR] = address; @@ -1333,32 +1353,32 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, else env->spr[SPR_40x_ESR] = 0x00000000; break; - case PPC_FLAGS_MMU_32B: + case POWERPC_MMU_32B: error_code = 0x40000000; break; #if defined(TARGET_PPC64) - case PPC_FLAGS_MMU_64B: + case POWERPC_MMU_64B: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_64BRIDGE: + case POWERPC_MMU_64BRIDGE: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; #endif - case PPC_FLAGS_MMU_601: + case POWERPC_MMU_601: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_BOOKE: + case POWERPC_MMU_BOOKE: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_BOOKE_FSL: + case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); return -1; - case PPC_FLAGS_MMU_401: + case POWERPC_MMU_REAL_4xx: cpu_abort(env, "PowerPC 401 should never raise any MMU " "exceptions\n"); return -1; @@ -1544,9 +1564,9 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) /* TLB management */ void ppc_tlb_invalidate_all (CPUPPCState *env) { - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { ppc6xx_tlb_invalidate_all(env); - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { ppc4xx_tlb_invalidate_all(env); } else { tlb_flush(env, 1); @@ -1707,9 +1727,11 @@ void do_store_msr (CPUPPCState *env, target_ulong value) fprintf(logfile, "%s: T0 %08lx\n", __func__, value); } #endif - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_602: - case PPC_FLAGS_EXCP_603: + switch (env->excp_model) { + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: if (((value >> MSR_TGPR) & 1) != msr_tgpr) { /* Swap temporary saved registers with GPRs */ swap_gpr_tgpr(env); @@ -1750,19 +1772,21 @@ void do_store_msr (CPUPPCState *env, target_ulong value) do_compute_hflags(env); enter_pm = 0; - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_603: + switch (env->excp_model) { + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: /* Don't handle SLEEP mode: we should disable all clocks... * No dynamic power-management. */ if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00C00000) != 0) enter_pm = 1; break; - case PPC_FLAGS_EXCP_604: + case POWERPC_EXCP_604: if (msr_pow == 1) enter_pm = 1; break; - case PPC_FLAGS_EXCP_7x0: + case POWERPC_EXCP_7x0: if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0) enter_pm = 1; break; @@ -1854,12 +1878,12 @@ void do_interrupt (CPUState *env) switch (excp) { /* Generic PowerPC exceptions */ case EXCP_RESET: /* 0x0100 */ - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: srr_0 = &env->spr[SPR_40x_SRR2]; srr_1 = &env->spr[SPR_40x_SRR3]; break; - case PPC_FLAGS_EXCP_BOOKE: + case POWERPC_EXCP_BOOKE: idx = 0; srr_0 = &env->spr[SPR_BOOKE_CSRR0]; srr_1 = &env->spr[SPR_BOOKE_CSRR1]; @@ -1872,12 +1896,12 @@ void do_interrupt (CPUState *env) } goto store_next; case EXCP_MACHINE_CHECK: /* 0x0200 */ - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: srr_0 = &env->spr[SPR_40x_SRR2]; srr_1 = &env->spr[SPR_40x_SRR3]; break; - case PPC_FLAGS_EXCP_BOOKE: + case POWERPC_EXCP_BOOKE: idx = 1; srr_0 = &env->spr[SPR_BOOKE_MCSRR0]; srr_1 = &env->spr[SPR_BOOKE_MCSRR1]; @@ -1920,7 +1944,7 @@ void do_interrupt (CPUState *env) idx = 4; goto store_next; case EXCP_ALIGN: /* 0x0600 */ - if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) { + if (likely(env->excp_model != POWERPC_EXCP_601)) { /* Store exception cause */ idx = 5; /* Get rS/rD and rA from faulting opcode */ @@ -2028,26 +2052,27 @@ void do_interrupt (CPUState *env) goto store_next; /* Implementation specific exceptions */ case 0x0A00: - if (likely(env->spr[SPR_PVR] == CPU_PPC_G2 || - env->spr[SPR_PVR] == CPU_PPC_G2LE)) { + switch (env->excp_model) { + case POWERPC_EXCP_G2: /* Critical interrupt on G2 */ /* XXX: TODO */ cpu_abort(env, "G2 critical interrupt is not implemented yet !\n"); goto store_next; - } else { + default: cpu_abort(env, "Invalid exception 0x0A00 !\n"); + break; } return; case 0x0F20: idx = 9; - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: /* APU unavailable on 405 */ /* XXX: TODO */ cpu_abort(env, "APU unavailable exception is not implemented yet !\n"); goto store_next; - case PPC_FLAGS_EXCP_74xx: + case POWERPC_EXCP_74xx: /* Altivec unavailable */ /* XXX: TODO */ cpu_abort(env, "Altivec unavailable exception " @@ -2060,8 +2085,8 @@ void do_interrupt (CPUState *env) return; case 0x1000: idx = 10; - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: /* PIT on 4xx */ msr &= ~0xFFFF0000; #if defined (DEBUG_EXCEPTIONS) @@ -2069,11 +2094,13 @@ void do_interrupt (CPUState *env) fprintf(logfile, "PIT exception\n"); #endif goto store_next; - case PPC_FLAGS_EXCP_602: - case PPC_FLAGS_EXCP_603: + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: /* ITLBMISS on 602/603 */ goto store_gprs; - case PPC_FLAGS_EXCP_7x5: + case POWERPC_EXCP_7x5: /* ITLBMISS on 745/755 */ goto tlb_miss; default: @@ -2083,8 +2110,8 @@ void do_interrupt (CPUState *env) return; case 0x1010: idx = 11; - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: /* FIT on 4xx */ msr &= ~0xFFFF0000; #if defined (DEBUG_EXCEPTIONS) @@ -2099,8 +2126,8 @@ void do_interrupt (CPUState *env) return; case 0x1020: idx = 12; - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: /* Watchdog on 4xx */ msr &= ~0xFFFF0000; #if defined (DEBUG_EXCEPTIONS) @@ -2108,7 +2135,7 @@ void do_interrupt (CPUState *env) fprintf(logfile, "WDT exception\n"); #endif goto store_next; - case PPC_FLAGS_EXCP_BOOKE: + case POWERPC_EXCP_BOOKE: srr_0 = &env->spr[SPR_BOOKE_CSRR0]; srr_1 = &env->spr[SPR_BOOKE_CSRR1]; break; @@ -2119,16 +2146,18 @@ void do_interrupt (CPUState *env) return; case 0x1100: idx = 13; - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: /* DTLBMISS on 4xx */ msr &= ~0xFFFF0000; goto store_next; - case PPC_FLAGS_EXCP_602: - case PPC_FLAGS_EXCP_603: + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: /* DLTLBMISS on 602/603 */ goto store_gprs; - case PPC_FLAGS_EXCP_7x5: + case POWERPC_EXCP_7x5: /* DLTLBMISS on 745/755 */ goto tlb_miss; default: @@ -2138,13 +2167,15 @@ void do_interrupt (CPUState *env) return; case 0x1200: idx = 14; - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: /* ITLBMISS on 4xx */ msr &= ~0xFFFF0000; goto store_next; - case PPC_FLAGS_EXCP_602: - case PPC_FLAGS_EXCP_603: + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: /* DSTLBMISS on 602/603 */ store_gprs: /* Swap temporary saved registers with GPRs */ @@ -2177,7 +2208,7 @@ void do_interrupt (CPUState *env) } #endif goto tlb_miss; - case PPC_FLAGS_EXCP_7x5: + case POWERPC_EXCP_7x5: /* DSTLBMISS on 745/755 */ tlb_miss: msr &= ~0xF83F0000; @@ -2192,13 +2223,15 @@ void do_interrupt (CPUState *env) } return; case 0x1300: - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_601: - case PPC_FLAGS_EXCP_602: - case PPC_FLAGS_EXCP_603: - case PPC_FLAGS_EXCP_604: - case PPC_FLAGS_EXCP_7x0: - case PPC_FLAGS_EXCP_7x5: + switch (env->excp_model) { + case POWERPC_EXCP_601: + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: + case POWERPC_EXCP_604: + case POWERPC_EXCP_7x0: + case POWERPC_EXCP_7x5: /* IABR on 6xx/7xx */ /* XXX: TODO */ cpu_abort(env, "IABR exception is not implemented yet !\n"); @@ -2209,13 +2242,15 @@ void do_interrupt (CPUState *env) } return; case 0x1400: - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_601: - case PPC_FLAGS_EXCP_602: - case PPC_FLAGS_EXCP_603: - case PPC_FLAGS_EXCP_604: - case PPC_FLAGS_EXCP_7x0: - case PPC_FLAGS_EXCP_7x5: + switch (env->excp_model) { + case POWERPC_EXCP_601: + case POWERPC_EXCP_602: + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: + case POWERPC_EXCP_604: + case POWERPC_EXCP_7x0: + case POWERPC_EXCP_7x5: /* SMI on 6xx/7xx */ /* XXX: TODO */ cpu_abort(env, "SMI exception is not implemented yet !\n"); @@ -2226,20 +2261,20 @@ void do_interrupt (CPUState *env) } return; case 0x1500: - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_602: + switch (env->excp_model) { + case POWERPC_EXCP_602: /* Watchdog on 602 */ /* XXX: TODO */ cpu_abort(env, "602 watchdog exception is not implemented yet !\n"); goto store_next; - case PPC_FLAGS_EXCP_970: + case POWERPC_EXCP_970: /* Soft patch exception on 970 */ /* XXX: TODO */ cpu_abort(env, "970 soft-patch exception is not implemented yet !\n"); goto store_next; - case PPC_FLAGS_EXCP_74xx: + case POWERPC_EXCP_74xx: /* VPU assist on 74xx */ /* XXX: TODO */ cpu_abort(env, "VPU assist exception is not implemented yet !\n"); @@ -2250,14 +2285,14 @@ void do_interrupt (CPUState *env) } return; case 0x1600: - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_602: + switch (env->excp_model) { + case POWERPC_EXCP_602: /* Emulation trap on 602 */ /* XXX: TODO */ cpu_abort(env, "602 emulation trap exception " "is not implemented yet !\n"); goto store_next; - case PPC_FLAGS_EXCP_970: + case POWERPC_EXCP_970: /* Maintenance exception on 970 */ /* XXX: TODO */ cpu_abort(env, @@ -2269,15 +2304,15 @@ void do_interrupt (CPUState *env) } return; case 0x1700: - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_7x0: - case PPC_FLAGS_EXCP_7x5: + switch (env->excp_model) { + case POWERPC_EXCP_7x0: + case POWERPC_EXCP_7x5: /* Thermal management interrupt on G3 */ /* XXX: TODO */ cpu_abort(env, "G3 thermal management exception " "is not implemented yet !\n"); goto store_next; - case PPC_FLAGS_EXCP_970: + case POWERPC_EXCP_970: /* VPU assist on 970 */ /* XXX: TODO */ cpu_abort(env, @@ -2289,8 +2324,8 @@ void do_interrupt (CPUState *env) } return; case 0x1800: - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_970: + switch (env->excp_model) { + case POWERPC_EXCP_970: /* Thermal exception on 970 */ /* XXX: TODO */ cpu_abort(env, "970 thermal management exception " @@ -2302,19 +2337,19 @@ void do_interrupt (CPUState *env) } return; case 0x2000: - switch (PPC_EXCP(env)) { - case PPC_FLAGS_EXCP_40x: + switch (env->excp_model) { + case POWERPC_EXCP_40x: /* DEBUG on 4xx */ /* XXX: TODO */ cpu_abort(env, "40x debug exception is not implemented yet !\n"); goto store_next; - case PPC_FLAGS_EXCP_601: + case POWERPC_EXCP_601: /* Run mode exception on 601 */ /* XXX: TODO */ cpu_abort(env, "601 run mode exception is not implemented yet !\n"); goto store_next; - case PPC_FLAGS_EXCP_BOOKE: + case POWERPC_EXCP_BOOKE: srr_0 = &env->spr[SPR_BOOKE_CSRR0]; srr_1 = &env->spr[SPR_BOOKE_CSRR1]; break; @@ -2361,7 +2396,7 @@ void do_interrupt (CPUState *env) msr_dr = 0; msr_ri = 0; msr_le = msr_ile; - if (PPC_EXCP(env) == PPC_FLAGS_EXCP_BOOKE) { + if (env->excp_model == POWERPC_EXCP_BOOKE) { msr_cm = msr_icm; if (idx == -1 || (idx >= 16 && idx < 32)) { cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n", diff --git a/target-ppc/op.c b/target-ppc/op.c index 593539bbf..93c463e30 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2319,7 +2319,6 @@ void OPPROTO op_405_check_satu (void) RETURN(); } -#if !defined(CONFIG_USER_ONLY) void OPPROTO op_load_dcr (void) { do_load_dcr(); @@ -2332,6 +2331,7 @@ void OPPROTO op_store_dcr (void) RETURN(); } +#if !defined(CONFIG_USER_ONLY) /* Return from critical interrupt : * same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1 */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 07b336b54..df00ba19c 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1206,6 +1206,41 @@ void do_405_check_sat (void) } } +/* XXX: to be improved to check access rights when in user-mode */ +void do_load_dcr (void) +{ + target_ulong val; + + if (unlikely(env->dcr_env == NULL)) { + if (loglevel != 0) { + fprintf(logfile, "No DCR environment\n"); + } + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); + } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) { + if (loglevel != 0) { + fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0); + } + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); + } else { + T0 = val; + } +} + +void do_store_dcr (void) +{ + if (unlikely(env->dcr_env == NULL)) { + if (loglevel != 0) { + fprintf(logfile, "No DCR environment\n"); + } + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); + } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) { + if (loglevel != 0) { + fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0); + } + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); + } +} + #if !defined(CONFIG_USER_ONLY) void do_40x_rfci (void) { @@ -1268,40 +1303,6 @@ void do_rfmci (void) env->interrupt_request = CPU_INTERRUPT_EXITTB; } -void do_load_dcr (void) -{ - target_ulong val; - - if (unlikely(env->dcr_env == NULL)) { - if (loglevel != 0) { - fprintf(logfile, "No DCR environment\n"); - } - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); - } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) { - if (loglevel != 0) { - fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0); - } - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); - } else { - T0 = val; - } -} - -void do_store_dcr (void) -{ - if (unlikely(env->dcr_env == NULL)) { - if (loglevel != 0) { - fprintf(logfile, "No DCR environment\n"); - } - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); - } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) { - if (loglevel != 0) { - fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0); - } - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); - } -} - void do_load_403_pb (int num) { T0 = env->pb[num]; @@ -2238,7 +2239,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) if (unlikely(ret != 0)) { if (likely(retaddr)) { /* now we have a real cpu fault */ - pc = (target_phys_addr_t)retaddr; + pc = (target_phys_addr_t)(unsigned long)retaddr; tb = tb_find_pc(pc); if (likely(tb)) { /* the PC is inside the translated code. It means that we have @@ -2261,16 +2262,14 @@ void do_tlbie (void) { T0 = (uint32_t)T0; #if !defined(FLUSH_ALL_TLBS) - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + /* XXX: Remove thoses tests */ + if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); if (env->id_tlbs == 1) ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1); - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { - /* XXX: TODO */ -#if 0 - ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, - env->spr[SPR_BOOKE_PID]); -#endif + } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { + ppc4xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, + env->spr[SPR_40x_PID]); } else { /* tlbie invalidate TLBs for all segments */ T0 &= TARGET_PAGE_MASK; @@ -2305,11 +2304,11 @@ void do_tlbie_64 (void) { T0 = (uint64_t)T0; #if !defined(FLUSH_ALL_TLBS) - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { + if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); if (env->id_tlbs == 1) ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1); - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { + } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { /* XXX: TODO */ #if 0 ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, @@ -2541,7 +2540,7 @@ void do_4xx_tlbwe_hi (void) "are not supported (%d)\n", tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7)); } - tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); + tlb->EPN = T1 & ~(tlb->size - 1); if (T1 & 0x40) tlb->prot |= PAGE_VALID; else @@ -2676,14 +2675,14 @@ void do_440_tlbwe (int word) void do_440_tlbsx (void) { - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]); + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF); } void do_440_tlbsx_ (void) { int tmp = xer_so; - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]); + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF); if (T0 != -1) tmp |= 0x02; env->crf[0] = tmp; diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 47f548e7b..4db8ac530 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -167,9 +167,9 @@ void do_440_tlbwe (int word); /* PowerPC 4xx specific helpers */ void do_405_check_ov (void); void do_405_check_sat (void); -#if !defined(CONFIG_USER_ONLY) void do_load_dcr (void); void do_store_dcr (void); +#if !defined(CONFIG_USER_ONLY) void do_40x_rfci (void); void do_rfci (void); void do_rfdi (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 9d6bf3206..4d98ea90b 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -27,11 +27,14 @@ #include "exec-all.h" #include "disas.h" +/* Include definitions for instructions classes and implementations flags */ //#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS //#define DEBUG_MEMORY_ACCESSES //#define DO_PPC_STATISTICS +/*****************************************************************************/ +/* Code translation helpers */ #if defined(USE_DIRECT_JUMP) #define TBPARAM(x) #else @@ -175,8 +178,10 @@ struct opc_handler_t { uint64_t type; /* handler */ void (*handler)(DisasContext *ctx); -#if defined(DO_PPC_STATISTICS) +#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) const unsigned char *oname; +#endif +#if defined(DO_PPC_STATISTICS) uint64_t count; #endif }; @@ -249,6 +254,7 @@ typedef struct opcode_t { const unsigned char *oname; } opcode_t; +/*****************************************************************************/ /*** Instruction decoding ***/ #define EXTRACT_HELPER(name, shift, nb) \ static inline uint32_t name (uint32_t opcode) \ @@ -365,6 +371,106 @@ static inline target_ulong MASK (uint32_t start, uint32_t end) return ret; } +/*****************************************************************************/ +/* PowerPC Instructions types definitions */ +enum { + PPC_NONE = 0x0000000000000000ULL, + /* integer operations instructions */ + /* flow control instructions */ + /* virtual memory instructions */ + /* ld/st with reservation instructions */ + /* cache control instructions */ + /* spr/msr access instructions */ + PPC_INSNS_BASE = 0x0000000000000001ULL, +#define PPC_INTEGER PPC_INSNS_BASE +#define PPC_FLOW PPC_INSNS_BASE +#define PPC_MEM PPC_INSNS_BASE +#define PPC_RES PPC_INSNS_BASE +#define PPC_CACHE PPC_INSNS_BASE +#define PPC_MISC PPC_INSNS_BASE + /* Optional floating point instructions */ + PPC_FLOAT = 0x0000000000000002ULL, + PPC_FLOAT_FSQRT = 0x0000000000000004ULL, + PPC_FLOAT_FRES = 0x0000000000000008ULL, + PPC_FLOAT_FRSQRTE = 0x0000000000000010ULL, + PPC_FLOAT_FSEL = 0x0000000000000020ULL, + PPC_FLOAT_STFIWX = 0x0000000000000040ULL, + /* external control instructions */ + PPC_EXTERN = 0x0000000000000080ULL, + /* segment register access instructions */ + PPC_SEGMENT = 0x0000000000000100ULL, + /* Optional cache control instruction */ + PPC_CACHE_DCBA = 0x0000000000000200ULL, + /* Optional memory control instructions */ + PPC_MEM_TLBIA = 0x0000000000000400ULL, + PPC_MEM_TLBIE = 0x0000000000000800ULL, + PPC_MEM_TLBSYNC = 0x0000000000001000ULL, + /* eieio & sync */ + PPC_MEM_SYNC = 0x0000000000002000ULL, + /* PowerPC 6xx TLB management instructions */ + PPC_6xx_TLB = 0x0000000000004000ULL, + /* Altivec support */ + PPC_ALTIVEC = 0x0000000000008000ULL, + /* Time base mftb instruction */ + PPC_MFTB = 0x0000000000010000ULL, + /* Embedded PowerPC dedicated instructions */ + PPC_EMB_COMMON = 0x0000000000020000ULL, + /* PowerPC 40x exception model */ + PPC_40x_EXCP = 0x0000000000040000ULL, + /* PowerPC 40x TLB management instructions */ + PPC_40x_TLB = 0x0000000000080000ULL, + /* PowerPC 405 Mac instructions */ + PPC_405_MAC = 0x0000000000100000ULL, + /* PowerPC 440 specific instructions */ + PPC_440_SPEC = 0x0000000000200000ULL, + /* Power-to-PowerPC bridge (601) */ + PPC_POWER_BR = 0x0000000000400000ULL, + /* PowerPC 602 specific */ + PPC_602_SPEC = 0x0000000000800000ULL, + /* Deprecated instructions */ + /* Original POWER instruction set */ + PPC_POWER = 0x0000000001000000ULL, + /* POWER2 instruction set extension */ + PPC_POWER2 = 0x0000000002000000ULL, + /* Power RTC support */ + PPC_POWER_RTC = 0x0000000004000000ULL, + /* 64 bits PowerPC instructions */ + /* 64 bits PowerPC instruction set */ + PPC_64B = 0x0000000008000000ULL, + /* 64 bits hypervisor extensions */ + PPC_64H = 0x0000000010000000ULL, + /* 64 bits PowerPC "bridge" features */ + PPC_64_BRIDGE = 0x0000000020000000ULL, + /* BookE (embedded) PowerPC specification */ + PPC_BOOKE = 0x0000000040000000ULL, + /* eieio */ + PPC_MEM_EIEIO = 0x0000000080000000ULL, + /* e500 vector instructions */ + PPC_E500_VECTOR = 0x0000000100000000ULL, + /* PowerPC 4xx dedicated instructions */ + PPC_4xx_COMMON = 0x0000000200000000ULL, + /* PowerPC 2.03 specification extensions */ + PPC_203 = 0x0000000400000000ULL, + /* PowerPC 2.03 SPE extension */ + PPC_SPE = 0x0000000800000000ULL, + /* PowerPC 2.03 SPE floating-point extension */ + PPC_SPEFPU = 0x0000001000000000ULL, + /* SLB management */ + PPC_SLBI = 0x0000002000000000ULL, + /* PowerPC 40x ibct instructions */ + PPC_40x_ICBT = 0x0000004000000000ULL, + /* PowerPC 74xx TLB management instructions */ + PPC_74xx_TLB = 0x0000008000000000ULL, + /* More BookE (embedded) instructions... */ + PPC_BOOKE_EXT = 0x0000010000000000ULL, + /* rfmci is not implemented in all BookE PowerPC */ + PPC_RFMCI = 0x0000020000000000ULL, + /* user-mode DCR access, implemented in PowerPC 460 */ + PPC_DCRUX = 0x0000040000000000ULL, +}; + +/*****************************************************************************/ +/* PowerPC instructions table */ #if HOST_LONG_BITS == 64 #define OPC_ALIGN 8 #else @@ -845,15 +951,15 @@ GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) #if defined(TARGET_PPC64) /* mulhd mulhd. */ -GEN_INT_ARITHN (mulhd, 0x1F, 0x09, 0x02, PPC_INTEGER); +GEN_INT_ARITHN (mulhd, 0x1F, 0x09, 0x02, PPC_64B); /* mulhdu mulhdu. */ -GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_INTEGER); +GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_64B); /* mulld mulld. mulldo mulldo. */ -GEN_INT_ARITH2 (mulld, 0x1F, 0x09, 0x07, PPC_INTEGER); +GEN_INT_ARITH2 (mulld, 0x1F, 0x09, 0x07, PPC_64B); /* divd divd. divdo divdo. */ -GEN_INT_ARITH2 (divd, 0x1F, 0x09, 0x0F, PPC_INTEGER); +GEN_INT_ARITH2 (divd, 0x1F, 0x09, 0x0F, PPC_64B); /* divdu divdu. divduo divduo. */ -GEN_INT_ARITH2 (divdu, 0x1F, 0x09, 0x0E, PPC_INTEGER); +GEN_INT_ARITH2 (divdu, 0x1F, 0x09, 0x0E, PPC_64B); #endif /*** Integer comparison ***/ @@ -1424,8 +1530,8 @@ __GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B); #endif /*** Floating-Point arithmetic ***/ -#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \ -GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ +#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, type) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ @@ -1444,9 +1550,9 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ gen_op_set_Rc1(); \ } -#define GEN_FLOAT_ACB(name, op2) \ -_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \ -_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1); +#define GEN_FLOAT_ACB(name, op2, type) \ +_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, type); \ +_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, type); #define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ @@ -1492,8 +1598,8 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ _GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \ _GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1); -#define GEN_FLOAT_B(name, op2, op3) \ -GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ +#define GEN_FLOAT_B(name, op2, op3, type) \ +GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ @@ -1507,8 +1613,8 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ gen_op_set_Rc1(); \ } -#define GEN_FLOAT_BS(name, op1, op2) \ -GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ +#define GEN_FLOAT_BS(name, op1, op2, type) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ @@ -1529,19 +1635,19 @@ GEN_FLOAT_AB(div, 0x12, 0x000007C0); /* fmul - fmuls */ GEN_FLOAT_AC(mul, 0x19, 0x0000F800); -/* fres */ /* XXX: not in 601 */ -GEN_FLOAT_BS(res, 0x3B, 0x18); +/* fres */ +GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES); -/* frsqrte */ /* XXX: not in 601 */ -GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A); +/* frsqrte */ +GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, PPC_FLOAT_FRSQRTE); -/* fsel */ /* XXX: not in 601 */ -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0); +/* fsel */ +_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL); /* fsub - fsubs */ GEN_FLOAT_AB(sub, 0x14, 0x000007C0); /* Optional: */ /* fsqrt */ -GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) +GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) { if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); @@ -1555,7 +1661,7 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) gen_op_set_Rc1(); } -GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) +GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) { if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); @@ -1572,28 +1678,28 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) /*** Floating-Point multiply-and-add ***/ /* fmadd - fmadds */ -GEN_FLOAT_ACB(madd, 0x1D); +GEN_FLOAT_ACB(madd, 0x1D, PPC_FLOAT); /* fmsub - fmsubs */ -GEN_FLOAT_ACB(msub, 0x1C); +GEN_FLOAT_ACB(msub, 0x1C, PPC_FLOAT); /* fnmadd - fnmadds */ -GEN_FLOAT_ACB(nmadd, 0x1F); +GEN_FLOAT_ACB(nmadd, 0x1F, PPC_FLOAT); /* fnmsub - fnmsubs */ -GEN_FLOAT_ACB(nmsub, 0x1E); +GEN_FLOAT_ACB(nmsub, 0x1E, PPC_FLOAT); /*** Floating-Point round & convert ***/ /* fctiw */ -GEN_FLOAT_B(ctiw, 0x0E, 0x00); +GEN_FLOAT_B(ctiw, 0x0E, 0x00, PPC_FLOAT); /* fctiwz */ -GEN_FLOAT_B(ctiwz, 0x0F, 0x00); +GEN_FLOAT_B(ctiwz, 0x0F, 0x00, PPC_FLOAT); /* frsp */ -GEN_FLOAT_B(rsp, 0x0C, 0x00); +GEN_FLOAT_B(rsp, 0x0C, 0x00, PPC_FLOAT); #if defined(TARGET_PPC64) /* fcfid */ -GEN_FLOAT_B(cfid, 0x0E, 0x1A); +GEN_FLOAT_B(cfid, 0x0E, 0x1A, PPC_64B); /* fctid */ -GEN_FLOAT_B(ctid, 0x0E, 0x19); +GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B); /* fctidz */ -GEN_FLOAT_B(ctidz, 0x0F, 0x19); +GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B); #endif /*** Floating-Point compare ***/ @@ -1627,7 +1733,7 @@ GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) /*** Floating-point move ***/ /* fabs */ -GEN_FLOAT_B(abs, 0x08, 0x08); +GEN_FLOAT_B(abs, 0x08, 0x08, PPC_FLOAT); /* fmr - fmr. */ GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) @@ -1644,9 +1750,9 @@ GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) } /* fnabs */ -GEN_FLOAT_B(nabs, 0x08, 0x04); +GEN_FLOAT_B(nabs, 0x08, 0x04, PPC_FLOAT); /* fneg */ -GEN_FLOAT_B(neg, 0x08, 0x01); +GEN_FLOAT_B(neg, 0x08, 0x01, PPC_FLOAT); /*** Floating-Point status & ctrl register ***/ /* mcrfs */ @@ -2426,7 +2532,7 @@ static GenOpFunc *gen_op_stdcx[] = { #endif /* ldarx */ -GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_RES) +GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B) { gen_addr_reg_index(ctx); op_ldarx(); @@ -2434,7 +2540,7 @@ GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_RES) } /* stdcx. */ -GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_RES) +GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B) { gen_addr_reg_index(ctx); gen_op_load_gpr_T1(rS(ctx->opcode)); @@ -2591,7 +2697,7 @@ GEN_STFS(fs, 0x14); /* Optional: */ /* stfiwx */ -GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) +GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT_STFIWX) { if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); @@ -2886,7 +2992,7 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) } #if defined(TARGET_PPC64) -GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW) +GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -3050,7 +3156,7 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) } /* mftb */ -GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB) +GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB) { gen_op_mfspr(ctx); } @@ -3074,7 +3180,7 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) /* mtmsr */ #if defined(TARGET_PPC64) -GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_MISC) +GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_64B) { #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); @@ -3296,7 +3402,7 @@ GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) /* Optional: */ /* dcba */ -GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT) +GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA) { } @@ -3568,7 +3674,7 @@ GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR) } /* clcs */ -GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */ +GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_POWER_clcs(); @@ -4222,14 +4328,14 @@ GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2) /* BookE specific instructions */ /* XXX: not implemented on 440 ? */ -GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE) +GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE_EXT) { /* XXX: TODO */ RET_INVAL(ctx); } /* XXX: not implemented on 440 ? */ -GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE) +GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE_EXT) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4331,99 +4437,98 @@ static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3, } } -#define GEN_MAC_HANDLER(name, opc2, opc3, is_440) \ -GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, \ - is_440 ? PPC_440_SPEC : PPC_405_MAC) \ +#define GEN_MAC_HANDLER(name, opc2, opc3) \ +GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC) \ { \ gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode), \ rD(ctx->opcode), Rc(ctx->opcode)); \ } /* macchw - macchw. */ -GEN_MAC_HANDLER(macchw, 0x0C, 0x05, 0); +GEN_MAC_HANDLER(macchw, 0x0C, 0x05); /* macchwo - macchwo. */ -GEN_MAC_HANDLER(macchwo, 0x0C, 0x15, 0); +GEN_MAC_HANDLER(macchwo, 0x0C, 0x15); /* macchws - macchws. */ -GEN_MAC_HANDLER(macchws, 0x0C, 0x07, 0); +GEN_MAC_HANDLER(macchws, 0x0C, 0x07); /* macchwso - macchwso. */ -GEN_MAC_HANDLER(macchwso, 0x0C, 0x17, 0); +GEN_MAC_HANDLER(macchwso, 0x0C, 0x17); /* macchwsu - macchwsu. */ -GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06, 0); +GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06); /* macchwsuo - macchwsuo. */ -GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16, 0); +GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16); /* macchwu - macchwu. */ -GEN_MAC_HANDLER(macchwu, 0x0C, 0x04, 0); +GEN_MAC_HANDLER(macchwu, 0x0C, 0x04); /* macchwuo - macchwuo. */ -GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14, 0); +GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14); /* machhw - machhw. */ -GEN_MAC_HANDLER(machhw, 0x0C, 0x01, 0); +GEN_MAC_HANDLER(machhw, 0x0C, 0x01); /* machhwo - machhwo. */ -GEN_MAC_HANDLER(machhwo, 0x0C, 0x11, 0); +GEN_MAC_HANDLER(machhwo, 0x0C, 0x11); /* machhws - machhws. */ -GEN_MAC_HANDLER(machhws, 0x0C, 0x03, 0); +GEN_MAC_HANDLER(machhws, 0x0C, 0x03); /* machhwso - machhwso. */ -GEN_MAC_HANDLER(machhwso, 0x0C, 0x13, 0); +GEN_MAC_HANDLER(machhwso, 0x0C, 0x13); /* machhwsu - machhwsu. */ -GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02, 0); +GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02); /* machhwsuo - machhwsuo. */ -GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12, 0); +GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12); /* machhwu - machhwu. */ -GEN_MAC_HANDLER(machhwu, 0x0C, 0x00, 0); +GEN_MAC_HANDLER(machhwu, 0x0C, 0x00); /* machhwuo - machhwuo. */ -GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10, 0); +GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10); /* maclhw - maclhw. */ -GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D, 0); +GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D); /* maclhwo - maclhwo. */ -GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D, 0); +GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D); /* maclhws - maclhws. */ -GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F, 0); +GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F); /* maclhwso - maclhwso. */ -GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F, 0); +GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F); /* maclhwu - maclhwu. */ -GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C, 0); +GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C); /* maclhwuo - maclhwuo. */ -GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C, 0); +GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C); /* maclhwsu - maclhwsu. */ -GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E, 0); +GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E); /* maclhwsuo - maclhwsuo. */ -GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E, 0); +GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E); /* nmacchw - nmacchw. */ -GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05, 0); +GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05); /* nmacchwo - nmacchwo. */ -GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15, 0); +GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15); /* nmacchws - nmacchws. */ -GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07, 0); +GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07); /* nmacchwso - nmacchwso. */ -GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17, 0); +GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17); /* nmachhw - nmachhw. */ -GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01, 0); +GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01); /* nmachhwo - nmachhwo. */ -GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11, 0); +GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11); /* nmachhws - nmachhws. */ -GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03, 1); +GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03); /* nmachhwso - nmachhwso. */ -GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13, 1); +GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13); /* nmaclhw - nmaclhw. */ -GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D, 1); +GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D); /* nmaclhwo - nmaclhwo. */ -GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D, 1); +GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D); /* nmaclhws - nmaclhws. */ -GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F, 1); +GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F); /* nmaclhwso - nmaclhwso. */ -GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F, 1); +GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F); /* mulchw - mulchw. */ -GEN_MAC_HANDLER(mulchw, 0x08, 0x05, 0); +GEN_MAC_HANDLER(mulchw, 0x08, 0x05); /* mulchwu - mulchwu. */ -GEN_MAC_HANDLER(mulchwu, 0x08, 0x04, 0); +GEN_MAC_HANDLER(mulchwu, 0x08, 0x04); /* mulhhw - mulhhw. */ -GEN_MAC_HANDLER(mulhhw, 0x08, 0x01, 0); +GEN_MAC_HANDLER(mulhhw, 0x08, 0x01); /* mulhhwu - mulhhwu. */ -GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00, 0); +GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00); /* mullhw - mullhw. */ -GEN_MAC_HANDLER(mullhw, 0x08, 0x0D, 0); +GEN_MAC_HANDLER(mullhw, 0x08, 0x0D); /* mullhwu - mullhwu. */ -GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C, 0); +GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C); /* mfdcr */ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) @@ -4463,7 +4568,7 @@ GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) /* mfdcrx */ /* XXX: not implemented on 440 ? */ -GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE) +GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT) { #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); @@ -4475,12 +4580,13 @@ GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE) gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_dcr(); gen_op_store_T0_gpr(rD(ctx->opcode)); + /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif } /* mtdcrx */ /* XXX: not implemented on 440 ? */ -GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000001, PPC_BOOKE) +GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_BOOKE_EXT) { #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); @@ -4492,9 +4598,28 @@ GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000001, PPC_BOOKE) gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rS(ctx->opcode)); gen_op_store_dcr(); + /* Note: Rc update flag set leads to undefined state of Rc0 */ #endif } +/* mfdcrux (PPC 460) : user-mode access to DCR */ +GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_dcr(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + /* Note: Rc update flag set leads to undefined state of Rc0 */ +} + +/* mtdcrux (PPC 460) : user-mode access to DCR */ +GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_store_dcr(); + /* Note: Rc update flag set leads to undefined state of Rc0 */ +} + /* dccci */ GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON) { @@ -4595,7 +4720,7 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE) /* BookE specific */ /* XXX: not implemented on 440 ? */ -GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE) +GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE_EXT) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4611,7 +4736,7 @@ GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE) } /* XXX: not implemented on 440 ? */ -GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE) +GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4628,7 +4753,7 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE) /* TLB management - PowerPC 405 implementation */ /* tlbre */ -GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) +GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4656,7 +4781,7 @@ GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) } /* tlbsx - tlbsx. */ -GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) +GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4675,7 +4800,7 @@ GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) } /* tlbwe */ -GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) +GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -5701,7 +5826,7 @@ void cpu_dump_state (CPUState *env, FILE *f, for (i = 0; i < 32; i++) { if ((i & (RGPL - 1)) == 0) cpu_fprintf(f, "GPR%02d", i); - cpu_fprintf(f, " " REGX, env->gpr[i]); + cpu_fprintf(f, " " REGX, (target_ulong)env->gpr[i]); if ((i & (RGPL - 1)) == (RGPL - 1)) cpu_fprintf(f, "\n"); } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 82270e659..c6f09aea5 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -32,20 +32,26 @@ struct ppc_def_t { uint32_t pvr; uint32_t pvr_mask; uint64_t insns_flags; - uint32_t flags; uint64_t msr_mask; + uint8_t mmu_model; + uint8_t excp_model; + uint8_t bus_model; + uint8_t pad; + void (*init_proc)(CPUPPCState *env); }; /* For user-mode emulation, we don't emulate any IRQ controller */ #if defined(CONFIG_USER_ONLY) -#define PPC_IRQ_INIT_FN(name) \ -static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \ -{ \ +#define PPC_IRQ_INIT_FN(name) \ +static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \ +{ \ } #else -#define PPC_IRQ_INIT_FN(name) \ +#define PPC_IRQ_INIT_FN(name) \ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); #endif + +PPC_IRQ_INIT_FN(401); PPC_IRQ_INIT_FN(405); PPC_IRQ_INIT_FN(6xx); PPC_IRQ_INIT_FN(970); @@ -285,7 +291,7 @@ static void spr_write_asr (void *opaque, int sprn) RET_STOP(ctx); } #endif -#endif /* !defined(CONFIG_USER_ONLY) */ +#endif /* PowerPC 601 specific registers */ /* RTC */ @@ -582,7 +588,7 @@ static void gen_low_BATs (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_dbat, &spr_write_dbatl, 0x00000000); - env->nb_BATs = 4; + env->nb_BATs += 4; } /* BATs 4-7 */ @@ -652,7 +658,7 @@ static void gen_high_BATs (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_dbat_h, &spr_write_dbatl_h, 0x00000000); - env->nb_BATs = 8; + env->nb_BATs += 4; } /* Generic PowerPC time base */ @@ -797,7 +803,7 @@ static void gen_spr_7xx (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_SIA, "SIA", + spr_register(env, SPR_SIAR, "SIAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); @@ -825,29 +831,33 @@ static void gen_spr_7xx (CPUPPCState *env) &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - spr_register(env, SPR_USIA, "USIA", + spr_register(env, SPR_USIAR, "USIAR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); - /* Thermal management */ + /* External access control */ /* XXX : not implemented */ - spr_register(env, SPR_THRM1, "THRM1", + spr_register(env, SPR_EAR, "EAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); +} + +static void gen_spr_thrm (CPUPPCState *env) +{ + /* Thermal management */ /* XXX : not implemented */ - spr_register(env, SPR_THRM2, "THRM2", + spr_register(env, SPR_THRM1, "THRM1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_THRM3, "THRM3", + spr_register(env, SPR_THRM2, "THRM2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* External access control */ /* XXX : not implemented */ - spr_register(env, SPR_EAR, "EAR", + spr_register(env, SPR_THRM3, "THRM3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -904,7 +914,7 @@ static void gen_spr_604 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_SIA, "SIA", + spr_register(env, SPR_SIAR, "SIAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); @@ -1004,7 +1014,7 @@ static void gen_spr_602 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_ESASR, "ESASR", + spr_register(env, SPR_ESASRR, "ESASRR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -1030,6 +1040,11 @@ static void gen_spr_602 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } /* SPR specific to PowerPC 601 implementation */ @@ -1104,7 +1119,116 @@ static void gen_spr_601 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_601_ubat, &spr_write_601_ubatl, 0x00000000); + env->nb_BATs = 4; +} + +static void gen_spr_74xx (CPUPPCState *env) +{ + /* Processor identification */ + spr_register(env, SPR_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MMCR2, "MMCR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UMMCR2, "UMMCR2", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* XXX: not implemented */ + spr_register(env, SPR_BAMR, "BAMR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UBAMR, "UBAMR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_MSSCR0, "MSSCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Altivec */ + spr_register(env, SPR_VRSAVE, "VRSAVE", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +#if defined (TODO) +static void gen_l3_ctrl (CPUPPCState *env) +{ + /* L3CR */ + /* XXX : not implemented */ + spr_register(env, SPR_L3CR, "L3CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3ITCR0 */ + spr_register(env, SPR_L3ITCR0, "L3ITCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3ITCR1 */ + spr_register(env, SPR_L3ITCR1, "L3ITCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3ITCR2 */ + spr_register(env, SPR_L3ITCR2, "L3ITCR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3ITCR3 */ + spr_register(env, SPR_L3ITCR3, "L3ITCR3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3OHCR */ + spr_register(env, SPR_L3OHCR, "L3OHCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3PM */ + spr_register(env, SPR_L3PM, "L3PM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} +#endif /* TODO */ + +#if defined (TODO) +static void gen_74xx_soft_tlb (CPUPPCState *env) +{ + /* XXX: TODO */ + spr_register(env, SPR_PTEHI, "PTEHI", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_PTELO, "PTELO", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_TLBMISS, "TLBMISS", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } +#endif /* TODO */ /* PowerPC BookE SPR */ static void gen_spr_BookE (CPUPPCState *env) @@ -1132,14 +1256,6 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); #endif /* Debug */ /* XXX : not implemented */ @@ -1366,6 +1482,7 @@ static void gen_spr_BookE (CPUPPCState *env) } /* FSL storage control registers */ +#if defined(TODO) static void gen_spr_BookE_FSL (CPUPPCState *env) { /* TLB assist registers */ @@ -1447,6 +1564,7 @@ static void gen_spr_BookE_FSL (CPUPPCState *env) break; } } +#endif /* SPR specific to PowerPC 440 implementation */ static void gen_spr_440 (CPUPPCState *env) @@ -1599,11 +1717,6 @@ static void gen_spr_40x (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_40x_DCWR, "DCWR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_40x_ICCR, "ICCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1613,11 +1726,6 @@ static void gen_spr_40x (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); - /* Bus access control */ - spr_register(env, SPR_40x_SGR, "SGR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0xFFFFFFFF); /* Exception */ spr_register(env, SPR_40x_DEAR, "DEAR", SPR_NOACCESS, SPR_NOACCESS, @@ -1834,6 +1942,19 @@ static void gen_spr_401 (CPUPPCState *env) 0x00000000); } +static void gen_spr_401x2 (CPUPPCState *env) +{ + gen_spr_401(env); + spr_register(env, SPR_40x_PID, "PID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_ZPR, "ZPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + /* SPR specific to PowerPC 403 implementation */ static void gen_spr_403 (CPUPPCState *env) { @@ -1867,11 +1988,10 @@ static void gen_spr_403 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* MMU */ - spr_register(env, SPR_40x_PID, "PID", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); +} + +static void gen_spr_403_real (CPUPPCState *env) +{ spr_register(env, SPR_403_PBL1, "PBL1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_403_pbr, &spr_write_403_pbr, @@ -1888,6 +2008,15 @@ static void gen_spr_403 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_403_pbr, &spr_write_403_pbr, 0x00000000); +} + +static void gen_spr_403_mmu (CPUPPCState *env) +{ + /* MMU */ + spr_register(env, SPR_40x_PID, "PID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); spr_register(env, SPR_40x_ZPR, "ZPR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1895,7 +2024,6 @@ static void gen_spr_403 (CPUPPCState *env) } /* SPR specific to PowerPC compression coprocessor extension */ -#if defined (TODO) static void gen_spr_compress (CPUPPCState *env) { spr_register(env, SPR_401_SKR, "SKR", @@ -1903,14 +2031,93 @@ static void gen_spr_compress (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); } + +#if defined (TARGET_PPC64) +#if defined (TODO) +/* SPR specific to PowerPC 620 */ +static void gen_spr_620 (CPUPPCState *env) +{ + spr_register(env, SPR_620_PMR0, "PMR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR1, "PMR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR2, "PMR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR3, "PMR3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR4, "PMR4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR5, "PMR5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR6, "PMR6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR7, "PMR7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR8, "PMR8", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMR9, "PMR9", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMRA, "PMR10", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMRB, "PMR11", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMRC, "PMR12", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMRD, "PMR13", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMRE, "PMR14", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_PMRF, "PMR15", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_HID8, "HID8", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_620_HID9, "HID9", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} #endif +#endif /* defined (TARGET_PPC64) */ // XXX: TODO /* * AMR => SPR 29 (Power 2.04) * CTRL => SPR 136 (Power 2.04) * CTRL => SPR 152 (Power 2.04) - * VRSAVE => SPR 256 (Altivec) * SCOMC => SPR 276 (64 bits ?) * SCOMD => SPR 277 (64 bits ?) * ASR => SPR 280 (64 bits) @@ -1942,2397 +2149,3341 @@ static void gen_spr_compress (CPUPPCState *env) * ... and more (thermal management, performance counters, ...) */ -static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) -{ - env->reserve = -1; - /* Default MMU definitions */ - env->nb_BATs = -1; - env->nb_tlb = 0; - env->nb_ways = 0; - /* XXX: missing: - * 32 bits PowerPC: - * - MPC5xx(x) - * - MPC8xx(x) - * - RCPU (same as MPC5xx ?) - */ - spr_register(env, SPR_PVR, "PVR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - def->pvr); - printf("%s: PVR %08x mask %08x => %08x\n", __func__, - def->pvr, def->pvr_mask, def->pvr & def->pvr_mask); - switch (def->pvr) { - /* Embedded PowerPC from IBM */ - case CPU_PPC_401A1: /* 401 A1 family */ - case CPU_PPC_401B2: /* 401 B2 family */ -#if 0 - case CPU_PPC_401B3: /* 401 B3 family */ -#endif - case CPU_PPC_401C2: /* 401 C2 family */ - case CPU_PPC_401D2: /* 401 D2 family */ - case CPU_PPC_401E2: /* 401 E2 family */ - case CPU_PPC_401F2: /* 401 F2 family */ - case CPU_PPC_401G2: /* 401 G2 family */ - case CPU_PPC_IOP480: /* IOP 480 family */ - case CPU_PPC_COBRA: /* IBM Processor for Network Resources */ - gen_spr_generic(env); - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401(env); -#if defined (TODO) - /* XXX: optional ? */ - gen_spr_compress(env); -#endif - env->nb_BATs = 0; - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; - /* XXX: TODO: allocate internal IRQ controller */ - break; - - case CPU_PPC_403GA: /* 403 GA family */ - case CPU_PPC_403GB: /* 403 GB family */ - case CPU_PPC_403GC: /* 403 GC family */ - case CPU_PPC_403GCX: /* 403 GCX family */ - gen_spr_generic(env); - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_403(env); - env->nb_BATs = 0; - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; - /* XXX: TODO: allocate internal IRQ controller */ - break; - - case CPU_PPC_405CR: /* 405 GP/CR family */ - case CPU_PPC_405EP: /* 405 EP family */ - case CPU_PPC_405GPR: /* 405 GPR family */ - case CPU_PPC_405D2: /* 405 D2 family */ - case CPU_PPC_405D4: /* 405 D4 family */ - gen_spr_generic(env); - /* Time base */ - gen_tbl(env); - gen_spr_40x(env); - gen_spr_405(env); - env->nb_BATs = 0; - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; - /* Allocate hardware IRQ controller */ - ppc405_irq_init(env); - break; +/*****************************************************************************/ +/* PowerPC implementations definitions */ - case CPU_PPC_NPE405H: /* NPe405 H family */ - case CPU_PPC_NPE405H2: - case CPU_PPC_NPE405L: /* Npe405 L family */ - gen_spr_generic(env); - /* Time base */ - gen_tbl(env); - gen_spr_40x(env); - gen_spr_405(env); - env->nb_BATs = 0; - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; - /* Allocate hardware IRQ controller */ - ppc405_irq_init(env); - break; +/* PowerPC 40x instruction set */ +#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_EMB_COMMON) -#if defined (TODO) - case CPU_PPC_STB01000: -#endif -#if defined (TODO) - case CPU_PPC_STB01010: -#endif -#if defined (TODO) - case CPU_PPC_STB0210: -#endif - case CPU_PPC_STB03: /* STB03 family */ -#if defined (TODO) - case CPU_PPC_STB043: /* STB043 family */ -#endif -#if defined (TODO) - case CPU_PPC_STB045: /* STB045 family */ -#endif - case CPU_PPC_STB25: /* STB25 family */ -#if defined (TODO) - case CPU_PPC_STB130: /* STB130 family */ -#endif - gen_spr_generic(env); - /* Time base */ - gen_tbl(env); - gen_spr_40x(env); - gen_spr_405(env); - env->nb_BATs = 0; - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; - /* Allocate hardware IRQ controller */ - ppc405_irq_init(env); - break; +/* PowerPC 401 */ +#define POWERPC_INSNS_401 (POWERPC_INSNS_EMB | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_401 (0x00000000000FD201ULL) +#define POWERPC_MMU_401 (POWERPC_MMU_REAL_4xx) +#define POWERPC_EXCP_401 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) - case CPU_PPC_440EP: /* 440 EP family */ - case CPU_PPC_440GP: /* 440 GP family */ - case CPU_PPC_440GX: /* 440 GX family */ - case CPU_PPC_440GXc: /* 440 GXc family */ - case CPU_PPC_440GXf: /* 440 GXf family */ - case CPU_PPC_440SP: /* 440 SP family */ - case CPU_PPC_440SP2: - case CPU_PPC_440SPE: /* 440 SPE family */ - gen_spr_generic(env); - /* Time base */ - gen_tbl(env); - gen_spr_BookE(env); - gen_spr_440(env); - env->nb_BATs = 0; - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; - /* XXX: TODO: allocate internal IRQ controller */ - break; +static void init_proc_401 (CPUPPCState *env) +{ + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_401(env); + /* Bus access control */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX: TODO: allocate internal IRQ controller */ +} - /* Embedded PowerPC from Freescale */ -#if defined (TODO) - case CPU_PPC_5xx: - break; -#endif -#if defined (TODO) - case CPU_PPC_8xx: /* MPC821 / 823 / 850 / 860 */ - break; -#endif -#if defined (TODO) - case CPU_PPC_82xx_HIP3: /* MPC8240 / 8260 */ - case CPU_PPC_82xx_HIP4: /* MPC8240 / 8260 */ - break; -#endif -#if defined (TODO) - case CPU_PPC_827x: /* MPC 827x / 828x */ - break; -#endif - - /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */ - case CPU_PPC_e500v110: - case CPU_PPC_e500v120: - case CPU_PPC_e500v210: - case CPU_PPC_e500v220: - gen_spr_generic(env); - /* Time base */ - gen_tbl(env); - gen_spr_BookE(env); - gen_spr_BookE_FSL(env); - env->nb_BATs = 0; - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; - /* XXX: TODO: allocate internal IRQ controller */ - break; - -#if defined (TODO) - case CPU_PPC_e600: - break; -#endif - - /* 32 bits PowerPC */ - case CPU_PPC_601: /* PowerPC 601 */ - gen_spr_generic(env); - gen_spr_ne_601(env); - gen_spr_601(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_601_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_601_HID5, "HID5", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ -#if 0 /* ? */ - spr_register(env, SPR_601_HID15, "HID15", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); -#endif - env->nb_tlb = 64; - env->nb_ways = 2; - env->id_tlbs = 0; - env->id_tlbs = 0; - /* XXX: TODO: allocate internal IRQ controller */ - break; - - case CPU_PPC_602: /* PowerPC 602 */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); - gen_spr_602(env); - /* hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); - break; - - case CPU_PPC_603: /* PowerPC 603 */ - case CPU_PPC_603E: /* PowerPC 603e */ - case CPU_PPC_603E7v: - case CPU_PPC_603E7v2: - case CPU_PPC_603P: /* PowerPC 603p */ - case CPU_PPC_603R: /* PowerPC 603r */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); - gen_spr_603(env); - /* hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); - break; - - case CPU_PPC_G2: /* PowerPC G2 family */ - case CPU_PPC_G2H4: - case CPU_PPC_G2gp: - case CPU_PPC_G2ls: - case CPU_PPC_G2LE: /* PowerPC G2LE family */ - case CPU_PPC_G2LEgp: - case CPU_PPC_G2LEls: - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - /* Memory management */ - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); - gen_spr_G2_755(env); - gen_spr_G2(env); - /* Hardware implementation register */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); - break; - - case CPU_PPC_604: /* PowerPC 604 */ - case CPU_PPC_604E: /* PowerPC 604e */ - case CPU_PPC_604R: /* PowerPC 604r */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_604(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); - break; - - case CPU_PPC_74x: /* PowerPC 740 / 750 */ - case CPU_PPC_740E: - case CPU_PPC_750E: - case CPU_PPC_74xP: /* PowerPC 740P / 750P */ - case CPU_PPC_750CXE21: /* IBM PowerPC 750cxe */ - case CPU_PPC_750CXE22: - case CPU_PPC_750CXE23: - case CPU_PPC_750CXE24: - case CPU_PPC_750CXE24b: - case CPU_PPC_750CXE31: - case CPU_PPC_750CXE31b: - case CPU_PPC_750CXR: - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_7xx(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); - break; - - case CPU_PPC_750FX10: /* IBM PowerPC 750 FX */ - case CPU_PPC_750FX20: - case CPU_PPC_750FX21: - case CPU_PPC_750FX22: - case CPU_PPC_750FX23: - case CPU_PPC_750GX10: /* IBM PowerPC 750 GX */ - case CPU_PPC_750GX11: - case CPU_PPC_750GX12: - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ - gen_high_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_7xx(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); - break; - - case CPU_PPC_755_10: /* PowerPC 755 */ - case CPU_PPC_755_11: - case CPU_PPC_755_20: - case CPU_PPC_755D: - case CPU_PPC_755E: - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - /* Memory management */ - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); - gen_spr_G2_755(env); - /* L2 cache control */ - /* XXX : not implemented */ - spr_register(env, SPR_ICTC, "ICTC", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_L2PM, "L2PM", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); - break; - -#if defined (TODO) - /* G4 family */ - case CPU_PPC_7400: /* PowerPC 7400 */ - case CPU_PPC_7410C: /* PowerPC 7410 */ - case CPU_PPC_7410D: - case CPU_PPC_7410E: - case CPU_PPC_7441: /* PowerPC 7441 */ - case CPU_PPC_7445: /* PowerPC 7445 */ - case CPU_PPC_7447: /* PowerPC 7447 */ - case CPU_PPC_7447A: /* PowerPC 7447A */ - case CPU_PPC_7448: /* PowerPC 7448 */ - case CPU_PPC_7450: /* PowerPC 7450 */ - case CPU_PPC_7450b: - case CPU_PPC_7451: /* PowerPC 7451 */ - case CPU_PPC_7451G: - case CPU_PPC_7455: /* PowerPC 7455 */ - case CPU_PPC_7455F: - case CPU_PPC_7455G: - case CPU_PPC_7457: /* PowerPC 7457 */ - case CPU_PPC_7457C: - case CPU_PPC_7457A: /* PowerPC 7457A */ - break; -#endif - - /* 64 bits PowerPC */ -#if defined (TARGET_PPC64) -#if defined (TODO) - case CPU_PPC_620: /* PowerPC 620 */ - case CPU_PPC_630: /* PowerPC 630 (Power 3) */ - case CPU_PPC_631: /* PowerPC 631 (Power 3+) */ - case CPU_PPC_POWER4: /* Power 4 */ - case CPU_PPC_POWER4P: /* Power 4+ */ - case CPU_PPC_POWER5: /* Power 5 */ - case CPU_PPC_POWER5P: /* Power 5+ */ -#endif - break; - - case CPU_PPC_970: /* PowerPC 970 */ - case CPU_PPC_970FX10: /* PowerPC 970 FX */ - case CPU_PPC_970FX20: - case CPU_PPC_970FX21: - case CPU_PPC_970FX30: - case CPU_PPC_970FX31: - case CPU_PPC_970MP10: /* PowerPC 970 MP */ - case CPU_PPC_970MP11: - gen_spr_generic(env); - gen_spr_ne_601(env); - /* XXX: not correct */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_7xx(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Allocate hardware IRQ controller */ - ppc970_irq_init(env); - break; - -#if defined (TODO) - case CPU_PPC_CELL10: /* Cell family */ - case CPU_PPC_CELL20: - case CPU_PPC_CELL30: - case CPU_PPC_CELL31: -#endif - break; - -#if defined (TODO) - case CPU_PPC_RS64: /* Apache (RS64/A35) */ - case CPU_PPC_RS64II: /* NorthStar (RS64-II/A50) */ - case CPU_PPC_RS64III: /* Pulsar (RS64-III) */ - case CPU_PPC_RS64IV: /* IceStar/IStar/SStar (RS64-IV) */ -#endif - break; -#endif /* defined (TARGET_PPC64) */ - -#if defined (TODO) - /* POWER */ - case CPU_POWER: /* POWER */ - case CPU_POWER2: /* POWER2 */ - break; -#endif - - default: - gen_spr_generic(env); - /* XXX: TODO: allocate internal IRQ controller */ - break; - } - if (env->nb_BATs == -1) - env->nb_BATs = 4; - /* Allocate TLBs buffer when needed */ - if (env->nb_tlb != 0) { - int nb_tlb = env->nb_tlb; - if (env->id_tlbs != 0) - nb_tlb *= 2; - env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t)); - /* Pre-compute some useful values */ - env->tlb_per_way = env->nb_tlb / env->nb_ways; - } +/* PowerPC 401x2 */ +#define POWERPC_INSNS_401x2 (POWERPC_INSNS_EMB | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_CACHE_DCBA | PPC_MFTB | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_401x2 (0x00000000001FD231ULL) +#define POWERPC_MMU_401x2 (POWERPC_MMU_SOFT_4xx_Z) +#define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) + +static void init_proc_401x2 (CPUPPCState *env) +{ + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_401x2(env); + gen_spr_compress(env); + /* Bus access control */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } -#if defined(PPC_DUMP_CPU) -static void dump_sprs (CPUPPCState *env) +/* PowerPC 401x3 */ +#if defined(TODO) +#define POWERPC_INSNS_401x3 (POWERPC_INSNS_EMB | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_CACHE_DCBA | PPC_MFTB | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_401x3 (0x00000000001FD631ULL) +#define POWERPC_MMU_401x3 (POWERPC_MMU_SOFT_4xx_Z) +#define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) + +static void init_proc_401x2 (CPUPPCState *env) { - ppc_spr_t *spr; - uint32_t pvr = env->spr[SPR_PVR]; - uint32_t sr, sw, ur, uw; - int i, j, n; - - printf("* SPRs for PVR=%08x\n", pvr); - for (i = 0; i < 32; i++) { - for (j = 0; j < 32; j++) { - n = (i << 5) | j; - spr = &env->spr_cb[n]; -#if !defined(CONFIG_USER_ONLY) - sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS; - sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS; -#else - sw = 0; - sr = 0; -#endif - uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS; - ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS; - if (sw || sr || uw || ur) { - printf("SPR: %4d (%03x) %-8s s%c%c u%c%c\n", - (i << 5) | j, (i << 5) | j, spr->name, - sw ? 'w' : '-', sr ? 'r' : '-', - uw ? 'w' : '-', ur ? 'r' : '-'); - } - } - } - fflush(stdout); - fflush(stderr); } -#endif - -/*****************************************************************************/ -#include -#include - -int fflush (FILE *stream); - -/* Opcode types */ -enum { - PPC_DIRECT = 0, /* Opcode routine */ - PPC_INDIRECT = 1, /* Indirect opcode table */ -}; - -static inline int is_indirect_opcode (void *handler) +#endif /* TODO */ + +/* IOP480 */ +#define POWERPC_INSNS_IOP480 (POWERPC_INSNS_EMB | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_CACHE_DCBA | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_IOP480 (0x00000000001FD231ULL) +#define POWERPC_MMU_IOP480 (POWERPC_MMU_SOFT_4xx_Z) +#define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) + +static void init_proc_IOP480 (CPUPPCState *env) { - return ((unsigned long)handler & 0x03) == PPC_INDIRECT; + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_401x2(env); + gen_spr_compress(env); + /* Bus access control */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } -static inline opc_handler_t **ind_table(void *handler) +/* PowerPC 403 */ +#define POWERPC_INSNS_403 (POWERPC_INSNS_EMB | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_403 (0x000000000007D00DULL) +#define POWERPC_MMU_403 (POWERPC_MMU_REAL_4xx) +#define POWERPC_EXCP_403 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) + +static void init_proc_403 (CPUPPCState *env) { - return (opc_handler_t **)((unsigned long)handler & ~3); + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_403(env); + gen_spr_403_real(env); + /* XXX: TODO: allocate internal IRQ controller */ } -/* Instruction table creation */ -/* Opcodes tables creation */ -static void fill_new_table (opc_handler_t **table, int len) +/* PowerPC 403 GCX */ +#define POWERPC_INSNS_403GCX (POWERPC_INSNS_EMB | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_403GCX (0x000000000007D00DULL) +#define POWERPC_MMU_403GCX (POWERPC_MMU_SOFT_4xx_Z) +#define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) +#define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) + +static void init_proc_403GCX (CPUPPCState *env) { - int i; - - for (i = 0; i < len; i++) - table[i] = &invalid_handler; + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_403(env); + gen_spr_403_real(env); + gen_spr_403_mmu(env); + /* Bus access control */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } -static int create_new_table (opc_handler_t **table, unsigned char idx) +/* PowerPC 405 */ +#define POWERPC_INSNS_405 (POWERPC_INSNS_EMB | PPC_MFTB | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_CACHE_DCBA | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT | \ + PPC_405_MAC) +#define POWERPC_MSRM_405 (0x000000000006E630ULL) +#define POWERPC_MMU_405 (POWERPC_MMU_SOFT_4xx) +#define POWERPC_EXCP_405 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_405 (PPC_FLAGS_INPUT_405) + +static void init_proc_405 (CPUPPCState *env) { - opc_handler_t **tmp; - - tmp = malloc(0x20 * sizeof(opc_handler_t)); - if (tmp == NULL) - return -1; - fill_new_table(tmp, 0x20); - table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT); - - return 0; + /* Time base */ + gen_tbl(env); + gen_spr_40x(env); + gen_spr_405(env); + /* Bus access control */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* Allocate hardware IRQ controller */ + ppc405_irq_init(env); } -static int insert_in_table (opc_handler_t **table, unsigned char idx, - opc_handler_t *handler) +/* PowerPC 440 EP */ +#define POWERPC_INSNS_440EP (POWERPC_INSNS_EMB | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC | PPC_RFMCI) +#define POWERPC_MSRM_440EP (0x000000000006D630ULL) +#define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE) + +static void init_proc_440EP (CPUPPCState *env) { - if (table[idx] != &invalid_handler) - return -1; - table[idx] = handler; - - return 0; + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + gen_spr_440(env); + spr_register(env, SPR_BOOKE_MCSR, "MCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_440_CCR1, "CCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } -static int register_direct_insn (opc_handler_t **ppc_opcodes, - unsigned char idx, opc_handler_t *handler) +/* PowerPC 440 GP */ +#define POWERPC_INSNS_440GP (POWERPC_INSNS_EMB | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON | \ + PPC_405_MAC | PPC_440_SPEC) +#define POWERPC_MSRM_440GP (0x000000000006FF30ULL) +#define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_440GP (PPC_FLAGS_INPUT_BookE) + +static void init_proc_440GP (CPUPPCState *env) { - if (insert_in_table(ppc_opcodes, idx, handler) < 0) { - printf("*** ERROR: opcode %02x already assigned in main " - "opcode table\n", idx); - return -1; - } - - return 0; + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + gen_spr_440(env); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } -static int register_ind_in_table (opc_handler_t **table, - unsigned char idx1, unsigned char idx2, - opc_handler_t *handler) +/* PowerPC 440x4 */ +#if defined(TODO) +#define POWERPC_INSNS_440x4 (POWERPC_INSNS_EMB | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC) +#define POWERPC_MSRM_440x4 (0x000000000006FF30ULL) +#define POWERPC_MMU_440x4 (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) + +static void init_proc_440x4 (CPUPPCState *env) { - if (table[idx1] == &invalid_handler) { - if (create_new_table(table, idx1) < 0) { - printf("*** ERROR: unable to create indirect table " - "idx=%02x\n", idx1); - return -1; - } - } else { - if (!is_indirect_opcode(table[idx1])) { - printf("*** ERROR: idx %02x already assigned to a direct " - "opcode\n", idx1); - return -1; - } - } - if (handler != NULL && - insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { - printf("*** ERROR: opcode %02x already assigned in " - "opcode table %02x\n", idx2, idx1); - return -1; - } - - return 0; + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + gen_spr_440(env); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } - -static int register_ind_insn (opc_handler_t **ppc_opcodes, - unsigned char idx1, unsigned char idx2, - opc_handler_t *handler) +#endif /* TODO */ + +/* PowerPC 440x5 */ +#define POWERPC_INSNS_440x5 (POWERPC_INSNS_EMB | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC | PPC_RFMCI) +#define POWERPC_MSRM_440x5 (0x000000000006FF30ULL) +#define POWERPC_MMU_440x5 (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_440x5 (PPC_FLAGS_INPUT_BookE) + +static void init_proc_440x5 (CPUPPCState *env) { - int ret; - - ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler); - - return ret; + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + gen_spr_440(env); + spr_register(env, SPR_BOOKE_MCSR, "MCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_440_CCR1, "CCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } -static int register_dblind_insn (opc_handler_t **ppc_opcodes, - unsigned char idx1, unsigned char idx2, - unsigned char idx3, opc_handler_t *handler) +/* PowerPC 460 (guessed) */ +#if defined(TODO) +#define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON | \ + PPC_405_MAC | PPC_440_SPEC | PPC_DCRUX) +#define POWERPC_MSRM_460 (0x000000000006FF30ULL) +#define POWERPC_MMU_460 (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) + +static void init_proc_460 (CPUPPCState *env) { - if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { - printf("*** ERROR: unable to join indirect table idx " - "[%02x-%02x]\n", idx1, idx2); - return -1; - } - if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, - handler) < 0) { - printf("*** ERROR: unable to insert opcode " - "[%02x-%02x-%02x]\n", idx1, idx2, idx3); - return -1; - } - - return 0; } - -static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn) +#endif /* TODO */ + +/* PowerPC 460F (guessed) */ +#if defined(TODO) +#define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_FLOAT | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ + PPC_FLOAT_STFIWX | \ + PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON | \ + PPC_405_MAC | PPC_440_SPEC | PPC_DCRUX) +#define POWERPC_MSRM_460 (0x000000000006FF30ULL) +#define POWERPC_MMU_460F (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) + +static void init_proc_460 (CPUPPCState *env) { - if (insn->opc2 != 0xFF) { - if (insn->opc3 != 0xFF) { - if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, - insn->opc3, &insn->handler) < 0) - return -1; - } else { - if (register_ind_insn(ppc_opcodes, insn->opc1, - insn->opc2, &insn->handler) < 0) - return -1; - } - } else { - if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) - return -1; - } - - return 0; + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + gen_spr_440(env); + spr_register(env, SPR_BOOKE_MCSR, "MCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_440_CCR1, "CCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_DCRIPR, "SPR_DCRIPR", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } - -static int test_opcode_table (opc_handler_t **table, int len) +#endif /* TODO */ + +/* Generic BookE PowerPC */ +#if defined(TODO) +#define POWERPC_INSNS_BookE (POWERPC_INSNS_EMB | \ + PPC_MEM_EIEIO | PPC_MEM_TLBSYNC | \ + PPC_CACHE_DCBA | \ + PPC_FLOAT | PPC_FLOAT_FSQRT | \ + PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_FSEL | PPC_FLOAT_STFIW | \ + PPC_BOOKE) +#define POWERPC_MSRM_BookE (0x000000000006D630ULL) +#define POWERPC_MMU_BookE (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_BookE (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_BookE (PPC_FLAGS_INPUT_BookE) + +static void init_proc_BookE (CPUPPCState *env) { - int i, count, tmp; - - for (i = 0, count = 0; i < len; i++) { - /* Consistency fixup */ - if (table[i] == NULL) - table[i] = &invalid_handler; - if (table[i] != &invalid_handler) { - if (is_indirect_opcode(table[i])) { - tmp = test_opcode_table(ind_table(table[i]), 0x20); - if (tmp == 0) { - free(table[i]); - table[i] = &invalid_handler; - } else { - count++; - } - } else { - count++; - } - } - } - - return count; } - -static void fix_opcode_tables (opc_handler_t **ppc_opcodes) +#endif /* TODO */ + +/* e200 core */ +#if defined(TODO) +#endif /* TODO */ + +/* e300 core */ +#if defined(TODO) +#endif /* TODO */ + +/* e500 core */ +#if defined(TODO) +#define POWERPC_INSNS_e500 (POWERPC_INSNS_EMB | \ + PPC_MEM_EIEIO | PPC_MEM_TLBSYNC | \ + PPC_CACHE_DCBA | \ + PPC_BOOKE | PPC_E500_VECTOR) +#define POWERPC_MMU_e500 (POWERPC_MMU_SOFT_4xx) +#define POWERPC_EXCP_e500 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_e500 (PPC_FLAGS_INPUT_BookE) + +static void init_proc_e500 (CPUPPCState *env) { - if (test_opcode_table(ppc_opcodes, 0x40) == 0) - printf("*** WARNING: no opcode defined !\n"); + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + /* Memory management */ + gen_spr_BookE_FSL(env); + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } - -/*****************************************************************************/ -static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) +#endif /* TODO */ + +/* e600 core */ +#if defined(TODO) +#endif /* TODO */ + +/* Non-embedded PowerPC */ +/* Base instructions set for all 6xx/7xx/74xx/970 PowerPC */ +#define POWERPC_INSNS_6xx (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \ + PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE) +/* Instructions common to all 6xx/7xx/74xx/970 PowerPC except 601 & 602 */ +#define POWERPC_INSNS_WORKS (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT | \ + PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ + PPC_MEM_TLBSYNC | PPC_MFTB) + +/* POWER : same as 601, without mfmsr, mfsr */ +#if defined(TODO) +#define POWERPC_INSNS_POWER (XXX_TODO) +/* POWER RSC (from RAD6000) */ +#define POWERPC_MSRM_POWER (0x00000000FEF0ULL) +#endif /* TODO */ + +/* PowerPC 601 */ +#define POWERPC_INSNS_601 (POWERPC_INSNS_6xx | PPC_EXTERN | PPC_POWER_BR) +#define POWERPC_MSRM_601 (0x000000000000FE70ULL) +//#define POWERPC_MMU_601 (POWERPC_MMU_601) +//#define POWERPC_EXCP_601 (POWERPC_EXCP_601) +#define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_601 (CPUPPCState *env) { - opcode_t *opc, *start, *end; - - fill_new_table(env->opcodes, 0x40); -#if defined(PPC_DUMP_CPU) - printf("* PowerPC instructions for PVR %08x: %s flags %016" PRIx64 - " %08x\n", - def->pvr, def->name, def->insns_flags, def->flags); -#endif - if (&opc_start < &opc_end) { - start = &opc_start; - end = &opc_end; - } else { - start = &opc_end; - end = &opc_start; - } - for (opc = start + 1; opc != end; opc++) { - if ((opc->handler.type & def->insns_flags) != 0) { - if (register_insn(env->opcodes, opc) < 0) { - printf("*** ERROR initializing PowerPC instruction " - "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, - opc->opc3); - return -1; - } -#if defined(PPC_DUMP_CPU) - if (opc1 != 0x00) { - if (opc->opc3 == 0xFF) { - if (opc->opc2 == 0xFF) { - printf("INSN: %02x -- -- (%02d ----) : %s\n", - opc->opc1, opc->opc1, opc->oname); - } else { - printf("INSN: %02x %02x -- (%02d %04d) : %s\n", - opc->opc1, opc->opc2, opc->opc1, opc->opc2, - opc->oname); - } - } else { - printf("INSN: %02x %02x %02x (%02d %04d) : %s\n", - opc->opc1, opc->opc2, opc->opc3, - opc->opc1, (opc->opc3 << 5) | opc->opc2, - opc->oname); - } - } -#endif - } - } - fix_opcode_tables(env->opcodes); - fflush(stdout); - fflush(stderr); - - return 0; + gen_spr_ne_601(env); + gen_spr_601(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_601_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_601_HID5, "HID5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_601_HID15, "HID15", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 2; + env->id_tlbs = 0; + env->id_tlbs = 0; + /* XXX: TODO: allocate internal IRQ controller */ } -int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) +/* PowerPC 602 */ +#define POWERPC_INSNS_602 (POWERPC_INSNS_6xx | PPC_MFTB | \ + PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ + PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_602_SPEC) +#define POWERPC_MSRM_602 (0x000000000033FF73ULL) +#define POWERPC_MMU_602 (POWERPC_MMU_SOFT_6xx) +//#define POWERPC_EXCP_602 (POWERPC_EXCP_602) +#define POWERPC_INPUT_602 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_602 (CPUPPCState *env) { - env->msr_mask = def->msr_mask; - env->flags = def->flags; - if (create_ppc_opcodes(env, def) < 0) - return -1; - init_ppc_proc(env, def); -#if defined(PPC_DUMP_CPU) - dump_sprs(env); - if (env->tlb != NULL) { - printf("%d %s TLB in %d ways\n", env->nb_tlb, - env->id_tlbs ? "splitted" : "merged", env->nb_ways); - } -#endif + gen_spr_ne_601(env); + gen_spr_602(env); + /* Time base */ + gen_tbl(env); + /* hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} - return 0; +/* PowerPC 603 */ +#define POWERPC_INSNS_603 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_MSRM_603 (0x000000000001FF73ULL) +#define POWERPC_MMU_603 (POWERPC_MMU_SOFT_6xx) +//#define POWERPC_EXCP_603 (POWERPC_EXCP_603) +#define POWERPC_INPUT_603 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_603 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_603(env); + /* Time base */ + gen_tbl(env); + /* hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); } +/* PowerPC 603e */ +#define POWERPC_INSNS_603E (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_MSRM_603E (0x000000000007FF73ULL) +#define POWERPC_MMU_603E (POWERPC_MMU_SOFT_6xx) +//#define POWERPC_EXCP_603E (POWERPC_EXCP_603E) +#define POWERPC_INPUT_603E (PPC_FLAGS_INPUT_6xx) + +static void init_proc_603E (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_603(env); + /* Time base */ + gen_tbl(env); + /* hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC G2 */ +#define POWERPC_INSNS_G2 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_MSRM_G2 (0x000000000006FFF2ULL) +#define POWERPC_MMU_G2 (POWERPC_MMU_SOFT_6xx) +//#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) +#define POWERPC_INPUT_G2 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_G2 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_G2_755(env); + gen_spr_G2(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation register */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC G2LE */ +#define POWERPC_INSNS_G2LE (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_MSRM_G2LE (0x000000000007FFF3ULL) +#define POWERPC_MMU_G2LE (POWERPC_MMU_SOFT_6xx) +#define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) +#define POWERPC_INPUT_G2LE (PPC_FLAGS_INPUT_6xx) + +static void init_proc_G2LE (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_G2_755(env); + gen_spr_G2(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation register */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 604 */ +#define POWERPC_INSNS_604 (POWERPC_INSNS_WORKS | PPC_EXTERN) +#define POWERPC_MSRM_604 (0x000000000005FF77ULL) +#define POWERPC_MMU_604 (POWERPC_MMU_32B) +//#define POWERPC_EXCP_604 (POWERPC_EXCP_604) +#define POWERPC_INPUT_604 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_604 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_604(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 740/750 (aka G3) */ +#define POWERPC_INSNS_7x0 (POWERPC_INSNS_WORKS | PPC_EXTERN) +#define POWERPC_MSRM_7x0 (0x000000000007FF77ULL) +#define POWERPC_MMU_7x0 (POWERPC_MMU_32B) +//#define POWERPC_EXCP_7x0 (POWERPC_EXCP_7x0) +#define POWERPC_INPUT_7x0 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_7x0 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* Thermal management */ + gen_spr_thrm(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 750FX/GX */ +#define POWERPC_INSNS_750fx (POWERPC_INSNS_WORKS | PPC_EXTERN) +#define POWERPC_MSRM_750fx (0x000000000007FF77ULL) +#define POWERPC_MMU_750fx (POWERPC_MMU_32B) +#define POWERPC_EXCP_750fx (POWERPC_EXCP_7x0) +#define POWERPC_INPUT_750fx (PPC_FLAGS_INPUT_6xx) + +static void init_proc_750fx (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* Thermal management */ + gen_spr_thrm(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ + gen_high_BATs(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 745/755 */ +#define POWERPC_INSNS_7x5 (POWERPC_INSNS_WORKS | PPC_EXTERN | PPC_6xx_TLB) +#define POWERPC_MSRM_7x5 (0x000000000007FF77ULL) +#define POWERPC_MMU_7x5 (POWERPC_MMU_SOFT_6xx) +//#define POWERPC_EXCP_7x5 (POWERPC_EXCP_7x5) +#define POWERPC_INPUT_7x5 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_7x5 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_G2_755(env); + /* Time base */ + gen_tbl(env); + /* L2 cache control */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTC, "ICTC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_L2PMCR, "L2PMCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 7400 (aka G4) */ +#define POWERPC_INSNS_7400 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ + PPC_EXTERN | PPC_MEM_TLBIA | \ + PPC_ALTIVEC) +#define POWERPC_MSRM_7400 (0x000000000205FF77ULL) +#define POWERPC_MMU_7400 (POWERPC_MMU_32B) +#define POWERPC_EXCP_7400 (POWERPC_EXCP_74xx) +#define POWERPC_INPUT_7400 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_7400 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* 74xx specific SPR */ + gen_spr_74xx(env); + /* Thermal management */ + gen_spr_thrm(env); + /* Memory management */ + gen_low_BATs(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 7410 (aka G4) */ +#define POWERPC_INSNS_7410 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ + PPC_EXTERN | PPC_MEM_TLBIA | \ + PPC_ALTIVEC) +#define POWERPC_MSRM_7410 (0x000000000205FF77ULL) +#define POWERPC_MMU_7410 (POWERPC_MMU_32B) +#define POWERPC_EXCP_7410 (POWERPC_EXCP_74xx) +#define POWERPC_INPUT_7410 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_7410 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* 74xx specific SPR */ + gen_spr_74xx(env); + /* Thermal management */ + gen_spr_thrm(env); + /* L2PMCR */ + /* XXX : not implemented */ + spr_register(env, SPR_L2PMCR, "L2PMCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* LDSTDB */ + /* XXX : not implemented */ + spr_register(env, SPR_LDSTDB, "LDSTDB", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 7440 (aka G4) */ +#if defined (TODO) +#define POWERPC_INSNS_7440 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ + PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ + PPC_ALTIVEC) +#define POWERPC_MSRM_7440 (0x000000000205FF77ULL) +#define POWERPC_MMU_7440 (POWERPC_MMU_SOFT_74xx) +#define POWERPC_EXCP_7440 (POWERPC_EXCP_74xx) +#define POWERPC_INPUT_7440 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_7440 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* 74xx specific SPR */ + gen_spr_74xx(env); + /* LDSTCR */ + /* XXX : not implemented */ + spr_register(env, SPR_LDSTCR, "LDSTCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* ICTRL */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTRL, "ICTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* MSSSR0 */ + spr_register(env, SPR_MSSSR0, "MSSSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* PMC */ + /* XXX : not implemented */ + spr_register(env, SPR_PMC5, "PMC5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UPMC5, "UPMC5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_PMC6, "PMC6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UPMC6, "UPMC6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_74xx_soft_tlb(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} +#endif /* TODO */ + +/* PowerPC 7450 (aka G4) */ +#if defined (TODO) +#define POWERPC_INSNS_7450 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ + PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ + PPC_ALTIVEC) +#define POWERPC_MSRM_7450 (0x000000000205FF77ULL) +#define POWERPC_MMU_7450 (POWERPC_MMU_SOFT_74xx) +#define POWERPC_EXCP_7450 (POWERPC_EXCP_74xx) +#define POWERPC_INPUT_7450 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_7450 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* 74xx specific SPR */ + gen_spr_74xx(env); + /* Level 3 cache control */ + gen_l3_ctrl(env); + /* LDSTCR */ + /* XXX : not implemented */ + spr_register(env, SPR_LDSTCR, "LDSTCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* ICTRL */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTRL, "ICTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* MSSSR0 */ + spr_register(env, SPR_MSSSR0, "MSSSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* PMC */ + /* XXX : not implemented */ + spr_register(env, SPR_PMC5, "PMC5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UPMC5, "UPMC5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_PMC6, "PMC6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UPMC6, "UPMC6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_74xx_soft_tlb(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} +#endif /* TODO */ + +/* PowerPC 7445 (aka G4) */ +#if defined (TODO) +#define POWERPC_INSNS_7445 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ + PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ + PPC_ALTIVEC) +#define POWERPC_MSRM_7445 (0x000000000205FF77ULL) +#define POWERPC_MMU_7445 (POWERPC_MMU_SOFT_74xx) +#define POWERPC_EXCP_7445 (POWERPC_EXCP_74xx) +#define POWERPC_INPUT_7445 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_7445 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* 74xx specific SPR */ + gen_spr_74xx(env); + /* LDSTCR */ + /* XXX : not implemented */ + spr_register(env, SPR_LDSTCR, "LDSTCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* ICTRL */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTRL, "ICTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* MSSSR0 */ + spr_register(env, SPR_MSSSR0, "MSSSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* PMC */ + /* XXX : not implemented */ + spr_register(env, SPR_PMC5, "PMC5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UPMC5, "UPMC5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_PMC6, "PMC6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UPMC6, "UPMC6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* SPRGs */ + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_74xx_soft_tlb(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} +#endif /* TODO */ + +/* PowerPC 7455 (aka G4) */ +#if defined (TODO) +#define POWERPC_INSNS_7455 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ + PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ + PPC_ALTIVEC) +#define POWERPC_MSRM_7455 (0x000000000205FF77ULL) +#define POWERPC_MMU_7455 (POWERPC_MMU_SOFT_74xx) +#define POWERPC_EXCP_7455 (POWERPC_EXCP_74xx) +#define POWERPC_INPUT_7455 (PPC_FLAGS_INPUT_6xx) + +static void init_proc_7455 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* 74xx specific SPR */ + gen_spr_74xx(env); + /* Level 3 cache control */ + gen_l3_ctrl(env); + /* LDSTCR */ + /* XXX : not implemented */ + spr_register(env, SPR_LDSTCR, "LDSTCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* ICTRL */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTRL, "ICTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* MSSSR0 */ + spr_register(env, SPR_MSSSR0, "MSSSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* PMC */ + /* XXX : not implemented */ + spr_register(env, SPR_PMC5, "PMC5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UPMC5, "UPMC5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_PMC6, "PMC6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_UPMC6, "UPMC6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* SPRGs */ + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_74xx_soft_tlb(env); + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} +#endif /* TODO */ + +#if defined (TARGET_PPC64) +/* PowerPC 970 */ +#if defined (TODO) +#define POWERPC_INSNS_970 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ + PPC_64B | PPC_ALTIVEC | \ + PPC_64_BRIDGE | PPC_SLBI) +#define POWERPC_MSRM_970 (0x900000000204FF36ULL) +#define POWERPC_MMU_970 (POWERPC_MMU_64BRIDGE) +//#define POWERPC_EXCP_970 (POWERPC_EXCP_970) +#define POWERPC_INPUT_970 (PPC_FLAGS_INPUT_970) + +static void init_proc_970 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + /* XXX: not correct */ + gen_low_BATs(env); +#if 0 // TODO + env->slb_nr = 32; +#endif + /* Allocate hardware IRQ controller */ + ppc970_irq_init(env); +} +#endif /* TODO */ + +/* PowerPC 970FX (aka G5) */ +#if defined (TODO) +#define POWERPC_INSNS_970FX (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ + PPC_64B | PPC_ALTIVEC | \ + PPC_64_BRIDGE | PPC_SLBI) +#define POWERPC_MSRM_970FX (0x800000000204FF36ULL) +#define POWERPC_MMU_970FX (POWERPC_MMU_64BRIDGE) +#define POWERPC_EXCP_970FX (POWERPC_EXCP_970) +#define POWERPC_INPUT_970FX (PPC_FLAGS_INPUT_970) + +static void init_proc_970FX (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + /* XXX: not correct */ + gen_low_BATs(env); +#if 0 // TODO + env->slb_nr = 32; +#endif + /* Allocate hardware IRQ controller */ + ppc970_irq_init(env); +} +#endif /* TODO */ + +/* PowerPC 970 GX */ +#if defined (TODO) +#define POWERPC_INSNS_970GX (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ + PPC_64B | PPC_ALTIVEC | \ + PPC_64_BRIDGE | PPC_SLBI) +#define POWERPC_MSRM_970GX (0x800000000204FF36ULL) +#define POWERPC_MMU_970GX (POWERPC_MMU_64BRIDGE) +#define POWERPC_EXCP_970GX (POWERPC_EXCP_970) +#define POWERPC_INPUT_970GX (PPC_FLAGS_INPUT_970) + +static void init_proc_970GX (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + /* XXX: not correct */ + gen_low_BATs(env); +#if 0 // TODO + env->slb_nr = 32; +#endif + /* Allocate hardware IRQ controller */ + ppc970_irq_init(env); +} +#endif /* TODO */ + +/* PowerPC 620 */ +#if defined (TODO) +#define POWERPC_INSNS_620 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ + PPC_64B | PPC_SLBI) +#define POWERPC_MSRM_620 (0x800000000005FF73ULL) +#define POWERPC_MMU_620 (POWERPC_MMU_64B) +#define POWERPC_EXCP_620 (POWERPC_EXCP_970) +#define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_970) + +static void init_proc_620 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_620(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + /* XXX: TODO: initialize internal interrupt controller */ +} +#endif /* TODO */ +#endif /* defined (TARGET_PPC64) */ + +/* Default 32 bits PowerPC target will be 604 */ +#define CPU_POWERPC_PPC32 CPU_POWERPC_604 +#define POWERPC_INSNS_PPC32 POWERPC_INSNS_604 +#define POWERPC_MSRM_PPC32 POWERPC_MSRM_604 +#define POWERPC_MMU_PPC32 POWERPC_MMU_604 +#define POWERPC_EXCP_PPC32 POWERPC_EXCP_604 +#define POWERPC_INPUT_PPC32 POWERPC_INPUT_604 +#define init_proc_PPC32 init_proc_604 + +/* Default 64 bits PowerPC target will be 970 FX */ +#define CPU_POWERPC_PPC64 CPU_POWERPC_970FX +#define POWERPC_INSNS_PPC64 POWERPC_INSNS_970FX +#define POWERPC_MSRM_PPC64 POWERPC_MSRM_970FX +#define POWERPC_MMU_PPC64 POWERPC_MMU_970FX +#define POWERPC_EXCP_PPC64 POWERPC_EXCP_970FX +#define POWERPC_INPUT_PPC64 POWERPC_INPUT_970FX +#define init_proc_PPC64 init_proc_970FX + +/* Default PowerPC target will be PowerPC 32 */ +#if defined (TARGET_PPC64) && 0 // XXX: TODO +#define CPU_POWERPC_PPC CPU_POWERPC_PPC64 +#define POWERPC_INSNS_PPC POWERPC_INSNS_PPC64 +#define POWERPC_MSRM_PPC POWERPC_MSRM_PPC64 +#define POWERPC_MMU_PPC POWERPC_MMU_PPC64 +#define POWERPC_EXCP_PPC POWERPC_EXCP_PPC64 +#define POWERPC_INPUT_PPC POWERPC_INPUT_PPC64 +#define init_proc_PPC init_proc_PPC64 +#else +#define CPU_POWERPC_PPC CPU_POWERPC_PPC32 +#define POWERPC_INSNS_PPC POWERPC_INSNS_PPC32 +#define POWERPC_MSRM_PPC POWERPC_MSRM_PPC32 +#define POWERPC_MMU_PPC POWERPC_MMU_PPC32 +#define POWERPC_EXCP_PPC POWERPC_EXCP_PPC32 +#define POWERPC_INPUT_PPC POWERPC_INPUT_PPC32 +#define init_proc_PPC init_proc_PPC32 +#endif + +/*****************************************************************************/ +/* PVR definitions for most known PowerPC */ +enum { + /* PowerPC 401 family */ + /* Generic PowerPC 401 */ +#define CPU_POWERPC_401 CPU_POWERPC_401G2 + /* PowerPC 401 cores */ + CPU_POWERPC_401A1 = 0x00210000, + CPU_POWERPC_401B2 = 0x00220000, +#if 0 + CPU_POWERPC_401B3 = xxx, +#endif + CPU_POWERPC_401C2 = 0x00230000, + CPU_POWERPC_401D2 = 0x00240000, + CPU_POWERPC_401E2 = 0x00250000, + CPU_POWERPC_401F2 = 0x00260000, + CPU_POWERPC_401G2 = 0x00270000, + /* PowerPC 401 microcontrolers */ +#if 0 + CPU_POWERPC_401GF = xxx, +#endif +#define CPU_POWERPC_IOP480 CPU_POWERPC_401B2 + /* IBM Processor for Network Resources */ + CPU_POWERPC_COBRA = 0x10100000, /* XXX: 405 ? */ +#if 0 + CPU_POWERPC_XIPCHIP = xxx, +#endif + /* PowerPC 403 family */ + /* Generic PowerPC 403 */ +#define CPU_POWERPC_403 CPU_POWERPC_403GC + /* PowerPC 403 microcontrollers */ + CPU_POWERPC_403GA = 0x00200011, + CPU_POWERPC_403GB = 0x00200100, + CPU_POWERPC_403GC = 0x00200200, + CPU_POWERPC_403GCX = 0x00201400, +#if 0 + CPU_POWERPC_403GP = xxx, +#endif + /* PowerPC 405 family */ + /* Generic PowerPC 405 */ +#define CPU_POWERPC_405 CPU_POWERPC_405D4 + /* PowerPC 405 cores */ +#if 0 + CPU_POWERPC_405A3 = xxx, +#endif +#if 0 + CPU_POWERPC_405A4 = xxx, +#endif +#if 0 + CPU_POWERPC_405B3 = xxx, +#endif +#if 0 + CPU_POWERPC_405B4 = xxx, +#endif +#if 0 + CPU_POWERPC_405C3 = xxx, +#endif +#if 0 + CPU_POWERPC_405C4 = xxx, +#endif + CPU_POWERPC_405D2 = 0x20010000, +#if 0 + CPU_POWERPC_405D3 = xxx, +#endif + CPU_POWERPC_405D4 = 0x41810000, +#if 0 + CPU_POWERPC_405D5 = xxx, +#endif +#if 0 + CPU_POWERPC_405E4 = xxx, +#endif +#if 0 + CPU_POWERPC_405F4 = xxx, +#endif +#if 0 + CPU_POWERPC_405F5 = xxx, +#endif +#if 0 + CPU_POWERPC_405F6 = xxx, +#endif + /* PowerPC 405 microcontrolers */ + /* XXX: missing 0x200108a0 */ +#define CPU_POWERPC_405CR CPU_POWERPC_405CRc + CPU_POWERPC_405CRa = 0x40110041, + CPU_POWERPC_405CRb = 0x401100C5, + CPU_POWERPC_405CRc = 0x40110145, + CPU_POWERPC_405EP = 0x51210950, +#if 0 + CPU_POWERPC_405EXr = xxx, +#endif + CPU_POWERPC_405EZ = 0x41511460, /* 0x51210950 ? */ +#if 0 + CPU_POWERPC_405FX = xxx, +#endif +#define CPU_POWERPC_405GP CPU_POWERPC_405GPd + CPU_POWERPC_405GPa = 0x40110000, + CPU_POWERPC_405GPb = 0x40110040, + CPU_POWERPC_405GPc = 0x40110082, + CPU_POWERPC_405GPd = 0x401100C4, +#define CPU_POWERPC_405GPe CPU_POWERPC_405CRc + CPU_POWERPC_405GPR = 0x50910951, +#if 0 + CPU_POWERPC_405H = xxx, +#endif +#if 0 + CPU_POWERPC_405L = xxx, +#endif + CPU_POWERPC_405LP = 0x41F10000, +#if 0 + CPU_POWERPC_405PM = xxx, +#endif +#if 0 + CPU_POWERPC_405PS = xxx, +#endif +#if 0 + CPU_POWERPC_405S = xxx, +#endif + /* IBM network processors */ + CPU_POWERPC_NPE405H = 0x414100C0, + CPU_POWERPC_NPE405H2 = 0x41410140, + CPU_POWERPC_NPE405L = 0x416100C0, + CPU_POWERPC_NPE4GS3 = 0x40B10000, +#if 0 + CPU_POWERPC_NPCxx1 = xxx, +#endif +#if 0 + CPU_POWERPC_NPR161 = xxx, +#endif +#if 0 + CPU_POWERPC_LC77700 = xxx, +#endif + /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */ +#if 0 + CPU_POWERPC_STB01000 = xxx, +#endif +#if 0 + CPU_POWERPC_STB01010 = xxx, +#endif +#if 0 + CPU_POWERPC_STB0210 = xxx, /* 401B3 */ +#endif + CPU_POWERPC_STB03 = 0x40310000, /* 0x40130000 ? */ +#if 0 + CPU_POWERPC_STB043 = xxx, +#endif +#if 0 + CPU_POWERPC_STB045 = xxx, +#endif + CPU_POWERPC_STB04 = 0x41810000, + CPU_POWERPC_STB25 = 0x51510950, +#if 0 + CPU_POWERPC_STB130 = xxx, +#endif + /* Xilinx cores */ + CPU_POWERPC_X2VP4 = 0x20010820, +#define CPU_POWERPC_X2VP7 CPU_POWERPC_X2VP4 + CPU_POWERPC_X2VP20 = 0x20010860, +#define CPU_POWERPC_X2VP50 CPU_POWERPC_X2VP20 +#if 0 + CPU_POWERPC_ZL10310 = xxx, +#endif +#if 0 + CPU_POWERPC_ZL10311 = xxx, +#endif +#if 0 + CPU_POWERPC_ZL10320 = xxx, +#endif +#if 0 + CPU_POWERPC_ZL10321 = xxx, +#endif + /* PowerPC 440 family */ + /* Generic PowerPC 440 */ +#define CPU_POWERPC_440 CPU_POWERPC_440GXf + /* PowerPC 440 cores */ +#if 0 + CPU_POWERPC_440A4 = xxx, +#endif +#if 0 + CPU_POWERPC_440A5 = xxx, +#endif +#if 0 + CPU_POWERPC_440B4 = xxx, +#endif +#if 0 + CPU_POWERPC_440F5 = xxx, +#endif +#if 0 + CPU_POWERPC_440G5 = xxx, +#endif +#if 0 + CPU_POWERPC_440H4 = xxx, +#endif +#if 0 + CPU_POWERPC_440H6 = xxx, +#endif + /* PowerPC 440 microcontrolers */ +#define CPU_POWERPC_440EP CPU_POWERPC_440EPb + CPU_POWERPC_440EPa = 0x42221850, + CPU_POWERPC_440EPb = 0x422218D3, +#define CPU_POWERPC_440GP CPU_POWERPC_440GPc + CPU_POWERPC_440GPb = 0x40120440, + CPU_POWERPC_440GPc = 0x40120481, +#define CPU_POWERPC_440GR CPU_POWERPC_440GRa +#define CPU_POWERPC_440GRa CPU_POWERPC_440EPb + CPU_POWERPC_440GRX = 0x200008D0, +#define CPU_POWERPC_440EPX CPU_POWERPC_440GRX +#define CPU_POWERPC_440GX CPU_POWERPC_440GXf + CPU_POWERPC_440GXa = 0x51B21850, + CPU_POWERPC_440GXb = 0x51B21851, + CPU_POWERPC_440GXc = 0x51B21892, + CPU_POWERPC_440GXf = 0x51B21894, +#if 0 + CPU_POWERPC_440S = xxx, +#endif + CPU_POWERPC_440SP = 0x53221850, + CPU_POWERPC_440SP2 = 0x53221891, + CPU_POWERPC_440SPE = 0x53421890, + /* PowerPC 460 family */ +#if 0 + /* Generic PowerPC 464 */ +#define CPU_POWERPC_464 CPU_POWERPC_464H90 +#endif + /* PowerPC 464 microcontrolers */ +#if 0 + CPU_POWERPC_464H90 = xxx, +#endif +#if 0 + CPU_POWERPC_464H90FP = xxx, +#endif + /* Freescale embedded PowerPC cores */ + /* e200 family */ +#define CPU_POWERPC_e200 CPU_POWERPC_e200z6 +#if 0 + CPU_POWERPC_e200z0 = xxx, +#endif +#if 0 + CPU_POWERPC_e200z3 = xxx, +#endif + CPU_POWERPC_e200z5 = 0x81000000, + CPU_POWERPC_e200z6 = 0x81120000, + /* e300 family */ +#define CPU_POWERPC_e300 CPU_POWERPC_e300c3 + CPU_POWERPC_e300c1 = 0x00830000, + CPU_POWERPC_e300c2 = 0x00840000, + CPU_POWERPC_e300c3 = 0x00850000, + /* e500 family */ +#define CPU_POWERPC_e500 CPU_POWERPC_e500_v22 + CPU_POWERPC_e500_v11 = 0x80200010, + CPU_POWERPC_e500_v12 = 0x80200020, + CPU_POWERPC_e500_v21 = 0x80210010, + CPU_POWERPC_e500_v22 = 0x80210020, +#if 0 + CPU_POWERPC_e500mc = xxx, +#endif + /* e600 family */ + CPU_POWERPC_e600 = 0x80040010, + /* PowerPC MPC 5xx cores */ + CPU_POWERPC_5xx = 0x00020020, + /* PowerPC MPC 8xx cores (aka PowerQUICC) */ + CPU_POWERPC_8xx = 0x00500000, + /* PowerPC MPC 8xxx cores (aka PowerQUICC-II) */ + CPU_POWERPC_82xx_HIP3 = 0x00810101, + CPU_POWERPC_82xx_HIP4 = 0x80811014, + CPU_POWERPC_827x = 0x80822013, + /* PowerPC 6xx cores */ + CPU_POWERPC_601 = 0x00010001, + CPU_POWERPC_601a = 0x00010002, + CPU_POWERPC_602 = 0x00050100, + CPU_POWERPC_603 = 0x00030100, +#define CPU_POWERPC_603E CPU_POWERPC_603E_v41 + CPU_POWERPC_603E_v11 = 0x00060101, + CPU_POWERPC_603E_v12 = 0x00060102, + CPU_POWERPC_603E_v13 = 0x00060103, + CPU_POWERPC_603E_v14 = 0x00060104, + CPU_POWERPC_603E_v22 = 0x00060202, + CPU_POWERPC_603E_v3 = 0x00060300, + CPU_POWERPC_603E_v4 = 0x00060400, + CPU_POWERPC_603E_v41 = 0x00060401, + CPU_POWERPC_603E7t = 0x00071201, + CPU_POWERPC_603E7v = 0x00070100, + CPU_POWERPC_603E7v1 = 0x00070101, + CPU_POWERPC_603E7v2 = 0x00070201, + CPU_POWERPC_603E7 = 0x00070200, + CPU_POWERPC_603P = 0x00070000, +#define CPU_POWERPC_603R CPU_POWERPC_603E7t + CPU_POWERPC_G2 = 0x00810011, +#if 0 // Linux pretends the MSB is zero... + CPU_POWERPC_G2H4 = 0x80811010, + CPU_POWERPC_G2gp = 0x80821010, + CPU_POWERPC_G2ls = 0x90810010, + CPU_POWERPC_G2LE = 0x80820010, + CPU_POWERPC_G2LEgp = 0x80822010, + CPU_POWERPC_G2LEls = 0xA0822010, +#else + CPU_POWERPC_G2H4 = 0x00811010, + CPU_POWERPC_G2gp = 0x00821010, + CPU_POWERPC_G2ls = 0x10810010, + CPU_POWERPC_G2LE = 0x00820010, + CPU_POWERPC_G2LEgp = 0x00822010, + CPU_POWERPC_G2LEls = 0x20822010, +#endif + CPU_POWERPC_604 = 0x00040103, +#define CPU_POWERPC_604E CPU_POWERPC_604E_v24 + CPU_POWERPC_604E_v10 = 0x00090100, /* Also 2110 & 2120 */ + CPU_POWERPC_604E_v22 = 0x00090202, + CPU_POWERPC_604E_v24 = 0x00090204, + CPU_POWERPC_604R = 0x000a0101, /* Also 0x00093102 */ +#if 0 + CPU_POWERPC_604EV = xxx, +#endif + /* PowerPC 740/750 cores (aka G3) */ + /* XXX: missing 0x00084202 */ +#define CPU_POWERPC_7x0 CPU_POWERPC_7x0_v31 + CPU_POWERPC_7x0_v20 = 0x00080200, + CPU_POWERPC_7x0_v21 = 0x00080201, + CPU_POWERPC_7x0_v22 = 0x00080202, + CPU_POWERPC_7x0_v30 = 0x00080300, + CPU_POWERPC_7x0_v31 = 0x00080301, + CPU_POWERPC_740E = 0x00080100, + CPU_POWERPC_7x0P = 0x10080000, + /* XXX: missing 0x00087010 (CL ?) */ + CPU_POWERPC_750CL = 0x00087200, +#define CPU_POWERPC_750CX CPU_POWERPC_750CX_v22 + CPU_POWERPC_750CX_v21 = 0x00082201, + CPU_POWERPC_750CX_v22 = 0x00082202, +#define CPU_POWERPC_750CXE CPU_POWERPC_750CXE_v31b + CPU_POWERPC_750CXE_v21 = 0x00082211, + CPU_POWERPC_750CXE_v22 = 0x00082212, + CPU_POWERPC_750CXE_v23 = 0x00082213, + CPU_POWERPC_750CXE_v24 = 0x00082214, + CPU_POWERPC_750CXE_v24b = 0x00083214, + CPU_POWERPC_750CXE_v31 = 0x00083211, + CPU_POWERPC_750CXE_v31b = 0x00083311, + CPU_POWERPC_750CXR = 0x00083410, + CPU_POWERPC_750E = 0x00080200, + CPU_POWERPC_750FL = 0x700A0203, +#define CPU_POWERPC_750FX CPU_POWERPC_750FX_v23 + CPU_POWERPC_750FX_v10 = 0x70000100, + CPU_POWERPC_750FX_v20 = 0x70000200, + CPU_POWERPC_750FX_v21 = 0x70000201, + CPU_POWERPC_750FX_v22 = 0x70000202, + CPU_POWERPC_750FX_v23 = 0x70000203, + CPU_POWERPC_750GL = 0x70020102, +#define CPU_POWERPC_750GX CPU_POWERPC_750GX_v12 + CPU_POWERPC_750GX_v10 = 0x70020100, + CPU_POWERPC_750GX_v11 = 0x70020101, + CPU_POWERPC_750GX_v12 = 0x70020102, +#define CPU_POWERPC_750L CPU_POWERPC_750L_v32 /* Aka LoneStar */ + CPU_POWERPC_750L_v22 = 0x00088202, + CPU_POWERPC_750L_v30 = 0x00088300, + CPU_POWERPC_750L_v32 = 0x00088302, + /* PowerPC 745/755 cores */ +#define CPU_POWERPC_7x5 CPU_POWERPC_7x5_v28 + CPU_POWERPC_7x5_v10 = 0x00083100, + CPU_POWERPC_7x5_v11 = 0x00083101, + CPU_POWERPC_7x5_v20 = 0x00083200, + CPU_POWERPC_7x5_v21 = 0x00083201, + CPU_POWERPC_7x5_v22 = 0x00083202, /* aka D */ + CPU_POWERPC_7x5_v23 = 0x00083203, /* aka E */ + CPU_POWERPC_7x5_v24 = 0x00083204, + CPU_POWERPC_7x5_v25 = 0x00083205, + CPU_POWERPC_7x5_v26 = 0x00083206, + CPU_POWERPC_7x5_v27 = 0x00083207, + CPU_POWERPC_7x5_v28 = 0x00083208, +#if 0 + CPU_POWERPC_7x5P = xxx, +#endif + /* PowerPC 74xx cores (aka G4) */ + /* XXX: missing 0x000C1101 */ +#define CPU_POWERPC_7400 CPU_POWERPC_7400_v29 + CPU_POWERPC_7400_v10 = 0x000C0100, + CPU_POWERPC_7400_v11 = 0x000C0101, + CPU_POWERPC_7400_v20 = 0x000C0200, + CPU_POWERPC_7400_v22 = 0x000C0202, + CPU_POWERPC_7400_v26 = 0x000C0206, + CPU_POWERPC_7400_v27 = 0x000C0207, + CPU_POWERPC_7400_v28 = 0x000C0208, + CPU_POWERPC_7400_v29 = 0x000C0209, +#define CPU_POWERPC_7410 CPU_POWERPC_7410_v14 + CPU_POWERPC_7410_v10 = 0x800C1100, + CPU_POWERPC_7410_v11 = 0x800C1101, + CPU_POWERPC_7410_v12 = 0x800C1102, /* aka C */ + CPU_POWERPC_7410_v13 = 0x800C1103, /* aka D */ + CPU_POWERPC_7410_v14 = 0x800C1104, /* aka E */ +#define CPU_POWERPC_7448 CPU_POWERPC_7448_v21 + CPU_POWERPC_7448_v10 = 0x80040100, + CPU_POWERPC_7448_v11 = 0x80040101, + CPU_POWERPC_7448_v20 = 0x80040200, + CPU_POWERPC_7448_v21 = 0x80040201, +#define CPU_POWERPC_7450 CPU_POWERPC_7450_v21 + CPU_POWERPC_7450_v10 = 0x80000100, + CPU_POWERPC_7450_v11 = 0x80000101, + CPU_POWERPC_7450_v12 = 0x80000102, + CPU_POWERPC_7450_v20 = 0x80000200, /* aka D: 2.04 */ + CPU_POWERPC_7450_v21 = 0x80000201, /* aka E */ + CPU_POWERPC_74x1 = 0x80000203, + CPU_POWERPC_74x1G = 0x80000210, /* aka G: 2.3 */ + /* XXX: missing 0x80010200 */ +#define CPU_POWERPC_74x5 CPU_POWERPC_74x5_v32 + CPU_POWERPC_74x5_v10 = 0x80010100, + CPU_POWERPC_74x5_v21 = 0x80010201, /* aka C: 2.1 */ + CPU_POWERPC_74x5_v32 = 0x80010302, + CPU_POWERPC_74x5_v33 = 0x80010303, /* aka F: 3.3 */ + CPU_POWERPC_74x5_v34 = 0x80010304, /* aka G: 3.4 */ +#define CPU_POWERPC_74x7 CPU_POWERPC_74x7_v12 + CPU_POWERPC_74x7_v10 = 0x80020100, /* aka A: 1.0 */ + CPU_POWERPC_74x7_v11 = 0x80030101, /* aka B: 1.1 */ + CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ + /* 64 bits PowerPC */ + CPU_POWERPC_620 = 0x00140000, + CPU_POWERPC_630 = 0x00400000, + CPU_POWERPC_631 = 0x00410104, + CPU_POWERPC_POWER4 = 0x00350000, + CPU_POWERPC_POWER4P = 0x00380000, + CPU_POWERPC_POWER5 = 0x003A0203, +#define CPU_POWERPC_POWER5GR CPU_POWERPC_POWER5 + CPU_POWERPC_POWER5P = 0x003B0000, +#define CPU_POWERPC_POWER5GS CPU_POWERPC_POWER5P + CPU_POWERPC_POWER6 = 0x003E0000, + CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 running POWER5 mode */ + CPU_POWERPC_POWER6A = 0x0F000002, + CPU_POWERPC_970 = 0x00390202, +#define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 + CPU_POWERPC_970FX_v10 = 0x00391100, + CPU_POWERPC_970FX_v20 = 0x003C0200, + CPU_POWERPC_970FX_v21 = 0x003C0201, + CPU_POWERPC_970FX_v30 = 0x003C0300, + CPU_POWERPC_970FX_v31 = 0x003C0301, + CPU_POWERPC_970GX = 0x00450000, +#define CPU_POWERPC_970MP CPU_POWERPC_970MP_v11 + CPU_POWERPC_970MP_v10 = 0x00440100, + CPU_POWERPC_970MP_v11 = 0x00440101, +#define CPU_POWERPC_CELL CPU_POWERPC_CELL_v32 + CPU_POWERPC_CELL_v10 = 0x00700100, + CPU_POWERPC_CELL_v20 = 0x00700400, + CPU_POWERPC_CELL_v30 = 0x00700500, + CPU_POWERPC_CELL_v31 = 0x00700501, +#define CPU_POWERPC_CELL_v32 CPU_POWERPC_CELL_v31 + CPU_POWERPC_RS64 = 0x00330000, + CPU_POWERPC_RS64II = 0x00340000, + CPU_POWERPC_RS64III = 0x00360000, + CPU_POWERPC_RS64IV = 0x00370000, + /* Original POWER */ + /* XXX: should be POWER (RIOS), RSC3308, RSC4608, + * POWER2 (RIOS2) & RSC2 (P2SC) here + */ +#if 0 + CPU_POWER = xxx, /* 0x20000 ? 0x30000 for RSC ? */ +#endif +#if 0 + CPU_POWER2 = xxx, /* 0x40000 ? */ +#endif + /* PA Semi core */ + CPU_POWERPC_PA6T = 0x00900000, +}; + +/* System version register (used on MPC 8xxx) */ +enum { + PPC_SVR_8540 = 0x80300000, + PPC_SVR_8541E = 0x807A0010, + PPC_SVR_8543v10 = 0x80320010, + PPC_SVR_8543v11 = 0x80320011, + PPC_SVR_8543v20 = 0x80320020, + PPC_SVR_8543Ev10 = 0x803A0010, + PPC_SVR_8543Ev11 = 0x803A0011, + PPC_SVR_8543Ev20 = 0x803A0020, + PPC_SVR_8545 = 0x80310220, + PPC_SVR_8545E = 0x80390220, + PPC_SVR_8547E = 0x80390120, + PPC_SCR_8548v10 = 0x80310010, + PPC_SCR_8548v11 = 0x80310011, + PPC_SCR_8548v20 = 0x80310020, + PPC_SVR_8548Ev10 = 0x80390010, + PPC_SVR_8548Ev11 = 0x80390011, + PPC_SVR_8548Ev20 = 0x80390020, + PPC_SVR_8555E = 0x80790010, + PPC_SVR_8560v10 = 0x80700010, + PPC_SVR_8560v20 = 0x80700020, +}; + /*****************************************************************************/ -/* PowerPC CPU definitions */ +/* PowerPC CPU definitions */ +#define POWERPC_DEF(_name, _pvr, _pvr_mask, _type) \ + { \ + .name = _name, \ + .pvr = _pvr, \ + .pvr_mask = _pvr_mask, \ + .insns_flags = glue(POWERPC_INSNS_,_type), \ + .msr_mask = glue(POWERPC_MSRM_,_type), \ + .mmu_model = glue(POWERPC_MMU_,_type), \ + .excp_model = glue(POWERPC_EXCP_,_type), \ + .bus_model = glue(POWERPC_INPUT_,_type), \ + .init_proc = &glue(init_proc_,_type), \ + } + static ppc_def_t ppc_defs[] = { - /* Embedded PowerPC */ + /* Embedded PowerPC */ + /* PowerPC 401 family */ /* Generic PowerPC 401 */ - { - .name = "401", - .pvr = CPU_PPC_401, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, + POWERPC_DEF("401", CPU_POWERPC_401, 0xFFFF0000, 401), + /* PowerPC 401 cores */ /* PowerPC 401A1 */ - { - .name = "401a1", - .pvr = CPU_PPC_401A1, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, - /* PowerPC 401B2 */ - { - .name = "401b2", - .pvr = CPU_PPC_401B2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, + POWERPC_DEF("401A1", CPU_POWERPC_401A1, 0xFFFFFFFF, 401), + /* PowerPC 401B2 */ + POWERPC_DEF("401B2", CPU_POWERPC_401B2, 0xFFFFFFFF, 401x2), #if defined (TODO) - /* PowerPC 401B3 */ - { - .name = "401b3", - .pvr = CPU_PPC_401B3, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, -#endif - /* PowerPC 401C2 */ - { - .name = "401c2", - .pvr = CPU_PPC_401C2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, - /* PowerPC 401D2 */ - { - .name = "401d2", - .pvr = CPU_PPC_401D2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, - /* PowerPC 401E2 */ - { - .name = "401e2", - .pvr = CPU_PPC_401E2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, - /* PowerPC 401F2 */ - { - .name = "401f2", - .pvr = CPU_PPC_401F2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, - /* PowerPC 401G2 */ - { - .name = "401g2", - .pvr = CPU_PPC_401G2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, + /* PowerPC 401B3 */ + POWERPC_DEF("401B3", CPU_POWERPC_401B3, 0xFFFFFFFF, 401x3), +#endif + /* PowerPC 401C2 */ + POWERPC_DEF("401C2", CPU_POWERPC_401C2, 0xFFFFFFFF, 401x2), + /* PowerPC 401D2 */ + POWERPC_DEF("401D2", CPU_POWERPC_401D2, 0xFFFFFFFF, 401x2), + /* PowerPC 401E2 */ + POWERPC_DEF("401E2", CPU_POWERPC_401E2, 0xFFFFFFFF, 401x2), + /* PowerPC 401F2 */ + POWERPC_DEF("401F2", CPU_POWERPC_401F2, 0xFFFFFFFF, 401x2), + /* PowerPC 401G2 */ + /* XXX: to be checked */ + POWERPC_DEF("401G2", CPU_POWERPC_401G2, 0xFFFFFFFF, 401x2), + /* PowerPC 401 microcontrolers */ #if defined (TODO) - /* PowerPC 401G2 */ - { - .name = "401gf", - .pvr = CPU_PPC_401GF, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, + /* PowerPC 401GF */ + POWERPC_DEF("401GF", CPU_POWERPC_401GF, 0xFFFFFFFF, 401), #endif + /* IOP480 (401 microcontroler) */ + POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, 0xFFFFFFFF, IOP480), + /* IBM Processor for Network Resources */ + POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 0xFFFFFFFF, 401), #if defined (TODO) - /* IOP480 (401 microcontroler) */ - { - .name = "iop480", - .pvr = CPU_PPC_IOP480, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, + POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 0xFFFFFFFF, 401), #endif + /* PowerPC 403 family */ + /* Generic PowerPC 403 */ + POWERPC_DEF("403", CPU_POWERPC_403, 0xFFFF0000, 403), + /* PowerPC 403 microcontrolers */ + /* PowerPC 403 GA */ + POWERPC_DEF("403GA", CPU_POWERPC_403GA, 0xFFFFFFFF, 403), + /* PowerPC 403 GB */ + POWERPC_DEF("403GB", CPU_POWERPC_403GB, 0xFFFFFFFF, 403), + /* PowerPC 403 GC */ + POWERPC_DEF("403GC", CPU_POWERPC_403GC, 0xFFFFFFFF, 403), + /* PowerPC 403 GCX */ + POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 0xFFFFFFFF, 403GCX), #if defined (TODO) - /* IBM Processor for Network Resources */ - { - .name = "Cobra", - .pvr = CPU_PPC_COBRA, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = 0x000FD201, - }, + /* PowerPC 403 GP */ + POWERPC_DEF("403GP", CPU_POWERPC_403GP, 0xFFFFFFFF, 403), #endif - /* Generic PowerPC 403 */ - { - .name = "403", - .pvr = CPU_PPC_403, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23DULL, - }, - /* PowerPC 403 GA */ - { - .name = "403ga", - .pvr = CPU_PPC_403GA, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23DULL, - }, - /* PowerPC 403 GB */ - { - .name = "403gb", - .pvr = CPU_PPC_403GB, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23DULL, - }, - /* PowerPC 403 GC */ - { - .name = "403gc", - .pvr = CPU_PPC_403GC, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23DULL, - }, - /* PowerPC 403 GCX */ - { - .name = "403gcx", - .pvr = CPU_PPC_403GCX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23DULL, - }, + /* PowerPC 405 family */ + /* Generic PowerPC 405 */ + POWERPC_DEF("405", CPU_POWERPC_405, 0xFFFF0000, 405), + /* PowerPC 405 cores */ #if defined (TODO) - /* PowerPC 403 GP */ - { - .name = "403gp", - .pvr = CPU_PPC_403GP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23DULL, - }, + /* PowerPC 405 A3 */ + POWERPC_DEF("405A3", CPU_POWERPC_405A3, 0xFFFFFFFF, 405), #endif - /* Generic PowerPC 405 */ - { - .name = "405", - .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, #if defined (TODO) - /* PowerPC 405 A3 */ - { - .name = "405a3", - .pvr = CPU_PPC_405A3, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 405 A4 */ + POWERPC_DEF("405A4", CPU_POWERPC_405A4, 0xFFFFFFFF, 405), #endif #if defined (TODO) - /* PowerPC 405 A4 */ - { - .name = "405a4", - .pvr = CPU_PPC_405A4, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 405 B3 */ + POWERPC_DEF("405B3", CPU_POWERPC_405B3, 0xFFFFFFFF, 405), #endif #if defined (TODO) - /* PowerPC 405 B3 */ - { - .name = "405b3", - .pvr = CPU_PPC_405B3, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, -#endif - /* PowerPC 405 D2 */ - { - .name = "405d2", - .pvr = CPU_PPC_405D2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - /* PowerPC 405 D4 */ - { - .name = "405d4", - .pvr = CPU_PPC_405D4, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - /* PowerPC 405 CR */ - { - .name = "405cr", - .pvr = CPU_PPC_405CR, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - /* PowerPC 405 GP */ - { - .name = "405gp", - .pvr = CPU_PPC_405GP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - /* PowerPC 405 EP */ - { - .name = "405ep", - .pvr = CPU_PPC_405EP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000000ED630ULL, - }, + /* PowerPC 405 B4 */ + POWERPC_DEF("405B4", CPU_POWERPC_405B4, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* PowerPC 405 C3 */ + POWERPC_DEF("405C3", CPU_POWERPC_405C3, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* PowerPC 405 C4 */ + POWERPC_DEF("405C4", CPU_POWERPC_405C4, 0xFFFFFFFF, 405), +#endif + /* PowerPC 405 D2 */ + POWERPC_DEF("405D2", CPU_POWERPC_405D2, 0xFFFFFFFF, 405), +#if defined (TODO) + /* PowerPC 405 D3 */ + POWERPC_DEF("405D3", CPU_POWERPC_405D3, 0xFFFFFFFF, 405), +#endif + /* PowerPC 405 D4 */ + POWERPC_DEF("405D4", CPU_POWERPC_405D4, 0xFFFFFFFF, 405), +#if defined (TODO) + /* PowerPC 405 D5 */ + POWERPC_DEF("405D5", CPU_POWERPC_405D5, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* PowerPC 405 E4 */ + POWERPC_DEF("405E4", CPU_POWERPC_405E4, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* PowerPC 405 F4 */ + POWERPC_DEF("405F4", CPU_POWERPC_405F4, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* PowerPC 405 F5 */ + POWERPC_DEF("405F5", CPU_POWERPC_405F5, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* PowerPC 405 F6 */ + POWERPC_DEF("405F6", CPU_POWERPC_405F6, 0xFFFFFFFF, 405), +#endif + /* PowerPC 405 microcontrolers */ + /* PowerPC 405 CR */ + POWERPC_DEF("405CR", CPU_POWERPC_405CR, 0xFFFFFFFF, 405), + /* PowerPC 405 CRa */ + POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 0xFFFFFFFF, 405), + /* PowerPC 405 CRb */ + POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 0xFFFFFFFF, 405), + /* PowerPC 405 CRc */ + POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 0xFFFFFFFF, 405), + /* PowerPC 405 EP */ + POWERPC_DEF("405EP", CPU_POWERPC_405EP, 0xFFFFFFFF, 405), +#if defined(TODO) + /* PowerPC 405 EXr */ + POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 0xFFFFFFFF, 405), +#endif + /* PowerPC 405 EZ */ + POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 0xFFFFFFFF, 405), +#if defined(TODO) + /* PowerPC 405 FX */ + POWERPC_DEF("405FX", CPU_POWERPC_405FX, 0xFFFFFFFF, 405), +#endif + /* PowerPC 405 GP */ + POWERPC_DEF("405GP", CPU_POWERPC_405GP, 0xFFFFFFFF, 405), + /* PowerPC 405 GPa */ + POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 0xFFFFFFFF, 405), + /* PowerPC 405 GPb */ + POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 0xFFFFFFFF, 405), + /* PowerPC 405 GPc */ + POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 0xFFFFFFFF, 405), + /* PowerPC 405 GPd */ + POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 0xFFFFFFFF, 405), + /* PowerPC 405 GPe */ + POWERPC_DEF("405GPe", CPU_POWERPC_405GPe, 0xFFFFFFFF, 405), + /* PowerPC 405 GPR */ + POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 0xFFFFFFFF, 405), +#if defined(TODO) + /* PowerPC 405 H */ + POWERPC_DEF("405H", CPU_POWERPC_405H, 0xFFFFFFFF, 405), +#endif +#if defined(TODO) + /* PowerPC 405 L */ + POWERPC_DEF("405L", CPU_POWERPC_405L, 0xFFFFFFFF, 405), +#endif + /* PowerPC 405 LP */ + POWERPC_DEF("405LP", CPU_POWERPC_405LP, 0xFFFFFFFF, 405), +#if defined(TODO) + /* PowerPC 405 PM */ + POWERPC_DEF("405PM", CPU_POWERPC_405PM, 0xFFFFFFFF, 405), +#endif +#if defined(TODO) + /* PowerPC 405 PS */ + POWERPC_DEF("405PS", CPU_POWERPC_405PS, 0xFFFFFFFF, 405), +#endif +#if defined(TODO) + /* PowerPC 405 S */ + POWERPC_DEF("405S", CPU_POWERPC_405S, 0xFFFFFFFF, 405), +#endif + /* Npe405 H */ + POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 0xFFFFFFFF, 405), + /* Npe405 H2 */ + POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 0xFFFFFFFF, 405), + /* Npe405 L */ + POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 0xFFFFFFFF, 405), + /* Npe4GS3 */ + POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 0xFFFFFFFF, 405), +#if defined (TODO) + POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* PowerPC LC77700 (Sanyo) */ + POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 0xFFFFFFFF, 405), +#endif + /* PowerPC 401/403/405 based set-top-box microcontrolers */ +#if defined (TODO) + /* STB010000 */ + POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 0xFFFFFFFF, 401x2), +#endif +#if defined (TODO) + /* STB01010 */ + POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 0xFFFFFFFF, 401x2), +#endif +#if defined (TODO) + /* STB0210 */ + POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 0xFFFFFFFF, 401x3), +#endif + /* STB03xx */ + POWERPC_DEF("STB03", CPU_POWERPC_STB03, 0xFFFFFFFF, 405), +#if defined (TODO) + /* STB043x */ + POWERPC_DEF("STB043", CPU_POWERPC_STB043, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* STB045x */ + POWERPC_DEF("STB045", CPU_POWERPC_STB045, 0xFFFFFFFF, 405), +#endif + /* STB04xx */ + POWERPC_DEF("STB04", CPU_POWERPC_STB04, 0xFFFF0000, 405), + /* STB25xx */ + POWERPC_DEF("STB25", CPU_POWERPC_STB25, 0xFFFFFFFF, 405), +#if defined (TODO) + /* STB130 */ + POWERPC_DEF("STB130", CPU_POWERPC_STB130, 0xFFFFFFFF, 405), +#endif + /* Xilinx PowerPC 405 cores */ + POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 0xFFFFFFFF, 405), + POWERPC_DEF("x2vp7", CPU_POWERPC_X2VP7, 0xFFFFFFFF, 405), + POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 0xFFFFFFFF, 405), + POWERPC_DEF("x2vp50", CPU_POWERPC_X2VP50, 0xFFFFFFFF, 405), +#if defined (TODO) + /* Zarlink ZL10310 */ + POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* Zarlink ZL10311 */ + POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* Zarlink ZL10320 */ + POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 0xFFFFFFFF, 405), +#endif +#if defined (TODO) + /* Zarlink ZL10321 */ + POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 0xFFFFFFFF, 405), +#endif + /* PowerPC 440 family */ + /* Generic PowerPC 440 */ + POWERPC_DEF("440", CPU_POWERPC_440, 0xFFFFFFFF, 440GP), + /* PowerPC 440 cores */ +#if defined (TODO) + /* PowerPC 440 A4 */ + POWERPC_DEF("440A4", CPU_POWERPC_440A4, 0xFFFFFFFF, 440x4), +#endif +#if defined (TODO) + /* PowerPC 440 A5 */ + POWERPC_DEF("440A5", CPU_POWERPC_440A5, 0xFFFFFFFF, 440x5), +#endif +#if defined (TODO) + /* PowerPC 440 B4 */ + POWERPC_DEF("440B4", CPU_POWERPC_440B4, 0xFFFFFFFF, 440x4), +#endif +#if defined (TODO) + /* PowerPC 440 G4 */ + POWERPC_DEF("440G4", CPU_POWERPC_440G4, 0xFFFFFFFF, 440x4), +#endif +#if defined (TODO) + /* PowerPC 440 F5 */ + POWERPC_DEF("440F5", CPU_POWERPC_440F5, 0xFFFFFFFF, 440x5), +#endif +#if defined (TODO) + /* PowerPC 440 G5 */ + POWERPC_DEF("440G5", CPU_POWERPC_440G5, 0xFFFFFFFF, 440x5), +#endif +#if defined (TODO) + /* PowerPC 440H4 */ + POWERPC_DEF("440H4", CPU_POWERPC_440H4, 0xFFFFFFFF, 440x4), +#endif +#if defined (TODO) + /* PowerPC 440H6 */ + POWERPC_DEF("440H6", CPU_POWERPC_440H6, 0xFFFFFFFF, 440Gx5), +#endif + /* PowerPC 440 microcontrolers */ + /* PowerPC 440 EP */ + POWERPC_DEF("440EP", CPU_POWERPC_440EP, 0xFFFFFFFF, 440EP), + /* PowerPC 440 EPa */ + POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 0xFFFFFFFF, 440EP), + /* PowerPC 440 EPb */ + POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 0xFFFFFFFF, 440EP), + /* PowerPC 440 EPX */ + POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 0xFFFFFFFF, 440EP), + /* PowerPC 440 GP */ + POWERPC_DEF("440GP", CPU_POWERPC_440GP, 0xFFFFFFFF, 440GP), + /* PowerPC 440 GPb */ + POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 0xFFFFFFFF, 440GP), + /* PowerPC 440 GPc */ + POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 0xFFFFFFFF, 440GP), + /* PowerPC 440 GR */ + POWERPC_DEF("440GR", CPU_POWERPC_440GR, 0xFFFFFFFF, 440x5), + /* PowerPC 440 GRa */ + POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 0xFFFFFFFF, 440x5), + /* PowerPC 440 GRX */ + POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 0xFFFFFFFF, 440x5), + /* PowerPC 440 GX */ + POWERPC_DEF("440GX", CPU_POWERPC_440GX, 0xFFFFFFFF, 440EP), + /* PowerPC 440 GXa */ + POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 0xFFFFFFFF, 440EP), + /* PowerPC 440 GXb */ + POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 0xFFFFFFFF, 440EP), + /* PowerPC 440 GXc */ + POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 0xFFFFFFFF, 440EP), + /* PowerPC 440 GXf */ + POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 0xFFFFFFFF, 440EP), +#if defined(TODO) + /* PowerPC 440 S */ + POWERPC_DEF("440S", CPU_POWERPC_440S, 0xFFFFFFFF, 440), +#endif + /* PowerPC 440 SP */ + POWERPC_DEF("440SP", CPU_POWERPC_440SP, 0xFFFFFFFF, 440EP), + /* PowerPC 440 SP2 */ + POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 0xFFFFFFFF, 440EP), + /* PowerPC 440 SPE */ + POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 0xFFFFFFFF, 440EP), + /* PowerPC 460 family */ +#if defined (TODO) + /* Generic PowerPC 464 */ + POWERPC_DEF("464", CPU_POWERPC_464, 0xFFFFFFFF, 460), +#endif + /* PowerPC 464 microcontrolers */ +#if defined (TODO) + /* PowerPC 464H90 */ + POWERPC_DEF("464H90", CPU_POWERPC_464H90, 0xFFFFFFFF, 460), +#endif +#if defined (TODO) + /* PowerPC 464H90F */ + POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 0xFFFFFFFF, 460F), +#endif + /* Freescale embedded PowerPC cores */ + /* e200 family */ +#if defined (TODO) + /* Generic PowerPC e200 core */ + POWERPC_DEF("e200", CPU_POWERPC_e200, 0xFFFFFFFF, e200), +#endif +#if defined (TODO) + /* PowerPC e200z5 core */ + POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, 0xFFFFFFFF, e200), +#endif +#if defined (TODO) + /* PowerPC e200z6 core */ + POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, 0xFFFFFFFF, e200), +#endif + /* e300 family */ +#if defined (TODO) + /* Generic PowerPC e300 core */ + POWERPC_DEF("e300", CPU_POWERPC_e300, 0xFFFFFFFF, e300), +#endif +#if defined (TODO) + /* PowerPC e300c1 core */ + POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, 0xFFFFFFFF, e300), +#endif +#if defined (TODO) + /* PowerPC e300c2 core */ + POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, 0xFFFFFFFF, e300), +#endif +#if defined (TODO) + /* PowerPC e300c3 core */ + POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, 0xFFFFFFFF, e300), +#endif + /* e500 family */ +#if defined (TODO) + /* PowerPC e500 core */ + POWERPC_DEF("e500", CPU_POWERPC_e500, 0xFFFFFFFF, e500), +#endif +#if defined (TODO) + /* PowerPC e500 v1.1 core */ + POWERPC_DEF("e500v1.1", CPU_POWERPC_e500_v11, 0xFFFFFFFF, e500), +#endif +#if defined (TODO) + /* PowerPC e500 v1.2 core */ + POWERPC_DEF("e500v1.2", CPU_POWERPC_e500_v12, 0xFFFFFFFF, e500), +#endif +#if defined (TODO) + /* PowerPC e500 v2.1 core */ + POWERPC_DEF("e500v2.1", CPU_POWERPC_e500_v21, 0xFFFFFFFF, e500), +#endif +#if defined (TODO) + /* PowerPC e500 v2.2 core */ + POWERPC_DEF("e500v2.2", CPU_POWERPC_e500_v22, 0xFFFFFFFF, e500), +#endif + /* e600 family */ +#if defined (TODO) + /* PowerPC e600 core */ + POWERPC_DEF("e600", CPU_POWERPC_e600, 0xFFFFFFFF, e600), +#endif + /* PowerPC MPC 5xx cores */ +#if defined (TODO) + /* PowerPC MPC 5xx */ + POWERPC_DEF("mpc5xx", CPU_POWERPC_5xx, 0xFFFFFFFF, 5xx), +#endif + /* PowerPC MPC 8xx cores */ +#if defined (TODO) + /* PowerPC MPC 8xx */ + POWERPC_DEF("mpc8xx", CPU_POWERPC_8xx, 0xFFFFFFFF, 8xx), +#endif + /* PowerPC MPC 8xxx cores */ +#if defined (TODO) + /* PowerPC MPC 82xx HIP3 */ + POWERPC_DEF("mpc82xxhip3", CPU_POWERPC_82xx_HIP3, 0xFFFFFFFF, 82xx), +#endif +#if defined (TODO) + /* PowerPC MPC 82xx HIP4 */ + POWERPC_DEF("mpc82xxhip4", CPU_POWERPC_82xx_HIP4, 0xFFFFFFFF, 82xx), +#endif +#if defined (TODO) + /* PowerPC MPC 827x */ + POWERPC_DEF("mpc827x", CPU_POWERPC_827x, 0xFFFFFFFF, 827x), +#endif + + /* 32 bits "classic" PowerPC */ + /* PowerPC 6xx family */ + /* PowerPC 601 */ + POWERPC_DEF("601", CPU_POWERPC_601, 0xFFFFFFFF, 601), + /* PowerPC 601v2 */ + POWERPC_DEF("601a", CPU_POWERPC_601a, 0xFFFFFFFF, 601), + /* PowerPC 602 */ + POWERPC_DEF("602", CPU_POWERPC_602, 0xFFFFFFFF, 602), + /* PowerPC 603 */ + POWERPC_DEF("603", CPU_POWERPC_603, 0xFFFFFFFF, 603), + /* Code name for PowerPC 603 */ + POWERPC_DEF("Vanilla", CPU_POWERPC_603, 0xFFFFFFFF, 603), + /* PowerPC 603e */ + POWERPC_DEF("603e", CPU_POWERPC_603E, 0xFFFFFFFF, 603E), + /* Code name for PowerPC 603e */ + POWERPC_DEF("Stretch", CPU_POWERPC_603E, 0xFFFFFFFF, 603E), + /* PowerPC 603e v1.1 */ + POWERPC_DEF("603e1.1", CPU_POWERPC_603E_v11, 0xFFFFFFFF, 603E), + /* PowerPC 603e v1.2 */ + POWERPC_DEF("603e1.2", CPU_POWERPC_603E_v12, 0xFFFFFFFF, 603E), + /* PowerPC 603e v1.3 */ + POWERPC_DEF("603e1.3", CPU_POWERPC_603E_v13, 0xFFFFFFFF, 603E), + /* PowerPC 603e v1.4 */ + POWERPC_DEF("603e1.4", CPU_POWERPC_603E_v14, 0xFFFFFFFF, 603E), + /* PowerPC 603e v2.2 */ + POWERPC_DEF("603e2.2", CPU_POWERPC_603E_v22, 0xFFFFFFFF, 603E), + /* PowerPC 603e v3 */ + POWERPC_DEF("603e3", CPU_POWERPC_603E_v3, 0xFFFFFFFF, 603E), + /* PowerPC 603e v4 */ + POWERPC_DEF("603e4", CPU_POWERPC_603E_v4, 0xFFFFFFFF, 603E), + /* PowerPC 603e v4.1 */ + POWERPC_DEF("603e4.1", CPU_POWERPC_603E_v41, 0xFFFFFFFF, 603E), + /* PowerPC 603e */ + POWERPC_DEF("603e7", CPU_POWERPC_603E7, 0xFFFFFFFF, 603E), + /* PowerPC 603e7t */ + POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 0xFFFFFFFF, 603E), + /* PowerPC 603e7v */ + POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 0xFFFFFFFF, 603E), + /* Code name for PowerPC 603ev */ + POWERPC_DEF("Vaillant", CPU_POWERPC_603E7v, 0xFFFFFFFF, 603E), + /* PowerPC 603e7v1 */ + POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 0xFFFFFFFF, 603E), + /* PowerPC 603e7v2 */ + POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 0xFFFFFFFF, 603E), + /* PowerPC 603p */ + /* to be checked */ + POWERPC_DEF("603p", CPU_POWERPC_603P, 0xFFFFFFFF, 603), + /* PowerPC 603r */ + POWERPC_DEF("603r", CPU_POWERPC_603R, 0xFFFFFFFF, 603E), + /* Code name for PowerPC 603r */ + POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 0xFFFFFFFF, 603E), + /* PowerPC G2 core */ + POWERPC_DEF("G2", CPU_POWERPC_G2, 0xFFFFFFFF, G2), + /* PowerPC G2 H4 */ + POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, 0xFFFFFFFF, G2), + /* PowerPC G2 GP */ + POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, 0xFFFFFFFF, G2), + /* PowerPC G2 LS */ + POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, 0xFFFFFFFF, G2), + /* PowerPC G2LE */ + /* Same as G2, with little-endian mode support */ + POWERPC_DEF("G2le", CPU_POWERPC_G2LE, 0xFFFFFFFF, G2LE), + /* PowerPC G2LE GP */ + POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, 0xFFFFFFFF, G2LE), + /* PowerPC G2LE LS */ + POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, 0xFFFFFFFF, G2LE), + /* PowerPC 604 */ + POWERPC_DEF("604", CPU_POWERPC_604, 0xFFFFFFFF, 604), + /* PowerPC 604e */ + POWERPC_DEF("604e", CPU_POWERPC_604E, 0xFFFFFFFF, 604), + /* PowerPC 604e v1.0 */ + POWERPC_DEF("604e1.0", CPU_POWERPC_604E_v10, 0xFFFFFFFF, 604), + /* PowerPC 604e v2.2 */ + POWERPC_DEF("604e2.2", CPU_POWERPC_604E_v22, 0xFFFFFFFF, 604), + /* PowerPC 604e v2.4 */ + POWERPC_DEF("604e2.4", CPU_POWERPC_604E_v24, 0xFFFFFFFF, 604), + /* PowerPC 604r */ + POWERPC_DEF("604r", CPU_POWERPC_604R, 0xFFFFFFFF, 604), +#if defined(TODO) + /* PowerPC 604ev */ + POWERPC_DEF("604ev", CPU_POWERPC_604EV, 0xFFFFFFFF, 604), +#endif + /* PowerPC 7xx family */ + /* Generic PowerPC 740 (G3) */ + POWERPC_DEF("740", CPU_POWERPC_7x0, 0xFFFFFFFF, 7x0), + /* Generic PowerPC 750 (G3) */ + POWERPC_DEF("750", CPU_POWERPC_7x0, 0xFFFFFFFF, 7x0), + /* Code name for generic PowerPC 740/750 (G3) */ + POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 0xFFFFFFFF, 7x0), + /* PowerPC 740/750 is also known as G3 */ + POWERPC_DEF("G3", CPU_POWERPC_7x0, 0xFFFFFFFF, 7x0), + /* PowerPC 740 v2.0 (G3) */ + POWERPC_DEF("740v2.0", CPU_POWERPC_7x0_v20, 0xFFFFFFFF, 7x0), + /* PowerPC 750 v2.0 (G3) */ + POWERPC_DEF("750v2.0", CPU_POWERPC_7x0_v20, 0xFFFFFFFF, 7x0), + /* PowerPC 740 v2.1 (G3) */ + POWERPC_DEF("740v2.1", CPU_POWERPC_7x0_v21, 0xFFFFFFFF, 7x0), + /* PowerPC 750 v2.1 (G3) */ + POWERPC_DEF("750v2.1", CPU_POWERPC_7x0_v21, 0xFFFFFFFF, 7x0), + /* PowerPC 740 v2.2 (G3) */ + POWERPC_DEF("740v2.2", CPU_POWERPC_7x0_v22, 0xFFFFFFFF, 7x0), + /* PowerPC 750 v2.2 (G3) */ + POWERPC_DEF("750v2.2", CPU_POWERPC_7x0_v22, 0xFFFFFFFF, 7x0), + /* PowerPC 740 v3.0 (G3) */ + POWERPC_DEF("740v3.0", CPU_POWERPC_7x0_v30, 0xFFFFFFFF, 7x0), + /* PowerPC 750 v3.0 (G3) */ + POWERPC_DEF("750v3.0", CPU_POWERPC_7x0_v30, 0xFFFFFFFF, 7x0), + /* PowerPC 740 v3.1 (G3) */ + POWERPC_DEF("740v3.1", CPU_POWERPC_7x0_v31, 0xFFFFFFFF, 7x0), + /* PowerPC 750 v3.1 (G3) */ + POWERPC_DEF("750v3.1", CPU_POWERPC_7x0_v31, 0xFFFFFFFF, 7x0), + /* PowerPC 740E (G3) */ + POWERPC_DEF("740e", CPU_POWERPC_740E, 0xFFFFFFFF, 7x0), + /* PowerPC 740P (G3) */ + POWERPC_DEF("740p", CPU_POWERPC_7x0P, 0xFFFFFFFF, 7x0), + /* PowerPC 750P (G3) */ + POWERPC_DEF("750p", CPU_POWERPC_7x0P, 0xFFFFFFFF, 7x0), + /* Code name for PowerPC 740P/750P (G3) */ + POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 0xFFFFFFFF, 7x0), + /* PowerPC 750CL (G3 embedded) */ + POWERPC_DEF("750cl", CPU_POWERPC_750CL, 0xFFFFFFFF, 7x0), + /* PowerPC 750CX (G3 embedded) */ + POWERPC_DEF("750cx", CPU_POWERPC_750CX, 0xFFFFFFFF, 7x0), + /* PowerPC 750CX v2.1 (G3 embedded) */ + POWERPC_DEF("750cx2.1", CPU_POWERPC_750CX_v21, 0xFFFFFFFF, 7x0), + /* PowerPC 750CX v2.2 (G3 embedded) */ + POWERPC_DEF("750cx2.2", CPU_POWERPC_750CX_v22, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXe (G3 embedded) */ + POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXe v2.1 (G3 embedded) */ + POWERPC_DEF("750cxe21", CPU_POWERPC_750CXE_v21, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXe v2.2 (G3 embedded) */ + POWERPC_DEF("750cxe22", CPU_POWERPC_750CXE_v22, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXe v2.3 (G3 embedded) */ + POWERPC_DEF("750cxe23", CPU_POWERPC_750CXE_v23, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXe v2.4 (G3 embedded) */ + POWERPC_DEF("750cxe24", CPU_POWERPC_750CXE_v24, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXe v2.4b (G3 embedded) */ + POWERPC_DEF("750cxe24b", CPU_POWERPC_750CXE_v24b, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXe v3.1 (G3 embedded) */ + POWERPC_DEF("750cxe31", CPU_POWERPC_750CXE_v31, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXe v3.1b (G3 embedded) */ + POWERPC_DEF("750cxe3.1b", CPU_POWERPC_750CXE_v31b, 0xFFFFFFFF, 7x0), + /* PowerPC 750CXr (G3 embedded) */ + POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 0xFFFFFFFF, 7x0), + /* PowerPC 750E (G3) */ + POWERPC_DEF("750e", CPU_POWERPC_750E, 0xFFFFFFFF, 7x0), + /* PowerPC 750FL (G3 embedded) */ + POWERPC_DEF("750fl", CPU_POWERPC_750FL, 0xFFFFFFFF, 7x0), + /* PowerPC 750FX (G3 embedded) */ + POWERPC_DEF("750fx", CPU_POWERPC_750FX, 0xFFFFFFFF, 750fx), + /* PowerPC 750FX v1.0 (G3 embedded) */ + POWERPC_DEF("750fx1.0", CPU_POWERPC_750FX_v10, 0xFFFFFFFF, 750fx), + /* PowerPC 750FX v2.0 (G3 embedded) */ + POWERPC_DEF("750fx2.0", CPU_POWERPC_750FX_v20, 0xFFFFFFFF, 750fx), + /* PowerPC 750FX v2.1 (G3 embedded) */ + POWERPC_DEF("750fx2.1", CPU_POWERPC_750FX_v21, 0xFFFFFFFF, 750fx), + /* PowerPC 750FX v2.2 (G3 embedded) */ + POWERPC_DEF("750fx2.2", CPU_POWERPC_750FX_v22, 0xFFFFFFFF, 750fx), + /* PowerPC 750FX v2.3 (G3 embedded) */ + POWERPC_DEF("750fx2.3", CPU_POWERPC_750FX_v23, 0xFFFFFFFF, 750fx), + /* PowerPC 750GL (G3 embedded) */ + POWERPC_DEF("750gl", CPU_POWERPC_750GL, 0xFFFFFFFF, 7x0), + /* PowerPC 750GX (G3 embedded) */ + POWERPC_DEF("750gx", CPU_POWERPC_750GX, 0xFFFFFFFF, 750fx), + /* PowerPC 750GX v1.0 (G3 embedded) */ + POWERPC_DEF("750gx1.0", CPU_POWERPC_750GX_v10, 0xFFFFFFFF, 750fx), + /* PowerPC 750GX v1.1 (G3 embedded) */ + POWERPC_DEF("750gx1.1", CPU_POWERPC_750GX_v11, 0xFFFFFFFF, 750fx), + /* PowerPC 750GX v1.2 (G3 embedded) */ + POWERPC_DEF("750gx1.2", CPU_POWERPC_750GX_v12, 0xFFFFFFFF, 750fx), + /* PowerPC 750L (G3 embedded) */ + POWERPC_DEF("750l", CPU_POWERPC_750L, 0xFFFFFFFF, 7x0), + /* Code name for PowerPC 750L (G3 embedded) */ + POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 0xFFFFFFFF, 7x0), + /* PowerPC 750L v2.2 (G3 embedded) */ + POWERPC_DEF("750l2.2", CPU_POWERPC_750L_v22, 0xFFFFFFFF, 7x0), + /* PowerPC 750L v3.0 (G3 embedded) */ + POWERPC_DEF("750l3.0", CPU_POWERPC_750L_v30, 0xFFFFFFFF, 7x0), + /* PowerPC 750L v3.2 (G3 embedded) */ + POWERPC_DEF("750l3.2", CPU_POWERPC_750L_v32, 0xFFFFFFFF, 7x0), + /* Generic PowerPC 745 */ + POWERPC_DEF("745", CPU_POWERPC_7x5, 0xFFFFFFFF, 7x5), + /* Generic PowerPC 755 */ + POWERPC_DEF("755", CPU_POWERPC_7x5, 0xFFFFFFFF, 7x5), + /* Code name for PowerPC 745/755 */ + POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v1.0 */ + POWERPC_DEF("745v1.0", CPU_POWERPC_7x5_v10, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v1.0 */ + POWERPC_DEF("755v1.0", CPU_POWERPC_7x5_v10, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v1.1 */ + POWERPC_DEF("745v1.1", CPU_POWERPC_7x5_v11, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v1.1 */ + POWERPC_DEF("755v1.1", CPU_POWERPC_7x5_v11, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.0 */ + POWERPC_DEF("745v2.0", CPU_POWERPC_7x5_v20, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.0 */ + POWERPC_DEF("755v2.0", CPU_POWERPC_7x5_v20, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.1 */ + POWERPC_DEF("745v2.1", CPU_POWERPC_7x5_v21, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.1 */ + POWERPC_DEF("755v2.1", CPU_POWERPC_7x5_v21, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.2 */ + POWERPC_DEF("745v2.2", CPU_POWERPC_7x5_v22, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.2 */ + POWERPC_DEF("755v2.2", CPU_POWERPC_7x5_v22, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.3 */ + POWERPC_DEF("745v2.3", CPU_POWERPC_7x5_v23, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.3 */ + POWERPC_DEF("755v2.3", CPU_POWERPC_7x5_v23, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.4 */ + POWERPC_DEF("745v2.4", CPU_POWERPC_7x5_v24, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.4 */ + POWERPC_DEF("755v2.4", CPU_POWERPC_7x5_v24, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.5 */ + POWERPC_DEF("745v2.5", CPU_POWERPC_7x5_v25, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.5 */ + POWERPC_DEF("755v2.5", CPU_POWERPC_7x5_v25, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.6 */ + POWERPC_DEF("745v2.6", CPU_POWERPC_7x5_v26, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.6 */ + POWERPC_DEF("755v2.6", CPU_POWERPC_7x5_v26, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.7 */ + POWERPC_DEF("745v2.7", CPU_POWERPC_7x5_v27, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.7 */ + POWERPC_DEF("755v2.7", CPU_POWERPC_7x5_v27, 0xFFFFFFFF, 7x5), + /* PowerPC 745 v2.8 */ + POWERPC_DEF("745v2.8", CPU_POWERPC_7x5_v28, 0xFFFFFFFF, 7x5), + /* PowerPC 755 v2.8 */ + POWERPC_DEF("755v2.8", CPU_POWERPC_7x5_v28, 0xFFFFFFFF, 7x5), +#if defined (TODO) + /* PowerPC 745P (G3) */ + POWERPC_DEF("745p", CPU_POWERPC_7x5P, 0xFFFFFFFF, 7x5), + /* PowerPC 755P (G3) */ + POWERPC_DEF("755p", CPU_POWERPC_7x5P, 0xFFFFFFFF, 7x5), +#endif + /* PowerPC 74xx family */ + /* PowerPC 7400 (G4) */ + POWERPC_DEF("7400", CPU_POWERPC_7400, 0xFFFFFFFF, 7400), + /* Code name for PowerPC 7400 */ + POWERPC_DEF("Max", CPU_POWERPC_7400, 0xFFFFFFFF, 7400), + /* PowerPC 74xx is also well known as G4 */ + POWERPC_DEF("G4", CPU_POWERPC_7400, 0xFFFFFFFF, 7400), + /* PowerPC 7400 v1.0 (G4) */ + POWERPC_DEF("7400v1.0", CPU_POWERPC_7400_v10, 0xFFFFFFFF, 7400), + /* PowerPC 7400 v1.1 (G4) */ + POWERPC_DEF("7400v1.1", CPU_POWERPC_7400_v11, 0xFFFFFFFF, 7400), + /* PowerPC 7400 v2.0 (G4) */ + POWERPC_DEF("7400v2.0", CPU_POWERPC_7400_v20, 0xFFFFFFFF, 7400), + /* PowerPC 7400 v2.2 (G4) */ + POWERPC_DEF("7400v2.2", CPU_POWERPC_7400_v22, 0xFFFFFFFF, 7400), + /* PowerPC 7400 v2.6 (G4) */ + POWERPC_DEF("7400v2.6", CPU_POWERPC_7400_v26, 0xFFFFFFFF, 7400), + /* PowerPC 7400 v2.7 (G4) */ + POWERPC_DEF("7400v2.7", CPU_POWERPC_7400_v27, 0xFFFFFFFF, 7400), + /* PowerPC 7400 v2.8 (G4) */ + POWERPC_DEF("7400v2.8", CPU_POWERPC_7400_v28, 0xFFFFFFFF, 7400), + /* PowerPC 7400 v2.9 (G4) */ + POWERPC_DEF("7400v2.9", CPU_POWERPC_7400_v29, 0xFFFFFFFF, 7400), + /* PowerPC 7410 (G4) */ + POWERPC_DEF("7410", CPU_POWERPC_7410, 0xFFFFFFFF, 7410), + /* Code name for PowerPC 7410 */ + POWERPC_DEF("Nitro", CPU_POWERPC_7410, 0xFFFFFFFF, 7410), + /* PowerPC 7410 v1.0 (G4) */ + POWERPC_DEF("7410v1.0", CPU_POWERPC_7410_v10, 0xFFFFFFFF, 7410), + /* PowerPC 7410 v1.1 (G4) */ + POWERPC_DEF("7410v1.1", CPU_POWERPC_7410_v11, 0xFFFFFFFF, 7410), + /* PowerPC 7410 v1.2 (G4) */ + POWERPC_DEF("7410v1.2", CPU_POWERPC_7410_v12, 0xFFFFFFFF, 7410), + /* PowerPC 7410 v1.3 (G4) */ + POWERPC_DEF("7410v1.3", CPU_POWERPC_7410_v13, 0xFFFFFFFF, 7410), + /* PowerPC 7410 v1.4 (G4) */ + POWERPC_DEF("7410v1.4", CPU_POWERPC_7410_v14, 0xFFFFFFFF, 7410), + /* PowerPC 7448 (G4) */ + POWERPC_DEF("7448", CPU_POWERPC_7448, 0xFFFFFFFF, 7400), + /* PowerPC 7448 v1.0 (G4) */ + POWERPC_DEF("7448v1.0", CPU_POWERPC_7448_v10, 0xFFFFFFFF, 7400), + /* PowerPC 7448 v1.1 (G4) */ + POWERPC_DEF("7448v1.1", CPU_POWERPC_7448_v11, 0xFFFFFFFF, 7400), + /* PowerPC 7448 v2.0 (G4) */ + POWERPC_DEF("7448v2.0", CPU_POWERPC_7448_v20, 0xFFFFFFFF, 7400), + /* PowerPC 7448 v2.1 (G4) */ + POWERPC_DEF("7448v2.1", CPU_POWERPC_7448_v21, 0xFFFFFFFF, 7400), +#if defined (TODO) + /* PowerPC 7450 (G4) */ + POWERPC_DEF("7450", CPU_POWERPC_7450, 0xFFFFFFFF, 7450), + /* Code name for PowerPC 7450 */ + POWERPC_DEF("Vger", CPU_POWERPC_7450, 0xFFFFFFFF, 7450), +#endif +#if defined (TODO) + /* PowerPC 7450 v1.0 (G4) */ + POWERPC_DEF("7450v1.0", CPU_POWERPC_7450_v10, 0xFFFFFFFF, 7450), +#endif +#if defined (TODO) + /* PowerPC 7450 v1.1 (G4) */ + POWERPC_DEF("7450v1.1", CPU_POWERPC_7450_v11, 0xFFFFFFFF, 7450), +#endif +#if defined (TODO) + /* PowerPC 7450 v1.2 (G4) */ + POWERPC_DEF("7450v1.2", CPU_POWERPC_7450_v12, 0xFFFFFFFF, 7450), +#endif +#if defined (TODO) + /* PowerPC 7450 v2.0 (G4) */ + POWERPC_DEF("7450v2.0", CPU_POWERPC_7450_v20, 0xFFFFFFFF, 7450), +#endif +#if defined (TODO) + /* PowerPC 7450 v2.1 (G4) */ + POWERPC_DEF("7450v2.1", CPU_POWERPC_7450_v21, 0xFFFFFFFF, 7450), +#endif +#if defined (TODO) + /* PowerPC 7441 (G4) */ + POWERPC_DEF("7441", CPU_POWERPC_74x1, 0xFFFFFFFF, 7440), + /* PowerPC 7451 (G4) */ + POWERPC_DEF("7451", CPU_POWERPC_74x1, 0xFFFFFFFF, 7450), +#endif #if defined (TODO) - /* PowerPC 405 EZ */ - { - .name = "405ez", - .pvr = CPU_PPC_405EZ, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7441g (G4) */ + POWERPC_DEF("7441g", CPU_POWERPC_74x1G, 0xFFFFFFFF, 7440), + /* PowerPC 7451g (G4) */ + POWERPC_DEF("7451g", CPU_POWERPC_74x1G, 0xFFFFFFFF, 7450), #endif #if defined (TODO) - /* PowerPC 405 GPR */ - { - .name = "405gpr", - .pvr = CPU_PPC_405GPR, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7445 (G4) */ + POWERPC_DEF("7445", CPU_POWERPC_74x5, 0xFFFFFFFF, 7445), + /* PowerPC 7455 (G4) */ + POWERPC_DEF("7455", CPU_POWERPC_74x5, 0xFFFFFFFF, 7455), + /* Code name for PowerPC 7445/7455 */ + POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 0xFFFFFFFF, 7455), #endif #if defined (TODO) - /* PowerPC 405 LP */ - { - .name = "405lp", - .pvr = CPU_PPC_405EZ, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, -#endif - /* Npe405 H */ - { - .name = "Npe405H", - .pvr = CPU_PPC_NPE405H, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - /* Npe405 H2 */ - { - .name = "Npe405H2", - .pvr = CPU_PPC_NPE405H2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - /* Npe405 L */ - { - .name = "Npe405L", - .pvr = CPU_PPC_NPE405L, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7445 v1.0 (G4) */ + POWERPC_DEF("7445v1.0", CPU_POWERPC_74x5_v10, 0xFFFFFFFF, 7445), + /* PowerPC 7455 v1.0 (G4) */ + POWERPC_DEF("7455v1.0", CPU_POWERPC_74x5_v10, 0xFFFFFFFF, 7455), +#endif #if defined (TODO) - /* PowerPC LP777000 */ - { - .name = "lp777000", - .pvr = CPU_PPC_LP777000, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7445 v2.1 (G4) */ + POWERPC_DEF("7445v2.1", CPU_POWERPC_74x5_v21, 0xFFFFFFFF, 7445), + /* PowerPC 7455 v2.1 (G4) */ + POWERPC_DEF("7455v2.1", CPU_POWERPC_74x5_v21, 0xFFFFFFFF, 7455), #endif #if defined (TODO) - /* STB010000 */ - { - .name = "STB01000", - .pvr = CPU_PPC_STB01000, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7445 v3.2 (G4) */ + POWERPC_DEF("7445v3.2", CPU_POWERPC_74x5_v32, 0xFFFFFFFF, 7445), + /* PowerPC 7455 v3.2 (G4) */ + POWERPC_DEF("7455v3.2", CPU_POWERPC_74x5_v32, 0xFFFFFFFF, 7455), #endif #if defined (TODO) - /* STB01010 */ - { - .name = "STB01010", - .pvr = CPU_PPC_STB01010, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7445 v3.3 (G4) */ + POWERPC_DEF("7445v3.3", CPU_POWERPC_74x5_v33, 0xFFFFFFFF, 7445), + /* PowerPC 7455 v3.3 (G4) */ + POWERPC_DEF("7455v3.3", CPU_POWERPC_74x5_v33, 0xFFFFFFFF, 7455), #endif #if defined (TODO) - /* STB0210 */ - { - .name = "STB0210", - .pvr = CPU_PPC_STB0210, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7445 v3.4 (G4) */ + POWERPC_DEF("7445v3.4", CPU_POWERPC_74x5_v34, 0xFFFFFFFF, 7445), + /* PowerPC 7455 v3.4 (G4) */ + POWERPC_DEF("7455v3.4", CPU_POWERPC_74x5_v34, 0xFFFFFFFF, 7455), #endif #if defined (TODO) - /* STB03xx */ - { - .name = "STB03", - .pvr = CPU_PPC_STB03, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7447 (G4) */ + POWERPC_DEF("7447", CPU_POWERPC_74x7, 0xFFFFFFFF, 7445), + /* PowerPC 7457 (G4) */ + POWERPC_DEF("7457", CPU_POWERPC_74x7, 0xFFFFFFFF, 7455), + /* Code name for PowerPC 7447/7457 */ + POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 0xFFFFFFFF, 7455), #endif #if defined (TODO) - /* STB043x */ - { - .name = "STB043", - .pvr = CPU_PPC_STB043, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7447 v1.0 (G4) */ + POWERPC_DEF("7447v1.0", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7445), + /* PowerPC 7457 v1.0 (G4) */ + POWERPC_DEF("7457v1.0", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7455), + /* Code name for PowerPC 7447A/7457A */ + POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7455), #endif #if defined (TODO) - /* STB045x */ - { - .name = "STB045", - .pvr = CPU_PPC_STB045, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, -#endif -#if defined (TODO) || 1 - /* STB25xx */ - { - .name = "STB25", - .pvr = CPU_PPC_STB25, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, + /* PowerPC 7447 v1.1 (G4) */ + POWERPC_DEF("7447v1.1", CPU_POWERPC_74x7_v11, 0xFFFFFFFF, 7445), + /* PowerPC 7457 v1.1 (G4) */ + POWERPC_DEF("7457v1.1", CPU_POWERPC_74x7_v11, 0xFFFFFFFF, 7455), #endif #if defined (TODO) - /* STB130 */ - { - .name = "STB130", - .pvr = CPU_PPC_STB130, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, -#endif - /* Xilinx PowerPC 405 cores */ + /* PowerPC 7447 v1.2 (G4) */ + POWERPC_DEF("7447v1.2", CPU_POWERPC_74x7_v12, 0xFFFFFFFF, 7445), + /* PowerPC 7457 v1.2 (G4) */ + POWERPC_DEF("7457v1.2", CPU_POWERPC_74x7_v12, 0xFFFFFFFF, 7455), +#endif + /* 64 bits PowerPC */ +#if defined (TARGET_PPC64) #if defined (TODO) - { - .name = "x2vp4", - .pvr = CPU_PPC_X2VP4, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - { - .name = "x2vp7", - .pvr = CPU_PPC_X2VP7, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - { - .name = "x2vp20", - .pvr = CPU_PPC_X2VP20, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, - { - .name = "x2vp50", - .pvr = CPU_PPC_X2VP50, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30ULL, - }, -#endif - /* PowerPC 440 EP */ - { - .name = "440ep", - .pvr = CPU_PPC_440EP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, - /* PowerPC 440 GR */ - { - .name = "440gr", - .pvr = CPU_PPC_440GR, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, - /* PowerPC 440 GP */ - { - .name = "440gp", - .pvr = CPU_PPC_440GP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, + /* PowerPC 620 */ + POWERPC_DEF("620", CPU_POWERPC_620, 0xFFFFFFFF, 620), +#endif #if defined (TODO) - /* PowerPC 440 GRX */ - { - .name = "440grx", - .pvr = CPU_PPC_440GRX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, -#endif - /* PowerPC 440 GX */ - { - .name = "440gx", - .pvr = CPU_PPC_440GX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, - /* PowerPC 440 GXc */ - { - .name = "440gxc", - .pvr = CPU_PPC_440GXc, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, - /* PowerPC 440 GXf */ - { - .name = "440gxf", - .pvr = CPU_PPC_440GXf, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, - /* PowerPC 440 SP */ - { - .name = "440sp", - .pvr = CPU_PPC_440SP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, - /* PowerPC 440 SP2 */ - { - .name = "440sp2", - .pvr = CPU_PPC_440SP2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, - /* PowerPC 440 SPE */ - { - .name = "440spe", - .pvr = CPU_PPC_440SPE, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630ULL, - }, - /* Fake generic BookE PowerPC */ - { - .name = "BookE", - .pvr = CPU_PPC_e500, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_BOOKE, - .flags = PPC_FLAGS_BOOKE, - .msr_mask = 0x000000000006D630ULL, - }, - /* PowerPC 460 cores - TODO */ - /* PowerPC MPC 5xx cores - TODO */ - /* PowerPC MPC 8xx cores - TODO */ - /* PowerPC MPC 8xxx cores - TODO */ - /* e200 cores - TODO */ - /* e500 cores - TODO */ - /* e600 cores - TODO */ - - /* 32 bits "classic" PowerPC */ + /* PowerPC 630 (POWER3) */ + POWERPC_DEF("630", CPU_POWERPC_630, 0xFFFFFFFF, 630), + POWERPC_DEF("POWER3", CPU_POWERPC_630, 0xFFFFFFFF, 630), +#endif #if defined (TODO) - /* PowerPC 601 */ - { - .name = "601", - .pvr = CPU_PPC_601, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_601, - .flags = PPC_FLAGS_601, - .msr_mask = 0x000000000000FD70ULL, - }, + /* PowerPC 631 (Power 3+) */ + POWERPC_DEF("631", CPU_POWERPC_631, 0xFFFFFFFF, 631), + POWERPC_DEF("POWER3+", CPU_POWERPC_631, 0xFFFFFFFF, 631), #endif #if defined (TODO) - /* PowerPC 602 */ - { - .name = "602", - .pvr = CPU_PPC_602, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_602, - .flags = PPC_FLAGS_602, - .msr_mask = 0x0000000000C7FF73ULL, - }, -#endif - /* PowerPC 603 */ - { - .name = "603", - .pvr = CPU_PPC_603, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, - /* PowerPC 603e */ - { - .name = "603e", - .pvr = CPU_PPC_603E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, - { - .name = "Stretch", - .pvr = CPU_PPC_603E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, - /* PowerPC 603p */ - { - .name = "603p", - .pvr = CPU_PPC_603P, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, - /* PowerPC 603e7 */ - { - .name = "603e7", - .pvr = CPU_PPC_603E7, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, - /* PowerPC 603e7v */ - { - .name = "603e7v", - .pvr = CPU_PPC_603E7v, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, - /* PowerPC 603e7v2 */ - { - .name = "603e7v2", - .pvr = CPU_PPC_603E7v2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, - /* PowerPC 603r */ - { - .name = "603r", - .pvr = CPU_PPC_603R, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, - { - .name = "Goldeneye", - .pvr = CPU_PPC_603R, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73ULL, - }, + /* POWER4 */ + POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, 0xFFFFFFFF, POWER4), +#endif #if defined (TODO) - /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ - { - .name = "G2", - .pvr = CPU_PPC_G2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2ULL, - }, - { - .name = "G2h4", - .pvr = CPU_PPC_G2H4, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2ULL, - }, - { - .name = "G2gp", - .pvr = CPU_PPC_G2gp, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2ULL, - }, - { - .name = "G2ls", - .pvr = CPU_PPC_G2ls, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2ULL, - }, - { /* Same as G2, with LE mode support */ - .name = "G2le", - .pvr = CPU_PPC_G2LE, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3ULL, - }, - { - .name = "G2legp", - .pvr = CPU_PPC_G2LEgp, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3ULL, - }, - { - .name = "G2lels", - .pvr = CPU_PPC_G2LEls, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3ULL, - }, -#endif - /* PowerPC 604 */ - { - .name = "604", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77ULL, - }, - /* PowerPC 604e */ - { - .name = "604e", - .pvr = CPU_PPC_604E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77ULL, - }, - /* PowerPC 604r */ - { - .name = "604r", - .pvr = CPU_PPC_604R, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77ULL, - }, - /* generic G3 */ - { - .name = "G3", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* MPC740 (G3) */ - { - .name = "740", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - { - .name = "Arthur", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* 740E (G3) */ - { - .name = "740e", - .pvr = CPU_PPC_740E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* MPC740P (G3) */ - { - .name = "740p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - { - .name = "Conan/Doyle", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, + /* POWER4p */ + POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, 0xFFFFFFFF, POWER4P), +#endif #if defined (TODO) - /* MPC745 (G3) */ - { - .name = "745", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, - { - .name = "Goldfinger", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, + /* POWER5 */ + POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, 0xFFFFFFFF, POWER5), + /* POWER5GR */ + POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, 0xFFFFFFFF, POWER5), #endif #if defined (TODO) - /* MPC745P (G3) */ - { - .name = "745p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, -#endif - /* MPC750 (G3) */ - { - .name = "750", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* MPC750P (G3) */ - { - .name = "750p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* 750E (G3) */ - { - .name = "750e", - .pvr = CPU_PPC_750E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* IBM 750CXe (G3 embedded) */ - { - .name = "750cxe", - .pvr = CPU_PPC_750CXE, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* IBM 750CXr (G3 embedded) */ - { - .name = "750cxr", - .pvr = CPU_PPC_750CXR, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* IBM 750FX (G3 embedded) */ - { - .name = "750fx", - .pvr = CPU_PPC_750FX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* IBM 750FL (G3 embedded) */ - { - .name = "750fl", - .pvr = CPU_PPC_750FL, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* IBM 750GX (G3 embedded) */ - { - .name = "750gx", - .pvr = CPU_PPC_750GX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* IBM 750L (G3 embedded) */ - { - .name = "750l", - .pvr = CPU_PPC_750L, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, - /* IBM 750CL (G3 embedded) */ - { - .name = "750cl", - .pvr = CPU_PPC_750CL, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77ULL, - }, + /* POWER5+ */ + POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, 0xFFFFFFFF, POWER5P), + /* POWER5GS */ + POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, 0xFFFFFFFF, POWER5P), +#endif #if defined (TODO) - /* MPC755 (G3) */ - { - .name = "755", - .pvr = CPU_PPC_755, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, + /* POWER6 */ + POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, 0xFFFFFFFF, POWER6), + /* POWER6 running in POWER5 mode */ + POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, 0xFFFFFFFF, POWER5), + /* POWER6A */ + POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, 0xFFFFFFFF, POWER6), #endif #if defined (TODO) - /* MPC755D (G3) */ - { - .name = "755d", - .pvr = CPU_PPC_755D, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, + /* PowerPC 970 */ + POWERPC_DEF("970", CPU_POWERPC_970, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* MPC755E (G3) */ - { - .name = "755e", - .pvr = CPU_PPC_755E, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, + /* PowerPC 970FX (G5) */ + POWERPC_DEF("970fx", CPU_POWERPC_970FX, 0xFFFFFFFF, 970FX), #endif #if defined (TODO) - /* MPC755P (G3) */ - { - .name = "755p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77ULL, - }, + /* PowerPC 970FX v1.0 (G5) */ + POWERPC_DEF("970fx1.0", CPU_POWERPC_970FX_v10, 0xFFFFFFFF, 970FX), #endif #if defined (TODO) - /* generic G4 */ - { - .name = "G4", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC 970FX v2.0 (G5) */ + POWERPC_DEF("970fx2.0", CPU_POWERPC_970FX_v20, 0xFFFFFFFF, 970FX), #endif #if defined (TODO) - /* PowerPC 7400 (G4) */ - { - .name = "7400", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, - { - .name = "Max", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC 970FX v2.1 (G5) */ + POWERPC_DEF("970fx2.1", CPU_POWERPC_970FX_v21, 0xFFFFFFFF, 970FX), #endif #if defined (TODO) - /* PowerPC 7410 (G4) */ - { - .name = "7410", - .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, - { - .name = "Nitro", - .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC 970FX v3.0 (G5) */ + POWERPC_DEF("970fx3.0", CPU_POWERPC_970FX_v30, 0xFFFFFFFF, 970FX), #endif #if defined (TODO) - /* PowerPC 7441 (G4) */ - { - .name = "7441", - .pvr = CPU_PPC_7441, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC 970FX v3.1 (G5) */ + POWERPC_DEF("970fx3.1", CPU_POWERPC_970FX_v31, 0xFFFFFFFF, 970FX), #endif #if defined (TODO) - /* PowerPC 7445 (G4) */ - { - .name = "7445", - .pvr = CPU_PPC_7445, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC 970GX (G5) */ + POWERPC_DEF("970gx", CPU_POWERPC_970GX, 0xFFFFFFFF, 970GX), #endif #if defined (TODO) - /* PowerPC 7447 (G4) */ - { - .name = "7447", - .pvr = CPU_PPC_7447, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC 970MP */ + POWERPC_DEF("970mp", CPU_POWERPC_970MP, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7447A (G4) */ - { - .name = "7447A", - .pvr = CPU_PPC_7447A, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC 970MP v1.0 */ + POWERPC_DEF("970mp1.0", CPU_POWERPC_970MP_v10, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7448 (G4) */ - { - .name = "7448", - .pvr = CPU_PPC_7448, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC 970MP v1.1 */ + POWERPC_DEF("970mp1.1", CPU_POWERPC_970MP_v11, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7450 (G4) */ - { - .name = "7450", - .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, - { - .name = "Vger", - .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC Cell */ + POWERPC_DEF("Cell", CPU_POWERPC_CELL, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7450b (G4) */ - { - .name = "7450b", - .pvr = CPU_PPC_7450B, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC Cell v1.0 */ + POWERPC_DEF("Cell1.0", CPU_POWERPC_CELL_v10, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7451 (G4) */ - { - .name = "7451", - .pvr = CPU_PPC_7451, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC Cell v2.0 */ + POWERPC_DEF("Cell2.0", CPU_POWERPC_CELL_v20, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7451g (G4) */ - { - .name = "7451g", - .pvr = CPU_PPC_7451G, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC Cell v3.0 */ + POWERPC_DEF("Cell3.0", CPU_POWERPC_CELL_v30, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7455 (G4) */ - { - .name = "7455", - .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, - { - .name = "Apollo 6", - .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC Cell v3.1 */ + POWERPC_DEF("Cell3.1", CPU_POWERPC_CELL_v31, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7455F (G4) */ - { - .name = "7455f", - .pvr = CPU_PPC_7455F, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* PowerPC Cell v3.2 */ + POWERPC_DEF("Cell3.2", CPU_POWERPC_CELL_v32, 0xFFFFFFFF, 970), #endif #if defined (TODO) - /* PowerPC 7455G (G4) */ - { - .name = "7455g", - .pvr = CPU_PPC_7455G, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* RS64 (Apache/A35) */ + /* This one seems to support the whole POWER2 instruction set + * and the PowerPC 64 one. + */ + /* What about A10 & A30 ? */ + POWERPC_DEF("RS64", CPU_POWERPC_RS64, 0xFFFFFFFF, RS64), + POWERPC_DEF("Apache", CPU_POWERPC_RS64, 0xFFFFFFFF, RS64), + POWERPC_DEF("A35", CPU_POWERPC_RS64, 0xFFFFFFFF, RS64), #endif #if defined (TODO) - /* PowerPC 7457 (G4) */ - { - .name = "7457", - .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, - { - .name = "Apollo 7", - .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* RS64-II (NorthStar/A50) */ + POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, 0xFFFFFFFF, RS64), + POWERPC_DEF("NorthStar", CPU_POWERPC_RS64II, 0xFFFFFFFF, RS64), + POWERPC_DEF("A50", CPU_POWERPC_RS64II, 0xFFFFFFFF, RS64), #endif #if defined (TODO) - /* PowerPC 7457A (G4) */ - { - .name = "7457A", - .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, - { - .name = "Apollo 7 PM", - .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* RS64-III (Pulsar) */ + POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, 0xFFFFFFFF, RS64), + POWERPC_DEF("Pulsar", CPU_POWERPC_RS64III, 0xFFFFFFFF, RS64), #endif #if defined (TODO) - /* PowerPC 7457C (G4) */ - { - .name = "7457c", - .pvr = CPU_PPC_7457C, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77ULL, - }, + /* RS64-IV (IceStar/IStar/SStar) */ + POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, 0xFFFFFFFF, RS64), + POWERPC_DEF("IceStar", CPU_POWERPC_RS64IV, 0xFFFFFFFF, RS64), + POWERPC_DEF("IStar", CPU_POWERPC_RS64IV, 0xFFFFFFFF, RS64), + POWERPC_DEF("SStar", CPU_POWERPC_RS64IV, 0xFFFFFFFF, RS64), #endif - /* 64 bits PowerPC */ -#if defined (TARGET_PPC64) +#endif /* defined (TARGET_PPC64) */ + /* POWER */ #if defined (TODO) - /* PowerPC 620 */ - { - .name = "620", - .pvr = CPU_PPC_620, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_620, - .flags = PPC_FLAGS_620, - .msr_mask = 0x800000000005FF73ULL, - }, + /* Original POWER */ + POWERPC_DEF("POWER", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), + POWERPC_DEF("RIOS", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), + POWERPC_DEF("RSC", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), + POWERPC_DEF("RSC3308", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), + POWERPC_DEF("RSC4608", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), #endif #if defined (TODO) - /* PowerPC 630 (POWER3) */ - { - .name = "630", - .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_630, - .flags = PPC_FLAGS_630, - .msr_mask = xxx, + /* POWER2 */ + POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, 0xFFFFFFFF, POWER), + POWERPC_DEF("RSC2", CPU_POWERPC_POWER2, 0xFFFFFFFF, POWER), + POWERPC_DEF("P2SC", CPU_POWERPC_POWER2, 0xFFFFFFFF, POWER), +#endif + /* PA semi cores */ +#if defined (TODO) + /* PA PA6T */ + POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, 0xFFFFFFFF, PA6T), +#endif + /* Generic PowerPCs */ +#if defined (TARGET_PPC64) +#if defined (TODO) + POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, 0xFFFFFFFF, PPC64), +#endif +#endif + POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, 0xFFFFFFFF, PPC32), + /* Fallback */ + POWERPC_DEF("ppc", CPU_POWERPC_PPC, 0xFFFFFFFF, PPC), +}; + +/*****************************************************************************/ +/* Generic CPU instanciation routine */ +static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) +{ +#if !defined(CONFIG_USER_ONLY) + env->irq_inputs = NULL; +#endif + /* Default MMU definitions */ + env->nb_BATs = 0; + env->nb_tlb = 0; + env->nb_ways = 0; + /* Register SPR common to all PowerPC implementations */ + gen_spr_generic(env); + spr_register(env, SPR_PVR, "PVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + def->pvr); + /* PowerPC implementation specific initialisations (SPRs, timers, ...) */ + (*def->init_proc)(env); + /* Allocate TLBs buffer when needed */ + if (env->nb_tlb != 0) { + int nb_tlb = env->nb_tlb; + if (env->id_tlbs != 0) + nb_tlb *= 2; + env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t)); + /* Pre-compute some useful values */ + env->tlb_per_way = env->nb_tlb / env->nb_ways; + } +#if !defined(CONFIG_USER_ONLY) + if (env->irq_inputs == NULL) { + fprintf(stderr, "WARNING: no internal IRQ controller registered.\n" + " Attempt Qemu to crash very soon !\n"); + } +#endif +} + +#if defined(PPC_DUMP_CPU) +static void dump_ppc_sprs (CPUPPCState *env) +{ + ppc_spr_t *spr; +#if !defined(CONFIG_USER_ONLY) + uint32_t sr, sw; +#endif + uint32_t ur, uw; + int i, j, n; + + printf("Special purpose registers:\n"); + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + n = (i << 5) | j; + spr = &env->spr_cb[n]; + uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS; + ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS; +#if !defined(CONFIG_USER_ONLY) + sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS; + sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS; + if (sw || sr || uw || ur) { + printf("SPR: %4d (%03x) %-8s s%c%c u%c%c\n", + (i << 5) | j, (i << 5) | j, spr->name, + sw ? 'w' : '-', sr ? 'r' : '-', + uw ? 'w' : '-', ur ? 'r' : '-'); + } +#else + if (uw || ur) { + printf("SPR: %4d (%03x) %-8s u%c%c\n", + (i << 5) | j, (i << 5) | j, spr->name, + uw ? 'w' : '-', ur ? 'r' : '-'); + } +#endif + } + } + fflush(stdout); + fflush(stderr); +} +#endif + +/*****************************************************************************/ +#include +#include + +int fflush (FILE *stream); + +/* Opcode types */ +enum { + PPC_DIRECT = 0, /* Opcode routine */ + PPC_INDIRECT = 1, /* Indirect opcode table */ +}; + +static inline int is_indirect_opcode (void *handler) +{ + return ((unsigned long)handler & 0x03) == PPC_INDIRECT; +} + +static inline opc_handler_t **ind_table(void *handler) +{ + return (opc_handler_t **)((unsigned long)handler & ~3); +} + +/* Instruction table creation */ +/* Opcodes tables creation */ +static void fill_new_table (opc_handler_t **table, int len) +{ + int i; + + for (i = 0; i < len; i++) + table[i] = &invalid_handler; +} + +static int create_new_table (opc_handler_t **table, unsigned char idx) +{ + opc_handler_t **tmp; + + tmp = malloc(0x20 * sizeof(opc_handler_t)); + if (tmp == NULL) + return -1; + fill_new_table(tmp, 0x20); + table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT); + + return 0; +} + +static int insert_in_table (opc_handler_t **table, unsigned char idx, + opc_handler_t *handler) +{ + if (table[idx] != &invalid_handler) + return -1; + table[idx] = handler; + + return 0; +} + +static int register_direct_insn (opc_handler_t **ppc_opcodes, + unsigned char idx, opc_handler_t *handler) +{ + if (insert_in_table(ppc_opcodes, idx, handler) < 0) { + printf("*** ERROR: opcode %02x already assigned in main " + "opcode table\n", idx); + return -1; + } + + return 0; +} + +static int register_ind_in_table (opc_handler_t **table, + unsigned char idx1, unsigned char idx2, + opc_handler_t *handler) +{ + if (table[idx1] == &invalid_handler) { + if (create_new_table(table, idx1) < 0) { + printf("*** ERROR: unable to create indirect table " + "idx=%02x\n", idx1); + return -1; + } + } else { + if (!is_indirect_opcode(table[idx1])) { + printf("*** ERROR: idx %02x already assigned to a direct " + "opcode\n", idx1); + return -1; + } } - { - .name = "POWER3", - .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_630, - .flags = PPC_FLAGS_630, - .msr_mask = xxx, + if (handler != NULL && + insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { + printf("*** ERROR: opcode %02x already assigned in " + "opcode table %02x\n", idx2, idx1); + return -1; } + + return 0; +} + +static int register_ind_insn (opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, + opc_handler_t *handler) +{ + int ret; + + ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler); + + return ret; +} + +static int register_dblind_insn (opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, + unsigned char idx3, opc_handler_t *handler) +{ + if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { + printf("*** ERROR: unable to join indirect table idx " + "[%02x-%02x]\n", idx1, idx2); + return -1; + } + if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, + handler) < 0) { + printf("*** ERROR: unable to insert opcode " + "[%02x-%02x-%02x]\n", idx1, idx2, idx3); + return -1; + } + + return 0; +} + +static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn) +{ + if (insn->opc2 != 0xFF) { + if (insn->opc3 != 0xFF) { + if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, + insn->opc3, &insn->handler) < 0) + return -1; + } else { + if (register_ind_insn(ppc_opcodes, insn->opc1, + insn->opc2, &insn->handler) < 0) + return -1; + } + } else { + if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) + return -1; + } + + return 0; +} + +static int test_opcode_table (opc_handler_t **table, int len) +{ + int i, count, tmp; + + for (i = 0, count = 0; i < len; i++) { + /* Consistency fixup */ + if (table[i] == NULL) + table[i] = &invalid_handler; + if (table[i] != &invalid_handler) { + if (is_indirect_opcode(table[i])) { + tmp = test_opcode_table(ind_table(table[i]), 0x20); + if (tmp == 0) { + free(table[i]); + table[i] = &invalid_handler; + } else { + count++; + } + } else { + count++; + } + } + } + + return count; +} + +static void fix_opcode_tables (opc_handler_t **ppc_opcodes) +{ + if (test_opcode_table(ppc_opcodes, 0x40) == 0) + printf("*** WARNING: no opcode defined !\n"); +} + +/*****************************************************************************/ +static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) +{ + opcode_t *opc, *start, *end; + + fill_new_table(env->opcodes, 0x40); + if (&opc_start < &opc_end) { + start = &opc_start; + end = &opc_end; + } else { + start = &opc_end; + end = &opc_start; + } + for (opc = start + 1; opc != end; opc++) { + if ((opc->handler.type & def->insns_flags) != 0) { + if (register_insn(env->opcodes, opc) < 0) { + printf("*** ERROR initializing PowerPC instruction " + "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + opc->opc3); + return -1; + } + } + } + fix_opcode_tables(env->opcodes); + fflush(stdout); + fflush(stderr); + + return 0; +} + +#if defined(PPC_DUMP_CPU) +static int dump_ppc_insns (CPUPPCState *env) +{ + opc_handler_t **table, *handler; + uint8_t opc1, opc2, opc3; + + printf("Instructions set:\n"); + /* opc1 is 6 bits long */ + for (opc1 = 0x00; opc1 < 0x40; opc1++) { + table = env->opcodes; + handler = table[opc1]; + if (is_indirect_opcode(handler)) { + /* opc2 is 5 bits long */ + for (opc2 = 0; opc2 < 0x20; opc2++) { + table = env->opcodes; + handler = env->opcodes[opc1]; + table = ind_table(handler); + handler = table[opc2]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + /* opc3 is 5 bits long */ + for (opc3 = 0; opc3 < 0x20; opc3++) { + handler = table[opc3]; + if (handler->handler != &gen_invalid) { + printf("INSN: %02x %02x %02x (%02d %04d) : %s\n", + opc1, opc2, opc3, opc1, (opc3 << 5) | opc2, + handler->oname); + } + } + } else { + if (handler->handler != &gen_invalid) { + printf("INSN: %02x %02x -- (%02d %04d) : %s\n", + opc1, opc2, opc1, opc2, handler->oname); + } + } + } + } else { + if (handler->handler != &gen_invalid) { + printf("INSN: %02x -- -- (%02d ----) : %s\n", + opc1, opc1, handler->oname); + } + } + } +} #endif -#if defined (TODO) - /* PowerPC 631 (Power 3+)*/ - { - .name = "631", - .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_631, - .flags = PPC_FLAGS_631, - .msr_mask = xxx, - }, - { - .name = "POWER3+", - .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_631, - .flags = PPC_FLAGS_631, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER4 */ - { - .name = "POWER4", - .pvr = CPU_PPC_POWER4, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_POWER4, - .flags = PPC_FLAGS_POWER4, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER4p */ - { - .name = "POWER4+", - .pvr = CPU_PPC_POWER4P, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_POWER4, - .flags = PPC_FLAGS_POWER4, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER5 */ - { - .name = "POWER5", - .pvr = CPU_PPC_POWER5, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_POWER5, - .flags = PPC_FLAGS_POWER5, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER5+ */ - { - .name = "POWER5+", - .pvr = CPU_PPC_POWER5P, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_POWER5, - .flags = PPC_FLAGS_POWER5, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* POWER6 */ - { - .name = "POWER6", - .pvr = CPU_PPC_POWER6, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_POWER6, - .flags = PPC_FLAGS_POWER6, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* PowerPC 970 */ - { - .name = "970", - .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_970, - .flags = PPC_FLAGS_970, - .msr_mask = 0x900000000204FF36ULL, - }, -#endif -#if defined (TODO) - /* PowerPC 970FX (G5) */ - { - .name = "970fx", - .pvr = CPU_PPC_970FX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_970FX, - .flags = PPC_FLAGS_970FX, - .msr_mask = 0x800000000204FF36ULL, - }, -#endif -#if defined (TODO) - /* PowerPC 970MP */ - { - .name = "970MP", - .pvr = CPU_PPC_970MP, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_970, - .flags = PPC_FLAGS_970, - .msr_mask = 0x900000000204FF36ULL, - }, -#endif -#if defined (TODO) - /* PowerPC Cell */ - { - .name = "Cell", - .pvr = CPU_PPC_CELL, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_970, - .flags = PPC_FLAGS_970, - .msr_mask = 0x900000000204FF36ULL, - }, -#endif -#if defined (TODO) - /* RS64 (Apache/A35) */ - /* This one seems to support the whole POWER2 instruction set - * and the PowerPC 64 one. - */ - { - .name = "RS64", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "Apache", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "A35", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* RS64-II (NorthStar/A50) */ - { - .name = "RS64-II", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "NortStar", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "A50", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* RS64-III (Pulsar) */ - { - .name = "RS64-III", - .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "Pulsar", - .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, -#endif -#if defined (TODO) - /* RS64-IV (IceStar/IStar/SStar) */ - { - .name = "RS64-IV", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "IceStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "IStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "SStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, -#endif - /* POWER */ -#if defined (TODO) - /* Original POWER */ - { - .name = "POWER", - .pvr = CPU_POWER, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_POWER, - .flags = PPC_FLAGS_POWER, - .msr_mask = xxx, - }, -#endif -#endif /* defined (TARGET_PPC64) */ -#if defined (TODO) - /* POWER2 */ - { - .name = "POWER2", - .pvr = CPU_POWER2, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_POWER, - .flags = PPC_FLAGS_POWER, - .msr_mask = xxx, - }, -#endif - /* Generic PowerPCs */ -#if defined (TODO) + +int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) +{ + env->msr_mask = def->msr_mask; + env->mmu_model = def->mmu_model; + env->excp_model = def->excp_model; + env->bus_model = def->bus_model; + if (create_ppc_opcodes(env, def) < 0) + return -1; + init_ppc_proc(env, def); +#if defined(PPC_DUMP_CPU) { - .name = "ppc64", - .pvr = CPU_PPC_970FX, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_PPC64, - .flags = PPC_FLAGS_PPC64, - .msr_mask = 0xA00000000204FF36ULL, - }, + const unsigned char *mmu_model, *excp_model, *bus_model; + switch (env->mmu_model) { + case POWERPC_MMU_32B: + mmu_model = "PowerPC 32"; + break; + case POWERPC_MMU_64B: + mmu_model = "PowerPC 64"; + break; + case POWERPC_MMU_601: + mmu_model = "PowerPC 601"; + break; + case POWERPC_MMU_SOFT_6xx: + mmu_model = "PowerPC 6xx/7xx with software driven TLBs"; + break; + case POWERPC_MMU_SOFT_74xx: + mmu_model = "PowerPC 74xx with software driven TLBs"; + break; + case POWERPC_MMU_SOFT_4xx: + mmu_model = "PowerPC 4xx with software driven TLBs"; + break; + case POWERPC_MMU_SOFT_4xx_Z: + mmu_model = "PowerPC 4xx with software driven TLBs " + "and zones protections"; + break; + case POWERPC_MMU_REAL_4xx: + mmu_model = "PowerPC 4xx real mode only"; + break; + case POWERPC_MMU_BOOKE: + mmu_model = "PowerPC BookE"; + break; + case POWERPC_MMU_BOOKE_FSL: + mmu_model = "PowerPC BookE FSL"; + break; + case POWERPC_MMU_64BRIDGE: + mmu_model = "PowerPC 64 bridge"; + break; + default: + mmu_model = "Unknown or invalid"; + break; + } + switch (env->excp_model) { + case POWERPC_EXCP_STD: + excp_model = "PowerPC"; + break; + case POWERPC_EXCP_40x: + excp_model = "PowerPC 40x"; + break; + case POWERPC_EXCP_601: + excp_model = "PowerPC 601"; + break; + case POWERPC_EXCP_602: + excp_model = "PowerPC 602"; + break; + case POWERPC_EXCP_603: + excp_model = "PowerPC 603"; + break; + case POWERPC_EXCP_603E: + excp_model = "PowerPC 603e"; + break; + case POWERPC_EXCP_604: + excp_model = "PowerPC 604"; + break; + case POWERPC_EXCP_7x0: + excp_model = "PowerPC 740/750"; + break; + case POWERPC_EXCP_7x5: + excp_model = "PowerPC 745/755"; + break; + case POWERPC_EXCP_74xx: + excp_model = "PowerPC 74xx"; + break; + case POWERPC_EXCP_970: + excp_model = "PowerPC 970"; + break; + case POWERPC_EXCP_BOOKE: + excp_model = "PowerPC BookE"; + break; + default: + excp_model = "Unknown or invalid"; + break; + } + switch (env->bus_model) { + case PPC_FLAGS_INPUT_6xx: + bus_model = "PowerPC 6xx"; + break; + case PPC_FLAGS_INPUT_BookE: + bus_model = "PowerPC BookE"; + break; + case PPC_FLAGS_INPUT_405: + bus_model = "PowerPC 405"; + break; + case PPC_FLAGS_INPUT_970: + bus_model = "PowerPC 970"; + break; + case PPC_FLAGS_INPUT_401: + bus_model = "PowerPC 401/403"; + break; + default: + bus_model = "Unknown or invalid"; + break; + } + printf("PowerPC %-12s : PVR %08x MSR %016" PRIx64 "\n" + " MMU model : %s\n", + def->name, def->pvr, def->msr_mask, mmu_model); + if (env->tlb != NULL) { + printf(" %d %s TLB in %d ways\n", + env->nb_tlb, env->id_tlbs ? "splitted" : "merged", + env->nb_ways); + } + printf(" Exceptions model : %s\n" + " Bus model : %s\n", + excp_model, bus_model); + } + dump_ppc_insns(env); + dump_ppc_sprs(env); + fflush(stdout); #endif - { - .name = "ppc32", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_PPC32, - .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77ULL, - }, - /* Fallback */ - { - .name = "ppc", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFFFFFF, - .insns_flags = PPC_INSNS_PPC32, - .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77ULL, - }, -}; + + return 0; +} int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) { @@ -4374,9 +5525,8 @@ void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) int i; for (i = 0; ; i++) { - (*cpu_fprintf)(f, "PowerPC %16s PVR %08x mask %08x\n", - ppc_defs[i].name, - ppc_defs[i].pvr, ppc_defs[i].pvr_mask); + (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", + ppc_defs[i].name, ppc_defs[i].pvr); if (strcmp(ppc_defs[i].name, "ppc") == 0) break; } -- cgit v1.2.3 From b8d3f5d1264260db42e1d64c9d7c537df0aa31ce Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 26 Sep 2007 23:55:31 +0000 Subject: Add flags to support PowerPC 405 bootinfos variations. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3245 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405.h | 3 ++- hw/ppc405_boards.c | 2 +- hw/ppc405_uc.c | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/ppc405.h b/hw/ppc405.h index b3f3b3d80..eacbefedd 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -57,7 +57,8 @@ struct ppc4xx_bd_info_t { CPUState *ppc405_init (const unsigned char *cpu_model, clk_setup_t *cpu_clk, clk_setup_t *tb_clk, uint32_t sysclk); -ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd); +ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, + uint32_t flags); /* */ typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 69655d84c..8f82ea9e1 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -288,7 +288,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, bd.bi_plb_busfreq = 33333333; bd.bi_pci_busfreq = 33333333; bd.bi_opbfreq = 33333333; - bdloc = ppc405_set_bootinfo(env, &bd); + bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001); env->gpr[3] = bdloc; kernel_base = KERNEL_LOAD_ADDR; /* now we can load the kernel */ diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index e3cbb09a2..aa5963aee 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -69,7 +69,8 @@ CPUState *ppc405_init (const unsigned char *cpu_model, return env; } -ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd) +ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, + uint32_t flags) { ram_addr_t bdloc; int i, n; @@ -103,7 +104,7 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd) for (i = 0; i < 6; i++) stb_raw(phys_ram_base + bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]); n = 0x6A; - if (env->spr[SPR_PVR] == CPU_PPC_405EP) { + if (flags & 0x00000001) { for (i = 0; i < 6; i++) stb_raw(phys_ram_base + bdloc + n++, bd->bi_pci_enetaddr2[i]); } -- cgit v1.2.3 From 92a343da3f50db3130f988b14650eb09e9748d11 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 27 Sep 2007 01:14:15 +0000 Subject: New ppc64-linux-user target. Allow use of PowerPC 970 for debugging (softmmu would not run, for now). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3246 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- linux-user/elfload.c | 1 + linux-user/ppc64/syscall.h | 20 ++++++++++---------- linux-user/qemu.h | 1 + target-ppc/translate_init.c | 28 ---------------------------- 5 files changed, 13 insertions(+), 39 deletions(-) diff --git a/configure b/configure index 6288ac06c..46a24171e 100755 --- a/configure +++ b/configure @@ -501,7 +501,7 @@ if test -z "$target_list" ; then fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user ppc64-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then diff --git a/linux-user/elfload.c b/linux-user/elfload.c index b87119e93..2a4333812 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1315,6 +1315,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1), info); + info->load_addr = reloc_func_desc; info->start_brk = info->brk = elf_brk; info->end_code = end_code; info->start_code = start_code; diff --git a/linux-user/ppc64/syscall.h b/linux-user/ppc64/syscall.h index 692061641..c47e58a95 100644 --- a/linux-user/ppc64/syscall.h +++ b/linux-user/ppc64/syscall.h @@ -65,18 +65,21 @@ struct target_revectored_struct { #define TARGET_SHMGET 23 #define TARGET_SHMCTL 24 +#if 0 // To make it compile, even if the definition in syscall.c is bugged struct target_msgbuf { int mtype; char mtext[1]; }; +#endif struct target_ipc_kludge { unsigned int msgp; /* Really (struct msgbuf *) */ int msgtyp; }; +#if 0 // To make it compile, even if the definition in syscall.c is bugged struct target_ipc_perm { - int key; + int __key; unsigned short uid; unsigned short gid; unsigned short cuid; @@ -84,7 +87,9 @@ struct target_ipc_perm { unsigned short mode; unsigned short seq; }; +#endif +#if 0 // To make it compile, even if the definition in syscall.c is bugged struct target_msqid_ds { struct target_ipc_perm msg_perm; unsigned int msg_first; /* really struct target_msg* */ @@ -100,7 +105,9 @@ struct target_msqid_ds { unsigned short msg_lspid; unsigned short msg_lrpid; }; +#endif +#if 0 // To make it compile, even if the definition in syscall.c is bugged struct target_shmid_ds { struct target_ipc_perm shm_perm; int shm_segsz; @@ -114,17 +121,10 @@ struct target_shmid_ds { unsigned long *shm_pages; void *attaches; /* really struct shm_desc * */ }; +#endif #define TARGET_IPC_RMID 0 #define TARGET_IPC_SET 1 #define TARGET_IPC_STAT 2 -union target_semun { - int val; - unsigned int buf; /* really struct semid_ds * */ - unsigned int array; /* really unsigned short * */ - unsigned int __buf; /* really struct seminfo * */ - unsigned int __pad; /* really void* */ -}; - -#define UNAME_MACHINE "ppc" +#define UNAME_MACHINE "ppc64" diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 8c03ad190..4b857f3d1 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -16,6 +16,7 @@ * task_struct fields in the kernel */ struct image_info { + target_ulong load_addr; unsigned long start_code; unsigned long end_code; unsigned long start_data; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index c6f09aea5..df6affa31 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3368,7 +3368,6 @@ static void init_proc_7455 (CPUPPCState *env) #if defined (TARGET_PPC64) /* PowerPC 970 */ -#if defined (TODO) #define POWERPC_INSNS_970 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ PPC_64_BRIDGE | PPC_SLBI) @@ -3408,10 +3407,8 @@ static void init_proc_970 (CPUPPCState *env) /* Allocate hardware IRQ controller */ ppc970_irq_init(env); } -#endif /* TODO */ /* PowerPC 970FX (aka G5) */ -#if defined (TODO) #define POWERPC_INSNS_970FX (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ PPC_64_BRIDGE | PPC_SLBI) @@ -3451,10 +3448,8 @@ static void init_proc_970FX (CPUPPCState *env) /* Allocate hardware IRQ controller */ ppc970_irq_init(env); } -#endif /* TODO */ /* PowerPC 970 GX */ -#if defined (TODO) #define POWERPC_INSNS_970GX (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ PPC_64_BRIDGE | PPC_SLBI) @@ -3494,7 +3489,6 @@ static void init_proc_970GX (CPUPPCState *env) /* Allocate hardware IRQ controller */ ppc970_irq_init(env); } -#endif /* TODO */ /* PowerPC 620 */ #if defined (TODO) @@ -4897,50 +4891,28 @@ static ppc_def_t ppc_defs[] = { /* POWER6A */ POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, 0xFFFFFFFF, POWER6), #endif -#if defined (TODO) /* PowerPC 970 */ POWERPC_DEF("970", CPU_POWERPC_970, 0xFFFFFFFF, 970), -#endif -#if defined (TODO) /* PowerPC 970FX (G5) */ POWERPC_DEF("970fx", CPU_POWERPC_970FX, 0xFFFFFFFF, 970FX), -#endif -#if defined (TODO) /* PowerPC 970FX v1.0 (G5) */ POWERPC_DEF("970fx1.0", CPU_POWERPC_970FX_v10, 0xFFFFFFFF, 970FX), -#endif -#if defined (TODO) /* PowerPC 970FX v2.0 (G5) */ POWERPC_DEF("970fx2.0", CPU_POWERPC_970FX_v20, 0xFFFFFFFF, 970FX), -#endif -#if defined (TODO) /* PowerPC 970FX v2.1 (G5) */ POWERPC_DEF("970fx2.1", CPU_POWERPC_970FX_v21, 0xFFFFFFFF, 970FX), -#endif -#if defined (TODO) /* PowerPC 970FX v3.0 (G5) */ POWERPC_DEF("970fx3.0", CPU_POWERPC_970FX_v30, 0xFFFFFFFF, 970FX), -#endif -#if defined (TODO) /* PowerPC 970FX v3.1 (G5) */ POWERPC_DEF("970fx3.1", CPU_POWERPC_970FX_v31, 0xFFFFFFFF, 970FX), -#endif -#if defined (TODO) /* PowerPC 970GX (G5) */ POWERPC_DEF("970gx", CPU_POWERPC_970GX, 0xFFFFFFFF, 970GX), -#endif -#if defined (TODO) /* PowerPC 970MP */ POWERPC_DEF("970mp", CPU_POWERPC_970MP, 0xFFFFFFFF, 970), -#endif -#if defined (TODO) /* PowerPC 970MP v1.0 */ POWERPC_DEF("970mp1.0", CPU_POWERPC_970MP_v10, 0xFFFFFFFF, 970), -#endif -#if defined (TODO) /* PowerPC 970MP v1.1 */ POWERPC_DEF("970mp1.1", CPU_POWERPC_970MP_v11, 0xFFFFFFFF, 970), -#endif #if defined (TODO) /* PowerPC Cell */ POWERPC_DEF("Cell", CPU_POWERPC_CELL, 0xFFFFFFFF, 970), -- cgit v1.2.3 From 40d0591e2c4922f545ebf1c9a3bd89e73e8428b4 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 27 Sep 2007 01:32:19 +0000 Subject: Fixes for PowerPC 64 rotate and mask instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3247 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 15 +++++++++++++++ target-ppc/translate.c | 30 +++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 93c463e30..976eb5304 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1353,6 +1353,21 @@ void OPPROTO op_andi_T1 (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_andi_T0_64 (void) +{ + T0 &= ((uint64_t)PARAM1 << 32) | PARAM2; + RETURN(); +} + +void OPPROTO op_andi_T1_64 (void) +{ + T1 &= ((uint64_t)PARAM1 << 32) | PARAM2; + RETURN(); +} +#endif + + /* count leading zero */ void OPPROTO op_cntlzw (void) { diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4d98ea90b..50c01cace 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1339,6 +1339,22 @@ GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B) \ gen_##name(ctx, 1, 1); \ } +static inline void gen_andi_T0_64 (DisasContext *ctx, uint64_t mask) +{ + if (mask >> 32) + gen_op_andi_T0_64(mask >> 32, mask & 0xFFFFFFFF); + else + gen_op_andi_T0(mask); +} + +static inline void gen_andi_T1_64 (DisasContext *ctx, uint64_t mask) +{ + if (mask >> 32) + gen_op_andi_T1_64(mask >> 32, mask & 0xFFFFFFFF); + else + gen_op_andi_T1(mask); +} + static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me, uint32_t sh) { @@ -1348,7 +1364,7 @@ static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me, } if (likely(mb == 0)) { if (likely(me == 63)) { - gen_op_rotli32_T0(sh); + gen_op_rotli64_T0(sh); goto do_store; } else if (likely(me == (63 - sh))) { gen_op_sli_T0(sh); @@ -1356,13 +1372,13 @@ static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me, } } else if (likely(me == 63)) { if (likely(sh == (64 - mb))) { - gen_op_srli_T0(mb); + gen_op_srli_T0_64(mb); goto do_store; } } gen_op_rotli64_T0(sh); do_mask: - gen_op_andi_T0(MASK(mb, me)); + gen_andi_T0_64(ctx, MASK(mb, me)); do_store: gen_op_store_T0_gpr(rA(ctx->opcode)); if (unlikely(Rc(ctx->opcode) != 0)) @@ -1405,7 +1421,7 @@ static inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me) gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_rotl64_T0_T1(); if (unlikely(mb != 0 || me != 63)) { - gen_op_andi_T0(MASK(mb, me)); + gen_andi_T0_64(ctx, MASK(mb, me)); } gen_op_store_T0_gpr(rA(ctx->opcode)); if (unlikely(Rc(ctx->opcode) != 0)) @@ -1452,11 +1468,11 @@ static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rA(ctx->opcode)); - gen_op_rotli64_T0(SH(ctx->opcode)); + gen_op_rotli64_T0(sh); do_mask: mask = MASK(mb, 63 - sh); - gen_op_andi_T0(mask); - gen_op_andi_T1(~mask); + gen_andi_T0_64(ctx, mask); + gen_andi_T1_64(ctx, ~mask); gen_op_or(); do_store: gen_op_store_T0_gpr(rA(ctx->opcode)); -- cgit v1.2.3 From 526216880d5c4cb2507bdb22d6a5d33016f38104 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 27 Sep 2007 01:52:00 +0000 Subject: SVM VINTR fix, by Alexander Graf. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3248 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 7 ++++--- target-i386/helper.c | 10 +++++++++- target-i386/translate.c | 2 -- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 8d9152040..55758faef 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -409,7 +409,7 @@ int cpu_exec(CPUState *env1) !(env->hflags & HF_INHIBIT_IRQ_MASK)) { int intno; svm_check_intercept(SVM_EXIT_INTR); - env->interrupt_request &= ~CPU_INTERRUPT_HARD; + env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); intno = cpu_get_pic_interrupt(env); if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); @@ -428,12 +428,13 @@ int cpu_exec(CPUState *env1) int intno; /* FIXME: this should respect TPR */ env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), - ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); + svm_check_intercept(SVM_EXIT_VINTR); intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); if (loglevel & CPU_LOG_TB_IN_ASM) fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno); do_interrupt(intno, 0, 0, -1, 1); + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), + ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); #if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else diff --git a/target-i386/helper.c b/target-i386/helper.c index 40dc41f3a..91fd6a96c 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -4120,8 +4120,9 @@ void helper_vmrun(target_ulong addr) if (loglevel & CPU_LOG_TB_IN_ASM) fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code); } - if (int_ctl & V_IRQ_MASK) + if ((int_ctl & V_IRQ_MASK) || (env->intercept & INTERCEPT_VINTR)) { env->interrupt_request |= CPU_INTERRUPT_VIRQ; + } cpu_loop_exit(); } @@ -4283,6 +4284,13 @@ void vmexit(uint64_t exit_code, uint64_t exit_info_1) ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), EIP); + if(env->hflags & HF_INHIBIT_IRQ_MASK) { + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK); + env->hflags &= ~HF_INHIBIT_IRQ_MASK; + } else { + stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); + } + /* Save the VM state in the vmcb */ SVM_SAVE_SEG(env->vm_vmcb, segs[R_ES], es); SVM_SAVE_SEG(env->vm_vmcb, segs[R_CS], cs); diff --git a/target-i386/translate.c b/target-i386/translate.c index d62d563bd..cd9541265 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5551,8 +5551,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_set_inhibit_irq(); /* give a chance to handle pending irqs */ gen_jmp_im(s->pc - s->cs_base); - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VINTR)) - break; gen_eob(s); } else { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); -- cgit v1.2.3 From 4118a97030aa9bd1d520d1d06bbe0655d829df04 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 27 Sep 2007 04:10:43 +0000 Subject: memset string pages to zero to avoid putting random data on the stack that may make some program crash at startup. Fix unsigned long / target_ulong confusion (more to do). Fix missing g2h macros. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3249 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 3 ++- linux-user/mmap.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 2a4333812..22e3283ae 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -517,7 +517,7 @@ static void bswap_sym(struct elf_sym *sym) * */ static unsigned long copy_elf_strings(int argc,char ** argv, void **page, - unsigned long p) + target_ulong p) { char *tmp, *tmp1, *pag = NULL; int len, offset = 0; @@ -544,6 +544,7 @@ static unsigned long copy_elf_strings(int argc,char ** argv, void **page, pag = (char *)page[p/TARGET_PAGE_SIZE]; if (!pag) { pag = (char *)malloc(TARGET_PAGE_SIZE); + memset(pag, 0, TARGET_PAGE_SIZE); page[p/TARGET_PAGE_SIZE] = pag; if (!pag) return 0; diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 28954f13f..29f1d9625 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -224,9 +224,9 @@ abort(); start = HOST_PAGE_ALIGN(real_start); end = start + HOST_PAGE_ALIGN(len); if (start > real_start) - munmap((void *)real_start, start - real_start); + munmap((void *)g2h(real_start), start - real_start); if (end < real_end) - munmap((void *)end, real_end - end); + munmap((void *)g2h(end), real_end - end); /* use it as a fixed mapping */ flags |= MAP_FIXED; } else { @@ -370,7 +370,7 @@ int target_munmap(target_ulong start, target_ulong len) /* unmap what we can */ if (real_start < real_end) { - ret = munmap((void *)real_start, real_end - real_start); + ret = munmap(g2h(real_start), real_end - real_start); if (ret != 0) return ret; } -- cgit v1.2.3 From e3878283def049b072ae47b8ee123ef6618ca2fc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 27 Sep 2007 04:47:25 +0000 Subject: Implement size bit in PowerPC 64 comparisons. Allow 'weight' field in sync instruction. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3250 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 50c01cace..d370b3ed8 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -969,7 +969,7 @@ GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ - if (ctx->sf_mode) \ + if (ctx->sf_mode && (ctx->opcode & 0x00200000)) \ gen_op_##name##_64(); \ else \ gen_op_##name(); \ @@ -993,7 +993,7 @@ GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) { gen_op_load_gpr_T0(rA(ctx->opcode)); #if defined(TARGET_PPC64) - if (ctx->sf_mode) + if (ctx->sf_mode && (ctx->opcode & 0x00200000)) gen_op_cmpi_64(SIMM(ctx->opcode)); else #endif @@ -1007,7 +1007,7 @@ GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) { gen_op_load_gpr_T0(rA(ctx->opcode)); #if defined(TARGET_PPC64) - if (ctx->sf_mode) + if (ctx->sf_mode && (ctx->opcode & 0x00200000)) gen_op_cmpli_64(UIMM(ctx->opcode)); else #endif @@ -2565,7 +2565,7 @@ GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B) #endif /* defined(TARGET_PPC64) */ /* sync */ -GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC) +GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03CF0801, PPC_MEM_SYNC) { } -- cgit v1.2.3 From e3b9808535376bff99343c8a61726059a965198e Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 27 Sep 2007 12:48:11 +0000 Subject: Build fix for PowerPC hosts, where "PPC" is a predefined macro name. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3251 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index df6affa31..cc8333f92 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3539,21 +3539,21 @@ static void init_proc_620 (CPUPPCState *env) /* Default PowerPC target will be PowerPC 32 */ #if defined (TARGET_PPC64) && 0 // XXX: TODO -#define CPU_POWERPC_PPC CPU_POWERPC_PPC64 -#define POWERPC_INSNS_PPC POWERPC_INSNS_PPC64 -#define POWERPC_MSRM_PPC POWERPC_MSRM_PPC64 -#define POWERPC_MMU_PPC POWERPC_MMU_PPC64 -#define POWERPC_EXCP_PPC POWERPC_EXCP_PPC64 -#define POWERPC_INPUT_PPC POWERPC_INPUT_PPC64 -#define init_proc_PPC init_proc_PPC64 +#define CPU_POWERPC_PPC CPU_POWERPC_PPC64 +#define POWERPC_INSNS_PPC_GENERIC POWERPC_INSNS_PPC64 +#define POWERPC_MSRM_PPC_GENERIC POWERPC_MSRM_PPC64 +#define POWERPC_MMU_PPC_GENERIC POWERPC_MMU_PPC64 +#define POWERPC_EXCP_PPC_GENERIC POWERPC_EXCP_PPC64 +#define POWERPC_INPUT_PPC_GENERIC POWERPC_INPUT_PPC64 +#define init_proc_PPC_GENERIC init_proc_PPC64 #else -#define CPU_POWERPC_PPC CPU_POWERPC_PPC32 -#define POWERPC_INSNS_PPC POWERPC_INSNS_PPC32 -#define POWERPC_MSRM_PPC POWERPC_MSRM_PPC32 -#define POWERPC_MMU_PPC POWERPC_MMU_PPC32 -#define POWERPC_EXCP_PPC POWERPC_EXCP_PPC32 -#define POWERPC_INPUT_PPC POWERPC_INPUT_PPC32 -#define init_proc_PPC init_proc_PPC32 +#define CPU_POWERPC_PPC CPU_POWERPC_PPC32 +#define POWERPC_INSNS_PPC_GENERIC POWERPC_INSNS_PPC32 +#define POWERPC_MSRM_PPC_GENERIC POWERPC_MSRM_PPC32 +#define POWERPC_MMU_PPC_GENERIC POWERPC_MMU_PPC32 +#define POWERPC_EXCP_PPC_GENERIC POWERPC_EXCP_PPC32 +#define POWERPC_INPUT_PPC_GENERIC POWERPC_INPUT_PPC32 +#define init_proc_PPC_GENERIC init_proc_PPC32 #endif /*****************************************************************************/ @@ -4994,7 +4994,7 @@ static ppc_def_t ppc_defs[] = { #endif POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, 0xFFFFFFFF, PPC32), /* Fallback */ - POWERPC_DEF("ppc", CPU_POWERPC_PPC, 0xFFFFFFFF, PPC), + POWERPC_DEF("ppc", CPU_POWERPC_PPC, 0xFFFFFFFF, PPC_GENERIC), }; /*****************************************************************************/ -- cgit v1.2.3 From a04e134ad1f4271bea2c7b7649b21e35ded91005 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 27 Sep 2007 13:57:58 +0000 Subject: linux-user sigaltstack() syscall, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3252 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/alpha/target_signal.h | 24 ++++++ linux-user/arm/target_signal.h | 24 ++++++ linux-user/i386/target_signal.h | 24 ++++++ linux-user/m68k/target_signal.h | 24 ++++++ linux-user/mips/target_signal.h | 24 ++++++ linux-user/ppc/target_signal.h | 24 ++++++ linux-user/ppc64/target_signal.h | 24 ++++++ linux-user/qemu.h | 4 + linux-user/sh4/target_signal.h | 24 ++++++ linux-user/signal.c | 156 +++++++++++++++++++++++++++---------- linux-user/sparc/target_signal.h | 24 ++++++ linux-user/sparc64/target_signal.h | 24 ++++++ linux-user/syscall.c | 7 ++ linux-user/x86_64/target_signal.h | 24 ++++++ target-alpha/cpu.h | 5 ++ target-arm/cpu.h | 5 ++ target-i386/cpu.h | 5 ++ target-mips/cpu.h | 5 ++ target-ppc/cpu.h | 5 ++ target-sparc/cpu.h | 12 +++ 20 files changed, 425 insertions(+), 43 deletions(-) create mode 100644 linux-user/alpha/target_signal.h create mode 100644 linux-user/arm/target_signal.h create mode 100644 linux-user/i386/target_signal.h create mode 100644 linux-user/m68k/target_signal.h create mode 100644 linux-user/mips/target_signal.h create mode 100644 linux-user/ppc/target_signal.h create mode 100644 linux-user/ppc64/target_signal.h create mode 100644 linux-user/sh4/target_signal.h create mode 100644 linux-user/sparc/target_signal.h create mode 100644 linux-user/sparc64/target_signal.h create mode 100644 linux-user/x86_64/target_signal.h diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h new file mode 100644 index 000000000..bf54ac71d --- /dev/null +++ b/linux-user/alpha/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_SIGSTKSZ 16384 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/arm/target_signal.h b/linux-user/arm/target_signal.h new file mode 100644 index 000000000..eb4a0bb12 --- /dev/null +++ b/linux-user/arm/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/i386/target_signal.h b/linux-user/i386/target_signal.h new file mode 100644 index 000000000..eb4a0bb12 --- /dev/null +++ b/linux-user/i386/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/m68k/target_signal.h b/linux-user/m68k/target_signal.h new file mode 100644 index 000000000..b48119507 --- /dev/null +++ b/linux-user/m68k/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h new file mode 100644 index 000000000..c94788497 --- /dev/null +++ b/linux-user/mips/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_ulong ss_size; + target_long ss_flags; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/ppc/target_signal.h b/linux-user/ppc/target_signal.h new file mode 100644 index 000000000..e210e7a31 --- /dev/null +++ b/linux-user/ppc/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/ppc64/target_signal.h b/linux-user/ppc64/target_signal.h new file mode 100644 index 000000000..e210e7a31 --- /dev/null +++ b/linux-user/ppc64/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 4b857f3d1..78e9ab34f 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -9,6 +9,7 @@ #include "cpu.h" #include "syscall.h" +#include "target_signal.h" #include "gdbstub.h" /* This struct is used to hold certain information about the image. @@ -149,6 +150,9 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); long do_sigreturn(CPUState *env); long do_rt_sigreturn(CPUState *env); +int do_sigaltstack(const struct target_sigaltstack *uss, + struct target_sigaltstack *uoss, + target_ulong sp); #ifdef TARGET_I386 /* vm86.c */ diff --git a/linux-user/sh4/target_signal.h b/linux-user/sh4/target_signal.h new file mode 100644 index 000000000..e210e7a31 --- /dev/null +++ b/linux-user/sh4/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/signal.c b/linux-user/signal.c index 97f10957d..945dd14e0 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -26,6 +26,7 @@ #include #include +#include "target_signal.h" #include "qemu.h" //#define DEBUG_SIGNAL @@ -45,6 +46,12 @@ struct emulated_sigaction { first signal, we put it here */ }; +struct target_sigaltstack target_sigaltstack_used = { + .ss_sp = 0, + .ss_size = 0, + .ss_flags = TARGET_SS_DISABLE, +}; + static struct emulated_sigaction sigact_table[TARGET_NSIG]; static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ static struct sigqueue *first_free; /* first free siginfo queue entry */ @@ -92,6 +99,18 @@ static uint8_t host_to_target_signal_table[65] = { }; static uint8_t target_to_host_signal_table[65]; +static inline int on_sig_stack(unsigned long sp) +{ + return (sp - target_sigaltstack_used.ss_sp + < target_sigaltstack_used.ss_size); +} + +static inline int sas_ss_flags(unsigned long sp) +{ + return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE + : on_sig_stack(sp) ? SS_ONSTACK : 0); +} + static inline int host_to_target_signal(int sig) { return host_to_target_signal_table[sig]; @@ -419,6 +438,67 @@ static void host_signal_handler(int host_signum, siginfo_t *info, } } +int do_sigaltstack(const struct target_sigaltstack *uss, + struct target_sigaltstack *uoss, + target_ulong sp) +{ + int ret; + struct target_sigaltstack oss; + + /* XXX: test errors */ + if(uoss) + { + __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp); + __put_user(target_sigaltstack_used.ss_size, &oss.ss_size); + __put_user(sas_ss_flags(sp), &oss.ss_flags); + } + + if(uss) + { + struct target_sigaltstack ss; + + ret = -EFAULT; + if (!access_ok(VERIFY_READ, uss, sizeof(*uss)) + || __get_user(ss.ss_sp, &uss->ss_sp) + || __get_user(ss.ss_size, &uss->ss_size) + || __get_user(ss.ss_flags, &uss->ss_flags)) + goto out; + + ret = -EPERM; + if (on_sig_stack(sp)) + goto out; + + ret = -EINVAL; + if (ss.ss_flags != TARGET_SS_DISABLE + && ss.ss_flags != TARGET_SS_ONSTACK + && ss.ss_flags != 0) + goto out; + + if (ss.ss_flags == TARGET_SS_DISABLE) { + ss.ss_size = 0; + ss.ss_sp = 0; + } else { + ret = -ENOMEM; + if (ss.ss_size < MINSIGSTKSZ) + goto out; + } + + target_sigaltstack_used.ss_sp = ss.ss_sp; + target_sigaltstack_used.ss_size = ss.ss_size; + } + + if (uoss) { + ret = -EFAULT; + if (!access_ok(VERIFY_WRITE, uoss, sizeof(oss))) + goto out; + memcpy(uoss, &oss, sizeof(oss)); + } + + ret = 0; +out: + return ret; +} + int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact) { @@ -551,12 +631,6 @@ struct target_sigcontext { target_ulong cr2; }; -typedef struct target_sigaltstack { - target_ulong ss_sp; - int ss_flags; - target_ulong ss_size; -} target_stack_t; - struct target_ucontext { target_ulong tuc_flags; target_ulong tuc_link; @@ -640,16 +714,14 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) /* Default to using normal stack */ esp = env->regs[R_ESP]; -#if 0 /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & SA_ONSTACK) { - if (sas_ss_flags(esp) == 0) - esp = current->sas_ss_sp + current->sas_ss_size; - } + if (ka->sa.sa_flags & TARGET_SA_ONSTACK) { + if (sas_ss_flags(esp) == 0) + esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } /* This is the legacy signal stack switching. */ else -#endif if ((env->segs[R_SS].selector & 0xffff) != __USER_DS && !(ka->sa.sa_flags & TARGET_SA_RESTORER) && ka->sa.sa_restorer) { @@ -750,11 +822,11 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, /* Create the ucontext. */ err |= __put_user(0, &frame->uc.tuc_flags); err |= __put_user(0, &frame->uc.tuc_link); - err |= __put_user(/*current->sas_ss_sp*/ 0, + err |= __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp); - err |= __put_user(/* sas_ss_flags(regs->esp) */ 0, + err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &frame->uc.tuc_stack.ss_flags); - err |= __put_user(/* current->sas_ss_size */ 0, + err |= __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env, set->sig[0]); @@ -880,7 +952,6 @@ long do_rt_sigreturn(CPUX86State *env) { struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env->regs[R_ESP] - 4); sigset_t set; - // stack_t st; int eax; #if 0 @@ -893,13 +964,9 @@ long do_rt_sigreturn(CPUX86State *env) if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) goto badframe; -#if 0 - if (__copy_from_user(&st, &frame->uc.tuc_stack, sizeof(st))) + if (do_sigaltstack(&frame->uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->esp); -#endif + return eax; badframe: @@ -933,12 +1000,6 @@ struct target_sigcontext { target_ulong fault_address; }; -typedef struct target_sigaltstack { - target_ulong ss_sp; - int ss_flags; - target_ulong ss_size; -} target_stack_t; - struct target_ucontext { target_ulong tuc_flags; target_ulong tuc_link; @@ -1031,13 +1092,11 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) { unsigned long sp = regs->regs[13]; -#if 0 /* * This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) - sp = current->sas_ss_sp + current->sas_ss_size; -#endif + if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; /* * ATPCS B01 mandates 8-byte alignment */ @@ -1074,8 +1133,8 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, else cpsr &= ~T_BIT; } -#endif -#endif +#endif /* CONFIG_ARM_THUMB */ +#endif /* 0 */ #endif /* TARGET_CONFIG_CPU_32 */ if (ka->sa.sa_flags & TARGET_SA_RESTORER) { @@ -1132,6 +1191,7 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, target_sigset_t *set, CPUState *env) { struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame)); + struct target_sigaltstack stack; int i, err = 0; if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) @@ -1144,6 +1204,15 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, /* Clear all the bits of the ucontext we don't use. */ memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext)); + memset(&stack, 0, sizeof(stack)); + __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); + __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); + __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); + if (!access_ok(VERIFY_WRITE, &frame->uc.tuc_stack, sizeof(stack))) + err = 1; + else + memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); + err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ env, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { @@ -1270,6 +1339,9 @@ long do_rt_sigreturn(CPUState *env) if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) goto badframe; + if (do_sigaltstack(&frame->uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT) + goto badframe; + #if 0 /* Send SIGTRAP if we're single-stepping */ if (ptrace_cancel_bpt(current)) @@ -1382,14 +1454,13 @@ static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, u unsigned long sp; sp = env->regwptr[UREG_FP]; -#if 0 /* This is the X/Open sanctioned signal stack switching. */ - if (sa->sa_flags & TARGET_SA_ONSTACK) { - if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) - sp = current->sas_ss_sp + current->sas_ss_size; + if (sa->sa.sa_flags & TARGET_SA_ONSTACK) { + if (!on_sig_stack(sp) + && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; } -#endif return g2h(sp - framesize); } @@ -1842,11 +1913,10 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) */ sp -= 32; -#if 0 /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; -#endif + if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) { + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } return g2h((sp - frame_size) & ~7); } diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h new file mode 100644 index 000000000..bf54ac71d --- /dev/null +++ b/linux-user/sparc/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_SIGSTKSZ 16384 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h new file mode 100644 index 000000000..bf54ac71d --- /dev/null +++ b/linux-user/sparc64/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 4096 +#define TARGET_SIGSTKSZ 16384 + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 41d58da14..5f1c804aa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4318,7 +4318,14 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, case TARGET_NR_capset: goto unimplemented; case TARGET_NR_sigaltstack: +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) + ret = do_sigaltstack((struct target_sigaltstack *)arg1, + (struct target_sigaltstack *)arg2, + get_sp_from_cpustate((CPUState *)cpu_env)); + break; +#else goto unimplemented; +#endif case TARGET_NR_sendfile: goto unimplemented; #ifdef TARGET_NR_getpmsg diff --git a/linux-user/x86_64/target_signal.h b/linux-user/x86_64/target_signal.h new file mode 100644 index 000000000..eb4a0bb12 --- /dev/null +++ b/linux-user/x86_64/target_signal.h @@ -0,0 +1,24 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_long ss_flags; + target_ulong ss_size; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#endif /* TARGET_SIGNAL_H */ diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 3f517e67b..ef61d8748 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -397,4 +397,9 @@ void cpu_loop_exit (void); void pal_init (CPUState *env); void call_pal (CPUState *env, int palcode); +static inline target_ulong get_sp_from_cpustate(CPUAlphaState *state) +{ + return state->ir[IR_SP]; +} + #endif /* !defined (__CPU_ALPHA_H__) */ diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 76fdbb26b..926aa2a32 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -300,6 +300,11 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define cpu_gen_code cpu_arm_gen_code #define cpu_signal_handler cpu_arm_signal_handler +static inline target_ulong get_sp_from_cpustate(CPUARMState *state) +{ + return state->regs[13]; +} + #include "cpu-all.h" #endif diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2cc7d64e9..4f454c6e9 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -688,6 +688,11 @@ static inline int cpu_get_time_fast(void) #define cpu_gen_code cpu_x86_gen_code #define cpu_signal_handler cpu_x86_signal_handler +static inline target_ulong get_sp_from_cpustate(CPUX86State *state) +{ + return state->regs[R_ESP]; +} + #include "cpu-all.h" #include "svm.h" diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 569f9325b..dd8388152 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -548,4 +548,9 @@ CPUMIPSState *cpu_mips_init(void); uint32_t cpu_mips_get_clock (void); int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); +static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) +{ + return state->gpr[29][state->current_tc]; +} + #endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f1df741e1..e428f70f1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1146,4 +1146,9 @@ enum { /*****************************************************************************/ +static inline target_ulong get_sp_from_cpustate(CPUPPCState *state) +{ + return state->gpr[1]; +} + #endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 5c8c49ab6..cb672717f 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -316,6 +316,18 @@ void cpu_check_irqs(CPUSPARCState *env); #define cpu_gen_code cpu_sparc_gen_code #define cpu_signal_handler cpu_sparc_signal_handler +#ifndef UREG_I6 +#define UREG_I6 6 +#endif +#ifndef UREG_FP +#define UREG_FP UREG_I6 +#endif + +static inline target_ulong get_sp_from_cpustate(CPUSPARCState *state) +{ + return state->regwptr[UREG_FP]; +} + #include "cpu-all.h" #endif -- cgit v1.2.3 From 198a74de4c61d3486c365f09361c605daab90af5 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 27 Sep 2007 16:44:32 +0000 Subject: Move get_sp_from_cpustate from cpu.h to target_signal.h. Enable sigaltstack processing for more architectures. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3253 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/alpha/target_signal.h | 5 +++++ linux-user/arm/target_signal.h | 5 +++++ linux-user/i386/target_signal.h | 5 +++++ linux-user/mips/target_signal.h | 5 +++++ linux-user/ppc/target_signal.h | 5 +++++ linux-user/sparc/target_signal.h | 12 ++++++++++++ linux-user/syscall.c | 3 ++- target-alpha/cpu.h | 5 ----- target-arm/cpu.h | 5 ----- target-i386/cpu.h | 5 ----- target-mips/cpu.h | 5 ----- target-ppc/cpu.h | 5 ----- target-sparc/cpu.h | 12 ------------ 13 files changed, 39 insertions(+), 38 deletions(-) diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h index bf54ac71d..7618c3e83 100644 --- a/linux-user/alpha/target_signal.h +++ b/linux-user/alpha/target_signal.h @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_SIGSTKSZ 16384 +static inline target_ulong get_sp_from_cpustate(CPUAlphaState *state) +{ + return state->ir[IR_SP]; +} + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/arm/target_signal.h b/linux-user/arm/target_signal.h index eb4a0bb12..d51816514 100644 --- a/linux-user/arm/target_signal.h +++ b/linux-user/arm/target_signal.h @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 +static inline target_ulong get_sp_from_cpustate(CPUARMState *state) +{ + return state->regs[13]; +} + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/i386/target_signal.h b/linux-user/i386/target_signal.h index eb4a0bb12..f93a8d62b 100644 --- a/linux-user/i386/target_signal.h +++ b/linux-user/i386/target_signal.h @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 +static inline target_ulong get_sp_from_cpustate(CPUX86State *state) +{ + return state->regs[R_ESP]; +} + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h index c94788497..d7611b01d 100644 --- a/linux-user/mips/target_signal.h +++ b/linux-user/mips/target_signal.h @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 +static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) +{ + return state->gpr[29][state->current_tc]; +} + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/ppc/target_signal.h b/linux-user/ppc/target_signal.h index e210e7a31..80ad21187 100644 --- a/linux-user/ppc/target_signal.h +++ b/linux-user/ppc/target_signal.h @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 +static inline target_ulong get_sp_from_cpustate(CPUPPCState *state) +{ + return state->gpr[1]; +} + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h index bf54ac71d..dfca12916 100644 --- a/linux-user/sparc/target_signal.h +++ b/linux-user/sparc/target_signal.h @@ -21,4 +21,16 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_SIGSTKSZ 16384 +#ifndef UREG_I6 +#define UREG_I6 6 +#endif +#ifndef UREG_FP +#define UREG_FP UREG_I6 +#endif + +static inline target_ulong get_sp_from_cpustate(CPUSPARCState *state) +{ + return state->regwptr[UREG_FP]; +} + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5f1c804aa..af5b9d922 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4318,7 +4318,8 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, case TARGET_NR_capset: goto unimplemented; case TARGET_NR_sigaltstack: -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \ + defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) ret = do_sigaltstack((struct target_sigaltstack *)arg1, (struct target_sigaltstack *)arg2, get_sp_from_cpustate((CPUState *)cpu_env)); diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index ef61d8748..3f517e67b 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -397,9 +397,4 @@ void cpu_loop_exit (void); void pal_init (CPUState *env); void call_pal (CPUState *env, int palcode); -static inline target_ulong get_sp_from_cpustate(CPUAlphaState *state) -{ - return state->ir[IR_SP]; -} - #endif /* !defined (__CPU_ALPHA_H__) */ diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 926aa2a32..76fdbb26b 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -300,11 +300,6 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define cpu_gen_code cpu_arm_gen_code #define cpu_signal_handler cpu_arm_signal_handler -static inline target_ulong get_sp_from_cpustate(CPUARMState *state) -{ - return state->regs[13]; -} - #include "cpu-all.h" #endif diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 4f454c6e9..2cc7d64e9 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -688,11 +688,6 @@ static inline int cpu_get_time_fast(void) #define cpu_gen_code cpu_x86_gen_code #define cpu_signal_handler cpu_x86_signal_handler -static inline target_ulong get_sp_from_cpustate(CPUX86State *state) -{ - return state->regs[R_ESP]; -} - #include "cpu-all.h" #include "svm.h" diff --git a/target-mips/cpu.h b/target-mips/cpu.h index dd8388152..569f9325b 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -548,9 +548,4 @@ CPUMIPSState *cpu_mips_init(void); uint32_t cpu_mips_get_clock (void); int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); -static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) -{ - return state->gpr[29][state->current_tc]; -} - #endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e428f70f1..f1df741e1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1146,9 +1146,4 @@ enum { /*****************************************************************************/ -static inline target_ulong get_sp_from_cpustate(CPUPPCState *state) -{ - return state->gpr[1]; -} - #endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index cb672717f..5c8c49ab6 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -316,18 +316,6 @@ void cpu_check_irqs(CPUSPARCState *env); #define cpu_gen_code cpu_sparc_gen_code #define cpu_signal_handler cpu_sparc_signal_handler -#ifndef UREG_I6 -#define UREG_I6 6 -#endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 -#endif - -static inline target_ulong get_sp_from_cpustate(CPUSPARCState *state) -{ - return state->regwptr[UREG_FP]; -} - #include "cpu-all.h" #endif -- cgit v1.2.3 From df0d37366561d8f23703cd7cf754fefde79e618c Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 28 Sep 2007 18:45:59 +0000 Subject: Build fix, ppc64 needs also a get_sp_from_cpustate function now. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3254 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ppc64/target_signal.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/ppc64/target_signal.h b/linux-user/ppc64/target_signal.h index e210e7a31..80ad21187 100644 --- a/linux-user/ppc64/target_signal.h +++ b/linux-user/ppc64/target_signal.h @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 +static inline target_ulong get_sp_from_cpustate(CPUPPCState *state) +{ + return state->gpr[1]; +} + #endif /* TARGET_SIGNAL_H */ -- cgit v1.2.3 From 418d7c7169818bce67a570fdc86ffb613f53263a Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 28 Sep 2007 19:30:36 +0000 Subject: Fix MIPS FP underflow handling, spotted by Daniel Jacobowitz. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3255 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 6b007a6be..00a6c4448 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1032,10 +1032,6 @@ FLOAT_OP(name, d) \ update_fcr31(); \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ FDT2 = 0x7ff7ffffffffffffULL; \ - else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ - if ((env->fpu->fcr31 & 0x3) == 0) \ - FDT2 &= FLOAT_SIGN64; \ - } \ } \ FLOAT_OP(name, s) \ { \ @@ -1044,10 +1040,6 @@ FLOAT_OP(name, s) \ update_fcr31(); \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ FST2 = 0x7fbfffff; \ - else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ - if ((env->fpu->fcr31 & 0x3) == 0) \ - FST2 &= FLOAT_SIGN32; \ - } \ } \ FLOAT_OP(name, ps) \ { \ @@ -1058,11 +1050,6 @@ FLOAT_OP(name, ps) \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \ FST2 = 0x7fbfffff; \ FSTH2 = 0x7fbfffff; \ - } else if (GET_FP_CAUSE(env->fpu->fcr31) & FP_UNDERFLOW) { \ - if ((env->fpu->fcr31 & 0x3) == 0) { \ - FST2 &= FLOAT_SIGN32; \ - FSTH2 &= FLOAT_SIGN32; \ - } \ } \ } FLOAT_BINOP(add) -- cgit v1.2.3 From d12f4c38226f6f029fb55cb9ec0ed4d2054a9851 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 11:51:08 +0000 Subject: Change POWERPC_PPC_GENERIC to POWERPC_DEFAULT. Use it as default for workstation targets. Fix PowerPC 750fl and 750gl definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3256 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 9 +-------- hw/ppc_prep.c | 3 +-- target-ppc/translate_init.c | 39 ++++++++++++++++++++------------------- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index dc115949f..64746159b 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -330,15 +330,8 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, qemu_register_reset(&cpu_ppc_reset, env); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - /* Default CPU is a generic 74x/75x */ if (cpu_model == NULL) - cpu_model = "750"; - /* XXX: CPU model (or PVR) should be provided on command line */ - // ppc_find_by_name("750gx", &def); // Linux boot OK - // ppc_find_by_name("750fx", &def); // Linux boot OK - /* Linux does not boot on 750cxe (and probably other 750cx based) - * because it assumes it has 8 IBAT & DBAT pairs as it only have 4. - */ + cpu_model = "default"; ppc_find_by_name(cpu_model, &def); if (def == NULL) { cpu_abort(env, "Unable to find PowerPC CPU definition\n"); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index de0e9f098..504ca33a9 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -544,9 +544,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, qemu_register_reset(&cpu_ppc_reset, env); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - /* Default CPU is a 604 */ if (cpu_model == NULL) - cpu_model = "604"; + cpu_model = "default"; ppc_find_by_name(cpu_model, &def); if (def == NULL) { cpu_abort(env, "Unable to find PowerPC CPU definition\n"); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index cc8333f92..dbdbb6c05 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3539,21 +3539,21 @@ static void init_proc_620 (CPUPPCState *env) /* Default PowerPC target will be PowerPC 32 */ #if defined (TARGET_PPC64) && 0 // XXX: TODO -#define CPU_POWERPC_PPC CPU_POWERPC_PPC64 -#define POWERPC_INSNS_PPC_GENERIC POWERPC_INSNS_PPC64 -#define POWERPC_MSRM_PPC_GENERIC POWERPC_MSRM_PPC64 -#define POWERPC_MMU_PPC_GENERIC POWERPC_MMU_PPC64 -#define POWERPC_EXCP_PPC_GENERIC POWERPC_EXCP_PPC64 -#define POWERPC_INPUT_PPC_GENERIC POWERPC_INPUT_PPC64 -#define init_proc_PPC_GENERIC init_proc_PPC64 +#define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC64 +#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC64 +#define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC64 +#define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC64 +#define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC64 +#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64 +#define init_proc_DEFAULT init_proc_PPC64 #else -#define CPU_POWERPC_PPC CPU_POWERPC_PPC32 -#define POWERPC_INSNS_PPC_GENERIC POWERPC_INSNS_PPC32 -#define POWERPC_MSRM_PPC_GENERIC POWERPC_MSRM_PPC32 -#define POWERPC_MMU_PPC_GENERIC POWERPC_MMU_PPC32 -#define POWERPC_EXCP_PPC_GENERIC POWERPC_EXCP_PPC32 -#define POWERPC_INPUT_PPC_GENERIC POWERPC_INPUT_PPC32 -#define init_proc_PPC_GENERIC init_proc_PPC32 +#define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC32 +#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32 +#define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC32 +#define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC32 +#define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC32 +#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32 +#define init_proc_DEFAULT init_proc_PPC32 #endif /*****************************************************************************/ @@ -4607,7 +4607,7 @@ static ppc_def_t ppc_defs[] = { /* PowerPC 750E (G3) */ POWERPC_DEF("750e", CPU_POWERPC_750E, 0xFFFFFFFF, 7x0), /* PowerPC 750FL (G3 embedded) */ - POWERPC_DEF("750fl", CPU_POWERPC_750FL, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750fl", CPU_POWERPC_750FL, 0xFFFFFFFF, 750fx), /* PowerPC 750FX (G3 embedded) */ POWERPC_DEF("750fx", CPU_POWERPC_750FX, 0xFFFFFFFF, 750fx), /* PowerPC 750FX v1.0 (G3 embedded) */ @@ -4621,7 +4621,7 @@ static ppc_def_t ppc_defs[] = { /* PowerPC 750FX v2.3 (G3 embedded) */ POWERPC_DEF("750fx2.3", CPU_POWERPC_750FX_v23, 0xFFFFFFFF, 750fx), /* PowerPC 750GL (G3 embedded) */ - POWERPC_DEF("750gl", CPU_POWERPC_750GL, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750gl", CPU_POWERPC_750GL, 0xFFFFFFFF, 750fx), /* PowerPC 750GX (G3 embedded) */ POWERPC_DEF("750gx", CPU_POWERPC_750GX, 0xFFFFFFFF, 750fx), /* PowerPC 750GX v1.0 (G3 embedded) */ @@ -4993,8 +4993,9 @@ static ppc_def_t ppc_defs[] = { #endif #endif POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, 0xFFFFFFFF, PPC32), + POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, 0xFFFFFFFF, DEFAULT), /* Fallback */ - POWERPC_DEF("ppc", CPU_POWERPC_PPC, 0xFFFFFFFF, PPC_GENERIC), + POWERPC_DEF("default", CPU_POWERPC_DEFAULT, 0xFFFFFFFF, DEFAULT), }; /*****************************************************************************/ @@ -5463,7 +5464,7 @@ int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) ret = -1; *def = NULL; - for (i = 0; strcmp(ppc_defs[i].name, "ppc") != 0; i++) { + for (i = 0; strcmp(ppc_defs[i].name, "default") != 0; i++) { if (strcasecmp(name, ppc_defs[i].name) == 0) { *def = &ppc_defs[i]; ret = 0; @@ -5499,7 +5500,7 @@ void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) for (i = 0; ; i++) { (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", ppc_defs[i].name, ppc_defs[i].pvr); - if (strcmp(ppc_defs[i].name, "ppc") == 0) + if (strcmp(ppc_defs[i].name, "default") == 0) break; } } -- cgit v1.2.3 From 237c0af0175d78955a3007372a2c9789a05705be Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 12:01:46 +0000 Subject: Define the proper bfd_mach to be used by the disassembler for each PowerPC emulated CPU. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3257 c046a42c-6fe2-441c-8c8c-71466251a162 --- disas.c | 11 ++++++++--- target-ppc/cpu.h | 1 + target-ppc/translate.c | 3 ++- target-ppc/translate_init.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/disas.c b/disas.c index d90329659..ae20d37bc 100644 --- a/disas.c +++ b/disas.c @@ -178,13 +178,18 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) disasm_info.mach = bfd_mach_sparc_v9b; #endif #elif defined(TARGET_PPC) - if (flags) + if (flags >> 16) disasm_info.endian = BFD_ENDIAN_LITTLE; + if (flags & 0xFFFF) { + /* If we have a precise definitions of the instructions set, use it */ + disasm_info.mach = flags & 0xFFFF; + } else { #ifdef TARGET_PPC64 - disasm_info.mach = bfd_mach_ppc64; + disasm_info.mach = bfd_mach_ppc64; #else - disasm_info.mach = bfd_mach_ppc; + disasm_info.mach = bfd_mach_ppc; #endif + } print_insn = print_insn_ppc; #elif defined(TARGET_M68K) print_insn = print_insn_m68k; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f1df741e1..79712b0c6 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -398,6 +398,7 @@ struct CPUPPCState { uint8_t excp_model; uint8_t bus_model; uint8_t pad; + int bfd_mach; uint32_t flags; int exception_index; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d370b3ed8..2e5cb6bcd 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6108,7 +6108,8 @@ static inline int gen_intermediate_code_internal (CPUState *env, } if (loglevel & CPU_LOG_TB_IN_ASM) { int flags; - flags = msr_le; + flags = env->bfd_mach; + flags |= msr_le << 16; fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); target_disas(logfile, pc_start, ctx.nip - pc_start, flags); fprintf(logfile, "\n"); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index dbdbb6c05..e3cb18360 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -23,6 +23,8 @@ * inside "#if defined(TODO) ... #endif" statements to make tests easier. */ +#include "dis-asm.h" + //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR //#define PPC_DEBUG_IRQ @@ -37,6 +39,7 @@ struct ppc_def_t { uint8_t excp_model; uint8_t bus_model; uint8_t pad; + int bfd_mach; void (*init_proc)(CPUPPCState *env); }; @@ -2163,6 +2166,7 @@ static void gen_spr_620 (CPUPPCState *env) #define POWERPC_MMU_401 (POWERPC_MMU_REAL_4xx) #define POWERPC_EXCP_401 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_401 (bfd_mach_ppc_403) static void init_proc_401 (CPUPPCState *env) { @@ -2192,6 +2196,7 @@ static void init_proc_401 (CPUPPCState *env) #define POWERPC_MMU_401x2 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) static void init_proc_401x2 (CPUPPCState *env) { @@ -2227,6 +2232,7 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_MMU_401x3 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) static void init_proc_401x2 (CPUPPCState *env) { @@ -2243,6 +2249,7 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_MMU_IOP480 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) #define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) static void init_proc_IOP480 (CPUPPCState *env) { @@ -2276,6 +2283,7 @@ static void init_proc_IOP480 (CPUPPCState *env) #define POWERPC_MMU_403 (POWERPC_MMU_REAL_4xx) #define POWERPC_EXCP_403 (POWERPC_EXCP_40x) #define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_403 (bfd_mach_ppc_403) static void init_proc_403 (CPUPPCState *env) { @@ -2295,6 +2303,7 @@ static void init_proc_403 (CPUPPCState *env) #define POWERPC_MMU_403GCX (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) #define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) static void init_proc_403GCX (CPUPPCState *env) { @@ -2330,6 +2339,7 @@ static void init_proc_403GCX (CPUPPCState *env) #define POWERPC_MMU_405 (POWERPC_MMU_SOFT_4xx) #define POWERPC_EXCP_405 (POWERPC_EXCP_40x) #define POWERPC_INPUT_405 (PPC_FLAGS_INPUT_405) +#define POWERPC_BFDM_405 (bfd_mach_ppc_403) static void init_proc_405 (CPUPPCState *env) { @@ -2364,6 +2374,7 @@ static void init_proc_405 (CPUPPCState *env) #define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_440EP (bfd_mach_ppc_403) static void init_proc_440EP (CPUPPCState *env) { @@ -2403,6 +2414,7 @@ static void init_proc_440EP (CPUPPCState *env) #define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440GP (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_440GP (bfd_mach_ppc_403) static void init_proc_440GP (CPUPPCState *env) { @@ -2427,6 +2439,7 @@ static void init_proc_440GP (CPUPPCState *env) #define POWERPC_MMU_440x4 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) static void init_proc_440x4 (CPUPPCState *env) { @@ -2451,6 +2464,7 @@ static void init_proc_440x4 (CPUPPCState *env) #define POWERPC_MMU_440x5 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440x5 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) static void init_proc_440x5 (CPUPPCState *env) { @@ -2491,6 +2505,7 @@ static void init_proc_440x5 (CPUPPCState *env) #define POWERPC_MMU_460 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_460 (bfd_mach_ppc_403) static void init_proc_460 (CPUPPCState *env) { @@ -2510,6 +2525,7 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_MMU_460F (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_460F (bfd_mach_ppc_403) static void init_proc_460 (CPUPPCState *env) { @@ -2558,6 +2574,7 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_MMU_BookE (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_BookE (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_BookE (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_BookE (bfd_mach_ppc_403) static void init_proc_BookE (CPUPPCState *env) { @@ -2581,6 +2598,7 @@ static void init_proc_BookE (CPUPPCState *env) #define POWERPC_MMU_e500 (POWERPC_MMU_SOFT_4xx) #define POWERPC_EXCP_e500 (POWERPC_EXCP_40x) #define POWERPC_INPUT_e500 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_e500 (bfd_mach_ppc_403) static void init_proc_e500 (CPUPPCState *env) { @@ -2623,6 +2641,7 @@ static void init_proc_e500 (CPUPPCState *env) //#define POWERPC_MMU_601 (POWERPC_MMU_601) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_601 (bfd_mach_ppc_601) static void init_proc_601 (CPUPPCState *env) { @@ -2671,6 +2690,7 @@ static void init_proc_601 (CPUPPCState *env) #define POWERPC_MMU_602 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_602 (POWERPC_EXCP_602) #define POWERPC_INPUT_602 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_602 (bfd_mach_ppc_602) static void init_proc_602 (CPUPPCState *env) { @@ -2702,6 +2722,7 @@ static void init_proc_602 (CPUPPCState *env) #define POWERPC_MMU_603 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_603 (POWERPC_EXCP_603) #define POWERPC_INPUT_603 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_603 (bfd_mach_ppc_603) static void init_proc_603 (CPUPPCState *env) { @@ -2733,6 +2754,7 @@ static void init_proc_603 (CPUPPCState *env) #define POWERPC_MMU_603E (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_603E (POWERPC_EXCP_603E) #define POWERPC_INPUT_603E (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_603E (bfd_mach_ppc_ec603e) static void init_proc_603E (CPUPPCState *env) { @@ -2769,6 +2791,7 @@ static void init_proc_603E (CPUPPCState *env) #define POWERPC_MMU_G2 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) #define POWERPC_INPUT_G2 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) static void init_proc_G2 (CPUPPCState *env) { @@ -2807,6 +2830,7 @@ static void init_proc_G2 (CPUPPCState *env) #define POWERPC_MMU_G2LE (POWERPC_MMU_SOFT_6xx) #define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) #define POWERPC_INPUT_G2LE (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) static void init_proc_G2LE (CPUPPCState *env) { @@ -2845,6 +2869,7 @@ static void init_proc_G2LE (CPUPPCState *env) #define POWERPC_MMU_604 (POWERPC_MMU_32B) //#define POWERPC_EXCP_604 (POWERPC_EXCP_604) #define POWERPC_INPUT_604 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_604 (bfd_mach_ppc_604) static void init_proc_604 (CPUPPCState *env) { @@ -2875,6 +2900,7 @@ static void init_proc_604 (CPUPPCState *env) #define POWERPC_MMU_7x0 (POWERPC_MMU_32B) //#define POWERPC_EXCP_7x0 (POWERPC_EXCP_7x0) #define POWERPC_INPUT_7x0 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7x0 (bfd_mach_ppc_750) static void init_proc_7x0 (CPUPPCState *env) { @@ -2907,6 +2933,7 @@ static void init_proc_7x0 (CPUPPCState *env) #define POWERPC_MMU_750fx (POWERPC_MMU_32B) #define POWERPC_EXCP_750fx (POWERPC_EXCP_7x0) #define POWERPC_INPUT_750fx (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_750fx (bfd_mach_ppc_750) static void init_proc_750fx (CPUPPCState *env) { @@ -2946,6 +2973,7 @@ static void init_proc_750fx (CPUPPCState *env) #define POWERPC_MMU_7x5 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_7x5 (POWERPC_EXCP_7x5) #define POWERPC_INPUT_7x5 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7x5 (bfd_mach_ppc_750) static void init_proc_7x5 (CPUPPCState *env) { @@ -2996,6 +3024,7 @@ static void init_proc_7x5 (CPUPPCState *env) #define POWERPC_MMU_7400 (POWERPC_MMU_32B) #define POWERPC_EXCP_7400 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7400 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7400 (bfd_mach_ppc_7400) static void init_proc_7400 (CPUPPCState *env) { @@ -3021,6 +3050,7 @@ static void init_proc_7400 (CPUPPCState *env) #define POWERPC_MMU_7410 (POWERPC_MMU_32B) #define POWERPC_EXCP_7410 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7410 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7410 (bfd_mach_ppc_7400) static void init_proc_7410 (CPUPPCState *env) { @@ -3059,6 +3089,7 @@ static void init_proc_7410 (CPUPPCState *env) #define POWERPC_MMU_7440 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7440 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7440 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7440 (bfd_mach_ppc_7400) static void init_proc_7440 (CPUPPCState *env) { @@ -3120,6 +3151,7 @@ static void init_proc_7440 (CPUPPCState *env) #define POWERPC_MMU_7450 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7450 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7450 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7450 (bfd_mach_ppc_7400) static void init_proc_7450 (CPUPPCState *env) { @@ -3183,6 +3215,7 @@ static void init_proc_7450 (CPUPPCState *env) #define POWERPC_MMU_7445 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7445 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7445 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7445 (bfd_mach_ppc_7400) static void init_proc_7445 (CPUPPCState *env) { @@ -3278,6 +3311,7 @@ static void init_proc_7445 (CPUPPCState *env) #define POWERPC_MMU_7455 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7455 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7455 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7455 (bfd_mach_ppc_7400) static void init_proc_7455 (CPUPPCState *env) { @@ -3375,6 +3409,7 @@ static void init_proc_7455 (CPUPPCState *env) #define POWERPC_MMU_970 (POWERPC_MMU_64BRIDGE) //#define POWERPC_EXCP_970 (POWERPC_EXCP_970) #define POWERPC_INPUT_970 (PPC_FLAGS_INPUT_970) +#define POWERPC_BFDM_970 (bfd_mach_ppc64) static void init_proc_970 (CPUPPCState *env) { @@ -3416,6 +3451,7 @@ static void init_proc_970 (CPUPPCState *env) #define POWERPC_MMU_970FX (POWERPC_MMU_64BRIDGE) #define POWERPC_EXCP_970FX (POWERPC_EXCP_970) #define POWERPC_INPUT_970FX (PPC_FLAGS_INPUT_970) +#define POWERPC_BFDM_970FX (bfd_mach_ppc64) static void init_proc_970FX (CPUPPCState *env) { @@ -3457,6 +3493,7 @@ static void init_proc_970FX (CPUPPCState *env) #define POWERPC_MMU_970GX (POWERPC_MMU_64BRIDGE) #define POWERPC_EXCP_970GX (POWERPC_EXCP_970) #define POWERPC_INPUT_970GX (PPC_FLAGS_INPUT_970) +#define POWERPC_BFDM_970GX (bfd_mach_ppc64) static void init_proc_970GX (CPUPPCState *env) { @@ -3498,6 +3535,7 @@ static void init_proc_970GX (CPUPPCState *env) #define POWERPC_MMU_620 (POWERPC_MMU_64B) #define POWERPC_EXCP_620 (POWERPC_EXCP_970) #define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_970) +#define POWERPC_BFDM_620 (bfd_mach_ppc64) static void init_proc_620 (CPUPPCState *env) { @@ -3527,6 +3565,7 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_EXCP_PPC32 POWERPC_EXCP_604 #define POWERPC_INPUT_PPC32 POWERPC_INPUT_604 #define init_proc_PPC32 init_proc_604 +#define POWERPC_BFDM_PPC32 POWERPC_BFDM_604 /* Default 64 bits PowerPC target will be 970 FX */ #define CPU_POWERPC_PPC64 CPU_POWERPC_970FX @@ -3536,6 +3575,7 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_EXCP_PPC64 POWERPC_EXCP_970FX #define POWERPC_INPUT_PPC64 POWERPC_INPUT_970FX #define init_proc_PPC64 init_proc_970FX +#define POWERPC_BFDM_PPC64 POWERPC_BFDM_970FX /* Default PowerPC target will be PowerPC 32 */ #if defined (TARGET_PPC64) && 0 // XXX: TODO @@ -3546,6 +3586,7 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC64 #define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64 #define init_proc_DEFAULT init_proc_PPC64 +#define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC64 #else #define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC32 #define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32 @@ -3554,6 +3595,7 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC32 #define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32 #define init_proc_DEFAULT init_proc_PPC32 +#define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC32 #endif /*****************************************************************************/ @@ -4048,6 +4090,7 @@ enum { .mmu_model = glue(POWERPC_MMU_,_type), \ .excp_model = glue(POWERPC_EXCP_,_type), \ .bus_model = glue(POWERPC_INPUT_,_type), \ + .bfd_mach = glue(POWERPC_BFDM_,_type), \ .init_proc = &glue(init_proc_,_type), \ } @@ -5332,6 +5375,7 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) env->mmu_model = def->mmu_model; env->excp_model = def->excp_model; env->bus_model = def->bus_model; + env->bfd_mach = def->bfd_mach; if (create_ppc_opcodes(env, def) < 0) return -1; init_ppc_proc(env, def); -- cgit v1.2.3 From f1548daae3c790b9740d41eaa7524572db612970 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 12:15:39 +0000 Subject: host_utils.o may also be useful for user-mode emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3258 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index 6c2a4128c..6f54de0b4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -269,7 +269,7 @@ OBJS+= libqemu.a # cpu emulator library LIBOBJS=exec.o kqemu.o translate-op.o translate-all.o cpu-exec.o\ - translate.o op.o + translate.o op.o host-utils.o ifdef CONFIG_SOFTFLOAT LIBOBJS+=fpu/softfloat.o else @@ -369,7 +369,6 @@ 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+=host-utils.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 block-parallels.o VL_OBJS+=irq.o -- cgit v1.2.3 From 29f640e2cfe4d7da114482fd8de257a27274288d Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 12:17:25 +0000 Subject: always_inline gcc directive can be useful. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3259 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 8 ++++++++ vl.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/exec-all.h b/exec-all.h index f58aea534..3151bb591 100644 --- a/exec-all.h +++ b/exec-all.h @@ -37,6 +37,14 @@ #define unlikely(x) __builtin_expect(!!(x), 0) #endif +#ifndef always_inline +#if __GNUC__ < 3 +#define always_inline inline +#else +#define always_inline __attribute__ (( always_inline )) inline +#endif +#endif + #ifdef __i386__ #define REGPARM(n) __attribute((regparm(n))) #else diff --git a/vl.h b/vl.h index b2dde5dd0..378ed273c 100644 --- a/vl.h +++ b/vl.h @@ -109,6 +109,14 @@ static inline char *realpath(const char *path, char *resolved_path) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#ifndef always_inline +#if __GNUC__ < 3 +#define always_inline inline +#else +#define always_inline __attribute__ (( always_inline )) inline +#endif +#endif + /* cutils.c */ void pstrcpy(char *buf, int buf_size, const char *str); char *pstrcat(char *buf, int buf_size, const char *s); -- cgit v1.2.3 From f93732914e0b06539170e84f046f01ebe99980f3 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 12:18:20 +0000 Subject: make cpu_abort dump cpu state in logfile, which is useful for debugging. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3260 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 7d8ae3fd9..0c0b6542e 100644 --- a/exec.c +++ b/exec.c @@ -1301,11 +1301,19 @@ void cpu_abort(CPUState *env, const char *fmt, ...) #else cpu_dump_state(env, stderr, fprintf, 0); #endif - va_end(ap); if (logfile) { + fprintf(logfile, "qemu: fatal: "); + vfprintf(logfile, fmt, ap); + fprintf(logfile, "\n"); +#ifdef TARGET_I386 + cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); +#else + cpu_dump_state(env, logfile, fprintf, 0); +#endif fflush(logfile); fclose(logfile); } + va_end(ap); abort(); } -- cgit v1.2.3 From e1833e1f96456fd8fc17463246fe0b2050e68efb Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 13:06:16 +0000 Subject: Rework PowerPC exceptions model to make it more versatile: * don't use exception vectors as the exception number. Use vectors numbers as defined in the PowerPC embedded specification instead and extend this model to cover all emulated PowerPC variants exceptions. * add some missing exceptions definitions, from PowerPC 2.04 specification and actual PowerPC implementations. * add code provision for hypervisor exceptions handling. * define exception vectors and prefix in CPUPPCState to emulate BookE exception vectors without any hacks. * define per CPU model valid exception vectors. * handle all known exceptions in user-mode only emulations. * fix hardware interrupts priorities in most cases. * change RET_EXCP macros name into GEN_EXCP as they don't return. * do not stop translation on most instructions that are not defined as context-synchronizing in PowerPC specification. * fix PowerPC 64 jump targets and link register update when in 32 bits mode. * Fix PowerPC 464 and 464F definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3261 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 570 ++++++++++++++----------- linux-user/main.c | 458 ++++++++++++-------- target-ppc/cpu.h | 268 ++++++------ target-ppc/helper.c | 993 +++++++++++++++++++++++--------------------- target-ppc/op_helper.c | 20 +- target-ppc/op_mem.h | 48 ++- target-ppc/translate.c | 440 ++++++++++---------- target-ppc/translate_init.c | 421 ++++++++++++++++++- 8 files changed, 1958 insertions(+), 1260 deletions(-) diff --git a/darwin-user/main.c b/darwin-user/main.c index fd62fc1b8..affd87454 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -139,17 +139,6 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); } -uint32_t cpu_ppc_load_decr (CPUState *env) -{ - /* TO FIX */ - return -1; -} - -void cpu_ppc_store_decr (CPUState *env, uint32_t value) -{ - /* TO FIX */ -} - void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value) { cpu_ppc_store_tbu( env, value ); @@ -165,6 +154,27 @@ uint32_t cpu_ppc601_load_rtcl (CPUState *env) return cpu_ppc_load_tbl(env) & 0x3FFFFF80; } +/* XXX: to be fixed */ +int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp) +{ + return -1; +} + +int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val) +{ + return -1; +} + +#define EXCP_DUMP(env, fmt, args...) \ +do { \ + fprintf(stderr, fmt , ##args); \ + cpu_dump_state(env, stderr, fprintf, 0); \ + if (loglevel != 0) { \ + fprintf(logfile, fmt , ##args); \ + cpu_dump_state(env, logfile, fprintf, 0); \ + } \ +} while (0) + void cpu_loop(CPUPPCState *env) { int trapnr; @@ -173,271 +183,365 @@ void cpu_loop(CPUPPCState *env) for(;;) { trapnr = cpu_ppc_exec(env); - if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && - trapnr != EXCP_TRACE) { - if (loglevel > 0) { - cpu_dump_state(env, logfile, fprintf, 0); - } - } switch(trapnr) { - case EXCP_NONE: + case POWERPC_EXCP_NONE: + /* Just go on */ break; - case EXCP_SYSCALL_USER: - /* system call */ - if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) - ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6], env->gpr[7], - env->gpr[8], env->gpr[9], env->gpr[10]*/); - else if(((int)env->gpr[0])<0) - ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6], env->gpr[7], - env->gpr[8], env->gpr[9], env->gpr[10]); - else - ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6], env->gpr[7], - env->gpr[8], env->gpr[9], env->gpr[10]); - - /* Unix syscall error signaling */ - if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) - { - if( (int)ret < 0 ) - env->nip += 0; - else - env->nip += 4; - } - - /* Return value */ - env->gpr[3] = ret; + case POWERPC_EXCP_CRITICAL: /* Critical input */ + cpu_abort(env, "Critical interrupt while in user mode. " + "Aborting\n"); break; - case EXCP_RESET: - /* Should not happen ! */ - fprintf(stderr, "RESET asked... Stop emulation\n"); - if (loglevel) - fprintf(logfile, "RESET asked... Stop emulation\n"); - abort(); - case EXCP_MACHINE_CHECK: - fprintf(stderr, "Machine check exeption... Stop emulation\n"); - if (loglevel) - fprintf(logfile, "RESET asked... Stop emulation\n"); - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_OBJERR; - info.si_addr = (void*)(env->nip - 4); - queue_signal(info.si_signo, &info); - case EXCP_DSI: + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + cpu_abort(env, "Machine check exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ #ifndef DAR /* To deal with multiple qemu header version as host for the darwin-user code */ # define DAR SPR_DAR #endif - fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]); - if (loglevel) { - fprintf(logfile, "Invalid data memory access: 0x%08x\n", - env->spr[DAR]); - } + EXCP_DUMP(env, "Invalid data memory access: 0x" ADDRX "\n", + env->spr[SPR_DAR]); /* Handle this via the gdb */ gdb_handlesig (env, SIGSEGV); info.si_addr = (void*)env->nip; queue_signal(info.si_signo, &info); break; - case EXCP_ISI: - fprintf(stderr, "Invalid instruction fetch\n"); - if (loglevel) - fprintf(logfile, "Invalid instruction fetch\n"); + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n", + env->spr[SPR_DAR]); /* Handle this via the gdb */ gdb_handlesig (env, SIGSEGV); info.si_addr = (void*)(env->nip - 4); queue_signal(info.si_signo, &info); break; - case EXCP_EXTERNAL: - /* Should not happen ! */ - fprintf(stderr, "External interruption... Stop emulation\n"); - if (loglevel) - fprintf(logfile, "External interruption... Stop emulation\n"); - abort(); - case EXCP_ALIGN: - fprintf(stderr, "Invalid unaligned memory access\n"); - if (loglevel) - fprintf(logfile, "Invalid unaligned memory access\n"); - info.si_signo = SIGBUS; + case POWERPC_EXCP_EXTERNAL: /* External input */ + cpu_abort(env, "External interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + EXCP_DUMP(env, "Unaligned memory access\n"); info.si_errno = 0; info.si_code = BUS_ADRALN; info.si_addr = (void*)(env->nip - 4); queue_signal(info.si_signo, &info); break; - case EXCP_PROGRAM: + case POWERPC_EXCP_PROGRAM: /* Program exception */ + /* XXX: check this */ switch (env->error_code & ~0xF) { - case EXCP_FP: - fprintf(stderr, "Program exception\n"); - if (loglevel) - fprintf(logfile, "Program exception\n"); - /* Set FX */ - env->fpscr[7] |= 0x8; - /* Finally, update FEX */ - if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & - ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) - env->fpscr[7] |= 0x4; - info.si_signo = SIGFPE; - info.si_errno = 0; - switch (env->error_code & 0xF) { - case EXCP_FP_OX: - info.si_code = FPE_FLTOVF; - break; - case EXCP_FP_UX: - info.si_code = FPE_FLTUND; - break; - case EXCP_FP_ZX: - case EXCP_FP_VXZDZ: - info.si_code = FPE_FLTDIV; - break; - case EXCP_FP_XX: - info.si_code = FPE_FLTRES; - break; - case EXCP_FP_VXSOFT: - info.si_code = FPE_FLTINV; - break; - case EXCP_FP_VXNAN: - case EXCP_FP_VXISI: - case EXCP_FP_VXIDI: - case EXCP_FP_VXIMZ: - case EXCP_FP_VXVC: - case EXCP_FP_VXSQRT: - case EXCP_FP_VXCVI: - info.si_code = FPE_FLTSUB; - break; - default: - fprintf(stderr, "Unknown floating point exception " - "(%02x)\n", env->error_code); - if (loglevel) { - fprintf(logfile, "Unknown floating point exception " - "(%02x)\n", env->error_code & 0xF); - } - } - break; - case EXCP_INVAL: - fprintf(stderr, "Invalid instruction\n"); - if (loglevel) - fprintf(logfile, "Invalid instruction\n"); - info.si_signo = SIGILL; - info.si_errno = 0; - switch (env->error_code & 0xF) { - case EXCP_INVAL_INVAL: - info.si_code = ILL_ILLOPC; - break; - case EXCP_INVAL_LSWX: - info.si_code = ILL_ILLOPN; - break; - case EXCP_INVAL_SPR: - info.si_code = ILL_PRVREG; - break; - case EXCP_INVAL_FP: - info.si_code = ILL_COPROC; - break; - default: - fprintf(stderr, "Unknown invalid operation (%02x)\n", - env->error_code & 0xF); - if (loglevel) { - fprintf(logfile, "Unknown invalid operation (%02x)\n", - env->error_code & 0xF); - } - info.si_code = ILL_ILLADR; - break; - } - /* Handle this via the gdb */ - gdb_handlesig (env, SIGSEGV); + case POWERPC_EXCP_FP: + EXCP_DUMP(env, "Floating point program exception\n"); + /* Set FX */ + env->fpscr[7] |= 0x8; + /* Finally, update FEX */ + if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & + ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) + env->fpscr[7] |= 0x4; + info.si_signo = SIGFPE; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case POWERPC_EXCP_FP_OX: + info.si_code = FPE_FLTOVF; + break; + case POWERPC_EXCP_FP_UX: + info.si_code = FPE_FLTUND; + break; + case POWERPC_EXCP_FP_ZX: + case POWERPC_EXCP_FP_VXZDZ: + info.si_code = FPE_FLTDIV; + break; + case POWERPC_EXCP_FP_XX: + info.si_code = FPE_FLTRES; + break; + case POWERPC_EXCP_FP_VXSOFT: + info.si_code = FPE_FLTINV; + break; + case POWERPC_EXCP_FP_VXNAN: + case POWERPC_EXCP_FP_VXISI: + case POWERPC_EXCP_FP_VXIDI: + case POWERPC_EXCP_FP_VXIMZ: + case POWERPC_EXCP_FP_VXVC: + case POWERPC_EXCP_FP_VXSQRT: + case POWERPC_EXCP_FP_VXCVI: + info.si_code = FPE_FLTSUB; + break; + default: + EXCP_DUMP(env, "Unknown floating point exception (%02x)\n", + env->error_code); + break; + } + break; + case POWERPC_EXCP_INVAL: + EXCP_DUMP(env, "Invalid instruction\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case POWERPC_EXCP_INVAL_INVAL: + info.si_code = ILL_ILLOPC; + break; + case POWERPC_EXCP_INVAL_LSWX: + info.si_code = ILL_ILLOPN; + break; + case POWERPC_EXCP_INVAL_SPR: + info.si_code = ILL_PRVREG; + break; + case POWERPC_EXCP_INVAL_FP: + info.si_code = ILL_COPROC; + break; + default: + EXCP_DUMP(env, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + info.si_code = ILL_ILLADR; + break; + } + /* Handle this via the gdb */ + gdb_handlesig (env, SIGSEGV); + break; + case POWERPC_EXCP_PRIV: + EXCP_DUMP(env, "Privilege violation\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case POWERPC_EXCP_PRIV_OPC: + info.si_code = ILL_PRVOPC; + break; + case POWERPC_EXCP_PRIV_REG: + info.si_code = ILL_PRVREG; break; - case EXCP_PRIV: - fprintf(stderr, "Privilege violation\n"); - if (loglevel) - fprintf(logfile, "Privilege violation\n"); - info.si_signo = SIGILL; - info.si_errno = 0; - switch (env->error_code & 0xF) { - case EXCP_PRIV_OPC: - info.si_code = ILL_PRVOPC; - break; - case EXCP_PRIV_REG: - info.si_code = ILL_PRVREG; - break; - default: - fprintf(stderr, "Unknown privilege violation (%02x)\n", - env->error_code & 0xF); - info.si_code = ILL_PRVOPC; - break; - } - break; - case EXCP_TRAP: - fprintf(stderr, "Tried to call a TRAP\n"); - if (loglevel) - fprintf(logfile, "Tried to call a TRAP\n"); - abort(); default: - /* Should not happen ! */ - fprintf(stderr, "Unknown program exception (%02x)\n", - env->error_code); - if (loglevel) { - fprintf(logfile, "Unknwon program exception (%02x)\n", - env->error_code); - } - abort(); + EXCP_DUMP(env, "Unknown privilege violation (%02x)\n", + env->error_code & 0xF); + info.si_code = ILL_PRVOPC; + break; + } + break; + case POWERPC_EXCP_TRAP: + cpu_abort(env, "Tried to call a TRAP\n"); + break; + default: + /* Should not happen ! */ + cpu_abort(env, "Unknown program exception (%02x)\n", + env->error_code); + break; } info.si_addr = (void*)(env->nip - 4); queue_signal(info.si_signo, &info); break; - case EXCP_NO_FP: - fprintf(stderr, "No floating point allowed\n"); - if (loglevel) - fprintf(logfile, "No floating point allowed\n"); - info.si_signo = SIGILL; + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ + EXCP_DUMP(env, "No floating point allowed\n"); + info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_COPROC; info.si_addr = (void*)(env->nip - 4); queue_signal(info.si_signo, &info); break; - case EXCP_DECR: - /* Should not happen ! */ - fprintf(stderr, "Decrementer exception\n"); - if (loglevel) - fprintf(logfile, "Decrementer exception\n"); - abort(); - case EXCP_TRACE: - /* Pass to gdb: we use this to trace execution */ - gdb_handlesig (env, SIGTRAP); + case POWERPC_EXCP_SYSCALL: /* System call exception */ + cpu_abort(env, "Syscall exception while in user mode. " + "Aborting\n"); break; - case EXCP_FP_ASSIST: - /* Should not happen ! */ - fprintf(stderr, "Floating point assist exception\n"); - if (loglevel) - fprintf(logfile, "Floating point assist exception\n"); - abort(); - case EXCP_MTMSR: - /* We reloaded the msr, just go on */ - if (msr_pr == 0) { - fprintf(stderr, "Tried to go into supervisor mode !\n"); - if (loglevel) - fprintf(logfile, "Tried to go into supervisor mode !\n"); - abort(); - } + case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ + EXCP_DUMP(env, "No APU instruction allowed\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_COPROC; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); break; - case EXCP_BRANCH: - /* We stopped because of a jump... */ + case POWERPC_EXCP_DECR: /* Decrementer exception */ + cpu_abort(env, "Decrementer interrupt while in user mode. " + "Aborting\n"); break; - case EXCP_INTERRUPT: - /* Don't know why this should ever happen... */ - fprintf(stderr, "EXCP_INTERRUPT\n"); + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + cpu_abort(env, "Fix interval timer interrupt while in user mode. " + "Aborting\n"); break; - case EXCP_DEBUG: + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ + cpu_abort(env, "Watchdog timer interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DTLB: /* Data TLB error */ + cpu_abort(env, "Data TLB exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ITLB: /* Instruction TLB error */ + cpu_abort(env, "Instruction TLB exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DEBUG: /* Debug interrupt */ gdb_handlesig (env, SIGTRAP); break; - default: - fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", - trapnr); - if (loglevel) { - fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " - "0x%02x - aborting\n", trapnr, env->error_code); +#if defined(TARGET_PPCEMB) + case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */ + EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_COPROC; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */ + cpu_abort(env, "Embedded floating-point data IRQ not handled\n"); + break; + case POWERPC_EXCP_EFPRI: /* Embedded floating-point round IRQ */ + cpu_abort(env, "Embedded floating-point round IRQ not handled\n"); + break; + case POWERPC_EXCP_EPERFM: /* Embedded performance monitor IRQ */ + cpu_abort(env, "Performance monitor exception not handled\n"); + break; + case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ + cpu_abort(env, "Doorbell interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ + cpu_abort(env, "Doorbell critical interrupt while in user mode. " + "Aborting\n"); + break; +#endif /* defined(TARGET_PPCEMB) */ + case POWERPC_EXCP_RESET: /* System reset exception */ + cpu_abort(env, "Reset interrupt while in user mode. " + "Aborting\n"); + break; +#if defined(TARGET_PPC64) /* PowerPC 64 */ + case POWERPC_EXCP_DSEG: /* Data segment exception */ + cpu_abort(env, "Data segment exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ISEG: /* Instruction segment exception */ + cpu_abort(env, "Instruction segment exception " + "while in user mode. Aborting\n"); + break; +#endif /* defined(TARGET_PPC64) */ +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ + cpu_abort(env, "Hypervisor decrementer interrupt " + "while in user mode. Aborting\n"); + break; +#endif /* defined(TARGET_PPC64H) */ + case POWERPC_EXCP_TRACE: /* Trace exception */ + /* Nothing to do: + * we use this exception to emulate step-by-step execution mode. + */ + break; +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ + cpu_abort(env, "Hypervisor data storage exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HISI: /* Hypervisor instruction storage excp */ + cpu_abort(env, "Hypervisor instruction storage exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ + cpu_abort(env, "Hypervisor data segment exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment excp */ + cpu_abort(env, "Hypervisor instruction segment exception " + "while in user mode. Aborting\n"); + break; +#endif /* defined(TARGET_PPC64H) */ + case POWERPC_EXCP_VPU: /* Vector unavailable exception */ + EXCP_DUMP(env, "No Altivec instructions allowed\n"); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_COPROC; + info.si_addr = (void*)(env->nip - 4); + queue_signal(info.si_signo, &info); + break; + case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */ + cpu_abort(env, "Programable interval timer interrupt " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_IO: /* IO error exception */ + cpu_abort(env, "IO error exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_RUNM: /* Run mode exception */ + cpu_abort(env, "Run mode exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_EMUL: /* Emulation trap exception */ + cpu_abort(env, "Emulation trap exception not handled\n"); + break; + case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ + cpu_abort(env, "Instruction fetch TLB exception " + "while in user-mode. Aborting"); + break; + case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ + cpu_abort(env, "Data load TLB exception while in user-mode. " + "Aborting"); + break; + case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ + cpu_abort(env, "Data store TLB exception while in user-mode. " + "Aborting"); + break; + case POWERPC_EXCP_FPA: /* Floating-point assist exception */ + cpu_abort(env, "Floating-point assist exception not handled\n"); + break; + case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ + cpu_abort(env, "Instruction address breakpoint exception " + "not handled\n"); + break; + case POWERPC_EXCP_SMI: /* System management interrupt */ + cpu_abort(env, "System management interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_THERM: /* Thermal interrupt */ + cpu_abort(env, "Thermal interrupt interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_PERFM: /* Embedded performance monitor IRQ */ + cpu_abort(env, "Performance monitor exception not handled\n"); + break; + case POWERPC_EXCP_VPUA: /* Vector assist exception */ + cpu_abort(env, "Vector assist exception not handled\n"); + break; + case POWERPC_EXCP_SOFTP: /* Soft patch exception */ + cpu_abort(env, "Soft patch exception not handled\n"); + break; + case POWERPC_EXCP_MAINT: /* Maintenance exception */ + cpu_abort(env, "Maintenance exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_STOP: /* stop translation */ + /* We did invalidate the instruction cache. Go on */ + break; + case POWERPC_EXCP_BRANCH: /* branch instruction: */ + /* We just stopped because of a branch. Go on */ + break; + case POWERPC_EXCP_SYSCALL_USER: + /* system call in user-mode emulation */ + /* system call */ + if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) + ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]*/); + else if(((int)env->gpr[0])<0) + ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]); + else + ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8], env->gpr[9], env->gpr[10]); + + /* Unix syscall error signaling */ + if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0) + { + if( (int)ret < 0 ) + env->nip += 0; + else + env->nip += 4; } - abort(); + + /* Return value */ + env->gpr[3] = ret; + break; + default: + cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr); + break; } process_pending_signals(env); } diff --git a/linux-user/main.c b/linux-user/main.c index b70c070c3..fb424ad88 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -723,6 +723,16 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val) return -1; } +#define EXCP_DUMP(env, fmt, args...) \ +do { \ + fprintf(stderr, fmt , ##args); \ + cpu_dump_state(env, stderr, fprintf, 0); \ + if (loglevel != 0) { \ + fprintf(logfile, fmt , ##args); \ + cpu_dump_state(env, logfile, fprintf, 0); \ + } \ +} while (0) + void cpu_loop(CPUPPCState *env) { target_siginfo_t info; @@ -731,60 +741,22 @@ void cpu_loop(CPUPPCState *env) for(;;) { trapnr = cpu_ppc_exec(env); - if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && - trapnr != EXCP_TRACE) { - if (loglevel > 0) { - cpu_dump_state(env, logfile, fprintf, 0); - } - } switch(trapnr) { - case EXCP_NONE: + case POWERPC_EXCP_NONE: + /* Just go on */ break; - case EXCP_SYSCALL_USER: - /* system call */ - /* WARNING: - * PPC ABI uses overflow flag in cr0 to signal an error - * in syscalls. - */ -#if 0 - printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0], - env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); -#endif - env->crf[0] &= ~0x1; - ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6], env->gpr[7], - env->gpr[8]); - if (ret > (uint32_t)(-515)) { - env->crf[0] |= 0x1; - ret = -ret; - } - env->gpr[3] = ret; -#if 0 - printf("syscall returned 0x%08x (%d)\n", ret, ret); -#endif + case POWERPC_EXCP_CRITICAL: /* Critical input */ + cpu_abort(env, "Critical interrupt while in user mode. " + "Aborting\n"); break; - case EXCP_RESET: - /* Should not happen ! */ - fprintf(stderr, "RESET asked... Stop emulation\n"); - if (loglevel) - fprintf(logfile, "RESET asked... Stop emulation\n"); - abort(); - case EXCP_MACHINE_CHECK: - fprintf(stderr, "Machine check exeption... Stop emulation\n"); - if (loglevel) - fprintf(logfile, "Machine check exception. Stop emulation\n"); - info.si_signo = TARGET_SIGBUS; - info.si_errno = 0; - info.si_code = TARGET_BUS_OBJERR; - info._sifields._sigfault._addr = env->nip - 4; - queue_signal(info.si_signo, &info); - case EXCP_DSI: - fprintf(stderr, "Invalid data memory access: 0x" ADDRX "\n", - env->spr[SPR_DAR]); - if (loglevel) { - fprintf(logfile, "Invalid data memory access: 0x" ADDRX "\n", - env->spr[SPR_DAR]); - } + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + cpu_abort(env, "Machine check exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ + EXCP_DUMP(env, "Invalid data memory access: 0x" ADDRX "\n", + env->spr[SPR_DAR]); + /* XXX: check this. Seems bugged */ switch (env->error_code & 0xFF000000) { case 0x40000000: info.si_signo = TARGET_SIGSEGV; @@ -803,12 +775,8 @@ void cpu_loop(CPUPPCState *env) break; default: /* Let's send a regular segfault... */ - fprintf(stderr, "Invalid segfault errno (%02x)\n", - env->error_code); - if (loglevel) { - fprintf(logfile, "Invalid segfault errno (%02x)\n", - env->error_code); - } + EXCP_DUMP(env, "Invalid segfault errno (%02x)\n", + env->error_code); info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; @@ -817,10 +785,10 @@ void cpu_loop(CPUPPCState *env) info._sifields._sigfault._addr = env->nip; queue_signal(info.si_signo, &info); break; - case EXCP_ISI: - fprintf(stderr, "Invalid instruction fetch\n"); - if (loglevel) - fprintf(logfile, "Invalid instruction fetch\n"); + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n", + env->spr[SPR_DAR]); + /* XXX: check this */ switch (env->error_code & 0xFF000000) { case 0x40000000: info.si_signo = TARGET_SIGSEGV; @@ -835,12 +803,8 @@ void cpu_loop(CPUPPCState *env) break; default: /* Let's send a regular segfault... */ - fprintf(stderr, "Invalid segfault errno (%02x)\n", - env->error_code); - if (loglevel) { - fprintf(logfile, "Invalid segfault errno (%02x)\n", - env->error_code); - } + EXCP_DUMP(env, "Invalid segfault errno (%02x)\n", + env->error_code); info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; @@ -849,28 +813,24 @@ void cpu_loop(CPUPPCState *env) info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); break; - case EXCP_EXTERNAL: - /* Should not happen ! */ - fprintf(stderr, "External interruption... Stop emulation\n"); - if (loglevel) - fprintf(logfile, "External interruption... Stop emulation\n"); - abort(); - case EXCP_ALIGN: - fprintf(stderr, "Invalid unaligned memory access\n"); - if (loglevel) - fprintf(logfile, "Invalid unaligned memory access\n"); + case POWERPC_EXCP_EXTERNAL: /* External input */ + cpu_abort(env, "External interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + EXCP_DUMP(env, "Unaligned memory access\n"); + /* XXX: check this */ info.si_signo = TARGET_SIGBUS; info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); break; - case EXCP_PROGRAM: + case POWERPC_EXCP_PROGRAM: /* Program exception */ + /* XXX: check this */ switch (env->error_code & ~0xF) { - case EXCP_FP: - fprintf(stderr, "Program exception\n"); - if (loglevel) - fprintf(logfile, "Program exception\n"); + case POWERPC_EXCP_FP: + EXCP_DUMP(env, "Floating point program exception\n"); /* Set FX */ env->fpscr[7] |= 0x8; /* Finally, update FEX */ @@ -880,155 +840,138 @@ void cpu_loop(CPUPPCState *env) info.si_signo = TARGET_SIGFPE; info.si_errno = 0; switch (env->error_code & 0xF) { - case EXCP_FP_OX: + case POWERPC_EXCP_FP_OX: info.si_code = TARGET_FPE_FLTOVF; break; - case EXCP_FP_UX: + case POWERPC_EXCP_FP_UX: info.si_code = TARGET_FPE_FLTUND; break; - case EXCP_FP_ZX: - case EXCP_FP_VXZDZ: + case POWERPC_EXCP_FP_ZX: + case POWERPC_EXCP_FP_VXZDZ: info.si_code = TARGET_FPE_FLTDIV; break; - case EXCP_FP_XX: + case POWERPC_EXCP_FP_XX: info.si_code = TARGET_FPE_FLTRES; break; - case EXCP_FP_VXSOFT: + case POWERPC_EXCP_FP_VXSOFT: info.si_code = TARGET_FPE_FLTINV; break; - case EXCP_FP_VXNAN: - case EXCP_FP_VXISI: - case EXCP_FP_VXIDI: - case EXCP_FP_VXIMZ: - case EXCP_FP_VXVC: - case EXCP_FP_VXSQRT: - case EXCP_FP_VXCVI: + case POWERPC_EXCP_FP_VXNAN: + case POWERPC_EXCP_FP_VXISI: + case POWERPC_EXCP_FP_VXIDI: + case POWERPC_EXCP_FP_VXIMZ: + case POWERPC_EXCP_FP_VXVC: + case POWERPC_EXCP_FP_VXSQRT: + case POWERPC_EXCP_FP_VXCVI: info.si_code = TARGET_FPE_FLTSUB; break; default: - fprintf(stderr, "Unknown floating point exception " - "(%02x)\n", env->error_code); - if (loglevel) { - fprintf(logfile, "Unknown floating point exception " - "(%02x)\n", env->error_code & 0xF); - } + EXCP_DUMP(env, "Unknown floating point exception (%02x)\n", + env->error_code); + break; } - break; - case EXCP_INVAL: - fprintf(stderr, "Invalid instruction\n"); - if (loglevel) - fprintf(logfile, "Invalid instruction\n"); + break; + case POWERPC_EXCP_INVAL: + EXCP_DUMP(env, "Invalid instruction\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; switch (env->error_code & 0xF) { - case EXCP_INVAL_INVAL: + case POWERPC_EXCP_INVAL_INVAL: info.si_code = TARGET_ILL_ILLOPC; break; - case EXCP_INVAL_LSWX: + case POWERPC_EXCP_INVAL_LSWX: info.si_code = TARGET_ILL_ILLOPN; break; - case EXCP_INVAL_SPR: + case POWERPC_EXCP_INVAL_SPR: info.si_code = TARGET_ILL_PRVREG; break; - case EXCP_INVAL_FP: + case POWERPC_EXCP_INVAL_FP: info.si_code = TARGET_ILL_COPROC; break; default: - fprintf(stderr, "Unknown invalid operation (%02x)\n", - env->error_code & 0xF); - if (loglevel) { - fprintf(logfile, "Unknown invalid operation (%02x)\n", - env->error_code & 0xF); - } + EXCP_DUMP(env, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); info.si_code = TARGET_ILL_ILLADR; break; } break; - case EXCP_PRIV: - fprintf(stderr, "Privilege violation\n"); - if (loglevel) - fprintf(logfile, "Privilege violation\n"); + case POWERPC_EXCP_PRIV: + EXCP_DUMP(env, "Privilege violation\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; switch (env->error_code & 0xF) { - case EXCP_PRIV_OPC: + case POWERPC_EXCP_PRIV_OPC: info.si_code = TARGET_ILL_PRVOPC; break; - case EXCP_PRIV_REG: + case POWERPC_EXCP_PRIV_REG: info.si_code = TARGET_ILL_PRVREG; - break; + break; default: - fprintf(stderr, "Unknown privilege violation (%02x)\n", - env->error_code & 0xF); + EXCP_DUMP(env, "Unknown privilege violation (%02x)\n", + env->error_code & 0xF); info.si_code = TARGET_ILL_PRVOPC; break; } break; - case EXCP_TRAP: - fprintf(stderr, "Tried to call a TRAP\n"); - if (loglevel) - fprintf(logfile, "Tried to call a TRAP\n"); - abort(); + case POWERPC_EXCP_TRAP: + cpu_abort(env, "Tried to call a TRAP\n"); + break; default: /* Should not happen ! */ - fprintf(stderr, "Unknown program exception (%02x)\n", - env->error_code); - if (loglevel) { - fprintf(logfile, "Unknwon program exception (%02x)\n", - env->error_code); - } - abort(); + cpu_abort(env, "Unknown program exception (%02x)\n", + env->error_code); + break; } info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); break; - case EXCP_NO_FP: - fprintf(stderr, "No floating point allowed\n"); - if (loglevel) - fprintf(logfile, "No floating point allowed\n"); + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ + EXCP_DUMP(env, "No floating point allowed\n"); info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip - 4; queue_signal(info.si_signo, &info); break; - case EXCP_DECR: - /* Should not happen ! */ - fprintf(stderr, "Decrementer exception\n"); - if (loglevel) - fprintf(logfile, "Decrementer exception\n"); - abort(); - case EXCP_TRACE: - /* Do nothing: we use this to trace execution */ - break; - case EXCP_FP_ASSIST: - /* Should not happen ! */ - fprintf(stderr, "Floating point assist exception\n"); - if (loglevel) - fprintf(logfile, "Floating point assist exception\n"); - abort(); - case EXCP_MTMSR: - /* We reloaded the msr, just go on */ - if (msr_pr == 0) { - fprintf(stderr, "Tried to go into supervisor mode !\n"); - if (loglevel) - fprintf(logfile, "Tried to go into supervisor mode !\n"); - abort(); - } + case POWERPC_EXCP_SYSCALL: /* System call exception */ + cpu_abort(env, "Syscall exception while in user mode. " + "Aborting\n"); break; - case EXCP_BRANCH: - /* We stopped because of a jump... */ + case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ + EXCP_DUMP(env, "No APU instruction allowed\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_COPROC; + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); break; - case EXCP_INTERRUPT: - /* Don't know why this should ever happen... */ + case POWERPC_EXCP_DECR: /* Decrementer exception */ + cpu_abort(env, "Decrementer interrupt while in user mode. " + "Aborting\n"); break; - case EXCP_DEBUG: + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + cpu_abort(env, "Fix interval timer interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ + cpu_abort(env, "Watchdog timer interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DTLB: /* Data TLB error */ + cpu_abort(env, "Data TLB exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ITLB: /* Instruction TLB error */ + cpu_abort(env, "Instruction TLB exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DEBUG: /* Debug interrupt */ + /* XXX: check this */ { int sig; - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) - { + sig = gdb_handlesig(env, TARGET_SIGTRAP); + if (sig) { info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; @@ -1036,14 +979,171 @@ void cpu_loop(CPUPPCState *env) } } break; - default: - fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", - trapnr); - if (loglevel) { - fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " - "0x%02x - aborting\n", trapnr, env->error_code); +#if defined(TARGET_PPCEMB) + case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */ + EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_COPROC; + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); + break; + case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */ + cpu_abort(env, "Embedded floating-point data IRQ not handled\n"); + break; + case POWERPC_EXCP_EFPRI: /* Embedded floating-point round IRQ */ + cpu_abort(env, "Embedded floating-point round IRQ not handled\n"); + break; + case POWERPC_EXCP_EPERFM: /* Embedded performance monitor IRQ */ + cpu_abort(env, "Performance monitor exception not handled\n"); + break; + case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ + cpu_abort(env, "Doorbell interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ + cpu_abort(env, "Doorbell critical interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_RESET: /* System reset exception */ + cpu_abort(env, "Reset interrupt while in user mode. " + "Aborting\n"); + break; +#endif /* defined(TARGET_PPCEMB) */ +#if defined(TARGET_PPC64) /* PowerPC 64 */ + case POWERPC_EXCP_DSEG: /* Data segment exception */ + cpu_abort(env, "Data segment exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_ISEG: /* Instruction segment exception */ + cpu_abort(env, "Instruction segment exception " + "while in user mode. Aborting\n"); + break; +#endif /* defined(TARGET_PPC64) */ +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ + cpu_abort(env, "Hypervisor decrementer interrupt " + "while in user mode. Aborting\n"); + break; +#endif /* defined(TARGET_PPC64H) */ + case POWERPC_EXCP_TRACE: /* Trace exception */ + /* Nothing to do: + * we use this exception to emulate step-by-step execution mode. + */ + break; +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ + cpu_abort(env, "Hypervisor data storage exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HISI: /* Hypervisor instruction storage excp */ + cpu_abort(env, "Hypervisor instruction storage exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ + cpu_abort(env, "Hypervisor data segment exception " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment excp */ + cpu_abort(env, "Hypervisor instruction segment exception " + "while in user mode. Aborting\n"); + break; +#endif /* defined(TARGET_PPC64H) */ + case POWERPC_EXCP_VPU: /* Vector unavailable exception */ + EXCP_DUMP(env, "No Altivec instructions allowed\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_COPROC; + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); + break; + case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */ + cpu_abort(env, "Programable interval timer interrupt " + "while in user mode. Aborting\n"); + break; + case POWERPC_EXCP_IO: /* IO error exception */ + cpu_abort(env, "IO error exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_RUNM: /* Run mode exception */ + cpu_abort(env, "Run mode exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_EMUL: /* Emulation trap exception */ + cpu_abort(env, "Emulation trap exception not handled\n"); + break; + case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ + cpu_abort(env, "Instruction fetch TLB exception " + "while in user-mode. Aborting"); + break; + case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ + cpu_abort(env, "Data load TLB exception while in user-mode. " + "Aborting"); + break; + case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ + cpu_abort(env, "Data store TLB exception while in user-mode. " + "Aborting"); + break; + case POWERPC_EXCP_FPA: /* Floating-point assist exception */ + cpu_abort(env, "Floating-point assist exception not handled\n"); + break; + case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ + cpu_abort(env, "Instruction address breakpoint exception " + "not handled\n"); + break; + case POWERPC_EXCP_SMI: /* System management interrupt */ + cpu_abort(env, "System management interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_THERM: /* Thermal interrupt */ + cpu_abort(env, "Thermal interrupt interrupt while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_PERFM: /* Embedded performance monitor IRQ */ + cpu_abort(env, "Performance monitor exception not handled\n"); + break; + case POWERPC_EXCP_VPUA: /* Vector assist exception */ + cpu_abort(env, "Vector assist exception not handled\n"); + break; + case POWERPC_EXCP_SOFTP: /* Soft patch exception */ + cpu_abort(env, "Soft patch exception not handled\n"); + break; + case POWERPC_EXCP_MAINT: /* Maintenance exception */ + cpu_abort(env, "Maintenance exception while in user mode. " + "Aborting\n"); + break; + case POWERPC_EXCP_STOP: /* stop translation */ + /* We did invalidate the instruction cache. Go on */ + break; + case POWERPC_EXCP_BRANCH: /* branch instruction: */ + /* We just stopped because of a branch. Go on */ + break; + case POWERPC_EXCP_SYSCALL_USER: + /* system call in user-mode emulation */ + /* WARNING: + * PPC ABI uses overflow flag in cr0 to signal an error + * in syscalls. + */ +#if 0 + printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0], + env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); +#endif + env->crf[0] &= ~0x1; + ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8]); + if (ret > (uint32_t)(-515)) { + env->crf[0] |= 0x1; + ret = -ret; } - abort(); + env->gpr[3] = ret; +#if 0 + printf("syscall returned 0x%08x (%d)\n", ret, ret); +#endif + break; + default: + cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr); + break; } process_pending_signals(env); } diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 79712b0c6..57e8f358c 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -148,6 +148,127 @@ enum { POWERPC_EXCP_BOOKE, }; +/*****************************************************************************/ +/* Exception vectors definitions */ +enum { + POWERPC_EXCP_NONE = -1, + /* The 64 first entries are used by the PowerPC embedded specification */ + POWERPC_EXCP_CRITICAL = 0, /* Critical input */ + POWERPC_EXCP_MCHECK = 1, /* Machine check exception */ + POWERPC_EXCP_DSI = 2, /* Data storage exception */ + POWERPC_EXCP_ISI = 3, /* Instruction storage exception */ + POWERPC_EXCP_EXTERNAL = 4, /* External input */ + POWERPC_EXCP_ALIGN = 5, /* Alignment exception */ + POWERPC_EXCP_PROGRAM = 6, /* Program exception */ + POWERPC_EXCP_FPU = 7, /* Floating-point unavailable exception */ + POWERPC_EXCP_SYSCALL = 8, /* System call exception */ + POWERPC_EXCP_APU = 9, /* Auxiliary processor unavailable */ + POWERPC_EXCP_DECR = 10, /* Decrementer exception */ + POWERPC_EXCP_FIT = 11, /* Fixed-interval timer interrupt */ + POWERPC_EXCP_WDT = 12, /* Watchdog timer interrupt */ + POWERPC_EXCP_DTLB = 13, /* Data TLB error */ + POWERPC_EXCP_ITLB = 14, /* Instruction TLB error */ + POWERPC_EXCP_DEBUG = 15, /* Debug interrupt */ + /* Vectors 16 to 31 are reserved */ +#if defined(TARGET_PPCEMB) + POWERPC_EXCP_SPEU = 32, /* SPE/embedded floating-point unavailable */ + POWERPC_EXCP_EFPDI = 33, /* Embedded floating-point data interrupt */ + POWERPC_EXCP_EFPRI = 34, /* Embedded floating-point round interrupt */ + POWERPC_EXCP_EPERFM = 35, /* Embedded performance monitor interrupt */ + POWERPC_EXCP_DOORI = 36, /* Embedded doorbell interrupt */ + POWERPC_EXCP_DOORCI = 37, /* Embedded doorbell critical interrupt */ +#endif /* defined(TARGET_PPCEMB) */ + /* Vectors 38 to 63 are reserved */ + /* Exceptions defined in the PowerPC server specification */ + POWERPC_EXCP_RESET = 64, /* System reset exception */ +#if defined(TARGET_PPC64) /* PowerPC 64 */ + POWERPC_EXCP_DSEG = 65, /* Data segment exception */ + POWERPC_EXCP_ISEG = 66, /* Instruction segment exception */ +#endif /* defined(TARGET_PPC64) */ +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + POWERPC_EXCP_HDECR = 67, /* Hypervisor decrementer exception */ +#endif /* defined(TARGET_PPC64H) */ + POWERPC_EXCP_TRACE = 68, /* Trace exception */ +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + POWERPC_EXCP_HDSI = 69, /* Hypervisor data storage exception */ + POWERPC_EXCP_HISI = 70, /* Hypervisor instruction storage exception */ + POWERPC_EXCP_HDSEG = 71, /* Hypervisor data segment exception */ + POWERPC_EXCP_HISEG = 72, /* Hypervisor instruction segment exception */ +#endif /* defined(TARGET_PPC64H) */ + POWERPC_EXCP_VPU = 73, /* Vector unavailable exception */ + /* 40x specific exceptions */ + POWERPC_EXCP_PIT = 74, /* Programmable interval timer interrupt */ + /* 601 specific exceptions */ + POWERPC_EXCP_IO = 75, /* IO error exception */ + POWERPC_EXCP_RUNM = 76, /* Run mode exception */ + /* 602 specific exceptions */ + POWERPC_EXCP_EMUL = 77, /* Emulation trap exception */ + /* 602/603 specific exceptions */ + POWERPC_EXCP_IFTLB = 78, /* Instruction fetch TLB error */ + POWERPC_EXCP_DLTLB = 79, /* Data load TLB miss */ + POWERPC_EXCP_DSTLB = 80, /* Data store TLB miss */ + /* Exceptions available on most PowerPC */ + POWERPC_EXCP_FPA = 81, /* Floating-point assist exception */ + POWERPC_EXCP_IABR = 82, /* Instruction address breakpoint */ + POWERPC_EXCP_SMI = 83, /* System management interrupt */ + POWERPC_EXCP_PERFM = 84, /* Embedded performance monitor interrupt */ + /* 7xx/74xx specific exceptions */ + POWERPC_EXCP_THERM = 85, /* Thermal interrupt */ + /* 74xx specific exceptions */ + POWERPC_EXCP_VPUA = 86, /* Vector assist exception */ + /* 970FX specific exceptions */ + POWERPC_EXCP_SOFTP = 87, /* Soft patch exception */ + POWERPC_EXCP_MAINT = 88, /* Maintenance exception */ + /* EOL */ + POWERPC_EXCP_NB = 96, + /* Qemu exceptions: used internally during code translation */ + POWERPC_EXCP_STOP = 0x200, /* stop translation */ + POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */ + /* Qemu exceptions: special cases we want to stop translation */ + POWERPC_EXCP_SYNC = 0x202, /* context synchronizing instruction */ + POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only */ +}; + + +/* Exceptions error codes */ +enum { + /* Exception subtypes for POWERPC_EXCP_ALIGN */ + POWERPC_EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ + POWERPC_EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ + POWERPC_EXCP_ALIGN_LE = 0x03, /* Multiple little-endian access */ + POWERPC_EXCP_ALIGN_PROT = 0x04, /* Access cross protection boundary */ + POWERPC_EXCP_ALIGN_BAT = 0x05, /* Access cross a BAT/seg boundary */ + POWERPC_EXCP_ALIGN_CACHE = 0x06, /* Impossible dcbz access */ + /* Exception subtypes for POWERPC_EXCP_PROGRAM */ + /* FP exceptions */ + POWERPC_EXCP_FP = 0x10, + POWERPC_EXCP_FP_OX = 0x01, /* FP overflow */ + POWERPC_EXCP_FP_UX = 0x02, /* FP underflow */ + POWERPC_EXCP_FP_ZX = 0x03, /* FP divide by zero */ + POWERPC_EXCP_FP_XX = 0x04, /* FP inexact */ + POWERPC_EXCP_FP_VXNAN = 0x05, /* FP invalid SNaN op */ + POWERPC_EXCP_FP_VXISI = 0x06, /* FP invalid infinite subtraction */ + POWERPC_EXCP_FP_VXIDI = 0x07, /* FP invalid infinite divide */ + POWERPC_EXCP_FP_VXZDZ = 0x08, /* FP invalid zero divide */ + POWERPC_EXCP_FP_VXIMZ = 0x09, /* FP invalid infinite * zero */ + POWERPC_EXCP_FP_VXVC = 0x0A, /* FP invalid compare */ + POWERPC_EXCP_FP_VXSOFT = 0x0B, /* FP invalid operation */ + POWERPC_EXCP_FP_VXSQRT = 0x0C, /* FP invalid square root */ + POWERPC_EXCP_FP_VXCVI = 0x0D, /* FP invalid integer conversion */ + /* Invalid instruction */ + POWERPC_EXCP_INVAL = 0x20, + POWERPC_EXCP_INVAL_INVAL = 0x01, /* Invalid instruction */ + POWERPC_EXCP_INVAL_LSWX = 0x02, /* Invalid lswx instruction */ + POWERPC_EXCP_INVAL_SPR = 0x03, /* Invalid SPR access */ + POWERPC_EXCP_INVAL_FP = 0x04, /* Unimplemented mandatory fp instr */ + /* Privileged instruction */ + POWERPC_EXCP_PRIV = 0x30, + POWERPC_EXCP_PRIV_OPC = 0x01, /* Privileged operation exception */ + POWERPC_EXCP_PRIV_REG = 0x02, /* Privileged register exception */ + /* Trap */ + POWERPC_EXCP_TRAP = 0x40, +}; + /*****************************************************************************/ /* Input pins model */ enum { @@ -411,6 +532,11 @@ struct CPUPPCState { */ uint32_t irq_input_state; void **irq_inputs; + /* Exception vectors */ + target_ulong excp_vectors[POWERPC_EXCP_NB]; + target_ulong excp_prefix; + target_ulong ivor_mask; + target_ulong ivpr_mask; #endif /* Those resources are used only during code translation */ @@ -634,9 +760,9 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_BOOKE_IAC1 (0x138) #define SPR_HRMOR (0x139) #define SPR_BOOKE_IAC2 (0x139) -#define SPR_HSSR0 (0x13A) +#define SPR_HSRR0 (0x13A) #define SPR_BOOKE_IAC3 (0x13A) -#define SPR_HSSR1 (0x13B) +#define SPR_HSRR1 (0x13B) #define SPR_BOOKE_IAC4 (0x13B) #define SPR_LPCR (0x13C) #define SPR_BOOKE_DAC1 (0x13C) @@ -948,117 +1074,6 @@ enum { ACCESS_CACHE = 0x60, /* Cache manipulation */ }; -/*****************************************************************************/ -/* Exceptions */ -#define EXCP_NONE -1 -/* PowerPC hardware exceptions : exception vectors defined in PowerPC book 3 */ -#define EXCP_RESET 0x0100 /* System reset */ -#define EXCP_MACHINE_CHECK 0x0200 /* Machine check exception */ -#define EXCP_DSI 0x0300 /* Data storage exception */ -#define EXCP_DSEG 0x0380 /* Data segment exception */ -#define EXCP_ISI 0x0400 /* Instruction storage exception */ -#define EXCP_ISEG 0x0480 /* Instruction segment exception */ -#define EXCP_EXTERNAL 0x0500 /* External interruption */ -#define EXCP_ALIGN 0x0600 /* Alignment exception */ -#define EXCP_PROGRAM 0x0700 /* Program exception */ -#define EXCP_NO_FP 0x0800 /* Floating point unavailable exception */ -#define EXCP_DECR 0x0900 /* Decrementer exception */ -#define EXCP_HDECR 0x0980 /* Hypervisor decrementer exception */ -#define EXCP_SYSCALL 0x0C00 /* System call */ -#define EXCP_TRACE 0x0D00 /* Trace exception */ -#define EXCP_PERF 0x0F00 /* Performance monitor exception */ -/* Exceptions defined in PowerPC 32 bits programming environment manual */ -#define EXCP_FP_ASSIST 0x0E00 /* Floating-point assist */ -/* Implementation specific exceptions */ -/* 40x exceptions */ -#define EXCP_40x_PIT 0x1000 /* Programmable interval timer interrupt */ -#define EXCP_40x_FIT 0x1010 /* Fixed interval timer interrupt */ -#define EXCP_40x_WATCHDOG 0x1020 /* Watchdog timer exception */ -#define EXCP_40x_DTLBMISS 0x1100 /* Data TLB miss exception */ -#define EXCP_40x_ITLBMISS 0x1200 /* Instruction TLB miss exception */ -#define EXCP_40x_DEBUG 0x2000 /* Debug exception */ -/* 405 specific exceptions */ -#define EXCP_405_APU 0x0F20 /* APU unavailable exception */ -/* 440 specific exceptions */ -#define EXCP_440_CRIT 0x0100 /* Critical interrupt */ -#define EXCP_440_SPEU 0x1600 /* SPE unavailable exception */ -#define EXCP_440_SPED 0x1700 /* SPE floating-point data exception */ -#define EXCP_440_SPER 0x1800 /* SPE floating-point round exception */ -/* TLB assist exceptions (602/603) */ -#define EXCP_I_TLBMISS 0x1000 /* Instruction TLB miss */ -#define EXCP_DL_TLBMISS 0x1100 /* Data load TLB miss */ -#define EXCP_DS_TLBMISS 0x1200 /* Data store TLB miss */ -/* Breakpoint exceptions (602/603/604/620/740/745/750/755...) */ -#define EXCP_IABR 0x1300 /* Instruction address breakpoint */ -#define EXCP_SMI 0x1400 /* System management interrupt */ -/* Altivec related exceptions */ -#define EXCP_VPU 0x0F20 /* VPU unavailable exception */ -/* 601 specific exceptions */ -#define EXCP_601_IO 0x0A00 /* IO error exception */ -#define EXCP_601_RUNM 0x2000 /* Run mode exception */ -/* 602 specific exceptions */ -#define EXCP_602_WATCHDOG 0x1500 /* Watchdog exception */ -#define EXCP_602_EMUL 0x1600 /* Emulation trap exception */ -/* G2 specific exceptions */ -#define EXCP_G2_CRIT 0x0A00 /* Critical interrupt */ -/* MPC740/745/750 & IBM 750 specific exceptions */ -#define EXCP_THRM 0x1700 /* Thermal management interrupt */ -/* 74xx specific exceptions */ -#define EXCP_74xx_VPUA 0x1600 /* VPU assist exception */ -/* 970FX specific exceptions */ -#define EXCP_970_SOFTP 0x1500 /* Soft patch exception */ -#define EXCP_970_MAINT 0x1600 /* Maintenance exception */ -#define EXCP_970_THRM 0x1800 /* Thermal exception */ -#define EXCP_970_VPUA 0x1700 /* VPU assist exception */ -/* SPE related exceptions */ -#define EXCP_NO_SPE 0x0F20 /* SPE unavailable exception */ -/* End of exception vectors area */ -#define EXCP_PPC_MAX 0x4000 -/* Qemu exceptions: special cases we want to stop translation */ -#define EXCP_MTMSR 0x11000 /* mtmsr instruction: */ - /* may change privilege level */ -#define EXCP_BRANCH 0x11001 /* branch instruction */ -#define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */ - -/* Error codes */ -enum { - /* Exception subtypes for EXCP_ALIGN */ - EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ - EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ - EXCP_ALIGN_LE = 0x03, /* Multiple little-endian access */ - EXCP_ALIGN_PROT = 0x04, /* Access cross protection boundary */ - EXCP_ALIGN_BAT = 0x05, /* Access cross a BAT/seg boundary */ - EXCP_ALIGN_CACHE = 0x06, /* Impossible dcbz access */ - /* Exception subtypes for EXCP_PROGRAM */ - /* FP exceptions */ - EXCP_FP = 0x10, - EXCP_FP_OX = 0x01, /* FP overflow */ - EXCP_FP_UX = 0x02, /* FP underflow */ - EXCP_FP_ZX = 0x03, /* FP divide by zero */ - EXCP_FP_XX = 0x04, /* FP inexact */ - EXCP_FP_VXNAN = 0x05, /* FP invalid SNaN op */ - EXCP_FP_VXISI = 0x06, /* FP invalid infinite subtraction */ - EXCP_FP_VXIDI = 0x07, /* FP invalid infinite divide */ - EXCP_FP_VXZDZ = 0x08, /* FP invalid zero divide */ - EXCP_FP_VXIMZ = 0x09, /* FP invalid infinite * zero */ - EXCP_FP_VXVC = 0x0A, /* FP invalid compare */ - EXCP_FP_VXSOFT = 0x0B, /* FP invalid operation */ - EXCP_FP_VXSQRT = 0x0C, /* FP invalid square root */ - EXCP_FP_VXCVI = 0x0D, /* FP invalid integer conversion */ - /* Invalid instruction */ - EXCP_INVAL = 0x20, - EXCP_INVAL_INVAL = 0x01, /* Invalid instruction */ - EXCP_INVAL_LSWX = 0x02, /* Invalid lswx instruction */ - EXCP_INVAL_SPR = 0x03, /* Invalid SPR access */ - EXCP_INVAL_FP = 0x04, /* Unimplemented mandatory fp instr */ - /* Privileged instruction */ - EXCP_PRIV = 0x30, - EXCP_PRIV_OPC = 0x01, /* Privileged operation exception */ - EXCP_PRIV_REG = 0x02, /* Privileged register exception */ - /* Trap */ - EXCP_TRAP = 0x40, -}; - /* Hardware interruption sources: * all those exception can be raised simulteaneously */ @@ -1130,19 +1145,22 @@ enum { /* Hardware exceptions definitions */ enum { /* External hardware exception sources */ - PPC_INTERRUPT_RESET = 0, /* Reset exception */ - PPC_INTERRUPT_MCK = 1, /* Machine check exception */ - PPC_INTERRUPT_EXT = 2, /* External interrupt */ - PPC_INTERRUPT_SMI = 3, /* System management interrupt */ - PPC_INTERRUPT_CEXT = 4, /* Critical external interrupt */ - PPC_INTERRUPT_DEBUG = 5, /* External debug exception */ - PPC_INTERRUPT_THERM = 6, /* Thermal exception */ + PPC_INTERRUPT_RESET = 0, /* Reset exception */ + PPC_INTERRUPT_MCK = 1, /* Machine check exception */ + PPC_INTERRUPT_EXT = 2, /* External interrupt */ + PPC_INTERRUPT_SMI = 3, /* System management interrupt */ + PPC_INTERRUPT_CEXT = 4, /* Critical external interrupt */ + PPC_INTERRUPT_DEBUG = 5, /* External debug exception */ + PPC_INTERRUPT_THERM = 6, /* Thermal exception */ /* Internal hardware exception sources */ - PPC_INTERRUPT_DECR = 7, /* Decrementer exception */ - PPC_INTERRUPT_HDECR = 8, /* Hypervisor decrementer exception */ - PPC_INTERRUPT_PIT = 9, /* Programmable inteval timer interrupt */ - PPC_INTERRUPT_FIT = 10, /* Fixed interval timer interrupt */ - PPC_INTERRUPT_WDT = 11, /* Watchdog timer interrupt */ + PPC_INTERRUPT_DECR = 7, /* Decrementer exception */ + PPC_INTERRUPT_HDECR = 8, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT = 9, /* Programmable inteval timer interrupt */ + PPC_INTERRUPT_FIT = 10, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT = 11, /* Watchdog timer interrupt */ + PPC_INTERRUPT_CDOORBELL = 12, /* Critical doorbell interrupt */ + PPC_INTERRUPT_DOORBELL = 13, /* Doorbell interrupt */ + PPC_INTERRUPT_PERFM = 14, /* Performance monitor interrupt */ }; /*****************************************************************************/ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f27a7f50a..8b6bed1e5 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -44,10 +44,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int exception, error_code; if (rw == 2) { - exception = EXCP_ISI; + exception = POWERPC_EXCP_ISI; error_code = 0; } else { - exception = EXCP_DSI; + exception = POWERPC_EXCP_DSI; error_code = 0; if (rw) error_code |= 0x02000000; @@ -1128,6 +1128,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, ctx->prot |= PAGE_WRITE; } } + break; case POWERPC_MMU_BOOKE: ctx->prot |= PAGE_WRITE; break; @@ -1250,20 +1251,20 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, cpu_dump_state(env, logfile, fprintf, 0); #endif if (access_type == ACCESS_CODE) { - exception = EXCP_ISI; + exception = POWERPC_EXCP_ISI; switch (ret) { case -1: /* No matches in page tables or TLB */ switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: - exception = EXCP_I_TLBMISS; + exception = POWERPC_EXCP_IFTLB; env->spr[SPR_IMISS] = address; env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; error_code = 1 << 18; goto tlb_miss; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: - exception = EXCP_40x_ITLBMISS; + exception = POWERPC_EXCP_ITLB; error_code = 0; env->spr[SPR_40x_DEAR] = address; env->spr[SPR_40x_ESR] = 0x00000000; @@ -1315,24 +1316,26 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /* No code fetch is allowed in direct-store areas */ error_code = 0x10000000; break; +#if defined(TARGET_PPC64) case -5: /* No match in segment table */ - exception = EXCP_ISEG; + exception = POWERPC_EXCP_ISEG; error_code = 0; break; +#endif } } else { - exception = EXCP_DSI; + exception = POWERPC_EXCP_DSI; switch (ret) { case -1: /* No matches in page tables or TLB */ switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: if (rw == 1) { - exception = EXCP_DS_TLBMISS; + exception = POWERPC_EXCP_DSTLB; error_code = 1 << 16; } else { - exception = EXCP_DL_TLBMISS; + exception = POWERPC_EXCP_DLTLB; error_code = 0; } env->spr[SPR_DMISS] = address; @@ -1345,7 +1348,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, goto out; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: - exception = EXCP_40x_DTLBMISS; + exception = POWERPC_EXCP_DTLB; error_code = 0; env->spr[SPR_40x_DEAR] = address; if (rw) @@ -1396,8 +1399,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, switch (access_type) { case ACCESS_FLOAT: /* Floating point load/store */ - exception = EXCP_ALIGN; - error_code = EXCP_ALIGN_FP; + exception = POWERPC_EXCP_ALIGN; + error_code = POWERPC_EXCP_ALIGN_FP; break; case ACCESS_RES: /* lwarx, ldarx or srwcx. */ @@ -1409,18 +1412,20 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, break; default: printf("DSI: invalid exception (%d)\n", ret); - exception = EXCP_PROGRAM; - error_code = EXCP_INVAL | EXCP_INVAL_INVAL; + exception = POWERPC_EXCP_PROGRAM; + error_code = POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL; break; } break; +#if defined(TARGET_PPC64) case -5: /* No match in segment table */ - exception = EXCP_DSEG; + exception = POWERPC_EXCP_DSEG; error_code = 0; break; +#endif } - if (exception == EXCP_DSI && rw == 1) + if (exception == POWERPC_EXCP_DSI && rw == 1) error_code |= 0x02000000; /* Store fault address */ env->spr[SPR_DAR] = address; @@ -1830,12 +1835,14 @@ void do_compute_hflags (CPUPPCState *env) #if defined (CONFIG_USER_ONLY) void do_interrupt (CPUState *env) { - env->exception_index = -1; + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; } void ppc_hw_interrupt (CPUState *env) { - env->exception_index = -1; + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; } #else /* defined (CONFIG_USER_ONLY) */ static void dump_syscall (CPUState *env) @@ -1846,126 +1853,122 @@ static void dump_syscall (CPUState *env) env->gpr[5], env->gpr[6], env->nip); } -void do_interrupt (CPUState *env) +/* Note that this function should be greatly optimized + * when called with a constant excp, from ppc_hw_interrupt + */ +static always_inline void powerpc_excp (CPUState *env, + int excp_model, int excp) { - target_ulong msr, *srr_0, *srr_1, *asrr_0, *asrr_1; - int excp, idx; + target_ulong msr, vector; + int srr0, srr1, asrr0, asrr1; - excp = env->exception_index; - msr = do_load_msr(env); - /* The default is to use SRR0 & SRR1 to save the exception context */ - srr_0 = &env->spr[SPR_SRR0]; - srr_1 = &env->spr[SPR_SRR1]; - asrr_0 = NULL; - asrr_1 = NULL; -#if defined (DEBUG_EXCEPTIONS) - if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { - if (loglevel != 0) { - fprintf(logfile, - "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", - env->nip, excp, env->error_code); - cpu_dump_state(env, logfile, fprintf, 0); - } - } -#endif if (loglevel & CPU_LOG_INT) { fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", env->nip, excp, env->error_code); } - msr_pow = 0; - idx = -1; - /* Generate informations in save/restore registers */ + msr = do_load_msr(env); + srr0 = SPR_SRR0; + srr1 = SPR_SRR1; + asrr0 = -1; + asrr1 = -1; + msr &= ~((target_ulong)0x783F0000); switch (excp) { - /* Generic PowerPC exceptions */ - case EXCP_RESET: /* 0x0100 */ - switch (env->excp_model) { + case POWERPC_EXCP_NONE: + /* Should never happen */ + return; + case POWERPC_EXCP_CRITICAL: /* Critical input */ + msr_ri = 0; /* XXX: check this */ + switch (excp_model) { case POWERPC_EXCP_40x: - srr_0 = &env->spr[SPR_40x_SRR2]; - srr_1 = &env->spr[SPR_40x_SRR3]; + srr0 = SPR_40x_SRR2; + srr1 = SPR_40x_SRR3; break; case POWERPC_EXCP_BOOKE: - idx = 0; - srr_0 = &env->spr[SPR_BOOKE_CSRR0]; - srr_1 = &env->spr[SPR_BOOKE_CSRR1]; + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; break; - default: - if (msr_ip) - excp += 0xFFC00; - excp |= 0xFFC00000; + case POWERPC_EXCP_G2: break; + default: + goto excp_invalid; } goto store_next; - case EXCP_MACHINE_CHECK: /* 0x0200 */ - switch (env->excp_model) { + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + if (msr_me == 0) { + /* Machine check exception is not enabled */ + /* XXX: we may just stop the processor here, to allow debugging */ + excp = POWERPC_EXCP_RESET; + goto excp_reset; + } + msr_ri = 0; + msr_me = 0; +#if defined(TARGET_PPC64H) + msr_hv = 1; +#endif + /* XXX: should also have something loaded in DAR / DSISR */ + switch (excp_model) { case POWERPC_EXCP_40x: - srr_0 = &env->spr[SPR_40x_SRR2]; - srr_1 = &env->spr[SPR_40x_SRR3]; + srr0 = SPR_40x_SRR2; + srr1 = SPR_40x_SRR3; break; case POWERPC_EXCP_BOOKE: - idx = 1; - srr_0 = &env->spr[SPR_BOOKE_MCSRR0]; - srr_1 = &env->spr[SPR_BOOKE_MCSRR1]; - asrr_0 = &env->spr[SPR_BOOKE_CSRR0]; - asrr_1 = &env->spr[SPR_BOOKE_CSRR1]; - msr_ce = 0; + srr0 = SPR_BOOKE_MCSRR0; + srr1 = SPR_BOOKE_MCSRR1; + asrr0 = SPR_BOOKE_CSRR0; + asrr1 = SPR_BOOKE_CSRR1; break; default: break; } - msr_me = 0; - break; - case EXCP_DSI: /* 0x0300 */ - /* Store exception cause */ - /* data location address has been stored - * when the fault has been detected - */ - idx = 2; - msr &= ~0xFFFF0000; + goto store_next; + case POWERPC_EXCP_DSI: /* Data storage exception */ #if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) { fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } +#endif + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; #endif goto store_next; - case EXCP_ISI: /* 0x0400 */ - /* Store exception cause */ - idx = 3; - msr &= ~0xFFFF0000; - msr |= env->error_code; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ #if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) { fprintf(logfile, "ISI exception: msr=0x" ADDRX ", nip=0x" ADDRX "\n", msr, env->nip); } #endif + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + msr |= env->error_code; goto store_next; - case EXCP_EXTERNAL: /* 0x0500 */ - idx = 4; + case POWERPC_EXCP_EXTERNAL: /* External input */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes0 == 1) + msr_hv = 1; +#endif goto store_next; - case EXCP_ALIGN: /* 0x0600 */ - if (likely(env->excp_model != POWERPC_EXCP_601)) { - /* Store exception cause */ - idx = 5; - /* Get rS/rD and rA from faulting opcode */ - env->spr[SPR_DSISR] |= - (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; - /* data location address has been stored - * when the fault has been detected - */ - } else { - /* IO error exception on PowerPC 601 */ - /* XXX: TODO */ - cpu_abort(env, - "601 IO error exception is not implemented yet !\n"); - } + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + /* XXX: this is false */ + /* Get rS/rD and rA from faulting opcode */ + env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; goto store_current; - case EXCP_PROGRAM: /* 0x0700 */ - idx = 6; - msr &= ~0xFFFF0000; + case POWERPC_EXCP_PROGRAM: /* Program exception */ switch (env->error_code & ~0xF) { - case EXCP_FP: - if (msr_fe0 == 0 && msr_fe1 == 0) { + case POWERPC_EXCP_FP: + if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { #if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) { fprintf(logfile, "Ignore floating point exception\n"); @@ -1973,6 +1976,11 @@ void do_interrupt (CPUState *env) #endif return; } + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif msr |= 0x00100000; /* Set FX */ env->fpscr[7] |= 0x8; @@ -1980,39 +1988,59 @@ void do_interrupt (CPUState *env) if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) env->fpscr[7] |= 0x4; + if (msr_fe0 != msr_fe1) { + msr |= 0x00010000; + goto store_current; + } break; - case EXCP_INVAL: + case POWERPC_EXCP_INVAL: #if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) { fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n", env->nip); } +#endif + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; #endif msr |= 0x00080000; break; - case EXCP_PRIV: + case POWERPC_EXCP_PRIV: + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif msr |= 0x00040000; break; - case EXCP_TRAP: - idx = 15; + case POWERPC_EXCP_TRAP: + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif msr |= 0x00020000; break; default: /* Should never occur */ + cpu_abort(env, "Invalid program exception %d. Aborting\n", + env->error_code); break; } - msr |= 0x00010000; - goto store_current; - case EXCP_NO_FP: /* 0x0800 */ - idx = 7; - msr &= ~0xFFFF0000; - goto store_current; - case EXCP_DECR: goto store_next; - case EXCP_SYSCALL: /* 0x0C00 */ - idx = 8; + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + goto store_current; + case POWERPC_EXCP_SYSCALL: /* System call exception */ /* NOTE: this is a temporary hack to support graphics OSI calls from the MOL driver */ + /* XXX: To be removed */ if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && env->osi_call) { if (env->osi_call(env) != 0) @@ -2021,166 +2049,254 @@ void do_interrupt (CPUState *env) if (loglevel & CPU_LOG_INT) { dump_syscall(env); } + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) + msr_hv = 1; +#endif + goto store_next; + case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ + msr_ri = 0; + goto store_current; + case POWERPC_EXCP_DECR: /* Decrementer exception */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + goto store_next; + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + /* FIT on 4xx */ +#if defined (DEBUG_EXCEPTIONS) + if (loglevel != 0) + fprintf(logfile, "FIT exception\n"); +#endif + msr_ri = 0; /* XXX: check this */ goto store_next; - case EXCP_TRACE: /* 0x0D00 */ + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ +#if defined (DEBUG_EXCEPTIONS) + if (loglevel != 0) + fprintf(logfile, "WDT exception\n"); +#endif + switch (excp_model) { + case POWERPC_EXCP_BOOKE: + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; + break; + default: + break; + } + msr_ri = 0; /* XXX: check this */ goto store_next; - case EXCP_PERF: /* 0x0F00 */ + case POWERPC_EXCP_DTLB: /* Data TLB error */ + msr_ri = 0; /* XXX: check this */ + goto store_next; + case POWERPC_EXCP_ITLB: /* Instruction TLB error */ + msr_ri = 0; /* XXX: check this */ + goto store_next; + case POWERPC_EXCP_DEBUG: /* Debug interrupt */ + switch (excp_model) { + case POWERPC_EXCP_BOOKE: + srr0 = SPR_BOOKE_DSRR0; + srr1 = SPR_BOOKE_DSRR1; + asrr0 = SPR_BOOKE_CSRR0; + asrr1 = SPR_BOOKE_CSRR1; + break; + default: + break; + } /* XXX: TODO */ - cpu_abort(env, - "Performance counter exception is not implemented yet !\n"); + cpu_abort(env, "Debug exception is not implemented yet !\n"); goto store_next; - /* 32 bits PowerPC specific exceptions */ - case EXCP_FP_ASSIST: /* 0x0E00 */ +#if defined(TARGET_PPCEMB) + case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ + msr_ri = 0; /* XXX: check this */ + goto store_current; + case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ /* XXX: TODO */ - cpu_abort(env, "Floating point assist exception " + cpu_abort(env, "Embedded floating point data exception " "is not implemented yet !\n"); goto store_next; - /* 64 bits PowerPC exceptions */ - case EXCP_DSEG: /* 0x0380 */ + case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ /* XXX: TODO */ - cpu_abort(env, "Data segment exception is not implemented yet !\n"); + cpu_abort(env, "Embedded floating point round exception " + "is not implemented yet !\n"); goto store_next; - case EXCP_ISEG: /* 0x0480 */ + case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ + msr_ri = 0; /* XXX: TODO */ cpu_abort(env, - "Instruction segment exception is not implemented yet !\n"); + "Performance counter exception is not implemented yet !\n"); goto store_next; - case EXCP_HDECR: /* 0x0980 */ + case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ /* XXX: TODO */ - cpu_abort(env, "Hypervisor decrementer exception is not implemented " - "yet !\n"); + cpu_abort(env, + "Embedded doorbell interrupt is not implemented yet !\n"); goto store_next; - /* Implementation specific exceptions */ - case 0x0A00: - switch (env->excp_model) { - case POWERPC_EXCP_G2: - /* Critical interrupt on G2 */ - /* XXX: TODO */ - cpu_abort(env, "G2 critical interrupt is not implemented yet !\n"); - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x0A00 !\n"); + case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ + switch (excp_model) { + case POWERPC_EXCP_BOOKE: + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; break; - } - return; - case 0x0F20: - idx = 9; - switch (env->excp_model) { - case POWERPC_EXCP_40x: - /* APU unavailable on 405 */ - /* XXX: TODO */ - cpu_abort(env, - "APU unavailable exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_74xx: - /* Altivec unavailable */ - /* XXX: TODO */ - cpu_abort(env, "Altivec unavailable exception " - "is not implemented yet !\n"); - goto store_next; default: - cpu_abort(env, "Invalid exception 0x0F20 !\n"); break; } - return; - case 0x1000: - idx = 10; - switch (env->excp_model) { - case POWERPC_EXCP_40x: - /* PIT on 4xx */ - msr &= ~0xFFFF0000; + /* XXX: TODO */ + cpu_abort(env, "Embedded doorbell critical interrupt " + "is not implemented yet !\n"); + goto store_next; +#endif /* defined(TARGET_PPCEMB) */ + case POWERPC_EXCP_RESET: /* System reset exception */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + msr_hv = 1; +#endif + excp_reset: + goto store_next; +#if defined(TARGET_PPC64) + case POWERPC_EXCP_DSEG: /* Data segment exception */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + /* XXX: TODO */ + cpu_abort(env, "Data segment exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_ISEG: /* Instruction segment exception */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + /* XXX: TODO */ + cpu_abort(env, + "Instruction segment exception is not implemented yet !\n"); + goto store_next; +#endif /* defined(TARGET_PPC64) */ +#if defined(TARGET_PPC64H) + case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSSR1; + msr_hv = 1; + goto store_next; +#endif + case POWERPC_EXCP_TRACE: /* Trace exception */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + goto store_next; +#if defined(TARGET_PPC64H) + case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSSR1; + msr_hv = 1; + goto store_next; + case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSSR1; + msr_hv = 1; + /* XXX: TODO */ + cpu_abort(env, "Hypervisor instruction storage exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSSR1; + msr_hv = 1; + goto store_next; + case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSSR1; + msr_hv = 1; + goto store_next; +#endif /* defined(TARGET_PPC64H) */ + case POWERPC_EXCP_VPU: /* Vector unavailable exception */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + goto store_current; + case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ #if defined (DEBUG_EXCEPTIONS) - if (loglevel != 0) - fprintf(logfile, "PIT exception\n"); + if (loglevel != 0) + fprintf(logfile, "PIT exception\n"); +#endif + msr_ri = 0; /* XXX: check this */ + goto store_next; + case POWERPC_EXCP_IO: /* IO error exception */ + /* XXX: TODO */ + cpu_abort(env, "601 IO error exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_RUNM: /* Run mode exception */ + /* XXX: TODO */ + cpu_abort(env, "601 run mode exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_EMUL: /* Emulation trap exception */ + /* XXX: TODO */ + cpu_abort(env, "602 emulation trap exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ + msr_ri = 0; /* XXX: check this */ +#if defined(TARGET_PPC64H) /* XXX: check this */ + if (lpes1 == 0) + msr_hv = 1; #endif - goto store_next; + switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: case POWERPC_EXCP_603E: case POWERPC_EXCP_G2: - /* ITLBMISS on 602/603 */ - goto store_gprs; + goto tlb_miss_tgpr; case POWERPC_EXCP_7x5: - /* ITLBMISS on 745/755 */ goto tlb_miss; default: - cpu_abort(env, "Invalid exception 0x1000 !\n"); - break; - } - return; - case 0x1010: - idx = 11; - switch (env->excp_model) { - case POWERPC_EXCP_40x: - /* FIT on 4xx */ - msr &= ~0xFFFF0000; -#if defined (DEBUG_EXCEPTIONS) - if (loglevel != 0) - fprintf(logfile, "FIT exception\n"); -#endif - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x1010 !\n"); + cpu_abort(env, "Invalid instruction TLB miss exception\n"); break; } - return; - case 0x1020: - idx = 12; - switch (env->excp_model) { - case POWERPC_EXCP_40x: - /* Watchdog on 4xx */ - msr &= ~0xFFFF0000; -#if defined (DEBUG_EXCEPTIONS) - if (loglevel != 0) - fprintf(logfile, "WDT exception\n"); + break; + case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ + msr_ri = 0; /* XXX: check this */ +#if defined(TARGET_PPC64H) /* XXX: check this */ + if (lpes1 == 0) + msr_hv = 1; #endif - goto store_next; - case POWERPC_EXCP_BOOKE: - srr_0 = &env->spr[SPR_BOOKE_CSRR0]; - srr_1 = &env->spr[SPR_BOOKE_CSRR1]; - break; - default: - cpu_abort(env, "Invalid exception 0x1020 !\n"); - break; - } - return; - case 0x1100: - idx = 13; - switch (env->excp_model) { - case POWERPC_EXCP_40x: - /* DTLBMISS on 4xx */ - msr &= ~0xFFFF0000; - goto store_next; + switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: case POWERPC_EXCP_603E: case POWERPC_EXCP_G2: - /* DLTLBMISS on 602/603 */ - goto store_gprs; + goto tlb_miss_tgpr; case POWERPC_EXCP_7x5: - /* DLTLBMISS on 745/755 */ goto tlb_miss; default: - cpu_abort(env, "Invalid exception 0x1100 !\n"); + cpu_abort(env, "Invalid data load TLB miss exception\n"); break; } - return; - case 0x1200: - idx = 14; - switch (env->excp_model) { - case POWERPC_EXCP_40x: - /* ITLBMISS on 4xx */ - msr &= ~0xFFFF0000; - goto store_next; + break; + case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ + msr_ri = 0; /* XXX: check this */ +#if defined(TARGET_PPC64H) /* XXX: check this */ + if (lpes1 == 0) + msr_hv = 1; +#endif + switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: case POWERPC_EXCP_603E: case POWERPC_EXCP_G2: - /* DSTLBMISS on 602/603 */ - store_gprs: + tlb_miss_tgpr: /* Swap temporary saved registers with GPRs */ swap_gpr_tgpr(env); msr_tgpr = 1; + goto tlb_miss; + case POWERPC_EXCP_7x5: + tlb_miss: #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { const unsigned char *es; @@ -2207,183 +2323,81 @@ void do_interrupt (CPUState *env) env->error_code); } #endif - goto tlb_miss; - case POWERPC_EXCP_7x5: - /* DSTLBMISS on 745/755 */ - tlb_miss: - msr &= ~0xF83F0000; msr |= env->crf[0] << 28; msr |= env->error_code; /* key, D/I, S/L bits */ /* Set way using a LRU mechanism */ msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x1200 !\n"); - break; - } - return; - case 0x1300: - switch (env->excp_model) { - case POWERPC_EXCP_601: - case POWERPC_EXCP_602: - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - case POWERPC_EXCP_604: - case POWERPC_EXCP_7x0: - case POWERPC_EXCP_7x5: - /* IABR on 6xx/7xx */ - /* XXX: TODO */ - cpu_abort(env, "IABR exception is not implemented yet !\n"); - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x1300 !\n"); - break; - } - return; - case 0x1400: - switch (env->excp_model) { - case POWERPC_EXCP_601: - case POWERPC_EXCP_602: - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - case POWERPC_EXCP_604: - case POWERPC_EXCP_7x0: - case POWERPC_EXCP_7x5: - /* SMI on 6xx/7xx */ - /* XXX: TODO */ - cpu_abort(env, "SMI exception is not implemented yet !\n"); - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x1400 !\n"); - break; - } - return; - case 0x1500: - switch (env->excp_model) { - case POWERPC_EXCP_602: - /* Watchdog on 602 */ - /* XXX: TODO */ - cpu_abort(env, - "602 watchdog exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_970: - /* Soft patch exception on 970 */ - /* XXX: TODO */ - cpu_abort(env, - "970 soft-patch exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_74xx: - /* VPU assist on 74xx */ - /* XXX: TODO */ - cpu_abort(env, "VPU assist exception is not implemented yet !\n"); - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x1500 !\n"); - break; - } - return; - case 0x1600: - switch (env->excp_model) { - case POWERPC_EXCP_602: - /* Emulation trap on 602 */ - /* XXX: TODO */ - cpu_abort(env, "602 emulation trap exception " - "is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_970: - /* Maintenance exception on 970 */ - /* XXX: TODO */ - cpu_abort(env, - "970 maintenance exception is not implemented yet !\n"); - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x1600 !\n"); - break; - } - return; - case 0x1700: - switch (env->excp_model) { - case POWERPC_EXCP_7x0: - case POWERPC_EXCP_7x5: - /* Thermal management interrupt on G3 */ - /* XXX: TODO */ - cpu_abort(env, "G3 thermal management exception " - "is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_970: - /* VPU assist on 970 */ - /* XXX: TODO */ - cpu_abort(env, - "970 VPU assist exception is not implemented yet !\n"); - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x1700 !\n"); - break; - } - return; - case 0x1800: - switch (env->excp_model) { - case POWERPC_EXCP_970: - /* Thermal exception on 970 */ - /* XXX: TODO */ - cpu_abort(env, "970 thermal management exception " - "is not implemented yet !\n"); - goto store_next; - default: - cpu_abort(env, "Invalid exception 0x1800 !\n"); - break; - } - return; - case 0x2000: - switch (env->excp_model) { - case POWERPC_EXCP_40x: - /* DEBUG on 4xx */ - /* XXX: TODO */ - cpu_abort(env, "40x debug exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_601: - /* Run mode exception on 601 */ - /* XXX: TODO */ - cpu_abort(env, - "601 run mode exception is not implemented yet !\n"); - goto store_next; - case POWERPC_EXCP_BOOKE: - srr_0 = &env->spr[SPR_BOOKE_CSRR0]; - srr_1 = &env->spr[SPR_BOOKE_CSRR1]; break; default: - cpu_abort(env, "Invalid exception 0x1800 !\n"); + cpu_abort(env, "Invalid data store TLB miss exception\n"); break; } - return; - /* Other exceptions */ - /* Qemu internal exceptions: - * we should never come here with those values: abort execution - */ + goto store_next; + case POWERPC_EXCP_FPA: /* Floating-point assist exception */ + /* XXX: TODO */ + cpu_abort(env, "Floating point assist exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ + /* XXX: TODO */ + cpu_abort(env, "IABR exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_SMI: /* System management interrupt */ + /* XXX: TODO */ + cpu_abort(env, "SMI exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_THERM: /* Thermal interrupt */ + /* XXX: TODO */ + cpu_abort(env, "Thermal management exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ + msr_ri = 0; +#if defined(TARGET_PPC64H) + if (lpes1 == 0) + msr_hv = 1; +#endif + /* XXX: TODO */ + cpu_abort(env, + "Performance counter exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_VPUA: /* Vector assist exception */ + /* XXX: TODO */ + cpu_abort(env, "VPU assist exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_SOFTP: /* Soft patch exception */ + /* XXX: TODO */ + cpu_abort(env, + "970 soft-patch exception is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_MAINT: /* Maintenance exception */ + /* XXX: TODO */ + cpu_abort(env, + "970 maintenance exception is not implemented yet !\n"); + goto store_next; default: - cpu_abort(env, "Invalid exception: code %d (%04x)\n", excp, excp); - return; + excp_invalid: + cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp); + break; store_current: /* save current instruction location */ - *srr_0 = env->nip - 4; + env->spr[srr0] = env->nip - 4; break; store_next: /* save next instruction location */ - *srr_0 = env->nip; + env->spr[srr0] = env->nip; break; } - /* Save msr */ - *srr_1 = msr; - if (asrr_0 != NULL) - *asrr_0 = *srr_0; - if (asrr_1 != NULL) - *asrr_1 = *srr_1; + /* Save MSR */ + env->spr[srr1] = msr; + /* If any alternate SRR register are defined, duplicate saved values */ + if (asrr0 != -1) + env->spr[asrr0] = env->spr[srr0]; + if (asrr1 != -1) + env->spr[asrr1] = env->spr[srr1]; /* If we disactivated any translation, flush TLBs */ - if (msr_ir || msr_dr) { + if (msr_ir || msr_dr) tlb_flush(env, 1); - } /* reload MSR with correct bits */ msr_ee = 0; msr_pr = 0; @@ -2394,37 +2408,42 @@ void do_interrupt (CPUState *env) msr_fe1 = 0; msr_ir = 0; msr_dr = 0; - msr_ri = 0; +#if 0 /* Fix this: not on all targets */ + msr_pmm = 0; +#endif msr_le = msr_ile; - if (env->excp_model == POWERPC_EXCP_BOOKE) { - msr_cm = msr_icm; - if (idx == -1 || (idx >= 16 && idx < 32)) { - cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n", - excp, excp, idx); - } + do_compute_hflags(env); + /* Jump to handler */ + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1) { + cpu_abort(env, "Raised an exception without defined vector %d\n", + excp); + } + vector |= env->excp_prefix; #if defined(TARGET_PPC64) - if (msr_cm) - env->nip = (uint64_t)env->spr[SPR_BOOKE_IVPR]; - else -#endif - env->nip = (uint32_t)env->spr[SPR_BOOKE_IVPR]; - if (idx < 16) - env->nip |= env->spr[SPR_BOOKE_IVOR0 + idx]; - else if (idx < 38) - env->nip |= env->spr[SPR_BOOKE_IVOR32 + idx - 32]; + if (excp_model == POWERPC_EXCP_BOOKE) { + msr_cm = msr_icm; + if (!msr_cm) + vector = (uint32_t)vector; } else { msr_sf = msr_isf; - env->nip = excp; + if (!msr_sf) + vector = (uint32_t)vector; } - do_compute_hflags(env); - /* Jump to handler */ - env->exception_index = EXCP_NONE; +#endif + env->nip = vector; + /* Reset exception state */ + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; } -void ppc_hw_interrupt (CPUPPCState *env) +void do_interrupt (CPUState *env) { - int raised = 0; + powerpc_excp(env, env->excp_model, env->exception_index); +} +void ppc_hw_interrupt (CPUPPCState *env) +{ #if 1 if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n", @@ -2432,82 +2451,125 @@ void ppc_hw_interrupt (CPUPPCState *env) env->interrupt_request, msr_me, msr_ee); } #endif - /* Raise it */ + /* External reset */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { - /* External reset / critical input */ - /* XXX: critical input should be handled another way. - * This code is not correct ! - */ - env->exception_index = EXCP_RESET; env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); - raised = 1; - } - if (raised == 0 && msr_me != 0) { - /* Machine check exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { - env->exception_index = EXCP_MACHINE_CHECK; - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); - raised = 1; - } + powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET); + return; + } + /* Machine check exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK); + return; } - if (raised == 0 && msr_ee != 0) { -#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ +#if 0 /* TODO */ + /* External debug exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG); + return; + } +#endif +#if defined(TARGET_PPC64H) + if ((msr_ee != 0 || msr_hv == 0 || msr_pr == 1) & hdice != 0) { /* Hypervisor decrementer exception */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { - env->exception_index = EXCP_HDECR; env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); - raised = 1; - } else + powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR); + return; + } + } +#endif + if (msr_ce != 0) { + /* External critical interrupt */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { + /* Taking a critical external interrupt does not clear the external + * critical interrupt status + */ +#if 0 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT); #endif + powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL); + return; + } + } + if (msr_ee != 0) { + /* Watchdog timer on embedded PowerPC */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT); + return; + } +#if defined(TARGET_PPCEMB) + if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI); + return; + } +#endif +#if defined(TARGET_PPCEMB) + /* External interrupt */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { + /* Taking an external interrupt does not clear the external + * interrupt status + */ +#if 0 + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); +#endif + powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL); + return; + } +#endif + /* Fixed interval timer on embedded PowerPC */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT); + return; + } + /* Programmable interval timer on embedded PowerPC */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT); + return; + } /* Decrementer exception */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { - env->exception_index = EXCP_DECR; env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); - raised = 1; - /* Programmable interval timer on embedded PowerPC */ - } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { - env->exception_index = EXCP_40x_PIT; - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); - raised = 1; - /* Fixed interval timer on embedded PowerPC */ - } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { - env->exception_index = EXCP_40x_FIT; - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); - raised = 1; - /* Watchdog timer on embedded PowerPC */ - } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { - env->exception_index = EXCP_40x_WATCHDOG; - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); - raised = 1; + powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR); + return; + } +#if !defined(TARGET_PPCEMB) /* External interrupt */ - } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { - env->exception_index = EXCP_EXTERNAL; + if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { /* Taking an external interrupt does not clear the external * interrupt status */ #if 0 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); #endif - raised = 1; -#if 0 // TODO - /* Thermal interrupt */ - } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { - env->exception_index = EXCP_970_THRM; - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); - raised = 1; + powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL); + return; + } #endif +#if defined(TARGET_PPCEMB) + if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI); + return; } -#if 0 // TODO - /* External debug exception */ - } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { - env->exception_index = EXCP_xxx; - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); - raised = 1; #endif - } - if (raised != 0) { - env->error_code = 0; - do_interrupt(env); + if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM); + return; + } + /* Thermal interrupt */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); + powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM); + return; + } } } #endif /* !CONFIG_USER_ONLY */ @@ -2572,7 +2634,8 @@ void cpu_ppc_reset (void *opaque) env->reserve = -1; /* Be sure no exception or interrupt is pending */ env->pending_interrupts = 0; - env->exception_index = EXCP_NONE; + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; /* Flush all TLBs */ tlb_flush(env, 1); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index df00ba19c..9a79953f7 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -47,8 +47,8 @@ void do_raise_exception_err (uint32_t exception, int error_code) printf("Raise exception %3x code : %d\n", exception, error_code); #endif switch (exception) { - case EXCP_PROGRAM: - if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) + case POWERPC_EXCP_PROGRAM: + if (error_code == POWERPC_EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) return; break; default: @@ -947,7 +947,7 @@ void do_tw (int flags) ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) || ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) || ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) { - do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); } } @@ -959,7 +959,7 @@ void do_td (int flags) ((int64_t)T0 == (int64_t)T1 && (flags & 0x04)) || ((uint64_t)T0 < (uint64_t)T1 && (flags & 0x02)) || ((uint64_t)T0 > (uint64_t)T1 && (flags & 0x01))))) - do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP); } #endif @@ -1215,12 +1215,14 @@ void do_load_dcr (void) if (loglevel != 0) { fprintf(logfile, "No DCR environment\n"); } - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) { if (loglevel != 0) { fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0); } - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); } else { T0 = val; } @@ -1232,12 +1234,14 @@ void do_store_dcr (void) if (loglevel != 0) { fprintf(logfile, "No DCR environment\n"); } - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) { if (loglevel != 0) { fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0); } - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG); } } diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index f1229859f..13440817b 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -296,7 +296,9 @@ void OPPROTO glue(op_lswx, MEMSUFFIX) (void) if (likely(T1 != 0)) { if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_LSWX); } else { glue(do_lsw, MEMSUFFIX)(PARAM1); } @@ -311,7 +313,9 @@ void OPPROTO glue(op_lswx_64, MEMSUFFIX) (void) if (likely(T1 != 0)) { if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_LSWX); } else { glue(do_lsw_64, MEMSUFFIX)(PARAM1); } @@ -326,7 +330,9 @@ void OPPROTO glue(op_lswx_le, MEMSUFFIX) (void) if (likely(T1 != 0)) { if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_LSWX); } else { glue(do_lsw_le, MEMSUFFIX)(PARAM1); } @@ -341,7 +347,9 @@ void OPPROTO glue(op_lswx_le_64, MEMSUFFIX) (void) if (likely(T1 != 0)) { if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { - do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | + POWERPC_EXCP_INVAL_LSWX); } else { glue(do_lsw_le_64, MEMSUFFIX)(PARAM1); } @@ -514,7 +522,7 @@ PPC_LDF_OP_64(fs_le, ldflr); void OPPROTO glue(op_lwarx, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0); env->reserve = (uint32_t)T0; @@ -526,7 +534,7 @@ void OPPROTO glue(op_lwarx, MEMSUFFIX) (void) void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0); env->reserve = (uint64_t)T0; @@ -537,7 +545,7 @@ void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void) void OPPROTO glue(op_ldarx, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { T1 = glue(ldq, MEMSUFFIX)((uint32_t)T0); env->reserve = (uint32_t)T0; @@ -548,7 +556,7 @@ void OPPROTO glue(op_ldarx, MEMSUFFIX) (void) void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { T1 = glue(ldq, MEMSUFFIX)((uint64_t)T0); env->reserve = (uint64_t)T0; @@ -560,7 +568,7 @@ void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void) void OPPROTO glue(op_lwarx_le, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0); env->reserve = (uint32_t)T0; @@ -572,7 +580,7 @@ void OPPROTO glue(op_lwarx_le, MEMSUFFIX) (void) void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0); env->reserve = (uint64_t)T0; @@ -583,7 +591,7 @@ void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void) void OPPROTO glue(op_ldarx_le, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { T1 = glue(ld64r, MEMSUFFIX)((uint32_t)T0); env->reserve = (uint32_t)T0; @@ -594,7 +602,7 @@ void OPPROTO glue(op_ldarx_le, MEMSUFFIX) (void) void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { T1 = glue(ld64r, MEMSUFFIX)((uint64_t)T0); env->reserve = (uint64_t)T0; @@ -607,7 +615,7 @@ void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void) void OPPROTO glue(op_stwcx, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_so; @@ -624,7 +632,7 @@ void OPPROTO glue(op_stwcx, MEMSUFFIX) (void) void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_so; @@ -640,7 +648,7 @@ void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void) void OPPROTO glue(op_stdcx, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_so; @@ -656,7 +664,7 @@ void OPPROTO glue(op_stdcx, MEMSUFFIX) (void) void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_so; @@ -673,7 +681,7 @@ void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void) void OPPROTO glue(op_stwcx_le, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_so; @@ -690,7 +698,7 @@ void OPPROTO glue(op_stwcx_le, MEMSUFFIX) (void) void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_so; @@ -706,7 +714,7 @@ void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void) void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_so; @@ -722,7 +730,7 @@ void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void) void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void) { if (unlikely(T0 & 0x03)) { - do_raise_exception(EXCP_ALIGN); + do_raise_exception(POWERPC_EXCP_ALIGN); } else { if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_so; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2e5cb6bcd..dc4e75891 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -207,35 +207,44 @@ static inline void gen_update_nip (DisasContext *ctx, target_ulong nip) gen_op_update_nip(nip); } -#define RET_EXCP(ctx, excp, error) \ +#define GEN_EXCP(ctx, excp, error) \ do { \ - if ((ctx)->exception == EXCP_NONE) { \ + if ((ctx)->exception == POWERPC_EXCP_NONE) { \ gen_update_nip(ctx, (ctx)->nip); \ } \ gen_op_raise_exception_err((excp), (error)); \ ctx->exception = (excp); \ } while (0) -#define RET_INVAL(ctx) \ -RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) +#define GEN_EXCP_INVAL(ctx) \ +GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM, \ + POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL) -#define RET_PRIVOPC(ctx) \ -RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) +#define GEN_EXCP_PRIVOPC(ctx) \ +GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM, \ + POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_OPC) -#define RET_PRIVREG(ctx) \ -RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) +#define GEN_EXCP_PRIVREG(ctx) \ +GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM, \ + POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG) + +#define GEN_EXCP_NO_FP(ctx) \ +GEN_EXCP(ctx, POWERPC_EXCP_FPU, 0) + +#define GEN_EXCP_NO_AP(ctx) \ +GEN_EXCP(ctx, POWERPC_EXCP_APU, 0) /* Stop translation */ -static inline void RET_STOP (DisasContext *ctx) +static inline void GEN_STOP (DisasContext *ctx) { gen_update_nip(ctx, ctx->nip); - ctx->exception = EXCP_MTMSR; + ctx->exception = POWERPC_EXCP_STOP; } /* No need to update nip here, as execution flow will change */ -static inline void RET_CHG_FLOW (DisasContext *ctx) +static inline void GEN_SYNC (DisasContext *ctx) { - ctx->exception = EXCP_MTMSR; + ctx->exception = POWERPC_EXCP_SYNC; } #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ @@ -535,7 +544,7 @@ GEN_OPCODE_MARK(start); /* Invalid instruction */ GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE) { - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); } static opc_handler_t invalid_handler = { @@ -1550,7 +1559,7 @@ __GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B); GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_op_reset_scrfx(); \ @@ -1574,7 +1583,7 @@ _GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, type); GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_op_reset_scrfx(); \ @@ -1596,7 +1605,7 @@ _GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1); GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_op_reset_scrfx(); \ @@ -1618,7 +1627,7 @@ _GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1); GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_op_reset_scrfx(); \ @@ -1633,7 +1642,7 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_op_reset_scrfx(); \ @@ -1666,7 +1675,7 @@ GEN_FLOAT_AB(sub, 0x14, 0x000007C0); GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_reset_scrfx(); @@ -1680,7 +1689,7 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_reset_scrfx(); @@ -1723,7 +1732,7 @@ GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B); GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_reset_scrfx(); @@ -1737,7 +1746,7 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_reset_scrfx(); @@ -1755,7 +1764,7 @@ GEN_FLOAT_B(abs, 0x08, 0x08, PPC_FLOAT); GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_reset_scrfx(); @@ -1775,7 +1784,7 @@ GEN_FLOAT_B(neg, 0x08, 0x01, PPC_FLOAT); GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_load_fpscr_T0(crfS(ctx->opcode)); @@ -1787,7 +1796,7 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_load_fpscr(); @@ -1802,7 +1811,7 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) uint8_t crb; if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } crb = crbD(ctx->opcode) >> 2; @@ -1819,7 +1828,7 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) uint8_t crb; if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } crb = crbD(ctx->opcode) >> 2; @@ -1834,7 +1843,7 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_load_fpr_FT0(rB(ctx->opcode)); @@ -1847,7 +1856,7 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode)); @@ -2002,7 +2011,7 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ if (unlikely(rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode))) { \ - RET_INVAL(ctx); \ + GEN_EXCP_INVAL(ctx); \ return; \ } \ if (type == PPC_64B) \ @@ -2019,7 +2028,7 @@ GEN_HANDLER(l##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \ { \ if (unlikely(rA(ctx->opcode) == 0 || \ rA(ctx->opcode) == rD(ctx->opcode))) { \ - RET_INVAL(ctx); \ + GEN_EXCP_INVAL(ctx); \ return; \ } \ gen_addr_reg_index(ctx); \ @@ -2067,7 +2076,7 @@ GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B) if (Rc(ctx->opcode)) { if (unlikely(rA(ctx->opcode) == 0 || rA(ctx->opcode) == rD(ctx->opcode))) { - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); return; } } @@ -2098,7 +2107,7 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ if (unlikely(rA(ctx->opcode) == 0)) { \ - RET_INVAL(ctx); \ + GEN_EXCP_INVAL(ctx); \ return; \ } \ if (type == PPC_64B) \ @@ -2114,7 +2123,7 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ GEN_HANDLER(st##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \ { \ if (unlikely(rA(ctx->opcode) == 0)) { \ - RET_INVAL(ctx); \ + GEN_EXCP_INVAL(ctx); \ return; \ } \ gen_addr_reg_index(ctx); \ @@ -2152,7 +2161,7 @@ GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B) { if (Rc(ctx->opcode)) { if (unlikely(rA(ctx->opcode) == 0)) { - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); return; } } @@ -2367,7 +2376,8 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) if (unlikely(((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) || ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) { - RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); + GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX); return; } /* NIP cannot be restored if the memory exception comes from an helper */ @@ -2426,6 +2436,7 @@ GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO) /* isync */ GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM) { + GEN_STOP(ctx); } #define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])() @@ -2574,7 +2585,7 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03CF0801, PPC_MEM_SYNC) GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_addr_imm_index(ctx, 0); \ @@ -2586,11 +2597,11 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ if (unlikely(rA(ctx->opcode) == 0)) { \ - RET_INVAL(ctx); \ + GEN_EXCP_INVAL(ctx); \ return; \ } \ gen_addr_imm_index(ctx, 0); \ @@ -2603,11 +2614,11 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ if (unlikely(rA(ctx->opcode) == 0)) { \ - RET_INVAL(ctx); \ + GEN_EXCP_INVAL(ctx); \ return; \ } \ gen_addr_reg_index(ctx); \ @@ -2620,7 +2631,7 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_addr_reg_index(ctx); \ @@ -2645,7 +2656,7 @@ GEN_LDFS(fs, 0x10); GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_addr_imm_index(ctx, 0); \ @@ -2657,11 +2668,11 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ if (unlikely(rA(ctx->opcode) == 0)) { \ - RET_INVAL(ctx); \ + GEN_EXCP_INVAL(ctx); \ return; \ } \ gen_addr_imm_index(ctx, 0); \ @@ -2674,11 +2685,11 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ if (unlikely(rA(ctx->opcode) == 0)) { \ - RET_INVAL(ctx); \ + GEN_EXCP_INVAL(ctx); \ return; \ } \ gen_addr_reg_index(ctx); \ @@ -2691,7 +2702,7 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_FP, 0); \ + GEN_EXCP_NO_FP(ctx); \ return; \ } \ gen_addr_reg_index(ctx); \ @@ -2716,12 +2727,12 @@ GEN_STFS(fs, 0x14); GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT_STFIWX) { if (unlikely(!ctx->fpu_enabled)) { - RET_EXCP(ctx, EXCP_NO_FP, 0); + GEN_EXCP_NO_FP(ctx); return; } gen_addr_reg_index(ctx); /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */ - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); } /*** Branch ***/ @@ -2760,6 +2771,16 @@ static inline void gen_goto_tb (DisasContext *ctx, int n, target_ulong dest) } } +static inline void gen_setlr (DisasContext *ctx, target_ulong nip) +{ +#if defined(TARGET_PPC64) + if (ctx->sf_mode != 0 && (nip >> 32)) + gen_op_setlr_64(ctx->nip >> 32, ctx->nip); + else +#endif + gen_op_setlr(ctx->nip); +} + /* b ba bl bla */ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { @@ -2776,16 +2797,14 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) target = ctx->nip + li - 4; else target = li; - if (LK(ctx->opcode)) { #if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_setlr_64(ctx->nip >> 32, ctx->nip); - else + if (!ctx->sf_mode) + target = (uint32_t)target; #endif - gen_op_setlr(ctx->nip); - } + if (LK(ctx->opcode)) + gen_setlr(ctx, ctx->nip); gen_goto_tb(ctx, 0, target); - ctx->exception = EXCP_BRANCH; + ctx->exception = POWERPC_EXCP_BRANCH; } #define BCOND_IM 0 @@ -2810,6 +2829,10 @@ static inline void gen_bcond (DisasContext *ctx, int type) } else { target = li; } +#if defined(TARGET_PPC64) + if (!ctx->sf_mode) + target = (uint32_t)target; +#endif break; case BCOND_CTR: gen_op_movl_T1_ctr(); @@ -2819,14 +2842,8 @@ static inline void gen_bcond (DisasContext *ctx, int type) gen_op_movl_T1_lr(); break; } - if (LK(ctx->opcode)) { -#if defined(TARGET_PPC64) - if (ctx->sf_mode) - gen_op_setlr_64(ctx->nip >> 32, ctx->nip); - else -#endif - gen_op_setlr(ctx->nip); - } + if (LK(ctx->opcode)) + gen_setlr(ctx, ctx->nip); if (bo & 0x10) { /* No CR condition */ switch (bo & 0x6) { @@ -2934,7 +2951,7 @@ static inline void gen_bcond (DisasContext *ctx, int type) gen_op_debug(); gen_op_exit_tb(); } - ctx->exception = EXCP_BRANCH; + ctx->exception = POWERPC_EXCP_BRANCH; } GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW) @@ -2995,15 +3012,15 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else /* Restore CPU state */ if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_rfi(); - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } @@ -3011,26 +3028,29 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else /* Restore CPU state */ if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_rfid(); - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } #endif /* sc */ -GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) +GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW) { + uint32_t lev; + + lev = (ctx->opcode >> 5) & 0x7F; #if defined(CONFIG_USER_ONLY) - RET_EXCP(ctx, EXCP_SYSCALL_USER, 0); + GEN_EXCP(ctx, POWERPC_EXCP_SYSCALL_USER, lev); #else - RET_EXCP(ctx, EXCP_SYSCALL, 0); + GEN_EXCP(ctx, POWERPC_EXCP_SYSCALL, lev); #endif } @@ -3108,10 +3128,10 @@ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC) GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_load_msr(); @@ -3153,7 +3173,7 @@ static inline void gen_op_mfspr (DisasContext *ctx) sprn, sprn); } printf("Trying to read privileged spr %d %03x\n", sprn, sprn); - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); } } else { /* Not defined */ @@ -3162,7 +3182,8 @@ static inline void gen_op_mfspr (DisasContext *ctx) sprn, sprn); } printf("Trying to read invalid spr %d %03x\n", sprn, sprn); - RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR); } } @@ -3199,17 +3220,17 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_64B) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_update_nip(ctx, ctx->nip); gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } #endif @@ -3217,10 +3238,10 @@ GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_64B) GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_update_nip(ctx, ctx->nip); @@ -3232,7 +3253,7 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) #endif gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } @@ -3259,7 +3280,7 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) sprn, sprn); } printf("Trying to write privileged spr %d %03x\n", sprn, sprn); - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); } } else { /* Not defined */ @@ -3268,7 +3289,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) sprn, sprn); } printf("Trying to write invalid spr %d %03x\n", sprn, sprn); - RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); + GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR); } } @@ -3288,10 +3310,10 @@ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_addr_reg_index(ctx); @@ -3407,13 +3429,11 @@ static GenOpFunc *gen_op_icbi[] = { }; #endif #endif + GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) { - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); op_icbi(); - RET_STOP(ctx); } /* Optional: */ @@ -3428,10 +3448,10 @@ GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA) GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_set_T1(SR(ctx->opcode)); @@ -3444,10 +3464,10 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_load_gpr_T1(rB(ctx->opcode)); @@ -3461,16 +3481,15 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_set_T1(SR(ctx->opcode)); gen_op_store_sr(); - RET_STOP(ctx); #endif } @@ -3478,17 +3497,16 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_srli_T1(28); gen_op_store_sr(); - RET_STOP(ctx); #endif } @@ -3498,16 +3516,15 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { if (loglevel != 0) fprintf(logfile, "%s: ! supervisor\n", __func__); - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_tlbia(); - RET_STOP(ctx); #endif } @@ -3515,10 +3532,10 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_load_gpr_T0(rB(ctx->opcode)); @@ -3528,7 +3545,6 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE) else #endif gen_op_tlbie(); - RET_STOP(ctx); #endif } @@ -3536,16 +3552,16 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE) GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } /* This has no effect: it should ensure that all previous * tlbie have completed */ - RET_STOP(ctx); + GEN_STOP(ctx); #endif } @@ -3554,16 +3570,15 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC) GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { if (loglevel != 0) fprintf(logfile, "%s: ! supervisor\n", __func__); - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_slbia(); - RET_STOP(ctx); #endif } @@ -3571,15 +3586,14 @@ GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI) GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_load_gpr_T0(rB(ctx->opcode)); gen_op_slbie(); - RET_STOP(ctx); #endif } #endif @@ -4073,24 +4087,24 @@ GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR) GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC) { /* XXX: TODO */ - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); } /* esa */ GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC) { /* XXX: TODO */ - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); } /* mfrom */ GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_load_gpr_T0(rA(ctx->opcode)); @@ -4104,15 +4118,14 @@ GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC) GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_load_gpr_T0(rB(ctx->opcode)); gen_op_6xx_tlbld(); - RET_STOP(ctx); #endif } @@ -4120,15 +4133,14 @@ GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_load_gpr_T0(rB(ctx->opcode)); gen_op_6xx_tlbli(); - RET_STOP(ctx); #endif } @@ -4144,10 +4156,10 @@ GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER) { /* Cache line invalidate: privileged and treated as no-op */ #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } #endif @@ -4162,10 +4174,10 @@ GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER) GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } int ra = rA(ctx->opcode); @@ -4182,10 +4194,10 @@ GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER) GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_addr_reg_index(ctx); @@ -4197,14 +4209,14 @@ GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER) GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_POWER_rfsvc(); - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } @@ -4347,17 +4359,17 @@ GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2) GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE_EXT) { /* XXX: TODO */ - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); } /* XXX: not implemented on 440 ? */ GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE_EXT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_addr_reg_index(ctx); @@ -4368,7 +4380,6 @@ GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE_EXT) else #endif gen_op_tlbie(); - RET_STOP(ctx); #endif } @@ -4550,12 +4561,12 @@ GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C); GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else uint32_t dcrn = SPR(ctx->opcode); if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_set_T0(dcrn); @@ -4568,12 +4579,12 @@ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else uint32_t dcrn = SPR(ctx->opcode); if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_set_T0(dcrn); @@ -4587,10 +4598,10 @@ GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_load_gpr_T0(rA(ctx->opcode)); @@ -4605,10 +4616,10 @@ GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT) GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_BOOKE_EXT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVREG(ctx); + GEN_EXCP_PRIVREG(ctx); return; } gen_op_load_gpr_T0(rA(ctx->opcode)); @@ -4640,10 +4651,10 @@ GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX) GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } /* interpreted as no-op */ @@ -4654,10 +4665,10 @@ GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON) GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_addr_reg_index(ctx); @@ -4679,10 +4690,10 @@ GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT) GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } /* interpreted as no-op */ @@ -4693,10 +4704,10 @@ GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON) GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } /* interpreted as no-op */ @@ -4707,30 +4718,30 @@ GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON) GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } /* Restore CPU state */ gen_op_40x_rfci(); - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } /* Restore CPU state */ gen_op_rfci(); - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } @@ -4739,15 +4750,15 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE) GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE_EXT) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } /* Restore CPU state */ gen_op_rfdi(); - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } @@ -4755,15 +4766,15 @@ GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE_EXT) GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } /* Restore CPU state */ gen_op_rfmci(); - RET_CHG_FLOW(ctx); + GEN_SYNC(ctx); #endif } @@ -4772,10 +4783,10 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI) GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } switch (rB(ctx->opcode)) { @@ -4790,7 +4801,7 @@ GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB) gen_op_store_T0_gpr(rD(ctx->opcode)); break; default: - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); break; } #endif @@ -4800,10 +4811,10 @@ GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB) GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_addr_reg_index(ctx); @@ -4819,10 +4830,10 @@ GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB) GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } switch (rB(ctx->opcode)) { @@ -4837,7 +4848,7 @@ GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB) gen_op_4xx_tlbwe_lo(); break; default: - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); break; } #endif @@ -4848,10 +4859,10 @@ GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB) GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } switch (rB(ctx->opcode)) { @@ -4863,7 +4874,7 @@ GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) gen_op_store_T0_gpr(rD(ctx->opcode)); break; default: - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); break; } #endif @@ -4873,10 +4884,10 @@ GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_addr_reg_index(ctx); @@ -4892,10 +4903,10 @@ GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } switch (rB(ctx->opcode)) { @@ -4907,7 +4918,7 @@ GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) gen_op_440_tlbwe(rB(ctx->opcode)); break; default: - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); break; } #endif @@ -4917,15 +4928,15 @@ GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_load_gpr_T0(rD(ctx->opcode)); gen_op_wrte(); - RET_EXCP(ctx, EXCP_MTMSR, 0); + GEN_STOP(ctx); #endif } @@ -4933,15 +4944,15 @@ GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON) { #if defined(CONFIG_USER_ONLY) - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - RET_PRIVOPC(ctx); + GEN_EXCP_PRIVOPC(ctx); return; } gen_op_set_T0(ctx->opcode & 0x00010000); gen_op_wrte(); - RET_EXCP(ctx, EXCP_MTMSR, 0); + GEN_STOP(ctx); #endif } @@ -5009,7 +5020,7 @@ GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) \ /* Handler for undefined SPE opcodes */ static inline void gen_speundef (DisasContext *ctx) { - RET_INVAL(ctx); + GEN_EXCP_INVAL(ctx); } /* SPE load and stores */ @@ -5101,7 +5112,7 @@ static GenOpFunc *gen_op_spe_st##name[] = { \ static inline void gen_evl##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_addr_spe_imm_index(ctx, sh); \ @@ -5113,7 +5124,7 @@ static inline void gen_evl##name (DisasContext *ctx) \ static inline void gen_evl##name##x (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_addr_reg_index(ctx); \ @@ -5130,7 +5141,7 @@ GEN_SPE_LDX(name) static inline void gen_evst##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_addr_spe_imm_index(ctx, sh); \ @@ -5142,7 +5153,7 @@ static inline void gen_evst##name (DisasContext *ctx) \ static inline void gen_evst##name##x (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_addr_reg_index(ctx); \ @@ -5164,7 +5175,7 @@ GEN_SPEOP_ST(name, sh) static inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_op_load_gpr64_T0(rA(ctx->opcode)); \ @@ -5177,7 +5188,7 @@ static inline void gen_##name (DisasContext *ctx) \ static inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_op_load_gpr64_T0(rA(ctx->opcode)); \ @@ -5189,7 +5200,7 @@ static inline void gen_##name (DisasContext *ctx) \ static inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_op_load_gpr64_T0(rA(ctx->opcode)); \ @@ -5239,7 +5250,7 @@ static inline void gen_brinc (DisasContext *ctx) static inline void gen_##name##i (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_op_load_gpr64_T0(rB(ctx->opcode)); \ @@ -5252,7 +5263,7 @@ static inline void gen_##name##i (DisasContext *ctx) \ static inline void gen_##name##i (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ - RET_EXCP(ctx, EXCP_NO_SPE, 0); \ + GEN_EXCP_NO_AP(ctx); \ return; \ } \ gen_op_load_gpr64_T0(rA(ctx->opcode)); \ @@ -5324,7 +5335,7 @@ GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); //// static inline void gen_evsel (DisasContext *ctx) { if (unlikely(!ctx->spe_enabled)) { - RET_EXCP(ctx, EXCP_NO_SPE, 0); + GEN_EXCP_NO_AP(ctx); return; } gen_op_load_crf_T0(ctx->opcode & 0x7); @@ -5942,7 +5953,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, nb_gen_labels = 0; ctx.nip = pc_start; ctx.tb = tb; - ctx.exception = EXCP_NONE; + ctx.exception = POWERPC_EXCP_NONE; ctx.spr_cb = env->spr_cb; #if defined(CONFIG_USER_ONLY) ctx.mem_idx = msr_le; @@ -5969,7 +5980,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, msr_se = 1; #endif /* Set env in case of segfault during code fetch */ - while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { + while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) { if (unlikely(env->nb_breakpoints > 0)) { for (j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == ctx.nip) { @@ -6038,18 +6049,18 @@ static inline int gen_intermediate_code_internal (CPUState *env, if (unlikely((ctx.opcode & handler->inval) != 0)) { if (loglevel != 0) { fprintf(logfile, "invalid bits: %08x for opcode: " - "%02x -%02x - %02x (%08x) 0x" ADDRX "\n", + "%02x - %02x - %02x (%08x) 0x" ADDRX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } else { printf("invalid bits: %08x for opcode: " - "%02x -%02x - %02x (%08x) 0x" ADDRX "\n", + "%02x - %02x - %02x (%08x) 0x" ADDRX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } - RET_INVAL(ctxp); + GEN_EXCP_INVAL(ctxp); break; } } @@ -6059,7 +6070,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, #endif /* Check trace mode exceptions */ #if 0 // XXX: buggy on embedded PowerPC - if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) || + if (unlikely((msr_be && ctx.exception == POWERPC_EXCP_BRANCH) || /* Check in single step trace mode * we need to stop except if: * - rfi, trap or syscall @@ -6068,10 +6079,13 @@ static inline int gen_intermediate_code_internal (CPUState *env, (msr_se && (ctx.nip < 0x100 || ctx.nip > 0xF00 || (ctx.nip & 0xFC) != 0x04) && - ctx.exception != EXCP_SYSCALL && - ctx.exception != EXCP_SYSCALL_USER && - ctx.exception != EXCP_TRAP))) { - RET_EXCP(ctxp, EXCP_TRACE, 0); +#if defined(CONFIG_USER_ONLY) + ctx.exception != POWERPC_EXCP_SYSCALL_USER && +#else + ctx.exception != POWERPC_EXCP_SYSCALL && +#endif + ctx.exception != POWERPC_EXCP_TRAP))) { + GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); } #endif /* if we reach a page boundary or are single stepping, stop @@ -6085,9 +6099,9 @@ static inline int gen_intermediate_code_internal (CPUState *env, break; #endif } - if (ctx.exception == EXCP_NONE) { + if (ctx.exception == POWERPC_EXCP_NONE) { gen_goto_tb(&ctx, 0, ctx.nip); - } else if (ctx.exception != EXCP_BRANCH) { + } else if (ctx.exception != POWERPC_EXCP_BRANCH) { gen_op_reset_T0(); /* Generate the return instruction */ gen_op_exit_tb(); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index e3cb18360..109dcdc25 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -192,7 +192,7 @@ static void spr_write_ibatu (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_ibatu((sprn - SPR_IBAT0U) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_ibatu_h (void *opaque, int sprn) @@ -200,7 +200,7 @@ static void spr_write_ibatu_h (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_ibatu((sprn - SPR_IBAT4U) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_ibatl (void *opaque, int sprn) @@ -208,7 +208,7 @@ static void spr_write_ibatl (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_ibatl((sprn - SPR_IBAT0L) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_ibatl_h (void *opaque, int sprn) @@ -216,7 +216,7 @@ static void spr_write_ibatl_h (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_ibatl((sprn - SPR_IBAT4L) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } /* DBAT0U...DBAT7U */ @@ -236,7 +236,7 @@ static void spr_write_dbatu (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_dbatu((sprn - SPR_DBAT0U) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_dbatu_h (void *opaque, int sprn) @@ -244,7 +244,7 @@ static void spr_write_dbatu_h (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_dbatu((sprn - SPR_DBAT4U) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_dbatl (void *opaque, int sprn) @@ -252,7 +252,7 @@ static void spr_write_dbatl (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_dbatl((sprn - SPR_DBAT0L) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_dbatl_h (void *opaque, int sprn) @@ -260,7 +260,7 @@ static void spr_write_dbatl_h (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_dbatl((sprn - SPR_DBAT4L) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } /* SDR1 */ @@ -274,7 +274,7 @@ static void spr_write_sdr1 (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_sdr1(); - RET_STOP(ctx); + GEN_STOP(ctx); } /* 64 bits PowerPC specific SPRs */ @@ -291,7 +291,7 @@ static void spr_write_asr (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_asr(); - RET_STOP(ctx); + GEN_STOP(ctx); } #endif #endif @@ -332,7 +332,7 @@ static void spr_write_601_ubatu (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_601_batu((sprn - SPR_IBAT0U) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_601_ubatl (void *opaque, int sprn) @@ -340,7 +340,7 @@ static void spr_write_601_ubatl (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_601_batl((sprn - SPR_IBAT0L) / 2); - RET_STOP(ctx); + GEN_STOP(ctx); } #endif @@ -362,7 +362,7 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn) gen_op_store_40x_dbcr0(); /* We must stop translation as we may have rebooted */ - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_40x_sler (void *opaque, int sprn) @@ -373,7 +373,7 @@ static void spr_write_40x_sler (void *opaque, int sprn) /* We must stop the translation as we may have changed * some regions endianness */ - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_booke_tcr (void *opaque, int sprn) @@ -400,7 +400,7 @@ static void spr_write_403_pbr (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_403_pb(sprn - SPR_403_PBL1); - RET_STOP(ctx); + GEN_STOP(ctx); } static void spr_write_pir (void *opaque, int sprn) @@ -2152,6 +2152,323 @@ static void gen_spr_620 (CPUPPCState *env) * ... and more (thermal management, performance counters, ...) */ +/*****************************************************************************/ +/* Exception vectors models */ +static void init_excp_4xx_real (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_PIT] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; + env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; +#endif +} + +static void init_excp_4xx_softmmu (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_PIT] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; + env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; +#endif +} + +static void init_excp_BookE (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_APU] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000; + env->excp_prefix = 0x00000000; + env->ivor_mask = 0x0000FFE0; + env->ivpr_mask = 0xFFFF0000; +#endif +} + +static void init_excp_601 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_IO] = 0x00000A00; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000; + env->excp_prefix = 0xFFF00000; +#endif +} + +static void init_excp_602 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_FPA] = 0x00000E00; + env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500; + env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600; + env->excp_prefix = 0xFFF00000; +#endif +} + +static void init_excp_603 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; +#endif +} + +static void init_excp_G2 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000A00; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; +#endif +} + +static void init_excp_604 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; +#endif +} + +#if defined (TODO) +static void init_excp_620 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_FPA] = 0x00000E00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; +#endif +} +#endif /* defined (TODO) */ + +static void init_excp_7x0 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; +#endif +} + +static void init_excp_750FX (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; +#endif +} + +static void init_excp_7400 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; +#endif +} + +#if defined (TODO) +static void init_excp_7450 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; + env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; +#endif +} +#endif /* defined (TODO) */ + +#if defined (TARGET_PPC64) +static void init_excp_970 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + env->excp_vectors[POWERPC_EXCP_HDECR] = 0x00000980; +#endif + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; + env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; +#endif +} +#endif + /*****************************************************************************/ /* PowerPC implementations definitions */ @@ -2183,6 +2500,7 @@ static void init_proc_401 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + init_excp_4xx_real(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2218,6 +2536,7 @@ static void init_proc_401x2 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_4xx_softmmu(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2234,8 +2553,9 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) -static void init_proc_401x2 (CPUPPCState *env) +static void init_proc_401x3 (CPUPPCState *env) { + init_excp_4xx_softmmu(env); } #endif /* TODO */ @@ -2271,6 +2591,7 @@ static void init_proc_IOP480 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_4xx_softmmu(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2291,6 +2612,7 @@ static void init_proc_403 (CPUPPCState *env) gen_spr_401_403(env); gen_spr_403(env); gen_spr_403_real(env); + init_excp_4xx_real(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2326,6 +2648,7 @@ static void init_proc_403GCX (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_4xx_softmmu(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2361,6 +2684,7 @@ static void init_proc_405 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_4xx_softmmu(env); /* Allocate hardware IRQ controller */ ppc405_irq_init(env); } @@ -2402,6 +2726,7 @@ static void init_proc_440EP (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2426,6 +2751,7 @@ static void init_proc_440GP (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2451,6 +2777,7 @@ static void init_proc_440x4 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } #endif /* TODO */ @@ -2492,6 +2819,7 @@ static void init_proc_440x5 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2509,6 +2837,36 @@ static void init_proc_440x5 (CPUPPCState *env) static void init_proc_460 (CPUPPCState *env) { + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + gen_spr_440(env); + spr_register(env, SPR_BOOKE_MCSR, "MCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_440_CCR1, "CCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_DCRIPR, "SPR_DCRIPR", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + init_excp_BookE(env); + /* XXX: TODO: allocate internal IRQ controller */ } #endif /* TODO */ @@ -2527,7 +2885,7 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460F (bfd_mach_ppc_403) -static void init_proc_460 (CPUPPCState *env) +static void init_proc_460F (CPUPPCState *env) { /* Time base */ gen_tbl(env); @@ -2557,6 +2915,7 @@ static void init_proc_460 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } #endif /* TODO */ @@ -2578,6 +2937,7 @@ static void init_proc_460 (CPUPPCState *env) static void init_proc_BookE (CPUPPCState *env) { + init_excp_BookE(env); } #endif /* TODO */ @@ -2610,6 +2970,7 @@ static void init_proc_e500 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } #endif /* TODO */ @@ -2678,6 +3039,7 @@ static void init_proc_601 (CPUPPCState *env) env->nb_ways = 2; env->id_tlbs = 0; env->id_tlbs = 0; + init_excp_601(env); /* XXX: TODO: allocate internal IRQ controller */ } @@ -2712,6 +3074,7 @@ static void init_proc_602 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_602(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -2744,6 +3107,7 @@ static void init_proc_603 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_603(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -2781,6 +3145,7 @@ static void init_proc_603E (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_603(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -2820,6 +3185,7 @@ static void init_proc_G2 (CPUPPCState *env) gen_low_BATs(env); gen_high_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_G2(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -2859,6 +3225,7 @@ static void init_proc_G2LE (CPUPPCState *env) gen_low_BATs(env); gen_high_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_G2(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -2890,6 +3257,7 @@ static void init_proc_604 (CPUPPCState *env) 0x00000000); /* Memory management */ gen_low_BATs(env); + init_excp_604(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -2923,6 +3291,7 @@ static void init_proc_7x0 (CPUPPCState *env) 0x00000000); /* Memory management */ gen_low_BATs(env); + init_excp_7x0(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -2963,6 +3332,7 @@ static void init_proc_750fx (CPUPPCState *env) gen_low_BATs(env); /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ gen_high_BATs(env); + init_excp_750FX(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -3038,6 +3408,7 @@ static void init_proc_7400 (CPUPPCState *env) gen_spr_thrm(env); /* Memory management */ gen_low_BATs(env); + init_excp_7400(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -3076,6 +3447,7 @@ static void init_proc_7410 (CPUPPCState *env) 0x00000000); /* Memory management */ gen_low_BATs(env); + init_excp_7400(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -3201,6 +3573,7 @@ static void init_proc_7450 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_74xx_soft_tlb(env); + init_excp_7450(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -3297,6 +3670,7 @@ static void init_proc_7445 (CPUPPCState *env) gen_low_BATs(env); gen_high_BATs(env); gen_74xx_soft_tlb(env); + init_excp_7450(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -3395,6 +3769,7 @@ static void init_proc_7455 (CPUPPCState *env) gen_low_BATs(env); gen_high_BATs(env); gen_74xx_soft_tlb(env); + init_excp_7450(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } @@ -3439,6 +3814,7 @@ static void init_proc_970 (CPUPPCState *env) #if 0 // TODO env->slb_nr = 32; #endif + init_excp_970(env); /* Allocate hardware IRQ controller */ ppc970_irq_init(env); } @@ -3481,6 +3857,7 @@ static void init_proc_970FX (CPUPPCState *env) #if 0 // TODO env->slb_nr = 32; #endif + init_excp_970(env); /* Allocate hardware IRQ controller */ ppc970_irq_init(env); } @@ -3523,6 +3900,7 @@ static void init_proc_970GX (CPUPPCState *env) #if 0 // TODO env->slb_nr = 32; #endif + init_excp_970(env); /* Allocate hardware IRQ controller */ ppc970_irq_init(env); } @@ -3552,6 +3930,7 @@ static void init_proc_620 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_high_BATs(env); + init_excp_620(env); /* XXX: TODO: initialize internal interrupt controller */ } #endif /* TODO */ @@ -5046,7 +5425,15 @@ static ppc_def_t ppc_defs[] = { static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) { #if !defined(CONFIG_USER_ONLY) + int i; + env->irq_inputs = NULL; + /* Set all exception vectors to an invalid address */ + for (i = 0; i < POWERPC_EXCP_NB; i++) + env->excp_vectors[i] = (target_ulong)(-1ULL); + env->excp_prefix = 0x00000000; + env->ivor_mask = 0x00000000; + env->ivpr_mask = 0x00000000; #endif /* Default MMU definitions */ env->nb_BATs = 0; -- cgit v1.2.3 From 8bb1f9c51c7fa4e4ea2eeed77eb011f10b6f72c6 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 13:12:58 +0000 Subject: Provision for x86_64-linux-user target: needs get_sp_from_cpustate git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3262 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/x86_64/target_signal.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/x86_64/target_signal.h b/linux-user/x86_64/target_signal.h index eb4a0bb12..f93a8d62b 100644 --- a/linux-user/x86_64/target_signal.h +++ b/linux-user/x86_64/target_signal.h @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 +static inline target_ulong get_sp_from_cpustate(CPUX86State *state) +{ + return state->regs[R_ESP]; +} + #endif /* TARGET_SIGNAL_H */ -- cgit v1.2.3 From 47c4d8f06bc53b331b899654d5e2e2642b3ce9ae Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 13:20:12 +0000 Subject: Fix PowerPC target objects dependencies git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3263 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.target b/Makefile.target index 6f54de0b4..e45b0cdc2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -624,8 +624,8 @@ translate.o: cpu.h exec-all.h disas.h endif ifeq ($(TARGET_BASE_ARCH), ppc) -op.o: op.c op_template.h op_mem.h -op_helper.o: op_helper_mem.h +op.o: op.c op_template.h op_mem.h op_helper.h +op_helper.o: op_helper.c mfrom_table.c op_helper_mem.h op_helper.h translate.o: translate.c translate_init.c endif -- cgit v1.2.3 From 58a7d32872badb7b94d2010e0100a25443e0ef77 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 13:21:37 +0000 Subject: Code provision for hypervisor timers resources, as described in PowerPC 2.04 specification. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3264 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++---- target-ppc/cpu.h | 6 ++++ 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index b3cf71b17..20ee532da 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -412,6 +412,13 @@ struct ppc_tb_t { /* Decrementer management */ uint64_t decr_next; /* Tick for next decr interrupt */ struct QEMUTimer *decr_timer; +#if defined(TARGET_PPC64H) + /* Hypervisor decrementer management */ + uint64_t hdecr_next; /* Tick for next hdecr interrupt */ + struct QEMUTimer *hdecr_timer; + uint64_t purr_load; + uint64_t purr_start; +#endif void *opaque; }; @@ -489,7 +496,7 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); } -uint32_t cpu_ppc_load_decr (CPUState *env) +static inline uint32_t _cpu_ppc_load_decr (CPUState *env, uint64_t *next) { ppc_tb_t *tb_env = env->tb_env; uint32_t decr; @@ -509,6 +516,32 @@ uint32_t cpu_ppc_load_decr (CPUState *env) return decr; } +uint32_t cpu_ppc_load_decr (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + + return _cpu_ppc_load_decr(env, &tb_env->decr_next); +} + +#if defined(TARGET_PPC64H) +uint32_t cpu_ppc_load_hdecr (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + + return _cpu_ppc_load_decr(env, &tb_env->hdecr_next); +} + +uint64_t cpu_ppc_load_purr (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t diff; + + diff = qemu_get_clock(vm_clock) - tb_env->purr_start; + + return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec); +} +#endif /* defined(TARGET_PPC64H) */ + /* When decrementer expires, * all we need to do is generate or queue a CPU exception */ @@ -523,8 +556,22 @@ static inline void cpu_ppc_decr_excp (CPUState *env) ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); } -static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, - uint32_t value, int is_excp) +static inline void cpu_ppc_hdecr_excp (CPUState *env) +{ + /* Raise it */ +#ifdef PPC_DEBUG_TB + if (loglevel != 0) { + fprintf(logfile, "raise decrementer exception\n"); + } +#endif + ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1); +} + +static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, + struct QEMUTimer *timer, + void (*raise_excp)(CPUState *), + uint32_t decr, uint32_t value, + int is_excp) { ppc_tb_t *tb_env = env->tb_env; uint64_t now, next; @@ -537,17 +584,27 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, now = qemu_get_clock(vm_clock); next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); if (is_excp) - next += tb_env->decr_next - now; + next += *nextp - now; if (next == now) next++; - tb_env->decr_next = next; + *nextp = next; /* Adjust timer */ - qemu_mod_timer(tb_env->decr_timer, next); + qemu_mod_timer(timer, next); /* If we set a negative value and the decrementer was positive, * raise an exception. */ if ((value & 0x80000000) && !(decr & 0x80000000)) - cpu_ppc_decr_excp(env); + (*raise_excp)(env); +} + + +static inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, + uint32_t value, int is_excp) +{ + ppc_tb_t *tb_env = env->tb_env; + + __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer, + &cpu_ppc_decr_excp, decr, value, is_excp); } void cpu_ppc_store_decr (CPUState *env, uint32_t value) @@ -560,6 +617,35 @@ static void cpu_ppc_decr_cb (void *opaque) _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); } +#if defined(TARGET_PPC64H) +static inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr, + uint32_t value, int is_excp) +{ + ppc_tb_t *tb_env = env->tb_env; + + __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer, + &cpu_ppc_hdecr_excp, hdecr, value, is_excp); +} + +void cpu_ppc_store_hdecr (CPUState *env, uint32_t value) +{ + _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0); +} + +static void cpu_ppc_hdecr_cb (void *opaque) +{ + _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1); +} + +void cpu_ppc_store_purr (CPUState *env, uint64_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + + tb_env->purr_load = value; + tb_env->purr_start = qemu_get_clock(vm_clock); +} +#endif /* defined(TARGET_PPC64H) */ + static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) { CPUState *env = opaque; @@ -571,6 +657,10 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) * it's not ready to handle it... */ _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); +#if defined(TARGET_PPC64H) + _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); + cpu_ppc_store_purr(env, 0x0000000000000000ULL); +#endif /* defined(TARGET_PPC64H) */ } /* Set up (once) timebase frequency (in Hz) */ @@ -584,6 +674,9 @@ clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq) env->tb_env = tb_env; /* Create new timer */ tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); +#if defined(TARGET_PPC64H) + tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env); +#endif /* defined(TARGET_PPC64H) */ cpu_ppc_set_tb_clk(env, freq); return &cpu_ppc_set_tb_clk; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 57e8f358c..21c3061f4 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -627,6 +627,12 @@ void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); uint32_t cpu_ppc_load_decr (CPUPPCState *env); void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); +#if defined(TARGET_PPC64H) +uint32_t cpu_ppc_load_hdecr (CPUPPCState *env); +void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value); +uint64_t cpu_ppc_load_purr (CPUPPCState *env); +void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value); +#endif uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env); uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env); #if !defined(CONFIG_USER_ONLY) -- cgit v1.2.3 From dee96f6ca300da3dc3bc97635d9c3d97a73b5e48 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 29 Sep 2007 15:02:38 +0000 Subject: PowerPC emulation optimization: avoid stopping translation after most SPR updates when a context-synchronization instruction is also needed. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3265 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 12 ++++++++++-- target-ppc/translate_init.c | 43 ------------------------------------------- 2 files changed, 10 insertions(+), 45 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index dc4e75891..e88cfafae 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3230,7 +3230,8 @@ GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_64B) gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - GEN_SYNC(ctx); + /* Note that mtmsr is not always defined as context-synchronizing */ + GEN_STOP(ctx); #endif } #endif @@ -3253,7 +3254,8 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) #endif gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ - GEN_SYNC(ctx); + /* Note that mtmsrd is not always defined as context-synchronizing */ + GEN_STOP(ctx); #endif } @@ -4936,6 +4938,9 @@ GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) } gen_op_load_gpr_T0(rD(ctx->opcode)); gen_op_wrte(); + /* Stop translation to have a chance to raise an exception + * if we just set msr_ee to 1 + */ GEN_STOP(ctx); #endif } @@ -4952,6 +4957,9 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON) } gen_op_set_T0(ctx->opcode & 0x00010000); gen_op_wrte(); + /* Stop translation to have a chance to raise an exception + * if we just set msr_ee to 1 + */ GEN_STOP(ctx); #endif } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 109dcdc25..53a6abf9c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -189,34 +189,22 @@ static void spr_read_ibat_h (void *opaque, int sprn) static void spr_write_ibatu (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_ibatu((sprn - SPR_IBAT0U) / 2); - GEN_STOP(ctx); } static void spr_write_ibatu_h (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_ibatu((sprn - SPR_IBAT4U) / 2); - GEN_STOP(ctx); } static void spr_write_ibatl (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_ibatl((sprn - SPR_IBAT0L) / 2); - GEN_STOP(ctx); } static void spr_write_ibatl_h (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_ibatl((sprn - SPR_IBAT4L) / 2); - GEN_STOP(ctx); } /* DBAT0U...DBAT7U */ @@ -233,34 +221,22 @@ static void spr_read_dbat_h (void *opaque, int sprn) static void spr_write_dbatu (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_dbatu((sprn - SPR_DBAT0U) / 2); - GEN_STOP(ctx); } static void spr_write_dbatu_h (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_dbatu((sprn - SPR_DBAT4U) / 2); - GEN_STOP(ctx); } static void spr_write_dbatl (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_dbatl((sprn - SPR_DBAT0L) / 2); - GEN_STOP(ctx); } static void spr_write_dbatl_h (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_dbatl((sprn - SPR_DBAT4L) / 2); - GEN_STOP(ctx); } /* SDR1 */ @@ -271,10 +247,7 @@ static void spr_read_sdr1 (void *opaque, int sprn) static void spr_write_sdr1 (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_sdr1(); - GEN_STOP(ctx); } /* 64 bits PowerPC specific SPRs */ @@ -291,7 +264,6 @@ static void spr_write_asr (void *opaque, int sprn) DisasContext *ctx = opaque; gen_op_store_asr(); - GEN_STOP(ctx); } #endif #endif @@ -329,18 +301,12 @@ static void spr_read_601_ubat (void *opaque, int sprn) static void spr_write_601_ubatu (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_601_batu((sprn - SPR_IBAT0U) / 2); - GEN_STOP(ctx); } static void spr_write_601_ubatl (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_601_batl((sprn - SPR_IBAT0L) / 2); - GEN_STOP(ctx); } #endif @@ -367,13 +333,7 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn) static void spr_write_40x_sler (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_40x_sler(); - /* We must stop the translation as we may have changed - * some regions endianness - */ - GEN_STOP(ctx); } static void spr_write_booke_tcr (void *opaque, int sprn) @@ -397,10 +357,7 @@ static void spr_read_403_pbr (void *opaque, int sprn) static void spr_write_403_pbr (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_403_pb(sprn - SPR_403_PBL1); - GEN_STOP(ctx); } static void spr_write_pir (void *opaque, int sprn) -- cgit v1.2.3 From 544540979cb8ebb4b4ca71bd8df89e5d8e7f8600 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:19:59 +0000 Subject: Less magic constants. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3266 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper.c | 54 ++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 00a6c4448..d23a45c0b 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -613,6 +613,10 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) #define FLOAT_ONE64 (0x3ffULL << 52) #define FLOAT_TWO32 (1 << 30) #define FLOAT_TWO64 (1ULL << 62) +#define FLOAT_QNAN32 0x7fbfffff +#define FLOAT_QNAN64 0x7ff7ffffffffffffULL +#define FLOAT_SNAN32 0x7fffffff +#define FLOAT_SNAN64 0x7fffffffffffffffULL /* convert MIPS rounding mode in FCR31 to IEEE library */ unsigned int ieee_rm[] = { @@ -736,7 +740,7 @@ FLOAT_OP(cvtl, d) DT2 = float64_to_int64(FDT0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(cvtl, s) { @@ -744,7 +748,7 @@ FLOAT_OP(cvtl, s) DT2 = float32_to_int64(FST0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(cvtps, pw) @@ -761,7 +765,7 @@ FLOAT_OP(cvtpw, ps) WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(cvts, d) { @@ -799,7 +803,7 @@ FLOAT_OP(cvtw, s) WT2 = float32_to_int32(FST0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(cvtw, d) { @@ -807,7 +811,7 @@ FLOAT_OP(cvtw, d) WT2 = float64_to_int32(FDT0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(roundl, d) @@ -817,7 +821,7 @@ FLOAT_OP(roundl, d) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(roundl, s) { @@ -826,7 +830,7 @@ FLOAT_OP(roundl, s) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(roundw, d) { @@ -835,7 +839,7 @@ FLOAT_OP(roundw, d) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(roundw, s) { @@ -844,7 +848,7 @@ FLOAT_OP(roundw, s) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(truncl, d) @@ -852,28 +856,28 @@ FLOAT_OP(truncl, d) DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(truncl, s) { DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(truncw, d) { WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(truncw, s) { WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status); update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(ceill, d) @@ -883,7 +887,7 @@ FLOAT_OP(ceill, d) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(ceill, s) { @@ -892,7 +896,7 @@ FLOAT_OP(ceill, s) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(ceilw, d) { @@ -901,7 +905,7 @@ FLOAT_OP(ceilw, d) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(ceilw, s) { @@ -910,7 +914,7 @@ FLOAT_OP(ceilw, s) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(floorl, d) @@ -920,7 +924,7 @@ FLOAT_OP(floorl, d) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(floorl, s) { @@ -929,7 +933,7 @@ FLOAT_OP(floorl, s) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + DT2 = FLOAT_SNAN64; } FLOAT_OP(floorw, d) { @@ -938,7 +942,7 @@ FLOAT_OP(floorw, d) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } FLOAT_OP(floorw, s) { @@ -947,7 +951,7 @@ FLOAT_OP(floorw, s) RESTORE_ROUNDING_MODE; update_fcr31(); if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + WT2 = FLOAT_SNAN32; } /* MIPS specific unary operations */ @@ -1031,7 +1035,7 @@ FLOAT_OP(name, d) \ FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status); \ update_fcr31(); \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ - FDT2 = 0x7ff7ffffffffffffULL; \ + FDT2 = FLOAT_QNAN64; \ } \ FLOAT_OP(name, s) \ { \ @@ -1039,7 +1043,7 @@ FLOAT_OP(name, s) \ FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \ update_fcr31(); \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ - FST2 = 0x7fbfffff; \ + FST2 = FLOAT_QNAN32; \ } \ FLOAT_OP(name, ps) \ { \ @@ -1048,8 +1052,8 @@ FLOAT_OP(name, ps) \ FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \ update_fcr31(); \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \ - FST2 = 0x7fbfffff; \ - FSTH2 = 0x7fbfffff; \ + FST2 = FLOAT_QNAN32; \ + FSTH2 = FLOAT_QNAN32; \ } \ } FLOAT_BINOP(add) -- cgit v1.2.3 From 671880e651e611ec32dbb978e61c0bd4bc3e180e Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:21:36 +0000 Subject: Supervisor mode implementation, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3267 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 13 +++++++--- target-mips/helper.c | 61 ++++++++++++++++++++++++-------------------- target-mips/translate_init.c | 6 ++--- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index 9ff3f08b5..b6300bd49 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -261,16 +261,21 @@ static inline void compute_hflags(CPUState *env) MIPS_HFLAG_FPU | MIPS_HFLAG_UM); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM) && - (env->CP0_Status & (1 << CP0St_UM))) - env->hflags |= MIPS_HFLAG_UM; + !(env->hflags & MIPS_HFLAG_DM)) { + if (env->CP0_Status & (1 << CP0St_UM)) + env->hflags |= MIPS_HFLAG_UM; + if (env->CP0_Status & (1 << CP0St_R0)) + env->hflags |= MIPS_HFLAG_SM; + } #ifdef TARGET_MIPS64 if (!(env->hflags & MIPS_HFLAG_UM) || (env->CP0_Status & (1 << CP0St_PX)) || (env->CP0_Status & (1 << CP0St_UX))) env->hflags |= MIPS_HFLAG_64; #endif - if ((env->CP0_Status & (1 << CP0St_CU0)) || !(env->hflags & MIPS_HFLAG_UM)) + if ((env->CP0_Status & (1 << CP0St_CU0)) || + (!(env->hflags & MIPS_HFLAG_UM) && + !(env->hflags & MIPS_HFLAG_SM))) env->hflags |= MIPS_HFLAG_CP0; if (env->CP0_Status & (1 << CP0St_CU1)) env->hflags |= MIPS_HFLAG_FPU; diff --git a/target-mips/helper.c b/target-mips/helper.c index 8e4233ed7..7424cda56 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -106,6 +106,8 @@ static int get_physical_address (CPUState *env, target_ulong *physical, { /* User mode can only access useg/xuseg */ int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM; + int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM; + int kernel_mode = !user_mode && !supervisor_mode; #ifdef TARGET_MIPS64 int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; @@ -120,14 +122,6 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } #endif -#ifdef TARGET_MIPS64 - if (user_mode && address > 0x3FFFFFFFFFFFFFFFULL) - return TLBRET_BADADDR; -#else - if (user_mode && address > 0x7FFFFFFFUL) - return TLBRET_BADADDR; -#endif - if (address <= (int32_t)0x7FFFFFFFUL) { /* useg */ if (env->CP0_Status & (1 << CP0St_ERL)) { @@ -150,16 +144,16 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } } else if (address < 0x7FFFFFFFFFFFFFFFULL) { /* xsseg */ - if (SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { + if ((supervisor_mode || kernel_mode) && + SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } } else if (address < 0xBFFFFFFFFFFFFFFFULL) { /* xkphys */ - /* XXX: check supervisor mode */ - if (KX && (address & 0x07FFFFFFFFFFFFFFULL) < 0X0000000FFFFFFFFFULL) - { + if (kernel_mode && KX && + (address & 0x07FFFFFFFFFFFFFFULL) < 0X0000000FFFFFFFFFULL) { *physical = address & 0X0000000FFFFFFFFFULL; *prot = PAGE_READ | PAGE_WRITE; } else { @@ -167,8 +161,8 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } } else if (address < 0xFFFFFFFF7FFFFFFFULL) { /* xkseg */ - /* XXX: check supervisor mode */ - if (KX && address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { + if (kernel_mode && KX && + address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; @@ -176,22 +170,35 @@ static int get_physical_address (CPUState *env, target_ulong *physical, #endif } else if (address < (int32_t)0xA0000000UL) { /* kseg0 */ - /* XXX: check supervisor mode */ - *physical = address - (int32_t)0x80000000UL; - *prot = PAGE_READ | PAGE_WRITE; + if (kernel_mode) { + *physical = address - (int32_t)0x80000000UL; + *prot = PAGE_READ | PAGE_WRITE; + } else { + ret = TLBRET_BADADDR; + } } else if (address < (int32_t)0xC0000000UL) { /* kseg1 */ - /* XXX: check supervisor mode */ - *physical = address - (int32_t)0xA0000000UL; - *prot = PAGE_READ | PAGE_WRITE; + if (kernel_mode) { + *physical = address - (int32_t)0xA0000000UL; + *prot = PAGE_READ | PAGE_WRITE; + } else { + ret = TLBRET_BADADDR; + } } else if (address < (int32_t)0xE0000000UL) { - /* kseg2 */ - ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); + /* sseg */ + if (supervisor_mode || kernel_mode) { + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); + } else { + ret = TLBRET_BADADDR; + } } else { /* kseg3 */ - /* XXX: check supervisor mode */ /* XXX: debug segment is not emulated */ - ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); + if (kernel_mode) { + ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); + } else { + ret = TLBRET_BADADDR; + } } #if 0 if (logfile) { @@ -369,7 +376,7 @@ void do_interrupt (CPUState *env) } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~MIPS_HFLAG_UM; + env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -395,7 +402,7 @@ void do_interrupt (CPUState *env) } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~MIPS_HFLAG_UM; + env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->PC[env->current_tc] = (int32_t)0xBFC00000; @@ -497,7 +504,7 @@ void do_interrupt (CPUState *env) } env->CP0_Status |= (1 << CP0St_EXL); env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~MIPS_HFLAG_UM; + env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); } env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 6bea0c4d1..b9f326656 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -141,7 +141,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, /* No DSP implemented. */ - .CP0_Status_rw_bitmask = 0x1278FF17, + .CP0_Status_rw_bitmask = 0x1278FF1F, .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, }, { @@ -156,7 +156,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, /* No DSP implemented. */ - .CP0_Status_rw_bitmask = 0x3678FF17, + .CP0_Status_rw_bitmask = 0x3678FF1F, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, @@ -173,7 +173,7 @@ static mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, /* No DSP implemented. */ - .CP0_Status_rw_bitmask = 0x3678FF17, + .CP0_Status_rw_bitmask = 0x3678FF1F, /* No DSP implemented. */ .CP0_TCStatus_rw_bitmask = (0 << CP0TCSt_TCU3) | (0 << CP0TCSt_TCU2) | (1 << CP0TCSt_TCU1) | (1 << CP0TCSt_TCU0) | -- cgit v1.2.3 From 0d78f544dede6b3cb16eda8fd3462fb0aa001a18 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:24:41 +0000 Subject: Add R2D-PLUS support, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3268 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/r2d.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 1 + vl.h | 3 +++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 hw/r2d.c diff --git a/Makefile.target b/Makefile.target index e45b0cdc2..280f3711b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -475,7 +475,7 @@ VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o ecc.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) -VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o +VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o endif ifeq ($(TARGET_BASE_ARCH), m68k) VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o diff --git a/hw/r2d.c b/hw/r2d.c new file mode 100644 index 000000000..345ef91ea --- /dev/null +++ b/hw/r2d.c @@ -0,0 +1,64 @@ +/* + * Renesas SH7751R R2D-PLUS emulation + * + * Copyright (c) 2007 Magnus Damm + * + * 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 SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ +#define SDRAM_SIZE 0x04000000 + +void r2d_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState * ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + int ret; + CPUState *env; + struct SH7750State *s; + + env = cpu_init(); + + /* Allocate memory space */ + cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0); + /* Register peripherals */ + s = sh7750_init(env); + /* Todo: register on board registers */ + { + int kernel_size; + + kernel_size = load_image(kernel_filename, phys_ram_base); + + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); + exit(1); + } + + env->pc = SDRAM_BASE | 0xa0000000; /* Start from P2 area */ + } +} + +QEMUMachine r2d_machine = { + "r2d", + "r2d-plus board", + r2d_init +}; diff --git a/vl.c b/vl.c index b2ebad968..46ce9008d 100644 --- a/vl.c +++ b/vl.c @@ -7383,6 +7383,7 @@ void register_machines(void) qemu_register_machine(&palmte_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); + qemu_register_machine(&r2d_machine); #elif defined(TARGET_ALPHA) /* XXX: TODO */ #elif defined(TARGET_M68K) diff --git a/vl.h b/vl.h index 378ed273c..ea7a05e3f 100644 --- a/vl.h +++ b/vl.h @@ -1206,6 +1206,9 @@ extern void cpu_mips_irqctrl_init (void); /* shix.c */ extern QEMUMachine shix_machine; +/* r2d.c */ +extern QEMUMachine r2d_machine; + #ifdef TARGET_PPC /* PowerPC hardware exceptions management helpers */ typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); -- cgit v1.2.3 From cd1a3f6840e9f4b57860ee0d151347e6ade73d11 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:40:09 +0000 Subject: Stand-alone TMU emulation code, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3269 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + hw/sh7750.c | 102 +--------------- hw/sh7750_regnames.c | 12 -- hw/sh7750_regs.h | 88 -------------- hw/sh_timer.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 6 + 6 files changed, 336 insertions(+), 196 deletions(-) create mode 100644 hw/sh_timer.c diff --git a/Makefile.target b/Makefile.target index 280f3711b..fd44a8120 100644 --- a/Makefile.target +++ b/Makefile.target @@ -476,6 +476,7 @@ CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o +VL_OBJS+= sh_timer.o ptimer.o endif ifeq ($(TARGET_BASE_ARCH), m68k) VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o diff --git a/hw/sh7750.c b/hw/sh7750.c index dcba14e1a..9002da31a 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -64,13 +64,6 @@ typedef struct SH7750State { uint8_t scbrr2; fifo serial2_receive_fifo; fifo serial2_transmit_fifo; - /* Timers */ - uint8_t tstr; - /* Timer 0 */ - QEMUTimer *timer0; - uint16_t tcr0; - uint32_t tcor0; - uint32_t tcnt0; /* IO ports */ uint16_t gpioic; uint32_t pctra; @@ -88,83 +81,8 @@ typedef struct SH7750State { sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ /* Cache */ uint32_t ccr; -} SH7750State; - -/********************************************************************** - Timers -**********************************************************************/ - -/* XXXXX At this time, timer0 works in underflow only mode, that is - the value of tcnt0 is read at alarm computation time and cannot - be read back by the guest OS */ - -static void start_timer0(SH7750State * s) -{ - uint64_t now, next, prescaler; - - if ((s->tcr0 & 6) == 6) { - fprintf(stderr, "rtc clock for timer 0 not supported\n"); - assert(0); - } - if ((s->tcr0 & 7) == 5) { - fprintf(stderr, "timer 0 configuration not supported\n"); - assert(0); - } - - if ((s->tcr0 & 4) == 4) - prescaler = 1024; - else - prescaler = 4 << (s->tcr0 & 3); - - now = qemu_get_clock(vm_clock); - /* XXXXX */ - next = - now + muldiv64(prescaler * s->tcnt0, ticks_per_sec, - s->periph_freq); - if (next == now) - next = now + 1; - fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next); - fprintf(stderr, "timer will underflow in %f seconds\n", - (float) (next - now) / (float) ticks_per_sec); - - qemu_mod_timer(s->timer0, next); -} - -static void timer_start_changed(SH7750State * s) -{ - if (s->tstr & SH7750_TSTR_STR0) { - start_timer0(s); - } else { - fprintf(stderr, "timer 0 is stopped\n"); - qemu_del_timer(s->timer0); - } -} - -static void timer0_cb(void *opaque) -{ - SH7750State *s = opaque; - - s->tcnt0 = (uint32_t) 0; /* XXXXX */ - if (--s->tcnt0 == (uint32_t) - 1) { - fprintf(stderr, "timer 0 underflow\n"); - s->tcnt0 = s->tcor0; - s->tcr0 |= SH7750_TCR_UNF; - if (s->tcr0 & SH7750_TCR_UNIE) { - fprintf(stderr, - "interrupt generation for timer 0 not supported\n"); - assert(0); - } - } - start_timer0(s); -} - -static void init_timers(SH7750State * s) -{ - s->tcor0 = 0xffffffff; - s->tcnt0 = 0xffffffff; - s->timer0 = qemu_new_timer(vm_clock, &timer0_cb, s); -} +} SH7750State; /********************************************************************** First serial port @@ -581,8 +499,6 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) fprintf(stderr, "Read access to refresh count register, incrementing\n"); return s->rfcr++; - case SH7750_TCR0_A7: - return s->tcr0; case SH7750_SCLSR2_A7: /* Read and clear overflow bit */ r = s->sclsr2; @@ -649,10 +565,6 @@ static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr, case SH7750_SCBRR2_A7: s->scbrr2 = mem_value; return; - case SH7750_TSTR_A7: - s->tstr = mem_value; - timer_start_changed(s); - return; case SH7750_SCSCR1_A7: s->scscr1 = mem_value; scscr1_changed(s); @@ -721,9 +633,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, case SH7750_SCSMR2_A7: s->scsmr2 = mem_value; return; - case SH7750_TCR0_A7: - s->tcr0 = mem_value; - return; case SH7750_GPIOIC_A7: s->gpioic = mem_value; if (mem_value != 0) { @@ -768,9 +677,6 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, s->portpullupb = portpullup(mem_value); portb_changed(s, temp); return; - case SH7750_TCNT0_A7: - s->tcnt0 = mem_value & 0xf; - return; case SH7750_MMUCR_A7: s->cpu->mmucr = mem_value; return; @@ -828,7 +734,11 @@ SH7750State *sh7750_init(CPUSH4State * cpu) sh7750_mem_read, sh7750_mem_write, s); cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); - init_timers(s); init_serial_ports(s); + + tmu012_init(0x1fd80000, + TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, + s->periph_freq); + tmu012_init(0x1e100000, 0, s->periph_freq); return s; } diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c index 5fcb0d6cc..6ae491771 100644 --- a/hw/sh7750_regnames.c +++ b/hw/sh7750_regnames.c @@ -42,18 +42,6 @@ static regname_t regnames[] = { REGNAME(SH7750_RMONAR_A7) REGNAME(SH7750_RCR1_A7) REGNAME(SH7750_RCR2_A7) - REGNAME(SH7750_TOCR_A7) - REGNAME(SH7750_TSTR_A7) - REGNAME(SH7750_TCOR0_A7) - REGNAME(SH7750_TCOR1_A7) - REGNAME(SH7750_TCOR2_A7) - REGNAME(SH7750_TCNT0_A7) - REGNAME(SH7750_TCNT1_A7) - REGNAME(SH7750_TCNT2_A7) - REGNAME(SH7750_TCR0_A7) - REGNAME(SH7750_TCR1_A7) - REGNAME(SH7750_TCR2_A7) - REGNAME(SH7750_TCPR2_A7) REGNAME(SH7750_BCR1_A7) REGNAME(SH7750_BCR2_A7) REGNAME(SH7750_WCR1_A7) diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h index 6b18ad2e1..85eab4312 100644 --- a/hw/sh7750_regs.h +++ b/hw/sh7750_regs.h @@ -524,94 +524,6 @@ year counters are stopped 1 - sec, min, hr, day-of-week, month, year counters operate normally */ - - -/* - * Timer Unit (TMU) - */ -/* Timer Output Control Register (byte) - TOCR */ -#define SH7750_TOCR_REGOFS 0xD80000 /* offset */ -#define SH7750_TOCR SH7750_P4_REG32(SH7750_TOCR_REGOFS) -#define SH7750_TOCR_A7 SH7750_A7_REG32(SH7750_TOCR_REGOFS) -#define SH7750_TOCR_TCOE 0x01 /* Timer Clock Pin Control: - 0 - TCLK is used as external clock - input or input capture control - 1 - TCLK is used as on-chip RTC - output clock pin */ - -/* Timer Start Register (byte) - TSTR */ -#define SH7750_TSTR_REGOFS 0xD80004 /* offset */ -#define SH7750_TSTR SH7750_P4_REG32(SH7750_TSTR_REGOFS) -#define SH7750_TSTR_A7 SH7750_A7_REG32(SH7750_TSTR_REGOFS) -#define SH7750_TSTR_STR2 0x04 /* TCNT2 performs count operations */ -#define SH7750_TSTR_STR1 0x02 /* TCNT1 performs count operations */ -#define SH7750_TSTR_STR0 0x01 /* TCNT0 performs count operations */ -#define SH7750_TSTR_STR(n) (1 << (n)) - -/* Timer Constant Register - TCOR0, TCOR1, TCOR2 */ -#define SH7750_TCOR_REGOFS(n) (0xD80008 + ((n)*12)) /* offset */ -#define SH7750_TCOR(n) SH7750_P4_REG32(SH7750_TCOR_REGOFS(n)) -#define SH7750_TCOR_A7(n) SH7750_A7_REG32(SH7750_TCOR_REGOFS(n)) -#define SH7750_TCOR0 SH7750_TCOR(0) -#define SH7750_TCOR1 SH7750_TCOR(1) -#define SH7750_TCOR2 SH7750_TCOR(2) -#define SH7750_TCOR0_A7 SH7750_TCOR_A7(0) -#define SH7750_TCOR1_A7 SH7750_TCOR_A7(1) -#define SH7750_TCOR2_A7 SH7750_TCOR_A7(2) - -/* Timer Counter Register - TCNT0, TCNT1, TCNT2 */ -#define SH7750_TCNT_REGOFS(n) (0xD8000C + ((n)*12)) /* offset */ -#define SH7750_TCNT(n) SH7750_P4_REG32(SH7750_TCNT_REGOFS(n)) -#define SH7750_TCNT_A7(n) SH7750_A7_REG32(SH7750_TCNT_REGOFS(n)) -#define SH7750_TCNT0 SH7750_TCNT(0) -#define SH7750_TCNT1 SH7750_TCNT(1) -#define SH7750_TCNT2 SH7750_TCNT(2) -#define SH7750_TCNT0_A7 SH7750_TCNT_A7(0) -#define SH7750_TCNT1_A7 SH7750_TCNT_A7(1) -#define SH7750_TCNT2_A7 SH7750_TCNT_A7(2) - -/* Timer Control Register (half) - TCR0, TCR1, TCR2 */ -#define SH7750_TCR_REGOFS(n) (0xD80010 + ((n)*12)) /* offset */ -#define SH7750_TCR(n) SH7750_P4_REG32(SH7750_TCR_REGOFS(n)) -#define SH7750_TCR_A7(n) SH7750_A7_REG32(SH7750_TCR_REGOFS(n)) -#define SH7750_TCR0 SH7750_TCR(0) -#define SH7750_TCR1 SH7750_TCR(1) -#define SH7750_TCR2 SH7750_TCR(2) -#define SH7750_TCR0_A7 SH7750_TCR_A7(0) -#define SH7750_TCR1_A7 SH7750_TCR_A7(1) -#define SH7750_TCR2_A7 SH7750_TCR_A7(2) - -#define SH7750_TCR2_ICPF 0x200 /* Input Capture Interrupt Flag - (1 - input capture has occured) */ -#define SH7750_TCR_UNF 0x100 /* Underflow flag */ -#define SH7750_TCR2_ICPE 0x0C0 /* Input Capture Control: */ -#define SH7750_TCR2_ICPE_DIS 0x000 /* Input Capture function is not used */ -#define SH7750_TCR2_ICPE_NOINT 0x080 /* Input Capture function is used, but - input capture interrupt is not - enabled */ -#define SH7750_TCR2_ICPE_INT 0x0C0 /* Input Capture function is used, - input capture interrupt enabled */ -#define SH7750_TCR_UNIE 0x020 /* Underflow Interrupt Control - (1 - underflow interrupt enabled) */ -#define SH7750_TCR_CKEG 0x018 /* Clock Edge selection: */ -#define SH7750_TCR_CKEG_RAISE 0x000 /* Count/capture on rising edge */ -#define SH7750_TCR_CKEG_FALL 0x008 /* Count/capture on falling edge */ -#define SH7750_TCR_CKEG_BOTH 0x018 /* Count/capture on both rising and - falling edges */ -#define SH7750_TCR_TPSC 0x007 /* Timer prescaler */ -#define SH7750_TCR_TPSC_DIV4 0x000 /* Counts on peripheral clock/4 */ -#define SH7750_TCR_TPSC_DIV16 0x001 /* Counts on peripheral clock/16 */ -#define SH7750_TCR_TPSC_DIV64 0x002 /* Counts on peripheral clock/64 */ -#define SH7750_TCR_TPSC_DIV256 0x003 /* Counts on peripheral clock/256 */ -#define SH7750_TCR_TPSC_DIV1024 0x004 /* Counts on peripheral clock/1024 */ -#define SH7750_TCR_TPSC_RTC 0x006 /* Counts on on-chip RTC output clk */ -#define SH7750_TCR_TPSC_EXT 0x007 /* Counts on external clock */ - -/* Input Capture Register (read-only) - TCPR2 */ -#define SH7750_TCPR2_REGOFS 0xD8002C /* offset */ -#define SH7750_TCPR2 SH7750_P4_REG32(SH7750_TCPR2_REGOFS) -#define SH7750_TCPR2_A7 SH7750_A7_REG32(SH7750_TCPR2_REGOFS) - /* * Bus State Controller - BSC */ diff --git a/hw/sh_timer.c b/hw/sh_timer.c new file mode 100644 index 000000000..40f3930cf --- /dev/null +++ b/hw/sh_timer.c @@ -0,0 +1,323 @@ +/* + * SuperH Timer modules. + * + * Copyright (c) 2007 Magnus Damm + * Based on arm_timer.c by Paul Brook + * Copyright (c) 2005-2006 CodeSourcery. + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +//#define DEBUG_TIMER + +#define TIMER_TCR_TPSC (7 << 0) +#define TIMER_TCR_CKEG (3 << 3) +#define TIMER_TCR_UNIE (1 << 5) +#define TIMER_TCR_ICPE (3 << 6) +#define TIMER_TCR_UNF (1 << 8) +#define TIMER_TCR_ICPF (1 << 9) +#define TIMER_TCR_RESERVED (0x3f << 10) + +#define TIMER_FEAT_CAPT (1 << 0) +#define TIMER_FEAT_EXTCLK (1 << 1) + +typedef struct { + ptimer_state *timer; + uint32_t tcnt; + uint32_t tcor; + uint32_t tcr; + uint32_t tcpr; + int freq; + int int_level; + int feat; + int enabled; + qemu_irq irq; +} sh_timer_state; + +/* Check all active timers, and schedule the next timer interrupt. */ + +static void sh_timer_update(sh_timer_state *s) +{ +#if 0 /* not yet */ + /* Update interrupts. */ + if (s->int_level && (s->tcr & TIMER_TCR_UNIE)) { + qemu_irq_raise(s->irq); + } else { + qemu_irq_lower(s->irq); + } +#endif +} + +uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) +{ + sh_timer_state *s = (sh_timer_state *)opaque; + + switch (offset >> 2) { + case 0: + return s->tcor; + case 1: + return ptimer_get_count(s->timer); + case 2: + return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0); + case 3: + if (s->feat & TIMER_FEAT_CAPT) + return s->tcpr; + default: + cpu_abort (cpu_single_env, "sh_timer_read: Bad offset %x\n", + (int)offset); + return 0; + } +} + +static void sh_timer_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + sh_timer_state *s = (sh_timer_state *)opaque; + int freq; + + switch (offset >> 2) { + case 0: + s->tcor = value; + ptimer_set_limit(s->timer, s->tcor, 0); + break; + case 1: + s->tcnt = value; + ptimer_set_count(s->timer, s->tcnt); + break; + case 2: + if (s->enabled) { + /* Pause the timer if it is running. This may cause some + inaccuracy dure to rounding, but avoids a whole lot of other + messyness. */ + ptimer_stop(s->timer); + } + freq = s->freq; + /* ??? Need to recalculate expiry time after changing divisor. */ + switch (value & TIMER_TCR_TPSC) { + case 0: freq >>= 2; break; + case 1: freq >>= 4; break; + case 2: freq >>= 6; break; + case 3: freq >>= 8; break; + case 4: freq >>= 10; break; + case 6: + case 7: if (s->feat & TIMER_FEAT_EXTCLK) break; + default: cpu_abort (cpu_single_env, + "sh_timer_write: Reserved TPSC value\n"); break; + } + switch ((value & TIMER_TCR_CKEG) >> 3) { + case 0: break; + case 1: + case 2: + case 3: if (s->feat & TIMER_FEAT_EXTCLK) break; + default: cpu_abort (cpu_single_env, + "sh_timer_write: Reserved CKEG value\n"); break; + } + switch ((value & TIMER_TCR_ICPE) >> 6) { + case 0: break; + case 2: + case 3: if (s->feat & TIMER_FEAT_CAPT) break; + default: cpu_abort (cpu_single_env, + "sh_timer_write: Reserved ICPE value\n"); break; + } + if ((value & TIMER_TCR_UNF) == 0) + s->int_level = 0; + + value &= ~TIMER_TCR_UNF; + + if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT))) + cpu_abort (cpu_single_env, + "sh_timer_write: Reserved ICPF value\n"); + + value &= ~TIMER_TCR_ICPF; /* capture not supported */ + + if (value & TIMER_TCR_RESERVED) + cpu_abort (cpu_single_env, + "sh_timer_write: Reserved TCR bits set\n"); + s->tcr = value; + ptimer_set_limit(s->timer, s->tcor, 0); + ptimer_set_freq(s->timer, freq); + if (s->enabled) { + /* Restart the timer if still enabled. */ + ptimer_run(s->timer, 0); + } + break; + case 3: + if (s->feat & TIMER_FEAT_CAPT) { + s->tcpr = value; + break; + } + default: + cpu_abort (cpu_single_env, "sh_timer_write: Bad offset %x\n", + (int)offset); + } + sh_timer_update(s); +} + +static void sh_timer_start_stop(void *opaque, int enable) +{ + sh_timer_state *s = (sh_timer_state *)opaque; + +#ifdef DEBUG_TIMER + printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled); +#endif + + if (s->enabled && !enable) { + ptimer_stop(s->timer); + } + if (!s->enabled && enable) { + ptimer_run(s->timer, 0); + } + s->enabled = !!enable; + +#ifdef DEBUG_TIMER + printf("sh_timer_start_stop done %d\n", s->enabled); +#endif +} + +static void sh_timer_tick(void *opaque) +{ + sh_timer_state *s = (sh_timer_state *)opaque; + s->int_level = s->enabled; + sh_timer_update(s); +} + +static void *sh_timer_init(uint32_t freq, int feat) +{ + sh_timer_state *s; + QEMUBH *bh; + + s = (sh_timer_state *)qemu_mallocz(sizeof(sh_timer_state)); + s->freq = freq; + s->feat = feat; + s->tcor = 0xffffffff; + s->tcnt = 0xffffffff; + s->tcpr = 0xdeadbeef; + s->tcor = 0; + s->enabled = 0; + + bh = qemu_bh_new(sh_timer_tick, s); + s->timer = ptimer_init(bh); + /* ??? Save/restore. */ + return s; +} + +typedef struct { + void *timer[3]; + int level[3]; + uint32_t tocr; + uint32_t tstr; + target_phys_addr_t base; + int feat; +} tmu012_state; + +static uint32_t tmu012_read(void *opaque, target_phys_addr_t offset) +{ + tmu012_state *s = (tmu012_state *)opaque; + +#ifdef DEBUG_TIMER + printf("tmu012_read 0x%lx\n", (unsigned long) offset); +#endif + offset -= s->base; + + if (offset >= 0x20) { + if (!(s->feat & TMU012_FEAT_3CHAN)) + cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n", + (int)offset); + return sh_timer_read(s->timer[2], offset - 0x20); + } + + if (offset >= 0x14) + return sh_timer_read(s->timer[1], offset - 0x14); + + if (offset >= 0x08) + return sh_timer_read(s->timer[0], offset - 0x08); + + if (offset == 4) + return s->tstr; + + if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) + return s->tocr; + + cpu_abort (cpu_single_env, "tmu012_write: Bad offset %x\n", + (int)offset); + return 0; +} + +static void tmu012_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + tmu012_state *s = (tmu012_state *)opaque; + +#ifdef DEBUG_TIMER + printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value); +#endif + offset -= s->base; + + if (offset >= 0x20) { + if (!(s->feat & TMU012_FEAT_3CHAN)) + cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n", + (int)offset); + sh_timer_write(s->timer[2], offset - 0x20, value); + return; + } + + if (offset >= 0x14) { + sh_timer_write(s->timer[1], offset - 0x14, value); + return; + } + + if (offset >= 0x08) { + sh_timer_write(s->timer[0], offset - 0x08, value); + return; + } + + if (offset == 4) { + sh_timer_start_stop(s->timer[0], value & (1 << 0)); + sh_timer_start_stop(s->timer[1], value & (1 << 1)); + if (s->feat & TMU012_FEAT_3CHAN) + sh_timer_start_stop(s->timer[2], value & (1 << 2)); + else + if (value & (1 << 2)) + cpu_abort (cpu_single_env, "tmu012_write: Bad channel\n"); + + s->tstr = value; + return; + } + + if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) { + s->tocr = value & (1 << 0); + } +} + +static CPUReadMemoryFunc *tmu012_readfn[] = { + tmu012_read, + tmu012_read, + tmu012_read +}; + +static CPUWriteMemoryFunc *tmu012_writefn[] = { + tmu012_write, + tmu012_write, + tmu012_write +}; + +void tmu012_init(uint32_t base, int feat, uint32_t freq) +{ + int iomemtype; + tmu012_state *s; + int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0; + + s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state)); + s->base = base; + s->feat = feat; + s->timer[0] = sh_timer_init(freq, timer_feat); + s->timer[1] = sh_timer_init(freq, timer_feat); + if (feat & TMU012_FEAT_3CHAN) + s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT); + iomemtype = cpu_register_io_memory(0, tmu012_readfn, + tmu012_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + /* ??? Save/restore. */ +} diff --git a/vl.h b/vl.h index ea7a05e3f..43adc2450 100644 --- a/vl.h +++ b/vl.h @@ -1517,6 +1517,12 @@ typedef struct { int sh7750_register_io_device(struct SH7750State *s, sh7750_io_device * device); +/* sh_timer.c */ +#define TMU012_FEAT_TOCR (1 << 0) +#define TMU012_FEAT_3CHAN (1 << 1) +#define TMU012_FEAT_EXTCLK (1 << 2) +void tmu012_init(uint32_t base, int feat, uint32_t freq); + /* tc58128.c */ int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); -- cgit v1.2.3 From 2f062c72275938cc8fcbf0ce083b73a35d6a5329 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:43:54 +0000 Subject: Stand-alone SCI/SCIF emulation code, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3270 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/sh7750.c | 345 +-------------------------------------------------- hw/sh7750_regnames.c | 18 --- hw/sh7750_regs.h | 225 --------------------------------- hw/sh_serial.c | 315 ++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 5 + 6 files changed, 325 insertions(+), 585 deletions(-) create mode 100644 hw/sh_serial.c diff --git a/Makefile.target b/Makefile.target index fd44a8120..0f190cfa0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -476,7 +476,7 @@ CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o -VL_OBJS+= sh_timer.o ptimer.o +VL_OBJS+= sh_timer.o ptimer.o sh_serial.o endif ifeq ($(TARGET_BASE_ARCH), m68k) VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o diff --git a/hw/sh7750.c b/hw/sh7750.c index 9002da31a..1028c5cc2 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -27,13 +27,6 @@ #include "sh7750_regs.h" #include "sh7750_regnames.h" -typedef struct { - uint8_t data[16]; - uint8_t length; /* Number of characters in the FIFO */ - uint8_t write_idx; /* Index of first character to write */ - uint8_t read_idx; /* Index of first character to read */ -} fifo; - #define NB_DEVICES 4 typedef struct SH7750State { @@ -43,27 +36,6 @@ typedef struct SH7750State { uint32_t periph_freq; /* SDRAM controller */ uint16_t rfcr; - /* First serial port */ - CharDriverState *serial1; - uint8_t scscr1; - uint8_t scsmr1; - uint8_t scbrr1; - uint8_t scssr1; - uint8_t scssr1_read; - uint8_t sctsr1; - uint8_t sctsr1_loaded; - uint8_t sctdr1; - uint8_t scrdr1; - /* Second serial port */ - CharDriverState *serial2; - uint16_t sclsr2; - uint16_t scscr2; - uint16_t scfcr2; - uint16_t scfsr2; - uint16_t scsmr2; - uint8_t scbrr2; - fifo serial2_receive_fifo; - fifo serial2_transmit_fifo; /* IO ports */ uint16_t gpioic; uint32_t pctra; @@ -84,263 +56,6 @@ typedef struct SH7750State { } SH7750State; -/********************************************************************** - First serial port -**********************************************************************/ - -static int serial1_can_receive(void *opaque) -{ - SH7750State *s = opaque; - - return s->scscr1 & SH7750_SCSCR_RE; -} - -static void serial1_receive_char(SH7750State * s, uint8_t c) -{ - if (s->scssr1 & SH7750_SCSSR1_RDRF) { - s->scssr1 |= SH7750_SCSSR1_ORER; - return; - } - - s->scrdr1 = c; - s->scssr1 |= SH7750_SCSSR1_RDRF; -} - -static void serial1_receive(void *opaque, const uint8_t * buf, int size) -{ - SH7750State *s = opaque; - int i; - - for (i = 0; i < size; i++) { - serial1_receive_char(s, buf[i]); - } -} - -static void serial1_event(void *opaque, int event) -{ - assert(0); -} - -static void serial1_maybe_send(SH7750State * s) -{ - uint8_t c; - - if (s->scssr1 & SH7750_SCSSR1_TDRE) - return; - c = s->sctdr1; - s->scssr1 |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND; - if (s->scscr1 & SH7750_SCSCR_TIE) { - fprintf(stderr, "interrupts for serial port 1 not implemented\n"); - assert(0); - } - /* XXXXX Check for errors in write */ - qemu_chr_write(s->serial1, &c, 1); -} - -static void serial1_change_scssr1(SH7750State * s, uint8_t mem_value) -{ - uint8_t new_flags; - - /* If transmit disable, TDRE and TEND stays up */ - if ((s->scscr1 & SH7750_SCSCR_TE) == 0) { - mem_value |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND; - } - - /* Only clear bits which have been read before and do not set any bit - in the flags */ - new_flags = s->scssr1 & ~s->scssr1_read; /* Preserve unread flags */ - new_flags &= mem_value | ~s->scssr1_read; /* Clear read flags */ - - s->scssr1 = (new_flags & 0xf8) | (mem_value & 1); - s->scssr1_read &= mem_value; - - /* If TDRE has been cleared, TEND will also be cleared */ - if ((s->scssr1 & SH7750_SCSSR1_TDRE) == 0) { - s->scssr1 &= ~SH7750_SCSSR1_TEND; - } - - /* Check for transmission to start */ - serial1_maybe_send(s); -} - -static void serial1_update_parameters(SH7750State * s) -{ - QEMUSerialSetParams ssp; - - if (s->scsmr1 & SH7750_SCSMR_CHR_7) - ssp.data_bits = 7; - else - ssp.data_bits = 8; - if (s->scsmr1 & SH7750_SCSMR_PE) { - if (s->scsmr1 & SH7750_SCSMR_PM_ODD) - ssp.parity = 'O'; - else - ssp.parity = 'E'; - } else - ssp.parity = 'N'; - if (s->scsmr1 & SH7750_SCSMR_STOP_2) - ssp.stop_bits = 2; - else - ssp.stop_bits = 1; - fprintf(stderr, "SCSMR1=%04x SCBRR1=%02x\n", s->scsmr1, s->scbrr1); - ssp.speed = s->periph_freq / - (32 * s->scbrr1 * (1 << (2 * (s->scsmr1 & 3)))) - 1; - fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n", - ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed); - qemu_chr_ioctl(s->serial1, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); -} - -static void scscr1_changed(SH7750State * s) -{ - if (s->scscr1 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) { - if (!s->serial1) { - fprintf(stderr, "serial port 1 not bound to anything\n"); - assert(0); - } - serial1_update_parameters(s); - } - if ((s->scscr1 & SH7750_SCSCR_RE) == 0) { - s->scssr1 |= SH7750_SCSSR1_TDRE; - } -} - -static void init_serial1(SH7750State * s, int serial_nb) -{ - CharDriverState *chr; - - s->scssr1 = 0x84; - chr = serial_hds[serial_nb]; - if (!chr) { - fprintf(stderr, - "no serial port associated to SH7750 first serial port\n"); - return; - } - - s->serial1 = chr; - qemu_chr_add_handlers(chr, serial1_can_receive, - serial1_receive, serial1_event, s); -} - -/********************************************************************** - Second serial port -**********************************************************************/ - -static int serial2_can_receive(void *opaque) -{ - SH7750State *s = opaque; - static uint8_t max_fifo_size[] = { 15, 1, 4, 6, 8, 10, 12, 14 }; - - return s->serial2_receive_fifo.length < - max_fifo_size[(s->scfcr2 >> 9) & 7]; -} - -static void serial2_adjust_receive_flags(SH7750State * s) -{ - static uint8_t max_fifo_size[] = { 1, 4, 8, 14 }; - - /* XXXXX Add interrupt generation */ - if (s->serial2_receive_fifo.length >= - max_fifo_size[(s->scfcr2 >> 7) & 3]) { - s->scfsr2 |= SH7750_SCFSR2_RDF; - s->scfsr2 &= ~SH7750_SCFSR2_DR; - } else { - s->scfsr2 &= ~SH7750_SCFSR2_RDF; - if (s->serial2_receive_fifo.length > 0) - s->scfsr2 |= SH7750_SCFSR2_DR; - else - s->scfsr2 &= ~SH7750_SCFSR2_DR; - } -} - -static void serial2_append_char(SH7750State * s, uint8_t c) -{ - if (s->serial2_receive_fifo.length == 16) { - /* Overflow */ - s->sclsr2 |= SH7750_SCLSR2_ORER; - return; - } - - s->serial2_receive_fifo.data[s->serial2_receive_fifo.write_idx++] = c; - s->serial2_receive_fifo.length++; - serial2_adjust_receive_flags(s); -} - -static void serial2_receive(void *opaque, const uint8_t * buf, int size) -{ - SH7750State *s = opaque; - int i; - - for (i = 0; i < size; i++) - serial2_append_char(s, buf[i]); -} - -static void serial2_event(void *opaque, int event) -{ - /* XXXXX */ - assert(0); -} - -static void serial2_update_parameters(SH7750State * s) -{ - QEMUSerialSetParams ssp; - - if (s->scsmr2 & SH7750_SCSMR_CHR_7) - ssp.data_bits = 7; - else - ssp.data_bits = 8; - if (s->scsmr2 & SH7750_SCSMR_PE) { - if (s->scsmr2 & SH7750_SCSMR_PM_ODD) - ssp.parity = 'O'; - else - ssp.parity = 'E'; - } else - ssp.parity = 'N'; - if (s->scsmr2 & SH7750_SCSMR_STOP_2) - ssp.stop_bits = 2; - else - ssp.stop_bits = 1; - fprintf(stderr, "SCSMR2=%04x SCBRR2=%02x\n", s->scsmr2, s->scbrr2); - ssp.speed = s->periph_freq / - (32 * s->scbrr2 * (1 << (2 * (s->scsmr2 & 3)))) - 1; - fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n", - ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed); - qemu_chr_ioctl(s->serial2, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); -} - -static void scscr2_changed(SH7750State * s) -{ - if (s->scscr2 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) { - if (!s->serial2) { - fprintf(stderr, "serial port 2 not bound to anything\n"); - assert(0); - } - serial2_update_parameters(s); - } -} - -static void init_serial2(SH7750State * s, int serial_nb) -{ - CharDriverState *chr; - - s->scfsr2 = 0x0060; - - chr = serial_hds[serial_nb]; - if (!chr) { - fprintf(stderr, - "no serial port associated to SH7750 second serial port\n"); - return; - } - - s->serial2 = chr; - qemu_chr_add_handlers(chr, serial2_can_receive, - serial2_receive, serial1_event, s); -} - -static void init_serial_ports(SH7750State * s) -{ - init_serial1(s, 0); - init_serial2(s, 1); -} /********************************************************************** I/O ports @@ -472,17 +187,7 @@ static void ignore_access(const char *kind, target_phys_addr_t addr) static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr) { - SH7750State *s = opaque; - uint8_t r; - switch (addr) { - case SH7750_SCSSR1_A7: - r = s->scssr1; - s->scssr1_read |= r; - return s->scssr1; - case SH7750_SCRDR1_A7: - s->scssr1 &= ~SH7750_SCSSR1_RDRF; - return s->scrdr1; default: error_access("byte read", addr); assert(0); @@ -492,20 +197,12 @@ static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr) static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) { SH7750State *s = opaque; - uint16_t r; switch (addr) { case SH7750_RFCR_A7: fprintf(stderr, "Read access to refresh count register, incrementing\n"); return s->rfcr++; - case SH7750_SCLSR2_A7: - /* Read and clear overflow bit */ - r = s->sclsr2; - s->sclsr2 = 0; - return r; - case SH7750_SCSFR2_A7: - return s->scfsr2; case SH7750_PDTRA_A7: return porta_lines(s); case SH7750_PDTRB_A7: @@ -554,34 +251,12 @@ static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t mem_value) { - SH7750State *s = opaque; - switch (addr) { /* PRECHARGE ? XXXXX */ case SH7750_PRECHARGE0_A7: case SH7750_PRECHARGE1_A7: ignore_access("byte write", addr); return; - case SH7750_SCBRR2_A7: - s->scbrr2 = mem_value; - return; - case SH7750_SCSCR1_A7: - s->scscr1 = mem_value; - scscr1_changed(s); - return; - case SH7750_SCSMR1_A7: - s->scsmr1 = mem_value; - return; - case SH7750_SCBRR1_A7: - s->scbrr1 = mem_value; - return; - case SH7750_SCTDR1_A7: - s->scssr1 &= ~SH7750_SCSSR1_TEND; - s->sctdr1 = mem_value; - return; - case SH7750_SCSSR1_A7: - serial1_change_scssr1(s, mem_value); - return; default: error_access("byte write", addr); assert(0); @@ -596,8 +271,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, switch (addr) { /* SDRAM controller */ - case SH7750_SCBRR1_A7: - case SH7750_SCBRR2_A7: case SH7750_BCR2_A7: case SH7750_BCR3_A7: case SH7750_RTCOR_A7: @@ -620,19 +293,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, fprintf(stderr, "Write access to refresh count register\n"); s->rfcr = mem_value; return; - case SH7750_SCLSR2_A7: - s->sclsr2 = mem_value; - return; - case SH7750_SCSCR2_A7: - s->scscr2 = mem_value; - scscr2_changed(s); - return; - case SH7750_SCFCR2_A7: - s->scfcr2 = mem_value; - return; - case SH7750_SCSMR2_A7: - s->scsmr2 = mem_value; - return; case SH7750_GPIOIC_A7: s->gpioic = mem_value; if (mem_value != 0) { @@ -734,7 +394,10 @@ SH7750State *sh7750_init(CPUSH4State * cpu) sh7750_mem_read, sh7750_mem_write, s); cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); - init_serial_ports(s); + + sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]); + sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF, + s->periph_freq, serial_hds[1]); tmu012_init(0x1fd80000, TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c index 6ae491771..84d5c1a2e 100644 --- a/hw/sh7750_regnames.c +++ b/hw/sh7750_regnames.c @@ -70,24 +70,6 @@ static regname_t regnames[] = { REGNAME(SH7750_CHCR2_A7) REGNAME(SH7750_CHCR3_A7) REGNAME(SH7750_DMAOR_A7) - REGNAME(SH7750_SCRDR1_A7) - REGNAME(SH7750_SCRDR2_A7) - REGNAME(SH7750_SCTDR1_A7) - REGNAME(SH7750_SCTDR2_A7) - REGNAME(SH7750_SCSMR1_A7) - REGNAME(SH7750_SCSMR2_A7) - REGNAME(SH7750_SCSCR1_A7) - REGNAME(SH7750_SCSCR2_A7) - REGNAME(SH7750_SCSSR1_A7) - REGNAME(SH7750_SCSFR2_A7) - REGNAME(SH7750_SCSPTR1_A7) - REGNAME(SH7750_SCSPTR2_A7) - REGNAME(SH7750_SCBRR1_A7) - REGNAME(SH7750_SCBRR2_A7) - REGNAME(SH7750_SCFCR2_A7) - REGNAME(SH7750_SCFDR2_A7) - REGNAME(SH7750_SCLSR2_A7) - REGNAME(SH7750_SCSCMR1_A7) REGNAME(SH7750_PCTRA_A7) REGNAME(SH7750_PDTRA_A7) REGNAME(SH7750_PCTRB_A7) diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h index 85eab4312..15b27690d 100644 --- a/hw/sh7750_regs.h +++ b/hw/sh7750_regs.h @@ -1168,231 +1168,6 @@ #define SH7750_DMAOR_NMIF 0x00000002 /* NMI Flag */ #define SH7750_DMAOR_DME 0x00000001 /* DMAC Master Enable */ -/* - * Serial Communication Interface - SCI - * Serial Communication Interface with FIFO - SCIF - */ -/* SCI Receive Data Register (byte, read-only) - SCRDR1, SCFRDR2 */ -#define SH7750_SCRDR_REGOFS(n) ((n) == 1 ? 0xE00014 : 0xE80014) /* offset */ -#define SH7750_SCRDR(n) SH7750_P4_REG32(SH7750_SCRDR_REGOFS(n)) -#define SH7750_SCRDR1 SH7750_SCRDR(1) -#define SH7750_SCRDR2 SH7750_SCRDR(2) -#define SH7750_SCRDR_A7(n) SH7750_A7_REG32(SH7750_SCRDR_REGOFS(n)) -#define SH7750_SCRDR1_A7 SH7750_SCRDR_A7(1) -#define SH7750_SCRDR2_A7 SH7750_SCRDR_A7(2) - -/* SCI Transmit Data Register (byte) - SCTDR1, SCFTDR2 */ -#define SH7750_SCTDR_REGOFS(n) ((n) == 1 ? 0xE0000C : 0xE8000C) /* offset */ -#define SH7750_SCTDR(n) SH7750_P4_REG32(SH7750_SCTDR_REGOFS(n)) -#define SH7750_SCTDR1 SH7750_SCTDR(1) -#define SH7750_SCTDR2 SH7750_SCTDR(2) -#define SH7750_SCTDR_A7(n) SH7750_A7_REG32(SH7750_SCTDR_REGOFS(n)) -#define SH7750_SCTDR1_A7 SH7750_SCTDR_A7(1) -#define SH7750_SCTDR2_A7 SH7750_SCTDR_A7(2) - -/* SCI Serial Mode Register - SCSMR1(byte), SCSMR2(half) */ -#define SH7750_SCSMR_REGOFS(n) ((n) == 1 ? 0xE00000 : 0xE80000) /* offset */ -#define SH7750_SCSMR(n) SH7750_P4_REG32(SH7750_SCSMR_REGOFS(n)) -#define SH7750_SCSMR1 SH7750_SCSMR(1) -#define SH7750_SCSMR2 SH7750_SCSMR(2) -#define SH7750_SCSMR_A7(n) SH7750_A7_REG32(SH7750_SCSMR_REGOFS(n)) -#define SH7750_SCSMR1_A7 SH7750_SCSMR_A7(1) -#define SH7750_SCSMR2_A7 SH7750_SCSMR_A7(2) - -#define SH7750_SCSMR1_CA 0x80 /* Communication Mode (C/A\): */ -#define SH7750_SCSMR1_CA_ASYNC 0x00 /* Asynchronous Mode */ -#define SH7750_SCSMR1_CA_SYNC 0x80 /* Synchronous Mode */ -#define SH7750_SCSMR_CHR 0x40 /* Character Length: */ -#define SH7750_SCSMR_CHR_8 0x00 /* 8-bit data */ -#define SH7750_SCSMR_CHR_7 0x40 /* 7-bit data */ -#define SH7750_SCSMR_PE 0x20 /* Parity Enable */ -#define SH7750_SCSMR_PM 0x10 /* Parity Mode: */ -#define SH7750_SCSMR_PM_EVEN 0x00 /* Even Parity */ -#define SH7750_SCSMR_PM_ODD 0x10 /* Odd Parity */ -#define SH7750_SCSMR_STOP 0x08 /* Stop Bit Length: */ -#define SH7750_SCSMR_STOP_1 0x00 /* 1 stop bit */ -#define SH7750_SCSMR_STOP_2 0x08 /* 2 stop bit */ -#define SH7750_SCSMR1_MP 0x04 /* Multiprocessor Mode */ -#define SH7750_SCSMR_CKS 0x03 /* Clock Select */ -#define SH7750_SCSMR_CKS_S 0 -#define SH7750_SCSMR_CKS_DIV1 0x00 /* Periph clock */ -#define SH7750_SCSMR_CKS_DIV4 0x01 /* Periph clock / 4 */ -#define SH7750_SCSMR_CKS_DIV16 0x02 /* Periph clock / 16 */ -#define SH7750_SCSMR_CKS_DIV64 0x03 /* Periph clock / 64 */ - -/* SCI Serial Control Register - SCSCR1(byte), SCSCR2(half) */ -#define SH7750_SCSCR_REGOFS(n) ((n) == 1 ? 0xE00008 : 0xE80008) /* offset */ -#define SH7750_SCSCR(n) SH7750_P4_REG32(SH7750_SCSCR_REGOFS(n)) -#define SH7750_SCSCR1 SH7750_SCSCR(1) -#define SH7750_SCSCR2 SH7750_SCSCR(2) -#define SH7750_SCSCR_A7(n) SH7750_A7_REG32(SH7750_SCSCR_REGOFS(n)) -#define SH7750_SCSCR1_A7 SH7750_SCSCR_A7(1) -#define SH7750_SCSCR2_A7 SH7750_SCSCR_A7(2) - -#define SH7750_SCSCR_TIE 0x80 /* Transmit Interrupt Enable */ -#define SH7750_SCSCR_RIE 0x40 /* Receive Interrupt Enable */ -#define SH7750_SCSCR_TE 0x20 /* Transmit Enable */ -#define SH7750_SCSCR_RE 0x10 /* Receive Enable */ -#define SH7750_SCSCR1_MPIE 0x08 /* Multiprocessor Interrupt Enable */ -#define SH7750_SCSCR2_REIE 0x08 /* Receive Error Interrupt Enable */ -#define SH7750_SCSCR1_TEIE 0x04 /* Transmit End Interrupt Enable */ -#define SH7750_SCSCR1_CKE 0x03 /* Clock Enable: */ -#define SH7750_SCSCR_CKE_INTCLK 0x00 /* Use Internal Clock */ -#define SH7750_SCSCR_CKE_EXTCLK 0x02 /* Use External Clock from SCK */ -#define SH7750_SCSCR1_CKE_ASYNC_SCK_CLKOUT 0x01 /* Use SCK as a clock output - in asynchronous mode */ - -/* SCI Serial Status Register - SCSSR1(byte), SCSFR2(half) */ -#define SH7750_SCSSR_REGOFS(n) ((n) == 1 ? 0xE00010 : 0xE80010) /* offset */ -#define SH7750_SCSSR(n) SH7750_P4_REG32(SH7750_SCSSR_REGOFS(n)) -#define SH7750_SCSSR1 SH7750_SCSSR(1) -#define SH7750_SCSFR2 SH7750_SCSSR(2) -#define SH7750_SCSSR_A7(n) SH7750_A7_REG32(SH7750_SCSSR_REGOFS(n)) -#define SH7750_SCSSR1_A7 SH7750_SCSSR_A7(1) -#define SH7750_SCSFR2_A7 SH7750_SCSSR_A7(2) - -#define SH7750_SCSSR1_TDRE 0x80 /* Transmit Data Register Empty */ -#define SH7750_SCSSR1_RDRF 0x40 /* Receive Data Register Full */ -#define SH7750_SCSSR1_ORER 0x20 /* Overrun Error */ -#define SH7750_SCSSR1_FER 0x10 /* Framing Error */ -#define SH7750_SCSSR1_PER 0x08 /* Parity Error */ -#define SH7750_SCSSR1_TEND 0x04 /* Transmit End */ -#define SH7750_SCSSR1_MPB 0x02 /* Multiprocessor Bit */ -#define SH7750_SCSSR1_MPBT 0x01 /* Multiprocessor Bit Transfer */ - -#define SH7750_SCFSR2_PERN 0xF000 /* Number of Parity Errors */ -#define SH7750_SCFSR2_PERN_S 12 -#define SH7750_SCFSR2_FERN 0x0F00 /* Number of Framing Errors */ -#define SH7750_SCFSR2_FERN_S 8 -#define SH7750_SCFSR2_ER 0x0080 /* Receive Error */ -#define SH7750_SCFSR2_TEND 0x0040 /* Transmit End */ -#define SH7750_SCFSR2_TDFE 0x0020 /* Transmit FIFO Data Empty */ -#define SH7750_SCFSR2_BRK 0x0010 /* Break Detect */ -#define SH7750_SCFSR2_FER 0x0008 /* Framing Error */ -#define SH7750_SCFSR2_PER 0x0004 /* Parity Error */ -#define SH7750_SCFSR2_RDF 0x0002 /* Receive FIFO Data Full */ -#define SH7750_SCFSR2_DR 0x0001 /* Receive Data Ready */ - -/* SCI Serial Port Register - SCSPTR1(byte) */ -#define SH7750_SCSPTR1_REGOFS 0xE0001C /* offset */ -#define SH7750_SCSPTR1 SH7750_P4_REG32(SH7750_SCSPTR1_REGOFS) -#define SH7750_SCSPTR1_A7 SH7750_A7_REG32(SH7750_SCSPTR1_REGOFS) - -#define SH7750_SCSPTR1_EIO 0x80 /* Error Interrupt Only */ -#define SH7750_SCSPTR1_SPB1IO 0x08 /* 1: Output SPB1DT bit to SCK pin */ -#define SH7750_SCSPTR1_SPB1DT 0x04 /* Serial Port Clock Port Data */ -#define SH7750_SCSPTR1_SPB0IO 0x02 /* 1: Output SPB0DT bit to TxD pin */ -#define SH7750_SCSPTR1_SPB0DT 0x01 /* Serial Port Break Data */ - -/* SCIF Serial Port Register - SCSPTR2(half) */ -#define SH7750_SCSPTR2_REGOFS 0xE80020 /* offset */ -#define SH7750_SCSPTR2 SH7750_P4_REG32(SH7750_SCSPTR2_REGOFS) -#define SH7750_SCSPTR2_A7 SH7750_A7_REG32(SH7750_SCSPTR2_REGOFS) - -#define SH7750_SCSPTR2_RTSIO 0x80 /* 1: Output RTSDT bit to RTS2\ pin */ -#define SH7750_SCSPTR2_RTSDT 0x40 /* RTS Port Data */ -#define SH7750_SCSPTR2_CTSIO 0x20 /* 1: Output CTSDT bit to CTS2\ pin */ -#define SH7750_SCSPTR2_CTSDT 0x10 /* CTS Port Data */ -#define SH7750_SCSPTR2_SPB2IO 0x02 /* 1: Output SPBDT bit to TxD2 pin */ -#define SH7750_SCSPTR2_SPB2DT 0x01 /* Serial Port Break Data */ - -/* SCI Bit Rate Register - SCBRR1(byte), SCBRR2(byte) */ -#define SH7750_SCBRR_REGOFS(n) ((n) == 1 ? 0xE00004 : 0xE80004) /* offset */ -#define SH7750_SCBRR(n) SH7750_P4_REG32(SH7750_SCBRR_REGOFS(n)) -#define SH7750_SCBRR1 SH7750_SCBRR_P4(1) -#define SH7750_SCBRR2 SH7750_SCBRR_P4(2) -#define SH7750_SCBRR_A7(n) SH7750_A7_REG32(SH7750_SCBRR_REGOFS(n)) -#define SH7750_SCBRR1_A7 SH7750_SCBRR_A7(1) -#define SH7750_SCBRR2_A7 SH7750_SCBRR_A7(2) - -/* SCIF FIFO Control Register - SCFCR2(half) */ -#define SH7750_SCFCR2_REGOFS 0xE80018 /* offset */ -#define SH7750_SCFCR2 SH7750_P4_REG32(SH7750_SCFCR2_REGOFS) -#define SH7750_SCFCR2_A7 SH7750_A7_REG32(SH7750_SCFCR2_REGOFS) - -#define SH7750_SCFCR2_RSTRG 0x700 /* RTS2\ Output Active Trigger; RTS2\ - signal goes to high level when the - number of received data stored in - FIFO exceeds the trigger number */ -#define SH7750_SCFCR2_RSTRG_15 0x000 /* 15 bytes */ -#define SH7750_SCFCR2_RSTRG_1 0x000 /* 1 byte */ -#define SH7750_SCFCR2_RSTRG_4 0x000 /* 4 bytes */ -#define SH7750_SCFCR2_RSTRG_6 0x000 /* 6 bytes */ -#define SH7750_SCFCR2_RSTRG_8 0x000 /* 8 bytes */ -#define SH7750_SCFCR2_RSTRG_10 0x000 /* 10 bytes */ -#define SH7750_SCFCR2_RSTRG_14 0x000 /* 14 bytes */ - -#define SH7750_SCFCR2_RTRG 0x0C0 /* Receive FIFO Data Number Trigger, - Receive Data Full (RDF) Flag sets - when number of receive data bytes is - equal or greater than the trigger - number */ -#define SH7750_SCFCR2_RTRG_1 0x000 /* 1 byte */ -#define SH7750_SCFCR2_RTRG_4 0x040 /* 4 bytes */ -#define SH7750_SCFCR2_RTRG_8 0x080 /* 8 bytes */ -#define SH7750_SCFCR2_RTRG_14 0x0C0 /* 14 bytes */ - -#define SH7750_SCFCR2_TTRG 0x030 /* Transmit FIFO Data Number Trigger, - Transmit FIFO Data Register Empty (TDFE) - flag sets when the number of remaining - transmit data bytes is equal or less - than the trigger number */ -#define SH7750_SCFCR2_TTRG_8 0x000 /* 8 bytes */ -#define SH7750_SCFCR2_TTRG_4 0x010 /* 4 bytes */ -#define SH7750_SCFCR2_TTRG_2 0x020 /* 2 bytes */ -#define SH7750_SCFCR2_TTRG_1 0x030 /* 1 byte */ - -#define SH7750_SCFCR2_MCE 0x008 /* Modem Control Enable */ -#define SH7750_SCFCR2_TFRST 0x004 /* Transmit FIFO Data Register Reset, - invalidates the transmit data in the - transmit FIFO */ -#define SH7750_SCFCR2_RFRST 0x002 /* Receive FIFO Data Register Reset, - invalidates the receive data in the - receive FIFO data register and resets - it to the empty state */ -#define SH7750_SCFCR2_LOOP 0x001 /* Loopback Test */ - -/* SCIF FIFO Data Count Register - SCFDR2(half, read-only) */ -#define SH7750_SCFDR2_REGOFS 0xE8001C /* offset */ -#define SH7750_SCFDR2 SH7750_P4_REG32(SH7750_SCFDR2_REGOFS) -#define SH7750_SCFDR2_A7 SH7750_A7_REG32(SH7750_SCFDR2_REGOFS) - -#define SH7750_SCFDR2_T 0x1F00 /* Number of untransmitted data bytes - in transmit FIFO */ -#define SH7750_SCFDR2_T_S 8 -#define SH7750_SCFDR2_R 0x001F /* Number of received data bytes in - receive FIFO */ -#define SH7750_SCFDR2_R_S 0 - -/* SCIF Line Status Register - SCLSR2(half, read-only) */ -#define SH7750_SCLSR2_REGOFS 0xE80024 /* offset */ -#define SH7750_SCLSR2 SH7750_P4_REG32(SH7750_SCLSR2_REGOFS) -#define SH7750_SCLSR2_A7 SH7750_A7_REG32(SH7750_SCLSR2_REGOFS) - -#define SH7750_SCLSR2_ORER 0x0001 /* Overrun Error */ - -/* - * SCI-based Smart Card Interface - */ -/* Smart Card Mode Register - SCSCMR1(byte) */ -#define SH7750_SCSCMR1_REGOFS 0xE00018 /* offset */ -#define SH7750_SCSCMR1 SH7750_P4_REG32(SH7750_SCSCMR1_REGOFS) -#define SH7750_SCSCMR1_A7 SH7750_A7_REG32(SH7750_SCSCMR1_REGOFS) - -#define SH7750_SCSCMR1_SDIR 0x08 /* Smart Card Data Transfer Direction: */ -#define SH7750_SCSCMR1_SDIR_LSBF 0x00 /* LSB-first */ -#define SH7750_SCSCMR1_SDIR_MSBF 0x08 /* MSB-first */ - -#define SH7750_SCSCMR1_SINV 0x04 /* Smart Card Data Inversion */ -#define SH7750_SCSCMR1_SMIF 0x01 /* Smart Card Interface Mode Select */ - -/* Smart-card specific bits in other registers */ -/* SCSMR1: */ -#define SH7750_SCSMR1_GSM 0x80 /* GSM mode select */ - -/* SCSSR1: */ -#define SH7750_SCSSR1_ERS 0x10 /* Error Signal Status */ - /* * I/O Ports */ diff --git a/hw/sh_serial.c b/hw/sh_serial.c new file mode 100644 index 000000000..03a096c1b --- /dev/null +++ b/hw/sh_serial.c @@ -0,0 +1,315 @@ +/* + * QEMU SCI/SCIF serial port emulation + * + * Copyright (c) 2007 Magnus Damm + * + * Based on serial.c - QEMU 16450 UART emulation + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include + +//#define DEBUG_SERIAL + +#define SH_SERIAL_FLAG_TEND (1 << 0) +#define SH_SERIAL_FLAG_TDE (1 << 1) +#define SH_SERIAL_FLAG_RDF (1 << 2) +#define SH_SERIAL_FLAG_BRK (1 << 3) +#define SH_SERIAL_FLAG_DR (1 << 4) + +typedef struct { + uint8_t smr; + uint8_t brr; + uint8_t scr; + uint8_t dr; /* ftdr / tdr */ + uint8_t sr; /* fsr / ssr */ + uint16_t fcr; + uint8_t sptr; + + uint8_t rx_fifo[16]; /* frdr / rdr */ + uint8_t rx_cnt; + + target_phys_addr_t base; + int freq; + int feat; + int flags; + + CharDriverState *chr; +} sh_serial_state; + +static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) +{ + sh_serial_state *s = opaque; + unsigned char ch; + +#ifdef DEBUG_SERIAL + printf("sh_serial: write base=0x%08lx offs=0x%02x val=0x%02x\n", + (unsigned long) s->base, offs, val); +#endif + switch(offs) { + case 0x00: /* SMR */ + s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff); + return; + case 0x04: /* BRR */ + s->brr = val; + return; + case 0x08: /* SCR */ + s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfb : 0xff); + if (!(val & (1 << 5))) + s->flags |= SH_SERIAL_FLAG_TEND; + return; + case 0x0c: /* FTDR / TDR */ + if (s->chr) { + ch = val; + qemu_chr_write(s->chr, &ch, 1); + } + s->dr = val; + s->flags &= ~SH_SERIAL_FLAG_TDE; + return; +#if 0 + case 0x14: /* FRDR / RDR */ + ret = 0; + break; +#endif + } + if (s->feat & SH_SERIAL_FEAT_SCIF) { + switch(offs) { + case 0x10: /* FSR */ + if (!(val & (1 << 6))) + s->flags &= ~SH_SERIAL_FLAG_TEND; + if (!(val & (1 << 5))) + s->flags &= ~SH_SERIAL_FLAG_TDE; + if (!(val & (1 << 4))) + s->flags &= ~SH_SERIAL_FLAG_BRK; + if (!(val & (1 << 1))) + s->flags &= ~SH_SERIAL_FLAG_RDF; + if (!(val & (1 << 0))) + s->flags &= ~SH_SERIAL_FLAG_DR; + return; + case 0x18: /* FCR */ + s->fcr = val; + return; + case 0x20: /* SPTR */ + s->sptr = val; + return; + case 0x24: /* LSR */ + return; + } + } + else { +#if 0 + switch(offs) { + case 0x0c: + ret = s->dr; + break; + case 0x10: + ret = 0; + break; + case 0x1c: + ret = s->sptr; + break; + } +#endif + } + + fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs); + assert(0); +} + +static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs) +{ + sh_serial_state *s = opaque; + uint32_t ret = ~0; + +#if 0 + switch(offs) { + case 0x00: + ret = s->smr; + break; + case 0x04: + ret = s->brr; + break; + case 0x08: + ret = s->scr; + break; + case 0x14: + ret = 0; + break; + } +#endif + if (s->feat & SH_SERIAL_FEAT_SCIF) { + switch(offs) { + case 0x10: /* FSR */ + ret = 0; + if (s->flags & SH_SERIAL_FLAG_TEND) + ret |= (1 << 6); + if (s->flags & SH_SERIAL_FLAG_TDE) + ret |= (1 << 5); + if (s->flags & SH_SERIAL_FLAG_BRK) + ret |= (1 << 4); + if (s->flags & SH_SERIAL_FLAG_RDF) + ret |= (1 << 1); + if (s->flags & SH_SERIAL_FLAG_DR) + ret |= (1 << 0); + + if (s->scr & (1 << 5)) + s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; + + break; +#if 0 + case 0x18: + ret = s->fcr; + break; +#endif + case 0x1c: + ret = s->rx_cnt; + break; + case 0x20: + ret = s->sptr; + break; + case 0x24: + ret = 0; + break; + } + } + else { +#if 0 + switch(offs) { + case 0x0c: + ret = s->dr; + break; + case 0x10: + ret = 0; + break; + case 0x1c: + ret = s->sptr; + break; + } +#endif + } +#ifdef DEBUG_SERIAL + printf("sh_serial: read base=0x%08lx offs=0x%02x val=0x%x\n", + (unsigned long) s->base, offs, ret); +#endif + + if (ret & ~((1 << 16) - 1)) { + fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs); + assert(0); + } + + return ret; +} + +static int sh_serial_can_receive(sh_serial_state *s) +{ + return 0; +} + +static void sh_serial_receive_byte(sh_serial_state *s, int ch) +{ +} + +static void sh_serial_receive_break(sh_serial_state *s) +{ +} + +static int sh_serial_can_receive1(void *opaque) +{ + sh_serial_state *s = opaque; + return sh_serial_can_receive(s); +} + +static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) +{ + sh_serial_state *s = opaque; + sh_serial_receive_byte(s, buf[0]); +} + +static void sh_serial_event(void *opaque, int event) +{ + sh_serial_state *s = opaque; + if (event == CHR_EVENT_BREAK) + sh_serial_receive_break(s); +} + +uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr) +{ + sh_serial_state *s = opaque; + return sh_serial_ioport_read(s, addr - s->base); +} + +void sh_serial_write (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + sh_serial_state *s = opaque; + sh_serial_ioport_write(s, addr - s->base, value); +} + +static CPUReadMemoryFunc *sh_serial_readfn[] = { + &sh_serial_read, + &sh_serial_read, + &sh_serial_read, +}; + +static CPUWriteMemoryFunc *sh_serial_writefn[] = { + &sh_serial_write, + &sh_serial_write, + &sh_serial_write, +}; + +void sh_serial_init (target_phys_addr_t base, int feat, + uint32_t freq, CharDriverState *chr) +{ + sh_serial_state *s; + int s_io_memory; + + s = qemu_mallocz(sizeof(sh_serial_state)); + if (!s) + return; + + s->base = base; + s->feat = feat; + s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; + + s->smr = 0; + s->brr = 0xff; + s->scr = 0; + s->sptr = 0; + + if (feat & SH_SERIAL_FEAT_SCIF) { + s->fcr = 0; + } + else { + s->dr = 0xff; + } + + s->rx_cnt = 0; + + s_io_memory = cpu_register_io_memory(0, sh_serial_readfn, + sh_serial_writefn, s); + cpu_register_physical_memory(base, 0x28, s_io_memory); + + s->chr = chr; + + if (chr) + qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, + sh_serial_event, s); +} diff --git a/vl.h b/vl.h index 43adc2450..4e0628332 100644 --- a/vl.h +++ b/vl.h @@ -1523,6 +1523,11 @@ int sh7750_register_io_device(struct SH7750State *s, #define TMU012_FEAT_EXTCLK (1 << 2) void tmu012_init(uint32_t base, int feat, uint32_t freq); +/* sh_serial.c */ +#define SH_SERIAL_FEAT_SCIF (1 << 0) +void sh_serial_init (target_phys_addr_t base, int feat, + uint32_t freq, CharDriverState *chr); + /* tc58128.c */ int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); -- cgit v1.2.3 From 3464c5899891efa0b7cb86b5a8090da50a3e6c88 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:47:44 +0000 Subject: Add INTC controller prototype, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3271 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sh7750.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/hw/sh7750.c b/hw/sh7750.c index 1028c5cc2..8ff6ca194 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -51,6 +51,14 @@ typedef struct SH7750State { uint16_t periph_pdtrb; /* Imposed by the peripherals */ uint16_t periph_portdirb; /* Direction seen from the peripherals */ sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ + + uint16_t icr; + uint16_t ipra; + uint16_t iprb; + uint16_t iprc; + uint16_t iprd; + uint32_t intpri00; + uint32_t intmsk00; /* Cache */ uint32_t ccr; @@ -207,6 +215,16 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) return porta_lines(s); case SH7750_PDTRB_A7: return portb_lines(s); + case 0x1fd00000: + return s->icr; + case 0x1fd00004: + return s->ipra; + case 0x1fd00008: + return s->iprb; + case 0x1fd0000c: + return s->iprc; + case 0x1fd00010: + return s->iprd; default: error_access("word read", addr); assert(0); @@ -242,6 +260,14 @@ static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) return 0x00110000; /* Minimum caches */ case 0x1f000044: /* Processor version PRR */ return 0x00000100; /* SH7750R */ + case 0x1e080000: + return s->intpri00; + case 0x1e080020: + return 0; + case 0x1e080040: + return s->intmsk00; + case 0x1e080060: + return 0; default: error_access("long read", addr); assert(0); @@ -300,6 +326,21 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, assert(0); } return; + case 0x1fd00000: + s->icr = mem_value; + return; + case 0x1fd00004: + s->ipra = mem_value; + return; + case 0x1fd00008: + s->iprb = mem_value; + return; + case 0x1fd0000c: + s->iprc = mem_value; + return; + case 0x1fd00010: + s->iprd = mem_value; + return; default: error_access("word write", addr); assert(0); @@ -364,6 +405,16 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, case SH7750_CCR_A7: s->ccr = mem_value; return; + case 0x1e080000: + s->intpri00 = mem_value; + return; + case 0x1e080020: + return; + case 0x1e080040: + s->intmsk00 = mem_value; + return; + case 0x1e080060: + return; default: error_access("long write", addr); assert(0); -- cgit v1.2.3 From ed8e0a4d4b57d90c8e049bfd030c6829625c47af Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:51:40 +0000 Subject: Add FRQCR read support, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3272 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sh7750.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/sh7750.c b/hw/sh7750.c index 8ff6ca194..bd3d31e36 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -207,6 +207,8 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) SH7750State *s = opaque; switch (addr) { + case SH7750_FRQCR_A7: + return 0; case SH7750_RFCR_A7: fprintf(stderr, "Read access to refresh count register, incrementing\n"); -- cgit v1.2.3 From c5e814b2719572abafc4359ef8ec3effd2087233 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:52:22 +0000 Subject: Fix rte opcode, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3273 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index fe3d0e945..35b6f08dc 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -277,7 +277,7 @@ void decode_opc(DisasContext * ctx) case 0x0038: /* ldtlb */ assert(0); /* XXXXX */ return; - case 0x004b: /* rte */ + case 0x002b: /* rte */ CHECK_NOT_DELAY_SLOT gen_op_rte(); ctx->flags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; -- cgit v1.2.3 From 8915ee7414146babf3ea58e73417f0ad274b88e4 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 19:55:21 +0000 Subject: Enable sh4-softmmu and sh4-linux-user builds by default, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3274 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 46a24171e..bba550719 100755 --- a/configure +++ b/configure @@ -497,11 +497,11 @@ 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 mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu sh4-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user ppc64-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user ppc64-linux-user sh4-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then -- cgit v1.2.3 From ff1aaf65e75da9f4f4d67b2c654ace1e51f25da0 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 21:18:26 +0000 Subject: Update tarbin rule. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3275 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index c7af33413..070b25886 100644 --- a/Makefile +++ b/Makefile @@ -144,6 +144,8 @@ tarbin: $(bindir)/qemu-system-mips64 \ $(bindir)/qemu-system-mips64el \ $(bindir)/qemu-system-arm \ + $(bindir)/qemu-system-m68k \ + $(bindir)/qemu-system-sh4 \ $(bindir)/qemu-i386 \ $(bindir)/qemu-arm \ $(bindir)/qemu-armeb \ @@ -153,6 +155,8 @@ tarbin: $(bindir)/qemu-mips \ $(bindir)/qemu-mipsel \ $(bindir)/qemu-alpha \ + $(bindir)/qemu-m68k \ + $(bindir)/qemu-sh4 \ $(bindir)/qemu-img \ $(datadir)/bios.bin \ $(datadir)/vgabios.bin \ -- cgit v1.2.3 From 4887d78b01594d994d51db8d11c1a04e65fca032 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 29 Sep 2007 21:22:33 +0000 Subject: Don't hardcode the host architecture name. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3276 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 070b25886..67bcf85ac 100644 --- a/Makefile +++ b/Makefile @@ -132,7 +132,7 @@ tar: # generate a binary distribution tarbin: - ( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \ + ( cd / ; tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \ $(bindir)/qemu \ $(bindir)/qemu-system-ppc \ $(bindir)/qemu-system-ppc64 \ -- cgit v1.2.3 From a062e36c58738321295e1031bebb1b89a0cdf01a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 00:38:38 +0000 Subject: Implement the PowerPC alternate time-base, following the 2.04 specification. Share most code with the time-base management routines. Remove time-base write routines from user-mode emulation environments. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3277 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 18 ++------- hw/ppc.c | 95 ++++++++++++++++++++++++++++++++++----------- linux-user/main.c | 22 ++--------- target-ppc/cpu.h | 8 +++- target-ppc/op.c | 24 ++++++++++++ target-ppc/translate_init.c | 24 ++++++++++++ 6 files changed, 134 insertions(+), 57 deletions(-) diff --git a/darwin-user/main.c b/darwin-user/main.c index affd87454..45495ed45 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -124,24 +124,14 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) return cpu_ppc_get_tb(env) >> 32; } -static void cpu_ppc_store_tb (CPUState *env, uint64_t value) +uint32_t cpu_ppc_load_atbl (CPUState *env) { - /* TO FIX */ -} - -void cpu_ppc_store_tbu (CPUState *env, uint32_t value) -{ - cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); -} - -void cpu_ppc_store_tbl (CPUState *env, uint32_t value) -{ - cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; } -void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value) +uint32_t cpu_ppc_load_atbu (CPUState *env) { - cpu_ppc_store_tbu( env, value ); + return cpu_ppc_get_tb(env) >> 32; } uint32_t cpu_ppc601_load_rtcu (CPUState *env) diff --git a/hw/ppc.c b/hw/ppc.c index 20ee532da..270097bf1 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -408,6 +408,7 @@ void ppc405_irq_init (CPUState *env) struct ppc_tb_t { /* Time base management */ int64_t tb_offset; /* Compensation */ + int64_t atb_offset; /* Compensation */ uint32_t tb_freq; /* TB frequency */ /* Decrementer management */ uint64_t decr_next; /* Tick for next decr interrupt */ @@ -422,7 +423,7 @@ struct ppc_tb_t { void *opaque; }; -static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env) +static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, int64_t tb_offset) { /* TB time in tb periods */ return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, @@ -434,19 +435,10 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env); -#ifdef PPC_DEBUG_TB - { - static int last_time; - int now; - now = time(NULL); - if (last_time != now) { - last_time = now; - if (loglevel != 0) { - fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n", - __func__, tb, now, tb_env->tb_offset); - } - } + tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); +#if defined(PPC_DEBUG_TB) + if (loglevel != 0) { + fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); } #endif @@ -458,7 +450,7 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env); + tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); @@ -468,32 +460,89 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) return tb >> 32; } -static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) +static inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, int64_t *tb_offsetp, + uint64_t value) { - tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) + *tb_offsetp = muldiv64(value, ticks_per_sec, tb_env->tb_freq) - qemu_get_clock(vm_clock); #ifdef PPC_DEBUG_TB if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value, - tb_env->tb_offset); + *tb_offsetp); } #endif } +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); + tb &= 0xFFFFFFFF00000000ULL; + cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, tb | (uint64_t)value); +} + void cpu_ppc_store_tbu (CPUState *env, uint32_t value) { ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; - cpu_ppc_store_tb(tb_env, - ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); + tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); + tb &= 0x00000000FFFFFFFFULL; + cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, + ((uint64_t)value << 32) | tb); } -void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +uint32_t cpu_ppc_load_atbl (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); +#if defined(PPC_DEBUG_TB) + if (loglevel != 0) { + fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); + } +#endif + + return tb & 0xFFFFFFFF; +} + +uint32_t cpu_ppc_load_atbu (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); +#if defined(PPC_DEBUG_TB) + if (loglevel != 0) { + fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); + } +#endif + + return tb >> 32; +} + +void cpu_ppc_store_atbl (CPUState *env, uint32_t value) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; + + tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); + tb &= 0xFFFFFFFF00000000ULL; + cpu_ppc_store_tb(tb_env, &tb_env->atb_offset, tb | (uint64_t)value); +} + +void cpu_ppc_store_atbu (CPUState *env, uint32_t value) { ppc_tb_t *tb_env = env->tb_env; + uint64_t tb; - cpu_ppc_store_tb(tb_env, - ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); + tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); + tb &= 0x00000000FFFFFFFFULL; + cpu_ppc_store_tb(tb_env, &tb_env->atb_offset, + ((uint64_t)value << 32) | tb); } static inline uint32_t _cpu_ppc_load_decr (CPUState *env, uint64_t *next) diff --git a/linux-user/main.c b/linux-user/main.c index fb424ad88..a06a7067b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -664,7 +664,6 @@ void cpu_loop (CPUSPARCState *env) #endif #ifdef TARGET_PPC - static inline uint64_t cpu_ppc_get_tb (CPUState *env) { /* TO FIX */ @@ -681,32 +680,19 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) return cpu_ppc_get_tb(env) >> 32; } -static void cpu_ppc_store_tb (CPUState *env, uint64_t value) -{ - /* TO FIX */ -} - -void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +uint32_t cpu_ppc_load_atbl (CPUState *env) { - cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; } -void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +uint32_t cpu_ppc_load_atbu (CPUState *env) { - cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); + return cpu_ppc_get_tb(env) >> 32; } -void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value) -__attribute__ (( alias ("cpu_ppc_store_tbu") )); - uint32_t cpu_ppc601_load_rtcu (CPUState *env) __attribute__ (( alias ("cpu_ppc_load_tbu") )); -void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value) -{ - cpu_ppc_store_tbl(env, value & 0x3FFFFF80); -} - uint32_t cpu_ppc601_load_rtcl (CPUState *env) { return cpu_ppc_load_tbl(env) & 0x3FFFFF80; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 21c3061f4..e4d12163a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -625,6 +625,10 @@ uint32_t cpu_ppc_load_tbl (CPUPPCState *env); uint32_t cpu_ppc_load_tbu (CPUPPCState *env); void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); +uint32_t cpu_ppc_load_atbl (CPUPPCState *env); +uint32_t cpu_ppc_load_atbu (CPUPPCState *env); +void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value); +void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value); uint32_t cpu_ppc_load_decr (CPUPPCState *env); void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); #if defined(TARGET_PPC64H) @@ -798,8 +802,8 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_BOOKE_SPEFSCR (0x200) #define SPR_E500_BBEAR (0x201) #define SPR_E500_BBTAR (0x202) -#define SPR_BOOKE_ATBL (0x20E) -#define SPR_BOOKE_ATBU (0x20F) +#define SPR_ATBL (0x20E) +#define SPR_ATBU (0x20F) #define SPR_IBAT0U (0x210) #define SPR_BOOKE_IVOR32 (0x210) #define SPR_IBAT0L (0x211) diff --git a/target-ppc/op.c b/target-ppc/op.c index 976eb5304..4622534c2 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -423,6 +423,18 @@ void OPPROTO op_load_tbu (void) RETURN(); } +void OPPROTO op_load_atbl (void) +{ + T0 = cpu_ppc_load_atbl(env); + RETURN(); +} + +void OPPROTO op_load_atbu (void) +{ + T0 = cpu_ppc_load_atbu(env); + RETURN(); +} + #if !defined(CONFIG_USER_ONLY) void OPPROTO op_store_tbl (void) { @@ -436,6 +448,18 @@ void OPPROTO op_store_tbu (void) RETURN(); } +void OPPROTO op_store_atbl (void) +{ + cpu_ppc_store_atbl(env, T0); + RETURN(); +} + +void OPPROTO op_store_atbu (void) +{ + cpu_ppc_store_atbu(env, T0); + RETURN(); +} + void OPPROTO op_load_decr (void) { T0 = cpu_ppc_load_decr(env); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 53a6abf9c..285e35143 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -162,6 +162,18 @@ static void spr_read_tbu (void *opaque, int sprn) gen_op_load_tbu(); } +__attribute__ (( unused )) +static void spr_read_atbl (void *opaque, int sprn) +{ + gen_op_load_atbl(); +} + +__attribute__ (( unused )) +static void spr_read_atbu (void *opaque, int sprn) +{ + gen_op_load_atbu(); +} + #if !defined(CONFIG_USER_ONLY) static void spr_write_tbl (void *opaque, int sprn) { @@ -172,6 +184,18 @@ static void spr_write_tbu (void *opaque, int sprn) { gen_op_store_tbu(); } + +__attribute__ (( unused )) +static void spr_write_atbl (void *opaque, int sprn) +{ + gen_op_store_atbl(); +} + +__attribute__ (( unused )) +static void spr_write_atbu (void *opaque, int sprn) +{ + gen_op_store_atbu(); +} #endif #if !defined(CONFIG_USER_ONLY) -- cgit v1.2.3 From a09d88b86a27f23709257bebe403cb4656f157e3 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 30 Sep 2007 00:45:51 +0000 Subject: Update TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3278 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 7 ------- 1 file changed, 7 deletions(-) diff --git a/target-mips/TODO b/target-mips/TODO index 784c95507..78310dda8 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -4,13 +4,6 @@ Unsolved issues/bugs in the mips/mipsel backend General ------- - [ls][dw][lr] report broken (aligned) BadVAddr -- Missing per-CPU instruction decoding, currently all implemented - instructions are regarded as valid -- Applications running on top of a emulated Linux segfault sometimes - when the Qemu FPU emulation is disabled, the tb misses a flush - in that case. -- gdb breakpoints inside the emulated system work only due to a hack - which disassembles over the end of the current tb. MIPS64 ------ -- cgit v1.2.3 From bfa1e5cf0abccb74e8de2c135e7d9f1f509730a9 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 00:50:23 +0000 Subject: XER is to be treated as a 64 bits register on 64 bits implementations, according to the PowerPC 2.04 specification. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3279 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 4 ++-- target-ppc/helper.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e4d12163a..791f30524 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -603,8 +603,8 @@ void ppc_store_asr (CPUPPCState *env, target_ulong value); target_ulong do_load_sr (CPUPPCState *env, int srnum); void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif -uint32_t ppc_load_xer (CPUPPCState *env); -void ppc_store_xer (CPUPPCState *env, uint32_t value); +target_ulong ppc_load_xer (CPUPPCState *env); +void ppc_store_xer (CPUPPCState *env, target_ulong value); target_ulong do_load_msr (CPUPPCState *env); void do_store_msr (CPUPPCState *env, target_ulong value); void ppc_store_msr_32 (CPUPPCState *env, uint32_t value); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 8b6bed1e5..4d629d41f 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1644,7 +1644,7 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) } #endif /* !defined (CONFIG_USER_ONLY) */ -uint32_t ppc_load_xer (CPUPPCState *env) +target_ulong ppc_load_xer (CPUPPCState *env) { return (xer_so << XER_SO) | (xer_ov << XER_OV) | @@ -1653,7 +1653,7 @@ uint32_t ppc_load_xer (CPUPPCState *env) (xer_cmp << XER_CMP); } -void ppc_store_xer (CPUPPCState *env, uint32_t value) +void ppc_store_xer (CPUPPCState *env, target_ulong value) { xer_so = (value >> XER_SO) & 0x01; xer_ov = (value >> XER_OV) & 0x01; -- cgit v1.2.3 From 477023a6038e8f457c604b138198f76d093b9a87 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 01:01:08 +0000 Subject: Improve single-precision floats load & stores: as the PowerPC registers only store double-precision floats, use float64_to_float32 & float32_to_float64 to do the appropriate conversion. Implement stfiwx. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3280 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_mem.h | 67 +++++++++++++++++++++++++++++++++++++--------- target-ppc/translate.c | 72 ++++++++++++++++++++++---------------------------- 2 files changed, 87 insertions(+), 52 deletions(-) diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 13440817b..71dfb1e34 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -403,11 +403,30 @@ void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void) \ } #endif +static inline void glue(stfs, MEMSUFFIX) (target_ulong EA, double d) +{ + glue(stfl, MEMSUFFIX)(EA, float64_to_float32(d, &env->fp_status)); +} + +static inline void glue(stfiwx, MEMSUFFIX) (target_ulong EA, double d) +{ + union { + double d; + uint64_t u; + } u; + + /* Store the low order 32 bits without any conversion */ + u.d = d; + glue(stl, MEMSUFFIX)(EA, u.u); +} + PPC_STF_OP(fd, stfq); -PPC_STF_OP(fs, stfl); +PPC_STF_OP(fs, stfs); +PPC_STF_OP(fiwx, stfiwx); #if defined(TARGET_PPC64) PPC_STF_OP_64(fd, stfq); -PPC_STF_OP_64(fs, stfl); +PPC_STF_OP_64(fs, stfs); +PPC_STF_OP_64(fiwx, stfiwx); #endif static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) @@ -429,14 +448,14 @@ static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) glue(stfq, MEMSUFFIX)(EA, u.d); } -static inline void glue(stflr, MEMSUFFIX) (target_ulong EA, float f) +static inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, double d) { union { float f; uint32_t u; } u; - u.f = f; + u.f = float64_to_float32(d, &env->fp_status); u.u = ((u.u & 0xFF000000UL) >> 24) | ((u.u & 0x00FF0000ULL) >> 8) | ((u.u & 0x0000FF00UL) << 8) | @@ -444,11 +463,30 @@ static inline void glue(stflr, MEMSUFFIX) (target_ulong EA, float f) glue(stfl, MEMSUFFIX)(EA, u.f); } +static inline void glue(stfiwxr, MEMSUFFIX) (target_ulong EA, double d) +{ + union { + double d; + uint64_t u; + } u; + + /* Store the low order 32 bits without any conversion */ + u.d = d; + u.u = ((u.u & 0xFF000000UL) >> 24) | + ((u.u & 0x00FF0000ULL) >> 8) | + ((u.u & 0x0000FF00UL) << 8) | + ((u.u & 0x000000FFULL) << 24); + glue(stl, MEMSUFFIX)(EA, u.u); +} + + PPC_STF_OP(fd_le, stfqr); -PPC_STF_OP(fs_le, stflr); +PPC_STF_OP(fs_le, stfsr); +PPC_STF_OP(fiwx_le, stfiwxr); #if defined(TARGET_PPC64) PPC_STF_OP_64(fd_le, stfqr); -PPC_STF_OP_64(fs_le, stflr); +PPC_STF_OP_64(fs_le, stfsr); +PPC_STF_OP_64(fiwx_le, stfiwxr); #endif /*** Floating-point load ***/ @@ -468,11 +506,16 @@ void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void) \ } #endif +static inline double glue(ldfs, MEMSUFFIX) (target_ulong EA) +{ + return float32_to_float64(glue(ldfl, MEMSUFFIX)(EA), &env->fp_status); +} + PPC_LDF_OP(fd, ldfq); -PPC_LDF_OP(fs, ldfl); +PPC_LDF_OP(fs, ldfs); #if defined(TARGET_PPC64) PPC_LDF_OP_64(fd, ldfq); -PPC_LDF_OP_64(fs, ldfl); +PPC_LDF_OP_64(fs, ldfs); #endif static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) @@ -495,7 +538,7 @@ static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) return u.d; } -static inline float glue(ldflr, MEMSUFFIX) (target_ulong EA) +static inline double glue(ldfsr, MEMSUFFIX) (target_ulong EA) { union { float f; @@ -508,14 +551,14 @@ static inline float glue(ldflr, MEMSUFFIX) (target_ulong EA) ((u.u & 0x0000FF00UL) << 8) | ((u.u & 0x000000FFULL) << 24); - return u.f; + return float32_to_float64(u.f, &env->fp_status); } PPC_LDF_OP(fd_le, ldfqr); -PPC_LDF_OP(fs_le, ldflr); +PPC_LDF_OP(fs_le, ldfsr); #if defined(TARGET_PPC64) PPC_LDF_OP_64(fd_le, ldfqr); -PPC_LDF_OP_64(fs_le, ldflr); +PPC_LDF_OP_64(fs_le, ldfsr); #endif /* Load and set reservation */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e88cfafae..7f84ed7d6 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2581,8 +2581,8 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03CF0801, PPC_MEM_SYNC) } /*** Floating-point load ***/ -#define GEN_LDF(width, opc) \ -GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +#define GEN_LDF(width, opc, type) \ +GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ @@ -2593,8 +2593,8 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ } -#define GEN_LDUF(width, opc) \ -GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +#define GEN_LDUF(width, opc, type) \ +GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ @@ -2610,8 +2610,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } -#define GEN_LDUXF(width, opc) \ -GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +#define GEN_LDUXF(width, opc, type) \ +GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ @@ -2627,8 +2627,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } -#define GEN_LDXF(width, opc2, opc3) \ -GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ +#define GEN_LDXF(width, opc2, opc3, type) \ +GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ @@ -2639,21 +2639,21 @@ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ } -#define GEN_LDFS(width, op) \ +#define GEN_LDFS(width, op, type) \ OP_LD_TABLE(width); \ -GEN_LDF(width, op | 0x20); \ -GEN_LDUF(width, op | 0x21); \ -GEN_LDUXF(width, op | 0x01); \ -GEN_LDXF(width, 0x17, op | 0x00) +GEN_LDF(width, op | 0x20, type); \ +GEN_LDUF(width, op | 0x21, type); \ +GEN_LDUXF(width, op | 0x01, type); \ +GEN_LDXF(width, 0x17, op | 0x00, type) /* lfd lfdu lfdux lfdx */ -GEN_LDFS(fd, 0x12); +GEN_LDFS(fd, 0x12, PPC_FLOAT); /* lfs lfsu lfsux lfsx */ -GEN_LDFS(fs, 0x10); +GEN_LDFS(fs, 0x10, PPC_FLOAT); /*** Floating-point store ***/ -#define GEN_STF(width, opc) \ -GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +#define GEN_STF(width, opc, type) \ +GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ @@ -2664,8 +2664,8 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ op_ldst(st##width); \ } -#define GEN_STUF(width, opc) \ -GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ +#define GEN_STUF(width, opc, type) \ +GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ @@ -2681,8 +2681,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } -#define GEN_STUXF(width, opc) \ -GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ +#define GEN_STUXF(width, opc, type) \ +GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ @@ -2698,8 +2698,8 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } -#define GEN_STXF(width, opc2, opc3) \ -GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ +#define GEN_STXF(width, opc2, opc3, type) \ +GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ @@ -2710,30 +2710,22 @@ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ op_ldst(st##width); \ } -#define GEN_STFS(width, op) \ +#define GEN_STFS(width, op, type) \ OP_ST_TABLE(width); \ -GEN_STF(width, op | 0x20); \ -GEN_STUF(width, op | 0x21); \ -GEN_STUXF(width, op | 0x01); \ -GEN_STXF(width, 0x17, op | 0x00) +GEN_STF(width, op | 0x20, type); \ +GEN_STUF(width, op | 0x21, type); \ +GEN_STUXF(width, op | 0x01, type); \ +GEN_STXF(width, 0x17, op | 0x00, type) /* stfd stfdu stfdux stfdx */ -GEN_STFS(fd, 0x16); +GEN_STFS(fd, 0x16, PPC_FLOAT); /* stfs stfsu stfsux stfsx */ -GEN_STFS(fs, 0x14); +GEN_STFS(fs, 0x14, PPC_FLOAT); /* Optional: */ /* stfiwx */ -GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT_STFIWX) -{ - if (unlikely(!ctx->fpu_enabled)) { - GEN_EXCP_NO_FP(ctx); - return; - } - gen_addr_reg_index(ctx); - /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */ - GEN_EXCP_INVAL(ctx); -} +OP_ST_TABLE(fiwx); +GEN_STXF(fiwx, 0x17, 0x1E, PPC_FLOAT_STFIWX); /*** Branch ***/ static inline void gen_goto_tb (DisasContext *ctx, int n, target_ulong dest) -- cgit v1.2.3 From d7e4b87e53923542c1a7220e08bcae2252f5a22e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 01:11:48 +0000 Subject: Implement new floating-point instructions (fre, frin, friz, frip, frim) as defined in the PowerPC 2.04 specification. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3281 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 31 ++++++++++++++++++++++++++++ target-ppc/op_helper.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ target-ppc/op_helper.h | 5 +++++ target-ppc/translate.c | 14 +++++++++++++ 4 files changed, 106 insertions(+) diff --git a/target-ppc/op.c b/target-ppc/op.c index 4622534c2..46843d790 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1701,6 +1701,13 @@ void OPPROTO op_fsqrt (void) RETURN(); } +/* fre - fre. */ +void OPPROTO op_fre (void) +{ + do_fre(); + RETURN(); +} + /* fres - fres. */ void OPPROTO op_fres (void) { @@ -1806,6 +1813,30 @@ void OPPROTO op_fctidz (void) } #endif +void OPPROTO op_frin (void) +{ + do_frin(); + RETURN(); +} + +void OPPROTO op_friz (void) +{ + do_friz(); + RETURN(); +} + +void OPPROTO op_frip (void) +{ + do_frip(); + RETURN(); +} + +void OPPROTO op_frim (void) +{ + do_frim(); + RETURN(); +} + /*** Floating-Point compare ***/ /* fcmpu */ void OPPROTO op_fcmpu (void) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 9a79953f7..08441caae 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -700,6 +700,36 @@ void do_fctidz (void) #endif +static inline void do_fri (int rounding_mode) +{ + int curmode; + + curmode = env->fp_status.float_rounding_mode; + set_float_rounding_mode(rounding_mode, &env->fp_status); + FT0 = float64_round_to_int(FT0, &env->fp_status); + set_float_rounding_mode(curmode, &env->fp_status); +} + +void do_frin (void) +{ + do_fri(float_round_nearest_even); +} + +void do_friz (void) +{ + do_fri(float_round_to_zero); +} + +void do_frip (void) +{ + do_fri(float_round_up); +} + +void do_frim (void) +{ + do_fri(float_round_down); +} + #if USE_PRECISE_EMULATION void do_fmadd (void) { @@ -789,6 +819,32 @@ void do_fsqrt (void) FT0 = float64_sqrt(FT0, &env->fp_status); } +void do_fre (void) +{ + union { + double d; + uint64_t i; + } p; + + if (likely(isnormal(FT0))) { + FT0 = float64_div(1.0, FT0, &env->fp_status); + } else { + p.d = FT0; + if (p.i == 0x8000000000000000ULL) { + p.i = 0xFFF0000000000000ULL; + } else if (p.i == 0x0000000000000000ULL) { + p.i = 0x7FF0000000000000ULL; + } else if (isnan(FT0)) { + p.i = 0x7FF8000000000000ULL; + } else if (FT0 < 0.0) { + p.i = 0x8000000000000000ULL; + } else { + p.i = 0x0000000000000000ULL; + } + FT0 = p.d; + } +} + void do_fres (void) { union { diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 4db8ac530..6c0d2fbf9 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -94,6 +94,7 @@ void do_popcntb_64 (void); /* Floating-point arithmetic helpers */ void do_fsqrt (void); +void do_fre (void); void do_fres (void); void do_frsqrte (void); void do_fsel (void); @@ -110,6 +111,10 @@ void do_fcfid (void); void do_fctid (void); void do_fctidz (void); #endif +void do_frin (void); +void do_friz (void); +void do_frip (void); +void do_frim (void); void do_fcmpu (void); void do_fcmpo (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 7f84ed7d6..f4ff22e38 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -476,6 +476,8 @@ enum { PPC_RFMCI = 0x0000020000000000ULL, /* user-mode DCR access, implemented in PowerPC 460 */ PPC_DCRUX = 0x0000040000000000ULL, + /* New floating-point extensions (PowerPC 2.0x) */ + PPC_FLOAT_EXT = 0x0000080000000000ULL, }; /*****************************************************************************/ @@ -1660,6 +1662,9 @@ GEN_FLOAT_AB(div, 0x12, 0x000007C0); /* fmul - fmuls */ GEN_FLOAT_AC(mul, 0x19, 0x0000F800); +/* fre */ +GEN_FLOAT_BS(re, 0x3F, 0x18, PPC_FLOAT_EXT); + /* fres */ GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES); @@ -1727,6 +1732,15 @@ GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B); GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B); #endif +/* frin */ +GEN_FLOAT_B(rin, 0x08, 0x0C, PPC_FLOAT_EXT); +/* friz */ +GEN_FLOAT_B(riz, 0x08, 0x0D, PPC_FLOAT_EXT); +/* frip */ +GEN_FLOAT_B(rip, 0x08, 0x0E, PPC_FLOAT_EXT); +/* frim */ +GEN_FLOAT_B(rim, 0x08, 0x0F, PPC_FLOAT_EXT); + /*** Floating-Point compare ***/ /* fcmpo */ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) -- cgit v1.2.3 From c80f84e3c037ebaebcec48f59c65be02a6d76a89 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 01:18:26 +0000 Subject: Implement Process Priority Register as defined in the PowerPC 2.04 spec. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3282 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 8 ++++++++ target-ppc/op_helper.c | 8 ++++++++ target-ppc/op_helper.h | 3 +++ target-ppc/translate.c | 20 ++++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/target-ppc/op.c b/target-ppc/op.c index 46843d790..fa8477ab9 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -295,6 +295,14 @@ void OPPROTO op_store_xer (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_store_pri (void) +{ + do_store_pri(PARAM1); + RETURN(); +} +#endif + #if !defined(CONFIG_USER_ONLY) /* Segment registers load and store */ void OPPROTO op_load_sr (void) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 08441caae..d75331722 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -112,6 +112,14 @@ void do_store_xer (void) xer_bc = (T0 >> XER_BC) & 0x7F; } +#if defined(TARGET_PPC64) +void do_store_pri (int prio) +{ + env->spr[SPR_PPR] &= ~0x001C000000000000ULL; + env->spr[SPR_PPR] |= ((uint64_t)prio & 0x7) << 50; +} +#endif + void do_load_fpscr (void) { /* The 32 MSB of the target fpr are undefined. diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 6c0d2fbf9..c5b4f2d19 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -57,6 +57,9 @@ void do_load_cr (void); void do_store_cr (uint32_t mask); void do_load_xer (void); void do_store_xer (void); +#if defined(TARGET_PPC64) +void do_store_pri (int prio); +#endif void do_load_fpscr (void); void do_store_fpscr (uint32_t mask); target_ulong ppc_load_dump_spr (int sprn); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f4ff22e38..08cd92cde 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1124,6 +1124,26 @@ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) } else if (unlikely(Rc(ctx->opcode) != 0)) { gen_op_load_gpr_T0(rs); gen_set_Rc0(ctx); +#if defined(TARGET_PPC64) + } else { + switch (rs) { + case 1: + /* Set process priority to low */ + gen_op_store_pri(2); + break; + case 6: + /* Set process priority to medium-low */ + gen_op_store_pri(3); + break; + case 2: + /* Set process priority to normal */ + gen_op_store_pri(4); + break; + default: + /* nop */ + break; + } +#endif } } -- cgit v1.2.3 From 868d585aced5457218b3443398d08594d9c3ba6d Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 01:29:07 +0000 Subject: Avoid crash on NULL timers. This is a rework of Stefan Weil proposed patch. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3283 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index c2c0decc8..da61313f1 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -161,10 +161,9 @@ static void set_alarm (m48t59_t *NVRAM, struct tm *tm) NVRAM->alarm = mktime(tm); if (NVRAM->alrm_timer != NULL) { qemu_del_timer(NVRAM->alrm_timer); - NVRAM->alrm_timer = NULL; + if (NVRAM->alarm - time(NULL) > 0) + qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); } - if (NVRAM->alarm - time(NULL) > 0) - qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); } /* Watchdog management */ @@ -188,15 +187,14 @@ static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) { uint64_t interval; /* in 1/16 seconds */ + NVRAM->buffer[0x1FF0] &= ~0x80; if (NVRAM->wd_timer != NULL) { qemu_del_timer(NVRAM->wd_timer); - NVRAM->wd_timer = NULL; - } - NVRAM->buffer[0x1FF0] &= ~0x80; - if (value != 0) { - interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); - qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + - ((interval * 1000) >> 4)); + if (value != 0) { + interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); + qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + + ((interval * 1000) >> 4)); + } } } -- cgit v1.2.3 From 540635ba650bd2529ce55c4135cd594a5fa109b5 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 30 Sep 2007 01:58:33 +0000 Subject: Code provision for n32/n64 mips userland emulation. Not functional yet. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3284 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 + Makefile.target | 8 ++ configure | 12 +- linux-user/main.c | 4 + linux-user/mips/syscall.h | 2 - linux-user/mips/target_signal.h | 2 +- linux-user/mips64/syscall.h | 221 ++++++++++++++++++++++++++++ linux-user/mips64/syscall_nr.h | 284 ++++++++++++++++++++++++++++++++++++ linux-user/mips64/target_signal.h | 29 ++++ linux-user/mips64/termbits.h | 245 +++++++++++++++++++++++++++++++ linux-user/mipsn32/syscall.h | 221 ++++++++++++++++++++++++++++ linux-user/mipsn32/syscall_nr.h | 288 +++++++++++++++++++++++++++++++++++++ linux-user/mipsn32/target_signal.h | 29 ++++ linux-user/mipsn32/termbits.h | 245 +++++++++++++++++++++++++++++++ linux-user/signal.c | 58 ++++++++ linux-user/syscall_defs.h | 140 +++++++++++++++++- qemu-binfmt-conf.sh | 6 +- target-mips/TODO | 2 +- target-mips/exec.h | 10 +- target-mips/helper.c | 16 +-- target-mips/mips-defs.h | 2 +- target-mips/op.c | 24 ++-- target-mips/op_helper.c | 10 +- target-mips/op_helper_mem.c | 4 +- target-mips/op_mem.c | 4 +- target-mips/op_template.c | 2 +- target-mips/translate.c | 54 +++---- target-mips/translate_init.c | 4 +- 28 files changed, 1854 insertions(+), 76 deletions(-) create mode 100644 linux-user/mips64/syscall.h create mode 100644 linux-user/mips64/syscall_nr.h create mode 100644 linux-user/mips64/target_signal.h create mode 100644 linux-user/mips64/termbits.h create mode 100644 linux-user/mipsn32/syscall.h create mode 100644 linux-user/mipsn32/syscall_nr.h create mode 100644 linux-user/mipsn32/target_signal.h create mode 100644 linux-user/mipsn32/termbits.h diff --git a/Makefile b/Makefile index 67bcf85ac..5ed7eb5c4 100644 --- a/Makefile +++ b/Makefile @@ -154,6 +154,10 @@ tarbin: $(bindir)/qemu-ppc64 \ $(bindir)/qemu-mips \ $(bindir)/qemu-mipsel \ + $(bindir)/qemu-mipsn32 \ + $(bindir)/qemu-mipsn32el \ + $(bindir)/qemu-mips64 \ + $(bindir)/qemu-mips64el \ $(bindir)/qemu-alpha \ $(bindir)/qemu-m68k \ $(bindir)/qemu-sh4 \ diff --git a/Makefile.target b/Makefile.target index 0f190cfa0..9b0459ec1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -4,6 +4,9 @@ TARGET_BASE_ARCH:=$(TARGET_ARCH) ifeq ($(TARGET_ARCH), x86_64) TARGET_BASE_ARCH:=i386 endif +ifeq ($(TARGET_ARCH), mipsn32) +TARGET_BASE_ARCH:=mips +endif ifeq ($(TARGET_ARCH), mips64) TARGET_BASE_ARCH:=mips endif @@ -50,6 +53,11 @@ ifeq ($(TARGET_ARCH),mips) TARGET_ARCH2=mipsel endif endif +ifeq ($(TARGET_ARCH),mipsn32) + ifneq ($(TARGET_WORDS_BIGENDIAN),yes) + TARGET_ARCH2=mipsn32el + endif +endif ifeq ($(TARGET_ARCH),mips64) ifneq ($(TARGET_WORDS_BIGENDIAN),yes) TARGET_ARCH2=mips64el diff --git a/configure b/configure index bba550719..ebc294ebe 100755 --- a/configure +++ b/configure @@ -931,6 +931,7 @@ target_bigendian="no" [ "$target_cpu" = "ppc64" ] && target_bigendian=yes [ "$target_cpu" = "ppcemb" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes +[ "$target_cpu" = "mipsn32" ] && target_bigendian=yes [ "$target_cpu" = "mips64" ] && target_bigendian=yes [ "$target_cpu" = "sh4eb" ] && target_bigendian=yes [ "$target_cpu" = "m68k" ] && target_bigendian=yes @@ -1042,15 +1043,16 @@ 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" = "mipsn32" -o "$target_cpu" = "mipsn32el" ; then + echo "TARGET_ARCH=mipsn32" >> $config_mak + echo "#define TARGET_ARCH \"mipsn32\"" >> $config_h + echo "#define TARGET_MIPS 1" >> $config_h + echo "#define TARGET_MIPSN32 1" >> $config_h elif test "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el" ; then echo "TARGET_ARCH=mips64" >> $config_mak echo "#define TARGET_ARCH \"mips64\"" >> $config_h echo "#define TARGET_MIPS 1" >> $config_h echo "#define TARGET_MIPS64 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 @@ -1090,7 +1092,7 @@ if test "$target_darwin_user" = "yes" ; then echo "#define CONFIG_DARWIN_USER 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 +if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k" -o "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" -o "$target_cpu" = "mipsn32" -o "$target_cpu" = "mipsn32el" -o "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el"; then echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h fi diff --git a/linux-user/main.c b/linux-user/main.c index a06a7067b..0b6fb977b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2145,7 +2145,11 @@ int main(int argc, char **argv) /* Choose and initialise CPU */ if (cpu_model == NULL) +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) + cpu_model = "20Kc"; +#else cpu_model = "24Kf"; +#endif mips_find_by_name(cpu_model, &def); if (def == NULL) cpu_abort(env, "Unable to find MIPS CPU definition\n"); diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 140729f00..a789348db 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -3,10 +3,8 @@ stack during a system call. */ struct target_pt_regs { -#if 1 /* Pad bytes for argument save space on the stack. */ target_ulong pad0[6]; -#endif /* Saved main processor registers. */ target_ulong regs[32]; diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h index d7611b01d..514195c03 100644 --- a/linux-user/mips/target_signal.h +++ b/linux-user/mips/target_signal.h @@ -6,7 +6,7 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; + target_long ss_sp; target_ulong ss_size; target_long ss_flags; } target_stack_t; diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h new file mode 100644 index 000000000..4ec506cb0 --- /dev/null +++ b/linux-user/mips64/syscall.h @@ -0,0 +1,221 @@ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { + /* Saved main processor registers. */ + target_ulong regs[32]; + + /* Saved special registers. */ + target_ulong cp0_status; + target_ulong lo; + target_ulong hi; + target_ulong cp0_badvaddr; + target_ulong cp0_cause; + target_ulong cp0_epc; +}; + +/* Target errno definitions taken from asm-mips/errno.h */ +#undef TARGET_ENOMSG +#define TARGET_ENOMSG 35 /* Identifier removed */ +#undef TARGET_EIDRM +#define TARGET_EIDRM 36 /* Identifier removed */ +#undef TARGET_ECHRNG +#define TARGET_ECHRNG 37 /* Channel number out of range */ +#undef TARGET_EL2NSYNC +#define TARGET_EL2NSYNC 38 /* Level 2 not synchronized */ +#undef TARGET_EL3HLT +#define TARGET_EL3HLT 39 /* Level 3 halted */ +#undef TARGET_EL3RST +#define TARGET_EL3RST 40 /* Level 3 reset */ +#undef TARGET_ELNRNG +#define TARGET_ELNRNG 41 /* Link number out of range */ +#undef TARGET_EUNATCH +#define TARGET_EUNATCH 42 /* Protocol driver not attached */ +#undef TARGET_ENOCSI +#define TARGET_ENOCSI 43 /* No CSI structure available */ +#undef TARGET_EL2HLT +#define TARGET_EL2HLT 44 /* Level 2 halted */ +#undef TARGET_EDEADLK +#define TARGET_EDEADLK 45 /* Resource deadlock would occur */ +#undef TARGET_ENOLCK +#define TARGET_ENOLCK 46 /* No record locks available */ +#undef TARGET_EBADE +#define TARGET_EBADE 50 /* Invalid exchange */ +#undef TARGET_EBADR +#define TARGET_EBADR 51 /* Invalid request descriptor */ +#undef TARGET_EXFULL +#define TARGET_EXFULL 52 /* TARGET_Exchange full */ +#undef TARGET_ENOANO +#define TARGET_ENOANO 53 /* No anode */ +#undef TARGET_EBADRQC +#define TARGET_EBADRQC 54 /* Invalid request code */ +#undef TARGET_EBADSLT +#define TARGET_EBADSLT 55 /* Invalid slot */ +#undef TARGET_EDEADLOCK +#define TARGET_EDEADLOCK 56 /* File locking deadlock error */ +#undef TARGET_EBFONT +#define TARGET_EBFONT 59 /* Bad font file format */ +#undef TARGET_ENOSTR +#define TARGET_ENOSTR 60 /* Device not a stream */ +#undef TARGET_ENODATA +#define TARGET_ENODATA 61 /* No data available */ +#undef TARGET_ETIME +#define TARGET_ETIME 62 /* Timer expired */ +#undef TARGET_ENOSR +#define TARGET_ENOSR 63 /* Out of streams resources */ +#undef TARGET_ENONET +#define TARGET_ENONET 64 /* Machine is not on the network */ +#undef TARGET_ENOPKG +#define TARGET_ENOPKG 65 /* Package not installed */ +#undef TARGET_EREMOTE +#define TARGET_EREMOTE 66 /* Object is remote */ +#undef TARGET_ENOLINK +#define TARGET_ENOLINK 67 /* Link has been severed */ +#undef TARGET_EADV +#define TARGET_EADV 68 /* Advertise error */ +#undef TARGET_ESRMNT +#define TARGET_ESRMNT 69 /* Srmount error */ +#undef TARGET_ECOMM +#define TARGET_ECOMM 70 /* Communication error on send */ +#undef TARGET_EPROTO +#define TARGET_EPROTO 71 /* Protocol error */ +#undef TARGET_EDOTDOT +#define TARGET_EDOTDOT 73 /* RFS specific error */ +#undef TARGET_EMULTIHOP +#define TARGET_EMULTIHOP 74 /* Multihop attempted */ +#undef TARGET_EBADMSG +#define TARGET_EBADMSG 77 /* Not a data message */ +#undef TARGET_ENAMETOOLONG +#define TARGET_ENAMETOOLONG 78 /* File name too long */ +#undef TARGET_EOVERFLOW +#define TARGET_EOVERFLOW 79 /* Value too large for defined data type */ +#undef TARGET_ENOTUNIQ +#define TARGET_ENOTUNIQ 80 /* Name not unique on network */ +#undef TARGET_EBADFD +#define TARGET_EBADFD 81 /* File descriptor in bad state */ +#undef TARGET_EREMCHG +#define TARGET_EREMCHG 82 /* Remote address changed */ +#undef TARGET_ELIBACC +#define TARGET_ELIBACC 83 /* Can not access a needed shared library */ +#undef TARGET_ELIBBAD +#define TARGET_ELIBBAD 84 /* Accessing a corrupted shared library */ +#undef TARGET_ELIBSCN +#define TARGET_ELIBSCN 85 /* .lib section in a.out corrupted */ +#undef TARGET_ELIBMAX +#define TARGET_ELIBMAX 86 /* Attempting to link in too many shared libraries */ +#undef TARGET_ELIBEXEC +#define TARGET_ELIBEXEC 87 /* Cannot exec a shared library directly */ +#undef TARGET_EILSEQ +#define TARGET_EILSEQ 88 /* Illegal byte sequence */ +#undef TARGET_ENOSYS +#define TARGET_ENOSYS 89 /* Function not implemented */ +#undef TARGET_ELOOP +#define TARGET_ELOOP 90 /* Too many symbolic links encountered */ +#undef TARGET_ERESTART +#define TARGET_ERESTART 91 /* Interrupted system call should be restarted */ +#undef TARGET_ESTRPIPE +#define TARGET_ESTRPIPE 92 /* Streams pipe error */ +#undef TARGET_ENOTEMPTY +#define TARGET_ENOTEMPTY 93 /* Directory not empty */ +#undef TARGET_EUSERS +#define TARGET_EUSERS 94 /* Too many users */ +#undef TARGET_ENOTSOCK +#define TARGET_ENOTSOCK 95 /* Socket operation on non-socket */ +#undef TARGET_EDESTADDRREQ +#define TARGET_EDESTADDRREQ 96 /* Destination address required */ +#undef TARGET_EMSGSIZE +#define TARGET_EMSGSIZE 97 /* Message too long */ +#undef TARGET_EPROTOTYPE +#define TARGET_EPROTOTYPE 98 /* Protocol wrong type for socket */ +#undef TARGET_ENOPROTOOPT +#define TARGET_ENOPROTOOPT 99 /* Protocol not available */ +#undef TARGET_EPROTONOSUPPORT +#define TARGET_EPROTONOSUPPORT 120 /* Protocol not supported */ +#undef TARGET_ESOCKTNOSUPPORT +#define TARGET_ESOCKTNOSUPPORT 121 /* Socket type not supported */ +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ +#undef TARGET_EPFNOSUPPORT +#define TARGET_EPFNOSUPPORT 123 /* Protocol family not supported */ +#undef TARGET_EAFNOSUPPORT +#define TARGET_EAFNOSUPPORT 124 /* Address family not supported by protocol */ +#undef TARGET_EADDRINUSE +#define TARGET_EADDRINUSE 125 /* Address already in use */ +#undef TARGET_EADDRNOTAVAIL +#define TARGET_EADDRNOTAVAIL 126 /* Cannot assign requested address */ +#undef TARGET_ENETDOWN +#define TARGET_ENETDOWN 127 /* Network is down */ +#undef TARGET_ENETUNREACH +#define TARGET_ENETUNREACH 128 /* Network is unreachable */ +#undef TARGET_ENETRESET +#define TARGET_ENETRESET 129 /* Network dropped connection because of reset */ +#undef TARGET_ECONNABORTED +#define TARGET_ECONNABORTED 130 /* Software caused connection abort */ +#undef TARGET_ECONNRESET +#define TARGET_ECONNRESET 131 /* Connection reset by peer */ +#undef TARGET_ENOBUFS +#define TARGET_ENOBUFS 132 /* No buffer space available */ +#undef TARGET_EISCONN +#define TARGET_EISCONN 133 /* Transport endpoint is already connected */ +#undef TARGET_ENOTCONN +#define TARGET_ENOTCONN 134 /* Transport endpoint is not connected */ +#undef TARGET_EUCLEAN +#define TARGET_EUCLEAN 135 /* Structure needs cleaning */ +#undef TARGET_ENOTNAM +#define TARGET_ENOTNAM 137 /* Not a XENIX named type file */ +#undef TARGET_ENAVAIL +#define TARGET_ENAVAIL 138 /* No XENIX semaphores available */ +#undef TARGET_EISNAM +#define TARGET_EISNAM 139 /* Is a named type file */ +#undef TARGET_EREMOTEIO +#define TARGET_EREMOTEIO 140 /* Remote I/O error */ +#undef TARGET_EINIT +#define TARGET_EINIT 141 /* Reserved */ +#undef TARGET_EREMDEV +#define TARGET_EREMDEV 142 /* TARGET_Error 142 */ +#undef TARGET_ESHUTDOWN +#define TARGET_ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ +#undef TARGET_ETOOMANYREFS +#define TARGET_ETOOMANYREFS 144 /* Too many references: cannot splice */ +#undef TARGET_ETIMEDOUT +#define TARGET_ETIMEDOUT 145 /* Connection timed out */ +#undef TARGET_ECONNREFUSED +#define TARGET_ECONNREFUSED 146 /* Connection refused */ +#undef TARGET_EHOSTDOWN +#define TARGET_EHOSTDOWN 147 /* Host is down */ +#undef TARGET_EHOSTUNREACH +#define TARGET_EHOSTUNREACH 148 /* No route to host */ +#undef TARGET_EALREADY +#define TARGET_EALREADY 149 /* Operation already in progress */ +#undef TARGET_EINPROGRESS +#define TARGET_EINPROGRESS 150 /* Operation now in progress */ +#undef TARGET_ESTALE +#define TARGET_ESTALE 151 /* Stale NFS file handle */ +#undef TARGET_ECANCELED +#define TARGET_ECANCELED 158 /* AIO operation canceled */ +/* + * These error are Linux extensions. + */ +#undef TARGET_ENOMEDIUM +#define TARGET_ENOMEDIUM 159 /* No medium found */ +#undef TARGET_EMEDIUMTYPE +#define TARGET_EMEDIUMTYPE 160 /* Wrong medium type */ +#undef TARGET_ENOKEY +#define TARGET_ENOKEY 161 /* Required key not available */ +#undef TARGET_EKEYEXPIRED +#define TARGET_EKEYEXPIRED 162 /* Key has expired */ +#undef TARGET_EKEYREVOKED +#define TARGET_EKEYREVOKED 163 /* Key has been revoked */ +#undef TARGET_EKEYREJECTED +#define TARGET_EKEYREJECTED 164 /* Key was rejected by service */ + +/* for robust mutexes */ +#undef TARGET_EOWNERDEAD +#define TARGET_EOWNERDEAD 165 /* Owner died */ +#undef TARGET_ENOTRECOVERABLE +#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ + + + +#define UNAME_MACHINE "mips64" diff --git a/linux-user/mips64/syscall_nr.h b/linux-user/mips64/syscall_nr.h new file mode 100644 index 000000000..28e1883b7 --- /dev/null +++ b/linux-user/mips64/syscall_nr.h @@ -0,0 +1,284 @@ +/* + * Linux 64-bit syscalls are in the range from 5000 to 5999. + */ +#define TARGET_NR_Linux 5000 +#define TARGET_NR_read (TARGET_NR_Linux + 0) +#define TARGET_NR_write (TARGET_NR_Linux + 1) +#define TARGET_NR_open (TARGET_NR_Linux + 2) +#define TARGET_NR_close (TARGET_NR_Linux + 3) +#define TARGET_NR_stat (TARGET_NR_Linux + 4) +#define TARGET_NR_fstat (TARGET_NR_Linux + 5) +#define TARGET_NR_lstat (TARGET_NR_Linux + 6) +#define TARGET_NR_poll (TARGET_NR_Linux + 7) +#define TARGET_NR_lseek (TARGET_NR_Linux + 8) +#define TARGET_NR_mmap (TARGET_NR_Linux + 9) +#define TARGET_NR_mprotect (TARGET_NR_Linux + 10) +#define TARGET_NR_munmap (TARGET_NR_Linux + 11) +#define TARGET_NR_brk (TARGET_NR_Linux + 12) +#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 13) +#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 14) +#define TARGET_NR_ioctl (TARGET_NR_Linux + 15) +#define TARGET_NR_pread64 (TARGET_NR_Linux + 16) +#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 17) +#define TARGET_NR_readv (TARGET_NR_Linux + 18) +#define TARGET_NR_writev (TARGET_NR_Linux + 19) +#define TARGET_NR_access (TARGET_NR_Linux + 20) +#define TARGET_NR_pipe (TARGET_NR_Linux + 21) +#define TARGET_NR__newselect (TARGET_NR_Linux + 22) +#define TARGET_NR_sched_yield (TARGET_NR_Linux + 23) +#define TARGET_NR_mremap (TARGET_NR_Linux + 24) +#define TARGET_NR_msync (TARGET_NR_Linux + 25) +#define TARGET_NR_mincore (TARGET_NR_Linux + 26) +#define TARGET_NR_madvise (TARGET_NR_Linux + 27) +#define TARGET_NR_shmget (TARGET_NR_Linux + 28) +#define TARGET_NR_shmat (TARGET_NR_Linux + 29) +#define TARGET_NR_shmctl (TARGET_NR_Linux + 30) +#define TARGET_NR_dup (TARGET_NR_Linux + 31) +#define TARGET_NR_dup2 (TARGET_NR_Linux + 32) +#define TARGET_NR_pause (TARGET_NR_Linux + 33) +#define TARGET_NR_nanosleep (TARGET_NR_Linux + 34) +#define TARGET_NR_getitimer (TARGET_NR_Linux + 35) +#define TARGET_NR_setitimer (TARGET_NR_Linux + 36) +#define TARGET_NR_alarm (TARGET_NR_Linux + 37) +#define TARGET_NR_getpid (TARGET_NR_Linux + 38) +#define TARGET_NR_sendfile (TARGET_NR_Linux + 39) +#define TARGET_NR_socket (TARGET_NR_Linux + 40) +#define TARGET_NR_connect (TARGET_NR_Linux + 41) +#define TARGET_NR_accept (TARGET_NR_Linux + 42) +#define TARGET_NR_sendto (TARGET_NR_Linux + 43) +#define TARGET_NR_recvfrom (TARGET_NR_Linux + 44) +#define TARGET_NR_sendmsg (TARGET_NR_Linux + 45) +#define TARGET_NR_recvmsg (TARGET_NR_Linux + 46) +#define TARGET_NR_shutdown (TARGET_NR_Linux + 47) +#define TARGET_NR_bind (TARGET_NR_Linux + 48) +#define TARGET_NR_listen (TARGET_NR_Linux + 49) +#define TARGET_NR_getsockname (TARGET_NR_Linux + 50) +#define TARGET_NR_getpeername (TARGET_NR_Linux + 51) +#define TARGET_NR_socketpair (TARGET_NR_Linux + 52) +#define TARGET_NR_setsockopt (TARGET_NR_Linux + 53) +#define TARGET_NR_getsockopt (TARGET_NR_Linux + 54) +#define TARGET_NR_clone (TARGET_NR_Linux + 55) +#define TARGET_NR_fork (TARGET_NR_Linux + 56) +#define TARGET_NR_execve (TARGET_NR_Linux + 57) +#define TARGET_NR_exit (TARGET_NR_Linux + 58) +#define TARGET_NR_wait4 (TARGET_NR_Linux + 59) +#define TARGET_NR_kill (TARGET_NR_Linux + 60) +#define TARGET_NR_uname (TARGET_NR_Linux + 61) +#define TARGET_NR_semget (TARGET_NR_Linux + 62) +#define TARGET_NR_semop (TARGET_NR_Linux + 63) +#define TARGET_NR_semctl (TARGET_NR_Linux + 64) +#define TARGET_NR_shmdt (TARGET_NR_Linux + 65) +#define TARGET_NR_msgget (TARGET_NR_Linux + 66) +#define TARGET_NR_msgsnd (TARGET_NR_Linux + 67) +#define TARGET_NR_msgrcv (TARGET_NR_Linux + 68) +#define TARGET_NR_msgctl (TARGET_NR_Linux + 69) +#define TARGET_NR_fcntl (TARGET_NR_Linux + 70) +#define TARGET_NR_flock (TARGET_NR_Linux + 71) +#define TARGET_NR_fsync (TARGET_NR_Linux + 72) +#define TARGET_NR_fdatasync (TARGET_NR_Linux + 73) +#define TARGET_NR_truncate (TARGET_NR_Linux + 74) +#define TARGET_NR_ftruncate (TARGET_NR_Linux + 75) +#define TARGET_NR_getdents (TARGET_NR_Linux + 76) +#define TARGET_NR_getcwd (TARGET_NR_Linux + 77) +#define TARGET_NR_chdir (TARGET_NR_Linux + 78) +#define TARGET_NR_fchdir (TARGET_NR_Linux + 79) +#define TARGET_NR_rename (TARGET_NR_Linux + 80) +#define TARGET_NR_mkdir (TARGET_NR_Linux + 81) +#define TARGET_NR_rmdir (TARGET_NR_Linux + 82) +#define TARGET_NR_creat (TARGET_NR_Linux + 83) +#define TARGET_NR_link (TARGET_NR_Linux + 84) +#define TARGET_NR_unlink (TARGET_NR_Linux + 85) +#define TARGET_NR_symlink (TARGET_NR_Linux + 86) +#define TARGET_NR_readlink (TARGET_NR_Linux + 87) +#define TARGET_NR_chmod (TARGET_NR_Linux + 88) +#define TARGET_NR_fchmod (TARGET_NR_Linux + 89) +#define TARGET_NR_chown (TARGET_NR_Linux + 90) +#define TARGET_NR_fchown (TARGET_NR_Linux + 91) +#define TARGET_NR_lchown (TARGET_NR_Linux + 92) +#define TARGET_NR_umask (TARGET_NR_Linux + 93) +#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 94) +#define TARGET_NR_getrlimit (TARGET_NR_Linux + 95) +#define TARGET_NR_getrusage (TARGET_NR_Linux + 96) +#define TARGET_NR_sysinfo (TARGET_NR_Linux + 97) +#define TARGET_NR_times (TARGET_NR_Linux + 98) +#define TARGET_NR_ptrace (TARGET_NR_Linux + 99) +#define TARGET_NR_getuid (TARGET_NR_Linux + 100) +#define TARGET_NR_syslog (TARGET_NR_Linux + 101) +#define TARGET_NR_getgid (TARGET_NR_Linux + 102) +#define TARGET_NR_setuid (TARGET_NR_Linux + 103) +#define TARGET_NR_setgid (TARGET_NR_Linux + 104) +#define TARGET_NR_geteuid (TARGET_NR_Linux + 105) +#define TARGET_NR_getegid (TARGET_NR_Linux + 106) +#define TARGET_NR_setpgid (TARGET_NR_Linux + 107) +#define TARGET_NR_getppid (TARGET_NR_Linux + 108) +#define TARGET_NR_getpgrp (TARGET_NR_Linux + 109) +#define TARGET_NR_setsid (TARGET_NR_Linux + 110) +#define TARGET_NR_setreuid (TARGET_NR_Linux + 111) +#define TARGET_NR_setregid (TARGET_NR_Linux + 112) +#define TARGET_NR_getgroups (TARGET_NR_Linux + 113) +#define TARGET_NR_setgroups (TARGET_NR_Linux + 114) +#define TARGET_NR_setresuid (TARGET_NR_Linux + 115) +#define TARGET_NR_getresuid (TARGET_NR_Linux + 116) +#define TARGET_NR_setresgid (TARGET_NR_Linux + 117) +#define TARGET_NR_getresgid (TARGET_NR_Linux + 118) +#define TARGET_NR_getpgid (TARGET_NR_Linux + 119) +#define TARGET_NR_setfsuid (TARGET_NR_Linux + 120) +#define TARGET_NR_setfsgid (TARGET_NR_Linux + 121) +#define TARGET_NR_getsid (TARGET_NR_Linux + 122) +#define TARGET_NR_capget (TARGET_NR_Linux + 123) +#define TARGET_NR_capset (TARGET_NR_Linux + 124) +#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 125) +#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 126) +#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 127) +#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 128) +#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 129) +#define TARGET_NR_utime (TARGET_NR_Linux + 130) +#define TARGET_NR_mknod (TARGET_NR_Linux + 131) +#define TARGET_NR_personality (TARGET_NR_Linux + 132) +#define TARGET_NR_ustat (TARGET_NR_Linux + 133) +#define TARGET_NR_statfs (TARGET_NR_Linux + 134) +#define TARGET_NR_fstatfs (TARGET_NR_Linux + 135) +#define TARGET_NR_sysfs (TARGET_NR_Linux + 136) +#define TARGET_NR_getpriority (TARGET_NR_Linux + 137) +#define TARGET_NR_setpriority (TARGET_NR_Linux + 138) +#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 139) +#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 140) +#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 141) +#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 142) +#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 143) +#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 144) +#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 145) +#define TARGET_NR_mlock (TARGET_NR_Linux + 146) +#define TARGET_NR_munlock (TARGET_NR_Linux + 147) +#define TARGET_NR_mlockall (TARGET_NR_Linux + 148) +#define TARGET_NR_munlockall (TARGET_NR_Linux + 149) +#define TARGET_NR_vhangup (TARGET_NR_Linux + 150) +#define TARGET_NR_pivot_root (TARGET_NR_Linux + 151) +#define TARGET_NR__sysctl (TARGET_NR_Linux + 152) +#define TARGET_NR_prctl (TARGET_NR_Linux + 153) +#define TARGET_NR_adjtimex (TARGET_NR_Linux + 154) +#define TARGET_NR_setrlimit (TARGET_NR_Linux + 155) +#define TARGET_NR_chroot (TARGET_NR_Linux + 156) +#define TARGET_NR_sync (TARGET_NR_Linux + 157) +#define TARGET_NR_acct (TARGET_NR_Linux + 158) +#define TARGET_NR_settimeofday (TARGET_NR_Linux + 159) +#define TARGET_NR_mount (TARGET_NR_Linux + 160) +#define TARGET_NR_umount2 (TARGET_NR_Linux + 161) +#define TARGET_NR_swapon (TARGET_NR_Linux + 162) +#define TARGET_NR_swapoff (TARGET_NR_Linux + 163) +#define TARGET_NR_reboot (TARGET_NR_Linux + 164) +#define TARGET_NR_sethostname (TARGET_NR_Linux + 165) +#define TARGET_NR_setdomainname (TARGET_NR_Linux + 166) +#define TARGET_NR_create_module (TARGET_NR_Linux + 167) +#define TARGET_NR_init_module (TARGET_NR_Linux + 168) +#define TARGET_NR_delete_module (TARGET_NR_Linux + 169) +#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 170) +#define TARGET_NR_query_module (TARGET_NR_Linux + 171) +#define TARGET_NR_quotactl (TARGET_NR_Linux + 172) +#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 173) +#define TARGET_NR_getpmsg (TARGET_NR_Linux + 174) +#define TARGET_NR_putpmsg (TARGET_NR_Linux + 175) +#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 176) +#define TARGET_NR_reserved177 (TARGET_NR_Linux + 177) +#define TARGET_NR_gettid (TARGET_NR_Linux + 178) +#define TARGET_NR_readahead (TARGET_NR_Linux + 179) +#define TARGET_NR_setxattr (TARGET_NR_Linux + 180) +#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 181) +#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 182) +#define TARGET_NR_getxattr (TARGET_NR_Linux + 183) +#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 184) +#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 185) +#define TARGET_NR_listxattr (TARGET_NR_Linux + 186) +#define TARGET_NR_llistxattr (TARGET_NR_Linux + 187) +#define TARGET_NR_flistxattr (TARGET_NR_Linux + 188) +#define TARGET_NR_removexattr (TARGET_NR_Linux + 189) +#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 190) +#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 191) +#define TARGET_NR_tkill (TARGET_NR_Linux + 192) +#define TARGET_NR_reserved193 (TARGET_NR_Linux + 193) +#define TARGET_NR_futex (TARGET_NR_Linux + 194) +#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 195) +#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 196) +#define TARGET_NR_cacheflush (TARGET_NR_Linux + 197) +#define TARGET_NR_cachectl (TARGET_NR_Linux + 198) +#define TARGET_NR_sysmips (TARGET_NR_Linux + 199) +#define TARGET_NR_io_setup (TARGET_NR_Linux + 200) +#define TARGET_NR_io_destroy (TARGET_NR_Linux + 201) +#define TARGET_NR_io_getevents (TARGET_NR_Linux + 202) +#define TARGET_NR_io_submit (TARGET_NR_Linux + 203) +#define TARGET_NR_io_cancel (TARGET_NR_Linux + 204) +#define TARGET_NR_exit_group (TARGET_NR_Linux + 205) +#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 206) +#define TARGET_NR_epoll_create (TARGET_NR_Linux + 207) +#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 208) +#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 209) +#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 210) +#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 211) +#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 212) +#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 213) +#define TARGET_NR_semtimedop (TARGET_NR_Linux + 214) +#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 215) +#define TARGET_NR_timer_create (TARGET_NR_Linux + 216) +#define TARGET_NR_timer_settime (TARGET_NR_Linux + 217) +#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 218) +#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 219) +#define TARGET_NR_timer_delete (TARGET_NR_Linux + 220) +#define TARGET_NR_clock_settime (TARGET_NR_Linux + 221) +#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 222) +#define TARGET_NR_clock_getres (TARGET_NR_Linux + 223) +#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 224) +#define TARGET_NR_tgkill (TARGET_NR_Linux + 225) +#define TARGET_NR_utimes (TARGET_NR_Linux + 226) +#define TARGET_NR_mbind (TARGET_NR_Linux + 227) +#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 228) +#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 229) +#define TARGET_NR_mq_open (TARGET_NR_Linux + 230) +#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 231) +#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 232) +#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 233) +#define TARGET_NR_mq_notify (TARGET_NR_Linux + 234) +#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 235) +#define TARGET_NR_vserver (TARGET_NR_Linux + 236) +#define TARGET_NR_waitid (TARGET_NR_Linux + 237) +/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 238) */ +#define TARGET_NR_add_key (TARGET_NR_Linux + 239) +#define TARGET_NR_request_key (TARGET_NR_Linux + 240) +#define TARGET_NR_keyctl (TARGET_NR_Linux + 241) +#define TARGET_NR_set_thread_area (TARGET_NR_Linux + 242) +#define TARGET_NR_inotify_init (TARGET_NR_Linux + 243) +#define TARGET_NR_inotify_add_watch (TARGET_NR_Linux + 244) +#define TARGET_NR_inotify_rm_watch (TARGET_NR_Linux + 245) +#define TARGET_NR_migrate_pages (TARGET_NR_Linux + 246) +#define TARGET_NR_openat (TARGET_NR_Linux + 247) +#define TARGET_NR_mkdirat (TARGET_NR_Linux + 248) +#define TARGET_NR_mknodat (TARGET_NR_Linux + 249) +#define TARGET_NR_fchownat (TARGET_NR_Linux + 250) +#define TARGET_NR_futimesat (TARGET_NR_Linux + 251) +#define TARGET_NR_newfstatat (TARGET_NR_Linux + 252) +#define TARGET_NR_unlinkat (TARGET_NR_Linux + 253) +#define TARGET_NR_renameat (TARGET_NR_Linux + 254) +#define TARGET_NR_linkat (TARGET_NR_Linux + 255) +#define TARGET_NR_symlinkat (TARGET_NR_Linux + 256) +#define TARGET_NR_readlinkat (TARGET_NR_Linux + 257) +#define TARGET_NR_fchmodat (TARGET_NR_Linux + 258) +#define TARGET_NR_faccessat (TARGET_NR_Linux + 259) +#define TARGET_NR_pselect6 (TARGET_NR_Linux + 260) +#define TARGET_NR_ppoll (TARGET_NR_Linux + 261) +#define TARGET_NR_unshare (TARGET_NR_Linux + 262) +#define TARGET_NR_splice (TARGET_NR_Linux + 263) +#define TARGET_NR_sync_file_range (TARGET_NR_Linux + 264) +#define TARGET_NR_tee (TARGET_NR_Linux + 265) +#define TARGET_NR_vmsplice (TARGET_NR_Linux + 266) +#define TARGET_NR_move_pages (TARGET_NR_Linux + 267) +#define TARGET_NR_set_robust_list (TARGET_NR_Linux + 268) +#define TARGET_NR_get_robust_list (TARGET_NR_Linux + 269) +#define TARGET_NR_kexec_load (TARGET_NR_Linux + 270) +#define TARGET_NR_getcpu (TARGET_NR_Linux + 271) +#define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 272) +#define TARGET_NR_ioprio_set (TARGET_NR_Linux + 273) +#define TARGET_NR_ioprio_get (TARGET_NR_Linux + 274) +#define TARGET_NR_utimensat (TARGET_NR_Linux + 275) +#define TARGET_NR_signalfd (TARGET_NR_Linux + 276) +#define TARGET_NR_timerfd (TARGET_NR_Linux + 277) +#define TARGET_NR_eventfd (TARGET_NR_Linux + 278) +#define TARGET_NR_fallocate (TARGET_NR_Linux + 279) diff --git a/linux-user/mips64/target_signal.h b/linux-user/mips64/target_signal.h new file mode 100644 index 000000000..514195c03 --- /dev/null +++ b/linux-user/mips64/target_signal.h @@ -0,0 +1,29 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_long ss_sp; + target_ulong ss_size; + target_long ss_flags; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) +{ + return state->gpr[29][state->current_tc]; +} + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/mips64/termbits.h b/linux-user/mips64/termbits.h new file mode 100644 index 000000000..d3a6cf8f9 --- /dev/null +++ b/linux-user/mips64/termbits.h @@ -0,0 +1,245 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 23 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_BOTHER 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_IEXTEN 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_TOSTOP 0100000 +#define TARGET_ITOSTOP TARGET_TOSTOP + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VMIN 4 +#define TARGET_VTIME 5 +#define TARGET_VEOL2 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +/* VDSUSP not supported */ +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOF 16 +#define TARGET_VEOL 17 + +/* ioctls */ + +#define TARGET_TCGETA 0x5401 +#define TARGET_TCSETA 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ +#define TARGET_TCSETAW 0x5403 +#define TARGET_TCSETAF 0x5404 + +#define TARGET_TCSBRK 0x5405 +#define TARGET_TCXONC 0x5406 +#define TARGET_TCFLSH 0x5407 + +#define TARGET_TCGETS 0x540d +#define TARGET_TCSETS 0x540e +#define TARGET_TCSETSW 0x540f +#define TARGET_TCSETSF 0x5410 + +#define TARGET_TIOCEXCL 0x740d /* set exclusive use of tty */ +#define TARGET_TIOCNXCL 0x740e /* reset exclusive use of tty */ +#define TARGET_TIOCOUTQ 0x7472 /* output queue size */ +#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */ +#define TARGET_TIOCMGET 0x741d /* get all modem bits */ +#define TARGET_TIOCMBIS 0x741b /* bis modem bits */ +#define TARGET_TIOCMBIC 0x741c /* bic modem bits */ +#define TARGET_TIOCMSET 0x741a /* set all modem bits */ +#define TARGET_TIOCPKT 0x5470 /* pty: set/clear packet mode */ +#define TARGET_TIOCPKT_DATA 0x00 /* data packet */ +#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */ +#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */ +#define TARGET_TIOCPKT_STOP 0x04 /* stop output */ +#define TARGET_TIOCPKT_START 0x08 /* start output */ +#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ +#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ +/* #define TIOCPKT_IOCTL 0x40 state change of pty driver */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) /* set window size */ +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) /* get window size */ +#define TARGET_TIOCNOTTY 0x5471 /* void tty association */ +#define TARGET_TIOCSETD 0x7401 +#define TARGET_TIOCGETD 0x7400 + +#define TARGET_FIOCLEX 0x6601 +#define TARGET_FIONCLEX 0x6602 +#define TARGET_FIOASYNC 0x667d +#define TARGET_FIONBIO 0x667e +#define TARGET_FIOQSIZE 0x667f + +#define TARGET_TIOCGLTC 0x7474 /* get special local chars */ +#define TARGET_TIOCSLTC 0x7475 /* set special local chars */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */ +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */ +#define TARGET_TIOCCONS TARGET_IOW('t', 120, int) /* become virtual console */ + +#define TARGET_FIONREAD 0x467f +#define TARGET_TIOCINQ TARGET_FIONREAD + +#define TARGET_TIOCGETP 0x7408 +#define TARGET_TIOCSETP 0x7409 +#define TARGET_TIOCSETN 0x740a /* TIOCSETP wo flush */ + +/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct termios) set termios struct */ +/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct termios) drain output, set */ +/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct termios) drn out, fls in, set */ +/* #define TARGET_TIOCGETD TARGET_IOR('t', 26, int) get line discipline */ +/* #define TARGET_TIOCSETD TARGET_IOW('t', 27, int) set line discipline */ + /* 127-124 compat */ + +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x7416 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +/* I hope the range from 0x5480 on is free ... */ +#define TARGET_TIOCSCTTY 0x5480 /* become controlling tty */ +#define TARGET_TIOCGSOFTCAR 0x5481 +#define TARGET_TIOCSSOFTCAR 0x5482 +#define TARGET_TIOCLINUX 0x5483 +#define TARGET_TIOCGSERIAL 0x5484 +#define TARGET_TIOCSSERIAL 0x5485 +#define TARGET_TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSERCONFIG 0x5488 +#define TARGET_TIOCSERGWILD 0x5489 +#define TARGET_TIOCSERSWILD 0x548a +#define TARGET_TIOCGLCKTRMIOS 0x548b +#define TARGET_TIOCSLCKTRMIOS 0x548c +#define TARGET_TIOCSERGSTRUCT 0x548d /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x548e /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x5493 /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x5494 /* Set Hayes ESP configuration */ diff --git a/linux-user/mipsn32/syscall.h b/linux-user/mipsn32/syscall.h new file mode 100644 index 000000000..4ec506cb0 --- /dev/null +++ b/linux-user/mipsn32/syscall.h @@ -0,0 +1,221 @@ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { + /* Saved main processor registers. */ + target_ulong regs[32]; + + /* Saved special registers. */ + target_ulong cp0_status; + target_ulong lo; + target_ulong hi; + target_ulong cp0_badvaddr; + target_ulong cp0_cause; + target_ulong cp0_epc; +}; + +/* Target errno definitions taken from asm-mips/errno.h */ +#undef TARGET_ENOMSG +#define TARGET_ENOMSG 35 /* Identifier removed */ +#undef TARGET_EIDRM +#define TARGET_EIDRM 36 /* Identifier removed */ +#undef TARGET_ECHRNG +#define TARGET_ECHRNG 37 /* Channel number out of range */ +#undef TARGET_EL2NSYNC +#define TARGET_EL2NSYNC 38 /* Level 2 not synchronized */ +#undef TARGET_EL3HLT +#define TARGET_EL3HLT 39 /* Level 3 halted */ +#undef TARGET_EL3RST +#define TARGET_EL3RST 40 /* Level 3 reset */ +#undef TARGET_ELNRNG +#define TARGET_ELNRNG 41 /* Link number out of range */ +#undef TARGET_EUNATCH +#define TARGET_EUNATCH 42 /* Protocol driver not attached */ +#undef TARGET_ENOCSI +#define TARGET_ENOCSI 43 /* No CSI structure available */ +#undef TARGET_EL2HLT +#define TARGET_EL2HLT 44 /* Level 2 halted */ +#undef TARGET_EDEADLK +#define TARGET_EDEADLK 45 /* Resource deadlock would occur */ +#undef TARGET_ENOLCK +#define TARGET_ENOLCK 46 /* No record locks available */ +#undef TARGET_EBADE +#define TARGET_EBADE 50 /* Invalid exchange */ +#undef TARGET_EBADR +#define TARGET_EBADR 51 /* Invalid request descriptor */ +#undef TARGET_EXFULL +#define TARGET_EXFULL 52 /* TARGET_Exchange full */ +#undef TARGET_ENOANO +#define TARGET_ENOANO 53 /* No anode */ +#undef TARGET_EBADRQC +#define TARGET_EBADRQC 54 /* Invalid request code */ +#undef TARGET_EBADSLT +#define TARGET_EBADSLT 55 /* Invalid slot */ +#undef TARGET_EDEADLOCK +#define TARGET_EDEADLOCK 56 /* File locking deadlock error */ +#undef TARGET_EBFONT +#define TARGET_EBFONT 59 /* Bad font file format */ +#undef TARGET_ENOSTR +#define TARGET_ENOSTR 60 /* Device not a stream */ +#undef TARGET_ENODATA +#define TARGET_ENODATA 61 /* No data available */ +#undef TARGET_ETIME +#define TARGET_ETIME 62 /* Timer expired */ +#undef TARGET_ENOSR +#define TARGET_ENOSR 63 /* Out of streams resources */ +#undef TARGET_ENONET +#define TARGET_ENONET 64 /* Machine is not on the network */ +#undef TARGET_ENOPKG +#define TARGET_ENOPKG 65 /* Package not installed */ +#undef TARGET_EREMOTE +#define TARGET_EREMOTE 66 /* Object is remote */ +#undef TARGET_ENOLINK +#define TARGET_ENOLINK 67 /* Link has been severed */ +#undef TARGET_EADV +#define TARGET_EADV 68 /* Advertise error */ +#undef TARGET_ESRMNT +#define TARGET_ESRMNT 69 /* Srmount error */ +#undef TARGET_ECOMM +#define TARGET_ECOMM 70 /* Communication error on send */ +#undef TARGET_EPROTO +#define TARGET_EPROTO 71 /* Protocol error */ +#undef TARGET_EDOTDOT +#define TARGET_EDOTDOT 73 /* RFS specific error */ +#undef TARGET_EMULTIHOP +#define TARGET_EMULTIHOP 74 /* Multihop attempted */ +#undef TARGET_EBADMSG +#define TARGET_EBADMSG 77 /* Not a data message */ +#undef TARGET_ENAMETOOLONG +#define TARGET_ENAMETOOLONG 78 /* File name too long */ +#undef TARGET_EOVERFLOW +#define TARGET_EOVERFLOW 79 /* Value too large for defined data type */ +#undef TARGET_ENOTUNIQ +#define TARGET_ENOTUNIQ 80 /* Name not unique on network */ +#undef TARGET_EBADFD +#define TARGET_EBADFD 81 /* File descriptor in bad state */ +#undef TARGET_EREMCHG +#define TARGET_EREMCHG 82 /* Remote address changed */ +#undef TARGET_ELIBACC +#define TARGET_ELIBACC 83 /* Can not access a needed shared library */ +#undef TARGET_ELIBBAD +#define TARGET_ELIBBAD 84 /* Accessing a corrupted shared library */ +#undef TARGET_ELIBSCN +#define TARGET_ELIBSCN 85 /* .lib section in a.out corrupted */ +#undef TARGET_ELIBMAX +#define TARGET_ELIBMAX 86 /* Attempting to link in too many shared libraries */ +#undef TARGET_ELIBEXEC +#define TARGET_ELIBEXEC 87 /* Cannot exec a shared library directly */ +#undef TARGET_EILSEQ +#define TARGET_EILSEQ 88 /* Illegal byte sequence */ +#undef TARGET_ENOSYS +#define TARGET_ENOSYS 89 /* Function not implemented */ +#undef TARGET_ELOOP +#define TARGET_ELOOP 90 /* Too many symbolic links encountered */ +#undef TARGET_ERESTART +#define TARGET_ERESTART 91 /* Interrupted system call should be restarted */ +#undef TARGET_ESTRPIPE +#define TARGET_ESTRPIPE 92 /* Streams pipe error */ +#undef TARGET_ENOTEMPTY +#define TARGET_ENOTEMPTY 93 /* Directory not empty */ +#undef TARGET_EUSERS +#define TARGET_EUSERS 94 /* Too many users */ +#undef TARGET_ENOTSOCK +#define TARGET_ENOTSOCK 95 /* Socket operation on non-socket */ +#undef TARGET_EDESTADDRREQ +#define TARGET_EDESTADDRREQ 96 /* Destination address required */ +#undef TARGET_EMSGSIZE +#define TARGET_EMSGSIZE 97 /* Message too long */ +#undef TARGET_EPROTOTYPE +#define TARGET_EPROTOTYPE 98 /* Protocol wrong type for socket */ +#undef TARGET_ENOPROTOOPT +#define TARGET_ENOPROTOOPT 99 /* Protocol not available */ +#undef TARGET_EPROTONOSUPPORT +#define TARGET_EPROTONOSUPPORT 120 /* Protocol not supported */ +#undef TARGET_ESOCKTNOSUPPORT +#define TARGET_ESOCKTNOSUPPORT 121 /* Socket type not supported */ +#undef TARGET_EOPNOTSUPP +#define TARGET_EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ +#undef TARGET_EPFNOSUPPORT +#define TARGET_EPFNOSUPPORT 123 /* Protocol family not supported */ +#undef TARGET_EAFNOSUPPORT +#define TARGET_EAFNOSUPPORT 124 /* Address family not supported by protocol */ +#undef TARGET_EADDRINUSE +#define TARGET_EADDRINUSE 125 /* Address already in use */ +#undef TARGET_EADDRNOTAVAIL +#define TARGET_EADDRNOTAVAIL 126 /* Cannot assign requested address */ +#undef TARGET_ENETDOWN +#define TARGET_ENETDOWN 127 /* Network is down */ +#undef TARGET_ENETUNREACH +#define TARGET_ENETUNREACH 128 /* Network is unreachable */ +#undef TARGET_ENETRESET +#define TARGET_ENETRESET 129 /* Network dropped connection because of reset */ +#undef TARGET_ECONNABORTED +#define TARGET_ECONNABORTED 130 /* Software caused connection abort */ +#undef TARGET_ECONNRESET +#define TARGET_ECONNRESET 131 /* Connection reset by peer */ +#undef TARGET_ENOBUFS +#define TARGET_ENOBUFS 132 /* No buffer space available */ +#undef TARGET_EISCONN +#define TARGET_EISCONN 133 /* Transport endpoint is already connected */ +#undef TARGET_ENOTCONN +#define TARGET_ENOTCONN 134 /* Transport endpoint is not connected */ +#undef TARGET_EUCLEAN +#define TARGET_EUCLEAN 135 /* Structure needs cleaning */ +#undef TARGET_ENOTNAM +#define TARGET_ENOTNAM 137 /* Not a XENIX named type file */ +#undef TARGET_ENAVAIL +#define TARGET_ENAVAIL 138 /* No XENIX semaphores available */ +#undef TARGET_EISNAM +#define TARGET_EISNAM 139 /* Is a named type file */ +#undef TARGET_EREMOTEIO +#define TARGET_EREMOTEIO 140 /* Remote I/O error */ +#undef TARGET_EINIT +#define TARGET_EINIT 141 /* Reserved */ +#undef TARGET_EREMDEV +#define TARGET_EREMDEV 142 /* TARGET_Error 142 */ +#undef TARGET_ESHUTDOWN +#define TARGET_ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ +#undef TARGET_ETOOMANYREFS +#define TARGET_ETOOMANYREFS 144 /* Too many references: cannot splice */ +#undef TARGET_ETIMEDOUT +#define TARGET_ETIMEDOUT 145 /* Connection timed out */ +#undef TARGET_ECONNREFUSED +#define TARGET_ECONNREFUSED 146 /* Connection refused */ +#undef TARGET_EHOSTDOWN +#define TARGET_EHOSTDOWN 147 /* Host is down */ +#undef TARGET_EHOSTUNREACH +#define TARGET_EHOSTUNREACH 148 /* No route to host */ +#undef TARGET_EALREADY +#define TARGET_EALREADY 149 /* Operation already in progress */ +#undef TARGET_EINPROGRESS +#define TARGET_EINPROGRESS 150 /* Operation now in progress */ +#undef TARGET_ESTALE +#define TARGET_ESTALE 151 /* Stale NFS file handle */ +#undef TARGET_ECANCELED +#define TARGET_ECANCELED 158 /* AIO operation canceled */ +/* + * These error are Linux extensions. + */ +#undef TARGET_ENOMEDIUM +#define TARGET_ENOMEDIUM 159 /* No medium found */ +#undef TARGET_EMEDIUMTYPE +#define TARGET_EMEDIUMTYPE 160 /* Wrong medium type */ +#undef TARGET_ENOKEY +#define TARGET_ENOKEY 161 /* Required key not available */ +#undef TARGET_EKEYEXPIRED +#define TARGET_EKEYEXPIRED 162 /* Key has expired */ +#undef TARGET_EKEYREVOKED +#define TARGET_EKEYREVOKED 163 /* Key has been revoked */ +#undef TARGET_EKEYREJECTED +#define TARGET_EKEYREJECTED 164 /* Key was rejected by service */ + +/* for robust mutexes */ +#undef TARGET_EOWNERDEAD +#define TARGET_EOWNERDEAD 165 /* Owner died */ +#undef TARGET_ENOTRECOVERABLE +#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ + + + +#define UNAME_MACHINE "mips64" diff --git a/linux-user/mipsn32/syscall_nr.h b/linux-user/mipsn32/syscall_nr.h new file mode 100644 index 000000000..a83c4c9b8 --- /dev/null +++ b/linux-user/mipsn32/syscall_nr.h @@ -0,0 +1,288 @@ +/* + * Linux N32 syscalls are in the range from 6000 to 6999. + */ +#define TARGET_NR_Linux 6000 +#define TARGET_NR_read (TARGET_NR_Linux + 0) +#define TARGET_NR_write (TARGET_NR_Linux + 1) +#define TARGET_NR_open (TARGET_NR_Linux + 2) +#define TARGET_NR_close (TARGET_NR_Linux + 3) +#define TARGET_NR_stat (TARGET_NR_Linux + 4) +#define TARGET_NR_fstat (TARGET_NR_Linux + 5) +#define TARGET_NR_lstat (TARGET_NR_Linux + 6) +#define TARGET_NR_poll (TARGET_NR_Linux + 7) +#define TARGET_NR_lseek (TARGET_NR_Linux + 8) +#define TARGET_NR_mmap (TARGET_NR_Linux + 9) +#define TARGET_NR_mprotect (TARGET_NR_Linux + 10) +#define TARGET_NR_munmap (TARGET_NR_Linux + 11) +#define TARGET_NR_brk (TARGET_NR_Linux + 12) +#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 13) +#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 14) +#define TARGET_NR_ioctl (TARGET_NR_Linux + 15) +#define TARGET_NR_pread64 (TARGET_NR_Linux + 16) +#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 17) +#define TARGET_NR_readv (TARGET_NR_Linux + 18) +#define TARGET_NR_writev (TARGET_NR_Linux + 19) +#define TARGET_NR_access (TARGET_NR_Linux + 20) +#define TARGET_NR_pipe (TARGET_NR_Linux + 21) +#define TARGET_NR__newselect (TARGET_NR_Linux + 22) +#define TARGET_NR_sched_yield (TARGET_NR_Linux + 23) +#define TARGET_NR_mremap (TARGET_NR_Linux + 24) +#define TARGET_NR_msync (TARGET_NR_Linux + 25) +#define TARGET_NR_mincore (TARGET_NR_Linux + 26) +#define TARGET_NR_madvise (TARGET_NR_Linux + 27) +#define TARGET_NR_shmget (TARGET_NR_Linux + 28) +#define TARGET_NR_shmat (TARGET_NR_Linux + 29) +#define TARGET_NR_shmctl (TARGET_NR_Linux + 30) +#define TARGET_NR_dup (TARGET_NR_Linux + 31) +#define TARGET_NR_dup2 (TARGET_NR_Linux + 32) +#define TARGET_NR_pause (TARGET_NR_Linux + 33) +#define TARGET_NR_nanosleep (TARGET_NR_Linux + 34) +#define TARGET_NR_getitimer (TARGET_NR_Linux + 35) +#define TARGET_NR_setitimer (TARGET_NR_Linux + 36) +#define TARGET_NR_alarm (TARGET_NR_Linux + 37) +#define TARGET_NR_getpid (TARGET_NR_Linux + 38) +#define TARGET_NR_sendfile (TARGET_NR_Linux + 39) +#define TARGET_NR_socket (TARGET_NR_Linux + 40) +#define TARGET_NR_connect (TARGET_NR_Linux + 41) +#define TARGET_NR_accept (TARGET_NR_Linux + 42) +#define TARGET_NR_sendto (TARGET_NR_Linux + 43) +#define TARGET_NR_recvfrom (TARGET_NR_Linux + 44) +#define TARGET_NR_sendmsg (TARGET_NR_Linux + 45) +#define TARGET_NR_recvmsg (TARGET_NR_Linux + 46) +#define TARGET_NR_shutdown (TARGET_NR_Linux + 47) +#define TARGET_NR_bind (TARGET_NR_Linux + 48) +#define TARGET_NR_listen (TARGET_NR_Linux + 49) +#define TARGET_NR_getsockname (TARGET_NR_Linux + 50) +#define TARGET_NR_getpeername (TARGET_NR_Linux + 51) +#define TARGET_NR_socketpair (TARGET_NR_Linux + 52) +#define TARGET_NR_setsockopt (TARGET_NR_Linux + 53) +#define TARGET_NR_getsockopt (TARGET_NR_Linux + 54) +#define TARGET_NR_clone (TARGET_NR_Linux + 55) +#define TARGET_NR_fork (TARGET_NR_Linux + 56) +#define TARGET_NR_execve (TARGET_NR_Linux + 57) +#define TARGET_NR_exit (TARGET_NR_Linux + 58) +#define TARGET_NR_wait4 (TARGET_NR_Linux + 59) +#define TARGET_NR_kill (TARGET_NR_Linux + 60) +#define TARGET_NR_uname (TARGET_NR_Linux + 61) +#define TARGET_NR_semget (TARGET_NR_Linux + 62) +#define TARGET_NR_semop (TARGET_NR_Linux + 63) +#define TARGET_NR_semctl (TARGET_NR_Linux + 64) +#define TARGET_NR_shmdt (TARGET_NR_Linux + 65) +#define TARGET_NR_msgget (TARGET_NR_Linux + 66) +#define TARGET_NR_msgsnd (TARGET_NR_Linux + 67) +#define TARGET_NR_msgrcv (TARGET_NR_Linux + 68) +#define TARGET_NR_msgctl (TARGET_NR_Linux + 69) +#define TARGET_NR_fcntl (TARGET_NR_Linux + 70) +#define TARGET_NR_flock (TARGET_NR_Linux + 71) +#define TARGET_NR_fsync (TARGET_NR_Linux + 72) +#define TARGET_NR_fdatasync (TARGET_NR_Linux + 73) +#define TARGET_NR_truncate (TARGET_NR_Linux + 74) +#define TARGET_NR_ftruncate (TARGET_NR_Linux + 75) +#define TARGET_NR_getdents (TARGET_NR_Linux + 76) +#define TARGET_NR_getcwd (TARGET_NR_Linux + 77) +#define TARGET_NR_chdir (TARGET_NR_Linux + 78) +#define TARGET_NR_fchdir (TARGET_NR_Linux + 79) +#define TARGET_NR_rename (TARGET_NR_Linux + 80) +#define TARGET_NR_mkdir (TARGET_NR_Linux + 81) +#define TARGET_NR_rmdir (TARGET_NR_Linux + 82) +#define TARGET_NR_creat (TARGET_NR_Linux + 83) +#define TARGET_NR_link (TARGET_NR_Linux + 84) +#define TARGET_NR_unlink (TARGET_NR_Linux + 85) +#define TARGET_NR_symlink (TARGET_NR_Linux + 86) +#define TARGET_NR_readlink (TARGET_NR_Linux + 87) +#define TARGET_NR_chmod (TARGET_NR_Linux + 88) +#define TARGET_NR_fchmod (TARGET_NR_Linux + 89) +#define TARGET_NR_chown (TARGET_NR_Linux + 90) +#define TARGET_NR_fchown (TARGET_NR_Linux + 91) +#define TARGET_NR_lchown (TARGET_NR_Linux + 92) +#define TARGET_NR_umask (TARGET_NR_Linux + 93) +#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 94) +#define TARGET_NR_getrlimit (TARGET_NR_Linux + 95) +#define TARGET_NR_getrusage (TARGET_NR_Linux + 96) +#define TARGET_NR_sysinfo (TARGET_NR_Linux + 97) +#define TARGET_NR_times (TARGET_NR_Linux + 98) +#define TARGET_NR_ptrace (TARGET_NR_Linux + 99) +#define TARGET_NR_getuid (TARGET_NR_Linux + 100) +#define TARGET_NR_syslog (TARGET_NR_Linux + 101) +#define TARGET_NR_getgid (TARGET_NR_Linux + 102) +#define TARGET_NR_setuid (TARGET_NR_Linux + 103) +#define TARGET_NR_setgid (TARGET_NR_Linux + 104) +#define TARGET_NR_geteuid (TARGET_NR_Linux + 105) +#define TARGET_NR_getegid (TARGET_NR_Linux + 106) +#define TARGET_NR_setpgid (TARGET_NR_Linux + 107) +#define TARGET_NR_getppid (TARGET_NR_Linux + 108) +#define TARGET_NR_getpgrp (TARGET_NR_Linux + 109) +#define TARGET_NR_setsid (TARGET_NR_Linux + 110) +#define TARGET_NR_setreuid (TARGET_NR_Linux + 111) +#define TARGET_NR_setregid (TARGET_NR_Linux + 112) +#define TARGET_NR_getgroups (TARGET_NR_Linux + 113) +#define TARGET_NR_setgroups (TARGET_NR_Linux + 114) +#define TARGET_NR_setresuid (TARGET_NR_Linux + 115) +#define TARGET_NR_getresuid (TARGET_NR_Linux + 116) +#define TARGET_NR_setresgid (TARGET_NR_Linux + 117) +#define TARGET_NR_getresgid (TARGET_NR_Linux + 118) +#define TARGET_NR_getpgid (TARGET_NR_Linux + 119) +#define TARGET_NR_setfsuid (TARGET_NR_Linux + 120) +#define TARGET_NR_setfsgid (TARGET_NR_Linux + 121) +#define TARGET_NR_getsid (TARGET_NR_Linux + 122) +#define TARGET_NR_capget (TARGET_NR_Linux + 123) +#define TARGET_NR_capset (TARGET_NR_Linux + 124) +#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 125) +#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 126) +#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 127) +#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 128) +#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 129) +#define TARGET_NR_utime (TARGET_NR_Linux + 130) +#define TARGET_NR_mknod (TARGET_NR_Linux + 131) +#define TARGET_NR_personality (TARGET_NR_Linux + 132) +#define TARGET_NR_ustat (TARGET_NR_Linux + 133) +#define TARGET_NR_statfs (TARGET_NR_Linux + 134) +#define TARGET_NR_fstatfs (TARGET_NR_Linux + 135) +#define TARGET_NR_sysfs (TARGET_NR_Linux + 136) +#define TARGET_NR_getpriority (TARGET_NR_Linux + 137) +#define TARGET_NR_setpriority (TARGET_NR_Linux + 138) +#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 139) +#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 140) +#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 141) +#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 142) +#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 143) +#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 144) +#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 145) +#define TARGET_NR_mlock (TARGET_NR_Linux + 146) +#define TARGET_NR_munlock (TARGET_NR_Linux + 147) +#define TARGET_NR_mlockall (TARGET_NR_Linux + 148) +#define TARGET_NR_munlockall (TARGET_NR_Linux + 149) +#define TARGET_NR_vhangup (TARGET_NR_Linux + 150) +#define TARGET_NR_pivot_root (TARGET_NR_Linux + 151) +#define TARGET_NR__sysctl (TARGET_NR_Linux + 152) +#define TARGET_NR_prctl (TARGET_NR_Linux + 153) +#define TARGET_NR_adjtimex (TARGET_NR_Linux + 154) +#define TARGET_NR_setrlimit (TARGET_NR_Linux + 155) +#define TARGET_NR_chroot (TARGET_NR_Linux + 156) +#define TARGET_NR_sync (TARGET_NR_Linux + 157) +#define TARGET_NR_acct (TARGET_NR_Linux + 158) +#define TARGET_NR_settimeofday (TARGET_NR_Linux + 159) +#define TARGET_NR_mount (TARGET_NR_Linux + 160) +#define TARGET_NR_umount2 (TARGET_NR_Linux + 161) +#define TARGET_NR_swapon (TARGET_NR_Linux + 162) +#define TARGET_NR_swapoff (TARGET_NR_Linux + 163) +#define TARGET_NR_reboot (TARGET_NR_Linux + 164) +#define TARGET_NR_sethostname (TARGET_NR_Linux + 165) +#define TARGET_NR_setdomainname (TARGET_NR_Linux + 166) +#define TARGET_NR_create_module (TARGET_NR_Linux + 167) +#define TARGET_NR_init_module (TARGET_NR_Linux + 168) +#define TARGET_NR_delete_module (TARGET_NR_Linux + 169) +#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 170) +#define TARGET_NR_query_module (TARGET_NR_Linux + 171) +#define TARGET_NR_quotactl (TARGET_NR_Linux + 172) +#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 173) +#define TARGET_NR_getpmsg (TARGET_NR_Linux + 174) +#define TARGET_NR_putpmsg (TARGET_NR_Linux + 175) +#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 176) +#define TARGET_NR_reserved177 (TARGET_NR_Linux + 177) +#define TARGET_NR_gettid (TARGET_NR_Linux + 178) +#define TARGET_NR_readahead (TARGET_NR_Linux + 179) +#define TARGET_NR_setxattr (TARGET_NR_Linux + 180) +#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 181) +#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 182) +#define TARGET_NR_getxattr (TARGET_NR_Linux + 183) +#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 184) +#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 185) +#define TARGET_NR_listxattr (TARGET_NR_Linux + 186) +#define TARGET_NR_llistxattr (TARGET_NR_Linux + 187) +#define TARGET_NR_flistxattr (TARGET_NR_Linux + 188) +#define TARGET_NR_removexattr (TARGET_NR_Linux + 189) +#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 190) +#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 191) +#define TARGET_NR_tkill (TARGET_NR_Linux + 192) +#define TARGET_NR_reserved193 (TARGET_NR_Linux + 193) +#define TARGET_NR_futex (TARGET_NR_Linux + 194) +#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 195) +#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 196) +#define TARGET_NR_cacheflush (TARGET_NR_Linux + 197) +#define TARGET_NR_cachectl (TARGET_NR_Linux + 198) +#define TARGET_NR_sysmips (TARGET_NR_Linux + 199) +#define TARGET_NR_io_setup (TARGET_NR_Linux + 200) +#define TARGET_NR_io_destroy (TARGET_NR_Linux + 201) +#define TARGET_NR_io_getevents (TARGET_NR_Linux + 202) +#define TARGET_NR_io_submit (TARGET_NR_Linux + 203) +#define TARGET_NR_io_cancel (TARGET_NR_Linux + 204) +#define TARGET_NR_exit_group (TARGET_NR_Linux + 205) +#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 206) +#define TARGET_NR_epoll_create (TARGET_NR_Linux + 207) +#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 208) +#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 209) +#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 210) +#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 211) +#define TARGET_NR_fcntl64 (TARGET_NR_Linux + 212) +#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 213) +#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 214) +#define TARGET_NR_semtimedop (TARGET_NR_Linux + 215) +#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 216) +#define TARGET_NR_statfs64 (TARGET_NR_Linux + 217) +#define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 218) +#define TARGET_NR_sendfile64 (TARGET_NR_Linux + 219) +#define TARGET_NR_timer_create (TARGET_NR_Linux + 220) +#define TARGET_NR_timer_settime (TARGET_NR_Linux + 221) +#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 222) +#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 223) +#define TARGET_NR_timer_delete (TARGET_NR_Linux + 224) +#define TARGET_NR_clock_settime (TARGET_NR_Linux + 225) +#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 226) +#define TARGET_NR_clock_getres (TARGET_NR_Linux + 227) +#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 228) +#define TARGET_NR_tgkill (TARGET_NR_Linux + 229) +#define TARGET_NR_utimes (TARGET_NR_Linux + 230) +#define TARGET_NR_mbind (TARGET_NR_Linux + 231) +#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 232) +#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 233) +#define TARGET_NR_mq_open (TARGET_NR_Linux + 234) +#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 235) +#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 236) +#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 237) +#define TARGET_NR_mq_notify (TARGET_NR_Linux + 238) +#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 239) +#define TARGET_NR_vserver (TARGET_NR_Linux + 240) +#define TARGET_NR_waitid (TARGET_NR_Linux + 241) +/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 242) */ +#define TARGET_NR_add_key (TARGET_NR_Linux + 243) +#define TARGET_NR_request_key (TARGET_NR_Linux + 244) +#define TARGET_NR_keyctl (TARGET_NR_Linux + 245) +#define TARGET_NR_set_thread_area (TARGET_NR_Linux + 246) +#define TARGET_NR_inotify_init (TARGET_NR_Linux + 247) +#define TARGET_NR_inotify_add_watch (TARGET_NR_Linux + 248) +#define TARGET_NR_inotify_rm_watch (TARGET_NR_Linux + 249) +#define TARGET_NR_migrate_pages (TARGET_NR_Linux + 250) +#define TARGET_NR_openat (TARGET_NR_Linux + 251) +#define TARGET_NR_mkdirat (TARGET_NR_Linux + 252) +#define TARGET_NR_mknodat (TARGET_NR_Linux + 253) +#define TARGET_NR_fchownat (TARGET_NR_Linux + 254) +#define TARGET_NR_futimesat (TARGET_NR_Linux + 255) +#define TARGET_NR_newfstatat (TARGET_NR_Linux + 256) +#define TARGET_NR_unlinkat (TARGET_NR_Linux + 257) +#define TARGET_NR_renameat (TARGET_NR_Linux + 258) +#define TARGET_NR_linkat (TARGET_NR_Linux + 259) +#define TARGET_NR_symlinkat (TARGET_NR_Linux + 260) +#define TARGET_NR_readlinkat (TARGET_NR_Linux + 261) +#define TARGET_NR_fchmodat (TARGET_NR_Linux + 262) +#define TARGET_NR_faccessat (TARGET_NR_Linux + 263) +#define TARGET_NR_pselect6 (TARGET_NR_Linux + 264) +#define TARGET_NR_ppoll (TARGET_NR_Linux + 265) +#define TARGET_NR_unshare (TARGET_NR_Linux + 266) +#define TARGET_NR_splice (TARGET_NR_Linux + 267) +#define TARGET_NR_sync_file_range (TARGET_NR_Linux + 268) +#define TARGET_NR_tee (TARGET_NR_Linux + 269) +#define TARGET_NR_vmsplice (TARGET_NR_Linux + 270) +#define TARGET_NR_move_pages (TARGET_NR_Linux + 271) +#define TARGET_NR_set_robust_list (TARGET_NR_Linux + 272) +#define TARGET_NR_get_robust_list (TARGET_NR_Linux + 273) +#define TARGET_NR_kexec_load (TARGET_NR_Linux + 274) +#define TARGET_NR_getcpu (TARGET_NR_Linux + 275) +#define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 276) +#define TARGET_NR_ioprio_set (TARGET_NR_Linux + 277) +#define TARGET_NR_ioprio_get (TARGET_NR_Linux + 278) +#define TARGET_NR_utimensat (TARGET_NR_Linux + 279) +#define TARGET_NR_signalfd (TARGET_NR_Linux + 280) +#define TARGET_NR_timerfd (TARGET_NR_Linux + 281) +#define TARGET_NR_eventfd (TARGET_NR_Linux + 282) +#define TARGET_NR_fallocate (TARGET_NR_Linux + 283) diff --git a/linux-user/mipsn32/target_signal.h b/linux-user/mipsn32/target_signal.h new file mode 100644 index 000000000..4adf726e6 --- /dev/null +++ b/linux-user/mipsn32/target_signal.h @@ -0,0 +1,29 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + int32_t ss_sp; + uint32_t ss_size; + int32_t ss_flags; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) +{ + return state->gpr[29][state->current_tc]; +} + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/mipsn32/termbits.h b/linux-user/mipsn32/termbits.h new file mode 100644 index 000000000..d3a6cf8f9 --- /dev/null +++ b/linux-user/mipsn32/termbits.h @@ -0,0 +1,245 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 23 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_BOTHER 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_IEXTEN 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_TOSTOP 0100000 +#define TARGET_ITOSTOP TARGET_TOSTOP + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VMIN 4 +#define TARGET_VTIME 5 +#define TARGET_VEOL2 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +/* VDSUSP not supported */ +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOF 16 +#define TARGET_VEOL 17 + +/* ioctls */ + +#define TARGET_TCGETA 0x5401 +#define TARGET_TCSETA 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ +#define TARGET_TCSETAW 0x5403 +#define TARGET_TCSETAF 0x5404 + +#define TARGET_TCSBRK 0x5405 +#define TARGET_TCXONC 0x5406 +#define TARGET_TCFLSH 0x5407 + +#define TARGET_TCGETS 0x540d +#define TARGET_TCSETS 0x540e +#define TARGET_TCSETSW 0x540f +#define TARGET_TCSETSF 0x5410 + +#define TARGET_TIOCEXCL 0x740d /* set exclusive use of tty */ +#define TARGET_TIOCNXCL 0x740e /* reset exclusive use of tty */ +#define TARGET_TIOCOUTQ 0x7472 /* output queue size */ +#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */ +#define TARGET_TIOCMGET 0x741d /* get all modem bits */ +#define TARGET_TIOCMBIS 0x741b /* bis modem bits */ +#define TARGET_TIOCMBIC 0x741c /* bic modem bits */ +#define TARGET_TIOCMSET 0x741a /* set all modem bits */ +#define TARGET_TIOCPKT 0x5470 /* pty: set/clear packet mode */ +#define TARGET_TIOCPKT_DATA 0x00 /* data packet */ +#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */ +#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */ +#define TARGET_TIOCPKT_STOP 0x04 /* stop output */ +#define TARGET_TIOCPKT_START 0x08 /* start output */ +#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ +#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ +/* #define TIOCPKT_IOCTL 0x40 state change of pty driver */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) /* set window size */ +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) /* get window size */ +#define TARGET_TIOCNOTTY 0x5471 /* void tty association */ +#define TARGET_TIOCSETD 0x7401 +#define TARGET_TIOCGETD 0x7400 + +#define TARGET_FIOCLEX 0x6601 +#define TARGET_FIONCLEX 0x6602 +#define TARGET_FIOASYNC 0x667d +#define TARGET_FIONBIO 0x667e +#define TARGET_FIOQSIZE 0x667f + +#define TARGET_TIOCGLTC 0x7474 /* get special local chars */ +#define TARGET_TIOCSLTC 0x7475 /* set special local chars */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */ +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */ +#define TARGET_TIOCCONS TARGET_IOW('t', 120, int) /* become virtual console */ + +#define TARGET_FIONREAD 0x467f +#define TARGET_TIOCINQ TARGET_FIONREAD + +#define TARGET_TIOCGETP 0x7408 +#define TARGET_TIOCSETP 0x7409 +#define TARGET_TIOCSETN 0x740a /* TIOCSETP wo flush */ + +/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct termios) set termios struct */ +/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct termios) drain output, set */ +/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct termios) drn out, fls in, set */ +/* #define TARGET_TIOCGETD TARGET_IOR('t', 26, int) get line discipline */ +/* #define TARGET_TIOCSETD TARGET_IOW('t', 27, int) set line discipline */ + /* 127-124 compat */ + +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x7416 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +/* I hope the range from 0x5480 on is free ... */ +#define TARGET_TIOCSCTTY 0x5480 /* become controlling tty */ +#define TARGET_TIOCGSOFTCAR 0x5481 +#define TARGET_TIOCSSOFTCAR 0x5482 +#define TARGET_TIOCLINUX 0x5483 +#define TARGET_TIOCGSERIAL 0x5484 +#define TARGET_TIOCSSERIAL 0x5485 +#define TARGET_TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSERCONFIG 0x5488 +#define TARGET_TIOCSERGWILD 0x5489 +#define TARGET_TIOCSERSWILD 0x548a +#define TARGET_TIOCGLCKTRMIOS 0x548b +#define TARGET_TIOCSLCKTRMIOS 0x548c +#define TARGET_TIOCSERGSTRUCT 0x548d /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x548e /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x5493 /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x5494 /* Set Hayes ESP configuration */ diff --git a/linux-user/signal.c b/linux-user/signal.c index 945dd14e0..d17c506d2 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1704,6 +1704,64 @@ long do_rt_sigreturn(CPUState *env) return -ENOSYS; } +#elif defined(TARGET_MIPS64) + +# warning signal handling not implemented + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_frame: not implemented\n"); +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_sigreturn: not implemented\n"); + return -ENOSYS; +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + +#elif defined(TARGET_MIPSN32) + +# warning signal handling not implemented + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_frame: not implemented\n"); +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_sigreturn: not implemented\n"); + return -ENOSYS; +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + #elif defined(TARGET_MIPS) struct target_sigcontext { diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 07f4fd36c..90bea9b70 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -307,7 +307,9 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SA_NODEFER 0x40000000 #define TARGET_SA_RESTART 0x10000000 #define TARGET_SA_RESETHAND 0x80000000 +#if !defined(TARGET_MIPSN32) && !defined(TARGET_MIPS64) #define TARGET_SA_RESTORER 0x04000000 /* Only for o32 */ +#endif #else #define TARGET_SA_NOCLDSTOP 0x00000001 #define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ @@ -447,8 +449,12 @@ int do_sigaction(int sig, const struct target_sigaction *act, #if defined(TARGET_MIPS) struct target_sigaction { - target_ulong sa_flags; + uint32_t sa_flags; +#if defined(TARGET_MIPSN32) + uint32_t _sa_handler; +#else target_ulong _sa_handler; +#endif target_sigset_t sa_mask; }; @@ -860,6 +866,8 @@ struct target_winsize { #define TARGET_MAP_EXECUTABLE 0x4000 /* mark it as an executable */ #define TARGET_MAP_LOCKED 0x8000 /* pages are locked */ #define TARGET_MAP_NORESERVE 0x0400 /* don't check for reservations */ +#define TARGET_MAP_POPULATE 0x10000 /* populate (prefault) pagetables */ +#define TARGET_MAP_NONBLOCK 0x20000 /* do not block on IO */ #else #define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ #define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ @@ -872,6 +880,8 @@ struct target_winsize { #define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ #define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ #endif +#define TARGET_MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define TARGET_MAP_NONBLOCK 0x10000 /* do not block on IO */ #endif #if defined(TARGET_I386) || defined(TARGET_ARM) @@ -1184,6 +1194,116 @@ struct target_stat64 { unsigned long long st_ino; } __attribute__((packed)); +#elif defined(TARGET_MIPS64) + +/* The memory layout is the same as of struct stat64 of the 32-bit kernel. */ +struct target_stat { + unsigned int st_dev; + unsigned int st_pad0[3]; /* Reserved for st_dev expansion */ + + target_ulong st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + int st_uid; + int st_gid; + + unsigned int st_rdev; + unsigned int st_pad1[3]; /* Reserved for st_rdev expansion */ + + target_ulong st_size; + + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + unsigned int target_st_atime; + unsigned int target_st_atime_nsec; + + unsigned int target_st_mtime; + unsigned int target_st_mtime_nsec; + + unsigned int target_st_ctime; + unsigned int target_st_ctime_nsec; + + unsigned int st_blksize; + unsigned int st_pad2; + + target_ulong st_blocks; +}; + +#elif defined(TARGET_MIPSN32) + +struct target_stat { + unsigned st_dev; + int st_pad1[3]; /* Reserved for network id */ + unsigned int st_ino; + unsigned int st_mode; + unsigned int st_nlink; + int st_uid; + int st_gid; + unsigned st_rdev; + unsigned int st_pad2[2]; + unsigned int st_size; + unsigned int st_pad3; + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + unsigned int target_st_atime; + unsigned int target_st_atime_nsec; + unsigned int target_st_mtime; + unsigned int target_st_mtime_nsec; + unsigned int target_st_ctime; + unsigned int target_st_ctime_nsec; + unsigned int st_blksize; + unsigned int st_blocks; + unsigned int st_pad4[14]; +}; + +/* + * This matches struct stat64 in glibc2.1, hence the absolutely insane + * amounts of padding around dev_t's. The memory layout is the same as of + * struct stat of the 64-bit kernel. + */ + +struct target_stat64 { + unsigned int st_dev; + unsigned int st_pad0[3]; /* Reserved for st_dev expansion */ + + target_ulong st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + int st_uid; + int st_gid; + + unsigned int st_rdev; + unsigned int st_pad1[3]; /* Reserved for st_rdev expansion */ + + int st_size; + + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + int target_st_atime; + unsigned int target_st_atime_nsec; /* Reserved for st_atime expansion */ + + int target_st_mtime; + unsigned int target_st_mtime_nsec; /* Reserved for st_mtime expansion */ + + int target_st_ctime; + unsigned int target_st_ctime_nsec; /* Reserved for st_ctime expansion */ + + unsigned int st_blksize; + unsigned int st_pad2; + + int st_blocks; +}; + #elif defined(TARGET_MIPS) struct target_stat { @@ -1366,6 +1486,23 @@ typedef struct { } target_fsid_t; #ifdef TARGET_MIPS +#ifdef TARGET_MIPSN32 +struct target_statfs { + int32_t f_type; + int32_t f_bsize; + int32_t f_frsize; /* Fragment size - unsupported */ + int32_t f_blocks; + int32_t f_bfree; + int32_t f_files; + int32_t f_ffree; + int32_t f_bavail; + + /* Linux specials */ + target_fsid_t f_fsid; + int32_t f_namelen; + int32_t f_spare[6]; +}; +#else struct target_statfs { target_long f_type; target_long f_bsize; @@ -1381,6 +1518,7 @@ struct target_statfs { target_long f_namelen; target_long f_spare[6]; }; +#endif struct target_statfs64 { uint32_t f_type; diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh index cf1445935..941f0cf61 100644 --- a/qemu-binfmt-conf.sh +++ b/qemu-binfmt-conf.sh @@ -46,10 +46,14 @@ if [ $cpu != "ppc" ] ; then fi if [ $cpu != "m68k" ] ; then echo 'Please check cpu value and header information for m68k!' - echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register + echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register fi if [ $cpu != "mips" ] ; then # FIXME: We could use the other endianness on a MIPS host. echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register + echo ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mipsn32:' > /proc/sys/fs/binfmt_misc/register + echo ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsn32el:' > /proc/sys/fs/binfmt_misc/register + echo ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register + echo ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register fi diff --git a/target-mips/TODO b/target-mips/TODO index 78310dda8..2d207cf90 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -7,7 +7,7 @@ General MIPS64 ------ -- Only lighly tested but apparently functional as of 2007-05-31. +- Userland emulation (both n32 and n64) not functional. "Generic" 4Kc system emulation ------------------------------ diff --git a/target-mips/exec.h b/target-mips/exec.h index b6300bd49..8e909787e 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -56,7 +56,7 @@ register target_ulong T2 asm(AREG3); #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #if TARGET_LONG_BITS > HOST_LONG_BITS void do_dsll (void); void do_dsll32 (void); @@ -84,7 +84,7 @@ void do_maddu (void); void do_msub (void); void do_msubu (void); #endif -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void do_ddiv (void); #if TARGET_LONG_BITS > HOST_LONG_BITS void do_ddivu (void); @@ -104,7 +104,7 @@ void do_lwl_raw (uint32_t); void do_lwr_raw (uint32_t); uint32_t do_swl_raw (uint32_t); uint32_t do_swr_raw (uint32_t); -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void do_ldl_raw (uint64_t); void do_ldr_raw (uint64_t); uint64_t do_sdl_raw (uint64_t); @@ -119,7 +119,7 @@ uint32_t do_swl_user (uint32_t); uint32_t do_swl_kernel (uint32_t); uint32_t do_swr_user (uint32_t); uint32_t do_swr_kernel (uint32_t); -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void do_ldl_user (uint64_t); void do_ldl_kernel (uint64_t); void do_ldr_user (uint64_t); @@ -267,7 +267,7 @@ static inline void compute_hflags(CPUState *env) if (env->CP0_Status & (1 << CP0St_R0)) env->hflags |= MIPS_HFLAG_SM; } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if (!(env->hflags & MIPS_HFLAG_UM) || (env->CP0_Status & (1 << CP0St_PX)) || (env->CP0_Status & (1 << CP0St_UX))) diff --git a/target-mips/helper.c b/target-mips/helper.c index 7424cda56..9c72481c2 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -76,7 +76,7 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); target_ulong tag = address & ~mask; target_ulong VPN = tlb->VPN & ~mask; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) tag &= env->SEGMask; #endif @@ -108,7 +108,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM; int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM; int kernel_mode = !user_mode && !supervisor_mode; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; @@ -130,7 +130,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) /* XXX: Assuming : - PABITS = 36 (correct for MIPS64R1) @@ -308,7 +308,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) env->CP0_EntryHi &= env->SEGMask; env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) | ((address & 0xC00000000000ULL) >> (env->SEGBITS - 9)) | @@ -428,7 +428,7 @@ void do_interrupt (CPUState *env) case EXCP_TLBL: cause = 2; if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) int R = env->CP0_BadVAddr >> 62; int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; @@ -479,7 +479,7 @@ void do_interrupt (CPUState *env) case EXCP_THREAD: cause = 25; if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) int R = env->CP0_BadVAddr >> 62; int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; @@ -562,7 +562,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); if (tlb->V0) { addr = tlb->VPN & ~mask; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) { addr |= 0x3FFFFF0000000000ULL; } @@ -575,7 +575,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) } if (tlb->V1) { addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) { addr |= 0x3FFFFF0000000000ULL; } diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index a796c7e09..5c98edf97 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -8,7 +8,7 @@ #define TARGET_PAGE_BITS 12 #define MIPS_TLB_MAX 128 -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #define TARGET_LONG_BITS 64 #else #define TARGET_LONG_BITS 32 diff --git a/target-mips/op.c b/target-mips/op.c index 2f513aeb6..429097052 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -296,7 +296,7 @@ void op_addr_add (void) /* For compatibility with 32-bit code, data reference in user mode with Status_UX = 0 should be casted to 32-bit and sign extended. See the MIPS64 PRA manual, section 4.10. */ -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if ((env->hflags & MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_UX))) T0 = (int64_t)(int32_t)(T0 + T1); @@ -379,7 +379,7 @@ void op_divu (void) RETURN(); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) /* Arithmetic */ void op_dadd (void) { @@ -448,7 +448,7 @@ void op_ddivu (void) RETURN(); } #endif -#endif /* TARGET_MIPS64 */ +#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ /* Logical */ void op_and (void) @@ -569,7 +569,7 @@ void op_clz (void) RETURN(); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #if TARGET_LONG_BITS > HOST_LONG_BITS /* Those might call libgcc functions. */ @@ -770,7 +770,7 @@ void op_dclz (void) } RETURN(); } -#endif +#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ /* 64 bits arithmetic */ #if TARGET_LONG_BITS > HOST_LONG_BITS @@ -873,7 +873,7 @@ void op_msubu (void) } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void op_dmult (void) { CALL_FROM_TB4(muls64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1); @@ -977,7 +977,7 @@ void op_save_btarget (void) RETURN(); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void op_save_btarget64 (void) { env->btarget = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; @@ -1804,7 +1804,7 @@ void op_mtc0_entryhi (void) /* 1k pages not implemented */ val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF); -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) val &= env->SEGMask; #endif old = env->CP0_EntryHi; @@ -2031,7 +2031,7 @@ void op_mtc0_desave (void) RETURN(); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void op_dmfc0_yqmask (void) { T0 = env->CP0_YQMask; @@ -2145,7 +2145,7 @@ void op_dmfc0_errorepc (void) T0 = env->CP0_ErrorEPC; RETURN(); } -#endif /* TARGET_MIPS64 */ +#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ /* MIPS MT functions */ void op_mftgpr(void) @@ -3059,7 +3059,7 @@ void op_save_pc (void) RETURN(); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void op_save_pc64 (void) { env->PC[env->current_tc] = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; @@ -3131,7 +3131,7 @@ void op_wsbh(void) RETURN(); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void op_dext(void) { unsigned int pos = PARAM1; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d23a45c0b..f4313280e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -74,7 +74,7 @@ void do_raise_exception_direct (uint32_t exception) #undef MEMSUFFIX #endif -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #if TARGET_LONG_BITS > HOST_LONG_BITS /* Those might call libgcc functions. */ void do_dsll (void) @@ -154,7 +154,7 @@ void do_drotrv (void) T0 = T1; } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#endif /* TARGET_MIPS64 */ +#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ /* 64 bits arithmetic for 32 bits hosts */ #if TARGET_LONG_BITS > HOST_LONG_BITS @@ -223,7 +223,7 @@ void do_div (void) } #endif -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void do_ddiv (void) { if (T1 != 0) { @@ -242,7 +242,7 @@ void do_ddivu (void) } } #endif -#endif /* TARGET_MIPS64 */ +#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ #if defined(CONFIG_USER_ONLY) void do_mfc0_random (void) @@ -383,7 +383,7 @@ static void r4k_fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb->mmu.r4k.tlb[idx]; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) tlb->VPN &= env->SEGMask; #endif tlb->ASID = env->CP0_EntryHi & 0xFF; diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c index 8663d9a52..700fc17b1 100644 --- a/target-mips/op_helper_mem.c +++ b/target-mips/op_helper_mem.c @@ -124,7 +124,7 @@ uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) return tmp; } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #ifdef TARGET_WORDS_BIGENDIAN #define GET_LMASK64(v) ((v) & 7) @@ -298,4 +298,4 @@ uint64_t glue(do_sdr, MEMSUFFIX) (uint64_t tmp) return tmp; } -#endif /* TARGET_MIPS64 */ +#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 19241f143..a15ad5a96 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -130,7 +130,7 @@ void glue(op_sc, MEMSUFFIX) (void) RETURN(); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void glue(op_ld, MEMSUFFIX) (void) { T0 = glue(ldq, MEMSUFFIX)(T0); @@ -198,7 +198,7 @@ void glue(op_scd, MEMSUFFIX) (void) } RETURN(); } -#endif /* TARGET_MIPS64 */ +#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ void glue(op_lwc1, MEMSUFFIX) (void) { diff --git a/target-mips/op_template.c b/target-mips/op_template.c index f3a05ade6..148656eb2 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -82,7 +82,7 @@ SET_RESET(T2, _T2) #undef SET_RESET -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #define SET64(treg, tregname) \ void glue(op_set64, tregname)(void) \ { \ diff --git a/target-mips/translate.c b/target-mips/translate.c index d4dfb2a6f..d3f80f298 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -590,7 +590,7 @@ do { \ } \ } while (0) -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #define GEN_LOAD_IMM_TN(Tn, Imm) \ do { \ if (Imm == 0) { \ @@ -638,7 +638,7 @@ do { \ static inline void gen_save_pc(target_ulong pc) { -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if (pc == (int32_t)pc) { gen_op_save_pc(pc); } else { @@ -651,7 +651,7 @@ static inline void gen_save_pc(target_ulong pc) static inline void gen_save_btarget(target_ulong btarget) { -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if (btarget == (int32_t)btarget) { gen_op_save_btarget(btarget); } else { @@ -808,7 +808,7 @@ static GenOpFunc *gen_op_s##width[] = { \ } #endif -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) OP_LD_TABLE(d); OP_LD_TABLE(dl); OP_LD_TABLE(dr); @@ -858,7 +858,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, /* Don't do NOP if destination is zero: we must perform the actual memory access. */ switch (opc) { -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_LWU: op_ldst(lwu); GEN_STORE_TN_REG(rt, T0); @@ -1054,7 +1054,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, switch (opc) { case OPC_ADDI: case OPC_ADDIU: -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DADDI: case OPC_DADDIU: #endif @@ -1074,7 +1074,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, case OPC_SLL: case OPC_SRA: case OPC_SRL: -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DSLL: case OPC_DSRA: case OPC_DSRL: @@ -1097,7 +1097,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, gen_op_add(); opn = "addiu"; break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DADDI: save_cpu_state(ctx, 1); gen_op_daddo(); @@ -1161,7 +1161,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, break; } break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DSLL: gen_op_dsll(); opn = "dsll"; @@ -1266,7 +1266,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, gen_op_sub(); opn = "subu"; break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DADD: save_cpu_state(ctx, 1); gen_op_daddo(); @@ -1352,7 +1352,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, break; } break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DSLLV: gen_op_dsllv(); opn = "dsllv"; @@ -1457,7 +1457,7 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, gen_op_multu(); opn = "multu"; break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DDIV: gen_op_ddiv(); opn = "ddiv"; @@ -1518,7 +1518,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, gen_op_clz(); opn = "clz"; break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DCLO: gen_op_dclo(); opn = "dclo"; @@ -2325,7 +2325,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) check_insn(env, ctx, ISA_MIPS3); gen_op_mfc0_xcontext(); rn = "XContext"; @@ -2907,7 +2907,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) check_insn(env, ctx, ISA_MIPS3); gen_op_mtc0_xcontext(); rn = "XContext"; @@ -3117,7 +3117,7 @@ die: generate_exception(ctx, EXCP_RI); } -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -4260,7 +4260,7 @@ die: #endif generate_exception(ctx, EXCP_RI); } -#endif /* TARGET_MIPS64 */ +#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int u, int sel, int h) @@ -4610,7 +4610,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DMFC0: check_insn(env, ctx, ISA_MIPS3); if (rt == 0) { @@ -5884,7 +5884,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, /* MIPS16 extension to MIPS32 */ /* SmartMIPS extension to MIPS32 */ -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) /* MDMX extension to MIPS64 */ /* MIPS-3D extension to MIPS64 */ @@ -5995,7 +5995,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) /* MIPS64 specific opcodes */ case OPC_DSLL: case OPC_DSRL ... OPC_DSRA: @@ -6051,7 +6051,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } /* Treat as NOP. */ break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DCLZ ... OPC_DCLO: check_insn(env, ctx, ISA_MIPS64); check_mips_64(ctx); @@ -6138,7 +6138,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_op_yield(); GEN_STORE_TN_REG(rd, T0); break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: check_insn(env, ctx, ISA_MIPS64R2); @@ -6200,7 +6200,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_MTC0: case OPC_MFTR: case OPC_MTTR: -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DMFC0: case OPC_DMTC0: #endif @@ -6321,7 +6321,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_CTC1: gen_cp1(ctx, op1, rt, rd); break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) case OPC_DMFC1: case OPC_DMTC1: check_insn(env, ctx, ISA_MIPS3); @@ -6404,7 +6404,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) /* MIPS64 opcodes */ case OPC_LWU: case OPC_LDL ... OPC_LDR: @@ -6671,7 +6671,7 @@ void dump_fpu (CPUState *env) } } -#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) +#if (defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) /* Debug help: The architecture requires 32bit code to maintain proper sign-extened values on 64bit machines. */ @@ -6726,7 +6726,7 @@ void cpu_dump_state (CPUState *env, FILE *f, env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); if (env->hflags & MIPS_HFLAG_FPU) fpu_dump_state(env, f, cpu_fprintf, flags); -#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) +#if (defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags); #endif } diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index b9f326656..748b9dd85 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -201,7 +201,7 @@ static mips_def_t mips_defs[] = (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13), .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, }, -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) { .name = "R4000", .CP0_PRid = 0x00000400, @@ -416,7 +416,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask; env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask; env->CP0_SRSCtl = def->CP0_SRSCtl; -#ifdef TARGET_MIPS64 +#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if (def->insn_flags & ISA_MIPS3) { env->hflags |= MIPS_HFLAG_64; -- cgit v1.2.3 From cf575356bfeda7eca56060bc4c6a2423869a262b Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 30 Sep 2007 02:10:37 +0000 Subject: Remove unused variable. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3285 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/r2d.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/r2d.c b/hw/r2d.c index 345ef91ea..33d03cbbf 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -32,7 +32,6 @@ void r2d_init(int ram_size, int vga_ram_size, int boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - int ret; CPUState *env; struct SH7750State *s; -- cgit v1.2.3 From 1548b15d23d33b8125a0268eaf2126088510a181 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 30 Sep 2007 02:14:03 +0000 Subject: Add mipsn32{,el}-linux-user. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3286 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cvsignore b/.cvsignore index 830aaa1f1..2d6f37f35 100644 --- a/.cvsignore +++ b/.cvsignore @@ -35,6 +35,8 @@ mips-linux-user mipsel-linux-user mips64-softmmu mips64el-softmmu +mipsn32-linux-user +mipsn32el-linux-user mips64-linux-user mips64el-linux-user m68k-linux-user -- cgit v1.2.3 From 0db1b20e478efd378c19e79057453a79b4c81e11 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 03:46:38 +0000 Subject: Synchronize with latest PowerPC ISA VEA: * fix invalid instructions bits masks * new wait instruction * more comments about effect of cache instructions on the MMU git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3287 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 08cd92cde..612b0ad85 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -478,6 +478,8 @@ enum { PPC_DCRUX = 0x0000040000000000ULL, /* New floating-point extensions (PowerPC 2.0x) */ PPC_FLOAT_EXT = 0x0000080000000000ULL, + /* New wait instruction (PowerPC 2.0x) */ + PPC_WAIT = 0x0000100000000000ULL, }; /*****************************************************************************/ @@ -2463,12 +2465,12 @@ GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) /*** Memory synchronisation ***/ /* eieio */ -GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO) +GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO) { } /* isync */ -GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM) +GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM) { GEN_STOP(ctx); } @@ -2610,10 +2612,18 @@ GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B) #endif /* defined(TARGET_PPC64) */ /* sync */ -GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03CF0801, PPC_MEM_SYNC) +GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03BFF801, PPC_MEM_SYNC) { } +/* wait */ +GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT) +{ + /* Stop translation, as the CPU is supposed to sleep from now */ + /* XXX: TODO: handle this idle CPU case */ + GEN_STOP(ctx); +} + /*** Floating-point load ***/ #define GEN_LDF(width, opc, type) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \ @@ -3328,7 +3338,7 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) * We just have to flush tb while invalidating instruction cache lines... */ /* dcbf */ -GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) +GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE) { gen_addr_reg_index(ctx); op_ldst(lbz); @@ -3360,16 +3370,18 @@ GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) } /* dcbt */ -GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE) +GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE) { + /* interpreted as no-op */ /* XXX: specification say this is treated as a load by the MMU * but does not generate any exception */ } /* dcbtst */ -GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE) +GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE) { + /* interpreted as no-op */ /* XXX: specification say this is treated as a load by the MMU * but does not generate any exception */ @@ -3468,6 +3480,10 @@ GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) /* dcba */ GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA) { + /* interpreted as no-op */ + /* XXX: specification say this is treated as a store by the MMU + * but does not generate any exception + */ } /*** Segment register manipulation ***/ @@ -5012,7 +5028,7 @@ GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE) } /* msync replaces sync on 440 */ -GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE) +GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE) { /* interpreted as no-op */ } -- cgit v1.2.3 From b0566f4f4584ca1c968daf64007df58cb5a21038 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 30 Sep 2007 13:01:15 +0000 Subject: Support UltraVNC clients, by Eduardo Felipe. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3288 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vnc.c b/vnc.c index 068da05c1..72c8d1cce 100644 --- a/vnc.c +++ b/vnc.c @@ -1818,6 +1818,7 @@ static int protocol_version(VncState *vs, char *version, size_t len) VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor); if (vs->major != 3 || (vs->minor != 3 && + vs->minor != 4 && vs->minor != 5 && vs->minor != 7 && vs->minor != 8)) { @@ -1827,10 +1828,10 @@ static int protocol_version(VncState *vs, char *version, size_t len) vnc_client_error(vs); return 0; } - /* Some broken client report v3.5 which spec requires to be treated + /* Some broken clients report v3.4 or v3.5, which spec requires to be treated * as equivalent to v3.3 by servers */ - if (vs->minor == 5) + if (vs->minor == 4 || vs->minor == 5) vs->minor = 3; if (vs->minor == 3) { -- cgit v1.2.3 From be147d08790d4d80bfcf2c209031eede52b7dd62 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 13:03:23 +0000 Subject: * Update OEA environment, following the PowerPC 2.04 specification: - New mtmsr/mtmsrd form that just update RI and EE bits - New hrfid, lq and stq instructions - Add support for supervisor and hypervisor modes process priority update - Code provision for hypervisor SPR accesses * Actually implement the wait instruction * Bugfixes (missing RETURN in micro-op / missing #ifdef) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3289 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 7 ++ target-ppc/op.c | 23 +++++- target-ppc/op_helper.c | 16 ++++ target-ppc/op_helper.h | 3 + target-ppc/translate.c | 196 +++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 213 insertions(+), 32 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 791f30524..53f4af3d2 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -287,6 +287,7 @@ enum { #define PPC_INPUT(env) (env->bus_model) +/*****************************************************************************/ typedef struct ppc_def_t ppc_def_t; typedef struct opc_handler_t opc_handler_t; @@ -306,6 +307,10 @@ struct ppc_spr_t { #if !defined(CONFIG_USER_ONLY) void (*oea_read)(void *opaque, int spr_num); void (*oea_write)(void *opaque, int spr_num); +#if defined(TARGET_PPC64H) + void (*hea_read)(void *opaque, int spr_num); + void (*hea_write)(void *opaque, int spr_num); +#endif #endif const unsigned char *name; }; @@ -607,7 +612,9 @@ target_ulong ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, target_ulong value); target_ulong do_load_msr (CPUPPCState *env); void do_store_msr (CPUPPCState *env, target_ulong value); +#if defined(TARGET_PPC64) void ppc_store_msr_32 (CPUPPCState *env, uint32_t value); +#endif void do_compute_hflags (CPUPPCState *env); void cpu_ppc_reset (void *opaque); diff --git a/target-ppc/op.c b/target-ppc/op.c index fa8477ab9..0694caf80 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -355,6 +355,13 @@ void OPPROTO op_store_msr (void) RETURN(); } +void OPPROTO op_update_riee (void) +{ + msr_ri = (T0 >> MSR_RI) & 1; + msr_ee = (T0 >> MSR_EE) & 1; + RETURN(); +} + #if defined (TARGET_PPC64) void OPPROTO op_store_msr_32 (void) { @@ -1913,6 +1920,12 @@ void OPPROTO op_check_reservation_64 (void) } #endif +void OPPROTO op_wait (void) +{ + env->halted = 1; + RETURN(); +} + /* Return from interrupt */ #if !defined(CONFIG_USER_ONLY) void OPPROTO op_rfi (void) @@ -1928,6 +1941,14 @@ void OPPROTO op_rfid (void) RETURN(); } #endif + +#if defined(TARGET_PPC64H) +void OPPROTO op_hrfid (void) +{ + do_hrfid(); + RETURN(); +} +#endif #endif /* Trap word */ @@ -2557,6 +2578,7 @@ void OPPROTO op_store_40x_pit (void) void OPPROTO op_store_40x_dbcr0 (void) { store_40x_dbcr0(env, T0); + RETURN(); } void OPPROTO op_store_40x_sler (void) @@ -2576,7 +2598,6 @@ void OPPROTO op_store_booke_tsr (void) store_booke_tsr(env, T0); RETURN(); } - #endif /* !defined(CONFIG_USER_ONLY) */ #if defined(TARGET_PPCEMB) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index d75331722..5223b1543 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1002,6 +1002,22 @@ void do_rfid (void) env->interrupt_request |= CPU_INTERRUPT_EXITTB; } #endif +#if defined(TARGET_PPC64H) +void do_hrfid (void) +{ + if (env->spr[SPR_HSRR1] & (1ULL << MSR_SF)) { + env->nip = (uint64_t)(env->spr[SPR_HSRR0] & ~0x00000003); + do_store_msr(env, (uint64_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL)); + } else { + env->nip = (uint32_t)(env->spr[SPR_HSRR0] & ~0x00000003); + do_store_msr(env, (uint32_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL)); + } +#if defined (DEBUG_OP) + cpu_dump_rfi(env->nip, do_load_msr(env)); +#endif + env->interrupt_request |= CPU_INTERRUPT_EXITTB; +} +#endif #endif void do_tw (int flags) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index c5b4f2d19..c7235cc3e 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -131,6 +131,9 @@ void do_rfi (void); #if defined(TARGET_PPC64) void do_rfid (void); #endif +#if defined(TARGET_PPC64H) +void do_hrfid (void); +#endif void do_tlbia (void); void do_tlbie (void); #if defined(TARGET_PPC64) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 612b0ad85..3f7b79927 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -480,6 +480,8 @@ enum { PPC_FLOAT_EXT = 0x0000080000000000ULL, /* New wait instruction (PowerPC 2.0x) */ PPC_WAIT = 0x0000100000000000ULL, + /* New 64 bits extensions (PowerPC 2.0x) */ + PPC_64BX = 0x0000200000000000ULL, }; /*****************************************************************************/ @@ -1141,6 +1143,34 @@ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) /* Set process priority to normal */ gen_op_store_pri(4); break; +#if !defined(CONFIG_USER_ONLY) + case 31: + if (ctx->supervisor > 0) { + /* Set process priority to very low */ + gen_op_store_pri(1); + } + break; + case 5: + if (ctx->supervisor > 0) { + /* Set process priority to medium-hight */ + gen_op_store_pri(5); + } + break; + case 3: + if (ctx->supervisor > 0) { + /* Set process priority to high */ + gen_op_store_pri(6); + } + break; +#if defined(TARGET_PPC64H) + case 7: + if (ctx->supervisor > 1) { + /* Set process priority to very high */ + gen_op_store_pri(7); + } + break; +#endif +#endif default: /* nop */ break; @@ -1902,12 +1932,11 @@ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) /*** Addressing modes ***/ /* Register indirect with immediate index : EA = (rA|0) + SIMM */ -static inline void gen_addr_imm_index (DisasContext *ctx, int maskl) +static inline void gen_addr_imm_index (DisasContext *ctx, target_long maskl) { target_long simm = SIMM(ctx->opcode); - if (maskl) - simm &= ~0x03; + simm &= ~maskl; if (rA(ctx->opcode) == 0) { gen_set_T0(simm); } else { @@ -2051,7 +2080,7 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ return; \ } \ if (type == PPC_64B) \ - gen_addr_imm_index(ctx, 1); \ + gen_addr_imm_index(ctx, 0x03); \ else \ gen_addr_imm_index(ctx, 0); \ op_ldst(l##width); \ @@ -2116,7 +2145,7 @@ GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B) return; } } - gen_addr_imm_index(ctx, 1); + gen_addr_imm_index(ctx, 0x03); if (ctx->opcode & 0x02) { /* lwa (lwau is undefined) */ op_ldst(lwa); @@ -2128,6 +2157,38 @@ GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B) if (Rc(ctx->opcode)) gen_op_store_T0_gpr(rA(ctx->opcode)); } +/* lq */ +GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX) +{ +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVOPC(ctx); +#else + int ra, rd; + + /* Restore CPU state */ + if (unlikely(ctx->supervisor == 0)) { + GEN_EXCP_PRIVOPC(ctx); + return; + } + ra = rA(ctx->opcode); + rd = rD(ctx->opcode); + if (unlikely((rd & 1) || rd == ra)) { + GEN_EXCP_INVAL(ctx); + return; + } + if (unlikely(ctx->mem_idx & 1)) { + /* Little-endian mode is not handled */ + GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE); + return; + } + gen_addr_imm_index(ctx, 0x0F); + op_ldst(ld); + gen_op_store_T1_gpr(rd); + gen_op_addi(8); + op_ldst(ld); + gen_op_store_T1_gpr(rd + 1); +#endif +} #endif /*** Integer store ***/ @@ -2147,7 +2208,7 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \ return; \ } \ if (type == PPC_64B) \ - gen_addr_imm_index(ctx, 1); \ + gen_addr_imm_index(ctx, 0x03); \ else \ gen_addr_imm_index(ctx, 0); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ @@ -2193,19 +2254,50 @@ GEN_STS(w, 0x04, PPC_INTEGER); OP_ST_TABLE(d); GEN_STUX(d, 0x15, 0x05, PPC_64B); GEN_STX(d, 0x15, 0x04, PPC_64B); -GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B) +GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B) { - if (Rc(ctx->opcode)) { - if (unlikely(rA(ctx->opcode) == 0)) { + int rs; + + rs = rS(ctx->opcode); + if ((ctx->opcode & 0x3) == 0x2) { +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVOPC(ctx); +#else + /* stq */ + if (unlikely(ctx->supervisor == 0)) { + GEN_EXCP_PRIVOPC(ctx); + return; + } + if (unlikely(rs & 1)) { GEN_EXCP_INVAL(ctx); return; } + if (unlikely(ctx->mem_idx & 1)) { + /* Little-endian mode is not handled */ + GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE); + return; + } + gen_addr_imm_index(ctx, 0x03); + gen_op_load_gpr_T1(rs); + op_ldst(std); + gen_op_addi(8); + gen_op_load_gpr_T1(rs + 1); + op_ldst(std); +#endif + } else { + /* std / stdu */ + if (Rc(ctx->opcode)) { + if (unlikely(rA(ctx->opcode) == 0)) { + GEN_EXCP_INVAL(ctx); + return; + } + } + gen_addr_imm_index(ctx, 0x03); + gen_op_load_gpr_T1(rs); + op_ldst(std); + if (Rc(ctx->opcode)) + gen_op_store_T0_gpr(rA(ctx->opcode)); } - gen_addr_imm_index(ctx, 1); - gen_op_load_gpr_T1(rS(ctx->opcode)); - op_ldst(std); - if (Rc(ctx->opcode)) - gen_op_store_T0_gpr(rA(ctx->opcode)); } #endif /*** Integer load and store with byte reverse ***/ @@ -2620,8 +2712,8 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03BFF801, PPC_MEM_SYNC) GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT) { /* Stop translation, as the CPU is supposed to sleep from now */ - /* XXX: TODO: handle this idle CPU case */ - GEN_STOP(ctx); + gen_op_wait(); + GEN_EXCP(ctx, EXCP_HLT, 1); } /*** Floating-point load ***/ @@ -3077,6 +3169,23 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B) } #endif +#if defined(TARGET_PPC64H) +GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64B) +{ +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVOPC(ctx); +#else + /* Restore CPU state */ + if (unlikely(ctx->supervisor <= 1)) { + GEN_EXCP_PRIVOPC(ctx); + return; + } + gen_op_hrfid(); + GEN_SYNC(ctx); +#endif +} +#endif + /* sc */ GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW) { @@ -3193,6 +3302,11 @@ static inline void gen_op_mfspr (DisasContext *ctx) uint32_t sprn = SPR(ctx->opcode); #if !defined(CONFIG_USER_ONLY) +#if defined(TARGET_PPC64H) + if (ctx->supervisor == 2) + read_cb = ctx->spr_cb[sprn].hea_read; + else +#endif if (ctx->supervisor) read_cb = ctx->spr_cb[sprn].oea_read; else @@ -3253,7 +3367,7 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) /* mtmsr */ #if defined(TARGET_PPC64) -GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_64B) +GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -3262,12 +3376,17 @@ GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_64B) GEN_EXCP_PRIVREG(ctx); return; } - gen_update_nip(ctx, ctx->nip); gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_store_msr(); - /* Must stop the translation as machine state (may have) changed */ - /* Note that mtmsr is not always defined as context-synchronizing */ - GEN_STOP(ctx); + if (ctx->opcode & 0x00010000) { + /* Special form that does not need any synchronisation */ + gen_op_update_riee(); + } else { + gen_update_nip(ctx, ctx->nip); + gen_op_store_msr(); + /* Must stop the translation as machine state (may have) changed */ + /* Note that mtmsr is not always defined as context-synchronizing */ + GEN_STOP(ctx); + } #endif } #endif @@ -3281,17 +3400,22 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) GEN_EXCP_PRIVREG(ctx); return; } - gen_update_nip(ctx, ctx->nip); gen_op_load_gpr_T0(rS(ctx->opcode)); + if (ctx->opcode & 0x00010000) { + /* Special form that does not need any synchronisation */ + gen_op_update_riee(); + } else { + gen_update_nip(ctx, ctx->nip); #if defined(TARGET_PPC64) - if (!ctx->sf_mode) - gen_op_store_msr_32(); - else + if (!ctx->sf_mode) + gen_op_store_msr_32(); + else #endif - gen_op_store_msr(); - /* Must stop the translation as machine state (may have) changed */ - /* Note that mtmsrd is not always defined as context-synchronizing */ - GEN_STOP(ctx); + gen_op_store_msr(); + /* Must stop the translation as machine state (may have) changed */ + /* Note that mtmsrd is not always defined as context-synchronizing */ + GEN_STOP(ctx); + } #endif } @@ -3302,6 +3426,11 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) uint32_t sprn = SPR(ctx->opcode); #if !defined(CONFIG_USER_ONLY) +#if defined(TARGET_PPC64H) + if (ctx->supervisor == 2) + write_cb = ctx->spr_cb[sprn].hea_write; + else +#endif if (ctx->supervisor) write_cb = ctx->spr_cb[sprn].oea_write; else @@ -6011,7 +6140,12 @@ static inline int gen_intermediate_code_internal (CPUState *env, ctx.mem_idx |= msr_sf << 1; #endif #else - ctx.supervisor = 1 - msr_pr; +#if defined(TARGET_PPC64H) + if (msr_pr == 0 && msr_hv == 1) + ctx.supervisor = 2; + else +#endif + ctx.supervisor = 1 - msr_pr; ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le; #if defined(TARGET_PPC64) ctx.mem_idx |= msr_sf << 2; -- cgit v1.2.3 From 0574b6fb10862d464be9b748e5d9e5327d178770 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 30 Sep 2007 13:49:22 +0000 Subject: Add get_sp_from_cpustate implementation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3290 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/sparc64/target_signal.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h index bf54ac71d..dfca12916 100644 --- a/linux-user/sparc64/target_signal.h +++ b/linux-user/sparc64/target_signal.h @@ -21,4 +21,16 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_SIGSTKSZ 16384 +#ifndef UREG_I6 +#define UREG_I6 6 +#endif +#ifndef UREG_FP +#define UREG_FP UREG_I6 +#endif + +static inline target_ulong get_sp_from_cpustate(CPUSPARCState *state) +{ + return state->regwptr[UREG_FP]; +} + #endif /* TARGET_SIGNAL_H */ -- cgit v1.2.3 From a5b85f7959378bc038803e51918e0f64461eb9b6 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 30 Sep 2007 14:32:45 +0000 Subject: Fix mmap to handle differing host/target page sizes, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3291 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mmap.c | 102 ++++++++++++++++++++++++++++++++++-------------------- linux-user/qemu.h | 4 +-- 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 29f1d9625..ea916b80a 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -36,7 +36,8 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) int prot1, ret; #ifdef DEBUG_MMAP - printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len, + printf("mprotect: start=0x" TARGET_FMT_lx + "len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', prot & PROT_EXEC ? 'x' : '-'); @@ -151,11 +152,11 @@ static int mmap_frag(target_ulong real_start, } /* NOTE: all the constants are the HOST ones */ -long target_mmap(target_ulong start, target_ulong len, int prot, +target_long target_mmap(target_ulong start, target_ulong len, int prot, int flags, int fd, target_ulong offset) { target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; - long host_start; + unsigned long host_start; #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ defined(__ia64) || defined(__mips__) static target_ulong last_start = 0x40000000; @@ -166,7 +167,8 @@ long target_mmap(target_ulong start, target_ulong len, int prot, #ifdef DEBUG_MMAP { - printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", + printf("mmap: start=0x" TARGET_FMT_lx + " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=", start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', @@ -186,7 +188,7 @@ long target_mmap(target_ulong start, target_ulong len, int prot, printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); break; } - printf("fd=%d offset=%lx\n", fd, offset); + printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset); } #endif @@ -209,34 +211,59 @@ long target_mmap(target_ulong start, target_ulong len, int prot, last_start += HOST_PAGE_ALIGN(len); } #endif - if (0 && qemu_host_page_size != qemu_real_host_page_size) { - /* NOTE: this code is only for debugging with '-p' option */ - /* ??? Can also occur when TARGET_PAGE_SIZE > host page size. */ - /* reserve a memory area */ - /* ??? This needs fixing for remapping. */ -abort(); - host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; - real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (real_start == -1) - return real_start; - real_end = real_start + host_len; - start = HOST_PAGE_ALIGN(real_start); - end = start + HOST_PAGE_ALIGN(len); - if (start > real_start) - munmap((void *)g2h(real_start), start - real_start); - if (end < real_end) - munmap((void *)g2h(end), real_end - end); - /* use it as a fixed mapping */ - flags |= MAP_FIXED; - } else { - /* if not fixed, no need to do anything */ host_offset = offset & qemu_host_page_mask; host_len = len + offset - host_offset; + + if (qemu_host_page_size > qemu_real_host_page_size) { + /* + * The guest expects to see mmapped areas aligned to it's pagesize. + * If the host's real page size is smaller than the guest's, we need + * to fixup the maps. It is done by allocating a larger area, + * displacing the map (if needed) and finally chopping off the spare + * room at the edges. + */ + + /* + * We assume qemu_host_page_size is always the same as + * TARGET_PAGE_SIZE, see exec.c. qemu_real_host_page_size is the + * hosts real page size. + */ + target_ulong host_end; + unsigned long host_aligned_start; + + host_len = HOST_PAGE_ALIGN(host_len + qemu_host_page_size + - qemu_real_host_page_size); + host_start = (unsigned long) mmap(real_start ? + g2h(real_start) : NULL, + host_len, prot, flags, + fd, host_offset); + if (host_start == -1) + return -1; + + host_end = host_start + host_len; + + /* Find start and end, aligned to the targets pagesize with-in the + large mmaped area. */ + host_aligned_start = TARGET_PAGE_ALIGN(host_start); + if (!(flags & MAP_ANONYMOUS)) + host_aligned_start += offset - host_offset; + + start = h2g(host_aligned_start); + end = start + TARGET_PAGE_ALIGN(len); + + /* Chop off the leftovers, if any. */ + if (host_aligned_start > host_start) + munmap((void *)host_start, host_aligned_start - host_start); + if (end < host_end) + munmap((void *)g2h(end), host_end - end); + + goto the_end1; + } else { + /* if not fixed, no need to do anything */ host_start = (long)mmap(real_start ? g2h(real_start) : NULL, host_len, prot, flags, fd, host_offset); if (host_start == -1) - return host_start; + return -1; /* update start so that it points to the file position at 'offset' */ if (!(flags & MAP_ANONYMOUS)) host_start += offset - host_offset; @@ -267,7 +294,7 @@ abort(); MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (retaddr == -1) - return retaddr; + return -1; pread(fd, g2h(start), len, offset); if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); @@ -300,7 +327,7 @@ abort(); prot, flags, fd, offset + real_end - qemu_host_page_size - start); if (ret == -1) - return ret; + return -1; real_end -= qemu_host_page_size; } @@ -314,13 +341,13 @@ abort(); ret = (long)mmap(g2h(real_start), real_end - real_start, prot, flags, fd, offset1); if (ret == -1) - return ret; + return -1; } the_end1: page_set_flags(start, start + len, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP - printf("ret=0x%lx\n", (long)start); + printf("ret=0x%llx\n", start); page_dump(stdout); printf("\n"); #endif @@ -381,17 +408,18 @@ int target_munmap(target_ulong start, target_ulong len) /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED blocks which have been allocated starting on a host page */ -long target_mremap(target_ulong old_addr, target_ulong old_size, +target_long target_mremap(target_ulong old_addr, target_ulong old_size, target_ulong new_size, unsigned long flags, target_ulong new_addr) { int prot; + unsigned long host_addr; /* XXX: use 5 args syscall */ - new_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); - if (new_addr == -1) - return new_addr; - new_addr = h2g(new_addr); + host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); + if (host_addr == -1) + return -1; + new_addr = h2g(host_addr); prot = page_get_flags(old_addr); page_set_flags(old_addr, old_addr + old_size, 0); page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 78e9ab34f..e07ac7b4d 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -164,10 +164,10 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr); /* mmap.c */ int target_mprotect(target_ulong start, target_ulong len, int prot); -long target_mmap(target_ulong start, target_ulong len, int prot, +target_long target_mmap(target_ulong start, target_ulong len, int prot, int flags, int fd, target_ulong offset); int target_munmap(target_ulong start, target_ulong len); -long target_mremap(target_ulong old_addr, target_ulong old_size, +target_long target_mremap(target_ulong old_addr, target_ulong old_size, target_ulong new_size, unsigned long flags, target_ulong new_addr); int target_msync(target_ulong start, target_ulong len, int flags); -- cgit v1.2.3 From 8a84de23b8f8fc63338dfcc58f572e33c428c1b7 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 14:44:52 +0000 Subject: Fix compilation on Darwin platform, avoiding the use of gcc function attributes (problem reported by Andreas Farber). : ---------------------------------------------------------------------- git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3292 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 2 +- hw/ppc.c | 22 ++++++++++++++++++---- vl.h | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/exec-all.h b/exec-all.h index 3151bb591..dc5a10d97 100644 --- a/exec-all.h +++ b/exec-all.h @@ -38,7 +38,7 @@ #endif #ifndef always_inline -#if __GNUC__ < 3 +#if (__GNUC__ < 3) || defined(__APPLE__) #define always_inline inline #else #define always_inline __attribute__ (( always_inline )) inline diff --git a/hw/ppc.c b/hw/ppc.c index 270097bf1..bde3bfcd0 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -445,7 +445,7 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) return tb & 0xFFFFFFFF; } -uint32_t cpu_ppc_load_tbu (CPUState *env) +static inline uint32_t _cpu_ppc_load_tbu (CPUState *env) { ppc_tb_t *tb_env = env->tb_env; uint64_t tb; @@ -460,6 +460,11 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) return tb >> 32; } +uint32_t cpu_ppc_load_tbu (CPUState *env) +{ + return _cpu_ppc_load_tbu(env); +} + static inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, int64_t *tb_offsetp, uint64_t value) { @@ -483,7 +488,7 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, tb | (uint64_t)value); } -void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +static inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value) { ppc_tb_t *tb_env = env->tb_env; uint64_t tb; @@ -494,6 +499,11 @@ void cpu_ppc_store_tbu (CPUState *env, uint32_t value) ((uint64_t)value << 32) | tb); } +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +{ + _cpu_ppc_store_tbu(env, value); +} + uint32_t cpu_ppc_load_atbl (CPUState *env) { ppc_tb_t *tb_env = env->tb_env; @@ -738,10 +748,14 @@ clk_setup_cb cpu_ppc601_rtc_init (CPUState *env) } void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value) -__attribute__ (( alias ("cpu_ppc_store_tbu") )); +{ + _cpu_ppc_store_tbu(env, value); +} uint32_t cpu_ppc601_load_rtcu (CPUState *env) -__attribute__ (( alias ("cpu_ppc_load_tbu") )); +{ + return _cpu_ppc_load_tbu(env); +} void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value) { diff --git a/vl.h b/vl.h index 4e0628332..0add259de 100644 --- a/vl.h +++ b/vl.h @@ -110,7 +110,7 @@ static inline char *realpath(const char *path, char *resolved_path) #endif #ifndef always_inline -#if __GNUC__ < 3 +#if (__GNUC__ < 3) || defined(__APPLE__) #define always_inline inline #else #define always_inline __attribute__ (( always_inline )) inline -- cgit v1.2.3 From 068abdc8a57023eeafe1025b964a50f8a39929b4 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 14:52:08 +0000 Subject: Fix inconsistent end conditions in ppc_find_xxx functions. (crash reported by Andreas Farber when using default CPU). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3293 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 285e35143..13069c53e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -5872,11 +5872,12 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) { - int i, ret; + int i, max, ret; ret = -1; *def = NULL; - for (i = 0; strcmp(ppc_defs[i].name, "default") != 0; i++) { + max = sizeof(ppc_defs) / sizeof(ppc_def_t); + for (i = 0; i < max; i++) { if (strcasecmp(name, ppc_defs[i].name) == 0) { *def = &ppc_defs[i]; ret = 0; @@ -5889,11 +5890,12 @@ int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) int ppc_find_by_pvr (uint32_t pvr, ppc_def_t **def) { - int i, ret; + int i, max, ret; ret = -1; *def = NULL; - for (i = 0; ppc_defs[i].name != NULL; i++) { + max = sizeof(ppc_defs) / sizeof(ppc_def_t); + for (i = 0; i < max; i++) { if ((pvr & ppc_defs[i].pvr_mask) == (ppc_defs[i].pvr & ppc_defs[i].pvr_mask)) { *def = &ppc_defs[i]; @@ -5907,12 +5909,11 @@ int ppc_find_by_pvr (uint32_t pvr, ppc_def_t **def) void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) { - int i; + int i, max; - for (i = 0; ; i++) { + max = sizeof(ppc_defs) / sizeof(ppc_def_t); + for (i = 0; i < max; i++) { (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", ppc_defs[i].name, ppc_defs[i].pvr); - if (strcmp(ppc_defs[i].name, "default") == 0) - break; } } -- cgit v1.2.3 From 56ba31ff0bde6ccfe37f19e823381ec142bf0f80 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 15:15:18 +0000 Subject: Fix missing case in the new PowerPC exception model. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3294 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 3 +++ linux-user/main.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/darwin-user/main.c b/darwin-user/main.c index 45495ed45..d0de491e0 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -529,6 +529,9 @@ void cpu_loop(CPUPPCState *env) /* Return value */ env->gpr[3] = ret; break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; default: cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr); break; diff --git a/linux-user/main.c b/linux-user/main.c index 0b6fb977b..af99d0455 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1127,6 +1127,9 @@ void cpu_loop(CPUPPCState *env) printf("syscall returned 0x%08x (%d)\n", ret, ret); #endif break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; default: cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr); break; -- cgit v1.2.3 From 1e6784f96094a931b3aab0f3868d0e4107f65539 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 15:19:48 +0000 Subject: Fix PowerPC TLB miss dump code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3295 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4d629d41f..3e6fb48cd 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2302,13 +2302,13 @@ static always_inline void powerpc_excp (CPUState *env, const unsigned char *es; target_ulong *miss, *cmp; int en; - if (excp == 0x1000) { + if (excp == POWERPC_EXCP_IFTLB) { es = "I"; en = 'I'; miss = &env->spr[SPR_IMISS]; cmp = &env->spr[SPR_ICMP]; } else { - if (excp == 0x1100) + if (excp == POWERPC_EXCP_DLTLB) es = "DL"; else es = "DS"; -- cgit v1.2.3 From a902d8866440c8f57c8e3c546e97de286f627408 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 30 Sep 2007 15:21:15 +0000 Subject: Fix (once again) PowerPC sync weight field. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3296 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3f7b79927..6faf0b671 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2704,7 +2704,7 @@ GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B) #endif /* defined(TARGET_PPC64) */ /* sync */ -GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03BFF801, PPC_MEM_SYNC) +GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC) { } -- cgit v1.2.3 From ee0b03fd85652ddd04d3499f03e6821732862308 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 30 Sep 2007 16:37:00 +0000 Subject: Fix Sparc64 wrasr instructions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3297 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d12a356c6..0cffa9e52 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2043,9 +2043,11 @@ static void disas_sparc_insn(DisasContext * dc) break; #else case 0x2: /* V9 wrccr */ + gen_op_xor_T1_T0(); gen_op_wrccr(); break; case 0x3: /* V9 wrasi */ + gen_op_xor_T1_T0(); gen_op_movl_env_T0(offsetof(CPUSPARCState, asi)); break; case 0x6: /* V9 wrfprs */ @@ -2066,6 +2068,7 @@ static void disas_sparc_insn(DisasContext * dc) case 0x13: /* Graphics Status */ if (gen_trap_ifnofpu(dc)) goto jmp_insn; + gen_op_xor_T1_T0(); gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr)); break; case 0x17: /* Tick compare */ @@ -2073,6 +2076,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto illegal_insn; #endif + gen_op_xor_T1_T0(); gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); gen_op_wrtick_cmpr(); break; @@ -2081,6 +2085,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto illegal_insn; #endif + gen_op_xor_T1_T0(); gen_op_wrstick(); break; case 0x19: /* System tick compare */ @@ -2088,6 +2093,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto illegal_insn; #endif + gen_op_xor_T1_T0(); gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); gen_op_wrstick_cmpr(); break; -- cgit v1.2.3 From 3391c81801c867bc8f4dd6ce32766e4e8345813b Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 30 Sep 2007 19:38:12 +0000 Subject: Fix Sparc64 ldfa, lddfa, stfa, and stdfa instructions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3298 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 2 ++ target-sparc/op.c | 22 +++++++++++++++ target-sparc/op_helper.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ target-sparc/translate.c | 42 ++++++++++++++++++++++++---- 4 files changed, 133 insertions(+), 6 deletions(-) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 35f4b5fd1..063e2ee64 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -51,6 +51,8 @@ void cpu_loop_exit(void); void helper_flush(target_ulong addr); void helper_ld_asi(int asi, int size, int sign); void helper_st_asi(int asi, int size); +void helper_ldf_asi(int asi, int size, int rd); +void helper_stf_asi(int asi, int size, int rd); void helper_rett(void); void helper_ldfsr(void); void set_cwp(int new_cwp); diff --git a/target-sparc/op.c b/target-sparc/op.c index bb084ee0d..613bcb09a 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1865,6 +1865,28 @@ void OPPROTO op_st_asi_reg() helper_st_asi(env->asi, PARAM2); } +void OPPROTO op_ldf_asi_reg() +{ + T0 += PARAM1; + helper_ldf_asi(env->asi, PARAM2, PARAM3); +} + +void OPPROTO op_stf_asi_reg() +{ + T0 += PARAM1; + helper_stf_asi(env->asi, PARAM2, PARAM3); +} + +void OPPROTO op_ldf_asi() +{ + helper_ldf_asi(PARAM1, PARAM2, PARAM3); +} + +void OPPROTO op_stf_asi() +{ + helper_stf_asi(PARAM1, PARAM2, PARAM3); +} + void OPPROTO op_ldstub_asi_reg() /* XXX: should be atomically */ { target_ulong tmp; diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index eea4a6377..fa51cdee9 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1126,6 +1126,79 @@ void helper_st_asi(int asi, int size) } } #endif /* CONFIG_USER_ONLY */ + +void helper_ldf_asi(int asi, int size, int rd) +{ + target_ulong tmp_T0 = T0, tmp_T1 = T1; + unsigned int i; + + switch (asi) { + case 0xf0: // Block load primary + case 0xf1: // Block load secondary + case 0xf8: // Block load primary LE + case 0xf9: // Block load secondary LE + for (i = 0; i < 8; i++) { + helper_ld_asi(asi & 0x8f, 8, 0); + *((int64_t *)&DT0) = T1; + T0 += 8; + } + T0 = tmp_T0; + T1 = tmp_T1; + + return; + default: + break; + } + + helper_ld_asi(asi, size, 0); + switch(size) { + default: + case 4: + *((uint32_t *)&FT0) = T1; + break; + case 8: + *((int64_t *)&DT0) = T1; + break; + } + T1 = tmp_T1; +} + +void helper_stf_asi(int asi, int size, int rd) +{ + target_ulong tmp_T0 = T0, tmp_T1 = T1; + unsigned int i; + + switch (asi) { + case 0xf0: // Block store primary + case 0xf1: // Block store secondary + case 0xf8: // Block store primary LE + case 0xf9: // Block store secondary LE + for (i = 0; i < 8; i++) { + T1 = *((int64_t *)&DT0); + helper_st_asi(asi & 0x8f, 8); + T0 += 8; + } + T0 = tmp_T0; + T1 = tmp_T1; + + return; + default: + break; + } + + switch(size) { + default: + case 4: + T1 = *((uint32_t *)&FT0); + break; + case 8: + T1 = *((int64_t *)&DT0); + break; + } + helper_st_asi(asi, size); + T1 = tmp_T1; +} + #endif /* TARGET_SPARC64 */ #ifndef TARGET_SPARC64 diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 0cffa9e52..94503bee8 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -427,6 +427,34 @@ static inline void gen_st_asi(int insn, int size) } } +static inline void gen_ldf_asi(int insn, int size) +{ + int asi, offset, rd; + + rd = GET_FIELD(insn, 2, 6); + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_ldf_asi_reg(offset, size, rd); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_ldf_asi(asi, size, rd); + } +} + +static inline void gen_stf_asi(int insn, int size) +{ + int asi, offset, rd; + + rd = GET_FIELD(insn, 2, 6); + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_stf_asi_reg(offset, size, rd); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_stf_asi(asi, size, rd); + } +} + static inline void gen_swap_asi(int insn) { int asi, offset; @@ -3069,11 +3097,11 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_ld_asi(insn, 8, 0); // XXX + gen_ldf_asi(insn, 4); goto skip_move; case 0x33: /* V9 lddfa */ - gen_op_check_align_T0_7(); - gen_ld_asi(insn, 8, 0); // XXX + gen_op_check_align_T0_3(); + gen_ldf_asi(insn, 8); goto skip_move; case 0x3d: /* V9 prefetcha, no effect */ goto skip_move; @@ -3245,11 +3273,13 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_st_asi(insn, 0); // XXX + gen_op_load_fpr_FT0(rd); + gen_stf_asi(insn, 4); break; case 0x37: /* V9 stdfa */ - gen_op_check_align_T0_7(); - gen_st_asi(insn, 0); // XXX + gen_op_check_align_T0_3(); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_stf_asi(insn, 8); break; case 0x3c: /* V9 casa */ #ifdef CONFIG_USER_ONLY -- cgit v1.2.3 From 4e290a0b714650097f10f9bfb06ab1ef6173afc1 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 01:27:10 +0000 Subject: Share input pins and internal interrupt controller between all PowerPC 40x. Fix critical input interrupt generation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3299 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 27 +++++++++++++-------------- target-ppc/cpu.h | 26 +++++++++----------------- target-ppc/translate_init.c | 27 +++++++++++++++++++-------- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index bde3bfcd0..8e7912e3c 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -284,8 +284,8 @@ void ppc970_irq_init (CPUState *env) env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7); } -/* PowerPC 405 internal IRQ controller */ -static void ppc405_set_irq (void *opaque, int pin, int level) +/* PowerPC 40x internal IRQ controller */ +static void ppc40x_set_irq (void *opaque, int pin, int level) { CPUState *env = opaque; int cur_level; @@ -300,7 +300,7 @@ static void ppc405_set_irq (void *opaque, int pin, int level) /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { switch (pin) { - case PPC405_INPUT_RESET_SYS: + case PPC40x_INPUT_RESET_SYS: if (level) { #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { @@ -311,7 +311,7 @@ static void ppc405_set_irq (void *opaque, int pin, int level) ppc40x_system_reset(env); } break; - case PPC405_INPUT_RESET_CHIP: + case PPC40x_INPUT_RESET_CHIP: if (level) { #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { @@ -321,8 +321,7 @@ static void ppc405_set_irq (void *opaque, int pin, int level) ppc40x_chip_reset(env); } break; - /* No break here */ - case PPC405_INPUT_RESET_CORE: + case PPC40x_INPUT_RESET_CORE: /* XXX: TODO: update DBSR[MRR] */ if (level) { #if defined(PPC_DEBUG_IRQ) @@ -333,7 +332,7 @@ static void ppc405_set_irq (void *opaque, int pin, int level) ppc40x_core_reset(env); } break; - case PPC405_INPUT_CINT: + case PPC40x_INPUT_CINT: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { @@ -341,10 +340,9 @@ static void ppc405_set_irq (void *opaque, int pin, int level) __func__, level); } #endif - /* XXX: TOFIX */ - ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + ppc_set_irq(env, PPC_INTERRUPT_CEXT, level); break; - case PPC405_INPUT_INT: + case PPC40x_INPUT_INT: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { @@ -354,7 +352,7 @@ static void ppc405_set_irq (void *opaque, int pin, int level) #endif ppc_set_irq(env, PPC_INTERRUPT_EXT, level); break; - case PPC405_INPUT_HALT: + case PPC40x_INPUT_HALT: /* Level sensitive - active low */ if (level) { #if defined(PPC_DEBUG_IRQ) @@ -372,7 +370,7 @@ static void ppc405_set_irq (void *opaque, int pin, int level) env->halted = 0; } break; - case PPC405_INPUT_DEBUG: + case PPC40x_INPUT_DEBUG: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { @@ -398,9 +396,10 @@ static void ppc405_set_irq (void *opaque, int pin, int level) } } -void ppc405_irq_init (CPUState *env) +void ppc40x_irq_init (CPUState *env) { - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc405_set_irq, env, 7); + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, + env, PPC40x_INPUT_NB); } /*****************************************************************************/ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 53f4af3d2..5d0a86be2 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1117,23 +1117,15 @@ enum { }; enum { - /* PowerPC 401/403 input pins */ - PPC401_INPUT_RESET = 0, - PPC401_INPUT_CINT = 1, - PPC401_INPUT_INT = 2, - PPC401_INPUT_BERR = 3, - PPC401_INPUT_HALT = 4, -}; - -enum { - /* PowerPC 405 input pins */ - PPC405_INPUT_RESET_CORE = 0, - PPC405_INPUT_RESET_CHIP = 1, - PPC405_INPUT_RESET_SYS = 2, - PPC405_INPUT_CINT = 3, - PPC405_INPUT_INT = 4, - PPC405_INPUT_HALT = 5, - PPC405_INPUT_DEBUG = 6, + /* PowerPC 40x input pins */ + PPC40x_INPUT_RESET_CORE = 0, + PPC40x_INPUT_RESET_CHIP = 1, + PPC40x_INPUT_RESET_SYS = 2, + PPC40x_INPUT_CINT = 3, + PPC40x_INPUT_INT = 4, + PPC40x_INPUT_HALT = 5, + PPC40x_INPUT_DEBUG = 6, + PPC40x_INPUT_NB, }; enum { diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 13069c53e..2c33cd61c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -54,8 +54,7 @@ static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); #endif -PPC_IRQ_INIT_FN(401); -PPC_IRQ_INIT_FN(405); +PPC_IRQ_INIT_FN(40x); PPC_IRQ_INIT_FN(6xx); PPC_IRQ_INIT_FN(970); @@ -2482,7 +2481,8 @@ static void init_proc_401 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); init_excp_4xx_real(env); - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } /* PowerPC 401x2 */ @@ -2518,7 +2518,8 @@ static void init_proc_401x2 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_4xx_softmmu(env); - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } /* PowerPC 401x3 */ @@ -2536,7 +2537,14 @@ static void init_proc_401x2 (CPUPPCState *env) static void init_proc_401x3 (CPUPPCState *env) { + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_401(env); + gen_spr_401x2(env); + gen_spr_compress(env); init_excp_4xx_softmmu(env); + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } #endif /* TODO */ @@ -2573,7 +2581,8 @@ static void init_proc_IOP480 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_4xx_softmmu(env); - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } /* PowerPC 403 */ @@ -2594,7 +2603,8 @@ static void init_proc_403 (CPUPPCState *env) gen_spr_403(env); gen_spr_403_real(env); init_excp_4xx_real(env); - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } /* PowerPC 403 GCX */ @@ -2630,7 +2640,8 @@ static void init_proc_403GCX (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_4xx_softmmu(env); - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } /* PowerPC 405 */ @@ -2667,7 +2678,7 @@ static void init_proc_405 (CPUPPCState *env) env->id_tlbs = 0; init_excp_4xx_softmmu(env); /* Allocate hardware IRQ controller */ - ppc405_irq_init(env); + ppc40x_irq_init(env); } /* PowerPC 440 EP */ -- cgit v1.2.3 From 6f5d427d587bf8a39b3a93c0d515d0929578b923 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 01:32:49 +0000 Subject: Implement embedded PowerPC exceptions prefix and vectors registers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3300 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 15 +++++++++ target-ppc/translate_init.c | 80 +++++++++++++++++++++++++++++++-------------- 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 0694caf80..8f0f11a66 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1949,6 +1949,21 @@ void OPPROTO op_hrfid (void) RETURN(); } #endif + +/* Exception vectors */ +void OPPROTO op_store_excp_prefix (void) +{ + T0 &= env->ivpr_mask; + env->excp_prefix = T0; + RETURN(); +} + +void OPPROTO op_store_excp_vector (void) +{ + T0 &= env->ivor_mask; + env->excp_vectors[PARAM1] = T0; + RETURN(); +} #endif /* Trap word */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2c33cd61c..1e3bcadf3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -389,6 +389,32 @@ static void spr_write_pir (void *opaque, int sprn) } #endif +#if !defined(CONFIG_USER_ONLY) +/* Callback used to write the exception vector base */ +static void spr_write_excp_prefix (void *opaque, int sprn) +{ + gen_op_store_excp_prefix(); + gen_op_store_spr(sprn); +} + +static void spr_write_excp_vector (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) { + gen_op_store_excp_vector(sprn - SPR_BOOKE_IVOR0); + gen_op_store_spr(sprn); + } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) { + gen_op_store_excp_vector(sprn - SPR_BOOKE_IVOR32 + 32); + gen_op_store_spr(sprn); + } else { + printf("Trying to write an unknown exception vector %d %03x\n", + sprn, sprn); + GEN_EXCP_PRIVREG(ctx); + } +} +#endif + #if defined(CONFIG_USER_ONLY) #define spr_register(env, num, name, uea_read, uea_write, \ oea_read, oea_write, initial_value) \ @@ -1311,97 +1337,97 @@ static void gen_spr_BookE (CPUPPCState *env) 0x00000000); spr_register(env, SPR_BOOKE_IVPR, "IVPR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_prefix, 0x00000000); /* Exception vectors */ spr_register(env, SPR_BOOKE_IVOR0, "IVOR0", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR1, "IVOR1", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR2, "IVOR2", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR3, "IVOR3", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR4, "IVOR4", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR5, "IVOR5", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR6, "IVOR6", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR7, "IVOR7", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR8, "IVOR8", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR9, "IVOR9", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR10, "IVOR10", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR11, "IVOR11", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR12, "IVOR12", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR13, "IVOR13", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR14, "IVOR14", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR15, "IVOR15", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); #if 0 spr_register(env, SPR_BOOKE_IVOR32, "IVOR32", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR33, "IVOR33", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR34, "IVOR34", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR35, "IVOR35", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR36, "IVOR36", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); spr_register(env, SPR_BOOKE_IVOR37, "IVOR37", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_vector, 0x00000000); #endif spr_register(env, SPR_BOOKE_PID, "PID", @@ -1720,7 +1746,7 @@ static void gen_spr_40x (CPUPPCState *env) 0x00000000); spr_register(env, SPR_40x_EVPR, "EVPR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_excp_prefix, 0x00000000); spr_register(env, SPR_40x_SRR2, "SRR2", &spr_read_generic, &spr_write_generic, @@ -2147,6 +2173,9 @@ static void init_excp_4xx_real (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; + env->excp_prefix = 0x00000000; + env->ivor_mask = 0x0000FFF0; + env->ivpr_mask = 0xFFFF0000; #endif } @@ -2167,6 +2196,9 @@ static void init_excp_4xx_softmmu (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100; env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; + env->excp_prefix = 0x00000000; + env->ivor_mask = 0x0000FFF0; + env->ivpr_mask = 0xFFFF0000; #endif } -- cgit v1.2.3 From 035feb8857d410c3e066f13d8f7bcf8e836e6972 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 01:38:03 +0000 Subject: Share more SPR instanciations between all PowerPC 401 incarnations. Add comments about some unimplemented storage control dedicated SPRs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3301 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 52 ++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 1e3bcadf3..d9b9c686a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1720,12 +1720,12 @@ static void gen_spr_440 (CPUPPCState *env) static void gen_spr_40x (CPUPPCState *env) { /* Cache */ - /* XXX : not implemented */ + /* not emulated, as Qemu do not emulate caches */ spr_register(env, SPR_40x_DCCR, "DCCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + /* not emulated, as Qemu do not emulate caches */ spr_register(env, SPR_40x_ICCR, "ICCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1839,6 +1839,7 @@ static void gen_spr_405 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Storage control */ + /* XXX: TODO: not implemented */ spr_register(env, SPR_405_SLER, "SLER", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_40x_sler, @@ -1945,10 +1946,21 @@ static void gen_spr_401 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Storage control */ + /* XXX: TODO: not implemented */ spr_register(env, SPR_405_SLER, "SLER", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_40x_sler, 0x00000000); + /* not emulated, as Qemu never does speculative access */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* not emulated, as Qemu do not emulate caches */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } static void gen_spr_401x2 (CPUPPCState *env) @@ -2502,16 +2514,6 @@ static void init_proc_401 (CPUPPCState *env) gen_spr_40x(env); gen_spr_401_403(env); gen_spr_401(env); - /* Bus access control */ - spr_register(env, SPR_40x_SGR, "SGR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0xFFFFFFFF); - /* XXX : not implemented */ - spr_register(env, SPR_40x_DCWR, "DCWR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); init_excp_4xx_real(env); /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); @@ -2535,16 +2537,6 @@ static void init_proc_401x2 (CPUPPCState *env) gen_spr_401_403(env); gen_spr_401x2(env); gen_spr_compress(env); - /* Bus access control */ - spr_register(env, SPR_40x_SGR, "SGR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0xFFFFFFFF); - /* XXX : not implemented */ - spr_register(env, SPR_40x_DCWR, "DCWR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); /* Memory management */ env->nb_tlb = 64; env->nb_ways = 1; @@ -2598,16 +2590,6 @@ static void init_proc_IOP480 (CPUPPCState *env) gen_spr_401_403(env); gen_spr_401x2(env); gen_spr_compress(env); - /* Bus access control */ - spr_register(env, SPR_40x_SGR, "SGR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0xFFFFFFFF); - /* XXX : not implemented */ - spr_register(env, SPR_40x_DCWR, "DCWR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); /* Memory management */ env->nb_tlb = 64; env->nb_ways = 1; @@ -2658,11 +2640,12 @@ static void init_proc_403GCX (CPUPPCState *env) gen_spr_403_real(env); gen_spr_403_mmu(env); /* Bus access control */ + /* not emulated, as Qemu never does speculative access */ spr_register(env, SPR_40x_SGR, "SGR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0xFFFFFFFF); - /* XXX : not implemented */ + /* not emulated, as Qemu do not emulate caches */ spr_register(env, SPR_40x_DCWR, "DCWR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2695,11 +2678,12 @@ static void init_proc_405 (CPUPPCState *env) gen_spr_40x(env); gen_spr_405(env); /* Bus access control */ + /* not emulated, as Qemu never does speculative access */ spr_register(env, SPR_40x_SGR, "SGR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0xFFFFFFFF); - /* XXX : not implemented */ + /* not emulated, as Qemu do not emulate caches */ spr_register(env, SPR_40x_DCWR, "DCWR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, -- cgit v1.2.3 From daf4f96ece7dc4abdfe29c9a7fdd694ffd8969bb Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 01:51:12 +0000 Subject: Avoid op helpers that would just call helpers for TLB & SLB management: call the helpers directly from the micro-ops. Avoid duplicated code for tlbsx. implementation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3302 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 5 ++ target-ppc/exec.h | 6 --- target-ppc/helper.c | 118 ++++++++++++++++++++++++++++++---------- target-ppc/op.c | 35 ++++++------ target-ppc/op_helper.c | 143 ------------------------------------------------- target-ppc/translate.c | 10 ++-- 6 files changed, 119 insertions(+), 198 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 5d0a86be2..c4ae41441 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -656,6 +656,11 @@ void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void ppc_tlb_invalidate_all (CPUPPCState *env); +void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); +#if defined(TARGET_PPC64) +void ppc_slb_invalidate_all (CPUPPCState *env); +void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0); +#endif int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid); #endif #endif diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 10a51e93c..8a5425827 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -100,14 +100,8 @@ void do_raise_exception (uint32_t exception); int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr, int rw, int access_type, int check_BATs); -void ppc6xx_tlb_invalidate_all (CPUState *env); -void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - int is_code); void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1); -void ppc4xx_tlb_invalidate_all (CPUState *env); -void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - uint32_t pid); static inline void env_to_regs (void) { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 3e6fb48cd..66dc7b22a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -237,7 +237,7 @@ static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr, return nr; } -void ppc6xx_tlb_invalidate_all (CPUState *env) +static void ppc6xx_tlb_invalidate_all (CPUState *env) { ppc6xx_tlb_t *tlb; int nr, max; @@ -253,14 +253,9 @@ void ppc6xx_tlb_invalidate_all (CPUState *env) max *= 2; for (nr = 0; nr < max; nr++) { tlb = &env->tlb[nr].tlb6; -#if !defined(FLUSH_ALL_TLBS) - tlb_flush_page(env, tlb->EPN); -#endif pte_invalidate(&tlb->pte0); } -#if defined(FLUSH_ALL_TLBS) tlb_flush(env, 1); -#endif } static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, @@ -292,8 +287,8 @@ static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, #endif } -void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - int is_code) +static void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, + int is_code) { __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0); } @@ -834,11 +829,13 @@ static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, return -1; } mask = ~(tlb->size - 1); +#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " ADDRX " " ADDRX " %d\n", __func__, i, address, pid, tlb->EPN, mask, (int)tlb->PID); } +#endif /* Check PID */ if (tlb->PID != 0 && tlb->PID != pid) return -1; @@ -876,44 +873,41 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) return ret; } -void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - uint32_t pid) +/* Helpers specific to PowerPC 40x implementations */ +static void ppc4xx_tlb_invalidate_all (CPUState *env) { ppcemb_tlb_t *tlb; - target_phys_addr_t raddr; - target_ulong page, end; int i; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; - if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { - end = tlb->EPN + tlb->size; - for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) - tlb_flush_page(env, page); - tlb->prot &= ~PAGE_VALID; - break; - } + tlb->prot &= ~PAGE_VALID; } + tlb_flush(env, 1); } -/* Helpers specific to PowerPC 40x implementations */ -void ppc4xx_tlb_invalidate_all (CPUState *env) +static void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, + uint32_t pid) { +#if !defined(FLUSH_ALL_TLBS) ppcemb_tlb_t *tlb; + target_phys_addr_t raddr; + target_ulong page, end; int i; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; - if (tlb->prot & PAGE_VALID) { -#if 0 // XXX: TLB have variable sizes then we flush all Qemu TLB. + if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { end = tlb->EPN + tlb->size; for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); -#endif tlb->prot &= ~PAGE_VALID; + break; } } - tlb_flush(env, 1); +#else + ppc4xx_tlb_invalidate_all(env); +#endif } int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, @@ -932,10 +926,12 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, continue; zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3; +#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", __func__, i, zsel, zpr, rw, tlb->attr); } +#endif if (access_type == ACCESS_CODE) { /* Check execute enable bit */ switch (zpr) { @@ -1009,19 +1005,23 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } if (ret >= 0) { ctx->raddr = raddr; +#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: access granted " ADDRX " => " REGX " %d %d\n", __func__, address, ctx->raddr, ctx->prot, ret); } +#endif return 0; } } +#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: access refused " ADDRX " => " REGX " %d %d\n", __func__, address, raddr, ctx->prot, ret); } +#endif return ret; } @@ -1569,15 +1569,77 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) /* TLB management */ void ppc_tlb_invalidate_all (CPUPPCState *env) { - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: ppc6xx_tlb_invalidate_all(env); - } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { + break; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: ppc4xx_tlb_invalidate_all(env); - } else { + break; + default: tlb_flush(env, 1); + break; + } +} + +void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) +{ +#if !defined(FLUSH_ALL_TLBS) + addr &= TARGET_PAGE_MASK; + switch (env->mmu_model) { + case POWERPC_MMU_SOFT_6xx: + ppc6xx_tlb_invalidate_virt(env, addr, 0); + if (env->id_tlbs == 1) + ppc6xx_tlb_invalidate_virt(env, addr, 1); + break; + case POWERPC_MMU_SOFT_4xx: + case POWERPC_MMU_SOFT_4xx_Z: + ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]); + break; + default: + /* tlbie invalidate TLBs for all segments */ + addr &= ~((target_ulong)-1 << 28); + /* XXX: this case should be optimized, + * giving a mask to tlb_flush_page + */ + tlb_flush_page(env, addr | (0x0 << 28)); + tlb_flush_page(env, addr | (0x1 << 28)); + tlb_flush_page(env, addr | (0x2 << 28)); + tlb_flush_page(env, addr | (0x3 << 28)); + tlb_flush_page(env, addr | (0x4 << 28)); + tlb_flush_page(env, addr | (0x5 << 28)); + tlb_flush_page(env, addr | (0x6 << 28)); + tlb_flush_page(env, addr | (0x7 << 28)); + tlb_flush_page(env, addr | (0x8 << 28)); + tlb_flush_page(env, addr | (0x9 << 28)); + tlb_flush_page(env, addr | (0xA << 28)); + tlb_flush_page(env, addr | (0xB << 28)); + tlb_flush_page(env, addr | (0xC << 28)); + tlb_flush_page(env, addr | (0xD << 28)); + tlb_flush_page(env, addr | (0xE << 28)); + tlb_flush_page(env, addr | (0xF << 28)); } +#else + ppc_tlb_invalidate_all(env); +#endif } +#if defined(TARGET_PPC64) +void ppc_slb_invalidate_all (CPUPPCState *env) +{ + /* XXX: TODO */ + tlb_flush(env, 1); +} + +void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) +{ + /* XXX: TODO */ + tlb_flush(env, 1); +} +#endif + + /*****************************************************************************/ /* Special registers manipulation */ #if defined(TARGET_PPC64) diff --git a/target-ppc/op.c b/target-ppc/op.c index 8f0f11a66..6ad68eaba 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1985,21 +1985,21 @@ void OPPROTO op_td (void) /* tlbia */ void OPPROTO op_tlbia (void) { - do_tlbia(); + ppc_tlb_invalidate_all(env); RETURN(); } /* tlbie */ void OPPROTO op_tlbie (void) { - do_tlbie(); + ppc_tlb_invalidate_one(env, (uint32_t)T0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_tlbie_64 (void) { - do_tlbie_64(); + ppc_tlb_invalidate_one(env, T0); RETURN(); } #endif @@ -2007,13 +2007,19 @@ void OPPROTO op_tlbie_64 (void) #if defined(TARGET_PPC64) void OPPROTO op_slbia (void) { - do_slbia(); + ppc_slb_invalidate_all(env); RETURN(); } void OPPROTO op_slbie (void) { - do_slbie(); + ppc_slb_invalidate_one(env, (uint32_t)T0); + RETURN(); +} + +void OPPROTO op_slbie_64 (void) +{ + ppc_slb_invalidate_one(env, T0); RETURN(); } #endif @@ -2487,13 +2493,18 @@ void OPPROTO op_440_tlbre (void) void OPPROTO op_440_tlbsx (void) { - do_440_tlbsx(); + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF); RETURN(); } -void OPPROTO op_440_tlbsx_ (void) +void OPPROTO op_4xx_tlbsx_check (void) { - do_440_tlbsx_(); + int tmp; + + tmp = xer_so; + if (T0 != -1) + tmp |= 0x02; + env->crf[0] = tmp; RETURN(); } @@ -2517,13 +2528,7 @@ void OPPROTO op_4xx_tlbre_hi (void) void OPPROTO op_4xx_tlbsx (void) { - do_4xx_tlbsx(); - RETURN(); -} - -void OPPROTO op_4xx_tlbsx_ (void) -{ - do_4xx_tlbsx_(); + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5223b1543..a7c81776f 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -36,7 +36,6 @@ //#define DEBUG_OP //#define DEBUG_EXCEPTIONS //#define DEBUG_SOFTWARE_TLB -//#define FLUSH_ALL_TLBS /*****************************************************************************/ /* Exceptions processing helpers */ @@ -2336,118 +2335,6 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) env = saved_env; } -/* TLB invalidation helpers */ -void do_tlbia (void) -{ - ppc_tlb_invalidate_all(env); -} - -void do_tlbie (void) -{ - T0 = (uint32_t)T0; -#if !defined(FLUSH_ALL_TLBS) - /* XXX: Remove thoses tests */ - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { - ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); - if (env->id_tlbs == 1) - ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1); - } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { - ppc4xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, - env->spr[SPR_40x_PID]); - } else { - /* tlbie invalidate TLBs for all segments */ - T0 &= TARGET_PAGE_MASK; - T0 &= ~((target_ulong)-1 << 28); - /* XXX: this case should be optimized, - * giving a mask to tlb_flush_page - */ - tlb_flush_page(env, T0 | (0x0 << 28)); - tlb_flush_page(env, T0 | (0x1 << 28)); - tlb_flush_page(env, T0 | (0x2 << 28)); - tlb_flush_page(env, T0 | (0x3 << 28)); - tlb_flush_page(env, T0 | (0x4 << 28)); - tlb_flush_page(env, T0 | (0x5 << 28)); - tlb_flush_page(env, T0 | (0x6 << 28)); - tlb_flush_page(env, T0 | (0x7 << 28)); - tlb_flush_page(env, T0 | (0x8 << 28)); - tlb_flush_page(env, T0 | (0x9 << 28)); - tlb_flush_page(env, T0 | (0xA << 28)); - tlb_flush_page(env, T0 | (0xB << 28)); - tlb_flush_page(env, T0 | (0xC << 28)); - tlb_flush_page(env, T0 | (0xD << 28)); - tlb_flush_page(env, T0 | (0xE << 28)); - tlb_flush_page(env, T0 | (0xF << 28)); - } -#else - do_tlbia(); -#endif -} - -#if defined(TARGET_PPC64) -void do_tlbie_64 (void) -{ - T0 = (uint64_t)T0; -#if !defined(FLUSH_ALL_TLBS) - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { - ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0); - if (env->id_tlbs == 1) - ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1); - } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) { - /* XXX: TODO */ -#if 0 - ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, - env->spr[SPR_BOOKE_PID]); -#endif - } else { - /* tlbie invalidate TLBs for all segments - * As we have 2^36 segments, invalidate all qemu TLBs - */ -#if 0 - T0 &= TARGET_PAGE_MASK; - T0 &= ~((target_ulong)-1 << 28); - /* XXX: this case should be optimized, - * giving a mask to tlb_flush_page - */ - tlb_flush_page(env, T0 | (0x0 << 28)); - tlb_flush_page(env, T0 | (0x1 << 28)); - tlb_flush_page(env, T0 | (0x2 << 28)); - tlb_flush_page(env, T0 | (0x3 << 28)); - tlb_flush_page(env, T0 | (0x4 << 28)); - tlb_flush_page(env, T0 | (0x5 << 28)); - tlb_flush_page(env, T0 | (0x6 << 28)); - tlb_flush_page(env, T0 | (0x7 << 28)); - tlb_flush_page(env, T0 | (0x8 << 28)); - tlb_flush_page(env, T0 | (0x9 << 28)); - tlb_flush_page(env, T0 | (0xA << 28)); - tlb_flush_page(env, T0 | (0xB << 28)); - tlb_flush_page(env, T0 | (0xC << 28)); - tlb_flush_page(env, T0 | (0xD << 28)); - tlb_flush_page(env, T0 | (0xE << 28)); - tlb_flush_page(env, T0 | (0xF << 28)); -#else - tlb_flush(env, 1); -#endif - } -#else - do_tlbia(); -#endif -} -#endif - -#if defined(TARGET_PPC64) -void do_slbia (void) -{ - /* XXX: TODO */ - tlb_flush(env, 1); -} - -void do_slbie (void) -{ - /* XXX: TODO */ - tlb_flush(env, 1); -} -#endif - /* Software driven TLBs management */ /* PowerPC 602/603 software TLB load instructions helpers */ void do_load_6xx_tlb (int is_code) @@ -2575,21 +2462,6 @@ void do_4xx_tlbre_hi (void) T0 |= 0x100; } -void do_4xx_tlbsx (void) -{ - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); -} - -void do_4xx_tlbsx_ (void) -{ - int tmp = xer_so; - - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]); - if (T0 != -1) - tmp |= 0x02; - env->crf[0] = tmp; -} - void do_4xx_tlbwe_hi (void) { ppcemb_tlb_t *tlb; @@ -2757,21 +2629,6 @@ void do_440_tlbwe (int word) } } -void do_440_tlbsx (void) -{ - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF); -} - -void do_440_tlbsx_ (void) -{ - int tmp = xer_so; - - T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF); - if (T0 != -1) - tmp |= 0x02; - env->crf[0] = tmp; -} - void do_440_tlbre (int word) { ppcemb_tlb_t *tlb; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6faf0b671..d76a92a65 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4991,10 +4991,9 @@ GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB) return; } gen_addr_reg_index(ctx); + gen_op_4xx_tlbsx(); if (Rc(ctx->opcode)) - gen_op_4xx_tlbsx_(); - else - gen_op_4xx_tlbsx(); + gen_op_4xx_tlbsx_check(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } @@ -5064,10 +5063,9 @@ GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) return; } gen_addr_reg_index(ctx); + gen_op_440_tlbsx(); if (Rc(ctx->opcode)) - gen_op_440_tlbsx_(); - else - gen_op_440_tlbsx(); + gen_op_4xx_tlbsx_check(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } -- cgit v1.2.3 From 5356c7b5a641c128f0c21bcbae2191068b41d179 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 01:59:12 +0000 Subject: Remove definitions for deprecated SLB & TLB related op helpers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3303 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index c7235cc3e..6f79cad91 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -134,16 +134,7 @@ void do_rfid (void); #if defined(TARGET_PPC64H) void do_hrfid (void); #endif -void do_tlbia (void); -void do_tlbie (void); -#if defined(TARGET_PPC64) -void do_tlbie_64 (void); -#endif void do_load_6xx_tlb (int is_code); -#if defined(TARGET_PPC64) -void do_slbia (void); -void do_slbie (void); -#endif #endif /* POWER / PowerPC 601 specific helpers */ @@ -170,8 +161,6 @@ void do_op_602_mfrom (void); /* PowerPC 440 specific helpers */ #if !defined(CONFIG_USER_ONLY) void do_440_tlbre (int word); -void do_440_tlbsx (void); -void do_440_tlbsx_ (void); void do_440_tlbwe (int word); #endif @@ -187,8 +176,6 @@ void do_rfdi (void); void do_rfmci (void); void do_4xx_tlbre_lo (void); void do_4xx_tlbre_hi (void); -void do_4xx_tlbsx (void); -void do_4xx_tlbsx_ (void); void do_4xx_tlbwe_lo (void); void do_4xx_tlbwe_hi (void); #endif -- cgit v1.2.3 From b48d7d697f2688a0e8e161c74c612ed4afb77a43 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 02:55:07 +0000 Subject: Compilation fix (forgotten patch). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3304 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405_uc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index aa5963aee..b6fc491ae 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -3051,9 +3051,9 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4], /* Universal interrupt controller */ irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); irqs[PPCUIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_INT]; + ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; irqs[PPCUIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_CINT]; + ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); *picp = pic; /* SDRAM controller */ @@ -3404,9 +3404,9 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2], /* Universal interrupt controller */ irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); irqs[PPCUIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_INT]; + ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; irqs[PPCUIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_CINT]; + ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); *picp = pic; /* SDRAM controller */ -- cgit v1.2.3 From 056b05f8d22d0fdd46bbf1fdf01e5f3a32242a16 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 03:03:51 +0000 Subject: Optimisations: avoid generation of duplicated micro-ops. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3305 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d76a92a65..e599243b7 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2996,6 +2996,7 @@ static inline void gen_bcond (DisasContext *ctx, int type) case 6: if (type == BCOND_IM) { gen_goto_tb(ctx, 0, target); + goto out; } else { #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -3004,8 +3005,9 @@ static inline void gen_bcond (DisasContext *ctx, int type) #endif gen_op_b_T1(); gen_op_reset_T0(); + goto no_test; } - goto no_test; + break; } } else { mask = 1 << (3 - (bi & 0x03)); @@ -3079,6 +3081,7 @@ static inline void gen_bcond (DisasContext *ctx, int type) gen_op_debug(); gen_op_exit_tb(); } + out: ctx->exception = POWERPC_EXCP_BRANCH; } @@ -3381,11 +3384,15 @@ GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B) /* Special form that does not need any synchronisation */ gen_op_update_riee(); } else { + /* XXX: we need to update nip before the store + * if we enter power saving mode, we will exit the loop + * directly from ppc_store_msr + */ gen_update_nip(ctx, ctx->nip); gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ - GEN_STOP(ctx); + ctx->exception = POWERPC_EXCP_STOP; } #endif } @@ -3405,6 +3412,10 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) /* Special form that does not need any synchronisation */ gen_op_update_riee(); } else { + /* XXX: we need to update nip before the store + * if we enter power saving mode, we will exit the loop + * directly from ppc_store_msr + */ gen_update_nip(ctx, ctx->nip); #if defined(TARGET_PPC64) if (!ctx->sf_mode) @@ -3414,7 +3425,7 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) gen_op_store_msr(); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsrd is not always defined as context-synchronizing */ - GEN_STOP(ctx); + ctx->exception = POWERPC_EXCP_STOP; } #endif } -- cgit v1.2.3 From 578bb25230229307c0b6ff62ae03ac0fbda27b18 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 04:48:45 +0000 Subject: More comments about unimplemented SPRs. Tag unused functions with unused attribute instead of using #ifdef (TODO) to ease tests: just have to enable the implementation in the cpu_defs table. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3306 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 166 +++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 56 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d9b9c686a..88d67d9cf 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -275,17 +275,16 @@ static void spr_write_sdr1 (void *opaque, int sprn) /* 64 bits PowerPC specific SPRs */ /* ASR */ -/* Currently unused */ -#if 0 && defined(TARGET_PPC64) +#if defined(TARGET_PPC64) +__attribute__ (( unused )) static void spr_read_asr (void *opaque, int sprn) { gen_op_load_asr(); } +__attribute__ (( unused )) static void spr_write_asr (void *opaque, int sprn) { - DisasContext *ctx = opaque; - gen_op_store_asr(); } #endif @@ -816,30 +815,37 @@ static void gen_spr_7xx (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UMMCR0, "UMMCR0", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UMMCR1, "UMMCR1", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC1, "UPMC1", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC2, "UPMC2", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC3, "UPMC3", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC4, "UPMC4", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_USIAR, "USIAR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -956,12 +962,14 @@ static void gen_spr_G2 (CPUPPCState *env) { /* Memory base address */ /* MBAR */ + /* XXX : not implemented */ spr_register(env, SPR_MBAR, "MBAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* System version register */ /* SVR */ + /* XXX : TODO: initialize it to an appropriate value */ spr_register(env, SPR_SVR, "SVR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, @@ -1143,6 +1151,7 @@ static void gen_spr_74xx (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UMMCR2, "UMMCR2", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -1152,10 +1161,12 @@ static void gen_spr_74xx (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_MSSCR0, "MSSCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1178,7 +1189,6 @@ static void gen_spr_74xx (CPUPPCState *env) 0x00000000); } -#if defined (TODO) static void gen_l3_ctrl (CPUPPCState *env) { /* L3CR */ @@ -1188,56 +1198,64 @@ static void gen_l3_ctrl (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR0 */ + /* XXX : not implemented */ spr_register(env, SPR_L3ITCR0, "L3ITCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR1 */ + /* XXX : not implemented */ spr_register(env, SPR_L3ITCR1, "L3ITCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR2 */ + /* XXX : not implemented */ spr_register(env, SPR_L3ITCR2, "L3ITCR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3ITCR3 */ + /* XXX : not implemented */ spr_register(env, SPR_L3ITCR3, "L3ITCR3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3OHCR */ + /* XXX : not implemented */ spr_register(env, SPR_L3OHCR, "L3OHCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* L3PM */ + /* XXX : not implemented */ spr_register(env, SPR_L3PM, "L3PM", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); } -#endif /* TODO */ -#if defined (TODO) -static void gen_74xx_soft_tlb (CPUPPCState *env) +static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) { - /* XXX: TODO */ + env->nb_tlb = nb_tlbs; + env->nb_ways = nb_ways; + env->id_tlbs = 1; + /* XXX : not implemented */ spr_register(env, SPR_PTEHI, "PTEHI", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_PTELO, "PTELO", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_TLBMISS, "TLBMISS", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); } -#endif /* TODO */ /* PowerPC BookE SPR */ static void gen_spr_BookE (CPUPPCState *env) @@ -1491,78 +1509,92 @@ static void gen_spr_BookE (CPUPPCState *env) } /* FSL storage control registers */ -#if defined(TODO) static void gen_spr_BookE_FSL (CPUPPCState *env) { /* TLB assist registers */ + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MAS0, "MAS0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MAS1, "MAS2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MAS2, "MAS3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MAS3, "MAS4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MAS4, "MAS5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MAS6, "MAS6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MAS7, "MAS7", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); if (env->nb_pids > 1) { + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_PID1, "PID1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); } if (env->nb_pids > 2) { + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_PID2, "PID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); } + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MMUCFG, "MMUCFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* TOFIX */ + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MMUCSR0, "MMUCSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* TOFIX */ switch (env->nb_ways) { case 4: + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* TOFIX */ /* Fallthru */ case 3: + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* TOFIX */ /* Fallthru */ case 2: + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* TOFIX */ /* Fallthru */ case 1: + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, @@ -1573,7 +1605,6 @@ static void gen_spr_BookE_FSL (CPUPPCState *env) break; } } -#endif /* SPR specific to PowerPC 440 implementation */ static void gen_spr_440 (CPUPPCState *env) @@ -1730,7 +1761,7 @@ static void gen_spr_40x (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ + /* not emulated, as Qemu do not emulate caches */ spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, @@ -1913,7 +1944,7 @@ static void gen_spr_401_403 (CPUPPCState *env) SPR_NOACCESS, &spr_write_tbu, 0x00000000); /* Debug */ - /* XXX: not implemented */ + /* not emulated, as Qemu do not emulate caches */ spr_register(env, SPR_403_CDBCR, "CDBCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1996,6 +2027,7 @@ static void gen_spr_403 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_40x_DAC2, "DAC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2005,6 +2037,7 @@ static void gen_spr_403 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_40x_IAC2, "IAC2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2047,6 +2080,7 @@ static void gen_spr_403_mmu (CPUPPCState *env) /* SPR specific to PowerPC compression coprocessor extension */ static void gen_spr_compress (CPUPPCState *env) { + /* XXX : not implemented */ spr_register(env, SPR_401_SKR, "SKR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2054,84 +2088,100 @@ static void gen_spr_compress (CPUPPCState *env) } #if defined (TARGET_PPC64) -#if defined (TODO) /* SPR specific to PowerPC 620 */ static void gen_spr_620 (CPUPPCState *env) { + /* XXX : not implemented */ spr_register(env, SPR_620_PMR0, "PMR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR1, "PMR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR2, "PMR2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR3, "PMR3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR4, "PMR4", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR5, "PMR5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR6, "PMR6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR7, "PMR7", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR8, "PMR8", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMR9, "PMR9", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMRA, "PMR10", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMRB, "PMR11", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMRC, "PMR12", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMRD, "PMR13", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMRE, "PMR14", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_PMRF, "PMR15", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_HID8, "HID8", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_620_HID9, "HID9", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); } -#endif #endif /* defined (TARGET_PPC64) */ // XXX: TODO @@ -2141,7 +2191,6 @@ static void gen_spr_620 (CPUPPCState *env) * CTRL => SPR 152 (Power 2.04) * SCOMC => SPR 276 (64 bits ?) * SCOMD => SPR 277 (64 bits ?) - * ASR => SPR 280 (64 bits) * TBU40 => SPR 286 (Power 2.04 hypv) * HSPRG0 => SPR 304 (Power 2.04 hypv) * HSPRG1 => SPR 305 (Power 2.04 hypv) @@ -2157,8 +2206,6 @@ static void gen_spr_620 (CPUPPCState *env) * LPCR => SPR 316 (970) * LPIDR => SPR 317 (970) * SPEFSCR => SPR 512 (Power 2.04 emb) - * ATBL => SPR 526 (Power 2.04 emb) - * ATBU => SPR 527 (Power 2.04 emb) * EPR => SPR 702 (Power 2.04 emb) * perf => 768-783 (Power 2.04) * perf => 784-799 (Power 2.04) @@ -2349,7 +2396,7 @@ static void init_excp_604 (CPUPPCState *env) #endif } -#if defined (TODO) +#if defined(TARGET_PPC64) static void init_excp_620 (CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) @@ -2370,7 +2417,7 @@ static void init_excp_620 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; #endif } -#endif /* defined (TODO) */ +#endif /* defined(TARGET_PPC64) */ static void init_excp_7x0 (CPUPPCState *env) { @@ -2436,7 +2483,6 @@ static void init_excp_7400 (CPUPPCState *env) #endif } -#if defined (TODO) static void init_excp_7450 (CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) @@ -2461,7 +2507,6 @@ static void init_excp_7450 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; #endif } -#endif /* defined (TODO) */ #if defined (TARGET_PPC64) static void init_excp_970 (CPUPPCState *env) @@ -2547,7 +2592,6 @@ static void init_proc_401x2 (CPUPPCState *env) } /* PowerPC 401x3 */ -#if defined(TODO) #define POWERPC_INSNS_401x3 (POWERPC_INSNS_EMB | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ @@ -2559,6 +2603,7 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) +__attribute__ (( unused )) static void init_proc_401x3 (CPUPPCState *env) { gen_spr_40x(env); @@ -2570,7 +2615,6 @@ static void init_proc_401x3 (CPUPPCState *env) /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); } -#endif /* TODO */ /* IOP480 */ #define POWERPC_INSNS_IOP480 (POWERPC_INSNS_EMB | \ @@ -2714,6 +2758,7 @@ static void init_proc_440EP (CPUPPCState *env) gen_tbl(env); gen_spr_BookE(env); gen_spr_440(env); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MCSR, "MCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2726,6 +2771,7 @@ static void init_proc_440EP (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_440_CCR1, "CCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2764,7 +2810,6 @@ static void init_proc_440GP (CPUPPCState *env) } /* PowerPC 440x4 */ -#if defined(TODO) #define POWERPC_INSNS_440x4 (POWERPC_INSNS_EMB | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ @@ -2775,6 +2820,7 @@ static void init_proc_440GP (CPUPPCState *env) #define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) +__attribute__ (( unused )) static void init_proc_440x4 (CPUPPCState *env) { /* Time base */ @@ -2788,7 +2834,6 @@ static void init_proc_440x4 (CPUPPCState *env) init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } -#endif /* TODO */ /* PowerPC 440x5 */ #define POWERPC_INSNS_440x5 (POWERPC_INSNS_EMB | \ @@ -2807,6 +2852,7 @@ static void init_proc_440x5 (CPUPPCState *env) gen_tbl(env); gen_spr_BookE(env); gen_spr_440(env); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MCSR, "MCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2819,6 +2865,7 @@ static void init_proc_440x5 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_440_CCR1, "CCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2832,8 +2879,7 @@ static void init_proc_440x5 (CPUPPCState *env) } /* PowerPC 460 (guessed) */ -#if defined(TODO) -#define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_460 (POWERPC_INSNS_EMB | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON | \ PPC_405_MAC | PPC_440_SPEC | PPC_DCRUX) @@ -2843,12 +2889,14 @@ static void init_proc_440x5 (CPUPPCState *env) #define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460 (bfd_mach_ppc_403) +__attribute__ (( unused )) static void init_proc_460 (CPUPPCState *env) { /* Time base */ gen_tbl(env); gen_spr_BookE(env); gen_spr_440(env); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MCSR, "MCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2861,10 +2909,12 @@ static void init_proc_460 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_440_CCR1, "CCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_DCRIPR, "SPR_DCRIPR", &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic, @@ -2876,10 +2926,8 @@ static void init_proc_460 (CPUPPCState *env) init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } -#endif /* TODO */ /* PowerPC 460F (guessed) */ -#if defined(TODO) #define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ PPC_FLOAT | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES | \ @@ -2893,12 +2941,14 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460F (bfd_mach_ppc_403) +__attribute__ (( unused )) static void init_proc_460F (CPUPPCState *env) { /* Time base */ gen_tbl(env); gen_spr_BookE(env); gen_spr_440(env); + /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MCSR, "MCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -2911,10 +2961,12 @@ static void init_proc_460F (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_440_CCR1, "CCR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_DCRIPR, "SPR_DCRIPR", &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic, @@ -2926,10 +2978,8 @@ static void init_proc_460F (CPUPPCState *env) init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } -#endif /* TODO */ /* Generic BookE PowerPC */ -#if defined(TODO) #define POWERPC_INSNS_BookE (POWERPC_INSNS_EMB | \ PPC_MEM_EIEIO | PPC_MEM_TLBSYNC | \ PPC_CACHE_DCBA | \ @@ -2943,22 +2993,17 @@ static void init_proc_460F (CPUPPCState *env) #define POWERPC_INPUT_BookE (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_BookE (bfd_mach_ppc_403) +__attribute__ (( unused )) static void init_proc_BookE (CPUPPCState *env) { init_excp_BookE(env); } -#endif /* TODO */ /* e200 core */ -#if defined(TODO) -#endif /* TODO */ /* e300 core */ -#if defined(TODO) -#endif /* TODO */ /* e500 core */ -#if defined(TODO) #define POWERPC_INSNS_e500 (POWERPC_INSNS_EMB | \ PPC_MEM_EIEIO | PPC_MEM_TLBSYNC | \ PPC_CACHE_DCBA | \ @@ -2968,6 +3013,7 @@ static void init_proc_BookE (CPUPPCState *env) #define POWERPC_INPUT_e500 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_e500 (bfd_mach_ppc_403) +__attribute__ (( unused )) static void init_proc_e500 (CPUPPCState *env) { /* Time base */ @@ -2981,11 +3027,8 @@ static void init_proc_e500 (CPUPPCState *env) init_excp_BookE(env); /* XXX: TODO: allocate internal IRQ controller */ } -#endif /* TODO */ /* e600 core */ -#if defined(TODO) -#endif /* TODO */ /* Non-embedded PowerPC */ /* Base instructions set for all 6xx/7xx/74xx/970 PowerPC */ @@ -3461,7 +3504,6 @@ static void init_proc_7410 (CPUPPCState *env) } /* PowerPC 7440 (aka G4) */ -#if defined (TODO) #define POWERPC_INSNS_7440 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ PPC_ALTIVEC) @@ -3471,6 +3513,7 @@ static void init_proc_7410 (CPUPPCState *env) #define POWERPC_INPUT_7440 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7440 (bfd_mach_ppc_7400) +__attribute__ (( unused )) static void init_proc_7440 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -3492,6 +3535,7 @@ static void init_proc_7440 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ + /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -3502,28 +3546,29 @@ static void init_proc_7440 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Memory management */ gen_low_BATs(env); - gen_74xx_soft_tlb(env); + gen_74xx_soft_tlb(env, 128, 2); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } -#endif /* TODO */ /* PowerPC 7450 (aka G4) */ -#if defined (TODO) #define POWERPC_INSNS_7450 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ PPC_ALTIVEC) @@ -3533,6 +3578,7 @@ static void init_proc_7440 (CPUPPCState *env) #define POWERPC_INPUT_7450 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7450 (bfd_mach_ppc_7400) +__attribute__ (( unused )) static void init_proc_7450 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -3556,6 +3602,7 @@ static void init_proc_7450 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ + /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -3566,29 +3613,30 @@ static void init_proc_7450 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); /* Memory management */ gen_low_BATs(env); - gen_74xx_soft_tlb(env); + gen_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } -#endif /* TODO */ /* PowerPC 7445 (aka G4) */ -#if defined (TODO) #define POWERPC_INSNS_7445 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ PPC_ALTIVEC) @@ -3598,6 +3646,7 @@ static void init_proc_7450 (CPUPPCState *env) #define POWERPC_INPUT_7445 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7445 (bfd_mach_ppc_7400) +__attribute__ (( unused )) static void init_proc_7445 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -3619,6 +3668,7 @@ static void init_proc_7445 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ + /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -3629,14 +3679,17 @@ static void init_proc_7445 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -3677,15 +3730,13 @@ static void init_proc_7445 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_high_BATs(env); - gen_74xx_soft_tlb(env); + gen_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } -#endif /* TODO */ /* PowerPC 7455 (aka G4) */ -#if defined (TODO) #define POWERPC_INSNS_7455 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ PPC_ALTIVEC) @@ -3695,6 +3746,7 @@ static void init_proc_7445 (CPUPPCState *env) #define POWERPC_INPUT_7455 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7455 (bfd_mach_ppc_7400) +__attribute__ (( unused )) static void init_proc_7455 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -3718,6 +3770,7 @@ static void init_proc_7455 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* MSSSR0 */ + /* XXX : not implemented */ spr_register(env, SPR_MSSSR0, "MSSSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -3728,14 +3781,17 @@ static void init_proc_7455 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC5, "UPMC5", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_PMC6, "PMC6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_UPMC6, "UPMC6", &spr_read_ureg, SPR_NOACCESS, &spr_read_ureg, SPR_NOACCESS, @@ -3776,12 +3832,11 @@ static void init_proc_7455 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_high_BATs(env); - gen_74xx_soft_tlb(env); + gen_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } -#endif /* TODO */ #if defined (TARGET_PPC64) /* PowerPC 970 */ @@ -3914,7 +3969,6 @@ static void init_proc_970GX (CPUPPCState *env) } /* PowerPC 620 */ -#if defined (TODO) #define POWERPC_INSNS_620 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_SLBI) #define POWERPC_MSRM_620 (0x800000000005FF73ULL) @@ -3923,6 +3977,7 @@ static void init_proc_970GX (CPUPPCState *env) #define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_620 (bfd_mach_ppc64) +__attribute__ (( unused )) static void init_proc_620 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -3941,7 +3996,6 @@ static void init_proc_620 (CPUPPCState *env) init_excp_620(env); /* XXX: TODO: initialize internal interrupt controller */ } -#endif /* TODO */ #endif /* defined (TARGET_PPC64) */ /* Default 32 bits PowerPC target will be 604 */ -- cgit v1.2.3 From 7dbe11acd807b7a1566b2fe665333a49f8358de0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 05:16:57 +0000 Subject: Handle all MMU models in switches, even if it's just to abort because of lack of supporting code. Implement 74xx software TLB model. Keep 74xx with software TLB disabled, as Linux is not able to handle TLB miss on those processors. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3307 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 107 +++++++++++++++++++++++++++++++++++++++++++++---- target-ppc/op.c | 15 ++++++- target-ppc/op_helper.c | 21 ++++++++++ target-ppc/op_helper.h | 1 + target-ppc/translate.c | 35 +++++++++++++++- 5 files changed, 169 insertions(+), 10 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 66dc7b22a..5b0fd09b9 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -664,7 +664,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, int ret, ret2; #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) { + if (env->mmu_model == POWERPC_MMU_64B || + env->mmu_model == POWERPC_MMU_64BRIDGE) { ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); if (ret < 0) return ret; @@ -730,7 +731,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } /* Initialize real address with an invalid value */ ctx->raddr = (target_ulong)-1; - if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) { + if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx || + env->mmu_model == POWERPC_MMU_SOFT_74xx)) { /* Software TLB search */ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type); } else { @@ -1092,9 +1094,11 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, switch (env->mmu_model) { case POWERPC_MMU_32B: case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: case POWERPC_MMU_601: case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_REAL_4xx: + case POWERPC_MMU_BOOKE: ctx->prot |= PAGE_WRITE; break; #if defined(TARGET_PPC64) @@ -1129,9 +1133,6 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, } } break; - case POWERPC_MMU_BOOKE: - ctx->prot |= PAGE_WRITE; - break; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ cpu_abort(env, "BookE FSL MMU model not implemented\n"); @@ -1162,6 +1163,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, switch (env->mmu_model) { case POWERPC_MMU_32B: case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: /* Try to find a BAT */ if (check_BATs) ret = get_bat(env, ctx, eaddr, rw, access_type); @@ -1262,6 +1264,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; error_code = 1 << 18; goto tlb_miss; + case POWERPC_MMU_SOFT_74xx: + exception = POWERPC_EXCP_IFTLB; + goto tlb_miss_74xx; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: exception = POWERPC_EXCP_ITLB; @@ -1346,6 +1351,19 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_HASH2] = ctx.pg_addr[1]; /* Do not alter DAR nor DSISR */ goto out; + case POWERPC_MMU_SOFT_74xx: + if (rw == 1) { + exception = POWERPC_EXCP_DSTLB; + } else { + exception = POWERPC_EXCP_DLTLB; + } + tlb_miss_74xx: + /* Implement LRU algorithm */ + env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) | + ((env->last_way + 1) & (env->nb_ways - 1)); + env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem; + error_code = ctx.key << 19; + break; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: exception = POWERPC_EXCP_DTLB; @@ -1571,13 +1589,31 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) { switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: ppc6xx_tlb_invalidate_all(env); break; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: ppc4xx_tlb_invalidate_all(env); break; - default: + case POWERPC_MMU_REAL_4xx: + cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n"); + break; + case POWERPC_MMU_BOOKE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + break; + case POWERPC_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + break; + case POWERPC_MMU_601: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + break; + case POWERPC_MMU_32B: + case POWERPC_MMU_64B: + case POWERPC_MMU_64BRIDGE: tlb_flush(env, 1); break; } @@ -1589,6 +1625,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) addr &= TARGET_PAGE_MASK; switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: + case POWERPC_MMU_SOFT_74xx: ppc6xx_tlb_invalidate_virt(env, addr, 0); if (env->id_tlbs == 1) ppc6xx_tlb_invalidate_virt(env, addr, 1); @@ -1597,7 +1634,22 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) case POWERPC_MMU_SOFT_4xx_Z: ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]); break; - default: + case POWERPC_MMU_REAL_4xx: + cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n"); + break; + case POWERPC_MMU_BOOKE: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + break; + case POWERPC_MMU_BOOKE_FSL: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + break; + case POWERPC_MMU_601: + /* XXX: TODO */ + cpu_abort(env, "MMU model not implemented\n"); + break; + case POWERPC_MMU_32B: /* tlbie invalidate TLBs for all segments */ addr &= ~((target_ulong)-1 << 28); /* XXX: this case should be optimized, @@ -1619,6 +1671,15 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) tlb_flush_page(env, addr | (0xD << 28)); tlb_flush_page(env, addr | (0xE << 28)); tlb_flush_page(env, addr | (0xF << 28)); + break; + case POWERPC_MMU_64B: + case POWERPC_MMU_64BRIDGE: + /* tlbie invalidate TLBs for all segments */ + /* XXX: given the fact that there are too many segments to invalidate, + * we just invalidate all TLBs + */ + tlb_flush(env, 1); + break; } #else ppc_tlb_invalidate_all(env); @@ -2317,6 +2378,8 @@ static always_inline void powerpc_excp (CPUState *env, goto tlb_miss_tgpr; case POWERPC_EXCP_7x5: goto tlb_miss; + case POWERPC_EXCP_74xx: + goto tlb_miss_74xx; default: cpu_abort(env, "Invalid instruction TLB miss exception\n"); break; @@ -2336,6 +2399,8 @@ static always_inline void powerpc_excp (CPUState *env, goto tlb_miss_tgpr; case POWERPC_EXCP_7x5: goto tlb_miss; + case POWERPC_EXCP_74xx: + goto tlb_miss_74xx; default: cpu_abort(env, "Invalid data load TLB miss exception\n"); break; @@ -2390,6 +2455,34 @@ static always_inline void powerpc_excp (CPUState *env, /* Set way using a LRU mechanism */ msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; break; + case POWERPC_EXCP_74xx: + tlb_miss_74xx: +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + const unsigned char *es; + target_ulong *miss, *cmp; + int en; + if (excp == POWERPC_EXCP_IFTLB) { + es = "I"; + en = 'I'; + miss = &env->spr[SPR_IMISS]; + cmp = &env->spr[SPR_ICMP]; + } else { + if (excp == POWERPC_EXCP_DLTLB) + es = "DL"; + else + es = "DS"; + en = 'D'; + miss = &env->spr[SPR_TLBMISS]; + cmp = &env->spr[SPR_PTEHI]; + } + fprintf(logfile, "74xx %sTLB miss: %cM " ADDRX " %cC " ADDRX + " %08x\n", + es, en, *miss, en, *cmp, env->error_code); + } +#endif + msr |= env->error_code; /* key bit */ + break; default: cpu_abort(env, "Invalid data store TLB miss exception\n"); break; diff --git a/target-ppc/op.c b/target-ppc/op.c index 6ad68eaba..822c26769 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2025,8 +2025,8 @@ void OPPROTO op_slbie_64 (void) #endif #endif -/* PowerPC 602/603/755 software TLB load instructions */ #if !defined(CONFIG_USER_ONLY) +/* PowerPC 602/603/755 software TLB load instructions */ void OPPROTO op_6xx_tlbld (void) { do_load_6xx_tlb(0); @@ -2038,6 +2038,19 @@ void OPPROTO op_6xx_tlbli (void) do_load_6xx_tlb(1); RETURN(); } + +/* PowerPC 74xx software TLB load instructions */ +void OPPROTO op_74xx_tlbld (void) +{ + do_load_74xx_tlb(0); + RETURN(); +} + +void OPPROTO op_74xx_tlbli (void) +{ + do_load_74xx_tlb(1); + RETURN(); +} #endif /* 601 specific */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index a7c81776f..8bb93ed36 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2363,6 +2363,27 @@ void do_load_6xx_tlb (int is_code) way, is_code, CMP, RPN); } +void do_load_74xx_tlb (int is_code) +{ + target_ulong RPN, CMP, EPN; + int way; + + RPN = env->spr[SPR_PTELO]; + CMP = env->spr[SPR_PTEHI]; + EPN = env->spr[SPR_TLBMISS] & ~0x3; + way = env->spr[SPR_TLBMISS] & 0x3; +#if defined (DEBUG_SOFTWARE_TLB) + if (loglevel != 0) { + fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n", + __func__, (unsigned long)T0, (unsigned long)EPN, + (unsigned long)CMP, (unsigned long)RPN, way); + } +#endif + /* Store this TLB */ + ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK), + way, is_code, CMP, RPN); +} + static target_ulong booke_tlb_to_page_size (int size) { return 1024 << (2 * size); diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 6f79cad91..0406682c7 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -135,6 +135,7 @@ void do_rfid (void); void do_hrfid (void); #endif void do_load_6xx_tlb (int is_code); +void do_load_74xx_tlb (int is_code); #endif /* POWER / PowerPC 601 specific helpers */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e599243b7..d8f6e95c9 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4299,7 +4299,7 @@ GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC) /* 602 - 603 - G2 TLB management */ /* tlbld */ -GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) +GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -4314,7 +4314,7 @@ GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) } /* tlbli */ -GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) +GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -4328,6 +4328,37 @@ GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) #endif } +/* 74xx TLB management */ +/* tlbld */ +GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB) +{ +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + GEN_EXCP_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_74xx_tlbld(); +#endif +} + +/* tlbli */ +GEN_HANDLER(tlbli_74xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB) +{ +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + GEN_EXCP_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_74xx_tlbli(); +#endif +} + /* POWER instructions not in PowerPC 601 */ /* clf */ GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER) -- cgit v1.2.3 From 30032c940a625f0aa8f04becf78e47274ec3a319 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 05:22:17 +0000 Subject: Fix missing nip updates for instructions that potentially generate exceptions from op helpers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3308 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d8f6e95c9..3cb89f497 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2634,6 +2634,8 @@ static GenOpFunc *gen_op_stwcx[] = { /* lwarx */ GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES) { + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); op_lwarx(); gen_op_store_T1_gpr(rD(ctx->opcode)); @@ -2642,6 +2644,8 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES) /* stwcx. */ GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) { + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); gen_op_load_gpr_T1(rS(ctx->opcode)); op_stwcx(); @@ -2689,6 +2693,8 @@ static GenOpFunc *gen_op_stdcx[] = { /* ldarx */ GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B) { + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); op_ldarx(); gen_op_store_T1_gpr(rD(ctx->opcode)); @@ -2697,6 +2703,8 @@ GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B) /* stdcx. */ GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B) { + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); gen_op_load_gpr_T1(rS(ctx->opcode)); op_stdcx(); @@ -3612,6 +3620,8 @@ static GenOpFunc *gen_op_icbi[] = { GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) { + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_update_nip(ctx, ctx->nip - 4); gen_addr_reg_index(ctx); op_icbi(); } -- cgit v1.2.3 From 55aa45ddde3283cdd781326d001f7456bf02f684 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 06:44:33 +0000 Subject: Quickly hack PowerPC BIOS able to boot on CDROM again. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3309 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/ppc_rom.bin | Bin 524288 -> 524288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin index f7cd8a82e..0ad028249 100644 Binary files a/pc-bios/ppc_rom.bin and b/pc-bios/ppc_rom.bin differ -- cgit v1.2.3 From 51996525c77e61a050562900a499798ded8981d0 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 1 Oct 2007 17:07:58 +0000 Subject: Fix block load ASIs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3310 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index fa51cdee9..a4839a055 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -862,7 +862,6 @@ void helper_st_asi(int asi, int size) case 0x19: // As if user secondary LE case 0x1c: // Bypass LE case 0x1d: // Bypass, non-cacheable LE - case 0x81: // Secondary case 0x88: // Primary LE case 0x89: // Secondary LE switch(size) { @@ -950,6 +949,7 @@ void helper_st_asi(int asi, int size) case 0x24: // Nucleus quad LDD 128 bit atomic case 0x2c: // Nucleus quad LDD 128 bit atomic case 0x4a: // UPA config + case 0x81: // Secondary case 0x89: // Secondary LE // XXX return; @@ -1137,10 +1137,18 @@ void helper_ldf_asi(int asi, int size, int rd) case 0xf1: // Block load secondary case 0xf8: // Block load primary LE case 0xf9: // Block load secondary LE - for (i = 0; i < 8; i++) { - helper_ld_asi(asi & 0x8f, 8, 0); - *((int64_t *)&DT0) = T1; - T0 += 8; + if (rd & 7) { + raise_exception(TT_ILL_INSN); + return; + } + if (T0 & 0x3f) { + raise_exception(TT_UNALIGNED); + return; + } + for (i = 0; i < 16; i++) { + helper_ld_asi(asi & 0x8f, 4, 0); + *(uint32_t *)&env->fpr[rd++] = T1; + T0 += 4; } T0 = tmp_T0; T1 = tmp_T1; @@ -1173,10 +1181,18 @@ void helper_stf_asi(int asi, int size, int rd) case 0xf1: // Block store secondary case 0xf8: // Block store primary LE case 0xf9: // Block store secondary LE - for (i = 0; i < 8; i++) { - T1 = *((int64_t *)&DT0); - helper_st_asi(asi & 0x8f, 8); - T0 += 8; + if (rd & 7) { + raise_exception(TT_ILL_INSN); + return; + } + if (T0 & 0x3f) { + raise_exception(TT_UNALIGNED); + return; + } + for (i = 0; i < 16; i++) { + T1 = *(uint32_t *)&env->fpr[rd++]; + helper_st_asi(asi & 0x8f, 4); + T0 += 4; } T0 = tmp_T0; T1 = tmp_T1; -- cgit v1.2.3 From a97fed52e57385fc749e6f6ef95be7ebdb81ba9b Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 21:49:57 +0000 Subject: Fix reproductible crash: call cpu_loop_exit from micro-op, not from helper.c git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3311 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 4 ++-- target-ppc/helper.c | 18 ++++++------------ target-ppc/op.c | 10 ++++++++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index c4ae41441..396a5884b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -611,9 +611,9 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); target_ulong ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, target_ulong value); target_ulong do_load_msr (CPUPPCState *env); -void do_store_msr (CPUPPCState *env, target_ulong value); +int do_store_msr (CPUPPCState *env, target_ulong value); #if defined(TARGET_PPC64) -void ppc_store_msr_32 (CPUPPCState *env, uint32_t value); +int ppc_store_msr_32 (CPUPPCState *env, uint32_t value); #endif void do_compute_hflags (CPUPPCState *env); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 5b0fd09b9..5fa5ee002 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1839,7 +1839,7 @@ target_ulong do_load_msr (CPUPPCState *env) ((target_ulong)msr_le << MSR_LE); } -void do_store_msr (CPUPPCState *env, target_ulong value) +int do_store_msr (CPUPPCState *env, target_ulong value) { int enter_pm; @@ -1921,21 +1921,15 @@ void do_store_msr (CPUPPCState *env, target_ulong value) default: break; } - if (enter_pm) { - if (likely(!env->halted)) { - /* power save: exit cpu loop */ - env->halted = 1; - env->exception_index = EXCP_HLT; - cpu_loop_exit(); - } - } + + return enter_pm; } #if defined(TARGET_PPC64) -void ppc_store_msr_32 (CPUPPCState *env, uint32_t value) +int ppc_store_msr_32 (CPUPPCState *env, uint32_t value) { - do_store_msr(env, - (do_load_msr(env) & ~0xFFFFFFFFULL) | (value & 0xFFFFFFFF)); + return do_store_msr(env, (do_load_msr(env) & ~0xFFFFFFFFULL) | + (value & 0xFFFFFFFF)); } #endif diff --git a/target-ppc/op.c b/target-ppc/op.c index 822c26769..72fd48346 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -351,7 +351,10 @@ void OPPROTO op_load_msr (void) void OPPROTO op_store_msr (void) { - do_store_msr(env, T0); + if (do_store_msr(env, T0)) { + env->halted = 1; + do_raise_exception(EXCP_HLT); + } RETURN(); } @@ -365,7 +368,10 @@ void OPPROTO op_update_riee (void) #if defined (TARGET_PPC64) void OPPROTO op_store_msr_32 (void) { - ppc_store_msr_32(env, T0); + if (ppc_store_msr_32(env, T0)) { + env->halted = 1; + do_raise_exception(EXCP_HLT); + } RETURN(); } #endif -- cgit v1.2.3 From 2f4011767ba7c0bf604bd4b24d91bc4e00e778fc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 1 Oct 2007 21:51:40 +0000 Subject: Fix nasty sign-extensions when running 32 bits CPU in the 64 bits emulator on 32 bits hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3312 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 72fd48346..2c0235031 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -180,7 +180,7 @@ void OPPROTO op_set_T1_64 (void) #if 0 // unused void OPPROTO op_set_T2 (void) { - T2 = PARAM1; + T2 = (uint32_t)PARAM1; RETURN(); } #endif @@ -572,7 +572,7 @@ void OPPROTO op_getbit_T1 (void) void OPPROTO op_setcrfbit (void) { - T1 = (T1 & PARAM1) | (T0 << PARAM2); + T1 = (T1 & (uint32_t)PARAM1) | (T0 << PARAM2); RETURN(); } @@ -1146,7 +1146,7 @@ void OPPROTO op_subfic (void) #if defined(TARGET_PPC64) void OPPROTO op_subfic_64 (void) { - T0 = PARAM1 + ~T0 + 1; + T0 = (int64_t)PARAM1 + ~T0 + 1; if ((uint64_t)T0 <= (uint64_t)PARAM1) { xer_ca = 1; } else { @@ -1388,26 +1388,26 @@ void OPPROTO op_andc (void) /* andi. */ void OPPROTO op_andi_T0 (void) { - T0 &= PARAM1; + T0 &= (uint32_t)PARAM1; RETURN(); } void OPPROTO op_andi_T1 (void) { - T1 &= PARAM1; + T1 &= (uint32_t)PARAM1; RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_andi_T0_64 (void) { - T0 &= ((uint64_t)PARAM1 << 32) | PARAM2; + T0 &= ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; RETURN(); } void OPPROTO op_andi_T1_64 (void) { - T1 &= ((uint64_t)PARAM1 << 32) | PARAM2; + T1 &= ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2; RETURN(); } #endif @@ -1496,7 +1496,7 @@ void OPPROTO op_orc (void) /* ori */ void OPPROTO op_ori (void) { - T0 |= PARAM1; + T0 |= (uint32_t)PARAM1; RETURN(); } @@ -1510,7 +1510,7 @@ void OPPROTO op_xor (void) /* xori */ void OPPROTO op_xori (void) { - T0 ^= PARAM1; + T0 ^= (uint32_t)PARAM1; RETURN(); } @@ -2229,7 +2229,7 @@ void OPPROTO op_POWER_nabso (void) void OPPROTO op_POWER_rlmi (void) { T0 = rotl32(T0, T2) & PARAM1; - T0 |= T1 & PARAM2; + T0 |= T1 & (uint32_t)PARAM2; RETURN(); } -- cgit v1.2.3 From 2857068eb1f7098d1af15d715c92fcd4e29d274f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Tue, 2 Oct 2007 10:11:50 +0000 Subject: Code provision for hypervisor mode memory accesses. Add comments in load & store tables to ease code reading. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3313 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 353 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 245 insertions(+), 108 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3cb89f497..5e4b12b03 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1979,6 +1979,7 @@ static inline void gen_addr_register (DisasContext *ctx) #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) +/* User mode only - 64 bits */ #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_raw, \ @@ -1997,6 +1998,7 @@ static GenOpFunc *gen_op_st##width[] = { \ #define gen_op_stb_le_64_raw gen_op_stb_64_raw #define gen_op_lbz_le_64_raw gen_op_lbz_64_raw #else +/* User mode only - 32 bits */ #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_raw, \ @@ -2013,34 +2015,75 @@ static GenOpFunc *gen_op_st##width[] = { \ #define gen_op_lbz_le_raw gen_op_lbz_raw #else #if defined(TARGET_PPC64) +#if defined(TARGET_PPC64H) +/* Full system - 64 bits with hypervisor mode */ #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_user, \ &gen_op_l##width##_le_user, \ - &gen_op_l##width##_kernel, \ - &gen_op_l##width##_le_kernel, \ &gen_op_l##width##_64_user, \ &gen_op_l##width##_le_64_user, \ + &gen_op_l##width##_kernel, \ + &gen_op_l##width##_le_kernel, \ &gen_op_l##width##_64_kernel, \ &gen_op_l##width##_le_64_kernel, \ + &gen_op_l##width##_hypv, \ + &gen_op_l##width##_le_hypv, \ + &gen_op_l##width##_64_hypv, \ + &gen_op_l##width##_le_64_hypv, \ }; #define OP_ST_TABLE(width) \ static GenOpFunc *gen_op_st##width[] = { \ &gen_op_st##width##_user, \ &gen_op_st##width##_le_user, \ + &gen_op_st##width##_64_user, \ + &gen_op_st##width##_le_64_user, \ &gen_op_st##width##_kernel, \ &gen_op_st##width##_le_kernel, \ + &gen_op_st##width##_64_kernel, \ + &gen_op_st##width##_le_64_kernel, \ + &gen_op_st##width##_hypv, \ + &gen_op_st##width##_le_hypv, \ + &gen_op_st##width##_64_hypv, \ + &gen_op_st##width##_le_64_hypv, \ +}; +/* Byte access routine are endian safe */ +#define gen_op_stb_le_hypv gen_op_stb_64_hypv +#define gen_op_lbz_le_hypv gen_op_lbz_64_hypv +#define gen_op_stb_le_64_hypv gen_op_stb_64_hypv +#define gen_op_lbz_le_64_hypv gen_op_lbz_64_hypv +#else +/* Full system - 64 bits */ +#define OP_LD_TABLE(width) \ +static GenOpFunc *gen_op_l##width[] = { \ + &gen_op_l##width##_user, \ + &gen_op_l##width##_le_user, \ + &gen_op_l##width##_64_user, \ + &gen_op_l##width##_le_64_user, \ + &gen_op_l##width##_kernel, \ + &gen_op_l##width##_le_kernel, \ + &gen_op_l##width##_64_kernel, \ + &gen_op_l##width##_le_64_kernel, \ +}; +#define OP_ST_TABLE(width) \ +static GenOpFunc *gen_op_st##width[] = { \ + &gen_op_st##width##_user, \ + &gen_op_st##width##_le_user, \ &gen_op_st##width##_64_user, \ &gen_op_st##width##_le_64_user, \ + &gen_op_st##width##_kernel, \ + &gen_op_st##width##_le_kernel, \ &gen_op_st##width##_64_kernel, \ &gen_op_st##width##_le_64_kernel, \ }; +#endif /* Byte access routine are endian safe */ -#define gen_op_stb_le_64_user gen_op_stb_64_user -#define gen_op_lbz_le_64_user gen_op_lbz_64_user +#define gen_op_stb_le_64_user gen_op_stb_64_user +#define gen_op_lbz_le_64_user gen_op_lbz_64_user #define gen_op_stb_le_64_kernel gen_op_stb_64_kernel #define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel #else +/* Full system - 32 bits */ #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ &gen_op_l##width##_user, \ @@ -2057,8 +2100,8 @@ static GenOpFunc *gen_op_st##width[] = { \ }; #endif /* Byte access routine are endian safe */ -#define gen_op_stb_le_user gen_op_stb_user -#define gen_op_lbz_le_user gen_op_lbz_user +#define gen_op_stb_le_user gen_op_stb_user +#define gen_op_lbz_le_user gen_op_lbz_user #define gen_op_stb_le_kernel gen_op_stb_kernel #define gen_op_lbz_le_kernel gen_op_lbz_kernel #endif @@ -2316,51 +2359,61 @@ GEN_STX(wbr, 0x16, 0x14, PPC_INTEGER); /*** Integer load and store multiple ***/ #define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg) -#if defined(TARGET_PPC64) #if defined(CONFIG_USER_ONLY) +/* User-mode only */ static GenOpFunc1 *gen_op_lmw[] = { &gen_op_lmw_raw, &gen_op_lmw_le_raw, +#if defined(TARGET_PPC64) &gen_op_lmw_64_raw, &gen_op_lmw_le_64_raw, +#endif }; static GenOpFunc1 *gen_op_stmw[] = { + &gen_op_stmw_raw, + &gen_op_stmw_le_raw, +#if defined(TARGET_PPC64) &gen_op_stmw_64_raw, &gen_op_stmw_le_64_raw, +#endif }; #else +#if defined(TARGET_PPC64) +/* Full system - 64 bits mode */ static GenOpFunc1 *gen_op_lmw[] = { &gen_op_lmw_user, &gen_op_lmw_le_user, - &gen_op_lmw_kernel, - &gen_op_lmw_le_kernel, &gen_op_lmw_64_user, &gen_op_lmw_le_64_user, + &gen_op_lmw_kernel, + &gen_op_lmw_le_kernel, &gen_op_lmw_64_kernel, &gen_op_lmw_le_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_lmw_hypv, + &gen_op_lmw_le_hypv, + &gen_op_lmw_64_hypv, + &gen_op_lmw_le_64_hypv, +#endif }; static GenOpFunc1 *gen_op_stmw[] = { &gen_op_stmw_user, &gen_op_stmw_le_user, - &gen_op_stmw_kernel, - &gen_op_stmw_le_kernel, &gen_op_stmw_64_user, &gen_op_stmw_le_64_user, + &gen_op_stmw_kernel, + &gen_op_stmw_le_kernel, &gen_op_stmw_64_kernel, &gen_op_stmw_le_64_kernel, -}; +#if defined(TARGET_PPC64H) + &gen_op_stmw_hypv, + &gen_op_stmw_le_hypv, + &gen_op_stmw_64_hypv, + &gen_op_stmw_le_64_hypv, #endif -#else -#if defined(CONFIG_USER_ONLY) -static GenOpFunc1 *gen_op_lmw[] = { - &gen_op_lmw_raw, - &gen_op_lmw_le_raw, -}; -static GenOpFunc1 *gen_op_stmw[] = { - &gen_op_stmw_raw, - &gen_op_stmw_le_raw, }; #else +/* Full system - 32 bits mode */ static GenOpFunc1 *gen_op_lmw[] = { &gen_op_lmw_user, &gen_op_lmw_le_user, @@ -2397,73 +2450,85 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) /*** Integer load and store strings ***/ #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start) #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb) -#if defined(TARGET_PPC64) #if defined(CONFIG_USER_ONLY) +/* User-mode only */ static GenOpFunc1 *gen_op_lswi[] = { &gen_op_lswi_raw, &gen_op_lswi_le_raw, +#if defined(TARGET_PPC64) &gen_op_lswi_64_raw, &gen_op_lswi_le_64_raw, +#endif }; static GenOpFunc3 *gen_op_lswx[] = { &gen_op_lswx_raw, &gen_op_lswx_le_raw, +#if defined(TARGET_PPC64) &gen_op_lswx_64_raw, &gen_op_lswx_le_64_raw, +#endif }; static GenOpFunc1 *gen_op_stsw[] = { &gen_op_stsw_raw, &gen_op_stsw_le_raw, +#if defined(TARGET_PPC64) &gen_op_stsw_64_raw, &gen_op_stsw_le_64_raw, +#endif }; #else +#if defined(TARGET_PPC64) +/* Full system - 64 bits mode */ static GenOpFunc1 *gen_op_lswi[] = { &gen_op_lswi_user, &gen_op_lswi_le_user, - &gen_op_lswi_kernel, - &gen_op_lswi_le_kernel, &gen_op_lswi_64_user, &gen_op_lswi_le_64_user, + &gen_op_lswi_kernel, + &gen_op_lswi_le_kernel, &gen_op_lswi_64_kernel, &gen_op_lswi_le_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_lswi_hypv, + &gen_op_lswi_le_hypv, + &gen_op_lswi_64_hypv, + &gen_op_lswi_le_64_hypv, +#endif }; static GenOpFunc3 *gen_op_lswx[] = { &gen_op_lswx_user, &gen_op_lswx_le_user, - &gen_op_lswx_kernel, - &gen_op_lswx_le_kernel, &gen_op_lswx_64_user, &gen_op_lswx_le_64_user, + &gen_op_lswx_kernel, + &gen_op_lswx_le_kernel, &gen_op_lswx_64_kernel, &gen_op_lswx_le_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_lswx_hypv, + &gen_op_lswx_le_hypv, + &gen_op_lswx_64_hypv, + &gen_op_lswx_le_64_hypv, +#endif }; static GenOpFunc1 *gen_op_stsw[] = { &gen_op_stsw_user, &gen_op_stsw_le_user, - &gen_op_stsw_kernel, - &gen_op_stsw_le_kernel, &gen_op_stsw_64_user, &gen_op_stsw_le_64_user, + &gen_op_stsw_kernel, + &gen_op_stsw_le_kernel, &gen_op_stsw_64_kernel, &gen_op_stsw_le_64_kernel, -}; +#if defined(TARGET_PPC64H) + &gen_op_stsw_hypv, + &gen_op_stsw_le_hypv, + &gen_op_stsw_64_hypv, + &gen_op_stsw_le_64_hypv, #endif -#else -#if defined(CONFIG_USER_ONLY) -static GenOpFunc1 *gen_op_lswi[] = { - &gen_op_lswi_raw, - &gen_op_lswi_le_raw, -}; -static GenOpFunc3 *gen_op_lswx[] = { - &gen_op_lswx_raw, - &gen_op_lswx_le_raw, -}; -static GenOpFunc1 *gen_op_stsw[] = { - &gen_op_stsw_raw, - &gen_op_stsw_le_raw, }; #else +/* Full system - 32 bits mode */ static GenOpFunc1 *gen_op_lswi[] = { &gen_op_lswi_user, &gen_op_lswi_le_user, @@ -2569,53 +2634,61 @@ GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM) #define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])() #define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])() -#if defined(TARGET_PPC64) #if defined(CONFIG_USER_ONLY) +/* User-mode only */ static GenOpFunc *gen_op_lwarx[] = { &gen_op_lwarx_raw, &gen_op_lwarx_le_raw, +#if defined(TARGET_PPC64) &gen_op_lwarx_64_raw, &gen_op_lwarx_le_64_raw, +#endif }; static GenOpFunc *gen_op_stwcx[] = { &gen_op_stwcx_raw, &gen_op_stwcx_le_raw, +#if defined(TARGET_PPC64) &gen_op_stwcx_64_raw, &gen_op_stwcx_le_64_raw, +#endif }; #else +#if defined(TARGET_PPC64) +/* Full system - 64 bits mode */ static GenOpFunc *gen_op_lwarx[] = { &gen_op_lwarx_user, &gen_op_lwarx_le_user, - &gen_op_lwarx_kernel, - &gen_op_lwarx_le_kernel, &gen_op_lwarx_64_user, &gen_op_lwarx_le_64_user, + &gen_op_lwarx_kernel, + &gen_op_lwarx_le_kernel, &gen_op_lwarx_64_kernel, &gen_op_lwarx_le_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_lwarx_hypv, + &gen_op_lwarx_le_hypv, + &gen_op_lwarx_64_hypv, + &gen_op_lwarx_le_64_hypv, +#endif }; static GenOpFunc *gen_op_stwcx[] = { &gen_op_stwcx_user, &gen_op_stwcx_le_user, - &gen_op_stwcx_kernel, - &gen_op_stwcx_le_kernel, &gen_op_stwcx_64_user, &gen_op_stwcx_le_64_user, + &gen_op_stwcx_kernel, + &gen_op_stwcx_le_kernel, &gen_op_stwcx_64_kernel, &gen_op_stwcx_le_64_kernel, -}; +#if defined(TARGET_PPC64H) + &gen_op_stwcx_hypv, + &gen_op_stwcx_le_hypv, + &gen_op_stwcx_64_hypv, + &gen_op_stwcx_le_64_hypv, #endif -#else -#if defined(CONFIG_USER_ONLY) -static GenOpFunc *gen_op_lwarx[] = { - &gen_op_lwarx_raw, - &gen_op_lwarx_le_raw, -}; -static GenOpFunc *gen_op_stwcx[] = { - &gen_op_stwcx_raw, - &gen_op_stwcx_le_raw, }; #else +/* Full system - 32 bits mode */ static GenOpFunc *gen_op_lwarx[] = { &gen_op_lwarx_user, &gen_op_lwarx_le_user, @@ -2655,6 +2728,7 @@ GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) #define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])() #define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) +/* User-mode only */ static GenOpFunc *gen_op_ldarx[] = { &gen_op_ldarx_raw, &gen_op_ldarx_le_raw, @@ -2668,25 +2742,38 @@ static GenOpFunc *gen_op_stdcx[] = { &gen_op_stdcx_le_64_raw, }; #else +/* Full system */ static GenOpFunc *gen_op_ldarx[] = { &gen_op_ldarx_user, &gen_op_ldarx_le_user, - &gen_op_ldarx_kernel, - &gen_op_ldarx_le_kernel, &gen_op_ldarx_64_user, &gen_op_ldarx_le_64_user, + &gen_op_ldarx_kernel, + &gen_op_ldarx_le_kernel, &gen_op_ldarx_64_kernel, &gen_op_ldarx_le_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_ldarx_hypv, + &gen_op_ldarx_le_hypv, + &gen_op_ldarx_64_hypv, + &gen_op_ldarx_le_64_hypv, +#endif }; static GenOpFunc *gen_op_stdcx[] = { &gen_op_stdcx_user, &gen_op_stdcx_le_user, - &gen_op_stdcx_kernel, - &gen_op_stdcx_le_kernel, &gen_op_stdcx_64_user, &gen_op_stdcx_le_64_user, + &gen_op_stdcx_kernel, + &gen_op_stdcx_le_kernel, &gen_op_stdcx_64_kernel, &gen_op_stdcx_le_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_stdcx_hypv, + &gen_op_stdcx_le_hypv, + &gen_op_stdcx_64_hypv, + &gen_op_stdcx_le_64_hypv, +#endif }; #endif @@ -3537,33 +3624,37 @@ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE) /* dcbz */ #define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() -#if defined(TARGET_PPC64) #if defined(CONFIG_USER_ONLY) +/* User-mode only */ static GenOpFunc *gen_op_dcbz[] = { &gen_op_dcbz_raw, &gen_op_dcbz_raw, +#if defined(TARGET_PPC64) &gen_op_dcbz_64_raw, &gen_op_dcbz_64_raw, +#endif }; #else +#if defined(TARGET_PPC64) +/* Full system - 64 bits mode */ static GenOpFunc *gen_op_dcbz[] = { &gen_op_dcbz_user, &gen_op_dcbz_user, - &gen_op_dcbz_kernel, - &gen_op_dcbz_kernel, &gen_op_dcbz_64_user, &gen_op_dcbz_64_user, + &gen_op_dcbz_kernel, + &gen_op_dcbz_kernel, &gen_op_dcbz_64_kernel, &gen_op_dcbz_64_kernel, -}; +#if defined(TARGET_PPC64H) + &gen_op_dcbz_hypv, + &gen_op_dcbz_hypv, + &gen_op_dcbz_64_hypv, + &gen_op_dcbz_64_hypv, #endif -#else -#if defined(CONFIG_USER_ONLY) -static GenOpFunc *gen_op_dcbz[] = { - &gen_op_dcbz_raw, - &gen_op_dcbz_raw, }; #else +/* Full system - 32 bits mode */ static GenOpFunc *gen_op_dcbz[] = { &gen_op_dcbz_user, &gen_op_dcbz_user, @@ -3582,33 +3673,37 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) /* icbi */ #define op_icbi() (*gen_op_icbi[ctx->mem_idx])() -#if defined(TARGET_PPC64) #if defined(CONFIG_USER_ONLY) +/* User-mode only */ static GenOpFunc *gen_op_icbi[] = { &gen_op_icbi_raw, &gen_op_icbi_raw, +#if defined(TARGET_PPC64) &gen_op_icbi_64_raw, &gen_op_icbi_64_raw, +#endif }; #else +/* Full system - 64 bits mode */ +#if defined(TARGET_PPC64) static GenOpFunc *gen_op_icbi[] = { &gen_op_icbi_user, &gen_op_icbi_user, - &gen_op_icbi_kernel, - &gen_op_icbi_kernel, &gen_op_icbi_64_user, &gen_op_icbi_64_user, + &gen_op_icbi_kernel, + &gen_op_icbi_kernel, &gen_op_icbi_64_kernel, &gen_op_icbi_64_kernel, -}; +#if defined(TARGET_PPC64H) + &gen_op_icbi_hypv, + &gen_op_icbi_hypv, + &gen_op_icbi_64_hypv, + &gen_op_icbi_64_hypv, #endif -#else -#if defined(CONFIG_USER_ONLY) -static GenOpFunc *gen_op_icbi[] = { - &gen_op_icbi_raw, - &gen_op_icbi_raw, }; #else +/* Full system - 32 bits mode */ static GenOpFunc *gen_op_icbi[] = { &gen_op_icbi_user, &gen_op_icbi_user, @@ -3796,53 +3891,61 @@ GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI) /* Optional: */ #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])() #define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])() -#if defined(TARGET_PPC64) #if defined(CONFIG_USER_ONLY) +/* User-mode only */ static GenOpFunc *gen_op_eciwx[] = { &gen_op_eciwx_raw, &gen_op_eciwx_le_raw, +#if defined(TARGET_PPC64) &gen_op_eciwx_64_raw, &gen_op_eciwx_le_64_raw, +#endif }; static GenOpFunc *gen_op_ecowx[] = { &gen_op_ecowx_raw, &gen_op_ecowx_le_raw, +#if defined(TARGET_PPC64) &gen_op_ecowx_64_raw, &gen_op_ecowx_le_64_raw, +#endif }; #else +#if defined(TARGET_PPC64) +/* Full system - 64 bits mode */ static GenOpFunc *gen_op_eciwx[] = { &gen_op_eciwx_user, &gen_op_eciwx_le_user, - &gen_op_eciwx_kernel, - &gen_op_eciwx_le_kernel, &gen_op_eciwx_64_user, &gen_op_eciwx_le_64_user, + &gen_op_eciwx_kernel, + &gen_op_eciwx_le_kernel, &gen_op_eciwx_64_kernel, &gen_op_eciwx_le_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_eciwx_hypv, + &gen_op_eciwx_le_hypv, + &gen_op_eciwx_64_hypv, + &gen_op_eciwx_le_64_hypv, +#endif }; static GenOpFunc *gen_op_ecowx[] = { &gen_op_ecowx_user, &gen_op_ecowx_le_user, - &gen_op_ecowx_kernel, - &gen_op_ecowx_le_kernel, &gen_op_ecowx_64_user, &gen_op_ecowx_le_64_user, + &gen_op_ecowx_kernel, + &gen_op_ecowx_le_kernel, &gen_op_ecowx_64_kernel, &gen_op_ecowx_le_64_kernel, -}; +#if defined(TARGET_PPC64H) + &gen_op_ecowx_hypv, + &gen_op_ecowx_le_hypv, + &gen_op_ecowx_64_hypv, + &gen_op_ecowx_le_64_hypv, #endif -#else -#if defined(CONFIG_USER_ONLY) -static GenOpFunc *gen_op_eciwx[] = { - &gen_op_eciwx_raw, - &gen_op_eciwx_le_raw, -}; -static GenOpFunc *gen_op_ecowx[] = { - &gen_op_ecowx_raw, - &gen_op_ecowx_le_raw, }; #else +/* Full system - 32 bits mode */ static GenOpFunc *gen_op_eciwx[] = { &gen_op_eciwx_user, &gen_op_eciwx_le_user, @@ -3981,7 +4084,7 @@ GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR) } /* As lscbx load from memory byte after byte, it's always endian safe */ -#define op_POWER_lscbx(start, ra, rb) \ +#define op_POWER_lscbx(start, ra, rb) \ (*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb) #if defined(CONFIG_USER_ONLY) static GenOpFunc3 *gen_op_POWER_lscbx[] = { @@ -5269,6 +5372,7 @@ static inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh) #define op_spe_ldst(name) (*gen_op_##name[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) +/* User-mode only - 64 bits mode */ #define OP_SPE_LD_TABLE(name) \ static GenOpFunc *gen_op_spe_l##name[] = { \ &gen_op_spe_l##name##_raw, \ @@ -5284,6 +5388,7 @@ static GenOpFunc *gen_op_spe_st##name[] = { \ &gen_op_spe_st##name##_le_64_raw, \ }; #else /* defined(TARGET_PPC64) */ +/* User-mode only - 32 bits mode */ #define OP_SPE_LD_TABLE(name) \ static GenOpFunc *gen_op_spe_l##name[] = { \ &gen_op_spe_l##name##_raw, \ @@ -5296,30 +5401,64 @@ static GenOpFunc *gen_op_spe_st##name[] = { \ }; #endif /* defined(TARGET_PPC64) */ #else /* defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_PPC64) +#if defined(TARGET_PPC64H) +/* Full system with hypervisor mode */ #define OP_SPE_LD_TABLE(name) \ static GenOpFunc *gen_op_spe_l##name[] = { \ &gen_op_spe_l##name##_user, \ &gen_op_spe_l##name##_le_user, \ - &gen_op_spe_l##name##_kernel, \ - &gen_op_spe_l##name##_le_kernel, \ &gen_op_spe_l##name##_64_user, \ &gen_op_spe_l##name##_le_64_user, \ + &gen_op_spe_l##name##_kernel, \ + &gen_op_spe_l##name##_le_kernel, \ &gen_op_spe_l##name##_64_kernel, \ &gen_op_spe_l##name##_le_64_kernel, \ + &gen_op_spe_l##name##_hypv, \ + &gen_op_spe_l##name##_le_hypv, \ + &gen_op_spe_l##name##_64_hypv, \ + &gen_op_spe_l##name##_le_64_hypv, \ }; #define OP_SPE_ST_TABLE(name) \ static GenOpFunc *gen_op_spe_st##name[] = { \ &gen_op_spe_st##name##_user, \ &gen_op_spe_st##name##_le_user, \ + &gen_op_spe_st##name##_64_user, \ + &gen_op_spe_st##name##_le_64_user, \ &gen_op_spe_st##name##_kernel, \ &gen_op_spe_st##name##_le_kernel, \ + &gen_op_spe_st##name##_64_kernel, \ + &gen_op_spe_st##name##_le_64_kernel, \ + &gen_op_spe_st##name##_hypv, \ + &gen_op_spe_st##name##_le_hypv, \ + &gen_op_spe_st##name##_64_hypv, \ + &gen_op_spe_st##name##_le_64_hypv, \ +}; +#elif defined(TARGET_PPC64) +/* Full system - 64 bits mode */ +#define OP_SPE_LD_TABLE(name) \ +static GenOpFunc *gen_op_spe_l##name[] = { \ + &gen_op_spe_l##name##_user, \ + &gen_op_spe_l##name##_le_user, \ + &gen_op_spe_l##name##_64_user, \ + &gen_op_spe_l##name##_le_64_user, \ + &gen_op_spe_l##name##_kernel, \ + &gen_op_spe_l##name##_le_kernel, \ + &gen_op_spe_l##name##_64_kernel, \ + &gen_op_spe_l##name##_le_64_kernel, \ +}; +#define OP_SPE_ST_TABLE(name) \ +static GenOpFunc *gen_op_spe_st##name[] = { \ + &gen_op_spe_st##name##_user, \ + &gen_op_spe_st##name##_le_user, \ &gen_op_spe_st##name##_64_user, \ &gen_op_spe_st##name##_le_64_user, \ + &gen_op_spe_st##name##_kernel, \ + &gen_op_spe_st##name##_le_kernel, \ &gen_op_spe_st##name##_64_kernel, \ &gen_op_spe_st##name##_le_64_kernel, \ }; #else /* defined(TARGET_PPC64) */ +/* Full system - 32 bits mode */ #define OP_SPE_LD_TABLE(name) \ static GenOpFunc *gen_op_spe_l##name[] = { \ &gen_op_spe_l##name##_user, \ @@ -6173,6 +6312,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, opc_handler_t **table, *handler; target_ulong pc_start; uint16_t *gen_opc_end; + int supervisor; int j, lj = -1; pc_start = tb->pc; @@ -6185,24 +6325,21 @@ static inline int gen_intermediate_code_internal (CPUState *env, ctx.exception = POWERPC_EXCP_NONE; ctx.spr_cb = env->spr_cb; #if defined(CONFIG_USER_ONLY) - ctx.mem_idx = msr_le; -#if defined(TARGET_PPC64) - ctx.mem_idx |= msr_sf << 1; -#endif + supervisor = 0; #else #if defined(TARGET_PPC64H) if (msr_pr == 0 && msr_hv == 1) - ctx.supervisor = 2; + supervisor = 2; else #endif - ctx.supervisor = 1 - msr_pr; - ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le; -#if defined(TARGET_PPC64) - ctx.mem_idx |= msr_sf << 2; -#endif + supervisor = 1 - msr_pr; + ctx.supervisor = supervisor; #endif #if defined(TARGET_PPC64) ctx.sf_mode = msr_sf; + ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | msr_le; +#else + ctx.mem_idx = (supervisor << 1) | msr_le; #endif ctx.fpu_enabled = msr_fp; #if defined(TARGET_PPCEMB) -- cgit v1.2.3 From 0bd5f4ce3b5c95cbcddef6c14776bdb950070c3f Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 2 Oct 2007 19:15:48 +0000 Subject: Fix kernel loading git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3314 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index a76c53b28..76b0e7ee8 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -440,7 +440,8 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, kernel_size = 0; if (linux_boot) { - kernel_size = load_elf(kernel_filename, -0xf0000000, NULL, NULL, NULL); + kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL, + NULL); if (kernel_size < 0) kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) -- cgit v1.2.3 From 217fae2d6be868d80c587639d82ed9b1028913bb Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 3 Oct 2007 01:04:20 +0000 Subject: Fix PowerPC 405 BIOS instanciation: is a 32 bits only target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3315 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405_boards.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 8f82ea9e1..ebf160cb7 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -226,8 +226,8 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, fl_idx, bios_size, bios_offset, -bios_size, bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors); #endif - pflash_register(-(bios_size), bios_offset, pflash_table[fl_idx], - 65536, fl_sectors, 2, + pflash_register((uint32_t)(-bios_size), bios_offset, + pflash_table[fl_idx], 65536, fl_sectors, 2, 0x0001, 0x22DA, 0x0000, 0x0000); fl_idx++; } else @@ -266,7 +266,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, memset(&bd, 0, sizeof(bd)); bd.bi_memstart = 0x00000000; bd.bi_memsize = ram_size; - bd.bi_flashstart = -(bios_size); + bd.bi_flashstart = -bios_size; bd.bi_flashsize = -bios_size; bd.bi_flashoffset = 0; bd.bi_sramstart = 0xFFF00000; @@ -539,8 +539,8 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, fl_idx, bios_size, bios_offset, -bios_size, bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors); #endif - pflash_register(-(bios_size), bios_offset, pflash_table[fl_idx], - 65536, fl_sectors, 4, + pflash_register((uint32_t)(-bios_size), bios_offset, + pflash_table[fl_idx], 65536, fl_sectors, 4, 0x0001, 0x22DA, 0x0000, 0x0000); fl_idx++; } else -- cgit v1.2.3 From 00af685fc974e4941ef2d309a2e8818d311a370c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 3 Oct 2007 01:05:39 +0000 Subject: We never have to export ppc_set_irq. Protect PowerPC 64 only features with #ifdef (TARGET_PPC64) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3316 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 4 +++- hw/ppc_chrp.c | 2 ++ target-ppc/cpu.h | 14 ++++++++++---- target-ppc/helper.c | 13 +++++++++++++ target-ppc/translate_init.c | 26 +++++++++++++++++--------- 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 8e7912e3c..a9bfc47d3 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -30,7 +30,7 @@ extern FILE *logfile; extern int loglevel; -void ppc_set_irq (CPUState *env, int n_IRQ, int level) +static void ppc_set_irq (CPUState *env, int n_IRQ, int level) { if (level) { env->pending_interrupts |= 1 << n_IRQ; @@ -162,6 +162,7 @@ void ppc6xx_irq_init (CPUState *env) env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6); } +#if defined(TARGET_PPC64) /* PowerPC 970 internal IRQ controller */ static void ppc970_set_irq (void *opaque, int pin, int level) { @@ -283,6 +284,7 @@ void ppc970_irq_init (CPUState *env) { env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7); } +#endif /* defined(TARGET_PPC64) */ /* PowerPC 40x internal IRQ controller */ static void ppc40x_set_irq (void *opaque, int pin, int level) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 64746159b..9c6ac84a4 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -491,6 +491,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, openpic_irqs[i][OPENPIC_OUTPUT_RESET] = ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET]; break; +#if defined(TARGET_PPC64) case PPC_FLAGS_INPUT_970: openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); openpic_irqs[i][OPENPIC_OUTPUT_INT] = @@ -505,6 +506,7 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, openpic_irqs[i][OPENPIC_OUTPUT_RESET] = ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET]; break; +#endif /* defined(TARGET_PPC64) */ default: cpu_abort(env, "Bus model not supported on mac99 machine\n"); exit(1); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 396a5884b..54baeb822 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -94,8 +94,6 @@ enum { POWERPC_MMU_UNKNOWN = 0, /* Standard 32 bits PowerPC MMU */ POWERPC_MMU_32B, - /* Standard 64 bits PowerPC MMU */ - POWERPC_MMU_64B, /* PowerPC 601 MMU */ POWERPC_MMU_601, /* PowerPC 6xx MMU with software TLB */ @@ -112,8 +110,12 @@ enum { POWERPC_MMU_BOOKE, /* BookE FSL MMU model */ POWERPC_MMU_BOOKE_FSL, +#if defined(TARGET_PPC64) + /* Standard 64 bits PowerPC MMU */ + POWERPC_MMU_64B, /* 64 bits "bridge" PowerPC MMU */ POWERPC_MMU_64BRIDGE, +#endif /* defined(TARGET_PPC64) */ }; /*****************************************************************************/ @@ -142,10 +144,12 @@ enum { POWERPC_EXCP_7x5, /* PowerPC 74xx exception model */ POWERPC_EXCP_74xx, - /* PowerPC 970 exception model */ - POWERPC_EXCP_970, /* BookE exception model */ POWERPC_EXCP_BOOKE, +#if defined(TARGET_PPC64) + /* PowerPC 970 exception model */ + POWERPC_EXCP_970, +#endif /* defined(TARGET_PPC64) */ }; /*****************************************************************************/ @@ -1133,6 +1137,7 @@ enum { PPC40x_INPUT_NB, }; +#if defined(TARGET_PPC64) enum { /* PowerPC 620 (and probably others) input pins */ PPC620_INPUT_HRESET = 0, @@ -1155,6 +1160,7 @@ enum { PPC970_INPUT_INT = 5, PPC970_INPUT_THINT = 6, }; +#endif /* Hardware exceptions definitions */ enum { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 5fa5ee002..438cad42a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1612,10 +1612,16 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) cpu_abort(env, "MMU model not implemented\n"); break; case POWERPC_MMU_32B: +#if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_64BRIDGE: +#endif /* defined(TARGET_PPC64) */ tlb_flush(env, 1); break; + default: + /* XXX: TODO */ + cpu_abort(env, "Unknown MMU model %d\n", env->mmu_model); + break; } } @@ -1672,14 +1678,21 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) tlb_flush_page(env, addr | (0xE << 28)); tlb_flush_page(env, addr | (0xF << 28)); break; +#if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_64BRIDGE: /* tlbie invalidate TLBs for all segments */ /* XXX: given the fact that there are too many segments to invalidate, + * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu, * we just invalidate all TLBs */ tlb_flush(env, 1); break; +#endif /* defined(TARGET_PPC64) */ + default: + /* XXX: TODO */ + cpu_abort(env, "Unknown MMU model 2\n"); + break; } #else ppc_tlb_invalidate_all(env); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 88d67d9cf..2a996cc1b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4448,6 +4448,7 @@ enum { CPU_POWERPC_74x7_v11 = 0x80030101, /* aka B: 1.1 */ CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ /* 64 bits PowerPC */ +#if defined(TARGET_PPC64) CPU_POWERPC_620 = 0x00140000, CPU_POWERPC_630 = 0x00400000, CPU_POWERPC_631 = 0x00410104, @@ -4481,6 +4482,7 @@ enum { CPU_POWERPC_RS64II = 0x00340000, CPU_POWERPC_RS64III = 0x00360000, CPU_POWERPC_RS64IV = 0x00370000, +#endif /* defined(TARGET_PPC64) */ /* Original POWER */ /* XXX: should be POWER (RIOS), RSC3308, RSC4608, * POWER2 (RIOS2) & RSC2 (P2SC) here @@ -5835,9 +5837,6 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) case POWERPC_MMU_32B: mmu_model = "PowerPC 32"; break; - case POWERPC_MMU_64B: - mmu_model = "PowerPC 64"; - break; case POWERPC_MMU_601: mmu_model = "PowerPC 601"; break; @@ -5863,9 +5862,14 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) case POWERPC_MMU_BOOKE_FSL: mmu_model = "PowerPC BookE FSL"; break; +#if defined (TARGET_PPC64) + case POWERPC_MMU_64B: + mmu_model = "PowerPC 64"; + break; case POWERPC_MMU_64BRIDGE: mmu_model = "PowerPC 64 bridge"; break; +#endif default: mmu_model = "Unknown or invalid"; break; @@ -5901,12 +5905,14 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) case POWERPC_EXCP_74xx: excp_model = "PowerPC 74xx"; break; - case POWERPC_EXCP_970: - excp_model = "PowerPC 970"; - break; case POWERPC_EXCP_BOOKE: excp_model = "PowerPC BookE"; break; +#if defined (TARGET_PPC64) + case POWERPC_EXCP_970: + excp_model = "PowerPC 970"; + break; +#endif default: excp_model = "Unknown or invalid"; break; @@ -5921,12 +5927,14 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) case PPC_FLAGS_INPUT_405: bus_model = "PowerPC 405"; break; - case PPC_FLAGS_INPUT_970: - bus_model = "PowerPC 970"; - break; case PPC_FLAGS_INPUT_401: bus_model = "PowerPC 401/403"; break; +#if defined (TARGET_PPC64) + case PPC_FLAGS_INPUT_970: + bus_model = "PowerPC 970"; + break; +#endif default: bus_model = "Unknown or invalid"; break; -- cgit v1.2.3 From fe33cc710327455a55bd4f44bc7aa69661cc7878 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 3 Oct 2007 01:06:57 +0000 Subject: Fix PowerPC initialisation and first reset: reset must occur after we defined the CPU features. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3317 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 6 +++--- hw/ppc_prep.c | 21 +++++++++++++-------- target-ppc/helper.c | 5 ++++- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 9c6ac84a4..653f7c3a7 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -327,9 +327,6 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* init CPUs */ env = cpu_init(); - qemu_register_reset(&cpu_ppc_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - if (cpu_model == NULL) cpu_model = "default"; ppc_find_by_name(cpu_model, &def); @@ -338,9 +335,12 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, } for (i = 0; i < smp_cpus; i++) { cpu_ppc_register(env, def); + cpu_ppc_reset(env); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); env->osi_call = vga_osi_call; + qemu_register_reset(&cpu_ppc_reset, env); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); envs[i] = env; } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 504ca33a9..9e2a4403a 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -26,6 +26,9 @@ //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO +/* SMP is not enabled, for now */ +#define MAX_CPUS 1 + #define BIOS_FILENAME "ppc_rom.bin" #define KERNEL_LOAD_ADDR 0x01000000 #define INITRD_LOAD_ADDR 0x01800000 @@ -521,7 +524,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, const char *initrd_filename, const char *cpu_model) { - CPUState *env; + CPUState *env, *envs[MAX_CPUS]; char buf[1024]; m48t59_t *nvram; int PPC_io_memory; @@ -539,20 +542,22 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, linux_boot = (kernel_filename != NULL); /* init CPUs */ - env = cpu_init(); - qemu_register_reset(&cpu_ppc_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - if (cpu_model == NULL) cpu_model = "default"; ppc_find_by_name(cpu_model, &def); if (def == NULL) { cpu_abort(env, "Unable to find PowerPC CPU definition\n"); } - cpu_ppc_register(env, def); - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + for (i = 0; i < smp_cpus; i++) { + cpu_ppc_register(env, def); + cpu_ppc_reset(env); + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + qemu_register_reset(&cpu_ppc_reset, env); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + envs[i] = env; + } /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 438cad42a..daee4c7a1 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2788,8 +2788,12 @@ void cpu_ppc_reset (void *opaque) #if defined(CONFIG_USER_ONLY) msr_fp = 1; /* Allow floating point exceptions */ msr_pr = 1; +#else +#if defined(TARGET_PPC64) + env->nip = 0x00000100; #else env->nip = 0xFFFFFFFC; +#endif ppc_tlb_invalidate_all(env); #endif do_compute_hflags(env); @@ -2810,7 +2814,6 @@ CPUPPCState *cpu_ppc_init (void) if (!env) return NULL; cpu_exec_init(env); - cpu_ppc_reset(env); return env; } -- cgit v1.2.3 From 0387d928754f08574a18ff72104d669d91dcc2f8 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 3 Oct 2007 17:46:29 +0000 Subject: Fix Sparc64 ldfa/stfa and float ops with fpr >= 32 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3318 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 94503bee8..1a6d56ac4 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -87,7 +87,7 @@ enum { #define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1)) #ifdef TARGET_SPARC64 -#define DFPREG(r) (((r & 1) << 6) | (r & 0x1e)) +#define DFPREG(r) (((r & 1) << 5) | (r & 0x1e)) #else #define DFPREG(r) (r & 0x1e) #endif @@ -431,7 +431,7 @@ static inline void gen_ldf_asi(int insn, int size) { int asi, offset, rd; - rd = GET_FIELD(insn, 2, 6); + rd = DFPREG(GET_FIELD(insn, 2, 6)); if (IS_IMM) { offset = GET_FIELD(insn, 25, 31); gen_op_ldf_asi_reg(offset, size, rd); @@ -445,7 +445,7 @@ static inline void gen_stf_asi(int insn, int size) { int asi, offset, rd; - rd = GET_FIELD(insn, 2, 6); + rd = DFPREG(GET_FIELD(insn, 2, 6)); if (IS_IMM) { offset = GET_FIELD(insn, 25, 31); gen_op_stf_asi_reg(offset, size, rd); -- cgit v1.2.3 From 8f793433afd8f892db15fc153bb0aa94145582d6 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 3 Oct 2007 20:19:40 +0000 Subject: Enable PowerPC 64 MMU model and exceptions. Cleanups in MMU exceptions generation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3319 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 139 +++++++++++++++++++++++++++------------------------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index daee4c7a1..1039111a0 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -45,10 +45,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, if (rw == 2) { exception = POWERPC_EXCP_ISI; - error_code = 0; + error_code = 0x40000000; } else { exception = POWERPC_EXCP_DSI; - error_code = 0; + error_code = 0x40000000; if (rw) error_code |= 0x02000000; env->spr[SPR_DAR] = address; @@ -1227,7 +1227,6 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu) { mmu_ctx_t ctx; - int exception = 0, error_code = 0; int access_type; int ret = 0; @@ -1253,40 +1252,34 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, cpu_dump_state(env, logfile, fprintf, 0); #endif if (access_type == ACCESS_CODE) { - exception = POWERPC_EXCP_ISI; switch (ret) { case -1: /* No matches in page tables or TLB */ switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: - exception = POWERPC_EXCP_IFTLB; + env->exception_index = POWERPC_EXCP_IFTLB; + env->error_code = 1 << 18; env->spr[SPR_IMISS] = address; env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; - error_code = 1 << 18; goto tlb_miss; case POWERPC_MMU_SOFT_74xx: - exception = POWERPC_EXCP_IFTLB; + env->exception_index = POWERPC_EXCP_IFTLB; goto tlb_miss_74xx; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: - exception = POWERPC_EXCP_ITLB; - error_code = 0; + env->exception_index = POWERPC_EXCP_ITLB; + env->error_code = 0; env->spr[SPR_40x_DEAR] = address; env->spr[SPR_40x_ESR] = 0x00000000; break; case POWERPC_MMU_32B: - error_code = 0x40000000; - break; #if defined(TARGET_PPC64) case POWERPC_MMU_64B: - /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); - return -1; case POWERPC_MMU_64BRIDGE: - /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); - return -1; #endif + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x40000000; + break; case POWERPC_MMU_601: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); @@ -1310,64 +1303,65 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, break; case -2: /* Access rights violation */ - error_code = 0x08000000; + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x08000000; break; case -3: /* No execute protection violation */ - error_code = 0x10000000; + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x10000000; break; case -4: /* Direct store exception */ /* No code fetch is allowed in direct-store areas */ - error_code = 0x10000000; + env->exception_index = POWERPC_EXCP_ISI; + env->error_code = 0x10000000; break; #if defined(TARGET_PPC64) case -5: /* No match in segment table */ - exception = POWERPC_EXCP_ISEG; - error_code = 0; + env->exception_index = POWERPC_EXCP_ISEG; + env->error_code = 0; break; #endif } } else { - exception = POWERPC_EXCP_DSI; switch (ret) { case -1: /* No matches in page tables or TLB */ switch (env->mmu_model) { case POWERPC_MMU_SOFT_6xx: if (rw == 1) { - exception = POWERPC_EXCP_DSTLB; - error_code = 1 << 16; + env->exception_index = POWERPC_EXCP_DSTLB; + env->error_code = 1 << 16; } else { - exception = POWERPC_EXCP_DLTLB; - error_code = 0; + env->exception_index = POWERPC_EXCP_DLTLB; + env->error_code = 0; } env->spr[SPR_DMISS] = address; env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem; tlb_miss: - error_code |= ctx.key << 19; + env->error_code |= ctx.key << 19; env->spr[SPR_HASH1] = ctx.pg_addr[0]; env->spr[SPR_HASH2] = ctx.pg_addr[1]; - /* Do not alter DAR nor DSISR */ - goto out; + break; case POWERPC_MMU_SOFT_74xx: if (rw == 1) { - exception = POWERPC_EXCP_DSTLB; + env->exception_index = POWERPC_EXCP_DSTLB; } else { - exception = POWERPC_EXCP_DLTLB; + env->exception_index = POWERPC_EXCP_DLTLB; } tlb_miss_74xx: /* Implement LRU algorithm */ + env->error_code = ctx.key << 19; env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) | ((env->last_way + 1) & (env->nb_ways - 1)); env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem; - error_code = ctx.key << 19; break; case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_SOFT_4xx_Z: - exception = POWERPC_EXCP_DTLB; - error_code = 0; + env->exception_index = POWERPC_EXCP_DTLB; + env->error_code = 0; env->spr[SPR_40x_DEAR] = address; if (rw) env->spr[SPR_40x_ESR] = 0x00800000; @@ -1375,18 +1369,18 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_40x_ESR] = 0x00000000; break; case POWERPC_MMU_32B: - error_code = 0x40000000; - break; #if defined(TARGET_PPC64) case POWERPC_MMU_64B: - /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); - return -1; case POWERPC_MMU_64BRIDGE: - /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); - return -1; #endif + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + if (rw == 1) + env->spr[SPR_DSISR] = 0x42000000; + else + env->spr[SPR_DSISR] = 0x40000000; + break; case POWERPC_MMU_601: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); @@ -1410,52 +1404,66 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, break; case -2: /* Access rights violation */ - error_code = 0x08000000; + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + if (rw == 1) + env->spr[SPR_DSISR] = 0x0A000000; + else + env->spr[SPR_DSISR] = 0x08000000; break; case -4: /* Direct store exception */ switch (access_type) { case ACCESS_FLOAT: /* Floating point load/store */ - exception = POWERPC_EXCP_ALIGN; - error_code = POWERPC_EXCP_ALIGN_FP; + env->exception_index = POWERPC_EXCP_ALIGN; + env->error_code = POWERPC_EXCP_ALIGN_FP; + env->spr[SPR_DAR] = address; break; case ACCESS_RES: - /* lwarx, ldarx or srwcx. */ - error_code = 0x04000000; + /* lwarx, ldarx or stwcx. */ + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + if (rw == 1) + env->spr[SPR_DSISR] = 0x06000000; + else + env->spr[SPR_DSISR] = 0x04000000; break; case ACCESS_EXT: /* eciwx or ecowx */ - error_code = 0x04100000; + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + if (rw == 1) + env->spr[SPR_DSISR] = 0x06100000; + else + env->spr[SPR_DSISR] = 0x04100000; break; default: printf("DSI: invalid exception (%d)\n", ret); - exception = POWERPC_EXCP_PROGRAM; - error_code = POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL; + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = + POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL; + env->spr[SPR_DAR] = address; break; } break; #if defined(TARGET_PPC64) case -5: /* No match in segment table */ - exception = POWERPC_EXCP_DSEG; - error_code = 0; + env->exception_index = POWERPC_EXCP_DSEG; + env->error_code = 0; + env->spr[SPR_DAR] = address; break; #endif } - if (exception == POWERPC_EXCP_DSI && rw == 1) - error_code |= 0x02000000; - /* Store fault address */ - env->spr[SPR_DAR] = address; - env->spr[SPR_DSISR] = error_code; } - out: #if 0 - printf("%s: set exception to %d %02x\n", - __func__, exception, error_code); + printf("%s: set exception to %d %02x\n", __func__, + env->exception, env->error_code); #endif - env->exception_index = exception; - env->error_code = error_code; ret = 1; } @@ -2291,8 +2299,6 @@ static always_inline void powerpc_excp (CPUState *env, if (lpes1 == 0) msr_hv = 1; #endif - /* XXX: TODO */ - cpu_abort(env, "Data segment exception is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ msr_ri = 0; @@ -2300,9 +2306,6 @@ static always_inline void powerpc_excp (CPUState *env, if (lpes1 == 0) msr_hv = 1; #endif - /* XXX: TODO */ - cpu_abort(env, - "Instruction segment exception is not implemented yet !\n"); goto store_next; #endif /* defined(TARGET_PPC64) */ #if defined(TARGET_PPC64H) -- cgit v1.2.3 From 064034211a65bb602a32ccee18d92109eb2cd656 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 3 Oct 2007 20:27:44 +0000 Subject: HID0 is a write-clear register on 970 (DBSR). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3320 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2a996cc1b..355f5ad07 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3859,7 +3859,7 @@ static void init_proc_970 (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_clear, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", @@ -3902,7 +3902,7 @@ static void init_proc_970FX (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_clear, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", @@ -3945,7 +3945,7 @@ static void init_proc_970GX (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_clear, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", -- cgit v1.2.3 From d63001d11434fc6bf217255b51f625a75d05fb35 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 4 Oct 2007 00:51:58 +0000 Subject: Make PowerPC cache line size implementation dependant. Implement dcbz tunable cache line size for PowerPC 970. Make hardware reset vector implementation dependant. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3321 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 11 +- target-ppc/op_helper.c | 12 +-- target-ppc/op_helper.h | 2 + target-ppc/op_helper_mem.h | 102 +++++++++++++++++- target-ppc/op_mem.h | 122 ++++++++++++++++++++-- target-ppc/translate.c | 185 ++++++++++++++++++++++++++++----- target-ppc/translate_init.c | 246 ++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 620 insertions(+), 60 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 54baeb822..43b8c90b1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -82,12 +82,6 @@ typedef uint32_t ppc_gpr_t; #define ELF_MACHINE EM_PPC #endif -/* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC - * have different cache line sizes - */ -#define ICACHE_LINE_SIZE 32 -#define DCACHE_LINE_SIZE 32 - /*****************************************************************************/ /* MMU model */ enum { @@ -521,6 +515,9 @@ struct CPUPPCState { /* 403 dedicated access protection registers */ target_ulong pb[4]; + int dcache_line_size; + int icache_line_size; + /* Those resources are used during exception processing */ /* CPU model definition */ target_ulong msr_mask; @@ -546,6 +543,7 @@ struct CPUPPCState { target_ulong excp_prefix; target_ulong ivor_mask; target_ulong ivpr_mask; + target_ulong hreset_vector; #endif /* Those resources are used only during code translation */ @@ -1052,6 +1050,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_601_HID5 (0x3F5) #define SPR_40x_DAC1 (0x3F6) #define SPR_MSSCR0 (0x3F6) +#define SPR_970_HID5 (0x3F6) #define SPR_MSSSR0 (0x3F7) #define SPR_DABRX (0x3F7) #define SPR_40x_DAC2 (0x3F7) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 8bb93ed36..56d2af75d 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1061,21 +1061,21 @@ void do_POWER_clcs (void) switch (T0) { case 0x0CUL: /* Instruction cache line size */ - T0 = ICACHE_LINE_SIZE; + T0 = env->icache_line_size; break; case 0x0DUL: /* Data cache line size */ - T0 = DCACHE_LINE_SIZE; + T0 = env->dcache_line_size; break; case 0x0EUL: /* Minimum cache line size */ - T0 = ICACHE_LINE_SIZE < DCACHE_LINE_SIZE ? - ICACHE_LINE_SIZE : DCACHE_LINE_SIZE; + T0 = env->icache_line_size < env->dcache_line_size ? + env->icache_line_size : env->dcache_line_size; break; case 0x0FUL: /* Maximum cache line size */ - T0 = ICACHE_LINE_SIZE > DCACHE_LINE_SIZE ? - ICACHE_LINE_SIZE : DCACHE_LINE_SIZE; + T0 = env->icache_line_size > env->dcache_line_size ? + env->icache_line_size : env->dcache_line_size; break; default: /* Undefined */ diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 0406682c7..65bee1ae7 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -30,6 +30,7 @@ void glue(do_lmw_le, MEMSUFFIX) (int dst); void glue(do_stmw, MEMSUFFIX) (int src); void glue(do_stmw_le, MEMSUFFIX) (int src); void glue(do_icbi, MEMSUFFIX) (void); +void glue(do_dcbz, MEMSUFFIX) (void); void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb); void glue(do_POWER2_lfq, MEMSUFFIX) (void); void glue(do_POWER2_lfq_le, MEMSUFFIX) (void); @@ -46,6 +47,7 @@ void glue(do_lmw_le_64, MEMSUFFIX) (int dst); void glue(do_stmw_64, MEMSUFFIX) (int src); void glue(do_stmw_le_64, MEMSUFFIX) (int src); void glue(do_icbi_64, MEMSUFFIX) (void); +void glue(do_dcbz_64, MEMSUFFIX) (void); #endif #else diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index e8cca09e9..f5cb6970c 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -252,8 +252,9 @@ void glue(do_icbi, MEMSUFFIX) (void) * do the load "by hand". */ tmp = glue(ldl, MEMSUFFIX)((uint32_t)T0); - T0 &= ~(ICACHE_LINE_SIZE - 1); - tb_invalidate_page_range((uint32_t)T0, (uint32_t)(T0 + ICACHE_LINE_SIZE)); + T0 &= ~(env->icache_line_size - 1); + tb_invalidate_page_range((uint32_t)T0, + (uint32_t)(T0 + env->icache_line_size)); } #if defined(TARGET_PPC64) @@ -266,8 +267,101 @@ void glue(do_icbi_64, MEMSUFFIX) (void) * do the load "by hand". */ tmp = glue(ldq, MEMSUFFIX)((uint64_t)T0); - T0 &= ~(ICACHE_LINE_SIZE - 1); - tb_invalidate_page_range((uint64_t)T0, (uint64_t)(T0 + ICACHE_LINE_SIZE)); + T0 &= ~(env->icache_line_size - 1); + tb_invalidate_page_range((uint64_t)T0, + (uint64_t)(T0 + env->icache_line_size)); +} +#endif + +void glue(do_dcbz, MEMSUFFIX) (void) +{ + int dcache_line_size = env->dcache_line_size; + + /* XXX: should be 970 specific (?) */ + if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) + dcache_line_size = 32; + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); + if (dcache_line_size >= 64) { + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0); + if (dcache_line_size >= 128) { + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x40UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x44UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x48UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x4CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x50UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x54UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x58UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x5CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x60UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x64UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x68UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x6CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x70UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x74UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x78UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x7CUL), 0); + } + } +} + +#if defined(TARGET_PPC64) +void glue(do_dcbz_64, MEMSUFFIX) (void) +{ + int dcache_line_size = env->dcache_line_size; + + /* XXX: should be 970 specific (?) */ + if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) + dcache_line_size = 32; + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); + if (dcache_line_size >= 64) { + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0); + if (dcache_line_size >= 128) { + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x40UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x44UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x48UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x4CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x50UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x54UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x58UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x5CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x60UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x64UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x68UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x6CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x70UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x74UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x78UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x7CUL), 0); + } + } } #endif diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 71dfb1e34..16d866777 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -787,7 +787,20 @@ void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void) } #endif -void OPPROTO glue(op_dcbz, MEMSUFFIX) (void) +void OPPROTO glue(op_dcbz_l32, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); + RETURN(); +} + +void OPPROTO glue(op_dcbz_l64, MEMSUFFIX) (void) { glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); @@ -797,8 +810,6 @@ void OPPROTO glue(op_dcbz, MEMSUFFIX) (void) glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); -#if DCACHE_LINE_SIZE == 64 - /* XXX: cache line size should be 64 for POWER & PowerPC 601 */ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0); @@ -807,12 +818,67 @@ void OPPROTO glue(op_dcbz, MEMSUFFIX) (void) glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0); -#endif + RETURN(); +} + +void OPPROTO glue(op_dcbz_l128, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x40UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x44UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x48UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x4CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x50UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x54UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x58UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x5CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x60UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x64UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x68UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x6CUL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x70UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x74UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x78UL), 0); + glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x7CUL), 0); + RETURN(); +} + +void OPPROTO glue(op_dcbz, MEMSUFFIX) (void) +{ + glue(do_dcbz, MEMSUFFIX)(); RETURN(); } #if defined(TARGET_PPC64) -void OPPROTO glue(op_dcbz_64, MEMSUFFIX) (void) +void OPPROTO glue(op_dcbz_l32_64, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); + RETURN(); +} + +void OPPROTO glue(op_dcbz_l64_64, MEMSUFFIX) (void) { glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); @@ -822,8 +888,6 @@ void OPPROTO glue(op_dcbz_64, MEMSUFFIX) (void) glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); -#if DCACHE_LINE_SIZE == 64 - /* XXX: cache line size should be 64 for POWER & PowerPC 601 */ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0); @@ -832,7 +896,49 @@ void OPPROTO glue(op_dcbz_64, MEMSUFFIX) (void) glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0); -#endif + RETURN(); +} + +void OPPROTO glue(op_dcbz_l128_64, MEMSUFFIX) (void) +{ + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x40UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x44UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x48UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x4CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x50UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x54UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x58UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x5CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x60UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x64UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x68UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x6CUL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x70UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x74UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x78UL), 0); + glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x7CUL), 0); + RETURN(); +} + +void OPPROTO glue(op_dcbz_64, MEMSUFFIX) (void) +{ + glue(do_dcbz_64, MEMSUFFIX)(); RETURN(); } #endif diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 5e4b12b03..77486f3b6 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -169,6 +169,7 @@ typedef struct DisasContext { #endif ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; + int dcache_line_size; } DisasContext; struct opc_handler_t { @@ -482,6 +483,10 @@ enum { PPC_WAIT = 0x0000100000000000ULL, /* New 64 bits extensions (PowerPC 2.0x) */ PPC_64BX = 0x0000200000000000ULL, + /* dcbz instruction with fixed cache line size */ + PPC_CACHE_DCBZ = 0x0000400000000000ULL, + /* dcbz instruction with tunable cache line size */ + PPC_CACHE_DCBZT = 0x0000800000000000ULL, }; /*****************************************************************************/ @@ -3623,51 +3628,178 @@ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE) } /* dcbz */ -#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() +#define op_dcbz(n) (*gen_op_dcbz[n][ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) /* User-mode only */ -static GenOpFunc *gen_op_dcbz[] = { - &gen_op_dcbz_raw, - &gen_op_dcbz_raw, +static GenOpFunc *gen_op_dcbz[4][4] = { + { + &gen_op_dcbz_l32_raw, + &gen_op_dcbz_l32_raw, #if defined(TARGET_PPC64) - &gen_op_dcbz_64_raw, - &gen_op_dcbz_64_raw, + &gen_op_dcbz_l32_64_raw, + &gen_op_dcbz_l32_64_raw, #endif + }, + { + &gen_op_dcbz_l64_raw, + &gen_op_dcbz_l64_raw, +#if defined(TARGET_PPC64) + &gen_op_dcbz_l64_64_raw, + &gen_op_dcbz_l64_64_raw, +#endif + }, + { + &gen_op_dcbz_l128_raw, + &gen_op_dcbz_l128_raw, +#if defined(TARGET_PPC64) + &gen_op_dcbz_l128_64_raw, + &gen_op_dcbz_l128_64_raw, +#endif + }, + { + &gen_op_dcbz_raw, + &gen_op_dcbz_raw, +#if defined(TARGET_PPC64) + &gen_op_dcbz_64_raw, + &gen_op_dcbz_64_raw, +#endif + }, }; #else #if defined(TARGET_PPC64) /* Full system - 64 bits mode */ -static GenOpFunc *gen_op_dcbz[] = { - &gen_op_dcbz_user, - &gen_op_dcbz_user, - &gen_op_dcbz_64_user, - &gen_op_dcbz_64_user, - &gen_op_dcbz_kernel, - &gen_op_dcbz_kernel, - &gen_op_dcbz_64_kernel, - &gen_op_dcbz_64_kernel, +static GenOpFunc *gen_op_dcbz[4][12] = { + { + &gen_op_dcbz_l32_user, + &gen_op_dcbz_l32_user, + &gen_op_dcbz_l32_64_user, + &gen_op_dcbz_l32_64_user, + &gen_op_dcbz_l32_kernel, + &gen_op_dcbz_l32_kernel, + &gen_op_dcbz_l32_64_kernel, + &gen_op_dcbz_l32_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_dcbz_l32_hypv, + &gen_op_dcbz_l32_hypv, + &gen_op_dcbz_l32_64_hypv, + &gen_op_dcbz_l32_64_hypv, +#endif + }, + { + &gen_op_dcbz_l64_user, + &gen_op_dcbz_l64_user, + &gen_op_dcbz_l64_64_user, + &gen_op_dcbz_l64_64_user, + &gen_op_dcbz_l64_kernel, + &gen_op_dcbz_l64_kernel, + &gen_op_dcbz_l64_64_kernel, + &gen_op_dcbz_l64_64_kernel, #if defined(TARGET_PPC64H) - &gen_op_dcbz_hypv, - &gen_op_dcbz_hypv, - &gen_op_dcbz_64_hypv, - &gen_op_dcbz_64_hypv, + &gen_op_dcbz_l64_hypv, + &gen_op_dcbz_l64_hypv, + &gen_op_dcbz_l64_64_hypv, + &gen_op_dcbz_l64_64_hypv, +#endif + }, + { + &gen_op_dcbz_l128_user, + &gen_op_dcbz_l128_user, + &gen_op_dcbz_l128_64_user, + &gen_op_dcbz_l128_64_user, + &gen_op_dcbz_l128_kernel, + &gen_op_dcbz_l128_kernel, + &gen_op_dcbz_l128_64_kernel, + &gen_op_dcbz_l128_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_dcbz_l128_hypv, + &gen_op_dcbz_l128_hypv, + &gen_op_dcbz_l128_64_hypv, + &gen_op_dcbz_l128_64_hypv, +#endif + }, + { + &gen_op_dcbz_user, + &gen_op_dcbz_user, + &gen_op_dcbz_64_user, + &gen_op_dcbz_64_user, + &gen_op_dcbz_kernel, + &gen_op_dcbz_kernel, + &gen_op_dcbz_64_kernel, + &gen_op_dcbz_64_kernel, +#if defined(TARGET_PPC64H) + &gen_op_dcbz_hypv, + &gen_op_dcbz_hypv, + &gen_op_dcbz_64_hypv, + &gen_op_dcbz_64_hypv, #endif + }, }; #else /* Full system - 32 bits mode */ -static GenOpFunc *gen_op_dcbz[] = { - &gen_op_dcbz_user, - &gen_op_dcbz_user, - &gen_op_dcbz_kernel, - &gen_op_dcbz_kernel, +static GenOpFunc *gen_op_dcbz[4][4] = { + { + &gen_op_dcbz_l32_user, + &gen_op_dcbz_l32_user, + &gen_op_dcbz_l32_kernel, + &gen_op_dcbz_l32_kernel, + }, + { + &gen_op_dcbz_l64_user, + &gen_op_dcbz_l64_user, + &gen_op_dcbz_l64_kernel, + &gen_op_dcbz_l64_kernel, + }, + { + &gen_op_dcbz_l128_user, + &gen_op_dcbz_l128_user, + &gen_op_dcbz_l128_kernel, + &gen_op_dcbz_l128_kernel, + }, + { + &gen_op_dcbz_user, + &gen_op_dcbz_user, + &gen_op_dcbz_kernel, + &gen_op_dcbz_kernel, + }, }; #endif #endif -GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) +static inline void handler_dcbz (DisasContext *ctx, int dcache_line_size) +{ + int n; + + switch (dcache_line_size) { + case 32: + n = 0; + break; + case 64: + n = 1; + break; + case 128: + n = 2; + break; + default: + n = 3; + break; + } + op_dcbz(n); +} + +GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ) { gen_addr_reg_index(ctx); - op_dcbz(); + handler_dcbz(ctx, ctx->dcache_line_size); + gen_op_check_reservation(); +} + +GEN_HANDLER(dcbz_970, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT) +{ + gen_addr_reg_index(ctx); + if (ctx->opcode & 0x00200000) + handler_dcbz(ctx, ctx->dcache_line_size); + else + handler_dcbz(ctx, -1); gen_op_check_reservation(); } @@ -6341,6 +6473,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, #else ctx.mem_idx = (supervisor << 1) | msr_le; #endif + ctx.dcache_line_size = env->dcache_line_size; ctx.fpu_enabled = msr_fp; #if defined(TARGET_PPCEMB) ctx.spe_enabled = msr_spe; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 355f5ad07..445cb5818 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2542,7 +2542,7 @@ static void init_excp_970 (CPUPPCState *env) /* PowerPC implementations definitions */ /* PowerPC 40x instruction set */ -#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_EMB_COMMON) +#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_CACHE_DCBZ | PPC_EMB_COMMON) /* PowerPC 401 */ #define POWERPC_INSNS_401 (POWERPC_INSNS_EMB | \ @@ -2560,8 +2560,14 @@ static void init_proc_401 (CPUPPCState *env) gen_spr_401_403(env); gen_spr_401(env); init_excp_4xx_real(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 401x2 */ @@ -2587,8 +2593,14 @@ static void init_proc_401x2 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 401x3 */ @@ -2612,8 +2624,14 @@ static void init_proc_401x3 (CPUPPCState *env) gen_spr_401x2(env); gen_spr_compress(env); init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* IOP480 */ @@ -2639,8 +2657,14 @@ static void init_proc_IOP480 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 403 */ @@ -2661,8 +2685,14 @@ static void init_proc_403 (CPUPPCState *env) gen_spr_403(env); gen_spr_403_real(env); init_excp_4xx_real(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 403 GCX */ @@ -2699,8 +2729,14 @@ static void init_proc_403GCX (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 405 */ @@ -2737,8 +2773,14 @@ static void init_proc_405 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 440 EP */ @@ -2781,7 +2823,13 @@ static void init_proc_440EP (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 440 GP */ @@ -2806,7 +2854,13 @@ static void init_proc_440GP (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 440x4 */ @@ -2832,7 +2886,13 @@ static void init_proc_440x4 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 440x5 */ @@ -2875,7 +2935,13 @@ static void init_proc_440x5 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 460 (guessed) */ @@ -2924,7 +2990,13 @@ static void init_proc_460 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 460F (guessed) */ @@ -2976,7 +3048,13 @@ static void init_proc_460F (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* Generic BookE PowerPC */ @@ -2997,6 +3075,12 @@ __attribute__ (( unused )) static void init_proc_BookE (CPUPPCState *env) { init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* e200 core */ @@ -3025,7 +3109,13 @@ static void init_proc_e500 (CPUPPCState *env) env->nb_ways = 1; env->id_tlbs = 0; init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* e600 core */ @@ -3038,7 +3128,7 @@ static void init_proc_e500 (CPUPPCState *env) #define POWERPC_INSNS_WORKS (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT | \ PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ - PPC_MEM_TLBSYNC | PPC_MFTB) + PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ | PPC_MFTB) /* POWER : same as 601, without mfmsr, mfsr */ #if defined(TODO) @@ -3048,7 +3138,8 @@ static void init_proc_e500 (CPUPPCState *env) #endif /* TODO */ /* PowerPC 601 */ -#define POWERPC_INSNS_601 (POWERPC_INSNS_6xx | PPC_EXTERN | PPC_POWER_BR) +#define POWERPC_INSNS_601 (POWERPC_INSNS_6xx | PPC_CACHE_DCBZ | \ + PPC_EXTERN | PPC_POWER_BR) #define POWERPC_MSRM_601 (0x000000000000FE70ULL) //#define POWERPC_MMU_601 (POWERPC_MMU_601) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) @@ -3091,14 +3182,21 @@ static void init_proc_601 (CPUPPCState *env) env->id_tlbs = 0; env->id_tlbs = 0; init_excp_601(env); + env->dcache_line_size = 64; + env->icache_line_size = 64; /* XXX: TODO: allocate internal IRQ controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 602 */ #define POWERPC_INSNS_602 (POWERPC_INSNS_6xx | PPC_MFTB | \ PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ - PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_602_SPEC) + PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ |\ + PPC_602_SPEC) #define POWERPC_MSRM_602 (0x000000000033FF73ULL) #define POWERPC_MMU_602 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_602 (POWERPC_EXCP_602) @@ -3126,8 +3224,14 @@ static void init_proc_602 (CPUPPCState *env) gen_low_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); init_excp_602(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 603 */ @@ -3159,8 +3263,14 @@ static void init_proc_603 (CPUPPCState *env) gen_low_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); init_excp_603(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 603e */ @@ -3197,8 +3307,14 @@ static void init_proc_603E (CPUPPCState *env) gen_low_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); init_excp_603(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC G2 */ @@ -3237,8 +3353,14 @@ static void init_proc_G2 (CPUPPCState *env) gen_high_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); init_excp_G2(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC G2LE */ @@ -3277,8 +3399,14 @@ static void init_proc_G2LE (CPUPPCState *env) gen_high_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); init_excp_G2(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 604 */ @@ -3309,8 +3437,14 @@ static void init_proc_604 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); init_excp_604(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 740/750 (aka G3) */ @@ -3343,8 +3477,14 @@ static void init_proc_7x0 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); init_excp_7x0(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 750FX/GX */ @@ -3384,8 +3524,14 @@ static void init_proc_750fx (CPUPPCState *env) /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ gen_high_BATs(env); init_excp_750FX(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 745/755 */ @@ -3433,8 +3579,14 @@ static void init_proc_7x5 (CPUPPCState *env) gen_low_BATs(env); gen_high_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 7400 (aka G4) */ @@ -3460,8 +3612,14 @@ static void init_proc_7400 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); init_excp_7400(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 7410 (aka G4) */ @@ -3499,8 +3657,14 @@ static void init_proc_7410 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); init_excp_7400(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 7440 (aka G4) */ @@ -3564,8 +3728,14 @@ static void init_proc_7440 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_74xx_soft_tlb(env, 128, 2); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 7450 (aka G4) */ @@ -3632,8 +3802,14 @@ static void init_proc_7450 (CPUPPCState *env) gen_low_BATs(env); gen_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 7445 (aka G4) */ @@ -3732,8 +3908,14 @@ static void init_proc_7445 (CPUPPCState *env) gen_high_BATs(env); gen_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } /* PowerPC 7455 (aka G4) */ @@ -3834,13 +4016,23 @@ static void init_proc_7455 (CPUPPCState *env) gen_high_BATs(env); gen_74xx_soft_tlb(env, 128, 2); init_excp_7450(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif } #if defined (TARGET_PPC64) +#define POWERPC_INSNS_WORK64 (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT | \ + PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ + PPC_MEM_TLBSYNC | PPC_CACHE_DCBZT | PPC_MFTB) /* PowerPC 970 */ -#define POWERPC_INSNS_970 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ +#define POWERPC_INSNS_970 (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ PPC_64_BRIDGE | PPC_SLBI) #define POWERPC_MSRM_970 (0x900000000204FF36ULL) @@ -3860,7 +4052,7 @@ static void init_proc_970 (CPUPPCState *env) spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_clear, - 0x00000000); + 0x60000000); /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, @@ -3878,12 +4070,18 @@ static void init_proc_970 (CPUPPCState *env) env->slb_nr = 32; #endif init_excp_970(env); + env->dcache_line_size = 128; + env->icache_line_size = 128; /* Allocate hardware IRQ controller */ ppc970_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; +#endif } /* PowerPC 970FX (aka G5) */ -#define POWERPC_INSNS_970FX (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ +#define POWERPC_INSNS_970FX (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ PPC_64_BRIDGE | PPC_SLBI) #define POWERPC_MSRM_970FX (0x800000000204FF36ULL) @@ -3903,7 +4101,7 @@ static void init_proc_970FX (CPUPPCState *env) spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_clear, - 0x00000000); + 0x60000000); /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, @@ -3914,6 +4112,11 @@ static void init_proc_970FX (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_970_HID5, "HID5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -3921,12 +4124,18 @@ static void init_proc_970FX (CPUPPCState *env) env->slb_nr = 32; #endif init_excp_970(env); + env->dcache_line_size = 128; + env->icache_line_size = 128; /* Allocate hardware IRQ controller */ ppc970_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; +#endif } /* PowerPC 970 GX */ -#define POWERPC_INSNS_970GX (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ +#define POWERPC_INSNS_970GX (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ PPC_64_BRIDGE | PPC_SLBI) #define POWERPC_MSRM_970GX (0x800000000204FF36ULL) @@ -3946,7 +4155,7 @@ static void init_proc_970GX (CPUPPCState *env) spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_clear, - 0x00000000); + 0x60000000); /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, @@ -3957,6 +4166,11 @@ static void init_proc_970GX (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_970_HID5, "HID5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -3964,8 +4178,14 @@ static void init_proc_970GX (CPUPPCState *env) env->slb_nr = 32; #endif init_excp_970(env); + env->dcache_line_size = 128; + env->icache_line_size = 128; /* Allocate hardware IRQ controller */ ppc970_irq_init(env); +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; +#endif } /* PowerPC 620 */ @@ -3994,7 +4214,13 @@ static void init_proc_620 (CPUPPCState *env) gen_low_BATs(env); gen_high_BATs(env); init_excp_620(env); + env->dcache_line_size = 64; + env->icache_line_size = 64; /* XXX: TODO: initialize internal interrupt controller */ +#if !defined(CONFIG_USER_ONLY) + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; /* ? */ +#endif } #endif /* defined (TARGET_PPC64) */ -- cgit v1.2.3 From e57448f11cb29c9b36acd117349070fe290465fa Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 4 Oct 2007 01:50:03 +0000 Subject: More cache tuning fixes: * fix the tunable cache line size probe for PowerPC 970. * initialize HID5 so cache line is 32 bytes long when running in user-mode only git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3322 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper_mem.h | 2 +- target-ppc/translate_init.c | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index f5cb6970c..4b0bb841e 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -324,7 +324,7 @@ void glue(do_dcbz_64, MEMSUFFIX) (void) int dcache_line_size = env->dcache_line_size; /* XXX: should be 970 specific (?) */ - if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) + if (((env->spr[SPR_970_HID5] >> 6) & 0x3) == 0x2) dcache_line_size = 32; glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 445cb5818..606a04f25 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4063,6 +4063,16 @@ static void init_proc_970 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_970_HID5, "HID5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, +#if defined(CONFIG_USER_ONLY) + 0x00000080 +#else + 0x00000000 +#endif + ); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -4116,7 +4126,12 @@ static void init_proc_970FX (CPUPPCState *env) spr_register(env, SPR_970_HID5, "HID5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0x00000000); +#if defined(CONFIG_USER_ONLY) + 0x00000080 +#else + 0x00000000 +#endif + ); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -4170,7 +4185,12 @@ static void init_proc_970GX (CPUPPCState *env) spr_register(env, SPR_970_HID5, "HID5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0x00000000); +#if defined(CONFIG_USER_ONLY) + 0x00000080 +#else + 0x00000000 +#endif + ); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); -- cgit v1.2.3 From 1cc8e6f067f9048556af1d1863271db55b15efc1 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 4 Oct 2007 01:54:44 +0000 Subject: We must reset the PowerPC CPU _after_ registering it, as hardware reset effect is implementation dependant. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3323 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405_uc.c | 6 ++++-- linux-user/main.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index b6fc491ae..8a31475ed 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -51,20 +51,22 @@ CPUState *ppc405_init (const unsigned char *cpu_model, /* init CPUs */ env = cpu_init(); - qemu_register_reset(&cpu_ppc_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); ppc_find_by_name(cpu_model, &def); if (def == NULL) { cpu_abort(env, "Unable to find PowerPC %s CPU definition\n", cpu_model); } cpu_ppc_register(env, def); + cpu_ppc_reset(env); cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ cpu_clk->opaque = env; /* Set time-base frequency to sysclk */ tb_clk->cb = ppc_emb_timers_init(env, sysclk); tb_clk->opaque = env; ppc_dcr_init(env, NULL, NULL); + /* Register Qemu callbacks */ + qemu_register_reset(&cpu_ppc_reset, env); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); return env; } diff --git a/linux-user/main.c b/linux-user/main.c index af99d0455..9c3d67d49 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2100,7 +2100,7 @@ int main(int argc, char **argv) "Unable to find PowerPC CPU definition\n"); } cpu_ppc_register(env, def); - + cpu_ppc_reset(env); for (i = 0; i < 32; i++) { if (i != 12 && i != 6 && i != 13) env->msr[i] = (regs->msr >> i) & 1; -- cgit v1.2.3 From 2b76bdc965ba7b4f27133cb345101d9535ddaa79 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 4 Oct 2007 19:41:17 +0000 Subject: Several corrections in the spitzkbd keymap (patch by Juergen Lock). Don't abort on illegal GPSR reads, instead only warn. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3324 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx_gpio.c | 7 +++++++ hw/spitz.c | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 85aeb50cc..723b1c1d0 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -24,6 +24,7 @@ struct pxa2xx_gpio_info_s { uint32_t rising[PXA2XX_GPIO_BANKS]; uint32_t falling[PXA2XX_GPIO_BANKS]; uint32_t status[PXA2XX_GPIO_BANKS]; + uint32_t gpsr[PXA2XX_GPIO_BANKS]; uint32_t gafr[PXA2XX_GPIO_BANKS * 2]; uint32_t prev_level[PXA2XX_GPIO_BANKS]; @@ -152,6 +153,11 @@ static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset) case GPDR: /* GPIO Pin-Direction registers */ return s->dir[bank]; + case GPSR: /* GPIO Pin-Output Set registers */ + printf("%s: Read from a write-only register " REG_FMT "\n", + __FUNCTION__, offset); + return s->gpsr[bank]; /* Return last written value. */ + case GRER: /* GPIO Rising-Edge Detect Enable registers */ return s->rising[bank]; @@ -201,6 +207,7 @@ static void pxa2xx_gpio_write(void *opaque, case GPSR: /* GPIO Pin-Output Set registers */ s->olevel[bank] |= value; pxa2xx_gpio_handler_update(s); + s->gpsr[bank] = value; break; case GPCR: /* GPIO Pin-Output Clear registers */ diff --git a/hw/spitz.c b/hw/spitz.c index 540e1b206..aca244ee2 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -194,8 +194,8 @@ static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = { { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 }, { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 }, { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 }, - { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x3d }, - { 0x37, 0x38, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 }, + { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x38 }, + { 0x37, 0x3d, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 }, { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 }, }; @@ -415,13 +415,17 @@ static void spitz_keyboard_pre_map(struct spitz_keyboard_s *s) s->pre_map[0x0d | SHIFT ] = 0x13 | FN; /* plus */ s->pre_map[0x1a ] = 0x14 | FN; /* bracketleft */ s->pre_map[0x1b ] = 0x15 | FN; /* bracketright */ + s->pre_map[0x1a | SHIFT ] = 0x16 | FN; /* braceleft */ + s->pre_map[0x1b | SHIFT ] = 0x17 | FN; /* braceright */ s->pre_map[0x27 ] = 0x22 | FN; /* semicolon */ s->pre_map[0x27 | SHIFT ] = 0x23 | FN; /* colon */ s->pre_map[0x09 | SHIFT ] = 0x24 | FN; /* asterisk */ s->pre_map[0x2b ] = 0x25 | FN; /* backslash */ s->pre_map[0x2b | SHIFT ] = 0x26 | FN; /* bar */ s->pre_map[0x0c | SHIFT ] = 0x30 | FN; /* underscore */ + s->pre_map[0x33 | SHIFT ] = 0x33 | FN; /* less */ s->pre_map[0x35 ] = 0x33 | SHIFT; /* slash */ + s->pre_map[0x34 | SHIFT ] = 0x34 | FN; /* greater */ s->pre_map[0x35 | SHIFT ] = 0x34 | SHIFT; /* question */ s->pre_map[0x49 ] = 0x48 | FN; /* Page_Up */ s->pre_map[0x51 ] = 0x50 | FN; /* Page_Down */ -- cgit v1.2.3 From 49a9b72568cddc0586468e888cd6ac6d9c97ed35 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 4 Oct 2007 19:47:09 +0000 Subject: (int64_t)UINT64_MAX is -1 and should not be assigned to nearest_delta_us, patch by Dan Kenigsberg. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3325 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 46ce9008d..c34f9590c 100644 --- a/vl.c +++ b/vl.c @@ -1181,7 +1181,7 @@ static void host_alarm_handler(int host_signum) static uint64_t qemu_next_deadline(void) { - int64_t nearest_delta_us = UINT64_MAX; + int64_t nearest_delta_us = INT64_MAX; int64_t vmdelta_us; if (active_timers[QEMU_TIMER_REALTIME]) -- cgit v1.2.3 From 30d6eaca96a4f9fd93e42267dceff70d421d6f9e Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 4 Oct 2007 19:59:04 +0000 Subject: Remove redundant qemu_rearm_alarm_timer() in qemu_del_timer, patch by Dan Kenigsberg. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3326 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/vl.c b/vl.c index c34f9590c..ebd5dbf20 100644 --- a/vl.c +++ b/vl.c @@ -988,8 +988,6 @@ void qemu_del_timer(QEMUTimer *ts) } pt = &t->next; } - - qemu_rearm_alarm_timer(alarm_timer); } /* modify the current timer so that it will be fired when current_time -- cgit v1.2.3 From 80f515e63688f43b7800027c233ec7139cf3375b Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 4 Oct 2007 21:53:55 +0000 Subject: sh775x interrupt controller by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3327 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/sh7750.c | 223 ++++++++++++++++++++++++------ hw/sh7750_regnames.c | 3 - hw/sh7750_regs.h | 42 ------ hw/sh_intc.c | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/sh_intc.h | 69 ++++++++++ 6 files changed, 631 insertions(+), 91 deletions(-) create mode 100644 hw/sh_intc.c create mode 100644 hw/sh_intc.h diff --git a/Makefile.target b/Makefile.target index 9b0459ec1..58219ba97 100644 --- a/Makefile.target +++ b/Makefile.target @@ -484,7 +484,7 @@ CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o -VL_OBJS+= sh_timer.o ptimer.o sh_serial.o +VL_OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o endif ifeq ($(TARGET_BASE_ARCH), m68k) VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o diff --git a/hw/sh7750.c b/hw/sh7750.c index bd3d31e36..4b2b515b7 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -1,6 +1,7 @@ /* * SH7750 device * + * Copyright (c) 2007 Magnus Damm * Copyright (c) 2005 Samuel Tardieu * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,6 +27,7 @@ #include "vl.h" #include "sh7750_regs.h" #include "sh7750_regnames.h" +#include "sh_intc.h" #define NB_DEVICES 4 @@ -53,15 +55,10 @@ typedef struct SH7750State { sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ uint16_t icr; - uint16_t ipra; - uint16_t iprb; - uint16_t iprc; - uint16_t iprd; - uint32_t intpri00; - uint32_t intmsk00; /* Cache */ uint32_t ccr; + struct intc_desc intc; } SH7750State; @@ -219,14 +216,6 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) return portb_lines(s); case 0x1fd00000: return s->icr; - case 0x1fd00004: - return s->ipra; - case 0x1fd00008: - return s->iprb; - case 0x1fd0000c: - return s->iprc; - case 0x1fd00010: - return s->iprd; default: error_access("word read", addr); assert(0); @@ -262,14 +251,6 @@ static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) return 0x00110000; /* Minimum caches */ case 0x1f000044: /* Processor version PRR */ return 0x00000100; /* SH7750R */ - case 0x1e080000: - return s->intpri00; - case 0x1e080020: - return 0; - case 0x1e080040: - return s->intmsk00; - case 0x1e080060: - return 0; default: error_access("long read", addr); assert(0); @@ -331,18 +312,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, case 0x1fd00000: s->icr = mem_value; return; - case 0x1fd00004: - s->ipra = mem_value; - return; - case 0x1fd00008: - s->iprb = mem_value; - return; - case 0x1fd0000c: - s->iprc = mem_value; - return; - case 0x1fd00010: - s->iprd = mem_value; - return; default: error_access("word write", addr); assert(0); @@ -407,16 +376,6 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, case SH7750_CCR_A7: s->ccr = mem_value; return; - case 0x1e080000: - s->intpri00 = mem_value; - return; - case 0x1e080020: - return; - case 0x1e080040: - s->intmsk00 = mem_value; - return; - case 0x1e080060: - return; default: error_access("long write", addr); assert(0); @@ -435,10 +394,144 @@ static CPUWriteMemoryFunc *sh7750_mem_write[] = { sh7750_mem_writel }; +/* sh775x interrupt controller tables for sh_intc.c + * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c + */ + +enum { + UNUSED = 0, + + /* interrupt sources */ + IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */ + HUDI, GPIOI, + DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, + DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, + DMAC_DMAE, + PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3, + TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, + RTC_ATI, RTC_PRI, RTC_CUI, + SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI, + SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI, + WDT, + REF_RCMI, REF_ROVI, + + /* interrupt groups */ + DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF, + + NR_SOURCES, +}; + +static struct intc_vect vectors[] = { + INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), + INTC_VECT(RTC_CUI, 0x4c0), + INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500), + INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540), + INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720), + INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760), + INTC_VECT(WDT, 0x560), + INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), +}; + +static struct intc_group groups[] = { + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), + INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI), + INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI), + INTC_GROUP(REF, REF_RCMI, REF_ROVI), +}; + +static struct intc_prio_reg prio_registers[] = { + { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, + { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, + { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, + { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, + TMU4, TMU3, + PCIC1, PCIC0_PCISERR } }, +}; + +/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */ + +static struct intc_vect vectors_dma4[] = { + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), + INTC_VECT(DMAC_DMAE, 0x6c0), +}; + +static struct intc_group groups_dma4[] = { + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, + DMAC_DMTE3, DMAC_DMAE), +}; + +/* SH7750R and SH7751R both have 8-channel DMA controllers */ + +static struct intc_vect vectors_dma8[] = { + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), + INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0), + INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0), + INTC_VECT(DMAC_DMAE, 0x6c0), +}; + +static struct intc_group groups_dma8[] = { + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, + DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5, + DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE), +}; + +/* SH7750R, SH7751 and SH7751R all have two extra timer channels */ + +static struct intc_vect vectors_tmu34[] = { + INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80), +}; + +static struct intc_mask_reg mask_registers[] = { + { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, TMU4, TMU3, + PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, + PCIC1_PCIDMA3, PCIC0_PCISERR } }, +}; + +/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */ + +static struct intc_vect vectors_irlm[] = { + INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0), + INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360), +}; + +/* SH7751 and SH7751R both have PCI */ + +static struct intc_vect vectors_pci[] = { + INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0), + INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0), + INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60), + INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20), +}; + +static struct intc_group groups_pci[] = { + INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3), +}; + +#define SH_CPU_SH7750 (1 << 0) +#define SH_CPU_SH7750S (1 << 1) +#define SH_CPU_SH7750R (1 << 2) +#define SH_CPU_SH7751 (1 << 3) +#define SH_CPU_SH7751R (1 << 4) +#define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R) +#define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R) + SH7750State *sh7750_init(CPUSH4State * cpu) { SH7750State *s; int sh7750_io_memory; + int cpu_model = SH_CPU_SH7751R; /* for now */ s = qemu_mallocz(sizeof(SH7750State)); s->cpu = cpu; @@ -448,6 +541,14 @@ SH7750State *sh7750_init(CPUSH4State * cpu) sh7750_mem_write, s); cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); + sh_intc_init(&s->intc, NR_SOURCES, + _INTC_ARRAY(mask_registers), + _INTC_ARRAY(prio_registers)); + + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors), + _INTC_ARRAY(groups)); + sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]); sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF, s->periph_freq, serial_hds[1]); @@ -455,6 +556,38 @@ SH7750State *sh7750_init(CPUSH4State * cpu) tmu012_init(0x1fd80000, TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, s->periph_freq); - tmu012_init(0x1e100000, 0, s->periph_freq); + + + if (cpu_model & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_dma4), + _INTC_ARRAY(groups_dma4)); + } + + if (cpu_model & (SH_CPU_SH7750R | SH_CPU_SH7751R)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_dma8), + _INTC_ARRAY(groups_dma8)); + } + + if (cpu_model & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_tmu34), + _INTC_ARRAY(NULL)); + tmu012_init(0x1e100000, 0, s->periph_freq); + } + + if (cpu_model & (SH_CPU_SH7751_ALL)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_pci), + _INTC_ARRAY(groups_pci)); + } + + if (cpu_model & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) { + sh_intc_register_sources(&s->intc, + _INTC_ARRAY(vectors_irlm), + _INTC_ARRAY(NULL)); + } + return s; } diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c index 84d5c1a2e..551ce8057 100644 --- a/hw/sh7750_regnames.c +++ b/hw/sh7750_regnames.c @@ -76,9 +76,6 @@ static regname_t regnames[] = { REGNAME(SH7750_PDTRB_A7) REGNAME(SH7750_GPIOIC_A7) REGNAME(SH7750_ICR_A7) - REGNAME(SH7750_IPRA_A7) - REGNAME(SH7750_IPRB_A7) - REGNAME(SH7750_IPRC_A7) REGNAME(SH7750_BCR3_A7) REGNAME(SH7750_BCR4_A7) REGNAME(SH7750_PRECHARGE0_A7) diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h index 15b27690d..c8fb32810 100644 --- a/hw/sh7750_regs.h +++ b/hw/sh7750_regs.h @@ -1241,48 +1241,6 @@ #define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent interrupt requests */ -/* Interrupt Priority Register A - IPRA (half) */ -#define SH7750_IPRA_REGOFS 0xD00004 /* offset */ -#define SH7750_IPRA SH7750_P4_REG32(SH7750_IPRA_REGOFS) -#define SH7750_IPRA_A7 SH7750_A7_REG32(SH7750_IPRA_REGOFS) - -#define SH7750_IPRA_TMU0 0xF000 /* TMU0 interrupt priority */ -#define SH7750_IPRA_TMU0_S 12 -#define SH7750_IPRA_TMU1 0x0F00 /* TMU1 interrupt priority */ -#define SH7750_IPRA_TMU1_S 8 -#define SH7750_IPRA_TMU2 0x00F0 /* TMU2 interrupt priority */ -#define SH7750_IPRA_TMU2_S 4 -#define SH7750_IPRA_RTC 0x000F /* RTC interrupt priority */ -#define SH7750_IPRA_RTC_S 0 - -/* Interrupt Priority Register B - IPRB (half) */ -#define SH7750_IPRB_REGOFS 0xD00008 /* offset */ -#define SH7750_IPRB SH7750_P4_REG32(SH7750_IPRB_REGOFS) -#define SH7750_IPRB_A7 SH7750_A7_REG32(SH7750_IPRB_REGOFS) - -#define SH7750_IPRB_WDT 0xF000 /* WDT interrupt priority */ -#define SH7750_IPRB_WDT_S 12 -#define SH7750_IPRB_REF 0x0F00 /* Memory Refresh unit interrupt - priority */ -#define SH7750_IPRB_REF_S 8 -#define SH7750_IPRB_SCI1 0x00F0 /* SCI1 interrupt priority */ -#define SH7750_IPRB_SCI1_S 4 - -/* Interrupt Priority Register - IPR (half) */ -#define SH7750_IPRC_REGOFS 0xD00004 /* offset */ -#define SH7750_IPRC SH7750_P4_REG32(SH7750_IPRC_REGOFS) -#define SH7750_IPRC_A7 SH7750_A7_REG32(SH7750_IPRC_REGOFS) - -#define SH7750_IPRC_GPIO 0xF000 /* GPIO interrupt priority */ -#define SH7750_IPRC_GPIO_S 12 -#define SH7750_IPRC_DMAC 0x0F00 /* DMAC interrupt priority */ -#define SH7750_IPRC_DMAC_S 8 -#define SH7750_IPRC_SCIF 0x00F0 /* SCIF interrupt priority */ -#define SH7750_IPRC_SCIF_S 4 -#define SH7750_IPRC_HUDI 0x000F /* H-UDI interrupt priority */ -#define SH7750_IPRC_HUDI_S 0 - - /* * User Break Controller registers */ diff --git a/hw/sh_intc.c b/hw/sh_intc.c new file mode 100644 index 000000000..7e8f16782 --- /dev/null +++ b/hw/sh_intc.c @@ -0,0 +1,383 @@ +/* + * SuperH interrupt controller module + * + * Copyright (c) 2007 Magnus Damm + * Based on sh_timer.c and arm_timer.c by Paul Brook + * Copyright (c) 2005-2006 CodeSourcery. + * + * This code is licenced under the GPL. + */ + +#include +#include "sh_intc.h" +#include "vl.h" + +//#define DEBUG_INTC + +#define INTC_A7(x) ((x) & 0x1fffffff) +#define INTC_ARRAY(x) (sizeof(x) / sizeof(x[0])) + +#define INTC_MODE_NONE 0 +#define INTC_MODE_DUAL_SET 1 +#define INTC_MODE_DUAL_CLR 2 +#define INTC_MODE_ENABLE_REG 3 +#define INTC_MODE_MASK_REG 4 +#define INTC_MODE_IS_PRIO 8 + +static unsigned int sh_intc_mode(unsigned long address, + unsigned long set_reg, unsigned long clr_reg) +{ + if ((address != INTC_A7(set_reg)) && + (address != INTC_A7(clr_reg))) + return INTC_MODE_NONE; + + if (set_reg && clr_reg) { + if (address == INTC_A7(set_reg)) + return INTC_MODE_DUAL_SET; + else + return INTC_MODE_DUAL_CLR; + } + + if (set_reg) + return INTC_MODE_ENABLE_REG; + else + return INTC_MODE_MASK_REG; +} + +static void sh_intc_locate(struct intc_desc *desc, + unsigned long address, + unsigned long **datap, + intc_enum **enums, + unsigned int *first, + unsigned int *width, + unsigned int *modep) +{ + unsigned int i, mode; + + /* this is slow but works for now */ + + if (desc->mask_regs) { + for (i = 0; i < desc->nr_mask_regs; i++) { + struct intc_mask_reg *mr = desc->mask_regs + i; + + mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg); + if (mode == INTC_MODE_NONE) + continue; + + *modep = mode; + *datap = &mr->value; + *enums = mr->enum_ids; + *first = mr->reg_width - 1; + *width = 1; + return; + } + } + + if (desc->prio_regs) { + for (i = 0; i < desc->nr_prio_regs; i++) { + struct intc_prio_reg *pr = desc->prio_regs + i; + + mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg); + if (mode == INTC_MODE_NONE) + continue; + + *modep = mode | INTC_MODE_IS_PRIO; + *datap = &pr->value; + *enums = pr->enum_ids; + *first = (pr->reg_width / pr->field_width) - 1; + *width = pr->field_width; + return; + } + } + + assert(0); +} + +static void sh_intc_toggle(struct intc_desc *desc, intc_enum id, + int enable, int is_group) +{ + struct intc_source *source = desc->sources + id; + int old = source->enable_count; + + if (!id) + return; + + if (!source->next_enum_id && (!source->enable_max || !source->vect)) { +#ifdef DEBUG_INTC + printf("sh_intc: reserved interrupt source %d modified\n", id); +#endif + return; + } + + if (source->vect) { + if (enable) + source->enable_count++; + else + source->enable_count--; + + if (source->enable_count == source->enable_max) { +#ifdef DEBUG_INTC + printf("sh_intc: enabling interrupt source %d -> 0x%04x\n", + id, source->vect); +#endif + } + + if (old == source->enable_max) { +#ifdef DEBUG_INTC + printf("sh_intc: disabling interrupt source %d -> 0x%04x\n", + id, source->vect); +#endif + } + } +#ifdef DEBUG_INTC + else { + printf("setting interrupt group %d to %d\n", id, !!enable); + } +#endif + + if ((is_group || !source->vect) && source->next_enum_id) { + sh_intc_toggle(desc, source->next_enum_id, enable, 1); + } + +#ifdef DEBUG_INTC + if (!source->vect) { + printf("setting interrupt group %d to %d - done\n", id, !!enable); + } +#endif +} + +static uint32_t sh_intc_read(void *opaque, target_phys_addr_t offset) +{ + struct intc_desc *desc = opaque; + intc_enum *enum_ids = NULL; + unsigned int first = 0; + unsigned int width = 0; + unsigned int mode = 0; + unsigned long *valuep; + +#ifdef DEBUG_INTC + printf("sh_intc_read 0x%lx\n", (unsigned long) offset); +#endif + + sh_intc_locate(desc, (unsigned long)offset, &valuep, + &enum_ids, &first, &width, &mode); + return *valuep; +} + +static void sh_intc_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + struct intc_desc *desc = opaque; + intc_enum *enum_ids = NULL; + unsigned int first = 0; + unsigned int width = 0; + unsigned int mode = 0; + unsigned int k; + unsigned long *valuep; + unsigned long mask; + +#ifdef DEBUG_INTC + printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value); +#endif + + sh_intc_locate(desc, (unsigned long)offset, &valuep, + &enum_ids, &first, &width, &mode); + + switch (mode) { + case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break; + case INTC_MODE_DUAL_SET: value |= *valuep; break; + case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break; + default: assert(0); + } + + for (k = 0; k <= first; k++) { + mask = ((1 << width) - 1) << ((first - k) * width); + + if ((*valuep & mask) == (value & mask)) + continue; +#if 0 + printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", + k, first, enum_ids[k], (unsigned int)mask); +#endif + sh_intc_toggle(desc, enum_ids[k], value & mask, 0); + } + + *valuep = value; + +#ifdef DEBUG_INTC + printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value); +#endif +} + +static CPUReadMemoryFunc *sh_intc_readfn[] = { + sh_intc_read, + sh_intc_read, + sh_intc_read +}; + +static CPUWriteMemoryFunc *sh_intc_writefn[] = { + sh_intc_write, + sh_intc_write, + sh_intc_write +}; + +struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id) +{ + if (id) + return desc->sources + id; + + return NULL; +} + +static void sh_intc_register(struct intc_desc *desc, + unsigned long address) +{ + if (address) + cpu_register_physical_memory(INTC_A7(address), 4, desc->iomemtype); +} + +static void sh_intc_register_source(struct intc_desc *desc, + intc_enum source, + struct intc_group *groups, + int nr_groups) +{ + unsigned int i, k; + struct intc_source *s; + + if (desc->mask_regs) { + for (i = 0; i < desc->nr_mask_regs; i++) { + struct intc_mask_reg *mr = desc->mask_regs + i; + + for (k = 0; k < INTC_ARRAY(mr->enum_ids); k++) { + if (mr->enum_ids[k] != source) + continue; + + s = sh_intc_source(desc, mr->enum_ids[k]); + if (s) + s->enable_max++; + } + } + } + + if (desc->prio_regs) { + for (i = 0; i < desc->nr_prio_regs; i++) { + struct intc_prio_reg *pr = desc->prio_regs + i; + + for (k = 0; k < INTC_ARRAY(pr->enum_ids); k++) { + if (pr->enum_ids[k] != source) + continue; + + s = sh_intc_source(desc, pr->enum_ids[k]); + if (s) + s->enable_max++; + } + } + } + + if (groups) { + for (i = 0; i < nr_groups; i++) { + struct intc_group *gr = groups + i; + + for (k = 0; k < INTC_ARRAY(gr->enum_ids); k++) { + if (gr->enum_ids[k] != source) + continue; + + s = sh_intc_source(desc, gr->enum_ids[k]); + if (s) + s->enable_max++; + } + } + } + +} + +void sh_intc_register_sources(struct intc_desc *desc, + struct intc_vect *vectors, + int nr_vectors, + struct intc_group *groups, + int nr_groups) +{ + unsigned int i, k; + struct intc_source *s; + + for (i = 0; i < nr_vectors; i++) { + struct intc_vect *vect = vectors + i; + + sh_intc_register_source(desc, vect->enum_id, groups, nr_groups); + s = sh_intc_source(desc, vect->enum_id); + if (s) + s->vect = vect->vect; + +#ifdef DEBUG_INTC + printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n", + vect->enum_id, s->vect, s->enable_count, s->enable_max); +#endif + } + + if (groups) { + for (i = 0; i < nr_groups; i++) { + struct intc_group *gr = groups + i; + + s = sh_intc_source(desc, gr->enum_id); + s->next_enum_id = gr->enum_ids[0]; + + for (k = 1; k < INTC_ARRAY(gr->enum_ids); k++) { + if (!gr->enum_ids[k]) + continue; + + s = sh_intc_source(desc, gr->enum_ids[k - 1]); + s->next_enum_id = gr->enum_ids[k]; + } + +#ifdef DEBUG_INTC + printf("sh_intc: registered group %d (%d/%d)\n", + gr->enum_id, s->enable_count, s->enable_max); +#endif + } + } +} + +int sh_intc_init(struct intc_desc *desc, + int nr_sources, + struct intc_mask_reg *mask_regs, + int nr_mask_regs, + struct intc_prio_reg *prio_regs, + int nr_prio_regs) +{ + unsigned int i; + + desc->nr_sources = nr_sources; + desc->mask_regs = mask_regs; + desc->nr_mask_regs = nr_mask_regs; + desc->prio_regs = prio_regs; + desc->nr_prio_regs = nr_prio_regs; + + i = sizeof(struct intc_source) * nr_sources; + desc->sources = malloc(i); + if (!desc->sources) + return -1; + + memset(desc->sources, 0, i); + + desc->iomemtype = cpu_register_io_memory(0, sh_intc_readfn, + sh_intc_writefn, desc); + if (desc->mask_regs) { + for (i = 0; i < desc->nr_mask_regs; i++) { + struct intc_mask_reg *mr = desc->mask_regs + i; + + sh_intc_register(desc, mr->set_reg); + sh_intc_register(desc, mr->clr_reg); + } + } + + if (desc->prio_regs) { + for (i = 0; i < desc->nr_prio_regs; i++) { + struct intc_prio_reg *pr = desc->prio_regs + i; + + sh_intc_register(desc, pr->set_reg); + sh_intc_register(desc, pr->clr_reg); + } + } + + return 0; +} diff --git a/hw/sh_intc.h b/hw/sh_intc.h new file mode 100644 index 000000000..991e991f9 --- /dev/null +++ b/hw/sh_intc.h @@ -0,0 +1,69 @@ +#ifndef __SH_INTC_H__ +#define __SH_INTC_H__ + +typedef unsigned char intc_enum; + +struct intc_vect { + intc_enum enum_id; + unsigned short vect; +}; + +#define INTC_VECT(enum_id, vect) { enum_id, vect } + +struct intc_group { + intc_enum enum_id; + intc_enum enum_ids[32]; +}; + +#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } } + +struct intc_mask_reg { + unsigned long set_reg, clr_reg, reg_width; + intc_enum enum_ids[32]; + unsigned long value; +}; + +struct intc_prio_reg { + unsigned long set_reg, clr_reg, reg_width, field_width; + intc_enum enum_ids[16]; + unsigned long value; +}; + +#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a) + +struct intc_source { + unsigned short vect; + intc_enum next_enum_id; + + int asserted; + int enable_count; + int enable_max; +}; + +struct intc_desc { + struct intc_source *sources; + int nr_sources; + struct intc_mask_reg *mask_regs; + int nr_mask_regs; + struct intc_prio_reg *prio_regs; + int nr_prio_regs; + + int iomemtype; +}; + +struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id); + +void sh_intc_register_sources(struct intc_desc *desc, + struct intc_vect *vectors, + int nr_vectors, + struct intc_group *groups, + int nr_groups); + +int sh_intc_init(struct intc_desc *desc, + int nr_sources, + struct intc_mask_reg *mask_regs, + int nr_mask_regs, + struct intc_prio_reg *prio_regs, + int nr_prio_regs); + +#endif /* __SH_INTC_H__ */ -- cgit v1.2.3 From b9dc033c0dea8e1113110a903799c5b31bb2104d Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 4 Oct 2007 22:47:34 +0000 Subject: USB iso transfers support for the linux redirector and for UHCI, by Arnon Gilboa. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3328 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 146 ++++++++++++--- usb-linux.c | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 621 insertions(+), 89 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 58674098e..95dd4a0cd 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -25,6 +25,7 @@ //#define DEBUG //#define DEBUG_PACKET +//#define DEBUG_ISOCH #define UHCI_CMD_FGR (1 << 4) #define UHCI_CMD_EGSM (1 << 3) @@ -88,6 +89,7 @@ typedef struct UHCIState { other queues will not be processed until the next frame. The solution is to allow multiple pending requests. */ uint32_t async_qh; + uint32_t async_frame_addr; USBPacket usb_packet; uint8_t usb_buf[2048]; } UHCIState; @@ -146,6 +148,58 @@ static void uhci_reset(UHCIState *s) } } +static void uhci_save(QEMUFile *f, void *opaque) +{ + UHCIState *s = opaque; + uint8_t num_ports = NB_PORTS; + int i; + + pci_device_save(&s->dev, f); + + qemu_put_8s(f, &num_ports); + for (i = 0; i < num_ports; ++i) + qemu_put_be16s(f, &s->ports[i].ctrl); + qemu_put_be16s(f, &s->cmd); + qemu_put_be16s(f, &s->status); + qemu_put_be16s(f, &s->intr); + qemu_put_be16s(f, &s->frnum); + qemu_put_be32s(f, &s->fl_base_addr); + qemu_put_8s(f, &s->sof_timing); + qemu_put_8s(f, &s->status2); + qemu_put_timer(f, s->frame_timer); +} + +static int uhci_load(QEMUFile *f, void *opaque, int version_id) +{ + UHCIState *s = opaque; + uint8_t num_ports; + int i, ret; + + if (version_id > 1) + return -EINVAL; + + ret = pci_device_load(&s->dev, f); + if (ret < 0) + return ret; + + qemu_get_8s(f, &num_ports); + if (num_ports != NB_PORTS) + return -EINVAL; + + for (i = 0; i < num_ports; ++i) + qemu_get_be16s(f, &s->ports[i].ctrl); + qemu_get_be16s(f, &s->cmd); + qemu_get_be16s(f, &s->status); + qemu_get_be16s(f, &s->intr); + qemu_get_be16s(f, &s->frnum); + qemu_get_be32s(f, &s->fl_base_addr); + qemu_get_8s(f, &s->sof_timing); + qemu_get_8s(f, &s->status2); + qemu_get_timer(f, s->frame_timer); + + return 0; +} + static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) { UHCIState *s = opaque; @@ -449,10 +503,11 @@ static void uhci_async_complete_packet(USBPacket * packet, void *opaque); 0 if TD successful 1 if TD unsuccessful or inactive */ -static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) +static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask, + int completion) { uint8_t pid; - int len, max_len, err, ret; + int len = 0, max_len, err, ret = 0; /* ??? This is wrong for async completion. */ if (td->ctrl & TD_CTRL_IOC) { @@ -465,7 +520,8 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) /* TD is active */ max_len = ((td->token >> 21) + 1) & 0x7ff; pid = td->token & 0xff; - if (s->async_qh) { + + if (completion && (s->async_qh || s->async_frame_addr)) { ret = s->usb_packet.len; if (ret >= 0) { len = ret; @@ -481,7 +537,8 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) len = 0; } s->async_qh = 0; - } else { + s->async_frame_addr = 0; + } else if (!completion) { s->usb_packet.pid = pid; s->usb_packet.devaddr = (td->token >> 8) & 0x7f; s->usb_packet.devep = (td->token >> 15) & 0xf; @@ -519,6 +576,7 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) return -1; } } + if (ret == USB_RET_ASYNC) { return 2; } @@ -584,8 +642,42 @@ static void uhci_async_complete_packet(USBPacket * packet, void *opaque) uint32_t link; uint32_t old_td_ctrl; uint32_t val; + uint32_t frame_addr; int ret; + /* Handle async isochronous packet completion */ + frame_addr = s->async_frame_addr; + if (frame_addr) { + cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); + le32_to_cpus(&link); + + cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td)); + le32_to_cpus(&td.link); + le32_to_cpus(&td.ctrl); + le32_to_cpus(&td.token); + le32_to_cpus(&td.buffer); + old_td_ctrl = td.ctrl; + ret = uhci_handle_td(s, &td, &s->pending_int_mask, 1); + + /* update the status bits of the TD */ + if (old_td_ctrl != td.ctrl) { + val = cpu_to_le32(td.ctrl); + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, + sizeof(val)); + } + if (ret == 2) { + s->async_frame_addr = frame_addr; + } else if (ret == 0) { + /* update qh element link */ + val = cpu_to_le32(td.link); + cpu_physical_memory_write(frame_addr, + (const uint8_t *)&val, + sizeof(val)); + } + return; + } + link = s->async_qh; if (!link) { /* This should never happen. It means a TD somehow got removed @@ -604,7 +696,8 @@ static void uhci_async_complete_packet(USBPacket * packet, void *opaque) le32_to_cpus(&td.token); le32_to_cpus(&td.buffer); old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &s->pending_int_mask); + ret = uhci_handle_td(s, &td, &s->pending_int_mask, 1); + /* update the status bits of the TD */ if (old_td_ctrl != td.ctrl) { val = cpu_to_le32(td.ctrl); @@ -697,7 +790,8 @@ static void uhci_frame_timer(void *opaque) le32_to_cpus(&td.token); le32_to_cpus(&td.buffer); old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &int_mask); + ret = uhci_handle_td(s, &td, &int_mask, 0); + /* update the status bits of the TD */ if (old_td_ctrl != td.ctrl) { val = cpu_to_le32(td.ctrl); @@ -731,27 +825,23 @@ static void uhci_frame_timer(void *opaque) le32_to_cpus(&td.ctrl); le32_to_cpus(&td.token); le32_to_cpus(&td.buffer); - /* Ignore isochonous transfers while there is an async packet - pending. This is wrong, but we don't implement isochronous - transfers anyway. */ - if (s->async_qh == 0) { - old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &int_mask); - /* update the status bits of the TD */ - if (old_td_ctrl != td.ctrl) { - val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - } - if (ret < 0) - break; /* interrupted frame */ - if (ret == 2) { - /* We can't handle async isochronous transfers. - Cancel The packet. */ - fprintf(stderr, "usb-uhci: Unimplemented async packet\n"); - usb_cancel_packet(&s->usb_packet); - } + + /* Handle isochonous transfer. */ + /* FIXME: might be more than one isoc in frame */ + old_td_ctrl = td.ctrl; + ret = uhci_handle_td(s, &td, &int_mask, 0); + + /* update the status bits of the TD */ + if (old_td_ctrl != td.ctrl) { + val = cpu_to_le32(td.ctrl); + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, + sizeof(val)); + } + if (ret < 0) + break; /* interrupted frame */ + if (ret == 2) { + s->async_frame_addr = frame_addr; } link = td.link; } @@ -767,6 +857,7 @@ static void uhci_frame_timer(void *opaque) usb_cancel_packet(&s->usb_packet); s->async_qh = 0; } + /* prepare the timer for the next frame */ expire_time = qemu_get_clock(vm_clock) + (ticks_per_sec / FRAME_TIMER_FREQ); @@ -855,4 +946,3 @@ void usb_uhci_piix4_init(PCIBus *bus, int devfn) pci_register_io_region(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); } - diff --git a/usb-linux.c b/usb-linux.c index 3a2330162..6de6e40cb 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -28,6 +28,7 @@ #include #include #include +#include /* We redefine it to avoid version problems */ struct usb_ctrltransfer { @@ -48,15 +49,172 @@ static int usb_host_find_device(int *pbus_num, int *paddr, const char *devname); //#define DEBUG +//#define DEBUG_ISOCH +//#define USE_ASYNCIO #define USBDEVFS_PATH "/proc/bus/usb" #define PRODUCT_NAME_SZ 32 +#define SIG_ISOCOMPLETE (SIGRTMIN+7) +#define MAX_ENDPOINTS 16 +struct sigaction sigact; + +/* endpoint association data */ +struct endp_data { + uint8_t type; +}; + +/* FIXME: move USBPacket to PendingURB */ typedef struct USBHostDevice { USBDevice dev; int fd; + USBPacket *packet; + struct endp_data endp_table[MAX_ENDPOINTS]; + int configuration; + uint8_t descr[1024]; + int descr_len; + int urbs_ready; } USBHostDevice; +typedef struct PendingURB { + struct usbdevfs_urb *urb; + USBHostDevice *dev; + QEMUBH *bh; + int status; + struct PendingURB *next; +} PendingURB; + +PendingURB *pending_urbs = NULL; + +int add_pending_urb(struct usbdevfs_urb *urb) +{ + PendingURB *purb = qemu_mallocz(sizeof(PendingURB)); + if (purb) { + purb->urb = urb; + purb->dev = NULL; + purb->bh = NULL; + purb->status = 0; + purb->next = pending_urbs; + pending_urbs = purb; + return 1; + } + return 0; +} + +int del_pending_urb(struct usbdevfs_urb *urb) +{ + PendingURB *purb = pending_urbs; + PendingURB *prev = NULL; + + while (purb && purb->urb != urb) { + prev = purb; + purb = purb->next; + } + + if (purb && purb->urb == urb) { + if (prev) { + prev->next = purb->next; + } else { + pending_urbs = purb->next; + } + qemu_free(purb); + return 1; + } + return 0; +} + +PendingURB *get_pending_urb(struct usbdevfs_urb *urb) +{ + PendingURB *purb = pending_urbs; + + while (purb && purb->urb != urb) { + purb = purb->next; + } + + if (purb && purb->urb == urb) { + return purb; + } + return NULL; +} + +static int usb_host_update_interfaces(USBHostDevice *dev, int configuration) +{ + int dev_descr_len, config_descr_len; + int interface, nb_interfaces, nb_configurations; + int ret, i; + + if (configuration == 0) /* address state - ignore */ + return 1; + + i = 0; + dev_descr_len = dev->descr[0]; + if (dev_descr_len > dev->descr_len) + goto fail; + nb_configurations = dev->descr[17]; + + i += dev_descr_len; + while (i < dev->descr_len) { +#ifdef DEBUG + printf("i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len, + dev->descr[i], dev->descr[i+1]); +#endif + if (dev->descr[i+1] != USB_DT_CONFIG) { + i += dev->descr[i]; + continue; + } + config_descr_len = dev->descr[i]; + + if (configuration == dev->descr[i + 5]) + break; + + i += config_descr_len; + } + + if (i >= dev->descr_len) { + printf("usb_host: error - device has no matching configuration\n"); + goto fail; + } + nb_interfaces = dev->descr[i + 4]; + +#ifdef USBDEVFS_DISCONNECT + /* earlier Linux 2.4 do not support that */ + { + struct usbdevfs_ioctl ctrl; + for (interface = 0; interface < nb_interfaces; interface++) { + ctrl.ioctl_code = USBDEVFS_DISCONNECT; + ctrl.ifno = interface; + ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl); + if (ret < 0 && errno != ENODATA) { + perror("USBDEVFS_DISCONNECT"); + goto fail; + } + } + } +#endif + + /* XXX: only grab if all interfaces are free */ + for (interface = 0; interface < nb_interfaces; interface++) { + ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface); + if (ret < 0) { + if (errno == EBUSY) { + fprintf(stderr, + "usb_host: warning - device already grabbed\n"); + } else { + perror("USBDEVFS_CLAIMINTERFACE"); + } + fail: + return 0; + } + } + +#ifdef DEBUG + printf("usb_host: %d interfaces claimed for configuration %d\n", + nb_interfaces, configuration); +#endif + + return 1; +} + static void usb_host_handle_reset(USBDevice *dev) { #if 0 @@ -76,6 +234,8 @@ static void usb_host_handle_destroy(USBDevice *dev) qemu_free(s); } +static int usb_linux_update_endp_table(USBHostDevice *s); + static int usb_host_handle_control(USBDevice *dev, int request, int value, @@ -85,13 +245,33 @@ static int usb_host_handle_control(USBDevice *dev, { USBHostDevice *s = (USBHostDevice *)dev; struct usb_ctrltransfer ct; + struct usbdevfs_setinterface si; + int intf_update_required = 0; int ret; if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) { /* specific SET_ADDRESS support */ dev->addr = value; return 0; + } else if (request == ((USB_RECIP_INTERFACE << 8) | + USB_REQ_SET_INTERFACE)) { + /* set alternate setting for the interface */ + si.interface = index; + si.altsetting = value; + ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si); + usb_linux_update_endp_table(s); + } else if (request == (DeviceOutRequest | USB_REQ_SET_CONFIGURATION)) { +#ifdef DEBUG + printf("usb_host_handle_control: SET_CONFIGURATION request - " + "config %d\n", value & 0xff); +#endif + if (s->configuration != (value & 0xff)) { + s->configuration = (value & 0xff); + intf_update_required = 1; + } + goto do_request; } else { + do_request: ct.bRequestType = request >> 8; ct.bRequest = request; ct.wValue = value; @@ -100,19 +280,28 @@ static int usb_host_handle_control(USBDevice *dev, ct.timeout = 50; ct.data = data; ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct); - if (ret < 0) { - switch(errno) { - case ETIMEDOUT: - return USB_RET_NAK; - default: - return USB_RET_STALL; - } - } else { - return ret; + } + + if (ret < 0) { + switch(errno) { + case ETIMEDOUT: + return USB_RET_NAK; + default: + return USB_RET_STALL; + } + } else { + if (intf_update_required) { +#ifdef DEBUG + printf("usb_host_handle_control: updating interfaces\n"); +#endif + usb_host_update_interfaces(s, value & 0xff); } - } + return ret; + } } +static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p); + static int usb_host_handle_data(USBDevice *dev, USBPacket *p) { USBHostDevice *s = (USBHostDevice *)dev; @@ -120,6 +309,10 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) int ret; uint8_t devep = p->devep; + if (s->endp_table[p->devep - 1].type == USBDEVFS_URB_TYPE_ISO) { + return usb_host_handle_isoch(dev, p); + } + /* XXX: optimize and handle all data types by looking at the config descriptor */ if (p->pid == USB_TOKEN_IN) @@ -145,18 +338,276 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) } } +static void usb_linux_bh_cb(void *opaque); + +void isoch_done(int signum, siginfo_t *info, void *context) { + struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr; + USBHostDevice *s = (USBHostDevice *)urb->usercontext; + PendingURB *purb; + + if (info->si_code != SI_ASYNCIO || + info->si_signo != SIG_ISOCOMPLETE) { + return; + } + + purb = get_pending_urb(urb); + if (purb) { + purb->bh = qemu_bh_new(usb_linux_bh_cb, purb); + if (purb->bh) { + purb->dev = s; + purb->status = info->si_errno; + qemu_bh_schedule(purb->bh); + } + } +} + +static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p) +{ + USBHostDevice *s = (USBHostDevice *)dev; + struct usbdevfs_urb *urb, *purb = NULL; + int ret; + uint8_t devep = p->devep; + + if (p->pid == USB_TOKEN_IN) + devep |= 0x80; + + urb = qemu_mallocz(sizeof(struct usbdevfs_urb) + + sizeof(struct usbdevfs_iso_packet_desc)); + if (!urb) { + printf("usb_host_handle_isoch: malloc failed\n"); + return 0; + } + + urb->type = USBDEVFS_URB_TYPE_ISO; + urb->endpoint = devep; + urb->status = 0; + urb->flags = USBDEVFS_URB_ISO_ASAP; + urb->buffer = p->data; + urb->buffer_length = p->len; + urb->actual_length = 0; + urb->start_frame = 0; + urb->error_count = 0; +#ifdef USE_ASYNCIO + urb->signr = SIG_ISOCOMPLETE; +#else + urb->signr = 0; +#endif + urb->usercontext = s; + urb->number_of_packets = 1; + urb->iso_frame_desc[0].length = p->len; + urb->iso_frame_desc[0].actual_length = 0; + urb->iso_frame_desc[0].status = 0; + ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); + if (ret == 0) { + if (!add_pending_urb(urb)) { + printf("usb_host_handle_isoch: add_pending_urb failed %p\n", urb); + } + } else { + printf("usb_host_handle_isoch: SUBMITURB ioctl=%d errno=%d\n", + ret, errno); + qemu_free(urb); + switch(errno) { + case ETIMEDOUT: + return USB_RET_NAK; + case EPIPE: + default: + return USB_RET_STALL; + } + } +#ifdef USE_ASYNCIO + /* FIXME: handle urbs_ready together with sync io + * workaround for injecting the signaled urbs into current frame */ + if (s->urbs_ready > 0) { + ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); + if (ret == 0) { + ret = purb->actual_length; + qemu_free(purb); + s->urbs_ready--; + } + return ret; + } + s->packet = p; + return USB_RET_ASYNC; +#else + ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); + if (ret == 0) { + if (del_pending_urb(purb)) { + ret = purb->actual_length; + qemu_free(purb); + } else { + printf("usb_host_handle_isoch: del_pending_urb failed %p\n", purb); + } + } else { +#ifdef DEBUG_ISOCH + printf("usb_host_handle_isoch: REAPURBNDELAY ioctl=%d errno=%d\n", + ret, errno); +#endif + } + return ret; +#endif +} + +static void usb_linux_bh_cb(void *opaque) +{ + PendingURB *pending_urb = (PendingURB *)opaque; + USBHostDevice *s = pending_urb->dev; + struct usbdevfs_urb *purb = NULL; + USBPacket *p = s->packet; + int ret; + + /* FIXME: handle purb->status */ + qemu_free(pending_urb->bh); + del_pending_urb(pending_urb->urb); + + if (!p) { + s->urbs_ready++; + return; + } + + ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); + if (ret < 0) { + printf("usb_linux_bh_cb: REAPURBNDELAY ioctl=%d errno=%d\n", + ret, errno); + return; + } + +#ifdef DEBUG_ISOCH + if (purb == pending_urb->urb) { + printf("usb_linux_bh_cb: urb mismatch reaped=%p pending=%p\n", + purb, urb); + } +#endif + + p->len = purb->actual_length; + usb_packet_complete(p); + qemu_free(purb); + s->packet = NULL; +} + +/* returns 1 on problem encountered or 0 for success */ +static int usb_linux_update_endp_table(USBHostDevice *s) +{ + uint8_t *descriptors; + uint8_t devep, type, configuration, alt_interface; + struct usb_ctrltransfer ct; + int interface, ret, length, i; + + ct.bRequestType = USB_DIR_IN; + ct.bRequest = USB_REQ_GET_CONFIGURATION; + ct.wValue = 0; + ct.wIndex = 0; + ct.wLength = 1; + ct.data = &configuration; + ct.timeout = 50; + + ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct); + if (ret < 0) { + perror("usb_linux_update_endp_table"); + return 1; + } + + /* in address state */ + if (configuration == 0) + return 1; + + /* get the desired configuration, interface, and endpoint descriptors + * from device description */ + descriptors = &s->descr[18]; + length = s->descr_len - 18; + i = 0; + + if (descriptors[i + 1] != USB_DT_CONFIG || + descriptors[i + 5] != configuration) { + printf("invalid descriptor data - configuration\n"); + return 1; + } + i += descriptors[i]; + + while (i < length) { + if (descriptors[i + 1] != USB_DT_INTERFACE || + (descriptors[i + 1] == USB_DT_INTERFACE && + descriptors[i + 4] == 0)) { + i += descriptors[i]; + continue; + } + + interface = descriptors[i + 2]; + + ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE; + ct.bRequest = USB_REQ_GET_INTERFACE; + ct.wValue = 0; + ct.wIndex = interface; + ct.wLength = 1; + ct.data = &alt_interface; + ct.timeout = 50; + + ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct); + if (ret < 0) { + perror("usb_linux_update_endp_table"); + return 1; + } + + /* the current interface descriptor is the active interface + * and has endpoints */ + if (descriptors[i + 3] != alt_interface) { + i += descriptors[i]; + continue; + } + + /* advance to the endpoints */ + while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) + i += descriptors[i]; + + if (i >= length) + break; + + while (i < length) { + if (descriptors[i + 1] != USB_DT_ENDPOINT) + break; + + devep = descriptors[i + 2]; + switch (descriptors[i + 3] & 0x3) { + case 0x00: + type = USBDEVFS_URB_TYPE_CONTROL; + break; + case 0x01: + type = USBDEVFS_URB_TYPE_ISO; + break; + case 0x02: + type = USBDEVFS_URB_TYPE_BULK; + break; + case 0x03: + type = USBDEVFS_URB_TYPE_INTERRUPT; + break; + default: + printf("usb_host: malformed endpoint type\n"); + type = USBDEVFS_URB_TYPE_BULK; + } + s->endp_table[(devep & 0xf) - 1].type = type; + + i += descriptors[i]; + } + } + return 0; +} + /* XXX: exclude high speed devices or implement EHCI */ USBDevice *usb_host_device_open(const char *devname) { - int fd, interface, ret, i; - USBHostDevice *dev; + int fd = -1, ret; + USBHostDevice *dev = NULL; struct usbdevfs_connectinfo ci; - uint8_t descr[1024]; char buf[1024]; - int descr_len, dev_descr_len, config_descr_len, nb_interfaces; int bus_num, addr; char product_name[PRODUCT_NAME_SZ]; + dev = qemu_mallocz(sizeof(USBHostDevice)); + if (!dev) + goto fail; + +#ifdef DEBUG_ISOCH + printf("usb_host_device_open %s\n", devname); +#endif if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name), devname) < 0) @@ -164,61 +615,35 @@ USBDevice *usb_host_device_open(const char *devname) snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", bus_num, addr); - fd = open(buf, O_RDWR); + fd = open(buf, O_RDWR | O_NONBLOCK); if (fd < 0) { perror(buf); return NULL; } - /* read the config description */ - descr_len = read(fd, descr, sizeof(descr)); - if (descr_len <= 0) { - perror("read descr"); + /* read the device description */ + dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); + if (dev->descr_len <= 0) { + perror("usb_host_update_interfaces: reading device data failed"); goto fail; } - i = 0; - dev_descr_len = descr[0]; - if (dev_descr_len > descr_len) - goto fail; - i += dev_descr_len; - config_descr_len = descr[i]; - if (i + config_descr_len > descr_len) - goto fail; - nb_interfaces = descr[i + 4]; - if (nb_interfaces != 1) { - /* NOTE: currently we grab only one interface */ - fprintf(stderr, "usb_host: only one interface supported\n"); - goto fail; - } - -#ifdef USBDEVFS_DISCONNECT - /* earlier Linux 2.4 do not support that */ +#ifdef DEBUG { - struct usbdevfs_ioctl ctrl; - ctrl.ioctl_code = USBDEVFS_DISCONNECT; - ctrl.ifno = 0; - ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl); - if (ret < 0 && errno != ENODATA) { - perror("USBDEVFS_DISCONNECT"); - goto fail; - } + int x; + printf("=== begin dumping device descriptor data ===\n"); + for (x = 0; x < dev->descr_len; x++) + printf("%02x ", dev->descr[x]); + printf("\n=== end dumping device descriptor data ===\n"); } #endif - /* XXX: only grab if all interfaces are free */ - interface = 0; - ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface); - if (ret < 0) { - if (errno == EBUSY) { - fprintf(stderr, "usb_host: device already grabbed\n"); - } else { - perror("USBDEVFS_CLAIMINTERFACE"); - } - fail: - close(fd); - return NULL; - } + dev->fd = fd; + dev->configuration = 1; + + /* XXX - do something about initial configuration */ + if (!usb_host_update_interfaces(dev, 1)) + goto fail; ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); if (ret < 0) { @@ -230,10 +655,10 @@ USBDevice *usb_host_device_open(const char *devname) printf("host USB device %d.%d grabbed\n", bus_num, addr); #endif - dev = qemu_mallocz(sizeof(USBHostDevice)); - if (!dev) + ret = usb_linux_update_endp_table(dev); + if (ret) goto fail; - dev->fd = fd; + if (ci.slow) dev->dev.speed = USB_SPEED_LOW; else @@ -252,7 +677,24 @@ USBDevice *usb_host_device_open(const char *devname) pstrcpy(dev->dev.devname, sizeof(dev->dev.devname), product_name); +#ifdef USE_ASYNCIO + /* set up the signal handlers */ + sigemptyset(&sigact.sa_mask); + sigact.sa_sigaction = isoch_done; + sigact.sa_flags = SA_SIGINFO; + sigact.sa_restorer = 0; + ret = sigaction(SIG_ISOCOMPLETE, &sigact, NULL); + if (ret < 0) { + printf("sigaction SIG_ISOCOMPLETE=%d errno=%d\n", ret, errno); + } +#endif + dev->urbs_ready = 0; return (USBDevice *)dev; +fail: + if (dev) + qemu_free(dev); + close(fd); + return NULL; } static int get_tag_value(char *buf, int buf_size, @@ -438,7 +880,7 @@ static const struct usb_class_info usb_class_info[] = { { USB_CLASS_APP_SPEC, "Application Specific" }, { USB_CLASS_VENDOR_SPEC, "Vendor Specific" }, { USB_CLASS_STILL_IMAGE, "Still Image" }, - { USB_CLASS_CSCID, "Smart Card" }, + { USB_CLASS_CSCID, "Smart Card" }, { USB_CLASS_CONTENT_SEC, "Content Security" }, { -1, NULL } }; -- cgit v1.2.3 From 4d043a09007d4d06c07b941d881ee298a026961e Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 4 Oct 2007 22:55:53 +0000 Subject: Quiet warnings introduced with the USB iso support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3329 c046a42c-6fe2-441c-8c8c-71466251a162 --- usb-linux.c | 89 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/usb-linux.c b/usb-linux.c index 6de6e40cb..53d501d7b 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -84,9 +84,9 @@ typedef struct PendingURB { struct PendingURB *next; } PendingURB; -PendingURB *pending_urbs = NULL; +static PendingURB *pending_urbs = NULL; -int add_pending_urb(struct usbdevfs_urb *urb) +static int add_pending_urb(struct usbdevfs_urb *urb) { PendingURB *purb = qemu_mallocz(sizeof(PendingURB)); if (purb) { @@ -101,7 +101,7 @@ int add_pending_urb(struct usbdevfs_urb *urb) return 0; } -int del_pending_urb(struct usbdevfs_urb *urb) +static int del_pending_urb(struct usbdevfs_urb *urb) { PendingURB *purb = pending_urbs; PendingURB *prev = NULL; @@ -123,7 +123,8 @@ int del_pending_urb(struct usbdevfs_urb *urb) return 0; } -PendingURB *get_pending_urb(struct usbdevfs_urb *urb) +#ifdef USE_ASYNCIO +static PendingURB *get_pending_urb(struct usbdevfs_urb *urb) { PendingURB *purb = pending_urbs; @@ -136,6 +137,7 @@ PendingURB *get_pending_urb(struct usbdevfs_urb *urb) } return NULL; } +#endif static int usb_host_update_interfaces(USBHostDevice *dev, int configuration) { @@ -338,9 +340,46 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) } } -static void usb_linux_bh_cb(void *opaque); +#ifdef USE_ASYNCIO +static void usb_linux_bh_cb(void *opaque) +{ + PendingURB *pending_urb = (PendingURB *)opaque; + USBHostDevice *s = pending_urb->dev; + struct usbdevfs_urb *purb = NULL; + USBPacket *p = s->packet; + int ret; + + /* FIXME: handle purb->status */ + qemu_free(pending_urb->bh); + del_pending_urb(pending_urb->urb); + + if (!p) { + s->urbs_ready++; + return; + } + + ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); + if (ret < 0) { + printf("usb_linux_bh_cb: REAPURBNDELAY ioctl=%d errno=%d\n", + ret, errno); + return; + } + +#ifdef DEBUG_ISOCH + if (purb == pending_urb->urb) { + printf("usb_linux_bh_cb: urb mismatch reaped=%p pending=%p\n", + purb, urb); + } +#endif + + p->len = purb->actual_length; + usb_packet_complete(p); + qemu_free(purb); + s->packet = NULL; +} -void isoch_done(int signum, siginfo_t *info, void *context) { +static void isoch_done(int signum, siginfo_t *info, void *context) +{ struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr; USBHostDevice *s = (USBHostDevice *)urb->usercontext; PendingURB *purb; @@ -360,6 +399,7 @@ void isoch_done(int signum, siginfo_t *info, void *context) { } } } +#endif static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p) { @@ -447,43 +487,6 @@ static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p) #endif } -static void usb_linux_bh_cb(void *opaque) -{ - PendingURB *pending_urb = (PendingURB *)opaque; - USBHostDevice *s = pending_urb->dev; - struct usbdevfs_urb *purb = NULL; - USBPacket *p = s->packet; - int ret; - - /* FIXME: handle purb->status */ - qemu_free(pending_urb->bh); - del_pending_urb(pending_urb->urb); - - if (!p) { - s->urbs_ready++; - return; - } - - ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); - if (ret < 0) { - printf("usb_linux_bh_cb: REAPURBNDELAY ioctl=%d errno=%d\n", - ret, errno); - return; - } - -#ifdef DEBUG_ISOCH - if (purb == pending_urb->urb) { - printf("usb_linux_bh_cb: urb mismatch reaped=%p pending=%p\n", - purb, urb); - } -#endif - - p->len = purb->actual_length; - usb_packet_complete(p); - qemu_free(purb); - s->packet = NULL; -} - /* returns 1 on problem encountered or 0 for success */ static int usb_linux_update_endp_table(USBHostDevice *s) { -- cgit v1.2.3 From e9c05b42e33e60a18e443d6526e9400ea2714444 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 4 Oct 2007 23:45:31 +0000 Subject: Implement PL110 byte order config bit (original patch by Richard Purdie). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3330 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pl110.c | 13 ++++-- hw/pl110_template.h | 119 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 95 insertions(+), 37 deletions(-) diff --git a/hw/pl110.c b/hw/pl110.c index 061ec7aba..adaf1315f 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -10,6 +10,7 @@ #include "vl.h" #define PL110_CR_EN 0x001 +#define PL110_CR_BGR 0x100 #define PL110_CR_BEBO 0x200 #define PL110_CR_BEPO 0x400 #define PL110_CR_PWR 0x800 @@ -114,6 +115,7 @@ static void pl110_update_display(void *opaque) int first, last = 0; int dirty, new_dirty; int i; + int bpp_offset; if (!pl110_enabled(s)) return; @@ -145,12 +147,17 @@ static void pl110_update_display(void *opaque) fprintf(stderr, "pl110: Bad color depth\n"); exit(1); } + if (s->cr & PL110_CR_BGR) + bpp_offset = 0; + else + bpp_offset = 18; + if (s->cr & PL110_CR_BEBO) - fn = fntable[s->bpp + 6]; + fn = fntable[s->bpp + 6 + bpp_offset]; else if (s->cr & PL110_CR_BEPO) - fn = fntable[s->bpp + 12]; + fn = fntable[s->bpp + 12 + bpp_offset]; else - fn = fntable[s->bpp]; + fn = fntable[s->bpp + bpp_offset]; src_width = s->cols; switch (s->bpp) { diff --git a/hw/pl110_template.h b/hw/pl110_template.h index f7cb1f495..33483c027 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -24,35 +24,68 @@ #error unknown bit depth #endif +#undef RGB +#define BORDER bgr #define ORDER 0 #include "pl110_template.h" #define ORDER 1 #include "pl110_template.h" #define ORDER 2 #include "pl110_template.h" +#undef BORDER +#define RGB +#define BORDER rgb +#define ORDER 0 +#include "pl110_template.h" +#define ORDER 1 +#include "pl110_template.h" +#define ORDER 2 +#include "pl110_template.h" +#undef BORDER -static drawfn glue(pl110_draw_fn_,BITS)[18] = +static drawfn glue(pl110_draw_fn_,BITS)[36] = { - glue(pl110_draw_line1_lblp,BITS), - glue(pl110_draw_line2_lblp,BITS), - glue(pl110_draw_line4_lblp,BITS), - glue(pl110_draw_line8_lblp,BITS), - glue(pl110_draw_line16_lblp,BITS), - glue(pl110_draw_line32_lblp,BITS), - - glue(pl110_draw_line1_bbbp,BITS), - glue(pl110_draw_line2_bbbp,BITS), - glue(pl110_draw_line4_bbbp,BITS), - glue(pl110_draw_line8_bbbp,BITS), - glue(pl110_draw_line16_bbbp,BITS), - glue(pl110_draw_line32_bbbp,BITS), - - glue(pl110_draw_line1_lbbp,BITS), - glue(pl110_draw_line2_lbbp,BITS), - glue(pl110_draw_line4_lbbp,BITS), - glue(pl110_draw_line8_lbbp,BITS), - glue(pl110_draw_line16_lbbp,BITS), - glue(pl110_draw_line32_lbbp,BITS) + glue(pl110_draw_line1_lblp_bgr,BITS), + glue(pl110_draw_line2_lblp_bgr,BITS), + glue(pl110_draw_line4_lblp_bgr,BITS), + glue(pl110_draw_line8_lblp_bgr,BITS), + glue(pl110_draw_line16_lblp_bgr,BITS), + glue(pl110_draw_line32_lblp_bgr,BITS), + + glue(pl110_draw_line1_bbbp_bgr,BITS), + glue(pl110_draw_line2_bbbp_bgr,BITS), + glue(pl110_draw_line4_bbbp_bgr,BITS), + glue(pl110_draw_line8_bbbp_bgr,BITS), + glue(pl110_draw_line16_bbbp_bgr,BITS), + glue(pl110_draw_line32_bbbp_bgr,BITS), + + glue(pl110_draw_line1_lbbp_bgr,BITS), + glue(pl110_draw_line2_lbbp_bgr,BITS), + glue(pl110_draw_line4_lbbp_bgr,BITS), + glue(pl110_draw_line8_lbbp_bgr,BITS), + glue(pl110_draw_line16_lbbp_bgr,BITS), + glue(pl110_draw_line32_lbbp_bgr,BITS), + + glue(pl110_draw_line1_lblp_rgb,BITS), + glue(pl110_draw_line2_lblp_rgb,BITS), + glue(pl110_draw_line4_lblp_rgb,BITS), + glue(pl110_draw_line8_lblp_rgb,BITS), + glue(pl110_draw_line16_lblp_rgb,BITS), + glue(pl110_draw_line32_lblp_rgb,BITS), + + glue(pl110_draw_line1_bbbp_rgb,BITS), + glue(pl110_draw_line2_bbbp_rgb,BITS), + glue(pl110_draw_line4_bbbp_rgb,BITS), + glue(pl110_draw_line8_bbbp_rgb,BITS), + glue(pl110_draw_line16_bbbp_rgb,BITS), + glue(pl110_draw_line32_bbbp_rgb,BITS), + + glue(pl110_draw_line1_lbbp_rgb,BITS), + glue(pl110_draw_line2_lbbp_rgb,BITS), + glue(pl110_draw_line4_lbbp_rgb,BITS), + glue(pl110_draw_line8_lbbp_rgb,BITS), + glue(pl110_draw_line16_lbbp_rgb,BITS), + glue(pl110_draw_line32_lbbp_rgb,BITS), }; #undef BITS @@ -61,18 +94,18 @@ static drawfn glue(pl110_draw_fn_,BITS)[18] = #else #if ORDER == 0 -#define NAME glue(lblp, BITS) +#define NAME glue(glue(lblp_, BORDER), BITS) #ifdef WORDS_BIGENDIAN #define SWAP_WORDS 1 #endif #elif ORDER == 1 -#define NAME glue(bbbp, BITS) +#define NAME glue(glue(bbbp_, BORDER), BITS) #ifndef WORDS_BIGENDIAN #define SWAP_WORDS 1 #endif #else #define SWAP_PIXELS 1 -#define NAME glue(lbbp, BITS) +#define NAME glue(glue(lbbp_, BORDER), BITS) #ifdef WORDS_BIGENDIAN #define SWAP_WORDS 1 #endif @@ -195,29 +228,38 @@ static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const #ifdef SWAP_WORDS data = bswap32(data); #endif +#ifdef RGB +#define LSB r +#define MSB b +#else +#define LSB b +#define MSB r +#endif #if 0 - r = data & 0x1f; + LSB = data & 0x1f; data >>= 5; g = data & 0x3f; data >>= 6; - b = data & 0x1f; + MSB = data & 0x1f; data >>= 5; #else - r = (data & 0x1f) << 3; + LSB = (data & 0x1f) << 3; data >>= 5; g = (data & 0x3f) << 2; data >>= 6; - b = (data & 0x1f) << 3; + MSB = (data & 0x1f) << 3; data >>= 5; #endif COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); - r = (data & 0x1f) << 3; + LSB = (data & 0x1f) << 3; data >>= 5; g = (data & 0x3f) << 2; data >>= 6; - b = (data & 0x1f) << 3; + MSB = (data & 0x1f) << 3; data >>= 5; COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); +#undef MSB +#undef LSB width -= 2; src += 4; } @@ -229,16 +271,25 @@ static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const unsigned int r, g, b; while (width > 0) { data = *(uint32_t *)src; +#ifdef RGB +#define LSB r +#define MSB b +#else +#define LSB b +#define MSB r +#endif #ifdef SWAP_WORDS - r = data & 0xff; + LSB = data & 0xff; g = (data >> 8) & 0xff; - b = (data >> 16) & 0xff; + MSB = (data >> 16) & 0xff; #else - r = (data >> 24) & 0xff; + LSB = (data >> 24) & 0xff; g = (data >> 16) & 0xff; - b = (data >> 8) & 0xff; + MSB = (data >> 8) & 0xff; #endif COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); +#undef MSB +#undef LSB width--; src += 4; } -- cgit v1.2.3 From 1192dad8798e4e4b72b14ff3a93c11cbb26eae5b Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 5 Oct 2007 13:08:35 +0000 Subject: New '-bios' option, used to select an alternate BIOS image from bios_dir. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3331 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 4 +++- hw/mips_pica61.c | 4 +++- hw/mips_r4k.c | 4 +++- hw/pc.c | 4 +++- hw/ppc405_boards.c | 8 ++++++-- hw/ppc_chrp.c | 4 +++- hw/ppc_prep.c | 4 +++- hw/shix.c | 8 +++++--- hw/sun4m.c | 4 +++- hw/sun4u.c | 4 +++- vl.c | 6 ++++++ vl.h | 1 + 12 files changed, 42 insertions(+), 13 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 3b37596d1..6f0edf9a3 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -791,7 +791,9 @@ void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, /* Load a BIOS image unless a kernel image has been specified. */ if (!kernel_filename) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); ret = load_image(buf, phys_ram_base + bios_offset); if (ret < 0 || ret > BIOS_SIZE) { fprintf(stderr, diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 2c4415017..958404617 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -94,7 +94,9 @@ void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device, /* load a BIOS image */ bios_offset = ram_size + vga_ram_size; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); bios_size = load_image(buf, phys_ram_base + bios_offset); if ((bios_size <= 0) || (bios_size > BIOS_SIZE)) { /* fatal */ diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 5769ade96..47b51c7b0 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -179,7 +179,9 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, preloaded we also initialize the hardware, since the BIOS wasn't run. */ bios_offset = ram_size + vga_ram_size; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); bios_size = load_image(buf, phys_ram_base + bios_offset); if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) { cpu_register_physical_memory(0x1fc00000, diff --git a/hw/pc.c b/hw/pc.c index ace0cee1f..5bc0b63e7 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -706,7 +706,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, vga_ram_addr = qemu_ram_alloc(vga_ram_size); /* BIOS load */ - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); bios_size = get_image_size(buf); if (bios_size <= 0 || (bios_size % 65536) != 0) { diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index ebf160cb7..8c00148d7 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -236,7 +236,9 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, #ifdef DEBUG_BOARD_INIT printf("Load BIOS from file\n"); #endif - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); bios_size = load_image(buf, phys_ram_base + bios_offset); if (bios_size < 0 || bios_size > BIOS_SIZE) { fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf); @@ -549,7 +551,9 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, #ifdef DEBUG_BOARD_INIT printf("Load BIOS from file\n"); #endif - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); bios_size = load_image(buf, phys_ram_base + bios_offset); if (bios_size < 0 || bios_size > BIOS_SIZE) { fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf); diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 653f7c3a7..f53c85b85 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -349,7 +349,9 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* allocate and load BIOS */ bios_offset = ram_size + vga_ram_size; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); bios_size = load_image(buf, phys_ram_base + bios_offset); if (bios_size < 0 || bios_size > BIOS_SIZE) { cpu_abort(env, "qemu: could not load PowerPC bios '%s'\n", buf); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 9e2a4403a..16d8915e5 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -564,7 +564,9 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, /* allocate and load BIOS */ bios_offset = ram_size + vga_ram_size; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); bios_size = load_image(buf, phys_ram_base + bios_offset); if (bios_size < 0 || bios_size > BIOS_SIZE) { cpu_abort(env, "qemu: could not load PPC PREP bios '%s'\n", buf); diff --git a/hw/shix.c b/hw/shix.c index e668426c8..884178e94 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -83,12 +83,14 @@ void shix_init(int ram_size, int vga_ram_size, int boot_device, cpu_register_physical_memory(0x0c000000, 0x01000000, 0x01004000); /* Load BIOS in 0 (and access it through P2, 0xA0000000) */ - printf("%s: load BIOS '%s'\n", __func__, BIOS_FILENAME); - ret = load_image(BIOS_FILENAME, phys_ram_base); + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + printf("%s: load BIOS '%s'\n", __func__, bios_name); + ret = load_image(bios_name, phys_ram_base); if (ret < 0) { /* Check bios size */ fprintf(stderr, "ret=%d\n", ret); fprintf(stderr, "qemu: could not load SHIX bios '%s'\n", - BIOS_FILENAME); + bios_name); exit(1); } diff --git a/hw/sun4m.c b/hw/sun4m.c index 76b0e7ee8..f9961c773 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -430,7 +430,9 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); + if (bios_name == NULL) + bios_name = PROM_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); ret = load_elf(buf, PROM_PADDR - PROM_VADDR, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", diff --git a/hw/sun4u.c b/hw/sun4u.c index 0e9e72e35..cc5e20083 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -382,7 +382,9 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); + if (bios_name == NULL) + bios_name = PROM_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); ret = load_elf(buf, PROM_ADDR - PROM_VADDR, NULL, NULL, NULL); if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", diff --git a/vl.c b/vl.c index ebd5dbf20..be99f959c 100644 --- a/vl.c +++ b/vl.c @@ -143,6 +143,7 @@ int inet_aton(const char *cp, struct in_addr *ia); #define MAX_IOPORTS 65536 const char *bios_dir = CONFIG_QEMU_SHAREDIR; +const char *bios_name = NULL; char phys_ram_file[1024]; void *ioport_opaque[MAX_IOPORTS]; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; @@ -7149,6 +7150,7 @@ enum { QEMU_OPTION_d, QEMU_OPTION_hdachs, QEMU_OPTION_L, + QEMU_OPTION_bios, QEMU_OPTION_no_code_copy, QEMU_OPTION_k, QEMU_OPTION_localtime, @@ -7241,6 +7243,7 @@ const QEMUOption qemu_options[] = { { "d", HAS_ARG, QEMU_OPTION_d }, { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, { "L", HAS_ARG, QEMU_OPTION_L }, + { "bios", HAS_ARG, QEMU_OPTION_bios }, { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, #ifdef USE_KQEMU { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, @@ -7887,6 +7890,9 @@ int main(int argc, char **argv) case QEMU_OPTION_L: bios_dir = optarg; break; + case QEMU_OPTION_bios: + bios_name = optarg; + break; case QEMU_OPTION_S: autostart = 0; break; diff --git a/vl.h b/vl.h index 0add259de..7a3d22c90 100644 --- a/vl.h +++ b/vl.h @@ -129,6 +129,7 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); void hw_error(const char *fmt, ...); extern const char *bios_dir; +extern const char *bios_name; extern int vm_running; extern const char *qemu_name; -- cgit v1.2.3 From 1c27f8fbfead8f5ff12da6946436fe35c6adcac4 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 5 Oct 2007 13:09:54 +0000 Subject: PowerPC hardware reset vector is now considered as part of the exception model. Use it at CPU initialisation time. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3332 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 6 +- target-ppc/translate_init.c | 162 ++++++++------------------------------------ 2 files changed, 31 insertions(+), 137 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 1039111a0..99562d668 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2792,11 +2792,7 @@ void cpu_ppc_reset (void *opaque) msr_fp = 1; /* Allow floating point exceptions */ msr_pr = 1; #else -#if defined(TARGET_PPC64) - env->nip = 0x00000100; -#else - env->nip = 0xFFFFFFFC; -#endif + env->nip = env->hreset_vector | env->excp_prefix; ppc_tlb_invalidate_all(env); #endif do_compute_hflags(env); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 606a04f25..2cf2c6309 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2235,6 +2235,8 @@ static void init_excp_4xx_real (CPUPPCState *env) env->excp_prefix = 0x00000000; env->ivor_mask = 0x0000FFF0; env->ivpr_mask = 0xFFFF0000; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2258,6 +2260,8 @@ static void init_excp_4xx_softmmu (CPUPPCState *env) env->excp_prefix = 0x00000000; env->ivor_mask = 0x0000FFF0; env->ivpr_mask = 0xFFFF0000; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2283,6 +2287,8 @@ static void init_excp_BookE (CPUPPCState *env) env->excp_prefix = 0x00000000; env->ivor_mask = 0x0000FFE0; env->ivpr_mask = 0xFFFF0000; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2302,6 +2308,8 @@ static void init_excp_601 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000; env->excp_prefix = 0xFFF00000; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2328,6 +2336,8 @@ static void init_excp_602 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500; env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600; env->excp_prefix = 0xFFF00000; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2350,6 +2360,8 @@ static void init_excp_603 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2373,6 +2385,8 @@ static void init_excp_G2 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2393,6 +2407,8 @@ static void init_excp_604 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2415,6 +2431,8 @@ static void init_excp_620 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; /* ? */ #endif } #endif /* defined(TARGET_PPC64) */ @@ -2436,6 +2454,8 @@ static void init_excp_7x0 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2457,6 +2477,8 @@ static void init_excp_750FX (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2480,6 +2502,8 @@ static void init_excp_7400 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2505,6 +2529,8 @@ static void init_excp_7450 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; #endif } @@ -2534,6 +2560,8 @@ static void init_excp_970 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; #endif } #endif @@ -2564,10 +2592,6 @@ static void init_proc_401 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 401x2 */ @@ -2597,10 +2621,6 @@ static void init_proc_401x2 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 401x3 */ @@ -2628,10 +2648,6 @@ static void init_proc_401x3 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* IOP480 */ @@ -2661,10 +2677,6 @@ static void init_proc_IOP480 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 403 */ @@ -2733,10 +2745,6 @@ static void init_proc_403GCX (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 405 */ @@ -2777,10 +2785,6 @@ static void init_proc_405 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 440 EP */ @@ -2826,10 +2830,6 @@ static void init_proc_440EP (CPUPPCState *env) env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 440 GP */ @@ -2857,10 +2857,6 @@ static void init_proc_440GP (CPUPPCState *env) env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 440x4 */ @@ -2889,10 +2885,6 @@ static void init_proc_440x4 (CPUPPCState *env) env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 440x5 */ @@ -2938,10 +2930,6 @@ static void init_proc_440x5 (CPUPPCState *env) env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 460 (guessed) */ @@ -2993,10 +2981,6 @@ static void init_proc_460 (CPUPPCState *env) env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 460F (guessed) */ @@ -3051,10 +3035,6 @@ static void init_proc_460F (CPUPPCState *env) env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* Generic BookE PowerPC */ @@ -3077,10 +3057,6 @@ static void init_proc_BookE (CPUPPCState *env) init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* e200 core */ @@ -3112,10 +3088,6 @@ static void init_proc_e500 (CPUPPCState *env) env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* e600 core */ @@ -3185,10 +3157,6 @@ static void init_proc_601 (CPUPPCState *env) env->dcache_line_size = 64; env->icache_line_size = 64; /* XXX: TODO: allocate internal IRQ controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 602 */ @@ -3228,10 +3196,6 @@ static void init_proc_602 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 603 */ @@ -3267,10 +3231,6 @@ static void init_proc_603 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 603e */ @@ -3311,10 +3271,6 @@ static void init_proc_603E (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC G2 */ @@ -3357,10 +3313,6 @@ static void init_proc_G2 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC G2LE */ @@ -3403,10 +3355,6 @@ static void init_proc_G2LE (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 604 */ @@ -3441,10 +3389,6 @@ static void init_proc_604 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 740/750 (aka G3) */ @@ -3481,10 +3425,6 @@ static void init_proc_7x0 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 750FX/GX */ @@ -3528,10 +3468,6 @@ static void init_proc_750fx (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 745/755 */ @@ -3579,6 +3515,7 @@ static void init_proc_7x5 (CPUPPCState *env) gen_low_BATs(env); gen_high_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); + /* XXX: exception vectors ? */ env->dcache_line_size = 32; env->icache_line_size = 32; /* Allocate hardware IRQ controller */ @@ -3616,10 +3553,6 @@ static void init_proc_7400 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 7410 (aka G4) */ @@ -3661,10 +3594,6 @@ static void init_proc_7410 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 7440 (aka G4) */ @@ -3728,14 +3657,11 @@ static void init_proc_7440 (CPUPPCState *env) /* Memory management */ gen_low_BATs(env); gen_74xx_soft_tlb(env, 128, 2); + init_excp_7450(env); env->dcache_line_size = 32; env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 7450 (aka G4) */ @@ -3806,10 +3732,6 @@ static void init_proc_7450 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 7445 (aka G4) */ @@ -3912,10 +3834,6 @@ static void init_proc_7445 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 7455 (aka G4) */ @@ -4020,10 +3938,6 @@ static void init_proc_7455 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } #if defined (TARGET_PPC64) @@ -4084,10 +3998,6 @@ static void init_proc_970 (CPUPPCState *env) env->icache_line_size = 128; /* Allocate hardware IRQ controller */ ppc970_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0x0000000000000100ULL; -#endif } /* PowerPC 970FX (aka G5) */ @@ -4143,10 +4053,6 @@ static void init_proc_970FX (CPUPPCState *env) env->icache_line_size = 128; /* Allocate hardware IRQ controller */ ppc970_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0x0000000000000100ULL; -#endif } /* PowerPC 970 GX */ @@ -4202,10 +4108,6 @@ static void init_proc_970GX (CPUPPCState *env) env->icache_line_size = 128; /* Allocate hardware IRQ controller */ ppc970_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0x0000000000000100ULL; -#endif } /* PowerPC 620 */ @@ -4237,10 +4139,6 @@ static void init_proc_620 (CPUPPCState *env) env->dcache_line_size = 64; env->icache_line_size = 64; /* XXX: TODO: initialize internal interrupt controller */ -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0x0000000000000100ULL; /* ? */ -#endif } #endif /* defined (TARGET_PPC64) */ -- cgit v1.2.3 From 65f9ee8d670e12a396857affb36920afd48f5e64 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 5 Oct 2007 13:11:25 +0000 Subject: Rename PowerPC MMUCSR0 and MMUCFG SPRs: those are not BookE specific. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3333 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 4 ++-- target-ppc/translate_init.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 43b8c90b1..03942bf4b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1042,7 +1042,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_440_DBDR (0x3F3) #define SPR_LDSTDB (0x3F4) #define SPR_40x_IAC1 (0x3F4) -#define SPR_BOOKE_MMUCSR0 (0x3F4) +#define SPR_MMUCSR0 (0x3F4) #define SPR_DABR (0x3F5) #define DABR_MASK (~(target_ulong)0x7) #define SPR_E500_BUCSR (0x3F5) @@ -1054,7 +1054,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define SPR_MSSSR0 (0x3F7) #define SPR_DABRX (0x3F7) #define SPR_40x_DAC2 (0x3F7) -#define SPR_BOOKE_MMUCFG (0x3F7) +#define SPR_MMUCFG (0x3F7) #define SPR_LDSTCR (0x3F8) #define SPR_L2PMCR (0x3F8) #define SPR_750_HID2 (0x3F8) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2cf2c6309..834c047f3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1562,12 +1562,12 @@ static void gen_spr_BookE_FSL (CPUPPCState *env) 0x00000000); } /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MMUCFG, "MMUCFG", + spr_register(env, SPR_MMUCFG, "MMUCFG", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, 0x00000000); /* TOFIX */ /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MMUCSR0, "MMUCSR0", + spr_register(env, SPR_MMUCSR0, "MMUCSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* TOFIX */ -- cgit v1.2.3 From 5bfb56b264d18be57f16c519464fc1919db44372 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 5 Oct 2007 17:01:51 +0000 Subject: Implement sparc64_[gs]et_context git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3334 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 8 ++ linux-user/qemu.h | 3 + linux-user/signal.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 9c3d67d49..127ae109a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -634,6 +634,14 @@ void cpu_loop (CPUSPARCState *env) queue_signal(info.si_signo, &info); } break; + case 0x16e: + flush_windows(env); + sparc64_get_context(env); + break; + case 0x16f: + flush_windows(env); + sparc64_set_context(env); + break; #endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index e07ac7b4d..defa6b71e 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -160,6 +160,9 @@ void save_v86_state(CPUX86State *env); void handle_vm86_trap(CPUX86State *env, int trapno); void handle_vm86_fault(CPUX86State *env); int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr); +#elif defined(TARGET_SPARC64) +void sparc64_set_context(CPUSPARCState *env); +void sparc64_get_context(CPUSPARCState *env); #endif /* mmap.c */ diff --git a/linux-user/signal.c b/linux-user/signal.c index d17c506d2..52041dafd 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1443,6 +1443,9 @@ struct target_rt_signal_frame { #define UREG_I0 0 #define UREG_I1 1 #define UREG_I2 2 +#define UREG_I3 3 +#define UREG_I4 4 +#define UREG_I5 5 #define UREG_I6 6 #define UREG_I7 7 #define UREG_L0 8 @@ -1704,6 +1707,239 @@ long do_rt_sigreturn(CPUState *env) return -ENOSYS; } +#ifdef TARGET_SPARC64 +#define MC_TSTATE 0 +#define MC_PC 1 +#define MC_NPC 2 +#define MC_Y 3 +#define MC_G1 4 +#define MC_G2 5 +#define MC_G3 6 +#define MC_G4 7 +#define MC_G5 8 +#define MC_G6 9 +#define MC_G7 10 +#define MC_O0 11 +#define MC_O1 12 +#define MC_O2 13 +#define MC_O3 14 +#define MC_O4 15 +#define MC_O5 16 +#define MC_O6 17 +#define MC_O7 18 +#define MC_NGREG 19 + +typedef target_ulong target_mc_greg_t; +typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG]; + +struct target_mc_fq { + target_ulong *mcfq_addr; + uint32_t mcfq_insn; +}; + +struct target_mc_fpu { + union { + uint32_t sregs[32]; + uint64_t dregs[32]; + //uint128_t qregs[16]; + } mcfpu_fregs; + target_ulong mcfpu_fsr; + target_ulong mcfpu_fprs; + target_ulong mcfpu_gsr; + struct target_mc_fq *mcfpu_fq; + unsigned char mcfpu_qcnt; + unsigned char mcfpu_qentsz; + unsigned char mcfpu_enab; +}; +typedef struct target_mc_fpu target_mc_fpu_t; + +typedef struct { + target_mc_gregset_t mc_gregs; + target_mc_greg_t mc_fp; + target_mc_greg_t mc_i7; + target_mc_fpu_t mc_fpregs; +} target_mcontext_t; + +struct target_ucontext { + struct target_ucontext *uc_link; + target_ulong uc_flags; + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; +}; + +/* A V9 register window */ +struct target_reg_window { + target_ulong locals[8]; + target_ulong ins[8]; +}; + +#define TARGET_STACK_BIAS 2047 + +/* {set, get}context() needed for 64-bit SparcLinux userland. */ +void sparc64_set_context(CPUSPARCState *env) +{ + struct target_ucontext *ucp = (struct target_ucontext *) + env->regwptr[UREG_I0]; + target_mc_gregset_t *grp; + target_ulong pc, npc, tstate; + target_ulong fp, i7; + unsigned char fenab; + int err; + unsigned int i; + target_ulong *src, *dst; + + grp = &ucp->uc_mcontext.mc_gregs; + err = get_user(pc, &((*grp)[MC_PC])); + err |= get_user(npc, &((*grp)[MC_NPC])); + if (err || ((pc | npc) & 3)) + goto do_sigsegv; + if (env->regwptr[UREG_I1]) { + target_sigset_t target_set; + sigset_t set; + + if (TARGET_NSIG_WORDS == 1) { + if (get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0])) + goto do_sigsegv; + } else { + src = &ucp->uc_sigmask; + dst = &target_set; + for (i = 0; i < sizeof(target_sigset_t) / sizeof(target_ulong); + i++, dst++, src++) + err |= get_user(dst, src); + if (err) + goto do_sigsegv; + } + target_to_host_sigset_internal(&set, &target_set); + sigprocmask(SIG_SETMASK, &set, NULL); + } + env->pc = pc; + env->npc = npc; + err |= get_user(env->y, &((*grp)[MC_Y])); + err |= get_user(tstate, &((*grp)[MC_TSTATE])); + env->asi = (tstate >> 24) & 0xff; + PUT_CCR(env, tstate >> 32); + PUT_CWP64(env, tstate & 0x1f); + err |= get_user(env->gregs[1], (&(*grp)[MC_G1])); + err |= get_user(env->gregs[2], (&(*grp)[MC_G2])); + err |= get_user(env->gregs[3], (&(*grp)[MC_G3])); + err |= get_user(env->gregs[4], (&(*grp)[MC_G4])); + err |= get_user(env->gregs[5], (&(*grp)[MC_G5])); + err |= get_user(env->gregs[6], (&(*grp)[MC_G6])); + err |= get_user(env->gregs[7], (&(*grp)[MC_G7])); + err |= get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0])); + err |= get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1])); + err |= get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2])); + err |= get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3])); + err |= get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4])); + err |= get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5])); + err |= get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6])); + err |= get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7])); + + err |= get_user(fp, &(ucp->uc_mcontext.mc_fp)); + err |= get_user(i7, &(ucp->uc_mcontext.mc_i7)); + err |= put_user(fp, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); + err |= put_user(i7, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); + + err |= get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); + err |= get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); + src = &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs); + dst = &env->fpr; + for (i = 0; i < 64; i++, dst++, src++) + err |= get_user(dst, src); + err |= get_user(env->fsr, + &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); + err |= get_user(env->gsr, + &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); + if (err) + goto do_sigsegv; + + return; + do_sigsegv: + force_sig(SIGSEGV); +} + +void sparc64_get_context(CPUSPARCState *env) +{ + struct target_ucontext *ucp = (struct target_ucontext *) + env->regwptr[UREG_I0]; + target_mc_gregset_t *grp; + target_mcontext_t *mcp; + target_ulong fp, i7; + int err; + unsigned int i; + target_ulong *src, *dst; + target_sigset_t target_set; + sigset_t set; + + mcp = &ucp->uc_mcontext; + grp = &mcp->mc_gregs; + + /* Skip over the trap instruction, first. */ + env->pc = env->npc; + env->npc += 4; + + err = 0; + + sigprocmask(0, NULL, &set); + host_to_target_sigset_internal(&target_set, &set); + if (TARGET_NSIG_WORDS == 1) + err |= put_user(target_set.sig[0], + (target_ulong *)&ucp->uc_sigmask); + else { + src = &target_set; + dst = &ucp->uc_sigmask; + for (i = 0; i < sizeof(target_sigset_t) / sizeof(target_ulong); + i++, dst++, src++) + err |= put_user(src, dst); + if (err) + goto do_sigsegv; + } + + err |= put_user(env->tstate, &((*grp)[MC_TSTATE])); + err |= put_user(env->pc, &((*grp)[MC_PC])); + err |= put_user(env->npc, &((*grp)[MC_NPC])); + err |= put_user(env->y, &((*grp)[MC_Y])); + err |= put_user(env->gregs[1], &((*grp)[MC_G1])); + err |= put_user(env->gregs[2], &((*grp)[MC_G2])); + err |= put_user(env->gregs[3], &((*grp)[MC_G3])); + err |= put_user(env->gregs[4], &((*grp)[MC_G4])); + err |= put_user(env->gregs[5], &((*grp)[MC_G5])); + err |= put_user(env->gregs[6], &((*grp)[MC_G6])); + err |= put_user(env->gregs[7], &((*grp)[MC_G7])); + err |= put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0])); + err |= put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1])); + err |= put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2])); + err |= put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3])); + err |= put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4])); + err |= put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5])); + err |= put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6])); + err |= put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7])); + + err |= get_user(fp, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); + err |= get_user(i7, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); + err |= put_user(fp, &(mcp->mc_fp)); + err |= put_user(i7, &(mcp->mc_i7)); + + src = &env->fpr; + dst = &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs); + for (i = 0; i < 64; i++, dst++, src++) + err |= put_user(src, dst); + err |= put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr)); + err |= put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr)); + err |= put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs)); + + if (err) + goto do_sigsegv; + + return; + do_sigsegv: + force_sig(SIGSEGV); +} +#endif #elif defined(TARGET_MIPS64) # warning signal handling not implemented -- cgit v1.2.3 From 12de9a396acbc95e25c5d60ed097cc55777eaaed Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 5 Oct 2007 22:06:02 +0000 Subject: Full implementation of PowerPC 64 MMU, just missing support for 1 TB memory segments. Remove the PowerPC 64 "bridge" MMU model and implement segment registers emulation using SLB entries instead. Make SLB area size implementation dependant. Improve TLB & SLB search debug traces. Temporary hack to make PowerPC 970 boot from ROM instead of RAM. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3335 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 14 +-- target-ppc/helper.c | 210 +++++++++++++++++++++++++++++++++++--------- target-ppc/op.c | 14 +++ target-ppc/translate.c | 167 ++++++++++++++++++++++++----------- target-ppc/translate_init.c | 87 +++++++++++++----- 5 files changed, 373 insertions(+), 119 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 03942bf4b..5824526be 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -105,10 +105,8 @@ enum { /* BookE FSL MMU model */ POWERPC_MMU_BOOKE_FSL, #if defined(TARGET_PPC64) - /* Standard 64 bits PowerPC MMU */ + /* 64 bits PowerPC MMU */ POWERPC_MMU_64B, - /* 64 bits "bridge" PowerPC MMU */ - POWERPC_MMU_64BRIDGE, #endif /* defined(TARGET_PPC64) */ }; @@ -514,6 +512,8 @@ struct CPUPPCState { ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ /* 403 dedicated access protection registers */ target_ulong pb[4]; + /* PowerPC 64 SLB area */ + int slb_nr; int dcache_line_size; int icache_line_size; @@ -606,10 +606,14 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value); #if defined(TARGET_PPC64) target_ulong ppc_load_asr (CPUPPCState *env); void ppc_store_asr (CPUPPCState *env, target_ulong value); -#endif +target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr); +void ppc_store_slb (CPUPPCState *env, int slb_nr, target_ulong rs); +#endif /* defined(TARGET_PPC64) */ +#if 0 // Unused target_ulong do_load_sr (CPUPPCState *env, int srnum); -void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif +void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); +#endif /* !defined(CONFIG_USER_ONLY) */ target_ulong ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, target_ulong value); target_ulong do_load_msr (CPUPPCState *env); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 99562d668..bb39fc05f 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -501,21 +501,31 @@ static inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) pte0 = ldq_phys(base + (i * 16)); pte1 = ldq_phys(base + (i * 16) + 8); r = pte64_check(ctx, pte0, pte1, h, rw); +#if defined (DEBUG_MMU) + if (loglevel != 0) { + fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX + " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", + base + (i * 16), pte0, pte1, + (int)(pte0 & 1), h, (int)((pte0 >> 1) & 1), + ctx->ptem); + } +#endif } else #endif { pte0 = ldl_phys(base + (i * 8)); pte1 = ldl_phys(base + (i * 8) + 4); r = pte32_check(ctx, pte0, pte1, h, rw); - } #if defined (DEBUG_MMU) - if (loglevel != 0) { - fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX - " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", - base + (i * 8), pte0, pte1, - (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem); - } + if (loglevel != 0) { + fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX + " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", + base + (i * 8), pte0, pte1, + (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), + ctx->ptem); + } #endif + } switch (r) { case -3: /* PTE inconsistency */ @@ -581,24 +591,15 @@ static int find_pte64 (mmu_ctx_t *ctx, int h, int rw) static inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw) { #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B || - env->mmu_model == POWERPC_MMU_64BRIDGE) + if (env->mmu_model == POWERPC_MMU_64B) return find_pte64(ctx, h, rw); #endif return find_pte32(ctx, h, rw); } -static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, - int sdr_sh, - target_phys_addr_t hash, - target_phys_addr_t mask) -{ - return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask); -} - #if defined(TARGET_PPC64) -static int slb_lookup (CPUState *env, target_ulong eaddr, +static int slb_lookup (CPUPPCState *env, target_ulong eaddr, target_ulong *vsid, target_ulong *page_mask, int *attr) { target_phys_addr_t sr_base; @@ -610,14 +611,23 @@ static int slb_lookup (CPUState *env, target_ulong eaddr, ret = -5; sr_base = env->spr[SPR_ASR]; +#if defined(DEBUG_SLB) + if (loglevel != 0) { + fprintf(logfile, "%s: eaddr " ADDRX " base " PADDRX "\n", + __func__, eaddr, sr_base); + } +#endif mask = 0x0000000000000000ULL; /* Avoid gcc warning */ -#if 0 /* XXX: Fix this */ slb_nr = env->slb_nr; -#else - slb_nr = 32; -#endif for (n = 0; n < slb_nr; n++) { tmp64 = ldq_phys(sr_base); + tmp = ldl_phys(sr_base + 8); +#if defined(DEBUG_SLB) + if (loglevel != 0) { + fprintf(logfile, "%s: seg %d " PADDRX " %016" PRIx64 " %08" PRIx32 "\n", + __func__, n, sr_base, tmp64, tmp); + } +#endif if (tmp64 & 0x0000000008000000ULL) { /* SLB entry is valid */ switch (tmp64 & 0x0000000006000000ULL) { @@ -636,7 +646,6 @@ static int slb_lookup (CPUState *env, target_ulong eaddr, } if ((eaddr & mask) == (tmp64 & mask)) { /* SLB match */ - tmp = ldl_phys(sr_base + 8); *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; *page_mask = ~mask; *attr = tmp & 0xFF; @@ -649,13 +658,80 @@ static int slb_lookup (CPUState *env, target_ulong eaddr, return ret; } + +target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr) +{ + target_phys_addr_t sr_base; + target_ulong rt; + uint64_t tmp64; + uint32_t tmp; + + sr_base = env->spr[SPR_ASR]; + sr_base += 12 * slb_nr; + tmp64 = ldq_phys(sr_base); + tmp = ldl_phys(sr_base + 8); + if (tmp64 & 0x0000000008000000ULL) { + /* SLB entry is valid */ + /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */ + rt = tmp >> 8; /* 65:88 => 40:63 */ + rt |= (tmp64 & 0x7) << 24; /* 62:64 => 37:39 */ + /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */ + rt |= ((tmp >> 4) & 0xF) << 27; + } else { + rt = 0; + } +#if defined(DEBUG_SLB) + if (loglevel != 0) { + fprintf(logfile, "%s: " PADDRX " %016" PRIx64 " %08" PRIx32 " => %d " + ADDRX "\n", __func__, sr_base, tmp64, tmp, slb_nr, rt); + } +#endif + + return rt; +} + +void ppc_store_slb (CPUPPCState *env, int slb_nr, target_ulong rs) +{ + target_phys_addr_t sr_base; + uint64_t tmp64; + uint32_t tmp; + + sr_base = env->spr[SPR_ASR]; + sr_base += 12 * slb_nr; + /* Copy Rs bits 37:63 to SLB 62:88 */ + tmp = rs << 8; + tmp64 = (rs >> 24) & 0x7; + /* Copy Rs bits 33:36 to SLB 89:92 */ + tmp |= ((rs >> 27) & 0xF) << 4; + /* Set the valid bit */ + tmp64 |= 1 << 27; + /* Set ESID */ + tmp64 |= (uint32_t)slb_nr << 28; +#if defined(DEBUG_SLB) + if (loglevel != 0) { + fprintf(logfile, "%s: %d " ADDRX " => " PADDRX " %016" PRIx64 " %08" + PRIx32 "\n", __func__, slb_nr, rs, sr_base, tmp64, tmp); + } +#endif + /* Write SLB entry to memory */ + stq_phys(sr_base, tmp64); + stl_phys(sr_base + 8, tmp); +} #endif /* defined(TARGET_PPC64) */ /* Perform segment based translation */ +static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, + int sdr_sh, + target_phys_addr_t hash, + target_phys_addr_t mask) +{ + return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask); +} + static int get_segment (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int type) { - target_phys_addr_t sdr, hash, mask, sdr_mask; + target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask; target_ulong sr, vsid, vsid_mask, pgidx, page_mask; #if defined(TARGET_PPC64) int attr; @@ -664,8 +740,12 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, int ret, ret2; #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B || - env->mmu_model == POWERPC_MMU_64BRIDGE) { + if (env->mmu_model == POWERPC_MMU_64B) { +#if defined (DEBUG_MMU) + if (loglevel != 0) { + fprintf(logfile, "Check SLBs\n"); + } +#endif ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); if (ret < 0) return ret; @@ -699,29 +779,53 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, msr_ir, msr_dr, msr_pr, rw, type); } - if (!ds && loglevel != 0) { - fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n", - ctx->key, sr & 0x10000000); - } #endif } +#if defined (DEBUG_MMU) + if (loglevel != 0) { + fprintf(logfile, "pte segment: key=%d ds %d nx %d vsid " ADDRX "\n", + ctx->key, ds, nx, vsid); + } +#endif ret = -1; if (!ds) { /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || nx == 0) { /* Page address translation */ - pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS; - hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; /* Primary table address */ sdr = env->sdr1; - mask = ((sdr & 0x000001FF) << sdr_sh) | sdr_mask; + pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS; +#if defined(TARGET_PPC64) + if (env->mmu_model == POWERPC_MMU_64B) { + htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F)); + /* XXX: this is false for 1 TB segments */ + hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; + } else +#endif + { + htab_mask = sdr & 0x000001FF; + hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; + } + mask = (htab_mask << sdr_sh) | sdr_mask; +#if defined (DEBUG_MMU) + if (loglevel != 0) { + fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX " mask " + PADDRX " " ADDRX "\n", sdr, sdr_sh, hash, mask, + page_mask); + } +#endif ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask); /* Secondary table address */ hash = (~hash) & vsid_mask; +#if defined (DEBUG_MMU) + if (loglevel != 0) { + fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX " mask " + PADDRX "\n", sdr, sdr_sh, hash, mask); + } +#endif ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask); #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B || - env->mmu_model == POWERPC_MMU_64BRIDGE) { + if (env->mmu_model == POWERPC_MMU_64B) { /* Only 5 bits of the page index are used in the AVPN */ ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); } else @@ -762,6 +866,27 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ret = ret2; } } +#if defined (DEBUG_MMU) + if (loglevel != 0) { + target_phys_addr_t curaddr; + uint32_t a0, a1, a2, a3; + fprintf(logfile, + "Page table: " PADDRX " len " PADDRX "\n", + sdr, mask + 0x80); + for (curaddr = sdr; curaddr < (sdr + mask + 0x80); + curaddr += 16) { + a0 = ldl_phys(curaddr); + a1 = ldl_phys(curaddr + 4); + a2 = ldl_phys(curaddr + 8); + a3 = ldl_phys(curaddr + 12); + if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) { + fprintf(logfile, + PADDRX ": %08x %08x %08x %08x\n", + curaddr, a0, a1, a2, a3); + } + } + } +#endif } else { #if defined (DEBUG_MMU) if (loglevel != 0) @@ -1103,7 +1228,6 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, break; #if defined(TARGET_PPC64) case POWERPC_MMU_64B: - case POWERPC_MMU_64BRIDGE: /* Real address are 60 bits long */ ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; ctx->prot |= PAGE_WRITE; @@ -1170,7 +1294,6 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, /* No break here */ #if defined(TARGET_PPC64) case POWERPC_MMU_64B: - case POWERPC_MMU_64BRIDGE: #endif if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ @@ -1275,7 +1398,6 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, case POWERPC_MMU_32B: #if defined(TARGET_PPC64) case POWERPC_MMU_64B: - case POWERPC_MMU_64BRIDGE: #endif env->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x40000000; @@ -1371,7 +1493,6 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, case POWERPC_MMU_32B: #if defined(TARGET_PPC64) case POWERPC_MMU_64B: - case POWERPC_MMU_64BRIDGE: #endif env->exception_index = POWERPC_EXCP_DSI; env->error_code = 0; @@ -1622,13 +1743,12 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) case POWERPC_MMU_32B: #if defined(TARGET_PPC64) case POWERPC_MMU_64B: - case POWERPC_MMU_64BRIDGE: #endif /* defined(TARGET_PPC64) */ tlb_flush(env, 1); break; default: /* XXX: TODO */ - cpu_abort(env, "Unknown MMU model %d\n", env->mmu_model); + cpu_abort(env, "Unknown MMU model\n"); break; } } @@ -1688,7 +1808,6 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) break; #if defined(TARGET_PPC64) case POWERPC_MMU_64B: - case POWERPC_MMU_64BRIDGE: /* tlbie invalidate TLBs for all segments */ /* XXX: given the fact that there are too many segments to invalidate, * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu, @@ -1699,7 +1818,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) #endif /* defined(TARGET_PPC64) */ default: /* XXX: TODO */ - cpu_abort(env, "Unknown MMU model 2\n"); + cpu_abort(env, "Unknown MMU model\n"); break; } #else @@ -1752,15 +1871,20 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value) } #endif if (env->sdr1 != value) { + /* XXX: for PowerPC 64, should check that the HTABSIZE value + * is <= 28 + */ env->sdr1 = value; tlb_flush(env, 1); } } +#if 0 // Unused target_ulong do_load_sr (CPUPPCState *env, int srnum) { return env->sr[srnum]; } +#endif void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) { diff --git a/target-ppc/op.c b/target-ppc/op.c index 2c0235031..2dc058efb 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -317,6 +317,20 @@ void OPPROTO op_store_sr (void) RETURN(); } +#if defined(TARGET_PPC64) +void OPPROTO op_load_slb (void) +{ + T0 = ppc_load_slb(env, T1); + RETURN(); +} + +void OPPROTO op_store_slb (void) +{ + ppc_store_slb(env, T1, T0); + RETURN(); +} +#endif /* defined(TARGET_PPC64) */ + void OPPROTO op_load_sdr1 (void) { T0 = env->sdr1; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 77486f3b6..bc6336b0c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -385,107 +385,107 @@ static inline target_ulong MASK (uint32_t start, uint32_t end) /* PowerPC Instructions types definitions */ enum { PPC_NONE = 0x0000000000000000ULL, - /* integer operations instructions */ - /* flow control instructions */ - /* virtual memory instructions */ - /* ld/st with reservation instructions */ - /* cache control instructions */ - /* spr/msr access instructions */ + /* PowerPC base instructions set */ PPC_INSNS_BASE = 0x0000000000000001ULL, + /* integer operations instructions */ #define PPC_INTEGER PPC_INSNS_BASE + /* flow control instructions */ #define PPC_FLOW PPC_INSNS_BASE + /* virtual memory instructions */ #define PPC_MEM PPC_INSNS_BASE + /* ld/st with reservation instructions */ #define PPC_RES PPC_INSNS_BASE + /* cache control instructions */ #define PPC_CACHE PPC_INSNS_BASE + /* spr/msr access instructions */ #define PPC_MISC PPC_INSNS_BASE - /* Optional floating point instructions */ + /* Optional floating point instructions */ PPC_FLOAT = 0x0000000000000002ULL, PPC_FLOAT_FSQRT = 0x0000000000000004ULL, PPC_FLOAT_FRES = 0x0000000000000008ULL, PPC_FLOAT_FRSQRTE = 0x0000000000000010ULL, PPC_FLOAT_FSEL = 0x0000000000000020ULL, PPC_FLOAT_STFIWX = 0x0000000000000040ULL, - /* external control instructions */ + /* external control instructions */ PPC_EXTERN = 0x0000000000000080ULL, - /* segment register access instructions */ + /* segment register access instructions */ PPC_SEGMENT = 0x0000000000000100ULL, - /* Optional cache control instruction */ + /* Optional cache control instruction */ PPC_CACHE_DCBA = 0x0000000000000200ULL, - /* Optional memory control instructions */ + /* Optional memory control instructions */ PPC_MEM_TLBIA = 0x0000000000000400ULL, PPC_MEM_TLBIE = 0x0000000000000800ULL, PPC_MEM_TLBSYNC = 0x0000000000001000ULL, - /* eieio & sync */ + /* eieio & sync */ PPC_MEM_SYNC = 0x0000000000002000ULL, - /* PowerPC 6xx TLB management instructions */ + /* PowerPC 6xx TLB management instructions */ PPC_6xx_TLB = 0x0000000000004000ULL, - /* Altivec support */ + /* Altivec support */ PPC_ALTIVEC = 0x0000000000008000ULL, - /* Time base mftb instruction */ + /* Time base mftb instruction */ PPC_MFTB = 0x0000000000010000ULL, - /* Embedded PowerPC dedicated instructions */ + /* Embedded PowerPC dedicated instructions */ PPC_EMB_COMMON = 0x0000000000020000ULL, - /* PowerPC 40x exception model */ + /* PowerPC 40x exception model */ PPC_40x_EXCP = 0x0000000000040000ULL, - /* PowerPC 40x TLB management instructions */ + /* PowerPC 40x TLB management instructions */ PPC_40x_TLB = 0x0000000000080000ULL, - /* PowerPC 405 Mac instructions */ + /* PowerPC 405 Mac instructions */ PPC_405_MAC = 0x0000000000100000ULL, - /* PowerPC 440 specific instructions */ + /* PowerPC 440 specific instructions */ PPC_440_SPEC = 0x0000000000200000ULL, - /* Power-to-PowerPC bridge (601) */ + /* Power-to-PowerPC bridge (601) */ PPC_POWER_BR = 0x0000000000400000ULL, - /* PowerPC 602 specific */ + /* PowerPC 602 specific */ PPC_602_SPEC = 0x0000000000800000ULL, - /* Deprecated instructions */ - /* Original POWER instruction set */ + /* Deprecated instructions */ + /* Original POWER instruction set */ PPC_POWER = 0x0000000001000000ULL, - /* POWER2 instruction set extension */ + /* POWER2 instruction set extension */ PPC_POWER2 = 0x0000000002000000ULL, - /* Power RTC support */ + /* Power RTC support */ PPC_POWER_RTC = 0x0000000004000000ULL, - /* 64 bits PowerPC instructions */ - /* 64 bits PowerPC instruction set */ + /* 64 bits PowerPC instruction set */ PPC_64B = 0x0000000008000000ULL, - /* 64 bits hypervisor extensions */ + /* 64 bits hypervisor extensions */ PPC_64H = 0x0000000010000000ULL, - /* 64 bits PowerPC "bridge" features */ - PPC_64_BRIDGE = 0x0000000020000000ULL, - /* BookE (embedded) PowerPC specification */ + /* segment register access instructions for PowerPC 64 "bridge" */ + PPC_SEGMENT_64B = 0x0000000020000000ULL, + /* BookE (embedded) PowerPC specification */ PPC_BOOKE = 0x0000000040000000ULL, - /* eieio */ + /* eieio */ PPC_MEM_EIEIO = 0x0000000080000000ULL, - /* e500 vector instructions */ + /* e500 vector instructions */ PPC_E500_VECTOR = 0x0000000100000000ULL, - /* PowerPC 4xx dedicated instructions */ + /* PowerPC 4xx dedicated instructions */ PPC_4xx_COMMON = 0x0000000200000000ULL, - /* PowerPC 2.03 specification extensions */ + /* PowerPC 2.03 specification extensions */ PPC_203 = 0x0000000400000000ULL, - /* PowerPC 2.03 SPE extension */ + /* PowerPC 2.03 SPE extension */ PPC_SPE = 0x0000000800000000ULL, - /* PowerPC 2.03 SPE floating-point extension */ + /* PowerPC 2.03 SPE floating-point extension */ PPC_SPEFPU = 0x0000001000000000ULL, - /* SLB management */ + /* SLB management */ PPC_SLBI = 0x0000002000000000ULL, - /* PowerPC 40x ibct instructions */ + /* PowerPC 40x ibct instructions */ PPC_40x_ICBT = 0x0000004000000000ULL, - /* PowerPC 74xx TLB management instructions */ + /* PowerPC 74xx TLB management instructions */ PPC_74xx_TLB = 0x0000008000000000ULL, - /* More BookE (embedded) instructions... */ + /* More BookE (embedded) instructions... */ PPC_BOOKE_EXT = 0x0000010000000000ULL, - /* rfmci is not implemented in all BookE PowerPC */ + /* rfmci is not implemented in all BookE PowerPC */ PPC_RFMCI = 0x0000020000000000ULL, - /* user-mode DCR access, implemented in PowerPC 460 */ + /* user-mode DCR access, implemented in PowerPC 460 */ PPC_DCRUX = 0x0000040000000000ULL, - /* New floating-point extensions (PowerPC 2.0x) */ + /* New floating-point extensions (PowerPC 2.0x) */ PPC_FLOAT_EXT = 0x0000080000000000ULL, - /* New wait instruction (PowerPC 2.0x) */ + /* New wait instruction (PowerPC 2.0x) */ PPC_WAIT = 0x0000100000000000ULL, - /* New 64 bits extensions (PowerPC 2.0x) */ + /* New 64 bits extensions (PowerPC 2.0x) */ PPC_64BX = 0x0000200000000000ULL, - /* dcbz instruction with fixed cache line size */ + /* dcbz instruction with fixed cache line size */ PPC_CACHE_DCBZ = 0x0000400000000000ULL, - /* dcbz instruction with tunable cache line size */ + /* dcbz instruction with tunable cache line size */ PPC_CACHE_DCBZT = 0x0000800000000000ULL, }; @@ -3931,6 +3931,75 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) #endif } +#if defined(TARGET_PPC64) +/* Specific implementation for PowerPC 64 "bridge" emulation using SLB */ +/* mfsr */ +GEN_HANDLER(mfsr_64b, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B) +{ +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + GEN_EXCP_PRIVREG(ctx); + return; + } + gen_op_set_T1(SR(ctx->opcode)); + gen_op_load_slb(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* mfsrin */ +GEN_HANDLER(mfsrin_64b, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT_64B) +{ +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + GEN_EXCP_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_srli_T1(28); + gen_op_load_slb(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* mtsr */ +GEN_HANDLER(mtsr_64b, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B) +{ +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + GEN_EXCP_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SR(ctx->opcode)); + gen_op_store_slb(); +#endif +} + +/* mtsrin */ +GEN_HANDLER(mtsrin_64b, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT_64B) +{ +#if defined(CONFIG_USER_ONLY) + GEN_EXCP_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + GEN_EXCP_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_srli_T1(28); + gen_op_store_slb(); +#endif +} +#endif /* defined(TARGET_PPC64) */ + /*** Lookaside buffer management ***/ /* Optional & supervisor only: */ /* tlbia */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 834c047f3..8bc6209df 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3095,12 +3095,13 @@ static void init_proc_e500 (CPUPPCState *env) /* Non-embedded PowerPC */ /* Base instructions set for all 6xx/7xx/74xx/970 PowerPC */ #define POWERPC_INSNS_6xx (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \ - PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE) + PPC_MEM_EIEIO | PPC_MEM_TLBIE) /* Instructions common to all 6xx/7xx/74xx/970 PowerPC except 601 & 602 */ #define POWERPC_INSNS_WORKS (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT | \ PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ - PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ | PPC_MFTB) + PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ | PPC_MFTB | \ + PPC_SEGMENT) /* POWER : same as 601, without mfmsr, mfsr */ #if defined(TODO) @@ -3111,7 +3112,7 @@ static void init_proc_e500 (CPUPPCState *env) /* PowerPC 601 */ #define POWERPC_INSNS_601 (POWERPC_INSNS_6xx | PPC_CACHE_DCBZ | \ - PPC_EXTERN | PPC_POWER_BR) + PPC_SEGMENT | PPC_EXTERN | PPC_POWER_BR) #define POWERPC_MSRM_601 (0x000000000000FE70ULL) //#define POWERPC_MMU_601 (POWERPC_MMU_601) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) @@ -3164,7 +3165,7 @@ static void init_proc_601 (CPUPPCState *env) PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ |\ - PPC_602_SPEC) + PPC_SEGMENT | PPC_602_SPEC) #define POWERPC_MSRM_602 (0x000000000033FF73ULL) #define POWERPC_MMU_602 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_602 (POWERPC_EXCP_602) @@ -3942,15 +3943,15 @@ static void init_proc_7455 (CPUPPCState *env) #if defined (TARGET_PPC64) #define POWERPC_INSNS_WORK64 (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT | \ - PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ - PPC_MEM_TLBSYNC | PPC_CACHE_DCBZT | PPC_MFTB) + PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ + PPC_MEM_TLBSYNC | PPC_CACHE_DCBZT | PPC_MFTB) /* PowerPC 970 */ #define POWERPC_INSNS_970 (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ - PPC_64_BRIDGE | PPC_SLBI) + PPC_SEGMENT_64B | PPC_SLBI) #define POWERPC_MSRM_970 (0x900000000204FF36ULL) -#define POWERPC_MMU_970 (POWERPC_MMU_64BRIDGE) +#define POWERPC_MMU_970 (POWERPC_MMU_64B) //#define POWERPC_EXCP_970 (POWERPC_EXCP_970) #define POWERPC_INPUT_970 (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970 (bfd_mach_ppc64) @@ -3990,9 +3991,24 @@ static void init_proc_970 (CPUPPCState *env) /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); -#if 0 // TODO - env->slb_nr = 32; + /* XXX : not implemented */ + spr_register(env, SPR_MMUCFG, "MMUCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* XXX : not implemented */ + spr_register(env, SPR_MMUCSR0, "MMUCSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* TOFIX */ + spr_register(env, SPR_HIOR, "SPR_HIOR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFF00000); /* XXX: This is a hack */ +#if !defined(CONFIG_USER_ONLY) + env->excp_prefix = 0xFFF00000; #endif + env->slb_nr = 32; init_excp_970(env); env->dcache_line_size = 128; env->icache_line_size = 128; @@ -4003,9 +4019,9 @@ static void init_proc_970 (CPUPPCState *env) /* PowerPC 970FX (aka G5) */ #define POWERPC_INSNS_970FX (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ - PPC_64_BRIDGE | PPC_SLBI) + PPC_SEGMENT_64B | PPC_SLBI) #define POWERPC_MSRM_970FX (0x800000000204FF36ULL) -#define POWERPC_MMU_970FX (POWERPC_MMU_64BRIDGE) +#define POWERPC_MMU_970FX (POWERPC_MMU_64B) #define POWERPC_EXCP_970FX (POWERPC_EXCP_970) #define POWERPC_INPUT_970FX (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970FX (bfd_mach_ppc64) @@ -4045,9 +4061,24 @@ static void init_proc_970FX (CPUPPCState *env) /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); -#if 0 // TODO - env->slb_nr = 32; + /* XXX : not implemented */ + spr_register(env, SPR_MMUCFG, "MMUCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* XXX : not implemented */ + spr_register(env, SPR_MMUCSR0, "MMUCSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* TOFIX */ + spr_register(env, SPR_HIOR, "SPR_HIOR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFF00000); /* XXX: This is a hack */ +#if !defined(CONFIG_USER_ONLY) + env->excp_prefix = 0xFFF00000; #endif + env->slb_nr = 32; init_excp_970(env); env->dcache_line_size = 128; env->icache_line_size = 128; @@ -4058,9 +4089,9 @@ static void init_proc_970FX (CPUPPCState *env) /* PowerPC 970 GX */ #define POWERPC_INSNS_970GX (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_ALTIVEC | \ - PPC_64_BRIDGE | PPC_SLBI) + PPC_SEGMENT_64B | PPC_SLBI) #define POWERPC_MSRM_970GX (0x800000000204FF36ULL) -#define POWERPC_MMU_970GX (POWERPC_MMU_64BRIDGE) +#define POWERPC_MMU_970GX (POWERPC_MMU_64B) #define POWERPC_EXCP_970GX (POWERPC_EXCP_970) #define POWERPC_INPUT_970GX (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970GX (bfd_mach_ppc64) @@ -4100,9 +4131,24 @@ static void init_proc_970GX (CPUPPCState *env) /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); -#if 0 // TODO - env->slb_nr = 32; + /* XXX : not implemented */ + spr_register(env, SPR_MMUCFG, "MMUCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* XXX : not implemented */ + spr_register(env, SPR_MMUCSR0, "MMUCSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* TOFIX */ + spr_register(env, SPR_HIOR, "SPR_HIOR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFF00000); /* XXX: This is a hack */ +#if !defined(CONFIG_USER_ONLY) + env->excp_prefix = 0xFFF00000; #endif + env->slb_nr = 32; init_excp_970(env); env->dcache_line_size = 128; env->icache_line_size = 128; @@ -6010,9 +6056,6 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) case POWERPC_MMU_64B: mmu_model = "PowerPC 64"; break; - case POWERPC_MMU_64BRIDGE: - mmu_model = "PowerPC 64 bridge"; - break; #endif default: mmu_model = "Unknown or invalid"; -- cgit v1.2.3 From aa6ad6fee28653943bb2ce2f48d7ed61c4d6d603 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 6 Oct 2007 11:24:18 +0000 Subject: Support for loading a real BIOS image (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3336 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index f9961c773..d2b6b7b88 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -49,7 +49,7 @@ #define KERNEL_LOAD_ADDR 0x00004000 #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 -#define PROM_SIZE_MAX (256 * 1024) +#define PROM_SIZE_MAX (512 * 1024) #define PROM_PADDR 0xff0000000ULL #define PROM_VADDR 0xffd00000 #define PROM_FILENAME "openbios-sparc32" @@ -434,10 +434,12 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, bios_name = PROM_FILENAME; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); ret = load_elf(buf, PROM_PADDR - PROM_VADDR, NULL, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "qemu: could not load prom '%s'\n", - buf); - exit(1); + if (ret < 0 || ret > PROM_SIZE_MAX) + ret = load_image(buf, phys_ram_base + prom_offset); + if (ret < 0 || ret > PROM_SIZE_MAX) { + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); } kernel_size = 0; -- cgit v1.2.3 From 81732d1926fd50283e12b0abdcbbe8242c8bb29c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 6 Oct 2007 11:25:43 +0000 Subject: Implement user mode for timers git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3337 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_timer.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++--------- hw/sun4m.c | 11 +++---- vl.h | 3 +- 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index d3c75bf3a..80fe15a6c 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -47,6 +47,8 @@ do { printf("TIMER: " fmt , ##args); } while (0) * */ +#define MAX_CPUS 16 + typedef struct SLAVIO_TIMERState { qemu_irq irq; ptimer_state *timer; @@ -54,10 +56,13 @@ typedef struct SLAVIO_TIMERState { uint64_t limit; int stopped; int mode; // 0 = processor, 1 = user, 2 = system + struct SLAVIO_TIMERState *slave[MAX_CPUS]; + uint32_t slave_mode; } SLAVIO_TIMERState; #define TIMER_MAXADDR 0x1f #define TIMER_SIZE (TIMER_MAXADDR + 1) +#define CPU_TIMER_SIZE 0x10 // Update count, set irq, update expire_time // Convert from ptimer countdown units @@ -120,7 +125,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) break; case 4: // read user/system mode - ret = s->mode & 1; + ret = s->slave_mode; break; default: ret = 0; @@ -141,10 +146,20 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { case 0: - // set limit, reset counter + if (s->mode == 1) { + // set user counter limit MSW, reset counter + qemu_irq_lower(s->irq); + s->limit &= 0xfffffe00ULL; + s->limit |= (uint64_t)val << 32; + if (!s->limit) + s->limit = 0x7ffffffffffffe00ULL; + ptimer_set_limit(s->timer, s->limit >> 9, 1); + break; + } + // set limit, reset counter reload = 1; - qemu_irq_lower(s->irq); - // fall through + qemu_irq_lower(s->irq); + // fall through case 2: // set limit without resetting counter s->limit = val & 0x7ffffe00ULL; @@ -152,6 +167,17 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 s->limit = 0x7ffffe00ULL; ptimer_set_limit(s->timer, s->limit >> 9, reload); break; + case 1: + // set user counter limit LSW, reset counter + if (s->mode == 1) { + qemu_irq_lower(s->irq); + s->limit &= 0x7fffffff00000000ULL; + s->limit |= val & 0xfffffe00ULL; + if (!s->limit) + s->limit = 0x7ffffffffffffe00ULL; + ptimer_set_limit(s->timer, s->limit >> 9, 1); + } + break; case 3: // start/stop user counter if (s->mode == 1) { @@ -167,13 +193,24 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 break; case 4: // bit 0: user (1) or system (0) counter mode - if (s->mode == 0 || s->mode == 1) - s->mode = val & 1; - if (s->mode == 1) { - qemu_irq_lower(s->irq); - s->limit = -1ULL; + { + unsigned int i; + + for (i = 0; i < MAX_CPUS; i++) { + if (val & (1 << i)) { + qemu_irq_lower(s->slave[i]->irq); + s->slave[i]->limit = -1ULL; + s->slave[i]->mode = 1; + } else { + s->slave[i]->mode = 0; + } + ptimer_stop(s->slave[i]->timer); + ptimer_set_limit(s->slave[i]->timer, s->slave[i]->limit >> 9, + 1); + ptimer_run(s->slave[i]->timer, 0); + } + s->slave_mode = val & ((1 << MAX_CPUS) - 1); } - ptimer_set_limit(s->timer, s->limit >> 9, 1); break; default: break; @@ -240,7 +277,8 @@ static void slavio_timer_reset(void *opaque) qemu_irq_lower(s->irq); } -void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) +static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, + qemu_irq irq, int mode) { int slavio_timer_io_memory; SLAVIO_TIMERState *s; @@ -248,7 +286,7 @@ void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); if (!s) - return; + return s; s->irq = irq; s->mode = mode; bh = qemu_bh_new(slavio_timer_irq, s); @@ -257,8 +295,29 @@ void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode) slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, slavio_timer_mem_write, s); - cpu_register_physical_memory(addr, TIMER_SIZE, slavio_timer_io_memory); + if (mode < 2) + cpu_register_physical_memory(addr, CPU_TIMER_SIZE, slavio_timer_io_memory); + else + cpu_register_physical_memory(addr, TIMER_SIZE, + slavio_timer_io_memory); register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s); qemu_register_reset(slavio_timer_reset, s); slavio_timer_reset(s); + + return s; +} + +void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, + qemu_irq *cpu_irqs) +{ + SLAVIO_TIMERState *master; + unsigned int i; + + master = slavio_timer_init(base + 0x10000ULL, master_irq, 2); + + for (i = 0; i < MAX_CPUS; i++) { + master->slave[i] = slavio_timer_init(base + (target_phys_addr_t) + (i * TARGET_PAGE_SIZE), + cpu_irqs[i], 0); + } } diff --git a/hw/sun4m.c b/hw/sun4m.c index d2b6b7b88..af96474bf 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -380,13 +380,10 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, hwdef->nvram_size, 8); - for (i = 0; i < MAX_CPUS; i++) { - slavio_timer_init(hwdef->counter_base + - (target_phys_addr_t)(i * TARGET_PAGE_SIZE), - slavio_cpu_irq[i], 0); - } - slavio_timer_init(hwdef->counter_base + 0x10000ULL, - slavio_irq[hwdef->clock1_irq], 2); + + slavio_timer_init_all(hwdef->counter_base, slavio_irq[hwdef->clock1_irq], + slavio_cpu_irq); + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device diff --git a/vl.h b/vl.h index 7a3d22c90..45032c8d3 100644 --- a/vl.h +++ b/vl.h @@ -1287,7 +1287,8 @@ int load_aout(const char *filename, uint8_t *addr); int load_uboot(const char *filename, target_ulong *ep, int *is_linux); /* slavio_timer.c */ -void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode); +void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, + qemu_irq *cpu_irqs); /* slavio_serial.c */ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, -- cgit v1.2.3 From f930d07eda320b221360556eaa0c695c48173567 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 6 Oct 2007 11:28:21 +0000 Subject: More detabification git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3338 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apb_pci.c | 16 +- hw/cs4231.c | 6 +- hw/esp.c | 158 +- hw/iommu.c | 100 +- hw/slavio_intctl.c | 66 +- hw/slavio_misc.c | 106 +- hw/slavio_serial.c | 194 +-- hw/slavio_timer.c | 68 +- hw/sun4m.c | 44 +- hw/sun4u.c | 46 +- hw/tcx.c | 112 +- sparc-dis.c | 4082 ++++++++++++++++++++++++++-------------------------- sparc.ld | 48 +- sparc64.ld | 48 +- 14 files changed, 2547 insertions(+), 2547 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 1de335384..fe9189247 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -70,7 +70,7 @@ static CPUReadMemoryFunc *pci_apb_config_read[] = { }; static void apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) + uint32_t val) { //PCIBus *s = opaque; @@ -80,14 +80,14 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr, case 0x18: // AFAR case 0x20: // Diagnostic case 0x28: // Target address space - // XXX + // XXX default: - break; + break; } } static uint32_t apb_config_readl (void *opaque, - target_phys_addr_t addr) + target_phys_addr_t addr) { //PCIBus *s = opaque; uint32_t val; @@ -98,10 +98,10 @@ static uint32_t apb_config_readl (void *opaque, case 0x18: // AFAR case 0x20: // Diagnostic case 0x28: // Target address space - // XXX + // XXX default: - val = 0; - break; + val = 0; + break; } return val; } @@ -222,7 +222,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, pci_apb_config_write, s); apb_config = cpu_register_io_memory(0, apb_config_read, - apb_config_write, s); + apb_config_write, s); pci_mem_data = cpu_register_io_memory(0, pci_apb_read, pci_apb_write, s); pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, diff --git a/hw/cs4231.c b/hw/cs4231.c index 390ef746f..982980038 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -79,11 +79,11 @@ static uint32_t cs_mem_readl(void *opaque, target_phys_addr_t addr) break; } DPRINTF("read dreg[%d]: 0x%8.8x\n", CS_RAP(s), ret); - break; + break; default: ret = s->regs[saddr]; DPRINTF("read reg[%d]: 0x%8.8x\n", saddr, ret); - break; + break; } return ret; } @@ -122,7 +122,7 @@ static void cs_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) break; default: s->regs[saddr] = val; - break; + break; } } diff --git a/hw/esp.c b/hw/esp.c index 943a159e0..96c6b3493 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -107,9 +107,9 @@ static int get_cmd(ESPState *s, uint8_t *buf) if (s->dma) { espdma_memory_read(s->dma_opaque, buf, dmalen); } else { - buf[0] = 0; - memcpy(&buf[1], s->ti_buf, dmalen); - dmalen++; + buf[0] = 0; + memcpy(&buf[1], s->ti_buf, dmalen); + dmalen++; } s->ti_size = 0; @@ -124,11 +124,11 @@ static int get_cmd(ESPState *s, uint8_t *buf) if (target >= MAX_DISKS || !s->scsi_dev[target]) { // No such drive - s->rregs[4] = STAT_IN; - s->rregs[5] = INTR_DC; - s->rregs[6] = SEQ_0; - qemu_irq_raise(s->irq); - return 0; + s->rregs[4] = STAT_IN; + s->rregs[5] = INTR_DC; + s->rregs[6] = SEQ_0; + qemu_irq_raise(s->irq); + return 0; } s->current_dev = s->scsi_dev[target]; return dmalen; @@ -190,14 +190,14 @@ static void write_response(ESPState *s) s->ti_buf[1] = 0; if (s->dma) { espdma_memory_write(s->dma_opaque, s->ti_buf, 2); - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS | INTR_FC; - s->rregs[6] = SEQ_CD; + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; + s->rregs[5] = INTR_BS | INTR_FC; + s->rregs[6] = SEQ_CD; } else { - s->ti_size = 2; - s->ti_rptr = 0; - s->ti_wptr = 0; - s->rregs[7] = 2; + s->ti_size = 2; + s->ti_rptr = 0; + s->ti_wptr = 0; + s->rregs[7] = 2; } qemu_irq_raise(s->irq); } @@ -359,9 +359,9 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); switch (saddr) { case 2: - // FIFO - if (s->ti_size > 0) { - s->ti_size--; + // FIFO + if (s->ti_size > 0) { + s->ti_size--; if ((s->rregs[4] & 6) == 0) { /* Data in/out. */ fprintf(stderr, "esp: PIO data read not implemented\n"); @@ -370,20 +370,20 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) s->rregs[2] = s->ti_buf[s->ti_rptr++]; } qemu_irq_raise(s->irq); - } - if (s->ti_size == 0) { + } + if (s->ti_size == 0) { s->ti_rptr = 0; s->ti_wptr = 0; } - break; + break; case 5: // interrupt // Clear interrupt/error status bits s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE); - qemu_irq_lower(s->irq); + qemu_irq_lower(s->irq); break; default: - break; + break; } return s->rregs[saddr]; } @@ -401,7 +401,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) s->rregs[4] &= ~STAT_TC; break; case 2: - // FIFO + // FIFO if (s->do_cmd) { s->cmdbuf[s->cmdlen++] = val & 0xff; } else if ((s->rregs[4] & 6) == 0) { @@ -413,73 +413,73 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) s->ti_size++; s->ti_buf[s->ti_wptr++] = val & 0xff; } - break; + break; case 3: s->rregs[saddr] = val; - // Command - if (val & 0x80) { - s->dma = 1; + // Command + if (val & 0x80) { + s->dma = 1; /* Reload DMA counter. */ s->rregs[0] = s->wregs[0]; s->rregs[1] = s->wregs[1]; - } else { - s->dma = 0; - } - switch(val & 0x7f) { - case 0: - DPRINTF("NOP (%2.2x)\n", val); - break; - case 1: - DPRINTF("Flush FIFO (%2.2x)\n", val); + } else { + s->dma = 0; + } + switch(val & 0x7f) { + case 0: + DPRINTF("NOP (%2.2x)\n", val); + break; + case 1: + DPRINTF("Flush FIFO (%2.2x)\n", val); //s->ti_size = 0; - s->rregs[5] = INTR_FC; - s->rregs[6] = 0; - break; - case 2: - DPRINTF("Chip reset (%2.2x)\n", val); - esp_reset(s); - break; - case 3: - DPRINTF("Bus reset (%2.2x)\n", val); - s->rregs[5] = INTR_RST; + s->rregs[5] = INTR_FC; + s->rregs[6] = 0; + break; + case 2: + DPRINTF("Chip reset (%2.2x)\n", val); + esp_reset(s); + break; + case 3: + DPRINTF("Bus reset (%2.2x)\n", val); + s->rregs[5] = INTR_RST; if (!(s->wregs[8] & 0x40)) { qemu_irq_raise(s->irq); } - break; - case 0x10: - handle_ti(s); - break; - case 0x11: - DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); - write_response(s); - break; - case 0x12: - DPRINTF("Message Accepted (%2.2x)\n", val); - write_response(s); - s->rregs[5] = INTR_DC; - s->rregs[6] = 0; - break; - case 0x1a: - DPRINTF("Set ATN (%2.2x)\n", val); - break; - case 0x42: - DPRINTF("Set ATN (%2.2x)\n", val); - handle_satn(s); - break; - case 0x43: - DPRINTF("Set ATN & stop (%2.2x)\n", val); - handle_satn_stop(s); - break; + break; + case 0x10: + handle_ti(s); + break; + case 0x11: + DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); + write_response(s); + break; + case 0x12: + DPRINTF("Message Accepted (%2.2x)\n", val); + write_response(s); + s->rregs[5] = INTR_DC; + s->rregs[6] = 0; + break; + case 0x1a: + DPRINTF("Set ATN (%2.2x)\n", val); + break; + case 0x42: + DPRINTF("Set ATN (%2.2x)\n", val); + handle_satn(s); + break; + case 0x43: + DPRINTF("Set ATN & stop (%2.2x)\n", val); + handle_satn_stop(s); + break; case 0x44: DPRINTF("Enable selection (%2.2x)\n", val); break; - default: - DPRINTF("Unhandled ESP command (%2.2x)\n", val); - break; - } - break; + default: + DPRINTF("Unhandled ESP command (%2.2x)\n", val); + break; + } + break; case 4 ... 7: - break; + break; case 8: s->rregs[saddr] = val; break; @@ -492,7 +492,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) s->rregs[saddr] = val; break; default: - break; + break; } s->wregs[saddr] = val; } diff --git a/hw/iommu.c b/hw/iommu.c index 0ee8c718e..55d39b9fd 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -81,7 +81,7 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ #define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ #define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses - produced by this device as pure + produced by this device as pure physical. */ #define IOMMU_SBCFG_MASK 0x00010003 @@ -98,7 +98,7 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define PAGE_SHIFT 12 #define PAGE_SIZE (1 << PAGE_SHIFT) -#define PAGE_MASK (PAGE_SIZE - 1) +#define PAGE_MASK (PAGE_SIZE - 1) typedef struct IOMMUState { target_phys_addr_t addr; @@ -114,9 +114,9 @@ static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) saddr = (addr - s->addr) >> 2; switch (saddr) { default: - DPRINTF("read reg[%d] = %x\n", (int)saddr, s->regs[saddr]); - return s->regs[saddr]; - break; + DPRINTF("read reg[%d] = %x\n", (int)saddr, s->regs[saddr]); + return s->regs[saddr]; + break; } return 0; } @@ -130,61 +130,61 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val DPRINTF("write reg[%d] = %x\n", (int)saddr, val); switch (saddr) { case IOMMU_CTRL: - switch (val & IOMMU_CTRL_RNGE) { - case IOMMU_RNGE_16MB: - s->iostart = 0xffffffffff000000ULL; - break; - case IOMMU_RNGE_32MB: - s->iostart = 0xfffffffffe000000ULL; - break; - case IOMMU_RNGE_64MB: - s->iostart = 0xfffffffffc000000ULL; - break; - case IOMMU_RNGE_128MB: - s->iostart = 0xfffffffff8000000ULL; - break; - case IOMMU_RNGE_256MB: - s->iostart = 0xfffffffff0000000ULL; - break; - case IOMMU_RNGE_512MB: - s->iostart = 0xffffffffe0000000ULL; - break; - case IOMMU_RNGE_1GB: - s->iostart = 0xffffffffc0000000ULL; - break; - default: - case IOMMU_RNGE_2GB: - s->iostart = 0xffffffff80000000ULL; - break; - } - DPRINTF("iostart = " TARGET_FMT_plx "\n", s->iostart); - s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION); - break; + switch (val & IOMMU_CTRL_RNGE) { + case IOMMU_RNGE_16MB: + s->iostart = 0xffffffffff000000ULL; + break; + case IOMMU_RNGE_32MB: + s->iostart = 0xfffffffffe000000ULL; + break; + case IOMMU_RNGE_64MB: + s->iostart = 0xfffffffffc000000ULL; + break; + case IOMMU_RNGE_128MB: + s->iostart = 0xfffffffff8000000ULL; + break; + case IOMMU_RNGE_256MB: + s->iostart = 0xfffffffff0000000ULL; + break; + case IOMMU_RNGE_512MB: + s->iostart = 0xffffffffe0000000ULL; + break; + case IOMMU_RNGE_1GB: + s->iostart = 0xffffffffc0000000ULL; + break; + default: + case IOMMU_RNGE_2GB: + s->iostart = 0xffffffff80000000ULL; + break; + } + DPRINTF("iostart = " TARGET_FMT_plx "\n", s->iostart); + s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION); + break; case IOMMU_BASE: - s->regs[saddr] = val & IOMMU_BASE_MASK; - break; + s->regs[saddr] = val & IOMMU_BASE_MASK; + break; case IOMMU_TLBFLUSH: - DPRINTF("tlb flush %x\n", val); - s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK; - break; + DPRINTF("tlb flush %x\n", val); + s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK; + break; case IOMMU_PGFLUSH: - DPRINTF("page flush %x\n", val); - s->regs[saddr] = val & IOMMU_PGFLUSH_MASK; - break; + DPRINTF("page flush %x\n", val); + s->regs[saddr] = val & IOMMU_PGFLUSH_MASK; + break; case IOMMU_SBCFG0: case IOMMU_SBCFG1: case IOMMU_SBCFG2: case IOMMU_SBCFG3: - s->regs[saddr] = val & IOMMU_SBCFG_MASK; - break; + s->regs[saddr] = val & IOMMU_SBCFG_MASK; + break; case IOMMU_ARBEN: // XXX implement SBus probing: fault when reading unmapped // addresses, fault cause and address stored to MMU/IOMMU - s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID; - break; + s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID; + break; default: - s->regs[saddr] = val; - break; + s->regs[saddr] = val; + break; } } @@ -283,7 +283,7 @@ static void iommu_save(QEMUFile *f, void *opaque) int i; for (i = 0; i < IOMMU_NREGS; i++) - qemu_put_be32s(f, &s->regs[i]); + qemu_put_be32s(f, &s->regs[i]); qemu_put_be64s(f, &s->iostart); } diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index f604702f8..541222877 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -100,21 +100,21 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, val); switch (saddr) { case 1: // clear pending softints - if (val & 0x4000) - val |= 80000000; - val &= 0xfffe0000; - s->intreg_pending[cpu] &= ~val; + if (val & 0x4000) + val |= 80000000; + val &= 0xfffe0000; + s->intreg_pending[cpu] &= ~val; slavio_check_interrupts(s); - DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); - break; + DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); + break; case 2: // set softint - val &= 0xfffe0000; - s->intreg_pending[cpu] |= val; + val &= 0xfffe0000; + s->intreg_pending[cpu] |= val; slavio_check_interrupts(s); - DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); - break; + DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); + break; default: - break; + break; } } @@ -165,27 +165,27 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val); switch (saddr) { case 2: // clear (enable) - // Force clear unused bits - val &= ~0x4fb2007f; - s->intregm_disabled &= ~val; - DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); - slavio_check_interrupts(s); - break; + // Force clear unused bits + val &= ~0x4fb2007f; + s->intregm_disabled &= ~val; + DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); + slavio_check_interrupts(s); + break; case 3: // set (disable, clear pending) - // Force clear unused bits - val &= ~0x4fb2007f; - s->intregm_disabled |= val; - s->intregm_pending &= ~val; + // Force clear unused bits + val &= ~0x4fb2007f; + s->intregm_disabled |= val; + s->intregm_pending &= ~val; slavio_check_interrupts(s); - DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); - break; + DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); + break; case 4: - s->target_cpu = val & (MAX_CPUS - 1); + s->target_cpu = val & (MAX_CPUS - 1); slavio_check_interrupts(s); - DPRINTF("Set master irq cpu %d\n", s->target_cpu); - break; + DPRINTF("Set master irq cpu %d\n", s->target_cpu); + break; default: - break; + break; } } @@ -207,7 +207,7 @@ void slavio_pic_info(void *opaque) int i; for (i = 0; i < MAX_CPUS; i++) { - term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); + term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); } term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled); } @@ -310,7 +310,7 @@ static void slavio_intctl_save(QEMUFile *f, void *opaque) int i; for (i = 0; i < MAX_CPUS; i++) { - qemu_put_be32s(f, &s->intreg_pending[i]); + qemu_put_be32s(f, &s->intreg_pending[i]); } qemu_put_be32s(f, &s->intregm_pending); qemu_put_be32s(f, &s->intregm_disabled); @@ -326,7 +326,7 @@ static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) return -EINVAL; for (i = 0; i < MAX_CPUS; i++) { - qemu_get_be32s(f, &s->intreg_pending[i]); + qemu_get_be32s(f, &s->intreg_pending[i]); } qemu_get_be32s(f, &s->intregm_pending); qemu_get_be32s(f, &s->intregm_disabled); @@ -341,7 +341,7 @@ static void slavio_intctl_reset(void *opaque) int i; for (i = 0; i < MAX_CPUS; i++) { - s->intreg_pending[i] = 0; + s->intreg_pending[i] = 0; } s->intregm_disabled = ~0xffb2007f; s->intregm_pending = 0; @@ -363,8 +363,8 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, s->intbit_to_level = intbit_to_level; for (i = 0; i < MAX_CPUS; i++) { - slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); - cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, + slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); + cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, slavio_intctl_io_memory); s->cpu_irqs[i] = parent_irq[i]; } diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 34072c623..1a2c11a15 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -76,9 +76,9 @@ void slavio_set_power_fail(void *opaque, int power_failing) MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config); if (power_failing && (s->config & 0x8)) { - s->aux2 |= 0x4; + s->aux2 |= 0x4; } else { - s->aux2 &= ~0x4; + s->aux2 &= ~0x4; } slavio_misc_update_irq(s); } @@ -89,44 +89,44 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32 switch (addr & 0xfff0000) { case 0x1800000: - MISC_DPRINTF("Write config %2.2x\n", val & 0xff); - s->config = val & 0xff; - slavio_misc_update_irq(s); - break; + MISC_DPRINTF("Write config %2.2x\n", val & 0xff); + s->config = val & 0xff; + slavio_misc_update_irq(s); + break; case 0x1900000: - MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); - s->aux1 = val & 0xff; - break; + MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); + s->aux1 = val & 0xff; + break; case 0x1910000: - val &= 0x3; - MISC_DPRINTF("Write aux2 %2.2x\n", val); - val |= s->aux2 & 0x4; - if (val & 0x2) // Clear Power Fail int - val &= 0x1; - s->aux2 = val; - if (val & 1) - qemu_system_shutdown_request(); - slavio_misc_update_irq(s); - break; + val &= 0x3; + MISC_DPRINTF("Write aux2 %2.2x\n", val); + val |= s->aux2 & 0x4; + if (val & 0x2) // Clear Power Fail int + val &= 0x1; + s->aux2 = val; + if (val & 1) + qemu_system_shutdown_request(); + slavio_misc_update_irq(s); + break; case 0x1a00000: - MISC_DPRINTF("Write diag %2.2x\n", val & 0xff); - s->diag = val & 0xff; - break; + MISC_DPRINTF("Write diag %2.2x\n", val & 0xff); + s->diag = val & 0xff; + break; case 0x1b00000: - MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); - s->mctrl = val & 0xff; - break; + MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); + s->mctrl = val & 0xff; + break; case 0x1f00000: - MISC_DPRINTF("Write system control %2.2x\n", val & 0xff); - if (val & 1) { - s->sysctrl = 0x2; - qemu_system_reset_request(); - } - break; + MISC_DPRINTF("Write system control %2.2x\n", val & 0xff); + if (val & 1) { + s->sysctrl = 0x2; + qemu_system_reset_request(); + } + break; case 0xa000000: - MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); + MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); - break; + break; } } @@ -137,32 +137,32 @@ static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr) switch (addr & 0xfff0000) { case 0x1800000: - ret = s->config; - MISC_DPRINTF("Read config %2.2x\n", ret); - break; + ret = s->config; + MISC_DPRINTF("Read config %2.2x\n", ret); + break; case 0x1900000: - ret = s->aux1; - MISC_DPRINTF("Read aux1 %2.2x\n", ret); - break; + ret = s->aux1; + MISC_DPRINTF("Read aux1 %2.2x\n", ret); + break; case 0x1910000: - ret = s->aux2; - MISC_DPRINTF("Read aux2 %2.2x\n", ret); - break; + ret = s->aux2; + MISC_DPRINTF("Read aux2 %2.2x\n", ret); + break; case 0x1a00000: - ret = s->diag; - MISC_DPRINTF("Read diag %2.2x\n", ret); - break; + ret = s->diag; + MISC_DPRINTF("Read diag %2.2x\n", ret); + break; case 0x1b00000: - ret = s->mctrl; - MISC_DPRINTF("Read modem control %2.2x\n", ret); - break; + ret = s->mctrl; + MISC_DPRINTF("Read modem control %2.2x\n", ret); + break; case 0x1f00000: - MISC_DPRINTF("Read system control %2.2x\n", ret); - ret = s->sysctrl; - break; + MISC_DPRINTF("Read system control %2.2x\n", ret); + ret = s->sysctrl; + break; case 0xa000000: - MISC_DPRINTF("Read power management %2.2x\n", ret); - break; + MISC_DPRINTF("Read power management %2.2x\n", ret); + break; } return ret; } diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 1aa5e7a17..2eb3379b4 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -139,7 +139,7 @@ static uint32_t get_queue(void *opaque) int val; if (q->count == 0) { - return 0; + return 0; } else { val = q->data[q->rptr]; if (++q->rptr == SERIO_QUEUE_SIZE) @@ -148,17 +148,17 @@ static uint32_t get_queue(void *opaque) } SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val); if (q->count > 0) - serial_receive_byte(s, 0); + serial_receive_byte(s, 0); return val; } static int slavio_serial_update_irq_chn(ChannelState *s) { if ((s->wregs[1] & 1) && // interrupts enabled - (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending - ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && - s->rxint == 1) || // rx ints enabled, pending - ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p + (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending + ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && + s->rxint == 1) || // rx ints enabled, pending + ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p return 1; } return 0; @@ -181,8 +181,8 @@ static void slavio_serial_reset_chn(ChannelState *s) s->reg = 0; for (i = 0; i < SERIAL_SIZE; i++) { - s->rregs[i] = 0; - s->wregs[i] = 0; + s->rregs[i] = 0; + s->wregs[i] = 0; } s->wregs[4] = 4; s->wregs[9] = 0xc0; @@ -367,82 +367,82 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint s = &serial->chn[channel]; switch (saddr) { case 0: - SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff); - newreg = 0; - switch (s->reg) { - case 0: - newreg = val & 7; - val &= 0x38; - switch (val) { - case 8: - newreg |= 0x8; - break; - case 0x28: + SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff); + newreg = 0; + switch (s->reg) { + case 0: + newreg = val & 7; + val &= 0x38; + switch (val) { + case 8: + newreg |= 0x8; + break; + case 0x28: clr_txint(s); - break; - case 0x38: + break; + case 0x38: if (s->rxint_under_svc) clr_rxint(s); else if (s->txint_under_svc) clr_txint(s); - break; - default: - break; - } - break; + break; + default: + break; + } + break; case 1 ... 3: case 6 ... 8: case 10 ... 11: case 14 ... 15: - s->wregs[s->reg] = val; - break; + s->wregs[s->reg] = val; + break; case 4: case 5: case 12: case 13: - s->wregs[s->reg] = val; + s->wregs[s->reg] = val; slavio_serial_update_parameters(s); - break; - case 9: - switch (val & 0xc0) { - case 0: - default: - break; - case 0x40: - slavio_serial_reset_chn(&serial->chn[1]); - return; - case 0x80: - slavio_serial_reset_chn(&serial->chn[0]); - return; - case 0xc0: - slavio_serial_reset(serial); - return; - } - break; - default: - break; - } - if (s->reg == 0) - s->reg = newreg; - else - s->reg = 0; - break; + break; + case 9: + switch (val & 0xc0) { + case 0: + default: + break; + case 0x40: + slavio_serial_reset_chn(&serial->chn[1]); + return; + case 0x80: + slavio_serial_reset_chn(&serial->chn[0]); + return; + case 0xc0: + slavio_serial_reset(serial); + return; + } + break; + default: + break; + } + if (s->reg == 0) + s->reg = newreg; + else + s->reg = 0; + break; case 1: - SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val); + SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val); s->tx = val; - if (s->wregs[5] & 8) { // tx enabled - if (s->chr) - qemu_chr_write(s->chr, &s->tx, 1); - else if (s->type == kbd) { - handle_kbd_command(s, val); - } - } + if (s->wregs[5] & 8) { // tx enabled + if (s->chr) + qemu_chr_write(s->chr, &s->tx, 1); + else if (s->type == kbd) { + handle_kbd_command(s, val); + } + } s->rregs[0] |= 4; // Tx buffer empty s->rregs[1] |= 1; // All sent set_txint(s); - break; + break; default: - break; + break; } } @@ -459,21 +459,21 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) s = &serial->chn[channel]; switch (saddr) { case 0: - SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]); - ret = s->rregs[s->reg]; - s->reg = 0; - return ret; + SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]); + ret = s->rregs[s->reg]; + s->reg = 0; + return ret; case 1: - s->rregs[0] &= ~1; + s->rregs[0] &= ~1; clr_rxint(s); - if (s->type == kbd || s->type == mouse) - ret = get_queue(s); - else - ret = s->rx; - SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret); - return ret; + if (s->type == kbd || s->type == mouse) + ret = get_queue(s); + else + ret = s->rx; + SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret); + return ret; default: - break; + break; } return 0; } @@ -484,10 +484,10 @@ static int serial_can_receive(void *opaque) int ret; if (((s->wregs[3] & 1) == 0) // Rx not enabled - || ((s->rregs[0] & 1) == 1)) // char already available - ret = 0; + || ((s->rregs[0] & 1) == 1)) // char already available + ret = 0; else - ret = 1; + ret = 1; //SER_DPRINTF("channel %c can receive %d\n", CHN_C(s), ret); return ret; } @@ -584,7 +584,7 @@ static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) ret = slavio_serial_load_chn(f, &s->chn[0], version_id); if (ret != 0) - return ret; + return ret; ret = slavio_serial_load_chn(f, &s->chn[1], version_id); return ret; @@ -607,13 +607,13 @@ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, s->chn[1].chr = chr2; for (i = 0; i < 2; i++) { - s->chn[i].irq = irq; - s->chn[i].chn = 1 - i; - s->chn[i].type = ser; - if (s->chn[i].chr) { - qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, + s->chn[i].irq = irq; + s->chn[i].chn = 1 - i; + s->chn[i].type = ser; + if (s->chn[i].chr) { + qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, serial_receive1, serial_event, &s->chn[i]); - } + } } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; @@ -698,21 +698,21 @@ static void handle_kbd_command(ChannelState *s, int val) switch (val) { case 1: // Reset, return type code clear_queue(s); - put_queue(s, 0xff); - put_queue(s, 4); // Type 4 - put_queue(s, 0x7f); - break; + put_queue(s, 0xff); + put_queue(s, 4); // Type 4 + put_queue(s, 0x7f); + break; case 0xe: // Set leds s->led_mode = 1; break; case 7: // Query layout case 0xf: clear_queue(s); - put_queue(s, 0xfe); - put_queue(s, 0); // XXX, layout? - break; + put_queue(s, 0xfe); + put_queue(s, 0); // XXX, layout? + break; default: - break; + break; } } @@ -768,9 +768,9 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq) if (!s) return; for (i = 0; i < 2; i++) { - s->chn[i].irq = irq; - s->chn[i].chn = 1 - i; - s->chn[i].chr = NULL; + s->chn[i].irq = irq; + s->chn[i].chn = 1 - i; + s->chn[i].chr = NULL; } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 80fe15a6c..fa4b95b3f 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -86,7 +86,7 @@ static void slavio_timer_irq(void *opaque) DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); s->reached = 0x80000000; if (s->mode != 1) - qemu_irq_raise(s->irq); + qemu_irq_raise(s->irq); } static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) @@ -97,34 +97,34 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { case 0: - // read limit (system counter mode) or read most signifying - // part of counter (user mode) - if (s->mode != 1) { - // clear irq + // read limit (system counter mode) or read most signifying + // part of counter (user mode) + if (s->mode != 1) { + // clear irq qemu_irq_lower(s->irq); - s->reached = 0; + s->reached = 0; ret = s->limit & 0x7fffffff; - } - else { - slavio_timer_get_out(s); + } + else { + slavio_timer_get_out(s); ret = s->counthigh & 0x7fffffff; - } + } break; case 1: - // read counter and reached bit (system mode) or read lsbits - // of counter (user mode) - slavio_timer_get_out(s); - if (s->mode != 1) + // read counter and reached bit (system mode) or read lsbits + // of counter (user mode) + slavio_timer_get_out(s); + if (s->mode != 1) ret = (s->count & 0x7fffffff) | s->reached; - else + else ret = s->count; break; case 3: - // read start/stop status + // read start/stop status ret = s->stopped; break; case 4: - // read user/system mode + // read user/system mode ret = s->slave_mode; break; default: @@ -161,14 +161,14 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 qemu_irq_lower(s->irq); // fall through case 2: - // set limit without resetting counter + // set limit without resetting counter s->limit = val & 0x7ffffe00ULL; if (!s->limit) s->limit = 0x7ffffe00ULL; ptimer_set_limit(s->timer, s->limit >> 9, reload); - break; + break; case 1: - // set user counter limit LSW, reset counter + // set user counter limit LSW, reset counter if (s->mode == 1) { qemu_irq_lower(s->irq); s->limit &= 0x7fffffff00000000ULL; @@ -179,20 +179,20 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 } break; case 3: - // start/stop user counter - if (s->mode == 1) { - if (val & 1) { + // start/stop user counter + if (s->mode == 1) { + if (val & 1) { ptimer_stop(s->timer); - s->stopped = 1; - } - else { + s->stopped = 1; + } + else { ptimer_run(s->timer, 0); - s->stopped = 0; - } - } - break; + s->stopped = 0; + } + } + break; case 4: - // bit 0: user (1) or system (0) counter mode + // bit 0: user (1) or system (0) counter mode { unsigned int i; @@ -211,9 +211,9 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 } s->slave_mode = val & ((1 << MAX_CPUS) - 1); } - break; + break; default: - break; + break; } } @@ -294,7 +294,7 @@ static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, ptimer_set_period(s->timer, 500ULL); slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, - slavio_timer_mem_write, s); + slavio_timer_mem_write, s); if (mode < 2) cpu_register_physical_memory(addr, CPU_TIMER_SIZE, slavio_timer_io_memory); else diff --git a/hw/sun4m.c b/hw/sun4m.c index af96474bf..1d9f76605 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -52,7 +52,7 @@ #define PROM_SIZE_MAX (512 * 1024) #define PROM_PADDR 0xff0000000ULL #define PROM_VADDR 0xffd00000 -#define PROM_FILENAME "openbios-sparc32" +#define PROM_FILENAME "openbios-sparc32" #define MAX_CPUS 16 #define MAX_PILS 16 @@ -158,9 +158,9 @@ static void nvram_finish_partition (m48t59_t *nvram, uint32_t start, extern int nographic; static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, - int boot_device, uint32_t RAM_size, - uint32_t kernel_size, - int width, int height, int depth, + int boot_device, uint32_t RAM_size, + uint32_t kernel_size, + int width, int height, int depth, int machine_id) { unsigned char tmp = 0; @@ -179,8 +179,8 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR); nvram_set_lword(nvram, 0x3C, kernel_size); if (cmdline) { - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); + strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); + nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); nvram_set_lword(nvram, 0x44, strlen(cmdline)); } // initrd_image, initrd_size passed differently @@ -444,13 +444,13 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL, NULL); if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) - kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) + kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); + exit(1); } /* load initrd */ @@ -464,14 +464,14 @@ static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, } } if (initrd_size > 0) { - for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) - == 0x48647253) { // HdrS - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); - break; - } - } + for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { + if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) + == 0x48647253) { // HdrS + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); + break; + } + } } } nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, @@ -509,8 +509,8 @@ static const struct hwdef hwdefs[] = { .cs_irq = 5, .machine_id = 0x80, .intbit_to_level = { - 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, - 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, }, /* SS-10 */ @@ -542,8 +542,8 @@ static const struct hwdef hwdefs[] = { .cs_irq = -1, .machine_id = 0x72, .intbit_to_level = { - 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, - 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, }, }; diff --git a/hw/sun4u.c b/hw/sun4u.c index cc5e20083..3b0834053 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -28,12 +28,12 @@ #define CMDLINE_ADDR 0x003ff000 #define INITRD_LOAD_ADDR 0x00300000 #define PROM_SIZE_MAX (512 * 1024) -#define PROM_ADDR 0x1fff0000000ULL -#define PROM_VADDR 0x000ffd00000ULL +#define PROM_ADDR 0x1fff0000000ULL +#define PROM_VADDR 0x000ffd00000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL -#define APB_MEM_BASE 0x1ff00000000ULL -#define VGA_BASE (APB_MEM_BASE + 0x400000ULL) -#define PROM_FILENAME "openbios-sparc64" +#define APB_MEM_BASE 0x1ff00000000ULL +#define VGA_BASE (APB_MEM_BASE + 0x400000ULL) +#define PROM_FILENAME "openbios-sparc64" #define NVRAM_SIZE 0x2000 /* TSC handling */ @@ -162,10 +162,10 @@ uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) odd = count & 1; count &= ~1; for (i = 0; i != count; i++) { - crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); + crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); } if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); + crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); } return crc; @@ -387,9 +387,9 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); ret = load_elf(buf, PROM_ADDR - PROM_VADDR, NULL, NULL, NULL); if (ret < 0) { - fprintf(stderr, "qemu: could not load prom '%s'\n", - buf); - exit(1); + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); } kernel_size = 0; @@ -398,13 +398,13 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, /* XXX: put correct offset */ kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL); if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) - kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) + kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); - exit(1); + exit(1); } /* load initrd */ @@ -417,14 +417,14 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, } } if (initrd_size > 0) { - for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) - == 0x48647253) { // HdrS - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); - break; - } - } + for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { + if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) + == 0x48647253) { // HdrS + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); + break; + } + } } } pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL); @@ -446,7 +446,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i], -1); + pci_nic_init(pci_bus, &nd_table[i], -1); } irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32); diff --git a/hw/tcx.c b/hw/tcx.c index 9a72d6a6b..a6c8e4891 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -84,39 +84,39 @@ static void update_palette_entries(TCXState *s, int start, int end) } static void tcx_draw_line32(TCXState *s1, uint8_t *d, - const uint8_t *s, int width) + const uint8_t *s, int width) { int x; uint8_t val; uint32_t *p = (uint32_t *)d; for(x = 0; x < width; x++) { - val = *s++; + val = *s++; *p++ = s1->palette[val]; } } static void tcx_draw_line16(TCXState *s1, uint8_t *d, - const uint8_t *s, int width) + const uint8_t *s, int width) { int x; uint8_t val; uint16_t *p = (uint16_t *)d; for(x = 0; x < width; x++) { - val = *s++; + val = *s++; *p++ = s1->palette[val]; } } static void tcx_draw_line8(TCXState *s1, uint8_t *d, - const uint8_t *s, int width) + const uint8_t *s, int width) { int x; uint8_t val; for(x = 0; x < width; x++) { - val = *s++; + val = *s++; *d++ = s1->palette[val]; } } @@ -183,7 +183,7 @@ static void tcx_update_display(void *opaque) void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); if (ts->ds->depth == 0) - return; + return; page = ts->vram_offset; y_start = -1; page_min = 0xffffffff; @@ -195,55 +195,55 @@ static void tcx_update_display(void *opaque) switch (ts->ds->depth) { case 32: - f = tcx_draw_line32; - break; + f = tcx_draw_line32; + break; case 15: case 16: - f = tcx_draw_line16; - break; + f = tcx_draw_line16; + break; default: case 8: - f = tcx_draw_line8; - break; + f = tcx_draw_line8; + break; case 0: - return; + return; } for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { - if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { - if (y_start < 0) + if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { + if (y_start < 0) y_start = y; if (page < page_min) page_min = page; if (page > page_max) page_max = page; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - } else { + f(ts, d, s, ts->width); + d += dd; + s += ds; + f(ts, d, s, ts->width); + d += dd; + s += ds; + f(ts, d, s, ts->width); + d += dd; + s += ds; + f(ts, d, s, ts->width); + d += dd; + s += ds; + } else { if (y_start >= 0) { /* flush to display */ dpy_update(ts->ds, 0, y_start, ts->width, y - y_start); y_start = -1; } - d += dd * 4; - s += ds * 4; - } + d += dd * 4; + s += ds * 4; + } } if (y_start >= 0) { - /* flush to display */ - dpy_update(ts->ds, 0, y_start, - ts->width, y - y_start); + /* flush to display */ + dpy_update(ts->ds, 0, y_start, + ts->width, y - y_start); } /* reset modified pages */ if (page_min <= page_max) { @@ -334,7 +334,7 @@ static void tcx_invalidate_display(void *opaque) int i; for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) { - cpu_physical_memory_set_dirty(s->vram_offset + i); + cpu_physical_memory_set_dirty(s->vram_offset + i); } } @@ -424,32 +424,32 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val) saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2; switch (saddr) { case 0: - s->dac_index = val >> 24; - s->dac_state = 0; - break; + s->dac_index = val >> 24; + s->dac_state = 0; + break; case 1: - switch (s->dac_state) { - case 0: - s->r[s->dac_index] = val >> 24; + switch (s->dac_state) { + case 0: + s->r[s->dac_index] = val >> 24; update_palette_entries(s, s->dac_index, s->dac_index + 1); - s->dac_state++; - break; - case 1: - s->g[s->dac_index] = val >> 24; + s->dac_state++; + break; + case 1: + s->g[s->dac_index] = val >> 24; update_palette_entries(s, s->dac_index, s->dac_index + 1); - s->dac_state++; - break; - case 2: - s->b[s->dac_index] = val >> 24; + s->dac_state++; + break; + case 2: + s->b[s->dac_index] = val >> 24; update_palette_entries(s, s->dac_index, s->dac_index + 1); s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement - default: - s->dac_state = 0; - break; - } - break; + default: + s->dac_state = 0; + break; + } + break; default: - break; + break; } return; } diff --git a/sparc-dis.c b/sparc-dis.c index 4d2020fcd..09fed0924 100644 --- a/sparc-dis.c +++ b/sparc-dis.c @@ -88,21 +88,21 @@ extern enum sparc_opcode_arch_val sparc_opcode_lookup_arch struct sparc_opcode { const char *name; - unsigned long match; /* Bits that must be set. */ - unsigned long lose; /* Bits that must not be set. */ + unsigned long match; /* Bits that must be set. */ + unsigned long lose; /* Bits that must not be set. */ const char *args; /* This was called "delayed" in versions before the flags. */ char flags; - short architecture; /* Bitmask of sparc_opcode_arch_val's. */ + short architecture; /* Bitmask of sparc_opcode_arch_val's. */ }; -#define F_DELAYED 1 /* Delayed branch */ -#define F_ALIAS 2 /* Alias for a "real" instruction */ -#define F_UNBR 4 /* Unconditional branch */ -#define F_CONDBR 8 /* Conditional branch */ -#define F_JSR 16 /* Subroutine call */ -#define F_FLOAT 32 /* Floating point instruction (not a branch) */ -#define F_FBR 64 /* Floating point branch */ +#define F_DELAYED 1 /* Delayed branch */ +#define F_ALIAS 2 /* Alias for a "real" instruction */ +#define F_UNBR 4 /* Unconditional branch */ +#define F_CONDBR 8 /* Conditional branch */ +#define F_JSR 16 /* Subroutine call */ +#define F_FLOAT 32 /* Floating point instruction (not a branch) */ +#define F_FBR 64 /* Floating point branch */ /* FIXME: Add F_ANACHRONISTIC flag for v9. */ /* @@ -117,104 +117,104 @@ The args component is a string containing one character for each operand of the instruction. Kinds of operands: - # Number used by optimizer. It is ignored. - 1 rs1 register. - 2 rs2 register. - d rd register. - e frs1 floating point register. - v frs1 floating point register (double/even). - V frs1 floating point register (quad/multiple of 4). - f frs2 floating point register. - B frs2 floating point register (double/even). - R frs2 floating point register (quad/multiple of 4). - g frsd floating point register. - H frsd floating point register (double/even). - J frsd floating point register (quad/multiple of 4). - b crs1 coprocessor register - c crs2 coprocessor register - D crsd coprocessor register - m alternate space register (asr) in rd - M alternate space register (asr) in rs1 - h 22 high bits. - X 5 bit unsigned immediate - Y 6 bit unsigned immediate - 3 SIAM mode (3 bits). (v9b) - K MEMBAR mask (7 bits). (v9) - j 10 bit Immediate. (v9) - I 11 bit Immediate. (v9) - i 13 bit Immediate. - n 22 bit immediate. - k 2+14 bit PC relative immediate. (v9) - G 19 bit PC relative immediate. (v9) - l 22 bit PC relative immediate. - L 30 bit PC relative immediate. - a Annul. The annul bit is set. - A Alternate address space. Stored as 8 bits. - C Coprocessor state register. - F floating point state register. - p Processor state register. - N Branch predict clear ",pn" (v9) - T Branch predict set ",pt" (v9) - z %icc. (v9) - Z %xcc. (v9) - q Floating point queue. - r Single register that is both rs1 and rd. - O Single register that is both rs2 and rd. - Q Coprocessor queue. - S Special case. - t Trap base register. - w Window invalid mask register. - y Y register. - u sparclet coprocessor registers in rd position - U sparclet coprocessor registers in rs1 position - E %ccr. (v9) - s %fprs. (v9) - P %pc. (v9) - W %tick. (v9) - o %asi. (v9) - 6 %fcc0. (v9) - 7 %fcc1. (v9) - 8 %fcc2. (v9) - 9 %fcc3. (v9) - ! Privileged Register in rd (v9) - ? Privileged Register in rs1 (v9) - * Prefetch function constant. (v9) - x OPF field (v9 impdep). - 0 32/64 bit immediate for set or setx (v9) insns - _ Ancillary state register in rd (v9a) - / Ancillary state register in rs1 (v9a) + # Number used by optimizer. It is ignored. + 1 rs1 register. + 2 rs2 register. + d rd register. + e frs1 floating point register. + v frs1 floating point register (double/even). + V frs1 floating point register (quad/multiple of 4). + f frs2 floating point register. + B frs2 floating point register (double/even). + R frs2 floating point register (quad/multiple of 4). + g frsd floating point register. + H frsd floating point register (double/even). + J frsd floating point register (quad/multiple of 4). + b crs1 coprocessor register + c crs2 coprocessor register + D crsd coprocessor register + m alternate space register (asr) in rd + M alternate space register (asr) in rs1 + h 22 high bits. + X 5 bit unsigned immediate + Y 6 bit unsigned immediate + 3 SIAM mode (3 bits). (v9b) + K MEMBAR mask (7 bits). (v9) + j 10 bit Immediate. (v9) + I 11 bit Immediate. (v9) + i 13 bit Immediate. + n 22 bit immediate. + k 2+14 bit PC relative immediate. (v9) + G 19 bit PC relative immediate. (v9) + l 22 bit PC relative immediate. + L 30 bit PC relative immediate. + a Annul. The annul bit is set. + A Alternate address space. Stored as 8 bits. + C Coprocessor state register. + F floating point state register. + p Processor state register. + N Branch predict clear ",pn" (v9) + T Branch predict set ",pt" (v9) + z %icc. (v9) + Z %xcc. (v9) + q Floating point queue. + r Single register that is both rs1 and rd. + O Single register that is both rs2 and rd. + Q Coprocessor queue. + S Special case. + t Trap base register. + w Window invalid mask register. + y Y register. + u sparclet coprocessor registers in rd position + U sparclet coprocessor registers in rs1 position + E %ccr. (v9) + s %fprs. (v9) + P %pc. (v9) + W %tick. (v9) + o %asi. (v9) + 6 %fcc0. (v9) + 7 %fcc1. (v9) + 8 %fcc2. (v9) + 9 %fcc3. (v9) + ! Privileged Register in rd (v9) + ? Privileged Register in rs1 (v9) + * Prefetch function constant. (v9) + x OPF field (v9 impdep). + 0 32/64 bit immediate for set or setx (v9) insns + _ Ancillary state register in rd (v9a) + / Ancillary state register in rs1 (v9a) The following chars are unused: (note: ,[] are used as punctuation) [45] */ -#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */ -#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */ -#define OP(x) ((unsigned)((x)&0x3) << 30) /* op field of all insns */ -#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */ -#define OPF_LOW5(x) OPF((x)&0x1f) /* v9 */ -#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */ -#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */ -#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */ -#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */ -#define F1(x) (OP(x)) -#define DISP30(x) ((x)&0x3fffffff) -#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */ -#define RS2(x) ((x)&0x1f) /* rs2 field */ -#define SIMM13(x) ((x)&0x1fff) /* simm13 field */ -#define RD(x) (((x)&0x1f) << 25) /* destination register field */ -#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */ -#define ASI_RS2(x) (SIMM13(x)) -#define MEMBAR(x) ((x)&0x7f) -#define SLCPOP(x) (((x)&0x7f) << 6) /* sparclet cpop */ - -#define ANNUL (1<<29) -#define BPRED (1<<19) /* v9 */ -#define IMMED F3I(1) -#define RD_G0 RD(~0) -#define RS1_G0 RS1(~0) -#define RS2_G0 RS2(~0) +#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */ +#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */ +#define OP(x) ((unsigned)((x)&0x3) << 30) /* op field of all insns */ +#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */ +#define OPF_LOW5(x) OPF((x)&0x1f) /* v9 */ +#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */ +#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */ +#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */ +#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */ +#define F1(x) (OP(x)) +#define DISP30(x) ((x)&0x3fffffff) +#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */ +#define RS2(x) ((x)&0x1f) /* rs2 field */ +#define SIMM13(x) ((x)&0x1fff) /* simm13 field */ +#define RD(x) (((x)&0x1f) << 25) /* destination register field */ +#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */ +#define ASI_RS2(x) (SIMM13(x)) +#define MEMBAR(x) ((x)&0x7f) +#define SLCPOP(x) (((x)&0x7f) << 6) /* sparclet cpop */ + +#define ANNUL (1<<29) +#define BPRED (1<<19) /* v9 */ +#define IMMED F3I(1) +#define RD_G0 RD(~0) +#define RS1_G0 RS1(~0) +#define RS2_G0 RS2(~0) extern const struct sparc_opcode sparc_opcodes[]; extern const int sparc_num_opcodes; @@ -229,43 +229,43 @@ extern int sparc_encode_sparclet_cpreg PARAMS ((const char *)); extern const char *sparc_decode_sparclet_cpreg PARAMS ((int)); /* Some defines to make life easy. */ -#define MASK_V6 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6) -#define MASK_V7 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V7) -#define MASK_V8 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8) -#define MASK_SPARCLET SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET) -#define MASK_SPARCLITE SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) -#define MASK_V9 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9) -#define MASK_V9A SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A) -#define MASK_V9B SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B) +#define MASK_V6 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6) +#define MASK_V7 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V7) +#define MASK_V8 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8) +#define MASK_SPARCLET SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET) +#define MASK_SPARCLITE SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) +#define MASK_V9 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9) +#define MASK_V9A SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A) +#define MASK_V9B SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B) /* Bit masks of architectures supporting the insn. */ -#define v6 (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \ - | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +#define v6 (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) /* v6 insns not supported on the sparclet */ -#define v6notlet (MASK_V6 | MASK_V7 | MASK_V8 \ - | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) -#define v7 (MASK_V7 | MASK_V8 | MASK_SPARCLET \ - | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +#define v6notlet (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) +#define v7 (MASK_V7 | MASK_V8 | MASK_SPARCLET \ + | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B) /* Although not all insns are implemented in hardware, sparclite is defined to be a superset of v8. Unimplemented insns trap and are then theoretically implemented in software. It's not clear that the same is true for sparclet, although the docs suggest it is. Rather than complicating things, the sparclet assembler recognizes all v8 insns. */ -#define v8 (MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE \ - | MASK_V9 | MASK_V9A | MASK_V9B) -#define sparclet (MASK_SPARCLET) -#define sparclite (MASK_SPARCLITE) -#define v9 (MASK_V9 | MASK_V9A | MASK_V9B) -#define v9a (MASK_V9A | MASK_V9B) -#define v9b (MASK_V9B) +#define v8 (MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE \ + | MASK_V9 | MASK_V9A | MASK_V9B) +#define sparclet (MASK_SPARCLET) +#define sparclite (MASK_SPARCLITE) +#define v9 (MASK_V9 | MASK_V9A | MASK_V9B) +#define v9a (MASK_V9A | MASK_V9B) +#define v9b (MASK_V9B) /* v6 insns not supported by v9 */ -#define v6notv9 (MASK_V6 | MASK_V7 | MASK_V8 \ - | MASK_SPARCLET | MASK_SPARCLITE) +#define v6notv9 (MASK_V6 | MASK_V7 | MASK_V8 \ + | MASK_SPARCLET | MASK_SPARCLITE) /* v9a instructions which would appear to be aliases to v9's impdep's otherwise */ -#define v9notv9a (MASK_V9) +#define v9notv9a (MASK_V9) /* Table of opcode architectures. The order is defined in opcode/sparc.h. */ @@ -296,959 +296,959 @@ sparc_opcode_lookup_arch (name) for (p = &sparc_opcode_archs[0]; p->name; ++p) { if (strcmp (name, p->name) == 0) - return (enum sparc_opcode_arch_val) (p - &sparc_opcode_archs[0]); + return (enum sparc_opcode_arch_val) (p - &sparc_opcode_archs[0]); } return SPARC_OPCODE_ARCH_BAD; } /* Branch condition field. */ -#define COND(x) (((x)&0xf)<<25) +#define COND(x) (((x)&0xf)<<25) /* v9: Move (MOVcc and FMOVcc) condition field. */ -#define MCOND(x,i_or_f) ((((i_or_f)&1)<<18)|(((x)>>11)&(0xf<<14))) /* v9 */ +#define MCOND(x,i_or_f) ((((i_or_f)&1)<<18)|(((x)>>11)&(0xf<<14))) /* v9 */ /* v9: Move register (MOVRcc and FMOVRcc) condition field. */ -#define RCOND(x) (((x)&0x7)<<10) /* v9 */ - -#define CONDA (COND(0x8)) -#define CONDCC (COND(0xd)) -#define CONDCS (COND(0x5)) -#define CONDE (COND(0x1)) -#define CONDG (COND(0xa)) -#define CONDGE (COND(0xb)) -#define CONDGU (COND(0xc)) -#define CONDL (COND(0x3)) -#define CONDLE (COND(0x2)) -#define CONDLEU (COND(0x4)) -#define CONDN (COND(0x0)) -#define CONDNE (COND(0x9)) -#define CONDNEG (COND(0x6)) -#define CONDPOS (COND(0xe)) -#define CONDVC (COND(0xf)) -#define CONDVS (COND(0x7)) - -#define CONDNZ CONDNE -#define CONDZ CONDE -#define CONDGEU CONDCC -#define CONDLU CONDCS - -#define FCONDA (COND(0x8)) -#define FCONDE (COND(0x9)) -#define FCONDG (COND(0x6)) -#define FCONDGE (COND(0xb)) -#define FCONDL (COND(0x4)) -#define FCONDLE (COND(0xd)) -#define FCONDLG (COND(0x2)) -#define FCONDN (COND(0x0)) -#define FCONDNE (COND(0x1)) -#define FCONDO (COND(0xf)) -#define FCONDU (COND(0x7)) -#define FCONDUE (COND(0xa)) -#define FCONDUG (COND(0x5)) -#define FCONDUGE (COND(0xc)) -#define FCONDUL (COND(0x3)) -#define FCONDULE (COND(0xe)) - -#define FCONDNZ FCONDNE -#define FCONDZ FCONDE - -#define ICC (0) /* v9 */ +#define RCOND(x) (((x)&0x7)<<10) /* v9 */ + +#define CONDA (COND(0x8)) +#define CONDCC (COND(0xd)) +#define CONDCS (COND(0x5)) +#define CONDE (COND(0x1)) +#define CONDG (COND(0xa)) +#define CONDGE (COND(0xb)) +#define CONDGU (COND(0xc)) +#define CONDL (COND(0x3)) +#define CONDLE (COND(0x2)) +#define CONDLEU (COND(0x4)) +#define CONDN (COND(0x0)) +#define CONDNE (COND(0x9)) +#define CONDNEG (COND(0x6)) +#define CONDPOS (COND(0xe)) +#define CONDVC (COND(0xf)) +#define CONDVS (COND(0x7)) + +#define CONDNZ CONDNE +#define CONDZ CONDE +#define CONDGEU CONDCC +#define CONDLU CONDCS + +#define FCONDA (COND(0x8)) +#define FCONDE (COND(0x9)) +#define FCONDG (COND(0x6)) +#define FCONDGE (COND(0xb)) +#define FCONDL (COND(0x4)) +#define FCONDLE (COND(0xd)) +#define FCONDLG (COND(0x2)) +#define FCONDN (COND(0x0)) +#define FCONDNE (COND(0x1)) +#define FCONDO (COND(0xf)) +#define FCONDU (COND(0x7)) +#define FCONDUE (COND(0xa)) +#define FCONDUG (COND(0x5)) +#define FCONDUGE (COND(0xc)) +#define FCONDUL (COND(0x3)) +#define FCONDULE (COND(0xe)) + +#define FCONDNZ FCONDNE +#define FCONDZ FCONDE + +#define ICC (0) /* v9 */ #define XCC (1<<12) /* v9 */ -#define FCC(x) (((x)&0x3)<<11) /* v9 */ -#define FBFCC(x) (((x)&0x3)<<20) /* v9 */ +#define FCC(x) (((x)&0x3)<<11) /* v9 */ +#define FBFCC(x) (((x)&0x3)<<20) /* v9 */ /* The order of the opcodes in the table is significant: - * The assembler requires that all instances of the same mnemonic must - be consecutive. If they aren't, the assembler will bomb at runtime. + * The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler will bomb at runtime. - * The disassembler should not care about the order of the opcodes. + * The disassembler should not care about the order of the opcodes. */ /* Entries for commutative arithmetic operations. */ /* ??? More entries can make use of this. */ #define COMMUTEOP(opcode, op3, arch_mask) \ -{ opcode, F3(2, op3, 0), F3(~2, ~op3, ~0)|ASI(~0), "1,2,d", 0, arch_mask }, \ -{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "1,i,d", 0, arch_mask }, \ -{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "i,1,d", 0, arch_mask } +{ opcode, F3(2, op3, 0), F3(~2, ~op3, ~0)|ASI(~0), "1,2,d", 0, arch_mask }, \ +{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "1,i,d", 0, arch_mask }, \ +{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "i,1,d", 0, arch_mask } const struct sparc_opcode sparc_opcodes[] = { -{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 }, -{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */ -{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 }, -{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 }, -{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 }, -{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */ -{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 }, -{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */ -{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 }, -{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 }, -{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 }, -{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */ - -{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RD(~0), "[1+2],F", 0, v6 }, -{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+%g0],d */ -{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[1+i],F", 0, v6 }, -{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[i+1],F", 0, v6 }, -{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~0),"[i],F", 0, v6 }, -{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+0],d */ - -{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", 0, v6notv9 }, -{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1],D", 0, v6notv9 }, /* ld [rs1+%g0],d */ -{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i],D", 0, v6notv9 }, -{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1],D", 0, v6notv9 }, -{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, -{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ld [rs1+0],d */ -{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0), "[1+2],C", 0, v6notv9 }, -{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0, "[1],C", 0, v6notv9 }, /* ld [rs1+%g0],d */ -{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[1+i],C", 0, v6notv9 }, -{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[i+1],C", 0, v6notv9 }, -{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0, "[i],C", 0, v6notv9 }, -{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0), "[1],C", 0, v6notv9 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 }, +{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 }, +{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 }, +{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */ + +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RD(~0), "[1+2],F", 0, v6 }, +{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[1+i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[i+1],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~0),"[i],F", 0, v6 }, +{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+0],d */ + +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1],D", 0, v6notv9 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, +{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ld [rs1+0],d */ +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0), "[1+2],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0, "[1],C", 0, v6notv9 }, /* ld [rs1+%g0],d */ +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[1+i],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[i+1],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0, "[i],C", 0, v6notv9 }, +{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0), "[1],C", 0, v6notv9 }, /* ld [rs1+0],d */ /* The v9 LDUW is the same as the old 'ld' opcode, it is not the same as the 'ld' pseudo-op in v9. */ -{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", F_ALIAS, v9 }, -{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", F_ALIAS, v9 }, /* ld [rs1+%g0],d */ -{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", F_ALIAS, v9 }, -{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", F_ALIAS, v9 }, -{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", F_ALIAS, v9 }, -{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", F_ALIAS, v9 }, /* ld [rs1+0],d */ - -{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0), "[1+2],d", 0, v6 }, -{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */ -{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[1+i],d", 0, v6 }, -{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[i+1],d", 0, v6 }, -{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0, "[i],d", 0, v6 }, -{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldd [rs1+0],d */ -{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0), "[1+2],H", 0, v6 }, -{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0), "[1],H", 0, v6 }, /* ldd [rs1+%g0],d */ -{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[1+i],H", 0, v6 }, -{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[i+1],H", 0, v6 }, -{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0, "[i],H", 0, v6 }, -{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0), "[1],H", 0, v6 }, /* ldd [rs1+0],d */ - -{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0), "[1+2],D", 0, v6notv9 }, -{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+%g0],d */ -{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i],D", 0, v6notv9 }, -{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1],D", 0, v6notv9 }, -{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, -{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+0],d */ - -{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI(~0), "[1+2],J", 0, v9 }, -{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI_RS2(~0), "[1],J", 0, v9 }, /* ldd [rs1+%g0],d */ -{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[1+i],J", 0, v9 }, -{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[i+1],J", 0, v9 }, -{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|RS1_G0, "[i],J", 0, v9 }, -{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|SIMM13(~0), "[1],J", 0, v9 }, /* ldd [rs1+0],d */ - -{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0), "[1+2],d", 0, v6 }, -{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */ -{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[1+i],d", 0, v6 }, -{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[i+1],d", 0, v6 }, -{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0, "[i],d", 0, v6 }, -{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsb [rs1+0],d */ - -{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */ -{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0), "[1+2],d", 0, v6 }, -{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[1+i],d", 0, v6 }, -{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[i+1],d", 0, v6 }, -{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0, "[i],d", 0, v6 }, -{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsh [rs1+0],d */ - -{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0), "[1+2],d", 0, v6 }, -{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */ -{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[1+i],d", 0, v6 }, -{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[i+1],d", 0, v6 }, -{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0, "[i],d", 0, v6 }, -{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldstub [rs1+0],d */ - -{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI(~0), "[1+2],d", 0, v9 }, -{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldsw [rs1+%g0],d */ -{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[1+i],d", 0, v9 }, -{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[i+1],d", 0, v9 }, -{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|RS1_G0, "[i],d", 0, v9 }, -{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldsw [rs1+0],d */ - -{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0), "[1+2],d", 0, v6 }, -{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */ -{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[1+i],d", 0, v6 }, -{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[i+1],d", 0, v6 }, -{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0, "[i],d", 0, v6 }, -{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldub [rs1+0],d */ - -{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0), "[1+2],d", 0, v6 }, -{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */ -{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[1+i],d", 0, v6 }, -{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[i+1],d", 0, v6 }, -{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0, "[i],d", 0, v6 }, -{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* lduh [rs1+0],d */ - -{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI(~0), "[1+2],d", 0, v9 }, -{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldx [rs1+%g0],d */ -{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[1+i],d", 0, v9 }, -{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[i+1],d", 0, v9 }, -{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|RS1_G0, "[i],d", 0, v9 }, -{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldx [rs1+0],d */ - -{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RD(~1), "[1+2],F", 0, v9 }, -{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RS2_G0|RD(~1), "[1],F", 0, v9 }, /* ld [rs1+%g0],d */ -{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[1+i],F", 0, v9 }, -{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[i+1],F", 0, v9 }, -{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~1), "[i],F", 0, v9 }, -{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~1),"[1],F", 0, v9 }, /* ld [rs1+0],d */ - -{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", 0, v6 }, -{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */ -{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", 0, v9 }, -{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", 0, v9 }, -{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ -{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2]A,g", 0, v9 }, -{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1]A,g", 0, v9 }, /* lda [rs1+%g0],d */ -{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i]o,g", 0, v9 }, -{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1]o,g", 0, v9 }, -{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i]o,g", 0, v9 }, -{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1]o,g", 0, v9 }, /* ld [rs1+0],d */ - -{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0), "[1+2]A,d", 0, v6 }, -{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */ -{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[1+i]o,d", 0, v9 }, -{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[i+1]o,d", 0, v9 }, -{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ - -{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0), "[1+2]A,H", 0, v9 }, -{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|RS2_G0, "[1]A,H", 0, v9 }, /* ldda [rs1+%g0],d */ -{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i]o,H", 0, v9 }, -{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1]o,H", 0, v9 }, -{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i]o,H", 0, v9 }, -{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1]o,H", 0, v9 }, /* ld [rs1+0],d */ - -{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0), "[1+2]A,J", 0, v9 }, -{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0)|RS2_G0, "[1]A,J", 0, v9 }, /* ldd [rs1+%g0],d */ -{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[1+i]o,J", 0, v9 }, -{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[i+1]o,J", 0, v9 }, -{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|RS1_G0, "[i]o,J", 0, v9 }, -{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|SIMM13(~0), "[1]o,J", 0, v9 }, /* ldd [rs1+0],d */ - -{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0), "[1+2]A,d", 0, v6 }, -{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */ -{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[1+i]o,d", 0, v9 }, -{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[i+1]o,d", 0, v9 }, -{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ - -{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0), "[1+2]A,d", 0, v6 }, -{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */ -{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[1+i]o,d", 0, v9 }, -{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[i+1]o,d", 0, v9 }, -{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ - -{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0), "[1+2]A,d", 0, v6 }, -{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */ -{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[1+i]o,d", 0, v9 }, -{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[i+1]o,d", 0, v9 }, -{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ - -{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0), "[1+2]A,d", 0, v9 }, -{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ -{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[1+i]o,d", 0, v9 }, -{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[i+1]o,d", 0, v9 }, -{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ - -{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0), "[1+2]A,d", 0, v6 }, -{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */ -{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[1+i]o,d", 0, v9 }, -{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[i+1]o,d", 0, v9 }, -{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ - -{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0), "[1+2]A,d", 0, v6 }, -{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */ -{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[1+i]o,d", 0, v9 }, -{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[i+1]o,d", 0, v9 }, -{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ - -{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", F_ALIAS, v9 }, /* lduwa === lda */ -{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", F_ALIAS, v9 }, /* lda [rs1+%g0],d */ -{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", F_ALIAS, v9 }, -{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", F_ALIAS, v9 }, -{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", F_ALIAS, v9 }, -{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", F_ALIAS, v9 }, /* ld [rs1+0],d */ - -{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0), "[1+2]A,d", 0, v9 }, -{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ -{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[1+i]o,d", 0, v9 }, -{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[i+1]o,d", 0, v9 }, -{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ - -{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, -{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */ -{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", 0, v6 }, -{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", 0, v6 }, -{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", 0, v6 }, -{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* st d,[rs1+0] */ -{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0), "g,[1+2]", 0, v6 }, -{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* st d[rs1+%g0] */ -{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[1+i]", 0, v6 }, -{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[i+1]", 0, v6 }, -{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0, "g,[i]", 0, v6 }, -{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* st d,[rs1+0] */ - -{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, -{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ -{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[1+i]", 0, v6notv9 }, -{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[i+1]", 0, v6notv9 }, -{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, -{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ -{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0), "C,[1+2]", 0, v6notv9 }, -{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ -{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[1+i]", 0, v6notv9 }, -{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[i+1]", 0, v6notv9 }, -{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0, "C,[i]", 0, v6notv9 }, -{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ - -{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0), "F,[1+2]", 0, v6 }, -{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0), "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */ -{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[1+i]", 0, v6 }, -{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[i+1]", 0, v6 }, -{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0, "F,[i]", 0, v6 }, -{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|SIMM13(~0), "F,[1]", 0, v6 }, /* st d,[rs1+0] */ - -{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, -{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ -{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, -{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, -{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, -{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ -{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, -{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ -{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, -{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, -{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, -{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ -{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, -{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ -{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, -{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, -{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, -{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ - -{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, -{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+%g0] */ -{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v6 }, -{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v6 }, -{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, -{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+0] */ - -{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", 0, v6 }, -{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */ -{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", 0, v9 }, -{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", 0, v9 }, -{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", 0, v9 }, -{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* st d,[rs1+0] */ - -{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0), "g,[1+2]A", 0, v9 }, -{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|RS2(~0), "g,[1]A", 0, v9 }, /* sta d,[rs1+%g0] */ -{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[1+i]o", 0, v9 }, -{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[i+1]o", 0, v9 }, -{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "g,[i]o", 0, v9 }, -{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "g,[1]o", 0, v9 }, /* st d,[rs1+0] */ - -{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, -{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ -{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, -{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, -{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, -{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ -{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, -{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ -{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, -{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, -{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, -{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ -{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, -{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ -{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, -{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, -{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, -{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ - -{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, -{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */ -{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", 0, v6 }, -{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", 0, v6 }, -{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", 0, v6 }, -{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+0] */ - -{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, -{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ -{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, -{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, -{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, -{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ -{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, -{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ -{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, -{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, -{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, -{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ - -{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", 0, v6 }, -{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */ -{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", 0, v9 }, -{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", 0, v9 }, -{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", 0, v9 }, -{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stb d,[rs1+0] */ - -{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, -{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ -{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, -{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, -{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, -{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ -{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, -{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ -{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, -{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, -{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, -{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ - -{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, -{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */ -{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", 0, v6 }, -{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", 0, v6 }, -{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", 0, v6 }, -{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* std d,[rs1+0] */ - -{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "q,[1+2]", 0, v6notv9 }, -{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ -{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[1+i]", 0, v6notv9 }, -{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[i+1]", 0, v6notv9 }, -{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "q,[i]", 0, v6notv9 }, -{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ -{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0), "H,[1+2]", 0, v6 }, -{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0), "H,[1]", 0, v6 }, /* std d,[rs1+%g0] */ -{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[1+i]", 0, v6 }, -{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[i+1]", 0, v6 }, -{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0, "H,[i]", 0, v6 }, -{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0), "H,[1]", 0, v6 }, /* std d,[rs1+0] */ - -{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "Q,[1+2]", 0, v6notv9 }, -{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ -{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[1+i]", 0, v6notv9 }, -{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[i+1]", 0, v6notv9 }, -{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "Q,[i]", 0, v6notv9 }, -{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ -{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, -{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ -{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[1+i]", 0, v6notv9 }, -{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[i+1]", 0, v6notv9 }, -{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, -{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ - -{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, -{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+%g0] */ -{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", F_ALIAS, v6 }, -{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", F_ALIAS, v6 }, -{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, -{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+0] */ - -{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0), "d,[1+2]A", 0, v6 }, -{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */ -{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[1+i]o", 0, v9 }, -{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[i+1]o", 0, v9 }, -{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|RS1_G0, "d,[i]o", 0, v9 }, -{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* std d,[rs1+0] */ -{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0), "H,[1+2]A", 0, v9 }, -{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|RS2(~0), "H,[1]A", 0, v9 }, /* stda d,[rs1+%g0] */ -{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[1+i]o", 0, v9 }, -{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[i+1]o", 0, v9 }, -{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "H,[i]o", 0, v9 }, -{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "H,[1]o", 0, v9 }, /* std d,[rs1+0] */ - -{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, -{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */ -{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", 0, v6 }, -{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", 0, v6 }, -{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", 0, v6 }, -{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+0] */ - -{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, -{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ -{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, -{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, -{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, -{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ -{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, -{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ -{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, -{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, -{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, -{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ - -{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", 0, v6 }, -{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stha ,[rs1+%g0] */ -{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", 0, v9 }, -{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", 0, v9 }, -{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", 0, v9 }, -{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* sth d,[rs1+0] */ - -{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, -{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ -{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, -{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, -{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, -{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ -{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, -{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ -{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, -{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, -{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, -{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ - -{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI(~0), "d,[1+2]", 0, v9 }, -{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI_RS2(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ -{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[1+i]", 0, v9 }, -{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[i+1]", 0, v9 }, -{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RS1_G0, "d,[i]", 0, v9 }, -{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|SIMM13(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+0] */ - -{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI(~0)|RD(~1), "F,[1+2]", 0, v9 }, -{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI_RS2(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ -{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[1+i]", 0, v9 }, -{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[i+1]", 0, v9 }, -{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RS1_G0|RD(~1), "F,[i]", 0, v9 }, -{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|SIMM13(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+0] */ - -{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0), "d,[1+2]A", 0, v9 }, -{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0)|RS2(~0), "d,[1]A", 0, v9 }, /* stxa d,[rs1+%g0] */ -{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[1+i]o", 0, v9 }, -{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[i+1]o", 0, v9 }, -{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|RS1_G0, "d,[i]o", 0, v9 }, -{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stx d,[rs1+0] */ - -{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "J,[1+2]", 0, v9 }, -{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "J,[1]", 0, v9 }, /* stq [rs1+%g0] */ -{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[1+i]", 0, v9 }, -{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[i+1]", 0, v9 }, -{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "J,[i]", 0, v9 }, -{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "J,[1]", 0, v9 }, /* stq [rs1+0] */ - -{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "J,[1+2]A", 0, v9 }, -{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "J,[1]A", 0, v9 }, /* stqa [rs1+%g0] */ -{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[1+i]o", 0, v9 }, -{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[i+1]o", 0, v9 }, -{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "J,[i]o", 0, v9 }, -{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "J,[1]o", 0, v9 }, /* stqa [rs1+0] */ - -{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0), "[1+2],d", 0, v7 }, -{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0), "[1],d", 0, v7 }, /* swap [rs1+%g0],d */ -{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[1+i],d", 0, v7 }, -{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[i+1],d", 0, v7 }, -{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0, "[i],d", 0, v7 }, -{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0), "[1],d", 0, v7 }, /* swap [rs1+0],d */ - -{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0), "[1+2]A,d", 0, v7 }, -{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0), "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */ -{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[1+i]o,d", 0, v9 }, -{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[i+1]o,d", 0, v9 }, -{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|RS1_G0, "[i]o,d", 0, v9 }, -{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* swap [rs1+0],d */ - -{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v6 }, /* restore %g0,%g0,%g0 */ -{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1), "1,i,d", 0, v6 }, -{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0), "", 0, v6 }, /* restore %g0,0,%g0 */ - -{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* rett rs1+rs2 */ -{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1,%g0 */ -{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* rett rs1+X */ -{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ -{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ -{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X */ -{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1+0 */ - -{ "save", F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "save", F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1), "1,i,d", 0, v6 }, -{ "save", 0x81e00000, ~0x81e00000, "", F_ALIAS, v6 }, - -{ "ret", F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */ +{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", F_ALIAS, v9 }, /* ld [rs1+%g0],d */ +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", F_ALIAS, v9 }, +{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", F_ALIAS, v9 }, /* ld [rs1+0],d */ + +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[1+i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[i+1],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldd [rs1+0],d */ +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0), "[1+2],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0), "[1],H", 0, v6 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[1+i],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[i+1],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0, "[i],H", 0, v6 }, +{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0), "[1],H", 0, v6 }, /* ldd [rs1+0],d */ + +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0), "[1+2],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+%g0],d */ +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i],D", 0, v6notv9 }, +{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+0],d */ + +{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI(~0), "[1+2],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI_RS2(~0), "[1],J", 0, v9 }, /* ldd [rs1+%g0],d */ +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[1+i],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[i+1],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|RS1_G0, "[i],J", 0, v9 }, +{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|SIMM13(~0), "[1],J", 0, v9 }, /* ldd [rs1+0],d */ + +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */ +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[1+i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[i+1],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsb [rs1+0],d */ + +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */ +{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[1+i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[i+1],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsh [rs1+0],d */ + +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */ +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[1+i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[i+1],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldstub [rs1+0],d */ + +{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI(~0), "[1+2],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldsw [rs1+%g0],d */ +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[1+i],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[i+1],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|RS1_G0, "[i],d", 0, v9 }, +{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldsw [rs1+0],d */ + +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */ +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[1+i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[i+1],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldub [rs1+0],d */ + +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0), "[1+2],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */ +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[1+i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[i+1],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0, "[i],d", 0, v6 }, +{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* lduh [rs1+0],d */ + +{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI(~0), "[1+2],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldx [rs1+%g0],d */ +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[1+i],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[i+1],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|RS1_G0, "[i],d", 0, v9 }, +{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldx [rs1+0],d */ + +{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RD(~1), "[1+2],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RS2_G0|RD(~1), "[1],F", 0, v9 }, /* ld [rs1+%g0],d */ +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[1+i],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[i+1],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~1), "[i],F", 0, v9 }, +{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~1),"[1],F", 0, v9 }, /* ld [rs1+0],d */ + +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", 0, v6 }, +{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */ +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ +{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2]A,g", 0, v9 }, +{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1]A,g", 0, v9 }, /* lda [rs1+%g0],d */ +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i]o,g", 0, v9 }, +{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1]o,g", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0), "[1+2]A,d", 0, v6 }, +{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */ +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[1+i]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[i+1]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0), "[1+2]A,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|RS2_G0, "[1]A,H", 0, v9 }, /* ldda [rs1+%g0],d */ +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i]o,H", 0, v9 }, +{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1]o,H", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0), "[1+2]A,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0)|RS2_G0, "[1]A,J", 0, v9 }, /* ldd [rs1+%g0],d */ +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[1+i]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[i+1]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|RS1_G0, "[i]o,J", 0, v9 }, +{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|SIMM13(~0), "[1]o,J", 0, v9 }, /* ldd [rs1+0],d */ + +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */ +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[1+i]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[i+1]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0), "[1+2]A,d", 0, v6 }, +{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */ +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[1+i]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[i+1]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0), "[1+2]A,d", 0, v6 }, +{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */ +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[1+i]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[i+1]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0), "[1+2]A,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[1+i]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[i+1]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0), "[1+2]A,d", 0, v6 }, +{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */ +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[1+i]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[i+1]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0), "[1+2]A,d", 0, v6 }, +{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */ +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[1+i]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[i+1]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", F_ALIAS, v9 }, /* lduwa === lda */ +{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", F_ALIAS, v9 }, /* lda [rs1+%g0],d */ +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", F_ALIAS, v9 }, +{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", F_ALIAS, v9 }, /* ld [rs1+0],d */ + +{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0), "[1+2]A,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */ +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[1+i]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[i+1]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */ + +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0), "g,[1+2]", 0, v6 }, +{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* st d[rs1+%g0] */ +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[1+i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[i+1]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0, "g,[i]", 0, v6 }, +{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[1+i]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[i+1]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, +{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0), "C,[1+2]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[1+i]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[i+1]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0, "C,[i]", 0, v6notv9 }, +{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+0] */ + +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0), "F,[1+2]", 0, v6 }, +{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0), "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */ +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[1+i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[i+1]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0, "F,[i]", 0, v6 }, +{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|SIMM13(~0), "F,[1]", 0, v6 }, /* st d,[rs1+0] */ + +{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */ +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 }, +{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */ + +{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+%g0] */ +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+0] */ + +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", 0, v6 }, +{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */ +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* st d,[rs1+0] */ + +{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0), "g,[1+2]A", 0, v9 }, +{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|RS2(~0), "g,[1]A", 0, v9 }, /* sta d,[rs1+%g0] */ +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[1+i]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[i+1]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "g,[i]o", 0, v9 }, +{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "g,[1]o", 0, v9 }, /* st d,[rs1+0] */ + +{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ +{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */ +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */ + +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */ +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+0] */ + +{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ +{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */ +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */ + +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", 0, v6 }, +{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */ +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stb d,[rs1+0] */ + +{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ +{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */ +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */ + +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "q,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "q,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0), "H,[1+2]", 0, v6 }, +{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0), "H,[1]", 0, v6 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[1+i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[i+1]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0, "H,[i]", 0, v6 }, +{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0), "H,[1]", 0, v6 }, /* std d,[rs1+0] */ + +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "Q,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "Q,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */ +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[1+i]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[i+1]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "D,[i]", 0, v6notv9 }, +{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+0] */ + +{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+%g0] */ +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+0] */ + +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0), "d,[1+2]A", 0, v6 }, +{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */ +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[1+i]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[i+1]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* std d,[rs1+0] */ +{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0), "H,[1+2]A", 0, v9 }, +{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|RS2(~0), "H,[1]A", 0, v9 }, /* stda d,[rs1+%g0] */ +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[1+i]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[i+1]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "H,[i]o", 0, v9 }, +{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "H,[1]o", 0, v9 }, /* std d,[rs1+0] */ + +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", 0, v6 }, +{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */ +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", 0, v6 }, +{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+0] */ + +{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ +{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */ +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 }, +{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */ + +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", 0, v6 }, +{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stha ,[rs1+%g0] */ +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* sth d,[rs1+0] */ + +{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ +{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 }, +{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */ +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 }, +{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */ + +{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI(~0), "d,[1+2]", 0, v9 }, +{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI_RS2(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[1+i]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[i+1]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RS1_G0, "d,[i]", 0, v9 }, +{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|SIMM13(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI(~0)|RD(~1), "F,[1+2]", 0, v9 }, +{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI_RS2(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+%g0] */ +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[1+i]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[i+1]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RS1_G0|RD(~1), "F,[i]", 0, v9 }, +{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|SIMM13(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0), "d,[1+2]A", 0, v9 }, +{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0)|RS2(~0), "d,[1]A", 0, v9 }, /* stxa d,[rs1+%g0] */ +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[1+i]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[i+1]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|RS1_G0, "d,[i]o", 0, v9 }, +{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stx d,[rs1+0] */ + +{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "J,[1+2]", 0, v9 }, +{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "J,[1]", 0, v9 }, /* stq [rs1+%g0] */ +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[1+i]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[i+1]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "J,[i]", 0, v9 }, +{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "J,[1]", 0, v9 }, /* stq [rs1+0] */ + +{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "J,[1+2]A", 0, v9 }, +{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "J,[1]A", 0, v9 }, /* stqa [rs1+%g0] */ +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[1+i]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[i+1]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "J,[i]o", 0, v9 }, +{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "J,[1]o", 0, v9 }, /* stqa [rs1+0] */ + +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0), "[1+2],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0), "[1],d", 0, v7 }, /* swap [rs1+%g0],d */ +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[1+i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[i+1],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0, "[i],d", 0, v7 }, +{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0), "[1],d", 0, v7 }, /* swap [rs1+0],d */ + +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0), "[1+2]A,d", 0, v7 }, +{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0), "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */ +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[1+i]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[i+1]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|RS1_G0, "[i]o,d", 0, v9 }, +{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* swap [rs1+0],d */ + +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v6 }, /* restore %g0,%g0,%g0 */ +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1), "1,i,d", 0, v6 }, +{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0), "", 0, v6 }, /* restore %g0,0,%g0 */ + +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* rett rs1+rs2 */ +{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1,%g0 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* rett rs1+X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X */ +{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1+0 */ + +{ "save", F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "save", F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1), "1,i,d", 0, v6 }, +{ "save", 0x81e00000, ~0x81e00000, "", F_ALIAS, v6 }, + +{ "ret", F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */ { "retl", F3(2, 0x38, 1)|RS1(0x0f)|SIMM13(8), F3(~2, ~0x38, ~1)|RS1(~0x0f)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %o7+8,%g0 */ -{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0), "1+2,d", F_JSR|F_DELAYED, v6 }, -{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,d */ -{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,d */ -{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,d */ -{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "1+i,d", F_JSR|F_DELAYED, v6 }, -{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "i+1,d", F_JSR|F_DELAYED, v6 }, - -{ "done", F3(2, 0x3e, 0)|RD(0), F3(~2, ~0x3e, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, -{ "retry", F3(2, 0x3e, 0)|RD(1), F3(~2, ~0x3e, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, -{ "saved", F3(2, 0x31, 0)|RD(0), F3(~2, ~0x31, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, -{ "restored", F3(2, 0x31, 0)|RD(1), F3(~2, ~0x31, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, -{ "sir", F3(2, 0x30, 1)|RD(0xf), F3(~2, ~0x30, ~1)|RD(~0xf)|RS1_G0, "i", 0, v9 }, - -{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v8 }, -{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", 0, v8 }, /* flush rs1+%g0 */ -{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", 0, v8 }, /* flush rs1+0 */ -{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", 0, v8 }, /* flush %g0+i */ -{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", 0, v8 }, -{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", 0, v8 }, +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0), "1+2,d", F_JSR|F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,d */ +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "1+i,d", F_JSR|F_DELAYED, v6 }, +{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "i+1,d", F_JSR|F_DELAYED, v6 }, + +{ "done", F3(2, 0x3e, 0)|RD(0), F3(~2, ~0x3e, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "retry", F3(2, 0x3e, 0)|RD(1), F3(~2, ~0x3e, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "saved", F3(2, 0x31, 0)|RD(0), F3(~2, ~0x31, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "restored", F3(2, 0x31, 0)|RD(1), F3(~2, ~0x31, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 }, +{ "sir", F3(2, 0x30, 1)|RD(0xf), F3(~2, ~0x30, ~1)|RD(~0xf)|RS1_G0, "i", 0, v9 }, + +{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v8 }, +{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", 0, v8 }, /* flush rs1+%g0 */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", 0, v8 }, /* flush rs1+0 */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", 0, v8 }, /* flush %g0+i */ +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", 0, v8 }, +{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", 0, v8 }, /* IFLUSH was renamed to FLUSH in v8. */ -{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", F_ALIAS, v6 }, -{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", F_ALIAS, v6 }, /* flush rs1+%g0 */ -{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", F_ALIAS, v6 }, /* flush rs1+0 */ -{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", F_ALIAS, v6 }, -{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", F_ALIAS, v6 }, -{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", F_ALIAS, v6 }, - -{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI(~0), "1+2", 0, v9 }, -{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI_RS2(~0), "1", 0, v9 }, /* return rs1+%g0 */ -{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|SIMM13(~0), "1", 0, v9 }, /* return rs1+0 */ -{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RS1_G0, "i", 0, v9 }, /* return %g0+i */ -{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "1+i", 0, v9 }, -{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "i+1", 0, v9 }, - -{ "flushw", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v9 }, - -{ "membar", F3(2, 0x28, 1)|RS1(0xf), F3(~2, ~0x28, ~1)|RD_G0|RS1(~0xf)|SIMM13(~127), "K", 0, v9 }, -{ "stbar", F3(2, 0x28, 0)|RS1(0xf), F3(~2, ~0x28, ~0)|RD_G0|RS1(~0xf)|SIMM13(~0), "", 0, v8 }, - -{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0), "[1+2],*", 0, v9 }, -{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0)|RS2_G0, "[1],*", 0, v9 }, /* prefetch [rs1+%g0],prefetch_fcn */ -{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[1+i],*", 0, v9 }, -{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[i+1],*", 0, v9 }, -{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|RS1_G0, "[i],*", 0, v9 }, -{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|SIMM13(~0), "[1],*", 0, v9 }, /* prefetch [rs1+0],prefetch_fcn */ -{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0), "[1+2]A,*", 0, v9 }, -{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0)|RS2_G0, "[1]A,*", 0, v9 }, /* prefetcha [rs1+%g0],prefetch_fcn */ -{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[1+i]o,*", 0, v9 }, -{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[i+1]o,*", 0, v9 }, -{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|RS1_G0, "[i]o,*", 0, v9 }, -{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|SIMM13(~0), "[1]o,*", 0, v9 }, /* prefetcha [rs1+0],d */ - -{ "sll", F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, -{ "sll", F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, -{ "sra", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, -{ "sra", F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, -{ "srl", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, -{ "srl", F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, - -{ "sllx", F3(2, 0x25, 0)|(1<<12), F3(~2, ~0x25, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, -{ "sllx", F3(2, 0x25, 1)|(1<<12), F3(~2, ~0x25, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, -{ "srax", F3(2, 0x27, 0)|(1<<12), F3(~2, ~0x27, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, -{ "srax", F3(2, 0x27, 1)|(1<<12), F3(~2, ~0x27, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, -{ "srlx", F3(2, 0x26, 0)|(1<<12), F3(~2, ~0x26, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, -{ "srlx", F3(2, 0x26, 1)|(1<<12), F3(~2, ~0x26, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, - -{ "mulscc", F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "mulscc", F3(2, 0x24, 1), F3(~2, ~0x24, ~1), "1,i,d", 0, v6 }, - -{ "divscc", F3(2, 0x1d, 0), F3(~2, ~0x1d, ~0)|ASI(~0), "1,2,d", 0, sparclite }, -{ "divscc", F3(2, 0x1d, 1), F3(~2, ~0x1d, ~1), "1,i,d", 0, sparclite }, - -{ "scan", F3(2, 0x2c, 0), F3(~2, ~0x2c, ~0)|ASI(~0), "1,2,d", 0, sparclet|sparclite }, -{ "scan", F3(2, 0x2c, 1), F3(~2, ~0x2c, ~1), "1,i,d", 0, sparclet|sparclite }, - -{ "popc", F3(2, 0x2e, 0), F3(~2, ~0x2e, ~0)|RS1_G0|ASI(~0),"2,d", 0, v9 }, -{ "popc", F3(2, 0x2e, 1), F3(~2, ~0x2e, ~1)|RS1_G0, "i,d", 0, v9 }, - -{ "clr", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "d", F_ALIAS, v6 }, /* or %g0,%g0,d */ -{ "clr", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0), "d", F_ALIAS, v6 }, /* or %g0,0,d */ -{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, -{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */ -{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, -{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, -{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, -{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */ - -{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, -{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */ -{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, -{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, -{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, -{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+0] */ - -{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, -{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */ -{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, -{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, -{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, -{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+0] */ - -{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v9 }, -{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+%g0] */ -{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[1+i]", F_ALIAS, v9 }, -{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[i+1]", F_ALIAS, v9 }, -{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v9 }, -{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+0] */ - -{ "orcc", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "1,i,d", 0, v6 }, -{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "i,1,d", 0, v6 }, +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", F_ALIAS, v6 }, /* flush rs1+%g0 */ +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", F_ALIAS, v6 }, /* flush rs1+0 */ +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", F_ALIAS, v6 }, +{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", F_ALIAS, v6 }, + +{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI(~0), "1+2", 0, v9 }, +{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI_RS2(~0), "1", 0, v9 }, /* return rs1+%g0 */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|SIMM13(~0), "1", 0, v9 }, /* return rs1+0 */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RS1_G0, "i", 0, v9 }, /* return %g0+i */ +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "1+i", 0, v9 }, +{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "i+1", 0, v9 }, + +{ "flushw", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v9 }, + +{ "membar", F3(2, 0x28, 1)|RS1(0xf), F3(~2, ~0x28, ~1)|RD_G0|RS1(~0xf)|SIMM13(~127), "K", 0, v9 }, +{ "stbar", F3(2, 0x28, 0)|RS1(0xf), F3(~2, ~0x28, ~0)|RD_G0|RS1(~0xf)|SIMM13(~0), "", 0, v8 }, + +{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0), "[1+2],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0)|RS2_G0, "[1],*", 0, v9 }, /* prefetch [rs1+%g0],prefetch_fcn */ +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[1+i],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[i+1],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|RS1_G0, "[i],*", 0, v9 }, +{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|SIMM13(~0), "[1],*", 0, v9 }, /* prefetch [rs1+0],prefetch_fcn */ +{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0), "[1+2]A,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0)|RS2_G0, "[1]A,*", 0, v9 }, /* prefetcha [rs1+%g0],prefetch_fcn */ +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[1+i]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[i+1]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|RS1_G0, "[i]o,*", 0, v9 }, +{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|SIMM13(~0), "[1]o,*", 0, v9 }, /* prefetcha [rs1+0],d */ + +{ "sll", F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "sll", F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, +{ "sra", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "sra", F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, +{ "srl", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 }, +{ "srl", F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 }, + +{ "sllx", F3(2, 0x25, 0)|(1<<12), F3(~2, ~0x25, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "sllx", F3(2, 0x25, 1)|(1<<12), F3(~2, ~0x25, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, +{ "srax", F3(2, 0x27, 0)|(1<<12), F3(~2, ~0x27, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "srax", F3(2, 0x27, 1)|(1<<12), F3(~2, ~0x27, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, +{ "srlx", F3(2, 0x26, 0)|(1<<12), F3(~2, ~0x26, ~0)|(0x7f<<5), "1,2,d", 0, v9 }, +{ "srlx", F3(2, 0x26, 1)|(1<<12), F3(~2, ~0x26, ~1)|(0x3f<<6), "1,Y,d", 0, v9 }, + +{ "mulscc", F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "mulscc", F3(2, 0x24, 1), F3(~2, ~0x24, ~1), "1,i,d", 0, v6 }, + +{ "divscc", F3(2, 0x1d, 0), F3(~2, ~0x1d, ~0)|ASI(~0), "1,2,d", 0, sparclite }, +{ "divscc", F3(2, 0x1d, 1), F3(~2, ~0x1d, ~1), "1,i,d", 0, sparclite }, + +{ "scan", F3(2, 0x2c, 0), F3(~2, ~0x2c, ~0)|ASI(~0), "1,2,d", 0, sparclet|sparclite }, +{ "scan", F3(2, 0x2c, 1), F3(~2, ~0x2c, ~1), "1,i,d", 0, sparclet|sparclite }, + +{ "popc", F3(2, 0x2e, 0), F3(~2, ~0x2e, ~0)|RS1_G0|ASI(~0),"2,d", 0, v9 }, +{ "popc", F3(2, 0x2e, 1), F3(~2, ~0x2e, ~1)|RS1_G0, "i,d", 0, v9 }, + +{ "clr", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "d", F_ALIAS, v6 }, /* or %g0,%g0,d */ +{ "clr", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0), "d", F_ALIAS, v6 }, /* or %g0,0,d */ +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */ +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */ + +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */ +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+0] */ + +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */ +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 }, +{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+0] */ + +{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+%g0] */ +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[1+i]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[i+1]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v9 }, +{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+0] */ + +{ "orcc", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "1,i,d", 0, v6 }, +{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "i,1,d", 0, v6 }, /* This is not a commutative instruction. */ -{ "orncc", F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "1,i,d", 0, v6 }, +{ "orncc", F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "1,i,d", 0, v6 }, /* This is not a commutative instruction. */ -{ "orn", F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "1,i,d", 0, v6 }, - -{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0), "1", 0, v6 }, /* orcc rs1, %g0, %g0 */ -{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */ -{ "tst", F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0), "1", 0, v6 }, /* orcc rs1, 0, %g0 */ - -{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", 0, v8 }, /* wr r,r,%asrX */ -{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", 0, v8 }, /* wr r,i,%asrX */ -{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ -{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", 0, v6 }, /* wr r,r,%y */ -{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", 0, v6 }, /* wr r,i,%y */ -{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ -{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", 0, v6notv9 }, /* wr r,r,%psr */ -{ "wr", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", 0, v6notv9 }, /* wr r,i,%psr */ -{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ -{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", 0, v6notv9 }, /* wr r,r,%wim */ -{ "wr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", 0, v6notv9 }, /* wr r,i,%wim */ -{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ -{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", 0, v6notv9 }, /* wr r,r,%tbr */ -{ "wr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", 0, v6notv9 }, /* wr r,i,%tbr */ -{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ - -{ "wr", F3(2, 0x30, 0)|RD(2), F3(~2, ~0x30, ~0)|RD(~2)|ASI(~0), "1,2,E", 0, v9 }, /* wr r,r,%ccr */ -{ "wr", F3(2, 0x30, 1)|RD(2), F3(~2, ~0x30, ~1)|RD(~2), "1,i,E", 0, v9 }, /* wr r,i,%ccr */ -{ "wr", F3(2, 0x30, 0)|RD(3), F3(~2, ~0x30, ~0)|RD(~3)|ASI(~0), "1,2,o", 0, v9 }, /* wr r,r,%asi */ -{ "wr", F3(2, 0x30, 1)|RD(3), F3(~2, ~0x30, ~1)|RD(~3), "1,i,o", 0, v9 }, /* wr r,i,%asi */ -{ "wr", F3(2, 0x30, 0)|RD(6), F3(~2, ~0x30, ~0)|RD(~6)|ASI(~0), "1,2,s", 0, v9 }, /* wr r,r,%fprs */ -{ "wr", F3(2, 0x30, 1)|RD(6), F3(~2, ~0x30, ~1)|RD(~6), "1,i,s", 0, v9 }, /* wr r,i,%fprs */ - -{ "wr", F3(2, 0x30, 0)|RD(16), F3(~2, ~0x30, ~0)|RD(~16)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pcr */ -{ "wr", F3(2, 0x30, 1)|RD(16), F3(~2, ~0x30, ~1)|RD(~16), "1,i,_", 0, v9a }, /* wr r,i,%pcr */ -{ "wr", F3(2, 0x30, 0)|RD(17), F3(~2, ~0x30, ~0)|RD(~17)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pic */ -{ "wr", F3(2, 0x30, 1)|RD(17), F3(~2, ~0x30, ~1)|RD(~17), "1,i,_", 0, v9a }, /* wr r,i,%pic */ -{ "wr", F3(2, 0x30, 0)|RD(18), F3(~2, ~0x30, ~0)|RD(~18)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%dcr */ -{ "wr", F3(2, 0x30, 1)|RD(18), F3(~2, ~0x30, ~1)|RD(~18), "1,i,_", 0, v9a }, /* wr r,i,%dcr */ -{ "wr", F3(2, 0x30, 0)|RD(19), F3(~2, ~0x30, ~0)|RD(~19)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%gsr */ -{ "wr", F3(2, 0x30, 1)|RD(19), F3(~2, ~0x30, ~1)|RD(~19), "1,i,_", 0, v9a }, /* wr r,i,%gsr */ -{ "wr", F3(2, 0x30, 0)|RD(20), F3(~2, ~0x30, ~0)|RD(~20)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%set_softint */ -{ "wr", F3(2, 0x30, 1)|RD(20), F3(~2, ~0x30, ~1)|RD(~20), "1,i,_", 0, v9a }, /* wr r,i,%set_softint */ -{ "wr", F3(2, 0x30, 0)|RD(21), F3(~2, ~0x30, ~0)|RD(~21)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%clear_softint */ -{ "wr", F3(2, 0x30, 1)|RD(21), F3(~2, ~0x30, ~1)|RD(~21), "1,i,_", 0, v9a }, /* wr r,i,%clear_softint */ -{ "wr", F3(2, 0x30, 0)|RD(22), F3(~2, ~0x30, ~0)|RD(~22)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%softint */ -{ "wr", F3(2, 0x30, 1)|RD(22), F3(~2, ~0x30, ~1)|RD(~22), "1,i,_", 0, v9a }, /* wr r,i,%softint */ -{ "wr", F3(2, 0x30, 0)|RD(23), F3(~2, ~0x30, ~0)|RD(~23)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%tick_cmpr */ -{ "wr", F3(2, 0x30, 1)|RD(23), F3(~2, ~0x30, ~1)|RD(~23), "1,i,_", 0, v9a }, /* wr r,i,%tick_cmpr */ -{ "wr", F3(2, 0x30, 0)|RD(24), F3(~2, ~0x30, ~0)|RD(~24)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick */ -{ "wr", F3(2, 0x30, 1)|RD(24), F3(~2, ~0x30, ~1)|RD(~24), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick */ -{ "wr", F3(2, 0x30, 0)|RD(25), F3(~2, ~0x30, ~0)|RD(~25)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick_cmpr */ -{ "wr", F3(2, 0x30, 1)|RD(25), F3(~2, ~0x30, ~1)|RD(~25), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick_cmpr */ - -{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", 0, v8 }, /* rd %asrX,r */ -{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", 0, v6 }, /* rd %y,r */ -{ "rd", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", 0, v6notv9 }, /* rd %psr,r */ -{ "rd", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", 0, v6notv9 }, /* rd %wim,r */ -{ "rd", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", 0, v6notv9 }, /* rd %tbr,r */ - -{ "rd", F3(2, 0x28, 0)|RS1(2), F3(~2, ~0x28, ~0)|RS1(~2)|SIMM13(~0), "E,d", 0, v9 }, /* rd %ccr,r */ -{ "rd", F3(2, 0x28, 0)|RS1(3), F3(~2, ~0x28, ~0)|RS1(~3)|SIMM13(~0), "o,d", 0, v9 }, /* rd %asi,r */ -{ "rd", F3(2, 0x28, 0)|RS1(4), F3(~2, ~0x28, ~0)|RS1(~4)|SIMM13(~0), "W,d", 0, v9 }, /* rd %tick,r */ -{ "rd", F3(2, 0x28, 0)|RS1(5), F3(~2, ~0x28, ~0)|RS1(~5)|SIMM13(~0), "P,d", 0, v9 }, /* rd %pc,r */ -{ "rd", F3(2, 0x28, 0)|RS1(6), F3(~2, ~0x28, ~0)|RS1(~6)|SIMM13(~0), "s,d", 0, v9 }, /* rd %fprs,r */ - -{ "rd", F3(2, 0x28, 0)|RS1(16), F3(~2, ~0x28, ~0)|RS1(~16)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pcr,r */ -{ "rd", F3(2, 0x28, 0)|RS1(17), F3(~2, ~0x28, ~0)|RS1(~17)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pic,r */ -{ "rd", F3(2, 0x28, 0)|RS1(18), F3(~2, ~0x28, ~0)|RS1(~18)|SIMM13(~0), "/,d", 0, v9a }, /* rd %dcr,r */ -{ "rd", F3(2, 0x28, 0)|RS1(19), F3(~2, ~0x28, ~0)|RS1(~19)|SIMM13(~0), "/,d", 0, v9a }, /* rd %gsr,r */ -{ "rd", F3(2, 0x28, 0)|RS1(22), F3(~2, ~0x28, ~0)|RS1(~22)|SIMM13(~0), "/,d", 0, v9a }, /* rd %softint,r */ -{ "rd", F3(2, 0x28, 0)|RS1(23), F3(~2, ~0x28, ~0)|RS1(~23)|SIMM13(~0), "/,d", 0, v9a }, /* rd %tick_cmpr,r */ -{ "rd", F3(2, 0x28, 0)|RS1(24), F3(~2, ~0x28, ~0)|RS1(~24)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick,r */ -{ "rd", F3(2, 0x28, 0)|RS1(25), F3(~2, ~0x28, ~0)|RS1(~25)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick_cmpr,r */ - -{ "rdpr", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|SIMM13(~0), "?,d", 0, v9 }, /* rdpr %priv,r */ -{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0), "1,2,!", 0, v9 }, /* wrpr r1,r2,%priv */ -{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|SIMM13(~0), "1,!", 0, v9 }, /* wrpr r1,%priv */ -{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "1,i,!", 0, v9 }, /* wrpr r1,i,%priv */ -{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,1,!", F_ALIAS, v9 }, /* wrpr i,r1,%priv */ -{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RS1(~0), "i,!", 0, v9 }, /* wrpr i,%priv */ +{ "orn", F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "1,i,d", 0, v6 }, + +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0), "1", 0, v6 }, /* orcc rs1, %g0, %g0 */ +{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */ +{ "tst", F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0), "1", 0, v6 }, /* orcc rs1, 0, %g0 */ + +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", 0, v8 }, /* wr r,r,%asrX */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", 0, v8 }, /* wr r,i,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", 0, v6 }, /* wr r,r,%y */ +{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", 0, v6 }, /* wr r,i,%y */ +{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", 0, v6notv9 }, /* wr r,r,%psr */ +{ "wr", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", 0, v6notv9 }, /* wr r,i,%psr */ +{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", 0, v6notv9 }, /* wr r,r,%wim */ +{ "wr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", 0, v6notv9 }, /* wr r,i,%wim */ +{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", 0, v6notv9 }, /* wr r,r,%tbr */ +{ "wr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", 0, v6notv9 }, /* wr r,i,%tbr */ +{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ + +{ "wr", F3(2, 0x30, 0)|RD(2), F3(~2, ~0x30, ~0)|RD(~2)|ASI(~0), "1,2,E", 0, v9 }, /* wr r,r,%ccr */ +{ "wr", F3(2, 0x30, 1)|RD(2), F3(~2, ~0x30, ~1)|RD(~2), "1,i,E", 0, v9 }, /* wr r,i,%ccr */ +{ "wr", F3(2, 0x30, 0)|RD(3), F3(~2, ~0x30, ~0)|RD(~3)|ASI(~0), "1,2,o", 0, v9 }, /* wr r,r,%asi */ +{ "wr", F3(2, 0x30, 1)|RD(3), F3(~2, ~0x30, ~1)|RD(~3), "1,i,o", 0, v9 }, /* wr r,i,%asi */ +{ "wr", F3(2, 0x30, 0)|RD(6), F3(~2, ~0x30, ~0)|RD(~6)|ASI(~0), "1,2,s", 0, v9 }, /* wr r,r,%fprs */ +{ "wr", F3(2, 0x30, 1)|RD(6), F3(~2, ~0x30, ~1)|RD(~6), "1,i,s", 0, v9 }, /* wr r,i,%fprs */ + +{ "wr", F3(2, 0x30, 0)|RD(16), F3(~2, ~0x30, ~0)|RD(~16)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pcr */ +{ "wr", F3(2, 0x30, 1)|RD(16), F3(~2, ~0x30, ~1)|RD(~16), "1,i,_", 0, v9a }, /* wr r,i,%pcr */ +{ "wr", F3(2, 0x30, 0)|RD(17), F3(~2, ~0x30, ~0)|RD(~17)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pic */ +{ "wr", F3(2, 0x30, 1)|RD(17), F3(~2, ~0x30, ~1)|RD(~17), "1,i,_", 0, v9a }, /* wr r,i,%pic */ +{ "wr", F3(2, 0x30, 0)|RD(18), F3(~2, ~0x30, ~0)|RD(~18)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%dcr */ +{ "wr", F3(2, 0x30, 1)|RD(18), F3(~2, ~0x30, ~1)|RD(~18), "1,i,_", 0, v9a }, /* wr r,i,%dcr */ +{ "wr", F3(2, 0x30, 0)|RD(19), F3(~2, ~0x30, ~0)|RD(~19)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%gsr */ +{ "wr", F3(2, 0x30, 1)|RD(19), F3(~2, ~0x30, ~1)|RD(~19), "1,i,_", 0, v9a }, /* wr r,i,%gsr */ +{ "wr", F3(2, 0x30, 0)|RD(20), F3(~2, ~0x30, ~0)|RD(~20)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%set_softint */ +{ "wr", F3(2, 0x30, 1)|RD(20), F3(~2, ~0x30, ~1)|RD(~20), "1,i,_", 0, v9a }, /* wr r,i,%set_softint */ +{ "wr", F3(2, 0x30, 0)|RD(21), F3(~2, ~0x30, ~0)|RD(~21)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%clear_softint */ +{ "wr", F3(2, 0x30, 1)|RD(21), F3(~2, ~0x30, ~1)|RD(~21), "1,i,_", 0, v9a }, /* wr r,i,%clear_softint */ +{ "wr", F3(2, 0x30, 0)|RD(22), F3(~2, ~0x30, ~0)|RD(~22)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%softint */ +{ "wr", F3(2, 0x30, 1)|RD(22), F3(~2, ~0x30, ~1)|RD(~22), "1,i,_", 0, v9a }, /* wr r,i,%softint */ +{ "wr", F3(2, 0x30, 0)|RD(23), F3(~2, ~0x30, ~0)|RD(~23)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%tick_cmpr */ +{ "wr", F3(2, 0x30, 1)|RD(23), F3(~2, ~0x30, ~1)|RD(~23), "1,i,_", 0, v9a }, /* wr r,i,%tick_cmpr */ +{ "wr", F3(2, 0x30, 0)|RD(24), F3(~2, ~0x30, ~0)|RD(~24)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick */ +{ "wr", F3(2, 0x30, 1)|RD(24), F3(~2, ~0x30, ~1)|RD(~24), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick */ +{ "wr", F3(2, 0x30, 0)|RD(25), F3(~2, ~0x30, ~0)|RD(~25)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick_cmpr */ +{ "wr", F3(2, 0x30, 1)|RD(25), F3(~2, ~0x30, ~1)|RD(~25), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick_cmpr */ + +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", 0, v8 }, /* rd %asrX,r */ +{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", 0, v6 }, /* rd %y,r */ +{ "rd", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", 0, v6notv9 }, /* rd %psr,r */ +{ "rd", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", 0, v6notv9 }, /* rd %wim,r */ +{ "rd", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", 0, v6notv9 }, /* rd %tbr,r */ + +{ "rd", F3(2, 0x28, 0)|RS1(2), F3(~2, ~0x28, ~0)|RS1(~2)|SIMM13(~0), "E,d", 0, v9 }, /* rd %ccr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(3), F3(~2, ~0x28, ~0)|RS1(~3)|SIMM13(~0), "o,d", 0, v9 }, /* rd %asi,r */ +{ "rd", F3(2, 0x28, 0)|RS1(4), F3(~2, ~0x28, ~0)|RS1(~4)|SIMM13(~0), "W,d", 0, v9 }, /* rd %tick,r */ +{ "rd", F3(2, 0x28, 0)|RS1(5), F3(~2, ~0x28, ~0)|RS1(~5)|SIMM13(~0), "P,d", 0, v9 }, /* rd %pc,r */ +{ "rd", F3(2, 0x28, 0)|RS1(6), F3(~2, ~0x28, ~0)|RS1(~6)|SIMM13(~0), "s,d", 0, v9 }, /* rd %fprs,r */ + +{ "rd", F3(2, 0x28, 0)|RS1(16), F3(~2, ~0x28, ~0)|RS1(~16)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pcr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(17), F3(~2, ~0x28, ~0)|RS1(~17)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pic,r */ +{ "rd", F3(2, 0x28, 0)|RS1(18), F3(~2, ~0x28, ~0)|RS1(~18)|SIMM13(~0), "/,d", 0, v9a }, /* rd %dcr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(19), F3(~2, ~0x28, ~0)|RS1(~19)|SIMM13(~0), "/,d", 0, v9a }, /* rd %gsr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(22), F3(~2, ~0x28, ~0)|RS1(~22)|SIMM13(~0), "/,d", 0, v9a }, /* rd %softint,r */ +{ "rd", F3(2, 0x28, 0)|RS1(23), F3(~2, ~0x28, ~0)|RS1(~23)|SIMM13(~0), "/,d", 0, v9a }, /* rd %tick_cmpr,r */ +{ "rd", F3(2, 0x28, 0)|RS1(24), F3(~2, ~0x28, ~0)|RS1(~24)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick,r */ +{ "rd", F3(2, 0x28, 0)|RS1(25), F3(~2, ~0x28, ~0)|RS1(~25)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick_cmpr,r */ + +{ "rdpr", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|SIMM13(~0), "?,d", 0, v9 }, /* rdpr %priv,r */ +{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0), "1,2,!", 0, v9 }, /* wrpr r1,r2,%priv */ +{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|SIMM13(~0), "1,!", 0, v9 }, /* wrpr r1,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "1,i,!", 0, v9 }, /* wrpr r1,i,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,1,!", F_ALIAS, v9 }, /* wrpr i,r1,%priv */ +{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RS1(~0), "i,!", 0, v9 }, /* wrpr i,%priv */ /* ??? This group seems wrong. A three operand move? */ -{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */ -{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */ -{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */ -{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */ -{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", F_ALIAS, v6notv9 }, /* wr r,r,%psr */ -{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", F_ALIAS, v6notv9 }, /* wr r,i,%psr */ -{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", F_ALIAS, v6notv9 }, /* wr r,r,%wim */ -{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", F_ALIAS, v6notv9 }, /* wr r,i,%wim */ -{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", F_ALIAS, v6notv9 }, /* wr r,r,%tbr */ -{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", F_ALIAS, v6notv9 }, /* wr r,i,%tbr */ - -{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", F_ALIAS, v8 }, /* rd %asr1,r */ -{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", F_ALIAS, v6 }, /* rd %y,r */ -{ "mov", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", F_ALIAS, v6notv9 }, /* rd %psr,r */ -{ "mov", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", F_ALIAS, v6notv9 }, /* rd %wim,r */ -{ "mov", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", F_ALIAS, v6notv9 }, /* rd %tbr,r */ - -{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ -{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "i,m", F_ALIAS, v8 }, /* wr %g0,i,%asrX */ -{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,0,%asrX */ -{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ -{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "i,y", F_ALIAS, v6 }, /* wr %g0,i,%y */ -{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0|SIMM13(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */ -{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ -{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "i,p", F_ALIAS, v6notv9 }, /* wr %g0,i,%psr */ -{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0|SIMM13(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,0,%psr */ -{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ -{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "i,w", F_ALIAS, v6notv9 }, /* wr %g0,i,%wim */ -{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0|SIMM13(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,0,%wim */ -{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ -{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "i,t", F_ALIAS, v6notv9 }, /* wr %g0,i,%tbr */ -{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0|SIMM13(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,0,%tbr */ - -{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0), "2,d", 0, v6 }, /* or %g0,rs2,d */ -{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0, "i,d", 0, v6 }, /* or %g0,i,d */ -{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0), "1,d", 0, v6 }, /* or rs1,%g0,d */ -{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0), "1,d", 0, v6 }, /* or rs1,0,d */ - -{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "1,i,d", 0, v6 }, -{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,1,d", 0, v6 }, - -{ "bset", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* or rd,rs2,rd */ -{ "bset", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,r", F_ALIAS, v6 }, /* or rd,i,rd */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", F_ALIAS, v6notv9 }, /* wr r,r,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", F_ALIAS, v6notv9 }, /* wr r,i,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", F_ALIAS, v6notv9 }, /* wr r,r,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", F_ALIAS, v6notv9 }, /* wr r,i,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", F_ALIAS, v6notv9 }, /* wr r,r,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", F_ALIAS, v6notv9 }, /* wr r,i,%tbr */ + +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", F_ALIAS, v8 }, /* rd %asr1,r */ +{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", F_ALIAS, v6 }, /* rd %y,r */ +{ "mov", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", F_ALIAS, v6notv9 }, /* rd %psr,r */ +{ "mov", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", F_ALIAS, v6notv9 }, /* rd %wim,r */ +{ "mov", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", F_ALIAS, v6notv9 }, /* rd %tbr,r */ + +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "i,m", F_ALIAS, v8 }, /* wr %g0,i,%asrX */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,0,%asrX */ +{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "i,y", F_ALIAS, v6 }, /* wr %g0,i,%y */ +{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0|SIMM13(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */ +{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "i,p", F_ALIAS, v6notv9 }, /* wr %g0,i,%psr */ +{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0|SIMM13(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,0,%psr */ +{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "i,w", F_ALIAS, v6notv9 }, /* wr %g0,i,%wim */ +{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0|SIMM13(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,0,%wim */ +{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "i,t", F_ALIAS, v6notv9 }, /* wr %g0,i,%tbr */ +{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0|SIMM13(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,0,%tbr */ + +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0), "2,d", 0, v6 }, /* or %g0,rs2,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0, "i,d", 0, v6 }, /* or %g0,i,d */ +{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0), "1,d", 0, v6 }, /* or rs1,%g0,d */ +{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0), "1,d", 0, v6 }, /* or rs1,0,d */ + +{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "1,i,d", 0, v6 }, +{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,1,d", 0, v6 }, + +{ "bset", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* or rd,rs2,rd */ +{ "bset", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,r", F_ALIAS, v6 }, /* or rd,i,rd */ /* This is not a commutative instruction. */ -{ "andn", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "1,i,d", 0, v6 }, +{ "andn", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "1,i,d", 0, v6 }, /* This is not a commutative instruction. */ -{ "andncc", F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "1,i,d", 0, v6 }, - -{ "bclr", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* andn rd,rs2,rd */ -{ "bclr", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,r", F_ALIAS, v6 }, /* andn rd,i,rd */ - -{ "cmp", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0), "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */ -{ "cmp", F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0, "1,i", 0, v6 }, /* subcc rs1,i,%g0 */ - -{ "sub", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "sub", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "1,i,d", 0, v6 }, - -{ "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 }, - -{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, -{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6notv9 }, -{ "subc", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "subc", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v9 }, - -{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, -{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6notv9 }, -{ "subccc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "subccc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v9 }, - -{ "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 }, -{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "i,1,d", 0, v6 }, - -{ "andcc", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "1,i,d", 0, v6 }, -{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "i,1,d", 0, v6 }, - -{ "dec", F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* sub rd,1,rd */ -{ "dec", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "i,r", F_ALIAS, v8 }, /* sub rd,imm,rd */ -{ "deccc", F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* subcc rd,1,rd */ -{ "deccc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "i,r", F_ALIAS, v8 }, /* subcc rd,imm,rd */ -{ "inc", F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* add rd,1,rd */ -{ "inc", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,r", F_ALIAS, v8 }, /* add rd,imm,rd */ -{ "inccc", F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* addcc rd,1,rd */ -{ "inccc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,r", F_ALIAS, v8 }, /* addcc rd,imm,rd */ - -{ "btst", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 }, /* andcc rs1,rs2,%g0 */ -{ "btst", F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 }, /* andcc rs1,i,%g0 */ - -{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */ -{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "O", F_ALIAS, v6 }, /* sub %g0,rd,rd */ - -{ "add", F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "1,i,d", 0, v6 }, -{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,1,d", 0, v6 }, -{ "addcc", F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 }, -{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 }, - -{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, -{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6notv9 }, -{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6notv9 }, -{ "addc", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v9 }, -{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v9 }, - -{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, -{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6notv9 }, -{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6notv9 }, -{ "addccc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v9 }, -{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v9 }, - -{ "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 }, -{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 }, -{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "i,1,d", 0, v8 }, -{ "smulcc", F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0), "1,2,d", 0, v8 }, -{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "1,i,d", 0, v8 }, -{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "i,1,d", 0, v8 }, -{ "umul", F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0), "1,2,d", 0, v8 }, -{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "1,i,d", 0, v8 }, -{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "i,1,d", 0, v8 }, -{ "umulcc", F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0), "1,2,d", 0, v8 }, -{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "1,i,d", 0, v8 }, -{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "i,1,d", 0, v8 }, -{ "sdiv", F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0), "1,2,d", 0, v8 }, -{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "1,i,d", 0, v8 }, -{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "i,1,d", 0, v8 }, -{ "sdivcc", F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0), "1,2,d", 0, v8 }, -{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "1,i,d", 0, v8 }, -{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "i,1,d", 0, v8 }, -{ "udiv", F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0), "1,2,d", 0, v8 }, -{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "1,i,d", 0, v8 }, -{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "i,1,d", 0, v8 }, -{ "udivcc", F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0), "1,2,d", 0, v8 }, -{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "1,i,d", 0, v8 }, -{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "i,1,d", 0, v8 }, - -{ "mulx", F3(2, 0x09, 0), F3(~2, ~0x09, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "mulx", F3(2, 0x09, 1), F3(~2, ~0x09, ~1), "1,i,d", 0, v9 }, -{ "sdivx", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "sdivx", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, v9 }, -{ "udivx", F3(2, 0x0d, 0), F3(~2, ~0x0d, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "udivx", F3(2, 0x0d, 1), F3(~2, ~0x0d, ~1), "1,i,d", 0, v9 }, - -{ "call", F1(0x1), F1(~0x1), "L", F_JSR|F_DELAYED, v6 }, -{ "call", F1(0x1), F1(~0x1), "L,#", F_JSR|F_DELAYED, v6 }, - -{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */ -{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2,#", F_JSR|F_DELAYED, v6 }, -{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%o7 */ -{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_JSR|F_DELAYED, v6 }, -{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */ -{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i,#", F_JSR|F_DELAYED, v6 }, -{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1", F_JSR|F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */ -{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1,#", F_JSR|F_DELAYED, v6 }, -{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,%o7 */ -{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i,#", F_JSR|F_DELAYED, v6 }, -{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,%o7 */ -{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1,#", F_JSR|F_DELAYED, v6 }, +{ "andncc", F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "1,i,d", 0, v6 }, + +{ "bclr", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* andn rd,rs2,rd */ +{ "bclr", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,r", F_ALIAS, v6 }, /* andn rd,i,rd */ + +{ "cmp", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0), "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */ +{ "cmp", F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0, "1,i", 0, v6 }, /* subcc rs1,i,%g0 */ + +{ "sub", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "sub", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "1,i,d", 0, v6 }, + +{ "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 }, + +{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6notv9 }, +{ "subc", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "subc", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v9 }, + +{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6notv9 }, +{ "subccc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "subccc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v9 }, + +{ "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 }, +{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "i,1,d", 0, v6 }, + +{ "andcc", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "1,i,d", 0, v6 }, +{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "i,1,d", 0, v6 }, + +{ "dec", F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* sub rd,1,rd */ +{ "dec", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "i,r", F_ALIAS, v8 }, /* sub rd,imm,rd */ +{ "deccc", F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* subcc rd,1,rd */ +{ "deccc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "i,r", F_ALIAS, v8 }, /* subcc rd,imm,rd */ +{ "inc", F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* add rd,1,rd */ +{ "inc", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,r", F_ALIAS, v8 }, /* add rd,imm,rd */ +{ "inccc", F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* addcc rd,1,rd */ +{ "inccc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,r", F_ALIAS, v8 }, /* addcc rd,imm,rd */ + +{ "btst", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 }, /* andcc rs1,rs2,%g0 */ +{ "btst", F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 }, /* andcc rs1,i,%g0 */ + +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */ +{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "O", F_ALIAS, v6 }, /* sub %g0,rd,rd */ + +{ "add", F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "1,i,d", 0, v6 }, +{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,1,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 }, +{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 }, + +{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6notv9 }, +{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6notv9 }, +{ "addc", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v9 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v9 }, + +{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6notv9 }, +{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6notv9 }, +{ "addccc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v9 }, + +{ "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 }, +{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "i,1,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "1,i,d", 0, v8 }, +{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "i,1,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "1,i,d", 0, v8 }, +{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "i,1,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "1,i,d", 0, v8 }, +{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "i,1,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "1,i,d", 0, v8 }, +{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "i,1,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "1,i,d", 0, v8 }, +{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "i,1,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "1,i,d", 0, v8 }, +{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "i,1,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0), "1,2,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "1,i,d", 0, v8 }, +{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "i,1,d", 0, v8 }, + +{ "mulx", F3(2, 0x09, 0), F3(~2, ~0x09, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "mulx", F3(2, 0x09, 1), F3(~2, ~0x09, ~1), "1,i,d", 0, v9 }, +{ "sdivx", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "sdivx", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, v9 }, +{ "udivx", F3(2, 0x0d, 0), F3(~2, ~0x0d, ~0)|ASI(~0), "1,2,d", 0, v9 }, +{ "udivx", F3(2, 0x0d, 1), F3(~2, ~0x0d, ~1), "1,i,d", 0, v9 }, + +{ "call", F1(0x1), F1(~0x1), "L", F_JSR|F_DELAYED, v6 }, +{ "call", F1(0x1), F1(~0x1), "L,#", F_JSR|F_DELAYED, v6 }, + +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%o7 */ +{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1", F_JSR|F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i,#", F_JSR|F_DELAYED, v6 }, +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,%o7 */ +{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1,#", F_JSR|F_DELAYED, v6 }, /* Conditional instructions. @@ -1278,18 +1278,18 @@ const struct sparc_opcode sparc_opcodes[] = { /* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */ #define tr(opcode, mask, lose, flags) \ - { opcode, (mask)|(2<<11)|IMMED, (lose)|RS1_G0, "Z,i", (flags), v9 }, /* %g0 + imm */ \ - { opcode, (mask)|(2<<11)|IMMED, (lose), "Z,1+i", (flags), v9 }, /* rs1 + imm */ \ - { opcode, (mask)|(2<<11), IMMED|(lose), "Z,1+2", (flags), v9 }, /* rs1 + rs2 */ \ - { opcode, (mask)|(2<<11), IMMED|(lose)|RS2_G0, "Z,1", (flags), v9 }, /* rs1 + %g0 */ \ - { opcode, (mask)|IMMED, (lose)|RS1_G0, "z,i", (flags)|F_ALIAS, v9 }, /* %g0 + imm */ \ - { opcode, (mask)|IMMED, (lose), "z,1+i", (flags)|F_ALIAS, v9 }, /* rs1 + imm */ \ - { opcode, (mask), IMMED|(lose), "z,1+2", (flags)|F_ALIAS, v9 }, /* rs1 + rs2 */ \ - { opcode, (mask), IMMED|(lose)|RS2_G0, "z,1", (flags)|F_ALIAS, v9 }, /* rs1 + %g0 */ \ - { opcode, (mask)|IMMED, (lose)|RS1_G0, "i", (flags), v6 }, /* %g0 + imm */ \ - { opcode, (mask)|IMMED, (lose), "1+i", (flags), v6 }, /* rs1 + imm */ \ - { opcode, (mask), IMMED|(lose), "1+2", (flags), v6 }, /* rs1 + rs2 */ \ - { opcode, (mask), IMMED|(lose)|RS2_G0, "1", (flags), v6 } /* rs1 + %g0 */ + { opcode, (mask)|(2<<11)|IMMED, (lose)|RS1_G0, "Z,i", (flags), v9 }, /* %g0 + imm */ \ + { opcode, (mask)|(2<<11)|IMMED, (lose), "Z,1+i", (flags), v9 }, /* rs1 + imm */ \ + { opcode, (mask)|(2<<11), IMMED|(lose), "Z,1+2", (flags), v9 }, /* rs1 + rs2 */ \ + { opcode, (mask)|(2<<11), IMMED|(lose)|RS2_G0, "Z,1", (flags), v9 }, /* rs1 + %g0 */ \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "z,i", (flags)|F_ALIAS, v9 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "z,1+i", (flags)|F_ALIAS, v9 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "z,1+2", (flags)|F_ALIAS, v9 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "z,1", (flags)|F_ALIAS, v9 }, /* rs1 + %g0 */ \ + { opcode, (mask)|IMMED, (lose)|RS1_G0, "i", (flags), v6 }, /* %g0 + imm */ \ + { opcode, (mask)|IMMED, (lose), "1+i", (flags), v6 }, /* rs1 + imm */ \ + { opcode, (mask), IMMED|(lose), "1+2", (flags), v6 }, /* rs1 + rs2 */ \ + { opcode, (mask), IMMED|(lose)|RS2_G0, "1", (flags), v6 } /* rs1 + %g0 */ /* v9: We must put `brx' before `br', to ensure that we never match something v9: against an expression unless it is an expression. Otherwise, we end @@ -1305,32 +1305,32 @@ const struct sparc_opcode sparc_opcodes[] = { /* Define all the conditions, all the branches, all the traps. */ /* Standard branch, trap mnemonics */ -cond ("b", "ta", CONDA, F_UNBR), +cond ("b", "ta", CONDA, F_UNBR), /* Alternative form (just for assembly, not for disassembly) */ -cond ("ba", "t", CONDA, F_UNBR|F_ALIAS), - -cond ("bcc", "tcc", CONDCC, F_CONDBR), -cond ("bcs", "tcs", CONDCS, F_CONDBR), -cond ("be", "te", CONDE, F_CONDBR), -cond ("beq", "teq", CONDE, F_CONDBR|F_ALIAS), -cond ("bg", "tg", CONDG, F_CONDBR), -cond ("bgt", "tgt", CONDG, F_CONDBR|F_ALIAS), -cond ("bge", "tge", CONDGE, F_CONDBR), -cond ("bgeu", "tgeu", CONDGEU, F_CONDBR|F_ALIAS), /* for cc */ -cond ("bgu", "tgu", CONDGU, F_CONDBR), -cond ("bl", "tl", CONDL, F_CONDBR), -cond ("blt", "tlt", CONDL, F_CONDBR|F_ALIAS), -cond ("ble", "tle", CONDLE, F_CONDBR), -cond ("bleu", "tleu", CONDLEU, F_CONDBR), -cond ("blu", "tlu", CONDLU, F_CONDBR|F_ALIAS), /* for cs */ -cond ("bn", "tn", CONDN, F_CONDBR), -cond ("bne", "tne", CONDNE, F_CONDBR), -cond ("bneg", "tneg", CONDNEG, F_CONDBR), -cond ("bnz", "tnz", CONDNZ, F_CONDBR|F_ALIAS), /* for ne */ -cond ("bpos", "tpos", CONDPOS, F_CONDBR), -cond ("bvc", "tvc", CONDVC, F_CONDBR), -cond ("bvs", "tvs", CONDVS, F_CONDBR), -cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ +cond ("ba", "t", CONDA, F_UNBR|F_ALIAS), + +cond ("bcc", "tcc", CONDCC, F_CONDBR), +cond ("bcs", "tcs", CONDCS, F_CONDBR), +cond ("be", "te", CONDE, F_CONDBR), +cond ("beq", "teq", CONDE, F_CONDBR|F_ALIAS), +cond ("bg", "tg", CONDG, F_CONDBR), +cond ("bgt", "tgt", CONDG, F_CONDBR|F_ALIAS), +cond ("bge", "tge", CONDGE, F_CONDBR), +cond ("bgeu", "tgeu", CONDGEU, F_CONDBR|F_ALIAS), /* for cc */ +cond ("bgu", "tgu", CONDGU, F_CONDBR), +cond ("bl", "tl", CONDL, F_CONDBR), +cond ("blt", "tlt", CONDL, F_CONDBR|F_ALIAS), +cond ("ble", "tle", CONDLE, F_CONDBR), +cond ("bleu", "tleu", CONDLEU, F_CONDBR), +cond ("blu", "tlu", CONDLU, F_CONDBR|F_ALIAS), /* for cs */ +cond ("bn", "tn", CONDN, F_CONDBR), +cond ("bne", "tne", CONDNE, F_CONDBR), +cond ("bneg", "tneg", CONDNEG, F_CONDBR), +cond ("bnz", "tnz", CONDNZ, F_CONDBR|F_ALIAS), /* for ne */ +cond ("bpos", "tpos", CONDPOS, F_CONDBR), +cond ("bvc", "tvc", CONDVC, F_CONDBR), +cond ("bvs", "tvs", CONDVS, F_CONDBR), +cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ #undef cond #undef br @@ -1436,42 +1436,42 @@ cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ movfcc (opcode, fcond, flags), /* v9 */ \ movicc (opcode, cond, flags) /* v9 */ -/* v9 */ movcc ("mova", CONDA, FCONDA, 0), -/* v9 */ movicc ("movcc", CONDCC, 0), -/* v9 */ movicc ("movgeu", CONDGEU, F_ALIAS), -/* v9 */ movicc ("movcs", CONDCS, 0), -/* v9 */ movicc ("movlu", CONDLU, F_ALIAS), -/* v9 */ movcc ("move", CONDE, FCONDE, 0), -/* v9 */ movcc ("movg", CONDG, FCONDG, 0), -/* v9 */ movcc ("movge", CONDGE, FCONDGE, 0), -/* v9 */ movicc ("movgu", CONDGU, 0), -/* v9 */ movcc ("movl", CONDL, FCONDL, 0), -/* v9 */ movcc ("movle", CONDLE, FCONDLE, 0), -/* v9 */ movicc ("movleu", CONDLEU, 0), -/* v9 */ movfcc ("movlg", FCONDLG, 0), -/* v9 */ movcc ("movn", CONDN, FCONDN, 0), -/* v9 */ movcc ("movne", CONDNE, FCONDNE, 0), -/* v9 */ movicc ("movneg", CONDNEG, 0), -/* v9 */ movcc ("movnz", CONDNZ, FCONDNZ, F_ALIAS), -/* v9 */ movfcc ("movo", FCONDO, 0), -/* v9 */ movicc ("movpos", CONDPOS, 0), -/* v9 */ movfcc ("movu", FCONDU, 0), -/* v9 */ movfcc ("movue", FCONDUE, 0), -/* v9 */ movfcc ("movug", FCONDUG, 0), -/* v9 */ movfcc ("movuge", FCONDUGE, 0), -/* v9 */ movfcc ("movul", FCONDUL, 0), -/* v9 */ movfcc ("movule", FCONDULE, 0), -/* v9 */ movicc ("movvc", CONDVC, 0), -/* v9 */ movicc ("movvs", CONDVS, 0), -/* v9 */ movcc ("movz", CONDZ, FCONDZ, F_ALIAS), +/* v9 */ movcc ("mova", CONDA, FCONDA, 0), +/* v9 */ movicc ("movcc", CONDCC, 0), +/* v9 */ movicc ("movgeu", CONDGEU, F_ALIAS), +/* v9 */ movicc ("movcs", CONDCS, 0), +/* v9 */ movicc ("movlu", CONDLU, F_ALIAS), +/* v9 */ movcc ("move", CONDE, FCONDE, 0), +/* v9 */ movcc ("movg", CONDG, FCONDG, 0), +/* v9 */ movcc ("movge", CONDGE, FCONDGE, 0), +/* v9 */ movicc ("movgu", CONDGU, 0), +/* v9 */ movcc ("movl", CONDL, FCONDL, 0), +/* v9 */ movcc ("movle", CONDLE, FCONDLE, 0), +/* v9 */ movicc ("movleu", CONDLEU, 0), +/* v9 */ movfcc ("movlg", FCONDLG, 0), +/* v9 */ movcc ("movn", CONDN, FCONDN, 0), +/* v9 */ movcc ("movne", CONDNE, FCONDNE, 0), +/* v9 */ movicc ("movneg", CONDNEG, 0), +/* v9 */ movcc ("movnz", CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ movfcc ("movo", FCONDO, 0), +/* v9 */ movicc ("movpos", CONDPOS, 0), +/* v9 */ movfcc ("movu", FCONDU, 0), +/* v9 */ movfcc ("movue", FCONDUE, 0), +/* v9 */ movfcc ("movug", FCONDUG, 0), +/* v9 */ movfcc ("movuge", FCONDUGE, 0), +/* v9 */ movfcc ("movul", FCONDUL, 0), +/* v9 */ movfcc ("movule", FCONDULE, 0), +/* v9 */ movicc ("movvc", CONDVC, 0), +/* v9 */ movicc ("movvs", CONDVS, 0), +/* v9 */ movcc ("movz", CONDZ, FCONDZ, F_ALIAS), #undef movicc /* v9 */ #undef movfcc /* v9 */ #undef movcc /* v9 */ -#define FM_SF 1 /* v9 - values for fpsize */ -#define FM_DF 2 /* v9 */ -#define FM_QF 3 /* v9 */ +#define FM_SF 1 /* v9 - values for fpsize */ +#define FM_DF 2 /* v9 */ +#define FM_QF 3 /* v9 */ #define fmovicc(opcode, fpsize, cond, flags) /* v9 */ \ { opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z,f,g", flags, v9 }, \ @@ -1492,90 +1492,90 @@ cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ { opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8,f,g", flags | F_FLOAT, v9 }, \ { opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9,f,g", flags | F_FLOAT, v9 } -/* v9 */ fmovcc ("fmovda", FM_DF, CONDA, FCONDA, 0), -/* v9 */ fmovcc ("fmovqa", FM_QF, CONDA, FCONDA, 0), -/* v9 */ fmovcc ("fmovsa", FM_SF, CONDA, FCONDA, 0), -/* v9 */ fmovicc ("fmovdcc", FM_DF, CONDCC, 0), -/* v9 */ fmovicc ("fmovqcc", FM_QF, CONDCC, 0), -/* v9 */ fmovicc ("fmovscc", FM_SF, CONDCC, 0), -/* v9 */ fmovicc ("fmovdcs", FM_DF, CONDCS, 0), -/* v9 */ fmovicc ("fmovqcs", FM_QF, CONDCS, 0), -/* v9 */ fmovicc ("fmovscs", FM_SF, CONDCS, 0), -/* v9 */ fmovcc ("fmovde", FM_DF, CONDE, FCONDE, 0), -/* v9 */ fmovcc ("fmovqe", FM_QF, CONDE, FCONDE, 0), -/* v9 */ fmovcc ("fmovse", FM_SF, CONDE, FCONDE, 0), -/* v9 */ fmovcc ("fmovdg", FM_DF, CONDG, FCONDG, 0), -/* v9 */ fmovcc ("fmovqg", FM_QF, CONDG, FCONDG, 0), -/* v9 */ fmovcc ("fmovsg", FM_SF, CONDG, FCONDG, 0), -/* v9 */ fmovcc ("fmovdge", FM_DF, CONDGE, FCONDGE, 0), -/* v9 */ fmovcc ("fmovqge", FM_QF, CONDGE, FCONDGE, 0), -/* v9 */ fmovcc ("fmovsge", FM_SF, CONDGE, FCONDGE, 0), -/* v9 */ fmovicc ("fmovdgeu", FM_DF, CONDGEU, F_ALIAS), -/* v9 */ fmovicc ("fmovqgeu", FM_QF, CONDGEU, F_ALIAS), -/* v9 */ fmovicc ("fmovsgeu", FM_SF, CONDGEU, F_ALIAS), -/* v9 */ fmovicc ("fmovdgu", FM_DF, CONDGU, 0), -/* v9 */ fmovicc ("fmovqgu", FM_QF, CONDGU, 0), -/* v9 */ fmovicc ("fmovsgu", FM_SF, CONDGU, 0), -/* v9 */ fmovcc ("fmovdl", FM_DF, CONDL, FCONDL, 0), -/* v9 */ fmovcc ("fmovql", FM_QF, CONDL, FCONDL, 0), -/* v9 */ fmovcc ("fmovsl", FM_SF, CONDL, FCONDL, 0), -/* v9 */ fmovcc ("fmovdle", FM_DF, CONDLE, FCONDLE, 0), -/* v9 */ fmovcc ("fmovqle", FM_QF, CONDLE, FCONDLE, 0), -/* v9 */ fmovcc ("fmovsle", FM_SF, CONDLE, FCONDLE, 0), -/* v9 */ fmovicc ("fmovdleu", FM_DF, CONDLEU, 0), -/* v9 */ fmovicc ("fmovqleu", FM_QF, CONDLEU, 0), -/* v9 */ fmovicc ("fmovsleu", FM_SF, CONDLEU, 0), -/* v9 */ fmovfcc ("fmovdlg", FM_DF, FCONDLG, 0), -/* v9 */ fmovfcc ("fmovqlg", FM_QF, FCONDLG, 0), -/* v9 */ fmovfcc ("fmovslg", FM_SF, FCONDLG, 0), -/* v9 */ fmovicc ("fmovdlu", FM_DF, CONDLU, F_ALIAS), -/* v9 */ fmovicc ("fmovqlu", FM_QF, CONDLU, F_ALIAS), -/* v9 */ fmovicc ("fmovslu", FM_SF, CONDLU, F_ALIAS), -/* v9 */ fmovcc ("fmovdn", FM_DF, CONDN, FCONDN, 0), -/* v9 */ fmovcc ("fmovqn", FM_QF, CONDN, FCONDN, 0), -/* v9 */ fmovcc ("fmovsn", FM_SF, CONDN, FCONDN, 0), -/* v9 */ fmovcc ("fmovdne", FM_DF, CONDNE, FCONDNE, 0), -/* v9 */ fmovcc ("fmovqne", FM_QF, CONDNE, FCONDNE, 0), -/* v9 */ fmovcc ("fmovsne", FM_SF, CONDNE, FCONDNE, 0), -/* v9 */ fmovicc ("fmovdneg", FM_DF, CONDNEG, 0), -/* v9 */ fmovicc ("fmovqneg", FM_QF, CONDNEG, 0), -/* v9 */ fmovicc ("fmovsneg", FM_SF, CONDNEG, 0), -/* v9 */ fmovcc ("fmovdnz", FM_DF, CONDNZ, FCONDNZ, F_ALIAS), -/* v9 */ fmovcc ("fmovqnz", FM_QF, CONDNZ, FCONDNZ, F_ALIAS), -/* v9 */ fmovcc ("fmovsnz", FM_SF, CONDNZ, FCONDNZ, F_ALIAS), -/* v9 */ fmovfcc ("fmovdo", FM_DF, FCONDO, 0), -/* v9 */ fmovfcc ("fmovqo", FM_QF, FCONDO, 0), -/* v9 */ fmovfcc ("fmovso", FM_SF, FCONDO, 0), -/* v9 */ fmovicc ("fmovdpos", FM_DF, CONDPOS, 0), -/* v9 */ fmovicc ("fmovqpos", FM_QF, CONDPOS, 0), -/* v9 */ fmovicc ("fmovspos", FM_SF, CONDPOS, 0), -/* v9 */ fmovfcc ("fmovdu", FM_DF, FCONDU, 0), -/* v9 */ fmovfcc ("fmovqu", FM_QF, FCONDU, 0), -/* v9 */ fmovfcc ("fmovsu", FM_SF, FCONDU, 0), -/* v9 */ fmovfcc ("fmovdue", FM_DF, FCONDUE, 0), -/* v9 */ fmovfcc ("fmovque", FM_QF, FCONDUE, 0), -/* v9 */ fmovfcc ("fmovsue", FM_SF, FCONDUE, 0), -/* v9 */ fmovfcc ("fmovdug", FM_DF, FCONDUG, 0), -/* v9 */ fmovfcc ("fmovqug", FM_QF, FCONDUG, 0), -/* v9 */ fmovfcc ("fmovsug", FM_SF, FCONDUG, 0), -/* v9 */ fmovfcc ("fmovduge", FM_DF, FCONDUGE, 0), -/* v9 */ fmovfcc ("fmovquge", FM_QF, FCONDUGE, 0), -/* v9 */ fmovfcc ("fmovsuge", FM_SF, FCONDUGE, 0), -/* v9 */ fmovfcc ("fmovdul", FM_DF, FCONDUL, 0), -/* v9 */ fmovfcc ("fmovqul", FM_QF, FCONDUL, 0), -/* v9 */ fmovfcc ("fmovsul", FM_SF, FCONDUL, 0), -/* v9 */ fmovfcc ("fmovdule", FM_DF, FCONDULE, 0), -/* v9 */ fmovfcc ("fmovqule", FM_QF, FCONDULE, 0), -/* v9 */ fmovfcc ("fmovsule", FM_SF, FCONDULE, 0), -/* v9 */ fmovicc ("fmovdvc", FM_DF, CONDVC, 0), -/* v9 */ fmovicc ("fmovqvc", FM_QF, CONDVC, 0), -/* v9 */ fmovicc ("fmovsvc", FM_SF, CONDVC, 0), -/* v9 */ fmovicc ("fmovdvs", FM_DF, CONDVS, 0), -/* v9 */ fmovicc ("fmovqvs", FM_QF, CONDVS, 0), -/* v9 */ fmovicc ("fmovsvs", FM_SF, CONDVS, 0), -/* v9 */ fmovcc ("fmovdz", FM_DF, CONDZ, FCONDZ, F_ALIAS), -/* v9 */ fmovcc ("fmovqz", FM_QF, CONDZ, FCONDZ, F_ALIAS), -/* v9 */ fmovcc ("fmovsz", FM_SF, CONDZ, FCONDZ, F_ALIAS), +/* v9 */ fmovcc ("fmovda", FM_DF, CONDA, FCONDA, 0), +/* v9 */ fmovcc ("fmovqa", FM_QF, CONDA, FCONDA, 0), +/* v9 */ fmovcc ("fmovsa", FM_SF, CONDA, FCONDA, 0), +/* v9 */ fmovicc ("fmovdcc", FM_DF, CONDCC, 0), +/* v9 */ fmovicc ("fmovqcc", FM_QF, CONDCC, 0), +/* v9 */ fmovicc ("fmovscc", FM_SF, CONDCC, 0), +/* v9 */ fmovicc ("fmovdcs", FM_DF, CONDCS, 0), +/* v9 */ fmovicc ("fmovqcs", FM_QF, CONDCS, 0), +/* v9 */ fmovicc ("fmovscs", FM_SF, CONDCS, 0), +/* v9 */ fmovcc ("fmovde", FM_DF, CONDE, FCONDE, 0), +/* v9 */ fmovcc ("fmovqe", FM_QF, CONDE, FCONDE, 0), +/* v9 */ fmovcc ("fmovse", FM_SF, CONDE, FCONDE, 0), +/* v9 */ fmovcc ("fmovdg", FM_DF, CONDG, FCONDG, 0), +/* v9 */ fmovcc ("fmovqg", FM_QF, CONDG, FCONDG, 0), +/* v9 */ fmovcc ("fmovsg", FM_SF, CONDG, FCONDG, 0), +/* v9 */ fmovcc ("fmovdge", FM_DF, CONDGE, FCONDGE, 0), +/* v9 */ fmovcc ("fmovqge", FM_QF, CONDGE, FCONDGE, 0), +/* v9 */ fmovcc ("fmovsge", FM_SF, CONDGE, FCONDGE, 0), +/* v9 */ fmovicc ("fmovdgeu", FM_DF, CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("fmovqgeu", FM_QF, CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("fmovsgeu", FM_SF, CONDGEU, F_ALIAS), +/* v9 */ fmovicc ("fmovdgu", FM_DF, CONDGU, 0), +/* v9 */ fmovicc ("fmovqgu", FM_QF, CONDGU, 0), +/* v9 */ fmovicc ("fmovsgu", FM_SF, CONDGU, 0), +/* v9 */ fmovcc ("fmovdl", FM_DF, CONDL, FCONDL, 0), +/* v9 */ fmovcc ("fmovql", FM_QF, CONDL, FCONDL, 0), +/* v9 */ fmovcc ("fmovsl", FM_SF, CONDL, FCONDL, 0), +/* v9 */ fmovcc ("fmovdle", FM_DF, CONDLE, FCONDLE, 0), +/* v9 */ fmovcc ("fmovqle", FM_QF, CONDLE, FCONDLE, 0), +/* v9 */ fmovcc ("fmovsle", FM_SF, CONDLE, FCONDLE, 0), +/* v9 */ fmovicc ("fmovdleu", FM_DF, CONDLEU, 0), +/* v9 */ fmovicc ("fmovqleu", FM_QF, CONDLEU, 0), +/* v9 */ fmovicc ("fmovsleu", FM_SF, CONDLEU, 0), +/* v9 */ fmovfcc ("fmovdlg", FM_DF, FCONDLG, 0), +/* v9 */ fmovfcc ("fmovqlg", FM_QF, FCONDLG, 0), +/* v9 */ fmovfcc ("fmovslg", FM_SF, FCONDLG, 0), +/* v9 */ fmovicc ("fmovdlu", FM_DF, CONDLU, F_ALIAS), +/* v9 */ fmovicc ("fmovqlu", FM_QF, CONDLU, F_ALIAS), +/* v9 */ fmovicc ("fmovslu", FM_SF, CONDLU, F_ALIAS), +/* v9 */ fmovcc ("fmovdn", FM_DF, CONDN, FCONDN, 0), +/* v9 */ fmovcc ("fmovqn", FM_QF, CONDN, FCONDN, 0), +/* v9 */ fmovcc ("fmovsn", FM_SF, CONDN, FCONDN, 0), +/* v9 */ fmovcc ("fmovdne", FM_DF, CONDNE, FCONDNE, 0), +/* v9 */ fmovcc ("fmovqne", FM_QF, CONDNE, FCONDNE, 0), +/* v9 */ fmovcc ("fmovsne", FM_SF, CONDNE, FCONDNE, 0), +/* v9 */ fmovicc ("fmovdneg", FM_DF, CONDNEG, 0), +/* v9 */ fmovicc ("fmovqneg", FM_QF, CONDNEG, 0), +/* v9 */ fmovicc ("fmovsneg", FM_SF, CONDNEG, 0), +/* v9 */ fmovcc ("fmovdnz", FM_DF, CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovcc ("fmovqnz", FM_QF, CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovcc ("fmovsnz", FM_SF, CONDNZ, FCONDNZ, F_ALIAS), +/* v9 */ fmovfcc ("fmovdo", FM_DF, FCONDO, 0), +/* v9 */ fmovfcc ("fmovqo", FM_QF, FCONDO, 0), +/* v9 */ fmovfcc ("fmovso", FM_SF, FCONDO, 0), +/* v9 */ fmovicc ("fmovdpos", FM_DF, CONDPOS, 0), +/* v9 */ fmovicc ("fmovqpos", FM_QF, CONDPOS, 0), +/* v9 */ fmovicc ("fmovspos", FM_SF, CONDPOS, 0), +/* v9 */ fmovfcc ("fmovdu", FM_DF, FCONDU, 0), +/* v9 */ fmovfcc ("fmovqu", FM_QF, FCONDU, 0), +/* v9 */ fmovfcc ("fmovsu", FM_SF, FCONDU, 0), +/* v9 */ fmovfcc ("fmovdue", FM_DF, FCONDUE, 0), +/* v9 */ fmovfcc ("fmovque", FM_QF, FCONDUE, 0), +/* v9 */ fmovfcc ("fmovsue", FM_SF, FCONDUE, 0), +/* v9 */ fmovfcc ("fmovdug", FM_DF, FCONDUG, 0), +/* v9 */ fmovfcc ("fmovqug", FM_QF, FCONDUG, 0), +/* v9 */ fmovfcc ("fmovsug", FM_SF, FCONDUG, 0), +/* v9 */ fmovfcc ("fmovduge", FM_DF, FCONDUGE, 0), +/* v9 */ fmovfcc ("fmovquge", FM_QF, FCONDUGE, 0), +/* v9 */ fmovfcc ("fmovsuge", FM_SF, FCONDUGE, 0), +/* v9 */ fmovfcc ("fmovdul", FM_DF, FCONDUL, 0), +/* v9 */ fmovfcc ("fmovqul", FM_QF, FCONDUL, 0), +/* v9 */ fmovfcc ("fmovsul", FM_SF, FCONDUL, 0), +/* v9 */ fmovfcc ("fmovdule", FM_DF, FCONDULE, 0), +/* v9 */ fmovfcc ("fmovqule", FM_QF, FCONDULE, 0), +/* v9 */ fmovfcc ("fmovsule", FM_SF, FCONDULE, 0), +/* v9 */ fmovicc ("fmovdvc", FM_DF, CONDVC, 0), +/* v9 */ fmovicc ("fmovqvc", FM_QF, CONDVC, 0), +/* v9 */ fmovicc ("fmovsvc", FM_SF, CONDVC, 0), +/* v9 */ fmovicc ("fmovdvs", FM_DF, CONDVS, 0), +/* v9 */ fmovicc ("fmovqvs", FM_QF, CONDVS, 0), +/* v9 */ fmovicc ("fmovsvs", FM_SF, CONDVS, 0), +/* v9 */ fmovcc ("fmovdz", FM_DF, CONDZ, FCONDZ, F_ALIAS), +/* v9 */ fmovcc ("fmovqz", FM_QF, CONDZ, FCONDZ, F_ALIAS), +/* v9 */ fmovcc ("fmovsz", FM_SF, CONDZ, FCONDZ, F_ALIAS), #undef fmovicc /* v9 */ #undef fmovfcc /* v9 */ @@ -1641,19 +1641,19 @@ cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */ FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags) CONDFC ("fb", "cb", 0x8, F_UNBR), -CONDFCL ("fba", "cba", 0x8, F_UNBR|F_ALIAS), -CONDFC ("fbe", "cb0", 0x9, F_CONDBR), +CONDFCL ("fba", "cba", 0x8, F_UNBR|F_ALIAS), +CONDFC ("fbe", "cb0", 0x9, F_CONDBR), CONDF ("fbz", 0x9, F_CONDBR|F_ALIAS), -CONDFC ("fbg", "cb2", 0x6, F_CONDBR), +CONDFC ("fbg", "cb2", 0x6, F_CONDBR), CONDFC ("fbge", "cb02", 0xb, F_CONDBR), -CONDFC ("fbl", "cb1", 0x4, F_CONDBR), +CONDFC ("fbl", "cb1", 0x4, F_CONDBR), CONDFC ("fble", "cb01", 0xd, F_CONDBR), CONDFC ("fblg", "cb12", 0x2, F_CONDBR), -CONDFCL ("fbn", "cbn", 0x0, F_UNBR), +CONDFCL ("fbn", "cbn", 0x0, F_UNBR), CONDFC ("fbne", "cb123", 0x1, F_CONDBR), CONDF ("fbnz", 0x1, F_CONDBR|F_ALIAS), -CONDFC ("fbo", "cb012", 0xf, F_CONDBR), -CONDFC ("fbu", "cb3", 0x7, F_CONDBR), +CONDFC ("fbo", "cb012", 0xf, F_CONDBR), +CONDFC ("fbu", "cb3", 0x7, F_CONDBR), CONDFC ("fbue", "cb03", 0xa, F_CONDBR), CONDFC ("fbug", "cb23", 0x5, F_CONDBR), CONDFC ("fbuge", "cb023", 0xc, F_CONDBR), @@ -1665,167 +1665,167 @@ CONDFC ("fbule", "cb013", 0xe, F_CONDBR), #undef CONDF #undef CBR #undef FBR -#undef FBRX /* v9 */ +#undef FBRX /* v9 */ -{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */ -{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */ -{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */ -{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */ -{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */ -{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+0,%g0 */ +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */ +{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */ +{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+0,%g0 */ -{ "nop", F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */ +{ "nop", F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */ -{ "set", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v6 }, -{ "setuw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, -{ "setsw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, -{ "setx", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,1,d", F_ALIAS, v9 }, +{ "set", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v6 }, +{ "setuw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, +{ "setsw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 }, +{ "setx", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,1,d", F_ALIAS, v9 }, -{ "sethi", F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 }, +{ "sethi", F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 }, -{ "taddcc", F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "1,i,d", 0, v6 }, -{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "i,1,d", 0, v6 }, -{ "taddcctv", F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "1,i,d", 0, v6 }, -{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "i,1,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "1,i,d", 0, v6 }, +{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "i,1,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "1,i,d", 0, v6 }, +{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "i,1,d", 0, v6 }, -{ "tsubcc", F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "tsubcc", F3(2, 0x21, 1), F3(~2, ~0x21, ~1), "1,i,d", 0, v6 }, -{ "tsubcctv", F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "tsubcctv", F3(2, 0x23, 1), F3(~2, ~0x23, ~1), "1,i,d", 0, v6 }, +{ "tsubcc", F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcc", F3(2, 0x21, 1), F3(~2, ~0x21, ~1), "1,i,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "tsubcctv", F3(2, 0x23, 1), F3(~2, ~0x23, ~1), "1,i,d", 0, v6 }, -{ "unimp", F2(0x0, 0x0), 0xffc00000, "n", 0, v6notv9 }, -{ "illtrap", F2(0, 0), F2(~0, ~0)|RD_G0, "n", 0, v9 }, +{ "unimp", F2(0x0, 0x0), 0xffc00000, "n", 0, v6notv9 }, +{ "illtrap", F2(0, 0), F2(~0, ~0)|RD_G0, "n", 0, v9 }, /* This *is* a commutative instruction. */ -{ "xnor", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "1,i,d", 0, v6 }, -{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "i,1,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "1,i,d", 0, v6 }, +{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "i,1,d", 0, v6 }, /* This *is* a commutative instruction. */ -{ "xnorcc", F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "1,i,d", 0, v6 }, -{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "i,1,d", 0, v6 }, -{ "xor", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "1,i,d", 0, v6 }, -{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,1,d", 0, v6 }, -{ "xorcc", F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0), "1,2,d", 0, v6 }, -{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "1,i,d", 0, v6 }, -{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "i,1,d", 0, v6 }, - -{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */ -{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */ - -{ "btog", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */ -{ "btog", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */ +{ "xnorcc", F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "1,i,d", 0, v6 }, +{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "i,1,d", 0, v6 }, +{ "xor", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "1,i,d", 0, v6 }, +{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,1,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "1,i,d", 0, v6 }, +{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "i,1,d", 0, v6 }, + +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */ +{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */ + +{ "btog", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */ +{ "btog", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */ /* FPop1 and FPop2 are not instructions. Don't accept them. */ -{ "fdtoi", F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", F_FLOAT, v6 }, -{ "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", F_FLOAT, v6 }, -{ "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", F_FLOAT, v8 }, - -{ "fdtox", F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,g", F_FLOAT, v9 }, -{ "fstox", F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,g", F_FLOAT, v9 }, -{ "fqtox", F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,g", F_FLOAT, v9 }, - -{ "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", F_FLOAT, v6 }, -{ "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", F_FLOAT, v6 }, -{ "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", F_FLOAT, v8 }, - -{ "fxtod", F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "f,H", F_FLOAT, v9 }, -{ "fxtos", F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "f,g", F_FLOAT, v9 }, -{ "fxtoq", F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "f,J", F_FLOAT, v9 }, - -{ "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", F_FLOAT, v8 }, -{ "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", F_FLOAT, v6 }, -{ "fqtod", F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", F_FLOAT, v8 }, -{ "fqtos", F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", F_FLOAT, v8 }, -{ "fstod", F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", F_FLOAT, v6 }, -{ "fstoq", F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", F_FLOAT, v8 }, - -{ "fdivd", F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", F_FLOAT, v6 }, -{ "fdivq", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT, v8 }, -{ "fdivx", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT|F_ALIAS, v8 }, -{ "fdivs", F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", F_FLOAT, v6 }, -{ "fmuld", F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", F_FLOAT, v6 }, -{ "fmulq", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT, v8 }, -{ "fmulx", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT|F_ALIAS, v8 }, -{ "fmuls", F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", F_FLOAT, v6 }, - -{ "fdmulq", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT, v8 }, -{ "fdmulx", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT|F_ALIAS, v8 }, -{ "fsmuld", F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", F_FLOAT, v8 }, - -{ "fsqrtd", F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", F_FLOAT, v7 }, -{ "fsqrtq", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT, v8 }, -{ "fsqrtx", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v8 }, -{ "fsqrts", F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", F_FLOAT, v7 }, - -{ "fabsd", F3F(2, 0x34, 0x00a), F3F(~2, ~0x34, ~0x00a)|RS1_G0, "B,H", F_FLOAT, v9 }, -{ "fabsq", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT, v9 }, -{ "fabsx", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, -{ "fabss", F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", F_FLOAT, v6 }, -{ "fmovd", F3F(2, 0x34, 0x002), F3F(~2, ~0x34, ~0x002)|RS1_G0, "B,H", F_FLOAT, v9 }, -{ "fmovq", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT, v9 }, -{ "fmovx", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, -{ "fmovs", F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", F_FLOAT, v6 }, -{ "fnegd", F3F(2, 0x34, 0x006), F3F(~2, ~0x34, ~0x006)|RS1_G0, "B,H", F_FLOAT, v9 }, -{ "fnegq", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT, v9 }, -{ "fnegx", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, -{ "fnegs", F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", F_FLOAT, v6 }, - -{ "faddd", F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", F_FLOAT, v6 }, -{ "faddq", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT, v8 }, -{ "faddx", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT|F_ALIAS, v8 }, -{ "fadds", F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", F_FLOAT, v6 }, -{ "fsubd", F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", F_FLOAT, v6 }, -{ "fsubq", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT, v8 }, -{ "fsubx", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT|F_ALIAS, v8 }, -{ "fsubs", F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", F_FLOAT, v6 }, - -#define CMPFCC(x) (((x)&0x3)<<25) - -{ "fcmpd", F3F(2, 0x35, 0x052), F3F(~2, ~0x35, ~0x052)|RD_G0, "v,B", F_FLOAT, v6 }, -{ "fcmpd", CMPFCC(0)|F3F(2, 0x35, 0x052), CMPFCC(~0)|F3F(~2, ~0x35, ~0x052), "6,v,B", F_FLOAT, v9 }, -{ "fcmpd", CMPFCC(1)|F3F(2, 0x35, 0x052), CMPFCC(~1)|F3F(~2, ~0x35, ~0x052), "7,v,B", F_FLOAT, v9 }, -{ "fcmpd", CMPFCC(2)|F3F(2, 0x35, 0x052), CMPFCC(~2)|F3F(~2, ~0x35, ~0x052), "8,v,B", F_FLOAT, v9 }, -{ "fcmpd", CMPFCC(3)|F3F(2, 0x35, 0x052), CMPFCC(~3)|F3F(~2, ~0x35, ~0x052), "9,v,B", F_FLOAT, v9 }, -{ "fcmped", F3F(2, 0x35, 0x056), F3F(~2, ~0x35, ~0x056)|RD_G0, "v,B", F_FLOAT, v6 }, -{ "fcmped", CMPFCC(0)|F3F(2, 0x35, 0x056), CMPFCC(~0)|F3F(~2, ~0x35, ~0x056), "6,v,B", F_FLOAT, v9 }, -{ "fcmped", CMPFCC(1)|F3F(2, 0x35, 0x056), CMPFCC(~1)|F3F(~2, ~0x35, ~0x056), "7,v,B", F_FLOAT, v9 }, -{ "fcmped", CMPFCC(2)|F3F(2, 0x35, 0x056), CMPFCC(~2)|F3F(~2, ~0x35, ~0x056), "8,v,B", F_FLOAT, v9 }, -{ "fcmped", CMPFCC(3)|F3F(2, 0x35, 0x056), CMPFCC(~3)|F3F(~2, ~0x35, ~0x056), "9,v,B", F_FLOAT, v9 }, -{ "fcmpq", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT, v8 }, -{ "fcmpq", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT, v9 }, -{ "fcmpq", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT, v9 }, -{ "fcmpq", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT, v9 }, -{ "fcmpq", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT, v9 }, -{ "fcmpeq", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT, v8 }, -{ "fcmpeq", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT, v9 }, -{ "fcmpeq", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT, v9 }, -{ "fcmpeq", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT, v9 }, -{ "fcmpeq", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT, v9 }, -{ "fcmpx", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, -{ "fcmpx", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT|F_ALIAS, v9 }, -{ "fcmpx", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT|F_ALIAS, v9 }, -{ "fcmpx", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT|F_ALIAS, v9 }, -{ "fcmpx", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT|F_ALIAS, v9 }, -{ "fcmpex", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, -{ "fcmpex", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT|F_ALIAS, v9 }, -{ "fcmpex", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT|F_ALIAS, v9 }, -{ "fcmpex", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT|F_ALIAS, v9 }, -{ "fcmpex", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT|F_ALIAS, v9 }, -{ "fcmps", F3F(2, 0x35, 0x051), F3F(~2, ~0x35, ~0x051)|RD_G0, "e,f", F_FLOAT, v6 }, -{ "fcmps", CMPFCC(0)|F3F(2, 0x35, 0x051), CMPFCC(~0)|F3F(~2, ~0x35, ~0x051), "6,e,f", F_FLOAT, v9 }, -{ "fcmps", CMPFCC(1)|F3F(2, 0x35, 0x051), CMPFCC(~1)|F3F(~2, ~0x35, ~0x051), "7,e,f", F_FLOAT, v9 }, -{ "fcmps", CMPFCC(2)|F3F(2, 0x35, 0x051), CMPFCC(~2)|F3F(~2, ~0x35, ~0x051), "8,e,f", F_FLOAT, v9 }, -{ "fcmps", CMPFCC(3)|F3F(2, 0x35, 0x051), CMPFCC(~3)|F3F(~2, ~0x35, ~0x051), "9,e,f", F_FLOAT, v9 }, -{ "fcmpes", F3F(2, 0x35, 0x055), F3F(~2, ~0x35, ~0x055)|RD_G0, "e,f", F_FLOAT, v6 }, -{ "fcmpes", CMPFCC(0)|F3F(2, 0x35, 0x055), CMPFCC(~0)|F3F(~2, ~0x35, ~0x055), "6,e,f", F_FLOAT, v9 }, -{ "fcmpes", CMPFCC(1)|F3F(2, 0x35, 0x055), CMPFCC(~1)|F3F(~2, ~0x35, ~0x055), "7,e,f", F_FLOAT, v9 }, -{ "fcmpes", CMPFCC(2)|F3F(2, 0x35, 0x055), CMPFCC(~2)|F3F(~2, ~0x35, ~0x055), "8,e,f", F_FLOAT, v9 }, -{ "fcmpes", CMPFCC(3)|F3F(2, 0x35, 0x055), CMPFCC(~3)|F3F(~2, ~0x35, ~0x055), "9,e,f", F_FLOAT, v9 }, +{ "fdtoi", F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", F_FLOAT, v6 }, +{ "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", F_FLOAT, v8 }, + +{ "fdtox", F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,g", F_FLOAT, v9 }, +{ "fstox", F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,g", F_FLOAT, v9 }, +{ "fqtox", F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,g", F_FLOAT, v9 }, + +{ "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", F_FLOAT, v6 }, +{ "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", F_FLOAT, v8 }, + +{ "fxtod", F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "f,H", F_FLOAT, v9 }, +{ "fxtos", F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "f,g", F_FLOAT, v9 }, +{ "fxtoq", F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "f,J", F_FLOAT, v9 }, + +{ "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", F_FLOAT, v8 }, +{ "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", F_FLOAT, v6 }, +{ "fqtod", F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", F_FLOAT, v8 }, +{ "fqtos", F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", F_FLOAT, v8 }, +{ "fstod", F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", F_FLOAT, v6 }, +{ "fstoq", F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", F_FLOAT, v8 }, + +{ "fdivd", F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", F_FLOAT, v6 }, +{ "fdivq", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT, v8 }, +{ "fdivx", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fdivs", F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", F_FLOAT, v6 }, +{ "fmuld", F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", F_FLOAT, v6 }, +{ "fmulq", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT, v8 }, +{ "fmulx", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fmuls", F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", F_FLOAT, v6 }, + +{ "fdmulq", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT, v8 }, +{ "fdmulx", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsmuld", F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", F_FLOAT, v8 }, + +{ "fsqrtd", F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", F_FLOAT, v7 }, +{ "fsqrtq", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT, v8 }, +{ "fsqrtx", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsqrts", F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", F_FLOAT, v7 }, + +{ "fabsd", F3F(2, 0x34, 0x00a), F3F(~2, ~0x34, ~0x00a)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fabsq", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fabsx", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fabss", F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fmovd", F3F(2, 0x34, 0x002), F3F(~2, ~0x34, ~0x002)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fmovq", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fmovx", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fmovs", F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", F_FLOAT, v6 }, +{ "fnegd", F3F(2, 0x34, 0x006), F3F(~2, ~0x34, ~0x006)|RS1_G0, "B,H", F_FLOAT, v9 }, +{ "fnegq", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT, v9 }, +{ "fnegx", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 }, +{ "fnegs", F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", F_FLOAT, v6 }, + +{ "faddd", F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", F_FLOAT, v6 }, +{ "faddq", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT, v8 }, +{ "faddx", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fadds", F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", F_FLOAT, v6 }, +{ "fsubd", F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", F_FLOAT, v6 }, +{ "fsubq", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT, v8 }, +{ "fsubx", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT|F_ALIAS, v8 }, +{ "fsubs", F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", F_FLOAT, v6 }, + +#define CMPFCC(x) (((x)&0x3)<<25) + +{ "fcmpd", F3F(2, 0x35, 0x052), F3F(~2, ~0x35, ~0x052)|RD_G0, "v,B", F_FLOAT, v6 }, +{ "fcmpd", CMPFCC(0)|F3F(2, 0x35, 0x052), CMPFCC(~0)|F3F(~2, ~0x35, ~0x052), "6,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(1)|F3F(2, 0x35, 0x052), CMPFCC(~1)|F3F(~2, ~0x35, ~0x052), "7,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(2)|F3F(2, 0x35, 0x052), CMPFCC(~2)|F3F(~2, ~0x35, ~0x052), "8,v,B", F_FLOAT, v9 }, +{ "fcmpd", CMPFCC(3)|F3F(2, 0x35, 0x052), CMPFCC(~3)|F3F(~2, ~0x35, ~0x052), "9,v,B", F_FLOAT, v9 }, +{ "fcmped", F3F(2, 0x35, 0x056), F3F(~2, ~0x35, ~0x056)|RD_G0, "v,B", F_FLOAT, v6 }, +{ "fcmped", CMPFCC(0)|F3F(2, 0x35, 0x056), CMPFCC(~0)|F3F(~2, ~0x35, ~0x056), "6,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(1)|F3F(2, 0x35, 0x056), CMPFCC(~1)|F3F(~2, ~0x35, ~0x056), "7,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(2)|F3F(2, 0x35, 0x056), CMPFCC(~2)|F3F(~2, ~0x35, ~0x056), "8,v,B", F_FLOAT, v9 }, +{ "fcmped", CMPFCC(3)|F3F(2, 0x35, 0x056), CMPFCC(~3)|F3F(~2, ~0x35, ~0x056), "9,v,B", F_FLOAT, v9 }, +{ "fcmpq", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT, v8 }, +{ "fcmpq", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT, v9 }, +{ "fcmpq", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT, v9 }, +{ "fcmpeq", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT, v8 }, +{ "fcmpeq", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT, v9 }, +{ "fcmpeq", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT, v9 }, +{ "fcmpx", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, +{ "fcmpx", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpx", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 }, +{ "fcmpex", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmpex", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT|F_ALIAS, v9 }, +{ "fcmps", F3F(2, 0x35, 0x051), F3F(~2, ~0x35, ~0x051)|RD_G0, "e,f", F_FLOAT, v6 }, +{ "fcmps", CMPFCC(0)|F3F(2, 0x35, 0x051), CMPFCC(~0)|F3F(~2, ~0x35, ~0x051), "6,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(1)|F3F(2, 0x35, 0x051), CMPFCC(~1)|F3F(~2, ~0x35, ~0x051), "7,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(2)|F3F(2, 0x35, 0x051), CMPFCC(~2)|F3F(~2, ~0x35, ~0x051), "8,e,f", F_FLOAT, v9 }, +{ "fcmps", CMPFCC(3)|F3F(2, 0x35, 0x051), CMPFCC(~3)|F3F(~2, ~0x35, ~0x051), "9,e,f", F_FLOAT, v9 }, +{ "fcmpes", F3F(2, 0x35, 0x055), F3F(~2, ~0x35, ~0x055)|RD_G0, "e,f", F_FLOAT, v6 }, +{ "fcmpes", CMPFCC(0)|F3F(2, 0x35, 0x055), CMPFCC(~0)|F3F(~2, ~0x35, ~0x055), "6,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(1)|F3F(2, 0x35, 0x055), CMPFCC(~1)|F3F(~2, ~0x35, ~0x055), "7,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(2)|F3F(2, 0x35, 0x055), CMPFCC(~2)|F3F(~2, ~0x35, ~0x055), "8,e,f", F_FLOAT, v9 }, +{ "fcmpes", CMPFCC(3)|F3F(2, 0x35, 0x055), CMPFCC(~3)|F3F(~2, ~0x35, ~0x055), "9,e,f", F_FLOAT, v9 }, /* These Extended FPop (FIFO) instructions are new in the Fujitsu MB86934, replacing the CPop instructions from v6 and later @@ -1835,30 +1835,30 @@ CONDFC ("fbule", "cb013", 0xe, F_CONDBR), #define EFPOP1_3(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op), args, 0, sparclite } #define EFPOP2_2(name, op, args) { name, F3F(2, 0x37, op), F3F(~2, ~0x37, ~op)|RD_G0, args, 0, sparclite } -EFPOP1_2 ("efitod", 0x0c8, "f,H"), -EFPOP1_2 ("efitos", 0x0c4, "f,g"), -EFPOP1_2 ("efdtoi", 0x0d2, "B,g"), -EFPOP1_2 ("efstoi", 0x0d1, "f,g"), -EFPOP1_2 ("efstod", 0x0c9, "f,H"), -EFPOP1_2 ("efdtos", 0x0c6, "B,g"), -EFPOP1_2 ("efmovs", 0x001, "f,g"), -EFPOP1_2 ("efnegs", 0x005, "f,g"), -EFPOP1_2 ("efabss", 0x009, "f,g"), -EFPOP1_2 ("efsqrtd", 0x02a, "B,H"), -EFPOP1_2 ("efsqrts", 0x029, "f,g"), -EFPOP1_3 ("efaddd", 0x042, "v,B,H"), -EFPOP1_3 ("efadds", 0x041, "e,f,g"), -EFPOP1_3 ("efsubd", 0x046, "v,B,H"), -EFPOP1_3 ("efsubs", 0x045, "e,f,g"), -EFPOP1_3 ("efdivd", 0x04e, "v,B,H"), -EFPOP1_3 ("efdivs", 0x04d, "e,f,g"), -EFPOP1_3 ("efmuld", 0x04a, "v,B,H"), -EFPOP1_3 ("efmuls", 0x049, "e,f,g"), -EFPOP1_3 ("efsmuld", 0x069, "e,f,H"), -EFPOP2_2 ("efcmpd", 0x052, "v,B"), -EFPOP2_2 ("efcmped", 0x056, "v,B"), -EFPOP2_2 ("efcmps", 0x051, "e,f"), -EFPOP2_2 ("efcmpes", 0x055, "e,f"), +EFPOP1_2 ("efitod", 0x0c8, "f,H"), +EFPOP1_2 ("efitos", 0x0c4, "f,g"), +EFPOP1_2 ("efdtoi", 0x0d2, "B,g"), +EFPOP1_2 ("efstoi", 0x0d1, "f,g"), +EFPOP1_2 ("efstod", 0x0c9, "f,H"), +EFPOP1_2 ("efdtos", 0x0c6, "B,g"), +EFPOP1_2 ("efmovs", 0x001, "f,g"), +EFPOP1_2 ("efnegs", 0x005, "f,g"), +EFPOP1_2 ("efabss", 0x009, "f,g"), +EFPOP1_2 ("efsqrtd", 0x02a, "B,H"), +EFPOP1_2 ("efsqrts", 0x029, "f,g"), +EFPOP1_3 ("efaddd", 0x042, "v,B,H"), +EFPOP1_3 ("efadds", 0x041, "e,f,g"), +EFPOP1_3 ("efsubd", 0x046, "v,B,H"), +EFPOP1_3 ("efsubs", 0x045, "e,f,g"), +EFPOP1_3 ("efdivd", 0x04e, "v,B,H"), +EFPOP1_3 ("efdivs", 0x04d, "e,f,g"), +EFPOP1_3 ("efmuld", 0x04a, "v,B,H"), +EFPOP1_3 ("efmuls", 0x049, "e,f,g"), +EFPOP1_3 ("efsmuld", 0x069, "e,f,H"), +EFPOP2_2 ("efcmpd", 0x052, "v,B"), +EFPOP2_2 ("efcmped", 0x056, "v,B"), +EFPOP2_2 ("efcmps", 0x051, "e,f"), +EFPOP2_2 ("efcmpes", 0x055, "e,f"), #undef EFPOP1_2 #undef EFPOP1_3 @@ -1866,8 +1866,8 @@ EFPOP2_2 ("efcmpes", 0x055, "e,f"), /* These are marked F_ALIAS, so that they won't conflict with sparclite insns present. Otherwise, the F_ALIAS flag is ignored. */ -{ "cpop1", F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", F_ALIAS, v6notv9 }, -{ "cpop2", F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", F_ALIAS, v6notv9 }, +{ "cpop1", F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", F_ALIAS, v6notv9 }, +{ "cpop2", F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", F_ALIAS, v6notv9 }, /* sparclet specific insns */ @@ -1878,20 +1878,20 @@ COMMUTEOP ("smacd", 0x2f, sparclet), COMMUTEOP ("umuld", 0x09, sparclet), COMMUTEOP ("smuld", 0x0d, sparclet), -{ "shuffle", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, sparclet }, -{ "shuffle", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, sparclet }, +{ "shuffle", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, sparclet }, +{ "shuffle", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, sparclet }, /* The manual isn't completely accurate on these insns. The `rs2' field is treated as being 6 bits to account for 6 bit immediates to cpush. It is assumed that it is intended that bit 5 is 0 when rs2 contains a reg. */ #define BIT5 (1<<5) -{ "crdcxt", F3(2, 0x36, 0)|SLCPOP(4), F3(~2, ~0x36, ~0)|SLCPOP(~4)|BIT5|RS2(~0), "U,d", 0, sparclet }, -{ "cwrcxt", F3(2, 0x36, 0)|SLCPOP(3), F3(~2, ~0x36, ~0)|SLCPOP(~3)|BIT5|RS2(~0), "1,u", 0, sparclet }, -{ "cpush", F3(2, 0x36, 0)|SLCPOP(0), F3(~2, ~0x36, ~0)|SLCPOP(~0)|BIT5|RD(~0), "1,2", 0, sparclet }, -{ "cpush", F3(2, 0x36, 1)|SLCPOP(0), F3(~2, ~0x36, ~1)|SLCPOP(~0)|RD(~0), "1,Y", 0, sparclet }, -{ "cpusha", F3(2, 0x36, 0)|SLCPOP(1), F3(~2, ~0x36, ~0)|SLCPOP(~1)|BIT5|RD(~0), "1,2", 0, sparclet }, -{ "cpusha", F3(2, 0x36, 1)|SLCPOP(1), F3(~2, ~0x36, ~1)|SLCPOP(~1)|RD(~0), "1,Y", 0, sparclet }, -{ "cpull", F3(2, 0x36, 0)|SLCPOP(2), F3(~2, ~0x36, ~0)|SLCPOP(~2)|BIT5|RS1(~0)|RS2(~0), "d", 0, sparclet }, +{ "crdcxt", F3(2, 0x36, 0)|SLCPOP(4), F3(~2, ~0x36, ~0)|SLCPOP(~4)|BIT5|RS2(~0), "U,d", 0, sparclet }, +{ "cwrcxt", F3(2, 0x36, 0)|SLCPOP(3), F3(~2, ~0x36, ~0)|SLCPOP(~3)|BIT5|RS2(~0), "1,u", 0, sparclet }, +{ "cpush", F3(2, 0x36, 0)|SLCPOP(0), F3(~2, ~0x36, ~0)|SLCPOP(~0)|BIT5|RD(~0), "1,2", 0, sparclet }, +{ "cpush", F3(2, 0x36, 1)|SLCPOP(0), F3(~2, ~0x36, ~1)|SLCPOP(~0)|RD(~0), "1,Y", 0, sparclet }, +{ "cpusha", F3(2, 0x36, 0)|SLCPOP(1), F3(~2, ~0x36, ~0)|SLCPOP(~1)|BIT5|RD(~0), "1,2", 0, sparclet }, +{ "cpusha", F3(2, 0x36, 1)|SLCPOP(1), F3(~2, ~0x36, ~1)|SLCPOP(~1)|RD(~0), "1,Y", 0, sparclet }, +{ "cpull", F3(2, 0x36, 0)|SLCPOP(2), F3(~2, ~0x36, ~0)|SLCPOP(~2)|BIT5|RS1(~0)|RS2(~0), "d", 0, sparclet }, #undef BIT5 /* sparclet coprocessor branch insns */ @@ -1923,108 +1923,108 @@ SLCBCC("cbnefr", 15), #undef SLCBCC2 #undef SLCBCC -{ "casa", F3(3, 0x3c, 0), F3(~3, ~0x3c, ~0), "[1]A,2,d", 0, v9 }, -{ "casa", F3(3, 0x3c, 1), F3(~3, ~0x3c, ~1), "[1]o,2,d", 0, v9 }, -{ "casxa", F3(3, 0x3e, 0), F3(~3, ~0x3e, ~0), "[1]A,2,d", 0, v9 }, -{ "casxa", F3(3, 0x3e, 1), F3(~3, ~0x3e, ~1), "[1]o,2,d", 0, v9 }, +{ "casa", F3(3, 0x3c, 0), F3(~3, ~0x3c, ~0), "[1]A,2,d", 0, v9 }, +{ "casa", F3(3, 0x3c, 1), F3(~3, ~0x3c, ~1), "[1]o,2,d", 0, v9 }, +{ "casxa", F3(3, 0x3e, 0), F3(~3, ~0x3e, ~0), "[1]A,2,d", 0, v9 }, +{ "casxa", F3(3, 0x3e, 1), F3(~3, ~0x3e, ~1), "[1]o,2,d", 0, v9 }, /* v9 synthetic insns */ -{ "iprefetch", F2(0, 1)|(2<<20)|BPRED, F2(~0, ~1)|(1<<20)|ANNUL|COND(~0), "G", 0, v9 }, /* bn,a,pt %xcc,label */ -{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* sra rs1,%g0,rd */ -{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* sra rd,%g0,rd */ -{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* srl rs1,%g0,rd */ -{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* srl rd,%g0,rd */ -{ "cas", F3(3, 0x3c, 0)|ASI(0x80), F3(~3, ~0x3c, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P,rs2,rd */ -{ "casl", F3(3, 0x3c, 0)|ASI(0x88), F3(~3, ~0x3c, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P_L,rs2,rd */ -{ "casx", F3(3, 0x3e, 0)|ASI(0x80), F3(~3, ~0x3e, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P,rs2,rd */ -{ "casxl", F3(3, 0x3e, 0)|ASI(0x88), F3(~3, ~0x3e, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P_L,rs2,rd */ +{ "iprefetch", F2(0, 1)|(2<<20)|BPRED, F2(~0, ~1)|(1<<20)|ANNUL|COND(~0), "G", 0, v9 }, /* bn,a,pt %xcc,label */ +{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* sra rs1,%g0,rd */ +{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* sra rd,%g0,rd */ +{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* srl rs1,%g0,rd */ +{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* srl rd,%g0,rd */ +{ "cas", F3(3, 0x3c, 0)|ASI(0x80), F3(~3, ~0x3c, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P,rs2,rd */ +{ "casl", F3(3, 0x3c, 0)|ASI(0x88), F3(~3, ~0x3c, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P_L,rs2,rd */ +{ "casx", F3(3, 0x3e, 0)|ASI(0x80), F3(~3, ~0x3e, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P,rs2,rd */ +{ "casxl", F3(3, 0x3e, 0)|ASI(0x88), F3(~3, ~0x3e, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P_L,rs2,rd */ /* Ultrasparc extensions */ -{ "shutdown", F3F(2, 0x36, 0x080), F3F(~2, ~0x36, ~0x080)|RD_G0|RS1_G0|RS2_G0, "", 0, v9a }, +{ "shutdown", F3F(2, 0x36, 0x080), F3F(~2, ~0x36, ~0x080)|RD_G0|RS1_G0|RS2_G0, "", 0, v9a }, /* FIXME: Do we want to mark these as F_FLOAT, or something similar? */ -{ "fpadd16", F3F(2, 0x36, 0x050), F3F(~2, ~0x36, ~0x050), "v,B,H", 0, v9a }, -{ "fpadd16s", F3F(2, 0x36, 0x051), F3F(~2, ~0x36, ~0x051), "e,f,g", 0, v9a }, -{ "fpadd32", F3F(2, 0x36, 0x052), F3F(~2, ~0x36, ~0x052), "v,B,H", 0, v9a }, -{ "fpadd32s", F3F(2, 0x36, 0x053), F3F(~2, ~0x36, ~0x053), "e,f,g", 0, v9a }, -{ "fpsub16", F3F(2, 0x36, 0x054), F3F(~2, ~0x36, ~0x054), "v,B,H", 0, v9a }, -{ "fpsub16s", F3F(2, 0x36, 0x055), F3F(~2, ~0x36, ~0x055), "e,f,g", 0, v9a }, -{ "fpsub32", F3F(2, 0x36, 0x056), F3F(~2, ~0x36, ~0x056), "v,B,H", 0, v9a }, -{ "fpsub32s", F3F(2, 0x36, 0x057), F3F(~2, ~0x36, ~0x057), "e,f,g", 0, v9a }, - -{ "fpack32", F3F(2, 0x36, 0x03a), F3F(~2, ~0x36, ~0x03a), "v,B,H", 0, v9a }, -{ "fpack16", F3F(2, 0x36, 0x03b), F3F(~2, ~0x36, ~0x03b)|RS1_G0, "B,g", 0, v9a }, -{ "fpackfix", F3F(2, 0x36, 0x03d), F3F(~2, ~0x36, ~0x03d)|RS1_G0, "B,g", 0, v9a }, -{ "fexpand", F3F(2, 0x36, 0x04d), F3F(~2, ~0x36, ~0x04d)|RS1_G0, "f,H", 0, v9a }, -{ "fpmerge", F3F(2, 0x36, 0x04b), F3F(~2, ~0x36, ~0x04b), "e,f,H", 0, v9a }, +{ "fpadd16", F3F(2, 0x36, 0x050), F3F(~2, ~0x36, ~0x050), "v,B,H", 0, v9a }, +{ "fpadd16s", F3F(2, 0x36, 0x051), F3F(~2, ~0x36, ~0x051), "e,f,g", 0, v9a }, +{ "fpadd32", F3F(2, 0x36, 0x052), F3F(~2, ~0x36, ~0x052), "v,B,H", 0, v9a }, +{ "fpadd32s", F3F(2, 0x36, 0x053), F3F(~2, ~0x36, ~0x053), "e,f,g", 0, v9a }, +{ "fpsub16", F3F(2, 0x36, 0x054), F3F(~2, ~0x36, ~0x054), "v,B,H", 0, v9a }, +{ "fpsub16s", F3F(2, 0x36, 0x055), F3F(~2, ~0x36, ~0x055), "e,f,g", 0, v9a }, +{ "fpsub32", F3F(2, 0x36, 0x056), F3F(~2, ~0x36, ~0x056), "v,B,H", 0, v9a }, +{ "fpsub32s", F3F(2, 0x36, 0x057), F3F(~2, ~0x36, ~0x057), "e,f,g", 0, v9a }, + +{ "fpack32", F3F(2, 0x36, 0x03a), F3F(~2, ~0x36, ~0x03a), "v,B,H", 0, v9a }, +{ "fpack16", F3F(2, 0x36, 0x03b), F3F(~2, ~0x36, ~0x03b)|RS1_G0, "B,g", 0, v9a }, +{ "fpackfix", F3F(2, 0x36, 0x03d), F3F(~2, ~0x36, ~0x03d)|RS1_G0, "B,g", 0, v9a }, +{ "fexpand", F3F(2, 0x36, 0x04d), F3F(~2, ~0x36, ~0x04d)|RS1_G0, "f,H", 0, v9a }, +{ "fpmerge", F3F(2, 0x36, 0x04b), F3F(~2, ~0x36, ~0x04b), "e,f,H", 0, v9a }, /* Note that the mixing of 32/64 bit regs is intentional. */ -{ "fmul8x16", F3F(2, 0x36, 0x031), F3F(~2, ~0x36, ~0x031), "e,B,H", 0, v9a }, -{ "fmul8x16au", F3F(2, 0x36, 0x033), F3F(~2, ~0x36, ~0x033), "e,f,H", 0, v9a }, -{ "fmul8x16al", F3F(2, 0x36, 0x035), F3F(~2, ~0x36, ~0x035), "e,f,H", 0, v9a }, -{ "fmul8sux16", F3F(2, 0x36, 0x036), F3F(~2, ~0x36, ~0x036), "v,B,H", 0, v9a }, -{ "fmul8ulx16", F3F(2, 0x36, 0x037), F3F(~2, ~0x36, ~0x037), "v,B,H", 0, v9a }, -{ "fmuld8sux16", F3F(2, 0x36, 0x038), F3F(~2, ~0x36, ~0x038), "e,f,H", 0, v9a }, -{ "fmuld8ulx16", F3F(2, 0x36, 0x039), F3F(~2, ~0x36, ~0x039), "e,f,H", 0, v9a }, - -{ "alignaddr", F3F(2, 0x36, 0x018), F3F(~2, ~0x36, ~0x018), "1,2,d", 0, v9a }, -{ "alignaddrl", F3F(2, 0x36, 0x01a), F3F(~2, ~0x36, ~0x01a), "1,2,d", 0, v9a }, -{ "faligndata", F3F(2, 0x36, 0x048), F3F(~2, ~0x36, ~0x048), "v,B,H", 0, v9a }, - -{ "fzero", F3F(2, 0x36, 0x060), F3F(~2, ~0x36, ~0x060), "H", 0, v9a }, -{ "fzeros", F3F(2, 0x36, 0x061), F3F(~2, ~0x36, ~0x061), "g", 0, v9a }, -{ "fone", F3F(2, 0x36, 0x07e), F3F(~2, ~0x36, ~0x07e), "H", 0, v9a }, -{ "fones", F3F(2, 0x36, 0x07f), F3F(~2, ~0x36, ~0x07f), "g", 0, v9a }, -{ "fsrc1", F3F(2, 0x36, 0x074), F3F(~2, ~0x36, ~0x074), "v,H", 0, v9a }, -{ "fsrc1s", F3F(2, 0x36, 0x075), F3F(~2, ~0x36, ~0x075), "e,g", 0, v9a }, -{ "fsrc2", F3F(2, 0x36, 0x078), F3F(~2, ~0x36, ~0x078), "B,H", 0, v9a }, -{ "fsrc2s", F3F(2, 0x36, 0x079), F3F(~2, ~0x36, ~0x079), "f,g", 0, v9a }, -{ "fnot1", F3F(2, 0x36, 0x06a), F3F(~2, ~0x36, ~0x06a), "v,H", 0, v9a }, -{ "fnot1s", F3F(2, 0x36, 0x06b), F3F(~2, ~0x36, ~0x06b), "e,g", 0, v9a }, -{ "fnot2", F3F(2, 0x36, 0x066), F3F(~2, ~0x36, ~0x066), "B,H", 0, v9a }, -{ "fnot2s", F3F(2, 0x36, 0x067), F3F(~2, ~0x36, ~0x067), "f,g", 0, v9a }, -{ "for", F3F(2, 0x36, 0x07c), F3F(~2, ~0x36, ~0x07c), "v,B,H", 0, v9a }, -{ "fors", F3F(2, 0x36, 0x07d), F3F(~2, ~0x36, ~0x07d), "e,f,g", 0, v9a }, -{ "fnor", F3F(2, 0x36, 0x062), F3F(~2, ~0x36, ~0x062), "v,B,H", 0, v9a }, -{ "fnors", F3F(2, 0x36, 0x063), F3F(~2, ~0x36, ~0x063), "e,f,g", 0, v9a }, -{ "fand", F3F(2, 0x36, 0x070), F3F(~2, ~0x36, ~0x070), "v,B,H", 0, v9a }, -{ "fands", F3F(2, 0x36, 0x071), F3F(~2, ~0x36, ~0x071), "e,f,g", 0, v9a }, -{ "fnand", F3F(2, 0x36, 0x06e), F3F(~2, ~0x36, ~0x06e), "v,B,H", 0, v9a }, -{ "fnands", F3F(2, 0x36, 0x06f), F3F(~2, ~0x36, ~0x06f), "e,f,g", 0, v9a }, -{ "fxor", F3F(2, 0x36, 0x06c), F3F(~2, ~0x36, ~0x06c), "v,B,H", 0, v9a }, -{ "fxors", F3F(2, 0x36, 0x06d), F3F(~2, ~0x36, ~0x06d), "e,f,g", 0, v9a }, -{ "fxnor", F3F(2, 0x36, 0x072), F3F(~2, ~0x36, ~0x072), "v,B,H", 0, v9a }, -{ "fxnors", F3F(2, 0x36, 0x073), F3F(~2, ~0x36, ~0x073), "e,f,g", 0, v9a }, -{ "fornot1", F3F(2, 0x36, 0x07a), F3F(~2, ~0x36, ~0x07a), "v,B,H", 0, v9a }, -{ "fornot1s", F3F(2, 0x36, 0x07b), F3F(~2, ~0x36, ~0x07b), "e,f,g", 0, v9a }, -{ "fornot2", F3F(2, 0x36, 0x076), F3F(~2, ~0x36, ~0x076), "v,B,H", 0, v9a }, -{ "fornot2s", F3F(2, 0x36, 0x077), F3F(~2, ~0x36, ~0x077), "e,f,g", 0, v9a }, -{ "fandnot1", F3F(2, 0x36, 0x068), F3F(~2, ~0x36, ~0x068), "v,B,H", 0, v9a }, -{ "fandnot1s", F3F(2, 0x36, 0x069), F3F(~2, ~0x36, ~0x069), "e,f,g", 0, v9a }, -{ "fandnot2", F3F(2, 0x36, 0x064), F3F(~2, ~0x36, ~0x064), "v,B,H", 0, v9a }, -{ "fandnot2s", F3F(2, 0x36, 0x065), F3F(~2, ~0x36, ~0x065), "e,f,g", 0, v9a }, - -{ "fcmpgt16", F3F(2, 0x36, 0x028), F3F(~2, ~0x36, ~0x028), "v,B,d", 0, v9a }, -{ "fcmpgt32", F3F(2, 0x36, 0x02c), F3F(~2, ~0x36, ~0x02c), "v,B,d", 0, v9a }, -{ "fcmple16", F3F(2, 0x36, 0x020), F3F(~2, ~0x36, ~0x020), "v,B,d", 0, v9a }, -{ "fcmple32", F3F(2, 0x36, 0x024), F3F(~2, ~0x36, ~0x024), "v,B,d", 0, v9a }, -{ "fcmpne16", F3F(2, 0x36, 0x022), F3F(~2, ~0x36, ~0x022), "v,B,d", 0, v9a }, -{ "fcmpne32", F3F(2, 0x36, 0x026), F3F(~2, ~0x36, ~0x026), "v,B,d", 0, v9a }, -{ "fcmpeq16", F3F(2, 0x36, 0x02a), F3F(~2, ~0x36, ~0x02a), "v,B,d", 0, v9a }, -{ "fcmpeq32", F3F(2, 0x36, 0x02e), F3F(~2, ~0x36, ~0x02e), "v,B,d", 0, v9a }, - -{ "edge8", F3F(2, 0x36, 0x000), F3F(~2, ~0x36, ~0x000), "1,2,d", 0, v9a }, -{ "edge8l", F3F(2, 0x36, 0x002), F3F(~2, ~0x36, ~0x002), "1,2,d", 0, v9a }, -{ "edge16", F3F(2, 0x36, 0x004), F3F(~2, ~0x36, ~0x004), "1,2,d", 0, v9a }, -{ "edge16l", F3F(2, 0x36, 0x006), F3F(~2, ~0x36, ~0x006), "1,2,d", 0, v9a }, -{ "edge32", F3F(2, 0x36, 0x008), F3F(~2, ~0x36, ~0x008), "1,2,d", 0, v9a }, -{ "edge32l", F3F(2, 0x36, 0x00a), F3F(~2, ~0x36, ~0x00a), "1,2,d", 0, v9a }, - -{ "pdist", F3F(2, 0x36, 0x03e), F3F(~2, ~0x36, ~0x03e), "v,B,H", 0, v9a }, - -{ "array8", F3F(2, 0x36, 0x010), F3F(~2, ~0x36, ~0x010), "1,2,d", 0, v9a }, -{ "array16", F3F(2, 0x36, 0x012), F3F(~2, ~0x36, ~0x012), "1,2,d", 0, v9a }, -{ "array32", F3F(2, 0x36, 0x014), F3F(~2, ~0x36, ~0x014), "1,2,d", 0, v9a }, +{ "fmul8x16", F3F(2, 0x36, 0x031), F3F(~2, ~0x36, ~0x031), "e,B,H", 0, v9a }, +{ "fmul8x16au", F3F(2, 0x36, 0x033), F3F(~2, ~0x36, ~0x033), "e,f,H", 0, v9a }, +{ "fmul8x16al", F3F(2, 0x36, 0x035), F3F(~2, ~0x36, ~0x035), "e,f,H", 0, v9a }, +{ "fmul8sux16", F3F(2, 0x36, 0x036), F3F(~2, ~0x36, ~0x036), "v,B,H", 0, v9a }, +{ "fmul8ulx16", F3F(2, 0x36, 0x037), F3F(~2, ~0x36, ~0x037), "v,B,H", 0, v9a }, +{ "fmuld8sux16", F3F(2, 0x36, 0x038), F3F(~2, ~0x36, ~0x038), "e,f,H", 0, v9a }, +{ "fmuld8ulx16", F3F(2, 0x36, 0x039), F3F(~2, ~0x36, ~0x039), "e,f,H", 0, v9a }, + +{ "alignaddr", F3F(2, 0x36, 0x018), F3F(~2, ~0x36, ~0x018), "1,2,d", 0, v9a }, +{ "alignaddrl", F3F(2, 0x36, 0x01a), F3F(~2, ~0x36, ~0x01a), "1,2,d", 0, v9a }, +{ "faligndata", F3F(2, 0x36, 0x048), F3F(~2, ~0x36, ~0x048), "v,B,H", 0, v9a }, + +{ "fzero", F3F(2, 0x36, 0x060), F3F(~2, ~0x36, ~0x060), "H", 0, v9a }, +{ "fzeros", F3F(2, 0x36, 0x061), F3F(~2, ~0x36, ~0x061), "g", 0, v9a }, +{ "fone", F3F(2, 0x36, 0x07e), F3F(~2, ~0x36, ~0x07e), "H", 0, v9a }, +{ "fones", F3F(2, 0x36, 0x07f), F3F(~2, ~0x36, ~0x07f), "g", 0, v9a }, +{ "fsrc1", F3F(2, 0x36, 0x074), F3F(~2, ~0x36, ~0x074), "v,H", 0, v9a }, +{ "fsrc1s", F3F(2, 0x36, 0x075), F3F(~2, ~0x36, ~0x075), "e,g", 0, v9a }, +{ "fsrc2", F3F(2, 0x36, 0x078), F3F(~2, ~0x36, ~0x078), "B,H", 0, v9a }, +{ "fsrc2s", F3F(2, 0x36, 0x079), F3F(~2, ~0x36, ~0x079), "f,g", 0, v9a }, +{ "fnot1", F3F(2, 0x36, 0x06a), F3F(~2, ~0x36, ~0x06a), "v,H", 0, v9a }, +{ "fnot1s", F3F(2, 0x36, 0x06b), F3F(~2, ~0x36, ~0x06b), "e,g", 0, v9a }, +{ "fnot2", F3F(2, 0x36, 0x066), F3F(~2, ~0x36, ~0x066), "B,H", 0, v9a }, +{ "fnot2s", F3F(2, 0x36, 0x067), F3F(~2, ~0x36, ~0x067), "f,g", 0, v9a }, +{ "for", F3F(2, 0x36, 0x07c), F3F(~2, ~0x36, ~0x07c), "v,B,H", 0, v9a }, +{ "fors", F3F(2, 0x36, 0x07d), F3F(~2, ~0x36, ~0x07d), "e,f,g", 0, v9a }, +{ "fnor", F3F(2, 0x36, 0x062), F3F(~2, ~0x36, ~0x062), "v,B,H", 0, v9a }, +{ "fnors", F3F(2, 0x36, 0x063), F3F(~2, ~0x36, ~0x063), "e,f,g", 0, v9a }, +{ "fand", F3F(2, 0x36, 0x070), F3F(~2, ~0x36, ~0x070), "v,B,H", 0, v9a }, +{ "fands", F3F(2, 0x36, 0x071), F3F(~2, ~0x36, ~0x071), "e,f,g", 0, v9a }, +{ "fnand", F3F(2, 0x36, 0x06e), F3F(~2, ~0x36, ~0x06e), "v,B,H", 0, v9a }, +{ "fnands", F3F(2, 0x36, 0x06f), F3F(~2, ~0x36, ~0x06f), "e,f,g", 0, v9a }, +{ "fxor", F3F(2, 0x36, 0x06c), F3F(~2, ~0x36, ~0x06c), "v,B,H", 0, v9a }, +{ "fxors", F3F(2, 0x36, 0x06d), F3F(~2, ~0x36, ~0x06d), "e,f,g", 0, v9a }, +{ "fxnor", F3F(2, 0x36, 0x072), F3F(~2, ~0x36, ~0x072), "v,B,H", 0, v9a }, +{ "fxnors", F3F(2, 0x36, 0x073), F3F(~2, ~0x36, ~0x073), "e,f,g", 0, v9a }, +{ "fornot1", F3F(2, 0x36, 0x07a), F3F(~2, ~0x36, ~0x07a), "v,B,H", 0, v9a }, +{ "fornot1s", F3F(2, 0x36, 0x07b), F3F(~2, ~0x36, ~0x07b), "e,f,g", 0, v9a }, +{ "fornot2", F3F(2, 0x36, 0x076), F3F(~2, ~0x36, ~0x076), "v,B,H", 0, v9a }, +{ "fornot2s", F3F(2, 0x36, 0x077), F3F(~2, ~0x36, ~0x077), "e,f,g", 0, v9a }, +{ "fandnot1", F3F(2, 0x36, 0x068), F3F(~2, ~0x36, ~0x068), "v,B,H", 0, v9a }, +{ "fandnot1s", F3F(2, 0x36, 0x069), F3F(~2, ~0x36, ~0x069), "e,f,g", 0, v9a }, +{ "fandnot2", F3F(2, 0x36, 0x064), F3F(~2, ~0x36, ~0x064), "v,B,H", 0, v9a }, +{ "fandnot2s", F3F(2, 0x36, 0x065), F3F(~2, ~0x36, ~0x065), "e,f,g", 0, v9a }, + +{ "fcmpgt16", F3F(2, 0x36, 0x028), F3F(~2, ~0x36, ~0x028), "v,B,d", 0, v9a }, +{ "fcmpgt32", F3F(2, 0x36, 0x02c), F3F(~2, ~0x36, ~0x02c), "v,B,d", 0, v9a }, +{ "fcmple16", F3F(2, 0x36, 0x020), F3F(~2, ~0x36, ~0x020), "v,B,d", 0, v9a }, +{ "fcmple32", F3F(2, 0x36, 0x024), F3F(~2, ~0x36, ~0x024), "v,B,d", 0, v9a }, +{ "fcmpne16", F3F(2, 0x36, 0x022), F3F(~2, ~0x36, ~0x022), "v,B,d", 0, v9a }, +{ "fcmpne32", F3F(2, 0x36, 0x026), F3F(~2, ~0x36, ~0x026), "v,B,d", 0, v9a }, +{ "fcmpeq16", F3F(2, 0x36, 0x02a), F3F(~2, ~0x36, ~0x02a), "v,B,d", 0, v9a }, +{ "fcmpeq32", F3F(2, 0x36, 0x02e), F3F(~2, ~0x36, ~0x02e), "v,B,d", 0, v9a }, + +{ "edge8", F3F(2, 0x36, 0x000), F3F(~2, ~0x36, ~0x000), "1,2,d", 0, v9a }, +{ "edge8l", F3F(2, 0x36, 0x002), F3F(~2, ~0x36, ~0x002), "1,2,d", 0, v9a }, +{ "edge16", F3F(2, 0x36, 0x004), F3F(~2, ~0x36, ~0x004), "1,2,d", 0, v9a }, +{ "edge16l", F3F(2, 0x36, 0x006), F3F(~2, ~0x36, ~0x006), "1,2,d", 0, v9a }, +{ "edge32", F3F(2, 0x36, 0x008), F3F(~2, ~0x36, ~0x008), "1,2,d", 0, v9a }, +{ "edge32l", F3F(2, 0x36, 0x00a), F3F(~2, ~0x36, ~0x00a), "1,2,d", 0, v9a }, + +{ "pdist", F3F(2, 0x36, 0x03e), F3F(~2, ~0x36, ~0x03e), "v,B,H", 0, v9a }, + +{ "array8", F3F(2, 0x36, 0x010), F3F(~2, ~0x36, ~0x010), "1,2,d", 0, v9a }, +{ "array16", F3F(2, 0x36, 0x012), F3F(~2, ~0x36, ~0x012), "1,2,d", 0, v9a }, +{ "array32", F3F(2, 0x36, 0x014), F3F(~2, ~0x36, ~0x014), "1,2,d", 0, v9a }, /* Cheetah instructions */ { "edge8n", F3F(2, 0x36, 0x001), F3F(~2, ~0x36, ~0x001), "1,2,d", 0, v9b }, @@ -2043,8 +2043,8 @@ SLCBCC("cbnefr", 15), with v9a instructions such as "edge8" which looks like impdep1. */ #define IMPDEP(name, code) \ -{ name, F3(2, code, 0), F3(~2, ~code, ~0)|ASI(~0), "1,2,d", 0, v9notv9a }, \ -{ name, F3(2, code, 1), F3(~2, ~code, ~1), "1,i,d", 0, v9notv9a }, \ +{ name, F3(2, code, 0), F3(~2, ~code, ~0)|ASI(~0), "1,2,d", 0, v9notv9a }, \ +{ name, F3(2, code, 1), F3(~2, ~code, ~1), "1,i,d", 0, v9notv9a }, \ { name, F3(2, code, 0), F3(~2, ~code, ~0), "x,1,2,d", 0, v9notv9a }, \ { name, F3(2, code, 0), F3(~2, ~code, ~0), "x,e,f,g", 0, v9notv9a } @@ -2303,8 +2303,8 @@ sparc_decode_sparclet_cpreg (value) /* Bitmask of v9 architectures. */ #define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \ - | (1 << SPARC_OPCODE_ARCH_V9A) \ - | (1 << SPARC_OPCODE_ARCH_V9B)) + | (1 << SPARC_OPCODE_ARCH_V9A) \ + | (1 << SPARC_OPCODE_ARCH_V9B)) /* 1 if INSN is for v9 only. */ #define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9)) /* 1 if INSN is for v9. */ @@ -2336,9 +2336,9 @@ static int compare_opcodes PARAMS ((const void *, const void *)); static int compute_arch_mask PARAMS ((unsigned long)); /* Sign-extend a value which is N bits long. */ -#define SEX(value, bits) \ - ((((int)(value)) << ((8 * sizeof (int)) - bits)) \ - >> ((8 * sizeof (int)) - bits) ) +#define SEX(value, bits) \ + ((((int)(value)) << ((8 * sizeof (int)) - bits)) \ + >> ((8 * sizeof (int)) - bits) ) static const char * const reg_names[] = { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", @@ -2357,7 +2357,7 @@ static const char * const reg_names[] = "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" }; -#define freg_names (®_names[4 * 8]) +#define freg_names (®_names[4 * 8]) /* These are ordered according to there register number in rdpr and wrpr insns. */ @@ -2403,55 +2403,55 @@ static const char * const v9a_asr_reg_names[] = { unsigned long int code; struct - { - unsigned int anop:2; - #define op ldst.anop - unsigned int anrd:5; - #define rd ldst.anrd - unsigned int op3:6; - unsigned int anrs1:5; - #define rs1 ldst.anrs1 - unsigned int i:1; - unsigned int anasi:8; - #define asi ldst.anasi - unsigned int anrs2:5; - #define rs2 ldst.anrs2 - #define shcnt rs2 - } ldst; + { + unsigned int anop:2; + #define op ldst.anop + unsigned int anrd:5; + #define rd ldst.anrd + unsigned int op3:6; + unsigned int anrs1:5; + #define rs1 ldst.anrs1 + unsigned int i:1; + unsigned int anasi:8; + #define asi ldst.anasi + unsigned int anrs2:5; + #define rs2 ldst.anrs2 + #define shcnt rs2 + } ldst; struct - { - unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1; - unsigned int IMM13:13; - #define imm13 IMM13.IMM13 - } IMM13; + { + unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1; + unsigned int IMM13:13; + #define imm13 IMM13.IMM13 + } IMM13; struct - { - unsigned int anop:2; - unsigned int a:1; - unsigned int cond:4; - unsigned int op2:3; - unsigned int DISP22:22; - #define disp22 branch.DISP22 - #define imm22 disp22 - } branch; + { + unsigned int anop:2; + unsigned int a:1; + unsigned int cond:4; + unsigned int op2:3; + unsigned int DISP22:22; + #define disp22 branch.DISP22 + #define imm22 disp22 + } branch; struct - { - unsigned int anop:2; - unsigned int a:1; - unsigned int z:1; - unsigned int rcond:3; - unsigned int op2:3; - unsigned int DISP16HI:2; - unsigned int p:1; - unsigned int _rs1:5; - unsigned int DISP16LO:14; - } branch16; + { + unsigned int anop:2; + unsigned int a:1; + unsigned int z:1; + unsigned int rcond:3; + unsigned int op2:3; + unsigned int DISP16HI:2; + unsigned int p:1; + unsigned int _rs1:5; + unsigned int DISP16LO:14; + } branch16; struct - { - unsigned int anop:2; - unsigned int adisp30:30; - #define disp30 call.adisp30 - } call; + { + unsigned int anop:2; + unsigned int adisp30:30; + #define disp30 call.adisp30 + } call; }; */ @@ -2467,8 +2467,8 @@ is_delayed_branch (insn) { const struct sparc_opcode *opcode = op->opcode; if ((opcode->match & insn) == opcode->match - && (opcode->lose & insn) == 0) - return (opcode->flags & F_DELAYED); + && (opcode->lose & insn) == 0) + return (opcode->flags & F_DELAYED); } return 0; } @@ -2510,13 +2510,13 @@ print_insn_sparc (memaddr, info) current_arch_mask = compute_arch_mask (info->mach); if (!opcodes_initialized) - sorted_opcodes = (const struct sparc_opcode **) + sorted_opcodes = (const struct sparc_opcode **) malloc (sparc_num_opcodes * sizeof (struct sparc_opcode *)); /* Reset the sorted table so we can resort it. */ for (i = 0; i < sparc_num_opcodes; ++i) - sorted_opcodes[i] = &sparc_opcodes[i]; + sorted_opcodes[i] = &sparc_opcodes[i]; qsort ((char *) sorted_opcodes, sparc_num_opcodes, - sizeof (sorted_opcodes[0]), compare_opcodes); + sizeof (sorted_opcodes[0]), compare_opcodes); build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes); current_mach = info->mach; @@ -2528,8 +2528,8 @@ print_insn_sparc (memaddr, info) (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); if (status != 0) { - (*info->memory_error_func) (status, memaddr, info); - return -1; + (*info->memory_error_func) (status, memaddr, info); + return -1; } } @@ -2542,10 +2542,10 @@ print_insn_sparc (memaddr, info) insn = getword (buffer); - info->insn_info_valid = 1; /* We do return this info */ - info->insn_type = dis_nonbranch; /* Assume non branch insn */ - info->branch_delay_insns = 0; /* Assume no delay */ - info->target = 0; /* Assume no target known */ + info->insn_info_valid = 1; /* We do return this info */ + info->insn_type = dis_nonbranch; /* Assume non branch insn */ + info->branch_delay_insns = 0; /* Assume no delay */ + info->target = 0; /* Assume no target known */ for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next) { @@ -2553,484 +2553,484 @@ print_insn_sparc (memaddr, info) /* If the insn isn't supported by the current architecture, skip it. */ if (! (opcode->architecture & current_arch_mask)) - continue; + continue; if ((opcode->match & insn) == opcode->match - && (opcode->lose & insn) == 0) - { - /* Nonzero means that we have found an instruction which has - the effect of adding or or'ing the imm13 field to rs1. */ - int imm_added_to_rs1 = 0; - int imm_ored_to_rs1 = 0; + && (opcode->lose & insn) == 0) + { + /* Nonzero means that we have found an instruction which has + the effect of adding or or'ing the imm13 field to rs1. */ + int imm_added_to_rs1 = 0; + int imm_ored_to_rs1 = 0; - /* Nonzero means that we have found a plus sign in the args - field of the opcode table. */ - int found_plus = 0; + /* Nonzero means that we have found a plus sign in the args + field of the opcode table. */ + int found_plus = 0; - /* Nonzero means we have an annulled branch. */ - int is_annulled = 0; + /* Nonzero means we have an annulled branch. */ + int is_annulled = 0; - /* Do we have an `add' or `or' instruction combining an + /* Do we have an `add' or `or' instruction combining an immediate with rs1? */ - if (opcode->match == 0x80102000) /* or */ - imm_ored_to_rs1 = 1; - if (opcode->match == 0x80002000) /* add */ - imm_added_to_rs1 = 1; - - if (X_RS1 (insn) != X_RD (insn) - && strchr (opcode->args, 'r') != 0) - /* Can't do simple format if source and dest are different. */ - continue; - if (X_RS2 (insn) != X_RD (insn) - && strchr (opcode->args, 'O') != 0) - /* Can't do simple format if source and dest are different. */ - continue; - - (*info->fprintf_func) (stream, opcode->name); - - { - register const char *s; - - if (opcode->args[0] != ',') - (*info->fprintf_func) (stream, " "); - for (s = opcode->args; *s != '\0'; ++s) - { - while (*s == ',') - { - (*info->fprintf_func) (stream, ","); - ++s; - switch (*s) { - case 'a': - (*info->fprintf_func) (stream, "a"); - is_annulled = 1; - ++s; - continue; - case 'N': - (*info->fprintf_func) (stream, "pn"); - ++s; - continue; - - case 'T': - (*info->fprintf_func) (stream, "pt"); - ++s; - continue; - - default: - break; - } /* switch on arg */ - } /* while there are comma started args */ - - (*info->fprintf_func) (stream, " "); - - switch (*s) - { - case '+': - found_plus = 1; - - /* note fall-through */ - default: - (*info->fprintf_func) (stream, "%c", *s); - break; - - case '#': - (*info->fprintf_func) (stream, "0"); - break; - -#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n]) - case '1': - case 'r': - reg (X_RS1 (insn)); - break; - - case '2': - case 'O': - reg (X_RS2 (insn)); - break; - - case 'd': - reg (X_RD (insn)); - break; -#undef reg - -#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n]) -#define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)]) - case 'e': - freg (X_RS1 (insn)); - break; - case 'v': /* double/even */ - case 'V': /* quad/multiple of 4 */ - fregx (X_RS1 (insn)); - break; - - case 'f': - freg (X_RS2 (insn)); - break; - case 'B': /* double/even */ - case 'R': /* quad/multiple of 4 */ - fregx (X_RS2 (insn)); - break; - - case 'g': - freg (X_RD (insn)); - break; - case 'H': /* double/even */ - case 'J': /* quad/multiple of 4 */ - fregx (X_RD (insn)); - break; -#undef freg -#undef fregx - -#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n)) - case 'b': - creg (X_RS1 (insn)); - break; - - case 'c': - creg (X_RS2 (insn)); - break; - - case 'D': - creg (X_RD (insn)); - break; -#undef creg - - case 'h': - (*info->fprintf_func) (stream, "%%hi(%#x)", - ((unsigned) 0xFFFFFFFF - & ((int) X_IMM22 (insn) << 10))); - break; - - case 'i': /* 13 bit immediate */ - case 'I': /* 11 bit immediate */ - case 'j': /* 10 bit immediate */ - { - int imm; - - if (*s == 'i') - imm = X_SIMM (insn, 13); - else if (*s == 'I') - imm = X_SIMM (insn, 11); - else - imm = X_SIMM (insn, 10); - - /* Check to see whether we have a 1+i, and take - note of that fact. - - Note: because of the way we sort the table, - we will be matching 1+i rather than i+1, - so it is OK to assume that i is after +, - not before it. */ - if (found_plus) - imm_added_to_rs1 = 1; - - if (imm <= 9) - (*info->fprintf_func) (stream, "%d", imm); - else - (*info->fprintf_func) (stream, "%#x", imm); - } - break; - - case 'X': /* 5 bit unsigned immediate */ - case 'Y': /* 6 bit unsigned immediate */ - { - int imm = X_IMM (insn, *s == 'X' ? 5 : 6); - - if (imm <= 9) - (info->fprintf_func) (stream, "%d", imm); - else - (info->fprintf_func) (stream, "%#x", (unsigned) imm); - } - break; - - case '3': - (info->fprintf_func) (stream, "%d", X_IMM (insn, 3)); - break; - - case 'K': - { - int mask = X_MEMBAR (insn); - int bit = 0x40, printed_one = 0; - const char *name; - - if (mask == 0) - (info->fprintf_func) (stream, "0"); - else - while (bit) - { - if (mask & bit) - { - if (printed_one) - (info->fprintf_func) (stream, "|"); - name = sparc_decode_membar (bit); - (info->fprintf_func) (stream, "%s", name); - printed_one = 1; - } - bit >>= 1; - } - break; - } - - case 'k': - info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4; - (*info->print_address_func) (info->target, info); - break; - - case 'G': - info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4; - (*info->print_address_func) (info->target, info); - break; - - case '6': - case '7': - case '8': - case '9': - (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0'); - break; - - case 'z': - (*info->fprintf_func) (stream, "%%icc"); - break; - - case 'Z': - (*info->fprintf_func) (stream, "%%xcc"); - break; - - case 'E': - (*info->fprintf_func) (stream, "%%ccr"); - break; - - case 's': - (*info->fprintf_func) (stream, "%%fprs"); - break; - - case 'o': - (*info->fprintf_func) (stream, "%%asi"); - break; - - case 'W': - (*info->fprintf_func) (stream, "%%tick"); - break; - - case 'P': - (*info->fprintf_func) (stream, "%%pc"); - break; - - case '?': - if (X_RS1 (insn) == 31) - (*info->fprintf_func) (stream, "%%ver"); - else if ((unsigned) X_RS1 (insn) < 16) - (*info->fprintf_func) (stream, "%%%s", - v9_priv_reg_names[X_RS1 (insn)]); - else - (*info->fprintf_func) (stream, "%%reserved"); - break; - - case '!': - if ((unsigned) X_RD (insn) < 15) - (*info->fprintf_func) (stream, "%%%s", - v9_priv_reg_names[X_RD (insn)]); - else - (*info->fprintf_func) (stream, "%%reserved"); - break; - - case '/': - if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25) - (*info->fprintf_func) (stream, "%%reserved"); - else - (*info->fprintf_func) (stream, "%%%s", - v9a_asr_reg_names[X_RS1 (insn)-16]); - break; - - case '_': - if (X_RD (insn) < 16 || X_RD (insn) > 25) - (*info->fprintf_func) (stream, "%%reserved"); - else - (*info->fprintf_func) (stream, "%%%s", - v9a_asr_reg_names[X_RD (insn)-16]); - break; - - case '*': - { - const char *name = sparc_decode_prefetch (X_RD (insn)); - - if (name) - (*info->fprintf_func) (stream, "%s", name); - else - (*info->fprintf_func) (stream, "%d", X_RD (insn)); - break; - } - - case 'M': - (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn)); - break; - - case 'm': - (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn)); - break; - - case 'L': - info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4; - (*info->print_address_func) (info->target, info); - break; - - case 'n': - (*info->fprintf_func) - (stream, "%#x", SEX (X_DISP22 (insn), 22)); - break; - - case 'l': - info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4; - (*info->print_address_func) (info->target, info); - break; - - case 'A': - { - const char *name; - - if ((info->mach == bfd_mach_sparc_v8plusa) || + if (opcode->match == 0x80102000) /* or */ + imm_ored_to_rs1 = 1; + if (opcode->match == 0x80002000) /* add */ + imm_added_to_rs1 = 1; + + if (X_RS1 (insn) != X_RD (insn) + && strchr (opcode->args, 'r') != 0) + /* Can't do simple format if source and dest are different. */ + continue; + if (X_RS2 (insn) != X_RD (insn) + && strchr (opcode->args, 'O') != 0) + /* Can't do simple format if source and dest are different. */ + continue; + + (*info->fprintf_func) (stream, opcode->name); + + { + register const char *s; + + if (opcode->args[0] != ',') + (*info->fprintf_func) (stream, " "); + for (s = opcode->args; *s != '\0'; ++s) + { + while (*s == ',') + { + (*info->fprintf_func) (stream, ","); + ++s; + switch (*s) { + case 'a': + (*info->fprintf_func) (stream, "a"); + is_annulled = 1; + ++s; + continue; + case 'N': + (*info->fprintf_func) (stream, "pn"); + ++s; + continue; + + case 'T': + (*info->fprintf_func) (stream, "pt"); + ++s; + continue; + + default: + break; + } /* switch on arg */ + } /* while there are comma started args */ + + (*info->fprintf_func) (stream, " "); + + switch (*s) + { + case '+': + found_plus = 1; + + /* note fall-through */ + default: + (*info->fprintf_func) (stream, "%c", *s); + break; + + case '#': + (*info->fprintf_func) (stream, "0"); + break; + +#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n]) + case '1': + case 'r': + reg (X_RS1 (insn)); + break; + + case '2': + case 'O': + reg (X_RS2 (insn)); + break; + + case 'd': + reg (X_RD (insn)); + break; +#undef reg + +#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n]) +#define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)]) + case 'e': + freg (X_RS1 (insn)); + break; + case 'v': /* double/even */ + case 'V': /* quad/multiple of 4 */ + fregx (X_RS1 (insn)); + break; + + case 'f': + freg (X_RS2 (insn)); + break; + case 'B': /* double/even */ + case 'R': /* quad/multiple of 4 */ + fregx (X_RS2 (insn)); + break; + + case 'g': + freg (X_RD (insn)); + break; + case 'H': /* double/even */ + case 'J': /* quad/multiple of 4 */ + fregx (X_RD (insn)); + break; +#undef freg +#undef fregx + +#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n)) + case 'b': + creg (X_RS1 (insn)); + break; + + case 'c': + creg (X_RS2 (insn)); + break; + + case 'D': + creg (X_RD (insn)); + break; +#undef creg + + case 'h': + (*info->fprintf_func) (stream, "%%hi(%#x)", + ((unsigned) 0xFFFFFFFF + & ((int) X_IMM22 (insn) << 10))); + break; + + case 'i': /* 13 bit immediate */ + case 'I': /* 11 bit immediate */ + case 'j': /* 10 bit immediate */ + { + int imm; + + if (*s == 'i') + imm = X_SIMM (insn, 13); + else if (*s == 'I') + imm = X_SIMM (insn, 11); + else + imm = X_SIMM (insn, 10); + + /* Check to see whether we have a 1+i, and take + note of that fact. + + Note: because of the way we sort the table, + we will be matching 1+i rather than i+1, + so it is OK to assume that i is after +, + not before it. */ + if (found_plus) + imm_added_to_rs1 = 1; + + if (imm <= 9) + (*info->fprintf_func) (stream, "%d", imm); + else + (*info->fprintf_func) (stream, "%#x", imm); + } + break; + + case 'X': /* 5 bit unsigned immediate */ + case 'Y': /* 6 bit unsigned immediate */ + { + int imm = X_IMM (insn, *s == 'X' ? 5 : 6); + + if (imm <= 9) + (info->fprintf_func) (stream, "%d", imm); + else + (info->fprintf_func) (stream, "%#x", (unsigned) imm); + } + break; + + case '3': + (info->fprintf_func) (stream, "%d", X_IMM (insn, 3)); + break; + + case 'K': + { + int mask = X_MEMBAR (insn); + int bit = 0x40, printed_one = 0; + const char *name; + + if (mask == 0) + (info->fprintf_func) (stream, "0"); + else + while (bit) + { + if (mask & bit) + { + if (printed_one) + (info->fprintf_func) (stream, "|"); + name = sparc_decode_membar (bit); + (info->fprintf_func) (stream, "%s", name); + printed_one = 1; + } + bit >>= 1; + } + break; + } + + case 'k': + info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'G': + info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4; + (*info->print_address_func) (info->target, info); + break; + + case '6': + case '7': + case '8': + case '9': + (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0'); + break; + + case 'z': + (*info->fprintf_func) (stream, "%%icc"); + break; + + case 'Z': + (*info->fprintf_func) (stream, "%%xcc"); + break; + + case 'E': + (*info->fprintf_func) (stream, "%%ccr"); + break; + + case 's': + (*info->fprintf_func) (stream, "%%fprs"); + break; + + case 'o': + (*info->fprintf_func) (stream, "%%asi"); + break; + + case 'W': + (*info->fprintf_func) (stream, "%%tick"); + break; + + case 'P': + (*info->fprintf_func) (stream, "%%pc"); + break; + + case '?': + if (X_RS1 (insn) == 31) + (*info->fprintf_func) (stream, "%%ver"); + else if ((unsigned) X_RS1 (insn) < 16) + (*info->fprintf_func) (stream, "%%%s", + v9_priv_reg_names[X_RS1 (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '!': + if ((unsigned) X_RD (insn) < 15) + (*info->fprintf_func) (stream, "%%%s", + v9_priv_reg_names[X_RD (insn)]); + else + (*info->fprintf_func) (stream, "%%reserved"); + break; + + case '/': + if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25) + (*info->fprintf_func) (stream, "%%reserved"); + else + (*info->fprintf_func) (stream, "%%%s", + v9a_asr_reg_names[X_RS1 (insn)-16]); + break; + + case '_': + if (X_RD (insn) < 16 || X_RD (insn) > 25) + (*info->fprintf_func) (stream, "%%reserved"); + else + (*info->fprintf_func) (stream, "%%%s", + v9a_asr_reg_names[X_RD (insn)-16]); + break; + + case '*': + { + const char *name = sparc_decode_prefetch (X_RD (insn)); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "%d", X_RD (insn)); + break; + } + + case 'M': + (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn)); + break; + + case 'm': + (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn)); + break; + + case 'L': + info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'n': + (*info->fprintf_func) + (stream, "%#x", SEX (X_DISP22 (insn), 22)); + break; + + case 'l': + info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4; + (*info->print_address_func) (info->target, info); + break; + + case 'A': + { + const char *name; + + if ((info->mach == bfd_mach_sparc_v8plusa) || ((info->mach >= bfd_mach_sparc_v9) && (info->mach <= bfd_mach_sparc_v9b))) - name = sparc_decode_asi_v9 (X_ASI (insn)); - else - name = sparc_decode_asi_v8 (X_ASI (insn)); - - if (name) - (*info->fprintf_func) (stream, "%s", name); - else - (*info->fprintf_func) (stream, "(%d)", X_ASI (insn)); - break; - } - - case 'C': - (*info->fprintf_func) (stream, "%%csr"); - break; - - case 'F': - (*info->fprintf_func) (stream, "%%fsr"); - break; - - case 'p': - (*info->fprintf_func) (stream, "%%psr"); - break; - - case 'q': - (*info->fprintf_func) (stream, "%%fq"); - break; - - case 'Q': - (*info->fprintf_func) (stream, "%%cq"); - break; - - case 't': - (*info->fprintf_func) (stream, "%%tbr"); - break; - - case 'w': - (*info->fprintf_func) (stream, "%%wim"); - break; - - case 'x': - (*info->fprintf_func) (stream, "%d", - ((X_LDST_I (insn) << 8) - + X_ASI (insn))); - break; - - case 'y': - (*info->fprintf_func) (stream, "%%y"); - break; - - case 'u': - case 'U': - { - int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn); - const char *name = sparc_decode_sparclet_cpreg (val); - - if (name) - (*info->fprintf_func) (stream, "%s", name); - else - (*info->fprintf_func) (stream, "%%cpreg(%d)", val); - break; - } - } - } - } - - /* If we are adding or or'ing something to rs1, then - check to see whether the previous instruction was - a sethi to the same register as in the sethi. - If so, attempt to print the result of the add or - or (in this context add and or do the same thing) - and its symbolic value. */ - if (imm_ored_to_rs1 || imm_added_to_rs1) - { - unsigned long prev_insn; - int errcode; - - errcode = - (*info->read_memory_func) - (memaddr - 4, buffer, sizeof (buffer), info); - prev_insn = getword (buffer); - - if (errcode == 0) - { - /* If it is a delayed branch, we need to look at the - instruction before the delayed branch. This handles - sequences such as - - sethi %o1, %hi(_foo), %o1 - call _printf - or %o1, %lo(_foo), %o1 - */ - - if (is_delayed_branch (prev_insn)) - { - errcode = (*info->read_memory_func) - (memaddr - 8, buffer, sizeof (buffer), info); - prev_insn = getword (buffer); - } - } - - /* If there was a problem reading memory, then assume - the previous instruction was not sethi. */ - if (errcode == 0) - { - /* Is it sethi to the same register? */ - if ((prev_insn & 0xc1c00000) == 0x01000000 - && X_RD (prev_insn) == X_RS1 (insn)) - { - (*info->fprintf_func) (stream, "\t! "); - info->target = - ((unsigned) 0xFFFFFFFF - & ((int) X_IMM22 (prev_insn) << 10)); - if (imm_added_to_rs1) - info->target += X_SIMM (insn, 13); - else - info->target |= X_SIMM (insn, 13); - (*info->print_address_func) (info->target, info); - info->insn_type = dis_dref; - info->data_size = 4; /* FIXME!!! */ - } - } - } - - if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR)) - { - /* FIXME -- check is_annulled flag */ - if (opcode->flags & F_UNBR) - info->insn_type = dis_branch; - if (opcode->flags & F_CONDBR) - info->insn_type = dis_condbranch; - if (opcode->flags & F_JSR) - info->insn_type = dis_jsr; - if (opcode->flags & F_DELAYED) - info->branch_delay_insns = 1; - } - - return sizeof (buffer); - } + name = sparc_decode_asi_v9 (X_ASI (insn)); + else + name = sparc_decode_asi_v8 (X_ASI (insn)); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "(%d)", X_ASI (insn)); + break; + } + + case 'C': + (*info->fprintf_func) (stream, "%%csr"); + break; + + case 'F': + (*info->fprintf_func) (stream, "%%fsr"); + break; + + case 'p': + (*info->fprintf_func) (stream, "%%psr"); + break; + + case 'q': + (*info->fprintf_func) (stream, "%%fq"); + break; + + case 'Q': + (*info->fprintf_func) (stream, "%%cq"); + break; + + case 't': + (*info->fprintf_func) (stream, "%%tbr"); + break; + + case 'w': + (*info->fprintf_func) (stream, "%%wim"); + break; + + case 'x': + (*info->fprintf_func) (stream, "%d", + ((X_LDST_I (insn) << 8) + + X_ASI (insn))); + break; + + case 'y': + (*info->fprintf_func) (stream, "%%y"); + break; + + case 'u': + case 'U': + { + int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn); + const char *name = sparc_decode_sparclet_cpreg (val); + + if (name) + (*info->fprintf_func) (stream, "%s", name); + else + (*info->fprintf_func) (stream, "%%cpreg(%d)", val); + break; + } + } + } + } + + /* If we are adding or or'ing something to rs1, then + check to see whether the previous instruction was + a sethi to the same register as in the sethi. + If so, attempt to print the result of the add or + or (in this context add and or do the same thing) + and its symbolic value. */ + if (imm_ored_to_rs1 || imm_added_to_rs1) + { + unsigned long prev_insn; + int errcode; + + errcode = + (*info->read_memory_func) + (memaddr - 4, buffer, sizeof (buffer), info); + prev_insn = getword (buffer); + + if (errcode == 0) + { + /* If it is a delayed branch, we need to look at the + instruction before the delayed branch. This handles + sequences such as + + sethi %o1, %hi(_foo), %o1 + call _printf + or %o1, %lo(_foo), %o1 + */ + + if (is_delayed_branch (prev_insn)) + { + errcode = (*info->read_memory_func) + (memaddr - 8, buffer, sizeof (buffer), info); + prev_insn = getword (buffer); + } + } + + /* If there was a problem reading memory, then assume + the previous instruction was not sethi. */ + if (errcode == 0) + { + /* Is it sethi to the same register? */ + if ((prev_insn & 0xc1c00000) == 0x01000000 + && X_RD (prev_insn) == X_RS1 (insn)) + { + (*info->fprintf_func) (stream, "\t! "); + info->target = + ((unsigned) 0xFFFFFFFF + & ((int) X_IMM22 (prev_insn) << 10)); + if (imm_added_to_rs1) + info->target += X_SIMM (insn, 13); + else + info->target |= X_SIMM (insn, 13); + (*info->print_address_func) (info->target, info); + info->insn_type = dis_dref; + info->data_size = 4; /* FIXME!!! */ + } + } + } + + if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR)) + { + /* FIXME -- check is_annulled flag */ + if (opcode->flags & F_UNBR) + info->insn_type = dis_branch; + if (opcode->flags & F_CONDBR) + info->insn_type = dis_condbranch; + if (opcode->flags & F_JSR) + info->insn_type = dis_jsr; + if (opcode->flags & F_DELAYED) + info->branch_delay_insns = 1; + } + + return sizeof (buffer); + } } - info->insn_type = dis_noninsn; /* Mark as non-valid instruction */ + info->insn_type = dis_noninsn; /* Mark as non-valid instruction */ (*info->fprintf_func) (stream, _("unknown")); return sizeof (buffer); } @@ -3051,10 +3051,10 @@ compute_arch_mask (mach) case bfd_mach_sparc_sparclite : case bfd_mach_sparc_sparclite_le : /* sparclites insns are recognized by default (because that's how - they've always been treated, for better or worse). Kludge this by - indicating generic v8 is also selected. */ + they've always been treated, for better or worse). Kludge this by + indicating generic v8 is also selected. */ return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE) - | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); + | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)); case bfd_mach_sparc_v8plus : case bfd_mach_sparc_v9 : return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9); @@ -3087,14 +3087,14 @@ compare_opcodes (const void *a, const void *b) if (op0->architecture & current_arch_mask) { if (! (op1->architecture & current_arch_mask)) - return -1; + return -1; } else { if (op1->architecture & current_arch_mask) - return 1; + return 1; else if (op0->architecture != op1->architecture) - return op0->architecture - op1->architecture; + return op0->architecture - op1->architecture; } /* If a bit is set in both match and lose, there is something @@ -3102,10 +3102,10 @@ compare_opcodes (const void *a, const void *b) if (match0 & lose0) { fprintf - (stderr, - /* xgettext:c-format */ - _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), - op0->name, match0, lose0); + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op0->name, match0, lose0); op0->lose &= ~op0->match; lose0 = op0->lose; } @@ -3113,10 +3113,10 @@ compare_opcodes (const void *a, const void *b) if (match1 & lose1) { fprintf - (stderr, - /* xgettext:c-format */ - _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), - op1->name, match1, lose1); + (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"), + op1->name, match1, lose1); op1->lose &= ~op1->match; lose1 = op1->lose; } @@ -3130,7 +3130,7 @@ compare_opcodes (const void *a, const void *b) int x1 = (match1 & x) != 0; if (x0 != x1) - return x1 - x0; + return x1 - x0; } for (i = 0; i < 32; ++i) @@ -3140,7 +3140,7 @@ compare_opcodes (const void *a, const void *b) int x1 = (lose1 & x) != 0; if (x0 != x1) - return x1 - x0; + return x1 - x0; } /* They are functionally equal. So as long as the opcode table is @@ -3160,12 +3160,12 @@ compare_opcodes (const void *a, const void *b) if (i) { if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */ - return i; + return i; else - fprintf (stderr, - /* xgettext:c-format */ - _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), - op0->name, op1->name); + fprintf (stderr, + /* xgettext:c-format */ + _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"), + op0->name, op1->name); } /* Fewer arguments are preferred. */ @@ -3183,15 +3183,15 @@ compare_opcodes (const void *a, const void *b) if (p0 && p1) { - /* There is a plus in both operands. Note that a plus - sign cannot be the first character in args, - so the following [-1]'s are valid. */ - if (p0[-1] == 'i' && p1[1] == 'i') - /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ - return 1; - if (p0[1] == 'i' && p1[-1] == 'i') - /* op0 is 1+i and op1 is i+1, so op0 goes first. */ - return -1; + /* There is a plus in both operands. Note that a plus + sign cannot be the first character in args, + so the following [-1]'s are valid. */ + if (p0[-1] == 'i' && p1[1] == 'i') + /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ + return 1; + if (p0[1] == 'i' && p1[-1] == 'i') + /* op0 is 1+i and op1 is i+1, so op0 goes first. */ + return -1; } } @@ -3252,14 +3252,14 @@ build_hash_table (opcode_table, hash_table, num_opcodes) for (i = 0; i < HASH_SIZE; ++i) { if (hash_count[i] < min_count) - min_count = hash_count[i]; - if (hash_count[i] > max_count) - max_count = hash_count[i]; - total += hash_count[i]; + min_count = hash_count[i]; + if (hash_count[i] > max_count) + max_count = hash_count[i]; + total += hash_count[i]; } printf ("Opcode hash table stats: min %d, max %d, ave %f\n", - min_count, max_count, (double) total / HASH_SIZE); + min_count, max_count, (double) total / HASH_SIZE); } #endif } diff --git a/sparc.ld b/sparc.ld index 2b19d57ff..26ab4151f 100644 --- a/sparc.ld +++ b/sparc.ld @@ -1,5 +1,5 @@ OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", - "elf32-sparc") + "elf32-sparc") OUTPUT_ARCH(sparc) SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); ENTRY(_start) @@ -7,13 +7,13 @@ 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) } + .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 : @@ -26,21 +26,21 @@ SECTIONS { *(.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 + .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) @@ -74,7 +74,7 @@ SECTIONS { *(.dtors) } - .plt : { *(.plt) } + .plt : { *(.plt) } .got : { *(.got.plt) *(.got) } .dynamic : { *(.dynamic) } /* We want the small data sections together, so single-instruction offsets diff --git a/sparc64.ld b/sparc64.ld index 19853ff68..54d2f7dd8 100644 --- a/sparc64.ld +++ b/sparc64.ld @@ -1,5 +1,5 @@ OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", - "elf64-sparc") + "elf64-sparc") OUTPUT_ARCH(sparc:v9) SEARCH_DIR(/lib64); SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib64); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib64); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib); ENTRY(_start) @@ -7,13 +7,13 @@ 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) } + .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 : @@ -26,21 +26,21 @@ SECTIONS { *(.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 + .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) @@ -82,7 +82,7 @@ SECTIONS { *(.dtors) } - .plt : { *(.plt) } + .plt : { *(.plt) } .got : { *(.got.plt) *(.got) } .dynamic : { *(.dynamic) } /* We want the small data sections together, so single-instruction offsets -- cgit v1.2.3 From 115646b6480b4f3f0fd9f7a66f46c96f68604cc7 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 7 Oct 2007 10:00:55 +0000 Subject: More user timer fixes (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3339 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 +- hw/slavio_timer.c | 154 ++++++++++++++++++++++++++++++------------------------ 2 files changed, 87 insertions(+), 69 deletions(-) diff --git a/Changelog b/Changelog index f61a58061..32161aa45 100644 --- a/Changelog +++ b/Changelog @@ -3,7 +3,7 @@ - Monitor multiplexing to several I/O channels (Jason Wessel) - ds1225y nvram support (Herve Poussineau) - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) - - Several Sparc fixes (Aurelien Jarno, Blue Swirl) + - Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif) - MIPS 64-bit FPU support (Thiemo Seufer) - Xscale PDA emulation (Andrzei Zaborowski) - ColdFire system emulation (Paul Brook) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index fa4b95b3f..1b17a3d37 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -54,16 +54,24 @@ typedef struct SLAVIO_TIMERState { ptimer_state *timer; uint32_t count, counthigh, reached; uint64_t limit; - int stopped; - int mode; // 0 = processor, 1 = user, 2 = system + // processor only + int running; + struct SLAVIO_TIMERState *master; + int slave_index; + // system only struct SLAVIO_TIMERState *slave[MAX_CPUS]; uint32_t slave_mode; } SLAVIO_TIMERState; #define TIMER_MAXADDR 0x1f -#define TIMER_SIZE (TIMER_MAXADDR + 1) +#define SYS_TIMER_SIZE 0x14 #define CPU_TIMER_SIZE 0x10 +static int slavio_timer_is_user(SLAVIO_TIMERState *s) +{ + return s->master && (s->master->slave_mode & (1 << s->slave_index)); +} + // Update count, set irq, update expire_time // Convert from ptimer countdown units static void slavio_timer_get_out(SLAVIO_TIMERState *s) @@ -84,9 +92,10 @@ static void slavio_timer_irq(void *opaque) slavio_timer_get_out(s); DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); - s->reached = 0x80000000; - if (s->mode != 1) + if (!slavio_timer_is_user(s)) { + s->reached = 0x80000000; qemu_irq_raise(s->irq); + } } static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) @@ -99,35 +108,39 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) case 0: // read limit (system counter mode) or read most signifying // part of counter (user mode) - if (s->mode != 1) { + if (slavio_timer_is_user(s)) { + // read user timer MSW + slavio_timer_get_out(s); + ret = s->counthigh; + } else { + // read limit // clear irq qemu_irq_lower(s->irq); s->reached = 0; ret = s->limit & 0x7fffffff; } - else { - slavio_timer_get_out(s); - ret = s->counthigh & 0x7fffffff; - } break; case 1: // read counter and reached bit (system mode) or read lsbits // of counter (user mode) slavio_timer_get_out(s); - if (s->mode != 1) - ret = (s->count & 0x7fffffff) | s->reached; - else - ret = s->count; + if (slavio_timer_is_user(s)) // read user timer LSW + ret = s->count & 0xffffffe00; + else // read limit + ret = (s->count & 0x7ffffe00) | s->reached; break; case 3: + // only available in processor counter/timer // read start/stop status - ret = s->stopped; + ret = s->running; break; case 4: + // only available in system counter // read user/system mode ret = s->slave_mode; break; default: + DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr); ret = 0; break; } @@ -146,20 +159,31 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { case 0: - if (s->mode == 1) { - // set user counter limit MSW, reset counter + if (slavio_timer_is_user(s)) { + // set user counter MSW, reset counter qemu_irq_lower(s->irq); - s->limit &= 0xfffffe00ULL; - s->limit |= (uint64_t)val << 32; + s->limit = 0x7ffffffffffffe00ULL; + DPRINTF("processor %d user timer reset\n", s->slave_index); + ptimer_set_limit(s->timer, s->limit >> 9, 1); + } else { + // set limit, reset counter + qemu_irq_lower(s->irq); + s->limit = val & 0x7ffffe00ULL; if (!s->limit) - s->limit = 0x7ffffffffffffe00ULL; + s->limit = 0x7ffffe00ULL; ptimer_set_limit(s->timer, s->limit >> 9, 1); - break; } - // set limit, reset counter - reload = 1; - qemu_irq_lower(s->irq); - // fall through + break; + case 1: + if (slavio_timer_is_user(s)) { + // set user counter LSW, reset counter + qemu_irq_lower(s->irq); + s->limit = 0x7ffffffffffffe00ULL; + DPRINTF("processor %d user timer reset\n", s->slave_index); + ptimer_set_limit(s->timer, s->limit >> 9, 1); + } else + DPRINTF("not user timer\n"); + break; case 2: // set limit without resetting counter s->limit = val & 0x7ffffe00ULL; @@ -167,52 +191,42 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 s->limit = 0x7ffffe00ULL; ptimer_set_limit(s->timer, s->limit >> 9, reload); break; - case 1: - // set user counter limit LSW, reset counter - if (s->mode == 1) { - qemu_irq_lower(s->irq); - s->limit &= 0x7fffffff00000000ULL; - s->limit |= val & 0xfffffe00ULL; - if (!s->limit) - s->limit = 0x7ffffffffffffe00ULL; - ptimer_set_limit(s->timer, s->limit >> 9, 1); - } - break; case 3: - // start/stop user counter - if (s->mode == 1) { - if (val & 1) { - ptimer_stop(s->timer); - s->stopped = 1; - } - else { + if (slavio_timer_is_user(s)) { + // start/stop user counter + if ((val & 1) && !s->running) { + DPRINTF("processor %d user timer started\n", s->slave_index); ptimer_run(s->timer, 0); - s->stopped = 0; + s->running = 1; + } else if (!(val & 1) && s->running) { + DPRINTF("processor %d user timer stopped\n", s->slave_index); + ptimer_stop(s->timer); + s->running = 0; } } break; case 4: - // bit 0: user (1) or system (0) counter mode - { + if (s->master == NULL) { unsigned int i; for (i = 0; i < MAX_CPUS; i++) { if (val & (1 << i)) { qemu_irq_lower(s->slave[i]->irq); s->slave[i]->limit = -1ULL; - s->slave[i]->mode = 1; - } else { - s->slave[i]->mode = 0; } - ptimer_stop(s->slave[i]->timer); - ptimer_set_limit(s->slave[i]->timer, s->slave[i]->limit >> 9, - 1); - ptimer_run(s->slave[i]->timer, 0); + if ((val & (1 << i)) != (s->slave_mode & (1 << i))) { + ptimer_stop(s->slave[i]->timer); + ptimer_set_limit(s->slave[i]->timer, s->slave[i]->limit >> 9, 1); + DPRINTF("processor %d timer changed\n", s->slave[i]->slave_index); + ptimer_run(s->slave[i]->timer, 0); + } } s->slave_mode = val & ((1 << MAX_CPUS) - 1); - } + } else + DPRINTF("not system timer\n"); break; default: + DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr); break; } } @@ -238,8 +252,8 @@ static void slavio_timer_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->counthigh); qemu_put_be32(f, 0); // Was irq qemu_put_be32s(f, &s->reached); - qemu_put_be32s(f, &s->stopped); - qemu_put_be32s(f, &s->mode); + qemu_put_be32s(f, &s->running); + qemu_put_be32s(f, 0); // Was mode qemu_put_ptimer(f, s->timer); } @@ -256,8 +270,8 @@ static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->counthigh); qemu_get_be32s(f, &tmp); // Was irq qemu_get_be32s(f, &s->reached); - qemu_get_be32s(f, &s->stopped); - qemu_get_be32s(f, &s->mode); + qemu_get_be32s(f, &s->running); + qemu_get_be32s(f, &tmp); // Was mode qemu_get_ptimer(f, s->timer); return 0; @@ -267,18 +281,22 @@ static void slavio_timer_reset(void *opaque) { SLAVIO_TIMERState *s = opaque; - s->limit = 0x7ffffe00ULL; + if (slavio_timer_is_user(s)) + s->limit = 0x7ffffffffffffe00ULL; + else + s->limit = 0x7ffffe00ULL; s->count = 0; s->reached = 0; - s->mode &= 2; ptimer_set_limit(s->timer, s->limit >> 9, 1); ptimer_run(s->timer, 0); - s->stopped = 1; + s->running = 1; qemu_irq_lower(s->irq); } static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, - qemu_irq irq, int mode) + qemu_irq irq, + SLAVIO_TIMERState *master, + int slave_index) { int slavio_timer_io_memory; SLAVIO_TIMERState *s; @@ -288,18 +306,18 @@ static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, if (!s) return s; s->irq = irq; - s->mode = mode; + s->master = master; + s->slave_index = slave_index; bh = qemu_bh_new(slavio_timer_irq, s); s->timer = ptimer_init(bh); ptimer_set_period(s->timer, 500ULL); slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, slavio_timer_mem_write, s); - if (mode < 2) + if (master) cpu_register_physical_memory(addr, CPU_TIMER_SIZE, slavio_timer_io_memory); else - cpu_register_physical_memory(addr, TIMER_SIZE, - slavio_timer_io_memory); + cpu_register_physical_memory(addr, SYS_TIMER_SIZE, slavio_timer_io_memory); register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s); qemu_register_reset(slavio_timer_reset, s); slavio_timer_reset(s); @@ -313,11 +331,11 @@ void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, SLAVIO_TIMERState *master; unsigned int i; - master = slavio_timer_init(base + 0x10000ULL, master_irq, 2); + master = slavio_timer_init(base + 0x10000ULL, master_irq, NULL, 0); for (i = 0; i < MAX_CPUS; i++) { master->slave[i] = slavio_timer_init(base + (target_phys_addr_t) (i * TARGET_PAGE_SIZE), - cpu_irqs[i], 0); + cpu_irqs[i], master, i); } } -- cgit v1.2.3 From 008ff9d756fb8e33e7a799e47d03faac503f8b2e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 14:21:26 +0000 Subject: Share devices that might be useful for all PowerPC 40x & 440 implementations (mostly CPU registration and UIC, for now). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3340 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc405.h | 20 +-- hw/ppc405_uc.c | 509 +--------------------------------------------------- hw/ppc4xx.h | 49 +++++ hw/ppc4xx_devs.c | 534 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 587 insertions(+), 525 deletions(-) create mode 100644 hw/ppc4xx.h create mode 100644 hw/ppc4xx_devs.c diff --git a/hw/ppc405.h b/hw/ppc405.h index eacbefedd..e03217016 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -25,6 +25,8 @@ #if !defined(PPC_405_H) #define PPC_405_H +#include "ppc4xx.h" + /* Bootinfo as set-up by u-boot */ typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t; struct ppc4xx_bd_info_t { @@ -54,19 +56,9 @@ struct ppc4xx_bd_info_t { }; /* PowerPC 405 core */ -CPUState *ppc405_init (const unsigned char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk); ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, uint32_t flags); -/* */ -typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; -int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, - target_phys_addr_t offset, uint32_t len, - CPUReadMemoryFunc **mem_read, - CPUWriteMemoryFunc **mem_write, void *opaque); -ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base); /* PowerPC 4xx peripheral local bus arbitrer */ void ppc4xx_plb_init (CPUState *env); /* PLB to OPB bridge */ @@ -74,14 +66,6 @@ void ppc4xx_pob_init (CPUState *env); /* OPB arbitrer */ void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, target_phys_addr_t offset); -/* PowerPC 4xx universal interrupt controller */ -enum { - PPCUIC_OUTPUT_INT = 0, - PPCUIC_OUTPUT_CINT = 1, - PPCUIC_OUTPUT_NB, -}; -qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, - uint32_t dcr_base, int has_ssr, int has_vr); /* SDRAM controller */ void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks, target_phys_addr_t *ram_bases, diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 8a31475ed..55f4bcc3d 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -27,7 +27,6 @@ extern int loglevel; extern FILE *logfile; -//#define DEBUG_MMIO #define DEBUG_OPBA #define DEBUG_SDRAM #define DEBUG_GPIO @@ -36,41 +35,9 @@ extern FILE *logfile; //#define DEBUG_I2C #define DEBUG_GPT #define DEBUG_MAL -#define DEBUG_UIC #define DEBUG_CLOCKS //#define DEBUG_UNASSIGNED -/*****************************************************************************/ -/* Generic PowerPC 405 processor instanciation */ -CPUState *ppc405_init (const unsigned char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk) -{ - CPUState *env; - ppc_def_t *def; - - /* init CPUs */ - env = cpu_init(); - ppc_find_by_name(cpu_model, &def); - if (def == NULL) { - cpu_abort(env, "Unable to find PowerPC %s CPU definition\n", - cpu_model); - } - cpu_ppc_register(env, def); - cpu_ppc_reset(env); - cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ - cpu_clk->opaque = env; - /* Set time-base frequency to sysclk */ - tb_clk->cb = ppc_emb_timers_init(env, sysclk); - tb_clk->opaque = env; - ppc_dcr_init(env, NULL, NULL); - /* Register Qemu callbacks */ - qemu_register_reset(&cpu_ppc_reset, env); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - - return env; -} - ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, uint32_t flags) { @@ -123,203 +90,6 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, /*****************************************************************************/ /* Shared peripherals */ -/*****************************************************************************/ -/* Fake device used to map multiple devices in a single memory page */ -#define MMIO_AREA_BITS 8 -#define MMIO_AREA_LEN (1 << MMIO_AREA_BITS) -#define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS)) -#define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1)) -struct ppc4xx_mmio_t { - target_phys_addr_t base; - CPUReadMemoryFunc **mem_read[MMIO_AREA_NB]; - CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB]; - void *opaque[MMIO_AREA_NB]; -}; - -static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr) -{ -#ifdef DEBUG_UNASSIGNED - ppc4xx_mmio_t *mmio; - - mmio = opaque; - printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n", - addr, mmio->base); -#endif - - return 0; -} - -static void unassigned_mmio_writeb (void *opaque, - target_phys_addr_t addr, uint32_t val) -{ -#ifdef DEBUG_UNASSIGNED - ppc4xx_mmio_t *mmio; - - mmio = opaque; - printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n", - addr, val, mmio->base); -#endif -} - -static CPUReadMemoryFunc *unassigned_mmio_read[3] = { - unassigned_mmio_readb, - unassigned_mmio_readb, - unassigned_mmio_readb, -}; - -static CPUWriteMemoryFunc *unassigned_mmio_write[3] = { - unassigned_mmio_writeb, - unassigned_mmio_writeb, - unassigned_mmio_writeb, -}; - -static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, - target_phys_addr_t addr, int len) -{ - CPUReadMemoryFunc **mem_read; - uint32_t ret; - int idx; - - idx = MMIO_IDX(addr - mmio->base); -#if defined(DEBUG_MMIO) - printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__, - mmio, len, addr, idx); -#endif - mem_read = mmio->mem_read[idx]; - ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base); - - return ret; -} - -static void mmio_writelen (ppc4xx_mmio_t *mmio, - target_phys_addr_t addr, uint32_t value, int len) -{ - CPUWriteMemoryFunc **mem_write; - int idx; - - idx = MMIO_IDX(addr - mmio->base); -#if defined(DEBUG_MMIO) - printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__, - mmio, len, addr, idx, value); -#endif - mem_write = mmio->mem_write[idx]; - (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value); -} - -static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr) -{ -#if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX "\n", __func__, addr); -#endif - - return mmio_readlen(opaque, addr, 0); -} - -static void mmio_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ -#if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); -#endif - mmio_writelen(opaque, addr, value, 0); -} - -static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr) -{ -#if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX "\n", __func__, addr); -#endif - - return mmio_readlen(opaque, addr, 1); -} - -static void mmio_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ -#if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); -#endif - mmio_writelen(opaque, addr, value, 1); -} - -static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr) -{ -#if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX "\n", __func__, addr); -#endif - - return mmio_readlen(opaque, addr, 2); -} - -static void mmio_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ -#if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); -#endif - mmio_writelen(opaque, addr, value, 2); -} - -static CPUReadMemoryFunc *mmio_read[] = { - &mmio_readb, - &mmio_readw, - &mmio_readl, -}; - -static CPUWriteMemoryFunc *mmio_write[] = { - &mmio_writeb, - &mmio_writew, - &mmio_writel, -}; - -int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, - target_phys_addr_t offset, uint32_t len, - CPUReadMemoryFunc **mem_read, - CPUWriteMemoryFunc **mem_write, void *opaque) -{ - uint32_t end; - int idx, eidx; - - if ((offset + len) > TARGET_PAGE_SIZE) - return -1; - idx = MMIO_IDX(offset); - end = offset + len - 1; - eidx = MMIO_IDX(end); -#if defined(DEBUG_MMIO) - printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len, - end, idx, eidx); -#endif - for (; idx <= eidx; idx++) { - mmio->mem_read[idx] = mem_read; - mmio->mem_write[idx] = mem_write; - mmio->opaque[idx] = opaque; - } - - return 0; -} - -ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) -{ - ppc4xx_mmio_t *mmio; - int mmio_memory; - - mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t)); - if (mmio != NULL) { - mmio->base = base; - mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); -#if defined(DEBUG_MMIO) - printf("%s: %p base %08x len %08x %d\n", __func__, - mmio, base, TARGET_PAGE_SIZE, mmio_memory); -#endif - cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); - ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, - unassigned_mmio_read, unassigned_mmio_write, - mmio); - } - - return mmio; -} - /*****************************************************************************/ /* Peripheral local bus arbitrer */ enum { @@ -624,281 +394,6 @@ void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, } } -/*****************************************************************************/ -/* "Universal" Interrupt controller */ -enum { - DCR_UICSR = 0x000, - DCR_UICSRS = 0x001, - DCR_UICER = 0x002, - DCR_UICCR = 0x003, - DCR_UICPR = 0x004, - DCR_UICTR = 0x005, - DCR_UICMSR = 0x006, - DCR_UICVR = 0x007, - DCR_UICVCR = 0x008, - DCR_UICMAX = 0x009, -}; - -#define UIC_MAX_IRQ 32 -typedef struct ppcuic_t ppcuic_t; -struct ppcuic_t { - uint32_t dcr_base; - int use_vectors; - uint32_t uicsr; /* Status register */ - uint32_t uicer; /* Enable register */ - uint32_t uiccr; /* Critical register */ - uint32_t uicpr; /* Polarity register */ - uint32_t uictr; /* Triggering register */ - uint32_t uicvcr; /* Vector configuration register */ - uint32_t uicvr; - qemu_irq *irqs; -}; - -static void ppcuic_trigger_irq (ppcuic_t *uic) -{ - uint32_t ir, cr; - int start, end, inc, i; - - /* Trigger interrupt if any is pending */ - ir = uic->uicsr & uic->uicer & (~uic->uiccr); - cr = uic->uicsr & uic->uicer & uic->uiccr; -#ifdef DEBUG_UIC - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n" - " %08x ir %08x cr %08x\n", __func__, - uic->uicsr, uic->uicer, uic->uiccr, - uic->uicsr & uic->uicer, ir, cr); - } -#endif - if (ir != 0x0000000) { -#ifdef DEBUG_UIC - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Raise UIC interrupt\n"); - } -#endif - qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); - } else { -#ifdef DEBUG_UIC - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Lower UIC interrupt\n"); - } -#endif - qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); - } - /* Trigger critical interrupt if any is pending and update vector */ - if (cr != 0x0000000) { - qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); - if (uic->use_vectors) { - /* Compute critical IRQ vector */ - if (uic->uicvcr & 1) { - start = 31; - end = 0; - inc = -1; - } else { - start = 0; - end = 31; - inc = 1; - } - uic->uicvr = uic->uicvcr & 0xFFFFFFFC; - for (i = start; i <= end; i += inc) { - if (cr & (1 << i)) { - uic->uicvr += (i - start) * 512 * inc; - break; - } - } - } -#ifdef DEBUG_UIC - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n", - uic->uicvr); - } -#endif - } else { -#ifdef DEBUG_UIC - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Lower UIC critical interrupt\n"); - } -#endif - qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); - uic->uicvr = 0x00000000; - } -} - -static void ppcuic_set_irq (void *opaque, int irq_num, int level) -{ - ppcuic_t *uic; - uint32_t mask, sr; - - uic = opaque; - mask = 1 << irq_num; -#ifdef DEBUG_UIC - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x " - "%08x\n", __func__, irq_num, level, - uic->uicsr, mask, uic->uicsr & mask, level << irq_num); - } -#endif - if (irq_num < 0 || irq_num > 31) - return; - sr = uic->uicsr; - if (!(uic->uicpr & mask)) { - /* Negatively asserted IRQ */ - level = level == 0 ? 1 : 0; - } - /* Update status register */ - if (uic->uictr & mask) { - /* Edge sensitive interrupt */ - if (level == 1) - uic->uicsr |= mask; - } else { - /* Level sensitive interrupt */ - if (level == 1) - uic->uicsr |= mask; - else - uic->uicsr &= ~mask; - } -#ifdef DEBUG_UIC - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__, - irq_num, level, uic->uicsr, sr); - } -#endif - if (sr != uic->uicsr) - ppcuic_trigger_irq(uic); -} - -static target_ulong dcr_read_uic (void *opaque, int dcrn) -{ - ppcuic_t *uic; - target_ulong ret; - - uic = opaque; - dcrn -= uic->dcr_base; - switch (dcrn) { - case DCR_UICSR: - case DCR_UICSRS: - ret = uic->uicsr; - break; - case DCR_UICER: - ret = uic->uicer; - break; - case DCR_UICCR: - ret = uic->uiccr; - break; - case DCR_UICPR: - ret = uic->uicpr; - break; - case DCR_UICTR: - ret = uic->uictr; - break; - case DCR_UICMSR: - ret = uic->uicsr & uic->uicer; - break; - case DCR_UICVR: - if (!uic->use_vectors) - goto no_read; - ret = uic->uicvr; - break; - case DCR_UICVCR: - if (!uic->use_vectors) - goto no_read; - ret = uic->uicvcr; - break; - default: - no_read: - ret = 0x00000000; - break; - } - - return ret; -} - -static void dcr_write_uic (void *opaque, int dcrn, target_ulong val) -{ - ppcuic_t *uic; - - uic = opaque; - dcrn -= uic->dcr_base; -#ifdef DEBUG_UIC - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val); - } -#endif - switch (dcrn) { - case DCR_UICSR: - uic->uicsr &= ~val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICSRS: - uic->uicsr |= val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICER: - uic->uicer = val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICCR: - uic->uiccr = val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICPR: - uic->uicpr = val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICTR: - uic->uictr = val; - ppcuic_trigger_irq(uic); - break; - case DCR_UICMSR: - break; - case DCR_UICVR: - break; - case DCR_UICVCR: - uic->uicvcr = val & 0xFFFFFFFD; - ppcuic_trigger_irq(uic); - break; - } -} - -static void ppcuic_reset (void *opaque) -{ - ppcuic_t *uic; - - uic = opaque; - uic->uiccr = 0x00000000; - uic->uicer = 0x00000000; - uic->uicpr = 0x00000000; - uic->uicsr = 0x00000000; - uic->uictr = 0x00000000; - if (uic->use_vectors) { - uic->uicvcr = 0x00000000; - uic->uicvr = 0x0000000; - } -} - -qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, - uint32_t dcr_base, int has_ssr, int has_vr) -{ - ppcuic_t *uic; - int i; - - uic = qemu_mallocz(sizeof(ppcuic_t)); - if (uic != NULL) { - uic->dcr_base = dcr_base; - uic->irqs = irqs; - if (has_vr) - uic->use_vectors = 1; - for (i = 0; i < DCR_UICMAX; i++) { - ppc_dcr_register(env, dcr_base + i, uic, - &dcr_read_uic, &dcr_write_uic); - } - qemu_register_reset(ppcuic_reset, uic); - ppcuic_reset(uic); - } - - return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); -} - /*****************************************************************************/ /* Code decompression controller */ /* XXX: TODO */ @@ -3040,7 +2535,7 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4], int i; memset(clk_setup, 0, sizeof(clk_setup)); - env = ppc405_init("405cr", &clk_setup[PPC405CR_CPU_CLK], + env = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], &clk_setup[PPC405CR_TMR_CLK], sysclk); /* Memory mapped devices registers */ mmio = ppc4xx_mmio_init(env, 0xEF600000); @@ -3390,7 +2885,7 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2], memset(clk_setup, 0, sizeof(clk_setup)); /* init CPUs */ - env = ppc405_init("405ep", &clk_setup[PPC405EP_CPU_CLK], + env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], &tlb_clk_setup, sysclk); clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h new file mode 100644 index 000000000..8d7863c14 --- /dev/null +++ b/hw/ppc4xx.h @@ -0,0 +1,49 @@ +/* + * QEMU PowerPC 4xx emulation shared definitions + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if !defined(PPC_4XX_H) +#define PPC_4XX_H + +/* PowerPC 4xx core initialization */ +CPUState *ppc4xx_init (const unsigned char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk); + +typedef struct ppc4xx_mmio_t ppc4xx_mmio_t; +int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset, uint32_t len, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, void *opaque); +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base); + +/* PowerPC 4xx universal interrupt controller */ +enum { + PPCUIC_OUTPUT_INT = 0, + PPCUIC_OUTPUT_CINT = 1, + PPCUIC_OUTPUT_NB, +}; +qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, + uint32_t dcr_base, int has_ssr, int has_vr); + +#endif /* !defined(PPC_4XX_H) */ diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c new file mode 100644 index 000000000..8cefd7470 --- /dev/null +++ b/hw/ppc4xx_devs.c @@ -0,0 +1,534 @@ +/* + * QEMU PowerPC 4xx embedded processors shared devices emulation + * + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "ppc4xx.h" + +extern int loglevel; +extern FILE *logfile; + +//#define DEBUG_MMIO +#define DEBUG_UIC + +/*****************************************************************************/ +/* Generic PowerPC 4xx processor instanciation */ +CPUState *ppc4xx_init (const unsigned char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk) +{ + CPUState *env; + ppc_def_t *def; + + /* init CPUs */ + env = cpu_init(); + ppc_find_by_name(cpu_model, &def); + if (def == NULL) { + cpu_abort(env, "Unable to find PowerPC %s CPU definition\n", + cpu_model); + } + cpu_ppc_register(env, def); + cpu_ppc_reset(env); + cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ + cpu_clk->opaque = env; + /* Set time-base frequency to sysclk */ + tb_clk->cb = ppc_emb_timers_init(env, sysclk); + tb_clk->opaque = env; + ppc_dcr_init(env, NULL, NULL); + /* Register qemu callbacks */ + qemu_register_reset(&cpu_ppc_reset, env); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + + return env; +} + +/*****************************************************************************/ +/* Fake device used to map multiple devices in a single memory page */ +#define MMIO_AREA_BITS 8 +#define MMIO_AREA_LEN (1 << MMIO_AREA_BITS) +#define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS)) +#define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1)) +struct ppc4xx_mmio_t { + target_phys_addr_t base; + CPUReadMemoryFunc **mem_read[MMIO_AREA_NB]; + CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB]; + void *opaque[MMIO_AREA_NB]; +}; + +static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr) +{ +#ifdef DEBUG_UNASSIGNED + ppc4xx_mmio_t *mmio; + + mmio = opaque; + printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n", + addr, mmio->base); +#endif + + return 0; +} + +static void unassigned_mmio_writeb (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ +#ifdef DEBUG_UNASSIGNED + ppc4xx_mmio_t *mmio; + + mmio = opaque; + printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n", + addr, val, mmio->base); +#endif +} + +static CPUReadMemoryFunc *unassigned_mmio_read[3] = { + unassigned_mmio_readb, + unassigned_mmio_readb, + unassigned_mmio_readb, +}; + +static CPUWriteMemoryFunc *unassigned_mmio_write[3] = { + unassigned_mmio_writeb, + unassigned_mmio_writeb, + unassigned_mmio_writeb, +}; + +static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, + target_phys_addr_t addr, int len) +{ + CPUReadMemoryFunc **mem_read; + uint32_t ret; + int idx; + + idx = MMIO_IDX(addr - mmio->base); +#if defined(DEBUG_MMIO) + printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__, + mmio, len, addr, idx); +#endif + mem_read = mmio->mem_read[idx]; + ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base); + + return ret; +} + +static void mmio_writelen (ppc4xx_mmio_t *mmio, + target_phys_addr_t addr, uint32_t value, int len) +{ + CPUWriteMemoryFunc **mem_write; + int idx; + + idx = MMIO_IDX(addr - mmio->base); +#if defined(DEBUG_MMIO) + printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__, + mmio, len, addr, idx, value); +#endif + mem_write = mmio->mem_write[idx]; + (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value); +} + +static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return mmio_readlen(opaque, addr, 0); +} + +static void mmio_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + mmio_writelen(opaque, addr, value, 0); +} + +static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return mmio_readlen(opaque, addr, 1); +} + +static void mmio_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + mmio_writelen(opaque, addr, value, 1); +} + +static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX "\n", __func__, addr); +#endif + + return mmio_readlen(opaque, addr, 2); +} + +static void mmio_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +#if defined(DEBUG_MMIO) + printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); +#endif + mmio_writelen(opaque, addr, value, 2); +} + +static CPUReadMemoryFunc *mmio_read[] = { + &mmio_readb, + &mmio_readw, + &mmio_readl, +}; + +static CPUWriteMemoryFunc *mmio_write[] = { + &mmio_writeb, + &mmio_writew, + &mmio_writel, +}; + +int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, + target_phys_addr_t offset, uint32_t len, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, void *opaque) +{ + uint32_t end; + int idx, eidx; + + if ((offset + len) > TARGET_PAGE_SIZE) + return -1; + idx = MMIO_IDX(offset); + end = offset + len - 1; + eidx = MMIO_IDX(end); +#if defined(DEBUG_MMIO) + printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len, + end, idx, eidx); +#endif + for (; idx <= eidx; idx++) { + mmio->mem_read[idx] = mem_read; + mmio->mem_write[idx] = mem_write; + mmio->opaque[idx] = opaque; + } + + return 0; +} + +ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) +{ + ppc4xx_mmio_t *mmio; + int mmio_memory; + + mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t)); + if (mmio != NULL) { + mmio->base = base; + mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); +#if defined(DEBUG_MMIO) + printf("%s: %p base %08x len %08x %d\n", __func__, + mmio, base, TARGET_PAGE_SIZE, mmio_memory); +#endif + cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); + ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, + unassigned_mmio_read, unassigned_mmio_write, + mmio); + } + + return mmio; +} + +/*****************************************************************************/ +/* "Universal" Interrupt controller */ +enum { + DCR_UICSR = 0x000, + DCR_UICSRS = 0x001, + DCR_UICER = 0x002, + DCR_UICCR = 0x003, + DCR_UICPR = 0x004, + DCR_UICTR = 0x005, + DCR_UICMSR = 0x006, + DCR_UICVR = 0x007, + DCR_UICVCR = 0x008, + DCR_UICMAX = 0x009, +}; + +#define UIC_MAX_IRQ 32 +typedef struct ppcuic_t ppcuic_t; +struct ppcuic_t { + uint32_t dcr_base; + int use_vectors; + uint32_t uicsr; /* Status register */ + uint32_t uicer; /* Enable register */ + uint32_t uiccr; /* Critical register */ + uint32_t uicpr; /* Polarity register */ + uint32_t uictr; /* Triggering register */ + uint32_t uicvcr; /* Vector configuration register */ + uint32_t uicvr; + qemu_irq *irqs; +}; + +static void ppcuic_trigger_irq (ppcuic_t *uic) +{ + uint32_t ir, cr; + int start, end, inc, i; + + /* Trigger interrupt if any is pending */ + ir = uic->uicsr & uic->uicer & (~uic->uiccr); + cr = uic->uicsr & uic->uicer & uic->uiccr; +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n" + " %08x ir %08x cr %08x\n", __func__, + uic->uicsr, uic->uicer, uic->uiccr, + uic->uicsr & uic->uicer, ir, cr); + } +#endif + if (ir != 0x0000000) { +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Raise UIC interrupt\n"); + } +#endif + qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); + } else { +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Lower UIC interrupt\n"); + } +#endif + qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); + } + /* Trigger critical interrupt if any is pending and update vector */ + if (cr != 0x0000000) { + qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); + if (uic->use_vectors) { + /* Compute critical IRQ vector */ + if (uic->uicvcr & 1) { + start = 31; + end = 0; + inc = -1; + } else { + start = 0; + end = 31; + inc = 1; + } + uic->uicvr = uic->uicvcr & 0xFFFFFFFC; + for (i = start; i <= end; i += inc) { + if (cr & (1 << i)) { + uic->uicvr += (i - start) * 512 * inc; + break; + } + } + } +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n", + uic->uicvr); + } +#endif + } else { +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "Lower UIC critical interrupt\n"); + } +#endif + qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); + uic->uicvr = 0x00000000; + } +} + +static void ppcuic_set_irq (void *opaque, int irq_num, int level) +{ + ppcuic_t *uic; + uint32_t mask, sr; + + uic = opaque; + mask = 1 << irq_num; +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x " + "%08x\n", __func__, irq_num, level, + uic->uicsr, mask, uic->uicsr & mask, level << irq_num); + } +#endif + if (irq_num < 0 || irq_num > 31) + return; + sr = uic->uicsr; + if (!(uic->uicpr & mask)) { + /* Negatively asserted IRQ */ + level = level == 0 ? 1 : 0; + } + /* Update status register */ + if (uic->uictr & mask) { + /* Edge sensitive interrupt */ + if (level == 1) + uic->uicsr |= mask; + } else { + /* Level sensitive interrupt */ + if (level == 1) + uic->uicsr |= mask; + else + uic->uicsr &= ~mask; + } +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__, + irq_num, level, uic->uicsr, sr); + } +#endif + if (sr != uic->uicsr) + ppcuic_trigger_irq(uic); +} + +static target_ulong dcr_read_uic (void *opaque, int dcrn) +{ + ppcuic_t *uic; + target_ulong ret; + + uic = opaque; + dcrn -= uic->dcr_base; + switch (dcrn) { + case DCR_UICSR: + case DCR_UICSRS: + ret = uic->uicsr; + break; + case DCR_UICER: + ret = uic->uicer; + break; + case DCR_UICCR: + ret = uic->uiccr; + break; + case DCR_UICPR: + ret = uic->uicpr; + break; + case DCR_UICTR: + ret = uic->uictr; + break; + case DCR_UICMSR: + ret = uic->uicsr & uic->uicer; + break; + case DCR_UICVR: + if (!uic->use_vectors) + goto no_read; + ret = uic->uicvr; + break; + case DCR_UICVCR: + if (!uic->use_vectors) + goto no_read; + ret = uic->uicvcr; + break; + default: + no_read: + ret = 0x00000000; + break; + } + + return ret; +} + +static void dcr_write_uic (void *opaque, int dcrn, target_ulong val) +{ + ppcuic_t *uic; + + uic = opaque; + dcrn -= uic->dcr_base; +#ifdef DEBUG_UIC + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val); + } +#endif + switch (dcrn) { + case DCR_UICSR: + uic->uicsr &= ~val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICSRS: + uic->uicsr |= val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICER: + uic->uicer = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICCR: + uic->uiccr = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICPR: + uic->uicpr = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICTR: + uic->uictr = val; + ppcuic_trigger_irq(uic); + break; + case DCR_UICMSR: + break; + case DCR_UICVR: + break; + case DCR_UICVCR: + uic->uicvcr = val & 0xFFFFFFFD; + ppcuic_trigger_irq(uic); + break; + } +} + +static void ppcuic_reset (void *opaque) +{ + ppcuic_t *uic; + + uic = opaque; + uic->uiccr = 0x00000000; + uic->uicer = 0x00000000; + uic->uicpr = 0x00000000; + uic->uicsr = 0x00000000; + uic->uictr = 0x00000000; + if (uic->use_vectors) { + uic->uicvcr = 0x00000000; + uic->uicvr = 0x0000000; + } +} + +qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, + uint32_t dcr_base, int has_ssr, int has_vr) +{ + ppcuic_t *uic; + int i; + + uic = qemu_mallocz(sizeof(ppcuic_t)); + if (uic != NULL) { + uic->dcr_base = dcr_base; + uic->irqs = irqs; + if (has_vr) + uic->use_vectors = 1; + for (i = 0; i < DCR_UICMAX; i++) { + ppc_dcr_register(env, dcr_base + i, uic, + &dcr_read_uic, &dcr_write_uic); + } + qemu_register_reset(ppcuic_reset, uic); + ppcuic_reset(uic); + } + + return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); +} -- cgit v1.2.3 From 7875ed20d7d39496c5e5e6bd85ced79e019bbe65 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 14:25:11 +0000 Subject: Share devices that may be useful for all PowerPC 40x and 440 implementations. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3341 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 58219ba97..6445a7ba4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -448,7 +448,9 @@ 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 pflash_cfi02.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 ppc405_uc.o ppc405_boards.o +VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o +# PowerPC 4xx boards +VL_OBJS+= ppc4xx_devs.o ppc405_uc.o ppc405_boards.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif ifeq ($(TARGET_BASE_ARCH), mips) -- cgit v1.2.3 From d26bfc9a1b449db84b80d39ed9d870671a944e5c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 14:41:00 +0000 Subject: Add MSR bits signification per PowerPC implementation flags (to be continued). As a side effect, single step and branch step are available again. Remove irrelevant MSR bits definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3342 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 67 +++++++++++++++++++++++++++++---------------- target-ppc/helper.c | 24 ++++++---------- target-ppc/translate.c | 50 ++++++++++++++++++--------------- target-ppc/translate_init.c | 42 ++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 61 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 5824526be..8a24d4d06 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -347,40 +347,37 @@ union ppc_tlb_t { #define MSR_CM 31 /* Computation mode for BookE hflags */ #define MSR_ICM 30 /* Interrupt computation mode for BookE */ #define MSR_UCLE 26 /* User-mode cache lock enable for BookE */ -#define MSR_VR 25 /* altivec available hflags */ -#define MSR_SPE 25 /* SPE enable for BookE hflags */ +#define MSR_VR 25 /* altivec available x hflags */ +#define MSR_SPE 25 /* SPE enable for BookE x hflags */ #define MSR_AP 23 /* Access privilege state on 602 hflags */ #define MSR_SA 22 /* Supervisor access mode on 602 hflags */ #define MSR_KEY 19 /* key bit on 603e */ -#define MSR_POW 18 /* Power management */ -#define MSR_WE 18 /* Wait state enable on embedded PowerPC */ -#define MSR_TGPR 17 /* TGPR usage on 602/603 */ -#define MSR_TLB 17 /* TLB update on ? */ -#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC */ +#define MSR_POW 18 /* Power management x */ +#define MSR_WE 18 /* Wait state enable on embedded PowerPC x */ +#define MSR_TGPR 17 /* TGPR usage on 602/603 x */ +#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */ #define MSR_ILE 16 /* Interrupt little-endian mode */ #define MSR_EE 15 /* External interrupt enable */ #define MSR_PR 14 /* Problem state hflags */ #define MSR_FP 13 /* Floating point available hflags */ #define MSR_ME 12 /* Machine check interrupt enable */ #define MSR_FE0 11 /* Floating point exception mode 0 hflags */ -#define MSR_SE 10 /* Single-step trace enable hflags */ -#define MSR_DWE 10 /* Debug wait enable on 405 */ -#define MSR_UBLE 10 /* User BTB lock enable on e500 */ -#define MSR_BE 9 /* Branch trace enable hflags */ -#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC */ +#define MSR_SE 10 /* Single-step trace enable x hflags */ +#define MSR_DWE 10 /* Debug wait enable on 405 x */ +#define MSR_UBLE 10 /* User BTB lock enable on e500 x */ +#define MSR_BE 9 /* Branch trace enable x hflags */ +#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */ #define MSR_FE1 8 /* Floating point exception mode 1 hflags */ #define MSR_AL 7 /* AL bit on POWER */ #define MSR_IP 6 /* Interrupt prefix */ #define MSR_IR 5 /* Instruction relocate */ -#define MSR_IS 5 /* Instruction address space on embedded PowerPC */ #define MSR_DR 4 /* Data relocate */ -#define MSR_DS 4 /* Data address space on embedded PowerPC */ -#define MSR_PE 3 /* Protection enable on 403 */ -#define MSR_EP 3 /* Exception prefix on 601 */ -#define MSR_PX 2 /* Protection exclusive on 403 */ -#define MSR_PMM 2 /* Performance monitor mark on POWER */ -#define MSR_RI 1 /* Recoverable interrupt */ -#define MSR_LE 0 /* Little-endian mode hflags */ +#define MSR_PE 3 /* Protection enable on 403 x */ +#define MSR_EP 3 /* Exception prefix on 601 x */ +#define MSR_PX 2 /* Protection exclusive on 403 x */ +#define MSR_PMM 2 /* Performance monitor mark on POWER x */ +#define MSR_RI 1 /* Recoverable interrupt 1 */ +#define MSR_LE 0 /* Little-endian mode 1 hflags */ #define msr_sf env->msr[MSR_SF] #define msr_isf env->msr[MSR_ISF] #define msr_hv env->msr[MSR_HV] @@ -395,7 +392,6 @@ union ppc_tlb_t { #define msr_pow env->msr[MSR_POW] #define msr_we env->msr[MSR_WE] #define msr_tgpr env->msr[MSR_TGPR] -#define msr_tlb env->msr[MSR_TLB] #define msr_ce env->msr[MSR_CE] #define msr_ile env->msr[MSR_ILE] #define msr_ee env->msr[MSR_EE] @@ -412,9 +408,7 @@ union ppc_tlb_t { #define msr_al env->msr[MSR_AL] #define msr_ip env->msr[MSR_IP] #define msr_ir env->msr[MSR_IR] -#define msr_is env->msr[MSR_IS] #define msr_dr env->msr[MSR_DR] -#define msr_ds env->msr[MSR_DS] #define msr_pe env->msr[MSR_PE] #define msr_ep env->msr[MSR_EP] #define msr_px env->msr[MSR_PX] @@ -422,6 +416,33 @@ union ppc_tlb_t { #define msr_ri env->msr[MSR_RI] #define msr_le env->msr[MSR_LE] +enum { + /* Beware that MSR bits are given using IBM standard (ie MSB is 0 !) */ + POWERPC_FLAG_NONE = 0x00000000, + /* Flag for MSR bit 25 signification (VRE/SPE) */ + POWERPC_FLAG_SPE = 0x00000001, + POWERPC_FLAG_VRE = 0x00000002, + /* Flag for MSR bit 18 may not be needed... */ + POWERPC_FLAG_POW = 0x00000004, + POWERPC_FLAG_WE = 0x00000008, + /* Flag for MSR bit 17 signification (TGPR/CE) */ + POWERPC_FLAG_TGPR = 0x00000010, + POWERPC_FLAG_CE = 0x00000020, + /* Flag for MSR bit 10 signification (SE/DWE/UBLE) */ + POWERPC_FLAG_SE = 0x00000040, + POWERPC_FLAG_DWE = 0x00000080, + POWERPC_FLAG_UBLE = 0x00000100, + /* Flag for MSR bit 9 signification (BE/DE) */ + POWERPC_FLAG_BE = 0x00000200, + POWERPC_FLAG_DE = 0x00000400, + /* Flag for MSR bit 3 signification (PE/EP) */ + POWERPC_FLAG_PE = 0x00000800, + POWERPC_FLAG_EP = 0x00001000, + /* Flag for MSR but 2 signification (PX/PMM) */ + POWERPC_FLAG_PX = 0x00002000, + POWERPC_FLAG_PMM = 0x00004000, +}; + /*****************************************************************************/ /* The whole PowerPC CPU context */ struct CPUPPCState { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index bb39fc05f..f1fe6806c 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1183,7 +1183,7 @@ int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, prot = (tlb->prot >> 4) & 0xF; /* Check the address space */ if (access_type == ACCESS_CODE) { - if (msr_is != (tlb->attr & 1)) + if (msr_ir != (tlb->attr & 1)) continue; ctx->prot = prot; if (prot & PAGE_EXEC) { @@ -1192,7 +1192,7 @@ int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } ret = -3; } else { - if (msr_ds != (tlb->attr & 1)) + if (msr_dr != (tlb->attr & 1)) continue; ctx->prot = prot; if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) { @@ -1964,7 +1964,7 @@ target_ulong do_load_msr (CPUPPCState *env) ((target_ulong)msr_sa << MSR_SA) | ((target_ulong)msr_key << MSR_KEY) | ((target_ulong)msr_pow << MSR_POW) | /* POW / WE */ - ((target_ulong)msr_tlb << MSR_TLB) | /* TLB / TGPE / CE */ + ((target_ulong)msr_tgpr << MSR_TGPR) | /* TGPR / CE */ ((target_ulong)msr_ile << MSR_ILE) | ((target_ulong)msr_ee << MSR_EE) | ((target_ulong)msr_pr << MSR_PR) | @@ -2000,18 +2000,10 @@ int do_store_msr (CPUPPCState *env, target_ulong value) fprintf(logfile, "%s: T0 %08lx\n", __func__, value); } #endif - switch (env->excp_model) { - case POWERPC_EXCP_602: - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - if (((value >> MSR_TGPR) & 1) != msr_tgpr) { - /* Swap temporary saved registers with GPRs */ - swap_gpr_tgpr(env); - } - break; - default: - break; + if (unlikely((env->flags & POWERPC_FLAG_TGPR) && + ((value >> MSR_TGPR) & 1) != msr_tgpr)) { + /* Swap temporary saved registers with GPRs */ + swap_gpr_tgpr(env); } #if defined (TARGET_PPC64) msr_sf = (value >> MSR_SF) & 1; @@ -2024,7 +2016,7 @@ int do_store_msr (CPUPPCState *env, target_ulong value) msr_sa = (value >> MSR_SA) & 1; msr_key = (value >> MSR_KEY) & 1; msr_pow = (value >> MSR_POW) & 1; /* POW / WE */ - msr_tlb = (value >> MSR_TLB) & 1; /* TLB / TGPR / CE */ + msr_tgpr = (value >> MSR_TGPR) & 1; /* TGPR / CE */ msr_ile = (value >> MSR_ILE) & 1; msr_ee = (value >> MSR_EE) & 1; msr_pr = (value >> MSR_PR) & 1; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index bc6336b0c..f30cb411f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6514,6 +6514,7 @@ static inline int gen_intermediate_code_internal (CPUState *env, target_ulong pc_start; uint16_t *gen_opc_end; int supervisor; + int single_step, branch_step; int j, lj = -1; pc_start = tb->pc; @@ -6545,9 +6546,20 @@ static inline int gen_intermediate_code_internal (CPUState *env, ctx.dcache_line_size = env->dcache_line_size; ctx.fpu_enabled = msr_fp; #if defined(TARGET_PPCEMB) - ctx.spe_enabled = msr_spe; + if (env->flags & POWERPC_FLAG_SPE) + ctx.spe_enabled = msr_spe; + else + ctx.spe_enabled = 0; #endif - ctx.singlestep_enabled = env->singlestep_enabled; + if ((env->flags & POWERPC_FLAG_SE) && msr_se) + single_step = 1; + else + single_step = 0; + if ((env->flags & POWERPC_FLAG_BE) && msr_be) + branch_step = 1; + else + branch_step = 0; + ctx.singlestep_enabled = env->singlestep_enabled || single_step == 1;; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; @@ -6642,30 +6654,24 @@ static inline int gen_intermediate_code_internal (CPUState *env, handler->count++; #endif /* Check trace mode exceptions */ -#if 0 // XXX: buggy on embedded PowerPC - if (unlikely((msr_be && ctx.exception == POWERPC_EXCP_BRANCH) || - /* Check in single step trace mode - * we need to stop except if: - * - rfi, trap or syscall - * - first instruction of an exception handler - */ - (msr_se && (ctx.nip < 0x100 || - ctx.nip > 0xF00 || - (ctx.nip & 0xFC) != 0x04) && + if (unlikely(branch_step != 0 && + ctx.exception == POWERPC_EXCP_BRANCH)) { + GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); + } else if (unlikely(single_step != 0 && + (ctx.nip <= 0x100 || ctx.nip > 0xF00 || + (ctx.nip & 0xFC) != 0x04) && #if defined(CONFIG_USER_ONLY) - ctx.exception != POWERPC_EXCP_SYSCALL_USER && + ctx.exception != POWERPC_EXCP_SYSCALL_USER && #else - ctx.exception != POWERPC_EXCP_SYSCALL && + ctx.exception != POWERPC_EXCP_SYSCALL && #endif - ctx.exception != POWERPC_EXCP_TRAP))) { + ctx.exception != POWERPC_EXCP_TRAP)) { GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); - } -#endif - /* if we reach a page boundary or are single stepping, stop - * generation - */ - if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || - (env->singlestep_enabled))) { + } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || + (env->singlestep_enabled))) { + /* if we reach a page boundary or are single stepping, stop + * generation + */ break; } #if defined (DO_SINGLE_STEP) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 8bc6209df..296727e76 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -39,6 +39,7 @@ struct ppc_def_t { uint8_t excp_model; uint8_t bus_model; uint8_t pad; + uint32_t flags; int bfd_mach; void (*init_proc)(CPUPPCState *env); }; @@ -2581,6 +2582,7 @@ static void init_excp_970 (CPUPPCState *env) #define POWERPC_EXCP_401 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401 (bfd_mach_ppc_403) +#define POWERPC_FLAG_401 (POWERPC_FLAG_NONE) static void init_proc_401 (CPUPPCState *env) { @@ -2605,6 +2607,7 @@ static void init_proc_401 (CPUPPCState *env) #define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) +#define POWERPC_FLAG_401x2 (POWERPC_FLAG_NONE) static void init_proc_401x2 (CPUPPCState *env) { @@ -2634,6 +2637,7 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) +#define POWERPC_FLAG_401x3 (POWERPC_FLAG_NONE) __attribute__ (( unused )) static void init_proc_401x3 (CPUPPCState *env) @@ -2661,6 +2665,7 @@ static void init_proc_401x3 (CPUPPCState *env) #define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) #define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) +#define POWERPC_FLAG_IOP480 (POWERPC_FLAG_NONE) static void init_proc_IOP480 (CPUPPCState *env) { @@ -2689,6 +2694,7 @@ static void init_proc_IOP480 (CPUPPCState *env) #define POWERPC_EXCP_403 (POWERPC_EXCP_40x) #define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403 (bfd_mach_ppc_403) +#define POWERPC_FLAG_403 (POWERPC_FLAG_NONE) static void init_proc_403 (CPUPPCState *env) { @@ -2717,6 +2723,7 @@ static void init_proc_403 (CPUPPCState *env) #define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) #define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) +#define POWERPC_FLAG_403GCX (POWERPC_FLAG_NONE) static void init_proc_403GCX (CPUPPCState *env) { @@ -2758,6 +2765,7 @@ static void init_proc_403GCX (CPUPPCState *env) #define POWERPC_EXCP_405 (POWERPC_EXCP_40x) #define POWERPC_INPUT_405 (PPC_FLAGS_INPUT_405) #define POWERPC_BFDM_405 (bfd_mach_ppc_403) +#define POWERPC_FLAG_405 (POWERPC_FLAG_NONE) static void init_proc_405 (CPUPPCState *env) { @@ -2797,6 +2805,7 @@ static void init_proc_405 (CPUPPCState *env) #define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440EP (bfd_mach_ppc_403) +#define POWERPC_FLAG_440EP (POWERPC_FLAG_NONE) static void init_proc_440EP (CPUPPCState *env) { @@ -2842,6 +2851,7 @@ static void init_proc_440EP (CPUPPCState *env) #define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440GP (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440GP (bfd_mach_ppc_403) +#define POWERPC_FLAG_440GP (POWERPC_FLAG_NONE) static void init_proc_440GP (CPUPPCState *env) { @@ -2869,6 +2879,7 @@ static void init_proc_440GP (CPUPPCState *env) #define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) +#define POWERPC_FLAG_440x4 (POWERPC_FLAG_NONE) __attribute__ (( unused )) static void init_proc_440x4 (CPUPPCState *env) @@ -2897,6 +2908,7 @@ static void init_proc_440x4 (CPUPPCState *env) #define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440x5 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) +#define POWERPC_FLAG_440x5 (POWERPC_FLAG_NONE) static void init_proc_440x5 (CPUPPCState *env) { @@ -2942,6 +2954,7 @@ static void init_proc_440x5 (CPUPPCState *env) #define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460 (bfd_mach_ppc_403) +#define POWERPC_FLAG_460 (POWERPC_FLAG_NONE) __attribute__ (( unused )) static void init_proc_460 (CPUPPCState *env) @@ -2996,6 +3009,7 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460F (bfd_mach_ppc_403) +#define POWERPC_FLAG_460F (POWERPC_FLAG_NONE) __attribute__ (( unused )) static void init_proc_460F (CPUPPCState *env) @@ -3050,6 +3064,7 @@ static void init_proc_460F (CPUPPCState *env) #define POWERPC_EXCP_BookE (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_BookE (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_BookE (bfd_mach_ppc_403) +#define POWERPC_FLAG_BookE (POWERPC_FLAG_NONE) __attribute__ (( unused )) static void init_proc_BookE (CPUPPCState *env) @@ -3072,6 +3087,7 @@ static void init_proc_BookE (CPUPPCState *env) #define POWERPC_EXCP_e500 (POWERPC_EXCP_40x) #define POWERPC_INPUT_e500 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_e500 (bfd_mach_ppc_403) +#define POWERPC_FLAG_e500 (POWERPC_FLAG_SPE) __attribute__ (( unused )) static void init_proc_e500 (CPUPPCState *env) @@ -3118,6 +3134,7 @@ static void init_proc_e500 (CPUPPCState *env) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_601 (bfd_mach_ppc_601) +#define POWERPC_FLAG_601 (POWERPC_FLAG_NONE) static void init_proc_601 (CPUPPCState *env) { @@ -3171,6 +3188,7 @@ static void init_proc_601 (CPUPPCState *env) //#define POWERPC_EXCP_602 (POWERPC_EXCP_602) #define POWERPC_INPUT_602 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_602 (bfd_mach_ppc_602) +#define POWERPC_FLAG_602 (POWERPC_FLAG_TGPR) static void init_proc_602 (CPUPPCState *env) { @@ -3206,6 +3224,7 @@ static void init_proc_602 (CPUPPCState *env) //#define POWERPC_EXCP_603 (POWERPC_EXCP_603) #define POWERPC_INPUT_603 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_603 (bfd_mach_ppc_603) +#define POWERPC_FLAG_603 (POWERPC_FLAG_TGPR) static void init_proc_603 (CPUPPCState *env) { @@ -3241,6 +3260,7 @@ static void init_proc_603 (CPUPPCState *env) //#define POWERPC_EXCP_603E (POWERPC_EXCP_603E) #define POWERPC_INPUT_603E (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_603E (bfd_mach_ppc_ec603e) +#define POWERPC_FLAG_603E (POWERPC_FLAG_TGPR) static void init_proc_603E (CPUPPCState *env) { @@ -3281,6 +3301,7 @@ static void init_proc_603E (CPUPPCState *env) //#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) #define POWERPC_INPUT_G2 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) +#define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR) static void init_proc_G2 (CPUPPCState *env) { @@ -3323,6 +3344,7 @@ static void init_proc_G2 (CPUPPCState *env) #define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) #define POWERPC_INPUT_G2LE (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) +#define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR) static void init_proc_G2LE (CPUPPCState *env) { @@ -3365,6 +3387,7 @@ static void init_proc_G2LE (CPUPPCState *env) //#define POWERPC_EXCP_604 (POWERPC_EXCP_604) #define POWERPC_INPUT_604 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_604 (bfd_mach_ppc_604) +#define POWERPC_FLAG_604 (POWERPC_FLAG_NONE) static void init_proc_604 (CPUPPCState *env) { @@ -3399,6 +3422,7 @@ static void init_proc_604 (CPUPPCState *env) //#define POWERPC_EXCP_7x0 (POWERPC_EXCP_7x0) #define POWERPC_INPUT_7x0 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7x0 (bfd_mach_ppc_750) +#define POWERPC_FLAG_7x0 (POWERPC_FLAG_NONE) static void init_proc_7x0 (CPUPPCState *env) { @@ -3435,6 +3459,7 @@ static void init_proc_7x0 (CPUPPCState *env) #define POWERPC_EXCP_750fx (POWERPC_EXCP_7x0) #define POWERPC_INPUT_750fx (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_750fx (bfd_mach_ppc_750) +#define POWERPC_FLAG_750fx (POWERPC_FLAG_NONE) static void init_proc_750fx (CPUPPCState *env) { @@ -3478,6 +3503,7 @@ static void init_proc_750fx (CPUPPCState *env) //#define POWERPC_EXCP_7x5 (POWERPC_EXCP_7x5) #define POWERPC_INPUT_7x5 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7x5 (bfd_mach_ppc_750) +#define POWERPC_FLAG_7x5 (POWERPC_FLAG_NONE) static void init_proc_7x5 (CPUPPCState *env) { @@ -3536,6 +3562,7 @@ static void init_proc_7x5 (CPUPPCState *env) #define POWERPC_EXCP_7400 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7400 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7400 (bfd_mach_ppc_7400) +#define POWERPC_FLAG_7400 (POWERPC_FLAG_VRE) static void init_proc_7400 (CPUPPCState *env) { @@ -3565,6 +3592,7 @@ static void init_proc_7400 (CPUPPCState *env) #define POWERPC_EXCP_7410 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7410 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7410 (bfd_mach_ppc_7400) +#define POWERPC_FLAG_7410 (POWERPC_FLAG_VRE) static void init_proc_7410 (CPUPPCState *env) { @@ -3606,6 +3634,7 @@ static void init_proc_7410 (CPUPPCState *env) #define POWERPC_EXCP_7440 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7440 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7440 (bfd_mach_ppc_7400) +#define POWERPC_FLAG_7440 (POWERPC_FLAG_VRE) __attribute__ (( unused )) static void init_proc_7440 (CPUPPCState *env) @@ -3674,6 +3703,7 @@ static void init_proc_7440 (CPUPPCState *env) #define POWERPC_EXCP_7450 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7450 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7450 (bfd_mach_ppc_7400) +#define POWERPC_FLAG_7450 (POWERPC_FLAG_VRE) __attribute__ (( unused )) static void init_proc_7450 (CPUPPCState *env) @@ -3744,6 +3774,7 @@ static void init_proc_7450 (CPUPPCState *env) #define POWERPC_EXCP_7445 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7445 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7445 (bfd_mach_ppc_7400) +#define POWERPC_FLAG_7445 (POWERPC_FLAG_VRE) __attribute__ (( unused )) static void init_proc_7445 (CPUPPCState *env) @@ -3846,6 +3877,7 @@ static void init_proc_7445 (CPUPPCState *env) #define POWERPC_EXCP_7455 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7455 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7455 (bfd_mach_ppc_7400) +#define POWERPC_FLAG_7455 (POWERPC_FLAG_VRE) __attribute__ (( unused )) static void init_proc_7455 (CPUPPCState *env) @@ -3955,6 +3987,7 @@ static void init_proc_7455 (CPUPPCState *env) //#define POWERPC_EXCP_970 (POWERPC_EXCP_970) #define POWERPC_INPUT_970 (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970 (bfd_mach_ppc64) +#define POWERPC_FLAG_970 (POWERPC_FLAG_VRE) static void init_proc_970 (CPUPPCState *env) { @@ -4025,6 +4058,7 @@ static void init_proc_970 (CPUPPCState *env) #define POWERPC_EXCP_970FX (POWERPC_EXCP_970) #define POWERPC_INPUT_970FX (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970FX (bfd_mach_ppc64) +#define POWERPC_FLAG_970FX (POWERPC_FLAG_VRE) static void init_proc_970FX (CPUPPCState *env) { @@ -4095,6 +4129,7 @@ static void init_proc_970FX (CPUPPCState *env) #define POWERPC_EXCP_970GX (POWERPC_EXCP_970) #define POWERPC_INPUT_970GX (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970GX (bfd_mach_ppc64) +#define POWERPC_FLAG_970GX (POWERPC_FLAG_VRE) static void init_proc_970GX (CPUPPCState *env) { @@ -4164,6 +4199,7 @@ static void init_proc_970GX (CPUPPCState *env) #define POWERPC_EXCP_620 (POWERPC_EXCP_970) #define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_620 (bfd_mach_ppc64) +#define POWERPC_FLAG_620 (POWERPC_FLAG_NONE) __attribute__ (( unused )) static void init_proc_620 (CPUPPCState *env) @@ -4197,6 +4233,7 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_INPUT_PPC32 POWERPC_INPUT_604 #define init_proc_PPC32 init_proc_604 #define POWERPC_BFDM_PPC32 POWERPC_BFDM_604 +#define POWERPC_FLAG_PPC32 POWERPC_FLAG_604 /* Default 64 bits PowerPC target will be 970 FX */ #define CPU_POWERPC_PPC64 CPU_POWERPC_970FX @@ -4207,6 +4244,7 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_INPUT_PPC64 POWERPC_INPUT_970FX #define init_proc_PPC64 init_proc_970FX #define POWERPC_BFDM_PPC64 POWERPC_BFDM_970FX +#define POWERPC_FLAG_PPC64 POWERPC_FLAG_970FX /* Default PowerPC target will be PowerPC 32 */ #if defined (TARGET_PPC64) && 0 // XXX: TODO @@ -4218,6 +4256,7 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64 #define init_proc_DEFAULT init_proc_PPC64 #define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC64 +#define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC64 #else #define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC32 #define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32 @@ -4227,6 +4266,7 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32 #define init_proc_DEFAULT init_proc_PPC32 #define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC32 +#define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC32 #endif /*****************************************************************************/ @@ -4724,6 +4764,7 @@ enum { .excp_model = glue(POWERPC_EXCP_,_type), \ .bus_model = glue(POWERPC_INPUT_,_type), \ .bfd_mach = glue(POWERPC_BFDM_,_type), \ + .flags = glue(POWERPC_FLAG_,_type), \ .init_proc = &glue(init_proc_,_type), \ } @@ -6016,6 +6057,7 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) env->mmu_model = def->mmu_model; env->excp_model = def->excp_model; env->bus_model = def->bus_model; + env->flags = def->flags; env->bfd_mach = def->bfd_mach; if (create_ppc_opcodes(env, def) < 0) return -1; -- cgit v1.2.3 From f2e63a42c9151d17d734ce5a173d81f1598f0565 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 15:43:50 +0000 Subject: Reorganize the CPUPPCState structure to group features. Add #ifdef to avoid compiling not relevant resources: - MMU related stuff for user-mode only targets - PowerPC 64 only resources for PowerPC 32 targets - embedded PowerPC extensions for non-ppcemb targets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3343 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 37 +++++++++++++++++++--------------- target-ppc/translate.c | 2 ++ target-ppc/translate_init.c | 49 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 69 insertions(+), 19 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8a24d4d06..e2d51ec07 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -495,9 +495,14 @@ struct CPUPPCState { int access_type; /* when a memory exception occurs, the access type is stored here */ - /* MMU context */ + /* MMU context - only relevant for full system emulation */ +#if !defined(CONFIG_USER_ONLY) +#if defined(TARGET_PPC64) /* Address space register */ target_ulong asr; + /* PowerPC 64 SLB area */ + int slb_nr; +#endif /* segment registers */ target_ulong sdr1; target_ulong sr[16]; @@ -505,17 +510,31 @@ struct CPUPPCState { int nb_BATs; target_ulong DBAT[2][8]; target_ulong IBAT[2][8]; + /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */ + int nb_tlb; /* Total number of TLB */ + int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */ + int nb_ways; /* Number of ways in the TLB set */ + int last_way; /* Last used way used to allocate TLB in a LRU way */ + int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ + int nb_pids; /* Number of available PID registers */ + ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ + /* 403 dedicated access protection registers */ + target_ulong pb[4]; +#endif /* Other registers */ /* Special purpose registers */ target_ulong spr[1024]; + ppc_spr_t spr_cb[1024]; /* Altivec registers */ ppc_avr_t avr[32]; uint32_t vscr; +#if defined(TARGET_PPCEMB) /* SPE registers */ ppc_gpr_t spe_acc; float_status spe_status; uint32_t spe_fscr; +#endif /* Internal devices resources */ /* Time base and decrementer */ @@ -523,19 +542,6 @@ struct CPUPPCState { /* Device control registers */ ppc_dcr_t *dcr_env; - /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */ - int nb_tlb; /* Total number of TLB */ - int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */ - int nb_ways; /* Number of ways in the TLB set */ - int last_way; /* Last used way used to allocate TLB in a LRU way */ - int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ - int nb_pids; /* Number of available PID registers */ - ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ - /* 403 dedicated access protection registers */ - target_ulong pb[4]; - /* PowerPC 64 SLB area */ - int slb_nr; - int dcache_line_size; int icache_line_size; @@ -570,8 +576,7 @@ struct CPUPPCState { /* Those resources are used only during code translation */ /* Next instruction pointer */ target_ulong nip; - /* SPR translation callbacks */ - ppc_spr_t spr_cb[1024]; + /* opcode handlers */ opc_handler_t *opcodes[0x40]; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f30cb411f..9d51bf9b1 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6448,9 +6448,11 @@ void cpu_dump_state (CPUState *env, FILE *f, if ((i & (RFPL - 1)) == (RFPL - 1)) cpu_fprintf(f, "\n"); } +#if !defined(CONFIG_USER_ONLY) cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL "SDR1 " REGX "\n", env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1); +#endif #undef RGPL #undef RFPL diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 296727e76..edff5cd90 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -533,6 +533,7 @@ static void gen_spr_ne_601 (CPUPPCState *env) /* BATs 0-3 */ static void gen_low_BATs (CPUPPCState *env) { +#if !defined(CONFIG_USER_ONLY) spr_register(env, SPR_IBAT0U, "IBAT0U", SPR_NOACCESS, SPR_NOACCESS, &spr_read_ibat, &spr_write_ibatu, @@ -598,11 +599,13 @@ static void gen_low_BATs (CPUPPCState *env) &spr_read_dbat, &spr_write_dbatl, 0x00000000); env->nb_BATs += 4; +#endif } /* BATs 4-7 */ static void gen_high_BATs (CPUPPCState *env) { +#if !defined(CONFIG_USER_ONLY) spr_register(env, SPR_IBAT4U, "IBAT4U", SPR_NOACCESS, SPR_NOACCESS, &spr_read_ibat_h, &spr_write_ibatu_h, @@ -668,6 +671,7 @@ static void gen_high_BATs (CPUPPCState *env) &spr_read_dbat_h, &spr_write_dbatl_h, 0x00000000); env->nb_BATs += 4; +#endif } /* Generic PowerPC time base */ @@ -694,6 +698,7 @@ static void gen_tbl (CPUPPCState *env) /* Softare table search registers */ static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) { +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = nb_tlbs; env->nb_ways = nb_ways; env->id_tlbs = 1; @@ -725,6 +730,7 @@ static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); +#endif } /* SPR common to MPC755 and G2 */ @@ -1105,6 +1111,7 @@ static void gen_spr_601 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) spr_register(env, SPR_IBAT0U, "IBAT0U", SPR_NOACCESS, SPR_NOACCESS, &spr_read_601_ubat, &spr_write_601_ubatu, @@ -1138,6 +1145,7 @@ static void gen_spr_601 (CPUPPCState *env) &spr_read_601_ubat, &spr_write_601_ubatl, 0x00000000); env->nb_BATs = 4; +#endif } static void gen_spr_74xx (CPUPPCState *env) @@ -1238,6 +1246,7 @@ static void gen_l3_ctrl (CPUPPCState *env) static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) { +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = nb_tlbs; env->nb_ways = nb_ways; env->id_tlbs = 1; @@ -1256,6 +1265,7 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); +#endif } /* PowerPC BookE SPR */ @@ -1512,6 +1522,7 @@ static void gen_spr_BookE (CPUPPCState *env) /* FSL storage control registers */ static void gen_spr_BookE_FSL (CPUPPCState *env) { +#if !defined(CONFIG_USER_ONLY) /* TLB assist registers */ /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MAS0, "MAS0", @@ -1605,6 +1616,7 @@ static void gen_spr_BookE_FSL (CPUPPCState *env) default: break; } +#endif } /* SPR specific to PowerPC 440 implementation */ @@ -2616,9 +2628,11 @@ static void init_proc_401x2 (CPUPPCState *env) gen_spr_401x2(env); gen_spr_compress(env); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -2674,9 +2688,11 @@ static void init_proc_IOP480 (CPUPPCState *env) gen_spr_401x2(env); gen_spr_compress(env); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -2744,9 +2760,11 @@ static void init_proc_403GCX (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -2785,9 +2803,11 @@ static void init_proc_405 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -2832,9 +2852,11 @@ static void init_proc_440EP (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -2860,9 +2882,11 @@ static void init_proc_440GP (CPUPPCState *env) gen_spr_BookE(env); gen_spr_440(env); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -2889,9 +2913,11 @@ static void init_proc_440x4 (CPUPPCState *env) gen_spr_BookE(env); gen_spr_440(env); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -2935,9 +2961,11 @@ static void init_proc_440x5 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -2987,9 +3015,11 @@ static void init_proc_460 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -3042,9 +3072,11 @@ static void init_proc_460F (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -3097,9 +3129,11 @@ static void init_proc_e500 (CPUPPCState *env) gen_spr_BookE(env); /* Memory management */ gen_spr_BookE_FSL(env); +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; +#endif init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -3167,10 +3201,11 @@ static void init_proc_601 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ +#if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 2; env->id_tlbs = 0; - env->id_tlbs = 0; +#endif init_excp_601(env); env->dcache_line_size = 64; env->icache_line_size = 64; @@ -4041,7 +4076,9 @@ static void init_proc_970 (CPUPPCState *env) #if !defined(CONFIG_USER_ONLY) env->excp_prefix = 0xFFF00000; #endif +#if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; +#endif init_excp_970(env); env->dcache_line_size = 128; env->icache_line_size = 128; @@ -4112,7 +4149,9 @@ static void init_proc_970FX (CPUPPCState *env) #if !defined(CONFIG_USER_ONLY) env->excp_prefix = 0xFFF00000; #endif +#if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; +#endif init_excp_970(env); env->dcache_line_size = 128; env->icache_line_size = 128; @@ -4183,7 +4222,9 @@ static void init_proc_970GX (CPUPPCState *env) #if !defined(CONFIG_USER_ONLY) env->excp_prefix = 0xFFF00000; #endif +#if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; +#endif init_excp_970(env); env->dcache_line_size = 128; env->icache_line_size = 128; @@ -5729,11 +5770,11 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) env->excp_prefix = 0x00000000; env->ivor_mask = 0x00000000; env->ivpr_mask = 0x00000000; -#endif /* Default MMU definitions */ env->nb_BATs = 0; env->nb_tlb = 0; env->nb_ways = 0; +#endif /* Register SPR common to all PowerPC implementations */ gen_spr_generic(env); spr_register(env, SPR_PVR, "PVR", @@ -5743,6 +5784,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) /* PowerPC implementation specific initialisations (SPRs, timers, ...) */ (*def->init_proc)(env); /* Allocate TLBs buffer when needed */ +#if !defined(CONFIG_USER_ONLY) if (env->nb_tlb != 0) { int nb_tlb = env->nb_tlb; if (env->id_tlbs != 0) @@ -5751,7 +5793,6 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) /* Pre-compute some useful values */ env->tlb_per_way = env->nb_tlb / env->nb_ways; } -#if !defined(CONFIG_USER_ONLY) if (env->irq_inputs == NULL) { fprintf(stderr, "WARNING: no internal IRQ controller registered.\n" " Attempt Qemu to crash very soon !\n"); @@ -6171,11 +6212,13 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) printf("PowerPC %-12s : PVR %08x MSR %016" PRIx64 "\n" " MMU model : %s\n", def->name, def->pvr, def->msr_mask, mmu_model); +#if !defined(CONFIG_USER_ONLY) if (env->tlb != NULL) { printf(" %d %s TLB in %d ways\n", env->nb_tlb, env->id_tlbs ? "splitted" : "merged", env->nb_ways); } +#endif printf(" Exceptions model : %s\n" " Bus model : %s\n", excp_model, bus_model); -- cgit v1.2.3 From 863cf0b72cee98e42aa03403c38d5cac7fa535ca Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 15:59:45 +0000 Subject: Fix confusions between host and target long types. Fix start_data computation. Fix auxiliary infos setup. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3344 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 108 +++++++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 47 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 22e3283ae..79c1c4da6 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -124,6 +124,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i /* XXX: it seems that r0 is zeroed after ! */ regs->ARM_r0 = 0; /* For uClinux PIC binaries. */ + /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ regs->ARM_r10 = infop->start_data; } @@ -516,8 +517,8 @@ static void bswap_sym(struct elf_sym *sym) * to be put directly into the top of new user memory. * */ -static unsigned long copy_elf_strings(int argc,char ** argv, void **page, - target_ulong p) +static target_ulong copy_elf_strings(int argc,char ** argv, void **page, + target_ulong p) { char *tmp, *tmp1, *pag = NULL; int len, offset = 0; @@ -566,8 +567,8 @@ static unsigned long copy_elf_strings(int argc,char ** argv, void **page, return p; } -unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, - struct image_info * info) +target_ulong setup_arg_pages(target_ulong p, struct linux_binprm * bprm, + struct image_info * info) { target_ulong stack_base, size, error; int i; @@ -605,7 +606,7 @@ unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, return p; } -static void set_brk(unsigned long start, unsigned long end) +static void set_brk(target_ulong start, target_ulong end) { /* page-align the start and end addresses... */ start = HOST_PAGE_ALIGN(start); @@ -624,9 +625,9 @@ static void set_brk(unsigned long start, unsigned long end) /* We need to explicitly zero any fractional pages after the data section (i.e. bss). This would contain the junk from the file that should not be in memory. */ -static void padzero(unsigned long elf_bss, unsigned long last_bss) +static void padzero(target_ulong elf_bss, target_ulong last_bss) { - unsigned long nbyte; + target_ulong nbyte; if (elf_bss >= last_bss) return; @@ -637,12 +638,12 @@ static void padzero(unsigned long elf_bss, unsigned long last_bss) patch target_mmap(), but it is more complicated as the file size must be known */ if (qemu_real_host_page_size < qemu_host_page_size) { - unsigned long end_addr, end_addr1; + target_ulong end_addr, end_addr1; end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & ~(qemu_real_host_page_size - 1); end_addr = HOST_PAGE_ALIGN(elf_bss); if (end_addr1 < end_addr) { - mmap((void *)end_addr1, end_addr - end_addr1, + mmap((void *)g2h(end_addr1), end_addr - end_addr1, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); } @@ -659,18 +660,18 @@ static void padzero(unsigned long elf_bss, unsigned long last_bss) } -static unsigned long create_elf_tables(target_ulong p, int argc, int envc, - struct elfhdr * exec, - unsigned long load_addr, - unsigned long load_bias, - unsigned long interp_load_addr, int ibcs, - struct image_info *info) +static target_ulong create_elf_tables(target_ulong p, int argc, int envc, + struct elfhdr * exec, + target_ulong load_addr, + target_ulong load_bias, + target_ulong interp_load_addr, int ibcs, + struct image_info *info) { target_ulong sp; int size; target_ulong u_platform; const char *k_platform; - const int n = sizeof(target_ulong); + const int n = sizeof(elf_addr_t); sp = p; u_platform = 0; @@ -697,10 +698,20 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, if (size & 15) sp -= 16 - (size & 15); + /* This is correct because Linux defines + * elf_addr_t as Elf32_Off / Elf64_Off + */ +#if ELF_CLASS == ELFCLASS32 #define NEW_AUX_ENT(id, val) do { \ - sp -= n; tputl(sp, val); \ - sp -= n; tputl(sp, id); \ + sp -= n; tput32(sp, val); \ + sp -= n; tput32(sp, id); \ } while(0) +#else +#define NEW_AUX_ENT(id, val) do { \ + sp -= n; tput64(sp, val); \ + sp -= n; tput64(sp, id); \ + } while(0) +#endif NEW_AUX_ENT (AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ @@ -732,17 +743,17 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc, } -static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, - int interpreter_fd, - unsigned long *interp_load_addr) +static target_ulong load_elf_interp(struct elfhdr * interp_elf_ex, + int interpreter_fd, + target_ulong *interp_load_addr) { struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; - unsigned long load_addr = 0; + target_ulong load_addr = 0; int load_addr_set = 0; int retval; - unsigned long last_bss, elf_bss; - unsigned long error; + target_ulong last_bss, elf_bss; + target_ulong error; int i; elf_bss = 0; @@ -756,20 +767,20 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine)) { - return ~0UL; + return ~((target_ulong)0UL); } /* Now read in all of the header information */ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) - return ~0UL; + return ~(target_ulong)0UL; elf_phdata = (struct elf_phdr *) malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); if (!elf_phdata) - return ~0UL; + return ~((target_ulong)0UL); /* * If the size of this structure has changed, then punt, since @@ -777,7 +788,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, */ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { free(elf_phdata); - return ~0UL; + return ~((target_ulong)0UL); } retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); @@ -818,8 +829,8 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; - unsigned long vaddr = 0; - unsigned long k; + target_ulong vaddr = 0; + target_ulong k; if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; @@ -839,7 +850,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, /* Real error */ close(interpreter_fd); free(elf_phdata); - return ~0UL; + return ~((target_ulong)0UL); } if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { @@ -884,7 +895,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, free(elf_phdata); *interp_load_addr = load_addr; - return ((unsigned long) interp_elf_ex->e_entry) + load_addr; + return ((target_ulong) interp_elf_ex->e_entry) + load_addr; } /* Best attempt to load symbols from this ELF object. */ @@ -972,22 +983,22 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct elfhdr interp_elf_ex; struct exec interp_ex; int interpreter_fd = -1; /* avoid warning */ - unsigned long load_addr, load_bias; + target_ulong load_addr, load_bias; int load_addr_set = 0; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; - unsigned long mapped_addr; + target_ulong mapped_addr; struct elf_phdr * elf_ppnt; struct elf_phdr *elf_phdata; - unsigned long elf_bss, k, elf_brk; + target_ulong elf_bss, k, elf_brk; int retval; char * elf_interpreter; - unsigned long elf_entry, interp_load_addr = 0; + target_ulong elf_entry, interp_load_addr = 0; int status; - unsigned long start_code, end_code, end_data; - unsigned long reloc_func_desc = 0; - unsigned long elf_stack; + target_ulong start_code, end_code, start_data, end_data; + target_ulong reloc_func_desc = 0; + target_ulong elf_stack; char passed_fileno[6]; ibcs2_interpreter = 0; @@ -1043,10 +1054,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, elf_brk = 0; - elf_stack = ~0UL; + elf_stack = ~((target_ulong)0UL); elf_interpreter = NULL; - start_code = ~0UL; + start_code = ~((target_ulong)0UL); end_code = 0; + start_data = 0; end_data = 0; for(i=0;i < elf_ex.e_phnum; i++) { @@ -1180,9 +1192,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* OK, This is the point of no return */ info->end_data = 0; info->end_code = 0; - info->start_mmap = (unsigned long)ELF_START_MMAP; + info->start_mmap = (target_ulong)ELF_START_MMAP; info->mmap = 0; - elf_entry = (unsigned long) elf_ex.e_entry; + elf_entry = (target_ulong) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will change some of these later */ @@ -1199,7 +1211,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0; int elf_flags = 0; - unsigned long error; + target_ulong error; if (elf_ppnt->p_type != PT_LOAD) continue; @@ -1257,6 +1269,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, k = elf_ppnt->p_vaddr; if (k < start_code) start_code = k; + if (start_data < k) + start_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; if (k > elf_bss) elf_bss = k; @@ -1273,7 +1287,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, elf_brk += load_bias; start_code += load_bias; end_code += load_bias; - // start_data += load_bias; + start_data += load_bias; end_data += load_bias; if (elf_interpreter) { @@ -1289,7 +1303,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, close(interpreter_fd); free(elf_interpreter); - if (elf_entry == ~0UL) { + if (elf_entry == ~((target_ulong)0UL)) { printf("Unable to load interpreter\n"); free(elf_phdata); exit(-1); @@ -1320,7 +1334,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, info->start_brk = info->brk = elf_brk; info->end_code = end_code; info->start_code = start_code; - info->start_data = end_code; + info->start_data = start_data; info->end_data = end_data; info->start_stack = bprm->p; -- cgit v1.2.3 From 3d177870554de21dad2479da786f4f6d7e26d529 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 16:06:13 +0000 Subject: Fix host and target longs confusions (continued). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3345 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 19 +++++++++++-------- linux-user/qemu.h | 26 +++++++++++++------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 127ae109a..fd130ef9c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1958,14 +1958,17 @@ int main(int argc, char **argv) if (loglevel) { page_dump(logfile); - fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); - fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); - fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); - fprintf(logfile, "start_data 0x%08lx\n" , info->start_data); - fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); - fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); - fprintf(logfile, "brk 0x%08lx\n" , info->brk); - fprintf(logfile, "entry 0x%08lx\n" , info->entry); + fprintf(logfile, "start_brk 0x" TARGET_FMT_lx "\n", info->start_brk); + fprintf(logfile, "end_code 0x" TARGET_FMT_lx "\n", info->end_code); + fprintf(logfile, "start_code 0x" TARGET_FMT_lx "\n", + info->start_code); + fprintf(logfile, "start_data 0x" TARGET_FMT_lx "\n", + info->start_data); + fprintf(logfile, "end_data 0x" TARGET_FMT_lx "\n", info->end_data); + fprintf(logfile, "start_stack 0x" TARGET_FMT_lx "\n", + info->start_stack); + fprintf(logfile, "brk 0x" TARGET_FMT_lx "\n", info->brk); + fprintf(logfile, "entry 0x" TARGET_FMT_lx "\n", info->entry); } target_set_brk(info->brk); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index defa6b71e..2c48e9231 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -17,18 +17,18 @@ * task_struct fields in the kernel */ struct image_info { - target_ulong load_addr; - unsigned long start_code; - unsigned long end_code; - unsigned long start_data; - unsigned long end_data; - unsigned long start_brk; - unsigned long brk; - unsigned long start_mmap; - unsigned long mmap; - unsigned long rss; - unsigned long start_stack; - unsigned long entry; + target_ulong load_addr; + target_ulong start_code; + target_ulong end_code; + target_ulong start_data; + target_ulong end_data; + target_ulong start_brk; + target_ulong brk; + target_ulong start_mmap; + target_ulong mmap; + target_ulong rss; + target_ulong start_stack; + target_ulong entry; target_ulong code_offset; target_ulong data_offset; char **host_argv; @@ -105,7 +105,7 @@ extern const char *qemu_uname_release; struct linux_binprm { char buf[128]; void *page[MAX_ARG_PAGES]; - unsigned long p; + target_ulong p; int fd; int e_uid, e_gid; int argc, envc; -- cgit v1.2.3 From ed26abdbc138db8fe845e5dfed4c2d8480c77a8f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 16:07:25 +0000 Subject: Report missing elf_addr_t definition from Linux kernel header git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3346 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/elf.h b/elf.h index 0c03f032a..1bba0228b 100644 --- a/elf.h +++ b/elf.h @@ -1130,6 +1130,7 @@ typedef struct elf64_note { #define elf_note elf32_note #define elf_shdr elf32_shdr #define elf_sym elf32_sym +#define elf_addr_t Elf32_Off #ifdef ELF_USES_RELOCA # define ELF_RELOC Elf32_Rela @@ -1144,6 +1145,7 @@ typedef struct elf64_note { #define elf_note elf64_note #define elf_shdr elf64_shdr #define elf_sym elf64_sym +#define elf_addr_t Elf64_Off #ifdef ELF_USES_RELOCA # define ELF_RELOC Elf64_Rela -- cgit v1.2.3 From b068d6a7138292de0f5c5fa6c99f0b79d4e1e7f0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 17:13:44 +0000 Subject: PowerPC target optimisations: make intensive use of always_inline. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3347 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 28 +++---- hw/ppc405_uc.c | 2 +- hw/ppc_prep.c | 7 +- target-ppc/exec.h | 14 ++-- target-ppc/helper.c | 45 ++++++------ target-ppc/op_helper.c | 108 +++++++++++++-------------- target-ppc/op_helper.h | 30 ++++---- target-ppc/op_helper_mem.h | 9 ++- target-ppc/op_mem.h | 106 +++++++++++++++------------ target-ppc/translate.c | 179 +++++++++++++++++++++++---------------------- 10 files changed, 275 insertions(+), 253 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index a9bfc47d3..f1722bb91 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -424,7 +424,8 @@ struct ppc_tb_t { void *opaque; }; -static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, int64_t tb_offset) +static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, + int64_t tb_offset) { /* TB time in tb periods */ return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, @@ -446,7 +447,7 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) return tb & 0xFFFFFFFF; } -static inline uint32_t _cpu_ppc_load_tbu (CPUState *env) +static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env) { ppc_tb_t *tb_env = env->tb_env; uint64_t tb; @@ -466,8 +467,9 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) return _cpu_ppc_load_tbu(env); } -static inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, int64_t *tb_offsetp, - uint64_t value) +static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, + int64_t *tb_offsetp, + uint64_t value) { *tb_offsetp = muldiv64(value, ticks_per_sec, tb_env->tb_freq) - qemu_get_clock(vm_clock); @@ -489,7 +491,7 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, tb | (uint64_t)value); } -static inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value) +static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value) { ppc_tb_t *tb_env = env->tb_env; uint64_t tb; @@ -556,7 +558,8 @@ void cpu_ppc_store_atbu (CPUState *env, uint32_t value) ((uint64_t)value << 32) | tb); } -static inline uint32_t _cpu_ppc_load_decr (CPUState *env, uint64_t *next) +static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env, + uint64_t *next) { ppc_tb_t *tb_env = env->tb_env; uint32_t decr; @@ -605,7 +608,7 @@ uint64_t cpu_ppc_load_purr (CPUState *env) /* When decrementer expires, * all we need to do is generate or queue a CPU exception */ -static inline void cpu_ppc_decr_excp (CPUState *env) +static always_inline void cpu_ppc_decr_excp (CPUState *env) { /* Raise it */ #ifdef PPC_DEBUG_TB @@ -616,7 +619,7 @@ static inline void cpu_ppc_decr_excp (CPUState *env) ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); } -static inline void cpu_ppc_hdecr_excp (CPUState *env) +static always_inline void cpu_ppc_hdecr_excp (CPUState *env) { /* Raise it */ #ifdef PPC_DEBUG_TB @@ -657,9 +660,8 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, (*raise_excp)(env); } - -static inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, - uint32_t value, int is_excp) +static always_inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, + uint32_t value, int is_excp) { ppc_tb_t *tb_env = env->tb_env; @@ -678,8 +680,8 @@ static void cpu_ppc_decr_cb (void *opaque) } #if defined(TARGET_PPC64H) -static inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr, - uint32_t value, int is_excp) +static always_inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr, + uint32_t value, int is_excp) { ppc_tb_t *tb_env = env->tb_env; diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 55f4bcc3d..2857a1255 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -463,7 +463,7 @@ static uint32_t sdram_bcr (target_phys_addr_t ram_base, return bcr; } -static inline target_phys_addr_t sdram_base (uint32_t bcr) +static always_inline target_phys_addr_t sdram_base (uint32_t bcr) { return bcr & 0xFF800000; } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 16d8915e5..2c4b24203 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -107,7 +107,7 @@ static void _PPC_intack_write (void *opaque, // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); } -static inline uint32_t _PPC_intack_read (target_phys_addr_t addr) +static always_inline uint32_t _PPC_intack_read (target_phys_addr_t addr) { uint32_t retval = 0; @@ -412,8 +412,9 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) return retval; } -static inline target_phys_addr_t prep_IO_address (sysctrl_t *sysctrl, - target_phys_addr_t addr) +static always_inline target_phys_addr_t prep_IO_address (sysctrl_t *sysctrl, + target_phys_addr_t + addr) { if (sysctrl->contiguous_map == 0) { /* 64 KB contiguous space for IOs */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 8a5425827..0c53de42b 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -68,23 +68,23 @@ register unsigned long T2 asm(AREG3); # define RETURN() __asm__ __volatile__("" : : : "memory"); #endif -static inline target_ulong rotl8 (target_ulong i, int n) +static always_inline target_ulong rotl8 (target_ulong i, int n) { return (((uint8_t)i << n) | ((uint8_t)i >> (8 - n))); } -static inline target_ulong rotl16 (target_ulong i, int n) +static always_inline target_ulong rotl16 (target_ulong i, int n) { return (((uint16_t)i << n) | ((uint16_t)i >> (16 - n))); } -static inline target_ulong rotl32 (target_ulong i, int n) +static always_inline target_ulong rotl32 (target_ulong i, int n) { return (((uint32_t)i << n) | ((uint32_t)i >> (32 - n))); } #if defined(TARGET_PPC64) -static inline target_ulong rotl64 (target_ulong i, int n) +static always_inline target_ulong rotl64 (target_ulong i, int n) { return (((uint64_t)i << n) | ((uint64_t)i >> (64 - n))); } @@ -103,18 +103,18 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr, void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1); -static inline void env_to_regs (void) +static always_inline void env_to_regs (void) { } -static inline void regs_to_env (void) +static always_inline void regs_to_env (void) { } int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int is_user, int is_softmmu); -static inline int cpu_halted (CPUState *env) +static always_inline int cpu_halted (CPUState *env) { if (!env->halted) return 0; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f1fe6806c..205e35f49 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -67,23 +67,23 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) #else /* Common routines used by software and hardware TLBs emulation */ -static inline int pte_is_valid (target_ulong pte0) +static always_inline int pte_is_valid (target_ulong pte0) { return pte0 & 0x80000000 ? 1 : 0; } -static inline void pte_invalidate (target_ulong *pte0) +static always_inline void pte_invalidate (target_ulong *pte0) { *pte0 &= ~0x80000000; } #if defined(TARGET_PPC64) -static inline int pte64_is_valid (target_ulong pte0) +static always_inline int pte64_is_valid (target_ulong pte0) { return pte0 & 0x0000000000000001ULL ? 1 : 0; } -static inline void pte64_invalidate (target_ulong *pte0) +static always_inline void pte64_invalidate (target_ulong *pte0) { *pte0 &= ~0x0000000000000001ULL; } @@ -96,9 +96,9 @@ static inline void pte64_invalidate (target_ulong *pte0) #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) #endif -static inline int _pte_check (mmu_ctx_t *ctx, int is_64b, - target_ulong pte0, target_ulong pte1, - int h, int rw) +static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, + target_ulong pte0, target_ulong pte1, + int h, int rw) { target_ulong ptem, mmask; int access, ret, pteh, ptev; @@ -258,9 +258,10 @@ static void ppc6xx_tlb_invalidate_all (CPUState *env) tlb_flush(env, 1); } -static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, - target_ulong eaddr, - int is_code, int match_epn) +static always_inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, + target_ulong eaddr, + int is_code, + int match_epn) { #if !defined(FLUSH_ALL_TLBS) ppc6xx_tlb_t *tlb; @@ -487,7 +488,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, } /* PTE table lookup */ -static inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) +static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) { target_ulong base, pte0, pte1; int i, good = -1; @@ -588,7 +589,8 @@ static int find_pte64 (mmu_ctx_t *ctx, int h, int rw) } #endif -static inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw) +static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, + int h, int rw) { #if defined(TARGET_PPC64) if (env->mmu_model == POWERPC_MMU_64B) @@ -720,10 +722,10 @@ void ppc_store_slb (CPUPPCState *env, int slb_nr, target_ulong rs) #endif /* defined(TARGET_PPC64) */ /* Perform segment based translation */ -static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, - int sdr_sh, - target_phys_addr_t hash, - target_phys_addr_t mask) +static always_inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, + int sdr_sh, + target_phys_addr_t hash, + target_phys_addr_t mask) { return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask); } @@ -1594,8 +1596,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, /*****************************************************************************/ /* BATs management */ #if !defined(FLUSH_ALL_TLBS) -static inline void do_invalidate_BAT (CPUPPCState *env, - target_ulong BATu, target_ulong mask) +static always_inline void do_invalidate_BAT (CPUPPCState *env, + target_ulong BATu, + target_ulong mask) { target_ulong base, end, page; @@ -1616,8 +1619,8 @@ static inline void do_invalidate_BAT (CPUPPCState *env, } #endif -static inline void dump_store_bat (CPUPPCState *env, char ID, int ul, int nr, - target_ulong value) +static always_inline void dump_store_bat (CPUPPCState *env, char ID, + int ul, int nr, target_ulong value) { #if defined (DEBUG_BATS) if (loglevel != 0) { @@ -1931,7 +1934,7 @@ void ppc_store_xer (CPUPPCState *env, target_ulong value) } /* Swap temporary saved registers with GPRs */ -static inline void swap_gpr_tgpr (CPUPPCState *env) +static always_inline void swap_gpr_tgpr (CPUPPCState *env) { ppc_gpr_t tmp; diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 56d2af75d..7a758f6c0 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -601,7 +601,7 @@ void do_srad (void) } #endif -static inline int popcnt (uint32_t val) +static always_inline int popcnt (uint32_t val) { int i; @@ -707,7 +707,7 @@ void do_fctidz (void) #endif -static inline void do_fri (int rounding_mode) +static always_inline void do_fri (int rounding_mode) { int curmode; @@ -1430,12 +1430,12 @@ static uint8_t hbrev[16] = { 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF, }; -static inline uint8_t byte_reverse (uint8_t val) +static always_inline uint8_t byte_reverse (uint8_t val) { return hbrev[val >> 4] | (hbrev[val & 0xF] << 4); } -static inline uint32_t word_reverse (uint32_t val) +static always_inline uint32_t word_reverse (uint32_t val) { return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) | (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24); @@ -1468,7 +1468,7 @@ void do_ev##name (void) \ } /* Fixed-point vector arithmetic */ -static inline uint32_t _do_eabs (uint32_t val) +static always_inline uint32_t _do_eabs (uint32_t val) { if (val != 0x80000000) val &= ~0x80000000; @@ -1476,12 +1476,12 @@ static inline uint32_t _do_eabs (uint32_t val) return val; } -static inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2) { return op1 + op2; } -static inline int _do_ecntlsw (uint32_t val) +static always_inline int _do_ecntlsw (uint32_t val) { if (val & 0x80000000) return _do_cntlzw(~val); @@ -1489,12 +1489,12 @@ static inline int _do_ecntlsw (uint32_t val) return _do_cntlzw(val); } -static inline int _do_ecntlzw (uint32_t val) +static always_inline int _do_ecntlzw (uint32_t val) { return _do_cntlzw(val); } -static inline uint32_t _do_eneg (uint32_t val) +static always_inline uint32_t _do_eneg (uint32_t val) { if (val != 0x80000000) val ^= 0x80000000; @@ -1502,35 +1502,35 @@ static inline uint32_t _do_eneg (uint32_t val) return val; } -static inline uint32_t _do_erlw (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_erlw (uint32_t op1, uint32_t op2) { return rotl32(op1, op2); } -static inline uint32_t _do_erndw (uint32_t val) +static always_inline uint32_t _do_erndw (uint32_t val) { return (val + 0x000080000000) & 0xFFFF0000; } -static inline uint32_t _do_eslw (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_eslw (uint32_t op1, uint32_t op2) { /* No error here: 6 bits are used */ return op1 << (op2 & 0x3F); } -static inline int32_t _do_esrws (int32_t op1, uint32_t op2) +static always_inline int32_t _do_esrws (int32_t op1, uint32_t op2) { /* No error here: 6 bits are used */ return op1 >> (op2 & 0x3F); } -static inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2) { /* No error here: 6 bits are used */ return op1 >> (op2 & 0x3F); } -static inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2) { return op2 - op1; } @@ -1559,7 +1559,7 @@ DO_SPE_OP2(srwu); DO_SPE_OP2(subfw); /* evsel is a little bit more complicated... */ -static inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n) +static always_inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n) { if (n) return op1; @@ -1582,31 +1582,31 @@ void do_ev##name (void) \ _do_e##name(T0_64, T1_64)); \ } -static inline uint32_t _do_evcmp_merge (int t0, int t1) +static always_inline uint32_t _do_evcmp_merge (int t0, int t1) { return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); } -static inline int _do_ecmpeq (uint32_t op1, uint32_t op2) +static always_inline int _do_ecmpeq (uint32_t op1, uint32_t op2) { return op1 == op2 ? 1 : 0; } -static inline int _do_ecmpgts (int32_t op1, int32_t op2) +static always_inline int _do_ecmpgts (int32_t op1, int32_t op2) { return op1 > op2 ? 1 : 0; } -static inline int _do_ecmpgtu (uint32_t op1, uint32_t op2) +static always_inline int _do_ecmpgtu (uint32_t op1, uint32_t op2) { return op1 > op2 ? 1 : 0; } -static inline int _do_ecmplts (int32_t op1, int32_t op2) +static always_inline int _do_ecmplts (int32_t op1, int32_t op2) { return op1 < op2 ? 1 : 0; } -static inline int _do_ecmpltu (uint32_t op1, uint32_t op2) +static always_inline int _do_ecmpltu (uint32_t op1, uint32_t op2) { return op1 < op2 ? 1 : 0; } @@ -1623,7 +1623,7 @@ DO_SPE_CMP(cmplts); DO_SPE_CMP(cmpltu); /* Single precision floating-point conversions from/to integer */ -static inline uint32_t _do_efscfsi (int32_t val) +static always_inline uint32_t _do_efscfsi (int32_t val) { union { uint32_t u; @@ -1635,7 +1635,7 @@ static inline uint32_t _do_efscfsi (int32_t val) return u.u; } -static inline uint32_t _do_efscfui (uint32_t val) +static always_inline uint32_t _do_efscfui (uint32_t val) { union { uint32_t u; @@ -1647,7 +1647,7 @@ static inline uint32_t _do_efscfui (uint32_t val) return u.u; } -static inline int32_t _do_efsctsi (uint32_t val) +static always_inline int32_t _do_efsctsi (uint32_t val) { union { int32_t u; @@ -1662,7 +1662,7 @@ static inline int32_t _do_efsctsi (uint32_t val) return float32_to_int32(u.f, &env->spe_status); } -static inline uint32_t _do_efsctui (uint32_t val) +static always_inline uint32_t _do_efsctui (uint32_t val) { union { int32_t u; @@ -1677,7 +1677,7 @@ static inline uint32_t _do_efsctui (uint32_t val) return float32_to_uint32(u.f, &env->spe_status); } -static inline int32_t _do_efsctsiz (uint32_t val) +static always_inline int32_t _do_efsctsiz (uint32_t val) { union { int32_t u; @@ -1692,7 +1692,7 @@ static inline int32_t _do_efsctsiz (uint32_t val) return float32_to_int32_round_to_zero(u.f, &env->spe_status); } -static inline uint32_t _do_efsctuiz (uint32_t val) +static always_inline uint32_t _do_efsctuiz (uint32_t val) { union { int32_t u; @@ -1738,7 +1738,7 @@ void do_efsctuiz (void) } /* Single precision floating-point conversion to/from fractional */ -static inline uint32_t _do_efscfsf (uint32_t val) +static always_inline uint32_t _do_efscfsf (uint32_t val) { union { uint32_t u; @@ -1753,7 +1753,7 @@ static inline uint32_t _do_efscfsf (uint32_t val) return u.u; } -static inline uint32_t _do_efscfuf (uint32_t val) +static always_inline uint32_t _do_efscfuf (uint32_t val) { union { uint32_t u; @@ -1768,7 +1768,7 @@ static inline uint32_t _do_efscfuf (uint32_t val) return u.u; } -static inline int32_t _do_efsctsf (uint32_t val) +static always_inline int32_t _do_efsctsf (uint32_t val) { union { int32_t u; @@ -1786,7 +1786,7 @@ static inline int32_t _do_efsctsf (uint32_t val) return float32_to_int32(u.f, &env->spe_status); } -static inline uint32_t _do_efsctuf (uint32_t val) +static always_inline uint32_t _do_efsctuf (uint32_t val) { union { int32_t u; @@ -1804,7 +1804,7 @@ static inline uint32_t _do_efsctuf (uint32_t val) return float32_to_uint32(u.f, &env->spe_status); } -static inline int32_t _do_efsctsfz (uint32_t val) +static always_inline int32_t _do_efsctsfz (uint32_t val) { union { int32_t u; @@ -1822,7 +1822,7 @@ static inline int32_t _do_efsctsfz (uint32_t val) return float32_to_int32_round_to_zero(u.f, &env->spe_status); } -static inline uint32_t _do_efsctufz (uint32_t val) +static always_inline uint32_t _do_efsctufz (uint32_t val) { union { int32_t u; @@ -1871,19 +1871,19 @@ void do_efsctufz (void) } /* Double precision floating point helpers */ -static inline int _do_efdcmplt (uint64_t op1, uint64_t op2) +static always_inline int _do_efdcmplt (uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return _do_efdtstlt(op1, op2); } -static inline int _do_efdcmpgt (uint64_t op1, uint64_t op2) +static always_inline int _do_efdcmpgt (uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return _do_efdtstgt(op1, op2); } -static inline int _do_efdcmpeq (uint64_t op1, uint64_t op2) +static always_inline int _do_efdcmpeq (uint64_t op1, uint64_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return _do_efdtsteq(op1, op2); @@ -1905,7 +1905,7 @@ void do_efdcmpeq (void) } /* Double precision floating-point conversion to/from integer */ -static inline uint64_t _do_efdcfsi (int64_t val) +static always_inline uint64_t _do_efdcfsi (int64_t val) { union { uint64_t u; @@ -1917,7 +1917,7 @@ static inline uint64_t _do_efdcfsi (int64_t val) return u.u; } -static inline uint64_t _do_efdcfui (uint64_t val) +static always_inline uint64_t _do_efdcfui (uint64_t val) { union { uint64_t u; @@ -1929,7 +1929,7 @@ static inline uint64_t _do_efdcfui (uint64_t val) return u.u; } -static inline int64_t _do_efdctsi (uint64_t val) +static always_inline int64_t _do_efdctsi (uint64_t val) { union { int64_t u; @@ -1944,7 +1944,7 @@ static inline int64_t _do_efdctsi (uint64_t val) return float64_to_int64(u.f, &env->spe_status); } -static inline uint64_t _do_efdctui (uint64_t val) +static always_inline uint64_t _do_efdctui (uint64_t val) { union { int64_t u; @@ -1959,7 +1959,7 @@ static inline uint64_t _do_efdctui (uint64_t val) return float64_to_uint64(u.f, &env->spe_status); } -static inline int64_t _do_efdctsiz (uint64_t val) +static always_inline int64_t _do_efdctsiz (uint64_t val) { union { int64_t u; @@ -1974,7 +1974,7 @@ static inline int64_t _do_efdctsiz (uint64_t val) return float64_to_int64_round_to_zero(u.f, &env->spe_status); } -static inline uint64_t _do_efdctuiz (uint64_t val) +static always_inline uint64_t _do_efdctuiz (uint64_t val) { union { int64_t u; @@ -2020,7 +2020,7 @@ void do_efdctuiz (void) } /* Double precision floating-point conversion to/from fractional */ -static inline uint64_t _do_efdcfsf (int64_t val) +static always_inline uint64_t _do_efdcfsf (int64_t val) { union { uint64_t u; @@ -2035,7 +2035,7 @@ static inline uint64_t _do_efdcfsf (int64_t val) return u.u; } -static inline uint64_t _do_efdcfuf (uint64_t val) +static always_inline uint64_t _do_efdcfuf (uint64_t val) { union { uint64_t u; @@ -2050,7 +2050,7 @@ static inline uint64_t _do_efdcfuf (uint64_t val) return u.u; } -static inline int64_t _do_efdctsf (uint64_t val) +static always_inline int64_t _do_efdctsf (uint64_t val) { union { int64_t u; @@ -2068,7 +2068,7 @@ static inline int64_t _do_efdctsf (uint64_t val) return float64_to_int32(u.f, &env->spe_status); } -static inline uint64_t _do_efdctuf (uint64_t val) +static always_inline uint64_t _do_efdctuf (uint64_t val) { union { int64_t u; @@ -2086,7 +2086,7 @@ static inline uint64_t _do_efdctuf (uint64_t val) return float64_to_uint32(u.f, &env->spe_status); } -static inline int64_t _do_efdctsfz (uint64_t val) +static always_inline int64_t _do_efdctsfz (uint64_t val) { union { int64_t u; @@ -2104,7 +2104,7 @@ static inline int64_t _do_efdctsfz (uint64_t val) return float64_to_int32_round_to_zero(u.f, &env->spe_status); } -static inline uint64_t _do_efdctufz (uint64_t val) +static always_inline uint64_t _do_efdctufz (uint64_t val) { union { int64_t u; @@ -2153,7 +2153,7 @@ void do_efdctufz (void) } /* Floating point conversion between single and double precision */ -static inline uint32_t _do_efscfd (uint64_t val) +static always_inline uint32_t _do_efscfd (uint64_t val) { union { uint64_t u; @@ -2170,7 +2170,7 @@ static inline uint32_t _do_efscfd (uint64_t val) return u2.u; } -static inline uint64_t _do_efdcfs (uint32_t val) +static always_inline uint64_t _do_efdcfs (uint32_t val) { union { uint64_t u; @@ -2214,19 +2214,19 @@ DO_SPE_OP2(fsmul); DO_SPE_OP2(fsdiv); /* Single-precision floating-point comparisons */ -static inline int _do_efscmplt (uint32_t op1, uint32_t op2) +static always_inline int _do_efscmplt (uint32_t op1, uint32_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return _do_efststlt(op1, op2); } -static inline int _do_efscmpgt (uint32_t op1, uint32_t op2) +static always_inline int _do_efscmpgt (uint32_t op1, uint32_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return _do_efststgt(op1, op2); } -static inline int _do_efscmpeq (uint32_t op1, uint32_t op2) +static always_inline int _do_efscmpeq (uint32_t op1, uint32_t op2) { /* XXX: TODO: test special values (NaN, infinites, ...) */ return _do_efststeq(op1, op2); diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 65bee1ae7..4688bc2fa 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -277,7 +277,7 @@ void do_evfsctuiz (void); /* Inlined helpers: used in micro-operation as well as helpers */ /* Generic fixed-point helpers */ -static inline int _do_cntlzw (uint32_t val) +static always_inline int _do_cntlzw (uint32_t val) { int cnt = 0; if (!(val & 0xFFFF0000UL)) { @@ -306,7 +306,7 @@ static inline int _do_cntlzw (uint32_t val) return cnt; } -static inline int _do_cntlzd (uint64_t val) +static always_inline int _do_cntlzd (uint64_t val) { int cnt = 0; #if HOST_LONG_BITS == 64 @@ -350,19 +350,19 @@ static inline int _do_cntlzd (uint64_t val) #if defined(TARGET_PPCEMB) /* SPE extension */ /* Single precision floating-point helpers */ -static inline uint32_t _do_efsabs (uint32_t val) +static always_inline uint32_t _do_efsabs (uint32_t val) { return val & ~0x80000000; } -static inline uint32_t _do_efsnabs (uint32_t val) +static always_inline uint32_t _do_efsnabs (uint32_t val) { return val | 0x80000000; } -static inline uint32_t _do_efsneg (uint32_t val) +static always_inline uint32_t _do_efsneg (uint32_t val) { return val ^ 0x80000000; } -static inline uint32_t _do_efsadd (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_efsadd (uint32_t op1, uint32_t op2) { union { uint32_t u; @@ -373,7 +373,7 @@ static inline uint32_t _do_efsadd (uint32_t op1, uint32_t op2) u1.f = float32_add(u1.f, u2.f, &env->spe_status); return u1.u; } -static inline uint32_t _do_efssub (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_efssub (uint32_t op1, uint32_t op2) { union { uint32_t u; @@ -384,7 +384,7 @@ static inline uint32_t _do_efssub (uint32_t op1, uint32_t op2) u1.f = float32_sub(u1.f, u2.f, &env->spe_status); return u1.u; } -static inline uint32_t _do_efsmul (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_efsmul (uint32_t op1, uint32_t op2) { union { uint32_t u; @@ -395,7 +395,7 @@ static inline uint32_t _do_efsmul (uint32_t op1, uint32_t op2) u1.f = float32_mul(u1.f, u2.f, &env->spe_status); return u1.u; } -static inline uint32_t _do_efsdiv (uint32_t op1, uint32_t op2) +static always_inline uint32_t _do_efsdiv (uint32_t op1, uint32_t op2) { union { uint32_t u; @@ -407,7 +407,7 @@ static inline uint32_t _do_efsdiv (uint32_t op1, uint32_t op2) return u1.u; } -static inline int _do_efststlt (uint32_t op1, uint32_t op2) +static always_inline int _do_efststlt (uint32_t op1, uint32_t op2) { union { uint32_t u; @@ -417,7 +417,7 @@ static inline int _do_efststlt (uint32_t op1, uint32_t op2) u2.u = op2; return float32_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0; } -static inline int _do_efststgt (uint32_t op1, uint32_t op2) +static always_inline int _do_efststgt (uint32_t op1, uint32_t op2) { union { uint32_t u; @@ -427,7 +427,7 @@ static inline int _do_efststgt (uint32_t op1, uint32_t op2) u2.u = op2; return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 1; } -static inline int _do_efststeq (uint32_t op1, uint32_t op2) +static always_inline int _do_efststeq (uint32_t op1, uint32_t op2) { union { uint32_t u; @@ -438,7 +438,7 @@ static inline int _do_efststeq (uint32_t op1, uint32_t op2) return float32_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0; } /* Double precision floating-point helpers */ -static inline int _do_efdtstlt (uint64_t op1, uint64_t op2) +static always_inline int _do_efdtstlt (uint64_t op1, uint64_t op2) { union { uint64_t u; @@ -448,7 +448,7 @@ static inline int _do_efdtstlt (uint64_t op1, uint64_t op2) u2.u = op2; return float64_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0; } -static inline int _do_efdtstgt (uint64_t op1, uint64_t op2) +static always_inline int _do_efdtstgt (uint64_t op1, uint64_t op2) { union { uint64_t u; @@ -458,7 +458,7 @@ static inline int _do_efdtstgt (uint64_t op1, uint64_t op2) u2.u = op2; return float64_le(u1.f, u2.f, &env->spe_status) ? 0 : 1; } -static inline int _do_efdtsteq (uint64_t op1, uint64_t op2) +static always_inline int _do_efdtsteq (uint64_t op1, uint64_t op2) { union { uint64_t u; diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index 4b0bb841e..a395e0262 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -19,14 +19,15 @@ */ /* Multiple word / string load and store */ -static inline target_ulong glue(ld32r, MEMSUFFIX) (target_ulong EA) +static always_inline target_ulong glue(ld32r, MEMSUFFIX) (target_ulong EA) { uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); return ((tmp & 0xFF000000UL) >> 24) | ((tmp & 0x00FF0000UL) >> 8) | ((tmp & 0x0000FF00UL) << 8) | ((tmp & 0x000000FFUL) << 24); } -static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, target_ulong data) +static always_inline void glue(st32r, MEMSUFFIX) (target_ulong EA, + target_ulong data) { uint32_t tmp = ((data & 0xFF000000UL) >> 24) | ((data & 0x00FF0000UL) >> 8) | @@ -399,7 +400,7 @@ void glue(do_POWER2_lfq, MEMSUFFIX) (void) FT1 = glue(ldfq, MEMSUFFIX)((uint32_t)(T0 + 4)); } -static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) +static always_inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) { union { double d; @@ -431,7 +432,7 @@ void glue(do_POWER2_stfq, MEMSUFFIX) (void) glue(stfq, MEMSUFFIX)((uint32_t)(T0 + 4), FT1); } -static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) { union { double d; diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 16d866777..60c043386 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -18,19 +18,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA) +static always_inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA) { uint16_t tmp = glue(lduw, MEMSUFFIX)(EA); return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); } -static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA) +static always_inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA) { int16_t tmp = glue(lduw, MEMSUFFIX)(EA); return (int16_t)((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); } -static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) +static always_inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) { uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); return ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | @@ -38,7 +38,7 @@ static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) } #if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) -static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) { uint64_t tmp = glue(ldq, MEMSUFFIX)(EA); return ((tmp & 0xFF00000000000000ULL) >> 56) | @@ -53,12 +53,12 @@ static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) #endif #if defined(TARGET_PPC64) -static inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA) +static always_inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA) { return (int32_t)glue(ldl, MEMSUFFIX)(EA); } -static inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA) +static always_inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA) { uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); return (int32_t)((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | @@ -66,13 +66,15 @@ static inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA) } #endif -static inline void glue(st16r, MEMSUFFIX) (target_ulong EA, uint16_t data) +static always_inline void glue(st16r, MEMSUFFIX) (target_ulong EA, + uint16_t data) { uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8); glue(stw, MEMSUFFIX)(EA, tmp); } -static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t data) +static always_inline void glue(st32r, MEMSUFFIX) (target_ulong EA, + uint32_t data) { uint32_t tmp = ((data & 0xFF000000) >> 24) | ((data & 0x00FF0000) >> 8) | ((data & 0x0000FF00) << 8) | ((data & 0x000000FF) << 24); @@ -80,7 +82,8 @@ static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t data) } #if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) -static inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t data) +static always_inline void glue(st64r, MEMSUFFIX) (target_ulong EA, + uint64_t data) { uint64_t tmp = ((data & 0xFF00000000000000ULL) >> 56) | ((data & 0x00FF000000000000ULL) >> 40) | @@ -403,12 +406,12 @@ void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void) \ } #endif -static inline void glue(stfs, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfs, MEMSUFFIX) (target_ulong EA, double d) { glue(stfl, MEMSUFFIX)(EA, float64_to_float32(d, &env->fp_status)); } -static inline void glue(stfiwx, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfiwx, MEMSUFFIX) (target_ulong EA, double d) { union { double d; @@ -429,7 +432,7 @@ PPC_STF_OP_64(fs, stfs); PPC_STF_OP_64(fiwx, stfiwx); #endif -static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) { union { double d; @@ -448,7 +451,7 @@ static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) glue(stfq, MEMSUFFIX)(EA, u.d); } -static inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, double d) { union { float f; @@ -463,7 +466,7 @@ static inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, double d) glue(stfl, MEMSUFFIX)(EA, u.f); } -static inline void glue(stfiwxr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfiwxr, MEMSUFFIX) (target_ulong EA, double d) { union { double d; @@ -506,7 +509,7 @@ void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void) \ } #endif -static inline double glue(ldfs, MEMSUFFIX) (target_ulong EA) +static always_inline double glue(ldfs, MEMSUFFIX) (target_ulong EA) { return float32_to_float64(glue(ldfl, MEMSUFFIX)(EA), &env->fp_status); } @@ -518,7 +521,7 @@ PPC_LDF_OP_64(fd, ldfq); PPC_LDF_OP_64(fs, ldfs); #endif -static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) +static always_inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) { union { double d; @@ -538,7 +541,7 @@ static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) return u.d; } -static inline double glue(ldfsr, MEMSUFFIX) (target_ulong EA) +static always_inline double glue(ldfsr, MEMSUFFIX) (target_ulong EA) { union { float f; @@ -1105,7 +1108,7 @@ PPC_SPE_ST_OP(dd, stq); PPC_SPE_LD_OP(dd_le, ld64r); PPC_SPE_ST_OP(dd_le, st64r); #endif -static inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = (uint64_t)glue(ldl, MEMSUFFIX)(EA) << 32; @@ -1113,13 +1116,14 @@ static inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(dw, spe_ldw); -static inline void glue(spe_stdw, MEMSUFFIX) (target_ulong EA, uint64_t data) +static always_inline void glue(spe_stdw, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(stl, MEMSUFFIX)(EA, data >> 32); glue(stl, MEMSUFFIX)(EA + 4, data); } PPC_SPE_ST_OP(dw, spe_stdw); -static inline uint64_t glue(spe_ldw_le, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_ldw_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = (uint64_t)glue(ld32r, MEMSUFFIX)(EA) << 32; @@ -1127,14 +1131,14 @@ static inline uint64_t glue(spe_ldw_le, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(dw_le, spe_ldw_le); -static inline void glue(spe_stdw_le, MEMSUFFIX) (target_ulong EA, - uint64_t data) +static always_inline void glue(spe_stdw_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(st32r, MEMSUFFIX)(EA, data >> 32); glue(st32r, MEMSUFFIX)(EA + 4, data); } PPC_SPE_ST_OP(dw_le, spe_stdw_le); -static inline uint64_t glue(spe_ldh, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_ldh, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48; @@ -1144,7 +1148,8 @@ static inline uint64_t glue(spe_ldh, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(dh, spe_ldh); -static inline void glue(spe_stdh, MEMSUFFIX) (target_ulong EA, uint64_t data) +static always_inline void glue(spe_stdh, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(stw, MEMSUFFIX)(EA, data >> 48); glue(stw, MEMSUFFIX)(EA + 2, data >> 32); @@ -1152,7 +1157,7 @@ static inline void glue(spe_stdh, MEMSUFFIX) (target_ulong EA, uint64_t data) glue(stw, MEMSUFFIX)(EA + 6, data); } PPC_SPE_ST_OP(dh, spe_stdh); -static inline uint64_t glue(spe_ldh_le, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_ldh_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48; @@ -1162,8 +1167,8 @@ static inline uint64_t glue(spe_ldh_le, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(dh_le, spe_ldh_le); -static inline void glue(spe_stdh_le, MEMSUFFIX) (target_ulong EA, - uint64_t data) +static always_inline void glue(spe_stdh_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(st16r, MEMSUFFIX)(EA, data >> 48); glue(st16r, MEMSUFFIX)(EA + 2, data >> 32); @@ -1171,7 +1176,7 @@ static inline void glue(spe_stdh_le, MEMSUFFIX) (target_ulong EA, glue(st16r, MEMSUFFIX)(EA + 6, data); } PPC_SPE_ST_OP(dh_le, spe_stdh_le); -static inline uint64_t glue(spe_lwhe, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lwhe, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48; @@ -1179,13 +1184,14 @@ static inline uint64_t glue(spe_lwhe, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whe, spe_lwhe); -static inline void glue(spe_stwhe, MEMSUFFIX) (target_ulong EA, uint64_t data) +static always_inline void glue(spe_stwhe, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(stw, MEMSUFFIX)(EA, data >> 48); glue(stw, MEMSUFFIX)(EA + 2, data >> 16); } PPC_SPE_ST_OP(whe, spe_stwhe); -static inline uint64_t glue(spe_lwhe_le, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lwhe_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48; @@ -1193,14 +1199,14 @@ static inline uint64_t glue(spe_lwhe_le, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whe_le, spe_lwhe_le); -static inline void glue(spe_stwhe_le, MEMSUFFIX) (target_ulong EA, - uint64_t data) +static always_inline void glue(spe_stwhe_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(st16r, MEMSUFFIX)(EA, data >> 48); glue(st16r, MEMSUFFIX)(EA + 2, data >> 16); } PPC_SPE_ST_OP(whe_le, spe_stwhe_le); -static inline uint64_t glue(spe_lwhou, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lwhou, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 32; @@ -1208,7 +1214,7 @@ static inline uint64_t glue(spe_lwhou, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whou, spe_lwhou); -static inline uint64_t glue(spe_lwhos, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lwhos, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = ((uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA))) << 32; @@ -1216,13 +1222,14 @@ static inline uint64_t glue(spe_lwhos, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whos, spe_lwhos); -static inline void glue(spe_stwho, MEMSUFFIX) (target_ulong EA, uint64_t data) +static always_inline void glue(spe_stwho, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(stw, MEMSUFFIX)(EA, data >> 32); glue(stw, MEMSUFFIX)(EA + 2, data); } PPC_SPE_ST_OP(who, spe_stwho); -static inline uint64_t glue(spe_lwhou_le, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lwhou_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 32; @@ -1230,7 +1237,7 @@ static inline uint64_t glue(spe_lwhou_le, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whou_le, spe_lwhou_le); -static inline uint64_t glue(spe_lwhos_le, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lwhos_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; ret = ((uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA))) << 32; @@ -1238,55 +1245,57 @@ static inline uint64_t glue(spe_lwhos_le, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whos_le, spe_lwhos_le); -static inline void glue(spe_stwho_le, MEMSUFFIX) (target_ulong EA, - uint64_t data) +static always_inline void glue(spe_stwho_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(st16r, MEMSUFFIX)(EA, data >> 32); glue(st16r, MEMSUFFIX)(EA + 2, data); } PPC_SPE_ST_OP(who_le, spe_stwho_le); #if !defined(TARGET_PPC64) -static inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, uint64_t data) +static always_inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(stl, MEMSUFFIX)(EA, data); } PPC_SPE_ST_OP(wwo, spe_stwwo); -static inline void glue(spe_stwwo_le, MEMSUFFIX) (target_ulong EA, - uint64_t data) +static always_inline void glue(spe_stwwo_le, MEMSUFFIX) (target_ulong EA, + uint64_t data) { glue(st32r, MEMSUFFIX)(EA, data); } PPC_SPE_ST_OP(wwo_le, spe_stwwo_le); #endif -static inline uint64_t glue(spe_lh, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lh, MEMSUFFIX) (target_ulong EA) { uint16_t tmp; tmp = glue(lduw, MEMSUFFIX)(EA); return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16); } PPC_SPE_LD_OP(h, spe_lh); -static inline uint64_t glue(spe_lh_le, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lh_le, MEMSUFFIX) (target_ulong EA) { uint16_t tmp; tmp = glue(ld16r, MEMSUFFIX)(EA); return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16); } PPC_SPE_LD_OP(h_le, spe_lh_le); -static inline uint64_t glue(spe_lwwsplat, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lwwsplat, MEMSUFFIX) (target_ulong EA) { uint32_t tmp; tmp = glue(ldl, MEMSUFFIX)(EA); return ((uint64_t)tmp << 32) | (uint64_t)tmp; } PPC_SPE_LD_OP(wwsplat, spe_lwwsplat); -static inline uint64_t glue(spe_lwwsplat_le, MEMSUFFIX) (target_ulong EA) +static always_inline +uint64_t glue(spe_lwwsplat_le, MEMSUFFIX) (target_ulong EA) { uint32_t tmp; tmp = glue(ld32r, MEMSUFFIX)(EA); return ((uint64_t)tmp << 32) | (uint64_t)tmp; } PPC_SPE_LD_OP(wwsplat_le, spe_lwwsplat_le); -static inline uint64_t glue(spe_lwhsplat, MEMSUFFIX) (target_ulong EA) +static always_inline uint64_t glue(spe_lwhsplat, MEMSUFFIX) (target_ulong EA) { uint64_t ret; uint16_t tmp; @@ -1297,7 +1306,8 @@ static inline uint64_t glue(spe_lwhsplat, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whsplat, spe_lwhsplat); -static inline uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA) +static always_inline +uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; uint16_t tmp; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 9d51bf9b1..59d032d26 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -53,7 +53,7 @@ static uint32_t *gen_opparam_ptr; #include "gen-op.h" -static inline void gen_set_T0 (target_ulong val) +static always_inline void gen_set_T0 (target_ulong val) { #if defined(TARGET_PPC64) if (val >> 32) @@ -63,7 +63,7 @@ static inline void gen_set_T0 (target_ulong val) gen_op_set_T0(val); } -static inline void gen_set_T1 (target_ulong val) +static always_inline void gen_set_T1 (target_ulong val) { #if defined(TARGET_PPC64) if (val >> 32) @@ -78,7 +78,7 @@ static GenOpFunc *NAME ## _table [8] = { \ NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ }; \ -static inline void func(int n) \ +static always_inline void func (int n) \ { \ NAME ## _table[n](); \ } @@ -90,7 +90,7 @@ NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ }; \ -static inline void func(int n) \ +static always_inline void func (int n) \ { \ NAME ## _table[n](); \ } @@ -106,7 +106,7 @@ NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ }; \ -static inline void func(int n) \ +static always_inline void func (int n) \ { \ NAME ## _table[n](); \ } @@ -121,7 +121,7 @@ GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf); GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr); GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr); GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr); -static inline void gen_op_store_T0_fpscri (int n, uint8_t param) +static always_inline void gen_op_store_T0_fpscri (int n, uint8_t param) { gen_op_set_T0(param); gen_op_store_T0_fpscr(n); @@ -187,7 +187,7 @@ struct opc_handler_t { #endif }; -static inline void gen_set_Rc0 (DisasContext *ctx) +static always_inline void gen_set_Rc0 (DisasContext *ctx) { #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -198,7 +198,7 @@ static inline void gen_set_Rc0 (DisasContext *ctx) gen_op_set_Rc0(); } -static inline void gen_update_nip (DisasContext *ctx, target_ulong nip) +static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip) { #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -236,14 +236,14 @@ GEN_EXCP(ctx, POWERPC_EXCP_FPU, 0) GEN_EXCP(ctx, POWERPC_EXCP_APU, 0) /* Stop translation */ -static inline void GEN_STOP (DisasContext *ctx) +static always_inline void GEN_STOP (DisasContext *ctx) { gen_update_nip(ctx, ctx->nip); ctx->exception = POWERPC_EXCP_STOP; } /* No need to update nip here, as execution flow will change */ -static inline void GEN_SYNC (DisasContext *ctx) +static always_inline void GEN_SYNC (DisasContext *ctx) { ctx->exception = POWERPC_EXCP_SYNC; } @@ -267,13 +267,13 @@ typedef struct opcode_t { /*****************************************************************************/ /*** Instruction decoding ***/ #define EXTRACT_HELPER(name, shift, nb) \ -static inline uint32_t name (uint32_t opcode) \ +static always_inline uint32_t name (uint32_t opcode) \ { \ return (opcode >> (shift)) & ((1 << (nb)) - 1); \ } #define EXTRACT_SHELPER(name, shift, nb) \ -static inline int32_t name (uint32_t opcode) \ +static always_inline int32_t name (uint32_t opcode) \ { \ return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \ } @@ -304,7 +304,7 @@ EXTRACT_HELPER(crbA, 16, 5); EXTRACT_HELPER(crbB, 11, 5); /* SPR / TBL */ EXTRACT_HELPER(_SPR, 11, 10); -static inline uint32_t SPR (uint32_t opcode) +static always_inline uint32_t SPR (uint32_t opcode) { uint32_t sprn = _SPR(opcode); @@ -336,12 +336,12 @@ EXTRACT_HELPER(FPIMM, 20, 4); /* Displacement */ EXTRACT_SHELPER(d, 0, 16); /* Immediate address */ -static inline target_ulong LI (uint32_t opcode) +static always_inline target_ulong LI (uint32_t opcode) { return (opcode >> 0) & 0x03FFFFFC; } -static inline uint32_t BD (uint32_t opcode) +static always_inline uint32_t BD (uint32_t opcode) { return (opcode >> 0) & 0xFFFC; } @@ -354,7 +354,7 @@ EXTRACT_HELPER(AA, 1, 1); EXTRACT_HELPER(LK, 0, 1); /* Create a mask between and bits */ -static inline target_ulong MASK (uint32_t start, uint32_t end) +static always_inline target_ulong MASK (uint32_t start, uint32_t end) { target_ulong ret; @@ -694,7 +694,7 @@ __GEN_INT_ARITH1_O_64(name##o, opc1, opc2, opc3 | 0x10, type) #endif /* add add. addo addo. */ -static inline void gen_op_addo (void) +static always_inline void gen_op_addo (void) { gen_op_move_T2_T0(); gen_op_add(); @@ -702,7 +702,7 @@ static inline void gen_op_addo (void) } #if defined(TARGET_PPC64) #define gen_op_add_64 gen_op_add -static inline void gen_op_addo_64 (void) +static always_inline void gen_op_addo_64 (void) { gen_op_move_T2_T0(); gen_op_add(); @@ -711,13 +711,13 @@ static inline void gen_op_addo_64 (void) #endif GEN_INT_ARITH2_64 (add, 0x1F, 0x0A, 0x08, PPC_INTEGER); /* addc addc. addco addco. */ -static inline void gen_op_addc (void) +static always_inline void gen_op_addc (void) { gen_op_move_T2_T0(); gen_op_add(); gen_op_check_addc(); } -static inline void gen_op_addco (void) +static always_inline void gen_op_addco (void) { gen_op_move_T2_T0(); gen_op_add(); @@ -725,13 +725,13 @@ static inline void gen_op_addco (void) gen_op_check_addo(); } #if defined(TARGET_PPC64) -static inline void gen_op_addc_64 (void) +static always_inline void gen_op_addc_64 (void) { gen_op_move_T2_T0(); gen_op_add(); gen_op_check_addc_64(); } -static inline void gen_op_addco_64 (void) +static always_inline void gen_op_addco_64 (void) { gen_op_move_T2_T0(); gen_op_add(); @@ -741,14 +741,14 @@ static inline void gen_op_addco_64 (void) #endif GEN_INT_ARITH2_64 (addc, 0x1F, 0x0A, 0x00, PPC_INTEGER); /* adde adde. addeo addeo. */ -static inline void gen_op_addeo (void) +static always_inline void gen_op_addeo (void) { gen_op_move_T2_T0(); gen_op_adde(); gen_op_check_addo(); } #if defined(TARGET_PPC64) -static inline void gen_op_addeo_64 (void) +static always_inline void gen_op_addeo_64 (void) { gen_op_move_T2_T0(); gen_op_adde_64(); @@ -757,13 +757,13 @@ static inline void gen_op_addeo_64 (void) #endif GEN_INT_ARITH2_64 (adde, 0x1F, 0x0A, 0x04, PPC_INTEGER); /* addme addme. addmeo addmeo. */ -static inline void gen_op_addme (void) +static always_inline void gen_op_addme (void) { gen_op_move_T1_T0(); gen_op_add_me(); } #if defined(TARGET_PPC64) -static inline void gen_op_addme_64 (void) +static always_inline void gen_op_addme_64 (void) { gen_op_move_T1_T0(); gen_op_add_me_64(); @@ -771,13 +771,13 @@ static inline void gen_op_addme_64 (void) #endif GEN_INT_ARITH1_64 (addme, 0x1F, 0x0A, 0x07, PPC_INTEGER); /* addze addze. addzeo addzeo. */ -static inline void gen_op_addze (void) +static always_inline void gen_op_addze (void) { gen_op_move_T2_T0(); gen_op_add_ze(); gen_op_check_addc(); } -static inline void gen_op_addzeo (void) +static always_inline void gen_op_addzeo (void) { gen_op_move_T2_T0(); gen_op_add_ze(); @@ -785,13 +785,13 @@ static inline void gen_op_addzeo (void) gen_op_check_addo(); } #if defined(TARGET_PPC64) -static inline void gen_op_addze_64 (void) +static always_inline void gen_op_addze_64 (void) { gen_op_move_T2_T0(); gen_op_add_ze(); gen_op_check_addc_64(); } -static inline void gen_op_addzeo_64 (void) +static always_inline void gen_op_addzeo_64 (void) { gen_op_move_T2_T0(); gen_op_add_ze(); @@ -813,7 +813,7 @@ GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07, PPC_INTEGER); /* neg neg. nego nego. */ GEN_INT_ARITH1_64 (neg, 0x1F, 0x08, 0x03, PPC_INTEGER); /* subf subf. subfo subfo. */ -static inline void gen_op_subfo (void) +static always_inline void gen_op_subfo (void) { gen_op_move_T2_T0(); gen_op_subf(); @@ -821,7 +821,7 @@ static inline void gen_op_subfo (void) } #if defined(TARGET_PPC64) #define gen_op_subf_64 gen_op_subf -static inline void gen_op_subfo_64 (void) +static always_inline void gen_op_subfo_64 (void) { gen_op_move_T2_T0(); gen_op_subf(); @@ -830,12 +830,12 @@ static inline void gen_op_subfo_64 (void) #endif GEN_INT_ARITH2_64 (subf, 0x1F, 0x08, 0x01, PPC_INTEGER); /* subfc subfc. subfco subfco. */ -static inline void gen_op_subfc (void) +static always_inline void gen_op_subfc (void) { gen_op_subf(); gen_op_check_subfc(); } -static inline void gen_op_subfco (void) +static always_inline void gen_op_subfco (void) { gen_op_move_T2_T0(); gen_op_subf(); @@ -843,12 +843,12 @@ static inline void gen_op_subfco (void) gen_op_check_subfo(); } #if defined(TARGET_PPC64) -static inline void gen_op_subfc_64 (void) +static always_inline void gen_op_subfc_64 (void) { gen_op_subf(); gen_op_check_subfc_64(); } -static inline void gen_op_subfco_64 (void) +static always_inline void gen_op_subfco_64 (void) { gen_op_move_T2_T0(); gen_op_subf(); @@ -858,7 +858,7 @@ static inline void gen_op_subfco_64 (void) #endif GEN_INT_ARITH2_64 (subfc, 0x1F, 0x08, 0x00, PPC_INTEGER); /* subfe subfe. subfeo subfeo. */ -static inline void gen_op_subfeo (void) +static always_inline void gen_op_subfeo (void) { gen_op_move_T2_T0(); gen_op_subfe(); @@ -866,7 +866,7 @@ static inline void gen_op_subfeo (void) } #if defined(TARGET_PPC64) #define gen_op_subfe_64 gen_op_subfe -static inline void gen_op_subfeo_64 (void) +static always_inline void gen_op_subfeo_64 (void) { gen_op_move_T2_T0(); gen_op_subfe_64(); @@ -1407,7 +1407,7 @@ GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B) \ gen_##name(ctx, 1, 1); \ } -static inline void gen_andi_T0_64 (DisasContext *ctx, uint64_t mask) +static always_inline void gen_andi_T0_64 (DisasContext *ctx, uint64_t mask) { if (mask >> 32) gen_op_andi_T0_64(mask >> 32, mask & 0xFFFFFFFF); @@ -1415,7 +1415,7 @@ static inline void gen_andi_T0_64 (DisasContext *ctx, uint64_t mask) gen_op_andi_T0(mask); } -static inline void gen_andi_T1_64 (DisasContext *ctx, uint64_t mask) +static always_inline void gen_andi_T1_64 (DisasContext *ctx, uint64_t mask) { if (mask >> 32) gen_op_andi_T1_64(mask >> 32, mask & 0xFFFFFFFF); @@ -1423,8 +1423,8 @@ static inline void gen_andi_T1_64 (DisasContext *ctx, uint64_t mask) gen_op_andi_T1(mask); } -static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me, - uint32_t sh) +static always_inline void gen_rldinm (DisasContext *ctx, uint32_t mb, + uint32_t me, uint32_t sh) { gen_op_load_gpr_T0(rS(ctx->opcode)); if (likely(sh == 0)) { @@ -1453,7 +1453,7 @@ static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me, gen_set_Rc0(ctx); } /* rldicl - rldicl. */ -static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn) +static always_inline void gen_rldicl (DisasContext *ctx, int mbn, int shn) { uint32_t sh, mb; @@ -1463,7 +1463,7 @@ static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn) } GEN_PPC64_R4(rldicl, 0x1E, 0x00); /* rldicr - rldicr. */ -static inline void gen_rldicr (DisasContext *ctx, int men, int shn) +static always_inline void gen_rldicr (DisasContext *ctx, int men, int shn) { uint32_t sh, me; @@ -1473,7 +1473,7 @@ static inline void gen_rldicr (DisasContext *ctx, int men, int shn) } GEN_PPC64_R4(rldicr, 0x1E, 0x02); /* rldic - rldic. */ -static inline void gen_rldic (DisasContext *ctx, int mbn, int shn) +static always_inline void gen_rldic (DisasContext *ctx, int mbn, int shn) { uint32_t sh, mb; @@ -1483,7 +1483,8 @@ static inline void gen_rldic (DisasContext *ctx, int mbn, int shn) } GEN_PPC64_R4(rldic, 0x1E, 0x04); -static inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me) +static always_inline void gen_rldnm (DisasContext *ctx, uint32_t mb, + uint32_t me) { gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); @@ -1497,7 +1498,7 @@ static inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me) } /* rldcl - rldcl. */ -static inline void gen_rldcl (DisasContext *ctx, int mbn) +static always_inline void gen_rldcl (DisasContext *ctx, int mbn) { uint32_t mb; @@ -1506,7 +1507,7 @@ static inline void gen_rldcl (DisasContext *ctx, int mbn) } GEN_PPC64_R2(rldcl, 0x1E, 0x08); /* rldcr - rldcr. */ -static inline void gen_rldcr (DisasContext *ctx, int men) +static always_inline void gen_rldcr (DisasContext *ctx, int men) { uint32_t me; @@ -1515,7 +1516,7 @@ static inline void gen_rldcr (DisasContext *ctx, int men) } GEN_PPC64_R2(rldcr, 0x1E, 0x09); /* rldimi - rldimi. */ -static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) +static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) { uint64_t mask; uint32_t sh, mb; @@ -1583,7 +1584,7 @@ __GEN_LOGICAL2(sld, 0x1B, 0x00, PPC_64B); /* srad & srad. */ __GEN_LOGICAL2(srad, 0x1A, 0x18, PPC_64B); /* sradi & sradi. */ -static inline void gen_sradi (DisasContext *ctx, int n) +static always_inline void gen_sradi (DisasContext *ctx, int n) { uint64_t mask; int sh, mb, me; @@ -1937,7 +1938,8 @@ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) /*** Addressing modes ***/ /* Register indirect with immediate index : EA = (rA|0) + SIMM */ -static inline void gen_addr_imm_index (DisasContext *ctx, target_long maskl) +static always_inline void gen_addr_imm_index (DisasContext *ctx, + target_long maskl) { target_long simm = SIMM(ctx->opcode); @@ -1954,7 +1956,7 @@ static inline void gen_addr_imm_index (DisasContext *ctx, target_long maskl) #endif } -static inline void gen_addr_reg_index (DisasContext *ctx) +static always_inline void gen_addr_reg_index (DisasContext *ctx) { if (rA(ctx->opcode) == 0) { gen_op_load_gpr_T0(rB(ctx->opcode)); @@ -1968,7 +1970,7 @@ static inline void gen_addr_reg_index (DisasContext *ctx) #endif } -static inline void gen_addr_register (DisasContext *ctx) +static always_inline void gen_addr_register (DisasContext *ctx) { if (rA(ctx->opcode) == 0) { gen_op_reset_T0(); @@ -2964,7 +2966,8 @@ OP_ST_TABLE(fiwx); GEN_STXF(fiwx, 0x17, 0x1E, PPC_FLOAT_STFIWX); /*** Branch ***/ -static inline void gen_goto_tb (DisasContext *ctx, int n, target_ulong dest) +static always_inline void gen_goto_tb (DisasContext *ctx, int n, + target_ulong dest) { TranslationBlock *tb; tb = ctx->tb; @@ -2999,7 +3002,7 @@ static inline void gen_goto_tb (DisasContext *ctx, int n, target_ulong dest) } } -static inline void gen_setlr (DisasContext *ctx, target_ulong nip) +static always_inline void gen_setlr (DisasContext *ctx, target_ulong nip) { #if defined(TARGET_PPC64) if (ctx->sf_mode != 0 && (nip >> 32)) @@ -3039,7 +3042,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) #define BCOND_LR 1 #define BCOND_CTR 2 -static inline void gen_bcond (DisasContext *ctx, int type) +static always_inline void gen_bcond (DisasContext *ctx, int type) { target_ulong target = 0; target_ulong li; @@ -3399,7 +3402,7 @@ static void spr_noaccess (void *opaque, int sprn) #endif /* mfspr */ -static inline void gen_op_mfspr (DisasContext *ctx) +static always_inline void gen_op_mfspr (DisasContext *ctx) { void (*read_cb)(void *opaque, int sprn); uint32_t sprn = SPR(ctx->opcode); @@ -3765,7 +3768,8 @@ static GenOpFunc *gen_op_dcbz[4][4] = { #endif #endif -static inline void handler_dcbz (DisasContext *ctx, int dcache_line_size) +static always_inline void handler_dcbz (DisasContext *ctx, + int dcache_line_size) { int n; @@ -4913,8 +4917,9 @@ GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE_EXT) } /* All 405 MAC instructions are translated here */ -static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3, - int ra, int rb, int rt, int Rc) +static always_inline void gen_405_mulladd_insn (DisasContext *ctx, + int opc2, int opc3, + int ra, int rb, int rt, int Rc) { gen_op_load_gpr_T0(ra); gen_op_load_gpr_T1(rb); @@ -5551,13 +5556,13 @@ GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) \ } /* Handler for undefined SPE opcodes */ -static inline void gen_speundef (DisasContext *ctx) +static always_inline void gen_speundef (DisasContext *ctx) { GEN_EXCP_INVAL(ctx); } /* SPE load and stores */ -static inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh) +static always_inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh) { target_long simm = rB(ctx->opcode); @@ -5678,7 +5683,7 @@ static GenOpFunc *gen_op_spe_st##name[] = { \ #endif /* defined(CONFIG_USER_ONLY) */ #define GEN_SPE_LD(name, sh) \ -static inline void gen_evl##name (DisasContext *ctx) \ +static always_inline void gen_evl##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5690,7 +5695,7 @@ static inline void gen_evl##name (DisasContext *ctx) \ } #define GEN_SPE_LDX(name) \ -static inline void gen_evl##name##x (DisasContext *ctx) \ +static always_inline void gen_evl##name##x (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5707,7 +5712,7 @@ GEN_SPE_LD(name, sh); \ GEN_SPE_LDX(name) #define GEN_SPE_ST(name, sh) \ -static inline void gen_evst##name (DisasContext *ctx) \ +static always_inline void gen_evst##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5719,7 +5724,7 @@ static inline void gen_evst##name (DisasContext *ctx) \ } #define GEN_SPE_STX(name) \ -static inline void gen_evst##name##x (DisasContext *ctx) \ +static always_inline void gen_evst##name##x (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5741,7 +5746,7 @@ GEN_SPEOP_ST(name, sh) /* SPE arithmetic and logic */ #define GEN_SPEOP_ARITH2(name) \ -static inline void gen_##name (DisasContext *ctx) \ +static always_inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5754,7 +5759,7 @@ static inline void gen_##name (DisasContext *ctx) \ } #define GEN_SPEOP_ARITH1(name) \ -static inline void gen_##name (DisasContext *ctx) \ +static always_inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5766,7 +5771,7 @@ static inline void gen_##name (DisasContext *ctx) \ } #define GEN_SPEOP_COMP(name) \ -static inline void gen_##name (DisasContext *ctx) \ +static always_inline void gen_##name (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5806,7 +5811,7 @@ GEN_SPEOP_ARITH1(evextsh); GEN_SPEOP_ARITH1(evrndw); GEN_SPEOP_ARITH1(evcntlzw); GEN_SPEOP_ARITH1(evcntlsw); -static inline void gen_brinc (DisasContext *ctx) +static always_inline void gen_brinc (DisasContext *ctx) { /* Note: brinc is usable even if SPE is disabled */ gen_op_load_gpr64_T0(rA(ctx->opcode)); @@ -5816,7 +5821,7 @@ static inline void gen_brinc (DisasContext *ctx) } #define GEN_SPEOP_ARITH_IMM2(name) \ -static inline void gen_##name##i (DisasContext *ctx) \ +static always_inline void gen_##name##i (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5829,7 +5834,7 @@ static inline void gen_##name##i (DisasContext *ctx) \ } #define GEN_SPEOP_LOGIC_IMM2(name) \ -static inline void gen_##name##i (DisasContext *ctx) \ +static always_inline void gen_##name##i (DisasContext *ctx) \ { \ if (unlikely(!ctx->spe_enabled)) { \ GEN_EXCP_NO_AP(ctx); \ @@ -5852,7 +5857,7 @@ GEN_SPEOP_LOGIC_IMM2(evsrws); #define gen_evsrwiu gen_evsrwui GEN_SPEOP_LOGIC_IMM2(evrlw); -static inline void gen_evsplati (DisasContext *ctx) +static always_inline void gen_evsplati (DisasContext *ctx) { int32_t imm = (int32_t)(rA(ctx->opcode) << 27) >> 27; @@ -5860,7 +5865,7 @@ static inline void gen_evsplati (DisasContext *ctx) gen_op_store_T0_gpr64(rD(ctx->opcode)); } -static inline void gen_evsplatfi (DisasContext *ctx) +static always_inline void gen_evsplatfi (DisasContext *ctx) { uint32_t imm = rA(ctx->opcode) << 27; @@ -5901,7 +5906,7 @@ GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, PPC_SPE); //// GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE); //// GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); //// -static inline void gen_evsel (DisasContext *ctx) +static always_inline void gen_evsel (DisasContext *ctx) { if (unlikely(!ctx->spe_enabled)) { GEN_EXCP_NO_AP(ctx); @@ -5991,13 +5996,13 @@ GEN_SPEOP_ST(who, 2); #endif #endif #define _GEN_OP_SPE_STWWE(suffix) \ -static inline void gen_op_spe_stwwe_##suffix (void) \ +static always_inline void gen_op_spe_stwwe_##suffix (void) \ { \ gen_op_srli32_T1_64(); \ gen_op_spe_stwwo_##suffix(); \ } #define _GEN_OP_SPE_STWWE_LE(suffix) \ -static inline void gen_op_spe_stwwe_le_##suffix (void) \ +static always_inline void gen_op_spe_stwwe_le_##suffix (void) \ { \ gen_op_srli32_T1_64(); \ gen_op_spe_stwwo_le_##suffix(); \ @@ -6006,12 +6011,12 @@ static inline void gen_op_spe_stwwe_le_##suffix (void) \ #define GEN_OP_SPE_STWWE(suffix) \ _GEN_OP_SPE_STWWE(suffix); \ _GEN_OP_SPE_STWWE_LE(suffix); \ -static inline void gen_op_spe_stwwe_64_##suffix (void) \ +static always_inline void gen_op_spe_stwwe_64_##suffix (void) \ { \ gen_op_srli32_T1_64(); \ gen_op_spe_stwwo_64_##suffix(); \ } \ -static inline void gen_op_spe_stwwe_le_64_##suffix (void) \ +static always_inline void gen_op_spe_stwwe_le_64_##suffix (void) \ { \ gen_op_srli32_T1_64(); \ gen_op_spe_stwwo_le_64_##suffix(); \ @@ -6031,21 +6036,21 @@ GEN_SPEOP_ST(wwe, 2); GEN_SPEOP_ST(wwo, 2); #define GEN_SPE_LDSPLAT(name, op, suffix) \ -static inline void gen_op_spe_l##name##_##suffix (void) \ +static always_inline void gen_op_spe_l##name##_##suffix (void) \ { \ gen_op_##op##_##suffix(); \ gen_op_splatw_T1_64(); \ } #define GEN_OP_SPE_LHE(suffix) \ -static inline void gen_op_spe_lhe_##suffix (void) \ +static always_inline void gen_op_spe_lhe_##suffix (void) \ { \ gen_op_spe_lh_##suffix(); \ gen_op_sli16_T1_64(); \ } #define GEN_OP_SPE_LHX(suffix) \ -static inline void gen_op_spe_lhx_##suffix (void) \ +static always_inline void gen_op_spe_lhx_##suffix (void) \ { \ gen_op_spe_lh_##suffix(); \ gen_op_extsh_T1_64(); \ @@ -6221,7 +6226,7 @@ GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0x00000000, PPC_SPE); /*** SPE floating-point extension ***/ #define GEN_SPEFPUOP_CONV(name) \ -static inline void gen_##name (DisasContext *ctx) \ +static always_inline void gen_##name (DisasContext *ctx) \ { \ gen_op_load_gpr64_T0(rB(ctx->opcode)); \ gen_op_##name(); \ @@ -6376,7 +6381,7 @@ GEN_OPCODE_MARK(end); /*****************************************************************************/ /* Misc PowerPC helpers */ -static inline uint32_t load_xer (CPUState *env) +static always_inline uint32_t load_xer (CPUState *env) { return (xer_so << XER_SO) | (xer_ov << XER_OV) | @@ -6507,9 +6512,9 @@ void cpu_dump_statistics (CPUState *env, FILE*f, } /*****************************************************************************/ -static inline int gen_intermediate_code_internal (CPUState *env, - TranslationBlock *tb, - int search_pc) +static always_inline int gen_intermediate_code_internal (CPUState *env, + TranslationBlock *tb, + int search_pc) { DisasContext ctx, *ctxp = &ctx; opc_handler_t **table, *handler; -- cgit v1.2.3 From b33c17e12d1af68a5733094f33578847379ed892 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 17:30:34 +0000 Subject: PowerPC target coding style fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3348 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 11 +++++------ target-ppc/cpu.h | 1 - target-ppc/helper.c | 40 +++++++++++++++++++--------------------- target-ppc/op.c | 2 -- target-ppc/op_mem.h | 2 -- target-ppc/translate.c | 2 +- 6 files changed, 25 insertions(+), 33 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index f1722bb91..46179dd56 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -600,7 +600,7 @@ uint64_t cpu_ppc_load_purr (CPUState *env) uint64_t diff; diff = qemu_get_clock(vm_clock) - tb_env->purr_start; - + return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec); } #endif /* defined(TARGET_PPC64H) */ @@ -631,10 +631,10 @@ static always_inline void cpu_ppc_hdecr_excp (CPUState *env) } static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, - struct QEMUTimer *timer, - void (*raise_excp)(CPUState *), - uint32_t decr, uint32_t value, - int is_excp) + struct QEMUTimer *timer, + void (*raise_excp)(CPUState *), + uint32_t decr, uint32_t value, + int is_excp) { ppc_tb_t *tb_env = env->tb_env; uint64_t now, next; @@ -1151,7 +1151,6 @@ int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn), return 0; } - #if 0 /*****************************************************************************/ /* Handle system reset (for now, just stop emulation) */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e2d51ec07..ef70fa034 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -225,7 +225,6 @@ enum { POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only */ }; - /* Exceptions error codes */ enum { /* Exception subtypes for POWERPC_EXCP_ALIGN */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 205e35f49..86debbc3c 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -626,8 +626,8 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, tmp = ldl_phys(sr_base + 8); #if defined(DEBUG_SLB) if (loglevel != 0) { - fprintf(logfile, "%s: seg %d " PADDRX " %016" PRIx64 " %08" PRIx32 "\n", - __func__, n, sr_base, tmp64, tmp); + fprintf(logfile, "%s: seg %d " PADDRX " %016" PRIx64 " %08" + PRIx32 "\n", __func__, n, sr_base, tmp64, tmp); } #endif if (tmp64 & 0x0000000008000000ULL) { @@ -869,25 +869,25 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } } #if defined (DEBUG_MMU) - if (loglevel != 0) { - target_phys_addr_t curaddr; - uint32_t a0, a1, a2, a3; + if (loglevel != 0) { + target_phys_addr_t curaddr; + uint32_t a0, a1, a2, a3; + fprintf(logfile, + "Page table: " PADDRX " len " PADDRX "\n", + sdr, mask + 0x80); + for (curaddr = sdr; curaddr < (sdr + mask + 0x80); + curaddr += 16) { + a0 = ldl_phys(curaddr); + a1 = ldl_phys(curaddr + 4); + a2 = ldl_phys(curaddr + 8); + a3 = ldl_phys(curaddr + 12); + if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) { fprintf(logfile, - "Page table: " PADDRX " len " PADDRX "\n", - sdr, mask + 0x80); - for (curaddr = sdr; curaddr < (sdr + mask + 0x80); - curaddr += 16) { - a0 = ldl_phys(curaddr); - a1 = ldl_phys(curaddr + 4); - a2 = ldl_phys(curaddr + 8); - a3 = ldl_phys(curaddr + 12); - if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) { - fprintf(logfile, - PADDRX ": %08x %08x %08x %08x\n", - curaddr, a0, a1, a2, a3); - } - } + PADDRX ": %08x %08x %08x %08x\n", + curaddr, a0, a1, a2, a3); } + } + } #endif } else { #if defined (DEBUG_MMU) @@ -1714,7 +1714,6 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) env->DBAT[1][nr] = value; } - /*****************************************************************************/ /* TLB management */ void ppc_tlb_invalidate_all (CPUPPCState *env) @@ -1843,7 +1842,6 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) } #endif - /*****************************************************************************/ /* Special registers manipulation */ #if defined(TARGET_PPC64) diff --git a/target-ppc/op.c b/target-ppc/op.c index 2dc058efb..1412c09ae 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -120,7 +120,6 @@ #define REG 31 #include "op_template.h" - void OPPROTO op_print_mem_EA (void) { do_print_mem_EA(T0); @@ -1426,7 +1425,6 @@ void OPPROTO op_andi_T1_64 (void) } #endif - /* count leading zero */ void OPPROTO op_cntlzw (void) { diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 60c043386..ea1b4a347 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -482,7 +482,6 @@ static always_inline void glue(stfiwxr, MEMSUFFIX) (target_ulong EA, double d) glue(stl, MEMSUFFIX)(EA, u.u); } - PPC_STF_OP(fd_le, stfqr); PPC_STF_OP(fs_le, stfsr); PPC_STF_OP(fiwx_le, stfiwxr); @@ -1079,7 +1078,6 @@ _PPC_SPE_LD_OP_64(name, op) _PPC_SPE_LD_OP(name, op) #endif - #define _PPC_SPE_ST_OP(name, op) \ void OPPROTO glue(glue(op_spe_st, name), MEMSUFFIX) (void) \ { \ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 59d032d26..1ff4b17bb 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6566,7 +6566,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, branch_step = 1; else branch_step = 0; - ctx.singlestep_enabled = env->singlestep_enabled || single_step == 1;; + ctx.singlestep_enabled = env->singlestep_enabled || single_step == 1; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; -- cgit v1.2.3 From a9d9eb8fd45279fa8455afa03331296dbe2871ff Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 18:19:26 +0000 Subject: Implement PowerPC Altivec load & stores, used by Apple firmware for memcpy. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3349 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 11 ++-- target-ppc/exec.h | 6 +- target-ppc/op_mem.h | 60 +++++++++++++++++ target-ppc/op_template.h | 40 ++++++++++++ target-ppc/translate.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 274 insertions(+), 8 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index ef70fa034..9cbd1c9aa 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -292,7 +292,7 @@ typedef struct CPUPPCState CPUPPCState; typedef struct ppc_tb_t ppc_tb_t; typedef struct ppc_spr_t ppc_spr_t; typedef struct ppc_dcr_t ppc_dcr_t; -typedef struct ppc_avr_t ppc_avr_t; +typedef union ppc_avr_t ppc_avr_t; typedef union ppc_tlb_t ppc_tlb_t; /* SPR access micro-ops generations callbacks */ @@ -311,8 +311,11 @@ struct ppc_spr_t { }; /* Altivec registers (128 bits) */ -struct ppc_avr_t { - uint32_t u[4]; +union ppc_avr_t { + uint8_t u8[16]; + uint16_t u16[8]; + uint32_t u32[4]; + uint64_t u64[2]; }; /* Software TLB cache */ @@ -454,7 +457,7 @@ struct CPUPPCState { */ ppc_gpr_t t0, t1, t2; #endif - ppc_avr_t t0_avr, t1_avr, t2_avr; + ppc_avr_t avr0, avr1, avr2; /* general purpose registers */ ppc_gpr_t gpr[32]; diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 0c53de42b..3fedf493e 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -54,9 +54,9 @@ register unsigned long T2 asm(AREG3); #define T2_64 T2 #endif /* Provision for Altivec */ -#define T0_avr (env->t0_avr) -#define T1_avr (env->t1_avr) -#define T2_avr (env->t2_avr) +#define AVR0 (env->avr0) +#define AVR1 (env->avr1) +#define AVR2 (env->avr2) #define FT0 (env->ft0) #define FT1 (env->ft1) diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index ea1b4a347..ca48f5de0 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -1054,6 +1054,66 @@ void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void) RETURN(); } +/* Altivec vector extension */ +#if defined(WORDS_BIGENDIAN) +#define VR_DWORD0 0 +#define VR_DWORD1 1 +#else +#define VR_DWORD0 1 +#define VR_DWORD1 0 +#endif +void OPPROTO glue(op_vr_lvx, MEMSUFFIX) (void) +{ + AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint32_t)T0); + AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint32_t)T0 + 8); +} + +void OPPROTO glue(op_vr_lvx_le, MEMSUFFIX) (void) +{ + AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint32_t)T0); + AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint32_t)T0 + 8); +} + +void OPPROTO glue(op_vr_stvx, MEMSUFFIX) (void) +{ + glue(stq, MEMSUFFIX)((uint32_t)T0, AVR0.u64[VR_DWORD0]); + glue(stq, MEMSUFFIX)((uint32_t)T0 + 8, AVR0.u64[VR_DWORD1]); +} + +void OPPROTO glue(op_vr_stvx_le, MEMSUFFIX) (void) +{ + glue(stq, MEMSUFFIX)((uint32_t)T0, AVR0.u64[VR_DWORD1]); + glue(stq, MEMSUFFIX)((uint32_t)T0 + 8, AVR0.u64[VR_DWORD0]); +} + +#if defined(TARGET_PPC64) +void OPPROTO glue(op_vr_lvx_64, MEMSUFFIX) (void) +{ + AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint64_t)T0); + AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint64_t)T0 + 8); +} + +void OPPROTO glue(op_vr_lvx_le_64, MEMSUFFIX) (void) +{ + AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint64_t)T0); + AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint64_t)T0 + 8); +} + +void OPPROTO glue(op_vr_stvx_64, MEMSUFFIX) (void) +{ + glue(stq, MEMSUFFIX)((uint64_t)T0, AVR0.u64[VR_DWORD0]); + glue(stq, MEMSUFFIX)((uint64_t)T0 + 8, AVR0.u64[VR_DWORD1]); +} + +void OPPROTO glue(op_vr_stvx_le_64, MEMSUFFIX) (void) +{ + glue(stq, MEMSUFFIX)((uint64_t)T0, AVR0.u64[VR_DWORD1]); + glue(stq, MEMSUFFIX)((uint64_t)T0 + 8, AVR0.u64[VR_DWORD0]); +} +#endif +#undef VR_DWORD0 +#undef VR_DWORD1 + #if defined(TARGET_PPCEMB) /* SPE extension */ #define _PPC_SPE_LD_OP(name, op) \ diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index d45062592..28dc59c94 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -57,6 +57,7 @@ void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) } #endif +/* General purpose registers containing vector operands moves */ #if defined(TARGET_PPCEMB) void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void) { @@ -99,6 +100,45 @@ void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) #endif #endif /* defined(TARGET_PPCEMB) */ +/* Altivec registers moves */ +void OPPROTO glue(op_load_avr_A0_avr, REG) (void) +{ + AVR0 = env->avr[REG]; + RETURN(); +} + +void OPPROTO glue(op_load_avr_A1_avr, REG) (void) +{ + AVR1 = env->avr[REG]; + RETURN(); +} + +void OPPROTO glue(op_load_avr_A2_avr, REG) (void) +{ + AVR2 = env->avr[REG]; + RETURN(); +} + +void OPPROTO glue(op_store_A0_avr_avr, REG) (void) +{ + env->avr[REG] = AVR0; + RETURN(); +} + +void OPPROTO glue(op_store_A1_avr_avr, REG) (void) +{ + env->avr[REG] = AVR1; + RETURN(); +} + +#if 0 // unused +void OPPROTO glue(op_store_A2_avr_avr, REG) (void) +{ + env->avr[REG] = AVR2; + RETURN(); +} +#endif + #if REG <= 7 /* Condition register moves */ void OPPROTO glue(op_load_crf_T0_crf, REG) (void) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1ff4b17bb..a17066341 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -164,6 +164,7 @@ typedef struct DisasContext { int sf_mode; #endif int fpu_enabled; + int altivec_enabled; #if defined(TARGET_PPCEMB) int spe_enabled; #endif @@ -235,6 +236,9 @@ GEN_EXCP(ctx, POWERPC_EXCP_FPU, 0) #define GEN_EXCP_NO_AP(ctx) \ GEN_EXCP(ctx, POWERPC_EXCP_APU, 0) +#define GEN_EXCP_NO_VR(ctx) \ +GEN_EXCP(ctx, POWERPC_EXCP_VPU, 0) + /* Stop translation */ static always_inline void GEN_STOP (DisasContext *ctx) { @@ -5530,6 +5534,161 @@ GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE) */ } +/*** Altivec vector extension ***/ +/* Altivec registers moves */ +GEN32(gen_op_load_avr_A0, gen_op_load_avr_A0_avr); +GEN32(gen_op_load_avr_A1, gen_op_load_avr_A1_avr); +GEN32(gen_op_load_avr_A2, gen_op_load_avr_A2_avr); + +GEN32(gen_op_store_A0_avr, gen_op_store_A0_avr_avr); +GEN32(gen_op_store_A1_avr, gen_op_store_A1_avr_avr); +#if 0 // unused +GEN32(gen_op_store_A2_avr, gen_op_store_A2_avr_avr); +#endif + +#define op_vr_ldst(name) (*gen_op_##name[ctx->mem_idx])() +#if defined(CONFIG_USER_ONLY) +#if defined(TARGET_PPC64) +/* User-mode only - 64 bits mode */ +#define OP_VR_LD_TABLE(name) \ +static GenOpFunc *gen_op_vr_l##name[] = { \ + &gen_op_vr_l##name##_raw, \ + &gen_op_vr_l##name##_le_raw, \ + &gen_op_vr_l##name##_64_raw, \ + &gen_op_vr_l##name##_le_64_raw, \ +}; +#define OP_VR_ST_TABLE(name) \ +static GenOpFunc *gen_op_vr_st##name[] = { \ + &gen_op_vr_st##name##_raw, \ + &gen_op_vr_st##name##_le_raw, \ + &gen_op_vr_st##name##_64_raw, \ + &gen_op_vr_st##name##_le_64_raw, \ +}; +#else /* defined(TARGET_PPC64) */ +/* User-mode only - 32 bits mode */ +#define OP_VR_LD_TABLE(name) \ +static GenOpFunc *gen_op_vr_l##name[] = { \ + &gen_op_vr_l##name##_raw, \ + &gen_op_vr_l##name##_le_raw, \ +}; +#define OP_VR_ST_TABLE(name) \ +static GenOpFunc *gen_op_vr_st##name[] = { \ + &gen_op_vr_st##name##_raw, \ + &gen_op_vr_st##name##_le_raw, \ +}; +#endif /* defined(TARGET_PPC64) */ +#else /* defined(CONFIG_USER_ONLY) */ +#if defined(TARGET_PPC64H) +/* Full system with hypervisor mode */ +#define OP_VR_LD_TABLE(name) \ +static GenOpFunc *gen_op_vr_l##name[] = { \ + &gen_op_vr_l##name##_user, \ + &gen_op_vr_l##name##_le_user, \ + &gen_op_vr_l##name##_64_user, \ + &gen_op_vr_l##name##_le_64_user, \ + &gen_op_vr_l##name##_kernel, \ + &gen_op_vr_l##name##_le_kernel, \ + &gen_op_vr_l##name##_64_kernel, \ + &gen_op_vr_l##name##_le_64_kernel, \ + &gen_op_vr_l##name##_hypv, \ + &gen_op_vr_l##name##_le_hypv, \ + &gen_op_vr_l##name##_64_hypv, \ + &gen_op_vr_l##name##_le_64_hypv, \ +}; +#define OP_VR_ST_TABLE(name) \ +static GenOpFunc *gen_op_vr_st##name[] = { \ + &gen_op_vr_st##name##_user, \ + &gen_op_vr_st##name##_le_user, \ + &gen_op_vr_st##name##_64_user, \ + &gen_op_vr_st##name##_le_64_user, \ + &gen_op_vr_st##name##_kernel, \ + &gen_op_vr_st##name##_le_kernel, \ + &gen_op_vr_st##name##_64_kernel, \ + &gen_op_vr_st##name##_le_64_kernel, \ + &gen_op_vr_st##name##_hypv, \ + &gen_op_vr_st##name##_le_hypv, \ + &gen_op_vr_st##name##_64_hypv, \ + &gen_op_vr_st##name##_le_64_hypv, \ +}; +#elif defined(TARGET_PPC64) +/* Full system - 64 bits mode */ +#define OP_VR_LD_TABLE(name) \ +static GenOpFunc *gen_op_vr_l##name[] = { \ + &gen_op_vr_l##name##_user, \ + &gen_op_vr_l##name##_le_user, \ + &gen_op_vr_l##name##_64_user, \ + &gen_op_vr_l##name##_le_64_user, \ + &gen_op_vr_l##name##_kernel, \ + &gen_op_vr_l##name##_le_kernel, \ + &gen_op_vr_l##name##_64_kernel, \ + &gen_op_vr_l##name##_le_64_kernel, \ +}; +#define OP_VR_ST_TABLE(name) \ +static GenOpFunc *gen_op_vr_st##name[] = { \ + &gen_op_vr_st##name##_user, \ + &gen_op_vr_st##name##_le_user, \ + &gen_op_vr_st##name##_64_user, \ + &gen_op_vr_st##name##_le_64_user, \ + &gen_op_vr_st##name##_kernel, \ + &gen_op_vr_st##name##_le_kernel, \ + &gen_op_vr_st##name##_64_kernel, \ + &gen_op_vr_st##name##_le_64_kernel, \ +}; +#else /* defined(TARGET_PPC64) */ +/* Full system - 32 bits mode */ +#define OP_VR_LD_TABLE(name) \ +static GenOpFunc *gen_op_vr_l##name[] = { \ + &gen_op_vr_l##name##_user, \ + &gen_op_vr_l##name##_le_user, \ + &gen_op_vr_l##name##_kernel, \ + &gen_op_vr_l##name##_le_kernel, \ +}; +#define OP_VR_ST_TABLE(name) \ +static GenOpFunc *gen_op_vr_st##name[] = { \ + &gen_op_vr_st##name##_user, \ + &gen_op_vr_st##name##_le_user, \ + &gen_op_vr_st##name##_kernel, \ + &gen_op_vr_st##name##_le_kernel, \ +}; +#endif /* defined(TARGET_PPC64) */ +#endif /* defined(CONFIG_USER_ONLY) */ + +#define GEN_VR_LDX(name, opc2, opc3) \ +GEN_HANDLER(l##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) \ +{ \ + if (unlikely(!ctx->altivec_enabled)) { \ + GEN_EXCP_NO_VR(ctx); \ + return; \ + } \ + gen_addr_reg_index(ctx); \ + op_vr_ldst(vr_l##name); \ + gen_op_store_A0_avr(rD(ctx->opcode)); \ +} + +#define GEN_VR_STX(name, opc2, opc3) \ +GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) \ +{ \ + if (unlikely(!ctx->altivec_enabled)) { \ + GEN_EXCP_NO_VR(ctx); \ + return; \ + } \ + gen_addr_reg_index(ctx); \ + gen_op_load_avr_A0(rS(ctx->opcode)); \ + op_vr_ldst(vr_st##name); \ +} + +OP_VR_LD_TABLE(vx); +GEN_VR_LDX(vx, 0x07, 0x03); +/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */ +#define gen_op_vr_lvxl gen_op_vr_lvx +GEN_VR_LDX(vxl, 0x07, 0x0B); + +OP_VR_ST_TABLE(vx); +GEN_VR_STX(vx, 0x07, 0x07); +/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */ +#define gen_op_vr_stvxl gen_op_vr_stvx +GEN_VR_STX(vxl, 0x07, 0x0F); + #if defined(TARGET_PPCEMB) /*** SPE extension ***/ @@ -6553,11 +6712,15 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, ctx.dcache_line_size = env->dcache_line_size; ctx.fpu_enabled = msr_fp; #if defined(TARGET_PPCEMB) - if (env->flags & POWERPC_FLAG_SPE) + if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) ctx.spe_enabled = msr_spe; else ctx.spe_enabled = 0; #endif + if ((env->flags & POWERPC_FLAG_VRE) && msr_vr) + ctx.altivec_enabled = msr_vr; + else + ctx.altivec_enabled = 0; if ((env->flags & POWERPC_FLAG_SE) && msr_se) single_step = 1; else -- cgit v1.2.3 From 417bf01068031468f9e95bdad928f368b1bc385d Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 7 Oct 2007 23:10:08 +0000 Subject: Work-around C89 and/or "old" gcc unspecified behavior (#if in macro calls). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3350 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 17 +++++++---------- target-ppc/translate_init.c | 27 +++++++++------------------ 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index a17066341..eb795fb6f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3297,16 +3297,17 @@ GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64B) #endif /* sc */ +#if defined(CONFIG_USER_ONLY) +#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER +#else +#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL +#endif GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW) { uint32_t lev; lev = (ctx->opcode >> 5) & 0x7F; -#if defined(CONFIG_USER_ONLY) - GEN_EXCP(ctx, POWERPC_EXCP_SYSCALL_USER, lev); -#else - GEN_EXCP(ctx, POWERPC_EXCP_SYSCALL, lev); -#endif + GEN_EXCP(ctx, POWERPC_SYSCALL, lev); } /*** Trap ***/ @@ -6830,11 +6831,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, } else if (unlikely(single_step != 0 && (ctx.nip <= 0x100 || ctx.nip > 0xF00 || (ctx.nip & 0xFC) != 0x04) && -#if defined(CONFIG_USER_ONLY) - ctx.exception != POWERPC_EXCP_SYSCALL_USER && -#else - ctx.exception != POWERPC_EXCP_SYSCALL && -#endif + ctx.exception != POWERPC_SYSCALL && ctx.exception != POWERPC_EXCP_TRAP)) { GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index edff5cd90..7ba9b1965 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4024,6 +4024,12 @@ static void init_proc_7455 (CPUPPCState *env) #define POWERPC_BFDM_970 (bfd_mach_ppc64) #define POWERPC_FLAG_970 (POWERPC_FLAG_VRE) +#if defined(CONFIG_USER_ONLY) +#define POWERPC970_HID5_INIT 0x00000080 +#else +#define POWERPC970_HID5_INIT 0x00000000 +#endif + static void init_proc_970 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4050,12 +4056,7 @@ static void init_proc_970 (CPUPPCState *env) spr_register(env, SPR_970_HID5, "HID5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, -#if defined(CONFIG_USER_ONLY) - 0x00000080 -#else - 0x00000000 -#endif - ); + POWERPC970_HID5_INIT); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -4123,12 +4124,7 @@ static void init_proc_970FX (CPUPPCState *env) spr_register(env, SPR_970_HID5, "HID5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, -#if defined(CONFIG_USER_ONLY) - 0x00000080 -#else - 0x00000000 -#endif - ); + POWERPC970_HID5_INIT); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -4196,12 +4192,7 @@ static void init_proc_970GX (CPUPPCState *env) spr_register(env, SPR_970_HID5, "HID5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, -#if defined(CONFIG_USER_ONLY) - 0x00000080 -#else - 0x00000000 -#endif - ); + POWERPC970_HID5_INIT); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); -- cgit v1.2.3 From 7a3a6927b656b1b6b6c59961cfb098f315ffee0e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 8 Oct 2007 02:23:00 +0000 Subject: Add missing exception vectors for PowerPC 7x5. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3351 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7ba9b1965..f0adf0edf 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2495,6 +2495,32 @@ static void init_excp_750FX (CPUPPCState *env) #endif } +/* XXX: Check if this is correct */ +static void init_excp_7x5 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + static void init_excp_7400 (CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) @@ -3577,7 +3603,7 @@ static void init_proc_7x5 (CPUPPCState *env) gen_low_BATs(env); gen_high_BATs(env); gen_6xx_7xx_soft_tlb(env, 64, 2); - /* XXX: exception vectors ? */ + init_excp_7x5(env); env->dcache_line_size = 32; env->icache_line_size = 32; /* Allocate hardware IRQ controller */ -- cgit v1.2.3 From 4e80effcf961b0ce3b794d239225aacb7f48f38c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 8 Oct 2007 02:35:41 +0000 Subject: Implement exception prefix feature for PowerPC 601. Fix PowerPC 601 hardware reset vector. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3352 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 13 +++++++------ target-ppc/translate_init.c | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 86debbc3c..3d686c10a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1996,16 +1996,17 @@ int do_store_msr (CPUPPCState *env, target_ulong value) tlb_flush(env, 1); env->interrupt_request |= CPU_INTERRUPT_EXITTB; } -#if 0 - if (loglevel != 0) { - fprintf(logfile, "%s: T0 %08lx\n", __func__, value); - } -#endif +#if !defined (CONFIG_USER_ONLY) if (unlikely((env->flags & POWERPC_FLAG_TGPR) && ((value >> MSR_TGPR) & 1) != msr_tgpr)) { /* Swap temporary saved registers with GPRs */ swap_gpr_tgpr(env); } + if (unlikely((value >> MSR_EP) & 1) != msr_ep) { + /* Change the exception prefix on PowerPC 601 */ + env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; + } +#endif #if defined (TARGET_PPC64) msr_sf = (value >> MSR_SF) & 1; msr_isf = (value >> MSR_ISF) & 1; @@ -2899,7 +2900,7 @@ void cpu_ppc_reset (void *opaque) #endif msr_ap = 0; /* TO BE CHECKED */ msr_sa = 0; /* TO BE CHECKED */ - msr_ip = 0; /* TO BE CHECKED */ + msr_ep = 1; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f0adf0edf..9f465bdf1 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2322,7 +2322,7 @@ static void init_excp_601 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000; env->excp_prefix = 0xFFF00000; /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; + env->hreset_vector = 0x00000100UL; #endif } -- cgit v1.2.3 From 141c8ae2250c3fbdb954511e1da165a5705859e0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 8 Oct 2007 02:44:11 +0000 Subject: Real-mode only PowerPC 40x do not have any TLBs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3353 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 3 ++- target-ppc/translate_init.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 3d686c10a..9caeb25b3 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2911,7 +2911,8 @@ void cpu_ppc_reset (void *opaque) msr_pr = 1; #else env->nip = env->hreset_vector | env->excp_prefix; - ppc_tlb_invalidate_all(env); + if (env->mmu_model != POWERPC_MMU_REAL_4xx) + ppc_tlb_invalidate_all(env); #endif do_compute_hflags(env); env->reserve = -1; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 9f465bdf1..89987d640 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2729,7 +2729,6 @@ static void init_proc_IOP480 (CPUPPCState *env) /* PowerPC 403 */ #define POWERPC_INSNS_403 (POWERPC_INSNS_EMB | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) #define POWERPC_MSRM_403 (0x000000000007D00DULL) #define POWERPC_MMU_403 (POWERPC_MMU_REAL_4xx) -- cgit v1.2.3 From 25ba3a681213390e9212dbc987d61843c3b41d5b Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 8 Oct 2007 02:58:07 +0000 Subject: Remove synonymous in PowerPC MSR bits definitions. Fix MSR EP bit buggy definition. Remove unuseful MSR flags. Fix MSR bits and flags definitions for most supported PowerPC implementations. Add MSR definitions/flags constistency checks and optional dump. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3354 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 35 +++----- target-ppc/helper.c | 20 ++--- target-ppc/translate_init.c | 210 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 193 insertions(+), 72 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 9cbd1c9aa..f4d9004f2 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -354,8 +354,7 @@ union ppc_tlb_t { #define MSR_AP 23 /* Access privilege state on 602 hflags */ #define MSR_SA 22 /* Supervisor access mode on 602 hflags */ #define MSR_KEY 19 /* key bit on 603e */ -#define MSR_POW 18 /* Power management x */ -#define MSR_WE 18 /* Wait state enable on embedded PowerPC x */ +#define MSR_POW 18 /* Power management */ #define MSR_TGPR 17 /* TGPR usage on 602/603 x */ #define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */ #define MSR_ILE 16 /* Interrupt little-endian mode */ @@ -371,11 +370,10 @@ union ppc_tlb_t { #define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */ #define MSR_FE1 8 /* Floating point exception mode 1 hflags */ #define MSR_AL 7 /* AL bit on POWER */ -#define MSR_IP 6 /* Interrupt prefix */ +#define MSR_EP 3 /* Exception prefix on 601 */ #define MSR_IR 5 /* Instruction relocate */ #define MSR_DR 4 /* Data relocate */ -#define MSR_PE 3 /* Protection enable on 403 x */ -#define MSR_EP 3 /* Exception prefix on 601 x */ +#define MSR_PE 3 /* Protection enable on 403 */ #define MSR_PX 2 /* Protection exclusive on 403 x */ #define MSR_PMM 2 /* Performance monitor mark on POWER x */ #define MSR_RI 1 /* Recoverable interrupt 1 */ @@ -392,7 +390,6 @@ union ppc_tlb_t { #define msr_sa env->msr[MSR_SA] #define msr_key env->msr[MSR_KEY] #define msr_pow env->msr[MSR_POW] -#define msr_we env->msr[MSR_WE] #define msr_tgpr env->msr[MSR_TGPR] #define msr_ce env->msr[MSR_CE] #define msr_ile env->msr[MSR_ILE] @@ -408,7 +405,6 @@ union ppc_tlb_t { #define msr_de env->msr[MSR_DE] #define msr_fe1 env->msr[MSR_FE1] #define msr_al env->msr[MSR_AL] -#define msr_ip env->msr[MSR_IP] #define msr_ir env->msr[MSR_IR] #define msr_dr env->msr[MSR_DR] #define msr_pe env->msr[MSR_PE] @@ -419,30 +415,23 @@ union ppc_tlb_t { #define msr_le env->msr[MSR_LE] enum { - /* Beware that MSR bits are given using IBM standard (ie MSB is 0 !) */ POWERPC_FLAG_NONE = 0x00000000, /* Flag for MSR bit 25 signification (VRE/SPE) */ POWERPC_FLAG_SPE = 0x00000001, POWERPC_FLAG_VRE = 0x00000002, - /* Flag for MSR bit 18 may not be needed... */ - POWERPC_FLAG_POW = 0x00000004, - POWERPC_FLAG_WE = 0x00000008, /* Flag for MSR bit 17 signification (TGPR/CE) */ - POWERPC_FLAG_TGPR = 0x00000010, - POWERPC_FLAG_CE = 0x00000020, + POWERPC_FLAG_TGPR = 0x00000004, + POWERPC_FLAG_CE = 0x00000008, /* Flag for MSR bit 10 signification (SE/DWE/UBLE) */ - POWERPC_FLAG_SE = 0x00000040, - POWERPC_FLAG_DWE = 0x00000080, - POWERPC_FLAG_UBLE = 0x00000100, + POWERPC_FLAG_SE = 0x00000010, + POWERPC_FLAG_DWE = 0x00000020, + POWERPC_FLAG_UBLE = 0x00000040, /* Flag for MSR bit 9 signification (BE/DE) */ - POWERPC_FLAG_BE = 0x00000200, - POWERPC_FLAG_DE = 0x00000400, - /* Flag for MSR bit 3 signification (PE/EP) */ - POWERPC_FLAG_PE = 0x00000800, - POWERPC_FLAG_EP = 0x00001000, + POWERPC_FLAG_BE = 0x00000080, + POWERPC_FLAG_DE = 0x00000100, /* Flag for MSR but 2 signification (PX/PMM) */ - POWERPC_FLAG_PX = 0x00002000, - POWERPC_FLAG_PMM = 0x00004000, + POWERPC_FLAG_PX = 0x00000200, + POWERPC_FLAG_PMM = 0x00000400, }; /*****************************************************************************/ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 9caeb25b3..c4eab18fc 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1964,7 +1964,7 @@ target_ulong do_load_msr (CPUPPCState *env) ((target_ulong)msr_ap << MSR_AP) | ((target_ulong)msr_sa << MSR_SA) | ((target_ulong)msr_key << MSR_KEY) | - ((target_ulong)msr_pow << MSR_POW) | /* POW / WE */ + ((target_ulong)msr_pow << MSR_POW) | ((target_ulong)msr_tgpr << MSR_TGPR) | /* TGPR / CE */ ((target_ulong)msr_ile << MSR_ILE) | ((target_ulong)msr_ee << MSR_EE) | @@ -1976,10 +1976,10 @@ target_ulong do_load_msr (CPUPPCState *env) ((target_ulong)msr_be << MSR_BE) | /* BE / DE */ ((target_ulong)msr_fe1 << MSR_FE1) | ((target_ulong)msr_al << MSR_AL) | - ((target_ulong)msr_ip << MSR_IP) | - ((target_ulong)msr_ir << MSR_IR) | /* IR / IS */ - ((target_ulong)msr_dr << MSR_DR) | /* DR / DS */ - ((target_ulong)msr_pe << MSR_PE) | /* PE / EP */ + ((target_ulong)msr_ep << MSR_EP) | + ((target_ulong)msr_ir << MSR_IR) | + ((target_ulong)msr_dr << MSR_DR) | + ((target_ulong)msr_pe << MSR_PE) | ((target_ulong)msr_px << MSR_PX) | /* PX / PMM */ ((target_ulong)msr_ri << MSR_RI) | ((target_ulong)msr_le << MSR_LE); @@ -2017,7 +2017,7 @@ int do_store_msr (CPUPPCState *env, target_ulong value) msr_ap = (value >> MSR_AP) & 1; msr_sa = (value >> MSR_SA) & 1; msr_key = (value >> MSR_KEY) & 1; - msr_pow = (value >> MSR_POW) & 1; /* POW / WE */ + msr_pow = (value >> MSR_POW) & 1; msr_tgpr = (value >> MSR_TGPR) & 1; /* TGPR / CE */ msr_ile = (value >> MSR_ILE) & 1; msr_ee = (value >> MSR_EE) & 1; @@ -2029,10 +2029,10 @@ int do_store_msr (CPUPPCState *env, target_ulong value) msr_be = (value >> MSR_BE) & 1; /* BE / DE */ msr_fe1 = (value >> MSR_FE1) & 1; msr_al = (value >> MSR_AL) & 1; - msr_ip = (value >> MSR_IP) & 1; - msr_ir = (value >> MSR_IR) & 1; /* IR / IS */ - msr_dr = (value >> MSR_DR) & 1; /* DR / DS */ - msr_pe = (value >> MSR_PE) & 1; /* PE / EP */ + msr_ep = (value >> MSR_EP) & 1; + msr_ir = (value >> MSR_IR) & 1; + msr_dr = (value >> MSR_DR) & 1; + msr_pe = (value >> MSR_PE) & 1; msr_px = (value >> MSR_PX) & 1; /* PX / PMM */ msr_ri = (value >> MSR_RI) & 1; msr_le = (value >> MSR_LE) & 1; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 89987d640..0210de853 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2620,7 +2620,7 @@ static void init_excp_970 (CPUPPCState *env) #define POWERPC_EXCP_401 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_401 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) static void init_proc_401 (CPUPPCState *env) { @@ -2645,7 +2645,7 @@ static void init_proc_401 (CPUPPCState *env) #define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401x2 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_401x2 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) static void init_proc_401x2 (CPUPPCState *env) { @@ -2677,7 +2677,7 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401x3 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_401x3 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) __attribute__ (( unused )) static void init_proc_401x3 (CPUPPCState *env) @@ -2705,7 +2705,7 @@ static void init_proc_401x3 (CPUPPCState *env) #define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) #define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) -#define POWERPC_FLAG_IOP480 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_IOP480 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) static void init_proc_IOP480 (CPUPPCState *env) { @@ -2735,7 +2735,7 @@ static void init_proc_IOP480 (CPUPPCState *env) #define POWERPC_EXCP_403 (POWERPC_EXCP_40x) #define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403 (bfd_mach_ppc_403) -#define POWERPC_FLAG_403 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_403 (POWERPC_FLAG_CE | POWERPC_FLAG_PX) static void init_proc_403 (CPUPPCState *env) { @@ -2764,7 +2764,7 @@ static void init_proc_403 (CPUPPCState *env) #define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) #define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) -#define POWERPC_FLAG_403GCX (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_403GCX (POWERPC_FLAG_CE | POWERPC_FLAG_PX) static void init_proc_403GCX (CPUPPCState *env) { @@ -2808,7 +2808,8 @@ static void init_proc_403GCX (CPUPPCState *env) #define POWERPC_EXCP_405 (POWERPC_EXCP_40x) #define POWERPC_INPUT_405 (PPC_FLAGS_INPUT_405) #define POWERPC_BFDM_405 (bfd_mach_ppc_403) -#define POWERPC_FLAG_405 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_405 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) static void init_proc_405 (CPUPPCState *env) { @@ -2850,7 +2851,8 @@ static void init_proc_405 (CPUPPCState *env) #define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440EP (bfd_mach_ppc_403) -#define POWERPC_FLAG_440EP (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_440EP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) static void init_proc_440EP (CPUPPCState *env) { @@ -2898,7 +2900,8 @@ static void init_proc_440EP (CPUPPCState *env) #define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440GP (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440GP (bfd_mach_ppc_403) -#define POWERPC_FLAG_440GP (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_440GP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) static void init_proc_440GP (CPUPPCState *env) { @@ -2928,7 +2931,8 @@ static void init_proc_440GP (CPUPPCState *env) #define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) -#define POWERPC_FLAG_440x4 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_440x4 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) __attribute__ (( unused )) static void init_proc_440x4 (CPUPPCState *env) @@ -2959,7 +2963,8 @@ static void init_proc_440x4 (CPUPPCState *env) #define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_440x5 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) -#define POWERPC_FLAG_440x5 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_440x5 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) static void init_proc_440x5 (CPUPPCState *env) { @@ -3007,7 +3012,8 @@ static void init_proc_440x5 (CPUPPCState *env) #define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460 (bfd_mach_ppc_403) -#define POWERPC_FLAG_460 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_460 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) __attribute__ (( unused )) static void init_proc_460 (CPUPPCState *env) @@ -3064,7 +3070,8 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) #define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460F (bfd_mach_ppc_403) -#define POWERPC_FLAG_460F (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_460F (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) __attribute__ (( unused )) static void init_proc_460F (CPUPPCState *env) @@ -3188,12 +3195,12 @@ static void init_proc_e500 (CPUPPCState *env) /* PowerPC 601 */ #define POWERPC_INSNS_601 (POWERPC_INSNS_6xx | PPC_CACHE_DCBZ | \ PPC_SEGMENT | PPC_EXTERN | PPC_POWER_BR) -#define POWERPC_MSRM_601 (0x000000000000FE70ULL) +#define POWERPC_MSRM_601 (0x000000000000FD70ULL) //#define POWERPC_MMU_601 (POWERPC_MMU_601) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_601 (bfd_mach_ppc_601) -#define POWERPC_FLAG_601 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_601 (POWERPC_FLAG_SE) static void init_proc_601 (CPUPPCState *env) { @@ -3248,7 +3255,8 @@ static void init_proc_601 (CPUPPCState *env) //#define POWERPC_EXCP_602 (POWERPC_EXCP_602) #define POWERPC_INPUT_602 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_602 (bfd_mach_ppc_602) -#define POWERPC_FLAG_602 (POWERPC_FLAG_TGPR) +#define POWERPC_FLAG_602 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE) static void init_proc_602 (CPUPPCState *env) { @@ -3279,12 +3287,13 @@ static void init_proc_602 (CPUPPCState *env) /* PowerPC 603 */ #define POWERPC_INSNS_603 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) -#define POWERPC_MSRM_603 (0x000000000001FF73ULL) +#define POWERPC_MSRM_603 (0x000000000007FF73ULL) #define POWERPC_MMU_603 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_603 (POWERPC_EXCP_603) #define POWERPC_INPUT_603 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_603 (bfd_mach_ppc_603) -#define POWERPC_FLAG_603 (POWERPC_FLAG_TGPR) +#define POWERPC_FLAG_603 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE) static void init_proc_603 (CPUPPCState *env) { @@ -3320,7 +3329,8 @@ static void init_proc_603 (CPUPPCState *env) //#define POWERPC_EXCP_603E (POWERPC_EXCP_603E) #define POWERPC_INPUT_603E (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_603E (bfd_mach_ppc_ec603e) -#define POWERPC_FLAG_603E (POWERPC_FLAG_TGPR) +#define POWERPC_FLAG_603E (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE) static void init_proc_603E (CPUPPCState *env) { @@ -3361,7 +3371,8 @@ static void init_proc_603E (CPUPPCState *env) //#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) #define POWERPC_INPUT_G2 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) -#define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR) +#define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE) static void init_proc_G2 (CPUPPCState *env) { @@ -3404,7 +3415,8 @@ static void init_proc_G2 (CPUPPCState *env) #define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) #define POWERPC_INPUT_G2LE (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) -#define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR) +#define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE) static void init_proc_G2LE (CPUPPCState *env) { @@ -3447,7 +3459,8 @@ static void init_proc_G2LE (CPUPPCState *env) //#define POWERPC_EXCP_604 (POWERPC_EXCP_604) #define POWERPC_INPUT_604 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_604 (bfd_mach_ppc_604) -#define POWERPC_FLAG_604 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_604 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM) static void init_proc_604 (CPUPPCState *env) { @@ -3477,12 +3490,13 @@ static void init_proc_604 (CPUPPCState *env) /* PowerPC 740/750 (aka G3) */ #define POWERPC_INSNS_7x0 (POWERPC_INSNS_WORKS | PPC_EXTERN) -#define POWERPC_MSRM_7x0 (0x000000000007FF77ULL) +#define POWERPC_MSRM_7x0 (0x000000000005FF77ULL) #define POWERPC_MMU_7x0 (POWERPC_MMU_32B) //#define POWERPC_EXCP_7x0 (POWERPC_EXCP_7x0) #define POWERPC_INPUT_7x0 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7x0 (bfd_mach_ppc_750) -#define POWERPC_FLAG_7x0 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_7x0 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM) static void init_proc_7x0 (CPUPPCState *env) { @@ -3514,12 +3528,13 @@ static void init_proc_7x0 (CPUPPCState *env) /* PowerPC 750FX/GX */ #define POWERPC_INSNS_750fx (POWERPC_INSNS_WORKS | PPC_EXTERN) -#define POWERPC_MSRM_750fx (0x000000000007FF77ULL) +#define POWERPC_MSRM_750fx (0x000000000005FF77ULL) #define POWERPC_MMU_750fx (POWERPC_MMU_32B) #define POWERPC_EXCP_750fx (POWERPC_EXCP_7x0) #define POWERPC_INPUT_750fx (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_750fx (bfd_mach_ppc_750) -#define POWERPC_FLAG_750fx (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_750fx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM) static void init_proc_750fx (CPUPPCState *env) { @@ -3558,12 +3573,13 @@ static void init_proc_750fx (CPUPPCState *env) /* PowerPC 745/755 */ #define POWERPC_INSNS_7x5 (POWERPC_INSNS_WORKS | PPC_EXTERN | PPC_6xx_TLB) -#define POWERPC_MSRM_7x5 (0x000000000007FF77ULL) +#define POWERPC_MSRM_7x5 (0x000000000005FF77ULL) #define POWERPC_MMU_7x5 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_7x5 (POWERPC_EXCP_7x5) #define POWERPC_INPUT_7x5 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7x5 (bfd_mach_ppc_750) -#define POWERPC_FLAG_7x5 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_7x5 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM) static void init_proc_7x5 (CPUPPCState *env) { @@ -3622,7 +3638,8 @@ static void init_proc_7x5 (CPUPPCState *env) #define POWERPC_EXCP_7400 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7400 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7400 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7400 (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_7400 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) static void init_proc_7400 (CPUPPCState *env) { @@ -3652,7 +3669,8 @@ static void init_proc_7400 (CPUPPCState *env) #define POWERPC_EXCP_7410 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7410 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7410 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7410 (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_7410 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) static void init_proc_7410 (CPUPPCState *env) { @@ -3694,7 +3712,8 @@ static void init_proc_7410 (CPUPPCState *env) #define POWERPC_EXCP_7440 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7440 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7440 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7440 (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_7440 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) __attribute__ (( unused )) static void init_proc_7440 (CPUPPCState *env) @@ -3763,7 +3782,8 @@ static void init_proc_7440 (CPUPPCState *env) #define POWERPC_EXCP_7450 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7450 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7450 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7450 (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_7450 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) __attribute__ (( unused )) static void init_proc_7450 (CPUPPCState *env) @@ -3834,7 +3854,8 @@ static void init_proc_7450 (CPUPPCState *env) #define POWERPC_EXCP_7445 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7445 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7445 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7445 (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_7445 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) __attribute__ (( unused )) static void init_proc_7445 (CPUPPCState *env) @@ -3937,7 +3958,8 @@ static void init_proc_7445 (CPUPPCState *env) #define POWERPC_EXCP_7455 (POWERPC_EXCP_74xx) #define POWERPC_INPUT_7455 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7455 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7455 (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_7455 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) __attribute__ (( unused )) static void init_proc_7455 (CPUPPCState *env) @@ -4047,7 +4069,8 @@ static void init_proc_7455 (CPUPPCState *env) //#define POWERPC_EXCP_970 (POWERPC_EXCP_970) #define POWERPC_INPUT_970 (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970 (bfd_mach_ppc64) -#define POWERPC_FLAG_970 (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_970 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) #if defined(CONFIG_USER_ONLY) #define POWERPC970_HID5_INIT 0x00000080 @@ -4121,7 +4144,8 @@ static void init_proc_970 (CPUPPCState *env) #define POWERPC_EXCP_970FX (POWERPC_EXCP_970) #define POWERPC_INPUT_970FX (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970FX (bfd_mach_ppc64) -#define POWERPC_FLAG_970FX (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_970FX (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) static void init_proc_970FX (CPUPPCState *env) { @@ -4189,7 +4213,8 @@ static void init_proc_970FX (CPUPPCState *env) #define POWERPC_EXCP_970GX (POWERPC_EXCP_970) #define POWERPC_INPUT_970GX (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970GX (bfd_mach_ppc64) -#define POWERPC_FLAG_970GX (POWERPC_FLAG_VRE) +#define POWERPC_FLAG_970GX (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) static void init_proc_970GX (CPUPPCState *env) { @@ -4256,7 +4281,7 @@ static void init_proc_970GX (CPUPPCState *env) #define POWERPC_EXCP_620 (POWERPC_EXCP_970) #define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_620 (bfd_mach_ppc64) -#define POWERPC_FLAG_620 (POWERPC_FLAG_NONE) +#define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE) __attribute__ (( unused )) static void init_proc_620 (CPUPPCState *env) @@ -5799,6 +5824,87 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) def->pvr); /* PowerPC implementation specific initialisations (SPRs, timers, ...) */ (*def->init_proc)(env); + /* MSR bits & flags consistency checks */ + if (env->msr_mask & (1 << 25)) { + switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) { + case POWERPC_FLAG_SPE: + case POWERPC_FLAG_VRE: + break; + default: + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should define POWERPC_FLAG_SPE or POWERPC_FLAG_VRE\n"); + exit(1); + } + } else if (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) { + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should not define POWERPC_FLAG_SPE nor POWERPC_FLAG_VRE\n"); + exit(1); + } + if (env->msr_mask & (1 << 17)) { + switch (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) { + case POWERPC_FLAG_TGPR: + case POWERPC_FLAG_CE: + break; + default: + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should define POWERPC_FLAG_TGPR or POWERPC_FLAG_CE\n"); + exit(1); + } + } else if (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) { + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should not define POWERPC_FLAG_TGPR nor POWERPC_FLAG_CE\n"); + exit(1); + } + if (env->msr_mask & (1 << 10)) { + switch (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE | + POWERPC_FLAG_UBLE)) { + case POWERPC_FLAG_SE: + case POWERPC_FLAG_DWE: + case POWERPC_FLAG_UBLE: + break; + default: + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should define POWERPC_FLAG_SE or POWERPC_FLAG_DWE or " + "POWERPC_FLAG_UBLE\n"); + exit(1); + } + } else if (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE | + POWERPC_FLAG_UBLE)) { + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should not define POWERPC_FLAG_SE nor POWERPC_FLAG_DWE nor " + "POWERPC_FLAG_UBLE\n"); + exit(1); + } + if (env->msr_mask & (1 << 9)) { + switch (env->flags & (POWERPC_FLAG_BE | POWERPC_FLAG_DE)) { + case POWERPC_FLAG_BE: + case POWERPC_FLAG_DE: + break; + default: + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should define POWERPC_FLAG_BE or POWERPC_FLAG_DE\n"); + exit(1); + } + } else if (env->flags & (POWERPC_FLAG_BE | POWERPC_FLAG_DE)) { + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should not define POWERPC_FLAG_BE nor POWERPC_FLAG_DE\n"); + exit(1); + } + if (env->msr_mask & (1 << 2)) { + switch (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) { + case POWERPC_FLAG_PX: + case POWERPC_FLAG_PMM: + break; + default: + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should define POWERPC_FLAG_PX or POWERPC_FLAG_PMM\n"); + exit(1); + } + } else if (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) { + fprintf(stderr, "PowerPC MSR definition inconsistency\n" + "Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n"); + exit(1); + } /* Allocate TLBs buffer when needed */ #if !defined(CONFIG_USER_ONLY) if (env->nb_tlb != 0) { @@ -6063,7 +6169,7 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) } #if defined(PPC_DUMP_CPU) -static int dump_ppc_insns (CPUPPCState *env) +static void dump_ppc_insns (CPUPPCState *env) { opc_handler_t **table, *handler; uint8_t opc1, opc2, opc3; @@ -6238,6 +6344,32 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) printf(" Exceptions model : %s\n" " Bus model : %s\n", excp_model, bus_model); + printf(" MSR features :\n"); + if (env->flags & POWERPC_FLAG_SPE) + printf(" signal processing engine enable" + "\n"); + else if (env->flags & POWERPC_FLAG_VRE) + printf(" vector processor enable\n"); + if (env->flags & POWERPC_FLAG_TGPR) + printf(" temporary GPRs\n"); + else if (env->flags & POWERPC_FLAG_CE) + printf(" critical input enable\n"); + if (env->flags & POWERPC_FLAG_SE) + printf(" single-step trace mode\n"); + else if (env->flags & POWERPC_FLAG_DWE) + printf(" debug wait enable\n"); + else if (env->flags & POWERPC_FLAG_UBLE) + printf(" user BTB lock enable\n"); + if (env->flags & POWERPC_FLAG_BE) + printf(" branch-step trace mode\n"); + else if (env->flags & POWERPC_FLAG_DE) + printf(" debug interrupt enable\n"); + if (env->flags & POWERPC_FLAG_PX) + printf(" inclusive protection\n"); + else if (env->flags & POWERPC_FLAG_PMM) + printf(" performance monitor mark\n"); + if (env->flags == POWERPC_FLAG_NONE) + printf(" none\n"); } dump_ppc_insns(env); dump_ppc_sprs(env); -- cgit v1.2.3 From 9b22787cda6d1ee30a14bf09d0dc5af111a3ad1f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 8 Oct 2007 03:00:35 +0000 Subject: Update PowerPC emulation status file. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3355 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/STATUS | 60 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/target-ppc/STATUS b/target-ppc/STATUS index b4daa97af..f346daf93 100644 --- a/target-ppc/STATUS +++ b/target-ppc/STATUS @@ -300,36 +300,41 @@ EXCP ? Altivec, ... needed registers. PowerPC 7441: -INSN KO Altivec missing + TLB load insns missing +INSN KO Altivec missing SPR OK MSR OK IRQ OK -MMU KO not implemented +MMU OK EXCP ? Altivec, ... +Linux does not have the code to handle TLB miss on this CPU + PowerPC 7450/7451: -INSN KO Altivec missing + TLB load insns missing +INSN KO Altivec missing SPR OK MSR OK IRQ OK -MMU KO not implemented +MMU OK EXCP ? Altivec, ... +Linux does not have the code to handle TLB miss on this CPU PowerPC 7445/7447: -INSN KO Altivec missing + TLB load insns missing +INSN KO Altivec missing SPR OK MSR OK IRQ OK -MMU KO not implemented +MMU OK EXCP ? Altivec, ... +Linux does not have the code to handle TLB miss on this CPU PowerPC 7455/7457: -INSN KO Altivec missing + TLB load insns missing +INSN KO Altivec missing SPR OK MSR OK IRQ OK -MMU KO not implemented +MMU OK EXCP ? Altivec, ... +Linux does not have the code to handle TLB miss on this CPU 64 bits PowerPC PowerPC 620: (disabled) @@ -340,21 +345,41 @@ IRQ KO MMU KO EXCP KO -PowerPC 970: (disabled) +PowerPC 970: INSN KO Altivec missing and more SPR KO MSR ? IRQ OK -MMU KO partially implemented -EXCP KO +MMU OK +EXCP KO partially implemented +Should be able to boot but there is no hw platform currently emulated. -PowerPC 970FX: (disabled) +PowerPC 970FX: INSN KO Altivec missing and more SPR KO MSR ? IRQ OK -MMU KO partially implemented -EXCP KO +MMU OK +EXCP KO partially implemented +Should be able to boot but there is no hw platform currently emulated. + +PowerPC 970GX: +INSN KO Altivec missing and more +SPR KO +MSR ? +IRQ OK +MMU OK +EXCP KO partially implemented +Should be able to boot but there is no hw platform currently emulated. + +PowerPC Cell: +INSN KO Altivec missing and more +SPR KO +MSR ? +IRQ ? +MMU ? +EXCP ? partially implemented +As the core is mostly a 970, should be able to boot. SPE are not implemented. PowerPC 630: (disabled: lack of detailed specifications) INSN KO @@ -465,12 +490,17 @@ EXCP KO PowerPC microcontrollers emulation status Implemementation should be sufficient to boot Linux: +(there seem to be problems with uboot freezing at some point) - PowerPC 405CR - PowerPC 405EP TODO: - More PowerPC 40x microcontrollers emulation -- PowerQUICC microcontrollers emulation +- PowerPC 440 microcontrollers emulation +- e200 microcontrollers emulation +- e300 microcontrollers emulation +- e500 microcontrollers emulation +- e600 microcontrollers emulation =============================================================================== PowerPC based platforms emulation status -- cgit v1.2.3 From 450d4ff553af32fc9d83fef20d7106b0151526b8 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 12:45:38 +0000 Subject: CRIS disassembler, originally from binutils, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3356 c046a42c-6fe2-441c-8c8c-71466251a162 --- cris-dis.c | 2907 +++++++++++++++++++++++++++++++++++++++++++++ target-cris/opcode-cris.h | 366 ++++++ 2 files changed, 3273 insertions(+) create mode 100644 cris-dis.c create mode 100644 target-cris/opcode-cris.h diff --git a/cris-dis.c b/cris-dis.c new file mode 100644 index 000000000..3b09f2767 --- /dev/null +++ b/cris-dis.c @@ -0,0 +1,2907 @@ +/* Disassembler code for CRIS. + Copyright 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. + Contributed by Axis Communications AB, Lund, Sweden. + Written by Hans-Peter Nilsson. + + This file is part of the GNU binutils and GDB, the GNU debugger. + + 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, 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., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "dis-asm.h" +//#include "sysdep.h" +#include "target-cris/opcode-cris.h" +//#include "libiberty.h" + + +#define FALSE 0 +#define TRUE 1 +#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) + +/* cris-opc.c -- Table of opcodes for the CRIS processor. + Copyright 2000, 2001, 2004 Free Software Foundation, Inc. + Contributed by Axis Communications AB, Lund, Sweden. + Originally written for GAS 1.38.1 by Mikael Asker. + Reorganized by Hans-Peter Nilsson. + +This file is part of GAS, GDB and the GNU binutils. + +GAS, GDB, and GNU binutils 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, or (at your +option) any later version. + +GAS, GDB, and 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 program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef NULL +#define NULL (0) +#endif + +/* This table isn't used for CRISv32 and the size of immediate operands. */ +const struct cris_spec_reg +cris_spec_regs[] = +{ + {"bz", 0, 1, cris_ver_v32p, NULL}, + {"p0", 0, 1, 0, NULL}, + {"vr", 1, 1, 0, NULL}, + {"p1", 1, 1, 0, NULL}, + {"pid", 2, 1, cris_ver_v32p, NULL}, + {"p2", 2, 1, cris_ver_v32p, NULL}, + {"p2", 2, 1, cris_ver_warning, NULL}, + {"srs", 3, 1, cris_ver_v32p, NULL}, + {"p3", 3, 1, cris_ver_v32p, NULL}, + {"p3", 3, 1, cris_ver_warning, NULL}, + {"wz", 4, 2, cris_ver_v32p, NULL}, + {"p4", 4, 2, 0, NULL}, + {"ccr", 5, 2, cris_ver_v0_10, NULL}, + {"exs", 5, 4, cris_ver_v32p, NULL}, + {"p5", 5, 2, cris_ver_v0_10, NULL}, + {"p5", 5, 4, cris_ver_v32p, NULL}, + {"dcr0",6, 2, cris_ver_v0_3, NULL}, + {"eda", 6, 4, cris_ver_v32p, NULL}, + {"p6", 6, 2, cris_ver_v0_3, NULL}, + {"p6", 6, 4, cris_ver_v32p, NULL}, + {"dcr1/mof", 7, 4, cris_ver_v10p, + "Register `dcr1/mof' with ambiguous size specified. Guessing 4 bytes"}, + {"dcr1/mof", 7, 2, cris_ver_v0_3, + "Register `dcr1/mof' with ambiguous size specified. Guessing 2 bytes"}, + {"mof", 7, 4, cris_ver_v10p, NULL}, + {"dcr1",7, 2, cris_ver_v0_3, NULL}, + {"p7", 7, 4, cris_ver_v10p, NULL}, + {"p7", 7, 2, cris_ver_v0_3, NULL}, + {"dz", 8, 4, cris_ver_v32p, NULL}, + {"p8", 8, 4, 0, NULL}, + {"ibr", 9, 4, cris_ver_v0_10, NULL}, + {"ebp", 9, 4, cris_ver_v32p, NULL}, + {"p9", 9, 4, 0, NULL}, + {"irp", 10, 4, cris_ver_v0_10, NULL}, + {"erp", 10, 4, cris_ver_v32p, NULL}, + {"p10", 10, 4, 0, NULL}, + {"srp", 11, 4, 0, NULL}, + {"p11", 11, 4, 0, NULL}, + /* For disassembly use only. Accept at assembly with a warning. */ + {"bar/dtp0", 12, 4, cris_ver_warning, + "Ambiguous register `bar/dtp0' specified"}, + {"nrp", 12, 4, cris_ver_v32p, NULL}, + {"bar", 12, 4, cris_ver_v8_10, NULL}, + {"dtp0",12, 4, cris_ver_v0_3, NULL}, + {"p12", 12, 4, 0, NULL}, + /* For disassembly use only. Accept at assembly with a warning. */ + {"dccr/dtp1",13, 4, cris_ver_warning, + "Ambiguous register `dccr/dtp1' specified"}, + {"ccs", 13, 4, cris_ver_v32p, NULL}, + {"dccr",13, 4, cris_ver_v8_10, NULL}, + {"dtp1",13, 4, cris_ver_v0_3, NULL}, + {"p13", 13, 4, 0, NULL}, + {"brp", 14, 4, cris_ver_v3_10, NULL}, + {"usp", 14, 4, cris_ver_v32p, NULL}, + {"p14", 14, 4, cris_ver_v3p, NULL}, + {"usp", 15, 4, cris_ver_v10, NULL}, + {"spc", 15, 4, cris_ver_v32p, NULL}, + {"p15", 15, 4, cris_ver_v10p, NULL}, + {NULL, 0, 0, cris_ver_version_all, NULL} +}; + +/* Add version specifiers to this table when necessary. + The (now) regular coding of register names suggests a simpler + implementation. */ +const struct cris_support_reg cris_support_regs[] = +{ + {"s0", 0}, + {"s1", 1}, + {"s2", 2}, + {"s3", 3}, + {"s4", 4}, + {"s5", 5}, + {"s6", 6}, + {"s7", 7}, + {"s8", 8}, + {"s9", 9}, + {"s10", 10}, + {"s11", 11}, + {"s12", 12}, + {"s13", 13}, + {"s14", 14}, + {"s15", 15}, + {NULL, 0} +}; + +/* All CRIS opcodes are 16 bits. + + - The match component is a mask saying which bits must match a + particular opcode in order for an instruction to be an instance + of that opcode. + + - The args component is a string containing characters symbolically + matching the operands of an instruction. Used for both assembly + and disassembly. + + Operand-matching characters: + [ ] , space + Verbatim. + A The string "ACR" (case-insensitive). + B Not really an operand. It causes a "BDAP -size,SP" prefix to be + output for the PUSH alias-instructions and recognizes a push- + prefix at disassembly. This letter isn't recognized for v32. + Must be followed by a R or P letter. + ! Non-match pattern, will not match if there's a prefix insn. + b Non-matching operand, used for branches with 16-bit + displacement. Only recognized by the disassembler. + c 5-bit unsigned immediate in bits <4:0>. + C 4-bit unsigned immediate in bits <3:0>. + d At assembly, optionally (as in put other cases before this one) + ".d" or ".D" at the start of the operands, followed by one space + character. At disassembly, nothing. + D General register in bits <15:12> and <3:0>. + f List of flags in bits <15:12> and <3:0>. + i 6-bit signed immediate in bits <5:0>. + I 6-bit unsigned immediate in bits <5:0>. + M Size modifier (B, W or D) for CLEAR instructions. + m Size modifier (B, W or D) in bits <5:4> + N A 32-bit dword, like in the difference between s and y. + This has no effect on bits in the opcode. Can also be expressed + as "[pc+]" in input. + n As N, but PC-relative (to the start of the instruction). + o [-128..127] word offset in bits <7:1> and <0>. Used by 8-bit + branch instructions. + O [-128..127] offset in bits <7:0>. Also matches a comma and a + general register after the expression, in bits <15:12>. Used + only for the BDAP prefix insn (in v32 the ADDOQ insn; same opcode). + P Special register in bits <15:12>. + p Indicates that the insn is a prefix insn. Must be first + character. + Q As O, but don't relax; force an 8-bit offset. + R General register in bits <15:12>. + r General register in bits <3:0>. + S Source operand in bit <10> and a prefix; a 3-operand prefix + without side-effect. + s Source operand in bits <10> and <3:0>, optionally with a + side-effect prefix, except [pc] (the name, not R15 as in ACR) + isn't allowed for v32 and higher. + T Support register in bits <15:12>. + u 4-bit (PC-relative) unsigned immediate word offset in bits <3:0>. + U Relaxes to either u or n, instruction is assumed LAPCQ or LAPC. + Not recognized at disassembly. + x Register-dot-modifier, for example "r5.w" in bits <15:12> and <5:4>. + y Like 's' but do not allow an integer at assembly. + Y The difference s-y; only an integer is allowed. + z Size modifier (B or W) in bit <4>. */ + + +/* Please note the order of the opcodes in this table is significant. + The assembler requires that all instances of the same mnemonic must + be consecutive. If they aren't, the assembler might not recognize + them, or may indicate an internal error. + + The disassembler should not normally care about the order of the + opcodes, but will prefer an earlier alternative if the "match-score" + (see cris-dis.c) is computed as equal. + + It should not be significant for proper execution that this table is + in alphabetical order, but please follow that convention for an easy + overview. */ + +const struct cris_opcode +cris_opcodes[] = +{ + {"abs", 0x06B0, 0x0940, "r,R", 0, SIZE_NONE, 0, + cris_abs_op}, + + {"add", 0x0600, 0x09c0, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0A00, 0x01c0, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"add", 0x0a00, 0x05c0, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, + cris_ver_v32p, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addc", 0x0570, 0x0A80, "r,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addc", 0x09A0, 0x0250, "s,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addi", 0x0540, 0x0A80, "x,r,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_addi_op}, + + {"addi", 0x0500, 0x0Ac0, "x,r", 0, SIZE_NONE, 0, + cris_addi_op}, + + /* This collates after "addo", but we want to disassemble as "addoq", + not "addo". */ + {"addoq", 0x0100, 0x0E00, "Q,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addo", 0x0940, 0x0280, "m s,R,A", 0, SIZE_FIELD_SIGNED, + cris_ver_v32p, + cris_not_implemented_op}, + + /* This must be located after the insn above, lest we misinterpret + "addo.b -1,r0,acr" as "addo .b-1,r0,acr". FIXME: Sounds like a + parser bug. */ + {"addo", 0x0100, 0x0E00, "O,A", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"addq", 0x0200, 0x0Dc0, "I,R", 0, SIZE_NONE, 0, + cris_quick_mode_add_sub_op}, + + {"adds", 0x0420, 0x0Bc0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"adds", 0x0820, 0x03c0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"adds", 0x0820, 0x03c0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"adds", 0x0820, 0x07c0, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"addu", 0x0400, 0x0be0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"addu", 0x0800, 0x03e0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addu", 0x0800, 0x03e0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"addu", 0x0800, 0x07e0, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"and", 0x0700, 0x08C0, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x00C0, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x00C0, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"and", 0x0B00, 0x04C0, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"andq", 0x0300, 0x0CC0, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"asr", 0x0780, 0x0840, "m r,R", 0, SIZE_NONE, 0, + cris_asr_op}, + + {"asrq", 0x03a0, 0x0c40, "c,R", 0, SIZE_NONE, 0, + cris_asrq_op}, + + {"ax", 0x15B0, 0xEA4F, "", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + /* FIXME: Should use branch #defines. */ + {"b", 0x0dff, 0x0200, "b", 1, SIZE_NONE, 0, + cris_sixteen_bit_offset_branch_op}, + + {"ba", + BA_QUICK_OPCODE, + 0x0F00+(0xF-CC_A)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + /* Needs to come after the usual "ba o", which might be relaxed to + this one. */ + {"ba", BA_DWORD_OPCODE, + 0xffff & (~BA_DWORD_OPCODE), "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bas", 0x0EBF, 0x0140, "n,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"basc", 0x0EFF, 0x0100, "n,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bcc", + BRANCH_QUICK_OPCODE+CC_CC*0x1000, + 0x0f00+(0xF-CC_CC)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bcs", + BRANCH_QUICK_OPCODE+CC_CS*0x1000, + 0x0f00+(0xF-CC_CS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bdap", + BDAP_INDIR_OPCODE, BDAP_INDIR_Z_BITS, "pm s,R", 0, SIZE_FIELD_SIGNED, + cris_ver_v0_10, + cris_bdap_prefix}, + + {"bdap", + BDAP_QUICK_OPCODE, BDAP_QUICK_Z_BITS, "pO", 0, SIZE_NONE, + cris_ver_v0_10, + cris_quick_mode_bdap_prefix}, + + {"beq", + BRANCH_QUICK_OPCODE+CC_EQ*0x1000, + 0x0f00+(0xF-CC_EQ)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + /* This is deliberately put before "bext" to trump it, even though not + in alphabetical order, since we don't do excluding version checks + for v0..v10. */ + {"bwf", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v10, + cris_eight_bit_offset_branch_op}, + + {"bext", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v0_3, + cris_eight_bit_offset_branch_op}, + + {"bge", + BRANCH_QUICK_OPCODE+CC_GE*0x1000, + 0x0f00+(0xF-CC_GE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bgt", + BRANCH_QUICK_OPCODE+CC_GT*0x1000, + 0x0f00+(0xF-CC_GT)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bhi", + BRANCH_QUICK_OPCODE+CC_HI*0x1000, + 0x0f00+(0xF-CC_HI)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bhs", + BRANCH_QUICK_OPCODE+CC_HS*0x1000, + 0x0f00+(0xF-CC_HS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"biap", BIAP_OPCODE, BIAP_Z_BITS, "pm r,R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_biap_prefix}, + + {"ble", + BRANCH_QUICK_OPCODE+CC_LE*0x1000, + 0x0f00+(0xF-CC_LE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"blo", + BRANCH_QUICK_OPCODE+CC_LO*0x1000, + 0x0f00+(0xF-CC_LO)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bls", + BRANCH_QUICK_OPCODE+CC_LS*0x1000, + 0x0f00+(0xF-CC_LS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"blt", + BRANCH_QUICK_OPCODE+CC_LT*0x1000, + 0x0f00+(0xF-CC_LT)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bmi", + BRANCH_QUICK_OPCODE+CC_MI*0x1000, + 0x0f00+(0xF-CC_MI)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bmod", 0x0ab0, 0x0140, "s,R", 0, SIZE_FIX_32, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bmod", 0x0ab0, 0x0140, "S,D", 0, SIZE_NONE, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bmod", 0x0ab0, 0x0540, "S,R,r", 0, SIZE_NONE, + cris_ver_sim_v0_10, + cris_not_implemented_op}, + + {"bne", + BRANCH_QUICK_OPCODE+CC_NE*0x1000, + 0x0f00+(0xF-CC_NE)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bound", 0x05c0, 0x0A00, "m r,R", 0, SIZE_NONE, 0, + cris_two_operand_bound_op}, + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"bound", 0x09c0, 0x0200, "m s,R", 0, SIZE_FIELD, + cris_ver_v0_10, + cris_two_operand_bound_op}, + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"bound", 0x0dcf, 0x0200, "m Y,R", 0, SIZE_FIELD, 0, + cris_two_operand_bound_op}, + {"bound", 0x09c0, 0x0200, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_two_operand_bound_op}, + {"bound", 0x09c0, 0x0600, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_bound_op}, + + {"bpl", + BRANCH_QUICK_OPCODE+CC_PL*0x1000, + 0x0f00+(0xF-CC_PL)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"break", 0xe930, 0x16c0, "C", 0, SIZE_NONE, + cris_ver_v3p, + cris_break_op}, + + {"bsb", + BRANCH_QUICK_OPCODE+CC_EXT*0x1000, + 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE, + cris_ver_v32p, + cris_eight_bit_offset_branch_op}, + + {"bsr", 0xBEBF, 0x4140, "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bsrc", 0xBEFF, 0x4100, "n", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"bstore", 0x0af0, 0x0100, "s,R", 0, SIZE_FIX_32, + cris_ver_warning, + cris_not_implemented_op}, + + {"bstore", 0x0af0, 0x0100, "S,D", 0, SIZE_NONE, + cris_ver_warning, + cris_not_implemented_op}, + + {"bstore", 0x0af0, 0x0500, "S,R,r", 0, SIZE_NONE, + cris_ver_warning, + cris_not_implemented_op}, + + {"btst", 0x04F0, 0x0B00, "r,R", 0, SIZE_NONE, 0, + cris_btst_nop_op}, + {"btstq", 0x0380, 0x0C60, "c,R", 0, SIZE_NONE, 0, + cris_btst_nop_op}, + + {"bvc", + BRANCH_QUICK_OPCODE+CC_VC*0x1000, + 0x0f00+(0xF-CC_VC)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"bvs", + BRANCH_QUICK_OPCODE+CC_VS*0x1000, + 0x0f00+(0xF-CC_VS)*0x1000, "o", 1, SIZE_NONE, 0, + cris_eight_bit_offset_branch_op}, + + {"clear", 0x0670, 0x3980, "M r", 0, SIZE_NONE, 0, + cris_reg_mode_clear_op}, + + {"clear", 0x0A70, 0x3180, "M y", 0, SIZE_NONE, 0, + cris_none_reg_mode_clear_test_op}, + + {"clear", 0x0A70, 0x3180, "M S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_clear_test_op}, + + {"clearf", 0x05F0, 0x0A00, "f", 0, SIZE_NONE, 0, + cris_clearf_di_op}, + + {"cmp", 0x06C0, 0x0900, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmp", 0x0Ac0, 0x0100, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmp", 0x0Ac0, 0x0100, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmpq", 0x02C0, 0x0D00, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"cmps", 0x08e0, 0x0300, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmps", 0x08e0, 0x0300, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"cmpu", 0x08c0, 0x0320, "z s,R" , 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"cmpu", 0x08c0, 0x0320, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"di", 0x25F0, 0xDA0F, "", 0, SIZE_NONE, 0, + cris_clearf_di_op}, + + {"dip", DIP_OPCODE, DIP_Z_BITS, "ps", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_dip_prefix}, + + {"div", 0x0980, 0x0640, "m R,r", 0, SIZE_FIELD, 0, + cris_not_implemented_op}, + + {"dstep", 0x06f0, 0x0900, "r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"ei", 0x25B0, 0xDA4F, "", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + {"fidxd", 0x0ab0, 0xf540, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"fidxi", 0x0d30, 0xF2C0, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ftagd", 0x1AB0, 0xE540, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ftagi", 0x1D30, 0xE2C0, "[r]", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"halt", 0xF930, 0x06CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"jas", 0x09B0, 0x0640, "r,P", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jas", 0x0DBF, 0x0240, "N,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jasc", 0x0B30, 0x04C0, "r,P", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jasc", 0x0F3F, 0x00C0, "N,P", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jbrc", 0x69b0, 0x9640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jbrc", 0x6930, 0x92c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jbrc", 0x6930, 0x92c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jir", 0xA9b0, 0x5640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jir", 0xA930, 0x52c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jir", 0xA930, 0x52c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jirc", 0x29b0, 0xd640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jirc", 0x2930, 0xd2c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jirc", 0x2930, 0xd2c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xB9b0, 0x4640, "r", 0, SIZE_NONE, 0, + cris_reg_mode_jump_op}, + + {"jsr", 0xB930, 0x42c0, "s", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xBDBF, 0x4240, "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jsr", 0xB930, 0x42c0, "S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0x39b0, 0xc640, "r", 0, SIZE_NONE, + cris_ver_v8_10, + cris_reg_mode_jump_op}, + + {"jsrc", 0x3930, 0xc2c0, "s", 0, SIZE_FIX_32, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0x3930, 0xc2c0, "S", 0, SIZE_NONE, + cris_ver_v8_10, + cris_none_reg_mode_jump_op}, + + {"jsrc", 0xBB30, 0x44C0, "r", 0, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jsrc", 0xBF3F, 0x40C0, "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_reg_mode_jump_op}, + + {"jump", 0x09b0, 0xF640, "r", 0, SIZE_NONE, 0, + cris_reg_mode_jump_op}, + + {"jump", + JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "s", 0, SIZE_FIX_32, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jump", + JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_jump_op}, + + {"jump", 0x09F0, 0x060F, "P", 0, SIZE_NONE, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jump", + JUMP_PC_INCR_OPCODE_V32, + (0xffff & ~JUMP_PC_INCR_OPCODE_V32), "N", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_none_reg_mode_jump_op}, + + {"jmpu", 0x8930, 0x72c0, "s", 0, SIZE_FIX_32, + cris_ver_v10, + cris_none_reg_mode_jump_op}, + + {"jmpu", 0x8930, 0x72c0, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_none_reg_mode_jump_op}, + + {"lapc", 0x0970, 0x0680, "U,R", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"lapc", 0x0D7F, 0x0280, "dn,R", 0, SIZE_FIX_32, + cris_ver_v32p, + cris_not_implemented_op}, + + {"lapcq", 0x0970, 0x0680, "u,R", 0, SIZE_NONE, + cris_ver_v32p, + cris_addi_op}, + + {"lsl", 0x04C0, 0x0B00, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lslq", 0x03c0, 0x0C20, "c,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lsr", 0x07C0, 0x0800, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lsrq", 0x03e0, 0x0C00, "c,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"lz", 0x0730, 0x08C0, "r,R", 0, SIZE_NONE, + cris_ver_v3p, + cris_not_implemented_op}, + + {"mcp", 0x07f0, 0x0800, "P,r", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"move", 0x0640, 0x0980, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0A40, 0x0180, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0A40, 0x0180, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0630, 0x09c0, "r,P", 0, SIZE_NONE, 0, + cris_move_to_preg_op}, + + {"move", 0x0670, 0x0980, "P,r", 0, SIZE_NONE, 0, + cris_reg_mode_move_from_preg_op}, + + {"move", 0x0BC0, 0x0000, "m R,y", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", 0x0BC0, 0x0000, "m D,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"move", + MOVE_M_TO_PREG_OPCODE, MOVE_M_TO_PREG_ZBITS, + "s,P", 0, SIZE_SPEC_REG, 0, + cris_move_to_preg_op}, + + {"move", 0x0A30, 0x01c0, "S,P", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_to_preg_op}, + + {"move", 0x0A70, 0x0180, "P,y", 0, SIZE_SPEC_REG, 0, + cris_none_reg_mode_move_from_preg_op}, + + {"move", 0x0A70, 0x0180, "P,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_move_from_preg_op}, + + {"move", 0x0B70, 0x0480, "r,T", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"move", 0x0F70, 0x0080, "T,r", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"movem", 0x0BF0, 0x0000, "R,y", 0, SIZE_FIX_32, 0, + cris_move_reg_to_mem_movem_op}, + + {"movem", 0x0BF0, 0x0000, "D,S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_reg_to_mem_movem_op}, + + {"movem", 0x0BB0, 0x0040, "s,R", 0, SIZE_FIX_32, 0, + cris_move_mem_to_reg_movem_op}, + + {"movem", 0x0BB0, 0x0040, "S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_mem_to_reg_movem_op}, + + {"moveq", 0x0240, 0x0D80, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"movs", 0x0460, 0x0B80, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"movs", 0x0860, 0x0380, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movs", 0x0860, 0x0380, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movu", 0x0440, 0x0Ba0, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"movu", 0x0840, 0x03a0, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"movu", 0x0840, 0x03a0, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"mstep", 0x07f0, 0x0800, "r,R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_dstep_logshift_mstep_neg_not_op}, + + {"muls", 0x0d00, 0x02c0, "m r,R", 0, SIZE_NONE, + cris_ver_v10p, + cris_muls_op}, + + {"mulu", 0x0900, 0x06c0, "m r,R", 0, SIZE_NONE, + cris_ver_v10p, + cris_mulu_op}, + + {"neg", 0x0580, 0x0A40, "m r,R", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"nop", NOP_OPCODE, NOP_Z_BITS, "", 0, SIZE_NONE, + cris_ver_v0_10, + cris_btst_nop_op}, + + {"nop", NOP_OPCODE_V32, NOP_Z_BITS_V32, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_btst_nop_op}, + + {"not", 0x8770, 0x7880, "r", 0, SIZE_NONE, 0, + cris_dstep_logshift_mstep_neg_not_op}, + + {"or", 0x0740, 0x0880, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0080, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0080, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"or", 0x0B40, 0x0480, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"orq", 0x0340, 0x0C80, "i,R", 0, SIZE_NONE, 0, + cris_quick_mode_and_cmp_move_or_op}, + + {"pop", 0x0E6E, 0x0191, "!R", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"pop", 0x0e3e, 0x01c1, "!P", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_move_from_preg_op}, + + {"push", 0x0FEE, 0x0011, "BR", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"push", 0x0E7E, 0x0181, "BP", 0, SIZE_NONE, + cris_ver_v0_10, + cris_move_to_preg_op}, + + {"rbf", 0x3b30, 0xc0c0, "y", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"rbf", 0x3b30, 0xc0c0, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"rfe", 0x2930, 0xD6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"rfg", 0x4930, 0xB6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"rfn", 0x5930, 0xA6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + {"ret", 0xB67F, 0x4980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"ret", 0xB9F0, 0x460F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"retb", 0xe67f, 0x1980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"rete", 0xA9F0, 0x560F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"reti", 0xA67F, 0x5980, "", 1, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_move_from_preg_op}, + + {"retn", 0xC9F0, 0x360F, "", 1, SIZE_NONE, + cris_ver_v32p, + cris_reg_mode_move_from_preg_op}, + + {"sbfs", 0x3b70, 0xc080, "y", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"sbfs", 0x3b70, 0xc080, "S", 0, SIZE_NONE, + cris_ver_v10, + cris_not_implemented_op}, + + {"sa", + 0x0530+CC_A*0x1000, + 0x0AC0+(0xf-CC_A)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"ssb", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v32p, + cris_scc_op}, + + {"scc", + 0x0530+CC_CC*0x1000, + 0x0AC0+(0xf-CC_CC)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"scs", + 0x0530+CC_CS*0x1000, + 0x0AC0+(0xf-CC_CS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"seq", + 0x0530+CC_EQ*0x1000, + 0x0AC0+(0xf-CC_EQ)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"setf", 0x05b0, 0x0A40, "f", 0, SIZE_NONE, 0, + cris_ax_ei_setf_op}, + + {"sfe", 0x3930, 0xC6CF, "", 0, SIZE_NONE, + cris_ver_v32p, + cris_not_implemented_op}, + + /* Need to have "swf" in front of "sext" so it is the one displayed in + disassembly. */ + {"swf", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v10, + cris_scc_op}, + + {"sext", + 0x0530+CC_EXT*0x1000, + 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE, + cris_ver_v0_3, + cris_scc_op}, + + {"sge", + 0x0530+CC_GE*0x1000, + 0x0AC0+(0xf-CC_GE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sgt", + 0x0530+CC_GT*0x1000, + 0x0AC0+(0xf-CC_GT)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"shi", + 0x0530+CC_HI*0x1000, + 0x0AC0+(0xf-CC_HI)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"shs", + 0x0530+CC_HS*0x1000, + 0x0AC0+(0xf-CC_HS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sle", + 0x0530+CC_LE*0x1000, + 0x0AC0+(0xf-CC_LE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"slo", + 0x0530+CC_LO*0x1000, + 0x0AC0+(0xf-CC_LO)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sls", + 0x0530+CC_LS*0x1000, + 0x0AC0+(0xf-CC_LS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"slt", + 0x0530+CC_LT*0x1000, + 0x0AC0+(0xf-CC_LT)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"smi", + 0x0530+CC_MI*0x1000, + 0x0AC0+(0xf-CC_MI)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sne", + 0x0530+CC_NE*0x1000, + 0x0AC0+(0xf-CC_NE)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"spl", + 0x0530+CC_PL*0x1000, + 0x0AC0+(0xf-CC_PL)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"sub", 0x0680, 0x0940, "m r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0140, "m s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0140, "m S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"sub", 0x0a80, 0x0540, "m S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"subq", 0x0280, 0x0d40, "I,R", 0, SIZE_NONE, 0, + cris_quick_mode_add_sub_op}, + + {"subs", 0x04a0, 0x0b40, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */ + {"subs", 0x08a0, 0x0340, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subs", 0x08a0, 0x0340, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subs", 0x08a0, 0x0740, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"subu", 0x0480, 0x0b60, "z r,R", 0, SIZE_NONE, 0, + cris_reg_mode_add_sub_cmp_and_or_move_op}, + + /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */ + {"subu", 0x0880, 0x0360, "z s,R", 0, SIZE_FIELD, 0, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subu", 0x0880, 0x0360, "z S,D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_add_sub_cmp_and_or_move_op}, + + {"subu", 0x0880, 0x0760, "z S,R,r", 0, SIZE_NONE, + cris_ver_v0_10, + cris_three_operand_add_sub_cmp_and_or_op}, + + {"svc", + 0x0530+CC_VC*0x1000, + 0x0AC0+(0xf-CC_VC)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + {"svs", + 0x0530+CC_VS*0x1000, + 0x0AC0+(0xf-CC_VS)*0x1000, "r", 0, SIZE_NONE, 0, + cris_scc_op}, + + /* The insn "swapn" is the same as "not" and will be disassembled as + such, but the swap* family of mnmonics are generally v8-and-higher + only, so count it in. */ + {"swapn", 0x8770, 0x7880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapw", 0x4770, 0xb880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnw", 0xc770, 0x3880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapb", 0x2770, 0xd880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnb", 0xA770, 0x5880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwb", 0x6770, 0x9880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwb", 0xE770, 0x1880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapr", 0x1770, 0xe880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnr", 0x9770, 0x6880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwr", 0x5770, 0xa880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwr", 0xd770, 0x2880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapbr", 0x3770, 0xc880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnbr", 0xb770, 0x4880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapwbr", 0x7770, 0x8880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"swapnwbr", 0xf770, 0x0880, "r", 0, SIZE_NONE, + cris_ver_v8p, + cris_not_implemented_op}, + + {"test", 0x0640, 0x0980, "m D", 0, SIZE_NONE, + cris_ver_v0_10, + cris_reg_mode_test_op}, + + {"test", 0x0b80, 0xf040, "m y", 0, SIZE_FIELD, 0, + cris_none_reg_mode_clear_test_op}, + + {"test", 0x0b80, 0xf040, "m S", 0, SIZE_NONE, + cris_ver_v0_10, + cris_none_reg_mode_clear_test_op}, + + {"xor", 0x07B0, 0x0840, "r,R", 0, SIZE_NONE, 0, + cris_xor_op}, + + {NULL, 0, 0, NULL, 0, 0, 0, cris_not_implemented_op} +}; + +/* Condition-names, indexed by the CC_* numbers as found in cris.h. */ +const char * const +cris_cc_strings[] = +{ + "hs", + "lo", + "ne", + "eq", + "vc", + "vs", + "pl", + "mi", + "ls", + "hi", + "ge", + "lt", + "gt", + "le", + "a", + /* This is a placeholder. In v0, this would be "ext". In v32, this + is "sb". See cris_conds15. */ + "wf" +}; + +/* Different names and semantics for condition 1111 (0xf). */ +const struct cris_cond15 cris_cond15s[] = +{ + /* FIXME: In what version did condition "ext" disappear? */ + {"ext", cris_ver_v0_3}, + {"wf", cris_ver_v10}, + {"sb", cris_ver_v32p}, + {NULL, 0} +}; + + +/* + * Local variables: + * eval: (c-set-style "gnu") + * indent-tabs-mode: t + * End: + */ + + +/* No instruction will be disassembled longer than this. In theory, and + in silicon, address prefixes can be cascaded. In practice, cascading + is not used by GCC, and not supported by the assembler. */ +#ifndef MAX_BYTES_PER_CRIS_INSN +#define MAX_BYTES_PER_CRIS_INSN 8 +#endif + +/* Whether or not to decode prefixes, folding it into the following + instruction. FIXME: Make this optional later. */ +#ifndef PARSE_PREFIX +#define PARSE_PREFIX 1 +#endif + +/* Sometimes we prefix all registers with this character. */ +#define REGISTER_PREFIX_CHAR '$' + +/* Whether or not to trace the following sequence: + sub* X,r%d + bound* Y,r%d + adds.w [pc+r%d.w],pc + + This is the assembly form of a switch-statement in C. + The "sub is optional. If there is none, then X will be zero. + X is the value of the first case, + Y is the number of cases (including default). + + This results in case offsets printed on the form: + case N: -> case_address + where N is an estimation on the corresponding 'case' operand in C, + and case_address is where execution of that case continues after the + sequence presented above. + + The old style of output was to print the offsets as instructions, + which made it hard to follow "case"-constructs in the disassembly, + and caused a lot of annoying warnings about undefined instructions. + + FIXME: Make this optional later. */ +#ifndef TRACE_CASE +#define TRACE_CASE (disdata->trace_case) +#endif + +enum cris_disass_family + { cris_dis_v0_v10, cris_dis_common_v10_v32, cris_dis_v32 }; + +/* Stored in the disasm_info->private_data member. */ +struct cris_disasm_data +{ + /* Whether to print something less confusing if we find something + matching a switch-construct. */ + bfd_boolean trace_case; + + /* Whether this code is flagged as crisv32. FIXME: Should be an enum + that includes "compatible". */ + enum cris_disass_family distype; +}; + +/* Value of first element in switch. */ +static long case_offset = 0; + +/* How many more case-offsets to print. */ +static long case_offset_counter = 0; + +/* Number of case offsets. */ +static long no_of_case_offsets = 0; + +/* Candidate for next case_offset. */ +static long last_immediate = 0; + +static int cris_constraint + (const char *, unsigned, unsigned, struct cris_disasm_data *); + +/* Parse disassembler options and store state in info. FIXME: For the + time being, we abuse static variables. */ + +static bfd_boolean +cris_parse_disassembler_options (disassemble_info *info, + enum cris_disass_family distype) +{ + struct cris_disasm_data *disdata; + + info->private_data = calloc (1, sizeof (struct cris_disasm_data)); + disdata = (struct cris_disasm_data *) info->private_data; + if (disdata == NULL) + return FALSE; + + /* Default true. */ + disdata->trace_case + = (info->disassembler_options == NULL + || (strcmp (info->disassembler_options, "nocase") != 0)); + + disdata->distype = distype; + return TRUE; +} + +static const struct cris_spec_reg * +spec_reg_info (unsigned int sreg, enum cris_disass_family distype) +{ + int i; + + for (i = 0; cris_spec_regs[i].name != NULL; i++) + { + if (cris_spec_regs[i].number == sreg) + { + if (distype == cris_dis_v32) + switch (cris_spec_regs[i].applicable_version) + { + case cris_ver_warning: + case cris_ver_version_all: + case cris_ver_v3p: + case cris_ver_v8p: + case cris_ver_v10p: + case cris_ver_v32p: + /* No ambiguous sizes or register names with CRISv32. */ + if (cris_spec_regs[i].warning == NULL) + return &cris_spec_regs[i]; + default: + ; + } + else if (cris_spec_regs[i].applicable_version != cris_ver_v32p) + return &cris_spec_regs[i]; + } + } + + return NULL; +} + +/* Return the number of bits in the argument. */ + +static int +number_of_bits (unsigned int val) +{ + int bits; + + for (bits = 0; val != 0; val &= val - 1) + bits++; + + return bits; +} + +/* Get an entry in the opcode-table. */ + +static const struct cris_opcode * +get_opcode_entry (unsigned int insn, + unsigned int prefix_insn, + struct cris_disasm_data *disdata) +{ + /* For non-prefixed insns, we keep a table of pointers, indexed by the + insn code. Each entry is initialized when found to be NULL. */ + static const struct cris_opcode **opc_table = NULL; + + const struct cris_opcode *max_matchedp = NULL; + const struct cris_opcode **prefix_opc_table = NULL; + + /* We hold a table for each prefix that need to be handled differently. */ + static const struct cris_opcode **dip_prefixes = NULL; + static const struct cris_opcode **bdapq_m1_prefixes = NULL; + static const struct cris_opcode **bdapq_m2_prefixes = NULL; + static const struct cris_opcode **bdapq_m4_prefixes = NULL; + static const struct cris_opcode **rest_prefixes = NULL; + + /* Allocate and clear the opcode-table. */ + if (opc_table == NULL) + { + opc_table = malloc (65536 * sizeof (opc_table[0])); + if (opc_table == NULL) + return NULL; + + memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *)); + + dip_prefixes + = malloc (65536 * sizeof (const struct cris_opcode **)); + if (dip_prefixes == NULL) + return NULL; + + memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0])); + + bdapq_m1_prefixes + = malloc (65536 * sizeof (const struct cris_opcode **)); + if (bdapq_m1_prefixes == NULL) + return NULL; + + memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0])); + + bdapq_m2_prefixes + = malloc (65536 * sizeof (const struct cris_opcode **)); + if (bdapq_m2_prefixes == NULL) + return NULL; + + memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0])); + + bdapq_m4_prefixes + = malloc (65536 * sizeof (const struct cris_opcode **)); + if (bdapq_m4_prefixes == NULL) + return NULL; + + memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0])); + + rest_prefixes + = malloc (65536 * sizeof (const struct cris_opcode **)); + if (rest_prefixes == NULL) + return NULL; + + memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0])); + } + + /* Get the right table if this is a prefix. + This code is connected to cris_constraints in that it knows what + prefixes play a role in recognition of patterns; the necessary + state is reflected by which table is used. If constraints + involving match or non-match of prefix insns are changed, then this + probably needs changing too. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + const struct cris_opcode *popcodep + = (opc_table[prefix_insn] != NULL + ? opc_table[prefix_insn] + : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata)); + + if (popcodep == NULL) + return NULL; + + if (popcodep->match == BDAP_QUICK_OPCODE) + { + /* Since some offsets are recognized with "push" macros, we + have to have different tables for them. */ + int offset = (prefix_insn & 255); + + if (offset > 127) + offset -= 256; + + switch (offset) + { + case -4: + prefix_opc_table = bdapq_m4_prefixes; + break; + + case -2: + prefix_opc_table = bdapq_m2_prefixes; + break; + + case -1: + prefix_opc_table = bdapq_m1_prefixes; + break; + + default: + prefix_opc_table = rest_prefixes; + break; + } + } + else if (popcodep->match == DIP_OPCODE) + /* We don't allow postincrement when the prefix is DIP, so use a + different table for DIP. */ + prefix_opc_table = dip_prefixes; + else + prefix_opc_table = rest_prefixes; + } + + if (prefix_insn != NO_CRIS_PREFIX + && prefix_opc_table[insn] != NULL) + max_matchedp = prefix_opc_table[insn]; + else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL) + max_matchedp = opc_table[insn]; + else + { + const struct cris_opcode *opcodep; + int max_level_of_match = -1; + + for (opcodep = cris_opcodes; + opcodep->name != NULL; + opcodep++) + { + int level_of_match; + + if (disdata->distype == cris_dis_v32) + { + switch (opcodep->applicable_version) + { + case cris_ver_version_all: + break; + + case cris_ver_v0_3: + case cris_ver_v0_10: + case cris_ver_v3_10: + case cris_ver_sim_v0_10: + case cris_ver_v8_10: + case cris_ver_v10: + case cris_ver_warning: + continue; + + case cris_ver_v3p: + case cris_ver_v8p: + case cris_ver_v10p: + case cris_ver_v32p: + break; + + case cris_ver_v8: + abort (); + default: + abort (); + } + } + else + { + switch (opcodep->applicable_version) + { + case cris_ver_version_all: + case cris_ver_v0_3: + case cris_ver_v3p: + case cris_ver_v0_10: + case cris_ver_v8p: + case cris_ver_v8_10: + case cris_ver_v10: + case cris_ver_sim_v0_10: + case cris_ver_v10p: + case cris_ver_warning: + break; + + case cris_ver_v32p: + continue; + + case cris_ver_v8: + abort (); + default: + abort (); + } + } + + /* We give a double lead for bits matching the template in + cris_opcodes. Not even, because then "move p8,r10" would + be given 2 bits lead over "clear.d r10". When there's a + tie, the first entry in the table wins. This is + deliberate, to avoid a more complicated recognition + formula. */ + if ((opcodep->match & insn) == opcodep->match + && (opcodep->lose & insn) == 0 + && ((level_of_match + = cris_constraint (opcodep->args, + insn, + prefix_insn, + disdata)) + >= 0) + && ((level_of_match + += 2 * number_of_bits (opcodep->match + | opcodep->lose)) + > max_level_of_match)) + { + max_matchedp = opcodep; + max_level_of_match = level_of_match; + + /* If there was a full match, never mind looking + further. */ + if (level_of_match >= 2 * 16) + break; + } + } + /* Fill in the new entry. + + If there are changes to the opcode-table involving prefixes, and + disassembly then does not work correctly, try removing the + else-clause below that fills in the prefix-table. If that + helps, you need to change the prefix_opc_table setting above, or + something related. */ + if (prefix_insn == NO_CRIS_PREFIX) + opc_table[insn] = max_matchedp; + else + prefix_opc_table[insn] = max_matchedp; + } + + return max_matchedp; +} + +/* Return -1 if the constraints of a bitwise-matched instruction say + that there is no match. Otherwise return a nonnegative number + indicating the confidence in the match (higher is better). */ + +static int +cris_constraint (const char *cs, + unsigned int insn, + unsigned int prefix_insn, + struct cris_disasm_data *disdata) +{ + int retval = 0; + int tmp; + int prefix_ok = 0; + const char *s; + + for (s = cs; *s; s++) + switch (*s) + { + case '!': + /* Do not recognize "pop" if there's a prefix and then only for + v0..v10. */ + if (prefix_insn != NO_CRIS_PREFIX + || disdata->distype != cris_dis_v0_v10) + return -1; + break; + + case 'U': + /* Not recognized at disassembly. */ + return -1; + + case 'M': + /* Size modifier for "clear", i.e. special register 0, 4 or 8. + Check that it is one of them. Only special register 12 could + be mismatched, but checking for matches is more logical than + checking for mismatches when there are only a few cases. */ + tmp = ((insn >> 12) & 0xf); + if (tmp != 0 && tmp != 4 && tmp != 8) + return -1; + break; + + case 'm': + if ((insn & 0x30) == 0x30) + return -1; + break; + + case 'S': + /* A prefix operand without side-effect. */ + if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0) + { + prefix_ok = 1; + break; + } + else + return -1; + + case 's': + case 'y': + case 'Y': + /* If this is a prefixed insn with postincrement (side-effect), + the prefix must not be DIP. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + if (insn & 0x400) + { + const struct cris_opcode *prefix_opcodep + = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); + + if (prefix_opcodep->match == DIP_OPCODE) + return -1; + } + + prefix_ok = 1; + } + break; + + case 'B': + /* If we don't fall through, then the prefix is ok. */ + prefix_ok = 1; + + /* A "push" prefix. Check for valid "push" size. + In case of special register, it may be != 4. */ + if (prefix_insn != NO_CRIS_PREFIX) + { + /* Match the prefix insn to BDAPQ. */ + const struct cris_opcode *prefix_opcodep + = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata); + + if (prefix_opcodep->match == BDAP_QUICK_OPCODE) + { + int pushsize = (prefix_insn & 255); + + if (pushsize > 127) + pushsize -= 256; + + if (s[1] == 'P') + { + unsigned int spec_reg = (insn >> 12) & 15; + const struct cris_spec_reg *sregp + = spec_reg_info (spec_reg, disdata->distype); + + /* For a special-register, the "prefix size" must + match the size of the register. */ + if (sregp && sregp->reg_size == (unsigned int) -pushsize) + break; + } + else if (s[1] == 'R') + { + if ((insn & 0x30) == 0x20 && pushsize == -4) + break; + } + /* FIXME: Should abort here; next constraint letter + *must* be 'P' or 'R'. */ + } + } + return -1; + + case 'D': + retval = (((insn >> 12) & 15) == (insn & 15)); + if (!retval) + return -1; + else + retval += 4; + break; + + case 'P': + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* Since we match four bits, we will give a value of 4-1 = 3 + in a match. If there is a corresponding exact match of a + special register in another pattern, it will get a value of + 4, which will be higher. This should be correct in that an + exact pattern would match better than a general pattern. + + Note that there is a reason for not returning zero; the + pattern for "clear" is partly matched in the bit-pattern + (the two lower bits must be zero), while the bit-pattern + for a move from a special register is matched in the + register constraint. */ + + if (sregp != NULL) + { + retval += 3; + break; + } + else + return -1; + } + } + + if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok) + return -1; + + return retval; +} + +/* Format number as hex with a leading "0x" into outbuffer. */ + +static char * +format_hex (unsigned long number, + char *outbuffer, + struct cris_disasm_data *disdata) +{ + /* Truncate negative numbers on >32-bit hosts. */ + number &= 0xffffffff; + + sprintf (outbuffer, "0x%lx", number); + + /* Save this value for the "case" support. */ + if (TRACE_CASE) + last_immediate = number; + + return outbuffer + strlen (outbuffer); +} + +/* Format number as decimal into outbuffer. Parameter signedp says + whether the number should be formatted as signed (!= 0) or + unsigned (== 0). */ + +static char * +format_dec (long number, char *outbuffer, int signedp) +{ + last_immediate = number; + sprintf (outbuffer, signedp ? "%ld" : "%lu", number); + + return outbuffer + strlen (outbuffer); +} + +/* Format the name of the general register regno into outbuffer. */ + +static char * +format_reg (struct cris_disasm_data *disdata, + int regno, + char *outbuffer_start, + bfd_boolean with_reg_prefix) +{ + char *outbuffer = outbuffer_start; + + if (with_reg_prefix) + *outbuffer++ = REGISTER_PREFIX_CHAR; + + switch (regno) + { + case 15: + /* For v32, there is no context in which we output PC. */ + if (disdata->distype == cris_dis_v32) + strcpy (outbuffer, "acr"); + else + strcpy (outbuffer, "pc"); + break; + + case 14: + strcpy (outbuffer, "sp"); + break; + + default: + sprintf (outbuffer, "r%d", regno); + break; + } + + return outbuffer_start + strlen (outbuffer_start); +} + +/* Format the name of a support register into outbuffer. */ + +static char * +format_sup_reg (unsigned int regno, + char *outbuffer_start, + bfd_boolean with_reg_prefix) +{ + char *outbuffer = outbuffer_start; + int i; + + if (with_reg_prefix) + *outbuffer++ = REGISTER_PREFIX_CHAR; + + for (i = 0; cris_support_regs[i].name != NULL; i++) + if (cris_support_regs[i].number == regno) + { + sprintf (outbuffer, "%s", cris_support_regs[i].name); + return outbuffer_start + strlen (outbuffer_start); + } + + /* There's supposed to be register names covering all numbers, though + some may be generic names. */ + sprintf (outbuffer, "format_sup_reg-BUG"); + return outbuffer_start + strlen (outbuffer_start); +} + +/* Return the length of an instruction. */ + +static unsigned +bytes_to_skip (unsigned int insn, + const struct cris_opcode *matchedp, + enum cris_disass_family distype, + const struct cris_opcode *prefix_matchedp) +{ + /* Each insn is a word plus "immediate" operands. */ + unsigned to_skip = 2; + const char *template = matchedp->args; + const char *s; + + for (s = template; *s; s++) + if ((*s == 's' || *s == 'N' || *s == 'Y') + && (insn & 0x400) && (insn & 15) == 15 + && prefix_matchedp == NULL) + { + /* Immediate via [pc+], so we have to check the size of the + operand. */ + int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3)); + + if (matchedp->imm_oprnd_size == SIZE_FIX_32) + to_skip += 4; + else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, distype); + + /* FIXME: Improve error handling; should have been caught + earlier. */ + if (sregp == NULL) + return 2; + + /* PC is incremented by two, not one, for a byte. Except on + CRISv32, where constants are always DWORD-size for + special registers. */ + to_skip += + distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1; + } + else + to_skip += (mode_size + 1) & ~1; + } + else if (*s == 'n') + to_skip += 4; + else if (*s == 'b') + to_skip += 2; + + return to_skip; +} + +/* Print condition code flags. */ + +static char * +print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp) +{ + /* Use the v8 (Etrax 100) flag definitions for disassembly. + The differences with v0 (Etrax 1..4) vs. Svinto are: + v0 'd' <=> v8 'm' + v0 'e' <=> v8 'b'. + FIXME: Emit v0..v3 flag names somehow. */ + static const char v8_fnames[] = "cvznxibm"; + static const char v32_fnames[] = "cvznxiup"; + const char *fnames + = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames; + + unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15)); + int i; + + for (i = 0; i < 8; i++) + if (flagbits & (1 << i)) + *cp++ = fnames[i]; + + return cp; +} + +/* Print out an insn with its operands, and update the info->insn_type + fields. The prefix_opcodep and the rest hold a prefix insn that is + supposed to be output as an address mode. */ + +static void +print_with_operands (const struct cris_opcode *opcodep, + unsigned int insn, + unsigned char *buffer, + bfd_vma addr, + disassemble_info *info, + /* If a prefix insn was before this insn (and is supposed + to be output as an address), here is a description of + it. */ + const struct cris_opcode *prefix_opcodep, + unsigned int prefix_insn, + unsigned char *prefix_buffer, + bfd_boolean with_reg_prefix) +{ + /* Get a buffer of somewhat reasonable size where we store + intermediate parts of the insn. */ + char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2]; + char *tp = temp; + static const char mode_char[] = "bwd?"; + const char *s; + const char *cs; + struct cris_disasm_data *disdata + = (struct cris_disasm_data *) info->private_data; + + /* Print out the name first thing we do. */ + (*info->fprintf_func) (info->stream, "%s", opcodep->name); + + cs = opcodep->args; + s = cs; + + /* Ignore any prefix indicator. */ + if (*s == 'p') + s++; + + if (*s == 'm' || *s == 'M' || *s == 'z') + { + *tp++ = '.'; + + /* Get the size-letter. */ + *tp++ = *s == 'M' + ? (insn & 0x8000 ? 'd' + : insn & 0x4000 ? 'w' : 'b') + : mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)]; + + /* Ignore the size and the space character that follows. */ + s += 2; + } + + /* Add a space if this isn't a long-branch, because for those will add + the condition part of the name later. */ + if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256)) + *tp++ = ' '; + + /* Fill in the insn-type if deducible from the name (and there's no + better way). */ + if (opcodep->name[0] == 'j') + { + if (CONST_STRNEQ (opcodep->name, "jsr")) + /* It's "jsr" or "jsrc". */ + info->insn_type = dis_jsr; + else + /* Any other jump-type insn is considered a branch. */ + info->insn_type = dis_branch; + } + + /* We might know some more fields right now. */ + info->branch_delay_insns = opcodep->delayed; + + /* Handle operands. */ + for (; *s; s++) + { + switch (*s) + { + case 'T': + tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix); + break; + + case 'A': + if (with_reg_prefix) + *tp++ = REGISTER_PREFIX_CHAR; + *tp++ = 'a'; + *tp++ = 'c'; + *tp++ = 'r'; + break; + + case '[': + case ']': + case ',': + *tp++ = *s; + break; + + case '!': + /* Ignore at this point; used at earlier stages to avoid + recognition if there's a prefix at something that in other + ways looks like a "pop". */ + break; + + case 'd': + /* Ignore. This is an optional ".d " on the large one of + relaxable insns. */ + break; + + case 'B': + /* This was the prefix that made this a "push". We've already + handled it by recognizing it, so signal that the prefix is + handled by setting it to NULL. */ + prefix_opcodep = NULL; + break; + + case 'D': + case 'r': + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + break; + + case 'R': + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + break; + + case 'n': + { + /* Like N but pc-relative to the start of the insn. */ + unsigned long number + = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + + buffer[5] * 0x1000000 + addr); + + /* Finish off and output previous formatted bytes. */ + *tp = 0; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + tp = temp; + + (*info->print_address_func) ((bfd_vma) number, info); + } + break; + + case 'u': + { + /* Like n but the offset is bits <3:0> in the instruction. */ + unsigned long number = (buffer[0] & 0xf) * 2 + addr; + + /* Finish off and output previous formatted bytes. */ + *tp = 0; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + tp = temp; + + (*info->print_address_func) ((bfd_vma) number, info); + } + break; + + case 'N': + case 'y': + case 'Y': + case 'S': + case 's': + /* Any "normal" memory operand. */ + if ((insn & 0x400) && (insn & 15) == 15 && prefix_opcodep == NULL) + { + /* We're looking at [pc+], i.e. we need to output an immediate + number, where the size can depend on different things. */ + long number; + int signedp + = ((*cs == 'z' && (insn & 0x20)) + || opcodep->match == BDAP_QUICK_OPCODE); + int nbytes; + + if (opcodep->imm_oprnd_size == SIZE_FIX_32) + nbytes = 4; + else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* A NULL return should have been as a non-match earlier, + so catch it as an internal error in the error-case + below. */ + if (sregp == NULL) + /* Whatever non-valid size. */ + nbytes = 42; + else + /* PC is always incremented by a multiple of two. + For CRISv32, immediates are always 4 bytes for + special registers. */ + nbytes = disdata->distype == cris_dis_v32 + ? 4 : (sregp->reg_size + 1) & ~1; + } + else + { + int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3)); + + if (mode_size == 1) + nbytes = 2; + else + nbytes = mode_size; + } + + switch (nbytes) + { + case 1: + number = buffer[2]; + if (signedp && number > 127) + number -= 256; + break; + + case 2: + number = buffer[2] + buffer[3] * 256; + if (signedp && number > 32767) + number -= 65536; + break; + + case 4: + number + = buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + + buffer[5] * 0x1000000; + break; + + default: + strcpy (tp, "bug"); + tp += 3; + number = 42; + } + + if ((*cs == 'z' && (insn & 0x20)) + || (opcodep->match == BDAP_QUICK_OPCODE + && (nbytes <= 2 || buffer[1 + nbytes] == 0))) + tp = format_dec (number, tp, signedp); + else + { + unsigned int highbyte = (number >> 24) & 0xff; + + /* Either output this as an address or as a number. If it's + a dword with the same high-byte as the address of the + insn, assume it's an address, and also if it's a non-zero + non-0xff high-byte. If this is a jsr or a jump, then + it's definitely an address. */ + if (nbytes == 4 + && (highbyte == ((addr >> 24) & 0xff) + || (highbyte != 0 && highbyte != 0xff) + || info->insn_type == dis_branch + || info->insn_type == dis_jsr)) + { + /* Finish off and output previous formatted bytes. */ + *tp = 0; + tp = temp; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + + info->target = number; + } + else + tp = format_hex (number, tp, disdata); + } + } + else + { + /* Not an immediate number. Then this is a (possibly + prefixed) memory operand. */ + if (info->insn_type != dis_nonbranch) + { + int mode_size + = 1 << ((insn >> 4) + & (opcodep->args[0] == 'z' ? 1 : 3)); + int size; + info->insn_type = dis_dref; + info->flags |= CRIS_DIS_FLAG_MEMREF; + + if (opcodep->imm_oprnd_size == SIZE_FIX_32) + size = 4; + else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + /* FIXME: Improve error handling; should have been caught + earlier. */ + if (sregp == NULL) + size = 4; + else + size = sregp->reg_size; + } + else + size = mode_size; + + info->data_size = size; + } + + *tp++ = '['; + + if (prefix_opcodep + /* We don't match dip with a postincremented field + as a side-effect address mode. */ + && ((insn & 0x400) == 0 + || prefix_opcodep->match != DIP_OPCODE)) + { + if (insn & 0x400) + { + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + *tp++ = '='; + } + + + /* We mainly ignore the prefix format string when the + address-mode syntax is output. */ + switch (prefix_opcodep->match) + { + case DIP_OPCODE: + /* It's [r], [r+] or [pc+]. */ + if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) + { + /* It's [pc+]. This cannot possibly be anything + but an address. */ + unsigned long number + = prefix_buffer[2] + prefix_buffer[3] * 256 + + prefix_buffer[4] * 65536 + + prefix_buffer[5] * 0x1000000; + + info->target = (bfd_vma) number; + + /* Finish off and output previous formatted + data. */ + *tp = 0; + tp = temp; + if (temp[0]) + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + } + else + { + /* For a memref in an address, we use target2. + In this case, target is zero. */ + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET2_MEM); + + info->target2 = prefix_insn & 15; + + *tp++ = '['; + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + if (prefix_insn & 0x400) + *tp++ = '+'; + *tp++ = ']'; + } + break; + + case BDAP_QUICK_OPCODE: + { + int number; + + number = prefix_buffer[0]; + if (number > 127) + number -= 256; + + /* Output "reg+num" or, if num < 0, "reg-num". */ + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + if (number >= 0) + *tp++ = '+'; + tp = format_dec (number, tp, 1); + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target = (prefix_insn >> 12) & 15; + info->target2 = (bfd_vma) number; + break; + } + + case BIAP_OPCODE: + /* Output "r+R.m". */ + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + *tp++ = '+'; + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + *tp++ = '.'; + *tp++ = mode_char[(prefix_insn >> 4) & 3]; + + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET_IS_REG + + | ((prefix_insn & 0x8000) + ? CRIS_DIS_FLAG_MEM_TARGET2_MULT4 + : ((prefix_insn & 0x8000) + ? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0))); + + /* Is it the casejump? It's a "adds.w [pc+r%d.w],pc". */ + if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f) + /* Then start interpreting data as offsets. */ + case_offset_counter = no_of_case_offsets; + break; + + case BDAP_INDIR_OPCODE: + /* Output "r+s.m", or, if "s" is [pc+], "r+s" or + "r-s". */ + tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp, + with_reg_prefix); + + if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) + { + long number; + unsigned int nbytes; + + /* It's a value. Get its size. */ + int mode_size = 1 << ((prefix_insn >> 4) & 3); + + if (mode_size == 1) + nbytes = 2; + else + nbytes = mode_size; + + switch (nbytes) + { + case 1: + number = prefix_buffer[2]; + if (number > 127) + number -= 256; + break; + + case 2: + number = prefix_buffer[2] + prefix_buffer[3] * 256; + if (number > 32767) + number -= 65536; + break; + + case 4: + number + = prefix_buffer[2] + prefix_buffer[3] * 256 + + prefix_buffer[4] * 65536 + + prefix_buffer[5] * 0x1000000; + break; + + default: + strcpy (tp, "bug"); + tp += 3; + number = 42; + } + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target2 = (bfd_vma) number; + + /* If the size is dword, then assume it's an + address. */ + if (nbytes == 4) + { + /* Finish off and output previous formatted + bytes. */ + *tp++ = '+'; + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s", temp); + + (*info->print_address_func) ((bfd_vma) number, info); + } + else + { + if (number >= 0) + *tp++ = '+'; + tp = format_dec (number, tp, 1); + } + } + else + { + /* Output "r+[R].m" or "r+[R+].m". */ + *tp++ = '+'; + *tp++ = '['; + tp = format_reg (disdata, prefix_insn & 15, tp, + with_reg_prefix); + if (prefix_insn & 0x400) + *tp++ = '+'; + *tp++ = ']'; + *tp++ = '.'; + *tp++ = mode_char[(prefix_insn >> 4) & 3]; + + info->flags + |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG + | CRIS_DIS_FLAG_MEM_TARGET2_MEM + | CRIS_DIS_FLAG_MEM_TARGET_IS_REG + + | (((prefix_insn >> 4) == 2) + ? 0 + : (((prefix_insn >> 4) & 3) == 1 + ? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD + : CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE))); + } + break; + + default: + (*info->fprintf_func) (info->stream, "?prefix-bug"); + } + + /* To mark that the prefix is used, reset it. */ + prefix_opcodep = NULL; + } + else + { + tp = format_reg (disdata, insn & 15, tp, with_reg_prefix); + + info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; + info->target = insn & 15; + + if (insn & 0x400) + *tp++ = '+'; + } + *tp++ = ']'; + } + break; + + case 'x': + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + *tp++ = '.'; + *tp++ = mode_char[(insn >> 4) & 3]; + break; + + case 'I': + tp = format_dec (insn & 63, tp, 0); + break; + + case 'b': + { + int where = buffer[2] + buffer[3] * 256; + + if (where > 32767) + where -= 65536; + + where += addr + ((disdata->distype == cris_dis_v32) ? 0 : 4); + + if (insn == BA_PC_INCR_OPCODE) + info->insn_type = dis_branch; + else + info->insn_type = dis_condbranch; + + info->target = (bfd_vma) where; + + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s%s ", + temp, cris_cc_strings[insn >> 12]); + + (*info->print_address_func) ((bfd_vma) where, info); + } + break; + + case 'c': + tp = format_dec (insn & 31, tp, 0); + break; + + case 'C': + tp = format_dec (insn & 15, tp, 0); + break; + + case 'o': + { + long offset = insn & 0xfe; + bfd_vma target; + + if (insn & 1) + offset |= ~0xff; + + if (opcodep->match == BA_QUICK_OPCODE) + info->insn_type = dis_branch; + else + info->insn_type = dis_condbranch; + + target = addr + ((disdata->distype == cris_dis_v32) ? 0 : 2) + offset; + info->target = target; + *tp = 0; + tp = temp; + (*info->fprintf_func) (info->stream, "%s", temp); + (*info->print_address_func) (target, info); + } + break; + + case 'Q': + case 'O': + { + long number = buffer[0]; + + if (number > 127) + number = number - 256; + + tp = format_dec (number, tp, 1); + *tp++ = ','; + tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix); + } + break; + + case 'f': + tp = print_flags (disdata, insn, tp); + break; + + case 'i': + tp = format_dec ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1); + break; + + case 'P': + { + const struct cris_spec_reg *sregp + = spec_reg_info ((insn >> 12) & 15, disdata->distype); + + if (sregp->name == NULL) + /* Should have been caught as a non-match eariler. */ + *tp++ = '?'; + else + { + if (with_reg_prefix) + *tp++ = REGISTER_PREFIX_CHAR; + strcpy (tp, sregp->name); + tp += strlen (tp); + } + } + break; + + default: + strcpy (tp, "???"); + tp += 3; + } + } + + *tp = 0; + + if (prefix_opcodep) + (*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")", + prefix_opcodep->name, prefix_opcodep->args); + + (*info->fprintf_func) (info->stream, "%s", temp); + + /* Get info for matching case-tables, if we don't have any active. + We assume that the last constant seen is used; either in the insn + itself or in a "move.d const,rN, sub.d rN,rM"-like sequence. */ + if (TRACE_CASE && case_offset_counter == 0) + { + if (CONST_STRNEQ (opcodep->name, "sub")) + case_offset = last_immediate; + + /* It could also be an "add", if there are negative case-values. */ + else if (CONST_STRNEQ (opcodep->name, "add")) + /* The first case is the negated operand to the add. */ + case_offset = -last_immediate; + + /* A bound insn will tell us the number of cases. */ + else if (CONST_STRNEQ (opcodep->name, "bound")) + no_of_case_offsets = last_immediate + 1; + + /* A jump or jsr or branch breaks the chain of insns for a + case-table, so assume default first-case again. */ + else if (info->insn_type == dis_jsr + || info->insn_type == dis_branch + || info->insn_type == dis_condbranch) + case_offset = 0; + } +} + + +/* Print the CRIS instruction at address memaddr on stream. Returns + length of the instruction, in bytes. Prefix register names with `$' if + WITH_REG_PREFIX. */ + +static int +print_insn_cris_generic (bfd_vma memaddr, + disassemble_info *info, + bfd_boolean with_reg_prefix) +{ + int nbytes; + unsigned int insn; + const struct cris_opcode *matchedp; + int advance = 0; + struct cris_disasm_data *disdata + = (struct cris_disasm_data *) info->private_data; + + /* No instruction will be disassembled as longer than this number of + bytes; stacked prefixes will not be expanded. */ + unsigned char buffer[MAX_BYTES_PER_CRIS_INSN]; + unsigned char *bufp; + int status = 0; + bfd_vma addr; + + /* There will be an "out of range" error after the last instruction. + Reading pairs of bytes in decreasing number, we hope that we will get + at least the amount that we will consume. + + If we can't get any data, or we do not get enough data, we print + the error message. */ + + for (nbytes = MAX_BYTES_PER_CRIS_INSN; nbytes > 0; nbytes -= 2) + { + status = (*info->read_memory_func) (memaddr, buffer, nbytes, info); + if (status == 0) + break; + } + + /* If we did not get all we asked for, then clear the rest. + Hopefully this makes a reproducible result in case of errors. */ + if (nbytes != MAX_BYTES_PER_CRIS_INSN) + memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes); + + addr = memaddr; + bufp = buffer; + + /* Set some defaults for the insn info. */ + info->insn_info_valid = 1; + info->branch_delay_insns = 0; + info->data_size = 0; + info->insn_type = dis_nonbranch; + info->flags = 0; + info->target = 0; + info->target2 = 0; + + /* If we got any data, disassemble it. */ + if (nbytes != 0) + { + matchedp = NULL; + + insn = bufp[0] + bufp[1] * 256; + + /* If we're in a case-table, don't disassemble the offsets. */ + if (TRACE_CASE && case_offset_counter != 0) + { + info->insn_type = dis_noninsn; + advance += 2; + + /* If to print data as offsets, then shortcut here. */ + (*info->fprintf_func) (info->stream, "case %ld%s: -> ", + case_offset + no_of_case_offsets + - case_offset_counter, + case_offset_counter == 1 ? "/default" : + ""); + + (*info->print_address_func) ((bfd_vma) + ((short) (insn) + + (long) (addr + - (no_of_case_offsets + - case_offset_counter) + * 2)), info); + case_offset_counter--; + + /* The default case start (without a "sub" or "add") must be + zero. */ + if (case_offset_counter == 0) + case_offset = 0; + } + else if (insn == 0) + { + /* We're often called to disassemble zeroes. While this is a + valid "bcc .+2" insn, it is also useless enough and enough + of a nuiscance that we will just output "bcc .+2" for it + and signal it as a noninsn. */ + (*info->fprintf_func) (info->stream, + disdata->distype == cris_dis_v32 + ? "bcc ." : "bcc .+2"); + info->insn_type = dis_noninsn; + advance += 2; + } + else + { + const struct cris_opcode *prefix_opcodep = NULL; + unsigned char *prefix_buffer = bufp; + unsigned int prefix_insn = insn; + int prefix_size = 0; + + matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX, disdata); + + /* Check if we're supposed to write out prefixes as address + modes and if this was a prefix. */ + if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p') + { + /* If it's a prefix, put it into the prefix vars and get the + main insn. */ + prefix_size = bytes_to_skip (prefix_insn, matchedp, + disdata->distype, NULL); + prefix_opcodep = matchedp; + + insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256; + matchedp = get_opcode_entry (insn, prefix_insn, disdata); + + if (matchedp != NULL) + { + addr += prefix_size; + bufp += prefix_size; + advance += prefix_size; + } + else + { + /* The "main" insn wasn't valid, at least not when + prefixed. Put back things enough to output the + prefix insn only, as a normal insn. */ + matchedp = prefix_opcodep; + insn = prefix_insn; + prefix_opcodep = NULL; + } + } + + if (matchedp == NULL) + { + (*info->fprintf_func) (info->stream, "??0x%x", insn); + advance += 2; + + info->insn_type = dis_noninsn; + } + else + { + advance + += bytes_to_skip (insn, matchedp, disdata->distype, + prefix_opcodep); + + /* The info_type and assorted fields will be set according + to the operands. */ + print_with_operands (matchedp, insn, bufp, addr, info, + prefix_opcodep, prefix_insn, + prefix_buffer, with_reg_prefix); + } + } + } + else + info->insn_type = dis_noninsn; + + /* If we read less than MAX_BYTES_PER_CRIS_INSN, i.e. we got an error + status when reading that much, and the insn decoding indicated a + length exceeding what we read, there is an error. */ + if (status != 0 && (nbytes == 0 || advance > nbytes)) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + /* Max supported insn size with one folded prefix insn. */ + info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN; + + /* I would like to set this to a fixed value larger than the actual + number of bytes to print in order to avoid spaces between bytes, + but objdump.c (2.9.1) does not like that, so we print 16-bit + chunks, which is the next choice. */ + info->bytes_per_chunk = 2; + + /* Printing bytes in order of increasing addresses makes sense, + especially on a little-endian target. + This is completely the opposite of what you think; setting this to + BFD_ENDIAN_LITTLE will print bytes in order N..0 rather than the 0..N + we want. */ + info->display_endian = BFD_ENDIAN_BIG; + + return advance; +} + +/* Disassemble, prefixing register names with `$'. CRIS v0..v10. */ +#if 0 +static int +print_insn_cris_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) + return -1; + return print_insn_cris_generic (vma, info, TRUE); +} +#endif +/* Disassemble, prefixing register names with `$'. CRIS v32. */ + +static int +print_insn_crisv32_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v32)) + return -1; + return print_insn_cris_generic (vma, info, TRUE); +} + +#if 0 +/* Disassemble, prefixing register names with `$'. + Common v10 and v32 subset. */ + +static int +print_insn_crisv10_v32_with_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) + return -1; + return print_insn_cris_generic (vma, info, TRUE); +} + +/* Disassemble, no prefixes on register names. CRIS v0..v10. */ + +static int +print_insn_cris_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) + return -1; + return print_insn_cris_generic (vma, info, FALSE); +} + +/* Disassemble, no prefixes on register names. CRIS v32. */ + +static int +print_insn_crisv32_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_v32)) + return -1; + return print_insn_cris_generic (vma, info, FALSE); +} + +/* Disassemble, no prefixes on register names. + Common v10 and v32 subset. */ + +static int +print_insn_crisv10_v32_without_register_prefix (bfd_vma vma, + disassemble_info *info) +{ + if (info->private_data == NULL + && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) + return -1; + return print_insn_cris_generic (vma, info, FALSE); +} +#endif + +int +print_insn_crisv32 (bfd_vma vma, + disassemble_info *info) +{ + return print_insn_crisv32_with_register_prefix(vma, info); +} + +/* Return a disassembler-function that prints registers with a `$' prefix, + or one that prints registers without a prefix. + FIXME: We should improve the solution to avoid the multitude of + functions seen above. */ +#if 0 +disassembler_ftype +cris_get_disassembler (bfd *abfd) +{ + /* If there's no bfd in sight, we return what is valid as input in all + contexts if fed back to the assembler: disassembly *with* register + prefix. Unfortunately this will be totally wrong for v32. */ + if (abfd == NULL) + return print_insn_cris_with_register_prefix; + + if (bfd_get_symbol_leading_char (abfd) == 0) + { + if (bfd_get_mach (abfd) == bfd_mach_cris_v32) + return print_insn_crisv32_with_register_prefix; + if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32) + return print_insn_crisv10_v32_with_register_prefix; + + /* We default to v10. This may be specifically specified in the + bfd mach, but is also the default setting. */ + return print_insn_cris_with_register_prefix; + } + + if (bfd_get_mach (abfd) == bfd_mach_cris_v32) + return print_insn_crisv32_without_register_prefix; + if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32) + return print_insn_crisv10_v32_without_register_prefix; + return print_insn_cris_without_register_prefix; +} +#endif +/* Local variables: + eval: (c-set-style "gnu") + indent-tabs-mode: t + End: */ diff --git a/target-cris/opcode-cris.h b/target-cris/opcode-cris.h new file mode 100644 index 000000000..76fbc2f3c --- /dev/null +++ b/target-cris/opcode-cris.h @@ -0,0 +1,366 @@ +/* cris.h -- Header file for CRIS opcode and register tables. + Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc. + Contributed by Axis Communications AB, Lund, Sweden. + Originally written for GAS 1.38.1 by Mikael Asker. + Updated, BFDized and GNUified by Hans-Peter Nilsson. + +This file is part of GAS, GDB and the GNU binutils. + +GAS, GDB, and GNU binutils 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, or (at your +option) any later version. + +GAS, GDB, and 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 program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef __CRIS_H_INCLUDED_ +#define __CRIS_H_INCLUDED_ + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + + +/* Registers. */ +#define MAX_REG (15) +#define REG_SP (14) +#define REG_PC (15) + +/* CPU version control of disassembly and assembly of instructions. + May affect how the instruction is assembled, at least the size of + immediate operands. */ +enum cris_insn_version_usage +{ + /* Any version. */ + cris_ver_version_all=0, + + /* Indeterminate (intended for disassembly only, or obsolete). */ + cris_ver_warning, + + /* Only for v0..3 (Etrax 1..4). */ + cris_ver_v0_3, + + /* Only for v3 or higher (ETRAX 4 and beyond). */ + cris_ver_v3p, + + /* Only for v8 (Etrax 100). */ + cris_ver_v8, + + /* Only for v8 or higher (ETRAX 100, ETRAX 100 LX). */ + cris_ver_v8p, + + /* Only for v0..10. FIXME: Not sure what to do with this. */ + cris_ver_sim_v0_10, + + /* Only for v0..10. */ + cris_ver_v0_10, + + /* Only for v3..10. (ETRAX 4, ETRAX 100 and ETRAX 100 LX). */ + cris_ver_v3_10, + + /* Only for v8..10 (ETRAX 100 and ETRAX 100 LX). */ + cris_ver_v8_10, + + /* Only for v10 (ETRAX 100 LX) and same series. */ + cris_ver_v10, + + /* Only for v10 (ETRAX 100 LX) and same series. */ + cris_ver_v10p, + + /* Only for v32 or higher (codename GUINNESS). + Of course some or all these of may change to cris_ver_v32p if/when + there's a new revision. */ + cris_ver_v32p +}; + + +/* Special registers. */ +struct cris_spec_reg +{ + const char *const name; + unsigned int number; + + /* The size of the register. */ + unsigned int reg_size; + + /* What CPU version the special register of that name is implemented + in. If cris_ver_warning, emit an unimplemented-warning. */ + enum cris_insn_version_usage applicable_version; + + /* There might be a specific warning for using a special register + here. */ + const char *const warning; +}; +extern const struct cris_spec_reg cris_spec_regs[]; + + +/* Support registers (kind of special too, but not named as such). */ +struct cris_support_reg +{ + const char *const name; + unsigned int number; +}; +extern const struct cris_support_reg cris_support_regs[]; + +struct cris_cond15 +{ + /* The name of the condition. */ + const char *const name; + + /* What CPU version this condition name applies to. */ + enum cris_insn_version_usage applicable_version; +}; +extern const struct cris_cond15 cris_conds15[]; + +/* Opcode-dependent constants. */ +#define AUTOINCR_BIT (0x04) + +/* Prefixes. */ +#define BDAP_QUICK_OPCODE (0x0100) +#define BDAP_QUICK_Z_BITS (0x0e00) + +#define BIAP_OPCODE (0x0540) +#define BIAP_Z_BITS (0x0a80) + +#define DIP_OPCODE (0x0970) +#define DIP_Z_BITS (0xf280) + +#define BDAP_INDIR_LOW (0x40) +#define BDAP_INDIR_LOW_Z (0x80) +#define BDAP_INDIR_HIGH (0x09) +#define BDAP_INDIR_HIGH_Z (0x02) + +#define BDAP_INDIR_OPCODE (BDAP_INDIR_HIGH * 0x0100 + BDAP_INDIR_LOW) +#define BDAP_INDIR_Z_BITS (BDAP_INDIR_HIGH_Z * 0x100 + BDAP_INDIR_LOW_Z) +#define BDAP_PC_LOW (BDAP_INDIR_LOW + REG_PC) +#define BDAP_INCR_HIGH (BDAP_INDIR_HIGH + AUTOINCR_BIT) + +/* No prefix must have this code for its "match" bits in the + opcode-table. "BCC .+2" will do nicely. */ +#define NO_CRIS_PREFIX 0 + +/* Definitions for condition codes. */ +#define CC_CC 0x0 +#define CC_HS 0x0 +#define CC_CS 0x1 +#define CC_LO 0x1 +#define CC_NE 0x2 +#define CC_EQ 0x3 +#define CC_VC 0x4 +#define CC_VS 0x5 +#define CC_PL 0x6 +#define CC_MI 0x7 +#define CC_LS 0x8 +#define CC_HI 0x9 +#define CC_GE 0xA +#define CC_LT 0xB +#define CC_GT 0xC +#define CC_LE 0xD +#define CC_A 0xE +#define CC_EXT 0xF + +/* A table of strings "cc", "cs"... indexed with condition code + values as above. */ +extern const char *const cris_cc_strings[]; + +/* Bcc quick. */ +#define BRANCH_QUICK_LOW (0) +#define BRANCH_QUICK_HIGH (0) +#define BRANCH_QUICK_OPCODE (BRANCH_QUICK_HIGH * 0x0100 + BRANCH_QUICK_LOW) +#define BRANCH_QUICK_Z_BITS (0x0F00) + +/* BA quick. */ +#define BA_QUICK_HIGH (BRANCH_QUICK_HIGH + CC_A * 0x10) +#define BA_QUICK_OPCODE (BA_QUICK_HIGH * 0x100 + BRANCH_QUICK_LOW) + +/* Bcc [PC+]. */ +#define BRANCH_PC_LOW (0xFF) +#define BRANCH_INCR_HIGH (0x0D) +#define BA_PC_INCR_OPCODE \ + ((BRANCH_INCR_HIGH + CC_A * 0x10) * 0x0100 + BRANCH_PC_LOW) + +/* Jump. */ +/* Note that old versions generated special register 8 (in high bits) + and not-that-old versions recognized it as a jump-instruction. + That opcode now belongs to JUMPU. */ +#define JUMP_INDIR_OPCODE (0x0930) +#define JUMP_INDIR_Z_BITS (0xf2c0) +#define JUMP_PC_INCR_OPCODE \ + (JUMP_INDIR_OPCODE + AUTOINCR_BIT * 0x0100 + REG_PC) + +#define MOVE_M_TO_PREG_OPCODE 0x0a30 +#define MOVE_M_TO_PREG_ZBITS 0x01c0 + +/* BDAP.D N,PC. */ +#define MOVE_PC_INCR_OPCODE_PREFIX \ + (((BDAP_INCR_HIGH | (REG_PC << 4)) << 8) | BDAP_PC_LOW | (2 << 4)) +#define MOVE_PC_INCR_OPCODE_SUFFIX \ + (MOVE_M_TO_PREG_OPCODE | REG_PC | (AUTOINCR_BIT << 8)) + +#define JUMP_PC_INCR_OPCODE_V32 (0x0DBF) + +/* BA DWORD (V32). */ +#define BA_DWORD_OPCODE (0x0EBF) + +/* Nop. */ +#define NOP_OPCODE (0x050F) +#define NOP_Z_BITS (0xFFFF ^ NOP_OPCODE) + +#define NOP_OPCODE_V32 (0x05B0) +#define NOP_Z_BITS_V32 (0xFFFF ^ NOP_OPCODE_V32) + +/* For the compatibility mode, let's use "MOVE R0,P0". Doesn't affect + registers or flags. Unfortunately shuts off interrupts for one cycle + for < v32, but there doesn't seem to be any alternative without that + effect. */ +#define NOP_OPCODE_COMMON (0x630) +#define NOP_OPCODE_ZBITS_COMMON (0xffff & ~NOP_OPCODE_COMMON) + +/* LAPC.D */ +#define LAPC_DWORD_OPCODE (0x0D7F) +#define LAPC_DWORD_Z_BITS (0x0fff & ~LAPC_DWORD_OPCODE) + +/* Structure of an opcode table entry. */ +enum cris_imm_oprnd_size_type +{ + /* No size is applicable. */ + SIZE_NONE, + + /* Always 32 bits. */ + SIZE_FIX_32, + + /* Indicated by size of special register. */ + SIZE_SPEC_REG, + + /* Indicated by size field, signed. */ + SIZE_FIELD_SIGNED, + + /* Indicated by size field, unsigned. */ + SIZE_FIELD_UNSIGNED, + + /* Indicated by size field, no sign implied. */ + SIZE_FIELD +}; + +/* For GDB. FIXME: Is this the best way to handle opcode + interpretation? */ +enum cris_op_type +{ + cris_not_implemented_op = 0, + cris_abs_op, + cris_addi_op, + cris_asr_op, + cris_asrq_op, + cris_ax_ei_setf_op, + cris_bdap_prefix, + cris_biap_prefix, + cris_break_op, + cris_btst_nop_op, + cris_clearf_di_op, + cris_dip_prefix, + cris_dstep_logshift_mstep_neg_not_op, + cris_eight_bit_offset_branch_op, + cris_move_mem_to_reg_movem_op, + cris_move_reg_to_mem_movem_op, + cris_move_to_preg_op, + cris_muls_op, + cris_mulu_op, + cris_none_reg_mode_add_sub_cmp_and_or_move_op, + cris_none_reg_mode_clear_test_op, + cris_none_reg_mode_jump_op, + cris_none_reg_mode_move_from_preg_op, + cris_quick_mode_add_sub_op, + cris_quick_mode_and_cmp_move_or_op, + cris_quick_mode_bdap_prefix, + cris_reg_mode_add_sub_cmp_and_or_move_op, + cris_reg_mode_clear_op, + cris_reg_mode_jump_op, + cris_reg_mode_move_from_preg_op, + cris_reg_mode_test_op, + cris_scc_op, + cris_sixteen_bit_offset_branch_op, + cris_three_operand_add_sub_cmp_and_or_op, + cris_three_operand_bound_op, + cris_two_operand_bound_op, + cris_xor_op +}; + +struct cris_opcode +{ + /* The name of the insn. */ + const char *name; + + /* Bits that must be 1 for a match. */ + unsigned int match; + + /* Bits that must be 0 for a match. */ + unsigned int lose; + + /* See the table in "opcodes/cris-opc.c". */ + const char *args; + + /* Nonzero if this is a delayed branch instruction. */ + char delayed; + + /* Size of immediate operands. */ + enum cris_imm_oprnd_size_type imm_oprnd_size; + + /* Indicates which version this insn was first implemented in. */ + enum cris_insn_version_usage applicable_version; + + /* What kind of operation this is. */ + enum cris_op_type op; +}; +extern const struct cris_opcode cris_opcodes[]; + + +/* These macros are for the target-specific flags in disassemble_info + used at disassembly. */ + +/* This insn accesses memory. This flag is more trustworthy than + checking insn_type for "dis_dref" which does not work for + e.g. "JSR [foo]". */ +#define CRIS_DIS_FLAG_MEMREF (1 << 0) + +/* The "target" field holds a register number. */ +#define CRIS_DIS_FLAG_MEM_TARGET_IS_REG (1 << 1) + +/* The "target2" field holds a register number; add it to "target". */ +#define CRIS_DIS_FLAG_MEM_TARGET2_IS_REG (1 << 2) + +/* Yet another add-on: the register in "target2" must be multiplied + by 2 before adding to "target". */ +#define CRIS_DIS_FLAG_MEM_TARGET2_MULT2 (1 << 3) + +/* Yet another add-on: the register in "target2" must be multiplied + by 4 (mutually exclusive with .._MULT2). */ +#define CRIS_DIS_FLAG_MEM_TARGET2_MULT4 (1 << 4) + +/* The register in "target2" is an indirect memory reference (of the + register there), add to "target". Assumed size is dword (mutually + exclusive with .._MULT[24]). */ +#define CRIS_DIS_FLAG_MEM_TARGET2_MEM (1 << 5) + +/* Add-on to CRIS_DIS_FLAG_MEM_TARGET2_MEM; the memory access is "byte"; + sign-extended before adding to "target". */ +#define CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE (1 << 6) + +/* Add-on to CRIS_DIS_FLAG_MEM_TARGET2_MEM; the memory access is "word"; + sign-extended before adding to "target". */ +#define CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD (1 << 7) + +#endif /* __CRIS_H_INCLUDED_ */ + +/* + * Local variables: + * eval: (c-set-style "gnu") + * indent-tabs-mode: t + * End: + */ -- cgit v1.2.3 From a25fd137c39406c9871640521492960e28388372 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 12:46:58 +0000 Subject: Wire up CRIS disassembler, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3357 c046a42c-6fe2-441c-8c8c-71466251a162 --- dis-asm.h | 5 +++++ disas.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/dis-asm.h b/dis-asm.h index bacd9c46b..a805a48e5 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -200,6 +200,10 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200, /* Matsushita MN10200 */ bfd_arch_mn10300, /* Matsushita MN10300 */ + bfd_arch_cris, /* Axis CRIS */ +#define bfd_mach_cris_v0_v10 255 +#define bfd_mach_cris_v32 32 +#define bfd_mach_cris_v10_v32 1032 bfd_arch_last }; #define bfd_mach_s390_31 31 @@ -382,6 +386,7 @@ extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_s390 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_crisv32 PARAMS ((bfd_vma, disassemble_info*)); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/disas.c b/disas.c index ae20d37bc..fe1fa9d5a 100644 --- a/disas.c +++ b/disas.c @@ -205,6 +205,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #elif defined(TARGET_ALPHA) disasm_info.mach = bfd_mach_alpha; print_insn = print_insn_alpha; +#elif defined(TARGET_CRIS) + disasm_info.mach = bfd_mach_cris_v32; + print_insn = print_insn_crisv32; #else fprintf(out, "0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", code); -- cgit v1.2.3 From 8170028d75297abac0124a2520380ec988ea1d19 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 12:49:08 +0000 Subject: CRIS instruction translation, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3358 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-cris/translate.c | 2507 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2507 insertions(+) create mode 100644 target-cris/translate.c diff --git a/target-cris/translate.c b/target-cris/translate.c new file mode 100644 index 000000000..40caef073 --- /dev/null +++ b/target-cris/translate.c @@ -0,0 +1,2507 @@ +/* + * CRIS emulation for qemu: main translation routines. + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias. + * + * 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 + */ + +/* + * This file implements a CRIS decoder-stage in SW. The decoder translates the + * guest (CRIS) machine-code into host machine code via dyngen using the + * micro-operations described in op.c + * + * The micro-operations for CRIS translation implement a RISC style ISA. + * Note that the micro-operations typically order their operands + * starting with the dst. CRIS asm, does the opposite. + * + * For example the following CRIS code: + * add.d [$r0], $r1 + * + * translates into: + * + * gen_movl_T0_reg(0); // Fetch $r0 into T0 + * gen_load_T0_T0(); // Load T0, @T0 + * gen_movl_reg_T0(1); // Writeback T0 into $r1 + * + * The actual names for the micro-code generators vary but the example + * illustrates the point. + */ + +#include +#include +#include +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "crisv32-decode.h" + +#define CRIS_STATS 0 +#if CRIS_STATS +#define STATS(x) x +#else +#define STATS(x) +#endif + +#define DISAS_CRIS 0 +#if DISAS_CRIS +#define DIS(x) x +#else +#define DIS(x) +#endif + +#ifdef USE_DIRECT_JUMP +#define TBPARAM(x) +#else +#define TBPARAM(x) (long)(x) +#endif + +#define BUG() (gen_BUG(dc, __FILE__, __LINE__)) +#define BUG_ON(x) ({if (x) BUG();}) + +/* Used by the decoder. */ +#define EXTRACT_FIELD(src, start, end) \ + (((src) >> start) & ((1 << (end - start + 1)) - 1)) + +#define CC_MASK_NZ 0xc +#define CC_MASK_NZV 0xe +#define CC_MASK_NZVC 0xf +#define CC_MASK_RNZV 0x10e + +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; +#include "gen-op.h" + +/* This is the state at translation time. */ +typedef struct DisasContext { + CPUState *env; + target_ulong pc, insn_pc; + + /* Decoder. */ + uint32_t ir; + uint32_t opcode; + unsigned int op1; + unsigned int op2; + unsigned int zsize, zzsize; + unsigned int mode; + unsigned int postinc; + + + struct + { + int op; + int size; + unsigned int mask; + } cc_state[3]; + int cc_i; + + int update_cc; + int cc_op; + int cc_size; + uint32_t cc_mask; + int flags_live; + int flagx_live; + int flags_x; + uint32_t tb_entry_flags; + + int memidx; /* user or kernel mode. */ + int is_jmp; + int dyn_jmp; + + uint32_t delayed_pc; + int delayed_branch; + int bcc; + uint32_t condlabel; + + struct TranslationBlock *tb; + int singlestep_enabled; +} DisasContext; + +void cris_prepare_jmp (DisasContext *dc, uint32_t dst); +static void gen_BUG(DisasContext *dc, char *file, int line) +{ + printf ("BUG: pc=%x %s %d\n", dc->pc, file, line); + fprintf (logfile, "BUG: pc=%x %s %d\n", dc->pc, file, line); + cpu_dump_state (dc->env, stdout, fprintf, 0); + fflush(NULL); + cris_prepare_jmp (dc, 0x70000000 + line); +} + +/* Table to generate quick moves from T0 onto any register. */ +static GenOpFunc *gen_movl_reg_T0[16] = +{ + gen_op_movl_r0_T0, gen_op_movl_r1_T0, + gen_op_movl_r2_T0, gen_op_movl_r3_T0, + gen_op_movl_r4_T0, gen_op_movl_r5_T0, + gen_op_movl_r6_T0, gen_op_movl_r7_T0, + gen_op_movl_r8_T0, gen_op_movl_r9_T0, + gen_op_movl_r10_T0, gen_op_movl_r11_T0, + gen_op_movl_r12_T0, gen_op_movl_r13_T0, + gen_op_movl_r14_T0, gen_op_movl_r15_T0, +}; +static GenOpFunc *gen_movl_T0_reg[16] = +{ + gen_op_movl_T0_r0, gen_op_movl_T0_r1, + gen_op_movl_T0_r2, gen_op_movl_T0_r3, + gen_op_movl_T0_r4, gen_op_movl_T0_r5, + gen_op_movl_T0_r6, gen_op_movl_T0_r7, + gen_op_movl_T0_r8, gen_op_movl_T0_r9, + gen_op_movl_T0_r10, gen_op_movl_T0_r11, + gen_op_movl_T0_r12, gen_op_movl_T0_r13, + gen_op_movl_T0_r14, gen_op_movl_T0_r15, +}; + +static void noop_write(void) { + /* nop. */ +} + +static void gen_vr_read(void) { + gen_op_movl_T0_im(32); +} + +static void gen_ccs_read(void) { + gen_op_movl_T0_p13(); +} + +static void gen_ccs_write(void) { + gen_op_movl_p13_T0(); +} + +/* Table to generate quick moves from T0 onto any register. */ +static GenOpFunc *gen_movl_preg_T0[16] = +{ + noop_write, /* bz, not writeable. */ + noop_write, /* vr, not writeable. */ + gen_op_movl_p2_T0, gen_op_movl_p3_T0, + noop_write, /* wz, not writeable. */ + gen_op_movl_p5_T0, + gen_op_movl_p6_T0, gen_op_movl_p7_T0, + noop_write, /* dz, not writeable. */ + gen_op_movl_p9_T0, + gen_op_movl_p10_T0, gen_op_movl_p11_T0, + gen_op_movl_p12_T0, + gen_ccs_write, /* ccs needs special treatment. */ + gen_op_movl_p14_T0, gen_op_movl_p15_T0, +}; +static GenOpFunc *gen_movl_T0_preg[16] = +{ + gen_op_movl_T0_p0, + gen_vr_read, + gen_op_movl_T0_p2, gen_op_movl_T0_p3, + gen_op_movl_T0_p4, gen_op_movl_T0_p5, + gen_op_movl_T0_p6, gen_op_movl_T0_p7, + gen_op_movl_T0_p8, gen_op_movl_T0_p9, + gen_op_movl_T0_p10, gen_op_movl_T0_p11, + gen_op_movl_T0_p12, + gen_ccs_read, /* ccs needs special treatment. */ + gen_op_movl_T0_p14, gen_op_movl_T0_p15, +}; + +/* We need this table to handle moves with implicit width. */ +int preg_sizes[] = { + 1, /* bz. */ + 1, /* vr. */ + 4, /* pid. */ + 1, /* srs. */ + 2, /* wz. */ + 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, +}; + +#ifdef CONFIG_USER_ONLY +#define GEN_OP_LD(width, reg) \ + void gen_op_ld##width##_T0_##reg (DisasContext *dc) { \ + gen_op_ld##width##_T0_##reg##_raw(); \ + } +#define GEN_OP_ST(width, reg) \ + void gen_op_st##width##_##reg##_T1 (DisasContext *dc) { \ + gen_op_st##width##_##reg##_T1_raw(); \ + } +#else +#define GEN_OP_LD(width, reg) \ + void gen_op_ld##width##_T0_##reg (DisasContext *dc) { \ + if (dc->memidx) gen_op_ld##width##_T0_##reg##_kernel(); \ + else gen_op_ld##width##_T0_##reg##_user();\ + } +#define GEN_OP_ST(width, reg) \ + void gen_op_st##width##_##reg##_T1 (DisasContext *dc) { \ + if (dc->memidx) gen_op_st##width##_##reg##_T1_kernel(); \ + else gen_op_st##width##_##reg##_T1_user();\ + } +#endif + +GEN_OP_LD(ub, T0) +GEN_OP_LD(b, T0) +GEN_OP_ST(b, T0) +GEN_OP_LD(uw, T0) +GEN_OP_LD(w, T0) +GEN_OP_ST(w, T0) +GEN_OP_LD(l, T0) +GEN_OP_ST(l, T0) + +static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) +{ + TranslationBlock *tb; + tb = dc->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + if (n == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_op_movl_T0_0(); + } else { + gen_op_movl_T0_0(); + } + gen_op_exit_tb(); +} + +/* Sign extend at translation time. */ +static int sign_extend(unsigned int val, unsigned int width) +{ + int sval; + + /* LSL. */ + val <<= 31 - width; + sval = val; + /* ASR. */ + sval >>= 31 - width; + return sval; +} + +static void cris_evaluate_flags(DisasContext *dc) +{ + if (!dc->flags_live) { + + switch (dc->cc_op) + { + case CC_OP_MCP: + gen_op_evaluate_flags_mcp (); + break; + case CC_OP_MULS: + gen_op_evaluate_flags_muls (); + break; + case CC_OP_MULU: + gen_op_evaluate_flags_mulu (); + break; + case CC_OP_MOVE: + switch (dc->cc_size) + { + case 4: + gen_op_evaluate_flags_move_4(); + break; + case 2: + gen_op_evaluate_flags_move_2(); + break; + default: + gen_op_evaluate_flags (); + break; + } + break; + + default: + { + switch (dc->cc_size) + { + case 4: + gen_op_evaluate_flags_alu_4 (); + break; + default: + gen_op_evaluate_flags (); + break; + } + } + break; + } + dc->flags_live = 1; + } +} + +static void cris_cc_mask(DisasContext *dc, unsigned int mask) +{ + uint32_t ovl; + + ovl = (dc->cc_mask ^ mask) & ~mask; + if (ovl) { + /* TODO: optimize this case. It trigs all the time. */ + cris_evaluate_flags (dc); + } + dc->cc_mask = mask; + + dc->update_cc = 1; + if (mask == 0) + dc->update_cc = 0; + else { + gen_op_update_cc_mask(mask); + dc->flags_live = 0; + } +} + +static void cris_update_cc_op(DisasContext *dc, int op) +{ + dc->cc_op = op; + gen_op_update_cc_op(op); + dc->flags_live = 0; +} +static void cris_update_cc_size(DisasContext *dc, int size) +{ + dc->cc_size = size; + gen_op_update_cc_size_im(size); +} + +/* op is the operation. + T0, T1 are the operands. + dst is the destination reg. +*/ +static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) +{ + int writeback = 1; + if (dc->update_cc) { + cris_update_cc_op(dc, op); + cris_update_cc_size(dc, size); + gen_op_update_cc_x(dc->flagx_live, dc->flags_x); + gen_op_update_cc_dest_T0(); + } + + /* Emit the ALU insns. */ + switch (op) + { + case CC_OP_ADD: + gen_op_addl_T0_T1(); + /* Extended arithmetics. */ + if (!dc->flagx_live) + gen_op_addxl_T0_C(); + else if (dc->flags_x) + gen_op_addxl_T0_C(); + break; + case CC_OP_ADDC: + gen_op_addl_T0_T1(); + gen_op_addl_T0_C(); + break; + case CC_OP_MCP: + gen_op_addl_T0_T1(); + gen_op_addl_T0_R(); + break; + case CC_OP_SUB: + gen_op_negl_T1_T1(); + gen_op_addl_T0_T1(); + /* CRIS flag evaluation needs ~src. */ + gen_op_negl_T1_T1(); + gen_op_not_T1_T1(); + + /* Extended arithmetics. */ + if (!dc->flagx_live) + gen_op_subxl_T0_C(); + else if (dc->flags_x) + gen_op_subxl_T0_C(); + break; + case CC_OP_MOVE: + gen_op_movl_T0_T1(); + break; + case CC_OP_OR: + gen_op_orl_T0_T1(); + break; + case CC_OP_AND: + gen_op_andl_T0_T1(); + break; + case CC_OP_XOR: + gen_op_xorl_T0_T1(); + break; + case CC_OP_LSL: + gen_op_lsll_T0_T1(); + break; + case CC_OP_LSR: + gen_op_lsrl_T0_T1(); + break; + case CC_OP_ASR: + gen_op_asrl_T0_T1(); + break; + case CC_OP_NEG: + gen_op_negl_T0_T1(); + /* Extended arithmetics. */ + gen_op_subxl_T0_C(); + break; + case CC_OP_LZ: + gen_op_lz_T0_T1(); + break; + case CC_OP_BTST: + gen_op_btst_T0_T1(); + writeback = 0; + break; + case CC_OP_MULS: + gen_op_muls_T0_T1(); + break; + case CC_OP_MULU: + gen_op_mulu_T0_T1(); + break; + case CC_OP_DSTEP: + gen_op_dstep_T0_T1(); + break; + case CC_OP_BOUND: + gen_op_bound_T0_T1(); + break; + case CC_OP_CMP: + gen_op_negl_T1_T1(); + gen_op_addl_T0_T1(); + /* CRIS flag evaluation needs ~src. */ + gen_op_negl_T1_T1(); + gen_op_not_T1_T1(); + + /* Extended arithmetics. */ + gen_op_subxl_T0_C(); + writeback = 0; + break; + default: + fprintf (logfile, "illegal ALU op.\n"); + BUG(); + break; + } + + if (dc->update_cc) + gen_op_update_cc_src_T1(); + + if (size == 1) + gen_op_andl_T0_im(0xff); + else if (size == 2) + gen_op_andl_T0_im(0xffff); + /* Writeback. */ + if (writeback) { + if (size == 4) + gen_movl_reg_T0[rd](); + else { + gen_op_movl_T1_T0(); + gen_movl_T0_reg[rd](); + if (size == 1) + gen_op_andl_T0_im(~0xff); + else + gen_op_andl_T0_im(~0xffff); + gen_op_orl_T0_T1(); + gen_movl_reg_T0[rd](); + gen_op_movl_T0_T1(); + } + } + if (dc->update_cc) + gen_op_update_cc_result_T0(); + + { + /* TODO: Optimize this. */ + if (!dc->flagx_live) + cris_evaluate_flags(dc); + } +} + +static int arith_cc(DisasContext *dc) +{ + if (dc->update_cc) { + switch (dc->cc_op) { + case CC_OP_ADD: return 1; + case CC_OP_SUB: return 1; + case CC_OP_LSL: return 1; + case CC_OP_LSR: return 1; + case CC_OP_ASR: return 1; + case CC_OP_CMP: return 1; + default: + return 0; + } + } + return 0; +} + +static void gen_tst_cc (DisasContext *dc, int cond) +{ + int arith_opt; + + /* TODO: optimize more condition codes. */ + arith_opt = arith_cc(dc) && !dc->flags_live; + switch (cond) { + case CC_EQ: + if (arith_opt) + gen_op_tst_cc_eq_fast (); + else { + cris_evaluate_flags(dc); + gen_op_tst_cc_eq (); + } + break; + case CC_NE: + if (arith_opt) + gen_op_tst_cc_ne_fast (); + else { + cris_evaluate_flags(dc); + gen_op_tst_cc_ne (); + } + break; + case CC_CS: + cris_evaluate_flags(dc); + gen_op_tst_cc_cs (); + break; + case CC_CC: + cris_evaluate_flags(dc); + gen_op_tst_cc_cc (); + break; + case CC_VS: + cris_evaluate_flags(dc); + gen_op_tst_cc_vs (); + break; + case CC_VC: + cris_evaluate_flags(dc); + gen_op_tst_cc_vc (); + break; + case CC_PL: + if (arith_opt) + gen_op_tst_cc_pl_fast (); + else { + cris_evaluate_flags(dc); + gen_op_tst_cc_pl (); + } + break; + case CC_MI: + if (arith_opt) + gen_op_tst_cc_mi_fast (); + else { + cris_evaluate_flags(dc); + gen_op_tst_cc_mi (); + } + break; + case CC_LS: + cris_evaluate_flags(dc); + gen_op_tst_cc_ls (); + break; + case CC_HI: + cris_evaluate_flags(dc); + gen_op_tst_cc_hi (); + break; + case CC_GE: + cris_evaluate_flags(dc); + gen_op_tst_cc_ge (); + break; + case CC_LT: + cris_evaluate_flags(dc); + gen_op_tst_cc_lt (); + break; + case CC_GT: + cris_evaluate_flags(dc); + gen_op_tst_cc_gt (); + break; + case CC_LE: + cris_evaluate_flags(dc); + gen_op_tst_cc_le (); + break; + case CC_P: + cris_evaluate_flags(dc); + gen_op_tst_cc_p (); + break; + case CC_A: + cris_evaluate_flags(dc); + gen_op_movl_T0_im (1); + break; + default: + BUG(); + break; + }; +} + +static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond) +{ + /* This helps us re-schedule the micro-code to insns in delay-slots + before the actual jump. */ + dc->delayed_branch = 2; + dc->delayed_pc = dc->pc + offset; + dc->bcc = cond; + if (cond != CC_A) + { + gen_tst_cc (dc, cond); + gen_op_evaluate_bcc (); + } + gen_op_movl_T0_im (dc->delayed_pc); + gen_op_movl_btarget_T0 (); +} + +/* Dynamic jumps, when the dest is in a live reg for example. */ +void cris_prepare_dyn_jmp (DisasContext *dc) +{ + /* This helps us re-schedule the micro-code to insns in delay-slots + before the actual jump. */ + dc->delayed_branch = 2; + dc->dyn_jmp = 1; + dc->bcc = CC_A; +} + +void cris_prepare_jmp (DisasContext *dc, uint32_t dst) +{ + /* This helps us re-schedule the micro-code to insns in delay-slots + before the actual jump. */ + dc->delayed_branch = 2; + dc->delayed_pc = dst; + dc->dyn_jmp = 0; + dc->bcc = CC_A; +} + +void gen_load_T0_T0 (DisasContext *dc, unsigned int size, int sign) +{ + if (size == 1) { + if (sign) + gen_op_ldb_T0_T0(dc); + else + gen_op_ldub_T0_T0(dc); + } + else if (size == 2) { + if (sign) + gen_op_ldw_T0_T0(dc); + else + gen_op_lduw_T0_T0(dc); + } + else { + gen_op_ldl_T0_T0(dc); + } +} + +void gen_store_T0_T1 (DisasContext *dc, unsigned int size) +{ + /* Remember, operands are flipped. CRIS has reversed order. */ + if (size == 1) { + gen_op_stb_T0_T1(dc); + } + else if (size == 2) { + gen_op_stw_T0_T1(dc); + } + else + gen_op_stl_T0_T1(dc); +} + +/* sign extend T1 according to size. */ +static void gen_sext_T1_T0(int size) +{ + if (size == 1) + gen_op_extb_T1_T0(); + else if (size == 2) + gen_op_extw_T1_T0(); +} + +static void gen_sext_T1_T1(int size) +{ + if (size == 1) + gen_op_extb_T1_T1(); + else if (size == 2) + gen_op_extw_T1_T1(); +} + +static void gen_sext_T0_T0(int size) +{ + if (size == 1) + gen_op_extb_T0_T0(); + else if (size == 2) + gen_op_extw_T0_T0(); +} + +static void gen_zext_T0_T0(int size) +{ + if (size == 1) + gen_op_zextb_T0_T0(); + else if (size == 2) + gen_op_zextw_T0_T0(); +} + +static void gen_zext_T1_T0(int size) +{ + if (size == 1) + gen_op_zextb_T1_T0(); + else if (size == 2) + gen_op_zextw_T1_T0(); +} + +static void gen_zext_T1_T1(int size) +{ + if (size == 1) + gen_op_zextb_T1_T1(); + else if (size == 2) + gen_op_zextw_T1_T1(); +} + +#if DISAS_CRIS +static char memsize_char(int size) +{ + switch (size) + { + case 1: return 'b'; break; + case 2: return 'w'; break; + case 4: return 'd'; break; + default: + return 'x'; + break; + } +} +#endif + +static unsigned int memsize_z(DisasContext *dc) +{ + return dc->zsize + 1; +} + +static unsigned int memsize_zz(DisasContext *dc) +{ + switch (dc->zzsize) + { + case 0: return 1; + case 1: return 2; + default: + return 4; + } +} + +static void do_postinc (DisasContext *dc, int size) +{ + if (!dc->postinc) + return; + gen_movl_T0_reg[dc->op1](); + gen_op_addl_T0_im(size); + gen_movl_reg_T0[dc->op1](); +} + + +static void dec_prep_move_r(DisasContext *dc, int rs, int rd, + int size, int s_ext) +{ + gen_movl_T0_reg[rs](); + gen_op_movl_T1_T0(); + if (s_ext) + gen_sext_T1_T1(size); + else + gen_zext_T1_T1(size); +} + +/* Prepare T0 and T1 for a register alu operation. + s_ext decides if the operand1 should be sign-extended or zero-extended when + needed. */ +static void dec_prep_alu_r(DisasContext *dc, int rs, int rd, + int size, int s_ext) +{ + dec_prep_move_r(dc, rs, rd, size, s_ext); + + gen_movl_T0_reg[rd](); + if (s_ext) + gen_sext_T0_T0(size); + else + gen_zext_T0_T0(size); +} + +/* Prepare T0 and T1 for a memory + alu operation. + s_ext decides if the operand1 should be sign-extended or zero-extended when + needed. */ +static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) +{ + unsigned int rs, rd; + uint32_t imm; + int is_imm; + int insn_len = 2; + + rs = dc->op1; + rd = dc->op2; + is_imm = rs == 15 && dc->postinc; + + /* Load [$rs] onto T1. */ + if (is_imm) { + insn_len = 2 + memsize; + if (memsize == 1) + insn_len++; + + imm = ldl_code(dc->pc + 2); + if (memsize != 4) { + if (s_ext) { + imm = sign_extend(imm, (memsize * 8) - 1); + } else { + if (memsize == 1) + imm &= 0xff; + else + imm &= 0xffff; + } + } + DIS(fprintf (logfile, "imm=%x rd=%d sext=%d ms=%d\n", + imm, rd, s_ext, memsize)); + gen_op_movl_T1_im (imm); + dc->postinc = 0; + } else { + gen_movl_T0_reg[rs](); + gen_load_T0_T0(dc, memsize, 0); + gen_op_movl_T1_T0(); + if (s_ext) + gen_sext_T1_T1(memsize); + else + gen_zext_T1_T1(memsize); + } + + /* put dest in T0. */ + gen_movl_T0_reg[rd](); + return insn_len; +} + +#if DISAS_CRIS +static const char *cc_name(int cc) +{ + static char *cc_names[16] = { + "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", + "ls", "hi", "ge", "lt", "gt", "le", "a", "p" + }; + assert(cc < 16); + return cc_names[cc]; +} +#endif + +static unsigned int dec_bccq(DisasContext *dc) +{ + int32_t offset; + int sign; + uint32_t cond = dc->op2; + int tmp; + + offset = EXTRACT_FIELD (dc->ir, 1, 7); + sign = EXTRACT_FIELD(dc->ir, 0, 0); + + offset *= 2; + offset |= sign << 8; + tmp = offset; + offset = sign_extend(offset, 8); + + /* op2 holds the condition-code. */ + cris_cc_mask(dc, 0); + cris_prepare_cc_branch (dc, offset, cond); + return 2; +} +static unsigned int dec_addoq(DisasContext *dc) +{ + uint32_t imm; + + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 7); + imm = sign_extend(dc->op1, 7); + + DIS(fprintf (logfile, "addoq %d, $r%u\n", imm, dc->op2)); + cris_cc_mask(dc, 0); + /* Fetch register operand, */ + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(imm); + crisv32_alu_op(dc, CC_OP_ADD, REG_ACR, 4); + return 2; +} +static unsigned int dec_addq(DisasContext *dc) +{ + DIS(fprintf (logfile, "addq %u, $r%u\n", dc->op1, dc->op2)); + + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + + cris_cc_mask(dc, CC_MASK_NZVC); + /* Fetch register operand, */ + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(dc->op1); + crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + return 2; +} +static unsigned int dec_moveq(DisasContext *dc) +{ + uint32_t imm; + + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + imm = sign_extend(dc->op1, 5); + DIS(fprintf (logfile, "moveq %d, $r%u\n", imm, dc->op2)); + + cris_cc_mask(dc, 0); + gen_op_movl_T1_im(imm); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + + return 2; +} +static unsigned int dec_subq(DisasContext *dc) +{ + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + + DIS(fprintf (logfile, "subq %u, $r%u\n", dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + /* Fetch register operand, */ + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(dc->op1); + crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + return 2; +} +static unsigned int dec_cmpq(DisasContext *dc) +{ + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + imm = sign_extend(dc->op1, 5); + + DIS(fprintf (logfile, "cmpq %d, $r%d\n", imm, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZVC); + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(imm); + crisv32_alu_op(dc, CC_OP_CMP, dc->op2, 4); + return 2; +} +static unsigned int dec_andq(DisasContext *dc) +{ + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + imm = sign_extend(dc->op1, 5); + + DIS(fprintf (logfile, "andq %d, $r%d\n", imm, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(imm); + crisv32_alu_op(dc, CC_OP_AND, dc->op2, 4); + return 2; +} +static unsigned int dec_orq(DisasContext *dc) +{ + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + imm = sign_extend(dc->op1, 5); + DIS(fprintf (logfile, "orq %d, $r%d\n", imm, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(imm); + crisv32_alu_op(dc, CC_OP_OR, dc->op2, 4); + return 2; +} +static unsigned int dec_btstq(DisasContext *dc) +{ + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + DIS(fprintf (logfile, "btstq %u, $r%d\n", dc->op1, dc->op2)); + cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(dc->op1); + crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); + + cris_update_cc_op(dc, CC_OP_FLAGS); + gen_op_movl_flags_T0(); + dc->flags_live = 1; + return 2; +} +static unsigned int dec_asrq(DisasContext *dc) +{ + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + DIS(fprintf (logfile, "asrq %u, $r%d\n", dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(dc->op1); + crisv32_alu_op(dc, CC_OP_ASR, dc->op2, 4); + return 2; +} +static unsigned int dec_lslq(DisasContext *dc) +{ + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + DIS(fprintf (logfile, "lslq %u, $r%d\n", dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(dc->op1); + crisv32_alu_op(dc, CC_OP_LSL, dc->op2, 4); + return 2; +} +static unsigned int dec_lsrq(DisasContext *dc) +{ + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + DIS(fprintf (logfile, "lsrq %u, $r%d\n", dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_im(dc->op1); + crisv32_alu_op(dc, CC_OP_LSR, dc->op2, 4); + return 2; +} + +static unsigned int dec_move_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + + DIS(fprintf (logfile, "move.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, size); + return 2; +} + +static unsigned int dec_scc_r(DisasContext *dc) +{ + int cond = dc->op2; + + DIS(fprintf (logfile, "s%s $r%u\n", + cc_name(cond), dc->op1)); + + if (cond != CC_A) + { + gen_tst_cc (dc, cond); + gen_op_movl_T1_T0(); + } + else + gen_op_movl_T1_im(1); + + cris_cc_mask(dc, 0); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, 4); + return 2; +} + +static unsigned int dec_and_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + + DIS(fprintf (logfile, "and.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_AND, dc->op2, size); + return 2; +} + +static unsigned int dec_lz_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "lz $r%u, $r%u\n", + dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); + crisv32_alu_op(dc, CC_OP_LZ, dc->op2, 4); + return 2; +} + +static unsigned int dec_lsl_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + + DIS(fprintf (logfile, "lsl.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + gen_op_andl_T1_im(63); + crisv32_alu_op(dc, CC_OP_LSL, dc->op2, size); + return 2; +} + +static unsigned int dec_lsr_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + + DIS(fprintf (logfile, "lsr.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + gen_op_andl_T1_im(63); + crisv32_alu_op(dc, CC_OP_LSR, dc->op2, size); + return 2; +} + +static unsigned int dec_asr_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + + DIS(fprintf (logfile, "asr.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1); + gen_op_andl_T1_im(63); + crisv32_alu_op(dc, CC_OP_ASR, dc->op2, size); + return 2; +} + +static unsigned int dec_muls_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + + DIS(fprintf (logfile, "muls.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZV); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1); + gen_sext_T0_T0(size); + crisv32_alu_op(dc, CC_OP_MULS, dc->op2, 4); + return 2; +} + +static unsigned int dec_mulu_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + + DIS(fprintf (logfile, "mulu.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZV); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + gen_zext_T0_T0(size); + crisv32_alu_op(dc, CC_OP_MULU, dc->op2, 4); + return 2; +} + + +static unsigned int dec_dstep_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "dstep $r%u, $r%u\n", dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op1](); + gen_op_movl_T1_T0(); + gen_movl_T0_reg[dc->op2](); + crisv32_alu_op(dc, CC_OP_DSTEP, dc->op2, 4); + return 2; +} + +static unsigned int dec_xor_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + DIS(fprintf (logfile, "xor.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + BUG_ON(size != 4); /* xor is dword. */ + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_XOR, dc->op2, 4); + return 2; +} + +static unsigned int dec_bound_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + DIS(fprintf (logfile, "bound.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + /* TODO: needs optmimization. */ + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + /* rd should be 4. */ + gen_movl_T0_reg[dc->op2](); + crisv32_alu_op(dc, CC_OP_BOUND, dc->op2, 4); + return 2; +} + +static unsigned int dec_cmp_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + DIS(fprintf (logfile, "cmp.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZVC); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_CMP, dc->op2, size); + return 2; +} + +static unsigned int dec_abs_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "abs $r%u, $r%u\n", + dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_move_r(dc, dc->op1, dc->op2, 4, 0); + gen_op_absl_T1_T1(); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + return 2; +} + +static unsigned int dec_add_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + DIS(fprintf (logfile, "add.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZVC); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_ADD, dc->op2, size); + return 2; +} + +static unsigned int dec_addc_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "addc $r%u, $r%u\n", + dc->op1, dc->op2)); + cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_NZVC); + dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); + crisv32_alu_op(dc, CC_OP_ADDC, dc->op2, 4); + return 2; +} + +static unsigned int dec_mcp_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "mcp $p%u, $r%u\n", + dc->op2, dc->op1)); + cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_RNZV); + gen_movl_T0_preg[dc->op2](); + gen_op_movl_T1_T0(); + gen_movl_T0_reg[dc->op1](); + crisv32_alu_op(dc, CC_OP_MCP, dc->op1, 4); + return 2; +} + +#if DISAS_CRIS +static char * swapmode_name(int mode, char *modename) { + int i = 0; + if (mode & 8) + modename[i++] = 'n'; + if (mode & 4) + modename[i++] = 'w'; + if (mode & 2) + modename[i++] = 'b'; + if (mode & 1) + modename[i++] = 'r'; + modename[i++] = 0; + return modename; +} +#endif + +static unsigned int dec_swap_r(DisasContext *dc) +{ + DIS(char modename[4]); + DIS(fprintf (logfile, "swap%s $r%u\n", + swapmode_name(dc->op2, modename), dc->op1)); + + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op1](); + if (dc->op2 & 8) + gen_op_not_T0_T0(); + if (dc->op2 & 4) + gen_op_swapw_T0_T0(); + if (dc->op2 & 2) + gen_op_swapb_T0_T0(); + if (dc->op2 & 1) + gen_op_swapr_T0_T0(); + gen_op_movl_T1_T0(); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, 4); + return 2; +} + +static unsigned int dec_or_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + DIS(fprintf (logfile, "or.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_OR, dc->op2, size); + return 2; +} + +static unsigned int dec_addi_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "addi.%c $r%u, $r%u\n", + memsize_char(memsize_zz(dc)), dc->op2, dc->op1)); + cris_cc_mask(dc, 0); + dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); + gen_op_lsll_T0_im(dc->zzsize); + gen_op_addl_T0_T1(); + gen_movl_reg_T0[dc->op1](); + return 2; +} + +static unsigned int dec_addi_acr(DisasContext *dc) +{ + DIS(fprintf (logfile, "addi.%c $r%u, $r%u, $acr\n", + memsize_char(memsize_zz(dc)), dc->op2, dc->op1)); + cris_cc_mask(dc, 0); + dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); + gen_op_lsll_T0_im(dc->zzsize); + gen_op_addl_T0_T1(); + gen_movl_reg_T0[REG_ACR](); + return 2; +} + +static unsigned int dec_neg_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + DIS(fprintf (logfile, "neg.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZVC); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_NEG, dc->op2, size); + return 2; +} + +static unsigned int dec_btst_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "btst $r%u, $r%u\n", + dc->op1, dc->op2)); + cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0); + crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); + + cris_update_cc_op(dc, CC_OP_FLAGS); + gen_op_movl_flags_T0(); + dc->flags_live = 1; + return 2; +} + +static unsigned int dec_sub_r(DisasContext *dc) +{ + int size = memsize_zz(dc); + DIS(fprintf (logfile, "sub.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2)); + cris_cc_mask(dc, CC_MASK_NZVC); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_SUB, dc->op2, size); + return 2; +} + +/* Zero extension. From size to dword. */ +static unsigned int dec_movu_r(DisasContext *dc) +{ + int size = memsize_z(dc); + DIS(fprintf (logfile, "movu.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + return 2; +} + +/* Sign extension. From size to dword. */ +static unsigned int dec_movs_r(DisasContext *dc) +{ + int size = memsize_z(dc); + DIS(fprintf (logfile, "movs.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + gen_movl_T0_reg[dc->op1](); + /* Size can only be qi or hi. */ + gen_sext_T1_T0(size); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + return 2; +} + +/* zero extension. From size to dword. */ +static unsigned int dec_addu_r(DisasContext *dc) +{ + int size = memsize_z(dc); + DIS(fprintf (logfile, "addu.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + gen_movl_T0_reg[dc->op1](); + /* Size can only be qi or hi. */ + gen_zext_T1_T0(size); + gen_movl_T0_reg[dc->op2](); + crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + return 2; +} +/* Sign extension. From size to dword. */ +static unsigned int dec_adds_r(DisasContext *dc) +{ + int size = memsize_z(dc); + DIS(fprintf (logfile, "adds.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + gen_movl_T0_reg[dc->op1](); + /* Size can only be qi or hi. */ + gen_sext_T1_T0(size); + gen_movl_T0_reg[dc->op2](); + crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + return 2; +} + +/* Zero extension. From size to dword. */ +static unsigned int dec_subu_r(DisasContext *dc) +{ + int size = memsize_z(dc); + DIS(fprintf (logfile, "subu.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + gen_movl_T0_reg[dc->op1](); + /* Size can only be qi or hi. */ + gen_zext_T1_T0(size); + gen_movl_T0_reg[dc->op2](); + crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + return 2; +} + +/* Sign extension. From size to dword. */ +static unsigned int dec_subs_r(DisasContext *dc) +{ + int size = memsize_z(dc); + DIS(fprintf (logfile, "subs.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + gen_movl_T0_reg[dc->op1](); + /* Size can only be qi or hi. */ + gen_sext_T1_T0(size); + gen_movl_T0_reg[dc->op2](); + crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + return 2; +} + +static unsigned int dec_setclrf(DisasContext *dc) +{ + uint32_t flags; + int set = (~dc->opcode >> 2) & 1; + + flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4) + | EXTRACT_FIELD(dc->ir, 0, 3); + DIS(fprintf (logfile, "set=%d flags=%x\n", set, flags)); + if (set && flags == 0) + DIS(fprintf (logfile, "nop\n")); + else if (!set && (flags & 0x20)) + DIS(fprintf (logfile, "di\n")); + else + DIS(fprintf (logfile, "%sf %x\n", + set ? "set" : "clr", + flags)); + + if (set && (flags & X_FLAG)) { + dc->flagx_live = 1; + dc->flags_x = 1; + } + + /* Simply decode the flags. */ + cris_evaluate_flags (dc); + cris_update_cc_op(dc, CC_OP_FLAGS); + if (set) + gen_op_setf (flags); + else + gen_op_clrf (flags); + dc->flags_live = 1; + return 2; +} + +static unsigned int dec_move_rs(DisasContext *dc) +{ + DIS(fprintf (logfile, "move $r%u, $s%u\n", dc->op1, dc->op2)); + cris_cc_mask(dc, 0); + gen_movl_T0_reg[dc->op1](); + gen_op_movl_sreg_T0(dc->op2); + + if (dc->op2 == 5) /* srs is checked at runtime. */ + gen_op_movl_tlb_lo_T0(); + return 2; +} +static unsigned int dec_move_sr(DisasContext *dc) +{ + DIS(fprintf (logfile, "move $s%u, $r%u\n", dc->op1, dc->op2)); + cris_cc_mask(dc, 0); + gen_op_movl_T0_sreg(dc->op1); + gen_op_movl_T1_T0(); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + return 2; +} +static unsigned int dec_move_rp(DisasContext *dc) +{ + DIS(fprintf (logfile, "move $r%u, $p%u\n", dc->op1, dc->op2)); + cris_cc_mask(dc, 0); + gen_movl_T0_reg[dc->op1](); + gen_op_movl_T1_T0(); + gen_movl_preg_T0[dc->op2](); + return 2; +} +static unsigned int dec_move_pr(DisasContext *dc) +{ + DIS(fprintf (logfile, "move $p%u, $r%u\n", dc->op1, dc->op2)); + cris_cc_mask(dc, 0); + gen_movl_T0_preg[dc->op2](); + gen_op_movl_T1_T0(); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op1, preg_sizes[dc->op2]); + return 2; +} + +static unsigned int dec_move_mr(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "move.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, memsize); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_movs_m(DisasContext *dc) +{ + int memsize = memsize_z(dc); + int insn_len; + DIS(fprintf (logfile, "movs.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + /* sign extend. */ + cris_cc_mask(dc, CC_MASK_NZ); + insn_len = dec_prep_alu_m(dc, 1, memsize); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_addu_m(DisasContext *dc) +{ + int memsize = memsize_z(dc); + int insn_len; + DIS(fprintf (logfile, "addu.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + /* sign extend. */ + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_adds_m(DisasContext *dc) +{ + int memsize = memsize_z(dc); + int insn_len; + DIS(fprintf (logfile, "adds.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + /* sign extend. */ + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 1, memsize); + crisv32_alu_op(dc, CC_OP_ADD, dc->op2, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_subu_m(DisasContext *dc) +{ + int memsize = memsize_z(dc); + int insn_len; + DIS(fprintf (logfile, "subu.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + /* sign extend. */ + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_subs_m(DisasContext *dc) +{ + int memsize = memsize_z(dc); + int insn_len; + DIS(fprintf (logfile, "subs.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + /* sign extend. */ + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 1, memsize); + crisv32_alu_op(dc, CC_OP_SUB, dc->op2, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_movu_m(DisasContext *dc) +{ + int memsize = memsize_z(dc); + int insn_len; + + DIS(fprintf (logfile, "movu.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_cmpu_m(DisasContext *dc) +{ + int memsize = memsize_z(dc); + int insn_len; + DIS(fprintf (logfile, "cmpu.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_CMP, dc->op2, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_cmps_m(DisasContext *dc) +{ + int memsize = memsize_z(dc); + int insn_len; + DIS(fprintf (logfile, "cmps.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 1, memsize); + crisv32_alu_op(dc, CC_OP_CMP, dc->op2, memsize_zz(dc)); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_cmp_m(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "cmp.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_CMP, dc->op2, memsize_zz(dc)); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_test_m(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "test.%d [$r%u%s] op2=%x\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + gen_op_clrf(3); + insn_len = dec_prep_alu_m(dc, 0, memsize); + gen_op_swp_T0_T1(); + gen_op_movl_T1_im(0); + crisv32_alu_op(dc, CC_OP_CMP, dc->op2, memsize_zz(dc)); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_and_m(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "and.%d [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_AND, dc->op2, memsize_zz(dc)); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_add_m(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "add.%d [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_ADD, dc->op2, memsize_zz(dc)); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_addo_m(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "add.%d [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, 0); + insn_len = dec_prep_alu_m(dc, 1, memsize); + crisv32_alu_op(dc, CC_OP_ADD, REG_ACR, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_bound_m(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "bound.%d [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, CC_MASK_NZ); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_BOUND, dc->op2, 4); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_addc_mr(DisasContext *dc) +{ + int insn_len = 2; + DIS(fprintf (logfile, "addc [$r%u%s, $r%u\n", + dc->op1, dc->postinc ? "+]" : "]", + dc->op2)); + + cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 0, 4); + crisv32_alu_op(dc, CC_OP_ADDC, dc->op2, 4); + do_postinc(dc, 4); + return insn_len; +} + +static unsigned int dec_sub_m(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "sub.%c [$r%u%s, $r%u ir=%x zz=%x\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2, dc->ir, dc->zzsize)); + + cris_cc_mask(dc, CC_MASK_NZVC); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_SUB, dc->op2, memsize); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_or_m(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len; + DIS(fprintf (logfile, "or.%d [$r%u%s, $r%u pc=%x\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2, dc->pc)); + + cris_cc_mask(dc, CC_MASK_NZ); + insn_len = dec_prep_alu_m(dc, 0, memsize); + crisv32_alu_op(dc, CC_OP_OR, dc->op2, memsize_zz(dc)); + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_move_mp(DisasContext *dc) +{ + int memsize = memsize_zz(dc); + int insn_len = 2; + + DIS(fprintf (logfile, "move.%c [$r%u%s, $p%u\n", + memsize_char(memsize), + dc->op1, + dc->postinc ? "+]" : "]", + dc->op2)); + + cris_cc_mask(dc, 0); + insn_len = dec_prep_alu_m(dc, 0, memsize); + gen_op_movl_T0_T1(); + gen_movl_preg_T0[dc->op2](); + + do_postinc(dc, memsize); + return insn_len; +} + +static unsigned int dec_move_pm(DisasContext *dc) +{ + int memsize; + + memsize = preg_sizes[dc->op2]; + + DIS(fprintf (logfile, "move.%d $p%u, [$r%u%s\n", + memsize, dc->op2, dc->op1, dc->postinc ? "+]" : "]")); + + cris_cc_mask(dc, 0); + /* prepare store. */ + gen_movl_T0_preg[dc->op2](); + gen_op_movl_T1_T0(); + gen_movl_T0_reg[dc->op1](); + gen_store_T0_T1(dc, memsize); + if (dc->postinc) + { + gen_op_addl_T0_im(memsize); + gen_movl_reg_T0[dc->op1](); + } + return 2; +} + +static unsigned int dec_movem_mr(DisasContext *dc) +{ + int i; + + DIS(fprintf (logfile, "movem [$r%u%s, $r%u\n", dc->op1, + dc->postinc ? "+]" : "]", dc->op2)); + + cris_cc_mask(dc, 0); + /* fetch the address into T1. */ + gen_movl_T0_reg[dc->op1](); + gen_op_movl_T1_T0(); + for (i = 0; i <= dc->op2; i++) { + /* Perform the load onto regnum i. Always dword wide. */ + gen_load_T0_T0(dc, 4, 0); + gen_movl_reg_T0[i](); + /* Update the address. */ + gen_op_addl_T1_im(4); + gen_op_movl_T0_T1(); + } + if (dc->postinc) { + /* writeback the updated pointer value. */ + gen_movl_reg_T0[dc->op1](); + } + return 2; +} + +static unsigned int dec_movem_rm(DisasContext *dc) +{ + int i; + + DIS(fprintf (logfile, "movem $r%u, [$r%u%s\n", dc->op2, dc->op1, + dc->postinc ? "+]" : "]")); + + cris_cc_mask(dc, 0); + for (i = 0; i <= dc->op2; i++) { + /* Fetch register i into T1. */ + gen_movl_T0_reg[i](); + gen_op_movl_T1_T0(); + + /* Fetch the address into T0. */ + gen_movl_T0_reg[dc->op1](); + /* Displace it. */ + gen_op_addl_T0_im(i * 4); + + /* Perform the store. */ + gen_store_T0_T1(dc, 4); + } + if (dc->postinc) { + /* Update the address. */ + gen_op_addl_T0_im(4); + /* writeback the updated pointer value. */ + gen_movl_reg_T0[dc->op1](); + } + return 2; +} + +static unsigned int dec_move_rm(DisasContext *dc) +{ + int memsize; + + memsize = memsize_zz(dc); + + DIS(fprintf (logfile, "move.%d $r%u, [$r%u]\n", + memsize, dc->op2, dc->op1)); + + cris_cc_mask(dc, 0); + /* prepare store. */ + gen_movl_T0_reg[dc->op2](); + gen_op_movl_T1_T0(); + gen_movl_T0_reg[dc->op1](); + gen_store_T0_T1(dc, memsize); + if (dc->postinc) + { + gen_op_addl_T0_im(memsize); + gen_movl_reg_T0[dc->op1](); + } + return 2; +} + + +static unsigned int dec_lapcq(DisasContext *dc) +{ + DIS(fprintf (logfile, "lapcq %x, $r%u\n", + dc->pc + dc->op1*2, dc->op2)); + cris_cc_mask(dc, 0); + gen_op_movl_T1_im(dc->pc + dc->op1*2); + crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, 4); + return 2; +} + +static unsigned int dec_lapc_im(DisasContext *dc) +{ + unsigned int rd; + int32_t imm; + int insn_len = 6; + + rd = dc->op2; + + cris_cc_mask(dc, 0); + imm = ldl_code(dc->pc + 2); + DIS(fprintf (logfile, "lapc 0x%x, $r%u\n", imm + dc->pc, dc->op2)); + gen_op_movl_T0_im (dc->pc + imm); + gen_movl_reg_T0[rd] (); + return insn_len; +} + +/* Jump to special reg. */ +static unsigned int dec_jump_p(DisasContext *dc) +{ + DIS(fprintf (logfile, "jump $p%u\n", dc->op2)); + cris_cc_mask(dc, 0); + /* Store the return address in Pd. */ + gen_movl_T0_preg[dc->op2](); + gen_op_movl_btarget_T0(); + cris_prepare_dyn_jmp(dc); + return 2; +} + +/* Jump and save. */ +static unsigned int dec_jas_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "jas $r%u, $p%u\n", dc->op1, dc->op2)); + cris_cc_mask(dc, 0); + /* Stor the return address in Pd. */ + gen_movl_T0_reg[dc->op1](); + gen_op_movl_btarget_T0(); + gen_op_movl_T0_im(dc->pc + 4); + gen_movl_preg_T0[dc->op2](); + cris_prepare_dyn_jmp(dc); + return 2; +} + +static unsigned int dec_jas_im(DisasContext *dc) +{ + uint32_t imm; + + imm = ldl_code(dc->pc + 2); + + DIS(fprintf (logfile, "jas 0x%x\n", imm)); + cris_cc_mask(dc, 0); + /* Stor the return address in Pd. */ + gen_op_movl_T0_im(imm); + gen_op_movl_btarget_T0(); + gen_op_movl_T0_im(dc->pc + 8); + gen_movl_preg_T0[dc->op2](); + cris_prepare_dyn_jmp(dc); + return 6; +} + +static unsigned int dec_jasc_im(DisasContext *dc) +{ + uint32_t imm; + + imm = ldl_code(dc->pc + 2); + + DIS(fprintf (logfile, "jasc 0x%x\n", imm)); + cris_cc_mask(dc, 0); + /* Stor the return address in Pd. */ + gen_op_movl_T0_im(imm); + gen_op_movl_btarget_T0(); + gen_op_movl_T0_im(dc->pc + 8 + 4); + gen_movl_preg_T0[dc->op2](); + cris_prepare_dyn_jmp(dc); + return 6; +} + +static unsigned int dec_jasc_r(DisasContext *dc) +{ + DIS(fprintf (logfile, "jasc_r $r%u, $p%u\n", dc->op1, dc->op2)); + cris_cc_mask(dc, 0); + /* Stor the return address in Pd. */ + gen_movl_T0_reg[dc->op1](); + gen_op_movl_btarget_T0(); + gen_op_movl_T0_im(dc->pc + 4 + 4); + gen_movl_preg_T0[dc->op2](); + cris_prepare_dyn_jmp(dc); + return 2; +} + +static unsigned int dec_bcc_im(DisasContext *dc) +{ + int32_t offset; + uint32_t cond = dc->op2; + + offset = ldl_code(dc->pc + 2); + offset = sign_extend(offset, 15); + + DIS(fprintf (logfile, "b%s %d pc=%x dst=%x\n", + cc_name(cond), offset, + dc->pc, dc->pc + offset)); + + cris_cc_mask(dc, 0); + /* op2 holds the condition-code. */ + cris_prepare_cc_branch (dc, offset, cond); + return 4; +} + +static unsigned int dec_bas_im(DisasContext *dc) +{ + int32_t simm; + + + simm = ldl_code(dc->pc + 2); + + DIS(fprintf (logfile, "bas 0x%x, $p%u\n", dc->pc + simm, dc->op2)); + cris_cc_mask(dc, 0); + /* Stor the return address in Pd. */ + gen_op_movl_T0_im(dc->pc + simm); + gen_op_movl_btarget_T0(); + gen_op_movl_T0_im(dc->pc + 8); + gen_movl_preg_T0[dc->op2](); + cris_prepare_dyn_jmp(dc); + return 6; +} + +static unsigned int dec_basc_im(DisasContext *dc) +{ + int32_t simm; + simm = ldl_code(dc->pc + 2); + + DIS(fprintf (logfile, "basc 0x%x, $p%u\n", dc->pc + simm, dc->op2)); + cris_cc_mask(dc, 0); + /* Stor the return address in Pd. */ + gen_op_movl_T0_im(dc->pc + simm); + gen_op_movl_btarget_T0(); + gen_op_movl_T0_im(dc->pc + 12); + gen_movl_preg_T0[dc->op2](); + cris_prepare_dyn_jmp(dc); + return 6; +} + +static unsigned int dec_rfe_etc(DisasContext *dc) +{ + DIS(fprintf (logfile, "rfe_etc opc=%x pc=0x%x op1=%d op2=%d\n", + dc->opcode, dc->pc, dc->op1, dc->op2)); + + cris_cc_mask(dc, 0); + + if (dc->op2 == 15) /* ignore halt. */ + goto done; + + switch (dc->op2 & 7) { + case 2: + /* rfe. */ + cris_evaluate_flags(dc); + gen_op_ccs_rshift(); + break; + case 5: + /* rfn. */ + BUG(); + break; + case 6: + /* break. */ + gen_op_movl_T0_im(dc->pc); + gen_op_movl_pc_T0(); + /* Breaks start at 16 in the exception vector. */ + gen_op_break_im(dc->op1 + 16); + break; + default: + printf ("op2=%x\n", dc->op2); + BUG(); + break; + + } + done: + return 2; +} + +static unsigned int dec_null(DisasContext *dc) +{ + printf ("unknown insn pc=%x opc=%x op1=%x op2=%x\n", + dc->pc, dc->opcode, dc->op1, dc->op2); + fflush(NULL); + BUG(); + return 2; +} + +struct decoder_info { + struct { + uint32_t bits; + uint32_t mask; + }; + unsigned int (*dec)(DisasContext *dc); +} decinfo[] = { + /* Order matters here. */ + {DEC_MOVEQ, dec_moveq}, + {DEC_BTSTQ, dec_btstq}, + {DEC_CMPQ, dec_cmpq}, + {DEC_ADDOQ, dec_addoq}, + {DEC_ADDQ, dec_addq}, + {DEC_SUBQ, dec_subq}, + {DEC_ANDQ, dec_andq}, + {DEC_ORQ, dec_orq}, + {DEC_ASRQ, dec_asrq}, + {DEC_LSLQ, dec_lslq}, + {DEC_LSRQ, dec_lsrq}, + {DEC_BCCQ, dec_bccq}, + + {DEC_BCC_IM, dec_bcc_im}, + {DEC_JAS_IM, dec_jas_im}, + {DEC_JAS_R, dec_jas_r}, + {DEC_JASC_IM, dec_jasc_im}, + {DEC_JASC_R, dec_jasc_r}, + {DEC_BAS_IM, dec_bas_im}, + {DEC_BASC_IM, dec_basc_im}, + {DEC_JUMP_P, dec_jump_p}, + {DEC_LAPC_IM, dec_lapc_im}, + {DEC_LAPCQ, dec_lapcq}, + + {DEC_RFE_ETC, dec_rfe_etc}, + {DEC_ADDC_MR, dec_addc_mr}, + + {DEC_MOVE_MP, dec_move_mp}, + {DEC_MOVE_PM, dec_move_pm}, + {DEC_MOVEM_MR, dec_movem_mr}, + {DEC_MOVEM_RM, dec_movem_rm}, + {DEC_MOVE_PR, dec_move_pr}, + {DEC_SCC_R, dec_scc_r}, + {DEC_SETF, dec_setclrf}, + {DEC_CLEARF, dec_setclrf}, + + {DEC_MOVE_SR, dec_move_sr}, + {DEC_MOVE_RP, dec_move_rp}, + {DEC_SWAP_R, dec_swap_r}, + {DEC_ABS_R, dec_abs_r}, + {DEC_LZ_R, dec_lz_r}, + {DEC_MOVE_RS, dec_move_rs}, + {DEC_BTST_R, dec_btst_r}, + {DEC_ADDC_R, dec_addc_r}, + + {DEC_DSTEP_R, dec_dstep_r}, + {DEC_XOR_R, dec_xor_r}, + {DEC_MCP_R, dec_mcp_r}, + {DEC_CMP_R, dec_cmp_r}, + + {DEC_ADDI_R, dec_addi_r}, + {DEC_ADDI_ACR, dec_addi_acr}, + + {DEC_ADD_R, dec_add_r}, + {DEC_SUB_R, dec_sub_r}, + + {DEC_ADDU_R, dec_addu_r}, + {DEC_ADDS_R, dec_adds_r}, + {DEC_SUBU_R, dec_subu_r}, + {DEC_SUBS_R, dec_subs_r}, + {DEC_LSL_R, dec_lsl_r}, + + {DEC_AND_R, dec_and_r}, + {DEC_OR_R, dec_or_r}, + {DEC_BOUND_R, dec_bound_r}, + {DEC_ASR_R, dec_asr_r}, + {DEC_LSR_R, dec_lsr_r}, + + {DEC_MOVU_R, dec_movu_r}, + {DEC_MOVS_R, dec_movs_r}, + {DEC_NEG_R, dec_neg_r}, + {DEC_MOVE_R, dec_move_r}, + + /* ftag_fidx_i_m. */ + /* ftag_fidx_d_m. */ + + {DEC_MULS_R, dec_muls_r}, + {DEC_MULU_R, dec_mulu_r}, + + {DEC_ADDU_M, dec_addu_m}, + {DEC_ADDS_M, dec_adds_m}, + {DEC_SUBU_M, dec_subu_m}, + {DEC_SUBS_M, dec_subs_m}, + + {DEC_CMPU_M, dec_cmpu_m}, + {DEC_CMPS_M, dec_cmps_m}, + {DEC_MOVU_M, dec_movu_m}, + {DEC_MOVS_M, dec_movs_m}, + + {DEC_CMP_M, dec_cmp_m}, + {DEC_ADDO_M, dec_addo_m}, + {DEC_BOUND_M, dec_bound_m}, + {DEC_ADD_M, dec_add_m}, + {DEC_SUB_M, dec_sub_m}, + {DEC_AND_M, dec_and_m}, + {DEC_OR_M, dec_or_m}, + {DEC_MOVE_RM, dec_move_rm}, + {DEC_TEST_M, dec_test_m}, + {DEC_MOVE_MR, dec_move_mr}, + + {{0, 0}, dec_null} +}; + +static inline unsigned int +cris_decoder(DisasContext *dc) +{ + unsigned int insn_len = 2; + uint32_t tmp; + int i; + + /* Load a halfword onto the instruction register. */ + tmp = ldl_code(dc->pc); + dc->ir = tmp & 0xffff; + + /* Now decode it. */ + dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 3); + dc->op2 = EXTRACT_FIELD(dc->ir, 12, 15); + dc->zsize = EXTRACT_FIELD(dc->ir, 4, 4); + dc->zzsize = EXTRACT_FIELD(dc->ir, 4, 5); + dc->postinc = EXTRACT_FIELD(dc->ir, 10, 10); + + /* Large switch for all insns. */ + for (i = 0; i < sizeof decinfo / sizeof decinfo[0]; i++) { + if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) + { + insn_len = decinfo[i].dec(dc); + break; + } + } + + return insn_len; +} + +static void check_breakpoint(CPUState *env, DisasContext *dc) +{ + int j; + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == dc->pc) { + cris_evaluate_flags (dc); + gen_op_movl_T0_im((long)dc->pc); + gen_op_movl_pc_T0(); + gen_op_debug(); + dc->is_jmp = DISAS_UPDATE; + } + } + } +} + + +/* generate intermediate code for basic block 'tb'. */ +struct DisasContext ctx; +static int +gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, + int search_pc) +{ + uint16_t *gen_opc_end; + uint32_t pc_start; + unsigned int insn_len; + int j, lj; + struct DisasContext *dc = &ctx; + uint32_t next_page_start; + + pc_start = tb->pc; + dc->env = env; + dc->tb = tb; + + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + + dc->is_jmp = DISAS_NEXT; + dc->pc = pc_start; + dc->singlestep_enabled = env->singlestep_enabled; + dc->flagx_live = 0; + dc->flags_x = 0; + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + lj = -1; + do + { + check_breakpoint(env, dc); + if (dc->is_jmp == DISAS_JUMP) + goto done; + + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = dc->pc; + gen_opc_instr_start[lj] = 1; + } + + insn_len = cris_decoder(dc); + STATS(gen_op_exec_insn()); + dc->pc += insn_len; + if (!dc->flagx_live + || (dc->flagx_live && + !(dc->cc_op == CC_OP_FLAGS && dc->flags_x))) { + gen_movl_T0_preg[SR_CCS](); + gen_op_andl_T0_im(~X_FLAG); + gen_movl_preg_T0[SR_CCS](); + dc->flagx_live = 1; + dc->flags_x = 0; + } + + /* Check for delayed branches here. If we do it before + actually genereating any host code, the simulator will just + loop doing nothing for on this program location. */ + if (dc->delayed_branch) { + dc->delayed_branch--; + if (dc->delayed_branch == 0) + { + if (dc->bcc == CC_A) { + gen_op_jmp (); + dc->is_jmp = DISAS_UPDATE; + } + else { + /* Conditional jmp. */ + gen_op_cc_jmp (dc->delayed_pc, dc->pc); + dc->is_jmp = DISAS_UPDATE; + } + } + } + + if (env->singlestep_enabled) + break; + } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end + && dc->pc < next_page_start); + + if (!dc->is_jmp) { + gen_op_movl_T0_im((long)dc->pc); + gen_op_movl_pc_T0(); + } + + cris_evaluate_flags (dc); + done: + if (__builtin_expect(env->singlestep_enabled, 0)) { + gen_op_debug(); + } else { + switch(dc->is_jmp) { + case DISAS_NEXT: + gen_goto_tb(dc, 1, dc->pc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + /* indicate that the hash table must be used + to find the next TB */ + /* T0 is used to index the jmp tables. */ + gen_op_movl_T0_0(); + gen_op_exit_tb(); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + } + } + *gen_opc_ptr = INDEX_op_end; + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } else { + tb->size = dc->pc - pc_start; + } + +#ifdef DEBUG_DISAS + if (loglevel & CPU_LOG_TB_IN_ASM) { + fprintf(logfile, "--------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + target_disas(logfile, pc_start, dc->pc + 4 - pc_start, 0); + fprintf(logfile, "\n"); + if (loglevel & CPU_LOG_TB_OP) { + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } + } +#endif + return 0; +} + +int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 1); +} + +void cpu_dump_state (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; + uint32_t srs; + + if (!env || !f) + return; + + cpu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n" + "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n" + "debug=%x %x %x\n", + env->pc, env->pregs[SR_CCS], env->btaken, env->btarget, + env->cc_op, + env->cc_src, env->cc_dest, env->cc_result, env->cc_mask, + env->debug1, env->debug2, env->debug3); + + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); + if ((i + 1) % 4 == 0) + cpu_fprintf(f, "\n"); + } + cpu_fprintf(f, "\nspecial regs:\n"); + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "p%2.2d=%8.8x ", i, env->pregs[i]); + if ((i + 1) % 4 == 0) + cpu_fprintf(f, "\n"); + } + srs = env->pregs[SR_SRS]; + cpu_fprintf(f, "\nsupport function regs bank %d:\n", srs); + if (srs < 256) { + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "s%2.2d=%8.8x ", + i, env->sregs[srs][i]); + if ((i + 1) % 4 == 0) + cpu_fprintf(f, "\n"); + } + } + cpu_fprintf(f, "\n\n"); + +} + +CPUCRISState *cpu_cris_init (void) +{ + CPUCRISState *env; + + env = qemu_mallocz(sizeof(CPUCRISState)); + if (!env) + return NULL; + cpu_exec_init(env); + cpu_reset(env); + return env; +} + +void cpu_reset (CPUCRISState *env) +{ + memset(env, 0, offsetof(CPUCRISState, breakpoints)); + tlb_flush(env, 1); +} -- cgit v1.2.3 From 5478670f3de77193cecf53c7df3a31b488a99cf4 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 12:50:59 +0000 Subject: CRIS insn decoding macros, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3359 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-cris/crisv32-decode.h | 126 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 target-cris/crisv32-decode.h diff --git a/target-cris/crisv32-decode.h b/target-cris/crisv32-decode.h new file mode 100644 index 000000000..5d30dcc4b --- /dev/null +++ b/target-cris/crisv32-decode.h @@ -0,0 +1,126 @@ +/* + * CRIS insn decoding macros. + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias. + * + * 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 + */ + +/* Convenient binary macros. */ +#define HEX__(n) 0x##n##LU +#define B8__(x) ((x&0x0000000FLU)?1:0) \ + + ((x&0x000000F0LU)?2:0) \ + + ((x&0x00000F00LU)?4:0) \ + + ((x&0x0000F000LU)?8:0) \ + + ((x&0x000F0000LU)?16:0) \ + + ((x&0x00F00000LU)?32:0) \ + + ((x&0x0F000000LU)?64:0) \ + + ((x&0xF0000000LU)?128:0) +#define B8(d) ((unsigned char)B8__(HEX__(d))) + +/* Quick imm. */ +#define DEC_BCCQ {B8(00000000), B8(11110000)} +#define DEC_ADDOQ {B8(00010000), B8(11110000)} +#define DEC_ADDQ {B8(00100000), B8(11111100)} +#define DEC_MOVEQ {B8(00100100), B8(11111100)} +#define DEC_SUBQ {B8(00101000), B8(11111100)} +#define DEC_CMPQ {B8(00101100), B8(11111100)} +#define DEC_ANDQ {B8(00110000), B8(11111100)} +#define DEC_ORQ {B8(00110100), B8(11111100)} +#define DEC_BTSTQ {B8(00111000), B8(11111110)} +#define DEC_ASRQ {B8(00111010), B8(11111110)} +#define DEC_LSLQ {B8(00111100), B8(11111110)} +#define DEC_LSRQ {B8(00111110), B8(11111110)} + +/* Register. */ +#define DEC_MOVU_R {B8(01000100), B8(11111110)} +#define DEC_MOVU_R {B8(01000100), B8(11111110)} +#define DEC_MOVS_R {B8(01000110), B8(11111110)} +#define DEC_MOVE_R {B8(01100100), B8(11111100)} +#define DEC_MOVE_RP {B8(01100011), B8(11111111)} +#define DEC_MOVE_PR {B8(01100111), B8(11111111)} +#define DEC_DSTEP_R {B8(01101111), B8(11111111)} +#define DEC_MOVE_RS {B8(10110111), B8(11111111)} +#define DEC_MOVE_SR {B8(11110111), B8(11111111)} +#define DEC_ADDU_R {B8(01000000), B8(11111110)} +#define DEC_ADDS_R {B8(01000010), B8(11111110)} +#define DEC_ADD_R {B8(01100000), B8(11111100)} +#define DEC_ADDI_R {B8(01010000), B8(11111100)} +#define DEC_MULS_R {B8(11010000), B8(11111100)} +#define DEC_MULU_R {B8(10010000), B8(11111100)} +#define DEC_ADDI_ACR {B8(01010100), B8(11111100)} +#define DEC_NEG_R {B8(01011000), B8(11111100)} +#define DEC_BOUND_R {B8(01011100), B8(11111100)} +#define DEC_SUBU_R {B8(01001000), B8(11111110)} +#define DEC_SUBS_R {B8(01001010), B8(11111110)} +#define DEC_SUB_R {B8(01101000), B8(11111100)} +#define DEC_CMP_R {B8(01101100), B8(11111100)} +#define DEC_AND_R {B8(01110000), B8(11111100)} +#define DEC_ABS_R {B8(01101011), B8(11111111)} +#define DEC_LZ_R {B8(01110011), B8(11111111)} +#define DEC_MCP_R {B8(01111111), B8(11111111)} +#define DEC_SWAP_R {B8(01110111), B8(11111111)} +#define DEC_XOR_R {B8(01111011), B8(11111111)} +#define DEC_LSL_R {B8(01001100), B8(11111100)} +#define DEC_LSR_R {B8(01111100), B8(11111100)} +#define DEC_ASR_R {B8(01111000), B8(11111100)} +#define DEC_OR_R {B8(01110100), B8(11111100)} +#define DEC_BTST_R {B8(01001111), B8(11111111)} + +/* Fixed. */ +#define DEC_SETF {B8(01011011), B8(11111111)} +#define DEC_CLEARF {B8(01011111), B8(11111111)} + +/* Memory. */ +#define DEC_ADDU_M {B8(10000000), B8(10111110)} +#define DEC_ADDS_M {B8(10000010), B8(10111110)} +#define DEC_MOVU_M {B8(10000100), B8(10111110)} +#define DEC_MOVS_M {B8(10000110), B8(10111110)} +#define DEC_SUBU_M {B8(10001000), B8(10111110)} +#define DEC_SUBS_M {B8(10001010), B8(10111110)} +#define DEC_CMPU_M {B8(10001100), B8(10111110)} +#define DEC_CMPS_M {B8(10001110), B8(10111110)} +#define DEC_ADDO_M {B8(10010100), B8(10111100)} +#define DEC_BOUND_M {B8(10011100), B8(10111100)} +#define DEC_ADD_M {B8(10100000), B8(10111100)} +#define DEC_MOVE_MR {B8(10100100), B8(10111100)} +#define DEC_SUB_M {B8(10101000), B8(10111100)} +#define DEC_CMP_M {B8(10101100), B8(10111100)} +#define DEC_AND_M {B8(10110000), B8(10111100)} +#define DEC_OR_M {B8(10110100), B8(10111100)} +#define DEC_TEST_M {B8(10111000), B8(10111100)} +#define DEC_MOVE_RM {B8(10111100), B8(10111100)} + +#define DEC_ADDC_R {B8(01010111), B8(11111111)} +#define DEC_ADDC_MR {B8(10011010), B8(10111111)} +#define DEC_LAPCQ {B8(10010111), B8(11111111)} +#define DEC_LAPC_IM {B8(11010111), B8(11111111)} + +#define DEC_MOVE_MP {B8(10100011), B8(10111111)} +#define DEC_MOVE_PM {B8(10100111), B8(10111111)} + +#define DEC_SCC_R {B8(01010011), B8(11111111)} +#define DEC_RFE_ETC {B8(10010011), B8(11111111)} +#define DEC_JUMP_P {B8(10011111), B8(11111111)} +#define DEC_BCC_IM {B8(11011111), B8(11111111)} +#define DEC_JAS_R {B8(10011011), B8(11111111)} +#define DEC_JASC_R {B8(10110011), B8(11111111)} +#define DEC_JAS_IM {B8(11011011), B8(11111111)} +#define DEC_JASC_IM {B8(11110011), B8(11111111)} +#define DEC_BAS_IM {B8(11101011), B8(11111111)} +#define DEC_BASC_IM {B8(11101111), B8(11111111)} +#define DEC_MOVEM_MR {B8(10111011), B8(10111111)} +#define DEC_MOVEM_RM {B8(10111111), B8(10111111)} -- cgit v1.2.3 From 4fa551d76893dfdd976d2745a42c17ca1cedaa55 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 12:52:43 +0000 Subject: CRIS micro-ops, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3360 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-cris/op.c | 1289 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1289 insertions(+) create mode 100644 target-cris/op.c diff --git a/target-cris/op.c b/target-cris/op.c new file mode 100644 index 000000000..3ce9888bc --- /dev/null +++ b/target-cris/op.c @@ -0,0 +1,1289 @@ +/* + * CRIS emulation micro-operations for qemu. + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "exec.h" + +#define REGNAME r0 +#define REG (env->regs[0]) +#include "op_template.h" + +#define REGNAME r1 +#define REG (env->regs[1]) +#include "op_template.h" + +#define REGNAME r2 +#define REG (env->regs[2]) +#include "op_template.h" + +#define REGNAME r3 +#define REG (env->regs[3]) +#include "op_template.h" + +#define REGNAME r4 +#define REG (env->regs[4]) +#include "op_template.h" + +#define REGNAME r5 +#define REG (env->regs[5]) +#include "op_template.h" + +#define REGNAME r6 +#define REG (env->regs[6]) +#include "op_template.h" + +#define REGNAME r7 +#define REG (env->regs[7]) +#include "op_template.h" + +#define REGNAME r8 +#define REG (env->regs[8]) +#include "op_template.h" + +#define REGNAME r9 +#define REG (env->regs[9]) +#include "op_template.h" + +#define REGNAME r10 +#define REG (env->regs[10]) +#include "op_template.h" + +#define REGNAME r11 +#define REG (env->regs[11]) +#include "op_template.h" + +#define REGNAME r12 +#define REG (env->regs[12]) +#include "op_template.h" + +#define REGNAME r13 +#define REG (env->regs[13]) +#include "op_template.h" + +#define REGNAME r14 +#define REG (env->regs[14]) +#include "op_template.h" + +#define REGNAME r15 +#define REG (env->regs[15]) +#include "op_template.h" + + +#define REGNAME p0 +#define REG (env->pregs[0]) +#include "op_template.h" + +#define REGNAME p1 +#define REG (env->pregs[1]) +#include "op_template.h" + +#define REGNAME p2 +#define REG (env->pregs[2]) +#include "op_template.h" + +#define REGNAME p3 +#define REG (env->pregs[3]) +#include "op_template.h" + +#define REGNAME p4 +#define REG (env->pregs[4]) +#include "op_template.h" + +#define REGNAME p5 +#define REG (env->pregs[5]) +#include "op_template.h" + +#define REGNAME p6 +#define REG (env->pregs[6]) +#include "op_template.h" + +#define REGNAME p7 +#define REG (env->pregs[7]) +#include "op_template.h" + +#define REGNAME p8 +#define REG (env->pregs[8]) +#include "op_template.h" + +#define REGNAME p9 +#define REG (env->pregs[9]) +#include "op_template.h" + +#define REGNAME p10 +#define REG (env->pregs[10]) +#include "op_template.h" + +#define REGNAME p11 +#define REG (env->pregs[11]) +#include "op_template.h" + +#define REGNAME p12 +#define REG (env->pregs[12]) +#include "op_template.h" + +#define REGNAME p13 +#define REG (env->pregs[13]) +#include "op_template.h" + +#define REGNAME p14 +#define REG (env->pregs[14]) +#include "op_template.h" + +#define REGNAME p15 +#define REG (env->pregs[15]) +#include "op_template.h" + +/* Microcode. */ + +void OPPROTO op_exit_tb (void) +{ + EXIT_TB(); +} + +void OPPROTO op_goto_tb0 (void) +{ + GOTO_TB(op_goto_tb0, PARAM1, 0); + RETURN(); +} + +void OPPROTO op_goto_tb1 (void) +{ + GOTO_TB(op_goto_tb1, PARAM1, 1); + RETURN(); +} + +void OPPROTO op_break_im(void) +{ + env->trapnr = PARAM1; + env->exception_index = EXCP_BREAK; + cpu_loop_exit(); +} + +void OPPROTO op_debug(void) +{ + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(); +} + +void OPPROTO op_exec_insn(void) +{ + env->stats.exec_insns++; + RETURN(); +} +void OPPROTO op_exec_load(void) +{ + env->stats.exec_loads++; + RETURN(); +} +void OPPROTO op_exec_store(void) +{ + env->stats.exec_stores++; + RETURN(); +} + +void OPPROTO op_ccs_lshift (void) +{ + uint32_t ccs; + + /* Apply the ccs shift. */ + ccs = env->pregs[SR_CCS]; + ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2); + env->pregs[SR_CCS] = ccs; +} +void OPPROTO op_ccs_rshift (void) +{ + uint32_t ccs; + + /* Apply the ccs shift. */ + ccs = env->pregs[SR_CCS]; + ccs = (ccs & 0xc0000000) | (ccs >> 10); + env->pregs[SR_CCS] = ccs; +} + +void OPPROTO op_setf (void) +{ + env->pregs[SR_CCS] |= PARAM1; + RETURN(); +} + +void OPPROTO op_clrf (void) +{ + env->pregs[SR_CCS] &= ~PARAM1; + RETURN(); +} + +void OPPROTO op_movl_debug1_T0 (void) +{ + env->debug1 = T0; + RETURN(); +} + +void OPPROTO op_movl_debug2_T0 (void) +{ + env->debug2 = T0; + RETURN(); +} + +void OPPROTO op_movl_debug3_T0 (void) +{ + env->debug3 = T0; + RETURN(); +} +void OPPROTO op_movl_debug1_T1 (void) +{ + env->debug1 = T1; + RETURN(); +} + +void OPPROTO op_movl_debug2_T1 (void) +{ + env->debug2 = T1; + RETURN(); +} + +void OPPROTO op_movl_debug3_T1 (void) +{ + env->debug3 = T1; + RETURN(); +} +void OPPROTO op_movl_debug3_im (void) +{ + env->debug3 = PARAM1; + RETURN(); +} +void OPPROTO op_movl_T0_flags (void) +{ + T0 = env->pregs[SR_CCS]; + RETURN(); +} +void OPPROTO op_movl_flags_T0 (void) +{ + env->pregs[SR_CCS] = T0; + RETURN(); +} + +void OPPROTO op_movl_sreg_T0 (void) +{ + env->sregs[env->pregs[SR_SRS]][PARAM1] = T0; + RETURN(); +} + +void OPPROTO op_movl_tlb_lo_T0 (void) +{ + int srs; + srs = env->pregs[SR_SRS]; + if (srs == 1 || srs == 2) + { + int set; + int idx; + uint32_t lo, hi; + + idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; + set >>= 4; + set &= 3; + + idx &= 31; + /* We've just made a write to tlb_lo. */ + lo = env->sregs[SFR_RW_MM_TLB_LO]; + hi = env->sregs[SFR_RW_MM_TLB_HI]; + env->tlbsets[srs - 1][set][idx].lo = lo; + env->tlbsets[srs - 1][set][idx].hi = hi; + } + + RETURN(); +} + +void OPPROTO op_movl_T0_sreg (void) +{ + T0 = env->sregs[env->pregs[SR_SRS]][PARAM1]; + RETURN(); +} + +void OPPROTO op_update_cc (void) +{ + env->cc_op = PARAM1; + env->cc_dest = PARAM2; + env->cc_src = PARAM3; + RETURN(); +} + +void OPPROTO op_update_cc_op (void) +{ + env->cc_op = PARAM1; + RETURN(); +} + +void OPPROTO op_update_cc_mask (void) +{ + env->cc_mask = PARAM1; + RETURN(); +} + +void OPPROTO op_update_cc_dest_T0 (void) +{ + env->cc_dest = T0; + RETURN(); +} + +void OPPROTO op_update_cc_result_T0 (void) +{ + env->cc_result = T0; + RETURN(); +} + +void OPPROTO op_update_cc_size_im (void) +{ + env->cc_size = PARAM1; + RETURN(); +} + +void OPPROTO op_update_cc_src_T1 (void) +{ + env->cc_src = T1; + RETURN(); +} +void OPPROTO op_update_cc_x (void) +{ + env->cc_x_live = PARAM1; + env->cc_x = PARAM2; + RETURN(); +} + +/* FIXME: is this allowed? */ +extern inline void evaluate_flags_writeback(uint32_t flags) +{ + int x; + + /* Extended arithmetics, leave the z flag alone. */ + env->debug3 = env->pregs[SR_CCS]; + + if (env->cc_x_live) + x = env->cc_x; + else + x = env->pregs[SR_CCS] & X_FLAG; + + if ((x || env->cc_op == CC_OP_ADDC) + && flags & Z_FLAG) + env->cc_mask &= ~Z_FLAG; + + /* all insn clear the x-flag except setf or clrf. */ + env->pregs[SR_CCS] &= ~(env->cc_mask | X_FLAG); + flags &= env->cc_mask; + env->pregs[SR_CCS] |= flags; + RETURN(); +} + +void OPPROTO op_evaluate_flags_muls(void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + /* were gonna have to redo the muls. */ + int64_t tmp, t0 ,t1; + int32_t mof; + int dneg; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + + /* cast into signed values to make GCC sign extend. */ + t0 = (int32_t)src; + t1 = (int32_t)dst; + dneg = ((int32_t)res) < 0; + + tmp = t0 * t1; + mof = tmp >> 32; + if (tmp == 0) + flags |= Z_FLAG; + else if (tmp < 0) + flags |= N_FLAG; + if ((dneg && mof != -1) + || (!dneg && mof != 0)) + flags |= V_FLAG; + evaluate_flags_writeback(flags); + RETURN(); +} + +void OPPROTO op_evaluate_flags_mulu(void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + /* were gonna have to redo the muls. */ + uint64_t tmp, t0 ,t1; + uint32_t mof; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + + /* cast into signed values to make GCC sign extend. */ + t0 = src; + t1 = dst; + + tmp = t0 * t1; + mof = tmp >> 32; + if (tmp == 0) + flags |= Z_FLAG; + else if (tmp >> 63) + flags |= N_FLAG; + if (mof) + flags |= V_FLAG; + + evaluate_flags_writeback(flags); + RETURN(); +} + +void OPPROTO op_evaluate_flags_mcp(void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + if ((res & 0x80000000L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x80000000L) == 0L) + && ((dst & 0x80000000L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x80000000L) != 0L) && + ((dst & 0x80000000L) != 0L)) + { + flags |= R_FLAG; + } + } + else + { + if (res == 0L) + flags |= Z_FLAG; + if (((src & 0x80000000L) != 0L) + && ((dst & 0x80000000L) != 0L)) + flags |= V_FLAG; + if ((dst & 0x80000000L) != 0L + || (src & 0x80000000L) != 0L) + flags |= R_FLAG; + } + + evaluate_flags_writeback(flags); + RETURN(); +} + +void OPPROTO op_evaluate_flags_alu_4(void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + if ((res & 0x80000000L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x80000000L) == 0L) + && ((dst & 0x80000000L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x80000000L) != 0L) && + ((dst & 0x80000000L) != 0L)) + { + flags |= C_FLAG; + } + } + else + { + if (res == 0L) + flags |= Z_FLAG; + if (((src & 0x80000000L) != 0L) + && ((dst & 0x80000000L) != 0L)) + flags |= V_FLAG; + if ((dst & 0x80000000L) != 0L + || (src & 0x80000000L) != 0L) + flags |= C_FLAG; + } + + if (env->cc_op == CC_OP_SUB + || env->cc_op == CC_OP_CMP) { + flags ^= C_FLAG; + } + evaluate_flags_writeback(flags); + RETURN(); +} + +void OPPROTO op_evaluate_flags_move_4 (void) +{ + uint32_t src; + uint32_t res; + uint32_t flags = 0; + + src = env->cc_src; + res = env->cc_result; + + if ((int32_t)res < 0) + flags |= N_FLAG; + else if (res == 0L) + flags |= Z_FLAG; + + evaluate_flags_writeback(flags); + RETURN(); +} +void OPPROTO op_evaluate_flags_move_2 (void) +{ + uint32_t src; + uint32_t flags = 0; + uint16_t res; + + src = env->cc_src; + res = env->cc_result; + + if ((int16_t)res < 0L) + flags |= N_FLAG; + else if (res == 0) + flags |= Z_FLAG; + + evaluate_flags_writeback(flags); + RETURN(); +} + +/* TODO: This is expensive. We could split things up and only evaluate part of + CCR on a need to know basis. For now, we simply re-evaluate everything. */ +void OPPROTO op_evaluate_flags (void) +{ + uint32_t src; + uint32_t dst; + uint32_t res; + uint32_t flags = 0; + + src = env->cc_src; + dst = env->cc_dest; + res = env->cc_result; + + + /* Now, evaluate the flags. This stuff is based on + Per Zander's CRISv10 simulator. */ + switch (env->cc_size) + { + case 1: + if ((res & 0x80L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x80L) == 0L) + && ((dst & 0x80L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x80L) != 0L) + && ((dst & 0x80L) != 0L)) + { + flags |= C_FLAG; + } + } + else + { + if ((res & 0xFFL) == 0L) + { + flags |= Z_FLAG; + } + if (((src & 0x80L) != 0L) + && ((dst & 0x80L) != 0L)) + { + flags |= V_FLAG; + } + if ((dst & 0x80L) != 0L + || (src & 0x80L) != 0L) + { + flags |= C_FLAG; + } + } + break; + case 2: + if ((res & 0x8000L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x8000L) == 0L) + && ((dst & 0x8000L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x8000L) != 0L) + && ((dst & 0x8000L) != 0L)) + { + flags |= C_FLAG; + } + } + else + { + if ((res & 0xFFFFL) == 0L) + { + flags |= Z_FLAG; + } + if (((src & 0x8000L) != 0L) + && ((dst & 0x8000L) != 0L)) + { + flags |= V_FLAG; + } + if ((dst & 0x8000L) != 0L + || (src & 0x8000L) != 0L) + { + flags |= C_FLAG; + } + } + break; + case 4: + if ((res & 0x80000000L) != 0L) + { + flags |= N_FLAG; + if (((src & 0x80000000L) == 0L) + && ((dst & 0x80000000L) == 0L)) + { + flags |= V_FLAG; + } + else if (((src & 0x80000000L) != 0L) && + ((dst & 0x80000000L) != 0L)) + { + flags |= C_FLAG; + } + } + else + { + if (res == 0L) + flags |= Z_FLAG; + if (((src & 0x80000000L) != 0L) + && ((dst & 0x80000000L) != 0L)) + flags |= V_FLAG; + if ((dst & 0x80000000L) != 0L + || (src & 0x80000000L) != 0L) + flags |= C_FLAG; + } + break; + default: + break; + } + + if (env->cc_op == CC_OP_SUB + || env->cc_op == CC_OP_CMP) { + flags ^= C_FLAG; + } + evaluate_flags_writeback(flags); + RETURN(); +} + +void OPPROTO op_extb_T0_T0 (void) +{ + T0 = ((int8_t)T0); + RETURN(); +} +void OPPROTO op_extb_T1_T0 (void) +{ + T1 = ((int8_t)T0); + RETURN(); +} +void OPPROTO op_extb_T1_T1 (void) +{ + T1 = ((int8_t)T1); + RETURN(); +} +void OPPROTO op_zextb_T0_T0 (void) +{ + T0 = ((uint8_t)T0); + RETURN(); +} +void OPPROTO op_zextb_T1_T0 (void) +{ + T1 = ((uint8_t)T0); + RETURN(); +} +void OPPROTO op_zextb_T1_T1 (void) +{ + T1 = ((uint8_t)T1); + RETURN(); +} +void OPPROTO op_extw_T0_T0 (void) +{ + T0 = ((int16_t)T0); + RETURN(); +} +void OPPROTO op_extw_T1_T0 (void) +{ + T1 = ((int16_t)T0); + RETURN(); +} +void OPPROTO op_extw_T1_T1 (void) +{ + T1 = ((int16_t)T1); + RETURN(); +} + +void OPPROTO op_zextw_T0_T0 (void) +{ + T0 = ((uint16_t)T0); + RETURN(); +} +void OPPROTO op_zextw_T1_T0 (void) +{ + T1 = ((uint16_t)T0); + RETURN(); +} + +void OPPROTO op_zextw_T1_T1 (void) +{ + T1 = ((uint16_t)T1); + RETURN(); +} + +void OPPROTO op_movl_T0_im (void) +{ + T0 = PARAM1; + RETURN(); +} +void OPPROTO op_movl_T1_im (void) +{ + T1 = PARAM1; + RETURN(); +} + +void OPPROTO op_addl_T0_im (void) +{ + T0 += PARAM1; + RETURN(); +} + +void OPPROTO op_addl_T1_im (void) +{ + T1 += PARAM1; + RETURN(); + +} +void OPPROTO op_subl_T0_im (void) +{ + T0 -= PARAM1; + RETURN(); +} + +void OPPROTO op_addxl_T0_C (void) +{ + if (env->pregs[SR_CCS] & X_FLAG) + T0 += !!(env->pregs[SR_CCS] & C_FLAG); + RETURN(); +} +void OPPROTO op_subxl_T0_C (void) +{ + if (env->pregs[SR_CCS] & X_FLAG) + T0 -= !!(env->pregs[SR_CCS] & C_FLAG); + RETURN(); +} +void OPPROTO op_addl_T0_C (void) +{ + T0 += !!(env->pregs[SR_CCS] & C_FLAG); + RETURN(); +} +void OPPROTO op_addl_T0_R (void) +{ + T0 += !!(env->pregs[SR_CCS] & R_FLAG); + RETURN(); +} + +void OPPROTO op_clr_R (void) +{ + env->pregs[SR_CCS] &= ~R_FLAG; + RETURN(); +} + + +void OPPROTO op_andl_T0_im (void) +{ + T0 &= PARAM1; + RETURN(); +} + +void OPPROTO op_andl_T1_im (void) +{ + T1 &= PARAM1; + RETURN(); +} + +void OPPROTO op_movl_T0_T1 (void) +{ + T0 = T1; + RETURN(); +} + +void OPPROTO op_swp_T0_T1 (void) +{ + T0 ^= T1; + T1 ^= T0; + T0 ^= T1; + RETURN(); +} + +void OPPROTO op_movl_T1_T0 (void) +{ + T1 = T0; + RETURN(); +} + +void OPPROTO op_movl_pc_T0 (void) +{ + env->pc = T0; + RETURN(); +} + +void OPPROTO op_movl_T0_0 (void) +{ + T0 = 0; + RETURN(); +} + +void OPPROTO op_addl_T0_T1 (void) +{ + T0 += T1; + RETURN(); +} + +void OPPROTO op_subl_T0_T1 (void) +{ + T0 -= T1; + RETURN(); +} + +void OPPROTO op_absl_T1_T1 (void) +{ + int32_t st = T1; + + T1 = st < 0 ? -st : st; + RETURN(); +} + +void OPPROTO op_muls_T0_T1 (void) +{ + int64_t tmp, t0 ,t1; + + /* cast into signed values to make GCC sign extend these babies. */ + t0 = (int32_t)T0; + t1 = (int32_t)T1; + + tmp = t0 * t1; + T0 = tmp & 0xffffffff; + env->pregs[REG_MOF] = tmp >> 32; + RETURN(); +} + +void OPPROTO op_mulu_T0_T1 (void) +{ + uint64_t tmp, t0 ,t1; + t0 = T0; + t1 = T1; + + tmp = t0 * t1; + T0 = tmp & 0xffffffff; + env->pregs[REG_MOF] = tmp >> 32; + RETURN(); +} + +void OPPROTO op_dstep_T0_T1 (void) +{ + T0 <<= 1; + if (T0 >= T1) + T0 -= T1; + RETURN(); +} + +void OPPROTO op_orl_T0_T1 (void) +{ + T0 |= T1; + RETURN(); +} + +void OPPROTO op_andl_T0_T1 (void) +{ + T0 &= T1; + RETURN(); +} + +void OPPROTO op_xorl_T0_T1 (void) +{ + T0 ^= T1; + RETURN(); +} + +void OPPROTO op_lsll_T0_T1 (void) +{ + int s = T1; + if (s > 31) + T0 = 0; + else + T0 <<= s; + RETURN(); +} + +void OPPROTO op_lsll_T0_im (void) +{ + T0 <<= PARAM1; + RETURN(); +} + +void OPPROTO op_lsrl_T0_T1 (void) +{ + int s = T1; + if (s > 31) + T0 = 0; + else + T0 >>= s; + RETURN(); +} + +/* Rely on GCC emitting an arithmetic shift for signed right shifts. */ +void OPPROTO op_asrl_T0_T1 (void) +{ + int s = T1; + if (s > 31) + T0 = T0 & 0x80000000 ? -1 : 0; + else + T0 = (int32_t)T0 >> s; + RETURN(); +} + +void OPPROTO op_btst_T0_T1 (void) +{ + /* FIXME: clean this up. */ + + /* des ref: + The N flag is set according to the selected bit in the dest reg. + The Z flag is set if the selected bit and all bits to the right are + zero. + The destination reg is not affected.*/ + unsigned int fz, sbit, bset, mask, masked_t0; + + sbit = T1 & 31; + bset = !!(T0 & (1 << sbit)); + mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1; + masked_t0 = T0 & mask; + fz = !(masked_t0 | bset); + /* Set the N and Z flags accordingly. */ + T0 = (bset << 3) | (fz << 2); + RETURN(); +} + +void OPPROTO op_bound_T0_T1 (void) +{ + if (T0 > T1) + T0 = T1; + RETURN(); +} + +void OPPROTO op_lz_T0_T1 (void) +{ + if (T1 == 0) + T0 = 32; + else + T0 = __builtin_clz(T1); + RETURN(); +} + +void OPPROTO op_negl_T0_T1 (void) +{ + T0 = -T1; + RETURN(); +} + +void OPPROTO op_negl_T1_T1 (void) +{ + T1 = -T1; + RETURN(); +} + +void OPPROTO op_not_T0_T0 (void) +{ + T0 = ~(T0); + RETURN(); +} +void OPPROTO op_not_T1_T1 (void) +{ + T1 = ~(T1); + RETURN(); +} + +void OPPROTO op_swapw_T0_T0 (void) +{ + T0 = (T0 << 16) | ((T0 >> 16)); + RETURN(); +} + +void OPPROTO op_swapb_T0_T0 (void) +{ + T0 = ((T0 << 8) & 0xff00ff00) | ((T0 >> 8) & 0x00ff00ff); + RETURN(); +} + +void OPPROTO op_swapr_T0_T0 (void) +{ + T0 = (((T0 << 7) & 0x80808080) | + ((T0 << 5) & 0x40404040) | + ((T0 << 3) & 0x20202020) | + ((T0 << 1) & 0x10101010) | + ((T0 >> 1) & 0x08080808) | + ((T0 >> 3) & 0x04040404) | + ((T0 >> 5) & 0x02020202) | + ((T0 >> 7) & 0x01010101)); + RETURN(); +} + +void OPPROTO op_tst_cc_eq (void) { + uint32_t flags = env->pregs[SR_CCS]; + int z_set; + + z_set = !!(flags & Z_FLAG); + T0 = z_set; + RETURN(); +} + +void OPPROTO op_tst_cc_eq_fast (void) { + T0 = !(env->cc_result); + RETURN(); +} + +void OPPROTO op_tst_cc_ne (void) { + uint32_t flags = env->pregs[SR_CCS]; + int z_set; + + z_set = !!(flags & Z_FLAG); + T0 = !z_set; + RETURN(); +} +void OPPROTO op_tst_cc_ne_fast (void) { + T0 = !!(env->cc_result); + RETURN(); +} + +void OPPROTO op_tst_cc_cc (void) { + uint32_t flags = env->pregs[SR_CCS]; + int c_set; + + c_set = !!(flags & C_FLAG); + T0 = !c_set; + RETURN(); +} +void OPPROTO op_tst_cc_cs (void) { + uint32_t flags = env->pregs[SR_CCS]; + int c_set; + + c_set = !!(flags & C_FLAG); + T0 = c_set; + RETURN(); +} + +void OPPROTO op_tst_cc_vc (void) { + uint32_t flags = env->pregs[SR_CCS]; + int v_set; + + v_set = !!(flags & V_FLAG); + T0 = !v_set; + RETURN(); +} +void OPPROTO op_tst_cc_vs (void) { + uint32_t flags = env->pregs[SR_CCS]; + int v_set; + + v_set = !!(flags & V_FLAG); + T0 = v_set; + RETURN(); +} +void OPPROTO op_tst_cc_pl (void) { + uint32_t flags = env->pregs[SR_CCS]; + int n_set; + + n_set = !!(flags & N_FLAG); + T0 = !n_set; + RETURN(); +} +void OPPROTO op_tst_cc_pl_fast (void) { + T0 = ((int32_t)env->cc_result) >= 0; + RETURN(); +} + +void OPPROTO op_tst_cc_mi (void) { + uint32_t flags = env->pregs[SR_CCS]; + int n_set; + + n_set = !!(flags & N_FLAG); + T0 = n_set; + RETURN(); +} +void OPPROTO op_tst_cc_mi_fast (void) { + T0 = ((int32_t)env->cc_result) < 0; + RETURN(); +} + +void OPPROTO op_tst_cc_ls (void) { + uint32_t flags = env->pregs[SR_CCS]; + int c_set; + int z_set; + + c_set = !!(flags & C_FLAG); + z_set = !!(flags & Z_FLAG); + T0 = c_set || z_set; + RETURN(); +} +void OPPROTO op_tst_cc_hi (void) { + uint32_t flags = env->pregs[SR_CCS]; + int z_set; + int c_set; + + z_set = !!(flags & Z_FLAG); + c_set = !!(flags & C_FLAG); + T0 = !c_set && !z_set; + RETURN(); + +} + +void OPPROTO op_tst_cc_ge (void) { + uint32_t flags = env->pregs[SR_CCS]; + int n_set; + int v_set; + + n_set = !!(flags & N_FLAG); + v_set = !!(flags & V_FLAG); + T0 = (n_set && v_set) || (!n_set && !v_set); + RETURN(); +} + +void OPPROTO op_tst_cc_ge_fast (void) { + T0 = ((int32_t)env->cc_src < (int32_t)env->cc_dest); + RETURN(); +} + +void OPPROTO op_tst_cc_lt (void) { + uint32_t flags = env->pregs[SR_CCS]; + int n_set; + int v_set; + + n_set = !!(flags & N_FLAG); + v_set = !!(flags & V_FLAG); + T0 = (n_set && !v_set) || (!n_set && v_set); + RETURN(); +} + +void OPPROTO op_tst_cc_gt (void) { + uint32_t flags = env->pregs[SR_CCS]; + int n_set; + int v_set; + int z_set; + + n_set = !!(flags & N_FLAG); + v_set = !!(flags & V_FLAG); + z_set = !!(flags & Z_FLAG); + T0 = (n_set && v_set && !z_set) + || (!n_set && !v_set && !z_set); + RETURN(); +} + +void OPPROTO op_tst_cc_le (void) { + uint32_t flags = env->pregs[SR_CCS]; + int n_set; + int v_set; + int z_set; + + n_set = !!(flags & N_FLAG); + v_set = !!(flags & V_FLAG); + z_set = !!(flags & Z_FLAG); + T0 = z_set || (n_set && !v_set) || (!n_set && v_set); + RETURN(); +} + +void OPPROTO op_tst_cc_p (void) { + uint32_t flags = env->pregs[SR_CCS]; + int p_set; + + p_set = !!(flags & P_FLAG); + T0 = p_set; + RETURN(); +} + +/* Evaluate the if the branch should be taken or not. Needs to be done in + the original sequence. The acutal branch is rescheduled to right after the + delay-slot. */ +void OPPROTO op_evaluate_bcc (void) +{ + env->btaken = T0; + RETURN(); +} + +/* this one is used on every alu op, optimize it!. */ +void OPPROTO op_goto_if_not_x (void) +{ + if (env->pregs[SR_CCS] & X_FLAG) + GOTO_LABEL_PARAM(1); + RETURN(); +} + +void OPPROTO op_cc_jmp (void) +{ + if (env->btaken) + env->pc = PARAM1; + else + env->pc = PARAM2; + RETURN(); +} + +void OPPROTO op_cc_ngoto (void) +{ + if (!env->btaken) + GOTO_LABEL_PARAM(1); + RETURN(); +} + +void OPPROTO op_movl_btarget_T0 (void) +{ + env->btarget = T0; + RETURN(); +} + +void OPPROTO op_jmp (void) +{ + env->pc = env->btarget; + RETURN(); +} + +/* Load and store */ +#define MEMSUFFIX _raw +#include "op_mem.c" +#undef MEMSUFFIX +#if !defined(CONFIG_USER_ONLY) +#define MEMSUFFIX _user +#include "op_mem.c" +#undef MEMSUFFIX + +#define MEMSUFFIX _kernel +#include "op_mem.c" +#undef MEMSUFFIX +#endif -- cgit v1.2.3 From 81fdc5f8d2d681da8d255baf0713144f8656bac9 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:04:02 +0000 Subject: The remainder of CRIS CPU emulation files, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3361 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-cris/cpu.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++ target-cris/exec.h | 68 ++++++++++++ target-cris/helper.c | 173 +++++++++++++++++++++++++++++++ target-cris/op_helper.c | 76 ++++++++++++++ target-cris/op_mem.c | 59 +++++++++++ target-cris/op_template.h | 48 +++++++++ 6 files changed, 680 insertions(+) create mode 100644 target-cris/cpu.h create mode 100644 target-cris/exec.h create mode 100644 target-cris/helper.c create mode 100644 target-cris/op_helper.c create mode 100644 target-cris/op_mem.c create mode 100644 target-cris/op_template.h diff --git a/target-cris/cpu.h b/target-cris/cpu.h new file mode 100644 index 000000000..11652c50f --- /dev/null +++ b/target-cris/cpu.h @@ -0,0 +1,256 @@ +/* + * CRIS virtual CPU header + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias + * + * 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 + * 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_CRIS_H +#define CPU_CRIS_H + +#define TARGET_LONG_BITS 32 + +#include "cpu-defs.h" + +#include "softfloat.h" + +#define TARGET_HAS_ICE 1 + +#define ELF_MACHINE EM_CRIS + +#define EXCP_MMU_EXEC 0 +#define EXCP_MMU_READ 1 +#define EXCP_MMU_WRITE 2 +#define EXCP_MMU_FLUSH 3 +#define EXCP_MMU_MISS 4 +#define EXCP_BREAK 16 /* trap. */ + +/* CPU flags. */ +#define S_FLAG 0x200 +#define R_FLAG 0x100 +#define P_FLAG 0x80 +#define U_FLAG 0x40 +#define P_FLAG 0x80 +#define U_FLAG 0x40 +#define I_FLAG 0x20 +#define X_FLAG 0x10 +#define N_FLAG 0x08 +#define Z_FLAG 0x04 +#define V_FLAG 0x02 +#define C_FLAG 0x01 +#define ALU_FLAGS 0x1F + +/* Condition codes. */ +#define CC_CC 0 +#define CC_CS 1 +#define CC_NE 2 +#define CC_EQ 3 +#define CC_VC 4 +#define CC_VS 5 +#define CC_PL 6 +#define CC_MI 7 +#define CC_LS 8 +#define CC_HI 9 +#define CC_GE 10 +#define CC_LT 11 +#define CC_GT 12 +#define CC_LE 13 +#define CC_A 14 +#define CC_P 15 + +/* Internal flags for the implementation. */ +#define F_DELAYSLOT 1 + +typedef struct CPUCRISState { + uint32_t debug1; + uint32_t debug2; + uint32_t debug3; + + /* + * We just store the stores to the tlbset here for later evaluation + * when the hw needs access to them. + * + * One for I and another for D. + */ + struct + { + uint32_t hi; + uint32_t lo; + } tlbsets[2][4][16]; + + uint32_t sregs[256][16]; /* grrr why so many?? */ + uint32_t regs[16]; + uint32_t pregs[16]; + uint32_t pc; + uint32_t sr; + uint32_t flag_mask; /* Per insn mask of affected flags. */ + + /* SSP and USP. */ + int current_sp; + uint32_t sp[2]; + + /* These are setup up by the guest code just before transfering the + control back to the host. */ + int jmp; + uint32_t btarget; + int btaken; + + /* for traps. */ + int trapnr; + + /* Condition flag tracking. */ + uint32_t cc_op; + uint32_t cc_mask; + uint32_t cc_dest; + uint32_t cc_src; + uint32_t cc_result; + + /* size of the operation, 1 = byte, 2 = word, 4 = dword. */ + int cc_size; + + /* extended arithmetics. */ + int cc_x_live; + int cc_x; + + int features; + + uint64_t pending_interrupts; + int interrupt_request; + int exception_index; + int user_mode_only; + int halted; + + struct + { + int exec_insns; + int exec_loads; + int exec_stores; + } stats; + + + jmp_buf jmp_env; + CPU_COMMON +} CPUCRISState; + +CPUCRISState *cpu_cris_init(void); +int cpu_cris_exec(CPUCRISState *s); +void cpu_cris_close(CPUCRISState *s); +void do_interrupt(CPUCRISState *env); +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +int cpu_cris_signal_handler(int host_signum, void *pinfo, + void *puc); +void cpu_cris_flush_flags(CPUCRISState *, int); + + +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, + int is_asi); + +enum { + CC_OP_DYNAMIC, /* Use env->cc_op */ + CC_OP_FLAGS, + CC_OP_LOGIC, + CC_OP_CMP, + CC_OP_MOVE, + CC_OP_MOVE_PD, + CC_OP_MOVE_SD, + CC_OP_ADD, + CC_OP_ADDC, + CC_OP_MCP, + CC_OP_ADDU, + CC_OP_SUB, + CC_OP_SUBU, + CC_OP_NEG, + CC_OP_BTST, + CC_OP_MULS, + CC_OP_MULU, + CC_OP_DSTEP, + CC_OP_BOUND, + + CC_OP_OR, + CC_OP_AND, + CC_OP_XOR, + CC_OP_LSL, + CC_OP_LSR, + CC_OP_ASR, + CC_OP_LZ +}; + +#define CCF_C 0x01 +#define CCF_V 0x02 +#define CCF_Z 0x04 +#define CCF_N 0x08 +#define CCF_X 0x10 + +#define CRIS_SSP 0 +#define CRIS_USP 1 + +typedef struct cris_def_t cris_def_t; + +int cpu_cris_set_model(CPUCRISState *env, const char * name); + +void cris_set_irq_level(CPUCRISState *env, int level, uint8_t vector); +void cris_set_macsr(CPUCRISState *env, uint32_t val); +void cris_switch_sp(CPUCRISState *env); + +void do_cris_semihosting(CPUCRISState *env, int nr); + +enum cris_features { + CRIS_FEATURE_CF_ISA_MUL, +}; + +static inline int cris_feature(CPUCRISState *env, int feature) +{ + return (env->features & (1u << feature)) != 0; +} + +void register_cris_insns (CPUCRISState *env); + +/* CRIS uses 8k pages. */ +#define TARGET_PAGE_BITS 13 + +#define CPUState CPUCRISState +#define cpu_init cpu_cris_init +#define cpu_exec cpu_cris_exec +#define cpu_gen_code cpu_cris_gen_code +#define cpu_signal_handler cpu_cris_signal_handler + +#include "cpu-all.h" + +/* Register aliases. */ +#define REG_SP 14 +#define REG_ACR 15 +#define REG_MOF 7 + +/* Support regs. */ +#define SR_PID 2 +#define SR_SRS 3 +#define SR_EBP 9 +#define SR_ERP 10 +#define SR_CCS 13 + +/* Support func regs. */ +#define SFR_RW_GC_CFG 0][0 +#define SFR_RW_MM_CFG 1][0 +#define SFR_RW_MM_KBASE_LO 1][1 +#define SFR_RW_MM_KBASE_HI 1][2 +#define SFR_R_MM_CAUSE 1][3 +#define SFR_RW_MM_TLB_SEL 1][4 +#define SFR_RW_MM_TLB_LO 1][5 +#define SFR_RW_MM_TLB_HI 1][6 + +#endif diff --git a/target-cris/exec.h b/target-cris/exec.h new file mode 100644 index 000000000..a4f555eb2 --- /dev/null +++ b/target-cris/exec.h @@ -0,0 +1,68 @@ +/* + * CRIS execution defines + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "dyngen-exec.h" + +#if 1 +register struct CPUCRISState *env asm(AREG0); +/* This is only used for tb lookup. */ +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +#else +struct CPUCRISState *env; +/* This is only used for tb lookup. */ +uint32_t T0; +uint32_t T1; +#endif +#include "cpu.h" +#include "exec-all.h" + +#define RETURN() __asm__ __volatile__("" : : : "memory"); + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu); +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr); + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + +void cpu_cris_flush_flags(CPUCRISState *env, int cc_op); +void helper_movec(CPUCRISState *env, int reg, uint32_t val); + +void cpu_loop_exit(void); + +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} diff --git a/target-cris/helper.c b/target-cris/helper.c new file mode 100644 index 000000000..3db3bea08 --- /dev/null +++ b/target-cris/helper.c @@ -0,0 +1,173 @@ +/* + * CRIS helper routines. + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias. + * + * 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 +#include + +#include "config.h" +#include "cpu.h" +#include "mmu.h" +#include "exec-all.h" + +#if defined(CONFIG_USER_ONLY) + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; +} + +int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + env->exception_index = 0xaa; + env->debug1 = address; + cpu_dump_state(env, stderr, fprintf, 0); + printf("%s addr=%x env->pc=%x\n", __func__, address, env->pc); + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ + return addr; +} + +#else /* !CONFIG_USER_ONLY */ + +int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + struct cris_mmu_result_t res; + int prot, miss; + target_ulong phy; + + address &= TARGET_PAGE_MASK; + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; +// printf ("%s pc=%x %x w=%d smmu=%d\n", __func__, env->pc, address, rw, is_softmmu); + miss = cris_mmu_translate(&res, env, address, rw, is_user); + if (miss) + { + /* handle the miss. */ + phy = 0; + env->exception_index = EXCP_MMU_MISS; + } + else + { + phy = res.phy; + } +// printf ("a=%x phy=%x\n", address, phy); + return tlb_set_page(env, address, phy, prot, is_user, is_softmmu); +} + + +static void cris_shift_ccs(CPUState *env) +{ + uint32_t ccs; + /* Apply the ccs shift. */ + ccs = env->pregs[SR_CCS]; + ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2); +// printf ("ccs=%x %x\n", env->pregs[SR_CCS], ccs); + env->pregs[SR_CCS] = ccs; +} + +void do_interrupt(CPUState *env) +{ + uint32_t ebp, isr; + int irqnum; + + fflush(NULL); + +#if 0 + printf ("exception index=%d interrupt_req=%d\n", + env->exception_index, + env->interrupt_request); +#endif + + switch (env->exception_index) + { + case EXCP_BREAK: +// printf ("BREAK! %d\n", env->trapnr); + irqnum = env->trapnr; + ebp = env->pregs[SR_EBP]; + isr = ldl_code(ebp + irqnum * 4); + env->pregs[SR_ERP] = env->pc + 2; + env->pc = isr; + + cris_shift_ccs(env); + + break; + case EXCP_MMU_MISS: +// printf ("MMU miss\n"); + irqnum = 4; + ebp = env->pregs[SR_EBP]; + isr = ldl_code(ebp + irqnum * 4); + env->pregs[SR_ERP] = env->pc; + env->pc = isr; + cris_shift_ccs(env); + break; + + default: + { + /* Maybe the irq was acked by sw before we got a + change to take it. */ + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + if (!env->pending_interrupts) + return; + if (!(env->pregs[SR_CCS] & I_FLAG)) { + return; + } + + irqnum = 31 - + __builtin_clz(env->pending_interrupts); + irqnum += 0x30; + ebp = env->pregs[SR_EBP]; + isr = ldl_code(ebp + irqnum * 4); + env->pregs[SR_ERP] = env->pc; + env->pc = isr; + + cris_shift_ccs(env); +#if 0 + printf ("%s ebp=%x %x isr=%x %d" + " ir=%x pending=%x\n", + __func__, + ebp, ebp + irqnum * 4, + isr, env->exception_index, + env->interrupt_request, + env->pending_interrupts); +#endif + } + + } + break; + } +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ +// printf ("%s\n", __func__); + uint32_t phy = addr; + struct cris_mmu_result_t res; + int miss; + miss = cris_mmu_translate(&res, env, addr, 0, 0); + if (!miss) + phy = res.phy; + return phy; +} +#endif diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c new file mode 100644 index 000000000..f84ceb9da --- /dev/null +++ b/target-cris/op_helper.c @@ -0,0 +1,76 @@ +/* + * CRIS helper routines + * + * Copyright (c) 2007 AXIS Communications + * Written by Edgar E. Iglesias + * + * 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 +#include "exec.h" + +#define MMUSUFFIX _mmu +#define GETPC() (__builtin_return_address(0)) + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* Try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +{ + TranslationBlock *tb; + CPUState *saved_env; + target_phys_addr_t pc; + int ret; + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + ret = cpu_cris_handle_mmu_fault(env, addr, is_write, is_user, 1); + if (__builtin_expect(ret, 0)) { + if (retaddr) { + /* now we have a real cpu fault */ + pc = (target_phys_addr_t)retaddr; + 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, NULL); + } + } + cpu_loop_exit(); + } + env = saved_env; +} + +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, + int is_asi) +{ + +} diff --git a/target-cris/op_mem.c b/target-cris/op_mem.c new file mode 100644 index 000000000..50ed10b57 --- /dev/null +++ b/target-cris/op_mem.c @@ -0,0 +1,59 @@ +/* + * CRIS memory access (load and store) micro operations. + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +void glue(op_ldb_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldsb, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_ldub_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldub, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stb_T0_T1, MEMSUFFIX) (void) { + glue(stb, MEMSUFFIX) (T0, T1); + RETURN(); +} + +void glue(op_ldw_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldsw, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_lduw_T0_T0, MEMSUFFIX) (void) { + T0 = glue(lduw, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stw_T0_T1, MEMSUFFIX) (void) { + glue(stw, MEMSUFFIX) (T0, T1); + RETURN(); +} + +void glue(op_ldl_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldl, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stl_T0_T1, MEMSUFFIX) (void) { + glue(stl, MEMSUFFIX) (T0, T1); + RETURN(); +} diff --git a/target-cris/op_template.h b/target-cris/op_template.h new file mode 100644 index 000000000..370fbf395 --- /dev/null +++ b/target-cris/op_template.h @@ -0,0 +1,48 @@ +/* + * CRIS micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SET_REG +#define SET_REG(x) REG = x +#endif + +void OPPROTO glue(op_movl_T0_, REGNAME)(void) +{ + T0 = REG; +} + +void OPPROTO glue(op_movl_T1_, REGNAME)(void) +{ + T1 = REG; +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) +{ + SET_REG (T0); +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) +{ + SET_REG (T1); +} + +#undef REG +#undef REGNAME +#undef SET_REG -- cgit v1.2.3 From 94cff60a0219eecd83a1fbd20a8db7e527322674 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:11:58 +0000 Subject: CRIS MMU emulation, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3362 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-cris/mmu.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ target-cris/mmu.h | 20 ++++++++ 2 files changed, 167 insertions(+) create mode 100644 target-cris/mmu.c create mode 100644 target-cris/mmu.h diff --git a/target-cris/mmu.c b/target-cris/mmu.c new file mode 100644 index 000000000..56299b7dd --- /dev/null +++ b/target-cris/mmu.c @@ -0,0 +1,147 @@ +/* + * CRIS mmu emulation. + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias. + * + * 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 CONFIG_USER_ONLY + +#include +#include +#include + +#include "config.h" +#include "cpu.h" +#include "mmu.h" +#include "exec-all.h" + + +static int cris_mmu_enabled(uint32_t rw_gc_cfg) +{ + return (rw_gc_cfg & 12) != 0; +} + +static int cris_mmu_segmented_addr(int seg, uint32_t rw_mm_cfg) +{ + return (1 << seg) & rw_mm_cfg; +} + +static uint32_t cris_mmu_translate_seg(CPUState *env, int seg) +{ + uint32_t base; + int i; + + if (seg < 8) + base = env->sregs[SFR_RW_MM_KBASE_LO]; + else + base = env->sregs[SFR_RW_MM_KBASE_HI]; + + i = seg & 7; + base >>= i * 4; + base &= 15; + + base <<= 28; + return base; +} +/* Used by the tlb decoder. */ +#define EXTRACT_FIELD(src, start, end) \ + (((src) >> start) & ((1 << (end - start + 1)) - 1)) + +static int cris_mmu_translate_page(struct cris_mmu_result_t *res, + CPUState *env, uint32_t vaddr, + int rw, int usermode) +{ + unsigned int vpage; + unsigned int idx; + uint32_t lo, hi; + uint32_t vpn, pfn = 0, pid, fg, fv, fk, fw, fx; + int i, match = 0; + + vpage = vaddr >> 13; + idx = vpage & 31; + vpage >>= 4; + + /* We know the index which to check on each set. + Scan both I and D. */ + for (i = 0; i < 4; i++) + { + lo = env->tlbsets[0][i][idx].lo; + hi = env->tlbsets[0][i][idx].hi; + + vpn = EXTRACT_FIELD(hi, 13, 31); + pid = EXTRACT_FIELD(hi, 0, 7); + + if (vpn == vpage + && pid == env->pregs[SR_PID]) { + match = 1; + break; + } + } + + if (match) { + pfn = EXTRACT_FIELD(lo, 13, 31); + fg = EXTRACT_FIELD(lo, 4, 4); + fv = EXTRACT_FIELD(lo, 3, 3); + fk = EXTRACT_FIELD(lo, 2, 2); + fw = EXTRACT_FIELD(lo, 1, 1); + fx = EXTRACT_FIELD(lo, 0, 0); + } + printf ("%s match=%d vaddr=%x vpage=%x vpn=%x pfn=%x pid=%x %x\n", + __func__, match, + vaddr, vpage, + vpn, pfn, pid, env->pregs[SR_PID]); + res->pfn = pfn; + return !match; +} + +int cris_mmu_translate(struct cris_mmu_result_t *res, + CPUState *env, uint32_t vaddr, + int rw, int is_user) +{ + uint32_t phy = vaddr; + int seg; + int miss = 0; + + if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) { + res->phy = vaddr; + return 0; + } + + seg = vaddr >> 28; + if (cris_mmu_segmented_addr(seg, env->sregs[SFR_RW_MM_CFG])) + { + uint32_t base; + + miss = 0; + base = cris_mmu_translate_seg(env, seg); + phy = base | (0x0fffffff & vaddr); + res->phy = phy; + } + else + { + miss = cris_mmu_translate_page(res, env, vaddr, rw, is_user); + if (!miss) { + phy &= 8191; + phy |= (res->pfn << 13); + res->phy = phy; + } + } +// printf ("miss=%d v=%x -> p=%x\n", miss, vaddr, phy); + return miss; +} +#endif diff --git a/target-cris/mmu.h b/target-cris/mmu.h new file mode 100644 index 000000000..adbc1fc5d --- /dev/null +++ b/target-cris/mmu.h @@ -0,0 +1,20 @@ +#define CRIS_MMU_ERR_EXEC 0 +#define CRIS_MMU_ERR_READ 1 +#define CRIS_MMU_ERR_WRITE 2 +#define CRIS_MMU_ERR_FLUSH 3 + +struct cris_mmu_result_t +{ + uint32_t phy; + uint32_t pfn; + int g:1; + int v:1; + int k:1; + int w:1; + int e:1; + int cause_op; +}; + +int cris_mmu_translate(struct cris_mmu_result_t *res, + CPUState *env, uint32_t vaddr, + int rw, int is_user); -- cgit v1.2.3 From f1ccf904778f7a840d2b751b5e429d4088ba9cb4 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:16:14 +0000 Subject: CRIS support in toplevel, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3363 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++- exec-all.h | 2 ++ exec.c | 4 ++++ gdbstub.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- softmmu_header.h | 6 ++++++ vl.c | 2 ++ vl.h | 3 +++ 7 files changed, 143 insertions(+), 2 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 55758faef..d09b564af 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -210,6 +210,10 @@ static inline TranslationBlock *tb_find_fast(void) flags = env->ps; cs_base = 0; pc = env->pc; +#elif defined(TARGET_CRIS) + flags = 0; + cs_base = 0; + pc = env->pc; #else #error unsupported CPU #endif @@ -284,6 +288,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_PPC) #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) +#elif defined(TARGET_CRIS) /* XXXXX */ #else #error unsupported target CPU @@ -335,6 +340,8 @@ int cpu_exec(CPUState *env1) do_interrupt(env); #elif defined(TARGET_ALPHA) do_interrupt(env); +#elif defined(TARGET_CRIS) + do_interrupt(env); #elif defined(TARGET_M68K) do_interrupt(0); #endif @@ -385,7 +392,7 @@ int cpu_exec(CPUState *env1) cpu_loop_exit(); } #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ - defined(TARGET_PPC) || defined(TARGET_ALPHA) + defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) if (interrupt_request & CPU_INTERRUPT_HALT) { env->interrupt_request &= ~CPU_INTERRUPT_HALT; env->halted = 1; @@ -517,6 +524,11 @@ int cpu_exec(CPUState *env1) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); } +#elif defined(TARGET_CRIS) + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + } #elif defined(TARGET_M68K) if (interrupt_request & CPU_INTERRUPT_HARD && ((env->sr & SR_I) >> SR_I_SHIFT) @@ -576,6 +588,8 @@ int cpu_exec(CPUState *env1) cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_ALPHA) cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_CRIS) + cpu_dump_state(env, logfile, fprintf, 0); #else #error unsupported target CPU #endif @@ -769,6 +783,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) #elif defined(TARGET_ALPHA) +#elif defined(TARGET_CRIS) /* XXXXX */ #else #error unsupported target CPU @@ -1200,6 +1215,51 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, /* never comes here */ return 1; } +#elif defined (TARGET_CRIS) +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_cris_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 diff --git a/exec-all.h b/exec-all.h index dc5a10d97..a01494b03 100644 --- a/exec-all.h +++ b/exec-all.h @@ -617,6 +617,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) is_user = ((env->ps >> 3) & 3); #elif defined (TARGET_M68K) is_user = ((env->sr & SR_S) == 0); +#elif defined (TARGET_CRIS) + is_user = (0); #else #error unimplemented CPU #endif diff --git a/exec.c b/exec.c index 0c0b6542e..175bd2801 100644 --- a/exec.c +++ b/exec.c @@ -2066,6 +2066,8 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) #endif #ifdef TARGET_SPARC do_unassigned_access(addr, 0, 0, 0); +#elif TARGET_CRIS + do_unassigned_access(addr, 0, 0, 0); #endif return 0; } @@ -2077,6 +2079,8 @@ static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_ #endif #ifdef TARGET_SPARC do_unassigned_access(addr, 1, 0, 0); +#elif TARGET_CRIS + do_unassigned_access(addr, 1, 0, 0); #endif } diff --git a/gdbstub.c b/gdbstub.c index 28f9b440c..139bc25fc 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -728,6 +728,66 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) for (i = 0; i < 8; i++) LOAD(env->gregs[i]); for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]); } +#elif defined (TARGET_CRIS) + +static int cris_save_32 (unsigned char *d, uint32_t value) +{ + *d++ = (value); + *d++ = (value >>= 8); + *d++ = (value >>= 8); + *d++ = (value >>= 8); + return 4; +} +static int cris_save_16 (unsigned char *d, uint32_t value) +{ + *d++ = (value); + *d++ = (value >>= 8); + return 2; +} +static int cris_save_8 (unsigned char *d, uint32_t value) +{ + *d++ = (value); + return 1; +} + +/* FIXME: this will bug on archs not supporting unaligned word accesses. */ +static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) +{ + uint8_t *ptr = mem_buf; + uint8_t srs; + int i; + + for (i = 0; i < 16; i++) + ptr += cris_save_32 (ptr, env->regs[i]); + + srs = env->pregs[SR_SRS]; + + ptr += cris_save_8 (ptr, env->pregs[0]); + ptr += cris_save_8 (ptr, env->pregs[1]); + ptr += cris_save_32 (ptr, env->pregs[2]); + ptr += cris_save_8 (ptr, srs); + ptr += cris_save_16 (ptr, env->pregs[4]); + + for (i = 5; i < 16; i++) + ptr += cris_save_32 (ptr, env->pregs[i]); + + ptr += cris_save_32 (ptr, env->pc); + + for (i = 0; i < 16; i++) + ptr += cris_save_32 (ptr, env->sregs[srs][i]); + + return ((uint8_t *)ptr - mem_buf); +} + +static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) +{ + uint32_t *ptr = (uint32_t *)mem_buf; + int i; + +#define LOAD(x) (x)=*ptr++; + for (i = 0; i < 16; i++) LOAD(env->regs[i]); + LOAD (env->pc); +} #else static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { @@ -745,7 +805,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) const char *p; int ch, reg_size, type; char buf[4096]; - uint8_t mem_buf[2000]; + uint8_t mem_buf[4096]; uint32_t *registers; target_ulong addr, len; @@ -776,6 +836,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) env->pc = addr; #elif defined (TARGET_MIPS) env->PC[env->current_tc] = addr; +#elif defined (TARGET_CRIS) + env->pc = addr; #endif } #ifdef CONFIG_USER_ONLY @@ -800,6 +862,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) env->pc = addr; #elif defined (TARGET_MIPS) env->PC[env->current_tc] = addr; +#elif defined (TARGET_CRIS) + env->pc = addr; #endif } cpu_single_step(env, 1); diff --git a/softmmu_header.h b/softmmu_header.h index 768b87781..384518bb6 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -67,6 +67,9 @@ #define CPU_MEM_INDEX ((env->ps >> 3) & 3) #elif defined (TARGET_M68K) #define CPU_MEM_INDEX ((env->sr & SR_S) == 0) +#elif defined (TARGET_CRIS) +/* CRIS FIXME: I guess we want to validate supervisor mode acceses here. */ +#define CPU_MEM_INDEX (0) #else #error unsupported CPU #endif @@ -90,6 +93,9 @@ #define CPU_MEM_INDEX ((env->ps >> 3) & 3) #elif defined (TARGET_M68K) #define CPU_MEM_INDEX ((env->sr & SR_S) == 0) +#elif defined (TARGET_CRIS) +/* CRIS FIXME: I guess we want to validate supervisor mode acceses here. */ +#define CPU_MEM_INDEX (0) #else #error unsupported CPU #endif diff --git a/vl.c b/vl.c index be99f959c..01bb06eda 100644 --- a/vl.c +++ b/vl.c @@ -7390,6 +7390,8 @@ void register_machines(void) #elif defined(TARGET_M68K) qemu_register_machine(&mcf5208evb_machine); qemu_register_machine(&an5206_machine); +#elif defined(TARGET_CRIS) + qemu_register_machine(&bareetraxfs_machine); #else #error unsupported CPU #endif diff --git a/vl.h b/vl.h index 45032c8d3..d13cb3728 100644 --- a/vl.h +++ b/vl.h @@ -1173,6 +1173,9 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base); void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); void acpi_bios_init(void); +/* Axis ETRAX. */ +extern QEMUMachine bareetraxfs_machine; + /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; -- cgit v1.2.3 From 83fa1010ae342c5ad0392182fcdcce438c71b163 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:26:33 +0000 Subject: EtraxFS board support, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3364 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/etraxfs.c | 178 +++++++++++++++++++++++++++++++++++ hw/etraxfs_ser.c | 122 ++++++++++++++++++++++++ hw/etraxfs_timer.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 568 insertions(+) create mode 100644 hw/etraxfs.c create mode 100644 hw/etraxfs_ser.c create mode 100644 hw/etraxfs_timer.c diff --git a/hw/etraxfs.c b/hw/etraxfs.c new file mode 100644 index 000000000..cf0f38493 --- /dev/null +++ b/hw/etraxfs.c @@ -0,0 +1,178 @@ +/* + * QEMU ETRAX System Emulator + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include +#include "vl.h" + +extern FILE *logfile; + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); +} + +static uint32_t fs_mmio_readb (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} +static uint32_t fs_mmio_readw (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} + +static uint32_t fs_mmio_readl (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x p=%x\n", __func__, addr, env->pc); + return r; +} + +static void +fs_mmio_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +fs_mmio_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +fs_mmio_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} + +static CPUReadMemoryFunc *fs_mmio_read[] = { + &fs_mmio_readb, + &fs_mmio_readw, + &fs_mmio_readl, +}; + +static CPUWriteMemoryFunc *fs_mmio_write[] = { + &fs_mmio_writeb, + &fs_mmio_writew, + &fs_mmio_writel, +}; + + +/* Init functions for different blocks. */ +extern void etraxfs_timer_init(CPUState *env, qemu_irq *irqs); +extern void etraxfs_ser_init(CPUState *env, qemu_irq *irqs); + +void etrax_ack_irq(CPUState *env, uint32_t mask) +{ + env->pending_interrupts &= ~mask; +} + +static void dummy_cpu_set_irq(void *opaque, int irq, int level) +{ + CPUState *env = opaque; + + /* Hmm, should this really be done here? */ + env->pending_interrupts |= 1 << irq; + cpu_interrupt(env, CPU_INTERRUPT_HARD); +} + +static +void bareetraxfs_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env; + qemu_irq *irqs; + int kernel_size; + int internal_regs; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "crisv32"; + } + env = cpu_init(); +/* register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); */ + qemu_register_reset(main_cpu_reset, env); + irqs = qemu_allocate_irqs(dummy_cpu_set_irq, env, 32); + + internal_regs = cpu_register_io_memory(0, + fs_mmio_read, fs_mmio_write, env); + /* 0xb0050000 is the last reg. */ + cpu_register_physical_memory (0xac000000, 0x4010000, internal_regs); + /* allocate RAM */ + cpu_register_physical_memory(0x40000000, ram_size, IO_MEM_RAM); + + etraxfs_timer_init(env, irqs); + etraxfs_ser_init(env, irqs); + + kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000); + /* magic for boot. */ + env->regs[8] = 0x56902387; + env->regs[9] = 0x40004000 + kernel_size; + env->pc = 0x40004000; + + { + unsigned char *ptr = phys_ram_base + 0x4000; + int i; + for (i = 0; i < 8; i++) + { + printf ("%2.2x ", ptr[i]); + } + printf("\n"); + } + + printf ("pc =%x\n", env->pc); + printf ("ram size =%d\n", ram_size); + printf ("kernel name =%s\n", kernel_filename); + printf ("kernel size =%d\n", kernel_size); + printf ("cpu haltd =%d\n", env->halted); +} + +void DMA_run(void) +{ +} + +void pic_info() +{ +} + +void irq_info() +{ +} + +QEMUMachine bareetraxfs_machine = { + "bareetraxfs", + "Bare ETRAX FS board", + bareetraxfs_init, +}; diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c new file mode 100644 index 000000000..3ff6ff77c --- /dev/null +++ b/hw/etraxfs_ser.c @@ -0,0 +1,122 @@ +/* + * QEMU ETRAX System Emulator + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include +#include "vl.h" + +#define RW_TR_DMA_EN 0xb0026004 +#define RW_DOUT 0xb002601c +#define RW_STAT_DIN 0xb0026020 +#define R_STAT_DIN 0xb0026024 + +static uint32_t ser_readb (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} +static uint32_t ser_readw (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} + +static uint32_t ser_readl (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + + switch (addr) + { + case RW_TR_DMA_EN: + break; + case R_STAT_DIN: + r |= 1 << 24; /* set tr_rdy. */ + r |= 1 << 22; /* set tr_idle. */ + break; + + default: + printf ("%s %x p=%x\n", __func__, addr, env->pc); + break; + } + return r; +} + +static void +ser_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +ser_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + + switch (addr) + { + case RW_TR_DMA_EN: + break; + case RW_DOUT: + if (isprint(value) || isspace(value)) + putchar(value); + else + putchar('.'); + break; + default: + printf ("%s %x %x pc=%x\n", + __func__, addr, value, env->pc); + break; + } +} + +static CPUReadMemoryFunc *ser_read[] = { + &ser_readb, + &ser_readw, + &ser_readl, +}; + +static CPUWriteMemoryFunc *ser_write[] = { + &ser_writeb, + &ser_writew, + &ser_writel, +}; + +void etraxfs_ser_init(CPUState *env, qemu_irq *irqs) +{ + int ser_regs; + + ser_regs = cpu_register_io_memory(0, ser_read, ser_write, env); + cpu_register_physical_memory (0xb0026000, 0x3c, ser_regs); +} diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c new file mode 100644 index 000000000..1c2e4035f --- /dev/null +++ b/hw/etraxfs_timer.c @@ -0,0 +1,268 @@ +/* + * QEMU ETRAX System Emulator + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * 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 +#include +#include "vl.h" + +void etrax_ack_irq(CPUState *env, uint32_t mask); + +#define R_TIME 0xb001e038 +#define RW_TMR0_DIV 0xb001e000 +#define R_TMR0_DATA 0xb001e004 +#define RW_TMR0_CTRL 0xb001e008 +#define RW_TMR1_DIV 0xb001e010 +#define R_TMR1_DATA 0xb001e014 +#define RW_TMR1_CTRL 0xb001e018 + +#define RW_INTR_MASK 0xb001e048 +#define RW_ACK_INTR 0xb001e04c +#define R_INTR 0xb001e050 +#define R_MASKED_INTR 0xb001e054 + + +uint32_t rw_intr_mask; +uint32_t rw_ack_intr; +uint32_t r_intr; + +struct fs_timer_t { + QEMUBH *bh; + unsigned int limit; + int scale; + ptimer_state *ptimer; + CPUState *env; + qemu_irq *irq; + uint32_t mask; +}; + +static struct fs_timer_t timer0; + +/* diff two timevals. Return a single int in us. */ +int diff_timeval_us(struct timeval *a, struct timeval *b) +{ + int diff; + + /* assume these values are signed. */ + diff = (a->tv_sec - b->tv_sec) * 1000 * 1000; + diff += (a->tv_usec - b->tv_usec); + return diff; +} + +static uint32_t timer_readb (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} +static uint32_t timer_readw (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + printf ("%s %x pc=%x\n", __func__, addr, env->pc); + return r; +} + +static uint32_t timer_readl (void *opaque, target_phys_addr_t addr) +{ + CPUState *env = opaque; + uint32_t r = 0; + + switch (addr) { + case R_TMR0_DATA: + break; + case R_TMR1_DATA: + printf ("R_TMR1_DATA\n"); + break; + case R_TIME: + { + static struct timeval last; + struct timeval now; + gettimeofday(&now, NULL); + if (!(last.tv_sec == 0 && last.tv_usec == 0)) { + r = diff_timeval_us(&now, &last); + r *= 1000; /* convert to ns. */ + r++; /* make sure we increase for each call. */ + } + last = now; + break; + } + + case RW_INTR_MASK: + r = rw_intr_mask; + break; + case R_MASKED_INTR: + r = r_intr & rw_intr_mask; + break; + default: + printf ("%s %x p=%x\n", __func__, addr, env->pc); + break; + } + return r; +} + +static void +timer_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} +static void +timer_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc); +} + +static void write_ctrl(struct fs_timer_t *t, uint32_t v) +{ + int op; + int freq; + int freq_hz; + + op = v & 3; + freq = v >> 2; + freq_hz = 32000000; + + switch (freq) + { + case 0: + case 1: + printf ("extern or disabled timer clock?\n"); + break; + case 4: freq_hz = 29493000; break; + case 5: freq_hz = 32000000; break; + case 6: freq_hz = 32768000; break; + case 7: freq_hz = 100000000; break; + default: + abort(); + break; + } + + printf ("freq_hz=%d limit=%d\n", freq_hz, t->limit); + t->scale = 0; + if (t->limit > 2048) + { + t->scale = 2048; + ptimer_set_period(timer0.ptimer, freq_hz / t->scale); + } + + printf ("op=%d\n", op); + switch (op) + { + case 0: + printf ("limit=%d %d\n", t->limit, t->limit/t->scale); + ptimer_set_limit(t->ptimer, t->limit / t->scale, 1); + break; + case 1: + ptimer_stop(t->ptimer); + break; + case 2: + ptimer_run(t->ptimer, 0); + break; + default: + abort(); + break; + } +} + +static void timer_ack_irq(void) +{ + if (!(r_intr & timer0.mask & rw_intr_mask)) { + qemu_irq_lower(timer0.irq[0]); + etrax_ack_irq(timer0.env, 1 << 0x1b); + } +} + +static void +timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + CPUState *env = opaque; + printf ("%s %x %x pc=%x\n", + __func__, addr, value, env->pc); + switch (addr) + { + case RW_TMR0_DIV: + printf ("RW_TMR0_DIV=%x\n", value); + timer0.limit = value; + break; + case RW_TMR0_CTRL: + printf ("RW_TMR0_CTRL=%x\n", value); + write_ctrl(&timer0, value); + break; + case RW_TMR1_DIV: + printf ("RW_TMR1_DIV=%x\n", value); + break; + case RW_TMR1_CTRL: + printf ("RW_TMR1_CTRL=%x\n", value); + break; + case RW_INTR_MASK: + printf ("RW_INTR_MASK=%x\n", value); + rw_intr_mask = value; + break; + case RW_ACK_INTR: + r_intr &= ~value; + timer_ack_irq(); + break; + default: + printf ("%s %x %x pc=%x\n", + __func__, addr, value, env->pc); + break; + } +} + +static CPUReadMemoryFunc *timer_read[] = { + &timer_readb, + &timer_readw, + &timer_readl, +}; + +static CPUWriteMemoryFunc *timer_write[] = { + &timer_writeb, + &timer_writew, + &timer_writel, +}; + +static void timer_irq(void *opaque) +{ + struct fs_timer_t *t = opaque; + + r_intr |= t->mask; + if (t->mask & rw_intr_mask) { + qemu_irq_raise(t->irq[0]); + } +} + +void etraxfs_timer_init(CPUState *env, qemu_irq *irqs) +{ + int timer_regs; + + timer0.bh = qemu_bh_new(timer_irq, &timer0); + timer0.ptimer = ptimer_init(timer0.bh); + timer0.irq = irqs + 0x1b; + timer0.mask = 1; + timer0.env = env; + + timer_regs = cpu_register_io_memory(0, timer_read, timer_write, env); + cpu_register_physical_memory (0xb001e000, 0x5c, timer_regs); +} -- cgit v1.2.3 From dd43edf4e136bff05cbbb6b42b96c024c591dbb9 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:32:20 +0000 Subject: CRIS testsuite, based on the SIM testsuite, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3365 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/cris/.gdbinit | 12 ++ tests/cris/Makefile | 153 ++++++++++++++++++++ tests/cris/README | 2 + tests/cris/check_abs.c | 39 +++++ tests/cris/check_addc.c | 57 ++++++++ tests/cris/check_addcm.c | 83 +++++++++++ tests/cris/check_addi.s | 57 ++++++++ tests/cris/check_addiv32.s | 62 ++++++++ tests/cris/check_addm.s | 96 +++++++++++++ tests/cris/check_addo.c | 125 ++++++++++++++++ tests/cris/check_addoq.c | 44 ++++++ tests/cris/check_addq.s | 47 ++++++ tests/cris/check_addr.s | 96 +++++++++++++ tests/cris/check_addxc.s | 91 ++++++++++++ tests/cris/check_addxm.s | 106 ++++++++++++++ tests/cris/check_addxr.s | 96 +++++++++++++ tests/cris/check_andc.s | 80 +++++++++++ tests/cris/check_andm.s | 90 ++++++++++++ tests/cris/check_andq.s | 46 ++++++ tests/cris/check_andr.s | 95 ++++++++++++ tests/cris/check_asr.s | 230 +++++++++++++++++++++++++++++ tests/cris/check_ba.s | 93 ++++++++++++ tests/cris/check_bas.s | 102 +++++++++++++ tests/cris/check_bcc.s | 197 +++++++++++++++++++++++++ tests/cris/check_bound.c | 139 ++++++++++++++++++ tests/cris/check_boundc.s | 101 +++++++++++++ tests/cris/check_boundr.s | 125 ++++++++++++++++ tests/cris/check_btst.s | 87 +++++++++++ tests/cris/check_clearfv32.s | 17 +++ tests/cris/check_clrjmp1.s | 36 +++++ tests/cris/check_cmp-2.s | 15 ++ tests/cris/check_cmpc.s | 86 +++++++++++ tests/cris/check_cmpm.s | 96 +++++++++++++ tests/cris/check_cmpq.s | 75 ++++++++++ tests/cris/check_cmpr.s | 102 +++++++++++++ tests/cris/check_cmpxc.s | 92 ++++++++++++ tests/cris/check_cmpxm.s | 106 ++++++++++++++ tests/cris/check_dstep.s | 42 ++++++ tests/cris/check_gcctorture_pr28634-1.c | 15 ++ tests/cris/check_gcctorture_pr28634.c | 15 ++ tests/cris/check_glibc_kernelversion.c | 116 +++++++++++++++ tests/cris/check_hello.c | 7 + tests/cris/check_int64.c | 45 ++++++ tests/cris/check_jsr.s | 85 +++++++++++ tests/cris/check_lapc.s | 78 ++++++++++ tests/cris/check_lsl.s | 217 ++++++++++++++++++++++++++++ tests/cris/check_lsr.s | 218 ++++++++++++++++++++++++++++ tests/cris/check_lz.c | 49 +++++++ tests/cris/check_mapbrk.c | 39 +++++ tests/cris/check_mcp.s | 49 +++++++ tests/cris/check_mmap1.c | 48 +++++++ tests/cris/check_mmap2.c | 48 +++++++ tests/cris/check_mmap3.c | 33 +++++ tests/cris/check_movdelsr1.s | 33 +++++ tests/cris/check_movecr.s | 37 +++++ tests/cris/check_movei.s | 47 ++++++ tests/cris/check_movemr.s | 79 ++++++++++ tests/cris/check_movemrv32.s | 97 +++++++++++++ tests/cris/check_moveq.c | 51 +++++++ tests/cris/check_mover.s | 29 ++++ tests/cris/check_moverm.s | 45 ++++++ tests/cris/check_movmp.s | 131 +++++++++++++++++ tests/cris/check_movpmv32.s | 35 +++++ tests/cris/check_movpr.s | 28 ++++ tests/cris/check_movprv32.s | 21 +++ tests/cris/check_movscr.s | 29 ++++ tests/cris/check_movsm.s | 44 ++++++ tests/cris/check_movsr.s | 46 ++++++ tests/cris/check_movucr.s | 33 +++++ tests/cris/check_movum.s | 40 ++++++ tests/cris/check_movur.s | 45 ++++++ tests/cris/check_mulv32.s | 51 +++++++ tests/cris/check_mulx.s | 246 ++++++++++++++++++++++++++++++++ tests/cris/check_neg.s | 104 ++++++++++++++ tests/cris/check_not.s | 31 ++++ tests/cris/check_openpf1.c | 38 +++++ tests/cris/check_openpf2.c | 16 +++ tests/cris/check_openpf3.c | 49 +++++++ tests/cris/check_openpf4.c | 5 + tests/cris/check_openpf5.c | 56 ++++++++ tests/cris/check_orc.s | 71 +++++++++ tests/cris/check_orm.s | 75 ++++++++++ tests/cris/check_orq.s | 41 ++++++ tests/cris/check_orr.s | 84 +++++++++++ tests/cris/check_ret.s | 25 ++++ tests/cris/check_scc.s | 95 ++++++++++++ tests/cris/check_stat1.c | 16 +++ tests/cris/check_stat2.c | 20 +++ tests/cris/check_stat3.c | 26 ++++ tests/cris/check_stat4.c | 28 ++++ tests/cris/check_subc.s | 87 +++++++++++ tests/cris/check_subm.s | 96 +++++++++++++ tests/cris/check_subq.s | 52 +++++++ tests/cris/check_subr.s | 102 +++++++++++++ tests/cris/check_swap.c | 75 ++++++++++ tests/cris/check_time1.c | 46 ++++++ tests/cris/check_time2.c | 18 +++ tests/cris/check_xarith.s | 46 ++++++ tests/cris/crisutils.h | 71 +++++++++ tests/cris/crt.s | 13 ++ tests/cris/sys.c | 48 +++++++ tests/cris/sys.h | 16 +++ tests/cris/testutils.inc | 117 +++++++++++++++ 103 files changed, 7014 insertions(+) create mode 100644 tests/cris/.gdbinit create mode 100644 tests/cris/Makefile create mode 100644 tests/cris/README create mode 100644 tests/cris/check_abs.c create mode 100644 tests/cris/check_addc.c create mode 100644 tests/cris/check_addcm.c create mode 100644 tests/cris/check_addi.s create mode 100644 tests/cris/check_addiv32.s create mode 100644 tests/cris/check_addm.s create mode 100644 tests/cris/check_addo.c create mode 100644 tests/cris/check_addoq.c create mode 100644 tests/cris/check_addq.s create mode 100644 tests/cris/check_addr.s create mode 100644 tests/cris/check_addxc.s create mode 100644 tests/cris/check_addxm.s create mode 100644 tests/cris/check_addxr.s create mode 100644 tests/cris/check_andc.s create mode 100644 tests/cris/check_andm.s create mode 100644 tests/cris/check_andq.s create mode 100644 tests/cris/check_andr.s create mode 100644 tests/cris/check_asr.s create mode 100644 tests/cris/check_ba.s create mode 100644 tests/cris/check_bas.s create mode 100644 tests/cris/check_bcc.s create mode 100644 tests/cris/check_bound.c create mode 100644 tests/cris/check_boundc.s create mode 100644 tests/cris/check_boundr.s create mode 100644 tests/cris/check_btst.s create mode 100644 tests/cris/check_clearfv32.s create mode 100644 tests/cris/check_clrjmp1.s create mode 100644 tests/cris/check_cmp-2.s create mode 100644 tests/cris/check_cmpc.s create mode 100644 tests/cris/check_cmpm.s create mode 100644 tests/cris/check_cmpq.s create mode 100644 tests/cris/check_cmpr.s create mode 100644 tests/cris/check_cmpxc.s create mode 100644 tests/cris/check_cmpxm.s create mode 100644 tests/cris/check_dstep.s create mode 100644 tests/cris/check_gcctorture_pr28634-1.c create mode 100644 tests/cris/check_gcctorture_pr28634.c create mode 100644 tests/cris/check_glibc_kernelversion.c create mode 100644 tests/cris/check_hello.c create mode 100644 tests/cris/check_int64.c create mode 100644 tests/cris/check_jsr.s create mode 100644 tests/cris/check_lapc.s create mode 100644 tests/cris/check_lsl.s create mode 100644 tests/cris/check_lsr.s create mode 100644 tests/cris/check_lz.c create mode 100644 tests/cris/check_mapbrk.c create mode 100644 tests/cris/check_mcp.s create mode 100644 tests/cris/check_mmap1.c create mode 100644 tests/cris/check_mmap2.c create mode 100644 tests/cris/check_mmap3.c create mode 100644 tests/cris/check_movdelsr1.s create mode 100644 tests/cris/check_movecr.s create mode 100644 tests/cris/check_movei.s create mode 100644 tests/cris/check_movemr.s create mode 100644 tests/cris/check_movemrv32.s create mode 100644 tests/cris/check_moveq.c create mode 100644 tests/cris/check_mover.s create mode 100644 tests/cris/check_moverm.s create mode 100644 tests/cris/check_movmp.s create mode 100644 tests/cris/check_movpmv32.s create mode 100644 tests/cris/check_movpr.s create mode 100644 tests/cris/check_movprv32.s create mode 100644 tests/cris/check_movscr.s create mode 100644 tests/cris/check_movsm.s create mode 100644 tests/cris/check_movsr.s create mode 100644 tests/cris/check_movucr.s create mode 100644 tests/cris/check_movum.s create mode 100644 tests/cris/check_movur.s create mode 100644 tests/cris/check_mulv32.s create mode 100644 tests/cris/check_mulx.s create mode 100644 tests/cris/check_neg.s create mode 100644 tests/cris/check_not.s create mode 100644 tests/cris/check_openpf1.c create mode 100644 tests/cris/check_openpf2.c create mode 100644 tests/cris/check_openpf3.c create mode 100644 tests/cris/check_openpf4.c create mode 100644 tests/cris/check_openpf5.c create mode 100644 tests/cris/check_orc.s create mode 100644 tests/cris/check_orm.s create mode 100644 tests/cris/check_orq.s create mode 100644 tests/cris/check_orr.s create mode 100644 tests/cris/check_ret.s create mode 100644 tests/cris/check_scc.s create mode 100644 tests/cris/check_stat1.c create mode 100644 tests/cris/check_stat2.c create mode 100644 tests/cris/check_stat3.c create mode 100644 tests/cris/check_stat4.c create mode 100644 tests/cris/check_subc.s create mode 100644 tests/cris/check_subm.s create mode 100644 tests/cris/check_subq.s create mode 100644 tests/cris/check_subr.s create mode 100644 tests/cris/check_swap.c create mode 100644 tests/cris/check_time1.c create mode 100644 tests/cris/check_time2.c create mode 100644 tests/cris/check_xarith.s create mode 100644 tests/cris/crisutils.h create mode 100644 tests/cris/crt.s create mode 100644 tests/cris/sys.c create mode 100644 tests/cris/sys.h create mode 100644 tests/cris/testutils.inc diff --git a/tests/cris/.gdbinit b/tests/cris/.gdbinit new file mode 100644 index 000000000..579eac943 --- /dev/null +++ b/tests/cris/.gdbinit @@ -0,0 +1,12 @@ +b main +b _fail +b exit +display /i $pc +display /x $srp +display /x $r0 +display /x $r1 +display /x $r2 +display /x $r3 +display /x $r4 +display /t $ccs + diff --git a/tests/cris/Makefile b/tests/cris/Makefile new file mode 100644 index 000000000..a6a28f4ec --- /dev/null +++ b/tests/cris/Makefile @@ -0,0 +1,153 @@ +-include ../../config-host.mak + +CROSS=crisv32-axis-linux-gnu- +SIM=../../cris-linux-user/qemu-cris -L ./ +SIMG=cris-axis-linux-gnu-run --sysroot=./ + +CC = $(CROSS)gcc +#AS = $(CROSS)as +AS = $(CC) -x assembler-with-cpp +SIZE = $(CROSS)size +LD = $(CC) +OBJCOPY = $(CROSS)objcopy + +# we rely on GCC inline:ing the stuff we tell it to in many places here. +CFLAGS = -Winline -Wall -g -O2 -static +NOSTDFLAGS = -nostartfiles -nostdlib +ASFLAGS += -g -Wa,-I,$(SRC_PATH)/tests/cris/ +LDLIBS = +NOSTDLIBS = -lgcc + +CRT = crt.o +SYS = sys.o +TESTCASES += check_abs.tst +TESTCASES += check_addc.tst +TESTCASES += check_addcm.tst +TESTCASES += check_addo.tst +TESTCASES += check_addoq.tst +TESTCASES += check_addi.tst +TESTCASES += check_addiv32.tst +TESTCASES += check_addm.tst +TESTCASES += check_addr.tst +TESTCASES += check_addq.tst +TESTCASES += check_addxc.tst +TESTCASES += check_addxm.tst +TESTCASES += check_addxr.tst +TESTCASES += check_andc.tst +TESTCASES += check_andm.tst +TESTCASES += check_andr.tst +TESTCASES += check_andq.tst +TESTCASES += check_asr.tst +TESTCASES += check_ba.tst +TESTCASES += check_bas.tst +TESTCASES += check_bcc.tst +TESTCASES += check_bound.tst +TESTCASES += check_boundc.tst +TESTCASES += check_boundr.tst +TESTCASES += check_btst.tst +TESTCASES += check_clearfv32.tst +TESTCASES += check_cmpc.tst +TESTCASES += check_cmpr.tst +TESTCASES += check_cmpq.tst +TESTCASES += check_cmpm.tst +TESTCASES += check_cmpxc.tst +TESTCASES += check_cmpxm.tst +TESTCASES += check_cmp-2.tst +TESTCASES += check_clrjmp1.tst +TESTCASES += check_dstep.tst +TESTCASES += check_int64.tst +# check_jsr is broken. +#TESTCASES += check_jsr.tst +TESTCASES += check_mcp.tst +TESTCASES += check_movei.tst +TESTCASES += check_mover.tst +TESTCASES += check_moverm.tst +TESTCASES += check_moveq.tst +TESTCASES += check_movemr.tst +TESTCASES += check_movemrv32.tst +TESTCASES += check_movecr.tst +TESTCASES += check_movmp.tst +TESTCASES += check_movpr.tst +TESTCASES += check_movprv32.tst +TESTCASES += check_movdelsr1.tst +TESTCASES += check_movpmv32.tst +TESTCASES += check_movsr.tst +TESTCASES += check_movsm.tst +TESTCASES += check_movscr.tst +TESTCASES += check_movur.tst +TESTCASES += check_movum.tst +TESTCASES += check_movucr.tst +TESTCASES += check_mulx.tst +TESTCASES += check_mulv32.tst +TESTCASES += check_neg.tst +TESTCASES += check_not.tst +TESTCASES += check_lz.tst +TESTCASES += check_lapc.tst +TESTCASES += check_lsl.tst +TESTCASES += check_lsr.tst +TESTCASES += check_orc.tst +TESTCASES += check_orm.tst +TESTCASES += check_orr.tst +TESTCASES += check_orq.tst +TESTCASES += check_ret.tst +TESTCASES += check_swap.tst +TESTCASES += check_scc.tst +TESTCASES += check_subc.tst +TESTCASES += check_subq.tst +TESTCASES += check_subr.tst +TESTCASES += check_subm.tst +TESTCASES += check_glibc_kernelversion.tst +TESTCASES += check_xarith.tst + +TESTCASES += check_hello.ctst +TESTCASES += check_stat1.ctst +TESTCASES += check_stat2.ctst +TESTCASES += check_stat3.ctst +TESTCASES += check_stat4.ctst +TESTCASES += check_openpf1.ctst +TESTCASES += check_openpf2.ctst +TESTCASES += check_openpf3.ctst +TESTCASES += check_openpf4.ctst +TESTCASES += check_openpf5.ctst +TESTCASES += check_mapbrk.ctst +TESTCASES += check_mmap1.ctst +TESTCASES += check_mmap2.ctst +TESTCASES += check_mmap3.ctst +TESTCASES += check_time1.ctst +TESTCASES += check_time2.ctst + + +TESTCASES += check_gcctorture_pr28634-1.ctst +#TESTCASES += check_gcctorture_pr28634.ctst + +all: build + +%.o: $(SRC_PATH)/tests/cris/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +%.o: $(SRC_PATH)/tests/cris/%.s + $(AS) $(ASFLAGS) -c $< -o $@ + +%.tst: %.o + $(CC) $(CFLAGS) $(NOSTDFLAGS) $(LDLIBS) $(NOSTDLIBS) $(CRT) $< $(SYS) -o $@ + +%.ctst: %.o + $(CC) $(CFLAGS) $(LDLIBS) $< -o $@ + +build: $(CRT) $(SYS) $(TESTCASES) + +check: $(CRT) $(SYS) $(TESTCASES) + @echo -e "\nQEMU simulator." + @for case in $(TESTCASES); do \ + echo -n "$$case "; \ + $(SIM) $$case; \ + done +check-g: $(CRT) $(SYS) $(TESTCASES) + @echo -e "\nGDB simulator." + @for case in $(TESTCASES); do \ + echo -n "$$case "; \ + $(SIMG) $$case; \ + done + +clean: + $(RM) -fr $(TESTCASES) $(CRT) $(SYS) diff --git a/tests/cris/README b/tests/cris/README new file mode 100644 index 000000000..93c955cbb --- /dev/null +++ b/tests/cris/README @@ -0,0 +1,2 @@ +Test-suite for the cris port. Heavily based on the test-suite for the CRIS port of sim by Hans-Peter Nilsson. + diff --git a/tests/cris/check_abs.c b/tests/cris/check_abs.c new file mode 100644 index 000000000..3966c87c7 --- /dev/null +++ b/tests/cris/check_abs.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +extern inline int cris_abs(int n) { + int r; + asm ("abs\t%1, %0\n" : "=r" (r) : "r" (n)); + return r; +} + +extern inline void +verify_abs(int val, int res, + const int n, const int z, const int v, const int c) +{ + int r; + + cris_tst_cc_init(); + r = cris_abs(val); + cris_tst_cc(n, z, v, c); + if (r != res) + err(); +} + +int main(void) +{ + verify_abs(-1, 1, 0, 0, 0, 0); + verify_abs(0x80000000, 0x80000000, 1, 0, 0, 0); + verify_abs(0x7fffffff, 0x7fffffff, 0, 0, 0, 0); + verify_abs(42, 42, 0, 0, 0, 0); + verify_abs(1, 1, 0, 0, 0, 0); + verify_abs(0xffff, 0xffff, 0, 0, 0, 0); + verify_abs(0xffff, 0xffff, 0, 0, 0, 0); + verify_abs(-31, 0x1f, 0, 0, 0, 0); + verify_abs(0, 0, 0, 1, 0, 0); + pass(); + return 0; +} diff --git a/tests/cris/check_addc.c b/tests/cris/check_addc.c new file mode 100644 index 000000000..e4078555f --- /dev/null +++ b/tests/cris/check_addc.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +extern inline int cris_addc(int a, const int b) { + asm ("addc\t%1, %0\n" : "+r" (a) : "r" (b)); + return a; +} + +#define verify_addc(a, b, res, n, z, v, c) \ +{ \ + int r; \ + r = cris_addc((a), (b)); \ + cris_tst_cc((n), (z), (v), (c)); \ + if (r != (res)) \ + err(); \ +} + +int main(void) +{ + cris_tst_cc_init(); + asm volatile ("clearf cz"); + verify_addc(0, 0, 0, 0, 0, 0, 0); + + cris_tst_cc_init(); + asm volatile ("setf z"); + verify_addc(0, 0, 0, 0, 1, 0, 0); + + cris_tst_cc_init(); + asm volatile ("setf cz"); + verify_addc(0, 0, 1, 0, 0, 0, 0); + cris_tst_cc_init(); + asm volatile ("clearf c"); + verify_addc(-1, 2, 1, 0, 0, 0, 1); + + cris_tst_cc_init(); + asm volatile ("clearf nzv"); + asm volatile ("setf c"); + verify_addc(-1, 2, 2, 0, 0, 0, 1); + + cris_tst_cc_init(); + asm volatile ("setf c"); + verify_addc(0xffff, 0xffff, 0x1ffff, 0, 0, 0, 0); + + cris_tst_cc_init(); + asm volatile ("clearf nzvc"); + verify_addc(-1, -1, 0xfffffffe, 1, 0, 0, 1); + + cris_tst_cc_init(); + asm volatile ("setf c"); + verify_addc(0x78134452, 0x5432f789, 0xcc463bdc, 1, 0, 1, 0); + + pass(); + return 0; +} diff --git a/tests/cris/check_addcm.c b/tests/cris/check_addcm.c new file mode 100644 index 000000000..9ffea29bd --- /dev/null +++ b/tests/cris/check_addcm.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +/* need to avoid acr as source here. */ +extern inline int cris_addc_m(int a, const int *b) { + asm volatile ("addc [%1], %0\n" : "+r" (a) : "r" (b)); + return a; +} + +/* 'b' is a crisv32 constrain to avoid postinc with $acr. */ +extern inline int cris_addc_pi_m(int a, int **b) { + asm volatile ("addc [%1+], %0\n" : "+r" (a), "+b" (*b)); + return a; +} + +#define verify_addc_m(a, b, res, n, z, v, c) \ +{ \ + int r; \ + r = cris_addc_m((a), (b)); \ + cris_tst_cc((n), (z), (v), (c)); \ + if (r != (res)) \ + err(); \ +} + +#define verify_addc_pi_m(a, b, res, n, z, v, c) \ +{ \ + int r; \ + r = cris_addc_pi_m((a), (b)); \ + cris_tst_cc((n), (z), (v), (c)); \ + if (r != (res)) \ + err(); \ +} + +int x[] = { 0, 0, 2, -1, 0xffff, -1, 0x5432f789}; + +int main(void) +{ + int *p = (void *)&x[0]; +#if 1 + cris_tst_cc_init(); + asm volatile ("clearf cz"); + verify_addc_m(0, p, 0, 0, 0, 0, 0); + + cris_tst_cc_init(); + asm volatile ("setf z"); + verify_addc_m(0, p, 0, 0, 1, 0, 0); + + cris_tst_cc_init(); + asm volatile ("setf c"); + verify_addc_m(0, p, 1, 0, 0, 0, 0); + + cris_tst_cc_init(); + asm volatile ("clearf c"); + verify_addc_pi_m(0, &p, 0, 0, 1, 0, 0); + + p = &x[1]; + cris_tst_cc_init(); + asm volatile ("setf c"); + verify_addc_pi_m(0, &p, 1, 0, 0, 0, 0); + + if (p != &x[2]) + err(); + + cris_tst_cc_init(); + asm volatile ("clearf c"); + verify_addc_pi_m(-1, &p, 1, 0, 0, 0, 1); + + if (p != &x[3]) + err(); +#endif + p = &x[3]; + /* TODO: investigate why this one fails. */ + cris_tst_cc_init(); + asm volatile ("setf c"); + verify_addc_m(2, p, 2, 0, 0, 0, 1); + p += 4; + + pass(); + return 0; +} diff --git a/tests/cris/check_addi.s b/tests/cris/check_addi.s new file mode 100644 index 000000000..a00dec02a --- /dev/null +++ b/tests/cris/check_addi.s @@ -0,0 +1,57 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 0\n1\n2\n4\nbe02460f\n69d035a6\nc16c14d4\n + + .include "testutils.inc" + start + moveq 0,r3 + moveq 0,r4 + clearf zcvn + addi r4.b,r3 + test_cc 0 0 0 0 + checkr3 0 + + moveq 0,r3 + moveq 1,r4 + setf zcvn + addi r4.b,r3 + test_cc 1 1 1 1 + checkr3 1 + + moveq 0,r3 + moveq 1,r4 + setf cv + clearf zn + addi r4.w,r3 + test_cc 0 0 1 1 + checkr3 2 + + moveq 0,r3 + moveq 1,r4 + clearf cv + setf zn + addi r4.d,r3 + test_cc 1 1 0 0 + checkr3 4 + + move.d 0x12345678,r3 + move.d 0xabcdef97,r4 + clearf cn + setf zv + addi r4.b,r3 + test_cc 0 1 1 0 + checkr3 be02460f + + move.d 0x12345678,r3 + move.d 0xabcdef97,r4 + setf cn + clearf zv + addi r4.w,r3 + test_cc 1 0 0 1 + checkr3 69d035a6 + + move.d 0x12345678,r3 + move.d 0xabcdef97,r4 + addi r4.d,r3 + checkr3 c16c14d4 + + quit diff --git a/tests/cris/check_addiv32.s b/tests/cris/check_addiv32.s new file mode 100644 index 000000000..20ba25d21 --- /dev/null +++ b/tests/cris/check_addiv32.s @@ -0,0 +1,62 @@ +# mach: crisv32 +# output: 4455aa77\n4455aa77\nee19ccff\nff22\n4455aa77\nff224455\n55aa77ff\n + + .include "testutils.inc" + .data +x: + .dword 0x55aa77ff + .dword 0xccff2244 + .dword 0x88ccee19 + + start + setf cv + moveq -1,r0 + move.d x-32768,r5 + move.d 32769,r6 + addi r6.b,r5,acr + test_cc 0 0 1 1 + move.d [acr],r3 + checkr3 4455aa77 + + addu.w 32771,r5 + setf znvc + moveq -1,r8 + addi r8.w,r5,acr + test_cc 1 1 1 1 + move.d [acr],r3 + checkr3 4455aa77 + + moveq 5,r10 + clearf znvc + addi r10.b,acr,acr + test_cc 0 0 0 0 + move.d [acr],r3 + checkr3 ee19ccff + + subq 1,r5 + move.d r5,r8 + subq 1,r8 + moveq 1,r9 + addi r9.d,r8,acr + test_cc 0 0 0 0 + movu.w [acr],r3 + checkr3 ff22 + + moveq -2,r11 + addi r11.w,acr,acr + move.d [acr],r3 + checkr3 4455aa77 + + moveq 5,r9 + addi r9.d,acr,acr + subq 18,acr + move.d [acr],r3 + checkr3 ff224455 + + move.d -76789888/4,r12 + addi r12.d,r5,acr + add.d 76789886,acr + move.d [acr],r3 + checkr3 55aa77ff + + quit diff --git a/tests/cris/check_addm.s b/tests/cris/check_addm.s new file mode 100644 index 000000000..efece9f53 --- /dev/null +++ b/tests/cris/check_addm.s @@ -0,0 +1,96 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n781344d0\n + + .include "testutils.inc" + .data +x: + .dword 2,-1,0xffff,-1,0x5432f789 + .word 2,-1,0xffff,0xf789 + .byte 2,0xff,0x89 + .byte 0x7e + + start + moveq -1,r3 + move.d x,r5 + add.d [r5+],r3 + test_cc 0 0 0 1 + checkr3 1 + + moveq 2,r3 + add.d [r5],r3 + test_cc 0 0 0 1 + addq 4,r5 + checkr3 1 + + move.d 0xffff,r3 + add.d [r5+],r3 + test_cc 0 0 0 0 + checkr3 1fffe + + moveq -1,r3 + add.d [r5+],r3 + test_cc 1 0 0 1 + checkr3 fffffffe + + move.d 0x78134452,r3 + add.d [r5+],r3 + test_cc 1 0 1 0 + checkr3 cc463bdb + + moveq -1,r3 + add.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 ffff0001 + + moveq 2,r3 + add.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 1 + + move.d 0xffff,r3 + add.w [r5],r3 + test_cc 1 0 0 1 + checkr3 fffe + + move.d 0xfedaffff,r3 + add.w [r5+],r3 + test_cc 1 0 0 1 + checkr3 fedafffe + + move.d 0x78134452,r3 + add.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 78133bdb + + moveq -1,r3 + add.b [r5],r3 + test_cc 0 0 0 1 + addq 1,r5 + checkr3 ffffff01 + + moveq 2,r3 + add.b [r5],r3 + test_cc 0 0 0 1 + checkr3 1 + + move.d 0xff,r3 + add.b [r5],r3 + test_cc 1 0 0 1 + checkr3 fe + + move.d 0xfeda49ff,r3 + add.b [r5+],r3 + test_cc 1 0 0 1 + checkr3 feda49fe + + move.d 0x78134452,r3 + add.b [r5+],r3 + test_cc 1 0 0 0 + checkr3 781344db + + move.d 0x78134452,r3 + add.b [r5],r3 + test_cc 1 0 1 0 + checkr3 781344d0 + + quit diff --git a/tests/cris/check_addo.c b/tests/cris/check_addo.c new file mode 100644 index 000000000..8a0565a1a --- /dev/null +++ b/tests/cris/check_addo.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +/* this would be better to do in asm, it's an orgy in GCC inline asm now. */ + +#define cris_addo_b(o, v) \ + asm volatile ("addo.b\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr"); +#define cris_addo_w(o, v) \ + asm volatile ("addo.w\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr"); +#define cris_addo_d(o, v) \ + asm volatile ("addo.d\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr"); +#define cris_addo_pi_b(o, v) \ + asm volatile ("addo.b\t[%0+], %1, $acr\n" \ + : "+b" (o): "r" (v) : "acr"); +#define cris_addo_pi_w(o, v) \ + asm volatile ("addo.w\t[%0+], %1, $acr\n" \ + : "+b" (o): "r" (v) : "acr"); +#define cris_addo_pi_d(o, v) \ + asm volatile ("addo.d\t[%0+], %1, $acr\n" \ + : "+b" (o): "r" (v) : "acr"); + +struct { + uint32_t v1; + uint16_t v2; + uint32_t v3; + uint8_t v4; + uint8_t v5; + uint16_t v6; + uint32_t v7; +} y = { + 32769, + -1, + 5, + 3, -4, + 2, + -76789887 +}; + +static int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19}; + +int main(void) +{ + int *r; + unsigned char *t, *p; + + /* Note, this test-case will trig an unaligned access, partly + to x[0] and to [x1]. */ + t = (unsigned char *)x; + t -= 32768; + p = (unsigned char *) &y.v1; + mb(); /* dont reorder anything beyond here. */ + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addo_pi_d(p, t); + cris_tst_cc(1, 1, 1, 1); + asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); + if (*r != 0x4455aa77) + err(); + + + t += 32770; + mb(); /* dont reorder anything beyond here. */ + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addo_pi_w(p, t); + cris_tst_cc(1, 1, 1, 1); + asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); + if (*r != 0x4455aa77) + err(); + + mb(); /* dont reorder anything beyond here. */ + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addo_d(p, r); + cris_tst_cc(1, 1, 1, 1); + p += 4; + asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); + if (*r != 0xee19ccff) + err(); + + mb(); /* dont reorder anything beyond here. */ + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addo_pi_b(p, t); + cris_tst_cc(1, 1, 1, 1); + asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); + if (*(uint16_t*)r != 0xff22) + err(); + + mb(); /* dont reorder anything beyond here. */ + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addo_b(p, r); + cris_tst_cc(1, 1, 1, 1); + p += 1; + asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); + if (*r != 0x4455aa77) + err(); + + mb(); /* dont reorder anything beyond here. */ + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addo_w(p, r); + cris_tst_cc(1, 1, 1, 1); + p += 2; + asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); + if (*r != 0xff224455) + err(); + + mb(); /* dont reorder anything beyond here. */ + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addo_pi_d(p, t); + cris_tst_cc(1, 1, 1, 1); + asm volatile ("move.d\t$acr, %0\n" : "=r" (r)); + r = (void*)(((char *)r) + 76789885); + if (*r != 0x55aa77ff) + err(); + + pass(); + return 0; +} diff --git a/tests/cris/check_addoq.c b/tests/cris/check_addoq.c new file mode 100644 index 000000000..b8b15c309 --- /dev/null +++ b/tests/cris/check_addoq.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +/* this would be better to do in asm, it's an orgy in GCC inline asm now. */ + +/* ACR will be clobbered. */ +#define cris_addoq(o, v) \ + asm volatile ("addoq\t%1, %0, $acr\n" : : "r" (v), "i" (o) : "acr"); + + +int main(void) +{ + int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19}; + int *p, *t = x + 1; + + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addoq(0, t); + cris_tst_cc(1, 1, 1, 1); + asm volatile ("move.d\t$acr, %0\n" : "=r" (p)); + if (*p != 0xccff2244) + err(); + + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_addoq(4, t); + cris_tst_cc(1, 1, 1, 1); + asm volatile ("move.d\t$acr, %0\n" : "=r" (p)); + if (*p != 0x88ccee19) + err(); + + cris_tst_cc_init(); + asm volatile ("clearf\tzvnc\n"); + cris_addoq(-8, t + 1); + cris_tst_cc(0, 0, 0, 0); + asm volatile ("move.d\t$acr, %0\n" : "=r" (p)); + if (*p != 0x55aa77ff) + err(); + pass(); + return 0; +} diff --git a/tests/cris/check_addq.s b/tests/cris/check_addq.s new file mode 100644 index 000000000..e6f874f9b --- /dev/null +++ b/tests/cris/check_addq.s @@ -0,0 +1,47 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: ffffffff\n0\n1\n100\n10000\n47\n67\na6\n80000001\n + + .include "testutils.inc" + start + moveq -2,r3 + addq 1,r3 + test_cc 1 0 0 0 + checkr3 ffffffff + + addq 1,r3 + test_cc 0 1 0 1 + checkr3 0 + + addq 1,r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d 0xff,r3 + addq 1,r3 + test_cc 0 0 0 0 + checkr3 100 + + move.d 0xffff,r3 + addq 1,r3 + test_cc 0 0 0 0 + checkr3 10000 + + move.d 0x42,r3 + addq 5,r3 + test_cc 0 0 0 0 + checkr3 47 + + addq 32,r3 + test_cc 0 0 0 0 + checkr3 67 + + addq 63,r3 + test_cc 0 0 0 0 + checkr3 a6 + + move.d 0x7ffffffe,r3 + addq 3,r3 + test_cc 1 0 1 0 + checkr3 80000001 + + quit diff --git a/tests/cris/check_addr.s b/tests/cris/check_addr.s new file mode 100644 index 000000000..7f55cdc1b --- /dev/null +++ b/tests/cris/check_addr.s @@ -0,0 +1,96 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq 2,r4 + add.d r4,r3 + test_cc 0 0 0 1 + checkr3 1 + + moveq 2,r3 + moveq -1,r4 + add.d r4,r3 + test_cc 0 0 0 1 + checkr3 1 + + move.d 0xffff,r4 + move.d r4,r3 + add.d r4,r3 + test_cc 0 0 0 0 + checkr3 1fffe + + moveq -1,r4 + move.d r4,r3 + add.d r4,r3 + test_cc 1 0 0 1 + checkr3 fffffffe + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + add.d r4,r3 + test_cc 1 0 1 0 + checkr3 cc463bdb + + moveq -1,r3 + moveq 2,r4 + add.w r4,r3 + test_cc 0 0 0 1 + checkr3 ffff0001 + + moveq 2,r3 + moveq -1,r4 + add.w r4,r3 + test_cc 0 0 0 1 + checkr3 1 + + move.d 0xffff,r4 + move.d r4,r3 + add.w r4,r3 + test_cc 1 0 0 1 + checkr3 fffe + + move.d 0xfedaffff,r4 + move.d r4,r3 + add.w r4,r3 + test_cc 1 0 0 1 + checkr3 fedafffe + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + add.w r4,r3 + test_cc 0 0 0 1 + checkr3 78133bdb + + moveq -1,r3 + moveq 2,r4 + add.b r4,r3 + test_cc 0 0 0 1 + checkr3 ffffff01 + + moveq 2,r3 + moveq -1,r4 + add.b r4,r3 + test_cc 0 0 0 1 + checkr3 1 + + move.d 0xff,r4 + move.d r4,r3 + add.b r4,r3 + test_cc 1 0 0 1 + checkr3 fe + + move.d 0xfeda49ff,r4 + move.d r4,r3 + add.b r4,r3 + test_cc 1 0 0 1 + checkr3 feda49fe + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + add.b r4,r3 + test_cc 1 0 0 0 + checkr3 781344db + + quit diff --git a/tests/cris/check_addxc.s b/tests/cris/check_addxc.s new file mode 100644 index 000000000..09c8355bf --- /dev/null +++ b/tests/cris/check_addxc.s @@ -0,0 +1,91 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n + + .include "testutils.inc" + start + moveq 2,r3 + adds.b 0xff,r3 + test_cc 0 0 0 1 + checkr3 1 + + moveq 2,r3 + adds.w 0xffff,r3 + test_cc 0 0 0 1 + checkr3 1 + + moveq 2,r3 + addu.b 0xff,r3 + checkr3 101 + + moveq 2,r3 + move.d 0xffffffff,r4 + addu.w -1,r3 + test_cc 0 0 0 0 + checkr3 10001 + + move.d 0xffff,r3 + addu.b -1,r3 + test_cc 0 0 0 0 + checkr3 100fe + + move.d 0xffff,r3 + addu.w -1,r3 + test_cc 0 0 0 0 + checkr3 1fffe + + move.d 0xffff,r3 + adds.b 0xff,r3 + test_cc 0 0 0 1 + checkr3 fffe + + move.d 0xffff,r3 + adds.w 0xffff,r3 + test_cc 0 0 0 1 + checkr3 fffe + + moveq -1,r3 + adds.b 0xff,r3 + test_cc 1 0 0 1 + checkr3 fffffffe + + moveq -1,r3 + adds.w 0xff,r3 + test_cc 0 0 0 1 + checkr3 fe + + moveq -1,r3 + adds.w 0xffff,r3 + test_cc 1 0 0 1 + checkr3 fffffffe + + move.d 0x78134452,r3 + addu.b 0x89,r3 + test_cc 0 0 0 0 + checkr3 781344db + + move.d 0x78134452,r3 + adds.b 0x89,r3 + test_cc 0 0 0 1 + checkr3 781343db + + move.d 0x78134452,r3 + addu.w 0xf789,r3 + test_cc 0 0 0 0 + checkr3 78143bdb + + move.d 0x78134452,r3 + adds.w 0xf789,r3 + test_cc 0 0 0 1 + checkr3 78133bdb + + move.d 0x7fffffee,r3 + addu.b 0xff,r3 + test_cc 1 0 1 0 + checkr3 800000ed + + move.d 0x1,r3 + adds.w 0xffff,r3 + test_cc 0 1 0 1 + checkr3 0 + + quit diff --git a/tests/cris/check_addxm.s b/tests/cris/check_addxm.s new file mode 100644 index 000000000..7563494b9 --- /dev/null +++ b/tests/cris/check_addxm.s @@ -0,0 +1,106 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n + + .include "testutils.inc" + .data +x: + .byte 0xff + .word 0xffff + .word 0xff + .word 0xffff + .byte 0x89 + .word 0xf789 + .byte 0xff + .word 0xffff + + start + moveq 2,r3 + move.d x,r5 + adds.b [r5+],r3 + test_cc 0 0 0 1 + checkr3 1 + + moveq 2,r3 + adds.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 1 + + moveq 2,r3 + subq 3,r5 + addu.b [r5+],r3 + test_cc 0 0 0 0 + checkr3 101 + + moveq 2,r3 + addu.w [r5+],r3 + subq 3,r5 + test_cc 0 0 0 0 + checkr3 10001 + + move.d 0xffff,r3 + addu.b [r5],r3 + test_cc 0 0 0 0 + checkr3 100fe + + move.d 0xffff,r3 + addu.w [r5],r3 + test_cc 0 0 0 0 + checkr3 1fffe + + move.d 0xffff,r3 + adds.b [r5],r3 + test_cc 0 0 0 1 + checkr3 fffe + + move.d 0xffff,r3 + adds.w [r5],r3 + test_cc 0 0 0 1 + checkr3 fffe + + moveq -1,r3 + adds.b [r5],r3 + test_cc 1 0 0 1 + addq 3,r5 + checkr3 fffffffe + + moveq -1,r3 + adds.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 fe + + moveq -1,r3 + adds.w [r5+],r3 + test_cc 1 0 0 1 + checkr3 fffffffe + + move.d 0x78134452,r3 + addu.b [r5],r3 + test_cc 0 0 0 0 + checkr3 781344db + + move.d 0x78134452,r3 + adds.b [r5+],r3 + test_cc 0 0 0 1 + checkr3 781343db + + move.d 0x78134452,r3 + addu.w [r5],r3 + test_cc 0 0 0 0 + checkr3 78143bdb + + move.d 0x78134452,r3 + adds.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 78133bdb + + move.d 0x7fffffee,r3 + addu.b [r5+],r3 + test_cc 1 0 1 0 + checkr3 800000ed + + move.d 0x1,r3 + adds.w [r5+],r3 + test_cc 0 1 0 1 + checkr3 0 + + quit diff --git a/tests/cris/check_addxr.s b/tests/cris/check_addxr.s new file mode 100644 index 000000000..7f55cdc1b --- /dev/null +++ b/tests/cris/check_addxr.s @@ -0,0 +1,96 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq 2,r4 + add.d r4,r3 + test_cc 0 0 0 1 + checkr3 1 + + moveq 2,r3 + moveq -1,r4 + add.d r4,r3 + test_cc 0 0 0 1 + checkr3 1 + + move.d 0xffff,r4 + move.d r4,r3 + add.d r4,r3 + test_cc 0 0 0 0 + checkr3 1fffe + + moveq -1,r4 + move.d r4,r3 + add.d r4,r3 + test_cc 1 0 0 1 + checkr3 fffffffe + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + add.d r4,r3 + test_cc 1 0 1 0 + checkr3 cc463bdb + + moveq -1,r3 + moveq 2,r4 + add.w r4,r3 + test_cc 0 0 0 1 + checkr3 ffff0001 + + moveq 2,r3 + moveq -1,r4 + add.w r4,r3 + test_cc 0 0 0 1 + checkr3 1 + + move.d 0xffff,r4 + move.d r4,r3 + add.w r4,r3 + test_cc 1 0 0 1 + checkr3 fffe + + move.d 0xfedaffff,r4 + move.d r4,r3 + add.w r4,r3 + test_cc 1 0 0 1 + checkr3 fedafffe + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + add.w r4,r3 + test_cc 0 0 0 1 + checkr3 78133bdb + + moveq -1,r3 + moveq 2,r4 + add.b r4,r3 + test_cc 0 0 0 1 + checkr3 ffffff01 + + moveq 2,r3 + moveq -1,r4 + add.b r4,r3 + test_cc 0 0 0 1 + checkr3 1 + + move.d 0xff,r4 + move.d r4,r3 + add.b r4,r3 + test_cc 1 0 0 1 + checkr3 fe + + move.d 0xfeda49ff,r4 + move.d r4,r3 + add.b r4,r3 + test_cc 1 0 0 1 + checkr3 feda49fe + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + add.b r4,r3 + test_cc 1 0 0 0 + checkr3 781344db + + quit diff --git a/tests/cris/check_andc.s b/tests/cris/check_andc.s new file mode 100644 index 000000000..a947b773c --- /dev/null +++ b/tests/cris/check_andc.s @@ -0,0 +1,80 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n + + .include "testutils.inc" + start + moveq -1,r3 + and.d 2,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + and.d -1,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + and.d 0xffff,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r3 + and.d -1,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x78134452,r3 + and.d 0x5432f789,r3 + test_move_cc 0 0 0 0 + checkr3 50124400 + + moveq -1,r3 + and.w 2,r3 + test_move_cc 0 0 0 0 + checkr3 ffff0002 + + moveq 2,r3 + and.w -1,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xfffff,r3 + and.w 0xffff,r3 + test_move_cc 1 0 0 0 + checkr3 fffff + + move.d 0xfedaffaf,r3 + and.w 0xff5f,r3 + test_move_cc 1 0 0 0 + checkr3 fedaff0f + + move.d 0x78134452,r3 + and.w 0xf789,r3 + test_move_cc 0 0 0 0 + checkr3 78134400 + + moveq -1,r3 + and.b 2,r3 + test_move_cc 0 0 0 0 + checkr3 ffffff02 + + moveq 2,r3 + and.b -1,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xfa7,r3 + and.b 0x5a,r3 + test_move_cc 0 0 0 0 + checkr3 f02 + + move.d 0x78134453,r3 + and.b 0x89,r3 + test_move_cc 0 0 0 0 + checkr3 78134401 + + and.b 0,r3 + test_move_cc 0 1 0 0 + checkr3 78134400 + + quit diff --git a/tests/cris/check_andm.s b/tests/cris/check_andm.s new file mode 100644 index 000000000..93858863f --- /dev/null +++ b/tests/cris/check_andm.s @@ -0,0 +1,90 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n + + .include "testutils.inc" + .data +x: + .dword 2,-1,0xffff,-1,0x5432f789 + .word 2,-1,0xffff,0xff5f,0xf789 + .byte 2,-1,0x5a,0x89,0 + + start + moveq -1,r3 + move.d x,r5 + and.d [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + and.d [r5],r3 + test_move_cc 0 0 0 0 + addq 4,r5 + checkr3 2 + + move.d 0xffff,r3 + and.d [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r3 + and.d [r5+],r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x78134452,r3 + and.d [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 50124400 + + moveq -1,r3 + and.w [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 ffff0002 + + moveq 2,r3 + and.w [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xfffff,r3 + and.w [r5],r3 + test_move_cc 1 0 0 0 + addq 2,r5 + checkr3 fffff + + move.d 0xfedaffaf,r3 + and.w [r5+],r3 + test_move_cc 1 0 0 0 + checkr3 fedaff0f + + move.d 0x78134452,r3 + and.w [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 78134400 + + moveq -1,r3 + and.b [r5],r3 + test_move_cc 0 0 0 0 + addq 1,r5 + checkr3 ffffff02 + + moveq 2,r3 + and.b [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xfa7,r3 + and.b [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 f02 + + move.d 0x78134453,r3 + and.b [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 78134401 + + and.b [r5],r3 + test_move_cc 0 1 0 0 + checkr3 78134400 + + quit diff --git a/tests/cris/check_andq.s b/tests/cris/check_andq.s new file mode 100644 index 000000000..55aa7b060 --- /dev/null +++ b/tests/cris/check_andq.s @@ -0,0 +1,46 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 2\n2\nffff\nffffffff\n1f\nffffffe0\n78134452\n0\n + + .include "testutils.inc" + start + moveq -1,r3 + andq 2,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + andq -1,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + andq -1,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r3 + andq -1,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + andq 31,r3 + test_move_cc 0 0 0 0 + checkr3 1f + + moveq -1,r3 + andq -32,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffe0 + + move.d 0x78134457,r3 + andq -14,r3 + test_move_cc 0 0 0 0 + checkr3 78134452 + + moveq 0,r3 + andq -14,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_andr.s b/tests/cris/check_andr.s new file mode 100644 index 000000000..61aa1dc32 --- /dev/null +++ b/tests/cris/check_andr.s @@ -0,0 +1,95 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq 2,r4 + and.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + moveq -1,r4 + and.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r4 + move.d r4,r3 + and.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r4 + move.d r4,r3 + and.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + and.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 50124400 + + moveq -1,r3 + moveq 2,r4 + and.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff0002 + + moveq 2,r3 + moveq -1,r4 + and.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xfffff,r3 + move.d 0xffff,r4 + and.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 fffff + + move.d 0xfedaffaf,r3 + move.d 0xff5f,r4 + and.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 fedaff0f + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + and.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 78134400 + + moveq -1,r3 + moveq 2,r4 + and.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffffff02 + + moveq 2,r3 + moveq -1,r4 + and.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0x5a,r4 + move.d 0xfa7,r3 + and.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 f02 + + move.d 0x5432f789,r4 + move.d 0x78134453,r3 + and.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 78134401 + + moveq 0,r7 + and.b r7,r3 + test_move_cc 0 1 0 0 + checkr3 78134400 + + quit diff --git a/tests/cris/check_asr.s b/tests/cris/check_asr.s new file mode 100644 index 000000000..0a02ae6f7 --- /dev/null +++ b/tests/cris/check_asr.s @@ -0,0 +1,230 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: ffffffff\n1\nffffffff\nffffffff\n5a67f\nffffffff\nffffffff\nffffffff\nf699fc67\nffffffff\n1\nffffffff\nffffffff\n5a67f\nda67ffff\nda67ffff\nda67ffff\nda67fc67\nffffffff\nffffffff\n1\nffffffff\nffffffff\n5a670007\nda67f1ff\nda67f1ff\nda67f1ff\nda67f1e7\nffffffff\nffffffff\n1\nffffffff\nffffffff\nffffffff\n5a67f1ff\n5a67f1f9\n0\n5a670000\n + + .include "testutils.inc" + start + moveq -1,r3 + asrq 0,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + asrq 1,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + asrq 31,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + asrq 15,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x5a67f19f,r3 + asrq 12,r3 + test_move_cc 0 0 0 0 + checkr3 5a67f + + move.d 0xda67f19f,r3 + move.d 31,r4 + asr.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0xda67f19f,r3 + move.d 32,r4 + asr.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0xda67f19f,r3 + move.d 33,r4 + asr.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0xda67f19f,r3 + move.d 66,r4 + asr.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 f699fc67 + + moveq -1,r3 + moveq 0,r4 + asr.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + moveq 1,r4 + asr.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + moveq 31,r4 + asr.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + moveq 15,r4 + asr.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x5a67f19f,r3 + moveq 12,r4 + asr.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 5a67f + + move.d 0xda67f19f,r3 + move.d 31,r4 + asr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67ffff + + move.d 0xda67f19f,r3 + move.d 32,r4 + asr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67ffff + + move.d 0xda67f19f,r3 + move.d 33,r4 + asr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67ffff + + move.d 0xda67f19f,r3 + move.d 66,r4 + asr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67fc67 + + moveq -1,r3 + moveq 0,r4 + asr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + moveq 1,r4 + asr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + moveq 1,r4 + asr.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + moveq 31,r4 + asr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + moveq 15,r4 + asr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x5a67719f,r3 + moveq 12,r4 + asr.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 5a670007 + + move.d 0xda67f19f,r3 + move.d 31,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67f1ff + + move.d 0xda67f19f,r3 + move.d 32,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67f1ff + + move.d 0xda67f19f,r3 + move.d 33,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67f1ff + + move.d 0xda67f19f,r3 + move.d 66,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67f1e7 + + moveq -1,r3 + moveq 0,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + moveq 1,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + moveq 1,r4 + asr.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + moveq 31,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + moveq 15,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + moveq 7,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + +; FIXME: was wrong. + move.d 0x5a67f19f,r3 + moveq 12,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 5a67f1ff + +; FIXME: was wrong. + move.d 0x5a67f19f,r3 + moveq 4,r4 + asr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 5a67f1f9 + + move.d 0x5a67f19f,r3 + asrq 31,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0x5a67419f,r3 + moveq 16,r4 + asr.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 5a670000 + + quit diff --git a/tests/cris/check_ba.s b/tests/cris/check_ba.s new file mode 100644 index 000000000..873a4086c --- /dev/null +++ b/tests/cris/check_ba.s @@ -0,0 +1,93 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: a\n + + + .set smalloffset,0 + .set largeoffset,0 + + + .macro fail + jump _fail + .endm + + .global main +main: + moveq 0,$r3 + +; Short forward branch. + ba 0f + addq 1,$r3 + fail + +; Max short forward branch. +1: + ba 2f + addq 1,$r3 + fail + +; Short backward branch. +0: + ba 1b + addq 1,$r3 + fail + + .space 254-2+smalloffset+1b-.,0 + moveq 0,$r3 + +2: +; Transit branch (long). + ba 3f + addq 1,$r3 + fail + + moveq 0,$r3 +4: +; Long forward branch. + ba 5f + addq 1,$r3 + fail + + .space 256-2-smalloffset+4b-.,0 + + moveq 0,$r3 + +; Max short backward branch. +3: + ba 4b + addq 1,$r3 + fail + +5: +; Max long forward branch. + ba 6f + addq 1,$r3 + fail + + .space 32766+largeoffset-2+5b-.,0 + + moveq 0,$r3 +6: +; Transit branch. + ba 7f + addq 1,$r3 + fail + + moveq 0,$r3 +9: + jsr pass + nop + +; Transit branch. + moveq 0,$r3 +7: + ba 8f + addq 1,$r3 + fail + + .space 32768-largeoffset+9b-.,0 + +8: +; Max long backward branch. + ba 9b + addq 1,$r3 + fail diff --git a/tests/cris/check_bas.s b/tests/cris/check_bas.s new file mode 100644 index 000000000..11929d420 --- /dev/null +++ b/tests/cris/check_bas.s @@ -0,0 +1,102 @@ +# mach: crisv32 +# output: 0\n0\n0\nfb349abc\n0\n12124243\n0\n0\neab5baad\n0\nefb37832\n + + .include "testutils.inc" + start +x: + setf zncv + bsr 0f + nop +0: + test_cc 1 1 1 1 + move srp,r3 + sub.d 0b,r3 + checkr3 0 + + bas 1f,mof + moveq 0,r0 +6: + nop + quit + +2: + move srp,r3 + sub.d 3f,r3 + checkr3 0 + move srp,r4 + subq 4,r4 + move.d [r4],r3 + checkr3 fb349abc + + basc 4f,mof + nop + .dword 0x12124243 +7: + nop + quit + +8: + move mof,r3 + sub.d 7f,r3 + checkr3 0 + + move mof,r4 + subq 4,r4 + move.d [r4],r3 + checkr3 eab5baad + + jasc 9f,mof + nop + .dword 0xefb37832 +0: + quit + + quit +9: + move mof,r3 + sub.d 0b,r3 + checkr3 0 + + move mof,r4 + subq 4,r4 + move.d [r4],r3 + checkr3 efb37832 + + quit + +4: + move mof,r3 + sub.d 7b,r3 + checkr3 0 + move mof,r4 + subq 4,r4 + move.d [r4],r3 + checkr3 12124243 + basc 5f,bz + moveq 0,r3 + .dword 0x7634aeba + quit + + .space 32770,0 +1: + move mof,r3 + sub.d 6b,r3 + checkr3 0 + + bsrc 2b + nop + .dword 0xfb349abc +3: + + quit + +5: + move mof,r3 + sub.d 7b,r3 + checkr3 0 + move.d 8b,r6 + jasc r6,mof + nop + .dword 0xeab5baad +7: + quit diff --git a/tests/cris/check_bcc.s b/tests/cris/check_bcc.s new file mode 100644 index 000000000..c57ffa6fa --- /dev/null +++ b/tests/cris/check_bcc.s @@ -0,0 +1,197 @@ + .global main + .type main, @function +main: + clearf nzvc + setf nzv + bcc 0f + addq 1, $r3 + jump dofail + +0: + clearf nzvc + setf nzv + bcs dofail + addq 1,$r3 + + clearf nzvc + setf ncv + bne 1f + addq 1, $r3 + +fail: +dofail: + jump _fail + +1: + clearf nzvc + setf ncv + beq dofail + addq 1,$r3 + + clearf nzvc + setf ncz + bvc 2f + addq 1,$r3 + jump dofail + +2: + clearf nzvc + setf ncz + bvs dofail + addq 1,$r3 + + clearf nzvc + setf vcz + bpl 3f + addq 1,$r3 + jump fail +3: + clearf nzvc + setf vcz + bmi dofail + addq 1,$r3 + + clearf nzvc + setf nv + bls dofail + addq 1,$r3 + + clearf nzvc + setf nv + bhi 4f + addq 1,$r3 + jump dofail + +4: + clearf nzvc + setf zc + bge 5f + addq 1,$r3 + jump dofail + +5: + clearf nzvc + setf zc + blt dofail + addq 1,$r3 + + clearf nzvc + setf c + bgt 6f + addq 1,$r3 + jump fail + +6: + clearf nzvc + setf c + ble dofail + addq 1,$r3 + +;;;;;;;;;; + + setf nzvc + clearf nzv + bcc dofail + addq 1,$r3 + + setf nzvc + clearf nzv + bcs 0f + addq 1,$r3 + jump fail + +0: + setf nzvc + clearf ncv + bne dofail + addq 1,$r3 + + setf nzvc + clearf ncv + beq 1f + addq 1,$r3 + jump fail + +1: + setf nzvc + clearf ncz + bvc dofail + addq 1,$r3 + + setf nzvc + clearf ncz + bvs 2f + addq 1,$r3 + jump fail + +2: + setf nzvc + clearf vcz + bpl dofail + addq 1,$r3 + + setf nzvc + clearf vcz + bmi 3f + addq 1,$r3 + jump fail + +3: + setf nzvc + clearf nv + bls 4f + addq 1,$r3 + jump fail + +4: + setf nzvc + clearf nv + bhi dofail + addq 1,$r3 + + setf zvc + clearf nzc + bge dofail + addq 1,$r3 + + setf nzc + clearf vzc + blt 5f + addq 1,$r3 + jump fail + +5: + setf nzvc + clearf c + bgt dofail + addq 1,$r3 + + setf nzvc + clearf c + ble 6f + addq 1,$r3 + jump fail + +6: + ; do a forward branch. + ba 2f + nop + .fill 100 +1: + ba 3f + nop + .fill 800 +2: + ba 1b + nop + .fill 1024 +3: + + moveq 31, $r0 +1: bne 1b + subq 1, $r0 + + jsr pass + moveq 0, $r10 + ret + nop diff --git a/tests/cris/check_bound.c b/tests/cris/check_bound.c new file mode 100644 index 000000000..411d2ad56 --- /dev/null +++ b/tests/cris/check_bound.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +extern inline int cris_bound_b(int v, int b) { + int r = v; + asm ("bound.b\t%1, %0\n" : "+r" (r) : "ri" (b)); + return r; +} + +extern inline int cris_bound_w(int v, int b) { + int r = v; + asm ("bound.w\t%1, %0\n" : "+r" (r) : "ri" (b)); + return r; +} + +extern inline int cris_bound_d(int v, int b) { + int r = v; + asm ("bound.d\t%1, %0\n" : "+r" (r) : "ri" (b)); + return r; +} + +int main(void) +{ + int r; + + cris_tst_cc_init(); + r = cris_bound_d(-1, 2); + cris_tst_cc(0, 0, 0, 0); + if (r != 2) + err(); + + cris_tst_cc_init(); + r = cris_bound_d(2, 0xffffffff); + cris_tst_cc(0, 0, 0, 0); + if (r != 2) + err(); + + cris_tst_cc_init(); + r = cris_bound_d(0xffff, 0xffff); + cris_tst_cc(0, 0, 0, 0); + if (r != 0xffff) + err(); + + cris_tst_cc_init(); + r = cris_bound_d(-1, 0xffffffff); + cris_tst_cc(1, 0, 0, 0); + if (r != 0xffffffff) + err(); + + cris_tst_cc_init(); + r = cris_bound_d(0x78134452, 0x5432f789); + cris_tst_cc(0, 0, 0, 0); + if (r != 0x5432f789) + err(); + + cris_tst_cc_init(); + r = cris_bound_w(-1, 2); + cris_tst_cc(0, 0, 0, 0); + if (r != 2) + err(); + + cris_tst_cc_init(); + r = cris_bound_w(-1, 0xffff); + cris_tst_cc(0, 0, 0, 0); + if (r != 0xffff) + err(); + + cris_tst_cc_init(); + r = cris_bound_w(2, 0xffff); + cris_tst_cc(0, 0, 0, 0); + if (r != 2) + err(); + + cris_tst_cc_init(); + r = cris_bound_w(0xfedaffff, 0xffff); + cris_tst_cc(0, 0, 0, 0); + if (r != 0xffff) + err(); + + cris_tst_cc_init(); + r = cris_bound_w(0x78134452, 0xf789); + cris_tst_cc(0, 0, 0, 0); + if (r != 0xf789) + err(); + + cris_tst_cc_init(); + r = cris_bound_b(-1, 2); + cris_tst_cc(0, 0, 0, 0); + if (r != 2) + err(); + + cris_tst_cc_init(); + r = cris_bound_b(2, 0xff); + cris_tst_cc(0, 0, 0, 0); + if (r != 2) + err(); + + cris_tst_cc_init(); + r = cris_bound_b(-1, 0xff); + cris_tst_cc(0, 0, 0, 0); + if (r != 0xff) + err(); + + cris_tst_cc_init(); + r = cris_bound_b(0xff, 0xff); + cris_tst_cc(0, 0, 0, 0); + if (r != 0xff) + err(); + + cris_tst_cc_init(); + r = cris_bound_b(0xfeda49ff, 0xff); + cris_tst_cc(0, 0, 0, 0); + if (r != 0xff) + err(); + + cris_tst_cc_init(); + r = cris_bound_b(0x78134452, 0x89); + cris_tst_cc(0, 0, 0, 0); + if (r != 0x89) + err(); + + cris_tst_cc_init(); + r = cris_bound_w(0x78134452, 0); + cris_tst_cc(0, 1, 0, 0); + if (r != 0) + err(); + + cris_tst_cc_init(); + r = cris_bound_b(0xffff, -1); + cris_tst_cc(0, 0, 0, 0); + if (r != 0xff) + err(); + + pass(); + return 0; +} diff --git a/tests/cris/check_boundc.s b/tests/cris/check_boundc.s new file mode 100644 index 000000000..fb9e5bc90 --- /dev/null +++ b/tests/cris/check_boundc.s @@ -0,0 +1,101 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 2\n2\nffff\nffffffff\n5432f789\n2\nffff\n2\nffff\nffff\nf789\n2\n2\nff\nff\nff\n89\n0\nff\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq 2,r4 + bound.d 2,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + bound.d 0xffffffff,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + bound.d 0xffff,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r3 + bound.d 0xffffffff,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x78134452,r3 + bound.d 0x5432f789,r3 + test_move_cc 0 0 0 0 + checkr3 5432f789 + + moveq -1,r3 + bound.w 2,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq -1,r3 + bound.w 0xffff,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq 2,r3 + bound.w 0xffff,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + bound.w 0xffff,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + move.d 0xfedaffff,r3 + bound.w 0xffff,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + move.d 0x78134452,r3 + bound.w 0xf789,r3 + test_move_cc 0 0 0 0 + checkr3 f789 + + moveq -1,r3 + bound.b 2,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + bound.b 0xff,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq -1,r3 + bound.b 0xff,r3 + test_move_cc 0 0 0 0 + checkr3 ff + + move.d 0xff,r3 + bound.b 0xff,r3 + test_move_cc 0 0 0 0 + checkr3 ff + + move.d 0xfeda49ff,r3 + bound.b 0xff,r3 + test_move_cc 0 0 0 0 + checkr3 ff + + move.d 0x78134452,r3 + bound.b 0x89,r3 + test_move_cc 0 0 0 0 + checkr3 89 + + bound.w 0,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0xffff,r3 + bound.b -1,r3 + test_move_cc 0 0 0 0 + checkr3 ff + + quit diff --git a/tests/cris/check_boundr.s b/tests/cris/check_boundr.s new file mode 100644 index 000000000..5c50cc5f6 --- /dev/null +++ b/tests/cris/check_boundr.s @@ -0,0 +1,125 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 2\n2\nffff\nffffffff\n5432f789\n2\n2\nffff\nffff\nffff\nf789\n2\n2\nff\nff\n89\nfeda4953\nfeda4962\n0\n0\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq 2,r4 + bound.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + moveq -1,r4 + bound.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r4 + move.d r4,r3 + bound.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r4 + move.d r4,r3 + bound.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + bound.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 5432f789 + + moveq -1,r3 + moveq 2,r4 + bound.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + moveq -1,r4 + bound.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq -1,r3 + bound.w r3,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + move.d 0xffff,r4 + move.d r4,r3 + bound.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + move.d 0xfedaffff,r4 + move.d r4,r3 + bound.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + bound.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 f789 + + moveq -1,r3 + moveq 2,r4 + bound.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + moveq 2,r3 + moveq -1,r4 + bound.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 2 + + move.d 0xff,r4 + move.d r4,r3 + bound.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 ff + + move.d 0xfeda49ff,r4 + move.d r4,r3 + bound.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 ff + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + bound.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 89 + + move.d 0xfeda4956,r3 + move.d 0xfeda4953,r4 + bound.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 feda4953 + + move.d 0xfeda4962,r3 + move.d 0xfeda4963,r4 + bound.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 feda4962 + + move.d 0xfeda4956,r3 + move.d 0,r4 + bound.d r4,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0xfeda4956,r4 + move.d 0,r3 + bound.d r4,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_btst.s b/tests/cris/check_btst.s new file mode 100644 index 000000000..741817731 --- /dev/null +++ b/tests/cris/check_btst.s @@ -0,0 +1,87 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1111\n + + .include "testutils.inc" + start + clearf nzvc + moveq -1,r3 + .if 1 ;..asm.arch.cris.v32 + .else + setf vc + .endif + btstq 0,r3 + test_cc 1 0 0 0 + + moveq 2,r3 + btstq 1,r3 + test_cc 1 0 0 0 + + moveq 4,r3 + btstq 1,r3 + test_cc 0 1 0 0 + + moveq -1,r3 + btstq 31,r3 + test_cc 1 0 0 0 + + move.d 0x5a67f19f,r3 + btstq 12,r3 + test_cc 1 0 0 0 + + move.d 0xda67f19f,r3 + move.d 29,r4 + btst r4,r3 + test_cc 0 0 0 0 + + move.d 0xda67f19f,r3 + move.d 32,r4 + btst r4,r3 + test_cc 1 0 0 0 + + move.d 0xda67f191,r3 + move.d 33,r4 + btst r4,r3 + test_cc 0 0 0 0 + + moveq -1,r3 + moveq 0,r4 + btst r4,r3 + test_cc 1 0 0 0 + + moveq 2,r3 + moveq 1,r4 + btst r4,r3 + test_cc 1 0 0 0 + + moveq -1,r3 + moveq 31,r4 + btst r4,r3 + test_cc 1 0 0 0 + + moveq 4,r3 + btstq 1,r3 + test_cc 0 1 0 0 + + moveq -1,r3 + moveq 15,r4 + btst r4,r3 + test_cc 1 0 0 0 + + move.d 0x5a67f19f,r3 + moveq 12,r4 + btst r4,r3 + test_cc 1 0 0 0 + + move.d 0x5a678000,r3 + moveq 11,r4 + btst r4,r3 + test_cc 0 1 0 0 + + move.d 0x5a67f19f,r3 + btst r3,r3 + test_cc 0 0 0 0 + + move.d 0x1111,r3 + checkr3 1111 + + quit diff --git a/tests/cris/check_clearfv32.s b/tests/cris/check_clearfv32.s new file mode 100644 index 000000000..db700728a --- /dev/null +++ b/tests/cris/check_clearfv32.s @@ -0,0 +1,17 @@ +# mach: crisv32 +# output: ef\nef\n + +; Check that "clearf x" doesn't trivially fail. + + .include "testutils.inc" + start + setf puixnzvc + clearf x ; Actually, x would be cleared by almost-all other insns. + move ccs,r3 + checkr3 ef + + setf puixnzvc + moveq 0, $r3 ; moveq should only clear the xflag. + move ccs,r3 + checkr3 ef + quit diff --git a/tests/cris/check_clrjmp1.s b/tests/cris/check_clrjmp1.s new file mode 100644 index 000000000..45a7005e2 --- /dev/null +++ b/tests/cris/check_clrjmp1.s @@ -0,0 +1,36 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: ffffff00\n + +; A bug resulting in a non-effectual clear.b discovered running the GCC +; testsuite; jump actually wrote to p0. + + .include "testutils.inc" + + start + jump 1f + nop + .p2align 8 +1: + move.d y,r4 + + .if 0 ;0 == ..asm.arch.cris.v32 +; There was a bug causing this insn to set special register p0 +; (byte-clear) to 8 (low 8 bits of location after insn). + jump [r4+] + .endif + +1: + move.d 0f,r4 + +; The corresponding bug would cause this insn too, to set p0. + jump r4 + nop + quit +0: + moveq -1,r3 + clear.b r3 + checkr3 ffffff00 + quit + +y: + .dword 1b diff --git a/tests/cris/check_cmp-2.s b/tests/cris/check_cmp-2.s new file mode 100644 index 000000000..c5c3f5ce8 --- /dev/null +++ b/tests/cris/check_cmp-2.s @@ -0,0 +1,15 @@ + + +.include "testutils.inc" + + start + + move.d 4294967283, $r0 + move.d $r0, $r10 + cmp.d $r0, $r10 + beq 1f + move.d $r10, $r3 + fail +1: + pass + quit \ No newline at end of file diff --git a/tests/cris/check_cmpc.s b/tests/cris/check_cmpc.s new file mode 100644 index 000000000..267c9ba8c --- /dev/null +++ b/tests/cris/check_cmpc.s @@ -0,0 +1,86 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649282\n + + .include "testutils.inc" + start + moveq -1,r3 + cmp.d -2,r3 + test_cc 0 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + cmp.d 1,r3 + test_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + cmp.d -0xffff,r3 + test_cc 0 0 0 1 + checkr3 ffff + + moveq -1,r3 + cmp.d 1,r3 + test_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x78134452,r3 + cmp.d -0x5432f789,r3 + test_cc 1 0 1 1 + checkr3 78134452 + + moveq -1,r3 + cmp.w -2,r3 + test_cc 0 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + cmp.w 1,r3 + test_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + cmp.w 1,r3 + test_cc 1 0 0 0 + checkr3 ffff + + move.d 0xfedaffff,r3 + cmp.w 1,r3 + test_cc 1 0 0 0 + checkr3 fedaffff + + move.d 0x78134452,r3 + cmp.w 0x877,r3 + test_cc 0 0 0 0 + checkr3 78134452 + + moveq -1,r3 + cmp.b -2,r3 + test_cc 0 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + cmp.b 1,r3 + test_cc 0 0 0 0 + checkr3 2 + + move.d 0xff,r3 + cmp.b 1,r3 + test_cc 1 0 0 0 + checkr3 ff + + move.d 0xfeda49ff,r3 + cmp.b 1,r3 + test_cc 1 0 0 0 + checkr3 feda49ff + + move.d 0x78134452,r3 + cmp.b 0x77,r3 + test_cc 1 0 0 1 + checkr3 78134452 + + move.d 0x85649282,r3 + cmp.b 0x82,r3 + test_cc 0 1 0 0 + checkr3 85649282 + + quit diff --git a/tests/cris/check_cmpm.s b/tests/cris/check_cmpm.s new file mode 100644 index 000000000..e4dde15b3 --- /dev/null +++ b/tests/cris/check_cmpm.s @@ -0,0 +1,96 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n + + .include "testutils.inc" + .data +x: + .dword -2,1,-0xffff,1,-0x5432f789 + .word -2,1,1,0x877 + .byte -2,1,0x77 + .byte 0x22 + + start + moveq -1,r3 + move.d x,r5 + cmp.d [r5+],r3 + test_cc 0 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + cmp.d [r5],r3 + test_cc 0 0 0 0 + addq 4,r5 + checkr3 2 + + move.d 0xffff,r3 + cmp.d [r5+],r3 + test_cc 0 0 0 1 + checkr3 ffff + + moveq -1,r3 + cmp.d [r5+],r3 + test_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x78134452,r3 + cmp.d [r5+],r3 + test_cc 1 0 1 1 + checkr3 78134452 + + moveq -1,r3 + cmp.w [r5+],r3 + test_cc 0 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + cmp.w [r5+],r3 + test_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + cmp.w [r5],r3 + test_cc 1 0 0 0 + checkr3 ffff + + move.d 0xfedaffff,r3 + cmp.w [r5+],r3 + test_cc 1 0 0 0 + checkr3 fedaffff + + move.d 0x78134452,r3 + cmp.w [r5+],r3 + test_cc 0 0 0 0 + checkr3 78134452 + + moveq -1,r3 + cmp.b [r5],r3 + test_cc 0 0 0 0 + addq 1,r5 + checkr3 ffffffff + + moveq 2,r3 + cmp.b [r5],r3 + test_cc 0 0 0 0 + checkr3 2 + + move.d 0xff,r3 + cmp.b [r5],r3 + test_cc 1 0 0 0 + checkr3 ff + + move.d 0xfeda49ff,r3 + cmp.b [r5+],r3 + test_cc 1 0 0 0 + checkr3 feda49ff + + move.d 0x78134452,r3 + cmp.b [r5+],r3 + test_cc 1 0 0 1 + checkr3 78134452 + + move.d 0x85649222,r3 + cmp.b [r5],r3 + test_cc 0 1 0 0 + checkr3 85649222 + + quit diff --git a/tests/cris/check_cmpq.s b/tests/cris/check_cmpq.s new file mode 100644 index 000000000..5469141c9 --- /dev/null +++ b/tests/cris/check_cmpq.s @@ -0,0 +1,75 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n1\n1f\n1f\nffffffe1\nffffffe1\nffffffe0\n0\n0\nffffffff\nffffffff\n10000\n100\n5678900\n + + .include "testutils.inc" + start + moveq 1,r3 + cmpq 1,r3 + test_cc 0 1 0 0 + checkr3 1 + + cmpq -1,r3 + test_cc 0 0 0 1 + checkr3 1 + + cmpq 31,r3 + test_cc 1 0 0 1 + checkr3 1 + + moveq 31,r3 + cmpq 31,r3 + test_cc 0 1 0 0 + checkr3 1f + + cmpq -31,r3 + test_cc 0 0 0 1 + checkr3 1f + + movs.b -31,r3 + cmpq -31,r3 + test_cc 0 1 0 0 + checkr3 ffffffe1 + + cmpq -32,r3 + test_cc 0 0 0 0 + checkr3 ffffffe1 + + movs.b -32,r3 + cmpq -32,r3 + test_cc 0 1 0 0 + checkr3 ffffffe0 + + moveq 0,r3 + cmpq 1,r3 + test_cc 1 0 0 1 + checkr3 0 + + cmpq -32,r3 + test_cc 0 0 0 1 + checkr3 0 + + moveq -1,r3 + cmpq 1,r3 + test_cc 1 0 0 0 + checkr3 ffffffff + + cmpq -1,r3 + test_cc 0 1 0 0 + checkr3 ffffffff + + move.d 0x10000,r3 + cmpq 1,r3 + test_cc 0 0 0 0 + checkr3 10000 + + move.d 0x100,r3 + cmpq 1,r3 + test_cc 0 0 0 0 + checkr3 100 + + move.d 0x5678900,r3 + cmpq 7,r3 + test_cc 0 0 0 0 + checkr3 5678900 + + quit diff --git a/tests/cris/check_cmpr.s b/tests/cris/check_cmpr.s new file mode 100644 index 000000000..b30af7a53 --- /dev/null +++ b/tests/cris/check_cmpr.s @@ -0,0 +1,102 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq -2,r4 + cmp.d r4,r3 + test_cc 0 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + moveq 1,r4 + cmp.d r4,r3 + test_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + move.d -0xffff,r4 + cmp.d r4,r3 + test_cc 0 0 0 1 + checkr3 ffff + + moveq 1,r4 + moveq -1,r3 + cmp.d r4,r3 + test_cc 1 0 0 0 + checkr3 ffffffff + + move.d -0x5432f789,r4 + move.d 0x78134452,r3 + cmp.d r4,r3 + test_cc 1 0 1 1 + checkr3 78134452 + + moveq -1,r3 + moveq -2,r4 + cmp.w r4,r3 + test_cc 0 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + moveq 1,r4 + cmp.w r4,r3 + test_cc 0 0 0 0 + checkr3 2 + + move.d 0xffff,r3 + move.d -0xffff,r4 + cmp.w r4,r3 + test_cc 1 0 0 0 + checkr3 ffff + + move.d 0xfedaffff,r3 + move.d -0xfedaffff,r4 + cmp.w r4,r3 + test_cc 1 0 0 0 + checkr3 fedaffff + + move.d -0x5432f789,r4 + move.d 0x78134452,r3 + cmp.w r4,r3 + test_cc 0 0 0 0 + checkr3 78134452 + + moveq -1,r3 + moveq -2,r4 + cmp.b r4,r3 + test_cc 0 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + moveq 1,r4 + cmp.b r4,r3 + test_cc 0 0 0 0 + checkr3 2 + + move.d -0xff,r4 + move.d 0xff,r3 + cmp.b r4,r3 + test_cc 1 0 0 0 + checkr3 ff + + move.d -0xfeda49ff,r4 + move.d 0xfeda49ff,r3 + cmp.b r4,r3 + test_cc 1 0 0 0 + checkr3 feda49ff + + move.d -0x5432f789,r4 + move.d 0x78134452,r3 + cmp.b r4,r3 + test_cc 1 0 0 1 + checkr3 78134452 + + move.d 0x85649222,r3 + move.d 0x77445622,r4 + cmp.b r4,r3 + test_cc 0 1 0 0 + checkr3 85649222 + + quit diff --git a/tests/cris/check_cmpxc.s b/tests/cris/check_cmpxc.s new file mode 100644 index 000000000..b237a9317 --- /dev/null +++ b/tests/cris/check_cmpxc.s @@ -0,0 +1,92 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n + + .include "testutils.inc" + start + moveq 2,r3 + cmps.b 0xff,r3 + test_cc 0 0 0 1 + checkr3 2 + + moveq 2,r3 + cmps.w 0xffff,r3 + test_cc 0 0 0 1 + checkr3 2 + + moveq 2,r3 + cmpu.b 0xff,r3 + test_cc 1 0 0 1 + checkr3 2 + + moveq 2,r3 + move.d 0xffffffff,r4 + cmpu.w -1,r3 + test_cc 1 0 0 1 + checkr3 2 + + move.d 0xffff,r3 + cmpu.b -1,r3 + test_cc 0 0 0 0 + checkr3 ffff + + move.d 0xffff,r3 + cmpu.w -1,r3 + test_cc 0 1 0 0 + checkr3 ffff + + move.d 0xffff,r3 + cmps.b 0xff,r3 + test_cc 0 0 0 1 + checkr3 ffff + + move.d 0xffff,r3 + cmps.w 0xffff,r3 + test_cc 0 0 0 1 + checkr3 ffff + + moveq -1,r3 + cmps.b 0xff,r3 + test_cc 0 1 0 0 + checkr3 ffffffff + + moveq -1,r3 + cmps.w 0xff,r3 + test_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + cmps.w 0xffff,r3 + test_cc 0 1 0 0 + checkr3 ffffffff + + move.d 0x78134452,r3 + cmpu.b 0x89,r3 + test_cc 0 0 0 0 + checkr3 78134452 + + move.d 0x78134452,r3 + cmps.b 0x89,r3 + test_cc 0 0 0 1 + checkr3 78134452 + + move.d 0x78134452,r3 + cmpu.w 0xf789,r3 + test_cc 0 0 0 0 + checkr3 78134452 + + move.d 0x78134452,r3 + cmps.w 0xf789,r3 + test_cc 0 0 0 1 + checkr3 78134452 + + move.d 0x4452,r3 + cmps.w 0x8002,r3 + test_cc 0 0 0 1 + checkr3 4452 + + move.d 0x80000032,r3 + cmpu.w 0x764,r3 + test_cc 0 0 1 0 + checkr3 80000032 + + quit diff --git a/tests/cris/check_cmpxm.s b/tests/cris/check_cmpxm.s new file mode 100644 index 000000000..87ea5bf8e --- /dev/null +++ b/tests/cris/check_cmpxm.s @@ -0,0 +1,106 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n + + .include "testutils.inc" + .data +x: + .byte 0xff + .word 0xffff + .word 0xff + .word 0xffff + .byte 0x89 + .word 0xf789 + .word 0x8002 + .word 0x764 + + start + moveq 2,r3 + move.d x,r5 + cmps.b [r5+],r3 + test_cc 0 0 0 1 + checkr3 2 + + moveq 2,r3 + cmps.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 2 + + moveq 2,r3 + subq 3,r5 + cmpu.b [r5+],r3 + test_cc 1 0 0 1 + checkr3 2 + + moveq 2,r3 + cmpu.w [r5+],r3 + test_cc 1 0 0 1 + subq 3,r5 + checkr3 2 + + move.d 0xffff,r3 + cmpu.b [r5],r3 + test_cc 0 0 0 0 + checkr3 ffff + + move.d 0xffff,r3 + cmpu.w [r5],r3 + test_cc 0 1 0 0 + checkr3 ffff + + move.d 0xffff,r3 + cmps.b [r5],r3 + test_cc 0 0 0 1 + checkr3 ffff + + move.d 0xffff,r3 + cmps.w [r5],r3 + test_cc 0 0 0 1 + checkr3 ffff + + moveq -1,r3 + cmps.b [r5],r3 + test_cc 0 1 0 0 + addq 3,r5 + checkr3 ffffffff + + moveq -1,r3 + cmps.w [r5+],r3 + test_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + cmps.w [r5+],r3 + test_cc 0 1 0 0 + checkr3 ffffffff + + move.d 0x78134452,r3 + cmpu.b [r5],r3 + test_cc 0 0 0 0 + checkr3 78134452 + + move.d 0x78134452,r3 + cmps.b [r5+],r3 + test_cc 0 0 0 1 + checkr3 78134452 + + move.d 0x78134452,r3 + cmpu.w [r5],r3 + test_cc 0 0 0 0 + checkr3 78134452 + + move.d 0x78134452,r3 + cmps.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 78134452 + + move.d 0x4452,r3 + cmps.w [r5+],r3 + test_cc 0 0 0 1 + checkr3 4452 + + move.d 0x80000032,r3 + cmpu.w [r5+],r3 + test_cc 0 0 1 0 + checkr3 80000032 + + quit diff --git a/tests/cris/check_dstep.s b/tests/cris/check_dstep.s new file mode 100644 index 000000000..bd43b838e --- /dev/null +++ b/tests/cris/check_dstep.s @@ -0,0 +1,42 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: fffffffc\n4\nffff\nfffffffe\n9bf3911b\n0\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq 2,r4 + dstep r4,r3 + test_move_cc 1 0 0 0 + checkr3 fffffffc + + moveq 2,r3 + moveq -1,r4 + dstep r4,r3 + test_move_cc 0 0 0 0 + checkr3 4 + + move.d 0xffff,r4 + move.d r4,r3 + dstep r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r4 + move.d r4,r3 + dstep r4,r3 + test_move_cc 1 0 0 0 + checkr3 fffffffe + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + dstep r4,r3 + test_move_cc 1 0 0 0 + checkr3 9bf3911b + + move.d 0xffff,r3 + move.d 0x1fffe,r4 + dstep r4,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_gcctorture_pr28634-1.c b/tests/cris/check_gcctorture_pr28634-1.c new file mode 100644 index 000000000..45ecd159b --- /dev/null +++ b/tests/cris/check_gcctorture_pr28634-1.c @@ -0,0 +1,15 @@ +/* PR rtl-optimization/28634. On targets with delayed branches, + dbr_schedule could do the next iteration's addition in the + branch delay slot, then subtract the value again if the branch + wasn't taken. This can lead to rounding errors. */ +int x = -1; +int y = 1; +int +main (void) +{ + while (y > 0) + y += x; + if (y != x + 1) + abort (); + exit (0); +} diff --git a/tests/cris/check_gcctorture_pr28634.c b/tests/cris/check_gcctorture_pr28634.c new file mode 100644 index 000000000..a0c525497 --- /dev/null +++ b/tests/cris/check_gcctorture_pr28634.c @@ -0,0 +1,15 @@ +/* PR rtl-optimization/28634. On targets with delayed branches, + dbr_schedule could do the next iteration's addition in the + branch delay slot, then subtract the value again if the branch + wasn't taken. This can lead to rounding errors. */ +double x = -0x1.0p53; +double y = 1; +int +main (void) +{ + while (y > 0) + y += x; + if (y != x + 1) + abort (); + exit (0); +} diff --git a/tests/cris/check_glibc_kernelversion.c b/tests/cris/check_glibc_kernelversion.c new file mode 100644 index 000000000..fcbc7b07f --- /dev/null +++ b/tests/cris/check_glibc_kernelversion.c @@ -0,0 +1,116 @@ +/* + * Check the lz insn. + */ + +#include +#include +#include +#include "sys.h" + +#define __LINUX_KERNEL_VERSION 131584 + +#define DL_SYSDEP_OSCHECK(FATAL) \ + do { \ + /* Test whether the kernel is new enough. This test is only \ + performed if the library is not compiled to run on all \ + kernels. */ \ + if (__LINUX_KERNEL_VERSION > 0) \ + { \ + char bufmem[64]; \ + char *buf = bufmem; \ + unsigned int version; \ + int parts; \ + char *cp; \ + struct utsname uts; \ + \ + /* Try the uname syscall */ \ + if (__uname (&uts)) \ + { \ + /* This was not successful. Now try reading the /proc \ + filesystem. */ \ + ssize_t reslen; \ + int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY); \ + if (fd == -1 \ + || (reslen = __read (fd, bufmem, sizeof (bufmem))) <= 0) \ + /* This also didn't work. We give up since we cannot \ + make sure the library can actually work. */ \ + FATAL ("FATAL: cannot determine library version\n"); \ + __close (fd); \ + buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0'; \ + } \ + else \ + buf = uts.release; \ + \ + /* Now convert it into a number. The string consists of at most \ + three parts. */ \ + version = 0; \ + parts = 0; \ + cp = buf; \ + while ((*cp >= '0') && (*cp <= '9')) \ + { \ + unsigned int here = *cp++ - '0'; \ + \ + while ((*cp >= '0') && (*cp <= '9')) \ + { \ + here *= 10; \ + here += *cp++ - '0'; \ + } \ + \ + ++parts; \ + version <<= 8; \ + version |= here; \ + \ + if (*cp++ != '.') \ + /* Another part following? */ \ + break; \ + } \ + \ + if (parts < 3) \ + version <<= 8 * (3 - parts); \ + \ + /* Now we can test with the required version. */ \ + if (version < __LINUX_KERNEL_VERSION) \ + /* Not sufficent. */ \ + FATAL ("FATAL: kernel too old\n"); \ + \ + _dl_osversion = version; \ + } \ + } while (0) + +int main(void) +{ + char bufmem[64] = "2.6.22"; + char *buf = bufmem; + unsigned int version; + int parts; + char *cp; + + version = 0; + parts = 0; + cp = buf; + while ((*cp >= '0') && (*cp <= '9')) + { + unsigned int here = *cp++ - '0'; + + while ((*cp >= '0') && (*cp <= '9')) + { + here *= 10; + here += *cp++ - '0'; + } + + ++parts; + version <<= 8; + version |= here; + + if (*cp++ != '.') + /* Another part following? */ + break; + } + + if (parts < 3) + version <<= 8 * (3 - parts); + if (version < __LINUX_KERNEL_VERSION) + err(); + pass(); + exit(0); +} diff --git a/tests/cris/check_hello.c b/tests/cris/check_hello.c new file mode 100644 index 000000000..fb403ba99 --- /dev/null +++ b/tests/cris/check_hello.c @@ -0,0 +1,7 @@ +#include +#include +int main () +{ + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_int64.c b/tests/cris/check_int64.c new file mode 100644 index 000000000..99ca6f115 --- /dev/null +++ b/tests/cris/check_int64.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + + +extern inline int64_t add64(const int64_t a, const int64_t b) { + return a + b; +} + +extern inline int64_t sub64(const int64_t a, const int64_t b) { + return a - b; +} + +int main(void) +{ + int64_t a = 1; + int64_t b = 2; + + /* FIXME: add some tests. */ + a = add64(a, b); + if (a != 3) + err(); + + a = sub64(a, b); + if (a != 1) + err(); + + a = add64(a, -4); + if (a != -3) + err(); + + a = add64(a, 3); + if (a != 0) + err(); + + a = 0; + a = sub64(a, 1); + if (a != -1) + err(); + + pass(); + return 0; +} diff --git a/tests/cris/check_jsr.s b/tests/cris/check_jsr.s new file mode 100644 index 000000000..106023787 --- /dev/null +++ b/tests/cris/check_jsr.s @@ -0,0 +1,85 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 0\n0\n0\n0\n0\n0\n + +# Test that jsr Rn and jsr [PC+] work. + + .include "testutils.inc" + start +x: + move.d 0f,r6 + setf nzvc + jsr r6 + .if 1; ..asm.arch.cris.v32 + nop + .endif +0: + test_move_cc 1 1 1 1 + move srp,r3 + sub.d 0b,r3 + checkr3 0 + + move.d 1f,r0 + setf nzvc + jsr r0 + .if 1 ; ..asm.arch.cris.v32 + moveq 0,r0 + .endif +6: + nop + quit + +2: + test_move_cc 0 0 0 0 + move srp,r3 + sub.d 3f,r3 + checkr3 0 + jsr 4f + .if 1 ; ..asm.arch.cris.v32 + nop + .endif +7: + nop + quit + +8: + move srp,r3 + sub.d 7b,r3 + checkr3 0 + quit + +4: + move srp,r3 + sub.d 7b,r3 + checkr3 0 + move.d 5f,r3 + jump r3 + .if 1; ..asm.arch.cris.v32 + moveq 0,r3 + .endif + quit + + .space 32770,0 +1: + test_move_cc 1 1 1 1 + move srp,r3 + sub.d 6b,r3 + checkr3 0 + + clearf cznv + jsr 2b + .if 1; ..asm.arch.cris.v32 + nop + .endif +3: + + quit + +5: + move srp,r3 + sub.d 7b,r3 + checkr3 0 + jump 8b + .if 1 ; ..asm.arch.cris.v32 + nop + .endif + quit diff --git a/tests/cris/check_lapc.s b/tests/cris/check_lapc.s new file mode 100644 index 000000000..9a6150b74 --- /dev/null +++ b/tests/cris/check_lapc.s @@ -0,0 +1,78 @@ +# mach: crisv32 +# output: 0\n0\nfffffffa\nfffffffe\nffffffda\n1e\n1e\n0\n + +.include "testutils.inc" + +; To accommodate dumpr3 with more than one instruction, keep it +; out of lapc operand ranges and difference calculations. + + start + lapc.d 0f,r3 +0: + sub.d .,r3 + checkr3 0 + + lapcq 0f,r3 +0: + sub.d .,r3 + checkr3 0 + + lapc.d .,r3 + sub.d .,r3 + checkr3 fffffffa + + lapcq .,r3 + sub.d .,r3 + checkr3 fffffffe + +0: + .rept 16 + nop + .endr + lapc.d 0b,r3 + sub.d .,r3 + checkr3 ffffffda + + setf zcvn + lapc.d 0f,r3 + test_cc 1 1 1 1 + sub.d .,r3 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +0: + checkr3 1e +0: + lapcq 0f,r3 + sub.d 0b,r3 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop +0: + checkr3 1e + clearf cn + setf zv +1: + lapcq .,r3 + test_cc 0 1 1 0 + sub.d 1b,r3 + checkr3 0 + + quit diff --git a/tests/cris/check_lsl.s b/tests/cris/check_lsl.s new file mode 100644 index 000000000..9e2ddd7cd --- /dev/null +++ b/tests/cris/check_lsl.s @@ -0,0 +1,217 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: ffffffff\n4\n80000000\nffff8000\n7f19f000\n80000000\n0\n0\n699fc67c\nffffffff\n4\n80000000\nffff8000\n7f19f000\nda670000\nda670000\nda670000\nda67c67c\nffffffff\nfffafffe\n4\nffff0000\nffff8000\n5a67f000\nda67f100\nda67f100\nda67f100\nda67f17c\nfff3faff\nfff3fafe\n4\nffffff00\nffffff00\nffffff80\n5a67f100\n5a67f1f0\n + + .include "testutils.inc" + start + moveq -1,r3 + lslq 0,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + lslq 1,r3 + test_move_cc 0 0 0 0 + checkr3 4 + + moveq -1,r3 + lslq 31,r3 + test_move_cc 1 0 0 0 + checkr3 80000000 + + moveq -1,r3 + lslq 15,r3 + test_move_cc 1 0 0 0 + checkr3 ffff8000 + + move.d 0x5a67f19f,r3 + lslq 12,r3 + test_move_cc 0 0 0 0 + checkr3 7f19f000 + + move.d 0xda67f19f,r3 + move.d 31,r4 + lsl.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 80000000 + + move.d 0xda67f19f,r3 + move.d 32,r4 + lsl.d r4,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0xda67f19f,r3 + move.d 33,r4 + lsl.d r4,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0xda67f19f,r3 + move.d 66,r4 + lsl.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 699fc67c + + moveq -1,r3 + moveq 0,r4 + lsl.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + moveq 1,r4 + lsl.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 4 + + moveq -1,r3 + moveq 31,r4 + lsl.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 80000000 + + moveq -1,r3 + moveq 15,r4 + lsl.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffff8000 + + move.d 0x5a67f19f,r3 + moveq 12,r4 + lsl.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 7f19f000 + + move.d 0xda67f19f,r3 + move.d 31,r4 + lsl.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 da670000 + + move.d 0xda67f19f,r3 + move.d 32,r4 + lsl.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 da670000 + + move.d 0xda67f19f,r3 + move.d 33,r4 + lsl.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 da670000 + + move.d 0xda67f19f,r3 + move.d 66,r4 + lsl.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 da67c67c + + moveq -1,r3 + moveq 0,r4 + lsl.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0xfffaffff,r3 + moveq 1,r4 + lsl.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 fffafffe + + moveq 2,r3 + moveq 1,r4 + lsl.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 4 + + moveq -1,r3 + moveq 31,r4 + lsl.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 ffff0000 + + moveq -1,r3 + moveq 15,r4 + lsl.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffff8000 + + move.d 0x5a67f19f,r3 + moveq 12,r4 + lsl.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 5a67f000 + + move.d 0xda67f19f,r3 + move.d 31,r4 + lsl.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 da67f100 + + move.d 0xda67f19f,r3 + move.d 32,r4 + lsl.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 da67f100 + + move.d 0xda67f19f,r3 + move.d 33,r4 + lsl.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 da67f100 + + move.d 0xda67f19f,r3 + move.d 66,r4 + lsl.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 da67f17c + + move.d 0xfff3faff,r3 + moveq 0,r4 + lsl.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 fff3faff + + move.d 0xfff3faff,r3 + moveq 1,r4 + lsl.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 fff3fafe + + moveq 2,r3 + moveq 1,r4 + lsl.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 4 + + moveq -1,r3 + moveq 31,r4 + lsl.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 ffffff00 + + moveq -1,r3 + moveq 15,r4 + lsl.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 ffffff00 + + moveq -1,r3 + moveq 7,r4 + lsl.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffff80 + + move.d 0x5a67f19f,r3 + moveq 12,r4 + lsl.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 5a67f100 + + move.d 0x5a67f19f,r3 + moveq 4,r4 + lsl.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 5a67f1f0 + + quit diff --git a/tests/cris/check_lsr.s b/tests/cris/check_lsr.s new file mode 100644 index 000000000..18fdbef9b --- /dev/null +++ b/tests/cris/check_lsr.s @@ -0,0 +1,218 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: ffffffff\n1\n1\n1ffff\n5a67f\n1\n0\n0\n3699fc67\nffffffff\n1\n1\n1ffff\n5a67f\nda670000\nda670000\nda670000\nda673c67\nffffffff\nffff7fff\n1\nffff0000\nffff0001\n5a67000f\nda67f100\nda67f100\nda67f100\nda67f127\nffffffff\nffffff7f\n1\nffffff00\nffffff00\nffffff01\n5a67f100\n5a67f109\n + + .include "testutils.inc" + start + moveq -1,r3 + lsrq 0,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + lsrq 1,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + lsrq 31,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + lsrq 15,r3 + test_move_cc 0 0 0 0 + checkr3 1ffff + + move.d 0x5a67f19f,r3 + lsrq 12,r3 + test_move_cc 0 0 0 0 + checkr3 5a67f + + move.d 0xda67f19f,r3 + move.d 31,r4 + lsr.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + move.d 0xda67f19f,r3 + move.d 32,r4 + lsr.d r4,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0xda67f19f,r3 + move.d 33,r4 + lsr.d r4,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0xda67f19f,r3 + move.d 66,r4 + lsr.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 3699fc67 + + moveq -1,r3 + moveq 0,r4 + lsr.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 2,r3 + moveq 1,r4 + lsr.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + moveq 31,r4 + lsr.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + moveq 15,r4 + lsr.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 1ffff + + move.d 0x5a67f19f,r3 + moveq 12,r4 + lsr.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 5a67f + + move.d 0xda67f19f,r3 + move.d 31,r4 + lsr.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 da670000 + + move.d 0xda67f19f,r3 + move.d 32,r4 + lsr.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 da670000 + + move.d 0xda67f19f,r3 + move.d 33,r4 + lsr.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 da670000 + + move.d 0xda67f19f,r3 + move.d 66,r4 + lsr.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 da673c67 + + moveq -1,r3 + moveq 0,r4 + lsr.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + moveq 1,r4 + lsr.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff7fff + + moveq 2,r3 + moveq 1,r4 + lsr.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 1 + +;; FIXME: this was wrong. Z should be set. + moveq -1,r3 + moveq 31,r4 + lsr.w r4,r3 + test_move_cc 0 1 0 0 + checkr3 ffff0000 + + moveq -1,r3 + moveq 15,r4 + lsr.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff0001 + + move.d 0x5a67f19f,r3 + moveq 12,r4 + lsr.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 5a67000f + + move.d 0xda67f19f,r3 + move.d 31,r4 + lsr.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 da67f100 + + move.d 0xda67f19f,r3 + move.d 32,r4 + lsr.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 da67f100 + + move.d 0xda67f19f,r3 + move.d 33,r4 + lsr.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 da67f100 + + move.d 0xda67f19f,r3 + move.d 66,r4 + lsr.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 da67f127 + + moveq -1,r3 + moveq 0,r4 + lsr.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq -1,r3 + moveq 1,r4 + lsr.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffffff7f + + moveq 2,r3 + moveq 1,r4 + lsr.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + moveq -1,r3 + moveq 31,r4 + lsr.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 ffffff00 + + moveq -1,r3 + moveq 15,r4 + lsr.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 ffffff00 + + moveq -1,r3 + moveq 7,r4 + lsr.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffffff01 + + move.d 0x5a67f19f,r3 + moveq 12,r4 + lsr.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 5a67f100 + + move.d 0x5a67f19f,r3 + moveq 4,r4 + lsr.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 5a67f109 + + quit diff --git a/tests/cris/check_lz.c b/tests/cris/check_lz.c new file mode 100644 index 000000000..7b30a265a --- /dev/null +++ b/tests/cris/check_lz.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include "sys.h" + +extern inline int cris_lz(int x) +{ + int r; + asm ("lz\t%1, %0\n" : "=r" (r) : "r" (x)); + return r; +} + +void check_lz(void) +{ + int i; + + if (cris_lz(0) != 32) + err(); + if (cris_lz(1) != 31) + err(); + if (cris_lz(2) != 30) + err(); + if (cris_lz(4) != 29) + err(); + if (cris_lz(8) != 28) + err(); + + /* try all positions with a single bit. */ + for (i = 1; i < 32; i++) { + if (cris_lz(1 << (i-1)) != (32 - i)) + err(); + } + + /* try all positions with all bits. */ + for (i = 1; i < 32; i++) { + /* split up this computation to clarify it. */ + uint32_t val; + val = (unsigned int)-1 >> (32 - i); + if (cris_lz(val) != (32 - i)) + err(); + } +} + +int main(void) +{ + check_lz(); + pass(); + exit(0); +} diff --git a/tests/cris/check_mapbrk.c b/tests/cris/check_mapbrk.c new file mode 100644 index 000000000..1aff7622b --- /dev/null +++ b/tests/cris/check_mapbrk.c @@ -0,0 +1,39 @@ +#include +#include + +/* Basic sanity check that syscalls to implement malloc (brk, mmap2, + munmap) are trivially functional. */ + +int main () +{ + void *p1, *p2, *p3, *p4, *p5, *p6; + + if ((p1 = malloc (8100)) == NULL + || (p2 = malloc (16300)) == NULL + || (p3 = malloc (4000)) == NULL + || (p4 = malloc (500)) == NULL + || (p5 = malloc (1023*1024)) == NULL + || (p6 = malloc (8191*1024)) == NULL) + { + printf ("fail\n"); + exit (1); + } + + free (p1); + free (p2); + free (p3); + free (p4); + free (p5); + free (p6); + + p1 = malloc (64000); + if (p1 == NULL) + { + printf ("fail\n"); + exit (1); + } + free (p1); + + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_mcp.s b/tests/cris/check_mcp.s new file mode 100644 index 000000000..e65ccddfd --- /dev/null +++ b/tests/cris/check_mcp.s @@ -0,0 +1,49 @@ +# mach: crisv32 +# output: fffffffe\n1\n1ffff\nfffffffe\ncc463bdc\n4c463bdc\n0\n + + .include "testutils.inc" + start + +; Set R, clear C. + move 0x100,ccs + moveq -5,r3 + move 2,mof + mcp mof,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + + moveq 2,r3 + move -1,srp + mcp srp,r3 + test_cc 0 0 0 0 + checkr3 1 + + move 0xffff,srp + move srp,r3 + mcp srp,r3 + test_cc 0 0 0 0 + checkr3 1ffff + + move -1,mof + move mof,r3 + mcp mof,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + + move 0x5432f789,mof + move.d 0x78134452,r3 + mcp mof,r3 + test_cc 1 0 1 0 + checkr3 cc463bdc + + move 0x80000000,srp + mcp srp,r3 + test_cc 0 0 1 0 + checkr3 4c463bdc + + move 0xb3b9c423,srp + mcp srp,r3 + test_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_mmap1.c b/tests/cris/check_mmap1.c new file mode 100644 index 000000000..b803f0c43 --- /dev/null +++ b/tests/cris/check_mmap1.c @@ -0,0 +1,48 @@ +/* +#notarget: cris*-*-elf +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + int fd = open (argv[0], O_RDONLY); + struct stat sb; + int size; + void *a; + const char *str = "a string you'll only find in the program"; + + if (fd == -1) + { + perror ("open"); + abort (); + } + + if (fstat (fd, &sb) < 0) + { + perror ("fstat"); + abort (); + } + + size = sb.st_size; + + /* We want to test mmapping a size that isn't exactly a page. */ + if ((size & 8191) == 0) + size--; + + a = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + + if (memmem (a, size, str, strlen (str) + 1) == NULL) + abort (); + + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_mmap2.c b/tests/cris/check_mmap2.c new file mode 100644 index 000000000..35139a0ed --- /dev/null +++ b/tests/cris/check_mmap2.c @@ -0,0 +1,48 @@ +/* +#notarget: cris*-*-elf +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + int fd = open (argv[0], O_RDONLY); + struct stat sb; + int size; + void *a; + const char *str = "a string you'll only find in the program"; + + if (fd == -1) + { + perror ("open"); + abort (); + } + + if (fstat (fd, &sb) < 0) + { + perror ("fstat"); + abort (); + } + + size = sb.st_size; + + /* We want to test mmapping a size that isn't exactly a page. */ + if ((size & 8191) == 0) + size--; + + a = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); + + if (memmem (a, size, str, strlen (str) + 1) == NULL) + abort (); + + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_mmap3.c b/tests/cris/check_mmap3.c new file mode 100644 index 000000000..34401fa0c --- /dev/null +++ b/tests/cris/check_mmap3.c @@ -0,0 +1,33 @@ +/* +#notarget: cris*-*-elf +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + volatile unsigned char *a; + + /* Check that we can map a non-multiple of a page and still get a full page. */ + a = mmap (NULL, 0x4c, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (a == NULL || a == (unsigned char *) -1) + abort (); + + a[0] = 0xbe; + a[8191] = 0xef; + memset ((char *) a + 1, 0, 8190); + + if (a[0] != 0xbe || a[8191] != 0xef) + abort (); + + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_movdelsr1.s b/tests/cris/check_movdelsr1.s new file mode 100644 index 000000000..300cc8774 --- /dev/null +++ b/tests/cris/check_movdelsr1.s @@ -0,0 +1,33 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: aa117acd\n +# output: eeaabb42\n + +; Bug with move to special register in delay slot, due to +; special flush-insn-cache simulator use. Ordinary move worked; +; special register caused branch to fail. + + .include "testutils.inc" + start + move -1,srp + + move.d 0xaa117acd,r1 + moveq 3,r9 + cmpq 1,r9 + bhi 0f + move.d r1,r3 + + fail +0: + checkr3 aa117acd + + move.d 0xeeaabb42,r1 + moveq 3,r9 + cmpq 1,r9 + bhi 0f + move r1,srp + + fail +0: + move srp,r3 + checkr3 eeaabb42 + quit diff --git a/tests/cris/check_movecr.s b/tests/cris/check_movecr.s new file mode 100644 index 000000000..da8ec2628 --- /dev/null +++ b/tests/cris/check_movecr.s @@ -0,0 +1,37 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: ffffff42\n94\nffff4321\n9234\n76543210\n76540000\n + +; Move constant byte, word, dword to register. Check that no extension is +; performed, that only part of the register is set. + + .include "testutils.inc" + startnostack + moveq -1,r3 + move.b 0x42,r3 + test_move_cc 0 0 0 0 + checkr3 ffffff42 + + moveq 0,r3 + move.b 0x94,r3 + test_move_cc 1 0 0 0 + checkr3 94 + + moveq -1,r3 + move.w 0x4321,r3 + test_move_cc 0 0 0 0 + checkr3 ffff4321 + + moveq 0,r3 + move.w 0x9234,r3 + test_move_cc 1 0 0 0 + checkr3 9234 + + move.d 0x76543210,r3 + test_move_cc 0 0 0 0 + checkr3 76543210 + + move.w 0,r3 + test_move_cc 0 1 0 0 + checkr3 76540000 + + quit diff --git a/tests/cris/check_movei.s b/tests/cris/check_movei.s new file mode 100644 index 000000000..2defda5f3 --- /dev/null +++ b/tests/cris/check_movei.s @@ -0,0 +1,47 @@ +# mach: crisv32 +# output: fffffffe\n +# output: fffffffe\n + +; Check basic integral-write semantics regarding flags. + + .include "testutils.inc" + start + +; A write that works. Check that flags are set correspondingly. + move.d d,r4 + moveq -2,r5 + setf c + clearf p + move.d [r4],r3 + ax + move.d r5,[r4] + move.d [r4],r3 + + bcc 0f + nop + fail + +0: + checkr3 fffffffe + +; A write that fails; check flags too. + move.d d,r4 + moveq 23,r5 + setf p + clearf c + move.d [r4],r3 + ax + move.d r5,[r4] + move.d [r4],r3 + + bcs 0f + nop + fail + +0: + checkr3 fffffffe + quit + + .data +d: + .dword 42424242 diff --git a/tests/cris/check_movemr.s b/tests/cris/check_movemr.s new file mode 100644 index 000000000..776da7683 --- /dev/null +++ b/tests/cris/check_movemr.s @@ -0,0 +1,79 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 12345678\n10234567\n12345678\n12344567\n12344523\n76543210\nffffffaa\naa\n9911\nffff9911\n78\n56\n3456\n6712\n + + .include "testutils.inc" + start + + .data +mem1: + .dword 0x12345678 +mem2: + .word 0x4567 +mem3: + .byte 0x23 + .dword 0x76543210 + .byte 0xaa,0x11,0x99 + + .text + move.d mem1,r2 + move.d [r2],r3 + test_move_cc 0 0 0 0 + checkr3 12345678 + + move.d mem2,r3 + move.d [r3],r3 + test_move_cc 0 0 0 0 + checkr3 10234567 + + move.d mem1,r2 + move.d [r2+],r3 + test_move_cc 0 0 0 0 + checkr3 12345678 + + move.w [r2+],r3 + test_move_cc 0 0 0 0 + checkr3 12344567 + + move.b [r2+],r3 + test_move_cc 0 0 0 0 + checkr3 12344523 + + move.d [r2+],r3 + test_move_cc 0 0 0 0 + checkr3 76543210 + + movs.b [r2],r3 + test_move_cc 1 0 0 0 + checkr3 ffffffaa + + movu.b [r2+],r3 + test_move_cc 0 0 0 0 + checkr3 aa + + movu.w [r2],r3 + test_move_cc 0 0 0 0 + checkr3 9911 + + movs.w [r2+],r3 + test_move_cc 1 0 0 0 + checkr3 ffff9911 + + move.d mem1,r13 + movs.b [r13+],r3 + test_move_cc 0 0 0 0 + checkr3 78 + + movu.b [r13],r3 + test_move_cc 0 0 0 0 + checkr3 56 + + movs.w [r13+],r3 + test_move_cc 0 0 0 0 + checkr3 3456 + + movu.w [r13+],r3 + test_move_cc 0 0 0 0 + checkr3 6712 + + quit + diff --git a/tests/cris/check_movemrv32.s b/tests/cris/check_movemrv32.s new file mode 100644 index 000000000..dc340afa4 --- /dev/null +++ b/tests/cris/check_movemrv32.s @@ -0,0 +1,97 @@ +# mach: crisv32 +# output: 15\n7\n2\nffff1234\nb\n16\nf\n2\nffffffef\nf\nffff1234\nf\nfffffff4\nd\nfffffff2\n10\nfffffff2\nd\n + + .include "testutils.inc" + .data +x: + .dword 8,9,10,11 +y: + .dword -12,13,-14,15,16 + + start + moveq 7,r0 + moveq 2,r1 + move.d 0xffff1234,r2 + moveq 21,r3 + move.d x,r4 + setf zcvn + movem r2,[r4+] + test_cc 1 1 1 1 + subq 12,r4 + + checkr3 15 + + move.d [r4+],r3 + checkr3 7 + + move.d [r4+],r3 + checkr3 2 + + move.d [r4+],r3 + checkr3 ffff1234 + + move.d [r4+],r3 + checkr3 b + + subq 16,r4 + moveq 22,r0 + moveq 15,r1 + clearf zcvn + movem r0,[r4] + test_cc 0 0 0 0 + move.d [r4+],r3 + checkr3 16 + + move.d r1,r3 + checkr3 f + + move.d [r4+],r3 + checkr3 2 + + subq 8,r4 + moveq 10,r2 + moveq -17,r0 + clearf zc + setf vn + movem r1,[r4] + test_cc 1 0 1 0 + move.d [r4+],r3 + checkr3 ffffffef + + move.d [r4+],r3 + checkr3 f + + move.d [r4+],r3 + checkr3 ffff1234 + + move.d y,r4 + setf zc + clearf vn + movem [r4+],r3 + test_cc 0 1 0 1 + checkr3 f + + move.d r0,r3 + checkr3 fffffff4 + + move.d r1,r3 + checkr3 d + + move.d r2,r3 + checkr3 fffffff2 + + move.d [r4],r3 + checkr3 10 + + subq 8,r4 + setf zcvn + movem [r4+],r0 + test_cc 1 1 1 1 + move.d r0,r3 + checkr3 fffffff2 + + move.d r1,r3 + checkr3 d + + quit + diff --git a/tests/cris/check_moveq.c b/tests/cris/check_moveq.c new file mode 100644 index 000000000..9f71194ac --- /dev/null +++ b/tests/cris/check_moveq.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +#define cris_moveq(dst, src) \ + asm volatile ("moveq %1, %0\n" : "=r" (dst) : "i" (src)); + + + +int main(void) +{ + int t; + + cris_tst_cc_init(); + asm volatile ("setf\tzvnc\n"); + cris_moveq(t, 10); + cris_tst_cc(1, 1, 1, 1); + if (t != 10) + err(); + + /* make sure moveq doesnt clobber the zflag. */ + cris_tst_cc_init(); + asm volatile ("setf vnc\n"); + asm volatile ("clearf z\n"); + cris_moveq(t, 0); + cris_tst_cc(1, 0, 1, 1); + if (t != 0) + err(); + + /* make sure moveq doesnt clobber the nflag. + Also check large immediates */ + cris_tst_cc_init(); + asm volatile ("setf zvc\n"); + asm volatile ("clearf n\n"); + cris_moveq(t, -31); + cris_tst_cc(0, 1, 1, 1); + if (t != -31) + err(); + + cris_tst_cc_init(); + asm volatile ("setf nzvc\n"); + cris_moveq(t, 31); + cris_tst_cc(1, 1, 1, 1); + if (t != 31) + err(); + + pass(); + return 0; +} diff --git a/tests/cris/check_mover.s b/tests/cris/check_mover.s new file mode 100644 index 000000000..c93106f17 --- /dev/null +++ b/tests/cris/check_mover.s @@ -0,0 +1,29 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: ffffff05\nffff0005\n5\nffffff00\n + +; Move between registers. Check that just the subreg is copied. + + .include "testutils.inc" + startnostack + moveq -30,r3 + moveq 5,r4 + move.b r4,r3 + test_move_cc 0 0 0 0 ; FIXME + checkr3 ffffff05 + + move.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff0005 + + move.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 5 + + moveq -1,r3 + moveq 0,r4 + move.b r4,r3 + test_move_cc 0 1 0 0 + checkr3 ffffff00 + + quit + diff --git a/tests/cris/check_moverm.s b/tests/cris/check_moverm.s new file mode 100644 index 000000000..95498464e --- /dev/null +++ b/tests/cris/check_moverm.s @@ -0,0 +1,45 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 7823fec2\n10231879\n102318fe\n + + .include "testutils.inc" + start + + .data +mem1: + .dword 0x12345678 +mem2: + .word 0x4567 +mem3: + .byte 0x23 + .dword 0x76543210 + .byte 0xaa,0x11,0x99 + + .text + move.d mem1,r2 + move.d 0x7823fec2,r4 + setf nzvc + move.d r4,[r2+] + test_cc 1 1 1 1 + subq 4,r2 + move.d [r2],r3 + checkr3 7823fec2 + + move.d mem2,r3 + move.d 0x45231879,r4 + clearf nzvc + move.w r4,[r3] + test_cc 0 0 0 0 + move.d [r3],r3 + checkr3 10231879 + + move.d mem2,r2 + moveq -2,r4 + clearf nc + setf zv + move.b r4,[r2+] + test_cc 0 1 1 0 + subq 1,r2 + move.d [r2],r3 + checkr3 102318ff + + quit diff --git a/tests/cris/check_movmp.s b/tests/cris/check_movmp.s new file mode 100644 index 000000000..7fc11f064 --- /dev/null +++ b/tests/cris/check_movmp.s @@ -0,0 +1,131 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n + +# Test generic "move Ps,[]" and "move [],Pd" insns; the ones with +# functionality common to all models. + + .include "testutils.inc" + start + + .data +filler: + .byte 0xaa + .word 0x4433 + .dword 0x55778866 + .byte 0xcc + + .text +; Test that writing to zero-registers is a nop + .if 0 + ; We used to just ignore the writes, but now an error is emitted. We + ; keep the test-code but disabled, in case we need to change this again. + move 0xaa,p0 + move 0x4433,p4 + move 0x55774433,p8 + .endif + + moveq -1,r3 + setf zcvn + clear.b r3 + test_cc 1 1 1 1 + checkr3 ffffff00 + + moveq -1,r3 + clearf zcvn + clear.w r3 + test_cc 0 0 0 0 + checkr3 ffff0000 + + moveq -1,r3 + clear.d r3 + checkr3 0 + +; "Write" using ordinary memory references too. + .if 0 ; See ".if 0" above. + move.d filler,r6 + move [r6],p0 + move [r6],p4 + move [r6],p8 + .endif + +# ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n + + moveq -1,r3 + clear.b r3 + checkr3 ffffff00 + + moveq -1,r3 + clear.w r3 + checkr3 ffff0000 + + moveq -1,r3 + clear.d r3 + checkr3 0 + +; And postincremented. + .if 0 ; See ".if 0" above. + move [r6+],p0 + move [r6+],p4 + move [r6+],p8 + .endif + +# ffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n + + moveq -1,r3 + clear.b r3 + checkr3 ffffff00 + + moveq -1,r3 + clear.w r3 + checkr3 ffff0000 + + moveq -1,r3 + clear.d r3 + checkr3 0 + +; Now see that we can write to the registers too. +# bb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n +; [PC+] + move.d filler,r9 + move 0xbb113344,srp + move srp,r3 + checkr3 bb113344 + +; [R+] + move [r9+],srp + move srp,r3 + checkr3 664433aa + +; [R] + move [r9],srp + move srp,r3 + checkr3 cc557788 + +; And check writing to memory, clear and srp. + + move.d filler,r9 + move 0xabcde012,srp + setf zcvn + move srp,[r9+] + test_cc 1 1 1 1 + subq 4,r9 + move.d [r9],r3 + checkr3 abcde012 + + clearf zcvn + clear.b [r9] + test_cc 0 0 0 0 + move.d [r9],r3 + checkr3 abcde000 + + addq 2,r9 + clear.w [r9+] + subq 2,r9 + move.d [r9],r3 + checkr3 77880000 + + clear.d [r9] + move.d [r9],r3 + checkr3 0 + + quit diff --git a/tests/cris/check_movpmv32.s b/tests/cris/check_movpmv32.s new file mode 100644 index 000000000..daf0970e4 --- /dev/null +++ b/tests/cris/check_movpmv32.s @@ -0,0 +1,35 @@ +# mach: crisv32 +# output: 11223320\nbb113344\naa557711\n + +# Test v32-specific special registers. FIXME: more registers. + + .include "testutils.inc" + start + .data +store: + .dword 0x11223344 + .dword 0x77665544 + + .text + moveq -1,r3 + move.d store,r4 + move vr,[r4] + move [r4+],mof + move mof,r3 + checkr3 11223320 + + moveq -1,r3 + clearf zcvn + move 0xbb113344,mof + test_cc 0 0 0 0 + move mof,r3 + checkr3 bb113344 + + setf zcvn + move 0xaa557711,mof + test_cc 1 1 1 1 + move mof,[r4] + move.d [r4],r3 + checkr3 aa557711 + + quit diff --git a/tests/cris/check_movpr.s b/tests/cris/check_movpr.s new file mode 100644 index 000000000..eef9bdb4f --- /dev/null +++ b/tests/cris/check_movpr.s @@ -0,0 +1,28 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: ffffff00\nffff0000\n0\nbb113344\n + +# Test generic "move Ps,Rd" and "move Rs,Pd" insns; the ones with +# functionality common to all models. + + .include "testutils.inc" + start + moveq -1,r3 + clear.b r3 + checkr3 ffffff00 + + moveq -1,r3 + clear.w r3 + checkr3 ffff0000 + + moveq -1,r3 + clear.d r3 + checkr3 0 + + moveq -1,r3 + move.d 0xbb113344,r4 + setf zcvn + move r4,srp + move srp,r3 + test_cc 1 1 1 1 + checkr3 bb113344 + quit diff --git a/tests/cris/check_movprv32.s b/tests/cris/check_movprv32.s new file mode 100644 index 000000000..d0d90e124 --- /dev/null +++ b/tests/cris/check_movprv32.s @@ -0,0 +1,21 @@ +# mach: crisv32 +# output: ffffff20\nbb113344\n + +# Test v32-specific special registers. FIXME: more registers. + + .include "testutils.inc" + start + moveq -1,r3 + setf zcvn + move vr,r3 + test_cc 1 1 1 1 + checkr3 ffffff20 + + moveq -1,r3 + move.d 0xbb113344,r4 + clearf cvnz + move r4,mof + test_cc 0 0 0 0 + move mof,r3 + checkr3 bb113344 + quit diff --git a/tests/cris/check_movscr.s b/tests/cris/check_movscr.s new file mode 100644 index 000000000..53c8ce6b5 --- /dev/null +++ b/tests/cris/check_movscr.s @@ -0,0 +1,29 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 42\nffffff85\n7685\nffff8765\n0\n + +; Move constant byte, word, dword to register. Check that sign-extension +; is performed. + + .include "testutils.inc" + start + moveq -1,r3 + movs.b 0x42,r3 + checkr3 42 + + movs.b 0x85,r3 + test_move_cc 1 0 0 0 + checkr3 ffffff85 + + movs.w 0x7685,r3 + test_move_cc 0 0 0 0 + checkr3 7685 + + movs.w 0x8765,r3 + test_move_cc 1 0 0 0 + checkr3 ffff8765 + + movs.w 0,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_movsm.s b/tests/cris/check_movsm.s new file mode 100644 index 000000000..7074336e7 --- /dev/null +++ b/tests/cris/check_movsm.s @@ -0,0 +1,44 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 5\nfffffff5\n5\nfffffff5\n0\n + +; Movs between registers. Check that sign-extension is performed and the +; full register is set. + + .include "testutils.inc" + + .data +x: + .byte 5,-11 + .word 5,-11 + .word 0 + + start + move.d x,r5 + + moveq -1,r3 + movs.b [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 5 + + moveq 0,r3 + movs.b [r5],r3 + test_move_cc 1 0 0 0 + addq 1,r5 + checkr3 fffffff5 + + moveq -1,r3 + movs.w [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 5 + + moveq 0,r3 + movs.w [r5],r3 + test_move_cc 1 0 0 0 + addq 2,r5 + checkr3 fffffff5 + + movs.w [r5],r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_movsr.s b/tests/cris/check_movsr.s new file mode 100644 index 000000000..d1889a7a1 --- /dev/null +++ b/tests/cris/check_movsr.s @@ -0,0 +1,46 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 5\nfffffff5\n5\nfffffff5\n0\n + +; Movs between registers. Check that sign-extension is performed and the +; full register is set. + + .include "testutils.inc" + start + moveq -1,r5 + moveq 5,r4 + move.b r4,r5 + moveq -1,r3 + movs.b r5,r3 + test_move_cc 0 0 0 0 + checkr3 5 + + moveq 0,r5 + moveq -11,r4 + move.b r4,r5 + moveq 0,r3 + movs.b r5,r3 + test_move_cc 1 0 0 0 + checkr3 fffffff5 + + moveq -1,r5 + moveq 5,r4 + move.w r4,r5 + moveq -1,r3 + movs.w r5,r3 + test_move_cc 0 0 0 0 + checkr3 5 + + moveq 0,r5 + moveq -11,r4 + move.w r4,r5 + moveq 0,r3 + movs.w r5,r3 + test_move_cc 1 0 0 0 + checkr3 fffffff5 + + moveq 0,r5 + movs.b r5,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_movucr.s b/tests/cris/check_movucr.s new file mode 100644 index 000000000..7c8487d1a --- /dev/null +++ b/tests/cris/check_movucr.s @@ -0,0 +1,33 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 42\n85\n7685\n8765\n0\n + +; Move constant byte, word, dword to register. Check that zero-extension +; is performed. + + .include "testutils.inc" + start + moveq -1,r3 + movu.b 0x42,r3 + test_move_cc 0 0 0 0 + checkr3 42 + + moveq -1,r3 + movu.b 0x85,r3 + test_move_cc 0 0 0 0 + checkr3 85 + + moveq -1,r3 + movu.w 0x7685,r3 + test_move_cc 0 0 0 0 + checkr3 7685 + + moveq -1,r3 + movu.w 0x8765,r3 + test_move_cc 0 0 0 0 + checkr3 8765 + + movu.b 0,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_movum.s b/tests/cris/check_movum.s new file mode 100644 index 000000000..038e53946 --- /dev/null +++ b/tests/cris/check_movum.s @@ -0,0 +1,40 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 5\nf5\n5\nfff5\n0\n + +; Movu between registers. Check that zero-extension is performed and the +; full register is set. + + .include "testutils.inc" + + .data +x: + .byte 5,-11 + .word 5,-11 + .word 0 + + start + move.d x,r5 + + movu.b [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 5 + + movu.b [r5],r3 + test_move_cc 0 0 0 0 + addq 1,r5 + checkr3 f5 + + movu.w [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 5 + + movu.w [r5],r3 + test_move_cc 0 0 0 0 + addq 2,r5 + checkr3 fff5 + + movu.w [r5],r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_movur.s b/tests/cris/check_movur.s new file mode 100644 index 000000000..3ecf475f7 --- /dev/null +++ b/tests/cris/check_movur.s @@ -0,0 +1,45 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 5\nf5\n5\nfff5\n0\n + +; Movu between registers. Check that zero-extension is performed and the +; full register is set. + + .include "testutils.inc" + start + moveq -1,r5 + moveq 5,r4 + move.b r4,r5 + moveq -1,r3 + movu.b r5,r3 + test_move_cc 0 0 0 0 + checkr3 5 + + moveq 0,r5 + moveq -11,r4 + move.b r4,r5 + moveq -1,r3 + movu.b r5,r3 + test_move_cc 0 0 0 0 + checkr3 f5 + + moveq -1,r5 + moveq 5,r4 + move.w r4,r5 + moveq -1,r3 + movu.w r5,r3 + test_move_cc 0 0 0 0 + checkr3 5 + + moveq 0,r5 + moveq -11,r4 + move.w r4,r5 + moveq -1,r3 + movu.w r5,r3 + test_move_cc 0 0 0 0 + checkr3 fff5 + + movu.w 0,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + quit diff --git a/tests/cris/check_mulv32.s b/tests/cris/check_mulv32.s new file mode 100644 index 000000000..f37935876 --- /dev/null +++ b/tests/cris/check_mulv32.s @@ -0,0 +1,51 @@ +# mach: crisv32 +# output: fffffffe\n +# output: ffffffff\n +# output: fffffffe\n +# output: 1\n +# output: fffffffe\n +# output: ffffffff\n +# output: fffffffe\n +# output: 1\n + +; Check that carry is not modified on v32. + + .include "testutils.inc" + start + moveq -1,r3 + moveq 2,r4 + setf c + muls.d r4,r3 + test_cc 1 0 0 1 + checkr3 fffffffe + move mof,r3 + checkr3 ffffffff + + moveq -1,r3 + moveq 2,r4 + setf c + mulu.d r4,r3 + test_cc 0 0 1 1 + checkr3 fffffffe + move mof,r3 + checkr3 1 + + moveq -1,r3 + moveq 2,r4 + clearf c + muls.d r4,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + move mof,r3 + checkr3 ffffffff + + moveq -1,r3 + moveq 2,r4 + clearf c + mulu.d r4,r3 + test_cc 0 0 1 0 + checkr3 fffffffe + move mof,r3 + checkr3 1 + + quit diff --git a/tests/cris/check_mulx.s b/tests/cris/check_mulx.s new file mode 100644 index 000000000..d43241a6f --- /dev/null +++ b/tests/cris/check_mulx.s @@ -0,0 +1,246 @@ +# mach: crisv10 crisv32 +# output: fffffffe\nffffffff\nfffffffe\n1\nfffffffe\nffffffff\nfffffffe\n1\nfffe0001\n0\nfffe0001\n0\n1\n0\n1\nfffffffe\n193eade2\n277e3a49\n193eade2\n277e3a49\nfffffffe\nffffffff\n1fffe\n0\nfffffffe\nffffffff\n1fffe\n0\n1\n0\nfffe0001\n0\nfdbdade2\nffffffff\n420fade2\n0\nfffffffe\nffffffff\n1fe\n0\nfffffffe\nffffffff\n1fe\n0\n1\n0\nfe01\n0\n1\n0\nfe01\n0\nffffd9e2\nffffffff\n2be2\n0\n0\n0\n0\n0\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq 2,r4 + muls.d r4,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + move mof,r3 + checkr3 ffffffff + + moveq -1,r3 + moveq 2,r4 + mulu.d r4,r3 + test_cc 0 0 1 0 + checkr3 fffffffe + move mof,r3 + checkr3 1 + + moveq 2,r3 + moveq -1,r4 + muls.d r4,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + move mof,r3 + checkr3 ffffffff + + moveq 2,r3 + moveq -1,r4 + mulu.d r4,r3 + test_cc 0 0 1 0 + checkr3 fffffffe + move mof,r3 + checkr3 1 + + move.d 0xffff,r4 + move.d r4,r3 + muls.d r4,r3 + test_cc 0 0 1 0 + checkr3 fffe0001 + move mof,r3 + checkr3 0 + + move.d 0xffff,r4 + move.d r4,r3 + mulu.d r4,r3 + test_cc 0 0 0 0 + checkr3 fffe0001 + move mof,r3 + checkr3 0 + + moveq -1,r4 + move.d r4,r3 + muls.d r4,r3 + test_cc 0 0 0 0 + checkr3 1 + move mof,r3 + checkr3 0 + + moveq -1,r4 + move.d r4,r3 + mulu.d r4,r3 + test_cc 1 0 1 0 + checkr3 1 + move mof,r3 + checkr3 fffffffe + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + muls.d r4,r3 + test_cc 0 0 1 0 + checkr3 193eade2 + move mof,r3 + checkr3 277e3a49 + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + mulu.d r4,r3 + test_cc 0 0 1 0 + checkr3 193eade2 + move mof,r3 + checkr3 277e3a49 + + move.d 0xffff,r3 + moveq 2,r4 + muls.w r4,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + move mof,r3 + checkr3 ffffffff + + moveq -1,r3 + moveq 2,r4 + mulu.w r4,r3 + test_cc 0 0 0 0 + checkr3 1fffe + move mof,r3 + checkr3 0 + + moveq 2,r3 + move.d 0xffff,r4 + muls.w r4,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + move mof,r3 + checkr3 ffffffff + + moveq 2,r3 + moveq -1,r4 + mulu.w r4,r3 + test_cc 0 0 0 0 + checkr3 1fffe + move mof,r3 + checkr3 0 + + move.d 0xffff,r4 + move.d r4,r3 + muls.w r4,r3 + test_cc 0 0 0 0 + checkr3 1 + move mof,r3 + checkr3 0 + + moveq -1,r4 + move.d r4,r3 + mulu.w r4,r3 + test_cc 0 0 0 0 + checkr3 fffe0001 + move mof,r3 + checkr3 0 + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + muls.w r4,r3 + test_cc 1 0 0 0 + checkr3 fdbdade2 + move mof,r3 + checkr3 ffffffff + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + mulu.w r4,r3 + test_cc 0 0 0 0 + checkr3 420fade2 + move mof,r3 + checkr3 0 + + move.d 0xff,r3 + moveq 2,r4 + muls.b r4,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + move mof,r3 + checkr3 ffffffff + + moveq -1,r3 + moveq 2,r4 + mulu.b r4,r3 + test_cc 0 0 0 0 + checkr3 1fe + move mof,r3 + checkr3 0 + + moveq 2,r3 + moveq -1,r4 + muls.b r4,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + move mof,r3 + checkr3 ffffffff + + moveq 2,r3 + moveq -1,r4 + mulu.b r4,r3 + test_cc 0 0 0 0 + checkr3 1fe + move mof,r3 + checkr3 0 + + move.d 0xff,r4 + move.d r4,r3 + muls.b r4,r3 + test_cc 0 0 0 0 + checkr3 1 + move mof,r3 + checkr3 0 + + moveq -1,r4 + move.d r4,r3 + mulu.b r4,r3 + test_cc 0 0 0 0 + checkr3 fe01 + move mof,r3 + checkr3 0 + + move.d 0xfeda49ff,r4 + move.d r4,r3 + muls.b r4,r3 + test_cc 0 0 0 0 + checkr3 1 + move mof,r3 + checkr3 0 + + move.d 0xfeda49ff,r4 + move.d r4,r3 + mulu.b r4,r3 + test_cc 0 0 0 0 + checkr3 fe01 + move mof,r3 + checkr3 0 + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + muls.b r4,r3 + test_cc 1 0 0 0 + checkr3 ffffd9e2 + move mof,r3 + checkr3 ffffffff + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + mulu.b r4,r3 + test_cc 0 0 0 0 + checkr3 2be2 + move mof,r3 + checkr3 0 + + moveq 0,r3 + move.d 0xf87f4aeb,r4 + muls.d r4,r3 + test_cc 0 1 0 0 + checkr3 0 + move mof,r3 + checkr3 0 + + move.d 0xf87f4aeb,r3 + moveq 0,r4 + mulu.d r4,r3 + test_cc 0 1 0 0 + checkr3 0 + move mof,r3 + checkr3 0 + + quit diff --git a/tests/cris/check_neg.s b/tests/cris/check_neg.s new file mode 100644 index 000000000..963c4b6f5 --- /dev/null +++ b/tests/cris/check_neg.s @@ -0,0 +1,104 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: ffffffff\nffffffff\n0\n80000000\n1\nba987655\nffff\nffff\n0\n89ab8000\nffff0001\n45677655\nff\nff\n0\n89abae80\nffffff01\n45678955\n + + .include "testutils.inc" + start + moveq 0,r3 + moveq 1,r4 + neg.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 1,r3 + moveq 0,r4 + neg.d r3,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + +;; FIXME: this was wrong. + moveq 0,r3 + neg.d r3,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0x80000000,r3 + neg.d r3,r3 + test_move_cc 1 0 0 0 + checkr3 80000000 + + moveq -1,r3 + neg.d r3,r3 + test_move_cc 0 0 0 0 + checkr3 1 + + move.d 0x456789ab,r3 + neg.d r3,r3 + test_move_cc 1 0 0 0 + checkr3 ba987655 + + moveq 0,r3 + moveq 1,r4 + neg.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffff + + moveq 1,r3 + moveq 0,r4 + neg.w r3,r3 + test_move_cc 1 0 0 0 + checkr3 ffff + + moveq 0,r3 + neg.w r3,r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0x89ab8000,r3 + neg.w r3,r3 + test_move_cc 1 0 0 0 + checkr3 89ab8000 + + moveq -1,r3 + neg.w r3,r3 + test_move_cc 0 0 0 0 + checkr3 ffff0001 + + move.d 0x456789ab,r3 + neg.w r3,r3 + test_move_cc 0 0 0 0 + checkr3 45677655 + + moveq 0,r3 + moveq 1,r4 + neg.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 ff + + moveq 1,r3 + moveq 0,r4 + neg.b r3,r3 + test_move_cc 1 0 0 0 + checkr3 ff + + moveq 0,r3 + neg.b r3,r3 + test_move_cc 0 1 0 0 + checkr3 0 + +;; FIXME: was wrong. + move.d 0x89abae80,r3 + neg.b r3,r3 + test_move_cc 1 0 0 1 + checkr3 89abae80 + + moveq -1,r3 + neg.b r3,r3 + test_move_cc 0 0 0 0 + checkr3 ffffff01 + + move.d 0x456789ab,r3 + neg.b r3,r3 + test_move_cc 0 0 0 0 + checkr3 45678955 + + quit diff --git a/tests/cris/check_not.s b/tests/cris/check_not.s new file mode 100644 index 000000000..33bcf155e --- /dev/null +++ b/tests/cris/check_not.s @@ -0,0 +1,31 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: fffffffe\nfffffffd\nffff0f00\n0\n87ecbbad\n + + .include "testutils.inc" + start + moveq 1,r3 + not r3 + test_move_cc 1 0 0 0 + checkr3 fffffffe + + moveq 2,r3 + not r3 + test_move_cc 1 0 0 0 + checkr3 fffffffd + + move.d 0xf0ff,r3 + not r3 + test_move_cc 1 0 0 0 + checkr3 ffff0f00 + + moveq -1,r3 + not r3 + test_move_cc 0 1 0 0 + checkr3 0 + + move.d 0x78134452,r3 + not r3 + test_move_cc 1 0 0 0 + checkr3 87ecbbad + + quit diff --git a/tests/cris/check_openpf1.c b/tests/cris/check_openpf1.c new file mode 100644 index 000000000..1d71e0bdd --- /dev/null +++ b/tests/cris/check_openpf1.c @@ -0,0 +1,38 @@ +/* Check that --sysroot is applied to open(2). +#sim: --sysroot=@exedir@ + + We assume, with EXE being the name of the executable: + - The simulator executes with cwd the same directory where the executable + is located (so argv[0] contains a plain filename without directory + components). + - There's no /EXE on the host file system. */ + +#include +#include +#include +#include +int main (int argc, char *argv[]) +{ + char *fnam = argv[0]; + FILE *f; + if (argv[0][0] != '/') + { + fnam = malloc (strlen (argv[0]) + 2); + if (fnam == NULL) + abort (); + strcpy (fnam, "/"); + strcat (fnam, argv[0]); + } + + f = fopen (fnam, "rb"); + if (f == NULL) + abort (); + close (f); + + /* Cover another execution path. */ + if (fopen ("/nonexistent", "rb") != NULL + || errno != ENOENT) + abort (); + printf ("pass\n"); + return 0; +} diff --git a/tests/cris/check_openpf2.c b/tests/cris/check_openpf2.c new file mode 100644 index 000000000..f44a8f34b --- /dev/null +++ b/tests/cris/check_openpf2.c @@ -0,0 +1,16 @@ +/* Check that the simulator has chdir:ed to the --sysroot argument +#sim: --sysroot=@srcdir@ + (or that --sysroot is applied to relative file paths). */ + +#include +#include +#include +int main (int argc, char *argv[]) +{ + FILE *f = fopen ("check_openpf2.c", "rb"); + if (f == NULL) + abort (); + close (f); + printf ("pass\n"); + return 0; +} diff --git a/tests/cris/check_openpf3.c b/tests/cris/check_openpf3.c new file mode 100644 index 000000000..557adee92 --- /dev/null +++ b/tests/cris/check_openpf3.c @@ -0,0 +1,49 @@ +/* Basic file operations (rename, unlink); once without sysroot. We + also test that the simulator has chdir:ed to PREFIX, when defined. */ + +#include +#include +#include +#include +#include +#include + +#ifndef PREFIX +#define PREFIX +#endif + +void err (const char *s) +{ + perror (s); + abort (); +} + +int main (int argc, char *argv[]) +{ + FILE *f; + struct stat buf; + + unlink (PREFIX "testfoo2.tmp"); + + f = fopen ("testfoo1.tmp", "w"); + if (f == NULL) + err ("open"); + fclose (f); + + if (rename (PREFIX "testfoo1.tmp", PREFIX "testfoo2.tmp") != 0) + err ("rename"); + + if (stat (PREFIX "testfoo2.tmp", &buf) != 0 + || !S_ISREG (buf.st_mode)) + err ("stat 1"); + + if (stat ("testfoo2.tmp", &buf) != 0 + || !S_ISREG (buf.st_mode)) + err ("stat 2"); + + if (unlink (PREFIX "testfoo2.tmp") != 0) + err ("unlink"); + + printf ("pass\n"); + return 0; +} diff --git a/tests/cris/check_openpf4.c b/tests/cris/check_openpf4.c new file mode 100644 index 000000000..8bbee41a6 --- /dev/null +++ b/tests/cris/check_openpf4.c @@ -0,0 +1,5 @@ +/* Basic file operations, now *with* sysroot. +#sim: --sysroot=@exedir@ +*/ +#define PREFIX "/" +#include "check_openpf3.c" diff --git a/tests/cris/check_openpf5.c b/tests/cris/check_openpf5.c new file mode 100644 index 000000000..1f86ea283 --- /dev/null +++ b/tests/cris/check_openpf5.c @@ -0,0 +1,56 @@ +/* Check that TRT happens when error on too many opened files. +#notarget: cris*-*-elf +#sim: --sysroot=@exedir@ +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + int i; + int filemax; + +#ifdef OPEN_MAX + filemax = OPEN_MAX; +#else + filemax = sysconf (_SC_OPEN_MAX); +#endif + + char *fn = malloc (strlen (argv[0]) + 2); + if (fn == NULL) + abort (); + strcpy (fn, "/"); + strcat (fn, argv[0]); + + for (i = 0; i < filemax + 1; i++) + { + if (open (fn, O_RDONLY) < 0) + { + /* Shouldn't happen too early. */ + if (i < filemax - 3 - 1) + { + fprintf (stderr, "i: %d\n", i); + abort (); + } + if (errno != EMFILE) + { + perror ("open"); + abort (); + } + goto ok; + } + } + abort (); + +ok: + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_orc.s b/tests/cris/check_orc.s new file mode 100644 index 000000000..c733f036a --- /dev/null +++ b/tests/cris/check_orc.s @@ -0,0 +1,71 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n + + .include "testutils.inc" + start + moveq 1,r3 + or.d 2,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + moveq 2,r3 + or.d 1,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0xf0ff,r3 + or.d 0xff0f,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r3 + or.d -1,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x78134452,r3 + or.d 0x5432f789,r3 + test_move_cc 0 0 0 0 + checkr3 7c33f7db + + move.d 0xffff0001,r3 + or.w 2,r3 + test_move_cc 0 0 0 0 + checkr3 ffff0003 + + moveq 2,r3 + or.w 1,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0xfedaffaf,r3 + or.w 0xff5f,r3 + test_move_cc 1 0 0 0 + checkr3 fedaffff + + move.d 0x78134452,r3 + or.w 0xf789,r3 + test_move_cc 1 0 0 0 + checkr3 7813f7db + + moveq 1,r3 + or.b 2,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + moveq 2,r3 + or.b 1,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0xfa3,r3 + or.b 0x4a,r3 + test_move_cc 1 0 0 0 + checkr3 feb + + move.d 0x78134453,r3 + or.b 0x89,r3 + test_move_cc 1 0 0 0 + checkr3 781344db + + quit diff --git a/tests/cris/check_orm.s b/tests/cris/check_orm.s new file mode 100644 index 000000000..ee723a6aa --- /dev/null +++ b/tests/cris/check_orm.s @@ -0,0 +1,75 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n + + .include "testutils.inc" + .data +x: + .dword 2,1,0xff0f,-1,0x5432f789 + .word 2,1,0xff5f,0xf789 + .byte 2,1,0x4a,0x89 + + start + moveq 1,r3 + move.d x,r5 + or.d [r5+],r3 + checkr3 3 + + moveq 2,r3 + or.d [r5],r3 + addq 4,r5 + checkr3 3 + + move.d 0xf0ff,r3 + or.d [r5+],r3 + checkr3 ffff + + moveq -1,r3 + or.d [r5+],r3 + checkr3 ffffffff + + move.d 0x78134452,r3 + or.d [r5+],r3 + checkr3 7c33f7db + + move.d 0xffff0001,r3 + or.w [r5+],r3 + checkr3 ffff0003 + + moveq 2,r3 + or.w [r5],r3 + addq 2,r5 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0xfedaffaf,r3 + or.w [r5+],r3 + test_move_cc 1 0 0 0 + checkr3 fedaffff + + move.d 0x78134452,r3 + or.w [r5+],r3 + test_move_cc 1 0 0 0 + checkr3 7813f7db + + moveq 1,r3 + or.b [r5+],r3 + test_move_cc 0 0 0 0 + checkr3 3 + + moveq 2,r3 + or.b [r5],r3 + addq 1,r5 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0xfa3,r3 + or.b [r5+],r3 + test_move_cc 1 0 0 0 + checkr3 feb + + move.d 0x78134453,r3 + or.b [r5],r3 + test_move_cc 1 0 0 0 + checkr3 781344db + + quit diff --git a/tests/cris/check_orq.s b/tests/cris/check_orq.s new file mode 100644 index 000000000..5060edc72 --- /dev/null +++ b/tests/cris/check_orq.s @@ -0,0 +1,41 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 3\n3\nffffffff\nffffffff\n1f\nffffffe0\n7813445e\n + + .include "testutils.inc" + start + moveq 1,r3 + orq 2,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + moveq 2,r3 + orq 1,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0xf0ff,r3 + orq -1,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 0,r3 + orq -1,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + moveq 0,r3 + orq 31,r3 + test_move_cc 0 0 0 0 + checkr3 1f + + moveq 0,r3 + orq -32,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffe0 + + move.d 0x78134452,r3 + orq 12,r3 + test_move_cc 0 0 0 0 + checkr3 7813445e + + quit diff --git a/tests/cris/check_orr.s b/tests/cris/check_orr.s new file mode 100644 index 000000000..a514c11bc --- /dev/null +++ b/tests/cris/check_orr.s @@ -0,0 +1,84 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n + + .include "testutils.inc" + start + moveq 1,r3 + moveq 2,r4 + or.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + moveq 2,r3 + moveq 1,r4 + or.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0xff0f,r4 + move.d 0xf0ff,r3 + or.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff + + moveq -1,r4 + move.d r4,r3 + or.d r4,r3 + test_move_cc 1 0 0 0 + checkr3 ffffffff + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + or.d r4,r3 + test_move_cc 0 0 0 0 + checkr3 7c33f7db + + move.d 0xffff0001,r3 + moveq 2,r4 + or.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 ffff0003 + + moveq 2,r3 + move.d 0xffff0001,r4 + or.w r4,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0xfedaffaf,r3 + move.d 0xffffff5f,r4 + or.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 fedaffff + + move.d 0x5432f789,r4 + move.d 0x78134452,r3 + or.w r4,r3 + test_move_cc 1 0 0 0 + checkr3 7813f7db + + moveq 1,r3 + move.d 0xffffff02,r4 + or.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + moveq 2,r3 + moveq 1,r4 + or.b r4,r3 + test_move_cc 0 0 0 0 + checkr3 3 + + move.d 0x4a,r4 + move.d 0xfa3,r3 + or.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 feb + + move.d 0x5432f789,r4 + move.d 0x78134453,r3 + or.b r4,r3 + test_move_cc 1 0 0 0 + checkr3 781344db + + quit diff --git a/tests/cris/check_ret.s b/tests/cris/check_ret.s new file mode 100644 index 000000000..b44fb2593 --- /dev/null +++ b/tests/cris/check_ret.s @@ -0,0 +1,25 @@ +# mach: crisv3 crisv8 crisv10 +# output: 3\n + +# Test that ret works. + + .include "testutils.inc" + start +x: + moveq 0,r3 + jsr z +w: + quit +y: + addq 1,r3 + checkr3 3 + quit + +z: + addq 1,r3 + move srp,r2 + add.d y-w,r2 + move r2,srp + ret + addq 1,r3 + quit diff --git a/tests/cris/check_scc.s b/tests/cris/check_scc.s new file mode 100644 index 000000000..4a8674cc1 --- /dev/null +++ b/tests/cris/check_scc.s @@ -0,0 +1,95 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n0\n1\n1\n0\n1\n0\n0\n1\n1\n0\n1\n1\n0\n + + .include "testutils.inc" + + .macro lcheckr3 v + move $ccs, $r9 + checkr3 \v + move $r9, $ccs + .endm + + start + clearf nzvc + scc r3 + lcheckr3 1 + scs r3 + lcheckr3 0 + sne r3 + lcheckr3 1 + seq r3 + lcheckr3 0 + svc r3 + lcheckr3 1 + svs r3 + lcheckr3 0 + spl r3 + lcheckr3 1 + smi r3 + lcheckr3 0 + sls r3 + lcheckr3 0 + shi r3 + lcheckr3 1 + sge r3 + lcheckr3 1 + slt r3 + lcheckr3 0 + sgt r3 + lcheckr3 1 + sle r3 + lcheckr3 0 + sa r3 + lcheckr3 1 + setf nzvc + scc r3 + lcheckr3 0 + scs r3 + lcheckr3 1 + sne r3 + lcheckr3 0 + svc r3 + lcheckr3 0 + svs r3 + lcheckr3 1 + spl r3 + lcheckr3 0 + smi r3 + lcheckr3 1 + sls r3 + lcheckr3 1 + shi r3 + lcheckr3 0 + sge r3 + lcheckr3 1 + slt r3 + lcheckr3 0 + sgt r3 + lcheckr3 0 + sle r3 + lcheckr3 1 + sa r3 + lcheckr3 1 + clearf n + sge r3 + lcheckr3 0 + slt r3 + lcheckr3 1 + + .if 1 ;..asm.arch.cris.v32 + setf p + ssb r3 + .else + moveq 1,r3 + .endif + lcheckr3 1 + + .if 1 ;..asm.arch.cris.v32 + clearf p + ssb r3 + .else + moveq 0,r3 + .endif + lcheckr3 0 + + quit diff --git a/tests/cris/check_stat1.c b/tests/cris/check_stat1.c new file mode 100644 index 000000000..2e2cae51d --- /dev/null +++ b/tests/cris/check_stat1.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#include + +int main (void) +{ + struct stat buf; + + if (stat (".", &buf) != 0 + || !S_ISDIR (buf.st_mode)) + abort (); + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_stat2.c b/tests/cris/check_stat2.c new file mode 100644 index 000000000..e36172ed2 --- /dev/null +++ b/tests/cris/check_stat2.c @@ -0,0 +1,20 @@ +/* +#notarget: cris*-*-elf +*/ + +#include +#include +#include +#include +#include + +int main (void) +{ + struct stat buf; + + if (lstat (".", &buf) != 0 + || !S_ISDIR (buf.st_mode)) + abort (); + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_stat3.c b/tests/cris/check_stat3.c new file mode 100644 index 000000000..a248ec086 --- /dev/null +++ b/tests/cris/check_stat3.c @@ -0,0 +1,26 @@ +/* Simulator options: +#sim: --sysroot=@exedir@ +*/ +#include +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + char path[1024] = "/"; + struct stat buf; + + strcat (path, argv[0]); + if (stat (".", &buf) != 0 + || !S_ISDIR (buf.st_mode)) + abort (); + if (stat (path, &buf) != 0 + || !S_ISREG (buf.st_mode)) + abort (); + printf ("pass\n"); + exit (0); +} + diff --git a/tests/cris/check_stat4.c b/tests/cris/check_stat4.c new file mode 100644 index 000000000..d10655d40 --- /dev/null +++ b/tests/cris/check_stat4.c @@ -0,0 +1,28 @@ +/* Simulator options: +#notarget: cris*-*-elf +#sim: --sysroot=@exedir@ +*/ + +#include +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + char path[1024] = "/"; + struct stat buf; + + strcat (path, argv[0]); + if (lstat (".", &buf) != 0 + || !S_ISDIR (buf.st_mode)) + abort (); + if (lstat (path, &buf) != 0 + || !S_ISREG (buf.st_mode)) + abort (); + printf ("pass\n"); + exit (0); +} + diff --git a/tests/cris/check_subc.s b/tests/cris/check_subc.s new file mode 100644 index 000000000..e34b5448e --- /dev/null +++ b/tests/cris/check_subc.s @@ -0,0 +1,87 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n + + .include "testutils.inc" + start + + moveq -1,r3 + sub.d -2,r3 + test_cc 0 0 0 0 + checkr3 1 + + moveq 2,r3 + sub.d 1,r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d 0xffff,r3 + sub.d -0xffff,r3 + test_cc 0 0 0 1 + checkr3 1fffe + + moveq -1,r3 + sub.d 1,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + + move.d 0x78134452,r3 + sub.d -0x5432f789,r3 + test_cc 1 0 1 1 + checkr3 cc463bdb + + moveq -1,r3 + sub.w -2,r3 + test_cc 0 0 0 0 + checkr3 ffff0001 + + moveq 2,r3 + sub.w 1,r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d 0xffff,r3 + sub.w 1,r3 + test_cc 1 0 0 0 + checkr3 fffe + + move.d 0xfedaffff,r3 + sub.w 1,r3 + test_cc 1 0 0 0 + checkr3 fedafffe + + move.d 0x78134452,r3 + sub.w 0x877,r3 + test_cc 0 0 0 0 + checkr3 78133bdb + + moveq -1,r3 + sub.b -2,r3 + test_cc 0 0 0 0 + checkr3 ffffff01 + + moveq 2,r3 + sub.b 1,r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d 0xff,r3 + sub.b 1,r3 + test_cc 1 0 0 0 + checkr3 fe + + move.d 0xfeda49ff,r3 + sub.b 1,r3 + test_cc 1 0 0 0 + checkr3 feda49fe + + move.d 0x78134452,r3 + sub.b 0x77,r3 + test_cc 1 0 0 1 + checkr3 781344db + + move.d 0x85649282,r3 + sub.b 0x82,r3 + test_cc 0 1 0 0 + checkr3 85649200 + + quit diff --git a/tests/cris/check_subm.s b/tests/cris/check_subm.s new file mode 100644 index 000000000..e07ea02dd --- /dev/null +++ b/tests/cris/check_subm.s @@ -0,0 +1,96 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n + + .include "testutils.inc" + .data +x: + .dword -2,1,-0xffff,1,-0x5432f789 + .word -2,1,1,0x877 + .byte -2,1,0x77 + .byte 0x22 + + start + moveq -1,r3 + move.d x,r5 + sub.d [r5+],r3 + test_cc 0 0 0 0 + checkr3 1 + + moveq 2,r3 + sub.d [r5],r3 + test_cc 0 0 0 0 + addq 4,r5 + checkr3 1 + + move.d 0xffff,r3 + sub.d [r5+],r3 + test_cc 0 0 0 1 + checkr3 1fffe + + moveq -1,r3 + sub.d [r5+],r3 + test_cc 1 0 0 0 + checkr3 fffffffe + + move.d 0x78134452,r3 + sub.d [r5+],r3 + test_cc 1 0 1 1 + checkr3 cc463bdb + + moveq -1,r3 + sub.w [r5+],r3 + test_cc 0 0 0 0 + checkr3 ffff0001 + + moveq 2,r3 + sub.w [r5+],r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d 0xffff,r3 + sub.w [r5],r3 + test_cc 1 0 0 0 + checkr3 fffe + + move.d 0xfedaffff,r3 + sub.w [r5+],r3 + test_cc 1 0 0 0 + checkr3 fedafffe + + move.d 0x78134452,r3 + sub.w [r5+],r3 + test_cc 0 0 0 0 + checkr3 78133bdb + + moveq -1,r3 + sub.b [r5],r3 + test_cc 0 0 0 0 + addq 1,r5 + checkr3 ffffff01 + + moveq 2,r3 + sub.b [r5],r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d 0xff,r3 + sub.b [r5],r3 + test_cc 1 0 0 0 + checkr3 fe + + move.d 0xfeda49ff,r3 + sub.b [r5+],r3 + test_cc 1 0 0 0 + checkr3 feda49fe + + move.d 0x78134452,r3 + sub.b [r5+],r3 + test_cc 1 0 0 1 + checkr3 781344db + + move.d 0x85649222,r3 + sub.b [r5],r3 + test_cc 0 1 0 0 + checkr3 85649200 + + quit diff --git a/tests/cris/check_subq.s b/tests/cris/check_subq.s new file mode 100644 index 000000000..9e34fa31a --- /dev/null +++ b/tests/cris/check_subq.s @@ -0,0 +1,52 @@ +# mach: crisv3 crisv8 crisv10 crisv32 +# output: 0\nffffffff\nfffffffe\nffff\nff\n56788f9\n56788d9\n567889a\n0\n7ffffffc\n + + .include "testutils.inc" + start + moveq 1,r3 + subq 1,r3 + test_cc 0 1 0 0 + checkr3 0 + + subq 1,r3 + test_cc 1 0 0 1 + checkr3 ffffffff + + subq 1,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + + move.d 0x10000,r3 + subq 1,r3 + test_cc 0 0 0 0 + checkr3 ffff + + move.d 0x100,r3 + subq 1,r3 + test_cc 0 0 0 0 + checkr3 ff + + move.d 0x5678900,r3 + subq 7,r3 + test_cc 0 0 0 0 + checkr3 56788f9 + + subq 32,r3 + test_cc 0 0 0 0 + checkr3 56788d9 + + subq 63,r3 + test_cc 0 0 0 0 + checkr3 567889a + + move.d 34,r3 + subq 34,r3 + test_cc 0 1 0 0 + checkr3 0 + + move.d 0x80000024,r3 + subq 40,r3 + test_cc 0 0 1 0 + checkr3 7ffffffc + + quit diff --git a/tests/cris/check_subr.s b/tests/cris/check_subr.s new file mode 100644 index 000000000..742fbc891 --- /dev/null +++ b/tests/cris/check_subr.s @@ -0,0 +1,102 @@ +# mach: crisv0 crisv3 crisv8 crisv10 crisv32 +# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n + + .include "testutils.inc" + start + moveq -1,r3 + moveq -2,r4 + sub.d r4,r3 + test_cc 0 0 0 0 + checkr3 1 + + moveq 2,r3 + moveq 1,r4 + sub.d r4,r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d 0xffff,r3 + move.d -0xffff,r4 + sub.d r4,r3 + test_cc 0 0 0 1 + checkr3 1fffe + + moveq 1,r4 + moveq -1,r3 + sub.d r4,r3 + test_cc 1 0 0 0 + checkr3 fffffffe + + move.d -0x5432f789,r4 + move.d 0x78134452,r3 + sub.d r4,r3 + test_cc 1 0 1 1 + checkr3 cc463bdb + + moveq -1,r3 + moveq -2,r4 + sub.w r4,r3 + test_cc 0 0 0 0 + checkr3 ffff0001 + + moveq 2,r3 + moveq 1,r4 + sub.w r4,r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d 0xffff,r3 + move.d -0xffff,r4 + sub.w r4,r3 + test_cc 1 0 0 0 + checkr3 fffe + + move.d 0xfedaffff,r3 + move.d -0xfedaffff,r4 + sub.w r4,r3 + test_cc 1 0 0 0 + checkr3 fedafffe + + move.d -0x5432f789,r4 + move.d 0x78134452,r3 + sub.w r4,r3 + test_cc 0 0 0 0 + checkr3 78133bdb + + moveq -1,r3 + moveq -2,r4 + sub.b r4,r3 + test_cc 0 0 0 0 + checkr3 ffffff01 + + moveq 2,r3 + moveq 1,r4 + sub.b r4,r3 + test_cc 0 0 0 0 + checkr3 1 + + move.d -0xff,r4 + move.d 0xff,r3 + sub.b r4,r3 + test_cc 1 0 0 0 + checkr3 fe + + move.d -0xfeda49ff,r4 + move.d 0xfeda49ff,r3 + sub.b r4,r3 + test_cc 1 0 0 0 + checkr3 feda49fe + + move.d -0x5432f789,r4 + move.d 0x78134452,r3 + sub.b r4,r3 + test_cc 1 0 0 1 + checkr3 781344db + + move.d 0x85649222,r3 + move.d 0x77445622,r4 + sub.b r4,r3 + test_cc 0 1 0 0 + checkr3 85649200 + + quit diff --git a/tests/cris/check_swap.c b/tests/cris/check_swap.c new file mode 100644 index 000000000..c1eac88e5 --- /dev/null +++ b/tests/cris/check_swap.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include "sys.h" +#include "crisutils.h" + +#define N 8 +#define W 4 +#define B 2 +#define R 1 + +extern inline int cris_swap(const int mode, int x) +{ + switch (mode) + { + case N: asm ("swapn\t%0\n" : "+r" (x) : "0" (x)); break; + case W: asm ("swapw\t%0\n" : "+r" (x) : "0" (x)); break; + case B: asm ("swapb\t%0\n" : "+r" (x) : "0" (x)); break; + case R: asm ("swapr\t%0\n" : "+r" (x) : "0" (x)); break; + case B|R: asm ("swapbr\t%0\n" : "+r" (x) : "0" (x)); break; + case W|R: asm ("swapwr\t%0\n" : "+r" (x) : "0" (x)); break; + case W|B: asm ("swapwb\t%0\n" : "+r" (x) : "0" (x)); break; + case W|B|R: asm ("swapwbr\t%0\n" : "+r" (x) : "0" (x)); break; + case N|R: asm ("swapnr\t%0\n" : "+r" (x) : "0" (x)); break; + case N|B: asm ("swapnb\t%0\n" : "+r" (x) : "0" (x)); break; + case N|B|R: asm ("swapnbr\t%0\n" : "+r" (x) : "0" (x)); break; + case N|W: asm ("swapnw\t%0\n" : "+r" (x) : "0" (x)); break; + default: + err(); + break; + } + return x; +} + +/* Made this a macro to be able to pick up the location of the errors. */ +#define verify_swap(mode, val, expected, n, z) \ +do { \ + int r; \ + cris_tst_cc_init(); \ + r = cris_swap(mode, val); \ + cris_tst_mov_cc(n, z); \ + if (r != expected) \ + err(); \ +} while(0); + +void check_swap(void) +{ + /* Some of these numbers are borrowed from GDB's cris sim + testsuite. */ + if (cris_swap(N, 0) != 0xffffffff) + err(); + if (cris_swap(W, 0x12345678) != 0x56781234) + err(); + if (cris_swap(B, 0x12345678) != 0x34127856) + err(); + + verify_swap(R, 0x78134452, 0x1ec8224a, 0, 0); + verify_swap(B, 0x78134452, 0x13785244, 0, 0); + verify_swap(B|R, 0x78134452, 0xc81e4a22, 1, 0); + verify_swap(W, 0x78134452, 0x44527813, 0, 0); + verify_swap(W|R, 0x78134452, 0x224a1ec8, 0, 0); + verify_swap(W|B|R, 0x78134452, 0x4a22c81e, 0, 0); + verify_swap(N, 0x78134452, 0x87ecbbad, 1, 0); + verify_swap(N|R, 0x78134452, 0xe137ddb5, 1, 0); + verify_swap(N|B, 0x78134452, 0xec87adbb, 1, 0); + verify_swap(N|B|R, 0x78134452, 0x37e1b5dd, 0, 0); + verify_swap(N|W, 0x78134452, 0xbbad87ec, 1, 0); + verify_swap(N|B|R, 0xffffffff, 0, 0, 1); +} + +int main(void) +{ + check_swap(); + pass(); +} diff --git a/tests/cris/check_time1.c b/tests/cris/check_time1.c new file mode 100644 index 000000000..3fcf0e153 --- /dev/null +++ b/tests/cris/check_time1.c @@ -0,0 +1,46 @@ +/* Basic time functionality test: check that milliseconds are + incremented for each syscall (does not work on host). */ +#include +#include +#include +#include +#include + +void err (const char *s) +{ + perror (s); + abort (); +} + +int +main (void) +{ + struct timeval t_m = {0, 0}; + struct timezone t_z = {0, 0}; + struct timeval t_m1 = {0, 0}; + int i; + + if (gettimeofday (&t_m, &t_z) != 0) + err ("gettimeofday"); + + for (i = 1; i < 10000; i++) + if (gettimeofday (&t_m1, NULL) != 0) + err ("gettimeofday 1"); + else + if (t_m1.tv_sec * 1000000 + t_m1.tv_usec + != (t_m.tv_sec * 1000000 + t_m.tv_usec + i * 1000)) + { + fprintf (stderr, "t0 (%ld, %ld), i %d, t1 (%ld, %ld)\n", + t_m.tv_sec, t_m.tv_usec, i, t_m1.tv_sec, t_m1.tv_usec); + abort (); + } + + if (time (NULL) != t_m1.tv_sec) + { + fprintf (stderr, "time != gettod\n"); + abort (); + } + + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_time2.c b/tests/cris/check_time2.c new file mode 100644 index 000000000..20b69b4f6 --- /dev/null +++ b/tests/cris/check_time2.c @@ -0,0 +1,18 @@ +/* CB_SYS_time doesn't implement the Linux time syscall; the return + value isn't written to the argument. */ + +#include +#include +#include + +int +main (void) +{ + time_t x = (time_t) -1; + time_t t = time (&x); + + if (t == (time_t) -1 || t != x) + abort (); + printf ("pass\n"); + exit (0); +} diff --git a/tests/cris/check_xarith.s b/tests/cris/check_xarith.s new file mode 100644 index 000000000..d0356abed --- /dev/null +++ b/tests/cris/check_xarith.s @@ -0,0 +1,46 @@ + +.include "testutils.inc" + + start + + moveq -1, $r0 + moveq 0, $r1 + addq 1, $r0 + ax + addq 0, $r1 + + move.d $r0, $r3 + checkr3 0 + move.d $r1, $r3 + checkr3 1 + + move.d 0, $r0 + moveq -1, $r1 + subq 1, $r0 + ax + subq 0, $r1 + + move.d $r0, $r3 + checkr3 ffffffff + move.d $r1, $r3 + checkr3 fffffffe + + + moveq -1, $r0 + moveq -1, $r1 + cmpq -1, $r0 + ax + cmpq -1, $r1 + beq 1f + nop + fail +1: + cmpq 0, $r0 + ax + cmpq -1, $r1 + bne 1f + nop + fail +1: + pass + quit diff --git a/tests/cris/crisutils.h b/tests/cris/crisutils.h new file mode 100644 index 000000000..63c713897 --- /dev/null +++ b/tests/cris/crisutils.h @@ -0,0 +1,71 @@ +static char *tst_cc_loc = NULL; + +#define cris_tst_cc_init() \ +do { tst_cc_loc = "test_cc failed at " CURRENT_LOCATION; } while(0) + +/* We need a real symbol to signal error. */ +static void _err(void) { + if (!tst_cc_loc) + tst_cc_loc = "tst_cc_failed\n"; + _fail(tst_cc_loc); +} + +extern inline void cris_tst_cc_n1(void) +{ + asm volatile ("bpl _err\n" + "nop\n"); +} +extern inline void cris_tst_cc_n0(void) +{ + asm volatile ("bmi _err\n" + "nop\n"); +} + +extern inline void cris_tst_cc_z1(void) +{ + asm volatile ("bne _err\n" + "nop\n"); +} +extern inline void cris_tst_cc_z0(void) +{ + asm volatile ("beq _err\n" + "nop\n"); +} +extern inline void cris_tst_cc_v1(void) +{ + asm volatile ("bvc _err\n" + "nop\n"); +} +extern inline void cris_tst_cc_v0(void) +{ + asm volatile ("bvs _err\n" + "nop\n"); +} + +extern inline void cris_tst_cc_c1(void) +{ + asm volatile ("bcc _err\n" + "nop\n"); +} +extern inline void cris_tst_cc_c0(void) +{ + asm volatile ("bcs _err\n" + "nop\n"); +} + +extern inline void cris_tst_mov_cc(int n, int z) +{ + if (n) cris_tst_cc_n1(); else cris_tst_cc_n0(); + if (z) cris_tst_cc_z1(); else cris_tst_cc_z0(); + asm volatile ("" : : "g" (_err)); +} + +extern inline void cris_tst_cc(const int n, const int z, + const int v, const int c) +{ + if (n) cris_tst_cc_n1(); else cris_tst_cc_n0(); + if (z) cris_tst_cc_z1(); else cris_tst_cc_z0(); + if (v) cris_tst_cc_v1(); else cris_tst_cc_v0(); + if (c) cris_tst_cc_c1(); else cris_tst_cc_c0(); + asm volatile ("" : : "g" (_err)); +} diff --git a/tests/cris/crt.s b/tests/cris/crt.s new file mode 100644 index 000000000..af027d747 --- /dev/null +++ b/tests/cris/crt.s @@ -0,0 +1,13 @@ + .data +_stack_start: + .space 8192, 0 +_stack_end: + .text + .global _start +_start: + move.d _stack_end, $sp + jsr main + nop + moveq 0, $r10 + jump exit + nop diff --git a/tests/cris/sys.c b/tests/cris/sys.c new file mode 100644 index 000000000..264ec06f3 --- /dev/null +++ b/tests/cris/sys.c @@ -0,0 +1,48 @@ +#include +#include +#include + +static inline int mystrlen(char *s) { + int i = 0; + while (s[i]) + i++; + return i; +} + +void pass(void) { + char s[] = "passed.\n"; + write (1, s, sizeof (s) - 1); + exit (0); +} + +void _fail(char *reason) { + char s[] = "failed: "; + int len = mystrlen(reason); + write (1, s, sizeof (s) - 1); + write (1, reason, len); + write (1, "\n", 1); +// exit (1); +} + +void *memset (void *s, int c, size_t n) { + char *p = s; + int i; + for (i = 0; i < n; i++) + p[i] = c; + return p; +} + +void exit (int status) { + asm volatile ("moveq 1, $r9\n" /* NR_exit. */ + "break 13\n"); + while(1) + ; +} + +ssize_t write (int fd, const void *buf, size_t count) { + int r; + asm volatile ("moveq 4, $r9\n" /* NR_write. */ + "break 13\n" : : : "memory"); + asm volatile ("move.d $r10, %0\n" : "=r" (r)); + return r; +} diff --git a/tests/cris/sys.h b/tests/cris/sys.h new file mode 100644 index 000000000..d2ed4ce75 --- /dev/null +++ b/tests/cris/sys.h @@ -0,0 +1,16 @@ +#include + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +#define CURRENT_LOCATION __FILE__ ":" TOSTRING(__LINE__) + +#define err() \ +{ \ + _fail("at " CURRENT_LOCATION " "); \ +} + +#define mb() asm volatile ("" : : : "memory") + +extern void pass(void); +extern void _fail(char *reason); diff --git a/tests/cris/testutils.inc b/tests/cris/testutils.inc new file mode 100644 index 000000000..4f434e1e4 --- /dev/null +++ b/tests/cris/testutils.inc @@ -0,0 +1,117 @@ + .syntax no_register_prefix + + .macro start + .text + .global main +main: + .endm + + .macro quit + jump pass + nop + .endm + + .macro pass + jump pass + nop + .endm + + .macro startnostack + start + .endm + + .macro fail + .data +99: + .asciz " checkr3 failed" + .text + move.d 99b, $r10 + jsr _fail + nop + .endm + + .macro checkr3 val + cmp.d 0x\val, $r3 + beq 100f + nop + .data +99: + .asciz "checkr3 failed" + .text + move.d 99b, $r10 + jsr _fail + nop +100: + .endm + +; Test the condition codes + .macro test_cc N Z V C + .if \N + bpl 9f + nop + .else + bmi 9f + nop + .endif + .if \Z + bne 9f + nop + .else + beq 9f + nop + .endif + .if \V + bvc 9f + nop + .else + bvs 9f + nop + .endif + .if \C + bcc 9f + nop + .else + bcs 9f + nop + .endif + ba 8f + nop +9: + .data +99: + .asciz "test_move_cc failed" + .text + move.d 99b, $r10 + jsr _fail + nop +8: + .endm + + + .macro test_move_cc N Z V C + .if \N + bpl 9f + nop + .else + bmi 9f + nop + .endif + .if \Z + bne 9f + nop + .else + beq 9f + nop + .endif + ba 8f + nop +9: + .data +99: + .asciz "test_move_cc failed" + .text + move.d 99b, $r10 + jsr _fail + nop +8: + .endm -- cgit v1.2.3 From e69b406510a7267b79d4ba7e8a1c8d4b28af2fb1 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:35:05 +0000 Subject: CRIS Linux usermode emulation, part 1. By Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3366 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/cris/syscall.h | 37 +++++ linux-user/cris/syscall_nr.h | 291 ++++++++++++++++++++++++++++++++++++++++ linux-user/cris/target_signal.h | 29 ++++ linux-user/cris/termbits.h | 214 +++++++++++++++++++++++++++++ 4 files changed, 571 insertions(+) create mode 100644 linux-user/cris/syscall.h create mode 100644 linux-user/cris/syscall_nr.h create mode 100644 linux-user/cris/target_signal.h create mode 100644 linux-user/cris/termbits.h diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h new file mode 100644 index 000000000..8fa7474ff --- /dev/null +++ b/linux-user/cris/syscall.h @@ -0,0 +1,37 @@ + +#define UNAME_MACHINE "cris" + +/* pt_regs not only specifices the format in the user-struct during + * ptrace but is also the frame format used in the kernel prologue/epilogues + * themselves + */ + +struct target_pt_regs { + unsigned long orig_r10; + /* pushed by movem r13, [sp] in SAVE_ALL. */ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long acr; + unsigned long srs; + unsigned long mof; + unsigned long spc; + unsigned long ccs; + unsigned long srp; + unsigned long erp; /* This is actually the debugged process' PC */ + /* For debugging purposes; saved only when needed. */ + unsigned long exs; + unsigned long eda; +}; + diff --git a/linux-user/cris/syscall_nr.h b/linux-user/cris/syscall_nr.h new file mode 100644 index 000000000..108a2ed21 --- /dev/null +++ b/linux-user/cris/syscall_nr.h @@ -0,0 +1,291 @@ +/* + * This file contains the system call numbers, and stub macros for libc. + */ + +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 + +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread64 180 +#define TARGET_NR_pwrite64 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 +#define TARGET_NR_getpmsg 188 /* some people actually want streams */ +#define TARGET_NR_putpmsg 189 /* some people actually want streams */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_pivot_root 217 +#define TARGET_NR_mincore 218 +#define TARGET_NR_madvise 219 +#define TARGET_NR_getdents64 220 +#define TARGET_NR_fcntl64 221 +/* 223 is unused */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_readahead 225 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_set_thread_area 243 +#define TARGET_NR_get_thread_area 244 +#define TARGET_NR_io_setup 245 +#define TARGET_NR_io_destroy 246 +#define TARGET_NR_io_getevents 247 +#define TARGET_NR_io_submit 248 +#define TARGET_NR_io_cancel 249 +#define TARGET_NR_fadvise64 250 +#define TARGET_NR_exit_group 252 +#define TARGET_NR_lookup_dcookie 253 +#define TARGET_NR_epoll_create 254 +#define TARGET_NR_epoll_ctl 255 +#define TARGET_NR_epoll_wait 256 +#define TARGET_NR_remap_file_pages 257 +#define TARGET_NR_set_tid_address 258 +#define TARGET_NR_timer_create 259 +#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) +#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) +#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) +#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) +#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) +#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) +#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) +#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) +#define TARGET_NR_statfs64 268 +#define TARGET_NR_fstatfs64 269 +#define TARGET_NR_tgkill 270 +#define TARGET_NR_utimes 271 +#define TARGET_NR_fadvise64_64 272 +#define TARGET_NR_vserver 273 +#define TARGET_NR_mbind 274 +#define TARGET_NR_get_mempolicy 275 +#define TARGET_NR_set_mempolicy 276 +#define TARGET_NR_mq_open 277 +#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1) +#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2) +#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3) +#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4) +#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5) +#define TARGET_NR_kexec_load 283 +#define TARGET_NR_waitid 284 +/* #define TARGET_NR_sys_setaltroot 285 */ +#define TARGET_NR_add_key 286 +#define TARGET_NR_request_key 287 +#define TARGET_NR_keyctl 288 diff --git a/linux-user/cris/target_signal.h b/linux-user/cris/target_signal.h new file mode 100644 index 000000000..e566de8ef --- /dev/null +++ b/linux-user/cris/target_signal.h @@ -0,0 +1,29 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + target_ulong ss_sp; + target_ulong ss_size; + target_long ss_flags; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +static inline target_ulong get_sp_from_cpustate(CPUCRISState *state) +{ + return state->regs[14]; +} + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/cris/termbits.h b/linux-user/cris/termbits.h new file mode 100644 index 000000000..adff80243 --- /dev/null +++ b/linux-user/cris/termbits.h @@ -0,0 +1,214 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + -- cgit v1.2.3 From 48733d195b10a61a18c0aafcdd0ae711bdfe03a6 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:36:46 +0000 Subject: CRIS Linux userland emulation, part 2. By Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3367 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 20 +++++++++++++ linux-user/main.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 8 +++-- linux-user/syscall_defs.h | 6 ++-- 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 79c1c4da6..1db6bab5e 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -334,6 +334,26 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif +#ifdef TARGET_CRIS + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_CRIS ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_CRIS + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->erp = infop->entry; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +#endif + #ifdef TARGET_M68K #define ELF_START_MMAP 0x80000000 diff --git a/linux-user/main.c b/linux-user/main.c index fd130ef9c..b4bc93da5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1601,6 +1601,61 @@ void cpu_loop (CPUState *env) } #endif +#ifdef TARGET_CRIS +void cpu_loop (CPUState *env) +{ + int trapnr, ret; + target_siginfo_t info; + + while (1) { + trapnr = cpu_cris_exec (env); + switch (trapnr) { + case 0xaa: + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->debug1; + queue_signal(info.si_signo, &info); + } + break; + case EXCP_BREAK: + ret = do_syscall(env, + env->regs[9], + env->regs[10], + env->regs[11], + env->regs[12], + env->regs[13], + env->pregs[7], + env->pregs[11]); + env->regs[10] = ret; + env->pc += 2; + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + exit (1); + } + process_pending_signals (env); + } +} +#endif + #ifdef TARGET_M68K void cpu_loop(CPUM68KState *env) @@ -2195,6 +2250,26 @@ int main(int argc, char **argv) env->pc = regs->pc; env->unique = regs->unique; } +#elif defined(TARGET_CRIS) + { + env->regs[0] = regs->r0; + env->regs[1] = regs->r1; + env->regs[2] = regs->r2; + env->regs[3] = regs->r3; + env->regs[4] = regs->r4; + env->regs[5] = regs->r5; + env->regs[6] = regs->r6; + env->regs[7] = regs->r7; + env->regs[8] = regs->r8; + env->regs[9] = regs->r9; + env->regs[10] = regs->r10; + env->regs[11] = regs->r11; + env->regs[12] = regs->r12; + env->regs[13] = regs->r13; + env->regs[14] = info->start_stack; + env->regs[15] = regs->acr; + env->pc = regs->erp; + } #else #error unsupported target CPU #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index af5b9d922..021ac9741 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -74,7 +74,7 @@ //#define DEBUG #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ - || defined(TARGET_M68K) || defined(TARGET_SH4) + || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) /* 16 bit uid wrappers emulation */ #define USE_UID16 #endif @@ -2286,6 +2286,10 @@ int do_fork(CPUState *env, unsigned int flags, target_ulong newsp) for (i = 7; i < 30; i++) new_env->ir[i] = 0; } +#elif defined(TARGET_CRIS) + if (!newsp) + newsp = env->regs[14]; + new_env->regs[14] = newsp; #else #error unsupported target CPU #endif @@ -3502,7 +3506,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, #endif #ifdef TARGET_NR_mmap case TARGET_NR_mmap: -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) { target_ulong *v; target_ulong v1, v2, v3, v4, v5, v6; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 90bea9b70..ccccebb5c 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -49,7 +49,7 @@ #define TARGET_IOC_TYPEBITS 8 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ - || defined(TARGET_M68K) || defined(TARGET_ALPHA) + || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -289,7 +289,7 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) #if defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u @@ -884,7 +884,7 @@ struct target_winsize { #define TARGET_MAP_NONBLOCK 0x10000 /* do not block on IO */ #endif -#if defined(TARGET_I386) || defined(TARGET_ARM) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_CRIS) struct target_stat { unsigned short st_dev; unsigned short __pad1; -- cgit v1.2.3 From e7daa60575932e76395cef2d19205d43f96983d7 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:38:27 +0000 Subject: Add CRIS configuration bits, by Edgar E. Iglesias. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3368 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 15 +++++++++++++++ configure | 19 ++++++++++++++++--- tests/Makefile | 5 +++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Makefile.target b/Makefile.target index 6445a7ba4..f31cc788c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -324,6 +324,15 @@ ifeq ($(TARGET_BASE_ARCH), alpha) LIBOBJS+= op_helper.o helper.o alpha_palcode.o endif +ifeq ($(TARGET_BASE_ARCH), cris) +LIBOBJS+= op_helper.o helper.o +LIBOBJS+= cris-dis.o + +ifndef CONFIG_USER_ONLY +LIBOBJS+= mmu.o +endif +endif + # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) @@ -461,6 +470,12 @@ VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds VL_OBJS+= piix_pci.o smbus_eeprom.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) CPPFLAGS += -DHAS_AUDIO endif +ifeq ($(TARGET_BASE_ARCH), cris) +VL_OBJS+= etraxfs.o +VL_OBJS+= ptimer.o +VL_OBJS+= etraxfs_timer.o +VL_OBJS+= etraxfs_ser.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 diff --git a/configure b/configure index ebc294ebe..a8dbf8511 100755 --- a/configure +++ b/configure @@ -53,6 +53,9 @@ case "$cpu" in mips64) cpu="mips64" ;; + cris) + cpu="cris" + ;; s390*) cpu="s390" ;; @@ -497,11 +500,11 @@ 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 mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu sh4-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu sh4-softmmu cris-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user ppc64-linux-user sh4-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user ppc64-linux-user sh4-linux-user cris-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then @@ -782,6 +785,9 @@ elif test "$cpu" = "mips" ; then elif test "$cpu" = "mips64" ; then echo "ARCH=mips64" >> $config_mak echo "#define HOST_MIPS64 1" >> $config_h +elif test "$cpu" = "cris" ; then + echo "ARCH=cris" >> $config_mak + echo "#define HOST_CRIS 1" >> $config_h elif test "$cpu" = "s390" ; then echo "ARCH=s390" >> $config_mak echo "#define HOST_S390 1" >> $config_h @@ -1053,6 +1059,12 @@ elif test "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el" ; then echo "#define TARGET_ARCH \"mips64\"" >> $config_h echo "#define TARGET_MIPS 1" >> $config_h echo "#define TARGET_MIPS64 1" >> $config_h +elif test "$target_cpu" = "cris" ; then + echo "TARGET_ARCH=cris" >> $config_mak + echo "#define TARGET_ARCH \"cris\"" >> $config_h + echo "#define TARGET_CRIS 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 @@ -1135,8 +1147,9 @@ 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" + DIRS="tests tests/cris" FILES="Makefile tests/Makefile" + FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit" for dir in $DIRS ; do mkdir -p $dir done diff --git a/tests/Makefile b/tests/Makefile index ec3a93ce6..97688b8f0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -98,6 +98,11 @@ test2: ../$${arch}-linux-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \ done + +# testsuite for the CRIS port. +test-cris: + $(MAKE) -C cris check + clean: rm -f *~ *.o test-i386.out test-i386.ref \ test-x86_64.log test-x86_64.ref qruncom $(TESTS) -- cgit v1.2.3 From 981623fee3dcb79dc73830fd51b88813cde5b467 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 8 Oct 2007 13:40:13 +0000 Subject: Mentione CRIS in Changelog. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3369 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 32161aa45..26fc301f2 100644 --- a/Changelog +++ b/Changelog @@ -12,6 +12,7 @@ - Preliminary Alpha guest support (J. Mayer) - Read-only support for Parallels disk images (Alex Beregszaszi) - SVM (x86 virtualization) support (Alexander Graf) + - CRIS emulation (Edgar E. Iglesias) version 0.9.0: -- cgit v1.2.3 From aacb758b65e7f98133f9425b2c8a80ae339c3877 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 9 Oct 2007 03:05:08 +0000 Subject: Update .cvsignore. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3370 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 38 +++----------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/.cvsignore b/.cvsignore index 2d6f37f35..b51b9895e 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,19 +1,9 @@ -arm-linux-user -arm-softmmu -armeb-linux-user config-host.* dyngen i386 -i386-softmmu -i386-darwin-user -i386-linux-user -ppc-softmmu -ppc64-softmmu -ppcemb-softmmu -ppc-darwin-user -ppc-linux-user -ppc64-linux-user -ppcemb-linux-user +*-softmmu +*-darwin-user +*-linux-user qemu-doc.html qemu-tech.html qemu-doc.info @@ -22,30 +12,8 @@ qemu.1 qemu.pod qemu-img.1 qemu-img.pod -sparc-linux-user qemu-img -sparc-softmmu -x86_64-softmmu -x86_64-linux-user -sparc64-linux-user -sparc64-softmmu -mips-softmmu -mipsel-softmmu -mips-linux-user -mipsel-linux-user -mips64-softmmu -mips64el-softmmu -mipsn32-linux-user -mipsn32el-linux-user -mips64-linux-user -mips64el-linux-user -m68k-linux-user -m68k-softmmu .gdbinit -sh4-linux-user -sh4-softmmu -alpha-linux-user -alpha-softmmu *.aux *.cp *.dvi -- cgit v1.2.3 From 0e21e12bb311c4c1095d0269dc2ef81196ccb60a Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 9 Oct 2007 03:08:56 +0000 Subject: Don't route PIC interrupts through the local APIC if the local APIC config says so. By Ari Kivity. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3371 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/apic.c | 33 +++++++++++++++++++++++++++++++++ hw/pc.c | 7 ++++--- vl.h | 1 + 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index 9e0f4762f..3a442bf82 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -484,6 +484,25 @@ int apic_get_interrupt(CPUState *env) return intno; } +int apic_accept_pic_intr(CPUState *env) +{ + APICState *s = env->apic_state; + uint32_t lvt0; + + if (!s) + return -1; + + lvt0 = s->lvt[APIC_LVT_LINT0]; + + if (s->id == 0 && + ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || + ((lvt0 & APIC_LVT_MASKED) == 0 && + ((lvt0 >> 8) & 0x7) == APIC_DM_EXTINT))) + return 1; + + return 0; +} + static uint32_t apic_get_current_count(APICState *s) { int64_t d; @@ -790,6 +809,13 @@ static void apic_reset(void *opaque) { APICState *s = opaque; apic_init_ipi(s); + + /* + * LINT0 delivery mode is set to ExtInt at initialization time + * typically by BIOS, so PIC interrupt can be delivered to the + * processor when local APIC is enabled. + */ + s->lvt[APIC_LVT_LINT0] = 0x700; } static CPUReadMemoryFunc *apic_mem_read[3] = { @@ -821,6 +847,13 @@ int apic_init(CPUState *env) s->apicbase = 0xfee00000 | (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; + /* + * LINT0 delivery mode is set to ExtInt at initialization time + * typically by BIOS, so PIC interrupt can be delivered to the + * processor when local APIC is enabled. + */ + s->lvt[APIC_LVT_LINT0] = 0x700; + /* XXX: mapping more APICs at the same memory location */ if (apic_io_memory == 0) { /* NOTE: the APIC is directly connected to the CPU - it is not diff --git a/hw/pc.c b/hw/pc.c index 5bc0b63e7..c561cbf2e 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -93,6 +93,9 @@ int cpu_get_pic_interrupt(CPUState *env) return intno; } /* read the irq from the PIC */ + if (!apic_accept_pic_intr(env)) + return -1; + intno = pic_read_irq(isa_pic); return intno; } @@ -100,10 +103,8 @@ int cpu_get_pic_interrupt(CPUState *env) static void pic_irq_request(void *opaque, int irq, int level) { CPUState *env = opaque; - if (level) + if (level && apic_accept_pic_intr(env)) cpu_interrupt(env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } /* PC cmos mappings */ diff --git a/vl.h b/vl.h index d13cb3728..aa7590063 100644 --- a/vl.h +++ b/vl.h @@ -1139,6 +1139,7 @@ void irq_info(void); typedef struct IOAPICState IOAPICState; int apic_init(CPUState *env); +int apic_accept_pic_intr(CPUState *env); int apic_get_interrupt(CPUState *env); IOAPICState *ioapic_init(void); void ioapic_set_irq(void *opaque, int vector, int level); -- cgit v1.2.3 From 4e9f853731f060236d9036663c12ca0594395d0d Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 9 Oct 2007 03:12:08 +0000 Subject: Fix [ls][wd][lr] instructions, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3372 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- target-mips/exec.h | 30 ------- target-mips/op_helper.c | 12 --- target-mips/op_mem.c | 223 +++++++++++++++++++++++++++++++++++++++++++----- target-mips/translate.c | 8 +- 5 files changed, 207 insertions(+), 68 deletions(-) diff --git a/Makefile.target b/Makefile.target index f31cc788c..fe0cf372a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -658,7 +658,7 @@ endif ifeq ($(TARGET_BASE_ARCH), mips) helper.o: cpu.h exec-all.h op.o: op_template.c fop_template.c op_mem.c exec.h cpu.h -op_helper.o: op_helper_mem.c exec.h softmmu_template.h cpu.h +op_helper.o: exec.h softmmu_template.h cpu.h translate.o: translate_init.c exec-all.h disas.h endif diff --git a/target-mips/exec.h b/target-mips/exec.h index 8e909787e..ea95da06e 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -100,36 +100,6 @@ void fpu_dump_state(CPUState *env, FILE *f, int (*fpu_fprintf)(FILE *f, const char *fmt, ...), int flags); void dump_sc (void); -void do_lwl_raw (uint32_t); -void do_lwr_raw (uint32_t); -uint32_t do_swl_raw (uint32_t); -uint32_t do_swr_raw (uint32_t); -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) -void do_ldl_raw (uint64_t); -void do_ldr_raw (uint64_t); -uint64_t do_sdl_raw (uint64_t); -uint64_t do_sdr_raw (uint64_t); -#endif -#if !defined(CONFIG_USER_ONLY) -void do_lwl_user (uint32_t); -void do_lwl_kernel (uint32_t); -void do_lwr_user (uint32_t); -void do_lwr_kernel (uint32_t); -uint32_t do_swl_user (uint32_t); -uint32_t do_swl_kernel (uint32_t); -uint32_t do_swr_user (uint32_t); -uint32_t do_swr_kernel (uint32_t); -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) -void do_ldl_user (uint64_t); -void do_ldl_kernel (uint64_t); -void do_ldr_user (uint64_t); -void do_ldr_kernel (uint64_t); -uint64_t do_sdl_user (uint64_t); -uint64_t do_sdl_kernel (uint64_t); -uint64_t do_sdr_user (uint64_t); -uint64_t do_sdr_kernel (uint64_t); -#endif -#endif void do_pmon (int function); void dump_sc (void); diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index f4313280e..3c23d8c36 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -62,18 +62,6 @@ void do_raise_exception_direct (uint32_t exception) do_raise_exception_direct_err (exception, 0); } -#define MEMSUFFIX _raw -#include "op_helper_mem.c" -#undef MEMSUFFIX -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_helper_mem.c" -#undef MEMSUFFIX -#define MEMSUFFIX _kernel -#include "op_helper_mem.c" -#undef MEMSUFFIX -#endif - #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #if TARGET_LONG_BITS > HOST_LONG_BITS /* Those might call libgcc functions. */ diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index a15ad5a96..d402d616b 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -75,34 +75,92 @@ void glue(op_sw, MEMSUFFIX) (void) /* "half" load and stores. We must do the memory access inline, or fault handling won't work. */ -/* XXX: This is broken, CP0_BADVADDR has the wrong (aligned) value. */ + +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK(v) ((v) & 3) +#define GET_OFFSET(addr, offset) (addr + (offset)) +#else +#define GET_LMASK(v) (((v) & 3) ^ 3) +#define GET_OFFSET(addr, offset) (addr - (offset)) +#endif + void glue(op_lwl, MEMSUFFIX) (void) { - uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); - CALL_FROM_TB1(glue(do_lwl, MEMSUFFIX), tmp); + target_ulong tmp; + + tmp = glue(ldub, MEMSUFFIX)(T0); + T1 = (int32_t)((T1 & 0x00FFFFFF) | (tmp << 24)); + + if (GET_LMASK(T0) <= 2) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 1)); + T1 = (T1 & 0xFF00FFFF) | (tmp << 16); + } + + if (GET_LMASK(T0) <= 1) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 2)); + T1 = (T1 & 0xFFFF00FF) | (tmp << 8); + } + + if (GET_LMASK(T0) == 0) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 3)); + T1 = (T1 & 0xFFFFFF00) | tmp; + } RETURN(); } void glue(op_lwr, MEMSUFFIX) (void) { - uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); - CALL_FROM_TB1(glue(do_lwr, MEMSUFFIX), tmp); + target_ulong tmp; + + tmp = glue(ldub, MEMSUFFIX)(T0); + T1 = (T1 & 0xFFFFFF00) | tmp; + + if (GET_LMASK(T0) >= 1) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -1)); + T1 = (T1 & 0xFFFF00FF) | (tmp << 8); + } + + if (GET_LMASK(T0) >= 2) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -2)); + T1 = (T1 & 0xFF00FFFF) | (tmp << 16); + } + + if (GET_LMASK(T0) == 3) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -3)); + T1 = (T1 & 0x00FFFFFF) | (tmp << 24); + } RETURN(); } void glue(op_swl, MEMSUFFIX) (void) { - uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); - tmp = CALL_FROM_TB1(glue(do_swl, MEMSUFFIX), tmp); - glue(stl, MEMSUFFIX)(T0 & ~3, tmp); + glue(stb, MEMSUFFIX)(T0, (uint8_t)(T1 >> 24)); + + if (GET_LMASK(T0) <= 2) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 1), (uint8_t)(T1 >> 16)); + + if (GET_LMASK(T0) <= 1) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 2), (uint8_t)(T1 >> 8)); + + if (GET_LMASK(T0) == 0) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 3), (uint8_t)T1); + RETURN(); } void glue(op_swr, MEMSUFFIX) (void) { - uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3); - tmp = CALL_FROM_TB1(glue(do_swr, MEMSUFFIX), tmp); - glue(stl, MEMSUFFIX)(T0 & ~3, tmp); + glue(stb, MEMSUFFIX)(T0, (uint8_t)T1); + + if (GET_LMASK(T0) >= 1) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -1), (uint8_t)(T1 >> 8)); + + if (GET_LMASK(T0) >= 2) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -2), (uint8_t)(T1 >> 16)); + + if (GET_LMASK(T0) == 3) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -3), (uint8_t)(T1 >> 24)); + RETURN(); } @@ -145,33 +203,156 @@ void glue(op_sd, MEMSUFFIX) (void) /* "half" load and stores. We must do the memory access inline, or fault handling won't work. */ + +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK64(v) ((v) & 7) +#else +#define GET_LMASK64(v) (((v) & 7) ^ 7) +#endif + void glue(op_ldl, MEMSUFFIX) (void) { - target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7); - CALL_FROM_TB1(glue(do_ldl, MEMSUFFIX), tmp); + uint64_t tmp; + + tmp = glue(ldub, MEMSUFFIX)(T0); + T1 = (T1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); + + if (GET_LMASK64(T0) <= 6) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 1)); + T1 = (T1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); + } + + if (GET_LMASK64(T0) <= 5) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 2)); + T1 = (T1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); + } + + if (GET_LMASK64(T0) <= 4) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 3)); + T1 = (T1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); + } + + if (GET_LMASK64(T0) <= 3) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 4)); + T1 = (T1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); + } + + if (GET_LMASK64(T0) <= 2) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 5)); + T1 = (T1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); + } + + if (GET_LMASK64(T0) <= 1) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 6)); + T1 = (T1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); + } + + if (GET_LMASK64(T0) == 0) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 7)); + T1 = (T1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; + } + RETURN(); } void glue(op_ldr, MEMSUFFIX) (void) { - target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7); - CALL_FROM_TB1(glue(do_ldr, MEMSUFFIX), tmp); + uint64_t tmp; + + tmp = glue(ldub, MEMSUFFIX)(T0); + T1 = (T1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; + + if (GET_LMASK64(T0) >= 1) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -1)); + T1 = (T1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); + } + + if (GET_LMASK64(T0) >= 2) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -2)); + T1 = (T1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); + } + + if (GET_LMASK64(T0) >= 3) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -3)); + T1 = (T1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); + } + + if (GET_LMASK64(T0) >= 4) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -4)); + T1 = (T1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); + } + + if (GET_LMASK64(T0) >= 5) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -5)); + T1 = (T1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); + } + + if (GET_LMASK64(T0) >= 6) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -6)); + T1 = (T1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); + } + + if (GET_LMASK64(T0) == 7) { + tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -7)); + T1 = (T1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); + } + RETURN(); } void glue(op_sdl, MEMSUFFIX) (void) { - target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7); - tmp = CALL_FROM_TB1(glue(do_sdl, MEMSUFFIX), tmp); - glue(stq, MEMSUFFIX)(T0 & ~7, tmp); + glue(stb, MEMSUFFIX)(T0, (uint8_t)(T1 >> 56)); + + if (GET_LMASK64(T0) <= 6) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 1), (uint8_t)(T1 >> 48)); + + if (GET_LMASK64(T0) <= 5) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 2), (uint8_t)(T1 >> 40)); + + if (GET_LMASK64(T0) <= 4) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 3), (uint8_t)(T1 >> 32)); + + if (GET_LMASK64(T0) <= 3) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 4), (uint8_t)(T1 >> 24)); + + if (GET_LMASK64(T0) <= 2) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 5), (uint8_t)(T1 >> 16)); + + if (GET_LMASK64(T0) <= 1) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 6), (uint8_t)(T1 >> 8)); + + if (GET_LMASK64(T0) <= 0) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 7), (uint8_t)T1); + RETURN(); } void glue(op_sdr, MEMSUFFIX) (void) { - target_long tmp = glue(ldq, MEMSUFFIX)(T0 & ~7); - tmp = CALL_FROM_TB1(glue(do_sdr, MEMSUFFIX), tmp); - glue(stq, MEMSUFFIX)(T0 & ~7, tmp); + glue(stb, MEMSUFFIX)(T0, (uint8_t)T1); + + if (GET_LMASK64(T0) >= 1) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -1), (uint8_t)(T1 >> 8)); + + if (GET_LMASK64(T0) >= 2) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -2), (uint8_t)(T1 >> 16)); + + if (GET_LMASK64(T0) >= 3) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -3), (uint8_t)(T1 >> 24)); + + if (GET_LMASK64(T0) >= 4) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -4), (uint8_t)(T1 >> 32)); + + if (GET_LMASK64(T0) >= 5) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -5), (uint8_t)(T1 >> 40)); + + if (GET_LMASK64(T0) >= 6) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -6), (uint8_t)(T1 >> 48)); + + if (GET_LMASK64(T0) == 7) + glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -7), (uint8_t)(T1 >> 56)); + RETURN(); } diff --git a/target-mips/translate.c b/target-mips/translate.c index d3f80f298..77499e83e 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -889,7 +889,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, case OPC_LDL: GEN_LOAD_REG_TN(T1, rt); op_ldst(ldl); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_TN_REG(rt, T1); opn = "ldl"; break; case OPC_SDL: @@ -900,7 +900,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, case OPC_LDR: GEN_LOAD_REG_TN(T1, rt); op_ldst(ldr); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_TN_REG(rt, T1); opn = "ldr"; break; case OPC_SDR: @@ -952,7 +952,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, case OPC_LWL: GEN_LOAD_REG_TN(T1, rt); op_ldst(lwl); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_TN_REG(rt, T1); opn = "lwl"; break; case OPC_SWL: @@ -963,7 +963,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, case OPC_LWR: GEN_LOAD_REG_TN(T1, rt); op_ldst(lwr); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_TN_REG(rt, T1); opn = "lwr"; break; case OPC_SWR: -- cgit v1.2.3 From ab19cb4129a6c54bc7da57e3f5c8b47116b64f63 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 9 Oct 2007 03:17:28 +0000 Subject: Delete file which should have been removed in the lst commit. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3373 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_helper_mem.c | 301 -------------------------------------------- 1 file changed, 301 deletions(-) delete mode 100644 target-mips/op_helper_mem.c diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c deleted file mode 100644 index 700fc17b1..000000000 --- a/target-mips/op_helper_mem.c +++ /dev/null @@ -1,301 +0,0 @@ -#undef DEBUG_OP - -#ifdef TARGET_WORDS_BIGENDIAN -#define GET_LMASK(v) ((v) & 3) -#else -#define GET_LMASK(v) (((v) & 3) ^ 3) -#endif - -void glue(do_lwl, MEMSUFFIX) (uint32_t tmp) -{ -#if defined (DEBUG_OP) - target_ulong sav = T0; -#endif - - switch (GET_LMASK(T0)) { - case 0: - T0 = (int32_t)tmp; - break; - case 1: - T0 = (int32_t)((tmp << 8) | (T1 & 0x000000FF)); - break; - case 2: - T0 = (int32_t)((tmp << 16) | (T1 & 0x0000FFFF)); - break; - case 3: - T0 = (int32_t)((tmp << 24) | (T1 & 0x00FFFFFF)); - break; - } -#if defined (DEBUG_OP) - if (logfile) { - fprintf(logfile, "%s: " TARGET_FMT_lx " - %08x " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", - __func__, sav, tmp, T1, T0); - } -#endif - RETURN(); -} - -void glue(do_lwr, MEMSUFFIX) (uint32_t tmp) -{ -#if defined (DEBUG_OP) - target_ulong sav = T0; -#endif - - switch (GET_LMASK(T0)) { - case 0: - T0 = (int32_t)((tmp >> 24) | (T1 & 0xFFFFFF00)); - break; - case 1: - T0 = (int32_t)((tmp >> 16) | (T1 & 0xFFFF0000)); - break; - case 2: - T0 = (int32_t)((tmp >> 8) | (T1 & 0xFF000000)); - break; - case 3: - T0 = (int32_t)tmp; - break; - } -#if defined (DEBUG_OP) - if (logfile) { - fprintf(logfile, "%s: " TARGET_FMT_lx " - %08x " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", - __func__, sav, tmp, T1, T0); - } -#endif - RETURN(); -} - -uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp) -{ -#if defined (DEBUG_OP) - target_ulong sav = tmp; -#endif - - switch (GET_LMASK(T0)) { - case 0: - tmp = (int32_t)T1; - break; - case 1: - tmp = (int32_t)((tmp & 0xFF000000) | ((uint32_t)T1 >> 8)); - break; - case 2: - tmp = (int32_t)((tmp & 0xFFFF0000) | ((uint32_t)T1 >> 16)); - break; - case 3: - tmp = (int32_t)((tmp & 0xFFFFFF00) | ((uint32_t)T1 >> 24)); - break; - } -#if defined (DEBUG_OP) - if (logfile) { - fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => %08x\n", - __func__, T0, sav, T1, tmp); - } -#endif - RETURN(); - return tmp; -} - -uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp) -{ -#if defined (DEBUG_OP) - target_ulong sav = tmp; -#endif - - switch (GET_LMASK(T0)) { - case 0: - tmp = (int32_t)((tmp & 0x00FFFFFF) | (T1 << 24)); - break; - case 1: - tmp = (int32_t)((tmp & 0x0000FFFF) | (T1 << 16)); - break; - case 2: - tmp = (int32_t)((tmp & 0x000000FF) | (T1 << 8)); - break; - case 3: - tmp = (int32_t)T1; - break; - } -#if defined (DEBUG_OP) - if (logfile) { - fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => %08x\n", - __func__, T0, sav, T1, tmp); - } -#endif - RETURN(); - return tmp; -} - -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) - -#ifdef TARGET_WORDS_BIGENDIAN -#define GET_LMASK64(v) ((v) & 7) -#else -#define GET_LMASK64(v) (((v) & 7) ^ 7) -#endif - -void glue(do_ldl, MEMSUFFIX) (uint64_t tmp) -{ -#if defined (DEBUG_OP) - target_ulong sav = T0; -#endif - - switch (GET_LMASK64(T0)) { - case 0: - T0 = tmp; - break; - case 1: - T0 = (tmp << 8) | (T1 & 0x00000000000000FFULL); - break; - case 2: - T0 = (tmp << 16) | (T1 & 0x000000000000FFFFULL); - break; - case 3: - T0 = (tmp << 24) | (T1 & 0x0000000000FFFFFFULL); - break; - case 4: - T0 = (tmp << 32) | (T1 & 0x00000000FFFFFFFFULL); - break; - case 5: - T0 = (tmp << 40) | (T1 & 0x000000FFFFFFFFFFULL); - break; - case 6: - T0 = (tmp << 48) | (T1 & 0x0000FFFFFFFFFFFFULL); - break; - case 7: - T0 = (tmp << 56) | (T1 & 0x00FFFFFFFFFFFFFFULL); - break; - } -#if defined (DEBUG_OP) - if (logfile) { - fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", - __func__, sav, tmp, T1, T0); - } -#endif - RETURN(); -} - -void glue(do_ldr, MEMSUFFIX) (uint64_t tmp) -{ -#if defined (DEBUG_OP) - target_ulong sav = T0; -#endif - - switch (GET_LMASK64(T0)) { - case 0: - T0 = (tmp >> 56) | (T1 & 0xFFFFFFFFFFFFFF00ULL); - break; - case 1: - T0 = (tmp >> 48) | (T1 & 0xFFFFFFFFFFFF0000ULL); - break; - case 2: - T0 = (tmp >> 40) | (T1 & 0xFFFFFFFFFF000000ULL); - break; - case 3: - T0 = (tmp >> 32) | (T1 & 0xFFFFFFFF00000000ULL); - break; - case 4: - T0 = (tmp >> 24) | (T1 & 0xFFFFFF0000000000ULL); - break; - case 5: - T0 = (tmp >> 16) | (T1 & 0xFFFF000000000000ULL); - break; - case 6: - T0 = (tmp >> 8) | (T1 & 0xFF00000000000000ULL); - break; - case 7: - T0 = tmp; - break; - } -#if defined (DEBUG_OP) - if (logfile) { - fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", - __func__, sav, tmp, T1, T0); - } -#endif - RETURN(); -} - -uint64_t glue(do_sdl, MEMSUFFIX) (uint64_t tmp) -{ -#if defined (DEBUG_OP) - target_ulong sav = tmp; -#endif - - switch (GET_LMASK64(T0)) { - case 0: - tmp = T1; - break; - case 1: - tmp = (tmp & 0xFF00000000000000ULL) | (T1 >> 8); - break; - case 2: - tmp = (tmp & 0xFFFF000000000000ULL) | (T1 >> 16); - break; - case 3: - tmp = (tmp & 0xFFFFFF0000000000ULL) | (T1 >> 24); - break; - case 4: - tmp = (tmp & 0xFFFFFFFF00000000ULL) | (T1 >> 32); - break; - case 5: - tmp = (tmp & 0xFFFFFFFFFF000000ULL) | (T1 >> 40); - break; - case 6: - tmp = (tmp & 0xFFFFFFFFFFFF0000ULL) | (T1 >> 48); - break; - case 7: - tmp = (tmp & 0xFFFFFFFFFFFFFF00ULL) | (T1 >> 56); - break; - } -#if defined (DEBUG_OP) - if (logfile) { - fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", - __func__, T0, sav, T1, tmp); - } -#endif - RETURN(); - return tmp; -} - -uint64_t glue(do_sdr, MEMSUFFIX) (uint64_t tmp) -{ -#if defined (DEBUG_OP) - target_ulong sav = tmp; -#endif - - switch (GET_LMASK64(T0)) { - case 0: - tmp = (tmp & 0x00FFFFFFFFFFFFFFULL) | (T1 << 56); - break; - case 1: - tmp = (tmp & 0x0000FFFFFFFFFFFFULL) | (T1 << 48); - break; - case 2: - tmp = (tmp & 0x000000FFFFFFFFFFULL) | (T1 << 40); - break; - case 3: - tmp = (tmp & 0x00000000FFFFFFFFULL) | (T1 << 32); - break; - case 4: - tmp = (tmp & 0x0000000000FFFFFFULL) | (T1 << 24); - break; - case 5: - tmp = (tmp & 0x000000000000FFFFULL) | (T1 << 16); - break; - case 6: - tmp = (tmp & 0x00000000000000FFULL) | (T1 << 8); - break; - case 7: - tmp = T1; - break; - } -#if defined (DEBUG_OP) - if (logfile) { - fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n", - __func__, T0, sav, T1, tmp); - } -#endif - RETURN(); - return tmp; -} - -#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ -- cgit v1.2.3 From 6dab28d5b5bfa67bef724efac0bc051a69ff1339 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 9 Oct 2007 03:19:01 +0000 Subject: Fix vmmouse for 64bit guest, by Dan Kenigsberg. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3374 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/vmport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vmport.c b/hw/vmport.c index e477fe88c..bf56b84c5 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -52,7 +52,7 @@ static uint32_t vmport_ioport_read(void *opaque, uint32_t addr) { VMPortState *s = opaque; unsigned char command; - target_ulong eax; + uint32_t eax; eax = s->env->regs[R_EAX]; if (eax != VMPORT_MAGIC) -- cgit v1.2.3 From aa3437359864a40e37ab0ddb221f243c3c952b14 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 9 Oct 2007 03:39:58 +0000 Subject: Use always_inline in the MIPS support where applicable. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3375 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 8 ++++---- target-mips/op.c | 4 ++-- target-mips/op_helper.c | 10 +++++----- target-mips/translate.c | 34 +++++++++++++++++----------------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index ea95da06e..45be7b37c 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -205,15 +205,15 @@ FOP_PROTO(le) FOP_PROTO(ngt) #undef FOP_PROTO -static inline void env_to_regs(void) +static always_inline void env_to_regs(void) { } -static inline void regs_to_env(void) +static always_inline void regs_to_env(void) { } -static inline int cpu_halted(CPUState *env) +static always_inline int cpu_halted(CPUState *env) { if (!env->halted) return 0; @@ -225,7 +225,7 @@ static inline int cpu_halted(CPUState *env) return EXCP_HALTED; } -static inline void compute_hflags(CPUState *env) +static always_inline void compute_hflags(CPUState *env) { env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_UM); diff --git a/target-mips/op.c b/target-mips/op.c index 429097052..3aefec249 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -812,13 +812,13 @@ void op_msubu (void) #else /* TARGET_LONG_BITS > HOST_LONG_BITS */ -static inline uint64_t get_HILO (void) +static always_inline uint64_t get_HILO (void) { return ((uint64_t)env->HI[0][env->current_tc] << 32) | ((uint64_t)(uint32_t)env->LO[0][env->current_tc]); } -static inline void set_HILO (uint64_t HILO) +static always_inline void set_HILO (uint64_t HILO) { env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF); env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 3c23d8c36..6d732a8a0 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -146,12 +146,12 @@ void do_drotrv (void) /* 64 bits arithmetic for 32 bits hosts */ #if TARGET_LONG_BITS > HOST_LONG_BITS -static inline uint64_t get_HILO (void) +static always_inline uint64_t get_HILO (void) { return (env->HI[0][env->current_tc] << 32) | (uint32_t)env->LO[0][env->current_tc]; } -static inline void set_HILO (uint64_t HILO) +static always_inline void set_HILO (uint64_t HILO) { env->LO[0][env->current_tc] = (int32_t)HILO; env->HI[0][env->current_tc] = (int32_t)(HILO >> 32); @@ -673,7 +673,7 @@ void do_ctc1 (int reg) do_raise_exception(EXCP_FPE); } -inline char ieee_ex_to_mips(char xcpt) +static always_inline char ieee_ex_to_mips(char xcpt) { return (xcpt & float_flag_inexact) >> 5 | (xcpt & float_flag_underflow) >> 3 | @@ -682,7 +682,7 @@ inline char ieee_ex_to_mips(char xcpt) (xcpt & float_flag_invalid) << 4; } -inline char mips_ex_to_ieee(char xcpt) +static always_inline char mips_ex_to_ieee(char xcpt) { return (xcpt & FP_INEXACT) << 5 | (xcpt & FP_UNDERFLOW) << 3 | @@ -691,7 +691,7 @@ inline char mips_ex_to_ieee(char xcpt) (xcpt & FP_INVALID) >> 4; } -inline void update_fcr31(void) +static always_inline void update_fcr31(void) { int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status)); diff --git a/target-mips/translate.c b/target-mips/translate.c index 77499e83e..d69edea30 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -436,7 +436,7 @@ NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ }; \ -static inline void func(int n) \ +static always_inline void func(int n) \ { \ NAME ## _table[n](); \ } @@ -470,7 +470,7 @@ NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ }; \ -static inline void func(int n) \ +static always_inline void func(int n) \ { \ NAME ## _table[n](); \ } @@ -521,7 +521,7 @@ static GenOpFunc1 * gen_op_cmp ## type ## _ ## fmt ## _table[16] = { \ gen_op_cmp ## type ## _ ## fmt ## _le, \ gen_op_cmp ## type ## _ ## fmt ## _ngt, \ }; \ -static inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \ +static always_inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \ { \ gen_op_cmp ## type ## _ ## fmt ## _table[n](cc); \ } @@ -636,7 +636,7 @@ do { \ glue(gen_op_store_fpr_, FTn)(Fn); \ } while (0) -static inline void gen_save_pc(target_ulong pc) +static always_inline void gen_save_pc(target_ulong pc) { #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if (pc == (int32_t)pc) { @@ -649,7 +649,7 @@ static inline void gen_save_pc(target_ulong pc) #endif } -static inline void gen_save_btarget(target_ulong btarget) +static always_inline void gen_save_btarget(target_ulong btarget) { #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) if (btarget == (int32_t)btarget) { @@ -662,7 +662,7 @@ static inline void gen_save_btarget(target_ulong btarget) #endif } -static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) +static always_inline void save_cpu_state (DisasContext *ctx, int do_save_pc) { #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { @@ -694,7 +694,7 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) } } -static inline void restore_cpu_state (CPUState *env, DisasContext *ctx) +static always_inline void restore_cpu_state (CPUState *env, DisasContext *ctx) { ctx->saved_hflags = ctx->hflags; switch (ctx->hflags & MIPS_HFLAG_BMASK) { @@ -712,7 +712,7 @@ static inline void restore_cpu_state (CPUState *env, DisasContext *ctx) } } -static inline void generate_exception_err (DisasContext *ctx, int excp, int err) +static always_inline void generate_exception_err (DisasContext *ctx, int excp, int err) { #if defined MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) @@ -726,24 +726,24 @@ static inline void generate_exception_err (DisasContext *ctx, int excp, int err) ctx->bstate = BS_EXCP; } -static inline void generate_exception (DisasContext *ctx, int excp) +static always_inline void generate_exception (DisasContext *ctx, int excp) { generate_exception_err (ctx, excp, 0); } -static inline void check_cp0_enabled(DisasContext *ctx) +static always_inline void check_cp0_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) generate_exception_err(ctx, EXCP_CpU, 1); } -static inline void check_cp1_enabled(DisasContext *ctx) +static always_inline void check_cp1_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU))) generate_exception_err(ctx, EXCP_CpU, 1); } -static inline void check_cp1_64bitmode(DisasContext *ctx) +static always_inline void check_cp1_64bitmode(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64))) generate_exception(ctx, EXCP_RI); @@ -768,7 +768,7 @@ void check_cp1_registers(DisasContext *ctx, int regs) /* This code generates a "reserved instruction" exception if the CPU does not support the instruction set corresponding to flags. */ -static inline void check_insn(CPUState *env, DisasContext *ctx, int flags) +static always_inline void check_insn(CPUState *env, DisasContext *ctx, int flags) { if (unlikely(!(env->insn_flags & flags))) generate_exception(ctx, EXCP_RI); @@ -776,7 +776,7 @@ static inline void check_insn(CPUState *env, DisasContext *ctx, int flags) /* This code generates a "reserved instruction" exception if the CPU is not MIPS MT capable. */ -static inline void check_mips_mt(CPUState *env, DisasContext *ctx) +static always_inline void check_mips_mt(CPUState *env, DisasContext *ctx) { if (unlikely(!(env->CP0_Config3 & (1 << CP0C3_MT)))) generate_exception(ctx, EXCP_RI); @@ -784,7 +784,7 @@ static inline void check_mips_mt(CPUState *env, DisasContext *ctx) /* This code generates a "reserved instruction" exception if 64-bit instructions are not enabled. */ -static inline void check_mips_64(DisasContext *ctx) +static always_inline void check_mips_64(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_64))) generate_exception(ctx, EXCP_RI); @@ -1634,7 +1634,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, ctx->bstate = BS_STOP; } -static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +static always_inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { TranslationBlock *tb; tb = ctx->tb; @@ -6477,7 +6477,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } } -static inline int +static always_inline int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) { -- cgit v1.2.3 From c6cda17aca3770e178aff5d851da1da9ebb1f210 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 9 Oct 2007 03:42:34 +0000 Subject: getpriority() shouldn't use libc wrapper, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3376 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 021ac9741..a1d9ee1e5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -145,6 +145,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #define __NR_sys_getcwd1 __NR_getcwd #define __NR_sys_getdents __NR_getdents #define __NR_sys_getdents64 __NR_getdents64 +#define __NR_sys_getpriority __NR_getpriority #define __NR_sys_linkat __NR_linkat #define __NR_sys_mkdirat __NR_mkdirat #define __NR_sys_mknodat __NR_mknodat @@ -187,6 +188,7 @@ _syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); #endif +_syscall2(int, sys_getpriority, int, which, int, who); _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); #if defined(TARGET_NR_linkat) && defined(__NR_linkat) @@ -3607,7 +3609,10 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, break; #endif case TARGET_NR_getpriority: - ret = get_errno(getpriority(arg1, arg2)); + /* libc does special remapping of the return value of + * sys_getpriority() so it's just easiest to call + * sys_getpriority() directly rather than through libc. */ + ret = sys_getpriority(arg1, arg2); break; case TARGET_NR_setpriority: ret = get_errno(setpriority(arg1, arg2, arg3)); -- cgit v1.2.3 From bf367b54092014edd36a64195697ea3959fba5cf Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 9 Oct 2007 11:41:47 +0000 Subject: Match values with the ones documented in the PIIX4 datasheet. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3377 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/acpi.c b/hw/acpi.c index 37fadaab6..6e3f69eac 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -400,7 +400,7 @@ static void pm_io_space_update(PIIX4PMState *s) if (s->dev.config[0x80] & 1) { pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); - pm_io_base &= 0xfffe; + pm_io_base &= 0xffc0; /* XXX: need to improve memory and ioport allocation */ #if defined(DEBUG) @@ -474,6 +474,8 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base) pci_conf[0x01] = 0x80; pci_conf[0x02] = 0x13; pci_conf[0x03] = 0x71; + pci_conf[0x06] = 0x80; + pci_conf[0x07] = 0x02; pci_conf[0x08] = 0x00; // revision number pci_conf[0x09] = 0x00; pci_conf[0x0a] = 0x80; // other bridge device -- cgit v1.2.3 From cb33da57aaa368d575825d80d734374e3ef8c472 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 9 Oct 2007 16:34:29 +0000 Subject: Support for executing 32 bit SPARC32PLUS files for Sparc64 user emulator git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3378 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 4 ++ configure | 7 +++ linux-user/elfload.c | 97 +++++++++++++++++++++++++++++++---------- linux-user/elfload32.c | 30 +++++++++++++ linux-user/linuxload.c | 4 ++ linux-user/main.c | 1 + linux-user/qemu.h | 5 +++ linux-user/sparc64/syscall_nr.h | 48 ++++++++++---------- 9 files changed, 149 insertions(+), 48 deletions(-) create mode 100755 linux-user/elfload32.c diff --git a/Changelog b/Changelog index 26fc301f2..4c7a1215c 100644 --- a/Changelog +++ b/Changelog @@ -13,6 +13,7 @@ - Read-only support for Parallels disk images (Alex Beregszaszi) - SVM (x86 virtualization) support (Alexander Graf) - CRIS emulation (Edgar E. Iglesias) + - SPARC32PLUS execution support (Blue Swirl) version 0.9.0: diff --git a/Makefile.target b/Makefile.target index fe0cf372a..8ebe3c3c7 100644 --- a/Makefile.target +++ b/Makefile.target @@ -254,6 +254,10 @@ LIBS+= $(AIOLIBS) ifdef TARGET_HAS_BFLT OBJS+= flatload.o endif +ifdef TARGET_HAS_ELFLOAD32 +OBJS+= elfload32.o +elfload32.o: elfload.c +endif ifeq ($(TARGET_ARCH), i386) OBJS+= vm86.o diff --git a/configure b/configure index a8dbf8511..8e705e1b0 100755 --- a/configure +++ b/configure @@ -999,6 +999,7 @@ echo "include ../config-host.mak" >> $config_mak echo "#include \"../config-host.h\"" >> $config_h bflt="no" +elfload32="no" interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h @@ -1023,6 +1024,7 @@ elif test "$target_cpu" = "sparc64" ; then echo "#define TARGET_ARCH \"sparc64\"" >> $config_h echo "#define TARGET_SPARC 1" >> $config_h echo "#define TARGET_SPARC64 1" >> $config_h + elfload32="yes" elif test "$target_cpu" = "ppc" ; then echo "TARGET_ARCH=ppc" >> $config_mak echo "#define TARGET_ARCH \"ppc\"" >> $config_h @@ -1112,6 +1114,11 @@ 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 +# 32 bit ELF loader in addition to native 64 bit loader? +if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then + echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak + echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h +fi # sdl defines if test "$target_user_only" = "no"; then diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 1db6bab5e..fbe7ddd84 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -12,6 +12,66 @@ #include "qemu.h" #include "disas.h" +/* from personality.h */ + +/* + * Flags for bug emulation. + * + * These occupy the top three bytes. + */ +enum { + ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ + FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors + * (signal handling) + */ + MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, + READ_IMPLIES_EXEC = 0x0400000, + ADDR_LIMIT_32BIT = 0x0800000, + SHORT_INODE = 0x1000000, + WHOLE_SECONDS = 0x2000000, + STICKY_TIMEOUTS = 0x4000000, + ADDR_LIMIT_3GB = 0x8000000, +}; + +/* + * Personality types. + * + * These go in the low byte. Avoid using the top bit, it will + * conflict with error returns. + */ +enum { + PER_LINUX = 0x0000, + PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, + PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, + PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, + PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | + WHOLE_SECONDS | SHORT_INODE, + PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, + PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, + PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, + PER_BSD = 0x0006, + PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, + PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, + PER_LINUX32 = 0x0008, + PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, + PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ + PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ + PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ + PER_RISCOS = 0x000c, + PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, + PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_OSF4 = 0x000f, /* OSF/1 v4 */ + PER_HPUX = 0x0010, + PER_MASK = 0x00ff, +}; + +/* + * Return the base personality without flags. + */ +#define personality(pers) (pers & PER_MASK) + /* this flag is uneffective under linux too, should be deleted */ #ifndef MAP_DENYWRITE #define MAP_DENYWRITE 0 @@ -154,7 +214,7 @@ enum #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SPARCV9 ) +#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB @@ -168,7 +228,10 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; - regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; + if (personality(infop->personality) == PER_LINUX32) + regs->u_regs[14] = infop->start_stack - 16 * 4; + else + regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; } #else @@ -412,6 +475,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_HWCAP 0 #endif +#ifdef OVERRIDE_ELF_CLASS +#undef ELF_CLASS +#define ELF_CLASS OVERRIDE_ELF_CLASS +#undef bswaptls +#define bswaptls(ptr) bswap32s(ptr) +#endif + #include "elf.h" struct exec @@ -439,25 +509,6 @@ struct exec /* max code+data+bss+brk space allocated to ET_DYN executables */ #define ET_DYN_MAP_SIZE (128 * 1024 * 1024) -/* from personality.h */ - -/* Flags for bug emulation. These occupy the top three bytes. */ -#define STICKY_TIMEOUTS 0x4000000 -#define WHOLE_SECONDS 0x2000000 - -/* Personality types. These go in the low byte. Avoid using the top bit, - * it will conflict with error returns. - */ -#define PER_MASK (0x00ff) -#define PER_LINUX (0x0000) -#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) -#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) -#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) -#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) -#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) -#define PER_BSD (0x0006) -#define PER_XENIX (0x0007 | STICKY_TIMEOUTS) - /* Necessary parameters */ #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE #define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) @@ -587,8 +638,8 @@ static target_ulong copy_elf_strings(int argc,char ** argv, void **page, return p; } -target_ulong setup_arg_pages(target_ulong p, struct linux_binprm * bprm, - struct image_info * info) +static target_ulong setup_arg_pages(target_ulong p, struct linux_binprm *bprm, + struct image_info *info) { target_ulong stack_base, size, error; int i; diff --git a/linux-user/elfload32.c b/linux-user/elfload32.c new file mode 100755 index 000000000..d1a15ff93 --- /dev/null +++ b/linux-user/elfload32.c @@ -0,0 +1,30 @@ +#define OVERRIDE_ELF_CLASS ELFCLASS32 +#define load_elf_binary load_elf_binary32 +#define do_init_thread do_init_thread32 + +#include "elfload.c" + +#undef load_elf_binary +#undef do_init_thread + +int load_elf_binary(struct linux_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info); + +int load_elf_binary_multi(struct linux_binprm *bprm, + struct target_pt_regs *regs, + struct image_info *info) +{ + struct elfhdr *elf_ex; + int retval; + + elf_ex = (struct elfhdr *) bprm->buf; /* exec-header */ + if (elf_ex->e_ident[EI_CLASS] == ELFCLASS64) { + retval = load_elf_binary(bprm, regs, info); + } else { + retval = load_elf_binary32(bprm, regs, info); + if (personality(info->personality) == PER_LINUX) + info->personality = PER_LINUX32; + } + + return retval; +} diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 0efbb76ce..51f29531c 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -169,7 +169,11 @@ int loader_exec(const char * filename, char ** argv, char ** envp, && bprm.buf[1] == 'E' && bprm.buf[2] == 'L' && bprm.buf[3] == 'F') { +#ifndef TARGET_HAS_ELFLOAD32 retval = load_elf_binary(&bprm,regs,infop); +#else + retval = load_elf_binary_multi(&bprm, regs, infop); +#endif #if defined(TARGET_HAS_BFLT) } else if (bprm.buf[0] == 'b' && bprm.buf[1] == 'F' diff --git a/linux-user/main.c b/linux-user/main.c index b4bc93da5..7de7ff5a7 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -564,6 +564,7 @@ void cpu_loop (CPUSPARCState *env) case 0x88: case 0x90: #else + case 0x110: case 0x16d: #endif ret = do_syscall (env, env->gregs[1], diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 2c48e9231..8a7cb2479 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -124,6 +124,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info); int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info); +#ifdef TARGET_HAS_ELFLOAD32 +int load_elf_binary_multi(struct linux_binprm *bprm, + struct target_pt_regs *regs, + struct image_info *info); +#endif void memcpy_to_target(target_ulong dest, const void *src, unsigned long len); diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h index 53102945a..70bee8080 100644 --- a/linux-user/sparc64/syscall_nr.h +++ b/linux-user/sparc64/syscall_nr.h @@ -29,11 +29,11 @@ #define TARGET_NR_sigaltstack 28 /* Common */ #define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */ #define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */ -/* #define TARGET_NR_lchown32 31 Linux sparc32 specific */ -/* #define TARGET_NR_fchown32 32 Linux sparc32 specific */ +#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */ +#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */ #define TARGET_NR_access 33 /* Common */ #define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */ -/* #define TARGET_NR_chown32 35 Linux sparc32 specific */ +#define TARGET_NR_chown32 35 /* Linux sparc32 specific */ #define TARGET_NR_sync 36 /* Common */ #define TARGET_NR_kill 37 /* Common */ #define TARGET_NR_stat 38 /* Common */ @@ -42,7 +42,7 @@ #define TARGET_NR_dup 41 /* Common */ #define TARGET_NR_pipe 42 /* Common */ #define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */ -/* #define TARGET_NR_getuid32 44 Linux sparc32 specific */ +#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */ #define TARGET_NR_umount2 45 /* Linux Specific */ #define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */ #define TARGET_NR_getgid 47 /* Common */ @@ -51,48 +51,48 @@ #define TARGET_NR_getegid 50 /* SunOS calls getgid() */ #define TARGET_NR_acct 51 /* Common */ #define TARGET_NR_memory_ordering 52 /* Linux Specific */ -/* #define TARGET_NR_getgid32 53 Linux sparc32 specific */ +#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */ #define TARGET_NR_ioctl 54 /* Common */ #define TARGET_NR_reboot 55 /* Common */ -/* #define TARGET_NR_mmap2 56 Linux sparc32 Specific */ +#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */ #define TARGET_NR_symlink 57 /* Common */ #define TARGET_NR_readlink 58 /* Common */ #define TARGET_NR_execve 59 /* Common */ #define TARGET_NR_umask 60 /* Common */ #define TARGET_NR_chroot 61 /* Common */ #define TARGET_NR_fstat 62 /* Common */ -/* #define TARGET_NR_fstat64 63 Linux sparc32 Specific */ +#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */ #define TARGET_NR_getpagesize 64 /* Common */ #define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */ #define TARGET_NR_vfork 66 /* Common */ #define TARGET_NR_pread64 67 /* Linux Specific */ #define TARGET_NR_pwrite64 68 /* Linux Specific */ -/* #define TARGET_NR_geteuid32 69 Linux sparc32, sbrk under SunOS */ -/* #define TARGET_NR_getegid32 70 Linux sparc32, sstk under SunOS */ +#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */ +#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */ #define TARGET_NR_mmap 71 /* Common */ -/* #define TARGET_NR_setreuid32 72 Linux sparc32, vadvise under SunOS */ +#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */ #define TARGET_NR_munmap 73 /* Common */ #define TARGET_NR_mprotect 74 /* Common */ #define TARGET_NR_madvise 75 /* Common */ #define TARGET_NR_vhangup 76 /* Common */ -/* #define TARGET_NR_truncate64 77 Linux sparc32 Specific */ +#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */ #define TARGET_NR_mincore 78 /* Common */ #define TARGET_NR_getgroups 79 /* Common */ #define TARGET_NR_setgroups 80 /* Common */ #define TARGET_NR_getpgrp 81 /* Common */ -/* #define TARGET_NR_setgroups32 82 Linux sparc32, setpgrp under SunOS */ +#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */ #define TARGET_NR_setitimer 83 /* Common */ -/* #define TARGET_NR_ftruncate64 84 Linux sparc32 Specific */ +#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */ #define TARGET_NR_swapon 85 /* Common */ #define TARGET_NR_getitimer 86 /* Common */ -/* #define TARGET_NR_setuid32 87 Linux sparc32, gethostname under SunOS */ +#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */ #define TARGET_NR_sethostname 88 /* Common */ -/* #define TARGET_NR_setgid32 89 Linux sparc32, getdtablesize under SunOS */ +#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */ #define TARGET_NR_dup2 90 /* Common */ -/* #define TARGET_NR_setfsuid32 91 Linux sparc32, getdopt under SunOS */ +#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */ #define TARGET_NR_fcntl 92 /* Common */ #define TARGET_NR_select 93 /* Common */ -/* #define TARGET_NR_setfsgid32 94 Linux sparc32, setdopt under SunOS */ +#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */ #define TARGET_NR_fsync 95 /* Common */ #define TARGET_NR_setpriority 96 /* Common */ #define TARGET_NR_socket 97 /* Common */ @@ -110,10 +110,10 @@ #define TARGET_NR_getresuid 109 /* Linux Specific, sigblock under SunOS */ #define TARGET_NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */ #define TARGET_NR_getresgid 111 /* Linux Specific, sigpause under SunOS */ -/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */ +/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */ #define TARGET_NR_recvmsg 113 /* Common */ #define TARGET_NR_sendmsg 114 /* Common */ -/* #define TARGET_NR_getgroups32 115 Linux sparc32, vtrace under SunOS */ +#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */ #define TARGET_NR_gettimeofday 116 /* Common */ #define TARGET_NR_getrusage 117 /* Common */ #define TARGET_NR_getsockopt 118 /* Common */ @@ -130,14 +130,14 @@ #define TARGET_NR_truncate 129 /* Common */ #define TARGET_NR_ftruncate 130 /* Common */ #define TARGET_NR_flock 131 /* Common */ -/* #define TARGET_NR_lstat64 132 Linux sparc32 Specific */ +#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */ #define TARGET_NR_sendto 133 /* Common */ #define TARGET_NR_shutdown 134 /* Common */ #define TARGET_NR_socketpair 135 /* Common */ #define TARGET_NR_mkdir 136 /* Common */ #define TARGET_NR_rmdir 137 /* Common */ #define TARGET_NR_utimes 138 /* SunOS Specific */ -/* #define TARGET_NR_stat64 139 Linux sparc32 Specific */ +#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */ #define TARGET_NR_sendfile64 140 /* adjtime under SunOS */ #define TARGET_NR_getpeername 141 /* Common */ #define TARGET_NR_futex 142 /* gethostid under SunOS */ @@ -153,7 +153,7 @@ /* #define TARGET_NR_putmsg 152 SunOS Specific */ #define TARGET_NR_poll 153 /* Common */ #define TARGET_NR_getdents64 154 /* Linux specific */ -/* #define TARGET_NR_fcntl64 155 Linux sparc32 Specific */ +#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */ /* #define TARGET_NR_getdirentries 156 SunOS Specific */ #define TARGET_NR_statfs 157 /* Common */ #define TARGET_NR_fstatfs 158 /* Common */ @@ -229,9 +229,7 @@ #define TARGET_NR_setfsuid 228 /* Linux Specific */ #define TARGET_NR_setfsgid 229 /* Linux Specific */ #define TARGET_NR__newselect 230 /* Linux Specific */ -#ifdef __KERNEL__ -#define TARGET_NR_time 231 /* Linux sparc32 */ -#endif +#define TARGET_NR_time 231 /* Linux sparc32 */ /* #define TARGET_NR_oldstat 232 Linux Specific */ #define TARGET_NR_stime 233 /* Linux Specific */ #define TARGET_NR_statfs64 234 /* Linux Specific */ -- cgit v1.2.3 From 90251fb96e9feba205ee4867cbfe21e0142ad341 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 10 Oct 2007 19:11:54 +0000 Subject: Fix taddcctv and tsubcctv (David Matthews) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3379 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 2 +- target-sparc/translate.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target-sparc/op.c b/target-sparc/op.c index 613bcb09a..e12347df1 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -534,7 +534,7 @@ void OPPROTO op_tadd_T1_T0_ccTV(void) ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) raise_exception(TT_TOVF); #else - if ((src1 & 0x03) || (T1 & 0x03)) + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) raise_exception(TT_TOVF); #endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 1a6d56ac4..27c22ede5 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2027,10 +2027,12 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_T0_reg(rd); break; case 0x22: /* taddcctv */ + save_state(dc); gen_op_tadd_T1_T0_ccTV(); gen_movl_T0_reg(rd); break; case 0x23: /* tsubcctv */ + save_state(dc); gen_op_tsub_T1_T0_ccTV(); gen_movl_T0_reg(rd); break; -- cgit v1.2.3 From c732abe2227954316a5db399aac2040ec0d68f91 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 12 Oct 2007 06:47:46 +0000 Subject: Unify '-cpu ?' option. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3380 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 11 +++-------- target-arm/cpu.h | 3 ++- target-arm/helper.c | 6 +++--- target-mips/cpu.h | 1 + target-ppc/cpu.h | 1 + target-sparc/cpu.h | 1 + vl.c | 11 +++-------- vl.h | 8 -------- 8 files changed, 14 insertions(+), 28 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 7de7ff5a7..1e406d3d4 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1945,14 +1945,9 @@ int main(int argc, char **argv) } else if (!strcmp(r, "cpu")) { cpu_model = argv[optind++]; if (strcmp(cpu_model, "?") == 0) { -#if defined(TARGET_PPC) - ppc_cpu_list(stdout, &fprintf); -#elif defined(TARGET_ARM) - arm_cpu_list(); -#elif defined(TARGET_MIPS) - mips_cpu_list(stdout, &fprintf); -#elif defined(TARGET_SPARC) - sparc_cpu_list(stdout, &fprintf); +/* XXX: implement xxx_cpu_list for targets that still miss it */ +#if defined(cpu_list) + cpu_list(stdout, &fprintf); #endif _exit(1); } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 76fdbb26b..7510a2480 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -260,7 +260,7 @@ static inline int arm_feature(CPUARMState *env, int feature) return (env->features & (1u << feature)) != 0; } -void arm_cpu_list(void); +void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); void cpu_arm_set_model(CPUARMState *env, const char *name); void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, @@ -299,6 +299,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define cpu_exec cpu_arm_exec #define cpu_gen_code cpu_arm_gen_code #define cpu_signal_handler cpu_arm_signal_handler +#define cpu_list arm_cpu_list #include "cpu-all.h" diff --git a/target-arm/helper.c b/target-arm/helper.c index 01573a238..4501feaef 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -126,13 +126,13 @@ static const struct arm_cpu_t arm_cpu_names[] = { { 0, NULL} }; -void arm_cpu_list(void) +void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) { int i; - printf ("Available CPUs:\n"); + (*cpu_fprintf)(f, "Available CPUs:\n"); for (i = 0; arm_cpu_names[i].name; i++) { - printf(" %s\n", arm_cpu_names[i].name); + (*cpu_fprintf)(f, " %s\n", arm_cpu_names[i].name); } } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 569f9325b..137260f32 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -482,6 +482,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def); #define cpu_exec cpu_mips_exec #define cpu_gen_code cpu_mips_gen_code #define cpu_signal_handler cpu_mips_signal_handler +#define cpu_list mips_cpu_list #include "cpu-all.h" diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f4d9004f2..b424abceb 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -697,6 +697,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define cpu_exec cpu_ppc_exec #define cpu_gen_code cpu_ppc_gen_code #define cpu_signal_handler cpu_ppc_signal_handler +#define cpu_list ppc_cpu_list #include "cpu-all.h" diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 5c8c49ab6..fac18a777 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -315,6 +315,7 @@ void cpu_check_irqs(CPUSPARCState *env); #define cpu_exec cpu_sparc_exec #define cpu_gen_code cpu_sparc_gen_code #define cpu_signal_handler cpu_sparc_signal_handler +#define cpu_list sparc_cpu_list #include "cpu-all.h" diff --git a/vl.c b/vl.c index 01bb06eda..65c3e6a47 100644 --- a/vl.c +++ b/vl.c @@ -7690,14 +7690,9 @@ int main(int argc, char **argv) case QEMU_OPTION_cpu: /* hw initialization will check this */ if (*optarg == '?') { -#if defined(TARGET_PPC) - ppc_cpu_list(stdout, &fprintf); -#elif defined(TARGET_ARM) - arm_cpu_list(); -#elif defined(TARGET_MIPS) - mips_cpu_list(stdout, &fprintf); -#elif defined(TARGET_SPARC) - sparc_cpu_list(stdout, &fprintf); +/* XXX: implement xxx_cpu_list for targets that still miss it */ +#if defined(cpu_list) + cpu_list(stdout, &fprintf); #endif exit(0); } else { diff --git a/vl.h b/vl.h index aa7590063..afa2cd6bb 100644 --- a/vl.h +++ b/vl.h @@ -741,14 +741,6 @@ int qemu_register_machine(QEMUMachine *m); typedef void SetIRQFunc(void *opaque, int irq_num, int level); -#if defined(TARGET_PPC) -void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -#endif - -#if defined(TARGET_MIPS) -void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -#endif - #include "hw/irq.h" /* ISA bus */ -- cgit v1.2.3 From ea6fd42fa273591d2dc0ca7780e810582783a6ba Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 13 Oct 2007 14:00:23 +0000 Subject: Static-ify function. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3381 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 47b51c7b0..ce7aaff9d 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -64,9 +64,10 @@ static CPUReadMemoryFunc *mips_qemu_read[] = { static int mips_qemu_iomemtype = 0; -void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) +static void load_kernel (CPUState *env, int ram_size, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) { int64_t entry, kernel_low, kernel_high; long kernel_size, initrd_size; -- cgit v1.2.3 From 89fc88da4c8be493c978cf587fb5f4cc0114d23b Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 13 Oct 2007 17:29:09 +0000 Subject: Fix off-by-one in address check. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3382 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 9c72481c2..a881876ff 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -131,18 +131,14 @@ static int get_physical_address (CPUState *env, target_ulong *physical, ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) -/* - XXX: Assuming : - - PABITS = 36 (correct for MIPS64R1) -*/ - } else if (address < 0x3FFFFFFFFFFFFFFFULL) { + } else if (address < 0x4000000000000000ULL) { /* xuseg */ if (UX && address < (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; } - } else if (address < 0x7FFFFFFFFFFFFFFFULL) { + } else if (address < 0x8000000000000000ULL) { /* xsseg */ if ((supervisor_mode || kernel_mode) && SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { @@ -150,16 +146,17 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else { ret = TLBRET_BADADDR; } - } else if (address < 0xBFFFFFFFFFFFFFFFULL) { + } else if (address < 0xC000000000000000ULL) { /* xkphys */ + /* XXX: Assumes PABITS = 36 (correct for MIPS64R1) */ if (kernel_mode && KX && - (address & 0x07FFFFFFFFFFFFFFULL) < 0X0000000FFFFFFFFFULL) { - *physical = address & 0X0000000FFFFFFFFFULL; + (address & 0x07FFFFFFFFFFFFFFULL) < 0x0000000FFFFFFFFFULL) { + *physical = address & 0x0000000FFFFFFFFFULL; *prot = PAGE_READ | PAGE_WRITE; } else { ret = TLBRET_BADADDR; } - } else if (address < 0xFFFFFFFF7FFFFFFFULL) { + } else if (address < 0xFFFFFFFF80000000ULL) { /* xkseg */ if (kernel_mode && KX && address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { @@ -185,7 +182,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, ret = TLBRET_BADADDR; } } else if (address < (int32_t)0xE0000000UL) { - /* sseg */ + /* sseg (kseg2) */ if (supervisor_mode || kernel_mode) { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { -- cgit v1.2.3 From d0f48074dbc21248f3b0a9fb48126cb0d95991b5 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 13 Oct 2007 19:00:52 +0000 Subject: Update TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3383 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/target-mips/TODO b/target-mips/TODO index 2d207cf90..bc287f63a 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -3,7 +3,32 @@ Unsolved issues/bugs in the mips/mipsel backend General ------- -- [ls][dw][lr] report broken (aligned) BadVAddr +- Unimplemented ASEs: + - MIPS16 + - MDMX + - SmartMIPS + - DSP r1 + - DSP r2 +- MT ASE only partially implemented and not functional +- Shadow register support only partially implemented, + lacks set switching on interrupt/exception. +- 34K ITC not implemented. +- A general lack of documentation, especially for technical internals. + Existing documentation is x86-centric. +- Reverse endianness bit not implemented +- The TLB emulation is very inefficient: + Qemu's softmmu implements a x86-style MMU, with separate entries + for read/write/execute, a TLB index which is just a modulo of the + virtual address, and a set of TLBs for each user/kernel/supervisor + MMU mode. + MIPS has a single entry for read/write/execute and only one MMU mode. + But it is fully associative with randomized entry indices, and uses + up to 256 ASID tags as additional matching criterion (which roughly + equates to 256 MMU modes). It also has a global flag which causes + entries to match regardless of ASID. + To cope with these differences, Qemu currently flushes the TLB at + each ASID change. Using the MMU modes to implement ASIDs hinges on + implementing the global bit efficiently. MIPS64 ------ -- cgit v1.2.3 From 6ebbf390003270afece028facef4d9834df81a8c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 07:07:08 +0000 Subject: Replace is_user variable with mmu_idx in softmmu core, allowing support of more than 2 mmu access modes. Add backward compatibility is_user variable in targets code when needed. Implement per target cpu_mmu_index function, avoiding duplicated code and #ifdef TARGET_xxx in softmmu core functions. Implement per target mmu modes definitions. As an example, add PowerPC hypervisor mode definition and Alpha executive and kernel modes definitions. Optimize PowerPC case, precomputing mmu_idx when MSR register changes and using the same definition in code translation code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3384 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 9 ---- cpu-exec.c | 19 ++++---- exec-all.h | 40 ++++------------ exec.c | 10 ++-- hw/alpha_palcode.c | 26 ++++++----- softmmu_exec.h | 58 +++++++++++++++++++++-- softmmu_header.h | 119 ++++++++++++++--------------------------------- softmmu_template.h | 60 ++++++++++++------------ target-alpha/cpu.h | 13 ++++++ target-alpha/exec.h | 2 +- target-alpha/helper.c | 4 +- target-alpha/op_helper.c | 24 +++++----- target-arm/cpu.h | 11 +++++ target-arm/exec.h | 2 +- target-arm/helper.c | 9 ++-- target-arm/op_helper.c | 4 +- target-cris/cpu.h | 12 +++++ target-cris/exec.h | 4 +- target-cris/helper.c | 8 ++-- target-cris/mmu.c | 3 +- target-cris/mmu.h | 2 +- target-cris/op_helper.c | 4 +- target-i386/cpu.h | 11 +++++ target-i386/exec.h | 4 +- target-i386/helper.c | 4 +- target-i386/helper2.c | 9 ++-- target-m68k/cpu.h | 11 +++++ target-m68k/exec.h | 2 +- target-m68k/helper.c | 6 +-- target-m68k/op_helper.c | 4 +- target-mips/cpu.h | 11 +++++ target-mips/exec.h | 2 +- target-mips/helper.c | 8 ++-- target-mips/op_helper.c | 4 +- target-ppc/cpu.h | 19 ++++++++ target-ppc/exec.h | 2 +- target-ppc/helper.c | 11 +++-- target-ppc/op_helper.c | 4 +- target-ppc/translate.c | 11 +---- target-sh4/cpu.h | 11 +++++ target-sh4/exec.h | 2 +- target-sh4/helper.c | 10 ++-- target-sh4/op_helper.c | 4 +- target-sparc/cpu.h | 11 +++++ target-sparc/exec.h | 2 +- target-sparc/helper.c | 25 +++++----- target-sparc/op_helper.c | 4 +- target-sparc/translate.c | 2 +- 48 files changed, 362 insertions(+), 275 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 915877617..86557e442 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -112,15 +112,6 @@ typedef struct CPUTLBEntry { target_phys_addr_t addend; } CPUTLBEntry; -/* Alpha has 4 different running levels */ -#if defined(TARGET_ALPHA) -#define NB_MMU_MODES 4 -#elif defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ -#define NB_MMU_MODES 3 -#else -#define NB_MMU_MODES 2 -#endif - #define CPU_COMMON \ struct TranslationBlock *current_tb; /* currently executing TB */ \ /* soft mmu support */ \ diff --git a/cpu-exec.c b/cpu-exec.c index d09b564af..0f5522974 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -884,8 +884,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_x86_handle_mmu_fault(env, address, is_write, - ((env->hflags & HF_CPL_MASK) == 3), 0); + ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -934,7 +933,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } /* see if it is an MMU fault */ - ret = cpu_arm_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -970,7 +969,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } /* see if it is an MMU fault */ - ret = cpu_sparc_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1007,7 +1006,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0); + ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1056,7 +1055,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } /* see if it is an MMU fault */ - ret = cpu_m68k_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1096,7 +1095,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_mips_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1146,7 +1145,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_sh4_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1191,7 +1190,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_alpha_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) @@ -1235,7 +1234,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, } /* see if it is an MMU fault */ - ret = cpu_cris_handle_mmu_fault(env, address, is_write, 1, 0); + ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0); if (ret < 0) return 0; /* not an MMU fault */ if (ret == 0) diff --git a/exec-all.h b/exec-all.h index a01494b03..57086f3de 100644 --- a/exec-all.h +++ b/exec-all.h @@ -117,14 +117,14 @@ void tlb_flush_page(CPUState *env, target_ulong addr); void tlb_flush(CPUState *env, int flush_global); int tlb_set_page_exec(CPUState *env, target_ulong vaddr, target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu); + int mmu_idx, int is_softmmu); static inline int tlb_set_page(CPUState *env, target_ulong vaddr, target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { if (prot & PAGE_READ) prot |= PAGE_EXEC; - return tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); + return tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); } #define CODE_GEN_MAX_SIZE 65536 @@ -562,10 +562,10 @@ extern int tb_invalidated_flag; #if !defined(CONFIG_USER_ONLY) -void tlb_fill(target_ulong addr, int is_write, int is_user, +void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr); -#define ACCESS_TYPE 3 +#define ACCESS_TYPE (NB_MMU_MODES + 1) #define MEMSUFFIX _code #define env cpu_single_env @@ -598,35 +598,15 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) is the offset relative to phys_ram_base */ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) { - int is_user, index, pd; + int mmu_idx, index, pd; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); -#if defined(TARGET_I386) - is_user = ((env->hflags & HF_CPL_MASK) == 3); -#elif defined (TARGET_PPC) - is_user = msr_pr; -#elif defined (TARGET_MIPS) - is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); -#elif defined (TARGET_SPARC) - is_user = (env->psrs == 0); -#elif defined (TARGET_ARM) - is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR); -#elif defined (TARGET_SH4) - is_user = ((env->sr & SR_MD) == 0); -#elif defined (TARGET_ALPHA) - is_user = ((env->ps >> 3) & 3); -#elif defined (TARGET_M68K) - is_user = ((env->sr & SR_S) == 0); -#elif defined (TARGET_CRIS) - is_user = (0); -#else -#error unimplemented CPU -#endif - if (__builtin_expect(env->tlb_table[is_user][index].addr_code != + mmu_idx = cpu_mmu_index(env); + if (__builtin_expect(env->tlb_table[mmu_idx][index].addr_code != (addr & TARGET_PAGE_MASK), 0)) { ldub_code(addr); } - pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; + pd = env->tlb_table[mmu_idx][index].addr_code & ~TARGET_PAGE_MASK; if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { #ifdef TARGET_SPARC do_unassigned_access(addr, 0, 1, 0); @@ -634,7 +614,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); #endif } - return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base; + return addr + env->tlb_table[mmu_idx][index].addend - (unsigned long)phys_ram_base; } #endif diff --git a/exec.c b/exec.c index 175bd2801..0daeaabe2 100644 --- a/exec.c +++ b/exec.c @@ -1608,7 +1608,7 @@ static inline void tlb_set_dirty(CPUState *env, conflicting with the host address space). */ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { PhysPageDesc *p; unsigned long pd; @@ -1626,8 +1626,8 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, pd = p->phys_offset; } #if defined(DEBUG_TLB) - printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n", - vaddr, (int)paddr, prot, is_user, is_softmmu, pd); + printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n", + vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd); #endif ret = 0; @@ -1664,7 +1664,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); addend -= vaddr; - te = &env->tlb_table[is_user][index]; + te = &env->tlb_table[mmu_idx][index]; te->addend = addend; if (prot & PAGE_READ) { te->addr_read = address; @@ -1790,7 +1790,7 @@ void tlb_flush_page(CPUState *env, target_ulong addr) int tlb_set_page_exec(CPUState *env, target_ulong vaddr, target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { return 0; } diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c index da2d9ad06..3bd2c5434 100644 --- a/hw/alpha_palcode.c +++ b/hw/alpha_palcode.c @@ -811,12 +811,14 @@ static int get_page_bits (CPUState *env) static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp, uint64_t ptebase, int page_bits, uint64_t level, - int is_user, int rw) + int mmu_idx, int rw) { uint64_t pteaddr, pte, pfn; uint8_t gh; - int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar; + int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user; + /* XXX: TOFIX */ + is_user = mmu_idx == MMU_USER_IDX; pteaddr = (ptebase << page_bits) + (8 * level); pte = ldq_raw(pteaddr); /* Decode all interresting PTE fields */ @@ -871,7 +873,7 @@ static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp, static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot, uint64_t ptebase, int page_bits, - uint64_t vaddr, int is_user, int rw) + uint64_t vaddr, int mmu_idx, int rw) { uint64_t pfn, page_mask, lvl_mask, level1, level2, level3; int lvl_bits, ret; @@ -909,7 +911,7 @@ static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot, break; } /* Level 3 PTE */ - ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, is_user, rw); + ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw); if (ret & 0x1) { /* Translation not valid */ ret = 1; @@ -943,7 +945,7 @@ static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot, static int virtual_to_physical (CPUState *env, uint64_t *physp, int *zbitsp, int *protp, - uint64_t virtual, int is_user, int rw) + uint64_t virtual, int mmu_idx, int rw) { uint64_t sva, ptebase; int seg, page_bits, ret; @@ -961,16 +963,16 @@ static int virtual_to_physical (CPUState *env, uint64_t *physp, case 0: /* seg1: 3 levels of PTE */ ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, - virtual, is_user, rw); + virtual, mmu_idx, rw); break; case 1: /* seg1: 2 levels of PTE */ ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, - virtual, is_user, rw); + virtual, mmu_idx, rw); break; case 2: /* kernel segment */ - if (is_user) { + if (mmu_idx != 0) { ret = 2; } else { *physp = virtual; @@ -979,7 +981,7 @@ static int virtual_to_physical (CPUState *env, uint64_t *physp, case 3: /* seg1: TB mapped */ ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, - virtual, is_user, rw); + virtual, mmu_idx, rw); break; default: ret = 1; @@ -991,7 +993,7 @@ static int virtual_to_physical (CPUState *env, uint64_t *physp, /* XXX: code provision */ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { uint64_t physical, page_size, end; int prot, zbits, ret; @@ -1000,7 +1002,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, ret = 2; } else { ret = virtual_to_physical(env, &physical, &zbits, &prot, - address, is_user, rw); + address, mmu_idx, rw); } switch (ret) { case 0: @@ -1009,7 +1011,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, address &= ~(page_size - 1); for (end = physical + page_size; physical < end; physical += 0x1000) { ret = tlb_set_page(env, address, physical, prot, - is_user, is_softmmu); + mmu_idx, is_softmmu); address += 0x1000; } break; diff --git a/softmmu_exec.h b/softmmu_exec.h index 3b789eeb7..b6e484918 100644 --- a/softmmu_exec.h +++ b/softmmu_exec.h @@ -1,10 +1,16 @@ /* Common softmmu definitions and inline routines. */ -#define ldul_user ldl_user -#define ldul_kernel ldl_kernel +/* XXX: find something cleaner. + * Furthermore, this is false for 64 bits targets + */ +#define ldul_user ldl_user +#define ldul_kernel ldl_kernel +#define ldul_hypv ldl_hypv +#define ldul_executive ldl_executive +#define ldul_supervisor ldl_supervisor #define ACCESS_TYPE 0 -#define MEMSUFFIX _kernel +#define MEMSUFFIX MMU_MODE0_SUFFIX #define DATA_SIZE 1 #include "softmmu_header.h" @@ -20,7 +26,7 @@ #undef MEMSUFFIX #define ACCESS_TYPE 1 -#define MEMSUFFIX _user +#define MEMSUFFIX MMU_MODE1_SUFFIX #define DATA_SIZE 1 #include "softmmu_header.h" @@ -35,8 +41,50 @@ #undef ACCESS_TYPE #undef MEMSUFFIX -/* these access are slower, they must be as rare as possible */ +#if (NB_MMU_MODES >= 3) + #define ACCESS_TYPE 2 +#define MEMSUFFIX MMU_MODE2_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#if (NB_MMU_MODES >= 4) + +#define ACCESS_TYPE 3 +#define MEMSUFFIX MMU_MODE3_SUFFIX +#define DATA_SIZE 1 +#include "softmmu_header.h" + +#define DATA_SIZE 2 +#include "softmmu_header.h" + +#define DATA_SIZE 4 +#include "softmmu_header.h" + +#define DATA_SIZE 8 +#include "softmmu_header.h" +#undef ACCESS_TYPE +#undef MEMSUFFIX + +#if (NB_MMU_MODES > 4) +#error "NB_MMU_MODES > 4 is not supported for now" +#endif /* (NB_MMU_MODES > 4) */ +#endif /* (NB_MMU_MODES == 4) */ +#endif /* (NB_MMU_MODES >= 3) */ + +/* these access are slower, they must be as rare as possible */ +#define ACCESS_TYPE (NB_MMU_MODES) #define MEMSUFFIX _data #define DATA_SIZE 1 #include "softmmu_header.h" diff --git a/softmmu_header.h b/softmmu_header.h index 384518bb6..80eefa80f 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -39,66 +39,19 @@ #error unsupported data size #endif -#if ACCESS_TYPE == 0 +#if ACCESS_TYPE < (NB_MMU_MODES) -#define CPU_MEM_INDEX 0 +#define CPU_MMU_INDEX ACCESS_TYPE #define MMUSUFFIX _mmu -#elif ACCESS_TYPE == 1 +#elif ACCESS_TYPE == (NB_MMU_MODES) -#define CPU_MEM_INDEX 1 +#define CPU_MMU_INDEX (cpu_mmu_index(env)) #define MMUSUFFIX _mmu -#elif ACCESS_TYPE == 2 - -#ifdef TARGET_I386 -#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) -#elif defined (TARGET_PPC) -#define CPU_MEM_INDEX (msr_pr) -#elif defined (TARGET_MIPS) -#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) -#elif defined (TARGET_SPARC) -#define CPU_MEM_INDEX ((env->psrs) == 0) -#elif defined (TARGET_ARM) -#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) -#elif defined (TARGET_SH4) -#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) -#elif defined (TARGET_ALPHA) -#define CPU_MEM_INDEX ((env->ps >> 3) & 3) -#elif defined (TARGET_M68K) -#define CPU_MEM_INDEX ((env->sr & SR_S) == 0) -#elif defined (TARGET_CRIS) -/* CRIS FIXME: I guess we want to validate supervisor mode acceses here. */ -#define CPU_MEM_INDEX (0) -#else -#error unsupported CPU -#endif -#define MMUSUFFIX _mmu +#elif ACCESS_TYPE == (NB_MMU_MODES + 1) -#elif ACCESS_TYPE == 3 - -#ifdef TARGET_I386 -#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) -#elif defined (TARGET_PPC) -#define CPU_MEM_INDEX (msr_pr) -#elif defined (TARGET_MIPS) -#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) -#elif defined (TARGET_SPARC) -#define CPU_MEM_INDEX ((env->psrs) == 0) -#elif defined (TARGET_ARM) -#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) -#elif defined (TARGET_SH4) -#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0) -#elif defined (TARGET_ALPHA) -#define CPU_MEM_INDEX ((env->ps >> 3) & 3) -#elif defined (TARGET_M68K) -#define CPU_MEM_INDEX ((env->sr & SR_S) == 0) -#elif defined (TARGET_CRIS) -/* CRIS FIXME: I guess we want to validate supervisor mode acceses here. */ -#define CPU_MEM_INDEX (0) -#else -#error unsupported CPU -#endif +#define CPU_MMU_INDEX (cpu_mmu_index(env)) #define MMUSUFFIX _cmmu #else @@ -111,18 +64,18 @@ #define RES_TYPE int #endif -#if ACCESS_TYPE == 3 +#if ACCESS_TYPE == (NB_MMU_MODES + 1) #define ADDR_READ addr_code #else #define ADDR_READ addr_read #endif DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, - int is_user); -void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE v, int is_user); + int mmu_idx); +void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE v, int mmu_idx); #if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \ - (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) + (ACCESS_TYPE < NB_MMU_MODES) && defined(ASM_SOFTMMU) #define CPU_TLB_ENTRY_BITS 4 @@ -161,8 +114,8 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)), - "i" (CPU_MEM_INDEX), + "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_read)), + "i" (CPU_MMU_INDEX), "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) : "%eax", "%ecx", "%edx", "memory", "cc"); return res; @@ -208,8 +161,8 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)), - "i" (CPU_MEM_INDEX), + "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_read)), + "i" (CPU_MMU_INDEX), "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX)) : "%eax", "%ecx", "%edx", "memory", "cc"); return res; @@ -260,8 +213,8 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)), - "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)), - "i" (CPU_MEM_INDEX), + "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MMU_INDEX][0].addr_write)), + "i" (CPU_MMU_INDEX), "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX)) : "%eax", "%ecx", "%edx", "memory", "cc"); } @@ -276,16 +229,16 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) RES_TYPE res; target_ulong addr; unsigned long physaddr; - int is_user; + int mmu_idx; addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != + mmu_idx = CPU_MMU_INDEX; + if (__builtin_expect(env->tlb_table[mmu_idx][index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { - res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user); + res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); } else { - physaddr = addr + env->tlb_table[is_user][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][index].addend; res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); } return res; @@ -297,23 +250,23 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) int res, index; target_ulong addr; unsigned long physaddr; - int is_user; + int mmu_idx; addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != + mmu_idx = CPU_MMU_INDEX; + if (__builtin_expect(env->tlb_table[mmu_idx][index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { - res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user); + res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); } else { - physaddr = addr + env->tlb_table[is_user][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][index].addend; res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); } return res; } #endif -#if ACCESS_TYPE != 3 +#if ACCESS_TYPE != (NB_MMU_MODES + 1) /* generic store macro */ @@ -322,25 +275,25 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE int index; target_ulong addr; unsigned long physaddr; - int is_user; + int mmu_idx; addr = ptr; index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - is_user = CPU_MEM_INDEX; - if (__builtin_expect(env->tlb_table[is_user][index].addr_write != + mmu_idx = CPU_MMU_INDEX; + if (__builtin_expect(env->tlb_table[mmu_idx][index].addr_write != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) { - glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user); + glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx); } else { - physaddr = addr + env->tlb_table[is_user][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][index].addend; glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); } } -#endif /* ACCESS_TYPE != 3 */ +#endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ #endif /* !asm */ -#if ACCESS_TYPE != 3 +#if ACCESS_TYPE != (NB_MMU_MODES + 1) #if DATA_SIZE == 8 static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr) @@ -386,7 +339,7 @@ static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) } #endif /* DATA_SIZE == 4 */ -#endif /* ACCESS_TYPE != 3 */ +#endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ #undef RES_TYPE #undef DATA_TYPE @@ -394,6 +347,6 @@ static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) #undef SUFFIX #undef USUFFIX #undef DATA_SIZE -#undef CPU_MEM_INDEX +#undef CPU_MMU_INDEX #undef MMUSUFFIX #undef ADDR_READ diff --git a/softmmu_template.h b/softmmu_template.h index ce6e4bd07..89b2f38c8 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -48,7 +48,7 @@ #endif static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, - int is_user, + int mmu_idx, void *retaddr); static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, target_ulong tlb_addr) @@ -76,7 +76,7 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, /* handle all cases except unaligned access which span two pages */ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, - int is_user) + int mmu_idx) { DATA_TYPE res; int index; @@ -88,9 +88,9 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, /* XXX: could done more in memory macro in a non portable way */ index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_table[is_user][index].ADDR_READ; + tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_table[is_user][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -101,16 +101,16 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, do_unaligned_access: retaddr = GETPC(); #ifdef ALIGNED_ONLY - do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); #endif res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, - is_user, retaddr); + mmu_idx, retaddr); } else { /* unaligned/aligned access in the same page */ #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) { retaddr = GETPC(); - do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); } #endif res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr); @@ -120,9 +120,9 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, retaddr = GETPC(); #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) - do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr); + do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); #endif - tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr); + tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); goto redo; } return res; @@ -130,7 +130,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, /* handle all unaligned cases */ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, - int is_user, + int mmu_idx, void *retaddr) { DATA_TYPE res, res1, res2; @@ -140,9 +140,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_table[is_user][index].ADDR_READ; + tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_table[is_user][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -154,9 +154,9 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, addr1 = addr & ~(DATA_SIZE - 1); addr2 = addr1 + DATA_SIZE; res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, - is_user, retaddr); + mmu_idx, retaddr); res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, - is_user, retaddr); + mmu_idx, retaddr); shift = (addr & (DATA_SIZE - 1)) * 8; #ifdef TARGET_WORDS_BIGENDIAN res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); @@ -170,7 +170,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, } } else { /* the page is not in the TLB : fill it */ - tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr); + tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); goto redo; } return res; @@ -180,7 +180,7 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, - int is_user, + int mmu_idx, void *retaddr); static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, @@ -211,7 +211,7 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, - int is_user) + int mmu_idx) { target_phys_addr_t physaddr; target_ulong tlb_addr; @@ -220,9 +220,9 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_table[is_user][index].addr_write; + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_table[is_user][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -233,16 +233,16 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, do_unaligned_access: retaddr = GETPC(); #ifdef ALIGNED_ONLY - do_unaligned_access(addr, 1, is_user, retaddr); + do_unaligned_access(addr, 1, mmu_idx, retaddr); #endif glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, - is_user, retaddr); + mmu_idx, retaddr); } else { /* aligned/unaligned access in the same page */ #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) { retaddr = GETPC(); - do_unaligned_access(addr, 1, is_user, retaddr); + do_unaligned_access(addr, 1, mmu_idx, retaddr); } #endif glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val); @@ -252,9 +252,9 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, retaddr = GETPC(); #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) - do_unaligned_access(addr, 1, is_user, retaddr); + do_unaligned_access(addr, 1, mmu_idx, retaddr); #endif - tlb_fill(addr, 1, is_user, retaddr); + tlb_fill(addr, 1, mmu_idx, retaddr); goto redo; } } @@ -262,7 +262,7 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, /* handles all unaligned cases */ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, - int is_user, + int mmu_idx, void *retaddr) { target_phys_addr_t physaddr; @@ -271,9 +271,9 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_table[is_user][index].addr_write; + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = addr + env->tlb_table[is_user][index].addend; + physaddr = addr + env->tlb_table[mmu_idx][index].addend; if (tlb_addr & ~TARGET_PAGE_MASK) { /* IO access */ if ((addr & (DATA_SIZE - 1)) != 0) @@ -285,10 +285,10 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, for(i = 0;i < DATA_SIZE; i++) { #ifdef TARGET_WORDS_BIGENDIAN glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), - is_user, retaddr); + mmu_idx, retaddr); #else glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), - is_user, retaddr); + mmu_idx, retaddr); #endif } } else { @@ -297,7 +297,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, } } else { /* the page is not in the TLB : fill it */ - tlb_fill(addr, 1, is_user, retaddr); + tlb_fill(addr, 1, mmu_idx, retaddr); goto redo; } } diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 3f517e67b..579ce613d 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -256,6 +256,8 @@ struct pal_handler_t { void (*call_pal)(CPUAlphaState *env, uint32_t palcode); }; +#define NB_MMU_MODES 4 + struct CPUAlphaState { uint64_t ir[31]; float64 fir[31]; @@ -302,6 +304,17 @@ struct CPUAlphaState { #define cpu_gen_code cpu_alpha_gen_code #define cpu_signal_handler cpu_alpha_signal_handler +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _executive +#define MMU_MODE2_SUFFIX _supervisor +#define MMU_MODE3_SUFFIX _user +#define MMU_USER_IDX 3 +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->ps >> 3) & 3; +} + #include "cpu-all.h" enum { diff --git a/target-alpha/exec.h b/target-alpha/exec.h index 80f358ca3..62cd07dcf 100644 --- a/target-alpha/exec.h +++ b/target-alpha/exec.h @@ -73,7 +73,7 @@ static inline void regs_to_env(void) } int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw, - int is_user, int is_softmmu); + int mmu_idx, int is_softmmu); int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 72cae49cf..fd39f5f89 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -28,7 +28,7 @@ #if defined(CONFIG_USER_ONLY) int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { if (rw == 2) env->exception_index = EXCP_ITB_MISS; @@ -57,7 +57,7 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) } int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { uint32_t opc; diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index deac6c259..badb85d69 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -1164,20 +1164,20 @@ void helper_mtpr (int iprn) void helper_ld_phys_to_virt (void) { uint64_t tlb_addr, physaddr; - int index, is_user; + int index, mmu_idx; void *retaddr; - is_user = (env->ps >> 3) & 3; + mmu_idx = cpu_mmu_index(env); index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_table[is_user][index].addr_read; + tlb_addr = env->tlb_table[mmu_idx][index].addr_read; if ((T0 & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = T0 + env->tlb_table[is_user][index].addend; + physaddr = T0 + env->tlb_table[mmu_idx][index].addend; } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); - tlb_fill(T0, 0, is_user, retaddr); + tlb_fill(T0, 0, mmu_idx, retaddr); goto redo; } T0 = physaddr; @@ -1186,20 +1186,20 @@ void helper_ld_phys_to_virt (void) void helper_st_phys_to_virt (void) { uint64_t tlb_addr, physaddr; - int index, is_user; + int index, mmu_idx; void *retaddr; - is_user = (env->ps >> 3) & 3; + mmu_idx = cpu_mmu_index(env); index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); redo: - tlb_addr = env->tlb_table[is_user][index].addr_write; + tlb_addr = env->tlb_table[mmu_idx][index].addr_write; if ((T0 & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { - physaddr = T0 + env->tlb_table[is_user][index].addend; + physaddr = T0 + env->tlb_table[mmu_idx][index].addend; } else { /* the page is not in the TLB : fill it */ retaddr = GETPC(); - tlb_fill(T0, 1, is_user, retaddr); + tlb_fill(T0, 1, mmu_idx, retaddr); goto redo; } T0 = physaddr; @@ -1223,7 +1223,7 @@ void helper_st_phys_to_virt (void) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; @@ -1234,7 +1234,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; - ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (!likely(ret == 0)) { if (likely(retaddr)) { /* now we have a real cpu fault */ diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7510a2480..5ffca1145 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -43,6 +43,8 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info, typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info, int dstreg, int operand); +#define NB_MMU_MODES 2 + /* We currently assume float and double are IEEE single and double precision respectively. Doing runtime conversions is tricky because VFP registers may contain @@ -301,6 +303,15 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define cpu_signal_handler cpu_arm_signal_handler #define cpu_list arm_cpu_list +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR ? 1 : 0; +} + #include "cpu-all.h" #endif diff --git a/target-arm/exec.h b/target-arm/exec.h index 9da19150b..0c53b8d5f 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -46,7 +46,7 @@ static inline void regs_to_env(void) } int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu); + int mmu_idx, int is_softmmu); static inline int cpu_halted(CPUState *env) { if (!env->halted) diff --git a/target-arm/helper.c b/target-arm/helper.c index 4501feaef..4f851ce22 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -169,7 +169,7 @@ void do_interrupt (CPUState *env) } int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { if (rw == 2) { env->exception_index = EXCP_PREFETCH_ABORT; @@ -547,18 +547,19 @@ do_fault: } int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, - int access_type, int is_user, int is_softmmu) + int access_type, int mmu_idx, int is_softmmu) { uint32_t phys_addr; int prot; - int ret; + int ret, is_user; + is_user = mmu_idx == MMU_USER_IDX; ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot); if (ret == 0) { /* Map a single [sub]page. */ phys_addr &= ~(uint32_t)0x3ff; address &= ~(uint32_t)0x3ff; - return tlb_set_page (env, address, phys_addr, prot, is_user, + return tlb_set_page (env, address, phys_addr, prot, mmu_idx, is_softmmu); } diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index c861bf7e4..c0e7c8d64 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -196,7 +196,7 @@ void do_vfp_get_fpscr(void) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; @@ -207,7 +207,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; - ret = cpu_arm_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (__builtin_expect(ret, 0)) { if (retaddr) { /* now we have a real cpu fault */ diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 11652c50f..ef0953b26 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -74,6 +74,8 @@ /* Internal flags for the implementation. */ #define F_DELAYSLOT 1 +#define NB_MMU_MODES 2 + typedef struct CPUCRISState { uint32_t debug1; uint32_t debug2; @@ -229,6 +231,16 @@ void register_cris_insns (CPUCRISState *env); #define cpu_gen_code cpu_cris_gen_code #define cpu_signal_handler cpu_cris_signal_handler +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +/* CRIS FIXME: I guess we want to validate supervisor mode acceses here. */ +static inline int cpu_mmu_index (CPUState *env) +{ + return 0; +} + #include "cpu-all.h" /* Register aliases. */ diff --git a/target-cris/exec.h b/target-cris/exec.h index a4f555eb2..fe63f1698 100644 --- a/target-cris/exec.h +++ b/target-cris/exec.h @@ -45,8 +45,8 @@ static inline void regs_to_env(void) } int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu); -void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr); + int mmu_idx, int is_softmmu); +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr); #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" diff --git a/target-cris/helper.c b/target-cris/helper.c index 3db3bea08..98305605a 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -35,7 +35,7 @@ void do_interrupt (CPUState *env) } int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { env->exception_index = 0xaa; env->debug1 = address; @@ -52,7 +52,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) #else /* !CONFIG_USER_ONLY */ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { struct cris_mmu_result_t res; int prot, miss; @@ -61,7 +61,7 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, address &= TARGET_PAGE_MASK; prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; // printf ("%s pc=%x %x w=%d smmu=%d\n", __func__, env->pc, address, rw, is_softmmu); - miss = cris_mmu_translate(&res, env, address, rw, is_user); + miss = cris_mmu_translate(&res, env, address, rw, mmu_idx); if (miss) { /* handle the miss. */ @@ -73,7 +73,7 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, phy = res.phy; } // printf ("a=%x phy=%x\n", address, phy); - return tlb_set_page(env, address, phy, prot, is_user, is_softmmu); + return tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu); } diff --git a/target-cris/mmu.c b/target-cris/mmu.c index 56299b7dd..2be4eb8f7 100644 --- a/target-cris/mmu.c +++ b/target-cris/mmu.c @@ -111,11 +111,12 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, int cris_mmu_translate(struct cris_mmu_result_t *res, CPUState *env, uint32_t vaddr, - int rw, int is_user) + int rw, int mmu_idx) { uint32_t phy = vaddr; int seg; int miss = 0; + int is_user = mmu_idx == MMU_USER_IDX; if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) { res->phy = vaddr; diff --git a/target-cris/mmu.h b/target-cris/mmu.h index adbc1fc5d..519c0fc81 100644 --- a/target-cris/mmu.h +++ b/target-cris/mmu.h @@ -17,4 +17,4 @@ struct cris_mmu_result_t int cris_mmu_translate(struct cris_mmu_result_t *res, CPUState *env, uint32_t vaddr, - int rw, int is_user); + int rw, int mmu_idx); diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index f84ceb9da..4f0f07cd4 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -41,7 +41,7 @@ NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; @@ -52,7 +52,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; - ret = cpu_cris_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (__builtin_expect(ret, 0)) { if (retaddr) { /* now we have a real cpu fault */ diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2cc7d64e9..23419909c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -432,6 +432,8 @@ typedef union { #define CPU_NB_REGS 8 #endif +#define NB_MMU_MODES 2 + typedef struct CPUX86State { #if TARGET_LONG_BITS > HOST_LONG_BITS /* temporaries if we cannot store them in host registers */ @@ -688,6 +690,15 @@ static inline int cpu_get_time_fast(void) #define cpu_gen_code cpu_x86_gen_code #define cpu_signal_handler cpu_x86_signal_handler +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; +} + #include "cpu-all.h" #include "svm.h" diff --git a/target-i386/exec.h b/target-i386/exec.h index 1cb73467b..8e2a55321 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -163,8 +163,8 @@ void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr); int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, - int is_write, int is_user, int is_softmmu); -void tlb_fill(target_ulong addr, int is_write, int is_user, + int is_write, int mmu_idx, int is_softmmu); +void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr); void __hidden cpu_lock(void); void __hidden cpu_unlock(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 91fd6a96c..c5d4487a6 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3885,7 +3885,7 @@ void update_fp_status(void) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; int ret; @@ -3897,7 +3897,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) saved_env = env; env = cpu_single_env; - ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (ret) { if (retaddr) { /* now we have a real cpu fault */ diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 541d83f92..7d5275c10 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -571,7 +571,7 @@ void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr) #if defined(CONFIG_USER_ONLY) int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, - int is_write, int is_user, int is_softmmu) + int is_write, int mmu_idx, int is_softmmu) { /* user mode only emulation */ is_write &= 1; @@ -598,14 +598,15 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) 2 = soft MMU activation required for this block */ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, - int is_write1, int is_user, int is_softmmu) + int is_write1, int mmu_idx, int is_softmmu) { uint64_t ptep, pte; uint32_t pdpe_addr, pde_addr, pte_addr; - int error_code, is_dirty, prot, page_size, ret, is_write; + int error_code, is_dirty, prot, page_size, ret, is_write, is_user; unsigned long paddr, page_offset; target_ulong vaddr, virt_addr; + is_user = mmu_idx == MMU_USER_IDX; #if defined(DEBUG_MMU) printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", addr, is_write1, is_user, env->eip); @@ -862,7 +863,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, paddr = (pte & TARGET_PAGE_MASK) + page_offset; vaddr = virt_addr + page_offset; - ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); + ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); return ret; do_fault_protect: error_code = PG_ERROR_P_MASK; diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index a34c13734..5004a9168 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -53,6 +53,8 @@ #define EXCP_RTE 0x100 #define EXCP_HALT_INSN 0x101 +#define NB_MMU_MODES 2 + typedef struct CPUM68KState { uint32_t dregs[8]; uint32_t aregs[8]; @@ -223,6 +225,15 @@ void register_m68k_insns (CPUM68KState *env); #define cpu_gen_code cpu_m68k_gen_code #define cpu_signal_handler cpu_m68k_signal_handler +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->sr & SR_S) == 0 ? 1 : 0; +} + #include "cpu-all.h" #endif diff --git a/target-m68k/exec.h b/target-m68k/exec.h index dc5bf5e60..b9e13ef04 100644 --- a/target-m68k/exec.h +++ b/target-m68k/exec.h @@ -38,7 +38,7 @@ static inline void regs_to_env(void) } int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu); + int mmu_idx, int is_softmmu); #if !defined(CONFIG_USER_ONLY) #include "softmmu_exec.h" diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 423a0e00a..f3c629979 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -301,7 +301,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) #if defined(CONFIG_USER_ONLY) int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { env->exception_index = EXCP_ACCESS; env->mmu.ar = address; @@ -311,13 +311,13 @@ int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #else int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { int prot; address &= TARGET_PAGE_MASK; prot = PAGE_READ | PAGE_WRITE; - return tlb_set_page(env, address, address, prot, is_user, is_softmmu); + return tlb_set_page(env, address, address, prot, mmu_idx, is_softmmu); } /* Notify CPU of a pending interrupt. Prioritization and vectoring should diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 70b7aec0e..917ef5288 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -49,7 +49,7 @@ extern int semihosting_enabled; NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; @@ -60,7 +60,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; - ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (__builtin_expect(ret, 0)) { if (retaddr) { /* now we have a real cpu fault */ diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 137260f32..35bf2fbf6 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -107,6 +107,8 @@ struct CPUMIPSFPUContext { #define FP_UNIMPLEMENTED 32 }; +#define NB_MMU_MODES 2 + typedef struct CPUMIPSMVPContext CPUMIPSMVPContext; struct CPUMIPSMVPContext { int32_t CP0_MVPControl; @@ -484,6 +486,15 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def); #define cpu_signal_handler cpu_mips_signal_handler #define cpu_list mips_cpu_list +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 1 : 0; +} + #include "cpu-all.h" /* Memory access type : diff --git a/target-mips/exec.h b/target-mips/exec.h index 45be7b37c..c6dc25cf6 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -105,7 +105,7 @@ void do_pmon (int function); void dump_sc (void); int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu); + int mmu_idx, int is_softmmu); void do_interrupt (CPUState *env); void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra); diff --git a/target-mips/helper.c b/target-mips/helper.c index a881876ff..45874d446 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -229,7 +229,7 @@ void cpu_mips_init_mmu (CPUState *env) #endif /* !defined(CONFIG_USER_ONLY) */ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { target_ulong physical; int prot; @@ -241,8 +241,8 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if 0 cpu_dump_state(env, logfile, fprintf, 0); #endif - fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d is_user %d smmu %d\n", - __func__, env->PC[env->current_tc], address, rw, is_user, is_softmmu); + fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n", + __func__, env->PC[env->current_tc], address, rw, mmu_idx, is_softmmu); } rw &= 1; @@ -265,7 +265,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, if (ret == TLBRET_MATCH) { ret = tlb_set_page(env, address & TARGET_PAGE_MASK, physical & TARGET_PAGE_MASK, prot, - is_user, is_softmmu); + mmu_idx, is_softmmu); } else if (ret < 0) { do_fault: switch (ret) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 6d732a8a0..6d7f750d0 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -563,7 +563,7 @@ static void do_unaligned_access (target_ulong addr, int is_write, int is_user, v do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL); } -void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; @@ -574,7 +574,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; - ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (ret) { if (retaddr) { /* now we have a real cpu fault */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b424abceb..d39bd971a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -434,6 +434,12 @@ enum { POWERPC_FLAG_PMM = 0x00000400, }; +#if defined(TARGET_PPC64H) +#define NB_MMU_MODES 3 +#else +#define NB_MMU_MODES 2 +#endif + /*****************************************************************************/ /* The whole PowerPC CPU context */ struct CPUPPCState { @@ -575,6 +581,7 @@ struct CPUPPCState { jmp_buf jmp_env; int user_mode_only; /* user mode only simulation */ target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ + int mmu_idx; /* precomputed MMU index to speed up mem accesses */ /* Power management */ int power_mode; @@ -699,6 +706,18 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); #define cpu_signal_handler cpu_ppc_signal_handler #define cpu_list ppc_cpu_list +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _user +#define MMU_MODE1_SUFFIX _kernel +#if defined(TARGET_PPC64H) +#define MMU_MODE2_SUFFIX _hypv +#endif +#define MMU_USER_IDX 0 +static inline int cpu_mmu_index (CPUState *env) +{ + return env->mmu_idx; +} + #include "cpu-all.h" /*****************************************************************************/ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 3fedf493e..5685fd7a4 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -112,7 +112,7 @@ static always_inline void regs_to_env (void) } int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu); + int mmu_idx, int is_softmmu); static always_inline int cpu_halted (CPUState *env) { diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c4eab18fc..dd5a07a53 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -39,7 +39,7 @@ #if defined(CONFIG_USER_ONLY) int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { int exception, error_code; @@ -1349,7 +1349,7 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) /* Perform address translation */ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { mmu_ctx_t ctx; int access_type; @@ -1370,7 +1370,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, if (ret == 0) { ret = tlb_set_page(env, address & TARGET_PAGE_MASK, ctx.raddr & TARGET_PAGE_MASK, ctx.prot, - is_user, is_softmmu); + mmu_idx, is_softmmu); } else if (ret < 0) { #if defined (DEBUG_MMU) if (loglevel != 0) @@ -2083,7 +2083,12 @@ void do_compute_hflags (CPUPPCState *env) env->hflags |= msr_cm << MSR_CM; env->hflags |= (uint64_t)msr_sf << MSR_SF; env->hflags |= (uint64_t)msr_hv << MSR_HV; + /* Precompute MMU index */ + if (msr_pr == 0 && msr_hv == 1) + env->mmu_idx = 2; + else #endif + env->mmu_idx = 1 - msr_pr; } /*****************************************************************************/ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 7a758f6c0..38c3a7ff8 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2307,7 +2307,7 @@ DO_SPE_OP1(fsctuf); NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; @@ -2318,7 +2318,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; - ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (unlikely(ret != 0)) { if (likely(retaddr)) { /* now we have a real cpu fault */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index eb795fb6f..6f2a9721f 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6693,15 +6693,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, ctx.tb = tb; ctx.exception = POWERPC_EXCP_NONE; ctx.spr_cb = env->spr_cb; -#if defined(CONFIG_USER_ONLY) - supervisor = 0; -#else -#if defined(TARGET_PPC64H) - if (msr_pr == 0 && msr_hv == 1) - supervisor = 2; - else -#endif - supervisor = 1 - msr_pr; + supervisor = env->mmu_idx; +#if !defined(CONFIG_USER_ONLY) ctx.supervisor = supervisor; #endif #if defined(TARGET_PPC64) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index add6a47b1..edfda1f90 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -77,6 +77,8 @@ typedef struct tlb_t { #define UTLB_SIZE 64 #define ITLB_SIZE 4 +#define NB_MMU_MODES 2 + typedef struct CPUSH4State { uint32_t flags; /* general execution flags */ uint32_t gregs[24]; /* general registers */ @@ -134,6 +136,15 @@ int cpu_sh4_signal_handler(int host_signum, void *pinfo, #define cpu_gen_code cpu_sh4_gen_code #define cpu_signal_handler cpu_sh4_signal_handler +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index (CPUState *env) +{ + return (env->sr & SR_MD) == 0 ? 1 : 0; +} + #include "cpu-all.h" /* Memory access type */ diff --git a/target-sh4/exec.h b/target-sh4/exec.h index a606fd186..608179918 100644 --- a/target-sh4/exec.h +++ b/target-sh4/exec.h @@ -63,7 +63,7 @@ static inline void env_to_regs(void) } int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, - int is_user, int is_softmmu); + int mmu_idx, int is_softmmu); int find_itlb_entry(CPUState * env, target_ulong address, int use_asid, int update); diff --git a/target-sh4/helper.c b/target-sh4/helper.c index a5af5ba15..b8a05e124 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -36,7 +36,7 @@ void do_interrupt (CPUState *env) } int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { env->tea = address; switch (rw) { @@ -372,15 +372,15 @@ int get_physical_address(CPUState * env, target_ulong * physical, } int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { target_ulong physical, page_offset, page_size; int prot, ret, access_type; /* XXXXX */ #if 0 - fprintf(stderr, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n", - __func__, env->pc, address, rw, is_user, is_softmmu); + fprintf(stderr, "%s pc %08x ad %08x rw %d mmu_idx %d smmu %d\n", + __func__, env->pc, address, rw, mmu_idx, is_softmmu); #endif access_type = ACCESS_INT; @@ -426,7 +426,7 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, address = (address & TARGET_PAGE_MASK) + page_offset; physical = (physical & TARGET_PAGE_MASK) + page_offset; - return tlb_set_page(env, address, physical, prot, is_user, is_softmmu); + return tlb_set_page(env, address, physical, prot, mmu_idx, is_softmmu); } target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index 292e9b30d..2535b8d6a 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -42,7 +42,7 @@ void do_raise_exception(void) #define SHIFT 3 #include "softmmu_template.h" -void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; @@ -53,7 +53,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) generated code */ saved_env = env; env = cpu_single_env; - ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (ret) { if (retaddr) { /* now we have a real cpu fault */ diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index fac18a777..30e1d827d 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -166,6 +166,8 @@ typedef struct sparc_def_t sparc_def_t; +#define NB_MMU_MODES 2 + typedef struct CPUSPARCState { target_ulong gregs[8]; /* general registers */ target_ulong *regwptr; /* pointer to current register window */ @@ -317,6 +319,15 @@ void cpu_check_irqs(CPUSPARCState *env); #define cpu_signal_handler cpu_sparc_signal_handler #define cpu_list sparc_cpu_list +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _user +#define MMU_USER_IDX 1 +static inline int cpu_mmu_index (CPUState *env) +{ + return env->psrs == 0 ? 1 : 0; +} + #include "cpu-all.h" #endif diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 063e2ee64..81c4741be 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -115,7 +115,7 @@ static inline void regs_to_env(void) } int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu); + int mmu_idx, int is_softmmu); static inline int cpu_halted(CPUState *env) { if (!env->halted) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index af8bc9694..ebe642f8c 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -49,7 +49,7 @@ void cpu_unlock(void) #if defined(CONFIG_USER_ONLY) int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { if (rw & 2) env->exception_index = TT_TFAULT; @@ -100,15 +100,16 @@ static const int perm_table[2][8] = { int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, int *access_index, target_ulong address, int rw, - int is_user) + int mmu_idx) { int access_perms = 0; target_phys_addr_t pde_ptr; uint32_t pde; target_ulong virt_addr; - int error_code = 0, is_dirty; + int error_code = 0, is_dirty, is_user; unsigned long page_offset; + is_user = mmu_idx == MMU_USER_IDX; virt_addr = address & TARGET_PAGE_MASK; if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ @@ -216,13 +217,13 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot /* Perform address translation */ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { target_phys_addr_t paddr; target_ulong vaddr; int error_code = 0, prot, ret = 0, access_index; - error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); + error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, mmu_idx); if (error_code == 0) { vaddr = address & TARGET_PAGE_MASK; paddr &= TARGET_PAGE_MASK; @@ -230,7 +231,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " TARGET_FMT_lx "\n", address, paddr, vaddr); #endif - ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); + ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); return ret; } @@ -246,7 +247,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, // switching to normal mode. vaddr = address & TARGET_PAGE_MASK; prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); + ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); return ret; } else { if (rw & 2) @@ -484,8 +485,10 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot, int *access_index, target_ulong address, int rw, - int is_user) + int mmu_idx) { + int is_user = mmu_idx == MMU_USER_IDX; + if (rw == 2) return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user); else @@ -494,20 +497,20 @@ int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot, /* Perform address translation */ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, - int is_user, int is_softmmu) + int mmu_idx, int is_softmmu) { target_ulong virt_addr, vaddr; target_phys_addr_t paddr; int error_code = 0, prot, ret = 0, access_index; - error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user); + error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, mmu_idx); if (error_code == 0) { virt_addr = address & TARGET_PAGE_MASK; vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1)); #ifdef DEBUG_MMU printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr); #endif - ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu); + ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); return ret; } // XXX diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index a4839a055..6d08e1c65 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1522,7 +1522,7 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user, NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) +void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; int ret; @@ -1534,7 +1534,7 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) saved_env = env; env = cpu_single_env; - ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1); + ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); if (ret) { if (retaddr) { /* now we have a real cpu fault */ diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 27c22ede5..3027bb8af 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3689,7 +3689,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) #else extern int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, int *access_index, target_ulong address, int rw, - int is_user); + int mmu_idx); target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { -- cgit v1.2.3 From b1806c9e67fd887bca117af2fc061f3dcc3beb98 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 08:18:12 +0000 Subject: Generate micro-ops for Alpha executive and supervisor modes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3385 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/op.c | 10 +++++++--- target-alpha/op_helper.c | 12 +++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/target-alpha/op.c b/target-alpha/op.c index 529a66de0..409325221 100644 --- a/target-alpha/op.c +++ b/target-alpha/op.c @@ -140,11 +140,15 @@ void OPPROTO op_tb_flush (void) #define MEMSUFFIX _raw #include "op_mem.h" #if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.h" #define MEMSUFFIX _kernel #include "op_mem.h" -/* Those are used for supervisor, executive and pal modes */ +#define MEMSUFFIX _executive +#include "op_mem.h" +#define MEMSUFFIX _supervisor +#include "op_mem.h" +#define MEMSUFFIX _user +#include "op_mem.h" +/* This is used for pal modes */ #define MEMSUFFIX _data #include "op_mem.h" #endif diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index badb85d69..e471a1f06 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -27,13 +27,19 @@ #include "op_helper_mem.h" #if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user +#define MEMSUFFIX _kernel #include "op_helper_mem.h" -#define MEMSUFFIX _kernel +#define MEMSUFFIX _executive +#include "op_helper_mem.h" + +#define MEMSUFFIX _supervisor +#include "op_helper_mem.h" + +#define MEMSUFFIX _user #include "op_helper_mem.h" -/* Those are used for supervisor and executive modes */ +/* This is used for pal modes */ #define MEMSUFFIX _data #include "op_helper_mem.h" #endif -- cgit v1.2.3 From 1e42b8f06dedf7229c3e7d4660ef85e404f8692f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 08:27:14 +0000 Subject: Generate micro-ops for PowerPC hypervisor mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3386 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 5 +++++ target-ppc/op_helper.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/target-ppc/op.c b/target-ppc/op.c index 1412c09ae..4889ad476 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1919,6 +1919,11 @@ void OPPROTO op_fneg (void) #define MEMSUFFIX _kernel #include "op_helper.h" #include "op_mem.h" +#if defined(TARGET_PPC64H) +#define MEMSUFFIX _hypv +#include "op_helper.h" +#include "op_mem.h" +#endif #endif /* Special op to check and maybe clear reservation */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 38c3a7ff8..f5331bace 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -31,6 +31,11 @@ #define MEMSUFFIX _kernel #include "op_helper.h" #include "op_helper_mem.h" +#if defined(TARGET_PPC64H) +#define MEMSUFFIX _hypv +#include "op_helper.h" +#include "op_helper_mem.h" +#endif #endif //#define DEBUG_OP -- cgit v1.2.3 From 22f8a8b31c1e20df835eb4a779c573647753ee77 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 08:38:29 +0000 Subject: Provision for PowerPC 64 with hypervisor mode support - not enabled for now. For consistency, group all PowerPC targets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3387 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +++ configure | 21 ++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Makefile.target b/Makefile.target index 8ebe3c3c7..e26491938 100644 --- a/Makefile.target +++ b/Makefile.target @@ -13,6 +13,9 @@ endif ifeq ($(TARGET_ARCH), ppc64) TARGET_BASE_ARCH:=ppc endif +ifeq ($(TARGET_ARCH), ppc64h) +TARGET_BASE_ARCH:=ppc +endif ifeq ($(TARGET_ARCH), ppcemb) TARGET_BASE_ARCH:=ppc endif diff --git a/configure b/configure index 8e705e1b0..1ef6933dc 100755 --- a/configure +++ b/configure @@ -500,11 +500,11 @@ 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 mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu sh4-softmmu cris-softmmu" + target_list="i386-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc-softmmu ppcemb-softmmu ppc64-softmmu m68k-softmmu sh4-softmmu cris-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user ppc64-linux-user sh4-linux-user cris-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppc64-linux-user x86_64-linux-user cris-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then @@ -934,8 +934,9 @@ target_bigendian="no" [ "$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" = "ppcemb" ] && target_bigendian=yes +[ "$target_cpu" = "ppc64" ] && target_bigendian=yes +[ "$target_cpu" = "ppc64h" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes [ "$target_cpu" = "mipsn32" ] && target_bigendian=yes [ "$target_cpu" = "mips64" ] && target_bigendian=yes @@ -1029,16 +1030,22 @@ 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" = "ppcemb" ; then + echo "TARGET_ARCH=ppcemb" >> $config_mak + echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h + echo "#define TARGET_PPC 1" >> $config_h + echo "#define TARGET_PPCEMB 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" = "ppcemb" ; then - echo "TARGET_ARCH=ppcemb" >> $config_mak - echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h +elif test "$target_cpu" = "ppc64h" ; then + echo "TARGET_ARCH=ppc64h" >> $config_mak + echo "#define TARGET_ARCH \"ppc64h\"" >> $config_h echo "#define TARGET_PPC 1" >> $config_h - echo "#define TARGET_PPCEMB 1" >> $config_h + echo "#define TARGET_PPC64 1" >> $config_h + echo "#define TARGET_PPC64H 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 -- cgit v1.2.3 From e63ecc6f68d5f9349683aef5d74e36137eafb72d Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 08:48:23 +0000 Subject: Do not allow PowerPC CPU restart after entering checkstop mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3388 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 8 +------- target-ppc/helper.c | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 46179dd56..2fd3a4e57 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -103,6 +103,7 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) case PPC6xx_INPUT_CKSTP_IN: /* Level sensitive - active low */ /* XXX: TODO: relay the signal to CKSTP_OUT pin */ + /* XXX: Note that the only way to restart the CPU is to reset it */ if (level) { #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { @@ -110,13 +111,6 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) } #endif env->halted = 1; - } else { -#if defined(PPC_DEBUG_IRQ) - if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: restart the CPU\n", __func__); - } -#endif - env->halted = 0; } break; case PPC6xx_INPUT_HRESET: diff --git a/target-ppc/helper.c b/target-ppc/helper.c index dd5a07a53..b3f3ae6d7 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2156,10 +2156,18 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; case POWERPC_EXCP_MCHECK: /* Machine check exception */ if (msr_me == 0) { - /* Machine check exception is not enabled */ - /* XXX: we may just stop the processor here, to allow debugging */ - excp = POWERPC_EXCP_RESET; - goto excp_reset; + /* Machine check exception is not enabled. + * Enter checkstop state. + */ + if (loglevel != 0) { + fprintf(logfile, "Machine check while not allowed. " + "Entering checkstop state\n"); + } else { + fprintf(stderr, "Machine check while not allowed. " + "Entering checkstop state\n"); + } + env->halted = 1; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; } msr_ri = 0; msr_me = 0; @@ -2413,7 +2421,6 @@ static always_inline void powerpc_excp (CPUState *env, #if defined(TARGET_PPC64H) msr_hv = 1; #endif - excp_reset: goto store_next; #if defined(TARGET_PPC64) case POWERPC_EXCP_DSEG: /* Data segment exception */ -- cgit v1.2.3 From bb6f6792bfa5ee7e3526fa3a23c622296e8bff1a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 08:50:17 +0000 Subject: Allow Alpha target to use supervisor and executive mode micro-ops. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3389 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/translate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 6a7da5adf..c036323cb 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -190,16 +190,16 @@ static GenOpFunc *gen_op_st##width[] = { \ #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_ld##width[] = { \ &gen_op_ld##width##_kernel, \ - &gen_op_ld##width##_user, /* executive */ \ - &gen_op_ld##width##_data, /* supervisor */ \ - &gen_op_ld##width##_data, /* user */ \ + &gen_op_ld##width##_executive, \ + &gen_op_ld##width##_supervisor, \ + &gen_op_ld##width##_user, \ } #define OP_ST_TABLE(width) \ static GenOpFunc *gen_op_st##width[] = { \ &gen_op_st##width##_kernel, \ - &gen_op_st##width##_user, /* executive */ \ - &gen_op_st##width##_data, /* supervisor */ \ - &gen_op_st##width##_data, /* user */ \ + &gen_op_st##width##_executive, \ + &gen_op_st##width##_supervisor, \ + &gen_op_st##width##_user, \ } #endif -- cgit v1.2.3 From a01d8cadadf4c0dad8fc5157ee56aea8ec323982 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 08:52:44 +0000 Subject: Fix memory corruption reported by Julian Seward (still more bugs to fix in PreP emulation). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3390 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/prep_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/prep_pci.c b/hw/prep_pci.c index f384e4215..6d6a1349c 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -135,7 +135,7 @@ PCIBus *pci_prep_init(qemu_irq *pic) int PPC_io_memory; s = qemu_mallocz(sizeof(PREPPCIState)); - s->bus = pci_register_bus(prep_set_irq, prep_map_irq, pic, 0, 2); + s->bus = pci_register_bus(prep_set_irq, prep_map_irq, pic, 0, 4); register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); -- cgit v1.2.3 From eacc324914c2dc7aecec3b4ea920252b685b5c8e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 09:06:19 +0000 Subject: Implement PowerPC 64 SLB invalidation helpers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3391 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 82 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b3f3ae6d7..eeba478be 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -601,6 +601,16 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, } #if defined(TARGET_PPC64) +static inline int slb_is_valid (uint64_t slb64) +{ + return slb64 & 0x0000000008000000ULL ? 1 : 0; +} + +static inline void slb_invalidate (uint64_t *slb64) +{ + *slb64 &= ~0x0000000008000000ULL; +} + static int slb_lookup (CPUPPCState *env, target_ulong eaddr, target_ulong *vsid, target_ulong *page_mask, int *attr) { @@ -609,7 +619,6 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, uint64_t tmp64; uint32_t tmp; int n, ret; - int slb_nr; ret = -5; sr_base = env->spr[SPR_ASR]; @@ -620,8 +629,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, } #endif mask = 0x0000000000000000ULL; /* Avoid gcc warning */ - slb_nr = env->slb_nr; - for (n = 0; n < slb_nr; n++) { + for (n = 0; n < env->slb_nr; n++) { tmp64 = ldq_phys(sr_base); tmp = ldl_phys(sr_base + 8); #if defined(DEBUG_SLB) @@ -630,7 +638,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, PRIx32 "\n", __func__, n, sr_base, tmp64, tmp); } #endif - if (tmp64 & 0x0000000008000000ULL) { + if (slb_is_valid(tmp64)) { /* SLB entry is valid */ switch (tmp64 & 0x0000000006000000ULL) { case 0x0000000000000000ULL: @@ -651,7 +659,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; *page_mask = ~mask; *attr = tmp & 0xFF; - ret = 0; + ret = n; break; } } @@ -661,6 +669,56 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, return ret; } +void ppc_slb_invalidate_all (CPUPPCState *env) +{ + target_phys_addr_t sr_base; + uint64_t tmp64; + int n, do_invalidate; + + do_invalidate = 0; + sr_base = env->spr[SPR_ASR]; + for (n = 0; n < env->slb_nr; n++) { + tmp64 = ldq_phys(sr_base); + if (slb_is_valid(tmp64)) { + slb_invalidate(&tmp64); + stq_phys(sr_base, tmp64); + /* XXX: given the fact that segment size is 256 MB or 1TB, + * and we still don't have a tlb_flush_mask(env, n, mask) + * in Qemu, we just invalidate all TLBs + */ + do_invalidate = 1; + } + sr_base += 12; + } + if (do_invalidate) + tlb_flush(env, 1); +} + +void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) +{ + target_phys_addr_t sr_base; + target_ulong vsid, page_mask; + uint64_t tmp64; + int attr; + int n; + + n = slb_lookup(env, T0, &vsid, &page_mask, &attr); + if (n >= 0) { + sr_base = env->spr[SPR_ASR]; + sr_base += 12 * n; + tmp64 = ldq_phys(sr_base); + if (slb_is_valid(tmp64)) { + slb_invalidate(&tmp64); + stq_phys(sr_base, tmp64); + /* XXX: given the fact that segment size is 256 MB or 1TB, + * and we still don't have a tlb_flush_mask(env, n, mask) + * in Qemu, we just invalidate all TLBs + */ + tlb_flush(env, 1); + } + } +} + target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr) { target_phys_addr_t sr_base; @@ -1828,20 +1886,6 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) #endif } -#if defined(TARGET_PPC64) -void ppc_slb_invalidate_all (CPUPPCState *env) -{ - /* XXX: TODO */ - tlb_flush(env, 1); -} - -void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) -{ - /* XXX: TODO */ - tlb_flush(env, 1); -} -#endif - /*****************************************************************************/ /* Special registers manipulation */ #if defined(TARGET_PPC64) -- cgit v1.2.3 From a13d7523cb4205e633e947d37559ef3a281c323e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 09:14:08 +0000 Subject: There is no need of a specific MMU model for PowerPC 601. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3392 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 -- target-ppc/helper.c | 21 --------------------- target-ppc/translate_init.c | 5 +---- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index d39bd971a..c6fc16ecb 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -88,8 +88,6 @@ enum { POWERPC_MMU_UNKNOWN = 0, /* Standard 32 bits PowerPC MMU */ POWERPC_MMU_32B, - /* PowerPC 601 MMU */ - POWERPC_MMU_601, /* PowerPC 6xx MMU with software TLB */ POWERPC_MMU_SOFT_6xx, /* PowerPC 74xx MMU with software TLB */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index eeba478be..12c8e71af 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1280,7 +1280,6 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, case POWERPC_MMU_32B: case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: - case POWERPC_MMU_601: case POWERPC_MMU_SOFT_4xx: case POWERPC_MMU_REAL_4xx: case POWERPC_MMU_BOOKE: @@ -1365,10 +1364,6 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, ret = mmu40x_get_physical_address(env, ctx, eaddr, rw, access_type); break; - case POWERPC_MMU_601: - /* XXX: TODO */ - cpu_abort(env, "601 MMU model not implemented\n"); - return -1; case POWERPC_MMU_BOOKE: ret = mmubooke_get_physical_address(env, ctx, eaddr, rw, access_type); @@ -1462,10 +1457,6 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x40000000; break; - case POWERPC_MMU_601: - /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); - return -1; case POWERPC_MMU_BOOKE: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); @@ -1562,10 +1553,6 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, else env->spr[SPR_DSISR] = 0x40000000; break; - case POWERPC_MMU_601: - /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); - return -1; case POWERPC_MMU_BOOKE: /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); @@ -1796,10 +1783,6 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); break; - case POWERPC_MMU_601: - /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); - break; case POWERPC_MMU_32B: #if defined(TARGET_PPC64) case POWERPC_MMU_64B: @@ -1839,10 +1822,6 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) /* XXX: TODO */ cpu_abort(env, "MMU model not implemented\n"); break; - case POWERPC_MMU_601: - /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); - break; case POWERPC_MMU_32B: /* tlbie invalidate TLBs for all segments */ addr &= ~((target_ulong)-1 << 28); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 0210de853..41a4c6410 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3196,7 +3196,7 @@ static void init_proc_e500 (CPUPPCState *env) #define POWERPC_INSNS_601 (POWERPC_INSNS_6xx | PPC_CACHE_DCBZ | \ PPC_SEGMENT | PPC_EXTERN | PPC_POWER_BR) #define POWERPC_MSRM_601 (0x000000000000FD70ULL) -//#define POWERPC_MMU_601 (POWERPC_MMU_601) +#define POWERPC_MMU_601 (POWERPC_MMU_32B) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_601 (bfd_mach_ppc_601) @@ -6232,9 +6232,6 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) case POWERPC_MMU_32B: mmu_model = "PowerPC 32"; break; - case POWERPC_MMU_601: - mmu_model = "PowerPC 601"; - break; case POWERPC_MMU_SOFT_6xx: mmu_model = "PowerPC 6xx/7xx with software driven TLBs"; break; -- cgit v1.2.3 From d68f13063bea4541fbb410fc2d195eb0f2926c79 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 09:27:16 +0000 Subject: Merge PowerPC 620 input bus definitions with standard PowerPC 6xx. Avoid hardcoding PowerPC interrupts definitions to ease updates. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3393 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index c6fc16ecb..c83d0baae 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1150,6 +1150,9 @@ enum { PPC6xx_INPUT_MCP = 3, PPC6xx_INPUT_SMI = 4, PPC6xx_INPUT_INT = 5, + PPC6xx_INPUT_TBEN = 6, + PPC6xx_INPUT_WAKEUP = 7, + PPC6xx_INPUT_NB, }; enum { @@ -1161,6 +1164,7 @@ enum { PPCBookE_INPUT_SMI = 4, PPCBookE_INPUT_INT = 5, PPCBookE_INPUT_CINT = 6, + PPCBookE_INPUT_NB, }; enum { @@ -1176,18 +1180,6 @@ enum { }; #if defined(TARGET_PPC64) -enum { - /* PowerPC 620 (and probably others) input pins */ - PPC620_INPUT_HRESET = 0, - PPC620_INPUT_SRESET = 1, - PPC620_INPUT_CKSTP = 2, - PPC620_INPUT_TBEN = 3, - PPC620_INPUT_WAKEUP = 4, - PPC620_INPUT_MCP = 5, - PPC620_INPUT_SMI = 6, - PPC620_INPUT_INT = 7, -}; - enum { /* PowerPC 970 input pins */ PPC970_INPUT_HRESET = 0, @@ -1204,21 +1196,22 @@ enum { enum { /* External hardware exception sources */ PPC_INTERRUPT_RESET = 0, /* Reset exception */ - PPC_INTERRUPT_MCK = 1, /* Machine check exception */ - PPC_INTERRUPT_EXT = 2, /* External interrupt */ - PPC_INTERRUPT_SMI = 3, /* System management interrupt */ - PPC_INTERRUPT_CEXT = 4, /* Critical external interrupt */ - PPC_INTERRUPT_DEBUG = 5, /* External debug exception */ - PPC_INTERRUPT_THERM = 6, /* Thermal exception */ + PPC_INTERRUPT_WAKEUP, /* Wakeup exception */ + PPC_INTERRUPT_MCK, /* Machine check exception */ + PPC_INTERRUPT_EXT, /* External interrupt */ + PPC_INTERRUPT_SMI, /* System management interrupt */ + PPC_INTERRUPT_CEXT, /* Critical external interrupt */ + PPC_INTERRUPT_DEBUG, /* External debug exception */ + PPC_INTERRUPT_THERM, /* Thermal exception */ /* Internal hardware exception sources */ - PPC_INTERRUPT_DECR = 7, /* Decrementer exception */ - PPC_INTERRUPT_HDECR = 8, /* Hypervisor decrementer exception */ - PPC_INTERRUPT_PIT = 9, /* Programmable inteval timer interrupt */ - PPC_INTERRUPT_FIT = 10, /* Fixed interval timer interrupt */ - PPC_INTERRUPT_WDT = 11, /* Watchdog timer interrupt */ - PPC_INTERRUPT_CDOORBELL = 12, /* Critical doorbell interrupt */ - PPC_INTERRUPT_DOORBELL = 13, /* Doorbell interrupt */ - PPC_INTERRUPT_PERFM = 14, /* Performance monitor interrupt */ + PPC_INTERRUPT_DECR, /* Decrementer exception */ + PPC_INTERRUPT_HDECR, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT, /* Programmable inteval timer interrupt */ + PPC_INTERRUPT_FIT, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT, /* Watchdog timer interrupt */ + PPC_INTERRUPT_CDOORBELL, /* Critical doorbell interrupt */ + PPC_INTERRUPT_DOORBELL, /* Doorbell interrupt */ + PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */ }; /*****************************************************************************/ -- cgit v1.2.3 From dbdd25065e90ba78c01b03d238785f25476c04a1 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 09:35:30 +0000 Subject: Implement time-base start/stop helpers. Implement PowerPC 6xx time-base enable input pin. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3394 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 92 insertions(+), 29 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 2fd3a4e57..742d3de59 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -30,6 +30,9 @@ extern FILE *logfile; extern int loglevel; +static void cpu_ppc_tb_stop (CPUState *env); +static void cpu_ppc_tb_start (CPUState *env); + static void ppc_set_irq (CPUState *env, int n_IRQ, int level) { if (level) { @@ -65,6 +68,19 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { switch (pin) { + case PPC6xx_INPUT_TBEN: + /* Level sensitive - active high */ +#if defined(PPC_DEBUG_IRQ) + if (loglevel & CPU_LOG_INT) { + fprintf(logfile, "%s: %s the time base\n", + __func__, level ? "start" : "stop"); + } +#endif + if (level) { + cpu_ppc_tb_start(env); + } else { + cpu_ppc_tb_stop(env); + } case PPC6xx_INPUT_INT: /* Level sensitive - active high */ #if defined(PPC_DEBUG_IRQ) @@ -402,11 +418,12 @@ void ppc40x_irq_init (CPUState *env) /* PowerPC time base and decrementer emulation */ struct ppc_tb_t { /* Time base management */ - int64_t tb_offset; /* Compensation */ - int64_t atb_offset; /* Compensation */ - uint32_t tb_freq; /* TB frequency */ + int64_t tb_offset; /* Compensation */ + int64_t atb_offset; /* Compensation */ + uint32_t tb_freq; /* TB frequency */ /* Decrementer management */ - uint64_t decr_next; /* Tick for next decr interrupt */ + uint64_t decr_next; /* Tick for next decr interrupt */ + uint32_t decr_freq; /* decrementer frequency */ struct QEMUTimer *decr_timer; #if defined(TARGET_PPC64H) /* Hypervisor decrementer management */ @@ -418,12 +435,11 @@ struct ppc_tb_t { void *opaque; }; -static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, +static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset) { /* TB time in tb periods */ - return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, - tb_env->tb_freq, ticks_per_sec); + return muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec) + tb_offset; } uint32_t cpu_ppc_load_tbl (CPUState *env) @@ -431,7 +447,7 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); @@ -446,7 +462,7 @@ static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); @@ -461,12 +477,11 @@ uint32_t cpu_ppc_load_tbu (CPUState *env) return _cpu_ppc_load_tbu(env); } -static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, +static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t vmclk, int64_t *tb_offsetp, uint64_t value) { - *tb_offsetp = muldiv64(value, ticks_per_sec, tb_env->tb_freq) - - qemu_get_clock(vm_clock); + *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec); #ifdef PPC_DEBUG_TB if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value, @@ -480,9 +495,10 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset); tb &= 0xFFFFFFFF00000000ULL; - cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, tb | (uint64_t)value); + cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock), + &tb_env->tb_offset, tb | (uint64_t)value); } static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value) @@ -490,10 +506,10 @@ static always_inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset); tb &= 0x00000000FFFFFFFFULL; - cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, - ((uint64_t)value << 32) | tb); + cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock), + &tb_env->tb_offset, ((uint64_t)value << 32) | tb); } void cpu_ppc_store_tbu (CPUState *env, uint32_t value) @@ -506,7 +522,7 @@ uint32_t cpu_ppc_load_atbl (CPUState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); @@ -521,7 +537,7 @@ uint32_t cpu_ppc_load_atbu (CPUState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); @@ -536,9 +552,10 @@ void cpu_ppc_store_atbl (CPUState *env, uint32_t value) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset); tb &= 0xFFFFFFFF00000000ULL; - cpu_ppc_store_tb(tb_env, &tb_env->atb_offset, tb | (uint64_t)value); + cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock), + &tb_env->atb_offset, tb | (uint64_t)value); } void cpu_ppc_store_atbu (CPUState *env, uint32_t value) @@ -546,10 +563,53 @@ void cpu_ppc_store_atbu (CPUState *env, uint32_t value) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; - tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset); + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset); tb &= 0x00000000FFFFFFFFULL; - cpu_ppc_store_tb(tb_env, &tb_env->atb_offset, - ((uint64_t)value << 32) | tb); + cpu_ppc_store_tb(tb_env, qemu_get_clock(vm_clock), + &tb_env->atb_offset, ((uint64_t)value << 32) | tb); +} + +static void cpu_ppc_tb_stop (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb, atb, vmclk; + + /* If the time base is already frozen, do nothing */ + if (tb_env->tb_freq != 0) { + vmclk = qemu_get_clock(vm_clock); + /* Get the time base */ + tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset); + /* Get the alternate time base */ + atb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->atb_offset); + /* Store the time base value (ie compute the current offset) */ + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); + /* Store the alternate time base value (compute the current offset) */ + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); + /* Set the time base frequency to zero */ + tb_env->tb_freq = 0; + /* Now, the time bases are frozen to tb_offset / atb_offset value */ + } +} + +static void cpu_ppc_tb_start (CPUState *env) +{ + ppc_tb_t *tb_env = env->tb_env; + uint64_t tb, atb, vmclk; + + /* If the time base is not frozen, do nothing */ + if (tb_env->tb_freq == 0) { + vmclk = qemu_get_clock(vm_clock); + /* Get the time base from tb_offset */ + tb = tb_env->tb_offset; + /* Get the alternate time base from atb_offset */ + atb = tb_env->atb_offset; + /* Restore the tb frequency from the decrementer frequency */ + tb_env->tb_freq = tb_env->decr_freq; + /* Store the time base value */ + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->tb_offset, tb); + /* Store the alternate time base value */ + cpu_ppc_store_tb(tb_env, vmclk, &tb_env->atb_offset, atb); + } } static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env, @@ -561,9 +621,9 @@ static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env, diff = tb_env->decr_next - qemu_get_clock(vm_clock); if (diff >= 0) - decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec); + decr = muldiv64(diff, tb_env->decr_freq, ticks_per_sec); else - decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec); + decr = -muldiv64(-diff, tb_env->decr_freq, ticks_per_sec); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { fprintf(logfile, "%s: 0x%08x\n", __func__, decr); @@ -639,7 +699,7 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, } #endif now = qemu_get_clock(vm_clock); - next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); + next = now + muldiv64(value, ticks_per_sec, tb_env->decr_freq); if (is_excp) next += *nextp - now; if (next == now) @@ -708,6 +768,7 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) ppc_tb_t *tb_env = env->tb_env; tb_env->tb_freq = freq; + tb_env->decr_freq = freq; /* There is a bug in Linux 2.4 kernels: * if a decrementer exception is pending when it enables msr_ee at startup, * it's not ready to handle it... @@ -848,7 +909,7 @@ static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp) #endif now = qemu_get_clock(vm_clock); next = now + muldiv64(ppcemb_timer->pit_reload, - ticks_per_sec, tb_env->tb_freq); + ticks_per_sec, tb_env->decr_freq); if (is_excp) next += tb_env->decr_next - now; if (next == now) @@ -912,7 +973,7 @@ static void cpu_4xx_wdt_cb (void *opaque) /* Cannot occur, but makes gcc happy */ return; } - next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq); + next = now + muldiv64(next, ticks_per_sec, tb_env->decr_freq); if (next == now) next++; #ifdef PPC_DEBUG_TB @@ -1014,6 +1075,7 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq) } #endif tb_env->tb_freq = freq; + tb_env->decr_freq = freq; /* XXX: we should also update all timers */ } @@ -1029,6 +1091,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) env->tb_env = tb_env; ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t)); tb_env->tb_freq = freq; + tb_env->decr_freq = freq; tb_env->opaque = ppcemb_timer; #ifdef PPC_DEBUG_TB if (loglevel != 0) { -- cgit v1.2.3 From b227a8e9aa5f27d29f77ba90d5eb9d0662a1175e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 14 Oct 2007 10:21:20 +0000 Subject: Properly implement non-execute bit on PowerPC segments and PTEs. Fix page protection bits for PowerPC 64 MMU. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3395 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 1 + target-ppc/helper.c | 265 +++++++++++++++++++++++++++------------------------- 2 files changed, 139 insertions(+), 127 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index c83d0baae..aeaacb257 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -596,6 +596,7 @@ struct mmu_ctx_t { target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */ target_ulong ptem; /* Virtual segment ID | API */ int key; /* Access key */ + int nx; /* Non-execute area */ }; /*****************************************************************************/ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 12c8e71af..76312476a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -96,12 +96,76 @@ static always_inline void pte64_invalidate (target_ulong *pte0) #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F) #endif +static always_inline int pp_check (int key, int pp, int nx) +{ + int access; + + /* Compute access rights */ + /* When pp is 3/7, the result is undefined. Set it to noaccess */ + access = 0; + if (key == 0) { + switch (pp) { + case 0x0: + case 0x1: + case 0x2: + access |= PAGE_WRITE; + /* No break here */ + case 0x3: + case 0x6: + access |= PAGE_READ; + break; + } + } else { + switch (pp) { + case 0x0: + case 0x6: + access = 0; + break; + case 0x1: + case 0x3: + access = PAGE_READ; + break; + case 0x2: + access = PAGE_READ | PAGE_WRITE; + break; + } + } + if (nx == 0) + access |= PAGE_EXEC; + + return access; +} + +static always_inline int check_prot (int prot, int rw, int access_type) +{ + int ret; + + if (access_type == ACCESS_CODE) { + if (prot & PAGE_EXEC) + ret = 0; + else + ret = -2; + } else if (rw) { + if (prot & PAGE_WRITE) + ret = 0; + else + ret = -2; + } else { + if (prot & PAGE_READ) + ret = 0; + else + ret = -2; + } + + return ret; +} + static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, target_ulong pte0, target_ulong pte1, - int h, int rw) + int h, int rw, int type) { target_ulong ptem, mmask; - int access, ret, pteh, ptev; + int access, ret, pteh, ptev, pp; access = 0; ret = -1; @@ -122,11 +186,15 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, if (is_64b) { ptem = pte0 & PTE64_PTEM_MASK; mmask = PTE64_CHECK_MASK; + pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004); + ctx->nx |= (pte1 >> 2) & 1; /* No execute bit */ + ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */ } else #endif { ptem = pte0 & PTE_PTEM_MASK; mmask = PTE_CHECK_MASK; + pp = pte1 & 0x00000003; } if (ptem == ctx->ptem) { if (ctx->raddr != (target_ulong)-1) { @@ -138,42 +206,23 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, } } /* Compute access rights */ - if (ctx->key == 0) { - access = PAGE_READ; - if ((pte1 & 0x00000003) != 0x3) - access |= PAGE_WRITE; - } else { - switch (pte1 & 0x00000003) { - case 0x0: - access = 0; - break; - case 0x1: - case 0x3: - access = PAGE_READ; - break; - case 0x2: - access = PAGE_READ | PAGE_WRITE; - break; - } - } + access = pp_check(ctx->key, pp, ctx->nx); /* Keep the matching PTE informations */ ctx->raddr = pte1; ctx->prot = access; - if ((rw == 0 && (access & PAGE_READ)) || - (rw == 1 && (access & PAGE_WRITE))) { + ret = check_prot(ctx->prot, rw, type); + if (ret == 0) { /* Access granted */ #if defined (DEBUG_MMU) if (loglevel != 0) fprintf(logfile, "PTE access granted !\n"); #endif - ret = 0; } else { /* Access right violation */ #if defined (DEBUG_MMU) if (loglevel != 0) fprintf(logfile, "PTE access rejected\n"); #endif - ret = -2; } } } @@ -181,17 +230,17 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, return ret; } -static int pte32_check (mmu_ctx_t *ctx, - target_ulong pte0, target_ulong pte1, int h, int rw) +static int pte32_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1, + int h, int rw, int type) { - return _pte_check(ctx, 0, pte0, pte1, h, rw); + return _pte_check(ctx, 0, pte0, pte1, h, rw, type); } #if defined(TARGET_PPC64) -static int pte64_check (mmu_ctx_t *ctx, - target_ulong pte0, target_ulong pte1, int h, int rw) +static int pte64_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1, + int h, int rw, int type) { - return _pte_check(ctx, 1, pte0, pte1, h, rw); + return _pte_check(ctx, 1, pte0, pte1, h, rw, type); } #endif @@ -353,7 +402,7 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D'); } #endif - switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) { + switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) { case -3: /* TLB inconsistency */ return -1; @@ -398,7 +447,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong base, BEPIl, BEPIu, bl; - int i; + int i, pp; int ret = -1; #if defined (DEBUG_BATS) @@ -447,19 +496,23 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, ctx->raddr = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | (virtual & 0x0001F000); - if (*BATl & 0x00000001) - ctx->prot = PAGE_READ; - if (*BATl & 0x00000002) - ctx->prot = PAGE_WRITE | PAGE_READ; + /* Compute access rights */ + pp = *BATl & 0x00000003; + ctx->prot = 0; + if (pp != 0) { + ctx->prot = PAGE_READ | PAGE_EXEC; + if (pp == 0x2) + ctx->prot |= PAGE_WRITE; + } + ret = check_prot(ctx->prot, rw, type); #if defined (DEBUG_BATS) - if (loglevel != 0) { + if (ret == 0 && loglevel != 0) { fprintf(logfile, "BAT %d match: r 0x" PADDRX " prot=%c%c\n", i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', ctx->prot & PAGE_WRITE ? 'W' : '-'); } #endif - ret = 0; break; } } @@ -483,12 +536,14 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, } #endif } + /* No hit */ return ret; } /* PTE table lookup */ -static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) +static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, + int rw, int type) { target_ulong base, pte0, pte1; int i, good = -1; @@ -501,7 +556,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) if (is_64b) { pte0 = ldq_phys(base + (i * 16)); pte1 = ldq_phys(base + (i * 16) + 8); - r = pte64_check(ctx, pte0, pte1, h, rw); + r = pte64_check(ctx, pte0, pte1, h, rw, type); #if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX @@ -516,7 +571,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) { pte0 = ldl_phys(base + (i * 8)); pte1 = ldl_phys(base + (i * 8) + 4); - r = pte32_check(ctx, pte0, pte1, h, rw); + r = pte32_check(ctx, pte0, pte1, h, rw, type); #if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX @@ -577,27 +632,27 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw) return ret; } -static int find_pte32 (mmu_ctx_t *ctx, int h, int rw) +static int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type) { - return _find_pte(ctx, 0, h, rw); + return _find_pte(ctx, 0, h, rw, type); } #if defined(TARGET_PPC64) -static int find_pte64 (mmu_ctx_t *ctx, int h, int rw) +static int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type) { - return _find_pte(ctx, 1, h, rw); + return _find_pte(ctx, 1, h, rw, type); } #endif static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, - int h, int rw) + int h, int rw, int type) { #if defined(TARGET_PPC64) if (env->mmu_model == POWERPC_MMU_64B) - return find_pte64(ctx, h, rw); + return find_pte64(ctx, h, rw, type); #endif - return find_pte32(ctx, h, rw); + return find_pte32(ctx, h, rw, type); } #if defined(TARGET_PPC64) @@ -796,7 +851,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, #if defined(TARGET_PPC64) int attr; #endif - int ds, nx, vsid_sh, sdr_sh; + int ds, vsid_sh, sdr_sh; int ret, ret2; #if defined(TARGET_PPC64) @@ -812,7 +867,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ctx->key = ((attr & 0x40) && msr_pr == 1) || ((attr & 0x80) && msr_pr == 0) ? 1 : 0; ds = 0; - nx = attr & 0x20 ? 1 : 0; + ctx->nx = attr & 0x20 ? 1 : 0; vsid_mask = 0x00003FFFFFFFFF80ULL; vsid_sh = 7; sdr_sh = 18; @@ -825,7 +880,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ctx->key = (((sr & 0x20000000) && msr_pr == 1) || ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; ds = sr & 0x80000000 ? 1 : 0; - nx = sr & 0x10000000 ? 1 : 0; + ctx->nx = sr & 0x10000000 ? 1 : 0; vsid = sr & 0x00FFFFFF; vsid_mask = 0x01FFFFC0; vsid_sh = 6; @@ -844,13 +899,13 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, #if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "pte segment: key=%d ds %d nx %d vsid " ADDRX "\n", - ctx->key, ds, nx, vsid); + ctx->key, ds, ctx->nx, vsid); } #endif ret = -1; if (!ds) { /* Check if instruction fetch is allowed, if needed */ - if (type != ACCESS_CODE || nx == 0) { + if (type != ACCESS_CODE || ctx->nx == 0) { /* Page address translation */ /* Primary table address */ sdr = env->sdr1; @@ -909,7 +964,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } #endif /* Primary table lookup */ - ret = find_pte(env, ctx, 0, rw); + ret = find_pte(env, ctx, 0, rw, type); if (ret < 0) { /* Secondary table lookup */ #if defined (DEBUG_MMU) @@ -921,7 +976,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, (uint32_t)hash, ctx->pg_addr[1]); } #endif - ret2 = find_pte(env, ctx, 1, rw); + ret2 = find_pte(env, ctx, 1, rw, type); if (ret2 != -1) ret = ret2; } @@ -1119,76 +1174,32 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, __func__, i, zsel, zpr, rw, tlb->attr); } #endif - if (access_type == ACCESS_CODE) { - /* Check execute enable bit */ - switch (zpr) { - case 0x2: - if (msr_pr) - goto check_exec_perm; - goto exec_granted; - case 0x0: - if (msr_pr) { - ctx->prot = 0; - ret = -3; - break; - } - /* No break here */ - case 0x1: - check_exec_perm: - /* Check from TLB entry */ - if (!(tlb->prot & PAGE_EXEC)) { - ret = -3; - } else { - if (tlb->prot & PAGE_WRITE) { - ctx->prot = PAGE_READ | PAGE_WRITE; - } else { - ctx->prot = PAGE_READ; - } - ret = 0; - } - break; - case 0x3: - exec_granted: - /* All accesses granted */ - ctx->prot = PAGE_READ | PAGE_WRITE; - ret = 0; - break; - } - } else { - switch (zpr) { - case 0x2: - if (msr_pr) - goto check_rw_perm; - goto rw_granted; - case 0x0: - if (msr_pr) { - ctx->prot = 0; - ret = -2; - break; - } - /* No break here */ - case 0x1: - check_rw_perm: - /* Check from TLB entry */ - /* Check write protection bit */ - if (tlb->prot & PAGE_WRITE) { - ctx->prot = PAGE_READ | PAGE_WRITE; - ret = 0; - } else { - ctx->prot = PAGE_READ; - if (rw) - ret = -2; - else - ret = 0; - } - break; - case 0x3: - rw_granted: - /* All accesses granted */ - ctx->prot = PAGE_READ | PAGE_WRITE; - ret = 0; + /* Check execute enable bit */ + switch (zpr) { + case 0x2: + if (msr_pr) + goto check_perms; + /* No break here */ + case 0x3: + /* All accesses granted */ + ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + ret = 0; + break; + case 0x0: + if (msr_pr) { + ctx->prot = 0; + ret = -2; break; } + /* No break here */ + case 0x1: + check_perms: + /* Check from TLB entry */ + /* XXX: there is a problem here or in the TLB fill code... */ + ctx->prot = tlb->prot; + ctx->prot |= PAGE_EXEC; + ret = check_prot(ctx->prot, rw, access_type); + break; } if (ret >= 0) { ctx->raddr = raddr; @@ -1274,7 +1285,7 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx, int in_plb, ret; ctx->raddr = eaddr; - ctx->prot = PAGE_READ; + ctx->prot = PAGE_READ | PAGE_EXEC; ret = 0; switch (env->mmu_model) { case POWERPC_MMU_32B: @@ -1421,9 +1432,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, } ret = get_physical_address(env, &ctx, address, rw, access_type, 1); if (ret == 0) { - ret = tlb_set_page(env, address & TARGET_PAGE_MASK, - ctx.raddr & TARGET_PAGE_MASK, ctx.prot, - mmu_idx, is_softmmu); + ret = tlb_set_page_exec(env, address & TARGET_PAGE_MASK, + ctx.raddr & TARGET_PAGE_MASK, ctx.prot, + mmu_idx, is_softmmu); } else if (ret < 0) { #if defined (DEBUG_MMU) if (loglevel != 0) -- cgit v1.2.3 From 992f48a036cccf7101e31bf3e5d901ce5320e886 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 14 Oct 2007 16:27:31 +0000 Subject: Support for 32 bit ABI on 64 bit targets (only enabled Sparc64) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3396 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 10 +- configure | 12 +- linux-user/alpha/syscall.h | 62 ++--- linux-user/alpha/target_signal.h | 8 +- linux-user/arm/syscall.h | 2 +- linux-user/arm/target_signal.h | 8 +- linux-user/cris/target_signal.h | 8 +- linux-user/elfload.c | 138 +++++----- linux-user/elfload32.c | 2 +- linux-user/flat.h | 32 +-- linux-user/flatload.c | 92 +++---- linux-user/i386/syscall.h | 48 ++-- linux-user/i386/target_signal.h | 8 +- linux-user/linuxload.c | 12 +- linux-user/m68k/syscall.h | 12 +- linux-user/m68k/target_signal.h | 6 +- linux-user/main.c | 29 ++- linux-user/mips/syscall.h | 16 +- linux-user/mips/target_signal.h | 8 +- linux-user/mips64/syscall.h | 14 +- linux-user/mips64/target_signal.h | 8 +- linux-user/mmap.c | 38 +-- linux-user/ppc/syscall.h | 2 +- linux-user/ppc/target_signal.h | 8 +- linux-user/ppc64/syscall.h | 2 +- linux-user/ppc64/target_signal.h | 8 +- linux-user/qemu.h | 96 ++++--- linux-user/sh4/target_signal.h | 6 +- linux-user/signal.c | 266 +++++++++---------- linux-user/sparc/syscall.h | 10 +- linux-user/sparc/target_signal.h | 8 +- linux-user/sparc64/syscall.h | 12 +- linux-user/sparc64/target_signal.h | 8 +- linux-user/syscall.c | 400 ++++++++++++++-------------- linux-user/syscall_defs.h | 522 ++++++++++++++++++------------------- linux-user/vm86.c | 2 +- linux-user/x86_64/syscall.h | 60 ++--- linux-user/x86_64/target_signal.h | 8 +- target-sparc/op_mem.h | 40 +-- thunk.c | 4 +- thunk.h | 4 +- 41 files changed, 1042 insertions(+), 997 deletions(-) diff --git a/Makefile.target b/Makefile.target index e26491938..f5b6447fa 100644 --- a/Makefile.target +++ b/Makefile.target @@ -31,7 +31,10 @@ CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH) endif ifdef CONFIG_LINUX_USER VPATH+=:$(SRC_PATH)/linux-user -CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH) +ifndef TARGET_ABI_DIR + TARGET_ABI_DIR=$(TARGET_ARCH) +endif +CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) endif BASE_CFLAGS= BASE_LDFLAGS= @@ -66,6 +69,11 @@ ifeq ($(TARGET_ARCH),mips64) TARGET_ARCH2=mips64el endif endif +ifeq ($(TARGET_ARCH),sparc64) + ifeq ($(TARGET_ABI_DIR),sparc) + TARGET_ARCH2=sparc32plus + endif +endif QEMU_USER=qemu-$(TARGET_ARCH2) # system emulator name ifdef CONFIG_SOFTMMU diff --git a/configure b/configure index 1ef6933dc..221c06865 100755 --- a/configure +++ b/configure @@ -504,7 +504,7 @@ if test -z "$target_list" ; then fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppc64-linux-user x86_64-linux-user cris-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppc64-linux-user x86_64-linux-user cris-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then @@ -933,6 +933,7 @@ target_bigendian="no" [ "$target_cpu" = "armeb" ] && target_bigendian=yes [ "$target_cpu" = "sparc" ] && target_bigendian=yes [ "$target_cpu" = "sparc64" ] && target_bigendian=yes +[ "$target_cpu" = "sparc32plus" ] && target_bigendian=yes [ "$target_cpu" = "ppc" ] && target_bigendian=yes [ "$target_cpu" = "ppcemb" ] && target_bigendian=yes [ "$target_cpu" = "ppc64" ] && target_bigendian=yes @@ -1026,6 +1027,13 @@ elif test "$target_cpu" = "sparc64" ; then echo "#define TARGET_SPARC 1" >> $config_h echo "#define TARGET_SPARC64 1" >> $config_h elfload32="yes" +elif test "$target_cpu" = "sparc32plus" ; then + echo "TARGET_ARCH=sparc64" >> $config_mak + echo "TARGET_ABI_DIR=sparc" >> $config_mak + echo "#define TARGET_ARCH \"sparc64\"" >> $config_h + echo "#define TARGET_SPARC 1" >> $config_h + echo "#define TARGET_SPARC64 1" >> $config_h + echo "#define TARGET_ABI32 1" >> $config_h elif test "$target_cpu" = "ppc" ; then echo "TARGET_ARCH=ppc" >> $config_mak echo "#define TARGET_ARCH \"ppc\"" >> $config_h @@ -1113,7 +1121,7 @@ if test "$target_darwin_user" = "yes" ; then echo "#define CONFIG_DARWIN_USER 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" -o "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" -o "$target_cpu" = "mipsn32" -o "$target_cpu" = "mipsn32el" -o "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el"; then +if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "sparc32plus" -o "$target_cpu" = "m68k" -o "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" -o "$target_cpu" = "mipsn32" -o "$target_cpu" = "mipsn32el" -o "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el"; then echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h fi diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h index 643581788..394afec56 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/syscall.h @@ -2,40 +2,40 @@ #define __USER_DS (1) struct target_pt_regs { - target_ulong r0; - target_ulong r1; - target_ulong r2; - target_ulong r3; - target_ulong r4; - target_ulong r5; - target_ulong r6; - target_ulong r7; - target_ulong r8; - target_ulong r19; - target_ulong r20; - target_ulong r21; - target_ulong r22; - target_ulong r23; - target_ulong r24; - target_ulong r25; - target_ulong r26; - target_ulong r27; - target_ulong r28; - target_ulong hae; + abi_ulong r0; + abi_ulong r1; + abi_ulong r2; + abi_ulong r3; + abi_ulong r4; + abi_ulong r5; + abi_ulong r6; + abi_ulong r7; + abi_ulong r8; + abi_ulong r19; + abi_ulong r20; + abi_ulong r21; + abi_ulong r22; + abi_ulong r23; + abi_ulong r24; + abi_ulong r25; + abi_ulong r26; + abi_ulong r27; + abi_ulong r28; + abi_ulong hae; /* JRP - These are the values provided to a0-a2 by PALcode */ - target_ulong trap_a0; - target_ulong trap_a1; - target_ulong trap_a2; + abi_ulong trap_a0; + abi_ulong trap_a1; + abi_ulong trap_a2; /* These are saved by PAL-code: */ - target_ulong ps; - target_ulong pc; - target_ulong gp; - target_ulong r16; - target_ulong r17; - target_ulong r18; + abi_ulong ps; + abi_ulong pc; + abi_ulong gp; + abi_ulong r16; + abi_ulong r17; + abi_ulong r18; /* Those is needed by qemu to temporary store the user stack pointer */ - target_ulong usp; - target_ulong unique; + abi_ulong usp; + abi_ulong unique; }; #define UNAME_MACHINE "alpha" diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h index 7618c3e83..2382ffdb6 100644 --- a/linux-user/alpha/target_signal.h +++ b/linux-user/alpha/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_SIGSTKSZ 16384 -static inline target_ulong get_sp_from_cpustate(CPUAlphaState *state) +static inline abi_ulong get_sp_from_cpustate(CPUAlphaState *state) { return state->ir[IR_SP]; } diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index 1d508f0a3..e7f2e8deb 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -3,7 +3,7 @@ stack during a system call. */ struct target_pt_regs { - target_long uregs[18]; + abi_long uregs[18]; }; #define ARM_cpsr uregs[16] diff --git a/linux-user/arm/target_signal.h b/linux-user/arm/target_signal.h index d51816514..2b3281312 100644 --- a/linux-user/arm/target_signal.h +++ b/linux-user/arm/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 -static inline target_ulong get_sp_from_cpustate(CPUARMState *state) +static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) { return state->regs[13]; } diff --git a/linux-user/cris/target_signal.h b/linux-user/cris/target_signal.h index e566de8ef..5611840f8 100644 --- a/linux-user/cris/target_signal.h +++ b/linux-user/cris/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_ulong ss_size; - target_long ss_flags; + abi_ulong ss_sp; + abi_ulong ss_size; + abi_long ss_flags; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 -static inline target_ulong get_sp_from_cpustate(CPUCRISState *state) +static inline abi_ulong get_sp_from_cpustate(CPUCRISState *state) { return state->regs[14]; } diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fbe7ddd84..0bb455bda 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -172,7 +172,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - target_long stack = infop->start_stack; + abi_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; if (infop->entry & 1) @@ -214,7 +214,11 @@ enum #define ELF_START_MMAP 0x80000000 +#ifndef TARGET_ABI32 #define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) +#else +#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC ) +#endif #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB @@ -224,14 +228,20 @@ enum static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { +#ifndef TARGET_ABI32 regs->tstate = 0; +#endif regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; +#ifdef TARGET_ABI32 + regs->u_regs[14] = infop->start_stack - 16 * 4; +#else if (personality(infop->personality) == PER_LINUX32) regs->u_regs[14] = infop->start_stack - 16 * 4; else regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; +#endif } #else @@ -313,10 +323,10 @@ do { \ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) { - target_ulong pos = infop->start_stack; - target_ulong tmp; + abi_ulong pos = infop->start_stack; + abi_ulong tmp; #ifdef TARGET_PPC64 - target_ulong entry, toc; + abi_ulong entry, toc; #endif _regs->msr = 1 << MSR_PR; /* Set user mode */ @@ -333,9 +343,9 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * * execution of PPC BSD programs. */ _regs->gpr[3] = tgetl(pos); - pos += sizeof(target_ulong); + pos += sizeof(abi_ulong); _regs->gpr[4] = pos; - for (tmp = 1; tmp != 0; pos += sizeof(target_ulong)) + for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) tmp = ldl(pos); _regs->gpr[5] = pos; } @@ -475,9 +485,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_HWCAP 0 #endif -#ifdef OVERRIDE_ELF_CLASS +#ifdef TARGET_ABI32 #undef ELF_CLASS -#define ELF_CLASS OVERRIDE_ELF_CLASS +#define ELF_CLASS ELFCLASS32 #undef bswaptls #define bswaptls(ptr) bswap32s(ptr) #endif @@ -588,8 +598,8 @@ static void bswap_sym(struct elf_sym *sym) * to be put directly into the top of new user memory. * */ -static target_ulong copy_elf_strings(int argc,char ** argv, void **page, - target_ulong p) +static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, + abi_ulong p) { char *tmp, *tmp1, *pag = NULL; int len, offset = 0; @@ -638,10 +648,10 @@ static target_ulong copy_elf_strings(int argc,char ** argv, void **page, return p; } -static target_ulong setup_arg_pages(target_ulong p, struct linux_binprm *bprm, - struct image_info *info) +static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, + struct image_info *info) { - target_ulong stack_base, size, error; + abi_ulong stack_base, size, error; int i; /* Create enough stack to hold everything. If we don't use @@ -677,7 +687,7 @@ static target_ulong setup_arg_pages(target_ulong p, struct linux_binprm *bprm, return p; } -static void set_brk(target_ulong start, target_ulong end) +static void set_brk(abi_ulong start, abi_ulong end) { /* page-align the start and end addresses... */ start = HOST_PAGE_ALIGN(start); @@ -696,9 +706,9 @@ static void set_brk(target_ulong start, target_ulong end) /* We need to explicitly zero any fractional pages after the data section (i.e. bss). This would contain the junk from the file that should not be in memory. */ -static void padzero(target_ulong elf_bss, target_ulong last_bss) +static void padzero(abi_ulong elf_bss, abi_ulong last_bss) { - target_ulong nbyte; + abi_ulong nbyte; if (elf_bss >= last_bss) return; @@ -709,7 +719,7 @@ static void padzero(target_ulong elf_bss, target_ulong last_bss) patch target_mmap(), but it is more complicated as the file size must be known */ if (qemu_real_host_page_size < qemu_host_page_size) { - target_ulong end_addr, end_addr1; + abi_ulong end_addr, end_addr1; end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & ~(qemu_real_host_page_size - 1); end_addr = HOST_PAGE_ALIGN(elf_bss); @@ -731,16 +741,16 @@ static void padzero(target_ulong elf_bss, target_ulong last_bss) } -static target_ulong create_elf_tables(target_ulong p, int argc, int envc, - struct elfhdr * exec, - target_ulong load_addr, - target_ulong load_bias, - target_ulong interp_load_addr, int ibcs, - struct image_info *info) +static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, + struct elfhdr * exec, + abi_ulong load_addr, + abi_ulong load_bias, + abi_ulong interp_load_addr, int ibcs, + struct image_info *info) { - target_ulong sp; + abi_ulong sp; int size; - target_ulong u_platform; + abi_ulong u_platform; const char *k_platform; const int n = sizeof(elf_addr_t); @@ -756,7 +766,7 @@ static target_ulong create_elf_tables(target_ulong p, int argc, int envc, /* * Force 16 byte _final_ alignment here for generality. */ - sp = sp &~ (target_ulong)15; + sp = sp &~ (abi_ulong)15; size = (DLINFO_ITEMS + 1) * 2; if (k_platform) size += 2; @@ -786,18 +796,18 @@ static target_ulong create_elf_tables(target_ulong p, int argc, int envc, NEW_AUX_ENT (AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ - NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); - NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum)); - NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); - NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr)); - NEW_AUX_ENT(AT_FLAGS, (target_ulong)0); + NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); + NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); + NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); + NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); + NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0); NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); - NEW_AUX_ENT(AT_UID, (target_ulong) getuid()); - NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid()); - NEW_AUX_ENT(AT_GID, (target_ulong) getgid()); - NEW_AUX_ENT(AT_EGID, (target_ulong) getegid()); - NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP); + NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); + NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); + NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); + NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); + NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO @@ -814,17 +824,17 @@ static target_ulong create_elf_tables(target_ulong p, int argc, int envc, } -static target_ulong load_elf_interp(struct elfhdr * interp_elf_ex, - int interpreter_fd, - target_ulong *interp_load_addr) +static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, + int interpreter_fd, + abi_ulong *interp_load_addr) { struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; - target_ulong load_addr = 0; + abi_ulong load_addr = 0; int load_addr_set = 0; int retval; - target_ulong last_bss, elf_bss; - target_ulong error; + abi_ulong last_bss, elf_bss; + abi_ulong error; int i; elf_bss = 0; @@ -838,20 +848,20 @@ static target_ulong load_elf_interp(struct elfhdr * interp_elf_ex, if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine)) { - return ~((target_ulong)0UL); + return ~((abi_ulong)0UL); } /* Now read in all of the header information */ if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) - return ~(target_ulong)0UL; + return ~(abi_ulong)0UL; elf_phdata = (struct elf_phdr *) malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); if (!elf_phdata) - return ~((target_ulong)0UL); + return ~((abi_ulong)0UL); /* * If the size of this structure has changed, then punt, since @@ -859,7 +869,7 @@ static target_ulong load_elf_interp(struct elfhdr * interp_elf_ex, */ if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { free(elf_phdata); - return ~((target_ulong)0UL); + return ~((abi_ulong)0UL); } retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); @@ -900,8 +910,8 @@ static target_ulong load_elf_interp(struct elfhdr * interp_elf_ex, if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; - target_ulong vaddr = 0; - target_ulong k; + abi_ulong vaddr = 0; + abi_ulong k; if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; @@ -921,7 +931,7 @@ static target_ulong load_elf_interp(struct elfhdr * interp_elf_ex, /* Real error */ close(interpreter_fd); free(elf_phdata); - return ~((target_ulong)0UL); + return ~((abi_ulong)0UL); } if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { @@ -966,7 +976,7 @@ static target_ulong load_elf_interp(struct elfhdr * interp_elf_ex, free(elf_phdata); *interp_load_addr = load_addr; - return ((target_ulong) interp_elf_ex->e_entry) + load_addr; + return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; } /* Best attempt to load symbols from this ELF object. */ @@ -1054,22 +1064,22 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct elfhdr interp_elf_ex; struct exec interp_ex; int interpreter_fd = -1; /* avoid warning */ - target_ulong load_addr, load_bias; + abi_ulong load_addr, load_bias; int load_addr_set = 0; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; - target_ulong mapped_addr; + abi_ulong mapped_addr; struct elf_phdr * elf_ppnt; struct elf_phdr *elf_phdata; - target_ulong elf_bss, k, elf_brk; + abi_ulong elf_bss, k, elf_brk; int retval; char * elf_interpreter; - target_ulong elf_entry, interp_load_addr = 0; + abi_ulong elf_entry, interp_load_addr = 0; int status; - target_ulong start_code, end_code, start_data, end_data; - target_ulong reloc_func_desc = 0; - target_ulong elf_stack; + abi_ulong start_code, end_code, start_data, end_data; + abi_ulong reloc_func_desc = 0; + abi_ulong elf_stack; char passed_fileno[6]; ibcs2_interpreter = 0; @@ -1125,9 +1135,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, elf_brk = 0; - elf_stack = ~((target_ulong)0UL); + elf_stack = ~((abi_ulong)0UL); elf_interpreter = NULL; - start_code = ~((target_ulong)0UL); + start_code = ~((abi_ulong)0UL); end_code = 0; start_data = 0; end_data = 0; @@ -1263,9 +1273,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* OK, This is the point of no return */ info->end_data = 0; info->end_code = 0; - info->start_mmap = (target_ulong)ELF_START_MMAP; + info->start_mmap = (abi_ulong)ELF_START_MMAP; info->mmap = 0; - elf_entry = (target_ulong) elf_ex.e_entry; + elf_entry = (abi_ulong) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will change some of these later */ @@ -1282,7 +1292,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0; int elf_flags = 0; - target_ulong error; + abi_ulong error; if (elf_ppnt->p_type != PT_LOAD) continue; @@ -1374,7 +1384,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, close(interpreter_fd); free(elf_interpreter); - if (elf_entry == ~((target_ulong)0UL)) { + if (elf_entry == ~((abi_ulong)0UL)) { printf("Unable to load interpreter\n"); free(elf_phdata); exit(-1); diff --git a/linux-user/elfload32.c b/linux-user/elfload32.c index d1a15ff93..4b4648c75 100755 --- a/linux-user/elfload32.c +++ b/linux-user/elfload32.c @@ -1,4 +1,4 @@ -#define OVERRIDE_ELF_CLASS ELFCLASS32 +#define TARGET_ABI32 #define load_elf_binary load_elf_binary32 #define do_init_thread do_init_thread32 diff --git a/linux-user/flat.h b/linux-user/flat.h index 9b84c7292..6f2d0c4b2 100644 --- a/linux-user/flat.h +++ b/linux-user/flat.h @@ -22,25 +22,25 @@ struct flat_hdr { char magic[4]; - target_ulong rev; /* version (as above) */ - target_ulong entry; /* Offset of first executable instruction - with text segment from beginning of file */ - target_ulong data_start; /* Offset of data segment from beginning of - file */ - target_ulong data_end; /* Offset of end of data segment - from beginning of file */ - target_ulong bss_end; /* Offset of end of bss segment from beginning - of file */ + abi_ulong rev; /* version (as above) */ + abi_ulong entry; /* Offset of first executable instruction + with text segment from beginning of file */ + abi_ulong data_start; /* Offset of data segment from beginning of + file */ + abi_ulong data_end; /* Offset of end of data segment + from beginning of file */ + abi_ulong bss_end; /* Offset of end of bss segment from beginning + of file */ /* (It is assumed that data_end through bss_end forms the bss segment.) */ - target_ulong stack_size; /* Size of stack, in bytes */ - target_ulong reloc_start; /* Offset of relocation records from - beginning of file */ - target_ulong reloc_count; /* Number of relocation records */ - target_ulong flags; - target_ulong build_date; /* When the program/library was built */ - target_ulong filler[5]; /* Reservered, set to zero */ + abi_ulong stack_size; /* Size of stack, in bytes */ + abi_ulong reloc_start; /* Offset of relocation records from + beginning of file */ + abi_ulong reloc_count; /* Number of relocation records */ + abi_ulong flags; + abi_ulong build_date; /* When the program/library was built */ + abi_ulong filler[5]; /* Reservered, set to zero */ }; #define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */ diff --git a/linux-user/flatload.c b/linux-user/flatload.c index db88e4b1c..86b77f988 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -63,13 +63,13 @@ #define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ struct lib_info { - target_ulong start_code; /* Start of text segment */ - target_ulong start_data; /* Start of data segment */ - target_ulong end_data; /* Start of bss section */ - target_ulong start_brk; /* End of data segment */ - target_ulong text_len; /* Length of text segment */ - target_ulong entry; /* Start address for this module */ - target_ulong build_date; /* When this one was compiled */ + abi_ulong start_code; /* Start of text segment */ + abi_ulong start_data; /* Start of data segment */ + abi_ulong end_data; /* Start of bss section */ + abi_ulong start_brk; /* End of data segment */ + abi_ulong text_len; /* Length of text segment */ + abi_ulong entry; /* Start address for this module */ + abi_ulong build_date; /* When this one was compiled */ short loaded; /* Has this library been loaded? */ }; @@ -89,7 +89,7 @@ struct linux_binprm; */ /* Push a block of strings onto the guest stack. */ -static target_ulong copy_strings(target_ulong p, int n, char **s) +static abi_ulong copy_strings(abi_ulong p, int n, char **s) { int len; @@ -102,8 +102,8 @@ static target_ulong copy_strings(target_ulong p, int n, char **s) return p; } -int target_pread(int fd, target_ulong ptr, target_ulong len, - target_ulong offset) +int target_pread(int fd, abi_ulong ptr, abi_ulong len, + abi_ulong offset) { void *buf; int ret; @@ -262,15 +262,15 @@ out: /****************************************************************************/ -static target_ulong -calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp) +static abi_ulong +calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp) { - target_ulong addr; + abi_ulong addr; int id; - target_ulong start_brk; - target_ulong start_data; - target_ulong text_len; - target_ulong start_code; + abi_ulong start_brk; + abi_ulong start_data; + abi_ulong text_len; + abi_ulong start_code; #ifdef CONFIG_BINFMT_SHARED_FLAT #error needs checking @@ -381,19 +381,19 @@ void old_reloc(struct lib_info *libinfo, uint32_t rl) /****************************************************************************/ static int load_flat_file(struct linux_binprm * bprm, - struct lib_info *libinfo, int id, target_ulong *extra_stack) + struct lib_info *libinfo, int id, abi_ulong *extra_stack) { struct flat_hdr * hdr; - target_ulong textpos = 0, datapos = 0, result; - target_ulong realdatastart = 0; - target_ulong text_len, data_len, bss_len, stack_len, flags; - target_ulong memp = 0; /* for finding the brk area */ - target_ulong extra; - target_ulong reloc = 0, rp; + abi_ulong textpos = 0, datapos = 0, result; + abi_ulong realdatastart = 0; + abi_ulong text_len, data_len, bss_len, stack_len, flags; + abi_ulong memp = 0; /* for finding the brk area */ + abi_ulong extra; + abi_ulong reloc = 0, rp; int i, rev, relocs = 0; - target_ulong fpos; - target_ulong start_code, end_code; - target_ulong indx_len; + abi_ulong fpos; + abi_ulong start_code, end_code; + abi_ulong indx_len; hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ @@ -440,14 +440,14 @@ static int load_flat_file(struct linux_binprm * bprm, /* * calculate the extra space we need to map in */ - extra = relocs * sizeof(target_ulong); + extra = relocs * sizeof(abi_ulong); if (extra < bss_len + stack_len) extra = bss_len + stack_len; /* Add space for library base pointers. Make sure this does not misalign the doesn't misalign the data segment. */ - indx_len = MAX_SHARED_LIBS * sizeof(target_ulong); - indx_len = (indx_len + 15) & ~(target_ulong)15; + indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong); + indx_len = (indx_len + 15) & ~(abi_ulong)15; /* * there are a couple of cases here, the separate code/data @@ -485,12 +485,12 @@ static int load_flat_file(struct linux_binprm * bprm, #ifdef CONFIG_BINFMT_ZFLAT if (flags & FLAT_FLAG_GZDATA) { result = decompress_exec(bprm, fpos, (char *) datapos, - data_len + (relocs * sizeof(target_ulong))) + data_len + (relocs * sizeof(abi_ulong))) } else #endif { result = target_pread(bprm->fd, datapos, - data_len + (relocs * sizeof(target_ulong)), + data_len + (relocs * sizeof(abi_ulong)), fpos); } if (result < 0) { @@ -544,7 +544,7 @@ static int load_flat_file(struct linux_binprm * bprm, text_len, 0); if (result >= 0) { result = target_pread(bprm->fd, datapos, - data_len + (relocs * sizeof(target_ulong)), + data_len + (relocs * sizeof(abi_ulong)), ntohl(hdr->data_start)); } } @@ -597,7 +597,7 @@ static int load_flat_file(struct linux_binprm * bprm, if (flags & FLAT_FLAG_GOTPIC) { rp = datapos; while (1) { - target_ulong addr; + abi_ulong addr; addr = tgetl(rp); if (addr == -1) break; @@ -607,7 +607,7 @@ static int load_flat_file(struct linux_binprm * bprm, return -ENOEXEC; tputl(rp, addr); } - rp += sizeof(target_ulong); + rp += sizeof(abi_ulong); } } @@ -624,12 +624,12 @@ static int load_flat_file(struct linux_binprm * bprm, */ if (rev > OLD_FLAT_VERSION) { for (i = 0; i < relocs; i++) { - target_ulong addr, relval; + abi_ulong addr, relval; /* Get the address of the pointer to be relocated (of course, the address has to be relocated first). */ - relval = tgetl(reloc + i * sizeof (target_ulong)); + relval = tgetl(reloc + i * sizeof (abi_ulong)); addr = flat_get_relocate_addr(relval); rp = calc_reloc(addr, libinfo, id, 1); if (rp == RELOC_FAILED) @@ -657,8 +657,8 @@ static int load_flat_file(struct linux_binprm * bprm, } } else { for (i = 0; i < relocs; i++) { - target_ulong relval; - relval = tgetl(reloc + i * sizeof (target_ulong)); + abi_ulong relval; + relval = tgetl(reloc + i * sizeof (abi_ulong)); old_reloc(&libinfo[0], relval); } } @@ -712,10 +712,10 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info) { struct lib_info libinfo[MAX_SHARED_LIBS]; - target_ulong p = bprm->p; - target_ulong stack_len; - target_ulong start_addr; - target_ulong sp; + abi_ulong p = bprm->p; + abi_ulong stack_len; + abi_ulong start_addr; + abi_ulong sp; int res; int i, j; @@ -740,7 +740,7 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* Update data segment pointers for all libraries */ for (i=0; ienvc, bprm->envp); p = copy_strings(p, bprm->argc, bprm->argv); /* Align stack. */ - sp = p & ~(target_ulong)(sizeof(target_ulong) - 1); + sp = p & ~(abi_ulong)(sizeof(abi_ulong) - 1); /* Enforce final stack alignment of 16 bytes. This is sufficient for all current targets, and excess alignment is harmless. */ stack_len = bprm->envc + bprm->argc + 2; stack_len += 3; /* argc, arvg, argp */ - stack_len *= sizeof(target_ulong); + stack_len *= sizeof(abi_ulong); if ((sp + stack_len) & 15) sp -= 16 - ((sp + stack_len) & 15); sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1); diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index 6e288b804..8045e1c7b 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -31,7 +31,7 @@ struct target_pt_regs { struct target_modify_ldt_ldt_s { unsigned int entry_number; - target_ulong base_addr; + abi_ulong base_addr; unsigned int limit; unsigned int flags; }; @@ -79,22 +79,22 @@ struct target_vm86_regs { /* * normal regs, with special meaning for the segment descriptors.. */ - target_long ebx; - target_long ecx; - target_long edx; - target_long esi; - target_long edi; - target_long ebp; - target_long eax; - target_long __null_ds; - target_long __null_es; - target_long __null_fs; - target_long __null_gs; - target_long orig_eax; - target_long eip; + abi_long ebx; + abi_long ecx; + abi_long edx; + abi_long esi; + abi_long edi; + abi_long ebp; + abi_long eax; + abi_long __null_ds; + abi_long __null_es; + abi_long __null_fs; + abi_long __null_gs; + abi_long orig_eax; + abi_long eip; unsigned short cs, __csh; - target_long eflags; - target_long esp; + abi_long eflags; + abi_long esp; unsigned short ss, __ssh; /* * these are specific to v86 mode: @@ -106,14 +106,14 @@ struct target_vm86_regs { }; struct target_revectored_struct { - target_ulong __map[8]; /* 256 bits */ + abi_ulong __map[8]; /* 256 bits */ }; struct target_vm86_struct { struct target_vm86_regs regs; - target_ulong flags; - target_ulong screen_bitmap; - target_ulong cpu_type; + abi_ulong flags; + abi_ulong screen_bitmap; + abi_ulong cpu_type; struct target_revectored_struct int_revectored; struct target_revectored_struct int21_revectored; }; @@ -124,7 +124,7 @@ struct target_vm86_struct { #define TARGET_VM86_SCREEN_BITMAP 0x0001 struct target_vm86plus_info_struct { - target_ulong flags; + abi_ulong flags; #define TARGET_force_return_for_pic (1 << 0) #define TARGET_vm86dbg_active (1 << 1) /* for debugger */ #define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */ @@ -134,9 +134,9 @@ struct target_vm86plus_info_struct { struct target_vm86plus_struct { struct target_vm86_regs regs; - target_ulong flags; - target_ulong screen_bitmap; - target_ulong cpu_type; + abi_ulong flags; + abi_ulong screen_bitmap; + abi_ulong cpu_type; struct target_revectored_struct int_revectored; struct target_revectored_struct int21_revectored; struct target_vm86plus_info_struct vm86plus; diff --git a/linux-user/i386/target_signal.h b/linux-user/i386/target_signal.h index f93a8d62b..9baf7fbeb 100644 --- a/linux-user/i386/target_signal.h +++ b/linux-user/i386/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 -static inline target_ulong get_sp_from_cpustate(CPUX86State *state) +static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) { return state->regs[R_ESP]; } diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 51f29531c..42a02d206 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -13,7 +13,7 @@ #define NGROUPS 32 /* ??? This should really be somewhere else. */ -void memcpy_to_target(target_ulong dest, const void *src, +void memcpy_to_target(abi_ulong dest, const void *src, unsigned long len) { void *host_ptr; @@ -109,12 +109,12 @@ static int prepare_binprm(struct linux_binprm *bprm) } /* Construct the envp and argv tables on the target stack. */ -target_ulong loader_build_argptr(int envc, int argc, target_ulong sp, - target_ulong stringp, int push_ptr) +abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, + abi_ulong stringp, int push_ptr) { - int n = sizeof(target_ulong); - target_ulong envp; - target_ulong argv; + int n = sizeof(abi_ulong); + abi_ulong envp; + abi_ulong argv; sp -= (envc + 1) * n; envp = sp; diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/syscall.h index c225567d2..47cc66b14 100644 --- a/linux-user/m68k/syscall.h +++ b/linux-user/m68k/syscall.h @@ -3,14 +3,14 @@ stack during a system call. */ struct target_pt_regs { - target_long d1, d2, d3, d4, d5, d6, d7; - target_long a0, a1, a2, a3, a4, a5, a6; - target_ulong d0; - target_ulong usp; - target_ulong orig_d0; + abi_long d1, d2, d3, d4, d5, d6, d7; + abi_long a0, a1, a2, a3, a4, a5, a6; + abi_ulong d0; + abi_ulong usp; + abi_ulong orig_d0; int16_t stkadj; uint16_t sr; - target_ulong pc; + abi_ulong pc; uint16_t fntvex; uint16_t __fill; }; diff --git a/linux-user/m68k/target_signal.h b/linux-user/m68k/target_signal.h index b48119507..47852d546 100644 --- a/linux-user/m68k/target_signal.h +++ b/linux-user/m68k/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; diff --git a/linux-user/main.c b/linux-user/main.c index 1e406d3d4..ac5a63bb5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -168,7 +168,7 @@ static void set_idt(int n, unsigned int dpl) void cpu_loop(CPUX86State *env) { int trapnr; - target_ulong pc; + abi_ulong pc; target_siginfo_t info; for(;;) { @@ -305,11 +305,11 @@ void cpu_loop(CPUX86State *env) #ifdef TARGET_ARM /* XXX: find a better solution */ -extern void tb_invalidate_page_range(target_ulong start, target_ulong end); +extern void tb_invalidate_page_range(abi_ulong start, abi_ulong end); -static void arm_cache_flush(target_ulong start, target_ulong last) +static void arm_cache_flush(abi_ulong start, abi_ulong last) { - target_ulong addr, last1; + abi_ulong addr, last1; if (last < start) return; @@ -474,7 +474,7 @@ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) static inline void save_window_offset(CPUSPARCState *env, int cwp1) { unsigned int i; - target_ulong sp_ptr; + abi_ulong sp_ptr; sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #if defined(DEBUG_WIN) @@ -483,7 +483,7 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1) #endif for(i = 0; i < 16; i++) { tputl(sp_ptr, env->regbase[get_reg_index(env, cwp1, 8 + i)]); - sp_ptr += sizeof(target_ulong); + sp_ptr += sizeof(abi_ulong); } } @@ -505,7 +505,7 @@ static void save_window(CPUSPARCState *env) static void restore_window(CPUSPARCState *env) { unsigned int new_wim, i, cwp1; - target_ulong sp_ptr; + abi_ulong sp_ptr; new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & ((1LL << NWINDOWS) - 1); @@ -519,7 +519,7 @@ static void restore_window(CPUSPARCState *env) #endif for(i = 0; i < 16; i++) { env->regbase[get_reg_index(env, cwp1, 8 + i)] = tgetl(sp_ptr); - sp_ptr += sizeof(target_ulong); + sp_ptr += sizeof(abi_ulong); } env->wim = new_wim; #ifdef TARGET_SPARC64 @@ -572,14 +572,14 @@ void cpu_loop (CPUSPARCState *env) env->regwptr[2], env->regwptr[3], env->regwptr[4], env->regwptr[5]); if ((unsigned int)ret >= (unsigned int)(-515)) { -#ifdef TARGET_SPARC64 +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) env->xcc |= PSR_CARRY; #else env->psr |= PSR_CARRY; #endif ret = -ret; } else { -#ifdef TARGET_SPARC64 +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) env->xcc &= ~PSR_CARRY; #else env->psr &= ~PSR_CARRY; @@ -591,6 +591,9 @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; case 0x83: /* flush windows */ +#ifdef TARGET_ABI32 + case 0x103: +#endif flush_windows(env); /* next instruction */ env->pc = env->npc; @@ -1489,8 +1492,8 @@ void cpu_loop(CPUMIPSState *env) ret = -ENOSYS; } else { int nb_args; - target_ulong sp_reg; - target_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; + abi_ulong sp_reg; + abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; nb_args = mips_syscall_args[syscall_num]; sp_reg = env->gpr[29][env->current_tc]; @@ -2239,7 +2242,7 @@ int main(int argc, char **argv) int i; for(i = 0; i < 28; i++) { - env->ir[i] = ((target_ulong *)regs)[i]; + env->ir[i] = ((abi_ulong *)regs)[i]; } env->ipr[IPR_USP] = regs->usp; env->ir[30] = regs->usp; diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index a789348db..9dfcc1f20 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -4,18 +4,18 @@ struct target_pt_regs { /* Pad bytes for argument save space on the stack. */ - target_ulong pad0[6]; + abi_ulong pad0[6]; /* Saved main processor registers. */ - target_ulong regs[32]; + abi_ulong regs[32]; /* Saved special registers. */ - target_ulong cp0_status; - target_ulong lo; - target_ulong hi; - target_ulong cp0_badvaddr; - target_ulong cp0_cause; - target_ulong cp0_epc; + abi_ulong cp0_status; + abi_ulong lo; + abi_ulong hi; + abi_ulong cp0_badvaddr; + abi_ulong cp0_cause; + abi_ulong cp0_epc; }; /* Target errno definitions taken from asm-mips/errno.h */ diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h index 514195c03..3b06e9824 100644 --- a/linux-user/mips/target_signal.h +++ b/linux-user/mips/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_long ss_sp; - target_ulong ss_size; - target_long ss_flags; + abi_long ss_sp; + abi_ulong ss_size; + abi_long ss_flags; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 -static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) +static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) { return state->gpr[29][state->current_tc]; } diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index 4ec506cb0..668a2b95d 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -4,15 +4,15 @@ struct target_pt_regs { /* Saved main processor registers. */ - target_ulong regs[32]; + abi_ulong regs[32]; /* Saved special registers. */ - target_ulong cp0_status; - target_ulong lo; - target_ulong hi; - target_ulong cp0_badvaddr; - target_ulong cp0_cause; - target_ulong cp0_epc; + abi_ulong cp0_status; + abi_ulong lo; + abi_ulong hi; + abi_ulong cp0_badvaddr; + abi_ulong cp0_cause; + abi_ulong cp0_epc; }; /* Target errno definitions taken from asm-mips/errno.h */ diff --git a/linux-user/mips64/target_signal.h b/linux-user/mips64/target_signal.h index 514195c03..3b06e9824 100644 --- a/linux-user/mips64/target_signal.h +++ b/linux-user/mips64/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_long ss_sp; - target_ulong ss_size; - target_long ss_flags; + abi_long ss_sp; + abi_ulong ss_size; + abi_long ss_flags; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 -static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) +static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) { return state->gpr[29][state->current_tc]; } diff --git a/linux-user/mmap.c b/linux-user/mmap.c index ea916b80a..4d18d2281 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -30,9 +30,9 @@ //#define DEBUG_MMAP /* NOTE: all the constants are the HOST ones, but addresses are target. */ -int target_mprotect(target_ulong start, target_ulong len, int prot) +int target_mprotect(abi_ulong start, abi_ulong len, int prot) { - target_ulong end, host_start, host_end, addr; + abi_ulong end, host_start, host_end, addr; int prot1, ret; #ifdef DEBUG_MMAP @@ -96,11 +96,11 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) } /* map an incomplete host page */ -static int mmap_frag(target_ulong real_start, - target_ulong start, target_ulong end, - int prot, int flags, int fd, target_ulong offset) +static int mmap_frag(abi_ulong real_start, + abi_ulong start, abi_ulong end, + int prot, int flags, int fd, abi_ulong offset) { - target_ulong real_end, ret, addr; + abi_ulong real_end, ret, addr; void *host_start; int prot1, prot_new; @@ -152,17 +152,17 @@ static int mmap_frag(target_ulong real_start, } /* NOTE: all the constants are the HOST ones */ -target_long target_mmap(target_ulong start, target_ulong len, int prot, - int flags, int fd, target_ulong offset) +abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, + int flags, int fd, abi_ulong offset) { - target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; + abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; unsigned long host_start; #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ defined(__ia64) || defined(__mips__) - static target_ulong last_start = 0x40000000; + static abi_ulong last_start = 0x40000000; #elif defined(__CYGWIN__) /* Cygwin doesn't have a whole lot of address space. */ - static target_ulong last_start = 0x18000000; + static abi_ulong last_start = 0x18000000; #endif #ifdef DEBUG_MMAP @@ -228,7 +228,7 @@ target_long target_mmap(target_ulong start, target_ulong len, int prot, * TARGET_PAGE_SIZE, see exec.c. qemu_real_host_page_size is the * hosts real page size. */ - target_ulong host_end; + abi_ulong host_end; unsigned long host_aligned_start; host_len = HOST_PAGE_ALIGN(host_len + qemu_host_page_size @@ -354,9 +354,9 @@ target_long target_mmap(target_ulong start, target_ulong len, int prot, return start; } -int target_munmap(target_ulong start, target_ulong len) +int target_munmap(abi_ulong start, abi_ulong len) { - target_ulong end, real_start, real_end, addr; + abi_ulong end, real_start, real_end, addr; int prot, ret; #ifdef DEBUG_MMAP @@ -408,9 +408,9 @@ int target_munmap(target_ulong start, target_ulong len) /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED blocks which have been allocated starting on a host page */ -target_long target_mremap(target_ulong old_addr, target_ulong old_size, - target_ulong new_size, unsigned long flags, - target_ulong new_addr) +abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, + abi_ulong new_size, unsigned long flags, + abi_ulong new_addr) { int prot; unsigned long host_addr; @@ -426,9 +426,9 @@ target_long target_mremap(target_ulong old_addr, target_ulong old_size, return new_addr; } -int target_msync(target_ulong start, target_ulong len, int flags) +int target_msync(abi_ulong start, abi_ulong len, int flags) { - target_ulong end; + abi_ulong end; if (start & ~TARGET_PAGE_MASK) return -EINVAL; diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index bf6b21b2f..30427f69e 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -44,7 +44,7 @@ struct target_pt_regs { /* ioctls */ struct target_revectored_struct { - target_ulong __map[8]; /* 256 bits */ + abi_ulong __map[8]; /* 256 bits */ }; /* diff --git a/linux-user/ppc/target_signal.h b/linux-user/ppc/target_signal.h index 80ad21187..defae809a 100644 --- a/linux-user/ppc/target_signal.h +++ b/linux-user/ppc/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 -static inline target_ulong get_sp_from_cpustate(CPUPPCState *state) +static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state) { return state->gpr[1]; } diff --git a/linux-user/ppc64/syscall.h b/linux-user/ppc64/syscall.h index c47e58a95..bdb1a07da 100644 --- a/linux-user/ppc64/syscall.h +++ b/linux-user/ppc64/syscall.h @@ -44,7 +44,7 @@ struct target_pt_regs { /* ioctls */ struct target_revectored_struct { - target_ulong __map[8]; /* 256 bits */ + abi_ulong __map[8]; /* 256 bits */ }; /* diff --git a/linux-user/ppc64/target_signal.h b/linux-user/ppc64/target_signal.h index 80ad21187..defae809a 100644 --- a/linux-user/ppc64/target_signal.h +++ b/linux-user/ppc64/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 -static inline target_ulong get_sp_from_cpustate(CPUPPCState *state) +static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state) { return state->gpr[1]; } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 8a7cb2479..e92db6ee6 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -1,13 +1,23 @@ #ifndef QEMU_H #define QEMU_H -#include "thunk.h" - #include #include -#include "syscall_defs.h" #include "cpu.h" + +#ifdef TARGET_ABI32 +typedef uint32_t abi_ulong; +typedef int32_t abi_long; +#define TARGET_ABI_BITS 32 +#else +typedef target_ulong abi_ulong; +typedef target_long abi_long; +#define TARGET_ABI_BITS TARGET_LONG_BITS +#endif + +#include "thunk.h" +#include "syscall_defs.h" #include "syscall.h" #include "target_signal.h" #include "gdbstub.h" @@ -17,20 +27,20 @@ * task_struct fields in the kernel */ struct image_info { - target_ulong load_addr; - target_ulong start_code; - target_ulong end_code; - target_ulong start_data; - target_ulong end_data; - target_ulong start_brk; - target_ulong brk; - target_ulong start_mmap; - target_ulong mmap; - target_ulong rss; - target_ulong start_stack; - target_ulong entry; - target_ulong code_offset; - target_ulong data_offset; + abi_ulong load_addr; + abi_ulong start_code; + abi_ulong end_code; + abi_ulong start_data; + abi_ulong end_data; + abi_ulong start_brk; + abi_ulong brk; + abi_ulong start_mmap; + abi_ulong mmap; + abi_ulong rss; + abi_ulong start_stack; + abi_ulong entry; + abi_ulong code_offset; + abi_ulong data_offset; char **host_argv; int personality; }; @@ -67,7 +77,7 @@ typedef struct TaskState { int swi_errno; #endif #if defined(TARGET_I386) && !defined(TARGET_X86_64) - target_ulong target_v86; + abi_ulong target_v86; struct vm86_saved_state vm86_saved_regs; struct target_vm86plus_struct vm86plus; uint32_t v86flags; @@ -105,7 +115,7 @@ extern const char *qemu_uname_release; struct linux_binprm { char buf[128]; void *page[MAX_ARG_PAGES]; - target_ulong p; + abi_ulong p; int fd; int e_uid, e_gid; int argc, envc; @@ -115,8 +125,8 @@ struct linux_binprm { }; void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); -target_ulong loader_build_argptr(int envc, int argc, target_ulong sp, - target_ulong stringp, int push_ptr); +abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, + abi_ulong stringp, int push_ptr); int loader_exec(const char * filename, char ** argv, char ** envp, struct target_pt_regs * regs, struct image_info *infop); @@ -130,14 +140,14 @@ int load_elf_binary_multi(struct linux_binprm *bprm, struct image_info *info); #endif -void memcpy_to_target(target_ulong dest, const void *src, +void memcpy_to_target(abi_ulong dest, const void *src, unsigned long len); -void target_set_brk(target_ulong new_brk); -target_long do_brk(target_ulong new_brk); +void target_set_brk(abi_ulong new_brk); +abi_long do_brk(abi_ulong new_brk); void syscall_init(void); -target_long do_syscall(void *cpu_env, int num, target_long arg1, - target_long arg2, target_long arg3, target_long arg4, - target_long arg5, target_long arg6); +abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6); void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); extern CPUState *global_env; void cpu_loop(CPUState *env); @@ -157,28 +167,28 @@ long do_sigreturn(CPUState *env); long do_rt_sigreturn(CPUState *env); int do_sigaltstack(const struct target_sigaltstack *uss, struct target_sigaltstack *uoss, - target_ulong sp); + abi_ulong sp); #ifdef TARGET_I386 /* vm86.c */ void save_v86_state(CPUX86State *env); void handle_vm86_trap(CPUX86State *env, int trapno); void handle_vm86_fault(CPUX86State *env); -int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr); +int do_vm86(CPUX86State *env, long subfunction, abi_ulong v86_addr); #elif defined(TARGET_SPARC64) void sparc64_set_context(CPUSPARCState *env); void sparc64_get_context(CPUSPARCState *env); #endif /* mmap.c */ -int target_mprotect(target_ulong start, target_ulong len, int prot); -target_long target_mmap(target_ulong start, target_ulong len, int prot, - int flags, int fd, target_ulong offset); -int target_munmap(target_ulong start, target_ulong len); -target_long target_mremap(target_ulong old_addr, target_ulong old_size, - target_ulong new_size, unsigned long flags, - target_ulong new_addr); -int target_msync(target_ulong start, target_ulong len, int flags); +int target_mprotect(abi_ulong start, abi_ulong len, int prot); +abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, + int flags, int fd, abi_ulong offset); +int target_munmap(abi_ulong start, abi_ulong len); +abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, + abi_ulong new_size, unsigned long flags, + abi_ulong new_addr); +int target_msync(abi_ulong start, abi_ulong len, int flags); /* user access */ @@ -260,7 +270,7 @@ int target_msync(target_ulong start, target_ulong len, int flags); /* Lock an area of guest memory into the host. If copy is true then the host area will have the same contents as the guest. */ -static inline void *lock_user(target_ulong guest_addr, long len, int copy) +static inline void *lock_user(abi_ulong guest_addr, long len, int copy) { #ifdef DEBUG_REMAP void *addr; @@ -277,8 +287,8 @@ static inline void *lock_user(target_ulong guest_addr, long len, int copy) /* Unlock an area of guest memory. The first LEN bytes must be flushed back to guest memory. */ -static inline void unlock_user(void *host_addr, target_ulong guest_addr, - long len) +static inline void unlock_user(void *host_addr, abi_ulong guest_addr, + long len) { #ifdef DEBUG_REMAP if (host_addr == g2h(guest_addr)) @@ -290,13 +300,13 @@ static inline void unlock_user(void *host_addr, target_ulong guest_addr, } /* Return the length of a string in target memory. */ -static inline int target_strlen(target_ulong ptr) +static inline int target_strlen(abi_ulong ptr) { return strlen(g2h(ptr)); } /* Like lock_user but for null terminated strings. */ -static inline void *lock_user_string(target_ulong guest_addr) +static inline void *lock_user_string(abi_ulong guest_addr) { long len; len = target_strlen(guest_addr) + 1; @@ -317,7 +327,7 @@ static inline void *lock_user_string(target_ulong guest_addr) #define tput32(addr, val) stl(addr, val) #define tget64(addr) ldq(addr) #define tput64(addr, val) stq(addr, val) -#if TARGET_LONG_BITS == 64 +#if TARGET_ABI_BITS == 64 #define tgetl(addr) ldq(addr) #define tputl(addr, val) stq(addr, val) #else diff --git a/linux-user/sh4/target_signal.h b/linux-user/sh4/target_signal.h index e210e7a31..1fb70921f 100644 --- a/linux-user/sh4/target_signal.h +++ b/linux-user/sh4/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; diff --git a/linux-user/signal.c b/linux-user/signal.c index 52041dafd..cacbc6992 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -26,8 +26,8 @@ #include #include -#include "target_signal.h" #include "qemu.h" +#include "target_signal.h" //#define DEBUG_SIGNAL @@ -134,12 +134,12 @@ static void host_to_target_sigset_internal(target_sigset_t *d, if (sigmask & (1 << i)) target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1); } -#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 +#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 32 d->sig[0] = target_sigmask; for(i = 1;i < TARGET_NSIG_WORDS; i++) { d->sig[i] = ((unsigned long *)s)[i]; } -#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 +#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 d->sig[0] = target_sigmask; d->sig[1] = sigmask >> 32; #else @@ -161,7 +161,7 @@ void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) { int i; unsigned long sigmask; - target_ulong target_sigmask; + abi_ulong target_sigmask; target_sigmask = s->sig[0]; sigmask = 0; @@ -169,16 +169,16 @@ void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) if (target_sigmask & (1 << i)) sigmask |= 1 << (target_to_host_signal(i + 1) - 1); } -#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 +#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 32 ((unsigned long *)d)[0] = sigmask; for(i = 1;i < TARGET_NSIG_WORDS; i++) { ((unsigned long *)d)[i] = s->sig[i]; } -#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 +#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32); #else #warning target_to_host_sigset -#endif /* TARGET_LONG_BITS */ +#endif /* TARGET_ABI_BITS */ } void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) @@ -191,7 +191,7 @@ void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) target_to_host_sigset_internal(d, &s1); } -void host_to_target_old_sigset(target_ulong *old_sigset, +void host_to_target_old_sigset(abi_ulong *old_sigset, const sigset_t *sigset) { target_sigset_t d; @@ -200,7 +200,7 @@ void host_to_target_old_sigset(target_ulong *old_sigset, } void target_to_host_old_sigset(sigset_t *sigset, - const target_ulong *old_sigset) + const abi_ulong *old_sigset) { target_sigset_t d; int i; @@ -233,7 +233,7 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, tinfo->_sifields._rt._uid = info->si_uid; /* XXX: potential problem if 64 bit */ tinfo->_sifields._rt._sigval.sival_ptr = - (target_ulong)info->si_value.sival_ptr; + (abi_ulong)info->si_value.sival_ptr; } } @@ -355,7 +355,7 @@ int queue_signal(int sig, target_siginfo_t *info) { struct emulated_sigaction *k; struct sigqueue *q, **pq; - target_ulong handler; + abi_ulong handler; #if defined(DEBUG_SIGNAL) fprintf(stderr, "queue_signal: sig=%d\n", @@ -440,7 +440,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, int do_sigaltstack(const struct target_sigaltstack *uss, struct target_sigaltstack *uoss, - target_ulong sp) + abi_ulong sp) { int ret; struct target_sigaltstack oss; @@ -579,29 +579,29 @@ struct target_fpxreg { }; struct target_xmmreg { - target_ulong element[4]; + abi_ulong element[4]; }; struct target_fpstate { /* Regular FPU environment */ - target_ulong cw; - target_ulong sw; - target_ulong tag; - target_ulong ipoff; - target_ulong cssel; - target_ulong dataoff; - target_ulong datasel; + abi_ulong cw; + abi_ulong sw; + abi_ulong tag; + abi_ulong ipoff; + abi_ulong cssel; + abi_ulong dataoff; + abi_ulong datasel; struct target_fpreg _st[8]; uint16_t status; uint16_t magic; /* 0xffff = regular FPU data only */ /* FXSR FPU environment */ - target_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */ - target_ulong mxcsr; - target_ulong reserved; + abi_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */ + abi_ulong mxcsr; + abi_ulong reserved; struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ struct target_xmmreg _xmm[8]; - target_ulong padding[56]; + abi_ulong padding[56]; }; #define X86_FXSR_MAGIC 0x0000 @@ -611,29 +611,29 @@ struct target_sigcontext { uint16_t fs, __fsh; uint16_t es, __esh; uint16_t ds, __dsh; - target_ulong edi; - target_ulong esi; - target_ulong ebp; - target_ulong esp; - target_ulong ebx; - target_ulong edx; - target_ulong ecx; - target_ulong eax; - target_ulong trapno; - target_ulong err; - target_ulong eip; + abi_ulong edi; + abi_ulong esi; + abi_ulong ebp; + abi_ulong esp; + abi_ulong ebx; + abi_ulong edx; + abi_ulong ecx; + abi_ulong eax; + abi_ulong trapno; + abi_ulong err; + abi_ulong eip; uint16_t cs, __csh; - target_ulong eflags; - target_ulong esp_at_signal; + abi_ulong eflags; + abi_ulong esp_at_signal; uint16_t ss, __ssh; - target_ulong fpstate; /* pointer */ - target_ulong oldmask; - target_ulong cr2; + abi_ulong fpstate; /* pointer */ + abi_ulong oldmask; + abi_ulong cr2; }; struct target_ucontext { - target_ulong tuc_flags; - target_ulong tuc_link; + abi_ulong tuc_flags; + abi_ulong tuc_link; target_stack_t tuc_stack; struct target_sigcontext tuc_mcontext; target_sigset_t tuc_sigmask; /* mask last for extensibility */ @@ -641,20 +641,20 @@ struct target_ucontext { struct sigframe { - target_ulong pretcode; + abi_ulong pretcode; int sig; struct target_sigcontext sc; struct target_fpstate fpstate; - target_ulong extramask[TARGET_NSIG_WORDS-1]; + abi_ulong extramask[TARGET_NSIG_WORDS-1]; char retcode[8]; }; struct rt_sigframe { - target_ulong pretcode; + abi_ulong pretcode; int sig; - target_ulong pinfo; - target_ulong puc; + abi_ulong pinfo; + abi_ulong puc; struct target_siginfo info; struct target_ucontext uc; struct target_fpstate fpstate; @@ -813,8 +813,8 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, ? current->exec_domain->signal_invmap[sig] : */sig), &frame->sig); - err |= __put_user((target_ulong)&frame->info, &frame->pinfo); - err |= __put_user((target_ulong)&frame->uc, &frame->puc); + err |= __put_user((abi_ulong)&frame->info, &frame->pinfo); + err |= __put_user((abi_ulong)&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; @@ -977,32 +977,32 @@ badframe: #elif defined(TARGET_ARM) struct target_sigcontext { - target_ulong trap_no; - target_ulong error_code; - target_ulong oldmask; - target_ulong arm_r0; - target_ulong arm_r1; - target_ulong arm_r2; - target_ulong arm_r3; - target_ulong arm_r4; - target_ulong arm_r5; - target_ulong arm_r6; - target_ulong arm_r7; - target_ulong arm_r8; - target_ulong arm_r9; - target_ulong arm_r10; - target_ulong arm_fp; - target_ulong arm_ip; - target_ulong arm_sp; - target_ulong arm_lr; - target_ulong arm_pc; - target_ulong arm_cpsr; - target_ulong fault_address; + abi_ulong trap_no; + abi_ulong error_code; + abi_ulong oldmask; + abi_ulong arm_r0; + abi_ulong arm_r1; + abi_ulong arm_r2; + abi_ulong arm_r3; + abi_ulong arm_r4; + abi_ulong arm_r5; + abi_ulong arm_r6; + abi_ulong arm_r7; + abi_ulong arm_r8; + abi_ulong arm_r9; + abi_ulong arm_r10; + abi_ulong arm_fp; + abi_ulong arm_ip; + abi_ulong arm_sp; + abi_ulong arm_lr; + abi_ulong arm_pc; + abi_ulong arm_cpsr; + abi_ulong fault_address; }; struct target_ucontext { - target_ulong tuc_flags; - target_ulong tuc_link; + abi_ulong tuc_flags; + abi_ulong tuc_link; target_stack_t tuc_stack; struct target_sigcontext tuc_mcontext; target_sigset_t tuc_sigmask; /* mask last for extensibility */ @@ -1011,8 +1011,8 @@ struct target_ucontext { struct sigframe { struct target_sigcontext sc; - target_ulong extramask[TARGET_NSIG_WORDS-1]; - target_ulong retcode; + abi_ulong extramask[TARGET_NSIG_WORDS-1]; + abi_ulong retcode; }; struct rt_sigframe @@ -1021,7 +1021,7 @@ struct rt_sigframe void *puc; struct target_siginfo info; struct target_ucontext uc; - target_ulong retcode; + abi_ulong retcode; }; #define TARGET_CONFIG_CPU_32 1 @@ -1039,7 +1039,7 @@ struct rt_sigframe #define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn)) #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn)) -static const target_ulong retcodes[4] = { +static const abi_ulong retcodes[4] = { SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN }; @@ -1105,14 +1105,14 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) static int setup_return(CPUState *env, struct emulated_sigaction *ka, - target_ulong *rc, void *frame, int usig) + abi_ulong *rc, void *frame, int usig) { - target_ulong handler = (target_ulong)ka->sa._sa_handler; - target_ulong retcode; + abi_ulong handler = (abi_ulong)ka->sa._sa_handler; + abi_ulong retcode; int thumb = 0; #if defined(TARGET_CONFIG_CPU_32) #if 0 - target_ulong cpsr = env->cpsr; + abi_ulong cpsr = env->cpsr; /* * Maybe we need to deliver a 32-bit signal to a 26-bit task. @@ -1138,7 +1138,7 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, #endif /* TARGET_CONFIG_CPU_32 */ if (ka->sa.sa_flags & TARGET_SA_RESTORER) { - retcode = (target_ulong)ka->sa.sa_restorer; + retcode = (abi_ulong)ka->sa.sa_restorer; } else { unsigned int idx = thumb; @@ -1148,10 +1148,10 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, if (__put_user(retcodes[idx], rc)) return 1; #if 0 - flush_icache_range((target_ulong)rc, - (target_ulong)(rc + 1)); + flush_icache_range((abi_ulong)rc, + (abi_ulong)(rc + 1)); #endif - retcode = ((target_ulong)rc) + thumb; + retcode = ((abi_ulong)rc) + thumb; } env->regs[0] = usig; @@ -1197,8 +1197,8 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) return /* 1 */; - __put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err); - __put_user_error(&frame->uc, (target_ulong *)&frame->puc, err); + __put_user_error(&frame->info, (abi_ulong *)&frame->pinfo, err); + __put_user_error(&frame->uc, (abi_ulong *)&frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); /* Clear all the bits of the ucontext we don't use. */ @@ -1229,8 +1229,8 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, * arguments for the signal handler. * -- Peter Maydell 2000-12-06 */ - env->regs[1] = (target_ulong)frame->pinfo; - env->regs[2] = (target_ulong)frame->puc; + env->regs[1] = (abi_ulong)frame->pinfo; + env->regs[2] = (abi_ulong)frame->puc; } // return err; @@ -1360,48 +1360,48 @@ badframe: /* This is what SunOS does, so shall I. */ struct target_sigcontext { - target_ulong sigc_onstack; /* state to restore */ + abi_ulong sigc_onstack; /* state to restore */ - target_ulong sigc_mask; /* sigmask to restore */ - target_ulong sigc_sp; /* stack pointer */ - target_ulong sigc_pc; /* program counter */ - target_ulong sigc_npc; /* next program counter */ - target_ulong sigc_psr; /* for condition codes etc */ - target_ulong sigc_g1; /* User uses these two registers */ - target_ulong sigc_o0; /* within the trampoline code. */ + abi_ulong sigc_mask; /* sigmask to restore */ + abi_ulong sigc_sp; /* stack pointer */ + abi_ulong sigc_pc; /* program counter */ + abi_ulong sigc_npc; /* next program counter */ + abi_ulong sigc_psr; /* for condition codes etc */ + abi_ulong sigc_g1; /* User uses these two registers */ + abi_ulong sigc_o0; /* within the trampoline code. */ /* Now comes information regarding the users window set * at the time of the signal. */ - target_ulong sigc_oswins; /* outstanding windows */ + abi_ulong sigc_oswins; /* outstanding windows */ /* stack ptrs for each regwin buf */ char *sigc_spbuf[__SUNOS_MAXWIN]; /* Windows to restore after signal */ struct { - target_ulong locals[8]; - target_ulong ins[8]; + abi_ulong locals[8]; + abi_ulong ins[8]; } sigc_wbuf[__SUNOS_MAXWIN]; }; /* A Sparc stack frame */ struct sparc_stackf { - target_ulong locals[8]; - target_ulong ins[6]; + abi_ulong locals[8]; + abi_ulong ins[6]; struct sparc_stackf *fp; - target_ulong callers_pc; + abi_ulong callers_pc; char *structptr; - target_ulong xargs[6]; - target_ulong xxargs[1]; + abi_ulong xargs[6]; + abi_ulong xxargs[1]; }; typedef struct { struct { - target_ulong psr; - target_ulong pc; - target_ulong npc; - target_ulong y; - target_ulong u_regs[16]; /* globals and ins */ + abi_ulong psr; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong u_regs[16]; /* globals and ins */ } si_regs; int si_mask; } __siginfo_t; @@ -1421,15 +1421,15 @@ struct target_signal_frame { struct sparc_stackf ss; __siginfo_t info; qemu_siginfo_fpu_t *fpu_save; - target_ulong insns[2] __attribute__ ((aligned (8))); - target_ulong extramask[TARGET_NSIG_WORDS - 1]; - target_ulong extra_size; /* Should be 0 */ + abi_ulong insns[2] __attribute__ ((aligned (8))); + abi_ulong extramask[TARGET_NSIG_WORDS - 1]; + abi_ulong extra_size; /* Should be 0 */ qemu_siginfo_fpu_t fpu_state; }; struct target_rt_signal_frame { struct sparc_stackf ss; siginfo_t info; - target_ulong regs[20]; + abi_ulong regs[20]; sigset_t mask; qemu_siginfo_fpu_t *fpu_save; unsigned int insns[2]; @@ -1468,7 +1468,7 @@ static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, u } static int -setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) +setup___siginfo(__siginfo_t *si, CPUState *env, abi_ulong mask) { int err = 0, i; @@ -1634,7 +1634,7 @@ long do_sigreturn(CPUState *env) uint32_t up_psr, pc, npc; target_sigset_t set; sigset_t host_set; - target_ulong fpu_save; + abi_ulong fpu_save; int err, i; sf = (struct target_signal_frame *)g2h(env->regwptr[UREG_FP]); @@ -1676,7 +1676,7 @@ long do_sigreturn(CPUState *env) err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); } - err |= __get_user(fpu_save, (target_ulong *)&sf->fpu_save); + err |= __get_user(fpu_save, (abi_ulong *)&sf->fpu_save); //if (fpu_save) // err |= restore_fpu_state(env, fpu_save); @@ -1729,11 +1729,11 @@ long do_rt_sigreturn(CPUState *env) #define MC_O7 18 #define MC_NGREG 19 -typedef target_ulong target_mc_greg_t; +typedef abi_ulong target_mc_greg_t; typedef target_mc_greg_t target_mc_gregset_t[MC_NGREG]; struct target_mc_fq { - target_ulong *mcfq_addr; + abi_ulong *mcfq_addr; uint32_t mcfq_insn; }; @@ -1743,9 +1743,9 @@ struct target_mc_fpu { uint64_t dregs[32]; //uint128_t qregs[16]; } mcfpu_fregs; - target_ulong mcfpu_fsr; - target_ulong mcfpu_fprs; - target_ulong mcfpu_gsr; + abi_ulong mcfpu_fsr; + abi_ulong mcfpu_fprs; + abi_ulong mcfpu_gsr; struct target_mc_fq *mcfpu_fq; unsigned char mcfpu_qcnt; unsigned char mcfpu_qentsz; @@ -1762,15 +1762,15 @@ typedef struct { struct target_ucontext { struct target_ucontext *uc_link; - target_ulong uc_flags; + abi_ulong uc_flags; target_sigset_t uc_sigmask; target_mcontext_t uc_mcontext; }; /* A V9 register window */ struct target_reg_window { - target_ulong locals[8]; - target_ulong ins[8]; + abi_ulong locals[8]; + abi_ulong ins[8]; }; #define TARGET_STACK_BIAS 2047 @@ -1781,12 +1781,12 @@ void sparc64_set_context(CPUSPARCState *env) struct target_ucontext *ucp = (struct target_ucontext *) env->regwptr[UREG_I0]; target_mc_gregset_t *grp; - target_ulong pc, npc, tstate; - target_ulong fp, i7; + abi_ulong pc, npc, tstate; + abi_ulong fp, i7; unsigned char fenab; int err; unsigned int i; - target_ulong *src, *dst; + abi_ulong *src, *dst; grp = &ucp->uc_mcontext.mc_gregs; err = get_user(pc, &((*grp)[MC_PC])); @@ -1803,7 +1803,7 @@ void sparc64_set_context(CPUSPARCState *env) } else { src = &ucp->uc_sigmask; dst = &target_set; - for (i = 0; i < sizeof(target_sigset_t) / sizeof(target_ulong); + for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong); i++, dst++, src++) err |= get_user(dst, src); if (err) @@ -1866,10 +1866,10 @@ void sparc64_get_context(CPUSPARCState *env) env->regwptr[UREG_I0]; target_mc_gregset_t *grp; target_mcontext_t *mcp; - target_ulong fp, i7; + abi_ulong fp, i7; int err; unsigned int i; - target_ulong *src, *dst; + abi_ulong *src, *dst; target_sigset_t target_set; sigset_t set; @@ -1886,11 +1886,11 @@ void sparc64_get_context(CPUSPARCState *env) host_to_target_sigset_internal(&target_set, &set); if (TARGET_NSIG_WORDS == 1) err |= put_user(target_set.sig[0], - (target_ulong *)&ucp->uc_sigmask); + (abi_ulong *)&ucp->uc_sigmask); else { src = &target_set; dst = &ucp->uc_sigmask; - for (i = 0; i < sizeof(target_sigset_t) / sizeof(target_ulong); + for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong); i++, dst++, src++) err |= put_user(src, dst); if (err) @@ -2354,7 +2354,7 @@ long do_rt_sigreturn(CPUState *env) void process_pending_signals(void *cpu_env) { int sig; - target_ulong handler; + abi_ulong handler; sigset_t set, old_set; target_sigset_t target_old_set; struct emulated_sigaction *k; diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index 5be90fa7f..5a9bb7e54 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -1,9 +1,9 @@ struct target_pt_regs { - target_ulong psr; - target_ulong pc; - target_ulong npc; - target_ulong y; - target_ulong u_regs[16]; + abi_ulong psr; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong u_regs[16]; }; #define UNAME_MACHINE "sun4" diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h index dfca12916..c7de300cd 100644 --- a/linux-user/sparc/target_signal.h +++ b/linux-user/sparc/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; @@ -28,7 +28,7 @@ typedef struct target_sigaltstack { #define UREG_FP UREG_I6 #endif -static inline target_ulong get_sp_from_cpustate(CPUSPARCState *state) +static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) { return state->regwptr[UREG_FP]; } diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h index c361558b6..81a816de9 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/syscall.h @@ -1,10 +1,10 @@ struct target_pt_regs { - target_ulong u_regs[16]; - target_ulong tstate; - target_ulong pc; - target_ulong npc; - target_ulong y; - target_ulong fprs; + abi_ulong u_regs[16]; + abi_ulong tstate; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong fprs; }; #define UNAME_MACHINE "sun4u" diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h index dfca12916..c7de300cd 100644 --- a/linux-user/sparc64/target_signal.h +++ b/linux-user/sparc64/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; @@ -28,7 +28,7 @@ typedef struct target_sigaltstack { #define UREG_FP UREG_I6 #endif -static inline target_ulong get_sp_from_cpustate(CPUSPARCState *state) +static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) { return state->regwptr[UREG_FP]; } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a1d9ee1e5..e4ea31349 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -368,7 +368,7 @@ static inline int host_to_target_errno(int err) return err; } -static inline target_long get_errno(target_long ret) +static inline abi_long get_errno(abi_long ret) { if (ret == -1) return -host_to_target_errno(errno); @@ -376,23 +376,23 @@ static inline target_long get_errno(target_long ret) return ret; } -static inline int is_error(target_long ret) +static inline int is_error(abi_long ret) { - return (target_ulong)ret >= (target_ulong)(-4096); + return (abi_ulong)ret >= (abi_ulong)(-4096); } -static target_ulong target_brk; -static target_ulong target_original_brk; +static abi_ulong target_brk; +static abi_ulong target_original_brk; -void target_set_brk(target_ulong new_brk) +void target_set_brk(abi_ulong new_brk) { target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); } -target_long do_brk(target_ulong new_brk) +abi_long do_brk(abi_ulong new_brk) { - target_ulong brk_page; - target_long mapped_addr; + abi_ulong brk_page; + abi_long mapped_addr; int new_alloc_size; if (!new_brk) @@ -422,7 +422,7 @@ target_long do_brk(target_ulong new_brk) } static inline fd_set *target_to_host_fds(fd_set *fds, - target_long *target_fds, int n) + abi_long *target_fds, int n) { #if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) return (fd_set *)target_fds; @@ -431,8 +431,8 @@ static inline fd_set *target_to_host_fds(fd_set *fds, if (target_fds) { FD_ZERO(fds); for(i = 0;i < n; i++) { - b = (tswapl(target_fds[i / TARGET_LONG_BITS]) >> - (i & (TARGET_LONG_BITS - 1))) & 1; + b = (tswapl(target_fds[i / TARGET_ABI_BITS]) >> + (i & (TARGET_ABI_BITS - 1))) & 1; if (b) FD_SET(i, fds); } @@ -443,21 +443,21 @@ static inline fd_set *target_to_host_fds(fd_set *fds, #endif } -static inline void host_to_target_fds(target_long *target_fds, +static inline void host_to_target_fds(abi_long *target_fds, fd_set *fds, int n) { #if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) /* nothing to do */ #else int i, nw, j, k; - target_long v; + abi_long v; if (target_fds) { - nw = (n + TARGET_LONG_BITS - 1) / TARGET_LONG_BITS; + nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; k = 0; for(i = 0;i < nw; i++) { v = 0; - for(j = 0; j < TARGET_LONG_BITS; j++) { + for(j = 0; j < TARGET_ABI_BITS; j++) { v |= ((FD_ISSET(k, fds) != 0) << j); k++; } @@ -473,7 +473,7 @@ static inline void host_to_target_fds(target_long *target_fds, #define HOST_HZ 100 #endif -static inline target_long host_to_target_clock_t(long ticks) +static inline abi_long host_to_target_clock_t(long ticks) { #if HOST_HZ == TARGET_HZ return ticks; @@ -482,7 +482,7 @@ static inline target_long host_to_target_clock_t(long ticks) #endif } -static inline void host_to_target_rusage(target_ulong target_addr, +static inline void host_to_target_rusage(abi_ulong target_addr, const struct rusage *rusage) { struct target_rusage *target_rusage; @@ -510,7 +510,7 @@ static inline void host_to_target_rusage(target_ulong target_addr, } static inline void target_to_host_timeval(struct timeval *tv, - target_ulong target_addr) + abi_ulong target_addr) { struct target_timeval *target_tv; @@ -520,7 +520,7 @@ static inline void target_to_host_timeval(struct timeval *tv, unlock_user_struct(target_tv, target_addr, 0); } -static inline void host_to_target_timeval(target_ulong target_addr, +static inline void host_to_target_timeval(abi_ulong target_addr, const struct timeval *tv) { struct target_timeval *target_tv; @@ -532,33 +532,33 @@ static inline void host_to_target_timeval(target_ulong target_addr, } -static target_long do_select(int n, - target_ulong rfd_p, target_ulong wfd_p, - target_ulong efd_p, target_ulong target_tv) +static abi_long do_select(int n, + abi_ulong rfd_p, abi_ulong wfd_p, + abi_ulong efd_p, abi_ulong target_tv) { fd_set rfds, wfds, efds; fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; - target_long *target_rfds, *target_wfds, *target_efds; + abi_long *target_rfds, *target_wfds, *target_efds; struct timeval tv, *tv_ptr; - target_long ret; + abi_long ret; int ok; if (rfd_p) { - target_rfds = lock_user(rfd_p, sizeof(target_long) * n, 1); + target_rfds = lock_user(rfd_p, sizeof(abi_long) * n, 1); rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); } else { target_rfds = NULL; rfds_ptr = NULL; } if (wfd_p) { - target_wfds = lock_user(wfd_p, sizeof(target_long) * n, 1); + target_wfds = lock_user(wfd_p, sizeof(abi_long) * n, 1); wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); } else { target_wfds = NULL; wfds_ptr = NULL; } if (efd_p) { - target_efds = lock_user(efd_p, sizeof(target_long) * n, 1); + target_efds = lock_user(efd_p, sizeof(abi_long) * n, 1); efds_ptr = target_to_host_fds(&efds, target_efds, n); } else { target_efds = NULL; @@ -584,17 +584,17 @@ static target_long do_select(int n, } } if (target_rfds) - unlock_user(target_rfds, rfd_p, ok ? sizeof(target_long) * n : 0); + unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); if (target_wfds) - unlock_user(target_wfds, wfd_p, ok ? sizeof(target_long) * n : 0); + unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); if (target_efds) - unlock_user(target_efds, efd_p, ok ? sizeof(target_long) * n : 0); + unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); return ret; } static inline void target_to_host_sockaddr(struct sockaddr *addr, - target_ulong target_addr, + abi_ulong target_addr, socklen_t len) { struct target_sockaddr *target_saddr; @@ -605,7 +605,7 @@ static inline void target_to_host_sockaddr(struct sockaddr *addr, unlock_user(target_saddr, target_addr, 0); } -static inline void host_to_target_sockaddr(target_ulong target_addr, +static inline void host_to_target_sockaddr(abi_ulong target_addr, struct sockaddr *addr, socklen_t len) { @@ -706,10 +706,10 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, msgh->msg_controllen = tswapl(space); } -static target_long do_setsockopt(int sockfd, int level, int optname, - target_ulong optval, socklen_t optlen) +static abi_long do_setsockopt(int sockfd, int level, int optname, + abi_ulong optval, socklen_t optlen) { - target_long ret; + abi_long ret; int val; switch(level) { @@ -827,10 +827,10 @@ static target_long do_setsockopt(int sockfd, int level, int optname, return ret; } -static target_long do_getsockopt(int sockfd, int level, int optname, - target_ulong optval, target_ulong optlen) +static abi_long do_getsockopt(int sockfd, int level, int optname, + abi_ulong optval, abi_ulong optlen) { - target_long ret; + abi_long ret; int len, lv, val; switch(level) { @@ -916,11 +916,11 @@ static target_long do_getsockopt(int sockfd, int level, int optname, return ret; } -static void lock_iovec(struct iovec *vec, target_ulong target_addr, +static void lock_iovec(struct iovec *vec, abi_ulong target_addr, int count, int copy) { struct target_iovec *target_vec; - target_ulong base; + abi_ulong base; int i; target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); @@ -932,11 +932,11 @@ static void lock_iovec(struct iovec *vec, target_ulong target_addr, unlock_user (target_vec, target_addr, 0); } -static void unlock_iovec(struct iovec *vec, target_ulong target_addr, +static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, int count, int copy) { struct target_iovec *target_vec; - target_ulong base; + abi_ulong base; int i; target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); @@ -947,7 +947,7 @@ static void unlock_iovec(struct iovec *vec, target_ulong target_addr, unlock_user (target_vec, target_addr, 0); } -static target_long do_socket(int domain, int type, int protocol) +static abi_long do_socket(int domain, int type, int protocol) { #if defined(TARGET_MIPS) switch(type) { @@ -974,8 +974,8 @@ static target_long do_socket(int domain, int type, int protocol) return get_errno(socket(domain, type, protocol)); } -static target_long do_bind(int sockfd, target_ulong target_addr, - socklen_t addrlen) +static abi_long do_bind(int sockfd, abi_ulong target_addr, + socklen_t addrlen) { void *addr = alloca(addrlen); @@ -983,8 +983,8 @@ static target_long do_bind(int sockfd, target_ulong target_addr, return get_errno(bind(sockfd, addr, addrlen)); } -static target_long do_connect(int sockfd, target_ulong target_addr, - socklen_t addrlen) +static abi_long do_connect(int sockfd, abi_ulong target_addr, + socklen_t addrlen) { void *addr = alloca(addrlen); @@ -992,15 +992,15 @@ static target_long do_connect(int sockfd, target_ulong target_addr, return get_errno(connect(sockfd, addr, addrlen)); } -static target_long do_sendrecvmsg(int fd, target_ulong target_msg, - int flags, int send) +static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, + int flags, int send) { - target_long ret; + abi_long ret; struct target_msghdr *msgp; struct msghdr msg; int count; struct iovec *vec; - target_ulong target_vec; + abi_ulong target_vec; lock_user_struct(msgp, target_msg, 1); if (msgp->msg_name) { @@ -1035,12 +1035,12 @@ static target_long do_sendrecvmsg(int fd, target_ulong target_msg, return ret; } -static target_long do_accept(int fd, target_ulong target_addr, - target_ulong target_addrlen) +static abi_long do_accept(int fd, abi_ulong target_addr, + abi_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); - target_long ret; + abi_long ret; ret = get_errno(accept(fd, addr, &addrlen)); if (!is_error(ret)) { @@ -1050,12 +1050,12 @@ static target_long do_accept(int fd, target_ulong target_addr, return ret; } -static target_long do_getpeername(int fd, target_ulong target_addr, - target_ulong target_addrlen) +static abi_long do_getpeername(int fd, abi_ulong target_addr, + abi_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); - target_long ret; + abi_long ret; ret = get_errno(getpeername(fd, addr, &addrlen)); if (!is_error(ret)) { @@ -1065,12 +1065,12 @@ static target_long do_getpeername(int fd, target_ulong target_addr, return ret; } -static target_long do_getsockname(int fd, target_ulong target_addr, - target_ulong target_addrlen) +static abi_long do_getsockname(int fd, abi_ulong target_addr, + abi_ulong target_addrlen) { socklen_t addrlen = tget32(target_addrlen); void *addr = alloca(addrlen); - target_long ret; + abi_long ret; ret = get_errno(getsockname(fd, addr, &addrlen)); if (!is_error(ret)) { @@ -1080,11 +1080,11 @@ static target_long do_getsockname(int fd, target_ulong target_addr, return ret; } -static target_long do_socketpair(int domain, int type, int protocol, - target_ulong target_tab) +static abi_long do_socketpair(int domain, int type, int protocol, + abi_ulong target_tab) { int tab[2]; - target_long ret; + abi_long ret; ret = get_errno(socketpair(domain, type, protocol, tab)); if (!is_error(ret)) { @@ -1094,12 +1094,12 @@ static target_long do_socketpair(int domain, int type, int protocol, return ret; } -static target_long do_sendto(int fd, target_ulong msg, size_t len, int flags, - target_ulong target_addr, socklen_t addrlen) +static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, + abi_ulong target_addr, socklen_t addrlen) { void *addr; void *host_msg; - target_long ret; + abi_long ret; host_msg = lock_user(msg, len, 1); if (target_addr) { @@ -1113,14 +1113,14 @@ static target_long do_sendto(int fd, target_ulong msg, size_t len, int flags, return ret; } -static target_long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, - target_ulong target_addr, - target_ulong target_addrlen) +static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, + abi_ulong target_addr, + abi_ulong target_addrlen) { socklen_t addrlen; void *addr; void *host_msg; - target_long ret; + abi_long ret; host_msg = lock_user(msg, len, 0); if (target_addr) { @@ -1144,10 +1144,10 @@ static target_long do_recvfrom(int fd, target_ulong msg, size_t len, int flags, } #ifdef TARGET_NR_socketcall -static target_long do_socketcall(int num, target_ulong vptr) +static abi_long do_socketcall(int num, abi_ulong vptr) { - target_long ret; - const int n = sizeof(target_ulong); + abi_long ret; + const int n = sizeof(abi_ulong); switch(num) { case SOCKOP_socket: @@ -1161,7 +1161,7 @@ static target_long do_socketcall(int num, target_ulong vptr) case SOCKOP_bind: { int sockfd = tgetl(vptr); - target_ulong target_addr = tgetl(vptr + n); + abi_ulong target_addr = tgetl(vptr + n); socklen_t addrlen = tgetl(vptr + 2 * n); ret = do_bind(sockfd, target_addr, addrlen); } @@ -1169,7 +1169,7 @@ static target_long do_socketcall(int num, target_ulong vptr) case SOCKOP_connect: { int sockfd = tgetl(vptr); - target_ulong target_addr = tgetl(vptr + n); + abi_ulong target_addr = tgetl(vptr + n); socklen_t addrlen = tgetl(vptr + 2 * n); ret = do_connect(sockfd, target_addr, addrlen); } @@ -1184,24 +1184,24 @@ static target_long do_socketcall(int num, target_ulong vptr) case SOCKOP_accept: { int sockfd = tgetl(vptr); - target_ulong target_addr = tgetl(vptr + n); - target_ulong target_addrlen = tgetl(vptr + 2 * n); + abi_ulong target_addr = tgetl(vptr + n); + abi_ulong target_addrlen = tgetl(vptr + 2 * n); ret = do_accept(sockfd, target_addr, target_addrlen); } break; case SOCKOP_getsockname: { int sockfd = tgetl(vptr); - target_ulong target_addr = tgetl(vptr + n); - target_ulong target_addrlen = tgetl(vptr + 2 * n); + abi_ulong target_addr = tgetl(vptr + n); + abi_ulong target_addrlen = tgetl(vptr + 2 * n); ret = do_getsockname(sockfd, target_addr, target_addrlen); } break; case SOCKOP_getpeername: { int sockfd = tgetl(vptr); - target_ulong target_addr = tgetl(vptr + n); - target_ulong target_addrlen = tgetl(vptr + 2 * n); + abi_ulong target_addr = tgetl(vptr + n); + abi_ulong target_addrlen = tgetl(vptr + 2 * n); ret = do_getpeername(sockfd, target_addr, target_addrlen); } break; @@ -1210,14 +1210,14 @@ static target_long do_socketcall(int num, target_ulong vptr) int domain = tgetl(vptr); int type = tgetl(vptr + n); int protocol = tgetl(vptr + 2 * n); - target_ulong tab = tgetl(vptr + 3 * n); + abi_ulong tab = tgetl(vptr + 3 * n); ret = do_socketpair(domain, type, protocol, tab); } break; case SOCKOP_send: { int sockfd = tgetl(vptr); - target_ulong msg = tgetl(vptr + n); + abi_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); ret = do_sendto(sockfd, msg, len, flags, 0, 0); @@ -1226,7 +1226,7 @@ static target_long do_socketcall(int num, target_ulong vptr) case SOCKOP_recv: { int sockfd = tgetl(vptr); - target_ulong msg = tgetl(vptr + n); + abi_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); ret = do_recvfrom(sockfd, msg, len, flags, 0, 0); @@ -1235,10 +1235,10 @@ static target_long do_socketcall(int num, target_ulong vptr) case SOCKOP_sendto: { int sockfd = tgetl(vptr); - target_ulong msg = tgetl(vptr + n); + abi_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - target_ulong addr = tgetl(vptr + 4 * n); + abi_ulong addr = tgetl(vptr + 4 * n); socklen_t addrlen = tgetl(vptr + 5 * n); ret = do_sendto(sockfd, msg, len, flags, addr, addrlen); } @@ -1246,11 +1246,11 @@ static target_long do_socketcall(int num, target_ulong vptr) case SOCKOP_recvfrom: { int sockfd = tgetl(vptr); - target_ulong msg = tgetl(vptr + n); + abi_ulong msg = tgetl(vptr + n); size_t len = tgetl(vptr + 2 * n); int flags = tgetl(vptr + 3 * n); - target_ulong addr = tgetl(vptr + 4 * n); - target_ulong addrlen = tgetl(vptr + 5 * n); + abi_ulong addr = tgetl(vptr + 4 * n); + abi_ulong addrlen = tgetl(vptr + 5 * n); ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen); } break; @@ -1266,7 +1266,7 @@ static target_long do_socketcall(int num, target_ulong vptr) case SOCKOP_recvmsg: { int fd; - target_ulong target_msg; + abi_ulong target_msg; int flags; fd = tgetl(vptr); @@ -1282,7 +1282,7 @@ static target_long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); int level = tgetl(vptr + n); int optname = tgetl(vptr + 2 * n); - target_ulong optval = tgetl(vptr + 3 * n); + abi_ulong optval = tgetl(vptr + 3 * n); socklen_t optlen = tgetl(vptr + 4 * n); ret = do_setsockopt(sockfd, level, optname, optval, optlen); @@ -1293,8 +1293,8 @@ static target_long do_socketcall(int num, target_ulong vptr) int sockfd = tgetl(vptr); int level = tgetl(vptr + n); int optname = tgetl(vptr + 2 * n); - target_ulong optval = tgetl(vptr + 3 * n); - target_ulong poptlen = tgetl(vptr + 4 * n); + abi_ulong optval = tgetl(vptr + 3 * n); + abi_ulong poptlen = tgetl(vptr + 4 * n); ret = do_getsockopt(sockfd, level, optname, optval, poptlen); } @@ -1318,33 +1318,33 @@ static struct shm_region { struct target_ipc_perm { - target_long __key; - target_ulong uid; - target_ulong gid; - target_ulong cuid; - target_ulong cgid; + abi_long __key; + abi_ulong uid; + abi_ulong gid; + abi_ulong cuid; + abi_ulong cgid; unsigned short int mode; unsigned short int __pad1; unsigned short int __seq; unsigned short int __pad2; - target_ulong __unused1; - target_ulong __unused2; + abi_ulong __unused1; + abi_ulong __unused2; }; struct target_semid_ds { struct target_ipc_perm sem_perm; - target_ulong sem_otime; - target_ulong __unused1; - target_ulong sem_ctime; - target_ulong __unused2; - target_ulong sem_nsems; - target_ulong __unused3; - target_ulong __unused4; + abi_ulong sem_otime; + abi_ulong __unused1; + abi_ulong sem_ctime; + abi_ulong __unused2; + abi_ulong sem_nsems; + abi_ulong __unused3; + abi_ulong __unused4; }; static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, - target_ulong target_addr) + abi_ulong target_addr) { struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; @@ -1360,7 +1360,7 @@ static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, unlock_user_struct(target_sd, target_addr, 0); } -static inline void host_to_target_ipc_perm(target_ulong target_addr, +static inline void host_to_target_ipc_perm(abi_ulong target_addr, struct ipc_perm *host_ip) { struct target_ipc_perm *target_ip; @@ -1378,7 +1378,7 @@ static inline void host_to_target_ipc_perm(target_ulong target_addr, } static inline void target_to_host_semid_ds(struct semid_ds *host_sd, - target_ulong target_addr) + abi_ulong target_addr) { struct target_semid_ds *target_sd; @@ -1390,7 +1390,7 @@ static inline void target_to_host_semid_ds(struct semid_ds *host_sd, unlock_user_struct(target_sd, target_addr, 0); } -static inline void host_to_target_semid_ds(target_ulong target_addr, +static inline void host_to_target_semid_ds(abi_ulong target_addr, struct semid_ds *host_sd) { struct target_semid_ds *target_sd; @@ -1411,13 +1411,13 @@ union semun { union target_semun { int val; - target_long buf; + abi_long buf; unsigned short int *array; }; static inline void target_to_host_semun(int cmd, union semun *host_su, - target_ulong target_addr, + abi_ulong target_addr, struct semid_ds *ds) { union target_semun *target_su; @@ -1448,7 +1448,7 @@ static inline void target_to_host_semun(int cmd, } static inline void host_to_target_semun(int cmd, - target_ulong target_addr, + abi_ulong target_addr, union semun *host_su, struct semid_ds *ds) { @@ -1478,13 +1478,13 @@ static inline void host_to_target_semun(int cmd, } } -static inline target_long do_semctl(int first, int second, int third, - target_long ptr) +static inline abi_long do_semctl(int first, int second, int third, + abi_long ptr) { union semun arg; struct semid_ds dsarg; int cmd = third&0xff; - target_long ret = 0; + abi_long ret = 0; switch( cmd ) { case GETVAL: @@ -1527,23 +1527,23 @@ static inline target_long do_semctl(int first, int second, int third, struct target_msqid_ds { struct target_ipc_perm msg_perm; - target_ulong msg_stime; - target_ulong __unused1; - target_ulong msg_rtime; - target_ulong __unused2; - target_ulong msg_ctime; - target_ulong __unused3; - target_ulong __msg_cbytes; - target_ulong msg_qnum; - target_ulong msg_qbytes; - target_ulong msg_lspid; - target_ulong msg_lrpid; - target_ulong __unused4; - target_ulong __unused5; + abi_ulong msg_stime; + abi_ulong __unused1; + abi_ulong msg_rtime; + abi_ulong __unused2; + abi_ulong msg_ctime; + abi_ulong __unused3; + abi_ulong __msg_cbytes; + abi_ulong msg_qnum; + abi_ulong msg_qbytes; + abi_ulong msg_lspid; + abi_ulong msg_lrpid; + abi_ulong __unused4; + abi_ulong __unused5; }; static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, - target_ulong target_addr) + abi_ulong target_addr) { struct target_msqid_ds *target_md; @@ -1560,7 +1560,7 @@ static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, unlock_user_struct(target_md, target_addr, 0); } -static inline void host_to_target_msqid_ds(target_ulong target_addr, +static inline void host_to_target_msqid_ds(abi_ulong target_addr, struct msqid_ds *host_md) { struct target_msqid_ds *target_md; @@ -1578,11 +1578,11 @@ static inline void host_to_target_msqid_ds(target_ulong target_addr, unlock_user_struct(target_md, target_addr, 1); } -static inline target_long do_msgctl(int first, int second, target_long ptr) +static inline abi_long do_msgctl(int first, int second, abi_long ptr) { struct msqid_ds dsarg; int cmd = second&0xff; - target_long ret = 0; + abi_long ret = 0; switch( cmd ) { case IPC_STAT: case IPC_SET: @@ -1596,16 +1596,16 @@ static inline target_long do_msgctl(int first, int second, target_long ptr) } struct target_msgbuf { - target_ulong mtype; + abi_ulong mtype; char mtext[1]; }; -static inline target_long do_msgsnd(int msqid, target_long msgp, - unsigned int msgsz, int msgflg) +static inline abi_long do_msgsnd(int msqid, abi_long msgp, + unsigned int msgsz, int msgflg) { struct target_msgbuf *target_mb; struct msgbuf *host_mb; - target_long ret = 0; + abi_long ret = 0; lock_user_struct(target_mb,msgp,0); host_mb = malloc(msgsz+sizeof(long)); @@ -1618,13 +1618,13 @@ static inline target_long do_msgsnd(int msqid, target_long msgp, return ret; } -static inline target_long do_msgrcv(int msqid, target_long msgp, - unsigned int msgsz, int msgtype, - int msgflg) +static inline abi_long do_msgrcv(int msqid, abi_long msgp, + unsigned int msgsz, int msgtype, + int msgflg) { struct target_msgbuf *target_mb; struct msgbuf *host_mb; - target_long ret = 0; + abi_long ret = 0; lock_user_struct(target_mb, msgp, 0); host_mb = malloc(msgsz+sizeof(long)); @@ -1639,12 +1639,12 @@ static inline target_long do_msgrcv(int msqid, target_long msgp, } /* ??? This only works with linear mappings. */ -static target_long do_ipc(unsigned int call, int first, - int second, int third, - target_long ptr, target_long fifth) +static abi_long do_ipc(unsigned int call, int first, + int second, int third, + abi_long ptr, abi_long fifth) { int version; - target_long ret = 0; + abi_long ret = 0; unsigned long raddr; struct shmid_ds shm_info; int i; @@ -1722,7 +1722,7 @@ static target_long do_ipc(unsigned int call, int first, break; } } - if (put_user(raddr, (target_ulong *)third)) + if (put_user(raddr, (abi_ulong *)third)) return -EFAULT; ret = 0; break; @@ -1803,11 +1803,11 @@ IOCTLEntry ioctl_entries[] = { }; /* ??? Implement proper locking for ioctls. */ -static target_long do_ioctl(int fd, target_long cmd, target_long arg) +static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) { const IOCTLEntry *ie; const argtype *arg_type; - target_long ret; + abi_long ret; uint8_t buf_temp[MAX_STRUCT_SIZE]; int target_size; void *argptr; @@ -2088,7 +2088,7 @@ static bitmask_transtbl fcntl_flags_tbl[] = { /* NOTE: there is really one LDT for all the threads */ uint8_t *ldt_table; -static int read_ldt(target_ulong ptr, unsigned long bytecount) +static int read_ldt(abi_ulong ptr, unsigned long bytecount) { int size; void *p; @@ -2107,7 +2107,7 @@ static int read_ldt(target_ulong ptr, unsigned long bytecount) /* XXX: add locking support */ static int write_ldt(CPUX86State *env, - target_ulong ptr, unsigned long bytecount, int oldmode) + abi_ulong ptr, unsigned long bytecount, int oldmode) { struct target_modify_ldt_ldt_s ldt_info; struct target_modify_ldt_ldt_s *target_ldt_info; @@ -2188,7 +2188,7 @@ install: } /* specific and weird i386 syscalls */ -int do_modify_ldt(CPUX86State *env, int func, target_ulong ptr, unsigned long bytecount) +int do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, unsigned long bytecount) { int ret = -ENOSYS; @@ -2220,7 +2220,7 @@ static int clone_func(void *arg) return 0; } -int do_fork(CPUState *env, unsigned int flags, target_ulong newsp) +int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp) { int ret; TaskState *ts; @@ -2310,13 +2310,13 @@ int do_fork(CPUState *env, unsigned int flags, target_ulong newsp) return ret; } -static target_long do_fcntl(int fd, int cmd, target_ulong arg) +static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) { struct flock fl; struct target_flock *target_fl; struct flock64 fl64; struct target_flock64 *target_fl64; - target_long ret; + abi_long ret; switch(cmd) { case TARGET_F_GETLK: @@ -2475,7 +2475,7 @@ void syscall_init(void) } } -#if TARGET_LONG_BITS == 32 +#if TARGET_ABI_BITS == 32 static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) { #ifdef TARGET_WORDS_BIG_ENDIAN @@ -2484,18 +2484,18 @@ static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) return ((uint64_t)word1 << 32) | word0; #endif } -#else /* TARGET_LONG_BITS == 32 */ +#else /* TARGET_ABI_BITS == 32 */ static inline uint64_t target_offset64(uint64_t word0, uint64_t word1) { return word0; } -#endif /* TARGET_LONG_BITS != 32 */ +#endif /* TARGET_ABI_BITS != 32 */ #ifdef TARGET_NR_truncate64 -static inline target_long target_truncate64(void *cpu_env, const char *arg1, - target_long arg2, - target_long arg3, - target_long arg4) +static inline abi_long target_truncate64(void *cpu_env, const char *arg1, + abi_long arg2, + abi_long arg3, + abi_long arg4) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) @@ -2509,10 +2509,10 @@ static inline target_long target_truncate64(void *cpu_env, const char *arg1, #endif #ifdef TARGET_NR_ftruncate64 -static inline target_long target_ftruncate64(void *cpu_env, target_long arg1, - target_long arg2, - target_long arg3, - target_long arg4) +static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, + abi_long arg2, + abi_long arg3, + abi_long arg4) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) @@ -2526,7 +2526,7 @@ static inline target_long target_ftruncate64(void *cpu_env, target_long arg1, #endif static inline void target_to_host_timespec(struct timespec *host_ts, - target_ulong target_addr) + abi_ulong target_addr) { struct target_timespec *target_ts; @@ -2536,7 +2536,7 @@ static inline void target_to_host_timespec(struct timespec *host_ts, unlock_user_struct(target_ts, target_addr, 0); } -static inline void host_to_target_timespec(target_ulong target_addr, +static inline void host_to_target_timespec(abi_ulong target_addr, struct timespec *host_ts) { struct target_timespec *target_ts; @@ -2547,11 +2547,11 @@ static inline void host_to_target_timespec(target_ulong target_addr, unlock_user_struct(target_ts, target_addr, 1); } -target_long do_syscall(void *cpu_env, int num, target_long arg1, - target_long arg2, target_long arg3, target_long arg4, - target_long arg5, target_long arg6) +abi_long do_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6) { - target_long ret; + abi_long ret; struct stat st; struct statfs stfs; void *p; @@ -2687,10 +2687,10 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, { char **argp, **envp; int argc, envc; - target_ulong gp; - target_ulong guest_argp; - target_ulong guest_envp; - target_ulong addr; + abi_ulong gp; + abi_ulong guest_argp; + abi_ulong guest_envp; + abi_ulong addr; char **q; argc = 0; @@ -2706,7 +2706,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, envp = alloca((envc + 1) * sizeof(void *)); for (gp = guest_argp, q = argp; ; - gp += sizeof(target_ulong), q++) { + gp += sizeof(abi_ulong), q++) { addr = tgetl(gp); if (!addr) break; @@ -2715,7 +2715,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, *q = NULL; for (gp = guest_envp, q = envp; ; - gp += sizeof(target_ulong), q++) { + gp += sizeof(abi_ulong), q++) { addr = tgetl(gp); if (!addr) break; @@ -2728,12 +2728,12 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, unlock_user(p, arg1, 0); for (gp = guest_argp, q = argp; *q; - gp += sizeof(target_ulong), q++) { + gp += sizeof(abi_ulong), q++) { addr = tgetl(gp); unlock_user(*q, addr, 0); } for (gp = guest_envp, q = envp; *q; - gp += sizeof(target_ulong), q++) { + gp += sizeof(abi_ulong), q++) { addr = tgetl(gp); unlock_user(*q, addr, 0); } @@ -3163,7 +3163,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, case TARGET_NR_sgetmask: { sigset_t cur_set; - target_ulong target_set; + abi_ulong target_set; sigprocmask(0, NULL, &cur_set); host_to_target_old_sigset(&target_set, &cur_set); ret = target_set; @@ -3174,7 +3174,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, case TARGET_NR_ssetmask: { sigset_t set, oset, cur_set; - target_ulong target_set = arg1; + abi_ulong target_set = arg1; sigprocmask(0, NULL, &cur_set); target_to_host_old_sigset(&set, &target_set); sigorset(&set, &set, &cur_set); @@ -3407,7 +3407,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, case TARGET_NR_select: { struct target_sel_arg_struct *sel; - target_ulong inp, outp, exp, tvp; + abi_ulong inp, outp, exp, tvp; long nsel; lock_user_struct(sel, arg1, 1); @@ -3510,9 +3510,9 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, case TARGET_NR_mmap: #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) { - target_ulong *v; - target_ulong v1, v2, v3, v4, v5, v6; - v = lock_user(arg1, 6 * sizeof(target_ulong), 1); + abi_ulong *v; + abi_ulong v1, v2, v3, v4, v5, v6; + v = lock_user(arg1, 6 * sizeof(abi_ulong), 1); v1 = tswapl(v[0]); v2 = tswapl(v[1]); v3 = tswapl(v[2]); @@ -3829,7 +3829,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, struct target_stat *target_st; lock_user_struct(target_st, arg2, 0); -#if defined(TARGET_MIPS) || defined(TARGET_SPARC64) +#if defined(TARGET_MIPS) || (defined(TARGET_SPARC64) && !defined(TARGET_ABI32)) target_st->st_dev = tswap32(st.st_dev); #else target_st->st_dev = tswap16(st.st_dev); @@ -3839,7 +3839,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */ target_st->st_uid = tswap32(st.st_uid); target_st->st_gid = tswap32(st.st_gid); -#elif defined(TARGET_SPARC64) +#elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32) target_st->st_mode = tswap32(st.st_mode); target_st->st_uid = tswap32(st.st_uid); target_st->st_gid = tswap32(st.st_gid); @@ -3852,7 +3852,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, /* If this is the same on PPC, then just merge w/ the above ifdef */ target_st->st_nlink = tswapl(st.st_nlink); target_st->st_rdev = tswapl(st.st_rdev); -#elif defined(TARGET_SPARC64) +#elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32) target_st->st_nlink = tswap32(st.st_nlink); target_st->st_rdev = tswap32(st.st_rdev); #else @@ -3892,9 +3892,9 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, case TARGET_NR_wait4: { int status; - target_long status_ptr = arg2; + abi_long status_ptr = arg2; struct rusage rusage, *rusage_ptr; - target_ulong target_rusage = arg4; + abi_ulong target_rusage = arg4; if (target_rusage) rusage_ptr = &rusage; else @@ -4045,14 +4045,14 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, break; #endif case TARGET_NR_getdents: -#if TARGET_LONG_SIZE != 4 +#if TARGET_ABI_BITS != 32 goto unimplemented; #warning not supported -#elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8 +#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 { struct target_dirent *target_dirp; struct dirent *dirp; - target_long count = arg3; + abi_long count = arg3; dirp = malloc(count); if (!dirp) @@ -4072,11 +4072,11 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, tde = target_dirp; while (len > 0) { reclen = de->d_reclen; - treclen = reclen - (2 * (sizeof(long) - sizeof(target_long))); + treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long))); tde->d_reclen = tswap16(treclen); tde->d_ino = tswapl(de->d_ino); tde->d_off = tswapl(de->d_off); - tnamelen = treclen - (2 * sizeof(target_long) + 2); + tnamelen = treclen - (2 * sizeof(abi_long) + 2); if (tnamelen > 256) tnamelen = 256; /* XXX: may not be correct */ @@ -4094,7 +4094,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, #else { struct dirent *dirp; - target_long count = arg3; + abi_long count = arg3; dirp = lock_user(arg2, count, 0); ret = get_errno(sys_getdents(arg1, dirp, count)); @@ -4122,7 +4122,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, case TARGET_NR_getdents64: { struct dirent64 *dirp; - target_long count = arg3; + abi_long count = arg3; dirp = lock_user(arg2, count, 0); ret = get_errno(sys_getdents64(arg1, dirp, count)); if (!is_error(ret)) { @@ -4742,7 +4742,7 @@ target_long do_syscall(void *cpu_env, int num, target_long arg1, ret = get_errno(0); break; #endif -#if TARGET_LONG_BITS == 32 +#if TARGET_ABI_BITS == 32 case TARGET_NR_fcntl64: { int cmd; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index ccccebb5c..6c80c91b3 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -105,13 +105,13 @@ struct target_sockaddr { }; struct target_timeval { - target_long tv_sec; - target_long tv_usec; + abi_long tv_sec; + abi_long tv_usec; }; struct target_timespec { - target_long tv_sec; - target_long tv_nsec; + abi_long tv_sec; + abi_long tv_nsec; }; struct target_itimerval { @@ -119,7 +119,7 @@ struct target_itimerval { struct target_timeval it_value; }; -typedef target_long target_clock_t; +typedef abi_long target_clock_t; #define TARGET_HZ 100 @@ -131,33 +131,33 @@ struct target_tms { }; struct target_utimbuf { - target_long actime; - target_long modtime; + abi_long actime; + abi_long modtime; }; struct target_sel_arg_struct { - target_long n; - target_long inp, outp, exp; - target_long tvp; + abi_long n; + abi_long inp, outp, exp; + abi_long tvp; }; struct target_iovec { - target_long iov_base; /* Starting address */ - target_long iov_len; /* Number of bytes */ + abi_long iov_base; /* Starting address */ + abi_long iov_len; /* Number of bytes */ }; struct target_msghdr { - target_long msg_name; /* Socket name */ - int msg_namelen; /* Length of name */ - target_long msg_iov; /* Data blocks */ - target_long msg_iovlen; /* Number of blocks */ - target_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ - target_long msg_controllen; /* Length of cmsg list */ + abi_long msg_name; /* Socket name */ + int msg_namelen; /* Length of name */ + abi_long msg_iov; /* Data blocks */ + abi_long msg_iovlen; /* Number of blocks */ + abi_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ + abi_long msg_controllen; /* Length of cmsg list */ unsigned int msg_flags; }; struct target_cmsghdr { - target_long cmsg_len; + abi_long cmsg_len; int cmsg_level; int cmsg_type; }; @@ -167,8 +167,8 @@ struct target_cmsghdr { #define TARGET_CMSG_FIRSTHDR(mhdr) \ ((size_t) tswapl((mhdr)->msg_controllen) >= sizeof (struct target_cmsghdr) \ ? (struct target_cmsghdr *) tswapl((mhdr)->msg_control) : (struct target_cmsghdr *) NULL) -#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (target_long) - 1) \ - & (size_t) ~(sizeof (target_long) - 1)) +#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \ + & (size_t) ~(sizeof (abi_long) - 1)) #define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \ + TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr))) #define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len)) @@ -191,20 +191,20 @@ __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cms struct target_rusage { struct target_timeval ru_utime; /* user time used */ struct target_timeval ru_stime; /* system time used */ - target_long ru_maxrss; /* maximum resident set size */ - target_long ru_ixrss; /* integral shared memory size */ - target_long ru_idrss; /* integral unshared data size */ - target_long ru_isrss; /* integral unshared stack size */ - target_long ru_minflt; /* page reclaims */ - target_long ru_majflt; /* page faults */ - target_long ru_nswap; /* swaps */ - target_long ru_inblock; /* block input operations */ - target_long ru_oublock; /* block output operations */ - target_long ru_msgsnd; /* messages sent */ - target_long ru_msgrcv; /* messages received */ - target_long ru_nsignals; /* signals received */ - target_long ru_nvcsw; /* voluntary context switches */ - target_long ru_nivcsw; /* involuntary " */ + abi_long ru_maxrss; /* maximum resident set size */ + abi_long ru_ixrss; /* integral shared memory size */ + abi_long ru_idrss; /* integral unshared data size */ + abi_long ru_isrss; /* integral unshared stack size */ + abi_long ru_minflt; /* page reclaims */ + abi_long ru_majflt; /* page faults */ + abi_long ru_nswap; /* swaps */ + abi_long ru_inblock; /* block input operations */ + abi_long ru_oublock; /* block output operations */ + abi_long ru_msgsnd; /* messages sent */ + abi_long ru_msgrcv; /* messages received */ + abi_long ru_nsignals; /* signals received */ + abi_long ru_nvcsw; /* voluntary context switches */ + abi_long ru_nivcsw; /* involuntary " */ }; typedef struct { @@ -225,8 +225,8 @@ struct kernel_statfs { }; struct target_dirent { - target_long d_ino; - target_long d_off; + abi_long d_ino; + abi_long d_off; unsigned short d_reclen; char d_name[256]; /* We must not include limits.h! */ }; @@ -241,20 +241,20 @@ struct target_dirent64 { /* mostly generic signal stuff */ -#define TARGET_SIG_DFL ((target_long)0) /* default signal handling */ -#define TARGET_SIG_IGN ((target_long)1) /* ignore signal */ -#define TARGET_SIG_ERR ((target_long)-1) /* error return from signal */ +#define TARGET_SIG_DFL ((abi_long)0) /* default signal handling */ +#define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */ +#define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */ #ifdef TARGET_MIPS #define TARGET_NSIG 128 #else #define TARGET_NSIG 64 #endif -#define TARGET_NSIG_BPW TARGET_LONG_BITS +#define TARGET_NSIG_BPW TARGET_ABI_BITS #define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) typedef struct { - target_ulong sig[TARGET_NSIG_WORDS]; + abi_ulong sig[TARGET_NSIG_WORDS]; } target_sigset_t; #ifdef BSWAP_NEEDED @@ -271,7 +271,7 @@ static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s) } #endif -static inline void target_siginitset(target_sigset_t *d, target_ulong set) +static inline void target_siginitset(target_sigset_t *d, abi_ulong set) { int i; d->sig[0] = set; @@ -281,10 +281,10 @@ static inline void target_siginitset(target_sigset_t *d, target_ulong set) void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); void target_to_host_sigset(sigset_t *d, const target_sigset_t *s); -void host_to_target_old_sigset(target_ulong *old_sigset, +void host_to_target_old_sigset(abi_ulong *old_sigset, const sigset_t *sigset); void target_to_host_old_sigset(sigset_t *sigset, - const target_ulong *old_sigset); + const abi_ulong *old_sigset); struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); @@ -453,40 +453,40 @@ struct target_sigaction { #if defined(TARGET_MIPSN32) uint32_t _sa_handler; #else - target_ulong _sa_handler; + abi_ulong _sa_handler; #endif target_sigset_t sa_mask; }; #else struct target_old_sigaction { - target_ulong _sa_handler; - target_ulong sa_mask; - target_ulong sa_flags; - target_ulong sa_restorer; + abi_ulong _sa_handler; + abi_ulong sa_mask; + abi_ulong sa_flags; + abi_ulong sa_restorer; }; struct target_sigaction { - target_ulong _sa_handler; - target_ulong sa_flags; - target_ulong sa_restorer; + abi_ulong _sa_handler; + abi_ulong sa_flags; + abi_ulong sa_restorer; target_sigset_t sa_mask; }; #endif typedef union target_sigval { int sival_int; - target_ulong sival_ptr; + abi_ulong sival_ptr; } target_sigval_t; #if 0 #if defined (TARGET_SPARC) typedef struct { struct { - target_ulong psr; - target_ulong pc; - target_ulong npc; - target_ulong y; - target_ulong u_regs[16]; /* globals and ins */ + abi_ulong psr; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong u_regs[16]; /* globals and ins */ } si_regs; int si_mask; } __siginfo_t; @@ -544,7 +544,7 @@ typedef struct target_siginfo { /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ struct { - target_ulong _addr; /* faulting insn/memory ref. */ + abi_ulong _addr; /* faulting insn/memory ref. */ } _sigfault; /* SIGPOLL */ @@ -614,8 +614,8 @@ typedef struct target_siginfo { #endif /* defined(TARGET_I386) || defined(TARGET_ARM) */ struct target_rlimit { - target_ulong rlim_cur; - target_ulong rlim_max; + abi_ulong rlim_cur; + abi_ulong rlim_max; }; struct target_pollfd { @@ -888,24 +888,24 @@ struct target_winsize { struct target_stat { unsigned short st_dev; unsigned short __pad1; - target_ulong st_ino; + abi_ulong st_ino; unsigned short st_mode; unsigned short st_nlink; unsigned short st_uid; unsigned short st_gid; unsigned short st_rdev; unsigned short __pad2; - target_ulong st_size; - target_ulong st_blksize; - target_ulong st_blocks; - target_ulong target_st_atime; - target_ulong __unused1; - target_ulong target_st_mtime; - target_ulong __unused2; - target_ulong target_st_ctime; - target_ulong __unused3; - target_ulong __unused4; - target_ulong __unused5; + abi_ulong st_size; + abi_ulong st_blksize; + abi_ulong st_blocks; + abi_ulong target_st_atime; + abi_ulong __unused1; + abi_ulong target_st_mtime; + abi_ulong __unused2; + abi_ulong target_st_ctime; + abi_ulong __unused3; + abi_ulong __unused4; + abi_ulong __unused5; }; /* This matches struct stat64 in glibc2.1, hence the absolutely @@ -916,31 +916,31 @@ struct target_stat64 { unsigned char __pad0[10]; #define TARGET_STAT64_HAS_BROKEN_ST_INO 1 - target_ulong __st_ino; + abi_ulong __st_ino; unsigned int st_mode; unsigned int st_nlink; - target_ulong st_uid; - target_ulong st_gid; + abi_ulong st_uid; + abi_ulong st_gid; unsigned short st_rdev; unsigned char __pad3[10]; long long st_size; - target_ulong st_blksize; + abi_ulong st_blksize; - target_ulong st_blocks; /* Number 512-byte blocks allocated. */ - target_ulong __pad4; /* future possible st_blocks high bits */ + abi_ulong st_blocks; /* Number 512-byte blocks allocated. */ + abi_ulong __pad4; /* future possible st_blocks high bits */ - target_ulong target_st_atime; - target_ulong __pad5; + abi_ulong target_st_atime; + abi_ulong __pad5; - target_ulong target_st_mtime; - target_ulong __pad6; + abi_ulong target_st_mtime; + abi_ulong __pad6; - target_ulong target_st_ctime; - target_ulong __pad7; /* will be high 32 bits of ctime someday */ + abi_ulong target_st_ctime; + abi_ulong __pad7; /* will be high 32 bits of ctime someday */ unsigned long long st_ino; } __attribute__((packed)); @@ -949,50 +949,50 @@ struct target_stat64 { struct target_eabi_stat64 { unsigned long long st_dev; unsigned int __pad1; - target_ulong __st_ino; + abi_ulong __st_ino; unsigned int st_mode; unsigned int st_nlink; - target_ulong st_uid; - target_ulong st_gid; + abi_ulong st_uid; + abi_ulong st_gid; unsigned long long st_rdev; unsigned int __pad2[2]; long long st_size; - target_ulong st_blksize; + abi_ulong st_blksize; unsigned int __pad3; unsigned long long st_blocks; - target_ulong target_st_atime; - target_ulong target_st_atime_nsec; + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; - target_ulong target_st_mtime; - target_ulong target_st_mtime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; - target_ulong target_st_ctime; - target_ulong target_st_ctime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; unsigned long long st_ino; } __attribute__ ((packed)); #endif -#elif defined(TARGET_SPARC64) +#elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32) struct target_stat { unsigned int st_dev; - target_ulong st_ino; + abi_ulong st_ino; unsigned int st_mode; unsigned int st_nlink; unsigned int st_uid; unsigned int st_gid; unsigned int st_rdev; - target_long st_size; - target_long target_st_atime; - target_long target_st_mtime; - target_long target_st_ctime; - target_long st_blksize; - target_long st_blocks; - target_ulong __unused4[2]; + abi_long st_size; + abi_long target_st_atime; + abi_long target_st_mtime; + abi_long target_st_ctime; + abi_long st_blksize; + abi_long st_blocks; + abi_ulong __unused4[2]; }; struct target_stat64 { @@ -1016,38 +1016,38 @@ struct target_stat64 { unsigned char __pad4[4]; unsigned int st_blocks; - target_ulong target_st_atime; - target_ulong __unused1; + abi_ulong target_st_atime; + abi_ulong __unused1; - target_ulong target_st_mtime; - target_ulong __unused2; + abi_ulong target_st_mtime; + abi_ulong __unused2; - target_ulong target_st_ctime; - target_ulong __unused3; + abi_ulong target_st_ctime; + abi_ulong __unused3; - target_ulong __unused4[3]; + abi_ulong __unused4[3]; }; #elif defined(TARGET_SPARC) struct target_stat { unsigned short st_dev; - target_ulong st_ino; + abi_ulong st_ino; unsigned short st_mode; short st_nlink; unsigned short st_uid; unsigned short st_gid; unsigned short st_rdev; - target_long st_size; - target_long target_st_atime; - target_ulong __unused1; - target_long target_st_mtime; - target_ulong __unused2; - target_long target_st_ctime; - target_ulong __unused3; - target_long st_blksize; - target_long st_blocks; - target_ulong __unused4[2]; + abi_long st_size; + abi_long target_st_atime; + abi_ulong __unused1; + abi_long target_st_mtime; + abi_ulong __unused2; + abi_long target_st_ctime; + abi_ulong __unused3; + abi_long st_blksize; + abi_long st_blocks; + abi_ulong __unused4[2]; }; struct target_stat64 { @@ -1090,23 +1090,23 @@ struct target_stat64 { struct target_stat { unsigned short st_dev; - target_ulong st_ino; + abi_ulong st_ino; unsigned int st_mode; unsigned short st_nlink; unsigned int st_uid; unsigned int st_gid; unsigned short st_rdev; - target_ulong st_size; - target_ulong st_blksize; - target_ulong st_blocks; - target_ulong target_st_atime; - target_ulong __unused1; - target_ulong target_st_mtime; - target_ulong __unused2; - target_ulong target_st_ctime; - target_ulong __unused3; - target_ulong __unused4; - target_ulong __unused5; + abi_ulong st_size; + abi_ulong st_blksize; + abi_ulong st_blocks; + abi_ulong target_st_atime; + abi_ulong __unused1; + abi_ulong target_st_mtime; + abi_ulong __unused2; + abi_ulong target_st_ctime; + abi_ulong __unused3; + abi_ulong __unused4; + abi_ulong __unused5; }; struct target_stat64 { @@ -1119,17 +1119,17 @@ struct target_stat64 { unsigned long long st_rdev; long long pad0; long long st_size; - target_ulong st_blksize; - target_ulong pad1; + abi_ulong st_blksize; + abi_ulong pad1; long long st_blocks; /* Number 512-byte blocks allocated. */ - target_ulong target_st_atime; - target_ulong target_st_atime_nsec; - target_ulong target_st_mtime; - target_ulong target_st_mtime_nsec; - target_ulong target_st_ctime; - target_ulong target_st_ctime_nsec; - target_ulong __unused4; - target_ulong __unused5; + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; + abi_ulong __unused4; + abi_ulong __unused5; }; #elif defined(TARGET_M68K) @@ -1137,24 +1137,24 @@ struct target_stat64 { struct target_stat { unsigned short st_dev; unsigned short __pad1; - target_ulong st_ino; + abi_ulong st_ino; unsigned short st_mode; unsigned short st_nlink; unsigned short st_uid; unsigned short st_gid; unsigned short st_rdev; unsigned short __pad2; - target_ulong st_size; - target_ulong st_blksize; - target_ulong st_blocks; - target_ulong target_st_atime; - target_ulong __unused1; - target_ulong target_st_mtime; - target_ulong __unused2; - target_ulong target_st_ctime; - target_ulong __unused3; - target_ulong __unused4; - target_ulong __unused5; + abi_ulong st_size; + abi_ulong st_blksize; + abi_ulong st_blocks; + abi_ulong target_st_atime; + abi_ulong __unused1; + abi_ulong target_st_mtime; + abi_ulong __unused2; + abi_ulong target_st_ctime; + abi_ulong __unused3; + abi_ulong __unused4; + abi_ulong __unused5; }; /* This matches struct stat64 in glibc2.1, hence the absolutely @@ -1165,31 +1165,31 @@ struct target_stat64 { unsigned char __pad1[2]; #define TARGET_STAT64_HAS_BROKEN_ST_INO 1 - target_ulong __st_ino; + abi_ulong __st_ino; unsigned int st_mode; unsigned int st_nlink; - target_ulong st_uid; - target_ulong st_gid; + abi_ulong st_uid; + abi_ulong st_gid; unsigned long long st_rdev; unsigned char __pad3[2]; long long st_size; - target_ulong st_blksize; + abi_ulong st_blksize; - target_ulong __pad4; /* future possible st_blocks high bits */ - target_ulong st_blocks; /* Number 512-byte blocks allocated. */ + abi_ulong __pad4; /* future possible st_blocks high bits */ + abi_ulong st_blocks; /* Number 512-byte blocks allocated. */ - target_ulong target_st_atime; - target_ulong target_st_atime_nsec; + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; - target_ulong target_st_mtime; - target_ulong target_st_mtime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; - target_ulong target_st_ctime; - target_ulong target_st_ctime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; unsigned long long st_ino; } __attribute__((packed)); @@ -1201,7 +1201,7 @@ struct target_stat { unsigned int st_dev; unsigned int st_pad0[3]; /* Reserved for st_dev expansion */ - target_ulong st_ino; + abi_ulong st_ino; unsigned int st_mode; unsigned int st_nlink; @@ -1212,7 +1212,7 @@ struct target_stat { unsigned int st_rdev; unsigned int st_pad1[3]; /* Reserved for st_rdev expansion */ - target_ulong st_size; + abi_ulong st_size; /* * Actually this should be timestruc_t st_atime, st_mtime and st_ctime @@ -1230,7 +1230,7 @@ struct target_stat { unsigned int st_blksize; unsigned int st_pad2; - target_ulong st_blocks; + abi_ulong st_blocks; }; #elif defined(TARGET_MIPSN32) @@ -1308,29 +1308,29 @@ struct target_stat64 { struct target_stat { unsigned st_dev; - target_long st_pad1[3]; /* Reserved for network id */ - target_ulong st_ino; + abi_long st_pad1[3]; /* Reserved for network id */ + abi_ulong st_ino; unsigned int st_mode; unsigned int st_nlink; int st_uid; int st_gid; unsigned st_rdev; - target_long st_pad2[2]; - target_long st_size; - target_long st_pad3; + abi_long st_pad2[2]; + abi_long st_size; + abi_long st_pad3; /* * Actually this should be timestruc_t st_atime, st_mtime and st_ctime * but we don't have it under Linux. */ - target_long target_st_atime; - target_long target_st_atime_nsec; - target_long target_st_mtime; - target_long target_st_mtime_nsec; - target_long target_st_ctime; - target_long target_st_ctime_nsec; - target_long st_blksize; - target_long st_blocks; - target_long st_pad4[14]; + abi_long target_st_atime; + abi_long target_st_atime_nsec; + abi_long target_st_mtime; + abi_long target_st_mtime_nsec; + abi_long target_st_ctime; + abi_long target_st_ctime_nsec; + abi_long st_blksize; + abi_long st_blocks; + abi_long st_pad4[14]; }; /* @@ -1340,8 +1340,8 @@ struct target_stat { */ struct target_stat64 { - target_ulong st_dev; - target_ulong st_pad0[3]; /* Reserved for st_dev expansion */ + abi_ulong st_dev; + abi_ulong st_pad0[3]; /* Reserved for st_dev expansion */ uint64_t st_ino; @@ -1351,8 +1351,8 @@ struct target_stat64 { int st_uid; int st_gid; - target_ulong st_rdev; - target_ulong st_pad1[3]; /* Reserved for st_rdev expansion */ + abi_ulong st_rdev; + abi_ulong st_pad1[3]; /* Reserved for st_rdev expansion */ int64_t st_size; @@ -1360,17 +1360,17 @@ struct target_stat64 { * Actually this should be timestruc_t st_atime, st_mtime and st_ctime * but we don't have it under Linux. */ - target_long target_st_atime; - target_ulong target_st_atime_nsec; /* Reserved for st_atime expansion */ + abi_long target_st_atime; + abi_ulong target_st_atime_nsec; /* Reserved for st_atime expansion */ - target_long target_st_mtime; - target_ulong target_st_mtime_nsec; /* Reserved for st_mtime expansion */ + abi_long target_st_mtime; + abi_ulong target_st_mtime_nsec; /* Reserved for st_mtime expansion */ - target_long target_st_ctime; - target_ulong target_st_ctime_nsec; /* Reserved for st_ctime expansion */ + abi_long target_st_ctime; + abi_ulong target_st_ctime_nsec; /* Reserved for st_ctime expansion */ - target_ulong st_blksize; - target_ulong st_pad2; + abi_ulong st_blksize; + abi_ulong st_pad2; int64_t st_blocks; }; @@ -1385,10 +1385,10 @@ struct target_stat { unsigned int st_uid; unsigned int st_gid; unsigned int st_rdev; - target_long st_size; - target_ulong target_st_atime; - target_ulong target_st_mtime; - target_ulong target_st_ctime; + abi_long st_size; + abi_ulong target_st_atime; + abi_ulong target_st_mtime; + abi_ulong target_st_ctime; unsigned int st_blksize; unsigned int st_blocks; unsigned int st_flags; @@ -1396,11 +1396,11 @@ struct target_stat { }; struct target_stat64 { - target_ulong st_dev; - target_ulong st_ino; - target_ulong st_rdev; - target_long st_size; - target_ulong st_blocks; + abi_ulong st_dev; + abi_ulong st_ino; + abi_ulong st_rdev; + abi_long st_size; + abi_ulong st_blocks; unsigned int st_mode; unsigned int st_uid; @@ -1409,36 +1409,36 @@ struct target_stat64 { unsigned int st_nlink; unsigned int __pad0; - target_ulong target_st_atime; - target_ulong target_st_atime_nsec; - target_ulong target_st_mtime; - target_ulong target_st_mtime_nsec; - target_ulong target_st_ctime; - target_ulong target_st_ctime_nsec; - target_long __unused[3]; + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; + abi_long __unused[3]; }; #elif defined(TARGET_SH4) struct target_stat { - target_ulong st_dev; - target_ulong st_ino; + abi_ulong st_dev; + abi_ulong st_ino; unsigned short st_mode; unsigned short st_nlink; unsigned short st_uid; unsigned short st_gid; - target_ulong st_rdev; - target_ulong st_size; - target_ulong st_blksize; - target_ulong st_blocks; - target_ulong target_st_atime; - target_ulong target_st_atime_nsec; - target_ulong target_st_mtime; - target_ulong target_st_mtime_nsec; - target_ulong target_st_ctime; - target_ulong target_st_ctime_nsec; - target_ulong __unused4; - target_ulong __unused5; + abi_ulong st_rdev; + abi_ulong st_size; + abi_ulong st_blksize; + abi_ulong st_blocks; + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; + abi_ulong __unused4; + abi_ulong __unused5; }; /* This matches struct stat64 in glibc2.1, hence the absolutely @@ -1449,30 +1449,30 @@ struct target_stat64 { unsigned char __pad0[4]; #define TARGET_STAT64_HAS_BROKEN_ST_INO 1 - target_ulong __st_ino; + abi_ulong __st_ino; unsigned int st_mode; unsigned int st_nlink; - target_ulong st_uid; - target_ulong st_gid; + abi_ulong st_uid; + abi_ulong st_gid; unsigned long long st_rdev; unsigned char __pad3[4]; long long st_size; - target_ulong st_blksize; + abi_ulong st_blksize; unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ - target_ulong target_st_atime; - target_ulong target_st_atime_nsec; + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; - target_ulong target_st_mtime; - target_ulong target_st_mtime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; - target_ulong target_st_ctime; - target_ulong target_st_ctime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; unsigned long long st_ino; }; @@ -1504,19 +1504,19 @@ struct target_statfs { }; #else struct target_statfs { - target_long f_type; - target_long f_bsize; - target_long f_frsize; /* Fragment size - unsupported */ - target_long f_blocks; - target_long f_bfree; - target_long f_files; - target_long f_ffree; - target_long f_bavail; + abi_long f_type; + abi_long f_bsize; + abi_long f_frsize; /* Fragment size - unsupported */ + abi_long f_blocks; + abi_long f_bfree; + abi_long f_files; + abi_long f_ffree; + abi_long f_bavail; /* Linux specials */ target_fsid_t f_fsid; - target_long f_namelen; - target_long f_spare[6]; + abi_long f_namelen; + abi_long f_spare[6]; }; #endif @@ -1688,8 +1688,8 @@ struct target_statfs64 { struct target_flock { short l_type; short l_whence; - target_ulong l_start; - target_ulong l_len; + abi_ulong l_start; + abi_ulong l_len; int l_pid; }; @@ -1856,20 +1856,20 @@ struct target_eabi_flock64 { #define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2) struct target_sysinfo { - target_long uptime; /* Seconds since boot */ - target_ulong loads[3]; /* 1, 5, and 15 minute load averages */ - target_ulong totalram; /* Total usable main memory size */ - target_ulong freeram; /* Available memory size */ - target_ulong sharedram; /* Amount of shared memory */ - target_ulong bufferram; /* Memory used by buffers */ - target_ulong totalswap; /* Total swap space size */ - target_ulong freeswap; /* swap space still available */ + abi_long uptime; /* Seconds since boot */ + abi_ulong loads[3]; /* 1, 5, and 15 minute load averages */ + abi_ulong totalram; /* Total usable main memory size */ + abi_ulong freeram; /* Available memory size */ + abi_ulong sharedram; /* Amount of shared memory */ + abi_ulong bufferram; /* Memory used by buffers */ + abi_ulong totalswap; /* Total swap space size */ + abi_ulong freeswap; /* swap space still available */ unsigned short procs; /* Number of current processes */ unsigned short pad; /* explicit padding for m68k */ - target_ulong totalhigh; /* Total high memory size */ - target_ulong freehigh; /* Available high memory size */ + abi_ulong totalhigh; /* Total high memory size */ + abi_ulong freehigh; /* Available high memory size */ unsigned int mem_unit; /* Memory unit size in bytes */ - char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */ + char _f[20-2*sizeof(abi_long)-sizeof(int)]; /* Padding: libc5 uses this.. */ }; #include "socket.h" diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 9639114fc..a3c92e1cc 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -381,7 +381,7 @@ void handle_vm86_fault(CPUX86State *env) } } -int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) +int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr) { TaskState *ts = env->opaque; struct target_vm86plus_struct * target_v86; diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h index 2f87dc964..cdba432bf 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/syscall.h @@ -2,30 +2,30 @@ #define __USER_DS (0x2B) struct target_pt_regs { - target_ulong r15; - target_ulong r14; - target_ulong r13; - target_ulong r12; - target_ulong rbp; - target_ulong rbx; + abi_ulong r15; + abi_ulong r14; + abi_ulong r13; + abi_ulong r12; + abi_ulong rbp; + abi_ulong rbx; /* arguments: non interrupts/non tracing syscalls only save upto here*/ - target_ulong r11; - target_ulong r10; - target_ulong r9; - target_ulong r8; - target_ulong rax; - target_ulong rcx; - target_ulong rdx; - target_ulong rsi; - target_ulong rdi; - target_ulong orig_rax; + abi_ulong r11; + abi_ulong r10; + abi_ulong r9; + abi_ulong r8; + abi_ulong rax; + abi_ulong rcx; + abi_ulong rdx; + abi_ulong rsi; + abi_ulong rdi; + abi_ulong orig_rax; /* end of arguments */ /* cpu exception frame or undefined */ - target_ulong rip; - target_ulong cs; - target_ulong eflags; - target_ulong rsp; - target_ulong ss; + abi_ulong rip; + abi_ulong cs; + abi_ulong eflags; + abi_ulong rsp; + abi_ulong ss; /* top of stack page */ }; @@ -41,7 +41,7 @@ struct target_pt_regs { #if 0 // Redefine this struct target_modify_ldt_ldt_s { unsigned int entry_number; - target_ulong base_addr; + abi_ulong base_addr; unsigned int limit; unsigned int seg_32bit:1; unsigned int contents:2; @@ -54,7 +54,7 @@ struct target_modify_ldt_ldt_s { #else struct target_modify_ldt_ldt_s { unsigned int entry_number; - target_ulong base_addr; + abi_ulong base_addr; unsigned int limit; unsigned int flags; }; @@ -71,8 +71,8 @@ struct target_ipc64_perm unsigned short __pad1; unsigned short seq; unsigned short __pad2; - target_ulong __unused1; - target_ulong __unused2; + abi_ulong __unused1; + abi_ulong __unused2; }; struct target_msqid64_ds { @@ -80,13 +80,13 @@ struct target_msqid64_ds { unsigned int msg_stime; /* last msgsnd time */ unsigned int msg_rtime; /* last msgrcv time */ unsigned int msg_ctime; /* last change time */ - target_ulong msg_cbytes; /* current number of bytes on queue */ - target_ulong msg_qnum; /* number of messages in queue */ - target_ulong msg_qbytes; /* max number of bytes on queue */ + abi_ulong msg_cbytes; /* current number of bytes on queue */ + abi_ulong msg_qnum; /* number of messages in queue */ + abi_ulong msg_qbytes; /* max number of bytes on queue */ unsigned int msg_lspid; /* pid of last msgsnd */ unsigned int msg_lrpid; /* last receive pid */ - target_ulong __unused4; - target_ulong __unused5; + abi_ulong __unused4; + abi_ulong __unused5; }; #define UNAME_MACHINE "x86_64" diff --git a/linux-user/x86_64/target_signal.h b/linux-user/x86_64/target_signal.h index f93a8d62b..9baf7fbeb 100644 --- a/linux-user/x86_64/target_signal.h +++ b/linux-user/x86_64/target_signal.h @@ -6,9 +6,9 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - target_ulong ss_sp; - target_long ss_flags; - target_ulong ss_size; + abi_ulong ss_sp; + abi_long ss_flags; + abi_ulong ss_size; } target_stack_t; @@ -21,7 +21,7 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 -static inline target_ulong get_sp_from_cpustate(CPUX86State *state) +static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) { return state->regs[R_ESP]; } diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index c0cf043b3..96ad71683 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -1,20 +1,26 @@ +#ifdef TARGET_ABI32 +#define ADDR(x) ((x) & 0xffffffff) +#else +#define ADDR(x) (x) +#endif + /*** Integer load ***/ #define SPARC_LD_OP(name, qp) \ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ { \ - T1 = (target_ulong)glue(qp, MEMSUFFIX)(T0); \ + T1 = (target_ulong)glue(qp, MEMSUFFIX)(ADDR(T0)); \ } #define SPARC_LD_OP_S(name, qp) \ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ { \ - T1 = (target_long)glue(qp, MEMSUFFIX)(T0); \ + T1 = (target_long)glue(qp, MEMSUFFIX)(ADDR(T0)); \ } #define SPARC_ST_OP(name, op) \ void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \ { \ - glue(op, MEMSUFFIX)(T0, T1); \ + glue(op, MEMSUFFIX)(ADDR(T0), T1); \ } SPARC_LD_OP(ld, ldl); @@ -30,60 +36,60 @@ SPARC_ST_OP(sth, stw); void OPPROTO glue(op_std, MEMSUFFIX)(void) { - glue(stl, MEMSUFFIX)(T0, T1); - glue(stl, MEMSUFFIX)((T0 + 4), T2); + glue(stl, MEMSUFFIX)(ADDR(T0), T1); + glue(stl, MEMSUFFIX)((ADDR(T0 + 4)), T2); } void OPPROTO glue(op_ldstub, MEMSUFFIX)(void) { - T1 = glue(ldub, MEMSUFFIX)(T0); - glue(stb, MEMSUFFIX)(T0, 0xff); /* XXX: Should be Atomically */ + T1 = glue(ldub, MEMSUFFIX)(ADDR(T0)); + glue(stb, MEMSUFFIX)(ADDR(T0), 0xff); /* XXX: Should be Atomically */ } void OPPROTO glue(op_swap, MEMSUFFIX)(void) { - target_ulong tmp = glue(ldl, MEMSUFFIX)(T0); - glue(stl, MEMSUFFIX)(T0, T1); /* XXX: Should be Atomically */ + target_ulong tmp = glue(ldl, MEMSUFFIX)(ADDR(T0)); + glue(stl, MEMSUFFIX)(ADDR(T0), T1); /* XXX: Should be Atomically */ T1 = tmp; } void OPPROTO glue(op_ldd, MEMSUFFIX)(void) { - T1 = glue(ldl, MEMSUFFIX)(T0); - T0 = glue(ldl, MEMSUFFIX)((T0 + 4)); + T1 = glue(ldl, MEMSUFFIX)(ADDR(T0)); + T0 = glue(ldl, MEMSUFFIX)((ADDR(T0 + 4))); } /*** Floating-point store ***/ void OPPROTO glue(op_stf, MEMSUFFIX) (void) { - glue(stfl, MEMSUFFIX)(T0, FT0); + glue(stfl, MEMSUFFIX)(ADDR(T0), FT0); } void OPPROTO glue(op_stdf, MEMSUFFIX) (void) { - glue(stfq, MEMSUFFIX)(T0, DT0); + glue(stfq, MEMSUFFIX)(ADDR(T0), DT0); } /*** Floating-point load ***/ void OPPROTO glue(op_ldf, MEMSUFFIX) (void) { - FT0 = glue(ldfl, MEMSUFFIX)(T0); + FT0 = glue(ldfl, MEMSUFFIX)(ADDR(T0)); } void OPPROTO glue(op_lddf, MEMSUFFIX) (void) { - DT0 = glue(ldfq, MEMSUFFIX)(T0); + DT0 = glue(ldfq, MEMSUFFIX)(ADDR(T0)); } #ifdef TARGET_SPARC64 void OPPROTO glue(op_lduw, MEMSUFFIX)(void) { - T1 = (uint64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff); + T1 = (uint64_t)(glue(ldl, MEMSUFFIX)(ADDR(T0)) & 0xffffffff); } void OPPROTO glue(op_ldsw, MEMSUFFIX)(void) { - T1 = (int64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff); + T1 = (int64_t)(glue(ldl, MEMSUFFIX)(ADDR(T0)) & 0xffffffff); } SPARC_LD_OP(ldx, ldq); diff --git a/thunk.c b/thunk.c index dbeb2b1fc..0347d6d04 100644 --- a/thunk.c +++ b/thunk.c @@ -136,13 +136,13 @@ const argtype *thunk_convert(void *dst, const void *src, case TYPE_ULONGLONG: *(uint64_t *)dst = tswap64(*(uint64_t *)src); break; -#if HOST_LONG_BITS == 32 && TARGET_LONG_BITS == 32 +#if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32 case TYPE_LONG: case TYPE_ULONG: case TYPE_PTRVOID: *(uint32_t *)dst = tswap32(*(uint32_t *)src); break; -#elif HOST_LONG_BITS == 64 && TARGET_LONG_BITS == 32 +#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32 case TYPE_LONG: case TYPE_ULONG: case TYPE_PTRVOID: diff --git a/thunk.h b/thunk.h index 7811df397..4bf256a00 100644 --- a/thunk.h +++ b/thunk.h @@ -98,7 +98,7 @@ static inline int thunk_type_size(const argtype *type_ptr, int is_host) if (is_host) { return HOST_LONG_SIZE; } else { - return TARGET_LONG_SIZE; + return TARGET_ABI_BITS / 8; } break; case TYPE_ARRAY: @@ -135,7 +135,7 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host) if (is_host) { return HOST_LONG_SIZE; } else { - return TARGET_LONG_SIZE; + return TARGET_ABI_BITS / 8; } break; case TYPE_ARRAY: -- cgit v1.2.3 From 952a328ff50c323b28fb07658ccbc6604cf26a45 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 14 Oct 2007 16:29:21 +0000 Subject: SuperSparc MXCC support (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3397 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 2 +- hw/sun4u.c | 2 +- linux-user/main.c | 2 +- target-sparc/cpu.h | 5 +- target-sparc/op_helper.c | 167 ++++++++++++++++++++++++++++++++++++++++++----- target-sparc/translate.c | 3 +- 6 files changed, 160 insertions(+), 21 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index 1d9f76605..a12aec9e8 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -327,7 +327,7 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, for(i = 0; i < smp_cpus; i++) { env = cpu_init(); - cpu_sparc_register(env, def); + cpu_sparc_register(env, def, i); envs[i] = env; if (i == 0) { qemu_register_reset(main_cpu_reset, env); diff --git a/hw/sun4u.c b/hw/sun4u.c index 3b0834053..bac0ebf46 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -358,7 +358,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, exit(1); } env = cpu_init(); - cpu_sparc_register(env, def); + cpu_sparc_register(env, def, 0); bh = qemu_bh_new(tick_irq, env); env->tick = ptimer_init(bh); ptimer_set_period(env->tick, 1ULL); diff --git a/linux-user/main.c b/linux-user/main.c index ac5a63bb5..1388d4833 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2142,7 +2142,7 @@ int main(int argc, char **argv) fprintf(stderr, "Unable to find Sparc CPU definition\n"); exit(1); } - cpu_sparc_register(env, def); + cpu_sparc_register(env, def, 0); env->pc = regs->pc; env->npc = regs->npc; env->y = regs->y; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 30e1d827d..e9699cfdc 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -212,6 +212,8 @@ typedef struct CPUSPARCState { uint64_t dtlb_tte[64]; #else uint32_t mmuregs[16]; + uint64_t mxccdata[4]; + uint64_t mxccregs[8]; #endif /* temporary float registers */ float32 ft0, ft1; @@ -268,7 +270,8 @@ int cpu_sparc_close(CPUSPARCState *s); int sparc_find_by_name (const unsigned char *name, const sparc_def_t **def); void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def); +int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def, + unsigned int cpu); #define GET_PSR(env) (env->version | (env->psr & PSR_ICC) | \ (env->psref? PSR_EF : 0) | \ diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 6d08e1c65..ac88b55d5 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -2,9 +2,24 @@ //#define DEBUG_PCALL //#define DEBUG_MMU +//#define DEBUG_MXCC //#define DEBUG_UNALIGNED //#define DEBUG_UNASSIGNED +#ifdef DEBUG_MMU +#define DPRINTF_MMU(fmt, args...) \ +do { printf("MMU: " fmt , ##args); } while (0) +#else +#define DPRINTF_MMU(fmt, args...) +#endif + +#ifdef DEBUG_MXCC +#define DPRINTF_MXCC(fmt, args...) \ +do { printf("MXCC: " fmt , ##args); } while (0) +#else +#define DPRINTF_MXCC(fmt, args...) +#endif + void raise_exception(int tt) { env->exception_index = tt; @@ -139,12 +154,58 @@ GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); #ifndef TARGET_SPARC64 #ifndef CONFIG_USER_ONLY + +#ifdef DEBUG_MXCC +static void dump_mxcc(CPUState *env) +{ + printf("mxccdata: %016llx %016llx %016llx %016llx\n", + env->mxccdata[0], env->mxccdata[1], env->mxccdata[2], env->mxccdata[3]); + printf("mxccregs: %016llx %016llx %016llx %016llx\n" + " %016llx %016llx %016llx %016llx\n", + env->mxccregs[0], env->mxccregs[1], env->mxccregs[2], env->mxccregs[3], + env->mxccregs[4], env->mxccregs[5], env->mxccregs[6], env->mxccregs[7]); +} +#endif + void helper_ld_asi(int asi, int size, int sign) { uint32_t ret = 0; +#ifdef DEBUG_MXCC + uint32_t last_T0 = T0; +#endif switch (asi) { case 2: /* SuperSparc MXCC registers */ + switch (T0) { + case 0x01c00a00: /* MXCC control register */ + if (size == 8) { + ret = env->mxccregs[3]; + T0 = env->mxccregs[3] >> 32; + } else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + case 0x01c00a04: /* MXCC control register */ + if (size == 4) + ret = env->mxccregs[3]; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + case 0x01c00f00: /* MBus port address register */ + if (size == 8) { + ret = env->mxccregs[7]; + T0 = env->mxccregs[7] >> 32; + } else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + default: + DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", T0, size); + break; + } + DPRINTF_MXCC("asi = %d, size = %d, sign = %d, T0 = %08x -> ret = %08x," + "T0 = %08x\n", asi, size, sign, last_T0, ret, T0); +#ifdef DEBUG_MXCC + dump_mxcc(env); +#endif break; case 3: /* MMU probe */ { @@ -157,9 +218,7 @@ void helper_ld_asi(int asi, int size, int sign) ret = mmu_probe(env, T0, mmulev); //bswap32s(&ret); } -#ifdef DEBUG_MMU - printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); -#endif + DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); } break; case 4: /* read MMU regs */ @@ -169,9 +228,7 @@ void helper_ld_asi(int asi, int size, int sign) ret = env->mmuregs[reg]; if (reg == 3) /* Fault status cleared on read */ env->mmuregs[reg] = 0; -#ifdef DEBUG_MMU - printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret); -#endif + DPRINTF_MMU("mmu_read: reg[%d] = 0x%08x\n", reg, ret); } break; case 9: /* Supervisor code access */ @@ -302,15 +359,93 @@ void helper_st_asi(int asi, int size) { switch(asi) { case 2: /* SuperSparc MXCC registers */ + switch (T0) { + case 0x01c00000: /* MXCC stream data register 0 */ + if (size == 8) + env->mxccdata[0] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + case 0x01c00008: /* MXCC stream data register 1 */ + if (size == 8) + env->mxccdata[1] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + case 0x01c00010: /* MXCC stream data register 2 */ + if (size == 8) + env->mxccdata[2] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + case 0x01c00018: /* MXCC stream data register 3 */ + if (size == 8) + env->mxccdata[3] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + case 0x01c00100: /* MXCC stream source */ + if (size == 8) + env->mxccregs[0] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 0); + env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 8); + env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 16); + env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 24); + break; + case 0x01c00200: /* MXCC stream destination */ + if (size == 8) + env->mxccregs[1] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, env->mxccdata[0]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, env->mxccdata[1]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, env->mxccdata[2]); + stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24, env->mxccdata[3]); + break; + case 0x01c00a00: /* MXCC control register */ + if (size == 8) + env->mxccregs[3] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + case 0x01c00a04: /* MXCC control register */ + if (size == 4) + env->mxccregs[3] = (env->mxccregs[0xa] & 0xffffffff00000000) | T1; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + case 0x01c00e00: /* MXCC error register */ + if (size == 8) + env->mxccregs[6] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + if (env->mxccregs[6] == 0xffffffffffffffffULL) { + // this is probably a reset + } + break; + case 0x01c00f00: /* MBus port address register */ + if (size == 8) + env->mxccregs[7] = ((uint64_t)T1 << 32) | T2; + else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; + default: + DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", T0, size); + break; + } + DPRINTF_MXCC("asi = %d, size = %d, T0 = %08x, T1 = %08x\n", asi, size, T0, T1); +#ifdef DEBUG_MXCC + dump_mxcc(env); +#endif break; case 3: /* MMU flush */ { int mmulev; mmulev = (T0 >> 8) & 15; -#ifdef DEBUG_MMU - printf("mmu flush level %d\n", mmulev); -#endif + DPRINTF_MMU("mmu flush level %d\n", mmulev); switch (mmulev) { case 0: // flush page tlb_flush_page(env, T0 & 0xfffff000); @@ -359,10 +494,10 @@ void helper_st_asi(int asi, int size) env->mmuregs[reg] = T1; break; } -#ifdef DEBUG_MMU if (oldreg != env->mmuregs[reg]) { - printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); + DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); } +#ifdef DEBUG_MMU dump_mmu(env); #endif return; @@ -962,8 +1097,8 @@ void helper_st_asi(int asi, int size) // Mappings generated during D/I MMU disabled mode are // invalid in normal mode if (oldreg != env->lsu) { + DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu); #ifdef DEBUG_MMU - printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu); dump_mmu(env); #endif tlb_flush(env, 1); @@ -995,10 +1130,10 @@ void helper_st_asi(int asi, int size) break; } env->immuregs[reg] = T1; -#ifdef DEBUG_MMU if (oldreg != env->immuregs[reg]) { - printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]); + DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]); } +#ifdef DEBUG_MMU dump_mmu(env); #endif return; @@ -1064,10 +1199,10 @@ void helper_st_asi(int asi, int size) break; } env->dmmuregs[reg] = T1; -#ifdef DEBUG_MMU if (oldreg != env->dmmuregs[reg]) { - printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); + DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); } +#ifdef DEBUG_MMU dump_mmu(env); #endif return; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 3027bb8af..046dc0b2e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3618,12 +3618,13 @@ void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) } } -int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def) +int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def, unsigned int cpu) { env->version = def->iu_version; env->fsr = def->fpu_version; #if !defined(TARGET_SPARC64) env->mmuregs[0] |= def->mmu_version; + env->mxccregs[7] = ((cpu + 8) & 0xf) << 24; #endif return 0; } -- cgit v1.2.3 From 6f27aba62e90b382d3d8e35e6d72046470c270a8 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 14 Oct 2007 17:07:21 +0000 Subject: Sparc64 hypervisor mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3398 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 39 +++++++++++++++++-- target-sparc/op.c | 5 +++ target-sparc/op_helper.c | 98 +++++++++++++++++++++++++++++++++--------------- target-sparc/translate.c | 27 +++++++------ 4 files changed, 121 insertions(+), 48 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e9699cfdc..51cbd4c32 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -98,6 +98,8 @@ #define PS_AG (1<<0) #define FPRS_FEF (1<<2) + +#define HS_PRIV (1<<2) #endif /* Fcc */ @@ -166,7 +168,11 @@ typedef struct sparc_def_t sparc_def_t; +#if !defined(TARGET_SPARC64) #define NB_MMU_MODES 2 +#else +#define NB_MMU_MODES 3 +#endif typedef struct CPUSPARCState { target_ulong gregs[8]; /* general registers */ @@ -323,12 +329,37 @@ void cpu_check_irqs(CPUSPARCState *env); #define cpu_list sparc_cpu_list /* MMU modes definitions */ -#define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _user -#define MMU_USER_IDX 1 +#define MMU_MODE0_SUFFIX _user +#define MMU_MODE1_SUFFIX _kernel +#ifdef TARGET_SPARC64 +#define MMU_MODE2_SUFFIX _hypv +#endif +#define MMU_USER_IDX 0 static inline int cpu_mmu_index (CPUState *env) { - return env->psrs == 0 ? 1 : 0; +#if defined(CONFIG_USER_ONLY) + return 0; +#elif !defined(TARGET_SPARC64) + return env->psrs; +#else + if (!env->psrs) + return 0; + else if ((env->hpstate & HS_PRIV) == 0) + return 1; + else + return 2; +#endif +} + +static inline int cpu_fpu_enabled(CPUState *env) +{ +#if defined(CONFIG_USER_ONLY) + return 1; +#elif !defined(TARGET_SPARC64) + return env->psref; +#else + return ((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0); +#endif } #include "cpu-all.h" diff --git a/target-sparc/op.c b/target-sparc/op.c index e12347df1..80864c3bb 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1023,6 +1023,11 @@ void OPPROTO op_sra(void) #define MEMSUFFIX _kernel #include "op_mem.h" + +#ifdef TARGET_SPARC64 +#define MEMSUFFIX _hypv +#include "op_mem.h" +#endif #endif void OPPROTO op_ldfsr(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index ac88b55d5..28c18b403 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -789,7 +789,8 @@ void helper_ld_asi(int asi, int size, int sign) { uint64_t ret = 0; - if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) + || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV)) raise_exception(TT_PRIV_ACT); switch (asi) { @@ -800,20 +801,38 @@ void helper_ld_asi(int asi, int size, int sign) case 0x88: // Primary LE case 0x8a: // Primary no-fault LE if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - switch(size) { - case 1: - ret = ldub_kernel(T0); - break; - case 2: - ret = lduw_kernel(T0 & ~1); - break; - case 4: - ret = ldl_kernel(T0 & ~3); - break; - default: - case 8: - ret = ldq_kernel(T0 & ~7); - break; + if (env->hpstate & HS_PRIV) { + switch(size) { + case 1: + ret = ldub_hypv(T0); + break; + case 2: + ret = lduw_hypv(T0 & ~1); + break; + case 4: + ret = ldl_hypv(T0 & ~3); + break; + default: + case 8: + ret = ldq_hypv(T0 & ~7); + break; + } + } else { + switch(size) { + case 1: + ret = ldub_kernel(T0); + break; + case 2: + ret = lduw_kernel(T0 & ~1); + break; + case 4: + ret = ldl_kernel(T0 & ~3); + break; + default: + case 8: + ret = ldq_kernel(T0 & ~7); + break; + } } } else { switch(size) { @@ -987,7 +1006,8 @@ void helper_ld_asi(int asi, int size, int sign) void helper_st_asi(int asi, int size) { - if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) + || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV)) raise_exception(TT_PRIV_ACT); /* Convert to little endian */ @@ -1022,20 +1042,38 @@ void helper_st_asi(int asi, int size) case 0x80: // Primary case 0x88: // Primary LE if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - switch(size) { - case 1: - stb_kernel(T0, T1); - break; - case 2: - stw_kernel(T0 & ~1, T1); - break; - case 4: - stl_kernel(T0 & ~3, T1); - break; - case 8: - default: - stq_kernel(T0 & ~7, T1); - break; + if (env->hpstate & HS_PRIV) { + switch(size) { + case 1: + stb_hypv(T0, T1); + break; + case 2: + stw_hypv(T0 & ~1, T1); + break; + case 4: + stl_hypv(T0 & ~3, T1); + break; + case 8: + default: + stq_hypv(T0 & ~7, T1); + break; + } + } else { + switch(size) { + case 1: + stb_kernel(T0, T1); + break; + case 2: + stw_kernel(T0 & ~1, T1); + break; + case 4: + stl_kernel(T0 & ~3, T1); + break; + case 8: + default: + stq_kernel(T0 & ~7, T1); + break; + } } } else { switch(size) { diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 046dc0b2e..d0dc51107 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -361,17 +361,24 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); #endif #define gen_op_ldst(name) gen_op_##name##_raw() #else -#define supervisor(dc) (dc->mem_idx == 1) +#define supervisor(dc) (dc->mem_idx >= 1) #ifdef TARGET_SPARC64 #define hypervisor(dc) (dc->mem_idx == 2) -#endif -#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() +#define OP_LD_TABLE(width) \ + static GenOpFunc * const gen_op_##width[] = { \ + &gen_op_##width##_user, \ + &gen_op_##width##_kernel, \ + &gen_op_##width##_hypv, \ + }; +#else #define OP_LD_TABLE(width) \ static GenOpFunc * const gen_op_##width[] = { \ &gen_op_##width##_user, \ &gen_op_##width##_kernel, \ }; #endif +#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() +#endif #ifndef CONFIG_USER_ONLY OP_LD_TABLE(ld); @@ -3378,17 +3385,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, dc->pc = pc_start; last_pc = dc->pc; dc->npc = (target_ulong) tb->cs_base; -#if defined(CONFIG_USER_ONLY) - dc->mem_idx = 0; - dc->fpu_enabled = 1; -#else - dc->mem_idx = ((env->psrs) != 0); -#ifdef TARGET_SPARC64 - dc->fpu_enabled = (((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0)); -#else - dc->fpu_enabled = ((env->psref) != 0); -#endif -#endif + dc->mem_idx = cpu_mmu_index(env); + dc->fpu_enabled = cpu_fpu_enabled(env); gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; @@ -3522,6 +3520,7 @@ void cpu_reset(CPUSPARCState *env) env->psrps = 1; #ifdef TARGET_SPARC64 env->pstate = PS_PRIV; + env->hpstate = HS_PRIV; env->pc = 0x1fff0000000ULL; #else env->pc = 0; -- cgit v1.2.3 From 94ced0753493b1732a212f2435ff6ca776468c10 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 14 Oct 2007 20:27:00 +0000 Subject: Fix bug in Sparc32 sta op (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3399 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 28c18b403..da4c18d2d 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -618,7 +618,7 @@ void helper_st_asi(int asi, int size) stl_phys((target_phys_addr_t)(T0 & ~3) | ((target_phys_addr_t)(asi & 0xf) << 32), T1); stl_phys((target_phys_addr_t)((T0 + 4) & ~3) - | ((target_phys_addr_t)(asi & 0xf) << 32), T1); + | ((target_phys_addr_t)(asi & 0xf) << 32), T2); break; } } -- cgit v1.2.3 From 6bf5b4e8a85a46b5f41eeea0910327608924b382 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Oct 2007 13:08:32 +0000 Subject: MIPSsim pseudo machine emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3400 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 ++- qemu-doc.texi | 15 ++++++++++++++- vl.c | 1 + vl.h | 12 +++++++++--- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Makefile.target b/Makefile.target index f5b6447fa..2a0648a29 100644 --- a/Makefile.target +++ b/Makefile.target @@ -478,11 +478,12 @@ VL_OBJS+= ppc4xx_devs.o ppc405_uc.o ppc405_boards.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif ifeq ($(TARGET_BASE_ARCH), mips) -VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o +VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o mips_mipssim.o VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= jazz_led.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o VL_OBJS+= piix_pci.o smbus_eeprom.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) +VL_OBJS+= mipsnet.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), cris) diff --git a/qemu-doc.texi b/qemu-doc.texi index c3a529ba9..5b534cc9b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2036,6 +2036,8 @@ A generic ISA PC-like machine "mips" The MIPS Malta prototype board "malta" @item An ACER Pica "pica61" +@item +MIPS MIPSsim emulator pseudo board "mipssim" @end itemize The generic emulation is supported by Debian 'Etch' and is able to @@ -2044,7 +2046,7 @@ emulated: @itemize @minus @item -MIPS 24Kf CPU +A range of MIPS CPUs, default is the 24Kf @item PC style serial port @item @@ -2083,6 +2085,17 @@ PC Keyboard IDE controller @end itemize +The MIPSsim emulation supports: + +@itemize @minus +@item +A range of MIPS CPUs, default is the 24Kf +@item +PC style serial port +@item +MIPSnet network emulation +@end itemize + @node ARM System emulator @section ARM System emulator diff --git a/vl.c b/vl.c index 65c3e6a47..6d8fe3542 100644 --- a/vl.c +++ b/vl.c @@ -7365,6 +7365,7 @@ void register_machines(void) qemu_register_machine(&mips_machine); qemu_register_machine(&mips_malta_machine); qemu_register_machine(&mips_pica61_machine); + qemu_register_machine(&mips_mipssim_machine); #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 qemu_register_machine(&sun4u_machine); diff --git a/vl.h b/vl.h index afa2cd6bb..adf6004a7 100644 --- a/vl.h +++ b/vl.h @@ -1068,6 +1068,9 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, qemu_irq irq, qemu_irq *reset); +/* mipsnet.c */ +void mipsnet_init(int base, qemu_irq irq, NICInfo *nd); + /* vmmouse.c */ void *vmmouse_init(void *m); @@ -1190,12 +1193,15 @@ extern QEMUMachine mips_machine; /* mips_malta.c */ extern QEMUMachine mips_malta_machine; -/* mips_int.c */ -extern void cpu_mips_irq_init_cpu(CPUState *env); - /* mips_pica61.c */ extern QEMUMachine mips_pica61_machine; +/* mips_mipssim.c */ +extern QEMUMachine mips_mipssim_machine; + +/* mips_int.c */ +extern void cpu_mips_irq_init_cpu(CPUState *env); + /* mips_timer.c */ extern void cpu_mips_clock_init(CPUState *); extern void cpu_mips_irqctrl_init (void); -- cgit v1.2.3 From f0fc6f8fbc195424af8bb9ca7409748f665d7b07 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Oct 2007 13:39:42 +0000 Subject: Second half of mipssim support, plus documentation improvements. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3401 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_mipssim.c | 167 +++++++++++++++++++++++++++++++++ hw/mipsnet.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-doc.texi | 6 +- 3 files changed, 440 insertions(+), 2 deletions(-) create mode 100644 hw/mips_mipssim.c create mode 100644 hw/mipsnet.c diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c new file mode 100644 index 000000000..6c061636b --- /dev/null +++ b/hw/mips_mipssim.c @@ -0,0 +1,167 @@ +/* + * QEMU/mipssim emulation + * + * Emulates a very simple machine model similiar to the one use by the + * proprietary MIPS emulator. + */ +#include "vl.h" + +#ifdef TARGET_WORDS_BIGENDIAN +#define BIOS_FILENAME "mips_bios.bin" +#else +#define BIOS_FILENAME "mipsel_bios.bin" +#endif + +#ifdef TARGET_MIPS64 +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) +#else +#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) +#endif + +#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) + +static void load_kernel (CPUState *env) +{ + int64_t entry, kernel_low, kernel_high; + long kernel_size; + long initrd_size; + ram_addr_t initrd_offset; + + kernel_size = load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, + &entry, &kernel_low, &kernel_high); + if (kernel_size >= 0) { + if ((entry & ~0x7fffffffULL) == 0x80000000) + entry = (int32_t)entry; + env->PC[env->current_tc] = entry; + } else { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + env->kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + initrd_offset = 0; + if (env->initrd_filename) { + initrd_size = get_image_size (env->initrd_filename); + if (initrd_size > 0) { + initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; + if (initrd_offset + initrd_size > env->ram_size) { + fprintf(stderr, + "qemu: memory too small for initial ram disk '%s'\n", + env->initrd_filename); + exit(1); + } + initrd_size = load_image(env->initrd_filename, + phys_ram_base + initrd_offset); + } + if (initrd_size == (target_ulong) -1) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + env->initrd_filename); + exit(1); + } + } +} + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); + cpu_mips_register(env, NULL); + + if (env->kernel_filename) + load_kernel (env); +} + +static void +mips_mipssim_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + char buf[1024]; + unsigned long bios_offset; + CPUState *env; + int ret; + mips_def_t *def; + + /* Init CPUs. */ + if (cpu_model == NULL) { +#ifdef TARGET_MIPS64 + cpu_model = "5Kf"; +#else + cpu_model = "24Kf"; +#endif + } + if (mips_find_by_name(cpu_model, &def) != 0) + def = NULL; + env = cpu_init(); + cpu_mips_register(env, def); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + qemu_register_reset(main_cpu_reset, env); + + /* Allocate RAM. */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + /* Map the BIOS / boot exception handler. */ + bios_offset = ram_size + vga_ram_size; + + /* Load a BIOS / boot exception handler image. */ + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); + ret = load_image(buf, phys_ram_base + bios_offset); + if ((ret < 0 || ret > BIOS_SIZE) && !kernel_filename) { + /* Bail out if we have neither a kernel image nor boot vector code. */ + fprintf(stderr, + "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", + buf); + exit(1); + } else { + /* We have a boot vector start address. */ + env->PC[env->current_tc] = (target_long)0xbfc00000; + cpu_register_physical_memory(0x1fc00000LL, + ret, bios_offset | IO_MEM_ROM); + } + + if (kernel_filename) { + env->ram_size = ram_size; + env->kernel_filename = kernel_filename; + env->kernel_cmdline = kernel_cmdline; + env->initrd_filename = initrd_filename; + load_kernel(env); + } + + /* Init CPU internal devices. */ + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); + cpu_mips_irqctrl_init(); + + /* Register 64 KB of ISA IO space at 0x1fd00000. */ + isa_mmio_init(0x1fd00000, 0x00010000); + + /* A single 16450 sits at offset 0x3f8. It is attached to + MIPS CPU INT2, which is interrupt 4. */ + if (serial_hds[0]) + serial_init(0x3f8, env->irq[4], serial_hds[0]); + + if (nd_table[0].vlan) { + if (nd_table[0].model == NULL + || strcmp(nd_table[0].model, "mipsnet") == 0) { + /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ + mipsnet_init(0x4200, env->irq[2], &nd_table[0]); + } else if (strcmp(nd_table[0].model, "?") == 0) { + fprintf(stderr, "qemu: Supported NICs: mipsnet\n"); + exit (1); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } + } +} + +QEMUMachine mips_mipssim_machine = { + "mipssim", + "MIPS MIPSsim platform", + mips_mipssim_init, +}; diff --git a/hw/mipsnet.c b/hw/mipsnet.c new file mode 100644 index 000000000..bebfd4d80 --- /dev/null +++ b/hw/mipsnet.c @@ -0,0 +1,269 @@ +#include "vl.h" + +#define DEBUG_MIPSNET_SEND +#define DEBUG_MIPSNET_RECEIVE +//#define DEBUG_MIPSNET_DATA +#define DEBUG_MIPSNET_IRQ + +/* MIPSnet register offsets */ + +#define MIPSNET_DEV_ID 0x00 +# define MIPSNET_DEV_ID_STRING "MIPSNET0" +#define MIPSNET_BUSY 0x08 +#define MIPSNET_RX_DATA_COUNT 0x0c +#define MIPSNET_TX_DATA_COUNT 0x10 +#define MIPSNET_INT_CTL 0x14 +# define MIPSNET_INTCTL_TXDONE 0x00000001 +# define MIPSNET_INTCTL_RXDONE 0x00000002 +# define MIPSNET_INTCTL_TESTBIT 0x80000000 +#define MIPSNET_INTERRUPT_INFO 0x18 +#define MIPSNET_RX_DATA_BUFFER 0x1c +#define MIPSNET_TX_DATA_BUFFER 0x20 + +#define MAX_ETH_FRAME_SIZE 1514 + +typedef struct MIPSnetState { + uint32_t busy; + uint32_t rx_count; + uint32_t rx_read; + uint32_t tx_count; + uint32_t tx_written; + uint32_t intctl; + uint8_t rx_buffer[MAX_ETH_FRAME_SIZE]; + uint8_t tx_buffer[MAX_ETH_FRAME_SIZE]; + qemu_irq irq; + VLANClientState *vc; + NICInfo *nd; +} MIPSnetState; + +static void mipsnet_reset(MIPSnetState *s) +{ + s->busy = 1; + s->rx_count = 0; + s->rx_read = 0; + s->tx_count = 0; + s->tx_written = 0; + s->intctl = 0; + memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE); + memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE); +} + +static void mipsnet_update_irq(MIPSnetState *s) +{ + int isr = !!s->intctl; +#ifdef DEBUG_MIPSNET_IRQ + printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl); +#endif + qemu_set_irq(s->irq, isr); +} + +static int mipsnet_buffer_full(MIPSnetState *s) +{ + if (s->rx_count >= MAX_ETH_FRAME_SIZE) + return 1; + return 0; +} + +static int mipsnet_can_receive(void *opaque) +{ + MIPSnetState *s = opaque; + + if (s->busy) + return 0; + return !mipsnet_buffer_full(s); +} + +static void mipsnet_receive(void *opaque, const uint8_t *buf, int size) +{ + MIPSnetState *s = opaque; + +#ifdef DEBUG_MIPSNET_RECEIVE + printf("mipsnet: receiving len=%d\n", size); +#endif + if (!mipsnet_can_receive(opaque)) + return; + + s->busy = 1; + + /* Just accept everything. */ + + /* Write packet data. */ + memcpy(s->rx_buffer, buf, size); + + s->rx_count = size; + s->rx_read = 0; + + /* Now we can signal we have received something. */ + s->intctl |= MIPSNET_INTCTL_RXDONE; + mipsnet_update_irq(s); +} + +static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr) +{ + MIPSnetState *s = opaque; + int ret = 0; + const char *devid = MIPSNET_DEV_ID_STRING; + + addr &= 0x3f; + switch (addr) { + case MIPSNET_DEV_ID: + ret = *((uint32_t *)&devid); + break; + case MIPSNET_DEV_ID + 4: + ret = *((uint32_t *)(&devid + 4)); + break; + case MIPSNET_BUSY: + ret = s->busy; + break; + case MIPSNET_RX_DATA_COUNT: + ret = s->rx_count; + break; + case MIPSNET_TX_DATA_COUNT: + ret = s->tx_count; + break; + case MIPSNET_INT_CTL: + ret = s->intctl; + s->intctl &= ~MIPSNET_INTCTL_TESTBIT; + break; + case MIPSNET_INTERRUPT_INFO: + /* XXX: This seems to be a per-VPE interrupt number. */ + ret = 0; + break; + case MIPSNET_RX_DATA_BUFFER: + if (s->rx_count) { + s->rx_count--; + ret = s->rx_buffer[s->rx_read++]; + } + break; + /* Reads as zero. */ + case MIPSNET_TX_DATA_BUFFER: + default: + break; + } +#ifdef DEBUG_MIPSNET_DATA + printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret); +#endif + return ret; +} + +static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + MIPSnetState *s = opaque; + + addr &= 0x3f; +#ifdef DEBUG_MIPSNET_DATA + printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val); +#endif + switch (addr) { + case MIPSNET_TX_DATA_COUNT: + s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0; + s->tx_written = 0; + break; + case MIPSNET_INT_CTL: + if (val & MIPSNET_INTCTL_TXDONE) { + s->intctl &= ~MIPSNET_INTCTL_TXDONE; + } else if (val & MIPSNET_INTCTL_RXDONE) { + s->intctl &= ~MIPSNET_INTCTL_RXDONE; + } else if (val & MIPSNET_INTCTL_TESTBIT) { + mipsnet_reset(s); + s->intctl |= MIPSNET_INTCTL_TESTBIT; + } else if (!val) { + /* ACK testbit interrupt, flag was cleared on read. */ + } + s->busy = !!s->intctl; + mipsnet_update_irq(s); + break; + case MIPSNET_TX_DATA_BUFFER: + s->tx_buffer[s->tx_written++] = val; + if (s->tx_written == s->tx_count) { + /* Send buffer. */ +#ifdef DEBUG_MIPSNET_SEND + printf("mipsnet: sending len=%d\n", s->tx_count); +#endif + qemu_send_packet(s->vc, s->tx_buffer, s->tx_count); + s->tx_count = s->tx_written = 0; + s->intctl |= MIPSNET_INTCTL_TXDONE; + s->busy = 1; + mipsnet_update_irq(s); + } + break; + /* Read-only registers */ + case MIPSNET_DEV_ID: + case MIPSNET_BUSY: + case MIPSNET_RX_DATA_COUNT: + case MIPSNET_INTERRUPT_INFO: + case MIPSNET_RX_DATA_BUFFER: + default: + break; + } +} + +static void mipsnet_save(QEMUFile *f, void *opaque) +{ + MIPSnetState *s = opaque; + + qemu_put_be32s(f, &s->busy); + qemu_put_be32s(f, &s->rx_count); + qemu_put_be32s(f, &s->rx_read); + qemu_put_be32s(f, &s->tx_count); + qemu_put_be32s(f, &s->tx_written); + qemu_put_be32s(f, &s->intctl); + qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE); + qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE); +} + +static int mipsnet_load(QEMUFile *f, void *opaque, int version_id) +{ + MIPSnetState *s = opaque; + + if (version_id > 0) + return -EINVAL; + + qemu_get_be32s(f, &s->busy); + qemu_get_be32s(f, &s->rx_count); + qemu_get_be32s(f, &s->rx_read); + qemu_get_be32s(f, &s->tx_count); + qemu_get_be32s(f, &s->tx_written); + qemu_get_be32s(f, &s->intctl); + qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE); + qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE); + + return 0; +} + +void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) +{ + MIPSnetState *s; + + s = qemu_mallocz(sizeof(MIPSnetState)); + if (!s) + return; + + register_ioport_write(base, 36, 1, mipsnet_ioport_write, s); + register_ioport_read(base, 36, 1, mipsnet_ioport_read, s); + register_ioport_write(base, 36, 2, mipsnet_ioport_write, s); + register_ioport_read(base, 36, 2, mipsnet_ioport_read, s); + register_ioport_write(base, 36, 4, mipsnet_ioport_write, s); + register_ioport_read(base, 36, 4, mipsnet_ioport_read, s); + + s->irq = irq; + s->nd = nd; + if (nd && nd->vlan) { + s->vc = qemu_new_vlan_client(nd->vlan, mipsnet_receive, + mipsnet_can_receive, s); + } else { + s->vc = NULL; + } + + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "mipsnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + s->nd->macaddr[0], + s->nd->macaddr[1], + s->nd->macaddr[2], + s->nd->macaddr[3], + s->nd->macaddr[4], + s->nd->macaddr[5]); + + mipsnet_reset(s); + register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s); +} diff --git a/qemu-doc.texi b/qemu-doc.texi index 5b534cc9b..6233ad1e9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2037,7 +2037,7 @@ The MIPS Malta prototype board "malta" @item An ACER Pica "pica61" @item -MIPS MIPSsim emulator pseudo board "mipssim" +MIPS emulator pseudo board "mipssim" @end itemize The generic emulation is supported by Debian 'Etch' and is able to @@ -2085,7 +2085,9 @@ PC Keyboard IDE controller @end itemize -The MIPSsim emulation supports: +The mipssim pseudo board emulation provides an environment similiar +to what the proprietary MIPS emulator uses for running Linux. +It supports: @itemize @minus @item -- cgit v1.2.3 From c7890fc2097ca60786683f51982ff32c50697dab Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Oct 2007 13:43:58 +0000 Subject: Update TODO. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3402 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/TODO | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-mips/TODO b/target-mips/TODO index bc287f63a..6d842e014 100644 --- a/target-mips/TODO +++ b/target-mips/TODO @@ -47,3 +47,9 @@ MALTA system emulation - We fake firmware support instead of doing the real thing - Real firmware falls over when trying to init RAM, presumably due to lacking system controller emulation. + +mipssim system emulation +------------------------ +- The mipsnet.c has a glitch: Booting from NFS root works up until + starting /sbin/init, then it Linux hangs with "NFS server not + responding". -- cgit v1.2.3 From dbe7fb91e1ab9e986186f54f5933466cfbfcd774 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 17 Oct 2007 17:34:17 +0000 Subject: Update Sparc32 OpenBIOS image to SVN revision 171. Changes: r170: Fix exception handling and printout r171: Fix 8 byte alignment problems git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3403 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pc-bios/README b/pc-bios/README index 9839fac7e..64dba9427 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,8 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 and Sparc64 images are built from SVN revision 169. + The included Sparc32 image is built from SVN revision 171 and + Sparc64 image from revision 169. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] -- cgit v1.2.3 From 8f577d3d29996ad5c60ac6419881557183806d8b Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 17 Oct 2007 17:34:57 +0000 Subject: Enable all alignment checks git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3404 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 53 +++++------------------------------------------- 1 file changed, 5 insertions(+), 48 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d0dc51107..cd60c114c 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -346,13 +346,6 @@ GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); -#ifdef ALIGN_7_BUGS_FIXED -#else -#ifndef CONFIG_USER_ONLY -#define gen_op_check_align_T0_7() -#endif -#endif - /* moves */ #ifdef CONFIG_USER_ONLY #define supervisor(dc) 0 @@ -2941,9 +2934,7 @@ static void disas_sparc_insn(DisasContext * dc) (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) { switch (xop) { case 0x0: /* load word */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif #ifndef TARGET_SPARC64 gen_op_ldst(ld); #else @@ -2954,15 +2945,13 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(ldub); break; case 0x2: /* load unsigned halfword */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); -#endif gen_op_ldst(lduh); break; case 0x3: /* load double word */ - gen_op_check_align_T0_7(); if (rd & 1) goto illegal_insn; + gen_op_check_align_T0_7(); gen_op_ldst(ldd); gen_movl_T0_reg(rd + 1); break; @@ -2970,18 +2959,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(ldsb); break; case 0xa: /* load signed halfword */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); -#endif gen_op_ldst(ldsh); break; case 0xd: /* ldstub -- XXX: should be atomically */ gen_op_ldst(ldstub); break; case 0x0f: /* swap register with memory. Also atomically */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_movl_reg_T1(rd); gen_op_ldst(swap); break; @@ -2992,9 +2977,8 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#elif CONFIG_USER_ONLY - gen_op_check_align_T0_3(); #endif + gen_op_check_align_T0_3(); gen_ld_asi(insn, 4, 0); break; case 0x11: /* load unsigned byte alternate */ @@ -3012,9 +2996,8 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#elif CONFIG_USER_ONLY - gen_op_check_align_T0_1(); #endif + gen_op_check_align_T0_1(); gen_ld_asi(insn, 2, 0); break; case 0x13: /* load double word alternate */ @@ -3045,9 +3028,8 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#elif CONFIG_USER_ONLY - gen_op_check_align_T0_1(); #endif + gen_op_check_align_T0_1(); gen_ld_asi(insn, 2, 1); break; case 0x1d: /* ldstuba -- XXX: should be atomically */ @@ -3065,9 +3047,8 @@ static void disas_sparc_insn(DisasContext * dc) goto illegal_insn; if (!supervisor(dc)) goto priv_insn; -#elif CONFIG_USER_ONLY - gen_op_check_align_T0_3(); #endif + gen_op_check_align_T0_3(); gen_movl_reg_T1(rd); gen_swap_asi(insn); break; @@ -3081,9 +3062,7 @@ static void disas_sparc_insn(DisasContext * dc) #endif #ifdef TARGET_SPARC64 case 0x08: /* V9 ldsw */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_op_ldst(ldsw); break; case 0x0b: /* V9 ldx */ @@ -3091,9 +3070,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldst(ldx); break; case 0x18: /* V9 ldswa */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_ld_asi(insn, 4, 1); break; case 0x1b: /* V9 ldxa */ @@ -3103,9 +3080,7 @@ static void disas_sparc_insn(DisasContext * dc) case 0x2d: /* V9 prefetch, no effect */ goto skip_move; case 0x30: /* V9 ldfa */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_ldf_asi(insn, 4); goto skip_move; case 0x33: /* V9 lddfa */ @@ -3129,16 +3104,12 @@ static void disas_sparc_insn(DisasContext * dc) goto jmp_insn; switch (xop) { case 0x20: /* load fpreg */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_op_ldst(ldf); gen_op_store_FT0_fpr(rd); break; case 0x21: /* load fsr */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_op_ldst(ldf); gen_op_ldfsr(); break; @@ -3157,18 +3128,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_movl_reg_T1(rd); switch (xop) { case 0x4: -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_op_ldst(st); break; case 0x5: gen_op_ldst(stb); break; case 0x6: -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); -#endif gen_op_ldst(sth); break; case 0x7: @@ -3187,9 +3154,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_st_asi(insn, 4); break; case 0x15: @@ -3208,9 +3173,7 @@ static void disas_sparc_insn(DisasContext * dc) if (!supervisor(dc)) goto priv_insn; #endif -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_1(); -#endif gen_st_asi(insn, 2); break; case 0x17: @@ -3246,9 +3209,7 @@ static void disas_sparc_insn(DisasContext * dc) goto jmp_insn; switch (xop) { case 0x24: -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_op_load_fpr_FT0(rd); gen_op_ldst(stf); break; @@ -3279,9 +3240,7 @@ static void disas_sparc_insn(DisasContext * dc) switch (xop) { #ifdef TARGET_SPARC64 case 0x34: /* V9 stfa */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif gen_op_load_fpr_FT0(rd); gen_stf_asi(insn, 4); break; @@ -3291,9 +3250,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_stf_asi(insn, 8); break; case 0x3c: /* V9 casa */ -#ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); -#endif flush_T2(dc); gen_movl_reg_T2(rd); gen_cas_asi(insn); -- cgit v1.2.3 From e909ec2f11550804d1a6c16ffa0e50acc4c1c077 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 17 Oct 2007 17:37:13 +0000 Subject: Use ldq and stq for 8 byte accesses (original patch by Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3405 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 43 ++++++++++++++++++++++--------------------- target-sparc/op_mem.h | 12 ++++++++---- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index da4c18d2d..ab456e30c 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -170,6 +170,7 @@ static void dump_mxcc(CPUState *env) void helper_ld_asi(int asi, int size, int sign) { uint32_t ret = 0; + uint64_t tmp; #ifdef DEBUG_MXCC uint32_t last_T0 = T0; #endif @@ -244,8 +245,9 @@ void helper_ld_asi(int asi, int size, int sign) ret = ldl_code(T0 & ~3); break; case 8: - ret = ldl_code(T0 & ~3); - T0 = ldl_code((T0 + 4) & ~3); + tmp = ldq_code(T0 & ~7); + ret = tmp >> 32; + T0 = tmp & 0xffffffff; break; } break; @@ -262,8 +264,9 @@ void helper_ld_asi(int asi, int size, int sign) ret = ldl_user(T0 & ~3); break; case 8: - ret = ldl_user(T0 & ~3); - T0 = ldl_user((T0 + 4) & ~3); + tmp = ldq_user(T0 & ~7); + ret = tmp >> 32; + T0 = tmp & 0xffffffff; break; } break; @@ -280,8 +283,9 @@ void helper_ld_asi(int asi, int size, int sign) ret = ldl_kernel(T0 & ~3); break; case 8: - ret = ldl_kernel(T0 & ~3); - T0 = ldl_kernel((T0 + 4) & ~3); + tmp = ldq_kernel(T0 & ~7); + ret = tmp >> 32; + T0 = tmp & 0xffffffff; break; } break; @@ -303,8 +307,9 @@ void helper_ld_asi(int asi, int size, int sign) ret = ldl_phys(T0 & ~3); break; case 8: - ret = ldl_phys(T0 & ~3); - T0 = ldl_phys((T0 + 4) & ~3); + tmp = ldq_phys(T0 & ~7); + ret = tmp >> 32; + T0 = tmp & 0xffffffff; break; } break; @@ -325,10 +330,10 @@ void helper_ld_asi(int asi, int size, int sign) | ((target_phys_addr_t)(asi & 0xf) << 32)); break; case 8: - ret = ldl_phys((target_phys_addr_t)(T0 & ~3) - | ((target_phys_addr_t)(asi & 0xf) << 32)); - T0 = ldl_phys((target_phys_addr_t)((T0 + 4) & ~3) + tmp = ldq_phys((target_phys_addr_t)(T0 & ~7) | ((target_phys_addr_t)(asi & 0xf) << 32)); + ret = tmp >> 32; + T0 = tmp & 0xffffffff; break; } break; @@ -515,8 +520,7 @@ void helper_st_asi(int asi, int size) stl_user(T0 & ~3, T1); break; case 8: - stl_user(T0 & ~3, T1); - stl_user((T0 + 4) & ~3, T2); + stq_user(T0 & ~7, ((uint64_t)T1 << 32) | T2); break; } break; @@ -533,8 +537,7 @@ void helper_st_asi(int asi, int size) stl_kernel(T0 & ~3, T1); break; case 8: - stl_kernel(T0 & ~3, T1); - stl_kernel((T0 + 4) & ~3, T2); + stq_kernel(T0 & ~7, ((uint64_t)T1 << 32) | T2); break; } break; @@ -591,8 +594,7 @@ void helper_st_asi(int asi, int size) stl_phys(T0 & ~3, T1); break; case 8: - stl_phys(T0 & ~3, T1); - stl_phys((T0 + 4) & ~3, T2); + stq_phys(T0 & ~7, ((uint64_t)T1 << 32) | T2); break; } } @@ -615,10 +617,9 @@ void helper_st_asi(int asi, int size) | ((target_phys_addr_t)(asi & 0xf) << 32), T1); break; case 8: - stl_phys((target_phys_addr_t)(T0 & ~3) - | ((target_phys_addr_t)(asi & 0xf) << 32), T1); - stl_phys((target_phys_addr_t)((T0 + 4) & ~3) - | ((target_phys_addr_t)(asi & 0xf) << 32), T2); + stq_phys((target_phys_addr_t)(T0 & ~7) + | ((target_phys_addr_t)(asi & 0xf) << 32), + ((uint64_t)T1 << 32) | T2); break; } } diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 96ad71683..4af00b371 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -36,8 +36,9 @@ SPARC_ST_OP(sth, stw); void OPPROTO glue(op_std, MEMSUFFIX)(void) { - glue(stl, MEMSUFFIX)(ADDR(T0), T1); - glue(stl, MEMSUFFIX)((ADDR(T0 + 4)), T2); + uint64_t tmp = ((uint64_t)T1 << 32) | (uint64_t)(T2 & 0xffffffff); + + glue(stq, MEMSUFFIX)(ADDR(T0), tmp); } void OPPROTO glue(op_ldstub, MEMSUFFIX)(void) @@ -55,8 +56,11 @@ void OPPROTO glue(op_swap, MEMSUFFIX)(void) void OPPROTO glue(op_ldd, MEMSUFFIX)(void) { - T1 = glue(ldl, MEMSUFFIX)(ADDR(T0)); - T0 = glue(ldl, MEMSUFFIX)((ADDR(T0 + 4))); + uint64_t tmp; + + tmp = glue(ldq, MEMSUFFIX)(ADDR(T0)); + T1 = tmp >> 32; + T0 = tmp & 0xffffffff; } /*** Floating-point store ***/ -- cgit v1.2.3 From 06c0b38830a47cadec4ddaec1788466bf9753d85 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 17 Oct 2007 17:42:21 +0000 Subject: Really update the image git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3406 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/openbios-sparc32 | Bin 272948 -> 272948 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 8bd024da6..8f5a63f0c 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ -- cgit v1.2.3 From 82790064116b066531c8b61067509a0fd4169ee0 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 17 Oct 2007 23:07:31 +0000 Subject: Cast ELF datatypes properly to host 64bit types. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3407 c046a42c-6fe2-441c-8c8c-71466251a162 --- elf_ops.h | 6 +++--- loader.c | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/elf_ops.h b/elf_ops.h index 173d12f05..646a569b2 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -159,7 +159,7 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, goto fail; if (pentry) - *pentry = (uint64_t)ehdr.e_entry; + *pentry = (uint64_t)(elf_sword)ehdr.e_entry; glue(load_symbols, SZ)(&ehdr, fd, must_swab); @@ -206,9 +206,9 @@ int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, } qemu_free(phdr); if (lowaddr) - *lowaddr = (uint64_t)low; + *lowaddr = (uint64_t)(elf_sword)low; if (highaddr) - *highaddr = (uint64_t)high; + *highaddr = (uint64_t)(elf_sword)high; return total_size; fail: qemu_free(data); diff --git a/loader.c b/loader.c index 40bcaf620..c39cb5535 100644 --- a/loader.c +++ b/loader.c @@ -173,6 +173,7 @@ static void *load_at(int fd, int offset, int size) #define SZ 32 #define elf_word uint32_t +#define elf_sword int32_t #define bswapSZs bswap32s #include "elf_ops.h" @@ -182,6 +183,7 @@ static void *load_at(int fd, int offset, int size) #undef elf_sym #undef elf_note #undef elf_word +#undef elf_sword #undef bswapSZs #undef SZ #define elfhdr elf64_hdr @@ -190,6 +192,7 @@ static void *load_at(int fd, int offset, int size) #define elf_shdr elf64_shdr #define elf_sym elf64_sym #define elf_word uint64_t +#define elf_sword int64_t #define bswapSZs bswap64s #define SZ 64 #include "elf_ops.h" -- cgit v1.2.3 From b533415989c55d929804d56ea4bfb93e8d5ce021 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 18 Oct 2007 15:05:11 +0000 Subject: Only map BIOS space when it was actually loaded. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3408 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_mipssim.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 6c061636b..b7b834fc2 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -82,7 +82,7 @@ mips_mipssim_init (int ram_size, int vga_ram_size, int boot_device, char buf[1024]; unsigned long bios_offset; CPUState *env; - int ret; + int bios_size; mips_def_t *def; /* Init CPUs. */ @@ -103,25 +103,24 @@ mips_mipssim_init (int ram_size, int vga_ram_size, int boot_device, /* Allocate RAM. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); - /* Map the BIOS / boot exception handler. */ - bios_offset = ram_size + vga_ram_size; - /* Load a BIOS / boot exception handler image. */ + bios_offset = ram_size + vga_ram_size; if (bios_name == NULL) bios_name = BIOS_FILENAME; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); - ret = load_image(buf, phys_ram_base + bios_offset); - if ((ret < 0 || ret > BIOS_SIZE) && !kernel_filename) { + bios_size = load_image(buf, phys_ram_base + bios_offset); + if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { /* Bail out if we have neither a kernel image nor boot vector code. */ fprintf(stderr, "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", buf); exit(1); } else { - /* We have a boot vector start address. */ - env->PC[env->current_tc] = (target_long)0xbfc00000; + /* Map the BIOS / boot exception handler. */ cpu_register_physical_memory(0x1fc00000LL, - ret, bios_offset | IO_MEM_ROM); + bios_size, bios_offset | IO_MEM_ROM); + /* We have a boot vector start address. */ + env->PC[env->current_tc] = (target_long)(int32_t)0xbfc00000; } if (kernel_filename) { -- cgit v1.2.3 From e85e7c6ea411c42e24e6e7b8ff5cdd99faae317a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 18 Oct 2007 19:59:49 +0000 Subject: Use the new TARGET_ABI32 feature to implement a ppc64abi32-linux-user target (PowerPC 64 running in 32 bits mode). Use the new TARGET_ABI_DIR feature to implement a ppcemb-linux-user target (PowerPC 32 with 64 bits GPRs and vector extensions). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3409 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 11 ++++++++++- linux-user/elfload.c | 6 +++--- linux-user/main.c | 18 +++++++++++------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/configure b/configure index 221c06865..492707a7b 100755 --- a/configure +++ b/configure @@ -504,7 +504,7 @@ if test -z "$target_list" ; then fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppc64-linux-user x86_64-linux-user cris-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppcemb-linux-user ppc64-linux-user ppc64abi32-linux-user x86_64-linux-user cris-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then @@ -937,6 +937,7 @@ target_bigendian="no" [ "$target_cpu" = "ppc" ] && target_bigendian=yes [ "$target_cpu" = "ppcemb" ] && target_bigendian=yes [ "$target_cpu" = "ppc64" ] && target_bigendian=yes +[ "$target_cpu" = "ppc64abi32" ] && target_bigendian=yes [ "$target_cpu" = "ppc64h" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes [ "$target_cpu" = "mipsn32" ] && target_bigendian=yes @@ -1040,6 +1041,7 @@ elif test "$target_cpu" = "ppc" ; then echo "#define TARGET_PPC 1" >> $config_h elif test "$target_cpu" = "ppcemb" ; then echo "TARGET_ARCH=ppcemb" >> $config_mak + echo "TARGET_ABI_DIR=ppc" >> $config_mak echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h echo "#define TARGET_PPC 1" >> $config_h echo "#define TARGET_PPCEMB 1" >> $config_h @@ -1048,6 +1050,13 @@ elif test "$target_cpu" = "ppc64" ; then 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" = "ppc64abi32" ; then + echo "TARGET_ARCH=ppc64" >> $config_mak + echo "#define TARGET_ARCH \"ppc64\"" >> $config_h + echo "TARGET_ABI_DIR=ppc" >> $config_mak + echo "#define TARGET_PPC 1" >> $config_h + echo "#define TARGET_PPC64 1" >> $config_h + echo "#define TARGET_ABI32 1" >> $config_h elif test "$target_cpu" = "ppc64h" ; then echo "TARGET_ARCH=ppc64h" >> $config_mak echo "#define TARGET_ARCH \"ppc64h\"" >> $config_h diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 0bb455bda..fbfa3b0de 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -269,7 +269,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#ifdef TARGET_PPC64 +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) #define elf_check_arch(x) ( (x) == EM_PPC64 ) @@ -325,13 +325,13 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * { abi_ulong pos = infop->start_stack; abi_ulong tmp; -#ifdef TARGET_PPC64 +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) abi_ulong entry, toc; #endif _regs->msr = 1 << MSR_PR; /* Set user mode */ _regs->gpr[1] = infop->start_stack; -#ifdef TARGET_PPC64 +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) entry = ldq_raw(infop->entry) + infop->load_addr; toc = ldq_raw(infop->entry + 8) + infop->load_addr; _regs->gpr[2] = toc; diff --git a/linux-user/main.c b/linux-user/main.c index 1388d4833..7c3912151 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1008,7 +1008,7 @@ void cpu_loop(CPUPPCState *env) "Aborting\n"); break; #endif /* defined(TARGET_PPCEMB) */ -#if defined(TARGET_PPC64) /* PowerPC 64 */ +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) /* PowerPC 64 */ case POWERPC_EXCP_DSEG: /* Data segment exception */ cpu_abort(env, "Data segment exception while in user mode. " "Aborting\n"); @@ -1017,19 +1017,21 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Instruction segment exception " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64) */ -#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ +#endif /* defined(TARGET_PPC64) && !defined(TARGET_ABI32) */ +#if defined(TARGET_PPC64H) && !defined(TARGET_ABI32) + /* PowerPC 64 with hypervisor mode support */ case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ cpu_abort(env, "Hypervisor decrementer interrupt " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64H) */ +#endif /* defined(TARGET_PPC64H) && !defined(TARGET_ABI32) */ case POWERPC_EXCP_TRACE: /* Trace exception */ /* Nothing to do: * we use this exception to emulate step-by-step execution mode. */ break; -#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ +#if defined(TARGET_PPC64H) && !defined(TARGET_ABI32) + /* PowerPC 64 with hypervisor mode support */ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ cpu_abort(env, "Hypervisor data storage exception " "while in user mode. Aborting\n"); @@ -1046,7 +1048,7 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Hypervisor instruction segment exception " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64H) */ +#endif /* defined(TARGET_PPC64H) && !defined(TARGET_ABI32) */ case POWERPC_EXCP_VPU: /* Vector unavailable exception */ EXCP_DUMP(env, "No Altivec instructions allowed\n"); info.si_signo = TARGET_SIGILL; @@ -2170,8 +2172,10 @@ int main(int argc, char **argv) if (i != 12 && i != 6 && i != 13) env->msr[i] = (regs->msr >> i) & 1; } -#if defined(TARGET_PPC64) +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) msr_sf = 1; +#else + msr_sf = 0; #endif env->nip = regs->nip; for(i = 0; i < 32; i++) { -- cgit v1.2.3 From f85e9a6870c7e96c2748ec0c40e04c00600189ae Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 18 Oct 2007 20:51:49 +0000 Subject: Use TARGET_ABI_DIR feature to unify PowerPC and PowerPC 64 definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3410 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 + linux-user/ppc/syscall.h | 4 + linux-user/ppc/syscall_nr.h | 12 ++ linux-user/ppc64/syscall.h | 130 ---------------- linux-user/ppc64/syscall_nr.h | 313 --------------------------------------- linux-user/ppc64/target_signal.h | 29 ---- linux-user/ppc64/termbits.h | 237 ----------------------------- 7 files changed, 18 insertions(+), 709 deletions(-) delete mode 100644 linux-user/ppc64/syscall.h delete mode 100644 linux-user/ppc64/syscall_nr.h delete mode 100644 linux-user/ppc64/target_signal.h delete mode 100644 linux-user/ppc64/termbits.h diff --git a/configure b/configure index 492707a7b..ba734673c 100755 --- a/configure +++ b/configure @@ -1048,6 +1048,7 @@ elif test "$target_cpu" = "ppcemb" ; then elif test "$target_cpu" = "ppc64" ; then echo "TARGET_ARCH=ppc64" >> $config_mak echo "#define TARGET_ARCH \"ppc64\"" >> $config_h + echo "TARGET_ABI_DIR=ppc" >> $config_mak echo "#define TARGET_PPC 1" >> $config_h echo "#define TARGET_PPC64 1" >> $config_h elif test "$target_cpu" = "ppc64abi32" ; then @@ -1060,6 +1061,7 @@ elif test "$target_cpu" = "ppc64abi32" ; then elif test "$target_cpu" = "ppc64h" ; then echo "TARGET_ARCH=ppc64h" >> $config_mak echo "#define TARGET_ARCH \"ppc64h\"" >> $config_h + echo "TARGET_ABI_DIR=ppc" >> $config_mak echo "#define TARGET_PPC 1" >> $config_h echo "#define TARGET_PPC64 1" >> $config_h echo "#define TARGET_PPC64H 1" >> $config_h diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index 30427f69e..f98d2bca5 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -51,4 +51,8 @@ struct target_revectored_struct { * flags masks */ +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) +#define UNAME_MACHINE "ppc64" +#else #define UNAME_MACHINE "ppc" +#endif diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h index 1e5ced713..8fa5bef3b 100644 --- a/linux-user/ppc/syscall_nr.h +++ b/linux-user/ppc/syscall_nr.h @@ -193,19 +193,23 @@ #define TARGET_NR_vfork 189 #define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */ #define TARGET_NR_readahead 191 +#if !defined(TARGET_PPC64) || defined(TARGET_ABI32) #define TARGET_NR_mmap2 192 #define TARGET_NR_truncate64 193 #define TARGET_NR_ftruncate64 194 #define TARGET_NR_stat64 195 #define TARGET_NR_lstat64 196 #define TARGET_NR_fstat64 197 +#endif #define TARGET_NR_pciconfig_read 198 #define TARGET_NR_pciconfig_write 199 #define TARGET_NR_pciconfig_iobase 200 #define TARGET_NR_multiplexer 201 #define TARGET_NR_getdents64 202 #define TARGET_NR_pivot_root 203 +#if !defined(TARGET_PPC64) || defined(TARGET_ABI32) #define TARGET_NR_fcntl64 204 +#endif #define TARGET_NR_madvise 205 #define TARGET_NR_mincore 206 #define TARGET_NR_gettid 207 @@ -227,7 +231,9 @@ #define TARGET_NR_sched_getaffinity 223 /* 224 currently unused */ #define TARGET_NR_tuxcall 225 +#if !defined(TARGET_PPC64) || defined(TARGET_ABI32) #define TARGET_NR_sendfile64 226 +#endif #define TARGET_NR_io_setup 227 #define TARGET_NR_io_destroy 228 #define TARGET_NR_io_getevents 229 @@ -255,7 +261,9 @@ #define TARGET_NR_utimes 251 #define TARGET_NR_statfs64 252 #define TARGET_NR_fstatfs64 253 +#if !defined(TARGET_PPC64) || defined(TARGET_ABI32) #define TARGET_NR_fadvise64_64 254 +#endif #define TARGET_NR_rtas 255 #define TARGET_NR_sys_debug_setcontext 256 /* Number 257 is reserved for vserver */ @@ -292,7 +300,11 @@ #define TARGET_NR_mknodat 288 #define TARGET_NR_fchownat 289 #define TARGET_NR_futimesat 290 +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) +#define TARGET_NR_newfstatat 291 +#else #define TARGET_NR_fstatat64 291 +#endif #define TARGET_NR_unlinkat 292 #define TARGET_NR_renameat 293 #define TARGET_NR_linkat 294 diff --git a/linux-user/ppc64/syscall.h b/linux-user/ppc64/syscall.h deleted file mode 100644 index bdb1a07da..000000000 --- a/linux-user/ppc64/syscall.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * PPC emulation for qemu: syscall definitions. - * - * Copyright (c) 2003 Jocelyn Mayer - * - * 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 - */ - -/* XXX: ABSOLUTELY BUGGY: - * for now, this is quite just a cut-and-paste from i386 target... - */ - -/* default linux values for the selectors */ -#define __USER_DS (1) - -struct target_pt_regs { - unsigned long gpr[32]; - unsigned long nip; - unsigned long msr; - unsigned long orig_gpr3; /* Used for restarting system calls */ - unsigned long ctr; - unsigned long link; - unsigned long xer; - unsigned long ccr; - unsigned long mq; /* 601 only (not used at present) */ - /* Used on APUS to hold IPL value. */ - unsigned long trap; /* Reason for being here */ - unsigned long dar; /* Fault registers */ - unsigned long dsisr; - unsigned long result; /* Result of a system call */ -}; - -/* ioctls */ -struct target_revectored_struct { - abi_ulong __map[8]; /* 256 bits */ -}; - -/* - * flags masks - */ - -/* ipcs */ - -#define TARGET_SEMOP 1 -#define TARGET_SEMGET 2 -#define TARGET_SEMCTL 3 -#define TARGET_MSGSND 11 -#define TARGET_MSGRCV 12 -#define TARGET_MSGGET 13 -#define TARGET_MSGCTL 14 -#define TARGET_SHMAT 21 -#define TARGET_SHMDT 22 -#define TARGET_SHMGET 23 -#define TARGET_SHMCTL 24 - -#if 0 // To make it compile, even if the definition in syscall.c is bugged -struct target_msgbuf { - int mtype; - char mtext[1]; -}; -#endif - -struct target_ipc_kludge { - unsigned int msgp; /* Really (struct msgbuf *) */ - int msgtyp; -}; - -#if 0 // To make it compile, even if the definition in syscall.c is bugged -struct target_ipc_perm { - int __key; - unsigned short uid; - unsigned short gid; - unsigned short cuid; - unsigned short cgid; - unsigned short mode; - unsigned short seq; -}; -#endif - -#if 0 // To make it compile, even if the definition in syscall.c is bugged -struct target_msqid_ds { - struct target_ipc_perm msg_perm; - unsigned int msg_first; /* really struct target_msg* */ - unsigned int msg_last; /* really struct target_msg* */ - unsigned int msg_stime; /* really target_time_t */ - unsigned int msg_rtime; /* really target_time_t */ - unsigned int msg_ctime; /* really target_time_t */ - unsigned int wwait; /* really struct wait_queue* */ - unsigned int rwait; /* really struct wait_queue* */ - unsigned short msg_cbytes; - unsigned short msg_qnum; - unsigned short msg_qbytes; - unsigned short msg_lspid; - unsigned short msg_lrpid; -}; -#endif - -#if 0 // To make it compile, even if the definition in syscall.c is bugged -struct target_shmid_ds { - struct target_ipc_perm shm_perm; - int shm_segsz; - unsigned int shm_atime; /* really target_time_t */ - unsigned int shm_dtime; /* really target_time_t */ - unsigned int shm_ctime; /* really target_time_t */ - unsigned short shm_cpid; - unsigned short shm_lpid; - short shm_nattch; - unsigned short shm_npages; - unsigned long *shm_pages; - void *attaches; /* really struct shm_desc * */ -}; -#endif - -#define TARGET_IPC_RMID 0 -#define TARGET_IPC_SET 1 -#define TARGET_IPC_STAT 2 - -#define UNAME_MACHINE "ppc64" diff --git a/linux-user/ppc64/syscall_nr.h b/linux-user/ppc64/syscall_nr.h deleted file mode 100644 index d78ce5394..000000000 --- a/linux-user/ppc64/syscall_nr.h +++ /dev/null @@ -1,313 +0,0 @@ -/* - * This file contains the system call numbers. - */ -#define TARGET_NR_restart_syscall 0 -#define TARGET_NR_exit 1 -#define TARGET_NR_fork 2 -#define TARGET_NR_read 3 -#define TARGET_NR_write 4 -#define TARGET_NR_open 5 -#define TARGET_NR_close 6 -#define TARGET_NR_waitpid 7 -#define TARGET_NR_creat 8 -#define TARGET_NR_link 9 -#define TARGET_NR_unlink 10 -#define TARGET_NR_execve 11 -#define TARGET_NR_chdir 12 -#define TARGET_NR_time 13 -#define TARGET_NR_mknod 14 -#define TARGET_NR_chmod 15 -#define TARGET_NR_lchown32 16 -#define TARGET_NR_break 17 -#define TARGET_NR_oldstat 18 -#define TARGET_NR_lseek 19 -#define TARGET_NR_getpid 20 -#define TARGET_NR_mount 21 -#define TARGET_NR_umount 22 -#define TARGET_NR_setuid32 23 -#define TARGET_NR_getuid32 24 -#define TARGET_NR_stime 25 -#define TARGET_NR_ptrace 26 -#define TARGET_NR_alarm 27 -#define TARGET_NR_oldfstat 28 -#define TARGET_NR_pause 29 -#define TARGET_NR_utime 30 -#define TARGET_NR_stty 31 -#define TARGET_NR_gtty 32 -#define TARGET_NR_access 33 -#define TARGET_NR_nice 34 -#define TARGET_NR_ftime 35 -#define TARGET_NR_sync 36 -#define TARGET_NR_kill 37 -#define TARGET_NR_rename 38 -#define TARGET_NR_mkdir 39 -#define TARGET_NR_rmdir 40 -#define TARGET_NR_dup 41 -#define TARGET_NR_pipe 42 -#define TARGET_NR_times 43 -#define TARGET_NR_prof 44 -#define TARGET_NR_brk 45 -#define TARGET_NR_setgid32 46 -#define TARGET_NR_getgid32 47 -#define TARGET_NR_signal 48 -#define TARGET_NR_geteuid32 49 -#define TARGET_NR_getegid32 50 -#define TARGET_NR_acct 51 -#define TARGET_NR_umount2 52 -#define TARGET_NR_lock 53 -#define TARGET_NR_ioctl 54 -#define TARGET_NR_fcntl 55 -#define TARGET_NR_mpx 56 -#define TARGET_NR_setpgid 57 -#define TARGET_NR_ulimit 58 -#define TARGET_NR_oldolduname 59 -#define TARGET_NR_umask 60 -#define TARGET_NR_chroot 61 -#define TARGET_NR_ustat 62 -#define TARGET_NR_dup2 63 -#define TARGET_NR_getppid 64 -#define TARGET_NR_getpgrp 65 -#define TARGET_NR_setsid 66 -#define TARGET_NR_sigaction 67 -#define TARGET_NR_sgetmask 68 -#define TARGET_NR_ssetmask 69 -#define TARGET_NR_setreuid32 70 -#define TARGET_NR_setregid32 71 -#define TARGET_NR_sigsuspend 72 -#define TARGET_NR_sigpending 73 -#define TARGET_NR_sethostname 74 -#define TARGET_NR_setrlimit 75 -#define TARGET_NR_getrlimit 76 -#define TARGET_NR_getrusage 77 -#define TARGET_NR_gettimeofday 78 -#define TARGET_NR_settimeofday 79 -#define TARGET_NR_getgroups32 80 -#define TARGET_NR_setgroups32 81 -#define TARGET_NR_select 82 -#define TARGET_NR_symlink 83 -#define TARGET_NR_oldlstat 84 -#define TARGET_NR_readlink 85 -#define TARGET_NR_uselib 86 -#define TARGET_NR_swapon 87 -#define TARGET_NR_reboot 88 -#define TARGET_NR_readdir 89 -#define TARGET_NR_mmap 90 -#define TARGET_NR_munmap 91 -#define TARGET_NR_truncate 92 -#define TARGET_NR_ftruncate 93 -#define TARGET_NR_fchmod 94 -#define TARGET_NR_fchown32 95 -#define TARGET_NR_getpriority 96 -#define TARGET_NR_setpriority 97 -#define TARGET_NR_profil 98 -#define TARGET_NR_statfs 99 -#define TARGET_NR_fstatfs 100 -#define TARGET_NR_ioperm 101 -#define TARGET_NR_socketcall 102 -#define TARGET_NR_syslog 103 -#define TARGET_NR_setitimer 104 -#define TARGET_NR_getitimer 105 -#define TARGET_NR_stat 106 -#define TARGET_NR_lstat 107 -#define TARGET_NR_fstat 108 -#define TARGET_NR_olduname 109 -#define TARGET_NR_iopl 110 -#define TARGET_NR_vhangup 111 -#define TARGET_NR_idle 112 -#define TARGET_NR_vm86 113 -#define TARGET_NR_wait4 114 -#define TARGET_NR_swapoff 115 -#define TARGET_NR_sysinfo 116 -#define TARGET_NR_ipc 117 -#define TARGET_NR_fsync 118 -#define TARGET_NR_sigreturn 119 -#define TARGET_NR_clone 120 -#define TARGET_NR_setdomainname 121 -#define TARGET_NR_uname 122 -#define TARGET_NR_modify_ldt 123 -#define TARGET_NR_adjtimex 124 -#define TARGET_NR_mprotect 125 -#define TARGET_NR_sigprocmask 126 -#define TARGET_NR_create_module 127 -#define TARGET_NR_init_module 128 -#define TARGET_NR_delete_module 129 -#define TARGET_NR_get_kernel_syms 130 -#define TARGET_NR_quotactl 131 -#define TARGET_NR_getpgid 132 -#define TARGET_NR_fchdir 133 -#define TARGET_NR_bdflush 134 -#define TARGET_NR_sysfs 135 -#define TARGET_NR_personality 136 -#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ -#define TARGET_NR_setfsuid32 138 -#define TARGET_NR_setfsgid32 139 -#define TARGET_NR__llseek 140 -#define TARGET_NR_getdents 141 -#define TARGET_NR__newselect 142 -#define TARGET_NR_flock 143 -#define TARGET_NR_msync 144 -#define TARGET_NR_readv 145 -#define TARGET_NR_writev 146 -#define TARGET_NR_getsid 147 -#define TARGET_NR_fdatasync 148 -#define TARGET_NR__sysctl 149 -#define TARGET_NR_mlock 150 -#define TARGET_NR_munlock 151 -#define TARGET_NR_mlockall 152 -#define TARGET_NR_munlockall 153 -#define TARGET_NR_sched_setparam 154 -#define TARGET_NR_sched_getparam 155 -#define TARGET_NR_sched_setscheduler 156 -#define TARGET_NR_sched_getscheduler 157 -#define TARGET_NR_sched_yield 158 -#define TARGET_NR_sched_get_priority_max 159 -#define TARGET_NR_sched_get_priority_min 160 -#define TARGET_NR_sched_rr_get_interval 161 -#define TARGET_NR_nanosleep 162 -#define TARGET_NR_mremap 163 -#define TARGET_NR_setresuid32 164 -#define TARGET_NR_getresuid32 165 -#define TARGET_NR_query_module 166 -#define TARGET_NR_poll 167 -#define TARGET_NR_nfsservctl 168 -#define TARGET_NR_setresgid32 169 -#define TARGET_NR_getresgid32 170 -#define TARGET_NR_prctl 171 -#define TARGET_NR_rt_sigreturn 172 -#define TARGET_NR_rt_sigaction 173 -#define TARGET_NR_rt_sigprocmask 174 -#define TARGET_NR_rt_sigpending 175 -#define TARGET_NR_rt_sigtimedwait 176 -#define TARGET_NR_rt_sigqueueinfo 177 -#define TARGET_NR_rt_sigsuspend 178 -#define TARGET_NR_pread64 179 -#define TARGET_NR_pwrite64 180 -#define TARGET_NR_chown32 181 -#define TARGET_NR_getcwd 182 -#define TARGET_NR_capget 183 -#define TARGET_NR_capset 184 -#define TARGET_NR_sigaltstack 185 -#define TARGET_NR_sendfile 186 -#define TARGET_NR_getpmsg 187 /* some people actually want streams */ -#define TARGET_NR_putpmsg 188 /* some people actually want streams */ -#define TARGET_NR_vfork 189 -#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */ -#define TARGET_NR_readahead 191 -#define TARGET_NR_mmap2 192 -#define TARGET_NR_truncate64 193 -#define TARGET_NR_ftruncate64 194 -#define TARGET_NR_stat64 195 -#define TARGET_NR_lstat64 196 -#define TARGET_NR_fstat64 197 -#define TARGET_NR_pciconfig_read 198 -#define TARGET_NR_pciconfig_write 199 -#define TARGET_NR_pciconfig_iobase 200 -#define TARGET_NR_multiplexer 201 -#define TARGET_NR_getdents64 202 -#define TARGET_NR_pivot_root 203 -#define TARGET_NR_fcntl64 204 -#define TARGET_NR_madvise 205 -#define TARGET_NR_mincore 206 -#define TARGET_NR_gettid 207 -#define TARGET_NR_tkill 208 -#define TARGET_NR_setxattr 209 -#define TARGET_NR_lsetxattr 210 -#define TARGET_NR_fsetxattr 211 -#define TARGET_NR_getxattr 212 -#define TARGET_NR_lgetxattr 213 -#define TARGET_NR_fgetxattr 214 -#define TARGET_NR_listxattr 215 -#define TARGET_NR_llistxattr 216 -#define TARGET_NR_flistxattr 217 -#define TARGET_NR_removexattr 218 -#define TARGET_NR_lremovexattr 219 -#define TARGET_NR_fremovexattr 220 -#define TARGET_NR_futex 221 -#define TARGET_NR_sched_setaffinity 222 -#define TARGET_NR_sched_getaffinity 223 -/* 224 currently unused */ -#define TARGET_NR_tuxcall 225 -#define TARGET_NR_sendfile64 226 -#define TARGET_NR_io_setup 227 -#define TARGET_NR_io_destroy 228 -#define TARGET_NR_io_getevents 229 -#define TARGET_NR_io_submit 230 -#define TARGET_NR_io_cancel 231 -#define TARGET_NR_set_tid_address 232 -#define TARGET_NR_fadvise64 233 -#define TARGET_NR_exit_group 234 -#define TARGET_NR_lookup_dcookie 235 -#define TARGET_NR_epoll_create 236 -#define TARGET_NR_epoll_ctl 237 -#define TARGET_NR_epoll_wait 238 -#define TARGET_NR_remap_file_pages 239 -#define TARGET_NR_timer_create 240 -#define TARGET_NR_timer_settime 241 -#define TARGET_NR_timer_gettime 242 -#define TARGET_NR_timer_getoverrun 243 -#define TARGET_NR_timer_delete 244 -#define TARGET_NR_clock_settime 245 -#define TARGET_NR_clock_gettime 246 -#define TARGET_NR_clock_getres 247 -#define TARGET_NR_clock_nanosleep 248 -#define TARGET_NR_swapcontext 249 -#define TARGET_NR_tgkill 250 -#define TARGET_NR_utimes 251 -#define TARGET_NR_statfs64 252 -#define TARGET_NR_fstatfs64 253 -#define TARGET_NR_fadvise64_64 254 -#define TARGET_NR_rtas 255 -#define TARGET_NR_sys_debug_setcontext 256 -/* Number 257 is reserved for vserver */ -#define TARGET_NR_migrate_pages 258 -#define TARGET_NR_mbind 259 -#define TARGET_NR_get_mempolicy 260 -#define TARGET_NR_set_mempolicy 261 -#define TARGET_NR_mq_open 262 -#define TARGET_NR_mq_unlink 263 -#define TARGET_NR_mq_timedsend 264 -#define TARGET_NR_mq_timedreceive 265 -#define TARGET_NR_mq_notify 266 -#define TARGET_NR_mq_getsetattr 267 -#define TARGET_NR_kexec_load 268 -#define TARGET_NR_add_key 269 -#define TARGET_NR_request_key 270 -#define TARGET_NR_keyctl 271 -#define TARGET_NR_waitid 272 -#define TARGET_NR_ioprio_set 273 -#define TARGET_NR_ioprio_get 274 -#define TARGET_NR_inotify_init 275 -#define TARGET_NR_inotify_add_watch 276 -#define TARGET_NR_inotify_rm_watch 277 -#define TARGET_NR_spu_run 278 -#define TARGET_NR_spu_create 279 -#define TARGET_NR_pselect6 280 -#define TARGET_NR_ppoll 281 -#define TARGET_NR_unshare 282 -#define TARGET_NR_splice 283 -#define TARGET_NR_tee 284 -#define TARGET_NR_vmsplice 285 -#define TARGET_NR_openat 286 -#define TARGET_NR_mkdirat 287 -#define TARGET_NR_mknodat 288 -#define TARGET_NR_fchownat 289 -#define TARGET_NR_futimesat 290 -#define TARGET_NR_newfstatat 291 -#define TARGET_NR_unlinkat 292 -#define TARGET_NR_renameat 293 -#define TARGET_NR_linkat 294 -#define TARGET_NR_symlinkat 295 -#define TARGET_NR_readlinkat 296 -#define TARGET_NR_fchmodat 297 -#define TARGET_NR_faccessat 298 -#define TARGET_NR_get_robust_list 299 -#define TARGET_NR_set_robust_list 300 -#define TARGET_NR_move_pages 301 -#define TARGET_NR_getcpu 302 -#define TARGET_NR_epoll_pwait 303 -#define TARGET_NR_utimensat 304 -#define TARGET_NR_signalfd 305 -#define TARGET_NR_timerfd 306 -#define TARGET_NR_eventfd 307 -#define TARGET_NR_sync_file_range2 308 -#define TARGET_NR_fallocate 309 diff --git a/linux-user/ppc64/target_signal.h b/linux-user/ppc64/target_signal.h deleted file mode 100644 index defae809a..000000000 --- a/linux-user/ppc64/target_signal.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - - -/* - * sigaltstack controls - */ -#define TARGET_SS_ONSTACK 1 -#define TARGET_SS_DISABLE 2 - -#define TARGET_MINSIGSTKSZ 2048 -#define TARGET_SIGSTKSZ 8192 - -static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state) -{ - return state->gpr[1]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/ppc64/termbits.h b/linux-user/ppc64/termbits.h deleted file mode 100644 index 41537ed39..000000000 --- a/linux-user/ppc64/termbits.h +++ /dev/null @@ -1,237 +0,0 @@ -/* from asm/termbits.h */ - -#define TARGET_NCCS 19 - -struct target_termios { - unsigned int c_iflag; /* input mode flags */ - unsigned int c_oflag; /* output mode flags */ - unsigned int c_cflag; /* control mode flags */ - unsigned int c_lflag; /* local mode flags */ - unsigned char c_cc[TARGET_NCCS]; /* control characters */ - unsigned char c_line; /* line discipline */ - unsigned int c_ispeed; /* input speed */ - unsigned int c_ospeed; /* output speed */ -}; - -/* c_cc character offsets */ -#define TARGET_VINTR 0 -#define TARGET_VQUIT 1 -#define TARGET_VERASE 2 -#define TARGET_VKILL 3 -#define TARGET_VEOF 4 -#define TARGET_VMIN 5 -#define TARGET_VEOL 6 -#define TARGET_VTIME 7 -#define TARGET_VEOL2 8 -#define TARGET_VSWTC 9 - -#define TARGET_VWERASE 10 -#define TARGET_VREPRINT 11 -#define TARGET_VSUSP 12 -#define TARGET_VSTART 13 -#define TARGET_VSTOP 14 -#define TARGET_VLNEXT 15 -#define TARGET_VDISCARD 16 - -#define TARGET_IGNBRK 0000001 -#define TARGET_BRKINT 0000002 -#define TARGET_IGNPAR 0000004 -#define TARGET_PARMRK 0000010 -#define TARGET_INPCK 0000020 -#define TARGET_ISTRIP 0000040 -#define TARGET_INLCR 0000100 -#define TARGET_IGNCR 0000200 -#define TARGET_ICRNL 0000400 -#define TARGET_IXON 0001000 -#define TARGET_IXOFF 0002000 -#define TARGET_IXANY 0004000 -#define TARGET_IUCLC 0010000 -#define TARGET_IMAXBEL 0020000 -#define TARGET_IUTF8 0040000 - -/* c_oflag bits */ -#define TARGET_OPOST 0000001 -#define TARGET_ONLCR 0000002 -#define TARGET_OLCUC 0000004 - -#define TARGET_OCRNL 0000010 -#define TARGET_ONOCR 0000020 -#define TARGET_ONLRET 0000040 - -#define TARGET_OFILL 00000100 -#define TARGET_OFDEL 00000200 -#define TARGET_NLDLY 00001400 -#define TARGET_NL0 00000000 -#define TARGET_NL1 00000400 -#define TARGET_NL2 00001000 -#define TARGET_NL3 00001400 -#define TARGET_TABDLY 00006000 -#define TARGET_TAB0 00000000 -#define TARGET_TAB1 00002000 -#define TARGET_TAB2 00004000 -#define TARGET_TAB3 00006000 -#define TARGET_XTABS 00006000 /* required by POSIX to == TAB3 */ -#define TARGET_CRDLY 00030000 -#define TARGET_CR0 00000000 -#define TARGET_CR1 00010000 -#define TARGET_CR2 00020000 -#define TARGET_CR3 00030000 -#define TARGET_FFDLY 00040000 -#define TARGET_FF0 00000000 -#define TARGET_FF1 00040000 -#define TARGET_BSDLY 00100000 -#define TARGET_BS0 00000000 -#define TARGET_BS1 00100000 -#define TARGET_VTDLY 00200000 -#define TARGET_VT0 00000000 -#define TARGET_VT1 00200000 - -/* c_cflag bit meaning */ -#define TARGET_CBAUD 0000377 -#define TARGET_B0 0000000 /* hang up */ -#define TARGET_B50 0000001 -#define TARGET_B75 0000002 -#define TARGET_B110 0000003 -#define TARGET_B134 0000004 -#define TARGET_B150 0000005 -#define TARGET_B200 0000006 -#define TARGET_B300 0000007 -#define TARGET_B600 0000010 -#define TARGET_B1200 0000011 -#define TARGET_B1800 0000012 -#define TARGET_B2400 0000013 -#define TARGET_B4800 0000014 -#define TARGET_B9600 0000015 -#define TARGET_B19200 0000016 -#define TARGET_B38400 0000017 -#define TARGET_EXTA B19200 -#define TARGET_EXTB B38400 -#define TARGET_CBAUDEX 0000000 -#define TARGET_B57600 00020 -#define TARGET_B115200 00021 -#define TARGET_B230400 00022 -#define TARGET_B460800 00023 -#define TARGET_B500000 00024 -#define TARGET_B576000 00025 -#define TARGET_B921600 00026 -#define TARGET_B1000000 00027 -#define TARGET_B1152000 00030 -#define TARGET_B1500000 00031 -#define TARGET_B2000000 00032 -#define TARGET_B2500000 00033 -#define TARGET_B3000000 00034 -#define TARGET_B3500000 00035 -#define TARGET_B4000000 00036 - -#define TARGET_CSIZE 00001400 -#define TARGET_CS5 00000000 -#define TARGET_CS6 00000400 -#define TARGET_CS7 00001000 -#define TARGET_CS8 00001400 - -#define TARGET_CSTOPB 00002000 -#define TARGET_CREAD 00004000 -#define TARGET_PARENB 00010000 -#define TARGET_PARODD 00020000 -#define TARGET_HUPCL 00040000 - -#define TARGET_CLOCAL 00100000 -#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ -#define TARGET_CRTSCTS 020000000000 /* flow control */ - -/* c_lflag bits */ -#define TARGET_ISIG 0x00000080 -#define TARGET_ICANON 0x00000100 -#define TARGET_XCASE 0x00004000 -#define TARGET_ECHO 0x00000008 -#define TARGET_ECHOE 0x00000002 -#define TARGET_ECHOK 0x00000004 -#define TARGET_ECHONL 0x00000010 -#define TARGET_NOFLSH 0x80000000 -#define TARGET_TOSTOP 0x00400000 -#define TARGET_ECHOCTL 0x00000040 -#define TARGET_ECHOPRT 0x00000020 -#define TARGET_ECHOKE 0x00000001 -#define TARGET_FLUSHO 0x00800000 -#define TARGET_PENDIN 0x20000000 -#define TARGET_IEXTEN 0x00000400 - -/* ioctls */ - -#define TARGET_FIOCLEX TARGET_IO('f', 1) -#define TARGET_FIONCLEX TARGET_IO('f', 2) -#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) -#define TARGET_FIONBIO TARGET_IOW('f', 126, int) -#define TARGET_FIONREAD TARGET_IOR('f', 127, int) -#define TARGET_TIOCINQ TARGET_FIONREAD -//#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) - -#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios) -#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios) -#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios) -#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios) - -#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio) -#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio) -#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio) -#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio) - -#define TARGET_TCSBRK TARGET_IO('t', 29) -#define TARGET_TCXONC TARGET_IO('t', 30) -#define TARGET_TCFLSH TARGET_IO('t', 31) - -#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) -#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) -#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ -#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ -#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ - -#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars) -#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars) -#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) -#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) - -#define TARGET_TIOCEXCL 0x540C -#define TARGET_TIOCNXCL 0x540D -#define TARGET_TIOCSCTTY 0x540E - -#define TARGET_TIOCSTI 0x5412 -#define TARGET_TIOCMGET 0x5415 -#define TARGET_TIOCMBIS 0x5416 -#define TARGET_TIOCMBIC 0x5417 -#define TARGET_TIOCMSET 0x5418 - -#define TARGET_TIOCGSOFTCAR 0x5419 -#define TARGET_TIOCSSOFTCAR 0x541A -#define TARGET_TIOCLINUX 0x541C -#define TARGET_TIOCCONS 0x541D -#define TARGET_TIOCGSERIAL 0x541E -#define TARGET_TIOCSSERIAL 0x541F -#define TARGET_TIOCPKT 0x5420 - -#define TARGET_TIOCNOTTY 0x5422 -#define TARGET_TIOCSETD 0x5423 -#define TARGET_TIOCGETD 0x5424 -#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ -#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ -#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ -#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ - -#define TARGET_TIOCSERCONFIG 0x5453 -#define TARGET_TIOCSERGWILD 0x5454 -#define TARGET_TIOCSERSWILD 0x5455 -#define TARGET_TIOCGLCKTRMIOS 0x5456 -#define TARGET_TIOCSLCKTRMIOS 0x5457 -#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ - /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ -# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ - -#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ - -- cgit v1.2.3 From 1e64e78d0c8861580a70c99f42d92e28b9a87af0 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 20 Oct 2007 07:07:47 +0000 Subject: Fix compiling Sparc64 on PPC host git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3411 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op.c | 3 +++ target-sparc/op_helper.c | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/target-sparc/op.c b/target-sparc/op.c index 80864c3bb..55ea2b9fe 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1711,6 +1711,9 @@ void OPPROTO op_fcmped_fcc3(void) /* Integer to float conversion. */ #ifdef USE_INT_TO_FLOAT_HELPERS F_HELPER(ito); +#ifdef TARGET_SPARC64 +F_HELPER(xto); +#endif #else F_OP(ito, s) { diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index ab456e30c..460ede249 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -69,6 +69,21 @@ void do_fitod(void) { DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); } +#ifdef TARGET_SPARC64 +void do_fxtos(void) +{ + set_float_exception_flags(0, &env->fp_status); + FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status); + check_ieee_exceptions(); +} + +void do_fxtod(void) +{ + set_float_exception_flags(0, &env->fp_status); + DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); + check_ieee_exceptions(); +} +#endif #endif void do_fabss(void) -- cgit v1.2.3 From 20b749f6079ba1f9a2959c88f22525d0fa49c1ac Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 20 Oct 2007 07:09:08 +0000 Subject: Avoid gcc warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3412 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 460ede249..7b1b08e43 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -806,7 +806,7 @@ void helper_ld_asi(int asi, int size, int sign) uint64_t ret = 0; if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV)) + || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) raise_exception(TT_PRIV_ACT); switch (asi) { @@ -1023,7 +1023,7 @@ void helper_ld_asi(int asi, int size, int sign) void helper_st_asi(int asi, int size) { if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) - || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV)) + || (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) raise_exception(TT_PRIV_ACT); /* Convert to little endian */ -- cgit v1.2.3 From a785e42e06ca502338e15cd87113049a6ae732b2 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 20 Oct 2007 08:09:05 +0000 Subject: Update Sparc parts in documentation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3413 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 14 ++++++++++++-- qemu-tech.texi | 10 ++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 6233ad1e9..4d31f648e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -242,7 +242,8 @@ Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. @item -smp n Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255 -CPUs are supported. +CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs +to 4. @item -audio-help @@ -1942,6 +1943,8 @@ More information is available at Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5 or SparcStation 10 (sun4m architecture). The emulation is somewhat complete. +SMP up to 16 CPUs is supported, but Linux limits the number of usable CPUs +to 4. QEMU emulates the following sun4m peripherals: @@ -1965,7 +1968,8 @@ Floppy drive CS4231 sound device (only on SS-5, not working yet) @end itemize -The number of peripherals is fixed in the architecture. +The number of peripherals is fixed in the architecture. Maximum memory size +depends on the machine type, for SS-5 it is 256MB and for SS-10 2047MB. Since version 0.8.2, QEMU uses OpenBIOS @url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable @@ -2382,6 +2386,12 @@ coldfire uClinux bFLT format binaries. The binary format is detected automatically. +@command{qemu-sparc32plus} can execute Sparc32 and SPARC32PLUS binaries +(Sparc64 CPU, 32 bit ABI). + +@command{qemu-sparc64} can execute some Sparc64 (Sparc64 CPU, 64 bit ABI) and +SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI). + @node Mac OS X/Darwin User space emulator @section Mac OS X/Darwin User space emulator diff --git a/qemu-tech.texi b/qemu-tech.texi index 242bbb641..9147096d9 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -199,9 +199,10 @@ FPU and MMU. @item Full SPARC V8 emulation, including privileged instructions, FPU and MMU. SPARC V9 emulation includes most privileged -instructions, FPU and I/D MMU, but misses most VIS instructions. +and VIS instructions, FPU and I/D MMU. Alignment is fully enforced. -@item Can run most 32-bit SPARC Linux binaries and some handcrafted 64-bit SPARC Linux binaries. +@item Can run most 32-bit SPARC Linux binaries, SPARC32PLUS Linux binaries and +some 64-bit SPARC Linux binaries. @end itemize @@ -212,10 +213,7 @@ Current QEMU limitations: @item IPC syscalls are missing. @item 128-bit floating point operations are not supported, though none of the -real CPUs implement them either. FCMPE[SD] are not correctly -implemented. Floating point exception support is untested. - -@item Alignment is not enforced at all. +real CPUs implement them either. Floating point exception support is untested. @item Atomic instructions are not correctly implemented. -- cgit v1.2.3 From 5a9b7d36a0730fa8992ee4cc05825bd0e9b184b0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 20 Oct 2007 09:13:55 +0000 Subject: Avoid PreP target kernel freeze waiting for IRQs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3414 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i8259.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i8259.c b/hw/i8259.c index 7c94d8d84..1e256d96b 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -164,7 +164,7 @@ void pic_update_irq(PicState2 *s) } /* all targets should do this rather than acking the IRQ in the cpu */ -#if defined(TARGET_MIPS) +#if defined(TARGET_MIPS) || defined(TARGET_PPC) else { qemu_irq_lower(s->parent_irq); } -- cgit v1.2.3 From 932a79df5d285d4fe48e7fce3b3c4f251d86af3f Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Oct 2007 18:29:34 +0000 Subject: Don't install tools if $(TOOLS) is empty, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3415 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 5ed7eb5c4..0eb39b5c0 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,9 @@ endif install: all $(if $(BUILD_DOCS),install-doc) mkdir -p "$(DESTDIR)$(bindir)" +ifneq ($(TOOLS),) $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)" +endif mkdir -p "$(DESTDIR)$(datadir)" for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ video.x openbios-sparc32 pxe-ne2k_pci.bin \ -- cgit v1.2.3 From 647de6ca243aab87a1fa480f3ffe4e64c922bcf2 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Oct 2007 19:45:44 +0000 Subject: Handle IBE on MIPS properly. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3416 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 2 +- target-mips/cpu.h | 3 +++ target-mips/op_helper.c | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/exec-all.h b/exec-all.h index 57086f3de..861688bd5 100644 --- a/exec-all.h +++ b/exec-all.h @@ -608,7 +608,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) } pd = env->tlb_table[mmu_idx][index].addr_code & ~TARGET_PAGE_MASK; if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { -#ifdef TARGET_SPARC +#if defined(TARGET_SPARC) || defined(TARGET_MIPS) do_unassigned_access(addr, 0, 1, 0); #else cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 35bf2fbf6..363fcd866 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -479,6 +479,9 @@ int mips_find_by_name (const unsigned char *name, mips_def_t **def); void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); int cpu_mips_register (CPUMIPSState *env, mips_def_t *def); +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, + int unused); + #define CPUState CPUMIPSState #define cpu_init cpu_mips_init #define cpu_exec cpu_mips_exec diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 6d7f750d0..f3e01202e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -591,6 +591,14 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) env = saved_env; } +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, + int unused) +{ + if (is_exec) + do_raise_exception(EXCP_IBE); + else + do_raise_exception(EXCP_DBE); +} #endif /* Complex FPU operations which may need stack space. */ -- cgit v1.2.3 From 1931e26054fdf2b1b84091f0b9662979eb6931ec Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Oct 2007 19:47:14 +0000 Subject: Check the Galilleo config register instead of hardcoding the endianness. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3417 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index fbebbbe6e..fdb70b3eb 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -306,9 +306,8 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, GT64120State *s = opaque; uint32_t saddr; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif + if (!(s->regs[GT_PCI0_CMD] & 1)) + val = bswap32(val); saddr = (addr & 0xfff) >> 2; switch (saddr) { @@ -528,8 +527,7 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, s->pci->config_reg = val & 0x80fffffc; break; case GT_PCI0_CFGDATA: - if (s->pci->config_reg & (1u << 31)) - pci_host_data_writel(s->pci, 0, val); + pci_host_data_writel(s->pci, 0, val); break; /* Interrupts */ @@ -585,9 +583,7 @@ static uint32_t gt64120_readl (void *opaque, uint32_t val; uint32_t saddr; - val = 0; saddr = (addr & 0xfff) >> 2; - switch (saddr) { /* CPU Configuration */ @@ -768,10 +764,7 @@ static uint32_t gt64120_readl (void *opaque, val = s->pci->config_reg; break; case GT_PCI0_CFGDATA: - if (!(s->pci->config_reg & (1u << 31))) - val = 0xffffffff; - else - val = pci_host_data_readl(s->pci, 0); + val = pci_host_data_readl(s->pci, 0); break; case GT_PCI0_CMD: @@ -844,9 +837,9 @@ static uint32_t gt64120_readl (void *opaque, break; } -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif + if (!(s->regs[GT_PCI0_CMD] & 1)) + val = bswap32(val); + return val; } @@ -1083,19 +1076,12 @@ void gt64120_reset(void *opaque) static uint32_t gt64120_read_config(PCIDevice *d, uint32_t address, int len) { - uint32_t val = pci_default_read_config(d, address, len); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; + return pci_default_read_config(d, address, len); } static void gt64120_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif pci_default_write_config(d, address, val, len); } -- cgit v1.2.3 From 0da46a6e2e5fc10b757612e9ac1707dc1fb6dc5a Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Oct 2007 20:23:07 +0000 Subject: Syscall target errno fixes, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3418 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 17 ++++--- linux-user/syscall.c | 138 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 100 insertions(+), 55 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index cacbc6992..0c5944aba 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -438,6 +438,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, } } +/* do_sigaltstack() returns target values and errnos. */ int do_sigaltstack(const struct target_sigaltstack *uss, struct target_sigaltstack *uoss, abi_ulong sp) @@ -457,18 +458,18 @@ int do_sigaltstack(const struct target_sigaltstack *uss, { struct target_sigaltstack ss; - ret = -EFAULT; + ret = -TARGET_EFAULT; if (!access_ok(VERIFY_READ, uss, sizeof(*uss)) || __get_user(ss.ss_sp, &uss->ss_sp) || __get_user(ss.ss_size, &uss->ss_size) || __get_user(ss.ss_flags, &uss->ss_flags)) goto out; - ret = -EPERM; + ret = -TARGET_EPERM; if (on_sig_stack(sp)) goto out; - ret = -EINVAL; + ret = -TARGET_EINVAL; if (ss.ss_flags != TARGET_SS_DISABLE && ss.ss_flags != TARGET_SS_ONSTACK && ss.ss_flags != 0) @@ -478,7 +479,7 @@ int do_sigaltstack(const struct target_sigaltstack *uss, ss.ss_size = 0; ss.ss_sp = 0; } else { - ret = -ENOMEM; + ret = -TARGET_ENOMEM; if (ss.ss_size < MINSIGSTKSZ) goto out; } @@ -488,7 +489,7 @@ int do_sigaltstack(const struct target_sigaltstack *uss, } if (uoss) { - ret = -EFAULT; + ret = -TARGET_EFAULT; if (!access_ok(VERIFY_WRITE, uoss, sizeof(oss))) goto out; memcpy(uoss, &oss, sizeof(oss)); @@ -499,12 +500,14 @@ out: return ret; } +/* do_sigaction() return host values and errnos */ int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact) { struct emulated_sigaction *k; struct sigaction act1; int host_sig; + int ret = 0; if (sig < 1 || sig > TARGET_NSIG || sig == SIGKILL || sig == SIGSTOP) return -EINVAL; @@ -546,10 +549,10 @@ int do_sigaction(int sig, const struct target_sigaction *act, } else { act1.sa_sigaction = host_signal_handler; } - sigaction(host_sig, &act1, NULL); + ret = sigaction(host_sig, &act1, NULL); } } - return 0; + return ret; } #ifndef offsetof diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e4ea31349..cf39f1535 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -167,6 +167,8 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ #ifdef __NR_gettid _syscall0(int, gettid) #else +/* This is a replacement for the host gettid() and must return a host + errno. */ static int gettid(void) { return -ENOSYS; } @@ -389,6 +391,7 @@ void target_set_brk(abi_ulong new_brk) target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); } +/* do_brk() must return target values and target errnos. */ abi_long do_brk(abi_ulong new_brk) { abi_ulong brk_page; @@ -398,7 +401,7 @@ abi_long do_brk(abi_ulong new_brk) if (!new_brk) return target_brk; if (new_brk < target_original_brk) - return -ENOMEM; + return -TARGET_ENOMEM; brk_page = HOST_PAGE_ALIGN(target_brk); @@ -532,6 +535,7 @@ static inline void host_to_target_timeval(abi_ulong target_addr, } +/* do_select() must return target values and target errnos. */ static abi_long do_select(int n, abi_ulong rfd_p, abi_ulong wfd_p, abi_ulong efd_p, abi_ulong target_tv) @@ -706,6 +710,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, msgh->msg_controllen = tswapl(space); } +/* do_setsockopt() Must return target values and target errnos. */ static abi_long do_setsockopt(int sockfd, int level, int optname, abi_ulong optval, socklen_t optlen) { @@ -716,7 +721,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, case SOL_TCP: /* TCP options all take an 'int' value. */ if (optlen < sizeof(uint32_t)) - return -EINVAL; + return -TARGET_EINVAL; val = tget32(optval); ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); @@ -814,7 +819,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, goto unimplemented; } if (optlen < sizeof(uint32_t)) - return -EINVAL; + return -TARGET_EINVAL; val = tget32(optval); ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); @@ -822,11 +827,12 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, default: unimplemented: gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname); - ret = -ENOSYS; + ret = -TARGET_ENOSYS; } return ret; } +/* do_getsockopt() Must return target values and target errnos. */ static abi_long do_getsockopt(int sockfd, int level, int optname, abi_ulong optval, abi_ulong optlen) { @@ -853,7 +859,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, int_case: len = tget32(optlen); if (len < 0) - return -EINVAL; + return -TARGET_EINVAL; lv = sizeof(int); ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); if (ret < 0) @@ -886,7 +892,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, case IP_MULTICAST_LOOP: len = tget32(optlen); if (len < 0) - return -EINVAL; + return -TARGET_EINVAL; lv = sizeof(int); ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); if (ret < 0) @@ -910,7 +916,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, unimplemented: gemu_log("getsockopt level=%d optname=%d not yet supported\n", level, optname); - ret = -ENOSYS; + ret = -TARGET_ENOSYS; break; } return ret; @@ -947,6 +953,7 @@ static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, unlock_user (target_vec, target_addr, 0); } +/* do_socket() Must return target values and target errnos. */ static abi_long do_socket(int domain, int type, int protocol) { #if defined(TARGET_MIPS) @@ -974,6 +981,7 @@ static abi_long do_socket(int domain, int type, int protocol) return get_errno(socket(domain, type, protocol)); } +/* do_bind() Must return target values and target errnos. */ static abi_long do_bind(int sockfd, abi_ulong target_addr, socklen_t addrlen) { @@ -983,6 +991,7 @@ static abi_long do_bind(int sockfd, abi_ulong target_addr, return get_errno(bind(sockfd, addr, addrlen)); } +/* do_connect() Must return target values and target errnos. */ static abi_long do_connect(int sockfd, abi_ulong target_addr, socklen_t addrlen) { @@ -992,6 +1001,7 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr, return get_errno(connect(sockfd, addr, addrlen)); } +/* do_sendrecvmsg() Must return target values and target errnos. */ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, int flags, int send) { @@ -1035,6 +1045,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, return ret; } +/* do_accept() Must return target values and target errnos. */ static abi_long do_accept(int fd, abi_ulong target_addr, abi_ulong target_addrlen) { @@ -1050,6 +1061,7 @@ static abi_long do_accept(int fd, abi_ulong target_addr, return ret; } +/* do_getpeername() Must return target values and target errnos. */ static abi_long do_getpeername(int fd, abi_ulong target_addr, abi_ulong target_addrlen) { @@ -1065,6 +1077,7 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr, return ret; } +/* do_getsockname() Must return target values and target errnos. */ static abi_long do_getsockname(int fd, abi_ulong target_addr, abi_ulong target_addrlen) { @@ -1080,6 +1093,7 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr, return ret; } +/* do_socketpair() Must return target values and target errnos. */ static abi_long do_socketpair(int domain, int type, int protocol, abi_ulong target_tab) { @@ -1094,6 +1108,7 @@ static abi_long do_socketpair(int domain, int type, int protocol, return ret; } +/* do_sendto() Must return target values and target errnos. */ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, abi_ulong target_addr, socklen_t addrlen) { @@ -1113,6 +1128,7 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, return ret; } +/* do_recvfrom() Must return target values and target errnos. */ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, abi_ulong target_addr, abi_ulong target_addrlen) @@ -1144,6 +1160,7 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, } #ifdef TARGET_NR_socketcall +/* do_socketcall() Must return target values and target errnos. */ static abi_long do_socketcall(int num, abi_ulong vptr) { abi_long ret; @@ -1301,7 +1318,7 @@ static abi_long do_socketcall(int num, abi_ulong vptr) break; default: gemu_log("Unsupported socketcall: %d\n", num); - ret = -ENOSYS; + ret = -TARGET_ENOSYS; break; } return ret; @@ -1639,6 +1656,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, } /* ??? This only works with linear mappings. */ +/* do_ipc() must return target values and target errnos. */ static abi_long do_ipc(unsigned int call, int first, int second, int third, abi_long ptr, abi_long fifth) @@ -1667,7 +1685,7 @@ static abi_long do_ipc(unsigned int call, int first, case IPCOP_semtimedop: gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); - ret = -ENOSYS; + ret = -TARGET_ENOSYS; break; case IPCOP_msgget: @@ -1723,7 +1741,7 @@ static abi_long do_ipc(unsigned int call, int first, } } if (put_user(raddr, (abi_ulong *)third)) - return -EFAULT; + return -TARGET_EFAULT; ret = 0; break; case IPCOP_shmdt: @@ -1757,7 +1775,7 @@ static abi_long do_ipc(unsigned int call, int first, default: unimplemented: gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); - ret = -ENOSYS; + ret = -TARGET_ENOSYS; break; } return ret; @@ -1803,6 +1821,7 @@ IOCTLEntry ioctl_entries[] = { }; /* ??? Implement proper locking for ioctls. */ +/* do_ioctl() Must return target values and target errnos. */ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) { const IOCTLEntry *ie; @@ -1816,7 +1835,7 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) for(;;) { if (ie->target_cmd == 0) { gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd); - return -ENOSYS; + return -TARGET_ENOSYS; } if (ie->target_cmd == cmd) break; @@ -1871,7 +1890,7 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) default: gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", (long)cmd, arg_type[0]); - ret = -ENOSYS; + ret = -TARGET_ENOSYS; break; } return ret; @@ -2106,6 +2125,7 @@ static int read_ldt(abi_ulong ptr, unsigned long bytecount) } /* XXX: add locking support */ +/* write_ldt() returns host errnos */ static int write_ldt(CPUX86State *env, abi_ulong ptr, unsigned long bytecount, int oldmode) { @@ -2188,6 +2208,8 @@ install: } /* specific and weird i386 syscalls */ +/* do_modify_ldt() returns host errnos (it is inconsistent with the + other do_*() functions which return target errnos). */ int do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, unsigned long bytecount) { int ret = -ENOSYS; @@ -2220,6 +2242,8 @@ static int clone_func(void *arg) return 0; } +/* do_fork() Must return host values and target errnos (unlike most + do_*() functions). */ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp) { int ret; @@ -2547,6 +2571,9 @@ static inline void host_to_target_timespec(abi_ulong target_addr, unlock_user_struct(target_ts, target_addr, 1); } +/* do_syscall() should always have a single exit point at the end so + that actions, such as logging of syscall results, can be performed. + All errnos that do_syscall() returns must be -TARGET_. */ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6) @@ -2590,12 +2617,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_openat) && defined(__NR_openat) case TARGET_NR_openat: if (!arg2) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; } p = lock_user_string(arg2); if (!access_ok(VERIFY_READ, p, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_openat(arg1, path(p), @@ -2644,16 +2672,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_linkat) && defined(__NR_linkat) case TARGET_NR_linkat: if (!arg2 || !arg4) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; - } + } { void * p2 = NULL; p = lock_user_string(arg2); p2 = lock_user_string(arg4); if (!access_ok(VERIFY_READ, p, 1) || !access_ok(VERIFY_READ, p2, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5)); if (p2) @@ -2671,12 +2700,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) case TARGET_NR_unlinkat: if (!arg2) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; } p = lock_user_string(arg2); if (!access_ok(VERIFY_READ, p, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_unlinkat(arg1, p, arg3)); if (p) @@ -2762,12 +2792,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) case TARGET_NR_mknodat: if (!arg2) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; } p = lock_user_string(arg2); if (!access_ok(VERIFY_READ, p, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); if (p) @@ -2894,12 +2925,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) case TARGET_NR_faccessat: if (!arg2) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; } p = lock_user_string(arg2); if (!access_ok(VERIFY_READ, p, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); if (p) @@ -2935,8 +2967,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_renameat) && defined(__NR_renameat) case TARGET_NR_renameat: if (!arg2 || !arg4) { - ret = -EFAULT; - goto fail; + ret = -TARGET_EFAULT; + goto fail; } { void *p2 = NULL; @@ -2944,7 +2976,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, p2 = lock_user_string(arg4); if (!access_ok(VERIFY_READ, p, 1) || !access_ok(VERIFY_READ, p2, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_renameat(arg1, p, arg3, p2)); if (p2) @@ -2962,12 +2995,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) case TARGET_NR_mkdirat: if (!arg2) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; } p = lock_user_string(arg2); if (!access_ok(VERIFY_READ, p, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_mkdirat(arg1, p, arg3)); if (p) @@ -3202,7 +3236,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, how = SIG_SETMASK; break; default: - ret = -EINVAL; + ret = -TARGET_EINVAL; goto fail; } p = lock_user(arg2, sizeof(target_sigset_t), 1); @@ -3239,7 +3273,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, how = SIG_SETMASK; break; default: - ret = -EINVAL; + ret = -TARGET_EINVAL; goto fail; } p = lock_user(arg2, sizeof(target_sigset_t), 1); @@ -3434,16 +3468,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) case TARGET_NR_symlinkat: if (!arg1 || !arg3) { - ret = -EFAULT; - goto fail; - } + ret = -TARGET_EFAULT; + goto fail; + } { void *p2 = NULL; p = lock_user_string(arg1); p2 = lock_user_string(arg3); if (!access_ok(VERIFY_READ, p, 1) || !access_ok(VERIFY_READ, p2, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_symlinkat(p, arg2, p2)); if (p2) @@ -3470,16 +3505,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) case TARGET_NR_readlinkat: if (!arg2 || !arg3) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; - } + } { void *p2 = NULL; p = lock_user_string(arg2); p2 = lock_user(arg3, arg4, 0); if (!access_ok(VERIFY_READ, p, 1) || !access_ok(VERIFY_READ, p2, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4)); if (p2) @@ -3596,12 +3632,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) case TARGET_NR_fchmodat: if (!arg2) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; } p = lock_user_string(arg2); if (!access_ok(VERIFY_READ, p, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); if (p) @@ -4055,8 +4092,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long count = arg3; dirp = malloc(count); - if (!dirp) - return -ENOMEM; + if (!dirp) { + ret = -TARGET_EFAULT; + goto fail; + } ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { @@ -4213,9 +4252,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR__sysctl: - /* We don't implement this, but ENODIR is always a safe + /* We don't implement this, but ENOTDIR is always a safe return value. */ - return -ENOTDIR; + ret = -TARGET_ENOTDIR; + break; case TARGET_NR_sched_setparam: { struct sched_param *target_schp; @@ -4514,12 +4554,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) case TARGET_NR_fchownat: if (!arg2) { - ret = -EFAULT; + ret = -TARGET_EFAULT; goto fail; } p = lock_user_string(arg2); if (!access_ok(VERIFY_READ, p, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); if (p) @@ -4958,7 +4999,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, else { p = lock_user_string(arg2); if (!access_ok(VERIFY_READ, p, 1)) - ret = -EFAULT; + /* Don't "goto fail" so that cleanup can happen. */ + ret = -TARGET_EFAULT; else ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); if (p) @@ -4974,7 +5016,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list) unimplemented_nowarn: #endif - ret = -ENOSYS; + ret = -TARGET_ENOSYS; break; } fail: -- cgit v1.2.3 From 3f6ffb6ac9709b6b9422e20c29f6bf4556c3af09 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Oct 2007 20:36:52 +0000 Subject: Enable ACPI interrupts, by Igor Lvovsky. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3419 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/piix_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 8c00f0d13..3c04e3a08 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -208,6 +208,7 @@ static void piix3_set_irq(qemu_irq *pic, int irq_num, int level) { int i, pic_irq, pic_level; + piix3_dev->config[0x60 + irq_num] &= ~0x80; // enable bit pci_irq_levels[irq_num] = level; /* now we change the pic irq level according to the piix irq mappings */ -- cgit v1.2.3 From e9c0822655af530f534e0597575b69d5e5f2fa66 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Oct 2007 20:40:05 +0000 Subject: Physical hard disk drive for win32, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3420 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/block-raw.c b/block-raw.c index 2f2e19f9b..1e5e5d15e 100644 --- a/block-raw.c +++ b/block-raw.c @@ -1174,7 +1174,7 @@ static int64_t raw_getlength(BlockDriverState *bs) BDRVRawState *s = bs->opaque; LARGE_INTEGER l; ULARGE_INTEGER available, total, total_free; - DISK_GEOMETRY dg; + DISK_GEOMETRY_EX dg; DWORD count; BOOL status; @@ -1190,11 +1190,10 @@ static int64_t raw_getlength(BlockDriverState *bs) l.QuadPart = total.QuadPart; break; case FTYPE_HARDDISK: - status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY, + status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &dg, sizeof(dg), &count, NULL); - if (status != FALSE) { - l.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder - * dg.SectorsPerTrack * dg.BytesPerSector; + if (status != 0) { + l = dg.DiskSize; } break; default: -- cgit v1.2.3 From a47b8d38b79b5208fb96464a92c3cd7ae3d51ac0 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 20 Oct 2007 20:48:09 +0000 Subject: "QEMU keyboard issue with Gujin-2.2", by Etienne Lorrain. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3421 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pckbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pckbd.c b/hw/pckbd.c index ff4916d21..9b96b1cba 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -207,7 +207,7 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) #endif switch(val) { case KBD_CCMD_READ_MODE: - kbd_queue(s, s->mode, 0); + kbd_queue(s, s->mode, 1); break; case KBD_CCMD_WRITE_MODE: case KBD_CCMD_WRITE_OBUF: -- cgit v1.2.3 From 615e2dba4f9d6f06fb7dcd3b13f20bac5d8e274d Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 21 Oct 2007 09:46:04 +0000 Subject: New status file for Alpha emulation target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3422 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/STATUS | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 target-alpha/STATUS diff --git a/target-alpha/STATUS b/target-alpha/STATUS new file mode 100644 index 000000000..8b7f352fb --- /dev/null +++ b/target-alpha/STATUS @@ -0,0 +1,33 @@ +(to be completed) + +Alpha emulation structure: +cpu.h : CPU definitions globally exported +exec.h : CPU definitions used only for translated code execution +helper.c : helpers that can be called either by the translated code + or the Qemu core, including the exception handler. +op.c : Alpha dedicated micro-operations used by the code translator +op_helper.c : helpers that can be called only from micro-operations +op_helper.h : micro-operations helpers prototypes +op_helper_mem.h : micro-operations templates + for load and stores accesses helpers +op_mem.h : micro-operations templates for load and stores accesses +op_template.h : micro-operation templates for register moves +translate.c : Alpha instructions to micro-operations translator + +Code translator status: +The Alpha CPU instruction emulation should be quite complete with the +limitation that the VAX floating-point load and stores are not implemented. +The 4 MMU modes are implemented. + +Linux user mode emulation status: +a few programs start to run. Most crash at a certain point, dereferencing a +NULL pointer. It seems that the UNIQUE register is not initialized properly. +It may appear that old executables, not relying on TLS support, run but +this is to be prooved... + +Full system emulation status: +* Alpha PALCode emulation is in a very early stage and is not sufficient + to run any real OS. The alpha-softmmu target is not enabled for now. +* no hardware platform description is implemented +* there might be problems in the Alpha PALCode dedicated instructions + that would prevent to use a native PALCode image. -- cgit v1.2.3 From bd3e2c4e696cc03d8de335ef5f6f3f22ac82132a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 21 Oct 2007 12:29:36 +0000 Subject: Allow use of PCI NICs on PowerPC PreP platform. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3423 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 2c4b24203..cafe88dc8 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -636,13 +636,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "ne2k_isa") == 0) { isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]); - } else if (strcmp(nd_table[0].model, "?") == 0) { - fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n"); - exit (1); } else { - /* Why ? */ - cpu_abort(env, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); + pci_nic_init(pci_bus, &nd_table[i], -1); } } -- cgit v1.2.3 From fce62c4eb3582a914b0c1a1d070b5924436b107b Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 21 Oct 2007 15:53:01 +0000 Subject: Bugfix: now PCI NICs really work on PowerPC PreP platform. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3424 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index cafe88dc8..7cb92c77f 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -633,8 +633,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; for(i = 0; i < nb_nics1; i++) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "ne2k_isa") == 0) { + if (nd_table[i].model == NULL + || strcmp(nd_table[i].model, "ne2k_isa") == 0) { isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]); } else { pci_nic_init(pci_bus, &nd_table[i], -1); -- cgit v1.2.3 From b46a8906b34828adec2702f1e918fc9f553f2ad3 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 21 Oct 2007 23:20:45 +0000 Subject: Support tap down script, by Wolfram Gloger. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3425 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/vl.c b/vl.c index 6d8fe3542..2f3d8d04e 100644 --- a/vl.c +++ b/vl.c @@ -117,6 +117,7 @@ int inet_aton(const char *cp, struct in_addr *ia); #include "exec-all.h" #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" +#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" #ifdef __sun__ #define SMBD_COMMAND "/usr/sfw/sbin/smbd" #else @@ -3789,6 +3790,7 @@ void net_slirp_smb(const char *exported_dir) typedef struct TAPState { VLANClientState *vc; int fd; + char down_script[1024]; } TAPState; static void tap_receive(void *opaque, const uint8_t *buf, int size) @@ -4024,27 +4026,13 @@ static int tap_open(char *ifname, int ifname_size) } #endif -static int net_tap_init(VLANState *vlan, const char *ifname1, - const char *setup_script) +static int launch_script(const char *setup_script, const char *ifname, int fd) { - TAPState *s; - int pid, status, fd; + int pid, status; char *args[3]; char **parg; - char ifname[128]; - - if (ifname1 != NULL) - pstrcpy(ifname, sizeof(ifname), ifname1); - else - ifname[0] = '\0'; - TFR(fd = tap_open(ifname, sizeof(ifname))); - if (fd < 0) - return -1; - if (!setup_script || !strcmp(setup_script, "no")) - setup_script = ""; - if (setup_script[0] != '\0') { - /* try to launch network init script */ + /* try to launch network script */ pid = fork(); if (pid >= 0) { if (pid == 0) { @@ -4058,7 +4046,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, parg = args; *parg++ = (char *)setup_script; - *parg++ = ifname; + *parg++ = (char *)ifname; *parg++ = NULL; execv(setup_script, args); _exit(1); @@ -4071,12 +4059,37 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, return -1; } } + return 0; +} + +static int net_tap_init(VLANState *vlan, const char *ifname1, + const char *setup_script, const char *down_script) +{ + TAPState *s; + int fd; + char ifname[128]; + + if (ifname1 != NULL) + pstrcpy(ifname, sizeof(ifname), ifname1); + else + ifname[0] = '\0'; + TFR(fd = tap_open(ifname, sizeof(ifname))); + if (fd < 0) + return -1; + + if (!setup_script || !strcmp(setup_script, "no")) + setup_script = ""; + if (setup_script[0] != '\0') { + if (launch_script(setup_script, ifname, fd)) + return -1; } s = net_tap_fd_init(vlan, fd); if (!s) return -1; snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s setup_script=%s", ifname, setup_script); + if (down_script && strcmp(down_script, "no")) + snprintf(s->down_script, sizeof(s->down_script), "%s", down_script); return 0; } @@ -4620,7 +4633,7 @@ static int net_client_init(const char *str) #else if (!strcmp(device, "tap")) { char ifname[64]; - char setup_script[1024]; + char setup_script[1024], down_script[1024]; int fd; vlan->nb_host_devs++; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { @@ -4635,7 +4648,10 @@ static int net_client_init(const char *str) if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); } - ret = net_tap_init(vlan, ifname, setup_script); + if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) { + pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT); + } + ret = net_tap_init(vlan, ifname, setup_script, down_script); } } else #endif @@ -7022,10 +7038,11 @@ static void help(int exitcode) "-net tap[,vlan=n],ifname=name\n" " connect the host TAP network interface to VLAN 'n'\n" #else - "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n" - " connect the host TAP network interface to VLAN 'n' and use\n" - " the network script 'file' (default=%s);\n" - " use 'script=no' to disable script execution;\n" + "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file][,downscript=dfile]\n" + " connect the host TAP network interface to VLAN 'n' and use the\n" + " network scripts 'file' (default=%s)\n" + " and 'dfile' (default=%s);\n" + " use '[down]script=no' to disable script execution;\n" " use 'fd=h' to connect to an already opened TAP interface\n" #endif "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n" @@ -7098,6 +7115,7 @@ static void help(int exitcode) DEFAULT_RAM_SIZE, #ifndef _WIN32 DEFAULT_NETWORK_SCRIPT, + DEFAULT_NETWORK_DOWN_SCRIPT, #endif DEFAULT_GDBSTUB_PORT, "/tmp/qemu.log"); @@ -8459,5 +8477,22 @@ int main(int argc, char **argv) main_loop(); quit_timers(); + + /* close network clients */ + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + VLANClientState *vc; + + for(vc = vlan->first_client; vc != NULL; vc = vc->next) +#if !defined(_WIN32) + if (vc->fd_read == tap_receive) { + char ifname[64]; + TAPState *s = vc->opaque; + + if (sscanf(vc->info_str, "tap: ifname=%63s ", ifname) == 1 && + s->down_script[0]) + launch_script(s->down_script, ifname, s->fd); + } +#endif + } return 0; } -- cgit v1.2.3 From d8a5950a62ee91d7fd8ed5ba459992b55e9cb3b7 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 23 Oct 2007 13:15:33 +0000 Subject: Switch bc1any* instructions off if no MIPS-3D is implemented. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3426 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index d69edea30..014a430e4 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -749,6 +749,12 @@ static always_inline void check_cp1_64bitmode(DisasContext *ctx) generate_exception(ctx, EXCP_RI); } +static always_inline void check_cp1_3d(CPUState *env, DisasContext *ctx) +{ + if (unlikely(!(env->fpu->fcr0 & (1 << FCR0_3D)))) + generate_exception(ctx, EXCP_RI); +} + /* * Verify if floating point register is valid; an operation is not defined * if bit 0 of any register specification is set and the FR bit in the @@ -6328,9 +6334,11 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_cp1(ctx, op1, rt, rd); break; #endif - case OPC_BC1: case OPC_BC1ANY2: case OPC_BC1ANY4: + check_cp1_3d(env, ctx); + /* fall through */ + case OPC_BC1: gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); return; -- cgit v1.2.3 From 7385ac0ba2456159a52b9b2cbb5f6c71921d0c23 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 23 Oct 2007 17:04:27 +0000 Subject: Use the standard ASE check for MIPS-3D and MT. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3427 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/mips-defs.h | 2 + target-mips/translate.c | 169 ++++++++++++++++++++----------------------- target-mips/translate_init.c | 2 +- 3 files changed, 80 insertions(+), 93 deletions(-) diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 5c98edf97..a30f2edae 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -32,6 +32,8 @@ #define ASE_MDMX 0x00004000 #define ASE_DSP 0x00008000 #define ASE_DSPR2 0x00010000 +#define ASE_MT 0x00020000 +#define ASE_SMARTMIPS 0x00040000 /* Chip specific instructions. */ /* Currently void */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 014a430e4..3a1f65c4c 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -749,12 +749,6 @@ static always_inline void check_cp1_64bitmode(DisasContext *ctx) generate_exception(ctx, EXCP_RI); } -static always_inline void check_cp1_3d(CPUState *env, DisasContext *ctx) -{ - if (unlikely(!(env->fpu->fcr0 & (1 << FCR0_3D)))) - generate_exception(ctx, EXCP_RI); -} - /* * Verify if floating point register is valid; an operation is not defined * if bit 0 of any register specification is set and the FR bit in the @@ -780,14 +774,6 @@ static always_inline void check_insn(CPUState *env, DisasContext *ctx, int flags generate_exception(ctx, EXCP_RI); } -/* This code generates a "reserved instruction" exception if the - CPU is not MIPS MT capable. */ -static always_inline void check_mips_mt(CPUState *env, DisasContext *ctx) -{ - if (unlikely(!(env->CP0_Config3 & (1 << CP0C3_MT)))) - generate_exception(ctx, EXCP_RI); -} - /* This code generates a "reserved instruction" exception if 64-bit instructions are not enabled. */ static always_inline void check_mips_64(DisasContext *ctx) @@ -1971,17 +1957,17 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_mvpcontrol(); rn = "MVPControl"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_mvpconf0(); rn = "MVPConf0"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_mvpconf1(); rn = "MVPConf1"; break; @@ -1996,37 +1982,37 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpecontrol(); rn = "VPEControl"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpeconf0(); rn = "VPEConf0"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpeconf1(); rn = "VPEConf1"; break; case 4: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_yqmask(); rn = "YQMask"; break; case 5: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpeschedule(); rn = "VPESchedule"; break; case 6: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpeschefback(); rn = "VPEScheFBack"; break; case 7: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpeopt(); rn = "VPEOpt"; break; @@ -2041,37 +2027,37 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tcstatus(); rn = "TCStatus"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tcbind(); rn = "TCBind"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tcrestart(); rn = "TCRestart"; break; case 4: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tchalt(); rn = "TCHalt"; break; case 5: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tccontext(); rn = "TCContext"; break; case 6: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tcschedule(); rn = "TCSchedule"; break; case 7: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tcschefback(); rn = "TCScheFBack"; break; @@ -2539,17 +2525,17 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_mvpcontrol(); rn = "MVPControl"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); /* ignored */ rn = "MVPConf0"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); /* ignored */ rn = "MVPConf1"; break; @@ -2564,37 +2550,37 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpecontrol(); rn = "VPEControl"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeconf0(); rn = "VPEConf0"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeconf1(); rn = "VPEConf1"; break; case 4: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_yqmask(); rn = "YQMask"; break; case 5: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeschedule(); rn = "VPESchedule"; break; case 6: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeschefback(); rn = "VPEScheFBack"; break; case 7: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeopt(); rn = "VPEOpt"; break; @@ -2609,37 +2595,37 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcstatus(); rn = "TCStatus"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcbind(); rn = "TCBind"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcrestart(); rn = "TCRestart"; break; case 4: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tchalt(); rn = "TCHalt"; break; case 5: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tccontext(); rn = "TCContext"; break; case 6: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcschedule(); rn = "TCSchedule"; break; case 7: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcschefback(); rn = "TCScheFBack"; break; @@ -3139,17 +3125,17 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_mvpcontrol(); rn = "MVPControl"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_mvpconf0(); rn = "MVPConf0"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_mvpconf1(); rn = "MVPConf1"; break; @@ -3164,37 +3150,37 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpecontrol(); rn = "VPEControl"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpeconf0(); rn = "VPEConf0"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpeconf1(); rn = "VPEConf1"; break; case 4: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmfc0_yqmask(); rn = "YQMask"; break; case 5: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmfc0_vpeschedule(); rn = "VPESchedule"; break; case 6: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmfc0_vpeschefback(); rn = "VPEScheFBack"; break; case 7: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_vpeopt(); rn = "VPEOpt"; break; @@ -3209,37 +3195,37 @@ static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tcstatus(); rn = "TCStatus"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mfc0_tcbind(); rn = "TCBind"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmfc0_tcrestart(); rn = "TCRestart"; break; case 4: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmfc0_tchalt(); rn = "TCHalt"; break; case 5: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmfc0_tccontext(); rn = "TCContext"; break; case 6: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmfc0_tcschedule(); rn = "TCSchedule"; break; case 7: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmfc0_tcschefback(); rn = "TCScheFBack"; break; @@ -3696,17 +3682,17 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Index"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_mvpcontrol(); rn = "MVPControl"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); /* ignored */ rn = "MVPConf0"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); /* ignored */ rn = "MVPConf1"; break; @@ -3721,37 +3707,37 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "Random"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpecontrol(); rn = "VPEControl"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeconf0(); rn = "VPEConf0"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeconf1(); rn = "VPEConf1"; break; case 4: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_yqmask(); rn = "YQMask"; break; case 5: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeschedule(); rn = "VPESchedule"; break; case 6: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeschefback(); rn = "VPEScheFBack"; break; case 7: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_vpeopt(); rn = "VPEOpt"; break; @@ -3766,37 +3752,37 @@ static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) rn = "EntryLo0"; break; case 1: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcstatus(); rn = "TCStatus"; break; case 2: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcbind(); rn = "TCBind"; break; case 3: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcrestart(); rn = "TCRestart"; break; case 4: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tchalt(); rn = "TCHalt"; break; case 5: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tccontext(); rn = "TCContext"; break; case 6: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcschedule(); rn = "TCSchedule"; break; case 7: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_mtc0_tcschefback(); rn = "TCScheFBack"; break; @@ -4636,7 +4622,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; #endif case OPC_MFTR: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); if (rd == 0) { /* Treat as NOP. */ return; @@ -4647,7 +4633,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int opn = "mftr"; break; case OPC_MTTR: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); GEN_LOAD_REG_TN(T0, rt); gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1, ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); @@ -5893,7 +5879,6 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) /* MDMX extension to MIPS64 */ -/* MIPS-3D extension to MIPS64 */ #endif @@ -6133,13 +6118,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx) GEN_STORE_TN_REG(rt, T0); break; case OPC_FORK: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); GEN_LOAD_REG_TN(T0, rt); GEN_LOAD_REG_TN(T1, rs); gen_op_fork(); break; case OPC_YIELD: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); GEN_LOAD_REG_TN(T0, rs); gen_op_yield(); GEN_STORE_TN_REG(rd, T0); @@ -6219,19 +6204,19 @@ static void decode_opc (CPUState *env, DisasContext *ctx) op2 = MASK_MFMC0(ctx->opcode); switch (op2) { case OPC_DMT: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dmt(); break; case OPC_EMT: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_emt(); break; case OPC_DVPE: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_dvpe(); break; case OPC_EVPE: - check_mips_mt(env, ctx); + check_insn(env, ctx, ASE_MT); gen_op_evpe(); break; case OPC_DI: @@ -6336,7 +6321,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) #endif case OPC_BC1ANY2: case OPC_BC1ANY4: - check_cp1_3d(env, ctx); + check_insn(env, ctx, ASE_MIPS3D); /* fall through */ case OPC_BC1: gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode), diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 748b9dd85..55c935e6d 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -199,7 +199,7 @@ static mips_def_t mips_defs[] = .CP0_SRSConf4_rw_bitmask = 0x3fffffff, .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) | (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13), - .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_MT, }, #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) { -- cgit v1.2.3 From 9278480e8f9155fc3b3ce459efd12b500a611b7f Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 23 Oct 2007 23:22:03 +0000 Subject: Fix CLO calculation for MIPS64. And a small code cleanup. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3428 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 3aefec249..ca367d763 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -543,9 +543,9 @@ void op_clo (void) T0 = 32; } else { for (n = 0; n < 32; n++) { - if (!(T0 & (1 << 31))) + if (!(((int32_t)T0) & (1 << 31))) break; - T0 = T0 << 1; + T0 <<= 1; } T0 = n; } @@ -562,7 +562,7 @@ void op_clz (void) for (n = 0; n < 32; n++) { if (T0 & (1 << 31)) break; - T0 = T0 << 1; + T0 <<= 1; } T0 = n; } @@ -747,7 +747,7 @@ void op_dclo (void) for (n = 0; n < 64; n++) { if (!(T0 & (1ULL << 63))) break; - T0 = T0 << 1; + T0 <<= 1; } T0 = n; } @@ -764,7 +764,7 @@ void op_dclz (void) for (n = 0; n < 64; n++) { if (T0 & (1ULL << 63)) break; - T0 = T0 << 1; + T0 <<= 1; } T0 = n; } -- cgit v1.2.3 From 67fc07d3fba681f3362f7644a69b7a581a2670e8 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 23 Oct 2007 23:22:54 +0000 Subject: Fix overflow when multiplying two large positive numbers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3429 c046a42c-6fe2-441c-8c8c-71466251a162 --- host-utils.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/host-utils.c b/host-utils.c index 10341063f..cf2c6f8f1 100644 --- a/host-utils.c +++ b/host-utils.c @@ -43,7 +43,8 @@ void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b) ph = (a >> 32) * (b >> 32); ph += (int64_t)pm1 >> 32; - pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32); + ph += (int64_t)pm2 >> 32; + pm1 = (uint64_t)((uint32_t)pm1) + (uint64_t)((uint32_t)pm2) + (pl >> 32); *phigh = ph + ((int64_t)pm1 >> 32); *plow = (pm1 << 32) + (uint32_t)pl; @@ -67,7 +68,8 @@ void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b) ph = (a >> 32) * (b >> 32); ph += pm1 >> 32; - pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32); + ph += pm2 >> 32; + pm1 = (uint64_t)((uint32_t)pm1) + (uint64_t)((uint32_t)pm2) + (pl >> 32); *phigh = ph + (pm1 >> 32); *plow = (pm1 << 32) + (uint32_t)pl; -- cgit v1.2.3 From 7d307e9edc944e255fc3462ff536ffeb78ac2c68 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 23 Oct 2007 23:23:43 +0000 Subject: Enforce proper sign extension for lwl/lwr on MIPS64. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3430 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op_mem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index d402d616b..42f5e2ba3 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -89,7 +89,7 @@ void glue(op_lwl, MEMSUFFIX) (void) target_ulong tmp; tmp = glue(ldub, MEMSUFFIX)(T0); - T1 = (int32_t)((T1 & 0x00FFFFFF) | (tmp << 24)); + T1 = (T1 & 0x00FFFFFF) | (tmp << 24); if (GET_LMASK(T0) <= 2) { tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 1)); @@ -105,6 +105,7 @@ void glue(op_lwl, MEMSUFFIX) (void) tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, 3)); T1 = (T1 & 0xFFFFFF00) | tmp; } + T1 = (int32_t)T1; RETURN(); } @@ -129,6 +130,7 @@ void glue(op_lwr, MEMSUFFIX) (void) tmp = glue(ldub, MEMSUFFIX)(GET_OFFSET(T0, -3)); T1 = (T1 & 0x00FFFFFF) | (tmp << 24); } + T1 = (int32_t)T1; RETURN(); } -- cgit v1.2.3 From 60445285a84915cc4a064acf0a3d15e89f9fac40 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 23 Oct 2007 23:58:21 +0000 Subject: Fix writable length of the index register. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3431 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target-mips/op.c b/target-mips/op.c index ca367d763..a666006ad 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1481,7 +1481,14 @@ void op_mfc0_desave (void) void op_mtc0_index (void) { - env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->tlb->nb_tlb); + int num = 1; + unsigned int tmp = env->tlb->nb_tlb; + + do { + tmp >>= 1; + num <<= 1; + } while (tmp); + env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 & (num - 1)); RETURN(); } -- cgit v1.2.3 From 6ad3872210a45b6741803bd692ee0c38472d9392 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Oct 2007 00:10:32 +0000 Subject: Force proper sign extension for mfc0/mfhc0 on MIPS64. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3432 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index a666006ad..5c26d176c 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -2328,7 +2328,7 @@ void op_ctc1 (void) void op_mfc1 (void) { - T0 = WT0; + T0 = (int32_t)WT0; DEBUG_FPU_STATE(); RETURN(); } @@ -2356,7 +2356,7 @@ void op_dmtc1 (void) void op_mfhc1 (void) { - T0 = WTH0; + T0 = (int32_t)WTH0; DEBUG_FPU_STATE(); RETURN(); } -- cgit v1.2.3 From 9f77c1cdcff154cfd095309bce37cea818b3226c Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Oct 2007 00:52:07 +0000 Subject: Remove bogus instruction decode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3433 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 3a1f65c4c..89fe5fe23 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -5400,7 +5400,6 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, opn = "cvt.d.l"; break; case FOP(38, 20): - case FOP(38, 21): check_cp1_64bitmode(ctx); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); -- cgit v1.2.3 From d8871c5a490c29c579bf981b955d9d3f970e15bd Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 24 Oct 2007 16:11:42 +0000 Subject: Fix typo, spotted by Edivaldo de Araujo Pereira. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3434 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index d0210825c..b84b75b43 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -269,9 +269,9 @@ static int img_create(int argc, char **argv) case 'e': flags |= BLOCK_FLAG_ENCRYPT; break; - case '6': + case '6': flags |= BLOCK_FLAG_COMPAT6; - break; + break; } } if (optind >= argc) @@ -471,7 +471,7 @@ static int img_convert(int argc, char **argv) error("Compression not supported for this file format"); if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2) error("Encryption not supported for this file format"); - if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_vmdk) + if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk) error("Alternative compatibility level not supported for this file format"); if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS) error("Compression and encryption not supported at the same time"); -- cgit v1.2.3 From 7ac256b8725304aabae78bf012c25b6416509c46 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 25 Oct 2007 21:30:37 +0000 Subject: Fix gdb stub for MIPS64. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3435 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 139bc25fc..37dc764f5 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -563,7 +563,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) ptr += sizeof(target_ulong); } - *(target_ulong *)ptr = tswapl(env->CP0_Status); + *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Status); ptr += sizeof(target_ulong); *(target_ulong *)ptr = tswapl(env->LO[0][env->current_tc]); @@ -575,7 +575,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->CP0_Cause); + *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Cause); ptr += sizeof(target_ulong); *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]); @@ -585,19 +585,34 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { for (i = 0; i < 32; i++) { - *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].fs[FP_ENDIAN_IDX]); + if (env->CP0_Status & (1 << CP0St_FR)) + *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].d); + else + *(target_ulong *)ptr = tswap32(env->fpu->fpr[i].w[FP_ENDIAN_IDX]); ptr += sizeof(target_ulong); } - *(target_ulong *)ptr = tswapl(env->fpu->fcr31); + *(target_ulong *)ptr = (int32_t)tswap32(env->fpu->fcr31); ptr += sizeof(target_ulong); - *(target_ulong *)ptr = tswapl(env->fpu->fcr0); + *(target_ulong *)ptr = (int32_t)tswap32(env->fpu->fcr0); ptr += sizeof(target_ulong); } - /* 32 FP registers, fsr, fir, fp. Not yet implemented. */ - /* what's 'fp' mean here? */ + /* "fp", pseudo frame pointer. Not yet implemented in gdb. */ + *(target_ulong *)ptr = 0; + ptr += sizeof(target_ulong); + + /* Registers for embedded use, we just pad them. */ + for (i = 0; i < 16; i++) + { + *(target_ulong *)ptr = 0; + ptr += sizeof(target_ulong); + } + + /* Processor ID. */ + *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_PRid); + ptr += sizeof(target_ulong); return ptr - mem_buf; } @@ -647,15 +662,17 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) { for (i = 0; i < 32; i++) { - env->fpu->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); + if (env->CP0_Status & (1 << CP0St_FR)) + env->fpu->fpr[i].d = tswapl(*(target_ulong *)ptr); + else + env->fpu->fpr[i].w[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr); ptr += sizeof(target_ulong); } - env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF; + env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0xFF83FFFF; ptr += sizeof(target_ulong); - env->fpu->fcr0 = tswapl(*(target_ulong *)ptr); - ptr += sizeof(target_ulong); + /* The remaining registers are assumed to be read-only. */ /* set rounding mode */ RESTORE_ROUNDING_MODE; -- cgit v1.2.3 From 0411a9725829d626bb0b2f11a461463c96061682 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 25 Oct 2007 21:35:50 +0000 Subject: Gprof prooved the PowerPC emulation spent too much time in MSR load and store routines. Coming back to a raw MSR storage model then speed-up the emulation. Improve fast MSR updates (wrtee wrteei and mtriee cases). Share rfi family instructions helpers code to avoid bug in duplicated code. Allow entering halt mode as the result of a rfi instruction. Add a new helper_regs.h file to avoid duplication of special registers manipulation routines (currently XER and MSR). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3436 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 4 +- linux-user/main.c | 13 +- monitor.c | 2 +- target-ppc/cpu.h | 82 +++++----- target-ppc/exec.h | 2 +- target-ppc/helper.c | 418 ++++++++++++++++------------------------------- target-ppc/helper_regs.h | 142 ++++++++++++++++ target-ppc/op.c | 41 +++-- target-ppc/op_helper.c | 149 ++++++----------- target-ppc/op_helper.h | 3 +- target-ppc/translate.c | 22 +-- 11 files changed, 407 insertions(+), 471 deletions(-) create mode 100644 target-ppc/helper_regs.h diff --git a/gdbstub.c b/gdbstub.c index 37dc764f5..89ee1d2e4 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -300,7 +300,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) } /* nip, msr, ccr, lnk, ctr, xer, mq */ registers[96] = tswapl(env->nip); - registers[97] = tswapl(do_load_msr(env)); + registers[97] = tswapl(env->msr); tmp = 0; for (i = 0; i < 8; i++) tmp |= env->crf[i] << (32 - ((i + 1) * 4)); @@ -329,7 +329,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size) } /* nip, msr, ccr, lnk, ctr, xer, mq */ env->nip = tswapl(registers[96]); - do_store_msr(env, tswapl(registers[97])); + ppc_store_msr(env, tswapl(registers[97])); registers[98] = tswapl(registers[98]); for (i = 0; i < 8; i++) env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF; diff --git a/linux-user/main.c b/linux-user/main.c index 7c3912151..7590db80a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2168,14 +2168,13 @@ int main(int argc, char **argv) } cpu_ppc_register(env, def); cpu_ppc_reset(env); - for (i = 0; i < 32; i++) { - if (i != 12 && i != 6 && i != 13) - env->msr[i] = (regs->msr >> i) & 1; - } -#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) - msr_sf = 1; + env->msr = regs->msr & ~((1 << 6) | (1 << 12) | (1 << 13)); +#if defined(TARGET_PPC64) +#if defined(TARGET_ABI32) + env->msr &= ~((target_ulong)1 << MSR_SF); #else - msr_sf = 0; + env->msr |= (target_ulong)1 << MSR_SF; +#endif #endif env->nip = regs->nip; for(i = 0; i < 32; i++) { diff --git a/monitor.c b/monitor.c index d1310a49b..65f23b4e9 100644 --- a/monitor.c +++ b/monitor.c @@ -1415,7 +1415,7 @@ static target_long monitor_get_msr (struct MonitorDef *md, int val) CPUState *env = mon_get_cpu(); if (!env) return 0; - return do_load_msr(env); + return env->msr; } static target_long monitor_get_xer (struct MonitorDef *md, int val) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index aeaacb257..cf4a110ac 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -368,7 +368,7 @@ union ppc_tlb_t { #define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */ #define MSR_FE1 8 /* Floating point exception mode 1 hflags */ #define MSR_AL 7 /* AL bit on POWER */ -#define MSR_EP 3 /* Exception prefix on 601 */ +#define MSR_EP 6 /* Exception prefix on 601 */ #define MSR_IR 5 /* Instruction relocate */ #define MSR_DR 4 /* Data relocate */ #define MSR_PE 3 /* Protection enable on 403 */ @@ -376,41 +376,42 @@ union ppc_tlb_t { #define MSR_PMM 2 /* Performance monitor mark on POWER x */ #define MSR_RI 1 /* Recoverable interrupt 1 */ #define MSR_LE 0 /* Little-endian mode 1 hflags */ -#define msr_sf env->msr[MSR_SF] -#define msr_isf env->msr[MSR_ISF] -#define msr_hv env->msr[MSR_HV] -#define msr_cm env->msr[MSR_CM] -#define msr_icm env->msr[MSR_ICM] -#define msr_ucle env->msr[MSR_UCLE] -#define msr_vr env->msr[MSR_VR] -#define msr_spe env->msr[MSR_SPE] -#define msr_ap env->msr[MSR_AP] -#define msr_sa env->msr[MSR_SA] -#define msr_key env->msr[MSR_KEY] -#define msr_pow env->msr[MSR_POW] -#define msr_tgpr env->msr[MSR_TGPR] -#define msr_ce env->msr[MSR_CE] -#define msr_ile env->msr[MSR_ILE] -#define msr_ee env->msr[MSR_EE] -#define msr_pr env->msr[MSR_PR] -#define msr_fp env->msr[MSR_FP] -#define msr_me env->msr[MSR_ME] -#define msr_fe0 env->msr[MSR_FE0] -#define msr_se env->msr[MSR_SE] -#define msr_dwe env->msr[MSR_DWE] -#define msr_uble env->msr[MSR_UBLE] -#define msr_be env->msr[MSR_BE] -#define msr_de env->msr[MSR_DE] -#define msr_fe1 env->msr[MSR_FE1] -#define msr_al env->msr[MSR_AL] -#define msr_ir env->msr[MSR_IR] -#define msr_dr env->msr[MSR_DR] -#define msr_pe env->msr[MSR_PE] -#define msr_ep env->msr[MSR_EP] -#define msr_px env->msr[MSR_PX] -#define msr_pmm env->msr[MSR_PMM] -#define msr_ri env->msr[MSR_RI] -#define msr_le env->msr[MSR_LE] + +#define msr_sf ((env->msr >> MSR_SF) & 1) +#define msr_isf ((env->msr >> MSR_ISF) & 1) +#define msr_hv ((env->msr >> MSR_HV) & 1) +#define msr_cm ((env->msr >> MSR_CM) & 1) +#define msr_icm ((env->msr >> MSR_ICM) & 1) +#define msr_ucle ((env->msr >> MSR_UCLE) & 1) +#define msr_vr ((env->msr >> MSR_VR) & 1) +#define msr_spe ((env->msr >> MSR_SE) & 1) +#define msr_ap ((env->msr >> MSR_AP) & 1) +#define msr_sa ((env->msr >> MSR_SA) & 1) +#define msr_key ((env->msr >> MSR_KEY) & 1) +#define msr_pow ((env->msr >> MSR_POW) & 1) +#define msr_tgpr ((env->msr >> MSR_TGPR) & 1) +#define msr_ce ((env->msr >> MSR_CE) & 1) +#define msr_ile ((env->msr >> MSR_ILE) & 1) +#define msr_ee ((env->msr >> MSR_EE) & 1) +#define msr_pr ((env->msr >> MSR_PR) & 1) +#define msr_fp ((env->msr >> MSR_FP) & 1) +#define msr_me ((env->msr >> MSR_ME) & 1) +#define msr_fe0 ((env->msr >> MSR_FE0) & 1) +#define msr_se ((env->msr >> MSR_SE) & 1) +#define msr_dwe ((env->msr >> MSR_DWE) & 1) +#define msr_uble ((env->msr >> MSR_UBLE) & 1) +#define msr_be ((env->msr >> MSR_BE) & 1) +#define msr_de ((env->msr >> MSR_DE) & 1) +#define msr_fe1 ((env->msr >> MSR_FE1) & 1) +#define msr_al ((env->msr >> MSR_AL) & 1) +#define msr_ep ((env->msr >> MSR_EP) & 1) +#define msr_ir ((env->msr >> MSR_IR) & 1) +#define msr_dr ((env->msr >> MSR_DR) & 1) +#define msr_pe ((env->msr >> MSR_PE) & 1) +#define msr_px ((env->msr >> MSR_PX) & 1) +#define msr_pmm ((env->msr >> MSR_PMM) & 1) +#define msr_ri ((env->msr >> MSR_RI) & 1) +#define msr_le ((env->msr >> MSR_LE) & 1) enum { POWERPC_FLAG_NONE = 0x00000000, @@ -468,7 +469,7 @@ struct CPUPPCState { /* Those ones are used in supervisor mode only */ /* machine state register */ - uint8_t msr[64]; + target_ulong msr; /* temporary general purpose registers */ ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */ @@ -639,13 +640,8 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ target_ulong ppc_load_xer (CPUPPCState *env); void ppc_store_xer (CPUPPCState *env, target_ulong value); -target_ulong do_load_msr (CPUPPCState *env); -int do_store_msr (CPUPPCState *env, target_ulong value); -#if defined(TARGET_PPC64) -int ppc_store_msr_32 (CPUPPCState *env, uint32_t value); -#endif +void ppc_store_msr (CPUPPCState *env, target_ulong value); -void do_compute_hflags (CPUPPCState *env); void cpu_ppc_reset (void *opaque); CPUPPCState *cpu_ppc_init (void); void cpu_ppc_close(CPUPPCState *env); diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 5685fd7a4..5abcee052 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -118,7 +118,7 @@ static always_inline int cpu_halted (CPUState *env) { if (!env->halted) return 0; - if (env->msr[MSR_EE] && (env->interrupt_request & CPU_INTERRUPT_HARD)) { + if (msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD)) { env->halted = 0; return 0; } diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 76312476a..ea672bb4a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -27,10 +27,12 @@ #include "cpu.h" #include "exec-all.h" +#include "helper_regs.h" //#define DEBUG_MMU //#define DEBUG_BATS //#define DEBUG_SOFTWARE_TLB +//#define DUMP_PAGE_TABLES //#define DEBUG_EXCEPTIONS //#define FLUSH_ALL_TLBS @@ -447,7 +449,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong base, BEPIl, BEPIu, bl; - int i, pp; + int i, pp, pr; int ret = -1; #if defined (DEBUG_BATS) @@ -456,6 +458,7 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif + pr = msr_pr; switch (type) { case ACCESS_CODE: BATlt = env->IBAT[1]; @@ -490,8 +493,8 @@ static int get_bat (CPUState *env, mmu_ctx_t *ctx, if ((virtual & 0xF0000000) == BEPIu && ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { /* BAT matches */ - if ((msr_pr == 0 && (*BATu & 0x00000002)) || - (msr_pr == 1 && (*BATu & 0x00000001))) { + if (((pr == 0) && (*BATu & 0x00000002)) || + ((pr != 0) && (*BATu & 0x00000001))) { /* Get physical address */ ctx->raddr = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | @@ -851,9 +854,10 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, #if defined(TARGET_PPC64) int attr; #endif - int ds, vsid_sh, sdr_sh; + int ds, vsid_sh, sdr_sh, pr; int ret, ret2; + pr = msr_pr; #if defined(TARGET_PPC64) if (env->mmu_model == POWERPC_MMU_64B) { #if defined (DEBUG_MMU) @@ -864,8 +868,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); if (ret < 0) return ret; - ctx->key = ((attr & 0x40) && msr_pr == 1) || - ((attr & 0x80) && msr_pr == 0) ? 1 : 0; + ctx->key = ((attr & 0x40) && (pr != 0)) || + ((attr & 0x80) && (pr == 0)) ? 1 : 0; ds = 0; ctx->nx = attr & 0x20 ? 1 : 0; vsid_mask = 0x00003FFFFFFFFF80ULL; @@ -877,8 +881,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, { sr = env->sr[eaddr >> 28]; page_mask = 0x0FFFFFFF; - ctx->key = (((sr & 0x20000000) && msr_pr == 1) || - ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; + ctx->key = (((sr & 0x20000000) && (pr != 0)) || + ((sr & 0x40000000) && (pr == 0))) ? 1 : 0; ds = sr & 0x80000000 ? 1 : 0; ctx->nx = sr & 0x10000000 ? 1 : 0; vsid = sr & 0x00FFFFFF; @@ -892,7 +896,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, " nip=0x" ADDRX " lr=0x" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, - env->lr, msr_ir, msr_dr, msr_pr, rw, type); + env->lr, (int)msr_ir, (int)msr_dr, pr != 0 ? 1 : 0, + rw, type); } #endif } @@ -981,7 +986,7 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, ret = ret2; } } -#if defined (DEBUG_MMU) +#if defined (DUMP_PAGE_TABLES) if (loglevel != 0) { target_phys_addr_t curaddr; uint32_t a0, a1, a2, a3; @@ -1157,10 +1162,11 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, { ppcemb_tlb_t *tlb; target_phys_addr_t raddr; - int i, ret, zsel, zpr; + int i, ret, zsel, zpr, pr; ret = -1; raddr = -1; + pr = msr_pr; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, @@ -1177,7 +1183,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, /* Check execute enable bit */ switch (zpr) { case 0x2: - if (msr_pr) + if (pr != 0) goto check_perms; /* No break here */ case 0x3: @@ -1186,7 +1192,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ret = 0; break; case 0x0: - if (msr_pr) { + if (pr != 0) { ctx->prot = 0; ret = -2; break; @@ -1248,7 +1254,7 @@ int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, if (ppcemb_tlb_check(env, tlb, &raddr, address, env->spr[SPR_BOOKE_PID], 1, i) < 0) continue; - if (msr_pr) + if (msr_pr != 0) prot = tlb->prot & 0xF; else prot = (tlb->prot >> 4) & 0xF; @@ -1343,6 +1349,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int access_type, int check_BATs) { int ret; + #if 0 if (loglevel != 0) { fprintf(logfile, "%s\n", __func__); @@ -1949,180 +1956,18 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) target_ulong ppc_load_xer (CPUPPCState *env) { - return (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); + return hreg_load_xer(env); } void ppc_store_xer (CPUPPCState *env, target_ulong value) { - xer_so = (value >> XER_SO) & 0x01; - xer_ov = (value >> XER_OV) & 0x01; - xer_ca = (value >> XER_CA) & 0x01; - xer_cmp = (value >> XER_CMP) & 0xFF; - xer_bc = (value >> XER_BC) & 0x7F; -} - -/* Swap temporary saved registers with GPRs */ -static always_inline void swap_gpr_tgpr (CPUPPCState *env) -{ - ppc_gpr_t tmp; - - tmp = env->gpr[0]; - env->gpr[0] = env->tgpr[0]; - env->tgpr[0] = tmp; - tmp = env->gpr[1]; - env->gpr[1] = env->tgpr[1]; - env->tgpr[1] = tmp; - tmp = env->gpr[2]; - env->gpr[2] = env->tgpr[2]; - env->tgpr[2] = tmp; - tmp = env->gpr[3]; - env->gpr[3] = env->tgpr[3]; - env->tgpr[3] = tmp; + hreg_store_xer(env, value); } /* GDBstub can read and write MSR... */ -target_ulong do_load_msr (CPUPPCState *env) -{ - return -#if defined (TARGET_PPC64) - ((target_ulong)msr_sf << MSR_SF) | - ((target_ulong)msr_isf << MSR_ISF) | - ((target_ulong)msr_hv << MSR_HV) | -#endif - ((target_ulong)msr_ucle << MSR_UCLE) | - ((target_ulong)msr_vr << MSR_VR) | /* VR / SPE */ - ((target_ulong)msr_ap << MSR_AP) | - ((target_ulong)msr_sa << MSR_SA) | - ((target_ulong)msr_key << MSR_KEY) | - ((target_ulong)msr_pow << MSR_POW) | - ((target_ulong)msr_tgpr << MSR_TGPR) | /* TGPR / CE */ - ((target_ulong)msr_ile << MSR_ILE) | - ((target_ulong)msr_ee << MSR_EE) | - ((target_ulong)msr_pr << MSR_PR) | - ((target_ulong)msr_fp << MSR_FP) | - ((target_ulong)msr_me << MSR_ME) | - ((target_ulong)msr_fe0 << MSR_FE0) | - ((target_ulong)msr_se << MSR_SE) | /* SE / DWE / UBLE */ - ((target_ulong)msr_be << MSR_BE) | /* BE / DE */ - ((target_ulong)msr_fe1 << MSR_FE1) | - ((target_ulong)msr_al << MSR_AL) | - ((target_ulong)msr_ep << MSR_EP) | - ((target_ulong)msr_ir << MSR_IR) | - ((target_ulong)msr_dr << MSR_DR) | - ((target_ulong)msr_pe << MSR_PE) | - ((target_ulong)msr_px << MSR_PX) | /* PX / PMM */ - ((target_ulong)msr_ri << MSR_RI) | - ((target_ulong)msr_le << MSR_LE); -} - -int do_store_msr (CPUPPCState *env, target_ulong value) -{ - int enter_pm; - - value &= env->msr_mask; - if (((value >> MSR_IR) & 1) != msr_ir || - ((value >> MSR_DR) & 1) != msr_dr) { - /* Flush all tlb when changing translation mode */ - tlb_flush(env, 1); - env->interrupt_request |= CPU_INTERRUPT_EXITTB; - } -#if !defined (CONFIG_USER_ONLY) - if (unlikely((env->flags & POWERPC_FLAG_TGPR) && - ((value >> MSR_TGPR) & 1) != msr_tgpr)) { - /* Swap temporary saved registers with GPRs */ - swap_gpr_tgpr(env); - } - if (unlikely((value >> MSR_EP) & 1) != msr_ep) { - /* Change the exception prefix on PowerPC 601 */ - env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; - } -#endif -#if defined (TARGET_PPC64) - msr_sf = (value >> MSR_SF) & 1; - msr_isf = (value >> MSR_ISF) & 1; - msr_hv = (value >> MSR_HV) & 1; -#endif - msr_ucle = (value >> MSR_UCLE) & 1; - msr_vr = (value >> MSR_VR) & 1; /* VR / SPE */ - msr_ap = (value >> MSR_AP) & 1; - msr_sa = (value >> MSR_SA) & 1; - msr_key = (value >> MSR_KEY) & 1; - msr_pow = (value >> MSR_POW) & 1; - msr_tgpr = (value >> MSR_TGPR) & 1; /* TGPR / CE */ - msr_ile = (value >> MSR_ILE) & 1; - msr_ee = (value >> MSR_EE) & 1; - msr_pr = (value >> MSR_PR) & 1; - msr_fp = (value >> MSR_FP) & 1; - msr_me = (value >> MSR_ME) & 1; - msr_fe0 = (value >> MSR_FE0) & 1; - msr_se = (value >> MSR_SE) & 1; /* SE / DWE / UBLE */ - msr_be = (value >> MSR_BE) & 1; /* BE / DE */ - msr_fe1 = (value >> MSR_FE1) & 1; - msr_al = (value >> MSR_AL) & 1; - msr_ep = (value >> MSR_EP) & 1; - msr_ir = (value >> MSR_IR) & 1; - msr_dr = (value >> MSR_DR) & 1; - msr_pe = (value >> MSR_PE) & 1; - msr_px = (value >> MSR_PX) & 1; /* PX / PMM */ - msr_ri = (value >> MSR_RI) & 1; - msr_le = (value >> MSR_LE) & 1; - do_compute_hflags(env); - - enter_pm = 0; - switch (env->excp_model) { - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - /* Don't handle SLEEP mode: we should disable all clocks... - * No dynamic power-management. - */ - if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00C00000) != 0) - enter_pm = 1; - break; - case POWERPC_EXCP_604: - if (msr_pow == 1) - enter_pm = 1; - break; - case POWERPC_EXCP_7x0: - if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0) - enter_pm = 1; - break; - default: - break; - } - - return enter_pm; -} - -#if defined(TARGET_PPC64) -int ppc_store_msr_32 (CPUPPCState *env, uint32_t value) -{ - return do_store_msr(env, (do_load_msr(env) & ~0xFFFFFFFFULL) | - (value & 0xFFFFFFFF)); -} -#endif - -void do_compute_hflags (CPUPPCState *env) +void ppc_store_msr (CPUPPCState *env, target_ulong value) { - /* Compute current hflags */ - env->hflags = (msr_vr << MSR_VR) | - (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) | - (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | - (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE); -#if defined (TARGET_PPC64) - env->hflags |= msr_cm << MSR_CM; - env->hflags |= (uint64_t)msr_sf << MSR_SF; - env->hflags |= (uint64_t)msr_hv << MSR_HV; - /* Precompute MMU index */ - if (msr_pr == 0 && msr_hv == 1) - env->mmu_idx = 2; - else -#endif - env->mmu_idx = 1 - msr_pr; + hreg_store_msr(env, value); } /*****************************************************************************/ @@ -2154,14 +1999,15 @@ static void dump_syscall (CPUState *env) static always_inline void powerpc_excp (CPUState *env, int excp_model, int excp) { - target_ulong msr, vector; + target_ulong msr, new_msr, vector; int srr0, srr1, asrr0, asrr1; if (loglevel & CPU_LOG_INT) { fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", env->nip, excp, env->error_code); } - msr = do_load_msr(env); + msr = env->msr; + new_msr = msr; srr0 = SPR_SRR0; srr1 = SPR_SRR1; asrr0 = -1; @@ -2172,7 +2018,7 @@ static always_inline void powerpc_excp (CPUState *env, /* Should never happen */ return; case POWERPC_EXCP_CRITICAL: /* Critical input */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ switch (excp_model) { case POWERPC_EXCP_40x: srr0 = SPR_40x_SRR2; @@ -2203,10 +2049,10 @@ static always_inline void powerpc_excp (CPUState *env, env->halted = 1; env->interrupt_request |= CPU_INTERRUPT_EXITTB; } - msr_ri = 0; - msr_me = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); + new_msr &= ~((target_ulong)1 << MSR_ME); #if defined(TARGET_PPC64H) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: should also have something loaded in DAR / DSISR */ switch (excp_model) { @@ -2231,10 +2077,10 @@ static always_inline void powerpc_excp (CPUState *env, "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ISI: /* Instruction storage exception */ @@ -2244,25 +2090,25 @@ static always_inline void powerpc_excp (CPUState *env, "\n", msr, env->nip); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= env->error_code; goto store_next; case POWERPC_EXCP_EXTERNAL: /* External input */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes0 == 1) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ @@ -2279,10 +2125,10 @@ static always_inline void powerpc_excp (CPUState *env, #endif return; } - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00100000; /* Set FX */ @@ -2303,26 +2149,26 @@ static always_inline void powerpc_excp (CPUState *env, env->nip); } #endif - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00080000; break; case POWERPC_EXCP_PRIV: - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00040000; break; case POWERPC_EXCP_TRAP: - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00020000; break; @@ -2334,10 +2180,10 @@ static always_inline void powerpc_excp (CPUState *env, } goto store_next; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_current; case POWERPC_EXCP_SYSCALL: /* System call exception */ @@ -2352,20 +2198,20 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel & CPU_LOG_INT) { dump_syscall(env); } - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); goto store_current; case POWERPC_EXCP_DECR: /* Decrementer exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ @@ -2374,7 +2220,7 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel != 0) fprintf(logfile, "FIT exception\n"); #endif - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ #if defined (DEBUG_EXCEPTIONS) @@ -2389,13 +2235,13 @@ static always_inline void powerpc_excp (CPUState *env, default: break; } - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_DTLB: /* Data TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_ITLB: /* Instruction TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_DEBUG: /* Debug interrupt */ switch (excp_model) { @@ -2413,7 +2259,7 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; #if defined(TARGET_PPCEMB) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_current; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ /* XXX: TODO */ @@ -2426,7 +2272,7 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: TODO */ cpu_abort(env, "Performance counter exception is not implemented yet !\n"); @@ -2451,24 +2297,24 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; #endif /* defined(TARGET_PPCEMB) */ case POWERPC_EXCP_RESET: /* System reset exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #if defined(TARGET_PPC64) case POWERPC_EXCP_DSEG: /* Data segment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #endif /* defined(TARGET_PPC64) */ @@ -2476,46 +2322,43 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; #endif case POWERPC_EXCP_TRACE: /* Trace exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; #if defined(TARGET_PPC64H) case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; - /* XXX: TODO */ - cpu_abort(env, "Hypervisor instruction storage exception " - "is not implemented yet !\n"); + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSSR1; - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; goto store_next; #endif /* defined(TARGET_PPC64H) */ case POWERPC_EXCP_VPU: /* Vector unavailable exception */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_current; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ @@ -2523,7 +2366,7 @@ static always_inline void powerpc_excp (CPUState *env, if (loglevel != 0) fprintf(logfile, "PIT exception\n"); #endif - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_next; case POWERPC_EXCP_IO: /* IO error exception */ /* XXX: TODO */ @@ -2539,10 +2382,10 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2560,10 +2403,10 @@ static always_inline void powerpc_excp (CPUState *env, } break; case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2581,10 +2424,10 @@ static always_inline void powerpc_excp (CPUState *env, } break; case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ - msr_ri = 0; /* XXX: check this */ + new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ #if defined(TARGET_PPC64H) /* XXX: check this */ if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif switch (excp_model) { case POWERPC_EXCP_602: @@ -2593,8 +2436,10 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_G2: tlb_miss_tgpr: /* Swap temporary saved registers with GPRs */ - swap_gpr_tgpr(env); - msr_tgpr = 1; + if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { + new_msr |= (target_ulong)1 << MSR_TGPR; + hreg_swap_gpr_tgpr(env); + } goto tlb_miss; case POWERPC_EXCP_7x5: tlb_miss: @@ -2639,8 +2484,8 @@ static always_inline void powerpc_excp (CPUState *env, if (excp == POWERPC_EXCP_IFTLB) { es = "I"; en = 'I'; - miss = &env->spr[SPR_IMISS]; - cmp = &env->spr[SPR_ICMP]; + miss = &env->spr[SPR_TLBMISS]; + cmp = &env->spr[SPR_PTEHI]; } else { if (excp == POWERPC_EXCP_DLTLB) es = "DL"; @@ -2681,10 +2526,10 @@ static always_inline void powerpc_excp (CPUState *env, "is not implemented yet !\n"); goto store_next; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ - msr_ri = 0; + new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) if (lpes1 == 0) - msr_hv = 1; + new_msr |= (target_ulong)1 << MSR_HV; #endif /* XXX: TODO */ cpu_abort(env, @@ -2725,23 +2570,26 @@ static always_inline void powerpc_excp (CPUState *env, if (asrr1 != -1) env->spr[asrr1] = env->spr[srr1]; /* If we disactivated any translation, flush TLBs */ - if (msr_ir || msr_dr) + if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR))) tlb_flush(env, 1); /* reload MSR with correct bits */ - msr_ee = 0; - msr_pr = 0; - msr_fp = 0; - msr_fe0 = 0; - msr_se = 0; - msr_be = 0; - msr_fe1 = 0; - msr_ir = 0; - msr_dr = 0; + new_msr &= ~((target_ulong)1 << MSR_EE); + new_msr &= ~((target_ulong)1 << MSR_PR); + new_msr &= ~((target_ulong)1 << MSR_FP); + new_msr &= ~((target_ulong)1 << MSR_FE0); + new_msr &= ~((target_ulong)1 << MSR_SE); + new_msr &= ~((target_ulong)1 << MSR_BE); + new_msr &= ~((target_ulong)1 << MSR_FE1); + new_msr &= ~((target_ulong)1 << MSR_IR); + new_msr &= ~((target_ulong)1 << MSR_DR); #if 0 /* Fix this: not on all targets */ - msr_pmm = 0; + new_msr &= ~((target_ulong)1 << MSR_PMM); #endif - msr_le = msr_ile; - do_compute_hflags(env); + new_msr &= ~((target_ulong)1 << MSR_LE); + if (msr_ile) + new_msr |= (target_ulong)1 << MSR_LE; + else + new_msr &= ~((target_ulong)1 << MSR_LE); /* Jump to handler */ vector = env->excp_vectors[excp]; if (vector == (target_ulong)-1) { @@ -2751,15 +2599,26 @@ static always_inline void powerpc_excp (CPUState *env, vector |= env->excp_prefix; #if defined(TARGET_PPC64) if (excp_model == POWERPC_EXCP_BOOKE) { - msr_cm = msr_icm; - if (!msr_cm) + if (!msr_icm) { + new_msr &= ~((target_ulong)1 << MSR_CM); vector = (uint32_t)vector; + } else { + new_msr |= (target_ulong)1 << MSR_CM; + } } else { - msr_sf = msr_isf; - if (!msr_sf) + if (!msr_isf) { + new_msr &= ~((target_ulong)1 << MSR_SF); vector = (uint32_t)vector; + } else { + new_msr |= (target_ulong)1 << MSR_SF; + } } #endif + /* XXX: we don't use hreg_store_msr here as already have treated + * any special case that could occur. Just store MSR and update hflags + */ + env->msr = new_msr; + hreg_compute_hflags(env); env->nip = vector; /* Reset exception state */ env->exception_index = POWERPC_EXCP_NONE; @@ -2773,11 +2632,11 @@ void do_interrupt (CPUState *env) void ppc_hw_interrupt (CPUPPCState *env) { -#if 1 +#if 0 if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n", __func__, env, env->pending_interrupts, - env->interrupt_request, msr_me, msr_ee); + env->interrupt_request, (int)msr_me, (int)msr_ee); } #endif /* External reset */ @@ -2801,7 +2660,7 @@ void ppc_hw_interrupt (CPUPPCState *env) } #endif #if defined(TARGET_PPC64H) - if ((msr_ee != 0 || msr_hv == 0 || msr_pr == 1) & hdice != 0) { + if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) & hdice != 0) { /* Hypervisor decrementer exception */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); @@ -2933,34 +2792,31 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr) void cpu_ppc_reset (void *opaque) { CPUPPCState *env; - int i; + target_ulong msr; env = opaque; - /* XXX: some of those flags initialisation values could depend - * on the actual PowerPC implementation - */ - for (i = 0; i < 63; i++) - env->msr[i] = 0; + msr = (target_ulong)0; #if defined(TARGET_PPC64) - msr_hv = 0; /* Should be 1... */ + msr |= (target_ulong)0 << MSR_HV; /* Should be 1... */ #endif - msr_ap = 0; /* TO BE CHECKED */ - msr_sa = 0; /* TO BE CHECKED */ - msr_ep = 1; + msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ + msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ + msr |= (target_ulong)1 << MSR_EP; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ - msr_se = 1; - msr_be = 1; + msr |= (target_ulong)1 << MSR_SE; + msr |= (target_ulong)1 << MSR_BE; #endif #if defined(CONFIG_USER_ONLY) - msr_fp = 1; /* Allow floating point exceptions */ - msr_pr = 1; + msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ + msr |= (target_ulong)1 << MSR_PR; #else env->nip = env->hreset_vector | env->excp_prefix; if (env->mmu_model != POWERPC_MMU_REAL_4xx) ppc_tlb_invalidate_all(env); #endif - do_compute_hflags(env); + env->msr = msr; + hreg_compute_hflags(env); env->reserve = -1; /* Be sure no exception or interrupt is pending */ env->pending_interrupts = 0; diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h new file mode 100644 index 000000000..75a3dddd5 --- /dev/null +++ b/target-ppc/helper_regs.h @@ -0,0 +1,142 @@ +/* + * PowerPC emulation special registers manipulation helpers for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * 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(__HELPER_REGS_H__) +#define __HELPER_REGS_H__ + +static always_inline target_ulong hreg_load_xer (CPUPPCState *env) +{ + return (xer_so << XER_SO) | + (xer_ov << XER_OV) | + (xer_ca << XER_CA) | + (xer_bc << XER_BC) | + (xer_cmp << XER_CMP); +} + +static always_inline void hreg_store_xer (CPUPPCState *env, target_ulong value) +{ + xer_so = (value >> XER_SO) & 0x01; + xer_ov = (value >> XER_OV) & 0x01; + xer_ca = (value >> XER_CA) & 0x01; + xer_cmp = (value >> XER_CMP) & 0xFF; + xer_bc = (value >> XER_BC) & 0x7F; +} + +/* Swap temporary saved registers with GPRs */ +static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) +{ + ppc_gpr_t tmp; + + tmp = env->gpr[0]; + env->gpr[0] = env->tgpr[0]; + env->tgpr[0] = tmp; + tmp = env->gpr[1]; + env->gpr[1] = env->tgpr[1]; + env->tgpr[1] = tmp; + tmp = env->gpr[2]; + env->gpr[2] = env->tgpr[2]; + env->tgpr[2] = tmp; + tmp = env->gpr[3]; + env->gpr[3] = env->tgpr[3]; + env->tgpr[3] = tmp; +} + +static always_inline void hreg_compute_hflags (CPUPPCState *env) +{ + target_ulong hflags_mask; + + /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ + hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | + (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | + (1 << MSR_LE); +#if defined (TARGET_PPC64) + hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF); +#if defined (TARGET_PPC64H) + hflags_mask |= 1ULL << MSR_HV; + /* Precompute MMU index */ + if (msr_pr == 0 && msr_hv != 0) + env->mmu_idx = 2; + else +#endif +#endif + env->mmu_idx = 1 - msr_pr; + env->hflags = env->msr & hflags_mask; +} + +static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) +{ + int enter_pm, excp; + + excp = 0; + value &= env->msr_mask; +#if !defined (CONFIG_USER_ONLY) + if (((value >> MSR_IR) & 1) != msr_ir || + ((value >> MSR_DR) & 1) != msr_dr) { + /* Flush all tlb when changing translation mode */ + tlb_flush(env, 1); + excp = POWERPC_EXCP_NONE; + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + } + if (unlikely((env->flags & POWERPC_FLAG_TGPR) && + ((value ^ env->msr) & (1 << MSR_TGPR)))) { + /* Swap temporary saved registers with GPRs */ + hreg_swap_gpr_tgpr(env); + } + if (unlikely((value >> MSR_EP) & 1) != msr_ep) { + /* Change the exception prefix on PowerPC 601 */ + env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; + } +#endif + env->msr = value; + hreg_compute_hflags(env); + enter_pm = 0; +#if !defined (CONFIG_USER_ONLY) + if (unlikely(msr_pow == 1)) { + switch (env->excp_model) { + case POWERPC_EXCP_603: + case POWERPC_EXCP_603E: + case POWERPC_EXCP_G2: + /* Don't handle SLEEP mode: we should disable all clocks... + * No dynamic power-management. + */ + if ((env->spr[SPR_HID0] & 0x00C00000) != 0) + enter_pm = 1; + break; + case POWERPC_EXCP_604: + enter_pm = 1; + break; + case POWERPC_EXCP_7x0: + if ((env->spr[SPR_HID0] & 0x00E00000) != 0) + enter_pm = 1; + break; + default: + break; + } + if (enter_pm) { + env->halted = 1; + excp = EXCP_HALTED; + } + } +#endif + + return excp; +} + +#endif /* !defined(__HELPER_REGS_H__) */ diff --git a/target-ppc/op.c b/target-ppc/op.c index 4889ad476..0030c1466 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -22,6 +22,7 @@ #include "config.h" #include "exec.h" +#include "helper_regs.h" #include "op_helper.h" #define REG 0 @@ -284,13 +285,13 @@ void OPPROTO op_store_xer_bc (void) void OPPROTO op_load_xer (void) { - do_load_xer(); + T0 = hreg_load_xer(env); RETURN(); } void OPPROTO op_store_xer (void) { - do_store_xer(); + hreg_store_xer(env, T0); RETURN(); } @@ -358,37 +359,36 @@ void OPPROTO op_store_asr (void) void OPPROTO op_load_msr (void) { - T0 = do_load_msr(env); + T0 = env->msr; RETURN(); } void OPPROTO op_store_msr (void) { - if (do_store_msr(env, T0)) { - env->halted = 1; - do_raise_exception(EXCP_HLT); - } + do_store_msr(); RETURN(); } -void OPPROTO op_update_riee (void) +#if defined (TARGET_PPC64) +void OPPROTO op_store_msr_32 (void) { - msr_ri = (T0 >> MSR_RI) & 1; - msr_ee = (T0 >> MSR_EE) & 1; + T0 = (env->msr & ~0xFFFFFFFFULL) | (T0 & 0xFFFFFFFF); + do_store_msr(); RETURN(); } +#endif -#if defined (TARGET_PPC64) -void OPPROTO op_store_msr_32 (void) +void OPPROTO op_update_riee (void) { - if (ppc_store_msr_32(env, T0)) { - env->halted = 1; - do_raise_exception(EXCP_HLT); - } + /* We don't call do_store_msr here as we won't trigger + * any special case nor change hflags + */ + T0 &= (1 << MSR_RI) | (1 << MSR_EE); + env->msr &= ~(1 << MSR_RI) | (1 << MSR_EE); + env->msr |= T0; RETURN(); } #endif -#endif /* SPR */ void OPPROTO op_load_spr (void) @@ -2517,7 +2517,12 @@ void OPPROTO op_rfmci (void) void OPPROTO op_wrte (void) { - msr_ee = T0 >> 16; + /* We don't call do_store_msr here as we won't trigger + * any special case nor change hflags + */ + T0 &= 1 << MSR_EE; + env->msr &= ~(1 << MSR_EE); + env->msr |= T0; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index f5331bace..c654b139c 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -19,6 +19,7 @@ */ #include "exec.h" +#include "helper_regs.h" #include "op_helper.h" #define MEMSUFFIX _raw @@ -98,24 +99,6 @@ void do_store_cr (uint32_t mask) } } -void do_load_xer (void) -{ - T0 = (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); -} - -void do_store_xer (void) -{ - xer_so = (T0 >> XER_SO) & 0x01; - xer_ov = (T0 >> XER_OV) & 0x01; - xer_ca = (T0 >> XER_CA) & 0x01; - xer_cmp = (T0 >> XER_CMP) & 0xFF; - xer_bc = (T0 >> XER_BC) & 0x7F; -} - #if defined(TARGET_PPC64) void do_store_pri (int prio) { @@ -970,56 +953,63 @@ void do_fcmpo (void) #if !defined (CONFIG_USER_ONLY) void cpu_dump_rfi (target_ulong RA, target_ulong msr); -void do_rfi (void) + +void do_store_msr (void) +{ + T0 = hreg_store_msr(env, T0); + if (T0 != 0) { + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + do_raise_exception(T0); + } +} + +static always_inline void __do_rfi (target_ulong nip, target_ulong msr, + target_ulong msrm, int keep_msrh) { #if defined(TARGET_PPC64) - if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { - env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + if (msr & (1ULL << MSR_SF)) { + nip = (uint64_t)nip; + msr &= (uint64_t)msrm; } else { - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - ppc_store_msr_32(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + nip = (uint32_t)nip; + msr = (uint32_t)(msr & msrm); + if (keep_msrh) + msr |= env->msr & ~((uint64_t)0xFFFFFFFF); } #else - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + nip = (uint32_t)nip; + msr &= (uint32_t)msrm; #endif + /* XXX: beware: this is false if VLE is supported */ + env->nip = nip & ~((target_ulong)0x00000003); + hreg_store_msr(env, msr); #if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); + cpu_dump_rfi(env->nip, env->msr); #endif + /* No need to raise an exception here, + * as rfi is always the last insn of a TB + */ env->interrupt_request |= CPU_INTERRUPT_EXITTB; } +void do_rfi (void) +{ + __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0xFFFF0000), 1); +} + #if defined(TARGET_PPC64) void do_rfid (void) { - if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { - env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); - } else { - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); - } -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0xFFFF0000), 0); } #endif #if defined(TARGET_PPC64H) void do_hrfid (void) { - if (env->spr[SPR_HSRR1] & (1ULL << MSR_SF)) { - env->nip = (uint64_t)(env->spr[SPR_HSRR0] & ~0x00000003); - do_store_msr(env, (uint64_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL)); - } else { - env->nip = (uint32_t)(env->spr[SPR_HSRR0] & ~0x00000003); - do_store_msr(env, (uint32_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL)); - } -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], + ~((target_ulong)0xFFFF0000), 0); } #endif #endif @@ -1214,13 +1204,7 @@ void do_POWER_rac (void) void do_POWER_rfsvc (void) { - env->nip = env->lr & ~0x00000003UL; - T0 = env->ctr & 0x0000FFFFUL; - do_store_msr(env, T0); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); } /* PowerPC 601 BAT management helper */ @@ -1332,63 +1316,26 @@ void do_store_dcr (void) #if !defined(CONFIG_USER_ONLY) void do_40x_rfci (void) { - env->nip = env->spr[SPR_40x_SRR2]; - do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], + ~((target_ulong)0xFFFF0000), 0); } void do_rfci (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_CSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_CSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_CSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_CSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_rfdi (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_DSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_DSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_DSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_DSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_rfmci (void) { -#if defined(TARGET_PPC64) - if (env->spr[SPR_BOOKE_MCSRR1] & (1 << MSR_CM)) { - env->nip = (uint64_t)env->spr[SPR_BOOKE_MCSRR0]; - } else -#endif - { - env->nip = (uint32_t)env->spr[SPR_BOOKE_MCSRR0]; - } - do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_MCSRR1] & ~0x3FFF0000); -#if defined (DEBUG_OP) - cpu_dump_rfi(env->nip, do_load_msr(env)); -#endif - env->interrupt_request = CPU_INTERRUPT_EXITTB; + __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, + ~((target_ulong)0x3FFF0000), 0); } void do_load_403_pb (int num) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 4688bc2fa..e260b4ff9 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -57,8 +57,6 @@ void do_print_mem_EA (target_ulong EA); /* Registers load and stores */ void do_load_cr (void); void do_store_cr (uint32_t mask); -void do_load_xer (void); -void do_store_xer (void); #if defined(TARGET_PPC64) void do_store_pri (int prio); #endif @@ -129,6 +127,7 @@ void do_tw (int flags); void do_td (int flags); #endif #if !defined(CONFIG_USER_ONLY) +void do_store_msr (void); void do_rfi (void); #if defined(TARGET_PPC64) void do_rfid (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6f2a9721f..817045de8 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6538,18 +6538,10 @@ GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPEFPU); // GEN_OPCODE_MARK(end); #include "translate_init.c" +#include "helper_regs.h" /*****************************************************************************/ /* Misc PowerPC helpers */ -static always_inline uint32_t load_xer (CPUState *env) -{ - return (xer_so << XER_SO) | - (xer_ov << XER_OV) | - (xer_ca << XER_CA) | - (xer_bc << XER_BC) | - (xer_cmp << XER_CMP); -} - void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) @@ -6566,8 +6558,8 @@ void cpu_dump_state (CPUState *env, FILE *f, int i; - cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX "\n", - env->nip, env->lr, env->ctr); + cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX " idx %d\n", + env->nip, env->lr, env->ctr, env->mmu_idx); cpu_fprintf(f, "MSR " REGX FILL " XER %08x " #if !defined(NO_TIMER_DUMP) "TB %08x %08x " @@ -6576,7 +6568,7 @@ void cpu_dump_state (CPUState *env, FILE *f, #endif #endif "\n", - do_load_msr(env), load_xer(env) + env->msr, hreg_load_xer(env) #if !defined(NO_TIMER_DUMP) , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) #if !defined(CONFIG_USER_ONLY) @@ -6753,7 +6745,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n", - ctx.nip, 1 - msr_pr, msr_ir); + ctx.nip, supervisor, (int)msr_ir); } #endif ctx.opcode = ldl_code(ctx.nip); @@ -6787,12 +6779,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, fprintf(logfile, "invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } else { printf("invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); + opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } } else { if (unlikely((ctx.opcode & handler->inval) != 0)) { -- cgit v1.2.3 From 8ca3f6c3824c6affa2f44d39e6b249ea7a6eb6b7 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 25 Oct 2007 21:37:25 +0000 Subject: Allow selection of all defined PowerPC 74xx (aka G4) CPUs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3437 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 41a4c6410..b979ad9e1 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -5542,110 +5542,74 @@ static ppc_def_t ppc_defs[] = { POWERPC_DEF("7448v2.0", CPU_POWERPC_7448_v20, 0xFFFFFFFF, 7400), /* PowerPC 7448 v2.1 (G4) */ POWERPC_DEF("7448v2.1", CPU_POWERPC_7448_v21, 0xFFFFFFFF, 7400), -#if defined (TODO) /* PowerPC 7450 (G4) */ POWERPC_DEF("7450", CPU_POWERPC_7450, 0xFFFFFFFF, 7450), /* Code name for PowerPC 7450 */ POWERPC_DEF("Vger", CPU_POWERPC_7450, 0xFFFFFFFF, 7450), -#endif -#if defined (TODO) /* PowerPC 7450 v1.0 (G4) */ POWERPC_DEF("7450v1.0", CPU_POWERPC_7450_v10, 0xFFFFFFFF, 7450), -#endif -#if defined (TODO) /* PowerPC 7450 v1.1 (G4) */ POWERPC_DEF("7450v1.1", CPU_POWERPC_7450_v11, 0xFFFFFFFF, 7450), -#endif -#if defined (TODO) /* PowerPC 7450 v1.2 (G4) */ POWERPC_DEF("7450v1.2", CPU_POWERPC_7450_v12, 0xFFFFFFFF, 7450), -#endif -#if defined (TODO) /* PowerPC 7450 v2.0 (G4) */ POWERPC_DEF("7450v2.0", CPU_POWERPC_7450_v20, 0xFFFFFFFF, 7450), -#endif -#if defined (TODO) /* PowerPC 7450 v2.1 (G4) */ POWERPC_DEF("7450v2.1", CPU_POWERPC_7450_v21, 0xFFFFFFFF, 7450), -#endif -#if defined (TODO) /* PowerPC 7441 (G4) */ POWERPC_DEF("7441", CPU_POWERPC_74x1, 0xFFFFFFFF, 7440), /* PowerPC 7451 (G4) */ POWERPC_DEF("7451", CPU_POWERPC_74x1, 0xFFFFFFFF, 7450), -#endif -#if defined (TODO) /* PowerPC 7441g (G4) */ POWERPC_DEF("7441g", CPU_POWERPC_74x1G, 0xFFFFFFFF, 7440), /* PowerPC 7451g (G4) */ POWERPC_DEF("7451g", CPU_POWERPC_74x1G, 0xFFFFFFFF, 7450), -#endif -#if defined (TODO) /* PowerPC 7445 (G4) */ POWERPC_DEF("7445", CPU_POWERPC_74x5, 0xFFFFFFFF, 7445), /* PowerPC 7455 (G4) */ POWERPC_DEF("7455", CPU_POWERPC_74x5, 0xFFFFFFFF, 7455), /* Code name for PowerPC 7445/7455 */ POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7445 v1.0 (G4) */ POWERPC_DEF("7445v1.0", CPU_POWERPC_74x5_v10, 0xFFFFFFFF, 7445), /* PowerPC 7455 v1.0 (G4) */ POWERPC_DEF("7455v1.0", CPU_POWERPC_74x5_v10, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7445 v2.1 (G4) */ POWERPC_DEF("7445v2.1", CPU_POWERPC_74x5_v21, 0xFFFFFFFF, 7445), /* PowerPC 7455 v2.1 (G4) */ POWERPC_DEF("7455v2.1", CPU_POWERPC_74x5_v21, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7445 v3.2 (G4) */ POWERPC_DEF("7445v3.2", CPU_POWERPC_74x5_v32, 0xFFFFFFFF, 7445), /* PowerPC 7455 v3.2 (G4) */ POWERPC_DEF("7455v3.2", CPU_POWERPC_74x5_v32, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7445 v3.3 (G4) */ POWERPC_DEF("7445v3.3", CPU_POWERPC_74x5_v33, 0xFFFFFFFF, 7445), /* PowerPC 7455 v3.3 (G4) */ POWERPC_DEF("7455v3.3", CPU_POWERPC_74x5_v33, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7445 v3.4 (G4) */ POWERPC_DEF("7445v3.4", CPU_POWERPC_74x5_v34, 0xFFFFFFFF, 7445), /* PowerPC 7455 v3.4 (G4) */ POWERPC_DEF("7455v3.4", CPU_POWERPC_74x5_v34, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7447 (G4) */ POWERPC_DEF("7447", CPU_POWERPC_74x7, 0xFFFFFFFF, 7445), /* PowerPC 7457 (G4) */ POWERPC_DEF("7457", CPU_POWERPC_74x7, 0xFFFFFFFF, 7455), /* Code name for PowerPC 7447/7457 */ POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7447 v1.0 (G4) */ POWERPC_DEF("7447v1.0", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7445), /* PowerPC 7457 v1.0 (G4) */ POWERPC_DEF("7457v1.0", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7455), /* Code name for PowerPC 7447A/7457A */ POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7447 v1.1 (G4) */ POWERPC_DEF("7447v1.1", CPU_POWERPC_74x7_v11, 0xFFFFFFFF, 7445), /* PowerPC 7457 v1.1 (G4) */ POWERPC_DEF("7457v1.1", CPU_POWERPC_74x7_v11, 0xFFFFFFFF, 7455), -#endif -#if defined (TODO) /* PowerPC 7447 v1.2 (G4) */ POWERPC_DEF("7447v1.2", CPU_POWERPC_74x7_v12, 0xFFFFFFFF, 7445), /* PowerPC 7457 v1.2 (G4) */ POWERPC_DEF("7457v1.2", CPU_POWERPC_74x7_v12, 0xFFFFFFFF, 7455), -#endif /* 64 bits PowerPC */ #if defined (TARGET_PPC64) #if defined (TODO) -- cgit v1.2.3 From 86f1d3ac73f37b7fbab06699cc2b9cd616438d32 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 25 Oct 2007 21:38:16 +0000 Subject: Update PowerPC emulation status file. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3438 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/STATUS | 59 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/target-ppc/STATUS b/target-ppc/STATUS index f346daf93..32e7ffa49 100644 --- a/target-ppc/STATUS +++ b/target-ppc/STATUS @@ -86,8 +86,8 @@ MSR OK IRQ OK MMU OK EXCP OK -=> Linux 2.4 boots (at least 1 proprietary firmware). - +Remarks: Linux 2.4 boots (at least 1 proprietary firmware). + uboot seems to freeze at boot time. To be checked: 405D2 405D4 405EZ 405LP Npe4GS3 STB03 STB04 STB25 x2vp4 x2vp7 x2vp20 x2vp50 @@ -203,8 +203,8 @@ MSR OK IRQ OK MMU ? EXCP ? at least timer and external interrupt are OK -Remarks: Linux crashes when entering user-mode. But it seems it does not - know about this CPU. As this CPU is close to 603e, it should be OK. +Remarks: Linux 2.4 crashes when entering user-mode. + Linux 2.6.22 boots on this CPU but does not recognize it. PowerPC 603: (603) INSN OK @@ -214,6 +214,7 @@ IRQ OK MMU OK EXCP OK Remarks: Linux 2.4 boots and properly recognizes the CPU + Linux 2.6.22 idem. PowerPC 603e: (603e11) INSN OK @@ -223,6 +224,7 @@ IRQ OK MMU OK EXCP OK Remarks: Linux 2.4 boots and properly recognizes the CPU + Linux 2.6.22 idem. PowerPC G2: INSN OK @@ -232,6 +234,7 @@ IRQ OK MMU OK EXCP OK Remarks: Linux 2.4 boots, recognizes the CPU as a 82xx. + Linux 2.6.22 idem. PowerPC G2le: INSN OK @@ -241,6 +244,7 @@ IRQ OK MMU OK EXCP OK Remarks: Linux 2.4 does not boots. Same symptoms as 602. + Linux 2.6.22 boots and properly recognizes the CPU. PowerPC 604: INSN OK @@ -250,6 +254,7 @@ IRQ OK MMU OK EXCP OK Remarks: Linux 2.4 boots and properly recognizes the CPU. + Linux 2.6.22 idem. PowerPC 7x0: INSN OK @@ -259,6 +264,7 @@ IRQ OK MMU OK EXCP OK Remarks: Linux 2.4 boots and properly recognizes the CPU. + Linux 2.6.22 idem. PowerPC 750fx: INSN OK @@ -268,6 +274,7 @@ IRQ OK MMU OK EXCP OK Remarks: Linux 2.4 boots but does not properly recognizes the CPU. + Linux 2.6.22 boots and properly recognizes the CPU. PowerPC 7x5: INSN ? @@ -276,7 +283,8 @@ MSR ? IRQ OK MMU ? EXCP OK -=> Linux 2.4 does not boot. +Remarks: Linux 2.4 does not boot. + Linux 2.6.22 idem. PowerPC 7400: INSN KO Altivec missing @@ -285,7 +293,8 @@ MSR OK IRQ OK MMU OK EXCP ? Altivec, ... -=> Linux 2.4 boots and properly recognize the CPU. +Remarks: Linux 2.4 boots and properly recognize the CPU. + Linux 2.6.22 idem. PowerPC 7410: INSN KO Altivec missing @@ -294,9 +303,10 @@ MSR OK IRQ OK MMU OK EXCP ? Altivec, ... -=> Linux 2.4 boots and properly recognize the CPU. - Note that UM says tlbld & tlbli are implemented bus this may be a mistake - as TLB load are managed by the hardware and it does not implement the +Remarks: Linux 2.4 boots and properly recognize the CPU. + Linux 2.6.22 idem. + Note that UM says tlbld & tlbli are implemented but this may be a mistake + as TLB loads are managed by the hardware and the CPU does not implement the needed registers. PowerPC 7441: @@ -306,8 +316,8 @@ MSR OK IRQ OK MMU OK EXCP ? Altivec, ... -Linux does not have the code to handle TLB miss on this CPU - +Remarks: Linux does not have the code to handle TLB miss on this CPU + Linux 2.6.22 idem. PowerPC 7450/7451: INSN KO Altivec missing @@ -316,7 +326,8 @@ MSR OK IRQ OK MMU OK EXCP ? Altivec, ... -Linux does not have the code to handle TLB miss on this CPU +Remarks: Linux does not have the code to handle TLB miss on this CPU + Linux 2.6.22 idem. PowerPC 7445/7447: INSN KO Altivec missing @@ -325,7 +336,8 @@ MSR OK IRQ OK MMU OK EXCP ? Altivec, ... -Linux does not have the code to handle TLB miss on this CPU +Remarks: Linux does not have the code to handle TLB miss on this CPU + Linux 2.6.22 idem. PowerPC 7455/7457: INSN KO Altivec missing @@ -334,7 +346,8 @@ MSR OK IRQ OK MMU OK EXCP ? Altivec, ... -Linux does not have the code to handle TLB miss on this CPU +Remarks: Linux does not have the code to handle TLB miss on this CPU + Linux 2.6.22 idem. 64 bits PowerPC PowerPC 620: (disabled) @@ -344,6 +357,7 @@ MSR ? IRQ KO MMU KO EXCP KO +Remarks: not much documentation for this implementation... PowerPC 970: INSN KO Altivec missing and more @@ -352,7 +366,7 @@ MSR ? IRQ OK MMU OK EXCP KO partially implemented -Should be able to boot but there is no hw platform currently emulated. +Remarks: Should be able to boot but there is no hw platform currently emulated. PowerPC 970FX: INSN KO Altivec missing and more @@ -361,7 +375,7 @@ MSR ? IRQ OK MMU OK EXCP KO partially implemented -Should be able to boot but there is no hw platform currently emulated. +Remarks: Should be able to boot but there is no hw platform currently emulated. PowerPC 970GX: INSN KO Altivec missing and more @@ -370,7 +384,7 @@ MSR ? IRQ OK MMU OK EXCP KO partially implemented -Should be able to boot but there is no hw platform currently emulated. +Remarks: Should be able to boot but there is no hw platform currently emulated. PowerPC Cell: INSN KO Altivec missing and more @@ -379,7 +393,8 @@ MSR ? IRQ ? MMU ? EXCP ? partially implemented -As the core is mostly a 970, should be able to boot. SPE are not implemented. +Remarks: As the core is mostly a 970, should be able to boot. + SPE are not implemented. PowerPC 630: (disabled: lack of detailed specifications) INSN KO @@ -495,7 +510,10 @@ Implemementation should be sufficient to boot Linux: - PowerPC 405EP TODO: -- More PowerPC 40x microcontrollers emulation +- PowerPC 401 microcontrollers emulation +- PowerPC 403 microcontrollers emulation +- more PowerPC 405 microcontrollers emulation +- Fixes / more features for implemented PowerPC 405 microcontrollers emulation - PowerPC 440 microcontrollers emulation - e200 microcontrollers emulation - e300 microcontrollers emulation @@ -530,6 +548,8 @@ PowerPC based platforms emulation status Need to provide a flash image ready to boot for reproductible tests. TODO: +- URGENT: fix PreP and heathrow platforms +- PowerPC 64 reference platform - MCA based RS/6000 emulation - CHRP emulation (not PowerMac) - PPAR emulation @@ -537,4 +557,3 @@ TODO: - misc PowerPC reference boards emulation =============================================================================== -(to be completed) -- cgit v1.2.3 From e494ead52114e9d7baa9f33bca0e5b15b577c16b Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 25 Oct 2007 23:00:03 +0000 Subject: Restore a more maintainable version of the 64bit multiply code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3439 c046a42c-6fe2-441c-8c8c-71466251a162 --- host-utils.c | 103 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/host-utils.c b/host-utils.c index cf2c6f8f1..d0d780e54 100644 --- a/host-utils.c +++ b/host-utils.c @@ -1,6 +1,7 @@ /* * Utility compute operations used by translated code. * + * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2007 Aurelien Jarno * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,54 +25,88 @@ #include "vl.h" -/* Signed 64x64 -> 128 multiplication */ +/* Long integer helpers */ +static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + *plow += a; + /* carry test */ + if (*plow < a) + (*phigh)++; + *phigh += b; +} -void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b) +static void neg128 (uint64_t *plow, uint64_t *phigh) { -#if defined(__x86_64__) - __asm__ ("imul %0\n\t" - : "=d" (*phigh), "=a" (*plow) - : "a" (a), "0" (b) - ); -#else - int64_t ph; - uint64_t pm1, pm2, pl; + *plow = ~*plow; + *phigh = ~*phigh; + add128(plow, phigh, 1, 0); +} - pl = (uint64_t)((uint32_t)a) * (uint64_t)((uint32_t)b); - pm1 = (a >> 32) * (uint32_t)b; - pm2 = (uint32_t)a * (b >> 32); - ph = (a >> 32) * (b >> 32); +static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +{ + uint32_t a0, a1, b0, b1; + uint64_t v; - ph += (int64_t)pm1 >> 32; - ph += (int64_t)pm2 >> 32; - pm1 = (uint64_t)((uint32_t)pm1) + (uint64_t)((uint32_t)pm2) + (pl >> 32); + a0 = a; + a1 = a >> 32; - *phigh = ph + ((int64_t)pm1 >> 32); - *plow = (pm1 << 32) + (uint32_t)pl; -#endif + b0 = b; + b1 = b >> 32; + + v = (uint64_t)a0 * (uint64_t)b0; + *plow = v; + *phigh = 0; + + v = (uint64_t)a0 * (uint64_t)b1; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b0; + add128(plow, phigh, v << 32, v >> 32); + + v = (uint64_t)a1 * (uint64_t)b1; + *phigh += v; } + /* Unsigned 64x64 -> 128 multiplication */ -void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b) +void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { #if defined(__x86_64__) __asm__ ("mul %0\n\t" : "=d" (*phigh), "=a" (*plow) - : "a" (a), "0" (b) - ); + : "a" (a), "0" (b)); #else - uint64_t ph, pm1, pm2, pl; - - pl = (uint64_t)((uint32_t)a) * (uint64_t)((uint32_t)b); - pm1 = (a >> 32) * (uint32_t)b; - pm2 = (uint32_t)a * (b >> 32); - ph = (a >> 32) * (b >> 32); + mul64(plow, phigh, a, b); +#endif +#if defined(DEBUG_MULDIV) + printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + a, b, *phigh, *plow); +#endif +} - ph += pm1 >> 32; - ph += pm2 >> 32; - pm1 = (uint64_t)((uint32_t)pm1) + (uint64_t)((uint32_t)pm2) + (pl >> 32); +/* Signed 64x64 -> 128 multiplication */ +void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) +{ +#if defined(__x86_64__) + __asm__ ("imul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b)); +#else + int sa, sb; - *phigh = ph + (pm1 >> 32); - *plow = (pm1 << 32) + (uint32_t)pl; + sa = (a < 0); + if (sa) + a = -a; + sb = (b < 0); + if (sb) + b = -b; + mul64(plow, phigh, a, b); + if (sa ^ sb) { + neg128(plow, phigh); + } +#endif +#if defined(DEBUG_MULDIV) + printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", + a, b, *phigh, *plow); #endif } -- cgit v1.2.3 From 2f462816ac343a804d51e157dad6b5d91426d3e1 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 25 Oct 2007 23:14:50 +0000 Subject: Implement power-management for all defined PowerPC CPUs. Fix PowerPC 970MP definition. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3440 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper_regs.h | 25 +------ target-ppc/translate_init.c | 179 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 174 insertions(+), 30 deletions(-) diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index 75a3dddd5..2a5de2ed1 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -82,7 +82,7 @@ static always_inline void hreg_compute_hflags (CPUPPCState *env) static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) { - int enter_pm, excp; + int excp; excp = 0; value &= env->msr_mask; @@ -106,30 +106,9 @@ static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) #endif env->msr = value; hreg_compute_hflags(env); - enter_pm = 0; #if !defined (CONFIG_USER_ONLY) if (unlikely(msr_pow == 1)) { - switch (env->excp_model) { - case POWERPC_EXCP_603: - case POWERPC_EXCP_603E: - case POWERPC_EXCP_G2: - /* Don't handle SLEEP mode: we should disable all clocks... - * No dynamic power-management. - */ - if ((env->spr[SPR_HID0] & 0x00C00000) != 0) - enter_pm = 1; - break; - case POWERPC_EXCP_604: - enter_pm = 1; - break; - case POWERPC_EXCP_7x0: - if ((env->spr[SPR_HID0] & 0x00E00000) != 0) - enter_pm = 1; - break; - default: - break; - } - if (enter_pm) { + if ((*env->check_pow)(env)) { env->halted = 1; excp = EXCP_HALTED; } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index b979ad9e1..5698622ba 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -42,6 +42,7 @@ struct ppc_def_t { uint32_t flags; int bfd_mach; void (*init_proc)(CPUPPCState *env); + int (*check_pow)(CPUPPCState *env); }; /* For user-mode emulation, we don't emulate any IRQ controller */ @@ -2605,6 +2606,26 @@ static void init_excp_970 (CPUPPCState *env) } #endif +/*****************************************************************************/ +/* Power management enable checks */ +static int check_pow_none (CPUPPCState *env) +{ + return 0; +} + +static int check_pow_nocheck (CPUPPCState *env) +{ + return 1; +} + +static int check_pow_hid0 (CPUPPCState *env) +{ + if (env->spr[SPR_HID0] & 0x00E00000) + return 1; + + return 0; +} + /*****************************************************************************/ /* PowerPC implementations definitions */ @@ -2621,6 +2642,7 @@ static void init_excp_970 (CPUPPCState *env) #define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401 (bfd_mach_ppc_403) #define POWERPC_FLAG_401 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define check_pow_401 check_pow_nocheck static void init_proc_401 (CPUPPCState *env) { @@ -2646,6 +2668,7 @@ static void init_proc_401 (CPUPPCState *env) #define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) #define POWERPC_FLAG_401x2 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define check_pow_401x2 check_pow_nocheck static void init_proc_401x2 (CPUPPCState *env) { @@ -2678,6 +2701,7 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) #define POWERPC_FLAG_401x3 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define check_pow_401x3 check_pow_nocheck __attribute__ (( unused )) static void init_proc_401x3 (CPUPPCState *env) @@ -2706,6 +2730,7 @@ static void init_proc_401x3 (CPUPPCState *env) #define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) #define POWERPC_FLAG_IOP480 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define check_pow_IOP480 check_pow_nocheck static void init_proc_IOP480 (CPUPPCState *env) { @@ -2736,6 +2761,7 @@ static void init_proc_IOP480 (CPUPPCState *env) #define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403 (bfd_mach_ppc_403) #define POWERPC_FLAG_403 (POWERPC_FLAG_CE | POWERPC_FLAG_PX) +#define check_pow_403 check_pow_nocheck static void init_proc_403 (CPUPPCState *env) { @@ -2765,6 +2791,7 @@ static void init_proc_403 (CPUPPCState *env) #define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) #define POWERPC_FLAG_403GCX (POWERPC_FLAG_CE | POWERPC_FLAG_PX) +#define check_pow_403GCX check_pow_nocheck static void init_proc_403GCX (CPUPPCState *env) { @@ -2810,6 +2837,7 @@ static void init_proc_403GCX (CPUPPCState *env) #define POWERPC_BFDM_405 (bfd_mach_ppc_403) #define POWERPC_FLAG_405 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE) +#define check_pow_405 check_pow_nocheck static void init_proc_405 (CPUPPCState *env) { @@ -2853,6 +2881,7 @@ static void init_proc_405 (CPUPPCState *env) #define POWERPC_BFDM_440EP (bfd_mach_ppc_403) #define POWERPC_FLAG_440EP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE) +#define check_pow_440EP check_pow_nocheck static void init_proc_440EP (CPUPPCState *env) { @@ -2902,6 +2931,7 @@ static void init_proc_440EP (CPUPPCState *env) #define POWERPC_BFDM_440GP (bfd_mach_ppc_403) #define POWERPC_FLAG_440GP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE) +#define check_pow_440GP check_pow_nocheck static void init_proc_440GP (CPUPPCState *env) { @@ -2933,6 +2963,7 @@ static void init_proc_440GP (CPUPPCState *env) #define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) #define POWERPC_FLAG_440x4 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE) +#define check_pow_440x4 check_pow_nocheck __attribute__ (( unused )) static void init_proc_440x4 (CPUPPCState *env) @@ -2965,6 +2996,7 @@ static void init_proc_440x4 (CPUPPCState *env) #define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) #define POWERPC_FLAG_440x5 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE) +#define check_pow_440x5 check_pow_nocheck static void init_proc_440x5 (CPUPPCState *env) { @@ -3014,6 +3046,7 @@ static void init_proc_440x5 (CPUPPCState *env) #define POWERPC_BFDM_460 (bfd_mach_ppc_403) #define POWERPC_FLAG_460 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE) +#define check_pow_460 check_pow_nocheck __attribute__ (( unused )) static void init_proc_460 (CPUPPCState *env) @@ -3072,6 +3105,7 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_BFDM_460F (bfd_mach_ppc_403) #define POWERPC_FLAG_460F (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE) +#define check_pow_460F check_pow_nocheck __attribute__ (( unused )) static void init_proc_460F (CPUPPCState *env) @@ -3129,6 +3163,7 @@ static void init_proc_460F (CPUPPCState *env) #define POWERPC_INPUT_BookE (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_BookE (bfd_mach_ppc_403) #define POWERPC_FLAG_BookE (POWERPC_FLAG_NONE) +#define check_pow_BookE check_pow_nocheck __attribute__ (( unused )) static void init_proc_BookE (CPUPPCState *env) @@ -3152,6 +3187,7 @@ static void init_proc_BookE (CPUPPCState *env) #define POWERPC_INPUT_e500 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_e500 (bfd_mach_ppc_403) #define POWERPC_FLAG_e500 (POWERPC_FLAG_SPE) +#define check_pow_e500 check_pow_hid0 __attribute__ (( unused )) static void init_proc_e500 (CPUPPCState *env) @@ -3201,6 +3237,7 @@ static void init_proc_e500 (CPUPPCState *env) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_601 (bfd_mach_ppc_601) #define POWERPC_FLAG_601 (POWERPC_FLAG_SE) +#define check_pow_601 check_pow_none static void init_proc_601 (CPUPPCState *env) { @@ -3257,6 +3294,7 @@ static void init_proc_601 (CPUPPCState *env) #define POWERPC_BFDM_602 (bfd_mach_ppc_602) #define POWERPC_FLAG_602 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE) +#define check_pow_602 check_pow_hid0 static void init_proc_602 (CPUPPCState *env) { @@ -3294,6 +3332,7 @@ static void init_proc_602 (CPUPPCState *env) #define POWERPC_BFDM_603 (bfd_mach_ppc_603) #define POWERPC_FLAG_603 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE) +#define check_pow_603 check_pow_hid0 static void init_proc_603 (CPUPPCState *env) { @@ -3331,6 +3370,7 @@ static void init_proc_603 (CPUPPCState *env) #define POWERPC_BFDM_603E (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_603E (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE) +#define check_pow_603E check_pow_hid0 static void init_proc_603E (CPUPPCState *env) { @@ -3373,6 +3413,7 @@ static void init_proc_603E (CPUPPCState *env) #define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE) +#define check_pow_G2 check_pow_hid0 static void init_proc_G2 (CPUPPCState *env) { @@ -3417,6 +3458,7 @@ static void init_proc_G2 (CPUPPCState *env) #define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE) +#define check_pow_G2LE check_pow_hid0 static void init_proc_G2LE (CPUPPCState *env) { @@ -3461,6 +3503,7 @@ static void init_proc_G2LE (CPUPPCState *env) #define POWERPC_BFDM_604 (bfd_mach_ppc_604) #define POWERPC_FLAG_604 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM) +#define check_pow_604 check_pow_nocheck static void init_proc_604 (CPUPPCState *env) { @@ -3497,6 +3540,7 @@ static void init_proc_604 (CPUPPCState *env) #define POWERPC_BFDM_7x0 (bfd_mach_ppc_750) #define POWERPC_FLAG_7x0 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM) +#define check_pow_7x0 check_pow_hid0 static void init_proc_7x0 (CPUPPCState *env) { @@ -3535,6 +3579,7 @@ static void init_proc_7x0 (CPUPPCState *env) #define POWERPC_BFDM_750fx (bfd_mach_ppc_750) #define POWERPC_FLAG_750fx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM) +#define check_pow_750fx check_pow_hid0 static void init_proc_750fx (CPUPPCState *env) { @@ -3580,6 +3625,7 @@ static void init_proc_750fx (CPUPPCState *env) #define POWERPC_BFDM_7x5 (bfd_mach_ppc_750) #define POWERPC_FLAG_7x5 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM) +#define check_pow_7x5 check_pow_hid0 static void init_proc_7x5 (CPUPPCState *env) { @@ -3640,6 +3686,7 @@ static void init_proc_7x5 (CPUPPCState *env) #define POWERPC_BFDM_7400 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7400 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM) +#define check_pow_7400 check_pow_hid0 static void init_proc_7400 (CPUPPCState *env) { @@ -3671,6 +3718,7 @@ static void init_proc_7400 (CPUPPCState *env) #define POWERPC_BFDM_7410 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7410 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM) +#define check_pow_7410 check_pow_hid0 static void init_proc_7410 (CPUPPCState *env) { @@ -3714,6 +3762,7 @@ static void init_proc_7410 (CPUPPCState *env) #define POWERPC_BFDM_7440 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7440 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM) +#define check_pow_7440 check_pow_hid0 __attribute__ (( unused )) static void init_proc_7440 (CPUPPCState *env) @@ -3784,6 +3833,7 @@ static void init_proc_7440 (CPUPPCState *env) #define POWERPC_BFDM_7450 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7450 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM) +#define check_pow_7450 check_pow_hid0 __attribute__ (( unused )) static void init_proc_7450 (CPUPPCState *env) @@ -3856,6 +3906,7 @@ static void init_proc_7450 (CPUPPCState *env) #define POWERPC_BFDM_7445 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7445 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM) +#define check_pow_7445 check_pow_hid0 __attribute__ (( unused )) static void init_proc_7445 (CPUPPCState *env) @@ -3960,6 +4011,7 @@ static void init_proc_7445 (CPUPPCState *env) #define POWERPC_BFDM_7455 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7455 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM) +#define check_pow_7455 check_pow_hid0 __attribute__ (( unused )) static void init_proc_7455 (CPUPPCState *env) @@ -4078,6 +4130,14 @@ static void init_proc_7455 (CPUPPCState *env) #define POWERPC970_HID5_INIT 0x00000000 #endif +static int check_pow_970 (CPUPPCState *env) +{ + if (env->spr[SPR_HID0] & 0x00600000) + return 1; + + return 0; +} + static void init_proc_970 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4147,6 +4207,14 @@ static void init_proc_970 (CPUPPCState *env) #define POWERPC_FLAG_970FX (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM) +static int check_pow_970FX (CPUPPCState *env) +{ + if (env->spr[SPR_HID0] & 0x00600000) + return 1; + + return 0; +} + static void init_proc_970FX (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4216,6 +4284,14 @@ static void init_proc_970FX (CPUPPCState *env) #define POWERPC_FLAG_970GX (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM) +static int check_pow_970GX (CPUPPCState *env) +{ + if (env->spr[SPR_HID0] & 0x00600000) + return 1; + + return 0; +} + static void init_proc_970GX (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4273,6 +4349,83 @@ static void init_proc_970GX (CPUPPCState *env) ppc970_irq_init(env); } +/* PowerPC 970 MP */ +#define POWERPC_INSNS_970MP (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ + PPC_64B | PPC_ALTIVEC | \ + PPC_SEGMENT_64B | PPC_SLBI) +#define POWERPC_MSRM_970MP (0x900000000204FF36ULL) +#define POWERPC_MMU_970MP (POWERPC_MMU_64B) +#define POWERPC_EXCP_970MP (POWERPC_EXCP_970) +#define POWERPC_INPUT_970MP (PPC_FLAGS_INPUT_970) +#define POWERPC_BFDM_970MP (bfd_mach_ppc64) +#define POWERPC_FLAG_970MP (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + +static int check_pow_970MP (CPUPPCState *env) +{ + if (env->spr[SPR_HID0] & 0x01C00000) + return 1; + + return 0; +} + +static void init_proc_970MP (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_clear, + 0x60000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_970_HID5, "HID5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + POWERPC970_HID5_INIT); + /* Memory management */ + /* XXX: not correct */ + gen_low_BATs(env); + /* XXX : not implemented */ + spr_register(env, SPR_MMUCFG, "MMUCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); /* TOFIX */ + /* XXX : not implemented */ + spr_register(env, SPR_MMUCSR0, "MMUCSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* TOFIX */ + spr_register(env, SPR_HIOR, "SPR_HIOR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFF00000); /* XXX: This is a hack */ +#if !defined(CONFIG_USER_ONLY) + env->excp_prefix = 0xFFF00000; +#endif +#if !defined(CONFIG_USER_ONLY) + env->slb_nr = 32; +#endif + init_excp_970(env); + env->dcache_line_size = 128; + env->icache_line_size = 128; + /* Allocate hardware IRQ controller */ + ppc970_irq_init(env); +} + /* PowerPC 620 */ #define POWERPC_INSNS_620 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_SLBI) @@ -4282,6 +4435,7 @@ static void init_proc_970GX (CPUPPCState *env) #define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_620 (bfd_mach_ppc64) #define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE) +#define check_pow_620 check_pow_nocheck /* Check this */ __attribute__ (( unused )) static void init_proc_620 (CPUPPCState *env) @@ -4313,9 +4467,10 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_MMU_PPC32 POWERPC_MMU_604 #define POWERPC_EXCP_PPC32 POWERPC_EXCP_604 #define POWERPC_INPUT_PPC32 POWERPC_INPUT_604 -#define init_proc_PPC32 init_proc_604 #define POWERPC_BFDM_PPC32 POWERPC_BFDM_604 #define POWERPC_FLAG_PPC32 POWERPC_FLAG_604 +#define check_pow_PPC32 check_pow_604 +#define init_proc_PPC32 init_proc_604 /* Default 64 bits PowerPC target will be 970 FX */ #define CPU_POWERPC_PPC64 CPU_POWERPC_970FX @@ -4324,9 +4479,10 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_MMU_PPC64 POWERPC_MMU_970FX #define POWERPC_EXCP_PPC64 POWERPC_EXCP_970FX #define POWERPC_INPUT_PPC64 POWERPC_INPUT_970FX -#define init_proc_PPC64 init_proc_970FX #define POWERPC_BFDM_PPC64 POWERPC_BFDM_970FX #define POWERPC_FLAG_PPC64 POWERPC_FLAG_970FX +#define check_pow_PPC64 check_pow_970FX +#define init_proc_PPC64 init_proc_970FX /* Default PowerPC target will be PowerPC 32 */ #if defined (TARGET_PPC64) && 0 // XXX: TODO @@ -4336,9 +4492,10 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC64 #define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC64 #define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64 -#define init_proc_DEFAULT init_proc_PPC64 #define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC64 #define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC64 +#define check_pow_DEFAULT check_pow_PPC64 +#define init_proc_DEFAULT init_proc_PPC64 #else #define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC32 #define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32 @@ -4346,9 +4503,10 @@ static void init_proc_620 (CPUPPCState *env) #define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC32 #define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC32 #define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32 -#define init_proc_DEFAULT init_proc_PPC32 #define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC32 #define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC32 +#define check_pow_DEFAULT check_pow_PPC32 +#define init_proc_DEFAULT init_proc_PPC32 #endif /*****************************************************************************/ @@ -4848,6 +5006,7 @@ enum { .bfd_mach = glue(POWERPC_BFDM_,_type), \ .flags = glue(POWERPC_FLAG_,_type), \ .init_proc = &glue(init_proc_,_type), \ + .check_pow = &glue(check_pow_,_type), \ } static ppc_def_t ppc_defs[] = { @@ -5671,11 +5830,11 @@ static ppc_def_t ppc_defs[] = { /* PowerPC 970GX (G5) */ POWERPC_DEF("970gx", CPU_POWERPC_970GX, 0xFFFFFFFF, 970GX), /* PowerPC 970MP */ - POWERPC_DEF("970mp", CPU_POWERPC_970MP, 0xFFFFFFFF, 970), + POWERPC_DEF("970mp", CPU_POWERPC_970MP, 0xFFFFFFFF, 970MP), /* PowerPC 970MP v1.0 */ - POWERPC_DEF("970mp1.0", CPU_POWERPC_970MP_v10, 0xFFFFFFFF, 970), + POWERPC_DEF("970mp1.0", CPU_POWERPC_970MP_v10, 0xFFFFFFFF, 970MP), /* PowerPC 970MP v1.1 */ - POWERPC_DEF("970mp1.1", CPU_POWERPC_970MP_v11, 0xFFFFFFFF, 970), + POWERPC_DEF("970mp1.1", CPU_POWERPC_970MP_v11, 0xFFFFFFFF, 970MP), #if defined (TODO) /* PowerPC Cell */ POWERPC_DEF("Cell", CPU_POWERPC_CELL, 0xFFFFFFFF, 970), @@ -5884,6 +6043,11 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) " Attempt Qemu to crash very soon !\n"); } #endif + if (env->check_pow == NULL) { + fprintf(stderr, "WARNING: no power management check handler " + "registered.\n" + " Attempt Qemu to crash very soon !\n"); + } } #if defined(PPC_DUMP_CPU) @@ -6186,6 +6350,7 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) env->bus_model = def->bus_model; env->flags = def->flags; env->bfd_mach = def->bfd_mach; + env->check_pow = def->check_pow; if (create_ppc_opcodes(env, def) < 0) return -1; init_ppc_proc(env, def); -- cgit v1.2.3 From cd346349b45ef056f138a184f660b8c34c3213cc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 25 Oct 2007 23:27:04 +0000 Subject: Add PowerPC power-management state check callback. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3441 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index cf4a110ac..fc1d9bbca 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -584,6 +584,7 @@ struct CPUPPCState { /* Power management */ int power_mode; + int (*check_pow)(CPUPPCState *env); /* temporary hack to handle OSI calls (only used if non NULL) */ int (*osi_call)(struct CPUPPCState *env); -- cgit v1.2.3 From 9d901a201bc37bbb40ca8fa325866cba047ec701 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 25 Oct 2007 23:28:36 +0000 Subject: Use host-utils for PowerPC 64 64x64 bits multiplications. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3442 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 4 +-- target-ppc/op_helper.c | 75 +------------------------------------------------- target-ppc/op_helper.h | 2 -- 3 files changed, 3 insertions(+), 78 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 0030c1466..0495879ce 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -980,7 +980,7 @@ void OPPROTO op_mulhd (void) { uint64_t tl, th; - do_imul64(&tl, &th); + muls64(&tl, &th, T0, T1); T0 = th; RETURN(); } @@ -998,7 +998,7 @@ void OPPROTO op_mulhdu (void) { uint64_t tl, th; - do_mul64(&tl, &th); + mulu64(&tl, &th, T0, T1); T0 = th; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index c654b139c..13c1fbb00 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -199,79 +199,6 @@ void ppc_store_dump_spr (int sprn, target_ulong val) /*****************************************************************************/ /* Fixed point operations helpers */ -#if defined(TARGET_PPC64) -static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) -{ - *plow += a; - /* carry test */ - if (*plow < a) - (*phigh)++; - *phigh += b; -} - -static void neg128 (uint64_t *plow, uint64_t *phigh) -{ - *plow = ~*plow; - *phigh = ~*phigh; - add128(plow, phigh, 1, 0); -} - -static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) -{ - uint32_t a0, a1, b0, b1; - uint64_t v; - - a0 = a; - a1 = a >> 32; - - b0 = b; - b1 = b >> 32; - - v = (uint64_t)a0 * (uint64_t)b0; - *plow = v; - *phigh = 0; - - v = (uint64_t)a0 * (uint64_t)b1; - add128(plow, phigh, v << 32, v >> 32); - - v = (uint64_t)a1 * (uint64_t)b0; - add128(plow, phigh, v << 32, v >> 32); - - v = (uint64_t)a1 * (uint64_t)b1; - *phigh += v; -#if defined(DEBUG_MULDIV) - printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", - a, b, *phigh, *plow); -#endif -} - -void do_mul64 (uint64_t *plow, uint64_t *phigh) -{ - mul64(plow, phigh, T0, T1); -} - -static void imul64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) -{ - int sa, sb; - - sa = (a < 0); - if (sa) - a = -a; - sb = (b < 0); - if (sb) - b = -b; - mul64(plow, phigh, a, b); - if (sa ^ sb) { - neg128(plow, phigh); - } -} - -void do_imul64 (uint64_t *plow, uint64_t *phigh) -{ - imul64(plow, phigh, T0, T1); -} -#endif - void do_adde (void) { T2 = T0; @@ -403,7 +330,7 @@ void do_mulldo (void) int64_t th; uint64_t tl; - do_imul64(&tl, &th); + muls64(&tl, &th, T0, T1); if (likely(th == 0)) { xer_ov = 0; } else { diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index e260b4ff9..d8b2f252c 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -79,8 +79,6 @@ void do_sraw (void); #if defined(TARGET_PPC64) void do_adde_64 (void); void do_addmeo_64 (void); -void do_imul64 (uint64_t *tl, uint64_t *th); -void do_mul64 (uint64_t *tl, uint64_t *th); void do_divdo (void); void do_divduo (void); void do_mulldo (void); -- cgit v1.2.3 From e14fe0a921631ab6cf1f404ad6243a716cb84366 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 25 Oct 2007 23:34:44 +0000 Subject: Use host-utils for Alpha 64x64 bits multiplications. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3443 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/op.c | 7 +++++-- target-alpha/op_helper.c | 28 ++++++---------------------- target-alpha/op_helper.h | 1 - 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/target-alpha/op.c b/target-alpha/op.c index 409325221..2a52be4f4 100644 --- a/target-alpha/op.c +++ b/target-alpha/op.c @@ -295,7 +295,7 @@ void OPPROTO op_mullv (void) void OPPROTO op_mulq (void) { - T0 *= T1; + T0 = (int64_t)T0 * (int64_t)T1; RETURN(); } @@ -307,7 +307,10 @@ void OPPROTO op_mulqv (void) void OPPROTO op_umulh (void) { - helper_umulh(); + uint64_t tl, th; + + mulu64(&tl, &th, T0, T1); + T0 = th; RETURN(); } diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index e471a1f06..3a34df49b 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -199,30 +199,14 @@ void helper_mullv (void) void helper_mulqv () { - uint64_t res, tmp0, tmp1; - - res = (T0 >> 32) * (T1 >> 32); - tmp0 = ((T0 & 0xFFFFFFFF) * (T1 >> 32)) + - ((T0 >> 32) * (T1 & 0xFFFFFFFF)); - tmp1 = (T0 & 0xFFFFFFFF) * (T1 & 0xFFFFFFFF); - tmp0 += tmp1 >> 32; - res += tmp0 >> 32; - T0 *= T1; - if (unlikely(res != 0)) { + uint64_t tl, th; + + muls64(&tl, &th, T0, T1); + /* If th != 0 && th != -1, then we had an overflow */ + if (unlikely((th + 1) > 1)) { helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); } -} - -void helper_umulh (void) -{ - uint64_t tmp0, tmp1; - - tmp0 = ((T0 & 0xFFFFFFFF) * (T1 >> 32)) + - ((T0 >> 32) * (T1 & 0xFFFFFFFF)); - tmp1 = (T0 & 0xFFFFFFFF) * (T1 & 0xFFFFFFFF); - tmp0 += tmp1 >> 32; - T0 = (T0 >> 32) * (T0 >> 32); - T0 += tmp0 >> 32; + T0 = tl; } void helper_ctpop (void) diff --git a/target-alpha/op_helper.h b/target-alpha/op_helper.h index 806a30d4a..0c65fd4a3 100644 --- a/target-alpha/op_helper.h +++ b/target-alpha/op_helper.h @@ -34,7 +34,6 @@ void helper_subqv (void); void helper_sublv (void); void helper_mullv (void); void helper_mulqv (void); -void helper_umulh (void); void helper_ctpop (void); void helper_ctlz (void); void helper_cttz (void); -- cgit v1.2.3 From 88ad920b8adbce8b00085c51a61e57b5fbc83b0c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 25 Oct 2007 23:36:08 +0000 Subject: Fix PowerPC 64x64 bits multiplication overflow check. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3444 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 13c1fbb00..06a5a561c 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -331,7 +331,8 @@ void do_mulldo (void) uint64_t tl; muls64(&tl, &th, T0, T1); - if (likely(th == 0)) { + /* If th != 0 && th != -1, then we had an overflow */ + if (likely((th + 1) <= 1)) { xer_ov = 0; } else { xer_ov = 1; -- cgit v1.2.3 From 2c1ee068b469ef5dcd8ea8f9220256a737e2b810 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 26 Oct 2007 00:37:04 +0000 Subject: Bugfix: PowerPC 64 slbia never invalidates the first segment entry. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3445 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index ea672bb4a..0ffa28ea7 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -735,7 +735,8 @@ void ppc_slb_invalidate_all (CPUPPCState *env) do_invalidate = 0; sr_base = env->spr[SPR_ASR]; - for (n = 0; n < env->slb_nr; n++) { + /* XXX: Warning: slbia never invalidates the first segment */ + for (n = 1; n < env->slb_nr; n++) { tmp64 = ldq_phys(sr_base); if (slb_is_valid(tmp64)) { slb_invalidate(&tmp64); -- cgit v1.2.3 From f9fdea6b85a6b95701aaeedad2ac3087e4b6b438 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 26 Oct 2007 00:38:37 +0000 Subject: Make PowerPC hypervisor resources able to compile, even if not enabled for now. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3446 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 0ffa28ea7..9bdd8835e 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2002,6 +2002,12 @@ static always_inline void powerpc_excp (CPUState *env, { target_ulong msr, new_msr, vector; int srr0, srr1, asrr0, asrr1; +#if defined(TARGET_PPC64H) + int lpes0, lpes1, lev; + + lpes0 = (env->spr[SPR_LPCR] >> 1) & 1; + lpes1 = (env->spr[SPR_LPCR] >> 2) & 1; +#endif if (loglevel & CPU_LOG_INT) { fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", @@ -2201,6 +2207,7 @@ static always_inline void powerpc_excp (CPUState *env, } new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) + lev = env->error_code; if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2322,7 +2329,7 @@ static always_inline void powerpc_excp (CPUState *env, #if defined(TARGET_PPC64H) case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ srr0 = SPR_HSRR0; - srr1 = SPR_HSSR1; + srr1 = SPR_HSRR1; new_msr |= (target_ulong)1 << MSR_HV; goto store_next; #endif @@ -2336,22 +2343,22 @@ static always_inline void powerpc_excp (CPUState *env, #if defined(TARGET_PPC64H) case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ srr0 = SPR_HSRR0; - srr1 = SPR_HSSR1; + srr1 = SPR_HSRR1; new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ srr0 = SPR_HSRR0; - srr1 = SPR_HSSR1; + srr1 = SPR_HSRR1; new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ srr0 = SPR_HSRR0; - srr1 = SPR_HSSR1; + srr1 = SPR_HSRR1; new_msr |= (target_ulong)1 << MSR_HV; goto store_next; case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ srr0 = SPR_HSRR0; - srr1 = SPR_HSSR1; + srr1 = SPR_HSRR1; new_msr |= (target_ulong)1 << MSR_HV; goto store_next; #endif /* defined(TARGET_PPC64H) */ @@ -2633,6 +2640,10 @@ void do_interrupt (CPUState *env) void ppc_hw_interrupt (CPUPPCState *env) { +#if defined(TARGET_PPC64H) + int hdice; +#endif + #if 0 if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n", @@ -2661,7 +2672,8 @@ void ppc_hw_interrupt (CPUPPCState *env) } #endif #if defined(TARGET_PPC64H) - if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) & hdice != 0) { + hdice = env->spr[SPR_LPCR] & 1; + if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) { /* Hypervisor decrementer exception */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); -- cgit v1.2.3 From c7697e1f51025283663c45880587d2da0af31a79 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 26 Oct 2007 00:46:07 +0000 Subject: Pretty dump for specific PowerPC instructions names. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3447 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 110 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 35 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 817045de8..54b37ac78 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -257,6 +257,12 @@ static void gen_##name (DisasContext *ctx); \ GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \ static void gen_##name (DisasContext *ctx) +#define GEN_HANDLER2(name, onam, opc1, opc2, opc3, inval, type) \ +static void gen_##name (DisasContext *ctx); \ +GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type); \ +static void gen_##name (DisasContext *ctx) + + typedef struct opcode_t { unsigned char opc1, opc2, opc3; #if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */ @@ -523,6 +529,20 @@ OPCODES_SECTION opcode_t opc_##name = { \ }, \ .oname = stringify(name), \ } +#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ) \ +OPCODES_SECTION opcode_t opc_##name = { \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval = invl, \ + .type = _typ, \ + .handler = &gen_##name, \ + .oname = onam, \ + }, \ + .oname = onam, \ +} #else #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ OPCODES_SECTION opcode_t opc_##name = { \ @@ -537,6 +557,19 @@ OPCODES_SECTION opcode_t opc_##name = { \ }, \ .oname = stringify(name), \ } +#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ) \ +OPCODES_SECTION opcode_t opc_##name = { \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval = invl, \ + .type = _typ, \ + .handler = &gen_##name, \ + }, \ + .oname = onam, \ +} #endif #define GEN_OPCODE_MARK(name) \ @@ -918,7 +951,7 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_op_store_T0_gpr(rD(ctx->opcode)); } /* addic. */ -GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { target_long simm = SIMM(ctx->opcode); @@ -1087,7 +1120,7 @@ GEN_LOGICAL2(and, 0x00, PPC_INTEGER); /* andc & andc. */ GEN_LOGICAL2(andc, 0x01, PPC_INTEGER); /* andi. */ -GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_andi_T0(UIMM(ctx->opcode)); @@ -1095,7 +1128,7 @@ GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) gen_set_Rc0(ctx); } /* andis. */ -GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) +GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_andi_T0(UIMM(ctx->opcode) << 16); @@ -1385,28 +1418,32 @@ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) #if defined(TARGET_PPC64) #define GEN_PPC64_R2(name, opc1, opc2) \ -GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B) \ +GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \ { \ gen_##name(ctx, 0); \ } \ -GEN_HANDLER(name##1, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B) \ +GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000, \ + PPC_64B) \ { \ gen_##name(ctx, 1); \ } #define GEN_PPC64_R4(name, opc1, opc2) \ -GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B) \ +GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \ { \ gen_##name(ctx, 0, 0); \ } \ -GEN_HANDLER(name##1, opc1, opc2 | 0x01, 0xFF, 0x00000000, PPC_64B) \ +GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x01, 0xFF, 0x00000000, \ + PPC_64B) \ { \ gen_##name(ctx, 0, 1); \ } \ -GEN_HANDLER(name##2, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B) \ +GEN_HANDLER2(name##2, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000, \ + PPC_64B) \ { \ gen_##name(ctx, 1, 0); \ } \ -GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B) \ +GEN_HANDLER2(name##3, stringify(name), opc1, opc2 | 0x11, 0xFF, 0x00000000, \ + PPC_64B) \ { \ gen_##name(ctx, 1, 1); \ } @@ -1606,11 +1643,11 @@ static always_inline void gen_sradi (DisasContext *ctx, int n) if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx); } -GEN_HANDLER(sradi0, 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B) +GEN_HANDLER2(sradi0, "sradi", 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B) { gen_sradi(ctx, 0); } -GEN_HANDLER(sradi1, 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B) +GEN_HANDLER2(sradi1, "sradi", 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B) { gen_sradi(ctx, 1); } @@ -2726,7 +2763,7 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES) } /* stwcx. */ -GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) +GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); @@ -2799,7 +2836,7 @@ GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B) } /* stdcx. */ -GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B) +GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); @@ -3802,7 +3839,7 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ) gen_op_check_reservation(); } -GEN_HANDLER(dcbz_970, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT) +GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT) { gen_addr_reg_index(ctx); if (ctx->opcode & 0x00200000) @@ -3943,7 +3980,7 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) #if defined(TARGET_PPC64) /* Specific implementation for PowerPC 64 "bridge" emulation using SLB */ /* mfsr */ -GEN_HANDLER(mfsr_64b, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B) +GEN_HANDLER2(mfsr_64b, "mfsr", 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -3959,7 +3996,8 @@ GEN_HANDLER(mfsr_64b, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B) } /* mfsrin */ -GEN_HANDLER(mfsrin_64b, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT_64B) +GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001, + PPC_SEGMENT_64B) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -3976,7 +4014,7 @@ GEN_HANDLER(mfsrin_64b, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT_64B) } /* mtsr */ -GEN_HANDLER(mtsr_64b, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B) +GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -3992,7 +4030,8 @@ GEN_HANDLER(mtsr_64b, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B) } /* mtsrin */ -GEN_HANDLER(mtsrin_64b, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT_64B) +GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001, + PPC_SEGMENT_64B) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -4215,6 +4254,7 @@ GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_POWER_clcs(); + /* Rc=1 sets CR0 to an undefined state */ gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -4622,7 +4662,7 @@ GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC) /* 602 - 603 - G2 TLB management */ /* tlbld */ -GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) +GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -4637,7 +4677,7 @@ GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) } /* tlbli */ -GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) +GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -4653,7 +4693,7 @@ GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) /* 74xx TLB management */ /* tlbld */ -GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB) +GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -4668,7 +4708,7 @@ GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB) } /* tlbli */ -GEN_HANDLER(tlbli_74xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB) +GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5217,7 +5257,7 @@ GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON) } /* icbt */ -GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT) +GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT) { /* interpreted as no-op */ /* XXX: specification say this is treated as a load by the MMU @@ -5254,7 +5294,7 @@ GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON) } /* rfci (supervisor only) */ -GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP) +GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5319,7 +5359,7 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI) /* TLB management - PowerPC 405 implementation */ /* tlbre */ -GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB) +GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5347,7 +5387,7 @@ GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB) } /* tlbsx - tlbsx. */ -GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB) +GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5365,7 +5405,7 @@ GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB) } /* tlbwe */ -GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB) +GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5394,7 +5434,7 @@ GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB) /* TLB management - PowerPC 440 implementation */ /* tlbre */ -GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) +GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5419,7 +5459,7 @@ GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) } /* tlbsx - tlbsx. */ -GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) +GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5437,7 +5477,7 @@ GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) } /* tlbwe */ -GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) +GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5527,7 +5567,7 @@ GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE) } /* icbt */ -GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE) +GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE) { /* interpreted as no-op */ /* XXX: specification say this is treated as a load by the MMU @@ -6079,19 +6119,19 @@ static always_inline void gen_evsel (DisasContext *ctx) gen_op_store_T0_gpr64(rD(ctx->opcode)); } -GEN_HANDLER(evsel0, 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE) +GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE) { gen_evsel(ctx); } -GEN_HANDLER(evsel1, 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE) +GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE) { gen_evsel(ctx); } -GEN_HANDLER(evsel2, 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE) +GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE) { gen_evsel(ctx); } -GEN_HANDLER(evsel3, 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE) +GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE) { gen_evsel(ctx); } -- cgit v1.2.3 From dac454af57c6389c2e3df0b8b51a9b35429d8caa Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 26 Oct 2007 00:48:00 +0000 Subject: Bugfix in PowerPC dcbi instruction: we must do a load before the store, or we'll store random data. Update cache instructions comments. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3448 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 54b37ac78..4c5e8c6b9 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3618,13 +3618,10 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) } /*** Cache management ***/ -/* For now, all those will be implemented as nop: - * this is valid, regarding the PowerPC specs... - * We just have to flush tb while invalidating instruction cache lines... - */ /* dcbf */ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE) { + /* XXX: specification says this is treated as a load by the MMU */ gen_addr_reg_index(ctx); op_ldst(lbz); } @@ -3641,7 +3638,7 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) } gen_addr_reg_index(ctx); /* XXX: specification says this should be treated as a store by the MMU */ - //op_ldst(lbz); + op_ldst(lbz); op_ldst(stb); #endif } -- cgit v1.2.3 From f0685f6e7a4179e75c4696de88de9657c6a86e95 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 26 Oct 2007 00:55:17 +0000 Subject: For consistency, align the address to the cache line before using it, when invalidating the instruction cache. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3449 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper_mem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index a395e0262..e8aa6407c 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -252,8 +252,8 @@ void glue(do_icbi, MEMSUFFIX) (void) * (not a fetch) by the MMU. To be sure it will be so, * do the load "by hand". */ - tmp = glue(ldl, MEMSUFFIX)((uint32_t)T0); T0 &= ~(env->icache_line_size - 1); + tmp = glue(ldl, MEMSUFFIX)((uint32_t)T0); tb_invalidate_page_range((uint32_t)T0, (uint32_t)(T0 + env->icache_line_size)); } @@ -267,8 +267,8 @@ void glue(do_icbi_64, MEMSUFFIX) (void) * (not a fetch) by the MMU. To be sure it will be so, * do the load "by hand". */ - tmp = glue(ldq, MEMSUFFIX)((uint64_t)T0); T0 &= ~(env->icache_line_size - 1); + tmp = glue(ldq, MEMSUFFIX)((uint64_t)T0); tb_invalidate_page_range((uint64_t)T0, (uint64_t)(T0 + env->icache_line_size)); } -- cgit v1.2.3 From 7d294b61edc6bd1be15739a11dce1414080dbb9b Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 26 Oct 2007 17:21:58 +0000 Subject: Fix Windows build failure, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3450 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index 2f3d8d04e..094afb319 100644 --- a/vl.c +++ b/vl.c @@ -8478,12 +8478,12 @@ int main(int argc, char **argv) main_loop(); quit_timers(); +#if !defined(_WIN32) /* close network clients */ for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { VLANClientState *vc; - for(vc = vlan->first_client; vc != NULL; vc = vc->next) -#if !defined(_WIN32) + for(vc = vlan->first_client; vc != NULL; vc = vc->next) { if (vc->fd_read == tap_receive) { char ifname[64]; TAPState *s = vc->opaque; @@ -8492,7 +8492,8 @@ int main(int argc, char **argv) s->down_script[0]) launch_script(s->down_script, ifname, s->fd); } -#endif } + } +#endif return 0; } -- cgit v1.2.3 From 31a60e22752d3daaa248ca10930f3cf4bc5f02e8 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 26 Oct 2007 18:42:59 +0000 Subject: Make Slirp statistics gathering and output conditional to LOG_ENABLED Add 'info slirp' command to monitor to display statistics Disable Slirp debugging code by default git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3451 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 4 +++ slirp/debug.c | 57 ++++++++++++++++++++++++++------------- slirp/debug.h | 10 ------- slirp/icmp_var.h | 2 ++ slirp/if.h | 2 ++ slirp/ip.h | 4 +++ slirp/ip_icmp.c | 16 ++++++----- slirp/ip_input.c | 32 ++++++++++++---------- slirp/ip_output.c | 10 +++---- slirp/libslirp.h | 2 ++ slirp/misc.c | 11 ++++++++ slirp/slirp.c | 11 +++++++- slirp/slirp.h | 11 +++++++- slirp/tcp_input.c | 78 +++++++++++++++++++++++++++--------------------------- slirp/tcp_output.c | 24 ++++++++--------- slirp/tcp_subr.c | 10 +++---- slirp/tcp_timer.c | 17 +++++++----- slirp/tcp_var.h | 3 +++ slirp/udp.c | 12 +++++---- slirp/udp.h | 5 ++++ vl.c | 4 +++ vl.h | 3 +++ 22 files changed, 203 insertions(+), 125 deletions(-) diff --git a/monitor.c b/monitor.c index 65f23b4e9..ac0c8e872 100644 --- a/monitor.c +++ b/monitor.c @@ -1364,6 +1364,10 @@ static term_cmd_t info_cmds[] = { #if defined(TARGET_PPC) { "cpustats", "", do_info_cpu_stats, "", "show CPU statistics", }, +#endif +#if defined(CONFIG_SLIRP) + { "slirp", "", do_info_slirp, + "", "show SLIRP statistics", }, #endif { NULL, NULL, }, }; diff --git a/slirp/debug.c b/slirp/debug.c index e31244550..77d504452 100644 --- a/slirp/debug.c +++ b/slirp/debug.c @@ -20,6 +20,7 @@ extern char *strerror _P((int)); /* Carry over one item from main.c so that the tty's restored. * Only done when the tty being used is /dev/tty --RedWolf */ +#ifndef CONFIG_QEMU extern struct termios slirp_tty_settings; extern int slirp_tty_restore; @@ -70,7 +71,9 @@ dump_packet(dat, n) } } #endif +#endif +#ifdef LOG_ENABLED #if 0 /* * Statistic routines @@ -80,7 +83,7 @@ dump_packet(dat, n) * the link as well. */ -void +static void ttystats(ttyp) struct ttys *ttyp; { @@ -119,8 +122,8 @@ ttystats(ttyp) lprint(" %6d bad input packets\r\n", is->in_mbad); } -void -allttystats() +static void +allttystats(void) { struct ttys *ttyp; @@ -129,8 +132,8 @@ allttystats() } #endif -void -ipstats() +static void +ipstats(void) { lprint(" \r\n"); @@ -153,9 +156,9 @@ ipstats() lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered); } -#if 0 -void -vjstats() +#ifndef CONFIG_QEMU +static void +vjstats(void) { lprint(" \r\n"); @@ -172,8 +175,8 @@ vjstats() } #endif -void -tcpstats() +static void +tcpstats(void) { lprint(" \r\n"); @@ -240,8 +243,8 @@ tcpstats() } -void -udpstats() +static void +udpstats(void) { lprint(" \r\n"); @@ -254,8 +257,8 @@ udpstats() lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets); } -void -icmpstats() +static void +icmpstats(void) { lprint(" \r\n"); lprint("ICMP stats:\r\n"); @@ -267,8 +270,8 @@ icmpstats() lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect); } -void -mbufstats() +static void +mbufstats(void) { struct mbuf *m; int i; @@ -291,8 +294,8 @@ mbufstats() lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued); } -void -sockstats() +static void +sockstats(void) { char buff[256]; int n; @@ -331,8 +334,9 @@ sockstats() so->so_rcv.sb_cc, so->so_snd.sb_cc); } } +#endif -#if 0 +#ifndef CONFIG_QEMU void slirp_exit(exit_status) int exit_status; @@ -374,3 +378,18 @@ slirp_exit(exit_status) exit(exit_status); } #endif + +void +slirp_stats(void) +{ +#ifdef LOG_ENABLED + ipstats(); + tcpstats(); + udpstats(); + icmpstats(); + mbufstats(); + sockstats(); +#else + lprint("SLIRP statistics code not compiled.\n"); +#endif +} diff --git a/slirp/debug.h b/slirp/debug.h index fa62cb9fe..8a523b2ed 100644 --- a/slirp/debug.h +++ b/slirp/debug.h @@ -37,14 +37,4 @@ extern int slirp_debug; #endif void debug_init _P((char *, int)); -//void ttystats _P((struct ttys *)); -void allttystats _P((void)); -void ipstats _P((void)); -void vjstats _P((void)); -void tcpstats _P((void)); -void udpstats _P((void)); -void icmpstats _P((void)); -void mbufstats _P((void)); -void sockstats _P((void)); -void slirp_exit _P((int)); diff --git a/slirp/icmp_var.h b/slirp/icmp_var.h index 03fc8c3ac..cd865b797 100644 --- a/slirp/icmp_var.h +++ b/slirp/icmp_var.h @@ -64,6 +64,8 @@ struct icmpstat { { "stats", CTLTYPE_STRUCT }, \ } +#ifdef LOG_ENABLED extern struct icmpstat icmpstat; +#endif #endif diff --git a/slirp/if.h b/slirp/if.h index bf24174a6..8f78ce7b6 100644 --- a/slirp/if.h +++ b/slirp/if.h @@ -29,6 +29,7 @@ extern struct mbuf *next_m; #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) +#ifdef LOG_ENABLED /* Interface statistics */ struct slirp_ifstats { u_int out_pkts; /* Output packets */ @@ -46,5 +47,6 @@ struct slirp_ifstats { u_int in_mbad; /* Bad incoming packets */ }; +#endif #endif diff --git a/slirp/ip.h b/slirp/ip.h index 371537d48..007facf3f 100644 --- a/slirp/ip.h +++ b/slirp/ip.h @@ -272,6 +272,7 @@ struct ipoption { int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ }; +#ifdef LOG_ENABLED /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. @@ -306,8 +307,11 @@ struct ipstat { }; extern struct ipstat ipstat; +#endif + extern struct ipq ipq; /* ip reass. queue */ extern u_int16_t ip_id; /* ip packet ctr, for ids */ + extern int ip_defttl; /* default IP ttl */ #endif diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index ae5a32118..4cf14c8e3 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -37,7 +37,9 @@ #include "slirp.h" #include "ip_icmp.h" +#ifdef LOG_ENABLED struct icmpstat icmpstat; +#endif /* The message sent when emulating PING */ /* Be nice and tell them it's just a psuedo-ping packet */ @@ -83,14 +85,14 @@ icmp_input(m, hlen) DEBUG_ARG("m = %lx", (long )m); DEBUG_ARG("m_len = %d", m->m_len); - icmpstat.icps_received++; + STAT(icmpstat.icps_received++); /* * Locate icmp structure in mbuf, and check * that its not corrupted and of at least minimum length. */ if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ - icmpstat.icps_tooshort++; + STAT(icmpstat.icps_tooshort++); freeit: m_freem(m); goto end_error; @@ -100,7 +102,7 @@ icmp_input(m, hlen) m->m_data += hlen; icp = mtod(m, struct icmp *); if (cksum(m, icmplen)) { - icmpstat.icps_checksum++; + STAT(icmpstat.icps_checksum++); goto freeit; } m->m_len += hlen; @@ -170,12 +172,12 @@ icmp_input(m, hlen) case ICMP_TSTAMP: case ICMP_MASKREQ: case ICMP_REDIRECT: - icmpstat.icps_notsupp++; + STAT(icmpstat.icps_notsupp++); m_freem(m); break; default: - icmpstat.icps_badtype++; + STAT(icmpstat.icps_badtype++); m_freem(m); } /* swith */ @@ -314,7 +316,7 @@ icmp_error(msrc, type, code, minsize, message) (void ) ip_output((struct socket *)NULL, m); - icmpstat.icps_reflect++; + STAT(icmpstat.icps_reflect++); end_error: return; @@ -371,5 +373,5 @@ icmp_reflect(m) (void ) ip_output((struct socket *)NULL, m); - icmpstat.icps_reflect++; + STAT(icmpstat.icps_reflect++); } diff --git a/slirp/ip_input.c b/slirp/ip_input.c index a7d6e3181..629745fba 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -46,7 +46,11 @@ #include "ip_icmp.h" int ip_defttl; + +#ifdef LOG_ENABLED struct ipstat ipstat; +#endif + struct ipq ipq; /* @@ -78,23 +82,23 @@ ip_input(m) DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m_len = %d", m->m_len); - ipstat.ips_total++; + STAT(ipstat.ips_total++); if (m->m_len < sizeof (struct ip)) { - ipstat.ips_toosmall++; + STAT(ipstat.ips_toosmall++); return; } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { - ipstat.ips_badvers++; + STAT(ipstat.ips_badvers++); goto bad; } hlen = ip->ip_hl << 2; if (hlenm->m_len) {/* min header length */ - ipstat.ips_badhlen++; /* or packet too short */ + STAT(ipstat.ips_badhlen++); /* or packet too short */ goto bad; } @@ -103,7 +107,7 @@ ip_input(m) * if (ip->ip_sum) { */ if(cksum(m,hlen)) { - ipstat.ips_badsum++; + STAT(ipstat.ips_badsum++); goto bad; } @@ -112,7 +116,7 @@ ip_input(m) */ NTOHS(ip->ip_len); if (ip->ip_len < hlen) { - ipstat.ips_badlen++; + STAT(ipstat.ips_badlen++); goto bad; } NTOHS(ip->ip_id); @@ -125,7 +129,7 @@ ip_input(m) * Drop packet if shorter than we expect. */ if (m->m_len < ip->ip_len) { - ipstat.ips_tooshort++; + STAT(ipstat.ips_tooshort++); goto bad; } /* Should drop packet if mbuf too long? hmmm... */ @@ -192,11 +196,11 @@ ip_input(m) * attempt reassembly; if it succeeds, proceed. */ if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { - ipstat.ips_fragments++; + STAT(ipstat.ips_fragments++); ip = ip_reass((struct ipasfrag *)ip, fp); if (ip == 0) return; - ipstat.ips_reassembled++; + STAT(ipstat.ips_reassembled++); m = dtom(ip); } else if (fp) @@ -208,7 +212,7 @@ ip_input(m) /* * Switch out to protocol's input routine. */ - ipstat.ips_delivered++; + STAT(ipstat.ips_delivered++); switch (ip->ip_p) { case IPPROTO_TCP: tcp_input(m, hlen, (struct socket *)NULL); @@ -220,7 +224,7 @@ ip_input(m) icmp_input(m, hlen); break; default: - ipstat.ips_noproto++; + STAT(ipstat.ips_noproto++); m_free(m); } return; @@ -385,7 +389,7 @@ insert: return ((struct ip *)ip); dropfrag: - ipstat.ips_fragdropped++; + STAT(ipstat.ips_fragdropped++); m_freem(m); return (0); } @@ -457,7 +461,7 @@ ip_slowtimo() --fp->ipq_ttl; fp = (struct ipq *) fp->next; if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { - ipstat.ips_fragtimeout++; + STAT(ipstat.ips_fragtimeout++); ip_freef((struct ipq *) fp->prev); } } @@ -664,7 +668,7 @@ bad: /* Not yet */ icmp_error(m, type, code, 0, 0); - ipstat.ips_badoptions++; + STAT(ipstat.ips_badoptions++); return (1); } diff --git a/slirp/ip_output.c b/slirp/ip_output.c index b1a848402..b41d0627c 100644 --- a/slirp/ip_output.c +++ b/slirp/ip_output.c @@ -80,7 +80,7 @@ ip_output(so, m0) ip->ip_off &= IP_DF; ip->ip_id = htons(ip_id++); ip->ip_hl = hlen >> 2; - ipstat.ips_localout++; + STAT(ipstat.ips_localout++); /* * Verify that we have any chance at all of being able to queue @@ -112,7 +112,7 @@ ip_output(so, m0) */ if (ip->ip_off & IP_DF) { error = -1; - ipstat.ips_cantfrag++; + STAT(ipstat.ips_cantfrag++); goto bad; } @@ -137,7 +137,7 @@ ip_output(so, m0) m = m_get(); if (m == 0) { error = -1; - ipstat.ips_odropped++; + STAT(ipstat.ips_odropped++); goto sendorfree; } m->m_data += if_maxlinkhdr; @@ -170,7 +170,7 @@ ip_output(so, m0) mhip->ip_sum = cksum(m, mhlen); *mnext = m; mnext = &m->m_nextpkt; - ipstat.ips_ofragments++; + STAT(ipstat.ips_ofragments++); } /* * Update first fragment by trimming what's been copied out @@ -193,7 +193,7 @@ sendorfree: } if (error == 0) - ipstat.ips_fragmented++; + STAT(ipstat.ips_fragmented++); } done: diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 639f5f222..7e4cfa98a 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -26,6 +26,8 @@ int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, extern const char *tftp_prefix; extern char slirp_hostname[33]; +void slirp_stats(void); + #ifdef __cplusplus } #endif diff --git a/slirp/misc.c b/slirp/misc.c index a41dd769b..d40fd629f 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -603,6 +603,16 @@ relay(s) } #endif +#ifdef CONFIG_QEMU +void lprint(const char *format, ...) +{ + va_list args; + + va_start(args, format); + term_vprintf(format, args); + va_end(args); +} +#else int (*lprint_print) _P((void *, const char *, va_list)); char *lprint_ptr, *lprint_ptr2, **lprint_arg; @@ -754,6 +764,7 @@ add_emu(buff) lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); } +#endif #ifdef BAD_SPRINTF diff --git a/slirp/slirp.c b/slirp/slirp.c index f535db12b..28f6c0cec 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -93,7 +93,9 @@ static int get_dns_addr(struct in_addr *pdns_addr) if (!f) return -1; +#ifdef DEBUG lprint("IP address of your DNS(s): "); +#endif while (fgets(buff, 512, f) != NULL) { if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { if (!inet_aton(buff2, &tmp_addr)) @@ -103,13 +105,20 @@ static int get_dns_addr(struct in_addr *pdns_addr) /* If it's the first one, set it to dns_addr */ if (!found) *pdns_addr = tmp_addr; +#ifdef DEBUG else lprint(", "); +#endif if (++found > 3) { +#ifdef DEBUG lprint("(more)"); +#endif break; - } else + } +#ifdef DEBUG + else lprint("%s", inet_ntoa(tmp_addr)); +#endif } } fclose(f); diff --git a/slirp/slirp.h b/slirp/slirp.h index 1ff68cb0b..ecff1d258 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -3,7 +3,16 @@ #define CONFIG_QEMU -#define DEBUG 1 +//#define DEBUG 1 + +// Uncomment the following line to enable SLIRP statistics printing in Qemu +//#define LOG_ENABLED + +#ifdef LOG_ENABLED +#define STAT(expr) expr +#else +#define STAT(expr) do { } while(0) +#endif #ifndef CONFIG_QEMU #include "version.h" diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 04f655312..abd827ebb 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -79,8 +79,8 @@ tcp_seq tcp_iss; /* tcp initial send seq # */ tp->t_flags |= TF_DELACK; \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++;\ - tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + STAT(tcpstat.tcps_rcvpack++); \ + STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len); \ if (so->so_emu) { \ if (tcp_emu((so),(m))) sbappend((so), (m)); \ } else \ @@ -99,8 +99,8 @@ tcp_seq tcp_iss; /* tcp initial send seq # */ tp->t_flags |= TF_DELACK; \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++;\ - tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + STAT(tcpstat.tcps_rcvpack++); \ + STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len); \ if (so->so_emu) { \ if (tcp_emu((so),(m))) sbappend(so, (m)); \ } else \ @@ -150,8 +150,8 @@ tcp_reass(tp, ti, m) i = q->ti_seq + q->ti_len - ti->ti_seq; if (i > 0) { if (i >= ti->ti_len) { - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += ti->ti_len; + STAT(tcpstat.tcps_rcvduppack++); + STAT(tcpstat.tcps_rcvdupbyte += ti->ti_len); m_freem(m); /* * Try to present any queued data @@ -167,8 +167,8 @@ tcp_reass(tp, ti, m) } q = (struct tcpiphdr *)(q->ti_next); } - tcpstat.tcps_rcvoopack++; - tcpstat.tcps_rcvoobyte += ti->ti_len; + STAT(tcpstat.tcps_rcvoopack++); + STAT(tcpstat.tcps_rcvoobyte += ti->ti_len); REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ /* @@ -275,7 +275,7 @@ tcp_input(m, iphlen, inso) } - tcpstat.tcps_rcvtotal++; + STAT(tcpstat.tcps_rcvtotal++); /* * Get IP and TCP header together in first mbuf. * Note: IP leaves IP header in first mbuf. @@ -308,7 +308,7 @@ tcp_input(m, iphlen, inso) * ti->ti_sum = cksum(m, len); * if (ti->ti_sum) { */ if(cksum(m, len)) { - tcpstat.tcps_rcvbadsum++; + STAT(tcpstat.tcps_rcvbadsum++); goto drop; } @@ -318,7 +318,7 @@ tcp_input(m, iphlen, inso) */ off = ti->ti_off << 2; if (off < sizeof (struct tcphdr) || off > tlen) { - tcpstat.tcps_rcvbadoff++; + STAT(tcpstat.tcps_rcvbadoff++); goto drop; } tlen -= off; @@ -375,7 +375,7 @@ findso: ti->ti_dst, ti->ti_dport); if (so) tcp_last_so = so; - ++tcpstat.tcps_socachemiss; + STAT(tcpstat.tcps_socachemiss++); } /* @@ -503,7 +503,7 @@ findso: /* * this is a pure ack for outstanding data. */ - ++tcpstat.tcps_predack; + STAT(tcpstat.tcps_predack++); /* if (ts_present) * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); * else @@ -511,8 +511,8 @@ findso: SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp, tp->t_rtt); acked = ti->ti_ack - tp->snd_una; - tcpstat.tcps_rcvackpack++; - tcpstat.tcps_rcvackbyte += acked; + STAT(tcpstat.tcps_rcvackpack++); + STAT(tcpstat.tcps_rcvackbyte += acked); sbdrop(&so->so_snd, acked); tp->snd_una = ti->ti_ack; m_freem(m); @@ -556,10 +556,10 @@ findso: * with nothing on the reassembly queue and * we have enough buffer space to take it. */ - ++tcpstat.tcps_preddat; + STAT(tcpstat.tcps_preddat++); tp->rcv_nxt += ti->ti_len; - tcpstat.tcps_rcvpack++; - tcpstat.tcps_rcvbyte += ti->ti_len; + STAT(tcpstat.tcps_rcvpack++); + STAT(tcpstat.tcps_rcvbyte += ti->ti_len); /* * Add data to socket buffer. */ @@ -726,7 +726,7 @@ findso: tp->t_flags |= TF_ACKNOW; tp->t_state = TCPS_SYN_RECEIVED; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tcpstat.tcps_accepts++; + STAT(tcpstat.tcps_accepts++); goto trimthenstep6; } /* case TCPS_LISTEN */ @@ -767,7 +767,7 @@ findso: tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW; if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { - tcpstat.tcps_connects++; + STAT(tcpstat.tcps_connects++); soisfconnected(so); tp->t_state = TCPS_ESTABLISHED; @@ -801,8 +801,8 @@ trimthenstep6: m_adj(m, -todrop); ti->ti_len = tp->rcv_wnd; tiflags &= ~TH_FIN; - tcpstat.tcps_rcvpackafterwin++; - tcpstat.tcps_rcvbyteafterwin += todrop; + STAT(tcpstat.tcps_rcvpackafterwin++); + STAT(tcpstat.tcps_rcvbyteafterwin += todrop); } tp->snd_wl1 = ti->ti_seq - 1; tp->rcv_up = ti->ti_seq; @@ -873,11 +873,11 @@ trimthenstep6: */ tp->t_flags |= TF_ACKNOW; todrop = ti->ti_len; - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += todrop; + STAT(tcpstat.tcps_rcvduppack++); + STAT(tcpstat.tcps_rcvdupbyte += todrop); } else { - tcpstat.tcps_rcvpartduppack++; - tcpstat.tcps_rcvpartdupbyte += todrop; + STAT(tcpstat.tcps_rcvpartduppack++); + STAT(tcpstat.tcps_rcvpartdupbyte += todrop); } m_adj(m, todrop); ti->ti_seq += todrop; @@ -896,7 +896,7 @@ trimthenstep6: if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { tp = tcp_close(tp); - tcpstat.tcps_rcvafterclose++; + STAT(tcpstat.tcps_rcvafterclose++); goto dropwithreset; } @@ -906,9 +906,9 @@ trimthenstep6: */ todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); if (todrop > 0) { - tcpstat.tcps_rcvpackafterwin++; + STAT(tcpstat.tcps_rcvpackafterwin++); if (todrop >= ti->ti_len) { - tcpstat.tcps_rcvbyteafterwin += ti->ti_len; + STAT(tcpstat.tcps_rcvbyteafterwin += ti->ti_len); /* * If a new connection request is received * while in TIME_WAIT, drop the old connection @@ -931,11 +931,11 @@ trimthenstep6: */ if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { tp->t_flags |= TF_ACKNOW; - tcpstat.tcps_rcvwinprobe++; + STAT(tcpstat.tcps_rcvwinprobe++); } else goto dropafterack; } else - tcpstat.tcps_rcvbyteafterwin += todrop; + STAT(tcpstat.tcps_rcvbyteafterwin += todrop); m_adj(m, -todrop); ti->ti_len -= todrop; tiflags &= ~(TH_PUSH|TH_FIN); @@ -976,7 +976,7 @@ trimthenstep6: /* so->so_error = ECONNRESET; */ close: tp->t_state = TCPS_CLOSED; - tcpstat.tcps_drops++; + STAT(tcpstat.tcps_drops++); tp = tcp_close(tp); goto drop; @@ -1015,7 +1015,7 @@ trimthenstep6: if (SEQ_GT(tp->snd_una, ti->ti_ack) || SEQ_GT(ti->ti_ack, tp->snd_max)) goto dropwithreset; - tcpstat.tcps_connects++; + STAT(tcpstat.tcps_connects++); tp->t_state = TCPS_ESTABLISHED; /* * The sent SYN is ack'ed with our sequence number +1 @@ -1072,7 +1072,7 @@ trimthenstep6: if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { - tcpstat.tcps_rcvdupack++; + STAT(tcpstat.tcps_rcvdupack++); DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", (long )m, (long )so)); /* @@ -1140,12 +1140,12 @@ trimthenstep6: tp->snd_cwnd = tp->snd_ssthresh; tp->t_dupacks = 0; if (SEQ_GT(ti->ti_ack, tp->snd_max)) { - tcpstat.tcps_rcvacktoomuch++; + STAT(tcpstat.tcps_rcvacktoomuch++); goto dropafterack; } acked = ti->ti_ack - tp->snd_una; - tcpstat.tcps_rcvackpack++; - tcpstat.tcps_rcvackbyte += acked; + STAT(tcpstat.tcps_rcvackpack++); + STAT(tcpstat.tcps_rcvackbyte += acked); /* * If we have a timestamp reply, update smoothed @@ -1284,7 +1284,7 @@ step6: /* keep track of pure window updates */ if (ti->ti_len == 0 && tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) - tcpstat.tcps_rcvwinupd++; + STAT(tcpstat.tcps_rcvwinupd++); tp->snd_wnd = tiwin; tp->snd_wl1 = ti->ti_seq; tp->snd_wl2 = ti->ti_ack; @@ -1616,7 +1616,7 @@ tcp_xmit_timer(tp, rtt) DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("rtt = %d", rtt); - tcpstat.tcps_rttupdated++; + STAT(tcpstat.tcps_rttupdated++); if (tp->t_srtt != 0) { /* * srtt is stored as fixed point with 3 bits after the diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c index 3eddfd38e..f4986516a 100644 --- a/slirp/tcp_output.c +++ b/slirp/tcp_output.c @@ -263,7 +263,7 @@ again: /* * No reason to send a segment, just return. */ - tcpstat.tcps_didnuttin++; + STAT(tcpstat.tcps_didnuttin++); return (0); @@ -339,13 +339,13 @@ send: */ if (len) { if (tp->t_force && len == 1) - tcpstat.tcps_sndprobe++; + STAT(tcpstat.tcps_sndprobe++); else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { - tcpstat.tcps_sndrexmitpack++; - tcpstat.tcps_sndrexmitbyte += len; + STAT(tcpstat.tcps_sndrexmitpack++); + STAT(tcpstat.tcps_sndrexmitbyte += len); } else { - tcpstat.tcps_sndpack++; - tcpstat.tcps_sndbyte += len; + STAT(tcpstat.tcps_sndpack++); + STAT(tcpstat.tcps_sndbyte += len); } m = m_get(); @@ -382,13 +382,13 @@ send: flags |= TH_PUSH; } else { if (tp->t_flags & TF_ACKNOW) - tcpstat.tcps_sndacks++; + STAT(tcpstat.tcps_sndacks++); else if (flags & (TH_SYN|TH_FIN|TH_RST)) - tcpstat.tcps_sndctrl++; + STAT(tcpstat.tcps_sndctrl++); else if (SEQ_GT(tp->snd_up, tp->snd_una)) - tcpstat.tcps_sndurg++; + STAT(tcpstat.tcps_sndurg++); else - tcpstat.tcps_sndwinup++; + STAT(tcpstat.tcps_sndwinup++); m = m_get(); if (m == NULL) { @@ -500,7 +500,7 @@ send: if (tp->t_rtt == 0) { tp->t_rtt = 1; tp->t_rtseq = startseq; - tcpstat.tcps_segstimed++; + STAT(tcpstat.tcps_segstimed++); } } @@ -567,7 +567,7 @@ out: */ return (error); } - tcpstat.tcps_sndtotal++; + STAT(tcpstat.tcps_sndtotal++); /* * Data sent (as far as we can tell). diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 3814ec19b..a20a0880b 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -255,9 +255,9 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err) if (TCPS_HAVERCVDSYN(tp->t_state)) { tp->t_state = TCPS_CLOSED; (void) tcp_output(tp); - tcpstat.tcps_drops++; + STAT(tcpstat.tcps_drops++); } else - tcpstat.tcps_conndrops++; + STAT(tcpstat.tcps_conndrops++); /* if (errno == ETIMEDOUT && tp->t_softerror) * errno = tp->t_softerror; */ @@ -305,7 +305,7 @@ tcp_close(tp) sbfree(&so->so_rcv); sbfree(&so->so_snd); sofree(so); - tcpstat.tcps_closed++; + STAT(tcpstat.tcps_closed++); return ((struct tcpcb *)0); } @@ -528,7 +528,7 @@ tcp_connect(inso) */ /* soisconnecting(so); */ /* NOFDREF used instead */ - tcpstat.tcps_connattempt++; + STAT(tcpstat.tcps_connattempt++); tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; @@ -857,7 +857,7 @@ tcp_emu(so, m) /*soisfconnecting(ns);*/ - tcpstat.tcps_connattempt++; + STAT(tcpstat.tcps_connattempt++); tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c index cc1bd50c0..3e865977c 100644 --- a/slirp/tcp_timer.c +++ b/slirp/tcp_timer.c @@ -41,7 +41,10 @@ int tcp_keepintvl = TCPTV_KEEPINTVL; int tcp_maxidle; int so_options = DO_KEEPALIVE; +#ifdef LOG_ENABLED struct tcpstat tcpstat; /* tcp statistics */ +#endif + u_int32_t tcp_now; /* for RFC 1323 timestamps */ /* @@ -62,7 +65,7 @@ tcp_fasttimo() (tp->t_flags & TF_DELACK)) { tp->t_flags &= ~TF_DELACK; tp->t_flags |= TF_ACKNOW; - tcpstat.tcps_delack++; + STAT(tcpstat.tcps_delack++); (void) tcp_output(tp); } } @@ -192,7 +195,7 @@ tcp_timers(tp, timer) * We tried our best, now the connection must die! */ tp->t_rxtshift = TCP_MAXRXTSHIFT; - tcpstat.tcps_timeoutdrop++; + STAT(tcpstat.tcps_timeoutdrop++); tp = tcp_drop(tp, tp->t_softerror); /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ return (tp); /* XXX */ @@ -204,7 +207,7 @@ tcp_timers(tp, timer) */ tp->t_rxtshift = 6; } - tcpstat.tcps_rexmttimeo++; + STAT(tcpstat.tcps_rexmttimeo++); rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; TCPT_RANGESET(tp->t_rxtcur, rexmt, (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ @@ -267,7 +270,7 @@ tcp_timers(tp, timer) * Force a byte to be output, if possible. */ case TCPT_PERSIST: - tcpstat.tcps_persisttimeo++; + STAT(tcpstat.tcps_persisttimeo++); tcp_setpersist(tp); tp->t_force = 1; (void) tcp_output(tp); @@ -279,7 +282,7 @@ tcp_timers(tp, timer) * or drop connection if idle for too long. */ case TCPT_KEEP: - tcpstat.tcps_keeptimeo++; + STAT(tcpstat.tcps_keeptimeo++); if (tp->t_state < TCPS_ESTABLISHED) goto dropit; @@ -299,7 +302,7 @@ tcp_timers(tp, timer) * by the protocol spec, this requires the * correspondent TCP to respond. */ - tcpstat.tcps_keepprobe++; + STAT(tcpstat.tcps_keepprobe++); #ifdef TCP_COMPAT_42 /* * The keepalive packet must have nonzero length @@ -317,7 +320,7 @@ tcp_timers(tp, timer) break; dropit: - tcpstat.tcps_keepdrops++; + STAT(tcpstat.tcps_keepdrops++); tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ break; } diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h index 0d6cd245e..82380f936 100644 --- a/slirp/tcp_var.h +++ b/slirp/tcp_var.h @@ -185,6 +185,7 @@ typedef u_int32_t mbufp_32; #endif #define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) +#ifdef LOG_ENABLED /* * TCP statistics. * Many of these should be kept per connection, @@ -247,6 +248,8 @@ struct tcpstat { }; extern struct tcpstat tcpstat; /* tcp statistics */ +#endif + extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ #endif diff --git a/slirp/udp.c b/slirp/udp.c index 44900ff14..851038094 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -45,7 +45,9 @@ #include #include "ip_icmp.h" +#ifdef LOG_ENABLED struct udpstat udpstat; +#endif struct socket udb; @@ -86,7 +88,7 @@ udp_input(m, iphlen) DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("iphlen = %d", iphlen); - udpstat.udps_ipackets++; + STAT(udpstat.udps_ipackets++); /* * Strip IP options, if any; should skip this, @@ -113,7 +115,7 @@ udp_input(m, iphlen) if (ip->ip_len != len) { if (len > ip->ip_len) { - udpstat.udps_badlen++; + STAT(udpstat.udps_badlen++); goto bad; } m_adj(m, len - ip->ip_len); @@ -140,7 +142,7 @@ udp_input(m, iphlen) * if (uh->uh_sum) { */ if(cksum(m, len + sizeof(struct ip))) { - udpstat.udps_badsum++; + STAT(udpstat.udps_badsum++); goto bad; } } @@ -181,7 +183,7 @@ udp_input(m, iphlen) if (tmp == &udb) { so = NULL; } else { - udpstat.udpps_pcbcachemiss++; + STAT(udpstat.udpps_pcbcachemiss++); udp_last_so = so; } } @@ -299,7 +301,7 @@ int udp_output2(struct socket *so, struct mbuf *m, ((struct ip *)ui)->ip_ttl = ip_defttl; ((struct ip *)ui)->ip_tos = iptos; - udpstat.udps_opackets++; + STAT(udpstat.udps_opackets++); error = ip_output(so, m); diff --git a/slirp/udp.h b/slirp/udp.h index 67da6cd73..12435eb82 100644 --- a/slirp/udp.h +++ b/slirp/udp.h @@ -72,6 +72,7 @@ struct udpiphdr { #define ui_ulen ui_u.uh_ulen #define ui_sum ui_u.uh_sum +#ifdef LOG_ENABLED struct udpstat { /* input statistics: */ u_long udps_ipackets; /* total input packets */ @@ -85,6 +86,7 @@ struct udpstat { /* output statistics: */ u_long udps_opackets; /* total output packets */ }; +#endif /* * Names for UDP sysctl objects @@ -92,7 +94,10 @@ struct udpstat { #define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ #define UDPCTL_MAXID 2 +#ifdef LOG_ENABLED extern struct udpstat udpstat; +#endif + extern struct socket udb; struct mbuf; diff --git a/vl.c b/vl.c index 094afb319..f9500a967 100644 --- a/vl.c +++ b/vl.c @@ -3782,6 +3782,10 @@ void net_slirp_smb(const char *exported_dir) } #endif /* !defined(_WIN32) */ +void do_info_slirp(void) +{ + slirp_stats(); +} #endif /* CONFIG_SLIRP */ diff --git a/vl.h b/vl.h index adf6004a7..681dd91ab 100644 --- a/vl.h +++ b/vl.h @@ -439,6 +439,9 @@ typedef struct NICInfo { extern int nb_nics; extern NICInfo nd_table[MAX_NICS]; +/* SLIRP */ +void do_info_slirp(void); + /* timers */ typedef struct QEMUClock QEMUClock; -- cgit v1.2.3 From 9634d9031c140b24c7ca0d8872632207f6ce7275 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 26 Oct 2007 19:01:16 +0000 Subject: Use const and static as needed, disable unused code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3452 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/bootp.c | 2 +- slirp/debug.c | 4 ++-- slirp/if.c | 20 -------------------- slirp/if.h | 25 +++++++++++++++++++------ slirp/ip.h | 2 -- slirp/ip_icmp.c | 2 +- slirp/ip_input.c | 31 +++++++++++++++--------------- slirp/ip_output.c | 6 +++--- slirp/main.h | 1 - slirp/mbuf.c | 27 ++++++++++----------------- slirp/mbuf.h | 1 - slirp/misc.c | 23 ++++++++++------------- slirp/misc.h | 6 +++--- slirp/sbuf.c | 8 ++++---- slirp/sbuf.h | 1 - slirp/slirp.c | 4 ++-- slirp/slirp.h | 11 +++-------- slirp/socket.c | 26 +++++++++++++++----------- slirp/socket.h | 5 ----- slirp/tcp.h | 4 +--- slirp/tcp_input.c | 55 +++++++++++++++++++++++++++--------------------------- slirp/tcp_output.c | 10 +++++----- slirp/tcp_subr.c | 39 +++++++++++++------------------------- slirp/tcp_timer.c | 28 +++++++++++---------------- slirp/tcp_timer.h | 7 +------ slirp/tftp.c | 8 ++++---- slirp/udp.c | 26 +++++++++++++------------- slirp/udp.h | 2 -- 28 files changed, 163 insertions(+), 221 deletions(-) diff --git a/slirp/bootp.c b/slirp/bootp.c index 9f2635bf3..3ae3db209 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -149,7 +149,7 @@ static void bootp_reply(struct bootp_t *bp) if ((m = m_get()) == NULL) return; - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; rbp = (struct bootp_t *)m->m_data; m->m_data += sizeof(struct udpiphdr); memset(rbp, 0, sizeof(struct bootp_t)); diff --git a/slirp/debug.c b/slirp/debug.c index 77d504452..7c8581d63 100644 --- a/slirp/debug.c +++ b/slirp/debug.c @@ -92,9 +92,9 @@ ttystats(ttyp) lprint(" \r\n"); - if (if_comp & IF_COMPRESS) + if (IF_COMP & IF_COMPRESS) strcpy(buff, "on"); - else if (if_comp & IF_NOCOMPRESS) + else if (IF_COMP & IF_NOCOMPRESS) strcpy(buff, "off"); else strcpy(buff, "off (for now)"); diff --git a/slirp/if.c b/slirp/if.c index 6d72fa72f..6feca55e3 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -7,9 +7,6 @@ #include -int if_mtu, if_mru; -int if_comp; -int if_maxlinkhdr; int if_queued = 0; /* Number of packets queued so far */ int if_thresh = 10; /* Number of packets queued before we start sending * (to prevent allocing too many mbufs) */ @@ -41,23 +38,6 @@ ifs_remque(ifm) void if_init() { -#if 0 - /* - * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, - * and 8 bytes for PPP, but need to have it on an 8byte boundary - */ -#ifdef USE_PPP - if_maxlinkhdr = 48; -#else - if_maxlinkhdr = 40; -#endif -#else - /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ - if_maxlinkhdr = 2 + 14 + 40; -#endif - if_mtu = 1500; - if_mru = 1500; - if_comp = IF_AUTOCOMP; if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq; if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq; // sl_compress_init(&comp_s); diff --git a/slirp/if.h b/slirp/if.h index 8f78ce7b6..ea96696b9 100644 --- a/slirp/if.h +++ b/slirp/if.h @@ -13,12 +13,25 @@ #define IF_AUTOCOMP 0x04 /* Autodetect (default) */ #define IF_NOCIDCOMP 0x08 /* CID compression */ -/* Needed for FreeBSD */ -#undef if_mtu -extern int if_mtu; -extern int if_mru; /* MTU and MRU */ -extern int if_comp; /* Flags for compression */ -extern int if_maxlinkhdr; +#define IF_MTU 1500 +#define IF_MRU 1500 +#define IF_COMP IF_AUTOCOMP /* Flags for compression */ + +#if 0 +/* + * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, + * and 8 bytes for PPP, but need to have it on an 8byte boundary + */ +#ifdef USE_PPP +#define IF_MAXLINKHDR 48 +#else +#define IF_MAXLINKHDR 40 +#endif +#else + /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ +#define IF_MAXLINKHDR (2 + 14 + 40) +#endif + extern int if_queued; /* Number of packets queued so far */ extern int if_thresh; /* Number of packets queued before we start sending * (to prevent allocing too many mbufs) */ diff --git a/slirp/ip.h b/slirp/ip.h index 007facf3f..a8cdb0d3f 100644 --- a/slirp/ip.h +++ b/slirp/ip.h @@ -312,6 +312,4 @@ extern struct ipstat ipstat; extern struct ipq ipq; /* ip reass. queue */ extern u_int16_t ip_id; /* ip packet ctr, for ids */ -extern int ip_defttl; /* default IP ttl */ - #endif diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 4cf14c8e3..b589651ca 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -46,7 +46,7 @@ struct icmpstat icmpstat; char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; /* list of actions for icmp_error() on RX of an icmp message */ -static int icmp_flush[19] = { +static const int icmp_flush[19] = { /* ECHO REPLY (0) */ 0, 1, 1, diff --git a/slirp/ip_input.c b/slirp/ip_input.c index 629745fba..b04684027 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -45,14 +45,19 @@ #include #include "ip_icmp.h" -int ip_defttl; - #ifdef LOG_ENABLED struct ipstat ipstat; #endif struct ipq ipq; +static struct ip *ip_reass(register struct ipasfrag *ip, + register struct ipq *fp); +static void ip_freef(struct ipq *fp); +static void ip_enq(register struct ipasfrag *p, + register struct ipasfrag *prev); +static void ip_deq(register struct ipasfrag *p); + /* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. @@ -64,7 +69,6 @@ ip_init() ip_id = tt.tv_sec & 0xffff; udp_init(); tcp_init(); - ip_defttl = IPDEFTTL; } /* @@ -239,10 +243,8 @@ bad: * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */ -struct ip * -ip_reass(ip, fp) - register struct ipasfrag *ip; - register struct ipq *fp; +static struct ip * +ip_reass(register struct ipasfrag *ip, register struct ipq *fp) { register struct mbuf *m = dtom(ip); register struct ipasfrag *q; @@ -398,9 +400,8 @@ dropfrag: * Free a fragment reassembly header and all * associated datagrams. */ -void -ip_freef(fp) - struct ipq *fp; +static void +ip_freef(struct ipq *fp) { register struct ipasfrag *q, *p; @@ -418,9 +419,8 @@ ip_freef(fp) * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */ -void -ip_enq(p, prev) - register struct ipasfrag *p, *prev; +static void +ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev) { DEBUG_CALL("ip_enq"); DEBUG_ARG("prev = %lx", (long)prev); @@ -433,9 +433,8 @@ ip_enq(p, prev) /* * To ip_enq as remque is to insque. */ -void -ip_deq(p) - register struct ipasfrag *p; +static void +ip_deq(register struct ipasfrag *p) { ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; diff --git a/slirp/ip_output.c b/slirp/ip_output.c index b41d0627c..86cf3a033 100644 --- a/slirp/ip_output.c +++ b/slirp/ip_output.c @@ -96,7 +96,7 @@ ip_output(so, m0) /* * If small enough for interface, can just send directly. */ - if ((u_int16_t)ip->ip_len <= if_mtu) { + if ((u_int16_t)ip->ip_len <= IF_MTU) { ip->ip_len = htons((u_int16_t)ip->ip_len); ip->ip_off = htons((u_int16_t)ip->ip_off); ip->ip_sum = 0; @@ -116,7 +116,7 @@ ip_output(so, m0) goto bad; } - len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ + len = (IF_MTU - hlen) &~ 7; /* ip databytes per packet */ if (len < 8) { error = -1; goto bad; @@ -140,7 +140,7 @@ ip_output(so, m0) STAT(ipstat.ips_odropped++); goto sendorfree; } - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; mhip = mtod(m, struct ip *); *mhip = *ip; diff --git a/slirp/main.h b/slirp/main.h index 9cd87584e..c01addac4 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -42,7 +42,6 @@ extern char *username; extern char *socket_path; extern int towrite_max; extern int ppp_exit; -extern int so_options; extern int tcp_keepintvl; extern uint8_t client_ethaddr[6]; diff --git a/slirp/mbuf.c b/slirp/mbuf.c index 392aea826..5d1255428 100644 --- a/slirp/mbuf.c +++ b/slirp/mbuf.c @@ -21,27 +21,20 @@ struct mbuf *mbutl; char *mclrefcnt; int mbuf_alloced = 0; struct mbuf m_freelist, m_usedlist; -int mbuf_thresh = 30; +#define MBUF_THRESH 30 int mbuf_max = 0; -int msize; + +/* + * Find a nice value for msize + * XXX if_maxlinkhdr already in mtu + */ +#define MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6) void m_init() { m_freelist.m_next = m_freelist.m_prev = &m_freelist; m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; - msize_init(); -} - -void -msize_init() -{ - /* - * Find a nice value for msize - * XXX if_maxlinkhdr already in mtu - */ - msize = (if_mtu>if_mru?if_mtu:if_mru) + - if_maxlinkhdr + sizeof(struct m_hdr ) + 6; } /* @@ -61,10 +54,10 @@ m_get() DEBUG_CALL("m_get"); if (m_freelist.m_next == &m_freelist) { - m = (struct mbuf *)malloc(msize); + m = (struct mbuf *)malloc(MSIZE); if (m == NULL) goto end_error; mbuf_alloced++; - if (mbuf_alloced > mbuf_thresh) + if (mbuf_alloced > MBUF_THRESH) flags = M_DOFREE; if (mbuf_alloced > mbuf_max) mbuf_max = mbuf_alloced; @@ -78,7 +71,7 @@ m_get() m->m_flags = (flags | M_USEDLIST); /* Initialise it */ - m->m_size = msize - sizeof(struct m_hdr); + m->m_size = MSIZE - sizeof(struct m_hdr); m->m_data = m->m_dat; m->m_len = 0; m->m_nextpkt = 0; diff --git a/slirp/mbuf.h b/slirp/mbuf.h index 1e8f7a8e4..f9f213255 100644 --- a/slirp/mbuf.h +++ b/slirp/mbuf.h @@ -135,7 +135,6 @@ extern struct mbuf m_freelist, m_usedlist; extern int mbuf_max; void m_init _P((void)); -void msize_init _P((void)); struct mbuf * m_get _P((void)); void m_free _P((struct mbuf *)); void m_cat _P((register struct mbuf *, register struct mbuf *)); diff --git a/slirp/misc.c b/slirp/misc.c index d40fd629f..755dfec94 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -8,8 +8,7 @@ #define WANT_SYS_IOCTL_H #include -u_int curtime, time_fasttimo, last_slowtimo, detach_time; -u_int detach_wait = 600000; /* 10 minutes */ +u_int curtime, time_fasttimo, last_slowtimo; #if 0 int x_port = -1; @@ -214,10 +213,7 @@ strerror(error) #ifdef _WIN32 int -fork_exec(so, ex, do_pty) - struct socket *so; - char *ex; - int do_pty; +fork_exec(struct socket *so, const char *ex, int do_pty) { /* not implemented */ return 0; @@ -225,6 +221,7 @@ fork_exec(so, ex, do_pty) #else +#ifndef CONFIG_QEMU int slirp_openpty(amaster, aslave) int *amaster, *aslave; @@ -289,6 +286,7 @@ slirp_openpty(amaster, aslave) return (-1); #endif } +#endif /* * XXX This is ugly @@ -302,23 +300,20 @@ slirp_openpty(amaster, aslave) * do_ptr = 2 Fork/exec using pty */ int -fork_exec(so, ex, do_pty) - struct socket *so; - char *ex; - int do_pty; +fork_exec(struct socket *so, const char *ex, int do_pty) { int s; struct sockaddr_in addr; int addrlen = sizeof(addr); int opt; - int master; + int master = -1; char *argv[256]; #if 0 char buff[256]; #endif /* don't want to clobber the original */ char *bptr; - char *curarg; + const char *curarg; int c, i, ret; DEBUG_CALL("fork_exec"); @@ -327,10 +322,12 @@ fork_exec(so, ex, do_pty) DEBUG_ARG("do_pty = %lx", (long)do_pty); if (do_pty == 2) { +#if 0 if (slirp_openpty(&master, &s) == -1) { lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } +#endif } else { addr.sin_family = AF_INET; addr.sin_port = 0; @@ -390,7 +387,7 @@ fork_exec(so, ex, do_pty) dup2(s, 0); dup2(s, 1); dup2(s, 2); - for (s = 3; s <= 255; s++) + for (s = getdtablesize() - 1; s >= 3; s--) close(s); i = 0; diff --git a/slirp/misc.h b/slirp/misc.h index 6484a8126..eee740575 100644 --- a/slirp/misc.h +++ b/slirp/misc.h @@ -12,12 +12,12 @@ struct ex_list { int ex_pty; /* Do we want a pty? */ int ex_addr; /* The last byte of the address */ int ex_fport; /* Port to telnet to */ - char *ex_exec; /* Command line of what to exec */ + const char *ex_exec; /* Command line of what to exec */ struct ex_list *ex_next; }; extern struct ex_list *exec_list; -extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait; +extern u_int curtime, time_fasttimo, last_slowtimo; extern int (*lprint_print) _P((void *, const char *, va_list)); extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; @@ -74,7 +74,7 @@ inline void slirp_insque _P((void *, void *)); inline void slirp_remque _P((void *)); int add_exec _P((struct ex_list **, int, char *, int, int)); int slirp_openpty _P((int *, int *)); -int fork_exec _P((struct socket *, char *, int)); +int fork_exec(struct socket *so, const char *ex, int do_pty); void snooze_hup _P((int)); void snooze _P((void)); void relay _P((int)); diff --git a/slirp/sbuf.c b/slirp/sbuf.c index 209064b1a..02c5fce0a 100644 --- a/slirp/sbuf.c +++ b/slirp/sbuf.c @@ -7,6 +7,8 @@ #include +static void sbappendsb(struct sbuf *sb, struct mbuf *m); + /* Done as a macro in socket.h */ /* int * sbspace(struct sockbuff *sb) @@ -133,10 +135,8 @@ sbappend(so, m) * Copy the data from m into sb * The caller is responsible to make sure there's enough room */ -void -sbappendsb(sb, m) - struct sbuf *sb; - struct mbuf *m; +static void +sbappendsb(struct sbuf *sb, struct mbuf *m) { int len, n, nn; diff --git a/slirp/sbuf.h b/slirp/sbuf.h index 89c4eb2f1..a4f103623 100644 --- a/slirp/sbuf.h +++ b/slirp/sbuf.h @@ -25,7 +25,6 @@ void sbfree _P((struct sbuf *)); void sbdrop _P((struct sbuf *, int)); void sbreserve _P((struct sbuf *, int)); void sbappend _P((struct socket *, struct mbuf *)); -void sbappendsb _P((struct sbuf *, struct mbuf *)); void sbcopy _P((struct sbuf *, int, int, char *)); #endif diff --git a/slirp/slirp.c b/slirp/slirp.c index 28f6c0cec..303f4825c 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -12,7 +12,7 @@ struct in_addr special_addr; /* virtual address alias for host */ struct in_addr alias_addr; -const uint8_t special_ethaddr[6] = { +static const uint8_t special_ethaddr[6] = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 }; @@ -130,7 +130,7 @@ static int get_dns_addr(struct in_addr *pdns_addr) #endif #ifdef _WIN32 -void slirp_cleanup(void) +static void slirp_cleanup(void) { WSACleanup(); } diff --git a/slirp/slirp.h b/slirp/slirp.h index ecff1d258..7b0e968f8 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -280,6 +280,9 @@ extern int do_echo; #define DEFAULT_BAUD 115200 +#define SO_OPTIONS DO_KEEPALIVE +#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL) + /* cksum.c */ int cksum(struct mbuf *m, int len); @@ -290,10 +293,6 @@ void if_output _P((struct socket *, struct mbuf *)); /* ip_input.c */ void ip_init _P((void)); void ip_input _P((struct mbuf *)); -struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); -void ip_freef _P((struct ipq *)); -void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); -void ip_deq _P((register struct ipasfrag *)); void ip_slowtimo _P((void)); void ip_stripoptions _P((register struct mbuf *, struct mbuf *)); @@ -301,10 +300,7 @@ void ip_stripoptions _P((register struct mbuf *, struct mbuf *)); int ip_output _P((struct socket *, struct mbuf *)); /* tcp_input.c */ -int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct mbuf *)); void tcp_input _P((register struct mbuf *, int, struct socket *)); -void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *)); -void tcp_xmit_timer _P((register struct tcpcb *, int)); int tcp_mss _P((register struct tcpcb *, u_int)); /* tcp_output.c */ @@ -317,7 +313,6 @@ void tcp_template _P((struct tcpcb *)); void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int)); struct tcpcb * tcp_newtcpcb _P((struct socket *)); struct tcpcb * tcp_close _P((register struct tcpcb *)); -void tcp_drain _P((void)); void tcp_sockclosed _P((struct tcpcb *)); int tcp_fconnect _P((struct socket *)); void tcp_connect _P((struct socket *)); diff --git a/slirp/socket.c b/slirp/socket.c index 7e07cf894..0c15132ea 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -13,12 +13,16 @@ #include #endif -void +static void sofcantrcvmore(struct socket *so); +static void sofcantsendmore(struct socket *so); + +#if 0 +static void so_init() { /* Nothing yet */ } - +#endif struct socket * solookup(head, laddr, lport, faddr, fport) @@ -421,7 +425,7 @@ sorecvfrom(so) int len, n; if (!(m = m_get())) return; - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; /* * XXX Shouldn't FIONREAD packets destined for port 53, @@ -604,12 +608,13 @@ solisten(port, laddr, lport, flags) return so; } +#if 0 /* * Data is available in so_rcv * Just write() the data to the socket * XXX not yet... */ -void +static void sorwakeup(so) struct socket *so; { @@ -622,12 +627,13 @@ sorwakeup(so) * We have room for a read() if we want to * For now, don't read, it'll be done in the main loop */ -void +static void sowwakeup(so) struct socket *so; { /* Nothing, yet */ } +#endif /* * Various session state calls @@ -652,9 +658,8 @@ soisfconnected(so) so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ } -void -sofcantrcvmore(so) - struct socket *so; +static void +sofcantrcvmore(struct socket *so) { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,0); @@ -669,9 +674,8 @@ sofcantrcvmore(so) so->so_state |= SS_FCANTRCVMORE; } -void -sofcantsendmore(so) - struct socket *so; +static void +sofcantsendmore(struct socket *so) { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,1); /* send FIN to fhost */ diff --git a/slirp/socket.h b/slirp/socket.h index 99cc17f32..94fb8d8cf 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -81,7 +81,6 @@ struct iovec { }; #endif -void so_init _P((void)); struct socket * solookup _P((struct socket *, struct in_addr, u_int, struct in_addr, u_int)); struct socket * socreate _P((void)); void sofree _P((struct socket *)); @@ -92,12 +91,8 @@ int sowrite _P((struct socket *)); void sorecvfrom _P((struct socket *)); int sosendto _P((struct socket *, struct mbuf *)); struct socket * solisten _P((u_int, u_int32_t, u_int, int)); -void sorwakeup _P((struct socket *)); -void sowwakeup _P((struct socket *)); void soisfconnecting _P((register struct socket *)); void soisfconnected _P((register struct socket *)); -void sofcantrcvmore _P((struct socket *)); -void sofcantsendmore _P((struct socket *)); void soisfdisconnected _P((struct socket *)); void sofwdrain _P((struct socket *)); diff --git a/slirp/tcp.h b/slirp/tcp.h index 229293c49..11150766d 100644 --- a/slirp/tcp.h +++ b/slirp/tcp.h @@ -42,8 +42,6 @@ typedef u_int32_t tcp_seq; #define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ #define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ -extern int tcp_rcvspace; -extern int tcp_sndspace; extern struct socket *tcp_last_so; #define TCP_SNDSPACE 8192 @@ -172,6 +170,6 @@ struct tcphdr { extern tcp_seq tcp_iss; /* tcp initial send seq # */ -extern char *tcpstates[]; +extern const char * const tcpstates[]; #endif diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index abd827ebb..17a9387f0 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -47,7 +47,7 @@ struct socket tcb; -int tcprexmtthresh = 3; +#define TCPREXMTTHRESH 3 struct socket *tcp_last_so = &tcb; tcp_seq tcp_iss; /* tcp initial send seq # */ @@ -112,12 +112,13 @@ tcp_seq tcp_iss; /* tcp initial send seq # */ } \ } #endif +static void tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, + struct tcpiphdr *ti); +static void tcp_xmit_timer(register struct tcpcb *tp, int rtt); -int -tcp_reass(tp, ti, m) - register struct tcpcb *tp; - register struct tcpiphdr *ti; - struct mbuf *m; +static int +tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti, + struct mbuf *m) { register struct tcpiphdr *q; struct socket *so = tp->t_socket; @@ -402,8 +403,8 @@ findso: goto dropwithreset; } - sbreserve(&so->so_snd, tcp_sndspace); - sbreserve(&so->so_rcv, tcp_rcvspace); + sbreserve(&so->so_snd, TCP_SNDSPACE); + sbreserve(&so->so_rcv, TCP_RCVSPACE); /* tcp_last_so = so; */ /* XXX ? */ /* tp = sototcpcb(so); */ @@ -448,10 +449,10 @@ findso: * Reset idle time and keep-alive timer. */ tp->t_idle = 0; - if (so_options) - tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + if (SO_OPTIONS) + tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL; else - tp->t_timer[TCPT_KEEP] = tcp_keepidle; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE; /* * Process options if not in LISTEN state, @@ -1102,7 +1103,7 @@ trimthenstep6: if (tp->t_timer[TCPT_REXMT] == 0 || ti->ti_ack != tp->snd_una) tp->t_dupacks = 0; - else if (++tp->t_dupacks == tcprexmtthresh) { + else if (++tp->t_dupacks == TCPREXMTTHRESH) { tcp_seq onxt = tp->snd_nxt; u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / @@ -1121,7 +1122,7 @@ trimthenstep6: if (SEQ_GT(onxt, tp->snd_nxt)) tp->snd_nxt = onxt; goto drop; - } else if (tp->t_dupacks > tcprexmtthresh) { + } else if (tp->t_dupacks > TCPREXMTTHRESH) { tp->snd_cwnd += tp->t_maxseg; (void) tcp_output(tp); goto drop; @@ -1135,7 +1136,7 @@ trimthenstep6: * If the congestion window was inflated to account * for the other side's cached packets, retract it. */ - if (tp->t_dupacks > tcprexmtthresh && + if (tp->t_dupacks > TCPREXMTTHRESH && tp->snd_cwnd > tp->snd_ssthresh) tp->snd_cwnd = tp->snd_ssthresh; tp->t_dupacks = 0; @@ -1227,7 +1228,7 @@ trimthenstep6: */ if (so->so_state & SS_FCANTRCVMORE) { soisfdisconnected(so); - tp->t_timer[TCPT_2MSL] = tcp_maxidle; + tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE; } tp->t_state = TCPS_FIN_WAIT_2; } @@ -1490,12 +1491,8 @@ drop: /* int *ts_present; * u_int32_t *ts_val, *ts_ecr; */ -void -tcp_dooptions(tp, cp, cnt, ti) - struct tcpcb *tp; - u_char *cp; - int cnt; - struct tcpiphdr *ti; +static void +tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti) { u_int16_t mss; int opt, optlen; @@ -1605,10 +1602,8 @@ tcp_pulloutofband(so, ti, m) * and update averages and current timeout. */ -void -tcp_xmit_timer(tp, rtt) - register struct tcpcb *tp; - int rtt; +static void +tcp_xmit_timer(register struct tcpcb *tp, int rtt) { register short delta; @@ -1707,7 +1702,7 @@ tcp_mss(tp, offer) DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("offer = %d", offer); - mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr); + mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr); if (offer) mss = min(mss, offer); mss = max(mss, 32); @@ -1716,8 +1711,12 @@ tcp_mss(tp, offer) tp->snd_cwnd = mss; - sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0)); - sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0)); + sbreserve(&so->so_snd, TCP_SNDSPACE + ((TCP_SNDSPACE % mss) ? + (mss - (TCP_SNDSPACE % mss)) : + 0)); + sbreserve(&so->so_rcv, TCP_RCVSPACE + ((TCP_RCVSPACE % mss) ? + (mss - (TCP_RCVSPACE % mss)) : + 0)); DEBUG_MISC((dfd, " returning mss = %d\n", mss)); diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c index f4986516a..dba4ed7a5 100644 --- a/slirp/tcp_output.c +++ b/slirp/tcp_output.c @@ -48,14 +48,14 @@ * Since this is only used in "stats socket", we give meaning * names instead of the REAL names */ -char *tcpstates[] = { +const char * const tcpstates[] = { /* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */ "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", }; -u_char tcp_outflags[TCP_NSTATES] = { +static const u_char tcp_outflags[TCP_NSTATES] = { TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK, @@ -354,7 +354,7 @@ send: error = 1; goto out; } - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; m->m_len = hdrlen; /* @@ -396,7 +396,7 @@ send: error = 1; goto out; } - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; m->m_len = hdrlen; } @@ -536,7 +536,7 @@ send: ((struct ip *)ti)->ip_len = m->m_len; - ((struct ip *)ti)->ip_ttl = ip_defttl; + ((struct ip *)ti)->ip_ttl = IPDEFTTL; ((struct ip *)ti)->ip_tos = so->so_iptos; /* #if BSD >= 43 */ diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index a20a0880b..d5ba21f17 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -46,11 +46,8 @@ #include /* patchable/settable parameters for tcp */ -int tcp_mssdflt = TCP_MSS; -int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; -int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ -int tcp_rcvspace; /* You may want to change this */ -int tcp_sndspace; /* Keep small if you have an error prone link */ +/* Don't do rfc1323 performance enhancements */ +#define TCP_DO_RFC1323 0 /* * Tcp initialization @@ -60,14 +57,6 @@ tcp_init() { tcp_iss = 1; /* wrong */ tcb.so_next = tcb.so_prev = &tcb; - - /* tcp_rcvspace = our Window we advertise to the remote */ - tcp_rcvspace = TCP_RCVSPACE; - tcp_sndspace = TCP_SNDSPACE; - - /* Make sure tcp_sndspace is at least 2*MSS */ - if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) - tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); } /* @@ -145,7 +134,7 @@ tcp_respond(tp, ti, m, ack, seq, flags) #else tlen = 0; #endif - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; *mtod(m, struct tcpiphdr *) = *ti; ti = mtod(m, struct tcpiphdr *); flags = TH_ACK; @@ -186,7 +175,7 @@ tcp_respond(tp, ti, m, ack, seq, flags) if(flags & TH_RST) ((struct ip *)ti)->ip_ttl = MAXTTL; else - ((struct ip *)ti)->ip_ttl = ip_defttl; + ((struct ip *)ti)->ip_ttl = IPDEFTTL; (void) ip_output((struct socket *)0, m); } @@ -208,9 +197,9 @@ tcp_newtcpcb(so) memset((char *) tp, 0, sizeof(struct tcpcb)); tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; - tp->t_maxseg = tcp_mssdflt; + tp->t_maxseg = TCP_MSS; - tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; + tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; tp->t_socket = so; /* @@ -219,7 +208,7 @@ tcp_newtcpcb(so) * reasonable initial retransmit time. */ tp->t_srtt = TCPTV_SRTTBASE; - tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; + tp->t_rttvar = TCPTV_SRTTDFLT << 2; tp->t_rttmin = TCPTV_MIN; TCPT_RANGESET(tp->t_rxtcur, @@ -309,6 +298,7 @@ tcp_close(tp) return ((struct tcpcb *)0); } +#ifdef notdef void tcp_drain() { @@ -319,9 +309,6 @@ tcp_drain() * When a source quench is received, close congestion window * to one segment. We will gradually open it again as we proceed. */ - -#ifdef notdef - void tcp_quench(i, errno) @@ -556,7 +543,7 @@ tcp_attach(so) /* * Set the socket's type of service field */ -struct tos_t tcptos[] = { +static const struct tos_t tcptos[] = { {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ @@ -572,7 +559,7 @@ struct tos_t tcptos[] = { {0, 0, 0, 0} }; -struct emu_t *tcpemu = 0; +static struct emu_t *tcpemu = 0; /* * Return TOS according to the above table @@ -665,7 +652,7 @@ tcp_emu(so, m) so_rcv->sb_rptr += m->m_len; m->m_data[m->m_len] = 0; /* NULL terminate */ if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { - if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { + if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) { HTONS(n1); HTONS(n2); /* n2 is the one on our host */ @@ -991,7 +978,7 @@ do_prompt: /* * Need to emulate the PORT command */ - x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", + x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]", &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; @@ -1022,7 +1009,7 @@ do_prompt: /* * Need to emulate the PASV response */ - x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]", + x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]", &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c index 3e865977c..244bad6a8 100644 --- a/slirp/tcp_timer.c +++ b/slirp/tcp_timer.c @@ -36,17 +36,14 @@ #include -int tcp_keepidle = TCPTV_KEEP_IDLE; -int tcp_keepintvl = TCPTV_KEEPINTVL; -int tcp_maxidle; -int so_options = DO_KEEPALIVE; - #ifdef LOG_ENABLED struct tcpstat tcpstat; /* tcp statistics */ #endif u_int32_t tcp_now; /* for RFC 1323 timestamps */ +static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer); + /* * Fast timeout routine for processing delayed acks */ @@ -84,7 +81,6 @@ tcp_slowtimo() DEBUG_CALL("tcp_slowtimo"); - tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; /* * Search through tcb's and update active timers. */ @@ -130,16 +126,14 @@ tcp_canceltimers(tp) tp->t_timer[i] = 0; } -int tcp_backoff[TCP_MAXRXTSHIFT + 1] = +const int tcp_backoff[TCP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; /* * TCP timer processing. */ -struct tcpcb * -tcp_timers(tp, timer) - register struct tcpcb *tp; - int timer; +static struct tcpcb * +tcp_timers(register struct tcpcb *tp, int timer) { register int rexmt; @@ -155,8 +149,8 @@ tcp_timers(tp, timer) */ case TCPT_2MSL: if (tp->t_state != TCPS_TIME_WAIT && - tp->t_idle <= tcp_maxidle) - tp->t_timer[TCPT_2MSL] = tcp_keepintvl; + tp->t_idle <= TCP_MAXIDLE) + tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL; else tp = tcp_close(tp); break; @@ -287,8 +281,8 @@ tcp_timers(tp, timer) goto dropit; /* if (tp->t_socket->so_options & SO_KEEPALIVE && */ - if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { - if (tp->t_idle >= tcp_keepidle + tcp_maxidle) + if ((SO_OPTIONS) && tp->t_state <= TCPS_CLOSE_WAIT) { + if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE) goto dropit; /* * Send a packet designed to force a response @@ -314,9 +308,9 @@ tcp_timers(tp, timer) tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, tp->rcv_nxt, tp->snd_una - 1, 0); #endif - tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL; } else - tp->t_timer[TCPT_KEEP] = tcp_keepidle; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE; break; dropit: diff --git a/slirp/tcp_timer.h b/slirp/tcp_timer.h index 59933bc1b..f251846b4 100644 --- a/slirp/tcp_timer.h +++ b/slirp/tcp_timer.h @@ -126,17 +126,12 @@ char *tcptimers[] = (tv) = (tvmax); \ } -extern int tcp_keepidle; /* time before keepalive probes begin */ -extern int tcp_keepintvl; /* time between keepalive probes */ -extern int tcp_maxidle; /* time to drop after starting probes */ -extern int tcp_ttl; /* time to live for TCP segs */ -extern int tcp_backoff[]; +extern const int tcp_backoff[]; struct tcpcb; void tcp_fasttimo _P((void)); void tcp_slowtimo _P((void)); void tcp_canceltimers _P((struct tcpcb *)); -struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); #endif diff --git a/slirp/tftp.c b/slirp/tftp.c index 2b2bf2c5a..562ae8953 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -34,7 +34,7 @@ struct tftp_session { int timestamp; }; -struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; +static struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; const char *tftp_prefix; @@ -143,7 +143,7 @@ static int tftp_send_oack(struct tftp_session *spt, memset(m->m_data, 0, m->m_size); - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); @@ -183,7 +183,7 @@ static int tftp_send_error(struct tftp_session *spt, memset(m->m_data, 0, m->m_size); - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); @@ -230,7 +230,7 @@ static int tftp_send_data(struct tftp_session *spt, memset(m->m_data, 0, m->m_size); - m->m_data += if_maxlinkhdr; + m->m_data += IF_MAXLINKHDR; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); diff --git a/slirp/udp.c b/slirp/udp.c index 851038094..c48923b0c 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -51,14 +51,17 @@ struct udpstat udpstat; struct socket udb; +static u_int8_t udp_tos(struct socket *so); +static void udp_emu(struct socket *so, struct mbuf *m); + /* * UDP protocol implementation. * Per RFC 768, August, 1980. */ #ifndef COMPAT_42 -int udpcksum = 1; +#define UDPCKSUM 1 #else -int udpcksum = 0; /* XXX */ +#define UDPCKSUM 0 /* XXX */ #endif struct socket *udp_last_so = &udb; @@ -132,7 +135,7 @@ udp_input(m, iphlen) /* * Checksum extended UDP header and data. */ - if (udpcksum && uh->uh_sum) { + if (UDPCKSUM && uh->uh_sum) { ((struct ipovly *)ip)->ih_next = 0; ((struct ipovly *)ip)->ih_prev = 0; ((struct ipovly *)ip)->ih_x1 = 0; @@ -292,13 +295,13 @@ int udp_output2(struct socket *so, struct mbuf *m, * Stuff checksum and output datagram. */ ui->ui_sum = 0; - if (udpcksum) { + if (UDPCKSUM) { if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) ui->ui_sum = 0xffff; } ((struct ip *)ui)->ip_len = m->m_len; - ((struct ip *)ui)->ip_ttl = ip_defttl; + ((struct ip *)ui)->ip_ttl = IPDEFTTL; ((struct ip *)ui)->ip_tos = iptos; STAT(udpstat.udps_opackets++); @@ -369,7 +372,7 @@ udp_detach(so) sofree(so); } -struct tos_t udptos[] = { +static const struct tos_t udptos[] = { {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ @@ -377,9 +380,8 @@ struct tos_t udptos[] = { {0, 0, 0, 0} }; -u_int8_t -udp_tos(so) - struct socket *so; +static u_int8_t +udp_tos(struct socket *so) { int i = 0; @@ -402,10 +404,8 @@ udp_tos(so) /* * Here, talk/ytalk/ntalk requests must be emulated */ -void -udp_emu(so, m) - struct socket *so; - struct mbuf *m; +static void +udp_emu(struct socket *so, struct mbuf *m) { struct sockaddr_in addr; int addrlen = sizeof(addr); diff --git a/slirp/udp.h b/slirp/udp.h index 12435eb82..4f69b098c 100644 --- a/slirp/udp.h +++ b/slirp/udp.h @@ -106,8 +106,6 @@ void udp_input _P((register struct mbuf *, int)); int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *)); int udp_attach _P((struct socket *)); void udp_detach _P((struct socket *)); -u_int8_t udp_tos _P((struct socket *)); -void udp_emu _P((struct socket *, struct mbuf *)); struct socket * udp_listen _P((u_int, u_int32_t, u_int, int)); int udp_output2(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, struct sockaddr_in *daddr, -- cgit v1.2.3 From 7878ff6bc7c9bc4091d19a51a1dc4bac2df23560 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 26 Oct 2007 19:34:46 +0000 Subject: Add const etc. to places forgotten from the previous commit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3453 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/if.c | 2 -- slirp/if.h | 2 -- slirp/ip_icmp.c | 4 ++-- slirp/ip_output.c | 6 +++++- slirp/slirp.h | 2 -- slirp/tcp_subr.c | 2 ++ 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/slirp/if.c b/slirp/if.c index 6feca55e3..67a7b6ff8 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -8,8 +8,6 @@ #include int if_queued = 0; /* Number of packets queued so far */ -int if_thresh = 10; /* Number of packets queued before we start sending - * (to prevent allocing too many mbufs) */ struct mbuf if_fastq; /* fast queue (for interactive data) */ struct mbuf if_batchq; /* queue for non-interactive data */ diff --git a/slirp/if.h b/slirp/if.h index ea96696b9..bed7152fe 100644 --- a/slirp/if.h +++ b/slirp/if.h @@ -33,8 +33,6 @@ #endif extern int if_queued; /* Number of packets queued so far */ -extern int if_thresh; /* Number of packets queued before we start sending - * (to prevent allocing too many mbufs) */ extern struct mbuf if_fastq; /* fast queue (for interactive data) */ extern struct mbuf if_batchq; /* queue for non-interactive data */ diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index b589651ca..d1da0a2fc 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -42,8 +42,8 @@ struct icmpstat icmpstat; #endif /* The message sent when emulating PING */ -/* Be nice and tell them it's just a psuedo-ping packet */ -char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; +/* Be nice and tell them it's just a pseudo-ping packet */ +const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; /* list of actions for icmp_error() on RX of an icmp message */ static const int icmp_flush[19] = { diff --git a/slirp/ip_output.c b/slirp/ip_output.c index 86cf3a033..a8a6067bd 100644 --- a/slirp/ip_output.c +++ b/slirp/ip_output.c @@ -46,6 +46,10 @@ u_int16_t ip_id; +/* Number of packets queued before we start sending + * (to prevent allocing too many mbufs) */ +#define IF_THRESH 10 + /* * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). @@ -87,7 +91,7 @@ ip_output(so, m0) * the packet or packet fragments */ /* XXX Hmmm... */ -/* if (if_queued > if_thresh && towrite <= 0) { +/* if (if_queued > IF_THRESH && towrite <= 0) { * error = ENOBUFS; * goto bad; * } diff --git a/slirp/slirp.h b/slirp/slirp.h index 7b0e968f8..a28e5feac 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -264,8 +264,6 @@ void if_start _P((struct ttys *)); void lprint _P((const char *, ...)); -extern int do_echo; - #if SIZEOF_CHAR_P == 4 # define insque_32 insque # define remque_32 remque diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index d5ba21f17..7d7127054 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -592,7 +592,9 @@ tcp_tos(so) return 0; } +#if 0 int do_echo = -1; +#endif /* * Emulate programs that try and connect to us -- cgit v1.2.3 From 5592a750b913c859c738eb2774c26632dcac8350 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 26 Oct 2007 22:35:02 +0000 Subject: The other half of the mul64 rework. Sorry for the breakage, I committed an incomplete version of what I tested. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3454 c046a42c-6fe2-441c-8c8c-71466251a162 --- host-utils.c | 2 ++ target-i386/helper.c | 6 +++--- target-mips/op.c | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/host-utils.c b/host-utils.c index d0d780e54..a3c838f4d 100644 --- a/host-utils.c +++ b/host-utils.c @@ -25,6 +25,8 @@ #include "vl.h" +//#define DEBUG_MULDIV + /* Long integer helpers */ static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { diff --git a/target-i386/helper.c b/target-i386/helper.c index c5d4487a6..88aa82e42 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3724,7 +3724,7 @@ void helper_mulq_EAX_T0(void) { uint64_t r0, r1; - mulu64(&r1, &r0, EAX, T0); + mulu64(&r0, &r1, EAX, T0); EAX = r0; EDX = r1; CC_DST = r0; @@ -3735,7 +3735,7 @@ void helper_imulq_EAX_T0(void) { uint64_t r0, r1; - muls64(&r1, &r0, EAX, T0); + muls64(&r0, &r1, EAX, T0); EAX = r0; EDX = r1; CC_DST = r0; @@ -3746,7 +3746,7 @@ void helper_imulq_T0_T1(void) { uint64_t r0, r1; - muls64(&r1, &r0, T0, T1); + muls64(&r0, &r1, T0, T1); T0 = r0; CC_DST = r0; CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); diff --git a/target-mips/op.c b/target-mips/op.c index 5c26d176c..1ecec9a57 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -876,13 +876,13 @@ void op_msubu (void) #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) void op_dmult (void) { - CALL_FROM_TB4(muls64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1); + CALL_FROM_TB4(muls64, &(env->LO[0][env->current_tc]), &(env->HI[0][env->current_tc]), T0, T1); RETURN(); } void op_dmultu (void) { - CALL_FROM_TB4(mulu64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1); + CALL_FROM_TB4(mulu64, &(env->LO[0][env->current_tc]), &(env->HI[0][env->current_tc]), T0, T1); RETURN(); } #endif -- cgit v1.2.3 From 05f778c8bdfa3f0499c3777f562db1feed338502 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 27 Oct 2007 13:05:54 +0000 Subject: Add sharable clz/clo inline functions and use them for the mips target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3455 c046a42c-6fe2-441c-8c8c-71466251a162 --- host-utils.h | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ target-mips/exec.h | 2 + target-mips/op.c | 67 +++++++++---------------------- target-mips/op_helper.c | 13 ++++++ 4 files changed, 137 insertions(+), 49 deletions(-) create mode 100644 host-utils.h diff --git a/host-utils.h b/host-utils.h new file mode 100644 index 000000000..d1e89c2f3 --- /dev/null +++ b/host-utils.h @@ -0,0 +1,104 @@ +/* + * Utility compute operations used by translated code. + * + * Copyright (c) 2007 Thiemo Seufer + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* Note that some of those functions may end up calling libgcc functions, + depending on the host machine. It is up to the target emulation to + cope with that. */ + +/* Binary search for leading zeros. */ + +static always_inline int clz32(uint32_t val) +{ + int cnt = 0; + + if (!(val & 0xFFFF0000U)) { + cnt += 16; + val <<= 16; + } + if (!(val & 0xFF000000U)) { + cnt += 8; + val <<= 8; + } + if (!(val & 0xF0000000U)) { + cnt += 4; + val <<= 4; + } + if (!(val & 0xC0000000U)) { + cnt += 2; + val <<= 2; + } + if (!(val & 0x80000000U)) { + cnt++; + val <<= 1; + } + if (!(val & 0x80000000U)) { + cnt++; + } + return cnt; +} + +static always_inline int clo32(uint32_t val) +{ + return clz32(~val); +} + +static always_inline int clz64(uint64_t val) +{ + int cnt = 0; + + if (!(val & 0xFFFFFFFF00000000ULL)) { + cnt += 32; + val <<= 32; + } + if (!(val & 0xFFFF000000000000ULL)) { + cnt += 16; + val <<= 16; + } + if (!(val & 0xFF00000000000000ULL)) { + cnt += 8; + val <<= 8; + } + if (!(val & 0xF000000000000000ULL)) { + cnt += 4; + val <<= 4; + } + if (!(val & 0xC000000000000000ULL)) { + cnt += 2; + val <<= 2; + } + if (!(val & 0x8000000000000000ULL)) { + cnt++; + val <<= 1; + } + if (!(val & 0x8000000000000000ULL)) { + cnt++; + } + return cnt; +} + +static always_inline int clo64(uint64_t val) +{ + return clz64(~val); +} diff --git a/target-mips/exec.h b/target-mips/exec.h index c6dc25cf6..61c09acb6 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -70,6 +70,8 @@ void do_dsllv (void); void do_dsrav (void); void do_dsrlv (void); void do_drotrv (void); +void do_dclo (void); +void do_dclz (void); #endif #endif diff --git a/target-mips/op.c b/target-mips/op.c index 1ecec9a57..9e8324d49 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -22,6 +22,7 @@ #include "config.h" #include "exec.h" +#include "host-utils.h" #ifndef CALL_FROM_TB0 #define CALL_FROM_TB0(func) func() @@ -537,35 +538,13 @@ void op_rotrv (void) void op_clo (void) { - int n; - - if (T0 == ~((target_ulong)0)) { - T0 = 32; - } else { - for (n = 0; n < 32; n++) { - if (!(((int32_t)T0) & (1 << 31))) - break; - T0 <<= 1; - } - T0 = n; - } + T0 = clo32(T0); RETURN(); } void op_clz (void) { - int n; - - if (T0 == 0) { - T0 = 32; - } else { - for (n = 0; n < 32; n++) { - if (T0 & (1 << 31)) - break; - T0 <<= 1; - } - T0 = n; - } + T0 = clz32(T0); RETURN(); } @@ -645,6 +624,18 @@ void op_drotrv (void) RETURN(); } +void op_dclo (void) +{ + CALL_FROM_TB0(do_dclo); + RETURN(); +} + +void op_dclz (void) +{ + CALL_FROM_TB0(do_dclz); + RETURN(); +} + #else /* TARGET_LONG_BITS > HOST_LONG_BITS */ void op_dsll (void) @@ -735,41 +726,19 @@ void op_drotrv (void) T0 = T1; RETURN(); } -#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ void op_dclo (void) { - int n; - - if (T0 == ~((target_ulong)0)) { - T0 = 64; - } else { - for (n = 0; n < 64; n++) { - if (!(T0 & (1ULL << 63))) - break; - T0 <<= 1; - } - T0 = n; - } + T0 = clo64(T0); RETURN(); } void op_dclz (void) { - int n; - - if (T0 == 0) { - T0 = 64; - } else { - for (n = 0; n < 64; n++) { - if (T0 & (1ULL << 63)) - break; - T0 <<= 1; - } - T0 = n; - } + T0 = clz64(T0); RETURN(); } +#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ #endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ /* 64 bits arithmetic */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index f3e01202e..ff26ab5af 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -20,6 +20,8 @@ #include #include "exec.h" +#include "host-utils.h" + #define GETPC() (__builtin_return_address(0)) /*****************************************************************************/ @@ -141,6 +143,17 @@ void do_drotrv (void) } else T0 = T1; } + +void do_dclo (void) +{ + T0 = clo64(T0); +} + +void do_dclz (void) +{ + T0 = clz64(T0); +} + #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ #endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ -- cgit v1.2.3 From 8378e71f136a021e795d41ceae64eedadcff291c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 27 Oct 2007 17:18:49 +0000 Subject: Fix endianness bug for PowerPC stfiwx instruction. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3456 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_mem.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index ca48f5de0..b1daf848d 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -411,17 +411,26 @@ static always_inline void glue(stfs, MEMSUFFIX) (target_ulong EA, double d) glue(stfl, MEMSUFFIX)(EA, float64_to_float32(d, &env->fp_status)); } +#if defined(WORDS_BIGENDIAN) +#define WORD0 0 +#define WORD1 1 +#else +#define WORD0 1 +#define WORD1 0 +#endif static always_inline void glue(stfiwx, MEMSUFFIX) (target_ulong EA, double d) { union { double d; - uint64_t u; + uint32_t u[2]; } u; /* Store the low order 32 bits without any conversion */ u.d = d; - glue(stl, MEMSUFFIX)(EA, u.u); + glue(stl, MEMSUFFIX)(EA, u.u[WORD0]); } +#undef WORD0 +#undef WORD1 PPC_STF_OP(fd, stfq); PPC_STF_OP(fs, stfs); -- cgit v1.2.3 From a32ff1ad95c4f09420c4b5e19dfd86ded0d2bc79 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 27 Oct 2007 17:29:35 +0000 Subject: PowerPC user-mode fix: MSR is now entirelly set-up in the cpu_reset routine. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3457 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/elfload.c | 1 - linux-user/main.c | 1 - 2 files changed, 2 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fbfa3b0de..ab5a74e49 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -329,7 +329,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * abi_ulong entry, toc; #endif - _regs->msr = 1 << MSR_PR; /* Set user mode */ _regs->gpr[1] = infop->start_stack; #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) entry = ldq_raw(infop->entry) + infop->load_addr; diff --git a/linux-user/main.c b/linux-user/main.c index 7590db80a..cac9561ba 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2168,7 +2168,6 @@ int main(int argc, char **argv) } cpu_ppc_register(env, def); cpu_ppc_reset(env); - env->msr = regs->msr & ~((1 << 6) | (1 << 12) | (1 << 13)); #if defined(TARGET_PPC64) #if defined(TARGET_ABI32) env->msr &= ~((target_ulong)1 << MSR_SF); -- cgit v1.2.3 From 7c58044c0ab79f11604f71aa04b4691baacef886 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 27 Oct 2007 17:54:30 +0000 Subject: Fix PowerPC FPSCR update and floating-point exception generation in most useful cases. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3458 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 7 +- linux-user/main.c | 8 +- target-ppc/cpu.h | 78 +++- target-ppc/helper.c | 13 +- target-ppc/op.c | 126 ++++++- target-ppc/op_helper.c | 919 ++++++++++++++++++++++++++++++++++++++--------- target-ppc/op_helper.h | 15 +- target-ppc/op_template.h | 33 -- target-ppc/translate.c | 272 +++++++++----- 9 files changed, 1122 insertions(+), 349 deletions(-) diff --git a/darwin-user/main.c b/darwin-user/main.c index d0de491e0..70328ec8e 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -224,11 +224,6 @@ void cpu_loop(CPUPPCState *env) case POWERPC_EXCP_FP: EXCP_DUMP(env, "Floating point program exception\n"); /* Set FX */ - env->fpscr[7] |= 0x8; - /* Finally, update FEX */ - if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & - ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) - env->fpscr[7] |= 0x4; info.si_signo = SIGFPE; info.si_errno = 0; switch (env->error_code & 0xF) { @@ -248,7 +243,7 @@ void cpu_loop(CPUPPCState *env) case POWERPC_EXCP_FP_VXSOFT: info.si_code = FPE_FLTINV; break; - case POWERPC_EXCP_FP_VXNAN: + case POWERPC_EXCP_FP_VXSNAN: case POWERPC_EXCP_FP_VXISI: case POWERPC_EXCP_FP_VXIDI: case POWERPC_EXCP_FP_VXIMZ: diff --git a/linux-user/main.c b/linux-user/main.c index cac9561ba..88a2e4886 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -829,12 +829,6 @@ void cpu_loop(CPUPPCState *env) switch (env->error_code & ~0xF) { case POWERPC_EXCP_FP: EXCP_DUMP(env, "Floating point program exception\n"); - /* Set FX */ - env->fpscr[7] |= 0x8; - /* Finally, update FEX */ - if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & - ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) - env->fpscr[7] |= 0x4; info.si_signo = TARGET_SIGFPE; info.si_errno = 0; switch (env->error_code & 0xF) { @@ -854,7 +848,7 @@ void cpu_loop(CPUPPCState *env) case POWERPC_EXCP_FP_VXSOFT: info.si_code = TARGET_FPE_FLTINV; break; - case POWERPC_EXCP_FP_VXNAN: + case POWERPC_EXCP_FP_VXSNAN: case POWERPC_EXCP_FP_VXISI: case POWERPC_EXCP_FP_VXIDI: case POWERPC_EXCP_FP_VXIMZ: diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index fc1d9bbca..196f98cae 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -239,7 +239,7 @@ enum { POWERPC_EXCP_FP_UX = 0x02, /* FP underflow */ POWERPC_EXCP_FP_ZX = 0x03, /* FP divide by zero */ POWERPC_EXCP_FP_XX = 0x04, /* FP inexact */ - POWERPC_EXCP_FP_VXNAN = 0x05, /* FP invalid SNaN op */ + POWERPC_EXCP_FP_VXSNAN = 0x05, /* FP invalid SNaN op */ POWERPC_EXCP_FP_VXISI = 0x06, /* FP invalid infinite subtraction */ POWERPC_EXCP_FP_VXIDI = 0x07, /* FP invalid infinite divide */ POWERPC_EXCP_FP_VXZDZ = 0x08, /* FP invalid zero divide */ @@ -433,14 +433,84 @@ enum { POWERPC_FLAG_PMM = 0x00000400, }; +/*****************************************************************************/ +/* Floating point status and control register */ +#define FPSCR_FX 31 /* Floating-point exception summary */ +#define FPSCR_FEX 30 /* Floating-point enabled exception summary */ +#define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */ +#define FPSCR_OX 28 /* Floating-point overflow exception */ +#define FPSCR_UX 27 /* Floating-point underflow exception */ +#define FPSCR_ZX 26 /* Floating-point zero divide exception */ +#define FPSCR_XX 25 /* Floating-point inexact exception */ +#define FPSCR_VXSNAN 24 /* Floating-point invalid operation exception (sNan) */ +#define FPSCR_VXISI 23 /* Floating-point invalid operation exception (inf) */ +#define FPSCR_VXIDI 22 /* Floating-point invalid operation exception (inf) */ +#define FPSCR_VXZDZ 21 /* Floating-point invalid operation exception (zero) */ +#define FPSCR_VXIMZ 20 /* Floating-point invalid operation exception (inf) */ +#define FPSCR_VXVC 19 /* Floating-point invalid operation exception (comp) */ +#define FPSCR_FR 18 /* Floating-point fraction rounded */ +#define FPSCR_FI 17 /* Floating-point fraction inexact */ +#define FPSCR_C 16 /* Floating-point result class descriptor */ +#define FPSCR_FL 15 /* Floating-point less than or negative */ +#define FPSCR_FG 14 /* Floating-point greater than or negative */ +#define FPSCR_FE 13 /* Floating-point equal or zero */ +#define FPSCR_FU 12 /* Floating-point unordered or NaN */ +#define FPSCR_FPCC 12 /* Floating-point condition code */ +#define FPSCR_FPRF 12 /* Floating-point result flags */ +#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */ +#define FPSCR_VXSQRT 9 /* Floating-point invalid operation exception (sqrt) */ +#define FPSCR_VXCVI 8 /* Floating-point invalid operation exception (int) */ +#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */ +#define FPSCR_OE 6 /* Floating-point overflow exception enable */ +#define FPSCR_UE 5 /* Floating-point undeflow exception enable */ +#define FPSCR_ZE 4 /* Floating-point zero divide exception enable */ +#define FPSCR_XE 3 /* Floating-point inexact exception enable */ +#define FPSCR_NI 2 /* Floating-point non-IEEE mode */ +#define FPSCR_RN1 1 +#define FPSCR_RN 0 /* Floating-point rounding control */ +#define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1) +#define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1) +#define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1) +#define fpscr_ux (((env->fpscr) >> FPSCR_UX) & 0x1) +#define fpscr_zx (((env->fpscr) >> FPSCR_ZX) & 0x1) +#define fpscr_xx (((env->fpscr) >> FPSCR_XX) & 0x1) +#define fpscr_vxsnan (((env->fpscr) >> FPSCR_VXSNAN) & 0x1) +#define fpscr_vxisi (((env->fpscr) >> FPSCR_VXISI) & 0x1) +#define fpscr_vxidi (((env->fpscr) >> FPSCR_VXIDI) & 0x1) +#define fpscr_vxzdz (((env->fpscr) >> FPSCR_VXZDZ) & 0x1) +#define fpscr_vximz (((env->fpscr) >> FPSCR_VXIMZ) & 0x1) +#define fpscr_vxvc (((env->fpscr) >> FPSCR_VXVC) & 0x1) +#define fpscr_fpcc (((env->fpscr) >> FPSCR_FPCC) & 0xF) +#define fpscr_vxsoft (((env->fpscr) >> FPSCR_VXSOFT) & 0x1) +#define fpscr_vxsqrt (((env->fpscr) >> FPSCR_VXSQRT) & 0x1) +#define fpscr_vxcvi (((env->fpscr) >> FPSCR_VXCVI) & 0x1) +#define fpscr_ve (((env->fpscr) >> FPSCR_VE) & 0x1) +#define fpscr_oe (((env->fpscr) >> FPSCR_OE) & 0x1) +#define fpscr_ue (((env->fpscr) >> FPSCR_UE) & 0x1) +#define fpscr_ze (((env->fpscr) >> FPSCR_ZE) & 0x1) +#define fpscr_xe (((env->fpscr) >> FPSCR_XE) & 0x1) +#define fpscr_ni (((env->fpscr) >> FPSCR_NI) & 0x1) +#define fpscr_rn (((env->fpscr) >> FPSCR_RN) & 0x3) +/* Invalid operation exception summary */ +#define fpscr_ix ((env->fpscr) & ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \ + (1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \ + (1 << FPSCR_VXIMZ) | (1 << FPSCR_VXVC) | \ + (1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \ + (1 << FPSCR_VXCVI))) +/* exception summary */ +#define fpscr_ex (((env->fpscr) >> FPSCR_XX) & 0x1F) +/* enabled exception summary */ +#define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \ + 0x1F) + +/*****************************************************************************/ +/* The whole PowerPC CPU context */ #if defined(TARGET_PPC64H) #define NB_MMU_MODES 3 #else #define NB_MMU_MODES 2 #endif -/*****************************************************************************/ -/* The whole PowerPC CPU context */ struct CPUPPCState { /* First are the most commonly used resources * during translated code execution @@ -482,7 +552,7 @@ struct CPUPPCState { /* floating point registers */ float64 fpr[32]; /* floating point status and control register */ - uint8_t fpscr[8]; + uint32_t fpscr; CPU_COMMON diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 9bdd8835e..869d5b767 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2130,6 +2130,8 @@ static always_inline void powerpc_excp (CPUState *env, fprintf(logfile, "Ignore floating point exception\n"); } #endif + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; return; } new_msr &= ~((target_ulong)1 << MSR_RI); @@ -2138,12 +2140,6 @@ static always_inline void powerpc_excp (CPUState *env, new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00100000; - /* Set FX */ - env->fpscr[7] |= 0x8; - /* Finally, update FEX */ - if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & - ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) - env->fpscr[7] |= 0x4; if (msr_fe0 != msr_fe1) { msr |= 0x00010000; goto store_current; @@ -2199,8 +2195,11 @@ static always_inline void powerpc_excp (CPUState *env, /* XXX: To be removed */ if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && env->osi_call) { - if (env->osi_call(env) != 0) + if (env->osi_call(env) != 0) { + env->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; return; + } } if (loglevel & CPU_LOG_INT) { dump_syscall(env); diff --git a/target-ppc/op.c b/target-ppc/op.c index 0495879ce..0146d33c3 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -135,13 +135,6 @@ void OPPROTO op_set_Rc0 (void) RETURN(); } -/* Set Rc1 (for floating point arithmetic) */ -void OPPROTO op_set_Rc1 (void) -{ - env->crf[1] = env->fpscr[7]; - RETURN(); -} - /* Constants load */ void OPPROTO op_reset_T0 (void) { @@ -552,21 +545,108 @@ void OPPROTO op_store_dbatl (void) #endif /* !defined(CONFIG_USER_ONLY) */ /* FPSCR */ -void OPPROTO op_load_fpscr (void) +#ifdef CONFIG_SOFTFLOAT +void OPPROTO op_reset_fpstatus (void) { - do_load_fpscr(); + env->fp_status.float_exception_flags = 0; RETURN(); } +#endif -void OPPROTO op_store_fpscr (void) +void OPPROTO op_compute_fprf (void) { - do_store_fpscr(PARAM1); + do_compute_fprf(PARAM1); RETURN(); } -void OPPROTO op_reset_scrfx (void) +#ifdef CONFIG_SOFTFLOAT +void OPPROTO op_float_check_status (void) { - env->fpscr[7] &= ~0x8; + do_float_check_status(); + RETURN(); +} +#else +void OPPROTO op_float_check_status (void) +{ + if (env->exception_index == POWERPC_EXCP_PROGRAM && + (env->error_code & POWERPC_EXCP_FP)) { + /* Differred floating-point exception after target FPR update */ + if (msr_fe0 != 0 || msr_fe1 != 0) + do_raise_exception_err(env->exception_index, env->error_code); + } + RETURN(); +} +#endif + +#if defined(WORDS_BIGENDIAN) +#define WORD0 0 +#define WORD1 1 +#else +#define WORD0 1 +#define WORD1 0 +#endif +void OPPROTO op_load_fpscr_FT0 (void) +{ + /* The 32 MSB of the target fpr are undefined. + * They'll be zero... + */ + union { + float64 d; + struct { + uint32_t u[2]; + } s; + } u; + + u.s.u[WORD0] = 0; + u.s.u[WORD1] = env->fpscr; + FT0 = u.d; + RETURN(); +} + +void OPPROTO op_set_FT0 (void) +{ + union { + float64 d; + struct { + uint32_t u[2]; + } s; + } u; + + u.s.u[WORD0] = 0; + u.s.u[WORD1] = PARAM1; + FT0 = u.d; + RETURN(); +} +#undef WORD0 +#undef WORD1 + +void OPPROTO op_load_fpscr_T0 (void) +{ + T0 = (env->fpscr >> PARAM1) & 0xF; + RETURN(); +} + +void OPPROTO op_load_fpcc (void) +{ + T0 = fpscr_fpcc; + RETURN(); +} + +void OPPROTO op_fpscr_resetbit (void) +{ + env->fpscr &= PARAM1; + RETURN(); +} + +void OPPROTO op_fpscr_setbit (void) +{ + do_fpscr_setbit(PARAM1); + RETURN(); +} + +void OPPROTO op_store_fpscr (void) +{ + do_store_fpscr(PARAM1); RETURN(); } @@ -1702,28 +1782,44 @@ void OPPROTO op_srli_T1_64 (void) /* fadd - fadd. */ void OPPROTO op_fadd (void) { +#if USE_PRECISE_EMULATION + do_fadd(); +#else FT0 = float64_add(FT0, FT1, &env->fp_status); +#endif RETURN(); } /* fsub - fsub. */ void OPPROTO op_fsub (void) { +#if USE_PRECISE_EMULATION + do_fsub(); +#else FT0 = float64_sub(FT0, FT1, &env->fp_status); +#endif RETURN(); } /* fmul - fmul. */ void OPPROTO op_fmul (void) { +#if USE_PRECISE_EMULATION + do_fmul(); +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); +#endif RETURN(); } /* fdiv - fdiv. */ void OPPROTO op_fdiv (void) { +#if USE_PRECISE_EMULATION + do_fdiv(); +#else FT0 = float64_div(FT0, FT1, &env->fp_status); +#endif RETURN(); } @@ -1805,7 +1901,11 @@ void OPPROTO op_fnmsub (void) /* frsp - frsp. */ void OPPROTO op_frsp (void) { +#if USE_PRECISE_EMULATION + do_frsp(); +#else FT0 = float64_to_float32(FT0, &env->fp_status); +#endif RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 06a5a561c..818277356 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -51,14 +51,6 @@ void do_raise_exception_err (uint32_t exception, int error_code) #if 0 printf("Raise exception %3x code : %d\n", exception, error_code); #endif - switch (exception) { - case POWERPC_EXCP_PROGRAM: - if (error_code == POWERPC_EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) - return; - break; - default: - break; - } env->exception_index = exception; env->error_code = error_code; cpu_loop_exit(); @@ -107,77 +99,6 @@ void do_store_pri (int prio) } #endif -void do_load_fpscr (void) -{ - /* The 32 MSB of the target fpr are undefined. - * They'll be zero... - */ - union { - float64 d; - struct { - uint32_t u[2]; - } s; - } u; - int i; - -#if defined(WORDS_BIGENDIAN) -#define WORD0 0 -#define WORD1 1 -#else -#define WORD0 1 -#define WORD1 0 -#endif - u.s.u[WORD0] = 0; - u.s.u[WORD1] = 0; - for (i = 0; i < 8; i++) - u.s.u[WORD1] |= env->fpscr[i] << (4 * i); - FT0 = u.d; -} - -void do_store_fpscr (uint32_t mask) -{ - /* - * We use only the 32 LSB of the incoming fpr - */ - union { - double d; - struct { - uint32_t u[2]; - } s; - } u; - int i, rnd_type; - - u.d = FT0; - if (mask & 0x80) - env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9); - for (i = 1; i < 7; i++) { - if (mask & (1 << (7 - i))) - env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF; - } - /* TODO: update FEX & VX */ - /* Set rounding mode */ - switch (env->fpscr[0] & 0x3) { - case 0: - /* Best approximation (round to nearest) */ - rnd_type = float_round_nearest_even; - break; - case 1: - /* Smaller magnitude (round toward zero) */ - rnd_type = float_round_to_zero; - break; - case 2: - /* Round toward +infinite */ - rnd_type = float_round_up; - break; - default: - case 3: - /* Round toward -infinite */ - rnd_type = float_round_down; - break; - } - set_float_rounding_mode(rnd_type, &env->fp_status); -} - target_ulong ppc_load_dump_spr (int sprn) { if (loglevel != 0) { @@ -553,6 +474,538 @@ void do_popcntb_64 (void) /*****************************************************************************/ /* Floating point operations helpers */ +static inline int fpisneg (float64 f) +{ + union { + float64 f; + uint64_t u; + } u; + + u.f = f; + + return u.u >> 63 != 0; +} + +static inline int isden (float f) +{ + union { + float64 f; + uint64_t u; + } u; + + u.f = f; + + return ((u.u >> 52) & 0x7FF) == 0; +} + +static inline int iszero (float64 f) +{ + union { + float64 f; + uint64_t u; + } u; + + u.f = f; + + return (u.u & ~0x8000000000000000ULL) == 0; +} + +static inline int isinfinity (float64 f) +{ + union { + float64 f; + uint64_t u; + } u; + + u.f = f; + + return ((u.u >> 51) & 0x3FF) == 0x3FF && + (u.u & 0x000FFFFFFFFFFFFFULL) == 0; +} + +void do_compute_fprf (int set_fprf) +{ + int isneg; + + isneg = fpisneg(FT0); + if (unlikely(float64_is_nan(FT0))) { + if (float64_is_signaling_nan(FT0)) { + /* Signaling NaN: flags are undefined */ + T0 = 0x00; + } else { + /* Quiet NaN */ + T0 = 0x11; + } + } else if (unlikely(isinfinity(FT0))) { + /* +/- infinity */ + if (isneg) + T0 = 0x09; + else + T0 = 0x05; + } else { + if (iszero(FT0)) { + /* +/- zero */ + if (isneg) + T0 = 0x12; + else + T0 = 0x02; + } else { + if (isden(FT0)) { + /* Denormalized numbers */ + T0 = 0x10; + } else { + /* Normalized numbers */ + T0 = 0x00; + } + if (isneg) { + T0 |= 0x08; + } else { + T0 |= 0x04; + } + } + } + if (set_fprf) { + /* We update FPSCR_FPRF */ + env->fpscr &= ~(0x1F << FPSCR_FPRF); + env->fpscr |= T0 << FPSCR_FPRF; + } + /* We just need fpcc to update Rc1 */ + T0 &= 0xF; +} + +/* Floating-point invalid operations exception */ +static always_inline void fload_invalid_op_excp (int op) +{ + int ve; + + ve = fpscr_ve; + if (op & POWERPC_EXCP_FP_VXSNAN) { + /* Operation on signaling NaN */ + env->fpscr |= 1 << FPSCR_VXSNAN; + } + if (op & POWERPC_EXCP_FP_VXSOFT) { + /* Software-defined condition */ + env->fpscr |= 1 << FPSCR_VXSOFT; + } + switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) { + case POWERPC_EXCP_FP_VXISI: + /* Magnitude subtraction of infinities */ + env->fpscr |= 1 << FPSCR_VXISI; + goto update_arith; + case POWERPC_EXCP_FP_VXIDI: + /* Division of infinity by infinity */ + env->fpscr |= 1 << FPSCR_VXIDI; + goto update_arith; + case POWERPC_EXCP_FP_VXZDZ: + /* Division of zero by zero */ + env->fpscr |= 1 << FPSCR_VXZDZ; + goto update_arith; + case POWERPC_EXCP_FP_VXIMZ: + /* Multiplication of zero by infinity */ + env->fpscr |= 1 << FPSCR_VXIMZ; + goto update_arith; + case POWERPC_EXCP_FP_VXVC: + /* Ordered comparison of NaN */ + env->fpscr |= 1 << FPSCR_VXVC; + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; + /* We must update the target FPR before raising the exception */ + if (ve != 0) { + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* Exception is differed */ + ve = 0; + } + break; + case POWERPC_EXCP_FP_VXSQRT: + /* Square root of a negative number */ + env->fpscr |= 1 << FPSCR_VXSQRT; + update_arith: + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + if (ve == 0) { + /* Set the result to quiet NaN */ + FT0 = (uint64_t)-1; + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; + } + break; + case POWERPC_EXCP_FP_VXCVI: + /* Invalid conversion */ + env->fpscr |= 1 << FPSCR_VXCVI; + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + if (ve == 0) { + /* Set the result to quiet NaN */ + FT0 = (uint64_t)-1; + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; + } + break; + } + /* Update the floating-point invalid operation summary */ + env->fpscr |= 1 << FPSCR_VX; + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (ve != 0) { + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + if (msr_fe0 != 0 || msr_fe1 != 0) + do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op); + } +} + +static always_inline void float_zero_divide_excp (void) +{ + union { + float64 f; + uint64_t u; + } u0, u1; + + + env->fpscr |= 1 << FPSCR_ZX; + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ze != 0) { + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + if (msr_fe0 != 0 || msr_fe1 != 0) { + do_raise_exception_err(POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX); + } + } else { + /* Set the result to infinity */ + u0.f = FT0; + u1.f = FT1; + u0.u = ((u0.u ^ u1.u) & 0x8000000000000000ULL); + u0.u |= 0x3FFULL << 51; + FT0 = u0.f; + } +} + +static always_inline void float_overflow_excp (void) +{ + env->fpscr |= 1 << FPSCR_OX; + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_oe != 0) { + /* XXX: should adjust the result */ + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* We must update the target FPR before raising the exception */ + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; + } else { + env->fpscr |= 1 << FPSCR_XX; + env->fpscr |= 1 << FPSCR_FI; + } +} + +static always_inline void float_underflow_excp (void) +{ + env->fpscr |= 1 << FPSCR_UX; + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ue != 0) { + /* XXX: should adjust the result */ + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* We must update the target FPR before raising the exception */ + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; + } +} + +static always_inline void float_inexact_excp (void) +{ + env->fpscr |= 1 << FPSCR_XX; + /* Update the floating-point exception summary */ + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_xe != 0) { + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* We must update the target FPR before raising the exception */ + env->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; + } +} + +static always_inline void fpscr_set_rounding_mode (void) +{ + int rnd_type; + + /* Set rounding mode */ + switch (fpscr_rn) { + case 0: + /* Best approximation (round to nearest) */ + rnd_type = float_round_nearest_even; + break; + case 1: + /* Smaller magnitude (round toward zero) */ + rnd_type = float_round_to_zero; + break; + case 2: + /* Round toward +infinite */ + rnd_type = float_round_up; + break; + default: + case 3: + /* Round toward -infinite */ + rnd_type = float_round_down; + break; + } + set_float_rounding_mode(rnd_type, &env->fp_status); +} + +void do_fpscr_setbit (int bit) +{ + int prev; + + prev = (env->fpscr >> bit) & 1; + env->fpscr |= 1 << bit; + if (prev == 0) { + switch (bit) { + case FPSCR_VX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ve) + goto raise_ve; + case FPSCR_OX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_oe) + goto raise_oe; + break; + case FPSCR_UX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ue) + goto raise_ue; + break; + case FPSCR_ZX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ze) + goto raise_ze; + break; + case FPSCR_XX: + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_xe) + goto raise_xe; + break; + case FPSCR_VXSNAN: + case FPSCR_VXISI: + case FPSCR_VXIDI: + case FPSCR_VXZDZ: + case FPSCR_VXIMZ: + case FPSCR_VXVC: + case FPSCR_VXSOFT: + case FPSCR_VXSQRT: + case FPSCR_VXCVI: + env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= 1 << FPSCR_FX; + if (fpscr_ve != 0) + goto raise_ve; + break; + case FPSCR_VE: + if (fpscr_vx != 0) { + raise_ve: + env->error_code = POWERPC_EXCP_FP; + if (fpscr_vxsnan) + env->error_code |= POWERPC_EXCP_FP_VXSNAN; + if (fpscr_vxisi) + env->error_code |= POWERPC_EXCP_FP_VXISI; + if (fpscr_vxidi) + env->error_code |= POWERPC_EXCP_FP_VXIDI; + if (fpscr_vxzdz) + env->error_code |= POWERPC_EXCP_FP_VXZDZ; + if (fpscr_vximz) + env->error_code |= POWERPC_EXCP_FP_VXIMZ; + if (fpscr_vxvc) + env->error_code |= POWERPC_EXCP_FP_VXVC; + if (fpscr_vxsoft) + env->error_code |= POWERPC_EXCP_FP_VXSOFT; + if (fpscr_vxsqrt) + env->error_code |= POWERPC_EXCP_FP_VXSQRT; + if (fpscr_vxcvi) + env->error_code |= POWERPC_EXCP_FP_VXCVI; + goto raise_excp; + } + break; + case FPSCR_OE: + if (fpscr_ox != 0) { + raise_oe: + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; + goto raise_excp; + } + break; + case FPSCR_UE: + if (fpscr_ux != 0) { + raise_ue: + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; + goto raise_excp; + } + break; + case FPSCR_ZE: + if (fpscr_zx != 0) { + raise_ze: + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX; + goto raise_excp; + } + break; + case FPSCR_XE: + if (fpscr_xx != 0) { + raise_xe: + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; + goto raise_excp; + } + break; + case FPSCR_RN1: + case FPSCR_RN: + fpscr_set_rounding_mode(); + break; + default: + break; + raise_excp: + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + /* We have to update Rc1 before raising the exception */ + env->exception_index = POWERPC_EXCP_PROGRAM; + break; + } + } +} + +#if defined(WORDS_BIGENDIAN) +#define WORD0 0 +#define WORD1 1 +#else +#define WORD0 1 +#define WORD1 0 +#endif +void do_store_fpscr (uint32_t mask) +{ + /* + * We use only the 32 LSB of the incoming fpr + */ + union { + double d; + struct { + uint32_t u[2]; + } s; + } u; + uint32_t prev, new; + int i; + + u.d = FT0; + prev = env->fpscr; + new = u.s.u[WORD1]; + new &= ~0x90000000; + new |= prev & 0x90000000; + for (i = 0; i < 7; i++) { + if (mask & (1 << i)) { + env->fpscr &= ~(0xF << (4 * i)); + env->fpscr |= new & (0xF << (4 * i)); + } + } + /* Update VX and FEX */ + if (fpscr_ix != 0) + env->fpscr |= 1 << FPSCR_VX; + if ((fpscr_ex & fpscr_eex) != 0) { + env->fpscr |= 1 << FPSCR_FEX; + env->exception_index = POWERPC_EXCP_PROGRAM; + /* XXX: we should compute it properly */ + env->error_code = POWERPC_EXCP_FP; + } + fpscr_set_rounding_mode(); +} +#undef WORD0 +#undef WORD1 + +#ifdef CONFIG_SOFTFLOAT +void do_float_check_status (void) +{ + if (env->exception_index == POWERPC_EXCP_PROGRAM && + (env->error_code & POWERPC_EXCP_FP)) { + /* Differred floating-point exception after target FPR update */ + if (msr_fe0 != 0 || msr_fe1 != 0) + do_raise_exception_err(env->exception_index, env->error_code); + } else if (env->fp_status.float_exception_flags & float_flag_overflow) { + float_overflow_excp(); + } else if (env->fp_status.float_exception_flags & float_flag_underflow) { + float_underflow_excp(); + } else if (env->fp_status.float_exception_flags & float_flag_inexact) { + float_inexact_excp(); + } +} +#endif + +#if USE_PRECISE_EMULATION +void do_fadd (void) +{ + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1))) { + /* sNaN addition */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else if (likely(isfinite(FT0) || isfinite(FT1) || + fpisneg(FT0) == fpisneg(FT1))) { + FT0 = float64_add(FT0, FT1, &env->fp_status); + } else { + /* Magnitude subtraction of infinities */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + } +} + +void do_fsub (void) +{ + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1))) { + /* sNaN subtraction */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else if (likely(isfinite(FT0) || isfinite(FT1) || + fpisneg(FT0) != fpisneg(FT1))) { + FT0 = float64_sub(FT0, FT1, &env->fp_status); + } else { + /* Magnitude subtraction of infinities */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI); + } +} + +void do_fmul (void) +{ + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1))) { + /* sNaN multiplication */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else if (unlikely((ifinf(FT0) && iszero(FT1)) || + (inzero(FT0) && isinfinity(FT1)))) { + /* Multiplication of zero by infinity */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); + } else { + FT0 = float64_mul(FT0, FT1, &env->fp_status); + } +} + +void do_fdiv (void) +{ + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1))) { + /* sNaN division */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else if (unlikely(isinfinity(FT0) && isinfinity(FT1))) { + /* Division of infinity by infinity */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI); + } else if (unlikely(iszero(FT1))) { + if (iszero(FT0)) { + /* Division of zero by zero */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ); + } else { + /* Division by zero */ + float_zero_divide_excp(); + } + } else { + FT0 = float64_div(FT0, FT1, &env->fp_status); + } +} +#endif /* USE_PRECISE_EMULATION */ + void do_fctiw (void) { union { @@ -560,14 +1013,22 @@ void do_fctiw (void) uint64_t i; } p; - p.i = float64_to_int32(FT0, &env->fp_status); + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN conversion */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) { + /* qNan / infinity conversion */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + p.i = float64_to_int32(FT0, &env->fp_status); #if USE_PRECISE_EMULATION - /* XXX: higher bits are not supposed to be significant. - * to make tests easier, return the same as a real PowerPC 750 (aka G3) - */ - p.i |= 0xFFF80000ULL << 32; + /* XXX: higher bits are not supposed to be significant. + * to make tests easier, return the same as a real PowerPC 750 + */ + p.i |= 0xFFF80000ULL << 32; #endif - FT0 = p.d; + FT0 = p.d; + } } void do_fctiwz (void) @@ -577,14 +1038,22 @@ void do_fctiwz (void) uint64_t i; } p; - p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN conversion */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) { + /* qNan / infinity conversion */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); #if USE_PRECISE_EMULATION - /* XXX: higher bits are not supposed to be significant. - * to make tests easier, return the same as a real PowerPC 750 (aka G3) - */ - p.i |= 0xFFF80000ULL << 32; + /* XXX: higher bits are not supposed to be significant. + * to make tests easier, return the same as a real PowerPC 750 + */ + p.i |= 0xFFF80000ULL << 32; #endif - FT0 = p.d; + FT0 = p.d; + } } #if defined(TARGET_PPC64) @@ -606,8 +1075,16 @@ void do_fctid (void) uint64_t i; } p; - p.i = float64_to_int64(FT0, &env->fp_status); - FT0 = p.d; + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN conversion */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) { + /* qNan / infinity conversion */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + p.i = float64_to_int64(FT0, &env->fp_status); + FT0 = p.d; + } } void do_fctidz (void) @@ -617,20 +1094,34 @@ void do_fctidz (void) uint64_t i; } p; - p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status); - FT0 = p.d; + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN conversion */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) { + /* qNan / infinity conversion */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status); + FT0 = p.d; + } } #endif static always_inline void do_fri (int rounding_mode) { - int curmode; - - curmode = env->fp_status.float_rounding_mode; - set_float_rounding_mode(rounding_mode, &env->fp_status); - FT0 = float64_round_to_int(FT0, &env->fp_status); - set_float_rounding_mode(curmode, &env->fp_status); + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN round */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) { + /* qNan / infinity round */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); + } else { + set_float_rounding_mode(rounding_mode, &env->fp_status); + FT0 = float64_round_to_int(FT0, &env->fp_status); + /* Restore rounding mode from FPSCR */ + fpscr_set_rounding_mode(); + } } void do_frin (void) @@ -656,90 +1147,142 @@ void do_frim (void) #if USE_PRECISE_EMULATION void do_fmadd (void) { + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1) || + float64_is_signaling_nan(FT2))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else { #ifdef FLOAT128 - float128 ft0_128, ft1_128; - - ft0_128 = float64_to_float128(FT0, &env->fp_status); - ft1_128 = float64_to_float128(FT1, &env->fp_status); - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - ft1_128 = float64_to_float128(FT2, &env->fp_status); - ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); - FT0 = float128_to_float64(ft0_128, &env->fp_status); + /* This is the way the PowerPC specification defines it */ + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); #else - /* This is OK on x86 hosts */ - FT0 = (FT0 * FT1) + FT2; + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) + FT2; #endif + } } void do_fmsub (void) { + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1) || + float64_is_signaling_nan(FT2))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else { #ifdef FLOAT128 - float128 ft0_128, ft1_128; - - ft0_128 = float64_to_float128(FT0, &env->fp_status); - ft1_128 = float64_to_float128(FT1, &env->fp_status); - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - ft1_128 = float64_to_float128(FT2, &env->fp_status); - ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); - FT0 = float128_to_float64(ft0_128, &env->fp_status); + /* This is the way the PowerPC specification defines it */ + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); #else - /* This is OK on x86 hosts */ - FT0 = (FT0 * FT1) - FT2; + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) - FT2; #endif + } } #endif /* USE_PRECISE_EMULATION */ void do_fnmadd (void) { + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1) || + float64_is_signaling_nan(FT2))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else { #if USE_PRECISE_EMULATION #ifdef FLOAT128 - float128 ft0_128, ft1_128; - - ft0_128 = float64_to_float128(FT0, &env->fp_status); - ft1_128 = float64_to_float128(FT1, &env->fp_status); - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - ft1_128 = float64_to_float128(FT2, &env->fp_status); - ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); - FT0 = float128_to_float64(ft0_128, &env->fp_status); + /* This is the way the PowerPC specification defines it */ + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); #else - /* This is OK on x86 hosts */ - FT0 = (FT0 * FT1) + FT2; + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) + FT2; #endif #else - FT0 = float64_mul(FT0, FT1, &env->fp_status); - FT0 = float64_add(FT0, FT2, &env->fp_status); + FT0 = float64_mul(FT0, FT1, &env->fp_status); + FT0 = float64_add(FT0, FT2, &env->fp_status); #endif - if (likely(!isnan(FT0))) - FT0 = float64_chs(FT0); + if (likely(!isnan(FT0))) + FT0 = float64_chs(FT0); + } } void do_fnmsub (void) { + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1) || + float64_is_signaling_nan(FT2))) { + /* sNaN operation */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else { #if USE_PRECISE_EMULATION #ifdef FLOAT128 - float128 ft0_128, ft1_128; - - ft0_128 = float64_to_float128(FT0, &env->fp_status); - ft1_128 = float64_to_float128(FT1, &env->fp_status); - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); - ft1_128 = float64_to_float128(FT2, &env->fp_status); - ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); - FT0 = float128_to_float64(ft0_128, &env->fp_status); + /* This is the way the PowerPC specification defines it */ + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); #else - /* This is OK on x86 hosts */ - FT0 = (FT0 * FT1) - FT2; + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) - FT2; #endif #else - FT0 = float64_mul(FT0, FT1, &env->fp_status); - FT0 = float64_sub(FT0, FT2, &env->fp_status); + FT0 = float64_mul(FT0, FT1, &env->fp_status); + FT0 = float64_sub(FT0, FT2, &env->fp_status); #endif - if (likely(!isnan(FT0))) - FT0 = float64_chs(FT0); + if (likely(!isnan(FT0))) + FT0 = float64_chs(FT0); + } } +#if USE_PRECISE_EMULATION +void do_frsp (void) +{ + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN square root */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else { + FT0 = float64_to_float32(FT0, &env->fp_status); + } +} +#endif /* USE_PRECISE_EMULATION */ + void do_fsqrt (void) { - FT0 = float64_sqrt(FT0, &env->fp_status); + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN square root */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else if (unlikely(fpisneg(FT0) && !iszero(FT0))) { + /* Square root of a negative nonzero number */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); + } else { + FT0 = float64_sqrt(FT0, &env->fp_status); + } } void do_fre (void) @@ -749,7 +1292,13 @@ void do_fre (void) uint64_t i; } p; - if (likely(isnormal(FT0))) { + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN reciprocal */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else if (unlikely(iszero(FT0))) { + /* Zero reciprocal */ + float_zero_divide_excp(); + } else if (likely(isnormal(FT0))) { FT0 = float64_div(1.0, FT0, &env->fp_status); } else { p.d = FT0; @@ -759,7 +1308,7 @@ void do_fre (void) p.i = 0x7FF0000000000000ULL; } else if (isnan(FT0)) { p.i = 0x7FF8000000000000ULL; - } else if (FT0 < 0.0) { + } else if (fpisneg(FT0)) { p.i = 0x8000000000000000ULL; } else { p.i = 0x0000000000000000ULL; @@ -775,7 +1324,13 @@ void do_fres (void) uint64_t i; } p; - if (likely(isnormal(FT0))) { + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN reciprocal */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else if (unlikely(iszero(FT0))) { + /* Zero reciprocal */ + float_zero_divide_excp(); + } else if (likely(isnormal(FT0))) { #if USE_PRECISE_EMULATION FT0 = float64_div(1.0, FT0, &env->fp_status); FT0 = float64_to_float32(FT0, &env->fp_status); @@ -790,7 +1345,7 @@ void do_fres (void) p.i = 0x7FF0000000000000ULL; } else if (isnan(FT0)) { p.i = 0x7FF8000000000000ULL; - } else if (FT0 < 0.0) { + } else if (fpisneg(FT0)) { p.i = 0x8000000000000000ULL; } else { p.i = 0x0000000000000000ULL; @@ -806,7 +1361,13 @@ void do_frsqrte (void) uint64_t i; } p; - if (likely(isnormal(FT0) && FT0 > 0.0)) { + if (unlikely(float64_is_signaling_nan(FT0))) { + /* sNaN reciprocal square root */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else if (unlikely(fpisneg(FT0) && !iszero(FT0))) { + /* Reciprocal square root of a negative nonzero number */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT); + } else if (likely(isnormal(FT0))) { FT0 = float64_sqrt(FT0, &env->fp_status); FT0 = float32_div(1.0, FT0, &env->fp_status); } else { @@ -816,9 +1377,8 @@ void do_frsqrte (void) } else if (p.i == 0x0000000000000000ULL) { p.i = 0x7FF0000000000000ULL; } else if (isnan(FT0)) { - if (!(p.i & 0x0008000000000000ULL)) - p.i |= 0x000FFFFFFFFFFFFFULL; - } else if (FT0 < 0) { + p.i |= 0x000FFFFFFFFFFFFFULL; + } else if (fpisneg(FT0)) { p.i = 0x7FF8000000000000ULL; } else { p.i = 0x0000000000000000ULL; @@ -829,7 +1389,7 @@ void do_frsqrte (void) void do_fsel (void) { - if (FT0 >= 0) + if (!fpisneg(FT0) || iszero(FT0)) FT0 = FT1; else FT0 = FT2; @@ -837,7 +1397,11 @@ void do_fsel (void) void do_fcmpu (void) { - if (likely(!isnan(FT0) && !isnan(FT1))) { + if (unlikely(float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1))) { + /* sNaN comparison */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); + } else { if (float64_lt(FT0, FT1, &env->fp_status)) { T0 = 0x08UL; } else if (!float64_le(FT0, FT1, &env->fp_status)) { @@ -845,18 +1409,25 @@ void do_fcmpu (void) } else { T0 = 0x02UL; } - } else { - T0 = 0x01UL; - env->fpscr[4] |= 0x1; - env->fpscr[6] |= 0x1; } - env->fpscr[3] = T0; + env->fpscr &= ~(0x0F << FPSCR_FPRF); + env->fpscr |= T0 << FPSCR_FPRF; } void do_fcmpo (void) { - env->fpscr[4] &= ~0x1; - if (likely(!isnan(FT0) && !isnan(FT1))) { + if (unlikely(float64_is_nan(FT0) || + float64_is_nan(FT1))) { + if (float64_is_signaling_nan(FT0) || + float64_is_signaling_nan(FT1)) { + /* sNaN comparison */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | + POWERPC_EXCP_FP_VXVC); + } else { + /* qNaN comparison */ + fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC); + } + } else { if (float64_lt(FT0, FT1, &env->fp_status)) { T0 = 0x08UL; } else if (!float64_le(FT0, FT1, &env->fp_status)) { @@ -864,19 +1435,9 @@ void do_fcmpo (void) } else { T0 = 0x02UL; } - } else { - T0 = 0x01UL; - env->fpscr[4] |= 0x1; - if (!float64_is_signaling_nan(FT0) || !float64_is_signaling_nan(FT1)) { - /* Quiet NaN case */ - env->fpscr[6] |= 0x1; - if (!(env->fpscr[1] & 0x8)) - env->fpscr[4] |= 0x8; - } else { - env->fpscr[4] |= 0x8; - } } - env->fpscr[3] = T0; + env->fpscr &= ~(0x0F << FPSCR_FPRF); + env->fpscr |= T0 << FPSCR_FPRF; } #if !defined (CONFIG_USER_ONLY) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index d8b2f252c..6597b3ca5 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -60,7 +60,7 @@ void do_store_cr (uint32_t mask); #if defined(TARGET_PPC64) void do_store_pri (int prio); #endif -void do_load_fpscr (void); +void do_fpscr_setbit (int bit); void do_store_fpscr (uint32_t mask); target_ulong ppc_load_dump_spr (int sprn); void ppc_store_dump_spr (int sprn, target_ulong val); @@ -94,6 +94,16 @@ void do_popcntb_64 (void); #endif /* Floating-point arithmetic helpers */ +void do_compute_fprf (int set_class); +#ifdef CONFIG_SOFTFLOAT +void do_float_check_status (void); +#endif +#if USE_PRECISE_EMULATION +void do_fadd (void); +void do_fsub (void); +void do_fmul (void); +void do_fdiv (void); +#endif void do_fsqrt (void); void do_fre (void); void do_fres (void); @@ -105,6 +115,9 @@ void do_fmsub (void); #endif void do_fnmadd (void); void do_fnmsub (void); +#if USE_PRECISE_EMULATION +void do_frsp (void); +#endif void do_fctiw (void); void do_fctiwz (void); #if defined(TARGET_PPC64) diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 28dc59c94..bdd884432 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -165,39 +165,6 @@ void OPPROTO glue(op_store_T1_crf_crf, REG) (void) RETURN(); } -/* Floating point condition and status register moves */ -void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void) -{ - T0 = env->fpscr[REG]; - RETURN(); -} - -#if REG == 0 -void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void) -{ - env->fpscr[REG] = (env->fpscr[REG] & 0x9) | (T0 & ~0x9); - RETURN(); -} - -void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void) -{ - env->fpscr[REG] = (env->fpscr[REG] & 0x9); - RETURN(); -} -#else -void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void) -{ - env->fpscr[REG] = T0; - RETURN(); -} - -void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void) -{ - env->fpscr[REG] = 0x0; - RETURN(); -} -#endif - #endif /* REG <= 7 */ /* floating point registers moves */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4c5e8c6b9..3c05b2cbb 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -32,6 +32,7 @@ //#define PPC_DEBUG_DISAS //#define DEBUG_MEMORY_ACCESSES //#define DO_PPC_STATISTICS +//#define OPTIMIZE_FPRF_UPDATE /*****************************************************************************/ /* Code translation helpers */ @@ -50,6 +51,10 @@ enum { static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; +#if defined(OPTIMIZE_FPRF_UPDATE) +static uint16_t *gen_fprf_buf[OPC_BUF_SIZE]; +static uint16_t **gen_fprf_ptr; +#endif #include "gen-op.h" @@ -117,16 +122,6 @@ GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf); GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf); GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf); -/* Floating point condition and status register moves */ -GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr); -GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr); -GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr); -static always_inline void gen_op_store_T0_fpscri (int n, uint8_t param) -{ - gen_op_set_T0(param); - gen_op_store_T0_fpscr(n); -} - /* General purpose registers moves */ GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr); @@ -199,6 +194,44 @@ static always_inline void gen_set_Rc0 (DisasContext *ctx) gen_op_set_Rc0(); } +static always_inline void gen_reset_fpstatus (void) +{ +#ifdef CONFIG_SOFTFLOAT + gen_op_reset_fpstatus(); +#endif +} + +static always_inline void gen_compute_fprf (int set_fprf, int set_rc) +{ + if (set_fprf != 0) { + /* This case might be optimized later */ +#if defined(OPTIMIZE_FPRF_UPDATE) + *gen_fprf_ptr++ = gen_opc_ptr; +#endif + gen_op_compute_fprf(1); + if (unlikely(set_rc)) + gen_op_store_T0_crf(1); + gen_op_float_check_status(); + } else if (unlikely(set_rc)) { + /* We always need to compute fpcc */ + gen_op_compute_fprf(0); + gen_op_store_T0_crf(1); + if (set_fprf) + gen_op_float_check_status(); + } +} + +static always_inline void gen_optimize_fprf (void) +{ +#if defined(OPTIMIZE_FPRF_UPDATE) + uint16_t **ptr; + + for (ptr = gen_fprf_buf; ptr != (gen_fprf_ptr - 1); ptr++) + *ptr = INDEX_op_nop1; + gen_fprf_ptr = gen_fprf_buf; +#endif +} + static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip) { #if defined(TARGET_PPC64) @@ -497,6 +530,8 @@ enum { PPC_CACHE_DCBZ = 0x0000400000000000ULL, /* dcbz instruction with tunable cache line size */ PPC_CACHE_DCBZT = 0x0000800000000000ULL, + /* frsqrtes extension */ + PPC_FLOAT_FRSQRTES = 0x0001000000000000ULL, }; /*****************************************************************************/ @@ -1656,124 +1691,127 @@ __GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B); #endif /*** Floating-Point arithmetic ***/ -#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, type) \ +#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rC(ctx->opcode)); \ gen_op_load_fpr_FT2(rB(ctx->opcode)); \ + gen_reset_fpstatus(); \ gen_op_f##op(); \ if (isfloat) { \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_op_set_Rc1(); \ + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } -#define GEN_FLOAT_ACB(name, op2, type) \ -_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, type); \ -_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, type); +#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ +_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type); \ +_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type); -#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \ -GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ +#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rB(ctx->opcode)); \ + gen_reset_fpstatus(); \ gen_op_f##op(); \ if (isfloat) { \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_op_set_Rc1(); \ + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } -#define GEN_FLOAT_AB(name, op2, inval) \ -_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \ -_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1); +#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ +_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ +_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type); -#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \ -GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ +#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \ +GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rA(ctx->opcode)); \ gen_op_load_fpr_FT1(rC(ctx->opcode)); \ + gen_reset_fpstatus(); \ gen_op_f##op(); \ if (isfloat) { \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_op_set_Rc1(); \ + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } -#define GEN_FLOAT_AC(name, op2, inval) \ -_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \ -_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1); +#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ +_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ +_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type); -#define GEN_FLOAT_B(name, op2, op3, type) \ +#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rB(ctx->opcode)); \ + gen_reset_fpstatus(); \ gen_op_f##name(); \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_op_set_Rc1(); \ + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } -#define GEN_FLOAT_BS(name, op1, op2, type) \ +#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) \ { \ if (unlikely(!ctx->fpu_enabled)) { \ GEN_EXCP_NO_FP(ctx); \ return; \ } \ - gen_op_reset_scrfx(); \ gen_op_load_fpr_FT0(rB(ctx->opcode)); \ + gen_reset_fpstatus(); \ gen_op_f##name(); \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_op_set_Rc1(); \ + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \ } /* fadd - fadds */ -GEN_FLOAT_AB(add, 0x15, 0x000007C0); +GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT); /* fdiv - fdivs */ -GEN_FLOAT_AB(div, 0x12, 0x000007C0); +GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT); /* fmul - fmuls */ -GEN_FLOAT_AC(mul, 0x19, 0x0000F800); +GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT); /* fre */ -GEN_FLOAT_BS(re, 0x3F, 0x18, PPC_FLOAT_EXT); +GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT); /* fres */ -GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES); +GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES); /* frsqrte */ -GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, PPC_FLOAT_FRSQRTE); +GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE); + +/* frsqrtes */ +static always_inline void gen_op_frsqrtes (void) +{ + gen_op_frsqrte(); + gen_op_frsp(); +} +GEN_FLOAT_BS(rsqrtes, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTES); /* fsel */ -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL); +_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL); /* fsub - fsubs */ -GEN_FLOAT_AB(sub, 0x14, 0x000007C0); +GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); /* Optional: */ /* fsqrt */ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) @@ -1782,12 +1820,11 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) GEN_EXCP_NO_FP(ctx); return; } - gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rB(ctx->opcode)); + gen_reset_fpstatus(); gen_op_fsqrt(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_op_set_Rc1(); + gen_compute_fprf(1, Rc(ctx->opcode) != 0); } GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) @@ -1796,49 +1833,48 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT) GEN_EXCP_NO_FP(ctx); return; } - gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rB(ctx->opcode)); + gen_reset_fpstatus(); gen_op_fsqrt(); gen_op_frsp(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_op_set_Rc1(); + gen_compute_fprf(1, Rc(ctx->opcode) != 0); } /*** Floating-Point multiply-and-add ***/ /* fmadd - fmadds */ -GEN_FLOAT_ACB(madd, 0x1D, PPC_FLOAT); +GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT); /* fmsub - fmsubs */ -GEN_FLOAT_ACB(msub, 0x1C, PPC_FLOAT); +GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT); /* fnmadd - fnmadds */ -GEN_FLOAT_ACB(nmadd, 0x1F, PPC_FLOAT); +GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT); /* fnmsub - fnmsubs */ -GEN_FLOAT_ACB(nmsub, 0x1E, PPC_FLOAT); +GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT); /*** Floating-Point round & convert ***/ /* fctiw */ -GEN_FLOAT_B(ctiw, 0x0E, 0x00, PPC_FLOAT); +GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT); /* fctiwz */ -GEN_FLOAT_B(ctiwz, 0x0F, 0x00, PPC_FLOAT); +GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT); /* frsp */ -GEN_FLOAT_B(rsp, 0x0C, 0x00, PPC_FLOAT); +GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT); #if defined(TARGET_PPC64) /* fcfid */ -GEN_FLOAT_B(cfid, 0x0E, 0x1A, PPC_64B); +GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B); /* fctid */ -GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B); +GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B); /* fctidz */ -GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B); +GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B); #endif /* frin */ -GEN_FLOAT_B(rin, 0x08, 0x0C, PPC_FLOAT_EXT); +GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT); /* friz */ -GEN_FLOAT_B(riz, 0x08, 0x0D, PPC_FLOAT_EXT); +GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT); /* frip */ -GEN_FLOAT_B(rip, 0x08, 0x0E, PPC_FLOAT_EXT); +GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT); /* frim */ -GEN_FLOAT_B(rim, 0x08, 0x0F, PPC_FLOAT_EXT); +GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT); /*** Floating-Point compare ***/ /* fcmpo */ @@ -1848,11 +1884,12 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) GEN_EXCP_NO_FP(ctx); return; } - gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rA(ctx->opcode)); gen_op_load_fpr_FT1(rB(ctx->opcode)); + gen_reset_fpstatus(); gen_op_fcmpo(); gen_op_store_T0_crf(crfD(ctx->opcode)); + gen_op_float_check_status(); } /* fcmpu */ @@ -1862,47 +1899,54 @@ GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) GEN_EXCP_NO_FP(ctx); return; } - gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rA(ctx->opcode)); gen_op_load_fpr_FT1(rB(ctx->opcode)); + gen_reset_fpstatus(); gen_op_fcmpu(); gen_op_store_T0_crf(crfD(ctx->opcode)); + gen_op_float_check_status(); } /*** Floating-point move ***/ /* fabs */ -GEN_FLOAT_B(abs, 0x08, 0x08, PPC_FLOAT); +/* XXX: beware that fabs never checks for NaNs nor update FPSCR */ +GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT); /* fmr - fmr. */ +/* XXX: beware that fmr never checks for NaNs nor update FPSCR */ GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) { if (unlikely(!ctx->fpu_enabled)) { GEN_EXCP_NO_FP(ctx); return; } - gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_op_set_Rc1(); + gen_compute_fprf(0, Rc(ctx->opcode) != 0); } /* fnabs */ -GEN_FLOAT_B(nabs, 0x08, 0x04, PPC_FLOAT); +/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */ +GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT); /* fneg */ -GEN_FLOAT_B(neg, 0x08, 0x01, PPC_FLOAT); +/* XXX: beware that fneg never checks for NaNs nor update FPSCR */ +GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT); /*** Floating-Point status & ctrl register ***/ /* mcrfs */ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) { + int bfa; + if (unlikely(!ctx->fpu_enabled)) { GEN_EXCP_NO_FP(ctx); return; } - gen_op_load_fpscr_T0(crfS(ctx->opcode)); + gen_optimize_fprf(); + bfa = 4 * (7 - crfS(ctx->opcode)); + gen_op_load_fpscr_T0(bfa); gen_op_store_T0_crf(crfD(ctx->opcode)); - gen_op_clear_fpscr(crfS(ctx->opcode)); + gen_op_fpscr_resetbit(~(0xF << bfa)); } /* mffs */ @@ -1912,10 +1956,11 @@ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) GEN_EXCP_NO_FP(ctx); return; } - gen_op_load_fpscr(); + gen_optimize_fprf(); + gen_reset_fpstatus(); + gen_op_load_fpscr_FT0(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_op_set_Rc1(); + gen_compute_fprf(0, Rc(ctx->opcode) != 0); } /* mtfsb0 */ @@ -1927,12 +1972,15 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) GEN_EXCP_NO_FP(ctx); return; } - crb = crbD(ctx->opcode) >> 2; - gen_op_load_fpscr_T0(crb); - gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03))); - gen_op_store_T0_fpscr(crb); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_op_set_Rc1(); + crb = 32 - (crbD(ctx->opcode) >> 2); + gen_optimize_fprf(); + gen_reset_fpstatus(); + if (likely(crb != 30 && crb != 29)) + gen_op_fpscr_resetbit(~(1 << crb)); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_op_load_fpcc(); + gen_op_set_Rc0(); + } } /* mtfsb1 */ @@ -1944,12 +1992,18 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) GEN_EXCP_NO_FP(ctx); return; } - crb = crbD(ctx->opcode) >> 2; - gen_op_load_fpscr_T0(crb); - gen_op_ori(1 << (crbD(ctx->opcode) & 0x03)); - gen_op_store_T0_fpscr(crb); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_op_set_Rc1(); + crb = 32 - (crbD(ctx->opcode) >> 2); + gen_optimize_fprf(); + gen_reset_fpstatus(); + /* XXX: we pretend we can only do IEEE floating-point computations */ + if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) + gen_op_fpscr_setbit(crb); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_op_load_fpcc(); + gen_op_set_Rc0(); + } + /* We can raise a differed exception */ + gen_op_float_check_status(); } /* mtfsf */ @@ -1959,22 +2013,39 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) GEN_EXCP_NO_FP(ctx); return; } + gen_optimize_fprf(); gen_op_load_fpr_FT0(rB(ctx->opcode)); + gen_reset_fpstatus(); gen_op_store_fpscr(FM(ctx->opcode)); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_op_set_Rc1(); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_op_load_fpcc(); + gen_op_set_Rc0(); + } + /* We can raise a differed exception */ + gen_op_float_check_status(); } /* mtfsfi */ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) { + int bf, sh; + if (unlikely(!ctx->fpu_enabled)) { GEN_EXCP_NO_FP(ctx); return; } - gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode)); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_op_set_Rc1(); + bf = crbD(ctx->opcode) >> 2; + sh = 7 - bf; + gen_optimize_fprf(); + gen_op_set_FT0(FPIMM(ctx->opcode) << (4 * sh)); + gen_reset_fpstatus(); + gen_op_store_fpscr(1 << sh); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_op_load_fpcc(); + gen_op_set_Rc0(); + } + /* We can raise a differed exception */ + gen_op_float_check_status(); } /*** Addressing modes ***/ @@ -6717,6 +6788,9 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; +#if defined(OPTIMIZE_FPRF_UPDATE) + gen_fprf_ptr = gen_fprf_buf; +#endif nb_gen_labels = 0; ctx.nip = pc_start; ctx.tb = tb; -- cgit v1.2.3 From 4f8eb6cfa27eed4a44f4beb259dd3d9081146dba Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 27 Oct 2007 17:59:46 +0000 Subject: PowerPC float bugfix: 64 bits float mantissa is 52 bits long. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3459 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 818277356..363d84cdb 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -519,7 +519,7 @@ static inline int isinfinity (float64 f) u.f = f; - return ((u.u >> 51) & 0x3FF) == 0x3FF && + return ((u.u >> 52) & 0x3FF) == 0x3FF && (u.u & 0x000FFFFFFFFFFFFFULL) == 0; } @@ -679,7 +679,7 @@ static always_inline void float_zero_divide_excp (void) u0.f = FT0; u1.f = FT1; u0.u = ((u0.u ^ u1.u) & 0x8000000000000000ULL); - u0.u |= 0x3FFULL << 51; + u0.u |= 0x3FFULL << 52; FT0 = u0.f; } } -- cgit v1.2.3 From 5bda28432fc8d269821f8c05e062f7c847f20cac Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 27 Oct 2007 23:34:30 +0000 Subject: PowerPC floating-point helper typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3460 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 363d84cdb..346b29b7e 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -974,8 +974,8 @@ void do_fmul (void) float64_is_signaling_nan(FT1))) { /* sNaN multiplication */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); - } else if (unlikely((ifinf(FT0) && iszero(FT1)) || - (inzero(FT0) && isinfinity(FT1)))) { + } else if (unlikely((isinfinity(FT0) && iszero(FT1)) || + (iszero(FT0) && isinfinity(FT1)))) { /* Multiplication of zero by infinity */ fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { -- cgit v1.2.3 From a11b8151dfc71f95ac04e5f73c7d5c042911b9e4 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 28 Oct 2007 00:55:05 +0000 Subject: PowerPC coding style and inlining fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3461 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 72 +++++++++++++++++++++++++++----------------------- target-ppc/op_helper.c | 13 +++++---- target-ppc/translate.c | 3 +-- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 869d5b767..d3b8db7e6 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -232,22 +232,24 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, return ret; } -static int pte32_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1, - int h, int rw, int type) +static always_inline int pte32_check (mmu_ctx_t *ctx, + target_ulong pte0, target_ulong pte1, + int h, int rw, int type) { return _pte_check(ctx, 0, pte0, pte1, h, rw, type); } #if defined(TARGET_PPC64) -static int pte64_check (mmu_ctx_t *ctx, target_ulong pte0, target_ulong pte1, - int h, int rw, int type) +static always_inline int pte64_check (mmu_ctx_t *ctx, + target_ulong pte0, target_ulong pte1, + int h, int rw, int type) { return _pte_check(ctx, 1, pte0, pte1, h, rw, type); } #endif -static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p, - int ret, int rw) +static always_inline int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p, + int ret, int rw) { int store = 0; @@ -272,8 +274,8 @@ static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p, } /* Software driven TLB helpers */ -static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr, - int way, int is_code) +static always_inline int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr, + int way, int is_code) { int nr; @@ -288,7 +290,7 @@ static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr, return nr; } -static void ppc6xx_tlb_invalidate_all (CPUState *env) +static always_inline void ppc6xx_tlb_invalidate_all (CPUState *env) { ppc6xx_tlb_t *tlb; int nr, max; @@ -339,8 +341,9 @@ static always_inline void __ppc6xx_tlb_invalidate_virt (CPUState *env, #endif } -static void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - int is_code) +static always_inline void ppc6xx_tlb_invalidate_virt (CPUState *env, + target_ulong eaddr, + int is_code) { __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0); } @@ -368,8 +371,9 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, env->last_way = way; } -static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int access_type) +static always_inline int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, + int access_type) { ppc6xx_tlb_t *tlb; int nr, best, way; @@ -444,8 +448,8 @@ static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, } /* Perform BAT hit & translation */ -static int get_bat (CPUState *env, mmu_ctx_t *ctx, - target_ulong virtual, int rw, int type) +static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, + target_ulong virtual, int rw, int type) { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong base, BEPIl, BEPIu, bl; @@ -635,13 +639,13 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, return ret; } -static int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type) +static always_inline int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type) { return _find_pte(ctx, 0, h, rw, type); } #if defined(TARGET_PPC64) -static int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type) +static always_inline int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type) { return _find_pte(ctx, 1, h, rw, type); } @@ -659,18 +663,19 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, } #if defined(TARGET_PPC64) -static inline int slb_is_valid (uint64_t slb64) +static always_inline int slb_is_valid (uint64_t slb64) { return slb64 & 0x0000000008000000ULL ? 1 : 0; } -static inline void slb_invalidate (uint64_t *slb64) +static always_inline void slb_invalidate (uint64_t *slb64) { *slb64 &= ~0x0000000008000000ULL; } -static int slb_lookup (CPUPPCState *env, target_ulong eaddr, - target_ulong *vsid, target_ulong *page_mask, int *attr) +static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr, + target_ulong *vsid, + target_ulong *page_mask, int *attr) { target_phys_addr_t sr_base; target_ulong mask; @@ -847,8 +852,8 @@ static always_inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask); } -static int get_segment (CPUState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int type) +static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int type) { target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask; target_ulong sr, vsid, vsid_mask, pgidx, page_mask; @@ -1063,10 +1068,10 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx, } /* Generic TLB check function for embedded PowerPC implementations */ -static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, - target_phys_addr_t *raddrp, - target_ulong address, - uint32_t pid, int ext, int i) +static always_inline int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, + target_phys_addr_t *raddrp, + target_ulong address, + uint32_t pid, int ext, int i) { target_ulong mask; @@ -1122,7 +1127,7 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) } /* Helpers specific to PowerPC 40x implementations */ -static void ppc4xx_tlb_invalidate_all (CPUState *env) +static always_inline void ppc4xx_tlb_invalidate_all (CPUState *env) { ppcemb_tlb_t *tlb; int i; @@ -1134,8 +1139,9 @@ static void ppc4xx_tlb_invalidate_all (CPUState *env) tlb_flush(env, 1); } -static void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, - uint32_t pid) +static always_inline void ppc4xx_tlb_invalidate_virt (CPUState *env, + target_ulong eaddr, + uint32_t pid) { #if !defined(FLUSH_ALL_TLBS) ppcemb_tlb_t *tlb; @@ -1286,8 +1292,8 @@ int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, return ret; } -static int check_physical (CPUState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw) +static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw) { int in_plb, ret; @@ -1986,7 +1992,7 @@ void ppc_hw_interrupt (CPUState *env) env->error_code = 0; } #else /* defined (CONFIG_USER_ONLY) */ -static void dump_syscall (CPUState *env) +static always_inline void dump_syscall (CPUState *env) { fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n", diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 346b29b7e..61075c086 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -474,7 +474,7 @@ void do_popcntb_64 (void) /*****************************************************************************/ /* Floating point operations helpers */ -static inline int fpisneg (float64 f) +static always_inline int fpisneg (float64 f) { union { float64 f; @@ -486,7 +486,7 @@ static inline int fpisneg (float64 f) return u.u >> 63 != 0; } -static inline int isden (float f) +static always_inline int isden (float f) { union { float64 f; @@ -498,7 +498,7 @@ static inline int isden (float f) return ((u.u >> 52) & 0x7FF) == 0; } -static inline int iszero (float64 f) +static always_inline int iszero (float64 f) { union { float64 f; @@ -510,7 +510,7 @@ static inline int iszero (float64 f) return (u.u & ~0x8000000000000000ULL) == 0; } -static inline int isinfinity (float64 f) +static always_inline int isinfinity (float64 f) { union { float64 f; @@ -661,7 +661,6 @@ static always_inline void float_zero_divide_excp (void) float64 f; uint64_t u; } u0, u1; - env->fpscr |= 1 << FPSCR_ZX; env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); @@ -2825,12 +2824,12 @@ void do_load_74xx_tlb (int is_code) way, is_code, CMP, RPN); } -static target_ulong booke_tlb_to_page_size (int size) +static always_inline target_ulong booke_tlb_to_page_size (int size) { return 1024 << (2 * size); } -static int booke_page_size_to_tlb (target_ulong page_size) +static always_inline int booke_page_size_to_tlb (target_ulong page_size) { int size; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3c05b2cbb..c3e5340f2 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -295,7 +295,6 @@ static void gen_##name (DisasContext *ctx); \ GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type); \ static void gen_##name (DisasContext *ctx) - typedef struct opcode_t { unsigned char opc1, opc2, opc3; #if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */ @@ -3503,7 +3502,7 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) #endif } -#if 0 +#if 1 #define SPR_NOACCESS ((void *)(-1)) #else static void spr_noaccess (void *opaque, int sprn) -- cgit v1.2.3 From f071b4d3ca5e83d332948a970a646437747b70ba Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 28 Oct 2007 00:56:24 +0000 Subject: Alpha coding style and inlining fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3462 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/cpu.h | 3 +- target-alpha/exec.h | 6 +- target-alpha/op_helper.c | 16 +++--- target-alpha/op_mem.h | 10 ++-- target-alpha/translate.c | 144 ++++++++++++++++++++++++++--------------------- 5 files changed, 98 insertions(+), 81 deletions(-) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 579ce613d..d65ccdea5 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -27,14 +27,13 @@ #include "cpu-defs.h" - #include #include "softfloat.h" #define TARGET_HAS_ICE 1 -#define ELF_MACHINE EM_ALPHA +#define ELF_MACHINE EM_ALPHA #define ICACHE_LINE_SIZE 32 #define DCACHE_LINE_SIZE 32 diff --git a/target-alpha/exec.h b/target-alpha/exec.h index 62cd07dcf..3b9754d83 100644 --- a/target-alpha/exec.h +++ b/target-alpha/exec.h @@ -64,11 +64,11 @@ register uint64_t T2 asm(AREG3); #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -static inline void env_to_regs(void) +static always_inline void env_to_regs(void) { } -static inline void regs_to_env(void) +static always_inline void regs_to_env(void) { } @@ -79,7 +79,7 @@ int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); void do_interrupt (CPUState *env); -static inline int cpu_halted(CPUState *env) { +static always_inline int cpu_halted(CPUState *env) { if (!env->halted) return 0; if (env->interrupt_request & CPU_INTERRUPT_HARD) { diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 3a34df49b..f9390c84d 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -294,7 +294,7 @@ void helper_cttz (void) T0 = n; } -static inline uint64_t byte_zap (uint64_t op, uint8_t mskb) +static always_inline uint64_t byte_zap (uint64_t op, uint8_t mskb) { uint64_t mask; @@ -609,7 +609,7 @@ void helper_ftoit (void) FT0 = p.d; } -static int vaxf_is_valid (float ff) +static always_inline int vaxf_is_valid (float ff) { union { float f; @@ -628,7 +628,7 @@ static int vaxf_is_valid (float ff) return 1; } -static float vaxf_to_ieee32 (float ff) +static always_inline float vaxf_to_ieee32 (float ff) { union { float f; @@ -648,7 +648,7 @@ static float vaxf_to_ieee32 (float ff) return p.f; } -static float ieee32_to_vaxf (float fi) +static always_inline float ieee32_to_vaxf (float fi) { union { float f; @@ -751,7 +751,7 @@ void helper_itoff (void) /* XXX: TODO */ } -static int vaxg_is_valid (double ff) +static always_inline int vaxg_is_valid (double ff) { union { double f; @@ -770,7 +770,7 @@ static int vaxg_is_valid (double ff) return 1; } -static double vaxg_to_ieee64 (double fg) +static always_inline double vaxg_to_ieee64 (double fg) { union { double f; @@ -790,7 +790,7 @@ static double vaxg_to_ieee64 (double fg) return p.f; } -static double ieee64_to_vaxg (double fi) +static always_inline double ieee64_to_vaxg (double fi) { union { double f; @@ -1044,7 +1044,7 @@ void helper_cvtlq (void) FT0 = q.d; } -static inline void __helper_cvtql (int s, int v) +static always_inline void __helper_cvtql (int s, int v) { union { double d; diff --git a/target-alpha/op_mem.h b/target-alpha/op_mem.h index 922d0d4de..4a0cfc799 100644 --- a/target-alpha/op_mem.h +++ b/target-alpha/op_mem.h @@ -26,21 +26,22 @@ void helper_print_mem_EA (target_ulong EA); #define print_mem_EA(EA) do { } while (0) #endif -static inline uint32_t glue(ldl_l, MEMSUFFIX) (target_ulong EA) +static always_inline uint32_t glue(ldl_l, MEMSUFFIX) (target_ulong EA) { env->lock = EA; return glue(ldl, MEMSUFFIX)(EA); } -static inline uint32_t glue(ldq_l, MEMSUFFIX) (target_ulong EA) +static always_inline uint32_t glue(ldq_l, MEMSUFFIX) (target_ulong EA) { env->lock = EA; return glue(ldq, MEMSUFFIX)(EA); } -static inline void glue(stl_c, MEMSUFFIX) (target_ulong EA, uint32_t data) +static always_inline void glue(stl_c, MEMSUFFIX) (target_ulong EA, + uint32_t data) { if (EA == env->lock) { glue(stl, MEMSUFFIX)(EA, data); @@ -51,7 +52,8 @@ static inline void glue(stl_c, MEMSUFFIX) (target_ulong EA, uint32_t data) env->lock = -1; } -static inline void glue(stq_c, MEMSUFFIX) (target_ulong EA, uint64_t data) +static always_inline void glue(stq_c, MEMSUFFIX) (target_ulong EA, + uint64_t data) { if (EA == env->lock) { glue(stq, MEMSUFFIX)(EA, data); diff --git a/target-alpha/translate.c b/target-alpha/translate.c index c036323cb..6f224b016 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -59,7 +59,7 @@ static uint32_t *gen_opparam_ptr; #include "gen-op.h" -static inline void gen_op_nop (void) +static always_inline void gen_op_nop (void) { #if defined(GENERATE_NOP) gen_op_no_op(); @@ -77,7 +77,7 @@ NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ }; \ -static inline void func(int n) \ +static always_inline void func (int n) \ { \ NAME ## _table[n](); \ } @@ -99,7 +99,7 @@ GEN32(gen_op_store_T1_ir, gen_op_store_T1_ir); GEN32(gen_op_store_T2_ir, gen_op_store_T2_ir); GEN32(gen_op_cmov_ir, gen_op_cmov_ir); -static inline void gen_load_ir (DisasContext *ctx, int irn, int Tn) +static always_inline void gen_load_ir (DisasContext *ctx, int irn, int Tn) { switch (Tn) { case 0: @@ -114,7 +114,7 @@ static inline void gen_load_ir (DisasContext *ctx, int irn, int Tn) } } -static inline void gen_store_ir (DisasContext *ctx, int irn, int Tn) +static always_inline void gen_store_ir (DisasContext *ctx, int irn, int Tn) { switch (Tn) { case 0: @@ -146,7 +146,7 @@ GEN32(gen_op_store_FT1_fir, gen_op_store_FT1_fir); GEN32(gen_op_store_FT2_fir, gen_op_store_FT2_fir); GEN32(gen_op_cmov_fir, gen_op_cmov_fir); -static inline void gen_load_fir (DisasContext *ctx, int firn, int Tn) +static always_inline void gen_load_fir (DisasContext *ctx, int firn, int Tn) { switch (Tn) { case 0: @@ -161,7 +161,7 @@ static inline void gen_load_fir (DisasContext *ctx, int firn, int Tn) } } -static inline void gen_store_fir (DisasContext *ctx, int firn, int Tn) +static always_inline void gen_store_fir (DisasContext *ctx, int firn, int Tn) { switch (Tn) { case 0: @@ -205,14 +205,14 @@ static GenOpFunc *gen_op_st##width[] = { \ #define GEN_LD(width) \ OP_LD_TABLE(width); \ -static void gen_ld##width (DisasContext *ctx) \ +static always_inline void gen_ld##width (DisasContext *ctx) \ { \ (*gen_op_ld##width[ctx->mem_idx])(); \ } #define GEN_ST(width) \ OP_ST_TABLE(width); \ -static void gen_st##width (DisasContext *ctx) \ +static always_inline void gen_st##width (DisasContext *ctx) \ { \ (*gen_op_st##width[ctx->mem_idx])(); \ } @@ -244,28 +244,28 @@ GEN_LD(t); GEN_ST(t); #if defined(__i386__) || defined(__x86_64__) -static inline void gen_op_set_s16_T0 (int16_t imm) +static always_inline void gen_op_set_s16_T0 (int16_t imm) { gen_op_set_s32_T0((int32_t)imm); } -static inline void gen_op_set_s16_T1 (int16_t imm) +static always_inline void gen_op_set_s16_T1 (int16_t imm) { gen_op_set_s32_T1((int32_t)imm); } -static inline void gen_op_set_u16_T0 (uint16_t imm) +static always_inline void gen_op_set_u16_T0 (uint16_t imm) { gen_op_set_s32_T0((uint32_t)imm); } -static inline void gen_op_set_u16_T1 (uint16_t imm) +static always_inline void gen_op_set_u16_T1 (uint16_t imm) { gen_op_set_s32_T1((uint32_t)imm); } #endif -static inline void gen_set_sT0 (DisasContext *ctx, int64_t imm) +static always_inline void gen_set_sT0 (DisasContext *ctx, int64_t imm) { int32_t imm32; int16_t imm16; @@ -291,7 +291,7 @@ static inline void gen_set_sT0 (DisasContext *ctx, int64_t imm) } } -static inline void gen_set_sT1 (DisasContext *ctx, int64_t imm) +static always_inline void gen_set_sT1 (DisasContext *ctx, int64_t imm) { int32_t imm32; int16_t imm16; @@ -317,7 +317,7 @@ static inline void gen_set_sT1 (DisasContext *ctx, int64_t imm) } } -static inline void gen_set_uT0 (DisasContext *ctx, uint64_t imm) +static always_inline void gen_set_uT0 (DisasContext *ctx, uint64_t imm) { if (!(imm >> 32)) { if ((!imm >> 16)) { @@ -337,7 +337,7 @@ static inline void gen_set_uT0 (DisasContext *ctx, uint64_t imm) } } -static inline void gen_set_uT1 (DisasContext *ctx, uint64_t imm) +static always_inline void gen_set_uT1 (DisasContext *ctx, uint64_t imm) { if (!(imm >> 32)) { if ((!imm >> 16)) { @@ -357,7 +357,7 @@ static inline void gen_set_uT1 (DisasContext *ctx, uint64_t imm) } } -static inline void gen_update_pc (DisasContext *ctx) +static always_inline void gen_update_pc (DisasContext *ctx) { if (!(ctx->pc >> 32)) { gen_op_update_pc32(ctx->pc); @@ -370,7 +370,7 @@ static inline void gen_update_pc (DisasContext *ctx) } } -static inline void _gen_op_bcond (DisasContext *ctx) +static always_inline void _gen_op_bcond (DisasContext *ctx) { #if 0 // Qemu does not know how to do this... gen_op_bcond(ctx->pc); @@ -379,20 +379,22 @@ static inline void _gen_op_bcond (DisasContext *ctx) #endif } -static inline void gen_excp (DisasContext *ctx, int exception, int error_code) +static always_inline void gen_excp (DisasContext *ctx, + int exception, int error_code) { gen_update_pc(ctx); gen_op_excp(exception, error_code); } -static inline void gen_invalid (DisasContext *ctx) +static always_inline void gen_invalid (DisasContext *ctx) { gen_excp(ctx, EXCP_OPCDEC, 0); } -static void gen_load_mem (DisasContext *ctx, - void (*gen_load_op)(DisasContext *ctx), - int ra, int rb, int32_t disp16, int clear) +static always_inline void gen_load_mem (DisasContext *ctx, + void (*gen_load_op)(DisasContext *ctx), + int ra, int rb, int32_t disp16, + int clear) { if (ra == 31 && disp16 == 0) { /* UNOP */ @@ -410,9 +412,10 @@ static void gen_load_mem (DisasContext *ctx, } } -static void gen_store_mem (DisasContext *ctx, - void (*gen_store_op)(DisasContext *ctx), - int ra, int rb, int32_t disp16, int clear) +static always_inline void gen_store_mem (DisasContext *ctx, + void (*gen_store_op)(DisasContext *ctx), + int ra, int rb, int32_t disp16, + int clear) { gen_load_ir(ctx, rb, 0); if (disp16 != 0) { @@ -425,9 +428,9 @@ static void gen_store_mem (DisasContext *ctx, (*gen_store_op)(ctx); } -static void gen_load_fmem (DisasContext *ctx, - void (*gen_load_fop)(DisasContext *ctx), - int ra, int rb, int32_t disp16) +static always_inline void gen_load_fmem (DisasContext *ctx, + void (*gen_load_fop)(DisasContext *ctx), + int ra, int rb, int32_t disp16) { gen_load_ir(ctx, rb, 0); if (disp16 != 0) { @@ -438,9 +441,9 @@ static void gen_load_fmem (DisasContext *ctx, gen_store_fir(ctx, ra, 1); } -static void gen_store_fmem (DisasContext *ctx, - void (*gen_store_fop)(DisasContext *ctx), - int ra, int rb, int32_t disp16) +static always_inline void gen_store_fmem (DisasContext *ctx, + void (*gen_store_fop)(DisasContext *ctx), + int ra, int rb, int32_t disp16) { gen_load_ir(ctx, rb, 0); if (disp16 != 0) { @@ -451,8 +454,9 @@ static void gen_store_fmem (DisasContext *ctx, (*gen_store_fop)(ctx); } -static void gen_bcond (DisasContext *ctx, void (*gen_test_op)(void), - int ra, int32_t disp16) +static always_inline void gen_bcond (DisasContext *ctx, + void (*gen_test_op)(void), + int ra, int32_t disp16) { if (disp16 != 0) { gen_set_uT0(ctx, ctx->pc); @@ -466,8 +470,9 @@ static void gen_bcond (DisasContext *ctx, void (*gen_test_op)(void), _gen_op_bcond(ctx); } -static void gen_fbcond (DisasContext *ctx, void (*gen_test_op)(void), - int ra, int32_t disp16) +static always_inline void gen_fbcond (DisasContext *ctx, + void (*gen_test_op)(void), + int ra, int32_t disp16) { if (disp16 != 0) { gen_set_uT0(ctx, ctx->pc); @@ -481,8 +486,9 @@ static void gen_fbcond (DisasContext *ctx, void (*gen_test_op)(void), _gen_op_bcond(ctx); } -static void gen_arith2 (DisasContext *ctx, void (*gen_arith_op)(void), - int rb, int rc, int islit, int8_t lit) +static always_inline void gen_arith2 (DisasContext *ctx, + void (*gen_arith_op)(void), + int rb, int rc, int islit, int8_t lit) { if (islit) gen_set_sT0(ctx, lit); @@ -492,8 +498,10 @@ static void gen_arith2 (DisasContext *ctx, void (*gen_arith_op)(void), gen_store_ir(ctx, rc, 0); } -static void gen_arith3 (DisasContext *ctx, void (*gen_arith_op)(void), - int ra, int rb, int rc, int islit, int8_t lit) +static always_inline void gen_arith3 (DisasContext *ctx, + void (*gen_arith_op)(void), + int ra, int rb, int rc, + int islit, int8_t lit) { gen_load_ir(ctx, ra, 0); if (islit) @@ -504,8 +512,10 @@ static void gen_arith3 (DisasContext *ctx, void (*gen_arith_op)(void), gen_store_ir(ctx, rc, 0); } -static void gen_cmov (DisasContext *ctx, void (*gen_test_op)(void), - int ra, int rb, int rc, int islit, int8_t lit) +static always_inline void gen_cmov (DisasContext *ctx, + void (*gen_test_op)(void), + int ra, int rb, int rc, + int islit, int8_t lit) { gen_load_ir(ctx, ra, 1); if (islit) @@ -516,16 +526,18 @@ static void gen_cmov (DisasContext *ctx, void (*gen_test_op)(void), gen_op_cmov_ir(rc); } -static void gen_farith2 (DisasContext *ctx, void (*gen_arith_fop)(void), - int rb, int rc) +static always_inline void gen_farith2 (DisasContext *ctx, + void (*gen_arith_fop)(void), + int rb, int rc) { gen_load_fir(ctx, rb, 0); (*gen_arith_fop)(); gen_store_fir(ctx, rc, 0); } -static void gen_farith3 (DisasContext *ctx, void (*gen_arith_fop)(void), - int ra, int rb, int rc) +static always_inline void gen_farith3 (DisasContext *ctx, + void (*gen_arith_fop)(void), + int ra, int rb, int rc) { gen_load_fir(ctx, ra, 0); gen_load_fir(ctx, rb, 1); @@ -533,8 +545,9 @@ static void gen_farith3 (DisasContext *ctx, void (*gen_arith_fop)(void), gen_store_fir(ctx, rc, 0); } -static void gen_fcmov (DisasContext *ctx, void (*gen_test_fop)(void), - int ra, int rb, int rc) +static always_inline void gen_fcmov (DisasContext *ctx, + void (*gen_test_fop)(void), + int ra, int rb, int rc) { gen_load_fir(ctx, ra, 0); gen_load_fir(ctx, rb, 1); @@ -542,77 +555,79 @@ static void gen_fcmov (DisasContext *ctx, void (*gen_test_fop)(void), gen_op_cmov_fir(rc); } -static void gen_fti (DisasContext *ctx, void (*gen_move_fop)(void), - int ra, int rc) +static always_inline void gen_fti (DisasContext *ctx, + void (*gen_move_fop)(void), + int ra, int rc) { gen_load_fir(ctx, rc, 0); (*gen_move_fop)(); gen_store_ir(ctx, ra, 0); } -static void gen_itf (DisasContext *ctx, void (*gen_move_fop)(void), - int ra, int rc) +static always_inline void gen_itf (DisasContext *ctx, + void (*gen_move_fop)(void), + int ra, int rc) { gen_load_ir(ctx, ra, 0); (*gen_move_fop)(); gen_store_fir(ctx, rc, 0); } -static void gen_s4addl (void) +static always_inline void gen_s4addl (void) { gen_op_s4(); gen_op_addl(); } -static void gen_s4subl (void) +static always_inline void gen_s4subl (void) { gen_op_s4(); gen_op_subl(); } -static void gen_s8addl (void) +static always_inline void gen_s8addl (void) { gen_op_s8(); gen_op_addl(); } -static void gen_s8subl (void) +static always_inline void gen_s8subl (void) { gen_op_s8(); gen_op_subl(); } -static void gen_s4addq (void) +static always_inline void gen_s4addq (void) { gen_op_s4(); gen_op_addq(); } -static void gen_s4subq (void) +static always_inline void gen_s4subq (void) { gen_op_s4(); gen_op_subq(); } -static void gen_s8addq (void) +static always_inline void gen_s8addq (void) { gen_op_s8(); gen_op_addq(); } -static void gen_s8subq (void) +static always_inline void gen_s8subq (void) { gen_op_s8(); gen_op_subq(); } -static void gen_amask (void) +static always_inline void gen_amask (void) { gen_op_load_amask(); gen_op_bic(); } -static int translate_one (DisasContext *ctx, uint32_t insn) +static always_inline int translate_one (DisasContext *ctx, uint32_t insn) { uint32_t palcode; int32_t disp21, disp16, disp12; @@ -1958,8 +1973,9 @@ static int translate_one (DisasContext *ctx, uint32_t insn) return ret; } -int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, - int search_pc) +static always_inline int gen_intermediate_code_internal (CPUState *env, + TranslationBlock *tb, + int search_pc) { #if defined ALPHA_DEBUG_DISAS static int insn_count; -- cgit v1.2.3 From 57ba97deb8d85c47dd60e8eb0c8a43687770137a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 28 Oct 2007 01:43:52 +0000 Subject: Less debug noise from the mipsnet driver. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3463 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mipsnet.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/mipsnet.c b/hw/mipsnet.c index bebfd4d80..97bc276b7 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -1,9 +1,9 @@ #include "vl.h" -#define DEBUG_MIPSNET_SEND -#define DEBUG_MIPSNET_RECEIVE +//#define DEBUG_MIPSNET_SEND +//#define DEBUG_MIPSNET_RECEIVE //#define DEBUG_MIPSNET_DATA -#define DEBUG_MIPSNET_IRQ +//#define DEBUG_MIPSNET_IRQ /* MIPSnet register offsets */ -- cgit v1.2.3 From 941db528719cda9ec54e3c5be901e175241141b2 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 28 Oct 2007 01:44:40 +0000 Subject: Use the shiny new clz helpers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3464 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-cris/helper.c | 4 ++-- target-cris/op.c | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/target-cris/helper.c b/target-cris/helper.c index 98305605a..d71959326 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -26,6 +26,7 @@ #include "cpu.h" #include "mmu.h" #include "exec-all.h" +#include "host-utils.h" #if defined(CONFIG_USER_ONLY) @@ -134,8 +135,7 @@ void do_interrupt(CPUState *env) return; } - irqnum = 31 - - __builtin_clz(env->pending_interrupts); + irqnum = 31 - clz32(env->pending_interrupts); irqnum += 0x30; ebp = env->pregs[SR_EBP]; isr = ldl_code(ebp + irqnum * 4); diff --git a/target-cris/op.c b/target-cris/op.c index 3ce9888bc..6e17719b6 100644 --- a/target-cris/op.c +++ b/target-cris/op.c @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec.h" +#include "host-utils.h" #define REGNAME r0 #define REG (env->regs[0]) @@ -1003,10 +1004,7 @@ void OPPROTO op_bound_T0_T1 (void) void OPPROTO op_lz_T0_T1 (void) { - if (T1 == 0) - T0 = 32; - else - T0 = __builtin_clz(T1); + T0 = clz32(T1); RETURN(); } -- cgit v1.2.3 From b9ef45ffa8df1b63b8d126910f62541fa355155e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 28 Oct 2007 12:52:38 +0000 Subject: Add shared ctz32, cto32, ctz64, cto64, ctpop8, ctpop16, ctpop32 and ctpop64 helpers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3465 c046a42c-6fe2-441c-8c8c-71466251a162 --- host-utils.h | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/host-utils.h b/host-utils.h index d1e89c2f3..fe306f6e4 100644 --- a/host-utils.h +++ b/host-utils.h @@ -102,3 +102,100 @@ static always_inline int clo64(uint64_t val) { return clz64(~val); } + +static always_inline int ctz32 (uint32_t val) +{ + int cnt; + + cnt = 0; + if (!(val & 0x0000FFFFUL)) { + cnt += 16; + val >>= 16; + } + if (!(val & 0x000000FFUL)) { + cnt += 8; + val >>= 8; + } + if (!(val & 0x0000000FUL)) { + cnt += 4; + val >>= 4; + } + if (!(val & 0x00000003UL)) { + cnt += 2; + val >>= 2; + } + if (!(val & 0x00000001UL)) { + cnt++; + val >>= 1; + } + if (!(val & 0x00000001UL)) { + cnt++; + } + + return cnt; + } + +static always_inline int cto32 (uint32_t val) + { + return ctz32(~val); +} + +static always_inline int ctz64 (uint64_t val) +{ + int cnt; + + cnt = 0; + if (!((uint32_t)val)) { + cnt += 32; + val >>= 32; + } + + return cnt + ctz32(val); +} + +static always_inline int cto64 (uint64_t val) +{ + return ctz64(~val); +} + +static always_inline int ctpop8 (uint8_t val) +{ + val = (val & 0x55) + ((val >> 1) & 0x55); + val = (val & 0x33) + ((val >> 2) & 0x33); + val = (val & 0x0f) + ((val >> 4) & 0x0f); + + return val; +} + +static always_inline int ctpop16 (uint16_t val) +{ + val = (val & 0x5555) + ((val >> 1) & 0x5555); + val = (val & 0x3333) + ((val >> 2) & 0x3333); + val = (val & 0x0f0f) + ((val >> 4) & 0x0f0f); + val = (val & 0x00ff) + ((val >> 8) & 0x00ff); + + return val; +} + +static always_inline int ctpop32 (uint32_t val) +{ + val = (val & 0x55555555) + ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f); + val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff); + val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff); + + return val; +} + +static always_inline int ctpop64 (uint64_t val) +{ + val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); + val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); + val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL); + val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) & 0x00ff00ff00ff00ffULL); + val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) & 0x0000ffff0000ffffULL); + val = (val & 0x00000000ffffffffULL) + ((val >> 32) & 0x00000000ffffffffULL); + + return val; + } -- cgit v1.2.3 From 603fcccece43303c623df2561f85ab2baba95e5f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 28 Oct 2007 12:54:53 +0000 Subject: Make Alpha and PowerPC targets use shared helpers for clz, clo, ctz, cto and ctpop. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3466 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/op_helper.c | 77 +++--------------------------------------------- target-ppc/op.c | 5 ++-- target-ppc/op_helper.c | 33 +++++++++++---------- target-ppc/op_helper.h | 76 +++-------------------------------------------- 4 files changed, 29 insertions(+), 162 deletions(-) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index f9390c84d..ae8470b59 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -19,6 +19,7 @@ */ #include "exec.h" +#include "host-utils.h" #include "softfloat.h" #include "op_helper.h" @@ -211,87 +212,17 @@ void helper_mulqv () void helper_ctpop (void) { - int n; - - for (n = 0; T0 != 0; n++) - T0 = T0 ^ (T0 - 1); - T0 = n; + T0 = ctpop64(T0); } void helper_ctlz (void) { - uint32_t op32; - int n; - - n = 0; - if (!(T0 & 0xFFFFFFFF00000000ULL)) { - n += 32; - T0 <<= 32; - } - /* Make it easier for 32 bits hosts */ - op32 = T0 >> 32; - if (!(op32 & 0xFFFF0000UL)) { - n += 16; - op32 <<= 16; - } - if (!(op32 & 0xFF000000UL)) { - n += 8; - op32 <<= 8; - } - if (!(op32 & 0xF0000000UL)) { - n += 4; - op32 <<= 4; - } - if (!(op32 & 0xC0000000UL)) { - n += 2; - op32 <<= 2; - } - if (!(op32 & 0x80000000UL)) { - n++; - op32 <<= 1; - } - if (!(op32 & 0x80000000UL)) { - n++; - } - T0 = n; + T0 = clz64(T0); } void helper_cttz (void) { - uint32_t op32; - int n; - - n = 0; - if (!(T0 & 0x00000000FFFFFFFFULL)) { - n += 32; - T0 >>= 32; - } - /* Make it easier for 32 bits hosts */ - op32 = T0; - if (!(op32 & 0x0000FFFFUL)) { - n += 16; - op32 >>= 16; - } - if (!(op32 & 0x000000FFUL)) { - n += 8; - op32 >>= 8; - } - if (!(op32 & 0x0000000FUL)) { - n += 4; - op32 >>= 4; - } - if (!(op32 & 0x00000003UL)) { - n += 2; - op32 >>= 2; - } - if (!(op32 & 0x00000001UL)) { - n++; - op32 >>= 1; - } - if (!(op32 & 0x00000001UL)) { - n++; - } - T0 = n; + T0 = ctz64(T0); } static always_inline uint64_t byte_zap (uint64_t op, uint8_t mskb) diff --git a/target-ppc/op.c b/target-ppc/op.c index 0146d33c3..4c170d84b 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -22,6 +22,7 @@ #include "config.h" #include "exec.h" +#include "host-utils.h" #include "helper_regs.h" #include "op_helper.h" @@ -1508,14 +1509,14 @@ void OPPROTO op_andi_T1_64 (void) /* count leading zero */ void OPPROTO op_cntlzw (void) { - T0 = _do_cntlzw(T0); + do_cntlzw(); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_cntlzd (void) { - T0 = _do_cntlzd(T0); + do_cntlzd(); RETURN(); } #endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 61075c086..751bd7212 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec.h" +#include "host-utils.h" #include "helper_regs.h" #include "op_helper.h" @@ -381,6 +382,18 @@ void do_subfzeo_64 (void) } #endif +void do_cntlzw (void) +{ + T0 = clz32(T0); +} + +#if defined(TARGET_PPC64) +void do_cntlzd (void) +{ + T0 = clz64(T0); +} +#endif + /* shift right arithmetic helper */ void do_sraw (void) { @@ -438,16 +451,6 @@ void do_srad (void) } #endif -static always_inline int popcnt (uint32_t val) -{ - int i; - - for (i = 0; val != 0;) - val = val ^ (val - 1); - - return i; -} - void do_popcntb (void) { uint32_t ret; @@ -455,7 +458,7 @@ void do_popcntb (void) ret = 0; for (i = 0; i < 32; i += 8) - ret |= popcnt((T0 >> i) & 0xFF) << i; + ret |= ctpop8((T0 >> i) & 0xFF) << i; T0 = ret; } @@ -467,7 +470,7 @@ void do_popcntb_64 (void) ret = 0; for (i = 0; i < 64; i += 8) - ret |= popcnt((T0 >> i) & 0xFF) << i; + ret |= ctpop8((T0 >> i) & 0xFF) << i; T0 = ret; } #endif @@ -1924,14 +1927,14 @@ static always_inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2) static always_inline int _do_ecntlsw (uint32_t val) { if (val & 0x80000000) - return _do_cntlzw(~val); + return clz32(~val); else - return _do_cntlzw(val); + return clz32(val); } static always_inline int _do_ecntlzw (uint32_t val) { - return _do_cntlzw(val); + return clz32(val); } static always_inline uint32_t _do_eneg (uint32_t val) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 6597b3ca5..915b32a28 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -75,6 +75,10 @@ void do_nego (void); void do_subfe (void); void do_subfmeo (void); void do_subfzeo (void); +void do_cntlzw (void); +#if defined(TARGET_PPC64) +void do_cntlzd (void); +#endif void do_sraw (void); #if defined(TARGET_PPC64) void do_adde_64 (void); @@ -285,78 +289,6 @@ void do_evfsctsiz (void); void do_evfsctuiz (void); #endif /* defined(TARGET_PPCEMB) */ -/* Inlined helpers: used in micro-operation as well as helpers */ -/* Generic fixed-point helpers */ -static always_inline int _do_cntlzw (uint32_t val) -{ - int cnt = 0; - if (!(val & 0xFFFF0000UL)) { - cnt += 16; - val <<= 16; - } - if (!(val & 0xFF000000UL)) { - cnt += 8; - val <<= 8; - } - if (!(val & 0xF0000000UL)) { - cnt += 4; - val <<= 4; - } - if (!(val & 0xC0000000UL)) { - cnt += 2; - val <<= 2; - } - if (!(val & 0x80000000UL)) { - cnt++; - val <<= 1; - } - if (!(val & 0x80000000UL)) { - cnt++; - } - return cnt; -} - -static always_inline int _do_cntlzd (uint64_t val) -{ - int cnt = 0; -#if HOST_LONG_BITS == 64 - if (!(val & 0xFFFFFFFF00000000ULL)) { - cnt += 32; - val <<= 32; - } - if (!(val & 0xFFFF000000000000ULL)) { - cnt += 16; - val <<= 16; - } - if (!(val & 0xFF00000000000000ULL)) { - cnt += 8; - val <<= 8; - } - if (!(val & 0xF000000000000000ULL)) { - cnt += 4; - val <<= 4; - } - if (!(val & 0xC000000000000000ULL)) { - cnt += 2; - val <<= 2; - } - if (!(val & 0x8000000000000000ULL)) { - cnt++; - val <<= 1; - } - if (!(val & 0x8000000000000000ULL)) { - cnt++; - } -#else - /* Make it easier on 32 bits host machines */ - if (!(val >> 32)) - cnt = _do_cntlzw(val) + 32; - else - cnt = _do_cntlzw(val >> 32); -#endif - return cnt; -} - #if defined(TARGET_PPCEMB) /* SPE extension */ /* Single precision floating-point helpers */ -- cgit v1.2.3 From 2f96c28d5518944fa3577b09582aa5ae39f8b509 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 28 Oct 2007 13:07:12 +0000 Subject: Use cpp to generate correct build dependencies for target objects instead of using incomplete hardcoded ones. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3467 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 60 ++++++--------------------------------------------------- 1 file changed, 6 insertions(+), 54 deletions(-) diff --git a/Makefile.target b/Makefile.target index 2a0648a29..cafcc60f0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -24,7 +24,7 @@ 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) +CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MP ifdef CONFIG_DARWIN_USER VPATH+=:$(SRC_PATH)/darwin-user CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH) @@ -645,58 +645,6 @@ cpu-exec.o: cpu-exec.c signal.o: signal.c $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< -vga.o: pixel_ops.h - -tcx.o: pixel_ops.h - -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) -helper.o: cpu.h exec-all.h -op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h exec.h cpu.h -op_helper.o: exec.h softmmu_template.h cpu.h -translate.o: cpu.h exec-all.h disas.h -endif - -ifeq ($(TARGET_BASE_ARCH), ppc) -op.o: op.c op_template.h op_mem.h op_helper.h -op_helper.o: op_helper.c mfrom_table.c op_helper_mem.h op_helper.h -translate.o: translate.c translate_init.c -endif - -ifeq ($(TARGET_BASE_ARCH), mips) -helper.o: cpu.h exec-all.h -op.o: op_template.c fop_template.c op_mem.c exec.h cpu.h -op_helper.o: exec.h softmmu_template.h cpu.h -translate.o: translate_init.c exec-all.h disas.h -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 - -ifeq ($(TARGET_BASE_ARCH), alpha) -op.o: op.c op_template.h op_mem.h -op_helper.o: op_helper_mem.h -endif - -$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h - %.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< @@ -704,7 +652,8 @@ $(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h $(CC) $(CPPFLAGS) -c -o $@ $< clean: - rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o + rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o + rm -f *.d */*.d install: all ifneq ($(PROGS),) @@ -720,3 +669,6 @@ 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 + +# Include automatically generated dependency files +-include $(wildcard *.d */*.d) -- cgit v1.2.3 From eed152bba588001550eb6a54366aee89f087f1bf Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 28 Oct 2007 14:35:04 +0000 Subject: Use shared ctpop64 helper git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3468 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 7b1b08e43..ccadf8510 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1,4 +1,5 @@ #include "exec.h" +#include "host-utils.h" //#define DEBUG_PCALL //#define DEBUG_MMU @@ -1469,12 +1470,7 @@ void do_rdpsr() void do_popc() { - T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL); - T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL); - T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL); - T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL); - T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL); - T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL); + T0 = ctpop64(T1); } static inline uint64_t *get_gregset(uint64_t pstate) -- cgit v1.2.3 From fe71e81aba0f0cc10cd807a1b3f7a2978db255ce Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 28 Oct 2007 16:45:01 +0000 Subject: Implement OMAP1 MPU I/O module. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3469 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/omap.h | 10 +++ 2 files changed, 295 insertions(+), 2 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index ccd8f4ef7..a1e8598bb 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -2787,6 +2787,282 @@ static void omap_clkm_init(target_phys_addr_t mpu_base, cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]); } +/* MPU I/O */ +struct omap_mpuio_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq kbd_irq; + qemu_irq *in; + qemu_irq handler[16]; + qemu_irq wakeup; + + uint16_t inputs; + uint16_t outputs; + uint16_t dir; + uint16_t edge; + uint16_t mask; + uint16_t ints; + + uint16_t debounce; + uint16_t latch; + uint8_t event; + + uint8_t buttons[5]; + uint8_t row_latch; + uint8_t cols; + int kbd_mask; + int clk; +}; + +static void omap_mpuio_set(void *opaque, int line, int level) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + uint16_t prev = s->inputs; + + if (level) + s->inputs |= 1 << line; + else + s->inputs &= ~(1 << line); + + if (((1 << line) & s->dir & ~s->mask) && s->clk) { + if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) { + s->ints |= 1 << line; + qemu_irq_raise(s->irq); + /* TODO: wakeup */ + } + if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ + (s->event >> 1) == line) /* PIN_SELECT */ + s->latch = s->inputs; + } +} + +static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) +{ + int i; + uint8_t *row, rows = 0, cols = ~s->cols; + + for (row = s->buttons + 4, i = 1 << 5; i; row --, i >>= 1) + if (*row & cols) + s->row_latch |= i; + + if (rows && ~s->kbd_mask && s->clk) + qemu_irq_raise(s->kbd_irq); + s->row_latch = rows ^ 0x1f; +} + +static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + int offset = addr - s->base; + uint16_t ret; + + switch (offset) { + case 0x00: /* INPUT_LATCH */ + return s->inputs; + + case 0x04: /* OUTPUT_REG */ + return s->outputs; + + case 0x08: /* IO_CNTL */ + return s->dir; + + case 0x10: /* KBR_LATCH */ + return s->row_latch; + + case 0x14: /* KBC_REG */ + return s->cols; + + case 0x18: /* GPIO_EVENT_MODE_REG */ + return s->event; + + case 0x1c: /* GPIO_INT_EDGE_REG */ + return s->edge; + + case 0x20: /* KBD_INT */ + return (s->row_latch != 0x1f) && !s->kbd_mask; + + case 0x24: /* GPIO_INT */ + ret = s->ints; + s->ints &= ~s->mask; + return ret; + + case 0x28: /* KBD_MASKIT */ + return s->kbd_mask; + + case 0x2c: /* GPIO_MASKIT */ + return s->mask; + + case 0x30: /* GPIO_DEBOUNCING_REG */ + return s->debounce; + + case 0x34: /* GPIO_LATCH_REG */ + return s->latch; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + int offset = addr - s->base; + uint16_t diff; + int ln; + + switch (offset) { + case 0x04: /* OUTPUT_REG */ + diff = s->outputs ^ (value & ~s->dir); + s->outputs = value; + value &= ~s->dir; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x08: /* IO_CNTL */ + diff = s->outputs & (s->dir ^ value); + s->dir = value; + + value = s->outputs & ~s->dir; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x14: /* KBC_REG */ + s->cols = value; + omap_mpuio_kbd_update(s); + break; + + case 0x18: /* GPIO_EVENT_MODE_REG */ + s->event = value & 0x1f; + break; + + case 0x1c: /* GPIO_INT_EDGE_REG */ + s->edge = value; + break; + + case 0x28: /* KBD_MASKIT */ + s->kbd_mask = value & 1; + omap_mpuio_kbd_update(s); + break; + + case 0x2c: /* GPIO_MASKIT */ + s->mask = value; + break; + + case 0x30: /* GPIO_DEBOUNCING_REG */ + s->debounce = value & 0x1ff; + break; + + case 0x00: /* INPUT_LATCH */ + case 0x10: /* KBR_LATCH */ + case 0x20: /* KBD_INT */ + case 0x24: /* GPIO_INT */ + case 0x34: /* GPIO_LATCH_REG */ + OMAP_RO_REG(addr); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_mpuio_readfn[] = { + omap_badwidth_read16, + omap_mpuio_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_mpuio_writefn[] = { + omap_badwidth_write16, + omap_mpuio_write, + omap_badwidth_write16, +}; + +void omap_mpuio_reset(struct omap_mpuio_s *s) +{ + s->inputs = 0; + s->outputs = 0; + s->dir = ~0; + s->event = 0; + s->edge = 0; + s->kbd_mask = 0; + s->mask = 0; + s->debounce = 0; + s->latch = 0; + s->ints = 0; + s->row_latch = 0x1f; +} + +static void omap_mpuio_onoff(void *opaque, int line, int on) +{ + struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; + + s->clk = on; + if (on) + omap_mpuio_kbd_update(s); +} + +struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, + qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, + omap_clk clk) +{ + int iomemtype; + struct omap_mpuio_s *s = (struct omap_mpuio_s *) + qemu_mallocz(sizeof(struct omap_mpuio_s)); + + s->base = base; + s->irq = gpio_int; + s->kbd_irq = kbd_int; + s->wakeup = wakeup; + s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); + omap_mpuio_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_mpuio_readfn, + omap_mpuio_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]); + + return s; +} + +qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s) +{ + return s->in; +} + +void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler) +{ + if (line >= 16 || line < 0) + cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); + s->handler[line] = handler; +} + +void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) +{ + if (row >= 5 || row < 0) + cpu_abort(cpu_single_env, "%s: No key %i-%i\n", + __FUNCTION__, col, row); + + if (down) + s->buttons[row] = 1 << col; + else + s->buttons[row] = ~(1 << col); + + omap_mpuio_kbd_update(s); +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -2814,6 +3090,7 @@ static void omap_mpu_reset(void *opaque) omap_uart_reset(mpu->uart2); omap_uart_reset(mpu->uart3); omap_mmc_reset(mpu->mmc); + omap_mpuio_reset(mpu->mpuio); cpu_reset(mpu->env); } @@ -2821,7 +3098,8 @@ static void omap_mpu_wakeup(void *opaque, int irq, int req) { struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); + if (mpu->env->halted) + cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); } struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, @@ -2839,6 +3117,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, cpu_arm_set_model(s->env, core ?: "ti925t"); + s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; + /* Clocks */ omap_clk_init(s); @@ -2922,8 +3202,11 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->mmc = omap_mmc_init(0xfffb7800, s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck")); + s->mpuio = omap_mpuio_init(0xfffb5000, + s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], + s->wakeup, omap_findclk(s, "clk32-kHz")); + qemu_register_reset(omap_mpu_reset, s); - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; return s; } diff --git a/hw/omap.h b/hw/omap.h index 96cd3affd..1ebb87aeb 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -450,6 +450,14 @@ struct omap_uart_s; struct omap_uart_s *omap_uart_init(target_phys_addr_t base, qemu_irq irq, omap_clk clk, CharDriverState *chr); +struct omap_mpuio_s; +struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, + qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, + omap_clk clk); +qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s); +void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler); +void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); @@ -563,6 +571,8 @@ struct omap_mpu_state_s { uint16_t dsp_idlect2; uint16_t dsp_rstct2; } clkm; + + struct omap_mpuio_s *mpuio; } *omap310_mpu_init(unsigned long sdram_size, DisplayState *ds, const char *core); -- cgit v1.2.3 From 38a34e1d7aa1ac64c2615952ee732da47eee9f14 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 28 Oct 2007 18:29:04 +0000 Subject: Add PalmT|E matrix keypad connected to OMAP GPIOs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3470 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 12 ++++++------ hw/palm.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index a1e8598bb..9c0e570ae 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -2841,12 +2841,11 @@ static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) int i; uint8_t *row, rows = 0, cols = ~s->cols; - for (row = s->buttons + 4, i = 1 << 5; i; row --, i >>= 1) + for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1) if (*row & cols) - s->row_latch |= i; + rows |= i; - if (rows && ~s->kbd_mask && s->clk) - qemu_irq_raise(s->kbd_irq); + qemu_set_irq(s->kbd_irq, rows && ~s->kbd_mask && s->clk); s->row_latch = rows ^ 0x1f; } @@ -3002,6 +3001,7 @@ void omap_mpuio_reset(struct omap_mpuio_s *s) s->latch = 0; s->ints = 0; s->row_latch = 0x1f; + s->clk = 1; } static void omap_mpuio_onoff(void *opaque, int line, int on) @@ -3056,9 +3056,9 @@ void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) __FUNCTION__, col, row); if (down) - s->buttons[row] = 1 << col; + s->buttons[row] |= 1 << col; else - s->buttons[row] = ~(1 << col); + s->buttons[row] &= ~(1 << col); omap_mpuio_kbd_update(s); } diff --git a/hw/palm.c b/hw/palm.c index 623fcd648..ead9cfd45 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -61,6 +61,35 @@ static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) { } +static struct { + int row; + int column; +} palmte_keymap[0x80] = { + [0 ... 0x7f] = { -1, -1 }, + [0x3b] = { 0, 0 }, /* F1 -> Calendar */ + [0x3c] = { 1, 0 }, /* F2 -> Contacts */ + [0x3d] = { 2, 0 }, /* F3 -> Tasks List */ + [0x3e] = { 3, 0 }, /* F4 -> Note Pad */ + [0x01] = { 4, 0 }, /* Esc -> Power */ + [0x4b] = { 0, 1 }, /* Left */ + [0x50] = { 1, 1 }, /* Down */ + [0x48] = { 2, 1 }, /* Up */ + [0x4d] = { 3, 1 }, /* Right */ + [0x4c] = { 4, 1 }, /* Centre */ + [0x39] = { 4, 1 }, /* Spc -> Centre */ +}; + +static void palmte_button_event(void *opaque, int keycode) +{ + struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; + + if (palmte_keymap[keycode & 0x7f].row != -1) + omap_mpuio_key(cpu->mpuio, + palmte_keymap[keycode & 0x7f].row, + palmte_keymap[keycode & 0x7f].column, + !(keycode & 0x80)); +} + static void palmte_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -101,6 +130,8 @@ static void palmte_init(int ram_size, int vga_ram_size, int boot_device, palmte_microwire_setup(cpu); + qemu_add_kbd_event_handler(palmte_button_event, cpu); + /* Setup initial (reset) machine state */ if (nb_option_roms) { rom_size = get_image_size(option_rom[0]); -- cgit v1.2.3 From 8e129e0748f866d730f1e39bff296219fedac244 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 28 Oct 2007 19:24:52 +0000 Subject: Handle MMC card insertion/removal/readonly signals. Hook them up to Palm T|E GPIOs. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3471 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 4 +++- hw/omap.h | 1 + hw/omap_mmc.c | 25 ++++++++++++++++++++++++- hw/palm.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index 9c0e570ae..f8c2073da 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -2882,7 +2882,9 @@ static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) case 0x24: /* GPIO_INT */ ret = s->ints; - s->ints &= ~s->mask; + s->ints &= s->mask; + if (ret) + qemu_irq_lower(s->irq); return ret; case 0x28: /* KBD_MASKIT */ diff --git a/hw/omap.h b/hw/omap.h index 1ebb87aeb..70888698c 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -470,6 +470,7 @@ struct omap_mmc_s; struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, qemu_irq irq, qemu_irq dma[], omap_clk clk); void omap_mmc_reset(struct omap_mmc_s *s); +void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover); # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index aa77660f2..008318db3 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -25,6 +25,7 @@ struct omap_mmc_s { target_phys_addr_t base; qemu_irq irq; qemu_irq *dma; + qemu_irq handler[2]; omap_clk clk; SDState *card; uint16_t last_cmd; @@ -506,6 +507,22 @@ void omap_mmc_reset(struct omap_mmc_s *host) host->transfer = 0; } +static void omap_mmc_ro_cb(void *opaque, int level) +{ + struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; + + if (s->handler[0]) + qemu_set_irq(s->handler[0], level); +} + +static void omap_mmc_cover_cb(void *opaque, int level) +{ + struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; + + if (s->handler[1]) + qemu_set_irq(s->handler[1], level); +} + struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, qemu_irq irq, qemu_irq dma[], omap_clk clk) { @@ -525,7 +542,13 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, /* Instantiate the storage */ s->card = sd_init(sd_bdrv); + sd_set_cb(s->card, s, omap_mmc_ro_cb, omap_mmc_cover_cb); + return s; } -/* TODO: insertion and read-only handlers */ +void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover) +{ + s->handler[0] = ro; + s->handler[1] = cover; +} diff --git a/hw/palm.c b/hw/palm.c index ead9cfd45..ba7e47f9f 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -57,6 +57,24 @@ static CPUWriteMemoryFunc *static_writefn[] = { }; /* Palm Tunsgten|E support */ + +/* Shared GPIOs */ +#define PALMTE_USBDETECT_GPIO 0 +#define PALMTE_USB_OR_DC_GPIO 1 +#define PALMTE_TSC_GPIO 4 +#define PALMTE_PINTDAV_GPIO 6 +#define PALMTE_MMC_WP_GPIO 8 +#define PALMTE_MMC_POWER_GPIO 9 +#define PALMTE_HDQ_GPIO 11 +#define PALMTE_HEADPHONES_GPIO 14 +#define PALMTE_SPEAKER_GPIO 15 +/* MPU private GPIOs */ +#define PALMTE_DC_GPIO 2 +#define PALMTE_MMC_SWITCH_GPIO 4 +#define PALMTE_MMC1_GPIO 6 +#define PALMTE_MMC2_GPIO 7 +#define PALMTE_MMC3_GPIO 11 + static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) { } @@ -90,6 +108,14 @@ static void palmte_button_event(void *opaque, int keycode) !(keycode & 0x80)); } +static void palmte_mmc_cover(void *opaque, int line, int level) +{ + struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; + + qemu_set_irq(omap_mpuio_in_get(cpu->mpuio)[PALMTE_MMC_SWITCH_GPIO], + !level); +} + static void palmte_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -132,6 +158,9 @@ static void palmte_init(int ram_size, int vga_ram_size, int boot_device, qemu_add_kbd_event_handler(palmte_button_event, cpu); + omap_mmc_handlers(cpu->mmc, 0, + qemu_allocate_irqs(palmte_mmc_cover, cpu, 1)[0]); + /* Setup initial (reset) machine state */ if (nb_option_roms) { rom_size = get_image_size(option_rom[0]); -- cgit v1.2.3 From 623a930ec30a75e6d6482ca8208d7bf1ca8d359b Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 28 Oct 2007 19:45:05 +0000 Subject: Implement missing MIPS supervisor mode bits. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3472 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 2 +- linux-user/elfload.c | 2 +- target-mips/cpu.h | 26 ++++++++++++++++---------- target-mips/exec.h | 12 ++++-------- target-mips/helper.c | 6 +++--- target-mips/op.c | 10 +++++++--- target-mips/op_helper.c | 18 ++++++++++++------ target-mips/translate.c | 12 +++++++----- 8 files changed, 51 insertions(+), 37 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 86557e442..8414aca22 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -122,7 +122,7 @@ typedef struct CPUTLBEntry { written */ \ target_ulong mem_write_vaddr; /* target virtual addr at which the \ memory was written */ \ - /* 0 = kernel, 1 = user */ \ + /* The meaning of the MMU modes is defined in the target code. */ \ CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ \ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ab5a74e49..2d758de20 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -374,7 +374,7 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - regs->cp0_status = CP0St_UM; + regs->cp0_status = 2 << CP0St_KSU; regs->cp0_epc = infop->entry; regs->regs[29] = infop->start_stack; } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 363fcd866..5fbb90e67 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -107,7 +107,7 @@ struct CPUMIPSFPUContext { #define FP_UNIMPLEMENTED 32 }; -#define NB_MMU_MODES 2 +#define NB_MMU_MODES 3 typedef struct CPUMIPSMVPContext CPUMIPSMVPContext; struct CPUMIPSMVPContext { @@ -285,8 +285,7 @@ struct CPUMIPSState { #define CP0St_KX 7 #define CP0St_SX 6 #define CP0St_UX 5 -#define CP0St_UM 4 -#define CP0St_R0 3 +#define CP0St_KSU 3 #define CP0St_ERL 2 #define CP0St_EXL 1 #define CP0St_IE 0 @@ -418,9 +417,14 @@ struct CPUMIPSState { /* TMASK defines different execution modes */ #define MIPS_HFLAG_TMASK 0x00FF #define MIPS_HFLAG_MODE 0x0007 /* execution modes */ -#define MIPS_HFLAG_UM 0x0001 /* user mode */ -#define MIPS_HFLAG_DM 0x0002 /* Debug mode */ -#define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */ + /* The KSU flags must be the lowest bits in hflags. The flag order + must be the same as defined for CP0 Status. This allows to use + the bits as the value of mmu_idx. */ +#define MIPS_HFLAG_KSU 0x0003 /* kernel/supervisor/user mode mask */ +#define MIPS_HFLAG_UM 0x0002 /* user mode flag */ +#define MIPS_HFLAG_SM 0x0001 /* supervisor mode flag */ +#define MIPS_HFLAG_KM 0x0000 /* kernel mode flag */ +#define MIPS_HFLAG_DM 0x0004 /* Debug mode */ #define MIPS_HFLAG_64 0x0008 /* 64-bit instructions enabled */ #define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */ #define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */ @@ -489,13 +493,15 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, #define cpu_signal_handler cpu_mips_signal_handler #define cpu_list mips_cpu_list -/* MMU modes definitions */ +/* MMU modes definitions. We carefully match the indices with our + hflags layout. */ #define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _user -#define MMU_USER_IDX 1 +#define MMU_MODE1_SUFFIX _super +#define MMU_MODE2_SUFFIX _user +#define MMU_USER_IDX 2 static inline int cpu_mmu_index (CPUState *env) { - return (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 1 : 0; + return env->hflags & MIPS_HFLAG_KSU; } #include "cpu-all.h" diff --git a/target-mips/exec.h b/target-mips/exec.h index 61c09acb6..529306f3b 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -230,24 +230,20 @@ static always_inline int cpu_halted(CPUState *env) static always_inline void compute_hflags(CPUState *env) { env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | - MIPS_HFLAG_FPU | MIPS_HFLAG_UM); + MIPS_HFLAG_FPU | MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { - if (env->CP0_Status & (1 << CP0St_UM)) - env->hflags |= MIPS_HFLAG_UM; - if (env->CP0_Status & (1 << CP0St_R0)) - env->hflags |= MIPS_HFLAG_SM; + env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; } #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) - if (!(env->hflags & MIPS_HFLAG_UM) || + if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || (env->CP0_Status & (1 << CP0St_PX)) || (env->CP0_Status & (1 << CP0St_UX))) env->hflags |= MIPS_HFLAG_64; #endif if ((env->CP0_Status & (1 << CP0St_CU0)) || - (!(env->hflags & MIPS_HFLAG_UM) && - !(env->hflags & MIPS_HFLAG_SM))) + !(env->hflags & MIPS_HFLAG_KSU)) env->hflags |= MIPS_HFLAG_CP0; if (env->CP0_Status & (1 << CP0St_CU1)) env->hflags |= MIPS_HFLAG_FPU; diff --git a/target-mips/helper.c b/target-mips/helper.c index 45874d446..708641c42 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -373,7 +373,7 @@ void do_interrupt (CPUState *env) } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); + env->hflags &= ~(MIPS_HFLAG_KSU); /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -399,7 +399,7 @@ void do_interrupt (CPUState *env) } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); + env->hflags &= ~(MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->PC[env->current_tc] = (int32_t)0xBFC00000; @@ -501,7 +501,7 @@ void do_interrupt (CPUState *env) } env->CP0_Status |= (1 << CP0St_EXL); env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); + env->hflags &= ~(MIPS_HFLAG_KSU); } env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { diff --git a/target-mips/op.c b/target-mips/op.c index 9e8324d49..f29134567 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -286,6 +286,10 @@ void op_store_LO (void) #include "op_mem.c" #undef MEMSUFFIX +#define MEMSUFFIX _super +#include "op_mem.c" +#undef MEMSUFFIX + #define MEMSUFFIX _kernel #include "op_mem.c" #undef MEMSUFFIX @@ -298,7 +302,7 @@ void op_addr_add (void) with Status_UX = 0 should be casted to 32-bit and sign extended. See the MIPS64 PRA manual, section 4.10. */ #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) - if ((env->hflags & MIPS_HFLAG_UM) && + if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_UX))) T0 = (int64_t)(int32_t)(T0 + T1); else @@ -1269,7 +1273,7 @@ void op_mftc0_status(void) T0 = env->CP0_Status & ~0xf1000018; T0 |= tcstatus & (0xf << CP0TCSt_TCU0); T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); - T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_R0); + T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU); RETURN(); } @@ -1833,7 +1837,7 @@ void op_mttc0_status(void) env->CP0_Status = T0 & ~0xf1000018; tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (T0 & (0xf << CP0St_CU0)); tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((T0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); - tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_R0)) << (CP0TCSt_TKSU - CP0St_R0)); + tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU)); env->CP0_TCStatus[other_tc] = tcstatus; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index ff26ab5af..3c04c55d8 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -315,8 +315,12 @@ void do_mtc0_status_debug(uint32_t old, uint32_t val) old, old & env->CP0_Cause & CP0Ca_IP_mask, val, val & env->CP0_Cause & CP0Ca_IP_mask, env->CP0_Cause); - (env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile) - : fputs("\n", logfile); + switch (env->hflags & MIPS_HFLAG_KSU) { + case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break; + case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break; + case MIPS_HFLAG_KM: fputs("\n", logfile); break; + default: cpu_abort(env, "Invalid MMU mode!\n"); break; + } } void do_mtc0_status_irqraise_debug(void) @@ -518,10 +522,12 @@ void debug_post_eret (void) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); if (env->hflags & MIPS_HFLAG_DM) fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC); - if (env->hflags & MIPS_HFLAG_UM) - fputs(", UM\n", logfile); - else - fputs("\n", logfile); + switch (env->hflags & MIPS_HFLAG_KSU) { + case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break; + case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break; + case MIPS_HFLAG_KM: fputs("\n", logfile); break; + default: cpu_abort(env, "Invalid MMU mode!\n"); break; + } } void do_pmon (int function) diff --git a/target-mips/translate.c b/target-mips/translate.c index 89fe5fe23..ce0b4dcfe 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -790,13 +790,15 @@ static always_inline void check_mips_64(DisasContext *ctx) #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_user, \ &gen_op_l##width##_kernel, \ + &gen_op_l##width##_super, \ + &gen_op_l##width##_user, \ } #define OP_ST_TABLE(width) \ static GenOpFunc *gen_op_s##width[] = { \ - &gen_op_s##width##_user, \ &gen_op_s##width##_kernel, \ + &gen_op_s##width##_super, \ + &gen_op_s##width##_user, \ } #endif @@ -6494,9 +6496,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ restore_cpu_state(env, &ctx); #if defined(CONFIG_USER_ONLY) - ctx.mem_idx = 0; + ctx.mem_idx = MIPS_HFLAG_UM; #else - ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); + ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; #endif #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { @@ -6507,7 +6509,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #endif #ifdef MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "\ntb %p super %d cond %04x\n", + fprintf(logfile, "\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags); #endif while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { -- cgit v1.2.3 From 6433014805f6f23050c4c4d0483b0241b3eaccb4 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 28 Oct 2007 21:02:29 +0000 Subject: Add OMAP Shared GPIO module. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3473 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/omap.h | 7 +++ hw/palm.c | 3 +- 3 files changed, 186 insertions(+), 1 deletion(-) diff --git a/hw/omap.c b/hw/omap.c index f8c2073da..a2a18a406 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -3065,6 +3065,179 @@ void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down) omap_mpuio_kbd_update(s); } +/* General-Purpose I/O */ +struct omap_gpio_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq *in; + qemu_irq handler[16]; + + uint16_t inputs; + uint16_t outputs; + uint16_t dir; + uint16_t edge; + uint16_t mask; + uint16_t ints; +}; + +static void omap_gpio_set(void *opaque, int line, int level) +{ + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; + uint16_t prev = s->inputs; + + if (level) + s->inputs |= 1 << line; + else + s->inputs &= ~(1 << line); + + if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) & + (1 << line) & s->dir & ~s->mask) { + s->ints |= 1 << line; + qemu_irq_raise(s->irq); + } +} + +static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; + int offset = addr - s->base; + uint16_t ret; + + switch (offset) { + case 0x00: /* DATA_INPUT */ + return s->inputs; + + case 0x04: /* DATA_OUTPUT */ + return s->outputs; + + case 0x08: /* DIRECTION_CONTROL */ + return s->dir; + + case 0x0c: /* INTERRUPT_CONTROL */ + return s->edge; + + case 0x10: /* INTERRUPT_MASK */ + return s->mask; + + case 0x14: /* INTERRUPT_STATUS */ + return s->ints; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_gpio_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; + int offset = addr - s->base; + uint16_t diff; + int ln; + + switch (offset) { + case 0x00: /* DATA_INPUT */ + OMAP_RO_REG(addr); + return; + + case 0x04: /* DATA_OUTPUT */ + diff = s->outputs ^ (value & ~s->dir); + s->outputs = value; + value &= ~s->dir; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x08: /* DIRECTION_CONTROL */ + diff = s->outputs & (s->dir ^ value); + s->dir = value; + + value = s->outputs & ~s->dir; + while ((ln = ffs(diff))) { + ln --; + if (s->handler[ln]) + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + diff &= ~(1 << ln); + } + break; + + case 0x0c: /* INTERRUPT_CONTROL */ + s->edge = value; + break; + + case 0x10: /* INTERRUPT_MASK */ + s->mask = value; + break; + + case 0x14: /* INTERRUPT_STATUS */ + s->ints &= ~value; + if (!s->ints) + qemu_irq_lower(s->irq); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_gpio_readfn[] = { + omap_gpio_read, + omap_badwidth_read32, + omap_badwidth_read32, +}; + +static CPUWriteMemoryFunc *omap_gpio_writefn[] = { + omap_gpio_write, + omap_badwidth_write32, + omap_badwidth_write32, +}; + +void omap_gpio_reset(struct omap_gpio_s *s) +{ + s->inputs = 0; + s->outputs = ~0; + s->dir = ~0; + s->edge = ~0; + s->mask = ~0; + s->ints = 0; +} + +struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk) +{ + int iomemtype; + struct omap_gpio_s *s = (struct omap_gpio_s *) + qemu_mallocz(sizeof(struct omap_gpio_s)); + + s->base = base; + s->irq = irq; + s->in = qemu_allocate_irqs(omap_gpio_set, s, 16); + omap_gpio_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_gpio_readfn, + omap_gpio_writefn, s); + cpu_register_physical_memory(s->base, 0x1000, iomemtype); + + return s; +} + +qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s) +{ + return s->in; +} + +void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler) +{ + if (line >= 16 || line < 0) + cpu_abort(cpu_single_env, "%s: No GPIO line %i\n", __FUNCTION__, line); + s->handler[line] = handler; +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -3093,6 +3266,7 @@ static void omap_mpu_reset(void *opaque) omap_uart_reset(mpu->uart3); omap_mmc_reset(mpu->mmc); omap_mpuio_reset(mpu->mpuio); + omap_gpio_reset(mpu->gpio); cpu_reset(mpu->env); } @@ -3208,6 +3382,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], s->wakeup, omap_findclk(s, "clk32-kHz")); + s->gpio = omap_gpio_init(0xfffcf000, s->irq[1][OMAP_INT_KEYBOARD], + omap_findclk(s, "mpuper_ck")); + qemu_register_reset(omap_mpu_reset, s); return s; diff --git a/hw/omap.h b/hw/omap.h index 70888698c..caaca9e69 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -458,6 +458,12 @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s); void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler); void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down); +struct omap_gpio_s; +struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, + qemu_irq irq, omap_clk clk); +qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s); +void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); @@ -574,6 +580,7 @@ struct omap_mpu_state_s { } clkm; struct omap_mpuio_s *mpuio; + struct omap_gpio_s *gpio; } *omap310_mpu_init(unsigned long sdram_size, DisplayState *ds, const char *core); diff --git a/hw/palm.c b/hw/palm.c index ba7e47f9f..1ee05b823 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -158,7 +158,8 @@ static void palmte_init(int ram_size, int vga_ram_size, int boot_device, qemu_add_kbd_event_handler(palmte_button_event, cpu); - omap_mmc_handlers(cpu->mmc, 0, + omap_mmc_handlers(cpu->mmc, + omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO], qemu_allocate_irqs(palmte_mmc_cover, cpu, 1)[0]); /* Setup initial (reset) machine state */ -- cgit v1.2.3 From 897b4c6c4e63afebdd41de0f1a19e17ab1f4c2b8 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 28 Oct 2007 23:33:05 +0000 Subject: Give an opaque to the m48t59 direct access routines to make it easier to use another NVRAM with the same API. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3474 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 14 ++++++++++---- hw/m48t59.h | 6 +++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index da61313f1..34979ad10 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -199,8 +199,9 @@ static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) } /* Direct access to NVRAM */ -void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) +void m48t59_write (void *opaque, uint32_t addr, uint32_t val) { + m48t59_t *NVRAM = opaque; struct tm tm; int tmp; @@ -357,8 +358,9 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) } } -uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) +uint32_t m48t59_read (void *opaque, uint32_t addr) { + m48t59_t *NVRAM = opaque; struct tm tm; uint32_t retval = 0xFF; @@ -451,13 +453,17 @@ uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) return retval; } -void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr) +void m48t59_set_addr (void *opaque, uint32_t addr) { + m48t59_t *NVRAM = opaque; + NVRAM->addr = addr; } -void m48t59_toggle_lock (m48t59_t *NVRAM, int lock) +void m48t59_toggle_lock (void *opaque, int lock) { + m48t59_t *NVRAM = opaque; + NVRAM->lock ^= 1 << lock; } diff --git a/hw/m48t59.h b/hw/m48t59.h index cfe9b2af5..f2eb4b1e3 100644 --- a/hw/m48t59.h +++ b/hw/m48t59.h @@ -3,9 +3,9 @@ typedef struct m48t59_t m48t59_t; -void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val); -uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr); -void m48t59_toggle_lock (m48t59_t *NVRAM, int lock); +void m48t59_write (void *private, uint32_t addr, uint32_t val); +uint32_t m48t59_read (void *private, uint32_t addr); +void m48t59_toggle_lock (void *private, int lock); m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, uint32_t io_base, uint16_t size, int type); -- cgit v1.2.3 From 3cbee15b9a6be17645e908bf7706d582c3e17156 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 28 Oct 2007 23:42:18 +0000 Subject: * sort the PowerPC target object files * make PowerPC NVRAM accessors generic to be able to use a MacIO NVRAM instead of the M48T59 one * split PowerMac targets code: - move all PowerMac related definitions and prototypes into hw/ppc_mac.h - add hw/mac_dbdma.c, hw/mac_nvram.c and macio.c which implements shared PowerMac devices - define the g3bw machine in a new hw/ppc_oldworld.c file * Fix the g3bw target: - fix the Grackle host PCI device - connect the Heathrow PIC to the PowerPC 6xx bus pins git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3475 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 19 +- hw/cuda.c | 12 +- hw/grackle_pci.c | 10 +- hw/heathrow_pic.c | 29 ++- hw/mac_dbdma.c | 79 ++++++++ hw/mac_nvram.c | 123 +++++++++++++ hw/macio.c | 116 ++++++++++++ hw/ppc.c | 67 ++++--- hw/ppc_chrp.c | 540 +++++++++++------------------------------------------- hw/ppc_mac.h | 70 +++++++ hw/ppc_oldworld.c | 298 ++++++++++++++++++++++++++++++ hw/ppc_prep.c | 14 +- vl.h | 43 ++--- 13 files changed, 908 insertions(+), 512 deletions(-) create mode 100644 hw/mac_dbdma.c create mode 100644 hw/mac_nvram.c create mode 100644 hw/macio.c create mode 100644 hw/ppc_mac.h create mode 100644 hw/ppc_oldworld.c diff --git a/Makefile.target b/Makefile.target index cafcc60f0..b6be19d3e 100644 --- a/Makefile.target +++ b/Makefile.target @@ -469,13 +469,20 @@ VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o vmport.o vmware_vga.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 pflash_cfi02.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 -# PowerPC 4xx boards -VL_OBJS+= ppc4xx_devs.o ppc405_uc.o ppc405_boards.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE +# shared objects +VL_OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o $(AUDIODRV) +# PREP target +VL_OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o +VL_OBJS+= prep_pci.o ppc_prep.o +# Mac shared devices +VL_OBJS+= macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o +# OldWorld PowerMac +VL_OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o +# NewWorld PowerMac +VL_OBJS+= unin_pci.o ppc_chrp.o +# PowerPC 4xx boards +VL_OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o endif ifeq ($(TARGET_BASE_ARCH), mips) VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o mips_mipssim.o diff --git a/hw/cuda.c b/hw/cuda.c index 9a05aebb5..42e357e3c 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -1,7 +1,8 @@ /* - * QEMU CUDA support + * QEMU PowerMac CUDA device support * - * Copyright (c) 2004 Fabrice Bellard + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,6 +23,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include "ppc_mac.h" /* XXX: implement all timer modes */ @@ -634,10 +636,9 @@ static CPUReadMemoryFunc *cuda_read[] = { &cuda_readl, }; -int cuda_init(qemu_irq irq) +void cuda_init (int *cuda_mem_index, qemu_irq irq) { CUDAState *s = &cuda_state; - int cuda_mem_index; s->irq = irq; @@ -653,6 +654,5 @@ int cuda_init(qemu_irq irq) set_counter(s, &s->timers[1], 0xffff); s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s); - cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); - return cuda_mem_index; + *cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); } diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index fb4605166..85c434c8e 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -1,7 +1,8 @@ /* - * QEMU Grackle (heathrow PPC) PCI host + * QEMU Grackle PCI host (heathrow OldWorld PowerMac) * - * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2006-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +24,7 @@ */ #include "vl.h" +#include "ppc_mac.h" typedef target_phys_addr_t pci_addr_t; #include "pci_host.h" @@ -82,7 +84,7 @@ static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num) static void pci_grackle_set_irq(qemu_irq *pic, int irq_num, int level) { - qemu_set_irq(pic[irq_num + 8], level); + qemu_set_irq(pic[irq_num + 0x15], level); } PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) @@ -93,7 +95,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) s = qemu_mallocz(sizeof(GrackleState)); s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq, - pic, 0, 0); + pic, 0, 4); pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, pci_grackle_config_write, s); diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index 96eb6565f..44dc97a2d 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -1,7 +1,8 @@ /* - * Heathrow PIC support (standard PowerMac PIC) + * Heathrow PIC support (OldWorld PowerMac) * - * Copyright (c) 2005 Fabrice Bellard + * Copyright (c) 2005-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,6 +23,7 @@ * THE SOFTWARE. */ #include "vl.h" +#include "ppc_mac.h" //#define DEBUG @@ -34,6 +36,7 @@ typedef struct HeathrowPIC { typedef struct HeathrowPICS { HeathrowPIC pics[2]; + qemu_irq *irqs; } HeathrowPICS; static inline int check_irq(HeathrowPIC *pic) @@ -45,9 +48,9 @@ static inline int check_irq(HeathrowPIC *pic) static void heathrow_pic_update(HeathrowPICS *s) { if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) { - cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); + qemu_irq_raise(s->irqs[0]); } else { - cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); + qemu_irq_lower(s->irqs[0]); } } @@ -57,12 +60,13 @@ static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) HeathrowPIC *pic; unsigned int n; +#ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); -#ifdef DEBUG - printf("pic_writel: %08x: %08x\n", - addr, value); #endif n = ((addr & 0xfff) - 0x10) >> 4; +#ifdef DEBUG + printf("pic_writel: " PADDRX " %u: %08x\n", addr, n, value); +#endif if (n >= 2) return; pic = &s->pics[n]; @@ -110,10 +114,11 @@ static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) } } #ifdef DEBUG - printf("pic_readl: %08x: %08x\n", - addr, value); + printf("pic_readl: " PADDRX " %u: %08x\n", addr, n, value); #endif +#ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); +#endif return value; } @@ -156,13 +161,17 @@ static void heathrow_pic_set_irq(void *opaque, int num, int level) heathrow_pic_update(s); } -qemu_irq *heathrow_pic_init(int *pmem_index) +qemu_irq *heathrow_pic_init(int *pmem_index, + int nb_cpus, qemu_irq **irqs) { HeathrowPICS *s; s = qemu_mallocz(sizeof(HeathrowPICS)); s->pics[0].level_triggered = 0; s->pics[1].level_triggered = 0x1ff00000; + /* only 1 CPU */ + s->irqs = irqs[0]; *pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s); + return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64); } diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c new file mode 100644 index 000000000..62c9746e7 --- /dev/null +++ b/hw/mac_dbdma.c @@ -0,0 +1,79 @@ +/* + * PowerMac descriptor-based DMA emulation + * + * Copyright (c) 2005-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "ppc_mac.h" + +/* DBDMA: currently no op - should suffice right now */ + +static void dbdma_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + printf("%s: 0x" PADDRX " <= 0x%08x\n", __func__, addr, value); +} + +static void dbdma_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +} + +static void dbdma_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ +} + +static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) +{ + printf("%s: 0x" PADDRX " => 0x00000000\n", __func__, addr); + + return 0; +} + +static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr) +{ + return 0; +} + +static CPUWriteMemoryFunc *dbdma_write[] = { + &dbdma_writeb, + &dbdma_writew, + &dbdma_writel, +}; + +static CPUReadMemoryFunc *dbdma_read[] = { + &dbdma_readb, + &dbdma_readw, + &dbdma_readl, +}; + +void dbdma_init (int *dbdma_mem_index) +{ + *dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL); +} + diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c new file mode 100644 index 000000000..f8b8d3755 --- /dev/null +++ b/hw/mac_nvram.c @@ -0,0 +1,123 @@ +/* + * PowerMac NVRAM emulation + * + * Copyright (c) 2005-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "ppc_mac.h" + +struct MacIONVRAMState { + uint8_t data[0x2000]; +}; + +/* Direct access to NVRAM */ +uint32_t macio_nvram_read (void *opaque, uint32_t addr) +{ + MacIONVRAMState *s = opaque; + uint32_t ret; + + // printf("%s: %p addr %04x\n", __func__, s, addr); + if (addr < 0x2000) + ret = s->data[addr]; + else + ret = -1; + + return ret; +} + +void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val) +{ + MacIONVRAMState *s = opaque; + + // printf("%s: %p addr %04x val %02x\n", __func__, s, addr, val); + if (addr < 0x2000) + s->data[addr] = val; +} + +/* macio style NVRAM device */ +static void macio_nvram_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + MacIONVRAMState *s = opaque; + addr = (addr >> 4) & 0x1fff; + s->data[addr] = value; + // printf("macio_nvram_writeb %04x = %02x\n", addr, value); +} + +static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr) +{ + MacIONVRAMState *s = opaque; + uint32_t value; + + addr = (addr >> 4) & 0x1fff; + value = s->data[addr]; + // printf("macio_nvram_readb %04x = %02x\n", addr, value); + + return value; +} + +static CPUWriteMemoryFunc *nvram_write[] = { + &macio_nvram_writeb, + &macio_nvram_writeb, + &macio_nvram_writeb, +}; + +static CPUReadMemoryFunc *nvram_read[] = { + &macio_nvram_readb, + &macio_nvram_readb, + &macio_nvram_readb, +}; + +MacIONVRAMState *macio_nvram_init (int *mem_index) +{ + MacIONVRAMState *s; + s = qemu_mallocz(sizeof(MacIONVRAMState)); + if (!s) + return NULL; + *mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + + return s; +} + +static uint8_t nvram_chksum (const uint8_t *buf, int n) +{ + int sum, i; + sum = 0; + for(i = 0; i < n; i++) + sum += buf[i]; + return (sum & 0xff) + (sum >> 8); +} + +/* set a free Mac OS NVRAM partition */ +void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len) +{ + uint8_t *buf; + char partition_name[12] = "wwwwwwwwwwww"; + + buf = nvr->data; + buf[0] = 0x7f; /* free partition magic */ + buf[1] = 0; /* checksum */ + buf[2] = len >> 8; + buf[3] = len; + memcpy(buf + 4, partition_name, 12); + buf[1] = nvram_chksum(buf, 16); +} diff --git a/hw/macio.c b/hw/macio.c new file mode 100644 index 000000000..82e3e9afe --- /dev/null +++ b/hw/macio.c @@ -0,0 +1,116 @@ +/* + * PowerMac MacIO device emulation + * + * Copyright (c) 2005-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "ppc_mac.h" + +typedef struct macio_state_t macio_state_t; +struct macio_state_t { + int is_oldworld; + int pic_mem_index; + int dbdma_mem_index; + int cuda_mem_index; + int nvram_mem_index; + int nb_ide; + int ide_mem_index[4]; +}; + +static void macio_map (PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + macio_state_t *macio_state; + int i; + + macio_state = (macio_state_t *)(pci_dev + 1); + if (macio_state->pic_mem_index >= 0) { + if (macio_state->is_oldworld) { + /* Heathrow PIC */ + cpu_register_physical_memory(addr + 0x00000, 0x1000, + macio_state->pic_mem_index); + } else { + /* OpenPIC */ + cpu_register_physical_memory(addr + 0x40000, 0x40000, + macio_state->pic_mem_index); + } + } + if (macio_state->dbdma_mem_index >= 0) { + cpu_register_physical_memory(addr + 0x08000, 0x1000, + macio_state->dbdma_mem_index); + } + if (macio_state->cuda_mem_index >= 0) { + cpu_register_physical_memory(addr + 0x16000, 0x2000, + macio_state->cuda_mem_index); + } + for (i = 0; i < macio_state->nb_ide; i++) { + if (macio_state->ide_mem_index[i] >= 0) { + cpu_register_physical_memory(addr + 0x1f000 + (i * 0x1000), 0x1000, + macio_state->ide_mem_index[i]); + } + } + if (macio_state->nvram_mem_index >= 0) { + cpu_register_physical_memory(addr + 0x60000, 0x20000, + macio_state->nvram_mem_index); + } +} + +void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, + int dbdma_mem_index, int cuda_mem_index, int nvram_mem_index, + int nb_ide, int *ide_mem_index) +{ + PCIDevice *d; + macio_state_t *macio_state; + int i; + + d = pci_register_device(bus, "macio", + sizeof(PCIDevice) + sizeof(macio_state_t), + -1, NULL, NULL); + macio_state = (macio_state_t *)(d + 1); + macio_state->is_oldworld = is_oldworld; + macio_state->pic_mem_index = pic_mem_index; + macio_state->dbdma_mem_index = dbdma_mem_index; + macio_state->cuda_mem_index = cuda_mem_index; + macio_state->nvram_mem_index = nvram_mem_index; + if (nb_ide > 4) + nb_ide = 4; + macio_state->nb_ide = nb_ide; + for (i = 0; i < nb_ide; i++) + macio_state->ide_mem_index[i] = ide_mem_index[i]; + for (; i < 4; i++) + macio_state->ide_mem_index[i] = -1; + /* Note: this code is strongly inspirated from the corresponding code + in PearPC */ + d->config[0x00] = 0x6b; // vendor_id + d->config[0x01] = 0x10; + d->config[0x02] = device_id; + d->config[0x03] = device_id >> 8; + + d->config[0x0a] = 0x00; // class_sub = pci2pci + d->config[0x0b] = 0xff; // class_base = bridge + d->config[0x0e] = 0x00; // header_type + + d->config[0x3d] = 0x01; // interrupt on pin 1 + + pci_register_io_region(d, 0, 0x80000, + PCI_ADDRESS_SPACE_MEM, macio_map); +} diff --git a/hw/ppc.c b/hw/ppc.c index 742d3de59..8b669071d 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ #include "vl.h" -#include "m48t59.h" //#define PPC_DEBUG_IRQ //#define PPC_DEBUG_TB @@ -1240,63 +1239,75 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) /*****************************************************************************/ /* NVRAM helpers */ -void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) +static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr) { - m48t59_write(nvram, addr, value); + return (*nvram->read_fn)(nvram->opaque, addr);; } -uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) +static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val) { - return m48t59_read(nvram, addr); + (*nvram->write_fn)(nvram->opaque, addr, val); } -void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) +void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value) { - m48t59_write(nvram, addr, value >> 8); - m48t59_write(nvram, addr + 1, value & 0xFF); + nvram_write(nvram, addr, value); } -uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) +uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr) +{ + return nvram_read(nvram, addr); +} + +void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value) +{ + nvram_write(nvram, addr, value >> 8); + nvram_write(nvram, addr + 1, value & 0xFF); +} + +uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr) { uint16_t tmp; - tmp = m48t59_read(nvram, addr) << 8; - tmp |= m48t59_read(nvram, addr + 1); + tmp = nvram_read(nvram, addr) << 8; + tmp |= nvram_read(nvram, addr + 1); + return tmp; } -void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) +void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value) { - m48t59_write(nvram, addr, value >> 24); - m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF); - m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF); - m48t59_write(nvram, addr + 3, value & 0xFF); + nvram_write(nvram, addr, value >> 24); + nvram_write(nvram, addr + 1, (value >> 16) & 0xFF); + nvram_write(nvram, addr + 2, (value >> 8) & 0xFF); + nvram_write(nvram, addr + 3, value & 0xFF); } -uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) +uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr) { uint32_t tmp; - tmp = m48t59_read(nvram, addr) << 24; - tmp |= m48t59_read(nvram, addr + 1) << 16; - tmp |= m48t59_read(nvram, addr + 2) << 8; - tmp |= m48t59_read(nvram, addr + 3); + tmp = nvram_read(nvram, addr) << 24; + tmp |= nvram_read(nvram, addr + 1) << 16; + tmp |= nvram_read(nvram, addr + 2) << 8; + tmp |= nvram_read(nvram, addr + 3); return tmp; } -void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, +void NVRAM_set_string (nvram_t *nvram, uint32_t addr, const unsigned char *str, uint32_t max) { int i; for (i = 0; i < max && str[i] != '\0'; i++) { - m48t59_write(nvram, addr + i, str[i]); + nvram_write(nvram, addr + i, str[i]); } - m48t59_write(nvram, addr + max - 1, '\0'); + nvram_write(nvram, addr + i, str[i]); + nvram_write(nvram, addr + max - 1, '\0'); } -int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) +int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max) { int i; @@ -1325,7 +1336,7 @@ static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) return tmp; } -uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) +uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count) { uint32_t i; uint16_t crc = 0xFFFF; @@ -1345,7 +1356,7 @@ uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) #define CMDLINE_ADDR 0x017ff000 -int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, +int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, const unsigned char *arch, uint32_t RAM_size, int boot_device, uint32_t kernel_image, uint32_t kernel_size, @@ -1382,7 +1393,7 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, NVRAM_set_word(nvram, 0x56, height); NVRAM_set_word(nvram, 0x58, depth); crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); - NVRAM_set_word(nvram, 0xFC, crc); + NVRAM_set_word(nvram, 0xFC, crc); return 0; } diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index f53c85b85..f71169e53 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -1,7 +1,8 @@ /* - * QEMU PPC CHRP/PMAC hardware System Emulator + * QEMU PowerPC CHRP (currently NewWorld PowerMac) hardware System Emulator * * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,171 +23,7 @@ * THE SOFTWARE. */ #include "vl.h" - -/* SMP is not enabled, for now */ -#define MAX_CPUS 1 - -#define BIOS_FILENAME "ppc_rom.bin" -#define VGABIOS_FILENAME "video.x" -#define NVRAM_SIZE 0x2000 - -#define KERNEL_LOAD_ADDR 0x01000000 -#define INITRD_LOAD_ADDR 0x01800000 - -/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA, - NVRAM */ - -static int dbdma_mem_index; -static int cuda_mem_index; -static int ide0_mem_index = -1; -static int ide1_mem_index = -1; -static int openpic_mem_index = -1; -static int heathrow_pic_mem_index = -1; -static int macio_nvram_mem_index = -1; - -/* DBDMA: currently no op - should suffice right now */ - -static void dbdma_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ - printf("%s: 0x" PADDRX " <= 0x%08x\n", __func__, addr, value); -} - -static void dbdma_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ -} - -static void dbdma_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ -} - -static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) -{ - printf("%s: 0x" PADDRX " => 0x00000000\n", __func__, addr); - - return 0; -} - -static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static CPUWriteMemoryFunc *dbdma_write[] = { - &dbdma_writeb, - &dbdma_writew, - &dbdma_writel, -}; - -static CPUReadMemoryFunc *dbdma_read[] = { - &dbdma_readb, - &dbdma_readw, - &dbdma_readl, -}; - -/* macio style NVRAM device */ -typedef struct MacIONVRAMState { - uint8_t data[0x2000]; -} MacIONVRAMState; - -static void macio_nvram_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ - MacIONVRAMState *s = opaque; - addr = (addr >> 4) & 0x1fff; - s->data[addr] = value; - // printf("macio_nvram_writeb %04x = %02x\n", addr, value); -} - -static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr) -{ - MacIONVRAMState *s = opaque; - uint32_t value; - - addr = (addr >> 4) & 0x1fff; - value = s->data[addr]; - // printf("macio_nvram_readb %04x = %02x\n", addr, value); - - return value; -} - -static CPUWriteMemoryFunc *macio_nvram_write[] = { - &macio_nvram_writeb, - &macio_nvram_writeb, - &macio_nvram_writeb, -}; - -static CPUReadMemoryFunc *macio_nvram_read[] = { - &macio_nvram_readb, - &macio_nvram_readb, - &macio_nvram_readb, -}; - -static MacIONVRAMState *macio_nvram_init (void) -{ - MacIONVRAMState *s; - s = qemu_mallocz(sizeof(MacIONVRAMState)); - if (!s) - return NULL; - macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read, - macio_nvram_write, s); - - return s; -} - -static void macio_map (PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - if (heathrow_pic_mem_index >= 0) { - cpu_register_physical_memory(addr + 0x00000, 0x1000, - heathrow_pic_mem_index); - } - cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index); - cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index); - if (ide0_mem_index >= 0) - cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index); - if (ide1_mem_index >= 0) - cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); - if (openpic_mem_index >= 0) { - cpu_register_physical_memory(addr + 0x40000, 0x40000, - openpic_mem_index); - } - if (macio_nvram_mem_index >= 0) - cpu_register_physical_memory(addr + 0x60000, 0x20000, - macio_nvram_mem_index); -} - -static void macio_init (PCIBus *bus, int device_id) -{ - PCIDevice *d; - - d = pci_register_device(bus, "macio", sizeof(PCIDevice), - -1, NULL, NULL); - /* Note: this code is strongly inspirated from the corresponding code - in PearPC */ - d->config[0x00] = 0x6b; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = device_id; - d->config[0x03] = device_id >> 8; - - d->config[0x0a] = 0x00; // class_sub = pci2pci - d->config[0x0b] = 0xff; // class_base = bridge - d->config[0x0e] = 0x00; // header_type - - d->config[0x3d] = 0x01; // interrupt on pin 1 - - dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL); - - pci_register_io_region(d, 0, 0x80000, - PCI_ADDRESS_SPACE_MEM, macio_map); -} +#include "ppc_mac.h" /* UniN device */ static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value) @@ -210,118 +47,34 @@ static CPUReadMemoryFunc *unin_read[] = { &unin_readl, }; -/* temporary frame buffer OSI calls for the video.x driver. The right - solution is to modify the driver to use VGA PCI I/Os */ -/* XXX: to be removed. This is no way related to emulation */ -static int vga_osi_call (CPUState *env) -{ - static int vga_vbl_enabled; - int linesize; - - // printf("osi_call R5=%d\n", env->gpr[5]); - - /* same handler as PearPC, coming from the original MOL video - driver. */ - switch(env->gpr[5]) { - case 4: - break; - case 28: /* set_vmode */ - if (env->gpr[6] != 1 || env->gpr[7] != 0) - env->gpr[3] = 1; - else - env->gpr[3] = 0; - break; - case 29: /* get_vmode_info */ - if (env->gpr[6] != 0) { - if (env->gpr[6] != 1 || env->gpr[7] != 0) { - env->gpr[3] = 1; - break; - } - } - env->gpr[3] = 0; - env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */ - env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */ - env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */ - env->gpr[7] = 85 << 16; /* refresh rate */ - env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */ - linesize = ((graphic_depth + 7) >> 3) * graphic_width; - linesize = (linesize + 3) & ~3; - env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */ - break; - case 31: /* set_video power */ - env->gpr[3] = 0; - break; - case 39: /* video_ctrl */ - if (env->gpr[6] == 0 || env->gpr[6] == 1) - vga_vbl_enabled = env->gpr[6]; - env->gpr[3] = 0; - break; - case 47: - break; - case 59: /* set_color */ - /* R6 = index, R7 = RGB */ - env->gpr[3] = 0; - break; - case 64: /* get color */ - /* R6 = index */ - env->gpr[3] = 0; - break; - case 116: /* set hwcursor */ - /* R6 = x, R7 = y, R8 = visible, R9 = data */ - break; - default: - fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]); - break; - } - - return 1; /* osi_call handled */ -} - -static uint8_t nvram_chksum (const uint8_t *buf, int n) -{ - int sum, i; - sum = 0; - for(i = 0; i < n; i++) - sum += buf[i]; - return (sum & 0xff) + (sum >> 8); -} - -/* set a free Mac OS NVRAM partition */ -void pmac_format_nvram_partition (uint8_t *buf, int len) -{ - char partition_name[12] = "wwwwwwwwwwww"; - - buf[0] = 0x7f; /* free partition magic */ - buf[1] = 0; /* checksum */ - buf[2] = len >> 8; - buf[3] = len; - memcpy(buf + 4, partition_name, 12); - buf[1] = nvram_chksum(buf, 16); -} - -/* PowerPC CHRP hardware initialisation */ -static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model, - int is_heathrow) +/* PowerPC Mac99 hardware initialisation */ +static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) { CPUState *env, *envs[MAX_CPUS]; char buf[1024]; qemu_irq *pic, **openpic_irqs; - m48t59_t *nvram; int unin_memory; int linux_boot, i; unsigned long bios_offset, vga_bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; ppc_def_t *def; PCIBus *pci_bus; - const char *arch_name; + nvram_t nvram; +#if 0 + MacIONVRAMState *nvr; + int nvram_mem_index; +#endif + m48t59_t *m48t59; int vga_bios_size, bios_size; qemu_irq *dummy_irq; + int pic_mem_index, dbdma_mem_index, cuda_mem_index; + int ide_mem_index[2]; linux_boot = (kernel_filename != NULL); @@ -338,7 +91,9 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, cpu_ppc_reset(env); /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); +#if 0 env->osi_call = vga_osi_call; +#endif qemu_register_reset(&cpu_ppc_reset, env); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); envs[i] = env; @@ -413,143 +168,91 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, initrd_size = 0; } - if (is_heathrow) { - isa_mem_base = 0x80000000; - - /* Register 2 MB of ISA IO space */ - isa_mmio_init(0xfe000000, 0x00200000); + isa_mem_base = 0x80000000; - /* init basic PC hardware */ - if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { - cpu_abort(env, "Only 6xx bus is supported on heathrow machine\n"); - exit(1); - } - pic = heathrow_pic_init(&heathrow_pic_mem_index); - pci_bus = pci_grackle_init(0xfec00000, pic); - pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, - ram_size, vga_ram_size, - vga_bios_offset, vga_bios_size); - - /* XXX: suppress that */ - dummy_irq = i8259_init(NULL); - - /* XXX: use Mac Serial port */ - serial_init(0x3f8, dummy_irq[4], serial_hds[0]); - - for(i = 0; i < nb_nics; i++) { - if (!nd_table[i].model) - nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i], -1); - } + /* Register 8 MB of ISA IO space */ + isa_mmio_init(0xf2000000, 0x00800000); - pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); - - /* cuda also initialize ADB */ - cuda_mem_index = cuda_init(pic[0x12]); - - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); - - { - MacIONVRAMState *nvr; - nvr = macio_nvram_init(); - pmac_format_nvram_partition(nvr->data, 0x2000); - } - - macio_init(pci_bus, 0x0017); - - nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59); - - arch_name = "HEATHROW"; - } else { - isa_mem_base = 0x80000000; + /* UniN init */ + unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); + cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); - /* Register 8 MB of ISA IO space */ - isa_mmio_init(0xf2000000, 0x00800000); - - /* UniN init */ - unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); - cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); - - openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *)); - openpic_irqs[0] = - qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); - for (i = 0; i < smp_cpus; i++) { - /* Mac99 IRQ connection between OpenPIC outputs pins - * and PowerPC input pins - */ - switch (PPC_INPUT(env)) { - case PPC_FLAGS_INPUT_6xx: - openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); - openpic_irqs[i][OPENPIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; - openpic_irqs[i][OPENPIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; - openpic_irqs[i][OPENPIC_OUTPUT_MCK] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP]; - /* Not connected ? */ - openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; - /* Check this */ - openpic_irqs[i][OPENPIC_OUTPUT_RESET] = - ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET]; - break; + openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *)); + openpic_irqs[0] = + qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); + for (i = 0; i < smp_cpus; i++) { + /* Mac99 IRQ connection between OpenPIC outputs pins + * and PowerPC input pins + */ + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_6xx: + openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); + openpic_irqs[i][OPENPIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_MCK] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP]; + /* Not connected ? */ + openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; + /* Check this */ + openpic_irqs[i][OPENPIC_OUTPUT_RESET] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET]; + break; #if defined(TARGET_PPC64) - case PPC_FLAGS_INPUT_970: - openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); - openpic_irqs[i][OPENPIC_OUTPUT_INT] = - ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT]; - openpic_irqs[i][OPENPIC_OUTPUT_CINT] = - ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT]; - openpic_irqs[i][OPENPIC_OUTPUT_MCK] = - ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP]; - /* Not connected ? */ - openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; - /* Check this */ - openpic_irqs[i][OPENPIC_OUTPUT_RESET] = - ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET]; - break; + case PPC_FLAGS_INPUT_970: + openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); + openpic_irqs[i][OPENPIC_OUTPUT_INT] = + ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_CINT] = + ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT]; + openpic_irqs[i][OPENPIC_OUTPUT_MCK] = + ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP]; + /* Not connected ? */ + openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; + /* Check this */ + openpic_irqs[i][OPENPIC_OUTPUT_RESET] = + ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET]; + break; #endif /* defined(TARGET_PPC64) */ - default: - cpu_abort(env, "Bus model not supported on mac99 machine\n"); - exit(1); - } - } - pic = openpic_init(NULL, &openpic_mem_index, smp_cpus, - openpic_irqs, NULL); - pci_bus = pci_pmac_init(pic); - /* init basic PC hardware */ - pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, - ram_size, vga_ram_size, - vga_bios_offset, vga_bios_size); - - /* XXX: suppress that */ - dummy_irq = i8259_init(NULL); - - /* XXX: use Mac Serial port */ - serial_init(0x3f8, dummy_irq[4], serial_hds[0]); - for(i = 0; i < nb_nics; i++) { - if (!nd_table[i].model) - nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i], -1); + default: + cpu_abort(env, "Bus model not supported on mac99 machine\n"); + exit(1); } + } + pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL); + pci_bus = pci_pmac_init(pic); + /* init basic PC hardware */ + pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, + ram_size, vga_ram_size, + vga_bios_offset, vga_bios_size); + + /* XXX: suppress that */ + dummy_irq = i8259_init(NULL); + + /* XXX: use Mac Serial port */ + serial_init(0x3f8, dummy_irq[4], serial_hds[0]); + for(i = 0; i < nb_nics; i++) { + if (!nd_table[i].model) + nd_table[i].model = "ne2k_pci"; + pci_nic_init(pci_bus, &nd_table[i], -1); + } #if 1 - ide0_mem_index = pmac_ide_init(&bs_table[0], pic[0x13]); - ide1_mem_index = pmac_ide_init(&bs_table[2], pic[0x14]); + ide_mem_index[0] = pmac_ide_init(&bs_table[0], pic[0x13]); + ide_mem_index[1] = pmac_ide_init(&bs_table[2], pic[0x14]); #else - pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); + pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); #endif - /* cuda also initialize ADB */ - cuda_mem_index = cuda_init(pic[0x19]); - - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); - - macio_init(pci_bus, 0x0022); + /* cuda also initialize ADB */ + cuda_init(&cuda_mem_index, pic[0x19]); + + adb_kbd_init(&adb_bus); + adb_mouse_init(&adb_bus); - nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59); + dbdma_init(&dbdma_mem_index); - arch_name = "MAC99"; - } + macio_init(pci_bus, 0x0022, 0, pic_mem_index, dbdma_mem_index, + cuda_mem_index, -1, 2, ide_mem_index); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); @@ -557,8 +260,21 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) graphic_depth = 15; - - PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device, +#if 0 /* XXX: this is ugly but needed for now, or OHW won't boot */ + /* The NewWorld NVRAM is not located in the MacIO device */ + nvr = macio_nvram_init(&nvram_mem_index); + pmac_format_nvram_partition(nvr, 0x2000); + cpu_register_physical_memory(0xFFF04000, 0x20000, nvram_mem_index); + nvram.opaque = nvr; + nvram.read_fn = &macio_nvram_read; + nvram.write_fn = &macio_nvram_write; +#else + m48t59 = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59); + nvram.opaque = m48t59; + nvram.read_fn = &m48t59_read; + nvram.write_fn = &m48t59_write; +#endif + PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "MAC99", ram_size, boot_device, kernel_base, kernel_size, kernel_cmdline, initrd_base, initrd_size, @@ -569,44 +285,10 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device, /* Special port to get debug messages from Open-Firmware */ register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); -} - -static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) -{ - ppc_chrp_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 0); -} - -static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) -{ - ppc_chrp_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 1); -} + } QEMUMachine core99_machine = { "mac99", "Mac99 based PowerMAC", ppc_core99_init, }; - -QEMUMachine heathrow_machine = { - "g3bw", - "Heathrow based PowerMAC", - ppc_heathrow_init, -}; diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h new file mode 100644 index 000000000..0ff80aba1 --- /dev/null +++ b/hw/ppc_mac.h @@ -0,0 +1,70 @@ +/* + * QEMU PowerMac emulation shared definitions and prototypes + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#if !defined(__PPC_MAC_H__) +#define __PPC_MAC_H__ + +/* SMP is not enabled, for now */ +#define MAX_CPUS 1 + +#define BIOS_FILENAME "ppc_rom.bin" +#define VGABIOS_FILENAME "video.x" +#define NVRAM_SIZE 0x2000 + +#define KERNEL_LOAD_ADDR 0x01000000 +#define INITRD_LOAD_ADDR 0x01800000 + +/* DBDMA */ +void dbdma_init (int *dbdma_mem_index); + +/* Cuda */ +void cuda_init (int *cuda_mem_index, qemu_irq irq); + +/* MacIO */ +void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, + int dbdma_mem_index, int cuda_mem_index, int nvram_mem_index, + int nb_ide, int *ide_mem_index); + +/* NewWorld PowerMac IDE */ +int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq); + +/* Heathrow PIC */ +qemu_irq *heathrow_pic_init(int *pmem_index, + int nb_cpus, qemu_irq **irqs); + +/* Grackle PCI */ +PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic); + +/* UniNorth PCI */ +PCIBus *pci_pmac_init(qemu_irq *pic); + +/* Mac NVRAM */ +typedef struct MacIONVRAMState MacIONVRAMState; + +MacIONVRAMState *macio_nvram_init (int *mem_index); +void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); +uint32_t macio_nvram_read (void *opaque, uint32_t addr); +void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val); + +#endif /* !defined(__PPC_MAC_H__) */ diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c new file mode 100644 index 000000000..1c25344a7 --- /dev/null +++ b/hw/ppc_oldworld.c @@ -0,0 +1,298 @@ +/* + * QEMU OldWorld PowerMac (currently ~G3 B&W) hardware System Emulator + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "ppc_mac.h" + +/* temporary frame buffer OSI calls for the video.x driver. The right + solution is to modify the driver to use VGA PCI I/Os */ +/* XXX: to be removed. This is no way related to emulation */ +static int vga_osi_call (CPUState *env) +{ + static int vga_vbl_enabled; + int linesize; + + // printf("osi_call R5=%d\n", env->gpr[5]); + + /* same handler as PearPC, coming from the original MOL video + driver. */ + switch(env->gpr[5]) { + case 4: + break; + case 28: /* set_vmode */ + if (env->gpr[6] != 1 || env->gpr[7] != 0) + env->gpr[3] = 1; + else + env->gpr[3] = 0; + break; + case 29: /* get_vmode_info */ + if (env->gpr[6] != 0) { + if (env->gpr[6] != 1 || env->gpr[7] != 0) { + env->gpr[3] = 1; + break; + } + } + env->gpr[3] = 0; + env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */ + env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */ + env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */ + env->gpr[7] = 85 << 16; /* refresh rate */ + env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */ + linesize = ((graphic_depth + 7) >> 3) * graphic_width; + linesize = (linesize + 3) & ~3; + env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */ + break; + case 31: /* set_video power */ + env->gpr[3] = 0; + break; + case 39: /* video_ctrl */ + if (env->gpr[6] == 0 || env->gpr[6] == 1) + vga_vbl_enabled = env->gpr[6]; + env->gpr[3] = 0; + break; + case 47: + break; + case 59: /* set_color */ + /* R6 = index, R7 = RGB */ + env->gpr[3] = 0; + break; + case 64: /* get color */ + /* R6 = index */ + env->gpr[3] = 0; + break; + case 116: /* set hwcursor */ + /* R6 = x, R7 = y, R8 = visible, R9 = data */ + break; + default: + fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]); + break; + } + + return 1; /* osi_call handled */ +} + +static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + CPUState *env, *envs[MAX_CPUS]; + char buf[1024]; + qemu_irq *pic, **heathrow_irqs; + nvram_t nvram; + m48t59_t *m48t59; + int linux_boot, i; + unsigned long bios_offset, vga_bios_offset; + uint32_t kernel_base, kernel_size, initrd_base, initrd_size; + ppc_def_t *def; + PCIBus *pci_bus; + MacIONVRAMState *nvr; + int vga_bios_size, bios_size; + qemu_irq *dummy_irq; + int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index; + + linux_boot = (kernel_filename != NULL); + + /* init CPUs */ + env = cpu_init(); + if (cpu_model == NULL) + cpu_model = "default"; + ppc_find_by_name(cpu_model, &def); + if (def == NULL) { + cpu_abort(env, "Unable to find PowerPC CPU definition\n"); + } + for (i = 0; i < smp_cpus; i++) { + cpu_ppc_register(env, def); + cpu_ppc_reset(env); + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + env->osi_call = vga_osi_call; + qemu_register_reset(&cpu_ppc_reset, env); + register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); + envs[i] = env; + } + + /* allocate RAM */ + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + /* allocate and load BIOS */ + bios_offset = ram_size + vga_ram_size; + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); + bios_size = load_image(buf, phys_ram_base + bios_offset); + if (bios_size < 0 || bios_size > BIOS_SIZE) { + cpu_abort(env, "qemu: could not load PowerPC bios '%s'\n", buf); + exit(1); + } + bios_size = (bios_size + 0xfff) & ~0xfff; + cpu_register_physical_memory((uint32_t)(-bios_size), + bios_size, bios_offset | IO_MEM_ROM); + + /* allocate and load VGA BIOS */ + vga_bios_offset = bios_offset + bios_size; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); + vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8); + if (vga_bios_size < 0) { + /* if no bios is present, we can still work */ + fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf); + vga_bios_size = 0; + } else { + /* set a specific header (XXX: find real Apple format for NDRV + drivers) */ + phys_ram_base[vga_bios_offset] = 'N'; + phys_ram_base[vga_bios_offset + 1] = 'D'; + phys_ram_base[vga_bios_offset + 2] = 'R'; + phys_ram_base[vga_bios_offset + 3] = 'V'; + cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4), + vga_bios_size); + vga_bios_size += 8; + } + vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff; + + if (linux_boot) { + kernel_base = KERNEL_LOAD_ADDR; + /* now we can load the kernel */ + kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); + if (kernel_size < 0) { + cpu_abort(env, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + /* load initrd */ + if (initrd_filename) { + initrd_base = INITRD_LOAD_ADDR; + initrd_size = load_image(initrd_filename, + phys_ram_base + initrd_base); + if (initrd_size < 0) { + cpu_abort(env, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } else { + initrd_base = 0; + initrd_size = 0; + } + boot_device = 'm'; + } else { + kernel_base = 0; + kernel_size = 0; + initrd_base = 0; + initrd_size = 0; + } + + isa_mem_base = 0x80000000; + + /* Register 2 MB of ISA IO space */ + isa_mmio_init(0xfe000000, 0x00200000); + + /* XXX: we register only 1 output pin for heathrow PIC */ + heathrow_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *)); + heathrow_irqs[0] = + qemu_mallocz(smp_cpus * sizeof(qemu_irq) * 1); + /* Connect the heathrow PIC outputs to the 6xx bus */ + for (i = 0; i < smp_cpus; i++) { + switch (PPC_INPUT(env)) { + case PPC_FLAGS_INPUT_6xx: + heathrow_irqs[i] = heathrow_irqs[0] + (i * 1); + heathrow_irqs[i][0] = + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]; + break; + default: + cpu_abort(env, "Bus model not supported on OldWorld Mac machine\n"); + exit(1); + } + } + + /* init basic PC hardware */ + if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { + cpu_abort(env, "Only 6xx bus is supported on heathrow machine\n"); + exit(1); + } + pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs); + pci_bus = pci_grackle_init(0xfec00000, pic); + pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, + ram_size, vga_ram_size, + vga_bios_offset, vga_bios_size); + + /* XXX: suppress that */ + dummy_irq = i8259_init(NULL); + + /* XXX: use Mac Serial port */ + serial_init(0x3f8, dummy_irq[4], serial_hds[0]); + + for(i = 0; i < nb_nics; i++) { + if (!nd_table[i].model) + nd_table[i].model = "ne2k_pci"; + pci_nic_init(pci_bus, &nd_table[i], -1); + } + + pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); + + /* cuda also initialize ADB */ + cuda_init(&cuda_mem_index, pic[0x12]); + + adb_kbd_init(&adb_bus); + adb_mouse_init(&adb_bus); + + nvr = macio_nvram_init(&nvram_mem_index); + pmac_format_nvram_partition(nvr, 0x2000); + + dbdma_init(&dbdma_mem_index); + + macio_init(pci_bus, 0x0017, 1, pic_mem_index, dbdma_mem_index, + cuda_mem_index, nvram_mem_index, 0, NULL); + + if (usb_enabled) { + usb_ohci_init_pci(pci_bus, 3, -1); + } + + if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) + graphic_depth = 15; + + m48t59 = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59); + nvram.opaque = m48t59; + nvram.read_fn = &m48t59_read; + nvram.write_fn = &m48t59_write; + PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "HEATHROW", ram_size, boot_device, + kernel_base, kernel_size, + kernel_cmdline, + initrd_base, initrd_size, + /* XXX: need an option to load a NVRAM image */ + 0, + graphic_width, graphic_height, graphic_depth); + /* No PCI init: the BIOS will do it */ + + /* Special port to get debug messages from Open-Firmware */ + register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); +} + +QEMUMachine heathrow_machine = { + "g3bw", + "Heathrow based PowerMAC", + ppc_heathrow_init, +}; diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 7cb92c77f..966617fe4 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -527,7 +527,8 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, { CPUState *env, *envs[MAX_CPUS]; char buf[1024]; - m48t59_t *nvram; + nvram_t nvram; + m48t59_t *m48t59; int PPC_io_memory; int linux_boot, i, nb_nics1, bios_size; unsigned long bios_offset; @@ -678,13 +679,16 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, usb_ohci_init_pci(pci_bus, 3, -1); } - nvram = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59); - if (nvram == NULL) + m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59); + if (m48t59 == NULL) return; - sysctrl->nvram = nvram; + sysctrl->nvram = m48t59; /* Initialise NVRAM */ - PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, + nvram.opaque = m48t59; + nvram.read_fn = &m48t59_read; + nvram.write_fn = &m48t59_write; + PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, kernel_base, kernel_size, kernel_cmdline, initrd_base, initrd_size, diff --git a/vl.h b/vl.h index 681dd91ab..5a7f74fc3 100644 --- a/vl.h +++ b/vl.h @@ -859,12 +859,6 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, /* prep_pci.c */ PCIBus *pci_prep_init(qemu_irq *pic); -/* grackle_pci.c */ -PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic); - -/* unin_pci.c */ -PCIBus *pci_pmac_init(qemu_irq *pic); - /* apb_pci.c */ PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base, qemu_irq *pic); @@ -892,9 +886,6 @@ enum { qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, qemu_irq **irqs, qemu_irq irq_out); -/* heathrow_pic.c */ -qemu_irq *heathrow_pic_init(int *pmem_index); - /* gt64xxx.c */ PCIBus *pci_gt64120_init(qemu_irq *pic); @@ -1004,7 +995,6 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, qemu_irq *pic); void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, qemu_irq *pic); -int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq); /* cdrom.c */ int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); @@ -1242,12 +1232,12 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq); void ppc40x_core_reset (CPUState *env); void ppc40x_chip_reset (CPUState *env); void ppc40x_system_reset (CPUState *env); -#endif void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); extern CPUWriteMemoryFunc *PPC_io_write[]; extern CPUReadMemoryFunc *PPC_io_read[]; void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); +#endif /* sun4m.c */ extern QEMUMachine ss5_machine, ss10_machine; @@ -1327,20 +1317,28 @@ void cs_init(target_phys_addr_t base, int irq, void *intctl); extern QEMUMachine sun4u_machine; /* NVRAM helpers */ +typedef uint32_t (*nvram_read_t)(void *private, uint32_t addr); +typedef void (*nvram_write_t)(void *private, uint32_t addr, uint32_t val); +typedef struct nvram_t { + void *opaque; + nvram_read_t read_fn; + nvram_write_t write_fn; +} nvram_t; + #include "hw/m48t59.h" -void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value); -uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr); -void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value); -uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr); -void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value); -uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr); -void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, +void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value); +uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr); +void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value); +uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr); +void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value); +uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr); +void NVRAM_set_string (nvram_t *nvram, uint32_t addr, const unsigned char *str, uint32_t max); -int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max); -void NVRAM_set_crc (m48t59_t *nvram, uint32_t addr, +int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max); +void NVRAM_set_crc (nvram_t *nvram, uint32_t addr, uint32_t start, uint32_t count); -int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, +int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, const unsigned char *arch, uint32_t RAM_size, int boot_device, uint32_t kernel_image, uint32_t kernel_size, @@ -1388,10 +1386,7 @@ ADBDevice *adb_register_device(ADBBusState *s, int devaddr, void adb_kbd_init(ADBBusState *bus); void adb_mouse_init(ADBBusState *bus); -/* cuda.c */ - extern ADBBusState adb_bus; -int cuda_init(qemu_irq irq); #include "hw/usb.h" -- cgit v1.2.3 From 1b6fd0bc551969c61f94f13cbcb013269ee3a07c Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 29 Oct 2007 00:49:32 +0000 Subject: Restrict CP0_PerfCnt to legal values. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3476 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op.c b/target-mips/op.c index f29134567..569c2f2a9 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1971,7 +1971,7 @@ void op_mtc0_depc (void) void op_mtc0_performance0 (void) { - env->CP0_Performance0 = T0; /* XXX */ + env->CP0_Performance0 = T0 & 0x000007ff; RETURN(); } -- cgit v1.2.3 From d951f6ff3fff1121e8b20e7655cb88b2601b61e6 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 29 Oct 2007 01:50:05 +0000 Subject: Implement OMAP MicroWire controller. Fix GPIO interrupt number. Reorder a couple of variables. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3477 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/omap.h | 25 ++++++--- hw/palm.c | 3 +- 3 files changed, 200 insertions(+), 16 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index a2a18a406..cfb7d2bfe 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -3101,7 +3101,6 @@ static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) { struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; int offset = addr - s->base; - uint16_t ret; switch (offset) { case 0x00: /* DATA_INPUT */ @@ -3238,6 +3237,175 @@ void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler) s->handler[line] = handler; } +/* MicroWire Interface */ +struct omap_uwire_s { + target_phys_addr_t base; + qemu_irq txirq; + qemu_irq rxirq; + qemu_irq txdrq; + + uint16_t txbuf; + uint16_t rxbuf; + uint16_t control; + uint16_t setup[5]; + + struct uwire_slave_s *chip[4]; +}; + +static void omap_uwire_transfer_start(struct omap_uwire_s *s) +{ + int chipselect = (s->control >> 10) & 3; /* INDEX */ + struct uwire_slave_s *slave = s->chip[chipselect]; + + if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ + if (s->control & (1 << 12)) /* CS_CMD */ + if (slave && slave->send) + slave->send(slave->opaque, + s->txbuf >> (16 - ((s->control >> 5) & 0x1f))); + s->control &= ~(1 << 14); /* CSRB */ + /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or + * a DRQ. When is the level IRQ supposed to be reset? */ + } + + if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ + if (s->control & (1 << 12)) /* CS_CMD */ + if (slave && slave->receive) + s->rxbuf = slave->receive(slave->opaque); + s->control |= 1 << 15; /* RDRB */ + /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or + * a DRQ. When is the level IRQ supposed to be reset? */ + } +} + +static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* RDR */ + s->control &= ~(1 << 15); /* RDRB */ + return s->rxbuf; + + case 0x04: /* CSR */ + return s->control; + + case 0x08: /* SR1 */ + return s->setup[0]; + case 0x0c: /* SR2 */ + return s->setup[1]; + case 0x10: /* SR3 */ + return s->setup[2]; + case 0x14: /* SR4 */ + return s->setup[3]; + case 0x18: /* SR5 */ + return s->setup[4]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_uwire_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* TDR */ + s->txbuf = value; /* TD */ + s->control |= 1 << 14; /* CSRB */ + if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ + ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ + (s->control & (1 << 12)))) /* CS_CMD */ + omap_uwire_transfer_start(s); + break; + + case 0x04: /* CSR */ + s->control = value & 0x1fff; + if (value & (1 << 13)) /* START */ + omap_uwire_transfer_start(s); + break; + + case 0x08: /* SR1 */ + s->setup[0] = value & 0x003f; + break; + + case 0x0c: /* SR2 */ + s->setup[1] = value & 0x0fc0; + break; + + case 0x10: /* SR3 */ + s->setup[2] = value & 0x0003; + break; + + case 0x14: /* SR4 */ + s->setup[3] = value & 0x0001; + break; + + case 0x18: /* SR5 */ + s->setup[4] = value & 0x000f; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_uwire_readfn[] = { + omap_badwidth_read16, + omap_uwire_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_uwire_writefn[] = { + omap_badwidth_write16, + omap_uwire_write, + omap_badwidth_write16, +}; + +void omap_uwire_reset(struct omap_uwire_s *s) +{ + s->control= 0; + s->setup[0] = 0; + s->setup[1] = 0; + s->setup[2] = 0; + s->setup[3] = 0; + s->setup[4] = 0; +} + +struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, + qemu_irq *irq, qemu_irq dma, omap_clk clk) +{ + int iomemtype; + struct omap_uwire_s *s = (struct omap_uwire_s *) + qemu_mallocz(sizeof(struct omap_uwire_s)); + + s->base = base; + s->txirq = irq[0]; + s->rxirq = irq[1]; + s->txdrq = dma; + omap_uwire_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_uwire_readfn, + omap_uwire_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +void omap_uwire_attach(struct omap_uwire_s *s, + struct uwire_slave_s *slave, int chipselect) +{ + if (chipselect < 0 || chipselect > 3) + cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n", __FUNCTION__, + chipselect); + + s->chip[chipselect] = slave; +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -3261,12 +3429,13 @@ static void omap_mpu_reset(void *opaque) omap_dpll_reset(&mpu->dpll[0]); omap_dpll_reset(&mpu->dpll[1]); omap_dpll_reset(&mpu->dpll[2]); - omap_uart_reset(mpu->uart1); - omap_uart_reset(mpu->uart2); - omap_uart_reset(mpu->uart3); + omap_uart_reset(mpu->uart[0]); + omap_uart_reset(mpu->uart[1]); + omap_uart_reset(mpu->uart[2]); omap_mmc_reset(mpu->mmc); omap_mpuio_reset(mpu->mpuio); omap_gpio_reset(mpu->gpio); + omap_uwire_reset(mpu->microwire); cpu_reset(mpu->env); } @@ -3361,13 +3530,13 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_tcmi_init(0xfffecc00, s); - s->uart1 = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], + s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], omap_findclk(s, "uart1_ck"), serial_hds[0]); - s->uart2 = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2], + s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2], omap_findclk(s, "uart2_ck"), serial_hds[0] ? serial_hds[1] : 0); - s->uart3 = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3], + s->uart[2] = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3], omap_findclk(s, "uart3_ck"), serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0); @@ -3382,9 +3551,12 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], s->wakeup, omap_findclk(s, "clk32-kHz")); - s->gpio = omap_gpio_init(0xfffcf000, s->irq[1][OMAP_INT_KEYBOARD], + s->gpio = omap_gpio_init(0xfffcf000, s->irq[0][OMAP_INT_GPIO_BANK1], omap_findclk(s, "mpuper_ck")); + s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], + s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); + qemu_register_reset(omap_mpu_reset, s); return s; diff --git a/hw/omap.h b/hw/omap.h index caaca9e69..e19f8ac7c 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -464,6 +464,17 @@ struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s); void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler); +struct uwire_slave_s { + uint16_t (*receive)(void *opaque); + void (*send)(void *opaque, uint16_t data); + void *opaque; +}; +struct omap_uwire_s; +struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, + qemu_irq *irq, qemu_irq dma, omap_clk clk); +void omap_uwire_attach(struct omap_uwire_s *s, + struct uwire_slave_s *slave, int chipselect); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); @@ -510,16 +521,19 @@ struct omap_mpu_state_s { unsigned long sram_size; /* MPUI-TIPB peripherals */ - struct omap_uart_s *uart3; + struct omap_uart_s *uart[3]; + + struct omap_gpio_s *gpio; /* MPU public TIPB peripherals */ struct omap_32khz_timer_s *os_timer; - struct omap_uart_s *uart1; - struct omap_uart_s *uart2; - struct omap_mmc_s *mmc; + struct omap_mpuio_s *mpuio; + + struct omap_uwire_s *microwire; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; @@ -578,9 +592,6 @@ struct omap_mpu_state_s { uint16_t dsp_idlect2; uint16_t dsp_rstct2; } clkm; - - struct omap_mpuio_s *mpuio; - struct omap_gpio_s *gpio; } *omap310_mpu_init(unsigned long sdram_size, DisplayState *ds, const char *core); diff --git a/hw/palm.c b/hw/palm.c index 1ee05b823..794574565 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -37,7 +37,8 @@ static uint32_t static_readw(void *opaque, target_phys_addr_t offset) { } static void static_write(void *opaque, target_phys_addr_t offset, - uint32_t value) { + uint32_t value) +{ #ifdef SPY printf("%s: value %08lx written at " PA_FMT "\n", __FUNCTION__, value, offset); -- cgit v1.2.3 From 6276c7675803abf1752b9bf5c68dd4b81dcf8fa7 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 29 Oct 2007 02:57:19 +0000 Subject: Fix logic bug which broke TLBL/TLBS handling somewhat. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3478 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 708641c42..933a6ac41 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -472,9 +472,6 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBS: cause = 3; - goto set_EPC; - case EXCP_THREAD: - cause = 25; if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) int R = env->CP0_BadVAddr >> 62; @@ -488,6 +485,9 @@ void do_interrupt (CPUState *env) #endif offset = 0x000; } + goto set_EPC; + case EXCP_THREAD: + cause = 25; set_EPC: if (!(env->CP0_Status & (1 << CP0St_EXL))) { if (env->hflags & MIPS_HFLAG_BMASK) { -- cgit v1.2.3 From d2123ead89bd2d337793dcd739352142ff69007c Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 29 Oct 2007 09:38:43 +0000 Subject: Preliminary MIPS64R2 mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3479 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 55c935e6d..997858a69 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -276,6 +276,27 @@ static mips_def_t mips_defs[] = .SEGBITS = 40, .insn_flags = CPU_MIPS64 | ASE_MIPS3D, }, + { + /* A generic CPU providing MIPS64 Release 2 features. + FIXME: Eventually this should be replaced by a real CPU model. */ + .name = "MIPS64R2-generic", + .CP0_PRid = 0x00000000, + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) | (0x1 << CP0C0_AR), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) | + (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) | + (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x36FBFFFF, + .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) | (1 << FCR0_L) | + (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | + (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), + .SEGBITS = 40, + .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D, + }, #endif }; -- cgit v1.2.3 From 4c823cff9e0a3a11d917869dfbc8ae94bff26bba Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 29 Oct 2007 10:19:50 +0000 Subject: PowerPC 601 / 620 / 970 need a 1MB firmware. This option is not allowed for PowerMac, as it would overlap with NVRAM. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3480 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 11 +++++++++++ hw/ppc_oldworld.c | 11 +++++++++++ hw/ppc_prep.c | 3 +++ vl.h | 4 +++- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index f71169e53..b97f99f8b 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -98,6 +98,13 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); envs[i] = env; } + if (env->nip < 0xFFF80000) { + /* Special test for PowerPC 601: + * the boot vector is at 0xFFF00100, then we need a 1MB BIOS. + * But the NVRAM is located at 0xFFF04000... + */ + cpu_abort(env, "Mac99 hardware can not handle 1 MB BIOS\n"); + } /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -113,6 +120,10 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, exit(1); } bios_size = (bios_size + 0xfff) & ~0xfff; + if (bios_size > 0x00080000) { + /* As the NVRAM is located at 0xFFF04000, we cannot use 1 MB BIOSes */ + cpu_abort(env, "Mac99 hardware can not handle 1 MB BIOS\n"); + } cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 1c25344a7..946ebd176 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -135,6 +135,13 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); envs[i] = env; } + if (env->nip < 0xFFF80000) { + /* Special test for PowerPC 601: + * the boot vector is at 0xFFF00100, then we need a 1MB BIOS. + * But the NVRAM is located at 0xFFF04000... + */ + cpu_abort(env, "G3BW Mac hardware can not handle 1 MB BIOS\n"); + } /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); @@ -150,6 +157,10 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, exit(1); } bios_size = (bios_size + 0xfff) & ~0xfff; + if (bios_size > 0x00080000) { + /* As the NVRAM is located at 0xFFF04000, we cannot use 1 MB BIOSes */ + cpu_abort(env, "G3BW Mac hardware can not handle 1 MB BIOS\n"); + } cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 966617fe4..fc9fd9107 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -574,6 +574,9 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, cpu_abort(env, "qemu: could not load PPC PREP bios '%s'\n", buf); exit(1); } + if (env->nip < 0xFFF80000 && bios_size < 0x00100000) { + cpu_abort(env, "PowerPC 601 / 620 / 970 need a 1MB BIOS\n"); + } bios_size = (bios_size + 0xfff) & ~0xfff; cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM); diff --git a/vl.h b/vl.h index 5a7f74fc3..964d2eaa3 100644 --- a/vl.h +++ b/vl.h @@ -197,7 +197,9 @@ extern unsigned int nb_prom_envs; /* XXX: make it dynamic */ #define MAX_BIOS_SIZE (4 * 1024 * 1024) -#if defined (TARGET_PPC) || defined (TARGET_SPARC64) +#if defined (TARGET_PPC) +#define BIOS_SIZE (1024 * 1024) +#elif defined (TARGET_SPARC64) #define BIOS_SIZE ((512 + 32) * 1024) #elif defined(TARGET_MIPS) #define BIOS_SIZE (4 * 1024 * 1024) -- cgit v1.2.3 From c4781a51a5f5e5ea2660d5373602c991fede7b5d Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 29 Oct 2007 10:21:12 +0000 Subject: Implement PreP reset port. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3481 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index fc9fd9107..49b363267 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -252,6 +252,7 @@ static CPUReadMemoryFunc *PPC_XCSR_read[] = { /* Fake super-io ports for PREP platform (Intel 82378ZB) */ typedef struct sysctrl_t { + qemu_irq reset_irq; m48t59_t *nvram; uint8_t state; uint8_t syscontrol; @@ -293,7 +294,9 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) /* Special port 92 */ /* Check soft reset asked */ if (val & 0x01) { - // cpu_interrupt(first_cpu, PPC_INTERRUPT_RESET); + qemu_irq_raise(sysctrl->reset_irq); + } else { + qemu_irq_lower(sysctrl->reset_irq); } /* Check LE mode */ if (val & 0x02) { @@ -660,6 +663,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); /* Register fake IO ports for PREP */ + sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET]; register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl); register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl); /* System control ports */ -- cgit v1.2.3 From ef397e88e96d4a798bd190bcd0c43865c3725ae2 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 29 Oct 2007 10:22:58 +0000 Subject: Temporary hack to avoid Qemu crash at PowerPC reset time. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3482 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 8 ++++++-- hw/ppc405_uc.c | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 8b669071d..d897e6218 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -131,13 +131,17 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) case PPC6xx_INPUT_HRESET: /* Level sensitive - active low */ if (level) { -#if 0 // XXX: TOFIX #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: reset the CPU\n", __func__); } #endif - cpu_reset(env); + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + /* XXX: TOFIX */ +#if 0 + cpu_ppc_reset(env); +#else + qemu_system_reset_request(); #endif } break; diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 2857a1255..efbc399d2 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -2189,12 +2189,17 @@ void ppc40x_core_reset (CPUState *env) target_ulong dbsr; printf("Reset PowerPC core\n"); + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + /* XXX: TOFIX */ +#if 0 cpu_ppc_reset(env); +#else + qemu_system_reset_request(); +#endif dbsr = env->spr[SPR_40x_DBSR]; dbsr &= ~0x00000300; dbsr |= 0x00000100; env->spr[SPR_40x_DBSR] = dbsr; - cpu_loop_exit(); } void ppc40x_chip_reset (CPUState *env) @@ -2202,13 +2207,18 @@ void ppc40x_chip_reset (CPUState *env) target_ulong dbsr; printf("Reset PowerPC chip\n"); + env->interrupt_request |= CPU_INTERRUPT_EXITTB; + /* XXX: TOFIX */ +#if 0 cpu_ppc_reset(env); +#else + qemu_system_reset_request(); +#endif /* XXX: TODO reset all internal peripherals */ dbsr = env->spr[SPR_40x_DBSR]; dbsr &= ~0x00000300; dbsr |= 0x00000200; env->spr[SPR_40x_DBSR] = dbsr; - cpu_loop_exit(); } void ppc40x_system_reset (CPUState *env) -- cgit v1.2.3 From 8c9d7f83bf1f2d61f0fdd5fbc030ab67c8f433e7 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 29 Oct 2007 10:24:59 +0000 Subject: Fix PreP PCI IRQ mapping. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3483 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/prep_pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 6d6a1349c..8c8a4988d 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -117,7 +117,6 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = { &PPC_PCIIO_readl, }; -/* Don't know if this matches real hardware, but it agrees with OHW. */ static int prep_map_irq(PCIDevice *pci_dev, int irq_num) { return (irq_num + (pci_dev->devfn >> 3)) & 1; @@ -125,7 +124,7 @@ static int prep_map_irq(PCIDevice *pci_dev, int irq_num) static void prep_set_irq(qemu_irq *pic, int irq_num, int level) { - qemu_set_irq(pic[irq_num ? 11 : 9], level); + qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level); } PCIBus *pci_prep_init(qemu_irq *pic) -- cgit v1.2.3 From 3efda49d150def64f69a79cbd8da760ea15a79b7 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 29 Oct 2007 10:34:01 +0000 Subject: Add a TI TSC2102 chip (touchscreen/ADC/audio-CODEC controller). Fix GPIO memory mapping address and register width. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3484 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 4 +- hw/omap.c | 11 +- hw/palm.c | 13 + hw/pxa.h | 2 +- hw/tsc210x.c | 848 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.h | 3 + 6 files changed, 873 insertions(+), 8 deletions(-) create mode 100644 hw/tsc210x.c diff --git a/Makefile.target b/Makefile.target index b6be19d3e..33dc285bb 100644 --- a/Makefile.target +++ b/Makefile.target @@ -518,8 +518,8 @@ VL_OBJS+= arm_gic.o realview.o arm_sysctl.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o -VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o -VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o ecc.o +VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o $(AUDIODRV) wm8750.o +VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o tsc210x.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) diff --git a/hw/omap.c b/hw/omap.c index cfb7d2bfe..d6978d8eb 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -3184,16 +3184,17 @@ static void omap_gpio_write(void *opaque, target_phys_addr_t addr, } } +/* *Some* sources say the memory region is 32-bit. */ static CPUReadMemoryFunc *omap_gpio_readfn[] = { + omap_badwidth_read16, omap_gpio_read, - omap_badwidth_read32, - omap_badwidth_read32, + omap_badwidth_read16, }; static CPUWriteMemoryFunc *omap_gpio_writefn[] = { + omap_badwidth_write16, omap_gpio_write, - omap_badwidth_write32, - omap_badwidth_write32, + omap_badwidth_write16, }; void omap_gpio_reset(struct omap_gpio_s *s) @@ -3551,7 +3552,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], s->wakeup, omap_findclk(s, "clk32-kHz")); - s->gpio = omap_gpio_init(0xfffcf000, s->irq[0][OMAP_INT_GPIO_BANK1], + s->gpio = omap_gpio_init(0xfffce000, s->irq[0][OMAP_INT_GPIO_BANK1], omap_findclk(s, "mpuper_ck")); s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], diff --git a/hw/palm.c b/hw/palm.c index 794574565..096641374 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -76,8 +76,21 @@ static CPUWriteMemoryFunc *static_writefn[] = { #define PALMTE_MMC2_GPIO 7 #define PALMTE_MMC3_GPIO 11 +static void palmte_pintdav(void *opaque, int line, int level) +{ + struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; + + qemu_set_irq(omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO], + !level); +} + static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) { + omap_uwire_attach( + cpu->microwire, + tsc2102_init( + qemu_allocate_irqs(palmte_pintdav, cpu, 1)[0]), + 0); } static struct { diff --git a/hw/pxa.h b/hw/pxa.h index 90ffd6076..037aebee4 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -4,7 +4,7 @@ * Copyright (c) 2006 Openedhand Ltd. * Written by Andrzej Zaborowski * - * This code is licenced under the GPL. + * This code is licenced under the GNU GPL v2. */ #ifndef PXA_H # define PXA_H "pxa.h" diff --git a/hw/tsc210x.c b/hw/tsc210x.c new file mode 100644 index 000000000..6aa2bc8ad --- /dev/null +++ b/hw/tsc210x.c @@ -0,0 +1,848 @@ +/* + * TI TSC2102 (touchscreen/sensors/audio controller) controller. + * + * Copyright (c) 2006 Andrzej Zaborowski + * + * 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 "vl.h" + +#define TSC_DATA_REGISTERS_PAGE 0x0 +#define TSC_CONTROL_REGISTERS_PAGE 0x1 +#define TSC_AUDIO_REGISTERS_PAGE 0x2 + +#define TSC_VERBOSE + +#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - resolution[p])) + +struct tsc210x_state_s { + qemu_irq pint; + QEMUTimer *timer; + struct uwire_slave_s chip; + + int x, y; + int pressure; + + int state, page, offset, irq; + uint16_t command, dav; + + int busy; + int enabled; + int host_mode; + int function; + int nextfunction; + int precision; + int nextprecision; + int filter; + int pin_func; + int ref; + int timing; + int noise; + + uint16_t audio_ctrl1; + uint16_t audio_ctrl2; + uint16_t audio_ctrl3; + uint16_t pll[2]; + uint16_t volume; + int64_t volume_change; + int softstep; + uint16_t dac_power; + int64_t powerdown; + uint16_t filter_data[0x14]; +}; + +static const int resolution[4] = { 12, 8, 10, 12 }; + +#define TSC_MODE_NO_SCAN 0x0 +#define TSC_MODE_XY_SCAN 0x1 +#define TSC_MODE_XYZ_SCAN 0x2 +#define TSC_MODE_X 0x3 +#define TSC_MODE_Y 0x4 +#define TSC_MODE_Z 0x5 +#define TSC_MODE_BAT1 0x6 +#define TSC_MODE_BAT2 0x7 +#define TSC_MODE_AUX 0x8 +#define TSC_MODE_AUX_SCAN 0x9 +#define TSC_MODE_TEMP1 0xa +#define TSC_MODE_PORT_SCAN 0xb +#define TSC_MODE_TEMP2 0xc +#define TSC_MODE_XX_DRV 0xd +#define TSC_MODE_YY_DRV 0xe +#define TSC_MODE_YX_DRV 0xf + +static const uint16_t mode_regs[16] = { + 0x0000, /* No scan */ + 0x0600, /* X, Y scan */ + 0x0780, /* X, Y, Z scan */ + 0x0400, /* X */ + 0x0200, /* Y */ + 0x0180, /* Z */ + 0x0040, /* BAT1 */ + 0x0030, /* BAT2 */ + 0x0010, /* AUX */ + 0x0010, /* AUX scan */ + 0x0004, /* TEMP1 */ + 0x0070, /* Port scan */ + 0x0002, /* TEMP2 */ + 0x0000, /* X+, X- drivers */ + 0x0000, /* Y+, Y- drivers */ + 0x0000, /* Y+, X- drivers */ +}; + +/* + * Convert screen coordinates to arbitrary values that the + * touchscreen in my Palm Tungsten E device returns. + * This shouldn't really matter (because the guest system + * should calibrate the touchscreen anyway), but let's + * imitate some real hardware. + */ +#define X_TRANSFORM(value) \ + ((3850 - ((int) (value) * (3850 - 250) / 32768)) << 4) +#define Y_TRANSFORM(value) \ + ((150 + ((int) (value) * (3037 - 150) / 32768)) << 4) +#define Z1_TRANSFORM(s) \ + ((400 - (s)->x + ((s)->pressure << 9)) << 4) +#define Z2_TRANSFORM(s) \ + ((4000 + (s)->y - ((s)->pressure << 10)) << 4) +#define BAT1_VAL 0x8660 +#define BAT2_VAL 0x0000 +#define AUX1_VAL 0x35c0 +#define AUX2_VAL 0xffff +#define TEMP1_VAL 0x8c70 +#define TEMP2_VAL 0xa5b0 + +#define TSC_POWEROFF_DELAY 50 +#define TSC_SOFTSTEP_DELAY 50 + +static void tsc210x_reset(struct tsc210x_state_s *s) +{ + s->state = 0; + s->pin_func = 2; + s->enabled = 0; + s->busy = 0; + s->nextfunction = 0; + s->ref = 0; + s->timing = 0; + s->irq = 0; + s->dav = 0; + + s->audio_ctrl1 = 0x0000; + s->audio_ctrl2 = 0x4410; + s->audio_ctrl3 = 0x0000; + s->pll[0] = 0x1004; + s->pll[1] = 0x0000; + s->volume = 0xffff; + s->dac_power = 0x8540; + s->softstep = 1; + s->volume_change = 0; + s->powerdown = 0; + s->filter_data[0x00] = 0x6be3; + s->filter_data[0x01] = 0x9666; + s->filter_data[0x02] = 0x675d; + s->filter_data[0x03] = 0x6be3; + s->filter_data[0x04] = 0x9666; + s->filter_data[0x05] = 0x675d; + s->filter_data[0x06] = 0x7d83; + s->filter_data[0x07] = 0x84ee; + s->filter_data[0x08] = 0x7d83; + s->filter_data[0x09] = 0x84ee; + s->filter_data[0x0a] = 0x6be3; + s->filter_data[0x0b] = 0x9666; + s->filter_data[0x0c] = 0x675d; + s->filter_data[0x0d] = 0x6be3; + s->filter_data[0x0e] = 0x9666; + s->filter_data[0x0f] = 0x675d; + s->filter_data[0x10] = 0x7d83; + s->filter_data[0x11] = 0x84ee; + s->filter_data[0x12] = 0x7d83; + s->filter_data[0x13] = 0x84ee; + + qemu_set_irq(s->pint, s->irq); +} + +static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) +{ + switch (reg) { + case 0x00: /* X */ + s->dav &= 0xfbff; + return TSC_CUT_RESOLUTION(X_TRANSFORM(s->x), s->precision) + + (s->noise & 3); + + case 0x01: /* Y */ + s->noise ++; + s->dav &= 0xfdff; + return TSC_CUT_RESOLUTION(Y_TRANSFORM(s->y), s->precision) ^ + (s->noise & 3); + + case 0x02: /* Z1 */ + s->dav &= 0xfeff; + return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) - + (s->noise & 3); + + case 0x03: /* Z2 */ + s->dav &= 0xff7f; + return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) | + (s->noise & 3); + + case 0x04: /* KPData */ + return 0xffff; + + case 0x05: /* BAT1 */ + s->dav &= 0xffbf; + return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision); + + case 0x06: /* BAT2 */ + s->dav &= 0xffdf; + return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision); + + case 0x07: /* AUX1 */ + s->dav &= 0xffef; + return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision); + + case 0x08: /* AUX2 */ + s->dav &= 0xfff7; + return 0xffff; + + case 0x09: /* TEMP1 */ + s->dav &= 0xfffb; + return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision); + + case 0x0a: /* TEMP2 */ + s->dav &= 0xfffd; + return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision); + + case 0x0b: /* DAC */ + s->dav &= 0xfffe; + return 0xffff; + + default: +#ifdef TSC_VERBOSE + fprintf(stderr, "tsc2102_data_register_read: " + "no such register: 0x%02x\n", reg); +#endif + return 0xffff; + } +} + +static uint16_t tsc2102_control_register_read( + struct tsc210x_state_s *s, int reg) +{ + switch (reg) { + case 0x00: /* TSC ADC */ + return (s->pressure << 15) | ((!s->busy) << 14) | + (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; + + case 0x01: /* Status */ + return (s->pin_func << 14) | ((!s->enabled) << 13) | + (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav; + + case 0x03: /* Reference */ + return s->ref; + + case 0x04: /* Reset */ + return 0xffff; + + case 0x05: /* Configuration */ + return s->timing; + + default: +#ifdef TSC_VERBOSE + fprintf(stderr, "tsc2102_control_register_read: " + "no such register: 0x%02x\n", reg); +#endif + return 0xffff; + } +} + +static uint16_t tsc2102_audio_register_read(struct tsc210x_state_s *s, int reg) +{ + int l_ch, r_ch; + uint16_t val; + + switch (reg) { + case 0x00: /* Audio Control 1 */ + return s->audio_ctrl1; + + case 0x01: + return 0xff00; + + case 0x02: /* DAC Volume Control */ + return s->volume; + + case 0x03: + return 0x8b00; + + case 0x04: /* Audio Control 2 */ + l_ch = 1; + r_ch = 1; + if (s->softstep && !(s->dac_power & (1 << 10))) { + l_ch = (qemu_get_clock(vm_clock) > + s->volume_change + TSC_SOFTSTEP_DELAY); + r_ch = (qemu_get_clock(vm_clock) > + s->volume_change + TSC_SOFTSTEP_DELAY); + } + + return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2); + + case 0x05: /* Stereo DAC Power Control */ + return 0x2aa0 | s->dac_power | + (((s->dac_power & (1 << 10)) && + (qemu_get_clock(vm_clock) > + s->powerdown + TSC_POWEROFF_DELAY)) << 6); + + case 0x06: /* Audio Control 3 */ + val = s->audio_ctrl3 | 0x0001; + s->audio_ctrl3 &= 0xff3f; + return val; + + case 0x07: /* LCH_BASS_BOOST_N0 */ + case 0x08: /* LCH_BASS_BOOST_N1 */ + case 0x09: /* LCH_BASS_BOOST_N2 */ + case 0x0a: /* LCH_BASS_BOOST_N3 */ + case 0x0b: /* LCH_BASS_BOOST_N4 */ + case 0x0c: /* LCH_BASS_BOOST_N5 */ + case 0x0d: /* LCH_BASS_BOOST_D1 */ + case 0x0e: /* LCH_BASS_BOOST_D2 */ + case 0x0f: /* LCH_BASS_BOOST_D4 */ + case 0x10: /* LCH_BASS_BOOST_D5 */ + case 0x11: /* RCH_BASS_BOOST_N0 */ + case 0x12: /* RCH_BASS_BOOST_N1 */ + case 0x13: /* RCH_BASS_BOOST_N2 */ + case 0x14: /* RCH_BASS_BOOST_N3 */ + case 0x15: /* RCH_BASS_BOOST_N4 */ + case 0x16: /* RCH_BASS_BOOST_N5 */ + case 0x17: /* RCH_BASS_BOOST_D1 */ + case 0x18: /* RCH_BASS_BOOST_D2 */ + case 0x19: /* RCH_BASS_BOOST_D4 */ + case 0x1a: /* RCH_BASS_BOOST_D5 */ + return s->filter_data[reg - 0x07]; + + case 0x1b: /* PLL Programmability 1 */ + return s->pll[0]; + + case 0x1c: /* PLL Programmability 2 */ + return s->pll[1]; + + case 0x1d: /* Audio Control 4 */ + return (!s->softstep) << 14; + + default: +#ifdef TSC_VERBOSE + fprintf(stderr, "tsc2102_audio_register_read: " + "no such register: 0x%02x\n", reg); +#endif + return 0xffff; + } +} + +static void tsc2102_data_register_write( + struct tsc210x_state_s *s, int reg, uint16_t value) +{ + switch (reg) { + case 0x00: /* X */ + case 0x01: /* Y */ + case 0x02: /* Z1 */ + case 0x03: /* Z2 */ + case 0x05: /* BAT1 */ + case 0x06: /* BAT2 */ + case 0x07: /* AUX1 */ + case 0x08: /* AUX2 */ + case 0x09: /* TEMP1 */ + case 0x0a: /* TEMP2 */ + return; + + default: +#ifdef TSC_VERBOSE + fprintf(stderr, "tsc2102_data_register_write: " + "no such register: 0x%02x\n", reg); +#endif + } +} + +static void tsc2102_control_register_write( + struct tsc210x_state_s *s, int reg, uint16_t value) +{ + switch (reg) { + case 0x00: /* TSC ADC */ + s->host_mode = value >> 15; + s->enabled = !(value & 0x4000); + if (s->busy && !s->enabled) + qemu_del_timer(s->timer); + s->busy &= s->enabled; + s->nextfunction = (value >> 10) & 0xf; + s->nextprecision = (value >> 8) & 3; + s->filter = value & 0xff; + return; + + case 0x01: /* Status */ + s->pin_func = value >> 14; + return; + + case 0x03: /* Reference */ + s->ref = value & 0x1f; + return; + + case 0x04: /* Reset */ + if (value == 0xbb00) { + if (s->busy) + qemu_del_timer(s->timer); + tsc210x_reset(s); +#ifdef TSC_VERBOSE + } else { + fprintf(stderr, "tsc2102_control_register_write: " + "wrong value written into RESET\n"); +#endif + } + return; + + case 0x05: /* Configuration */ + s->timing = value & 0x3f; +#ifdef TSC_VERBOSE + if (value & ~0x3f) + fprintf(stderr, "tsc2102_control_register_write: " + "wrong value written into CONFIG\n"); +#endif + return; + + default: +#ifdef TSC_VERBOSE + fprintf(stderr, "tsc2102_control_register_write: " + "no such register: 0x%02x\n", reg); +#endif + } +} + +static void tsc2102_audio_register_write( + struct tsc210x_state_s *s, int reg, uint16_t value) +{ + switch (reg) { + case 0x00: /* Audio Control 1 */ + s->audio_ctrl1 = value & 0x0f3f; +#ifdef TSC_VERBOSE + if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7))) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into Audio 1\n"); +#endif + return; + + case 0x01: +#ifdef TSC_VERBOSE + if (value != 0xff00) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into reg 0x01\n"); +#endif + return; + + case 0x02: /* DAC Volume Control */ + s->volume = value; + s->volume_change = qemu_get_clock(vm_clock); + return; + + case 0x03: +#ifdef TSC_VERBOSE + if (value != 0x8b00) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into reg 0x03\n"); +#endif + return; + + case 0x04: /* Audio Control 2 */ + s->audio_ctrl2 = value & 0xf7f2; +#ifdef TSC_VERBOSE + if (value & ~0xf7fd) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into Audio 2\n"); +#endif + return; + + case 0x05: /* Stereo DAC Power Control */ + if ((value & ~s->dac_power) & (1 << 10)) + s->powerdown = qemu_get_clock(vm_clock); + + s->dac_power = value & 0x9543; +#ifdef TSC_VERBOSE + if ((value & ~0x9543) != 0x2aa0) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into Power\n"); +#endif + return; + + case 0x06: /* Audio Control 3 */ + s->audio_ctrl3 &= 0x00c0; + s->audio_ctrl3 |= value & 0xf800; +#ifdef TSC_VERBOSE + if (value & ~0xf8c7) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into Audio 3\n"); +#endif + return; + + case 0x07: /* LCH_BASS_BOOST_N0 */ + case 0x08: /* LCH_BASS_BOOST_N1 */ + case 0x09: /* LCH_BASS_BOOST_N2 */ + case 0x0a: /* LCH_BASS_BOOST_N3 */ + case 0x0b: /* LCH_BASS_BOOST_N4 */ + case 0x0c: /* LCH_BASS_BOOST_N5 */ + case 0x0d: /* LCH_BASS_BOOST_D1 */ + case 0x0e: /* LCH_BASS_BOOST_D2 */ + case 0x0f: /* LCH_BASS_BOOST_D4 */ + case 0x10: /* LCH_BASS_BOOST_D5 */ + case 0x11: /* RCH_BASS_BOOST_N0 */ + case 0x12: /* RCH_BASS_BOOST_N1 */ + case 0x13: /* RCH_BASS_BOOST_N2 */ + case 0x14: /* RCH_BASS_BOOST_N3 */ + case 0x15: /* RCH_BASS_BOOST_N4 */ + case 0x16: /* RCH_BASS_BOOST_N5 */ + case 0x17: /* RCH_BASS_BOOST_D1 */ + case 0x18: /* RCH_BASS_BOOST_D2 */ + case 0x19: /* RCH_BASS_BOOST_D4 */ + case 0x1a: /* RCH_BASS_BOOST_D5 */ + s->filter_data[reg - 0x07] = value; + return; + + case 0x1b: /* PLL Programmability 1 */ + s->pll[0] = value & 0xfffc; +#ifdef TSC_VERBOSE + if (value & ~0xfffc) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into PLL 1\n"); +#endif + return; + + case 0x1c: /* PLL Programmability 2 */ + s->pll[1] = value & 0xfffc; +#ifdef TSC_VERBOSE + if (value & ~0xfffc) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into PLL 2\n"); +#endif + return; + + case 0x1d: /* Audio Control 4 */ + s->softstep = !(value & 0x4000); +#ifdef TSC_VERBOSE + if (value & ~0x4000) + fprintf(stderr, "tsc2102_audio_register_write: " + "wrong value written into Audio 4\n"); +#endif + return; + + default: +#ifdef TSC_VERBOSE + fprintf(stderr, "tsc2102_audio_register_write: " + "no such register: 0x%02x\n", reg); +#endif + } +} + +/* This handles most of the chip logic. */ +static void tsc210x_pin_update(struct tsc210x_state_s *s) +{ + int64_t expires; + int pin_state; + + switch (s->pin_func) { + case 0: + pin_state = s->pressure; + break; + case 1: + pin_state = !!s->dav; + break; + case 2: + default: + pin_state = s->pressure && !s->dav; + } + + if (!s->enabled) + pin_state = 0; + + if (pin_state != s->irq) { + s->irq = pin_state; + qemu_set_irq(s->pint, s->irq); + } + + switch (s->nextfunction) { + case TSC_MODE_XY_SCAN: + case TSC_MODE_XYZ_SCAN: + if (!s->pressure) + return; + break; + + case TSC_MODE_X: + case TSC_MODE_Y: + case TSC_MODE_Z: + if (!s->pressure) + return; + /* Fall through */ + case TSC_MODE_BAT1: + case TSC_MODE_BAT2: + case TSC_MODE_AUX: + case TSC_MODE_TEMP1: + case TSC_MODE_TEMP2: + if (s->dav) + s->enabled = 0; + break; + + case TSC_MODE_AUX_SCAN: + case TSC_MODE_PORT_SCAN: + break; + + case TSC_MODE_NO_SCAN: + case TSC_MODE_XX_DRV: + case TSC_MODE_YY_DRV: + case TSC_MODE_YX_DRV: + default: + return; + } + + if (!s->enabled || s->busy) + return; + + s->busy = 1; + s->precision = s->nextprecision; + s->function = s->nextfunction; + expires = qemu_get_clock(vm_clock) + (ticks_per_sec >> 10); + qemu_mod_timer(s->timer, expires); +} + +static uint16_t tsc210x_read(struct tsc210x_state_s *s) +{ + uint16_t ret = 0x0000; + + if (!s->command) + fprintf(stderr, "tsc210x_read: SPI underrun!\n"); + + switch (s->page) { + case TSC_DATA_REGISTERS_PAGE: + ret = tsc2102_data_register_read(s, s->offset); + break; + case TSC_CONTROL_REGISTERS_PAGE: + ret = tsc2102_control_register_read(s, s->offset); + break; + case TSC_AUDIO_REGISTERS_PAGE: + ret = tsc2102_audio_register_read(s, s->offset); + break; + default: + cpu_abort(cpu_single_env, "tsc210x_read: wrong memory page\n"); + } + + tsc210x_pin_update(s); + + /* Allow sequential reads. */ + s->offset ++; + s->state = 0; + return ret; +} + +static void tsc210x_write(struct tsc210x_state_s *s, uint16_t value) +{ + /* + * This is a two-state state machine for reading + * command and data every second time. + */ + if (!s->state) { + s->command = value >> 15; + s->page = (value >> 11) & 0x0f; + s->offset = (value >> 5) & 0x3f; + s->state = 1; + } else { + if (s->command) + fprintf(stderr, "tsc210x_write: SPI overrun!\n"); + else + switch (s->page) { + case TSC_DATA_REGISTERS_PAGE: + tsc2102_data_register_write(s, s->offset, value); + break; + case TSC_CONTROL_REGISTERS_PAGE: + tsc2102_control_register_write(s, s->offset, value); + break; + case TSC_AUDIO_REGISTERS_PAGE: + tsc2102_audio_register_write(s, s->offset, value); + break; + default: + cpu_abort(cpu_single_env, + "tsc210x_write: wrong memory page\n"); + } + + tsc210x_pin_update(s); + s->state = 0; + } +} + +static void tsc210x_timer_tick(void *opaque) +{ + struct tsc210x_state_s *s = opaque; + + /* Timer ticked -- a set of conversions has been finished. */ + + if (!s->busy) + return; + + s->busy = 0; + s->dav |= mode_regs[s->function]; + tsc210x_pin_update(s); +} + +static void tsc210x_touchscreen_event(void *opaque, + int x, int y, int z, int buttons_state) +{ + struct tsc210x_state_s *s = opaque; + int p = s->pressure; + + if (buttons_state) { + s->x = x; + s->y = y; + } + s->pressure = !!buttons_state; + + /* + * Note: We would get better responsiveness in the guest by + * signaling TS events immediately, but for now we simulate + * the first conversion delay for sake of correctness. + */ + if (p != s->pressure) + tsc210x_pin_update(s); +} + +static void tsc210x_save(QEMUFile *f, void *opaque) +{ + struct tsc210x_state_s *s = (struct tsc210x_state_s *) opaque; + int64_t now = qemu_get_clock(vm_clock); + int i; + + qemu_put_be16(f, s->x); + qemu_put_be16(f, s->y); + qemu_put_byte(f, s->pressure); + + qemu_put_byte(f, s->state); + qemu_put_byte(f, s->page); + qemu_put_byte(f, s->offset); + qemu_put_byte(f, s->command); + + qemu_put_byte(f, s->irq); + qemu_put_be16s(f, &s->dav); + + qemu_put_timer(f, s->timer); + qemu_put_byte(f, s->enabled); + qemu_put_byte(f, s->host_mode); + qemu_put_byte(f, s->function); + qemu_put_byte(f, s->nextfunction); + qemu_put_byte(f, s->precision); + qemu_put_byte(f, s->nextprecision); + qemu_put_byte(f, s->filter); + qemu_put_byte(f, s->pin_func); + qemu_put_byte(f, s->ref); + qemu_put_byte(f, s->timing); + qemu_put_be32(f, s->noise); + + qemu_put_be16s(f, &s->audio_ctrl1); + qemu_put_be16s(f, &s->audio_ctrl2); + qemu_put_be16s(f, &s->audio_ctrl3); + qemu_put_be16s(f, &s->pll[0]); + qemu_put_be16s(f, &s->pll[1]); + qemu_put_be16s(f, &s->volume); + qemu_put_be64(f, (uint64_t) (s->volume_change - now)); + qemu_put_be64(f, (uint64_t) (s->powerdown - now)); + qemu_put_byte(f, s->softstep); + qemu_put_be16s(f, &s->dac_power); + + for (i = 0; i < 0x14; i ++) + qemu_put_be16s(f, &s->filter_data[i]); +} + +static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) +{ + struct tsc210x_state_s *s = (struct tsc210x_state_s *) opaque; + int64_t now = qemu_get_clock(vm_clock); + int i; + + s->x = qemu_get_be16(f); + s->y = qemu_get_be16(f); + s->pressure = qemu_get_byte(f); + + s->state = qemu_get_byte(f); + s->page = qemu_get_byte(f); + s->offset = qemu_get_byte(f); + s->command = qemu_get_byte(f); + + s->irq = qemu_get_byte(f); + qemu_get_be16s(f, &s->dav); + + qemu_get_timer(f, s->timer); + s->enabled = qemu_get_byte(f); + s->host_mode = qemu_get_byte(f); + s->function = qemu_get_byte(f); + s->nextfunction = qemu_get_byte(f); + s->precision = qemu_get_byte(f); + s->nextprecision = qemu_get_byte(f); + s->filter = qemu_get_byte(f); + s->pin_func = qemu_get_byte(f); + s->ref = qemu_get_byte(f); + s->timing = qemu_get_byte(f); + s->noise = qemu_get_be32(f); + + qemu_get_be16s(f, &s->audio_ctrl1); + qemu_get_be16s(f, &s->audio_ctrl2); + qemu_get_be16s(f, &s->audio_ctrl3); + qemu_get_be16s(f, &s->pll[0]); + qemu_get_be16s(f, &s->pll[1]); + qemu_get_be16s(f, &s->volume); + s->volume_change = (int64_t) qemu_get_be64(f) + now; + s->powerdown = (int64_t) qemu_get_be64(f) + now; + s->softstep = qemu_get_byte(f); + qemu_get_be16s(f, &s->dac_power); + + for (i = 0; i < 0x14; i ++) + qemu_get_be16s(f, &s->filter_data[i]); + + s->busy = qemu_timer_pending(s->timer); + qemu_set_irq(s->pint, s->irq); + + return 0; +} + +static int tsc2102_iid = 0; + +struct uwire_slave_s *tsc2102_init(qemu_irq pint) +{ + struct tsc210x_state_s *s; + + s = (struct tsc210x_state_s *) + qemu_mallocz(sizeof(struct tsc210x_state_s)); + memset(s, 0, sizeof(struct tsc210x_state_s)); + s->x = 160; + s->y = 160; + s->pressure = 0; + s->precision = s->nextprecision = 0; + s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); + s->pint = pint; + + s->chip.opaque = s; + s->chip.send = (void *) tsc210x_write; + s->chip.receive = (void *) tsc210x_read; + + tsc210x_reset(s); + + qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, + "QEMU TSC2102-driven Touchscreen"); + + qemu_register_reset((void *) tsc210x_reset, s); + register_savevm("tsc2102", tsc2102_iid ++, 0, + tsc210x_save, tsc210x_load, s); + + return &s->chip; +} diff --git a/vl.h b/vl.h index 964d2eaa3..6c9803386 100644 --- a/vl.h +++ b/vl.h @@ -1663,6 +1663,9 @@ void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); #include "hw/omap.h" +/* tsc210x.c */ +struct uwire_slave_s *tsc2102_init(qemu_irq pint); + /* mcf_uart.c */ uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr); void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val); -- cgit v1.2.3 From b50a6563d8590675905b730d32f17fa119664e0e Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 29 Oct 2007 10:59:29 +0000 Subject: Add a qemu_irq_invert() shortcut for inverting a signal. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3485 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/irq.c | 11 +++++++++++ hw/irq.h | 2 ++ hw/palm.c | 24 +++++------------------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/hw/irq.c b/hw/irq.c index e46ee603c..bb30ced11 100644 --- a/hw/irq.c +++ b/hw/irq.c @@ -55,3 +55,14 @@ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) return s; } +static void qemu_notirq(void *opaque, int line, int level) +{ + struct IRQState *irq = opaque; + + irq->handler(irq->opaque, irq->n, !level); +} + +qemu_irq qemu_irq_invert(qemu_irq irq) +{ + return qemu_allocate_irqs(qemu_notirq, irq, 1)[0]; +} diff --git a/hw/irq.h b/hw/irq.h index 652fd6abe..2d1a3548b 100644 --- a/hw/irq.h +++ b/hw/irq.h @@ -19,3 +19,5 @@ static inline void qemu_irq_lower(qemu_irq irq) /* Returns an array of N IRQs. */ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); +/* Returns a new IRQ with opposite polarity. */ +qemu_irq qemu_irq_invert(qemu_irq irq); diff --git a/hw/palm.c b/hw/palm.c index 096641374..a6c9f7d97 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -76,20 +76,13 @@ static CPUWriteMemoryFunc *static_writefn[] = { #define PALMTE_MMC2_GPIO 7 #define PALMTE_MMC3_GPIO 11 -static void palmte_pintdav(void *opaque, int line, int level) -{ - struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; - - qemu_set_irq(omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO], - !level); -} - static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) { + qemu_irq p_int = omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]; + omap_uwire_attach( cpu->microwire, - tsc2102_init( - qemu_allocate_irqs(palmte_pintdav, cpu, 1)[0]), + tsc2102_init(qemu_irq_invert(p_int)), 0); } @@ -122,14 +115,6 @@ static void palmte_button_event(void *opaque, int keycode) !(keycode & 0x80)); } -static void palmte_mmc_cover(void *opaque, int line, int level) -{ - struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque; - - qemu_set_irq(omap_mpuio_in_get(cpu->mpuio)[PALMTE_MMC_SWITCH_GPIO], - !level); -} - static void palmte_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -174,7 +159,8 @@ static void palmte_init(int ram_size, int vga_ram_size, int boot_device, omap_mmc_handlers(cpu->mmc, omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO], - qemu_allocate_irqs(palmte_mmc_cover, cpu, 1)[0]); + qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio) + [PALMTE_MMC_SWITCH_GPIO])); /* Setup initial (reset) machine state */ if (nb_option_roms) { -- cgit v1.2.3 From 273af66025e8cc6982febfb4a74a8d9106a92440 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 29 Oct 2007 14:39:49 +0000 Subject: Adjust s390 addresses (the MSB is defined as "to be ignored"). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3486 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/op_helper.c | 6 +++++- target-arm/op_helper.c | 6 +++++- target-cris/op_helper.c | 6 +++++- target-i386/helper.c | 6 +++++- target-m68k/op_helper.c | 6 +++++- target-mips/op_helper.c | 6 +++++- target-ppc/op_helper.c | 6 +++++- target-sh4/op_helper.c | 6 +++++- target-sparc/op_helper.c | 6 +++++- 9 files changed, 45 insertions(+), 9 deletions(-) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index ae8470b59..fa1e6acc5 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -1076,7 +1076,11 @@ void helper_mtpr (int iprn) /* Softmmu support */ #if !defined (CONFIG_USER_ONLY) -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif /* XXX: the two following helpers are pure hacks. * Hopefully, we emulate the PALcode, then we should never see diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index c0e7c8d64..6e14a4dff 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -178,7 +178,11 @@ void do_vfp_get_fpscr(void) #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif #define SHIFT 0 #include "softmmu_template.h" diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index 4f0f07cd4..d0ec519b1 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -23,7 +23,11 @@ #include "exec.h" #define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif #define SHIFT 0 #include "softmmu_template.h" diff --git a/target-i386/helper.c b/target-i386/helper.c index 88aa82e42..bb927f673 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3865,7 +3865,11 @@ void update_fp_status(void) #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif #define SHIFT 0 #include "softmmu_template.h" diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 917ef5288..80ec89040 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -31,7 +31,11 @@ void do_interrupt(int is_hw) extern int semihosting_enabled; #define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif #define SHIFT 0 #include "softmmu_template.h" diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 3c04c55d8..50c76d1ca 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -22,7 +22,11 @@ #include "host-utils.h" -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif /*****************************************************************************/ /* Exceptions processing helpers */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 751bd7212..da5a6f5e3 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2732,7 +2732,11 @@ DO_SPE_OP1(fsctuf); #if !defined (CONFIG_USER_ONLY) #define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif #define SHIFT 0 #include "softmmu_template.h" diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index 2535b8d6a..c1bc4e894 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -28,7 +28,11 @@ void do_raise_exception(void) #ifndef CONFIG_USER_ONLY #define MMUSUFFIX _mmu -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif #define SHIFT 0 #include "softmmu_template.h" diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index ccadf8510..374678879 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1680,7 +1680,11 @@ static void do_unaligned_access(target_ulong addr, int is_write, int is_user, #define MMUSUFFIX _mmu #define ALIGNED_ONLY -#define GETPC() (__builtin_return_address(0)) +#ifdef __s390__ +# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) +#else +# define GETPC() (__builtin_return_address(0)) +#endif #define SHIFT 0 #include "softmmu_template.h" -- cgit v1.2.3 From 86c4a9f5131414143b2ee82acb65a74de3baa8f5 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 29 Oct 2007 21:54:35 +0000 Subject: Fix two PowerPC FPU emulation bugs (thanks to Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3487 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index da5a6f5e3..e534fab9f 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -522,7 +522,7 @@ static always_inline int isinfinity (float64 f) u.f = f; - return ((u.u >> 52) & 0x3FF) == 0x3FF && + return ((u.u >> 52) & 0x7FF) == 0x7FF && (u.u & 0x000FFFFFFFFFFFFFULL) == 0; } @@ -681,7 +681,7 @@ static always_inline void float_zero_divide_excp (void) u0.f = FT0; u1.f = FT1; u0.u = ((u0.u ^ u1.u) & 0x8000000000000000ULL); - u0.u |= 0x3FFULL << 52; + u0.u |= 0x7FFULL << 52; FT0 = u0.f; } } -- cgit v1.2.3 From 12bc92ab8acf5e42598b6fa943ceb98ccce6ba71 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 30 Oct 2007 21:06:14 +0000 Subject: Do not make NETLINK socket connections possible (Alexander Graf). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3488 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cf39f1535..6d1997e09 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -978,6 +978,8 @@ static abi_long do_socket(int domain, int type, int protocol) break; } #endif + if (domain == PF_NETLINK) + return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */ return get_errno(socket(domain, type, protocol)); } -- cgit v1.2.3 From a528b80cb09977806129249ea604aaef3830f3ec Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 30 Oct 2007 22:38:53 +0000 Subject: Miscellaneous VNC related fixes from Xen forwarded by Matthew Kent. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3489 c046a42c-6fe2-441c-8c8c-71466251a162 --- console.c | 21 ++++++++++++-------- keymaps.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- vl.h | 1 + vnc.c | 35 +++++++++++++++++++++++++++++++-- vnc_keysym.h | 14 +++++++++++++ 5 files changed, 124 insertions(+), 11 deletions(-) diff --git a/console.c b/console.c index ff725c2e6..9d3c2f627 100644 --- a/console.c +++ b/console.c @@ -509,7 +509,7 @@ static void text_console_resize(TextConsole *s) c++; } } - free(s->cells); + qemu_free(s->cells); s->cells = cells; } @@ -1167,11 +1167,21 @@ int is_graphic_console(void) return active_console->console_type == GRAPHIC_CONSOLE; } +void console_color_init(DisplayState *ds) +{ + int i, j; + for (j = 0; j < 2; j++) { + for (i = 0; i < 8; i++) { + color_table[j][i] = col_expand(ds, + vga_get_color(ds, color_table_rgb[j][i])); + } + } +} + CharDriverState *text_console_init(DisplayState *ds, const char *p) { CharDriverState *chr; TextConsole *s; - int i,j; unsigned width; unsigned height; static int color_inited; @@ -1195,12 +1205,7 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p) 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])); - } - } + console_color_init(s->ds); } s->y_displayed = 0; s->y_base = 0; diff --git a/keymaps.c b/keymaps.c index f0f8c103d..15c40fadc 100644 --- a/keymaps.c +++ b/keymaps.c @@ -32,6 +32,12 @@ static int get_keysym(const char *name) return 0; } +struct key_range { + int start; + int end; + struct key_range *next; +}; + #define MAX_NORMAL_KEYCODE 512 #define MAX_EXTRA_COUNT 256 typedef struct { @@ -41,8 +47,34 @@ typedef struct { uint16_t keycode; } keysym2keycode_extra[MAX_EXTRA_COUNT]; int extra_count; + struct key_range *keypad_range; + struct key_range *numlock_range; } kbd_layout_t; +static void add_to_key_range(struct key_range **krp, int code) { + struct key_range *kr; + for (kr = *krp; kr; kr = kr->next) { + if (code >= kr->start && code <= kr->end) + break; + if (code == kr->start - 1) { + kr->start--; + break; + } + if (code == kr->end + 1) { + kr->end++; + break; + } + } + if (kr == NULL) { + kr = qemu_mallocz(sizeof(*kr)); + if (kr) { + kr->start = kr->end = code; + kr->next = *krp; + *krp = kr; + } + } +} + static kbd_layout_t *parse_keyboard_layout(const char *language, kbd_layout_t * k) { @@ -87,7 +119,15 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, // fprintf(stderr, "Warning: unknown keysym %s\n", line); } else { const char *rest = end_of_keysym + 1; - int keycode = strtol(rest, NULL, 0); + char *rest2; + int keycode = strtol(rest, &rest2, 0); + + if (rest && strstr(rest, "numlock")) { + add_to_key_range(&k->keypad_range, keycode); + add_to_key_range(&k->numlock_range, keysym); + //fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode); + } + /* if(keycode&0x80) keycode=(keycode<<8)^0x80e0; */ if (keysym < MAX_NORMAL_KEYCODE) { @@ -143,3 +183,25 @@ static int keysym2scancode(void *kbd_layout, int keysym) } return 0; } + +static inline int keycode_is_keypad(void *kbd_layout, int keycode) +{ + kbd_layout_t *k = kbd_layout; + struct key_range *kr; + + for (kr = k->keypad_range; kr; kr = kr->next) + if (keycode >= kr->start && keycode <= kr->end) + return 1; + return 0; +} + +static inline int keysym_is_numlock(void *kbd_layout, int keysym) +{ + kbd_layout_t *k = kbd_layout; + struct key_range *kr; + + for (kr = k->numlock_range; kr; kr = kr->next) + if (keysym >= kr->start && keysym <= kr->end) + return 1; + return 0; +} diff --git a/vl.h b/vl.h index 6c9803386..90fdcf913 100644 --- a/vl.h +++ b/vl.h @@ -374,6 +374,7 @@ void vga_hw_screen_dump(const char *filename); int is_graphic_console(void); CharDriverState *text_console_init(DisplayState *ds, const char *p); void console_select(unsigned int index); +void console_color_init(DisplayState *ds); /* serial ports */ diff --git a/vnc.c b/vnc.c index 72c8d1cce..83d001161 100644 --- a/vnc.c +++ b/vnc.c @@ -284,7 +284,10 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h) exit(1); } - ds->depth = vs->depth * 8; + if (ds->depth != vs->depth * 8) { + ds->depth = vs->depth * 8; + console_color_init(ds); + } size_changed = ds->width != w || ds->height != h; ds->width = w; ds->height = h; @@ -907,6 +910,12 @@ static void reset_keys(VncState *vs) } } +static void press_key(VncState *vs, int keysym) +{ + kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f); + kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80); +} + static void do_key_event(VncState *vs, int down, uint32_t sym) { int keycode; @@ -934,6 +943,28 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) return; } break; + case 0x45: /* NumLock */ + if (!down) + vs->modifiers_state[keycode] ^= 1; + break; + } + + if (keycode_is_keypad(vs->kbd_layout, keycode)) { + /* If the numlock state needs to change then simulate an additional + keypress before sending this one. This will happen if the user + toggles numlock away from the VNC window. + */ + if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) { + if (!vs->modifiers_state[0x45]) { + vs->modifiers_state[0x45] = 1; + press_key(vs, 0xff7f); + } + } else { + if (vs->modifiers_state[0x45]) { + vs->modifiers_state[0x45] = 0; + press_key(vs, 0xff7f); + } + } } if (is_graphic_console()) { @@ -991,7 +1022,7 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) static void key_event(VncState *vs, int down, uint32_t sym) { - if (sym >= 'A' && sym <= 'Z') + if (sym >= 'A' && sym <= 'Z' && is_graphic_console()) sym = sym - 'A' + 'a'; do_key_event(vs, down, sym); } diff --git a/vnc_keysym.h b/vnc_keysym.h index 14fe47f9e..5c4710444 100644 --- a/vnc_keysym.h +++ b/vnc_keysym.h @@ -231,6 +231,19 @@ static name2keysym_t name2keysym[]={ {"Home", 0xff50}, /* XK_Home */ {"End", 0xff57}, /* XK_End */ {"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */ +{"KP_Home", 0xff95}, +{"KP_Left", 0xff96}, +{"KP_Up", 0xff97}, +{"KP_Right", 0xff98}, +{"KP_Down", 0xff99}, +{"KP_Prior", 0xff9a}, +{"KP_Page_Up", 0xff9a}, +{"KP_Next", 0xff9b}, +{"KP_Page_Down", 0xff9b}, +{"KP_End", 0xff9c}, +{"KP_Begin", 0xff9d}, +{"KP_Insert", 0xff9e}, +{"KP_Delete", 0xff9f}, {"F1", 0xffbe}, /* XK_F1 */ {"F2", 0xffbf}, /* XK_F2 */ {"F3", 0xffc0}, /* XK_F3 */ @@ -258,6 +271,7 @@ static name2keysym_t name2keysym[]={ {"KP_8", 0xffb8}, /* XK_KP_8 */ {"KP_9", 0xffb9}, /* XK_KP_9 */ {"KP_Add", 0xffab}, /* XK_KP_Add */ +{"KP_Separator", 0xffac},/* XK_KP_Separator */ {"KP_Decimal", 0xffae}, /* XK_KP_Decimal */ {"KP_Divide", 0xffaf}, /* XK_KP_Divide */ {"KP_Enter", 0xff8d}, /* XK_KP_Enter */ -- cgit v1.2.3 From c9f103069ed27f7520b6028d29c09767f1b85f43 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 30 Oct 2007 23:19:52 +0000 Subject: Declare function before use, reduces compiler warning noise. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3490 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slirp/misc.c b/slirp/misc.c index 755dfec94..9ea7dd068 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -601,6 +601,8 @@ relay(s) #endif #ifdef CONFIG_QEMU +extern void term_vprintf(const char *fmt, va_list ap); + void lprint(const char *format, ...) { va_list args; -- cgit v1.2.3 From 5ad265ee5bb946d9be6e555d135c961abbe9b31c Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 00:21:35 +0000 Subject: x86_64 support in cpu_gdb_read_registers(), by Goran Weinholt. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3491 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/gdbstub.c b/gdbstub.c index 89ee1d2e4..eb1d75fed 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -225,8 +225,56 @@ static int put_packet(GDBState *s, char *buf) static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf) { - uint32_t *registers = (uint32_t *)mem_buf; int i, fpus; + uint32_t *registers = (uint32_t *)mem_buf; + +#ifdef TARGET_X86_64 + /* This corresponds with amd64_register_info[] in gdb/amd64-tdep.c */ + uint64_t *registers64 = (uint64_t *)mem_buf; + + if (env->hflags & HF_CS64_MASK) { + registers64[0] = tswap64(env->regs[R_EAX]); + registers64[1] = tswap64(env->regs[R_EBX]); + registers64[2] = tswap64(env->regs[R_ECX]); + registers64[3] = tswap64(env->regs[R_EDX]); + registers64[4] = tswap64(env->regs[R_ESI]); + registers64[5] = tswap64(env->regs[R_EDI]); + registers64[6] = tswap64(env->regs[R_EBP]); + registers64[7] = tswap64(env->regs[R_ESP]); + for(i = 8; i < 16; i++) { + registers64[i] = tswap64(env->regs[i]); + } + registers64[16] = tswap64(env->eip); + + registers = (uint32_t *)®isters64[17]; + registers[0] = tswap32(env->eflags); + registers[1] = tswap32(env->segs[R_CS].selector); + registers[2] = tswap32(env->segs[R_SS].selector); + registers[3] = tswap32(env->segs[R_DS].selector); + registers[4] = tswap32(env->segs[R_ES].selector); + registers[5] = tswap32(env->segs[R_FS].selector); + registers[6] = tswap32(env->segs[R_GS].selector); + /* XXX: convert floats */ + for(i = 0; i < 8; i++) { + memcpy(mem_buf + 16 * 8 + 7 * 4 + i * 10, &env->fpregs[i], 10); + } + registers[27] = tswap32(env->fpuc); /* fctrl */ + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; + registers[28] = tswap32(fpus); /* fstat */ + registers[29] = 0; /* ftag */ + registers[30] = 0; /* fiseg */ + registers[31] = 0; /* fioff */ + registers[32] = 0; /* foseg */ + registers[33] = 0; /* fooff */ + registers[34] = 0; /* fop */ + for(i = 0; i < 16; i++) { + memcpy(mem_buf + 16 * 8 + 35 * 4 + i * 16, &env->xmm_regs[i], 16); + } + registers[99] = tswap32(env->mxcsr); + + return 8 * 17 + 4 * 7 + 10 * 8 + 4 * 8 + 16 * 16 + 4; + } +#endif for(i = 0; i < 8; i++) { registers[i] = env->regs[i]; -- cgit v1.2.3 From 046833eae35d9a8c2ed8e87681a74d6a615a0395 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 00:27:50 +0000 Subject: Use a O_NONBLOCK pipe for iso completion signals for thread-safety, by Arnon Gilboa. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3492 c046a42c-6fe2-441c-8c8c-71466251a162 --- usb-linux.c | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/usb-linux.c b/usb-linux.c index 53d501d7b..00864f08b 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -68,6 +68,7 @@ struct endp_data { typedef struct USBHostDevice { USBDevice dev; int fd; + int pipe_fds[2]; USBPacket *packet; struct endp_data endp_table[MAX_ENDPOINTS]; int configuration; @@ -78,8 +79,6 @@ typedef struct USBHostDevice { typedef struct PendingURB { struct usbdevfs_urb *urb; - USBHostDevice *dev; - QEMUBH *bh; int status; struct PendingURB *next; } PendingURB; @@ -91,8 +90,6 @@ static int add_pending_urb(struct usbdevfs_urb *urb) PendingURB *purb = qemu_mallocz(sizeof(PendingURB)); if (purb) { purb->urb = urb; - purb->dev = NULL; - purb->bh = NULL; purb->status = 0; purb->next = pending_urbs; pending_urbs = purb; @@ -341,16 +338,21 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) } #ifdef USE_ASYNCIO -static void usb_linux_bh_cb(void *opaque) +static void urb_completion_pipe_read(void *opaque) { - PendingURB *pending_urb = (PendingURB *)opaque; - USBHostDevice *s = pending_urb->dev; - struct usbdevfs_urb *purb = NULL; + USBHostDevice *s = opaque; USBPacket *p = s->packet; - int ret; + PendingURB *pending_urb = NULL; + struct usbdevfs_urb *purb = NULL; + int len, ret; + + len = read(s->pipe_fds[0], &pending_urb, sizeof(pending_urb)); + if (len != sizeof(pending_urb)) { + printf("urb_completion: error reading pending_urb, len=%d\n", len); + return; + } - /* FIXME: handle purb->status */ - qemu_free(pending_urb->bh); + /* FIXME: handle pending_urb->status */ del_pending_urb(pending_urb->urb); if (!p) { @@ -360,14 +362,14 @@ static void usb_linux_bh_cb(void *opaque) ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); if (ret < 0) { - printf("usb_linux_bh_cb: REAPURBNDELAY ioctl=%d errno=%d\n", + printf("urb_completion: REAPURBNDELAY ioctl=%d errno=%d\n", ret, errno); return; } #ifdef DEBUG_ISOCH if (purb == pending_urb->urb) { - printf("usb_linux_bh_cb: urb mismatch reaped=%p pending=%p\n", + printf("urb_completion: urb mismatch reaped=%p pending=%p\n", purb, urb); } #endif @@ -391,12 +393,8 @@ static void isoch_done(int signum, siginfo_t *info, void *context) purb = get_pending_urb(urb); if (purb) { - purb->bh = qemu_bh_new(usb_linux_bh_cb, purb); - if (purb->bh) { - purb->dev = s; - purb->status = info->si_errno; - qemu_bh_schedule(purb->bh); - } + purb->status = info->si_errno; + write(s->pipe_fds[1], &purb, sizeof(purb)); } } #endif @@ -627,7 +625,7 @@ USBDevice *usb_host_device_open(const char *devname) /* read the device description */ dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); if (dev->descr_len <= 0) { - perror("usb_host_update_interfaces: reading device data failed"); + perror("usb_host_device_open: reading device data failed"); goto fail; } @@ -650,7 +648,7 @@ USBDevice *usb_host_device_open(const char *devname) ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); if (ret < 0) { - perror("USBDEVFS_CONNECTINFO"); + perror("usb_host_device_open: USBDEVFS_CONNECTINFO"); goto fail; } @@ -688,8 +686,17 @@ USBDevice *usb_host_device_open(const char *devname) sigact.sa_restorer = 0; ret = sigaction(SIG_ISOCOMPLETE, &sigact, NULL); if (ret < 0) { - printf("sigaction SIG_ISOCOMPLETE=%d errno=%d\n", ret, errno); + perror("usb_host_device_open: sigaction failed"); + goto fail; + } + + if (pipe(dev->pipe_fds) < 0) { + perror("usb_host_device_open: pipe creation failed"); + goto fail; } + fcntl(dev->pipe_fds[0], F_SETFL, O_NONBLOCK | O_ASYNC); + fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK); + qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev); #endif dev->urbs_ready = 0; return (USBDevice *)dev; -- cgit v1.2.3 From 7bfe5777023bb88e8f63a3e80a836f3eb7b13fdc Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 00:34:21 +0000 Subject: OHCI USB isochronous transfers support (Arnon Gilboa). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3493 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-ohci.c | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 340 insertions(+), 17 deletions(-) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 2d5af7da0..287c45eb0 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -32,6 +32,7 @@ //#define DEBUG_OHCI /* Dump packet contents. */ //#define DEBUG_PACKET +//#define DEBUG_ISOCH /* This causes frames to occur 1000x slower */ //#define OHCI_TIME_WARP 1 @@ -132,8 +133,8 @@ static void ohci_bus_stop(OHCIState *ohci); #define OHCI_ED_S (1<<13) #define OHCI_ED_K (1<<14) #define OHCI_ED_F (1<<15) -#define OHCI_ED_MPS_SHIFT 7 -#define OHCI_ED_MPS_MASK (0xf<> 2); @@ -431,6 +483,12 @@ static inline int ohci_read_td(uint32_t addr, struct ohci_td *td) return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); } +static inline int ohci_read_iso_td(uint32_t addr, struct ohci_iso_td *td) +{ + return (get_dwords(addr, (uint32_t *)td, 4) && + get_words(addr + 16, td->offset, 8)); +} + static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed) { return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); @@ -441,6 +499,12 @@ static inline int ohci_put_td(uint32_t addr, struct ohci_td *td) return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); } +static inline int ohci_put_iso_td(uint32_t addr, struct ohci_iso_td *td) +{ + return (put_dwords(addr, (uint32_t *)td, 4) && + put_words(addr + 16, td->offset, 8)); +} + /* Read/Write the contents of a TD from/to main memory. */ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) { @@ -459,16 +523,270 @@ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) cpu_physical_memory_rw(ptr, buf, len - n, write); } -static void ohci_process_lists(OHCIState *ohci); +/* Read/Write the contents of an ISO TD from/to main memory. */ +static void ohci_copy_iso_td(uint32_t start_addr, uint32_t end_addr, + uint8_t *buf, int len, int write) +{ + uint32_t ptr; + uint32_t n; -static void ohci_async_complete_packet(USBPacket * packet, void *opaque) + ptr = start_addr; + n = 0x1000 - (ptr & 0xfff); + if (n > len) + n = len; + cpu_physical_memory_rw(ptr, buf, n, write); + if (n == len) + return; + ptr = end_addr & ~0xfffu; + buf += n; + cpu_physical_memory_rw(ptr, buf, len - n, write); +} + +static void ohci_process_lists(OHCIState *ohci, int completion); + +static void ohci_async_complete_packet(USBPacket *packet, void *opaque) { OHCIState *ohci = opaque; #ifdef DEBUG_PACKET dprintf("Async packet complete\n"); #endif ohci->async_complete = 1; - ohci_process_lists(ohci); + ohci_process_lists(ohci, 1); +} + +#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b))) + +static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, + int completion) +{ + int dir; + size_t len = 0; + char *str = NULL; + int pid; + int ret; + int i; + USBDevice *dev; + struct ohci_iso_td iso_td; + uint32_t addr; + uint16_t starting_frame; + int16_t relative_frame_number; + int frame_count; + uint32_t start_offset, next_offset, end_offset = 0; + uint32_t start_addr, end_addr; + + addr = ed->head & OHCI_DPTR_MASK; + + if (!ohci_read_iso_td(addr, &iso_td)) { + printf("usb-ohci: ISO_TD read error at %x\n", addr); + return 0; + } + + starting_frame = OHCI_BM(iso_td.flags, TD_SF); + frame_count = OHCI_BM(iso_td.flags, TD_FC); + relative_frame_number = USUB(ohci->frame_number, starting_frame); + +#ifdef DEBUG_ISOCH + printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n" + "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n" + "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n" + "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n" + "frame_number 0x%.8x starting_frame 0x%.8x\n" + "frame_count 0x%.8x relative %d\n" + "di 0x%.8x cc 0x%.8x\n", + ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK, + iso_td.flags, iso_td.bp, iso_td.next, iso_td.be, + iso_td.offset[0], iso_td.offset[1], iso_td.offset[2], iso_td.offset[3], + iso_td.offset[4], iso_td.offset[5], iso_td.offset[6], iso_td.offset[7], + ohci->frame_number, starting_frame, + frame_count, relative_frame_number, + OHCI_BM(iso_td.flags, TD_DI), OHCI_BM(iso_td.flags, TD_CC)); +#endif + + if (relative_frame_number < 0) { + dprintf("usb-ohci: ISO_TD R=%d < 0\n", relative_frame_number); + return 1; + } else if (relative_frame_number > frame_count) { + /* ISO TD expired - retire the TD to the Done Queue and continue with + the next ISO TD of the same ED */ + dprintf("usb-ohci: ISO_TD R=%d > FC=%d\n", relative_frame_number, + frame_count); + OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN); + ed->head &= ~OHCI_DPTR_MASK; + ed->head |= (iso_td.next & OHCI_DPTR_MASK); + iso_td.next = ohci->done; + ohci->done = addr; + i = OHCI_BM(iso_td.flags, TD_DI); + if (i < ohci->done_count) + ohci->done_count = i; + ohci_put_iso_td(addr, &iso_td); + return 0; + } + + dir = OHCI_BM(ed->flags, ED_D); + switch (dir) { + case OHCI_TD_DIR_IN: + str = "in"; + pid = USB_TOKEN_IN; + break; + case OHCI_TD_DIR_OUT: + str = "out"; + pid = USB_TOKEN_OUT; + break; + case OHCI_TD_DIR_SETUP: + str = "setup"; + pid = USB_TOKEN_SETUP; + break; + default: + printf("usb-ohci: Bad direction %d\n", dir); + return 1; + } + + if (!iso_td.bp || !iso_td.be) { + printf("usb-ohci: ISO_TD bp 0x%.8x be 0x%.8x\n", iso_td.bp, iso_td.be); + return 1; + } + + start_offset = iso_td.offset[relative_frame_number]; + next_offset = iso_td.offset[relative_frame_number + 1]; + + if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) || + ((relative_frame_number < frame_count) && + !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) { + printf("usb-ohci: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n", + start_offset, next_offset); + return 1; + } + + if ((relative_frame_number < frame_count) && (start_offset > next_offset)) { + printf("usb-ohci: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n", + start_offset, next_offset); + return 1; + } + + if ((start_offset & 0x1000) == 0) { + start_addr = (iso_td.bp & OHCI_PAGE_MASK) | + (start_offset & OHCI_OFFSET_MASK); + } else { + start_addr = (iso_td.be & OHCI_PAGE_MASK) | + (start_offset & OHCI_OFFSET_MASK); + } + + if (relative_frame_number < frame_count) { + end_offset = next_offset - 1; + if ((end_offset & 0x1000) == 0) { + end_addr = (iso_td.bp & OHCI_PAGE_MASK) | + (end_offset & OHCI_OFFSET_MASK); + } else { + end_addr = (iso_td.be & OHCI_PAGE_MASK) | + (end_offset & OHCI_OFFSET_MASK); + } + } else { + /* Last packet in the ISO TD */ + end_addr = iso_td.be; + } + + if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) { + len = (end_addr & OHCI_OFFSET_MASK) + 0x1001 + - (start_addr & OHCI_OFFSET_MASK); + } else { + len = end_addr - start_addr + 1; + } + + if (len && dir != OHCI_TD_DIR_IN) { + ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, len, 0); + } + + if (completion) { + ret = ohci->usb_packet.len; + } else { + ret = USB_RET_NODEV; + for (i = 0; i < ohci->num_ports; i++) { + dev = ohci->rhport[i].port.dev; + if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) + continue; + ohci->usb_packet.pid = pid; + ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA); + ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN); + ohci->usb_packet.data = ohci->usb_buf; + ohci->usb_packet.len = len; + ohci->usb_packet.complete_cb = ohci_async_complete_packet; + ohci->usb_packet.complete_opaque = ohci; + ret = dev->handle_packet(dev, &ohci->usb_packet); + if (ret != USB_RET_NODEV) + break; + } + + if (ret == USB_RET_ASYNC) { + return 1; + } + } + +#ifdef DEBUG_ISOCH + printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n", + start_offset, end_offset, start_addr, end_addr, str, len, ret); +#endif + + /* Writeback */ + if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) { + /* IN transfer succeeded */ + ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, ret, 1); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, + OHCI_CC_NOERROR); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret); + } else if (dir == OHCI_TD_DIR_OUT && ret == len) { + /* OUT transfer succeeded */ + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, + OHCI_CC_NOERROR); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0); + } else { + if (ret > len) { + printf("usb-ohci: DataOverrun %d > %zu\n", ret, len); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, + OHCI_CC_DATAOVERRUN); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, + len); + } else if (ret >= 0) { + printf("usb-ohci: DataUnderrun %d\n", ret); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, + OHCI_CC_DATAUNDERRUN); + } else { + switch (ret) { + case USB_RET_NODEV: + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, + OHCI_CC_DEVICENOTRESPONDING); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, + 0); + break; + case USB_RET_NAK: + case USB_RET_STALL: + printf("usb-ohci: got NAK/STALL %d\n", ret); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, + OHCI_CC_STALL); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, + 0); + break; + default: + printf("usb-ohci: Bad device response %d\n", ret); + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, + OHCI_CC_UNDEXPETEDPID); + break; + } + } + } + + if (relative_frame_number == frame_count) { + /* Last data packet of ISO TD - retire the TD to the Done Queue */ + OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR); + ed->head &= ~OHCI_DPTR_MASK; + ed->head |= (iso_td.next & OHCI_DPTR_MASK); + iso_td.next = ohci->done; + ohci->done = addr; + i = OHCI_BM(iso_td.flags, TD_DI); + if (i < ohci->done_count) + ohci->done_count = i; + } + ohci_put_iso_td(addr, &iso_td); + return 1; } /* Service a transport descriptor. @@ -671,7 +989,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) } /* Service an endpoint list. Returns nonzero if active TD were found. */ -static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) +static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) { struct ohci_ed ed; uint32_t next_ed; @@ -702,10 +1020,6 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) continue; } - /* Skip isochronous endpoints. */ - if (ed.flags & OHCI_ED_F) - continue; - while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { #ifdef DEBUG_PACKET dprintf("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u " @@ -719,8 +1033,14 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) #endif active = 1; - if (ohci_service_td(ohci, &ed)) - break; + if ((ed.flags & OHCI_ED_F) == 0) { + if (ohci_service_td(ohci, &ed)) + break; + } else { + /* Handle isochronous endpoints */ + if (ohci_service_iso_td(ohci, &ed, completion)) + break; + } } ohci_put_ed(cur, &ed); @@ -738,19 +1058,19 @@ static void ohci_sof(OHCIState *ohci) } /* Process Control and Bulk lists. */ -static void ohci_process_lists(OHCIState *ohci) +static void ohci_process_lists(OHCIState *ohci, int completion) { if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); - if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { + if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) { ohci->ctrl_cur = 0; ohci->status &= ~OHCI_STATUS_CLF; } } if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { - if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { + if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) { ohci->bulk_cur = 0; ohci->status &= ~OHCI_STATUS_BLF; } @@ -770,7 +1090,7 @@ static void ohci_frame_boundary(void *opaque) int n; n = ohci->frame_number & 0x1f; - ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n])); + ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0); } /* Cancel all pending packets if either of the lists has been disabled. */ @@ -780,7 +1100,7 @@ static void ohci_frame_boundary(void *opaque) ohci->async_td = 0; } ohci->old_ctl = ohci->ctl; - ohci_process_lists(ohci); + ohci_process_lists(ohci, 0); /* Frame boundary, so do EOF stuf here */ ohci->frt = ohci->fit; @@ -1206,6 +1526,9 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) ohci_set_frame_interval(ohci, val); break; + case 15: /* HcFmNumber */ + break; + case 16: /* HcPeriodicStart */ ohci->pstart = val & 0xffff; break; -- cgit v1.2.3 From 405ee3ad573c35790500048d07d5c7ac93167e6a Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 00:47:13 +0000 Subject: Invalidate TLBs when domains are changed (Matthew Warton). Legalise cp15 pid register writes (Matthew Warton). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3494 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 4f851ce22..d06ee69e7 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -704,6 +704,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) break; case 3: /* MMU Domain access control / MPU write buffer control. */ env->cp15.c3 = val; + tlb_flush(env, 1); /* Flush TLB as domain not tracked in TLB */ break; case 4: /* Reserved. */ goto bad_reg; @@ -814,8 +815,6 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 13: /* Process ID. */ switch (op2) { case 0: - if (!arm_feature(env, ARM_FEATURE_MPU)) - goto bad_reg; /* Unlike real hardware the qemu TLB uses virtual addresses, not modified virtual addresses, so this causes a TLB flush. */ -- cgit v1.2.3 From fe8f78e4fb11f624764c75dd7e1337a20ad1f92e Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 01:03:28 +0000 Subject: Add gcc-3.4.6 to the list of gcc3 versions (Carlo Marcelo Arenas Belon). Add --disable-sdl to configure's help (Carlo Marcelo Arenas Belon). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3495 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index ba734673c..c8a78b969 100755 --- a/configure +++ b/configure @@ -23,7 +23,7 @@ static="no" cross_prefix="" cc="gcc" gcc3_search="yes" -gcc3_list="gcc-3.4 gcc34 gcc-3.3.6 gcc-3.3 gcc33 gcc-3.2 gcc32" +gcc3_list="gcc-3.4.6 gcc-3.4 gcc34 gcc-3.3.6 gcc-3.3 gcc33 gcc-3.2 gcc32" host_cc="gcc" ar="ar" make="make" @@ -377,6 +377,7 @@ 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 " --disable-sdl disable SDL" echo " --enable-cocoa enable COCOA (Mac OS X only)" echo " --enable-mingw32 enable Win32 cross compilation with mingw32" echo " --enable-adlib enable Adlib emulation" -- cgit v1.2.3 From 926c2d23dfa599ea8c8213342b21cfe56b1d22ca Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 01:11:44 +0000 Subject: Support multipart images as input to qemu-img (Salvador Fandino). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3496 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 18 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index b84b75b43..8ebc4ba31 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -23,6 +23,7 @@ */ #include "vl.h" #include "block_int.h" +#include #ifdef _WIN32 #include @@ -101,7 +102,7 @@ void help(void) "Command syntax:\n" " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" " commit [-f fmt] filename\n" - " convert [-c] [-e] [-6] [-f fmt] filename [-O output_fmt] output_filename\n" + " convert [-c] [-e] [-6] [-f fmt] filename [filename2 [...]] [-O output_fmt] output_filename\n" " info [-f fmt] filename\n" "\n" "Command parameters:\n" @@ -418,11 +419,11 @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum) static int img_convert(int argc, char **argv) { - int c, ret, n, n1, flags, cluster_size, cluster_sectors; - const char *filename, *fmt, *out_fmt, *out_filename; + int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors; + const char *fmt, *out_fmt, *out_filename; BlockDriver *drv; - BlockDriverState *bs, *out_bs; - int64_t total_sectors, nb_sectors, sector_num; + BlockDriverState **bs, *out_bs; + int64_t total_sectors, nb_sectors, sector_num, bs_offset, bs_sectors; uint8_t buf[IO_BUF_SIZE]; const uint8_t *buf1; BlockDriverInfo bdi; @@ -455,14 +456,24 @@ static int img_convert(int argc, char **argv) break; } } - if (optind >= argc) - help(); - filename = argv[optind++]; - if (optind >= argc) - help(); - out_filename = argv[optind++]; - bs = bdrv_new_open(filename, fmt); + bs_n = argc - optind - 1; + if (bs_n < 1) help(); + + out_filename = argv[argc - 1]; + + bs = calloc(bs_n, sizeof(BlockDriverState *)); + if (!bs) + error("Out of memory"); + + total_sectors = 0; + for (bs_i = 0; bs_i < bs_n; bs_i++) { + bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt); + if (!bs[bs_i]) + error("Could not open '%s'", argv[optind + bs_i]); + bdrv_get_geometry(bs[bs_i], &bs_sectors); + total_sectors += bs_sectors; + } drv = bdrv_find_format(out_fmt); if (!drv) @@ -475,7 +486,7 @@ static int img_convert(int argc, char **argv) error("Alternative compatibility level not supported for this file format"); if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS) error("Compression and encryption not supported at the same time"); - bdrv_get_geometry(bs, &total_sectors); + ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags); if (ret < 0) { if (ret == -ENOTSUP) { @@ -487,7 +498,11 @@ static int img_convert(int argc, char **argv) out_bs = bdrv_new_open(out_filename, out_fmt); - if (flags && BLOCK_FLAG_COMPRESS) { + bs_i = 0; + bs_offset = 0; + bdrv_get_geometry(bs[0], &bs_sectors); + + if (flags & BLOCK_FLAG_COMPRESS) { if (bdrv_get_info(out_bs, &bdi) < 0) error("could not get block driver info"); cluster_size = bdi.cluster_size; @@ -496,6 +511,10 @@ static int img_convert(int argc, char **argv) cluster_sectors = cluster_size >> 9; sector_num = 0; for(;;) { + int64_t bs_num; + int remainder; + uint8_t *buf2; + nb_sectors = total_sectors - sector_num; if (nb_sectors <= 0) break; @@ -503,8 +522,37 @@ static int img_convert(int argc, char **argv) n = cluster_sectors; else n = nb_sectors; - if (bdrv_read(bs, sector_num, buf, n) < 0) - error("error while reading"); + + bs_num = sector_num - bs_offset; + assert (bs_num >= 0); + remainder = n; + buf2 = buf; + while (remainder > 0) { + int nlow; + while (bs_num == bs_sectors) { + bs_i++; + assert (bs_i < bs_n); + bs_offset += bs_sectors; + bdrv_get_geometry(bs[bs_i], &bs_sectors); + bs_num = 0; + /* printf("changing part: sector_num=%lld, " + "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n", + sector_num, bs_i, bs_offset, bs_sectors); */ + } + assert (bs_num < bs_sectors); + + nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder; + + if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) + error("error while reading"); + + buf2 += nlow * 512; + bs_num += nlow; + + remainder -= nlow; + } + assert (remainder == 0); + if (n < cluster_sectors) memset(buf + n * 512, 0, cluster_size - n * 512); if (is_not_zero(buf, cluster_size)) { @@ -527,7 +575,21 @@ static int img_convert(int argc, char **argv) n = (IO_BUF_SIZE / 512); else n = nb_sectors; - if (bdrv_read(bs, sector_num, buf, n) < 0) + + while (sector_num - bs_offset >= bs_sectors) { + bs_i ++; + assert (bs_i < bs_n); + bs_offset += bs_sectors; + bdrv_get_geometry(bs[bs_i], &bs_sectors); + /* printf("changing part: sector_num=%lld, bs_i=%d, " + "bs_offset=%lld, bs_sectors=%lld\n", + sector_num, bs_i, bs_offset, bs_sectors); */ + } + + if (n > bs_offset + bs_sectors - sector_num) + n = bs_offset + bs_sectors - sector_num; + + if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) error("error while reading"); /* NOTE: at the same time we convert, we do not write zero sectors to have a chance to compress the image. Ideally, we @@ -545,7 +607,9 @@ static int img_convert(int argc, char **argv) } } bdrv_delete(out_bs); - bdrv_delete(bs); + for (bs_i = 0; bs_i < bs_n; bs_i++) + bdrv_delete(bs[bs_i]); + free(bs); return 0; } -- cgit v1.2.3 From 6ac0e82da197d42b84f6ac5509fa22f90cb357be Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 01:54:04 +0000 Subject: Set boot sequence from command line (Dan Kenigsberg). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3497 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/an5206.c | 2 +- hw/etraxfs.c | 2 +- hw/integratorcp.c | 5 +++-- hw/mcf5208.c | 5 +++-- hw/mips_malta.c | 2 +- hw/mips_mipssim.c | 2 +- hw/mips_pica61.c | 2 +- hw/mips_r4k.c | 2 +- hw/palm.c | 5 +++-- hw/pc.c | 49 +++++++++++++++++++++++++++---------------------- hw/ppc405_boards.c | 18 ++++++++++-------- hw/ppc_chrp.c | 13 +++++++------ hw/ppc_oldworld.c | 13 +++++++------ hw/ppc_prep.c | 7 ++++--- hw/r2d.c | 2 +- hw/realview.c | 5 +++-- hw/shix.c | 2 +- hw/spitz.c | 20 ++++++++++++-------- hw/sun4m.c | 13 +++++++------ hw/sun4u.c | 4 ++-- hw/versatilepb.c | 9 +++++---- vl.c | 40 ++++++++++++++++++++++++++-------------- vl.h | 2 +- 23 files changed, 128 insertions(+), 96 deletions(-) diff --git a/hw/an5206.c b/hw/an5206.c index 94ecccb3e..d9931df59 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -27,7 +27,7 @@ void DMA_run (void) /* Board init. */ -static void an5206_init(int ram_size, int vga_ram_size, int boot_device, +static void an5206_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/etraxfs.c b/hw/etraxfs.c index cf0f38493..6697c7d5d 100644 --- a/hw/etraxfs.c +++ b/hw/etraxfs.c @@ -107,7 +107,7 @@ static void dummy_cpu_set_irq(void *opaque, int irq, int level) } static -void bareetraxfs_init (int ram_size, int vga_ram_size, int boot_device, +void bareetraxfs_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 83c6208cf..5d2c65125 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -462,8 +462,9 @@ static void icp_control_init(uint32_t base) /* Board init. */ -static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void integratorcp_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 993a68694..bcb1c80be 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -197,8 +197,9 @@ static void mcf5208_sys_init(qemu_irq *pic) } } -static void mcf5208evb_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void mcf5208evb_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 6f0edf9a3..9d099a053 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -740,7 +740,7 @@ static void main_cpu_reset(void *opaque) } static -void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, +void mips_malta_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index b7b834fc2..0a2e456e4 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -74,7 +74,7 @@ static void main_cpu_reset(void *opaque) } static void -mips_mipssim_init (int ram_size, int vga_ram_size, int boot_device, +mips_mipssim_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 958404617..d79f7bea3 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -55,7 +55,7 @@ static void main_cpu_reset(void *opaque) } static -void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device, +void mips_pica61_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index ce7aaff9d..dfcf86758 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -137,7 +137,7 @@ static void main_cpu_reset(void *opaque) } static -void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, +void mips_r4k_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/palm.c b/hw/palm.c index a6c9f7d97..c21b44a9d 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -115,8 +115,9 @@ static void palmte_button_event(void *opaque, int keycode) !(keycode & 0x80)); } -static void palmte_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void palmte_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/pc.c b/hw/pc.c index c561cbf2e..8a1c57752 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -152,8 +152,25 @@ static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) rtc_set_memory(s, info_ofs + 8, sectors); } +/* convert boot_device letter to something recognizable by the bios */ +static int boot_device2nibble(char boot_device) +{ + switch(boot_device) { + case 'a': + case 'b': + return 0x01; /* floppy boot */ + case 'c': + return 0x02; /* hard drive boot */ + case 'd': + return 0x03; /* CD-ROM boot */ + case 'n': + return 0x04; /* Network boot */ + } + return 0; +} + /* hd_table must contain 4 block drivers */ -static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table) +static void cmos_init(int ram_size, const char *boot_device, BlockDriverState **hd_table) { RTCState *s = rtc_state; int val; @@ -184,24 +201,12 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); - switch(boot_device) { - case 'a': - case 'b': - rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ - if (!fd_bootchk) - rtc_set_memory(s, 0x38, 0x01); /* disable signature check */ - break; - default: - case 'c': - rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */ - break; - case 'd': - rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */ - break; - case 'n': - rtc_set_memory(s, 0x3d, 0x04); /* Network boot */ - break; - } + /* set boot devices, and disable floppy signature check if requested */ + rtc_set_memory(s, 0x3d, + boot_device2nibble(boot_device[1]) << 4 | + boot_device2nibble(boot_device[0]) ); + rtc_set_memory(s, 0x38, + boot_device2nibble(boot_device[2]) << 4 | (fd_bootchk ? 0x0 : 0x1)); /* floppy type */ @@ -663,7 +668,7 @@ static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic) } /* PC hardware initialisation */ -static void pc_init1(int ram_size, int vga_ram_size, int boot_device, +static void pc_init1(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, @@ -940,7 +945,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, #endif } -static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, +static void pc_init_pci(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, @@ -954,7 +959,7 @@ static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, initrd_filename, 1); } -static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device, +static void pc_init_isa(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 8c00148d7..ab134418f 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -171,9 +171,9 @@ static void ref405ep_fpga_init (uint32_t base) } } -static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, +static void ref405ep_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, @@ -191,6 +191,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, target_ulong kernel_base, kernel_size, initrd_base, initrd_size; int linux_boot; int fl_idx, fl_sectors, len; + int ppc_boot_device = boot_device[0]; /* XXX: fix this */ ram_bases[0] = 0x00000000; @@ -322,7 +323,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device, } env->gpr[4] = initrd_base; env->gpr[5] = initrd_size; - boot_device = 'm'; + ppc_boot_device = 'm'; if (kernel_cmdline != NULL) { len = strlen(kernel_cmdline); bdloc -= ((len + 255) & ~255); @@ -496,9 +497,9 @@ static void taihu_cpld_init (uint32_t base) } } -static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, +static void taihu_405ep_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, @@ -513,6 +514,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, target_ulong kernel_base, kernel_size, initrd_base, initrd_size; int linux_boot; int fl_idx, fl_sectors; + int ppc_boot_device = boot_device[0]; /* RAM is soldered to the board so the size cannot be changed */ ram_bases[0] = 0x00000000; @@ -615,7 +617,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device, initrd_base = 0; initrd_size = 0; } - boot_device = 'm'; + ppc_boot_device = 'm'; } else { kernel_base = 0; kernel_size = 0; diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index b97f99f8b..daa99d585 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -48,9 +48,9 @@ static CPUReadMemoryFunc *unin_read[] = { }; /* PowerPC Mac99 hardware initialisation */ -static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, +static void ppc_core99_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, @@ -75,6 +75,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, qemu_irq *dummy_irq; int pic_mem_index, dbdma_mem_index, cuda_mem_index; int ide_mem_index[2]; + int ppc_boot_device = boot_device[0]; linux_boot = (kernel_filename != NULL); @@ -171,7 +172,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, initrd_base = 0; initrd_size = 0; } - boot_device = 'm'; + ppc_boot_device = 'm'; } else { kernel_base = 0; kernel_size = 0; @@ -285,8 +286,8 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device, nvram.read_fn = &m48t59_read; nvram.write_fn = &m48t59_write; #endif - PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "MAC99", ram_size, boot_device, - kernel_base, kernel_size, + PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "MAC99", ram_size, + ppc_boot_device, kernel_base, kernel_size, kernel_cmdline, initrd_base, initrd_size, /* XXX: need an option to load a NVRAM image */ diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 946ebd176..7a0850522 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -92,9 +92,9 @@ static int vga_osi_call (CPUState *env) return 1; /* osi_call handled */ } -static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, +static void ppc_heathrow_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, @@ -114,6 +114,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, int vga_bios_size, bios_size; qemu_irq *dummy_irq; int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index; + int ppc_boot_device = boot_device[0]; linux_boot = (kernel_filename != NULL); @@ -208,7 +209,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, initrd_base = 0; initrd_size = 0; } - boot_device = 'm'; + ppc_boot_device = 'm'; } else { kernel_base = 0; kernel_size = 0; @@ -289,8 +290,8 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device, nvram.opaque = m48t59; nvram.read_fn = &m48t59_read; nvram.write_fn = &m48t59_write; - PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "HEATHROW", ram_size, boot_device, - kernel_base, kernel_size, + PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "HEATHROW", ram_size, + ppc_boot_device, kernel_base, kernel_size, kernel_cmdline, initrd_base, initrd_size, /* XXX: need an option to load a NVRAM image */ diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 49b363267..c557f878a 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -521,7 +521,7 @@ CPUReadMemoryFunc *PPC_prep_io_read[] = { #define NVRAM_SIZE 0x2000 /* PowerPC PREP hardware initialisation */ -static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, +static void ppc_prep_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -539,6 +539,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, ppc_def_t *def; PCIBus *pci_bus; qemu_irq *i8259; + int ppc_boot_device = boot_device[0]; sysctrl = qemu_mallocz(sizeof(sysctrl_t)); if (sysctrl == NULL) @@ -607,7 +608,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, initrd_base = 0; initrd_size = 0; } - boot_device = 'm'; + ppc_boot_device = 'm'; } else { kernel_base = 0; kernel_size = 0; @@ -695,7 +696,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, nvram.opaque = m48t59; nvram.read_fn = &m48t59_read; nvram.write_fn = &m48t59_write; - PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, + PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "PREP", ram_size, ppc_boot_device, kernel_base, kernel_size, kernel_cmdline, initrd_base, initrd_size, diff --git a/hw/r2d.c b/hw/r2d.c index 33d03cbbf..fa3505100 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -27,7 +27,7 @@ #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ #define SDRAM_SIZE 0x04000000 -void r2d_init(int ram_size, int vga_ram_size, int boot_device, +static void r2d_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState * ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/realview.c b/hw/realview.c index 375f78acd..b2f4ff278 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -12,8 +12,9 @@ /* Board init. */ -static void realview_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void realview_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/shix.c b/hw/shix.c index 884178e94..e65427a4c 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -62,7 +62,7 @@ void vga_screen_dump(const char *filename) /* XXXXX */ } -void shix_init(int ram_size, int vga_ram_size, int boot_device, +static void shix_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState * ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/spitz.c b/hw/spitz.c index aca244ee2..68bba18e1 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1228,8 +1228,9 @@ static void spitz_common_init(int ram_size, int vga_ram_size, sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE); } -static void spitz_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void spitz_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -1237,8 +1238,9 @@ static void spitz_init(int ram_size, int vga_ram_size, int boot_device, kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9); } -static void borzoi_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void borzoi_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -1246,8 +1248,9 @@ static void borzoi_init(int ram_size, int vga_ram_size, int boot_device, kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f); } -static void akita_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void akita_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -1255,8 +1258,9 @@ static void akita_init(int ram_size, int vga_ram_size, int boot_device, kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8); } -static void terrier_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void terrier_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/sun4m.c b/hw/sun4m.c index a12aec9e8..b3328021d 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -158,7 +158,7 @@ static void nvram_finish_partition (m48t59_t *nvram, uint32_t start, extern int nographic; static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, - int boot_device, uint32_t RAM_size, + const char *boot_device, uint32_t RAM_size, uint32_t kernel_size, int width, int height, int depth, int machine_id) @@ -175,7 +175,7 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, m48t59_write(nvram, 0x2E, 0); m48t59_write(nvram, 0x2F, nographic & 0xff); nvram_set_lword(nvram, 0x30, RAM_size); - m48t59_write(nvram, 0x34, boot_device & 0xff); + m48t59_write(nvram, 0x34, boot_device[0] & 0xff); nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR); nvram_set_lword(nvram, 0x3C, kernel_size); if (cmdline) { @@ -408,7 +408,8 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, return nvram; } -static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device, +static void sun4m_load_kernel(long vram_size, int RAM_size, + const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, @@ -548,7 +549,7 @@ static const struct hwdef hwdefs[] = { }, }; -static void sun4m_common_init(int RAM_size, int boot_device, DisplayState *ds, +static void sun4m_common_init(int RAM_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, unsigned int machine, int max_ram) @@ -569,7 +570,7 @@ static void sun4m_common_init(int RAM_size, int boot_device, DisplayState *ds, } /* SPARCstation 5 hardware initialisation */ -static void ss5_init(int RAM_size, int vga_ram_size, int boot_device, +static void ss5_init(int RAM_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -582,7 +583,7 @@ static void ss5_init(int RAM_size, int vga_ram_size, int boot_device, } /* SPARCstation 10 hardware initialisation */ -static void ss10_init(int RAM_size, int vga_ram_size, int boot_device, +static void ss10_init(int RAM_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/sun4u.c b/hw/sun4u.c index bac0ebf46..317ba741a 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -331,7 +331,7 @@ static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; static fdctrl_t *floppy_controller; /* Sun4u hardware initialisation */ -static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, +static void sun4u_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -456,7 +456,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, i8042_init(NULL/*1*/, NULL/*12*/, 0x60); floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table); nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59); - sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device, + sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device[0], KERNEL_LOAD_ADDR, kernel_size, kernel_cmdline, INITRD_LOAD_ADDR, initrd_size, diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 2e3dedd81..31d58ef7a 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -151,8 +151,9 @@ static qemu_irq *vpb_sic_init(uint32_t base, qemu_irq *parent, int irq) peripherans and expansion busses. For now we emulate a subset of the PB peripherals and just change the board ID. */ -static void versatile_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void versatile_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, int board_id) @@ -266,7 +267,7 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, initrd_filename, board_id, 0x0); } -static void vpb_init(int ram_size, int vga_ram_size, int boot_device, +static void vpb_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -277,7 +278,7 @@ static void vpb_init(int ram_size, int vga_ram_size, int boot_device, initrd_filename, cpu_model, 0x183); } -static void vab_init(int ram_size, int vga_ram_size, int boot_device, +static void vab_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/vl.c b/vl.c index f9500a967..73a22da5c 100644 --- a/vl.c +++ b/vl.c @@ -162,7 +162,12 @@ static DisplayState display_state; int nographic; const char* keyboard_layout = NULL; int64_t ticks_per_sec; -int boot_device = 'c'; +#if defined(TARGET_I386) +#define MAX_BOOT_DEVICES 3 +#else +#define MAX_BOOT_DEVICES 1 +#endif +static char boot_device[MAX_BOOT_DEVICES + 1]; int ram_size; int pit_min_timer_count = 0; int nb_nics; @@ -7810,14 +7815,19 @@ int main(int argc, char **argv) } break; case QEMU_OPTION_boot: - boot_device = optarg[0]; - if (boot_device != 'a' && + if (strlen(optarg) > MAX_BOOT_DEVICES) { + fprintf(stderr, "qemu: too many boot devices\n"); + exit(1); + } + strncpy(boot_device, optarg, MAX_BOOT_DEVICES); #if defined(TARGET_SPARC) || defined(TARGET_I386) - // Network boot - boot_device != 'n' && +#define BOOTCHARS "acdn" +#else +#define BOOTCHARS "acd" #endif - boot_device != 'c' && boot_device != 'd') { - fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device); + if (strlen(boot_device) != strspn(boot_device, BOOTCHARS)) { + fprintf(stderr, "qemu: invalid boot device " + "sequence '%s'\n", boot_device); exit(1); } break; @@ -8168,20 +8178,22 @@ int main(int argc, char **argv) linux_boot = (kernel_filename != NULL); if (!linux_boot && - boot_device != 'n' && + (!strchr(boot_device, 'n')) && hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') help(1); /* boot to floppy or the default cd if no hard disk defined yet */ - if (hd_filename[0] == '\0' && boot_device == 'c') { - if (fd_filename[0] != '\0') - boot_device = 'a'; + if (!boot_device[0]) { + if (hd_filename[0] != '\0') + boot_device[0] = 'c'; + else if (fd_filename[0] != '\0') + boot_device[0] = 'a'; else - boot_device = 'd'; + boot_device[0] = 'd'; + boot_device[1] = 0; } - setvbuf(stdout, NULL, _IOLBF, 0); init_timers(); @@ -8220,7 +8232,7 @@ int main(int argc, char **argv) } #ifdef TARGET_I386 - if (boot_device == 'n') { + if (strchr(boot_device, 'n')) { for (i = 0; i < nb_nics; i++) { const char *model = nd_table[i].model; char buf[1024]; diff --git a/vl.h b/vl.h index 90fdcf913..2ef8886a1 100644 --- a/vl.h +++ b/vl.h @@ -731,7 +731,7 @@ void path_combine(char *dest, int dest_size, #ifndef QEMU_TOOL typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, - int boot_device, + const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model); -- cgit v1.2.3 From a26c97adce76e23ab4ad2ad152d77291ad495484 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 01:58:56 +0000 Subject: Handle 3.7 VNC clients authentication correctly (Dan Kenigsberg). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3498 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vnc.c b/vnc.c index 83d001161..88cca3b73 100644 --- a/vnc.c +++ b/vnc.c @@ -1806,7 +1806,10 @@ static int protocol_client_auth(VncState *vs, char *data, size_t len) switch (vs->auth) { case VNC_AUTH_NONE: VNC_DEBUG("Accept auth none\n"); - vnc_write_u32(vs, 0); /* Accept auth completion */ + if (vs->minor >= 8) { + vnc_write_u32(vs, 0); /* Accept auth completion */ + vnc_flush(vs); + } vnc_read_when(vs, protocol_client_init, 1); break; -- cgit v1.2.3 From ad8488750bc09eefc2469a6eb8b2dd2abf0940c3 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 31 Oct 2007 02:01:33 +0000 Subject: Correct the WBINVD intercept in SVM (Alexander Graf). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3499 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index cd9541265..7ab8f4b69 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6010,7 +6010,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVD)) + if (gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD)) break; /* nothing to do */ } -- cgit v1.2.3 From a79ee211ceee191de97d0862a93128e7688a2843 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 31 Oct 2007 17:14:08 +0000 Subject: Add copyright and license header. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3500 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_mipssim.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 0a2e456e4..11bad5970 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -3,6 +3,26 @@ * * Emulates a very simple machine model similiar to the one use by the * proprietary MIPS emulator. + * + * Copyright (c) 2007 Thiemo Seufer + * + * 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" -- cgit v1.2.3 From fc0d441e14f07a35f9ea67ac8ca032a2ea902b38 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 31 Oct 2007 22:02:17 +0000 Subject: Fix CR ops with complement, thanks to Julian Seward for testing and reporting the bug : * remove bugged CR ops specific micro-ops * use standard and / or / shift operations instead * comment not-used-anymore op_store_T1_crf_crf micro-op template. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3501 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 25 ++++++------------------- target-ppc/op_template.h | 2 ++ target-ppc/translate.c | 24 +++++++++++++++++++----- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 4c170d84b..da08ec526 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -651,25 +651,6 @@ void OPPROTO op_store_fpscr (void) RETURN(); } -/* crf operations */ -void OPPROTO op_getbit_T0 (void) -{ - T0 = (T0 >> PARAM1) & 1; - RETURN(); -} - -void OPPROTO op_getbit_T1 (void) -{ - T1 = (T1 >> PARAM1) & 1; - RETURN(); -} - -void OPPROTO op_setcrfbit (void) -{ - T1 = (T1 & (uint32_t)PARAM1) | (T0 << PARAM2); - RETURN(); -} - /* Branch */ #define EIP env->nip @@ -1737,6 +1718,12 @@ void OPPROTO op_sli_T0 (void) RETURN(); } +void OPPROTO op_sli_T1 (void) +{ + T1 = T1 << PARAM1; + RETURN(); +} + void OPPROTO op_srl_T0_T1 (void) { T0 = (uint32_t)T0 >> T1; diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index bdd884432..51f9b3681 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -159,11 +159,13 @@ void OPPROTO glue(op_store_T0_crf_crf, REG) (void) RETURN(); } +#if 0 // Unused void OPPROTO glue(op_store_T1_crf_crf, REG) (void) { env->crf[REG] = T1; RETURN(); } +#endif #endif /* REG <= 7 */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c3e5340f2..015a6215a 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -120,7 +120,9 @@ static always_inline void func (int n) \ GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf); GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf); GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf); +#if 0 // Unused GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf); +#endif /* General purpose registers moves */ GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr); @@ -3318,15 +3320,27 @@ GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW) #define GEN_CRLOGIC(op, opc) \ GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \ { \ + uint8_t bitmask; \ + int sh; \ gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \ - gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03)); \ + sh = (crbD(ctx->opcode) & 0x03) - (crbA(ctx->opcode) & 0x03); \ + if (sh > 0) \ + gen_op_srli_T0(sh); \ + else if (sh < 0) \ + gen_op_sli_T0(-sh); \ gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \ - gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03)); \ + sh = (crbD(ctx->opcode) & 0x03) - (crbB(ctx->opcode) & 0x03); \ + if (sh > 0) \ + gen_op_srli_T1(sh); \ + else if (sh < 0) \ + gen_op_sli_T1(-sh); \ gen_op_##op(); \ + bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03)); \ + gen_op_andi_T0(bitmask); \ gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \ - gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \ - 3 - (crbD(ctx->opcode) & 0x03)); \ - gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \ + gen_op_andi_T1(~bitmask); \ + gen_op_or(); \ + gen_op_store_T0_crf(crbD(ctx->opcode) >> 2); \ } /* crand */ -- cgit v1.2.3 From b92c47c1cc25bafd75d81f121e06b68b35d0beed Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 1 Nov 2007 00:07:38 +0000 Subject: Strace for userland emulation, by Stuart Anderson and Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3502 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- linux-user/main.c | 4 ++++ linux-user/qemu.h | 8 ++++++++ linux-user/syscall.c | 35 +++++++++++++++++++++++++++++++++-- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/Makefile.target b/Makefile.target index 33dc285bb..07047c18a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -259,7 +259,7 @@ main.o: BASE_CFLAGS+=-p endif ifdef CONFIG_LINUX_USER -OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \ +OBJS= main.o syscall.o strace.o mmap.o signal.o path.o osdep.o thunk.o \ elfload.o linuxload.o LIBS+= $(AIOLIBS) ifdef TARGET_HAS_BFLT diff --git a/linux-user/main.c b/linux-user/main.c index 88a2e4886..6a026b012 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1980,6 +1980,10 @@ int main(int argc, char **argv) env = cpu_init(); global_env = env; + if(getenv("QEMU_STRACE") ){ + do_strace=1; + } + wrk = environ; while (*(wrk++)) environ_count++; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index e92db6ee6..22a4fec61 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -153,10 +153,18 @@ extern CPUState *global_env; void cpu_loop(CPUState *env); void init_paths(const char *prefix); const char *path(const char *pathname); +char *target_strerror(int err); extern int loglevel; extern FILE *logfile; +/* strace.c */ +void print_syscall(int num, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6); +void print_syscall_ret(int num, target_long arg1); +extern int do_strace; + /* signal.c */ void process_pending_signals(void *cpu_env); void signal_init(void); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6d1997e09..07e84d963 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -251,11 +251,18 @@ extern int setresgid(gid_t, gid_t, gid_t); extern int getresgid(gid_t *, gid_t *, gid_t *); extern int setgroups(int, gid_t *); +#define ERRNO_TABLE_SIZE 1200 + +/* target_to_host_errno_table[] is initialized from + * host_to_target_errno_table[] in syscall_init(). */ +static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = { +}; + /* * This list is the union of errno values overridden in asm-/errno.h * minus the errnos that are not actually generic to all archs. */ -static uint16_t host_to_target_errno_table[1200] = { +static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { [EIDRM] = TARGET_EIDRM, [ECHRNG] = TARGET_ECHRNG, [EL2NSYNC] = TARGET_EL2NSYNC, @@ -361,7 +368,7 @@ static uint16_t host_to_target_errno_table[1200] = { #ifdef ENOTRECOVERABLE [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE, #endif - }; +}; static inline int host_to_target_errno(int err) { @@ -370,6 +377,13 @@ static inline int host_to_target_errno(int err) return err; } +static inline int target_to_host_errno(int err) +{ + if (target_to_host_errno_table[err]) + return target_to_host_errno_table[err]; + return err; +} + static inline abi_long get_errno(abi_long ret) { if (ret == -1) @@ -383,6 +397,11 @@ static inline int is_error(abi_long ret) return (abi_ulong)ret >= (abi_ulong)(-4096); } +char *target_strerror(int err) +{ + return strerror(target_to_host_errno(err)); +} + static abi_ulong target_brk; static abi_ulong target_original_brk; @@ -2465,6 +2484,7 @@ void syscall_init(void) IOCTLEntry *ie; const argtype *arg_type; int size; + int i; #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); #define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); @@ -2490,6 +2510,12 @@ void syscall_init(void) ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) | (size << TARGET_IOC_SIZESHIFT); } + + /* Build target_to_host_errno_table[] table from + * host_to_target_errno_table[]. */ + for (i=0; i < ERRNO_TABLE_SIZE; i++) + target_to_host_errno_table[host_to_target_errno_table[i]] = i; + /* automatic consistency check if same arch */ #if defined(__i386__) && defined(TARGET_I386) if (ie->target_cmd != ie->host_cmd) { @@ -2588,6 +2614,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef DEBUG gemu_log("syscall %d", num); #endif + if(do_strace) + print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); + switch(num) { case TARGET_NR_exit: #ifdef HAVE_GPROF @@ -5025,5 +5054,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef DEBUG gemu_log(" = %ld\n", ret); #endif + if(do_strace) + print_syscall_ret(num, ret); return ret; } -- cgit v1.2.3 From 93a0019ba3a0656b5b0497d1e447e770f59bb37b Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 1 Nov 2007 00:11:47 +0000 Subject: Mention userland strace support, and mipssim machine emulation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3503 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index 4c7a1215c..3b82c1bac 100644 --- a/Changelog +++ b/Changelog @@ -14,6 +14,8 @@ - SVM (x86 virtualization) support (Alexander Graf) - CRIS emulation (Edgar E. Iglesias) - SPARC32PLUS execution support (Blue Swirl) + - MIPS mipssim pequdo machine (Thiemo Seufer) + - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh) version 0.9.0: -- cgit v1.2.3 From 33189d31154c1738f0897a8f3475f1ecdaca9c78 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 1 Nov 2007 00:13:36 +0000 Subject: Add new files fir strace support, missed in earlier commit. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3504 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/strace.c | 299 ++++++++++ linux-user/strace.list | 1515 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1814 insertions(+) create mode 100644 linux-user/strace.c create mode 100644 linux-user/strace.list diff --git a/linux-user/strace.c b/linux-user/strace.c new file mode 100644 index 000000000..14323e7d4 --- /dev/null +++ b/linux-user/strace.c @@ -0,0 +1,299 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qemu.h" + +int do_strace=0; + +struct syscallname { + int nr; + char *name; + char *format; + void (*call)(struct syscallname *, + target_long, target_long, target_long, + target_long, target_long, target_long); + void (*result)(struct syscallname *, target_long); +}; + +/* + * Utility functions + */ +static void +print_ipc_cmd(int cmd) +{ +#define output_cmd(val) \ +if( cmd == val ) { \ + gemu_log(#val); \ + return; \ +} + + cmd &= 0xff; + + /* General IPC commands */ + output_cmd( IPC_RMID ); + output_cmd( IPC_SET ); + output_cmd( IPC_STAT ); + output_cmd( IPC_INFO ); + /* msgctl() commands */ + #ifdef __USER_MISC + output_cmd( MSG_STAT ); + output_cmd( MSG_INFO ); + #endif + /* shmctl() commands */ + output_cmd( SHM_LOCK ); + output_cmd( SHM_UNLOCK ); + output_cmd( SHM_STAT ); + output_cmd( SHM_INFO ); + /* semctl() commands */ + output_cmd( GETPID ); + output_cmd( GETVAL ); + output_cmd( GETALL ); + output_cmd( GETNCNT ); + output_cmd( GETZCNT ); + output_cmd( SETVAL ); + output_cmd( SETALL ); + output_cmd( SEM_STAT ); + output_cmd( SEM_INFO ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + output_cmd( IPC_RMID ); + + /* Some value we don't recognize */ + gemu_log("%d",cmd); +} + +static void +print_fdset(int n, target_ulong target_fds_addr) +{ + int i; + + gemu_log("["); + if( target_fds_addr ) { + target_long *target_fds; + + if (!access_ok(VERIFY_READ, target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1))) + return; + + target_fds = lock_user(target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1), 1); + for (i=n; i>=0; i--) { + if ((tswapl(target_fds[i / TARGET_LONG_BITS]) >> (i & (TARGET_LONG_BITS - 1))) & 1) + gemu_log("%d,", i ); + } + unlock_user(target_fds, target_fds_addr, 0); + } + gemu_log("]"); +} + +static void +print_timeval(target_ulong tv_addr) +{ + if( tv_addr ) { + struct target_timeval *tv; + + if (!access_ok(VERIFY_READ, tv_addr, sizeof(*tv))) + return; + + tv = lock_user(tv_addr, sizeof(*tv), 1); + gemu_log("{%d,%d}", tv->tv_sec, tv->tv_usec); + unlock_user(tv, tv_addr, 0); + } else + gemu_log("NULL"); +} + +/* + * Sysycall specific output functions + */ + +/* select */ +static long newselect_arg1 = 0; +static long newselect_arg2 = 0; +static long newselect_arg3 = 0; +static long newselect_arg4 = 0; +static long newselect_arg5 = 0; + +static void +print_newselect(struct syscallname *name, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + gemu_log("%s(" TARGET_FMT_ld ",", name->name, arg1); + print_fdset(arg1, arg2); + gemu_log(","); + print_fdset(arg1, arg3); + gemu_log(","); + print_fdset(arg1, arg4); + gemu_log(","); + print_timeval(arg5); + gemu_log(")"); + + /* save for use in the return output function below */ + newselect_arg1=arg1; + newselect_arg2=arg2; + newselect_arg3=arg3; + newselect_arg4=arg4; + newselect_arg5=arg5; +} + +static void +print_semctl(struct syscallname *name, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld ",", name->name, arg1, arg2); + print_ipc_cmd(arg3); + gemu_log(",0x" TARGET_FMT_lx ")", arg4); +} + +static void +print_execve(struct syscallname *name, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + target_ulong arg_ptr_addr; + char *s; + + if (!access_ok(VERIFY_READ, arg1, 1)) + return; + + s = lock_user_string(arg1); + gemu_log("%s(\"%s\",{", name->name, s); + unlock_user(s, arg1, 0); + + for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(target_ulong)) { + target_ulong *arg_ptr, arg_addr, s_addr; + + if (!access_ok(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong))) + return; + + arg_ptr = lock_user(arg_ptr_addr, sizeof(target_ulong), 1); + arg_addr = tswapl(*arg_ptr); + unlock_user(arg_ptr, arg_ptr_addr, 0); + if (!arg_addr) + break; + s = lock_user_string(arg_addr); + gemu_log("\"%s\",", s); + unlock_user(s, s_addr, 0); + } + + gemu_log("NULL})"); +} + +static void +print_ipc(struct syscallname *name, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + switch(arg1) { + case IPCOP_semctl: + name->name = "semctl"; + print_semctl(name,arg2,arg3,arg4,arg5,arg6,0); + break; + default: + gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld ")", + name->name, arg1, arg2, arg3, arg4); + } +} + +/* + * Variants for the return value output function + */ + +static void +print_syscall_ret_addr(struct syscallname *name, target_long ret) +{ +if( ret == -1 ) { + gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno)); + } else { + gemu_log(" = " TARGET_FMT_lx "\n", ret); + } +} + +static void +print_syscall_ret_raw(struct syscallname *name, target_long ret) +{ + gemu_log(" = " TARGET_FMT_lx "\n", ret); +} + +static void +print_syscall_ret_newselect(struct syscallname *name, target_long ret) +{ + gemu_log(" = " TARGET_FMT_lx " (", ret); + print_fdset(newselect_arg1,newselect_arg2); + gemu_log(","); + print_fdset(newselect_arg1,newselect_arg3); + gemu_log(","); + print_fdset(newselect_arg1,newselect_arg4); + gemu_log(","); + print_timeval(newselect_arg5); + gemu_log(")\n"); +} + +/* + * An array of all of the syscalls we know about + */ + +static struct syscallname scnames[] = { +#include "strace.list" +}; + +static int nsyscalls = sizeof(scnames)/sizeof(struct syscallname); + +/* + * The public interface to this module. + */ +void +print_syscall(int num, + target_long arg1, target_long arg2, target_long arg3, + target_long arg4, target_long arg5, target_long arg6) +{ + int i; + char *format="%s(%ld,%ld,%ld,%ld,%ld,%ld)"; + + gemu_log("%d ", getpid() ); + + for(i=0;i Date: Thu, 1 Nov 2007 19:23:51 +0000 Subject: Fix slirp compilation failure when using a newer gcc git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3505 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/misc.h | 2 ++ slirp/tcp_subr.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/slirp/misc.h b/slirp/misc.h index eee740575..e405e38dc 100644 --- a/slirp/misc.h +++ b/slirp/misc.h @@ -63,7 +63,9 @@ struct emu_t { struct emu_t *next; }; +#ifndef CONFIG_QEMU extern struct emu_t *tcpemu; +#endif extern int x_port, x_server, x_display; diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 7d7127054..ba1296d4b 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -559,7 +559,10 @@ static const struct tos_t tcptos[] = { {0, 0, 0, 0} }; -static struct emu_t *tcpemu = 0; +#ifdef CONFIG_QEMU +static +#endif +struct emu_t *tcpemu = 0; /* * Return TOS according to the above table -- cgit v1.2.3 From 3d97b40b05c61d6d85ad1ab9cbb72a076db2aa74 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Nov 2007 19:02:07 +0000 Subject: EFAULT - verify pages are in cache and are read/write, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3506 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + exec.c | 27 +++++++++++++++++++++++++++ linux-user/qemu.h | 3 ++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index 4e200928f..76daec947 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -691,6 +691,7 @@ 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); +int page_check_range(target_ulong start, target_ulong len, int flags); CPUState *cpu_copy(CPUState *env); diff --git a/exec.c b/exec.c index 0daeaabe2..7c8864c8b 100644 --- a/exec.c +++ b/exec.c @@ -1875,6 +1875,33 @@ void page_set_flags(target_ulong start, target_ulong end, int flags) spin_unlock(&tb_lock); } +int page_check_range(target_ulong start, target_ulong len, int flags) +{ + PageDesc *p; + target_ulong end; + target_ulong addr; + + end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */ + start = start & TARGET_PAGE_MASK; + + if( end < start ) + /* we've wrapped around */ + return -1; + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { + p = page_find(addr >> TARGET_PAGE_BITS); + if( !p ) + return -1; + if( !(p->flags & PAGE_VALID) ) + return -1; + + if (!(p->flags & PAGE_READ) && (flags & PAGE_READ) ) + return -1; + if (!(p->flags & PAGE_WRITE) && (flags & PAGE_WRITE) ) + return -1; + } + return 0; +} + /* called from signal handler: invalidate the code and unprotect the page. Return TRUE if the fault was succesfully handled. */ int page_unprotect(target_ulong address, unsigned long pc, void *puc) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 22a4fec61..bcc0b34f3 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -203,7 +203,8 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); #define VERIFY_READ 0 #define VERIFY_WRITE 1 -#define access_ok(type,addr,size) (1) +#define access_ok(type,addr,size) \ + (page_check_range((target_ulong)addr,size,(type==VERIFY_READ)?PAGE_READ:PAGE_WRITE)==0) /* NOTE get_user and put_user use host addresses. */ #define __put_user(x,ptr)\ -- cgit v1.2.3 From 80210bcd719c615d3ae9cd851e9e961bac722538 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Nov 2007 19:08:57 +0000 Subject: Fix compiler warnings, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3507 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mmap.c | 44 +++++++++++++++++++++++--------------------- target-i386/helper2.c | 1 + 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 4d18d2281..f87303402 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -37,7 +37,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) #ifdef DEBUG_MMAP printf("mprotect: start=0x" TARGET_FMT_lx - "len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len, + "len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', prot & PROT_EXEC ? 'x' : '-'); @@ -100,7 +100,7 @@ static int mmap_frag(abi_ulong real_start, abi_ulong start, abi_ulong end, int prot, int flags, int fd, abi_ulong offset) { - abi_ulong real_end, ret, addr; + abi_ulong real_end, addr; void *host_start; int prot1, prot_new; @@ -116,10 +116,10 @@ static int mmap_frag(abi_ulong real_start, if (prot1 == 0) { /* no page was there, so we allocate one */ - ret = (long)mmap(host_start, qemu_host_page_size, prot, - flags | MAP_ANONYMOUS, -1, 0); - if (ret == -1) - return ret; + void *p = mmap(host_start, qemu_host_page_size, prot, + flags | MAP_ANONYMOUS, -1, 0); + if (p == MAP_FAILED) + return -1; prot1 = prot; } prot1 &= PAGE_BITS; @@ -168,7 +168,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, #ifdef DEBUG_MMAP { printf("mmap: start=0x" TARGET_FMT_lx - " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=", + " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=", start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', @@ -230,16 +230,16 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, */ abi_ulong host_end; unsigned long host_aligned_start; + void *p; host_len = HOST_PAGE_ALIGN(host_len + qemu_host_page_size - qemu_real_host_page_size); - host_start = (unsigned long) mmap(real_start ? - g2h(real_start) : NULL, - host_len, prot, flags, - fd, host_offset); - if (host_start == -1) + p = mmap(real_start ? g2h(real_start) : NULL, + host_len, prot, flags, fd, host_offset); + if (p == MAP_FAILED) return -1; + host_start = (unsigned long)p; host_end = host_start + host_len; /* Find start and end, aligned to the targets pagesize with-in the @@ -260,11 +260,12 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, goto the_end1; } else { /* if not fixed, no need to do anything */ - host_start = (long)mmap(real_start ? g2h(real_start) : NULL, + void *p = mmap(real_start ? g2h(real_start) : NULL, host_len, prot, flags, fd, host_offset); - if (host_start == -1) + if (p == MAP_FAILED) return -1; /* update start so that it points to the file position at 'offset' */ + host_start = (unsigned long)p; if (!(flags & MAP_ANONYMOUS)) host_start += offset - host_offset; start = h2g(host_start); @@ -333,14 +334,15 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, /* map the middle (easier) */ if (real_start < real_end) { + void *p; unsigned long offset1; - if (flags & MAP_ANONYMOUS) - offset1 = 0; - else - offset1 = offset + real_start - start; - ret = (long)mmap(g2h(real_start), real_end - real_start, - prot, flags, fd, offset1); - if (ret == -1) + if (flags & MAP_ANONYMOUS) + offset1 = 0; + else + offset1 = offset + real_start - start; + p = mmap(g2h(real_start), real_end - real_start, + prot, flags, fd, offset1); + if (p == MAP_FAILED) return -1; } the_end1: diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 7d5275c10..1d59bc571 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -32,6 +32,7 @@ //#define DEBUG_MMU #ifdef USE_CODE_COPY +#include #include #include #include -- cgit v1.2.3 From 89343ecde51e7c287e8647a13f9e18f68a37c87c Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 2 Nov 2007 20:24:22 +0000 Subject: EFAULT - update __get_user() __put_user(), by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3508 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index bcc0b34f3..d0f650eda 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -206,22 +206,22 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); #define access_ok(type,addr,size) \ (page_check_range((target_ulong)addr,size,(type==VERIFY_READ)?PAGE_READ:PAGE_WRITE)==0) -/* NOTE get_user and put_user use host addresses. */ -#define __put_user(x,ptr)\ +/* NOTE __get_user and __put_user use host pointers and don't check access. */ +#define __put_user(x, hptr)\ ({\ - int size = sizeof(*ptr);\ + int size = sizeof(*hptr);\ switch(size) {\ case 1:\ - *(uint8_t *)(ptr) = (typeof(*ptr))(x);\ + *(uint8_t *)(hptr) = (typeof(*hptr))(x);\ break;\ case 2:\ - *(uint16_t *)(ptr) = tswap16((typeof(*ptr))(x));\ + *(uint16_t *)(hptr) = tswap16((typeof(*hptr))(x));\ break;\ case 4:\ - *(uint32_t *)(ptr) = tswap32((typeof(*ptr))(x));\ + *(uint32_t *)(hptr) = tswap32((typeof(*hptr))(x));\ break;\ case 8:\ - *(uint64_t *)(ptr) = tswap64((typeof(*ptr))(x));\ + *(uint64_t *)(hptr) = tswap64((typeof(*hptr))(x));\ break;\ default:\ abort();\ @@ -229,21 +229,21 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); 0;\ }) -#define __get_user(x, ptr) \ +#define __get_user(x, hptr) \ ({\ - int size = sizeof(*ptr);\ + int size = sizeof(*hptr);\ switch(size) {\ case 1:\ - x = (typeof(*ptr))*(uint8_t *)(ptr);\ + x = (typeof(*hptr))*(uint8_t *)(hptr);\ break;\ case 2:\ - x = (typeof(*ptr))tswap16(*(uint16_t *)(ptr));\ + x = (typeof(*hptr))tswap16(*(uint16_t *)(hptr));\ break;\ case 4:\ - x = (typeof(*ptr))tswap32(*(uint32_t *)(ptr));\ + x = (typeof(*hptr))tswap32(*(uint32_t *)(hptr));\ break;\ case 8:\ - x = (typeof(*ptr))tswap64(*(uint64_t *)(ptr));\ + x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\ break;\ default:\ abort();\ -- cgit v1.2.3 From 5b52b9911f5fecd936fa982a99c37750544e87f8 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 2 Nov 2007 22:35:33 +0000 Subject: Fix PowerPC program exception that was broken by FPU exception patches (bug reported by Jason Wessel) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3509 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index d3b8db7e6..f68656d5d 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2146,10 +2146,9 @@ static always_inline void powerpc_excp (CPUState *env, new_msr |= (target_ulong)1 << MSR_HV; #endif msr |= 0x00100000; - if (msr_fe0 != msr_fe1) { - msr |= 0x00010000; - goto store_current; - } + if (msr_fe0 == msr_fe1) + goto store_next; + msr |= 0x00010000; break; case POWERPC_EXCP_INVAL: #if defined (DEBUG_EXCEPTIONS) @@ -2187,7 +2186,7 @@ static always_inline void powerpc_excp (CPUState *env, env->error_code); break; } - goto store_next; + goto store_current; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) -- cgit v1.2.3 From 9fceefa7d12c832c4da69737ce216c415309a7c3 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 2 Nov 2007 22:47:50 +0000 Subject: Don't print any message when a priviledge exception occurs on mfpvr as the Linux allows applications to read this register. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3510 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 015a6215a..3b1c9919a 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3550,11 +3550,17 @@ static always_inline void gen_op_mfspr (DisasContext *ctx) gen_op_store_T0_gpr(rD(ctx->opcode)); } else { /* Privilege exception */ - if (loglevel != 0) { - fprintf(logfile, "Trying to read privileged spr %d %03x\n", - sprn, sprn); + /* This is a hack to avoid warnings when running Linux: + * this OS breaks the PowerPC virtualisation model, + * allowing userland application to read the PVR + */ + if (sprn != SPR_PVR) { + if (loglevel != 0) { + fprintf(logfile, "Trying to read privileged spr %d %03x\n", + sprn, sprn); + } + printf("Trying to read privileged spr %d %03x\n", sprn, sprn); } - printf("Trying to read privileged spr %d %03x\n", sprn, sprn); GEN_EXCP_PRIVREG(ctx); } } else { -- cgit v1.2.3 From 7fc42b4bbddc47a6bebc281ee96e9ddcd537d46e Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 3 Nov 2007 00:41:31 +0000 Subject: The PINT/DAV pin is active low in the chip spec, not inverted on the board. Make changes on known GPIO lines be verbose, initialise GPIO levels. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3511 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/palm.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- hw/tsc210x.c | 8 ++++---- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/hw/palm.c b/hw/palm.c index c21b44a9d..8800dc608 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -78,11 +78,10 @@ static CPUWriteMemoryFunc *static_writefn[] = { static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) { - qemu_irq p_int = omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]; - omap_uwire_attach( cpu->microwire, - tsc2102_init(qemu_irq_invert(p_int)), + tsc2102_init( + omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]), 0); } @@ -115,6 +114,62 @@ static void palmte_button_event(void *opaque, int keycode) !(keycode & 0x80)); } +static void palmte_onoff_gpios(void *opaque, int line, int level) +{ + switch (line) { + case 0: + printf("%s: current to MMC/SD card %sabled.\n", + __FUNCTION__, level ? "dis" : "en"); + break; + case 1: + printf("%s: internal speaker amplifier %s.\n", + __FUNCTION__, level ? "down" : "on"); + break; + + /* These LCD & Audio output signals have not been identified yet. */ + case 2: + case 3: + case 4: + printf("%s: LCD GPIO%i %s.\n", + __FUNCTION__, line - 1, level ? "high" : "low"); + break; + case 5: + case 6: + printf("%s: Audio GPIO%i %s.\n", + __FUNCTION__, line - 4, level ? "high" : "low"); + break; + } +} + +static void palmte_gpio_setup(struct omap_mpu_state_s *cpu) +{ + qemu_irq *misc_gpio; + + omap_mmc_handlers(cpu->mmc, + omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO], + qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio) + [PALMTE_MMC_SWITCH_GPIO])); + + misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7); + omap_gpio_out_set(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]); + omap_gpio_out_set(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]); + omap_gpio_out_set(cpu->gpio, 11, misc_gpio[2]); + omap_gpio_out_set(cpu->gpio, 12, misc_gpio[3]); + omap_gpio_out_set(cpu->gpio, 13, misc_gpio[4]); + omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]); + omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]); + + /* Reset some inputs to initial state. */ + qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USBDETECT_GPIO]); + qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USB_OR_DC_GPIO]); + qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[4]); + qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_HEADPHONES_GPIO]); + qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]); + qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]); + qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]); + qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]); +} + static void palmte_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -158,10 +213,7 @@ static void palmte_init(int ram_size, int vga_ram_size, qemu_add_kbd_event_handler(palmte_button_event, cpu); - omap_mmc_handlers(cpu->mmc, - omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO], - qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio) - [PALMTE_MMC_SWITCH_GPIO])); + palmte_gpio_setup(cpu); /* Setup initial (reset) machine state */ if (nb_option_roms) { diff --git a/hw/tsc210x.c b/hw/tsc210x.c index 6aa2bc8ad..31cf3a444 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -1,5 +1,5 @@ /* - * TI TSC2102 (touchscreen/sensors/audio controller) controller. + * TI TSC2102 (touchscreen/sensors/audio controller) emulator. * * Copyright (c) 2006 Andrzej Zaborowski * @@ -171,7 +171,7 @@ static void tsc210x_reset(struct tsc210x_state_s *s) s->filter_data[0x12] = 0x7d83; s->filter_data[0x13] = 0x84ee; - qemu_set_irq(s->pint, s->irq); + qemu_set_irq(s->pint, !s->irq); } static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) @@ -572,7 +572,7 @@ static void tsc210x_pin_update(struct tsc210x_state_s *s) if (pin_state != s->irq) { s->irq = pin_state; - qemu_set_irq(s->pint, s->irq); + qemu_set_irq(s->pint, !s->irq); } switch (s->nextfunction) { @@ -810,7 +810,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be16s(f, &s->filter_data[i]); s->busy = qemu_timer_pending(s->timer); - qemu_set_irq(s->pint, s->irq); + qemu_set_irq(s->pint, !s->irq); return 0; } -- cgit v1.2.3 From 66450b1596fddd03204b54cc4f9fb99fb928c857 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 3 Nov 2007 00:46:16 +0000 Subject: Implement OMAP PWL (backlight) module. Fix GPIO clock name and output level change notifications. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3512 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/omap.h | 11 ++++++ 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index d6978d8eb..a8e00de6f 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -22,6 +22,18 @@ #include "arm_pic.h" /* Should signal the TCMI */ +uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) +{ + OMAP_8B_REG(addr); + return 0; +} + +void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + OMAP_8B_REG(addr); +} + uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) { OMAP_16B_REG(addr); @@ -3140,9 +3152,8 @@ static void omap_gpio_write(void *opaque, target_phys_addr_t addr, return; case 0x04: /* DATA_OUTPUT */ - diff = s->outputs ^ (value & ~s->dir); + diff = (s->outputs ^ value) & ~s->dir; s->outputs = value; - value &= ~s->dir; while ((ln = ffs(diff))) { ln --; if (s->handler[ln]) @@ -3369,7 +3380,7 @@ static CPUWriteMemoryFunc *omap_uwire_writefn[] = { void omap_uwire_reset(struct omap_uwire_s *s) { - s->control= 0; + s->control = 0; s->setup[0] = 0; s->setup[1] = 0; s->setup[2] = 0; @@ -3407,6 +3418,97 @@ void omap_uwire_attach(struct omap_uwire_s *s, s->chip[chipselect] = slave; } +/* Pseudonoise Pulse-Width Light Modulator */ +void omap_pwl_update(struct omap_mpu_state_s *s) +{ + int output = (s->pwl.clk && s->pwl.enable) ? s->pwl.level : 0; + + if (output != s->pwl.output) { + s->pwl.output = output; + printf("%s: Backlight now at %i/256\n", __FUNCTION__, output); + } +} + +static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->pwl.base; + + switch (offset) { + case 0x00: /* PWL_LEVEL */ + return s->pwl.level; + case 0x04: /* PWL_CTRL */ + return s->pwl.enable; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_pwl_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->pwl.base; + + switch (offset) { + case 0x00: /* PWL_LEVEL */ + s->pwl.level = value; + omap_pwl_update(s); + break; + case 0x04: /* PWL_CTRL */ + s->pwl.enable = value & 1; + omap_pwl_update(s); + break; + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_pwl_readfn[] = { + omap_badwidth_read8, + omap_badwidth_read8, + omap_pwl_read, +}; + +static CPUWriteMemoryFunc *omap_pwl_writefn[] = { + omap_badwidth_write8, + omap_badwidth_write8, + omap_pwl_write, +}; + +void omap_pwl_reset(struct omap_mpu_state_s *s) +{ + s->pwl.output = 0; + s->pwl.level = 0; + s->pwl.enable = 0; + s->pwl.clk = 1; + omap_pwl_update(s); +} + +static void omap_pwl_clk_update(void *opaque, int line, int on) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + + s->pwl.clk = on; + omap_pwl_update(s); +} + +static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s, + omap_clk clk) +{ + int iomemtype; + + s->pwl.base = base; + omap_pwl_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_pwl_readfn, + omap_pwl_writefn, s); + cpu_register_physical_memory(s->pwl.base, 0x800, iomemtype); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -3437,6 +3539,7 @@ static void omap_mpu_reset(void *opaque) omap_mpuio_reset(mpu->mpuio); omap_gpio_reset(mpu->gpio); omap_uwire_reset(mpu->microwire); + omap_pwl_reset(mpu); cpu_reset(mpu->env); } @@ -3553,11 +3656,13 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->wakeup, omap_findclk(s, "clk32-kHz")); s->gpio = omap_gpio_init(0xfffce000, s->irq[0][OMAP_INT_GPIO_BANK1], - omap_findclk(s, "mpuper_ck")); + omap_findclk(s, "arm_gpio_ck")); s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); + omap_pwl_init(0xfffb5800, s, omap_findclk(s, "clk32-kHz")); + qemu_register_reset(omap_mpu_reset, s); return s; diff --git a/hw/omap.h b/hw/omap.h index e19f8ac7c..f81954951 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -534,6 +534,14 @@ struct omap_mpu_state_s { struct omap_uwire_s *microwire; + struct { + target_phys_addr_t base; + uint8_t output; + uint8_t level; + uint8_t enable; + int clk; + } pwl; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; @@ -615,6 +623,9 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, # define OMAP_RO_REG(paddr) \ printf("%s: Read-only register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) +# define OMAP_8B_REG(paddr) \ + printf("%s: 8-bit register " OMAP_FMT_plx "\n", \ + __FUNCTION__, paddr) # define OMAP_16B_REG(paddr) \ printf("%s: 16-bit register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) -- cgit v1.2.3 From f34c417ba63cd379ad7e1953bc3f520454601e27 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 3 Nov 2007 00:48:26 +0000 Subject: Add OMAP Pulse-width Tone module. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3513 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/omap.h | 8 ++++++ 2 files changed, 103 insertions(+) diff --git a/hw/omap.c b/hw/omap.c index a8e00de6f..67d9ea7fc 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -3509,6 +3509,100 @@ static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s, omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); } +/* Pulse-Width Tone module */ +static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->pwt.base; + + switch (offset) { + case 0x00: /* FRC */ + return s->pwt.frc; + case 0x04: /* VCR */ + return s->pwt.vrc; + case 0x08: /* GCR */ + return s->pwt.gcr; + } + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_pwt_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + int offset = addr - s->pwt.base; + + switch (offset) { + case 0x00: /* FRC */ + s->pwt.frc = value & 0x3f; + break; + case 0x04: /* VRC */ + if ((value ^ s->pwt.vrc) & 1) { + if (value & 1) + printf("%s: %iHz buzz on\n", __FUNCTION__, (int) + /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */ + ((omap_clk_getrate(s->pwt.clk) >> 3) / + /* Pre-multiplexer divider */ + ((s->pwt.gcr & 2) ? 1 : 154) / + /* Octave multiplexer */ + (2 << (value & 3)) * + /* 101/107 divider */ + ((value & (1 << 2)) ? 101 : 107) * + /* 49/55 divider */ + ((value & (1 << 3)) ? 49 : 55) * + /* 50/63 divider */ + ((value & (1 << 4)) ? 50 : 63) * + /* 80/127 divider */ + ((value & (1 << 5)) ? 80 : 127) / + (107 * 55 * 63 * 127))); + else + printf("%s: silence!\n", __FUNCTION__); + } + s->pwt.vrc = value & 0x7f; + break; + case 0x08: /* GCR */ + s->pwt.gcr = value & 3; + break; + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_pwt_readfn[] = { + omap_badwidth_read8, + omap_badwidth_read8, + omap_pwt_read, +}; + +static CPUWriteMemoryFunc *omap_pwt_writefn[] = { + omap_badwidth_write8, + omap_badwidth_write8, + omap_pwt_write, +}; + +void omap_pwt_reset(struct omap_mpu_state_s *s) +{ + s->pwt.frc = 0; + s->pwt.vrc = 0; + s->pwt.gcr = 0; +} + +static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, + omap_clk clk) +{ + int iomemtype; + + s->pwt.base = base; + s->pwt.clk = clk; + omap_pwt_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_pwt_readfn, + omap_pwt_writefn, s); + cpu_register_physical_memory(s->pwt.base, 0x800, iomemtype); +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -3662,6 +3756,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); omap_pwl_init(0xfffb5800, s, omap_findclk(s, "clk32-kHz")); + omap_pwt_init(0xfffb6000, s, omap_findclk(s, "xtal_osc_12m")); qemu_register_reset(omap_mpu_reset, s); diff --git a/hw/omap.h b/hw/omap.h index f81954951..0735fcc7e 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -542,6 +542,14 @@ struct omap_mpu_state_s { int clk; } pwl; + struct { + target_phys_addr_t base; + uint8_t frc; + uint8_t vrc; + uint8_t gcr; + omap_clk clk; + } pwt; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; -- cgit v1.2.3 From 4a2c8ac2bc67d689bc7df130d3105af52fa36b18 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 3 Nov 2007 00:51:03 +0000 Subject: Initial OMAP I^2C controller implementation (communication not tested). Correct an i2c_start_transfer comment. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3514 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/i2c.c | 3 +- hw/omap.c | 420 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/omap.h | 7 ++ 3 files changed, 428 insertions(+), 2 deletions(-) diff --git a/hw/i2c.c b/hw/i2c.c index f0d117c14..627bbfc4e 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -51,8 +51,7 @@ int i2c_bus_busy(i2c_bus *bus) return bus->current_dev != NULL; } -/* Returns nonzero if the bus is already busy, or is the address is not - valid. */ +/* Returns non-zero if the address is not valid. */ /* TODO: Make this handle multiple masters. */ int i2c_start_transfer(i2c_bus *bus, int address, int recv) { diff --git a/hw/omap.c b/hw/omap.c index 67d9ea7fc..ef0386838 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -3603,6 +3603,421 @@ static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, cpu_register_physical_memory(s->pwt.base, 0x800, iomemtype); } +/* Inter-Integrated Circuit Controller (only the "New I2C") */ +struct omap_i2c_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq drq[2]; + i2c_slave slave; + i2c_bus *bus; + + uint8_t mask; + uint16_t stat; + uint16_t dma; + uint16_t count; + int count_cur; + uint32_t fifo; + int rxlen; + int txlen; + uint16_t control; + uint16_t addr[2]; + uint8_t divider; + uint8_t times[2]; + uint16_t test; +}; + +static void omap_i2c_interrupts_update(struct omap_i2c_s *s) +{ + qemu_set_irq(s->irq, s->stat & s->mask); + if ((s->dma >> 15) & 1) /* RDMA_EN */ + qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */ + if ((s->dma >> 7) & 1) /* XDMA_EN */ + qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */ +} + +/* These are only stubs now. */ +static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; + + if ((~s->control >> 15) & 1) /* I2C_EN */ + return; + + switch (event) { + case I2C_START_SEND: + case I2C_START_RECV: + s->stat |= 1 << 9; /* AAS */ + break; + case I2C_FINISH: + s->stat |= 1 << 2; /* ARDY */ + break; + case I2C_NACK: + s->stat |= 1 << 1; /* NACK */ + break; + } + + omap_i2c_interrupts_update(s); +} + +static int omap_i2c_rx(i2c_slave *i2c) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; + uint8_t ret = 0; + + if ((~s->control >> 15) & 1) /* I2C_EN */ + return -1; + + if (s->txlen) + ret = s->fifo >> ((-- s->txlen) << 3) & 0xff; + else + s->stat |= 1 << 10; /* XUDF */ + s->stat |= 1 << 4; /* XRDY */ + + omap_i2c_interrupts_update(s); + return ret; +} + +static int omap_i2c_tx(i2c_slave *i2c, uint8_t data) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; + + if ((~s->control >> 15) & 1) /* I2C_EN */ + return 1; + + if (s->rxlen < 4) + s->fifo |= data << ((s->rxlen ++) << 3); + else + s->stat |= 1 << 11; /* ROVR */ + s->stat |= 1 << 3; /* RRDY */ + + omap_i2c_interrupts_update(s); + return 1; +} + +static void omap_i2c_fifo_run(struct omap_i2c_s *s) +{ + int ack = 1; + + if (!i2c_bus_busy(s->bus)) + return; + + if ((s->control >> 2) & 1) { /* RM */ + if ((s->control >> 1) & 1) { /* STP */ + i2c_end_transfer(s->bus); + s->control &= ~(1 << 1); /* STP */ + s->count_cur = s->count; + } else if ((s->control >> 9) & 1) { /* TRX */ + while (ack && s->txlen) + ack = (i2c_send(s->bus, + (s->fifo >> ((-- s->txlen) << 3)) & + 0xff) >= 0); + s->stat |= 1 << 4; /* XRDY */ + } else { + while (s->rxlen < 4) + s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); + s->stat |= 1 << 3; /* RRDY */ + } + } else { + if ((s->control >> 9) & 1) { /* TRX */ + while (ack && s->count_cur && s->txlen) { + ack = (i2c_send(s->bus, + (s->fifo >> ((-- s->txlen) << 3)) & + 0xff) >= 0); + s->count_cur --; + } + if (ack && s->count_cur) + s->stat |= 1 << 4; /* XRDY */ + if (!s->count_cur) { + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ + } + } else { + while (s->count_cur && s->rxlen < 4) { + s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); + s->count_cur --; + } + if (s->rxlen) + s->stat |= 1 << 3; /* RRDY */ + } + if (!s->count_cur) { + if ((s->control >> 1) & 1) { /* STP */ + i2c_end_transfer(s->bus); + s->control &= ~(1 << 1); /* STP */ + s->count_cur = s->count; + } else { + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ + } + } + } + + s->stat |= (!ack) << 1; /* NACK */ + if (!ack) + s->control &= ~(1 << 1); /* STP */ +} + +static void omap_i2c_reset(struct omap_i2c_s *s) +{ + s->mask = 0; + s->stat = 0; + s->dma = 0; + s->count = 0; + s->count_cur = 0; + s->fifo = 0; + s->rxlen = 0; + s->txlen = 0; + s->control = 0; + s->addr[0] = 0; + s->addr[1] = 0; + s->divider = 0; + s->times[0] = 0; + s->times[1] = 0; + s->test = 0; +} + +static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; + int offset = addr - s->base; + uint16_t ret; + + switch (offset) { + case 0x00: /* I2C_REV */ + /* TODO: set a value greater or equal to real hardware */ + return 0x11; /* REV */ + + case 0x04: /* I2C_IE */ + return s->mask; + + case 0x08: /* I2C_STAT */ + return s->stat | (i2c_bus_busy(s->bus) << 12); + + case 0x0c: /* I2C_IV */ + ret = ffs(s->stat & s->mask); + if (ret) + s->stat ^= 1 << (ret - 1); + omap_i2c_interrupts_update(s); + return ret; + + case 0x14: /* I2C_BUF */ + return s->dma; + + case 0x18: /* I2C_CNT */ + return s->count_cur; /* DCOUNT */ + + case 0x1c: /* I2C_DATA */ + ret = 0; + if (s->control & (1 << 14)) { /* BE */ + ret |= ((s->fifo >> 0) & 0xff) << 8; + ret |= ((s->fifo >> 8) & 0xff) << 0; + } else { + ret |= ((s->fifo >> 8) & 0xff) << 8; + ret |= ((s->fifo >> 0) & 0xff) << 0; + } + if (s->rxlen == 1) { + s->stat |= 1 << 15; /* SBD */ + s->rxlen = 0; + } else if (s->rxlen > 1) { + if (s->rxlen > 2) + s->fifo >>= 16; + s->rxlen -= 2; + } else + /* XXX: remote access (qualifier) error - what's that? */; + if (!s->rxlen) { + s->stat |= ~(1 << 3); /* RRDY */ + if (((s->control >> 10) & 1) && /* MST */ + ((~s->control >> 9) & 1)) { /* TRX */ + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ + } + } + s->stat &= ~(1 << 11); /* ROVR */ + omap_i2c_fifo_run(s); + omap_i2c_interrupts_update(s); + return ret; + + case 0x24: /* I2C_CON */ + return s->control; + + case 0x28: /* I2C_OA */ + return s->addr[0]; + + case 0x2c: /* I2C_SA */ + return s->addr[1]; + + case 0x30: /* I2C_PSC */ + return s->divider; + + case 0x34: /* I2C_SCLL */ + return s->times[0]; + + case 0x38: /* I2C_SCLH */ + return s->times[1]; + + case 0x3c: /* I2C_SYSTEST */ + if (s->test & (1 << 15)) { /* ST_EN */ + s->test ^= 0xa; + return s->test; + } else + return s->test & ~0x300f; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_i2c_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; + int offset = addr - s->base; + int nack; + + switch (offset) { + case 0x00: /* I2C_REV */ + case 0x08: /* I2C_STAT */ + case 0x0c: /* I2C_IV */ + OMAP_BAD_REG(addr); + return; + + case 0x04: /* I2C_IE */ + s->mask = value & 0x1f; + break; + + case 0x14: /* I2C_BUF */ + s->dma = value & 0x8080; + if (value & (1 << 15)) /* RDMA_EN */ + s->mask &= ~(1 << 3); /* RRDY_IE */ + if (value & (1 << 7)) /* XDMA_EN */ + s->mask &= ~(1 << 4); /* XRDY_IE */ + break; + + case 0x18: /* I2C_CNT */ + s->count = value; /* DCOUNT */ + break; + + case 0x1c: /* I2C_DATA */ + if (s->txlen > 2) { + /* XXX: remote access (qualifier) error - what's that? */ + break; + } + s->fifo <<= 16; + s->txlen += 2; + if (s->control & (1 << 14)) { /* BE */ + s->fifo |= ((value >> 8) & 0xff) << 8; + s->fifo |= ((value >> 0) & 0xff) << 0; + } else { + s->fifo |= ((value >> 0) & 0xff) << 8; + s->fifo |= ((value >> 8) & 0xff) << 0; + } + s->stat &= ~(1 << 10); /* XUDF */ + if (s->txlen > 2) + s->stat &= ~(1 << 4); /* XRDY */ + omap_i2c_fifo_run(s); + omap_i2c_interrupts_update(s); + break; + + case 0x24: /* I2C_CON */ + s->control = value & 0xcf07; + if (~value & (1 << 15)) { /* I2C_EN */ + omap_i2c_reset(s); + break; + } + if (~value & (1 << 10)) { /* MST */ + printf("%s: I^2C slave mode not supported\n", __FUNCTION__); + break; + } + if (value & (1 << 9)) { /* XA */ + printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__); + break; + } + if (value & (1 << 0)) { /* STT */ + nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */ + (~value >> 9) & 1); /* TRX */ + s->stat |= nack << 1; /* NACK */ + s->control &= ~(1 << 0); /* STT */ + if (nack) + s->control &= ~(1 << 1); /* STP */ + else + omap_i2c_fifo_run(s); + omap_i2c_interrupts_update(s); + } + break; + + case 0x28: /* I2C_OA */ + s->addr[0] = value & 0x3ff; + i2c_set_slave_address(&s->slave, value & 0x7f); + break; + + case 0x2c: /* I2C_SA */ + s->addr[1] = value & 0x3ff; + break; + + case 0x30: /* I2C_PSC */ + s->divider = value; + break; + + case 0x34: /* I2C_SCLL */ + s->times[0] = value; + break; + + case 0x38: /* I2C_SCLH */ + s->times[1] = value; + break; + + case 0x3c: /* I2C_SYSTEST */ + s->test = value & 0xf00f; + if (value & (1 << 15)) /* ST_EN */ + printf("%s: System Test not supported\n", __FUNCTION__); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_i2c_readfn[] = { + omap_badwidth_read16, + omap_i2c_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_i2c_writefn[] = { + omap_badwidth_write16, + omap_i2c_write, + omap_i2c_write, /* TODO: Only the last fifo write can be 8 bit. */ +}; + +struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, + qemu_irq irq, qemu_irq *dma, omap_clk clk) +{ + int iomemtype; + struct omap_i2c_s *s = (struct omap_i2c_s *) + qemu_mallocz(sizeof(struct omap_i2c_s)); + + s->base = base; + s->irq = irq; + s->drq[0] = dma[0]; + s->drq[1] = dma[1]; + s->slave.event = omap_i2c_event; + s->slave.recv = omap_i2c_rx; + s->slave.send = omap_i2c_tx; + s->bus = i2c_init_bus(); + omap_i2c_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_i2c_readfn, + omap_i2c_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +i2c_bus *omap_i2c_bus(struct omap_i2c_s *s) +{ + return s->bus; +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -3634,6 +4049,8 @@ static void omap_mpu_reset(void *opaque) omap_gpio_reset(mpu->gpio); omap_uwire_reset(mpu->microwire); omap_pwl_reset(mpu); + omap_pwt_reset(mpu); + omap_i2c_reset(mpu->i2c); cpu_reset(mpu->env); } @@ -3758,6 +4175,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_pwl_init(0xfffb5800, s, omap_findclk(s, "clk32-kHz")); omap_pwt_init(0xfffb6000, s, omap_findclk(s, "xtal_osc_12m")); + s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], + &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); + qemu_register_reset(omap_mpu_reset, s); return s; diff --git a/hw/omap.h b/hw/omap.h index 0735fcc7e..4b5b57973 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -475,6 +475,11 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, void omap_uwire_attach(struct omap_uwire_s *s, struct uwire_slave_s *slave, int chipselect); +struct omap_i2c_s; +struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, + qemu_irq irq, qemu_irq *dma, omap_clk clk); +i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); @@ -550,6 +555,8 @@ struct omap_mpu_state_s { omap_clk clk; } pwt; + struct omap_i2c_s *i2c; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; -- cgit v1.2.3 From 5c1c390feac308327eee376845d90355b16615b9 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 3 Nov 2007 12:44:02 +0000 Subject: Implement OMAP on-chip RTC (Linux guest date/time now matches with host). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3515 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 429 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/omap.h | 4 + 2 files changed, 433 insertions(+) diff --git a/hw/omap.c b/hw/omap.c index ef0386838..eb80b0a3a 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -4018,6 +4018,432 @@ i2c_bus *omap_i2c_bus(struct omap_i2c_s *s) return s->bus; } +/* Real-time Clock module */ +struct omap_rtc_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq alarm; + QEMUTimer *clk; + + uint8_t interrupts; + uint8_t status; + int16_t comp_reg; + int running; + int pm_am; + int auto_comp; + int round; + struct tm *(*convert)(const time_t *timep, struct tm *result); + struct tm alarm_tm; + time_t alarm_ti; + + struct tm current_tm; + time_t ti; + uint64_t tick; +}; + +static void omap_rtc_interrupts_update(struct omap_rtc_s *s) +{ + qemu_set_irq(s->alarm, (s->status >> 6) & 1); +} + +static void omap_rtc_alarm_update(struct omap_rtc_s *s) +{ + s->alarm_ti = mktime(&s->alarm_tm); + if (s->alarm_ti == -1) + printf("%s: conversion failed\n", __FUNCTION__); +} + +static inline uint8_t omap_rtc_bcd(int num) +{ + return ((num / 10) << 4) | (num % 10); +} + +static inline int omap_rtc_bin(uint8_t num) +{ + return (num & 15) + 10 * (num >> 4); +} + +static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; + int offset = addr - s->base; + uint8_t i; + + switch (offset) { + case 0x00: /* SECONDS_REG */ + return omap_rtc_bcd(s->current_tm.tm_sec); + + case 0x04: /* MINUTES_REG */ + return omap_rtc_bcd(s->current_tm.tm_min); + + case 0x08: /* HOURS_REG */ + if (s->pm_am) + return ((s->current_tm.tm_hour > 11) << 7) | + omap_rtc_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); + else + return omap_rtc_bcd(s->current_tm.tm_hour); + + case 0x0c: /* DAYS_REG */ + return omap_rtc_bcd(s->current_tm.tm_mday); + + case 0x10: /* MONTHS_REG */ + return omap_rtc_bcd(s->current_tm.tm_mon + 1); + + case 0x14: /* YEARS_REG */ + return omap_rtc_bcd(s->current_tm.tm_year % 100); + + case 0x18: /* WEEK_REG */ + return s->current_tm.tm_wday; + + case 0x20: /* ALARM_SECONDS_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_sec); + + case 0x24: /* ALARM_MINUTES_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_min); + + case 0x28: /* ALARM_HOURS_REG */ + if (s->pm_am) + return ((s->alarm_tm.tm_hour > 11) << 7) | + omap_rtc_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); + else + return omap_rtc_bcd(s->alarm_tm.tm_hour); + + case 0x2c: /* ALARM_DAYS_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_mday); + + case 0x30: /* ALARM_MONTHS_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_mon + 1); + + case 0x34: /* ALARM_YEARS_REG */ + return omap_rtc_bcd(s->alarm_tm.tm_year % 100); + + case 0x40: /* RTC_CTRL_REG */ + return (s->pm_am << 3) | (s->auto_comp << 2) | + (s->round << 1) | s->running; + + case 0x44: /* RTC_STATUS_REG */ + i = s->status; + s->status &= ~0x3d; + return i; + + case 0x48: /* RTC_INTERRUPTS_REG */ + return s->interrupts; + + case 0x4c: /* RTC_COMP_LSB_REG */ + return ((uint16_t) s->comp_reg) & 0xff; + + case 0x50: /* RTC_COMP_MSB_REG */ + return ((uint16_t) s->comp_reg) >> 8; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_rtc_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; + int offset = addr - s->base; + struct tm new_tm; + time_t ti[2]; + + switch (offset) { + case 0x00: /* SECONDS_REG */ +#if ALMDEBUG + printf("RTC SEC_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_sec; + s->ti += omap_rtc_bin(value); + return; + + case 0x04: /* MINUTES_REG */ +#if ALMDEBUG + printf("RTC MIN_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_min * 60; + s->ti += omap_rtc_bin(value) * 60; + return; + + case 0x08: /* HOURS_REG */ +#if ALMDEBUG + printf("RTC HRS_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_hour * 3600; + if (s->pm_am) { + s->ti += (omap_rtc_bin(value & 0x3f) & 12) * 3600; + s->ti += ((value >> 7) & 1) * 43200; + } else + s->ti += omap_rtc_bin(value & 0x3f) * 3600; + return; + + case 0x0c: /* DAYS_REG */ +#if ALMDEBUG + printf("RTC DAY_REG <-- %02x\n", value); +#endif + s->ti -= s->current_tm.tm_mday * 86400; + s->ti += omap_rtc_bin(value) * 86400; + return; + + case 0x10: /* MONTHS_REG */ +#if ALMDEBUG + printf("RTC MTH_REG <-- %02x\n", value); +#endif + memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); + new_tm.tm_mon = omap_rtc_bin(value); + ti[0] = mktime(&s->current_tm); + ti[1] = mktime(&new_tm); + + if (ti[0] != -1 && ti[1] != -1) { + s->ti -= ti[0]; + s->ti += ti[1]; + } else { + /* A less accurate version */ + s->ti -= s->current_tm.tm_mon * 2592000; + s->ti += omap_rtc_bin(value) * 2592000; + } + return; + + case 0x14: /* YEARS_REG */ +#if ALMDEBUG + printf("RTC YRS_REG <-- %02x\n", value); +#endif + memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); + new_tm.tm_year += omap_rtc_bin(value) - (new_tm.tm_year % 100); + ti[0] = mktime(&s->current_tm); + ti[1] = mktime(&new_tm); + + if (ti[0] != -1 && ti[1] != -1) { + s->ti -= ti[0]; + s->ti += ti[1]; + } else { + /* A less accurate version */ + s->ti -= (s->current_tm.tm_year % 100) * 31536000; + s->ti += omap_rtc_bin(value) * 31536000; + } + return; + + case 0x18: /* WEEK_REG */ + return; /* Ignored */ + + case 0x20: /* ALARM_SECONDS_REG */ +#if ALMDEBUG + printf("ALM SEC_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_sec = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x24: /* ALARM_MINUTES_REG */ +#if ALMDEBUG + printf("ALM MIN_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_min = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x28: /* ALARM_HOURS_REG */ +#if ALMDEBUG + printf("ALM HRS_REG <-- %02x\n", value); +#endif + if (s->pm_am) + s->alarm_tm.tm_hour = + ((omap_rtc_bin(value & 0x3f)) % 12) + + ((value >> 7) & 1) * 12; + else + s->alarm_tm.tm_hour = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x2c: /* ALARM_DAYS_REG */ +#if ALMDEBUG + printf("ALM DAY_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_mday = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x30: /* ALARM_MONTHS_REG */ +#if ALMDEBUG + printf("ALM MON_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_mon = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x34: /* ALARM_YEARS_REG */ +#if ALMDEBUG + printf("ALM YRS_REG <-- %02x\n", value); +#endif + s->alarm_tm.tm_year = omap_rtc_bin(value); + omap_rtc_alarm_update(s); + return; + + case 0x40: /* RTC_CTRL_REG */ +#if ALMDEBUG + printf("RTC CONTROL <-- %02x\n", value); +#endif + s->pm_am = (value >> 3) & 1; + s->auto_comp = (value >> 2) & 1; + s->round = (value >> 1) & 1; + s->running = value & 1; + s->status &= 0xfd; + s->status |= s->running << 1; + return; + + case 0x44: /* RTC_STATUS_REG */ +#if ALMDEBUG + printf("RTC STATUSL <-- %02x\n", value); +#endif + s->status &= ~((value & 0xc0) ^ 0x80); + omap_rtc_interrupts_update(s); + return; + + case 0x48: /* RTC_INTERRUPTS_REG */ +#if ALMDEBUG + printf("RTC INTRS <-- %02x\n", value); +#endif + s->interrupts = value; + return; + + case 0x4c: /* RTC_COMP_LSB_REG */ +#if ALMDEBUG + printf("RTC COMPLSB <-- %02x\n", value); +#endif + s->comp_reg &= 0xff00; + s->comp_reg |= 0x00ff & value; + return; + + case 0x50: /* RTC_COMP_MSB_REG */ +#if ALMDEBUG + printf("RTC COMPMSB <-- %02x\n", value); +#endif + s->comp_reg &= 0x00ff; + s->comp_reg |= 0xff00 & (value << 8); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_rtc_readfn[] = { + omap_rtc_read, + omap_badwidth_read8, + omap_badwidth_read8, +}; + +static CPUWriteMemoryFunc *omap_rtc_writefn[] = { + omap_rtc_write, + omap_badwidth_write8, + omap_badwidth_write8, +}; + +static void omap_rtc_tick(void *opaque) +{ + struct omap_rtc_s *s = opaque; + + if (s->round) { + /* Round to nearest full minute. */ + if (s->current_tm.tm_sec < 30) + s->ti -= s->current_tm.tm_sec; + else + s->ti += 60 - s->current_tm.tm_sec; + + s->round = 0; + } + + localtime_r(&s->ti, &s->current_tm); + + if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { + s->status |= 0x40; + omap_rtc_interrupts_update(s); + } + + if (s->interrupts & 0x04) + switch (s->interrupts & 3) { + case 0: + s->status |= 0x04; + qemu_irq_raise(s->irq); + break; + case 1: + if (s->current_tm.tm_sec) + break; + s->status |= 0x08; + qemu_irq_raise(s->irq); + break; + case 2: + if (s->current_tm.tm_sec || s->current_tm.tm_min) + break; + s->status |= 0x10; + qemu_irq_raise(s->irq); + break; + case 3: + if (s->current_tm.tm_sec || + s->current_tm.tm_min || s->current_tm.tm_hour) + break; + s->status |= 0x20; + qemu_irq_raise(s->irq); + break; + } + + /* Move on */ + if (s->running) + s->ti ++; + s->tick += 1000; + + /* + * Every full hour add a rough approximation of the compensation + * register to the 32kHz Timer (which drives the RTC) value. + */ + if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min) + s->tick += s->comp_reg * 1000 / 32768; + + qemu_mod_timer(s->clk, s->tick); +} + +void omap_rtc_reset(struct omap_rtc_s *s) +{ + s->interrupts = 0; + s->comp_reg = 0; + s->running = 0; + s->pm_am = 0; + s->auto_comp = 0; + s->round = 0; + s->tick = qemu_get_clock(rt_clock); + memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); + s->alarm_tm.tm_mday = 0x01; + s->status = 1 << 7; + time(&s->ti); + s->ti = mktime(s->convert(&s->ti, &s->current_tm)); + + omap_rtc_alarm_update(s); + omap_rtc_tick(s); +} + +struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, + qemu_irq *irq, omap_clk clk) +{ + int iomemtype; + struct omap_rtc_s *s = (struct omap_rtc_s *) + qemu_mallocz(sizeof(struct omap_rtc_s)); + + s->base = base; + s->irq = irq[0]; + s->alarm = irq[1]; + s->clk = qemu_new_timer(rt_clock, omap_rtc_tick, s); + s->convert = rtc_utc ? gmtime_r : localtime_r; + + omap_rtc_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_rtc_readfn, + omap_rtc_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -4051,6 +4477,7 @@ static void omap_mpu_reset(void *opaque) omap_pwl_reset(mpu); omap_pwt_reset(mpu); omap_i2c_reset(mpu->i2c); + omap_rtc_reset(mpu->rtc); cpu_reset(mpu->env); } @@ -4178,6 +4605,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); + s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], + omap_findclk(s, "clk32-kHz")); qemu_register_reset(omap_mpu_reset, s); return s; diff --git a/hw/omap.h b/hw/omap.h index 4b5b57973..9b8da8f31 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -480,6 +480,10 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, qemu_irq irq, qemu_irq *dma, omap_clk clk); i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); +struct omap_rtc_s; +struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, + qemu_irq *irq, omap_clk clk); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); -- cgit v1.2.3 From 026459262747819f90a4056292582661294342ce Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 3 Nov 2007 12:50:46 +0000 Subject: Split I^2C controller out of hw/omap.c. Insert a list of missing memory mappings from OMAP310 datasheet. Add missing "rtc" field for RTC. Correct PWL and PWT register read/write handler pointers. Add a Changelog entry about OMAP emulation. Add a qemu-doc snippet about Palm T|E platform. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3516 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 3 +- Makefile.target | 3 +- hw/omap.c | 448 ++++---------------------------------------------------- hw/omap.h | 14 +- hw/omap_i2c.c | 435 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-doc.texi | 24 +++ 6 files changed, 500 insertions(+), 427 deletions(-) create mode 100644 hw/omap_i2c.c diff --git a/Changelog b/Changelog index 3b82c1bac..101240023 100644 --- a/Changelog +++ b/Changelog @@ -5,7 +5,7 @@ - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) - Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif) - MIPS 64-bit FPU support (Thiemo Seufer) - - Xscale PDA emulation (Andrzei Zaborowski) + - Xscale PDA emulation (Andrzej Zaborowski) - ColdFire system emulation (Paul Brook) - Improved SH4 support (Magnus Damm) - MIPS64 support (Aurelien Jarno, Thiemo Seufer) @@ -16,6 +16,7 @@ - SPARC32PLUS execution support (Blue Swirl) - MIPS mipssim pequdo machine (Thiemo Seufer) - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh) + - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski) version 0.9.0: diff --git a/Makefile.target b/Makefile.target index 07047c18a..48528413f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -519,7 +519,8 @@ VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o $(AUDIODRV) wm8750.o -VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o tsc210x.o +VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o +VL_OBJS+= palm.o tsc210x.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) diff --git a/hw/omap.c b/hw/omap.c index eb80b0a3a..0a77ee4e6 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -24,8 +24,11 @@ /* Should signal the TCMI */ uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) { + uint8_t ret; + OMAP_8B_REG(addr); - return 0; + cpu_physical_memory_read(addr, &ret, 1); + return ret; } void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, @@ -3466,15 +3469,15 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr, } static CPUReadMemoryFunc *omap_pwl_readfn[] = { + omap_pwl_read, omap_badwidth_read8, omap_badwidth_read8, - omap_pwl_read, }; static CPUWriteMemoryFunc *omap_pwl_writefn[] = { + omap_pwl_write, omap_badwidth_write8, omap_badwidth_write8, - omap_pwl_write, }; void omap_pwl_reset(struct omap_mpu_state_s *s) @@ -3571,15 +3574,15 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr, } static CPUReadMemoryFunc *omap_pwt_readfn[] = { + omap_pwt_read, omap_badwidth_read8, omap_badwidth_read8, - omap_pwt_read, }; static CPUWriteMemoryFunc *omap_pwt_writefn[] = { + omap_pwt_write, omap_badwidth_write8, omap_badwidth_write8, - omap_pwt_write, }; void omap_pwt_reset(struct omap_mpu_state_s *s) @@ -3603,421 +3606,6 @@ static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, cpu_register_physical_memory(s->pwt.base, 0x800, iomemtype); } -/* Inter-Integrated Circuit Controller (only the "New I2C") */ -struct omap_i2c_s { - target_phys_addr_t base; - qemu_irq irq; - qemu_irq drq[2]; - i2c_slave slave; - i2c_bus *bus; - - uint8_t mask; - uint16_t stat; - uint16_t dma; - uint16_t count; - int count_cur; - uint32_t fifo; - int rxlen; - int txlen; - uint16_t control; - uint16_t addr[2]; - uint8_t divider; - uint8_t times[2]; - uint16_t test; -}; - -static void omap_i2c_interrupts_update(struct omap_i2c_s *s) -{ - qemu_set_irq(s->irq, s->stat & s->mask); - if ((s->dma >> 15) & 1) /* RDMA_EN */ - qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */ - if ((s->dma >> 7) & 1) /* XDMA_EN */ - qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */ -} - -/* These are only stubs now. */ -static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event) -{ - struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; - - if ((~s->control >> 15) & 1) /* I2C_EN */ - return; - - switch (event) { - case I2C_START_SEND: - case I2C_START_RECV: - s->stat |= 1 << 9; /* AAS */ - break; - case I2C_FINISH: - s->stat |= 1 << 2; /* ARDY */ - break; - case I2C_NACK: - s->stat |= 1 << 1; /* NACK */ - break; - } - - omap_i2c_interrupts_update(s); -} - -static int omap_i2c_rx(i2c_slave *i2c) -{ - struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; - uint8_t ret = 0; - - if ((~s->control >> 15) & 1) /* I2C_EN */ - return -1; - - if (s->txlen) - ret = s->fifo >> ((-- s->txlen) << 3) & 0xff; - else - s->stat |= 1 << 10; /* XUDF */ - s->stat |= 1 << 4; /* XRDY */ - - omap_i2c_interrupts_update(s); - return ret; -} - -static int omap_i2c_tx(i2c_slave *i2c, uint8_t data) -{ - struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; - - if ((~s->control >> 15) & 1) /* I2C_EN */ - return 1; - - if (s->rxlen < 4) - s->fifo |= data << ((s->rxlen ++) << 3); - else - s->stat |= 1 << 11; /* ROVR */ - s->stat |= 1 << 3; /* RRDY */ - - omap_i2c_interrupts_update(s); - return 1; -} - -static void omap_i2c_fifo_run(struct omap_i2c_s *s) -{ - int ack = 1; - - if (!i2c_bus_busy(s->bus)) - return; - - if ((s->control >> 2) & 1) { /* RM */ - if ((s->control >> 1) & 1) { /* STP */ - i2c_end_transfer(s->bus); - s->control &= ~(1 << 1); /* STP */ - s->count_cur = s->count; - } else if ((s->control >> 9) & 1) { /* TRX */ - while (ack && s->txlen) - ack = (i2c_send(s->bus, - (s->fifo >> ((-- s->txlen) << 3)) & - 0xff) >= 0); - s->stat |= 1 << 4; /* XRDY */ - } else { - while (s->rxlen < 4) - s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); - s->stat |= 1 << 3; /* RRDY */ - } - } else { - if ((s->control >> 9) & 1) { /* TRX */ - while (ack && s->count_cur && s->txlen) { - ack = (i2c_send(s->bus, - (s->fifo >> ((-- s->txlen) << 3)) & - 0xff) >= 0); - s->count_cur --; - } - if (ack && s->count_cur) - s->stat |= 1 << 4; /* XRDY */ - if (!s->count_cur) { - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ - } - } else { - while (s->count_cur && s->rxlen < 4) { - s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); - s->count_cur --; - } - if (s->rxlen) - s->stat |= 1 << 3; /* RRDY */ - } - if (!s->count_cur) { - if ((s->control >> 1) & 1) { /* STP */ - i2c_end_transfer(s->bus); - s->control &= ~(1 << 1); /* STP */ - s->count_cur = s->count; - } else { - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ - } - } - } - - s->stat |= (!ack) << 1; /* NACK */ - if (!ack) - s->control &= ~(1 << 1); /* STP */ -} - -static void omap_i2c_reset(struct omap_i2c_s *s) -{ - s->mask = 0; - s->stat = 0; - s->dma = 0; - s->count = 0; - s->count_cur = 0; - s->fifo = 0; - s->rxlen = 0; - s->txlen = 0; - s->control = 0; - s->addr[0] = 0; - s->addr[1] = 0; - s->divider = 0; - s->times[0] = 0; - s->times[1] = 0; - s->test = 0; -} - -static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; - int offset = addr - s->base; - uint16_t ret; - - switch (offset) { - case 0x00: /* I2C_REV */ - /* TODO: set a value greater or equal to real hardware */ - return 0x11; /* REV */ - - case 0x04: /* I2C_IE */ - return s->mask; - - case 0x08: /* I2C_STAT */ - return s->stat | (i2c_bus_busy(s->bus) << 12); - - case 0x0c: /* I2C_IV */ - ret = ffs(s->stat & s->mask); - if (ret) - s->stat ^= 1 << (ret - 1); - omap_i2c_interrupts_update(s); - return ret; - - case 0x14: /* I2C_BUF */ - return s->dma; - - case 0x18: /* I2C_CNT */ - return s->count_cur; /* DCOUNT */ - - case 0x1c: /* I2C_DATA */ - ret = 0; - if (s->control & (1 << 14)) { /* BE */ - ret |= ((s->fifo >> 0) & 0xff) << 8; - ret |= ((s->fifo >> 8) & 0xff) << 0; - } else { - ret |= ((s->fifo >> 8) & 0xff) << 8; - ret |= ((s->fifo >> 0) & 0xff) << 0; - } - if (s->rxlen == 1) { - s->stat |= 1 << 15; /* SBD */ - s->rxlen = 0; - } else if (s->rxlen > 1) { - if (s->rxlen > 2) - s->fifo >>= 16; - s->rxlen -= 2; - } else - /* XXX: remote access (qualifier) error - what's that? */; - if (!s->rxlen) { - s->stat |= ~(1 << 3); /* RRDY */ - if (((s->control >> 10) & 1) && /* MST */ - ((~s->control >> 9) & 1)) { /* TRX */ - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ - } - } - s->stat &= ~(1 << 11); /* ROVR */ - omap_i2c_fifo_run(s); - omap_i2c_interrupts_update(s); - return ret; - - case 0x24: /* I2C_CON */ - return s->control; - - case 0x28: /* I2C_OA */ - return s->addr[0]; - - case 0x2c: /* I2C_SA */ - return s->addr[1]; - - case 0x30: /* I2C_PSC */ - return s->divider; - - case 0x34: /* I2C_SCLL */ - return s->times[0]; - - case 0x38: /* I2C_SCLH */ - return s->times[1]; - - case 0x3c: /* I2C_SYSTEST */ - if (s->test & (1 << 15)) { /* ST_EN */ - s->test ^= 0xa; - return s->test; - } else - return s->test & ~0x300f; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_i2c_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; - int offset = addr - s->base; - int nack; - - switch (offset) { - case 0x00: /* I2C_REV */ - case 0x08: /* I2C_STAT */ - case 0x0c: /* I2C_IV */ - OMAP_BAD_REG(addr); - return; - - case 0x04: /* I2C_IE */ - s->mask = value & 0x1f; - break; - - case 0x14: /* I2C_BUF */ - s->dma = value & 0x8080; - if (value & (1 << 15)) /* RDMA_EN */ - s->mask &= ~(1 << 3); /* RRDY_IE */ - if (value & (1 << 7)) /* XDMA_EN */ - s->mask &= ~(1 << 4); /* XRDY_IE */ - break; - - case 0x18: /* I2C_CNT */ - s->count = value; /* DCOUNT */ - break; - - case 0x1c: /* I2C_DATA */ - if (s->txlen > 2) { - /* XXX: remote access (qualifier) error - what's that? */ - break; - } - s->fifo <<= 16; - s->txlen += 2; - if (s->control & (1 << 14)) { /* BE */ - s->fifo |= ((value >> 8) & 0xff) << 8; - s->fifo |= ((value >> 0) & 0xff) << 0; - } else { - s->fifo |= ((value >> 0) & 0xff) << 8; - s->fifo |= ((value >> 8) & 0xff) << 0; - } - s->stat &= ~(1 << 10); /* XUDF */ - if (s->txlen > 2) - s->stat &= ~(1 << 4); /* XRDY */ - omap_i2c_fifo_run(s); - omap_i2c_interrupts_update(s); - break; - - case 0x24: /* I2C_CON */ - s->control = value & 0xcf07; - if (~value & (1 << 15)) { /* I2C_EN */ - omap_i2c_reset(s); - break; - } - if (~value & (1 << 10)) { /* MST */ - printf("%s: I^2C slave mode not supported\n", __FUNCTION__); - break; - } - if (value & (1 << 9)) { /* XA */ - printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__); - break; - } - if (value & (1 << 0)) { /* STT */ - nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */ - (~value >> 9) & 1); /* TRX */ - s->stat |= nack << 1; /* NACK */ - s->control &= ~(1 << 0); /* STT */ - if (nack) - s->control &= ~(1 << 1); /* STP */ - else - omap_i2c_fifo_run(s); - omap_i2c_interrupts_update(s); - } - break; - - case 0x28: /* I2C_OA */ - s->addr[0] = value & 0x3ff; - i2c_set_slave_address(&s->slave, value & 0x7f); - break; - - case 0x2c: /* I2C_SA */ - s->addr[1] = value & 0x3ff; - break; - - case 0x30: /* I2C_PSC */ - s->divider = value; - break; - - case 0x34: /* I2C_SCLL */ - s->times[0] = value; - break; - - case 0x38: /* I2C_SCLH */ - s->times[1] = value; - break; - - case 0x3c: /* I2C_SYSTEST */ - s->test = value & 0xf00f; - if (value & (1 << 15)) /* ST_EN */ - printf("%s: System Test not supported\n", __FUNCTION__); - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc *omap_i2c_readfn[] = { - omap_badwidth_read16, - omap_i2c_read, - omap_badwidth_read16, -}; - -static CPUWriteMemoryFunc *omap_i2c_writefn[] = { - omap_badwidth_write16, - omap_i2c_write, - omap_i2c_write, /* TODO: Only the last fifo write can be 8 bit. */ -}; - -struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, - qemu_irq irq, qemu_irq *dma, omap_clk clk) -{ - int iomemtype; - struct omap_i2c_s *s = (struct omap_i2c_s *) - qemu_mallocz(sizeof(struct omap_i2c_s)); - - s->base = base; - s->irq = irq; - s->drq[0] = dma[0]; - s->drq[1] = dma[1]; - s->slave.event = omap_i2c_event; - s->slave.recv = omap_i2c_rx; - s->slave.send = omap_i2c_tx; - s->bus = i2c_init_bus(); - omap_i2c_reset(s); - - iomemtype = cpu_register_io_memory(0, omap_i2c_readfn, - omap_i2c_writefn, s); - cpu_register_physical_memory(s->base, 0x800, iomemtype); - - return s; -} - -i2c_bus *omap_i2c_bus(struct omap_i2c_s *s) -{ - return s->bus; -} - /* Real-time Clock module */ struct omap_rtc_s { target_phys_addr_t base; @@ -4607,6 +4195,26 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], omap_findclk(s, "clk32-kHz")); + + /* Register mappings not currenlty implemented: + * McBSP2 Comm fffb1000 - fffb17ff + * McBSP1 Audio fffb1800 - fffb1fff (not mapped on OMAP310) + * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) + * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) + * USB W2FC fffb4000 - fffb47ff + * Camera Interface fffb6800 - fffb6fff + * McBSP3 fffb7000 - fffb77ff (not mapped on OMAP310) + * USB Host fffba000 - fffba7ff + * FAC fffba800 - fffbafff + * HDQ/1-Wire fffbc000 - fffbc7ff + * LED1 fffbd000 - fffbd7ff + * LED2 fffbd800 - fffbdfff + * Mailbox fffcf000 - fffcf7ff + * Local bus IF fffec100 - fffec1ff + * Local bus MMU fffec200 - fffec2ff + * DSP MMU fffed200 - fffed2ff + */ + qemu_register_reset(omap_mpu_reset, s); return s; diff --git a/hw/omap.h b/hw/omap.h index 9b8da8f31..aced59329 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -475,11 +475,6 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, void omap_uwire_attach(struct omap_uwire_s *s, struct uwire_slave_s *slave, int chipselect); -struct omap_i2c_s; -struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, - qemu_irq irq, qemu_irq *dma, omap_clk clk); -i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); - struct omap_rtc_s; struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, qemu_irq *irq, omap_clk clk); @@ -498,6 +493,13 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, void omap_mmc_reset(struct omap_mmc_s *s); void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover); +/* omap_i2c.c */ +struct omap_i2c_s; +struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, + qemu_irq irq, qemu_irq *dma, omap_clk clk); +void omap_i2c_reset(struct omap_i2c_s *s); +i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); + # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) # define cpu_is_omap15xx(cpu) \ @@ -561,6 +563,8 @@ struct omap_mpu_state_s { struct omap_i2c_s *i2c; + struct omap_rtc_s *rtc; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c new file mode 100644 index 000000000..af00be320 --- /dev/null +++ b/hw/omap_i2c.c @@ -0,0 +1,435 @@ +/* + * TI OMAP on-chip I2C controller. Only "new I2C" mode supported. + * + * Copyright (C) 2007 Andrzej Zaborowski + * + * 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 "vl.h" + +struct omap_i2c_s { + target_phys_addr_t base; + qemu_irq irq; + qemu_irq drq[2]; + i2c_slave slave; + i2c_bus *bus; + + uint8_t mask; + uint16_t stat; + uint16_t dma; + uint16_t count; + int count_cur; + uint32_t fifo; + int rxlen; + int txlen; + uint16_t control; + uint16_t addr[2]; + uint8_t divider; + uint8_t times[2]; + uint16_t test; +}; + +static void omap_i2c_interrupts_update(struct omap_i2c_s *s) +{ + qemu_set_irq(s->irq, s->stat & s->mask); + if ((s->dma >> 15) & 1) /* RDMA_EN */ + qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */ + if ((s->dma >> 7) & 1) /* XDMA_EN */ + qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */ +} + +/* These are only stubs now. */ +static void omap_i2c_event(i2c_slave *i2c, enum i2c_event event) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; + + if ((~s->control >> 15) & 1) /* I2C_EN */ + return; + + switch (event) { + case I2C_START_SEND: + case I2C_START_RECV: + s->stat |= 1 << 9; /* AAS */ + break; + case I2C_FINISH: + s->stat |= 1 << 2; /* ARDY */ + break; + case I2C_NACK: + s->stat |= 1 << 1; /* NACK */ + break; + } + + omap_i2c_interrupts_update(s); +} + +static int omap_i2c_rx(i2c_slave *i2c) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; + uint8_t ret = 0; + + if ((~s->control >> 15) & 1) /* I2C_EN */ + return -1; + + if (s->txlen) + ret = s->fifo >> ((-- s->txlen) << 3) & 0xff; + else + s->stat |= 1 << 10; /* XUDF */ + s->stat |= 1 << 4; /* XRDY */ + + omap_i2c_interrupts_update(s); + return ret; +} + +static int omap_i2c_tx(i2c_slave *i2c, uint8_t data) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) i2c; + + if ((~s->control >> 15) & 1) /* I2C_EN */ + return 1; + + if (s->rxlen < 4) + s->fifo |= data << ((s->rxlen ++) << 3); + else + s->stat |= 1 << 11; /* ROVR */ + s->stat |= 1 << 3; /* RRDY */ + + omap_i2c_interrupts_update(s); + return 1; +} + +static void omap_i2c_fifo_run(struct omap_i2c_s *s) +{ + int ack = 1; + + if (!i2c_bus_busy(s->bus)) + return; + + if ((s->control >> 2) & 1) { /* RM */ + if ((s->control >> 1) & 1) { /* STP */ + i2c_end_transfer(s->bus); + s->control &= ~(1 << 1); /* STP */ + s->count_cur = s->count; + } else if ((s->control >> 9) & 1) { /* TRX */ + while (ack && s->txlen) + ack = (i2c_send(s->bus, + (s->fifo >> ((-- s->txlen) << 3)) & + 0xff) >= 0); + s->stat |= 1 << 4; /* XRDY */ + } else { + while (s->rxlen < 4) + s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); + s->stat |= 1 << 3; /* RRDY */ + } + } else { + if ((s->control >> 9) & 1) { /* TRX */ + while (ack && s->count_cur && s->txlen) { + ack = (i2c_send(s->bus, + (s->fifo >> ((-- s->txlen) << 3)) & + 0xff) >= 0); + s->count_cur --; + } + if (ack && s->count_cur) + s->stat |= 1 << 4; /* XRDY */ + if (!s->count_cur) { + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ + } + } else { + while (s->count_cur && s->rxlen < 4) { + s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); + s->count_cur --; + } + if (s->rxlen) + s->stat |= 1 << 3; /* RRDY */ + } + if (!s->count_cur) { + if ((s->control >> 1) & 1) { /* STP */ + i2c_end_transfer(s->bus); + s->control &= ~(1 << 1); /* STP */ + s->count_cur = s->count; + } else { + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ + } + } + } + + s->stat |= (!ack) << 1; /* NACK */ + if (!ack) + s->control &= ~(1 << 1); /* STP */ +} + +void omap_i2c_reset(struct omap_i2c_s *s) +{ + s->mask = 0; + s->stat = 0; + s->dma = 0; + s->count = 0; + s->count_cur = 0; + s->fifo = 0; + s->rxlen = 0; + s->txlen = 0; + s->control = 0; + s->addr[0] = 0; + s->addr[1] = 0; + s->divider = 0; + s->times[0] = 0; + s->times[1] = 0; + s->test = 0; +} + +static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; + int offset = addr - s->base; + uint16_t ret; + + switch (offset) { + case 0x00: /* I2C_REV */ + /* TODO: set a value greater or equal to real hardware */ + return 0x11; /* REV */ + + case 0x04: /* I2C_IE */ + return s->mask; + + case 0x08: /* I2C_STAT */ + return s->stat | (i2c_bus_busy(s->bus) << 12); + + case 0x0c: /* I2C_IV */ + ret = ffs(s->stat & s->mask); + if (ret) + s->stat ^= 1 << (ret - 1); + omap_i2c_interrupts_update(s); + return ret; + + case 0x14: /* I2C_BUF */ + return s->dma; + + case 0x18: /* I2C_CNT */ + return s->count_cur; /* DCOUNT */ + + case 0x1c: /* I2C_DATA */ + ret = 0; + if (s->control & (1 << 14)) { /* BE */ + ret |= ((s->fifo >> 0) & 0xff) << 8; + ret |= ((s->fifo >> 8) & 0xff) << 0; + } else { + ret |= ((s->fifo >> 8) & 0xff) << 8; + ret |= ((s->fifo >> 0) & 0xff) << 0; + } + if (s->rxlen == 1) { + s->stat |= 1 << 15; /* SBD */ + s->rxlen = 0; + } else if (s->rxlen > 1) { + if (s->rxlen > 2) + s->fifo >>= 16; + s->rxlen -= 2; + } else + /* XXX: remote access (qualifier) error - what's that? */; + if (!s->rxlen) { + s->stat |= ~(1 << 3); /* RRDY */ + if (((s->control >> 10) & 1) && /* MST */ + ((~s->control >> 9) & 1)) { /* TRX */ + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ + } + } + s->stat &= ~(1 << 11); /* ROVR */ + omap_i2c_fifo_run(s); + omap_i2c_interrupts_update(s); + return ret; + + case 0x24: /* I2C_CON */ + return s->control; + + case 0x28: /* I2C_OA */ + return s->addr[0]; + + case 0x2c: /* I2C_SA */ + return s->addr[1]; + + case 0x30: /* I2C_PSC */ + return s->divider; + + case 0x34: /* I2C_SCLL */ + return s->times[0]; + + case 0x38: /* I2C_SCLH */ + return s->times[1]; + + case 0x3c: /* I2C_SYSTEST */ + if (s->test & (1 << 15)) { /* ST_EN */ + s->test ^= 0xa; + return s->test; + } else + return s->test & ~0x300f; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_i2c_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; + int offset = addr - s->base; + int nack; + + switch (offset) { + case 0x00: /* I2C_REV */ + case 0x08: /* I2C_STAT */ + case 0x0c: /* I2C_IV */ + OMAP_BAD_REG(addr); + return; + + case 0x04: /* I2C_IE */ + s->mask = value & 0x1f; + break; + + case 0x14: /* I2C_BUF */ + s->dma = value & 0x8080; + if (value & (1 << 15)) /* RDMA_EN */ + s->mask &= ~(1 << 3); /* RRDY_IE */ + if (value & (1 << 7)) /* XDMA_EN */ + s->mask &= ~(1 << 4); /* XRDY_IE */ + break; + + case 0x18: /* I2C_CNT */ + s->count = value; /* DCOUNT */ + break; + + case 0x1c: /* I2C_DATA */ + if (s->txlen > 2) { + /* XXX: remote access (qualifier) error - what's that? */ + break; + } + s->fifo <<= 16; + s->txlen += 2; + if (s->control & (1 << 14)) { /* BE */ + s->fifo |= ((value >> 8) & 0xff) << 8; + s->fifo |= ((value >> 0) & 0xff) << 0; + } else { + s->fifo |= ((value >> 0) & 0xff) << 8; + s->fifo |= ((value >> 8) & 0xff) << 0; + } + s->stat &= ~(1 << 10); /* XUDF */ + if (s->txlen > 2) + s->stat &= ~(1 << 4); /* XRDY */ + omap_i2c_fifo_run(s); + omap_i2c_interrupts_update(s); + break; + + case 0x24: /* I2C_CON */ + s->control = value & 0xcf07; + if (~value & (1 << 15)) { /* I2C_EN */ + omap_i2c_reset(s); + break; + } + if (~value & (1 << 10)) { /* MST */ + printf("%s: I^2C slave mode not supported\n", __FUNCTION__); + break; + } + if (value & (1 << 9)) { /* XA */ + printf("%s: 10-bit addressing mode not supported\n", __FUNCTION__); + break; + } + if (value & (1 << 0)) { /* STT */ + nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */ + (~value >> 9) & 1); /* TRX */ + s->stat |= nack << 1; /* NACK */ + s->control &= ~(1 << 0); /* STT */ + if (nack) + s->control &= ~(1 << 1); /* STP */ + else + omap_i2c_fifo_run(s); + omap_i2c_interrupts_update(s); + } + break; + + case 0x28: /* I2C_OA */ + s->addr[0] = value & 0x3ff; + i2c_set_slave_address(&s->slave, value & 0x7f); + break; + + case 0x2c: /* I2C_SA */ + s->addr[1] = value & 0x3ff; + break; + + case 0x30: /* I2C_PSC */ + s->divider = value; + break; + + case 0x34: /* I2C_SCLL */ + s->times[0] = value; + break; + + case 0x38: /* I2C_SCLH */ + s->times[1] = value; + break; + + case 0x3c: /* I2C_SYSTEST */ + s->test = value & 0xf00f; + if (value & (1 << 15)) /* ST_EN */ + printf("%s: System Test not supported\n", __FUNCTION__); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_i2c_readfn[] = { + omap_badwidth_read16, + omap_i2c_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_i2c_writefn[] = { + omap_badwidth_write16, + omap_i2c_write, + omap_i2c_write, /* TODO: Only the last fifo write can be 8 bit. */ +}; + +struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, + qemu_irq irq, qemu_irq *dma, omap_clk clk) +{ + int iomemtype; + struct omap_i2c_s *s = (struct omap_i2c_s *) + qemu_mallocz(sizeof(struct omap_i2c_s)); + + s->base = base; + s->irq = irq; + s->drq[0] = dma[0]; + s->drq[1] = dma[1]; + s->slave.event = omap_i2c_event; + s->slave.recv = omap_i2c_rx; + s->slave.send = omap_i2c_tx; + s->bus = i2c_init_bus(); + omap_i2c_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_i2c_readfn, + omap_i2c_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +i2c_bus *omap_i2c_bus(struct omap_i2c_s *s) +{ + return s->bus; +} diff --git a/qemu-doc.texi b/qemu-doc.texi index 4d31f648e..75ba3825f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -83,6 +83,7 @@ For system emulation, the following hardware targets are supported: @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) @item Freescale MCF5208EVB (ColdFire V2). @item Arnewsh MCF5206 evaluation board (ColdFire V2). +@item Palm Tungsten|E PDA (OMAP310 processor) @end itemize For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported. @@ -2208,6 +2209,29 @@ Three on-chip UARTs WM8750 audio CODEC on I@math{^2}C and I@math{^2}S busses @end itemize +The Palm Tungsten|E PDA (codename "Cheetah") emulation includes the +following elements: + +@itemize @minus +@item +Texas Instruments OMAP310 System-on-chip (ARM 925T core) +@item +ROM and RAM memories (ROM firmware image can be loaded with -option-rom) +@item +On-chip LCD controller +@item +On-chip Real Time Clock +@item +TI TSC2102i touchscreen controller / analog-digital converter / Audio +CODEC, connected through MicroWire and I@math{^2}S busses +@item +GPIO-connected matrix keypad +@item +Secure Digital card connected to OMAP MMC/SD host +@item +Three on-chip UARTs +@end itemize + A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. -- cgit v1.2.3 From f10c315f8fa1b5ea06fdccee0001928af47d9147 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 3 Nov 2007 13:22:08 +0000 Subject: Fix incorrect PowerPC instruction fetch exception dump. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3517 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 6a026b012..6fe51107c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -785,7 +785,7 @@ void cpu_loop(CPUPPCState *env) break; case POWERPC_EXCP_ISI: /* Instruction storage exception */ EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n", - env->spr[SPR_DAR]); + env->spr[SPR_SRR0]); /* XXX: check this */ switch (env->error_code & 0xFF000000) { case 0x40000000: -- cgit v1.2.3 From faadf50e2962dd54175647a80bd6fc4319c91973 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 3 Nov 2007 13:37:12 +0000 Subject: PowerPC MMU and exception fixes: * PowerPC 601 (and probably POWER/POWER2) uses a different BAT format than later PowerPC implementation. * Bugfix in BATs check: must not stop after 4 BATs when more are provided. * Enable POWER 'rac' instruction. * Fix exception prefix for all supported PowerPC implementations. * Fix exceptions, MMU model and bus model for PowerPC 601 & 620. * Enable PowerPC 620 as it could mostly boot a PreP target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3518 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 + target-ppc/exec.h | 2 +- target-ppc/helper.c | 94 +++++++++++++++++++++++++++++++++++---------- target-ppc/op_helper.c | 9 +++-- target-ppc/translate_init.c | 62 +++++++++++++++--------------- 5 files changed, 114 insertions(+), 55 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 196f98cae..4beeab25f 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -102,6 +102,8 @@ enum { POWERPC_MMU_BOOKE, /* BookE FSL MMU model */ POWERPC_MMU_BOOKE_FSL, + /* PowerPC 601 MMU model (specific BATs format) */ + POWERPC_MMU_601, #if defined(TARGET_PPC64) /* 64 bits PowerPC MMU */ POWERPC_MMU_64B, diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 5abcee052..f56135704 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -98,7 +98,7 @@ void do_raise_exception_err (uint32_t exception, int error_code); void do_raise_exception (uint32_t exception); int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr, - int rw, int access_type, int check_BATs); + int rw, int access_type); void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, target_ulong pte0, target_ulong pte1); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f68656d5d..9d6f490b5 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -448,12 +448,65 @@ static always_inline int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, } /* Perform BAT hit & translation */ +static always_inline void bat_size_prot (CPUState *env, target_ulong *blp, + int *validp, int *protp, + target_ulong *BATu, target_ulong *BATl) +{ + target_ulong bl; + int pp, valid, prot; + + bl = (*BATu & 0x00001FFC) << 15; + valid = 0; + prot = 0; + if (((msr_pr == 0) && (*BATu & 0x00000002)) || + ((msr_pr != 0) && (*BATu & 0x00000001))) { + valid = 1; + pp = *BATl & 0x00000003; + if (pp != 0) { + prot = PAGE_READ | PAGE_EXEC; + if (pp == 0x2) + prot |= PAGE_WRITE; + } + } + *blp = bl; + *validp = valid; + *protp = prot; +} + +static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp, + int *validp, int *protp, + target_ulong *BATu, + target_ulong *BATl) +{ + target_ulong bl; + int key, pp, valid, prot; + + bl = (*BATl & 0x0000003F) << 17; + if (loglevel != 0) { + fprintf(logfile, "b %02x ==> bl %08x msk %08x\n", + *BATl & 0x0000003F, bl, ~bl); + } + prot = 0; + valid = (*BATl >> 6) & 1; + if (valid) { + pp = *BATu & 0x00000003; + if (msr_pr == 0) + key = (*BATu >> 3) & 1; + else + key = (*BATu >> 2) & 1; + prot = pp_check(key, pp, 0); + } + *blp = bl; + *validp = valid; + *protp = prot; +} + static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, target_ulong virtual, int rw, int type) { target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong base, BEPIl, BEPIu, bl; - int i, pp, pr; + int i, valid, prot; int ret = -1; #if defined (DEBUG_BATS) @@ -462,7 +515,6 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif - pr = msr_pr; switch (type) { case ACCESS_CODE: BATlt = env->IBAT[1]; @@ -480,12 +532,16 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, } #endif base = virtual & 0xFFFC0000; - for (i = 0; i < 4; i++) { + for (i = 0; i < env->nb_BATs; i++) { BATu = &BATut[i]; BATl = &BATlt[i]; BEPIu = *BATu & 0xF0000000; BEPIl = *BATu & 0x0FFE0000; - bl = (*BATu & 0x00001FFC) << 15; + if (unlikely(env->mmu_model == POWERPC_MMU_601)) { + bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl); + } else { + bat_size_prot(env, &bl, &valid, &prot, BATu, BATl); + } #if defined (DEBUG_BATS) if (loglevel != 0) { fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX @@ -497,20 +553,13 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, if ((virtual & 0xF0000000) == BEPIu && ((virtual & 0x0FFE0000) & ~bl) == BEPIl) { /* BAT matches */ - if (((pr == 0) && (*BATu & 0x00000002)) || - ((pr != 0) && (*BATu & 0x00000001))) { + if (valid != 0) { /* Get physical address */ ctx->raddr = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | (virtual & 0x0001F000); /* Compute access rights */ - pp = *BATl & 0x00000003; - ctx->prot = 0; - if (pp != 0) { - ctx->prot = PAGE_READ | PAGE_EXEC; - if (pp == 0x2) - ctx->prot |= PAGE_WRITE; - } + ctx->prot = prot; ret = check_prot(ctx->prot, rw, type); #if defined (DEBUG_BATS) if (ret == 0 && loglevel != 0) { @@ -1302,6 +1351,7 @@ static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx, ret = 0; switch (env->mmu_model) { case POWERPC_MMU_32B: + case POWERPC_MMU_601: case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: case POWERPC_MMU_SOFT_4xx: @@ -1353,7 +1403,7 @@ static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx, } int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, - int rw, int access_type, int check_BATs) + int rw, int access_type) { int ret; @@ -1370,15 +1420,15 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, ret = -1; switch (env->mmu_model) { case POWERPC_MMU_32B: + case POWERPC_MMU_601: case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: - /* Try to find a BAT */ - if (check_BATs) - ret = get_bat(env, ctx, eaddr, rw, access_type); - /* No break here */ #if defined(TARGET_PPC64) case POWERPC_MMU_64B: #endif + /* Try to find a BAT */ + if (env->nb_BATs != 0) + ret = get_bat(env, ctx, eaddr, rw, access_type); if (ret < 0) { /* We didn't match any BAT entry or don't have BATs */ ret = get_segment(env, ctx, eaddr, rw, access_type); @@ -1419,7 +1469,7 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) { mmu_ctx_t ctx; - if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0)) + if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) return -1; return ctx.raddr & TARGET_PAGE_MASK; @@ -1444,7 +1494,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, access_type = ACCESS_INT; // access_type = env->access_type; } - ret = get_physical_address(env, &ctx, address, rw, access_type, 1); + ret = get_physical_address(env, &ctx, address, rw, access_type); if (ret == 0) { ret = tlb_set_page_exec(env, address & TARGET_PAGE_MASK, ctx.raddr & TARGET_PAGE_MASK, ctx.prot, @@ -1476,6 +1526,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_40x_ESR] = 0x00000000; break; case POWERPC_MMU_32B: + case POWERPC_MMU_601: #if defined(TARGET_PPC64) case POWERPC_MMU_64B: #endif @@ -1567,6 +1618,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, env->spr[SPR_40x_ESR] = 0x00000000; break; case POWERPC_MMU_32B: + case POWERPC_MMU_601: #if defined(TARGET_PPC64) case POWERPC_MMU_64B: #endif @@ -1809,6 +1861,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) cpu_abort(env, "MMU model not implemented\n"); break; case POWERPC_MMU_32B: + case POWERPC_MMU_601: #if defined(TARGET_PPC64) case POWERPC_MMU_64B: #endif /* defined(TARGET_PPC64) */ @@ -1848,6 +1901,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) cpu_abort(env, "MMU model not implemented\n"); break; case POWERPC_MMU_32B: + case POWERPC_MMU_601: /* tlbie invalidate TLBs for all segments */ addr &= ~((target_ulong)-1 << 28); /* XXX: this case should be optimized, diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index e534fab9f..f5d26aeaa 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1682,15 +1682,18 @@ void do_POWER_mulo (void) #if !defined (CONFIG_USER_ONLY) void do_POWER_rac (void) { -#if 0 mmu_ctx_t ctx; + int nb_BATs; /* We don't have to generate many instances of this instruction, * as rac is supervisor only. */ - if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT, 1) == 0) + /* XXX: FIX THIS: Pretend we have no BAT */ + nb_BATs = env->nb_BATs; + env->nb_BATs = 0; + if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT) == 0) T0 = ctx.raddr; -#endif + env->nb_BATs = nb_BATs; } void do_POWER_rfsvc (void) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 5698622ba..dcf1e1fd0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2246,9 +2246,9 @@ static void init_excp_4xx_real (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; - env->excp_prefix = 0x00000000; - env->ivor_mask = 0x0000FFF0; - env->ivpr_mask = 0xFFFF0000; + env->excp_prefix = 0x00000000UL; + env->ivor_mask = 0x0000FFF0UL; + env->ivpr_mask = 0xFFFF0000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2271,9 +2271,9 @@ static void init_excp_4xx_softmmu (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100; env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; - env->excp_prefix = 0x00000000; - env->ivor_mask = 0x0000FFF0; - env->ivpr_mask = 0xFFFF0000; + env->excp_prefix = 0x00000000UL; + env->ivor_mask = 0x0000FFF0UL; + env->ivpr_mask = 0xFFFF0000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2298,9 +2298,9 @@ static void init_excp_BookE (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000; env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000; - env->excp_prefix = 0x00000000; - env->ivor_mask = 0x0000FFE0; - env->ivpr_mask = 0xFFFF0000; + env->excp_prefix = 0x00000000UL; + env->ivor_mask = 0x0000FFE0UL; + env->ivpr_mask = 0xFFFF0000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2321,7 +2321,7 @@ static void init_excp_601 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_IO] = 0x00000A00; env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000; - env->excp_prefix = 0xFFF00000; + env->excp_prefix = 0xFFF00000UL; /* Hardware reset vector */ env->hreset_vector = 0x00000100UL; #endif @@ -2349,7 +2349,7 @@ static void init_excp_602 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500; env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600; - env->excp_prefix = 0xFFF00000; + env->excp_prefix = 0xFFF00000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2374,6 +2374,7 @@ static void init_excp_603 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2399,6 +2400,7 @@ static void init_excp_G2 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2421,6 +2423,7 @@ static void init_excp_604 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2433,7 +2436,9 @@ static void init_excp_620 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; @@ -2445,8 +2450,9 @@ static void init_excp_620 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0xFFF00000UL; /* Hardware reset vector */ - env->hreset_vector = 0x0000000000000100ULL; /* ? */ + env->hreset_vector = 0x0000000000000100ULL; #endif } #endif /* defined(TARGET_PPC64) */ @@ -2468,6 +2474,7 @@ static void init_excp_7x0 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2491,6 +2498,7 @@ static void init_excp_750FX (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2517,6 +2525,7 @@ static void init_excp_7x5 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2542,6 +2551,7 @@ static void init_excp_7400 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2569,6 +2579,7 @@ static void init_excp_7450 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; + env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif @@ -2600,6 +2611,7 @@ static void init_excp_970 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; + env->excp_prefix = 0x00000000FFF00000ULL; /* Hardware reset vector */ env->hreset_vector = 0x0000000000000100ULL; #endif @@ -3232,7 +3244,7 @@ static void init_proc_e500 (CPUPPCState *env) #define POWERPC_INSNS_601 (POWERPC_INSNS_6xx | PPC_CACHE_DCBZ | \ PPC_SEGMENT | PPC_EXTERN | PPC_POWER_BR) #define POWERPC_MSRM_601 (0x000000000000FD70ULL) -#define POWERPC_MMU_601 (POWERPC_MMU_32B) +//#define POWERPC_MMU_601 (POWERPC_MMU_601) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_601 (bfd_mach_ppc_601) @@ -3248,7 +3260,7 @@ static void init_proc_601 (CPUPPCState *env) spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0x00000000); + 0x80010080); /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, @@ -3278,7 +3290,8 @@ static void init_proc_601 (CPUPPCState *env) init_excp_601(env); env->dcache_line_size = 64; env->icache_line_size = 64; - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); } /* PowerPC 602 */ @@ -4182,9 +4195,6 @@ static void init_proc_970 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0xFFF00000); /* XXX: This is a hack */ -#if !defined(CONFIG_USER_ONLY) - env->excp_prefix = 0xFFF00000; -#endif #if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; #endif @@ -4259,9 +4269,6 @@ static void init_proc_970FX (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0xFFF00000); /* XXX: This is a hack */ -#if !defined(CONFIG_USER_ONLY) - env->excp_prefix = 0xFFF00000; -#endif #if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; #endif @@ -4336,9 +4343,6 @@ static void init_proc_970GX (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0xFFF00000); /* XXX: This is a hack */ -#if !defined(CONFIG_USER_ONLY) - env->excp_prefix = 0xFFF00000; -#endif #if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; #endif @@ -4413,9 +4417,6 @@ static void init_proc_970MP (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0xFFF00000); /* XXX: This is a hack */ -#if !defined(CONFIG_USER_ONLY) - env->excp_prefix = 0xFFF00000; -#endif #if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; #endif @@ -4432,7 +4433,7 @@ static void init_proc_970MP (CPUPPCState *env) #define POWERPC_MSRM_620 (0x800000000005FF73ULL) #define POWERPC_MMU_620 (POWERPC_MMU_64B) #define POWERPC_EXCP_620 (POWERPC_EXCP_970) -#define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_970) +#define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_620 (bfd_mach_ppc64) #define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE) #define check_pow_620 check_pow_nocheck /* Check this */ @@ -4456,7 +4457,8 @@ static void init_proc_620 (CPUPPCState *env) init_excp_620(env); env->dcache_line_size = 64; env->icache_line_size = 64; - /* XXX: TODO: initialize internal interrupt controller */ + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); } #endif /* defined (TARGET_PPC64) */ @@ -5771,10 +5773,8 @@ static ppc_def_t ppc_defs[] = { POWERPC_DEF("7457v1.2", CPU_POWERPC_74x7_v12, 0xFFFFFFFF, 7455), /* 64 bits PowerPC */ #if defined (TARGET_PPC64) -#if defined (TODO) /* PowerPC 620 */ POWERPC_DEF("620", CPU_POWERPC_620, 0xFFFFFFFF, 620), -#endif #if defined (TODO) /* PowerPC 630 (POWER3) */ POWERPC_DEF("630", CPU_POWERPC_630, 0xFFFFFFFF, 630), -- cgit v1.2.3 From 2e13d23ac089e554fc0efd285ec2176ca36576c7 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 3 Nov 2007 14:23:07 +0000 Subject: Fix PowerPC high BATs access: BAT number was incorrect. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3519 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index dcf1e1fd0..0d648de0c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -241,7 +241,7 @@ static void spr_read_dbat (void *opaque, int sprn) static void spr_read_dbat_h (void *opaque, int sprn) { - gen_op_load_dbat(sprn & 1, (sprn - SPR_DBAT4U) / 2); + gen_op_load_dbat(sprn & 1, ((sprn - SPR_DBAT4U) / 2) + 4); } static void spr_write_dbatu (void *opaque, int sprn) @@ -251,7 +251,7 @@ static void spr_write_dbatu (void *opaque, int sprn) static void spr_write_dbatu_h (void *opaque, int sprn) { - gen_op_store_dbatu((sprn - SPR_DBAT4U) / 2); + gen_op_store_dbatu(((sprn - SPR_DBAT4U) / 2) + 4); } static void spr_write_dbatl (void *opaque, int sprn) @@ -261,7 +261,7 @@ static void spr_write_dbatl (void *opaque, int sprn) static void spr_write_dbatl_h (void *opaque, int sprn) { - gen_op_store_dbatl((sprn - SPR_DBAT4L) / 2); + gen_op_store_dbatl(((sprn - SPR_DBAT4L) / 2) + 4); } /* SDR1 */ -- cgit v1.2.3 From f3e3285dcdcf84aa3f19ae888a914660922ad5f7 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 3 Nov 2007 15:12:16 +0000 Subject: Fix some compiler warnings. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3520 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 6 ++++++ linux-user/strace.c | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index d0f650eda..6fc0bbffc 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -9,10 +9,16 @@ #ifdef TARGET_ABI32 typedef uint32_t abi_ulong; typedef int32_t abi_long; +#define TARGET_ABI_FMT_lx "%08x" +#define TARGET_ABI_FMT_ld "%d" +#define TARGET_ABI_FMT_lu "%u" #define TARGET_ABI_BITS 32 #else typedef target_ulong abi_ulong; typedef target_long abi_long; +#define TARGET_ABI_FMT_lx TARGET_FMT_lx +#define TARGET_ABI_FMT_ld TARGET_FMT_ld +#define TARGET_ABI_FMT_lu TARGET_FMT_lu #define TARGET_ABI_BITS TARGET_LONG_BITS #endif diff --git a/linux-user/strace.c b/linux-user/strace.c index 14323e7d4..c645ddfca 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -106,7 +106,8 @@ print_timeval(target_ulong tv_addr) return; tv = lock_user(tv_addr, sizeof(*tv), 1); - gemu_log("{%d,%d}", tv->tv_sec, tv->tv_usec); + gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}", + tv->tv_sec, tv->tv_usec); unlock_user(tv, tv_addr, 0); } else gemu_log("NULL"); @@ -220,12 +221,15 @@ if( ret == -1 ) { } } +#if 0 /* currently unused */ static void print_syscall_ret_raw(struct syscallname *name, target_long ret) { gemu_log(" = " TARGET_FMT_lx "\n", ret); } +#endif +#ifdef TARGET_NR__newselect static void print_syscall_ret_newselect(struct syscallname *name, target_long ret) { @@ -239,6 +243,7 @@ print_syscall_ret_newselect(struct syscallname *name, target_long ret) print_timeval(newselect_arg5); gemu_log(")\n"); } +#endif /* * An array of all of the syscalls we know about -- cgit v1.2.3 From 74e9115560fbdd6342f3e1a42ced6bd76b227f82 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 4 Nov 2007 01:16:04 +0000 Subject: Fix PowerMac NVRAM device. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3521 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mac_nvram.c | 22 ++++++++++++++++++++-- hw/macio.c | 12 +++++------- hw/ppc_chrp.c | 6 +++--- hw/ppc_mac.h | 5 +++-- hw/ppc_oldworld.c | 4 ++-- 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index f8b8d3755..8997abb9e 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -26,6 +26,9 @@ #include "ppc_mac.h" struct MacIONVRAMState { + target_phys_addr_t mem_base; + target_phys_addr_t size; + int mem_index; uint8_t data[0x2000]; }; @@ -58,6 +61,8 @@ static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { MacIONVRAMState *s = opaque; + + addr -= s->mem_base; addr = (addr >> 4) & 0x1fff; s->data[addr] = value; // printf("macio_nvram_writeb %04x = %02x\n", addr, value); @@ -68,6 +73,7 @@ static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr) MacIONVRAMState *s = opaque; uint32_t value; + addr -= s->mem_base; addr = (addr >> 4) & 0x1fff; value = s->data[addr]; // printf("macio_nvram_readb %04x = %02x\n", addr, value); @@ -87,17 +93,29 @@ static CPUReadMemoryFunc *nvram_read[] = { &macio_nvram_readb, }; -MacIONVRAMState *macio_nvram_init (int *mem_index) +MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size) { MacIONVRAMState *s; + s = qemu_mallocz(sizeof(MacIONVRAMState)); if (!s) return NULL; - *mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + s->size = size; + s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + *mem_index = s->mem_index; return s; } +void macio_nvram_map (void *opaque, target_phys_addr_t mem_base) +{ + MacIONVRAMState *s; + + s = opaque; + s->mem_base = mem_base; + cpu_register_physical_memory(mem_base, s->size, s->mem_index); +} + static uint8_t nvram_chksum (const uint8_t *buf, int n) { int sum, i; diff --git a/hw/macio.c b/hw/macio.c index 82e3e9afe..5a5db4773 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -31,7 +31,7 @@ struct macio_state_t { int pic_mem_index; int dbdma_mem_index; int cuda_mem_index; - int nvram_mem_index; + void *nvram; int nb_ide; int ide_mem_index[4]; }; @@ -68,14 +68,12 @@ static void macio_map (PCIDevice *pci_dev, int region_num, macio_state->ide_mem_index[i]); } } - if (macio_state->nvram_mem_index >= 0) { - cpu_register_physical_memory(addr + 0x60000, 0x20000, - macio_state->nvram_mem_index); - } + if (macio_state->nvram != NULL) + macio_nvram_map(macio_state->nvram, addr + 0x60000); } void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, - int dbdma_mem_index, int cuda_mem_index, int nvram_mem_index, + int dbdma_mem_index, int cuda_mem_index, void *nvram, int nb_ide, int *ide_mem_index) { PCIDevice *d; @@ -90,7 +88,7 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, macio_state->pic_mem_index = pic_mem_index; macio_state->dbdma_mem_index = dbdma_mem_index; macio_state->cuda_mem_index = cuda_mem_index; - macio_state->nvram_mem_index = nvram_mem_index; + macio_state->nvram = nvram; if (nb_ide > 4) nb_ide = 4; macio_state->nb_ide = nb_ide; diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index daa99d585..387da50ae 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -264,7 +264,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, dbdma_init(&dbdma_mem_index); macio_init(pci_bus, 0x0022, 0, pic_mem_index, dbdma_mem_index, - cuda_mem_index, -1, 2, ide_mem_index); + cuda_mem_index, NULL, 2, ide_mem_index); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); @@ -274,9 +274,9 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, graphic_depth = 15; #if 0 /* XXX: this is ugly but needed for now, or OHW won't boot */ /* The NewWorld NVRAM is not located in the MacIO device */ - nvr = macio_nvram_init(&nvram_mem_index); + nvr = macio_nvram_init(&nvram_mem_index, 0x2000); pmac_format_nvram_partition(nvr, 0x2000); - cpu_register_physical_memory(0xFFF04000, 0x20000, nvram_mem_index); + macio_nvram_map(nvr, 0xFFF04000); nvram.opaque = nvr; nvram.read_fn = &macio_nvram_read; nvram.write_fn = &macio_nvram_write; diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index 0ff80aba1..7ed7b55a9 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -43,7 +43,7 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq); /* MacIO */ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, - int dbdma_mem_index, int cuda_mem_index, int nvram_mem_index, + int dbdma_mem_index, int cuda_mem_index, void *nvram, int nb_ide, int *ide_mem_index); /* NewWorld PowerMac IDE */ @@ -62,7 +62,8 @@ PCIBus *pci_pmac_init(qemu_irq *pic); /* Mac NVRAM */ typedef struct MacIONVRAMState MacIONVRAMState; -MacIONVRAMState *macio_nvram_init (int *mem_index); +MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size); +void macio_nvram_map (void *opaque, target_phys_addr_t mem_base); void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); uint32_t macio_nvram_read (void *opaque, uint32_t addr); void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 7a0850522..49012cddf 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -271,13 +271,13 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - nvr = macio_nvram_init(&nvram_mem_index); + nvr = macio_nvram_init(&nvram_mem_index, 0x2000); pmac_format_nvram_partition(nvr, 0x2000); dbdma_init(&dbdma_mem_index); macio_init(pci_bus, 0x0017, 1, pic_mem_index, dbdma_mem_index, - cuda_mem_index, nvram_mem_index, 0, NULL); + cuda_mem_index, nvr, 0, NULL); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); -- cgit v1.2.3 From 077fc2061e254422c44b2de16c526476398113ae Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 4 Nov 2007 01:57:29 +0000 Subject: Improve PowerPC CPU state dump. Dump NIP on SPR access faults. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3522 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3b1c9919a..cd7a48346 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3556,20 +3556,22 @@ static always_inline void gen_op_mfspr (DisasContext *ctx) */ if (sprn != SPR_PVR) { if (loglevel != 0) { - fprintf(logfile, "Trying to read privileged spr %d %03x\n", - sprn, sprn); + fprintf(logfile, "Trying to read privileged spr %d %03x at" + ADDRX "\n", sprn, sprn, ctx->nip); } - printf("Trying to read privileged spr %d %03x\n", sprn, sprn); + printf("Trying to read privileged spr %d %03x at " ADDRX "\n", + sprn, sprn, ctx->nip); } GEN_EXCP_PRIVREG(ctx); } } else { /* Not defined */ if (loglevel != 0) { - fprintf(logfile, "Trying to read invalid spr %d %03x\n", - sprn, sprn); + fprintf(logfile, "Trying to read invalid spr %d %03x at " + ADDRX "\n", sprn, sprn, ctx->nip); } - printf("Trying to read invalid spr %d %03x\n", sprn, sprn); + printf("Trying to read invalid spr %d %03x at " ADDRX "\n", + sprn, sprn, ctx->nip); GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR); } @@ -3689,19 +3691,21 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) } else { /* Privilege exception */ if (loglevel != 0) { - fprintf(logfile, "Trying to write privileged spr %d %03x\n", - sprn, sprn); + fprintf(logfile, "Trying to write privileged spr %d %03x at " + ADDRX "\n", sprn, sprn, ctx->nip); } - printf("Trying to write privileged spr %d %03x\n", sprn, sprn); + printf("Trying to write privileged spr %d %03x at " ADDRX "\n", + sprn, sprn, ctx->nip); GEN_EXCP_PRIVREG(ctx); } } else { /* Not defined */ if (loglevel != 0) { - fprintf(logfile, "Trying to write invalid spr %d %03x\n", - sprn, sprn); + fprintf(logfile, "Trying to write invalid spr %d %03x at " + ADDRX "\n", sprn, sprn, ctx->nip); } - printf("Trying to write invalid spr %d %03x\n", sprn, sprn); + printf("Trying to write invalid spr %d %03x at " ADDRX "\n", + sprn, sprn, ctx->nip); GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR); } @@ -6685,24 +6689,23 @@ void cpu_dump_state (CPUState *env, FILE *f, int i; - cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX " idx %d\n", - env->nip, env->lr, env->ctr, env->mmu_idx); - cpu_fprintf(f, "MSR " REGX FILL " XER %08x " + cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX " XER %08x\n", + env->nip, env->lr, env->ctr, hreg_load_xer(env)); + cpu_fprintf(f, "MSR " REGX FILL " HID0 " REGX FILL " HF " REGX FILL + " idx %d\n", + env->msr, env->hflags, env->spr[SPR_HID0], env->mmu_idx); #if !defined(NO_TIMER_DUMP) - "TB %08x %08x " + cpu_fprintf(f, "TB %08x %08x " #if !defined(CONFIG_USER_ONLY) "DECR %08x" -#endif #endif "\n", - env->msr, hreg_load_xer(env) -#if !defined(NO_TIMER_DUMP) - , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) + cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) #if !defined(CONFIG_USER_ONLY) , cpu_ppc_load_decr(env) -#endif #endif ); +#endif for (i = 0; i < 32; i++) { if ((i & (RGPL - 1)) == 0) cpu_fprintf(f, "GPR%02d", i); @@ -6733,8 +6736,7 @@ void cpu_dump_state (CPUState *env, FILE *f, cpu_fprintf(f, "\n"); } #if !defined(CONFIG_USER_ONLY) - cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL - "SDR1 " REGX "\n", + cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " SDR1 " REGX "\n", env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1); #endif -- cgit v1.2.3 From 7a51ad822f533472cab908d2622578d51eb97dc6 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 4 Nov 2007 02:24:58 +0000 Subject: For consistency, move muls64 / mulu64 prototypes to host-utils.h Make x86_64 optimized versions inline. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3523 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec-all.h | 3 --- host-utils.c | 15 ++------------- host-utils.h | 53 ++++++++++++++++++++++++++-------------------------- target-alpha/op.c | 1 + target-i386/helper.c | 1 + 5 files changed, 31 insertions(+), 42 deletions(-) diff --git a/exec-all.h b/exec-all.h index 861688bd5..0ced25ca1 100644 --- a/exec-all.h +++ b/exec-all.h @@ -91,9 +91,6 @@ void optimize_flags_init(void); extern FILE *logfile; extern int loglevel; -void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b); -void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); - int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); diff --git a/host-utils.c b/host-utils.c index a3c838f4d..7cd0843f9 100644 --- a/host-utils.c +++ b/host-utils.c @@ -28,6 +28,7 @@ //#define DEBUG_MULDIV /* Long integer helpers */ +#if !defined(__x86_64__) static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { *plow += a; @@ -69,17 +70,10 @@ static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) *phigh += v; } - /* Unsigned 64x64 -> 128 multiplication */ void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { -#if defined(__x86_64__) - __asm__ ("mul %0\n\t" - : "=d" (*phigh), "=a" (*plow) - : "a" (a), "0" (b)); -#else mul64(plow, phigh, a, b); -#endif #if defined(DEBUG_MULDIV) printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", a, b, *phigh, *plow); @@ -89,11 +83,6 @@ void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) /* Signed 64x64 -> 128 multiplication */ void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) { -#if defined(__x86_64__) - __asm__ ("imul %0\n\t" - : "=d" (*phigh), "=a" (*plow) - : "a" (a), "0" (b)); -#else int sa, sb; sa = (a < 0); @@ -106,9 +95,9 @@ void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) if (sa ^ sb) { neg128(plow, phigh); } -#endif #if defined(DEBUG_MULDIV) printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", a, b, *phigh, *plow); #endif } +#endif /* !defined(__x86_64__) */ diff --git a/host-utils.h b/host-utils.h index fe306f6e4..234a06218 100644 --- a/host-utils.h +++ b/host-utils.h @@ -23,6 +23,28 @@ * THE SOFTWARE. */ +#if defined(__x86_64__) +#define __HAVE_FAST_MULU64__ +static always_inline void mulu64 (uint64_t *plow, uint64_t *phigh, + uint64_t a, uint64_t b) +{ + __asm__ ("mul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b)); +} +#define __HAVE_FAST_MULS64__ +static always_inline void muls64 (uint64_t *plow, uint64_t *phigh, + int64_t a, int64_t b) +{ + __asm__ ("imul %0\n\t" + : "=d" (*phigh), "=a" (*plow) + : "a" (a), "0" (b)); +} +#else +void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b); +void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); +#endif + /* Note that some of those functions may end up calling libgcc functions, depending on the host machine. It is up to the target emulation to cope with that. */ @@ -68,34 +90,13 @@ static always_inline int clz64(uint64_t val) { int cnt = 0; - if (!(val & 0xFFFFFFFF00000000ULL)) { + if (!(val >> 32)) { cnt += 32; - val <<= 32; - } - if (!(val & 0xFFFF000000000000ULL)) { - cnt += 16; - val <<= 16; - } - if (!(val & 0xFF00000000000000ULL)) { - cnt += 8; - val <<= 8; - } - if (!(val & 0xF000000000000000ULL)) { - cnt += 4; - val <<= 4; - } - if (!(val & 0xC000000000000000ULL)) { - cnt += 2; - val <<= 2; - } - if (!(val & 0x8000000000000000ULL)) { - cnt++; - val <<= 1; - } - if (!(val & 0x8000000000000000ULL)) { - cnt++; + } else { + val >>= 32; } - return cnt; + + return cnt + clz32(val); } static always_inline int clo64(uint64_t val) diff --git a/target-alpha/op.c b/target-alpha/op.c index 2a52be4f4..da93e7cdf 100644 --- a/target-alpha/op.c +++ b/target-alpha/op.c @@ -22,6 +22,7 @@ #include "config.h" #include "exec.h" +#include "host-utils.h" #include "op_helper.h" diff --git a/target-i386/helper.c b/target-i386/helper.c index bb927f673..0a75e8c33 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec.h" +#include "host-utils.h" //#define DEBUG_PCALL -- cgit v1.2.3 From 056401eae60953822098ff1dc30860364c9681be Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 4 Nov 2007 02:55:33 +0000 Subject: PowerPC 601 need specific callbacks for its BATs setup. Implement PowerPC 601 HID0 register, needed for little-endian mode support. As a consequence, we need to merge hflags coming from MSR with other ones. Use little-endian mode from hflags instead of MSR during code translation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3524 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 5 +++- target-ppc/helper.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ target-ppc/helper_regs.h | 19 ++++++++---- target-ppc/op.c | 19 +++++------- target-ppc/op_helper.c | 21 +++++++++---- target-ppc/op_helper.h | 2 +- target-ppc/translate.c | 21 +++++++------ target-ppc/translate_init.c | 11 ++++++- 8 files changed, 136 insertions(+), 35 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 4beeab25f..939dbcd98 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -651,7 +651,8 @@ struct CPUPPCState { /* Those resources are used only in Qemu core */ jmp_buf jmp_env; int user_mode_only; /* user mode only simulation */ - target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ + target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ + target_ulong hflags_nmsr; /* specific hflags, not comming from MSR */ int mmu_idx; /* precomputed MMU index to speed up mem accesses */ /* Power management */ @@ -698,6 +699,8 @@ target_ulong do_load_dbatu (CPUPPCState *env, int nr); target_ulong do_load_dbatl (CPUPPCState *env, int nr); void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value); void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value); +void do_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value); +void do_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value); target_ulong do_load_sdr1 (CPUPPCState *env); void do_store_sdr1 (CPUPPCState *env, target_ulong value); #if defined(TARGET_PPC64) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 9d6f490b5..9fd9721cd 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -482,10 +482,12 @@ static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp, int key, pp, valid, prot; bl = (*BATl & 0x0000003F) << 17; +#if defined (DEBUG_BATS) if (loglevel != 0) { fprintf(logfile, "b %02x ==> bl %08x msk %08x\n", *BATl & 0x0000003F, bl, ~bl); } +#endif prot = 0; valid = (*BATl >> 6) & 1; if (valid) { @@ -1836,6 +1838,76 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) env->DBAT[1][nr] = value; } +void do_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value) +{ + target_ulong mask; + int do_inval; + + dump_store_bat(env, 'I', 0, nr, value); + if (env->IBAT[0][nr] != value) { + do_inval = 0; + mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; + if (env->IBAT[1][nr] & 0x40) { + /* Invalidate BAT only if it is valid */ +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + do_inval = 1; +#endif + } + /* When storing valid upper BAT, mask BEPI and BRPN + * and invalidate all TLBs covered by this BAT + */ + env->IBAT[0][nr] = (value & 0x00001FFFUL) | + (value & ~0x0001FFFFUL & ~mask); + env->DBAT[0][nr] = env->IBAT[0][nr]; + if (env->IBAT[1][nr] & 0x40) { +#if !defined(FLUSH_ALL_TLBS) + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + do_inval = 1; +#endif + } +#if defined(FLUSH_ALL_TLBS) + if (do_inval) + tlb_flush(env, 1); +#endif + } +} + +void do_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value) +{ + target_ulong mask; + int do_inval; + + dump_store_bat(env, 'I', 1, nr, value); + if (env->IBAT[1][nr] != value) { + do_inval = 0; + if (env->IBAT[1][nr] & 0x40) { +#if !defined(FLUSH_ALL_TLBS) + mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + do_inval = 1; +#endif + } + if (value & 0x40) { +#if !defined(FLUSH_ALL_TLBS) + mask = (value << 17) & 0x0FFE0000UL; + do_invalidate_BAT(env, env->IBAT[0][nr], mask); +#else + do_inval = 1; +#endif + } + env->IBAT[1][nr] = value; + env->DBAT[1][nr] = value; +#if defined(FLUSH_ALL_TLBS) + if (do_inval) + tlb_flush(env, 1); +#endif + } +} + /*****************************************************************************/ /* TLB management */ void ppc_tlb_invalidate_all (CPUPPCState *env) @@ -2684,6 +2756,7 @@ static always_inline void powerpc_excp (CPUState *env, * any special case that could occur. Just store MSR and update hflags */ env->msr = new_msr; + env->hflags_nmsr = 0x00000000; hreg_compute_hflags(env); env->nip = vector; /* Reset exception state */ diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index 2a5de2ed1..c52ae9ebc 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -58,6 +58,17 @@ static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) env->tgpr[3] = tmp; } +static always_inline void hreg_compute_mem_idx (CPUPPCState *env) +{ +#if defined (TARGET_PPC64H) + /* Precompute MMU index */ + if (msr_pr == 0 && msr_hv != 0) + env->mmu_idx = 2; + else +#endif + env->mmu_idx = 1 - msr_pr; +} + static always_inline void hreg_compute_hflags (CPUPPCState *env) { target_ulong hflags_mask; @@ -70,14 +81,12 @@ static always_inline void hreg_compute_hflags (CPUPPCState *env) hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF); #if defined (TARGET_PPC64H) hflags_mask |= 1ULL << MSR_HV; - /* Precompute MMU index */ - if (msr_pr == 0 && msr_hv != 0) - env->mmu_idx = 2; - else #endif #endif - env->mmu_idx = 1 - msr_pr; + hreg_compute_mem_idx(env); env->hflags = env->msr & hflags_mask; + /* Merge with hflags coming from other registers */ + env->hflags |= env->hflags_nmsr; } static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) diff --git a/target-ppc/op.c b/target-ppc/op.c index da08ec526..730dc0e90 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2190,30 +2190,27 @@ void OPPROTO op_store_601_rtcu (void) RETURN(); } +void OPPROTO op_store_hid0_601 (void) +{ + do_store_hid0_601(); + RETURN(); +} + void OPPROTO op_load_601_bat (void) { T0 = env->IBAT[PARAM1][PARAM2]; RETURN(); } -#endif /* !defined(CONFIG_USER_ONLY) */ -/* 601 unified BATs store. - * To avoid using specific MMU code for 601, we store BATs in - * IBAT and DBAT simultaneously, then emulate unified BATs. - */ -#if !defined(CONFIG_USER_ONLY) void OPPROTO op_store_601_batl (void) { - int nr = PARAM1; - - env->IBAT[1][nr] = T0; - env->DBAT[1][nr] = T0; + do_store_ibatl_601(env, PARAM1, T0); RETURN(); } void OPPROTO op_store_601_batu (void) { - do_store_601_batu(PARAM1); + do_store_ibatu_601(env, PARAM1, T0); RETURN(); } #endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index f5d26aeaa..6ed9c9533 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1701,12 +1701,23 @@ void do_POWER_rfsvc (void) __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); } -/* PowerPC 601 BAT management helper */ -void do_store_601_batu (int nr) +void do_store_hid0_601 (void) { - do_store_ibatu(env, nr, (uint32_t)T0); - env->DBAT[0][nr] = env->IBAT[0][nr]; - env->DBAT[1][nr] = env->IBAT[1][nr]; + uint32_t hid0; + + hid0 = env->spr[SPR_HID0]; + if ((T0 ^ hid0) & 0x00000008) { + /* Change current endianness */ + env->hflags &= ~(1 << MSR_LE); + env->hflags_nmsr &= ~(1 << MSR_LE); + env->hflags_nmsr |= (1 << MSR_LE) & (((T0 >> 3) & 1) << MSR_LE); + env->hflags |= env->hflags_nmsr; + if (loglevel != 0) { + fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n", + __func__, T0 & 0x8 ? 'l' : 'b', env->hflags); + } + } + env->spr[SPR_HID0] = T0; } #endif diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 915b32a28..6575d3df6 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -155,7 +155,6 @@ void do_load_74xx_tlb (int is_code); #endif /* POWER / PowerPC 601 specific helpers */ -void do_store_601_batu (int nr); void do_POWER_abso (void); void do_POWER_clcs (void); void do_POWER_div (void); @@ -168,6 +167,7 @@ void do_POWER_mulo (void); #if !defined(CONFIG_USER_ONLY) void do_POWER_rac (void); void do_POWER_rfsvc (void); +void do_store_hid0_601 (void); #endif /* PowerPC 602 specific helper */ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index cd7a48346..1adff9fdf 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6801,7 +6801,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, opc_handler_t **table, *handler; target_ulong pc_start; uint16_t *gen_opc_end; - int supervisor; + int supervisor, little_endian; int single_step, branch_step; int j, lj = -1; @@ -6821,11 +6821,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, #if !defined(CONFIG_USER_ONLY) ctx.supervisor = supervisor; #endif + little_endian = env->hflags & (1 << MSR_LE) ? 1 : 0; #if defined(TARGET_PPC64) ctx.sf_mode = msr_sf; - ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | msr_le; + ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | little_endian; #else - ctx.mem_idx = (supervisor << 1) | msr_le; + ctx.mem_idx = (supervisor << 1) | little_endian; #endif ctx.dcache_line_size = env->dcache_line_size; ctx.fpu_enabled = msr_fp; @@ -6880,18 +6881,16 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, ctx.nip, supervisor, (int)msr_ir); } #endif - ctx.opcode = ldl_code(ctx.nip); - if (msr_le) { - ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) | - ((ctx.opcode & 0x00FF0000) >> 8) | - ((ctx.opcode & 0x0000FF00) << 8) | - ((ctx.opcode & 0x000000FF) << 24); + if (unlikely(little_endian)) { + ctx.opcode = bswap32(ldl_code(ctx.nip)); + } else { + ctx.opcode = ldl_code(ctx.nip); } #if defined PPC_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n", ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), msr_le ? "little" : "big"); + opc3(ctx.opcode), little_endian ? "little" : "big"); } #endif ctx.nip += 4; @@ -6986,7 +6985,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, if (loglevel & CPU_LOG_TB_IN_ASM) { int flags; flags = env->bfd_mach; - flags |= msr_le << 16; + flags |= little_endian << 16; fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); target_disas(logfile, pc_start, ctx.nip - pc_start, flags); fprintf(logfile, "\n"); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 0d648de0c..eae228b26 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -314,6 +314,15 @@ static void spr_write_601_rtcl (void *opaque, int sprn) { gen_op_store_601_rtcl(); } + +static void spr_write_hid0_601 (void *opaque, int sprn) +{ + DisasContext *ctx = opaque; + + gen_op_store_hid0_601(); + /* Must stop the translation as endianness may have changed */ + GEN_STOP(ctx); +} #endif /* Unified bats */ @@ -3259,7 +3268,7 @@ static void init_proc_601 (CPUPPCState *env) /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_hid0_601, 0x80010080); /* XXX : not implemented */ spr_register(env, SPR_HID1, "HID1", -- cgit v1.2.3 From ab3d1727d126525284843a7c00cdb4de867d98e2 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 4 Nov 2007 07:31:40 +0000 Subject: Fix debug statements git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3525 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/exec.c b/exec.c index 7c8864c8b..aa5c9aed0 100644 --- a/exec.c +++ b/exec.c @@ -339,10 +339,10 @@ void tb_flush(CPUState *env1) { CPUState *env; #if defined(DEBUG_FLUSH) - printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", - code_gen_ptr - code_gen_buffer, - nb_tbs, - nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); + printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n", + (unsigned long)(code_gen_ptr - code_gen_buffer), + nb_tbs, nb_tbs > 0 ? + ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0); #endif nb_tbs = 0; @@ -889,7 +889,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, mprotect(g2h(page_addr), qemu_host_page_size, (prot & PAGE_BITS) & ~PAGE_WRITE); #ifdef DEBUG_TB_INVALIDATE - printf("protecting code page: 0x%08lx\n", + printf("protecting code page: 0x" TARGET_FMT_lx "\n", page_addr); #endif } @@ -2089,7 +2089,7 @@ void qemu_ram_free(ram_addr_t addr) static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem read " TARGET_FMT_lx "\n", addr); + printf("Unassigned mem read " TARGET_FMT_plx "\n", addr); #endif #ifdef TARGET_SPARC do_unassigned_access(addr, 0, 0, 0); @@ -2102,7 +2102,7 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { #ifdef DEBUG_UNASSIGNED - printf("Unassigned mem write " TARGET_FMT_lx " = 0x%x\n", addr, val); + printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val); #endif #ifdef TARGET_SPARC do_unassigned_access(addr, 1, 0, 0); -- cgit v1.2.3 From e616a7e821c477fdb88cc422a8d925e0028e93b5 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 4 Nov 2007 08:49:01 +0000 Subject: Fix grackle (in fact MPC106) PCI host bridge header to avoid confusing firmwares and OSes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3526 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/grackle_pci.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 85c434c8e..af63a4155 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -115,22 +115,6 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) d->config[0x0b] = 0x06; // class_base = PCI_bridge d->config[0x0e] = 0x00; // header_type - d->config[0x18] = 0x00; // primary_bus - d->config[0x19] = 0x01; // secondary_bus - d->config[0x1a] = 0x00; // subordinate_bus - d->config[0x1c] = 0x00; - d->config[0x1d] = 0x00; - - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x00; - d->config[0x22] = 0x01; // memory_limit - d->config[0x23] = 0x00; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x00; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x00; - #if 0 /* PCI2PCI bridge same values as PearPC - check this */ d->config[0x00] = 0x11; // vendor_id -- cgit v1.2.3 From b854bc196f5c4b4e3299c0b0ee63cf828ece9e77 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 4 Nov 2007 11:42:11 +0000 Subject: Make accesses with wrong width also work as apparently real hardware allows them when the fault is disabled. Fix DMA register writes if target_phys_addr_t is 64-bit. Make more functions static. A timer hack to make PalmOS run in finite time (uses very short timer periods, much shorter than clocksource tick). Re-calculate internal clock rates on start-up. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3527 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 60 +++++++++++++++++++++++++++++++++++++++++----------------- hw/omap.h | 15 ++++++++++++--- hw/omap1_clk.c | 4 ++++ 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index 0a77ee4e6..80d56b1e7 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -27,38 +27,51 @@ uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) uint8_t ret; OMAP_8B_REG(addr); - cpu_physical_memory_read(addr, &ret, 1); + cpu_physical_memory_read(addr, (void *) &ret, 1); return ret; } void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, uint32_t value) { + uint8_t val8 = value; + OMAP_8B_REG(addr); + cpu_physical_memory_write(addr, (void *) &val8, 1); } uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) { + uint16_t ret; + OMAP_16B_REG(addr); - return 0; + cpu_physical_memory_read(addr, (void *) &ret, 2); + return ret; } void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, uint32_t value) { + uint16_t val16 = value; + OMAP_16B_REG(addr); + cpu_physical_memory_write(addr, (void *) &val16, 2); } uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr) { + uint32_t ret; + OMAP_32B_REG(addr); - return 0; + cpu_physical_memory_read(addr, (void *) &ret, 4); + return ret; } void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, uint32_t value) { OMAP_32B_REG(addr); + cpu_physical_memory_write(addr, (void *) &value, 4); } /* Interrupt Handlers */ @@ -787,7 +800,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ s->ch[ch].addr[0] &= 0x0000ffff; - s->ch[ch].addr[0] |= value << 16; + s->ch[ch].addr[0] |= (uint32_t) value << 16; break; case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ @@ -797,7 +810,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ s->ch[ch].addr[1] &= 0x0000ffff; - s->ch[ch].addr[1] |= value << 16; + s->ch[ch].addr[1] |= (uint32_t) value << 16; break; case 0x10: /* SYS_DMA_CEN_CH0 */ @@ -1033,37 +1046,37 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, } /* DMA ports */ -int omap_validate_emiff_addr(struct omap_mpu_state_s *s, +static int omap_validate_emiff_addr(struct omap_mpu_state_s *s, target_phys_addr_t addr) { return addr >= OMAP_EMIFF_BASE && addr < OMAP_EMIFF_BASE + s->sdram_size; } -int omap_validate_emifs_addr(struct omap_mpu_state_s *s, +static int omap_validate_emifs_addr(struct omap_mpu_state_s *s, target_phys_addr_t addr) { return addr >= OMAP_EMIFS_BASE && addr < OMAP_EMIFF_BASE; } -int omap_validate_imif_addr(struct omap_mpu_state_s *s, +static int omap_validate_imif_addr(struct omap_mpu_state_s *s, target_phys_addr_t addr) { return addr >= OMAP_IMIF_BASE && addr < OMAP_IMIF_BASE + s->sram_size; } -int omap_validate_tipb_addr(struct omap_mpu_state_s *s, +static int omap_validate_tipb_addr(struct omap_mpu_state_s *s, target_phys_addr_t addr) { return addr >= 0xfffb0000 && addr < 0xffff0000; } -int omap_validate_local_addr(struct omap_mpu_state_s *s, +static int omap_validate_local_addr(struct omap_mpu_state_s *s, target_phys_addr_t addr) { return addr >= OMAP_LOCALBUS_BASE && addr < OMAP_LOCALBUS_BASE + 0x1000000; } -int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, +static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, target_phys_addr_t addr) { return addr >= 0xe1010000 && addr < 0xe1020004; @@ -1110,9 +1123,23 @@ static inline void omap_timer_update(struct omap_mpu_timer_s *timer) if (timer->enable && timer->st && timer->rate) { timer->val = timer->reset_val; /* Should skip this on clk enable */ - expires = timer->time + muldiv64(timer->val << (timer->ptv + 1), + expires = muldiv64(timer->val << (timer->ptv + 1), ticks_per_sec, timer->rate); - qemu_mod_timer(timer->timer, expires); + + /* If timer expiry would be sooner than in about 1 ms and + * auto-reload isn't set, then fire immediately. This is a hack + * to make systems like PalmOS run in acceptable time. PalmOS + * sets the interval to a very low value and polls the status bit + * in a busy loop when it wants to sleep just a couple of CPU + * ticks. */ + if (expires > (ticks_per_sec >> 10) || timer->ar) + qemu_mod_timer(timer->timer, timer->time + expires); + else { + timer->val = 0; + timer->st = 0; + if (timer->it_ena) + qemu_irq_raise(timer->irq); + } } else qemu_del_timer(timer->timer); } @@ -3502,12 +3529,11 @@ static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s, { int iomemtype; - s->pwl.base = base; omap_pwl_reset(s); iomemtype = cpu_register_io_memory(0, omap_pwl_readfn, omap_pwl_writefn, s); - cpu_register_physical_memory(s->pwl.base, 0x800, iomemtype); + cpu_register_physical_memory(base, 0x800, iomemtype); omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]); } @@ -3597,13 +3623,12 @@ static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, { int iomemtype; - s->pwt.base = base; s->pwt.clk = clk; omap_pwt_reset(s); iomemtype = cpu_register_io_memory(0, omap_pwt_readfn, omap_pwt_writefn, s); - cpu_register_physical_memory(s->pwt.base, 0x800, iomemtype); + cpu_register_physical_memory(base, 0x800, iomemtype); } /* Real-time Clock module */ @@ -4207,6 +4232,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, * USB Host fffba000 - fffba7ff * FAC fffba800 - fffbafff * HDQ/1-Wire fffbc000 - fffbc7ff + * TIPB switches fffbc800 - fffbcfff * LED1 fffbd000 - fffbd7ff * LED2 fffbd800 - fffbdfff * Mailbox fffcf000 - fffcf7ff diff --git a/hw/omap.h b/hw/omap.h index aced59329..bceb45872 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -646,14 +646,23 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, # define OMAP_RO_REG(paddr) \ printf("%s: Read-only register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) -# define OMAP_8B_REG(paddr) \ + +# define TCMI_VERBOSE 1 + +# ifdef TCMI_VERBOSE +# define OMAP_8B_REG(paddr) \ printf("%s: 8-bit register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) -# define OMAP_16B_REG(paddr) \ +# define OMAP_16B_REG(paddr) \ printf("%s: 16-bit register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) -# define OMAP_32B_REG(paddr) \ +# define OMAP_32B_REG(paddr) \ printf("%s: 32-bit register " OMAP_FMT_plx "\n", \ __FUNCTION__, paddr) +# else +# define OMAP_8B_REG(paddr) +# define OMAP_16B_REG(paddr) +# define OMAP_32B_REG(paddr) +# endif #endif /* hw_omap_h */ diff --git a/hw/omap1_clk.c b/hw/omap1_clk.c index 7888e4155..c8540de70 100644 --- a/hw/omap1_clk.c +++ b/hw/omap1_clk.c @@ -742,4 +742,8 @@ void omap_clk_init(struct omap_mpu_state_s *mpu) j->multiplier = j->multiplier ?: 1; j ++; } + for (j = mpu->clks; count --; j ++) { + omap_clk_update(j); + omap_clk_rate_update(j); + } } -- cgit v1.2.3 From 741402f933bbc41eb0a51b10c7053718fca46a14 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 4 Nov 2007 11:59:15 +0000 Subject: Remove target dependent code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3528 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 28 +++++++++++++++++++++------- hw/sun4m.c | 3 ++- vl.h | 2 ++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index dcd1d46b4..c124fb702 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -395,6 +395,8 @@ struct fdctrl_t { uint8_t lock; /* Power down config (also with status regB access mode */ uint8_t pwrd; + /* Sun4m quirks? */ + int sun; /* Floppy drives */ fdrive_t drives[2]; }; @@ -405,12 +407,14 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) uint32_t retval; switch (reg & 0x07) { -#ifdef TARGET_SPARC case 0x00: - // Identify to Linux as S82078B - retval = fdctrl_read_statusB(fdctrl); + if (fdctrl->sun) { + // Identify to Linux as S82078B + retval = fdctrl_read_statusB(fdctrl); + } else { + retval = (uint32_t)(-1); + } break; -#endif case 0x01: retval = fdctrl_read_statusB(fdctrl); break; @@ -598,6 +602,7 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, fdctrl->dma_chann = dma_chann; fdctrl->io_base = io_base; fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */ + fdctrl->sun = 0; if (fdctrl->dma_chann != -1) { fdctrl->dma_en = 1; DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl); @@ -631,6 +636,17 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, return fdctrl; } +fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, + BlockDriverState **fds) +{ + fdctrl_t *fdctrl; + + fdctrl = fdctrl_init(irq, 0, 1, io_base, fds); + fdctrl->sun = 1; + + return fdctrl; +} + /* XXX: may change if moved to bdrv */ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num) { @@ -647,14 +663,12 @@ static void fdctrl_reset_irq (fdctrl_t *fdctrl) static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) { -#ifdef TARGET_SPARC // Sparc mutation - if (!fdctrl->dma_en) { + if (fdctrl->sun && !fdctrl->dma_en) { fdctrl->state &= ~FD_CTRL_BUSY; fdctrl->int_status = status; return; } -#endif if (~(fdctrl->state & FD_CTRL_INTR)) { qemu_set_irq(fdctrl->irq, 1); fdctrl->state |= FD_CTRL_INTR; diff --git a/hw/sun4m.c b/hw/sun4m.c index b3328021d..01e0deead 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -389,7 +389,8 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], serial_hds[1], serial_hds[0]); - fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table); + + sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd_table); main_esp = esp_init(bs_table, hwdef->esp_base, espdma, *espdma_irq, esp_reset); diff --git a/vl.h b/vl.h index 2ef8886a1..ad4d05f0b 100644 --- a/vl.h +++ b/vl.h @@ -1041,6 +1041,8 @@ typedef struct fdctrl_t fdctrl_t; fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, target_phys_addr_t io_base, BlockDriverState **fds); +fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, + BlockDriverState **fds); int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); /* eepro100.c */ -- cgit v1.2.3 From 51a652717490eaa2d1d03cfa940126ac538f6bdc Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 4 Nov 2007 12:00:17 +0000 Subject: Constification git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3529 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index c124fb702..26a11da98 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -179,7 +179,7 @@ typedef struct fd_format_t { const unsigned char *str; } fd_format_t; -static fd_format_t fd_formats[] = { +static const fd_format_t fd_formats[] = { /* First entry is default format */ /* 1.44 MB 3"1/2 floppy disks */ { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", }, @@ -229,7 +229,7 @@ static fd_format_t fd_formats[] = { /* Revalidate a disk drive after a disk change */ static void fd_revalidate (fdrive_t *drv) { - fd_format_t *parse; + const fd_format_t *parse; int64_t nb_sectors, size; int i, first_match, match; int nb_heads, max_track, last_sect, ro; -- cgit v1.2.3 From cf965d24064671ce2d5a874e532b8189fdb6e863 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 4 Nov 2007 12:19:22 +0000 Subject: Add register mappings in DSP space (must be accessible for MPU too). Don't set microwire CSR-busy bit too early. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3530 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++------------- hw/omap.h | 4 ++-- hw/omap_i2c.c | 4 ++-- hw/omap_mmc.c | 4 ++-- 4 files changed, 66 insertions(+), 22 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index 80d56b1e7..66e3b51f3 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -1401,7 +1401,7 @@ struct omap_32khz_timer_s { static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr) { struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; - int offset = addr - s->timer.base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* TVR */ @@ -1424,7 +1424,7 @@ static void omap_os_timer_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; - int offset = addr - s->timer.base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* TVR */ @@ -2894,7 +2894,7 @@ static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) { struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; uint16_t ret; switch (offset) { @@ -2950,7 +2950,7 @@ static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; uint16_t diff; int ln; @@ -3142,7 +3142,7 @@ static void omap_gpio_set(void *opaque, int line, int level) static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) { struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* DATA_INPUT */ @@ -3172,7 +3172,7 @@ static void omap_gpio_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; uint16_t diff; int ln; @@ -3322,7 +3322,7 @@ static void omap_uwire_transfer_start(struct omap_uwire_s *s) static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr) { struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* RDR */ @@ -3352,16 +3352,17 @@ static void omap_uwire_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* TDR */ s->txbuf = value; /* TD */ - s->control |= 1 << 14; /* CSRB */ if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ - (s->control & (1 << 12)))) /* CS_CMD */ + (s->control & (1 << 12)))) { /* CS_CMD */ + s->control |= 1 << 14; /* CSRB */ omap_uwire_transfer_start(s); + } break; case 0x04: /* CSR */ @@ -3462,7 +3463,7 @@ void omap_pwl_update(struct omap_mpu_state_s *s) static uint32_t omap_pwl_read(void *opaque, target_phys_addr_t addr) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->pwl.base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* PWL_LEVEL */ @@ -3478,7 +3479,7 @@ static void omap_pwl_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->pwl.base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* PWL_LEVEL */ @@ -3542,7 +3543,7 @@ static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s, static uint32_t omap_pwt_read(void *opaque, target_phys_addr_t addr) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->pwt.base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* FRC */ @@ -3560,7 +3561,7 @@ static void omap_pwt_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; - int offset = addr - s->pwt.base; + int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* FRC */ @@ -3679,7 +3680,7 @@ static inline int omap_rtc_bin(uint8_t num) static uint32_t omap_rtc_read(void *opaque, target_phys_addr_t addr) { struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; uint8_t i; switch (offset) { @@ -3757,7 +3758,7 @@ static void omap_rtc_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; struct tm new_tm; time_t ti[2]; @@ -4094,6 +4095,47 @@ static void omap_mpu_reset(void *opaque) cpu_reset(mpu->env); } +static const struct omap_map_s { + target_phys_addr_t phys_dsp; + target_phys_addr_t phys_mpu; + uint32_t size; + const char *name; +} omap15xx_dsp_mm[] = { + /* Strobe 0 */ + { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */ + { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */ + { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */ + { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */ + { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */ + { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */ + { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */ + { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */ + { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */ + { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */ + { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */ + { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */ + { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */ + { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */ + { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */ + { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */ + { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */ + /* Strobe 1 */ + { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */ + + { 0 } +}; + +static void omap_setup_dsp_mapping(const struct omap_map_s *map) +{ + int io; + + for (; map->phys_dsp; map ++) { + io = cpu_get_physical_page_desc(map->phys_mpu); + + cpu_register_physical_memory(map->phys_dsp, map->size, io); + } +} + static void omap_mpu_wakeup(void *opaque, int irq, int req) { struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; @@ -4241,6 +4283,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, * DSP MMU fffed200 - fffed2ff */ + omap_setup_dsp_mapping(omap15xx_dsp_mm); + qemu_register_reset(omap_mpu_reset, s); return s; diff --git a/hw/omap.h b/hw/omap.h index bceb45872..dbfc6dd40 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -546,7 +546,6 @@ struct omap_mpu_state_s { struct omap_uwire_s *microwire; struct { - target_phys_addr_t base; uint8_t output; uint8_t level; uint8_t enable; @@ -554,7 +553,6 @@ struct omap_mpu_state_s { } pwl; struct { - target_phys_addr_t base; uint8_t frc; uint8_t vrc; uint8_t gcr; @@ -665,4 +663,6 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, # define OMAP_32B_REG(paddr) # endif +# define OMAP_MPUI_REG_MASK 0x000007ff + #endif /* hw_omap_h */ diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index af00be320..878c046ce 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -194,7 +194,7 @@ void omap_i2c_reset(struct omap_i2c_s *s) static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) { struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; uint16_t ret; switch (offset) { @@ -286,7 +286,7 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; - int offset = addr - s->base; + int offset = addr & OMAP_MPUI_REG_MASK; int nack; switch (offset) { diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index 008318db3..406b404db 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -269,7 +269,7 @@ static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset) { uint16_t i; struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; - offset -= s->base; + offset &= OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* MMC_CMD */ @@ -351,7 +351,7 @@ static void omap_mmc_write(void *opaque, target_phys_addr_t offset, { int i; struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; - offset -= s->base; + offset &= OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* MMC_CMD */ -- cgit v1.2.3 From a06e5a3c6448befb8d5c1ac046cb41fc100f2cac Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 4 Nov 2007 16:58:07 +0000 Subject: Fix Solaris breakage git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3531 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index 26a11da98..c6e2362d9 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -396,7 +396,7 @@ struct fdctrl_t { /* Power down config (also with status regB access mode */ uint8_t pwrd; /* Sun4m quirks? */ - int sun; + int sun4m; /* Floppy drives */ fdrive_t drives[2]; }; @@ -408,7 +408,7 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) switch (reg & 0x07) { case 0x00: - if (fdctrl->sun) { + if (fdctrl->sun4m) { // Identify to Linux as S82078B retval = fdctrl_read_statusB(fdctrl); } else { @@ -602,7 +602,7 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, fdctrl->dma_chann = dma_chann; fdctrl->io_base = io_base; fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */ - fdctrl->sun = 0; + fdctrl->sun4m = 0; if (fdctrl->dma_chann != -1) { fdctrl->dma_en = 1; DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl); @@ -642,7 +642,7 @@ fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, fdctrl_t *fdctrl; fdctrl = fdctrl_init(irq, 0, 1, io_base, fds); - fdctrl->sun = 1; + fdctrl->sun4m = 1; return fdctrl; } @@ -664,7 +664,7 @@ static void fdctrl_reset_irq (fdctrl_t *fdctrl) static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) { // Sparc mutation - if (fdctrl->sun && !fdctrl->dma_en) { + if (fdctrl->sun4m && !fdctrl->dma_en) { fdctrl->state &= ~FD_CTRL_BUSY; fdctrl->int_status = status; return; -- cgit v1.2.3 From d6c1a327a94437f0ed74ba970b97fd962462bc77 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 4 Nov 2007 17:17:08 +0000 Subject: Fix memory corruption: bdrv_read/write API has been changed to take nb_sectors instead of len in bytes but the fdc driver has never been fixed. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3532 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index c6e2362d9..db76acb96 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1213,8 +1213,7 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) len = fdctrl->data_len - fdctrl->data_pos; if (len > FD_SECTOR_LEN) len = FD_SECTOR_LEN; - bdrv_read(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, len); + bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1); } } retval = fdctrl->fifo[pos]; @@ -1321,8 +1320,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) fdctrl->fifo[fdctrl->data_pos++] = value; if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) || fdctrl->data_pos == fdctrl->data_len) { - bdrv_write(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, FD_SECTOR_LEN); + bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1); } /* Switch from transfer mode to status mode * then from status mode to command mode -- cgit v1.2.3 From bfa30a38968c204725a007e6cf845178231d3645 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 4 Nov 2007 17:27:07 +0000 Subject: Change sysctrl register to 32 bits (original patch by Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3533 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_misc.c | 96 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 20 deletions(-) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 1a2c11a15..ebf184930 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -44,10 +44,13 @@ typedef struct MiscState { qemu_irq irq; uint8_t config; uint8_t aux1, aux2; - uint8_t diag, mctrl, sysctrl; + uint8_t diag, mctrl; + uint32_t sysctrl; } MiscState; #define MISC_SIZE 1 +#define SYSCTRL_MAXADDR 3 +#define SYSCTRL_SIZE (SYSCTRL_MAXADDR + 1) static void slavio_misc_update_irq(void *opaque) { @@ -83,7 +86,8 @@ void slavio_set_power_fail(void *opaque, int power_failing) slavio_misc_update_irq(s); } -static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) { MiscState *s = opaque; @@ -116,13 +120,6 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32 MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); s->mctrl = val & 0xff; break; - case 0x1f00000: - MISC_DPRINTF("Write system control %2.2x\n", val & 0xff); - if (val & 1) { - s->sysctrl = 0x2; - qemu_system_reset_request(); - } - break; case 0xa000000: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); @@ -156,10 +153,6 @@ static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr) ret = s->mctrl; MISC_DPRINTF("Read modem control %2.2x\n", ret); break; - case 0x1f00000: - MISC_DPRINTF("Read system control %2.2x\n", ret); - ret = s->sysctrl; - break; case 0xa000000: MISC_DPRINTF("Read power management %2.2x\n", ret); break; @@ -179,10 +172,62 @@ static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = { slavio_misc_mem_writeb, }; +static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr) +{ + MiscState *s = opaque; + uint32_t ret = 0, saddr; + + saddr = addr & SYSCTRL_MAXADDR; + switch (saddr) { + case 0: + ret = s->sysctrl; + break; + default: + break; + } + MISC_DPRINTF("Read system control reg 0x" TARGET_FMT_plx " = %x\n", addr, + ret); + return ret; +} + +static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + MiscState *s = opaque; + uint32_t saddr; + + saddr = addr & SYSCTRL_MAXADDR; + MISC_DPRINTF("Write system control reg 0x" TARGET_FMT_plx " = %x\n", addr, + val); + switch (saddr) { + case 0: + if (val & 1) { + s->sysctrl = 0x2; + qemu_system_reset_request(); + } + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = { + slavio_sysctrl_mem_readl, + slavio_sysctrl_mem_readl, + slavio_sysctrl_mem_readl, +}; + +static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = { + slavio_sysctrl_mem_writel, + slavio_sysctrl_mem_writel, + slavio_sysctrl_mem_writel, +}; + static void slavio_misc_save(QEMUFile *f, void *opaque) { MiscState *s = opaque; int tmp; + uint8_t tmp8; tmp = 0; qemu_put_be32s(f, &tmp); /* ignored, was IRQ. */ @@ -191,13 +236,15 @@ static void slavio_misc_save(QEMUFile *f, void *opaque) qemu_put_8s(f, &s->aux2); qemu_put_8s(f, &s->diag); qemu_put_8s(f, &s->mctrl); - qemu_put_8s(f, &s->sysctrl); + tmp8 = s->sysctrl & 0xff; + qemu_put_8s(f, &tmp8); } static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) { MiscState *s = opaque; int tmp; + uint8_t tmp8; if (version_id != 1) return -EINVAL; @@ -208,7 +255,8 @@ static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->aux2); qemu_get_8s(f, &s->diag); qemu_get_8s(f, &s->mctrl); - qemu_get_8s(f, &s->sysctrl); + qemu_get_8s(f, &tmp8); + s->sysctrl = (uint32_t)tmp8; return 0; } @@ -222,7 +270,9 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, if (!s) return NULL; - slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s); + /* 8 bit registers */ + slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, + slavio_misc_mem_write, s); // Slavio control cpu_register_physical_memory(base + 0x1800000, MISC_SIZE, slavio_misc_io_memory); @@ -238,15 +288,21 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, // Modem control cpu_register_physical_memory(base + 0x1b00000, MISC_SIZE, slavio_misc_io_memory); - // System control - cpu_register_physical_memory(base + 0x1f00000, MISC_SIZE, - slavio_misc_io_memory); // Power management cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory); + /* 32 bit registers */ + slavio_misc_io_memory = cpu_register_io_memory(0, slavio_sysctrl_mem_read, + slavio_sysctrl_mem_write, + s); + // System control + cpu_register_physical_memory(base + 0x1f00000, SYSCTRL_SIZE, + slavio_misc_io_memory); + s->irq = irq; - register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s); + register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, + s); qemu_register_reset(slavio_misc_reset, s); slavio_misc_reset(s); return s; -- cgit v1.2.3 From d8f699cb32c8c418b65aa6a2c252e097ae4716ae Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 4 Nov 2007 22:53:50 +0000 Subject: Zeroing ITR shouldn't ack irq zero. Fix PWT & PWL clocks, fix user refcounting for clocks, add 'hsab_ck' and 'usb_w2fc_ck'. Fix TCMI register addresses. Implement OMAP McBSP controller and connection to I2S-compatible CODECs. Add audio support for TSC2102 as an I2S CODEC. Connect TSC2102 I2S interface to CPU's McBSP1 interface in the Palm Tungsten|E. Correct '>' instead of '>>' typos. Implement GPIO PIN_CONTROL register (not in OMAP310 TRM, from OMAP1510). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3534 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 568 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- hw/omap.h | 123 +++++++++++++ hw/omap1_clk.c | 20 +- hw/palm.c | 17 +- hw/tsc210x.c | 188 ++++++++++++++++++- vl.h | 3 +- 6 files changed, 858 insertions(+), 61 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index 66e3b51f3..4efc5fa1b 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -254,7 +254,7 @@ static void omap_inth_write(void *opaque, target_phys_addr_t addr, switch (offset) { case 0x00: /* ITR */ - s->irqs &= value; + s->irqs &= value | 1; omap_inth_sir_update(s); omap_inth_update(s); return; @@ -992,7 +992,7 @@ static void omap_dma_clk_update(void *opaque, int line, int on) struct omap_dma_s *s = (struct omap_dma_s *) opaque; if (on) { - s->delay = ticks_per_sec >> 5; + s->delay = ticks_per_sec >> 7; if (s->run_count) qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); } else { @@ -1325,8 +1325,10 @@ static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, s->mode |= (value >> 15) & 1; if (s->last_wr == 0xf5) { if ((value & 0xff) == 0xa0) { - s->mode = 0; - omap_clk_put(s->timer.clk); + if (s->mode) { + s->mode = 0; + omap_clk_put(s->timer.clk); + } } else { /* XXX: on T|E hardware somehow this has no effect, * on Zire 71 it works as specified. */ @@ -2217,23 +2219,23 @@ static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr) uint32_t ret; switch (offset) { - case 0xfffecc00: /* IMIF_PRIO */ - case 0xfffecc04: /* EMIFS_PRIO */ - case 0xfffecc08: /* EMIFF_PRIO */ - case 0xfffecc0c: /* EMIFS_CONFIG */ - case 0xfffecc10: /* EMIFS_CS0_CONFIG */ - case 0xfffecc14: /* EMIFS_CS1_CONFIG */ - case 0xfffecc18: /* EMIFS_CS2_CONFIG */ - case 0xfffecc1c: /* EMIFS_CS3_CONFIG */ - case 0xfffecc24: /* EMIFF_MRS */ - case 0xfffecc28: /* TIMEOUT1 */ - case 0xfffecc2c: /* TIMEOUT2 */ - case 0xfffecc30: /* TIMEOUT3 */ - case 0xfffecc3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0xfffecc40: /* EMIFS_CFG_DYN_WAIT */ + case 0x00: /* IMIF_PRIO */ + case 0x04: /* EMIFS_PRIO */ + case 0x08: /* EMIFF_PRIO */ + case 0x0c: /* EMIFS_CONFIG */ + case 0x10: /* EMIFS_CS0_CONFIG */ + case 0x14: /* EMIFS_CS1_CONFIG */ + case 0x18: /* EMIFS_CS2_CONFIG */ + case 0x1c: /* EMIFS_CS3_CONFIG */ + case 0x24: /* EMIFF_MRS */ + case 0x28: /* TIMEOUT1 */ + case 0x2c: /* TIMEOUT2 */ + case 0x30: /* TIMEOUT3 */ + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0x40: /* EMIFS_CFG_DYN_WAIT */ return s->tcmi_regs[offset >> 2]; - case 0xfffecc20: /* EMIFF_SDRAM_CONFIG */ + case 0x20: /* EMIFF_SDRAM_CONFIG */ ret = s->tcmi_regs[offset >> 2]; s->tcmi_regs[offset >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ /* XXX: We can try using the VGA_DIRTY flag for this */ @@ -2251,23 +2253,23 @@ static void omap_tcmi_write(void *opaque, target_phys_addr_t addr, int offset = addr - s->tcmi_base; switch (offset) { - case 0xfffecc00: /* IMIF_PRIO */ - case 0xfffecc04: /* EMIFS_PRIO */ - case 0xfffecc08: /* EMIFF_PRIO */ - case 0xfffecc10: /* EMIFS_CS0_CONFIG */ - case 0xfffecc14: /* EMIFS_CS1_CONFIG */ - case 0xfffecc18: /* EMIFS_CS2_CONFIG */ - case 0xfffecc1c: /* EMIFS_CS3_CONFIG */ - case 0xfffecc20: /* EMIFF_SDRAM_CONFIG */ - case 0xfffecc24: /* EMIFF_MRS */ - case 0xfffecc28: /* TIMEOUT1 */ - case 0xfffecc2c: /* TIMEOUT2 */ - case 0xfffecc30: /* TIMEOUT3 */ - case 0xfffecc3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0xfffecc40: /* EMIFS_CFG_DYN_WAIT */ + case 0x00: /* IMIF_PRIO */ + case 0x04: /* EMIFS_PRIO */ + case 0x08: /* EMIFF_PRIO */ + case 0x10: /* EMIFS_CS0_CONFIG */ + case 0x14: /* EMIFS_CS1_CONFIG */ + case 0x18: /* EMIFS_CS2_CONFIG */ + case 0x1c: /* EMIFS_CS3_CONFIG */ + case 0x20: /* EMIFF_SDRAM_CONFIG */ + case 0x24: /* EMIFF_MRS */ + case 0x28: /* TIMEOUT1 */ + case 0x2c: /* TIMEOUT2 */ + case 0x30: /* TIMEOUT3 */ + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0x40: /* EMIFS_CFG_DYN_WAIT */ s->tcmi_regs[offset >> 2] = value; break; - case 0xfffecc0c: /* EMIFS_CONFIG */ + case 0x0c: /* EMIFS_CONFIG */ s->tcmi_regs[offset >> 2] = (value & 0xf) | (1 << 4); break; @@ -2441,7 +2443,7 @@ static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr) return s->clkm.arm_rstct2; case 0x18: /* ARM_SYSST */ - return (s->clkm.clocking_scheme < 11) | s->clkm.cold_start; + return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start; case 0x1c: /* ARM_CKOUT1 */ return s->clkm.arm_ckout1; @@ -2720,7 +2722,7 @@ static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr) return s->clkm.dsp_rstct2; case 0x18: /* DSP_SYSST */ - return (s->clkm.clocking_scheme < 11) | s->clkm.cold_start | + return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | (s->env->halted << 6); /* Quite useless... */ } @@ -2796,9 +2798,9 @@ static void omap_clkm_reset(struct omap_mpu_state_s *s) s->clkm.clocking_scheme = 0; omap_clkm_ckctl_update(s, ~0, 0x3000); s->clkm.arm_ckctl = 0x3000; - omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 & 0x0400, 0x0400); + omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400); s->clkm.arm_idlect1 = 0x0400; - omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 & 0x0100, 0x0100); + omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100); s->clkm.arm_idlect2 = 0x0100; s->clkm.arm_ewupct = 0x003f; s->clkm.arm_rstct1 = 0x0000; @@ -2822,8 +2824,11 @@ static void omap_clkm_init(target_phys_addr_t mpu_base, s->clkm.mpu_base = mpu_base; s->clkm.dsp_base = dsp_base; - s->clkm.cold_start = 0x3a; + s->clkm.arm_idlect1 = 0x03ff; + s->clkm.arm_idlect2 = 0x0100; + s->clkm.dsp_idlect1 = 0x0002; omap_clkm_reset(s); + s->clkm.cold_start = 0x3a; cpu_register_physical_memory(s->clkm.mpu_base, 0x100, iomemtype[0]); cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]); @@ -2956,9 +2961,8 @@ static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, switch (offset) { case 0x04: /* OUTPUT_REG */ - diff = s->outputs ^ (value & ~s->dir); + diff = (s->outputs ^ value) & ~s->dir; s->outputs = value; - value &= ~s->dir; while ((ln = ffs(diff))) { ln --; if (s->handler[ln]) @@ -3120,6 +3124,7 @@ struct omap_gpio_s { uint16_t edge; uint16_t mask; uint16_t ints; + uint16_t pins; }; static void omap_gpio_set(void *opaque, int line, int level) @@ -3146,7 +3151,7 @@ static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) switch (offset) { case 0x00: /* DATA_INPUT */ - return s->inputs; + return s->inputs & s->pins; case 0x04: /* DATA_OUTPUT */ return s->outputs; @@ -3162,6 +3167,10 @@ static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) case 0x14: /* INTERRUPT_STATUS */ return s->ints; + + case 0x18: /* PIN_CONTROL (not in OMAP310) */ + OMAP_BAD_REG(addr); + return s->pins; } OMAP_BAD_REG(addr); @@ -3219,6 +3228,11 @@ static void omap_gpio_write(void *opaque, target_phys_addr_t addr, qemu_irq_lower(s->irq); break; + case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ + OMAP_BAD_REG(addr); + s->pins = value; + break; + default: OMAP_BAD_REG(addr); return; @@ -3246,6 +3260,7 @@ void omap_gpio_reset(struct omap_gpio_s *s) s->edge = ~0; s->mask = ~0; s->ints = 0; + s->pins = ~0; } struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, @@ -4058,6 +4073,458 @@ struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, return s; } +/* Multi-channel Buffered Serial Port interfaces */ +struct omap_mcbsp_s { + target_phys_addr_t base; + qemu_irq txirq; + qemu_irq rxirq; + qemu_irq txdrq; + qemu_irq rxdrq; + + uint16_t spcr[2]; + uint16_t rcr[2]; + uint16_t xcr[2]; + uint16_t srgr[2]; + uint16_t mcr[2]; + uint16_t pcr; + uint16_t rcer[8]; + uint16_t xcer[8]; + int tx_rate; + int rx_rate; + int tx_req; + + struct i2s_codec_s *codec; +}; + +static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) +{ + int irq; + + switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ + case 0: + irq = (s->spcr[0] >> 1) & 1; /* RRDY */ + break; + case 3: + irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ + break; + default: + irq = 0; + break; + } + + qemu_set_irq(s->rxirq, irq); + + switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ + case 0: + irq = (s->spcr[1] >> 1) & 1; /* XRDY */ + break; + case 3: + irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ + break; + default: + irq = 0; + break; + } + + qemu_set_irq(s->txirq, irq); +} + +static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) +{ + int prev = s->tx_req; + + s->tx_req = (s->tx_rate || + (s->spcr[0] & (1 << 12))) && /* CLKSTP */ + (s->spcr[1] & (1 << 6)) && /* GRST */ + (s->spcr[1] & (1 << 0)); /* XRST */ + + if (!s->tx_req && prev) { + s->spcr[1] &= ~(1 << 1); /* XRDY */ + qemu_irq_lower(s->txdrq); + omap_mcbsp_intr_update(s); + + if (s->codec) + s->codec->tx_swallow(s->codec->opaque); + } else if (s->codec && s->tx_req && !prev) { + s->spcr[1] |= 1 << 1; /* XRDY */ + qemu_irq_raise(s->txdrq); + omap_mcbsp_intr_update(s); + } +} + +static void omap_mcbsp_rate_update(struct omap_mcbsp_s *s) +{ + int rx_clk = 0, tx_clk = 0; + int cpu_rate = 1500000; /* XXX */ + if (!s->codec) + return; + + if (s->spcr[1] & (1 << 6)) { /* GRST */ + if (s->spcr[0] & (1 << 0)) /* RRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 8))) /* CLKRM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ + rx_clk = cpu_rate / + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + if (s->spcr[1] & (1 << 0)) /* XRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 9))) /* CLKXM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ + tx_clk = cpu_rate / + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + } + + s->codec->set_rate(s->codec->opaque, rx_clk, tx_clk); +} + +static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) +{ + if (!(s->spcr[0] & 1)) { /* RRST */ + if (s->codec) + s->codec->in.len = 0; + return; + } + + if ((s->spcr[0] >> 1) & 1) /* RRDY */ + s->spcr[0] |= 1 << 2; /* RFULL */ + s->spcr[0] |= 1 << 1; /* RRDY */ + qemu_irq_raise(s->rxdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) +{ + s->spcr[0] &= ~(1 << 1); /* RRDY */ + qemu_irq_lower(s->rxdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) +{ + if (s->tx_rate) + return; + s->tx_rate = 1; + omap_mcbsp_req_update(s); +} + +static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) +{ + s->tx_rate = 0; + omap_mcbsp_req_update(s); +} + +static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + uint16_t ret; + + switch (offset) { + case 0x00: /* DRR2 */ + if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ + return 0x0000; + /* Fall through. */ + case 0x02: /* DRR1 */ + if (!s->codec) + return 0x0000; + if (s->codec->in.len < 2) { + printf("%s: Rx FIFO underrun\n", __FUNCTION__); + omap_mcbsp_rx_stop(s); + } else { + s->codec->in.len -= 2; + ret = s->codec->in.fifo[s->codec->in.start ++] << 8; + ret |= s->codec->in.fifo[s->codec->in.start ++]; + if (!s->codec->in.len) + omap_mcbsp_rx_stop(s); + return ret; + } + return 0x0000; + + case 0x04: /* DXR2 */ + case 0x06: /* DXR1 */ + return 0x0000; + + case 0x08: /* SPCR2 */ + return s->spcr[1]; + case 0x0a: /* SPCR1 */ + return s->spcr[0]; + case 0x0c: /* RCR2 */ + return s->rcr[1]; + case 0x0e: /* RCR1 */ + return s->rcr[0]; + case 0x10: /* XCR2 */ + return s->xcr[1]; + case 0x12: /* XCR1 */ + return s->xcr[0]; + case 0x14: /* SRGR2 */ + return s->srgr[1]; + case 0x16: /* SRGR1 */ + return s->srgr[0]; + case 0x18: /* MCR2 */ + return s->mcr[1]; + case 0x1a: /* MCR1 */ + return s->mcr[0]; + case 0x1c: /* RCERA */ + return s->rcer[0]; + case 0x1e: /* RCERB */ + return s->rcer[1]; + case 0x20: /* XCERA */ + return s->xcer[0]; + case 0x22: /* XCERB */ + return s->xcer[1]; + case 0x24: /* PCR0 */ + return s->pcr; + case 0x26: /* RCERC */ + return s->rcer[2]; + case 0x28: /* RCERD */ + return s->rcer[3]; + case 0x2a: /* XCERC */ + return s->xcer[2]; + case 0x2c: /* XCERD */ + return s->xcer[3]; + case 0x2e: /* RCERE */ + return s->rcer[4]; + case 0x30: /* RCERF */ + return s->rcer[5]; + case 0x32: /* XCERE */ + return s->xcer[4]; + case 0x34: /* XCERF */ + return s->xcer[5]; + case 0x36: /* RCERG */ + return s->rcer[6]; + case 0x38: /* RCERH */ + return s->rcer[7]; + case 0x3a: /* XCERG */ + return s->xcer[6]; + case 0x3c: /* XCERH */ + return s->xcer[7]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* DRR2 */ + case 0x02: /* DRR1 */ + OMAP_RO_REG(addr); + return; + + case 0x04: /* DXR2 */ + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ + return; + /* Fall through. */ + case 0x06: /* DXR1 */ + if (!s->codec) + return; + if (s->tx_req) { + if (s->codec->out.len > s->codec->out.size - 2) { + printf("%s: Tx FIFO overrun\n", __FUNCTION__); + omap_mcbsp_tx_stop(s); + } else { + s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; + if (s->codec->out.len >= s->codec->out.size) + omap_mcbsp_tx_stop(s); + } + } else + printf("%s: Tx FIFO overrun\n", __FUNCTION__); + return; + + case 0x08: /* SPCR2 */ + s->spcr[1] &= 0x0002; + s->spcr[1] |= 0x03f9 & value; + s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ + if (~value & 1) { /* XRST */ + s->spcr[1] &= ~6; + qemu_irq_lower(s->rxdrq); + if (s->codec) + s->codec->out.len = 0; + } + if (s->codec) + omap_mcbsp_rate_update(s); + omap_mcbsp_req_update(s); + return; + case 0x0a: /* SPCR1 */ + s->spcr[0] &= 0x0006; + s->spcr[0] |= 0xf8f9 & value; + if (value & (1 << 15)) /* DLB */ + printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); + if (~value & 1) { /* RRST */ + s->spcr[0] &= ~6; + qemu_irq_lower(s->txdrq); + if (s->codec) + s->codec->in.len = 0; + } + if (s->codec) + omap_mcbsp_rate_update(s); + omap_mcbsp_req_update(s); + return; + + case 0x0c: /* RCR2 */ + s->rcr[1] = value & 0xffff; + return; + case 0x0e: /* RCR1 */ + s->rcr[0] = value & 0x7fe0; + return; + case 0x10: /* XCR2 */ + s->xcr[1] = value & 0xffff; + return; + case 0x12: /* XCR1 */ + s->xcr[0] = value & 0x7fe0; + return; + case 0x14: /* SRGR2 */ + s->srgr[1] = value & 0xffff; + omap_mcbsp_rate_update(s); + return; + case 0x16: /* SRGR1 */ + s->srgr[0] = value & 0xffff; + omap_mcbsp_rate_update(s); + return; + case 0x18: /* MCR2 */ + s->mcr[1] = value & 0x03e3; + if (value & 3) /* XMCM */ + printf("%s: Tx channel selection mode enable attempt\n", + __FUNCTION__); + return; + case 0x1a: /* MCR1 */ + s->mcr[0] = value & 0x03e1; + if (value & 1) /* RMCM */ + printf("%s: Rx channel selection mode enable attempt\n", + __FUNCTION__); + return; + case 0x1c: /* RCERA */ + s->rcer[0] = value & 0xffff; + return; + case 0x1e: /* RCERB */ + s->rcer[1] = value & 0xffff; + return; + case 0x20: /* XCERA */ + s->xcer[0] = value & 0xffff; + return; + case 0x22: /* XCERB */ + s->xcer[1] = value & 0xffff; + return; + case 0x24: /* PCR0 */ + s->pcr = value & 0x7faf; + return; + case 0x26: /* RCERC */ + s->rcer[2] = value & 0xffff; + return; + case 0x28: /* RCERD */ + s->rcer[3] = value & 0xffff; + return; + case 0x2a: /* XCERC */ + s->xcer[2] = value & 0xffff; + return; + case 0x2c: /* XCERD */ + s->xcer[3] = value & 0xffff; + return; + case 0x2e: /* RCERE */ + s->rcer[4] = value & 0xffff; + return; + case 0x30: /* RCERF */ + s->rcer[5] = value & 0xffff; + return; + case 0x32: /* XCERE */ + s->xcer[4] = value & 0xffff; + return; + case 0x34: /* XCERF */ + s->xcer[5] = value & 0xffff; + return; + case 0x36: /* RCERG */ + s->rcer[6] = value & 0xffff; + return; + case 0x38: /* RCERH */ + s->rcer[7] = value & 0xffff; + return; + case 0x3a: /* XCERG */ + s->xcer[6] = value & 0xffff; + return; + case 0x3c: /* XCERH */ + s->xcer[7] = value & 0xffff; + return; + } + + OMAP_BAD_REG(addr); +} + +static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { + omap_badwidth_read16, + omap_mcbsp_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = { + omap_badwidth_write16, + omap_mcbsp_write, + omap_badwidth_write16, +}; + +static void omap_mcbsp_reset(struct omap_mcbsp_s *s) +{ + memset(&s->spcr, 0, sizeof(s->spcr)); + memset(&s->rcr, 0, sizeof(s->rcr)); + memset(&s->xcr, 0, sizeof(s->xcr)); + s->srgr[0] = 0x0001; + s->srgr[1] = 0x2000; + memset(&s->mcr, 0, sizeof(s->mcr)); + memset(&s->pcr, 0, sizeof(s->pcr)); + memset(&s->rcer, 0, sizeof(s->rcer)); + memset(&s->xcer, 0, sizeof(s->xcer)); + s->tx_req = 0; + s->tx_rate = 0; + s->rx_rate = 0; +} + +struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, + qemu_irq *irq, qemu_irq *dma, omap_clk clk) +{ + int iomemtype; + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) + qemu_mallocz(sizeof(struct omap_mcbsp_s)); + + s->base = base; + s->txirq = irq[0]; + s->rxirq = irq[1]; + s->txdrq = dma[0]; + s->rxdrq = dma[1]; + omap_mcbsp_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, + omap_mcbsp_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + + omap_mcbsp_rx_start(s); +} + +void omap_mcbsp_i2s_start(void *opaque, int line, int level) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + + omap_mcbsp_tx_start(s); +} + +void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) +{ + s->codec = slave; + slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0]; + slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0]; +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -4092,6 +4559,9 @@ static void omap_mpu_reset(void *opaque) omap_pwt_reset(mpu); omap_i2c_reset(mpu->i2c); omap_rtc_reset(mpu->rtc); + omap_mcbsp_reset(mpu->mcbsp1); + omap_mcbsp_reset(mpu->mcbsp2); + omap_mcbsp_reset(mpu->mcbsp3); cpu_reset(mpu->env); } @@ -4254,8 +4724,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); - omap_pwl_init(0xfffb5800, s, omap_findclk(s, "clk32-kHz")); - omap_pwt_init(0xfffb6000, s, omap_findclk(s, "xtal_osc_12m")); + omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck")); + omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck")); s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); @@ -4263,14 +4733,18 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], omap_findclk(s, "clk32-kHz")); + s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX], + &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck")); + s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX], + &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck")); + s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX], + &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); + /* Register mappings not currenlty implemented: - * McBSP2 Comm fffb1000 - fffb17ff - * McBSP1 Audio fffb1800 - fffb1fff (not mapped on OMAP310) * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) * USB W2FC fffb4000 - fffb47ff * Camera Interface fffb6800 - fffb6fff - * McBSP3 fffb7000 - fffb77ff (not mapped on OMAP310) * USB Host fffba000 - fffba7ff * FAC fffba800 - fffbafff * HDQ/1-Wire fffbc000 - fffbc7ff diff --git a/hw/omap.h b/hw/omap.h index dbfc6dd40..6de4f3e10 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -479,6 +479,30 @@ struct omap_rtc_s; struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, qemu_irq *irq, omap_clk clk); +struct i2s_codec_s { + void *opaque; + + /* The CPU can call this if it is generating the clock signal on the + * i2s port. The CODEC can ignore it if it is set up as a clock + * master and generates its own clock. */ + void (*set_rate)(void *opaque, int in, int out); + + void (*tx_swallow)(void *opaque); + qemu_irq rx_swallow; + qemu_irq tx_start; + + struct i2s_fifo_s { + uint8_t *fifo; + int len; + int start; + int size; + } in, out; +}; +struct omap_mcbsp_s; +struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, + qemu_irq *irq, qemu_irq *dma, omap_clk clk); +void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); @@ -536,6 +560,9 @@ struct omap_mpu_state_s { struct omap_gpio_s *gpio; + struct omap_mcbsp_s *mcbsp1; + struct omap_mcbsp_s *mcbsp3; + /* MPU public TIPB peripherals */ struct omap_32khz_timer_s *os_timer; @@ -563,6 +590,8 @@ struct omap_mpu_state_s { struct omap_rtc_s *rtc; + struct omap_mcbsp_s *mcbsp2; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; @@ -646,6 +675,7 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, __FUNCTION__, paddr) # define TCMI_VERBOSE 1 +//# define MEM_VERBOSE 1 # ifdef TCMI_VERBOSE # define OMAP_8B_REG(paddr) \ @@ -665,4 +695,97 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, # define OMAP_MPUI_REG_MASK 0x000007ff +# ifdef MEM_VERBOSE +struct io_fn { + CPUReadMemoryFunc **mem_read; + CPUWriteMemoryFunc **mem_write; + void *opaque; + int in; +}; + +static uint32_t io_readb(void *opaque, target_phys_addr_t addr) +{ + struct io_fn *s = opaque; + uint32_t ret; + + s->in ++; + ret = s->mem_read[0](s->opaque, addr); + s->in --; + if (!s->in) + fprintf(stderr, "%08x ---> %02x\n", (uint32_t) addr, ret); + return ret; +} +static uint32_t io_readh(void *opaque, target_phys_addr_t addr) +{ + struct io_fn *s = opaque; + uint32_t ret; + + s->in ++; + ret = s->mem_read[1](s->opaque, addr); + s->in --; + if (!s->in) + fprintf(stderr, "%08x ---> %04x\n", (uint32_t) addr, ret); + return ret; +} +static uint32_t io_readw(void *opaque, target_phys_addr_t addr) +{ + struct io_fn *s = opaque; + uint32_t ret; + + s->in ++; + ret = s->mem_read[2](s->opaque, addr); + s->in --; + if (!s->in) + fprintf(stderr, "%08x ---> %08x\n", (uint32_t) addr, ret); + return ret; +} +static void io_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct io_fn *s = opaque; + + if (!s->in) + fprintf(stderr, "%08x <--- %02x\n", (uint32_t) addr, value); + s->in ++; + s->mem_write[0](s->opaque, addr, value); + s->in --; +} +static void io_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct io_fn *s = opaque; + + if (!s->in) + fprintf(stderr, "%08x <--- %04x\n", (uint32_t) addr, value); + s->in ++; + s->mem_write[1](s->opaque, addr, value); + s->in --; +} +static void io_writew(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct io_fn *s = opaque; + + if (!s->in) + fprintf(stderr, "%08x <--- %08x\n", (uint32_t) addr, value); + s->in ++; + s->mem_write[2](s->opaque, addr, value); + s->in --; +} + +static CPUReadMemoryFunc *io_readfn[] = { io_readb, io_readh, io_readw, }; +static CPUWriteMemoryFunc *io_writefn[] = { io_writeb, io_writeh, io_writew, }; + +inline static int debug_register_io_memory(int io_index, + CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, + void *opaque) +{ + struct io_fn *s = qemu_malloc(sizeof(struct io_fn)); + + s->mem_read = mem_read; + s->mem_write = mem_write; + s->opaque = opaque; + s->in = 0; + return cpu_register_io_memory(io_index, io_readfn, io_writefn, s); +} +# define cpu_register_io_memory debug_register_io_memory +# endif + #endif /* hw_omap_h */ diff --git a/hw/omap1_clk.c b/hw/omap1_clk.c index c8540de70..b2ec23c13 100644 --- a/hw/omap1_clk.c +++ b/hw/omap1_clk.c @@ -307,6 +307,12 @@ static struct clk lbfree_ck = { .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, }; +static struct clk hsab_ck = { + .name = "hsab_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, +}; + static struct clk rhea1_ck = { .name = "rhea1_ck", .parent = &tc_ck, @@ -359,7 +365,7 @@ static struct clk uart2_ck = { static struct clk uart3_1510 = { .name = "uart3_ck", /* Direct from ULPD, no real parent */ - .parent = &armper_ck,/* either armper_ck or dpll4 */ + .parent = &armper_ck, /* either armper_ck or dpll4 */ .rate = 12000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; @@ -395,11 +401,12 @@ static struct clk usb_hhc_ck16xx = { .flags = CLOCK_IN_OMAP16XX, }; -static struct clk usb_dc_ck = { - .name = "usb_dc_ck", - /* Direct from ULPD, no parent */ +static struct clk usb_w2fc_mclk = { + .name = "usb_w2fc_mclk", + .alias = "usb_w2fc_ck", + .parent = &ck_48m, .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, }; static struct clk mclk_1510 = { @@ -539,6 +546,7 @@ static struct clk *onchip_clks[] = { &api_ck, &lb_ck, &lbfree_ck, + &hsab_ck, &rhea1_ck, &rhea2_ck, &lcd_ck_16xx, @@ -551,7 +559,6 @@ static struct clk *onchip_clks[] = { &uart3_16xx, &usb_clk0, &usb_hhc_ck1510, &usb_hhc_ck16xx, - &usb_dc_ck, &mclk_1510, &mclk_16xx, &mclk_310, &bclk_1510, &bclk_16xx, &bclk_310, &mmc1_ck, @@ -560,6 +567,7 @@ static struct clk *onchip_clks[] = { &cam_exclk, &cam_lclk, &clk32k, + &usb_w2fc_mclk, /* Virtual clocks */ &i2c_fck, &i2c_ick, diff --git a/hw/palm.c b/hw/palm.c index 8800dc608..bd17930f4 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -78,11 +78,18 @@ static CPUWriteMemoryFunc *static_writefn[] = { static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) { - omap_uwire_attach( - cpu->microwire, - tsc2102_init( - omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]), - 0); + struct uwire_slave_s *tsc; + AudioState *audio = 0; + +#ifdef HAS_AUDIO + audio = AUD_init(); +#endif + + tsc = tsc2102_init(omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO], + audio); + + omap_uwire_attach(cpu->microwire, tsc, 0); + omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc)); } static struct { diff --git a/hw/tsc210x.c b/hw/tsc210x.c index 31cf3a444..50d3edacd 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -32,7 +32,11 @@ struct tsc210x_state_s { qemu_irq pint; QEMUTimer *timer; + QEMUSoundCard card; struct uwire_slave_s chip; + struct i2s_codec_s codec; + uint8_t in_fifo[16384]; + uint8_t out_fifo[16384]; int x, y; int pressure; @@ -63,6 +67,13 @@ struct tsc210x_state_s { uint16_t dac_power; int64_t powerdown; uint16_t filter_data[0x14]; + + const char *name; + SWVoiceIn *adc_voice[1]; + SWVoiceOut *dac_voice[1]; + int i2s_rx_rate; + int i2s_tx_rate; + AudioState *audio; }; static const int resolution[4] = { 12, 8, 10, 12 }; @@ -171,9 +182,144 @@ static void tsc210x_reset(struct tsc210x_state_s *s) s->filter_data[0x12] = 0x7d83; s->filter_data[0x13] = 0x84ee; + s->i2s_tx_rate = 0; + s->i2s_rx_rate = 0; + qemu_set_irq(s->pint, !s->irq); } +struct tsc210x_rate_info_s { + int rate; + int dsor; + int fsref; +}; + +/* { rate, dsor, fsref } */ +static const struct tsc210x_rate_info_s tsc2101_rates[] = { + /* Fsref / 6.0 */ + { 7350, 7, 1 }, + { 8000, 7, 0 }, + /* Fsref / 5.5 */ + { 8018, 6, 1 }, + { 8727, 6, 0 }, + /* Fsref / 5.0 */ + { 8820, 5, 1 }, + { 9600, 5, 0 }, + /* Fsref / 4.0 */ + { 11025, 4, 1 }, + { 12000, 4, 0 }, + /* Fsref / 3.0 */ + { 14700, 3, 1 }, + { 16000, 3, 0 }, + /* Fsref / 2.0 */ + { 22050, 2, 1 }, + { 24000, 2, 0 }, + /* Fsref / 1.5 */ + { 29400, 1, 1 }, + { 32000, 1, 0 }, + /* Fsref */ + { 44100, 0, 1 }, + { 48000, 0, 0 }, + + { 0, 0, 0 }, +}; + +/* { rate, dsor, fsref } */ +static const struct tsc210x_rate_info_s tsc2102_rates[] = { + /* Fsref / 6.0 */ + { 7350, 63, 1 }, + { 8000, 63, 0 }, + /* Fsref / 6.0 */ + { 7350, 54, 1 }, + { 8000, 54, 0 }, + /* Fsref / 5.0 */ + { 8820, 45, 1 }, + { 9600, 45, 0 }, + /* Fsref / 4.0 */ + { 11025, 36, 1 }, + { 12000, 36, 0 }, + /* Fsref / 3.0 */ + { 14700, 27, 1 }, + { 16000, 27, 0 }, + /* Fsref / 2.0 */ + { 22050, 18, 1 }, + { 24000, 18, 0 }, + /* Fsref / 1.5 */ + { 29400, 9, 1 }, + { 32000, 9, 0 }, + /* Fsref */ + { 44100, 0, 1 }, + { 48000, 0, 0 }, + + { 0, 0, 0 }, +}; + +static inline void tsc210x_out_flush(struct tsc210x_state_s *s, int len) +{ + uint8_t *data = s->codec.out.fifo + s->codec.out.start; + uint8_t *end = data + len; + + while (data < end) + data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data); + + s->codec.out.len -= len; + if (s->codec.out.len) + memmove(s->codec.out.fifo, end, s->codec.out.len); + s->codec.out.start = 0; +} + +static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b) +{ + if (s->codec.out.len >= free_b) { + tsc210x_out_flush(s, free_b); + return; + } + + s->codec.out.size = MIN(free_b, 16384); + qemu_irq_raise(s->codec.tx_start); +} + +static void tsc2102_audio_set_format(struct tsc210x_state_s *s) +{ + int enable; + const struct tsc210x_rate_info_s *rate; + audsettings_t fmt; + + if (s->dac_voice[0]) { + tsc210x_out_flush(s, s->codec.out.len); + s->codec.out.size = 0; + AUD_set_active_out(s->dac_voice[0], 0); + AUD_close_out(&s->card, s->dac_voice[0]); + s->dac_voice[0] = 0; + } + + enable = + (~s->dac_power & (1 << 15)) && /* PWDNC */ + (~s->dac_power & (1 << 10)); /* DAPWDN */ + if (!enable) + return; + + for (rate = tsc2102_rates; rate->rate; rate ++) + if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ + rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ + break; + if (!rate->rate) { + printf("%s: unknown sampling rate configured\n", __FUNCTION__); + return; + } + + /* Force our own sampling rate even in slave DAC mode */ + fmt.endianness = 0; + fmt.nchannels = 2; + fmt.freq = rate->rate; + fmt.fmt = AUD_FMT_S16; + + s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], + "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt); + if (s->dac_voice[0]) + AUD_set_active_out(s->dac_voice[0], 1); +} + static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) { switch (reg) { @@ -437,6 +583,8 @@ static void tsc2102_audio_register_write( fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Audio 1\n"); #endif + if (s->audio) + tsc2102_audio_set_format(s); return; case 0x01: @@ -479,6 +627,8 @@ static void tsc2102_audio_register_write( fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Power\n"); #endif + if (s->audio) + tsc2102_audio_set_format(s); return; case 0x06: /* Audio Control 3 */ @@ -489,6 +639,8 @@ static void tsc2102_audio_register_write( fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Audio 3\n"); #endif + if (s->audio) + tsc2102_audio_set_format(s); return; case 0x07: /* LCH_BASS_BOOST_N0 */ @@ -718,6 +870,20 @@ static void tsc210x_touchscreen_event(void *opaque, tsc210x_pin_update(s); } +static void tsc210x_i2s_swallow(struct tsc210x_state_s *s) +{ + if (s->dac_voice[0]) + tsc210x_out_flush(s, s->codec.out.len); + else + s->codec.out.len = 0; +} + +static void tsc210x_i2s_set_rate(struct tsc210x_state_s *s, int in, int out) +{ + s->i2s_tx_rate = out; + s->i2s_rx_rate = in; +} + static void tsc210x_save(QEMUFile *f, void *opaque) { struct tsc210x_state_s *s = (struct tsc210x_state_s *) opaque; @@ -817,7 +983,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) static int tsc2102_iid = 0; -struct uwire_slave_s *tsc2102_init(qemu_irq pint) +struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) { struct tsc210x_state_s *s; @@ -830,19 +996,37 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint) s->precision = s->nextprecision = 0; s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); s->pint = pint; + s->name = "tsc2102"; + s->audio = audio; s->chip.opaque = s; s->chip.send = (void *) tsc210x_write; s->chip.receive = (void *) tsc210x_read; + s->codec.opaque = s; + s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; + s->codec.set_rate = (void *) tsc210x_i2s_set_rate; + s->codec.in.fifo = s->in_fifo; + s->codec.out.fifo = s->out_fifo; + tsc210x_reset(s); qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, "QEMU TSC2102-driven Touchscreen"); + if (s->audio) + AUD_register_card(s->audio, s->name, &s->card); + qemu_register_reset((void *) tsc210x_reset, s); - register_savevm("tsc2102", tsc2102_iid ++, 0, + register_savevm(s->name, tsc2102_iid ++, 0, tsc210x_save, tsc210x_load, s); return &s->chip; } + +struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip) +{ + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; + + return &s->codec; +} diff --git a/vl.h b/vl.h index ad4d05f0b..6df63eb20 100644 --- a/vl.h +++ b/vl.h @@ -1667,7 +1667,8 @@ void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); #include "hw/omap.h" /* tsc210x.c */ -struct uwire_slave_s *tsc2102_init(qemu_irq pint); +struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); +struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); /* mcf_uart.c */ uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr); -- cgit v1.2.3 From 4f431960976661fc60c5e7e05df6550cc592bceb Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 5 Nov 2007 03:11:37 +0000 Subject: No functional changes: remove dead code and fix indentation & wrapping lines. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3535 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/fdc.c | 395 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 196 insertions(+), 199 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index db76acb96..f0033b862 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -106,7 +106,7 @@ static void fd_init (fdrive_t *drv, BlockDriverState *bs) } static int _fd_sector (uint8_t head, uint8_t track, - uint8_t sect, uint8_t last_sect) + uint8_t sect, uint8_t last_sect) { return (((track * 2) + head) * last_sect) + sect - 1; } @@ -124,7 +124,7 @@ static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect, int ret; if (track > drv->max_track || - (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) { + (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) { FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n", head, track, sect, 1, (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, @@ -149,8 +149,8 @@ static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect, } #endif drv->head = head; - if (drv->track != track) - ret = 1; + if (drv->track != track) + ret = 1; drv->track = track; drv->sect = sect; } @@ -236,58 +236,58 @@ static void fd_revalidate (fdrive_t *drv) FLOPPY_DPRINTF("revalidate\n"); if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { - ro = bdrv_is_read_only(drv->bs); - bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect); - if (nb_heads != 0 && max_track != 0 && last_sect != 0) { - FLOPPY_DPRINTF("User defined disk (%d %d %d)", + ro = bdrv_is_read_only(drv->bs); + bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect); + if (nb_heads != 0 && max_track != 0 && last_sect != 0) { + FLOPPY_DPRINTF("User defined disk (%d %d %d)", nb_heads - 1, max_track, last_sect); - } else { - bdrv_get_geometry(drv->bs, &nb_sectors); - match = -1; - first_match = -1; - for (i = 0;; i++) { - parse = &fd_formats[i]; - if (parse->drive == FDRIVE_DRV_NONE) - break; - if (drv->drive == parse->drive || - drv->drive == FDRIVE_DRV_NONE) { - size = (parse->max_head + 1) * parse->max_track * - parse->last_sect; - if (nb_sectors == size) { - match = i; - break; - } - if (first_match == -1) - first_match = i; - } - } - if (match == -1) { - if (first_match == -1) - match = 1; - else - match = first_match; - parse = &fd_formats[match]; - } - nb_heads = parse->max_head + 1; - max_track = parse->max_track; - last_sect = parse->last_sect; - drv->drive = parse->drive; - FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str, + } else { + bdrv_get_geometry(drv->bs, &nb_sectors); + match = -1; + first_match = -1; + for (i = 0;; i++) { + parse = &fd_formats[i]; + if (parse->drive == FDRIVE_DRV_NONE) + break; + if (drv->drive == parse->drive || + drv->drive == FDRIVE_DRV_NONE) { + size = (parse->max_head + 1) * parse->max_track * + parse->last_sect; + if (nb_sectors == size) { + match = i; + break; + } + if (first_match == -1) + first_match = i; + } + } + if (match == -1) { + if (first_match == -1) + match = 1; + else + match = first_match; + parse = &fd_formats[match]; + } + nb_heads = parse->max_head + 1; + max_track = parse->max_track; + last_sect = parse->last_sect; + drv->drive = parse->drive; + FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str, nb_heads, max_track, last_sect, ro ? "ro" : "rw"); - } - if (nb_heads == 1) { - drv->flags &= ~FDISK_DBL_SIDES; - } else { - drv->flags |= FDISK_DBL_SIDES; - } - drv->max_track = max_track; - drv->last_sect = last_sect; - drv->ro = ro; + } + if (nb_heads == 1) { + drv->flags &= ~FDISK_DBL_SIDES; + } else { + drv->flags |= FDISK_DBL_SIDES; + } + drv->max_track = max_track; + drv->last_sect = last_sect; + drv->ro = ro; } else { - FLOPPY_DPRINTF("No disk in drive\n"); + FLOPPY_DPRINTF("No disk in drive\n"); drv->last_sect = 0; - drv->max_track = 0; - drv->flags &= ~FDISK_DBL_SIDES; + drv->max_track = 0; + drv->flags &= ~FDISK_DBL_SIDES; } } @@ -414,28 +414,28 @@ static uint32_t fdctrl_read (void *opaque, uint32_t reg) } else { retval = (uint32_t)(-1); } - break; + break; case 0x01: - retval = fdctrl_read_statusB(fdctrl); - break; + retval = fdctrl_read_statusB(fdctrl); + break; case 0x02: - retval = fdctrl_read_dor(fdctrl); - break; + retval = fdctrl_read_dor(fdctrl); + break; case 0x03: retval = fdctrl_read_tape(fdctrl); - break; + break; case 0x04: retval = fdctrl_read_main_status(fdctrl); - break; + break; case 0x05: retval = fdctrl_read_data(fdctrl); - break; + break; case 0x07: retval = fdctrl_read_dir(fdctrl); - break; + break; default: - retval = (uint32_t)(-1); - break; + retval = (uint32_t)(-1); + break; } FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval); @@ -450,19 +450,19 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) switch (reg & 0x07) { case 0x02: - fdctrl_write_dor(fdctrl, value); - break; + fdctrl_write_dor(fdctrl, value); + break; case 0x03: fdctrl_write_tape(fdctrl, value); - break; + break; case 0x04: fdctrl_write_rate(fdctrl, value); - break; + break; case 0x05: fdctrl_write_data(fdctrl, value); - break; + break; default: - break; + break; } } @@ -615,7 +615,8 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, fdctrl_reset(fdctrl, 0); fdctrl->state = FD_CTRL_ACTIVE; if (mem_mapped) { - io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl); + io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, + fdctrl); cpu_register_physical_memory(io_base, 0x08, io_mem); } else { register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read, @@ -665,9 +666,9 @@ static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) { // Sparc mutation if (fdctrl->sun4m && !fdctrl->dma_en) { - fdctrl->state &= ~FD_CTRL_BUSY; - fdctrl->int_status = status; - return; + fdctrl->state &= ~FD_CTRL_BUSY; + fdctrl->int_status = status; + return; } if (~(fdctrl->state & FD_CTRL_INTR)) { qemu_set_irq(fdctrl->irq, 1); @@ -727,9 +728,9 @@ static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl) /* Drive motors state indicators */ if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON) - retval |= 1 << 5; + retval |= 1 << 5; if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON) - retval |= 1 << 4; + retval |= 1 << 4; /* DMA enable */ retval |= fdctrl->dma_en << 3; /* Reset indicator */ @@ -836,9 +837,9 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) { /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); - return; - } + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); + return; + } FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); /* Reset: autoclear */ if (value & 0x80) { @@ -856,6 +857,7 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) static int fdctrl_media_changed(fdrive_t *drv) { int ret; + if (!drv->bs) return 0; ret = bdrv_media_changed(drv->bs); @@ -871,7 +873,7 @@ static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl) uint32_t retval = 0; if (fdctrl_media_changed(drv0(fdctrl)) || - fdctrl_media_changed(drv1(fdctrl))) + fdctrl_media_changed(drv1(fdctrl))) retval |= 0x80; if (retval != 0) FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval); @@ -918,7 +920,7 @@ static void fdctrl_unimplemented (fdctrl_t *fdctrl) /* Callback for transfer end (stop or abort) */ static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, - uint8_t status1, uint8_t status2) + uint8_t status1, uint8_t status2) { fdrive_t *cur_drv; @@ -1000,12 +1002,12 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) if (fdctrl->fifo[5] == 00) { fdctrl->data_len = fdctrl->fifo[8]; } else { - int tmp; + int tmp; fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); tmp = (cur_drv->last_sect - ks + 1); if (fdctrl->fifo[0] & 0x80) tmp += cur_drv->last_sect; - fdctrl->data_len *= tmp; + fdctrl->data_len *= tmp; } fdctrl->eot = fdctrl->fifo[6]; if (fdctrl->dma_en) { @@ -1014,9 +1016,9 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) dma_mode = DMA_get_channel_mode(fdctrl->dma_chann); dma_mode = (dma_mode >> 2) & 3; FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n", - dma_mode, direction, + dma_mode, direction, (128 << fdctrl->fifo[5]) * - (cur_drv->last_sect - ks + 1), fdctrl->data_len); + (cur_drv->last_sect - ks + 1), fdctrl->data_len); if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL || direction == FD_DIR_SCANH) && dma_mode == 0) || (direction == FD_DIR_WRITE && dma_mode == 2) || @@ -1030,7 +1032,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) DMA_schedule(fdctrl->dma_chann); return; } else { - FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction); + FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction); } } FLOPPY_DPRINTF("start non-DMA transfer\n"); @@ -1070,11 +1072,11 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, if (dma_len > fdctrl->data_len) dma_len = fdctrl->data_len; if (cur_drv->bs == NULL) { - if (fdctrl->data_dir == FD_DIR_WRITE) - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); - else - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); - len = 0; + if (fdctrl->data_dir == FD_DIR_WRITE) + fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); + else + fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); + len = 0; goto transfer_error; } rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; @@ -1088,45 +1090,39 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, cur_drv->track, cur_drv->sect, fd_sector(cur_drv), fd_sector(cur_drv) * 512); if (fdctrl->data_dir != FD_DIR_WRITE || - len < FD_SECTOR_LEN || rel_pos != 0) { + len < FD_SECTOR_LEN || rel_pos != 0) { /* READ & SCAN commands and realign to a sector for WRITE */ if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, 1) < 0) { + fdctrl->fifo, 1) < 0) { FLOPPY_DPRINTF("Floppy: error getting sector %d\n", fd_sector(cur_drv)); /* Sure, image size is too small... */ memset(fdctrl->fifo, 0, FD_SECTOR_LEN); } } - switch (fdctrl->data_dir) { - case FD_DIR_READ: - /* READ commands */ + switch (fdctrl->data_dir) { + case FD_DIR_READ: + /* READ commands */ DMA_write_memory (nchan, fdctrl->fifo + rel_pos, fdctrl->data_pos, len); -/* cpu_physical_memory_write(addr + fdctrl->data_pos, */ -/* fdctrl->fifo + rel_pos, len); */ - break; - case FD_DIR_WRITE: + break; + case FD_DIR_WRITE: /* WRITE commands */ DMA_read_memory (nchan, fdctrl->fifo + rel_pos, fdctrl->data_pos, len); -/* cpu_physical_memory_read(addr + fdctrl->data_pos, */ -/* fdctrl->fifo + rel_pos, len); */ if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, 1) < 0) { + fdctrl->fifo, 1) < 0) { FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); goto transfer_error; } - break; - default: - /* SCAN commands */ + break; + default: + /* SCAN commands */ { - uint8_t tmpbuf[FD_SECTOR_LEN]; + uint8_t tmpbuf[FD_SECTOR_LEN]; int ret; DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len); -/* cpu_physical_memory_read(addr + fdctrl->data_pos, */ -/* tmpbuf, len); */ ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len); if (ret == 0) { status2 = 0x08; @@ -1138,47 +1134,47 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, goto end_transfer; } } - break; + break; } - fdctrl->data_pos += len; - rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; + fdctrl->data_pos += len; + rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; if (rel_pos == 0) { /* Seek to next sector */ - FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", - cur_drv->head, cur_drv->track, cur_drv->sect, - fd_sector(cur_drv), - fdctrl->data_pos - len); + FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", + cur_drv->head, cur_drv->track, cur_drv->sect, + fd_sector(cur_drv), + fdctrl->data_pos - len); /* XXX: cur_drv->sect >= cur_drv->last_sect should be an error in fact */ if (cur_drv->sect >= cur_drv->last_sect || cur_drv->sect == fdctrl->eot) { - cur_drv->sect = 1; - if (FD_MULTI_TRACK(fdctrl->data_state)) { - if (cur_drv->head == 0 && - (cur_drv->flags & FDISK_DBL_SIDES) != 0) { + cur_drv->sect = 1; + if (FD_MULTI_TRACK(fdctrl->data_state)) { + if (cur_drv->head == 0 && + (cur_drv->flags & FDISK_DBL_SIDES) != 0) { cur_drv->head = 1; } else { cur_drv->head = 0; - cur_drv->track++; - if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) - break; + cur_drv->track++; + if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) + break; } } else { cur_drv->track++; break; } - FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", - cur_drv->head, cur_drv->track, - cur_drv->sect, fd_sector(cur_drv)); + FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", + cur_drv->head, cur_drv->track, + cur_drv->sect, fd_sector(cur_drv)); } else { cur_drv->sect++; } } } -end_transfer: + end_transfer: len = fdctrl->data_pos - start_pos; FLOPPY_DPRINTF("end transfer %d %d %d\n", - fdctrl->data_pos, len, fdctrl->data_len); + fdctrl->data_pos, len, fdctrl->data_len); if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL || fdctrl->data_dir == FD_DIR_SCANH) @@ -1188,7 +1184,7 @@ end_transfer: fdctrl->data_len -= len; // if (fdctrl->data_len == 0) fdctrl_stop_transfer(fdctrl, status0, status1, status2); -transfer_error: + transfer_error: return len; } @@ -1284,18 +1280,18 @@ static void fdctrl_format_sector (fdctrl_t *fdctrl) FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); } else { - if (cur_drv->sect == cur_drv->last_sect) { - fdctrl->data_state &= ~FD_STATE_FORMAT; - /* Last sector done */ - if (FD_DID_SEEK(fdctrl->data_state)) - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); - else - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); - } else { - /* More to do */ - fdctrl->data_pos = 0; - fdctrl->data_len = 4; - } + if (cur_drv->sect == cur_drv->last_sect) { + fdctrl->data_state &= ~FD_STATE_FORMAT; + /* Last sector done */ + if (FD_DID_SEEK(fdctrl->data_state)) + fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); + else + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); + } else { + /* More to do */ + fdctrl->data_pos = 0; + fdctrl->data_len = 4; + } } } @@ -1423,8 +1419,8 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) #endif fdctrl->fifo[1] = cur_drv->track; fdctrl_set_fifo(fdctrl, 2, 0); - fdctrl_reset_irq(fdctrl); - fdctrl->int_status = 0xC0; + fdctrl_reset_irq(fdctrl); + fdctrl->int_status = 0xC0; return; case 0x0E: /* DUMPREG */ @@ -1439,7 +1435,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en; fdctrl->fifo[6] = cur_drv->last_sect; fdctrl->fifo[7] = (fdctrl->lock << 7) | - (cur_drv->perpendicular << 2); + (cur_drv->perpendicular << 2); fdctrl->fifo[8] = fdctrl->config; fdctrl->fifo[9] = fdctrl->precomp_trk; fdctrl_set_fifo(fdctrl, 10, 0); @@ -1507,7 +1503,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) fdctrl->fifo[7] = fdctrl->timer1; fdctrl->fifo[8] = cur_drv->last_sect; fdctrl->fifo[9] = (fdctrl->lock << 7) | - (cur_drv->perpendicular << 2); + (cur_drv->perpendicular << 2); fdctrl->fifo[10] = fdctrl->config; fdctrl->fifo[11] = fdctrl->precomp_trk; fdctrl->fifo[12] = fdctrl->pwrd; @@ -1584,25 +1580,25 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) return; } } -enqueue: + enqueue: FLOPPY_DPRINTF("%s: %02x\n", __func__, value); fdctrl->fifo[fdctrl->data_pos] = value; if (++fdctrl->data_pos == fdctrl->data_len) { /* We now have all parameters * and will be able to treat the command */ - if (fdctrl->data_state & FD_STATE_FORMAT) { - fdctrl_format_sector(fdctrl); - return; - } - switch (fdctrl->fifo[0] & 0x1F) { - case 0x06: - { - /* READ variants */ - FLOPPY_DPRINTF("treat READ command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_READ); + if (fdctrl->data_state & FD_STATE_FORMAT) { + fdctrl_format_sector(fdctrl); return; } + switch (fdctrl->fifo[0] & 0x1F) { + case 0x06: + { + /* READ variants */ + FLOPPY_DPRINTF("treat READ command\n"); + fdctrl_start_transfer(fdctrl, FD_DIR_READ); + return; + } case 0x0C: /* READ_DELETED variants */ // FLOPPY_DPRINTF("treat READ_DELETED command\n"); @@ -1657,7 +1653,7 @@ enqueue: FLOPPY_DPRINTF("treat SPECIFY command\n"); fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF; fdctrl->timer1 = fdctrl->fifo[2] >> 1; - fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ; + fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ; /* No result back */ fdctrl_reset_fifo(fdctrl); break; @@ -1665,7 +1661,7 @@ enqueue: /* SENSE_DRIVE_STATUS */ FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n"); fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); + cur_drv = get_cur_drv(fdctrl); cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; /* 1 Byte status back */ fdctrl->fifo[0] = (cur_drv->ro << 6) | @@ -1679,23 +1675,23 @@ enqueue: /* RECALIBRATE */ FLOPPY_DPRINTF("treat RECALIBRATE command\n"); fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); + cur_drv = get_cur_drv(fdctrl); fd_recalibrate(cur_drv); - fdctrl_reset_fifo(fdctrl); + fdctrl_reset_fifo(fdctrl); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, 0x20); + fdctrl_raise_irq(fdctrl, 0x20); break; case 0x0F: /* SEEK */ FLOPPY_DPRINTF("treat SEEK command\n"); fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); + cur_drv = get_cur_drv(fdctrl); + fd_start(cur_drv); if (fdctrl->fifo[2] <= cur_drv->track) cur_drv->dir = 1; else cur_drv->dir = 0; - fdctrl_reset_fifo(fdctrl); + fdctrl_reset_fifo(fdctrl); if (fdctrl->fifo[2] > cur_drv->max_track) { fdctrl_raise_irq(fdctrl, 0x60); } else { @@ -1740,7 +1736,7 @@ enqueue: fdctrl_start_transfer(fdctrl, FD_DIR_READ); break; case 0x4A: - /* READ_ID */ + /* READ_ID */ FLOPPY_DPRINTF("treat READ_ID command\n"); /* XXX: should set main status register to busy */ cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; @@ -1766,30 +1762,30 @@ enqueue: break; case 0x4D: /* FORMAT_TRACK */ - FLOPPY_DPRINTF("treat FORMAT_TRACK command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fdctrl->data_state |= FD_STATE_FORMAT; - if (fdctrl->fifo[0] & 0x80) - fdctrl->data_state |= FD_STATE_MULTI; - else - fdctrl->data_state &= ~FD_STATE_MULTI; - fdctrl->data_state &= ~FD_STATE_SEEK; - cur_drv->bps = - fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2]; + FLOPPY_DPRINTF("treat FORMAT_TRACK command\n"); + fdctrl->cur_drv = fdctrl->fifo[1] & 1; + cur_drv = get_cur_drv(fdctrl); + fdctrl->data_state |= FD_STATE_FORMAT; + if (fdctrl->fifo[0] & 0x80) + fdctrl->data_state |= FD_STATE_MULTI; + else + fdctrl->data_state &= ~FD_STATE_MULTI; + fdctrl->data_state &= ~FD_STATE_SEEK; + cur_drv->bps = + fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2]; #if 0 - cur_drv->last_sect = - cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] : - fdctrl->fifo[3] / 2; + cur_drv->last_sect = + cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] : + fdctrl->fifo[3] / 2; #else - cur_drv->last_sect = fdctrl->fifo[3]; + cur_drv->last_sect = fdctrl->fifo[3]; #endif - /* TODO: implement format using DMA expected by the Bochs BIOS - * and Linux fdformat (read 3 bytes per sector via DMA and fill - * the sector with the specified fill byte - */ - fdctrl->data_state &= ~FD_STATE_FORMAT; - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); + /* TODO: implement format using DMA expected by the Bochs BIOS + * and Linux fdformat (read 3 bytes per sector via DMA and fill + * the sector with the specified fill byte + */ + fdctrl->data_state &= ~FD_STATE_FORMAT; + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); break; case 0x8E: /* DRIVE_SPECIFICATION_COMMAND */ @@ -1815,16 +1811,16 @@ enqueue: /* RELATIVE_SEEK_OUT */ FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n"); fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); - cur_drv->dir = 0; + cur_drv = get_cur_drv(fdctrl); + fd_start(cur_drv); + cur_drv->dir = 0; if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) { - cur_drv->track = cur_drv->max_track - 1; + cur_drv->track = cur_drv->max_track - 1; } else { cur_drv->track += fdctrl->fifo[2]; } - fdctrl_reset_fifo(fdctrl); - fdctrl_raise_irq(fdctrl, 0x20); + fdctrl_reset_fifo(fdctrl); + fdctrl_raise_irq(fdctrl, 0x20); break; case 0xCD: /* FORMAT_AND_WRITE */ @@ -1833,20 +1829,20 @@ enqueue: fdctrl_unimplemented(fdctrl); break; case 0xCF: - /* RELATIVE_SEEK_IN */ + /* RELATIVE_SEEK_IN */ FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n"); fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); - cur_drv->dir = 1; + cur_drv = get_cur_drv(fdctrl); + fd_start(cur_drv); + cur_drv->dir = 1; if (fdctrl->fifo[2] > cur_drv->track) { - cur_drv->track = 0; + cur_drv->track = 0; } else { cur_drv->track -= fdctrl->fifo[2]; } - fdctrl_reset_fifo(fdctrl); - /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, 0x20); + fdctrl_reset_fifo(fdctrl); + /* Raise Interrupt */ + fdctrl_raise_irq(fdctrl, 0x20); break; } } @@ -1856,6 +1852,7 @@ static void fdctrl_result_timer(void *opaque) { fdctrl_t *fdctrl = opaque; fdrive_t *cur_drv = get_cur_drv(fdctrl); + /* Pretend we are spinning. * This is needed for Coherent, which uses READ ID to check for * sector interleaving. -- cgit v1.2.3 From 084ed5cc90ad533dbf5532092256fc5a499b91e3 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 5 Nov 2007 13:01:41 +0000 Subject: Code used by the linux-user targets should not use vl.h. Include exec.h instead. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3536 c046a42c-6fe2-441c-8c8c-71466251a162 --- host-utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/host-utils.c b/host-utils.c index 7cd0843f9..f92c3396c 100644 --- a/host-utils.c +++ b/host-utils.c @@ -23,7 +23,8 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "exec.h" +#include "host-utils.h" //#define DEBUG_MULDIV -- cgit v1.2.3 From 05e1d83049e295383d40c5d9015c0e0f0f672baf Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 5 Nov 2007 13:16:23 +0000 Subject: Fix muls64 prototype to match the actual implementation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3537 c046a42c-6fe2-441c-8c8c-71466251a162 --- host-utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host-utils.h b/host-utils.h index 234a06218..dafd0329c 100644 --- a/host-utils.h +++ b/host-utils.h @@ -41,7 +41,7 @@ static always_inline void muls64 (uint64_t *plow, uint64_t *phigh, : "a" (a), "0" (b)); } #else -void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b); +void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b); void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); #endif -- cgit v1.2.3 From 4259e1a5663830523c842b28462622705a260144 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 5 Nov 2007 13:27:21 +0000 Subject: Add -lpthread flag. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3538 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index c8a78b969..8eb4e7458 100755 --- a/configure +++ b/configure @@ -312,7 +312,8 @@ done if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then AIOLIBS= else - AIOLIBS="-lrt" + # Some Linux architectures (e.g. s390) don't imply -lpthread automatically. + AIOLIBS="-lrt -lpthread" fi # default flags for all hosts -- cgit v1.2.3 From 2331d91e775db285bdf0db4e68a949e67167b27b Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Nov 2007 16:07:32 +0000 Subject: moved declarations git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3539 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dyngen.c b/dyngen.c index f136e02c2..562fd0def 100644 --- a/dyngen.c +++ b/dyngen.c @@ -701,6 +701,8 @@ int load_object(const char *filename) uint32_t *n_strtab; EXE_SYM *sym; EXE_RELOC *rel; + const char *p; + int aux_size, j; fd = open(filename, O_RDONLY #ifdef _WIN32 @@ -727,7 +729,6 @@ int load_object(const char *filename) 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)) @@ -771,7 +772,6 @@ int load_object(const char *filename) /* 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; -- cgit v1.2.3 From 7e0af5d09729c13900e3e7933ec2071a3646017a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Nov 2007 16:24:33 +0000 Subject: added -startdate option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3540 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mc146818rtc.c | 13 +++++++++---- qemu-doc.texi | 5 +++++ vl.c | 39 +++++++++++++++++++++++++++++++++++++++ vl.h | 1 + 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 789ebd3f6..be9c63db2 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -393,11 +393,16 @@ void rtc_set_date_from_host(RTCState *s) int val; /* set the CMOS date */ - time(&ti); - if (rtc_utc) + if (rtc_start_date == -1) { + time(&ti); + if (rtc_utc) + tm = gmtime(&ti); + else + tm = localtime(&ti); + } else { + ti = rtc_start_date; tm = gmtime(&ti); - else - tm = localtime(&ti); + } rtc_set_date(s, tm); val = to_bcd(s, (tm->tm_year / 100) + 19); diff --git a/qemu-doc.texi b/qemu-doc.texi index 75ba3825f..3645ba2c1 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -268,6 +268,11 @@ Set the real time clock to local time (the default is to UTC time). This option is needed to have correct date in MS-DOS or Windows. +@item -startdate date +Set the initial date of the real time clock. Valid format for +@var{date} are: @code{now} or @code{2006-06-17T16:01:21} or +@code{2006-06-17}. The default value is @code{now}. + @item -pidfile file Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. diff --git a/vl.c b/vl.c index 73a22da5c..c13b1a1f4 100644 --- a/vl.c +++ b/vl.c @@ -174,6 +174,7 @@ int nb_nics; NICInfo nd_table[MAX_NICS]; int vm_running; int rtc_utc = 1; +int rtc_start_date = -1; /* -1 means now */ int cirrus_vga_enabled = 1; int vmsvga_enabled = 0; #ifdef TARGET_SPARC @@ -7212,6 +7213,7 @@ enum { QEMU_OPTION_prom_env, QEMU_OPTION_old_param, QEMU_OPTION_clock, + QEMU_OPTION_startdate, }; typedef struct QEMUOption { @@ -7318,6 +7320,7 @@ const QEMUOption qemu_options[] = { { "old-param", 0, QEMU_OPTION_old_param }, #endif { "clock", HAS_ARG, QEMU_OPTION_clock }, + { "startdate", HAS_ARG, QEMU_OPTION_startdate }, { NULL }, }; @@ -8107,6 +8110,42 @@ int main(int argc, char **argv) case QEMU_OPTION_clock: configure_alarms(optarg); break; + case QEMU_OPTION_startdate: + { + struct tm tm; + if (!strcmp(optarg, "now")) { + rtc_start_date = -1; + } else { + if (sscanf(optarg, "%d-%d-%dT%d:%d:%d", + &tm.tm_year, + &tm.tm_mon, + &tm.tm_mday, + &tm.tm_hour, + &tm.tm_min, + &tm.tm_sec) == 6) { + /* OK */ + } else if (sscanf(optarg, "%d-%d-%d", + &tm.tm_year, + &tm.tm_mon, + &tm.tm_mday) == 3) { + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + } else { + goto date_fail; + } + tm.tm_year -= 1900; + tm.tm_mon--; + rtc_start_date = timegm(&tm); + if (rtc_start_date == -1) { + date_fail: + fprintf(stderr, "Invalid date format. Valid format are:\n" + "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n"); + exit(1); + } + } + } + break; } } } diff --git a/vl.h b/vl.h index 6df63eb20..92ffd3c84 100644 --- a/vl.h +++ b/vl.h @@ -166,6 +166,7 @@ void main_loop_wait(int timeout); extern int ram_size; extern int bios_size; extern int rtc_utc; +extern int rtc_start_date; extern int cirrus_vga_enabled; extern int vmsvga_enabled; extern int graphic_width; -- cgit v1.2.3 From bc4edd79ee56bfa1c023006cf5a95631e0a52f18 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Nov 2007 16:54:42 +0000 Subject: removed traces git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3541 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index 8a1c57752..9a0b0a441 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -482,7 +482,9 @@ static void load_linux(const char *kernel_filename, } /* kernel protocol version */ +#if 0 fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202)); +#endif if (ldl_p(header+0x202) == 0x53726448) protocol = lduw_p(header+0x206); else @@ -505,6 +507,7 @@ static void load_linux(const char *kernel_filename, prot_addr = phys_ram_base + 0x100000; } +#if 0 fprintf(stderr, "qemu: real_addr = %#zx\n" "qemu: cmdline_addr = %#zx\n" @@ -512,6 +515,7 @@ static void load_linux(const char *kernel_filename, real_addr-phys_ram_base, cmdline_addr-phys_ram_base, prot_addr-phys_ram_base); +#endif /* highest address for loading the initrd */ if (protocol >= 0x203) -- cgit v1.2.3 From 6d5f237a592706773733e71e6da81dcd625fbb24 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 7 Nov 2007 17:03:37 +0000 Subject: CPU specific boot mode (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3542 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 6 ++---- target-sparc/cpu.h | 2 +- target-sparc/helper.c | 2 +- target-sparc/op_helper.c | 4 ++-- target-sparc/translate.c | 11 +++++++++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 0f5522974..3bfa0bc1f 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -181,10 +181,8 @@ static inline TranslationBlock *tb_find_fast(void) 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 Boot . MMU enabled . MMU no-fault . Supervisor - flags = (env->psref << 4) | (((env->mmuregs[0] & MMU_BM) >> 14) << 3) - | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1) - | env->psrs; + // FPU enable . Supervisor + flags = (env->psref << 4) | env->psrs; #endif cs_base = env->npc; pc = env->pc; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 51cbd4c32..0e5a4e222 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -147,7 +147,6 @@ /* MMU */ #define MMU_E (1<<0) #define MMU_NF (1<<1) -#define MMU_BM (1<<14) #define PTE_ENTRYTYPE_MASK 3 #define PTE_ACCESS_MASK 0x1c @@ -200,6 +199,7 @@ typedef struct CPUSPARCState { int interrupt_index; int interrupt_request; int halted; + uint32_t mmu_bm; /* NOTE: we allow 8 more registers to handle wrapping */ target_ulong regbase[NWINDOWS * 16 + 8]; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index ebe642f8c..3ddda872e 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -114,7 +114,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ // Boot mode: instruction fetches are taken from PROM - if (rw == 2 && (env->mmuregs[0] & MMU_BM)) { + if (rw == 2 && (env->mmuregs[0] & env->mmu_bm)) { *physical = 0xff0000000ULL | (address & 0x3ffffULL); *prot = PAGE_READ | PAGE_EXEC; return 0; diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 374678879..13c16618f 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -493,8 +493,8 @@ void helper_st_asi(int asi, int size) oldreg = env->mmuregs[reg]; switch(reg) { case 0: - env->mmuregs[reg] &= ~(MMU_E | MMU_NF | MMU_BM); - env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF | MMU_BM); + env->mmuregs[reg] &= ~(MMU_E | MMU_NF | env->mmu_bm); + env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF | env->mmu_bm); // Mappings generated during no-fault mode or MMU // disabled mode are invalid in normal mode if (oldreg != env->mmuregs[reg]) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index cd60c114c..cc8402cad 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -59,6 +59,7 @@ struct sparc_def_t { target_ulong iu_version; uint32_t fpu_version; uint32_t mmu_version; + uint32_t mmu_bm; }; static uint16_t *gen_opc_ptr; @@ -3482,7 +3483,7 @@ void cpu_reset(CPUSPARCState *env) #else env->pc = 0; env->mmuregs[0] &= ~(MMU_E | MMU_NF); - env->mmuregs[0] |= MMU_BM; + env->mmuregs[0] |= env->mmu_bm; #endif env->npc = env->pc + 4; #endif @@ -3496,7 +3497,6 @@ CPUSPARCState *cpu_sparc_init(void) if (!env) return NULL; cpu_exec_init(env); - cpu_reset(env); return (env); } @@ -3515,30 +3515,35 @@ static const sparc_def_t sparc_defs[] = { .iu_version = 0x04 << 24, /* Impl 0, ver 4 */ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */ + .mmu_bm = 0x00004000, }, { .name = "Fujitsu MB86907", .iu_version = 0x05 << 24, /* Impl 0, ver 5 */ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */ + .mmu_bm = 0x00004000, }, { .name = "TI MicroSparc I", .iu_version = 0x41000000, .fpu_version = 4 << 17, .mmu_version = 0x41000000, + .mmu_bm = 0x00004000, }, { .name = "TI SuperSparc II", .iu_version = 0x40000000, .fpu_version = 0 << 17, .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, }, { .name = "Ross RT620", .iu_version = 0x1e000000, .fpu_version = 1 << 17, .mmu_version = 0x17000000, + .mmu_bm = 0x00004000, }, #endif }; @@ -3579,9 +3584,11 @@ int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def, unsigned int env->version = def->iu_version; env->fsr = def->fpu_version; #if !defined(TARGET_SPARC64) + env->mmu_bm = def->mmu_bm; env->mmuregs[0] |= def->mmu_version; env->mxccregs[7] = ((cpu + 8) & 0xf) << 24; #endif + cpu_reset(env); return 0; } -- cgit v1.2.3 From 4fb240a4956fe222e8f65f0d915f8e07a409ee52 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Nov 2007 19:24:02 +0000 Subject: compile common code once git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3543 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- Makefile.target | 61 +++++++------------------------------- 2 files changed, 98 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 0eb39b5c0..1f77f2c01 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,9 @@ BASE_LDFLAGS= BASE_CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS) BASE_LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS) -CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE +CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP +CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE +CPPFLAGS += -DQEMU_TOOL LIBS= ifdef CONFIG_STATIC BASE_LDFLAGS += -static @@ -24,23 +26,100 @@ endif LIBS+=$(AIOLIBS) -all: $(TOOLS) $(DOCS) recurse-all +all: libqemu_common.a $(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 block-parallels.c - $(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS) +###################################################################### +# libqemu_common.a: target indepedent part of system emulation. The +# long term path is to suppress *all* target specific code in case of +# system emulation, i.e. a single QEMU executable should support all +# CPUs and machines. +OBJS+=cutils.o readline.o console.o +#OBJS+=block.o block-raw.o +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 block-parallels.o + +ifdef CONFIG_WIN32 +OBJS+=tap-win32.o +endif + +AUDIO_OBJS = audio.o noaudio.o wavaudio.o mixeng.o +ifdef CONFIG_SDL +AUDIO_OBJS += sdlaudio.o +endif +ifdef CONFIG_OSS +AUDIO_OBJS += ossaudio.o +endif +ifdef CONFIG_COREAUDIO +AUDIO_OBJS += coreaudio.o +endif +ifdef CONFIG_ALSA +AUDIO_OBJS += alsaaudio.o +endif +ifdef CONFIG_DSOUND +AUDIO_OBJS += dsoundaudio.o +endif +ifdef CONFIG_FMOD +AUDIO_OBJS += fmodaudio.o +audio/audio.o audio/fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS) +endif +AUDIO_OBJS+= wavcapture.o +OBJS+=$(addprefix audio/, $(AUDIO_OBJS)) + +ifdef CONFIG_SDL +OBJS+=sdl.o x_keymap.o +endif +OBJS+=vnc.o d3des.o + +ifdef CONFIG_COCOA +OBJS+=cocoa.o +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 +OBJS+=$(addprefix slirp/, $(SLIRP_OBJS)) +endif + +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 d3des.c d3des.h + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + +audio/sdlaudio.o: audio/sdlaudio.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< + +libqemu_common.a: $(OBJS) + rm -f $@ + $(AR) rcs $@ $(OBJS) + +###################################################################### + +qemu-img$(EXESUF): qemu-img.o block.o block-raw.o libqemu_common.a + $(CC) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS) + +%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + +# dyngen host tool dyngen$(EXESUF): dyngen.c $(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^ clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h - rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS cscope.* *.pod *~ */*~ + rm -f *.o *.d *.a $(TOOLS) dyngen$(EXESUF) TAGS cscope.* *.pod *~ */*~ + rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d $(MAKE) -C tests clean for d in $(TARGET_DIRS); do \ $(MAKE) -C $$d $@ || exit 1 ; \ @@ -180,3 +259,6 @@ tarbin: ifneq ($(wildcard .depend),) include .depend endif + +# Include automatically generated dependency files +-include $(wildcard *.d audio/*.d slirp/*.d) diff --git a/Makefile.target b/Makefile.target index 48528413f..e8ead7df5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -23,7 +23,7 @@ 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 +VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MP ifdef CONFIG_DARWIN_USER VPATH+=:$(SRC_PATH)/darwin-user @@ -399,43 +399,25 @@ ifeq ($(ARCH),alpha) 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=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o +# XXX: suppress QEMU_TOOL tests 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 block-parallels.o VL_OBJS+=irq.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 + +SOUND_HW = sb16.o es1370.o ifdef CONFIG_ADLIB SOUND_HW += fmopl.o adlib.o endif -AUDIODRV+= wavcapture.o ifdef CONFIG_VNC_TLS CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS) @@ -462,7 +444,7 @@ VL_OBJS += rtl8139.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+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o 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 smbus_eeprom.o vmmouse.o vmport.o vmware_vga.o @@ -471,7 +453,7 @@ endif ifeq ($(TARGET_BASE_ARCH), ppc) CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE # shared objects -VL_OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o $(AUDIODRV) +VL_OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o # PREP target VL_OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o VL_OBJS+= prep_pci.o ppc_prep.o @@ -489,7 +471,7 @@ VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o mips_mipssim.o VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= jazz_led.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o -VL_OBJS+= piix_pci.o smbus_eeprom.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV) +VL_OBJS+= piix_pci.o smbus_eeprom.o parallel.o cirrus_vga.o $(SOUND_HW) VL_OBJS+= mipsnet.o CPPFLAGS += -DHAS_AUDIO endif @@ -518,7 +500,7 @@ VL_OBJS+= arm_gic.o realview.o arm_sysctl.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o -VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o $(AUDIODRV) wm8750.o +VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o wm8750.o VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o VL_OBJS+= palm.o tsc210x.o CPPFLAGS += -DHAS_AUDIO @@ -534,12 +516,7 @@ endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o endif -ifdef CONFIG_SDL -VL_OBJS+=sdl.o x_keymap.o -endif -VL_OBJS+=vnc.o d3des.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 @@ -547,10 +524,6 @@ 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_OS_LDFLAGS) @@ -589,21 +562,9 @@ ifdef CONFIG_WIN32 SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole endif -$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a +$(QEMU_SYSTEM): $(VL_OBJS) ../libqemu_common.a libqemu.a $(CC) $(VL_LDFLAGS) $(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 d3des.c d3des.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 @@ -660,7 +621,7 @@ signal.o: signal.c $(CC) $(CPPFLAGS) -c -o $@ $< clean: - rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o + rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o fpu/*.o rm -f *.d */*.d install: all -- cgit v1.2.3 From 49ecc3fa91f6650c76fa9a6fab26533b6549278c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Nov 2007 19:25:15 +0000 Subject: SDL and COCA are no longer target dependent - support for common code compilation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3544 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 56 ++++++++++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/configure b/configure index 8eb4e7458..751dc83d8 100755 --- a/configure +++ b/configure @@ -908,6 +908,29 @@ echo "TARGET_DIRS=$target_list" >> $config_mak if [ "$build_docs" = "yes" ] ; then echo "BUILD_DOCS=yes" >> $config_mak fi +if test "$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 +if test "$cocoa" = "yes" ; then + echo "#define CONFIG_COCOA 1" >> $config_h + echo "CONFIG_COCOA=yes" >> $config_mak +fi # XXX: suppress that if [ "$bsd" = "yes" ] ; then @@ -985,9 +1008,6 @@ mkdir -p $target_dir/fpu if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-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 @@ -1147,34 +1167,6 @@ if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak echo "#define TARGET_HAS_ELFLOAD32 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 test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h @@ -1182,7 +1174,7 @@ 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 tests/cris" + DIRS="tests tests/cris slirp audio" FILES="Makefile tests/Makefile" FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit" for dir in $DIRS ; do -- cgit v1.2.3 From 4728efa329df7c14883956ffa66dc60bc138181a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Nov 2007 19:26:22 +0000 Subject: fixed QEMU_TOOL tests git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3545 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 121 ++++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/vl.h b/vl.h index 92ffd3c84..d5df5d10a 100644 --- a/vl.h +++ b/vl.h @@ -72,8 +72,8 @@ static inline char *realpath(const char *path, char *resolved_path) #ifdef QEMU_TOOL -/* we use QEMU_TOOL in the command line tools which do not depend on - the target CPU type */ +/* we use QEMU_TOOL on code which does not depend on the target CPU + type */ #include "config-host.h" #include #include "osdep.h" @@ -81,7 +81,6 @@ static inline char *realpath(const char *path, char *resolved_path) #else -#include "audio/audio.h" #include "cpu.h" #endif /* !defined(QEMU_TOOL) */ @@ -117,6 +116,8 @@ static inline char *realpath(const char *path, char *resolved_path) #endif #endif +#include "audio/audio.h" + /* cutils.c */ void pstrcpy(char *buf, int buf_size, const char *str); char *pstrcat(char *buf, int buf_size, const char *s); @@ -360,6 +361,38 @@ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); typedef struct DisplayState DisplayState; typedef struct TextConsole TextConsole; +struct DisplayState { + uint8_t *data; + int linesize; + int depth; + int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ + int width; + int height; + void *opaque; + struct QEMUTimer *gui_timer; + + void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); + void (*dpy_resize)(struct DisplayState *s, int w, int h); + void (*dpy_refresh)(struct DisplayState *s); + void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, + int dst_x, int dst_y, int w, int h); + void (*dpy_fill)(struct DisplayState *s, int x, int y, + int w, int h, uint32_t c); + void (*mouse_set)(int x, int y, int on); + void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, + uint8_t *image, uint8_t *mask); +}; + +static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) +{ + s->dpy_update(s, x, y, w, h); +} + +static inline void dpy_resize(DisplayState *s, int w, int h) +{ + s->dpy_resize(s, w, h); +} + typedef void (*vga_hw_update_ptr)(void *); typedef void (*vga_hw_invalidate_ptr)(void *); typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); @@ -729,6 +762,31 @@ void path_combine(char *dest, int dest_size, const char *base_path, const char *filename); + +/* monitor.c */ +void monitor_init(CharDriverState *hd, int show_banner); +void term_puts(const char *str); +void term_vprintf(const char *fmt, va_list ap); +void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +void term_print_filename(const char *filename); +void term_flush(void); +void term_print_help(void); +void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size); + +/* readline.c */ +typedef void ReadLineFunc(void *opaque, const char *str); + +extern int completion_index; +void add_completion(const char *str); +void readline_handle_byte(int ch); +void readline_find_completion(const char *cmdline); +const char *readline_get_history(unsigned int index); +void readline_start(const char *prompt, int is_password, + ReadLineFunc *readline_func, void *opaque); + +void kqemu_record_dump(void); + #ifndef QEMU_TOOL typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, @@ -916,38 +974,6 @@ extern struct soundhw soundhw[]; #define VGA_RAM_SIZE (9 * 1024 * 1024) #endif -struct DisplayState { - uint8_t *data; - int linesize; - int depth; - int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ - int width; - int height; - void *opaque; - QEMUTimer *gui_timer; - - void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); - void (*dpy_resize)(struct DisplayState *s, int w, int h); - void (*dpy_refresh)(struct DisplayState *s); - void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, - int dst_x, int dst_y, int w, int h); - void (*dpy_fill)(struct DisplayState *s, int x, int y, - int w, int h, uint32_t c); - void (*mouse_set)(int x, int y, int on); - void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, - uint8_t *image, uint8_t *mask); -}; - -static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) -{ - s->dpy_update(s, x, y, w, h); -} - -static inline void dpy_resize(DisplayState *s, int w, int h) -{ - s->dpy_resize(s, w, h); -} - int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, @@ -1696,29 +1722,4 @@ extern QEMUMachine mcf5208evb_machine; #include "gdbstub.h" #endif /* defined(QEMU_TOOL) */ - -/* monitor.c */ -void monitor_init(CharDriverState *hd, int show_banner); -void term_puts(const char *str); -void term_vprintf(const char *fmt, va_list ap); -void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -void term_print_filename(const char *filename); -void term_flush(void); -void term_print_help(void); -void monitor_readline(const char *prompt, int is_password, - char *buf, int buf_size); - -/* readline.c */ -typedef void ReadLineFunc(void *opaque, const char *str); - -extern int completion_index; -void add_completion(const char *str); -void readline_handle_byte(int ch); -void readline_find_completion(const char *cmdline); -const char *readline_get_history(unsigned int index); -void readline_start(const char *prompt, int is_password, - ReadLineFunc *readline_func, void *opaque); - -void kqemu_record_dump(void); - #endif /* VL_H */ -- cgit v1.2.3 From 5fa0ab8fcbd25bbb72f51f923f0595e05f091476 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 7 Nov 2007 19:27:18 +0000 Subject: use config-host.h instead of config.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3546 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/audio.h | 2 +- slirp/slirp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/audio.h b/audio/audio.h index 287cc5c73..db1a94097 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -24,7 +24,7 @@ #ifndef QEMU_AUDIO_H #define QEMU_AUDIO_H -#include "config.h" +#include "config-host.h" #include "sys-queue.h" typedef void (*audio_callback_fn_t) (void *opaque, int avail); diff --git a/slirp/slirp.h b/slirp/slirp.h index a28e5feac..1809ba73c 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -17,7 +17,7 @@ #ifndef CONFIG_QEMU #include "version.h" #endif -#include "config.h" +#include "config-host.h" #include "slirp_config.h" #ifdef _WIN32 -- cgit v1.2.3 From a049de6161feb4d62bdd962401d3e35ebf4331dc Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Nov 2007 13:28:47 +0000 Subject: added -cpu option for x86 (initial patch by Dan Kenigsberg) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3547 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 18 ++- target-i386/cpu.h | 39 +++++- target-i386/helper2.c | 329 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 322 insertions(+), 64 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 9a0b0a441..f6192f76b 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -676,7 +676,7 @@ static void pc_init1(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, - int pci_enabled) + int pci_enabled, const char *cpu_model) { char buf[1024]; int ret, linux_boot, i; @@ -692,6 +692,18 @@ static void pc_init1(int ram_size, int vga_ram_size, const char *boot_device, linux_boot = (kernel_filename != NULL); /* init CPUs */ + if (cpu_model == NULL) { +#ifdef TARGET_X86_64 + cpu_model = "qemu64"; +#else + cpu_model = "qemu32"; +#endif + } + + if (x86_find_cpu_by_name(cpu_model)) { + fprintf(stderr, "Unable to find x86 CPU definition\n"); + exit(1); + } for(i = 0; i < smp_cpus; i++) { env = cpu_init(); if (i != 0) @@ -960,7 +972,7 @@ static void pc_init_pci(int ram_size, int vga_ram_size, const char *boot_device, pc_init1(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, - initrd_filename, 1); + initrd_filename, 1, cpu_model); } static void pc_init_isa(int ram_size, int vga_ram_size, const char *boot_device, @@ -974,7 +986,7 @@ static void pc_init_isa(int ram_size, int vga_ram_size, const char *boot_device, pc_init1(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, - initrd_filename, 0); + initrd_filename, 0, cpu_model); } QEMUMachine pc_machine = { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 23419909c..e92fc3104 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -274,23 +274,56 @@ #define CPUID_CMOV (1 << 15) #define CPUID_PAT (1 << 16) #define CPUID_PSE36 (1 << 17) +#define CPUID_PN (1 << 18) #define CPUID_CLFLUSH (1 << 19) -/* ... */ +#define CPUID_DTS (1 << 21) +#define CPUID_ACPI (1 << 22) #define CPUID_MMX (1 << 23) #define CPUID_FXSR (1 << 24) #define CPUID_SSE (1 << 25) #define CPUID_SSE2 (1 << 26) +#define CPUID_SS (1 << 27) +#define CPUID_HT (1 << 28) +#define CPUID_TM (1 << 29) +#define CPUID_IA64 (1 << 30) +#define CPUID_PBE (1 << 31) #define CPUID_EXT_SSE3 (1 << 0) #define CPUID_EXT_MONITOR (1 << 3) +#define CPUID_EXT_DSCPL (1 << 4) +#define CPUID_EXT_VMX (1 << 5) +#define CPUID_EXT_SMX (1 << 6) +#define CPUID_EXT_EST (1 << 7) +#define CPUID_EXT_TM2 (1 << 8) +#define CPUID_EXT_SSSE3 (1 << 9) +#define CPUID_EXT_CID (1 << 10) #define CPUID_EXT_CX16 (1 << 13) +#define CPUID_EXT_XTPR (1 << 14) +#define CPUID_EXT_DCA (1 << 17) +#define CPUID_EXT_POPCNT (1 << 22) #define CPUID_EXT2_SYSCALL (1 << 11) +#define CPUID_EXT2_MP (1 << 19) #define CPUID_EXT2_NX (1 << 20) +#define CPUID_EXT2_MMXEXT (1 << 22) #define CPUID_EXT2_FFXSR (1 << 25) +#define CPUID_EXT2_PDPE1GB (1 << 26) +#define CPUID_EXT2_RDTSCP (1 << 27) #define CPUID_EXT2_LM (1 << 29) +#define CPUID_EXT2_3DNOWEXT (1 << 30) +#define CPUID_EXT2_3DNOW (1 << 31) +#define CPUID_EXT3_LAHF_LM (1 << 0) +#define CPUID_EXT3_CMP_LEG (1 << 1) #define CPUID_EXT3_SVM (1 << 2) +#define CPUID_EXT3_EXTAPIC (1 << 3) +#define CPUID_EXT3_CR8LEG (1 << 4) +#define CPUID_EXT3_ABM (1 << 5) +#define CPUID_EXT3_SSE4A (1 << 6) +#define CPUID_EXT3_MISALIGNSSE (1 << 7) +#define CPUID_EXT3_3DNOWPREFETCH (1 << 8) +#define CPUID_EXT3_OSVW (1 << 9) +#define CPUID_EXT3_IBS (1 << 10) #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 @@ -566,6 +599,9 @@ typedef struct CPUX86State { CPUX86State *cpu_x86_init(void); int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); +int x86_find_cpu_by_name (const unsigned char *name); +void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, + ...)); int cpu_get_pic_interrupt(CPUX86State *s); /* MSDOS compatibility mode FPU exception support */ void cpu_set_ferr(CPUX86State *s); @@ -689,6 +725,7 @@ static inline int cpu_get_time_fast(void) #define cpu_exec cpu_x86_exec #define cpu_gen_code cpu_x86_gen_code #define cpu_signal_handler cpu_x86_signal_handler +#define cpu_list x86_cpu_list /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 1d59bc571..87788d721 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -47,6 +47,67 @@ int modify_ldt(int func, void *ptr, unsigned long bytecount) #endif #endif /* USE_CODE_COPY */ +static struct x86_def_t *x86_cpu_def; +typedef struct x86_def_t x86_def_t; +static int cpu_x86_register (CPUX86State *env, const x86_def_t *def); + +static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, + uint32_t *ext_features, + uint32_t *ext2_features, + uint32_t *ext3_features) +{ + int i; + /* feature flags taken from "Intel Processor Identification and the CPUID + * Instruction" and AMD's "CPUID Specification". In cases of disagreement + * about feature names, the Linux name is used. */ + const char *feature_name[] = { + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", + "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", + "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx", + "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe", + }; + const char *ext_feature_name[] = { + "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est", + "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, + NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; + const char *ext2_feature_name[] = { + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", + "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mttr", "pge", "mca", "cmov", + "pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx", + "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow", + }; + const char *ext3_feature_name[] = { + "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse", + "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; + + for ( i = 0 ; i < 32 ; i++ ) + if (feature_name[i] && !strcmp (flagname, feature_name[i])) { + *features |= 1 << i; + return; + } + for ( i = 0 ; i < 32 ; i++ ) + if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) { + *ext_features |= 1 << i; + return; + } + for ( i = 0 ; i < 32 ; i++ ) + if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) { + *ext2_features |= 1 << i; + return; + } + for ( i = 0 ; i < 32 ; i++ ) + if (ext3_features[i] && !strcmp (flagname, ext3_feature_name[i])) { + *ext3_features |= 1 << i; + return; + } + fprintf(stderr, "CPU feature %s not found\n", flagname); +} + CPUX86State *cpu_x86_init(void) { CPUX86State *env; @@ -81,71 +142,219 @@ CPUX86State *cpu_x86_init(void) asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); } #endif - { - int family, model, stepping; -#ifdef TARGET_X86_64 - env->cpuid_vendor1 = 0x68747541; /* "Auth" */ - env->cpuid_vendor2 = 0x69746e65; /* "enti" */ - env->cpuid_vendor3 = 0x444d4163; /* "cAMD" */ - family = 6; - model = 2; - stepping = 3; -#else - env->cpuid_vendor1 = 0x756e6547; /* "Genu" */ - env->cpuid_vendor2 = 0x49656e69; /* "ineI" */ - env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */ -#if 0 - /* pentium 75-200 */ - family = 5; - model = 2; - stepping = 11; -#else - /* pentium pro */ - family = 6; - model = 3; - stepping = 3; -#endif + cpu_x86_register(env, x86_cpu_def); + cpu_reset(env); +#ifdef USE_KQEMU + kqemu_init(env); #endif - env->cpuid_level = 2; - env->cpuid_version = (family << 8) | (model << 4) | stepping; - env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE | - CPUID_TSC | CPUID_MSR | CPUID_MCE | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV | - CPUID_PAT); - env->pat = 0x0007040600070406ULL; - env->cpuid_ext3_features = CPUID_EXT3_SVM; - env->cpuid_ext_features = CPUID_EXT_SSE3; - env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP; - env->cpuid_features |= CPUID_APIC; - env->cpuid_xlevel = 0x8000000e; - { - const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION; - int c, len, i; - len = strlen(model_id); - for(i = 0; i < 48; i++) { - if (i >= len) - c = '\0'; - else - c = model_id[i]; - env->cpuid_model[i >> 2] |= c << (8 * (i & 3)); - } - } -#ifdef TARGET_X86_64 - /* currently not enabled for std i386 because not fully tested */ - env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF); - env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX; + return env; +} + +struct x86_def_t { + const char *name; + uint32_t vendor1, vendor2, vendor3; + int family; + int model; + int stepping; + uint32_t features, ext_features, ext2_features, ext3_features; + uint32_t xlevel; +}; +#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \ + CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \ + CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \ + CPUID_PAE | CPUID_SEP | CPUID_APIC) +static x86_def_t x86_defs[] = { +#ifdef TARGET_X86_64 + { + .name = "qemu64", + .vendor1 = 0x68747541, /* "Auth" */ + .vendor2 = 0x69746e65, /* "enti" */ + .vendor3 = 0x444d4163, /* "cAMD" */ + .family = 6, + .model = 2, + .stepping = 3, + .features = PPRO_FEATURES | /* these features are needed for Win64 and aren't fully implemented */ - env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA; + CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* this feature is needed for Solaris and isn't fully implemented */ - env->cpuid_features |= CPUID_PSE36; + CPUID_PSE36, + .ext_features = CPUID_EXT_SSE3, + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, + .ext3_features = CPUID_EXT3_SVM, + .xlevel = 0x80000008, + }, #endif + { + .name = "qemu32", + .family = 6, + .model = 3, + .stepping = 3, + .features = PPRO_FEATURES, + .ext_features = CPUID_EXT_SSE3, + .xlevel = 0, + }, + { + .name = "486", + .family = 4, + .model = 0, + .stepping = 0, + .features = 0x0000000B, + .xlevel = 0, + }, + { + .name = "pentium", + .family = 5, + .model = 4, + .stepping = 3, + .features = 0x008001BF, + .xlevel = 0, + }, + { + .name = "pentium2", + .family = 6, + .model = 5, + .stepping = 2, + .features = 0x0183F9FF, + .xlevel = 0, + }, + { + .name = "pentium3", + .family = 6, + .model = 7, + .stepping = 3, + .features = 0x0383F9FF, + .xlevel = 0, + }, +}; + +int x86_find_cpu_by_name(const unsigned char *cpu_model) +{ + int ret; + unsigned int i; + + char *s = strdup(cpu_model); + char *featurestr, *name = strtok(s, ","); + uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0; + uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0; + int family = -1, model = -1, stepping = -1; + + ret = -1; + x86_cpu_def = NULL; + for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) { + if (strcmp(name, x86_defs[i].name) == 0) { + x86_cpu_def = &x86_defs[i]; + ret = 0; + break; + } } - cpu_reset(env); -#ifdef USE_KQEMU - kqemu_init(env); -#endif - return env; + if (!x86_cpu_def) + goto error; + + featurestr = strtok(NULL, ","); + + while (featurestr) { + char *val; + if (featurestr[0] == '+') { + add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features); + } else if (featurestr[0] == '-') { + add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features); + } else if ((val = strchr(featurestr, '='))) { + *val = 0; val++; + if (!strcmp(featurestr, "family")) { + char *err; + family = strtol(val, &err, 10); + if (!*val || *err || family < 0) { + fprintf(stderr, "bad numerical value %s\n", val); + x86_cpu_def = 0; + goto error; + } + x86_cpu_def->family = family; + } else if (!strcmp(featurestr, "model")) { + char *err; + model = strtol(val, &err, 10); + if (!*val || *err || model < 0 || model > 0xf) { + fprintf(stderr, "bad numerical value %s\n", val); + x86_cpu_def = 0; + goto error; + } + x86_cpu_def->model = model; + } else if (!strcmp(featurestr, "stepping")) { + char *err; + stepping = strtol(val, &err, 10); + if (!*val || *err || stepping < 0 || stepping > 0xf) { + fprintf(stderr, "bad numerical value %s\n", val); + x86_cpu_def = 0; + goto error; + } + x86_cpu_def->stepping = stepping; + } else { + fprintf(stderr, "unregnized feature %s\n", featurestr); + x86_cpu_def = 0; + goto error; + } + } else { + fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); + x86_cpu_def = 0; + goto error; + } + featurestr = strtok(NULL, ","); + } + x86_cpu_def->features |= plus_features; + x86_cpu_def->ext_features |= plus_ext_features; + x86_cpu_def->ext2_features |= plus_ext2_features; + x86_cpu_def->ext3_features |= plus_ext3_features; + x86_cpu_def->features &= ~minus_features; + x86_cpu_def->ext_features &= ~minus_ext_features; + x86_cpu_def->ext2_features &= ~minus_ext2_features; + x86_cpu_def->ext3_features &= ~minus_ext3_features; + +error: + free(s); + return ret; +} + +void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +{ + unsigned int i; + + for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) + (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name); +} + +int cpu_x86_register (CPUX86State *env, const x86_def_t *def) +{ + if (def->vendor1) { + env->cpuid_vendor1 = def->vendor1; + env->cpuid_vendor2 = def->vendor2; + env->cpuid_vendor3 = def->vendor3; + } else { + env->cpuid_vendor1 = 0x756e6547; /* "Genu" */ + env->cpuid_vendor2 = 0x49656e69; /* "ineI" */ + env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */ + } + env->cpuid_level = 2; + env->cpuid_version = (def->family << 8) | (def->model << 4) | def->stepping; + env->cpuid_features = def->features; + env->pat = 0x0007040600070406ULL; + env->cpuid_ext_features = def->ext_features; + env->cpuid_ext2_features = def->ext2_features; + env->cpuid_xlevel = def->xlevel; + env->cpuid_ext3_features = def->ext3_features; + { + const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION; + int c, len, i; + len = strlen(model_id); + for(i = 0; i < 48; i++) { + if (i >= len) + c = '\0'; + else + c = model_id[i]; + env->cpuid_model[i >> 2] |= c << (8 * (i & 3)); + } + } + return 0; } /* NOTE: must be called outside the CPU execute loop */ @@ -185,7 +394,7 @@ void cpu_reset(CPUX86State *env) cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0); env->eip = 0xfff0; - env->regs[R_EDX] = 0x600; /* indicate P6 processor */ + env->regs[R_EDX] = env->cpuid_version; env->eflags = 0x2; -- cgit v1.2.3 From 46027c07de45d84441b40cc2db675efd29588af0 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Nov 2007 13:56:19 +0000 Subject: added -cpu option for x86 - fixed glibc hack in case the global variables are moved git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3548 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 6fe51107c..f80000f2f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -45,12 +45,20 @@ const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; /* for recent libc, we add these dummy symbols which are not declared when generating a linked object (bug in ld ?) */ #if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC) -long __preinit_array_start[0]; -long __preinit_array_end[0]; -long __init_array_start[0]; -long __init_array_end[0]; -long __fini_array_start[0]; -long __fini_array_end[0]; +asm(".globl __preinit_array_start\n" + ".globl __preinit_array_end\n" + ".globl __init_array_start\n" + ".globl __init_array_end\n" + ".globl __fini_array_start\n" + ".globl __fini_array_end\n" + ".section \".rodata\"\n" + "__preinit_array_start:\n" + "__preinit_array_end:\n" + "__init_array_start:\n" + "__init_array_end:\n" + "__fini_array_start:\n" + "__fini_array_end:\n" + ".long 0\n"); #endif /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so @@ -1975,6 +1983,23 @@ int main(int argc, char **argv) /* Scan interp_prefix dir for replacement files. */ init_paths(interp_prefix); +#if defined(TARGET_I386) + /* must be done before cpu_init() for x86 XXX: suppress this hack + by adding a new parameter to cpu_init and by suppressing + cpu_xxx_register() */ + if (cpu_model == NULL) { +#ifdef TARGET_X86_64 + cpu_model = "qemu64"; +#else + cpu_model = "qemu32"; +#endif + } + if (x86_find_cpu_by_name(cpu_model)) { + fprintf(stderr, "Unable to find x86 CPU definition\n"); + exit(1); + } +#endif + /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ env = cpu_init(); -- cgit v1.2.3 From abf283372b9d0c1a63a7a401f9129beb2c360d9f Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Nov 2007 14:01:49 +0000 Subject: removed unused code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3549 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index f80000f2f..716348cff 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -28,11 +28,6 @@ #define DEBUG_LOGFILE "/tmp/qemu.log" -#ifdef __APPLE__ -#include -# define environ (*_NSGetEnviron()) -#endif - static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char *qemu_uname_release = CONFIG_UNAME_RELEASE; -- cgit v1.2.3 From 838104f60845adfa3ff5ad30e7f3a28c76f42bea Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Nov 2007 14:24:28 +0000 Subject: removed git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3550 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/translate-copy.c | 1323 ------------------------------------------ 1 file changed, 1323 deletions(-) delete mode 100644 target-i386/translate-copy.c diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c deleted file mode 100644 index d68764360..000000000 --- a/target-i386/translate-copy.c +++ /dev/null @@ -1,1323 +0,0 @@ -/* - * i386 on i386 translation - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "cpu.h" -#include "exec-all.h" -#include "disas.h" - -#ifdef USE_CODE_COPY - -#include -#include -#include - -extern char exec_loop; - -/* operand size */ -enum { - OT_BYTE = 0, - OT_WORD, - OT_LONG, - OT_QUAD, -}; - -#define PREFIX_REPZ 0x01 -#define PREFIX_REPNZ 0x02 -#define PREFIX_LOCK 0x04 -#define PREFIX_DATA 0x08 -#define PREFIX_ADR 0x10 - -typedef struct DisasContext { - /* current insn context */ - int override; /* -1 if no override */ - int prefix; - int aflag, dflag; - target_ulong pc; /* pc = eip + cs_base */ - int is_jmp; /* 1 = means jump (stop translation), 2 means CPU - static state change (stop translation) */ - /* code output */ - uint8_t *gen_code_ptr; - uint8_t *gen_code_start; - - /* current block context */ - target_ulong cs_base; /* base of CS segment */ - int pe; /* protected mode */ - int code32; /* 32 bit code segment */ - int f_st; /* currently unused */ - int vm86; /* vm86 mode */ - int cpl; - int iopl; - int flags; - struct TranslationBlock *tb; -} DisasContext; - -#define CPU_FIELD_OFFSET(field) offsetof(CPUState, field) - -#define CPU_SEG 0x64 /* fs override */ - -static inline void gb(DisasContext *s, uint32_t val) -{ - *s->gen_code_ptr++ = val; -} - -static inline void gw(DisasContext *s, uint32_t val) -{ - *s->gen_code_ptr++ = val; - *s->gen_code_ptr++ = val >> 8; -} - -static inline void gl(DisasContext *s, uint32_t val) -{ - *s->gen_code_ptr++ = val; - *s->gen_code_ptr++ = val >> 8; - *s->gen_code_ptr++ = val >> 16; - *s->gen_code_ptr++ = val >> 24; -} - -static inline void gjmp(DisasContext *s, long val) -{ - gb(s, 0xe9); /* jmp */ - gl(s, val - (long)(s->gen_code_ptr + 4)); -} - -static inline void gen_movl_addr_im(DisasContext *s, - uint32_t addr, uint32_t val) -{ - gb(s, CPU_SEG); /* seg movl im, addr */ - gb(s, 0xc7); - gb(s, 0x05); - gl(s, addr); - gl(s, val); -} - -static inline void gen_movw_addr_im(DisasContext *s, - uint32_t addr, uint32_t val) -{ - gb(s, CPU_SEG); /* seg movl im, addr */ - gb(s, 0x66); - gb(s, 0xc7); - gb(s, 0x05); - gl(s, addr); - gw(s, val); -} - - -static void gen_jmp(DisasContext *s, uint32_t target_eip) -{ - TranslationBlock *tb = s->tb; - - gb(s, 0xe9); /* jmp */ - tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start; - gl(s, 0); - - tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; - gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); - gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); - gjmp(s, (long)&exec_loop); - - s->is_jmp = 1; -} - -static void gen_jcc(DisasContext *s, int op, - uint32_t target_eip, uint32_t next_eip) -{ - TranslationBlock *tb = s->tb; - - gb(s, 0x0f); /* jcc */ - gb(s, 0x80 + op); - tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start; - gl(s, 0); - gb(s, 0xe9); /* jmp */ - tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start; - gl(s, 0); - - tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; - gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); - gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); - gjmp(s, (long)&exec_loop); - - tb->tb_next_offset[1] = s->gen_code_ptr - s->gen_code_start; - gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), next_eip); - gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb | 1); - gjmp(s, (long)&exec_loop); - - s->is_jmp = 1; -} - -static void gen_eob(DisasContext *s) -{ - gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), 0); - gjmp(s, (long)&exec_loop); - - s->is_jmp = 1; -} - -static inline void gen_lea_modrm(DisasContext *s, int modrm) -{ - int havesib; - int base, disp; - int index; - int scale; - int mod, rm, code; - - mod = (modrm >> 6) & 3; - rm = modrm & 7; - - if (s->aflag) { - - havesib = 0; - base = rm; - index = 0; - scale = 0; - - if (base == 4) { - havesib = 1; - code = ldub_code(s->pc++); - scale = (code >> 6) & 3; - index = (code >> 3) & 7; - base = code & 7; - } - - switch (mod) { - case 0: - if (base == 5) { - base = -1; - disp = ldl_code(s->pc); - s->pc += 4; - } else { - disp = 0; - } - break; - case 1: - disp = (int8_t)ldub_code(s->pc++); - break; - default: - case 2: - disp = ldl_code(s->pc); - s->pc += 4; - break; - } - - } else { - switch (mod) { - case 0: - if (rm == 6) { - disp = lduw_code(s->pc); - s->pc += 2; - } else { - disp = 0; - } - break; - case 1: - disp = (int8_t)ldub_code(s->pc++); - break; - default: - case 2: - disp = lduw_code(s->pc); - s->pc += 2; - break; - } - } -} - -static inline void parse_modrm(DisasContext *s, int modrm) -{ - if ((modrm & 0xc0) != 0xc0) - gen_lea_modrm(s, modrm); -} - -static inline uint32_t insn_get(DisasContext *s, int ot) -{ - uint32_t ret; - - switch(ot) { - case OT_BYTE: - ret = ldub_code(s->pc); - s->pc++; - break; - case OT_WORD: - ret = lduw_code(s->pc); - s->pc += 2; - break; - default: - case OT_LONG: - ret = ldl_code(s->pc); - s->pc += 4; - break; - } - return ret; -} - -/* convert one instruction. s->is_jmp is set if the translation must - be stopped. */ -static int disas_insn(DisasContext *s) -{ - target_ulong pc_start, pc_tmp, pc_start_insn; - int b, prefixes, aflag, dflag, next_eip, val; - int ot; - int modrm, mod, op, rm; - - pc_start = s->pc; - prefixes = 0; - aflag = s->code32; - dflag = s->code32; - s->override = -1; - next_byte: - b = ldub_code(s->pc); - s->pc++; - /* check prefixes */ - switch (b) { - case 0xf3: - prefixes |= PREFIX_REPZ; - goto next_byte; - case 0xf2: - prefixes |= PREFIX_REPNZ; - goto next_byte; - case 0xf0: - prefixes |= PREFIX_LOCK; - goto next_byte; - case 0x2e: - s->override = R_CS; - goto next_byte; - case 0x36: - s->override = R_SS; - goto next_byte; - case 0x3e: - s->override = R_DS; - goto next_byte; - case 0x26: - s->override = R_ES; - goto next_byte; - case 0x64: - s->override = R_FS; - goto next_byte; - case 0x65: - s->override = R_GS; - goto next_byte; - case 0x66: - prefixes |= PREFIX_DATA; - goto next_byte; - case 0x67: - prefixes |= PREFIX_ADR; - goto next_byte; - } - - if (prefixes & PREFIX_DATA) - dflag ^= 1; - if (prefixes & PREFIX_ADR) - aflag ^= 1; - - s->prefix = prefixes; - s->aflag = aflag; - s->dflag = dflag; - - /* lock generation */ - if (prefixes & PREFIX_LOCK) - goto unsupported_op; - if (s->override == R_FS || s->override == R_GS || s->override == R_CS) - goto unsupported_op; - - pc_start_insn = s->pc - 1; - /* now check op code */ - reswitch: - switch(b) { - case 0x0f: - /**************************/ - /* extended op code */ - b = ldub_code(s->pc++) | 0x100; - goto reswitch; - - /**************************/ - /* arith & logic */ - case 0x00 ... 0x05: - case 0x08 ... 0x0d: - case 0x10 ... 0x15: - case 0x18 ... 0x1d: - case 0x20 ... 0x25: - case 0x28 ... 0x2d: - case 0x30 ... 0x35: - case 0x38 ... 0x3d: - { - int f; - f = (b >> 1) & 3; - - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - switch(f) { - case 0: /* OP Ev, Gv */ - modrm = ldub_code(s->pc++); - parse_modrm(s, modrm); - break; - case 1: /* OP Gv, Ev */ - modrm = ldub_code(s->pc++); - parse_modrm(s, modrm); - break; - case 2: /* OP A, Iv */ - insn_get(s, ot); - break; - } - } - break; - - case 0x80: /* GRP1 */ - case 0x81: - case 0x82: - case 0x83: - { - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - modrm = ldub_code(s->pc++); - parse_modrm(s, modrm); - - switch(b) { - default: - case 0x80: - case 0x81: - case 0x82: - insn_get(s, ot); - break; - case 0x83: - insn_get(s, OT_BYTE); - break; - } - } - break; - - /**************************/ - /* inc, dec, and other misc arith */ - case 0x40 ... 0x47: /* inc Gv */ - break; - case 0x48 ... 0x4f: /* dec Gv */ - break; - case 0xf6: /* GRP3 */ - case 0xf7: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - modrm = ldub_code(s->pc++); - op = (modrm >> 3) & 7; - parse_modrm(s, modrm); - - switch(op) { - case 0: /* test */ - insn_get(s, ot); - break; - case 2: /* not */ - break; - case 3: /* neg */ - break; - case 4: /* mul */ - break; - case 5: /* imul */ - break; - case 6: /* div */ - break; - case 7: /* idiv */ - break; - default: - goto illegal_op; - } - break; - - case 0xfe: /* GRP4 */ - case 0xff: /* GRP5 */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - - modrm = ldub_code(s->pc++); - mod = (modrm >> 6) & 3; - op = (modrm >> 3) & 7; - if (op >= 2 && b == 0xfe) { - goto illegal_op; - } - pc_tmp = s->pc; - parse_modrm(s, modrm); - - switch(op) { - case 0: /* inc Ev */ - break; - case 1: /* dec Ev */ - break; - case 2: /* call Ev */ - /* XXX: optimize and handle MEM exceptions specifically - fs movl %eax, regs[0] - movl Ev, %eax - pushl next_eip - fs movl %eax, eip - */ - goto unsupported_op; - case 3: /* lcall Ev */ - goto unsupported_op; - case 4: /* jmp Ev */ - /* XXX: optimize and handle MEM exceptions specifically - fs movl %eax, regs[0] - movl Ev, %eax - fs movl %eax, eip - */ - goto unsupported_op; - case 5: /* ljmp Ev */ - goto unsupported_op; - case 6: /* push Ev */ - break; - default: - goto illegal_op; - } - break; - case 0xa8: /* test eAX, Iv */ - case 0xa9: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - insn_get(s, ot); - break; - - case 0x98: /* CWDE/CBW */ - break; - case 0x99: /* CDQ/CWD */ - break; - case 0x1af: /* imul Gv, Ev */ - case 0x69: /* imul Gv, Ev, I */ - case 0x6b: - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub_code(s->pc++); - parse_modrm(s, modrm); - if (b == 0x69) { - insn_get(s, ot); - } else if (b == 0x6b) { - insn_get(s, OT_BYTE); - } else { - } - break; - - case 0x84: /* test Ev, Gv */ - case 0x85: - - case 0x1c0: - case 0x1c1: /* xadd Ev, Gv */ - - case 0x1b0: - case 0x1b1: /* cmpxchg Ev, Gv */ - - case 0x8f: /* pop Ev */ - - case 0x88: - case 0x89: /* mov Gv, Ev */ - - case 0x8a: - case 0x8b: /* mov Ev, Gv */ - - case 0x1b6: /* movzbS Gv, Eb */ - case 0x1b7: /* movzwS Gv, Eb */ - case 0x1be: /* movsbS Gv, Eb */ - case 0x1bf: /* movswS Gv, Eb */ - - case 0x86: - case 0x87: /* xchg Ev, Gv */ - - case 0xd0: - case 0xd1: /* shift Ev,1 */ - - case 0xd2: - case 0xd3: /* shift Ev,cl */ - - case 0x1a5: /* shld cl */ - case 0x1ad: /* shrd cl */ - - case 0x190 ... 0x19f: /* setcc Gv */ - - /* XXX: emulate cmov if not available ? */ - case 0x140 ... 0x14f: /* cmov Gv, Ev */ - - case 0x1a3: /* bt Gv, Ev */ - case 0x1ab: /* bts */ - case 0x1b3: /* btr */ - case 0x1bb: /* btc */ - - case 0x1bc: /* bsf */ - case 0x1bd: /* bsr */ - - modrm = ldub_code(s->pc++); - parse_modrm(s, modrm); - break; - - case 0x1c7: /* cmpxchg8b */ - modrm = ldub_code(s->pc++); - mod = (modrm >> 6) & 3; - if (mod == 3) - goto illegal_op; - parse_modrm(s, modrm); - break; - - /**************************/ - /* push/pop */ - case 0x50 ... 0x57: /* push */ - case 0x58 ... 0x5f: /* pop */ - case 0x60: /* pusha */ - case 0x61: /* popa */ - break; - - case 0x68: /* push Iv */ - case 0x6a: - ot = dflag ? OT_LONG : OT_WORD; - if (b == 0x68) - insn_get(s, ot); - else - insn_get(s, OT_BYTE); - break; - case 0xc8: /* enter */ - lduw_code(s->pc); - s->pc += 2; - ldub_code(s->pc++); - break; - case 0xc9: /* leave */ - break; - - case 0x06: /* push es */ - case 0x0e: /* push cs */ - case 0x16: /* push ss */ - case 0x1e: /* push ds */ - /* XXX: optimize: - push segs[n].selector - */ - goto unsupported_op; - case 0x1a0: /* push fs */ - case 0x1a8: /* push gs */ - goto unsupported_op; - case 0x07: /* pop es */ - case 0x17: /* pop ss */ - case 0x1f: /* pop ds */ - goto unsupported_op; - case 0x1a1: /* pop fs */ - case 0x1a9: /* pop gs */ - goto unsupported_op; - case 0x8e: /* mov seg, Gv */ - /* XXX: optimize: - fs movl r, regs[] - movl segs[].selector, r - mov r, Gv - fs movl regs[], r - */ - goto unsupported_op; - case 0x8c: /* mov Gv, seg */ - goto unsupported_op; - case 0xc4: /* les Gv */ - op = R_ES; - goto do_lxx; - case 0xc5: /* lds Gv */ - op = R_DS; - goto do_lxx; - case 0x1b2: /* lss Gv */ - op = R_SS; - goto do_lxx; - case 0x1b4: /* lfs Gv */ - op = R_FS; - goto do_lxx; - case 0x1b5: /* lgs Gv */ - op = R_GS; - do_lxx: - goto unsupported_op; - /************************/ - /* floats */ - case 0xd8 ... 0xdf: -#if 1 - /* currently not stable enough */ - goto unsupported_op; -#else - if (s->flags & (HF_EM_MASK | HF_TS_MASK)) - goto unsupported_op; -#endif -#if 0 - /* for testing FPU context switch */ - { - static int count; - count = (count + 1) % 3; - if (count != 0) - goto unsupported_op; - } -#endif - modrm = ldub_code(s->pc++); - mod = (modrm >> 6) & 3; - rm = modrm & 7; - op = ((b & 7) << 3) | ((modrm >> 3) & 7); - if (mod != 3) { - /* memory op */ - parse_modrm(s, modrm); - switch(op) { - case 0x00 ... 0x07: /* fxxxs */ - case 0x10 ... 0x17: /* fixxxl */ - case 0x20 ... 0x27: /* fxxxl */ - case 0x30 ... 0x37: /* fixxx */ - break; - case 0x08: /* flds */ - case 0x0a: /* fsts */ - case 0x0b: /* fstps */ - case 0x18: /* fildl */ - case 0x1a: /* fistl */ - case 0x1b: /* fistpl */ - case 0x28: /* fldl */ - case 0x2a: /* fstl */ - case 0x2b: /* fstpl */ - case 0x38: /* filds */ - case 0x3a: /* fists */ - case 0x3b: /* fistps */ - case 0x0c: /* fldenv mem */ - case 0x0d: /* fldcw mem */ - case 0x0e: /* fnstenv mem */ - case 0x0f: /* fnstcw mem */ - case 0x1d: /* fldt mem */ - case 0x1f: /* fstpt mem */ - case 0x2c: /* frstor mem */ - case 0x2e: /* fnsave mem */ - case 0x2f: /* fnstsw mem */ - case 0x3c: /* fbld */ - case 0x3e: /* fbstp */ - case 0x3d: /* fildll */ - case 0x3f: /* fistpll */ - break; - default: - goto illegal_op; - } - } else { - /* register float ops */ - switch(op) { - case 0x08: /* fld sti */ - case 0x09: /* fxchg sti */ - break; - case 0x0a: /* grp d9/2 */ - switch(rm) { - case 0: /* fnop */ - break; - default: - goto illegal_op; - } - break; - case 0x0c: /* grp d9/4 */ - switch(rm) { - case 0: /* fchs */ - case 1: /* fabs */ - case 4: /* ftst */ - case 5: /* fxam */ - break; - default: - goto illegal_op; - } - break; - case 0x0d: /* grp d9/5 */ - switch(rm) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - break; - default: - goto illegal_op; - } - break; - case 0x0e: /* grp d9/6 */ - break; - case 0x0f: /* grp d9/7 */ - break; - case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ - case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ - case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ - break; - case 0x02: /* fcom */ - break; - case 0x03: /* fcomp */ - break; - case 0x15: /* da/5 */ - switch(rm) { - case 1: /* fucompp */ - break; - default: - goto illegal_op; - } - break; - case 0x1c: - switch(rm) { - case 0: /* feni (287 only, just do nop here) */ - case 1: /* fdisi (287 only, just do nop here) */ - goto unsupported_op; - case 2: /* fclex */ - case 3: /* fninit */ - case 4: /* fsetpm (287 only, just do nop here) */ - break; - default: - goto illegal_op; - } - break; - case 0x1d: /* fucomi */ - break; - case 0x1e: /* fcomi */ - break; - case 0x28: /* ffree sti */ - break; - case 0x2a: /* fst sti */ - break; - case 0x2b: /* fstp sti */ - break; - case 0x2c: /* fucom st(i) */ - break; - case 0x2d: /* fucomp st(i) */ - break; - case 0x33: /* de/3 */ - switch(rm) { - case 1: /* fcompp */ - break; - default: - goto illegal_op; - } - break; - case 0x3c: /* df/4 */ - switch(rm) { - case 0: - break; - default: - goto illegal_op; - } - break; - case 0x3d: /* fucomip */ - break; - case 0x3e: /* fcomip */ - break; - case 0x10 ... 0x13: /* fcmovxx */ - case 0x18 ... 0x1b: - break; - default: - goto illegal_op; - } - } - s->tb->cflags |= CF_TB_FP_USED; - break; - - /**************************/ - /* mov */ - case 0xc6: - case 0xc7: /* mov Ev, Iv */ - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub_code(s->pc++); - parse_modrm(s, modrm); - insn_get(s, ot); - break; - - case 0x8d: /* lea */ - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub_code(s->pc++); - mod = (modrm >> 6) & 3; - if (mod == 3) - goto illegal_op; - parse_modrm(s, modrm); - break; - - case 0xa0: /* mov EAX, Ov */ - case 0xa1: - case 0xa2: /* mov Ov, EAX */ - case 0xa3: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (s->aflag) - insn_get(s, OT_LONG); - else - insn_get(s, OT_WORD); - break; - case 0xd7: /* xlat */ - break; - case 0xb0 ... 0xb7: /* mov R, Ib */ - insn_get(s, OT_BYTE); - break; - case 0xb8 ... 0xbf: /* mov R, Iv */ - ot = dflag ? OT_LONG : OT_WORD; - insn_get(s, ot); - break; - - case 0x91 ... 0x97: /* xchg R, EAX */ - break; - - /************************/ - /* shifts */ - case 0xc0: - case 0xc1: /* shift Ev,imm */ - - case 0x1a4: /* shld imm */ - case 0x1ac: /* shrd imm */ - modrm = ldub_code(s->pc++); - parse_modrm(s, modrm); - ldub_code(s->pc++); - break; - - /************************/ - /* string ops */ - - case 0xa4: /* movsS */ - case 0xa5: - break; - - case 0xaa: /* stosS */ - case 0xab: - break; - - case 0xac: /* lodsS */ - case 0xad: - break; - - case 0xae: /* scasS */ - case 0xaf: - break; - - case 0xa6: /* cmpsS */ - case 0xa7: - break; - - case 0x6c: /* insS */ - case 0x6d: - goto unsupported_op; - - case 0x6e: /* outsS */ - case 0x6f: - goto unsupported_op; - - /************************/ - /* port I/O */ - case 0xe4: - case 0xe5: - goto unsupported_op; - - case 0xe6: - case 0xe7: - goto unsupported_op; - - case 0xec: - case 0xed: - goto unsupported_op; - - case 0xee: - case 0xef: - goto unsupported_op; - - /************************/ - /* control */ -#if 0 - case 0xc2: /* ret im */ - val = ldsw_code(s->pc); - s->pc += 2; - gen_pop_T0(s); - gen_stack_update(s, val + (2 << s->dflag)); - if (s->dflag == 0) - gen_op_andl_T0_ffff(); - gen_op_jmp_T0(); - gen_eob(s); - break; -#endif - - case 0xc3: /* ret */ - gb(s, CPU_SEG); - if (!s->dflag) - gb(s, 0x66); /* d16 */ - gb(s, 0x8f); /* pop addr */ - gb(s, 0x05); - gl(s, CPU_FIELD_OFFSET(eip)); - if (!s->dflag) { - /* reset high bits of EIP */ - gen_movw_addr_im(s, CPU_FIELD_OFFSET(eip) + 2, 0); - } - gen_eob(s); - goto no_copy; - case 0xca: /* lret im */ - case 0xcb: /* lret */ - case 0xcf: /* iret */ - case 0x9a: /* lcall im */ - case 0xea: /* ljmp im */ - goto unsupported_op; - - case 0xe8: /* call im */ - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); - next_eip = s->pc - s->cs_base; - val += next_eip; - if (s->dflag) { - gb(s, 0x68); /* pushl imm */ - gl(s, next_eip); - } else { - gb(s, 0x66); /* pushw imm */ - gb(s, 0x68); - gw(s, next_eip); - val &= 0xffff; - } - gen_jmp(s, val); - goto no_copy; - case 0xe9: /* jmp */ - ot = dflag ? OT_LONG : OT_WORD; - val = insn_get(s, ot); - val += s->pc - s->cs_base; - if (s->dflag == 0) - val = val & 0xffff; - gen_jmp(s, val); - goto no_copy; - case 0xeb: /* jmp Jb */ - val = (int8_t)insn_get(s, OT_BYTE); - val += s->pc - s->cs_base; - if (s->dflag == 0) - val = val & 0xffff; - gen_jmp(s, val); - goto no_copy; - case 0x70 ... 0x7f: /* jcc Jb */ - val = (int8_t)insn_get(s, OT_BYTE); - goto do_jcc; - case 0x180 ... 0x18f: /* jcc Jv */ - if (dflag) { - val = insn_get(s, OT_LONG); - } else { - val = (int16_t)insn_get(s, OT_WORD); - } - do_jcc: - next_eip = s->pc - s->cs_base; - val += next_eip; - if (s->dflag == 0) - val &= 0xffff; - gen_jcc(s, b & 0xf, val, next_eip); - goto no_copy; - - /************************/ - /* flags */ - case 0x9c: /* pushf */ - /* XXX: put specific code ? */ - goto unsupported_op; - case 0x9d: /* popf */ - goto unsupported_op; - - case 0x9e: /* sahf */ - case 0x9f: /* lahf */ - case 0xf5: /* cmc */ - case 0xf8: /* clc */ - case 0xf9: /* stc */ - case 0xfc: /* cld */ - case 0xfd: /* std */ - break; - - /************************/ - /* bit operations */ - case 0x1ba: /* bt/bts/btr/btc Gv, im */ - ot = dflag ? OT_LONG : OT_WORD; - modrm = ldub_code(s->pc++); - op = (modrm >> 3) & 7; - parse_modrm(s, modrm); - /* load shift */ - ldub_code(s->pc++); - if (op < 4) - goto illegal_op; - break; - /************************/ - /* bcd */ - case 0x27: /* daa */ - break; - case 0x2f: /* das */ - break; - case 0x37: /* aaa */ - break; - case 0x3f: /* aas */ - break; - case 0xd4: /* aam */ - ldub_code(s->pc++); - break; - case 0xd5: /* aad */ - ldub_code(s->pc++); - break; - /************************/ - /* misc */ - case 0x90: /* nop */ - break; - case 0x9b: /* fwait */ - if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == - (HF_MP_MASK | HF_TS_MASK)) { - goto unsupported_op; - } - break; - case 0xcc: /* int3 */ - goto unsupported_op; - case 0xcd: /* int N */ - goto unsupported_op; - case 0xce: /* into */ - goto unsupported_op; - case 0xf1: /* icebp (undocumented, exits to external debugger) */ - goto unsupported_op; - case 0xfa: /* cli */ - goto unsupported_op; - case 0xfb: /* sti */ - goto unsupported_op; - case 0x62: /* bound */ - modrm = ldub_code(s->pc++); - mod = (modrm >> 6) & 3; - if (mod == 3) - goto illegal_op; - parse_modrm(s, modrm); - break; - case 0x1c8 ... 0x1cf: /* bswap reg */ - break; - case 0xd6: /* salc */ - break; - case 0xe0: /* loopnz */ - case 0xe1: /* loopz */ - case 0xe2: /* loop */ - case 0xe3: /* jecxz */ - goto unsupported_op; - - case 0x130: /* wrmsr */ - case 0x132: /* rdmsr */ - goto unsupported_op; - case 0x131: /* rdtsc */ - goto unsupported_op; - case 0x1a2: /* cpuid */ - goto unsupported_op; - case 0xf4: /* hlt */ - goto unsupported_op; - case 0x100: - goto unsupported_op; - case 0x101: - goto unsupported_op; - case 0x108: /* invd */ - case 0x109: /* wbinvd */ - goto unsupported_op; - case 0x63: /* arpl */ - goto unsupported_op; - case 0x102: /* lar */ - case 0x103: /* lsl */ - goto unsupported_op; - case 0x118: - goto unsupported_op; - case 0x120: /* mov reg, crN */ - case 0x122: /* mov crN, reg */ - goto unsupported_op; - case 0x121: /* mov reg, drN */ - case 0x123: /* mov drN, reg */ - goto unsupported_op; - case 0x106: /* clts */ - goto unsupported_op; - default: - goto illegal_op; - } - - /* just copy the code */ - - /* no override yet */ - if (!s->dflag) - gb(s, 0x66); - if (!s->aflag) - gb(s, 0x67); - if (prefixes & PREFIX_REPZ) - gb(s, 0xf3); - else if (prefixes & PREFIX_REPNZ) - gb(s, 0xf2); - { - int len, i; - len = s->pc - pc_start_insn; - for(i = 0; i < len; i++) { - *s->gen_code_ptr++ = ldub_code(pc_start_insn + i); - } - } - no_copy: - return 0; - illegal_op: - unsupported_op: - /* fall back to slower code gen necessary */ - s->pc = pc_start; - return -1; -} - -#define GEN_CODE_MAX_SIZE 8192 -#define GEN_CODE_MAX_INSN_SIZE 512 - -static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, - uint8_t *gen_code_ptr, - int *gen_code_size_ptr, - int search_pc, - uint8_t *tc_ptr) -{ - DisasContext dc1, *dc = &dc1; - target_ulong pc_insn, pc_start, cs_base; - uint8_t *gen_code_end; - int flags, ret; - - if (env->nb_breakpoints > 0 || - env->singlestep_enabled) - return -1; - flags = tb->flags; - if (flags & (HF_TF_MASK | HF_ADDSEG_MASK | - HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK)) - return -1; - if (!(flags & HF_SS32_MASK)) - return -1; - if (tb->cflags & CF_SINGLE_INSN) - return -1; - gen_code_end = gen_code_ptr + - GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE; - dc->gen_code_ptr = gen_code_ptr; - dc->gen_code_start = gen_code_ptr; - - /* generate intermediate code */ - pc_start = tb->pc; - cs_base = tb->cs_base; - dc->pc = pc_start; - dc->cs_base = cs_base; - dc->pe = (flags >> HF_PE_SHIFT) & 1; - dc->code32 = (flags >> HF_CS32_SHIFT) & 1; - dc->f_st = 0; - dc->vm86 = (flags >> VM_SHIFT) & 1; - dc->cpl = (flags >> HF_CPL_SHIFT) & 3; - dc->iopl = (flags >> IOPL_SHIFT) & 3; - dc->tb = tb; - dc->flags = flags; - - dc->is_jmp = 0; - - for(;;) { - pc_insn = dc->pc; - ret = disas_insn(dc); - if (ret < 0) { - /* unsupported insn */ - if (dc->pc == pc_start) { - /* if first instruction, signal that no copying was done */ - return -1; - } else { - gen_jmp(dc, dc->pc - dc->cs_base); - dc->is_jmp = 1; - } - } - if (search_pc) { - /* search pc mode */ - if (tc_ptr < dc->gen_code_ptr) { - env->eip = pc_insn - cs_base; - return 0; - } - } - /* stop translation if indicated */ - if (dc->is_jmp) - break; - /* if too long translation, stop generation */ - if (dc->gen_code_ptr >= gen_code_end || - (dc->pc - pc_start) >= (TARGET_PAGE_SIZE - 32)) { - gen_jmp(dc, dc->pc - dc->cs_base); - break; - } - } - -#ifdef DEBUG_DISAS - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "----------------\n"); - fprintf(logfile, "IN: COPY: %s fpu=%d\n", - lookup_symbol(pc_start), - tb->cflags & CF_TB_FP_USED ? 1 : 0); - target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32); - fprintf(logfile, "\n"); - } -#endif - - if (!search_pc) { - *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start; - tb->size = dc->pc - pc_start; - tb->cflags |= CF_CODE_COPY; - return 0; - } else { - return -1; - } -} - -/* generate code by just copying data. Return -1 if cannot generate - any code. Return 0 if code was generated */ -int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr) -{ - /* generate machine code */ - tb->tb_next_offset[0] = 0xffff; - tb->tb_next_offset[1] = 0xffff; -#ifdef USE_DIRECT_JUMP - /* the following two entries are optional (only used for string ops) */ - tb->tb_jmp_offset[2] = 0xffff; - tb->tb_jmp_offset[3] = 0xffff; -#endif - return gen_intermediate_code_internal(env, tb, - tb->tc_ptr, gen_code_size_ptr, - 0, NULL); -} - -static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE]; - -int cpu_restore_state_copy(TranslationBlock *tb, - CPUState *env, unsigned long searched_pc, - void *puc) -{ - struct ucontext *uc = puc; - int ret, eflags; - - /* find opc index corresponding to search_pc */ - if (searched_pc < (unsigned long)tb->tc_ptr) - return -1; - searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf; - ret = gen_intermediate_code_internal(env, tb, - dummy_gen_code_buf, NULL, - 1, (uint8_t *)searched_pc); - if (ret < 0) - return ret; - /* restore all the CPU state from the CPU context from the - signal. The FPU context stays in the host CPU. */ - - env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX]; - env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX]; - env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX]; - env->regs[R_EBX] = uc->uc_mcontext.gregs[REG_EBX]; - env->regs[R_ESP] = uc->uc_mcontext.gregs[REG_ESP]; - env->regs[R_EBP] = uc->uc_mcontext.gregs[REG_EBP]; - env->regs[R_ESI] = uc->uc_mcontext.gregs[REG_ESI]; - env->regs[R_EDI] = uc->uc_mcontext.gregs[REG_EDI]; - eflags = uc->uc_mcontext.gregs[REG_EFL]; - env->df = 1 - (2 * ((eflags >> 10) & 1)); - env->cc_src = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - env->cc_op = CC_OP_EFLAGS; - return 0; -} - -#endif /* USE_CODE_COPY */ -- cgit v1.2.3 From ec6338bac30f982c16c23106edcf1ce4a04da575 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 8 Nov 2007 14:25:03 +0000 Subject: removed obsolete x86 code copy support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3551 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 -- cpu-exec.c | 126 ++---------------------------------------------- darwin-user/main.c | 8 --- darwin-user/signal.c | 6 +-- exec.c | 5 -- linux-user/main.c | 8 --- linux-user/signal.c | 6 +-- target-i386/cpu.h | 11 ----- target-i386/helper2.c | 105 ---------------------------------------- target-i386/translate.c | 3 -- tests/qruncom.c | 3 -- translate-all.c | 45 ++++++----------- vl.c | 21 -------- 13 files changed, 23 insertions(+), 327 deletions(-) diff --git a/Makefile.target b/Makefile.target index e8ead7df5..ab925ad09 100644 --- a/Makefile.target +++ b/Makefile.target @@ -302,9 +302,6 @@ 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) diff --git a/cpu-exec.c b/cpu-exec.c index 3bfa0bc1f..4ba63fba3 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -612,19 +612,9 @@ int cpu_exec(CPUState *env1) #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 - ) { + tb->page_addr[1] == -1) { 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); } } @@ -648,80 +638,6 @@ int cpu_exec(CPUState *env1) : /* 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; @@ -759,11 +675,6 @@ int cpu_exec(CPUState *env1) #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); #elif defined(TARGET_ARM) @@ -1275,26 +1186,6 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, # define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) #endif -#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, void *pinfo, void *puc) { @@ -1311,17 +1202,10 @@ int cpu_signal_handler(int host_signum, void *pinfo, #endif pc = EIP_sig(uc); trapno = TRAP_sig(uc); -#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 ? - (ERROR_sig(uc) >> 1) & 1 : 0, - &uc->uc_sigmask, puc); + return handle_cpu_signal(pc, (unsigned long)info->si_addr, + trapno == 0xe ? + (ERROR_sig(uc) >> 1) & 1 : 0, + &uc->uc_sigmask, puc); } #elif defined(__x86_64__) diff --git a/darwin-user/main.c b/darwin-user/main.c index 70328ec8e..f240f35a6 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -757,9 +757,6 @@ void usage(void) "-s size set the stack size in bytes (default=%ld)\n" "\n" "debug options:\n" -#ifdef USE_CODE_COPY - "-no-code-copy disable code copy acceleration\n" -#endif "-d options activate log (logfile='%s')\n" "-g wait for gdb on port 1234\n" "-p pagesize set the host page size to 'pagesize'\n", @@ -845,11 +842,6 @@ int main(int argc, char **argv) if (!strcmp(r, "g")) { use_gdbstub = 1; } else -#ifdef USE_CODE_COPY - if (!strcmp(r, "no-code-copy")) { - code_copy_enabled = 0; - } else -#endif { usage(); } diff --git a/darwin-user/signal.c b/darwin-user/signal.c index a0b9f89dc..8dbfa931e 100644 --- a/darwin-user/signal.c +++ b/darwin-user/signal.c @@ -198,11 +198,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, /* the CPU emulator uses some host signals to detect exceptions, we we forward to it some signals */ - if (host_signum == SIGSEGV || host_signum == SIGBUS -#if defined(TARGET_I386) && defined(USE_CODE_COPY) - || host_signum == SIGFPE -#endif - ) { + if (host_signum == SIGSEGV || host_signum == SIGBUS) { if (cpu_signal_handler(host_signum, (void*)info, puc)) return; } diff --git a/exec.c b/exec.c index aa5c9aed0..b49e520c1 100644 --- a/exec.c +++ b/exec.c @@ -944,11 +944,6 @@ void tb_link_phys(TranslationBlock *tb, tb->jmp_first = (TranslationBlock *)((long)tb | 2); tb->jmp_next[0] = NULL; tb->jmp_next[1] = NULL; -#ifdef USE_CODE_COPY - tb->cflags &= ~CF_FP_USED; - if (tb->cflags & CF_TB_FP_USED) - tb->cflags |= CF_FP_USED; -#endif /* init original jump addresses */ if (tb->tb_next_offset[0] != 0xffff) diff --git a/linux-user/main.c b/linux-user/main.c index 716348cff..b480a9ca2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1855,9 +1855,6 @@ void usage(void) "-drop-ld-preload drop LD_PRELOAD for target process\n" "\n" "debug options:\n" -#ifdef USE_CODE_COPY - "-no-code-copy disable code copy acceleration\n" -#endif "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n", TARGET_ARCH, @@ -1956,11 +1953,6 @@ int main(int argc, char **argv) } else if (!strcmp(r, "drop-ld-preload")) { drop_ld_preload = 1; } else -#ifdef USE_CODE_COPY - if (!strcmp(r, "no-code-copy")) { - code_copy_enabled = 0; - } else -#endif { usage(); } diff --git a/linux-user/signal.c b/linux-user/signal.c index 0c5944aba..984c598f2 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -415,11 +415,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info, /* the CPU emulator uses some host signals to detect exceptions, we we forward to it some signals */ - if (host_signum == SIGSEGV || host_signum == SIGBUS -#if defined(TARGET_I386) && defined(USE_CODE_COPY) - || host_signum == SIGFPE -#endif - ) { + if (host_signum == SIGSEGV || host_signum == SIGBUS) { if (cpu_signal_handler(host_signum, info, puc)) return; } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e92fc3104..c8fb12591 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -46,10 +46,6 @@ #include "softfloat.h" -#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(__APPLE__) -#define USE_CODE_COPY -#endif - #define R_EAX 0 #define R_ECX 1 #define R_EDX 2 @@ -552,13 +548,6 @@ typedef struct CPUX86State { uint64_t pat; - /* temporary data for USE_CODE_COPY mode */ -#ifdef USE_CODE_COPY - uint32_t tmp0; - uint32_t saved_esp; - int native_fp_regs; /* if true, the FPU state is in the native CPU regs */ -#endif - /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 87788d721..065532049 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -31,22 +31,6 @@ //#define DEBUG_MMU -#ifdef USE_CODE_COPY -#include -#include -#include -#include - -int modify_ldt(int func, void *ptr, unsigned long bytecount) -{ - return syscall(__NR_modify_ldt, func, ptr, bytecount); -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) -#define modify_ldt_ldt_s user_desc -#endif -#endif /* USE_CODE_COPY */ - static struct x86_def_t *x86_cpu_def; typedef struct x86_def_t x86_def_t; static int cpu_x86_register (CPUX86State *env, const x86_def_t *def); @@ -123,25 +107,6 @@ CPUX86State *cpu_x86_init(void) inited = 1; optimize_flags_init(); } -#ifdef USE_CODE_COPY - /* testing code for code copy case */ - { - struct modify_ldt_ldt_s ldt; - - ldt.entry_number = 1; - ldt.base_addr = (unsigned long)env; - ldt.limit = (sizeof(CPUState) + 0xfff) >> 12; - ldt.seg_32bit = 1; - ldt.contents = MODIFY_LDT_CONTENTS_DATA; - ldt.read_exec_only = 0; - ldt.limit_in_pages = 1; - ldt.seg_not_present = 0; - ldt.useable = 1; - modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ - - asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7)); - } -#endif cpu_x86_register(env, x86_cpu_def); cpu_reset(env); #ifdef USE_KQEMU @@ -1186,73 +1151,3 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return paddr; } #endif /* !CONFIG_USER_ONLY */ - -#if defined(USE_CODE_COPY) -struct fpstate { - uint16_t fpuc; - uint16_t dummy1; - uint16_t fpus; - uint16_t dummy2; - uint16_t fptag; - uint16_t dummy3; - - uint32_t fpip; - uint32_t fpcs; - uint32_t fpoo; - uint32_t fpos; - uint8_t fpregs1[8 * 10]; -}; - -void restore_native_fp_state(CPUState *env) -{ - int fptag, i, j; - struct fpstate fp1, *fp = &fp1; - - fp->fpuc = env->fpuc; - fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; - fptag = 0; - for (i=7; i>=0; i--) { - fptag <<= 2; - if (env->fptags[i]) { - fptag |= 3; - } else { - /* the FPU automatically computes it */ - } - } - fp->fptag = fptag; - j = env->fpstt; - for(i = 0;i < 8; i++) { - memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10); - j = (j + 1) & 7; - } - asm volatile ("frstor %0" : "=m" (*fp)); - env->native_fp_regs = 1; -} - -void save_native_fp_state(CPUState *env) -{ - int fptag, i, j; - uint16_t fpuc; - struct fpstate fp1, *fp = &fp1; - - asm volatile ("fsave %0" : : "m" (*fp)); - env->fpuc = fp->fpuc; - env->fpstt = (fp->fpus >> 11) & 7; - env->fpus = fp->fpus & ~0x3800; - fptag = fp->fptag; - for(i = 0;i < 8; i++) { - env->fptags[i] = ((fptag & 3) == 3); - fptag >>= 2; - } - j = env->fpstt; - for(i = 0;i < 8; i++) { - memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10); - j = (j + 1) & 7; - } - /* we must restore the default rounding state */ - /* XXX: we do not restore the exception state */ - fpuc = 0x037f | (env->fpuc & (3 << 10)); - asm volatile("fldcw %0" : : "m" (fpuc)); - env->native_fp_regs = 0; -} -#endif diff --git a/target-i386/translate.c b/target-i386/translate.c index 7ab8f4b69..02dc6cf61 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4888,9 +4888,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) goto illegal_op; } } -#ifdef USE_CODE_COPY - s->tb->cflags |= CF_TB_FP_USED; -#endif break; /************************/ /* string ops */ diff --git a/tests/qruncom.c b/tests/qruncom.c index ad0d938ee..1f2b63e3c 100644 --- a/tests/qruncom.c +++ b/tests/qruncom.c @@ -193,9 +193,6 @@ int main(int argc, char **argv) act.sa_sigaction = host_segv_handler; sigaction(SIGSEGV, &act, NULL); sigaction(SIGBUS, &act, NULL); -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - sigaction(SIGFPE, &act, NULL); -#endif } // cpu_set_log(CPU_LOG_TB_IN_ASM | CPU_LOG_TB_OUT_ASM | CPU_LOG_EXEC); diff --git a/translate-all.c b/translate-all.c index 197c48c54..c42fedf7f 100644 --- a/translate-all.c +++ b/translate-all.c @@ -144,35 +144,27 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb, uint8_t *gen_code_buf; int gen_code_size; -#ifdef USE_CODE_COPY - if (code_copy_enabled && - cpu_gen_code_copy(env, tb, max_code_size, &gen_code_size) == 0) { - /* nothing more to do */ - } else -#endif - { - if (gen_intermediate_code(env, tb) < 0) - return -1; - - /* generate machine code */ - tb->tb_next_offset[0] = 0xffff; - tb->tb_next_offset[1] = 0xffff; - gen_code_buf = tb->tc_ptr; + if (gen_intermediate_code(env, tb) < 0) + return -1; + + /* generate machine code */ + tb->tb_next_offset[0] = 0xffff; + tb->tb_next_offset[1] = 0xffff; + gen_code_buf = tb->tc_ptr; #ifdef USE_DIRECT_JUMP - /* the following two entries are optional (only used for string ops) */ - tb->tb_jmp_offset[2] = 0xffff; - tb->tb_jmp_offset[3] = 0xffff; + /* the following two entries are optional (only used for string ops) */ + tb->tb_jmp_offset[2] = 0xffff; + tb->tb_jmp_offset[3] = 0xffff; #endif - dyngen_labels(gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf); - - gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, + dyngen_labels(gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf); + + gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, #ifdef USE_DIRECT_JUMP - tb->tb_jmp_offset, + tb->tb_jmp_offset, #else - NULL, + NULL, #endif - gen_opc_buf, gen_opparam_buf, gen_labels); - } + gen_opc_buf, gen_opparam_buf, gen_labels); *gen_code_size_ptr = gen_code_size; #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_OUT_ASM) { @@ -195,11 +187,6 @@ int cpu_restore_state(TranslationBlock *tb, unsigned long tc_ptr; uint16_t *opc_ptr; -#ifdef USE_CODE_COPY - if (tb->cflags & CF_CODE_COPY) { - return cpu_restore_state_copy(tb, env, searched_pc, puc); - } -#endif if (gen_intermediate_code_pc(env, tb) < 0) return -1; diff --git a/vl.c b/vl.c index c13b1a1f4..03859a995 100644 --- a/vl.c +++ b/vl.c @@ -1222,9 +1222,6 @@ static void enable_sigio_timer(int fd) /* timer signal */ sigfillset(&act.sa_mask); act.sa_flags = 0; -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; -#endif act.sa_handler = host_alarm_handler; sigaction(SIGIO, &act, NULL); @@ -1322,9 +1319,6 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t) sigfillset(&act.sa_mask); act.sa_flags = 0; -#if defined(TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; -#endif act.sa_handler = host_alarm_handler; sigaction(SIGALRM, &act, NULL); @@ -1399,9 +1393,6 @@ static int unix_start_timer(struct qemu_alarm_timer *t) /* timer signal */ sigfillset(&act.sa_mask); act.sa_flags = 0; -#if defined(TARGET_I386) && defined(USE_CODE_COPY) - act.sa_flags |= SA_ONSTACK; -#endif act.sa_handler = host_alarm_handler; sigaction(SIGALRM, &act, NULL); @@ -7093,9 +7084,6 @@ static void help(int exitcode) "-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n" "-no-kqemu disable KQEMU kernel module usage\n" #endif -#ifdef USE_CODE_COPY - "-no-code-copy disable code copy acceleration\n" -#endif #ifdef TARGET_I386 "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" @@ -7324,15 +7312,6 @@ const QEMUOption qemu_options[] = { { NULL }, }; -#if defined (TARGET_I386) && defined(USE_CODE_COPY) - -/* this stack is only used during signal handling */ -#define SIGNAL_STACK_SIZE 32768 - -static uint8_t *signal_stack; - -#endif - /* password input */ int qemu_key_check(BlockDriverState *bs, const char *name) -- cgit v1.2.3 From 31c2a146ec3ac18f01c645c3c0d779f138c0d805 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 8 Nov 2007 16:38:17 +0000 Subject: Revert "Last AIO Patch" as requested by Fabrice, it is incomplete and breaks other (non-Windows) systems. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3552 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 56 ++++++++++++++++++-------------------------------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index 329d053e1..5f76c2767 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -358,7 +358,7 @@ typedef struct IDEState { uint8_t *data_ptr; uint8_t *data_end; uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; - QEMUTimer *sector_write_timer; /* only used for win2k instal hack */ + QEMUTimer *sector_write_timer; /* only used for win2k install hack */ uint32_t irq_count; /* counts IRQs when using win2k install hack */ /* CF-ATA extended error */ uint8_t ext_error; @@ -865,44 +865,10 @@ static void ide_sector_write_timer_cb(void *opaque) ide_set_irq(s); } -static void ide_sector_write_aio_cb(void *opaque, int ret) -{ - BMDMAState *bm = opaque; - IDEState *s = bm->ide_if; - -#ifdef TARGET_I386 - if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { - /* It seems there is a bug in the Windows 2000 installer HDD - IDE driver which fills the disk with empty logs when the - IDE write IRQ comes too early. This hack tries to correct - that at the expense of slower write performances. Use this - option _only_ to install Windows 2000. You must disable it - for normal use. */ - qemu_mod_timer(s->sector_write_timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); - } else -#endif - { - ide_set_irq(s); - } - bm->aiocb = NULL; -} - static void ide_sector_write(IDEState *s) { - BMDMAState *bm; int64_t sector_num; - int n, n1; - - s->io_buffer_index = 0; - s->io_buffer_size = 0; - bm = s->bmdma; - if(bm == NULL) { - bm = qemu_mallocz(sizeof(BMDMAState)); - s->bmdma = bm; - } - bm->ide_if = s; - bm->dma_cb = ide_sector_write_aio_cb; + int ret, n, n1; s->status = READY_STAT | SEEK_STAT; sector_num = ide_get_sector(s); @@ -912,6 +878,7 @@ static void ide_sector_write(IDEState *s) n = s->nsector; if (n > s->req_nb_sectors) n = s->req_nb_sectors; + ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); s->nsector -= n; if (s->nsector == 0) { /* no more sectors to write */ @@ -924,8 +891,21 @@ static void ide_sector_write(IDEState *s) } ide_set_sector(s, sector_num + n); - bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, - ide_sector_write_aio_cb, bm); +#ifdef TARGET_I386 + if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { + /* It seems there is a bug in the Windows 2000 installer HDD + IDE driver which fills the disk with empty logs when the + IDE write IRQ comes too early. This hack tries to correct + that at the expense of slower write performances. Use this + option _only_ to install Windows 2000. You must disable it + for normal use. */ + qemu_mod_timer(s->sector_write_timer, + qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); + } else +#endif + { + ide_set_irq(s); + } } /* XXX: handle errors */ -- cgit v1.2.3 From 0ab5ec319ab735ae4dbccf2f7134d160eae96933 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 8 Nov 2007 16:43:05 +0000 Subject: .cvsignore dependency files. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3553 c046a42c-6fe2-441c-8c8c-71466251a162 --- .cvsignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.cvsignore b/.cvsignore index b51b9895e..81d708236 100644 --- a/.cvsignore +++ b/.cvsignore @@ -24,3 +24,4 @@ qemu-img *.toc *.tp *.vr +*.d -- cgit v1.2.3 From 855cea8c9273b01acc0975df2f27e2f33357a6bc Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 8 Nov 2007 16:44:01 +0000 Subject: Formatting fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3554 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index ce0b4dcfe..9ec28eacc 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2523,7 +2523,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 0: switch (sel) { case 0: - gen_op_mtc0_index(); + gen_op_mtc0_index(); rn = "Index"; break; case 1: -- cgit v1.2.3 From 5850586c072456e6f007096ea8a489c97118f8f1 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 8 Nov 2007 16:44:36 +0000 Subject: More .cvsignore. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3555 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/.cvsignore | 1 + slirp/.cvsignore | 1 + 2 files changed, 2 insertions(+) create mode 100644 audio/.cvsignore create mode 100644 slirp/.cvsignore diff --git a/audio/.cvsignore b/audio/.cvsignore new file mode 100644 index 000000000..a4383358e --- /dev/null +++ b/audio/.cvsignore @@ -0,0 +1 @@ +*.d diff --git a/slirp/.cvsignore b/slirp/.cvsignore new file mode 100644 index 000000000..a4383358e --- /dev/null +++ b/slirp/.cvsignore @@ -0,0 +1 @@ +*.d -- cgit v1.2.3 From d26bc2118e99702eb8c1bb240786bcadd7fa21ac Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 8 Nov 2007 18:05:37 +0000 Subject: Clean out the N32 macros from target-mips, and introduce MIPS ABI specific defines for linux-user. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3556 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 4 +++- linux-user/main.c | 2 +- linux-user/signal.c | 6 ++--- linux-user/syscall_defs.h | 14 ++++++------ target-mips/exec.h | 6 ++--- target-mips/helper.c | 16 ++++++------- target-mips/mips-defs.h | 2 +- target-mips/op.c | 24 ++++++++++---------- target-mips/op_helper.c | 10 ++++---- target-mips/op_mem.c | 4 ++-- target-mips/op_template.c | 2 +- target-mips/translate.c | 54 ++++++++++++++++++++++---------------------- target-mips/translate_init.c | 4 ++-- 13 files changed, 75 insertions(+), 73 deletions(-) diff --git a/configure b/configure index 751dc83d8..87166b461 100755 --- a/configure +++ b/configure @@ -1099,16 +1099,18 @@ 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 "#define TARGET_ABI_MIPSO32 1" >> $config_h elif test "$target_cpu" = "mipsn32" -o "$target_cpu" = "mipsn32el" ; then echo "TARGET_ARCH=mipsn32" >> $config_mak echo "#define TARGET_ARCH \"mipsn32\"" >> $config_h echo "#define TARGET_MIPS 1" >> $config_h - echo "#define TARGET_MIPSN32 1" >> $config_h + echo "#define TARGET_ABI_MIPSN32 1" >> $config_h elif test "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el" ; then echo "TARGET_ARCH=mips64" >> $config_mak echo "#define TARGET_ARCH \"mips64\"" >> $config_h echo "#define TARGET_MIPS 1" >> $config_h echo "#define TARGET_MIPS64 1" >> $config_h + echo "#define TARGET_ABI_MIPSN64 1" >> $config_h elif test "$target_cpu" = "cris" ; then echo "TARGET_ARCH=cris" >> $config_mak echo "#define TARGET_ARCH \"cris\"" >> $config_h diff --git a/linux-user/main.c b/linux-user/main.c index b480a9ca2..77667a55e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2225,7 +2225,7 @@ int main(int argc, char **argv) /* Choose and initialise CPU */ if (cpu_model == NULL) -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) cpu_model = "20Kc"; #else cpu_model = "24Kf"; diff --git a/linux-user/signal.c b/linux-user/signal.c index 984c598f2..a0f151102 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1939,7 +1939,7 @@ void sparc64_get_context(CPUSPARCState *env) force_sig(SIGSEGV); } #endif -#elif defined(TARGET_MIPS64) +#elif defined(TARGET_ABI_MIPSN64) # warning signal handling not implemented @@ -1968,7 +1968,7 @@ long do_rt_sigreturn(CPUState *env) return -ENOSYS; } -#elif defined(TARGET_MIPSN32) +#elif defined(TARGET_ABI_MIPSN32) # warning signal handling not implemented @@ -1997,7 +1997,7 @@ long do_rt_sigreturn(CPUState *env) return -ENOSYS; } -#elif defined(TARGET_MIPS) +#elif defined(TARGET_ABI_MIPSO32) struct target_sigcontext { uint32_t sc_regmask; /* Unused */ diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 6c80c91b3..99b17cb05 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -307,8 +307,8 @@ int do_sigaction(int sig, const struct target_sigaction *act, #define TARGET_SA_NODEFER 0x40000000 #define TARGET_SA_RESTART 0x10000000 #define TARGET_SA_RESETHAND 0x80000000 -#if !defined(TARGET_MIPSN32) && !defined(TARGET_MIPS64) -#define TARGET_SA_RESTORER 0x04000000 /* Only for o32 */ +#if !defined(TARGET_ABI_MIPSN32) && !defined(TARGET_ABI_MIPSN64) +#define TARGET_SA_RESTORER 0x04000000 /* Only for O32 */ #endif #else #define TARGET_SA_NOCLDSTOP 0x00000001 @@ -450,7 +450,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction { uint32_t sa_flags; -#if defined(TARGET_MIPSN32) +#if defined(TARGET_ABI_MIPSN32) uint32_t _sa_handler; #else abi_ulong _sa_handler; @@ -1194,7 +1194,7 @@ struct target_stat64 { unsigned long long st_ino; } __attribute__((packed)); -#elif defined(TARGET_MIPS64) +#elif defined(TARGET_ABI_MIPSN64) /* The memory layout is the same as of struct stat64 of the 32-bit kernel. */ struct target_stat { @@ -1233,7 +1233,7 @@ struct target_stat { abi_ulong st_blocks; }; -#elif defined(TARGET_MIPSN32) +#elif defined(TARGET_ABI_MIPSN32) struct target_stat { unsigned st_dev; @@ -1304,7 +1304,7 @@ struct target_stat64 { int st_blocks; }; -#elif defined(TARGET_MIPS) +#elif defined(TARGET_ABI_MIPSO32) struct target_stat { unsigned st_dev; @@ -1486,7 +1486,7 @@ typedef struct { } target_fsid_t; #ifdef TARGET_MIPS -#ifdef TARGET_MIPSN32 +#ifdef TARGET_ABI_MIPSN32 struct target_statfs { int32_t f_type; int32_t f_bsize; diff --git a/target-mips/exec.h b/target-mips/exec.h index 529306f3b..6a05f86c7 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -56,7 +56,7 @@ register target_ulong T2 asm(AREG3); #include "softmmu_exec.h" #endif /* !defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) #if TARGET_LONG_BITS > HOST_LONG_BITS void do_dsll (void); void do_dsll32 (void); @@ -86,7 +86,7 @@ void do_maddu (void); void do_msub (void); void do_msubu (void); #endif -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) void do_ddiv (void); #if TARGET_LONG_BITS > HOST_LONG_BITS void do_ddivu (void); @@ -236,7 +236,7 @@ static always_inline void compute_hflags(CPUState *env) !(env->hflags & MIPS_HFLAG_DM)) { env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || (env->CP0_Status & (1 << CP0St_PX)) || (env->CP0_Status & (1 << CP0St_UX))) diff --git a/target-mips/helper.c b/target-mips/helper.c index 933a6ac41..6cdcd7f1d 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -76,7 +76,7 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot, target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); target_ulong tag = address & ~mask; target_ulong VPN = tlb->VPN & ~mask; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) tag &= env->SEGMask; #endif @@ -108,7 +108,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM; int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM; int kernel_mode = !user_mode && !supervisor_mode; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; @@ -130,7 +130,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) } else if (address < 0x4000000000000000ULL) { /* xuseg */ if (UX && address < (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { @@ -305,7 +305,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ((address >> 9) & 0x007ffff0); env->CP0_EntryHi = (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1)); -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) env->CP0_EntryHi &= env->SEGMask; env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) | ((address & 0xC00000000000ULL) >> (env->SEGBITS - 9)) | @@ -425,7 +425,7 @@ void do_interrupt (CPUState *env) case EXCP_TLBL: cause = 2; if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) int R = env->CP0_BadVAddr >> 62; int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; @@ -473,7 +473,7 @@ void do_interrupt (CPUState *env) case EXCP_TLBS: cause = 3; if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) { -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) int R = env->CP0_BadVAddr >> 62; int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; @@ -559,7 +559,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); if (tlb->V0) { addr = tlb->VPN & ~mask; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) { addr |= 0x3FFFFF0000000000ULL; } @@ -572,7 +572,7 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra) } if (tlb->V1) { addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1); -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) { addr |= 0x3FFFFF0000000000ULL; } diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index a30f2edae..251fa359d 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -8,7 +8,7 @@ #define TARGET_PAGE_BITS 12 #define MIPS_TLB_MAX 128 -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) #define TARGET_LONG_BITS 64 #else #define TARGET_LONG_BITS 32 diff --git a/target-mips/op.c b/target-mips/op.c index 569c2f2a9..f5796c87e 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -301,7 +301,7 @@ void op_addr_add (void) /* For compatibility with 32-bit code, data reference in user mode with Status_UX = 0 should be casted to 32-bit and sign extended. See the MIPS64 PRA manual, section 4.10. */ -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_UX))) T0 = (int64_t)(int32_t)(T0 + T1); @@ -384,7 +384,7 @@ void op_divu (void) RETURN(); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) /* Arithmetic */ void op_dadd (void) { @@ -453,7 +453,7 @@ void op_ddivu (void) RETURN(); } #endif -#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ +#endif /* TARGET_MIPS64 */ /* Logical */ void op_and (void) @@ -552,7 +552,7 @@ void op_clz (void) RETURN(); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) #if TARGET_LONG_BITS > HOST_LONG_BITS /* Those might call libgcc functions. */ @@ -743,7 +743,7 @@ void op_dclz (void) RETURN(); } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ +#endif /* TARGET_MIPS64 */ /* 64 bits arithmetic */ #if TARGET_LONG_BITS > HOST_LONG_BITS @@ -846,7 +846,7 @@ void op_msubu (void) } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) void op_dmult (void) { CALL_FROM_TB4(muls64, &(env->LO[0][env->current_tc]), &(env->HI[0][env->current_tc]), T0, T1); @@ -950,7 +950,7 @@ void op_save_btarget (void) RETURN(); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) void op_save_btarget64 (void) { env->btarget = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; @@ -1784,7 +1784,7 @@ void op_mtc0_entryhi (void) /* 1k pages not implemented */ val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF); -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) val &= env->SEGMask; #endif old = env->CP0_EntryHi; @@ -2011,7 +2011,7 @@ void op_mtc0_desave (void) RETURN(); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) void op_dmfc0_yqmask (void) { T0 = env->CP0_YQMask; @@ -2125,7 +2125,7 @@ void op_dmfc0_errorepc (void) T0 = env->CP0_ErrorEPC; RETURN(); } -#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ +#endif /* TARGET_MIPS64 */ /* MIPS MT functions */ void op_mftgpr(void) @@ -3039,7 +3039,7 @@ void op_save_pc (void) RETURN(); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) void op_save_pc64 (void) { env->PC[env->current_tc] = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; @@ -3111,7 +3111,7 @@ void op_wsbh(void) RETURN(); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) void op_dext(void) { unsigned int pos = PARAM1; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 50c76d1ca..31d062ad4 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -68,7 +68,7 @@ void do_raise_exception_direct (uint32_t exception) do_raise_exception_direct_err (exception, 0); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) #if TARGET_LONG_BITS > HOST_LONG_BITS /* Those might call libgcc functions. */ void do_dsll (void) @@ -159,7 +159,7 @@ void do_dclz (void) } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ -#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ +#endif /* TARGET_MIPS64 */ /* 64 bits arithmetic for 32 bits hosts */ #if TARGET_LONG_BITS > HOST_LONG_BITS @@ -228,7 +228,7 @@ void do_div (void) } #endif -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) void do_ddiv (void) { if (T1 != 0) { @@ -247,7 +247,7 @@ void do_ddivu (void) } } #endif -#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ +#endif /* TARGET_MIPS64 */ #if defined(CONFIG_USER_ONLY) void do_mfc0_random (void) @@ -392,7 +392,7 @@ static void r4k_fill_tlb (int idx) /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb->mmu.r4k.tlb[idx]; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) tlb->VPN &= env->SEGMask; #endif tlb->ASID = env->CP0_EntryHi & 0xFF; diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 42f5e2ba3..5c981ada8 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -190,7 +190,7 @@ void glue(op_sc, MEMSUFFIX) (void) RETURN(); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) void glue(op_ld, MEMSUFFIX) (void) { T0 = glue(ldq, MEMSUFFIX)(T0); @@ -381,7 +381,7 @@ void glue(op_scd, MEMSUFFIX) (void) } RETURN(); } -#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ +#endif /* TARGET_MIPS64 */ void glue(op_lwc1, MEMSUFFIX) (void) { diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 148656eb2..036e6cef5 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -82,7 +82,7 @@ SET_RESET(T2, _T2) #undef SET_RESET -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) #define SET64(treg, tregname) \ void glue(op_set64, tregname)(void) \ { \ diff --git a/target-mips/translate.c b/target-mips/translate.c index 9ec28eacc..578cd9a25 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -590,7 +590,7 @@ do { \ } \ } while (0) -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) #define GEN_LOAD_IMM_TN(Tn, Imm) \ do { \ if (Imm == 0) { \ @@ -638,7 +638,7 @@ do { \ static always_inline void gen_save_pc(target_ulong pc) { -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) if (pc == (int32_t)pc) { gen_op_save_pc(pc); } else { @@ -651,7 +651,7 @@ static always_inline void gen_save_pc(target_ulong pc) static always_inline void gen_save_btarget(target_ulong btarget) { -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) if (btarget == (int32_t)btarget) { gen_op_save_btarget(btarget); } else { @@ -802,7 +802,7 @@ static GenOpFunc *gen_op_s##width[] = { \ } #endif -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) OP_LD_TABLE(d); OP_LD_TABLE(dl); OP_LD_TABLE(dr); @@ -852,7 +852,7 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, /* Don't do NOP if destination is zero: we must perform the actual memory access. */ switch (opc) { -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_LWU: op_ldst(lwu); GEN_STORE_TN_REG(rt, T0); @@ -1048,7 +1048,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, switch (opc) { case OPC_ADDI: case OPC_ADDIU: -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DADDI: case OPC_DADDIU: #endif @@ -1068,7 +1068,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, case OPC_SLL: case OPC_SRA: case OPC_SRL: -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DSLL: case OPC_DSRA: case OPC_DSRL: @@ -1091,7 +1091,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, gen_op_add(); opn = "addiu"; break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DADDI: save_cpu_state(ctx, 1); gen_op_daddo(); @@ -1155,7 +1155,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, break; } break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DSLL: gen_op_dsll(); opn = "dsll"; @@ -1260,7 +1260,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, gen_op_sub(); opn = "subu"; break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DADD: save_cpu_state(ctx, 1); gen_op_daddo(); @@ -1346,7 +1346,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, break; } break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DSLLV: gen_op_dsllv(); opn = "dsllv"; @@ -1451,7 +1451,7 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, gen_op_multu(); opn = "multu"; break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DDIV: gen_op_ddiv(); opn = "ddiv"; @@ -1512,7 +1512,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, gen_op_clz(); opn = "clz"; break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DCLO: gen_op_dclo(); opn = "dclo"; @@ -2319,7 +2319,7 @@ static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) check_insn(env, ctx, ISA_MIPS3); gen_op_mfc0_xcontext(); rn = "XContext"; @@ -2901,7 +2901,7 @@ static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel) case 20: switch (sel) { case 0: -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) check_insn(env, ctx, ISA_MIPS3); gen_op_mtc0_xcontext(); rn = "XContext"; @@ -3111,7 +3111,7 @@ die: generate_exception(ctx, EXCP_RI); } -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel) { const char *rn = "invalid"; @@ -4254,7 +4254,7 @@ die: #endif generate_exception(ctx, EXCP_RI); } -#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */ +#endif /* TARGET_MIPS64 */ static void gen_mftr(CPUState *env, DisasContext *ctx, int rt, int u, int sel, int h) @@ -4604,7 +4604,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DMFC0: check_insn(env, ctx, ISA_MIPS3); if (rt == 0) { @@ -5877,7 +5877,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, /* MIPS16 extension to MIPS32 */ /* SmartMIPS extension to MIPS32 */ -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) /* MDMX extension to MIPS64 */ @@ -5987,7 +5987,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) /* MIPS64 specific opcodes */ case OPC_DSLL: case OPC_DSRL ... OPC_DSRA: @@ -6043,7 +6043,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } /* Treat as NOP. */ break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DCLZ ... OPC_DCLO: check_insn(env, ctx, ISA_MIPS64); check_mips_64(ctx); @@ -6130,7 +6130,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_op_yield(); GEN_STORE_TN_REG(rd, T0); break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: check_insn(env, ctx, ISA_MIPS64R2); @@ -6192,7 +6192,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_MTC0: case OPC_MFTR: case OPC_MTTR: -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DMFC0: case OPC_DMTC0: #endif @@ -6313,7 +6313,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) case OPC_CTC1: gen_cp1(ctx, op1, rt, rd); break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) case OPC_DMFC1: case OPC_DMTC1: check_insn(env, ctx, ISA_MIPS3); @@ -6398,7 +6398,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) /* MIPS64 opcodes */ case OPC_LWU: case OPC_LDL ... OPC_LDR: @@ -6665,7 +6665,7 @@ void dump_fpu (CPUState *env) } } -#if (defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) +#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) /* Debug help: The architecture requires 32bit code to maintain proper sign-extened values on 64bit machines. */ @@ -6720,7 +6720,7 @@ void cpu_dump_state (CPUState *env, FILE *f, env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); if (env->hflags & MIPS_HFLAG_FPU) fpu_dump_state(env, f, cpu_fprintf, flags); -#if (defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) +#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags); #endif } diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 997858a69..1302b76ca 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -201,7 +201,7 @@ static mips_def_t mips_defs[] = (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13), .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP | ASE_MT, }, -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) { .name = "R4000", .CP0_PRid = 0x00000400, @@ -437,7 +437,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask; env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask; env->CP0_SRSCtl = def->CP0_SRSCtl; -#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) +#if defined(TARGET_MIPS64) if (def->insn_flags & ISA_MIPS3) { env->hflags |= MIPS_HFLAG_64; -- cgit v1.2.3 From 7df526e317fe4c193589bfdf2ee06255325344cc Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 9 Nov 2007 17:52:11 +0000 Subject: Move kernel loader parameters from the cpu state to being board specific. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3557 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 45 ++++++++++++++++++++++++++------------------- hw/mips_mipssim.c | 33 ++++++++++++++++++++------------- hw/mips_r4k.c | 48 ++++++++++++++++++++++++++---------------------- target-mips/cpu.h | 5 ----- 4 files changed, 72 insertions(+), 59 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 9d099a053..3b9170a48 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -59,6 +59,13 @@ typedef struct { static PITState *pit; +static struct _loaderparams { + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} loaderparams; + /* Malta FPGA */ static void malta_fpga_update_display(void *opaque) { @@ -534,8 +541,8 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */ stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ - stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */ - stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ + stl_raw(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */ + stl_raw(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */ /* Load BAR registers as done by YAMON */ stl_raw(p++, 0x3c09b400); /* lui t1, 0xb400 */ @@ -675,48 +682,48 @@ static int64_t load_kernel (CPUState *env) long initrd_size; ram_addr_t initrd_offset; - if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, + if (load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_entry, &kernel_low, &kernel_high) < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", - env->kernel_filename); + loaderparams.kernel_filename); exit(1); } /* load initrd */ initrd_size = 0; initrd_offset = 0; - if (env->initrd_filename) { - initrd_size = get_image_size (env->initrd_filename); + if (loaderparams.initrd_filename) { + initrd_size = get_image_size (loaderparams.initrd_filename); if (initrd_size > 0) { initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; - if (initrd_offset + initrd_size > env->ram_size) { + if (initrd_offset + initrd_size > ram_size) { fprintf(stderr, "qemu: memory too small for initial ram disk '%s'\n", - env->initrd_filename); + loaderparams.initrd_filename); exit(1); } - initrd_size = load_image(env->initrd_filename, + initrd_size = load_image(loaderparams.initrd_filename, phys_ram_base + initrd_offset); } if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - env->initrd_filename); + loaderparams.initrd_filename); exit(1); } } /* Store command line. */ - prom_set(index++, env->kernel_filename); + prom_set(index++, loaderparams.kernel_filename); if (initrd_size > 0) prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s", PHYS_TO_VIRT(initrd_offset), initrd_size, - env->kernel_cmdline); + loaderparams.kernel_cmdline); else - prom_set(index++, env->kernel_cmdline); + prom_set(index++, loaderparams.kernel_cmdline); /* Setup minimum environment variables */ prom_set(index++, "memsize"); - prom_set(index++, "%i", env->ram_size); + prom_set(index++, "%i", loaderparams.ram_size); prom_set(index++, "modetty0"); prom_set(index++, "38400n8r"); prom_set(index++, NULL); @@ -733,7 +740,7 @@ static void main_cpu_reset(void *opaque) /* The bootload does not need to be rewritten as it is located in a read only location. The kernel location and the arguments table location does not change. */ - if (env->kernel_filename) { + if (loaderparams.kernel_filename) { env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); load_kernel (env); } @@ -818,10 +825,10 @@ void mips_malta_init (int ram_size, int vga_ram_size, const char *boot_device, /* If a kernel image has been specified, write a small bootloader to the flash location. */ if (kernel_filename) { - env->ram_size = ram_size; - env->kernel_filename = kernel_filename; - env->kernel_cmdline = kernel_cmdline; - env->initrd_filename = initrd_filename; + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = kernel_filename; + loaderparams.kernel_cmdline = kernel_cmdline; + loaderparams.initrd_filename = initrd_filename; kernel_entry = load_kernel(env); env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); write_bootloader(env, bios_offset, kernel_entry); diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 11bad5970..08e4b0b01 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -40,6 +40,13 @@ #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) +static struct _loaderparams { + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} loaderparams; + static void load_kernel (CPUState *env) { int64_t entry, kernel_low, kernel_high; @@ -47,7 +54,7 @@ static void load_kernel (CPUState *env) long initrd_size; ram_addr_t initrd_offset; - kernel_size = load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, + kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND, &entry, &kernel_low, &kernel_high); if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) @@ -55,29 +62,29 @@ static void load_kernel (CPUState *env) env->PC[env->current_tc] = entry; } else { fprintf(stderr, "qemu: could not load kernel '%s'\n", - env->kernel_filename); + loaderparams.kernel_filename); exit(1); } /* load initrd */ initrd_size = 0; initrd_offset = 0; - if (env->initrd_filename) { - initrd_size = get_image_size (env->initrd_filename); + if (loaderparams.initrd_filename) { + initrd_size = get_image_size (loaderparams.initrd_filename); if (initrd_size > 0) { initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; - if (initrd_offset + initrd_size > env->ram_size) { + if (initrd_offset + initrd_size > loaderparams.ram_size) { fprintf(stderr, "qemu: memory too small for initial ram disk '%s'\n", - env->initrd_filename); + loaderparams.initrd_filename); exit(1); } - initrd_size = load_image(env->initrd_filename, + initrd_size = load_image(loaderparams.initrd_filename, phys_ram_base + initrd_offset); } if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - env->initrd_filename); + loaderparams.initrd_filename); exit(1); } } @@ -89,7 +96,7 @@ static void main_cpu_reset(void *opaque) cpu_reset(env); cpu_mips_register(env, NULL); - if (env->kernel_filename) + if (loaderparams.kernel_filename) load_kernel (env); } @@ -144,10 +151,10 @@ mips_mipssim_init (int ram_size, int vga_ram_size, const char *boot_device, } if (kernel_filename) { - env->ram_size = ram_size; - env->kernel_filename = kernel_filename; - env->kernel_cmdline = kernel_cmdline; - env->initrd_filename = initrd_filename; + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = kernel_filename; + loaderparams.kernel_cmdline = kernel_cmdline; + loaderparams.initrd_filename = initrd_filename; load_kernel(env); } diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index dfcf86758..e4817e6b7 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -36,6 +36,13 @@ static PITState *pit; /* PIT i8254 */ /*i8254 PIT is attached to the IRQ0 at PIC i8259 */ +static struct _loaderparams { + int ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; +} loaderparams; + static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, uint32_t val) { @@ -64,16 +71,13 @@ static CPUReadMemoryFunc *mips_qemu_read[] = { static int mips_qemu_iomemtype = 0; -static void load_kernel (CPUState *env, int ram_size, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) +static void load_kernel (CPUState *env) { int64_t entry, kernel_low, kernel_high; long kernel_size, initrd_size; ram_addr_t initrd_offset; - kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, + kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND, &entry, &kernel_low, &kernel_high); if (kernel_size >= 0) { if ((entry & ~0x7fffffffULL) == 0x80000000) @@ -81,29 +85,29 @@ static void load_kernel (CPUState *env, int ram_size, env->PC[env->current_tc] = entry; } else { fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + loaderparams.kernel_filename); exit(1); } /* load initrd */ initrd_size = 0; initrd_offset = 0; - if (initrd_filename) { - initrd_size = get_image_size (initrd_filename); + if (loaderparams.initrd_filename) { + initrd_size = get_image_size (loaderparams.initrd_filename); if (initrd_size > 0) { initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; if (initrd_offset + initrd_size > ram_size) { fprintf(stderr, "qemu: memory too small for initial ram disk '%s'\n", - initrd_filename); + loaderparams.initrd_filename); exit(1); } - initrd_size = load_image(initrd_filename, + initrd_size = load_image(loaderparams.initrd_filename, phys_ram_base + initrd_offset); } if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + loaderparams.initrd_filename); exit(1); } } @@ -115,10 +119,12 @@ static void load_kernel (CPUState *env, int ram_size, "rd_start=0x" TARGET_FMT_lx " rd_size=%li ", PHYS_TO_VIRT((uint32_t)initrd_offset), initrd_size); - strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline); + strcpy (phys_ram_base + (16 << 20) - 256 + ret, + loaderparams.kernel_cmdline); } else { - strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); + strcpy (phys_ram_base + (16 << 20) - 256, + loaderparams.kernel_cmdline); } *(int32_t *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); @@ -131,9 +137,8 @@ static void main_cpu_reset(void *opaque) cpu_reset(env); cpu_mips_register(env, NULL); - if (env->kernel_filename) - load_kernel (env, env->ram_size, env->kernel_filename, - env->kernel_cmdline, env->initrd_filename); + if (loaderparams.kernel_filename) + load_kernel (env); } static @@ -194,12 +199,11 @@ void mips_r4k_init (int ram_size, int vga_ram_size, const char *boot_device, } if (kernel_filename) { - load_kernel (env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename); - env->ram_size = ram_size; - env->kernel_filename = kernel_filename; - env->kernel_cmdline = kernel_cmdline; - env->initrd_filename = initrd_filename; + loaderparams.ram_size = ram_size; + loaderparams.kernel_filename = kernel_filename; + loaderparams.kernel_cmdline = kernel_cmdline; + loaderparams.initrd_filename = initrd_filename; + load_kernel (env); } /* Init CPU internal devices */ diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 5fbb90e67..1c850c782 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -456,11 +456,6 @@ struct CPUMIPSState { CPU_COMMON - int ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; - mips_def_t *cpu_model; #ifndef CONFIG_USER_ONLY void *irq[8]; -- cgit v1.2.3 From e3d7e8431eb4c6c20dae7e45c6e0fa223003ecdd Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 9 Nov 2007 18:17:50 +0000 Subject: Fix typo, spotted by Samuel Thibault. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3558 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/rtl8139.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index a970eb3a9..dc06f6617 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -1464,7 +1464,7 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ - uint32 mask = 0x4cff; + uint32_t mask = 0x4cff; if (1 || !rtl8139_config_writeable(s)) { -- cgit v1.2.3 From 406f82e8338624179130cdc91bbfb2b33cd98211 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 9 Nov 2007 19:08:43 +0000 Subject: More CPU definitions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3559 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 106 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 4 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index cc8402cad..12b5c96e2 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3510,6 +3510,13 @@ static const sparc_def_t sparc_defs[] = { .mmu_version = 0, }, #else + { + .name = "Fujitsu MB86900", + .iu_version = 0x00 << 24, /* Impl 0, ver 0 */ + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */ + .mmu_bm = 0x00004000, + }, { .name = "Fujitsu MB86904", .iu_version = 0x04 << 24, /* Impl 0, ver 4 */ @@ -3524,6 +3531,34 @@ static const sparc_def_t sparc_defs[] = { .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */ .mmu_bm = 0x00004000, }, + { + .name = "LSI L64811", + .iu_version = 0x10 << 24, /* Impl 1, ver 0 */ + .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + }, + { + .name = "Cypress CY7C601", + .iu_version = 0x11 << 24, /* Impl 1, ver 1 */ + .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + }, + { + .name = "Cypress CY7C611", + .iu_version = 0x13 << 24, /* Impl 1, ver 3 */ + .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + }, + { + .name = "TI SuperSparc II", + .iu_version = 0x40000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + }, { .name = "TI MicroSparc I", .iu_version = 0x41000000, @@ -3532,17 +3567,80 @@ static const sparc_def_t sparc_defs[] = { .mmu_bm = 0x00004000, }, { - .name = "TI SuperSparc II", - .iu_version = 0x40000000, + .name = "TI MicroSparc II", + .iu_version = 0x42000000, + .fpu_version = 4 << 17, + .mmu_version = 0x02000000, + .mmu_bm = 0x00004000, + }, + { + .name = "TI MicroSparc IIep", + .iu_version = 0x42000000, + .fpu_version = 4 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00004000, + }, + { + .name = "TI SuperSparc 51", + .iu_version = 0x43000000, .fpu_version = 0 << 17, .mmu_version = 0x04000000, .mmu_bm = 0x00002000, }, { - .name = "Ross RT620", + .name = "TI SuperSparc 61", + .iu_version = 0x44000000, + .fpu_version = 0 << 17, + .mmu_version = 0x04000000, + .mmu_bm = 0x00002000, + }, + { + .name = "Ross RT625", .iu_version = 0x1e000000, .fpu_version = 1 << 17, - .mmu_version = 0x17000000, + .mmu_version = 0x1e000000, + .mmu_bm = 0x00004000, + }, + { + .name = "Ross RT620", + .iu_version = 0x1f000000, + .fpu_version = 1 << 17, + .mmu_version = 0x1f000000, + .mmu_bm = 0x00004000, + }, + { + .name = "BIT B5010", + .iu_version = 0x20000000, + .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */ + .mmu_version = 0x20000000, + .mmu_bm = 0x00004000, + }, + { + .name = "Matsushita MN10501", + .iu_version = 0x50000000, + .fpu_version = 0 << 17, + .mmu_version = 0x50000000, + .mmu_bm = 0x00004000, + }, + { + .name = "Weitek W8601", + .iu_version = 0x90 << 24, /* Impl 9, ver 0 */ + .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */ + .mmu_version = 0x10 << 24, + .mmu_bm = 0x00004000, + }, + { + .name = "LEON2", + .iu_version = 0xf2000000, + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0xf2000000, + .mmu_bm = 0x00004000, + }, + { + .name = "LEON3", + .iu_version = 0xf3000000, + .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ + .mmu_version = 0xf3000000, .mmu_bm = 0x00004000, }, #endif -- cgit v1.2.3 From 8f6f6026f14581fe09b65c2b31c0052577bf5b2f Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 9 Nov 2007 23:09:41 +0000 Subject: Use FORCE_RET, scrap RETURN which was implemented in target-specific code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3560 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/exec.h | 6 - target-mips/fop_template.c | 16 +- target-mips/op.c | 742 ++++++++++++++++++++++----------------------- target-mips/op_mem.c | 58 ++-- target-mips/op_template.c | 20 +- 5 files changed, 418 insertions(+), 424 deletions(-) diff --git a/target-mips/exec.h b/target-mips/exec.h index 6a05f86c7..307049ed3 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -43,12 +43,6 @@ register target_ulong T2 asm(AREG3); #define WTH2 (env->fpu->ft2.w[!FP_ENDIAN_IDX]) #endif -#if defined (DEBUG_OP) -# define RETURN() __asm__ __volatile__("nop" : : : "memory"); -#else -# define RETURN() __asm__ __volatile__("" : : : "memory"); -#endif - #include "cpu.h" #include "exec-all.h" diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index 25b2ca7a5..8ee052513 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -25,14 +25,14 @@ void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ treg = env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX]; \ - RETURN(); \ + FORCE_RET(); \ } #define OP_WSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \ - RETURN(); \ + FORCE_RET(); \ } /* WT0 = FREG.w: op_load_fpr_WT0_fprFREG */ @@ -54,7 +54,7 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) else \ treg = (uint64_t)(env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \ - RETURN(); \ + FORCE_RET(); \ } #define OP_DSTORE_FREG(treg, tregname, FREG) \ @@ -66,7 +66,7 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \ } \ - RETURN(); \ + FORCE_RET(); \ } OP_DLOAD_FREG(DT0, DT0_fpr, FREG) @@ -82,14 +82,14 @@ OP_DSTORE_FREG(DT2, DT2_fpr, FREG) void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ treg = env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX]; \ - RETURN(); \ + FORCE_RET(); \ } #define OP_PSSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \ - RETURN(); \ + FORCE_RET(); \ } OP_PSLOAD_FREG(WTH0, WTH0_fpr, FREG) @@ -109,12 +109,12 @@ OP_PSSTORE_FREG(WTH2, WTH2_fpr, FREG) void glue(op_set, tregname)(void) \ { \ treg = PARAM1; \ - RETURN(); \ + FORCE_RET(); \ } \ void glue(op_reset, tregname)(void) \ { \ treg = 0; \ - RETURN(); \ + FORCE_RET(); \ } SET_RESET(WT0, _WT0) diff --git a/target-mips/op.c b/target-mips/op.c index f5796c87e..4b3e01b4b 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -250,31 +250,31 @@ void op_dup_T0 (void) { T2 = T0; - RETURN(); + FORCE_RET(); } void op_load_HI (void) { T0 = env->HI[PARAM1][env->current_tc]; - RETURN(); + FORCE_RET(); } void op_store_HI (void) { env->HI[PARAM1][env->current_tc] = T0; - RETURN(); + FORCE_RET(); } void op_load_LO (void) { T0 = env->LO[PARAM1][env->current_tc]; - RETURN(); + FORCE_RET(); } void op_store_LO (void) { env->LO[PARAM1][env->current_tc] = T0; - RETURN(); + FORCE_RET(); } /* Load and store */ @@ -308,14 +308,14 @@ void op_addr_add (void) else #endif T0 += T1; - RETURN(); + FORCE_RET(); } /* Arithmetic */ void op_add (void) { T0 = (int32_t)((int32_t)T0 + (int32_t)T1); - RETURN(); + FORCE_RET(); } void op_addo (void) @@ -329,13 +329,13 @@ void op_addo (void) CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); } T0 = (int32_t)T0; - RETURN(); + FORCE_RET(); } void op_sub (void) { T0 = (int32_t)((int32_t)T0 - (int32_t)T1); - RETURN(); + FORCE_RET(); } void op_subo (void) @@ -349,20 +349,20 @@ void op_subo (void) CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); } T0 = (int32_t)T0; - RETURN(); + FORCE_RET(); } void op_mul (void) { T0 = (int32_t)((int32_t)T0 * (int32_t)T1); - RETURN(); + FORCE_RET(); } #if HOST_LONG_BITS < 64 void op_div (void) { CALL_FROM_TB0(do_div); - RETURN(); + FORCE_RET(); } #else void op_div (void) @@ -371,7 +371,7 @@ void op_div (void) env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1); env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1); } - RETURN(); + FORCE_RET(); } #endif @@ -381,7 +381,7 @@ void op_divu (void) env->LO[0][env->current_tc] = (int32_t)((uint32_t)T0 / (uint32_t)T1); env->HI[0][env->current_tc] = (int32_t)((uint32_t)T0 % (uint32_t)T1); } - RETURN(); + FORCE_RET(); } #if defined(TARGET_MIPS64) @@ -389,7 +389,7 @@ void op_divu (void) void op_dadd (void) { T0 += T1; - RETURN(); + FORCE_RET(); } void op_daddo (void) @@ -402,13 +402,13 @@ void op_daddo (void) /* operands of same sign, result different sign */ CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); } - RETURN(); + FORCE_RET(); } void op_dsub (void) { T0 -= T1; - RETURN(); + FORCE_RET(); } void op_dsubo (void) @@ -421,27 +421,27 @@ void op_dsubo (void) /* operands of different sign, first operand and result different sign */ CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); } - RETURN(); + FORCE_RET(); } void op_dmul (void) { T0 = (int64_t)T0 * (int64_t)T1; - RETURN(); + FORCE_RET(); } /* Those might call libgcc functions. */ void op_ddiv (void) { do_ddiv(); - RETURN(); + FORCE_RET(); } #if TARGET_LONG_BITS > HOST_LONG_BITS void op_ddivu (void) { do_ddivu(); - RETURN(); + FORCE_RET(); } #else void op_ddivu (void) @@ -450,7 +450,7 @@ void op_ddivu (void) env->LO[0][env->current_tc] = T0 / T1; env->HI[0][env->current_tc] = T0 % T1; } - RETURN(); + FORCE_RET(); } #endif #endif /* TARGET_MIPS64 */ @@ -459,43 +459,43 @@ void op_ddivu (void) void op_and (void) { T0 &= T1; - RETURN(); + FORCE_RET(); } void op_nor (void) { T0 = ~(T0 | T1); - RETURN(); + FORCE_RET(); } void op_or (void) { T0 |= T1; - RETURN(); + FORCE_RET(); } void op_xor (void) { T0 ^= T1; - RETURN(); + FORCE_RET(); } void op_sll (void) { T0 = (int32_t)((uint32_t)T0 << T1); - RETURN(); + FORCE_RET(); } void op_sra (void) { T0 = (int32_t)((int32_t)T0 >> T1); - RETURN(); + FORCE_RET(); } void op_srl (void) { T0 = (int32_t)((uint32_t)T0 >> T1); - RETURN(); + FORCE_RET(); } void op_rotr (void) @@ -506,25 +506,25 @@ void op_rotr (void) tmp = (int32_t)((uint32_t)T0 << (0x20 - T1)); T0 = (int32_t)((uint32_t)T0 >> T1) | tmp; } - RETURN(); + FORCE_RET(); } void op_sllv (void) { T0 = (int32_t)((uint32_t)T1 << ((uint32_t)T0 & 0x1F)); - RETURN(); + FORCE_RET(); } void op_srav (void) { T0 = (int32_t)((int32_t)T1 >> (T0 & 0x1F)); - RETURN(); + FORCE_RET(); } void op_srlv (void) { T0 = (int32_t)((uint32_t)T1 >> (T0 & 0x1F)); - RETURN(); + FORCE_RET(); } void op_rotrv (void) @@ -537,19 +537,19 @@ void op_rotrv (void) T0 = (int32_t)((uint32_t)T1 >> T0) | tmp; } else T0 = T1; - RETURN(); + FORCE_RET(); } void op_clo (void) { T0 = clo32(T0); - RETURN(); + FORCE_RET(); } void op_clz (void) { T0 = clz32(T0); - RETURN(); + FORCE_RET(); } #if defined(TARGET_MIPS64) @@ -559,85 +559,85 @@ void op_clz (void) void op_dsll (void) { CALL_FROM_TB0(do_dsll); - RETURN(); + FORCE_RET(); } void op_dsll32 (void) { CALL_FROM_TB0(do_dsll32); - RETURN(); + FORCE_RET(); } void op_dsra (void) { CALL_FROM_TB0(do_dsra); - RETURN(); + FORCE_RET(); } void op_dsra32 (void) { CALL_FROM_TB0(do_dsra32); - RETURN(); + FORCE_RET(); } void op_dsrl (void) { CALL_FROM_TB0(do_dsrl); - RETURN(); + FORCE_RET(); } void op_dsrl32 (void) { CALL_FROM_TB0(do_dsrl32); - RETURN(); + FORCE_RET(); } void op_drotr (void) { CALL_FROM_TB0(do_drotr); - RETURN(); + FORCE_RET(); } void op_drotr32 (void) { CALL_FROM_TB0(do_drotr32); - RETURN(); + FORCE_RET(); } void op_dsllv (void) { CALL_FROM_TB0(do_dsllv); - RETURN(); + FORCE_RET(); } void op_dsrav (void) { CALL_FROM_TB0(do_dsrav); - RETURN(); + FORCE_RET(); } void op_dsrlv (void) { CALL_FROM_TB0(do_dsrlv); - RETURN(); + FORCE_RET(); } void op_drotrv (void) { CALL_FROM_TB0(do_drotrv); - RETURN(); + FORCE_RET(); } void op_dclo (void) { CALL_FROM_TB0(do_dclo); - RETURN(); + FORCE_RET(); } void op_dclz (void) { CALL_FROM_TB0(do_dclz); - RETURN(); + FORCE_RET(); } #else /* TARGET_LONG_BITS > HOST_LONG_BITS */ @@ -645,37 +645,37 @@ void op_dclz (void) void op_dsll (void) { T0 = T0 << T1; - RETURN(); + FORCE_RET(); } void op_dsll32 (void) { T0 = T0 << (T1 + 32); - RETURN(); + FORCE_RET(); } void op_dsra (void) { T0 = (int64_t)T0 >> T1; - RETURN(); + FORCE_RET(); } void op_dsra32 (void) { T0 = (int64_t)T0 >> (T1 + 32); - RETURN(); + FORCE_RET(); } void op_dsrl (void) { T0 = T0 >> T1; - RETURN(); + FORCE_RET(); } void op_dsrl32 (void) { T0 = T0 >> (T1 + 32); - RETURN(); + FORCE_RET(); } void op_drotr (void) @@ -686,7 +686,7 @@ void op_drotr (void) tmp = T0 << (0x40 - T1); T0 = (T0 >> T1) | tmp; } - RETURN(); + FORCE_RET(); } void op_drotr32 (void) @@ -697,25 +697,25 @@ void op_drotr32 (void) tmp = T0 << (0x40 - (32 + T1)); T0 = (T0 >> (32 + T1)) | tmp; } - RETURN(); + FORCE_RET(); } void op_dsllv (void) { T0 = T1 << (T0 & 0x3F); - RETURN(); + FORCE_RET(); } void op_dsrav (void) { T0 = (int64_t)T1 >> (T0 & 0x3F); - RETURN(); + FORCE_RET(); } void op_dsrlv (void) { T0 = T1 >> (T0 & 0x3F); - RETURN(); + FORCE_RET(); } void op_drotrv (void) @@ -728,19 +728,19 @@ void op_drotrv (void) T0 = (T1 >> T0) | tmp; } else T0 = T1; - RETURN(); + FORCE_RET(); } void op_dclo (void) { T0 = clo64(T0); - RETURN(); + FORCE_RET(); } void op_dclz (void) { T0 = clz64(T0); - RETURN(); + FORCE_RET(); } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ #endif /* TARGET_MIPS64 */ @@ -750,37 +750,37 @@ void op_dclz (void) void op_mult (void) { CALL_FROM_TB0(do_mult); - RETURN(); + FORCE_RET(); } void op_multu (void) { CALL_FROM_TB0(do_multu); - RETURN(); + FORCE_RET(); } void op_madd (void) { CALL_FROM_TB0(do_madd); - RETURN(); + FORCE_RET(); } void op_maddu (void) { CALL_FROM_TB0(do_maddu); - RETURN(); + FORCE_RET(); } void op_msub (void) { CALL_FROM_TB0(do_msub); - RETURN(); + FORCE_RET(); } void op_msubu (void) { CALL_FROM_TB0(do_msubu); - RETURN(); + FORCE_RET(); } #else /* TARGET_LONG_BITS > HOST_LONG_BITS */ @@ -800,13 +800,13 @@ static always_inline void set_HILO (uint64_t HILO) void op_mult (void) { set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); - RETURN(); + FORCE_RET(); } void op_multu (void) { set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); - RETURN(); + FORCE_RET(); } void op_madd (void) @@ -815,7 +815,7 @@ void op_madd (void) tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() + tmp); - RETURN(); + FORCE_RET(); } void op_maddu (void) @@ -824,7 +824,7 @@ void op_maddu (void) tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); set_HILO(get_HILO() + tmp); - RETURN(); + FORCE_RET(); } void op_msub (void) @@ -833,7 +833,7 @@ void op_msub (void) tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); set_HILO((int64_t)get_HILO() - tmp); - RETURN(); + FORCE_RET(); } void op_msubu (void) @@ -842,7 +842,7 @@ void op_msubu (void) tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1); set_HILO(get_HILO() - tmp); - RETURN(); + FORCE_RET(); } #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */ @@ -850,13 +850,13 @@ void op_msubu (void) void op_dmult (void) { CALL_FROM_TB4(muls64, &(env->LO[0][env->current_tc]), &(env->HI[0][env->current_tc]), T0, T1); - RETURN(); + FORCE_RET(); } void op_dmultu (void) { CALL_FROM_TB4(mulu64, &(env->LO[0][env->current_tc]), &(env->HI[0][env->current_tc]), T0, T1); - RETURN(); + FORCE_RET(); } #endif @@ -865,28 +865,28 @@ void op_movn (void) { if (T1 != 0) env->gpr[PARAM1][env->current_tc] = T0; - RETURN(); + FORCE_RET(); } void op_movz (void) { if (T1 == 0) env->gpr[PARAM1][env->current_tc] = T0; - RETURN(); + FORCE_RET(); } void op_movf (void) { if (!(env->fpu->fcr31 & PARAM1)) T0 = T1; - RETURN(); + FORCE_RET(); } void op_movt (void) { if (env->fpu->fcr31 & PARAM1) T0 = T1; - RETURN(); + FORCE_RET(); } /* Tests */ @@ -898,7 +898,7 @@ void glue(op_, name) (void) \ } else { \ T0 = 0; \ } \ - RETURN(); \ + FORCE_RET(); \ } OP_COND(eq, T0 == T1); @@ -916,45 +916,45 @@ OP_COND(ltz, (target_long)T0 < 0); void OPPROTO op_goto_tb0(void) { GOTO_TB(op_goto_tb0, PARAM1, 0); - RETURN(); + FORCE_RET(); } void OPPROTO op_goto_tb1(void) { GOTO_TB(op_goto_tb1, PARAM1, 1); - RETURN(); + FORCE_RET(); } /* Branch to register */ void op_save_breg_target (void) { env->btarget = T2; - RETURN(); + FORCE_RET(); } void op_restore_breg_target (void) { T2 = env->btarget; - RETURN(); + FORCE_RET(); } void op_breg (void) { env->PC[env->current_tc] = T2; - RETURN(); + FORCE_RET(); } void op_save_btarget (void) { env->btarget = PARAM1; - RETURN(); + FORCE_RET(); } #if defined(TARGET_MIPS64) void op_save_btarget64 (void) { env->btarget = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; - RETURN(); + FORCE_RET(); } #endif @@ -962,111 +962,111 @@ void op_save_btarget64 (void) void op_set_bcond (void) { T2 = T0; - RETURN(); + FORCE_RET(); } void op_save_bcond (void) { env->bcond = T2; - RETURN(); + FORCE_RET(); } void op_restore_bcond (void) { T2 = env->bcond; - RETURN(); + FORCE_RET(); } void op_jnz_T2 (void) { if (T2) GOTO_LABEL_PARAM(1); - RETURN(); + FORCE_RET(); } /* CP0 functions */ void op_mfc0_index (void) { T0 = env->CP0_Index; - RETURN(); + FORCE_RET(); } void op_mfc0_mvpcontrol (void) { T0 = env->mvp->CP0_MVPControl; - RETURN(); + FORCE_RET(); } void op_mfc0_mvpconf0 (void) { T0 = env->mvp->CP0_MVPConf0; - RETURN(); + FORCE_RET(); } void op_mfc0_mvpconf1 (void) { T0 = env->mvp->CP0_MVPConf1; - RETURN(); + FORCE_RET(); } void op_mfc0_random (void) { CALL_FROM_TB0(do_mfc0_random); - RETURN(); + FORCE_RET(); } void op_mfc0_vpecontrol (void) { T0 = env->CP0_VPEControl; - RETURN(); + FORCE_RET(); } void op_mfc0_vpeconf0 (void) { T0 = env->CP0_VPEConf0; - RETURN(); + FORCE_RET(); } void op_mfc0_vpeconf1 (void) { T0 = env->CP0_VPEConf1; - RETURN(); + FORCE_RET(); } void op_mfc0_yqmask (void) { T0 = env->CP0_YQMask; - RETURN(); + FORCE_RET(); } void op_mfc0_vpeschedule (void) { T0 = env->CP0_VPESchedule; - RETURN(); + FORCE_RET(); } void op_mfc0_vpeschefback (void) { T0 = env->CP0_VPEScheFBack; - RETURN(); + FORCE_RET(); } void op_mfc0_vpeopt (void) { T0 = env->CP0_VPEOpt; - RETURN(); + FORCE_RET(); } void op_mfc0_entrylo0 (void) { T0 = (int32_t)env->CP0_EntryLo0; - RETURN(); + FORCE_RET(); } void op_mfc0_tcstatus (void) { T0 = env->CP0_TCStatus[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_mftc0_tcstatus(void) @@ -1074,13 +1074,13 @@ void op_mftc0_tcstatus(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->CP0_TCStatus[other_tc]; - RETURN(); + FORCE_RET(); } void op_mfc0_tcbind (void) { T0 = env->CP0_TCBind[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_mftc0_tcbind(void) @@ -1088,13 +1088,13 @@ void op_mftc0_tcbind(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->CP0_TCBind[other_tc]; - RETURN(); + FORCE_RET(); } void op_mfc0_tcrestart (void) { T0 = env->PC[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_mftc0_tcrestart(void) @@ -1102,13 +1102,13 @@ void op_mftc0_tcrestart(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->PC[other_tc]; - RETURN(); + FORCE_RET(); } void op_mfc0_tchalt (void) { T0 = env->CP0_TCHalt[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_mftc0_tchalt(void) @@ -1116,13 +1116,13 @@ void op_mftc0_tchalt(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->CP0_TCHalt[other_tc]; - RETURN(); + FORCE_RET(); } void op_mfc0_tccontext (void) { T0 = env->CP0_TCContext[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_mftc0_tccontext(void) @@ -1130,13 +1130,13 @@ void op_mftc0_tccontext(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->CP0_TCContext[other_tc]; - RETURN(); + FORCE_RET(); } void op_mfc0_tcschedule (void) { T0 = env->CP0_TCSchedule[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_mftc0_tcschedule(void) @@ -1144,13 +1144,13 @@ void op_mftc0_tcschedule(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->CP0_TCSchedule[other_tc]; - RETURN(); + FORCE_RET(); } void op_mfc0_tcschefback (void) { T0 = env->CP0_TCScheFBack[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_mftc0_tcschefback(void) @@ -1158,91 +1158,91 @@ void op_mftc0_tcschefback(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->CP0_TCScheFBack[other_tc]; - RETURN(); + FORCE_RET(); } void op_mfc0_entrylo1 (void) { T0 = (int32_t)env->CP0_EntryLo1; - RETURN(); + FORCE_RET(); } void op_mfc0_context (void) { T0 = (int32_t)env->CP0_Context; - RETURN(); + FORCE_RET(); } void op_mfc0_pagemask (void) { T0 = env->CP0_PageMask; - RETURN(); + FORCE_RET(); } void op_mfc0_pagegrain (void) { T0 = env->CP0_PageGrain; - RETURN(); + FORCE_RET(); } void op_mfc0_wired (void) { T0 = env->CP0_Wired; - RETURN(); + FORCE_RET(); } void op_mfc0_srsconf0 (void) { T0 = env->CP0_SRSConf0; - RETURN(); + FORCE_RET(); } void op_mfc0_srsconf1 (void) { T0 = env->CP0_SRSConf1; - RETURN(); + FORCE_RET(); } void op_mfc0_srsconf2 (void) { T0 = env->CP0_SRSConf2; - RETURN(); + FORCE_RET(); } void op_mfc0_srsconf3 (void) { T0 = env->CP0_SRSConf3; - RETURN(); + FORCE_RET(); } void op_mfc0_srsconf4 (void) { T0 = env->CP0_SRSConf4; - RETURN(); + FORCE_RET(); } void op_mfc0_hwrena (void) { T0 = env->CP0_HWREna; - RETURN(); + FORCE_RET(); } void op_mfc0_badvaddr (void) { T0 = (int32_t)env->CP0_BadVAddr; - RETURN(); + FORCE_RET(); } void op_mfc0_count (void) { CALL_FROM_TB0(do_mfc0_count); - RETURN(); + FORCE_RET(); } void op_mfc0_entryhi (void) { T0 = (int32_t)env->CP0_EntryHi; - RETURN(); + FORCE_RET(); } void op_mftc0_entryhi(void) @@ -1250,19 +1250,19 @@ void op_mftc0_entryhi(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff); - RETURN(); + FORCE_RET(); } void op_mfc0_compare (void) { T0 = env->CP0_Compare; - RETURN(); + FORCE_RET(); } void op_mfc0_status (void) { T0 = env->CP0_Status; - RETURN(); + FORCE_RET(); } void op_mftc0_status(void) @@ -1274,115 +1274,115 @@ void op_mftc0_status(void) T0 |= tcstatus & (0xf << CP0TCSt_TCU0); T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU); - RETURN(); + FORCE_RET(); } void op_mfc0_intctl (void) { T0 = env->CP0_IntCtl; - RETURN(); + FORCE_RET(); } void op_mfc0_srsctl (void) { T0 = env->CP0_SRSCtl; - RETURN(); + FORCE_RET(); } void op_mfc0_srsmap (void) { T0 = env->CP0_SRSMap; - RETURN(); + FORCE_RET(); } void op_mfc0_cause (void) { T0 = env->CP0_Cause; - RETURN(); + FORCE_RET(); } void op_mfc0_epc (void) { T0 = (int32_t)env->CP0_EPC; - RETURN(); + FORCE_RET(); } void op_mfc0_prid (void) { T0 = env->CP0_PRid; - RETURN(); + FORCE_RET(); } void op_mfc0_ebase (void) { T0 = env->CP0_EBase; - RETURN(); + FORCE_RET(); } void op_mfc0_config0 (void) { T0 = env->CP0_Config0; - RETURN(); + FORCE_RET(); } void op_mfc0_config1 (void) { T0 = env->CP0_Config1; - RETURN(); + FORCE_RET(); } void op_mfc0_config2 (void) { T0 = env->CP0_Config2; - RETURN(); + FORCE_RET(); } void op_mfc0_config3 (void) { T0 = env->CP0_Config3; - RETURN(); + FORCE_RET(); } void op_mfc0_config6 (void) { T0 = env->CP0_Config6; - RETURN(); + FORCE_RET(); } void op_mfc0_config7 (void) { T0 = env->CP0_Config7; - RETURN(); + FORCE_RET(); } void op_mfc0_lladdr (void) { T0 = (int32_t)env->CP0_LLAddr >> 4; - RETURN(); + FORCE_RET(); } void op_mfc0_watchlo (void) { T0 = (int32_t)env->CP0_WatchLo[PARAM1]; - RETURN(); + FORCE_RET(); } void op_mfc0_watchhi (void) { T0 = env->CP0_WatchHi[PARAM1]; - RETURN(); + FORCE_RET(); } void op_mfc0_xcontext (void) { T0 = (int32_t)env->CP0_XContext; - RETURN(); + FORCE_RET(); } void op_mfc0_framemask (void) { T0 = env->CP0_Framemask; - RETURN(); + FORCE_RET(); } void op_mfc0_debug (void) @@ -1390,7 +1390,7 @@ void op_mfc0_debug (void) T0 = env->CP0_Debug; if (env->hflags & MIPS_HFLAG_DM) T0 |= 1 << CP0DB_DM; - RETURN(); + FORCE_RET(); } void op_mftc0_debug(void) @@ -1401,55 +1401,55 @@ void op_mftc0_debug(void) T0 = (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | (env->CP0_Debug_tcstatus[other_tc] & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); - RETURN(); + FORCE_RET(); } void op_mfc0_depc (void) { T0 = (int32_t)env->CP0_DEPC; - RETURN(); + FORCE_RET(); } void op_mfc0_performance0 (void) { T0 = env->CP0_Performance0; - RETURN(); + FORCE_RET(); } void op_mfc0_taglo (void) { T0 = env->CP0_TagLo; - RETURN(); + FORCE_RET(); } void op_mfc0_datalo (void) { T0 = env->CP0_DataLo; - RETURN(); + FORCE_RET(); } void op_mfc0_taghi (void) { T0 = env->CP0_TagHi; - RETURN(); + FORCE_RET(); } void op_mfc0_datahi (void) { T0 = env->CP0_DataHi; - RETURN(); + FORCE_RET(); } void op_mfc0_errorepc (void) { T0 = (int32_t)env->CP0_ErrorEPC; - RETURN(); + FORCE_RET(); } void op_mfc0_desave (void) { T0 = env->CP0_DESAVE; - RETURN(); + FORCE_RET(); } void op_mtc0_index (void) @@ -1462,7 +1462,7 @@ void op_mtc0_index (void) num <<= 1; } while (tmp); env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 & (num - 1)); - RETURN(); + FORCE_RET(); } void op_mtc0_mvpcontrol (void) @@ -1480,7 +1480,7 @@ void op_mtc0_mvpcontrol (void) // TODO: Enable/disable shared TLB, enable/disable VPEs. env->mvp->CP0_MVPControl = newval; - RETURN(); + FORCE_RET(); } void op_mtc0_vpecontrol (void) @@ -1498,7 +1498,7 @@ void op_mtc0_vpecontrol (void) // TODO: Enable/disable TCs. env->CP0_VPEControl = newval; - RETURN(); + FORCE_RET(); } void op_mtc0_vpeconf0 (void) @@ -1516,7 +1516,7 @@ void op_mtc0_vpeconf0 (void) // TODO: TC exclusive handling due to ERL/EXL. env->CP0_VPEConf0 = newval; - RETURN(); + FORCE_RET(); } void op_mtc0_vpeconf1 (void) @@ -1535,32 +1535,32 @@ void op_mtc0_vpeconf1 (void) // TODO: Handle FPU (CP1) binding. env->CP0_VPEConf1 = newval; - RETURN(); + FORCE_RET(); } void op_mtc0_yqmask (void) { /* Yield qualifier inputs not implemented. */ env->CP0_YQMask = 0x00000000; - RETURN(); + FORCE_RET(); } void op_mtc0_vpeschedule (void) { env->CP0_VPESchedule = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_vpeschefback (void) { env->CP0_VPEScheFBack = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_vpeopt (void) { env->CP0_VPEOpt = T0 & 0x0000ffff; - RETURN(); + FORCE_RET(); } void op_mtc0_entrylo0 (void) @@ -1568,7 +1568,7 @@ void op_mtc0_entrylo0 (void) /* Large physaddr not implemented */ /* 1k pages not implemented */ env->CP0_EntryLo0 = T0 & 0x3FFFFFFF; - RETURN(); + FORCE_RET(); } void op_mtc0_tcstatus (void) @@ -1581,7 +1581,7 @@ void op_mtc0_tcstatus (void) // TODO: Sync with CP0_Status. env->CP0_TCStatus[env->current_tc] = newval; - RETURN(); + FORCE_RET(); } void op_mttc0_tcstatus (void) @@ -1591,7 +1591,7 @@ void op_mttc0_tcstatus (void) // TODO: Sync with CP0_Status. env->CP0_TCStatus[other_tc] = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_tcbind (void) @@ -1603,7 +1603,7 @@ void op_mtc0_tcbind (void) mask |= (1 << CP0TCBd_CurVPE); newval = (env->CP0_TCBind[env->current_tc] & ~mask) | (T0 & mask); env->CP0_TCBind[env->current_tc] = newval; - RETURN(); + FORCE_RET(); } void op_mttc0_tcbind (void) @@ -1616,7 +1616,7 @@ void op_mttc0_tcbind (void) mask |= (1 << CP0TCBd_CurVPE); newval = (env->CP0_TCBind[other_tc] & ~mask) | (T0 & mask); env->CP0_TCBind[other_tc] = newval; - RETURN(); + FORCE_RET(); } void op_mtc0_tcrestart (void) @@ -1625,7 +1625,7 @@ void op_mtc0_tcrestart (void) env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS); env->CP0_LLAddr = 0ULL; /* MIPS16 not implemented. */ - RETURN(); + FORCE_RET(); } void op_mttc0_tcrestart (void) @@ -1636,7 +1636,7 @@ void op_mttc0_tcrestart (void) env->CP0_TCStatus[other_tc] &= ~(1 << CP0TCSt_TDS); env->CP0_LLAddr = 0ULL; /* MIPS16 not implemented. */ - RETURN(); + FORCE_RET(); } void op_mtc0_tchalt (void) @@ -1645,7 +1645,7 @@ void op_mtc0_tchalt (void) // TODO: Halt TC / Restart (if allocated+active) TC. - RETURN(); + FORCE_RET(); } void op_mttc0_tchalt (void) @@ -1655,13 +1655,13 @@ void op_mttc0_tchalt (void) // TODO: Halt TC / Restart (if allocated+active) TC. env->CP0_TCHalt[other_tc] = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_tccontext (void) { env->CP0_TCContext[env->current_tc] = T0; - RETURN(); + FORCE_RET(); } void op_mttc0_tccontext (void) @@ -1669,13 +1669,13 @@ void op_mttc0_tccontext (void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); env->CP0_TCContext[other_tc] = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_tcschedule (void) { env->CP0_TCSchedule[env->current_tc] = T0; - RETURN(); + FORCE_RET(); } void op_mttc0_tcschedule (void) @@ -1683,13 +1683,13 @@ void op_mttc0_tcschedule (void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); env->CP0_TCSchedule[other_tc] = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_tcschefback (void) { env->CP0_TCScheFBack[env->current_tc] = T0; - RETURN(); + FORCE_RET(); } void op_mttc0_tcschefback (void) @@ -1697,7 +1697,7 @@ void op_mttc0_tcschefback (void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); env->CP0_TCScheFBack[other_tc] = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_entrylo1 (void) @@ -1705,20 +1705,20 @@ void op_mtc0_entrylo1 (void) /* Large physaddr not implemented */ /* 1k pages not implemented */ env->CP0_EntryLo1 = T0 & 0x3FFFFFFF; - RETURN(); + FORCE_RET(); } void op_mtc0_context (void) { env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (T0 & ~0x007FFFFF); - RETURN(); + FORCE_RET(); } void op_mtc0_pagemask (void) { /* 1k pages not implemented */ env->CP0_PageMask = T0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); - RETURN(); + FORCE_RET(); } void op_mtc0_pagegrain (void) @@ -1727,55 +1727,55 @@ void op_mtc0_pagegrain (void) /* Large physaddr not implemented */ /* 1k pages not implemented */ env->CP0_PageGrain = 0; - RETURN(); + FORCE_RET(); } void op_mtc0_wired (void) { env->CP0_Wired = T0 % env->tlb->nb_tlb; - RETURN(); + FORCE_RET(); } void op_mtc0_srsconf0 (void) { env->CP0_SRSConf0 |= T0 & env->CP0_SRSConf0_rw_bitmask; - RETURN(); + FORCE_RET(); } void op_mtc0_srsconf1 (void) { env->CP0_SRSConf1 |= T0 & env->CP0_SRSConf1_rw_bitmask; - RETURN(); + FORCE_RET(); } void op_mtc0_srsconf2 (void) { env->CP0_SRSConf2 |= T0 & env->CP0_SRSConf2_rw_bitmask; - RETURN(); + FORCE_RET(); } void op_mtc0_srsconf3 (void) { env->CP0_SRSConf3 |= T0 & env->CP0_SRSConf3_rw_bitmask; - RETURN(); + FORCE_RET(); } void op_mtc0_srsconf4 (void) { env->CP0_SRSConf4 |= T0 & env->CP0_SRSConf4_rw_bitmask; - RETURN(); + FORCE_RET(); } void op_mtc0_hwrena (void) { env->CP0_HWREna = T0 & 0x0000000F; - RETURN(); + FORCE_RET(); } void op_mtc0_count (void) { CALL_FROM_TB2(cpu_mips_store_count, env, T0); - RETURN(); + FORCE_RET(); } void op_mtc0_entryhi (void) @@ -1796,7 +1796,7 @@ void op_mtc0_entryhi (void) /* If the ASID changes, flush qemu's TLB. */ if ((old & 0xFF) != (val & 0xFF)) CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1); - RETURN(); + FORCE_RET(); } void op_mttc0_entryhi(void) @@ -1805,13 +1805,13 @@ void op_mttc0_entryhi(void) env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (T0 & ~0xff); env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (T0 & 0xff); - RETURN(); + FORCE_RET(); } void op_mtc0_compare (void) { CALL_FROM_TB2(cpu_mips_store_compare, env, T0); - RETURN(); + FORCE_RET(); } void op_mtc0_status (void) @@ -1826,7 +1826,7 @@ void op_mtc0_status (void) if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB2(do_mtc0_status_debug, old, val); CALL_FROM_TB1(cpu_mips_update_irq, env); - RETURN(); + FORCE_RET(); } void op_mttc0_status(void) @@ -1839,27 +1839,27 @@ void op_mttc0_status(void) tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((T0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU)); env->CP0_TCStatus[other_tc] = tcstatus; - RETURN(); + FORCE_RET(); } void op_mtc0_intctl (void) { /* vectored interrupts not implemented, no performance counters. */ env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (T0 & 0x000002e0); - RETURN(); + FORCE_RET(); } void op_mtc0_srsctl (void) { uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (T0 & mask); - RETURN(); + FORCE_RET(); } void op_mtc0_srsmap (void) { env->CP0_SRSMap = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_cause (void) @@ -1884,13 +1884,13 @@ void op_mtc0_cause (void) if (T0 & CP0Ca_IP_mask) { CALL_FROM_TB1(cpu_mips_update_irq, env); } - RETURN(); + FORCE_RET(); } void op_mtc0_epc (void) { env->CP0_EPC = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_ebase (void) @@ -1898,20 +1898,20 @@ void op_mtc0_ebase (void) /* vectored interrupts not implemented */ /* Multi-CPU not implemented */ env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000); - RETURN(); + FORCE_RET(); } void op_mtc0_config0 (void) { env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (T0 & 0x00000007); - RETURN(); + FORCE_RET(); } void op_mtc0_config2 (void) { /* tertiary/secondary caches not implemented */ env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); - RETURN(); + FORCE_RET(); } void op_mtc0_watchlo (void) @@ -1919,27 +1919,27 @@ void op_mtc0_watchlo (void) /* Watch exceptions for instructions, data loads, data stores not implemented. */ env->CP0_WatchLo[PARAM1] = (T0 & ~0x7); - RETURN(); + FORCE_RET(); } void op_mtc0_watchhi (void) { env->CP0_WatchHi[PARAM1] = (T0 & 0x40FF0FF8); env->CP0_WatchHi[PARAM1] &= ~(env->CP0_WatchHi[PARAM1] & T0 & 0x7); - RETURN(); + FORCE_RET(); } void op_mtc0_xcontext (void) { target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask); - RETURN(); + FORCE_RET(); } void op_mtc0_framemask (void) { env->CP0_Framemask = T0; /* XXX */ - RETURN(); + FORCE_RET(); } void op_mtc0_debug (void) @@ -1949,7 +1949,7 @@ void op_mtc0_debug (void) env->hflags |= MIPS_HFLAG_DM; else env->hflags &= ~MIPS_HFLAG_DM; - RETURN(); + FORCE_RET(); } void op_mttc0_debug(void) @@ -1960,170 +1960,170 @@ void op_mttc0_debug(void) env->CP0_Debug_tcstatus[other_tc] = T0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) | (T0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); - RETURN(); + FORCE_RET(); } void op_mtc0_depc (void) { env->CP0_DEPC = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_performance0 (void) { env->CP0_Performance0 = T0 & 0x000007ff; - RETURN(); + FORCE_RET(); } void op_mtc0_taglo (void) { env->CP0_TagLo = T0 & 0xFFFFFCF6; - RETURN(); + FORCE_RET(); } void op_mtc0_datalo (void) { env->CP0_DataLo = T0; /* XXX */ - RETURN(); + FORCE_RET(); } void op_mtc0_taghi (void) { env->CP0_TagHi = T0; /* XXX */ - RETURN(); + FORCE_RET(); } void op_mtc0_datahi (void) { env->CP0_DataHi = T0; /* XXX */ - RETURN(); + FORCE_RET(); } void op_mtc0_errorepc (void) { env->CP0_ErrorEPC = T0; - RETURN(); + FORCE_RET(); } void op_mtc0_desave (void) { env->CP0_DESAVE = T0; - RETURN(); + FORCE_RET(); } #if defined(TARGET_MIPS64) void op_dmfc0_yqmask (void) { T0 = env->CP0_YQMask; - RETURN(); + FORCE_RET(); } void op_dmfc0_vpeschedule (void) { T0 = env->CP0_VPESchedule; - RETURN(); + FORCE_RET(); } void op_dmfc0_vpeschefback (void) { T0 = env->CP0_VPEScheFBack; - RETURN(); + FORCE_RET(); } void op_dmfc0_entrylo0 (void) { T0 = env->CP0_EntryLo0; - RETURN(); + FORCE_RET(); } void op_dmfc0_tcrestart (void) { T0 = env->PC[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_dmfc0_tchalt (void) { T0 = env->CP0_TCHalt[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_dmfc0_tccontext (void) { T0 = env->CP0_TCContext[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_dmfc0_tcschedule (void) { T0 = env->CP0_TCSchedule[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_dmfc0_tcschefback (void) { T0 = env->CP0_TCScheFBack[env->current_tc]; - RETURN(); + FORCE_RET(); } void op_dmfc0_entrylo1 (void) { T0 = env->CP0_EntryLo1; - RETURN(); + FORCE_RET(); } void op_dmfc0_context (void) { T0 = env->CP0_Context; - RETURN(); + FORCE_RET(); } void op_dmfc0_badvaddr (void) { T0 = env->CP0_BadVAddr; - RETURN(); + FORCE_RET(); } void op_dmfc0_entryhi (void) { T0 = env->CP0_EntryHi; - RETURN(); + FORCE_RET(); } void op_dmfc0_epc (void) { T0 = env->CP0_EPC; - RETURN(); + FORCE_RET(); } void op_dmfc0_lladdr (void) { T0 = env->CP0_LLAddr >> 4; - RETURN(); + FORCE_RET(); } void op_dmfc0_watchlo (void) { T0 = env->CP0_WatchLo[PARAM1]; - RETURN(); + FORCE_RET(); } void op_dmfc0_xcontext (void) { T0 = env->CP0_XContext; - RETURN(); + FORCE_RET(); } void op_dmfc0_depc (void) { T0 = env->CP0_DEPC; - RETURN(); + FORCE_RET(); } void op_dmfc0_errorepc (void) { T0 = env->CP0_ErrorEPC; - RETURN(); + FORCE_RET(); } #endif /* TARGET_MIPS64 */ @@ -2133,7 +2133,7 @@ void op_mftgpr(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->gpr[PARAM1][other_tc]; - RETURN(); + FORCE_RET(); } void op_mftlo(void) @@ -2141,7 +2141,7 @@ void op_mftlo(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->LO[PARAM1][other_tc]; - RETURN(); + FORCE_RET(); } void op_mfthi(void) @@ -2149,7 +2149,7 @@ void op_mfthi(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->HI[PARAM1][other_tc]; - RETURN(); + FORCE_RET(); } void op_mftacx(void) @@ -2157,7 +2157,7 @@ void op_mftacx(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->ACX[PARAM1][other_tc]; - RETURN(); + FORCE_RET(); } void op_mftdsp(void) @@ -2165,7 +2165,7 @@ void op_mftdsp(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->DSPControl[other_tc]; - RETURN(); + FORCE_RET(); } void op_mttgpr(void) @@ -2173,7 +2173,7 @@ void op_mttgpr(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->gpr[PARAM1][other_tc]; - RETURN(); + FORCE_RET(); } void op_mttlo(void) @@ -2181,7 +2181,7 @@ void op_mttlo(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->LO[PARAM1][other_tc]; - RETURN(); + FORCE_RET(); } void op_mtthi(void) @@ -2189,7 +2189,7 @@ void op_mtthi(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->HI[PARAM1][other_tc]; - RETURN(); + FORCE_RET(); } void op_mttacx(void) @@ -2197,7 +2197,7 @@ void op_mttacx(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->ACX[PARAM1][other_tc]; - RETURN(); + FORCE_RET(); } void op_mttdsp(void) @@ -2205,7 +2205,7 @@ void op_mttdsp(void) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); T0 = env->DSPControl[other_tc]; - RETURN(); + FORCE_RET(); } @@ -2214,7 +2214,7 @@ void op_dmt(void) // TODO T0 = 0; // rt = T0 - RETURN(); + FORCE_RET(); } void op_emt(void) @@ -2222,7 +2222,7 @@ void op_emt(void) // TODO T0 = 0; // rt = T0 - RETURN(); + FORCE_RET(); } void op_dvpe(void) @@ -2230,7 +2230,7 @@ void op_dvpe(void) // TODO T0 = 0; // rt = T0 - RETURN(); + FORCE_RET(); } void op_evpe(void) @@ -2238,7 +2238,7 @@ void op_evpe(void) // TODO T0 = 0; // rt = T0 - RETURN(); + FORCE_RET(); } void op_fork(void) @@ -2246,7 +2246,7 @@ void op_fork(void) // T0 = rt, T1 = rs T0 = 0; // TODO: store to TC register - RETURN(); + FORCE_RET(); } void op_yield(void) @@ -2275,7 +2275,7 @@ void op_yield(void) CALL_FROM_TB1(do_raise_exception, EXCP_THREAD); } T0 = env->CP0_YQMask; - RETURN(); + FORCE_RET(); } /* CP1 functions */ @@ -2289,56 +2289,56 @@ void op_cfc1 (void) { CALL_FROM_TB1(do_cfc1, PARAM1); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_ctc1 (void) { CALL_FROM_TB1(do_ctc1, PARAM1); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_mfc1 (void) { T0 = (int32_t)WT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_mtc1 (void) { WT0 = T0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_dmfc1 (void) { T0 = DT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_dmtc1 (void) { DT0 = T0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_mfhc1 (void) { T0 = (int32_t)WTH0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_mthc1 (void) { WTH0 = T0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } /* Float support. @@ -2352,117 +2352,117 @@ FLOAT_OP(cvtd, s) { CALL_FROM_TB0(do_float_cvtd_s); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtd, w) { CALL_FROM_TB0(do_float_cvtd_w); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtd, l) { CALL_FROM_TB0(do_float_cvtd_l); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtl, d) { CALL_FROM_TB0(do_float_cvtl_d); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtl, s) { CALL_FROM_TB0(do_float_cvtl_s); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtps, s) { WT2 = WT0; WTH2 = WT1; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtps, pw) { CALL_FROM_TB0(do_float_cvtps_pw); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtpw, ps) { CALL_FROM_TB0(do_float_cvtpw_ps); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvts, d) { CALL_FROM_TB0(do_float_cvts_d); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvts, w) { CALL_FROM_TB0(do_float_cvts_w); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvts, l) { CALL_FROM_TB0(do_float_cvts_l); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvts, pl) { CALL_FROM_TB0(do_float_cvts_pl); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvts, pu) { CALL_FROM_TB0(do_float_cvts_pu); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtw, s) { CALL_FROM_TB0(do_float_cvtw_s); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(cvtw, d) { CALL_FROM_TB0(do_float_cvtw_d); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(pll, ps) { DT2 = ((uint64_t)WT0 << 32) | WT1; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(plu, ps) { DT2 = ((uint64_t)WT0 << 32) | WTH1; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(pul, ps) { DT2 = ((uint64_t)WTH0 << 32) | WT1; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(puu, ps) { DT2 = ((uint64_t)WTH0 << 32) | WTH1; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } #define FLOAT_ROUNDOP(op, ttype, stype) \ @@ -2470,7 +2470,7 @@ FLOAT_OP(op ## ttype, stype) \ { \ CALL_FROM_TB0(do_float_ ## op ## ttype ## _ ## stype); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } FLOAT_ROUNDOP(round, l, d) @@ -2499,14 +2499,14 @@ FLOAT_OP(movf, d) if (!(env->fpu->fcr31 & PARAM1)) DT2 = DT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movf, s) { if (!(env->fpu->fcr31 & PARAM1)) WT2 = WT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movf, ps) { @@ -2515,21 +2515,21 @@ FLOAT_OP(movf, ps) WTH2 = WTH0; } DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movt, d) { if (env->fpu->fcr31 & PARAM1) DT2 = DT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movt, s) { if (env->fpu->fcr31 & PARAM1) WT2 = WT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movt, ps) { @@ -2538,21 +2538,21 @@ FLOAT_OP(movt, ps) WTH2 = WTH0; } DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movz, d) { if (!T0) DT2 = DT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movz, s) { if (!T0) WT2 = WT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movz, ps) { @@ -2561,21 +2561,21 @@ FLOAT_OP(movz, ps) WTH2 = WTH0; } DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movn, d) { if (T0) DT2 = DT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movn, s) { if (T0) WT2 = WT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(movn, ps) { @@ -2584,28 +2584,28 @@ FLOAT_OP(movn, ps) WTH2 = WTH0; } DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } /* operations calling helpers, for s, d and ps */ -#define FLOAT_HOP(name) \ +#define FLOAT_HOP(name) \ FLOAT_OP(name, d) \ { \ CALL_FROM_TB0(do_float_ ## name ## _d); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(name, s) \ { \ CALL_FROM_TB0(do_float_ ## name ## _s); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(name, ps) \ { \ CALL_FROM_TB0(do_float_ ## name ## _ps); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } FLOAT_HOP(add) FLOAT_HOP(sub) @@ -2623,13 +2623,13 @@ FLOAT_OP(name, d) \ { \ CALL_FROM_TB0(do_float_ ## name ## _d); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(name, s) \ { \ CALL_FROM_TB0(do_float_ ## name ## _s); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } FLOAT_HOP(rsqrt) FLOAT_HOP(recip) @@ -2641,7 +2641,7 @@ FLOAT_OP(name, ps) \ { \ CALL_FROM_TB0(do_float_ ## name ## _ps); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } FLOAT_HOP(addr) FLOAT_HOP(mulr) @@ -2654,14 +2654,14 @@ FLOAT_OP(name1 ## name2, d) \ FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(name1 ## name2, s) \ { \ FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(name1 ## name2, ps) \ { \ @@ -2670,7 +2670,7 @@ FLOAT_OP(name1 ## name2, ps) \ FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } FLOAT_TERNOP(mul, add) FLOAT_TERNOP(mul, sub) @@ -2684,7 +2684,7 @@ FLOAT_OP(n ## name1 ## name2, d) \ FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ FDT2 ^= 1ULL << 63; \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(n ## name1 ## name2, s) \ { \ @@ -2692,7 +2692,7 @@ FLOAT_OP(n ## name1 ## name2, s) \ FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ FST2 ^= 1 << 31; \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(n ## name1 ## name2, ps) \ { \ @@ -2703,7 +2703,7 @@ FLOAT_OP(n ## name1 ## name2, ps) \ FST2 ^= 1 << 31; \ FSTH2 ^= 1 << 31; \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } FLOAT_NTERNOP(mul, add) FLOAT_NTERNOP(mul, sub) @@ -2713,15 +2713,15 @@ FLOAT_NTERNOP(mul, sub) #define FLOAT_UNOP(name) \ FLOAT_OP(name, d) \ { \ - FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \ + FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(name, s) \ { \ - FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \ + FST2 = float32_ ## name(FST0, &env->fpu->fp_status); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } FLOAT_UNOP(sqrt) #undef FLOAT_UNOP @@ -2732,20 +2732,20 @@ FLOAT_OP(name, d) \ { \ FDT2 = float64_ ## name(FDT0); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(name, s) \ { \ FST2 = float32_ ## name(FST0); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ FLOAT_OP(name, ps) \ { \ FST2 = float32_ ## name(FST0); \ FSTH2 = float32_ ## name(FSTH0); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } FLOAT_UNOP(abs) FLOAT_UNOP(chs) @@ -2755,20 +2755,20 @@ FLOAT_OP(mov, d) { FDT2 = FDT0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(mov, s) { FST2 = FST0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(mov, ps) { FST2 = FST0; FSTH2 = FSTH0; DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } FLOAT_OP(alnv, ps) { @@ -2790,14 +2790,14 @@ FLOAT_OP(alnv, ps) break; } DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } #ifdef CONFIG_SOFTFLOAT #define clear_invalid() do { \ int flags = get_float_exception_flags(&env->fpu->fp_status); \ flags &= ~float_flag_invalid; \ - set_float_exception_flags(flags, &env->fpu->fp_status); \ + set_float_exception_flags(flags, &env->fpu->fp_status); \ } while(0) #else #define clear_invalid() do { } while(0) @@ -2810,13 +2810,13 @@ void OPPROTO op_cmp ## _ ## fmt ## _ ## op(void) \ { \ CALL_FROM_TB1(do_cmp ## _ ## fmt ## _ ## op, PARAM1); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } \ void OPPROTO op_cmpabs ## _ ## fmt ## _ ## op(void) \ { \ CALL_FROM_TB1(do_cmpabs ## _ ## fmt ## _ ## op, PARAM1); \ DEBUG_FPU_STATE(); \ - RETURN(); \ + FORCE_RET(); \ } #define CMP_OPS(op) \ CMP_OP(d, op) \ @@ -2846,62 +2846,62 @@ void op_bc1f (void) { T0 = !!(~GET_FP_COND(env->fpu) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_bc1any2f (void) { T0 = !!(~GET_FP_COND(env->fpu) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_bc1any4f (void) { T0 = !!(~GET_FP_COND(env->fpu) & (0xf << PARAM1)); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_bc1t (void) { T0 = !!(GET_FP_COND(env->fpu) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_bc1any2t (void) { T0 = !!(GET_FP_COND(env->fpu) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_bc1any4t (void) { T0 = !!(GET_FP_COND(env->fpu) & (0xf << PARAM1)); DEBUG_FPU_STATE(); - RETURN(); + FORCE_RET(); } void op_tlbwi (void) { CALL_FROM_TB0(env->tlb->do_tlbwi); - RETURN(); + FORCE_RET(); } void op_tlbwr (void) { CALL_FROM_TB0(env->tlb->do_tlbwr); - RETURN(); + FORCE_RET(); } void op_tlbp (void) { CALL_FROM_TB0(env->tlb->do_tlbp); - RETURN(); + FORCE_RET(); } void op_tlbr (void) { CALL_FROM_TB0(env->tlb->do_tlbr); - RETURN(); + FORCE_RET(); } /* Specials */ @@ -2915,7 +2915,7 @@ void op_tls_value (void) void op_pmon (void) { CALL_FROM_TB1(do_pmon, PARAM1); - RETURN(); + FORCE_RET(); } void op_di (void) @@ -2923,7 +2923,7 @@ void op_di (void) T0 = env->CP0_Status; env->CP0_Status = T0 & ~(1 << CP0St_IE); CALL_FROM_TB1(cpu_mips_update_irq, env); - RETURN(); + FORCE_RET(); } void op_ei (void) @@ -2931,7 +2931,7 @@ void op_ei (void) T0 = env->CP0_Status; env->CP0_Status = T0 | (1 << CP0St_IE); CALL_FROM_TB1(cpu_mips_update_irq, env); - RETURN(); + FORCE_RET(); } void op_trap (void) @@ -2939,19 +2939,19 @@ void op_trap (void) if (T0) { CALL_FROM_TB1(do_raise_exception, EXCP_TRAP); } - RETURN(); + FORCE_RET(); } void op_debug (void) { CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG); - RETURN(); + FORCE_RET(); } void op_set_lladdr (void) { env->CP0_LLAddr = T2; - RETURN(); + FORCE_RET(); } void debug_pre_eret (void); @@ -2971,7 +2971,7 @@ void op_eret (void) if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; - RETURN(); + FORCE_RET(); } void op_deret (void) @@ -2984,7 +2984,7 @@ void op_deret (void) if (loglevel & CPU_LOG_EXEC) CALL_FROM_TB0(debug_post_eret); env->CP0_LLAddr = 1; - RETURN(); + FORCE_RET(); } void op_rdhwr_cpunum(void) @@ -2994,7 +2994,7 @@ void op_rdhwr_cpunum(void) T0 = env->CP0_EBase & 0x3ff; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); - RETURN(); + FORCE_RET(); } void op_rdhwr_synci_step(void) @@ -3004,7 +3004,7 @@ void op_rdhwr_synci_step(void) T0 = env->SYNCI_Step; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); - RETURN(); + FORCE_RET(); } void op_rdhwr_cc(void) @@ -3014,7 +3014,7 @@ void op_rdhwr_cc(void) T0 = env->CP0_Count; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); - RETURN(); + FORCE_RET(); } void op_rdhwr_ccres(void) @@ -3024,26 +3024,26 @@ void op_rdhwr_ccres(void) T0 = env->CCRes; else CALL_FROM_TB1(do_raise_exception, EXCP_RI); - RETURN(); + FORCE_RET(); } void op_save_state (void) { env->hflags = PARAM1; - RETURN(); + FORCE_RET(); } void op_save_pc (void) { env->PC[env->current_tc] = PARAM1; - RETURN(); + FORCE_RET(); } #if defined(TARGET_MIPS64) void op_save_pc64 (void) { env->PC[env->current_tc] = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; - RETURN(); + FORCE_RET(); } #endif @@ -3057,32 +3057,32 @@ void op_interrupt_restart (void) env->CP0_Cause &= ~(0x1f << CP0Ca_EC); CALL_FROM_TB1(do_raise_exception, EXCP_EXT_INTERRUPT); } - RETURN(); + FORCE_RET(); } void op_raise_exception (void) { CALL_FROM_TB1(do_raise_exception, PARAM1); - RETURN(); + FORCE_RET(); } void op_raise_exception_err (void) { CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2); - RETURN(); + FORCE_RET(); } void op_exit_tb (void) { EXIT_TB(); - RETURN(); + FORCE_RET(); } void op_wait (void) { env->halted = 1; CALL_FROM_TB1(do_raise_exception, EXCP_HLT); - RETURN(); + FORCE_RET(); } /* Bitfield operations. */ @@ -3092,7 +3092,7 @@ void op_ext(void) unsigned int size = PARAM2; T0 = ((uint32_t)T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0); - RETURN(); + FORCE_RET(); } void op_ins(void) @@ -3102,13 +3102,13 @@ void op_ins(void) target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; T0 = (T0 & ~mask) | (((uint32_t)T1 << pos) & mask); - RETURN(); + FORCE_RET(); } void op_wsbh(void) { T0 = ((T1 << 8) & ~0x00FF00FF) | ((T1 >> 8) & 0x00FF00FF); - RETURN(); + FORCE_RET(); } #if defined(TARGET_MIPS64) @@ -3118,7 +3118,7 @@ void op_dext(void) unsigned int size = PARAM2; T0 = (T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0); - RETURN(); + FORCE_RET(); } void op_dins(void) @@ -3128,30 +3128,30 @@ void op_dins(void) target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; T0 = (T0 & ~mask) | ((T1 << pos) & mask); - RETURN(); + FORCE_RET(); } void op_dsbh(void) { T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL); - RETURN(); + FORCE_RET(); } void op_dshd(void) { T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL); - RETURN(); + FORCE_RET(); } #endif void op_seb(void) { T0 = ((T1 & 0xFF) ^ 0x80) - 0x80; - RETURN(); + FORCE_RET(); } void op_seh(void) { T0 = ((T1 & 0xFFFF) ^ 0x8000) - 0x8000; - RETURN(); + FORCE_RET(); } diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c index 5c981ada8..85872ca8f 100644 --- a/target-mips/op_mem.c +++ b/target-mips/op_mem.c @@ -22,55 +22,55 @@ void glue(op_lb, MEMSUFFIX) (void) { T0 = glue(ldsb, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_lbu, MEMSUFFIX) (void) { T0 = glue(ldub, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_sb, MEMSUFFIX) (void) { glue(stb, MEMSUFFIX)(T0, T1); - RETURN(); + FORCE_RET(); } void glue(op_lh, MEMSUFFIX) (void) { T0 = glue(ldsw, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_lhu, MEMSUFFIX) (void) { T0 = glue(lduw, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_sh, MEMSUFFIX) (void) { glue(stw, MEMSUFFIX)(T0, T1); - RETURN(); + FORCE_RET(); } void glue(op_lw, MEMSUFFIX) (void) { T0 = glue(ldl, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_lwu, MEMSUFFIX) (void) { T0 = (uint32_t)glue(ldl, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_sw, MEMSUFFIX) (void) { glue(stl, MEMSUFFIX)(T0, T1); - RETURN(); + FORCE_RET(); } /* "half" load and stores. We must do the memory access inline, @@ -106,7 +106,7 @@ void glue(op_lwl, MEMSUFFIX) (void) T1 = (T1 & 0xFFFFFF00) | tmp; } T1 = (int32_t)T1; - RETURN(); + FORCE_RET(); } void glue(op_lwr, MEMSUFFIX) (void) @@ -131,7 +131,7 @@ void glue(op_lwr, MEMSUFFIX) (void) T1 = (T1 & 0x00FFFFFF) | (tmp << 24); } T1 = (int32_t)T1; - RETURN(); + FORCE_RET(); } void glue(op_swl, MEMSUFFIX) (void) @@ -147,7 +147,7 @@ void glue(op_swl, MEMSUFFIX) (void) if (GET_LMASK(T0) == 0) glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 3), (uint8_t)T1); - RETURN(); + FORCE_RET(); } void glue(op_swr, MEMSUFFIX) (void) @@ -163,7 +163,7 @@ void glue(op_swr, MEMSUFFIX) (void) if (GET_LMASK(T0) == 3) glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -3), (uint8_t)(T1 >> 24)); - RETURN(); + FORCE_RET(); } void glue(op_ll, MEMSUFFIX) (void) @@ -171,7 +171,7 @@ void glue(op_ll, MEMSUFFIX) (void) T1 = T0; T0 = glue(ldl, MEMSUFFIX)(T0); env->CP0_LLAddr = T1; - RETURN(); + FORCE_RET(); } void glue(op_sc, MEMSUFFIX) (void) @@ -187,20 +187,20 @@ void glue(op_sc, MEMSUFFIX) (void) } else { T0 = 0; } - RETURN(); + FORCE_RET(); } #if defined(TARGET_MIPS64) void glue(op_ld, MEMSUFFIX) (void) { T0 = glue(ldq, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_sd, MEMSUFFIX) (void) { glue(stq, MEMSUFFIX)(T0, T1); - RETURN(); + FORCE_RET(); } /* "half" load and stores. We must do the memory access inline, @@ -254,7 +254,7 @@ void glue(op_ldl, MEMSUFFIX) (void) T1 = (T1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; } - RETURN(); + FORCE_RET(); } void glue(op_ldr, MEMSUFFIX) (void) @@ -299,7 +299,7 @@ void glue(op_ldr, MEMSUFFIX) (void) T1 = (T1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); } - RETURN(); + FORCE_RET(); } void glue(op_sdl, MEMSUFFIX) (void) @@ -327,7 +327,7 @@ void glue(op_sdl, MEMSUFFIX) (void) if (GET_LMASK64(T0) <= 0) glue(stb, MEMSUFFIX)(GET_OFFSET(T0, 7), (uint8_t)T1); - RETURN(); + FORCE_RET(); } void glue(op_sdr, MEMSUFFIX) (void) @@ -355,7 +355,7 @@ void glue(op_sdr, MEMSUFFIX) (void) if (GET_LMASK64(T0) == 7) glue(stb, MEMSUFFIX)(GET_OFFSET(T0, -7), (uint8_t)(T1 >> 56)); - RETURN(); + FORCE_RET(); } void glue(op_lld, MEMSUFFIX) (void) @@ -363,7 +363,7 @@ void glue(op_lld, MEMSUFFIX) (void) T1 = T0; T0 = glue(ldq, MEMSUFFIX)(T0); env->CP0_LLAddr = T1; - RETURN(); + FORCE_RET(); } void glue(op_scd, MEMSUFFIX) (void) @@ -379,37 +379,37 @@ void glue(op_scd, MEMSUFFIX) (void) } else { T0 = 0; } - RETURN(); + FORCE_RET(); } #endif /* TARGET_MIPS64 */ void glue(op_lwc1, MEMSUFFIX) (void) { WT0 = glue(ldl, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_swc1, MEMSUFFIX) (void) { glue(stl, MEMSUFFIX)(T0, WT0); - RETURN(); + FORCE_RET(); } void glue(op_ldc1, MEMSUFFIX) (void) { DT0 = glue(ldq, MEMSUFFIX)(T0); - RETURN(); + FORCE_RET(); } void glue(op_sdc1, MEMSUFFIX) (void) { glue(stq, MEMSUFFIX)(T0, DT0); - RETURN(); + FORCE_RET(); } void glue(op_luxc1, MEMSUFFIX) (void) { DT0 = glue(ldq, MEMSUFFIX)(T0 & ~0x7); - RETURN(); + FORCE_RET(); } void glue(op_suxc1, MEMSUFFIX) (void) { glue(stq, MEMSUFFIX)(T0 & ~0x7, DT0); - RETURN(); + FORCE_RET(); } diff --git a/target-mips/op_template.c b/target-mips/op_template.c index 036e6cef5..48b91e1be 100644 --- a/target-mips/op_template.c +++ b/target-mips/op_template.c @@ -22,44 +22,44 @@ void glue(op_load_gpr_T0_gpr, REG) (void) { T0 = env->gpr[REG][env->current_tc]; - RETURN(); + FORCE_RET(); } void glue(op_store_T0_gpr_gpr, REG) (void) { env->gpr[REG][env->current_tc] = T0; - RETURN(); + FORCE_RET(); } void glue(op_load_gpr_T1_gpr, REG) (void) { T1 = env->gpr[REG][env->current_tc]; - RETURN(); + FORCE_RET(); } void glue(op_store_T1_gpr_gpr, REG) (void) { env->gpr[REG][env->current_tc] = T1; - RETURN(); + FORCE_RET(); } void glue(op_load_gpr_T2_gpr, REG) (void) { T2 = env->gpr[REG][env->current_tc]; - RETURN(); + FORCE_RET(); } void glue(op_load_srsgpr_T0_gpr, REG) (void) { T0 = env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf]; - RETURN(); + FORCE_RET(); } void glue(op_store_T0_srsgpr_gpr, REG) (void) { env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf] = T0; - RETURN(); + FORCE_RET(); } #endif @@ -68,12 +68,12 @@ void glue(op_store_T0_srsgpr_gpr, REG) (void) void glue(op_set, tregname)(void) \ { \ treg = (int32_t)PARAM1; \ - RETURN(); \ + FORCE_RET(); \ } \ void glue(op_reset, tregname)(void) \ { \ treg = 0; \ - RETURN(); \ + FORCE_RET(); \ } \ SET_RESET(T0, _T0) @@ -87,7 +87,7 @@ SET_RESET(T2, _T2) void glue(op_set64, tregname)(void) \ { \ treg = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; \ - RETURN(); \ + FORCE_RET(); \ } SET64(T0, _T0) -- cgit v1.2.3 From 7d77bf200682ed8cbd0c94bdfbac64dc4b23b149 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 10 Nov 2007 09:32:02 +0000 Subject: More Sparc64 CPU definitions git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3561 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 12b5c96e2..6aeb3273a 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3502,9 +3502,107 @@ CPUSPARCState *cpu_sparc_init(void) static const sparc_def_t sparc_defs[] = { #ifdef TARGET_SPARC64 + { + .name = "Fujitsu Sparc64", + .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Fujitsu Sparc64 III", + .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Fujitsu Sparc64 IV", + .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Fujitsu Sparc64 V", + .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "TI UltraSparc I", + .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, { .name = "TI UltraSparc II", - .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0 << 24) + .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "TI UltraSparc IIi", + .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "TI UltraSparc IIe", + .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc III", + .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc III Cu", + .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc IIIi", + .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc IV", + .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc IV+", + .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "Sun UltraSparc IIIi+", + .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24) + | (MAXTL << 8) | (NWINDOWS - 1)), + .fpu_version = 0x00000000, + .mmu_version = 0, + }, + { + .name = "NEC UltraSparc I", + .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24) | (MAXTL << 8) | (NWINDOWS - 1)), .fpu_version = 0x00000000, .mmu_version = 0, -- cgit v1.2.3 From aaed909a495e78364abc6812df672d2e764961a8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Nov 2007 15:15:54 +0000 Subject: added cpu_model parameter to cpu_init() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3562 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 11 +++++- exec.c | 5 +++ hw/an5206.c | 4 +-- hw/etraxfs.c | 2 +- hw/integratorcp.c | 7 ++-- hw/mcf5208.c | 7 ++-- hw/mips_malta.c | 11 +++--- hw/mips_mipssim.c | 10 +++--- hw/mips_pica61.c | 10 +++--- hw/mips_r4k.c | 10 +++--- hw/omap.c | 11 ++++-- hw/pc.c | 10 +++--- hw/ppc4xx_devs.c | 13 +++---- hw/ppc_chrp.c | 15 ++++---- hw/ppc_oldworld.c | 15 ++++---- hw/ppc_prep.c | 13 +++---- hw/pxa2xx.c | 19 +++++++--- hw/r2d.c | 9 ++++- hw/realview.c | 8 +++-- hw/shix.c | 5 ++- hw/sun4m.c | 14 ++++---- hw/sun4u.c | 7 ++-- hw/versatilepb.c | 7 ++-- linux-user/main.c | 85 ++++++++++++++------------------------------ target-alpha/cpu.h | 2 +- target-alpha/translate.c | 3 +- target-arm/cpu.h | 3 +- target-arm/helper.c | 19 +++++----- target-cris/cpu.h | 6 +--- target-cris/translate.c | 2 +- target-i386/cpu.h | 3 +- target-i386/helper2.c | 38 +++++++++++--------- target-m68k/cpu.h | 10 ++---- target-m68k/helper.c | 43 ++++++++++++++++++++-- target-m68k/translate.c | 32 ----------------- target-mips/cpu.h | 6 ++-- target-mips/translate.c | 13 +++++-- target-mips/translate_init.c | 33 ++++++----------- target-ppc/cpu.h | 11 +++--- target-ppc/helper.c | 12 +++++-- target-ppc/translate_init.c | 32 ++++++----------- target-sh4/cpu.h | 2 +- target-sh4/translate.c | 2 +- target-sparc/cpu.h | 8 ++--- target-sparc/translate.c | 54 +++++++++++++++------------- tests/qruncom.c | 2 +- 46 files changed, 320 insertions(+), 324 deletions(-) diff --git a/darwin-user/main.c b/darwin-user/main.c index f240f35a6..607d3d65f 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -785,6 +785,7 @@ int main(int argc, char **argv) int optind; short use_gdbstub = 0; const char *r; + const char *cpu_model; if (argc <= 1) usage(); @@ -855,7 +856,15 @@ int main(int argc, char **argv) /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ - env = cpu_init(); +#if defined(TARGET_I386) + cpu_model = "qemu32"; +#elif defined(TARGET_PPC) + cpu_model = "750"; +#else +#error unsupported CPU +#endif + + env = cpu_init(cpu_model); printf("Starting %s with qemu\n----------------\n", filename); diff --git a/exec.c b/exec.c index b49e520c1..798780363 100644 --- a/exec.c +++ b/exec.c @@ -1314,6 +1314,8 @@ void cpu_abort(CPUState *env, const char *fmt, ...) CPUState *cpu_copy(CPUState *env) { +#if 0 + /* XXX: broken, must be handled by each CPU */ CPUState *new_env = cpu_init(); /* preserve chaining and index */ CPUState *next_cpu = new_env->next_cpu; @@ -1322,6 +1324,9 @@ CPUState *cpu_copy(CPUState *env) new_env->next_cpu = next_cpu; new_env->cpu_index = cpu_index; return new_env; +#else + return NULL; +#endif } #if !defined(CONFIG_USER_ONLY) diff --git a/hw/an5206.c b/hw/an5206.c index d9931df59..b5f93f671 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -37,10 +37,10 @@ static void an5206_init(int ram_size, int vga_ram_size, const char *boot_device, uint64_t elf_entry; target_ulong entry; - env = cpu_init(); if (!cpu_model) cpu_model = "m5206"; - if (cpu_m68k_set_model(env, cpu_model)) { + env = cpu_init(cpu_model); + if (!env) { cpu_abort(env, "Unable to find m68k CPU definition\n"); } diff --git a/hw/etraxfs.c b/hw/etraxfs.c index 6697c7d5d..da2196834 100644 --- a/hw/etraxfs.c +++ b/hw/etraxfs.c @@ -121,7 +121,7 @@ void bareetraxfs_init (int ram_size, int vga_ram_size, const char *boot_device, if (cpu_model == NULL) { cpu_model = "crisv32"; } - env = cpu_init(); + env = cpu_init(cpu_model); /* register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); */ qemu_register_reset(main_cpu_reset, env); irqs = qemu_allocate_irqs(dummy_cpu_set_irq, env, 32); diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 5d2c65125..0091f4fd1 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -473,10 +473,13 @@ static void integratorcp_init(int ram_size, int vga_ram_size, qemu_irq *pic; qemu_irq *cpu_pic; - env = cpu_init(); if (!cpu_model) cpu_model = "arm926"; - cpu_arm_set_model(env, cpu_model); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } bios_offset = ram_size + vga_ram_size; /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ /* ??? RAM shoud repeat to fill physical memory space. */ diff --git a/hw/mcf5208.c b/hw/mcf5208.c index bcb1c80be..93f78906d 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -209,11 +209,12 @@ static void mcf5208evb_init(int ram_size, int vga_ram_size, target_ulong entry; qemu_irq *pic; - env = cpu_init(); if (!cpu_model) cpu_model = "m5208"; - if (cpu_m68k_set_model(env, cpu_model)) { - cpu_abort(env, "Unable to find m68k CPU definition\n"); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find m68k CPU definition\n"); + exit(1); } /* Initialize CPU registers. */ diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 3b9170a48..2c193be23 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -735,7 +735,6 @@ static void main_cpu_reset(void *opaque) { CPUState *env = opaque; cpu_reset(env); - cpu_mips_register(env, NULL); /* The bootload does not need to be rewritten as it is located in a read only location. The kernel location and the arguments table @@ -761,7 +760,6 @@ void mips_malta_init (int ram_size, int vga_ram_size, const char *boot_device, /* fdctrl_t *floppy_controller; */ MaltaFPGAState *malta_fpga; int ret; - mips_def_t *def; qemu_irq *i8259; int piix4_devfn; uint8_t *eeprom_buf; @@ -776,10 +774,11 @@ void mips_malta_init (int ram_size, int vga_ram_size, const char *boot_device, cpu_model = "24Kf"; #endif } - if (mips_find_by_name(cpu_model, &def) != 0) - def = NULL; - env = cpu_init(); - cpu_mips_register(env, def); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 08e4b0b01..93288a6ef 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -94,7 +94,6 @@ static void main_cpu_reset(void *opaque) { CPUState *env = opaque; cpu_reset(env); - cpu_mips_register(env, NULL); if (loaderparams.kernel_filename) load_kernel (env); @@ -120,10 +119,11 @@ mips_mipssim_init (int ram_size, int vga_ram_size, const char *boot_device, cpu_model = "24Kf"; #endif } - if (mips_find_by_name(cpu_model, &def) != 0) - def = NULL; - env = cpu_init(); - cpu_mips_register(env, def); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index d79f7bea3..8e7ce6ce3 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -51,7 +51,6 @@ static void main_cpu_reset(void *opaque) { CPUState *env = opaque; cpu_reset(env); - cpu_mips_register(env, NULL); } static @@ -78,10 +77,11 @@ void mips_pica61_init (int ram_size, int vga_ram_size, const char *boot_device, cpu_model = "24Kf"; #endif } - if (mips_find_by_name(cpu_model, &def) != 0) - def = NULL; - env = cpu_init(); - cpu_mips_register(env, def); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index e4817e6b7..5a8bf6c24 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -135,7 +135,6 @@ static void main_cpu_reset(void *opaque) { CPUState *env = opaque; cpu_reset(env); - cpu_mips_register(env, NULL); if (loaderparams.kernel_filename) load_kernel (env); @@ -164,10 +163,11 @@ void mips_r4k_init (int ram_size, int vga_ram_size, const char *boot_device, cpu_model = "24Kf"; #endif } - if (mips_find_by_name(cpu_model, &def) != 0) - def = NULL; - env = cpu_init(); - cpu_mips_register(env, def); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); diff --git a/hw/omap.c b/hw/omap.c index 4efc5fa1b..a0f0a1925 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -4620,15 +4620,20 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) qemu_mallocz(sizeof(struct omap_mpu_state_s)); ram_addr_t imif_base, emiff_base; + + if (!core) + core = "ti925t"; /* Core */ s->mpu_model = omap310; - s->env = cpu_init(); + s->env = cpu_init(core); + if (!s->env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } s->sdram_size = sdram_size; s->sram_size = OMAP15XX_SRAM_SIZE; - cpu_arm_set_model(s->env, core ?: "ti925t"); - s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0]; /* Clocks */ diff --git a/hw/pc.c b/hw/pc.c index f6192f76b..727ae3a23 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -700,12 +700,12 @@ static void pc_init1(int ram_size, int vga_ram_size, const char *boot_device, #endif } - if (x86_find_cpu_by_name(cpu_model)) { - fprintf(stderr, "Unable to find x86 CPU definition\n"); - exit(1); - } for(i = 0; i < smp_cpus; i++) { - env = cpu_init(); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find x86 CPU definition\n"); + exit(1); + } if (i != 0) env->hflags |= HF_HALTED_MASK; if (smp_cpus > 1) { diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 8cefd7470..72490b089 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -37,17 +37,14 @@ CPUState *ppc4xx_init (const unsigned char *cpu_model, uint32_t sysclk) { CPUState *env; - ppc_def_t *def; /* init CPUs */ - env = cpu_init(); - ppc_find_by_name(cpu_model, &def); - if (def == NULL) { - cpu_abort(env, "Unable to find PowerPC %s CPU definition\n", - cpu_model); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find PowerPC %s CPU definition\n", + cpu_model); + exit(1); } - cpu_ppc_register(env, def); - cpu_ppc_reset(env); cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ cpu_clk->opaque = env; /* Set time-base frequency to sysclk */ diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 387da50ae..a791af269 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -56,14 +56,13 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, const char *initrd_filename, const char *cpu_model) { - CPUState *env, *envs[MAX_CPUS]; + CPUState *env = NULL, *envs[MAX_CPUS]; char buf[1024]; qemu_irq *pic, **openpic_irqs; int unin_memory; int linux_boot, i; unsigned long bios_offset, vga_bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; - ppc_def_t *def; PCIBus *pci_bus; nvram_t nvram; #if 0 @@ -80,16 +79,14 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, linux_boot = (kernel_filename != NULL); /* init CPUs */ - env = cpu_init(); if (cpu_model == NULL) cpu_model = "default"; - ppc_find_by_name(cpu_model, &def); - if (def == NULL) { - cpu_abort(env, "Unable to find PowerPC CPU definition\n"); - } for (i = 0; i < smp_cpus; i++) { - cpu_ppc_register(env, def); - cpu_ppc_reset(env); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find PowerPC CPU definition\n"); + exit(1); + } /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); #if 0 diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 49012cddf..bafe7b519 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -100,7 +100,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, const char *initrd_filename, const char *cpu_model) { - CPUState *env, *envs[MAX_CPUS]; + CPUState *env = NULL, *envs[MAX_CPUS]; char buf[1024]; qemu_irq *pic, **heathrow_irqs; nvram_t nvram; @@ -108,7 +108,6 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int linux_boot, i; unsigned long bios_offset, vga_bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; - ppc_def_t *def; PCIBus *pci_bus; MacIONVRAMState *nvr; int vga_bios_size, bios_size; @@ -119,16 +118,14 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, linux_boot = (kernel_filename != NULL); /* init CPUs */ - env = cpu_init(); if (cpu_model == NULL) cpu_model = "default"; - ppc_find_by_name(cpu_model, &def); - if (def == NULL) { - cpu_abort(env, "Unable to find PowerPC CPU definition\n"); - } for (i = 0; i < smp_cpus; i++) { - cpu_ppc_register(env, def); - cpu_ppc_reset(env); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find PowerPC CPU definition\n"); + exit(1); + } /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); env->osi_call = vga_osi_call; diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index c557f878a..5474d512c 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -536,7 +536,6 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, const char *boot_devi int linux_boot, i, nb_nics1, bios_size; unsigned long bios_offset; uint32_t kernel_base, kernel_size, initrd_base, initrd_size; - ppc_def_t *def; PCIBus *pci_bus; qemu_irq *i8259; int ppc_boot_device = boot_device[0]; @@ -548,16 +547,14 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, const char *boot_devi linux_boot = (kernel_filename != NULL); /* init CPUs */ - env = cpu_init(); if (cpu_model == NULL) cpu_model = "default"; - ppc_find_by_name(cpu_model, &def); - if (def == NULL) { - cpu_abort(env, "Unable to find PowerPC CPU definition\n"); - } for (i = 0; i < smp_cpus; i++) { - cpu_ppc_register(env, def); - cpu_ppc_reset(env); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find PowerPC CPU definition\n"); + exit(1); + } /* Set time-base frequency to 100 Mhz */ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); qemu_register_reset(&cpu_ppc_reset, env); diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 6109fc13e..ebaff1320 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2023,9 +2023,14 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, fprintf(stderr, "Machine requires a PXA27x processor.\n"); exit(1); } - - s->env = cpu_init(); - cpu_arm_set_model(s->env, revision ?: "pxa270"); + if (!revision) + revision = "pxa270"; + + s->env = cpu_init(revision); + if (!s->env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env); /* SDRAM & Internal Memory Storage */ @@ -2132,10 +2137,14 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, struct pxa2xx_state_s *s; struct pxa2xx_ssp_s *ssp; int iomemtype, i; + s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s)); - s->env = cpu_init(); - cpu_arm_set_model(s->env, "pxa255"); + s->env = cpu_init("pxa255"); + if (!s->env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env); /* SDRAM & Internal Memory Storage */ diff --git a/hw/r2d.c b/hw/r2d.c index fa3505100..ec6540e36 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -35,7 +35,14 @@ static void r2d_init(int ram_size, int vga_ram_size, const char *boot_device, CPUState *env; struct SH7750State *s; - env = cpu_init(); + if (!cpu_model) + cpu_model = "any"; + + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } /* Allocate memory space */ cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0); diff --git a/hw/realview.c b/hw/realview.c index b2f4ff278..f97d6e625 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -26,10 +26,14 @@ static void realview_init(int ram_size, int vga_ram_size, int n; int done_smc = 0; - env = cpu_init(); if (!cpu_model) cpu_model = "arm926"; - cpu_arm_set_model(env, cpu_model); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + /* ??? RAM shoud repeat to fill physical memory space. */ /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); diff --git a/hw/shix.c b/hw/shix.c index e65427a4c..0ec2b0e37 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -70,9 +70,12 @@ static void shix_init(int ram_size, int vga_ram_size, const char *boot_device, int ret; CPUState *env; struct SH7750State *s; + + if (!cpu_model) + cpu_model = "any"; printf("Initializing CPU\n"); - env = cpu_init(); + env = cpu_init(cpu_model); /* Allocate memory space */ printf("Allocating ROM\n"); diff --git a/hw/sun4m.c b/hw/sun4m.c index 01e0deead..7b92add95 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -313,21 +313,19 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, CPUState *env, *envs[MAX_CPUS]; unsigned int i; void *iommu, *espdma, *ledma, *main_esp, *nvram; - const sparc_def_t *def; qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; qemu_irq *esp_reset, *le_reset; /* init CPUs */ - sparc_find_by_name(cpu_model, &def); - if (def == NULL) { - fprintf(stderr, "Unable to find Sparc CPU definition\n"); - exit(1); - } for(i = 0; i < smp_cpus; i++) { - env = cpu_init(); - cpu_sparc_register(env, def, i); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find Sparc CPU definition\n"); + exit(1); + } + cpu_sparc_set_id(env, i); envs[i] = env; if (i == 0) { qemu_register_reset(main_cpu_reset, env); diff --git a/hw/sun4u.c b/hw/sun4u.c index 317ba741a..bdc6f9510 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -343,7 +343,6 @@ static void sun4u_init(int ram_size, int vga_ram_size, const char *boot_device, unsigned int i; long prom_offset, initrd_size, kernel_size; PCIBus *pci_bus; - const sparc_def_t *def; QEMUBH *bh; qemu_irq *irq; @@ -352,13 +351,11 @@ static void sun4u_init(int ram_size, int vga_ram_size, const char *boot_device, /* init CPUs */ if (cpu_model == NULL) cpu_model = "TI UltraSparc II"; - sparc_find_by_name(cpu_model, &def); - if (def == NULL) { + env = cpu_init(cpu_model); + if (!env) { fprintf(stderr, "Unable to find Sparc CPU definition\n"); exit(1); } - env = cpu_init(); - cpu_sparc_register(env, def, 0); bh = qemu_bh_new(tick_irq, env); env->tick = ptimer_init(bh); ptimer_set_period(env->tick, 1ULL); diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 31d58ef7a..fc27c4688 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -167,10 +167,13 @@ static void versatile_init(int ram_size, int vga_ram_size, int n; int done_smc = 0; - env = cpu_init(); if (!cpu_model) cpu_model = "arm926"; - cpu_arm_set_model(env, cpu_model); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } /* ??? RAM shoud repeat to fill physical memory space. */ /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); diff --git a/linux-user/main.c b/linux-user/main.c index 77667a55e..18e509d08 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1970,26 +1970,42 @@ int main(int argc, char **argv) /* Scan interp_prefix dir for replacement files. */ init_paths(interp_prefix); -#if defined(TARGET_I386) - /* must be done before cpu_init() for x86 XXX: suppress this hack - by adding a new parameter to cpu_init and by suppressing - cpu_xxx_register() */ if (cpu_model == NULL) { +#if defined(TARGET_I386) #ifdef TARGET_X86_64 cpu_model = "qemu64"; #else cpu_model = "qemu32"; #endif - } - if (x86_find_cpu_by_name(cpu_model)) { - fprintf(stderr, "Unable to find x86 CPU definition\n"); - exit(1); - } +#elif defined(TARGET_ARM) + cpu_model = "arm926"; +#elif defined(TARGET_M68K) + cpu_model = "any"; +#elif defined(TARGET_SPARC) +#ifdef TARGET_SPARC64 + cpu_model = "TI UltraSparc II"; +#else + cpu_model = "Fujitsu MB86904"; #endif - +#elif defined(TARGET_MIPS) +#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) + cpu_model = "20Kc"; +#else + cpu_model = "24Kf"; +#endif +#elif defined(TARGET_PPC) + cpu_model = "750"; +#else + cpu_model = "any"; +#endif + } /* NOTE: we need to init the CPU at this stage to get qemu_host_page_size */ - env = cpu_init(); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } global_env = env; if(getenv("QEMU_STRACE") ){ @@ -2130,9 +2146,6 @@ int main(int argc, char **argv) #elif defined(TARGET_ARM) { int i; - if (cpu_model == NULL) - cpu_model = "arm926"; - cpu_arm_set_model(env, cpu_model); cpsr_write(env, regs->uregs[16], 0xffffffff); for(i = 0; i < 16; i++) { env->regs[i] = regs->uregs[i]; @@ -2141,20 +2154,6 @@ int main(int argc, char **argv) #elif defined(TARGET_SPARC) { int i; - const sparc_def_t *def; -#ifdef TARGET_SPARC64 - if (cpu_model == NULL) - cpu_model = "TI UltraSparc II"; -#else - if (cpu_model == NULL) - cpu_model = "Fujitsu MB86904"; -#endif - sparc_find_by_name(cpu_model, &def); - if (def == NULL) { - fprintf(stderr, "Unable to find Sparc CPU definition\n"); - exit(1); - } - cpu_sparc_register(env, def, 0); env->pc = regs->pc; env->npc = regs->npc; env->y = regs->y; @@ -2165,19 +2164,8 @@ int main(int argc, char **argv) } #elif defined(TARGET_PPC) { - ppc_def_t *def; int i; - /* Choose and initialise CPU */ - if (cpu_model == NULL) - cpu_model = "750"; - ppc_find_by_name(cpu_model, &def); - if (def == NULL) { - cpu_abort(env, - "Unable to find PowerPC CPU definition\n"); - } - cpu_ppc_register(env, def); - cpu_ppc_reset(env); #if defined(TARGET_PPC64) #if defined(TARGET_ABI32) env->msr &= ~((target_ulong)1 << MSR_SF); @@ -2192,12 +2180,6 @@ int main(int argc, char **argv) } #elif defined(TARGET_M68K) { - if (cpu_model == NULL) - cpu_model = "any"; - if (cpu_m68k_set_model(env, cpu_model)) { - cpu_abort(cpu_single_env, - "Unable to find m68k CPU definition\n"); - } env->pc = regs->pc; env->dregs[0] = regs->d0; env->dregs[1] = regs->d1; @@ -2220,21 +2202,8 @@ int main(int argc, char **argv) } #elif defined(TARGET_MIPS) { - mips_def_t *def; int i; - /* Choose and initialise CPU */ - if (cpu_model == NULL) -#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) - cpu_model = "20Kc"; -#else - cpu_model = "24Kf"; -#endif - mips_find_by_name(cpu_model, &def); - if (def == NULL) - cpu_abort(env, "Unable to find MIPS CPU definition\n"); - cpu_mips_register(env, def); - for(i = 0; i < 32; i++) { env->gpr[i][env->current_tc] = regs->regs[i]; } diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index d65ccdea5..f8bbc70d7 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -396,7 +396,7 @@ enum { IR_ZERO = 31, }; -CPUAlphaState * cpu_alpha_init (void); +CPUAlphaState * cpu_alpha_init (const char *cpu_model); int cpu_alpha_exec(CPUAlphaState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 6f224b016..01e6ded12 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -2095,7 +2095,7 @@ int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } -CPUAlphaState * cpu_alpha_init (void) +CPUAlphaState * cpu_alpha_init (const char *cpu_model) { CPUAlphaState *env; uint64_t hwpcb; @@ -2133,3 +2133,4 @@ CPUAlphaState * cpu_alpha_init (void) return env; } + diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 5ffca1145..fb22b908d 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -164,7 +164,7 @@ typedef struct CPUARMState { target_phys_addr_t loader_start; } CPUARMState; -CPUARMState *cpu_arm_init(void); +CPUARMState *cpu_arm_init(const char *cpu_model); int cpu_arm_exec(CPUARMState *s); void cpu_arm_close(CPUARMState *s); void do_interrupt(CPUARMState *); @@ -263,7 +263,6 @@ static inline int arm_feature(CPUARMState *env, int feature) } void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -void cpu_arm_set_model(CPUARMState *env, const char *name); void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, diff --git a/target-arm/helper.c b/target-arm/helper.c index d06ee69e7..06eac66a1 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5,6 +5,8 @@ #include "cpu.h" #include "exec-all.h" +static uint32_t cpu_arm_find_by_name(const char *name); + static inline void set_feature(CPUARMState *env, int feature) { env->features |= 1u << feature; @@ -89,14 +91,19 @@ void cpu_reset(CPUARMState *env) tlb_flush(env, 1); } -CPUARMState *cpu_arm_init(void) +CPUARMState *cpu_arm_init(const char *cpu_model) { CPUARMState *env; + uint32_t id; + id = cpu_arm_find_by_name(cpu_model); + if (id == 0) + return NULL; env = qemu_mallocz(sizeof(CPUARMState)); if (!env) return NULL; cpu_exec_init(env); + env->cp15.c0_cpuid = id; cpu_reset(env); return env; } @@ -136,24 +143,20 @@ void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) } } -void cpu_arm_set_model(CPUARMState *env, const char *name) +/* return 0 if not found */ +static uint32_t cpu_arm_find_by_name(const char *name) { int i; uint32_t id; id = 0; - i = 0; for (i = 0; arm_cpu_names[i].name; i++) { if (strcmp(name, arm_cpu_names[i].name) == 0) { id = arm_cpu_names[i].id; break; } } - if (!id) { - cpu_abort(env, "Unknown CPU '%s'", name); - return; - } - cpu_reset_model_id(env, id); + return id; } void cpu_arm_close(CPUARMState *env) diff --git a/target-cris/cpu.h b/target-cris/cpu.h index ef0953b26..56b0497f1 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -147,7 +147,7 @@ typedef struct CPUCRISState { CPU_COMMON } CPUCRISState; -CPUCRISState *cpu_cris_init(void); +CPUCRISState *cpu_cris_init(const char *cpu_model); int cpu_cris_exec(CPUCRISState *s); void cpu_cris_close(CPUCRISState *s); void do_interrupt(CPUCRISState *env); @@ -201,10 +201,6 @@ enum { #define CRIS_SSP 0 #define CRIS_USP 1 -typedef struct cris_def_t cris_def_t; - -int cpu_cris_set_model(CPUCRISState *env, const char * name); - void cris_set_irq_level(CPUCRISState *env, int level, uint8_t vector); void cris_set_macsr(CPUCRISState *env, uint32_t val); void cris_switch_sp(CPUCRISState *env); diff --git a/target-cris/translate.c b/target-cris/translate.c index 40caef073..44ba804f2 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -2488,7 +2488,7 @@ void cpu_dump_state (CPUState *env, FILE *f, } -CPUCRISState *cpu_cris_init (void) +CPUCRISState *cpu_cris_init (const char *cpu_model) { CPUCRISState *env; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index c8fb12591..a6ad54be3 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -585,10 +585,9 @@ typedef struct CPUX86State { struct APICState *apic_state; } CPUX86State; -CPUX86State *cpu_x86_init(void); +CPUX86State *cpu_x86_init(const char *cpu_model); int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); -int x86_find_cpu_by_name (const unsigned char *name); void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); int cpu_get_pic_interrupt(CPUX86State *s); diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 065532049..b46475e30 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -31,9 +31,7 @@ //#define DEBUG_MMU -static struct x86_def_t *x86_cpu_def; -typedef struct x86_def_t x86_def_t; -static int cpu_x86_register (CPUX86State *env, const x86_def_t *def); +static int cpu_x86_register (CPUX86State *env, const char *cpu_model); static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, uint32_t *ext_features, @@ -92,7 +90,7 @@ static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, fprintf(stderr, "CPU feature %s not found\n", flagname); } -CPUX86State *cpu_x86_init(void) +CPUX86State *cpu_x86_init(const char *cpu_model) { CPUX86State *env; static int inited; @@ -107,7 +105,10 @@ CPUX86State *cpu_x86_init(void) inited = 1; optimize_flags_init(); } - cpu_x86_register(env, x86_cpu_def); + if (cpu_x86_register(env, cpu_model) < 0) { + cpu_x86_close(env); + return NULL; + } cpu_reset(env); #ifdef USE_KQEMU kqemu_init(env); @@ -115,7 +116,7 @@ CPUX86State *cpu_x86_init(void) return env; } -struct x86_def_t { +typedef struct x86_def_t { const char *name; uint32_t vendor1, vendor2, vendor3; int family; @@ -123,7 +124,7 @@ struct x86_def_t { int stepping; uint32_t features, ext_features, ext2_features, ext3_features; uint32_t xlevel; -}; +} x86_def_t; #define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \ CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \ @@ -194,10 +195,10 @@ static x86_def_t x86_defs[] = { }, }; -int x86_find_cpu_by_name(const unsigned char *cpu_model) +static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) { - int ret; unsigned int i; + x86_def_t *def; char *s = strdup(cpu_model); char *featurestr, *name = strtok(s, ","); @@ -205,17 +206,16 @@ int x86_find_cpu_by_name(const unsigned char *cpu_model) uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0; int family = -1, model = -1, stepping = -1; - ret = -1; - x86_cpu_def = NULL; + def = NULL; for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) { if (strcmp(name, x86_defs[i].name) == 0) { - x86_cpu_def = &x86_defs[i]; - ret = 0; + def = &x86_defs[i]; break; } } - if (!x86_cpu_def) + if (!def) goto error; + memcpy(x86_cpu_def, def, sizeof(*def)); featurestr = strtok(NULL, ","); @@ -274,10 +274,12 @@ int x86_find_cpu_by_name(const unsigned char *cpu_model) x86_cpu_def->ext_features &= ~minus_ext_features; x86_cpu_def->ext2_features &= ~minus_ext2_features; x86_cpu_def->ext3_features &= ~minus_ext3_features; + free(s); + return 0; error: free(s); - return ret; + return -1; } void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) @@ -288,8 +290,12 @@ void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name); } -int cpu_x86_register (CPUX86State *env, const x86_def_t *def) +static int cpu_x86_register (CPUX86State *env, const char *cpu_model) { + x86_def_t def1, *def = &def1; + + if (cpu_x86_find_by_name(def, cpu_model) < 0) + return -1; if (def->vendor1) { env->cpuid_vendor1 = def->vendor1; env->cpuid_vendor2 = def->vendor2; diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 5004a9168..732929bfa 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -100,8 +100,6 @@ typedef struct CPUM68KState { uint32_t rambar0; uint32_t cacr; - uint32_t features; - /* ??? remove this. */ uint32_t t1; @@ -118,9 +116,11 @@ typedef struct CPUM68KState { uint32_t qregs[MAX_QREGS]; CPU_COMMON + + uint32_t features; } CPUM68KState; -CPUM68KState *cpu_m68k_init(void); +CPUM68KState *cpu_m68k_init(const char *cpu_model); int cpu_m68k_exec(CPUM68KState *s); void cpu_m68k_close(CPUM68KState *s); void do_interrupt(int is_hw); @@ -174,10 +174,6 @@ enum { #define MACSR_V 0x002 #define MACSR_EV 0x001 -typedef struct m68k_def_t m68k_def_t; - -int cpu_m68k_set_model(CPUM68KState *env, const char * name); - void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); void m68k_set_macsr(CPUM68KState *env, uint32_t val); void m68k_switch_sp(CPUM68KState *env); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index f3c629979..8fef67226 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -33,6 +33,8 @@ enum m68k_cpuid { M68K_CPUID_ANY, }; +typedef struct m68k_def_t m68k_def_t; + struct m68k_def_t { const char * name; enum m68k_cpuid id; @@ -51,7 +53,7 @@ static void m68k_set_feature(CPUM68KState *env, int feature) env->features |= (1u << feature); } -int cpu_m68k_set_model(CPUM68KState *env, const char * name) +static int cpu_m68k_set_model(CPUM68KState *env, const char *name) { m68k_def_t *def; @@ -60,7 +62,7 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) break; } if (!def->name) - return 1; + return -1; switch (def->id) { case M68K_CPUID_M5206: @@ -98,8 +100,43 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) } register_m68k_insns(env); +} + +void cpu_reset(CPUM68KState *env) +{ + memset(env, 0, offsetof(CPUM68KState, breakpoints)); +#if !defined (CONFIG_USER_ONLY) + env->sr = 0x2700; +#endif + m68k_switch_sp(env); + /* ??? FP regs should be initialized to NaN. */ + env->cc_op = CC_OP_FLAGS; + /* TODO: We should set PC from the interrupt vector. */ + env->pc = 0; + tlb_flush(env, 1); +} - return 0; +CPUM68KState *cpu_m68k_init(const char *cpu_model) +{ + CPUM68KState *env; + + env = malloc(sizeof(CPUM68KState)); + if (!env) + return NULL; + cpu_exec_init(env); + + if (cpu_m68k_set_model(env, cpu_model) < 0) { + cpu_m68k_close(env); + return NULL; + } + + cpu_reset(env); + return env; +} + +void cpu_m68k_close(CPUM68KState *env) +{ + qemu_free(env); } void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index f6b4fad64..499f053e3 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3279,38 +3279,6 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) return gen_intermediate_code_internal(env, tb, 1); } -void cpu_reset(CPUM68KState *env) -{ - memset(env, 0, offsetof(CPUM68KState, breakpoints)); -#if !defined (CONFIG_USER_ONLY) - env->sr = 0x2700; -#endif - m68k_switch_sp(env); - /* ??? FP regs should be initialized to NaN. */ - env->cc_op = CC_OP_FLAGS; - /* TODO: We should set PC from the interrupt vector. */ - env->pc = 0; - tlb_flush(env, 1); -} - -CPUM68KState *cpu_m68k_init(void) -{ - CPUM68KState *env; - - env = malloc(sizeof(CPUM68KState)); - if (!env) - return NULL; - cpu_exec_init(env); - - cpu_reset(env); - return env; -} - -void cpu_m68k_close(CPUM68KState *env) -{ - free(env); -} - void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 1c850c782..482f27d1e 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -456,7 +456,7 @@ struct CPUMIPSState { CPU_COMMON - mips_def_t *cpu_model; + const mips_def_t *cpu_model; #ifndef CONFIG_USER_ONLY void *irq[8]; #endif @@ -474,9 +474,7 @@ void r4k_do_tlbwi (void); void r4k_do_tlbwr (void); void r4k_do_tlbp (void); void r4k_do_tlbr (void); -int mips_find_by_name (const unsigned char *name, mips_def_t **def); void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -int cpu_mips_register (CPUMIPSState *env, mips_def_t *def); void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int unused); @@ -560,7 +558,7 @@ enum { }; int cpu_mips_exec(CPUMIPSState *s); -CPUMIPSState *cpu_mips_init(void); +CPUMIPSState *cpu_mips_init(const char *cpu_model); uint32_t cpu_mips_get_clock (void); int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); diff --git a/target-mips/translate.c b/target-mips/translate.c index 578cd9a25..ac439d27a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -6725,13 +6725,21 @@ void cpu_dump_state (CPUState *env, FILE *f, #endif } -CPUMIPSState *cpu_mips_init (void) +#include "translate_init.c" + +CPUMIPSState *cpu_mips_init (const char *cpu_model) { CPUMIPSState *env; + const mips_def_t *def; + def = cpu_mips_find_by_name(cpu_model); + if (!def) + return NULL; env = qemu_mallocz(sizeof(CPUMIPSState)); if (!env) return NULL; + env->cpu_model = def; + cpu_exec_init(env); cpu_reset(env); return env; @@ -6780,6 +6788,5 @@ void cpu_reset (CPUMIPSState *env) #else env->hflags = MIPS_HFLAG_CP0; #endif + cpu_mips_register(env, env->cpu_model); } - -#include "translate_init.c" diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 1302b76ca..44aff7f37 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -53,7 +53,6 @@ Define a major version 1, minor version 0. */ #define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV)) - struct mips_def_t { const unsigned char *name; int32_t CP0_PRid; @@ -300,21 +299,16 @@ static mips_def_t mips_defs[] = #endif }; -int mips_find_by_name (const unsigned char *name, mips_def_t **def) +static const mips_def_t *cpu_mips_find_by_name (const unsigned char *name) { - int i, ret; + int i; - ret = -1; - *def = NULL; for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) { if (strcasecmp(name, mips_defs[i].name) == 0) { - *def = &mips_defs[i]; - ret = 0; - break; + return &mips_defs[i]; } } - - return ret; + return NULL; } void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) @@ -328,19 +322,19 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) } #ifndef CONFIG_USER_ONLY -static void no_mmu_init (CPUMIPSState *env, mips_def_t *def) +static void no_mmu_init (CPUMIPSState *env, const mips_def_t *def) { env->tlb->nb_tlb = 1; env->tlb->map_address = &no_mmu_map_address; } -static void fixed_mmu_init (CPUMIPSState *env, mips_def_t *def) +static void fixed_mmu_init (CPUMIPSState *env, const mips_def_t *def) { env->tlb->nb_tlb = 1; env->tlb->map_address = &fixed_mmu_map_address; } -static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def) +static void r4k_mmu_init (CPUMIPSState *env, const mips_def_t *def) { env->tlb->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); env->tlb->map_address = &r4k_map_address; @@ -350,7 +344,7 @@ static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def) env->tlb->do_tlbr = r4k_do_tlbr; } -static void mmu_init (CPUMIPSState *env, mips_def_t *def) +static void mmu_init (CPUMIPSState *env, const mips_def_t *def) { env->tlb = qemu_mallocz(sizeof(CPUMIPSTLBContext)); @@ -376,7 +370,7 @@ static void mmu_init (CPUMIPSState *env, mips_def_t *def) } #endif /* CONFIG_USER_ONLY */ -static void fpu_init (CPUMIPSState *env, mips_def_t *def) +static void fpu_init (CPUMIPSState *env, const mips_def_t *def) { env->fpu = qemu_mallocz(sizeof(CPUMIPSFPUContext)); @@ -389,7 +383,7 @@ static void fpu_init (CPUMIPSState *env, mips_def_t *def) #endif } -static void mvp_init (CPUMIPSState *env, mips_def_t *def) +static void mvp_init (CPUMIPSState *env, const mips_def_t *def) { env->mvp = qemu_mallocz(sizeof(CPUMIPSMVPContext)); @@ -415,13 +409,8 @@ static void mvp_init (CPUMIPSState *env, mips_def_t *def) (0x1 << CP0MVPC1_PCP1); } -int cpu_mips_register (CPUMIPSState *env, mips_def_t *def) +static int cpu_mips_register (CPUMIPSState *env, const mips_def_t *def) { - if (!def) - def = env->cpu_model; - if (!def) - cpu_abort(env, "Unable to find MIPS CPU definition\n"); - env->cpu_model = def; env->CP0_PRid = def->CP0_PRid; env->CP0_Config0 = def->CP0_Config0; #ifdef TARGET_WORDS_BIGENDIAN diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 939dbcd98..7fcdd4121 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -675,7 +675,7 @@ struct mmu_ctx_t { }; /*****************************************************************************/ -CPUPPCState *cpu_ppc_init (void); +CPUPPCState *cpu_ppc_init (const char *cpu_model); int cpu_ppc_exec (CPUPPCState *s); void cpu_ppc_close (CPUPPCState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV @@ -719,13 +719,12 @@ void ppc_store_xer (CPUPPCState *env, target_ulong value); void ppc_store_msr (CPUPPCState *env, target_ulong value); void cpu_ppc_reset (void *opaque); -CPUPPCState *cpu_ppc_init (void); -void cpu_ppc_close(CPUPPCState *env); -int ppc_find_by_name (const unsigned char *name, ppc_def_t **def); -int ppc_find_by_pvr (uint32_t apvr, ppc_def_t **def); void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def); + +const ppc_def_t *cpu_ppc_find_by_name (const unsigned char *name); +const ppc_def_t *cpu_ppc_find_by_pvr (uint32_t pvr); +int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); /* Time-base and decrementer management */ #ifndef NO_CPU_IO_DEFS diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 9fd9721cd..f7df19e1c 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2970,20 +2970,26 @@ void cpu_ppc_reset (void *opaque) tlb_flush(env, 1); } -CPUPPCState *cpu_ppc_init (void) +CPUPPCState *cpu_ppc_init (const char *cpu_model) { CPUPPCState *env; + const ppc_def_t *def; + + def = cpu_ppc_find_by_name(cpu_model); + if (!def) + return NULL; env = qemu_mallocz(sizeof(CPUPPCState)); if (!env) return NULL; cpu_exec_init(env); - + cpu_ppc_register_internal(env, def); + cpu_ppc_reset(env); return env; } void cpu_ppc_close (CPUPPCState *env) { /* Should also remove all opcode tables... */ - free(env); + qemu_free(env); } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index eae228b26..973e0c5db 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -5931,7 +5931,7 @@ static ppc_def_t ppc_defs[] = { /*****************************************************************************/ /* Generic CPU instanciation routine */ -static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) +static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) { #if !defined(CONFIG_USER_ONLY) int i; @@ -6276,7 +6276,7 @@ static void fix_opcode_tables (opc_handler_t **ppc_opcodes) } /*****************************************************************************/ -static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) +static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) { opcode_t *opc, *start, *end; @@ -6351,7 +6351,7 @@ static void dump_ppc_insns (CPUPPCState *env) } #endif -int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) +int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) { env->msr_mask = def->msr_mask; env->mmu_model = def->mmu_model; @@ -6514,41 +6514,31 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) return 0; } -int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) +const ppc_def_t *cpu_ppc_find_by_name (const unsigned char *name) { - int i, max, ret; + int i, max; - ret = -1; - *def = NULL; max = sizeof(ppc_defs) / sizeof(ppc_def_t); for (i = 0; i < max; i++) { if (strcasecmp(name, ppc_defs[i].name) == 0) { - *def = &ppc_defs[i]; - ret = 0; - break; + return &ppc_defs[i]; } } - - return ret; + return NULL; } -int ppc_find_by_pvr (uint32_t pvr, ppc_def_t **def) +const ppc_def_t *cpu_ppc_find_by_pvr (uint32_t pvr) { - int i, max, ret; + int i, max; - ret = -1; - *def = NULL; max = sizeof(ppc_defs) / sizeof(ppc_def_t); for (i = 0; i < max; i++) { if ((pvr & ppc_defs[i].pvr_mask) == (ppc_defs[i].pvr & ppc_defs[i].pvr_mask)) { - *def = &ppc_defs[i]; - ret = 0; - break; + return &ppc_defs[i]; } } - - return ret; + return NULL; } void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index edfda1f90..79701306c 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -123,7 +123,7 @@ typedef struct CPUSH4State { tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ } CPUSH4State; -CPUSH4State *cpu_sh4_init(void); +CPUSH4State *cpu_sh4_init(const char *cpu_model); int cpu_sh4_exec(CPUSH4State * s); int cpu_sh4_signal_handler(int host_signum, void *pinfo, void *puc); diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 35b6f08dc..8d5e99e97 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -141,7 +141,7 @@ void cpu_sh4_reset(CPUSH4State * env) env->mmucr = 0; } -CPUSH4State *cpu_sh4_init(void) +CPUSH4State *cpu_sh4_init(const char *cpu_model) { CPUSH4State *env; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 0e5a4e222..23f9ab136 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -165,8 +165,6 @@ /* 2 <= NWINDOWS <= 32. In QEMU it must also be a power of two. */ #define NWINDOWS 8 -typedef struct sparc_def_t sparc_def_t; - #if !defined(TARGET_SPARC64) #define NB_MMU_MODES 2 #else @@ -270,14 +268,12 @@ typedef struct CPUSPARCState { } while (0) #endif -CPUSPARCState *cpu_sparc_init(void); +CPUSPARCState *cpu_sparc_init(const char *cpu_model); int cpu_sparc_exec(CPUSPARCState *s); int cpu_sparc_close(CPUSPARCState *s); -int sparc_find_by_name (const unsigned char *name, const sparc_def_t **def); void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); -int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def, - unsigned int cpu); +void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu); #define GET_PSR(env) (env->version | (env->psr & PSR_ICC) | \ (env->psref? PSR_EF : 0) | \ diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 6aeb3273a..1e373cea3 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -54,6 +54,8 @@ typedef struct DisasContext { struct TranslationBlock *tb; } DisasContext; +typedef struct sparc_def_t sparc_def_t; + struct sparc_def_t { const unsigned char *name; target_ulong iu_version; @@ -62,6 +64,8 @@ struct sparc_def_t { uint32_t mmu_bm; }; +static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name); + static uint16_t *gen_opc_ptr; static uint32_t *gen_opparam_ptr; extern FILE *logfile; @@ -3489,15 +3493,36 @@ void cpu_reset(CPUSPARCState *env) #endif } -CPUSPARCState *cpu_sparc_init(void) +CPUSPARCState *cpu_sparc_init(const char *cpu_model) { CPUSPARCState *env; + const sparc_def_t *def; + + def = cpu_sparc_find_by_name(cpu_model); + if (!def) + return NULL; env = qemu_mallocz(sizeof(CPUSPARCState)); if (!env) return NULL; cpu_exec_init(env); - return (env); + env->version = def->iu_version; + env->fsr = def->fpu_version; +#if !defined(TARGET_SPARC64) + env->mmu_bm = def->mmu_bm; + env->mmuregs[0] |= def->mmu_version; + cpu_sparc_set_id(env, 0); +#endif + cpu_reset(env); + + return env; +} + +void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu) +{ +#if !defined(TARGET_SPARC64) + env->mxccregs[7] = ((cpu + 8) & 0xf) << 24; +#endif } static const sparc_def_t sparc_defs[] = { @@ -3744,22 +3769,16 @@ static const sparc_def_t sparc_defs[] = { #endif }; -int sparc_find_by_name(const unsigned char *name, const sparc_def_t **def) +static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name) { - int ret; unsigned int i; - ret = -1; - *def = NULL; for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) { if (strcasecmp(name, sparc_defs[i].name) == 0) { - *def = &sparc_defs[i]; - ret = 0; - break; + return &sparc_defs[i]; } } - - return ret; + return NULL; } void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) @@ -3775,19 +3794,6 @@ void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) } } -int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def, unsigned int cpu) -{ - env->version = def->iu_version; - env->fsr = def->fpu_version; -#if !defined(TARGET_SPARC64) - env->mmu_bm = def->mmu_bm; - env->mmuregs[0] |= def->mmu_version; - env->mxccregs[7] = ((cpu + 8) & 0xf) << 24; -#endif - cpu_reset(env); - return 0; -} - #define GET_FLAG(a,b) ((env->psr & a)?b:'-') void cpu_dump_state(CPUState *env, FILE *f, diff --git a/tests/qruncom.c b/tests/qruncom.c index 1f2b63e3c..7b25fcded 100644 --- a/tests/qruncom.c +++ b/tests/qruncom.c @@ -197,7 +197,7 @@ int main(int argc, char **argv) // cpu_set_log(CPU_LOG_TB_IN_ASM | CPU_LOG_TB_OUT_ASM | CPU_LOG_EXEC); - env = cpu_init(); + env = cpu_init("qemu32"); /* disable code copy to simplify debugging */ code_copy_enabled = 0; -- cgit v1.2.3 From 2a324a26a8c2a311507ffe8917f96df0ae391fad Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Nov 2007 15:36:21 +0000 Subject: exported display init functions to common code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3563 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/vl.h b/vl.h index d5df5d10a..683b62db2 100644 --- a/vl.h +++ b/vl.h @@ -787,6 +787,22 @@ void readline_start(const char *prompt, int is_password, void kqemu_record_dump(void); +/* sdl.c */ +void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); + +/* cocoa.m */ +void cocoa_display_init(DisplayState *ds, int full_screen); + +/* vnc.c */ +void vnc_display_init(DisplayState *ds); +void vnc_display_close(DisplayState *ds); +int vnc_display_open(DisplayState *ds, const char *display); +int vnc_display_password(DisplayState *ds, const char *password); +void do_info_vnc(void); + +/* x_keymap.c */ +extern uint8_t _translate_keycode(const int key); + #ifndef QEMU_TOOL typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, @@ -994,22 +1010,6 @@ void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); -/* sdl.c */ -void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); - -/* cocoa.m */ -void cocoa_display_init(DisplayState *ds, int full_screen); - -/* vnc.c */ -void vnc_display_init(DisplayState *ds); -void vnc_display_close(DisplayState *ds); -int vnc_display_open(DisplayState *ds, const char *display); -int vnc_display_password(DisplayState *ds, const char *password); -void do_info_vnc(void); - -/* x_keymap.c */ -extern uint8_t _translate_keycode(const int key); - /* ide.c */ #define MAX_DISKS 4 -- cgit v1.2.3 From 4d1165fa61784885f9099aaaf276fb1a0fc14cff Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 10 Nov 2007 16:34:46 +0000 Subject: Fix 64-bit host printf format mismatches. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3564 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/integratorcp.c | 10 ++++++---- hw/pl011.c | 4 ++-- hw/pl050.c | 4 ++-- hw/pl080.c | 4 ++-- hw/pl110.c | 4 ++-- hw/pl181.c | 4 ++-- hw/pl190.c | 4 ++-- hw/smc91c111.c | 4 ++-- 8 files changed, 20 insertions(+), 18 deletions(-) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 0091f4fd1..75315a8b9 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -99,7 +99,7 @@ static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset) return 0; default: cpu_abort (cpu_single_env, - "integratorcm_read: Unimplemented offset 0x%x\n", offset); + "integratorcm_read: Unimplemented offset 0x%x\n", (int)offset); return 0; } } @@ -207,7 +207,7 @@ static void integratorcm_write(void *opaque, target_phys_addr_t offset, break; default: cpu_abort (cpu_single_env, - "integratorcm_write: Unimplemented offset 0x%x\n", offset); + "integratorcm_write: Unimplemented offset 0x%x\n", (int)offset); break; } } @@ -414,7 +414,8 @@ static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset) case 3: /* CP_DECODE */ return 0x11; default: - cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", + (int)offset); return 0; } } @@ -431,7 +432,8 @@ static void icp_control_write(void *opaque, target_phys_addr_t offset, /* Nothing interesting implemented yet. */ break; default: - cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", + (int)offset); } } static CPUReadMemoryFunc *icp_control_readfn[] = { diff --git a/hw/pl011.c b/hw/pl011.c index 94ed6994d..df3349188 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -99,7 +99,7 @@ static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) case 18: /* UARTDMACR */ return s->dmacr; default: - cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", (int)offset); return 0; } } @@ -172,7 +172,7 @@ static void pl011_write(void *opaque, target_phys_addr_t offset, cpu_abort(cpu_single_env, "PL011: DMA not implemented\n"); break; default: - cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", (int)offset); } } diff --git a/hw/pl050.c b/hw/pl050.c index b3a27976c..1f56261b4 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -79,7 +79,7 @@ static uint32_t pl050_read(void *opaque, target_phys_addr_t offset) case 4: /* KMIIR */ return s->pending | 2; default: - cpu_abort (cpu_single_env, "pl050_read: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl050_read: Bad offset %x\n", (int)offset); return 0; } } @@ -108,7 +108,7 @@ static void pl050_write(void *opaque, target_phys_addr_t offset, s->clk = value; return; default: - cpu_abort (cpu_single_env, "pl050_write: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl050_write: Bad offset %x\n", (int)offset); } } static CPUReadMemoryFunc *pl050_readfn[] = { diff --git a/hw/pl080.c b/hw/pl080.c index b24cfbaf0..d581024ca 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -243,7 +243,7 @@ static uint32_t pl080_read(void *opaque, target_phys_addr_t offset) return s->sync; default: bad_offset: - cpu_abort(cpu_single_env, "pl080_read: Bad offset %x\n", offset); + cpu_abort(cpu_single_env, "pl080_read: Bad offset %x\n", (int)offset); return 0; } } @@ -305,7 +305,7 @@ static void pl080_write(void *opaque, target_phys_addr_t offset, break; default: bad_offset: - cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset); + cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", (int)offset); } pl080_update(s); } diff --git a/hw/pl110.c b/hw/pl110.c index adaf1315f..97cbee545 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -326,7 +326,7 @@ static uint32_t pl110_read(void *opaque, target_phys_addr_t offset) case 12: /* LCDLPCURR */ return s->lpbase; default: - cpu_abort (cpu_single_env, "pl110_read: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl110_read: Bad offset %x\n", (int)offset); return 0; } } @@ -393,7 +393,7 @@ static void pl110_write(void *opaque, target_phys_addr_t offset, pl110_update(s); break; default: - cpu_abort (cpu_single_env, "pl110_write: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl110_write: Bad offset %x\n", (int)offset); } } diff --git a/hw/pl181.c b/hw/pl181.c index a905cbb21..bd067ddac 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -333,7 +333,7 @@ static uint32_t pl181_read(void *opaque, target_phys_addr_t offset) return value; } default: - cpu_abort (cpu_single_env, "pl181_read: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl181_read: Bad offset %x\n", (int)offset); return 0; } } @@ -405,7 +405,7 @@ static void pl181_write(void *opaque, target_phys_addr_t offset, } break; default: - cpu_abort (cpu_single_env, "pl181_write: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl181_write: Bad offset %x\n", (int)offset); } pl181_update(s); } diff --git a/hw/pl190.c b/hw/pl190.c index 23494d8e1..79ba3ab79 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -139,7 +139,7 @@ static uint32_t pl190_read(void *opaque, target_phys_addr_t offset) case 13: /* DEFVECTADDR */ return s->vect_addr[16]; default: - cpu_abort (cpu_single_env, "pl190_read: Bad offset %x\n", offset); + cpu_abort (cpu_single_env, "pl190_read: Bad offset %x\n", (int)offset); return 0; } } @@ -197,7 +197,7 @@ static void pl190_write(void *opaque, target_phys_addr_t offset, uint32_t val) cpu_abort(cpu_single_env, "pl190: Test mode not implemented\n"); break; default: - cpu_abort(cpu_single_env, "pl190_write: Bad offset %x\n", offset); + cpu_abort(cpu_single_env, "pl190_write: Bad offset %x\n", (int)offset); return; } pl190_update(s); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index b8d0cba5f..25e6f79c7 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -413,7 +413,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, break; } cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n", - s->bank, offset); + s->bank, (int)offset); } static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) @@ -555,7 +555,7 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) break; } cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n", - s->bank, offset); + s->bank, (int)offset); return 0; } -- cgit v1.2.3 From 4b0f1a8b3247a1d6d9f7cda82600a2bceb76d8d9 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 10 Nov 2007 17:38:00 +0000 Subject: Update ARM disassembler. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3565 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm-dis.c | 4973 +++++++++++++++++++++++++++++++++++++++++++++---------------- dis-asm.h | 20 +- 2 files changed, 3743 insertions(+), 1250 deletions(-) diff --git a/arm-dis.c b/arm-dis.c index 11f580b2f..ee44292bd 100644 --- a/arm-dis.c +++ b/arm-dis.c @@ -1,550 +1,1496 @@ /* Instruction printing code for the ARM - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 - Free Software Foundation, Inc. + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 + 2007, Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modification by James G. Smith (jsmith@cygnus.co.uk) -This file is part of libopcodes. + 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 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. + 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. */ + 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Start of qemu specific additions. Mostly this is stub definitions + for things we don't care about. */ #include "dis-asm.h" +#define FALSE 0 +#define TRUE (!FALSE) +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n') + +#define ARM_EXT_V1 0 +#define ARM_EXT_V2 0 +#define ARM_EXT_V2S 0 +#define ARM_EXT_V3 0 +#define ARM_EXT_V3M 0 +#define ARM_EXT_V4 0 +#define ARM_EXT_V4T 0 +#define ARM_EXT_V5 0 +#define ARM_EXT_V5T 0 +#define ARM_EXT_V5ExP 0 +#define ARM_EXT_V5E 0 +#define ARM_EXT_V5J 0 +#define ARM_EXT_V6 0 +#define ARM_EXT_V6K 0 +#define ARM_EXT_V6Z 0 +#define ARM_EXT_V6T2 0 +#define ARM_EXT_V7 0 +#define ARM_EXT_DIV 0 + +/* Co-processor space extensions. */ +#define ARM_CEXT_XSCALE 0 +#define ARM_CEXT_MAVERICK 0 +#define ARM_CEXT_IWMMXT 0 + +#define FPU_FPA_EXT_V1 0 +#define FPU_FPA_EXT_V2 0 +#define FPU_VFP_EXT_NONE 0 +#define FPU_VFP_EXT_V1xD 0 +#define FPU_VFP_EXT_V1 0 +#define FPU_VFP_EXT_V2 0 +#define FPU_MAVERICK 0 +#define FPU_VFP_EXT_V3 0 +#define FPU_NEON_EXT_V1 0 + +int floatformat_ieee_single_little; +/* Assume host uses ieee float. */ +static void floatformat_to_double (int *ignored, unsigned char *data, + double *dest) +{ + union { + uint32_t i; + float f; + } u; + u.i = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + *dest = u.f; +} + +/* End of qemu specific additions. */ + +/* FIXME: Belongs in global header. */ +#ifndef strneq +#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) +#endif -struct arm_opcode { - unsigned long value, mask; /* recognise instruction if (op&mask)==value */ - char *assembler; /* how to disassemble this instruction */ +#ifndef NUM_ELEM +#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) +#endif + +struct opcode32 +{ + unsigned long arch; /* Architecture defining this insn. */ + unsigned long value, mask; /* Recognise insn if (op&mask)==value. */ + const char *assembler; /* How to disassemble this insn. */ }; -struct thumb_opcode +struct opcode16 { - unsigned short value, mask; /* recognise instruction if (op&mask)==value */ - char * assembler; /* how to disassemble this instruction */ + unsigned long arch; /* Architecture defining this insn. */ + unsigned short value, mask; /* Recognise insn if (op&mask)==value. */ + const char *assembler; /* How to disassemble this insn. */ }; -/* format of the assembler string : +/* print_insn_coprocessor recognizes the following format control codes: %% % + + %c print condition code (always bits 28-31 in ARM mode) + %q print shifter argument + %u print condition code (unconditional in ARM mode) + %A print address for ldc/stc/ldf/stf instruction + %B print vstm/vldm register list + %C print vstr/vldr address operand + %I print cirrus signed shift immediate: bits 0..3|4..6 + %F print the COUNT field of a LFM/SFM instruction. + %P print floating point precision in arithmetic insn + %Q print floating point precision in ldf/stf insn + %R print floating point rounding mode + + %r print as an ARM register %d print the bitfield in decimal + %k print immediate for VFPv3 conversion instruction %x print the bitfield in hex %X print the bitfield as 1 hex digit without leading "0x" - %r print as an ARM register %f print a floating point constant if >7 else a floating point register - %y print a single precision VFP reg. + %w print as an iWMMXt width field - [bhwd]ss/us + %g print as an iWMMXt 64-bit register + %G print as an iWMMXt general purpose or control register + %D print as a NEON D register + %Q print as a NEON Q register + + %y print a single precision VFP reg. Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair - %z print a double precision VFP reg + %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 - %'c print specified char iff bit is one - %`c print specified char iff bit is zero - %?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) + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + %L print as an iWMMXt N/M width field. + %Z print the Immediate of a WSHUFH instruction. + %l like 'A' except use byte offsets for 'B' & 'H' + versions. + %i print 5-bit immediate in bits 8,3..0 + (print "32" when 0) + %r print register offset address for wldt/wstr instruction +*/ + +/* Common coprocessor opcodes shared between Arm and Thumb-2. */ + +static const struct opcode32 coprocessor_opcodes[] = +{ + /* XScale instructions. */ + {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"}, + {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"}, + + /* Intel Wireless MMX technology instructions. */ +#define FIRST_IWMMXT_INSN 0x0e130130 +#define IWMMXT_INSN_COUNT 73 + {ARM_CEXT_IWMMXT, 0x0e130130, 0x0f3f0fff, "tandc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e400010, 0x0ff00f3f, "tbcst%6-7w%c\t%16-19g, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e130170, 0x0f3f0ff8, "textrc%22-23w%c\t%12-15r, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e100070, 0x0f300ff0, "textrm%3?su%22-23w%c\t%12-15r, %16-19g, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e600010, 0x0ff00f38, "tinsr%6-7w%c\t%16-19g, %12-15r, #%0-2d"}, + {ARM_CEXT_XSCALE, 0x0e000110, 0x0ff00fff, "tmcr%c\t%16-19G, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0c400000, 0x0ff00ff0, "tmcrr%c\t%0-3g, %12-15r, %16-19r"}, + {ARM_CEXT_XSCALE, 0x0e2c0010, 0x0ffc0e10, "tmia%17?tb%16?tb%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e200010, 0x0fff0e10, "tmia%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e280010, 0x0fff0e10, "tmiaph%c\t%5-8g, %0-3r, %12-15r"}, + {ARM_CEXT_XSCALE, 0x0e100030, 0x0f300fff, "tmovmsk%22-23w%c\t%12-15r, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e100110, 0x0ff00ff0, "tmrc%c\t%12-15r, %16-19G"}, + {ARM_CEXT_XSCALE, 0x0c500000, 0x0ff00ff0, "tmrrc%c\t%12-15r, %16-19r, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e130150, 0x0f3f0fff, "torc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e130190, 0x0f3f0fff, "torvsc%22-23w%c\t%12-15r"}, + {ARM_CEXT_XSCALE, 0x0e2001c0, 0x0f300fff, "wabs%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e0001c0, 0x0f300fff, "wacc%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e000180, 0x0f000ff0, "wadd%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e2001a0, 0x0f300ff0, "waddbhus%22?ml%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ea001a0, 0x0ff00ff0, "waddsubhx%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000020, 0x0f800ff0, "waligni%c\t%12-15g, %16-19g, %0-3g, #%20-22d"}, + {ARM_CEXT_XSCALE, 0x0e800020, 0x0fc00ff0, "walignr%20-21d%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e200000, 0x0fe00ff0, "wand%20'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800000, 0x0fa00ff0, "wavg2%22?hb%20'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e400000, 0x0fe00ff0, "wavg4%20'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000060, 0x0f300ff0, "wcmpeq%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100060, 0x0f100ff0, "wcmpgt%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0xfc500100, 0xfe500f00, "wldrd\t%12-15g, %r"}, + {ARM_CEXT_XSCALE, 0xfc100100, 0xfe500f00, "wldrw\t%12-15G, %A"}, + {ARM_CEXT_XSCALE, 0x0c100000, 0x0e100e00, "wldr%L%c\t%12-15g, %l"}, + {ARM_CEXT_XSCALE, 0x0e400100, 0x0fc00ff0, "wmac%21?su%20'z%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800100, 0x0fc00ff0, "wmadd%21?su%20'x%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec00100, 0x0fd00ff0, "wmadd%21?sun%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000160, 0x0f100ff0, "wmax%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000080, 0x0f100fe0, "wmerge%c\t%12-15g, %16-19g, %0-3g, #%21-23d"}, + {ARM_CEXT_XSCALE, 0x0e0000a0, 0x0f800ff0, "wmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e800120, 0x0f800ff0, "wmiaw%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100160, 0x0f100ff0, "wmin%21?su%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000100, 0x0fc00ff0, "wmul%21?su%20?ml%23'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ed00100, 0x0fd00ff0, "wmul%21?sumr%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ee000c0, 0x0fe00ff0, "wmulwsm%20`r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec000c0, 0x0fe00ff0, "wmulwum%20`r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0eb000c0, 0x0ff00ff0, "wmulwl%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e8000a0, 0x0f800ff0, "wqmia%21?tb%20?tb%22'n%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100080, 0x0fd00ff0, "wqmulm%21'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ec000e0, 0x0fd00ff0, "wqmulwm%21'r%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000000, 0x0ff00ff0, "wor%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000080, 0x0f000ff0, "wpack%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0xfe300040, 0xff300ef0, "wror%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e300040, 0x0f300ff0, "wror%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e300140, 0x0f300ff0, "wror%22-23wg%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0x0e000120, 0x0fa00ff0, "wsad%22?hb%20'z%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e0001e0, 0x0f000ff0, "wshufh%c\t%12-15g, %16-19g, #%Z"}, + {ARM_CEXT_XSCALE, 0xfe100040, 0xff300ef0, "wsll%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e100040, 0x0f300ff0, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100148, 0x0f300ffc, "wsll%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfe000040, 0xff300ef0, "wsra%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e000040, 0x0f300ff0, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e000148, 0x0f300ffc, "wsra%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfe200040, 0xff300ef0, "wsrl%22-23w\t%12-15g, %16-19g, #%i"}, + {ARM_CEXT_XSCALE, 0x0e200040, 0x0f300ff0, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e200148, 0x0f300ffc, "wsrl%22-23w%8'g%c\t%12-15g, %16-19g, %0-3G"}, + {ARM_CEXT_XSCALE, 0xfc400100, 0xfe500f00, "wstrd\t%12-15g, %r"}, + {ARM_CEXT_XSCALE, 0xfc000100, 0xfe500f00, "wstrw\t%12-15G, %A"}, + {ARM_CEXT_XSCALE, 0x0c000000, 0x0e100e00, "wstr%L%c\t%12-15g, %l"}, + {ARM_CEXT_XSCALE, 0x0e0001a0, 0x0f000ff0, "wsub%20-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0ed001c0, 0x0ff00ff0, "wsubaddhx%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e1001c0, 0x0f300ff0, "wabsdiff%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e0000c0, 0x0fd00fff, "wunpckeh%21?sub%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e4000c0, 0x0fd00fff, "wunpckeh%21?suh%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e8000c0, 0x0fd00fff, "wunpckeh%21?suw%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e0000e0, 0x0f100fff, "wunpckel%21?su%22-23w%c\t%12-15g, %16-19g"}, + {ARM_CEXT_XSCALE, 0x0e1000c0, 0x0f300ff0, "wunpckih%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e1000e0, 0x0f300ff0, "wunpckil%22-23w%c\t%12-15g, %16-19g, %0-3g"}, + {ARM_CEXT_XSCALE, 0x0e100000, 0x0ff00ff0, "wxor%c\t%12-15g, %16-19g, %0-3g"}, + + /* Floating point coprocessor (FPA) instructions */ + {FPU_FPA_EXT_V1, 0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"}, + {FPU_FPA_EXT_V1, 0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"}, + {FPU_FPA_EXT_V1, 0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"}, + {FPU_FPA_EXT_V1, 0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"}, + {FPU_FPA_EXT_V1, 0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"}, + {FPU_FPA_EXT_V1, 0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"}, + {FPU_FPA_EXT_V2, 0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"}, + {FPU_FPA_EXT_V2, 0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"}, + + /* Register load/store */ + {FPU_NEON_EXT_V1, 0x0d200b00, 0x0fb00f01, "vstmdb%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0d300b00, 0x0fb00f01, "vldmdb%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0c800b00, 0x0f900f01, "vstmia%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0c900b00, 0x0f900f01, "vldmia%c\t%16-19r%21'!, %B"}, + {FPU_NEON_EXT_V1, 0x0d000b00, 0x0f300f00, "vstr%c\t%12-15,22D, %C"}, + {FPU_NEON_EXT_V1, 0x0d100b00, 0x0f300f00, "vldr%c\t%12-15,22D, %C"}, + + /* Data transfer between ARM and NEON registers */ + {FPU_NEON_EXT_V1, 0x0e800b10, 0x0ff00f70, "vdup%c.32\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e800b30, 0x0ff00f70, "vdup%c.16\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ea00b10, 0x0ff00f70, "vdup%c.32\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ea00b30, 0x0ff00f70, "vdup%c.16\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ec00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7D, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0ee00b10, 0x0ff00f70, "vdup%c.8\t%16-19,7Q, %12-15r"}, + {FPU_NEON_EXT_V1, 0x0c400b10, 0x0ff00fd0, "vmov%c\t%0-3,5D, %12-15r, %16-19r"}, + {FPU_NEON_EXT_V1, 0x0c500b10, 0x0ff00fd0, "vmov%c\t%12-15r, %16-19r, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0x0e000b10, 0x0fd00f70, "vmov%c.32\t%16-19,7D[%21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e100b10, 0x0f500f70, "vmov%c.32\t%12-15r, %16-19,7D[%21d]"}, + {FPU_NEON_EXT_V1, 0x0e000b30, 0x0fd00f30, "vmov%c.16\t%16-19,7D[%6,21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e100b30, 0x0f500f30, "vmov%c.%23?us16\t%12-15r, %16-19,7D[%6,21d]"}, + {FPU_NEON_EXT_V1, 0x0e400b10, 0x0fd00f10, "vmov%c.8\t%16-19,7D[%5,6,21d], %12-15r"}, + {FPU_NEON_EXT_V1, 0x0e500b10, 0x0f500f10, "vmov%c.%23?us8\t%12-15r, %16-19,7D[%5,6,21d]"}, + + /* Floating point coprocessor (VFP) instructions */ + {FPU_VFP_EXT_V1xD, 0x0ef1fa10, 0x0fffffff, "fmstat%c"}, + {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee60a10, 0x0fff0fff, "fmxr%c\tmvfr1, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee70a10, 0x0fff0fff, "fmxr%c\tmvfr0, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"}, + {FPU_VFP_EXT_V1xD, 0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"}, + {FPU_VFP_EXT_V1xD, 0x0ef60a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr1"}, + {FPU_VFP_EXT_V1xD, 0x0ef70a10, 0x0fff0fff, "fmrx%c\t%12-15r, mvfr0"}, + {FPU_VFP_EXT_V1xD, 0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"}, + {FPU_VFP_EXT_V1xD, 0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"}, + {FPU_VFP_EXT_V1xD, 0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"}, + {FPU_VFP_EXT_V1, 0x0e000b10, 0x0ff00fff, "fmdlr%c\t%z2, %12-15r"}, + {FPU_VFP_EXT_V1, 0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %z2"}, + {FPU_VFP_EXT_V1, 0x0e200b10, 0x0ff00fff, "fmdhr%c\t%z2, %12-15r"}, + {FPU_VFP_EXT_V1, 0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %z2"}, + {FPU_VFP_EXT_V1xD, 0x0ee00a10, 0x0ff00fff, "fmxr%c\t, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, "}, + {FPU_VFP_EXT_V1xD, 0x0e000a10, 0x0ff00f7f, "fmsr%c\t%y2, %12-15r"}, + {FPU_VFP_EXT_V1xD, 0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %y2"}, + {FPU_VFP_EXT_V1xD, 0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%y1"}, + {FPU_VFP_EXT_V1, 0x0eb50b40, 0x0fbf0f70, "fcmp%7'ezd%c\t%z1"}, + {FPU_VFP_EXT_V1xD, 0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb00b40, 0x0fbf0fd0, "fcpyd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb00bc0, 0x0fbf0fd0, "fabsd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb10b40, 0x0fbf0fd0, "fnegd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb10bc0, 0x0fbf0fd0, "fsqrtd%c\t%z1, %z0"}, + {FPU_VFP_EXT_V1, 0x0eb70ac0, 0x0fbf0fd0, "fcvtds%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb70bc0, 0x0fbf0fd0, "fcvtsd%c\t%y1, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb80b40, 0x0fbf0fd0, "fuitod%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb80bc0, 0x0fbf0fd0, "fsitod%c\t%z1, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0eb40b40, 0x0fbf0f50, "fcmp%7'ed%c\t%z1, %z0"}, + {FPU_VFP_EXT_V3, 0x0eba0a40, 0x0fbe0f50, "f%16?us%7?lhtos%c\t%y1, #%5,0-3k"}, + {FPU_VFP_EXT_V3, 0x0eba0b40, 0x0fbe0f50, "f%16?us%7?lhtod%c\t%z1, #%5,0-3k"}, + {FPU_VFP_EXT_V1xD, 0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%y1, %y0"}, + {FPU_VFP_EXT_V1, 0x0ebc0b40, 0x0fbe0f50, "fto%16?sui%7'zd%c\t%y1, %z0"}, + {FPU_VFP_EXT_V3, 0x0ebe0a40, 0x0fbe0f50, "fto%16?us%7?lhs%c\t%y1, #%5,0-3k"}, + {FPU_VFP_EXT_V3, 0x0ebe0b40, 0x0fbe0f50, "fto%16?us%7?lhd%c\t%z1, #%5,0-3k"}, + {FPU_VFP_EXT_V1, 0x0c500b10, 0x0fb00ff0, "fmrrd%c\t%12-15r, %16-19r, %z0"}, + {FPU_VFP_EXT_V3, 0x0eb00a00, 0x0fb00ff0, "fconsts%c\t%y1, #%0-3,16-19d"}, + {FPU_VFP_EXT_V3, 0x0eb00b00, 0x0fb00ff0, "fconstd%c\t%z1, #%0-3,16-19d"}, + {FPU_VFP_EXT_V2, 0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%y4, %12-15r, %16-19r"}, + {FPU_VFP_EXT_V2, 0x0c400b10, 0x0ff00fd0, "fmdrr%c\t%z0, %12-15r, %16-19r"}, + {FPU_VFP_EXT_V2, 0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %y4"}, + {FPU_VFP_EXT_V1xD, 0x0e000a00, 0x0fb00f50, "fmacs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e000a40, 0x0fb00f50, "fnmacs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e000b00, 0x0fb00f50, "fmacd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e000b40, 0x0fb00f50, "fnmacd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e100a00, 0x0fb00f50, "fmscs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e100a40, 0x0fb00f50, "fnmscs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e100b00, 0x0fb00f50, "fmscd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e100b40, 0x0fb00f50, "fnmscd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e200a00, 0x0fb00f50, "fmuls%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e200a40, 0x0fb00f50, "fnmuls%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e200b00, 0x0fb00f50, "fmuld%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e200b40, 0x0fb00f50, "fnmuld%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e300a00, 0x0fb00f50, "fadds%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1xD, 0x0e300a40, 0x0fb00f50, "fsubs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e300b00, 0x0fb00f50, "faddd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1, 0x0e300b40, 0x0fb00f50, "fsubd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0e800a00, 0x0fb00f50, "fdivs%c\t%y1, %y2, %y0"}, + {FPU_VFP_EXT_V1, 0x0e800b00, 0x0fb00f50, "fdivd%c\t%z1, %z2, %z0"}, + {FPU_VFP_EXT_V1xD, 0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0d200b00, 0x0fb00f00, "fstmdb%0?xd%c\t%16-19r!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0d300b00, 0x0fb00f00, "fldmdb%0?xd%c\t%16-19r!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0d000a00, 0x0f300f00, "fsts%c\t%y1, %A"}, + {FPU_VFP_EXT_V1, 0x0d000b00, 0x0f300f00, "fstd%c\t%z1, %A"}, + {FPU_VFP_EXT_V1xD, 0x0d100a00, 0x0f300f00, "flds%c\t%y1, %A"}, + {FPU_VFP_EXT_V1, 0x0d100b00, 0x0f300f00, "fldd%c\t%z1, %A"}, + {FPU_VFP_EXT_V1xD, 0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0c800b00, 0x0f900f00, "fstmia%0?xd%c\t%16-19r%21'!, %z3"}, + {FPU_VFP_EXT_V1xD, 0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %y3"}, + {FPU_VFP_EXT_V1xD, 0x0c900b00, 0x0f900f00, "fldmia%0?xd%c\t%16-19r%21'!, %z3"}, + + /* Cirrus coprocessor instructions. */ + {ARM_CEXT_MAVERICK, 0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, + {ARM_CEXT_MAVERICK, 0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200440, 0x0ff00fff, "cfmval32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100440, 0x0ff00fff, "cfmv32al%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200460, 0x0ff00fff, "cfmvam32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100460, 0x0ff00fff, "cfmv32am%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e200480, 0x0ff00fff, "cfmvah32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100480, 0x0ff00fff, "cfmv32ah%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004a0, 0x0ff00fff, "cfmva32%c\tmvax%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1004a0, 0x0ff00fff, "cfmv32a%c\tmvfx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004c0, 0x0ff00fff, "cfmva64%c\tmvax%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1004c0, 0x0ff00fff, "cfmv64a%c\tmvdx%12-15d, mvax%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e2004e0, 0x0fff0fff, "cfmvsc32%c\tdspsc, mvdx%12-15d"}, + {ARM_CEXT_MAVERICK, 0x0e1004e0, 0x0fff0fff, "cfmv32sc%c\tmvdx%12-15d, dspsc"}, + {ARM_CEXT_MAVERICK, 0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"}, + {ARM_CEXT_MAVERICK, 0x0e000500, 0x0ff00f10, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"}, + {ARM_CEXT_MAVERICK, 0x0e200500, 0x0ff00f10, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"}, + {ARM_CEXT_MAVERICK, 0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"}, + {ARM_CEXT_MAVERICK, 0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e000600, 0x0ff00f10, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e100600, 0x0ff00f10, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e200600, 0x0ff00f10, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, + {ARM_CEXT_MAVERICK, 0x0e300600, 0x0ff00f10, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, + + /* Generic coprocessor instructions */ + {ARM_EXT_V2, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V2, 0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V2, 0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V2, 0x0c000000, 0x0e100000, "stc%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V2, 0x0c100000, 0x0e100000, "ldc%22'l%c\t%8-11d, cr%12-15d, %A"}, + + /* V6 coprocessor instructions */ + {ARM_EXT_V6, 0xfc500000, 0xfff00000, "mrrc2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + {ARM_EXT_V6, 0xfc400000, 0xfff00000, "mcrr2%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, + + /* V5 coprocessor instructions */ + {ARM_EXT_V5, 0xfc100000, 0xfe100000, "ldc2%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V5, 0xfc000000, 0xfe100000, "stc2%22'l%c\t%8-11d, cr%12-15d, %A"}, + {ARM_EXT_V5, 0xfe000000, 0xff000010, "cdp2%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V5, 0xfe000010, 0xff100010, "mcr2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + {ARM_EXT_V5, 0xfe100010, 0xff100010, "mrc2%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, + + {0, 0, 0, 0} +}; + +/* Neon opcode table: This does not encode the top byte -- that is + checked by the print_insn_neon routine, as it depends on whether we are + doing thumb32 or arm32 disassembly. */ + +/* print_insn_neon recognizes the following format control codes: + + %% % + + %c print condition code + %A print v{st,ld}[1234] operands + %B print v{st,ld}[1234] any one operands + %C print v{st,ld}[1234] single->all operands + %D print scalar + %E print vmov, vmvn, vorr, vbic encoded constant + %F print vtbl,vtbx register list + + %r print as an ARM register + %d print the bitfield in decimal + %e print the 2^N - bitfield in decimal + %D print as a NEON D register + %Q print as a NEON Q register + %R print as a NEON D or Q register + %Sn print byte scaled width limited by n + %Tn print short scaled width limited by n + %Un print long scaled width limited by n + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order */ + +static const struct opcode32 neon_opcodes[] = +{ + /* Extract */ + {FPU_NEON_EXT_V1, 0xf2b00840, 0xffb00850, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, + {FPU_NEON_EXT_V1, 0xf2b00000, 0xffb00810, "vext%c.8\t%12-15,22R, %16-19,7R, %0-3,5R, #%8-11d"}, + + /* Move data element to all lanes */ + {FPU_NEON_EXT_V1, 0xf3b40c00, 0xffb70f90, "vdup%c.32\t%12-15,22R, %0-3,5D[%19d]"}, + {FPU_NEON_EXT_V1, 0xf3b20c00, 0xffb30f90, "vdup%c.16\t%12-15,22R, %0-3,5D[%18-19d]"}, + {FPU_NEON_EXT_V1, 0xf3b10c00, 0xffb10f90, "vdup%c.8\t%12-15,22R, %0-3,5D[%17-19d]"}, + + /* Table lookup */ + {FPU_NEON_EXT_V1, 0xf3b00800, 0xffb00c50, "vtbl%c.8\t%12-15,22D, %F, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3b00840, 0xffb00c50, "vtbx%c.8\t%12-15,22D, %F, %0-3,5D"}, + + /* Two registers, miscellaneous */ + {FPU_NEON_EXT_V1, 0xf2880a10, 0xfebf0fd0, "vmovl%c.%24?us8\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2900a10, 0xfebf0fd0, "vmovl%c.%24?us16\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfebf0fd0, "vmovl%c.%24?us32\t%12-15,22Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3b00500, 0xffbf0f90, "vcnt%c.8\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00580, 0xffbf0f90, "vmvn%c\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20000, 0xffbf0f90, "vswp%c\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20200, 0xffb30fd0, "vmovn%c.i%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20240, 0xffb30fd0, "vqmovun%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20280, 0xffb30fd0, "vqmovn%c.s%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b202c0, 0xffb30fd0, "vqmovn%c.u%18-19T2\t%12-15,22D, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3b20300, 0xffb30fd0, "vshll%c.i%18-19S2\t%12-15,22Q, %0-3,5D, #%18-19S2"}, + {FPU_NEON_EXT_V1, 0xf3bb0400, 0xffbf0e90, "vrecpe%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3bb0480, 0xffbf0e90, "vrsqrte%c.%8?fu%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00000, 0xffb30f90, "vrev64%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00080, 0xffb30f90, "vrev32%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00100, 0xffb30f90, "vrev16%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00400, 0xffb30f90, "vcls%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00480, 0xffb30f90, "vclz%c.i%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00700, 0xffb30f90, "vqabs%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00780, 0xffb30f90, "vqneg%c.s%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20080, 0xffb30f90, "vtrn%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20100, 0xffb30f90, "vuzp%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b20180, 0xffb30f90, "vzip%c.%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b10000, 0xffb30b90, "vcgt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10080, 0xffb30b90, "vcge%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10100, 0xffb30b90, "vceq%c.%10?fi%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10180, 0xffb30b90, "vcle%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10200, 0xffb30b90, "vclt%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R, #0"}, + {FPU_NEON_EXT_V1, 0xf3b10300, 0xffb30b90, "vabs%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b10380, 0xffb30b90, "vneg%c.%10?fs%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00200, 0xffb30f10, "vpaddl%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b00600, 0xffb30f10, "vpadal%c.%7?us%18-19S2\t%12-15,22R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3b30600, 0xffb30e10, "vcvt%c.%7-8?usff%18-19Sa.%7-8?ffus%18-19Sa\t%12-15,22R, %0-3,5R"}, + + /* Three registers of the same length */ + {FPU_NEON_EXT_V1, 0xf2000110, 0xffb00f10, "vand%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2100110, 0xffb00f10, "vbic%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200110, 0xffb00f10, "vorr%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2300110, 0xffb00f10, "vorn%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000110, 0xffb00f10, "veor%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3100110, 0xffb00f10, "vbsl%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200110, 0xffb00f10, "vbit%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3300110, 0xffb00f10, "vbif%c\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000d00, 0xffa00f10, "vadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000d10, 0xffa00f10, "vmla%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000e00, 0xffa00f10, "vceq%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000f00, 0xffa00f10, "vmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000f10, 0xffa00f10, "vrecps%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200d00, 0xffa00f10, "vsub%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200d10, 0xffa00f10, "vmls%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200f00, 0xffa00f10, "vmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2200f10, 0xffa00f10, "vrsqrts%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000d00, 0xffa00f10, "vpadd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000d10, 0xffa00f10, "vmul%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000e00, 0xffa00f10, "vcge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000e10, 0xffa00f10, "vacge%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000f00, 0xffa00f10, "vpmax%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200d00, 0xffa00f10, "vabd%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200e00, 0xffa00f10, "vcgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200e10, 0xffa00f10, "vacgt%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3200f00, 0xffa00f10, "vpmin%c.f%20U0\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000800, 0xff800f10, "vadd%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000810, 0xff800f10, "vtst%c.%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000900, 0xff800f10, "vmla%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000b00, 0xff800f10, "vqdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000b10, 0xff800f10, "vpadd%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000800, 0xff800f10, "vsub%c.i%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000810, 0xff800f10, "vceq%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000900, 0xff800f10, "vmls%c.i%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf3000b00, 0xff800f10, "vqrdmulh%c.s%20-21S6\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000000, 0xfe800f10, "vhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000010, 0xfe800f10, "vqadd%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000100, 0xfe800f10, "vrhadd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000200, 0xfe800f10, "vhsub%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000210, 0xfe800f10, "vqsub%c.%24?us%20-21S3\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000300, 0xfe800f10, "vcgt%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000310, 0xfe800f10, "vcge%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000400, 0xfe800f10, "vshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000410, 0xfe800f10, "vqshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000500, 0xfe800f10, "vrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000510, 0xfe800f10, "vqrshl%c.%24?us%20-21S3\t%12-15,22R, %0-3,5R, %16-19,7R"}, + {FPU_NEON_EXT_V1, 0xf2000600, 0xfe800f10, "vmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000610, 0xfe800f10, "vmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000700, 0xfe800f10, "vabd%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000710, 0xfe800f10, "vaba%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000910, 0xfe800f10, "vmul%c.%24?pi%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000a00, 0xfe800f10, "vpmax%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + {FPU_NEON_EXT_V1, 0xf2000a10, 0xfe800f10, "vpmin%c.%24?us%20-21S2\t%12-15,22R, %16-19,7R, %0-3,5R"}, + + /* One register and an immediate value */ + {FPU_NEON_EXT_V1, 0xf2800e10, 0xfeb80fb0, "vmov%c.i8\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800e30, 0xfeb80fb0, "vmov%c.i64\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800f10, 0xfeb80fb0, "vmov%c.f32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800810, 0xfeb80db0, "vmov%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800830, 0xfeb80db0, "vmvn%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800910, 0xfeb80db0, "vorr%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800930, 0xfeb80db0, "vbic%c.i16\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800c10, 0xfeb80eb0, "vmov%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800c30, 0xfeb80eb0, "vmvn%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800110, 0xfeb809b0, "vorr%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800130, 0xfeb809b0, "vbic%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800010, 0xfeb808b0, "vmov%c.i32\t%12-15,22R, %E"}, + {FPU_NEON_EXT_V1, 0xf2800030, 0xfeb808b0, "vmvn%c.i32\t%12-15,22R, %E"}, + + /* Two registers and a shift amount */ + {FPU_NEON_EXT_V1, 0xf2880810, 0xffb80fd0, "vshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880850, 0xffb80fd0, "vrshrn%c.i16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880810, 0xfeb80fd0, "vqshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880850, 0xfeb80fd0, "vqrshrun%c.s16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880910, 0xfeb80fd0, "vqshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880950, 0xfeb80fd0, "vqrshrn%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880a10, 0xfeb80fd0, "vshll%c.%24?us8\t%12-15,22D, %0-3,5Q, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2900810, 0xffb00fd0, "vshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900850, 0xffb00fd0, "vrshrn%c.i32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2880510, 0xffb80f90, "vshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf3880410, 0xffb80f90, "vsri%c.8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf3880510, 0xffb80f90, "vsli%c.8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf3880610, 0xffb80f90, "vqshlu%c.s8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2900810, 0xfeb00fd0, "vqshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900850, 0xfeb00fd0, "vqrshrun%c.s32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900910, 0xfeb00fd0, "vqshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900950, 0xfeb00fd0, "vqrshrn%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900a10, 0xfeb00fd0, "vshll%c.%24?us16\t%12-15,22D, %0-3,5Q, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2880010, 0xfeb80f90, "vshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880110, 0xfeb80f90, "vsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880210, 0xfeb80f90, "vrshr%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880310, 0xfeb80f90, "vrsra%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18e"}, + {FPU_NEON_EXT_V1, 0xf2880710, 0xfeb80f90, "vqshl%c.%24?us8\t%12-15,22R, %0-3,5R, #%16-18d"}, + {FPU_NEON_EXT_V1, 0xf2a00810, 0xffa00fd0, "vshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00850, 0xffa00fd0, "vrshrn%c.i64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2900510, 0xffb00f90, "vshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf3900410, 0xffb00f90, "vsri%c.16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf3900510, 0xffb00f90, "vsli%c.16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf3900610, 0xffb00f90, "vqshlu%c.s16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2a00a10, 0xfea00fd0, "vshll%c.%24?us32\t%12-15,22D, %0-3,5Q, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2900010, 0xfeb00f90, "vshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900110, 0xfeb00f90, "vsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900210, 0xfeb00f90, "vrshr%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900310, 0xfeb00f90, "vrsra%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19e"}, + {FPU_NEON_EXT_V1, 0xf2900710, 0xfeb00f90, "vqshl%c.%24?us16\t%12-15,22R, %0-3,5R, #%16-19d"}, + {FPU_NEON_EXT_V1, 0xf2800810, 0xfec00fd0, "vqshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800850, 0xfec00fd0, "vqrshrun%c.s64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800910, 0xfec00fd0, "vqshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2800950, 0xfec00fd0, "vqrshrn%c.%24?us64\t%12-15,22D, %0-3,5Q, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00510, 0xffa00f90, "vshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf3a00410, 0xffa00f90, "vsri%c.32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf3a00510, 0xffa00f90, "vsli%c.32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf3a00610, 0xffa00f90, "vqshlu%c.s32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2a00010, 0xfea00f90, "vshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00110, 0xfea00f90, "vsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00210, 0xfea00f90, "vrshr%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00310, 0xfea00f90, "vrsra%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20e"}, + {FPU_NEON_EXT_V1, 0xf2a00710, 0xfea00f90, "vqshl%c.%24?us32\t%12-15,22R, %0-3,5R, #%16-20d"}, + {FPU_NEON_EXT_V1, 0xf2800590, 0xff800f90, "vshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf3800490, 0xff800f90, "vsri%c.64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf3800590, 0xff800f90, "vsli%c.64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf3800690, 0xff800f90, "vqshlu%c.s64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf2800090, 0xfe800f90, "vshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800190, 0xfe800f90, "vsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800290, 0xfe800f90, "vrshr%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800390, 0xfe800f90, "vrsra%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21e"}, + {FPU_NEON_EXT_V1, 0xf2800790, 0xfe800f90, "vqshl%c.%24?us64\t%12-15,22R, %0-3,5R, #%16-21d"}, + {FPU_NEON_EXT_V1, 0xf2a00e10, 0xfea00e90, "vcvt%c.%24,8?usff32.%24,8?ffus32\t%12-15,22R, %0-3,5R, #%16-20e"}, + + /* Three registers of different lengths */ + {FPU_NEON_EXT_V1, 0xf2800e00, 0xfea00f50, "vmull%c.p%20S0\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800400, 0xff800f50, "vaddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800600, 0xff800f50, "vsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800900, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800b00, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800d00, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf3800400, 0xff800f50, "vraddhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf3800600, 0xff800f50, "vrsubhn%c.i%20-21T2\t%12-15,22D, %16-19,7Q, %0-3,5Q"}, + {FPU_NEON_EXT_V1, 0xf2800000, 0xfe800f50, "vaddl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800100, 0xfe800f50, "vaddw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800200, 0xfe800f50, "vsubl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800300, 0xfe800f50, "vsubw%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7Q, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800500, 0xfe800f50, "vabal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800700, 0xfe800f50, "vabdl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800800, 0xfe800f50, "vmlal%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800a00, 0xfe800f50, "vmlsl%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + {FPU_NEON_EXT_V1, 0xf2800c00, 0xfe800f50, "vmull%c.%24?us%20-21S2\t%12-15,22Q, %16-19,7D, %0-3,5D"}, + + /* Two registers and a scalar */ + {FPU_NEON_EXT_V1, 0xf2800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800340, 0xff800f50, "vqdmlal%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800540, 0xff800f50, "vmls%c.f%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800740, 0xff800f50, "vqdmlsl%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800b40, 0xff800f50, "vqdmull%c.s%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22D, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf3800040, 0xff800f50, "vmla%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800140, 0xff800f50, "vmla%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800440, 0xff800f50, "vmls%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800540, 0xff800f50, "vmls%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800840, 0xff800f50, "vmul%c.i%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800940, 0xff800f50, "vmul%c.f%20-21Sa\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800c40, 0xff800f50, "vqdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf3800d40, 0xff800f50, "vqrdmulh%c.s%20-21S6\t%12-15,22Q, %16-19,7Q, %D"}, + {FPU_NEON_EXT_V1, 0xf2800240, 0xfe800f50, "vmlal%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800640, 0xfe800f50, "vmlsl%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + {FPU_NEON_EXT_V1, 0xf2800a40, 0xfe800f50, "vmull%c.%24?us%20-21S6\t%12-15,22Q, %16-19,7D, %D"}, + + /* Element and structure load/store */ + {FPU_NEON_EXT_V1, 0xf4a00fc0, 0xffb00fc0, "vld4%c.32\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00c00, 0xffb00f00, "vld1%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00d00, 0xffb00f00, "vld2%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00e00, 0xffb00f00, "vld3%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4a00f00, 0xffb00f00, "vld4%c.%6-7S2\t%C"}, + {FPU_NEON_EXT_V1, 0xf4000200, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000300, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000400, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000500, 0xff900f00, "v%21?ls%21?dt3%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000600, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000700, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000800, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000900, 0xff900f00, "v%21?ls%21?dt2%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000a00, 0xff900f00, "v%21?ls%21?dt1%c.%6-7S3\t%A"}, + {FPU_NEON_EXT_V1, 0xf4000000, 0xff900e00, "v%21?ls%21?dt4%c.%6-7S2\t%A"}, + {FPU_NEON_EXT_V1, 0xf4800000, 0xff900300, "v%21?ls%21?dt1%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800100, 0xff900300, "v%21?ls%21?dt2%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800200, 0xff900300, "v%21?ls%21?dt3%c.%10-11S2\t%B"}, + {FPU_NEON_EXT_V1, 0xf4800300, 0xff900300, "v%21?ls%21?dt4%c.%10-11S2\t%B"}, + + {0,0 ,0, 0} +}; + +/* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb. All three are partially + ordered: they must be searched linearly from the top to obtain a correct + match. */ + +/* print_insn_arm recognizes the following format control codes: + + %% % + %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 + %c print condition code (always bits 28-31) %m print register mask for ldm/stm instruction + %o print operand2 (immediate or register + shift) + %p print 'p' iff bits 12-15 are 15 + %t print 't' iff bit 21 set and bit 24 clear + %B print arm BLX(1) destination %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) + %U print barrier type. + %P print address for pli instruction. + + %r print as an ARM register + %d print the bitfield in decimal + %W print the bitfield plus one in decimal + %x print the bitfield in hex + %X print the bitfield as 1 hex digit without leading "0x" + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + %e print arm SMI operand (bits 0..7,8..19). + %E print the LSB and WIDTH fields of a BFI or BFC instruction. + %V print the 16-bit immediate field of a MOVT or MOVW instruction. */ + +static const struct opcode32 arm_opcodes[] = +{ + /* ARM instructions. */ + {ARM_EXT_V1, 0xe1a00000, 0xffffffff, "nop\t\t\t(mov r0,r0)"}, + {ARM_EXT_V4T | ARM_EXT_V5, 0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"}, + {ARM_EXT_V2, 0x00000090, 0x0fe000f0, "mul%20's%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V2, 0x00200090, 0x0fe000f0, "mla%20's%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V2S, 0x01000090, 0x0fb00ff0, "swp%22'b%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + + /* V7 instructions. */ + {ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"}, + {ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"}, + {ARM_EXT_V7, 0xf57ff050, 0xfffffff0, "dmb\t%U"}, + {ARM_EXT_V7, 0xf57ff040, 0xfffffff0, "dsb\t%U"}, + {ARM_EXT_V7, 0xf57ff060, 0xfffffff0, "isb\t%U"}, + + /* ARM V6T2 instructions. */ + {ARM_EXT_V6T2, 0x07c0001f, 0x0fe0007f, "bfc%c\t%12-15r, %E"}, + {ARM_EXT_V6T2, 0x07c00010, 0x0fe00070, "bfi%c\t%12-15r, %0-3r, %E"}, + {ARM_EXT_V6T2, 0x00600090, 0x0ff000f0, "mls%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6T2, 0x006000b0, 0x0f7000f0, "strht%c\t%12-15r, %s"}, + {ARM_EXT_V6T2, 0x00300090, 0x0f300090, "ldr%6's%5?hbt%c\t%12-15r, %s"}, + {ARM_EXT_V6T2, 0x03000000, 0x0ff00000, "movw%c\t%12-15r, %V"}, + {ARM_EXT_V6T2, 0x03400000, 0x0ff00000, "movt%c\t%12-15r, %V"}, + {ARM_EXT_V6T2, 0x06ff0f30, 0x0fff0ff0, "rbit%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6T2, 0x07a00050, 0x0fa00070, "%22?usbfx%c\t%12-15r, %0-3r, #%7-11d, #%16-20W"}, + + /* ARM V6Z instructions. */ + {ARM_EXT_V6Z, 0x01600070, 0x0ff000f0, "smc%c\t%e"}, + + /* ARM V6K instructions. */ + {ARM_EXT_V6K, 0xf57ff01f, 0xffffffff, "clrex"}, + {ARM_EXT_V6K, 0x01d00f9f, 0x0ff00fff, "ldrexb%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01b00f9f, 0x0ff00fff, "ldrexd%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01f00f9f, 0x0ff00fff, "ldrexh%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01c00f90, 0x0ff00ff0, "strexb%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01a00f90, 0x0ff00ff0, "strexd%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6K, 0x01e00f90, 0x0ff00ff0, "strexh%c\t%12-15r, %0-3r, [%16-19r]"}, + + /* ARM V6K NOP hints. */ + {ARM_EXT_V6K, 0x0320f001, 0x0fffffff, "yield%c"}, + {ARM_EXT_V6K, 0x0320f002, 0x0fffffff, "wfe%c"}, + {ARM_EXT_V6K, 0x0320f003, 0x0fffffff, "wfi%c"}, + {ARM_EXT_V6K, 0x0320f004, 0x0fffffff, "sev%c"}, + {ARM_EXT_V6K, 0x0320f000, 0x0fffff00, "nop%c\t{%0-7d}"}, + + /* ARM V6 instructions. */ + {ARM_EXT_V6, 0xf1080000, 0xfffffe3f, "cpsie\t%8'a%7'i%6'f"}, + {ARM_EXT_V6, 0xf10a0000, 0xfffffe20, "cpsie\t%8'a%7'i%6'f,#%0-4d"}, + {ARM_EXT_V6, 0xf10C0000, 0xfffffe3f, "cpsid\t%8'a%7'i%6'f"}, + {ARM_EXT_V6, 0xf10e0000, 0xfffffe20, "cpsid\t%8'a%7'i%6'f,#%0-4d"}, + {ARM_EXT_V6, 0xf1000000, 0xfff1fe20, "cps\t#%0-4d"}, + {ARM_EXT_V6, 0x06800010, 0x0ff00ff0, "pkhbt%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06800010, 0x0ff00070, "pkhbt%c\t%12-15r, %16-19r, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06800050, 0x0ff00ff0, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #32"}, + {ARM_EXT_V6, 0x06800050, 0x0ff00070, "pkhtb%c\t%12-15r, %16-19r, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x01900f9f, 0x0ff00fff, "ldrex%c\tr%12-15d, [%16-19r]"}, + {ARM_EXT_V6, 0x06200f10, 0x0ff00ff0, "qadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f90, 0x0ff00ff0, "qadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f30, 0x0ff00ff0, "qaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f70, 0x0ff00ff0, "qsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200ff0, 0x0ff00ff0, "qsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06200f50, 0x0ff00ff0, "qsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f10, 0x0ff00ff0, "sadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f90, 0x0ff00ff0, "sadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f30, 0x0ff00ff0, "saddaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f10, 0x0ff00ff0, "shadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f90, 0x0ff00ff0, "shadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f30, 0x0ff00ff0, "shaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f70, 0x0ff00ff0, "shsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300ff0, 0x0ff00ff0, "shsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06300f50, 0x0ff00ff0, "shsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f70, 0x0ff00ff0, "ssub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100ff0, 0x0ff00ff0, "ssub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06100f50, 0x0ff00ff0, "ssubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f10, 0x0ff00ff0, "uadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f90, 0x0ff00ff0, "uadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f30, 0x0ff00ff0, "uaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f10, 0x0ff00ff0, "uhadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f90, 0x0ff00ff0, "uhadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f30, 0x0ff00ff0, "uhaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f70, 0x0ff00ff0, "uhsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700ff0, 0x0ff00ff0, "uhsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06700f50, 0x0ff00ff0, "uhsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f10, 0x0ff00ff0, "uqadd16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f90, 0x0ff00ff0, "uqadd8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f30, 0x0ff00ff0, "uqaddsubx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f70, 0x0ff00ff0, "uqsub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600ff0, 0x0ff00ff0, "uqsub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06600f50, 0x0ff00ff0, "uqsubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f70, 0x0ff00ff0, "usub16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500ff0, 0x0ff00ff0, "usub8%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06500f50, 0x0ff00ff0, "usubaddx%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0f30, 0x0fff0ff0, "rev%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0fb0, 0x0fff0ff0, "rev16%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ff0fb0, 0x0fff0ff0, "revsh%c\t\%12-15r, %0-3r"}, + {ARM_EXT_V6, 0xf8100a00, 0xfe50ffff, "rfe%23?id%24?ba\t\%16-19r%21'!"}, + {ARM_EXT_V6, 0x06bf0070, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06bf0470, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06bf0870, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06bf0c70, 0x0fff0ff0, "sxth%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x068f0070, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x068f0470, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x068f0870, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x068f0c70, 0x0fff0ff0, "sxtb16%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06af0070, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06af0470, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06af0870, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06af0c70, 0x0fff0ff0, "sxtb%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06ff0070, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ff0470, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06ff0870, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06ff0c70, 0x0fff0ff0, "uxth%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06cf0070, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06cf0470, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06cf0870, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06cf0c70, 0x0fff0ff0, "uxtb16%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06ef0070, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r"}, + {ARM_EXT_V6, 0x06ef0470, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06ef0870, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06ef0c70, 0x0fff0ff0, "uxtb%c\t%12-15r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06b00070, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06b00470, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06b00870, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06b00c70, 0x0ff00ff0, "sxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06800070, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06800470, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06800870, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06800c70, 0x0ff00ff0, "sxtab16%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06a00070, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06a00470, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06a00870, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06a00c70, 0x0ff00ff0, "sxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06f00070, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06f00470, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06f00870, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06f00c70, 0x0ff00ff0, "uxtah%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06c00070, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06c00470, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06c00870, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06c00c70, 0x0ff00ff0, "uxtab16%c\t%12-15r, %16-19r, %0-3r, ROR #24"}, + {ARM_EXT_V6, 0x06e00070, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0x06e00470, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #8"}, + {ARM_EXT_V6, 0x06e00870, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #16"}, + {ARM_EXT_V6, 0x06e00c70, 0x0ff00ff0, "uxtab%c\t%12-15r, %16-19r, %0-3r, ror #24"}, + {ARM_EXT_V6, 0x06800fb0, 0x0ff00ff0, "sel%c\t%12-15r, %16-19r, %0-3r"}, + {ARM_EXT_V6, 0xf1010000, 0xfffffc00, "setend\t%9?ble"}, + {ARM_EXT_V6, 0x0700f010, 0x0ff0f0d0, "smuad%5'x%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0700f050, 0x0ff0f0d0, "smusd%5'x%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07000010, 0x0ff000d0, "smlad%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x07400010, 0x0ff000d0, "smlald%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07000050, 0x0ff000d0, "smlsd%5'x%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x07400050, 0x0ff000d0, "smlsld%5'x%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0750f010, 0x0ff0f0d0, "smmul%5'r%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07500010, 0x0ff000d0, "smmla%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x075000d0, 0x0ff000d0, "smmls%5'r%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0xf84d0500, 0xfe5fffe0, "srs%23?id%24?ba\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6, 0x06a00010, 0x0fe00ff0, "ssat%c\t%12-15r, #%16-20W, %0-3r"}, + {ARM_EXT_V6, 0x06a00010, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06a00050, 0x0fe00070, "ssat%c\t%12-15r, #%16-20W, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x06a00f30, 0x0ff00ff0, "ssat16%c\t%12-15r, #%16-19W, %0-3r"}, + {ARM_EXT_V6, 0x01800f90, 0x0ff00ff0, "strex%c\t%12-15r, %0-3r, [%16-19r]"}, + {ARM_EXT_V6, 0x00400090, 0x0ff000f0, "umaal%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x0780f010, 0x0ff0f0f0, "usad8%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V6, 0x07800010, 0x0ff000f0, "usada8%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V6, 0x06e00010, 0x0fe00ff0, "usat%c\t%12-15r, #%16-20d, %0-3r"}, + {ARM_EXT_V6, 0x06e00010, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, lsl #%7-11d"}, + {ARM_EXT_V6, 0x06e00050, 0x0fe00070, "usat%c\t%12-15r, #%16-20d, %0-3r, asr #%7-11d"}, + {ARM_EXT_V6, 0x06e00f30, 0x0ff00ff0, "usat16%c\t%12-15r, #%16-19d, %0-3r"}, + + /* V5J instruction. */ + {ARM_EXT_V5J, 0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"}, + + /* V5 Instructions. */ + {ARM_EXT_V5, 0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"}, + {ARM_EXT_V5, 0xfa000000, 0xfe000000, "blx\t%B"}, + {ARM_EXT_V5, 0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"}, + {ARM_EXT_V5, 0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"}, + + /* V5E "El Segundo" Instructions. */ + {ARM_EXT_V5E, 0x000000d0, 0x0e1000f0, "ldrd%c\t%12-15r, %s"}, + {ARM_EXT_V5E, 0x000000f0, 0x0e1000f0, "strd%c\t%12-15r, %s"}, + {ARM_EXT_V5E, 0xf450f000, 0xfc70f000, "pld\t%a"}, + {ARM_EXT_V5ExP, 0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + + {ARM_EXT_V5ExP, 0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + {ARM_EXT_V5ExP, 0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, + + {ARM_EXT_V5ExP, 0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"}, + {ARM_EXT_V5ExP, 0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"}, + + {ARM_EXT_V5ExP, 0x01000050, 0x0ff00ff0, "qadd%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01200050, 0x0ff00ff0, "qsub%c\t%12-15r, %0-3r, %16-19r"}, + {ARM_EXT_V5ExP, 0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"}, + + /* ARM Instructions. */ + {ARM_EXT_V1, 0x00000090, 0x0e100090, "str%6's%5?hb%c\t%12-15r, %s"}, + {ARM_EXT_V1, 0x00100090, 0x0e100090, "ldr%6's%5?hb%c\t%12-15r, %s"}, + {ARM_EXT_V1, 0x00000000, 0x0de00000, "and%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00200000, 0x0de00000, "eor%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00400000, 0x0de00000, "sub%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00600000, 0x0de00000, "rsb%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00800000, 0x0de00000, "add%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00a00000, 0x0de00000, "adc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00c00000, 0x0de00000, "sbc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x00e00000, 0x0de00000, "rsc%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"}, + {ARM_EXT_V3, 0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"}, + {ARM_EXT_V1, 0x01000000, 0x0de00000, "tst%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01200000, 0x0de00000, "teq%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01400000, 0x0de00000, "cmp%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01600000, 0x0de00000, "cmn%p%c\t%16-19r, %o"}, + {ARM_EXT_V1, 0x01800000, 0x0de00000, "orr%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x03a00000, 0x0fef0000, "mov%20's%c\t%12-15r, %o"}, + {ARM_EXT_V1, 0x01a00000, 0x0def0ff0, "mov%20's%c\t%12-15r, %0-3r"}, + {ARM_EXT_V1, 0x01a00000, 0x0def0060, "lsl%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00020, 0x0def0060, "lsr%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00040, 0x0def0060, "asr%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01a00060, 0x0def0ff0, "rrx%20's%c\t%12-15r, %0-3r"}, + {ARM_EXT_V1, 0x01a00060, 0x0def0060, "ror%20's%c\t%12-15r, %q"}, + {ARM_EXT_V1, 0x01c00000, 0x0de00000, "bic%20's%c\t%12-15r, %16-19r, %o"}, + {ARM_EXT_V1, 0x01e00000, 0x0de00000, "mvn%20's%c\t%12-15r, %o"}, + {ARM_EXT_V1, 0x052d0004, 0x0fff0fff, "push%c\t{%12-15r}\t\t; (str%c %12-15r, %a)"}, + {ARM_EXT_V1, 0x04000000, 0x0e100000, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x06000000, 0x0e100ff0, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x04000000, 0x0c100010, "str%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x06000010, 0x0e000010, "undefined"}, + {ARM_EXT_V1, 0x049d0004, 0x0fff0fff, "pop%c\t{%12-15r}\t\t; (ldr%c %12-15r, %a)"}, + {ARM_EXT_V1, 0x04100000, 0x0c100000, "ldr%22'b%t%c\t%12-15r, %a"}, + {ARM_EXT_V1, 0x092d0000, 0x0fff0000, "push%c\t%m"}, + {ARM_EXT_V1, 0x08800000, 0x0ff00000, "stm%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08000000, 0x0e100000, "stm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08bd0000, 0x0fff0000, "pop%c\t%m"}, + {ARM_EXT_V1, 0x08900000, 0x0f900000, "ldm%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x08100000, 0x0e100000, "ldm%23?id%24?ba%c\t%16-19r%21'!, %m%22'^"}, + {ARM_EXT_V1, 0x0a000000, 0x0e000000, "b%24'l%c\t%b"}, + {ARM_EXT_V1, 0x0f000000, 0x0f000000, "svc%c\t%0-23x"}, + + /* The rest. */ + {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined instruction %0-31x"}, + {0, 0x00000000, 0x00000000, 0} +}; + +/* print_insn_thumb16 recognizes the following format control codes: + %S print Thumb register (bits 3..5 as high number if bit 6 set) + %D print Thumb register (bits 0..2 as high number if bit 7 set) %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 - %B print Thumb branch destination (signed displacement) - %W print (bitfield * 4) as a decimal + %M print Thumb register mask + %b print CZB's 6-bit unsigned branch destination + %s print Thumb right-shift immediate (6..10; 0 == 32). + %c print the condition code + %C print the condition code, or "s" if not conditional + %x print warning if conditional an not at end of IT block" + %X print "\t; unpredictable " if conditional + %I print IT instruction suffix and operands + %r print bitfield as an ARM register + %d print bitfield as a decimal %H print (bitfield * 2) as a decimal + %W print (bitfield * 4) as a decimal %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, "}, - {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, %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 */ + %B print Thumb branch destination (signed displacement) + %c print bitfield as a condition code + %'c print specified char iff bit is one + %?ab print a if bit is one else print b. */ -static struct thumb_opcode thumb_opcodes[] = +static const struct opcode16 thumb_opcodes[] = { /* Thumb instructions. */ + /* ARM V6K no-argument instructions. */ + {ARM_EXT_V6K, 0xbf00, 0xffff, "nop%c"}, + {ARM_EXT_V6K, 0xbf10, 0xffff, "yield%c"}, + {ARM_EXT_V6K, 0xbf20, 0xffff, "wfe%c"}, + {ARM_EXT_V6K, 0xbf30, 0xffff, "wfi%c"}, + {ARM_EXT_V6K, 0xbf40, 0xffff, "sev%c"}, + {ARM_EXT_V6K, 0xbf00, 0xff0f, "nop%c\t{%4-7d}"}, + + /* ARM V6T2 instructions. */ + {ARM_EXT_V6T2, 0xb900, 0xfd00, "cbnz\t%0-2r, %b%X"}, + {ARM_EXT_V6T2, 0xb100, 0xfd00, "cbz\t%0-2r, %b%X"}, + {ARM_EXT_V6T2, 0xbf00, 0xff00, "it%I%X"}, + + /* ARM V6. */ + {ARM_EXT_V6, 0xb660, 0xfff8, "cpsie\t%2'a%1'i%0'f%X"}, + {ARM_EXT_V6, 0xb670, 0xfff8, "cpsid\t%2'a%1'i%0'f%X"}, + {ARM_EXT_V6, 0x4600, 0xffc0, "mov%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xba00, 0xffc0, "rev%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xba40, 0xffc0, "rev16%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xbac0, 0xffc0, "revsh%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb650, 0xfff7, "setend\t%3?ble%X"}, + {ARM_EXT_V6, 0xb200, 0xffc0, "sxth%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb240, 0xffc0, "sxtb%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb280, 0xffc0, "uxth%c\t%0-2r, %3-5r"}, + {ARM_EXT_V6, 0xb2c0, 0xffc0, "uxtb%c\t%0-2r, %3-5r"}, + /* 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 - 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)"}, + {ARM_EXT_V5T, 0xbe00, 0xff00, "bkpt\t%0-7x"}, /* Is always unconditional. */ + /* This is BLX(2). BLX(1) is a 32-bit instruction. */ + {ARM_EXT_V5T, 0x4780, 0xff87, "blx%c\t%3-6r%x"}, /* note: 4 bit register number. */ + /* ARM V4T ISA (Thumb v1). */ + {ARM_EXT_V4T, 0x46C0, 0xFFFF, "nop%c\t\t\t(mov r8, r8)"}, /* 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"}, + {ARM_EXT_V4T, 0x4000, 0xFFC0, "and%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4040, 0xFFC0, "eor%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4080, 0xFFC0, "lsl%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x40C0, 0xFFC0, "lsr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4100, 0xFFC0, "asr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4140, 0xFFC0, "adc%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4180, 0xFFC0, "sbc%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x41C0, 0xFFC0, "ror%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4200, 0xFFC0, "tst%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4240, 0xFFC0, "neg%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4280, 0xFFC0, "cmp%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x42C0, 0xFFC0, "cmn%c\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4300, 0xFFC0, "orr%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4340, 0xFFC0, "mul%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x4380, 0xFFC0, "bic%C\t%0-2r, %3-5r"}, + {ARM_EXT_V4T, 0x43C0, 0xFFC0, "mvn%C\t%0-2r, %3-5r"}, /* format 13 */ - {0xB000, 0xFF80, "add\tsp, #%0-6W"}, - {0xB080, 0xFF80, "sub\tsp, #%0-6W"}, + {ARM_EXT_V4T, 0xB000, 0xFF80, "add%c\tsp, #%0-6W"}, + {ARM_EXT_V4T, 0xB080, 0xFF80, "sub%c\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"}, + {ARM_EXT_V4T, 0x4700, 0xFF80, "bx%c\t%S%x"}, + {ARM_EXT_V4T, 0x4400, 0xFF00, "add%c\t%D, %S"}, + {ARM_EXT_V4T, 0x4500, 0xFF00, "cmp%c\t%D, %S"}, + {ARM_EXT_V4T, 0x4600, 0xFF00, "mov%c\t%D, %S"}, /* format 14 */ - {0xB400, 0xFE00, "push\t%N"}, - {0xBC00, 0xFE00, "pop\t%O"}, + {ARM_EXT_V4T, 0xB400, 0xFE00, "push%c\t%N"}, + {ARM_EXT_V4T, 0xBC00, 0xFE00, "pop%c\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"}, + {ARM_EXT_V4T, 0x1800, 0xFE00, "add%C\t%0-2r, %3-5r, %6-8r"}, + {ARM_EXT_V4T, 0x1A00, 0xFE00, "sub%C\t%0-2r, %3-5r, %6-8r"}, + {ARM_EXT_V4T, 0x1C00, 0xFE00, "add%C\t%0-2r, %3-5r, #%6-8d"}, + {ARM_EXT_V4T, 0x1E00, 0xFE00, "sub%C\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]"}, + {ARM_EXT_V4T, 0x5200, 0xFE00, "strh%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5A00, 0xFE00, "ldrh%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5600, 0xF600, "ldrs%11?hb%c\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]"}, + {ARM_EXT_V4T, 0x5000, 0xFA00, "str%10'b%c\t%0-2r, [%3-5r, %6-8r]"}, + {ARM_EXT_V4T, 0x5800, 0xFA00, "ldr%10'b%c\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"}, + {ARM_EXT_V4T, 0x0000, 0xF800, "lsl%C\t%0-2r, %3-5r, #%6-10d"}, + {ARM_EXT_V4T, 0x0800, 0xF800, "lsr%C\t%0-2r, %3-5r, %s"}, + {ARM_EXT_V4T, 0x1000, 0xF800, "asr%C\t%0-2r, %3-5r, %s"}, /* 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"}, + {ARM_EXT_V4T, 0x2000, 0xF800, "mov%C\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x2800, 0xF800, "cmp%c\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x3000, 0xF800, "add%C\t%8-10r, #%0-7d"}, + {ARM_EXT_V4T, 0x3800, 0xF800, "sub%C\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,=" */ + {ARM_EXT_V4T, 0x4800, 0xF800, "ldr%c\t%8-10r, [pc, #%0-7W]\t(%0-7a)"}, /* TODO: Disassemble PC relative "LDR rD,=" */ /* 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]"}, + {ARM_EXT_V4T, 0x6000, 0xF800, "str%c\t%0-2r, [%3-5r, #%6-10W]"}, + {ARM_EXT_V4T, 0x6800, 0xF800, "ldr%c\t%0-2r, [%3-5r, #%6-10W]"}, + {ARM_EXT_V4T, 0x7000, 0xF800, "strb%c\t%0-2r, [%3-5r, #%6-10d]"}, + {ARM_EXT_V4T, 0x7800, 0xF800, "ldrb%c\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]"}, + {ARM_EXT_V4T, 0x8000, 0xF800, "strh%c\t%0-2r, [%3-5r, #%6-10H]"}, + {ARM_EXT_V4T, 0x8800, 0xF800, "ldrh%c\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]"}, + {ARM_EXT_V4T, 0x9000, 0xF800, "str%c\t%8-10r, [sp, #%0-7W]"}, + {ARM_EXT_V4T, 0x9800, 0xF800, "ldr%c\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"}, + {ARM_EXT_V4T, 0xA000, 0xF800, "add%c\t%8-10r, pc, #%0-7W\t(adr %8-10r, %0-7a)"}, + {ARM_EXT_V4T, 0xA800, 0xF800, "add%c\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"}, + {ARM_EXT_V4T, 0xC000, 0xF800, "stmia%c\t%8-10r!, %M"}, + {ARM_EXT_V4T, 0xC800, 0xF800, "ldmia%c\t%8-10r!, %M"}, /* 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} + {ARM_EXT_V4T, 0xDF00, 0xFF00, "svc%c\t%0-7d"}, + /* format 16 */ + {ARM_EXT_V4T, 0xDE00, 0xFE00, "undefined"}, + {ARM_EXT_V4T, 0xD000, 0xF000, "b%8-11c.n\t%0-7B%X"}, + /* format 18 */ + {ARM_EXT_V4T, 0xE000, 0xF800, "b%c.n\t%0-10B%x"}, + + /* The E800 .. FFFF range is unconditionally redirected to the + 32-bit table, because even in pre-V6T2 ISAs, BL and BLX(1) pairs + are processed via that table. Thus, we can never encounter a + bare "second half of BL/BLX(1)" instruction here. */ + {ARM_EXT_V1, 0x0000, 0x0000, "undefined"}, + {0, 0, 0, 0} }; -#define BDISP23(x) ((((((x) & 0x07ff) << 11) | (((x) & 0x07ff0000) >> 16)) \ - ^ 0x200000) - 0x200000) /* 23bit */ - -#ifndef streq -#define streq(a,b) (strcmp ((a), (b)) == 0) -#endif +/* Thumb32 opcodes use the same table structure as the ARM opcodes. + We adopt the convention that hw1 is the high 16 bits of .value and + .mask, hw2 the low 16 bits. + + print_insn_thumb32 recognizes the following format control codes: + + %% % + + %I print a 12-bit immediate from hw1[10],hw2[14:12,7:0] + %M print a modified 12-bit immediate (same location) + %J print a 16-bit immediate from hw1[3:0,10],hw2[14:12,7:0] + %K print a 16-bit immediate from hw2[3:0],hw1[3:0],hw2[11:4] + %S print a possibly-shifted Rm + + %a print the address of a plain load/store + %w print the width and signedness of a core load/store + %m print register mask for ldm/stm + + %E print the lsb and width fields of a bfc/bfi instruction + %F print the lsb and width fields of a sbfx/ubfx instruction + %b print a conditional branch offset + %B print an unconditional branch offset + %s print the shift field of an SSAT instruction + %R print the rotation field of an SXT instruction + %U print barrier type. + %P print address for pli instruction. + %c print the condition code + %x print warning if conditional an not at end of IT block" + %X print "\t; unpredictable " if conditional + + %d print bitfield in decimal + %W print bitfield*4 in decimal + %r print bitfield as an ARM register + %c print bitfield as a condition code + + %'c print specified char iff bitfield is all ones + %`c print specified char iff bitfield is all zeroes + %?ab... select from array of values in big endian order + + With one exception at the bottom (done because BL and BLX(1) need + to come dead last), this table was machine-sorted first in + decreasing order of number of bits set in the mask, then in + increasing numeric order of mask, then in increasing numeric order + of opcode. This order is not the clearest for a human reader, but + is guaranteed never to catch a special-case bit pattern with a more + general mask, which is important, because this instruction encoding + makes heavy use of special-case bit patterns. */ +static const struct opcode32 thumb32_opcodes[] = +{ + /* V7 instructions. */ + {ARM_EXT_V7, 0xf910f000, 0xff70f000, "pli%c\t%a"}, + {ARM_EXT_V7, 0xf3af80f0, 0xfffffff0, "dbg%c\t#%0-3d"}, + {ARM_EXT_V7, 0xf3bf8f50, 0xfffffff0, "dmb%c\t%U"}, + {ARM_EXT_V7, 0xf3bf8f40, 0xfffffff0, "dsb%c\t%U"}, + {ARM_EXT_V7, 0xf3bf8f60, 0xfffffff0, "isb%c\t%U"}, + {ARM_EXT_DIV, 0xfb90f0f0, 0xfff0f0f0, "sdiv%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_DIV, 0xfbb0f0f0, 0xfff0f0f0, "udiv%c\t%8-11r, %16-19r, %0-3r"}, + + /* Instructions defined in the basic V6T2 set. */ + {ARM_EXT_V6T2, 0xf3af8000, 0xffffffff, "nop%c.w"}, + {ARM_EXT_V6T2, 0xf3af8001, 0xffffffff, "yield%c.w"}, + {ARM_EXT_V6T2, 0xf3af8002, 0xffffffff, "wfe%c.w"}, + {ARM_EXT_V6T2, 0xf3af8003, 0xffffffff, "wfi%c.w"}, + {ARM_EXT_V6T2, 0xf3af9004, 0xffffffff, "sev%c.w"}, + {ARM_EXT_V6T2, 0xf3af8000, 0xffffff00, "nop%c.w\t{%0-7d}"}, + + {ARM_EXT_V6T2, 0xf3bf8f2f, 0xffffffff, "clrex%c"}, + {ARM_EXT_V6T2, 0xf3af8400, 0xffffff1f, "cpsie.w\t%7'a%6'i%5'f%X"}, + {ARM_EXT_V6T2, 0xf3af8600, 0xffffff1f, "cpsid.w\t%7'a%6'i%5'f%X"}, + {ARM_EXT_V6T2, 0xf3c08f00, 0xfff0ffff, "bxj%c\t%16-19r%x"}, + {ARM_EXT_V6T2, 0xe810c000, 0xffd0ffff, "rfedb%c\t%16-19r%21'!"}, + {ARM_EXT_V6T2, 0xe990c000, 0xffd0ffff, "rfeia%c\t%16-19r%21'!"}, + {ARM_EXT_V6T2, 0xf3ef8000, 0xffeff000, "mrs%c\t%8-11r, %D"}, + {ARM_EXT_V6T2, 0xf3af8100, 0xffffffe0, "cps\t#%0-4d%X"}, + {ARM_EXT_V6T2, 0xe8d0f000, 0xfff0fff0, "tbb%c\t[%16-19r, %0-3r]%x"}, + {ARM_EXT_V6T2, 0xe8d0f010, 0xfff0fff0, "tbh%c\t[%16-19r, %0-3r, lsl #1]%x"}, + {ARM_EXT_V6T2, 0xf3af8500, 0xffffff00, "cpsie\t%7'a%6'i%5'f, #%0-4d%X"}, + {ARM_EXT_V6T2, 0xf3af8700, 0xffffff00, "cpsid\t%7'a%6'i%5'f, #%0-4d%X"}, + {ARM_EXT_V6T2, 0xf3de8f00, 0xffffff00, "subs%c\tpc, lr, #%0-7d"}, + {ARM_EXT_V6T2, 0xf3808000, 0xffe0f000, "msr%c\t%C, %16-19r"}, + {ARM_EXT_V6T2, 0xe8500f00, 0xfff00fff, "ldrex%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe8d00f4f, 0xfff00fef, "ldrex%4?hb%c\t%12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe800c000, 0xffd0ffe0, "srsdb%c\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6T2, 0xe980c000, 0xffd0ffe0, "srsia%c\t%16-19r%21'!, #%0-4d"}, + {ARM_EXT_V6T2, 0xfa0ff080, 0xfffff0c0, "sxth%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa1ff080, 0xfffff0c0, "uxth%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa2ff080, 0xfffff0c0, "sxtb16%c\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa3ff080, 0xfffff0c0, "uxtb16%c\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa4ff080, 0xfffff0c0, "sxtb%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa5ff080, 0xfffff0c0, "uxtb%c.w\t%8-11r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xe8400000, 0xfff000ff, "strex%c\t%8-11r, %12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe8d0007f, 0xfff000ff, "ldrexd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xfa80f000, 0xfff0f0f0, "sadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f010, 0xfff0f0f0, "qadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f020, 0xfff0f0f0, "shadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f040, 0xfff0f0f0, "uadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f050, 0xfff0f0f0, "uqadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f060, 0xfff0f0f0, "uhadd8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa80f080, 0xfff0f0f0, "qadd%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f090, 0xfff0f0f0, "qdadd%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f0a0, 0xfff0f0f0, "qsub%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa80f0b0, 0xfff0f0f0, "qdsub%c\t%8-11r, %0-3r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f000, 0xfff0f0f0, "sadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f010, 0xfff0f0f0, "qadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f020, 0xfff0f0f0, "shadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f040, 0xfff0f0f0, "uadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f050, 0xfff0f0f0, "uqadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f060, 0xfff0f0f0, "uhadd16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa90f080, 0xfff0f0f0, "rev%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f090, 0xfff0f0f0, "rev16%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f0a0, 0xfff0f0f0, "rbit%c\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfa90f0b0, 0xfff0f0f0, "revsh%c.w\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfaa0f000, 0xfff0f0f0, "saddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f010, 0xfff0f0f0, "qaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f020, 0xfff0f0f0, "shaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f040, 0xfff0f0f0, "uaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f050, 0xfff0f0f0, "uqaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f060, 0xfff0f0f0, "uhaddsubx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfaa0f080, 0xfff0f0f0, "sel%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfab0f080, 0xfff0f0f0, "clz%c\t%8-11r, %16-19r"}, + {ARM_EXT_V6T2, 0xfac0f000, 0xfff0f0f0, "ssub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f010, 0xfff0f0f0, "qsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f020, 0xfff0f0f0, "shsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f040, 0xfff0f0f0, "usub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f050, 0xfff0f0f0, "uqsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfac0f060, 0xfff0f0f0, "uhsub8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f000, 0xfff0f0f0, "ssub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f010, 0xfff0f0f0, "qsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f020, 0xfff0f0f0, "shsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f040, 0xfff0f0f0, "usub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f050, 0xfff0f0f0, "uqsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfad0f060, 0xfff0f0f0, "uhsub16%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f000, 0xfff0f0f0, "ssubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f010, 0xfff0f0f0, "qsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f020, 0xfff0f0f0, "shsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f040, 0xfff0f0f0, "usubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f050, 0xfff0f0f0, "uqsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfae0f060, 0xfff0f0f0, "uhsubaddx%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb00f000, 0xfff0f0f0, "mul%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb70f000, 0xfff0f0f0, "usad8%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa00f000, 0xffe0f0f0, "lsl%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa20f000, 0xffe0f0f0, "lsr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa40f000, 0xffe0f0f0, "asr%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa60f000, 0xffe0f0f0, "ror%20's%c.w\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xe8c00f40, 0xfff00fe0, "strex%4?hb%c\t%0-3r, %12-15r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xf3200000, 0xfff0f0e0, "ssat16%c\t%8-11r, #%0-4d, %16-19r"}, + {ARM_EXT_V6T2, 0xf3a00000, 0xfff0f0e0, "usat16%c\t%8-11r, #%0-4d, %16-19r"}, + {ARM_EXT_V6T2, 0xfb20f000, 0xfff0f0e0, "smuad%4'x%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb30f000, 0xfff0f0e0, "smulw%4?tb%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb40f000, 0xfff0f0e0, "smusd%4'x%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfb50f000, 0xfff0f0e0, "smmul%4'r%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfa00f080, 0xfff0f0c0, "sxtah%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa10f080, 0xfff0f0c0, "uxtah%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa20f080, 0xfff0f0c0, "sxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa30f080, 0xfff0f0c0, "uxtab16%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa40f080, 0xfff0f0c0, "sxtab%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfa50f080, 0xfff0f0c0, "uxtab%c\t%8-11r, %16-19r, %0-3r%R"}, + {ARM_EXT_V6T2, 0xfb10f000, 0xfff0f0c0, "smul%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xf36f0000, 0xffff8020, "bfc%c\t%8-11r, %E"}, + {ARM_EXT_V6T2, 0xea100f00, 0xfff08f00, "tst%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xea900f00, 0xfff08f00, "teq%c\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb100f00, 0xfff08f00, "cmn%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xebb00f00, 0xfff08f00, "cmp%c.w\t%16-19r, %S"}, + {ARM_EXT_V6T2, 0xf0100f00, 0xfbf08f00, "tst%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0900f00, 0xfbf08f00, "teq%c\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1100f00, 0xfbf08f00, "cmn%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1b00f00, 0xfbf08f00, "cmp%c.w\t%16-19r, %M"}, + {ARM_EXT_V6T2, 0xea4f0000, 0xffef8000, "mov%20's%c.w\t%8-11r, %S"}, + {ARM_EXT_V6T2, 0xea6f0000, 0xffef8000, "mvn%20's%c.w\t%8-11r, %S"}, + {ARM_EXT_V6T2, 0xe8c00070, 0xfff000f0, "strexd%c\t%0-3r, %12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xfb000000, 0xfff000f0, "mla%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb000010, 0xfff000f0, "mls%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb700000, 0xfff000f0, "usada8%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb800000, 0xfff000f0, "smull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfba00000, 0xfff000f0, "umull%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbc00000, 0xfff000f0, "smlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbe00000, 0xfff000f0, "umlal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbe00060, 0xfff000f0, "umaal%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xe8500f00, 0xfff00f00, "ldrex%c\t%12-15r, [%16-19r, #%0-7W]"}, + {ARM_EXT_V6T2, 0xf7f08000, 0xfff0f000, "smc%c\t%K"}, + {ARM_EXT_V6T2, 0xf04f0000, 0xfbef8000, "mov%20's%c.w\t%8-11r, %M"}, + {ARM_EXT_V6T2, 0xf06f0000, 0xfbef8000, "mvn%20's%c.w\t%8-11r, %M"}, + {ARM_EXT_V6T2, 0xf810f000, 0xff70f000, "pld%c\t%a"}, + {ARM_EXT_V6T2, 0xfb200000, 0xfff000e0, "smlad%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb300000, 0xfff000e0, "smlaw%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb400000, 0xfff000e0, "smlsd%4'x%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb500000, 0xfff000e0, "smmla%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfb600000, 0xfff000e0, "smmls%4'r%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfbc000c0, 0xfff000e0, "smlald%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xfbd000c0, 0xfff000e0, "smlsld%4'x%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xeac00000, 0xfff08030, "pkhbt%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeac00020, 0xfff08030, "pkhtb%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xf3400000, 0xfff08020, "sbfx%c\t%8-11r, %16-19r, %F"}, + {ARM_EXT_V6T2, 0xf3c00000, 0xfff08020, "ubfx%c\t%8-11r, %16-19r, %F"}, + {ARM_EXT_V6T2, 0xf8000e00, 0xff900f00, "str%wt%c\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xfb100000, 0xfff000c0, "smla%5?tb%4?tb%c\t%8-11r, %16-19r, %0-3r, %12-15r"}, + {ARM_EXT_V6T2, 0xfbc00080, 0xfff000c0, "smlal%5?tb%4?tb%c\t%12-15r, %8-11r, %16-19r, %0-3r"}, + {ARM_EXT_V6T2, 0xf3600000, 0xfff08020, "bfi%c\t%8-11r, %16-19r, %E"}, + {ARM_EXT_V6T2, 0xf8100e00, 0xfe900f00, "ldr%wt%c\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xf3000000, 0xffd08020, "ssat%c\t%8-11r, #%0-4d, %16-19r%s"}, + {ARM_EXT_V6T2, 0xf3800000, 0xffd08020, "usat%c\t%8-11r, #%0-4d, %16-19r%s"}, + {ARM_EXT_V6T2, 0xf2000000, 0xfbf08000, "addw%c\t%8-11r, %16-19r, %I"}, + {ARM_EXT_V6T2, 0xf2400000, 0xfbf08000, "movw%c\t%8-11r, %J"}, + {ARM_EXT_V6T2, 0xf2a00000, 0xfbf08000, "subw%c\t%8-11r, %16-19r, %I"}, + {ARM_EXT_V6T2, 0xf2c00000, 0xfbf08000, "movt%c\t%8-11r, %J"}, + {ARM_EXT_V6T2, 0xea000000, 0xffe08000, "and%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea200000, 0xffe08000, "bic%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea400000, 0xffe08000, "orr%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea600000, 0xffe08000, "orn%20's%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xea800000, 0xffe08000, "eor%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb000000, 0xffe08000, "add%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb400000, 0xffe08000, "adc%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeb600000, 0xffe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xeba00000, 0xffe08000, "sub%20's%c.w\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xebc00000, 0xffe08000, "rsb%20's%c\t%8-11r, %16-19r, %S"}, + {ARM_EXT_V6T2, 0xe8400000, 0xfff00000, "strex%c\t%8-11r, %12-15r, [%16-19r, #%0-7W]"}, + {ARM_EXT_V6T2, 0xf0000000, 0xfbe08000, "and%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0200000, 0xfbe08000, "bic%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0400000, 0xfbe08000, "orr%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0600000, 0xfbe08000, "orn%20's%c\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf0800000, 0xfbe08000, "eor%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1000000, 0xfbe08000, "add%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1400000, 0xfbe08000, "adc%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1600000, 0xfbe08000, "sbc%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1a00000, 0xfbe08000, "sub%20's%c.w\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xf1c00000, 0xfbe08000, "rsb%20's%c\t%8-11r, %16-19r, %M"}, + {ARM_EXT_V6T2, 0xe8800000, 0xffd00000, "stmia%c.w\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe8900000, 0xffd00000, "ldmia%c.w\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9000000, 0xffd00000, "stmdb%c\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9100000, 0xffd00000, "ldmdb%c\t%16-19r%21'!, %m"}, + {ARM_EXT_V6T2, 0xe9c00000, 0xffd000ff, "strd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe9d00000, 0xffd000ff, "ldrd%c\t%12-15r, %8-11r, [%16-19r]"}, + {ARM_EXT_V6T2, 0xe9400000, 0xff500000, "strd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, + {ARM_EXT_V6T2, 0xe9500000, 0xff500000, "ldrd%c\t%12-15r, %8-11r, [%16-19r, #%23`-%0-7W]%21'!"}, + {ARM_EXT_V6T2, 0xe8600000, 0xff700000, "strd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, + {ARM_EXT_V6T2, 0xe8700000, 0xff700000, "ldrd%c\t%12-15r, %8-11r, [%16-19r], #%23`-%0-7W"}, + {ARM_EXT_V6T2, 0xf8000000, 0xff100000, "str%w%c.w\t%12-15r, %a"}, + {ARM_EXT_V6T2, 0xf8100000, 0xfe100000, "ldr%w%c.w\t%12-15r, %a"}, + + /* Filter out Bcc with cond=E or F, which are used for other instructions. */ + {ARM_EXT_V6T2, 0xf3c08000, 0xfbc0d000, "undefined (bcc, cond=0xF)"}, + {ARM_EXT_V6T2, 0xf3808000, 0xfbc0d000, "undefined (bcc, cond=0xE)"}, + {ARM_EXT_V6T2, 0xf0008000, 0xf800d000, "b%22-25c.w\t%b%X"}, + {ARM_EXT_V6T2, 0xf0009000, 0xf800d000, "b%c.w\t%B%x"}, + + /* These have been 32-bit since the invention of Thumb. */ + {ARM_EXT_V4T, 0xf000c000, 0xf800d000, "blx%c\t%B%x"}, + {ARM_EXT_V4T, 0xf000d000, 0xf800d000, "bl%c\t%B%x"}, + + /* Fallback. */ + {ARM_EXT_V1, 0x00000000, 0x00000000, "undefined"}, + {0, 0, 0, 0} +}; -#ifndef strneq -#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) -#endif +static const char *const arm_conditional[] = +{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", "", ""}; -#ifndef NUM_ELEM -#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) -#endif +static const char *const arm_fp_const[] = +{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"}; -static char * arm_conditional[] = -{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le", "", "nv"}; +static const char *const arm_shift[] = +{"lsl", "lsr", "asr", "ror"}; typedef struct { - const char * name; - const char * description; - const char * reg_names[16]; + const char *name; + const char *description; + const char *reg_names[16]; } arm_regname; -static arm_regname regnames[] = +static const arm_regname regnames[] = { { "raw" , "Select raw register names", { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, @@ -557,44 +1503,67 @@ static arm_regname regnames[] = { "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" }} + { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}, +}; + +static const char *const iwmmxt_wwnames[] = +{"b", "h", "w", "d"}; + +static const char *const iwmmxt_wwssnames[] = +{"b", "bus", "bc", "bss", + "h", "hus", "hc", "hss", + "w", "wus", "wc", "wss", + "d", "dus", "dc", "dss" }; -/* Default to STD register name set. */ -static unsigned int regname_selected = 2; +static const char *const iwmmxt_regnames[] = +{ "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", + "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15" +}; + +static const char *const iwmmxt_cregnames[] = +{ "wcid", "wcon", "wcssf", "wcasf", "reserved", "reserved", "reserved", "reserved", + "wcgr0", "wcgr1", "wcgr2", "wcgr3", "reserved", "reserved", "reserved", "reserved" +}; + +/* Default to GCC register name set. */ +static unsigned int regname_selected = 1; #define NUM_ARM_REGNAMES NUM_ELEM (regnames) #define arm_regnames regnames[regname_selected].reg_names -static boolean force_thumb = false; +static bfd_boolean force_thumb = FALSE; + +/* Current IT instruction state. This contains the same state as the IT + bits in the CPSR. */ +static unsigned int ifthen_state; +/* IT state for the next instruction. */ +static unsigned int ifthen_next_state; +/* The address of the insn for which the IT state is valid. */ +static bfd_vma ifthen_address; +#define IFTHEN_COND ((ifthen_state >> 4) & 0xf) + +/* Cached mapping symbol state. */ +enum map_type { + MAP_ARM, + MAP_THUMB, + MAP_DATA +}; -static char * arm_fp_const[] = -{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"}; +enum map_type last_type; +int last_mapping_sym = -1; +bfd_vma last_mapping_addr = 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 () +get_arm_regname_num_options (void) { return NUM_ARM_REGNAMES; } int -set_arm_regname_option (option) - int option; +set_arm_regname_option (int option) { int old = regname_selected; regname_selected = option; @@ -602,11 +1571,8 @@ set_arm_regname_option (option) } int -get_arm_regnames (option, setname, setdescription, register_names) - int option; - const char **setname; - const char **setdescription; - const char ***register_names; +get_arm_regnames (int option, const char **setname, const char **setdescription, + const char *const **register_names) { *setname = regnames[option].name; *setdescription = regnames[option].description; @@ -614,11 +1580,46 @@ get_arm_regnames (option, setname, setdescription, register_names) return 16; } +/* Decode a bitfield of the form matching regexp (N(-N)?,)*N(-N)?. + Returns pointer to following character of the format string and + fills in *VALUEP and *WIDTHP with the extracted value and number of + bits extracted. WIDTHP can be NULL. */ + +static const char * +arm_decode_bitfield (const char *ptr, unsigned long insn, + unsigned long *valuep, int *widthp) +{ + unsigned long value = 0; + int width = 0; + + do + { + int start, end; + int bits; + + for (start = 0; *ptr >= '0' && *ptr <= '9'; ptr++) + start = start * 10 + *ptr - '0'; + if (*ptr == '-') + for (end = 0, ptr++; *ptr >= '0' && *ptr <= '9'; ptr++) + end = end * 10 + *ptr - '0'; + else + end = start; + bits = end - start; + if (bits < 0) + abort (); + value |= ((insn >> start) & ((2ul << bits) - 1)) << width; + width += bits + 1; + } + while (*ptr++ == ','); + *valuep = value; + if (widthp) + *widthp = width; + return ptr - 1; +} + static void -arm_decode_shift (given, func, stream) - long given; - fprintf_ftype func; - void * stream; +arm_decode_shift (long given, fprintf_ftype func, void *stream, + int print_shift) { func (stream, "%s", arm_regnames[given & 0xf]); @@ -640,32 +1641,75 @@ arm_decode_shift (given, func, stream) amount = 32; } - func (stream, ", %s #%d", arm_shift[shift], amount); + if (print_shift) + func (stream, ", %s #%d", arm_shift[shift], amount); + else + func (stream, ", #%d", amount); } - else + else if (print_shift) func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5], arm_regnames[(given & 0xf00) >> 8]); + else + func (stream, ", %s", arm_regnames[(given & 0xf00) >> 8]); } } -/* Print one instruction from PC on INFO->STREAM. - Return the size of the instruction (always 4 on ARM). */ +/* Print one coprocessor instruction on INFO->STREAM. + Return TRUE if the instuction matched, FALSE if this is not a + recognised coprocessor instruction. */ -static int -print_insn_arm1 (pc, info, given) - bfd_vma pc; - struct disassemble_info * info; - long given; +static bfd_boolean +print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given, + bfd_boolean thumb) { - struct arm_opcode * insn; - void * stream = info->stream; - fprintf_ftype func = info->fprintf_func; - - for (insn = arm_opcodes; insn->assembler; insn++) + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + unsigned long mask; + unsigned long value; + int cond; + + for (insn = coprocessor_opcodes; insn->assembler; insn++) { - if ((given & insn->mask) == insn->value) + if (insn->value == FIRST_IWMMXT_INSN + && info->mach != bfd_mach_arm_XScale + && info->mach != bfd_mach_arm_iWMMXt + && info->mach != bfd_mach_arm_iWMMXt2) + insn = insn + IWMMXT_INSN_COUNT; + + mask = insn->mask; + value = insn->value; + if (thumb) + { + /* The high 4 bits are 0xe for Arm conditional instructions, and + 0xe for arm unconditional instructions. The rest of the + encoding is the same. */ + mask |= 0xf0000000; + value |= 0xe0000000; + if (ifthen_state) + cond = IFTHEN_COND; + else + cond = 16; + } + else + { + /* Only match unconditional instuctions against unconditional + patterns. */ + if ((given & 0xf0000000) == 0xf0000000) + { + mask |= 0xf0000000; + cond = 16; + } + else + { + cond = (given >> 28) & 0xf; + if (cond == 0xe) + cond = 16; + } + } + if ((given & mask) == value) { - char * c; + const char *c; for (c = insn->assembler; *c; c++) { @@ -677,256 +1721,81 @@ print_insn_arm1 (pc, info, given) 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); + case 'A': + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); - offset += pc + 8; + if ((given & (1 << 24)) != 0) + { + int offset = given & 0xff; - /* 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, "!"); - } + if (offset) + func (stream, ", #%s%d]%s", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4, + ((given & 0x00200000) != 0 ? "!" : "")); else - { - /* Post indexed. */ - func (stream, "], #%d", offset); - - /* ie ignore the offset. */ - offset = pc + 8; - } - - func (stream, "\t; "); - info->print_address_func (offset, info); + func (stream, "]"); } 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); - } + int offset = given & 0xff; - func (stream, "]%s", - ((given & 0x00200000) != 0) ? "!" : ""); - } - else + func (stream, "]"); + + if (given & (1 << 21)) { - 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); - } + if (offset) + func (stream, ", #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4); } + else + func (stream, ", {%d}", offset); } break; - case 's': - if ((given & 0x004f0000) == 0x004f0000) - { - /* PC relative with immediate offset. */ - int offset = ((given & 0xf00) >> 4) | (given & 0xf); + case 'B': + { + int regno = ((given >> 12) & 0xf) | ((given >> (22 - 4)) & 0x10); + int offset = (given >> 1) & 0x3f; + + if (offset == 1) + func (stream, "{d%d}", regno); + else if (regno + offset > 32) + func (stream, "{d%d-}", regno, regno + offset - 1); + else + func (stream, "{d%d-d%d}", regno, regno + offset - 1); + } + break; - if ((given & 0x00800000) == 0) - offset = -offset; + case 'C': + { + int rn = (given >> 16) & 0xf; + int offset = (given & 0xff) * 4; + int add = (given >> 23) & 1; - func (stream, "[pc, #%d]\t; ", offset); + func (stream, "[%s", arm_regnames[rn]); - (*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; + if (offset) + { + if (!add) + offset = -offset; + func (stream, ", #%d", offset); + } + func (stream, "]"); + if (rn == 15) + { + func (stream, "\t; "); + /* FIXME: Unsure if info->bytes_per_chunk is the + right thing to use here. */ + info->print_address_func (offset + pc + + info->bytes_per_chunk * 2, 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); - } + func (stream, "%s", arm_conditional[cond]); break; case 'I': @@ -948,18 +1817,6 @@ print_insn_arm1 (pc, info, given) 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) { @@ -1031,188 +1888,256 @@ print_insn_arm1 (pc, info, given) 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'; + int width; + unsigned long value; + + c = arm_decode_bitfield (c, given, &value, &width); switch (*c) { - case '-': - c++; + case 'r': + func (stream, "%s", arm_regnames[value]); + break; + case 'D': + func (stream, "d%ld", value); + break; + case 'Q': + if (value & 1) + func (stream, "", value >> 1); + else + func (stream, "q%ld", value >> 1); + break; + case 'd': + func (stream, "%ld", value); + break; + case 'k': + { + int from = (given & (1 << 7)) ? 32 : 16; + func (stream, "%ld", from - value); + } + break; + + case 'f': + if (value > 7) + func (stream, "#%s", arm_fp_const[value & 7]); + else + func (stream, "f%ld", value); + break; - while (*c >= '0' && *c <= '9') - bitend = (bitend * 10) + *c++ - '0'; + case 'w': + if (width == 2) + func (stream, "%s", iwmmxt_wwnames[value]); + else + func (stream, "%s", iwmmxt_wwssnames[value]); + break; - if (!bitend) - abort (); + case 'g': + func (stream, "%s", iwmmxt_regnames[value]); + break; + case 'G': + func (stream, "%s", iwmmxt_cregnames[value]); + break; - switch (*c) - { - case 'r': - { - long reg; + case 'x': + func (stream, "0x%lx", value); + break; + + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; - reg = given >> bitstart; - reg &= (2 << (bitend - bitstart)) - 1; + case 'y': + case 'z': + { + int single = *c++ == 'y'; + int regno; - func (stream, "%s", arm_regnames[reg]); - } - break; - case 'd': + switch (*c) + { + case '4': /* Sm pair */ + func (stream, "{"); + /* Fall through. */ + case '0': /* Sm, Dm */ + regno = given & 0x0000000f; + if (single) { - long reg; + regno <<= 1; + regno += (given >> 5) & 1; + } + else + regno += ((given >> 5) & 1) << 4; + break; - reg = given >> bitstart; - reg &= (2 << (bitend - bitstart)) - 1; + case '1': /* Sd, Dd */ + regno = (given >> 12) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 22) & 1; + } + else + regno += ((given >> 22) & 1) << 4; + break; - func (stream, "%d", reg); + case '2': /* Sn, Dn */ + regno = (given >> 16) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 7) & 1; } - break; - case 'x': + else + regno += ((given >> 7) & 1) << 4; + break; + + case '3': /* List */ + func (stream, "{"); + regno = (given >> 12) & 0x0000000f; + if (single) { - long reg; + regno <<= 1; + regno += (given >> 22) & 1; + } + else + regno += ((given >> 22) & 1) << 4; + break; - reg = given >> bitstart; - reg &= (2 << (bitend - bitstart)) - 1; + default: + abort (); + } - func (stream, "0x%08x", reg); + func (stream, "%c%d", single ? 's' : 'd', regno); - /* 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; + if (*c == '3') + { + int count = given & 0xff; - reg = given >> bitstart; - reg &= (2 << (bitend - bitstart)) - 1; + if (single == 0) + count >>= 1; - func (stream, "%01x", reg & 0xf); - } - break; - case 'f': + if (--count) { - long reg; + func (stream, "-%c%d", + single ? 's' : 'd', + regno + count); + } - reg = given >> bitstart; - reg &= (2 << (bitend - bitstart)) - 1; + func (stream, "}"); + } + else if (*c == '4') + func (stream, ", %c%d}", single ? 's' : 'd', + regno + 1); + } + break; - if (reg > 7) - func (stream, "#%s", - arm_fp_const[reg & 7]); - else - func (stream, "f%d", reg); - } - break; - default: - abort (); - } + case 'L': + switch (given & 0x00400100) + { + case 0x00000000: func (stream, "b"); break; + case 0x00400000: func (stream, "h"); break; + case 0x00000100: func (stream, "w"); break; + case 0x00400100: func (stream, "d"); break; + default: break; + } + 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 (); - } + case 'Z': + { + int value; + /* given (20, 23) | given (0, 3) */ + value = ((given >> 16) & 0xf0) | (given & 0xf); + func (stream, "%d", value); + } + break; - func (stream, "%c%d", single ? 's' : 'd', regno); + case 'l': + /* This is like the 'A' operator, except that if + the width field "M" is zero, then the offset is + *not* multiplied by four. */ + { + int offset = given & 0xff; + int multiplier = (given & 0x00000100) ? 4 : 1; - if (bitstart == 3) - { - int count = given & 0xff; + func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); - if (single == 0) - count >>= 1; + if (offset) + { + if ((given & 0x01000000) != 0) + func (stream, ", #%s%d]%s", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * multiplier, + ((given & 0x00200000) != 0 ? "!" : "")); + else + func (stream, "], #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * multiplier); + } + else + func (stream, "]"); + } + break; - if (--count) - { - func (stream, "-%c%d", - single ? 's' : 'd', - regno + count); - } + case 'r': + { + int imm4 = (given >> 4) & 0xf; + int puw_bits = ((given >> 22) & 6) | ((given >> 21) & 1); + int ubit = (given >> 23) & 1; + const char *rm = arm_regnames [given & 0xf]; + const char *rn = arm_regnames [(given >> 16) & 0xf]; - func (stream, "}"); - } - else if (bitstart == 4) - func (stream, ", %c%d}", single ? 's' : 'd', - regno + 1); + switch (puw_bits) + { + case 1: + /* fall through */ + case 3: + func (stream, "[%s], %c%s", rn, ubit ? '+' : '-', rm); + if (imm4) + func (stream, ", lsl #%d", imm4); + break; + case 4: + /* fall through */ + case 5: + /* fall through */ + case 6: + /* fall through */ + case 7: + func (stream, "[%s, %c%s", rn, ubit ? '+' : '-', rm); + if (imm4 > 0) + func (stream, ", lsl #%d", imm4); + func (stream, "]"); + if (puw_bits == 5 || puw_bits == 7) + func (stream, "!"); break; + + default: + func (stream, "INVALID"); } + } + 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 (); - } + case 'i': + { + long imm5; + imm5 = ((given & 0x100) >> 4) | (given & 0xf); + func (stream, "%ld", (imm5 == 0) ? 32 : imm5); + } break; default: @@ -1223,329 +2148,1768 @@ print_insn_arm1 (pc, info, given) else func (stream, "%c", *c); } - return 4; + return TRUE; } } - abort (); + return FALSE; } -/* 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; +static void +print_arm_address (bfd_vma pc, struct disassemble_info *info, long given) { - struct thumb_opcode * insn; - void * stream = info->stream; - fprintf_ftype func = info->fprintf_func; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; - for (insn = thumb_opcodes; insn->assembler; insn++) + if (((given & 0x000f0000) == 0x000f0000) + && ((given & 0x02000000) == 0)) { - if ((given & insn->mask) == insn->value) - { - char * c = insn->assembler; + int offset = given & 0xfff; - /* Special processing for Thumb 2 instruction BL sequence: */ - if (!*c) /* Check for empty (not NULL) assembler string. */ - { - long offset; + func (stream, "[pc"); - 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; + if (given & 0x01000000) + { + if ((given & 0x00800000) == 0) + offset = - offset; - case 'D': - { - long reg; + /* Pre-indexed. */ + func (stream, ", #%d]", offset); - reg = given & 0x7; - if (given & (1 << 7)) - reg += 8; + offset += pc + 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; + /* 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); - func (stream, "{"); + /* ie ignore the offset. */ + offset = pc + 8; + } - /* 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]); - } + 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, 1); + } - if (domasklr) - { - if (started) - func (stream, ", "); - started = 1; - func (stream, arm_regnames[14] /* "lr" */); - } + 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, 1); + } + } + } +} + +/* Print one neon instruction on INFO->STREAM. + Return TRUE if the instuction matched, FALSE if this is not a + recognised neon instruction. */ + +static bfd_boolean +print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (thumb) + { + if ((given & 0xef000000) == 0xef000000) + { + /* move bit 28 to bit 24 to translate Thumb2 to ARM encoding. */ + unsigned long bit28 = given & (1 << 28); + + given &= 0x00ffffff; + if (bit28) + given |= 0xf3000000; + else + given |= 0xf2000000; + } + else if ((given & 0xff000000) == 0xf9000000) + given ^= 0xf9000000 ^ 0xf4000000; + else + return FALSE; + } + + for (insn = neon_opcodes; insn->assembler; insn++) + { + if ((given & insn->mask) == insn->value) + { + const char *c; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (thumb && ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'A': + { + static const unsigned char enc[16] = + { + 0x4, 0x14, /* st4 0,1 */ + 0x4, /* st1 2 */ + 0x4, /* st2 3 */ + 0x3, /* st3 4 */ + 0x13, /* st3 5 */ + 0x3, /* st1 6 */ + 0x1, /* st1 7 */ + 0x2, /* st2 8 */ + 0x12, /* st2 9 */ + 0x2, /* st1 10 */ + 0, 0, 0, 0, 0 + }; + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int align = ((given >> 4) & 0x3); + int type = ((given >> 8) & 0xf); + int n = enc[type] & 0xf; + int stride = (enc[type] >> 4) + 1; + int ix; + + func (stream, "{"); + if (stride > 1) + for (ix = 0; ix != n; ix++) + func (stream, "%sd%d", ix ? "," : "", rd + ix * stride); + else if (n == 1) + func (stream, "d%d", rd); + else + func (stream, "d%d-d%d", rd, rd + n - 1); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + func (stream, ", :%d", 32 << align); + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'B': + { + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int idx_align = ((given >> 4) & 0xf); + int align = 0; + int size = ((given >> 10) & 0x3); + int idx = idx_align >> (size + 1); + int length = ((given >> 8) & 3) + 1; + int stride = 1; + int i; + + if (length > 1 && size > 0) + stride = (idx_align & (1 << size)) ? 2 : 1; + + switch (length) + { + case 1: + { + int amask = (1 << size) - 1; + if ((idx_align & (1 << size)) != 0) + return FALSE; + if (size > 0) + { + if ((idx_align & amask) == amask) + align = 8 << size; + else if ((idx_align & amask) != 0) + return FALSE; + } + } + break; + + case 2: + if (size == 2 && (idx_align & 2) != 0) + return FALSE; + align = (idx_align & 1) ? 16 << size : 0; + break; + + case 3: + if ((size == 2 && (idx_align & 3) != 0) + || (idx_align & 1) != 0) + return FALSE; + break; + + case 4: + if (size == 2) + { + if ((idx_align & 3) == 3) + return FALSE; + align = (idx_align & 3) * 64; + } + else + align = (idx_align & 1) ? 32 << size : 0; + break; + + default: + abort (); + } + + func (stream, "{"); + for (i = 0; i < length; i++) + func (stream, "%sd%d[%d]", (i == 0) ? "" : ",", + rd + i * stride, idx); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + func (stream, ", :%d", align); + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'C': + { + int rd = ((given >> 12) & 0xf) | (((given >> 22) & 1) << 4); + int rn = ((given >> 16) & 0xf); + int rm = ((given >> 0) & 0xf); + int align = ((given >> 4) & 0x1); + int size = ((given >> 6) & 0x3); + int type = ((given >> 8) & 0x3); + int n = type + 1; + int stride = ((given >> 5) & 0x1); + int ix; + + if (stride && (n == 1)) + n++; + else + stride++; + + func (stream, "{"); + if (stride > 1) + for (ix = 0; ix != n; ix++) + func (stream, "%sd%d[]", ix ? "," : "", rd + ix * stride); + else if (n == 1) + func (stream, "d%d[]", rd); + else + func (stream, "d%d[]-d%d[]", rd, rd + n - 1); + func (stream, "}, [%s", arm_regnames[rn]); + if (align) + { + int align = (8 * (type + 1)) << size; + if (type == 3) + align = (size > 1) ? align >> 1 : align; + if (type == 2 || (type == 0 && !size)) + func (stream, ", :", align); + else + func (stream, ", :%d", align); + } + func (stream, "]"); + if (rm == 0xd) + func (stream, "!"); + else if (rm != 0xf) + func (stream, ", %s", arm_regnames[rm]); + } + break; + + case 'D': + { + int raw_reg = (given & 0xf) | ((given >> 1) & 0x10); + int size = (given >> 20) & 3; + int reg = raw_reg & ((4 << size) - 1); + int ix = raw_reg >> size >> 2; + + func (stream, "d%d[%d]", reg, ix); + } + break; + + case 'E': + /* Neon encoded constant for mov, mvn, vorr, vbic */ + { + int bits = 0; + int cmode = (given >> 8) & 0xf; + int op = (given >> 5) & 0x1; + unsigned long value = 0, hival = 0; + unsigned shift; + int size = 0; + int isfloat = 0; + + bits |= ((given >> 24) & 1) << 7; + bits |= ((given >> 16) & 7) << 4; + bits |= ((given >> 0) & 15) << 0; + + if (cmode < 8) + { + shift = (cmode >> 1) & 3; + value = (unsigned long)bits << (8 * shift); + size = 32; + } + else if (cmode < 12) + { + shift = (cmode >> 1) & 1; + value = (unsigned long)bits << (8 * shift); + size = 16; + } + else if (cmode < 14) + { + shift = (cmode & 1) + 1; + value = (unsigned long)bits << (8 * shift); + value |= (1ul << (8 * shift)) - 1; + size = 32; + } + else if (cmode == 14) + { + if (op) + { + /* bit replication into bytes */ + int ix; + unsigned long mask; + + value = 0; + hival = 0; + for (ix = 7; ix >= 0; ix--) + { + mask = ((bits >> ix) & 1) ? 0xff : 0; + if (ix <= 3) + value = (value << 8) | mask; + else + hival = (hival << 8) | mask; + } + size = 64; + } + else + { + /* byte replication */ + value = (unsigned long)bits; + size = 8; + } + } + else if (!op) + { + /* floating point encoding */ + int tmp; + + value = (unsigned long)(bits & 0x7f) << 19; + value |= (unsigned long)(bits & 0x80) << 24; + tmp = bits & 0x40 ? 0x3c : 0x40; + value |= (unsigned long)tmp << 24; + size = 32; + isfloat = 1; + } + else + { + func (stream, "", + bits, cmode, op); + size = 32; + break; + } + switch (size) + { + case 8: + func (stream, "#%ld\t; 0x%.2lx", value, value); + break; + + case 16: + func (stream, "#%ld\t; 0x%.4lx", value, value); + break; + + case 32: + if (isfloat) + { + unsigned char valbytes[4]; + double fvalue; + + /* Do this a byte at a time so we don't have to + worry about the host's endianness. */ + valbytes[0] = value & 0xff; + valbytes[1] = (value >> 8) & 0xff; + valbytes[2] = (value >> 16) & 0xff; + valbytes[3] = (value >> 24) & 0xff; + + floatformat_to_double + (&floatformat_ieee_single_little, valbytes, + &fvalue); + + func (stream, "#%.7g\t; 0x%.8lx", fvalue, + value); + } + else + func (stream, "#%ld\t; 0x%.8lx", + (long) ((value & 0x80000000) + ? value | ~0xffffffffl : value), value); + break; + + case 64: + func (stream, "#0x%.8lx%.8lx", hival, value); + break; + + default: + abort (); + } + } + break; + + case 'F': + { + int regno = ((given >> 16) & 0xf) | ((given >> (7 - 4)) & 0x10); + int num = (given >> 8) & 0x3; + + if (!num) + func (stream, "{d%d}", regno); + else if (num + regno >= 32) + func (stream, "{d%d-= '0' && *c <= '9') + limit = *c - '0'; + else if (*c >= 'a' && *c <= 'f') + limit = *c - 'a' + 10; + else + abort (); + low = limit >> 2; + high = limit & 3; + + if (value < low || value > high) + func (stream, "", base << value); + else + func (stream, "%d", base << value); + } + break; + case 'R': + if (given & (1 << 6)) + goto Q; + /* FALLTHROUGH */ + case 'D': + func (stream, "d%ld", value); + break; + case 'Q': + Q: + if (value & 1) + func (stream, "", value >> 1); + else + func (stream, "q%ld", value >> 1); + break; + + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; + + default: + abort (); + } + } + } + else + func (stream, "%c", *c); + } + return TRUE; + } + } + return FALSE; +} + +/* Print one ARM instruction from PC on INFO->STREAM. */ + +static void +print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given) +{ + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + if (print_insn_coprocessor (pc, info, given, FALSE)) + return; + + if (print_insn_neon (info, given, FALSE)) + return; + + for (insn = arm_opcodes; insn->assembler; insn++) + { + if (insn->value == FIRST_IWMMXT_INSN + && info->mach != bfd_mach_arm_XScale + && info->mach != bfd_mach_arm_iWMMXt) + insn = insn + IWMMXT_INSN_COUNT; + + if ((given & insn->mask) == insn->value + /* Special case: an instruction with all bits set in the condition field + (0xFnnn_nnnn) is only matched if all those bits are set in insn->mask, + or by the catchall at the end of the table. */ + && ((given & 0xF0000000) != 0xF0000000 + || (insn->mask & 0xF0000000) == 0xF0000000 + || (insn->mask == 0 && insn->value == 0))) + { + const char *c; + + for (c = insn->assembler; *c; c++) + { + if (*c == '%') + { + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'a': + print_arm_address (pc, info, given); + break; + + case 'P': + /* Set P address bit and use normal address + printing routine. */ + print_arm_address (pc, info, given | (1 << 24)); + 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': + { + int disp = (((given & 0xffffff) ^ 0x800000) - 0x800000); + info->print_address_func (disp*4 + pc + 8, info); + } + break; + + case 'c': + if (((given >> 28) & 0xf) != 0xe) + 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 'q': + arm_decode_shift (given, func, stream, 0); + 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, 1); + 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 & (1 << 24)) != 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; + + func (stream, "]"); + + if (given & (1 << 21)) + { + if (offset) + func (stream, ", #%s%d", + ((given & 0x00800000) == 0 ? "-" : ""), + offset * 4); + } + else + func (stream, ", {%d}", offset); + } + 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 '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 'U': + switch (given & 0xf) + { + case 0xf: func(stream, "sy"); break; + case 0x7: func(stream, "un"); break; + case 0xe: func(stream, "st"); break; + case 0x6: func(stream, "unst"); break; + default: + func(stream, "#%d", (int)given & 0xf); + break; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int width; + unsigned long value; + + c = arm_decode_bitfield (c, given, &value, &width); + + switch (*c) + { + case 'r': + func (stream, "%s", arm_regnames[value]); + break; + case 'd': + func (stream, "%ld", value); + break; + case 'b': + func (stream, "%ld", value * 8); + break; + case 'W': + func (stream, "%ld", value + 1); + break; + case 'x': + func (stream, "0x%08lx", value); + + /* 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': + func (stream, "%01lx", value & 0xf); + break; + case '`': + c++; + if (value == 0) + func (stream, "%c", *c); + break; + case '\'': + c++; + if (value == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + case '?': + func (stream, "%c", c[(1 << width) - (int)value]); + c += 1 << width; + break; + default: + abort (); + } + break; + + case 'e': + { + int imm; + + imm = (given & 0xf) | ((given & 0xfff00) >> 4); + func (stream, "%d", imm); + } + break; + + case 'E': + /* LSB and WIDTH fields of BFI or BFC. The machine- + language instruction encodes LSB and MSB. */ + { + long msb = (given & 0x001f0000) >> 16; + long lsb = (given & 0x00000f80) >> 7; + + long width = msb - lsb + 1; + if (width > 0) + func (stream, "#%lu, #%lu", lsb, width); + else + func (stream, "(invalid: %lu:%lu)", lsb, msb); + } + break; + + case 'V': + /* 16-bit unsigned immediate from a MOVT or MOVW + instruction, encoded in bits 0:11 and 15:19. */ + { + long hi = (given & 0x000f0000) >> 4; + long lo = (given & 0x00000fff); + long imm16 = hi | lo; + func (stream, "#%lu\t; 0x%lx", imm16, imm16); + } + break; + + default: + abort (); + } + } + } + else + func (stream, "%c", *c); + } + return; + } + } + abort (); +} + +/* Print one 16-bit Thumb instruction from PC on INFO->STREAM. */ + +static void +print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given) +{ + const struct opcode16 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; + + for (insn = thumb_opcodes; insn->assembler; insn++) + if ((given & insn->mask) == insn->value) + { + const char *c = insn->assembler; + for (; *c; c++) + { + int domaskpc = 0; + int domasklr = 0; + + if (*c != '%') + { + func (stream, "%c", *c); + continue; + } + + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'C': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + else + func (stream, "s"); + break; + + case 'I': + { + unsigned int tmp; + + ifthen_next_state = given & 0xff; + for (tmp = given << 1; tmp & 0xf; tmp <<= 1) + func (stream, ((given ^ tmp) & 0x10) ? "e" : "t"); + func (stream, "\t%s", arm_conditional[(given >> 4) & 0xf]); + } + break; + + case 'x': + if (ifthen_next_state) + func (stream, "\t; unpredictable branch in IT block\n"); + break; + + case 'X': + if (ifthen_state) + func (stream, "\t; unpredictable ", + arm_conditional[IFTHEN_COND]); + 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 '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" */); + } - if (domaskpc) - { - if (started) - func (stream, ", "); - func (stream, arm_regnames[15] /* "pc" */); - } + func (stream, "}"); + } + break; - func (stream, "}"); - } - break; + case 'b': + /* Print ARM V6T2 CZB address: pc+4+6 bits. */ + { + bfd_vma address = (pc + 4 + + ((given & 0x00f8) >> 2) + + ((given & 0x0200) >> 3)); + info->print_address_func (address, info); + } + break; + case 's': + /* Right shift immediate -- bits 6..10; 1-31 print + as themselves, 0 prints as 32. */ + { + long imm = (given & 0x07c0) >> 6; + if (imm == 0) + imm = 32; + func (stream, "#%ld", imm); + } + 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; + 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'; + 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; - } - } + 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, "%ld", reg); + break; + + case 'H': + func (stream, "%ld", reg << 1); + break; + + case 'W': + func (stream, "%ld", 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%04lx", reg); + break; + + case 'B': + reg = ((reg ^ (1 << bitend)) - (1 << bitend)); + info->print_address_func (reg * 2 + pc + 4, info); + break; + + case 'c': + func (stream, "%s", arm_conditional [reg]); + 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 (); + } + } + return; + } /* No match. */ abort (); } -/* Parse an individual disassembler option. */ +/* Return the name of an V7M special register. */ +static const char * +psr_name (int regno) +{ + switch (regno) + { + case 0: return "APSR"; + case 1: return "IAPSR"; + case 2: return "EAPSR"; + case 3: return "PSR"; + case 5: return "IPSR"; + case 6: return "EPSR"; + case 7: return "IEPSR"; + case 8: return "MSP"; + case 9: return "PSP"; + case 16: return "PRIMASK"; + case 17: return "BASEPRI"; + case 18: return "BASEPRI_MASK"; + case 19: return "FAULTMASK"; + case 20: return "CONTROL"; + default: return ""; + } +} + +/* Print one 32-bit Thumb instruction from PC on INFO->STREAM. */ -void -parse_arm_disassembler_option (option) - char * option; +static void +print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given) { - if (option == NULL) - return; + const struct opcode32 *insn; + void *stream = info->stream; + fprintf_ftype func = info->fprintf_func; - if (strneq (option, "reg-names-", 10)) - { - int i; + if (print_insn_coprocessor (pc, info, given, TRUE)) + return; - option += 10; + if (print_insn_neon (info, given, TRUE)) + return; - for (i = NUM_ARM_REGNAMES; i--;) - if (streq (option, regnames[i].name)) + for (insn = thumb32_opcodes; insn->assembler; insn++) + if ((given & insn->mask) == insn->value) + { + const char *c = insn->assembler; + for (; *c; c++) { - regname_selected = i; - break; - } + if (*c != '%') + { + func (stream, "%c", *c); + continue; + } + + switch (*++c) + { + case '%': + func (stream, "%%"); + break; + + case 'c': + if (ifthen_state) + func (stream, "%s", arm_conditional[IFTHEN_COND]); + break; + + case 'x': + if (ifthen_next_state) + func (stream, "\t; unpredictable branch in IT block\n"); + break; + + case 'X': + if (ifthen_state) + func (stream, "\t; unpredictable ", + arm_conditional[IFTHEN_COND]); + break; + + case 'I': + { + unsigned int imm12 = 0; + imm12 |= (given & 0x000000ffu); + imm12 |= (given & 0x00007000u) >> 4; + imm12 |= (given & 0x04000000u) >> 15; + func (stream, "#%u\t; 0x%x", imm12, imm12); + } + 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); + case 'M': + { + unsigned int bits = 0, imm, imm8, mod; + bits |= (given & 0x000000ffu); + bits |= (given & 0x00007000u) >> 4; + bits |= (given & 0x04000000u) >> 15; + imm8 = (bits & 0x0ff); + mod = (bits & 0xf00) >> 8; + switch (mod) + { + case 0: imm = imm8; break; + case 1: imm = ((imm8<<16) | imm8); break; + case 2: imm = ((imm8<<24) | (imm8 << 8)); break; + case 3: imm = ((imm8<<24) | (imm8 << 16) | (imm8 << 8) | imm8); break; + default: + mod = (bits & 0xf80) >> 7; + imm8 = (bits & 0x07f) | 0x80; + imm = (((imm8 << (32 - mod)) | (imm8 >> mod)) & 0xffffffff); + } + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'J': + { + unsigned int imm = 0; + imm |= (given & 0x000000ffu); + imm |= (given & 0x00007000u) >> 4; + imm |= (given & 0x04000000u) >> 15; + imm |= (given & 0x000f0000u) >> 4; + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'K': + { + unsigned int imm = 0; + imm |= (given & 0x000f0000u) >> 16; + imm |= (given & 0x00000ff0u) >> 0; + imm |= (given & 0x0000000fu) << 12; + func (stream, "#%u\t; 0x%x", imm, imm); + } + break; + + case 'S': + { + unsigned int reg = (given & 0x0000000fu); + unsigned int stp = (given & 0x00000030u) >> 4; + unsigned int imm = 0; + imm |= (given & 0x000000c0u) >> 6; + imm |= (given & 0x00007000u) >> 10; + + func (stream, "%s", arm_regnames[reg]); + switch (stp) + { + case 0: + if (imm > 0) + func (stream, ", lsl #%u", imm); + break; + + case 1: + if (imm == 0) + imm = 32; + func (stream, ", lsr #%u", imm); + break; + + case 2: + if (imm == 0) + imm = 32; + func (stream, ", asr #%u", imm); + break; + + case 3: + if (imm == 0) + func (stream, ", rrx"); + else + func (stream, ", ror #%u", imm); + } + } + break; + + case 'a': + { + unsigned int Rn = (given & 0x000f0000) >> 16; + unsigned int U = (given & 0x00800000) >> 23; + unsigned int op = (given & 0x00000f00) >> 8; + unsigned int i12 = (given & 0x00000fff); + unsigned int i8 = (given & 0x000000ff); + bfd_boolean writeback = FALSE, postind = FALSE; + int offset = 0; + + func (stream, "[%s", arm_regnames[Rn]); + if (U) /* 12-bit positive immediate offset */ + offset = i12; + else if (Rn == 15) /* 12-bit negative immediate offset */ + offset = -(int)i12; + else if (op == 0x0) /* shifted register offset */ + { + unsigned int Rm = (i8 & 0x0f); + unsigned int sh = (i8 & 0x30) >> 4; + func (stream, ", %s", arm_regnames[Rm]); + if (sh) + func (stream, ", lsl #%u", sh); + func (stream, "]"); + break; + } + else switch (op) + { + case 0xE: /* 8-bit positive immediate offset */ + offset = i8; + break; + + case 0xC: /* 8-bit negative immediate offset */ + offset = -i8; + break; + + case 0xF: /* 8-bit + preindex with wb */ + offset = i8; + writeback = TRUE; + break; + + case 0xD: /* 8-bit - preindex with wb */ + offset = -i8; + writeback = TRUE; + break; + + case 0xB: /* 8-bit + postindex */ + offset = i8; + postind = TRUE; + break; + + case 0x9: /* 8-bit - postindex */ + offset = -i8; + postind = TRUE; + break; + + default: + func (stream, ", ]"); + goto skip; + } + + if (postind) + func (stream, "], #%d", offset); + else + { + if (offset) + func (stream, ", #%d", offset); + func (stream, writeback ? "]!" : "]"); + } + + if (Rn == 15) + { + func (stream, "\t; "); + info->print_address_func (((pc + 4) & ~3) + offset, info); + } + } + skip: + break; + + case 'A': + { + unsigned int P = (given & 0x01000000) >> 24; + unsigned int U = (given & 0x00800000) >> 23; + unsigned int W = (given & 0x00400000) >> 21; + unsigned int Rn = (given & 0x000f0000) >> 16; + unsigned int off = (given & 0x000000ff); + + func (stream, "[%s", arm_regnames[Rn]); + if (P) + { + if (off || !U) + func (stream, ", #%c%u", U ? '+' : '-', off * 4); + func (stream, "]"); + if (W) + func (stream, "!"); + } + else + { + func (stream, "], "); + if (W) + func (stream, "#%c%u", U ? '+' : '-', off * 4); + else + func (stream, "{%u}", off); + } + } + break; + + case 'w': + { + unsigned int Sbit = (given & 0x01000000) >> 24; + unsigned int type = (given & 0x00600000) >> 21; + switch (type) + { + case 0: func (stream, Sbit ? "sb" : "b"); break; + case 1: func (stream, Sbit ? "sh" : "h"); break; + case 2: + if (Sbit) + func (stream, "??"); + break; + case 3: + func (stream, "??"); + break; + } + } + 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 'E': + { + unsigned int msb = (given & 0x0000001f); + unsigned int lsb = 0; + lsb |= (given & 0x000000c0u) >> 6; + lsb |= (given & 0x00007000u) >> 10; + func (stream, "#%u, #%u", lsb, msb - lsb + 1); + } + break; + + case 'F': + { + unsigned int width = (given & 0x0000001f) + 1; + unsigned int lsb = 0; + lsb |= (given & 0x000000c0u) >> 6; + lsb |= (given & 0x00007000u) >> 10; + func (stream, "#%u, #%u", lsb, width); + } + break; + + case 'b': + { + unsigned int S = (given & 0x04000000u) >> 26; + unsigned int J1 = (given & 0x00002000u) >> 13; + unsigned int J2 = (given & 0x00000800u) >> 11; + int offset = 0; + + offset |= !S << 20; + offset |= J2 << 19; + offset |= J1 << 18; + offset |= (given & 0x003f0000) >> 4; + offset |= (given & 0x000007ff) << 1; + offset -= (1 << 20); + + info->print_address_func (pc + 4 + offset, info); + } + break; + + case 'B': + { + unsigned int S = (given & 0x04000000u) >> 26; + unsigned int I1 = (given & 0x00002000u) >> 13; + unsigned int I2 = (given & 0x00000800u) >> 11; + int offset = 0; + + offset |= !S << 24; + offset |= !(I1 ^ S) << 23; + offset |= !(I2 ^ S) << 22; + offset |= (given & 0x03ff0000u) >> 4; + offset |= (given & 0x000007ffu) << 1; + offset -= (1 << 24); + offset += pc + 4; + + /* BLX target addresses are always word aligned. */ + if ((given & 0x00001000u) == 0) + offset &= ~2u; + + info->print_address_func (offset, info); + } + break; + + case 's': + { + unsigned int shift = 0; + shift |= (given & 0x000000c0u) >> 6; + shift |= (given & 0x00007000u) >> 10; + if (given & 0x00200000u) + func (stream, ", asr #%u", shift); + else if (shift) + func (stream, ", lsl #%u", shift); + /* else print nothing - lsl #0 */ + } + break; + + case 'R': + { + unsigned int rot = (given & 0x00000030) >> 4; + if (rot) + func (stream, ", ror #%u", rot * 8); + } + break; + + case 'U': + switch (given & 0xf) + { + case 0xf: func(stream, "sy"); break; + case 0x7: func(stream, "un"); break; + case 0xe: func(stream, "st"); break; + case 0x6: func(stream, "unst"); break; + default: + func(stream, "#%d", (int)given & 0xf); + break; + } + break; + + case 'C': + if ((given & 0xff) == 0) + { + func (stream, "%cPSR_", (given & 0x100000) ? 'S' : 'C'); + if (given & 0x800) + func (stream, "f"); + if (given & 0x400) + func (stream, "s"); + if (given & 0x200) + func (stream, "x"); + if (given & 0x100) + func (stream, "c"); + } + else + { + func (stream, psr_name (given & 0xff)); + } + break; + + case 'D': + if ((given & 0xff) == 0) + func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C'); + else + func (stream, psr_name (given & 0xff)); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int width; + unsigned long val; + + c = arm_decode_bitfield (c, given, &val, &width); + + switch (*c) + { + case 'd': func (stream, "%lu", val); break; + case 'W': func (stream, "%lu", val * 4); break; + case 'r': func (stream, "%s", arm_regnames[val]); break; + + case 'c': + func (stream, "%s", arm_conditional[val]); + break; + + case '\'': + c++; + if (val == ((1ul << width) - 1)) + func (stream, "%c", *c); + break; + + case '`': + c++; + if (val == 0) + func (stream, "%c", *c); + break; + + case '?': + func (stream, "%c", c[(1 << width) - (int)val]); + c += 1 << width; + break; + + default: + abort (); + } + } + break; - return; + default: + abort (); + } + } + return; + } + + /* No match. */ + abort (); } -/* Parse the string of disassembler options, spliting it at whitespaces. */ +/* Print data bytes on INFO->STREAM. */ static void -parse_disassembler_options (options) - char * options; +print_insn_data (bfd_vma pc ATTRIBUTE_UNUSED, struct disassemble_info *info, + long given) { - char * space; - - if (options == NULL) - return; + switch (info->bytes_per_chunk) + { + case 1: + info->fprintf_func (info->stream, ".byte\t0x%02lx", given); + break; + case 2: + info->fprintf_func (info->stream, ".short\t0x%04lx", given); + break; + case 4: + info->fprintf_func (info->stream, ".word\t0x%08lx", given); + break; + default: + abort (); + } +} - do +/* Search back through the insn stream to determine if this instruction is + conditionally executed. */ +static void +find_ifthen_state (bfd_vma pc, struct disassemble_info *info, + bfd_boolean little) +{ + unsigned char b[2]; + unsigned int insn; + int status; + /* COUNT is twice the number of instructions seen. It will be odd if we + just crossed an instruction boundary. */ + int count; + int it_count; + unsigned int seen_it; + bfd_vma addr; + + ifthen_address = pc; + ifthen_state = 0; + + addr = pc; + count = 1; + it_count = 0; + seen_it = 0; + /* Scan backwards looking for IT instructions, keeping track of where + instruction boundaries are. We don't know if something is actually an + IT instruction until we find a definite instruction boundary. */ + for (;;) { - space = strchr (options, ' '); + if (addr == 0 || info->symbol_at_address_func(addr, info)) + { + /* A symbol must be on an instruction boundary, and will not + be within an IT block. */ + if (seen_it && (count & 1)) + break; + + return; + } + addr -= 2; + status = info->read_memory_func (addr, (bfd_byte *)b, 2, info); + if (status) + return; - if (space) + if (little) + insn = (b[0]) | (b[1] << 8); + else + insn = (b[1]) | (b[0] << 8); + if (seen_it) + { + if ((insn & 0xf800) < 0xe800) + { + /* Addr + 2 is an instruction boundary. See if this matches + the expected boundary based on the position of the last + IT candidate. */ + if (count & 1) + break; + seen_it = 0; + } + } + if ((insn & 0xff00) == 0xbf00 && (insn & 0xf) != 0) { - * space = '\0'; - parse_arm_disassembler_option (options); - * space = ' '; - options = space + 1; + /* This could be an IT instruction. */ + seen_it = insn; + it_count = count >> 1; } + if ((insn & 0xf800) >= 0xe800) + count++; else - parse_arm_disassembler_option (options); + count = (count + 2) | 1; + /* IT blocks contain at most 4 instructions. */ + if (count >= 8 && !seen_it) + return; } - while (space); + /* We found an IT instruction. */ + ifthen_state = (seen_it & 0xe0) | ((seen_it << it_count) & 0x1f); + if ((ifthen_state & 0xf) == 0) + ifthen_state = 0; } /* 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; +print_insn_arm (bfd_vma pc, struct disassemble_info *info) { - unsigned char b[4]; - long given; - int status; - int is_thumb; - int little; + unsigned char b[4]; + long given; + int status; + int is_thumb = FALSE; + int is_data = FALSE; + unsigned int size = 4; + void (*printer) (bfd_vma, struct disassemble_info *, long); +#if 0 + bfd_boolean found = FALSE; if (info->disassembler_options) { @@ -1555,15 +3919,91 @@ print_insn_arm (pc, info) info->disassembler_options = NULL; } - is_thumb = force_thumb; - if (pc & 1) + /* First check the full symtab for a mapping symbol, even if there + are no usable non-mapping symbols for this address. */ + if (info->symtab != NULL + && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour) { - is_thumb = 1; - pc &= ~(bfd_vma) 1; + bfd_vma addr; + int n; + int last_sym = -1; + enum map_type type = MAP_ARM; + + if (pc <= last_mapping_addr) + last_mapping_sym = -1; + is_thumb = (last_type == MAP_THUMB); + found = FALSE; + /* Start scanning at the start of the function, or wherever + we finished last time. */ + n = info->symtab_pos + 1; + if (n < last_mapping_sym) + n = last_mapping_sym; + + /* Scan up to the location being disassembled. */ + for (; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + break; + if ((info->section == NULL + || info->section == info->symtab[n]->section) + && get_sym_code_type (info, n, &type)) + { + last_sym = n; + found = TRUE; + } + } + + if (!found) + { + n = info->symtab_pos; + if (n < last_mapping_sym - 1) + n = last_mapping_sym - 1; + + /* No mapping symbol found at this address. Look backwards + for a preceeding one. */ + for (; n >= 0; n--) + { + if (get_sym_code_type (info, n, &type)) + { + last_sym = n; + found = TRUE; + break; + } + } + } + + last_mapping_sym = last_sym; + last_type = type; + is_thumb = (last_type == MAP_THUMB); + is_data = (last_type == MAP_DATA); + + /* Look a little bit ahead to see if we should print out + two or four bytes of data. If there's a symbol, + mapping or otherwise, after two bytes then don't + print more. */ + if (is_data) + { + size = 4 - (pc & 3); + for (n = last_sym + 1; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + { + if (addr - pc < size) + size = addr - pc; + break; + } + } + /* If the next symbol is after three bytes, we need to + print only part of the data, so that we can use either + .byte or .short. */ + if (size == 3) + size = (pc & 1) ? 1 : 2; + } } -#if 0 - if (!is_thumb && info->symbols != NULL) + if (info->symbols != NULL) { if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour) { @@ -1576,8 +4016,11 @@ print_insn_arm (pc, info) || 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) + else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour + && !found) { + /* If no mapping symbol has been found then fall back to the type + of the function symbol. */ elf_symbol_type * es; unsigned int type; @@ -1587,64 +4030,103 @@ print_insn_arm (pc, info) is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT); } } -#endif +#else + int little; little = (info->endian == BFD_ENDIAN_LITTLE); - info->bytes_per_chunk = 4; - info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; + is_thumb |= (pc & 1); + pc &= ~(bfd_vma)1; +#endif - if (little) - { - status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info); - if (status != 0 && is_thumb) - { - info->bytes_per_chunk = 2; + if (force_thumb) + is_thumb = TRUE; - status = info->read_memory_func (pc, (bfd_byte *) b, 2, info); - b[3] = b[2] = 0; - } + info->bytes_per_line = 4; - if (status != 0) - { - info->memory_error_func (status, pc, info); - return -1; - } + if (is_data) + { + int i; + + /* size was already set above. */ + info->bytes_per_chunk = size; + printer = print_insn_data; - given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); + status = info->read_memory_func (pc, (bfd_byte *)b, size, info); + given = 0; + if (little) + for (i = size - 1; i >= 0; i--) + given = b[i] | (given << 8); + else + for (i = 0; i < (int) size; i++) + given = b[i] | (given << 8); + } + else if (!is_thumb) + { + /* In ARM mode endianness is a straightforward issue: the instruction + is four bytes long and is either ordered 0123 or 3210. */ + printer = print_insn_arm_internal; + info->bytes_per_chunk = 4; + size = 4; + + status = info->read_memory_func (pc, (bfd_byte *)b, 4, info); + if (little) + given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); + else + given = (b[3]) | (b[2] << 8) | (b[1] << 16) | (b[0] << 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; - } + /* In Thumb mode we have the additional wrinkle of two + instruction lengths. Fortunately, the bits that determine + the length of the current instruction are always to be found + in the first two bytes. */ + printer = print_insn_thumb16; + info->bytes_per_chunk = 2; + size = 2; + + status = info->read_memory_func (pc, (bfd_byte *)b, 2, info); + if (little) + given = (b[0]) | (b[1] << 8); + else + given = (b[1]) | (b[0] << 8); - if (is_thumb) + if (!status) { - if (pc & 0x2) + /* These bit patterns signal a four-byte Thumb + instruction. */ + if ((given & 0xF800) == 0xF800 + || (given & 0xF800) == 0xF000 + || (given & 0xF800) == 0xE800) { - 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; - } + status = info->read_memory_func (pc + 2, (bfd_byte *)b, 2, info); + if (little) + given = (b[0]) | (b[1] << 8) | (given << 16); + else + given = (b[1]) | (b[0] << 8) | (given << 16); - given |= (b[0] << 24) | (b[1] << 16); + printer = print_insn_thumb32; + size = 4; } + } + + if (ifthen_address != pc) + find_ifthen_state(pc, info, little); + + if (ifthen_state) + { + if ((ifthen_state & 0xf) == 0x8) + ifthen_next_state = 0; else - given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16); + ifthen_next_state = (ifthen_state & 0xe0) + | ((ifthen_state & 0xf) << 1); } - else - given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); } + if (status) + { + info->memory_error_func (status, pc, info); + return -1; + } 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 @@ -1652,16 +4134,19 @@ print_insn_arm (pc, info) 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; + printer (pc, info, given); + + if (is_thumb) + { + ifthen_state = ifthen_next_state; + ifthen_address += size; + } + return size; } void -print_arm_disassembler_options (FILE * stream) +print_arm_disassembler_options (FILE *stream) { int i; diff --git a/dis-asm.h b/dis-asm.h index a805a48e5..2f333a90f 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -183,12 +183,20 @@ enum bfd_architecture bfd_arch_alpha, /* Dec Alpha */ #define bfd_mach_alpha 1 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 +#define bfd_mach_arm_unknown 0 +#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 +#define bfd_mach_arm_5 7 +#define bfd_mach_arm_5T 8 +#define bfd_mach_arm_5TE 9 +#define bfd_mach_arm_XScale 10 +#define bfd_mach_arm_ep9312 11 +#define bfd_mach_arm_iWMMXt 12 +#define bfd_mach_arm_iWMMXt2 13 bfd_arch_ns32k, /* National Semiconductors ns32000 */ bfd_arch_w65, /* WDC 65816 */ bfd_arch_tic30, /* Texas Instruments TMS320C30 */ -- cgit v1.2.3 From 8fc7cc580f94dff04dd3d72d912bae38f0b614f9 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 10 Nov 2007 17:43:49 +0000 Subject: Fix m68k FP register debug dumps. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3566 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 499f053e3..68f39aab7 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3291,13 +3291,13 @@ void cpu_dump_state(CPUState *env, FILE *f, u.d = env->fregs[i]; cpu_fprintf (f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n", i, env->dregs[i], i, env->aregs[i], - i, u.l.upper, u.l.lower, u.d); + i, u.l.upper, u.l.lower, *(double *)&u.d); } cpu_fprintf (f, "PC = %08x ", env->pc); sr = env->sr; cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & 0x10) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-'); - cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result); + cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result); } -- cgit v1.2.3 From ca02f31955113212eb250a3c58c7ab26b1a2a8df Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 10 Nov 2007 18:03:23 +0000 Subject: Add dummy m68k board. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3567 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/dummy_m68k.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 1 + vl.h | 3 +++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 hw/dummy_m68k.c diff --git a/Makefile.target b/Makefile.target index ab925ad09..ee91a57d1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -508,7 +508,7 @@ VL_OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o endif ifeq ($(TARGET_BASE_ARCH), m68k) VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o -VL_OBJS+= m68k-semi.o +VL_OBJS+= m68k-semi.o dummy_m68k.o endif ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c new file mode 100644 index 000000000..630591508 --- /dev/null +++ b/hw/dummy_m68k.c @@ -0,0 +1,66 @@ +/* + * Dummy board with just RAM and CPU for use as an ISS. + * + * Copyright (c) 2007 CodeSourcery. + * + * This code is licenced under the GPL + */ + +#include "vl.h" + +#define KERNEL_LOAD_ADDR 0x10000 + +/* Board init. */ + +static void dummy_m68k_init(int ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env; + int kernel_size; + uint64_t elf_entry; + target_ulong entry; + + env = cpu_init(); + if (!cpu_model) + cpu_model = "cfv4e"; + if (cpu_m68k_set_model(env, cpu_model)) { + cpu_abort(env, "Unable to find m68k CPU definition\n"); + } + + /* Initialize CPU registers. */ + env->vbr = 0; + + /* RAM at address zero */ + cpu_register_physical_memory(0, ram_size, + qemu_ram_alloc(ram_size) | IO_MEM_RAM); + + /* Load kernel. */ + if (kernel_filename) { + kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL); + entry = elf_entry; + if (kernel_size < 0) { + kernel_size = load_uboot(kernel_filename, &entry, NULL); + } + if (kernel_size < 0) { + kernel_size = load_image(kernel_filename, + phys_ram_base + KERNEL_LOAD_ADDR); + entry = KERNEL_LOAD_ADDR; + } + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + } else { + entry = 0; + } + env->pc = entry; +} + +QEMUMachine dummy_m68k_machine = { + "dummy", + "Dummy board", + dummy_m68k_init, +}; diff --git a/vl.c b/vl.c index 03859a995..e70ed4c31 100644 --- a/vl.c +++ b/vl.c @@ -7400,6 +7400,7 @@ void register_machines(void) #elif defined(TARGET_M68K) qemu_register_machine(&mcf5208evb_machine); qemu_register_machine(&an5206_machine); + qemu_register_machine(&dummy_m68k_machine); #elif defined(TARGET_CRIS) qemu_register_machine(&bareetraxfs_machine); #else diff --git a/vl.h b/vl.h index 683b62db2..099bbb7ad 100644 --- a/vl.h +++ b/vl.h @@ -1719,6 +1719,9 @@ extern QEMUMachine an5206_machine; /* mcf5208.c */ extern QEMUMachine mcf5208evb_machine; +/* dummy_m68k.c */ +extern QEMUMachine dummy_m68k_machine; + #include "gdbstub.h" #endif /* defined(QEMU_TOOL) */ -- cgit v1.2.3 From cd08ce8f3622e0ddee4a38ad9dfd919a54782228 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 10 Nov 2007 19:21:30 +0000 Subject: Fix build failure. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3568 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dummy_m68k.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 630591508..722554711 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -12,8 +12,9 @@ /* Board init. */ -static void dummy_m68k_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void dummy_m68k_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -22,11 +23,12 @@ static void dummy_m68k_init(int ram_size, int vga_ram_size, int boot_device, uint64_t elf_entry; target_ulong entry; - env = cpu_init(); if (!cpu_model) cpu_model = "cfv4e"; - if (cpu_m68k_set_model(env, cpu_model)) { - cpu_abort(env, "Unable to find m68k CPU definition\n"); + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find m68k CPU definition\n"); + exit(1); } /* Initialize CPU registers. */ -- cgit v1.2.3 From da0b0df8c7c842670457088b12096ec63ea66fae Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 10 Nov 2007 19:30:52 +0000 Subject: Fix Makefile dependencies. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3569 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1f77f2c01..d0ec05720 100644 --- a/Makefile +++ b/Makefile @@ -26,9 +26,9 @@ endif LIBS+=$(AIOLIBS) -all: libqemu_common.a $(TOOLS) $(DOCS) recurse-all +all: $(TOOLS) $(DOCS) recurse-all -subdir-%: dyngen$(EXESUF) +subdir-%: dyngen$(EXESUF) libqemu_common.a $(MAKE) -C $(subst subdir-,,$@) all recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) -- cgit v1.2.3 From 3c6b20885dd6395882947e13901313a2fc291113 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 Nov 2007 19:36:39 +0000 Subject: always use mktimegm git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3570 c046a42c-6fe2-441c-8c8c-71466251a162 --- cutils.c | 14 ++++++++++++++ vl.c | 2 +- vl.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cutils.c b/cutils.c index 074b5acd4..7836a3e99 100644 --- a/cutils.c +++ b/cutils.c @@ -81,3 +81,17 @@ int stristart(const char *str, const char *val, const char **ptr) *ptr = p; return 1; } + +time_t mktimegm(struct tm *tm) +{ + time_t t; + int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday; + if (m < 3) { + m += 12; + y--; + } + t = 86400 * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + + y / 400 - 719469); + t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec; + return t; +} diff --git a/vl.c b/vl.c index e70ed4c31..d1ae8cab9 100644 --- a/vl.c +++ b/vl.c @@ -8116,7 +8116,7 @@ int main(int argc, char **argv) } tm.tm_year -= 1900; tm.tm_mon--; - rtc_start_date = timegm(&tm); + rtc_start_date = mktimegm(&tm); if (rtc_start_date == -1) { date_fail: fprintf(stderr, "Invalid date format. Valid format are:\n" diff --git a/vl.h b/vl.h index 099bbb7ad..047fd3bbb 100644 --- a/vl.h +++ b/vl.h @@ -123,6 +123,7 @@ void pstrcpy(char *buf, int buf_size, const char *str); char *pstrcat(char *buf, int buf_size, const char *s); int strstart(const char *str, const char *val, const char **ptr); int stristart(const char *str, const char *val, const char **ptr); +time_t mktimegm(struct tm *tm); /* vl.c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); -- cgit v1.2.3 From ee4e83ed8ddc8dac572a0123398adf78b63014ae Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 10 Nov 2007 23:51:02 +0000 Subject: Allow selection of PowerPC CPU giving a PVR. Remove unused pvr_mask field from CPU definition. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3571 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 1 - target-ppc/translate_init.c | 791 +++++++++++++++++++++++--------------------- 2 files changed, 420 insertions(+), 372 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7fcdd4121..198da43f3 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -723,7 +723,6 @@ void cpu_ppc_reset (void *opaque); void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); const ppc_def_t *cpu_ppc_find_by_name (const unsigned char *name); -const ppc_def_t *cpu_ppc_find_by_pvr (uint32_t pvr); int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); /* Time-base and decrementer management */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 973e0c5db..20a24b453 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -24,6 +24,7 @@ */ #include "dis-asm.h" +#include "host-utils.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -32,7 +33,6 @@ struct ppc_def_t { const unsigned char *name; uint32_t pvr; - uint32_t pvr_mask; uint64_t insns_flags; uint64_t msr_mask; uint8_t mmu_model; @@ -5004,11 +5004,10 @@ enum { /*****************************************************************************/ /* PowerPC CPU definitions */ -#define POWERPC_DEF(_name, _pvr, _pvr_mask, _type) \ +#define POWERPC_DEF(_name, _pvr, _type) \ { \ .name = _name, \ .pvr = _pvr, \ - .pvr_mask = _pvr_mask, \ .insns_flags = glue(POWERPC_INSNS_,_type), \ .msr_mask = glue(POWERPC_MSRM_,_type), \ .mmu_model = glue(POWERPC_MMU_,_type), \ @@ -5020,853 +5019,857 @@ enum { .check_pow = &glue(check_pow_,_type), \ } -static ppc_def_t ppc_defs[] = { +static const ppc_def_t ppc_defs[] = { /* Embedded PowerPC */ /* PowerPC 401 family */ /* Generic PowerPC 401 */ - POWERPC_DEF("401", CPU_POWERPC_401, 0xFFFF0000, 401), + POWERPC_DEF("401", CPU_POWERPC_401, 401), /* PowerPC 401 cores */ /* PowerPC 401A1 */ - POWERPC_DEF("401A1", CPU_POWERPC_401A1, 0xFFFFFFFF, 401), + POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401), /* PowerPC 401B2 */ - POWERPC_DEF("401B2", CPU_POWERPC_401B2, 0xFFFFFFFF, 401x2), + POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2), #if defined (TODO) /* PowerPC 401B3 */ - POWERPC_DEF("401B3", CPU_POWERPC_401B3, 0xFFFFFFFF, 401x3), + POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3), #endif /* PowerPC 401C2 */ - POWERPC_DEF("401C2", CPU_POWERPC_401C2, 0xFFFFFFFF, 401x2), + POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2), /* PowerPC 401D2 */ - POWERPC_DEF("401D2", CPU_POWERPC_401D2, 0xFFFFFFFF, 401x2), + POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2), /* PowerPC 401E2 */ - POWERPC_DEF("401E2", CPU_POWERPC_401E2, 0xFFFFFFFF, 401x2), + POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2), /* PowerPC 401F2 */ - POWERPC_DEF("401F2", CPU_POWERPC_401F2, 0xFFFFFFFF, 401x2), + POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2), /* PowerPC 401G2 */ /* XXX: to be checked */ - POWERPC_DEF("401G2", CPU_POWERPC_401G2, 0xFFFFFFFF, 401x2), + POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2), /* PowerPC 401 microcontrolers */ #if defined (TODO) /* PowerPC 401GF */ - POWERPC_DEF("401GF", CPU_POWERPC_401GF, 0xFFFFFFFF, 401), + POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401), #endif /* IOP480 (401 microcontroler) */ - POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, 0xFFFFFFFF, IOP480), + POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480), /* IBM Processor for Network Resources */ - POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 0xFFFFFFFF, 401), + POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401), #if defined (TODO) - POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 0xFFFFFFFF, 401), + POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401), #endif /* PowerPC 403 family */ /* Generic PowerPC 403 */ - POWERPC_DEF("403", CPU_POWERPC_403, 0xFFFF0000, 403), + POWERPC_DEF("403", CPU_POWERPC_403, 403), /* PowerPC 403 microcontrolers */ /* PowerPC 403 GA */ - POWERPC_DEF("403GA", CPU_POWERPC_403GA, 0xFFFFFFFF, 403), + POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403), /* PowerPC 403 GB */ - POWERPC_DEF("403GB", CPU_POWERPC_403GB, 0xFFFFFFFF, 403), + POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403), /* PowerPC 403 GC */ - POWERPC_DEF("403GC", CPU_POWERPC_403GC, 0xFFFFFFFF, 403), + POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403), /* PowerPC 403 GCX */ - POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 0xFFFFFFFF, 403GCX), + POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX), #if defined (TODO) /* PowerPC 403 GP */ - POWERPC_DEF("403GP", CPU_POWERPC_403GP, 0xFFFFFFFF, 403), + POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403), #endif /* PowerPC 405 family */ /* Generic PowerPC 405 */ - POWERPC_DEF("405", CPU_POWERPC_405, 0xFFFF0000, 405), + POWERPC_DEF("405", CPU_POWERPC_405, 405), /* PowerPC 405 cores */ #if defined (TODO) /* PowerPC 405 A3 */ - POWERPC_DEF("405A3", CPU_POWERPC_405A3, 0xFFFFFFFF, 405), + POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405), #endif #if defined (TODO) /* PowerPC 405 A4 */ - POWERPC_DEF("405A4", CPU_POWERPC_405A4, 0xFFFFFFFF, 405), + POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405), #endif #if defined (TODO) /* PowerPC 405 B3 */ - POWERPC_DEF("405B3", CPU_POWERPC_405B3, 0xFFFFFFFF, 405), + POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405), #endif #if defined (TODO) /* PowerPC 405 B4 */ - POWERPC_DEF("405B4", CPU_POWERPC_405B4, 0xFFFFFFFF, 405), + POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405), #endif #if defined (TODO) /* PowerPC 405 C3 */ - POWERPC_DEF("405C3", CPU_POWERPC_405C3, 0xFFFFFFFF, 405), + POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405), #endif #if defined (TODO) /* PowerPC 405 C4 */ - POWERPC_DEF("405C4", CPU_POWERPC_405C4, 0xFFFFFFFF, 405), + POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405), #endif /* PowerPC 405 D2 */ - POWERPC_DEF("405D2", CPU_POWERPC_405D2, 0xFFFFFFFF, 405), + POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405), #if defined (TODO) /* PowerPC 405 D3 */ - POWERPC_DEF("405D3", CPU_POWERPC_405D3, 0xFFFFFFFF, 405), + POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405), #endif /* PowerPC 405 D4 */ - POWERPC_DEF("405D4", CPU_POWERPC_405D4, 0xFFFFFFFF, 405), + POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405), #if defined (TODO) /* PowerPC 405 D5 */ - POWERPC_DEF("405D5", CPU_POWERPC_405D5, 0xFFFFFFFF, 405), + POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405), #endif #if defined (TODO) /* PowerPC 405 E4 */ - POWERPC_DEF("405E4", CPU_POWERPC_405E4, 0xFFFFFFFF, 405), + POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405), #endif #if defined (TODO) /* PowerPC 405 F4 */ - POWERPC_DEF("405F4", CPU_POWERPC_405F4, 0xFFFFFFFF, 405), + POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405), #endif #if defined (TODO) /* PowerPC 405 F5 */ - POWERPC_DEF("405F5", CPU_POWERPC_405F5, 0xFFFFFFFF, 405), + POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405), #endif #if defined (TODO) /* PowerPC 405 F6 */ - POWERPC_DEF("405F6", CPU_POWERPC_405F6, 0xFFFFFFFF, 405), + POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405), #endif /* PowerPC 405 microcontrolers */ /* PowerPC 405 CR */ - POWERPC_DEF("405CR", CPU_POWERPC_405CR, 0xFFFFFFFF, 405), + POWERPC_DEF("405CR", CPU_POWERPC_405CR, 405), /* PowerPC 405 CRa */ - POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 0xFFFFFFFF, 405), + POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405), /* PowerPC 405 CRb */ - POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 0xFFFFFFFF, 405), + POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405), /* PowerPC 405 CRc */ - POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 0xFFFFFFFF, 405), + POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405), /* PowerPC 405 EP */ - POWERPC_DEF("405EP", CPU_POWERPC_405EP, 0xFFFFFFFF, 405), + POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405), #if defined(TODO) /* PowerPC 405 EXr */ - POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 0xFFFFFFFF, 405), + POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405), #endif /* PowerPC 405 EZ */ - POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 0xFFFFFFFF, 405), + POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405), #if defined(TODO) /* PowerPC 405 FX */ - POWERPC_DEF("405FX", CPU_POWERPC_405FX, 0xFFFFFFFF, 405), + POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405), #endif /* PowerPC 405 GP */ - POWERPC_DEF("405GP", CPU_POWERPC_405GP, 0xFFFFFFFF, 405), + POWERPC_DEF("405GP", CPU_POWERPC_405GP, 405), /* PowerPC 405 GPa */ - POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 0xFFFFFFFF, 405), + POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405), /* PowerPC 405 GPb */ - POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 0xFFFFFFFF, 405), + POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405), /* PowerPC 405 GPc */ - POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 0xFFFFFFFF, 405), + POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405), /* PowerPC 405 GPd */ - POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 0xFFFFFFFF, 405), + POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405), /* PowerPC 405 GPe */ - POWERPC_DEF("405GPe", CPU_POWERPC_405GPe, 0xFFFFFFFF, 405), + POWERPC_DEF("405GPe", CPU_POWERPC_405GPe, 405), /* PowerPC 405 GPR */ - POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 0xFFFFFFFF, 405), + POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405), #if defined(TODO) /* PowerPC 405 H */ - POWERPC_DEF("405H", CPU_POWERPC_405H, 0xFFFFFFFF, 405), + POWERPC_DEF("405H", CPU_POWERPC_405H, 405), #endif #if defined(TODO) /* PowerPC 405 L */ - POWERPC_DEF("405L", CPU_POWERPC_405L, 0xFFFFFFFF, 405), + POWERPC_DEF("405L", CPU_POWERPC_405L, 405), #endif /* PowerPC 405 LP */ - POWERPC_DEF("405LP", CPU_POWERPC_405LP, 0xFFFFFFFF, 405), + POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405), #if defined(TODO) /* PowerPC 405 PM */ - POWERPC_DEF("405PM", CPU_POWERPC_405PM, 0xFFFFFFFF, 405), + POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405), #endif #if defined(TODO) /* PowerPC 405 PS */ - POWERPC_DEF("405PS", CPU_POWERPC_405PS, 0xFFFFFFFF, 405), + POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405), #endif #if defined(TODO) /* PowerPC 405 S */ - POWERPC_DEF("405S", CPU_POWERPC_405S, 0xFFFFFFFF, 405), + POWERPC_DEF("405S", CPU_POWERPC_405S, 405), #endif /* Npe405 H */ - POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 0xFFFFFFFF, 405), + POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405), /* Npe405 H2 */ - POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 0xFFFFFFFF, 405), + POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405), /* Npe405 L */ - POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 0xFFFFFFFF, 405), + POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405), /* Npe4GS3 */ - POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 0xFFFFFFFF, 405), + POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405), #if defined (TODO) - POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 0xFFFFFFFF, 405), + POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405), #endif #if defined (TODO) - POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 0xFFFFFFFF, 405), + POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405), #endif #if defined (TODO) /* PowerPC LC77700 (Sanyo) */ - POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 0xFFFFFFFF, 405), + POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405), #endif /* PowerPC 401/403/405 based set-top-box microcontrolers */ #if defined (TODO) /* STB010000 */ - POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 0xFFFFFFFF, 401x2), + POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2), #endif #if defined (TODO) /* STB01010 */ - POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 0xFFFFFFFF, 401x2), + POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2), #endif #if defined (TODO) /* STB0210 */ - POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 0xFFFFFFFF, 401x3), + POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3), #endif /* STB03xx */ - POWERPC_DEF("STB03", CPU_POWERPC_STB03, 0xFFFFFFFF, 405), + POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405), #if defined (TODO) /* STB043x */ - POWERPC_DEF("STB043", CPU_POWERPC_STB043, 0xFFFFFFFF, 405), + POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405), #endif #if defined (TODO) /* STB045x */ - POWERPC_DEF("STB045", CPU_POWERPC_STB045, 0xFFFFFFFF, 405), + POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405), #endif /* STB04xx */ - POWERPC_DEF("STB04", CPU_POWERPC_STB04, 0xFFFF0000, 405), + POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405), /* STB25xx */ - POWERPC_DEF("STB25", CPU_POWERPC_STB25, 0xFFFFFFFF, 405), + POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405), #if defined (TODO) /* STB130 */ - POWERPC_DEF("STB130", CPU_POWERPC_STB130, 0xFFFFFFFF, 405), + POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405), #endif /* Xilinx PowerPC 405 cores */ - POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 0xFFFFFFFF, 405), - POWERPC_DEF("x2vp7", CPU_POWERPC_X2VP7, 0xFFFFFFFF, 405), - POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 0xFFFFFFFF, 405), - POWERPC_DEF("x2vp50", CPU_POWERPC_X2VP50, 0xFFFFFFFF, 405), + POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405), + POWERPC_DEF("x2vp7", CPU_POWERPC_X2VP7, 405), + POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405), + POWERPC_DEF("x2vp50", CPU_POWERPC_X2VP50, 405), #if defined (TODO) /* Zarlink ZL10310 */ - POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 0xFFFFFFFF, 405), + POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405), #endif #if defined (TODO) /* Zarlink ZL10311 */ - POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 0xFFFFFFFF, 405), + POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405), #endif #if defined (TODO) /* Zarlink ZL10320 */ - POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 0xFFFFFFFF, 405), + POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405), #endif #if defined (TODO) /* Zarlink ZL10321 */ - POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 0xFFFFFFFF, 405), + POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405), #endif /* PowerPC 440 family */ /* Generic PowerPC 440 */ - POWERPC_DEF("440", CPU_POWERPC_440, 0xFFFFFFFF, 440GP), + POWERPC_DEF("440", CPU_POWERPC_440, 440GP), /* PowerPC 440 cores */ #if defined (TODO) /* PowerPC 440 A4 */ - POWERPC_DEF("440A4", CPU_POWERPC_440A4, 0xFFFFFFFF, 440x4), + POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4), #endif #if defined (TODO) /* PowerPC 440 A5 */ - POWERPC_DEF("440A5", CPU_POWERPC_440A5, 0xFFFFFFFF, 440x5), + POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5), #endif #if defined (TODO) /* PowerPC 440 B4 */ - POWERPC_DEF("440B4", CPU_POWERPC_440B4, 0xFFFFFFFF, 440x4), + POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4), #endif #if defined (TODO) /* PowerPC 440 G4 */ - POWERPC_DEF("440G4", CPU_POWERPC_440G4, 0xFFFFFFFF, 440x4), + POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4), #endif #if defined (TODO) /* PowerPC 440 F5 */ - POWERPC_DEF("440F5", CPU_POWERPC_440F5, 0xFFFFFFFF, 440x5), + POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5), #endif #if defined (TODO) /* PowerPC 440 G5 */ - POWERPC_DEF("440G5", CPU_POWERPC_440G5, 0xFFFFFFFF, 440x5), + POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5), #endif #if defined (TODO) /* PowerPC 440H4 */ - POWERPC_DEF("440H4", CPU_POWERPC_440H4, 0xFFFFFFFF, 440x4), + POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4), #endif #if defined (TODO) /* PowerPC 440H6 */ - POWERPC_DEF("440H6", CPU_POWERPC_440H6, 0xFFFFFFFF, 440Gx5), + POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5), #endif /* PowerPC 440 microcontrolers */ /* PowerPC 440 EP */ - POWERPC_DEF("440EP", CPU_POWERPC_440EP, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440EP", CPU_POWERPC_440EP, 440EP), /* PowerPC 440 EPa */ - POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP), /* PowerPC 440 EPb */ - POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP), /* PowerPC 440 EPX */ - POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP), /* PowerPC 440 GP */ - POWERPC_DEF("440GP", CPU_POWERPC_440GP, 0xFFFFFFFF, 440GP), + POWERPC_DEF("440GP", CPU_POWERPC_440GP, 440GP), /* PowerPC 440 GPb */ - POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 0xFFFFFFFF, 440GP), + POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP), /* PowerPC 440 GPc */ - POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 0xFFFFFFFF, 440GP), + POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP), /* PowerPC 440 GR */ - POWERPC_DEF("440GR", CPU_POWERPC_440GR, 0xFFFFFFFF, 440x5), + POWERPC_DEF("440GR", CPU_POWERPC_440GR, 440x5), /* PowerPC 440 GRa */ - POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 0xFFFFFFFF, 440x5), + POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5), /* PowerPC 440 GRX */ - POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 0xFFFFFFFF, 440x5), + POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5), /* PowerPC 440 GX */ - POWERPC_DEF("440GX", CPU_POWERPC_440GX, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440GX", CPU_POWERPC_440GX, 440EP), /* PowerPC 440 GXa */ - POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP), /* PowerPC 440 GXb */ - POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP), /* PowerPC 440 GXc */ - POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP), /* PowerPC 440 GXf */ - POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP), #if defined(TODO) /* PowerPC 440 S */ - POWERPC_DEF("440S", CPU_POWERPC_440S, 0xFFFFFFFF, 440), + POWERPC_DEF("440S", CPU_POWERPC_440S, 440), #endif /* PowerPC 440 SP */ - POWERPC_DEF("440SP", CPU_POWERPC_440SP, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP), /* PowerPC 440 SP2 */ - POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP), /* PowerPC 440 SPE */ - POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 0xFFFFFFFF, 440EP), + POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP), /* PowerPC 460 family */ #if defined (TODO) /* Generic PowerPC 464 */ - POWERPC_DEF("464", CPU_POWERPC_464, 0xFFFFFFFF, 460), + POWERPC_DEF("464", CPU_POWERPC_464, 460), #endif /* PowerPC 464 microcontrolers */ #if defined (TODO) /* PowerPC 464H90 */ - POWERPC_DEF("464H90", CPU_POWERPC_464H90, 0xFFFFFFFF, 460), + POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460), #endif #if defined (TODO) /* PowerPC 464H90F */ - POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 0xFFFFFFFF, 460F), + POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F), #endif /* Freescale embedded PowerPC cores */ /* e200 family */ #if defined (TODO) /* Generic PowerPC e200 core */ - POWERPC_DEF("e200", CPU_POWERPC_e200, 0xFFFFFFFF, e200), + POWERPC_DEF("e200", CPU_POWERPC_e200, e200), #endif #if defined (TODO) /* PowerPC e200z5 core */ - POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, 0xFFFFFFFF, e200), + POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200), #endif #if defined (TODO) /* PowerPC e200z6 core */ - POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, 0xFFFFFFFF, e200), + POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200), #endif /* e300 family */ #if defined (TODO) /* Generic PowerPC e300 core */ - POWERPC_DEF("e300", CPU_POWERPC_e300, 0xFFFFFFFF, e300), + POWERPC_DEF("e300", CPU_POWERPC_e300, e300), #endif #if defined (TODO) /* PowerPC e300c1 core */ - POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, 0xFFFFFFFF, e300), + POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300), #endif #if defined (TODO) /* PowerPC e300c2 core */ - POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, 0xFFFFFFFF, e300), + POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300), #endif #if defined (TODO) /* PowerPC e300c3 core */ - POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, 0xFFFFFFFF, e300), + POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300), #endif /* e500 family */ #if defined (TODO) /* PowerPC e500 core */ - POWERPC_DEF("e500", CPU_POWERPC_e500, 0xFFFFFFFF, e500), + POWERPC_DEF("e500", CPU_POWERPC_e500, e500), #endif #if defined (TODO) /* PowerPC e500 v1.1 core */ - POWERPC_DEF("e500v1.1", CPU_POWERPC_e500_v11, 0xFFFFFFFF, e500), + POWERPC_DEF("e500v1.1", CPU_POWERPC_e500_v11, e500), #endif #if defined (TODO) /* PowerPC e500 v1.2 core */ - POWERPC_DEF("e500v1.2", CPU_POWERPC_e500_v12, 0xFFFFFFFF, e500), + POWERPC_DEF("e500v1.2", CPU_POWERPC_e500_v12, e500), #endif #if defined (TODO) /* PowerPC e500 v2.1 core */ - POWERPC_DEF("e500v2.1", CPU_POWERPC_e500_v21, 0xFFFFFFFF, e500), + POWERPC_DEF("e500v2.1", CPU_POWERPC_e500_v21, e500), #endif #if defined (TODO) /* PowerPC e500 v2.2 core */ - POWERPC_DEF("e500v2.2", CPU_POWERPC_e500_v22, 0xFFFFFFFF, e500), + POWERPC_DEF("e500v2.2", CPU_POWERPC_e500_v22, e500), #endif /* e600 family */ #if defined (TODO) /* PowerPC e600 core */ - POWERPC_DEF("e600", CPU_POWERPC_e600, 0xFFFFFFFF, e600), + POWERPC_DEF("e600", CPU_POWERPC_e600, e600), #endif /* PowerPC MPC 5xx cores */ #if defined (TODO) /* PowerPC MPC 5xx */ - POWERPC_DEF("mpc5xx", CPU_POWERPC_5xx, 0xFFFFFFFF, 5xx), + POWERPC_DEF("mpc5xx", CPU_POWERPC_5xx, 5xx), #endif /* PowerPC MPC 8xx cores */ #if defined (TODO) /* PowerPC MPC 8xx */ - POWERPC_DEF("mpc8xx", CPU_POWERPC_8xx, 0xFFFFFFFF, 8xx), + POWERPC_DEF("mpc8xx", CPU_POWERPC_8xx, 8xx), #endif /* PowerPC MPC 8xxx cores */ #if defined (TODO) /* PowerPC MPC 82xx HIP3 */ - POWERPC_DEF("mpc82xxhip3", CPU_POWERPC_82xx_HIP3, 0xFFFFFFFF, 82xx), + POWERPC_DEF("mpc82xxhip3", CPU_POWERPC_82xx_HIP3, 82xx), #endif #if defined (TODO) /* PowerPC MPC 82xx HIP4 */ - POWERPC_DEF("mpc82xxhip4", CPU_POWERPC_82xx_HIP4, 0xFFFFFFFF, 82xx), + POWERPC_DEF("mpc82xxhip4", CPU_POWERPC_82xx_HIP4, 82xx), #endif #if defined (TODO) /* PowerPC MPC 827x */ - POWERPC_DEF("mpc827x", CPU_POWERPC_827x, 0xFFFFFFFF, 827x), + POWERPC_DEF("mpc827x", CPU_POWERPC_827x, 827x), #endif /* 32 bits "classic" PowerPC */ /* PowerPC 6xx family */ /* PowerPC 601 */ - POWERPC_DEF("601", CPU_POWERPC_601, 0xFFFFFFFF, 601), + POWERPC_DEF("601", CPU_POWERPC_601, 601), /* PowerPC 601v2 */ - POWERPC_DEF("601a", CPU_POWERPC_601a, 0xFFFFFFFF, 601), + POWERPC_DEF("601a", CPU_POWERPC_601a, 601), /* PowerPC 602 */ - POWERPC_DEF("602", CPU_POWERPC_602, 0xFFFFFFFF, 602), + POWERPC_DEF("602", CPU_POWERPC_602, 602), /* PowerPC 603 */ - POWERPC_DEF("603", CPU_POWERPC_603, 0xFFFFFFFF, 603), + POWERPC_DEF("603", CPU_POWERPC_603, 603), /* Code name for PowerPC 603 */ - POWERPC_DEF("Vanilla", CPU_POWERPC_603, 0xFFFFFFFF, 603), + POWERPC_DEF("Vanilla", CPU_POWERPC_603, 603), /* PowerPC 603e */ - POWERPC_DEF("603e", CPU_POWERPC_603E, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e", CPU_POWERPC_603E, 603E), /* Code name for PowerPC 603e */ - POWERPC_DEF("Stretch", CPU_POWERPC_603E, 0xFFFFFFFF, 603E), + POWERPC_DEF("Stretch", CPU_POWERPC_603E, 603E), /* PowerPC 603e v1.1 */ - POWERPC_DEF("603e1.1", CPU_POWERPC_603E_v11, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e1.1", CPU_POWERPC_603E_v11, 603E), /* PowerPC 603e v1.2 */ - POWERPC_DEF("603e1.2", CPU_POWERPC_603E_v12, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e1.2", CPU_POWERPC_603E_v12, 603E), /* PowerPC 603e v1.3 */ - POWERPC_DEF("603e1.3", CPU_POWERPC_603E_v13, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e1.3", CPU_POWERPC_603E_v13, 603E), /* PowerPC 603e v1.4 */ - POWERPC_DEF("603e1.4", CPU_POWERPC_603E_v14, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e1.4", CPU_POWERPC_603E_v14, 603E), /* PowerPC 603e v2.2 */ - POWERPC_DEF("603e2.2", CPU_POWERPC_603E_v22, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e2.2", CPU_POWERPC_603E_v22, 603E), /* PowerPC 603e v3 */ - POWERPC_DEF("603e3", CPU_POWERPC_603E_v3, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e3", CPU_POWERPC_603E_v3, 603E), /* PowerPC 603e v4 */ - POWERPC_DEF("603e4", CPU_POWERPC_603E_v4, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e4", CPU_POWERPC_603E_v4, 603E), /* PowerPC 603e v4.1 */ - POWERPC_DEF("603e4.1", CPU_POWERPC_603E_v41, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e4.1", CPU_POWERPC_603E_v41, 603E), /* PowerPC 603e */ - POWERPC_DEF("603e7", CPU_POWERPC_603E7, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E), /* PowerPC 603e7t */ - POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E), /* PowerPC 603e7v */ - POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E), /* Code name for PowerPC 603ev */ - POWERPC_DEF("Vaillant", CPU_POWERPC_603E7v, 0xFFFFFFFF, 603E), + POWERPC_DEF("Vaillant", CPU_POWERPC_603E7v, 603E), /* PowerPC 603e7v1 */ - POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E), /* PowerPC 603e7v2 */ - POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 0xFFFFFFFF, 603E), + POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E), /* PowerPC 603p */ /* to be checked */ - POWERPC_DEF("603p", CPU_POWERPC_603P, 0xFFFFFFFF, 603), + POWERPC_DEF("603p", CPU_POWERPC_603P, 603), /* PowerPC 603r */ - POWERPC_DEF("603r", CPU_POWERPC_603R, 0xFFFFFFFF, 603E), + POWERPC_DEF("603r", CPU_POWERPC_603R, 603E), /* Code name for PowerPC 603r */ - POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 0xFFFFFFFF, 603E), + POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 603E), /* PowerPC G2 core */ - POWERPC_DEF("G2", CPU_POWERPC_G2, 0xFFFFFFFF, G2), + POWERPC_DEF("G2", CPU_POWERPC_G2, G2), /* PowerPC G2 H4 */ - POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, 0xFFFFFFFF, G2), + POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2), /* PowerPC G2 GP */ - POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, 0xFFFFFFFF, G2), + POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2), /* PowerPC G2 LS */ - POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, 0xFFFFFFFF, G2), + POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2), /* PowerPC G2LE */ /* Same as G2, with little-endian mode support */ - POWERPC_DEF("G2le", CPU_POWERPC_G2LE, 0xFFFFFFFF, G2LE), + POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE), /* PowerPC G2LE GP */ - POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, 0xFFFFFFFF, G2LE), + POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE), /* PowerPC G2LE LS */ - POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, 0xFFFFFFFF, G2LE), + POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE), /* PowerPC 604 */ - POWERPC_DEF("604", CPU_POWERPC_604, 0xFFFFFFFF, 604), + POWERPC_DEF("604", CPU_POWERPC_604, 604), /* PowerPC 604e */ - POWERPC_DEF("604e", CPU_POWERPC_604E, 0xFFFFFFFF, 604), + /* XXX: code names "Sirocco" "Mach 5" */ + POWERPC_DEF("604e", CPU_POWERPC_604E, 604), /* PowerPC 604e v1.0 */ - POWERPC_DEF("604e1.0", CPU_POWERPC_604E_v10, 0xFFFFFFFF, 604), + POWERPC_DEF("604e1.0", CPU_POWERPC_604E_v10, 604), /* PowerPC 604e v2.2 */ - POWERPC_DEF("604e2.2", CPU_POWERPC_604E_v22, 0xFFFFFFFF, 604), + POWERPC_DEF("604e2.2", CPU_POWERPC_604E_v22, 604), /* PowerPC 604e v2.4 */ - POWERPC_DEF("604e2.4", CPU_POWERPC_604E_v24, 0xFFFFFFFF, 604), + POWERPC_DEF("604e2.4", CPU_POWERPC_604E_v24, 604), /* PowerPC 604r */ - POWERPC_DEF("604r", CPU_POWERPC_604R, 0xFFFFFFFF, 604), + POWERPC_DEF("604r", CPU_POWERPC_604R, 604), #if defined(TODO) /* PowerPC 604ev */ - POWERPC_DEF("604ev", CPU_POWERPC_604EV, 0xFFFFFFFF, 604), + POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604), #endif /* PowerPC 7xx family */ /* Generic PowerPC 740 (G3) */ - POWERPC_DEF("740", CPU_POWERPC_7x0, 0xFFFFFFFF, 7x0), + POWERPC_DEF("740", CPU_POWERPC_7x0, 7x0), /* Generic PowerPC 750 (G3) */ - POWERPC_DEF("750", CPU_POWERPC_7x0, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750", CPU_POWERPC_7x0, 7x0), /* Code name for generic PowerPC 740/750 (G3) */ - POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 0xFFFFFFFF, 7x0), + POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 7x0), + /* XXX: 750 codename "Typhoon" */ /* PowerPC 740/750 is also known as G3 */ - POWERPC_DEF("G3", CPU_POWERPC_7x0, 0xFFFFFFFF, 7x0), + POWERPC_DEF("G3", CPU_POWERPC_7x0, 7x0), /* PowerPC 740 v2.0 (G3) */ - POWERPC_DEF("740v2.0", CPU_POWERPC_7x0_v20, 0xFFFFFFFF, 7x0), + POWERPC_DEF("740v2.0", CPU_POWERPC_7x0_v20, 7x0), /* PowerPC 750 v2.0 (G3) */ - POWERPC_DEF("750v2.0", CPU_POWERPC_7x0_v20, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750v2.0", CPU_POWERPC_7x0_v20, 7x0), /* PowerPC 740 v2.1 (G3) */ - POWERPC_DEF("740v2.1", CPU_POWERPC_7x0_v21, 0xFFFFFFFF, 7x0), + POWERPC_DEF("740v2.1", CPU_POWERPC_7x0_v21, 7x0), /* PowerPC 750 v2.1 (G3) */ - POWERPC_DEF("750v2.1", CPU_POWERPC_7x0_v21, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750v2.1", CPU_POWERPC_7x0_v21, 7x0), /* PowerPC 740 v2.2 (G3) */ - POWERPC_DEF("740v2.2", CPU_POWERPC_7x0_v22, 0xFFFFFFFF, 7x0), + POWERPC_DEF("740v2.2", CPU_POWERPC_7x0_v22, 7x0), /* PowerPC 750 v2.2 (G3) */ - POWERPC_DEF("750v2.2", CPU_POWERPC_7x0_v22, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750v2.2", CPU_POWERPC_7x0_v22, 7x0), /* PowerPC 740 v3.0 (G3) */ - POWERPC_DEF("740v3.0", CPU_POWERPC_7x0_v30, 0xFFFFFFFF, 7x0), + POWERPC_DEF("740v3.0", CPU_POWERPC_7x0_v30, 7x0), /* PowerPC 750 v3.0 (G3) */ - POWERPC_DEF("750v3.0", CPU_POWERPC_7x0_v30, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750v3.0", CPU_POWERPC_7x0_v30, 7x0), /* PowerPC 740 v3.1 (G3) */ - POWERPC_DEF("740v3.1", CPU_POWERPC_7x0_v31, 0xFFFFFFFF, 7x0), + POWERPC_DEF("740v3.1", CPU_POWERPC_7x0_v31, 7x0), /* PowerPC 750 v3.1 (G3) */ - POWERPC_DEF("750v3.1", CPU_POWERPC_7x0_v31, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750v3.1", CPU_POWERPC_7x0_v31, 7x0), /* PowerPC 740E (G3) */ - POWERPC_DEF("740e", CPU_POWERPC_740E, 0xFFFFFFFF, 7x0), + POWERPC_DEF("740e", CPU_POWERPC_740E, 7x0), /* PowerPC 740P (G3) */ - POWERPC_DEF("740p", CPU_POWERPC_7x0P, 0xFFFFFFFF, 7x0), + POWERPC_DEF("740p", CPU_POWERPC_7x0P, 7x0), /* PowerPC 750P (G3) */ - POWERPC_DEF("750p", CPU_POWERPC_7x0P, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750p", CPU_POWERPC_7x0P, 7x0), /* Code name for PowerPC 740P/750P (G3) */ - POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 0xFFFFFFFF, 7x0), + POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 7x0), /* PowerPC 750CL (G3 embedded) */ - POWERPC_DEF("750cl", CPU_POWERPC_750CL, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cl", CPU_POWERPC_750CL, 7x0), /* PowerPC 750CX (G3 embedded) */ - POWERPC_DEF("750cx", CPU_POWERPC_750CX, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cx", CPU_POWERPC_750CX, 7x0), /* PowerPC 750CX v2.1 (G3 embedded) */ - POWERPC_DEF("750cx2.1", CPU_POWERPC_750CX_v21, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cx2.1", CPU_POWERPC_750CX_v21, 7x0), /* PowerPC 750CX v2.2 (G3 embedded) */ - POWERPC_DEF("750cx2.2", CPU_POWERPC_750CX_v22, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cx2.2", CPU_POWERPC_750CX_v22, 7x0), /* PowerPC 750CXe (G3 embedded) */ - POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 7x0), /* PowerPC 750CXe v2.1 (G3 embedded) */ - POWERPC_DEF("750cxe21", CPU_POWERPC_750CXE_v21, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxe21", CPU_POWERPC_750CXE_v21, 7x0), /* PowerPC 750CXe v2.2 (G3 embedded) */ - POWERPC_DEF("750cxe22", CPU_POWERPC_750CXE_v22, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxe22", CPU_POWERPC_750CXE_v22, 7x0), /* PowerPC 750CXe v2.3 (G3 embedded) */ - POWERPC_DEF("750cxe23", CPU_POWERPC_750CXE_v23, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxe23", CPU_POWERPC_750CXE_v23, 7x0), /* PowerPC 750CXe v2.4 (G3 embedded) */ - POWERPC_DEF("750cxe24", CPU_POWERPC_750CXE_v24, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxe24", CPU_POWERPC_750CXE_v24, 7x0), /* PowerPC 750CXe v2.4b (G3 embedded) */ - POWERPC_DEF("750cxe24b", CPU_POWERPC_750CXE_v24b, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxe24b", CPU_POWERPC_750CXE_v24b, 7x0), /* PowerPC 750CXe v3.1 (G3 embedded) */ - POWERPC_DEF("750cxe31", CPU_POWERPC_750CXE_v31, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxe31", CPU_POWERPC_750CXE_v31, 7x0), /* PowerPC 750CXe v3.1b (G3 embedded) */ - POWERPC_DEF("750cxe3.1b", CPU_POWERPC_750CXE_v31b, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxe3.1b", CPU_POWERPC_750CXE_v31b, 7x0), /* PowerPC 750CXr (G3 embedded) */ - POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 7x0), /* PowerPC 750E (G3) */ - POWERPC_DEF("750e", CPU_POWERPC_750E, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750e", CPU_POWERPC_750E, 7x0), /* PowerPC 750FL (G3 embedded) */ - POWERPC_DEF("750fl", CPU_POWERPC_750FL, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx), /* PowerPC 750FX (G3 embedded) */ - POWERPC_DEF("750fx", CPU_POWERPC_750FX, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750fx", CPU_POWERPC_750FX, 750fx), /* PowerPC 750FX v1.0 (G3 embedded) */ - POWERPC_DEF("750fx1.0", CPU_POWERPC_750FX_v10, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750fx1.0", CPU_POWERPC_750FX_v10, 750fx), /* PowerPC 750FX v2.0 (G3 embedded) */ - POWERPC_DEF("750fx2.0", CPU_POWERPC_750FX_v20, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750fx2.0", CPU_POWERPC_750FX_v20, 750fx), /* PowerPC 750FX v2.1 (G3 embedded) */ - POWERPC_DEF("750fx2.1", CPU_POWERPC_750FX_v21, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750fx2.1", CPU_POWERPC_750FX_v21, 750fx), /* PowerPC 750FX v2.2 (G3 embedded) */ - POWERPC_DEF("750fx2.2", CPU_POWERPC_750FX_v22, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750fx2.2", CPU_POWERPC_750FX_v22, 750fx), /* PowerPC 750FX v2.3 (G3 embedded) */ - POWERPC_DEF("750fx2.3", CPU_POWERPC_750FX_v23, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750fx2.3", CPU_POWERPC_750FX_v23, 750fx), /* PowerPC 750GL (G3 embedded) */ - POWERPC_DEF("750gl", CPU_POWERPC_750GL, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750fx), /* PowerPC 750GX (G3 embedded) */ - POWERPC_DEF("750gx", CPU_POWERPC_750GX, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750gx", CPU_POWERPC_750GX, 750fx), /* PowerPC 750GX v1.0 (G3 embedded) */ - POWERPC_DEF("750gx1.0", CPU_POWERPC_750GX_v10, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750gx1.0", CPU_POWERPC_750GX_v10, 750fx), /* PowerPC 750GX v1.1 (G3 embedded) */ - POWERPC_DEF("750gx1.1", CPU_POWERPC_750GX_v11, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750gx1.1", CPU_POWERPC_750GX_v11, 750fx), /* PowerPC 750GX v1.2 (G3 embedded) */ - POWERPC_DEF("750gx1.2", CPU_POWERPC_750GX_v12, 0xFFFFFFFF, 750fx), + POWERPC_DEF("750gx1.2", CPU_POWERPC_750GX_v12, 750fx), /* PowerPC 750L (G3 embedded) */ - POWERPC_DEF("750l", CPU_POWERPC_750L, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750l", CPU_POWERPC_750L, 7x0), /* Code name for PowerPC 750L (G3 embedded) */ - POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 0xFFFFFFFF, 7x0), + POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 7x0), /* PowerPC 750L v2.2 (G3 embedded) */ - POWERPC_DEF("750l2.2", CPU_POWERPC_750L_v22, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750l2.2", CPU_POWERPC_750L_v22, 7x0), /* PowerPC 750L v3.0 (G3 embedded) */ - POWERPC_DEF("750l3.0", CPU_POWERPC_750L_v30, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750l3.0", CPU_POWERPC_750L_v30, 7x0), /* PowerPC 750L v3.2 (G3 embedded) */ - POWERPC_DEF("750l3.2", CPU_POWERPC_750L_v32, 0xFFFFFFFF, 7x0), + POWERPC_DEF("750l3.2", CPU_POWERPC_750L_v32, 7x0), /* Generic PowerPC 745 */ - POWERPC_DEF("745", CPU_POWERPC_7x5, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745", CPU_POWERPC_7x5, 7x5), /* Generic PowerPC 755 */ - POWERPC_DEF("755", CPU_POWERPC_7x5, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755", CPU_POWERPC_7x5, 7x5), /* Code name for PowerPC 745/755 */ - POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 0xFFFFFFFF, 7x5), + POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 7x5), /* PowerPC 745 v1.0 */ - POWERPC_DEF("745v1.0", CPU_POWERPC_7x5_v10, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v1.0", CPU_POWERPC_7x5_v10, 7x5), /* PowerPC 755 v1.0 */ - POWERPC_DEF("755v1.0", CPU_POWERPC_7x5_v10, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v1.0", CPU_POWERPC_7x5_v10, 7x5), /* PowerPC 745 v1.1 */ - POWERPC_DEF("745v1.1", CPU_POWERPC_7x5_v11, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v1.1", CPU_POWERPC_7x5_v11, 7x5), /* PowerPC 755 v1.1 */ - POWERPC_DEF("755v1.1", CPU_POWERPC_7x5_v11, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v1.1", CPU_POWERPC_7x5_v11, 7x5), /* PowerPC 745 v2.0 */ - POWERPC_DEF("745v2.0", CPU_POWERPC_7x5_v20, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.0", CPU_POWERPC_7x5_v20, 7x5), /* PowerPC 755 v2.0 */ - POWERPC_DEF("755v2.0", CPU_POWERPC_7x5_v20, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.0", CPU_POWERPC_7x5_v20, 7x5), /* PowerPC 745 v2.1 */ - POWERPC_DEF("745v2.1", CPU_POWERPC_7x5_v21, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.1", CPU_POWERPC_7x5_v21, 7x5), /* PowerPC 755 v2.1 */ - POWERPC_DEF("755v2.1", CPU_POWERPC_7x5_v21, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.1", CPU_POWERPC_7x5_v21, 7x5), /* PowerPC 745 v2.2 */ - POWERPC_DEF("745v2.2", CPU_POWERPC_7x5_v22, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.2", CPU_POWERPC_7x5_v22, 7x5), /* PowerPC 755 v2.2 */ - POWERPC_DEF("755v2.2", CPU_POWERPC_7x5_v22, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.2", CPU_POWERPC_7x5_v22, 7x5), /* PowerPC 745 v2.3 */ - POWERPC_DEF("745v2.3", CPU_POWERPC_7x5_v23, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.3", CPU_POWERPC_7x5_v23, 7x5), /* PowerPC 755 v2.3 */ - POWERPC_DEF("755v2.3", CPU_POWERPC_7x5_v23, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.3", CPU_POWERPC_7x5_v23, 7x5), /* PowerPC 745 v2.4 */ - POWERPC_DEF("745v2.4", CPU_POWERPC_7x5_v24, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.4", CPU_POWERPC_7x5_v24, 7x5), /* PowerPC 755 v2.4 */ - POWERPC_DEF("755v2.4", CPU_POWERPC_7x5_v24, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.4", CPU_POWERPC_7x5_v24, 7x5), /* PowerPC 745 v2.5 */ - POWERPC_DEF("745v2.5", CPU_POWERPC_7x5_v25, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.5", CPU_POWERPC_7x5_v25, 7x5), /* PowerPC 755 v2.5 */ - POWERPC_DEF("755v2.5", CPU_POWERPC_7x5_v25, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.5", CPU_POWERPC_7x5_v25, 7x5), /* PowerPC 745 v2.6 */ - POWERPC_DEF("745v2.6", CPU_POWERPC_7x5_v26, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.6", CPU_POWERPC_7x5_v26, 7x5), /* PowerPC 755 v2.6 */ - POWERPC_DEF("755v2.6", CPU_POWERPC_7x5_v26, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.6", CPU_POWERPC_7x5_v26, 7x5), /* PowerPC 745 v2.7 */ - POWERPC_DEF("745v2.7", CPU_POWERPC_7x5_v27, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.7", CPU_POWERPC_7x5_v27, 7x5), /* PowerPC 755 v2.7 */ - POWERPC_DEF("755v2.7", CPU_POWERPC_7x5_v27, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.7", CPU_POWERPC_7x5_v27, 7x5), /* PowerPC 745 v2.8 */ - POWERPC_DEF("745v2.8", CPU_POWERPC_7x5_v28, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745v2.8", CPU_POWERPC_7x5_v28, 7x5), /* PowerPC 755 v2.8 */ - POWERPC_DEF("755v2.8", CPU_POWERPC_7x5_v28, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755v2.8", CPU_POWERPC_7x5_v28, 7x5), #if defined (TODO) /* PowerPC 745P (G3) */ - POWERPC_DEF("745p", CPU_POWERPC_7x5P, 0xFFFFFFFF, 7x5), + POWERPC_DEF("745p", CPU_POWERPC_7x5P, 7x5), /* PowerPC 755P (G3) */ - POWERPC_DEF("755p", CPU_POWERPC_7x5P, 0xFFFFFFFF, 7x5), + POWERPC_DEF("755p", CPU_POWERPC_7x5P, 7x5), #endif /* PowerPC 74xx family */ /* PowerPC 7400 (G4) */ - POWERPC_DEF("7400", CPU_POWERPC_7400, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400", CPU_POWERPC_7400, 7400), /* Code name for PowerPC 7400 */ - POWERPC_DEF("Max", CPU_POWERPC_7400, 0xFFFFFFFF, 7400), + POWERPC_DEF("Max", CPU_POWERPC_7400, 7400), /* PowerPC 74xx is also well known as G4 */ - POWERPC_DEF("G4", CPU_POWERPC_7400, 0xFFFFFFFF, 7400), + POWERPC_DEF("G4", CPU_POWERPC_7400, 7400), /* PowerPC 7400 v1.0 (G4) */ - POWERPC_DEF("7400v1.0", CPU_POWERPC_7400_v10, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400v1.0", CPU_POWERPC_7400_v10, 7400), /* PowerPC 7400 v1.1 (G4) */ - POWERPC_DEF("7400v1.1", CPU_POWERPC_7400_v11, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400v1.1", CPU_POWERPC_7400_v11, 7400), /* PowerPC 7400 v2.0 (G4) */ - POWERPC_DEF("7400v2.0", CPU_POWERPC_7400_v20, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400v2.0", CPU_POWERPC_7400_v20, 7400), /* PowerPC 7400 v2.2 (G4) */ - POWERPC_DEF("7400v2.2", CPU_POWERPC_7400_v22, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400v2.2", CPU_POWERPC_7400_v22, 7400), /* PowerPC 7400 v2.6 (G4) */ - POWERPC_DEF("7400v2.6", CPU_POWERPC_7400_v26, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400v2.6", CPU_POWERPC_7400_v26, 7400), /* PowerPC 7400 v2.7 (G4) */ - POWERPC_DEF("7400v2.7", CPU_POWERPC_7400_v27, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400v2.7", CPU_POWERPC_7400_v27, 7400), /* PowerPC 7400 v2.8 (G4) */ - POWERPC_DEF("7400v2.8", CPU_POWERPC_7400_v28, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400v2.8", CPU_POWERPC_7400_v28, 7400), /* PowerPC 7400 v2.9 (G4) */ - POWERPC_DEF("7400v2.9", CPU_POWERPC_7400_v29, 0xFFFFFFFF, 7400), + POWERPC_DEF("7400v2.9", CPU_POWERPC_7400_v29, 7400), /* PowerPC 7410 (G4) */ - POWERPC_DEF("7410", CPU_POWERPC_7410, 0xFFFFFFFF, 7410), + POWERPC_DEF("7410", CPU_POWERPC_7410, 7410), /* Code name for PowerPC 7410 */ - POWERPC_DEF("Nitro", CPU_POWERPC_7410, 0xFFFFFFFF, 7410), + POWERPC_DEF("Nitro", CPU_POWERPC_7410, 7410), /* PowerPC 7410 v1.0 (G4) */ - POWERPC_DEF("7410v1.0", CPU_POWERPC_7410_v10, 0xFFFFFFFF, 7410), + POWERPC_DEF("7410v1.0", CPU_POWERPC_7410_v10, 7410), /* PowerPC 7410 v1.1 (G4) */ - POWERPC_DEF("7410v1.1", CPU_POWERPC_7410_v11, 0xFFFFFFFF, 7410), + POWERPC_DEF("7410v1.1", CPU_POWERPC_7410_v11, 7410), /* PowerPC 7410 v1.2 (G4) */ - POWERPC_DEF("7410v1.2", CPU_POWERPC_7410_v12, 0xFFFFFFFF, 7410), + POWERPC_DEF("7410v1.2", CPU_POWERPC_7410_v12, 7410), /* PowerPC 7410 v1.3 (G4) */ - POWERPC_DEF("7410v1.3", CPU_POWERPC_7410_v13, 0xFFFFFFFF, 7410), + POWERPC_DEF("7410v1.3", CPU_POWERPC_7410_v13, 7410), /* PowerPC 7410 v1.4 (G4) */ - POWERPC_DEF("7410v1.4", CPU_POWERPC_7410_v14, 0xFFFFFFFF, 7410), + POWERPC_DEF("7410v1.4", CPU_POWERPC_7410_v14, 7410), /* PowerPC 7448 (G4) */ - POWERPC_DEF("7448", CPU_POWERPC_7448, 0xFFFFFFFF, 7400), + POWERPC_DEF("7448", CPU_POWERPC_7448, 7400), /* PowerPC 7448 v1.0 (G4) */ - POWERPC_DEF("7448v1.0", CPU_POWERPC_7448_v10, 0xFFFFFFFF, 7400), + POWERPC_DEF("7448v1.0", CPU_POWERPC_7448_v10, 7400), /* PowerPC 7448 v1.1 (G4) */ - POWERPC_DEF("7448v1.1", CPU_POWERPC_7448_v11, 0xFFFFFFFF, 7400), + POWERPC_DEF("7448v1.1", CPU_POWERPC_7448_v11, 7400), /* PowerPC 7448 v2.0 (G4) */ - POWERPC_DEF("7448v2.0", CPU_POWERPC_7448_v20, 0xFFFFFFFF, 7400), + POWERPC_DEF("7448v2.0", CPU_POWERPC_7448_v20, 7400), /* PowerPC 7448 v2.1 (G4) */ - POWERPC_DEF("7448v2.1", CPU_POWERPC_7448_v21, 0xFFFFFFFF, 7400), + POWERPC_DEF("7448v2.1", CPU_POWERPC_7448_v21, 7400), /* PowerPC 7450 (G4) */ - POWERPC_DEF("7450", CPU_POWERPC_7450, 0xFFFFFFFF, 7450), + POWERPC_DEF("7450", CPU_POWERPC_7450, 7450), /* Code name for PowerPC 7450 */ - POWERPC_DEF("Vger", CPU_POWERPC_7450, 0xFFFFFFFF, 7450), + POWERPC_DEF("Vger", CPU_POWERPC_7450, 7450), /* PowerPC 7450 v1.0 (G4) */ - POWERPC_DEF("7450v1.0", CPU_POWERPC_7450_v10, 0xFFFFFFFF, 7450), + POWERPC_DEF("7450v1.0", CPU_POWERPC_7450_v10, 7450), /* PowerPC 7450 v1.1 (G4) */ - POWERPC_DEF("7450v1.1", CPU_POWERPC_7450_v11, 0xFFFFFFFF, 7450), + POWERPC_DEF("7450v1.1", CPU_POWERPC_7450_v11, 7450), /* PowerPC 7450 v1.2 (G4) */ - POWERPC_DEF("7450v1.2", CPU_POWERPC_7450_v12, 0xFFFFFFFF, 7450), + POWERPC_DEF("7450v1.2", CPU_POWERPC_7450_v12, 7450), /* PowerPC 7450 v2.0 (G4) */ - POWERPC_DEF("7450v2.0", CPU_POWERPC_7450_v20, 0xFFFFFFFF, 7450), + POWERPC_DEF("7450v2.0", CPU_POWERPC_7450_v20, 7450), /* PowerPC 7450 v2.1 (G4) */ - POWERPC_DEF("7450v2.1", CPU_POWERPC_7450_v21, 0xFFFFFFFF, 7450), + POWERPC_DEF("7450v2.1", CPU_POWERPC_7450_v21, 7450), /* PowerPC 7441 (G4) */ - POWERPC_DEF("7441", CPU_POWERPC_74x1, 0xFFFFFFFF, 7440), + POWERPC_DEF("7441", CPU_POWERPC_74x1, 7440), /* PowerPC 7451 (G4) */ - POWERPC_DEF("7451", CPU_POWERPC_74x1, 0xFFFFFFFF, 7450), + POWERPC_DEF("7451", CPU_POWERPC_74x1, 7450), /* PowerPC 7441g (G4) */ - POWERPC_DEF("7441g", CPU_POWERPC_74x1G, 0xFFFFFFFF, 7440), + POWERPC_DEF("7441g", CPU_POWERPC_74x1G, 7440), /* PowerPC 7451g (G4) */ - POWERPC_DEF("7451g", CPU_POWERPC_74x1G, 0xFFFFFFFF, 7450), + POWERPC_DEF("7451g", CPU_POWERPC_74x1G, 7450), /* PowerPC 7445 (G4) */ - POWERPC_DEF("7445", CPU_POWERPC_74x5, 0xFFFFFFFF, 7445), + POWERPC_DEF("7445", CPU_POWERPC_74x5, 7445), /* PowerPC 7455 (G4) */ - POWERPC_DEF("7455", CPU_POWERPC_74x5, 0xFFFFFFFF, 7455), + POWERPC_DEF("7455", CPU_POWERPC_74x5, 7455), /* Code name for PowerPC 7445/7455 */ - POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 0xFFFFFFFF, 7455), + POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 7455), /* PowerPC 7445 v1.0 (G4) */ - POWERPC_DEF("7445v1.0", CPU_POWERPC_74x5_v10, 0xFFFFFFFF, 7445), + POWERPC_DEF("7445v1.0", CPU_POWERPC_74x5_v10, 7445), /* PowerPC 7455 v1.0 (G4) */ - POWERPC_DEF("7455v1.0", CPU_POWERPC_74x5_v10, 0xFFFFFFFF, 7455), + POWERPC_DEF("7455v1.0", CPU_POWERPC_74x5_v10, 7455), /* PowerPC 7445 v2.1 (G4) */ - POWERPC_DEF("7445v2.1", CPU_POWERPC_74x5_v21, 0xFFFFFFFF, 7445), + POWERPC_DEF("7445v2.1", CPU_POWERPC_74x5_v21, 7445), /* PowerPC 7455 v2.1 (G4) */ - POWERPC_DEF("7455v2.1", CPU_POWERPC_74x5_v21, 0xFFFFFFFF, 7455), + POWERPC_DEF("7455v2.1", CPU_POWERPC_74x5_v21, 7455), /* PowerPC 7445 v3.2 (G4) */ - POWERPC_DEF("7445v3.2", CPU_POWERPC_74x5_v32, 0xFFFFFFFF, 7445), + POWERPC_DEF("7445v3.2", CPU_POWERPC_74x5_v32, 7445), /* PowerPC 7455 v3.2 (G4) */ - POWERPC_DEF("7455v3.2", CPU_POWERPC_74x5_v32, 0xFFFFFFFF, 7455), + POWERPC_DEF("7455v3.2", CPU_POWERPC_74x5_v32, 7455), /* PowerPC 7445 v3.3 (G4) */ - POWERPC_DEF("7445v3.3", CPU_POWERPC_74x5_v33, 0xFFFFFFFF, 7445), + POWERPC_DEF("7445v3.3", CPU_POWERPC_74x5_v33, 7445), /* PowerPC 7455 v3.3 (G4) */ - POWERPC_DEF("7455v3.3", CPU_POWERPC_74x5_v33, 0xFFFFFFFF, 7455), + POWERPC_DEF("7455v3.3", CPU_POWERPC_74x5_v33, 7455), /* PowerPC 7445 v3.4 (G4) */ - POWERPC_DEF("7445v3.4", CPU_POWERPC_74x5_v34, 0xFFFFFFFF, 7445), + POWERPC_DEF("7445v3.4", CPU_POWERPC_74x5_v34, 7445), /* PowerPC 7455 v3.4 (G4) */ - POWERPC_DEF("7455v3.4", CPU_POWERPC_74x5_v34, 0xFFFFFFFF, 7455), + POWERPC_DEF("7455v3.4", CPU_POWERPC_74x5_v34, 7455), /* PowerPC 7447 (G4) */ - POWERPC_DEF("7447", CPU_POWERPC_74x7, 0xFFFFFFFF, 7445), + POWERPC_DEF("7447", CPU_POWERPC_74x7, 7445), /* PowerPC 7457 (G4) */ - POWERPC_DEF("7457", CPU_POWERPC_74x7, 0xFFFFFFFF, 7455), + POWERPC_DEF("7457", CPU_POWERPC_74x7, 7455), /* Code name for PowerPC 7447/7457 */ - POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 0xFFFFFFFF, 7455), + POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 7455), /* PowerPC 7447 v1.0 (G4) */ - POWERPC_DEF("7447v1.0", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7445), + POWERPC_DEF("7447v1.0", CPU_POWERPC_74x7_v10, 7445), /* PowerPC 7457 v1.0 (G4) */ - POWERPC_DEF("7457v1.0", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7455), + POWERPC_DEF("7457v1.0", CPU_POWERPC_74x7_v10, 7455), /* Code name for PowerPC 7447A/7457A */ - POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7_v10, 0xFFFFFFFF, 7455), + POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7_v10, 7455), /* PowerPC 7447 v1.1 (G4) */ - POWERPC_DEF("7447v1.1", CPU_POWERPC_74x7_v11, 0xFFFFFFFF, 7445), + POWERPC_DEF("7447v1.1", CPU_POWERPC_74x7_v11, 7445), /* PowerPC 7457 v1.1 (G4) */ - POWERPC_DEF("7457v1.1", CPU_POWERPC_74x7_v11, 0xFFFFFFFF, 7455), + POWERPC_DEF("7457v1.1", CPU_POWERPC_74x7_v11, 7455), /* PowerPC 7447 v1.2 (G4) */ - POWERPC_DEF("7447v1.2", CPU_POWERPC_74x7_v12, 0xFFFFFFFF, 7445), + POWERPC_DEF("7447v1.2", CPU_POWERPC_74x7_v12, 7445), /* PowerPC 7457 v1.2 (G4) */ - POWERPC_DEF("7457v1.2", CPU_POWERPC_74x7_v12, 0xFFFFFFFF, 7455), + POWERPC_DEF("7457v1.2", CPU_POWERPC_74x7_v12, 7455), /* 64 bits PowerPC */ #if defined (TARGET_PPC64) /* PowerPC 620 */ - POWERPC_DEF("620", CPU_POWERPC_620, 0xFFFFFFFF, 620), + /* XXX: code name "Trident" */ + POWERPC_DEF("620", CPU_POWERPC_620, 620), #if defined (TODO) /* PowerPC 630 (POWER3) */ - POWERPC_DEF("630", CPU_POWERPC_630, 0xFFFFFFFF, 630), - POWERPC_DEF("POWER3", CPU_POWERPC_630, 0xFFFFFFFF, 630), + /* XXX: code names: "Boxer" "Dino" */ + POWERPC_DEF("630", CPU_POWERPC_630, 630), + POWERPC_DEF("POWER3", CPU_POWERPC_630, 630), #endif #if defined (TODO) /* PowerPC 631 (Power 3+) */ - POWERPC_DEF("631", CPU_POWERPC_631, 0xFFFFFFFF, 631), - POWERPC_DEF("POWER3+", CPU_POWERPC_631, 0xFFFFFFFF, 631), + POWERPC_DEF("631", CPU_POWERPC_631, 631), + POWERPC_DEF("POWER3+", CPU_POWERPC_631, 631), #endif #if defined (TODO) /* POWER4 */ - POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, 0xFFFFFFFF, POWER4), + POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4), #endif #if defined (TODO) /* POWER4p */ - POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, 0xFFFFFFFF, POWER4P), + POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P), #endif #if defined (TODO) /* POWER5 */ - POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, 0xFFFFFFFF, POWER5), + POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5), /* POWER5GR */ - POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, 0xFFFFFFFF, POWER5), + POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5), #endif #if defined (TODO) /* POWER5+ */ - POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, 0xFFFFFFFF, POWER5P), + POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P), /* POWER5GS */ - POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, 0xFFFFFFFF, POWER5P), + POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P), #endif #if defined (TODO) /* POWER6 */ - POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, 0xFFFFFFFF, POWER6), + POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6), /* POWER6 running in POWER5 mode */ - POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, 0xFFFFFFFF, POWER5), + POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5), /* POWER6A */ - POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, 0xFFFFFFFF, POWER6), + POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6), #endif /* PowerPC 970 */ - POWERPC_DEF("970", CPU_POWERPC_970, 0xFFFFFFFF, 970), + POWERPC_DEF("970", CPU_POWERPC_970, 970), /* PowerPC 970FX (G5) */ - POWERPC_DEF("970fx", CPU_POWERPC_970FX, 0xFFFFFFFF, 970FX), + POWERPC_DEF("970fx", CPU_POWERPC_970FX, 970FX), /* PowerPC 970FX v1.0 (G5) */ - POWERPC_DEF("970fx1.0", CPU_POWERPC_970FX_v10, 0xFFFFFFFF, 970FX), + POWERPC_DEF("970fx1.0", CPU_POWERPC_970FX_v10, 970FX), /* PowerPC 970FX v2.0 (G5) */ - POWERPC_DEF("970fx2.0", CPU_POWERPC_970FX_v20, 0xFFFFFFFF, 970FX), + POWERPC_DEF("970fx2.0", CPU_POWERPC_970FX_v20, 970FX), /* PowerPC 970FX v2.1 (G5) */ - POWERPC_DEF("970fx2.1", CPU_POWERPC_970FX_v21, 0xFFFFFFFF, 970FX), + POWERPC_DEF("970fx2.1", CPU_POWERPC_970FX_v21, 970FX), /* PowerPC 970FX v3.0 (G5) */ - POWERPC_DEF("970fx3.0", CPU_POWERPC_970FX_v30, 0xFFFFFFFF, 970FX), + POWERPC_DEF("970fx3.0", CPU_POWERPC_970FX_v30, 970FX), /* PowerPC 970FX v3.1 (G5) */ - POWERPC_DEF("970fx3.1", CPU_POWERPC_970FX_v31, 0xFFFFFFFF, 970FX), + POWERPC_DEF("970fx3.1", CPU_POWERPC_970FX_v31, 970FX), /* PowerPC 970GX (G5) */ - POWERPC_DEF("970gx", CPU_POWERPC_970GX, 0xFFFFFFFF, 970GX), + POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX), /* PowerPC 970MP */ - POWERPC_DEF("970mp", CPU_POWERPC_970MP, 0xFFFFFFFF, 970MP), + POWERPC_DEF("970mp", CPU_POWERPC_970MP, 970MP), /* PowerPC 970MP v1.0 */ - POWERPC_DEF("970mp1.0", CPU_POWERPC_970MP_v10, 0xFFFFFFFF, 970MP), + POWERPC_DEF("970mp1.0", CPU_POWERPC_970MP_v10, 970MP), /* PowerPC 970MP v1.1 */ - POWERPC_DEF("970mp1.1", CPU_POWERPC_970MP_v11, 0xFFFFFFFF, 970MP), + POWERPC_DEF("970mp1.1", CPU_POWERPC_970MP_v11, 970MP), #if defined (TODO) /* PowerPC Cell */ - POWERPC_DEF("Cell", CPU_POWERPC_CELL, 0xFFFFFFFF, 970), + POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970), #endif #if defined (TODO) /* PowerPC Cell v1.0 */ - POWERPC_DEF("Cell1.0", CPU_POWERPC_CELL_v10, 0xFFFFFFFF, 970), + POWERPC_DEF("Cell1.0", CPU_POWERPC_CELL_v10, 970), #endif #if defined (TODO) /* PowerPC Cell v2.0 */ - POWERPC_DEF("Cell2.0", CPU_POWERPC_CELL_v20, 0xFFFFFFFF, 970), + POWERPC_DEF("Cell2.0", CPU_POWERPC_CELL_v20, 970), #endif #if defined (TODO) /* PowerPC Cell v3.0 */ - POWERPC_DEF("Cell3.0", CPU_POWERPC_CELL_v30, 0xFFFFFFFF, 970), + POWERPC_DEF("Cell3.0", CPU_POWERPC_CELL_v30, 970), #endif #if defined (TODO) /* PowerPC Cell v3.1 */ - POWERPC_DEF("Cell3.1", CPU_POWERPC_CELL_v31, 0xFFFFFFFF, 970), + POWERPC_DEF("Cell3.1", CPU_POWERPC_CELL_v31, 970), #endif #if defined (TODO) /* PowerPC Cell v3.2 */ - POWERPC_DEF("Cell3.2", CPU_POWERPC_CELL_v32, 0xFFFFFFFF, 970), + POWERPC_DEF("Cell3.2", CPU_POWERPC_CELL_v32, 970), #endif #if defined (TODO) /* RS64 (Apache/A35) */ @@ -5874,59 +5877,59 @@ static ppc_def_t ppc_defs[] = { * and the PowerPC 64 one. */ /* What about A10 & A30 ? */ - POWERPC_DEF("RS64", CPU_POWERPC_RS64, 0xFFFFFFFF, RS64), - POWERPC_DEF("Apache", CPU_POWERPC_RS64, 0xFFFFFFFF, RS64), - POWERPC_DEF("A35", CPU_POWERPC_RS64, 0xFFFFFFFF, RS64), + POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64), + POWERPC_DEF("Apache", CPU_POWERPC_RS64, RS64), + POWERPC_DEF("A35", CPU_POWERPC_RS64, RS64), #endif #if defined (TODO) /* RS64-II (NorthStar/A50) */ - POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, 0xFFFFFFFF, RS64), - POWERPC_DEF("NorthStar", CPU_POWERPC_RS64II, 0xFFFFFFFF, RS64), - POWERPC_DEF("A50", CPU_POWERPC_RS64II, 0xFFFFFFFF, RS64), + POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64), + POWERPC_DEF("NorthStar", CPU_POWERPC_RS64II, RS64), + POWERPC_DEF("A50", CPU_POWERPC_RS64II, RS64), #endif #if defined (TODO) /* RS64-III (Pulsar) */ - POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, 0xFFFFFFFF, RS64), - POWERPC_DEF("Pulsar", CPU_POWERPC_RS64III, 0xFFFFFFFF, RS64), + POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64), + POWERPC_DEF("Pulsar", CPU_POWERPC_RS64III, RS64), #endif #if defined (TODO) /* RS64-IV (IceStar/IStar/SStar) */ - POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, 0xFFFFFFFF, RS64), - POWERPC_DEF("IceStar", CPU_POWERPC_RS64IV, 0xFFFFFFFF, RS64), - POWERPC_DEF("IStar", CPU_POWERPC_RS64IV, 0xFFFFFFFF, RS64), - POWERPC_DEF("SStar", CPU_POWERPC_RS64IV, 0xFFFFFFFF, RS64), + POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64), + POWERPC_DEF("IceStar", CPU_POWERPC_RS64IV, RS64), + POWERPC_DEF("IStar", CPU_POWERPC_RS64IV, RS64), + POWERPC_DEF("SStar", CPU_POWERPC_RS64IV, RS64), #endif #endif /* defined (TARGET_PPC64) */ /* POWER */ #if defined (TODO) /* Original POWER */ - POWERPC_DEF("POWER", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), - POWERPC_DEF("RIOS", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), - POWERPC_DEF("RSC", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), - POWERPC_DEF("RSC3308", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), - POWERPC_DEF("RSC4608", CPU_POWERPC_POWER, 0xFFFFFFFF, POWER), + POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("RIOS", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("RSC", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("RSC3308", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("RSC4608", CPU_POWERPC_POWER, POWER), #endif #if defined (TODO) /* POWER2 */ - POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, 0xFFFFFFFF, POWER), - POWERPC_DEF("RSC2", CPU_POWERPC_POWER2, 0xFFFFFFFF, POWER), - POWERPC_DEF("P2SC", CPU_POWERPC_POWER2, 0xFFFFFFFF, POWER), + POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER), + POWERPC_DEF("RSC2", CPU_POWERPC_POWER2, POWER), + POWERPC_DEF("P2SC", CPU_POWERPC_POWER2, POWER), #endif /* PA semi cores */ #if defined (TODO) /* PA PA6T */ - POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, 0xFFFFFFFF, PA6T), + POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T), #endif /* Generic PowerPCs */ #if defined (TARGET_PPC64) #if defined (TODO) - POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, 0xFFFFFFFF, PPC64), + POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, PPC64), #endif #endif - POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, 0xFFFFFFFF, PPC32), - POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, 0xFFFFFFFF, DEFAULT), + POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, PPC32), + POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, DEFAULT), /* Fallback */ - POWERPC_DEF("default", CPU_POWERPC_DEFAULT, 0xFFFFFFFF, DEFAULT), + POWERPC_DEF("default", CPU_POWERPC_DEFAULT, DEFAULT), }; /*****************************************************************************/ @@ -6514,31 +6517,77 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) return 0; } -const ppc_def_t *cpu_ppc_find_by_name (const unsigned char *name) +static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr) { - int i, max; + const ppc_def_t *ret; + uint32_t pvr_rev; + int i, best, match, best_match, max; + ret = NULL; max = sizeof(ppc_defs) / sizeof(ppc_def_t); + best = -1; + pvr_rev = pvr & 0xFFFF; + /* We want all specified bits to match */ + best_match = 32 - ctz32(pvr_rev); for (i = 0; i < max; i++) { - if (strcasecmp(name, ppc_defs[i].name) == 0) { - return &ppc_defs[i]; + /* We check that the 16 higher bits are the same to ensure the CPU + * model will be the choosen one. + */ + if (((pvr ^ ppc_defs[i].pvr) >> 16) == 0) { + /* We want as much as possible of the low-level 16 bits + * to be the same but we allow inexact matches. + */ + match = clz32(pvr_rev ^ (ppc_defs[i].pvr & 0xFFFF)); + /* We check '>=' instead of '>' because the PPC_defs table + * is ordered by increasing revision. + * Then, we will match the higher revision compatible + * with the requested PVR + */ + if (match >= best_match) { + best = i; + best_match = match; + } } } - return NULL; + if (best != -1) + ret = &ppc_defs[best]; + + return ret; } -const ppc_def_t *cpu_ppc_find_by_pvr (uint32_t pvr) -{ - int i, max; +#include +const ppc_def_t *cpu_ppc_find_by_name (const unsigned char *name) +{ + const ppc_def_t *ret; + const unsigned char *p; + int i, max, len; + + /* Check if the given name is a PVR */ + len = strlen(name); + if (len == 10 && name[0] == '0' && name[1] == 'x') { + p = name + 2; + goto check_pvr; + } else if (len == 8) { + p = name; + check_pvr: + for (i = 0; i < 8; i++) { + if (!isxdigit(*p++)) + break; + } + if (i == 8) + return ppc_find_by_pvr(strtoul(name, NULL, 16)); + } + ret = NULL; max = sizeof(ppc_defs) / sizeof(ppc_def_t); for (i = 0; i < max; i++) { - if ((pvr & ppc_defs[i].pvr_mask) == - (ppc_defs[i].pvr & ppc_defs[i].pvr_mask)) { - return &ppc_defs[i]; + if (strcasecmp(name, ppc_defs[i].name) == 0) { + ret = &ppc_defs[i]; + break; } } - return NULL; + + return ret; } void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) -- cgit v1.2.3 From 9ee6e8bb853bdea7ef6c645a1a07aa55fd206aba Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Nov 2007 00:04:49 +0000 Subject: ARMv7 support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3572 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 1 + Makefile.target | 4 +- cpu-exec.c | 13 +- fpu/softfloat-native.h | 16 + fpu/softfloat.c | 75 + fpu/softfloat.h | 4 + hw/arm_boot.c | 22 +- hw/arm_gic.c | 460 ++-- hw/arm_sysctl.c | 5 +- hw/armv7m.c | 204 ++ hw/armv7m_nvic.c | 381 ++++ hw/integratorcp.c | 4 +- hw/mpcore.c | 323 +++ hw/pl011.c | 15 +- hw/pl022.c | 264 +++ hw/pl061.c | 256 +++ hw/pxa2xx.c | 8 +- hw/realview.c | 66 +- hw/realview_gic.c | 64 + hw/ssd0303.c | 273 +++ hw/ssd0323.c | 267 +++ hw/stellaris.c | 1101 ++++++++++ hw/versatilepb.c | 8 +- qemu-doc.texi | 42 +- target-arm/cpu.h | 187 +- target-arm/exec.h | 19 +- target-arm/helper.c | 1104 ++++++++-- target-arm/op.c | 731 ++++++- target-arm/op_addsub.h | 106 + target-arm/op_helper.c | 78 +- target-arm/op_mem.h | 59 + target-arm/op_neon.h | 1754 +++++++++++++++ target-arm/translate.c | 5630 +++++++++++++++++++++++++++++++++++++++++------- vl.c | 54 +- vl.h | 40 +- 35 files changed, 12392 insertions(+), 1246 deletions(-) create mode 100644 hw/armv7m.c create mode 100644 hw/armv7m_nvic.c create mode 100644 hw/mpcore.c create mode 100644 hw/pl022.c create mode 100644 hw/pl061.c create mode 100644 hw/realview_gic.c create mode 100644 hw/ssd0303.c create mode 100644 hw/ssd0323.c create mode 100644 hw/stellaris.c create mode 100644 target-arm/op_addsub.h create mode 100644 target-arm/op_neon.h diff --git a/Changelog b/Changelog index 101240023..75f39d6ef 100644 --- a/Changelog +++ b/Changelog @@ -17,6 +17,7 @@ - MIPS mipssim pequdo machine (Thiemo Seufer) - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh) - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski) + - ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery) version 0.9.0: diff --git a/Makefile.target b/Makefile.target index ee91a57d1..25fed3fa6 100644 --- a/Makefile.target +++ b/Makefile.target @@ -493,7 +493,9 @@ 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 pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o VL_OBJS+= versatile_pci.o sd.o ptimer.o -VL_OBJS+= arm_gic.o realview.o arm_sysctl.o +VL_OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o +VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o i2c.o ssd0303.o pl022.o +VL_OBJS+= ssd0323.o pl061.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o diff --git a/cpu-exec.c b/cpu-exec.c index 4ba63fba3..aa58cbb24 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -173,6 +173,7 @@ static inline TranslationBlock *tb_find_fast(void) flags |= (1 << 6); if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) flags |= (1 << 7); + flags |= (env->condexec_bits << 8); cs_base = 0; pc = env->regs[15]; #elif defined(TARGET_SPARC) @@ -511,8 +512,18 @@ int cpu_exec(CPUState *env1) env->exception_index = EXCP_FIQ; do_interrupt(env); } + /* ARMv7-M interrupt return works by loading a magic value + into the PC. On real hardware the load causes the + return to occur. The qemu implementation performs the + jump normally, then does the exception return when the + CPU tries to execute code at the magic address. + This will cause the magic PC value to be pushed to + the stack if an interrupt occured at the wrong time. + We avoid this by disabling interrupts when + pc contains a magic address. */ if (interrupt_request & CPU_INTERRUPT_HARD - && !(env->uncached_cpsr & CPSR_I)) { + && ((IS_M(env) && env->regs[15] < 0xfffffff0) + || !(env->uncached_cpsr & CPSR_I))) { env->exception_index = EXCP_IRQ; do_interrupt(env); } diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 29777178b..53bf68192 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -224,6 +224,11 @@ INLINE float32 float32_chs(float32 a) return -a; } +INLINE float32 float32_scalbn(float32 a, int n) +{ + return scalbnf(a, n); +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -311,6 +316,11 @@ INLINE float64 float64_chs(float64 a) return -a; } +INLINE float64 float64_scalbn(float64 a, int n) +{ + return scalbn(a, n); +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -391,4 +401,10 @@ INLINE floatx80 floatx80_chs(floatx80 a) { return -a; } + +INLINE floatx80 floatx80_scalbn(floatx80 a, int n) +{ + return scalbnl(a, n); +} + #endif diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 6db6cf132..8ebb69264 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5377,3 +5377,78 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ COMPARE(32, 0xff) COMPARE(64, 0x7ff) + +/* Multiply A by 2 raised to the power N. */ +float32 float32_scalbn( float32 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + + if ( aExp == 0xFF ) { + return a; + } + aExp += n; + return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); +} + +float64 float64_scalbn( float64 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + + if ( aExp == 0x7FF ) { + return a; + } + aExp += n; + return roundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); +} + +#ifdef FLOATX80 +floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + + if ( aExp == 0x7FF ) { + return a; + } + aExp += n; + return roundAndPackFloatx80( STATUS(floatx80_rounding_precision), + aSign, aExp, aSig, 0 STATUS_VAR ); +} +#endif + +#ifdef FLOAT128 +float128 float128_scalbn( float128 a, int n STATUS_PARAM ) +{ + flag aSign; + int32 aExp; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + return a; + } + aExp += n; + return roundAndPackFloat128( aSign, aExp, aSig0, aSig1, 0 STATUS_VAR ); + +} +#endif diff --git a/fpu/softfloat.h b/fpu/softfloat.h index f344d2ea5..f0261fb6a 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -244,6 +244,7 @@ int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); int float32_is_nan( float32 ); int float32_is_signaling_nan( float32 ); +float32 float32_scalbn( float32, int STATUS_PARAM ); INLINE float32 float32_abs(float32 a) { @@ -295,6 +296,7 @@ int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); int float64_is_nan( float64 a ); int float64_is_signaling_nan( float64 ); +float64 float64_scalbn( float64, int STATUS_PARAM ); INLINE float64 float64_abs(float64 a) { @@ -339,6 +341,7 @@ int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_nan( floatx80 ); int floatx80_is_signaling_nan( floatx80 ); +floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM ); INLINE floatx80 floatx80_abs(floatx80 a) { @@ -387,6 +390,7 @@ int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); int float128_is_nan( float128 ); int float128_is_signaling_nan( float128 ); +float128 float128_scalbn( float128, int STATUS_PARAM ); INLINE float128 float128_abs(float128 a) { diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 7a99b4175..8ef14ab4e 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -1,7 +1,7 @@ /* * ARM kernel loader. * - * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2006-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL. @@ -24,6 +24,22 @@ static uint32_t bootloader[] = { 0 /* Kernel entry point. Set by integratorcp_init. */ }; +/* Entry point for secondary CPUs. Enable interrupt controller and + Issue WFI until start address is written to system controller. */ +static uint32_t smpboot[] = { + 0xe3a00201, /* mov r0, #0x10000000 */ + 0xe3800601, /* orr r0, r0, #0x001000000 */ + 0xe3a01001, /* mov r1, #1 */ + 0xe5801100, /* str r1, [r0, #0x100] */ + 0xe3a00201, /* mov r0, #0x10000000 */ + 0xe3800030, /* orr r0, #0x30 */ + 0xe320f003, /* wfi */ + 0xe5901000, /* ldr r1, [r0] */ + 0xe3110003, /* tst r1, #3 */ + 0x1afffffb, /* bne */ + 0xe12fff11 /* bx r1 */ +}; + static void main_cpu_reset(void *opaque) { CPUState *env = opaque; @@ -33,6 +49,8 @@ static void main_cpu_reset(void *opaque) arm_load_kernel(env, env->ram_size, env->kernel_filename, env->kernel_cmdline, env->initrd_filename, env->board_id, env->loader_start); + + /* TODO: Reset secondary CPUs. */ } static void set_kernel_args(uint32_t ram_size, int initrd_size, @@ -211,6 +229,8 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) stl_raw(phys_ram_base + (n * 4), bootloader[n]); + for (n = 0; n < sizeof(smpboot) / 4; n++) + stl_raw(phys_ram_base + ram_size + (n * 4), smpboot[n]); if (old_param) set_kernel_args_old(ram_size, initrd_size, kernel_cmdline, loader_start); diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 8cd7182cf..774b79bf8 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -1,17 +1,15 @@ /* - * ARM AMBA Generic/Distributed Interrupt Controller + * ARM Generic/Distributed Interrupt Controller * - * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2006-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL. */ -/* TODO: Some variants of this controller can handle multiple CPUs. - Currently only single CPU operation is implemented. */ - -#include "vl.h" -#include "arm_pic.h" +/* This file contains implementation code for the RealView EB interrupt + controller, MPCore distributed interrupt controller and ARMv7-M + Nested Vectored Interrupt Controller. */ //#define DEBUG_GIC @@ -22,58 +20,84 @@ do { printf("arm_gic: " fmt , ##args); } while (0) #define DPRINTF(fmt, args...) do {} while(0) #endif -/* Distributed interrupt controller. */ - +#ifdef NVIC +static const uint8_t gic_id[] = +{ 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 }; +#define GIC_DIST_OFFSET 0 +/* The NVIC has 16 internal vectors. However these are not exposed + through the normal GIC interface. */ +#define GIC_BASE_IRQ 32 +#else static const uint8_t gic_id[] = { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; - -#define GIC_NIRQ 96 +#define GIC_DIST_OFFSET 0x1000 +#define GIC_BASE_IRQ 0 +#endif typedef struct gic_irq_state { + /* ??? The documentation seems to imply the enable bits are global, even + for per-cpu interrupts. This seems strange. */ unsigned enabled:1; - unsigned pending:1; - unsigned active:1; + unsigned pending:NCPU; + unsigned active:NCPU; unsigned level:1; - unsigned model:1; /* 0 = 1:N, 1 = N:N */ + unsigned model:1; /* 0 = N:N, 1 = 1:N */ unsigned trigger:1; /* nonzero = edge triggered. */ } gic_irq_state; +#define ALL_CPU_MASK ((1 << NCPU) - 1) + #define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1 #define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0 #define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled -#define GIC_SET_PENDING(irq) s->irq_state[irq].pending = 1 -#define GIC_CLEAR_PENDING(irq) s->irq_state[irq].pending = 0 -#define GIC_TEST_PENDING(irq) s->irq_state[irq].pending -#define GIC_SET_ACTIVE(irq) s->irq_state[irq].active = 1 -#define GIC_CLEAR_ACTIVE(irq) s->irq_state[irq].active = 0 -#define GIC_TEST_ACTIVE(irq) s->irq_state[irq].active +#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm) +#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm) +#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0) +#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm) +#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm) +#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0) #define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1 #define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0 #define GIC_TEST_MODEL(irq) s->irq_state[irq].model -#define GIC_SET_LEVEL(irq) s->irq_state[irq].level = 1 -#define GIC_CLEAR_LEVEL(irq) s->irq_state[irq].level = 0 -#define GIC_TEST_LEVEL(irq) s->irq_state[irq].level +#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm) +#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm) +#define GIC_TEST_LEVEL(irq, cm) (s->irq_state[irq].level & (cm)) != 0 #define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1 #define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0 #define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger +#define GIC_GET_PRIORITY(irq, cpu) \ + (((irq) < 32) ? s->priority1[irq][cpu] : s->priority2[(irq) - 32]) +#ifdef NVIC +#define GIC_TARGET(irq) 1 +#else +#define GIC_TARGET(irq) s->irq_target[irq] +#endif typedef struct gic_state { uint32_t base; - qemu_irq parent_irq; + qemu_irq parent_irq[NCPU]; int enabled; - int cpu_enabled; + int cpu_enabled[NCPU]; gic_irq_state irq_state[GIC_NIRQ]; +#ifndef NVIC int irq_target[GIC_NIRQ]; - int priority[GIC_NIRQ]; - int last_active[GIC_NIRQ]; - - int priority_mask; - int running_irq; - int running_priority; - int current_pending; +#endif + int priority1[32][NCPU]; + int priority2[GIC_NIRQ - 32]; + int last_active[GIC_NIRQ][NCPU]; + + int priority_mask[NCPU]; + int running_irq[NCPU]; + int running_priority[NCPU]; + int current_pending[NCPU]; + + qemu_irq *in; +#ifdef NVIC + void *nvic; +#endif } gic_state; /* TODO: Many places that call this routine could be optimized. */ @@ -83,112 +107,136 @@ static void gic_update(gic_state *s) int best_irq; int best_prio; int irq; - - s->current_pending = 1023; - if (!s->enabled || !s->cpu_enabled) { - qemu_irq_lower(s->parent_irq); - return; - } - best_prio = 0x100; - best_irq = 1023; - for (irq = 0; irq < 96; irq++) { - if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq)) { - if (s->priority[irq] < best_prio) { - best_prio = s->priority[irq]; - best_irq = irq; + int level; + int cpu; + int cm; + + for (cpu = 0; cpu < NCPU; cpu++) { + cm = 1 << cpu; + s->current_pending[cpu] = 1023; + if (!s->enabled || !s->cpu_enabled[cpu]) { + qemu_irq_lower(s->parent_irq[cpu]); + return; + } + best_prio = 0x100; + best_irq = 1023; + for (irq = 0; irq < GIC_NIRQ; irq++) { + if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq, cm)) { + if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { + best_prio = GIC_GET_PRIORITY(irq, cpu); + best_irq = irq; + } } } - } - if (best_prio > s->priority_mask) { - qemu_irq_lower(s->parent_irq); - } else { - s->current_pending = best_irq; - if (best_prio < s->running_priority) { - DPRINTF("Raised pending IRQ %d\n", best_irq); - qemu_irq_raise(s->parent_irq); + level = 0; + if (best_prio <= s->priority_mask[cpu]) { + s->current_pending[cpu] = best_irq; + if (best_prio < s->running_priority[cpu]) { + DPRINTF("Raised pending IRQ %d\n", best_irq); + level = 1; + } } + qemu_set_irq(s->parent_irq[cpu], level); } } +static void __attribute__((unused)) +gic_set_pending_private(gic_state *s, int cpu, int irq) +{ + int cm = 1 << cpu; + + if (GIC_TEST_PENDING(irq, cm)) + return; + + DPRINTF("Set %d pending cpu %d\n", irq, cpu); + GIC_SET_PENDING(irq, cm); + gic_update(s); +} + +/* Process a change in an external IRQ input. */ static void gic_set_irq(void *opaque, int irq, int level) { gic_state *s = (gic_state *)opaque; /* The first external input line is internal interrupt 32. */ irq += 32; - if (level == GIC_TEST_LEVEL(irq)) + if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK)) return; if (level) { - GIC_SET_LEVEL(irq); + GIC_SET_LEVEL(irq, ALL_CPU_MASK); if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) { - DPRINTF("Set %d pending\n", irq); - GIC_SET_PENDING(irq); + DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq)); + GIC_SET_PENDING(irq, GIC_TARGET(irq)); } } else { - GIC_CLEAR_LEVEL(irq); + GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK); } gic_update(s); } -static void gic_set_running_irq(gic_state *s, int irq) +static void gic_set_running_irq(gic_state *s, int cpu, int irq) { - s->running_irq = irq; - if (irq == 1023) - s->running_priority = 0x100; - else - s->running_priority = s->priority[irq]; + s->running_irq[cpu] = irq; + if (irq == 1023) { + s->running_priority[cpu] = 0x100; + } else { + s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu); + } gic_update(s); } -static uint32_t gic_acknowledge_irq(gic_state *s) +static uint32_t gic_acknowledge_irq(gic_state *s, int cpu) { int new_irq; - new_irq = s->current_pending; - if (new_irq == 1023 || s->priority[new_irq] >= s->running_priority) { + int cm = 1 << cpu; + new_irq = s->current_pending[cpu]; + if (new_irq == 1023 + || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) { DPRINTF("ACK no pending IRQ\n"); return 1023; } - qemu_irq_lower(s->parent_irq); - s->last_active[new_irq] = s->running_irq; - /* For level triggered interrupts we clear the pending bit while - the interrupt is active. */ - GIC_CLEAR_PENDING(new_irq); - gic_set_running_irq(s, new_irq); + s->last_active[new_irq][cpu] = s->running_irq[cpu]; + /* Clear pending flags for both level and edge triggered interrupts. + Level triggered IRQs will be reasserted once they become inactive. */ + GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm); + gic_set_running_irq(s, cpu, new_irq); DPRINTF("ACK %d\n", new_irq); return new_irq; } -static void gic_complete_irq(gic_state * s, int irq) +static void gic_complete_irq(gic_state * s, int cpu, int irq) { int update = 0; + int cm = 1 << cpu; DPRINTF("EOI %d\n", irq); - if (s->running_irq == 1023) + if (s->running_irq[cpu] == 1023) return; /* No active IRQ. */ if (irq != 1023) { /* Mark level triggered interrupts as pending if they are still raised. */ if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq) - && GIC_TEST_LEVEL(irq)) { - GIC_SET_PENDING(irq); + && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { + DPRINTF("Set %d pending mask %x\n", irq, cm); + GIC_SET_PENDING(irq, cm); update = 1; } } - if (irq != s->running_irq) { + if (irq != s->running_irq[cpu]) { /* Complete an IRQ that is not currently running. */ - int tmp = s->running_irq; - while (s->last_active[tmp] != 1023) { - if (s->last_active[tmp] == irq) { - s->last_active[tmp] = s->last_active[irq]; + int tmp = s->running_irq[cpu]; + while (s->last_active[tmp][cpu] != 1023) { + if (s->last_active[tmp][cpu] == irq) { + s->last_active[tmp][cpu] = s->last_active[irq][cpu]; break; } - tmp = s->last_active[tmp]; + tmp = s->last_active[tmp][cpu]; } if (update) { gic_update(s); } } else { /* Complete the current running IRQ. */ - gic_set_running_irq(s, s->last_active[s->running_irq]); + gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); } } @@ -198,15 +246,22 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) uint32_t res; int irq; int i; + int cpu; + int cm; + int mask; - offset -= s->base + 0x1000; + cpu = gic_get_current_cpu(); + cm = 1 << cpu; + offset -= s->base + GIC_DIST_OFFSET; if (offset < 0x100) { +#ifndef NVIC if (offset == 0) return s->enabled; if (offset == 4) - return (GIC_NIRQ / 32) - 1; + return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5); if (offset < 0x08) return 0; +#endif goto bad_reg; } else if (offset < 0x200) { /* Interrupt Set/Clear Enable. */ @@ -214,6 +269,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) irq = (offset - 0x100) * 8; else irq = (offset - 0x180) * 8; + irq += GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; res = 0; @@ -228,40 +284,48 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) irq = (offset - 0x200) * 8; else irq = (offset - 0x280) * 8; + irq += GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; res = 0; + mask = (irq < 32) ? cm : ALL_CPU_MASK; for (i = 0; i < 8; i++) { - if (GIC_TEST_PENDING(irq + i)) { + if (GIC_TEST_PENDING(irq + i, mask)) { res |= (1 << i); } } } else if (offset < 0x400) { /* Interrupt Active. */ - irq = (offset - 0x300) * 8; + irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; res = 0; + mask = (irq < 32) ? cm : ALL_CPU_MASK; for (i = 0; i < 8; i++) { - if (GIC_TEST_ACTIVE(irq + i)) { + if (GIC_TEST_ACTIVE(irq + i, mask)) { res |= (1 << i); } } } else if (offset < 0x800) { /* Interrupt Priority. */ - irq = offset - 0x400; + irq = (offset - 0x400) + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; - res = s->priority[irq]; + res = GIC_GET_PRIORITY(irq, cpu); +#ifndef NVIC } else if (offset < 0xc00) { /* Interrupt CPU Target. */ - irq = offset - 0x800; + irq = (offset - 0x800) + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; - res = s->irq_target[irq]; + if (irq >= 29 && irq <= 31) { + res = cm; + } else { + res = GIC_TARGET(irq); + } } else if (offset < 0xf00) { /* Interrupt Configuration. */ - irq = (offset - 0xc00) * 2; + irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; res = 0; @@ -271,6 +335,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) if (GIC_TEST_TRIGGER(irq + i)) res |= (2 << (i * 2)); } +#endif } else if (offset < 0xfe0) { goto bad_reg; } else /* offset >= 0xfe0 */ { @@ -282,7 +347,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) } return res; bad_reg: - cpu_abort (cpu_single_env, "gic_dist_readb: Bad offset %x\n", offset); + cpu_abort(cpu_single_env, "gic_dist_readb: Bad offset %x\n", (int)offset); return 0; } @@ -297,6 +362,13 @@ static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset) static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) { uint32_t val; +#ifdef NVIC + gic_state *s = (gic_state *)opaque; + uint32_t addr; + addr = offset - s->base; + if (addr < 0x100 || addr > 0xd00) + return nvic_readl(s->nvic, addr); +#endif val = gic_dist_readw(opaque, offset); val |= gic_dist_readw(opaque, offset + 2) << 16; return val; @@ -308,9 +380,14 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, gic_state *s = (gic_state *)opaque; int irq; int i; + int cpu; - offset -= s->base + 0x1000; + cpu = gic_get_current_cpu(); + offset -= s->base + GIC_DIST_OFFSET; if (offset < 0x100) { +#ifdef NVIC + goto bad_reg; +#else if (offset == 0) { s->enabled = (value & 1); DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); @@ -319,27 +396,36 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else { goto bad_reg; } +#endif } else if (offset < 0x180) { /* Interrupt Set Enable. */ - irq = (offset - 0x100) * 8; + irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; + if (irq < 16) + value = 0xff; for (i = 0; i < 8; i++) { if (value & (1 << i)) { + int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq); if (!GIC_TEST_ENABLED(irq + i)) DPRINTF("Enabled IRQ %d\n", irq + i); GIC_SET_ENABLED(irq + i); /* If a raised level triggered IRQ enabled then mark is as pending. */ - if (GIC_TEST_LEVEL(irq + i) && !GIC_TEST_TRIGGER(irq + i)) - GIC_SET_PENDING(irq + i); + if (GIC_TEST_LEVEL(irq + i, mask) + && !GIC_TEST_TRIGGER(irq + i)) { + DPRINTF("Set %d pending mask %x\n", irq + i, mask); + GIC_SET_PENDING(irq + i, mask); + } } } } else if (offset < 0x200) { /* Interrupt Clear Enable. */ - irq = (offset - 0x180) * 8; + irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; + if (irq < 16) + value = 0; for (i = 0; i < 8; i++) { if (value & (1 << i)) { if (GIC_TEST_ENABLED(irq + i)) @@ -349,22 +435,28 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } } else if (offset < 0x280) { /* Interrupt Set Pending. */ - irq = (offset - 0x200) * 8; + irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; + if (irq < 16) + irq = 0; + for (i = 0; i < 8; i++) { if (value & (1 << i)) { - GIC_SET_PENDING(irq + i); + GIC_SET_PENDING(irq + i, GIC_TARGET(irq)); } } } else if (offset < 0x300) { /* Interrupt Clear Pending. */ - irq = (offset - 0x280) * 8; + irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; for (i = 0; i < 8; i++) { + /* ??? This currently clears the pending bit for all CPUs, even + for per-CPU interrupts. It's unclear whether this is the + corect behavior. */ if (value & (1 << i)) { - GIC_CLEAR_PENDING(irq + i); + GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); } } } else if (offset < 0x400) { @@ -372,21 +464,32 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, goto bad_reg; } else if (offset < 0x800) { /* Interrupt Priority. */ - irq = offset - 0x400; + irq = (offset - 0x400) + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; - s->priority[irq] = value; + if (irq < 32) { + s->priority1[irq][cpu] = value; + } else { + s->priority2[irq - 32] = value; + } +#ifndef NVIC } else if (offset < 0xc00) { /* Interrupt CPU Target. */ - irq = offset - 0x800; + irq = (offset - 0x800) + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; - s->irq_target[irq] = value; + if (irq < 29) + value = 0; + else if (irq < 32) + value = ALL_CPU_MASK; + s->irq_target[irq] = value & ALL_CPU_MASK; } else if (offset < 0xf00) { /* Interrupt Configuration. */ - irq = (offset - 0xc00) * 4; + irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; + if (irq < 32) + value |= 0xaa; for (i = 0; i < 4; i++) { if (value & (1 << (i * 2))) { GIC_SET_MODEL(irq + i); @@ -399,25 +502,20 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, GIC_CLEAR_TRIGGER(irq + i); } } +#endif } else { - /* 0xf00 is only handled for word writes. */ + /* 0xf00 is only handled for 32-bit writes. */ goto bad_reg; } gic_update(s); return; bad_reg: - cpu_abort (cpu_single_env, "gic_dist_writeb: Bad offset %x\n", offset); + cpu_abort(cpu_single_env, "gic_dist_writeb: Bad offset %x\n", (int)offset); } static void gic_dist_writew(void *opaque, target_phys_addr_t offset, uint32_t value) { - gic_state *s = (gic_state *)opaque; - if (offset - s->base == 0xf00) { - GIC_SET_PENDING(value & 0x3ff); - gic_update(s); - return; - } gic_dist_writeb(opaque, offset, value & 0xff); gic_dist_writeb(opaque, offset + 1, value >> 8); } @@ -425,6 +523,41 @@ static void gic_dist_writew(void *opaque, target_phys_addr_t offset, static void gic_dist_writel(void *opaque, target_phys_addr_t offset, uint32_t value) { + gic_state *s = (gic_state *)opaque; +#ifdef NVIC + uint32_t addr; + addr = offset - s->base; + if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) { + nvic_writel(s->nvic, addr, value); + return; + } +#endif + if (offset - s->base == GIC_DIST_OFFSET + 0xf00) { + int cpu; + int irq; + int mask; + + cpu = gic_get_current_cpu(); + irq = value & 0x3ff; + switch ((value >> 24) & 3) { + case 0: + mask = (value >> 16) & ALL_CPU_MASK; + break; + case 1: + mask = 1 << cpu; + break; + case 2: + mask = ALL_CPU_MASK ^ (1 << cpu); + break; + default: + DPRINTF("Bad Soft Int target filter\n"); + mask = ALL_CPU_MASK; + break; + } + GIC_SET_PENDING(irq, mask); + gic_update(s); + return; + } gic_dist_writew(opaque, offset, value & 0xffff); gic_dist_writew(opaque, offset + 2, value >> 16); } @@ -441,105 +574,100 @@ static CPUWriteMemoryFunc *gic_dist_writefn[] = { gic_dist_writel }; -static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset) +#ifndef NVIC +static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) { - gic_state *s = (gic_state *)opaque; - offset -= s->base; switch (offset) { case 0x00: /* Control */ - return s->cpu_enabled; + return s->cpu_enabled[cpu]; case 0x04: /* Priority mask */ - return s->priority_mask; + return s->priority_mask[cpu]; case 0x08: /* Binary Point */ /* ??? Not implemented. */ return 0; case 0x0c: /* Acknowledge */ - return gic_acknowledge_irq(s); + return gic_acknowledge_irq(s, cpu); case 0x14: /* Runing Priority */ - return s->running_priority; + return s->running_priority[cpu]; case 0x18: /* Highest Pending Interrupt */ - return s->current_pending; + return s->current_pending[cpu]; default: - cpu_abort (cpu_single_env, "gic_cpu_read: Bad offset %x\n", offset); + cpu_abort(cpu_single_env, "gic_cpu_read: Bad offset %x\n", + (int)offset); return 0; } } -static void gic_cpu_write(void *opaque, target_phys_addr_t offset, - uint32_t value) +static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) { - gic_state *s = (gic_state *)opaque; - offset -= s->base; switch (offset) { case 0x00: /* Control */ - s->cpu_enabled = (value & 1); + s->cpu_enabled[cpu] = (value & 1); DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis"); break; case 0x04: /* Priority mask */ - s->priority_mask = (value & 0x3ff); + s->priority_mask[cpu] = (value & 0xff); break; case 0x08: /* Binary Point */ /* ??? Not implemented. */ break; case 0x10: /* End Of Interrupt */ - return gic_complete_irq(s, value & 0x3ff); + return gic_complete_irq(s, cpu, value & 0x3ff); default: - cpu_abort (cpu_single_env, "gic_cpu_write: Bad offset %x\n", offset); + cpu_abort(cpu_single_env, "gic_cpu_write: Bad offset %x\n", + (int)offset); return; } gic_update(s); } - -static CPUReadMemoryFunc *gic_cpu_readfn[] = { - gic_cpu_read, - gic_cpu_read, - gic_cpu_read -}; - -static CPUWriteMemoryFunc *gic_cpu_writefn[] = { - gic_cpu_write, - gic_cpu_write, - gic_cpu_write -}; +#endif static void gic_reset(gic_state *s) { int i; memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state)); - s->priority_mask = 0xf0; - s->current_pending = 1023; - s->running_irq = 1023; - s->running_priority = 0x100; + for (i = 0 ; i < NCPU; i++) { + s->priority_mask[i] = 0xf0; + s->current_pending[i] = 1023; + s->running_irq[i] = 1023; + s->running_priority[i] = 0x100; +#ifdef NVIC + /* The NVIC doesn't have per-cpu interfaces, so enable by default. */ + s->cpu_enabled[i] = 1; +#else + s->cpu_enabled[i] = 0; +#endif + } for (i = 0; i < 15; i++) { GIC_SET_ENABLED(i); GIC_SET_TRIGGER(i); } +#ifdef NVIC + /* The NVIC is always enabled. */ + s->enabled = 1; +#else s->enabled = 0; - s->cpu_enabled = 0; +#endif } -qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq) +static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq) { gic_state *s; - qemu_irq *qi; int iomemtype; + int i; s = (gic_state *)qemu_mallocz(sizeof(gic_state)); if (!s) return NULL; - qi = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ); - s->parent_irq = parent_irq; - if (base != 0xffffffff) { - iomemtype = cpu_register_io_memory(0, gic_cpu_readfn, - gic_cpu_writefn, s); - cpu_register_physical_memory(base, 0x00001000, iomemtype); - iomemtype = cpu_register_io_memory(0, gic_dist_readfn, - gic_dist_writefn, s); - cpu_register_physical_memory(base + 0x1000, 0x00001000, iomemtype); - s->base = base; - } else { - s->base = 0; + s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ); + for (i = 0; i < NCPU; i++) { + s->parent_irq[i] = parent_irq[i]; } + iomemtype = cpu_register_io_memory(0, gic_dist_readfn, + gic_dist_writefn, s); + cpu_register_physical_memory(base + GIC_DIST_OFFSET, 0x00001000, + iomemtype); + s->base = base; gic_reset(s); - return qi; + return s; } diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 468a494db..e3179e2a9 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -1,7 +1,7 @@ /* * Status and system control registers for ARM RealView/Versatile boards. * - * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2006-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL. @@ -200,6 +200,9 @@ void arm_sysctl_init(uint32_t base, uint32_t sys_id) return; s->base = base; s->sys_id = sys_id; + /* The MPcore bootloader uses these flags to start secondary CPUs. + We don't use a bootloader, so do this here. */ + s->flags = 3; iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn, arm_sysctl_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); diff --git a/hw/armv7m.c b/hw/armv7m.c new file mode 100644 index 000000000..f0a90e12d --- /dev/null +++ b/hw/armv7m.c @@ -0,0 +1,204 @@ +/* + * ARMV7M System emulation. + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +/* Bitbanded IO. Each word corresponds to a single bit. */ + +/* Get the byte address of the real memory for a bitband acess. */ +static inline uint32_t bitband_addr(uint32_t addr) +{ + uint32_t res; + + res = addr & 0xe0000000; + res |= (addr & 0x1ffffff) >> 5; + return res; + +} + +static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset) +{ + uint8_t v; + cpu_physical_memory_read(bitband_addr(offset), &v, 1); + return (v & (1 << ((offset >> 2) & 7))) != 0; +} + +static void bitband_writeb(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + uint32_t addr; + uint8_t mask; + uint8_t v; + addr = bitband_addr(offset); + mask = (1 << ((offset >> 2) & 7)); + cpu_physical_memory_read(addr, &v, 1); + if (value & 1) + v |= mask; + else + v &= ~mask; + cpu_physical_memory_write(addr, &v, 1); +} + +static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset) +{ + uint32_t addr; + uint16_t mask; + uint16_t v; + addr = bitband_addr(offset) & ~1; + mask = (1 << ((offset >> 2) & 15)); + mask = tswap16(mask); + cpu_physical_memory_read(addr, (uint8_t *)&v, 2); + return (v & mask) != 0; +} + +static void bitband_writew(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + uint32_t addr; + uint16_t mask; + uint16_t v; + addr = bitband_addr(offset) & ~1; + mask = (1 << ((offset >> 2) & 15)); + mask = tswap16(mask); + cpu_physical_memory_read(addr, (uint8_t *)&v, 2); + if (value & 1) + v |= mask; + else + v &= ~mask; + cpu_physical_memory_write(addr, (uint8_t *)&v, 2); +} + +static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset) +{ + uint32_t addr; + uint32_t mask; + uint32_t v; + addr = bitband_addr(offset) & ~3; + mask = (1 << ((offset >> 2) & 31)); + mask = tswap32(mask); + cpu_physical_memory_read(addr, (uint8_t *)&v, 4); + return (v & mask) != 0; +} + +static void bitband_writel(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + uint32_t addr; + uint32_t mask; + uint32_t v; + addr = bitband_addr(offset) & ~3; + mask = (1 << ((offset >> 2) & 31)); + mask = tswap32(mask); + cpu_physical_memory_read(addr, (uint8_t *)&v, 4); + if (value & 1) + v |= mask; + else + v &= ~mask; + cpu_physical_memory_write(addr, (uint8_t *)&v, 4); +} + +static CPUReadMemoryFunc *bitband_readfn[] = { + bitband_readb, + bitband_readw, + bitband_readl +}; + +static CPUWriteMemoryFunc *bitband_writefn[] = { + bitband_writeb, + bitband_writew, + bitband_writel +}; + +static void armv7m_bitband_init(void) +{ + int iomemtype; + + iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn, + NULL); + cpu_register_physical_memory(0x22000000, 0x02000000, iomemtype); + cpu_register_physical_memory(0x42000000, 0x02000000, iomemtype); +} + +/* Board init. */ +/* Init CPU and memory for a v7-M based board. + flash_size and sram_size are in kb. + Returns the NVIC array. */ + +qemu_irq *armv7m_init(int flash_size, int sram_size, + const char *kernel_filename, const char *cpu_model) +{ + CPUState *env; + qemu_irq *pic; + uint32_t pc; + int image_size; + uint64_t entry; + uint64_t lowaddr; + + flash_size *= 1024; + sram_size *= 1024; + + if (!cpu_model) + cpu_model = "cortex-m3"; + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + +#if 0 + /* > 32Mb SRAM gets complicated because it overlaps the bitband area. + We don't have proper commandline options, so allocate half of memory + as SRAM, up to a maximum of 32Mb, and the rest as code. */ + if (ram_size > (512 + 32) * 1024 * 1024) + ram_size = (512 + 32) * 1024 * 1024; + sram_size = (ram_size / 2) & TARGET_PAGE_MASK; + if (sram_size > 32 * 1024 * 1024) + sram_size = 32 * 1024 * 1024; + code_size = ram_size - sram_size; +#endif + + /* Flash programming is done via the SCU, so pretend it is ROM. */ + cpu_register_physical_memory(0, flash_size, IO_MEM_ROM); + cpu_register_physical_memory(0x20000000, sram_size, + flash_size + IO_MEM_RAM); + armv7m_bitband_init(); + + pic = armv7m_nvic_init(env); + + image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL); + if (image_size < 0) { + image_size = load_image(kernel_filename, phys_ram_base); + lowaddr = 0; + } + if (image_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* If the image was loaded at address zero then assume it is a + regular ROM image and perform the normal CPU reset sequence. + Otherwise jump directly to the entry point. */ + if (lowaddr == 0) { + env->regs[13] = tswap32(*(uint32_t *)phys_ram_base); + pc = tswap32(*(uint32_t *)(phys_ram_base + 4)); + } else { + pc = entry; + } + env->thumb = pc & 1; + env->regs[15] = pc & ~1; + + /* Hack to map an additional page of ram at the top of the address + space. This stops qemu complaining about executing code outside RAM + when returning from an exception. */ + cpu_register_physical_memory(0xfffff000, 0x1000, IO_MEM_RAM + ram_size); + + return pic; +} + diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c new file mode 100644 index 000000000..d30408288 --- /dev/null +++ b/hw/armv7m_nvic.c @@ -0,0 +1,381 @@ +/* + * ARM Nested Vectored Interrupt Controller + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + * + * The ARMv7M System controller is fairly tightly tied in with the + * NVIC. Much of that is also implemented here. + */ + +#include "vl.h" +#include "arm_pic.h" + +#define GIC_NIRQ 64 +#define NCPU 1 +#define NVIC 1 + +/* Only a single "CPU" interface is present. */ +static inline int +gic_get_current_cpu(void) +{ + return 0; +} + +static uint32_t nvic_readl(void *opaque, uint32_t offset); +static void nvic_writel(void *opaque, uint32_t offset, uint32_t value); + +#include "arm_gic.c" + +typedef struct { + struct { + uint32_t control; + uint32_t reload; + int64_t tick; + QEMUTimer *timer; + } systick; + gic_state *gic; +} nvic_state; + +/* qemu timers run at 1GHz. We want something closer to 1MHz. */ +#define SYSTICK_SCALE 1000ULL + +#define SYSTICK_ENABLE (1 << 0) +#define SYSTICK_TICKINT (1 << 1) +#define SYSTICK_CLKSOURCE (1 << 2) +#define SYSTICK_COUNTFLAG (1 << 16) + +/* Conversion factor from qemu timer to SysTick frequencies. + QEMU uses a base of 1GHz, so these give 20MHz and 1MHz for core and + reference frequencies. */ + +static inline int64_t systick_scale(nvic_state *s) +{ + if (s->systick.control & SYSTICK_CLKSOURCE) + return 50; + else + return 1000; +} + +static void systick_reload(nvic_state *s, int reset) +{ + if (reset) + s->systick.tick = qemu_get_clock(vm_clock); + s->systick.tick += (s->systick.reload + 1) * systick_scale(s); + qemu_mod_timer(s->systick.timer, s->systick.tick); +} + +static void systick_timer_tick(void * opaque) +{ + nvic_state *s = (nvic_state *)opaque; + s->systick.control |= SYSTICK_COUNTFLAG; + if (s->systick.control & SYSTICK_TICKINT) { + /* Trigger the interrupt. */ + armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); + } + if (s->systick.reload == 0) { + s->systick.control &= ~SYSTICK_ENABLE; + } else { + systick_reload(s, 0); + } +} + +/* The external routines use the hardware vector numbering, ie. the first + IRQ is #16. The internal GIC routines use #32 as the first IRQ. */ +void armv7m_nvic_set_pending(void *opaque, int irq) +{ + nvic_state *s = (nvic_state *)opaque; + if (irq >= 16) + irq += 16; + gic_set_pending_private(s->gic, 0, irq); +} + +/* Make pending IRQ active. */ +int armv7m_nvic_acknowledge_irq(void *opaque) +{ + nvic_state *s = (nvic_state *)opaque; + uint32_t irq; + + irq = gic_acknowledge_irq(s->gic, 0); + if (irq == 1023) + cpu_abort(cpu_single_env, "Interrupt but no vector\n"); + if (irq >= 32) + irq -= 16; + return irq; +} + +void armv7m_nvic_complete_irq(void *opaque, int irq) +{ + nvic_state *s = (nvic_state *)opaque; + if (irq >= 16) + irq += 16; + gic_complete_irq(s->gic, 0, irq); +} + +static uint32_t nvic_readl(void *opaque, uint32_t offset) +{ + nvic_state *s = (nvic_state *)opaque; + uint32_t val; + int irq; + + switch (offset) { + case 4: /* Interrupt Control Type. */ + return (GIC_NIRQ / 32) - 1; + case 0x10: /* SysTick Control and Status. */ + val = s->systick.control; + s->systick.control &= ~SYSTICK_COUNTFLAG; + return val; + case 0x14: /* SysTick Reload Value. */ + return s->systick.reload; + case 0x18: /* SysTick Current Value. */ + { + int64_t t; + if ((s->systick.control & SYSTICK_ENABLE) == 0) + return 0; + t = qemu_get_clock(vm_clock); + if (t >= s->systick.tick) + return 0; + val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1; + /* The interrupt in triggered when the timer reaches zero. + However the counter is not reloaded until the next clock + tick. This is a hack to return zero during the first tick. */ + if (val > s->systick.reload) + val = 0; + return val; + } + case 0x1c: /* SysTick Calibration Value. */ + return 10000; + case 0xd00: /* CPUID Base. */ + return cpu_single_env->cp15.c0_cpuid; + case 0xd04: /* Interrypt Control State. */ + /* VECTACTIVE */ + val = s->gic->running_irq[0]; + if (val == 1023) { + val = 0; + } else if (val >= 32) { + val -= 16; + } + /* RETTOBASE */ + if (s->gic->running_irq[0] == 1023 + || s->gic->last_active[s->gic->running_irq[0]][0] == 1023) { + val |= (1 << 11); + } + /* VECTPENDING */ + if (s->gic->current_pending[0] != 1023) + val |= (s->gic->current_pending[0] << 12); + /* ISRPENDING */ + for (irq = 32; irq < GIC_NIRQ; irq++) { + if (s->gic->irq_state[irq].pending) { + val |= (1 << 22); + break; + } + } + /* PENDSTSET */ + if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending) + val |= (1 << 26); + /* PENDSVSET */ + if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending) + val |= (1 << 28); + /* NMIPENDSET */ + if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending) + val |= (1 << 31); + return val; + case 0xd08: /* Vector Table Offset. */ + return cpu_single_env->v7m.vecbase; + case 0xd0c: /* Application Interrupt/Reset Control. */ + return 0xfa05000; + case 0xd10: /* System Control. */ + /* TODO: Implement SLEEPONEXIT. */ + return 0; + case 0xd14: /* Configuration Control. */ + /* TODO: Implement Configuration Control bits. */ + return 0; + case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ + irq = offset - 0xd14; + val = 0; + val = s->gic->priority1[irq++][0]; + val = s->gic->priority1[irq++][0] << 8; + val = s->gic->priority1[irq++][0] << 16; + val = s->gic->priority1[irq][0] << 24; + return val; + case 0xd24: /* System Handler Status. */ + val = 0; + if (s->gic->irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0); + if (s->gic->irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1); + if (s->gic->irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3); + if (s->gic->irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7); + if (s->gic->irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8); + if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10); + if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11); + if (s->gic->irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12); + if (s->gic->irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13); + if (s->gic->irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14); + if (s->gic->irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15); + if (s->gic->irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16); + if (s->gic->irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17); + if (s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18); + return val; + case 0xd28: /* Configurable Fault Status. */ + /* TODO: Implement Fault Status. */ + cpu_abort(cpu_single_env, + "Not implemented: Configurable Fault Status."); + return 0; + case 0xd2c: /* Hard Fault Status. */ + case 0xd30: /* Debug Fault Status. */ + case 0xd34: /* Mem Manage Address. */ + case 0xd38: /* Bus Fault Address. */ + case 0xd3c: /* Aux Fault Status. */ + /* TODO: Implement fault status registers. */ + goto bad_reg; + case 0xd40: /* PFR0. */ + return 0x00000030; + case 0xd44: /* PRF1. */ + return 0x00000200; + case 0xd48: /* DFR0. */ + return 0x00100000; + case 0xd4c: /* AFR0. */ + return 0x00000000; + case 0xd50: /* MMFR0. */ + return 0x00000030; + case 0xd54: /* MMFR1. */ + return 0x00000000; + case 0xd58: /* MMFR2. */ + return 0x00000000; + case 0xd5c: /* MMFR3. */ + return 0x00000000; + case 0xd60: /* ISAR0. */ + return 0x01141110; + case 0xd64: /* ISAR1. */ + return 0x02111000; + case 0xd68: /* ISAR2. */ + return 0x21112231; + case 0xd6c: /* ISAR3. */ + return 0x01111110; + case 0xd70: /* ISAR4. */ + return 0x01310102; + /* TODO: Implement debug registers. */ + default: + bad_reg: + cpu_abort(cpu_single_env, "NVIC: Bad read offset 0x%x\n", offset); + } +} + +static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) +{ + nvic_state *s = (nvic_state *)opaque; + uint32_t oldval; + switch (offset) { + case 0x10: /* SysTick Control and Status. */ + oldval = s->systick.control; + s->systick.control &= 0xfffffff8; + s->systick.control |= value & 7; + if ((oldval ^ value) & SYSTICK_ENABLE) { + int64_t now = qemu_get_clock(vm_clock); + if (value & SYSTICK_ENABLE) { + if (s->systick.tick) { + s->systick.tick += now; + qemu_mod_timer(s->systick.timer, s->systick.tick); + } else { + systick_reload(s, 1); + } + } else { + qemu_del_timer(s->systick.timer); + s->systick.tick -= now; + if (s->systick.tick < 0) + s->systick.tick = 0; + } + } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) { + /* This is a hack. Force the timer to be reloaded + when the reference clock is changed. */ + systick_reload(s, 1); + } + break; + case 0x14: /* SysTick Reload Value. */ + s->systick.reload = value; + break; + case 0x18: /* SysTick Current Value. Writes reload the timer. */ + systick_reload(s, 1); + s->systick.control &= ~SYSTICK_COUNTFLAG; + break; + case 0xd04: /* Interrupt Control State. */ + if (value & (1 << 31)) { + armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI); + } + if (value & (1 << 28)) { + armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV); + } else if (value & (1 << 27)) { + s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending = 0; + gic_update(s->gic); + } + if (value & (1 << 26)) { + armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); + } else if (value & (1 << 25)) { + s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending = 0; + gic_update(s->gic); + } + break; + case 0xd08: /* Vector Table Offset. */ + cpu_single_env->v7m.vecbase = value & 0xffffff80; + break; + case 0xd0c: /* Application Interrupt/Reset Control. */ + if ((value >> 16) == 0x05fa) { + if (value & 2) { + cpu_abort(cpu_single_env, "VECTCLRACTIVE not implemented"); + } + if (value & 5) { + cpu_abort(cpu_single_env, "System reset"); + } + } + break; + case 0xd10: /* System Control. */ + case 0xd14: /* Configuration Control. */ + /* TODO: Implement control registers. */ + goto bad_reg; + case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ + { + int irq; + irq = offset - 0xd14; + s->gic->priority1[irq++][0] = value & 0xff; + s->gic->priority1[irq++][0] = (value >> 8) & 0xff; + s->gic->priority1[irq++][0] = (value >> 16) & 0xff; + s->gic->priority1[irq][0] = (value >> 24) & 0xff; + gic_update(s->gic); + } + break; + case 0xd24: /* System Handler Control. */ + /* TODO: Real hardware allows you to set/clear the active bits + under some circumstances. We don't implement this. */ + s->gic->irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0; + s->gic->irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0; + s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0; + break; + case 0xd28: /* Configurable Fault Status. */ + case 0xd2c: /* Hard Fault Status. */ + case 0xd30: /* Debug Fault Status. */ + case 0xd34: /* Mem Manage Address. */ + case 0xd38: /* Bus Fault Address. */ + case 0xd3c: /* Aux Fault Status. */ + goto bad_reg; + default: + bad_reg: + cpu_abort(cpu_single_env, "NVIC: Bad write offset 0x%x\n", offset); + } +} + +qemu_irq *armv7m_nvic_init(CPUState *env) +{ + nvic_state *s; + qemu_irq *parent; + + parent = arm_pic_init_cpu(env); + s = (nvic_state *)qemu_mallocz(sizeof(nvic_state)); + s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]); + s->gic->nvic = s; + s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s); + if (env->v7m.nvic) + cpu_abort(env, "CPU can only have one NVIC\n"); + env->v7m.nvic = s; + return s->gic->in; +} diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 75315a8b9..31e7d7d0e 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -497,8 +497,8 @@ static void integratorcp_init(int ram_size, int vga_ram_size, icp_pic_init(0xca000000, pic[26], NULL); icp_pit_init(0x13000000, pic, 5); pl031_init(0x15000000, pic[8]); - pl011_init(0x16000000, pic[1], serial_hds[0]); - pl011_init(0x17000000, pic[2], serial_hds[1]); + pl011_init(0x16000000, pic[1], serial_hds[0], PL011_ARM); + pl011_init(0x17000000, pic[2], serial_hds[1], PL011_ARM); icp_control_init(0xcb000000); pl050_init(0x18000000, pic[3], 0); pl050_init(0x19000000, pic[4], 1); diff --git a/hw/mpcore.c b/hw/mpcore.c new file mode 100644 index 000000000..cc33208e0 --- /dev/null +++ b/hw/mpcore.c @@ -0,0 +1,323 @@ +/* + * ARM MPCore internal peripheral emulation. + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +#define MPCORE_PRIV_BASE 0x10100000 +#define NCPU 4 +/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines + (+ 32 internal). However my test chip only exposes/reports 32. + More importantly Linux falls over if more than 32 are present! */ +#define GIC_NIRQ 64 + +static inline int +gic_get_current_cpu(void) +{ + return cpu_single_env->cpu_index; +} + +#include "arm_gic.c" + +/* MPCore private memory region. */ + +typedef struct { + uint32_t count; + uint32_t load; + uint32_t control; + uint32_t status; + uint32_t old_status; + int64_t tick; + QEMUTimer *timer; + struct mpcore_priv_state *mpcore; + int id; /* Encodes both timer/watchdog and CPU. */ +} mpcore_timer_state; + +typedef struct mpcore_priv_state { + gic_state *gic; + uint32_t scu_control; + mpcore_timer_state timer[8]; +} mpcore_priv_state; + +/* Per-CPU Timers. */ + +static inline void mpcore_timer_update_irq(mpcore_timer_state *s) +{ + if (s->status & ~s->old_status) { + gic_set_pending_private(s->mpcore->gic, s->id >> 1, 29 + (s->id & 1)); + } + s->old_status = s->status; +} + +/* Return conversion factor from mpcore timer ticks to qemu timer ticks. */ +static inline uint32_t mpcore_timer_scale(mpcore_timer_state *s) +{ + return (((s->control >> 8) & 0xff) + 1) * 10; +} + +static void mpcore_timer_reload(mpcore_timer_state *s, int restart) +{ + if (s->count == 0) + return; + if (restart) + s->tick = qemu_get_clock(vm_clock); + s->tick += (int64_t)s->count * mpcore_timer_scale(s); + qemu_mod_timer(s->timer, s->tick); +} + +static void mpcore_timer_tick(void *opaque) +{ + mpcore_timer_state *s = (mpcore_timer_state *)opaque; + s->status = 1; + if (s->control & 2) { + s->count = s->load; + mpcore_timer_reload(s, 0); + } else { + s->count = 0; + } + mpcore_timer_update_irq(s); +} + +static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset) +{ + int64_t val; + switch (offset) { + case 0: /* Load */ + return s->load; + /* Fall through. */ + case 4: /* Counter. */ + if (((s->control & 1) == 0) || (s->count == 0)) + return 0; + /* Slow and ugly, but hopefully won't happen too often. */ + val = s->tick - qemu_get_clock(vm_clock); + val /= mpcore_timer_scale(s); + if (val < 0) + val = 0; + return val; + case 8: /* Control. */ + return s->control; + case 12: /* Interrupt status. */ + return s->status; + } +} + +static void mpcore_timer_write(mpcore_timer_state *s, int offset, + uint32_t value) +{ + int64_t old; + switch (offset) { + case 0: /* Load */ + s->load = value; + /* Fall through. */ + case 4: /* Counter. */ + if ((s->control & 1) && s->count) { + /* Cancel the previous timer. */ + qemu_del_timer(s->timer); + } + s->count = value; + if (s->control & 1) { + mpcore_timer_reload(s, 1); + } + break; + case 8: /* Control. */ + old = s->control; + s->control = value; + if (((old & 1) == 0) && (value & 1)) { + if (s->count == 0 && (s->control & 2)) + s->count = s->load; + mpcore_timer_reload(s, 1); + } + break; + case 12: /* Interrupt status. */ + s->status &= ~value; + mpcore_timer_update_irq(s); + break; + } +} + +static void mpcore_timer_init(mpcore_priv_state *mpcore, + mpcore_timer_state *s, int id) +{ + s->id = id; + s->mpcore = mpcore; + s->timer = qemu_new_timer(vm_clock, mpcore_timer_tick, s); +} + + +/* Per-CPU private memory mapped IO. */ + +static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) +{ + mpcore_priv_state *s = (mpcore_priv_state *)opaque; + int id; + offset &= 0xfff; + if (offset < 0x100) { + /* SCU */ + switch (offset) { + case 0x00: /* Control. */ + return s->scu_control; + case 0x04: /* Configuration. */ + return 0xf3; + case 0x08: /* CPU status. */ + return 0; + case 0x0c: /* Invalidate all. */ + return 0; + default: + goto bad_reg; + } + } else if (offset < 0x600) { + /* Interrupt controller. */ + if (offset < 0x200) { + id = gic_get_current_cpu(); + } else { + id = (offset - 0x200) >> 8; + } + return gic_cpu_read(s->gic, id, offset & 0xff); + } else if (offset < 0xb00) { + /* Timers. */ + if (offset < 0x700) { + id = gic_get_current_cpu(); + } else { + id = (offset - 0x700) >> 8; + } + id <<= 1; + if (offset & 0x20) + id++; + return mpcore_timer_read(&s->timer[id], offset & 0xf); + } +bad_reg: + cpu_abort(cpu_single_env, "mpcore_priv_read: Bad offset %x\n", + (int)offset); + return 0; +} + +static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + mpcore_priv_state *s = (mpcore_priv_state *)opaque; + int id; + offset &= 0xfff; + if (offset < 0x100) { + /* SCU */ + switch (offset) { + case 0: /* Control register. */ + s->scu_control = value & 1; + break; + case 0x0c: /* Invalidate all. */ + /* This is a no-op as cache is not emulated. */ + break; + default: + goto bad_reg; + } + } else if (offset < 0x600) { + /* Interrupt controller. */ + if (offset < 0x200) { + id = gic_get_current_cpu(); + } else { + id = (offset - 0x200) >> 8; + } + gic_cpu_write(s->gic, id, offset & 0xff, value); + } else if (offset < 0xb00) { + /* Timers. */ + if (offset < 0x700) { + id = gic_get_current_cpu(); + } else { + id = (offset - 0x700) >> 8; + } + id <<= 1; + if (offset & 0x20) + id++; + mpcore_timer_write(&s->timer[id], offset & 0xf, value); + return; + } + return; +bad_reg: + cpu_abort(cpu_single_env, "mpcore_priv_read: Bad offset %x\n", + (int)offset); +} + +static CPUReadMemoryFunc *mpcore_priv_readfn[] = { + mpcore_priv_read, + mpcore_priv_read, + mpcore_priv_read +}; + +static CPUWriteMemoryFunc *mpcore_priv_writefn[] = { + mpcore_priv_write, + mpcore_priv_write, + mpcore_priv_write +}; + + +static qemu_irq *mpcore_priv_init(uint32_t base, qemu_irq *pic_irq) +{ + mpcore_priv_state *s; + int iomemtype; + int i; + + s = (mpcore_priv_state *)qemu_mallocz(sizeof(mpcore_priv_state)); + if (!s) + return NULL; + s->gic = gic_init(base, pic_irq); + if (!s->gic) + return NULL; + iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn, + mpcore_priv_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + for (i = 0; i < 8; i++) { + mpcore_timer_init(s, &s->timer[i], i); + } + return s->gic->in; +} + +/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ + controllers. The output of these, plus some of the raw input lines + are fed into a single SMP-aware interrupt controller on the CPU. */ +typedef struct { + qemu_irq *cpuic; + qemu_irq *rvic[4]; +} mpcore_rirq_state; + +/* Map baseboard IRQs onto CPU IRQ lines. */ +static const int mpcore_irq_map[32] = { + -1, -1, -1, -1, 1, 2, -1, -1, + -1, -1, 6, -1, 4, 5, -1, -1, + -1, 14, 15, 0, 7, 8, -1, -1, + -1, -1, -1, -1, 9, 3, -1, -1, +}; + +static void mpcore_rirq_set_irq(void *opaque, int irq, int level) +{ + mpcore_rirq_state *s = (mpcore_rirq_state *)opaque; + int i; + + for (i = 0; i < 4; i++) { + qemu_set_irq(s->rvic[i][irq], level); + } + if (irq < 32) { + irq = mpcore_irq_map[irq]; + if (irq >= 0) { + qemu_set_irq(s->cpuic[irq], level); + } + } +} + +qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq) +{ + mpcore_rirq_state *s; + int n; + + /* ??? IRQ routing is hardcoded to "normal" mode. */ + s = qemu_mallocz(sizeof(mpcore_rirq_state)); + s->cpuic = mpcore_priv_init(MPCORE_PRIV_BASE, cpu_irq); + for (n = 0; n < 4; n++) { + s->rvic[n] = realview_gic_init(0x10040000 + n * 0x10000, + s->cpuic[10 + n]); + } + return qemu_allocate_irqs(mpcore_rirq_set_irq, s, 64); +} diff --git a/hw/pl011.c b/hw/pl011.c index df3349188..903755414 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -28,6 +28,7 @@ typedef struct { int read_trigger; CharDriverState *chr; qemu_irq irq; + enum pl011_type type; } pl011_state; #define PL011_INT_TX 0x20 @@ -38,8 +39,10 @@ typedef struct { #define PL011_FLAG_TXFF 0x20 #define PL011_FLAG_RXFE 0x10 -static const unsigned char pl011_id[] = -{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; +static const unsigned char pl011_id[2][8] = { + { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }, /* PL011_ARM */ + { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }, /* PL011_LUMINARY */ +}; static void pl011_update(pl011_state *s) { @@ -56,7 +59,7 @@ static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) offset -= s->base; if (offset >= 0xfe0 && offset < 0x1000) { - return pl011_id[(offset - 0xfe0) >> 2]; + return pl011_id[s->type][(offset - 0xfe0) >> 2]; } switch (offset >> 2) { case 0: /* UARTDR */ @@ -137,6 +140,9 @@ static void pl011_write(void *opaque, target_phys_addr_t offset, case 1: /* UARTCR */ s->cr = value; break; + case 6: /* UARTFR */ + /* Writes to Flag register are ignored. */ + break; case 8: /* UARTUARTILPR */ s->ilpr = value; break; @@ -224,7 +230,7 @@ static CPUWriteMemoryFunc *pl011_writefn[] = { }; void pl011_init(uint32_t base, qemu_irq irq, - CharDriverState *chr) + CharDriverState *chr, enum pl011_type type) { int iomemtype; pl011_state *s; @@ -235,6 +241,7 @@ void pl011_init(uint32_t base, qemu_irq irq, cpu_register_physical_memory(base, 0x00001000, iomemtype); s->base = base; s->irq = irq; + s->type = type; s->chr = chr; s->read_trigger = 1; s->ifl = 0x12; diff --git a/hw/pl022.c b/hw/pl022.c new file mode 100644 index 000000000..d7c735b7c --- /dev/null +++ b/hw/pl022.c @@ -0,0 +1,264 @@ +/* + * Arm PrimeCell PL022 Synchronous Serial Port + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +//#define DEBUG_PL022 1 + +#ifdef DEBUG_PL022 +#define DPRINTF(fmt, args...) \ +do { printf("pl022: " fmt , ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "pl022: error: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "pl022: error: " fmt , ##args);} while (0) +#endif + +#define PL022_CR1_LBM 0x01 +#define PL022_CR1_SSE 0x02 +#define PL022_CR1_MS 0x04 +#define PL022_CR1_SDO 0x08 + +#define PL022_SR_TFE 0x01 +#define PL022_SR_TNF 0x02 +#define PL022_SR_RNE 0x04 +#define PL022_SR_RFF 0x08 +#define PL022_SR_BSY 0x10 + +#define PL022_INT_ROR 0x01 +#define PL022_INT_RT 0x04 +#define PL022_INT_RX 0x04 +#define PL022_INT_TX 0x08 + +typedef struct { + uint32_t base; + uint32_t cr0; + uint32_t cr1; + uint32_t bitmask; + uint32_t sr; + uint32_t cpsr; + uint32_t is; + uint32_t im; + /* The FIFO head points to the next empty entry. */ + int tx_fifo_head; + int rx_fifo_head; + int tx_fifo_len; + int rx_fifo_len; + uint16_t tx_fifo[8]; + uint16_t rx_fifo[8]; + qemu_irq irq; + int (*xfer_cb)(void *, int); + void *opaque; +} pl022_state; + +static const unsigned char pl022_id[8] = + { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; + +static void pl022_update(pl022_state *s) +{ + s->sr = 0; + if (s->tx_fifo_len == 0) + s->sr |= PL022_SR_TFE; + if (s->tx_fifo_len != 8) + s->sr |= PL022_SR_TNF; + if (s->rx_fifo_len != 0) + s->sr |= PL022_SR_RNE; + if (s->rx_fifo_len == 8) + s->sr |= PL022_SR_RFF; + if (s->tx_fifo_len) + s->sr |= PL022_SR_BSY; + s->is = 0; + if (s->rx_fifo_len >= 4) + s->is |= PL022_INT_RX; + if (s->tx_fifo_len <= 4) + s->is |= PL022_INT_TX; + + qemu_set_irq(s->irq, (s->is & s->im) != 0); +} + +static void pl022_xfer(pl022_state *s) +{ + int i; + int o; + int val; + + if ((s->cr1 & PL022_CR1_SSE) == 0) { + pl022_update(s); + DPRINTF("Disabled\n"); + return; + } + + DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len); + i = (s->tx_fifo_head - s->tx_fifo_len) & 7; + o = s->rx_fifo_head; + /* ??? We do not emulate the line speed. + This may break some applications. The are two problematic cases: + (a) A driver feeds data into the TX FIFO until it is full, + and only then drains the RX FIFO. On real hardware the CPU can + feed data fast enough that the RX fifo never gets chance to overflow. + (b) A driver transmits data, deliberately allowing the RX FIFO to + overflow because it ignores the RX data anyway. + + We choose to support (a) by stalling the transmit engine if it would + cause the RX FIFO to overflow. In practice much transmit-only code + falls into (a) because it flushes the RX FIFO to determine when + the transfer has completed. */ + while (s->tx_fifo_len && s->rx_fifo_len < 8) { + DPRINTF("xfer\n"); + val = s->tx_fifo[i]; + if (s->cr1 & PL022_CR1_LBM) { + /* Loopback mode. */ + } else if (s->xfer_cb) { + val = s->xfer_cb(s->opaque, val); + } else { + val = 0; + } + s->rx_fifo[o] = val & s->bitmask; + i = (i + 1) & 7; + o = (o + 1) & 7; + s->tx_fifo_len--; + s->rx_fifo_len++; + } + s->rx_fifo_head = o; + pl022_update(s); +} + +static uint32_t pl022_read(void *opaque, target_phys_addr_t offset) +{ + pl022_state *s = (pl022_state *)opaque; + int val; + + offset -= s->base; + if (offset >= 0xfe0 && offset < 0x1000) { + return pl022_id[(offset - 0xfe0) >> 2]; + } + switch (offset) { + case 0x00: /* CR0 */ + return s->cr0; + case 0x04: /* CR1 */ + return s->cr1; + case 0x08: /* DR */ + if (s->rx_fifo_len) { + val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7]; + DPRINTF("RX %02x\n", val); + s->rx_fifo_len--; + pl022_xfer(s); + } else { + val = 0; + } + return val; + case 0x0c: /* SR */ + return s->sr; + case 0x10: /* CPSR */ + return s->cpsr; + case 0x14: /* IMSC */ + return s->im; + case 0x18: /* RIS */ + return s->is; + case 0x1c: /* MIS */ + return s->im & s->is; + case 0x20: /* DMACR */ + /* Not implemented. */ + return 0; + default: + cpu_abort (cpu_single_env, "pl022_read: Bad offset %x\n", + (int)offset); + return 0; + } +} + +static void pl022_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + pl022_state *s = (pl022_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* CR0 */ + s->cr0 = value; + /* Clock rate and format are ignored. */ + s->bitmask = (1 << ((value & 15) + 1)) - 1; + break; + case 0x04: /* CR1 */ + s->cr1 = value; + if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE)) + == (PL022_CR1_MS | PL022_CR1_SSE)) { + BADF("SPI slave mode not implemented\n"); + } + pl022_xfer(s); + break; + case 0x08: /* DR */ + if (s->tx_fifo_len < 8) { + DPRINTF("TX %02x\n", value); + s->tx_fifo[s->tx_fifo_head] = value & s->bitmask; + s->tx_fifo_head = (s->tx_fifo_head + 1) & 7; + s->tx_fifo_len++; + pl022_xfer(s); + } + break; + case 0x10: /* CPSR */ + /* Prescaler. Ignored. */ + s->cpsr = value & 0xff; + break; + case 0x14: /* IMSC */ + s->im = value; + pl022_update(s); + break; + case 0x20: /* DMACR */ + if (value) + cpu_abort (cpu_single_env, "pl022: DMA not implemented\n"); + break; + default: + cpu_abort (cpu_single_env, "pl022_write: Bad offset %x\n", + (int)offset); + } +} + +static void pl022_reset(pl022_state *s) +{ + s->rx_fifo_len = 0; + s->tx_fifo_len = 0; + s->im = 0; + s->is = PL022_INT_TX; + s->sr = PL022_SR_TFE | PL022_SR_TNF; +} + +static CPUReadMemoryFunc *pl022_readfn[] = { + pl022_read, + pl022_read, + pl022_read +}; + +static CPUWriteMemoryFunc *pl022_writefn[] = { + pl022_write, + pl022_write, + pl022_write +}; + +void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int), + void * opaque) +{ + int iomemtype; + pl022_state *s; + + s = (pl022_state *)qemu_mallocz(sizeof(pl022_state)); + iomemtype = cpu_register_io_memory(0, pl022_readfn, + pl022_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + s->base = base; + s->irq = irq; + s->xfer_cb = xfer_cb; + s->opaque = opaque; + pl022_reset(s); + /* ??? Save/restore. */ +} + + diff --git a/hw/pl061.c b/hw/pl061.c new file mode 100644 index 000000000..fa5004a96 --- /dev/null +++ b/hw/pl061.c @@ -0,0 +1,256 @@ +/* + * Arm PrimeCell PL061 General Purpose IO with additional + * Luminary Micro Stellaris bits. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" + +//#define DEBUG_PL061 1 + +#ifdef DEBUG_PL061 +#define DPRINTF(fmt, args...) \ +do { printf("pl061: " fmt , ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "pl061: error: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "pl061: error: " fmt , ##args);} while (0) +#endif + +static const uint8_t pl061_id[12] = + { 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; + +typedef struct { + uint32_t base; + int locked; + uint8_t data; + uint8_t old_data; + uint8_t dir; + uint8_t isense; + uint8_t ibe; + uint8_t iev; + uint8_t im; + uint8_t istate; + uint8_t afsel; + uint8_t dr2r; + uint8_t dr4r; + uint8_t dr8r; + uint8_t odr; + uint8_t pur; + uint8_t pdr; + uint8_t slr; + uint8_t den; + uint8_t cr; + qemu_irq irq; + qemu_irq out[8]; +} pl061_state; + +static void pl061_update(pl061_state *s) +{ + uint8_t changed; + uint8_t mask; + int i; + + changed = s->old_data ^ s->data; + if (!changed) + return; + + s->old_data = s->data; + for (i = 0; i < 8; i++) { + mask = 1 << i; + if ((changed & mask & s->dir) && s->out) { + DPRINTF("Set output %d = %d\n", i, (s->data & mask) != 0); + qemu_set_irq(s->out[i], (s->data & mask) != 0); + } + } + + /* FIXME: Implement input interrupts. */ +} + +static uint32_t pl061_read(void *opaque, target_phys_addr_t offset) +{ + pl061_state *s = (pl061_state *)opaque; + + offset -= s->base; + if (offset >= 0xfd0 && offset < 0x1000) { + return pl061_id[(offset - 0xfd0) >> 2]; + } + if (offset < 0x400) { + return s->data & (offset >> 2); + } + switch (offset) { + case 0x400: /* Direction */ + return s->dir; + case 0x404: /* Interrupt sense */ + return s->isense; + case 0x408: /* Interrupt both edges */ + return s->ibe; + case 0x40c: /* Interupt event */ + return s->iev; + case 0x410: /* Interrupt mask */ + return s->im; + case 0x414: /* Raw interrupt status */ + return s->istate; + case 0x418: /* Masked interrupt status */ + return s->istate | s->im; + case 0x420: /* Alternate function select */ + return s->afsel; + case 0x500: /* 2mA drive */ + return s->dr2r; + case 0x504: /* 4mA drive */ + return s->dr4r; + case 0x508: /* 8mA drive */ + return s->dr8r; + case 0x50c: /* Open drain */ + return s->odr; + case 0x510: /* Pull-up */ + return s->pur; + case 0x514: /* Pull-down */ + return s->pdr; + case 0x518: /* Slew rate control */ + return s->slr; + case 0x51c: /* Digital enable */ + return s->den; + case 0x520: /* Lock */ + return s->locked; + case 0x524: /* Commit */ + return s->cr; + default: + cpu_abort (cpu_single_env, "pl061_read: Bad offset %x\n", + (int)offset); + return 0; + } +} + +static void pl061_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + pl061_state *s = (pl061_state *)opaque; + uint8_t mask; + + offset -= s->base; + if (offset < 0x400) { + mask = (offset >> 2) & s->dir; + s->data = (s->data & ~mask) | (value & mask); + pl061_update(s); + return; + } + switch (offset) { + case 0x400: /* Direction */ + s->dir = value; + break; + case 0x404: /* Interrupt sense */ + s->isense = value; + break; + case 0x408: /* Interrupt both edges */ + s->ibe = value; + break; + case 0x40c: /* Interupt event */ + s->iev = value; + break; + case 0x410: /* Interrupt mask */ + s->im = value; + break; + case 0x41c: /* Interrupt clear */ + s->istate &= ~value; + break; + case 0x420: /* Alternate function select */ + mask = s->cr; + s->afsel = (s->afsel & ~mask) | (value & mask); + break; + case 0x500: /* 2mA drive */ + s->dr2r = value; + break; + case 0x504: /* 4mA drive */ + s->dr4r = value; + break; + case 0x508: /* 8mA drive */ + s->dr8r = value; + break; + case 0x50c: /* Open drain */ + s->odr = value; + break; + case 0x510: /* Pull-up */ + s->pur = value; + break; + case 0x514: /* Pull-down */ + s->pdr = value; + break; + case 0x518: /* Slew rate control */ + s->slr = value; + break; + case 0x51c: /* Digital enable */ + s->den = value; + break; + case 0x520: /* Lock */ + s->locked = (value != 0xacce551); + break; + case 0x524: /* Commit */ + if (!s->locked) + s->cr = value; + break; + default: + cpu_abort (cpu_single_env, "pl061_write: Bad offset %x\n", + (int)offset); + } + pl061_update(s); +} + +static void pl061_reset(pl061_state *s) +{ + s->locked = 1; + s->cr = 0xff; +} + +void pl061_set_irq(void * opaque, int irq, int level) +{ + pl061_state *s = (pl061_state *)opaque; + uint8_t mask; + + mask = 1 << irq; + if ((s->dir & mask) == 0) { + s->data &= ~mask; + if (level) + s->data |= mask; + pl061_update(s); + } +} + +static CPUReadMemoryFunc *pl061_readfn[] = { + pl061_read, + pl061_read, + pl061_read +}; + +static CPUWriteMemoryFunc *pl061_writefn[] = { + pl061_write, + pl061_write, + pl061_write +}; + +/* Returns an array of inputs. */ +qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out) +{ + int iomemtype; + pl061_state *s; + + s = (pl061_state *)qemu_mallocz(sizeof(pl061_state)); + iomemtype = cpu_register_io_memory(0, pl061_readfn, + pl061_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + s->base = base; + s->irq = irq; + pl061_reset(s); + if (out) + *out = s->out; + + /* ??? Save/restore. */ + return qemu_allocate_irqs(pl061_set_irq, s, 8); +} + diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index ebaff1320..3c1083902 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -297,7 +297,7 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm, ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; s->env->cp15.c1_sys = 0; s->env->cp15.c1_coproc = 0; - s->env->cp15.c2_base = 0; + s->env->cp15.c2_base0 = 0; s->env->cp15.c3 = 0; s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ @@ -2031,7 +2031,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env); + register_savevm("cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, + s->env); /* SDRAM & Internal Memory Storage */ cpu_register_physical_memory(PXA2XX_SDRAM_BASE, @@ -2145,7 +2146,8 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env); + register_savevm("cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, + s->env); /* SDRAM & Internal Memory Storage */ cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size, diff --git a/hw/realview.c b/hw/realview.c index f97d6e625..e02deeed7 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -25,13 +25,32 @@ static void realview_init(int ram_size, int vga_ram_size, NICInfo *nd; int n; int done_smc = 0; + qemu_irq cpu_irq[4]; + int ncpu; if (!cpu_model) cpu_model = "arm926"; - env = cpu_init(cpu_model); - if (!env) { - fprintf(stderr, "Unable to find CPU definition\n"); - exit(1); + /* FIXME: obey smp_cpus. */ + if (strcmp(cpu_model, "arm11mpcore") == 0) { + ncpu = 4; + } else { + ncpu = 1; + } + + for (n = 0; n < ncpu; n++) { + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + pic = arm_pic_init_cpu(env); + cpu_irq[n] = pic[ARM_PIC_CPU_IRQ]; + if (n > 0) { + /* Set entry point for secondary CPUs. This assumes we're using + the init code from arm_boot.c. Real hardware resets all CPUs + the same. */ + env->regs[15] = 0x80000000; + } } /* ??? RAM shoud repeat to fill physical memory space. */ @@ -39,18 +58,23 @@ static void realview_init(int ram_size, int vga_ram_size, cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); arm_sysctl_init(0x10000000, 0xc1400400); - pic = arm_pic_init_cpu(env); - /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3 - is nIRQ (there are inconsistencies). However Linux 2.6.17 expects - GIC1 to be nIRQ and ignores all the others, so do that for now. */ - pic = arm_gic_init(0x10040000, pic[ARM_PIC_CPU_IRQ]); + + if (ncpu == 1) { + /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3 + is nIRQ (there are inconsistencies). However Linux 2.6.17 expects + GIC1 to be nIRQ and ignores all the others, so do that for now. */ + pic = realview_gic_init(0x10040000, cpu_irq[0]); + } else { + pic = mpcore_irq_init(cpu_irq); + } + pl050_init(0x10006000, pic[20], 0); pl050_init(0x10007000, pic[21], 1); - pl011_init(0x10009000, pic[12], serial_hds[0]); - pl011_init(0x1000a000, pic[13], serial_hds[1]); - pl011_init(0x1000b000, pic[14], serial_hds[2]); - pl011_init(0x1000c000, pic[15], serial_hds[3]); + pl011_init(0x10009000, pic[12], serial_hds[0], PL011_ARM); + pl011_init(0x1000a000, pic[13], serial_hds[1], PL011_ARM); + pl011_init(0x1000b000, pic[14], serial_hds[2], PL011_ARM); + pl011_init(0x1000c000, pic[15], serial_hds[3], PL011_ARM); /* DMA controller is optional, apparently. */ pl080_init(0x10030000, pic[24], 2); @@ -114,10 +138,10 @@ static void realview_init(int ram_size, int vga_ram_size, /* 0x10019000 PCI controller config. */ /* 0x10020000 CLCD. */ /* 0x10030000 DMA Controller. */ - /* 0x10040000 GIC1 (FIQ1). */ - /* 0x10050000 GIC2 (IRQ1). */ - /* 0x10060000 GIC3 (FIQ2). */ - /* 0x10070000 GIC4 (IRQ2). */ + /* 0x10040000 GIC1. */ + /* 0x10050000 GIC2. */ + /* 0x10060000 GIC3. */ + /* 0x10070000 GIC4. */ /* 0x10080000 SMC. */ /* 0x40000000 NOR flash. */ /* 0x44000000 DoC flash. */ @@ -137,8 +161,14 @@ static void realview_init(int ram_size, int vga_ram_size, /* 0x68000000 PCI mem 1. */ /* 0x6c000000 PCI mem 2. */ - arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, + arm_load_kernel(first_cpu, ram_size, kernel_filename, kernel_cmdline, initrd_filename, 0x33b, 0x0); + + /* ??? Hack to map an additional page of ram for the secondary CPU + startup code. I guess this works on real hardware because the + BootROM happens to be in ROM/flash or in memory that isn't clobbered + until after Linux boots the secondary CPUs. */ + cpu_register_physical_memory(0x80000000, 0x1000, IO_MEM_RAM + ram_size); } QEMUMachine realview_machine = { diff --git a/hw/realview_gic.c b/hw/realview_gic.c new file mode 100644 index 000000000..cbc961491 --- /dev/null +++ b/hw/realview_gic.c @@ -0,0 +1,64 @@ +/* + * ARM RealView Emulation Baseboard Interrupt Controller + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "arm_pic.h" + +#define GIC_NIRQ 96 +#define NCPU 1 + +/* Only a single "CPU" interface is present. */ +static inline int +gic_get_current_cpu(void) +{ + return 0; +} + +#include "arm_gic.c" + +static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset) +{ + gic_state *s = (gic_state *)opaque; + offset -= s->base; + return gic_cpu_read(s, gic_get_current_cpu(), offset); +} + +static void realview_gic_cpu_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + gic_state *s = (gic_state *)opaque; + offset -= s->base; + gic_cpu_write(s, gic_get_current_cpu(), offset, value); +} + +static CPUReadMemoryFunc *realview_gic_cpu_readfn[] = { + realview_gic_cpu_read, + realview_gic_cpu_read, + realview_gic_cpu_read +}; + +static CPUWriteMemoryFunc *realview_gic_cpu_writefn[] = { + realview_gic_cpu_write, + realview_gic_cpu_write, + realview_gic_cpu_write +}; + +qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq) +{ + gic_state *s; + int iomemtype; + + s = gic_init(base, &parent_irq); + if (!s) + return NULL; + iomemtype = cpu_register_io_memory(0, realview_gic_cpu_readfn, + realview_gic_cpu_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + return s->in; +} diff --git a/hw/ssd0303.c b/hw/ssd0303.c new file mode 100644 index 000000000..138cfc7fa --- /dev/null +++ b/hw/ssd0303.c @@ -0,0 +1,273 @@ +/* + * SSD0303 OLED controller with OSRAM Pictiva 96x16 display. + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +/* The controller can support a variety of different displays, but we only + implement one. Most of the commends relating to brightness and geometry + setup are ignored. */ +#include "vl.h" + +//#define DEBUG_SSD0303 1 + +#ifdef DEBUG_SSD0303 +#define DPRINTF(fmt, args...) \ +do { printf("ssd0303: " fmt , ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "ssd0303: error: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "ssd0303: error: " fmt , ##args);} while (0) +#endif + +/* Scaling factor for pixels. */ +#define MAGNIFY 4 + +enum ssd0303_mode +{ + SSD0303_IDLE, + SSD0303_DATA, + SSD0303_CMD +}; + +enum ssd0303_cmd { + SSD0303_CMD_NONE, + SSD0303_CMD_SKIP1 +}; + +typedef struct { + i2c_slave i2c; + DisplayState *ds; + int row; + int col; + int start_line; + int mirror; + int flash; + int enabled; + int inverse; + int redraw; + enum ssd0303_mode mode; + enum ssd0303_cmd cmd_state; + uint8_t framebuffer[132*8]; +} ssd0303_state; + +static int ssd0303_recv(i2c_slave *i2c) +{ + BADF("Reads not implemented\n"); + return -1; +} + +static int ssd0303_send(i2c_slave *i2c, uint8_t data) +{ + ssd0303_state *s = (ssd0303_state *)i2c; + enum ssd0303_cmd old_cmd_state; + switch (s->mode) { + case SSD0303_IDLE: + DPRINTF("byte 0x%02x\n", data); + if (data == 0x80) + s->mode = SSD0303_CMD; + else if (data == 0x40) + s->mode = SSD0303_DATA; + else + BADF("Unexpected byte 0x%x\n", data); + break; + case SSD0303_DATA: + DPRINTF("data 0x%02x\n", data); + if (s->col < 132) { + s->framebuffer[s->col + s->row * 132] = data; + s->col++; + s->redraw = 1; + } + break; + case SSD0303_CMD: + old_cmd_state = s->cmd_state; + s->cmd_state = SSD0303_CMD_NONE; + switch (old_cmd_state) { + case SSD0303_CMD_NONE: + DPRINTF("cmd 0x%02x\n", data); + s->mode = SSD0303_IDLE; + switch (data) { + case 0x00 ... 0x0f: /* Set lower colum address. */ + s->col = (s->col & 0xf0) | (data & 0xf); + break; + case 0x10 ... 0x20: /* Set higher column address. */ + s->col = (s->col & 0x0f) | ((data & 0xf) << 4); + break; + case 0x40 ... 0x7f: /* Set start line. */ + s->start_line = 0; + break; + case 0x81: /* Set contrast (Ignored). */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xa0: /* Mirror off. */ + s->mirror = 0; + break; + case 0xa1: /* Mirror off. */ + s->mirror = 1; + break; + case 0xa4: /* Entire display off. */ + s->flash = 0; + break; + case 0xa5: /* Entire display on. */ + s->flash = 1; + break; + case 0xa6: /* Inverse off. */ + s->inverse = 0; + break; + case 0xa7: /* Inverse on. */ + s->inverse = 1; + break; + case 0xa8: /* Set multipled ratio (Ignored). */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xad: /* DC-DC power control. */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xae: /* Display off. */ + s->enabled = 0; + break; + case 0xaf: /* Display on. */ + s->enabled = 1; + break; + case 0xb0 ... 0xbf: /* Set Page address. */ + s->row = data & 7; + break; + case 0xc0 ... 0xc8: /* Set COM output direction (Ignored). */ + break; + case 0xd3: /* Set display offset (Ignored). */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xd5: /* Set display clock (Ignored). */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xd8: /* Set color and power mode (Ignored). */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xd9: /* Set pre-charge period (Ignored). */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xda: /* Set COM pin configuration (Ignored). */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xdb: /* Set VCOM dselect level (Ignored). */ + s->cmd_state = SSD0303_CMD_SKIP1; + break; + case 0xe3: /* no-op. */ + break; + default: + BADF("Unknown command: 0x%x\n", data); + } + break; + case SSD0303_CMD_SKIP1: + DPRINTF("skip 0x%02x\n", data); + break; + } + break; + } + return 0; +} + +static void ssd0303_event(i2c_slave *i2c, enum i2c_event event) +{ + ssd0303_state *s = (ssd0303_state *)i2c; + switch (event) { + case I2C_FINISH: + s->mode = SSD0303_IDLE; + break; + case I2C_START_RECV: + case I2C_START_SEND: + case I2C_NACK: + /* Nothing to do. */ + break; + } +} + +static void ssd0303_update_display(void *opaque) +{ + ssd0303_state *s = (ssd0303_state *)opaque; + uint8_t *dest; + uint8_t *src; + int x; + int y; + int line; + char *colors[2]; + char colortab[MAGNIFY * 8]; + int dest_width; + uint8_t mask; + + if (s->redraw) { + switch (s->ds->depth) { + case 0: + return; + case 15: + dest_width = 2; + break; + case 16: + dest_width = 2; + break; + case 24: + dest_width = 3; + break; + case 32: + dest_width = 4; + break; + default: + BADF("Bad color depth\n"); + return; + } + dest_width *= MAGNIFY; + memset(colortab, 0xff, dest_width); + memset(colortab + dest_width, 0, dest_width); + if (s->flash) { + colors[0] = colortab; + colors[1] = colortab; + } else if (s->inverse) { + colors[0] = colortab; + colors[1] = colortab + dest_width; + } else { + colors[0] = colortab + dest_width; + colors[1] = colortab; + } + dest = s->ds->data; + for (y = 0; y < 16; y++) { + line = (y + s->start_line) & 63; + src = s->framebuffer + 132 * (line >> 3) + 36; + mask = 1 << (line & 7); + for (x = 0; x < 96; x++) { + memcpy(dest, colors[(*src & mask) != 0], dest_width); + dest += dest_width; + src++; + } + for (x = 1; x < MAGNIFY; x++) { + memcpy(dest, dest - dest_width * 96, dest_width * 96); + dest += dest_width * 96; + } + } + } + dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); +} + +static void ssd0303_invalidate_display(void * opaque) +{ + ssd0303_state *s = (ssd0303_state *)opaque; + s->redraw = 1; +} + +void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address) +{ + ssd0303_state *s; + + s = (ssd0303_state *)i2c_slave_init(bus, address, sizeof(ssd0303_state)); + s->ds = ds; + s->i2c.event = ssd0303_event; + s->i2c.recv = ssd0303_recv; + s->i2c.send = ssd0303_send; + graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display, + NULL, s); + dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); +} diff --git a/hw/ssd0323.c b/hw/ssd0323.c new file mode 100644 index 000000000..67361bce2 --- /dev/null +++ b/hw/ssd0323.c @@ -0,0 +1,267 @@ +/* + * SSD0323 OLED controller with OSRAM Pictiva 128x64 display. + * + * Copyright (c) 2006-2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +/* The controller can support a variety of different displays, but we only + implement one. Most of the commends relating to brightness and geometry + setup are ignored. */ +#include "vl.h" + +//#define DEBUG_SSD0323 1 + +#ifdef DEBUG_SSD0323 +#define DPRINTF(fmt, args...) \ +do { printf("ssd0323: " fmt , ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "ssd0323: error: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "ssd0323: error: " fmt , ##args);} while (0) +#endif + +/* Scaling factor for pixels. */ +#define MAGNIFY 4 + +enum ssd0323_mode +{ + SSD0323_CMD, + SSD0323_DATA +}; + +typedef struct { + DisplayState *ds; + + int cmd_len; + int cmd; + int cmd_data[8]; + int row; + int row_start; + int row_end; + int col; + int col_start; + int col_end; + int redraw; + enum ssd0323_mode mode; + uint8_t framebuffer[128 * 80 / 2]; +} ssd0323_state; + +int ssd0323_xfer_ssi(void *opaque, int data) +{ + ssd0323_state *s = (ssd0323_state *)opaque; + switch (s->mode) { + case SSD0323_DATA: + DPRINTF("data 0x%02x\n", data); + s->framebuffer[s->col + s->row * 64] = data; + s->col++; + if (s->col > s->col_end) { + s->row++; + s->col = s->col_start; + } + if (s->row > s->row_end) { + s->row = s->row_start; + } + s->redraw = 1; + break; + case SSD0323_CMD: + DPRINTF("cmd 0x%02x\n", data); + if (s->cmd_len == 0) { + s->cmd = data; + } else { + s->cmd_data[s->cmd_len - 1] = data; + } + s->cmd_len++; + switch (s->cmd) { +#define DATA(x) if (s->cmd_len <= (x)) return 0 + case 0x15: /* Set column. */ + DATA(2); + s->col_start = s->cmd_data[0] % 64; + s->col_end = s->cmd_data[1] % 64; + break; + case 0x75: /* Set row. */ + DATA(2); + s->row_start = s->cmd_data[0] % 80; + s->row_end = s->cmd_data[1] % 80; + break; + case 0x81: /* Set contrast */ + DATA(1); + break; + case 0x84: case 0x85: case 0x86: /* Max current. */ + DATA(0); + break; + case 0xa0: /* Set remapping. */ + /* FIXME: Implement this. */ + DATA(1); + break; + case 0xa1: /* Set display start line. */ + case 0xa2: /* Set display offset. */ + /* FIXME: Implement these. */ + DATA(1); + break; + case 0xa4: /* Normal mode. */ + case 0xa5: /* All on. */ + case 0xa6: /* All off. */ + case 0xa7: /* Inverse. */ + /* FIXME: Implement these. */ + DATA(0); + break; + case 0xa8: /* Set multiplex ratio. */ + case 0xad: /* Set DC-DC converter. */ + DATA(1); + /* Ignored. Don't care. */ + break; + case 0xae: /* Display off. */ + case 0xaf: /* Display on. */ + DATA(0); + /* TODO: Implement power control. */ + break; + case 0xb1: /* Set phase length. */ + case 0xb2: /* Set row period. */ + case 0xb3: /* Set clock rate. */ + case 0xbc: /* Set precharge. */ + case 0xbe: /* Set VCOMH. */ + case 0xbf: /* Set segment low. */ + DATA(1); + /* Ignored. Don't care. */ + break; + case 0xb8: /* Set grey scale table. */ + /* FIXME: Implement this. */ + DATA(8); + break; + case 0xe3: /* NOP. */ + DATA(0); + break; + default: + BADF("Unknown command: 0x%x\n", data); + } + s->cmd_len = 0; + return 0; + } + return 0; +} + +static void ssd0323_update_display(void *opaque) +{ + ssd0323_state *s = (ssd0323_state *)opaque; + uint8_t *dest; + uint8_t *src; + int x; + int y; + int i; + int line; + char *colors[16]; + char colortab[MAGNIFY * 64]; + char *p; + int dest_width; + + if (s->redraw) { + switch (s->ds->depth) { + case 0: + return; + case 15: + dest_width = 2; + break; + case 16: + dest_width = 2; + break; + case 24: + dest_width = 3; + break; + case 32: + dest_width = 4; + break; + default: + BADF("Bad color depth\n"); + return; + } + p = colortab; + for (i = 0; i < 16; i++) { + int n; + colors[i] = p; + switch (s->ds->depth) { + case 15: + n = i * 2 + (i >> 3); + p[0] = n | (n << 5); + p[1] = (n << 2) | (n >> 3); + break; + case 16: + n = i * 2 + (i >> 3); + p[0] = n | (n << 6) | ((n << 1) & 0x20); + p[1] = (n << 3) | (n >> 2); + break; + case 24: + case 32: + n = (i << 4) | i; + p[0] = p[1] = p[2] = n; + break; + default: + BADF("Bad color depth\n"); + return; + } + p += dest_width; + } + dest = s->ds->data; + for (y = 0; y < 64; y++) { + line = y; + src = s->framebuffer + 64 * line; + for (x = 0; x < 64; x++) { + int val; + val = *src >> 4; + for (i = 0; i < MAGNIFY; i++) { + memcpy(dest, colors[val], dest_width); + dest += dest_width; + } + val = *src & 0xf; + for (i = 0; i < MAGNIFY; i++) { + memcpy(dest, colors[val], dest_width); + dest += dest_width; + } + src++; + } + for (i = 1; i < MAGNIFY; i++) { + memcpy(dest, dest - dest_width * MAGNIFY * 128, + dest_width * 128 * MAGNIFY); + dest += dest_width * 128 * MAGNIFY; + } + } + } + dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); +} + +static void ssd0323_invalidate_display(void * opaque) +{ + ssd0323_state *s = (ssd0323_state *)opaque; + s->redraw = 1; +} + +/* Command/data input. */ +static void ssd0323_cd(void *opaque, int n, int level) +{ + ssd0323_state *s = (ssd0323_state *)opaque; + DPRINTF("%s mode\n", level ? "Data" : "Command"); + s->mode = level ? SSD0323_DATA : SSD0323_CMD; +} + +void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p) +{ + ssd0323_state *s; + qemu_irq *cmd; + + s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state)); + s->ds = ds; + graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display, + NULL, s); + dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); + s->col_end = 63; + s->row_end = 79; + + cmd = qemu_allocate_irqs(ssd0323_cd, s, 1); + *cmd_p = *cmd; + + return s; +} diff --git a/hw/stellaris.c b/hw/stellaris.c new file mode 100644 index 000000000..62f2c0344 --- /dev/null +++ b/hw/stellaris.c @@ -0,0 +1,1101 @@ +/* + * Luminary Micro Stellaris preipherals + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "vl.h" +#include "arm_pic.h" + +typedef const struct { + const char *name; + uint32_t did0; + uint32_t did1; + uint32_t dc0; + uint32_t dc1; + uint32_t dc2; + uint32_t dc3; + uint32_t dc4; + enum {OLED_I2C, OLED_SSI} oled; +} stellaris_board_info; + +/* General purpose timer module. */ + +/* Multiplication factor to convert from GPTM timer ticks to qemu timer + ticks. */ +static int stellaris_clock_scale; + +typedef struct gptm_state { + uint32_t config; + uint32_t mode[2]; + uint32_t control; + uint32_t state; + uint32_t mask; + uint32_t load[2]; + uint32_t match[2]; + uint32_t prescale[2]; + uint32_t match_prescale[2]; + uint32_t rtc; + int64_t tick[2]; + struct gptm_state *opaque[2]; + uint32_t base; + QEMUTimer *timer[2]; + /* The timers have an alternate output used to trigger the ADC. */ + qemu_irq trigger; + qemu_irq irq; +} gptm_state; + +static void gptm_update_irq(gptm_state *s) +{ + int level; + level = (s->state & s->mask) != 0; + qemu_set_irq(s->irq, level); +} + +static void gptm_stop(gptm_state *s, int n) +{ + qemu_del_timer(s->timer[n]); +} + +static void gptm_reload(gptm_state *s, int n, int reset) +{ + int64_t tick; + if (reset) + tick = qemu_get_clock(vm_clock); + else + tick = s->tick[n]; + + if (s->config == 0) { + /* 32-bit CountDown. */ + uint32_t count; + count = s->load[0] | (s->load[1] << 16); + tick += (int64_t)count * stellaris_clock_scale; + } else if (s->config == 1) { + /* 32-bit RTC. 1Hz tick. */ + tick += ticks_per_sec; + } else if (s->mode[n] == 0xa) { + /* PWM mode. Not implemented. */ + } else { + cpu_abort(cpu_single_env, "TODO: 16-bit timer mode 0x%x\n", + s->mode[n]); + } + s->tick[n] = tick; + qemu_mod_timer(s->timer[n], tick); +} + +static void gptm_tick(void *opaque) +{ + gptm_state **p = (gptm_state **)opaque; + gptm_state *s; + int n; + + s = *p; + n = p - s->opaque; + if (s->config == 0) { + s->state |= 1; + if ((s->control & 0x20)) { + /* Output trigger. */ + qemu_irq_raise(s->trigger); + qemu_irq_lower(s->trigger); + } + if (s->mode[0] & 1) { + /* One-shot. */ + s->control &= ~1; + } else { + /* Periodic. */ + gptm_reload(s, 0, 0); + } + } else if (s->config == 1) { + /* RTC. */ + uint32_t match; + s->rtc++; + match = s->match[0] | (s->match[1] << 16); + if (s->rtc > match) + s->rtc = 0; + if (s->rtc == 0) { + s->state |= 8; + } + gptm_reload(s, 0, 0); + } else if (s->mode[n] == 0xa) { + /* PWM mode. Not implemented. */ + } else { + cpu_abort(cpu_single_env, "TODO: 16-bit timer mode 0x%x\n", + s->mode[n]); + } + gptm_update_irq(s); +} + +static uint32_t gptm_read(void *opaque, target_phys_addr_t offset) +{ + gptm_state *s = (gptm_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* CFG */ + return s->config; + case 0x04: /* TAMR */ + return s->mode[0]; + case 0x08: /* TBMR */ + return s->mode[1]; + case 0x0c: /* CTL */ + return s->control; + case 0x18: /* IMR */ + return s->mask; + case 0x1c: /* RIS */ + return s->state; + case 0x20: /* MIS */ + return s->state & s->mask; + case 0x24: /* CR */ + return 0; + case 0x28: /* TAILR */ + return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0); + case 0x2c: /* TBILR */ + return s->load[1]; + case 0x30: /* TAMARCHR */ + return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0); + case 0x34: /* TBMATCHR */ + return s->match[1]; + case 0x38: /* TAPR */ + return s->prescale[0]; + case 0x3c: /* TBPR */ + return s->prescale[1]; + case 0x40: /* TAPMR */ + return s->match_prescale[0]; + case 0x44: /* TBPMR */ + return s->match_prescale[1]; + case 0x48: /* TAR */ + if (s->control == 1) + return s->rtc; + case 0x4c: /* TBR */ + cpu_abort(cpu_single_env, "TODO: Timer value read\n"); + default: + cpu_abort(cpu_single_env, "gptm_read: Bad offset 0x%x\n", (int)offset); + return 0; + } +} + +static void gptm_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + gptm_state *s = (gptm_state *)opaque; + uint32_t oldval; + + offset -= s->base; + /* The timers should be disabled before changing the configuration. + We take advantage of this and defer everything until the timer + is enabled. */ + switch (offset) { + case 0x00: /* CFG */ + s->config = value; + break; + case 0x04: /* TAMR */ + s->mode[0] = value; + break; + case 0x08: /* TBMR */ + s->mode[1] = value; + break; + case 0x0c: /* CTL */ + oldval = s->control; + s->control = value; + /* TODO: Implement pause. */ + if ((oldval ^ value) & 1) { + if (value & 1) { + gptm_reload(s, 0, 1); + } else { + gptm_stop(s, 0); + } + } + if (((oldval ^ value) & 0x100) && s->config >= 4) { + if (value & 0x100) { + gptm_reload(s, 1, 1); + } else { + gptm_stop(s, 1); + } + } + break; + case 0x18: /* IMR */ + s->mask = value & 0x77; + gptm_update_irq(s); + break; + case 0x24: /* CR */ + s->state &= ~value; + break; + case 0x28: /* TAILR */ + s->load[0] = value & 0xffff; + if (s->config < 4) { + s->load[1] = value >> 16; + } + break; + case 0x2c: /* TBILR */ + s->load[1] = value & 0xffff; + break; + case 0x30: /* TAMARCHR */ + s->match[0] = value & 0xffff; + if (s->config < 4) { + s->match[1] = value >> 16; + } + break; + case 0x34: /* TBMATCHR */ + s->match[1] = value >> 16; + break; + case 0x38: /* TAPR */ + s->prescale[0] = value; + break; + case 0x3c: /* TBPR */ + s->prescale[1] = value; + break; + case 0x40: /* TAPMR */ + s->match_prescale[0] = value; + break; + case 0x44: /* TBPMR */ + s->match_prescale[0] = value; + break; + default: + cpu_abort(cpu_single_env, "gptm_write: Bad offset 0x%x\n", (int)offset); + } + gptm_update_irq(s); +} + +static CPUReadMemoryFunc *gptm_readfn[] = { + gptm_read, + gptm_read, + gptm_read +}; + +static CPUWriteMemoryFunc *gptm_writefn[] = { + gptm_write, + gptm_write, + gptm_write +}; + +static void stellaris_gptm_init(uint32_t base, qemu_irq irq, qemu_irq trigger) +{ + int iomemtype; + gptm_state *s; + + s = (gptm_state *)qemu_mallocz(sizeof(gptm_state)); + s->base = base; + s->irq = irq; + s->trigger = trigger; + s->opaque[0] = s->opaque[1] = s; + + iomemtype = cpu_register_io_memory(0, gptm_readfn, + gptm_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]); + s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]); + /* ??? Save/restore. */ +} + + +/* System controller. */ + +typedef struct { + uint32_t base; + uint32_t pborctl; + uint32_t ldopctl; + uint32_t int_status; + uint32_t int_mask; + uint32_t resc; + uint32_t rcc; + uint32_t rcgc[3]; + uint32_t scgc[3]; + uint32_t dcgc[3]; + uint32_t clkvclr; + uint32_t ldoarst; + qemu_irq irq; + stellaris_board_info *board; +} ssys_state; + +static void ssys_update(ssys_state *s) +{ + qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0); +} + +static uint32_t pllcfg_sandstorm[16] = { + 0x31c0, /* 1 Mhz */ + 0x1ae0, /* 1.8432 Mhz */ + 0x18c0, /* 2 Mhz */ + 0xd573, /* 2.4576 Mhz */ + 0x37a6, /* 3.57954 Mhz */ + 0x1ae2, /* 3.6864 Mhz */ + 0x0c40, /* 4 Mhz */ + 0x98bc, /* 4.906 Mhz */ + 0x935b, /* 4.9152 Mhz */ + 0x09c0, /* 5 Mhz */ + 0x4dee, /* 5.12 Mhz */ + 0x0c41, /* 6 Mhz */ + 0x75db, /* 6.144 Mhz */ + 0x1ae6, /* 7.3728 Mhz */ + 0x0600, /* 8 Mhz */ + 0x585b /* 8.192 Mhz */ +}; + +static uint32_t pllcfg_fury[16] = { + 0x3200, /* 1 Mhz */ + 0x1b20, /* 1.8432 Mhz */ + 0x1900, /* 2 Mhz */ + 0xf42b, /* 2.4576 Mhz */ + 0x37e3, /* 3.57954 Mhz */ + 0x1b21, /* 3.6864 Mhz */ + 0x0c80, /* 4 Mhz */ + 0x98ee, /* 4.906 Mhz */ + 0xd5b4, /* 4.9152 Mhz */ + 0x0a00, /* 5 Mhz */ + 0x4e27, /* 5.12 Mhz */ + 0x1902, /* 6 Mhz */ + 0xec1c, /* 6.144 Mhz */ + 0x1b23, /* 7.3728 Mhz */ + 0x0640, /* 8 Mhz */ + 0xb11c /* 8.192 Mhz */ +}; + +static uint32_t ssys_read(void *opaque, target_phys_addr_t offset) +{ + ssys_state *s = (ssys_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x000: /* DID0 */ + return s->board->did0; + case 0x004: /* DID1 */ + return s->board->did1; + case 0x008: /* DC0 */ + return s->board->dc0; + case 0x010: /* DC1 */ + return s->board->dc1; + case 0x014: /* DC2 */ + return s->board->dc2; + case 0x018: /* DC3 */ + return s->board->dc3; + case 0x01c: /* DC4 */ + return s->board->dc4; + case 0x030: /* PBORCTL */ + return s->pborctl; + case 0x034: /* LDOPCTL */ + return s->ldopctl; + case 0x040: /* SRCR0 */ + return 0; + case 0x044: /* SRCR1 */ + return 0; + case 0x048: /* SRCR2 */ + return 0; + case 0x050: /* RIS */ + return s->int_status; + case 0x054: /* IMC */ + return s->int_mask; + case 0x058: /* MISC */ + return s->int_status & s->int_mask; + case 0x05c: /* RESC */ + return s->resc; + case 0x060: /* RCC */ + return s->rcc; + case 0x064: /* PLLCFG */ + { + int xtal; + xtal = (s->rcc >> 6) & 0xf; + if (s->board->did0 & (1 << 16)) { + return pllcfg_fury[xtal]; + } else { + return pllcfg_sandstorm[xtal]; + } + } + case 0x100: /* RCGC0 */ + return s->rcgc[0]; + case 0x104: /* RCGC1 */ + return s->rcgc[1]; + case 0x108: /* RCGC2 */ + return s->rcgc[2]; + case 0x110: /* SCGC0 */ + return s->scgc[0]; + case 0x114: /* SCGC1 */ + return s->scgc[1]; + case 0x118: /* SCGC2 */ + return s->scgc[2]; + case 0x120: /* DCGC0 */ + return s->dcgc[0]; + case 0x124: /* DCGC1 */ + return s->dcgc[1]; + case 0x128: /* DCGC2 */ + return s->dcgc[2]; + case 0x150: /* CLKVCLR */ + return s->clkvclr; + case 0x160: /* LDOARST */ + return s->ldoarst; + default: + cpu_abort(cpu_single_env, "gptm_read: Bad offset 0x%x\n", (int)offset); + return 0; + } +} + +static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + ssys_state *s = (ssys_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x030: /* PBORCTL */ + s->pborctl = value & 0xffff; + break; + case 0x034: /* LDOPCTL */ + s->ldopctl = value & 0x1f; + break; + case 0x040: /* SRCR0 */ + case 0x044: /* SRCR1 */ + case 0x048: /* SRCR2 */ + fprintf(stderr, "Peripheral reset not implemented\n"); + break; + case 0x054: /* IMC */ + s->int_mask = value & 0x7f; + break; + case 0x058: /* MISC */ + s->int_status &= ~value; + break; + case 0x05c: /* RESC */ + s->resc = value & 0x3f; + break; + case 0x060: /* RCC */ + if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { + /* PLL enable. */ + s->int_status |= (1 << 6); + } + s->rcc = value; + stellaris_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); + break; + case 0x100: /* RCGC0 */ + s->rcgc[0] = value; + break; + case 0x104: /* RCGC1 */ + s->rcgc[1] = value; + break; + case 0x108: /* RCGC2 */ + s->rcgc[2] = value; + break; + case 0x110: /* SCGC0 */ + s->scgc[0] = value; + break; + case 0x114: /* SCGC1 */ + s->scgc[1] = value; + break; + case 0x118: /* SCGC2 */ + s->scgc[2] = value; + break; + case 0x120: /* DCGC0 */ + s->dcgc[0] = value; + break; + case 0x124: /* DCGC1 */ + s->dcgc[1] = value; + break; + case 0x128: /* DCGC2 */ + s->dcgc[2] = value; + break; + case 0x150: /* CLKVCLR */ + s->clkvclr = value; + break; + case 0x160: /* LDOARST */ + s->ldoarst = value; + break; + default: + cpu_abort(cpu_single_env, "gptm_write: Bad offset 0x%x\n", (int)offset); + } + ssys_update(s); +} + +static CPUReadMemoryFunc *ssys_readfn[] = { + ssys_read, + ssys_read, + ssys_read +}; + +static CPUWriteMemoryFunc *ssys_writefn[] = { + ssys_write, + ssys_write, + ssys_write +}; + +void ssys_reset(void *opaque) +{ + ssys_state *s = (ssys_state *)opaque; + + s->pborctl = 0x7ffd; + s->rcc = 0x078e3ac0; + s->rcgc[0] = 1; + s->scgc[0] = 1; + s->dcgc[0] = 1; +} + +static void stellaris_sys_init(uint32_t base, qemu_irq irq, + stellaris_board_info * board) +{ + int iomemtype; + ssys_state *s; + + s = (ssys_state *)qemu_mallocz(sizeof(ssys_state)); + s->base = base; + s->irq = irq; + s->board = board; + + iomemtype = cpu_register_io_memory(0, ssys_readfn, + ssys_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + ssys_reset(s); + /* ??? Save/restore. */ +} + + +/* I2C controller. */ + +typedef struct { + i2c_bus *bus; + qemu_irq irq; + uint32_t base; + uint32_t msa; + uint32_t mcs; + uint32_t mdr; + uint32_t mtpr; + uint32_t mimr; + uint32_t mris; + uint32_t mcr; +} stellaris_i2c_state; + +#define STELLARIS_I2C_MCS_BUSY 0x01 +#define STELLARIS_I2C_MCS_ERROR 0x02 +#define STELLARIS_I2C_MCS_ADRACK 0x04 +#define STELLARIS_I2C_MCS_DATACK 0x08 +#define STELLARIS_I2C_MCS_ARBLST 0x10 +#define STELLARIS_I2C_MCS_IDLE 0x20 +#define STELLARIS_I2C_MCS_BUSBSY 0x40 + +static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset) +{ + stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* MSA */ + return s->msa; + case 0x04: /* MCS */ + /* We don't emulate timing, so the controller is never busy. */ + return s->mcs | STELLARIS_I2C_MCS_IDLE; + case 0x08: /* MDR */ + return s->mdr; + case 0x0c: /* MTPR */ + return s->mtpr; + case 0x10: /* MIMR */ + return s->mimr; + case 0x14: /* MRIS */ + return s->mris; + case 0x18: /* MMIS */ + return s->mris & s->mimr; + case 0x20: /* MCR */ + return s->mcr; + default: + cpu_abort(cpu_single_env, "strllaris_i2c_read: Bad offset 0x%x\n", + (int)offset); + return 0; + } +} + +static void stellaris_i2c_update(stellaris_i2c_state *s) +{ + int level; + + level = (s->mris & s->mimr) != 0; + qemu_set_irq(s->irq, level); +} + +static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* MSA */ + s->msa = value & 0xff; + break; + case 0x04: /* MCS */ + if ((s->mcr & 0x10) == 0) { + /* Disabled. Do nothing. */ + break; + } + /* Grab the bus if this is starting a transfer. */ + if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { + if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) { + s->mcs |= STELLARIS_I2C_MCS_ARBLST; + } else { + s->mcs &= ~STELLARIS_I2C_MCS_ARBLST; + s->mcs |= STELLARIS_I2C_MCS_BUSBSY; + } + } + /* If we don't have the bus then indicate an error. */ + if (!i2c_bus_busy(s->bus) + || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { + s->mcs |= STELLARIS_I2C_MCS_ERROR; + break; + } + s->mcs &= ~STELLARIS_I2C_MCS_ERROR; + if (value & 1) { + /* Transfer a byte. */ + /* TODO: Handle errors. */ + if (s->msa & 1) { + /* Recv */ + s->mdr = i2c_recv(s->bus) & 0xff; + } else { + /* Send */ + i2c_send(s->bus, s->mdr); + } + /* Raise an interrupt. */ + s->mris |= 1; + } + if (value & 4) { + /* Finish transfer. */ + i2c_end_transfer(s->bus); + s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY; + } + break; + case 0x08: /* MDR */ + s->mdr = value & 0xff; + break; + case 0x0c: /* MTPR */ + s->mtpr = value & 0xff; + break; + case 0x10: /* MIMR */ + s->mimr = 1; + break; + case 0x1c: /* MICR */ + s->mris &= ~value; + break; + case 0x20: /* MCR */ + if (value & 1) + cpu_abort(cpu_single_env, + "stellaris_i2c_write: Loopback not implemented\n"); + if (value & 0x20) + cpu_abort(cpu_single_env, + "stellaris_i2c_write: Slave mode not implemented\n"); + s->mcr = value & 0x31; + break; + default: + cpu_abort(cpu_single_env, "stellaris_i2c_write: Bad offset 0x%x\n", + (int)offset); + } + stellaris_i2c_update(s); +} + +static void stellaris_i2c_reset(stellaris_i2c_state *s) +{ + if (s->mcs & STELLARIS_I2C_MCS_BUSBSY) + i2c_end_transfer(s->bus); + + s->msa = 0; + s->mcs = 0; + s->mdr = 0; + s->mtpr = 1; + s->mimr = 0; + s->mris = 0; + s->mcr = 0; + stellaris_i2c_update(s); +} + +static CPUReadMemoryFunc *stellaris_i2c_readfn[] = { + stellaris_i2c_read, + stellaris_i2c_read, + stellaris_i2c_read +}; + +static CPUWriteMemoryFunc *stellaris_i2c_writefn[] = { + stellaris_i2c_write, + stellaris_i2c_write, + stellaris_i2c_write +}; + +static void stellaris_i2c_init(uint32_t base, qemu_irq irq, i2c_bus *bus) +{ + stellaris_i2c_state *s; + int iomemtype; + + s = (stellaris_i2c_state *)qemu_mallocz(sizeof(stellaris_i2c_state)); + s->base = base; + s->irq = irq; + s->bus = bus; + + iomemtype = cpu_register_io_memory(0, stellaris_i2c_readfn, + stellaris_i2c_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + /* ??? For now we only implement the master interface. */ + stellaris_i2c_reset(s); +} + +/* Analogue to Digital Converter. This is only partially implemented, + enough for applications that use a combined ADC and timer tick. */ + +#define STELLARIS_ADC_EM_CONTROLLER 0 +#define STELLARIS_ADC_EM_COMP 1 +#define STELLARIS_ADC_EM_EXTERNAL 4 +#define STELLARIS_ADC_EM_TIMER 5 +#define STELLARIS_ADC_EM_PWM0 6 +#define STELLARIS_ADC_EM_PWM1 7 +#define STELLARIS_ADC_EM_PWM2 8 + +#define STELLARIS_ADC_FIFO_EMPTY 0x0100 +#define STELLARIS_ADC_FIFO_FULL 0x1000 + +typedef struct +{ + uint32_t base; + uint32_t actss; + uint32_t ris; + uint32_t im; + uint32_t emux; + uint32_t ostat; + uint32_t ustat; + uint32_t sspri; + uint32_t sac; + struct { + uint32_t state; + uint32_t data[16]; + } fifo[4]; + uint32_t ssmux[4]; + uint32_t ssctl[4]; + qemu_irq irq; +} stellaris_adc_state; + +static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n) +{ + int tail; + + tail = s->fifo[n].state & 0xf; + if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) { + s->ustat |= 1 << n; + } else { + s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf); + s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL; + if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf)) + s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY; + } + return s->fifo[n].data[tail]; +} + +static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n, + uint32_t value) +{ + int head; + + head = (s->fifo[n].state >> 4) & 0xf; + if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) { + s->ostat |= 1 << n; + return; + } + s->fifo[n].data[head] = value; + head = (head + 1) & 0xf; + s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY; + s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4); + if ((s->fifo[n].state & 0xf) == head) + s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL; +} + +static void stellaris_adc_update(stellaris_adc_state *s) +{ + int level; + + level = (s->ris & s->im) != 0; + qemu_set_irq(s->irq, level); +} + +static void stellaris_adc_trigger(void *opaque, int irq, int level) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + /* Some applications use the ADC as a random number source, so introduce + some variation into the signal. */ + static uint32_t noise = 0; + + if ((s->actss & 1) == 0) { + return; + } + + noise = noise * 314159 + 1; + /* ??? actual inputs not implemented. Return an arbitrary value. */ + stellaris_adc_fifo_write(s, 0, 0x200 + ((noise >> 16) & 7)); + s->ris |= 1; + stellaris_adc_update(s); +} + +static void stellaris_adc_reset(stellaris_adc_state *s) +{ + int n; + + for (n = 0; n < 4; n++) { + s->ssmux[n] = 0; + s->ssctl[n] = 0; + s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY; + } +} + +static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + + /* TODO: Implement this. */ + offset -= s->base; + if (offset >= 0x40 && offset < 0xc0) { + int n; + n = (offset - 0x40) >> 5; + switch (offset & 0x1f) { + case 0x00: /* SSMUX */ + return s->ssmux[n]; + case 0x04: /* SSCTL */ + return s->ssctl[n]; + case 0x08: /* SSFIFO */ + return stellaris_adc_fifo_read(s, n); + case 0x0c: /* SSFSTAT */ + return s->fifo[n].state; + default: + break; + } + } + switch (offset) { + case 0x00: /* ACTSS */ + return s->actss; + case 0x04: /* RIS */ + return s->ris; + case 0x08: /* IM */ + return s->im; + case 0x0c: /* ISC */ + return s->ris & s->im; + case 0x10: /* OSTAT */ + return s->ostat; + case 0x14: /* EMUX */ + return s->emux; + case 0x18: /* USTAT */ + return s->ustat; + case 0x20: /* SSPRI */ + return s->sspri; + case 0x30: /* SAC */ + return s->sac; + default: + cpu_abort(cpu_single_env, "strllaris_adc_read: Bad offset 0x%x\n", + (int)offset); + return 0; + } +} + +static void stellaris_adc_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + stellaris_adc_state *s = (stellaris_adc_state *)opaque; + + /* TODO: Implement this. */ + offset -= s->base; + if (offset >= 0x40 && offset < 0xc0) { + int n; + n = (offset - 0x40) >> 5; + switch (offset & 0x1f) { + case 0x00: /* SSMUX */ + s->ssmux[n] = value & 0x33333333; + return; + case 0x04: /* SSCTL */ + if (value != 6) { + cpu_abort(cpu_single_env, "ADC: Unimplemented sequence %x\n", + value); + } + s->ssctl[n] = value; + return; + default: + break; + } + } + switch (offset) { + case 0x00: /* ACTSS */ + s->actss = value & 0xf; + if (value & 0xe) { + cpu_abort(cpu_single_env, + "Not implemented: ADC sequencers 1-3\n"); + } + break; + case 0x08: /* IM */ + s->im = value; + break; + case 0x0c: /* ISC */ + s->ris &= ~value; + break; + case 0x10: /* OSTAT */ + s->ostat &= ~value; + break; + case 0x14: /* EMUX */ + s->emux = value; + break; + case 0x18: /* USTAT */ + s->ustat &= ~value; + break; + case 0x20: /* SSPRI */ + s->sspri = value; + break; + case 0x28: /* PSSI */ + cpu_abort(cpu_single_env, "Not implemented: ADC sample initiate\n"); + break; + case 0x30: /* SAC */ + s->sac = value; + break; + default: + cpu_abort(cpu_single_env, "stellaris_adc_write: Bad offset 0x%x\n", + (int)offset); + } + stellaris_adc_update(s); +} + +static CPUReadMemoryFunc *stellaris_adc_readfn[] = { + stellaris_adc_read, + stellaris_adc_read, + stellaris_adc_read +}; + +static CPUWriteMemoryFunc *stellaris_adc_writefn[] = { + stellaris_adc_write, + stellaris_adc_write, + stellaris_adc_write +}; + +static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq) +{ + stellaris_adc_state *s; + int iomemtype; + qemu_irq *qi; + + s = (stellaris_adc_state *)qemu_mallocz(sizeof(stellaris_adc_state)); + s->base = base; + s->irq = irq; + + iomemtype = cpu_register_io_memory(0, stellaris_adc_readfn, + stellaris_adc_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + stellaris_adc_reset(s); + qi = qemu_allocate_irqs(stellaris_adc_trigger, s, 1); + return qi[0]; +} + +/* Board init. */ +static stellaris_board_info stellaris_boards[] = { + { "LM3S811EVB", + 0, + 0x0032000e, + 0x001f001f, /* dc0 */ + 0x001132bf, + 0x01071013, + 0x3f0f01ff, + 0x0000001f, + OLED_I2C + }, + { "LM3S6965EVB", + 0x10010002, + 0x1073402e, + 0x00ff007f, /* dc0 */ + 0x001133ff, + 0x030f5317, + 0x0f0f87ff, + 0x5000007f, + OLED_SSI + } +}; + +static void stellaris_init(const char *kernel_filename, const char *cpu_model, + DisplayState *ds, stellaris_board_info *board) +{ + static const int uart_irq[] = {5, 6, 33, 34}; + static const int timer_irq[] = {19, 21, 23, 35}; + static const uint32_t gpio_addr[7] = + { 0x40004000, 0x40005000, 0x40006000, 0x40007000, + 0x40024000, 0x40025000, 0x40026000}; + static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; + + qemu_irq *pic; + qemu_irq *gpio_in[5]; + qemu_irq *gpio_out[5]; + qemu_irq adc; + int sram_size; + int flash_size; + i2c_bus *i2c; + int i; + + flash_size = ((board->dc0 & 0xffff) + 1) << 1; + sram_size = (board->dc0 >> 18) + 1; + pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model); + + if (board->dc1 & (1 << 16)) { + adc = stellaris_adc_init(0x40038000, pic[14]); + } else { + adc = NULL; + } + for (i = 0; i < 4; i++) { + if (board->dc2 & (0x10000 << i)) { + stellaris_gptm_init(0x40030000 + i * 0x1000, + pic[timer_irq[i]], adc); + } + } + + stellaris_sys_init(0x400fe000, pic[28], board); + + for (i = 0; i < 7; i++) { + if (board->dc4 & (1 << i)) { + gpio_in[i] = pl061_init(gpio_addr[i], pic[gpio_irq[i]], + &gpio_out[i]); + } + } + + if (board->dc2 & (1 << 12)) { + i2c = i2c_init_bus(); + stellaris_i2c_init(0x40020000, pic[8], i2c); + if (board->oled == OLED_I2C) { + ssd0303_init(ds, i2c, 0x3d); + } + } + + for (i = 0; i < 4; i++) { + if (board->dc2 & (1 << i)) { + pl011_init(0x4000c000 + i * 0x1000, pic[uart_irq[i]], + serial_hds[i], PL011_LUMINARY); + } + } + if (board->dc2 & (1 << 4)) { + if (board->oled == OLED_SSI) { + void * oled; + /* FIXME: Implement chip select for OLED/MMC. */ + oled = ssd0323_init(ds, &gpio_out[2][7]); + pl022_init(0x40008000, pic[7], ssd0323_xfer_ssi, oled); + } else { + pl022_init(0x40008000, pic[7], NULL, NULL); + } + } +} + +/* FIXME: Figure out how to generate these from stellaris_boards. */ +static void lm3s811evb_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + stellaris_init(kernel_filename, cpu_model, ds, &stellaris_boards[0]); +} + +static void lm3s6965evb_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + stellaris_init(kernel_filename, cpu_model, ds, &stellaris_boards[1]); +} + +QEMUMachine lm3s811evb_machine = { + "lm3s811evb", + "Stellaris LM3S811EVB", + lm3s811evb_init, +}; + +QEMUMachine lm3s6965evb_machine = { + "lm3s6965evb", + "Stellaris LM3S6965EVB", + lm3s6965evb_init, +}; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index fc27c4688..4e8e76e26 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -208,10 +208,10 @@ static void versatile_init(int ram_size, int vga_ram_size, } } - pl011_init(0x101f1000, pic[12], serial_hds[0]); - pl011_init(0x101f2000, pic[13], serial_hds[1]); - pl011_init(0x101f3000, pic[14], serial_hds[2]); - pl011_init(0x10009000, sic[6], serial_hds[3]); + pl011_init(0x101f1000, pic[12], serial_hds[0], PL011_ARM); + pl011_init(0x101f2000, pic[13], serial_hds[1], PL011_ARM); + pl011_init(0x101f3000, pic[14], serial_hds[2], PL011_ARM); + pl011_init(0x10009000, sic[6], serial_hds[3], PL011_ARM); pl080_init(0x10130000, pic[17], 8); sp804_init(0x101e2000, pic[4]); diff --git a/qemu-doc.texi b/qemu-doc.texi index 3645ba2c1..740d30359 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -77,10 +77,12 @@ For system emulation, the following hardware targets are supported: @item Sun4m (32-bit Sparc processor) @item Sun4u (64-bit Sparc processor, in progress) @item Malta board (32-bit MIPS processor) -@item ARM Integrator/CP (ARM926E, 1026E or 946E processor) -@item ARM Versatile baseboard (ARM926E) -@item ARM RealView Emulation baseboard (ARM926EJ-S) +@item ARM Integrator/CP (ARM) +@item ARM Versatile baseboard (ARM) +@item ARM RealView Emulation baseboard (ARM) @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor) +@item Luminary Micro LM3S811EVB (ARM Cortex-M3) +@item Luminary Micro LM3S6965EVB (ARM Cortex-M3) @item Freescale MCF5208EVB (ColdFire V2). @item Arnewsh MCF5206 evaluation board (ColdFire V2). @item Palm Tungsten|E PDA (OMAP310 processor) @@ -2117,7 +2119,7 @@ devices: @itemize @minus @item -ARM926E, ARM1026E or ARM946E CPU +ARM926E, ARM1026E, ARM946E, ARM1136 or Cortex-A8 CPU @item Two PL011 UARTs @item @@ -2134,7 +2136,7 @@ The ARM Versatile baseboard is emulated with the following devices: @itemize @minus @item -ARM926E CPU +ARM926E, ARM1136 or Cortex-A8 CPU @item PL190 Vectored Interrupt Controller @item @@ -2163,7 +2165,7 @@ The ARM RealView Emulation baseboard is emulated with the following devices: @itemize @minus @item -ARM926E CPU +ARM926E, ARM1136, ARM11MPCORE(x4) or Cortex-A8 CPU @item ARM AMBA Generic/Distributed Interrupt Controller @item @@ -2237,6 +2239,34 @@ Secure Digital card connected to OMAP MMC/SD host Three on-chip UARTs @end itemize +The Luminary Micro Stellaris LM3S811EVB emulation includes the following +devices: + +@itemize @minus +@item +Cortex-M3 CPU core. +@item +64k Flash and 8k SRAM. +@item +Timers, UARTs, ADC and I@math{^2}C interface. +@item +OSRAM Pictiva 96x16 OLED with SSD0303 controller on I@math{^2}C bus. +@end itemize + +The Luminary Micro Stellaris LM3S6965EVB emulation includes the following +devices: + +@itemize @minus +@item +Cortex-M3 CPU core. +@item +256k Flash and 64k SRAM. +@item +Timers, UARTs, ADC, I@math{^2}C and SSI interfaces. +@item +OSRAM Pictiva 128x64 OLED with SSD0323 controller connected via SSI. +@end itemize + A Linux 2.6 test image is available on the QEMU web site. More information is available in the QEMU mailing-list archive. diff --git a/target-arm/cpu.h b/target-arm/cpu.h index fb22b908d..59b96963b 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -37,6 +37,18 @@ #define EXCP_IRQ 5 #define EXCP_FIQ 6 #define EXCP_BKPT 7 +#define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ + +#define ARMV7M_EXCP_RESET 1 +#define ARMV7M_EXCP_NMI 2 +#define ARMV7M_EXCP_HARD 3 +#define ARMV7M_EXCP_MEM 4 +#define ARMV7M_EXCP_BUS 5 +#define ARMV7M_EXCP_USAGE 6 +#define ARMV7M_EXCP_SVC 11 +#define ARMV7M_EXCP_DEBUG 12 +#define ARMV7M_EXCP_PENDSV 14 +#define ARMV7M_EXCP_SYSTICK 15 typedef void ARMWriteCPFunc(void *opaque, int cp_info, int srcreg, int operand, uint32_t value); @@ -76,17 +88,22 @@ typedef struct CPUARMState { uint32_t VF; /* V is the bit 31. All other bits are undefined */ uint32_t NZF; /* N is bit 31. Z is computed from NZF */ uint32_t QF; /* 0 or 1 */ - - int thumb; /* 0 = arm mode, 1 = thumb mode */ + uint32_t GE; /* cpsr[19:16] */ + int thumb; /* cprs[5]. 0 = arm mode, 1 = thumb mode. */ + uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */ /* System control coprocessor (cp15) */ struct { uint32_t c0_cpuid; uint32_t c0_cachetype; + uint32_t c0_c1[8]; /* Feature registers. */ + uint32_t c0_c2[8]; /* Instruction set registers. */ uint32_t c1_sys; /* System control register. */ uint32_t c1_coproc; /* Coprocessor access register. */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ - uint32_t c2_base; /* MMU translation table base. */ + uint32_t c2_base0; /* MMU translation table base 0. */ + uint32_t c2_base1; /* MMU translation table base 1. */ + uint32_t c2_mask; /* MMU translation table base mask. */ uint32_t c2_data; /* MPU data cachable bits. */ uint32_t c2_insn; /* MPU instruction cachable bits. */ uint32_t c3; /* MMU domain access control register @@ -100,6 +117,9 @@ typedef struct CPUARMState { uint32_t c9_data; uint32_t c13_fcse; /* FCSE PID. */ uint32_t c13_context; /* Context ID. */ + uint32_t c13_tls1; /* User RW Thread register. */ + uint32_t c13_tls2; /* User RO Thread register. */ + uint32_t c13_tls3; /* Privileged Thread register. */ uint32_t c15_cpar; /* XScale Coprocessor Access Register */ uint32_t c15_ticonfig; /* TI925T configuration byte. */ uint32_t c15_i_max; /* Maximum D-cache dirty line index. */ @@ -107,6 +127,17 @@ typedef struct CPUARMState { uint32_t c15_threadid; /* TI debugger thread-ID. */ } cp15; + struct { + uint32_t other_sp; + uint32_t vecbase; + uint32_t basepri; + uint32_t control; + int current_sp; + int exception; + int pending_exception; + void *nvic; + } v7m; + /* Coprocessor IO used by peripherals */ struct { ARMReadCPFunc *cp_read; @@ -117,6 +148,10 @@ typedef struct CPUARMState { /* Internal CPU feature flags. */ uint32_t features; + /* Callback for vectored interrupt controller. */ + int (*get_irq_vector)(struct CPUARMState *); + void *irq_opaque; + /* exception/interrupt handling */ jmp_buf jmp_env; int exception_index; @@ -126,7 +161,7 @@ typedef struct CPUARMState { /* VFP coprocessor state. */ struct { - float64 regs[16]; + float64 regs[32]; uint32_t xregs[16]; /* We store these fpcsr fields separately for convenience. */ @@ -136,9 +171,16 @@ typedef struct CPUARMState { /* Temporary variables if we don't have spare fp regs. */ float32 tmp0s, tmp1s; float64 tmp0d, tmp1d; + /* scratch space when Tn are not sufficient. */ + uint32_t scratch[8]; float_status fp_status; } vfp; +#if defined(CONFIG_USER_ONLY) + struct mmon_state *mmon_entry; +#else + uint32_t mmon_addr; +#endif /* iwMMXt coprocessor state. */ struct { @@ -169,6 +211,7 @@ int cpu_arm_exec(CPUARMState *s); void cpu_arm_close(CPUARMState *s); void do_interrupt(CPUARMState *); void switch_mode(CPUARMState *, int); +uint32_t do_arm_semihosting(CPUARMState *env); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero @@ -176,6 +219,9 @@ void switch_mode(CPUARMState *, int); int cpu_arm_signal_handler(int host_signum, void *pinfo, void *puc); +void cpu_lock(void); +void cpu_unlock(void); + #define CPSR_M (0x1f) #define CPSR_T (1 << 5) #define CPSR_F (1 << 6) @@ -183,13 +229,24 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo, #define CPSR_A (1 << 8) #define CPSR_E (1 << 9) #define CPSR_IT_2_7 (0xfc00) -/* Bits 20-23 reserved. */ +#define CPSR_GE (0xf << 16) +#define CPSR_RESERVED (0xf << 20) #define CPSR_J (1 << 24) #define CPSR_IT_0_1 (3 << 25) #define CPSR_Q (1 << 27) -#define CPSR_NZCV (0xf << 28) +#define CPSR_V (1 << 28) +#define CPSR_C (1 << 29) +#define CPSR_Z (1 << 30) +#define CPSR_N (1 << 31) +#define CPSR_NZCV (CPSR_N | CPSR_Z | CPSR_C | CPSR_V) + +#define CPSR_IT (CPSR_IT_0_1 | CPSR_IT_2_7) +#define CACHED_CPSR_BITS (CPSR_T | CPSR_GE | CPSR_IT | CPSR_Q | CPSR_NZCV) +/* Bits writable in user mode. */ +#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE) +/* Execution state bits. MRS read as zero, MSR writes ignored. */ +#define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J) -#define CACHED_CPSR_BITS (CPSR_T | CPSR_Q | CPSR_NZCV) /* Return the current CPSR value. */ static inline uint32_t cpsr_read(CPUARMState *env) { @@ -197,7 +254,21 @@ static inline uint32_t cpsr_read(CPUARMState *env) ZF = (env->NZF == 0); return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) - | (env->thumb << 5); + | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) + | ((env->condexec_bits & 0xfc) << 8) + | (env->GE << 16); +} + +/* Return the current xPSR value. */ +static inline uint32_t xpsr_read(CPUARMState *env) +{ + int ZF; + ZF = (env->NZF == 0); + return (env->NZF & 0x80000000) | (ZF << 30) + | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + | (env->thumb << 24) | ((env->condexec_bits & 3) << 25) + | ((env->condexec_bits & 0xfc) << 8) + | env->v7m.exception; } /* Set the CPSR. Note that some bits of mask must be all-set or all-clear. */ @@ -213,6 +284,17 @@ static inline void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) env->QF = ((val & CPSR_Q) != 0); if (mask & CPSR_T) env->thumb = ((val & CPSR_T) != 0); + if (mask & CPSR_IT_0_1) { + env->condexec_bits &= ~3; + env->condexec_bits |= (val >> 25) & 3; + } + if (mask & CPSR_IT_2_7) { + env->condexec_bits &= 3; + env->condexec_bits |= (val >> 8) & 0xfc; + } + if (mask & CPSR_GE) { + env->GE = (val >> 16) & 0xf; + } if ((env->uncached_cpsr ^ val) & mask & CPSR_M) { switch_mode(env, val & CPSR_M); @@ -221,6 +303,32 @@ static inline void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); } +/* Set the xPSR. Note that some bits of mask must be all-set or all-clear. */ +static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) +{ + /* NOTE: N = 1 and Z = 1 cannot be stored currently */ + if (mask & CPSR_NZCV) { + env->NZF = (val & 0xc0000000) ^ 0x40000000; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + if (mask & CPSR_Q) + env->QF = ((val & CPSR_Q) != 0); + if (mask & (1 << 24)) + env->thumb = ((val & (1 << 24)) != 0); + if (mask & CPSR_IT_0_1) { + env->condexec_bits &= ~3; + env->condexec_bits |= (val >> 25) & 3; + } + if (mask & CPSR_IT_2_7) { + env->condexec_bits &= 3; + env->condexec_bits |= (val >> 8) & 0xfc; + } + if (mask & 0x1ff) { + env->v7m.exception = val & 0x1ff; + } +} + enum arm_cpu_mode { ARM_CPU_MODE_USR = 0x10, ARM_CPU_MODE_FIQ = 0x11, @@ -234,6 +342,8 @@ enum arm_cpu_mode { /* VFP system registers. */ #define ARM_VFP_FPSID 0 #define ARM_VFP_FPSCR 1 +#define ARM_VFP_MVFR1 6 +#define ARM_VFP_MVFR0 7 #define ARM_VFP_FPEXC 8 #define ARM_VFP_FPINST 9 #define ARM_VFP_FPINST2 10 @@ -253,7 +363,15 @@ enum arm_features { ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */ + ARM_FEATURE_V6, + ARM_FEATURE_V6K, + ARM_FEATURE_V7, + ARM_FEATURE_THUMB2, ARM_FEATURE_MPU, /* Only has Memory Protection Unit, not full MMU. */ + ARM_FEATURE_VFP3, + ARM_FEATURE_NEON, + ARM_FEATURE_DIV, + ARM_FEATURE_M, /* Microcontroller profile. */ ARM_FEATURE_OMAPCP /* OMAP specific CP15 ops handling. */ }; @@ -264,27 +382,44 @@ static inline int arm_feature(CPUARMState *env, int feature) void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +/* Interface between CPU and Interrupt controller. */ +void armv7m_nvic_set_pending(void *opaque, int irq); +int armv7m_nvic_acknowledge_irq(void *opaque); +void armv7m_nvic_complete_irq(void *opaque, int irq); + void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, void *opaque); -#define ARM_CPUID_ARM1026 0x4106a262 -#define ARM_CPUID_ARM926 0x41069265 -#define ARM_CPUID_ARM946 0x41059461 -#define ARM_CPUID_TI915T 0x54029152 -#define ARM_CPUID_TI925T 0x54029252 -#define ARM_CPUID_PXA250 0x69052100 -#define ARM_CPUID_PXA255 0x69052d00 -#define ARM_CPUID_PXA260 0x69052903 -#define ARM_CPUID_PXA261 0x69052d05 -#define ARM_CPUID_PXA262 0x69052d06 -#define ARM_CPUID_PXA270 0x69054110 -#define ARM_CPUID_PXA270_A0 0x69054110 -#define ARM_CPUID_PXA270_A1 0x69054111 -#define ARM_CPUID_PXA270_B0 0x69054112 -#define ARM_CPUID_PXA270_B1 0x69054113 -#define ARM_CPUID_PXA270_C0 0x69054114 -#define ARM_CPUID_PXA270_C5 0x69054117 +/* Does the core conform to the the "MicroController" profile. e.g. Cortex-M3. + Note the M in older cores (eg. ARM7TDMI) stands for Multiply. These are + conventional cores (ie. Application or Realtime profile). */ + +#define IS_M(env) arm_feature(env, ARM_FEATURE_M) +#define ARM_CPUID(env) (env->cp15.c0_cpuid) + +#define ARM_CPUID_ARM1026 0x4106a262 +#define ARM_CPUID_ARM926 0x41069265 +#define ARM_CPUID_ARM946 0x41059461 +#define ARM_CPUID_TI915T 0x54029152 +#define ARM_CPUID_TI925T 0x54029252 +#define ARM_CPUID_PXA250 0x69052100 +#define ARM_CPUID_PXA255 0x69052d00 +#define ARM_CPUID_PXA260 0x69052903 +#define ARM_CPUID_PXA261 0x69052d05 +#define ARM_CPUID_PXA262 0x69052d06 +#define ARM_CPUID_PXA270 0x69054110 +#define ARM_CPUID_PXA270_A0 0x69054110 +#define ARM_CPUID_PXA270_A1 0x69054111 +#define ARM_CPUID_PXA270_B0 0x69054112 +#define ARM_CPUID_PXA270_B1 0x69054113 +#define ARM_CPUID_PXA270_C0 0x69054114 +#define ARM_CPUID_PXA270_C5 0x69054117 +#define ARM_CPUID_ARM1136 0x4117b363 +#define ARM_CPUID_ARM11MPCORE 0x410fb022 +#define ARM_CPUID_CORTEXA8 0x410fc080 +#define ARM_CPUID_CORTEXM3 0x410fc231 +#define ARM_CPUID_ANY 0xffffffff #if defined(CONFIG_USER_ONLY) #define TARGET_PAGE_BITS 12 @@ -302,6 +437,8 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define cpu_signal_handler cpu_arm_signal_handler #define cpu_list arm_cpu_list +#define ARM_CPU_SAVE_VERSION 1 + /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel #define MMU_MODE1_SUFFIX _user diff --git a/target-arm/exec.h b/target-arm/exec.h index 0c53b8d5f..cb202062d 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -68,12 +68,18 @@ static inline int cpu_halted(CPUState *env) { /* In op_helper.c */ -void cpu_lock(void); -void cpu_unlock(void); void helper_set_cp(CPUState *, uint32_t, uint32_t); uint32_t helper_get_cp(CPUState *, uint32_t); void helper_set_cp15(CPUState *, uint32_t, uint32_t); uint32_t helper_get_cp15(CPUState *, uint32_t); +void helper_set_r13_banked(CPUState *env, int mode, uint32_t val); +uint32_t helper_get_r13_banked(CPUState *env, int mode); +uint32_t helper_v7m_mrs(CPUState *env, int reg); +void helper_v7m_msr(CPUState *env, int reg, uint32_t val); + +void helper_mark_exclusive(CPUARMState *, uint32_t addr); +int helper_test_exclusive(CPUARMState *, uint32_t addr); +void helper_clrex(CPUARMState *env); void cpu_loop_exit(void); @@ -91,4 +97,11 @@ void do_vfp_cmpes(void); void do_vfp_cmped(void); void do_vfp_set_fpscr(void); void do_vfp_get_fpscr(void); - +float32 helper_recps_f32(float32, float32); +float32 helper_rsqrts_f32(float32, float32); +uint32_t helper_recpe_u32(uint32_t); +uint32_t helper_rsqrte_u32(uint32_t); +float32 helper_recpe_f32(float32); +float32 helper_rsqrte_f32(float32); +void helper_neon_tbl(int rn, int maxindex); +uint32_t helper_neon_mul_p8(uint32_t op1, uint32_t op2); diff --git a/target-arm/helper.c b/target-arm/helper.c index 06eac66a1..69752564d 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -4,6 +4,25 @@ #include "cpu.h" #include "exec-all.h" +#include "gdbstub.h" + +static uint32_t cortexa8_cp15_c0_c1[8] = +{ 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 }; + +static uint32_t cortexa8_cp15_c0_c2[8] = +{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 }; + +static uint32_t mpcore_cp15_c0_c1[8] = +{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 }; + +static uint32_t mpcore_cp15_c0_c2[8] = +{ 0x00100011, 0x12002111, 0x11221011, 0x01102131, 0x141, 0, 0, 0 }; + +static uint32_t arm1136_cp15_c0_c1[8] = +{ 0x111, 0x1, 0x2, 0x3, 0x01130003, 0x10030302, 0x01222110, 0 }; + +static uint32_t arm1136_cp15_c0_c2[8] = +{ 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 }; static uint32_t cpu_arm_find_by_name(const char *name); @@ -34,6 +53,62 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_cachetype = 0x1dd20d2; env->cp15.c1_sys = 0x00090078; break; + case ARM_CPUID_ARM1136: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; + memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x1dd20d2; + break; + case ARM_CPUID_ARM11MPCORE: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_AUXCR); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000; + memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x1dd20d2; + break; + case ARM_CPUID_CORTEXA8: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_AUXCR); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_VFP3); + set_feature(env, ARM_FEATURE_NEON); + env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0; + env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222; + env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100; + memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t)); + memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t)); + env->cp15.c0_cachetype = 0x1dd20d2; + break; + case ARM_CPUID_CORTEXM3: + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_M); + set_feature(env, ARM_FEATURE_DIV); + break; + case ARM_CPUID_ANY: /* For userspace emulation. */ + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_V6K); + set_feature(env, ARM_FEATURE_V7); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_VFP); + set_feature(env, ARM_FEATURE_VFP3); + set_feature(env, ARM_FEATURE_NEON); + set_feature(env, ARM_FEATURE_DIV); + break; case ARM_CPUID_TI915T: case ARM_CPUID_TI925T: set_feature(env, ARM_FEATURE_OMAPCP); @@ -85,6 +160,10 @@ void cpu_reset(CPUARMState *env) #else /* SVC mode with interrupts disabled. */ env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is + clear at reset. */ + if (IS_M(env)) + env->uncached_cpsr &= ~CPSR_I; env->vfp.xregs[ARM_VFP_FPEXC] = 0; #endif env->regs[15] = 0; @@ -117,6 +196,10 @@ static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_ARM926, "arm926"}, { ARM_CPUID_ARM946, "arm946"}, { ARM_CPUID_ARM1026, "arm1026"}, + { ARM_CPUID_ARM1136, "arm1136"}, + { ARM_CPUID_ARM11MPCORE, "arm11mpcore"}, + { ARM_CPUID_CORTEXM3, "cortex-m3"}, + { ARM_CPUID_CORTEXA8, "cortex-a8"}, { ARM_CPUID_TI925T, "ti925t" }, { ARM_CPUID_PXA250, "pxa250" }, { ARM_CPUID_PXA255, "pxa255" }, @@ -130,6 +213,7 @@ static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_PXA270_B1, "pxa270-b1" }, { ARM_CPUID_PXA270_C0, "pxa270-c0" }, { ARM_CPUID_PXA270_C5, "pxa270-c5" }, + { ARM_CPUID_ANY, "any"}, { 0, NULL} }; @@ -164,6 +248,30 @@ void cpu_arm_close(CPUARMState *env) free(env); } +/* Polynomial multiplication is like integer multiplcation except the + partial products are XORed, not added. */ +uint32_t helper_neon_mul_p8(uint32_t op1, uint32_t op2) +{ + uint32_t mask; + uint32_t result; + result = 0; + while (op1) { + mask = 0; + if (op1 & 1) + mask |= 0xff; + if (op1 & (1 << 8)) + mask |= (0xff << 8); + if (op1 & (1 << 16)) + mask |= (0xff << 16); + if (op1 & (1 << 24)) + mask |= (0xff << 24); + result ^= op2 & mask; + op1 = (op1 >> 1) & 0x7f7f7f7f; + op2 = (op2 << 1) & 0xfefefefe; + } + return result; +} + #if defined(CONFIG_USER_ONLY) void do_interrupt (CPUState *env) @@ -171,6 +279,16 @@ void do_interrupt (CPUState *env) env->exception_index = -1; } +/* Structure used to record exclusive memory locations. */ +typedef struct mmon_state { + struct mmon_state *next; + CPUARMState *cpu_env; + uint32_t addr; +} mmon_state; + +/* Chain of current locks. */ +static mmon_state* mmon_head = NULL; + int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int mmu_idx, int is_softmmu) { @@ -184,6 +302,64 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 1; } +static void allocate_mmon_state(CPUState *env) +{ + env->mmon_entry = malloc(sizeof (mmon_state)); + if (!env->mmon_entry) + abort(); + memset (env->mmon_entry, 0, sizeof (mmon_state)); + env->mmon_entry->cpu_env = env; + mmon_head = env->mmon_entry; +} + +/* Flush any monitor locks for the specified address. */ +static void flush_mmon(uint32_t addr) +{ + mmon_state *mon; + + for (mon = mmon_head; mon; mon = mon->next) + { + if (mon->addr != addr) + continue; + + mon->addr = 0; + break; + } +} + +/* Mark an address for exclusive access. */ +void helper_mark_exclusive(CPUState *env, uint32_t addr) +{ + if (!env->mmon_entry) + allocate_mmon_state(env); + /* Clear any previous locks. */ + flush_mmon(addr); + env->mmon_entry->addr = addr; +} + +/* Test if an exclusive address is still exclusive. Returns zero + if the address is still exclusive. */ +int helper_test_exclusive(CPUState *env, uint32_t addr) +{ + int res; + + if (!env->mmon_entry) + return 1; + if (env->mmon_entry->addr == addr) + res = 0; + else + res = 1; + flush_mmon(addr); + return res; +} + +void helper_clrex(CPUState *env) +{ + if (!(env->mmon_entry && env->mmon_entry->addr)) + return; + flush_mmon(env->mmon_entry->addr); +} + target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { return addr; @@ -215,12 +391,35 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) return 0; } +/* These should probably raise undefined insn exceptions. */ +void helper_v7m_msr(CPUState *env, int reg, uint32_t val) +{ + cpu_abort(env, "v7m_mrs %d\n", reg); +} + +uint32_t helper_v7m_mrs(CPUState *env, int reg) +{ + cpu_abort(env, "v7m_mrs %d\n", reg); + return 0; +} + void switch_mode(CPUState *env, int mode) { if (mode != ARM_CPU_MODE_USR) cpu_abort(env, "Tried to switch out of user mode\n"); } +void helper_set_r13_banked(CPUState *env, int mode, uint32_t val) +{ + cpu_abort(env, "banked r13 write\n"); +} + +uint32_t helper_get_r13_banked(CPUState *env, int mode) +{ + cpu_abort(env, "banked r13 read\n"); + return 0; +} + #else extern int semihosting_enabled; @@ -275,6 +474,129 @@ void switch_mode(CPUState *env, int mode) env->spsr = env->banked_spsr[i]; } +static void v7m_push(CPUARMState *env, uint32_t val) +{ + env->regs[13] -= 4; + stl_phys(env->regs[13], val); +} + +static uint32_t v7m_pop(CPUARMState *env) +{ + uint32_t val; + val = ldl_phys(env->regs[13]); + env->regs[13] += 4; + return val; +} + +/* Switch to V7M main or process stack pointer. */ +static void switch_v7m_sp(CPUARMState *env, int process) +{ + uint32_t tmp; + if (env->v7m.current_sp != process) { + tmp = env->v7m.other_sp; + env->v7m.other_sp = env->regs[13]; + env->regs[13] = tmp; + env->v7m.current_sp = process; + } +} + +static void do_v7m_exception_exit(CPUARMState *env) +{ + uint32_t type; + uint32_t xpsr; + + type = env->regs[15]; + if (env->v7m.exception != 0) + armv7m_nvic_complete_irq(env->v7m.nvic, env->v7m.exception); + + /* Switch to the target stack. */ + switch_v7m_sp(env, (type & 4) != 0); + /* Pop registers. */ + env->regs[0] = v7m_pop(env); + env->regs[1] = v7m_pop(env); + env->regs[2] = v7m_pop(env); + env->regs[3] = v7m_pop(env); + env->regs[12] = v7m_pop(env); + env->regs[14] = v7m_pop(env); + env->regs[15] = v7m_pop(env); + xpsr = v7m_pop(env); + xpsr_write(env, xpsr, 0xfffffdff); + /* Undo stack alignment. */ + if (xpsr & 0x200) + env->regs[13] |= 4; + /* ??? The exception return type specifies Thread/Handler mode. However + this is also implied by the xPSR value. Not sure what to do + if there is a mismatch. */ + /* ??? Likewise for mismatches between the CONTROL register and the stack + pointer. */ +} + +void do_interrupt_v7m(CPUARMState *env) +{ + uint32_t xpsr = xpsr_read(env); + uint32_t lr; + uint32_t addr; + + lr = 0xfffffff1; + if (env->v7m.current_sp) + lr |= 4; + if (env->v7m.exception == 0) + lr |= 8; + + /* For exceptions we just mark as pending on the NVIC, and let that + handle it. */ + /* TODO: Need to escalate if the current priority is higher than the + one we're raising. */ + switch (env->exception_index) { + case EXCP_UDEF: + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_USAGE); + return; + case EXCP_SWI: + env->regs[15] += 2; + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_SVC); + return; + case EXCP_PREFETCH_ABORT: + case EXCP_DATA_ABORT: + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_MEM); + return; + case EXCP_BKPT: + armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_DEBUG); + return; + case EXCP_IRQ: + env->v7m.exception = armv7m_nvic_acknowledge_irq(env->v7m.nvic); + break; + case EXCP_EXCEPTION_EXIT: + do_v7m_exception_exit(env); + return; + default: + cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index); + return; /* Never happens. Keep compiler happy. */ + } + + /* Align stack pointer. */ + /* ??? Should only do this if Configuration Control Register + STACKALIGN bit is set. */ + if (env->regs[13] & 4) { + env->regs[13] += 4; + xpsr |= 0x200; + } + /* Switch to the hander mode. */ + v7m_push(env, xpsr); + v7m_push(env, env->regs[15]); + v7m_push(env, env->regs[14]); + v7m_push(env, env->regs[12]); + v7m_push(env, env->regs[3]); + v7m_push(env, env->regs[2]); + v7m_push(env, env->regs[1]); + v7m_push(env, env->regs[0]); + switch_v7m_sp(env, 0); + env->uncached_cpsr &= ~CPSR_IT; + env->regs[14] = lr; + addr = ldl_phys(env->v7m.vecbase + env->v7m.exception * 4); + env->regs[15] = addr & 0xfffffffe; + env->thumb = addr & 1; +} + /* Handle a CPU exception. */ void do_interrupt(CPUARMState *env) { @@ -283,6 +605,10 @@ void do_interrupt(CPUARMState *env) int new_mode; uint32_t offset; + if (IS_M(env)) { + do_interrupt_v7m(env); + return; + } /* TODO: Vectored interrupt controller. */ switch (env->exception_index) { case EXCP_UDEF: @@ -317,8 +643,19 @@ void do_interrupt(CPUARMState *env) /* The PC already points to the next instructon. */ offset = 0; break; - case EXCP_PREFETCH_ABORT: case EXCP_BKPT: + /* See if this is a semihosting syscall. */ + if (env->thumb) { + mask = lduw_code(env->regs[15]) & 0xff; + if (mask == 0xab + && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { + env->regs[15] += 2; + env->regs[0] = do_arm_semihosting(env); + return; + } + } + /* Fall through to prefetch abort. */ + case EXCP_PREFETCH_ABORT: new_mode = ARM_CPU_MODE_ABT; addr = 0x0c; mask = CPSR_A | CPSR_I; @@ -354,6 +691,8 @@ void do_interrupt(CPUARMState *env) } switch_mode (env, new_mode); env->spsr = cpsr_read(env); + /* Clear IT bits. */ + env->condexec_bits = 0; /* Switch to the new mode, and switch to Arm mode. */ /* ??? Thumb interrupt handlers not implemented. */ env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode; @@ -370,9 +709,16 @@ void do_interrupt(CPUARMState *env) static inline int check_ap(CPUState *env, int ap, int domain, int access_type, int is_user) { + int prot_ro; + if (domain == 3) return PAGE_READ | PAGE_WRITE; + if (access_type == 1) + prot_ro = 0; + else + prot_ro = PAGE_READ; + switch (ap) { case 0: if (access_type == 1) @@ -389,18 +735,24 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type, return is_user ? 0 : PAGE_READ | PAGE_WRITE; case 2: if (is_user) - return (access_type == 1) ? 0 : PAGE_READ; + return prot_ro; else return PAGE_READ | PAGE_WRITE; case 3: return PAGE_READ | PAGE_WRITE; + case 4: case 7: /* Reserved. */ + return 0; + case 5: + return is_user ? 0 : prot_ro; + case 6: + return prot_ro; default: abort(); } } -static int get_phys_addr(CPUState *env, uint32_t address, int access_type, - int is_user, uint32_t *phys_ptr, int *prot) +static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) { int code; uint32_t table; @@ -410,145 +762,259 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, int domain; uint32_t phys_addr; - /* Fast Context Switch Extension. */ - if (address < 0x02000000) - address += env->cp15.c13_fcse; - - if ((env->cp15.c1_sys & 1) == 0) { - /* MMU/MPU disabled. */ - *phys_ptr = address; - *prot = PAGE_READ | PAGE_WRITE; - } else if (arm_feature(env, ARM_FEATURE_MPU)) { - int n; - uint32_t mask; - uint32_t base; - - *phys_ptr = address; - for (n = 7; n >= 0; n--) { - base = env->cp15.c6_region[n]; - if ((base & 1) == 0) - continue; - mask = 1 << ((base >> 1) & 0x1f); - /* Keep this shift separate from the above to avoid an - (undefined) << 32. */ - mask = (mask << 1) - 1; - if (((base ^ address) & ~mask) == 0) - break; - } - if (n < 0) - return 2; - - if (access_type == 2) { - mask = env->cp15.c5_insn; - } else { - mask = env->cp15.c5_data; - } - mask = (mask >> (n * 4)) & 0xf; - switch (mask) { - case 0: - return 1; - case 1: - if (is_user) - return 1; - *prot = PAGE_READ | PAGE_WRITE; - break; - case 2: - *prot = PAGE_READ; - if (!is_user) - *prot |= PAGE_WRITE; + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + if (address & env->cp15.c2_mask) + table = env->cp15.c2_base1; + else + table = env->cp15.c2_base0; + table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc); + desc = ldl_phys(table); + type = (desc & 3); + domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; + if (type == 0) { + /* Secton translation fault. */ + code = 5; + goto do_fault; + } + if (domain == 0 || domain == 2) { + if (type == 2) + code = 9; /* Section domain fault. */ + else + code = 11; /* Page domain fault. */ + goto do_fault; + } + if (type == 2) { + /* 1Mb section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); + ap = (desc >> 10) & 3; + code = 13; + } else { + /* Lookup l2 entry. */ + if (type == 1) { + /* Coarse pagetable. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + } else { + /* Fine pagetable. */ + table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); + } + desc = ldl_phys(table); + switch (desc & 3) { + case 0: /* Page translation fault. */ + code = 7; + goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; break; - case 3: - *prot = PAGE_READ | PAGE_WRITE; + case 2: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + ap = (desc >> (4 + ((address >> 13) & 6))) & 3; break; - case 5: - if (is_user) - return 1; - *prot = PAGE_READ; - break; - case 6: - *prot = PAGE_READ; + case 3: /* 1k page. */ + if (type == 1) { + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + } else { + /* Page translation fault. */ + code = 7; + goto do_fault; + } + } else { + phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); + } + ap = (desc >> 4) & 3; break; default: - /* Bad permission. */ - return 1; + /* Never happens, but compiler isn't smart enough to tell. */ + abort(); } + code = 15; + } + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; + } + *phys_ptr = phys_addr; + return 0; +do_fault: + return code | (domain << 4); +} + +static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int code; + uint32_t table; + uint32_t desc; + uint32_t xn; + int type; + int ap; + int domain; + uint32_t phys_addr; + + /* Pagetable walk. */ + /* Lookup l1 descriptor. */ + if (address & env->cp15.c2_mask) + table = env->cp15.c2_base1; + else + table = env->cp15.c2_base0; + table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc); + desc = ldl_phys(table); + type = (desc & 3); + if (type == 0) { + /* Secton translation fault. */ + code = 5; + domain = 0; + goto do_fault; + } else if (type == 2 && (desc & (1 << 18))) { + /* Supersection. */ + domain = 0; } else { - /* Pagetable walk. */ - /* Lookup l1 descriptor. */ - table = (env->cp15.c2_base & 0xffffc000) | ((address >> 18) & 0x3ffc); - desc = ldl_phys(table); - type = (desc & 3); - domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; - if (type == 0) { - /* Secton translation fault. */ - code = 5; - goto do_fault; - } - if (domain == 0 || domain == 2) { - if (type == 2) - code = 9; /* Section domain fault. */ - else - code = 11; /* Page domain fault. */ - goto do_fault; - } - if (type == 2) { - /* 1Mb section. */ - phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); - ap = (desc >> 10) & 3; - code = 13; + /* Section or page. */ + domain = (desc >> 4) & 0x1e; + } + domain = (env->cp15.c3 >> domain) & 3; + if (domain == 0 || domain == 2) { + if (type == 2) + code = 9; /* Section domain fault. */ + else + code = 11; /* Page domain fault. */ + goto do_fault; + } + if (type == 2) { + if (desc & (1 << 18)) { + /* Supersection. */ + phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); } else { - /* Lookup l2 entry. */ - if (type == 1) { - /* Coarse pagetable. */ - table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - } else { - /* Fine pagetable. */ - table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); - } - desc = ldl_phys(table); - switch (desc & 3) { - case 0: /* Page translation fault. */ - code = 7; - goto do_fault; - case 1: /* 64k page. */ - phys_addr = (desc & 0xffff0000) | (address & 0xffff); - ap = (desc >> (4 + ((address >> 13) & 6))) & 3; - break; - case 2: /* 4k page. */ - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - ap = (desc >> (4 + ((address >> 13) & 6))) & 3; - break; - case 3: /* 1k page. */ - if (type == 1) { - if (arm_feature(env, ARM_FEATURE_XSCALE)) - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - else { - /* Page translation fault. */ - code = 7; - goto do_fault; - } - } else - phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); - ap = (desc >> 4) & 3; - break; - default: - /* Never happens, but compiler isn't smart enough to tell. */ - abort(); - } - code = 15; + /* Section. */ + phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); } - *prot = check_ap(env, ap, domain, access_type, is_user); - if (!*prot) { - /* Access permission fault. */ + ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); + xn = desc & (1 << 4); + code = 13; + } else { + /* Lookup l2 entry. */ + table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); + desc = ldl_phys(table); + ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); + switch (desc & 3) { + case 0: /* Page translation fault. */ + code = 7; goto do_fault; + case 1: /* 64k page. */ + phys_addr = (desc & 0xffff0000) | (address & 0xffff); + xn = desc & (1 << 15); + break; + case 2: case 3: /* 4k page. */ + phys_addr = (desc & 0xfffff000) | (address & 0xfff); + xn = desc & 1; + break; + default: + /* Never happens, but compiler isn't smart enough to tell. */ + abort(); } - *phys_ptr = phys_addr; + code = 15; + } + if (xn && access_type == 2) + goto do_fault; + + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; } + *phys_ptr = phys_addr; return 0; do_fault: return code | (domain << 4); } +static int get_phys_addr_mpu(CPUState *env, uint32_t address, int access_type, + int is_user, uint32_t *phys_ptr, int *prot) +{ + int n; + uint32_t mask; + uint32_t base; + + *phys_ptr = address; + for (n = 7; n >= 0; n--) { + base = env->cp15.c6_region[n]; + if ((base & 1) == 0) + continue; + mask = 1 << ((base >> 1) & 0x1f); + /* Keep this shift separate from the above to avoid an + (undefined) << 32. */ + mask = (mask << 1) - 1; + if (((base ^ address) & ~mask) == 0) + break; + } + if (n < 0) + return 2; + + if (access_type == 2) { + mask = env->cp15.c5_insn; + } else { + mask = env->cp15.c5_data; + } + mask = (mask >> (n * 4)) & 0xf; + switch (mask) { + case 0: + return 1; + case 1: + if (is_user) + return 1; + *prot = PAGE_READ | PAGE_WRITE; + break; + case 2: + *prot = PAGE_READ; + if (!is_user) + *prot |= PAGE_WRITE; + break; + case 3: + *prot = PAGE_READ | PAGE_WRITE; + break; + case 5: + if (is_user) + return 1; + *prot = PAGE_READ; + break; + case 6: + *prot = PAGE_READ; + break; + default: + /* Bad permission. */ + return 1; + } + return 0; +} + +static inline int get_phys_addr(CPUState *env, uint32_t address, + int access_type, int is_user, + uint32_t *phys_ptr, int *prot) +{ + /* Fast Context Switch Extension. */ + if (address < 0x02000000) + address += env->cp15.c13_fcse; + + if ((env->cp15.c1_sys & 1) == 0) { + /* MMU/MPU disabled. */ + *phys_ptr = address; + *prot = PAGE_READ | PAGE_WRITE; + return 0; + } else if (arm_feature(env, ARM_FEATURE_MPU)) { + return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr, + prot); + } else if (env->cp15.c1_sys & (1 << 23)) { + return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr, + prot); + } else { + return get_phys_addr_v5(env, address, access_type, is_user, phys_ptr, + prot); + } +} + int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int access_type, int mmu_idx, int is_softmmu) { @@ -572,6 +1038,8 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, env->exception_index = EXCP_PREFETCH_ABORT; } else { env->cp15.c5_data = ret; + if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6)) + env->cp15.c5_data |= (1 << 11); env->cp15.c6_data = address; env->exception_index = EXCP_DATA_ABORT; } @@ -592,6 +1060,24 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return phys_addr; } +/* Not really implemented. Need to figure out a sane way of doing this. + Maybe add generic watchpoint support and use that. */ + +void helper_mark_exclusive(CPUState *env, uint32_t addr) +{ + env->mmon_addr = addr; +} + +int helper_test_exclusive(CPUState *env, uint32_t addr) +{ + return (env->mmon_addr != addr); +} + +void helper_clrex(CPUState *env) +{ + env->mmon_addr = -1; +} + void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val) { int cp_num = (insn >> 8) & 0xf; @@ -649,13 +1135,20 @@ static uint32_t extended_mpu_ap_bits(uint32_t val) void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) { - uint32_t op2; - uint32_t crm; + int op1; + int op2; + int crm; + op1 = (insn >> 21) & 7; op2 = (insn >> 5) & 7; crm = insn & 0xf; switch ((insn >> 16) & 0xf) { - case 0: /* ID codes. */ + case 0: + if (((insn >> 21) & 7) == 2) { + /* ??? Select cache level. Ignore. */ + return; + } + /* ID codes. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) break; if (arm_feature(env, ARM_FEATURE_OMAPCP)) @@ -672,12 +1165,13 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) /* This may enable/disable the MMU, so do a TLB flush. */ tlb_flush(env, 1); break; - case 1: + case 1: /* Auxiliary cotrol register. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { env->cp15.c1_xscaleauxcr = val; break; } - goto bad_reg; + /* Not implemented. */ + break; case 2: if (arm_feature(env, ARM_FEATURE_XSCALE)) goto bad_reg; @@ -702,7 +1196,19 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) goto bad_reg; } } else { - env->cp15.c2_base = val; + switch (op2) { + case 0: + env->cp15.c2_base0 = val; + break; + case 1: + env->cp15.c2_base1 = val; + break; + case 2: + env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val); + break; + default: + goto bad_reg; + } } break; case 3: /* MMU Domain access control / MPU write buffer control. */ @@ -751,7 +1257,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) case 0: env->cp15.c6_data = val; break; - case 1: + case 1: /* ??? This is WFAR on armv6 */ + case 2: env->cp15.c6_insn = val; break; default: @@ -763,6 +1270,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) env->cp15.c15_i_max = 0x000; env->cp15.c15_i_min = 0xff0; /* No cache, so nothing to do. */ + /* ??? MPCore has VA to PA translation functions. */ break; case 8: /* MMU TLB control. */ switch (op2) { @@ -783,6 +1291,13 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) tlb_flush(env, 1); #endif break; + case 2: /* Invalidate on ASID. */ + tlb_flush(env, val == 0); + break; + case 3: /* Invalidate single entry on MVA. */ + /* ??? This is like case 1, but ignores ASID. */ + tlb_flush(env, 1); + break; default: goto bad_reg; } @@ -792,17 +1307,26 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) break; switch (crm) { case 0: /* Cache lockdown. */ - switch (op2) { - case 0: - env->cp15.c9_data = val; - break; - case 1: - env->cp15.c9_insn = val; - break; - default: - goto bad_reg; - } - break; + switch (op1) { + case 0: /* L1 cache. */ + switch (op2) { + case 0: + env->cp15.c9_data = val; + break; + case 1: + env->cp15.c9_insn = val; + break; + default: + goto bad_reg; + } + break; + case 1: /* L2 cache. */ + /* Ignore writes to L2 lockdown/auxiliary registers. */ + break; + default: + goto bad_reg; + } + break; case 1: /* TCM memory region registers. */ /* Not implemented. */ goto bad_reg; @@ -832,6 +1356,15 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) tlb_flush(env, 0); env->cp15.c13_context = val; break; + case 2: + env->cp15.c13_tls1 = val; + break; + case 3: + env->cp15.c13_tls2 = val; + break; + case 4: + env->cp15.c13_tls3 = val; + break; default: goto bad_reg; } @@ -880,27 +1413,64 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val) return; bad_reg: /* ??? For debugging only. Should raise illegal instruction exception. */ - cpu_abort(env, "Unimplemented cp15 register write\n"); + cpu_abort(env, "Unimplemented cp15 register write (c%d, c%d, {%d, %d})\n", + (insn >> 16) & 0xf, crm, op1, op2); } uint32_t helper_get_cp15(CPUState *env, uint32_t insn) { - uint32_t op2; - uint32_t crm; + int op1; + int op2; + int crm; + op1 = (insn >> 21) & 7; op2 = (insn >> 5) & 7; crm = insn & 0xf; switch ((insn >> 16) & 0xf) { case 0: /* ID codes. */ - switch (op2) { - default: /* Device ID. */ - return env->cp15.c0_cpuid; - case 1: /* Cache Type. */ - return env->cp15.c0_cachetype; - case 2: /* TCM status. */ + switch (op1) { + case 0: + switch (crm) { + case 0: + switch (op2) { + case 0: /* Device ID. */ + return env->cp15.c0_cpuid; + case 1: /* Cache Type. */ + return env->cp15.c0_cachetype; + case 2: /* TCM status. */ + return 0; + case 3: /* TLB type register. */ + return 0; /* No lockable TLB entries. */ + case 5: /* CPU ID */ + return env->cpu_index; + default: + goto bad_reg; + } + case 1: + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + return env->cp15.c0_c1[op2]; + case 2: + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + return env->cp15.c0_c2[op2]; + case 3: case 4: case 5: case 6: case 7: + return 0; + default: + goto bad_reg; + } + case 1: + /* These registers aren't documented on arm11 cores. However + Linux looks at them anyway. */ + if (!arm_feature(env, ARM_FEATURE_V6)) + goto bad_reg; + if (crm != 0) + goto bad_reg; if (arm_feature(env, ARM_FEATURE_XSCALE)) goto bad_reg; return 0; + default: + goto bad_reg; } case 1: /* System configuration. */ if (arm_feature(env, ARM_FEATURE_OMAPCP)) @@ -909,11 +1479,22 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 0: /* Control register. */ return env->cp15.c1_sys; case 1: /* Auxiliary control register. */ - if (arm_feature(env, ARM_FEATURE_AUXCR)) - return 1; if (arm_feature(env, ARM_FEATURE_XSCALE)) return env->cp15.c1_xscaleauxcr; - goto bad_reg; + if (!arm_feature(env, ARM_FEATURE_AUXCR)) + goto bad_reg; + switch (ARM_CPUID(env)) { + case ARM_CPUID_ARM1026: + return 1; + case ARM_CPUID_ARM1136: + return 7; + case ARM_CPUID_ARM11MPCORE: + return 1; + case ARM_CPUID_CORTEXA8: + return 0; + default: + goto bad_reg; + } case 2: /* Coprocessor access register. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) goto bad_reg; @@ -934,8 +1515,27 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) goto bad_reg; } } else { - return env->cp15.c2_base; - } + switch (op2) { + case 0: + return env->cp15.c2_base0; + case 1: + return env->cp15.c2_base1; + case 2: + { + int n; + uint32_t mask; + n = 0; + mask = env->cp15.c2_mask; + while (mask) { + n++; + mask <<= 1; + } + return n; + } + default: + goto bad_reg; + } + } case 3: /* MMU Domain access control / MPU write buffer control. */ return env->cp15.c3; case 4: /* Reserved. */ @@ -963,26 +1563,37 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) default: goto bad_reg; } - case 6: /* MMU Fault address / MPU base/size. */ + case 6: /* MMU Fault address. */ if (arm_feature(env, ARM_FEATURE_MPU)) { - int n; - n = (insn & 0xf); - if (n >= 8) + if (crm >= 8) goto bad_reg; - return env->cp15.c6_region[n]; + return env->cp15.c6_region[crm]; } else { if (arm_feature(env, ARM_FEATURE_OMAPCP)) op2 = 0; - switch (op2) { - case 0: - return env->cp15.c6_data; - case 1: - /* Arm9 doesn't have an IFAR, but implementing it anyway - shouldn't do any harm. */ - return env->cp15.c6_insn; - default: - goto bad_reg; - } + switch (op2) { + case 0: + return env->cp15.c6_data; + case 1: + if (arm_feature(env, ARM_FEATURE_V6)) { + /* Watchpoint Fault Adrress. */ + return 0; /* Not implemented. */ + } else { + /* Instruction Fault Adrress. */ + /* Arm9 doesn't have an IFAR, but implementing it anyway + shouldn't do any harm. */ + return env->cp15.c6_insn; + } + case 2: + if (arm_feature(env, ARM_FEATURE_V6)) { + /* Instruction Fault Adrress. */ + return env->cp15.c6_insn; + } else { + goto bad_reg; + } + default: + goto bad_reg; + } } case 7: /* Cache control. */ /* ??? This is for test, clean and invaidate operations that set the @@ -993,13 +1604,23 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) case 8: /* MMU TLB control. */ goto bad_reg; case 9: /* Cache lockdown. */ - if (arm_feature(env, ARM_FEATURE_OMAPCP)) + switch (op1) { + case 0: /* L1 cache. */ + if (arm_feature(env, ARM_FEATURE_OMAPCP)) + return 0; + switch (op2) { + case 0: + return env->cp15.c9_data; + case 1: + return env->cp15.c9_insn; + default: + goto bad_reg; + } + case 1: /* L2 cache */ + if (crm != 0) + goto bad_reg; + /* L2 Lockdown and Auxiliary control. */ return 0; - switch (op2) { - case 0: - return env->cp15.c9_data; - case 1: - return env->cp15.c9_insn; default: goto bad_reg; } @@ -1015,6 +1636,12 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) return env->cp15.c13_fcse; case 1: return env->cp15.c13_context; + case 2: + return env->cp15.c13_tls1; + case 3: + return env->cp15.c13_tls2; + case 4: + return env->cp15.c13_tls3; default: goto bad_reg; } @@ -1048,10 +1675,125 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn) } bad_reg: /* ??? For debugging only. Should raise illegal instruction exception. */ - cpu_abort(env, "Unimplemented cp15 register read\n"); + cpu_abort(env, "Unimplemented cp15 register read (c%d, c%d, {%d, %d})\n", + (insn >> 16) & 0xf, crm, op1, op2); return 0; } +void helper_set_r13_banked(CPUState *env, int mode, uint32_t val) +{ + env->banked_r13[bank_number(mode)] = val; +} + +uint32_t helper_get_r13_banked(CPUState *env, int mode) +{ + return env->banked_r13[bank_number(mode)]; +} + +uint32_t helper_v7m_mrs(CPUState *env, int reg) +{ + switch (reg) { + case 0: /* APSR */ + return xpsr_read(env) & 0xf8000000; + case 1: /* IAPSR */ + return xpsr_read(env) & 0xf80001ff; + case 2: /* EAPSR */ + return xpsr_read(env) & 0xff00fc00; + case 3: /* xPSR */ + return xpsr_read(env) & 0xff00fdff; + case 5: /* IPSR */ + return xpsr_read(env) & 0x000001ff; + case 6: /* EPSR */ + return xpsr_read(env) & 0x0700fc00; + case 7: /* IEPSR */ + return xpsr_read(env) & 0x0700edff; + case 8: /* MSP */ + return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13]; + case 9: /* PSP */ + return env->v7m.current_sp ? env->regs[13] : env->v7m.other_sp; + case 16: /* PRIMASK */ + return (env->uncached_cpsr & CPSR_I) != 0; + case 17: /* FAULTMASK */ + return (env->uncached_cpsr & CPSR_F) != 0; + case 18: /* BASEPRI */ + case 19: /* BASEPRI_MAX */ + return env->v7m.basepri; + case 20: /* CONTROL */ + return env->v7m.control; + default: + /* ??? For debugging only. */ + cpu_abort(env, "Unimplemented system register read (%d)\n", reg); + return 0; + } +} + +void helper_v7m_msr(CPUState *env, int reg, uint32_t val) +{ + switch (reg) { + case 0: /* APSR */ + xpsr_write(env, val, 0xf8000000); + break; + case 1: /* IAPSR */ + xpsr_write(env, val, 0xf8000000); + break; + case 2: /* EAPSR */ + xpsr_write(env, val, 0xfe00fc00); + break; + case 3: /* xPSR */ + xpsr_write(env, val, 0xfe00fc00); + break; + case 5: /* IPSR */ + /* IPSR bits are readonly. */ + break; + case 6: /* EPSR */ + xpsr_write(env, val, 0x0600fc00); + break; + case 7: /* IEPSR */ + xpsr_write(env, val, 0x0600fc00); + break; + case 8: /* MSP */ + if (env->v7m.current_sp) + env->v7m.other_sp = val; + else + env->regs[13] = val; + break; + case 9: /* PSP */ + if (env->v7m.current_sp) + env->regs[13] = val; + else + env->v7m.other_sp = val; + break; + case 16: /* PRIMASK */ + if (val & 1) + env->uncached_cpsr |= CPSR_I; + else + env->uncached_cpsr &= ~CPSR_I; + break; + case 17: /* FAULTMASK */ + if (val & 1) + env->uncached_cpsr |= CPSR_F; + else + env->uncached_cpsr &= ~CPSR_F; + break; + case 18: /* BASEPRI */ + env->v7m.basepri = val & 0xff; + break; + case 19: /* BASEPRI_MAX */ + val &= 0xff; + if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0)) + env->v7m.basepri = val; + break; + case 20: /* CONTROL */ + env->v7m.control = val & 3; + switch_v7m_sp(env, (val & 2) != 0); + break; + default: + /* ??? For debugging only. */ + cpu_abort(env, "Unimplemented system register write (%d)\n", reg); + return; + } +} + void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write, void *opaque) diff --git a/target-arm/op.c b/target-arm/op.c index e8a536c1a..216944af5 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -2,7 +2,7 @@ * ARM micro operations * * Copyright (c) 2003 Fabrice Bellard - * Copyright (c) 2005 CodeSourcery, LLC + * Copyright (c) 2005-2007 CodeSourcery, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -101,11 +101,6 @@ void OPPROTO op_movl_T0_im(void) T0 = PARAM1; } -void OPPROTO op_movl_T0_T1(void) -{ - T0 = T1; -} - void OPPROTO op_movl_T1_im(void) { T1 = PARAM1; @@ -236,6 +231,11 @@ void OPPROTO op_bicl_T0_T1(void) T0 &= ~T1; } +void OPPROTO op_notl_T0(void) +{ + T0 = ~T0; +} + void OPPROTO op_notl_T1(void) { T1 = ~T1; @@ -351,6 +351,19 @@ void OPPROTO op_test_le(void) FORCE_RET(); } +void OPPROTO op_test_T0(void) +{ + if (T0) + GOTO_LABEL_PARAM(1); + FORCE_RET(); +} +void OPPROTO op_testn_T0(void) +{ + if (!T0) + GOTO_LABEL_PARAM(1); + FORCE_RET(); +} + void OPPROTO op_goto_tb0(void) { GOTO_TB(op_goto_tb0, PARAM1, 0); @@ -368,7 +381,8 @@ void OPPROTO op_exit_tb(void) void OPPROTO op_movl_T0_cpsr(void) { - T0 = cpsr_read(env); + /* Execution state bits always read as zero. */ + T0 = cpsr_read(env) & ~CPSR_EXEC; FORCE_RET(); } @@ -438,6 +452,28 @@ void OPPROTO op_addq_lo_T0_T1(void) T0 = res; } +/* Dual 16-bit accumulate. */ +void OPPROTO op_addq_T0_T1_dual(void) +{ + uint64_t res; + res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); + res += (int32_t)T0; + res += (int32_t)T1; + env->regs[PARAM1] = (uint32_t)res; + env->regs[PARAM2] = res >> 32; +} + +/* Dual 16-bit subtract accumulate. */ +void OPPROTO op_subq_T0_T1_dual(void) +{ + uint64_t res; + res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); + res += (int32_t)T0; + res -= (int32_t)T1; + env->regs[PARAM1] = (uint32_t)res; + env->regs[PARAM2] = res >> 32; +} + void OPPROTO op_logicq_cc(void) { env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); @@ -455,8 +491,21 @@ void OPPROTO op_logicq_cc(void) #include "op_mem.h" #endif +void OPPROTO op_clrex(void) +{ + cpu_lock(); + helper_clrex(env); + cpu_unlock(); +} + /* shifts */ +/* Used by NEON. */ +void OPPROTO op_shll_T0_im(void) +{ + T1 = T1 << PARAM1; +} + /* T1 based */ void OPPROTO op_shll_T1_im(void) @@ -813,8 +862,39 @@ void OPPROTO op_double_T1_saturate(void) FORCE_RET(); } -/* thumb shift by immediate */ -void OPPROTO op_shll_T0_im_thumb(void) +/* Unsigned saturating arithmetic for NEON. */ +void OPPROTO op_addl_T0_T1_usaturate(void) +{ + uint32_t res; + + res = T0 + T1; + if (res < T0) { + env->QF = 1; + T0 = 0xffffffff; + } else { + T0 = res; + } + + FORCE_RET(); +} + +void OPPROTO op_subl_T0_T1_usaturate(void) +{ + uint32_t res; + + res = T0 - T1; + if (res > T0) { + env->QF = 1; + T0 = 0; + } else { + T0 = res; + } + + FORCE_RET(); +} + +/* Thumb shift by immediate */ +void OPPROTO op_shll_T0_im_thumb_cc(void) { int shift; shift = PARAM1; @@ -826,7 +906,13 @@ void OPPROTO op_shll_T0_im_thumb(void) FORCE_RET(); } -void OPPROTO op_shrl_T0_im_thumb(void) +void OPPROTO op_shll_T0_im_thumb(void) +{ + T0 = T0 << PARAM1; + FORCE_RET(); +} + +void OPPROTO op_shrl_T0_im_thumb_cc(void) { int shift; @@ -842,7 +928,20 @@ void OPPROTO op_shrl_T0_im_thumb(void) FORCE_RET(); } -void OPPROTO op_sarl_T0_im_thumb(void) +void OPPROTO op_shrl_T0_im_thumb(void) +{ + int shift; + + shift = PARAM1; + if (shift == 0) { + T0 = 0; + } else { + T0 = T0 >> shift; + } + FORCE_RET(); +} + +void OPPROTO op_sarl_T0_im_thumb_cc(void) { int shift; @@ -858,6 +957,19 @@ void OPPROTO op_sarl_T0_im_thumb(void) FORCE_RET(); } +void OPPROTO op_sarl_T0_im_thumb(void) +{ + int shift; + + shift = PARAM1; + if (shift == 0) { + env->CF = T0 & 1; + } else { + T0 = ((int32_t)T0) >> shift; + } + FORCE_RET(); +} + /* exceptions */ void OPPROTO op_swi(void) @@ -891,6 +1003,12 @@ void OPPROTO op_bkpt(void) cpu_loop_exit(); } +void OPPROTO op_exception_exit(void) +{ + env->exception_index = EXCP_EXCEPTION_EXIT; + cpu_loop_exit(); +} + /* VFP support. We follow the convention used for VFP instrunctions: Single precition routines have a "s" suffix, double precision a "d" suffix. */ @@ -982,6 +1100,28 @@ static inline uint32_t vfp_stoi(float32 s) return v.i; } +static inline float64 vfp_itod(uint64_t i) +{ + union { + uint64_t i; + float64 d; + } v; + + v.i = i; + return v.d; +} + +static inline uint64_t vfp_dtoi(float64 d) +{ + union { + uint64_t i; + float64 d; + } v; + + v.d = d; + return v.i; +} + /* Integer to float conversion. */ VFP_OP(uito, s) { @@ -1056,6 +1196,32 @@ VFP_OP(fcvts, d) FT0s = float64_to_float32(FT0d, &env->vfp.fp_status); } +/* VFP3 fixed point conversion. */ +#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ +VFP_OP(name##to, p) \ +{ \ + ftype tmp; \ + tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(FT0##p), \ + &env->vfp.fp_status); \ + FT0##p = ftype##_scalbn(tmp, PARAM1, &env->vfp.fp_status); \ +} \ +VFP_OP(to##name, p) \ +{ \ + ftype tmp; \ + tmp = ftype##_scalbn(FT0##p, PARAM1, &env->vfp.fp_status); \ + FT0##p = vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ + &env->vfp.fp_status)); \ +} + +VFP_CONV_FIX(sh, d, float64, int16, ) +VFP_CONV_FIX(sl, d, float64, int32, ) +VFP_CONV_FIX(uh, d, float64, uint16, u) +VFP_CONV_FIX(ul, d, float64, uint32, u) +VFP_CONV_FIX(sh, s, float32, int16, ) +VFP_CONV_FIX(sl, s, float32, int32, ) +VFP_CONV_FIX(uh, s, float32, uint16, u) +VFP_CONV_FIX(ul, s, float32, uint32, u) + /* Get and Put values from registers. */ VFP_OP(getreg_F0, d) { @@ -1142,6 +1308,20 @@ void OPPROTO op_vfp_mdrr(void) FT0d = u.d; } +/* Load immediate. PARAM1 is the 32 most significant bits of the value. */ +void OPPROTO op_vfp_fconstd(void) +{ + CPU_DoubleU u; + u.l.upper = PARAM1; + u.l.lower = 0; + FT0d = u.d; +} + +void OPPROTO op_vfp_fconsts(void) +{ + FT0s = vfp_itos(PARAM1); +} + /* Copy the most significant bit of T0 to all bits of T1. */ void OPPROTO op_signbit_T1_T0(void) { @@ -1204,9 +1384,9 @@ void OPPROTO op_movl_user_T0(void) FORCE_RET(); } -void OPPROTO op_movl_T2_T0(void) +void OPPROTO op_movl_T0_T1(void) { - T2 = T0; + T0 = T1; } void OPPROTO op_movl_T0_T2(void) @@ -1214,5 +1394,530 @@ void OPPROTO op_movl_T0_T2(void) T0 = T2; } +void OPPROTO op_movl_T1_T0(void) +{ + T1 = T0; +} + +void OPPROTO op_movl_T1_T2(void) +{ + T1 = T2; +} + +void OPPROTO op_movl_T2_T0(void) +{ + T2 = T0; +} + +/* ARMv6 Media instructions. */ + +/* Note that signed overflow is undefined in C. The following routines are + careful to use unsigned types where modulo arithmetic is required. + Failure to do so _will_ break on newer gcc. */ + +/* Signed saturating arithmetic. */ + +/* Perform 16-bit signed satruating addition. */ +static inline uint16_t add16_sat(uint16_t a, uint16_t b) +{ + uint16_t res; + + res = a + b; + if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) { + if (a & 0x8000) + res = 0x8000; + else + res = 0x7fff; + } + return res; +} + +/* Perform 8-bit signed satruating addition. */ +static inline uint8_t add8_sat(uint8_t a, uint8_t b) +{ + uint8_t res; + + res = a + b; + if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) { + if (a & 0x80) + res = 0x80; + else + res = 0x7f; + } + return res; +} + +/* Perform 16-bit signed satruating subtraction. */ +static inline uint16_t sub16_sat(uint16_t a, uint16_t b) +{ + uint16_t res; + + res = a - b; + if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) { + if (a & 0x8000) + res = 0x8000; + else + res = 0x7fff; + } + return res; +} + +/* Perform 8-bit signed satruating subtraction. */ +static inline uint8_t sub8_sat(uint8_t a, uint8_t b) +{ + uint8_t res; + + res = a - b; + if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) { + if (a & 0x80) + res = 0x80; + else + res = 0x7f; + } + return res; +} + +#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16); +#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16); +#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8); +#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8); +#define PFX q + +#include "op_addsub.h" + +/* Unsigned saturating arithmetic. */ +static inline uint16_t add16_usat(uint16_t a, uint8_t b) +{ + uint16_t res; + res = a + b; + if (res < a) + res = 0xffff; + return res; +} + +static inline uint16_t sub16_usat(uint16_t a, uint8_t b) +{ + if (a < b) + return a - b; + else + return 0; +} + +static inline uint8_t add8_usat(uint8_t a, uint8_t b) +{ + uint8_t res; + res = a + b; + if (res < a) + res = 0xff; + return res; +} + +static inline uint8_t sub8_usat(uint8_t a, uint8_t b) +{ + if (a < b) + return a - b; + else + return 0; +} + +#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16); +#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16); +#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8); +#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8); +#define PFX uq + +#include "op_addsub.h" + +/* Signed modulo arithmetic. */ +#define SARITH16(a, b, n, op) do { \ + int32_t sum; \ + sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \ + RESULT(sum, n, 16); \ + if (sum >= 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SARITH8(a, b, n, op) do { \ + int32_t sum; \ + sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \ + RESULT(sum, n, 8); \ + if (sum >= 0) \ + ge |= 1 << n; \ + } while(0) + + +#define ADD16(a, b, n) SARITH16(a, b, n, +) +#define SUB16(a, b, n) SARITH16(a, b, n, -) +#define ADD8(a, b, n) SARITH8(a, b, n, +) +#define SUB8(a, b, n) SARITH8(a, b, n, -) +#define PFX s +#define ARITH_GE + +#include "op_addsub.h" + +/* Unsigned modulo arithmetic. */ +#define ADD16(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \ + RESULT(sum, n, 16); \ + if ((sum >> 16) == 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define ADD8(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \ + RESULT(sum, n, 8); \ + if ((sum >> 8) == 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SUB16(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \ + RESULT(sum, n, 16); \ + if ((sum >> 16) == 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define SUB8(a, b, n) do { \ + uint32_t sum; \ + sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \ + RESULT(sum, n, 8); \ + if ((sum >> 8) == 0) \ + ge |= 3 << (n * 2); \ + } while(0) + +#define PFX u +#define ARITH_GE + +#include "op_addsub.h" + +/* Halved signed arithmetic. */ +#define ADD16(a, b, n) \ + RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16) +#define SUB16(a, b, n) \ + RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16) +#define ADD8(a, b, n) \ + RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8) +#define SUB8(a, b, n) \ + RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8) +#define PFX sh + +#include "op_addsub.h" + +/* Halved unsigned arithmetic. */ +#define ADD16(a, b, n) \ + RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16) +#define SUB16(a, b, n) \ + RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16) +#define ADD8(a, b, n) \ + RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8) +#define SUB8(a, b, n) \ + RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8) +#define PFX uh + +#include "op_addsub.h" + +void OPPROTO op_pkhtb_T0_T1(void) +{ + T0 = (T0 & 0xffff0000) | (T1 & 0xffff); +} + +void OPPROTO op_pkhbt_T0_T1(void) +{ + T0 = (T0 & 0xffff) | (T1 & 0xffff0000); +} +void OPPROTO op_rev_T0(void) +{ + T0 = ((T0 & 0xff000000) >> 24) + | ((T0 & 0x00ff0000) >> 8) + | ((T0 & 0x0000ff00) << 8) + | ((T0 & 0x000000ff) << 24); +} + +void OPPROTO op_revh_T0(void) +{ + T0 = (T0 >> 16) | (T0 << 16); +} + +void OPPROTO op_rev16_T0(void) +{ + T0 = ((T0 & 0xff000000) >> 8) + | ((T0 & 0x00ff0000) << 8) + | ((T0 & 0x0000ff00) >> 8) + | ((T0 & 0x000000ff) << 8); +} + +void OPPROTO op_revsh_T0(void) +{ + T0 = (int16_t)( ((T0 & 0x0000ff00) >> 8) + | ((T0 & 0x000000ff) << 8)); +} + +void OPPROTO op_rbit_T0(void) +{ + T0 = ((T0 & 0xff000000) >> 24) + | ((T0 & 0x00ff0000) >> 8) + | ((T0 & 0x0000ff00) << 8) + | ((T0 & 0x000000ff) << 24); + T0 = ((T0 & 0xf0f0f0f0) >> 4) + | ((T0 & 0x0f0f0f0f) << 4); + T0 = ((T0 & 0x88888888) >> 3) + | ((T0 & 0x44444444) >> 1) + | ((T0 & 0x22222222) << 1) + | ((T0 & 0x11111111) << 3); +} + +/* Swap low and high halfwords. */ +void OPPROTO op_swap_half_T1(void) +{ + T1 = (T1 >> 16) | (T1 << 16); + FORCE_RET(); +} + +/* Dual 16-bit signed multiply. */ +void OPPROTO op_mul_dual_T0_T1(void) +{ + int32_t low; + int32_t high; + low = (int32_t)(int16_t)T0 * (int32_t)(int16_t)T1; + high = (((int32_t)T0) >> 16) * (((int32_t)T1) >> 16); + T0 = low; + T1 = high; +} + +void OPPROTO op_sel_T0_T1(void) +{ + uint32_t mask; + uint32_t flags; + + flags = env->GE; + mask = 0; + if (flags & 1) + mask |= 0xff; + if (flags & 2) + mask |= 0xff00; + if (flags & 4) + mask |= 0xff0000; + if (flags & 8) + mask |= 0xff000000; + T0 = (T0 & mask) | (T1 & ~mask); + FORCE_RET(); +} + +void OPPROTO op_roundqd_T0_T1(void) +{ + T0 = T1 + ((uint32_t)T0 >> 31); +} + +/* Signed saturation. */ +static inline uint32_t do_ssat(int32_t val, int shift) +{ + int32_t top; + uint32_t mask; + + shift = PARAM1; + top = val >> shift; + mask = (1u << shift) - 1; + if (top > 0) { + env->QF = 1; + return mask; + } else if (top < -1) { + env->QF = 1; + return ~mask; + } + return val; +} + +/* Unsigned saturation. */ +static inline uint32_t do_usat(int32_t val, int shift) +{ + uint32_t max; + + shift = PARAM1; + max = (1u << shift) - 1; + if (val < 0) { + env->QF = 1; + return 0; + } else if (val > max) { + env->QF = 1; + return max; + } + return val; +} + +/* Signed saturate. */ +void OPPROTO op_ssat_T1(void) +{ + T0 = do_ssat(T0, PARAM1); + FORCE_RET(); +} + +/* Dual halfword signed saturate. */ +void OPPROTO op_ssat16_T1(void) +{ + uint32_t res; + + res = (uint16_t)do_ssat((int16_t)T0, PARAM1); + res |= do_ssat(((int32_t)T0) >> 16, PARAM1) << 16; + T0 = res; + FORCE_RET(); +} + +/* Unsigned saturate. */ +void OPPROTO op_usat_T1(void) +{ + T0 = do_usat(T0, PARAM1); + FORCE_RET(); +} + +/* Dual halfword unsigned saturate. */ +void OPPROTO op_usat16_T1(void) +{ + uint32_t res; + + res = (uint16_t)do_usat((int16_t)T0, PARAM1); + res |= do_usat(((int32_t)T0) >> 16, PARAM1) << 16; + T0 = res; + FORCE_RET(); +} + +/* Dual 16-bit add. */ +void OPPROTO op_add16_T1_T2(void) +{ + uint32_t mask; + mask = (T0 & T1) & 0x8000; + T0 ^= ~0x8000; + T1 ^= ~0x8000; + T0 = (T0 + T1) ^ mask; +} + +static inline uint8_t do_usad(uint8_t a, uint8_t b) +{ + if (a > b) + return a - b; + else + return b - a; +} + +/* Unsigned sum of absolute byte differences. */ +void OPPROTO op_usad8_T0_T1(void) +{ + uint32_t sum; + sum = do_usad(T0, T1); + sum += do_usad(T0 >> 8, T1 >> 8); + sum += do_usad(T0 >> 16, T1 >>16); + sum += do_usad(T0 >> 24, T1 >> 24); + T0 = sum; +} + +/* Thumb-2 instructions. */ + +/* Insert T1 into T0. Result goes in T1. */ +void OPPROTO op_bfi_T1_T0(void) +{ + int shift = PARAM1; + uint32_t mask = PARAM2; + uint32_t bits; + + bits = (T1 << shift) & mask; + T1 = (T0 & ~mask) | bits; +} + +/* Unsigned bitfield extract. */ +void OPPROTO op_ubfx_T1(void) +{ + uint32_t shift = PARAM1; + uint32_t mask = PARAM2; + + T1 >>= shift; + T1 &= mask; +} + +/* Signed bitfield extract. */ +void OPPROTO op_sbfx_T1(void) +{ + uint32_t shift = PARAM1; + uint32_t width = PARAM2; + int32_t val; + + val = T1 << (32 - (shift + width)); + T1 = val >> (32 - width); +} + +void OPPROTO op_movtop_T0_im(void) +{ + T0 = (T0 & 0xffff) | PARAM1; +} + +/* Used by table branch instructions. */ +void OPPROTO op_jmp_T0_im(void) +{ + env->regs[15] = PARAM1 + (T0 << 1); +} + +void OPPROTO op_set_condexec(void) +{ + env->condexec_bits = PARAM1; +} + +void OPPROTO op_sdivl_T0_T1(void) +{ + int32_t num; + int32_t den; + num = T0; + den = T1; + if (den == 0) + T0 = 0; + else + T0 = num / den; + FORCE_RET(); +} + +void OPPROTO op_udivl_T0_T1(void) +{ + uint32_t num; + uint32_t den; + num = T0; + den = T1; + if (den == 0) + T0 = 0; + else + T0 = num / den; + FORCE_RET(); +} + +void OPPROTO op_movl_T1_r13_banked(void) +{ + T1 = helper_get_r13_banked(env, PARAM1); +} + +void OPPROTO op_movl_r13_T1_banked(void) +{ + helper_set_r13_banked(env, PARAM1, T1); +} + +void OPPROTO op_v7m_mrs_T0(void) +{ + T0 = helper_v7m_mrs(env, PARAM1); +} + +void OPPROTO op_v7m_msr_T0(void) +{ + helper_v7m_msr(env, PARAM1, T0); +} + +void OPPROTO op_movl_T0_sp(void) +{ + if (PARAM1 == env->v7m.current_sp) + T0 = env->regs[13]; + else + T0 = env->v7m.other_sp; + FORCE_RET(); +} + +#include "op_neon.h" + /* iwMMXt support */ #include "op_iwmmxt.c" diff --git a/target-arm/op_addsub.h b/target-arm/op_addsub.h new file mode 100644 index 000000000..d15360d80 --- /dev/null +++ b/target-arm/op_addsub.h @@ -0,0 +1,106 @@ +/* + * ARMv6 integer SIMD operations. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#ifdef ARITH_GE +#define DECLARE_GE uint32_t ge = 0 +#define SET_GE env->GE = ge +#else +#define DECLARE_GE do{}while(0) +#define SET_GE do{}while(0) +#endif + +#define RESULT(val, n, width) \ + res |= ((uint32_t)(glue(glue(uint,width),_t))(val)) << (n * width) + +void OPPROTO glue(glue(op_,PFX),add16_T0_T1)(void) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD16(T0, T1, 0); + ADD16(T0 >> 16, T1 >> 16, 1); + SET_GE; + T0 = res; + FORCE_RET(); +} + +void OPPROTO glue(glue(op_,PFX),add8_T0_T1)(void) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD8(T0, T1, 0); + ADD8(T0 >> 8, T1 >> 8, 1); + ADD8(T0 >> 16, T1 >> 16, 2); + ADD8(T0 >> 24, T1 >> 24, 3); + SET_GE; + T0 = res; + FORCE_RET(); +} + +void OPPROTO glue(glue(op_,PFX),sub16_T0_T1)(void) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB16(T0, T1, 0); + SUB16(T0 >> 16, T1 >> 16, 1); + SET_GE; + T0 = res; + FORCE_RET(); +} + +void OPPROTO glue(glue(op_,PFX),sub8_T0_T1)(void) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB8(T0, T1, 0); + SUB8(T0 >> 8, T1 >> 8, 1); + SUB8(T0 >> 16, T1 >> 16, 2); + SUB8(T0 >> 24, T1 >> 24, 3); + SET_GE; + T0 = res; + FORCE_RET(); +} + +void OPPROTO glue(glue(op_,PFX),subaddx_T0_T1)(void) +{ + uint32_t res = 0; + DECLARE_GE; + + ADD16(T0, T1, 0); + SUB16(T0 >> 16, T1 >> 16, 1); + SET_GE; + T0 = res; + FORCE_RET(); +} + +void OPPROTO glue(glue(op_,PFX),addsubx_T0_T1)(void) +{ + uint32_t res = 0; + DECLARE_GE; + + SUB16(T0, T1, 0); + ADD16(T0 >> 16, T1 >> 16, 1); + SET_GE; + T0 = res; + FORCE_RET(); +} + +#undef DECLARE_GE +#undef SET_GE +#undef RESULT + +#undef ARITH_GE +#undef PFX +#undef ADD16 +#undef SUB16 +#undef ADD8 +#undef SUB8 diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 6e14a4dff..a9bd95b05 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -1,7 +1,7 @@ /* * ARM helper routines * - * Copyright (c) 2005 CodeSourcery, LLC + * Copyright (c) 2005-2007 CodeSourcery, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -175,6 +175,81 @@ void do_vfp_get_fpscr(void) T0 |= vfp_exceptbits_from_host(i); } +float32 helper_recps_f32(float32 a, float32 b) +{ + float_status *s = &env->vfp.fp_status; + float32 two = int32_to_float32(2, s); + return float32_sub(two, float32_mul(a, b, s), s); +} + +float32 helper_rsqrts_f32(float32 a, float32 b) +{ + float_status *s = &env->vfp.fp_status; + float32 three = int32_to_float32(3, s); + return float32_sub(three, float32_mul(a, b, s), s); +} + +/* TODO: The architecture specifies the value that the estimate functions + should return. We return the exact reciprocal/root instead. */ +float32 helper_recpe_f32(float32 a) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, a, s); +} + +float32 helper_rsqrte_f32(float32 a) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, float32_sqrt(a, s), s); +} + +uint32_t helper_recpe_u32(uint32_t a) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_recpe_f32(tmp); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + +uint32_t helper_rsqrte_u32(uint32_t a) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_rsqrte_f32(tmp); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + +void helper_neon_tbl(int rn, int maxindex) +{ + uint32_t val; + uint32_t mask; + uint32_t tmp; + int index; + int shift; + uint64_t *table; + table = (uint64_t *)&env->vfp.regs[rn]; + val = 0; + mask = 0; + for (shift = 0; shift < 32; shift += 8) { + index = (T1 >> shift) & 0xff; + if (index <= maxindex) { + tmp = (table[index >> 3] >> (index & 7)) & 0xff; + val |= tmp << shift; + } else { + val |= T0 & (0xff << shift); + } + } + T0 = val; +} + #if !defined(CONFIG_USER_ONLY) #define MMUSUFFIX _mmu @@ -227,5 +302,4 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) } env = saved_env; } - #endif diff --git a/target-arm/op_mem.h b/target-arm/op_mem.h index 6bccb0651..b12b63c5f 100644 --- a/target-arm/op_mem.h +++ b/target-arm/op_mem.h @@ -1,5 +1,6 @@ /* ARM memory operations. */ +void helper_ld(uint32_t); /* Load from address T1 into T0. */ #define MEM_LD_OP(name) \ void OPPROTO glue(op_ld##name,MEMSUFFIX)(void) \ @@ -49,6 +50,64 @@ MEM_SWP_OP(l, l) #undef MEM_SWP_OP +/* Load-locked, store exclusive. */ +#define EXCLUSIVE_OP(suffix, ldsuffix) \ +void OPPROTO glue(op_ld##suffix##ex,MEMSUFFIX)(void) \ +{ \ + cpu_lock(); \ + helper_mark_exclusive(env, T1); \ + T0 = glue(ld##ldsuffix,MEMSUFFIX)(T1); \ + cpu_unlock(); \ + FORCE_RET(); \ +} \ + \ +void OPPROTO glue(op_st##suffix##ex,MEMSUFFIX)(void) \ +{ \ + int failed; \ + cpu_lock(); \ + failed = helper_test_exclusive(env, T1); \ + /* ??? Is it safe to hold the cpu lock over a store? */ \ + if (!failed) { \ + glue(st##suffix,MEMSUFFIX)(T1, T0); \ + } \ + T0 = failed; \ + cpu_unlock(); \ + FORCE_RET(); \ +} + +EXCLUSIVE_OP(b, ub) +EXCLUSIVE_OP(w, uw) +EXCLUSIVE_OP(l, l) + +#undef EXCLUSIVE_OP + +/* Load exclusive T0:T1 from address T1. */ +void OPPROTO glue(op_ldqex,MEMSUFFIX)(void) +{ + cpu_lock(); + helper_mark_exclusive(env, T1); + T0 = glue(ldl,MEMSUFFIX)(T1); + T1 = glue(ldl,MEMSUFFIX)((T1 + 4)); + cpu_unlock(); + FORCE_RET(); +} + +/* Store exclusive T0:T2 to address T1. */ +void OPPROTO glue(op_stqex,MEMSUFFIX)(void) +{ + int failed; + cpu_lock(); + failed = helper_test_exclusive(env, T1); + /* ??? Is it safe to hold the cpu lock over a store? */ + if (!failed) { + glue(stl,MEMSUFFIX)(T1, T0); + glue(stl,MEMSUFFIX)((T1 + 4), T2); + } + T0 = failed; + cpu_unlock(); + FORCE_RET(); +} + /* Floating point load/store. Address is in T1 */ #define VFP_MEM_OP(p, w) \ void OPPROTO glue(op_vfp_ld##p,MEMSUFFIX)(void) \ diff --git a/target-arm/op_neon.h b/target-arm/op_neon.h new file mode 100644 index 000000000..232375e18 --- /dev/null +++ b/target-arm/op_neon.h @@ -0,0 +1,1754 @@ +/* + * ARM NEON vector operations. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ +/* Note that for NEON an "l" prefix means it is a wide operation, unlike + scalar arm ops where it means a word size operation. */ + +/* ??? NEON ops should probably have their own float status. */ +#define NFS &env->vfp.fp_status +#define NEON_OP(name) void OPPROTO op_neon_##name (void) + +NEON_OP(getreg_T0) +{ + T0 = *(uint32_t *)((char *) env + PARAM1); +} + +NEON_OP(getreg_T1) +{ + T1 = *(uint32_t *)((char *) env + PARAM1); +} + +NEON_OP(getreg_T2) +{ + T2 = *(uint32_t *)((char *) env + PARAM1); +} + +NEON_OP(setreg_T0) +{ + *(uint32_t *)((char *) env + PARAM1) = T0; +} + +NEON_OP(setreg_T1) +{ + *(uint32_t *)((char *) env + PARAM1) = T1; +} + +NEON_OP(setreg_T2) +{ + *(uint32_t *)((char *) env + PARAM1) = T2; +} + +#define NEON_TYPE1(name, type) \ +typedef struct \ +{ \ + type v1; \ +} neon_##name; +#ifdef WORDS_BIGENDIAN +#define NEON_TYPE2(name, type) \ +typedef struct \ +{ \ + type v2; \ + type v1; \ +} neon_##name; +#define NEON_TYPE4(name, type) \ +typedef struct \ +{ \ + type v4; \ + type v3; \ + type v2; \ + type v1; \ +} neon_##name; +#else +#define NEON_TYPE2(name, type) \ +typedef struct \ +{ \ + type v1; \ + type v2; \ +} neon_##name; +#define NEON_TYPE4(name, type) \ +typedef struct \ +{ \ + type v1; \ + type v2; \ + type v3; \ + type v4; \ +} neon_##name; +#endif + +NEON_TYPE4(s8, int8_t) +NEON_TYPE4(u8, uint8_t) +NEON_TYPE2(s16, int16_t) +NEON_TYPE2(u16, uint16_t) +NEON_TYPE1(s32, int32_t) +NEON_TYPE1(u32, uint32_t) +#undef NEON_TYPE4 +#undef NEON_TYPE2 +#undef NEON_TYPE1 + +/* Copy from a uint32_t to a vector structure type. */ +#define NEON_UNPACK(vtype, dest, val) do { \ + union { \ + vtype v; \ + uint32_t i; \ + } conv_u; \ + conv_u.i = (val); \ + dest = conv_u.v; \ + } while(0) + +/* Copy from a vector structure type to a uint32_t. */ +#define NEON_PACK(vtype, dest, val) do { \ + union { \ + vtype v; \ + uint32_t i; \ + } conv_u; \ + conv_u.v = (val); \ + dest = conv_u.i; \ + } while(0) + +#define NEON_DO1 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); +#define NEON_DO2 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ + NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); +#define NEON_DO4 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc2.v1); \ + NEON_FN(vdest.v2, vsrc1.v2, vsrc2.v2); \ + NEON_FN(vdest.v3, vsrc1.v3, vsrc2.v3); \ + NEON_FN(vdest.v4, vsrc1.v4, vsrc2.v4); + +#define NEON_VOP(name, vtype, n) \ +NEON_OP(name) \ +{ \ + vtype vsrc1; \ + vtype vsrc2; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, T0); \ + NEON_UNPACK(vtype, vsrc2, T1); \ + NEON_DO##n; \ + NEON_PACK(vtype, T0, vdest); \ + FORCE_RET(); \ +} + +#define NEON_VOP1(name, vtype, n) \ +NEON_OP(name) \ +{ \ + vtype vsrc1; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, T0); \ + NEON_DO##n; \ + NEON_PACK(vtype, T0, vdest); \ + FORCE_RET(); \ +} + +/* Pairwise operations. */ +/* For 32-bit elements each segment only contains a single element, so + the elementwise and pairwise operations are the same. */ +#define NEON_PDO2 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ + NEON_FN(vdest.v2, vsrc2.v1, vsrc2.v2); +#define NEON_PDO4 \ + NEON_FN(vdest.v1, vsrc1.v1, vsrc1.v2); \ + NEON_FN(vdest.v2, vsrc1.v3, vsrc1.v4); \ + NEON_FN(vdest.v3, vsrc2.v1, vsrc2.v2); \ + NEON_FN(vdest.v4, vsrc2.v3, vsrc2.v4); \ + +#define NEON_POP(name, vtype, n) \ +NEON_OP(name) \ +{ \ + vtype vsrc1; \ + vtype vsrc2; \ + vtype vdest; \ + NEON_UNPACK(vtype, vsrc1, T0); \ + NEON_UNPACK(vtype, vsrc2, T1); \ + NEON_PDO##n; \ + NEON_PACK(vtype, T0, vdest); \ + FORCE_RET(); \ +} + +#define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1 +NEON_VOP(hadd_s8, neon_s8, 4) +NEON_VOP(hadd_u8, neon_u8, 4) +NEON_VOP(hadd_s16, neon_s16, 2) +NEON_VOP(hadd_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(hadd_s32) +{ + int32_t src1 = T0; + int32_t src2 = T1; + int32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if (src1 & src2 & 1) + dest++; + T0 = dest; + FORCE_RET(); +} + +NEON_OP(hadd_u32) +{ + uint32_t src1 = T0; + uint32_t src2 = T1; + uint32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if (src1 & src2 & 1) + dest++; + T0 = dest; + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) dest = (src1 + src2 + 1) >> 1 +NEON_VOP(rhadd_s8, neon_s8, 4) +NEON_VOP(rhadd_u8, neon_u8, 4) +NEON_VOP(rhadd_s16, neon_s16, 2) +NEON_VOP(rhadd_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(rhadd_s32) +{ + int32_t src1 = T0; + int32_t src2 = T1; + int32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if ((src1 | src2) & 1) + dest++; + T0 = dest; + FORCE_RET(); +} + +NEON_OP(rhadd_u32) +{ + uint32_t src1 = T0; + uint32_t src2 = T1; + uint32_t dest; + + dest = (src1 >> 1) + (src2 >> 1); + if ((src1 | src2) & 1) + dest++; + T0 = dest; + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) dest = (src1 - src2) >> 1 +NEON_VOP(hsub_s8, neon_s8, 4) +NEON_VOP(hsub_u8, neon_u8, 4) +NEON_VOP(hsub_s16, neon_s16, 2) +NEON_VOP(hsub_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(hsub_s32) +{ + int32_t src1 = T0; + int32_t src2 = T1; + int32_t dest; + + dest = (src1 >> 1) - (src2 >> 1); + if ((~src1) & src2 & 1) + dest--; + T0 = dest; + FORCE_RET(); +} + +NEON_OP(hsub_u32) +{ + uint32_t src1 = T0; + uint32_t src2 = T1; + uint32_t dest; + + dest = (src1 >> 1) - (src2 >> 1); + if ((~src1) & src2 & 1) + dest--; + T0 = dest; + FORCE_RET(); +} + +/* ??? bsl, bif and bit are all the same op, just with the oparands in a + differnet order. It's currently easier to have 3 differnt ops than + rearange the operands. */ + +/* Bitwise Select. */ +NEON_OP(bsl) +{ + T0 = (T0 & T2) | (T1 & ~T2); +} + +/* Bitwise Insert If True. */ +NEON_OP(bit) +{ + T0 = (T0 & T1) | (T2 & ~T1); +} + +/* Bitwise Insert If False. */ +NEON_OP(bif) +{ + T0 = (T2 & T1) | (T0 & ~T1); +} + +#define NEON_USAT(dest, src1, src2, type) do { \ + uint32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + env->QF = 1; \ + dest = ~0; \ + } else { \ + dest = tmp; \ + }} while(0) +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) +NEON_VOP(qadd_u8, neon_u8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) +NEON_VOP(qadd_u16, neon_u16, 2) +#undef NEON_FN +#undef NEON_USAT + +#define NEON_SSAT(dest, src1, src2, type) do { \ + int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + env->QF = 1; \ + if (src2 > 0) { \ + tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ + } else { \ + tmp = 1 << (sizeof(type) * 8 - 1); \ + } \ + } \ + dest = tmp; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) +NEON_VOP(qadd_s8, neon_s8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) +NEON_VOP(qadd_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_SSAT + +#define NEON_USAT(dest, src1, src2, type) do { \ + uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + env->QF = 1; \ + dest = 0; \ + } else { \ + dest = tmp; \ + }} while(0) +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint8_t) +NEON_VOP(qsub_u8, neon_u8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_USAT(dest, src1, src2, uint16_t) +NEON_VOP(qsub_u16, neon_u16, 2) +#undef NEON_FN +#undef NEON_USAT + +#define NEON_SSAT(dest, src1, src2, type) do { \ + int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ + if (tmp != (type)tmp) { \ + env->QF = 1; \ + if (src2 < 0) { \ + tmp = (1 << (sizeof(type) * 8 - 1)) - 1; \ + } else { \ + tmp = 1 << (sizeof(type) * 8 - 1); \ + } \ + } \ + dest = tmp; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int8_t) +NEON_VOP(qsub_s8, neon_s8, 4) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_SSAT(dest, src1, src2, int16_t) +NEON_VOP(qsub_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_SSAT + +#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? ~0 : 0 +NEON_VOP(cgt_s8, neon_s8, 4) +NEON_VOP(cgt_u8, neon_u8, 4) +NEON_VOP(cgt_s16, neon_s16, 2) +NEON_VOP(cgt_u16, neon_u16, 2) +NEON_VOP(cgt_s32, neon_s32, 1) +NEON_VOP(cgt_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 >= src2) ? ~0 : 0 +NEON_VOP(cge_s8, neon_s8, 4) +NEON_VOP(cge_u8, neon_u8, 4) +NEON_VOP(cge_s16, neon_s16, 2) +NEON_VOP(cge_u16, neon_u16, 2) +NEON_VOP(cge_s32, neon_s32, 1) +NEON_VOP(cge_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src2; \ + if (tmp < 0) { \ + dest = src1 >> -tmp; \ + } else { \ + dest = src1 << tmp; \ + }} while (0) +NEON_VOP(shl_s8, neon_s8, 4) +NEON_VOP(shl_u8, neon_u8, 4) +NEON_VOP(shl_s16, neon_s16, 2) +NEON_VOP(shl_u16, neon_u16, 2) +NEON_VOP(shl_s32, neon_s32, 1) +NEON_VOP(shl_u32, neon_u32, 1) +#undef NEON_FN + +NEON_OP(shl_u64) +{ + int8_t shift = T2; + uint64_t val = T0 | ((uint64_t)T1 << 32); + if (shift < 0) { + val >>= -shift; + } else { + val <<= shift; + } + T0 = val; + T1 = val >> 32; + FORCE_RET(); +} + +NEON_OP(shl_s64) +{ + int8_t shift = T2; + int64_t val = T0 | ((uint64_t)T1 << 32); + if (shift < 0) { + val >>= -shift; + } else { + val <<= shift; + } + T0 = val; + T1 = val >> 32; + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src1; \ + if (tmp < 0) { \ + dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src2 << tmp; \ + }} while (0) + +NEON_VOP(rshl_s8, neon_s8, 4) +NEON_VOP(rshl_u8, neon_u8, 4) +NEON_VOP(rshl_s16, neon_s16, 2) +NEON_VOP(rshl_u16, neon_u16, 2) +NEON_VOP(rshl_s32, neon_s32, 1) +NEON_VOP(rshl_u32, neon_u32, 1) +#undef NEON_FN + +NEON_OP(rshl_u64) +{ + int8_t shift = T2; + uint64_t val = T0 | ((uint64_t)T1 << 32); + if (shift < 0) { + val = (val + ((uint64_t)1 << (-1 - shift))) >> -shift; + val >>= -shift; + } else { + val <<= shift; + } + T0 = val; + T1 = val >> 32; + FORCE_RET(); +} + +NEON_OP(rshl_s64) +{ + int8_t shift = T2; + int64_t val = T0 | ((uint64_t)T1 << 32); + if (shift < 0) { + val = (val + ((int64_t)1 << (-1 - shift))) >> -shift; + } else { + val <<= shift; + } + T0 = val; + T1 = val >> 32; + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src1; \ + if (tmp < 0) { \ + dest = src2 >> -tmp; \ + } else { \ + dest = src2 << tmp; \ + if ((dest >> tmp) != src2) { \ + env->QF = 1; \ + dest = ~0; \ + } \ + }} while (0) +NEON_VOP(qshl_s8, neon_s8, 4) +NEON_VOP(qshl_s16, neon_s16, 2) +NEON_VOP(qshl_s32, neon_s32, 1) +#undef NEON_FN + +NEON_OP(qshl_s64) +{ + int8_t shift = T2; + int64_t val = T0 | ((uint64_t)T1 << 32); + if (shift < 0) { + val >>= -shift; + } else { + int64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + env->QF = 1; + val = (tmp >> 63) ^ 0x7fffffffffffffffULL; + } + } + T0 = val; + T1 = val >> 32; + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src1; \ + if (tmp < 0) { \ + dest = src2 >> -tmp; \ + } else { \ + dest = src2 << tmp; \ + if ((dest >> tmp) != src2) { \ + env->QF = 1; \ + dest = src2 >> 31; \ + } \ + }} while (0) +NEON_VOP(qshl_u8, neon_u8, 4) +NEON_VOP(qshl_u16, neon_u16, 2) +NEON_VOP(qshl_u32, neon_u32, 1) +#undef NEON_FN + +NEON_OP(qshl_u64) +{ + int8_t shift = T2; + uint64_t val = T0 | ((uint64_t)T1 << 32); + if (shift < 0) { + val >>= -shift; + } else { + uint64_t tmp = val; + val <<= shift; + if ((val >> shift) != tmp) { + env->QF = 1; + val = ~(uint64_t)0; + } + } + T0 = val; + T1 = val >> 32; + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src1; \ + if (tmp < 0) { \ + dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src2 << tmp; \ + if ((dest >> tmp) != src2) { \ + dest = ~0; \ + } \ + }} while (0) +NEON_VOP(qrshl_s8, neon_s8, 4) +NEON_VOP(qrshl_s16, neon_s16, 2) +NEON_VOP(qrshl_s32, neon_s32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) do { \ + int8_t tmp; \ + tmp = (int8_t)src1; \ + if (tmp < 0) { \ + dest = (src2 + (1 << (-1 - tmp))) >> -tmp; \ + } else { \ + dest = src2 << tmp; \ + if ((dest >> tmp) != src2) { \ + env->QF = 1; \ + dest = src2 >> 31; \ + } \ + }} while (0) +NEON_VOP(qrshl_u8, neon_u8, 4) +NEON_VOP(qrshl_u16, neon_u16, 2) +NEON_VOP(qrshl_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 > src2) ? src1 : src2 +NEON_VOP(max_s8, neon_s8, 4) +NEON_VOP(max_u8, neon_u8, 4) +NEON_VOP(max_s16, neon_s16, 2) +NEON_VOP(max_u16, neon_u16, 2) +NEON_VOP(max_s32, neon_s32, 1) +NEON_VOP(max_u32, neon_u32, 1) +NEON_POP(pmax_s8, neon_s8, 4) +NEON_POP(pmax_u8, neon_u8, 4) +NEON_POP(pmax_s16, neon_s16, 2) +NEON_POP(pmax_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(max_f32) +{ + float32 f0 = vfp_itos(T0); + float32 f1 = vfp_itos(T1); + T0 = (float32_compare_quiet(f0, f1, NFS) == 1) ? T0 : T1; + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) dest = (src1 < src2) ? src1 : src2 +NEON_VOP(min_s8, neon_s8, 4) +NEON_VOP(min_u8, neon_u8, 4) +NEON_VOP(min_s16, neon_s16, 2) +NEON_VOP(min_u16, neon_u16, 2) +NEON_VOP(min_s32, neon_s32, 1) +NEON_VOP(min_u32, neon_u32, 1) +NEON_POP(pmin_s8, neon_s8, 4) +NEON_POP(pmin_u8, neon_u8, 4) +NEON_POP(pmin_s16, neon_s16, 2) +NEON_POP(pmin_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(min_f32) +{ + float32 f0 = vfp_itos(T0); + float32 f1 = vfp_itos(T1); + T0 = (float32_compare_quiet(f0, f1, NFS) == -1) ? T0 : T1; + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) \ + dest = (src1 > src2) ? (src1 - src2) : (src2 - src1) +NEON_VOP(abd_s8, neon_s8, 4) +NEON_VOP(abd_u8, neon_u8, 4) +NEON_VOP(abd_s16, neon_s16, 2) +NEON_VOP(abd_u16, neon_u16, 2) +NEON_VOP(abd_s32, neon_s32, 1) +NEON_VOP(abd_u32, neon_u32, 1) +#undef NEON_FN + +NEON_OP(abd_f32) +{ + float32 f0 = vfp_itos(T0); + float32 f1 = vfp_itos(T1); + T0 = vfp_stoi((float32_compare_quiet(f0, f1, NFS) == 1) + ? float32_sub(f0, f1, NFS) + : float32_sub(f1, f0, NFS)); + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) dest = src1 + src2 +NEON_VOP(add_u8, neon_u8, 4) +NEON_VOP(add_u16, neon_u16, 2) +NEON_POP(padd_u8, neon_u8, 4) +NEON_POP(padd_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(add_f32) +{ + T0 = vfp_stoi(float32_add(vfp_itos(T0), vfp_itos(T1), NFS)); + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) dest = src1 - src2 +NEON_VOP(sub_u8, neon_u8, 4) +NEON_VOP(sub_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(sub_f32) +{ + T0 = vfp_stoi(float32_sub(vfp_itos(T0), vfp_itos(T1), NFS)); + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) dest = src2 - src1 +NEON_VOP(rsb_u8, neon_u8, 4) +NEON_VOP(rsb_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(rsb_f32) +{ + T0 = vfp_stoi(float32_sub(vfp_itos(T1), vfp_itos(T0), NFS)); + FORCE_RET(); +} + +#define NEON_FN(dest, src1, src2) dest = src1 * src2 +NEON_VOP(mul_u8, neon_u8, 4) +NEON_VOP(mul_u16, neon_u16, 2) +#undef NEON_FN + +NEON_OP(mul_f32) +{ + T0 = vfp_stoi(float32_mul(vfp_itos(T0), vfp_itos(T1), NFS)); + FORCE_RET(); +} + +NEON_OP(mul_p8) +{ + T0 = helper_neon_mul_p8(T0, T1); +} + +#define NEON_FN(dest, src1, src2) dest = (src1 & src2) ? -1 : 0 +NEON_VOP(tst_u8, neon_u8, 4) +NEON_VOP(tst_u16, neon_u16, 2) +NEON_VOP(tst_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_FN(dest, src1, src2) dest = (src1 == src2) ? -1 : 0 +NEON_VOP(ceq_u8, neon_u8, 4) +NEON_VOP(ceq_u16, neon_u16, 2) +NEON_VOP(ceq_u32, neon_u32, 1) +#undef NEON_FN + +#define NEON_QDMULH16(dest, src1, src2, round) do { \ + uint32_t tmp = (int32_t)(int16_t) src1 * (int16_t) src2; \ + if ((tmp ^ (tmp << 1)) & SIGNBIT) { \ + env->QF = 1; \ + tmp = (tmp >> 31) ^ ~SIGNBIT; \ + } \ + tmp <<= 1; \ + if (round) { \ + int32_t old = tmp; \ + tmp += 1 << 15; \ + if ((int32_t)tmp < old) { \ + env->QF = 1; \ + tmp = SIGNBIT - 1; \ + } \ + } \ + dest = tmp >> 16; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 0) +NEON_VOP(qdmulh_s16, neon_s16, 2) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_QDMULH16(dest, src1, src2, 1) +NEON_VOP(qrdmulh_s16, neon_s16, 2) +#undef NEON_FN +#undef NEON_QDMULH16 + +#define SIGNBIT64 ((uint64_t)1 << 63) +#define NEON_QDMULH32(dest, src1, src2, round) do { \ + uint64_t tmp = (int64_t)(int32_t) src1 * (int32_t) src2; \ + if ((tmp ^ (tmp << 1)) & SIGNBIT64) { \ + env->QF = 1; \ + tmp = (tmp >> 63) ^ ~SIGNBIT64; \ + } else { \ + tmp <<= 1; \ + } \ + if (round) { \ + int64_t old = tmp; \ + tmp += (int64_t)1 << 31; \ + if ((int64_t)tmp < old) { \ + env->QF = 1; \ + tmp = SIGNBIT64 - 1; \ + } \ + } \ + dest = tmp >> 32; \ + } while(0) +#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 0) +NEON_VOP(qdmulh_s32, neon_s32, 1) +#undef NEON_FN +#define NEON_FN(dest, src1, src2) NEON_QDMULH32(dest, src1, src2, 1) +NEON_VOP(qrdmulh_s32, neon_s32, 1) +#undef NEON_FN +#undef NEON_QDMULH32 + +NEON_OP(recps_f32) +{ + T0 = vfp_stoi(helper_recps_f32(vfp_itos(T0), vfp_itos(T1))); + FORCE_RET(); +} + +NEON_OP(rsqrts_f32) +{ + T0 = vfp_stoi(helper_rsqrts_f32(vfp_itos(T0), vfp_itos(T1))); + FORCE_RET(); +} + +/* Floating point comparisons produce an integer result. */ +#define NEON_VOP_FCMP(name, cmp) \ +NEON_OP(name) \ +{ \ + if (float32_compare_quiet(vfp_itos(T0), vfp_itos(T1), NFS) cmp 0) \ + T0 = -1; \ + else \ + T0 = 0; \ + FORCE_RET(); \ +} + +NEON_VOP_FCMP(ceq_f32, ==) +NEON_VOP_FCMP(cge_f32, >=) +NEON_VOP_FCMP(cgt_f32, >) + +NEON_OP(acge_f32) +{ + float32 f0 = float32_abs(vfp_itos(T0)); + float32 f1 = float32_abs(vfp_itos(T1)); + T0 = (float32_compare_quiet(f0, f1,NFS) >= 0) ? -1 : 0; + FORCE_RET(); +} + +NEON_OP(acgt_f32) +{ + float32 f0 = float32_abs(vfp_itos(T0)); + float32 f1 = float32_abs(vfp_itos(T1)); + T0 = (float32_compare_quiet(f0, f1, NFS) > 0) ? -1 : 0; + FORCE_RET(); +} + +/* Narrowing instructions. The named type is the destination type. */ +NEON_OP(narrow_u8) +{ + T0 = (T0 & 0xff) | ((T0 >> 8) & 0xff00) + | ((T1 << 16) & 0xff0000) | (T1 << 24); + FORCE_RET(); +} + +NEON_OP(narrow_sat_u8) +{ + neon_u16 src; + neon_u8 dest; +#define SAT8(d, s) \ + if (s > 0xff) { \ + d = 0xff; \ + env->QF = 1; \ + } else { \ + d = s; \ + } + + NEON_UNPACK(neon_u16, src, T0); + SAT8(dest.v1, src.v1); + SAT8(dest.v2, src.v2); + NEON_UNPACK(neon_u16, src, T1); + SAT8(dest.v3, src.v1); + SAT8(dest.v4, src.v2); + NEON_PACK(neon_u8, T0, dest); + FORCE_RET(); +#undef SAT8 +} + +NEON_OP(narrow_sat_s8) +{ + neon_s16 src; + neon_s8 dest; +#define SAT8(d, s) \ + if (s != (uint8_t)s) { \ + d = (s >> 15) ^ 0x7f; \ + env->QF = 1; \ + } else { \ + d = s; \ + } + + NEON_UNPACK(neon_s16, src, T0); + SAT8(dest.v1, src.v1); + SAT8(dest.v2, src.v2); + NEON_UNPACK(neon_s16, src, T1); + SAT8(dest.v3, src.v1); + SAT8(dest.v4, src.v2); + NEON_PACK(neon_s8, T0, dest); + FORCE_RET(); +#undef SAT8 +} + +NEON_OP(narrow_u16) +{ + T0 = (T0 & 0xffff) | (T1 << 16); +} + +NEON_OP(narrow_sat_u16) +{ + if (T0 > 0xffff) { + T0 = 0xffff; + env->QF = 1; + } + if (T1 > 0xffff) { + T1 = 0xffff; + env->QF = 1; + } + T0 |= T1 << 16; + FORCE_RET(); +} + +NEON_OP(narrow_sat_s16) +{ + if ((int32_t)T0 != (int16_t)T0) { + T0 = ((int32_t)T0 >> 31) ^ 0x7fff; + env->QF = 1; + } + if ((int32_t)T1 != (int16_t) T1) { + T1 = ((int32_t)T1 >> 31) ^ 0x7fff; + env->QF = 1; + } + T0 = (uint16_t)T0 | (T1 << 16); + FORCE_RET(); +} + +NEON_OP(narrow_sat_u32) +{ + if (T1) { + T0 = 0xffffffffu; + env->QF = 1; + } + FORCE_RET(); +} + +NEON_OP(narrow_sat_s32) +{ + int32_t sign = (int32_t)T1 >> 31; + + if ((int32_t)T1 != sign) { + T0 = sign ^ 0x7fffffff; + env->QF = 1; + } + FORCE_RET(); +} + +/* Narrowing instructions. Named type is the narrow type. */ +NEON_OP(narrow_high_u8) +{ + T0 = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00) + | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000); + FORCE_RET(); +} + +NEON_OP(narrow_high_u16) +{ + T0 = (T0 >> 16) | (T1 & 0xffff0000); + FORCE_RET(); +} + +NEON_OP(narrow_high_round_u8) +{ + T0 = (((T0 + 0x80) >> 8) & 0xff) | (((T0 + 0x800000) >> 16) & 0xff00) + | (((T1 + 0x80) << 8) & 0xff0000) | ((T1 + 0x800000) & 0xff000000); + FORCE_RET(); +} + +NEON_OP(narrow_high_round_u16) +{ + T0 = ((T0 + 0x8000) >> 16) | ((T1 + 0x8000) & 0xffff0000); + FORCE_RET(); +} + +NEON_OP(narrow_high_round_u32) +{ + if (T0 >= 0x80000000u) + T0 = T1 + 1; + else + T0 = T1; + FORCE_RET(); +} + +/* Widening instructions. Named type is source type. */ +NEON_OP(widen_s8) +{ + uint32_t src; + + src = T0; + T0 = (uint16_t)(int8_t)src | ((int8_t)(src >> 8) << 16); + T1 = (uint16_t)(int8_t)(src >> 16) | ((int8_t)(src >> 24) << 16); +} + +NEON_OP(widen_u8) +{ + T1 = ((T0 >> 8) & 0xff0000) | ((T0 >> 16) & 0xff); + T0 = ((T0 << 8) & 0xff0000) | (T0 & 0xff); +} + +NEON_OP(widen_s16) +{ + int32_t src; + + src = T0; + T0 = (int16_t)src; + T1 = src >> 16; +} + +NEON_OP(widen_u16) +{ + T1 = T0 >> 16; + T0 &= 0xffff; +} + +NEON_OP(widen_s32) +{ + T1 = (int32_t)T0 >> 31; + FORCE_RET(); +} + +NEON_OP(widen_high_u8) +{ + T1 = (T0 & 0xff000000) | ((T0 >> 8) & 0xff00); + T0 = ((T0 << 16) & 0xff000000) | ((T0 << 8) & 0xff00); +} + +NEON_OP(widen_high_u16) +{ + T1 = T0 & 0xffff0000; + T0 <<= 16; +} + +/* Long operations. The type is the wide type. */ +NEON_OP(shll_u16) +{ + int shift = PARAM1; + uint32_t mask; + + mask = 0xffff >> (16 - shift); + mask |= mask << 16; + mask = ~mask; + + T0 = (T0 << shift) & mask; + T1 = (T1 << shift) & mask; + FORCE_RET(); +} + +NEON_OP(shll_u64) +{ + int shift = PARAM1; + + T1 <<= shift; + T1 |= T0 >> (32 - shift); + T0 <<= shift; + FORCE_RET(); +} + +NEON_OP(addl_u16) +{ + uint32_t tmp; + uint32_t high; + + tmp = env->vfp.scratch[0]; + high = (T0 >> 16) + (tmp >> 16); + T0 = (uint16_t)(T0 + tmp); + T0 |= (high << 16); + tmp = env->vfp.scratch[1]; + high = (T1 >> 16) + (tmp >> 16); + T1 = (uint16_t)(T1 + tmp); + T1 |= (high << 16); + FORCE_RET(); +} + +NEON_OP(addl_u32) +{ + T0 += env->vfp.scratch[0]; + T1 += env->vfp.scratch[1]; + FORCE_RET(); +} + +NEON_OP(addl_u64) +{ + uint64_t tmp; + tmp = T0 | ((uint64_t)T1 << 32); + tmp += env->vfp.scratch[0]; + tmp += (uint64_t)env->vfp.scratch[1] << 32; + T0 = tmp; + T1 = tmp >> 32; + FORCE_RET(); +} + +NEON_OP(subl_u16) +{ + uint32_t tmp; + uint32_t high; + + tmp = env->vfp.scratch[0]; + high = (T0 >> 16) - (tmp >> 16); + T0 = (uint16_t)(T0 - tmp); + T0 |= (high << 16); + tmp = env->vfp.scratch[1]; + high = (T1 >> 16) - (tmp >> 16); + T1 = (uint16_t)(T1 - tmp); + T1 |= (high << 16); + FORCE_RET(); +} + +NEON_OP(subl_u32) +{ + T0 -= env->vfp.scratch[0]; + T1 -= env->vfp.scratch[1]; + FORCE_RET(); +} + +NEON_OP(subl_u64) +{ + uint64_t tmp; + tmp = T0 | ((uint64_t)T1 << 32); + tmp -= env->vfp.scratch[0]; + tmp -= (uint64_t)env->vfp.scratch[1] << 32; + T0 = tmp; + T1 = tmp >> 32; + FORCE_RET(); +} + +#define DO_ABD(dest, x, y, type) do { \ + type tmp_x = x; \ + type tmp_y = y; \ + dest = ((tmp_x > tmp_y) ? tmp_x - tmp_y : tmp_y - tmp_x); \ + } while(0) + +NEON_OP(abdl_u16) +{ + uint32_t tmp; + uint32_t low; + uint32_t high; + + DO_ABD(low, T0, T1, uint8_t); + DO_ABD(tmp, T0 >> 8, T1 >> 8, uint8_t); + low |= tmp << 16; + DO_ABD(high, T0 >> 16, T1 >> 16, uint8_t); + DO_ABD(tmp, T0 >> 24, T1 >> 24, uint8_t); + high |= tmp << 16; + T0 = low; + T1 = high; + FORCE_RET(); +} + +NEON_OP(abdl_s16) +{ + uint32_t tmp; + uint32_t low; + uint32_t high; + + DO_ABD(low, T0, T1, int8_t); + DO_ABD(tmp, T0 >> 8, T1 >> 8, int8_t); + low |= tmp << 16; + DO_ABD(high, T0 >> 16, T1 >> 16, int8_t); + DO_ABD(tmp, T0 >> 24, T1 >> 24, int8_t); + high |= tmp << 16; + T0 = low; + T1 = high; + FORCE_RET(); +} + +NEON_OP(abdl_u32) +{ + uint32_t low; + uint32_t high; + + DO_ABD(low, T0, T1, uint16_t); + DO_ABD(high, T0 >> 16, T1 >> 16, uint16_t); + T0 = low; + T1 = high; + FORCE_RET(); +} + +NEON_OP(abdl_s32) +{ + uint32_t low; + uint32_t high; + + DO_ABD(low, T0, T1, int16_t); + DO_ABD(high, T0 >> 16, T1 >> 16, int16_t); + T0 = low; + T1 = high; + FORCE_RET(); +} + +NEON_OP(abdl_u64) +{ + DO_ABD(T0, T0, T1, uint32_t); + T1 = 0; +} + +NEON_OP(abdl_s64) +{ + DO_ABD(T0, T0, T1, int32_t); + T1 = 0; +} +#undef DO_ABD + +/* Widening multiple. Named type is the source type. */ +#define DO_MULL(dest, x, y, type1, type2) do { \ + type1 tmp_x = x; \ + type1 tmp_y = y; \ + dest = (type2)((type2)tmp_x * (type2)tmp_y); \ + } while(0) + +NEON_OP(mull_u8) +{ + uint32_t tmp; + uint32_t low; + uint32_t high; + + DO_MULL(low, T0, T1, uint8_t, uint16_t); + DO_MULL(tmp, T0 >> 8, T1 >> 8, uint8_t, uint16_t); + low |= tmp << 16; + DO_MULL(high, T0 >> 16, T1 >> 16, uint8_t, uint16_t); + DO_MULL(tmp, T0 >> 24, T1 >> 24, uint8_t, uint16_t); + high |= tmp << 16; + T0 = low; + T1 = high; + FORCE_RET(); +} + +NEON_OP(mull_s8) +{ + uint32_t tmp; + uint32_t low; + uint32_t high; + + DO_MULL(low, T0, T1, int8_t, uint16_t); + DO_MULL(tmp, T0 >> 8, T1 >> 8, int8_t, uint16_t); + low |= tmp << 16; + DO_MULL(high, T0 >> 16, T1 >> 16, int8_t, uint16_t); + DO_MULL(tmp, T0 >> 24, T1 >> 24, int8_t, uint16_t); + high |= tmp << 16; + T0 = low; + T1 = high; + FORCE_RET(); +} + +NEON_OP(mull_u16) +{ + uint32_t low; + uint32_t high; + + DO_MULL(low, T0, T1, uint16_t, uint32_t); + DO_MULL(high, T0 >> 16, T1 >> 16, uint16_t, uint32_t); + T0 = low; + T1 = high; + FORCE_RET(); +} + +NEON_OP(mull_s16) +{ + uint32_t low; + uint32_t high; + + DO_MULL(low, T0, T1, int16_t, uint32_t); + DO_MULL(high, T0 >> 16, T1 >> 16, int16_t, uint32_t); + T0 = low; + T1 = high; + FORCE_RET(); +} + +NEON_OP(addl_saturate_s32) +{ + uint32_t tmp; + uint32_t res; + + tmp = env->vfp.scratch[0]; + res = T0 + tmp; + if (((res ^ T0) & SIGNBIT) && !((T0 ^ tmp) & SIGNBIT)) { + env->QF = 1; + T0 = (T0 >> 31) ^ 0x7fffffff; + } else { + T0 = res; + } + tmp = env->vfp.scratch[1]; + res = T1 + tmp; + if (((res ^ T1) & SIGNBIT) && !((T1 ^ tmp) & SIGNBIT)) { + env->QF = 1; + T1 = (T1 >> 31) ^ 0x7fffffff; + } else { + T1 = res; + } + FORCE_RET(); +} + +NEON_OP(addl_saturate_s64) +{ + uint64_t src1; + uint64_t src2; + uint64_t res; + + src1 = T0 + ((uint64_t)T1 << 32); + src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32); + res = src1 + src2; + if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) { + env->QF = 1; + T0 = ~(int64_t)src1 >> 63; + T1 = T0 ^ 0x80000000; + } else { + T0 = res; + T1 = res >> 32; + } + FORCE_RET(); +} + +NEON_OP(addl_saturate_u64) +{ + uint64_t src1; + uint64_t src2; + uint64_t res; + + src1 = T0 + ((uint64_t)T1 << 32); + src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32); + res = src1 + src2; + if (res < src1) { + env->QF = 1; + T0 = 0xffffffff; + T1 = 0xffffffff; + } else { + T0 = res; + T1 = res >> 32; + } + FORCE_RET(); +} + +NEON_OP(subl_saturate_s64) +{ + uint64_t src1; + uint64_t src2; + uint64_t res; + + src1 = T0 + ((uint64_t)T1 << 32); + src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32); + res = src1 - src2; + if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) { + env->QF = 1; + T0 = ~(int64_t)src1 >> 63; + T1 = T0 ^ 0x80000000; + } else { + T0 = res; + T1 = res >> 32; + } + FORCE_RET(); +} + +NEON_OP(subl_saturate_u64) +{ + uint64_t src1; + uint64_t src2; + uint64_t res; + + src1 = T0 + ((uint64_t)T1 << 32); + src2 = env->vfp.scratch[0] + ((uint64_t)env->vfp.scratch[1] << 32); + if (src1 < src2) { + env->QF = 1; + T0 = 0; + T1 = 0; + } else { + res = src1 - src2; + T0 = res; + T1 = res >> 32; + } + FORCE_RET(); +} + +NEON_OP(negl_u16) +{ + uint32_t tmp; + tmp = T0 >> 16; + tmp = -tmp; + T0 = (-T0 & 0xffff) | (tmp << 16); + tmp = T1 >> 16; + tmp = -tmp; + T1 = (-T1 & 0xffff) | (tmp << 16); + FORCE_RET(); +} + +NEON_OP(negl_u32) +{ + T0 = -T0; + T1 = -T1; + FORCE_RET(); +} + +NEON_OP(negl_u64) +{ + uint64_t val; + + val = T0 | ((uint64_t)T1 << 32); + val = -val; + T0 = val; + T1 = val >> 32; + FORCE_RET(); +} + +/* Scalar operations. */ +NEON_OP(dup_low16) +{ + T0 = (T0 & 0xffff) | (T0 << 16); + FORCE_RET(); +} + +NEON_OP(dup_high16) +{ + T0 = (T0 >> 16) | (T0 & 0xffff0000); + FORCE_RET(); +} + +/* Helper for VEXT */ +NEON_OP(extract) +{ + int shift = PARAM1; + T0 = (T0 >> shift) | (T1 << (32 - shift)); + FORCE_RET(); +} + +/* Pairwise add long. Named type is source type. */ +NEON_OP(paddl_s8) +{ + int8_t src1; + int8_t src2; + uint16_t result; + src1 = T0 >> 24; + src2 = T0 >> 16; + result = (uint16_t)src1 + src2; + src1 = T0 >> 8; + src2 = T0; + T0 = (uint16_t)((uint16_t)src1 + src2) | ((uint32_t)result << 16); + FORCE_RET(); +} + +NEON_OP(paddl_u8) +{ + uint8_t src1; + uint8_t src2; + uint16_t result; + src1 = T0 >> 24; + src2 = T0 >> 16; + result = (uint16_t)src1 + src2; + src1 = T0 >> 8; + src2 = T0; + T0 = (uint16_t)((uint16_t)src1 + src2) | ((uint32_t)result << 16); + FORCE_RET(); +} + +NEON_OP(paddl_s16) +{ + T0 = (uint32_t)(int16_t)T0 + (uint32_t)(int16_t)(T0 >> 16); + FORCE_RET(); +} + +NEON_OP(paddl_u16) +{ + T0 = (uint32_t)(uint16_t)T0 + (uint32_t)(uint16_t)(T0 >> 16); + FORCE_RET(); +} + +NEON_OP(paddl_s32) +{ + int64_t tmp; + tmp = (int64_t)(int32_t)T0 + (int64_t)(int32_t)T1; + T0 = tmp; + T1 = tmp >> 32; + FORCE_RET(); +} + +NEON_OP(paddl_u32) +{ + uint64_t tmp; + tmp = (uint64_t)T0 + (uint64_t)T1; + T0 = tmp; + T1 = tmp >> 32; + FORCE_RET(); +} + +/* Count Leading Sign/Zero Bits. */ +static inline int do_clz8(uint8_t x) +{ + int n; + for (n = 8; x; n--) + x >>= 1; + return n; +} + +static inline int do_clz16(uint16_t x) +{ + int n; + for (n = 16; x; n--) + x >>= 1; + return n; +} + +NEON_OP(clz_u8) +{ + uint32_t result; + uint32_t tmp; + + tmp = T0; + result = do_clz8(tmp); + result |= do_clz8(tmp >> 8) << 8; + result |= do_clz8(tmp >> 16) << 16; + result |= do_clz8(tmp >> 24) << 24; + T0 = result; + FORCE_RET(); +} + +NEON_OP(clz_u16) +{ + uint32_t result; + uint32_t tmp; + tmp = T0; + result = do_clz16(tmp); + result |= do_clz16(tmp >> 16) << 16; + T0 = result; + FORCE_RET(); +} + +NEON_OP(cls_s8) +{ + uint32_t result; + int8_t tmp; + tmp = T0; + result = do_clz8((tmp < 0) ? ~tmp : tmp) - 1; + tmp = T0 >> 8; + result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 8; + tmp = T0 >> 16; + result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 16; + tmp = T0 >> 24; + result |= (do_clz8((tmp < 0) ? ~tmp : tmp) - 1) << 24; + T0 = result; + FORCE_RET(); +} + +NEON_OP(cls_s16) +{ + uint32_t result; + int16_t tmp; + tmp = T0; + result = do_clz16((tmp < 0) ? ~tmp : tmp) - 1; + tmp = T0 >> 16; + result |= (do_clz16((tmp < 0) ? ~tmp : tmp) - 1) << 16; + T0 = result; + FORCE_RET(); +} + +NEON_OP(cls_s32) +{ + int count; + if ((int32_t)T0 < 0) + T0 = ~T0; + for (count = 32; T0 > 0; count--) + T0 = T0 >> 1; + T0 = count - 1; + FORCE_RET(); +} + +/* Bit count. */ +NEON_OP(cnt_u8) +{ + T0 = (T0 & 0x55555555) + ((T0 >> 1) & 0x55555555); + T0 = (T0 & 0x33333333) + ((T0 >> 2) & 0x33333333); + T0 = (T0 & 0x0f0f0f0f) + ((T0 >> 4) & 0x0f0f0f0f); + FORCE_RET(); +} + +/* Saturnating negation. */ +/* ??? Make these use NEON_VOP1 */ +#define DO_QABS8(x) do { \ + if (x == (int8_t)0x80) { \ + x = 0x7f; \ + env->QF = 1; \ + } else if (x < 0) { \ + x = -x; \ + }} while (0) +NEON_OP(qabs_s8) +{ + neon_s8 vec; + NEON_UNPACK(neon_s8, vec, T0); + DO_QABS8(vec.v1); + DO_QABS8(vec.v2); + DO_QABS8(vec.v3); + DO_QABS8(vec.v4); + NEON_PACK(neon_s8, T0, vec); + FORCE_RET(); +} +#undef DO_QABS8 + +#define DO_QNEG8(x) do { \ + if (x == (int8_t)0x80) { \ + x = 0x7f; \ + env->QF = 1; \ + } else { \ + x = -x; \ + }} while (0) +NEON_OP(qneg_s8) +{ + neon_s8 vec; + NEON_UNPACK(neon_s8, vec, T0); + DO_QNEG8(vec.v1); + DO_QNEG8(vec.v2); + DO_QNEG8(vec.v3); + DO_QNEG8(vec.v4); + NEON_PACK(neon_s8, T0, vec); + FORCE_RET(); +} +#undef DO_QNEG8 + +#define DO_QABS16(x) do { \ + if (x == (int16_t)0x8000) { \ + x = 0x7fff; \ + env->QF = 1; \ + } else if (x < 0) { \ + x = -x; \ + }} while (0) +NEON_OP(qabs_s16) +{ + neon_s16 vec; + NEON_UNPACK(neon_s16, vec, T0); + DO_QABS16(vec.v1); + DO_QABS16(vec.v2); + NEON_PACK(neon_s16, T0, vec); + FORCE_RET(); +} +#undef DO_QABS16 + +#define DO_QNEG16(x) do { \ + if (x == (int16_t)0x8000) { \ + x = 0x7fff; \ + env->QF = 1; \ + } else { \ + x = -x; \ + }} while (0) +NEON_OP(qneg_s16) +{ + neon_s16 vec; + NEON_UNPACK(neon_s16, vec, T0); + DO_QNEG16(vec.v1); + DO_QNEG16(vec.v2); + NEON_PACK(neon_s16, T0, vec); + FORCE_RET(); +} +#undef DO_QNEG16 + +NEON_OP(qabs_s32) +{ + if (T0 == 0x80000000) { + T0 = 0x7fffffff; + env->QF = 1; + } else if ((int32_t)T0 < 0) { + T0 = -T0; + } + FORCE_RET(); +} + +NEON_OP(qneg_s32) +{ + if (T0 == 0x80000000) { + T0 = 0x7fffffff; + env->QF = 1; + } else { + T0 = -T0; + } + FORCE_RET(); +} + +/* Unary opperations */ +#define NEON_FN(dest, src, dummy) dest = (src < 0) ? -src : src +NEON_VOP1(abs_s8, neon_s8, 4) +NEON_VOP1(abs_s16, neon_s16, 2) +NEON_OP(abs_s32) +{ + if ((int32_t)T0 < 0) + T0 = -T0; + FORCE_RET(); +} +#undef NEON_FN + +/* Transpose. Argument order is rather strange to avoid special casing + the tranlation code. + On input T0 = rm, T1 = rd. On output T0 = rd, T1 = rm */ +NEON_OP(trn_u8) +{ + uint32_t rd; + uint32_t rm; + rd = ((T0 & 0x00ff00ff) << 8) | (T1 & 0x00ff00ff); + rm = ((T1 & 0xff00ff00) >> 8) | (T0 & 0xff00ff00); + T0 = rd; + T1 = rm; + FORCE_RET(); +} + +NEON_OP(trn_u16) +{ + uint32_t rd; + uint32_t rm; + rd = (T0 << 16) | (T1 & 0xffff); + rm = (T1 >> 16) | (T0 & 0xffff0000); + T0 = rd; + T1 = rm; + FORCE_RET(); +} + +/* Worker routines for zip and unzip. */ +NEON_OP(unzip_u8) +{ + uint32_t rd; + uint32_t rm; + rd = (T0 & 0xff) | ((T0 >> 8) & 0xff00) + | ((T1 << 16) & 0xff0000) | ((T1 << 8) & 0xff000000); + rm = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00) + | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000); + T0 = rd; + T1 = rm; + FORCE_RET(); +} + +NEON_OP(zip_u8) +{ + uint32_t rd; + uint32_t rm; + rd = (T0 & 0xff) | ((T1 << 8) & 0xff00) + | ((T0 << 16) & 0xff0000) | ((T1 << 24) & 0xff000000); + rm = ((T0 >> 16) & 0xff) | ((T1 >> 8) & 0xff00) + | ((T0 >> 8) & 0xff0000) | (T1 & 0xff000000); + T0 = rd; + T1 = rm; + FORCE_RET(); +} + +NEON_OP(zip_u16) +{ + uint32_t tmp; + + tmp = (T0 & 0xffff) | (T1 << 16); + T1 = (T1 & 0xffff0000) | (T0 >> 16); + T0 = tmp; + FORCE_RET(); +} + +/* Reciprocal/root estimate. */ +NEON_OP(recpe_u32) +{ + T0 = helper_recpe_u32(T0); +} + +NEON_OP(rsqrte_u32) +{ + T0 = helper_rsqrte_u32(T0); +} + +NEON_OP(recpe_f32) +{ + FT0s = helper_recpe_f32(FT0s); +} + +NEON_OP(rsqrte_f32) +{ + FT0s = helper_rsqrte_f32(FT0s); +} + +/* Table lookup. This accessed the register file directly. */ +NEON_OP(tbl) +{ + helper_neon_tbl(PARAM1, PARAM2); +} + +NEON_OP(dup_u8) +{ + T0 = (T0 >> PARAM1) & 0xff; + T0 |= T0 << 8; + T0 |= T0 << 16; + FORCE_RET(); +} + +/* Helpers for element load/store. */ +NEON_OP(insert_elt) +{ + int shift = PARAM1; + uint32_t mask = PARAM2; + T2 = (T2 & mask) | (T0 << shift); + FORCE_RET(); +} + +NEON_OP(extract_elt) +{ + int shift = PARAM1; + uint32_t mask = PARAM2; + T0 = (T2 & mask) >> shift; + FORCE_RET(); +} diff --git a/target-arm/translate.c b/target-arm/translate.c index bb01f2f34..9366bf146 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2,7 +2,7 @@ * ARM translation * * Copyright (c) 2003 Fabrice Bellard - * Copyright (c) 2005 CodeSourcery, LLC + * Copyright (c) 2005-2007 CodeSourcery * Copyright (c) 2007 OpenedHand, Ltd. * * This library is free software; you can redistribute it and/or @@ -29,9 +29,11 @@ #include "exec-all.h" #include "disas.h" -#define ENABLE_ARCH_5J 0 -#define ENABLE_ARCH_6 1 -#define ENABLE_ARCH_6T2 1 +#define ENABLE_ARCH_5J 0 +#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6) +#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K) +#define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2) +#define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7) #define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op; @@ -43,6 +45,9 @@ typedef struct DisasContext { int condjmp; /* The label that will be jumped to when the instruction is skipped. */ int condlabel; + /* Thumb-2 condtional execution bits. */ + int condexec_mask; + int condexec_cond; struct TranslationBlock *tb; int singlestep_enabled; int thumb; @@ -58,7 +63,10 @@ typedef struct DisasContext { #define IS_USER(s) (s->user) #endif -#define DISAS_JUMP_NEXT 4 +/* These instructions trap after executing, so defer them until after the + conditional executions state has been updated. */ +#define DISAS_WFI 4 +#define DISAS_SWI 5 #ifdef USE_DIRECT_JUMP #define TBPARAM(x) @@ -81,6 +89,51 @@ enum { #include "gen-op.h" +#define PAS_OP(pfx) { \ + gen_op_ ## pfx ## add16_T0_T1, \ + gen_op_ ## pfx ## addsubx_T0_T1, \ + gen_op_ ## pfx ## subaddx_T0_T1, \ + gen_op_ ## pfx ## sub16_T0_T1, \ + gen_op_ ## pfx ## add8_T0_T1, \ + NULL, \ + NULL, \ + gen_op_ ## pfx ## sub8_T0_T1 } + +static GenOpFunc *gen_arm_parallel_addsub[8][8] = { + {}, + PAS_OP(s), + PAS_OP(q), + PAS_OP(sh), + {}, + PAS_OP(u), + PAS_OP(uq), + PAS_OP(uh), +}; +#undef PAS_OP + +/* For unknown reasons Arm and Thumb-2 use arbitrarily diffenet encodings. */ +#define PAS_OP(pfx) { \ + gen_op_ ## pfx ## add8_T0_T1, \ + gen_op_ ## pfx ## add16_T0_T1, \ + gen_op_ ## pfx ## addsubx_T0_T1, \ + NULL, \ + gen_op_ ## pfx ## sub8_T0_T1, \ + gen_op_ ## pfx ## sub16_T0_T1, \ + gen_op_ ## pfx ## subaddx_T0_T1, \ + NULL } + +static GenOpFunc *gen_thumb2_parallel_addsub[8][8] = { + PAS_OP(s), + PAS_OP(q), + PAS_OP(sh), + {}, + PAS_OP(u), + PAS_OP(uq), + PAS_OP(uh), + {} +}; +#undef PAS_OP + static GenOpFunc1 *gen_test_cc[14] = { gen_op_test_eq, gen_op_test_ne, @@ -275,6 +328,12 @@ static GenOpFunc1 *gen_op_movl_TN_im[3] = { gen_op_movl_T2_im, }; +static GenOpFunc1 *gen_shift_T0_im_thumb_cc[3] = { + gen_op_shll_T0_im_thumb_cc, + gen_op_shrl_T0_im_thumb_cc, + gen_op_sarl_T0_im_thumb_cc, +}; + static GenOpFunc1 *gen_shift_T0_im_thumb[3] = { gen_op_shll_T0_im_thumb, gen_op_shrl_T0_im_thumb, @@ -421,6 +480,15 @@ static inline void gen_vfp_##name(int dp) \ gen_op_vfp_##name##s(); \ } +#define VFP_OP1(name) \ +static inline void gen_vfp_##name(int dp, int arg) \ +{ \ + if (dp) \ + gen_op_vfp_##name##d(arg); \ + else \ + gen_op_vfp_##name##s(arg); \ +} + VFP_OP(add) VFP_OP(sub) VFP_OP(mul) @@ -437,9 +505,25 @@ VFP_OP(toui) VFP_OP(touiz) VFP_OP(tosi) VFP_OP(tosiz) +VFP_OP1(tosh) +VFP_OP1(tosl) +VFP_OP1(touh) +VFP_OP1(toul) +VFP_OP1(shto) +VFP_OP1(slto) +VFP_OP1(uhto) +VFP_OP1(ulto) #undef VFP_OP +static inline void gen_vfp_fconst(int dp, uint32_t val) +{ + if (dp) + gen_op_vfp_fconstd(val); + else + gen_op_vfp_fconsts(val); +} + static inline void gen_vfp_ld(DisasContext *s, int dp) { if (dp) @@ -469,6 +553,20 @@ vfp_reg_offset (int dp, int reg) + offsetof(CPU_DoubleU, l.lower); } } + +/* Return the offset of a 32-bit piece of a NEON register. + zero is the least significant end of the register. */ +static inline long +neon_reg_offset (int reg, int n) +{ + int sreg; + sreg = reg * 2 + n; + return vfp_reg_offset(0, sreg); +} + +#define NEON_GET_REG(T, reg, n) gen_op_neon_getreg_##T(neon_reg_offset(reg, n)) +#define NEON_SET_REG(T, reg, n) gen_op_neon_setreg_##T(neon_reg_offset(reg, n)) + static inline void gen_mov_F0_vreg(int dp, int reg) { if (dp) @@ -1582,14 +1680,49 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) return 0; } +static int cp15_user_ok(uint32_t insn) +{ + int cpn = (insn >> 16) & 0xf; + int cpm = insn & 0xf; + int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); + + if (cpn == 13 && cpm == 0) { + /* TLS register. */ + if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT))) + return 1; + } + if (cpn == 7) { + /* ISB, DSB, DMB. */ + if ((cpm == 5 && op == 4) + || (cpm == 10 && (op == 4 || op == 5))) + return 1; + } + return 0; +} + /* Disassemble system coprocessor (cp15) instruction. Return nonzero if instruction is not defined. */ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) { uint32_t rd; - /* ??? Some cp15 registers are accessible from userspace. */ - if (IS_USER(s)) { + /* M profile cores use memory mapped registers instead of cp15. */ + if (arm_feature(env, ARM_FEATURE_M)) + return 1; + + if ((insn & (1 << 25)) == 0) { + if (insn & (1 << 20)) { + /* mrrc */ + return 1; + } + /* mcrr. Used for block cache operations, so implement as no-op. */ + return 0; + } + if ((insn & (1 << 4)) == 0) { + /* cdp */ + return 1; + } + if (IS_USER(s) && !cp15_user_ok(insn)) { return 1; } if ((insn & 0x0fff0fff) == 0x0e070f90 @@ -1597,8 +1730,7 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) /* Wait for interrupt. */ gen_op_movl_T0_im((long)s->pc); gen_op_movl_reg_TN[0][15](); - gen_op_wfi(); - s->is_jmp = DISAS_JUMP; + s->is_jmp = DISAS_WFI; return 0; } rd = (insn >> 12) & 0xf; @@ -1620,6 +1752,32 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) return 0; } +#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n)) +#define VFP_SREG(insn, bigbit, smallbit) \ + ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1)) +#define VFP_DREG(reg, insn, bigbit, smallbit) do { \ + if (arm_feature(env, ARM_FEATURE_VFP3)) { \ + reg = (((insn) >> (bigbit)) & 0x0f) \ + | (((insn) >> ((smallbit) - 4)) & 0x10); \ + } else { \ + if (insn & (1 << (smallbit))) \ + return 1; \ + reg = ((insn) >> (bigbit)) & 0x0f; \ + }} while (0) + +#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22) +#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22) +#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7) +#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7) +#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5) +#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) + +static inline int +vfp_enabled(CPUState * env) +{ + return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0); +} + /* Disassemble a VFP instruction. Returns nonzero if an error occured (ie. an undefined instruction). */ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) @@ -1630,12 +1788,13 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) if (!arm_feature(env, ARM_FEATURE_VFP)) return 1; - if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) { - /* VFP disabled. Only allow fmxr/fmrx to/from fpexc and fpsid. */ + if (!vfp_enabled(env)) { + /* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */ if ((insn & 0x0fe00fff) != 0x0ee00a10) return 1; rn = (insn >> 16) & 0xf; - if (rn != 0 && rn != 8) + if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC + && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0) return 1; } dp = ((insn & 0xf00) == 0xb00); @@ -1643,44 +1802,129 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) case 0xe: if (insn & (1 << 4)) { /* single register transfer */ - if ((insn & 0x6f) != 0x00) - return 1; rd = (insn >> 12) & 0xf; if (dp) { - if (insn & 0x80) + int size; + int pass; + + VFP_DREG_N(rn, insn); + if (insn & 0xf) return 1; - rn = (insn >> 16) & 0xf; - /* Get the existing value even for arm->vfp moves because - we only set half the register. */ - gen_mov_F0_vreg(1, rn); - gen_op_vfp_mrrd(); + if (insn & 0x00c00060 + && !arm_feature(env, ARM_FEATURE_NEON)) + return 1; + + pass = (insn >> 21) & 1; + if (insn & (1 << 22)) { + size = 0; + offset = ((insn >> 5) & 3) * 8; + } else if (insn & (1 << 5)) { + size = 1; + offset = (insn & (1 << 6)) ? 16 : 0; + } else { + size = 2; + offset = 0; + } if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ - if (insn & (1 << 21)) - gen_movl_reg_T1(s, rd); - else - gen_movl_reg_T0(s, rd); + switch (size) { + case 0: + NEON_GET_REG(T1, rn, pass); + if (offset) + gen_op_shrl_T1_im(offset); + if (insn & (1 << 23)) + gen_op_uxtb_T1(); + else + gen_op_sxtb_T1(); + break; + case 1: + NEON_GET_REG(T1, rn, pass); + if (insn & (1 << 23)) { + if (offset) { + gen_op_shrl_T1_im(16); + } else { + gen_op_uxth_T1(); + } + } else { + if (offset) { + gen_op_sarl_T1_im(16); + } else { + gen_op_sxth_T1(); + } + } + break; + case 2: + NEON_GET_REG(T1, rn, pass); + break; + } + gen_movl_reg_T1(s, rd); } else { /* arm->vfp */ - if (insn & (1 << 21)) - gen_movl_T1_reg(s, rd); - else - gen_movl_T0_reg(s, rd); - gen_op_vfp_mdrr(); - gen_mov_vreg_F0(dp, rn); + gen_movl_T0_reg(s, rd); + if (insn & (1 << 23)) { + /* VDUP */ + if (size == 0) { + gen_op_neon_dup_u8(0); + } else if (size == 1) { + gen_op_neon_dup_low16(); + } + NEON_SET_REG(T0, rn, 0); + NEON_SET_REG(T0, rn, 1); + } else { + /* VMOV */ + switch (size) { + case 0: + NEON_GET_REG(T2, rn, pass); + gen_op_movl_T1_im(0xff); + gen_op_andl_T0_T1(); + gen_op_neon_insert_elt(offset, ~(0xff << offset)); + NEON_SET_REG(T2, rn, pass); + break; + case 1: + NEON_GET_REG(T2, rn, pass); + gen_op_movl_T1_im(0xffff); + gen_op_andl_T0_T1(); + bank_mask = offset ? 0xffff : 0xffff0000; + gen_op_neon_insert_elt(offset, bank_mask); + NEON_SET_REG(T2, rn, pass); + break; + case 2: + NEON_SET_REG(T0, rn, pass); + break; + } + } } - } else { - rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); + } else { /* !dp */ + if ((insn & 0x6f) != 0x00) + return 1; + rn = VFP_SREG_N(insn); if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ if (insn & (1 << 21)) { /* system register */ rn >>= 1; + switch (rn) { case ARM_VFP_FPSID: + /* VFP2 allows access for FSID from userspace. + VFP3 restricts all id registers to privileged + accesses. */ + if (IS_USER(s) + && arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_op_vfp_movl_T0_xreg(rn); + break; case ARM_VFP_FPEXC: + if (IS_USER(s)) + return 1; + gen_op_vfp_movl_T0_xreg(rn); + break; case ARM_VFP_FPINST: case ARM_VFP_FPINST2: + /* Not present in VFP3. */ + if (IS_USER(s) + || arm_feature(env, ARM_FEATURE_VFP3)) + return 1; gen_op_vfp_movl_T0_xreg(rn); break; case ARM_VFP_FPSCR: @@ -1689,6 +1933,13 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) else gen_op_vfp_movl_T0_fpscr(); break; + case ARM_VFP_MVFR0: + case ARM_VFP_MVFR1: + if (IS_USER(s) + || !arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_op_vfp_movl_T0_xreg(rn); + break; default: return 1; } @@ -1709,6 +1960,8 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) /* system register */ switch (rn) { case ARM_VFP_FPSID: + case ARM_VFP_MVFR0: + case ARM_VFP_MVFR1: /* Writes are ignored. */ break; case ARM_VFP_FPSCR: @@ -1716,6 +1969,8 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_lookup_tb(s); break; case ARM_VFP_FPEXC: + if (IS_USER(s)) + return 1; gen_op_vfp_movl_xreg_T0(rn); gen_lookup_tb(s); break; @@ -1742,38 +1997,31 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); } else { /* rn is register number */ - if (insn & (1 << 7)) - return 1; - rn = (insn >> 16) & 0xf; + VFP_DREG_N(rn, insn); } if (op == 15 && (rn == 15 || rn > 17)) { /* Integer or single precision destination. */ - rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1); + rd = VFP_SREG_D(insn); } else { - if (insn & (1 << 22)) - return 1; - rd = (insn >> 12) & 0xf; + VFP_DREG_D(rd, insn); } if (op == 15 && (rn == 16 || rn == 17)) { /* Integer source. */ rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); } else { - if (insn & (1 << 5)) - return 1; - rm = insn & 0xf; + VFP_DREG_M(rm, insn); } } else { - rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); + rn = VFP_SREG_N(insn); if (op == 15 && rn == 15) { /* Double precision destination. */ - if (insn & (1 << 22)) - return 1; - rd = (insn >> 12) & 0xf; - } else - rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1); - rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); + VFP_DREG_D(rd, insn); + } else { + rd = VFP_SREG_D(insn); + } + rm = VFP_SREG_M(insn); } veclen = env->vfp.vec_len; @@ -1831,9 +2079,17 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_mov_F0_vreg(dp, rd); gen_vfp_F1_ld0(dp); break; + case 20: + case 21: + case 22: + case 23: + /* Source and destination the same. */ + gen_mov_F0_vreg(dp, rd); + break; default: /* One source operand. */ gen_mov_F0_vreg(dp, rm); + break; } } else { /* Two source operands. */ @@ -1882,6 +2138,27 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) case 8: /* div: fn / fm */ gen_vfp_div(dp); break; + case 14: /* fconst */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + + n = (insn << 12) & 0x80000000; + i = ((insn >> 12) & 0x70) | (insn & 0xf); + if (dp) { + if (i & 0x40) + i |= 0x3f80; + else + i |= 0x4000; + n |= i << 16; + } else { + if (i & 0x40) + i |= 0x780; + else + i |= 0x800; + n |= i << 19; + } + gen_vfp_fconst(dp, n); + break; case 15: /* extension space */ switch (rn) { case 0: /* cpy */ @@ -1921,6 +2198,26 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) case 17: /* fsito */ gen_vfp_sito(dp); break; + case 20: /* fshto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_shto(dp, rm); + break; + case 21: /* fslto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_slto(dp, rm); + break; + case 22: /* fuhto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_uhto(dp, rm); + break; + case 23: /* fulto */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_ulto(dp, rm); + break; case 24: /* ftoui */ gen_vfp_toui(dp); break; @@ -1933,6 +2230,26 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) case 27: /* ftosiz */ gen_vfp_tosiz(dp); break; + case 28: /* ftosh */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_tosh(dp, rm); + break; + case 29: /* ftosl */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_tosl(dp, rm); + break; + case 30: /* ftouh */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_touh(dp, rm); + break; + case 31: /* ftoul */ + if (!arm_feature(env, ARM_FEATURE_VFP3)) + return 1; + gen_vfp_toul(dp, rm); + break; default: /* undefined */ printf ("rn:%d\n", rn); return 1; @@ -1994,16 +2311,15 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 0xc: case 0xd: - if (dp && (insn & (1 << 22))) { + if (dp && (insn & 0x03e00000) == 0x00400000) { /* two-register transfer */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; if (dp) { - if (insn & (1 << 5)) - return 1; - rm = insn & 0xf; - } else - rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1); + VFP_DREG_M(rm, insn); + } else { + rm = VFP_SREG_M(insn); + } if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ @@ -2040,10 +2356,14 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Load/store */ rn = (insn >> 16) & 0xf; if (dp) - rd = (insn >> 12) & 0xf; + VFP_DREG_D(rd, insn); else - rd = ((insn >> 11) & 0x1e) | ((insn >> 22) & 1); - gen_movl_T1_reg(s, rn); + rd = VFP_SREG_D(insn); + if (s->thumb && rn == 15) { + gen_op_movl_T1_im(s->pc & ~2); + } else { + gen_movl_T1_reg(s, rn); + } if ((insn & 0x01200000) == 0x01000000) { /* Single load/store */ offset = (insn & 0xff) << 2; @@ -2156,8 +2476,9 @@ static inline void gen_mulxy(int x, int y) } /* Return the mask of PSR bits set by a MSR instruction. */ -static uint32_t msr_mask(DisasContext *s, int flags, int spsr) { +static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) { uint32_t mask; + uint32_t reserved; mask = 0; if (flags & (1 << 0)) @@ -2168,14 +2489,19 @@ static uint32_t msr_mask(DisasContext *s, int flags, int spsr) { mask |= 0xff0000; if (flags & (1 << 3)) mask |= 0xff000000; + /* Mask out undefined bits. */ - mask &= 0xf90f03ff; - /* Mask out state bits. */ + mask &= ~CPSR_RESERVED; + if (!arm_feature(env, ARM_FEATURE_V6)) + reserved &= ~(CPSR_E | CPSR_GE); + if (!arm_feature(env, ARM_FEATURE_THUMB2)) + reserved &= ~CPSR_IT; + /* Mask out execution state bits. */ if (!spsr) - mask &= ~0x01000020; + reserved &= ~CPSR_EXEC; /* Mask out privileged bits. */ if (IS_USER(s)) - mask &= 0xf80f0200; + mask &= CPSR_USER; return mask; } @@ -2194,6 +2520,7 @@ static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr) return 0; } +/* Generate an old-style exception return. */ static void gen_exception_return(DisasContext *s) { gen_op_movl_reg_TN[0][15](); @@ -2202,775 +2529,4309 @@ static void gen_exception_return(DisasContext *s) s->is_jmp = DISAS_UPDATE; } -static void disas_arm_insn(CPUState * env, DisasContext *s) +/* Generate a v6 exception return. */ +static void gen_rfe(DisasContext *s) { - unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; + gen_op_movl_cpsr_T0(0xffffffff); + gen_op_movl_T0_T2(); + gen_op_movl_reg_TN[0][15](); + s->is_jmp = DISAS_UPDATE; +} - insn = ldl_code(s->pc); - s->pc += 4; +static inline void +gen_set_condexec (DisasContext *s) +{ + if (s->condexec_mask) { + gen_op_set_condexec((s->condexec_cond << 4) | (s->condexec_mask >> 1)); + } +} - cond = insn >> 28; - if (cond == 0xf){ - /* Unconditional instructions. */ - if ((insn & 0x0d70f000) == 0x0550f000) - return; /* PLD */ - else if ((insn & 0x0e000000) == 0x0a000000) { - /* branch link and change to thumb (blx ) */ - int32_t offset; +static void gen_nop_hint(DisasContext *s, int val) +{ + switch (val) { + case 3: /* wfi */ + gen_op_movl_T0_im((long)s->pc); + gen_op_movl_reg_TN[0][15](); + s->is_jmp = DISAS_WFI; + break; + case 2: /* wfe */ + case 4: /* sev */ + /* TODO: Implement SEV and WFE. May help SMP performance. */ + default: /* nop */ + break; + } +} - val = (uint32_t)s->pc; - gen_op_movl_T0_im(val); - gen_movl_reg_T0(s, 14); - /* Sign-extend the 24-bit offset */ - offset = (((int32_t)insn) << 8) >> 8; - /* offset * 4 + bit24 * 2 + (thumb bit) */ - val += (offset << 2) | ((insn >> 23) & 2) | 1; - /* pipeline offset */ - val += 4; - gen_op_movl_T0_im(val); - gen_bx(s); - return; - } else if ((insn & 0x0e000f00) == 0x0c000100) { - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - /* iWMMXt register transfer. */ - if (env->cp15.c15_cpar & (1 << 1)) - if (!disas_iwmmxt_insn(env, s, insn)) - return; - } - } else if ((insn & 0x0fe00000) == 0x0c400000) { - /* Coprocessor double register transfer. */ - } else if ((insn & 0x0f000010) == 0x0e000010) { - /* Additional coprocessor register transfer. */ - } else if ((insn & 0x0ff10010) == 0x01000000) { - /* cps (privileged) */ - } else if ((insn & 0x0ffffdff) == 0x01010000) { - /* setend */ - if (insn & (1 << 9)) { - /* BE8 mode not implemented. */ - goto illegal_op; - } - return; - } - goto illegal_op; +/* Neon shift by constant. The actual ops are the same as used for variable + shifts. [OP][U][SIZE] */ +static GenOpFunc *gen_neon_shift_im[8][2][4] = { + { /* 0 */ /* VSHR */ + { + gen_op_neon_shl_u8, + gen_op_neon_shl_u16, + gen_op_neon_shl_u32, + gen_op_neon_shl_u64 + }, { + gen_op_neon_shl_s8, + gen_op_neon_shl_s16, + gen_op_neon_shl_s32, + gen_op_neon_shl_s64 + } + }, { /* 1 */ /* VSRA */ + { + gen_op_neon_shl_u8, + gen_op_neon_shl_u16, + gen_op_neon_shl_u32, + gen_op_neon_shl_u64 + }, { + gen_op_neon_shl_s8, + gen_op_neon_shl_s16, + gen_op_neon_shl_s32, + gen_op_neon_shl_s64 + } + }, { /* 2 */ /* VRSHR */ + { + gen_op_neon_rshl_u8, + gen_op_neon_rshl_u16, + gen_op_neon_rshl_u32, + gen_op_neon_rshl_u64 + }, { + gen_op_neon_rshl_s8, + gen_op_neon_rshl_s16, + gen_op_neon_rshl_s32, + gen_op_neon_rshl_s64 + } + }, { /* 3 */ /* VRSRA */ + { + gen_op_neon_rshl_u8, + gen_op_neon_rshl_u16, + gen_op_neon_rshl_u32, + gen_op_neon_rshl_u64 + }, { + gen_op_neon_rshl_s8, + gen_op_neon_rshl_s16, + gen_op_neon_rshl_s32, + gen_op_neon_rshl_s64 + } + }, { /* 4 */ + { + NULL, NULL, NULL, NULL + }, { /* VSRI */ + gen_op_neon_shl_u8, + gen_op_neon_shl_u16, + gen_op_neon_shl_u32, + gen_op_neon_shl_u64, + } + }, { /* 5 */ + { /* VSHL */ + gen_op_neon_shl_u8, + gen_op_neon_shl_u16, + gen_op_neon_shl_u32, + gen_op_neon_shl_u64, + }, { /* VSLI */ + gen_op_neon_shl_u8, + gen_op_neon_shl_u16, + gen_op_neon_shl_u32, + gen_op_neon_shl_u64, + } + }, { /* 6 */ /* VQSHL */ + { + gen_op_neon_qshl_u8, + gen_op_neon_qshl_u16, + gen_op_neon_qshl_u32, + gen_op_neon_qshl_u64 + }, { + gen_op_neon_qshl_s8, + gen_op_neon_qshl_s16, + gen_op_neon_qshl_s32, + gen_op_neon_qshl_s64 + } + }, { /* 7 */ /* VQSHLU */ + { + gen_op_neon_qshl_u8, + gen_op_neon_qshl_u16, + gen_op_neon_qshl_u32, + gen_op_neon_qshl_u64 + }, { + gen_op_neon_qshl_u8, + gen_op_neon_qshl_u16, + gen_op_neon_qshl_u32, + gen_op_neon_qshl_u64 + } } - if (cond != 0xe) { - /* if not always execute, we generate a conditional jump to - next instruction */ - s->condlabel = gen_new_label(); - gen_test_cc[cond ^ 1](s->condlabel); - s->condjmp = 1; - //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); - //s->is_jmp = DISAS_JUMP_NEXT; +}; + +/* [R][U][size - 1] */ +static GenOpFunc *gen_neon_shift_im_narrow[2][2][3] = { + { + { + gen_op_neon_shl_u16, + gen_op_neon_shl_u32, + gen_op_neon_shl_u64 + }, { + gen_op_neon_shl_s16, + gen_op_neon_shl_s32, + gen_op_neon_shl_s64 + } + }, { + { + gen_op_neon_rshl_u16, + gen_op_neon_rshl_u32, + gen_op_neon_rshl_u64 + }, { + gen_op_neon_rshl_s16, + gen_op_neon_rshl_s32, + gen_op_neon_rshl_s64 + } } - if ((insn & 0x0f900000) == 0x03000000) { - if ((insn & 0x0fb0f000) != 0x0320f000) - goto illegal_op; - /* CPSR = immediate */ - val = insn & 0xff; - shift = ((insn >> 8) & 0xf) * 2; - if (shift) - val = (val >> shift) | (val << (32 - shift)); - gen_op_movl_T0_im(val); - i = ((insn & (1 << 22)) != 0); - if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i)) - goto illegal_op; - } else if ((insn & 0x0f900000) == 0x01000000 - && (insn & 0x00000090) != 0x00000090) { - /* miscellaneous instructions */ - op1 = (insn >> 21) & 3; - sh = (insn >> 4) & 0xf; - rm = insn & 0xf; - switch (sh) { - case 0x0: /* move program status register */ - if (op1 & 1) { - /* PSR = reg */ - gen_movl_T0_reg(s, rm); - i = ((op1 & 2) != 0); - if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i)) - goto illegal_op; - } else { - /* reg = PSR */ - rd = (insn >> 12) & 0xf; - if (op1 & 2) { - if (IS_USER(s)) - goto illegal_op; - gen_op_movl_T0_spsr(); - } else { - gen_op_movl_T0_cpsr(); - } - gen_movl_reg_T0(s, rd); - } - break; - case 0x1: - if (op1 == 1) { - /* branch/exchange thumb (bx). */ - gen_movl_T0_reg(s, rm); - gen_bx(s); - } else if (op1 == 3) { - /* clz */ - rd = (insn >> 12) & 0xf; - gen_movl_T0_reg(s, rm); - gen_op_clz_T0(); - gen_movl_reg_T0(s, rd); - } else { - goto illegal_op; - } - break; - case 0x2: - if (op1 == 1) { - ARCH(5J); /* bxj */ - /* Trivial implementation equivalent to bx. */ - gen_movl_T0_reg(s, rm); - gen_bx(s); - } else { - goto illegal_op; - } - break; - case 0x3: - if (op1 != 1) - goto illegal_op; +}; - /* branch link/exchange thumb (blx) */ - val = (uint32_t)s->pc; - gen_op_movl_T1_im(val); - gen_movl_T0_reg(s, rm); - gen_movl_reg_T1(s, 14); - gen_bx(s); - break; - case 0x5: /* saturating add/subtract */ - rd = (insn >> 12) & 0xf; - rn = (insn >> 16) & 0xf; - gen_movl_T0_reg(s, rm); +static inline void +gen_op_neon_narrow_u32 () +{ + /* No-op. */ +} + +static GenOpFunc *gen_neon_narrow[3] = { + gen_op_neon_narrow_u8, + gen_op_neon_narrow_u16, + gen_op_neon_narrow_u32 +}; + +static GenOpFunc *gen_neon_narrow_satu[3] = { + gen_op_neon_narrow_sat_u8, + gen_op_neon_narrow_sat_u16, + gen_op_neon_narrow_sat_u32 +}; + +static GenOpFunc *gen_neon_narrow_sats[3] = { + gen_op_neon_narrow_sat_s8, + gen_op_neon_narrow_sat_s16, + gen_op_neon_narrow_sat_s32 +}; + +static inline int gen_neon_add(int size) +{ + switch (size) { + case 0: gen_op_neon_add_u8(); break; + case 1: gen_op_neon_add_u16(); break; + case 2: gen_op_addl_T0_T1(); break; + default: return 1; + } + return 0; +} + +/* 32-bit pairwise ops end up the same as the elementsise versions. */ +#define gen_op_neon_pmax_s32 gen_op_neon_max_s32 +#define gen_op_neon_pmax_u32 gen_op_neon_max_u32 +#define gen_op_neon_pmin_s32 gen_op_neon_min_s32 +#define gen_op_neon_pmin_u32 gen_op_neon_min_u32 + +#define GEN_NEON_INTEGER_OP(name) do { \ + switch ((size << 1) | u) { \ + case 0: gen_op_neon_##name##_s8(); break; \ + case 1: gen_op_neon_##name##_u8(); break; \ + case 2: gen_op_neon_##name##_s16(); break; \ + case 3: gen_op_neon_##name##_u16(); break; \ + case 4: gen_op_neon_##name##_s32(); break; \ + case 5: gen_op_neon_##name##_u32(); break; \ + default: return 1; \ + }} while (0) + +static inline void +gen_neon_movl_scratch_T0(int scratch) +{ + uint32_t offset; + + offset = offsetof(CPUARMState, vfp.scratch[scratch]); + gen_op_neon_setreg_T0(offset); +} + +static inline void +gen_neon_movl_scratch_T1(int scratch) +{ + uint32_t offset; + + offset = offsetof(CPUARMState, vfp.scratch[scratch]); + gen_op_neon_setreg_T1(offset); +} + +static inline void +gen_neon_movl_T0_scratch(int scratch) +{ + uint32_t offset; + + offset = offsetof(CPUARMState, vfp.scratch[scratch]); + gen_op_neon_getreg_T0(offset); +} + +static inline void +gen_neon_movl_T1_scratch(int scratch) +{ + uint32_t offset; + + offset = offsetof(CPUARMState, vfp.scratch[scratch]); + gen_op_neon_getreg_T1(offset); +} + +static inline void gen_op_neon_widen_u32(void) +{ + gen_op_movl_T1_im(0); +} + +static inline void gen_neon_get_scalar(int size, int reg) +{ + if (size == 1) { + NEON_GET_REG(T0, reg >> 1, reg & 1); + } else { + NEON_GET_REG(T0, reg >> 2, (reg >> 1) & 1); + if (reg & 1) + gen_op_neon_dup_low16(); + else + gen_op_neon_dup_high16(); + } +} + +static void gen_neon_unzip(int reg, int q, int tmp, int size) +{ + int n; + + for (n = 0; n < q + 1; n += 2) { + NEON_GET_REG(T0, reg, n); + NEON_GET_REG(T0, reg, n + n); + switch (size) { + case 0: gen_op_neon_unzip_u8(); break; + case 1: gen_op_neon_zip_u16(); break; /* zip and unzip are the same. */ + case 2: /* no-op */; break; + default: abort(); + } + gen_neon_movl_scratch_T0(tmp + n); + gen_neon_movl_scratch_T1(tmp + n + 1); + } +} + +static struct { + int nregs; + int interleave; + int spacing; +} neon_ls_element_type[11] = { + {4, 4, 1}, + {4, 4, 2}, + {4, 1, 1}, + {4, 2, 1}, + {3, 3, 1}, + {3, 3, 2}, + {3, 1, 1}, + {1, 1, 1}, + {2, 2, 1}, + {2, 2, 2}, + {2, 1, 1} +}; + +/* Translate a NEON load/store element instruction. Return nonzero if the + instruction is invalid. */ +static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int rd, rn, rm; + int op; + int nregs; + int interleave; + int stride; + int size; + int reg; + int pass; + int load; + int shift; + uint32_t mask; + int n; + + if (!vfp_enabled(env)) + return 1; + VFP_DREG_D(rd, insn); + rn = (insn >> 16) & 0xf; + rm = insn & 0xf; + load = (insn & (1 << 21)) != 0; + if ((insn & (1 << 23)) == 0) { + /* Load store all elements. */ + op = (insn >> 8) & 0xf; + size = (insn >> 6) & 3; + if (op > 10 || size == 3) + return 1; + nregs = neon_ls_element_type[op].nregs; + interleave = neon_ls_element_type[op].interleave; + gen_movl_T1_reg(s, rn); + stride = (1 << size) * interleave; + for (reg = 0; reg < nregs; reg++) { + if (interleave > 2 || (interleave == 2 && nregs == 2)) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T1_im((1 << size) * reg); + } else if (interleave == 2 && nregs == 4 && reg == 2) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T1_im(1 << size); + } + for (pass = 0; pass < 2; pass++) { + if (size == 2) { + if (load) { + gen_ldst(ldl, s); + NEON_SET_REG(T0, rd, pass); + } else { + NEON_GET_REG(T0, rd, pass); + gen_ldst(stl, s); + } + gen_op_addl_T1_im(stride); + } else if (size == 1) { + if (load) { + gen_ldst(lduw, s); + gen_op_addl_T1_im(stride); + gen_op_movl_T2_T0(); + gen_ldst(lduw, s); + gen_op_addl_T1_im(stride); + gen_op_neon_insert_elt(16, 0xffff); + NEON_SET_REG(T2, rd, pass); + } else { + NEON_GET_REG(T2, rd, pass); + gen_op_movl_T0_T2(); + gen_ldst(stw, s); + gen_op_addl_T1_im(stride); + gen_op_neon_extract_elt(16, 0xffff0000); + gen_ldst(stw, s); + gen_op_addl_T1_im(stride); + } + } else /* size == 0 */ { + if (load) { + mask = 0xff; + for (n = 0; n < 4; n++) { + gen_ldst(ldub, s); + gen_op_addl_T1_im(stride); + if (n == 0) { + gen_op_movl_T2_T0(); + } else { + gen_op_neon_insert_elt(n * 8, ~mask); + } + mask <<= 8; + } + NEON_SET_REG(T2, rd, pass); + } else { + NEON_GET_REG(T2, rd, pass); + mask = 0xff; + for (n = 0; n < 4; n++) { + if (n == 0) { + gen_op_movl_T0_T2(); + } else { + gen_op_neon_extract_elt(n * 8, mask); + } + gen_ldst(stb, s); + gen_op_addl_T1_im(stride); + mask <<= 8; + } + } + } + } + rd += neon_ls_element_type[op].spacing; + } + stride = nregs * 8; + } else { + size = (insn >> 10) & 3; + if (size == 3) { + /* Load single element to all lanes. */ + if (!load) + return 1; + size = (insn >> 6) & 3; + nregs = ((insn >> 8) & 3) + 1; + stride = (insn & (1 << 5)) ? 2 : 1; gen_movl_T1_reg(s, rn); - if (op1 & 2) - gen_op_double_T1_saturate(); - if (op1 & 1) - gen_op_subl_T0_T1_saturate(); - else - gen_op_addl_T0_T1_saturate(); - gen_movl_reg_T0(s, rd); - break; - case 7: /* bkpt */ - gen_op_movl_T0_im((long)s->pc - 4); - gen_op_movl_reg_TN[0][15](); - gen_op_bkpt(); - s->is_jmp = DISAS_JUMP; - break; - case 0x8: /* signed multiply */ - case 0xa: - case 0xc: - case 0xe: - rs = (insn >> 8) & 0xf; - rn = (insn >> 12) & 0xf; - rd = (insn >> 16) & 0xf; - if (op1 == 1) { - /* (32 * 16) >> 16 */ - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rs); - if (sh & 4) - gen_op_sarl_T1_im(16); - else - gen_op_sxth_T1(); - gen_op_imulw_T0_T1(); - if ((sh & 2) == 0) { - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1_setq(); + for (reg = 0; reg < nregs; reg++) { + switch (size) { + case 0: + gen_ldst(ldub, s); + gen_op_neon_dup_u8(0); + break; + case 1: + gen_ldst(lduw, s); + gen_op_neon_dup_low16(); + break; + case 2: + gen_ldst(ldl, s); + break; + case 3: + return 1; } - gen_movl_reg_T0(s, rd); - } else { - /* 16 * 16 */ - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rs); - gen_mulxy(sh & 2, sh & 4); - if (op1 == 2) { - gen_op_signbit_T1_T0(); - gen_op_addq_T0_T1(rn, rd); - gen_movl_reg_T0(s, rn); - gen_movl_reg_T1(s, rd); - } else { - if (op1 == 0) { - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1_setq(); + gen_op_addl_T1_im(1 << size); + NEON_SET_REG(T0, rd, 0); + NEON_SET_REG(T0, rd, 1); + rd += stride; + } + stride = (1 << size) * nregs; + } else { + /* Single element. */ + pass = (insn >> 7) & 1; + switch (size) { + case 0: + shift = ((insn >> 5) & 3) * 8; + mask = 0xff << shift; + stride = 1; + break; + case 1: + shift = ((insn >> 6) & 1) * 16; + mask = shift ? 0xffff0000 : 0xffff; + stride = (insn & (1 << 5)) ? 2 : 1; + break; + case 2: + shift = 0; + mask = 0xffffffff; + stride = (insn & (1 << 6)) ? 2 : 1; + break; + default: + abort(); + } + nregs = ((insn >> 8) & 3) + 1; + gen_movl_T1_reg(s, rn); + for (reg = 0; reg < nregs; reg++) { + if (load) { + if (size != 2) { + NEON_GET_REG(T2, rd, pass); + } + switch (size) { + case 0: + gen_ldst(ldub, s); + break; + case 1: + gen_ldst(lduw, s); + break; + case 2: + gen_ldst(ldl, s); + NEON_SET_REG(T0, rd, pass); + break; + } + if (size != 2) { + gen_op_neon_insert_elt(shift, ~mask); + NEON_SET_REG(T0, rd, pass); + } + } else { /* Store */ + if (size == 2) { + NEON_GET_REG(T0, rd, pass); + } else { + NEON_GET_REG(T2, rd, pass); + gen_op_neon_extract_elt(shift, mask); + } + switch (size) { + case 0: + gen_ldst(stb, s); + break; + case 1: + gen_ldst(stw, s); + break; + case 2: + gen_ldst(stl, s); + break; } - gen_movl_reg_T0(s, rd); } + rd += stride; + gen_op_addl_T1_im(1 << size); } - break; - default: - goto illegal_op; + stride = nregs * (1 << size); } - } else if (((insn & 0x0e000000) == 0 && - (insn & 0x00000090) != 0x90) || - ((insn & 0x0e000000) == (1 << 25))) { - int set_cc, logic_cc, shiftop; + } + if (rm != 15) { + gen_movl_T1_reg(s, rn); + if (rm == 13) { + gen_op_addl_T1_im(stride); + } else { + gen_movl_T2_reg(s, rm); + gen_op_addl_T1_T2(); + } + gen_movl_reg_T1(s, rn); + } + return 0; +} - op1 = (insn >> 21) & 0xf; - set_cc = (insn >> 20) & 1; - logic_cc = table_logic_cc[op1] & set_cc; +/* Translate a NEON data processing instruction. Return nonzero if the + instruction is invalid. + In general we process vectors in 32-bit chunks. This means we can reuse + some of the scalar ops, and hopefully the code generated for 32-bit + hosts won't be too awful. The downside is that the few 64-bit operations + (mainly shifts) get complicated. */ - /* data processing instruction */ - if (insn & (1 << 25)) { - /* immediate operand */ - val = insn & 0xff; - shift = ((insn >> 8) & 0xf) * 2; - if (shift) - val = (val >> shift) | (val << (32 - shift)); - gen_op_movl_T1_im(val); - if (logic_cc && shift) - gen_op_mov_CF_T1(); - } else { - /* register */ - rm = (insn) & 0xf; - gen_movl_T1_reg(s, rm); - shiftop = (insn >> 5) & 3; - if (!(insn & (1 << 4))) { - shift = (insn >> 7) & 0x1f; - if (shift != 0) { - if (logic_cc) { - gen_shift_T1_im_cc[shiftop](shift); +static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int op; + int q; + int rd, rn, rm; + int size; + int shift; + int pass; + int count; + int pairwise; + int u; + int n; + uint32_t imm; + + if (!vfp_enabled(env)) + return 1; + q = (insn & (1 << 6)) != 0; + u = (insn >> 24) & 1; + VFP_DREG_D(rd, insn); + VFP_DREG_N(rn, insn); + VFP_DREG_M(rm, insn); + size = (insn >> 20) & 3; + if ((insn & (1 << 23)) == 0) { + /* Three register same length. */ + op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1); + if (size == 3 && (op == 1 || op == 5 || op == 16)) { + for (pass = 0; pass < (q ? 2 : 1); pass++) { + NEON_GET_REG(T0, rm, pass * 2); + NEON_GET_REG(T1, rm, pass * 2 + 1); + gen_neon_movl_scratch_T0(0); + gen_neon_movl_scratch_T1(1); + NEON_GET_REG(T0, rn, pass * 2); + NEON_GET_REG(T1, rn, pass * 2 + 1); + switch (op) { + case 1: /* VQADD */ + if (u) { + gen_op_neon_addl_saturate_u64(); } else { - gen_shift_T1_im[shiftop](shift); + gen_op_neon_addl_saturate_s64(); } - } else if (shiftop != 0) { - if (logic_cc) { - gen_shift_T1_0_cc[shiftop](); + break; + case 5: /* VQSUB */ + if (u) { + gen_op_neon_subl_saturate_u64(); } else { - gen_shift_T1_0[shiftop](); + gen_op_neon_subl_saturate_s64(); } + break; + case 16: + if (u) { + gen_op_neon_subl_u64(); + } else { + gen_op_neon_addl_u64(); + } + break; + default: + abort(); } - } else { - rs = (insn >> 8) & 0xf; - gen_movl_T0_reg(s, rs); - if (logic_cc) { - gen_shift_T1_T0_cc[shiftop](); - } else { - gen_shift_T1_T0[shiftop](); - } + NEON_SET_REG(T0, rd, pass * 2); + NEON_SET_REG(T1, rd, pass * 2 + 1); } + return 0; } - if (op1 != 0x0f && op1 != 0x0d) { - rn = (insn >> 16) & 0xf; - gen_movl_T0_reg(s, rn); - } - rd = (insn >> 12) & 0xf; - switch(op1) { - case 0x00: - gen_op_andl_T0_T1(); - gen_movl_reg_T0(s, rd); - if (logic_cc) - gen_op_logic_T0_cc(); + switch (op) { + case 8: /* VSHL */ + case 9: /* VQSHL */ + case 10: /* VRSHL */ + case 11: /* VQSHL */ + /* Shift operations have Rn and Rm reversed. */ + { + int tmp; + tmp = rn; + rn = rm; + rm = tmp; + pairwise = 0; + } break; - case 0x01: - gen_op_xorl_T0_T1(); - gen_movl_reg_T0(s, rd); - if (logic_cc) - gen_op_logic_T0_cc(); + case 20: /* VPMAX */ + case 21: /* VPMIN */ + case 23: /* VPADD */ + pairwise = 1; break; - case 0x02: - if (set_cc && rd == 15) { - /* SUBS r15, ... is used for exception return. */ - if (IS_USER(s)) - goto illegal_op; - gen_op_subl_T0_T1_cc(); - gen_exception_return(s); - } else { - if (set_cc) - gen_op_subl_T0_T1_cc(); - else - gen_op_subl_T0_T1(); - gen_movl_reg_T0(s, rd); - } + case 26: /* VPADD (float) */ + pairwise = (u && size < 2); break; - case 0x03: - if (set_cc) - gen_op_rsbl_T0_T1_cc(); - else - gen_op_rsbl_T0_T1(); - gen_movl_reg_T0(s, rd); - break; - case 0x04: - if (set_cc) - gen_op_addl_T0_T1_cc(); - else - gen_op_addl_T0_T1(); - gen_movl_reg_T0(s, rd); + case 30: /* VPMIN/VPMAX (float) */ + pairwise = u; break; - case 0x05: - if (set_cc) - gen_op_adcl_T0_T1_cc(); - else - gen_op_adcl_T0_T1(); - gen_movl_reg_T0(s, rd); + default: + pairwise = 0; break; - case 0x06: - if (set_cc) - gen_op_sbcl_T0_T1_cc(); + } + for (pass = 0; pass < (q ? 4 : 2); pass++) { + + if (pairwise) { + /* Pairwise. */ + if (q) + n = (pass & 1) * 2; else - gen_op_sbcl_T0_T1(); - gen_movl_reg_T0(s, rd); + n = 0; + if (pass < q + 1) { + NEON_GET_REG(T0, rn, n); + NEON_GET_REG(T1, rn, n + 1); + } else { + NEON_GET_REG(T0, rm, n); + NEON_GET_REG(T1, rm, n + 1); + } + } else { + /* Elementwise. */ + NEON_GET_REG(T0, rn, pass); + NEON_GET_REG(T1, rm, pass); + } + switch (op) { + case 0: /* VHADD */ + GEN_NEON_INTEGER_OP(hadd); + break; + case 1: /* VQADD */ + switch (size << 1| u) { + case 0: gen_op_neon_qadd_s8(); break; + case 1: gen_op_neon_qadd_u8(); break; + case 2: gen_op_neon_qadd_s16(); break; + case 3: gen_op_neon_qadd_u16(); break; + case 4: gen_op_addl_T0_T1_saturate(); break; + case 5: gen_op_addl_T0_T1_usaturate(); break; + default: abort(); + } break; - case 0x07: - if (set_cc) - gen_op_rscl_T0_T1_cc(); - else - gen_op_rscl_T0_T1(); - gen_movl_reg_T0(s, rd); + case 2: /* VRHADD */ + GEN_NEON_INTEGER_OP(rhadd); break; - case 0x08: - if (set_cc) { + case 3: /* Logic ops. */ + switch ((u << 2) | size) { + case 0: /* VAND */ gen_op_andl_T0_T1(); - gen_op_logic_T0_cc(); + break; + case 1: /* BIC */ + gen_op_bicl_T0_T1(); + break; + case 2: /* VORR */ + gen_op_orl_T0_T1(); + break; + case 3: /* VORN */ + gen_op_notl_T1(); + gen_op_orl_T0_T1(); + break; + case 4: /* VEOR */ + gen_op_xorl_T0_T1(); + break; + case 5: /* VBSL */ + NEON_GET_REG(T2, rd, pass); + gen_op_neon_bsl(); + break; + case 6: /* VBIT */ + NEON_GET_REG(T2, rd, pass); + gen_op_neon_bit(); + break; + case 7: /* VBIF */ + NEON_GET_REG(T2, rd, pass); + gen_op_neon_bif(); + break; } break; - case 0x09: - if (set_cc) { - gen_op_xorl_T0_T1(); - gen_op_logic_T0_cc(); + case 4: /* VHSUB */ + GEN_NEON_INTEGER_OP(hsub); + break; + case 5: /* VQSUB */ + switch ((size << 1) | u) { + case 0: gen_op_neon_qsub_s8(); break; + case 1: gen_op_neon_qsub_u8(); break; + case 2: gen_op_neon_qsub_s16(); break; + case 3: gen_op_neon_qsub_u16(); break; + case 4: gen_op_subl_T0_T1_saturate(); break; + case 5: gen_op_subl_T0_T1_usaturate(); break; + default: abort(); } break; - case 0x0a: - if (set_cc) { - gen_op_subl_T0_T1_cc(); + case 6: /* VCGT */ + GEN_NEON_INTEGER_OP(cgt); + break; + case 7: /* VCGE */ + GEN_NEON_INTEGER_OP(cge); + break; + case 8: /* VSHL */ + switch ((size << 1) | u) { + case 0: gen_op_neon_shl_s8(); break; + case 1: gen_op_neon_shl_u8(); break; + case 2: gen_op_neon_shl_s16(); break; + case 3: gen_op_neon_shl_u16(); break; + case 4: gen_op_neon_shl_s32(); break; + case 5: gen_op_neon_shl_u32(); break; +#if 0 + /* ??? Implementing these is tricky because the vector ops work + on 32-bit pieces. */ + case 6: gen_op_neon_shl_s64(); break; + case 7: gen_op_neon_shl_u64(); break; +#else + case 6: case 7: cpu_abort(env, "VSHL.64 not implemented"); +#endif } break; - case 0x0b: - if (set_cc) { - gen_op_addl_T0_T1_cc(); + case 9: /* VQSHL */ + switch ((size << 1) | u) { + case 0: gen_op_neon_qshl_s8(); break; + case 1: gen_op_neon_qshl_u8(); break; + case 2: gen_op_neon_qshl_s16(); break; + case 3: gen_op_neon_qshl_u16(); break; + case 4: gen_op_neon_qshl_s32(); break; + case 5: gen_op_neon_qshl_u32(); break; +#if 0 + /* ??? Implementing these is tricky because the vector ops work + on 32-bit pieces. */ + case 6: gen_op_neon_qshl_s64(); break; + case 7: gen_op_neon_qshl_u64(); break; +#else + case 6: case 7: cpu_abort(env, "VQSHL.64 not implemented"); +#endif } break; - case 0x0c: - gen_op_orl_T0_T1(); - gen_movl_reg_T0(s, rd); - if (logic_cc) - gen_op_logic_T0_cc(); + case 10: /* VRSHL */ + switch ((size << 1) | u) { + case 0: gen_op_neon_rshl_s8(); break; + case 1: gen_op_neon_rshl_u8(); break; + case 2: gen_op_neon_rshl_s16(); break; + case 3: gen_op_neon_rshl_u16(); break; + case 4: gen_op_neon_rshl_s32(); break; + case 5: gen_op_neon_rshl_u32(); break; +#if 0 + /* ??? Implementing these is tricky because the vector ops work + on 32-bit pieces. */ + case 6: gen_op_neon_rshl_s64(); break; + case 7: gen_op_neon_rshl_u64(); break; +#else + case 6: case 7: cpu_abort(env, "VRSHL.64 not implemented"); +#endif + } break; - case 0x0d: - if (logic_cc && rd == 15) { - /* MOVS r15, ... is used for exception return. */ - if (IS_USER(s)) - goto illegal_op; - gen_op_movl_T0_T1(); - gen_exception_return(s); + case 11: /* VQRSHL */ + switch ((size << 1) | u) { + case 0: gen_op_neon_qrshl_s8(); break; + case 1: gen_op_neon_qrshl_u8(); break; + case 2: gen_op_neon_qrshl_s16(); break; + case 3: gen_op_neon_qrshl_u16(); break; + case 4: gen_op_neon_qrshl_s32(); break; + case 5: gen_op_neon_qrshl_u32(); break; +#if 0 + /* ??? Implementing these is tricky because the vector ops work + on 32-bit pieces. */ + case 6: gen_op_neon_qrshl_s64(); break; + case 7: gen_op_neon_qrshl_u64(); break; +#else + case 6: case 7: cpu_abort(env, "VQRSHL.64 not implemented"); +#endif + } + break; + case 12: /* VMAX */ + GEN_NEON_INTEGER_OP(max); + break; + case 13: /* VMIN */ + GEN_NEON_INTEGER_OP(min); + break; + case 14: /* VABD */ + GEN_NEON_INTEGER_OP(abd); + break; + case 15: /* VABA */ + GEN_NEON_INTEGER_OP(abd); + NEON_GET_REG(T1, rd, pass); + gen_neon_add(size); + break; + case 16: + if (!u) { /* VADD */ + if (gen_neon_add(size)) + return 1; + } else { /* VSUB */ + switch (size) { + case 0: gen_op_neon_sub_u8(); break; + case 1: gen_op_neon_sub_u16(); break; + case 2: gen_op_subl_T0_T1(); break; + default: return 1; + } + } + break; + case 17: + if (!u) { /* VTST */ + switch (size) { + case 0: gen_op_neon_tst_u8(); break; + case 1: gen_op_neon_tst_u16(); break; + case 2: gen_op_neon_tst_u32(); break; + default: return 1; + } + } else { /* VCEQ */ + switch (size) { + case 0: gen_op_neon_ceq_u8(); break; + case 1: gen_op_neon_ceq_u16(); break; + case 2: gen_op_neon_ceq_u32(); break; + default: return 1; + } + } + break; + case 18: /* Multiply. */ + switch (size) { + case 0: gen_op_neon_mul_u8(); break; + case 1: gen_op_neon_mul_u16(); break; + case 2: gen_op_mul_T0_T1(); break; + default: return 1; + } + NEON_GET_REG(T1, rd, pass); + if (u) { /* VMLS */ + switch (size) { + case 0: gen_op_neon_rsb_u8(); break; + case 1: gen_op_neon_rsb_u16(); break; + case 2: gen_op_rsbl_T0_T1(); break; + default: return 1; + } + } else { /* VMLA */ + gen_neon_add(size); + } + break; + case 19: /* VMUL */ + if (u) { /* polynomial */ + gen_op_neon_mul_p8(); + } else { /* Integer */ + switch (size) { + case 0: gen_op_neon_mul_u8(); break; + case 1: gen_op_neon_mul_u16(); break; + case 2: gen_op_mul_T0_T1(); break; + default: return 1; + } + } + break; + case 20: /* VPMAX */ + GEN_NEON_INTEGER_OP(pmax); + break; + case 21: /* VPMIN */ + GEN_NEON_INTEGER_OP(pmin); + break; + case 22: /* Hultiply high. */ + if (!u) { /* VQDMULH */ + switch (size) { + case 1: gen_op_neon_qdmulh_s16(); break; + case 2: gen_op_neon_qdmulh_s32(); break; + default: return 1; + } + } else { /* VQRDHMUL */ + switch (size) { + case 1: gen_op_neon_qrdmulh_s16(); break; + case 2: gen_op_neon_qrdmulh_s32(); break; + default: return 1; + } + } + break; + case 23: /* VPADD */ + if (u) + return 1; + switch (size) { + case 0: gen_op_neon_padd_u8(); break; + case 1: gen_op_neon_padd_u16(); break; + case 2: gen_op_addl_T0_T1(); break; + default: return 1; + } + break; + case 26: /* Floating point arithnetic. */ + switch ((u << 2) | size) { + case 0: /* VADD */ + gen_op_neon_add_f32(); + break; + case 2: /* VSUB */ + gen_op_neon_sub_f32(); + break; + case 4: /* VPADD */ + gen_op_neon_add_f32(); + break; + case 6: /* VABD */ + gen_op_neon_abd_f32(); + break; + default: + return 1; + } + break; + case 27: /* Float multiply. */ + gen_op_neon_mul_f32(); + if (!u) { + NEON_GET_REG(T1, rd, pass); + if (size == 0) { + gen_op_neon_add_f32(); + } else { + gen_op_neon_rsb_f32(); + } + } + break; + case 28: /* Float compare. */ + if (!u) { + gen_op_neon_ceq_f32(); } else { - gen_movl_reg_T1(s, rd); - if (logic_cc) - gen_op_logic_T1_cc(); + if (size == 0) + gen_op_neon_cge_f32(); + else + gen_op_neon_cgt_f32(); } break; - case 0x0e: - gen_op_bicl_T0_T1(); - gen_movl_reg_T0(s, rd); - if (logic_cc) - gen_op_logic_T0_cc(); + case 29: /* Float compare absolute. */ + if (!u) + return 1; + if (size == 0) + gen_op_neon_acge_f32(); + else + gen_op_neon_acgt_f32(); break; - default: - case 0x0f: - gen_op_notl_T1(); - gen_movl_reg_T1(s, rd); - if (logic_cc) - gen_op_logic_T1_cc(); + case 30: /* Float min/max. */ + if (size == 0) + gen_op_neon_max_f32(); + else + gen_op_neon_min_f32(); + break; + case 31: + if (size == 0) + gen_op_neon_recps_f32(); + else + gen_op_neon_rsqrts_f32(); break; + default: + abort(); } - } else { - /* other instructions */ - op1 = (insn >> 24) & 0xf; - switch(op1) { - case 0x0: - case 0x1: - /* multiplies, extra load/stores */ - sh = (insn >> 5) & 3; - if (sh == 0) { - if (op1 == 0x0) { - rd = (insn >> 16) & 0xf; - rn = (insn >> 12) & 0xf; - rs = (insn >> 8) & 0xf; - rm = (insn) & 0xf; - if (((insn >> 22) & 3) == 0) { - /* 32 bit mul */ - gen_movl_T0_reg(s, rs); - gen_movl_T1_reg(s, rm); - gen_op_mul_T0_T1(); - if (insn & (1 << 21)) { - gen_movl_T1_reg(s, rn); - gen_op_addl_T0_T1(); - } - if (insn & (1 << 20)) - gen_op_logic_T0_cc(); - gen_movl_reg_T0(s, rd); + /* Save the result. For elementwise operations we can put it + straight into the destination register. For pairwise operations + we have to be careful to avoid clobbering the source operands. */ + if (pairwise && rd == rm) { + gen_neon_movl_scratch_T0(pass); + } else { + NEON_SET_REG(T0, rd, pass); + } + + } /* for pass */ + if (pairwise && rd == rm) { + for (pass = 0; pass < (q ? 4 : 2); pass++) { + gen_neon_movl_T0_scratch(pass); + NEON_SET_REG(T0, rd, pass); + } + } + } else if (insn & (1 << 4)) { + if ((insn & 0x00380080) != 0) { + /* Two registers and shift. */ + op = (insn >> 8) & 0xf; + if (insn & (1 << 7)) { + /* 64-bit shift. */ + size = 3; + } else { + size = 2; + while ((insn & (1 << (size + 19))) == 0) + size--; + } + shift = (insn >> 16) & ((1 << (3 + size)) - 1); + /* To avoid excessive dumplication of ops we implement shift + by immediate using the variable shift operations. */ + if (op < 8) { + /* Shift by immediate: + VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */ + /* Right shifts are encoded as N - shift, where N is the + element size in bits. */ + if (op <= 4) + shift = shift - (1 << (size + 3)); + else + shift++; + if (size == 3) { + count = q + 1; + } else { + count = q ? 4: 2; + } + switch (size) { + case 0: + imm = (uint8_t) shift; + imm |= imm << 8; + imm |= imm << 16; + break; + case 1: + imm = (uint16_t) shift; + imm |= imm << 16; + break; + case 2: + case 3: + imm = shift; + break; + default: + abort(); + } + + for (pass = 0; pass < count; pass++) { + if (size < 3) { + /* Operands in T0 and T1. */ + gen_op_movl_T1_im(imm); + NEON_GET_REG(T0, rm, pass); } else { - /* 64 bit mul */ - gen_movl_T0_reg(s, rs); - gen_movl_T1_reg(s, rm); - if (insn & (1 << 22)) - gen_op_imull_T0_T1(); - else - gen_op_mull_T0_T1(); - if (insn & (1 << 21)) /* mult accumulate */ - gen_op_addq_T0_T1(rn, rd); - if (!(insn & (1 << 23))) { /* double accumulate */ - ARCH(6); - gen_op_addq_lo_T0_T1(rn); - gen_op_addq_lo_T0_T1(rd); + /* Operands in {T0, T1} and env->vfp.scratch. */ + gen_op_movl_T0_im(imm); + gen_neon_movl_scratch_T0(0); + gen_op_movl_T0_im((int32_t)imm >> 31); + gen_neon_movl_scratch_T0(1); + NEON_GET_REG(T0, rm, pass * 2); + NEON_GET_REG(T1, rm, pass * 2 + 1); + } + + if (gen_neon_shift_im[op][u][size] == NULL) + return 1; + gen_neon_shift_im[op][u][size](); + + if (op == 1 || op == 3) { + /* Accumulate. */ + if (size == 3) { + gen_neon_movl_scratch_T0(0); + gen_neon_movl_scratch_T1(1); + NEON_GET_REG(T0, rd, pass * 2); + NEON_GET_REG(T1, rd, pass * 2 + 1); + gen_op_neon_addl_u64(); + } else { + NEON_GET_REG(T1, rd, pass); + gen_neon_add(size); } - if (insn & (1 << 20)) - gen_op_logicq_cc(); - gen_movl_reg_T0(s, rn); - gen_movl_reg_T1(s, rd); + } else if (op == 4 || (op == 5 && u)) { + /* Insert */ + if (size == 3) { + cpu_abort(env, "VS[LR]I.64 not implemented"); + } + switch (size) { + case 0: + if (op == 4) + imm = 0xff >> -shift; + else + imm = (uint8_t)(0xff << shift); + imm |= imm << 8; + imm |= imm << 16; + break; + case 1: + if (op == 4) + imm = 0xffff >> -shift; + else + imm = (uint16_t)(0xffff << shift); + imm |= imm << 16; + break; + case 2: + if (op == 4) + imm = 0xffffffffu >> -shift; + else + imm = 0xffffffffu << shift; + break; + default: + abort(); + } + NEON_GET_REG(T1, rd, pass); + gen_op_movl_T2_im(imm); + gen_op_neon_bsl(); } + if (size == 3) { + NEON_SET_REG(T0, rd, pass * 2); + NEON_SET_REG(T1, rd, pass * 2 + 1); + } else { + NEON_SET_REG(T0, rd, pass); + } + } /* for pass */ + } else if (op < 10) { + /* Shift by immedaiate and narrow: + VSHRN, VRSHRN, VQSHRN, VQRSHRN. */ + shift = shift - (1 << (size + 3)); + size++; + if (size == 3) { + count = q + 1; } else { - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - if (insn & (1 << 23)) { - /* load/store exclusive */ - goto illegal_op; + count = q ? 4: 2; + } + switch (size) { + case 1: + imm = (uint16_t) shift; + imm |= imm << 16; + break; + case 2: + case 3: + imm = shift; + break; + default: + abort(); + } + + /* Processing MSB first means we need to do less shuffling at + the end. */ + for (pass = count - 1; pass >= 0; pass--) { + /* Avoid clobbering the second operand before it has been + written. */ + n = pass; + if (rd == rm) + n ^= (count - 1); + else + n = pass; + + if (size < 3) { + /* Operands in T0 and T1. */ + gen_op_movl_T1_im(imm); + NEON_GET_REG(T0, rm, n); } else { - /* SWP instruction */ - rm = (insn) & 0xf; + /* Operands in {T0, T1} and env->vfp.scratch. */ + gen_op_movl_T0_im(imm); + gen_neon_movl_scratch_T0(0); + gen_op_movl_T0_im((int32_t)imm >> 31); + gen_neon_movl_scratch_T0(1); + NEON_GET_REG(T0, rm, n * 2); + NEON_GET_REG(T0, rm, n * 2 + 1); + } - gen_movl_T0_reg(s, rm); - gen_movl_T1_reg(s, rn); - if (insn & (1 << 22)) { - gen_ldst(swpb, s); + gen_neon_shift_im_narrow[q][u][size - 1](); + + if (size < 3 && (pass & 1) == 0) { + gen_neon_movl_scratch_T0(0); + } else { + uint32_t offset; + + if (size < 3) + gen_neon_movl_T1_scratch(0); + + if (op == 8 && !u) { + gen_neon_narrow[size - 1](); } else { - gen_ldst(swpl, s); + if (op == 8) + gen_neon_narrow_sats[size - 2](); + else + gen_neon_narrow_satu[size - 1](); } - gen_movl_reg_T0(s, rd); + if (size == 3) + offset = neon_reg_offset(rd, n); + else + offset = neon_reg_offset(rd, n >> 1); + gen_op_neon_setreg_T0(offset); + } + } /* for pass */ + } else if (op == 10) { + /* VSHLL */ + if (q) + return 1; + for (pass = 0; pass < 2; pass++) { + /* Avoid clobbering the input operand. */ + if (rd == rm) + n = 1 - pass; + else + n = pass; + + NEON_GET_REG(T0, rm, n); + GEN_NEON_INTEGER_OP(widen); + if (shift != 0) { + /* The shift is less than the width of the source + type, so in some cases we can just + shift the whole register. */ + if (size == 1 || (size == 0 && u)) { + gen_op_shll_T0_im(shift); + gen_op_shll_T1_im(shift); + } else { + switch (size) { + case 0: gen_op_neon_shll_u16(shift); break; + case 2: gen_op_neon_shll_u64(shift); break; + default: abort(); + } + } + } + NEON_SET_REG(T0, rd, n * 2); + NEON_SET_REG(T1, rd, n * 2 + 1); + } + } else if (op == 15 || op == 16) { + /* VCVT fixed-point. */ + for (pass = 0; pass < (q ? 4 : 2); pass++) { + gen_op_vfp_getreg_F0s(neon_reg_offset(rm, pass)); + if (op & 1) { + if (u) + gen_op_vfp_ultos(shift); + else + gen_op_vfp_sltos(shift); + } else { + if (u) + gen_op_vfp_touls(shift); + else + gen_op_vfp_tosls(shift); } + gen_op_vfp_setreg_F0s(neon_reg_offset(rd, pass)); } } else { - int address_offset; - int load; - /* Misc load/store */ - rn = (insn >> 16) & 0xf; + return 1; + } + } else { /* (insn & 0x00380080) == 0 */ + int invert; + + op = (insn >> 8) & 0xf; + /* One register and immediate. */ + imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf); + invert = (insn & (1 << 5)) != 0; + switch (op) { + case 0: case 1: + /* no-op */ + break; + case 2: case 3: + imm <<= 8; + break; + case 4: case 5: + imm <<= 16; + break; + case 6: case 7: + imm <<= 24; + break; + case 8: case 9: + imm |= imm << 16; + break; + case 10: case 11: + imm = (imm << 8) | (imm << 24); + break; + case 12: + imm = (imm < 8) | 0xff; + break; + case 13: + imm = (imm << 16) | 0xffff; + break; + case 14: + imm |= (imm << 8) | (imm << 16) | (imm << 24); + if (invert) + imm = ~imm; + break; + case 15: + imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) + | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); + break; + } + if (invert) + imm = ~imm; + + if (op != 14 || !invert) + gen_op_movl_T1_im(imm); + + for (pass = 0; pass < (q ? 4 : 2); pass++) { + if (op & 1 && op < 12) { + NEON_GET_REG(T0, rd, pass); + if (invert) { + /* The immediate value has already been inverted, so + BIC becomes AND. */ + gen_op_andl_T0_T1(); + } else { + gen_op_orl_T0_T1(); + } + NEON_SET_REG(T0, rd, pass); + } else { + if (op == 14 && invert) { + uint32_t tmp; + tmp = 0; + for (n = 0; n < 4; n++) { + if (imm & (1 << (n + (pass & 1) * 4))) + tmp |= 0xff << (n * 8); + } + gen_op_movl_T1_im(tmp); + } + /* VMOV, VMVN. */ + NEON_SET_REG(T1, rd, pass); + } + } + } + } else { /* (insn & 0x00800010 == 0x00800010) */ + if (size != 3) { + op = (insn >> 8) & 0xf; + if ((insn & (1 << 6)) == 0) { + /* Three registers of different lengths. */ + int src1_wide; + int src2_wide; + int prewiden; + /* prewiden, src1_wide, src2_wide */ + static const int neon_3reg_wide[16][3] = { + {1, 0, 0}, /* VADDL */ + {1, 1, 0}, /* VADDW */ + {1, 0, 0}, /* VSUBL */ + {1, 1, 0}, /* VSUBW */ + {0, 1, 1}, /* VADDHN */ + {0, 0, 0}, /* VABAL */ + {0, 1, 1}, /* VSUBHN */ + {0, 0, 0}, /* VABDL */ + {0, 0, 0}, /* VMLAL */ + {0, 0, 0}, /* VQDMLAL */ + {0, 0, 0}, /* VMLSL */ + {0, 0, 0}, /* VQDMLSL */ + {0, 0, 0}, /* Integer VMULL */ + {0, 0, 0}, /* VQDMULL */ + {0, 0, 0} /* Polynomial VMULL */ + }; + + prewiden = neon_3reg_wide[op][0]; + src1_wide = neon_3reg_wide[op][1]; + src2_wide = neon_3reg_wide[op][2]; + + /* Avoid overlapping operands. Wide source operands are + always aligned so will never overlap with wide + destinations in problematic ways. */ + if (rd == rm) { + NEON_GET_REG(T2, rm, 1); + } else if (rd == rn) { + NEON_GET_REG(T2, rn, 1); + } + for (pass = 0; pass < 2; pass++) { + /* Load the second operand into env->vfp.scratch. + Also widen narrow operands. */ + if (pass == 1 && rd == rm) { + if (prewiden) { + gen_op_movl_T0_T2(); + } else { + gen_op_movl_T1_T2(); + } + } else { + if (src2_wide) { + NEON_GET_REG(T0, rm, pass * 2); + NEON_GET_REG(T1, rm, pass * 2 + 1); + } else { + if (prewiden) { + NEON_GET_REG(T0, rm, pass); + } else { + NEON_GET_REG(T1, rm, pass); + } + } + } + if (prewiden && !src2_wide) { + GEN_NEON_INTEGER_OP(widen); + } + if (prewiden || src2_wide) { + gen_neon_movl_scratch_T0(0); + gen_neon_movl_scratch_T1(1); + } + + /* Load the first operand. */ + if (pass == 1 && rd == rn) { + gen_op_movl_T0_T2(); + } else { + if (src1_wide) { + NEON_GET_REG(T0, rn, pass * 2); + NEON_GET_REG(T1, rn, pass * 2 + 1); + } else { + NEON_GET_REG(T0, rn, pass); + } + } + if (prewiden && !src1_wide) { + GEN_NEON_INTEGER_OP(widen); + } + switch (op) { + case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */ + switch (size) { + case 0: gen_op_neon_addl_u16(); break; + case 1: gen_op_neon_addl_u32(); break; + case 2: gen_op_neon_addl_u64(); break; + default: abort(); + } + break; + case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHL, VRSUBHL */ + switch (size) { + case 0: gen_op_neon_subl_u16(); break; + case 1: gen_op_neon_subl_u32(); break; + case 2: gen_op_neon_subl_u64(); break; + default: abort(); + } + break; + case 5: case 7: /* VABAL, VABDL */ + switch ((size << 1) | u) { + case 0: gen_op_neon_abdl_s16(); break; + case 1: gen_op_neon_abdl_u16(); break; + case 2: gen_op_neon_abdl_s32(); break; + case 3: gen_op_neon_abdl_u32(); break; + case 4: gen_op_neon_abdl_s64(); break; + case 5: gen_op_neon_abdl_u64(); break; + default: abort(); + } + break; + case 8: case 9: case 10: case 11: case 12: case 13: + /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */ + switch ((size << 1) | u) { + case 0: gen_op_neon_mull_s8(); break; + case 1: gen_op_neon_mull_u8(); break; + case 2: gen_op_neon_mull_s16(); break; + case 3: gen_op_neon_mull_u16(); break; + case 4: gen_op_imull_T0_T1(); break; + case 5: gen_op_mull_T0_T1(); break; + default: abort(); + } + break; + case 14: /* Polynomial VMULL */ + cpu_abort(env, "Polynomial VMULL not implemented"); + + default: /* 15 is RESERVED. */ + return 1; + } + if (op == 5 || op == 13 || (op >= 8 && op <= 11)) { + /* Accumulate. */ + if (op == 10 || op == 11) { + switch (size) { + case 0: gen_op_neon_negl_u16(); break; + case 1: gen_op_neon_negl_u32(); break; + case 2: gen_op_neon_negl_u64(); break; + default: abort(); + } + } + + gen_neon_movl_scratch_T0(0); + gen_neon_movl_scratch_T1(1); + + if (op != 13) { + NEON_GET_REG(T0, rd, pass * 2); + NEON_GET_REG(T1, rd, pass * 2 + 1); + } + + switch (op) { + case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */ + switch (size) { + case 0: gen_op_neon_addl_u16(); break; + case 1: gen_op_neon_addl_u32(); break; + case 2: gen_op_neon_addl_u64(); break; + default: abort(); + } + break; + case 9: case 11: /* VQDMLAL, VQDMLSL */ + switch (size) { + case 1: gen_op_neon_addl_saturate_s32(); break; + case 2: gen_op_neon_addl_saturate_s64(); break; + default: abort(); + } + /* Fall through. */ + case 13: /* VQDMULL */ + switch (size) { + case 1: gen_op_neon_addl_saturate_s32(); break; + case 2: gen_op_neon_addl_saturate_s64(); break; + default: abort(); + } + break; + default: + abort(); + } + NEON_SET_REG(T0, rd, pass * 2); + NEON_SET_REG(T1, rd, pass * 2 + 1); + } else if (op == 4 || op == 6) { + /* Narrowing operation. */ + if (u) { + switch (size) { + case 0: gen_op_neon_narrow_high_u8(); break; + case 1: gen_op_neon_narrow_high_u16(); break; + case 2: gen_op_movl_T0_T1(); break; + default: abort(); + } + } else { + switch (size) { + case 0: gen_op_neon_narrow_high_round_u8(); break; + case 1: gen_op_neon_narrow_high_round_u16(); break; + case 2: gen_op_neon_narrow_high_round_u32(); break; + default: abort(); + } + } + NEON_SET_REG(T0, rd, pass); + } else { + /* Write back the result. */ + NEON_SET_REG(T0, rd, pass * 2); + NEON_SET_REG(T1, rd, pass * 2 + 1); + } + } + } else { + /* Two registers and a scalar. */ + switch (op) { + case 0: /* Integer VMLA scalar */ + case 1: /* Float VMLA scalar */ + case 4: /* Integer VMLS scalar */ + case 5: /* Floating point VMLS scalar */ + case 8: /* Integer VMUL scalar */ + case 9: /* Floating point VMUL scalar */ + case 12: /* VQDMULH scalar */ + case 13: /* VQRDMULH scalar */ + gen_neon_get_scalar(size, rm); + gen_op_movl_T2_T0(); + for (pass = 0; pass < (u ? 4 : 2); pass++) { + if (pass != 0) + gen_op_movl_T0_T2(); + NEON_GET_REG(T1, rn, pass); + if (op == 12) { + if (size == 1) { + gen_op_neon_qdmulh_s16(); + } else { + gen_op_neon_qdmulh_s32(); + } + } else if (op == 13) { + if (size == 1) { + gen_op_neon_qrdmulh_s16(); + } else { + gen_op_neon_qrdmulh_s32(); + } + } else if (op & 1) { + gen_op_neon_mul_f32(); + } else { + switch (size) { + case 0: gen_op_neon_mul_u8(); break; + case 1: gen_op_neon_mul_u16(); break; + case 2: gen_op_mul_T0_T1(); break; + default: return 1; + } + } + if (op < 8) { + /* Accumulate. */ + NEON_GET_REG(T1, rd, pass); + switch (op) { + case 0: + gen_neon_add(size); + break; + case 1: + gen_op_neon_add_f32(); + break; + case 4: + switch (size) { + case 0: gen_op_neon_rsb_u8(); break; + case 1: gen_op_neon_rsb_u16(); break; + case 2: gen_op_rsbl_T0_T1(); break; + default: return 1; + } + break; + case 5: + gen_op_neon_rsb_f32(); + break; + default: + abort(); + } + } + NEON_SET_REG(T0, rd, pass); + } + break; + case 2: /* VMLAL sclar */ + case 3: /* VQDMLAL scalar */ + case 6: /* VMLSL scalar */ + case 7: /* VQDMLSL scalar */ + case 10: /* VMULL scalar */ + case 11: /* VQDMULL scalar */ + if (rd == rn) { + /* Save overlapping operands before they are + clobbered. */ + NEON_GET_REG(T0, rn, 1); + gen_neon_movl_scratch_T0(2); + } + gen_neon_get_scalar(size, rm); + gen_op_movl_T2_T0(); + for (pass = 0; pass < 2; pass++) { + if (pass != 0) { + gen_op_movl_T0_T2(); + } + if (pass != 0 && rd == rn) { + gen_neon_movl_T1_scratch(2); + } else { + NEON_GET_REG(T1, rn, pass); + } + switch ((size << 1) | u) { + case 0: gen_op_neon_mull_s8(); break; + case 1: gen_op_neon_mull_u8(); break; + case 2: gen_op_neon_mull_s16(); break; + case 3: gen_op_neon_mull_u16(); break; + case 4: gen_op_imull_T0_T1(); break; + case 5: gen_op_mull_T0_T1(); break; + default: abort(); + } + if (op == 6 || op == 7) { + switch (size) { + case 0: gen_op_neon_negl_u16(); break; + case 1: gen_op_neon_negl_u32(); break; + case 2: gen_op_neon_negl_u64(); break; + default: abort(); + } + } + gen_neon_movl_scratch_T0(0); + gen_neon_movl_scratch_T1(1); + NEON_GET_REG(T0, rd, pass * 2); + NEON_GET_REG(T1, rd, pass * 2 + 1); + switch (op) { + case 2: case 6: + switch (size) { + case 0: gen_op_neon_addl_u16(); break; + case 1: gen_op_neon_addl_u32(); break; + case 2: gen_op_neon_addl_u64(); break; + default: abort(); + } + break; + case 3: case 7: + switch (size) { + case 1: + gen_op_neon_addl_saturate_s32(); + gen_op_neon_addl_saturate_s32(); + break; + case 2: + gen_op_neon_addl_saturate_s64(); + gen_op_neon_addl_saturate_s64(); + break; + default: abort(); + } + break; + case 10: + /* no-op */ + break; + case 11: + switch (size) { + case 1: gen_op_neon_addl_saturate_s32(); break; + case 2: gen_op_neon_addl_saturate_s64(); break; + default: abort(); + } + break; + default: + abort(); + } + NEON_SET_REG(T0, rd, pass * 2); + NEON_SET_REG(T1, rd, pass * 2 + 1); + } + break; + default: /* 14 and 15 are RESERVED */ + return 1; + } + } + } else { /* size == 3 */ + if (!u) { + /* Extract. */ + int reg; + imm = (insn >> 8) & 0xf; + reg = rn; + count = q ? 4 : 2; + n = imm >> 2; + NEON_GET_REG(T0, reg, n); + for (pass = 0; pass < count; pass++) { + n++; + if (n > count) { + reg = rm; + n -= count; + } + if (imm & 3) { + NEON_GET_REG(T1, reg, n); + gen_op_neon_extract((insn << 3) & 0x1f); + } + /* ??? This is broken if rd and rm overlap */ + NEON_SET_REG(T0, rd, pass); + if (imm & 3) { + gen_op_movl_T0_T1(); + } else { + NEON_GET_REG(T0, reg, n); + } + } + } else if ((insn & (1 << 11)) == 0) { + /* Two register misc. */ + op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); + size = (insn >> 18) & 3; + switch (op) { + case 0: /* VREV64 */ + if (size == 3) + return 1; + for (pass = 0; pass < (q ? 2 : 1); pass++) { + NEON_GET_REG(T0, rm, pass * 2); + NEON_GET_REG(T1, rm, pass * 2 + 1); + switch (size) { + case 0: gen_op_rev_T0(); break; + case 1: gen_op_revh_T0(); break; + case 2: /* no-op */ break; + default: abort(); + } + NEON_SET_REG(T0, rd, pass * 2 + 1); + if (size == 2) { + NEON_SET_REG(T1, rd, pass * 2); + } else { + gen_op_movl_T0_T1(); + switch (size) { + case 0: gen_op_rev_T0(); break; + case 1: gen_op_revh_T0(); break; + default: abort(); + } + NEON_SET_REG(T0, rd, pass * 2); + } + } + break; + case 4: case 5: /* VPADDL */ + case 12: case 13: /* VPADAL */ + if (size < 2) + goto elementwise; + if (size == 3) + return 1; + for (pass = 0; pass < (q ? 2 : 1); pass++) { + NEON_GET_REG(T0, rm, pass * 2); + NEON_GET_REG(T1, rm, pass * 2 + 1); + if (op & 1) + gen_op_neon_paddl_u32(); + else + gen_op_neon_paddl_s32(); + if (op >= 12) { + /* Accumulate. */ + gen_neon_movl_scratch_T0(0); + gen_neon_movl_scratch_T1(1); + + NEON_GET_REG(T0, rd, pass * 2); + NEON_GET_REG(T1, rd, pass * 2 + 1); + gen_op_neon_addl_u64(); + } + NEON_SET_REG(T0, rd, pass * 2); + NEON_SET_REG(T1, rd, pass * 2 + 1); + } + break; + case 33: /* VTRN */ + if (size == 2) { + for (n = 0; n < (q ? 4 : 2); n += 2) { + NEON_GET_REG(T0, rm, n); + NEON_GET_REG(T1, rd, n + 1); + NEON_SET_REG(T1, rm, n); + NEON_SET_REG(T0, rd, n + 1); + } + } else { + goto elementwise; + } + break; + case 34: /* VUZP */ + /* Reg Before After + Rd A3 A2 A1 A0 B2 B0 A2 A0 + Rm B3 B2 B1 B0 B3 B1 A3 A1 + */ + if (size == 3) + return 1; + gen_neon_unzip(rd, q, 0, size); + gen_neon_unzip(rm, q, 4, size); + if (q) { + static int unzip_order_q[8] = + {0, 2, 4, 6, 1, 3, 5, 7}; + for (n = 0; n < 8; n++) { + int reg = (n < 4) ? rd : rm; + gen_neon_movl_T0_scratch(unzip_order_q[n]); + NEON_SET_REG(T0, reg, n % 4); + } + } else { + static int unzip_order[4] = + {0, 4, 1, 5}; + for (n = 0; n < 4; n++) { + int reg = (n < 2) ? rd : rm; + gen_neon_movl_T0_scratch(unzip_order[n]); + NEON_SET_REG(T0, reg, n % 2); + } + } + break; + case 35: /* VZIP */ + /* Reg Before After + Rd A3 A2 A1 A0 B1 A1 B0 A0 + Rm B3 B2 B1 B0 B3 A3 B2 A2 + */ + if (size == 3) + return 1; + count = (q ? 4 : 2); + for (n = 0; n < count; n++) { + NEON_GET_REG(T0, rd, n); + NEON_GET_REG(T1, rd, n); + switch (size) { + case 0: gen_op_neon_zip_u8(); break; + case 1: gen_op_neon_zip_u16(); break; + case 2: /* no-op */; break; + default: abort(); + } + gen_neon_movl_scratch_T0(n * 2); + gen_neon_movl_scratch_T1(n * 2 + 1); + } + for (n = 0; n < count * 2; n++) { + int reg = (n < count) ? rd : rm; + gen_neon_movl_T0_scratch(n); + NEON_SET_REG(T0, reg, n % count); + } + break; + case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */ + for (pass = 0; pass < 2; pass++) { + if (rd == rm + 1) { + n = 1 - pass; + } else { + n = pass; + } + NEON_GET_REG(T0, rm, n * 2); + NEON_GET_REG(T1, rm, n * 2 + 1); + if (op == 36 && q == 0) { + switch (size) { + case 0: gen_op_neon_narrow_u8(); break; + case 1: gen_op_neon_narrow_u16(); break; + case 2: /* no-op */ break; + default: return 1; + } + } else if (q) { + switch (size) { + case 0: gen_op_neon_narrow_sat_u8(); break; + case 1: gen_op_neon_narrow_sat_u16(); break; + case 2: gen_op_neon_narrow_sat_u32(); break; + default: return 1; + } + } else { + switch (size) { + case 0: gen_op_neon_narrow_sat_s8(); break; + case 1: gen_op_neon_narrow_sat_s16(); break; + case 2: gen_op_neon_narrow_sat_s32(); break; + default: return 1; + } + } + NEON_SET_REG(T0, rd, n); + } + break; + case 38: /* VSHLL */ + if (q) + return 1; + if (rm == rd) { + NEON_GET_REG(T2, rm, 1); + } + for (pass = 0; pass < 2; pass++) { + if (pass == 1 && rm == rd) { + gen_op_movl_T0_T2(); + } else { + NEON_GET_REG(T0, rm, pass); + } + switch (size) { + case 0: gen_op_neon_widen_high_u8(); break; + case 1: gen_op_neon_widen_high_u16(); break; + case 2: + gen_op_movl_T1_T0(); + gen_op_movl_T0_im(0); + break; + default: return 1; + } + NEON_SET_REG(T0, rd, pass * 2); + NEON_SET_REG(T1, rd, pass * 2 + 1); + } + break; + default: + elementwise: + for (pass = 0; pass < (q ? 4 : 2); pass++) { + if (op == 30 || op == 31 || op >= 58) { + gen_op_vfp_getreg_F0s(neon_reg_offset(rm, pass)); + } else { + NEON_GET_REG(T0, rm, pass); + } + switch (op) { + case 1: /* VREV32 */ + switch (size) { + case 0: gen_op_rev_T0(); break; + case 1: gen_op_revh_T0(); break; + default: return 1; + } + break; + case 2: /* VREV16 */ + if (size != 0) + return 1; + gen_op_rev16_T0(); + break; + case 4: case 5: /* VPADDL */ + case 12: case 13: /* VPADAL */ + switch ((size << 1) | (op & 1)) { + case 0: gen_op_neon_paddl_s8(); break; + case 1: gen_op_neon_paddl_u8(); break; + case 2: gen_op_neon_paddl_s16(); break; + case 3: gen_op_neon_paddl_u16(); break; + default: abort(); + } + if (op >= 12) { + /* Accumulate */ + NEON_GET_REG(T1, rd, pass); + switch (size) { + case 0: gen_op_neon_add_u16(); break; + case 1: gen_op_addl_T0_T1(); break; + default: abort(); + } + } + break; + case 8: /* CLS */ + switch (size) { + case 0: gen_op_neon_cls_s8(); break; + case 1: gen_op_neon_cls_s16(); break; + case 2: gen_op_neon_cls_s32(); break; + default: return 1; + } + break; + case 9: /* CLZ */ + switch (size) { + case 0: gen_op_neon_clz_u8(); break; + case 1: gen_op_neon_clz_u16(); break; + case 2: gen_op_clz_T0(); break; + default: return 1; + } + break; + case 10: /* CNT */ + if (size != 0) + return 1; + gen_op_neon_cnt_u8(); + break; + case 11: /* VNOT */ + if (size != 0) + return 1; + gen_op_notl_T0(); + break; + case 14: /* VQABS */ + switch (size) { + case 0: gen_op_neon_qabs_s8(); break; + case 1: gen_op_neon_qabs_s16(); break; + case 2: gen_op_neon_qabs_s32(); break; + default: return 1; + } + break; + case 15: /* VQNEG */ + switch (size) { + case 0: gen_op_neon_qneg_s8(); break; + case 1: gen_op_neon_qneg_s16(); break; + case 2: gen_op_neon_qneg_s32(); break; + default: return 1; + } + break; + case 16: case 19: /* VCGT #0, VCLE #0 */ + gen_op_movl_T1_im(0); + switch(size) { + case 0: gen_op_neon_cgt_s8(); break; + case 1: gen_op_neon_cgt_s16(); break; + case 2: gen_op_neon_cgt_s32(); break; + default: return 1; + } + if (op == 19) + gen_op_notl_T0(); + break; + case 17: case 20: /* VCGE #0, VCLT #0 */ + gen_op_movl_T1_im(0); + switch(size) { + case 0: gen_op_neon_cge_s8(); break; + case 1: gen_op_neon_cge_s16(); break; + case 2: gen_op_neon_cge_s32(); break; + default: return 1; + } + if (op == 20) + gen_op_notl_T0(); + break; + case 18: /* VCEQ #0 */ + gen_op_movl_T1_im(0); + switch(size) { + case 0: gen_op_neon_ceq_u8(); break; + case 1: gen_op_neon_ceq_u16(); break; + case 2: gen_op_neon_ceq_u32(); break; + default: return 1; + } + break; + case 22: /* VABS */ + switch(size) { + case 0: gen_op_neon_abs_s8(); break; + case 1: gen_op_neon_abs_s16(); break; + case 2: gen_op_neon_abs_s32(); break; + default: return 1; + } + break; + case 23: /* VNEG */ + gen_op_movl_T1_im(0); + switch(size) { + case 0: gen_op_neon_rsb_u8(); break; + case 1: gen_op_neon_rsb_u16(); break; + case 2: gen_op_rsbl_T0_T1(); break; + default: return 1; + } + break; + case 24: case 27: /* Float VCGT #0, Float VCLE #0 */ + gen_op_movl_T1_im(0); + gen_op_neon_cgt_f32(); + if (op == 27) + gen_op_notl_T0(); + break; + case 25: case 28: /* Float VCGE #0, Float VCLT #0 */ + gen_op_movl_T1_im(0); + gen_op_neon_cge_f32(); + if (op == 28) + gen_op_notl_T0(); + break; + case 26: /* Float VCEQ #0 */ + gen_op_movl_T1_im(0); + gen_op_neon_ceq_f32(); + break; + case 30: /* Float VABS */ + gen_op_vfp_abss(); + break; + case 31: /* Float VNEG */ + gen_op_vfp_negs(); + break; + case 32: /* VSWP */ + NEON_GET_REG(T1, rd, pass); + NEON_SET_REG(T1, rm, pass); + break; + case 33: /* VTRN */ + NEON_GET_REG(T1, rd, pass); + switch (size) { + case 0: gen_op_neon_trn_u8(); break; + case 1: gen_op_neon_trn_u16(); break; + case 2: abort(); + default: return 1; + } + NEON_SET_REG(T1, rm, pass); + break; + case 56: /* Integer VRECPE */ + gen_op_neon_recpe_u32(); + break; + case 57: /* Integer VRSQRTE */ + gen_op_neon_rsqrte_u32(); + break; + case 58: /* Float VRECPE */ + gen_op_neon_recpe_f32(); + break; + case 59: /* Float VRSQRTE */ + gen_op_neon_rsqrte_f32(); + break; + case 60: /* VCVT.F32.S32 */ + gen_op_vfp_tosizs(); + break; + case 61: /* VCVT.F32.U32 */ + gen_op_vfp_touizs(); + break; + case 62: /* VCVT.S32.F32 */ + gen_op_vfp_sitos(); + break; + case 63: /* VCVT.U32.F32 */ + gen_op_vfp_uitos(); + break; + default: + /* Reserved: 21, 29, 39-56 */ + return 1; + } + if (op == 30 || op == 31 || op >= 58) { + gen_op_vfp_setreg_F0s(neon_reg_offset(rm, pass)); + } else { + NEON_SET_REG(T0, rd, pass); + } + } + break; + } + } else if ((insn & (1 << 10)) == 0) { + /* VTBL, VTBX. */ + n = (insn >> 5) & 0x18; + NEON_GET_REG(T1, rm, 0); + if (insn & (1 << 6)) { + NEON_GET_REG(T0, rd, 0); + } else { + gen_op_movl_T0_im(0); + } + gen_op_neon_tbl(rn, n); + gen_op_movl_T2_T0(); + NEON_GET_REG(T1, rm, 1); + if (insn & (1 << 6)) { + NEON_GET_REG(T0, rd, 0); + } else { + gen_op_movl_T0_im(0); + } + gen_op_neon_tbl(rn, n); + NEON_SET_REG(T2, rd, 0); + NEON_SET_REG(T0, rd, 1); + } else if ((insn & 0x380) == 0) { + /* VDUP */ + if (insn & (1 << 19)) { + NEON_SET_REG(T0, rm, 1); + } else { + NEON_SET_REG(T0, rm, 0); + } + if (insn & (1 << 16)) { + gen_op_neon_dup_u8(((insn >> 17) & 3) * 8); + } else if (insn & (1 << 17)) { + if ((insn >> 18) & 1) + gen_op_neon_dup_high16(); + else + gen_op_neon_dup_low16(); + } + for (pass = 0; pass < (q ? 4 : 2); pass++) { + NEON_SET_REG(T0, rd, pass); + } + } else { + return 1; + } + } + } + return 0; +} + +static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn) +{ + int cpnum; + + cpnum = (insn >> 8) & 0xf; + if (arm_feature(env, ARM_FEATURE_XSCALE) + && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum))) + return 1; + + switch (cpnum) { + case 0: + case 1: + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + return disas_iwmmxt_insn(env, s, insn); + } else if (arm_feature(env, ARM_FEATURE_XSCALE)) { + return disas_dsp_insn(env, s, insn); + } + return 1; + case 10: + case 11: + return disas_vfp_insn (env, s, insn); + case 15: + return disas_cp15_insn (env, s, insn); + default: + /* Unknown coprocessor. See if the board has hooked it. */ + return disas_cp_insn (env, s, insn); + } +} + +static void disas_arm_insn(CPUState * env, DisasContext *s) +{ + unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; + + insn = ldl_code(s->pc); + s->pc += 4; + + /* M variants do not implement ARM mode. */ + if (IS_M(env)) + goto illegal_op; + cond = insn >> 28; + if (cond == 0xf){ + /* Unconditional instructions. */ + if (((insn >> 25) & 7) == 1) { + /* NEON Data processing. */ + if (!arm_feature(env, ARM_FEATURE_NEON)) + goto illegal_op; + + if (disas_neon_data_insn(env, s, insn)) + goto illegal_op; + return; + } + if ((insn & 0x0f100000) == 0x04000000) { + /* NEON load/store. */ + if (!arm_feature(env, ARM_FEATURE_NEON)) + goto illegal_op; + + if (disas_neon_ls_insn(env, s, insn)) + goto illegal_op; + return; + } + if ((insn & 0x0d70f000) == 0x0550f000) + return; /* PLD */ + else if ((insn & 0x0ffffdff) == 0x01010000) { + ARCH(6); + /* setend */ + if (insn & (1 << 9)) { + /* BE8 mode not implemented. */ + goto illegal_op; + } + return; + } else if ((insn & 0x0fffff00) == 0x057ff000) { + switch ((insn >> 4) & 0xf) { + case 1: /* clrex */ + ARCH(6K); + gen_op_clrex(); + return; + case 4: /* dsb */ + case 5: /* dmb */ + case 6: /* isb */ + ARCH(7); + /* We don't emulate caches so these are a no-op. */ + return; + default: + goto illegal_op; + } + } else if ((insn & 0x0e5fffe0) == 0x084d0500) { + /* srs */ + uint32_t offset; + if (IS_USER(s)) + goto illegal_op; + ARCH(6); + op1 = (insn & 0x1f); + if (op1 == (env->uncached_cpsr & CPSR_M)) { + gen_movl_T1_reg(s, 13); + } else { + gen_op_movl_T1_r13_banked(op1); + } + i = (insn >> 23) & 3; + switch (i) { + case 0: offset = -4; break; /* DA */ + case 1: offset = -8; break; /* DB */ + case 2: offset = 0; break; /* IA */ + case 3: offset = 4; break; /* IB */ + default: abort(); + } + if (offset) + gen_op_addl_T1_im(offset); + gen_movl_T0_reg(s, 14); + gen_ldst(stl, s); + gen_op_movl_T0_cpsr(); + gen_op_addl_T1_im(4); + gen_ldst(stl, s); + if (insn & (1 << 21)) { + /* Base writeback. */ + switch (i) { + case 0: offset = -8; break; + case 1: offset = -4; break; + case 2: offset = 4; break; + case 3: offset = 0; break; + default: abort(); + } + if (offset) + gen_op_addl_T1_im(offset); + if (op1 == (env->uncached_cpsr & CPSR_M)) { + gen_movl_reg_T1(s, 13); + } else { + gen_op_movl_r13_T1_banked(op1); + } + } + } else if ((insn & 0x0e5fffe0) == 0x081d0a00) { + /* rfe */ + uint32_t offset; + if (IS_USER(s)) + goto illegal_op; + ARCH(6); + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + i = (insn >> 23) & 3; + switch (i) { + case 0: offset = 0; break; /* DA */ + case 1: offset = -4; break; /* DB */ + case 2: offset = 4; break; /* IA */ + case 3: offset = 8; break; /* IB */ + default: abort(); + } + if (offset) + gen_op_addl_T1_im(offset); + /* Load CPSR into T2 and PC into T0. */ + gen_ldst(ldl, s); + gen_op_movl_T2_T0(); + gen_op_addl_T1_im(-4); + gen_ldst(ldl, s); + if (insn & (1 << 21)) { + /* Base writeback. */ + switch (i) { + case 0: offset = -4; break; + case 1: offset = 0; break; + case 2: offset = 8; break; + case 3: offset = 4; break; + default: abort(); + } + if (offset) + gen_op_addl_T1_im(offset); + gen_movl_reg_T1(s, rn); + } + gen_rfe(s); + } else if ((insn & 0x0e000000) == 0x0a000000) { + /* branch link and change to thumb (blx ) */ + int32_t offset; + + val = (uint32_t)s->pc; + gen_op_movl_T0_im(val); + gen_movl_reg_T0(s, 14); + /* Sign-extend the 24-bit offset */ + offset = (((int32_t)insn) << 8) >> 8; + /* offset * 4 + bit24 * 2 + (thumb bit) */ + val += (offset << 2) | ((insn >> 23) & 2) | 1; + /* pipeline offset */ + val += 4; + gen_op_movl_T0_im(val); + gen_bx(s); + return; + } else if ((insn & 0x0e000f00) == 0x0c000100) { + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + /* iWMMXt register transfer. */ + if (env->cp15.c15_cpar & (1 << 1)) + if (!disas_iwmmxt_insn(env, s, insn)) + return; + } + } else if ((insn & 0x0fe00000) == 0x0c400000) { + /* Coprocessor double register transfer. */ + } else if ((insn & 0x0f000010) == 0x0e000010) { + /* Additional coprocessor register transfer. */ + } else if ((insn & 0x0ff10010) == 0x01000000) { + uint32_t mask; + uint32_t val; + /* cps (privileged) */ + if (IS_USER(s)) + return; + mask = val = 0; + if (insn & (1 << 19)) { + if (insn & (1 << 8)) + mask |= CPSR_A; + if (insn & (1 << 7)) + mask |= CPSR_I; + if (insn & (1 << 6)) + mask |= CPSR_F; + if (insn & (1 << 18)) + val |= mask; + } + if (insn & (1 << 14)) { + mask |= CPSR_M; + val |= (insn & 0x1f); + } + if (mask) { + gen_op_movl_T0_im(val); + gen_set_psr_T0(s, mask, 0); + } + return; + } + goto illegal_op; + } + if (cond != 0xe) { + /* if not always execute, we generate a conditional jump to + next instruction */ + s->condlabel = gen_new_label(); + gen_test_cc[cond ^ 1](s->condlabel); + s->condjmp = 1; + } + if ((insn & 0x0f900000) == 0x03000000) { + if ((insn & (1 << 21)) == 0) { + ARCH(6T2); + rd = (insn >> 12) & 0xf; + val = ((insn >> 4) & 0xf000) | (insn & 0xfff); + if ((insn & (1 << 22)) == 0) { + /* MOVW */ + gen_op_movl_T0_im(val); + } else { + /* MOVT */ + gen_movl_T0_reg(s, rd); + gen_op_movl_T1_im(0xffff); + gen_op_andl_T0_T1(); + gen_op_movl_T1_im(val << 16); + gen_op_orl_T0_T1(); + } + gen_movl_reg_T0(s, rd); + } else { + if (((insn >> 12) & 0xf) != 0xf) + goto illegal_op; + if (((insn >> 16) & 0xf) == 0) { + gen_nop_hint(s, insn & 0xff); + } else { + /* CPSR = immediate */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) + val = (val >> shift) | (val << (32 - shift)); + gen_op_movl_T0_im(val); + i = ((insn & (1 << 22)) != 0); + if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i)) + goto illegal_op; + } + } + } else if ((insn & 0x0f900000) == 0x01000000 + && (insn & 0x00000090) != 0x00000090) { + /* miscellaneous instructions */ + op1 = (insn >> 21) & 3; + sh = (insn >> 4) & 0xf; + rm = insn & 0xf; + switch (sh) { + case 0x0: /* move program status register */ + if (op1 & 1) { + /* PSR = reg */ + gen_movl_T0_reg(s, rm); + i = ((op1 & 2) != 0); + if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i)) + goto illegal_op; + } else { + /* reg = PSR */ + rd = (insn >> 12) & 0xf; + if (op1 & 2) { + if (IS_USER(s)) + goto illegal_op; + gen_op_movl_T0_spsr(); + } else { + gen_op_movl_T0_cpsr(); + } + gen_movl_reg_T0(s, rd); + } + break; + case 0x1: + if (op1 == 1) { + /* branch/exchange thumb (bx). */ + gen_movl_T0_reg(s, rm); + gen_bx(s); + } else if (op1 == 3) { + /* clz */ + rd = (insn >> 12) & 0xf; + gen_movl_T0_reg(s, rm); + gen_op_clz_T0(); + gen_movl_reg_T0(s, rd); + } else { + goto illegal_op; + } + break; + case 0x2: + if (op1 == 1) { + ARCH(5J); /* bxj */ + /* Trivial implementation equivalent to bx. */ + gen_movl_T0_reg(s, rm); + gen_bx(s); + } else { + goto illegal_op; + } + break; + case 0x3: + if (op1 != 1) + goto illegal_op; + + /* branch link/exchange thumb (blx) */ + val = (uint32_t)s->pc; + gen_op_movl_T1_im(val); + gen_movl_T0_reg(s, rm); + gen_movl_reg_T1(s, 14); + gen_bx(s); + break; + case 0x5: /* saturating add/subtract */ + rd = (insn >> 12) & 0xf; + rn = (insn >> 16) & 0xf; + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if (op1 & 2) + gen_op_double_T1_saturate(); + if (op1 & 1) + gen_op_subl_T0_T1_saturate(); + else + gen_op_addl_T0_T1_saturate(); + gen_movl_reg_T0(s, rd); + break; + case 7: /* bkpt */ + gen_set_condexec(s); + gen_op_movl_T0_im((long)s->pc - 4); + gen_op_movl_reg_TN[0][15](); + gen_op_bkpt(); + s->is_jmp = DISAS_JUMP; + break; + case 0x8: /* signed multiply */ + case 0xa: + case 0xc: + case 0xe: + rs = (insn >> 8) & 0xf; + rn = (insn >> 12) & 0xf; + rd = (insn >> 16) & 0xf; + if (op1 == 1) { + /* (32 * 16) >> 16 */ + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rs); + if (sh & 4) + gen_op_sarl_T1_im(16); + else + gen_op_sxth_T1(); + gen_op_imulw_T0_T1(); + if ((sh & 2) == 0) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + } else { + /* 16 * 16 */ + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rs); + gen_mulxy(sh & 2, sh & 4); + if (op1 == 2) { + gen_op_signbit_T1_T0(); + gen_op_addq_T0_T1(rn, rd); + gen_movl_reg_T0(s, rn); + gen_movl_reg_T1(s, rd); + } else { + if (op1 == 0) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + } + } + break; + default: + goto illegal_op; + } + } else if (((insn & 0x0e000000) == 0 && + (insn & 0x00000090) != 0x90) || + ((insn & 0x0e000000) == (1 << 25))) { + int set_cc, logic_cc, shiftop; + + op1 = (insn >> 21) & 0xf; + set_cc = (insn >> 20) & 1; + logic_cc = table_logic_cc[op1] & set_cc; + + /* data processing instruction */ + if (insn & (1 << 25)) { + /* immediate operand */ + val = insn & 0xff; + shift = ((insn >> 8) & 0xf) * 2; + if (shift) + val = (val >> shift) | (val << (32 - shift)); + gen_op_movl_T1_im(val); + if (logic_cc && shift) + gen_op_mov_CF_T1(); + } else { + /* register */ + rm = (insn) & 0xf; + gen_movl_T1_reg(s, rm); + shiftop = (insn >> 5) & 3; + if (!(insn & (1 << 4))) { + shift = (insn >> 7) & 0x1f; + if (shift != 0) { + if (logic_cc) { + gen_shift_T1_im_cc[shiftop](shift); + } else { + gen_shift_T1_im[shiftop](shift); + } + } else if (shiftop != 0) { + if (logic_cc) { + gen_shift_T1_0_cc[shiftop](); + } else { + gen_shift_T1_0[shiftop](); + } + } + } else { + rs = (insn >> 8) & 0xf; + gen_movl_T0_reg(s, rs); + if (logic_cc) { + gen_shift_T1_T0_cc[shiftop](); + } else { + gen_shift_T1_T0[shiftop](); + } + } + } + if (op1 != 0x0f && op1 != 0x0d) { + rn = (insn >> 16) & 0xf; + gen_movl_T0_reg(s, rn); + } + rd = (insn >> 12) & 0xf; + switch(op1) { + case 0x00: + gen_op_andl_T0_T1(); + gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); + break; + case 0x01: + gen_op_xorl_T0_T1(); + gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); + break; + case 0x02: + if (set_cc && rd == 15) { + /* SUBS r15, ... is used for exception return. */ + if (IS_USER(s)) + goto illegal_op; + gen_op_subl_T0_T1_cc(); + gen_exception_return(s); + } else { + if (set_cc) + gen_op_subl_T0_T1_cc(); + else + gen_op_subl_T0_T1(); + gen_movl_reg_T0(s, rd); + } + break; + case 0x03: + if (set_cc) + gen_op_rsbl_T0_T1_cc(); + else + gen_op_rsbl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x04: + if (set_cc) + gen_op_addl_T0_T1_cc(); + else + gen_op_addl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x05: + if (set_cc) + gen_op_adcl_T0_T1_cc(); + else + gen_op_adcl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x06: + if (set_cc) + gen_op_sbcl_T0_T1_cc(); + else + gen_op_sbcl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x07: + if (set_cc) + gen_op_rscl_T0_T1_cc(); + else + gen_op_rscl_T0_T1(); + gen_movl_reg_T0(s, rd); + break; + case 0x08: + if (set_cc) { + gen_op_andl_T0_T1(); + gen_op_logic_T0_cc(); + } + break; + case 0x09: + if (set_cc) { + gen_op_xorl_T0_T1(); + gen_op_logic_T0_cc(); + } + break; + case 0x0a: + if (set_cc) { + gen_op_subl_T0_T1_cc(); + } + break; + case 0x0b: + if (set_cc) { + gen_op_addl_T0_T1_cc(); + } + break; + case 0x0c: + gen_op_orl_T0_T1(); + gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); + break; + case 0x0d: + if (logic_cc && rd == 15) { + /* MOVS r15, ... is used for exception return. */ + if (IS_USER(s)) + goto illegal_op; + gen_op_movl_T0_T1(); + gen_exception_return(s); + } else { + gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); + } + break; + case 0x0e: + gen_op_bicl_T0_T1(); + gen_movl_reg_T0(s, rd); + if (logic_cc) + gen_op_logic_T0_cc(); + break; + default: + case 0x0f: + gen_op_notl_T1(); + gen_movl_reg_T1(s, rd); + if (logic_cc) + gen_op_logic_T1_cc(); + break; + } + } else { + /* other instructions */ + op1 = (insn >> 24) & 0xf; + switch(op1) { + case 0x0: + case 0x1: + /* multiplies, extra load/stores */ + sh = (insn >> 5) & 3; + if (sh == 0) { + if (op1 == 0x0) { + rd = (insn >> 16) & 0xf; + rn = (insn >> 12) & 0xf; + rs = (insn >> 8) & 0xf; + rm = (insn) & 0xf; + op1 = (insn >> 20) & 0xf; + switch (op1) { + case 0: case 1: case 2: case 3: case 6: + /* 32 bit mul */ + gen_movl_T0_reg(s, rs); + gen_movl_T1_reg(s, rm); + gen_op_mul_T0_T1(); + if (insn & (1 << 22)) { + /* Subtract (mls) */ + ARCH(6T2); + gen_movl_T1_reg(s, rn); + gen_op_rsbl_T0_T1(); + } else if (insn & (1 << 21)) { + /* Add */ + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1(); + } + if (insn & (1 << 20)) + gen_op_logic_T0_cc(); + gen_movl_reg_T0(s, rd); + break; + default: + /* 64 bit mul */ + gen_movl_T0_reg(s, rs); + gen_movl_T1_reg(s, rm); + if (insn & (1 << 22)) + gen_op_imull_T0_T1(); + else + gen_op_mull_T0_T1(); + if (insn & (1 << 21)) /* mult accumulate */ + gen_op_addq_T0_T1(rn, rd); + if (!(insn & (1 << 23))) { /* double accumulate */ + ARCH(6); + gen_op_addq_lo_T0_T1(rn); + gen_op_addq_lo_T0_T1(rd); + } + if (insn & (1 << 20)) + gen_op_logicq_cc(); + gen_movl_reg_T0(s, rn); + gen_movl_reg_T1(s, rd); + break; + } + } else { + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + if (insn & (1 << 23)) { + /* load/store exclusive */ + gen_movl_T1_reg(s, rn); + if (insn & (1 << 20)) { + gen_ldst(ldlex, s); + } else { + rm = insn & 0xf; + gen_movl_T0_reg(s, rm); + gen_ldst(stlex, s); + } + gen_movl_reg_T0(s, rd); + } else { + /* SWP instruction */ + rm = (insn) & 0xf; + + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if (insn & (1 << 22)) { + gen_ldst(swpb, s); + } else { + gen_ldst(swpl, s); + } + gen_movl_reg_T0(s, rd); + } + } + } else { + int address_offset; + int load; + /* Misc load/store */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + gen_movl_T1_reg(s, rn); + if (insn & (1 << 24)) + gen_add_datah_offset(s, insn, 0); + address_offset = 0; + if (insn & (1 << 20)) { + /* load */ + switch(sh) { + case 1: + gen_ldst(lduw, s); + break; + case 2: + gen_ldst(ldsb, s); + break; + default: + case 3: + gen_ldst(ldsw, s); + break; + } + load = 1; + } else if (sh & 2) { + /* doubleword */ + if (sh & 1) { + /* store */ + gen_movl_T0_reg(s, rd); + gen_ldst(stl, s); + gen_op_addl_T1_im(4); + gen_movl_T0_reg(s, rd + 1); + gen_ldst(stl, s); + load = 0; + } else { + /* load */ + gen_ldst(ldl, s); + gen_movl_reg_T0(s, rd); + gen_op_addl_T1_im(4); + gen_ldst(ldl, s); + rd++; + load = 1; + } + address_offset = -4; + } else { + /* store */ + gen_movl_T0_reg(s, rd); + gen_ldst(stw, s); + load = 0; + } + /* Perform base writeback before the loaded value to + ensure correct behavior with overlapping index registers. + ldrd with base writeback is is undefined if the + destination and index registers overlap. */ + if (!(insn & (1 << 24))) { + gen_add_datah_offset(s, insn, address_offset); + gen_movl_reg_T1(s, rn); + } else if (insn & (1 << 21)) { + if (address_offset) + gen_op_addl_T1_im(address_offset); + gen_movl_reg_T1(s, rn); + } + if (load) { + /* Complete the load. */ + gen_movl_reg_T0(s, rd); + } + } + break; + case 0x4: + case 0x5: + goto do_ldst; + case 0x6: + case 0x7: + if (insn & (1 << 4)) { + ARCH(6); + /* Armv6 Media instructions. */ + rm = insn & 0xf; + rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; + rs = (insn >> 8) & 0xf; + switch ((insn >> 23) & 3) { + case 0: /* Parallel add/subtract. */ + op1 = (insn >> 20) & 7; + gen_movl_T0_reg(s, rn); + gen_movl_T1_reg(s, rm); + sh = (insn >> 5) & 7; + if ((op1 & 3) == 0 || sh == 5 || sh == 6) + goto illegal_op; + gen_arm_parallel_addsub[op1][sh](); + gen_movl_reg_T0(s, rd); + break; + case 1: + if ((insn & 0x00700020) == 0) { + /* Hafword pack. */ + gen_movl_T0_reg(s, rn); + gen_movl_T1_reg(s, rm); + shift = (insn >> 7) & 0x1f; + if (shift) + gen_op_shll_T1_im(shift); + if (insn & (1 << 6)) + gen_op_pkhtb_T0_T1(); + else + gen_op_pkhbt_T0_T1(); + gen_movl_reg_T0(s, rd); + } else if ((insn & 0x00200020) == 0x00200000) { + /* [us]sat */ + gen_movl_T1_reg(s, rm); + shift = (insn >> 7) & 0x1f; + if (insn & (1 << 6)) { + if (shift == 0) + shift = 31; + gen_op_sarl_T1_im(shift); + } else { + gen_op_shll_T1_im(shift); + } + sh = (insn >> 16) & 0x1f; + if (sh != 0) { + if (insn & (1 << 22)) + gen_op_usat_T1(sh); + else + gen_op_ssat_T1(sh); + } + gen_movl_T1_reg(s, rd); + } else if ((insn & 0x00300fe0) == 0x00200f20) { + /* [us]sat16 */ + gen_movl_T1_reg(s, rm); + sh = (insn >> 16) & 0x1f; + if (sh != 0) { + if (insn & (1 << 22)) + gen_op_usat16_T1(sh); + else + gen_op_ssat16_T1(sh); + } + gen_movl_T1_reg(s, rd); + } else if ((insn & 0x00700fe0) == 0x00000fa0) { + /* Select bytes. */ + gen_movl_T0_reg(s, rn); + gen_movl_T1_reg(s, rm); + gen_op_sel_T0_T1(); + gen_movl_reg_T0(s, rd); + } else if ((insn & 0x000003e0) == 0x00000060) { + gen_movl_T1_reg(s, rm); + shift = (insn >> 10) & 3; + /* ??? In many cases it's not neccessary to do a + rotate, a shift is sufficient. */ + if (shift != 0) + gen_op_rorl_T1_im(shift * 8); + op1 = (insn >> 20) & 7; + switch (op1) { + case 0: gen_op_sxtb16_T1(); break; + case 2: gen_op_sxtb_T1(); break; + case 3: gen_op_sxth_T1(); break; + case 4: gen_op_uxtb16_T1(); break; + case 6: gen_op_uxtb_T1(); break; + case 7: gen_op_uxth_T1(); break; + default: goto illegal_op; + } + if (rn != 15) { + gen_movl_T2_reg(s, rn); + if ((op1 & 3) == 0) { + gen_op_add16_T1_T2(); + } else { + gen_op_addl_T1_T2(); + } + } + gen_movl_reg_T1(s, rd); + } else if ((insn & 0x003f0f60) == 0x003f0f20) { + /* rev */ + gen_movl_T0_reg(s, rm); + if (insn & (1 << 22)) { + if (insn & (1 << 7)) { + gen_op_revsh_T0(); + } else { + ARCH(6T2); + gen_op_rbit_T0(); + } + } else { + if (insn & (1 << 7)) + gen_op_rev16_T0(); + else + gen_op_rev_T0(); + } + gen_movl_reg_T0(s, rd); + } else { + goto illegal_op; + } + break; + case 2: /* Multiplies (Type 3). */ + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rs); + if (insn & (1 << 20)) { + /* Signed multiply most significant [accumulate]. */ + gen_op_imull_T0_T1(); + if (insn & (1 << 5)) + gen_op_roundqd_T0_T1(); + else + gen_op_movl_T0_T1(); + if (rn != 15) { + gen_movl_T1_reg(s, rn); + if (insn & (1 << 6)) { + gen_op_addl_T0_T1(); + } else { + gen_op_rsbl_T0_T1(); + } + } + gen_movl_reg_T0(s, rd); + } else { + if (insn & (1 << 5)) + gen_op_swap_half_T1(); + gen_op_mul_dual_T0_T1(); + if (insn & (1 << 22)) { + if (insn & (1 << 6)) { + /* smlald */ + gen_op_addq_T0_T1_dual(rn, rd); + } else { + /* smlsld */ + gen_op_subq_T0_T1_dual(rn, rd); + } + } else { + /* This addition cannot overflow. */ + if (insn & (1 << 6)) { + /* sm[ul]sd */ + gen_op_subl_T0_T1(); + } else { + /* sm[ul]ad */ + gen_op_addl_T0_T1(); + } + if (rn != 15) + { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + } + } + break; + case 3: + op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7); + switch (op1) { + case 0: /* Unsigned sum of absolute differences. */ + goto illegal_op; + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rs); + gen_op_usad8_T0_T1(); + if (rn != 15) { + gen_movl_T1_reg(s, rn); + gen_op_addl_T0_T1(); + } + gen_movl_reg_T0(s, rd); + break; + case 0x20: case 0x24: case 0x28: case 0x2c: + /* Bitfield insert/clear. */ + ARCH(6T2); + shift = (insn >> 7) & 0x1f; + i = (insn >> 16) & 0x1f; + i = i + 1 - shift; + if (rm == 15) { + gen_op_movl_T1_im(0); + } else { + gen_movl_T1_reg(s, rm); + } + if (i != 32) { + gen_movl_T0_reg(s, rd); + gen_op_bfi_T1_T0(shift, ((1u << i) - 1) << shift); + } + gen_movl_reg_T1(s, rd); + break; + case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */ + case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */ + gen_movl_T1_reg(s, rm); + shift = (insn >> 7) & 0x1f; + i = ((insn >> 16) & 0x1f) + 1; + if (shift + i > 32) + goto illegal_op; + if (i < 32) { + if (op1 & 0x20) { + gen_op_ubfx_T1(shift, (1u << i) - 1); + } else { + gen_op_sbfx_T1(shift, i); + } + } + gen_movl_reg_T1(s, rd); + break; + default: + goto illegal_op; + } + break; + } + break; + } + do_ldst: + /* Check for undefined extension instructions + * per the ARM Bible IE: + * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx + */ + sh = (0xf << 20) | (0xf << 4); + if (op1 == 0x7 && ((insn & sh) == sh)) + { + goto illegal_op; + } + /* load/store byte/word */ + rn = (insn >> 16) & 0xf; + rd = (insn >> 12) & 0xf; + gen_movl_T1_reg(s, rn); + i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000); + if (insn & (1 << 24)) + gen_add_data_offset(s, insn); + if (insn & (1 << 20)) { + /* load */ + s->is_mem = 1; +#if defined(CONFIG_USER_ONLY) + if (insn & (1 << 22)) + gen_op_ldub_raw(); + else + gen_op_ldl_raw(); +#else + if (insn & (1 << 22)) { + if (i) + gen_op_ldub_user(); + else + gen_op_ldub_kernel(); + } else { + if (i) + gen_op_ldl_user(); + else + gen_op_ldl_kernel(); + } +#endif + } else { + /* store */ + gen_movl_T0_reg(s, rd); +#if defined(CONFIG_USER_ONLY) + if (insn & (1 << 22)) + gen_op_stb_raw(); + else + gen_op_stl_raw(); +#else + if (insn & (1 << 22)) { + if (i) + gen_op_stb_user(); + else + gen_op_stb_kernel(); + } else { + if (i) + gen_op_stl_user(); + else + gen_op_stl_kernel(); + } +#endif + } + if (!(insn & (1 << 24))) { + gen_add_data_offset(s, insn); + gen_movl_reg_T1(s, rn); + } else if (insn & (1 << 21)) + gen_movl_reg_T1(s, rn); { + } + if (insn & (1 << 20)) { + /* Complete the load. */ + if (rd == 15) + gen_bx(s); + else + gen_movl_reg_T0(s, rd); + } + break; + case 0x08: + case 0x09: + { + int j, n, user, loaded_base; + /* load/store multiple words */ + /* XXX: store correct base if write back */ + user = 0; + if (insn & (1 << 22)) { + if (IS_USER(s)) + goto illegal_op; /* only usable in supervisor mode */ + + if ((insn & (1 << 15)) == 0) + user = 1; + } + rn = (insn >> 16) & 0xf; + gen_movl_T1_reg(s, rn); + + /* compute total size */ + loaded_base = 0; + n = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) + n++; + } + /* XXX: test invalid n == 0 case ? */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + gen_op_addl_T1_im(4); + } else { + /* post increment */ + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + gen_op_addl_T1_im(-(n * 4)); + } else { + /* post decrement */ + if (n != 1) + gen_op_addl_T1_im(-((n - 1) * 4)); + } + } + j = 0; + for(i=0;i<16;i++) { + if (insn & (1 << i)) { + if (insn & (1 << 20)) { + /* load */ + gen_ldst(ldl, s); + if (i == 15) { + gen_bx(s); + } else if (user) { + gen_op_movl_user_T0(i); + } else if (i == rn) { + gen_op_movl_T2_T0(); + loaded_base = 1; + } else { + gen_movl_reg_T0(s, i); + } + } else { + /* store */ + if (i == 15) { + /* special case: r15 = PC + 8 */ + val = (long)s->pc + 4; + gen_op_movl_TN_im[0](val); + } else if (user) { + gen_op_movl_T0_user(i); + } else { + gen_movl_T0_reg(s, i); + } + gen_ldst(stl, s); + } + j++; + /* no need to add after the last transfer */ + if (j != n) + gen_op_addl_T1_im(4); + } + } + if (insn & (1 << 21)) { + /* write back */ + if (insn & (1 << 23)) { + if (insn & (1 << 24)) { + /* pre increment */ + } else { + /* post increment */ + gen_op_addl_T1_im(4); + } + } else { + if (insn & (1 << 24)) { + /* pre decrement */ + if (n != 1) + gen_op_addl_T1_im(-((n - 1) * 4)); + } else { + /* post decrement */ + gen_op_addl_T1_im(-(n * 4)); + } + } + gen_movl_reg_T1(s, rn); + } + if (loaded_base) { + gen_op_movl_T0_T2(); + gen_movl_reg_T0(s, rn); + } + if ((insn & (1 << 22)) && !user) { + /* Restore CPSR from SPSR. */ + gen_op_movl_T0_spsr(); + gen_op_movl_cpsr_T0(0xffffffff); + s->is_jmp = DISAS_UPDATE; + } + } + break; + case 0xa: + case 0xb: + { + int32_t offset; + + /* branch (and link) */ + val = (int32_t)s->pc; + if (insn & (1 << 24)) { + gen_op_movl_T0_im(val); + gen_op_movl_reg_TN[0][14](); + } + offset = (((int32_t)insn << 8) >> 8); + val += (offset << 2) + 4; + gen_jmp(s, val); + } + break; + case 0xc: + case 0xd: + case 0xe: + /* Coprocessor. */ + if (disas_coproc_insn(env, s, insn)) + goto illegal_op; + break; + case 0xf: + /* swi */ + gen_op_movl_T0_im((long)s->pc); + gen_op_movl_reg_TN[0][15](); + s->is_jmp = DISAS_SWI; + break; + default: + illegal_op: + gen_set_condexec(s); + gen_op_movl_T0_im((long)s->pc - 4); + gen_op_movl_reg_TN[0][15](); + gen_op_undef_insn(); + s->is_jmp = DISAS_JUMP; + break; + } + } +} + +/* Return true if this is a Thumb-2 logical op. */ +static int +thumb2_logic_op(int op) +{ + return (op < 8); +} + +/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero + then set condition code flags based on the result of the operation. + If SHIFTER_OUT is nonzero then set the carry flag for logical operations + to the high bit of T1. + Returns zero if the opcode is valid. */ + +static int +gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out) +{ + int logic_cc; + + logic_cc = 0; + switch (op) { + case 0: /* and */ + gen_op_andl_T0_T1(); + logic_cc = conds; + break; + case 1: /* bic */ + gen_op_bicl_T0_T1(); + logic_cc = conds; + break; + case 2: /* orr */ + gen_op_orl_T0_T1(); + logic_cc = conds; + break; + case 3: /* orn */ + gen_op_notl_T1(); + gen_op_orl_T0_T1(); + logic_cc = conds; + break; + case 4: /* eor */ + gen_op_xorl_T0_T1(); + logic_cc = conds; + break; + case 8: /* add */ + if (conds) + gen_op_addl_T0_T1_cc(); + else + gen_op_addl_T0_T1(); + break; + case 10: /* adc */ + if (conds) + gen_op_adcl_T0_T1_cc(); + else + gen_op_adcl_T0_T1(); + break; + case 11: /* sbc */ + if (conds) + gen_op_sbcl_T0_T1_cc(); + else + gen_op_sbcl_T0_T1(); + break; + case 13: /* sub */ + if (conds) + gen_op_subl_T0_T1_cc(); + else + gen_op_subl_T0_T1(); + break; + case 14: /* rsb */ + if (conds) + gen_op_rsbl_T0_T1_cc(); + else + gen_op_rsbl_T0_T1(); + break; + default: /* 5, 6, 7, 9, 12, 15. */ + return 1; + } + if (logic_cc) { + gen_op_logic_T0_cc(); + if (shifter_out) + gen_op_mov_CF_T1(); + } + return 0; +} + +/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction + is not legal. */ +static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) +{ + uint32_t insn, imm, shift, offset, addr; + uint32_t rd, rn, rm, rs; + int op; + int shiftop; + int conds; + int logic_cc; + + if (!(arm_feature(env, ARM_FEATURE_THUMB2) + || arm_feature (env, ARM_FEATURE_M))) { + /* Thumb-1 cores may need to tread bl and blx as a pair of + 16-bit instructions to get correct prefetch abort behavior. */ + insn = insn_hw1; + if ((insn & (1 << 12)) == 0) { + /* Second half of blx. */ + offset = ((insn & 0x7ff) << 1); + gen_movl_T0_reg(s, 14); + gen_op_movl_T1_im(offset); + gen_op_addl_T0_T1(); + gen_op_movl_T1_im(0xfffffffc); + gen_op_andl_T0_T1(); + + addr = (uint32_t)s->pc; + gen_op_movl_T1_im(addr | 1); + gen_movl_reg_T1(s, 14); + gen_bx(s); + return 0; + } + if (insn & (1 << 11)) { + /* Second half of bl. */ + offset = ((insn & 0x7ff) << 1) | 1; + gen_movl_T0_reg(s, 14); + gen_op_movl_T1_im(offset); + gen_op_addl_T0_T1(); + + addr = (uint32_t)s->pc; + gen_op_movl_T1_im(addr | 1); + gen_movl_reg_T1(s, 14); + gen_bx(s); + return 0; + } + if ((s->pc & ~TARGET_PAGE_MASK) == 0) { + /* Instruction spans a page boundary. Implement it as two + 16-bit instructions in case the second half causes an + prefetch abort. */ + offset = ((int32_t)insn << 21) >> 9; + addr = s->pc + 2 + offset; + gen_op_movl_T0_im(addr); + gen_movl_reg_T0(s, 14); + return 0; + } + /* Fall through to 32-bit decode. */ + } + + insn = lduw_code(s->pc); + s->pc += 2; + insn |= (uint32_t)insn_hw1 << 16; + + if ((insn & 0xf800e800) != 0xf000e800) { + ARCH(6T2); + } + + rn = (insn >> 16) & 0xf; + rs = (insn >> 12) & 0xf; + rd = (insn >> 8) & 0xf; + rm = insn & 0xf; + switch ((insn >> 25) & 0xf) { + case 0: case 1: case 2: case 3: + /* 16-bit instructions. Should never happen. */ + abort(); + case 4: + if (insn & (1 << 22)) { + /* Other load/store, table branch. */ + if (insn & 0x01200000) { + /* Load/store doubleword. */ + if (rn == 15) { + gen_op_movl_T1_im(s->pc & ~3); + } else { + gen_movl_T1_reg(s, rn); + } + offset = (insn & 0xff) * 4; + if ((insn & (1 << 23)) == 0) + offset = -offset; + if (insn & (1 << 24)) { + gen_op_addl_T1_im(offset); + offset = 0; + } + if (insn & (1 << 20)) { + /* ldrd */ + gen_ldst(ldl, s); + gen_movl_reg_T0(s, rs); + gen_op_addl_T1_im(4); + gen_ldst(ldl, s); + gen_movl_reg_T0(s, rd); + } else { + /* strd */ + gen_movl_T0_reg(s, rs); + gen_ldst(stl, s); + gen_op_addl_T1_im(4); + gen_movl_T0_reg(s, rd); + gen_ldst(stl, s); + } + if (insn & (1 << 21)) { + /* Base writeback. */ + if (rn == 15) + goto illegal_op; + gen_op_addl_T1_im(offset - 4); + gen_movl_reg_T1(s, rn); + } + } else if ((insn & (1 << 23)) == 0) { + /* Load/store exclusive word. */ + gen_movl_T0_reg(s, rd); gen_movl_T1_reg(s, rn); - if (insn & (1 << 24)) - gen_add_datah_offset(s, insn, 0); - address_offset = 0; if (insn & (1 << 20)) { - /* load */ - switch(sh) { + gen_ldst(ldlex, s); + } else { + gen_ldst(stlex, s); + } + gen_movl_reg_T0(s, rd); + } else if ((insn & (1 << 6)) == 0) { + /* Table Branch. */ + if (rn == 15) { + gen_op_movl_T1_im(s->pc); + } else { + gen_movl_T1_reg(s, rn); + } + gen_movl_T2_reg(s, rm); + gen_op_addl_T1_T2(); + if (insn & (1 << 4)) { + /* tbh */ + gen_op_addl_T1_T2(); + gen_ldst(lduw, s); + } else { /* tbb */ + gen_ldst(ldub, s); + } + gen_op_jmp_T0_im(s->pc); + s->is_jmp = DISAS_JUMP; + } else { + /* Load/store exclusive byte/halfword/doubleword. */ + op = (insn >> 4) & 0x3; + gen_movl_T1_reg(s, rn); + if (insn & (1 << 20)) { + switch (op) { + case 0: + gen_ldst(ldbex, s); + break; case 1: - gen_ldst(lduw, s); + gen_ldst(ldwex, s); break; - case 2: - gen_ldst(ldsb, s); + case 3: + gen_ldst(ldqex, s); + gen_movl_reg_T1(s, rd); break; default: + goto illegal_op; + } + gen_movl_reg_T0(s, rs); + } else { + gen_movl_T0_reg(s, rs); + switch (op) { + case 0: + gen_ldst(stbex, s); + break; + case 1: + gen_ldst(stwex, s); + break; case 3: - gen_ldst(ldsw, s); + gen_movl_T2_reg(s, rd); + gen_ldst(stqex, s); break; + default: + goto illegal_op; } - load = 1; - } else if (sh & 2) { - /* doubleword */ - if (sh & 1) { - /* store */ - gen_movl_T0_reg(s, rd); - gen_ldst(stl, s); + gen_movl_reg_T0(s, rm); + } + } + } else { + /* Load/store multiple, RFE, SRS. */ + if (((insn >> 23) & 1) == ((insn >> 24) & 1)) { + /* Not available in user mode. */ + if (!IS_USER(s)) + goto illegal_op; + if (insn & (1 << 20)) { + /* rfe */ + gen_movl_T1_reg(s, rn); + if (insn & (1 << 24)) { gen_op_addl_T1_im(4); - gen_movl_T0_reg(s, rd + 1); + } else { + gen_op_addl_T1_im(-4); + } + /* Load CPSR into T2 and PC into T0. */ + gen_ldst(ldl, s); + gen_op_movl_T2_T0(); + gen_op_addl_T1_im(-4); + gen_ldst(ldl, s); + if (insn & (1 << 21)) { + /* Base writeback. */ + if (insn & (1 << 24)) + gen_op_addl_T1_im(8); + gen_movl_reg_T1(s, rn); + } + gen_rfe(s); + } else { + /* srs */ + op = (insn & 0x1f); + if (op == (env->uncached_cpsr & CPSR_M)) { + gen_movl_T1_reg(s, 13); + } else { + gen_op_movl_T1_r13_banked(op); + } + if ((insn & (1 << 24)) == 0) { + gen_op_addl_T1_im(-8); + } + gen_movl_T0_reg(s, 14); + gen_ldst(stl, s); + gen_op_movl_T0_cpsr(); + gen_op_addl_T1_im(4); + gen_ldst(stl, s); + if (insn & (1 << 21)) { + if ((insn & (1 << 24)) == 0) { + gen_op_addl_T1_im(-4); + } else { + gen_op_addl_T1_im(4); + } + if (op == (env->uncached_cpsr & CPSR_M)) { + gen_movl_reg_T1(s, 13); + } else { + gen_op_movl_r13_T1_banked(op); + } + } + } + } else { + int i; + /* Load/store multiple. */ + gen_movl_T1_reg(s, rn); + offset = 0; + for (i = 0; i < 16; i++) { + if (insn & (1 << i)) + offset += 4; + } + if (insn & (1 << 24)) { + gen_op_addl_T1_im(-offset); + } + + for (i = 0; i < 16; i++) { + if ((insn & (1 << i)) == 0) + continue; + if (insn & (1 << 20)) { + /* Load. */ + gen_ldst(ldl, s); + if (i == 15) { + gen_bx(s); + } else { + gen_movl_reg_T0(s, i); + } + } else { + /* Store. */ + gen_movl_T0_reg(s, i); gen_ldst(stl, s); - load = 0; + } + gen_op_addl_T1_im(4); + } + if (insn & (1 << 21)) { + /* Base register writeback. */ + if (insn & (1 << 24)) { + gen_op_addl_T1_im(-offset); + } + /* Fault if writeback register is in register list. */ + if (insn & (1 << rn)) + goto illegal_op; + gen_movl_reg_T1(s, rn); + } + } + } + break; + case 5: /* Data processing register constant shift. */ + if (rn == 15) + gen_op_movl_T0_im(0); + else + gen_movl_T0_reg(s, rn); + gen_movl_T1_reg(s, rm); + op = (insn >> 21) & 0xf; + shiftop = (insn >> 4) & 3; + shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); + conds = (insn & (1 << 20)) != 0; + logic_cc = (conds && thumb2_logic_op(op)); + if (shift != 0) { + if (logic_cc) { + gen_shift_T1_im_cc[shiftop](shift); + } else { + gen_shift_T1_im[shiftop](shift); + } + } else if (shiftop != 0) { + if (logic_cc) { + gen_shift_T1_0_cc[shiftop](); + } else { + gen_shift_T1_0[shiftop](); + } + } + if (gen_thumb2_data_op(s, op, conds, 0)) + goto illegal_op; + if (rd != 15) + gen_movl_reg_T0(s, rd); + break; + case 13: /* Misc data processing. */ + op = ((insn >> 22) & 6) | ((insn >> 7) & 1); + if (op < 4 && (insn & 0xf000) != 0xf000) + goto illegal_op; + switch (op) { + case 0: /* Register controlled shift. */ + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if ((insn & 0x70) != 0) + goto illegal_op; + op = (insn >> 21) & 3; + if (insn & (1 << 20)) { + gen_shift_T1_T0_cc[op](); + gen_op_logic_T1_cc(); + } else { + gen_shift_T1_T0[op](); + } + gen_movl_reg_T1(s, rd); + break; + case 1: /* Sign/zero extend. */ + gen_movl_T1_reg(s, rm); + shift = (insn >> 4) & 3; + /* ??? In many cases it's not neccessary to do a + rotate, a shift is sufficient. */ + if (shift != 0) + gen_op_rorl_T1_im(shift * 8); + op = (insn >> 20) & 7; + switch (op) { + case 0: gen_op_sxth_T1(); break; + case 1: gen_op_uxth_T1(); break; + case 2: gen_op_sxtb16_T1(); break; + case 3: gen_op_uxtb16_T1(); break; + case 4: gen_op_sxtb_T1(); break; + case 5: gen_op_uxtb_T1(); break; + default: goto illegal_op; + } + if (rn != 15) { + gen_movl_T2_reg(s, rn); + if ((op >> 1) == 1) { + gen_op_add16_T1_T2(); + } else { + gen_op_addl_T1_T2(); + } + } + gen_movl_reg_T1(s, rd); + break; + case 2: /* SIMD add/subtract. */ + op = (insn >> 20) & 7; + shift = (insn >> 4) & 7; + if ((op & 3) == 3 || (shift & 3) == 3) + goto illegal_op; + gen_movl_T0_reg(s, rn); + gen_movl_T1_reg(s, rm); + gen_thumb2_parallel_addsub[op][shift](); + gen_movl_reg_T0(s, rd); + break; + case 3: /* Other data processing. */ + op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7); + if (op < 4) { + /* Saturating add/subtract. */ + gen_movl_T0_reg(s, rm); + gen_movl_T1_reg(s, rn); + if (op & 2) + gen_op_double_T1_saturate(); + if (op & 1) + gen_op_subl_T0_T1_saturate(); + else + gen_op_addl_T0_T1_saturate(); + } else { + gen_movl_T0_reg(s, rn); + switch (op) { + case 0x0a: /* rbit */ + gen_op_rbit_T0(); + break; + case 0x08: /* rev */ + gen_op_rev_T0(); + break; + case 0x09: /* rev16 */ + gen_op_rev16_T0(); + break; + case 0x0b: /* revsh */ + gen_op_revsh_T0(); + break; + case 0x10: /* sel */ + gen_movl_T1_reg(s, rm); + gen_op_sel_T0_T1(); + break; + case 0x18: /* clz */ + gen_op_clz_T0(); + break; + default: + goto illegal_op; + } + } + gen_movl_reg_T0(s, rd); + break; + case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */ + op = (insn >> 4) & 0xf; + gen_movl_T0_reg(s, rn); + gen_movl_T1_reg(s, rm); + switch ((insn >> 20) & 7) { + case 0: /* 32 x 32 -> 32 */ + gen_op_mul_T0_T1(); + if (rs != 15) { + gen_movl_T1_reg(s, rs); + if (op) + gen_op_rsbl_T0_T1(); + else + gen_op_addl_T0_T1(); + } + gen_movl_reg_T0(s, rd); + break; + case 1: /* 16 x 16 -> 32 */ + gen_mulxy(op & 2, op & 1); + if (rs != 15) { + gen_movl_T1_reg(s, rs); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + break; + case 2: /* Dual multiply add. */ + case 4: /* Dual multiply subtract. */ + if (op) + gen_op_swap_half_T1(); + gen_op_mul_dual_T0_T1(); + /* This addition cannot overflow. */ + if (insn & (1 << 22)) { + gen_op_subl_T0_T1(); + } else { + gen_op_addl_T0_T1(); + } + if (rs != 15) + { + gen_movl_T1_reg(s, rs); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + break; + case 3: /* 32 * 16 -> 32msb */ + if (op) + gen_op_sarl_T1_im(16); + else + gen_op_sxth_T1(); + gen_op_imulw_T0_T1(); + if (rs != 15) + { + gen_movl_T1_reg(s, rs); + gen_op_addl_T0_T1_setq(); + } + gen_movl_reg_T0(s, rd); + break; + case 5: case 6: /* 32 * 32 -> 32msb */ + gen_op_imull_T0_T1(); + if (insn & (1 << 5)) + gen_op_roundqd_T0_T1(); + else + gen_op_movl_T0_T1(); + if (rs != 15) { + gen_movl_T1_reg(s, rs); + if (insn & (1 << 21)) { + gen_op_addl_T0_T1(); } else { - /* load */ - gen_ldst(ldl, s); - gen_movl_reg_T0(s, rd); - gen_op_addl_T1_im(4); - gen_ldst(ldl, s); - rd++; - load = 1; + gen_op_rsbl_T0_T1(); } - address_offset = -4; - } else { - /* store */ - gen_movl_T0_reg(s, rd); - gen_ldst(stw, s); - load = 0; - } - /* Perform base writeback before the loaded value to - ensure correct behavior with overlapping index registers. - ldrd with base writeback is is undefined if the - destination and index registers overlap. */ - if (!(insn & (1 << 24))) { - gen_add_datah_offset(s, insn, address_offset); - gen_movl_reg_T1(s, rn); - } else if (insn & (1 << 21)) { - if (address_offset) - gen_op_addl_T1_im(address_offset); - gen_movl_reg_T1(s, rn); } - if (load) { - /* Complete the load. */ - gen_movl_reg_T0(s, rd); + gen_movl_reg_T0(s, rd); + break; + case 7: /* Unsigned sum of absolute differences. */ + gen_op_usad8_T0_T1(); + if (rs != 15) { + gen_movl_T1_reg(s, rs); + gen_op_addl_T0_T1(); } + gen_movl_reg_T0(s, rd); + break; } break; - case 0x4: - case 0x5: - case 0x6: - case 0x7: - /* Check for undefined extension instructions - * per the ARM Bible IE: - * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx - */ - sh = (0xf << 20) | (0xf << 4); - if (op1 == 0x7 && ((insn & sh) == sh)) - { - goto illegal_op; - } - /* load/store byte/word */ - rn = (insn >> 16) & 0xf; - rd = (insn >> 12) & 0xf; - gen_movl_T1_reg(s, rn); - i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000); - if (insn & (1 << 24)) - gen_add_data_offset(s, insn); - if (insn & (1 << 20)) { - /* load */ - s->is_mem = 1; -#if defined(CONFIG_USER_ONLY) - if (insn & (1 << 22)) - gen_op_ldub_raw(); + case 6: case 7: /* 64-bit multiply, Divide. */ + op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70); + gen_movl_T0_reg(s, rn); + gen_movl_T1_reg(s, rm); + if ((op & 0x50) == 0x10) { + /* sdiv, udiv */ + if (!arm_feature(env, ARM_FEATURE_DIV)) + goto illegal_op; + if (op & 0x20) + gen_op_udivl_T0_T1(); else - gen_op_ldl_raw(); -#else - if (insn & (1 << 22)) { - if (i) - gen_op_ldub_user(); - else - gen_op_ldub_kernel(); + gen_op_sdivl_T0_T1(); + gen_movl_reg_T0(s, rd); + } else if ((op & 0xe) == 0xc) { + /* Dual multiply accumulate long. */ + if (op & 1) + gen_op_swap_half_T1(); + gen_op_mul_dual_T0_T1(); + if (op & 0x10) { + gen_op_subl_T0_T1(); } else { - if (i) - gen_op_ldl_user(); - else - gen_op_ldl_kernel(); + gen_op_addl_T0_T1(); } -#endif + gen_op_signbit_T1_T0(); + gen_op_addq_T0_T1(rs, rd); + gen_movl_reg_T0(s, rs); + gen_movl_reg_T1(s, rd); } else { - /* store */ - gen_movl_T0_reg(s, rd); -#if defined(CONFIG_USER_ONLY) - if (insn & (1 << 22)) - gen_op_stb_raw(); - else - gen_op_stl_raw(); -#else - if (insn & (1 << 22)) { - if (i) - gen_op_stb_user(); - else - gen_op_stb_kernel(); + if (op & 0x20) { + /* Unsigned 64-bit multiply */ + gen_op_mull_T0_T1(); } else { - if (i) - gen_op_stl_user(); - else - gen_op_stl_kernel(); + if (op & 8) { + /* smlalxy */ + gen_mulxy(op & 2, op & 1); + gen_op_signbit_T1_T0(); + } else { + /* Signed 64-bit multiply */ + gen_op_imull_T0_T1(); + } } -#endif - } - if (!(insn & (1 << 24))) { - gen_add_data_offset(s, insn); - gen_movl_reg_T1(s, rn); - } else if (insn & (1 << 21)) - gen_movl_reg_T1(s, rn); { - } - if (insn & (1 << 20)) { - /* Complete the load. */ - if (rd == 15) - gen_bx(s); - else - gen_movl_reg_T0(s, rd); + if (op & 4) { + /* umaal */ + gen_op_addq_lo_T0_T1(rs); + gen_op_addq_lo_T0_T1(rd); + } else if (op & 0x40) { + /* 64-bit accumulate. */ + gen_op_addq_T0_T1(rs, rd); + } + gen_movl_reg_T0(s, rs); + gen_movl_reg_T1(s, rd); } break; - case 0x08: - case 0x09: - { - int j, n, user, loaded_base; - /* load/store multiple words */ - /* XXX: store correct base if write back */ - user = 0; - if (insn & (1 << 22)) { - if (IS_USER(s)) - goto illegal_op; /* only usable in supervisor mode */ - - if ((insn & (1 << 15)) == 0) - user = 1; + } + break; + case 6: case 7: case 14: case 15: + /* Coprocessor. */ + if (((insn >> 24) & 3) == 3) { + /* Translate into the equivalent ARM encoding. */ + insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4); + if (disas_neon_data_insn(env, s, insn)) + goto illegal_op; + } else { + if (insn & (1 << 28)) + goto illegal_op; + if (disas_coproc_insn (env, s, insn)) + goto illegal_op; + } + break; + case 8: case 9: case 10: case 11: + if (insn & (1 << 15)) { + /* Branches, misc control. */ + if (insn & 0x5000) { + /* Unconditional branch. */ + /* signextend(hw1[10:0]) -> offset[:12]. */ + offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff; + /* hw1[10:0] -> offset[11:1]. */ + offset |= (insn & 0x7ff) << 1; + /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22] + offset[24:22] already have the same value because of the + sign extension above. */ + offset ^= ((~insn) & (1 << 13)) << 10; + offset ^= ((~insn) & (1 << 11)) << 11; + + addr = s->pc; + if (insn & (1 << 14)) { + /* Branch and link. */ + gen_op_movl_T1_im(addr | 1); + gen_movl_reg_T1(s, 14); } - rn = (insn >> 16) & 0xf; - gen_movl_T1_reg(s, rn); - /* compute total size */ - loaded_base = 0; - n = 0; - for(i=0;i<16;i++) { - if (insn & (1 << i)) - n++; + addr += offset; + if (insn & (1 << 12)) { + /* b/bl */ + gen_jmp(s, addr); + } else { + /* blx */ + addr &= ~(uint32_t)2; + gen_op_movl_T0_im(addr); + gen_bx(s); } - /* XXX: test invalid n == 0 case ? */ - if (insn & (1 << 23)) { - if (insn & (1 << 24)) { - /* pre increment */ - gen_op_addl_T1_im(4); - } else { - /* post increment */ - } + } else if (((insn >> 23) & 7) == 7) { + /* Misc control */ + if (insn & (1 << 13)) + goto illegal_op; + + if (insn & (1 << 26)) { + /* Secure monitor call (v6Z) */ + goto illegal_op; /* not implemented. */ } else { - if (insn & (1 << 24)) { - /* pre decrement */ - gen_op_addl_T1_im(-(n * 4)); - } else { - /* post decrement */ - if (n != 1) - gen_op_addl_T1_im(-((n - 1) * 4)); + op = (insn >> 20) & 7; + switch (op) { + case 0: /* msr cpsr. */ + if (IS_M(env)) { + gen_op_v7m_msr_T0(insn & 0xff); + gen_movl_reg_T0(s, rn); + gen_lookup_tb(s); + break; + } + /* fall through */ + case 1: /* msr spsr. */ + if (IS_M(env)) + goto illegal_op; + gen_movl_T0_reg(s, rn); + if (gen_set_psr_T0(s, + msr_mask(env, s, (insn >> 8) & 0xf, op == 1), + op == 1)) + goto illegal_op; + break; + case 2: /* cps, nop-hint. */ + if (((insn >> 8) & 7) == 0) { + gen_nop_hint(s, insn & 0xff); + } + /* Implemented as NOP in user mode. */ + if (IS_USER(s)) + break; + offset = 0; + imm = 0; + if (insn & (1 << 10)) { + if (insn & (1 << 7)) + offset |= CPSR_A; + if (insn & (1 << 6)) + offset |= CPSR_I; + if (insn & (1 << 5)) + offset |= CPSR_F; + if (insn & (1 << 9)) + imm = CPSR_A | CPSR_I | CPSR_F; + } + if (insn & (1 << 8)) { + offset |= 0x1f; + imm |= (insn & 0x1f); + } + if (offset) { + gen_op_movl_T0_im(imm); + gen_set_psr_T0(s, offset, 0); + } + break; + case 3: /* Special control operations. */ + op = (insn >> 4) & 0xf; + switch (op) { + case 2: /* clrex */ + gen_op_clrex(); + break; + case 4: /* dsb */ + case 5: /* dmb */ + case 6: /* isb */ + /* These execute as NOPs. */ + ARCH(7); + break; + default: + goto illegal_op; + } + break; + case 4: /* bxj */ + /* Trivial implementation equivalent to bx. */ + gen_movl_T0_reg(s, rn); + gen_bx(s); + break; + case 5: /* Exception return. */ + /* Unpredictable in user mode. */ + goto illegal_op; + case 6: /* mrs cpsr. */ + if (IS_M(env)) { + gen_op_v7m_mrs_T0(insn & 0xff); + } else { + gen_op_movl_T0_cpsr(); + } + gen_movl_reg_T0(s, rd); + break; + case 7: /* mrs spsr. */ + /* Not accessible in user mode. */ + if (IS_USER(s) || IS_M(env)) + goto illegal_op; + gen_op_movl_T0_spsr(); + gen_movl_reg_T0(s, rd); + break; } } - j = 0; - for(i=0;i<16;i++) { - if (insn & (1 << i)) { - if (insn & (1 << 20)) { - /* load */ - gen_ldst(ldl, s); - if (i == 15) { - gen_bx(s); - } else if (user) { - gen_op_movl_user_T0(i); - } else if (i == rn) { - gen_op_movl_T2_T0(); - loaded_base = 1; - } else { - gen_movl_reg_T0(s, i); - } + } else { + /* Conditional branch. */ + op = (insn >> 22) & 0xf; + /* Generate a conditional jump to next instruction. */ + s->condlabel = gen_new_label(); + gen_test_cc[op ^ 1](s->condlabel); + s->condjmp = 1; + + /* offset[11:1] = insn[10:0] */ + offset = (insn & 0x7ff) << 1; + /* offset[17:12] = insn[21:16]. */ + offset |= (insn & 0x003f0000) >> 4; + /* offset[31:20] = insn[26]. */ + offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11; + /* offset[18] = insn[13]. */ + offset |= (insn & (1 << 13)) << 5; + /* offset[19] = insn[11]. */ + offset |= (insn & (1 << 11)) << 8; + + /* jump to the offset */ + addr = s->pc + offset; + gen_jmp(s, addr); + } + } else { + /* Data processing immediate. */ + if (insn & (1 << 25)) { + if (insn & (1 << 24)) { + if (insn & (1 << 20)) + goto illegal_op; + /* Bitfield/Saturate. */ + op = (insn >> 21) & 7; + imm = insn & 0x1f; + shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); + if (rn == 15) + gen_op_movl_T1_im(0); + else + gen_movl_T1_reg(s, rn); + switch (op) { + case 2: /* Signed bitfield extract. */ + imm++; + if (shift + imm > 32) + goto illegal_op; + if (imm < 32) + gen_op_sbfx_T1(shift, imm); + break; + case 6: /* Unsigned bitfield extract. */ + imm++; + if (shift + imm > 32) + goto illegal_op; + if (imm < 32) + gen_op_ubfx_T1(shift, (1u << imm) - 1); + break; + case 3: /* Bitfield insert/clear. */ + if (imm < shift) + goto illegal_op; + imm = imm + 1 - shift; + if (imm != 32) { + gen_movl_T0_reg(s, rd); + gen_op_bfi_T1_T0(shift, ((1u << imm) - 1) << shift); + } + break; + case 7: + goto illegal_op; + default: /* Saturate. */ + gen_movl_T1_reg(s, rn); + if (shift) { + if (op & 1) + gen_op_sarl_T1_im(shift); + else + gen_op_shll_T1_im(shift); + } + if (op & 4) { + /* Unsigned. */ + gen_op_ssat_T1(imm); + if ((op & 1) && shift == 0) + gen_op_usat16_T1(imm); + else + gen_op_usat_T1(imm); } else { - /* store */ - if (i == 15) { - /* special case: r15 = PC + 8 */ - val = (long)s->pc + 4; - gen_op_movl_TN_im[0](val); - } else if (user) { - gen_op_movl_T0_user(i); - } else { - gen_movl_T0_reg(s, i); - } - gen_ldst(stl, s); + /* Signed. */ + gen_op_ssat_T1(imm); + if ((op & 1) && shift == 0) + gen_op_ssat16_T1(imm); + else + gen_op_ssat_T1(imm); } - j++; - /* no need to add after the last transfer */ - if (j != n) - gen_op_addl_T1_im(4); + break; } - } - if (insn & (1 << 21)) { - /* write back */ - if (insn & (1 << 23)) { - if (insn & (1 << 24)) { - /* pre increment */ + gen_movl_reg_T1(s, rd); + } else { + imm = ((insn & 0x04000000) >> 15) + | ((insn & 0x7000) >> 4) | (insn & 0xff); + if (insn & (1 << 22)) { + /* 16-bit immediate. */ + imm |= (insn >> 4) & 0xf000; + if (insn & (1 << 23)) { + /* movt */ + gen_movl_T0_reg(s, rd); + gen_op_movtop_T0_im(imm << 16); } else { - /* post increment */ - gen_op_addl_T1_im(4); + /* movw */ + gen_op_movl_T0_im(imm); } } else { - if (insn & (1 << 24)) { - /* pre decrement */ - if (n != 1) - gen_op_addl_T1_im(-((n - 1) * 4)); + /* Add/sub 12-bit immediate. */ + if (rn == 15) { + addr = s->pc & ~(uint32_t)3; + if (insn & (1 << 23)) + addr -= imm; + else + addr += imm; + gen_op_movl_T0_im(addr); } else { - /* post decrement */ - gen_op_addl_T1_im(-(n * 4)); + gen_movl_T0_reg(s, rn); + gen_op_movl_T1_im(imm); + if (insn & (1 << 23)) + gen_op_subl_T0_T1(); + else + gen_op_addl_T0_T1(); } - } - gen_movl_reg_T1(s, rn); - } - if (loaded_base) { - gen_op_movl_T0_T2(); - gen_movl_reg_T0(s, rn); + } + gen_movl_reg_T0(s, rd); } - if ((insn & (1 << 22)) && !user) { - /* Restore CPSR from SPSR. */ - gen_op_movl_T0_spsr(); - gen_op_movl_cpsr_T0(0xffffffff); - s->is_jmp = DISAS_UPDATE; + } else { + int shifter_out = 0; + /* modified 12-bit immediate. */ + shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12); + imm = (insn & 0xff); + switch (shift) { + case 0: /* XY */ + /* Nothing to do. */ + break; + case 1: /* 00XY00XY */ + imm |= imm << 16; + break; + case 2: /* XY00XY00 */ + imm |= imm << 16; + imm <<= 8; + break; + case 3: /* XYXYXYXY */ + imm |= imm << 16; + imm |= imm << 8; + break; + default: /* Rotated constant. */ + shift = (shift << 1) | (imm >> 7); + imm |= 0x80; + imm = imm << (32 - shift); + shifter_out = 1; + break; } - } - break; - case 0xa: - case 0xb: - { - int32_t offset; - - /* branch (and link) */ - val = (int32_t)s->pc; - if (insn & (1 << 24)) { - gen_op_movl_T0_im(val); - gen_op_movl_reg_TN[0][14](); + gen_op_movl_T1_im(imm); + rn = (insn >> 16) & 0xf; + if (rn == 15) + gen_op_movl_T0_im(0); + else + gen_movl_T0_reg(s, rn); + op = (insn >> 21) & 0xf; + if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0, + shifter_out)) + goto illegal_op; + rd = (insn >> 8) & 0xf; + if (rd != 15) { + gen_movl_reg_T0(s, rd); } - offset = (((int32_t)insn << 8) >> 8); - val += (offset << 2) + 4; - gen_jmp(s, val); } - break; - case 0xc: - case 0xd: - case 0xe: - /* Coprocessor. */ - op1 = (insn >> 8) & 0xf; - if (arm_feature(env, ARM_FEATURE_XSCALE) && - ((env->cp15.c15_cpar ^ 0x3fff) & (1 << op1))) + } + break; + case 12: /* Load/store single data item. */ + { + int postinc = 0; + int writeback = 0; + if ((insn & 0x01100000) == 0x01000000) { + if (disas_neon_ls_insn(env, s, insn)) goto illegal_op; - switch (op1) { - case 0 ... 1: - if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - if (disas_iwmmxt_insn(env, s, insn)) - goto illegal_op; - } else if (arm_feature(env, ARM_FEATURE_XSCALE)) { - if (disas_dsp_insn(env, s, insn)) + break; + } + if (rn == 15) { + /* PC relative. */ + /* s->pc has already been incremented by 4. */ + imm = s->pc & 0xfffffffc; + if (insn & (1 << 23)) + imm += insn & 0xfff; + else + imm -= insn & 0xfff; + gen_op_movl_T1_im(imm); + } else { + gen_movl_T1_reg(s, rn); + if (insn & (1 << 23)) { + /* Positive offset. */ + imm = insn & 0xfff; + gen_op_addl_T1_im(imm); + } else { + op = (insn >> 8) & 7; + imm = insn & 0xff; + switch (op) { + case 0: case 8: /* Shifted Register. */ + shift = (insn >> 4) & 0xf; + if (shift > 3) goto illegal_op; - } else - goto illegal_op; - break; - case 2 ... 9: - case 12 ... 14: - if (disas_cp_insn (env, s, insn)) - goto illegal_op; - break; - case 10: - case 11: - if (disas_vfp_insn (env, s, insn)) + gen_movl_T2_reg(s, rm); + if (shift) + gen_op_shll_T2_im(shift); + gen_op_addl_T1_T2(); + break; + case 4: /* Negative offset. */ + gen_op_addl_T1_im(-imm); + break; + case 6: /* User privilege. */ + gen_op_addl_T1_im(imm); + break; + case 1: /* Post-decrement. */ + imm = -imm; + /* Fall through. */ + case 3: /* Post-increment. */ + gen_op_movl_T2_im(imm); + postinc = 1; + writeback = 1; + break; + case 5: /* Pre-decrement. */ + imm = -imm; + /* Fall through. */ + case 7: /* Pre-increment. */ + gen_op_addl_T1_im(imm); + writeback = 1; + break; + default: goto illegal_op; - break; - case 15: - if (disas_cp15_insn (env, s, insn)) + } + } + } + op = ((insn >> 21) & 3) | ((insn >> 22) & 4); + if (insn & (1 << 20)) { + /* Load. */ + if (rs == 15 && op != 2) { + if (op & 2) goto illegal_op; - break; - default: - /* unknown coprocessor. */ + /* Memory hint. Implemented as NOP. */ + } else { + switch (op) { + case 0: gen_ldst(ldub, s); break; + case 4: gen_ldst(ldsb, s); break; + case 1: gen_ldst(lduw, s); break; + case 5: gen_ldst(ldsw, s); break; + case 2: gen_ldst(ldl, s); break; + default: goto illegal_op; + } + if (rs == 15) { + gen_bx(s); + } else { + gen_movl_reg_T0(s, rs); + } + } + } else { + /* Store. */ + if (rs == 15) goto illegal_op; + gen_movl_T0_reg(s, rs); + switch (op) { + case 0: gen_ldst(stb, s); break; + case 1: gen_ldst(stw, s); break; + case 2: gen_ldst(stl, s); break; + default: goto illegal_op; } - break; - case 0xf: - /* swi */ - gen_op_movl_T0_im((long)s->pc); - gen_op_movl_reg_TN[0][15](); - gen_op_swi(); - s->is_jmp = DISAS_JUMP; - break; - default: - illegal_op: - gen_op_movl_T0_im((long)s->pc - 4); - gen_op_movl_reg_TN[0][15](); - gen_op_undef_insn(); - s->is_jmp = DISAS_JUMP; - break; } + if (postinc) + gen_op_addl_T1_im(imm); + if (writeback) + gen_movl_reg_T1(s, rn); + } + break; + default: + goto illegal_op; } + return 0; +illegal_op: + return 1; } -static void disas_thumb_insn(DisasContext *s) +static void disas_thumb_insn(CPUState *env, DisasContext *s) { uint32_t val, insn, op, rm, rn, rd, shift, cond; int32_t offset; int i; + if (s->condexec_mask) { + cond = s->condexec_cond; + s->condlabel = gen_new_label(); + gen_test_cc[cond ^ 1](s->condlabel); + s->condjmp = 1; + } + insn = lduw_code(s->pc); s->pc += 2; @@ -2990,17 +6851,27 @@ static void disas_thumb_insn(DisasContext *s) rm = (insn >> 6) & 7; gen_movl_T1_reg(s, rm); } - if (insn & (1 << 9)) - gen_op_subl_T0_T1_cc(); - else - gen_op_addl_T0_T1_cc(); + if (insn & (1 << 9)) { + if (s->condexec_mask) + gen_op_subl_T0_T1(); + else + gen_op_subl_T0_T1_cc(); + } else { + if (s->condexec_mask) + gen_op_addl_T0_T1(); + else + gen_op_addl_T0_T1_cc(); + } gen_movl_reg_T0(s, rd); } else { /* shift immediate */ rm = (insn >> 3) & 7; shift = (insn >> 6) & 0x1f; gen_movl_T0_reg(s, rm); - gen_shift_T0_im_thumb[op](shift); + if (s->condexec_mask) + gen_shift_T0_im_thumb[op](shift); + else + gen_shift_T0_im_thumb_cc[op](shift); gen_movl_reg_T0(s, rd); } break; @@ -3016,16 +6887,23 @@ static void disas_thumb_insn(DisasContext *s) } switch (op) { case 0: /* mov */ - gen_op_logic_T0_cc(); + if (!s->condexec_mask) + gen_op_logic_T0_cc(); break; case 1: /* cmp */ gen_op_subl_T0_T1_cc(); break; case 2: /* add */ - gen_op_addl_T0_T1_cc(); + if (s->condexec_mask) + gen_op_addl_T0_T1(); + else + gen_op_addl_T0_T1_cc(); break; case 3: /* sub */ - gen_op_subl_T0_T1_cc(); + if (s->condexec_mask) + gen_op_subl_T0_T1(); + else + gen_op_subl_T0_T1_cc(); break; } if (op != 1) @@ -3099,33 +6977,57 @@ static void disas_thumb_insn(DisasContext *s) switch (op) { case 0x0: /* and */ gen_op_andl_T0_T1(); - gen_op_logic_T0_cc(); + if (!s->condexec_mask) + gen_op_logic_T0_cc(); break; case 0x1: /* eor */ gen_op_xorl_T0_T1(); - gen_op_logic_T0_cc(); + if (!s->condexec_mask) + gen_op_logic_T0_cc(); break; case 0x2: /* lsl */ - gen_op_shll_T1_T0_cc(); - gen_op_logic_T1_cc(); + if (s->condexec_mask) { + gen_op_shll_T1_T0(); + } else { + gen_op_shll_T1_T0_cc(); + gen_op_logic_T1_cc(); + } break; case 0x3: /* lsr */ - gen_op_shrl_T1_T0_cc(); - gen_op_logic_T1_cc(); + if (s->condexec_mask) { + gen_op_shrl_T1_T0(); + } else { + gen_op_shrl_T1_T0_cc(); + gen_op_logic_T1_cc(); + } break; case 0x4: /* asr */ - gen_op_sarl_T1_T0_cc(); - gen_op_logic_T1_cc(); + if (s->condexec_mask) { + gen_op_sarl_T1_T0(); + } else { + gen_op_sarl_T1_T0_cc(); + gen_op_logic_T1_cc(); + } break; case 0x5: /* adc */ - gen_op_adcl_T0_T1_cc(); + if (s->condexec_mask) + gen_op_adcl_T0_T1(); + else + gen_op_adcl_T0_T1_cc(); break; case 0x6: /* sbc */ - gen_op_sbcl_T0_T1_cc(); + if (s->condexec_mask) + gen_op_sbcl_T0_T1(); + else + gen_op_sbcl_T0_T1_cc(); break; case 0x7: /* ror */ - gen_op_rorl_T1_T0_cc(); - gen_op_logic_T1_cc(); + if (s->condexec_mask) { + gen_op_rorl_T1_T0(); + } else { + gen_op_rorl_T1_T0_cc(); + gen_op_logic_T1_cc(); + } break; case 0x8: /* tst */ gen_op_andl_T0_T1(); @@ -3133,7 +7035,10 @@ static void disas_thumb_insn(DisasContext *s) rd = 16; break; case 0x9: /* neg */ - gen_op_subl_T0_T1_cc(); + if (s->condexec_mask) + gen_op_subl_T0_T1(); + else + gen_op_subl_T0_T1_cc(); break; case 0xa: /* cmp */ gen_op_subl_T0_T1_cc(); @@ -3145,19 +7050,23 @@ static void disas_thumb_insn(DisasContext *s) break; case 0xc: /* orr */ gen_op_orl_T0_T1(); - gen_op_logic_T0_cc(); + if (!s->condexec_mask) + gen_op_logic_T0_cc(); break; case 0xd: /* mul */ gen_op_mull_T0_T1(); - gen_op_logic_T0_cc(); + if (!s->condexec_mask) + gen_op_logic_T0_cc(); break; case 0xe: /* bic */ gen_op_bicl_T0_T1(); - gen_op_logic_T0_cc(); + if (!s->condexec_mask) + gen_op_logic_T0_cc(); break; case 0xf: /* mvn */ gen_op_notl_T1(); - gen_op_logic_T1_cc(); + if (!s->condexec_mask) + gen_op_logic_T1_cc(); val = 1; rm = rd; break; @@ -3323,6 +7232,19 @@ static void disas_thumb_insn(DisasContext *s) gen_movl_reg_T1(s, 13); break; + case 2: /* sign/zero extend. */ + ARCH(6); + rd = insn & 7; + rm = (insn >> 3) & 7; + gen_movl_T1_reg(s, rm); + switch ((insn >> 6) & 3) { + case 0: gen_op_sxth_T1(); break; + case 1: gen_op_sxtb_T1(); break; + case 2: gen_op_uxth_T1(); break; + case 3: gen_op_uxtb_T1(); break; + } + gen_movl_reg_T1(s, rd); + break; case 4: case 5: case 0xc: case 0xd: /* push/pop */ gen_movl_T1_reg(s, 13); @@ -3378,13 +7300,82 @@ static void disas_thumb_insn(DisasContext *s) gen_bx(s); break; + case 1: case 3: case 9: case 11: /* czb */ + rm = insn & 7; + gen_movl_T0_reg(s, rm); + s->condlabel = gen_new_label(); + s->condjmp = 1; + if (insn & (1 << 11)) + gen_op_testn_T0(s->condlabel); + else + gen_op_test_T0(s->condlabel); + + offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3; + val = (uint32_t)s->pc + 2; + val += offset; + gen_jmp(s, val); + break; + + case 15: /* IT, nop-hint. */ + if ((insn & 0xf) == 0) { + gen_nop_hint(s, (insn >> 4) & 0xf); + break; + } + /* If Then. */ + s->condexec_cond = (insn >> 4) & 0xe; + s->condexec_mask = insn & 0x1f; + /* No actual code generated for this insn, just setup state. */ + break; + case 0xe: /* bkpt */ + gen_set_condexec(s); gen_op_movl_T0_im((long)s->pc - 2); gen_op_movl_reg_TN[0][15](); gen_op_bkpt(); s->is_jmp = DISAS_JUMP; break; + case 0xa: /* rev */ + ARCH(6); + rn = (insn >> 3) & 0x7; + rd = insn & 0x7; + gen_movl_T0_reg(s, rn); + switch ((insn >> 6) & 3) { + case 0: gen_op_rev_T0(); break; + case 1: gen_op_rev16_T0(); break; + case 3: gen_op_revsh_T0(); break; + default: goto illegal_op; + } + gen_movl_reg_T0(s, rd); + break; + + case 6: /* cps */ + ARCH(6); + if (IS_USER(s)) + break; + if (IS_M(env)) { + val = (insn & (1 << 4)) != 0; + gen_op_movl_T0_im(val); + /* PRIMASK */ + if (insn & 1) + gen_op_v7m_msr_T0(16); + /* FAULTMASK */ + if (insn & 2) + gen_op_v7m_msr_T0(17); + + gen_lookup_tb(s); + } else { + if (insn & (1 << 4)) + shift = CPSR_A | CPSR_I | CPSR_F; + else + shift = 0; + + val = ((insn & 7) << 6) & shift; + gen_op_movl_T0_im(val); + gen_set_psr_T0(s, shift, 0); + } + break; + default: goto undef; } @@ -3423,19 +7414,17 @@ static void disas_thumb_insn(DisasContext *s) if (cond == 0xf) { /* swi */ + gen_set_condexec(s); gen_op_movl_T0_im((long)s->pc | 1); /* Don't set r15. */ gen_op_movl_reg_TN[0][15](); - gen_op_swi(); - s->is_jmp = DISAS_JUMP; + s->is_jmp = DISAS_SWI; break; } /* generate a conditional jump to next instruction */ s->condlabel = gen_new_label(); gen_test_cc[cond ^ 1](s->condlabel); s->condjmp = 1; - //gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc); - //s->is_jmp = DISAS_JUMP_NEXT; gen_movl_T1_reg(s, 15); /* jump to the offset */ @@ -3446,22 +7435,12 @@ static void disas_thumb_insn(DisasContext *s) break; case 14: - /* unconditional branch */ if (insn & (1 << 11)) { - /* Second half of blx. */ - offset = ((insn & 0x7ff) << 1); - gen_movl_T0_reg(s, 14); - gen_op_movl_T1_im(offset); - gen_op_addl_T0_T1(); - gen_op_movl_T1_im(0xfffffffc); - gen_op_andl_T0_T1(); - - val = (uint32_t)s->pc; - gen_op_movl_T1_im(val | 1); - gen_movl_reg_T1(s, 14); - gen_bx(s); + if (disas_thumb2_insn(env, s, insn)) + goto undef32; break; } + /* unconditional branch */ val = (uint32_t)s->pc; offset = ((int32_t)insn << 21) >> 21; val += (offset << 1) + 2; @@ -3469,51 +7448,21 @@ static void disas_thumb_insn(DisasContext *s) break; case 15: - /* branch and link [and switch to arm] */ - if ((s->pc & ~TARGET_PAGE_MASK) == 0) { - /* Instruction spans a page boundary. Implement it as two - 16-bit instructions in case the second half causes an - prefetch abort. */ - offset = ((int32_t)insn << 21) >> 9; - val = s->pc + 2 + offset; - gen_op_movl_T0_im(val); - gen_movl_reg_T0(s, 14); - break; - } - if (insn & (1 << 11)) { - /* Second half of bl. */ - offset = ((insn & 0x7ff) << 1) | 1; - gen_movl_T0_reg(s, 14); - gen_op_movl_T1_im(offset); - gen_op_addl_T0_T1(); - - val = (uint32_t)s->pc; - gen_op_movl_T1_im(val | 1); - gen_movl_reg_T1(s, 14); - gen_bx(s); - break; - } - offset = ((int32_t)insn << 21) >> 10; - insn = lduw_code(s->pc); - offset |= insn & 0x7ff; - - val = (uint32_t)s->pc + 2; - gen_op_movl_T1_im(val | 1); - gen_movl_reg_T1(s, 14); - - val += offset << 1; - if (insn & (1 << 12)) { - /* bl */ - gen_jmp(s, val); - } else { - /* blx */ - val &= ~(uint32_t)2; - gen_op_movl_T0_im(val); - gen_bx(s); - } + if (disas_thumb2_insn(env, s, insn)) + goto undef32; + break; } return; +undef32: + gen_set_condexec(s); + gen_op_movl_T0_im((long)s->pc - 4); + gen_op_movl_reg_TN[0][15](); + gen_op_undef_insn(); + s->is_jmp = DISAS_JUMP; + return; +illegal_op: undef: + gen_set_condexec(s); gen_op_movl_T0_im((long)s->pc - 2); gen_op_movl_reg_TN[0][15](); gen_op_undef_insn(); @@ -3547,21 +7496,44 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->singlestep_enabled = env->singlestep_enabled; dc->condjmp = 0; dc->thumb = env->thumb; + dc->condexec_mask = (env->condexec_bits & 0xf) << 1; + dc->condexec_cond = env->condexec_bits >> 4; dc->is_mem = 0; #if !defined(CONFIG_USER_ONLY) - dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; + if (IS_M(env)) { + dc->user = ((env->v7m.exception == 0) && (env->v7m.control & 1)); + } else { + dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; + } #endif next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; nb_gen_labels = 0; lj = -1; + /* Reset the conditional execution bits immediately. This avoids + complications trying to do it at the end of the block. */ + if (env->condexec_bits) + gen_op_set_condexec(0); do { +#ifndef CONFIG_USER_ONLY + if (dc->pc >= 0xfffffff0 && IS_M(env)) { + /* We always get here via a jump, so know we are not in a + conditional execution block. */ + gen_op_exception_exit(); + } +#endif + if (env->nb_breakpoints > 0) { for(j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == dc->pc) { + gen_set_condexec(dc); gen_op_movl_T0_im((long)dc->pc); gen_op_movl_reg_TN[0][15](); gen_op_debug(); dc->is_jmp = DISAS_JUMP; + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + dc->pc += 2; + goto done_generating; break; } } @@ -3577,10 +7549,19 @@ static inline int gen_intermediate_code_internal(CPUState *env, gen_opc_instr_start[lj] = 1; } - if (env->thumb) - disas_thumb_insn(dc); - else - disas_arm_insn(env, dc); + if (env->thumb) { + disas_thumb_insn(env, dc); + if (dc->condexec_mask) { + dc->condexec_cond = (dc->condexec_cond & 0xe) + | ((dc->condexec_mask >> 4) & 1); + dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f; + if (dc->condexec_mask == 0) { + dc->condexec_cond = 0; + } + } + } else { + disas_arm_insn(env, dc); + } if (dc->condjmp && !dc->is_jmp) { gen_set_label(dc->condlabel); @@ -3599,13 +7580,19 @@ static inline int gen_intermediate_code_internal(CPUState *env, } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && dc->pc < next_page_start); + /* At this stage dc->condjmp will only be set when the skipped - * instruction was a conditional branch, and the PC has already been - * written. */ + instruction was a conditional branch or trap, and the PC has + already been written. */ if (__builtin_expect(env->singlestep_enabled, 0)) { /* Make sure the pc is updated, and raise a debug exception. */ if (dc->condjmp) { - gen_op_debug(); + gen_set_condexec(dc); + if (dc->is_jmp == DISAS_SWI) { + gen_op_swi(); + } else { + gen_op_debug(); + } gen_set_label(dc->condlabel); } if (dc->condjmp || !dc->is_jmp) { @@ -3613,8 +7600,24 @@ static inline int gen_intermediate_code_internal(CPUState *env, gen_op_movl_reg_TN[0][15](); dc->condjmp = 0; } - gen_op_debug(); + gen_set_condexec(dc); + if (dc->is_jmp == DISAS_SWI && !dc->condjmp) { + gen_op_swi(); + } else { + /* FIXME: Single stepping a WFI insn will not halt + the CPU. */ + gen_op_debug(); + } } else { + /* While branches must always occur at the end of an IT block, + there are a few other things that can cause us to terminate + the TB in the middel of an IT block: + - Exception generating instructions (bkpt, swi, undefined). + - Page boundaries. + - Hardware watchpoints. + Hardware breakpoints have already been handled and skip this code. + */ + gen_set_condexec(dc); switch(dc->is_jmp) { case DISAS_NEXT: gen_goto_tb(dc, 1, dc->pc); @@ -3629,13 +7632,21 @@ static inline int gen_intermediate_code_internal(CPUState *env, case DISAS_TB_JUMP: /* nothing more to generate */ break; + case DISAS_WFI: + gen_op_wfi(); + break; + case DISAS_SWI: + gen_op_swi(); + break; } if (dc->condjmp) { gen_set_label(dc->condlabel); + gen_set_condexec(dc); gen_goto_tb(dc, 1, dc->pc); dc->condjmp = 0; } } +done_generating: *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS @@ -3676,6 +7687,7 @@ static const char *cpu_mode_names[16] = { "usr", "fiq", "irq", "svc", "???", "???", "???", "abt", "???", "???", "???", "und", "???", "???", "???", "sys" }; + void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) diff --git a/vl.c b/vl.c index d1ae8cab9..7ffc904e0 100644 --- a/vl.c +++ b/vl.c @@ -6126,7 +6126,9 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32(f, env->cp15.c1_sys); qemu_put_be32(f, env->cp15.c1_coproc); qemu_put_be32(f, env->cp15.c1_xscaleauxcr); - qemu_put_be32(f, env->cp15.c2_base); + qemu_put_be32(f, env->cp15.c2_base0); + qemu_put_be32(f, env->cp15.c2_base1); + qemu_put_be32(f, env->cp15.c2_mask); qemu_put_be32(f, env->cp15.c2_data); qemu_put_be32(f, env->cp15.c2_insn); qemu_put_be32(f, env->cp15.c3); @@ -6141,6 +6143,9 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32(f, env->cp15.c9_data); qemu_put_be32(f, env->cp15.c13_fcse); qemu_put_be32(f, env->cp15.c13_context); + qemu_put_be32(f, env->cp15.c13_tls1); + qemu_put_be32(f, env->cp15.c13_tls2); + qemu_put_be32(f, env->cp15.c13_tls3); qemu_put_be32(f, env->cp15.c15_cpar); qemu_put_be32(f, env->features); @@ -6159,6 +6164,15 @@ void cpu_save(QEMUFile *f, void *opaque) /* TODO: Should use proper FPSCR access functions. */ qemu_put_be32(f, env->vfp.vec_len); qemu_put_be32(f, env->vfp.vec_stride); + + if (arm_feature(env, ARM_FEATURE_VFP3)) { + for (i = 16; i < 32; i++) { + CPU_DoubleU u; + u.d = env->vfp.regs[i]; + qemu_put_be32(f, u.l.upper); + qemu_put_be32(f, u.l.lower); + } + } } if (arm_feature(env, ARM_FEATURE_IWMMXT)) { @@ -6169,6 +6183,15 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_be32(f, env->iwmmxt.cregs[i]); } } + + if (arm_feature(env, ARM_FEATURE_M)) { + qemu_put_be32(f, env->v7m.other_sp); + qemu_put_be32(f, env->v7m.vecbase); + qemu_put_be32(f, env->v7m.basepri); + qemu_put_be32(f, env->v7m.control); + qemu_put_be32(f, env->v7m.current_sp); + qemu_put_be32(f, env->v7m.exception); + } } int cpu_load(QEMUFile *f, void *opaque, int version_id) @@ -6176,7 +6199,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) CPUARMState *env = (CPUARMState *)opaque; int i; - if (version_id != 0) + if (version_id != ARM_CPU_SAVE_VERSION) return -EINVAL; for (i = 0; i < 16; i++) { @@ -6198,7 +6221,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) env->cp15.c1_sys = qemu_get_be32(f); env->cp15.c1_coproc = qemu_get_be32(f); env->cp15.c1_xscaleauxcr = qemu_get_be32(f); - env->cp15.c2_base = qemu_get_be32(f); + env->cp15.c2_base0 = qemu_get_be32(f); + env->cp15.c2_base1 = qemu_get_be32(f); + env->cp15.c2_mask = qemu_get_be32(f); env->cp15.c2_data = qemu_get_be32(f); env->cp15.c2_insn = qemu_get_be32(f); env->cp15.c3 = qemu_get_be32(f); @@ -6213,6 +6238,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) env->cp15.c9_data = qemu_get_be32(f); env->cp15.c13_fcse = qemu_get_be32(f); env->cp15.c13_context = qemu_get_be32(f); + env->cp15.c13_tls1 = qemu_get_be32(f); + env->cp15.c13_tls2 = qemu_get_be32(f); + env->cp15.c13_tls3 = qemu_get_be32(f); env->cp15.c15_cpar = qemu_get_be32(f); env->features = qemu_get_be32(f); @@ -6231,6 +6259,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) /* TODO: Should use proper FPSCR access functions. */ env->vfp.vec_len = qemu_get_be32(f); env->vfp.vec_stride = qemu_get_be32(f); + + if (arm_feature(env, ARM_FEATURE_VFP3)) { + for (i = 0; i < 16; i++) { + CPU_DoubleU u; + u.l.upper = qemu_get_be32(f); + u.l.lower = qemu_get_be32(f); + env->vfp.regs[i] = u.d; + } + } } if (arm_feature(env, ARM_FEATURE_IWMMXT)) { @@ -6242,6 +6279,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) } } + if (arm_feature(env, ARM_FEATURE_M)) { + env->v7m.other_sp = qemu_get_be32(f); + env->v7m.vecbase = qemu_get_be32(f); + env->v7m.basepri = qemu_get_be32(f); + env->v7m.control = qemu_get_be32(f); + env->v7m.current_sp = qemu_get_be32(f); + env->v7m.exception = qemu_get_be32(f); + } + return 0; } @@ -7392,6 +7438,8 @@ void register_machines(void) qemu_register_machine(&borzoipda_machine); qemu_register_machine(&terrierpda_machine); qemu_register_machine(&palmte_machine); + qemu_register_machine(&lm3s811evb_machine); + qemu_register_machine(&lm3s6965evb_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); qemu_register_machine(&r2d_machine); diff --git a/vl.h b/vl.h index 047fd3bbb..c4b4f777b 100644 --- a/vl.h +++ b/vl.h @@ -1482,6 +1482,14 @@ extern QEMUMachine terrierpda_machine; /* palm.c */ extern QEMUMachine palmte_machine; +/* armv7m.c */ +qemu_irq *armv7m_init(int flash_size, int sram_size, + const char *kernel_filename, const char *cpu_model); + +/* stellaris.c */ +extern QEMUMachine lm3s811evb_machine; +extern QEMUMachine lm3s6965evb_machine; + /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); @@ -1502,11 +1510,24 @@ void pl031_init(uint32_t base, qemu_irq irq); void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int); /* pl011.c */ -void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr); +enum pl011_type { + PL011_ARM, + PL011_LUMINARY +}; + +void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr, + enum pl011_type type); + +/* pl022.c */ +void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int), + void *opaque); /* pl050.c */ void pl050_init(uint32_t base, qemu_irq irq, int is_mouse); +/* pl061.c */ +qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out); + /* pl080.c */ void *pl080_init(uint32_t base, qemu_irq irq, int nchannels); @@ -1524,8 +1545,11 @@ void icp_pit_init(uint32_t base, qemu_irq *pic, int irq); /* arm_sysctl.c */ void arm_sysctl_init(uint32_t base, uint32_t sys_id); -/* arm_gic.c */ -qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq); +/* realview_gic.c */ +qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq); + +/* mpcore.c */ +extern qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq); /* arm_boot.c */ @@ -1533,6 +1557,16 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, int board_id, target_phys_addr_t loader_start); +/* armv7m_nvic.c */ +qemu_irq *armv7m_nvic_init(CPUState *env); + +/* ssd0303.c */ +void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address); + +/* ssd0323.c */ +int ssd0323_xfer_ssi(void *opaque, int data); +void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p); + /* sh7750.c */ struct SH7750State; -- cgit v1.2.3 From a76dc35afd2663343229d9dc05d493950d067b56 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 11 Nov 2007 00:16:10 +0000 Subject: Fix typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3573 c046a42c-6fe2-441c-8c8c-71466251a162 --- Changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 75f39d6ef..17b97ecdd 100644 --- a/Changelog +++ b/Changelog @@ -14,7 +14,7 @@ - SVM (x86 virtualization) support (Alexander Graf) - CRIS emulation (Edgar E. Iglesias) - SPARC32PLUS execution support (Blue Swirl) - - MIPS mipssim pequdo machine (Thiemo Seufer) + - MIPS mipssim pseudo machine (Thiemo Seufer) - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh) - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski) - ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery) -- cgit v1.2.3 From c3e10c7b4377c1cbc0a4fbc12312c2cf41c0cda7 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 11 Nov 2007 00:18:34 +0000 Subject: Optimize PowerPC overflow flag computation in most useful cases. Use the same routines to check overflow for addo, subfo and PowerPC 405 multiply and add cases. Fix carry reset in addme(o) and subfme(o) cases. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3574 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 70 +++++++++++++++------------------------------- target-ppc/op_helper.c | 75 +++++++++++++++----------------------------------- target-ppc/op_helper.h | 1 - target-ppc/translate.c | 26 ++++++++--------- 4 files changed, 57 insertions(+), 115 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 730dc0e90..bbc5c5b9a 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -191,6 +191,12 @@ void OPPROTO op_move_T2_T0 (void) RETURN(); } +void OPPROTO op_moven_T2_T0 (void) +{ + T2 = ~T0; + RETURN(); +} + /* Generate exceptions */ void OPPROTO op_raise_exception_err (void) { @@ -847,26 +853,18 @@ void OPPROTO op_add (void) void OPPROTO op_check_addo (void) { - if (likely(!(((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) & - ((uint32_t)T2 ^ (uint32_t)T0) & (1UL << 31)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } + xer_ov = (((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) & + ((uint32_t)T2 ^ (uint32_t)T0)) >> 31; + xer_so |= xer_ov; RETURN(); } #if defined(TARGET_PPC64) void OPPROTO op_check_addo_64 (void) { - if (likely(!(((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) & - ((uint64_t)T2 ^ (uint64_t)T0) & (1ULL << 63)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } + xer_ov = (((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) & + ((uint64_t)T2 ^ (uint64_t)T0)) >> 63; + xer_so |= xer_ov; RETURN(); } #endif @@ -922,6 +920,8 @@ void OPPROTO op_add_me (void) T0 += xer_ca + (-1); if (likely((uint32_t)T1 != 0)) xer_ca = 1; + else + xer_ca = 0; RETURN(); } @@ -931,6 +931,8 @@ void OPPROTO op_add_me_64 (void) T0 += xer_ca + (-1); if (likely((uint64_t)T1 != 0)) xer_ca = 1; + else + xer_ca = 0; RETURN(); } #endif @@ -1142,32 +1144,6 @@ void OPPROTO op_subf (void) RETURN(); } -void OPPROTO op_check_subfo (void) -{ - if (likely(!(((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) & - ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO op_check_subfo_64 (void) -{ - if (likely(!(((uint64_t)(~T2) ^ (uint64_t)T1 ^ UINT64_MAX) & - ((uint64_t)(~T2) ^ (uint64_t)T0) & (1ULL << 63)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } - RETURN(); -} -#endif - /* subtract from carrying */ void OPPROTO op_check_subfc (void) { @@ -1235,8 +1211,10 @@ void OPPROTO op_subfic_64 (void) void OPPROTO op_subfme (void) { T0 = ~T0 + xer_ca - 1; - if (likely((uint32_t)T0 != (uint32_t)-1)) + if (likely((uint32_t)T0 != UINT32_MAX)) xer_ca = 1; + else + xer_ca = 0; RETURN(); } @@ -1244,8 +1222,10 @@ void OPPROTO op_subfme (void) void OPPROTO op_subfme_64 (void) { T0 = ~T0 + xer_ca - 1; - if (likely((uint64_t)T0 != (uint64_t)-1)) + if (likely((uint64_t)T0 != UINT64_MAX)) xer_ca = 1; + else + xer_ca = 0; RETURN(); } #endif @@ -2528,12 +2508,6 @@ void OPPROTO op_405_mullhwu (void) RETURN(); } -void OPPROTO op_405_check_ov (void) -{ - do_405_check_ov(); - RETURN(); -} - void OPPROTO op_405_check_sat (void) { do_405_check_sat(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 6ed9c9533..75bf33bff 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -151,15 +151,12 @@ void do_addmeo (void) { T1 = T0; T0 += xer_ca + (-1); - if (likely(!((uint32_t)T1 & - ((uint32_t)T1 ^ (uint32_t)T0) & (1UL << 31)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } + xer_ov = ((uint32_t)T1 & ((uint32_t)T1 ^ (uint32_t)T0)) >> 31; + xer_so |= xer_ov; if (likely(T1 != 0)) xer_ca = 1; + else + xer_ca = 0; } #if defined(TARGET_PPC64) @@ -167,15 +164,12 @@ void do_addmeo_64 (void) { T1 = T0; T0 += xer_ca + (-1); - if (likely(!((uint64_t)T1 & - ((uint64_t)T1 ^ (uint64_t)T0) & (1ULL << 63)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } + xer_ov = ((uint64_t)T1 & ((uint64_t)T1 ^ (uint64_t)T0)) >> 63; + xer_so |= xer_ov; if (likely(T1 != 0)) xer_ca = 1; + else + xer_ca = 0; } #endif @@ -316,15 +310,12 @@ void do_subfmeo (void) { T1 = T0; T0 = ~T0 + xer_ca - 1; - if (likely(!((uint32_t)~T1 & ((uint32_t)~T1 ^ (uint32_t)T0) & - (1UL << 31)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } + xer_ov = ((uint32_t)~T1 & ((uint32_t)~T1 ^ (uint32_t)T0)) >> 31; + xer_so |= xer_ov; if (likely((uint32_t)T1 != UINT32_MAX)) xer_ca = 1; + else + xer_ca = 0; } #if defined(TARGET_PPC64) @@ -332,15 +323,12 @@ void do_subfmeo_64 (void) { T1 = T0; T0 = ~T0 + xer_ca - 1; - if (likely(!((uint64_t)~T1 & ((uint64_t)~T1 ^ (uint64_t)T0) & - (1ULL << 63)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } + xer_ov = ((uint64_t)~T1 & ((uint64_t)~T1 ^ (uint64_t)T0)) >> 63; + xer_so |= xer_ov; if (likely((uint64_t)T1 != UINT64_MAX)) xer_ca = 1; + else + xer_ca = 0; } #endif @@ -348,13 +336,9 @@ void do_subfzeo (void) { T1 = T0; T0 = ~T0 + xer_ca; - if (likely(!(((uint32_t)~T1 ^ UINT32_MAX) & - ((uint32_t)(~T1) ^ (uint32_t)T0) & (1UL << 31)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } + xer_ov = (((uint32_t)~T1 ^ UINT32_MAX) & + ((uint32_t)(~T1) ^ (uint32_t)T0)) >> 31; + xer_so |= xer_ov; if (likely((uint32_t)T0 >= (uint32_t)~T1)) { xer_ca = 0; } else { @@ -367,13 +351,9 @@ void do_subfzeo_64 (void) { T1 = T0; T0 = ~T0 + xer_ca; - if (likely(!(((uint64_t)~T1 ^ UINT64_MAX) & - ((uint64_t)(~T1) ^ (uint64_t)T0) & (1ULL << 63)))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } + xer_ov = (((uint64_t)~T1 ^ UINT64_MAX) & + ((uint64_t)(~T1) ^ (uint64_t)T0)) >> 63; + xer_so |= xer_ov; if (likely((uint64_t)T0 >= (uint64_t)~T1)) { xer_ca = 0; } else { @@ -1755,17 +1735,6 @@ void do_op_602_mfrom (void) /*****************************************************************************/ /* Embedded PowerPC specific helpers */ -void do_405_check_ov (void) -{ - if (likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) || - !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) { - xer_ov = 0; - } else { - xer_ov = 1; - xer_so = 1; - } -} - void do_405_check_sat (void) { if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) || diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 6575d3df6..5b77cb25a 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -182,7 +182,6 @@ void do_440_tlbwe (int word); #endif /* PowerPC 4xx specific helpers */ -void do_405_check_ov (void); void do_405_check_sat (void); void do_load_dcr (void); void do_store_dcr (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1adff9fdf..73b2e2212 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -888,17 +888,17 @@ GEN_INT_ARITH1_64 (neg, 0x1F, 0x08, 0x03, PPC_INTEGER); /* subf subf. subfo subfo. */ static always_inline void gen_op_subfo (void) { - gen_op_move_T2_T0(); + gen_op_moven_T2_T0(); gen_op_subf(); - gen_op_check_subfo(); + gen_op_check_addo(); } #if defined(TARGET_PPC64) #define gen_op_subf_64 gen_op_subf static always_inline void gen_op_subfo_64 (void) { - gen_op_move_T2_T0(); + gen_op_moven_T2_T0(); gen_op_subf(); - gen_op_check_subfo_64(); + gen_op_check_addo_64(); } #endif GEN_INT_ARITH2_64 (subf, 0x1F, 0x08, 0x01, PPC_INTEGER); @@ -910,10 +910,10 @@ static always_inline void gen_op_subfc (void) } static always_inline void gen_op_subfco (void) { - gen_op_move_T2_T0(); + gen_op_moven_T2_T0(); gen_op_subf(); gen_op_check_subfc(); - gen_op_check_subfo(); + gen_op_check_addo(); } #if defined(TARGET_PPC64) static always_inline void gen_op_subfc_64 (void) @@ -923,27 +923,27 @@ static always_inline void gen_op_subfc_64 (void) } static always_inline void gen_op_subfco_64 (void) { - gen_op_move_T2_T0(); + gen_op_moven_T2_T0(); gen_op_subf(); gen_op_check_subfc_64(); - gen_op_check_subfo_64(); + gen_op_check_addo_64(); } #endif GEN_INT_ARITH2_64 (subfc, 0x1F, 0x08, 0x00, PPC_INTEGER); /* subfe subfe. subfeo subfeo. */ static always_inline void gen_op_subfeo (void) { - gen_op_move_T2_T0(); + gen_op_moven_T2_T0(); gen_op_subfe(); - gen_op_check_subfo(); + gen_op_check_addo(); } #if defined(TARGET_PPC64) #define gen_op_subfe_64 gen_op_subfe static always_inline void gen_op_subfeo_64 (void) { - gen_op_move_T2_T0(); + gen_op_moven_T2_T0(); gen_op_subfe_64(); - gen_op_check_subfo_64(); + gen_op_check_addo_64(); } #endif GEN_INT_ARITH2_64 (subfe, 0x1F, 0x08, 0x04, PPC_INTEGER); @@ -5116,7 +5116,7 @@ static always_inline void gen_405_mulladd_insn (DisasContext *ctx, if (opc3 & 0x10) { /* Check overflow */ if (opc3 & 0x01) - gen_op_405_check_ov(); + gen_op_check_addo(); else gen_op_405_check_ovu(); } -- cgit v1.2.3 From 9c7e37e7fad48f6e7bbafa29f7980a4a9bf191b7 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 11 Nov 2007 00:33:08 +0000 Subject: Fix POWER abs & abso computation. Fix PowerPC SPE evabs & evneg (thanks to Fabrice Bellard for reporting the bug) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3575 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 4 ++-- target-ppc/op_helper.c | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index bbc5c5b9a..81c426c1a 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2199,9 +2199,9 @@ void OPPROTO op_store_601_batu (void) /* XXX: those micro-ops need tests ! */ void OPPROTO op_POWER_abs (void) { - if (T0 == INT32_MIN) + if ((int32_t)T0 == INT32_MIN) T0 = INT32_MAX; - else if (T0 < 0) + else if ((int32_t)T0 < 0) T0 = -T0; RETURN(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 75bf33bff..7d1411a1f 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1512,14 +1512,16 @@ void do_td (int flags) /* PowerPC 601 specific instructions (POWER bridge) */ void do_POWER_abso (void) { - if ((uint32_t)T0 == INT32_MIN) { + if ((int32_t)T0 == INT32_MIN) { T0 = INT32_MAX; xer_ov = 1; - xer_so = 1; - } else { + } else if ((int32_t)T0 < 0) { T0 = -T0; xer_ov = 0; + } else { + xer_ov = 0; } + xer_so |= xer_ov; } void do_POWER_clcs (void) @@ -1896,8 +1898,8 @@ void do_ev##name (void) \ /* Fixed-point vector arithmetic */ static always_inline uint32_t _do_eabs (uint32_t val) { - if (val != 0x80000000) - val &= ~0x80000000; + if ((val & 0x80000000) && val != 0x80000000) + val -= val; return val; } @@ -1923,7 +1925,7 @@ static always_inline int _do_ecntlzw (uint32_t val) static always_inline uint32_t _do_eneg (uint32_t val) { if (val != 0x80000000) - val ^= 0x80000000; + val -= val; return val; } -- cgit v1.2.3 From aba9ee8726e3a06ba3e08d985531049e68c45181 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Nov 2007 01:18:28 +0000 Subject: Remove duplicate i2c.o. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3576 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 25fed3fa6..a1de14bc4 100644 --- a/Makefile.target +++ b/Makefile.target @@ -494,7 +494,7 @@ VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o VL_OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o VL_OBJS+= versatile_pci.o sd.o ptimer.o VL_OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o -VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o i2c.o ssd0303.o pl022.o +VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o ssd0303.o pl022.o VL_OBJS+= ssd0323.o pl061.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o -- cgit v1.2.3 From 28c5af54c661e73e5596918fa67a22b5e87c2022 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 11 Nov 2007 01:50:45 +0000 Subject: More generic boot devices specification, allowing more devices to be specified and avoiding per-target hardcoded limitations. The machine implementations can then check if the given devices match the actual hardware implementation and firmware API. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3577 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pc.c | 22 +++++++++--- hw/ppc_chrp.c | 15 +++++++- hw/ppc_oldworld.c | 23 +++++++++++-- hw/ppc_prep.c | 16 +++++++-- vl.c | 100 ++++++++++++++++++++++++++++++++---------------------- 5 files changed, 125 insertions(+), 51 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 727ae3a23..8c165ee5d 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -173,6 +173,7 @@ static int boot_device2nibble(char boot_device) static void cmos_init(int ram_size, const char *boot_device, BlockDriverState **hd_table) { RTCState *s = rtc_state; + int nbds, bds[3] = { 0, }; int val; int fd0, fd1, nb; int i; @@ -202,11 +203,22 @@ static void cmos_init(int ram_size, const char *boot_device, BlockDriverState ** rtc_set_memory(s, 0x35, val >> 8); /* set boot devices, and disable floppy signature check if requested */ - rtc_set_memory(s, 0x3d, - boot_device2nibble(boot_device[1]) << 4 | - boot_device2nibble(boot_device[0]) ); - rtc_set_memory(s, 0x38, - boot_device2nibble(boot_device[2]) << 4 | (fd_bootchk ? 0x0 : 0x1)); +#define PC_MAX_BOOT_DEVICES 3 + nbds = strlen(boot_device); + if (nbds > PC_MAX_BOOT_DEVICES) { + fprintf(stderr, "Too many boot devices for PC\n"); + exit(1); + } + for (i = 0; i < nbds; i++) { + bds[i] = boot_device2nibble(boot_device[i]); + if (bds[i] == 0) { + fprintf(stderr, "Invalid boot device for PC: '%c'\n", + boot_device[i]); + exit(1); + } + } + rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]); + rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1)); /* floppy type */ diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index a791af269..a2d07c8fe 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -74,7 +74,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, qemu_irq *dummy_irq; int pic_mem_index, dbdma_mem_index, cuda_mem_index; int ide_mem_index[2]; - int ppc_boot_device = boot_device[0]; + int ppc_boot_device; linux_boot = (kernel_filename != NULL); @@ -175,6 +175,19 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, kernel_size = 0; initrd_base = 0; initrd_size = 0; + ppc_boot_device = '\0'; + /* We consider that NewWorld PowerMac never have any floppy drive + * For now, OHW cannot boot from the network. + */ + for (i = 0; i < boot_device[i] != '\0'; i++) { + ppc_boot_device = boot_device[i]; + if (ppc_boot_device >= 'c' && ppc_boot_device <= 'f') + break; + } + if (ppc_boot_device == '\0') { + fprintf(stderr, "No valid boot device for Mac99 machine\n"); + exit(1); + } } isa_mem_base = 0x80000000; diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index bafe7b519..b6ce58bc0 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -113,7 +113,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int vga_bios_size, bios_size; qemu_irq *dummy_irq; int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index; - int ppc_boot_device = boot_device[0]; + int ppc_boot_device; linux_boot = (kernel_filename != NULL); @@ -212,6 +212,25 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, kernel_size = 0; initrd_base = 0; initrd_size = 0; + ppc_boot_device = '\0'; + for (i = 0; i < boot_device[i] != '\0'; i++) { + ppc_boot_device = boot_device[i]; + /* TOFIX: for now, the second IDE channel is not properly + * emulated. The Mac floppy disk are not emulated. + * For now, OHW cannot boot from the network. + */ +#if 0 + if (ppc_boot_device >= 'a' && ppc_boot_device <= 'f') + break; +#else + if (ppc_boot_device >= 'c' && ppc_boot_device <= 'd') + break; +#endif + } + if (ppc_boot_device == '\0') { + fprintf(stderr, "No valid boot device for Mac99 machine\n"); + exit(1); + } } isa_mem_base = 0x80000000; @@ -272,7 +291,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, pmac_format_nvram_partition(nvr, 0x2000); dbdma_init(&dbdma_mem_index); - + macio_init(pci_bus, 0x0017, 1, pic_mem_index, dbdma_mem_index, cuda_mem_index, nvr, 0, NULL); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 5474d512c..60b695623 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -521,7 +521,8 @@ CPUReadMemoryFunc *PPC_prep_io_read[] = { #define NVRAM_SIZE 0x2000 /* PowerPC PREP hardware initialisation */ -static void ppc_prep_init (int ram_size, int vga_ram_size, const char *boot_device, +static void ppc_prep_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, @@ -538,7 +539,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, const char *boot_devi uint32_t kernel_base, kernel_size, initrd_base, initrd_size; PCIBus *pci_bus; qemu_irq *i8259; - int ppc_boot_device = boot_device[0]; + int ppc_boot_device; sysctrl = qemu_mallocz(sizeof(sysctrl_t)); if (sysctrl == NULL) @@ -611,6 +612,17 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, const char *boot_devi kernel_size = 0; initrd_base = 0; initrd_size = 0; + ppc_boot_device = '\0'; + /* For now, OHW cannot boot from the network. */ + for (i = 0; i < boot_device[i] != '\0'; i++) { + ppc_boot_device = boot_device[i]; + if (ppc_boot_device >= 'a' && ppc_boot_device <= 'f') + break; + } + if (ppc_boot_device == '\0') { + fprintf(stderr, "No valid boot device for Mac99 machine\n"); + exit(1); + } } isa_mem_base = 0xc0000000; diff --git a/vl.c b/vl.c index 7ffc904e0..41042eb8a 100644 --- a/vl.c +++ b/vl.c @@ -162,12 +162,6 @@ static DisplayState display_state; int nographic; const char* keyboard_layout = NULL; int64_t ticks_per_sec; -#if defined(TARGET_I386) -#define MAX_BOOT_DEVICES 3 -#else -#define MAX_BOOT_DEVICES 1 -#endif -static char boot_device[MAX_BOOT_DEVICES + 1]; int ram_size; int pit_min_timer_count = 0; int nb_nics; @@ -7587,14 +7581,16 @@ int main(int argc, char **argv) int use_gdbstub; const char *gdbstub_port; #endif + uint32_t boot_devices_bitmap = 0; int i, cdrom_index, pflash_index; - int snapshot, linux_boot; + int snapshot, linux_boot, net_boot; const char *initrd_filename; const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; const char *pflash_filename[MAX_PFLASH]; const char *sd_filename; const char *mtd_filename; const char *kernel_filename, *kernel_cmdline; + const char *boot_devices = ""; DisplayState *ds = &display_state; int cyls, heads, secs, translation; char net_clients[MAX_NET_CLIENTS][256]; @@ -7846,20 +7842,34 @@ int main(int argc, char **argv) } break; case QEMU_OPTION_boot: - if (strlen(optarg) > MAX_BOOT_DEVICES) { - fprintf(stderr, "qemu: too many boot devices\n"); - exit(1); - } - strncpy(boot_device, optarg, MAX_BOOT_DEVICES); -#if defined(TARGET_SPARC) || defined(TARGET_I386) -#define BOOTCHARS "acdn" -#else -#define BOOTCHARS "acd" -#endif - if (strlen(boot_device) != strspn(boot_device, BOOTCHARS)) { - fprintf(stderr, "qemu: invalid boot device " - "sequence '%s'\n", boot_device); - exit(1); + boot_devices = optarg; + /* We just do some generic consistency checks */ + { + /* Could easily be extended to 64 devices if needed */ + const unsigned char *p; + + boot_devices_bitmap = 0; + for (p = boot_devices; *p != '\0'; p++) { + /* Allowed boot devices are: + * a b : floppy disk drives + * c ... f : IDE disk drives + * g ... m : machine implementation dependant drives + * n ... p : network devices + * It's up to each machine implementation to check + * if the given boot devices match the actual hardware + * implementation and firmware features. + */ + if (*p < 'a' || *p > 'q') { + fprintf(stderr, "Invalid boot device '%c'\n", *p); + exit(1); + } + if (boot_devices_bitmap & (1 << (*p - 'a'))) { + fprintf(stderr, + "Boot device '%c' was given twice\n",*p); + exit(1); + } + boot_devices_bitmap |= 1 << (*p - 'a'); + } } break; case QEMU_OPTION_fda: @@ -8243,23 +8253,23 @@ int main(int argc, char **argv) kqemu_allowed = 0; #endif linux_boot = (kernel_filename != NULL); - - if (!linux_boot && - (!strchr(boot_device, 'n')) && + net_boot = (boot_devices_bitmap >> ('n' - 'a')) && 0xF; + + /* XXX: this should not be: some embedded targets just have flash */ + if (!linux_boot && net_boot == 0 && hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') help(1); /* boot to floppy or the default cd if no hard disk defined yet */ - if (!boot_device[0]) { + if (!boot_devices[0]) { if (hd_filename[0] != '\0') - boot_device[0] = 'c'; + boot_devices = "c"; else if (fd_filename[0] != '\0') - boot_device[0] = 'a'; + boot_devices = "a"; else - boot_device[0] = 'd'; - boot_device[1] = 0; + boot_devices = "d"; } setvbuf(stdout, NULL, _IOLBF, 0); @@ -8299,20 +8309,28 @@ int main(int argc, char **argv) } #ifdef TARGET_I386 - if (strchr(boot_device, 'n')) { - for (i = 0; i < nb_nics; i++) { + /* XXX: this should be moved in the PC machine instanciation code */ + if (net_boot != 0) { + int netroms = 0; + for (i = 0; i < nb_nics && i < 4; i++) { const char *model = nd_table[i].model; char buf[1024]; - if (model == NULL) - model = "ne2k_pci"; - snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model); - if (get_image_size(buf) > 0) { - option_rom[nb_option_roms] = strdup(buf); - nb_option_roms++; - break; - } + if (net_boot & (1 << i)) { + if (model == NULL) + model = "ne2k_pci"; + snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model); + if (get_image_size(buf) > 0) { + if (nb_option_roms >= MAX_OPTION_ROMS) { + fprintf(stderr, "Too many option ROMs\n"); + exit(1); + } + option_rom[nb_option_roms] = strdup(buf); + nb_option_roms++; + netroms++; + } + } } - if (i == nb_nics) { + if (netroms == 0) { fprintf(stderr, "No valid PXE rom found for network device\n"); exit(1); } @@ -8492,7 +8510,7 @@ int main(int argc, char **argv) } } - machine->init(ram_size, vga_ram_size, boot_device, + machine->init(ram_size, vga_ram_size, boot_devices, ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); -- cgit v1.2.3 From faf07963cb03f98d52ca1f7fde7482a3cb309bcc Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Nov 2007 02:51:17 +0000 Subject: Split block API from vl.h. Remove QEMU_TOOL. Replace with QEMU_IMG and NEED_CPU_H. Avoid linking qemu-img against whole system emulatior. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3578 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 22 +++-- Makefile.target | 4 +- aes.c | 2 +- block-bochs.c | 2 +- block-cloop.c | 2 +- block-cow.c | 2 +- block-dmg.c | 2 +- block-parallels.c | 2 +- block-qcow.c | 2 +- block-qcow2.c | 2 +- block-raw.c | 35 ++++---- block-vmdk.c | 2 +- block-vpc.c | 2 +- block-vvfat.c | 2 +- block.c | 12 ++- block.h | 157 ++++++++++++++++++++++++++++++++++++ block_int.h | 4 + cutils.c | 2 +- qemu-common.h | 83 +++++++++++++++++++ qemu-img.c | 2 +- vl.h | 235 ++---------------------------------------------------- 21 files changed, 307 insertions(+), 271 deletions(-) create mode 100644 block.h create mode 100644 qemu-common.h diff --git a/Makefile b/Makefile index d0ec05720..73f9e3db1 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,6 @@ BASE_LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS) CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -CPPFLAGS += -DQEMU_TOOL LIBS= ifdef CONFIG_STATIC BASE_LDFLAGS += -static @@ -33,15 +32,23 @@ subdir-%: dyngen$(EXESUF) libqemu_common.a recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS)) +####################################################################### +# BLOCK_OBJS is code used by both qemu system emulation and qemu-img + +BLOCK_OBJS=cutils.o +BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o +BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o +BLOCK_OBJS+=block-qcow2.o block-parallels.o + ###################################################################### -# libqemu_common.a: target indepedent part of system emulation. The +# libqemu_common.a: Target indepedent part of system emulation. The # long term path is to suppress *all* target specific code in case of # system emulation, i.e. a single QEMU executable should support all # CPUs and machines. -OBJS+=cutils.o readline.o console.o -#OBJS+=block.o block-raw.o -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 block-parallels.o +OBJS=$(BLOCK_OBJS) +OBJS+=readline.o console.o +OBJS+=block.o ifdef CONFIG_WIN32 OBJS+=tap-win32.o @@ -105,9 +112,12 @@ libqemu_common.a: $(OBJS) ###################################################################### -qemu-img$(EXESUF): qemu-img.o block.o block-raw.o libqemu_common.a +qemu-img$(EXESUF): qemu-img.o qemu-img-block.o qemu-img-block-raw.o $(BLOCK_OBJS) $(CC) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS) +qemu-img-%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_IMG $(BASE_CFLAGS) -c -o $@ $< + %.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< diff --git a/Makefile.target b/Makefile.target index a1de14bc4..33cf23bec 100644 --- a/Makefile.target +++ b/Makefile.target @@ -24,7 +24,7 @@ TARGET_BASE_ARCH:=sparc endif TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw -CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MP +CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MP -DNEED_CPU_H ifdef CONFIG_DARWIN_USER VPATH+=:$(SRC_PATH)/darwin-user CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH) @@ -398,7 +398,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o # XXX: suppress QEMU_TOOL tests -VL_OBJS+=block.o block-raw.o +VL_OBJS+=block-raw.o VL_OBJS+=irq.o ifdef CONFIG_ALSA diff --git a/aes.c b/aes.c index 40ed109d3..bb1e1043b 100644 --- a/aes.c +++ b/aes.c @@ -27,7 +27,7 @@ * 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 "qemu-common.h" #include "aes.h" #define NDEBUG diff --git a/block-bochs.c b/block-bochs.c index 9baea9b6f..b167e0bbf 100644 --- a/block-bochs.c +++ b/block-bochs.c @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" /**************************************************************/ diff --git a/block-cloop.c b/block-cloop.c index 0c9ddb381..43d380127 100644 --- a/block-cloop.c +++ b/block-cloop.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" #include diff --git a/block-cow.c b/block-cow.c index 47a91e5ac..9e7b64602 100644 --- a/block-cow.c +++ b/block-cow.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #ifndef _WIN32 -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" #include diff --git a/block-dmg.c b/block-dmg.c index 681f4dc71..62117c97a 100644 --- a/block-dmg.c +++ b/block-dmg.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" #include "bswap.h" #include diff --git a/block-parallels.c b/block-parallels.c index b0fb99cee..4654b07b1 100644 --- a/block-parallels.c +++ b/block-parallels.c @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" /**************************************************************/ diff --git a/block-qcow.c b/block-qcow.c index 9a0bca0e7..730ae67ed 100644 --- a/block-qcow.c +++ b/block-qcow.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" #include #include "aes.h" diff --git a/block-qcow2.c b/block-qcow2.c index b74fe348e..577210b21 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" #include #include "aes.h" diff --git a/block-raw.c b/block-raw.c index 1e5e5d15e..828668157 100644 --- a/block-raw.c +++ b/block-raw.c @@ -21,16 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#ifdef QEMU_IMG +#include "qemu-common.h" +#else #include "vl.h" +#endif #include "block_int.h" #include #ifndef _WIN32 #include -#ifndef QEMU_TOOL -#include "exec-all.h" -#endif - #ifdef CONFIG_COCOA #include #include @@ -59,8 +59,9 @@ //#define DEBUG_FLOPPY -#define DEBUG_BLOCK -#if defined(DEBUG_BLOCK) && !defined(QEMU_TOOL) +//#define DEBUG_BLOCK +#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) +#include "exec-all.h" #define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0) #else @@ -242,7 +243,7 @@ static int aio_initialized = 0; static void aio_signal_handler(int signum) { -#ifndef QEMU_TOOL +#ifndef QEMU_IMG CPUState *env = cpu_single_env; if (env) { /* stop the currently executing cpu because a timer occured */ @@ -352,7 +353,7 @@ void qemu_aio_wait(void) sigset_t set; int nb_sigs; -#ifndef QEMU_TOOL +#ifndef QEMU_IMG if (qemu_bh_poll()) return; #endif @@ -693,7 +694,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) return 0; } -#if defined(__linux__) && !defined(QEMU_TOOL) +#if defined(__linux__) && !defined(QEMU_IMG) /* 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 @@ -976,7 +977,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) } else { create_flags = OPEN_EXISTING; } -#ifdef QEMU_TOOL +#ifdef QEMU_IMG overlapped = FILE_ATTRIBUTE_NORMAL; #else overlapped = FILE_FLAG_OVERLAPPED; @@ -1039,7 +1040,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, } #if 0 -#ifndef QEMU_TOOL +#ifndef QEMU_IMG static void raw_aio_cb(void *opaque) { RawAIOCB *acb = opaque; @@ -1078,7 +1079,7 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs, acb->ov.OffsetHigh = offset >> 32; acb->ov.hEvent = acb->hEvent; acb->count = nb_sectors * 512; -#ifndef QEMU_TOOL +#ifndef QEMU_IMG qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb); #endif return acb; @@ -1100,7 +1101,7 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, qemu_aio_release(acb); return NULL; } -#ifdef QEMU_TOOL +#ifdef QEMU_IMG qemu_aio_release(acb); #endif return (BlockDriverAIOCB *)acb; @@ -1122,7 +1123,7 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, qemu_aio_release(acb); return NULL; } -#ifdef QEMU_TOOL +#ifdef QEMU_IMG qemu_aio_release(acb); #endif return (BlockDriverAIOCB *)acb; @@ -1130,7 +1131,7 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, static void raw_aio_cancel(BlockDriverAIOCB *blockacb) { -#ifndef QEMU_TOOL +#ifndef QEMU_IMG RawAIOCB *acb = (RawAIOCB *)blockacb; BlockDriverState *bs = acb->common.bs; BDRVRawState *s = bs->opaque; @@ -1238,7 +1239,7 @@ void qemu_aio_wait_start(void) void qemu_aio_wait(void) { -#ifndef QEMU_TOOL +#ifndef QEMU_IMG qemu_bh_poll(); #endif } @@ -1344,7 +1345,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) } create_flags = OPEN_EXISTING; -#ifdef QEMU_TOOL +#ifdef QEMU_IMG overlapped = FILE_ATTRIBUTE_NORMAL; #else overlapped = FILE_FLAG_OVERLAPPED; diff --git a/block-vmdk.c b/block-vmdk.c index ad2270034..af979a1e8 100644 --- a/block-vmdk.c +++ b/block-vmdk.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') diff --git a/block-vpc.c b/block-vpc.c index be74c290d..87b9d69a6 100644 --- a/block-vpc.c +++ b/block-vpc.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" /**************************************************************/ diff --git a/block-vvfat.c b/block-vvfat.c index 3237c266c..43004e534 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -25,7 +25,7 @@ #include #include #include -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" #ifndef S_IWGRP diff --git a/block.c b/block.c index 3c7039947..1cb943b82 100644 --- a/block.c +++ b/block.c @@ -21,7 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#ifdef QEMU_IMG +#include "qemu-common.h" +#else #include "vl.h" +#endif #include "block_int.h" #ifdef _BSD @@ -53,7 +57,7 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); -static BlockDriverState *bdrv_first; +BlockDriverState *bdrv_first; static BlockDriver *first_drv; int path_is_absolute(const char *path) @@ -859,6 +863,7 @@ void bdrv_flush(BlockDriverState *bs) bdrv_flush(bs->backing_hd); } +#ifndef QEMU_IMG void bdrv_info(void) { BlockDriverState *bs; @@ -898,6 +903,7 @@ void bdrv_info(void) term_printf("\n"); } } +#endif void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size) @@ -1102,7 +1108,7 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb) /**************************************************************/ /* async block device emulation */ -#ifdef QEMU_TOOL +#ifdef QEMU_IMG static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) @@ -1172,7 +1178,7 @@ static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb) qemu_bh_cancel(acb->bh); qemu_aio_release(acb); } -#endif /* !QEMU_TOOL */ +#endif /* !QEMU_IMG */ /**************************************************************/ /* sync block device emulation */ diff --git a/block.h b/block.h new file mode 100644 index 000000000..42baf11f4 --- /dev/null +++ b/block.h @@ -0,0 +1,157 @@ +#ifndef BLOCK_H +#define BLOCK_H + +/* block.c */ +typedef struct BlockDriverState BlockDriverState; +typedef struct BlockDriver BlockDriver; + +extern BlockDriver bdrv_raw; +extern BlockDriver bdrv_host_device; +extern BlockDriver bdrv_cow; +extern BlockDriver bdrv_qcow; +extern BlockDriver bdrv_vmdk; +extern BlockDriver bdrv_cloop; +extern BlockDriver bdrv_dmg; +extern BlockDriver bdrv_bochs; +extern BlockDriver bdrv_vpc; +extern BlockDriver bdrv_vvfat; +extern BlockDriver bdrv_qcow2; +extern BlockDriver bdrv_parallels; + +typedef struct BlockDriverInfo { + /* in bytes, 0 if irrelevant */ + int cluster_size; + /* offset at which the VM state can be saved (0 if not possible) */ + int64_t vm_state_offset; +} BlockDriverInfo; + +typedef struct QEMUSnapshotInfo { + char id_str[128]; /* unique snapshot id */ + /* the following fields are informative. They are not needed for + the consistency of the snapshot */ + char name[256]; /* user choosen name */ + uint32_t vm_state_size; /* VM state info size */ + uint32_t date_sec; /* UTC date of the snapshot */ + uint32_t date_nsec; + uint64_t vm_clock_nsec; /* VM clock relative to boot */ +} QEMUSnapshotInfo; + +#define BDRV_O_RDONLY 0x0000 +#define BDRV_O_RDWR 0x0002 +#define BDRV_O_ACCESS 0x0003 +#define BDRV_O_CREAT 0x0004 /* create an empty file */ +#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */ +#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to + use a disk image format on top of + it (default for + bdrv_file_open()) */ + +#ifndef QEMU_IMG +void bdrv_info(void); +#endif + +void bdrv_init(void); +BlockDriver *bdrv_find_format(const char *format_name); +int bdrv_create(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, int flags); +BlockDriverState *bdrv_new(const char *device_name); +void bdrv_delete(BlockDriverState *bs); +int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); +int bdrv_open(BlockDriverState *bs, const char *filename, int flags); +int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, + BlockDriver *drv); +void bdrv_close(BlockDriverState *bs); +int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); +int bdrv_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +int bdrv_pread(BlockDriverState *bs, int64_t offset, + void *buf, int count); +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, + const void *buf, int count); +int bdrv_truncate(BlockDriverState *bs, int64_t offset); +int64_t bdrv_getlength(BlockDriverState *bs); +void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); +int bdrv_commit(BlockDriverState *bs); +void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); +/* async block I/O */ +typedef struct BlockDriverAIOCB BlockDriverAIOCB; +typedef void BlockDriverCompletionFunc(void *opaque, int ret); + +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); + +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); +void qemu_aio_wait_end(void); + +int qemu_key_check(BlockDriverState *bs, const char *name); + +/* Ensure contents are flushed to disk. */ +void bdrv_flush(BlockDriverState *bs); + +#define BDRV_TYPE_HD 0 +#define BDRV_TYPE_CDROM 1 +#define BDRV_TYPE_FLOPPY 2 +#define BIOS_ATA_TRANSLATION_AUTO 0 +#define BIOS_ATA_TRANSLATION_NONE 1 +#define BIOS_ATA_TRANSLATION_LBA 2 +#define BIOS_ATA_TRANSLATION_LARGE 3 +#define BIOS_ATA_TRANSLATION_RECHS 4 + +void bdrv_set_geometry_hint(BlockDriverState *bs, + int cyls, int heads, int secs); +void bdrv_set_type_hint(BlockDriverState *bs, int type); +void bdrv_set_translation_hint(BlockDriverState *bs, int translation); +void bdrv_get_geometry_hint(BlockDriverState *bs, + int *pcyls, int *pheads, int *psecs); +int bdrv_get_type_hint(BlockDriverState *bs); +int bdrv_get_translation_hint(BlockDriverState *bs); +int bdrv_is_removable(BlockDriverState *bs); +int bdrv_is_read_only(BlockDriverState *bs); +int bdrv_is_inserted(BlockDriverState *bs); +int bdrv_media_changed(BlockDriverState *bs); +int bdrv_is_locked(BlockDriverState *bs); +void bdrv_set_locked(BlockDriverState *bs, int locked); +void bdrv_eject(BlockDriverState *bs, int eject_flag); +void bdrv_set_change_cb(BlockDriverState *bs, + void (*change_cb)(void *opaque), void *opaque); +void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); +BlockDriverState *bdrv_find(const char *name); +void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); +int bdrv_is_encrypted(BlockDriverState *bs); +int bdrv_set_key(BlockDriverState *bs, const char *key); +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), + void *opaque); +const char *bdrv_get_device_name(BlockDriverState *bs); +int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); + +void bdrv_get_backing_filename(BlockDriverState *bs, + char *filename, int filename_size); +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); +char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); + +char *get_human_readable_size(char *buf, int buf_size, int64_t size); +int path_is_absolute(const char *path); +void path_combine(char *dest, int dest_size, + const char *base_path, + const char *filename); + +#endif diff --git a/block_int.h b/block_int.h index b034023e0..2c5f168f6 100644 --- a/block_int.h +++ b/block_int.h @@ -24,6 +24,8 @@ #ifndef BLOCK_INT_H #define BLOCK_INT_H +#include "block.h" + #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPRESS 2 #define BLOCK_FLAG_COMPAT6 4 @@ -133,4 +135,6 @@ void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque); void qemu_aio_release(void *p); +BlockDriverState *bdrv_first; + #endif /* BLOCK_INT_H */ diff --git a/cutils.c b/cutils.c index 7836a3e99..9ef2fa627 100644 --- a/cutils.c +++ b/cutils.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" void pstrcpy(char *buf, int buf_size, const char *str) { diff --git a/qemu-common.h b/qemu-common.h new file mode 100644 index 000000000..64f4e78ae --- /dev/null +++ b/qemu-common.h @@ -0,0 +1,83 @@ +/* Common header file that is included by all of qemu. */ +#ifndef QEMU_COMMON_H +#define QEMU_COMMON_H + +/* we put basic includes here to avoid repeating them in device drivers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef ENOMEDIUM +#define ENOMEDIUM ENODEV +#endif + +#ifdef _WIN32 +#include +#define fsync _commit +#define lseek _lseeki64 +#define ENOTSUP 4096 +extern int qemu_ftruncate64(int, int64_t); +#define ftruncate qemu_ftruncate64 + + +static inline char *realpath(const char *path, char *resolved_path) +{ + _fullpath(resolved_path, path, _MAX_PATH); + return resolved_path; +} + +#define PRId64 "I64d" +#define PRIx64 "I64x" +#define PRIu64 "I64u" +#define PRIo64 "I64o" +#endif + +/* FIXME: Remove NEED_CPU_H. */ +#ifndef NEED_CPU_H + +#include "config-host.h" +#include +#include "osdep.h" +#include "bswap.h" + +#else + +#include "cpu.h" + +#endif /* !defined(NEED_CPU_H) */ + +/* bottom halves */ +typedef struct QEMUBH QEMUBH; + +typedef void QEMUBHFunc(void *opaque); + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); +void qemu_bh_schedule(QEMUBH *bh); +void qemu_bh_cancel(QEMUBH *bh); +void qemu_bh_delete(QEMUBH *bh); +int qemu_bh_poll(void); + +/* cutils.c */ +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); +time_t mktimegm(struct tm *tm); + +#endif diff --git a/qemu-img.c b/qemu-img.c index 8ebc4ba31..095a59338 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "block_int.h" #include diff --git a/vl.h b/vl.h index c4b4f777b..a73da2710 100644 --- a/vl.h +++ b/vl.h @@ -24,66 +24,10 @@ #ifndef VL_H #define VL_H -/* we put basic includes here to avoid repeating them in device drivers */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef O_LARGEFILE -#define O_LARGEFILE 0 -#endif -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifndef ENOMEDIUM -#define ENOMEDIUM ENODEV -#endif - -#ifdef _WIN32 -#include -#define fsync _commit -#define lseek _lseeki64 -#define ENOTSUP 4096 -extern int qemu_ftruncate64(int, int64_t); -#define ftruncate qemu_ftruncate64 - - -static inline char *realpath(const char *path, char *resolved_path) -{ - _fullpath(resolved_path, path, _MAX_PATH); - return resolved_path; -} - -#define PRId64 "I64d" -#define PRIx64 "I64x" -#define PRIu64 "I64u" -#define PRIo64 "I64o" -#endif - -#ifdef QEMU_TOOL - -/* we use QEMU_TOOL on code which does not depend on the target CPU - type */ -#include "config-host.h" -#include -#include "osdep.h" -#include "bswap.h" - -#else - -#include "cpu.h" +#include "qemu-common.h" -#endif /* !defined(QEMU_TOOL) */ +/* FIXME: Remove this. */ +#include "block.h" #ifndef glue #define xglue(x, y) x ## y @@ -118,13 +62,6 @@ static inline char *realpath(const char *path, char *resolved_path) #include "audio/audio.h" -/* cutils.c */ -void pstrcpy(char *buf, int buf_size, const char *str); -char *pstrcat(char *buf, int buf_size, const char *s); -int strstart(const char *str, const char *val, const char **ptr); -int stristart(const char *str, const char *val, const char **ptr); -time_t mktimegm(struct tm *tm); - /* vl.c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); @@ -297,8 +234,6 @@ int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); #endif -typedef struct QEMUBH QEMUBH; - /* character device */ #define CHR_EVENT_BREAK 0 /* serial break char */ @@ -604,166 +539,6 @@ void do_loadvm(const char *name); void do_delvm(const char *name); void do_info_snapshots(void); -/* bottom halves */ -typedef void QEMUBHFunc(void *opaque); - -QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); -void qemu_bh_schedule(QEMUBH *bh); -void qemu_bh_cancel(QEMUBH *bh); -void qemu_bh_delete(QEMUBH *bh); -int qemu_bh_poll(void); - -/* block.c */ -typedef struct BlockDriverState BlockDriverState; -typedef struct BlockDriver BlockDriver; - -extern BlockDriver bdrv_raw; -extern BlockDriver bdrv_host_device; -extern BlockDriver bdrv_cow; -extern BlockDriver bdrv_qcow; -extern BlockDriver bdrv_vmdk; -extern BlockDriver bdrv_cloop; -extern BlockDriver bdrv_dmg; -extern BlockDriver bdrv_bochs; -extern BlockDriver bdrv_vpc; -extern BlockDriver bdrv_vvfat; -extern BlockDriver bdrv_qcow2; -extern BlockDriver bdrv_parallels; - -typedef struct BlockDriverInfo { - /* in bytes, 0 if irrelevant */ - int cluster_size; - /* offset at which the VM state can be saved (0 if not possible) */ - int64_t vm_state_offset; -} BlockDriverInfo; - -typedef struct QEMUSnapshotInfo { - char id_str[128]; /* unique snapshot id */ - /* the following fields are informative. They are not needed for - the consistency of the snapshot */ - char name[256]; /* user choosen name */ - uint32_t vm_state_size; /* VM state info size */ - uint32_t date_sec; /* UTC date of the snapshot */ - uint32_t date_nsec; - uint64_t vm_clock_nsec; /* VM clock relative to boot */ -} QEMUSnapshotInfo; - -#define BDRV_O_RDONLY 0x0000 -#define BDRV_O_RDWR 0x0002 -#define BDRV_O_ACCESS 0x0003 -#define BDRV_O_CREAT 0x0004 /* create an empty file */ -#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */ -#define BDRV_O_FILE 0x0010 /* open as a raw file (do not try to - use a disk image format on top of - it (default for - bdrv_file_open()) */ - -void bdrv_init(void); -BlockDriver *bdrv_find_format(const char *format_name); -int bdrv_create(BlockDriver *drv, - const char *filename, int64_t size_in_sectors, - const char *backing_file, int flags); -BlockDriverState *bdrv_new(const char *device_name); -void bdrv_delete(BlockDriverState *bs); -int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); -int bdrv_open(BlockDriverState *bs, const char *filename, int flags); -int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, - BlockDriver *drv); -void bdrv_close(BlockDriverState *bs); -int bdrv_read(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors); -int bdrv_write(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors); -int bdrv_pread(BlockDriverState *bs, int64_t offset, - void *buf, int count); -int bdrv_pwrite(BlockDriverState *bs, int64_t offset, - const void *buf, int count); -int bdrv_truncate(BlockDriverState *bs, int64_t offset); -int64_t bdrv_getlength(BlockDriverState *bs); -void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr); -int bdrv_commit(BlockDriverState *bs); -void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); -/* async block I/O */ -typedef struct BlockDriverAIOCB BlockDriverAIOCB; -typedef void BlockDriverCompletionFunc(void *opaque, int ret); - -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); - -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); -void qemu_aio_wait_end(void); - -int qemu_key_check(BlockDriverState *bs, const char *name); - -/* Ensure contents are flushed to disk. */ -void bdrv_flush(BlockDriverState *bs); - -#define BDRV_TYPE_HD 0 -#define BDRV_TYPE_CDROM 1 -#define BDRV_TYPE_FLOPPY 2 -#define BIOS_ATA_TRANSLATION_AUTO 0 -#define BIOS_ATA_TRANSLATION_NONE 1 -#define BIOS_ATA_TRANSLATION_LBA 2 -#define BIOS_ATA_TRANSLATION_LARGE 3 -#define BIOS_ATA_TRANSLATION_RECHS 4 - -void bdrv_set_geometry_hint(BlockDriverState *bs, - int cyls, int heads, int secs); -void bdrv_set_type_hint(BlockDriverState *bs, int type); -void bdrv_set_translation_hint(BlockDriverState *bs, int translation); -void bdrv_get_geometry_hint(BlockDriverState *bs, - int *pcyls, int *pheads, int *psecs); -int bdrv_get_type_hint(BlockDriverState *bs); -int bdrv_get_translation_hint(BlockDriverState *bs); -int bdrv_is_removable(BlockDriverState *bs); -int bdrv_is_read_only(BlockDriverState *bs); -int bdrv_is_inserted(BlockDriverState *bs); -int bdrv_media_changed(BlockDriverState *bs); -int bdrv_is_locked(BlockDriverState *bs); -void bdrv_set_locked(BlockDriverState *bs, int locked); -void bdrv_eject(BlockDriverState *bs, int eject_flag); -void bdrv_set_change_cb(BlockDriverState *bs, - void (*change_cb)(void *opaque), void *opaque); -void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); -void bdrv_info(void); -BlockDriverState *bdrv_find(const char *name); -void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); -int bdrv_is_encrypted(BlockDriverState *bs); -int bdrv_set_key(BlockDriverState *bs, const char *key); -void bdrv_iterate_format(void (*it)(void *opaque, const char *name), - void *opaque); -const char *bdrv_get_device_name(BlockDriverState *bs); -int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors); -int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); - -void bdrv_get_backing_filename(BlockDriverState *bs, - char *filename, int filename_size); -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); -char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); - -char *get_human_readable_size(char *buf, int buf_size, int64_t size); -int path_is_absolute(const char *path); -void path_combine(char *dest, int dest_size, - const char *base_path, - const char *filename); - - /* monitor.c */ void monitor_init(CharDriverState *hd, int show_banner); void term_puts(const char *str); @@ -804,7 +579,7 @@ void do_info_vnc(void); /* x_keymap.c */ extern uint8_t _translate_keycode(const int key); -#ifndef QEMU_TOOL +#ifdef NEED_CPU_H typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, const char *boot_device, @@ -1759,5 +1534,5 @@ extern QEMUMachine dummy_m68k_machine; #include "gdbstub.h" -#endif /* defined(QEMU_TOOL) */ +#endif /* defined(NEED_CPU_H) */ #endif /* VL_H */ -- cgit v1.2.3 From 3f379ab18741e75325cfca22f368de846d8b89f1 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Nov 2007 03:33:13 +0000 Subject: Cleanup qemu-img.c. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3579 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-img.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 095a59338..f1a8aebf5 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -64,20 +64,7 @@ char *qemu_strdup(const char *str) return ptr; } -void term_printf(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); -} - -void term_print_filename(const char *filename) -{ - term_printf(filename); -} - -void __attribute__((noreturn)) error(const char *fmt, ...) +static void __attribute__((noreturn)) error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -93,7 +80,7 @@ static void format_print(void *opaque, const char *name) printf(" %s", name); } -void help(void) +static void help(void) { printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2007 Fabrice Bellard\n" "usage: qemu-img command [command options]\n" @@ -175,7 +162,7 @@ static void term_init(void) atexit(term_exit); } -int read_password(char *buf, int buf_size) +static int read_password(char *buf, int buf_size) { uint8_t ch; int i, ret; -- cgit v1.2.3 From ae5fc4507e39d35904cea8ee2b311959c8747c71 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Nov 2007 11:43:27 +0000 Subject: block-raw/kqemu fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3580 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-raw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-raw.c b/block-raw.c index 828668157..71c39ab08 100644 --- a/block-raw.c +++ b/block-raw.c @@ -25,6 +25,7 @@ #include "qemu-common.h" #else #include "vl.h" +#include "exec-all.h" #endif #include "block_int.h" #include @@ -61,7 +62,6 @@ //#define DEBUG_BLOCK #if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) -#include "exec-all.h" #define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0) #else -- cgit v1.2.3 From c6ee607c94753d8cfe3561cf2898c246536c31ea Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Nov 2007 12:02:33 +0000 Subject: mips_r4k warning fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3581 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 5a8bf6c24..acdb384cd 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -15,11 +15,7 @@ #define BIOS_FILENAME "mipsel_bios.bin" #endif -#ifdef TARGET_MIPS64 -#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) -#else -#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) -#endif +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff) #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) @@ -152,7 +148,6 @@ void mips_r4k_init (int ram_size, int vga_ram_size, const char *boot_device, CPUState *env; RTCState *rtc_state; int i; - mips_def_t *def; qemu_irq *i8259; /* init CPUs */ -- cgit v1.2.3 From 44f8625d23f9807c0853556ffe1c44540bd453f9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 12:35:55 +0000 Subject: fixed invalid type git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3582 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/op_helper.c | 4 ++-- target-arm/op_helper.c | 4 ++-- target-cris/op_helper.c | 4 ++-- target-m68k/op_helper.c | 4 ++-- target-ppc/op_helper.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index fa1e6acc5..9a3009c4d 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -1152,7 +1152,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; - target_phys_addr_t pc; + unsigned long pc; int ret; /* XXX: hack to restore env in all cases, even if not called from @@ -1163,7 +1163,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (!likely(ret == 0)) { if (likely(retaddr)) { /* now we have a real cpu fault */ - pc = (target_phys_addr_t)retaddr; + pc = (unsigned long)retaddr; tb = tb_find_pc(pc); if (likely(tb)) { /* the PC is inside the translated code. It means that we have diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index a9bd95b05..2b9ec0fa7 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -279,7 +279,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; - target_phys_addr_t pc; + unsigned long pc; int ret; /* XXX: hack to restore env in all cases, even if not called from @@ -290,7 +290,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (__builtin_expect(ret, 0)) { if (retaddr) { /* now we have a real cpu fault */ - pc = (target_phys_addr_t)retaddr; + pc = (unsigned long)retaddr; tb = tb_find_pc(pc); if (tb) { /* the PC is inside the translated code. It means that we have diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index d0ec519b1..458b0585d 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -49,7 +49,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; - target_phys_addr_t pc; + unsigned long pc; int ret; /* XXX: hack to restore env in all cases, even if not called from @@ -60,7 +60,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (__builtin_expect(ret, 0)) { if (retaddr) { /* now we have a real cpu fault */ - pc = (target_phys_addr_t)retaddr; + pc = (unsigned long)retaddr; tb = tb_find_pc(pc); if (tb) { /* the PC is inside the translated code. It means that we have diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 80ec89040..547f13da5 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -57,7 +57,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; - target_phys_addr_t pc; + unsigned long pc; int ret; /* XXX: hack to restore env in all cases, even if not called from @@ -68,7 +68,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (__builtin_expect(ret, 0)) { if (retaddr) { /* now we have a real cpu fault */ - pc = (target_phys_addr_t)retaddr; + pc = (unsigned long)retaddr; tb = tb_find_pc(pc); if (tb) { /* the PC is inside the translated code. It means that we have diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 7d1411a1f..2c6cef127 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2743,7 +2743,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) { TranslationBlock *tb; CPUState *saved_env; - target_phys_addr_t pc; + unsigned long pc; int ret; /* XXX: hack to restore env in all cases, even if not called from @@ -2754,7 +2754,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) if (unlikely(ret != 0)) { if (likely(retaddr)) { /* now we have a real cpu fault */ - pc = (target_phys_addr_t)(unsigned long)retaddr; + pc = (unsigned long)retaddr; tb = tb_find_pc(pc); if (likely(tb)) { /* the PC is inside the translated code. It means that we have -- cgit v1.2.3 From 579a97f7ff4c0f958a5d8adcba717a205bb58567 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 14:26:47 +0000 Subject: Linux user memory access API change (initial patch by Thayne Harbaugh) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3583 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- arm-semi.c | 52 ++- exec.c | 10 +- linux-user/elfload.c | 3 +- linux-user/flatload.c | 2 +- linux-user/linuxload.c | 9 +- linux-user/qemu.h | 121 +++--- linux-user/signal.c | 244 ++++++------ linux-user/strace.c | 33 +- linux-user/syscall.c | 985 ++++++++++++++++++++++++++++--------------------- linux-user/uaccess.c | 51 +++ linux-user/vm86.c | 7 +- m68k-semi.c | 84 +++-- softmmu-semi.h | 2 +- 14 files changed, 977 insertions(+), 628 deletions(-) create mode 100644 linux-user/uaccess.c diff --git a/Makefile.target b/Makefile.target index 33cf23bec..18938e879 100644 --- a/Makefile.target +++ b/Makefile.target @@ -260,7 +260,7 @@ endif ifdef CONFIG_LINUX_USER OBJS= main.o syscall.o strace.o mmap.o signal.o path.o osdep.o thunk.o \ - elfload.o linuxload.o + elfload.o linuxload.o uaccess.o LIBS+= $(AIOLIBS) ifdef TARGET_HAS_BFLT OBJS+= flatload.o diff --git a/arm-semi.c b/arm-semi.c index ff7a343bc..d5fb9a55a 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -184,9 +184,11 @@ uint32_t do_arm_semihosting(CPUState *env) args = env->regs[1]; switch (nr) { case SYS_OPEN: - s = lock_user_string(ARG(0)); + if (!(s = lock_user_string(ARG(0)))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; if (ARG(1) >= 12) - return (uint32_t)-1; + return (uint32_t)-1; if (strcmp(s, ":tt") == 0) { if (ARG(1) < 4) return STDIN_FILENO; @@ -221,7 +223,9 @@ uint32_t do_arm_semihosting(CPUState *env) } } case SYS_WRITE0: - s = lock_user_string(args); + if (!(s = lock_user_string(args))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; len = strlen(s); if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len); @@ -238,7 +242,9 @@ uint32_t do_arm_semihosting(CPUState *env) gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len); return env->regs[0]; } else { - s = lock_user(ARG(1), len, 1); + if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; ret = set_swi_errno(ts, write(ARG(0), s, len)); unlock_user(s, ARG(1), 0); if (ret == (uint32_t)-1) @@ -252,7 +258,9 @@ uint32_t do_arm_semihosting(CPUState *env) gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len); return env->regs[0]; } else { - s = lock_user(ARG(1), len, 0); + if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; do ret = set_swi_errno(ts, read(ARG(0), s, len)); while (ret == -1 && errno == EINTR); @@ -301,7 +309,9 @@ uint32_t do_arm_semihosting(CPUState *env) gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1); ret = env->regs[0]; } else { - s = lock_user_string(ARG(0)); + if (!(s = lock_user_string(ARG(0)))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; ret = set_swi_errno(ts, remove(s)); unlock_user(s, ARG(0), 0); } @@ -315,9 +325,15 @@ uint32_t do_arm_semihosting(CPUState *env) char *s2; s = lock_user_string(ARG(0)); s2 = lock_user_string(ARG(2)); - ret = set_swi_errno(ts, rename(s, s2)); - unlock_user(s2, ARG(2), 0); - unlock_user(s, ARG(0), 0); + if (!s || !s2) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + ret = (uint32_t)-1; + else + ret = set_swi_errno(ts, rename(s, s2)); + if (s2) + unlock_user(s2, ARG(2), 0); + if (s) + unlock_user(s, ARG(0), 0); return ret; } case SYS_CLOCK: @@ -329,7 +345,9 @@ uint32_t do_arm_semihosting(CPUState *env) gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1); return env->regs[0]; } else { - s = lock_user_string(ARG(0)); + if (!(s = lock_user_string(ARG(0)))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; ret = set_swi_errno(ts, system(s)); unlock_user(s, ARG(0), 0); } @@ -346,7 +364,11 @@ uint32_t do_arm_semihosting(CPUState *env) char **arg = ts->info->host_argv; int len = ARG(1); /* lock the buffer on the ARM side */ - char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0); + char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0); + + if (!cmdline_buffer) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; s = cmdline_buffer; while (*arg && len > 2) { @@ -402,7 +424,9 @@ uint32_t do_arm_semihosting(CPUState *env) ts->heap_limit = limit; } - ptr = lock_user(ARG(0), 16, 0); + if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; ptr[0] = tswap32(ts->heap_base); ptr[1] = tswap32(ts->heap_limit); ptr[2] = tswap32(ts->stack_base); @@ -410,7 +434,9 @@ uint32_t do_arm_semihosting(CPUState *env) unlock_user(ptr, ARG(0), 16); #else limit = ram_size; - ptr = lock_user(ARG(0), 16, 0); + if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0))) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; /* TODO: Make this use the limit of the loaded application. */ ptr[0] = tswap32(limit / 2); ptr[1] = tswap32(limit); diff --git a/exec.c b/exec.c index 798780363..e817a4e5e 100644 --- a/exec.c +++ b/exec.c @@ -2510,13 +2510,19 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, if (is_write) { if (!(flags & PAGE_WRITE)) return; - p = lock_user(addr, len, 0); + /* XXX: this code should not depend on lock_user */ + if (!(p = lock_user(VERIFY_WRITE, addr, len, 0))) + /* FIXME - should this return an error rather than just fail? */ + return; memcpy(p, buf, len); unlock_user(p, addr, len); } else { if (!(flags & PAGE_READ)) return; - p = lock_user(addr, len, 1); + /* XXX: this code should not depend on lock_user */ + if (!(p = lock_user(VERIFY_READ, addr, len, 1))) + /* FIXME - should this return an error rather than just fail? */ + return; memcpy(buf, p, len); unlock_user(p, addr, 0); } diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 2d758de20..14c6417ae 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -677,7 +677,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { info->rss++; - + /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); free(bprm->page[i]); } @@ -760,6 +760,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, size_t len = strlen(k_platform) + 1; sp -= (len + n - 1) & ~(n - 1); u_platform = sp; + /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(sp, k_platform, len); } /* diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 86b77f988..7a76c0fcd 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -108,7 +108,7 @@ int target_pread(int fd, abi_ulong ptr, abi_ulong len, void *buf; int ret; - buf = lock_user(ptr, len, 0); + buf = lock_user(VERIFY_WRITE, ptr, len, 0); ret = pread(fd, buf, len, offset); unlock_user(buf, ptr, len); return ret; diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 42a02d206..684ec06ce 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -13,14 +13,17 @@ #define NGROUPS 32 /* ??? This should really be somewhere else. */ -void memcpy_to_target(abi_ulong dest, const void *src, - unsigned long len) +abi_long memcpy_to_target(abi_ulong dest, const void *src, + unsigned long len) { void *host_ptr; - host_ptr = lock_user(dest, len, 0); + host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); + if (!host_ptr) + return -TARGET_EFAULT; memcpy(host_ptr, src, len); unlock_user(host_ptr, dest, 1); + return 0; } static int in_group_p(gid_t g) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 6fc0bbffc..68ce12a62 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -146,8 +146,8 @@ int load_elf_binary_multi(struct linux_binprm *bprm, struct image_info *info); #endif -void memcpy_to_target(abi_ulong dest, const void *src, - unsigned long len); +abi_long memcpy_to_target(abi_ulong dest, const void *src, + unsigned long len); void target_set_brk(abi_ulong new_brk); abi_long do_brk(abi_ulong new_brk); void syscall_init(void); @@ -179,9 +179,7 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); long do_sigreturn(CPUState *env); long do_rt_sigreturn(CPUState *env); -int do_sigaltstack(const struct target_sigaltstack *uss, - struct target_sigaltstack *uoss, - abi_ulong sp); +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); #ifdef TARGET_I386 /* vm86.c */ @@ -207,12 +205,15 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); /* user access */ #define VERIFY_READ 0 -#define VERIFY_WRITE 1 +#define VERIFY_WRITE 1 /* implies read access */ #define access_ok(type,addr,size) \ (page_check_range((target_ulong)addr,size,(type==VERIFY_READ)?PAGE_READ:PAGE_WRITE)==0) /* NOTE __get_user and __put_user use host pointers and don't check access. */ +/* These are usually used to access struct data members once the + * struct has been locked - usually with lock_user_struct(). + */ #define __put_user(x, hptr)\ ({\ int size = sizeof(*hptr);\ @@ -257,26 +258,44 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); 0;\ }) -#define put_user(x,ptr)\ -({\ - int __ret;\ - if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\ - __ret = __put_user(x, ptr);\ - else\ - __ret = -EFAULT;\ - __ret;\ +/* put_user()/get_user() take a guest address and check access */ +/* These are usually used to access an atomic data type, such as an int, + * that has been passed by address. These internally perform locking + * and unlocking on the data type. + */ +#define put_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type *__hptr; \ + abi_long __ret; \ + if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \ + __ret = __put_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, sizeof(target_type)); \ + } else \ + __ret = -TARGET_EFAULT; \ + __ret; \ }) -#define get_user(x,ptr)\ -({\ - int __ret;\ - if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\ - __ret = __get_user(x, ptr);\ - else\ - __ret = -EFAULT;\ - __ret;\ +#define get_user(x, gaddr, target_type) \ +({ \ + abi_ulong __gaddr = (gaddr); \ + target_type *__hptr; \ + abi_long __ret; \ + if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ + __ret = __get_user((x), __hptr); \ + unlock_user(__hptr, __gaddr, 0); \ + } else \ + __ret = -TARGET_EFAULT; \ + __ret; \ }) +/* copy_from_user() and copy_to_user() are usually used to copy data + * buffers between the target and host. These internally perform + * locking/unlocking of the memory. + */ +abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len); +abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); + /* Functions for accessing guest memory. The tget and tput functions read/write single values, byteswapping as neccessary. The lock_user gets a pointer to a contiguous area of guest memory, but does not perform @@ -285,53 +304,61 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); /* Lock an area of guest memory into the host. If copy is true then the host area will have the same contents as the guest. */ -static inline void *lock_user(abi_ulong guest_addr, long len, int copy) +static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) { + if (!access_ok(type, guest_addr, len)) + return NULL; #ifdef DEBUG_REMAP - void *addr; - addr = malloc(len); - if (copy) - memcpy(addr, g2h(guest_addr), len); - else - memset(addr, 0, len); - return addr; + { + void *addr; + addr = malloc(len); + if (copy) + memcpy(addr, g2h(guest_addr), len); + else + memset(addr, 0, len); + return addr; + } #else return g2h(guest_addr); #endif } -/* Unlock an area of guest memory. The first LEN bytes must be flushed back - to guest memory. */ -static inline void unlock_user(void *host_addr, abi_ulong guest_addr, +/* Unlock an area of guest memory. The first LEN bytes must be + flushed back to guest memory. host_ptr = NULL is explicitely + allowed and does nothing. */ +static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len) { + #ifdef DEBUG_REMAP - if (host_addr == g2h(guest_addr)) + if (!host_ptr) + return; + if (host_ptr == g2h(guest_addr)) return; if (len > 0) - memcpy(g2h(guest_addr), host_addr, len); - free(host_addr); + memcpy(g2h(guest_ptr), host_ptr, len); + free(host_ptr); #endif } -/* Return the length of a string in target memory. */ -static inline int target_strlen(abi_ulong ptr) -{ - return strlen(g2h(ptr)); -} +/* Return the length of a string in target memory or -TARGET_EFAULT if + access error. */ +abi_long target_strlen(abi_ulong gaddr); /* Like lock_user but for null terminated strings. */ static inline void *lock_user_string(abi_ulong guest_addr) { - long len; - len = target_strlen(guest_addr) + 1; - return lock_user(guest_addr, len, 1); + abi_long len; + len = target_strlen(guest_addr); + if (len < 0) + return NULL; + return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1); } /* Helper macros for locking/ulocking a target struct. */ -#define lock_user_struct(host_ptr, guest_addr, copy) \ - host_ptr = lock_user(guest_addr, sizeof(*host_ptr), copy) -#define unlock_user_struct(host_ptr, guest_addr, copy) \ +#define lock_user_struct(type, host_ptr, guest_addr, copy) \ + (host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy)) +#define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) #define tget8(addr) ldub(addr) diff --git a/linux-user/signal.c b/linux-user/signal.c index a0f151102..e9da0971f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -435,31 +435,32 @@ static void host_signal_handler(int host_signum, siginfo_t *info, } /* do_sigaltstack() returns target values and errnos. */ -int do_sigaltstack(const struct target_sigaltstack *uss, - struct target_sigaltstack *uoss, - abi_ulong sp) +/* compare linux/kernel/signal.c:do_sigaltstack() */ +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) { int ret; struct target_sigaltstack oss; /* XXX: test errors */ - if(uoss) + if(uoss_addr) { __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp); __put_user(target_sigaltstack_used.ss_size, &oss.ss_size); __put_user(sas_ss_flags(sp), &oss.ss_flags); } - if(uss) + if(uss_addr) { - struct target_sigaltstack ss; + struct target_sigaltstack *uss; + struct target_sigaltstack ss; ret = -TARGET_EFAULT; - if (!access_ok(VERIFY_READ, uss, sizeof(*uss)) + if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) || __get_user(ss.ss_sp, &uss->ss_sp) || __get_user(ss.ss_size, &uss->ss_size) || __get_user(ss.ss_flags, &uss->ss_flags)) goto out; + unlock_user_struct(uss, uss_addr, 0); ret = -TARGET_EPERM; if (on_sig_stack(sp)) @@ -484,11 +485,10 @@ int do_sigaltstack(const struct target_sigaltstack *uss, target_sigaltstack_used.ss_size = ss.ss_size; } - if (uoss) { + if (uoss_addr) { ret = -TARGET_EFAULT; - if (!access_ok(VERIFY_WRITE, uoss, sizeof(oss))) + if (copy_to_user(uoss_addr, &oss, sizeof(oss))) goto out; - memcpy(uoss, &oss, sizeof(oss)); } ret = 0; @@ -671,6 +671,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, { int err = 0; + /* already locked in setup_frame() */ err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs); err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs); err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es); @@ -706,7 +707,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, * Determine which stack to use.. */ -static inline void * +static inline abi_ulong get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) { unsigned long esp; @@ -726,19 +727,22 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) ka->sa.sa_restorer) { esp = (unsigned long) ka->sa.sa_restorer; } - return g2h((esp - frame_size) & -8ul); + return (esp - frame_size) & -8ul; } +/* compare linux/arch/i386/kernel/signal.c:setup_frame() */ static void setup_frame(int sig, struct emulated_sigaction *ka, target_sigset_t *set, CPUX86State *env) { + abi_ulong frame_addr; struct sigframe *frame; int i, err = 0; - frame = get_sigframe(ka, env, sizeof(*frame)); + frame_addr = get_sigframe(ka, env, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; + err |= __put_user((/*current->exec_domain && current->exec_domain->signal_invmap && sig < 32 @@ -786,24 +790,29 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, cpu_x86_load_seg(env, R_CS, __USER_CS); env->eflags &= ~TF_MASK; + unlock_user_struct(frame, frame_addr, 1); + return; give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); if (sig == TARGET_SIGSEGV) ka->sa._sa_handler = TARGET_SIG_DFL; force_sig(TARGET_SIGSEGV /* , current */); } +/* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUX86State *env) { + abi_ulong frame_addr; struct rt_sigframe *frame; int i, err = 0; - frame = get_sigframe(ka, env, sizeof(*frame)); + frame_addr = get_sigframe(ka, env, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; err |= __put_user((/*current->exec_domain @@ -859,9 +868,12 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, cpu_x86_load_seg(env, R_CS, __USER_CS); env->eflags &= ~TF_MASK; + unlock_user_struct(frame, frame_addr, 1); + return; give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); if (sig == TARGET_SIGSEGV) ka->sa._sa_handler = TARGET_SIG_DFL; force_sig(TARGET_SIGSEGV /* , current */); @@ -918,7 +930,8 @@ badframe: long do_sigreturn(CPUX86State *env) { - struct sigframe *frame = (struct sigframe *)g2h(env->regs[R_ESP] - 8); + struct sigframe *frame; + abi_ulong frame_addr = env->regs[R_ESP] - 8; target_sigset_t target_set; sigset_t set; int eax, i; @@ -926,6 +939,8 @@ long do_sigreturn(CPUX86State *env) #if defined(DEBUG_SIGNAL) fprintf(stderr, "do_sigreturn\n"); #endif + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; /* set blocked signals */ if (__get_user(target_set.sig[0], &frame->sc.oldmask)) goto badframe; @@ -940,9 +955,11 @@ long do_sigreturn(CPUX86State *env) /* restore registers */ if (restore_sigcontext(env, &frame->sc, &eax)) goto badframe; + unlock_user_struct(frame, frame_addr, 0); return eax; badframe: + unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); return 0; } @@ -963,7 +980,7 @@ long do_rt_sigreturn(CPUX86State *env) if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) goto badframe; - if (do_sigaltstack(&frame->uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(h2g(&frame->uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; return eax; @@ -1086,7 +1103,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ return err; } -static inline void * +static inline abi_ulong get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) { unsigned long sp = regs->regs[13]; @@ -1099,7 +1116,7 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) /* * ATPCS B01 mandates 8-byte alignment */ - return g2h((sp - framesize) & ~7); + return (sp - framesize) & ~7; } static int @@ -1167,33 +1184,43 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, return 0; } +/* compare linux/arch/arm/kernel/signal.c:setup_frame() */ static void setup_frame(int usig, struct emulated_sigaction *ka, target_sigset_t *set, CPUState *regs) { - struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); + struct sigframe *frame; + abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); int i, err = 0; + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + return; + err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); for(i = 1; i < TARGET_NSIG_WORDS; i++) { if (__put_user(set->sig[i], &frame->extramask[i - 1])) - return; + goto end; } if (err == 0) err = setup_return(regs, ka, &frame->retcode, frame, usig); + +end: + unlock_user_struct(frame, frame_addr, 1); // return err; } +/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUState *env) { - struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame)); + struct rt_sigframe *frame; + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); struct target_sigaltstack stack; int i, err = 0; - if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) return /* 1 */; __put_user_error(&frame->info, (abi_ulong *)&frame->pinfo, err); @@ -1207,16 +1234,13 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); - if (!access_ok(VERIFY_WRITE, &frame->uc.tuc_stack, sizeof(stack))) - err = 1; - else - memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); + err |= copy_to_user(&frame->uc.tuc_stack, &stack, sizeof(stack)); err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ env, set->sig[0]); for(i = 0; i < TARGET_NSIG_WORDS; i++) { if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) - return; + goto end; } if (err == 0) @@ -1232,6 +1256,9 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, env->regs[2] = (abi_ulong)frame->puc; } +end: + unlock_user_struct(frame, frame_addr, 1); + // return err; } @@ -1338,7 +1365,7 @@ long do_rt_sigreturn(CPUState *env) if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) goto badframe; - if (do_sigaltstack(&frame->uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(h2g(&frame->uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; #if 0 @@ -1788,8 +1815,8 @@ void sparc64_set_context(CPUSPARCState *env) abi_ulong *src, *dst; grp = &ucp->uc_mcontext.mc_gregs; - err = get_user(pc, &((*grp)[MC_PC])); - err |= get_user(npc, &((*grp)[MC_NPC])); + err = __get_user(pc, &((*grp)[MC_PC])); + err |= __get_user(npc, &((*grp)[MC_NPC])); if (err || ((pc | npc) & 3)) goto do_sigsegv; if (env->regwptr[UREG_I1]) { @@ -1797,14 +1824,14 @@ void sparc64_set_context(CPUSPARCState *env) sigset_t set; if (TARGET_NSIG_WORDS == 1) { - if (get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0])) + if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0])) goto do_sigsegv; } else { src = &ucp->uc_sigmask; dst = &target_set; for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong); i++, dst++, src++) - err |= get_user(dst, src); + err |= __get_user(dst, src); if (err) goto do_sigsegv; } @@ -1813,44 +1840,44 @@ void sparc64_set_context(CPUSPARCState *env) } env->pc = pc; env->npc = npc; - err |= get_user(env->y, &((*grp)[MC_Y])); - err |= get_user(tstate, &((*grp)[MC_TSTATE])); + err |= __get_user(env->y, &((*grp)[MC_Y])); + err |= __get_user(tstate, &((*grp)[MC_TSTATE])); env->asi = (tstate >> 24) & 0xff; PUT_CCR(env, tstate >> 32); PUT_CWP64(env, tstate & 0x1f); - err |= get_user(env->gregs[1], (&(*grp)[MC_G1])); - err |= get_user(env->gregs[2], (&(*grp)[MC_G2])); - err |= get_user(env->gregs[3], (&(*grp)[MC_G3])); - err |= get_user(env->gregs[4], (&(*grp)[MC_G4])); - err |= get_user(env->gregs[5], (&(*grp)[MC_G5])); - err |= get_user(env->gregs[6], (&(*grp)[MC_G6])); - err |= get_user(env->gregs[7], (&(*grp)[MC_G7])); - err |= get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0])); - err |= get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1])); - err |= get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2])); - err |= get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3])); - err |= get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4])); - err |= get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5])); - err |= get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6])); - err |= get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7])); - - err |= get_user(fp, &(ucp->uc_mcontext.mc_fp)); - err |= get_user(i7, &(ucp->uc_mcontext.mc_i7)); - err |= put_user(fp, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); - err |= put_user(i7, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); - - err |= get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); - err |= get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); + err |= __get_user(env->gregs[1], (&(*grp)[MC_G1])); + err |= __get_user(env->gregs[2], (&(*grp)[MC_G2])); + err |= __get_user(env->gregs[3], (&(*grp)[MC_G3])); + err |= __get_user(env->gregs[4], (&(*grp)[MC_G4])); + err |= __get_user(env->gregs[5], (&(*grp)[MC_G5])); + err |= __get_user(env->gregs[6], (&(*grp)[MC_G6])); + err |= __get_user(env->gregs[7], (&(*grp)[MC_G7])); + err |= __get_user(env->regwptr[UREG_I0], (&(*grp)[MC_O0])); + err |= __get_user(env->regwptr[UREG_I1], (&(*grp)[MC_O1])); + err |= __get_user(env->regwptr[UREG_I2], (&(*grp)[MC_O2])); + err |= __get_user(env->regwptr[UREG_I3], (&(*grp)[MC_O3])); + err |= __get_user(env->regwptr[UREG_I4], (&(*grp)[MC_O4])); + err |= __get_user(env->regwptr[UREG_I5], (&(*grp)[MC_O5])); + err |= __get_user(env->regwptr[UREG_I6], (&(*grp)[MC_O6])); + err |= __get_user(env->regwptr[UREG_I7], (&(*grp)[MC_O7])); + + err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp)); + err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7)); + err |= __put_user(fp, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); + err |= __put_user(i7, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); + + err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); + err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); src = &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs); dst = &env->fpr; for (i = 0; i < 64; i++, dst++, src++) - err |= get_user(dst, src); - err |= get_user(env->fsr, - &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); - err |= get_user(env->gsr, - &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); + err |= __get_user(dst, src); + err |= __get_user(env->fsr, + &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); + err |= __get_user(env->gsr, + &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); if (err) goto do_sigsegv; @@ -1884,52 +1911,52 @@ void sparc64_get_context(CPUSPARCState *env) sigprocmask(0, NULL, &set); host_to_target_sigset_internal(&target_set, &set); if (TARGET_NSIG_WORDS == 1) - err |= put_user(target_set.sig[0], - (abi_ulong *)&ucp->uc_sigmask); + err |= __put_user(target_set.sig[0], + (abi_ulong *)&ucp->uc_sigmask); else { src = &target_set; dst = &ucp->uc_sigmask; for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong); i++, dst++, src++) - err |= put_user(src, dst); + err |= __put_user(src, dst); if (err) goto do_sigsegv; } - err |= put_user(env->tstate, &((*grp)[MC_TSTATE])); - err |= put_user(env->pc, &((*grp)[MC_PC])); - err |= put_user(env->npc, &((*grp)[MC_NPC])); - err |= put_user(env->y, &((*grp)[MC_Y])); - err |= put_user(env->gregs[1], &((*grp)[MC_G1])); - err |= put_user(env->gregs[2], &((*grp)[MC_G2])); - err |= put_user(env->gregs[3], &((*grp)[MC_G3])); - err |= put_user(env->gregs[4], &((*grp)[MC_G4])); - err |= put_user(env->gregs[5], &((*grp)[MC_G5])); - err |= put_user(env->gregs[6], &((*grp)[MC_G6])); - err |= put_user(env->gregs[7], &((*grp)[MC_G7])); - err |= put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0])); - err |= put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1])); - err |= put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2])); - err |= put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3])); - err |= put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4])); - err |= put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5])); - err |= put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6])); - err |= put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7])); - - err |= get_user(fp, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); - err |= get_user(i7, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); - err |= put_user(fp, &(mcp->mc_fp)); - err |= put_user(i7, &(mcp->mc_i7)); + err |= __put_user(env->tstate, &((*grp)[MC_TSTATE])); + err |= __put_user(env->pc, &((*grp)[MC_PC])); + err |= __put_user(env->npc, &((*grp)[MC_NPC])); + err |= __put_user(env->y, &((*grp)[MC_Y])); + err |= __put_user(env->gregs[1], &((*grp)[MC_G1])); + err |= __put_user(env->gregs[2], &((*grp)[MC_G2])); + err |= __put_user(env->gregs[3], &((*grp)[MC_G3])); + err |= __put_user(env->gregs[4], &((*grp)[MC_G4])); + err |= __put_user(env->gregs[5], &((*grp)[MC_G5])); + err |= __put_user(env->gregs[6], &((*grp)[MC_G6])); + err |= __put_user(env->gregs[7], &((*grp)[MC_G7])); + err |= __put_user(env->regwptr[UREG_I0], &((*grp)[MC_O0])); + err |= __put_user(env->regwptr[UREG_I1], &((*grp)[MC_O1])); + err |= __put_user(env->regwptr[UREG_I2], &((*grp)[MC_O2])); + err |= __put_user(env->regwptr[UREG_I3], &((*grp)[MC_O3])); + err |= __put_user(env->regwptr[UREG_I4], &((*grp)[MC_O4])); + err |= __put_user(env->regwptr[UREG_I5], &((*grp)[MC_O5])); + err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6])); + err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7])); + + err |= __get_user(fp, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); + err |= __get_user(i7, + (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); + err |= __put_user(fp, &(mcp->mc_fp)); + err |= __put_user(i7, &(mcp->mc_i7)); src = &env->fpr; dst = &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs); for (i = 0; i < 64; i++, dst++, src++) - err |= put_user(src, dst); - err |= put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr)); - err |= put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr)); - err |= put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs)); + err |= __put_user(src, dst); + err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr)); + err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr)); + err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs)); if (err) goto do_sigsegv; @@ -2191,7 +2218,7 @@ restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) /* * Determine which stack to use.. */ -static inline void * +static inline abi_ulong get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) { unsigned long sp; @@ -2211,17 +2238,19 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; } - return g2h((sp - frame_size) & ~7); + return (sp - frame_size) & ~7; } +/* compare linux/arch/mips/kernel/signal.c:setup_frame() */ static void setup_frame(int sig, struct emulated_sigaction * ka, - target_sigset_t *set, CPUState *regs) + target_sigset_t *set, CPUState *regs) { struct sigframe *frame; + abi_ulong frame_addr; int i; - frame = get_sigframe(ka, regs, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); @@ -2253,9 +2282,11 @@ static void setup_frame(int sig, struct emulated_sigaction * ka, * since it returns to userland using eret * we cannot do this here, and we must set PC directly */ regs->PC[regs->current_tc] = regs->gpr[25][regs->current_tc] = ka->sa._sa_handler; + unlock_user_struct(frame, frame_addr, 1); return; give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); force_sig(TARGET_SIGSEGV/*, current*/); return; } @@ -2263,6 +2294,7 @@ give_sigsegv: long do_sigreturn(CPUState *regs) { struct sigframe *frame; + abi_ulong frame_addr; sigset_t blocked; target_sigset_t target_set; int i; @@ -2270,8 +2302,8 @@ long do_sigreturn(CPUState *regs) #if defined(DEBUG_SIGNAL) fprintf(stderr, "do_sigreturn\n"); #endif - frame = (struct sigframe *) regs->gpr[29][regs->current_tc]; - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + frame_addr = regs->gpr[29][regs->current_tc]; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) goto badframe; for(i = 0; i < TARGET_NSIG_WORDS; i++) { diff --git a/linux-user/strace.c b/linux-user/strace.c index c645ddfca..315ae5c31 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -81,14 +81,18 @@ print_fdset(int n, target_ulong target_fds_addr) gemu_log("["); if( target_fds_addr ) { - target_long *target_fds; + abi_long *target_fds; - if (!access_ok(VERIFY_READ, target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1))) + target_fds = lock_user(VERIFY_READ, + target_fds_addr, + sizeof(*target_fds)*(n / TARGET_ABI_BITS + 1), + 1); + + if (!target_fds) return; - target_fds = lock_user(target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1), 1); for (i=n; i>=0; i--) { - if ((tswapl(target_fds[i / TARGET_LONG_BITS]) >> (i & (TARGET_LONG_BITS - 1))) & 1) + if ((tswapl(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1) gemu_log("%d,", i ); } unlock_user(target_fds, target_fds_addr, 0); @@ -102,10 +106,9 @@ print_timeval(target_ulong tv_addr) if( tv_addr ) { struct target_timeval *tv; - if (!access_ok(VERIFY_READ, tv_addr, sizeof(*tv))) + tv = lock_user(VERIFY_READ, tv_addr, sizeof(*tv), 1); + if (!tv) return; - - tv = lock_user(tv_addr, sizeof(*tv), 1); gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}", tv->tv_sec, tv->tv_usec); unlock_user(tv, tv_addr, 0); @@ -165,27 +168,25 @@ print_execve(struct syscallname *name, target_ulong arg_ptr_addr; char *s; - if (!access_ok(VERIFY_READ, arg1, 1)) + if (!(s = lock_user_string(arg1))) return; - - s = lock_user_string(arg1); gemu_log("%s(\"%s\",{", name->name, s); unlock_user(s, arg1, 0); for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(target_ulong)) { target_ulong *arg_ptr, arg_addr, s_addr; - if (!access_ok(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong))) + arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong), 1); + if (!arg_ptr) return; - - arg_ptr = lock_user(arg_ptr_addr, sizeof(target_ulong), 1); arg_addr = tswapl(*arg_ptr); unlock_user(arg_ptr, arg_ptr_addr, 0); if (!arg_addr) break; - s = lock_user_string(arg_addr); - gemu_log("\"%s\",", s); - unlock_user(s, s_addr, 0); + if ((s = lock_user_string(arg_addr))) { + gemu_log("\"%s\",", s); + unlock_user(s, s_addr, 0); + } } gemu_log("NULL})"); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 07e84d963..656f78ee4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -504,12 +504,13 @@ static inline abi_long host_to_target_clock_t(long ticks) #endif } -static inline void host_to_target_rusage(abi_ulong target_addr, - const struct rusage *rusage) +static inline abi_long host_to_target_rusage(abi_ulong target_addr, + const struct rusage *rusage) { struct target_rusage *target_rusage; - lock_user_struct(target_rusage, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rusage, target_addr, 0)) + return -TARGET_EFAULT; target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec); target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec); target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec); @@ -529,28 +530,36 @@ static inline void host_to_target_rusage(abi_ulong target_addr, target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw); target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw); unlock_user_struct(target_rusage, target_addr, 1); + + return 0; } -static inline void target_to_host_timeval(struct timeval *tv, - abi_ulong target_addr) +static inline abi_long target_to_host_timeval(struct timeval *tv, + abi_ulong target_addr) { struct target_timeval *target_tv; - lock_user_struct(target_tv, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_tv, target_addr, 1)) + return -TARGET_EFAULT; tv->tv_sec = tswapl(target_tv->tv_sec); tv->tv_usec = tswapl(target_tv->tv_usec); unlock_user_struct(target_tv, target_addr, 0); + + return 0; } -static inline void host_to_target_timeval(abi_ulong target_addr, - const struct timeval *tv) +static inline abi_long host_to_target_timeval(abi_ulong target_addr, + const struct timeval *tv) { struct target_timeval *target_tv; - lock_user_struct(target_tv, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_tv, target_addr, 0)) + return -TARGET_EFAULT; target_tv->tv_sec = tswapl(tv->tv_sec); target_tv->tv_usec = tswapl(tv->tv_usec); unlock_user_struct(target_tv, target_addr, 1); + + return 0; } @@ -567,21 +576,33 @@ static abi_long do_select(int n, int ok; if (rfd_p) { - target_rfds = lock_user(rfd_p, sizeof(abi_long) * n, 1); + target_rfds = lock_user(VERIFY_WRITE, rfd_p, sizeof(abi_long) * n, 1); + if (!target_rfds) { + ret = -TARGET_EFAULT; + goto end; + } rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); } else { target_rfds = NULL; rfds_ptr = NULL; } if (wfd_p) { - target_wfds = lock_user(wfd_p, sizeof(abi_long) * n, 1); + target_wfds = lock_user(VERIFY_WRITE, wfd_p, sizeof(abi_long) * n, 1); + if (!target_wfds) { + ret = -TARGET_EFAULT; + goto end; + } wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); } else { target_wfds = NULL; wfds_ptr = NULL; } if (efd_p) { - target_efds = lock_user(efd_p, sizeof(abi_long) * n, 1); + target_efds = lock_user(VERIFY_WRITE, efd_p, sizeof(abi_long) * n, 1); + if (!target_efds) { + ret = -TARGET_EFAULT; + goto end; + } efds_ptr = target_to_host_fds(&efds, target_efds, n); } else { target_efds = NULL; @@ -606,38 +627,45 @@ static abi_long do_select(int n, host_to_target_timeval(target_tv, &tv); } } - if (target_rfds) - unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); - if (target_wfds) - unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); - if (target_efds) - unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); + +end: + unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); + unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); + unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); return ret; } -static inline void target_to_host_sockaddr(struct sockaddr *addr, - abi_ulong target_addr, - socklen_t len) +static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, + abi_ulong target_addr, + socklen_t len) { struct target_sockaddr *target_saddr; - target_saddr = lock_user(target_addr, len, 1); + target_saddr = lock_user(VERIFY_READ, target_addr, len, 1); + if (!target_saddr) + return -TARGET_EFAULT; memcpy(addr, target_saddr, len); addr->sa_family = tswap16(target_saddr->sa_family); unlock_user(target_saddr, target_addr, 0); + + return 0; } -static inline void host_to_target_sockaddr(abi_ulong target_addr, - struct sockaddr *addr, - socklen_t len) +static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, + struct sockaddr *addr, + socklen_t len) { struct target_sockaddr *target_saddr; - target_saddr = lock_user(target_addr, len, 0); + target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0); + if (!target_saddr) + return -TARGET_EFAULT; memcpy(target_saddr, addr, len); target_saddr->sa_family = tswap16(addr->sa_family); unlock_user(target_saddr, target_addr, len); + + return 0; } /* ??? Should this also swap msgh->name? */ @@ -941,35 +969,56 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, return ret; } -static void lock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) +/* FIXME + * lock_iovec()/unlock_iovec() have a return code of 0 for success where + * other lock functions have a return code of 0 for failure. + */ +static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, + int count, int copy) { struct target_iovec *target_vec; abi_ulong base; - int i; + int i, j; - target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); + if (!target_vec) + return -TARGET_EFAULT; for(i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); vec[i].iov_len = tswapl(target_vec[i].iov_len); - vec[i].iov_base = lock_user(base, vec[i].iov_len, copy); + vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); + if (!vec[i].iov_base) + goto fail; + } + unlock_user (target_vec, target_addr, 0); + return 0; + fail: + /* failure - unwind locks */ + for (j = 0; j < i; j++) { + base = tswapl(target_vec[j].iov_base); + unlock_user(vec[j].iov_base, base, 0); } unlock_user (target_vec, target_addr, 0); + return -TARGET_EFAULT; } -static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) +static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, + int count, int copy) { struct target_iovec *target_vec; abi_ulong base; int i; - target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); + if (!target_vec) + return -TARGET_EFAULT; for(i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); } unlock_user (target_vec, target_addr, 0); + + return 0; } /* do_socket() Must return target values and target errnos. */ @@ -1033,7 +1082,12 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, struct iovec *vec; abi_ulong target_vec; - lock_user_struct(msgp, target_msg, 1); + /* FIXME */ + if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, + msgp, + target_msg, + send ? 1 : 0)) + return -TARGET_EFAULT; if (msgp->msg_name) { msg.msg_namelen = tswap32(msgp->msg_namelen); msg.msg_name = alloca(msg.msg_namelen); @@ -1050,7 +1104,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, count = tswapl(msgp->msg_iovlen); vec = alloca(count * sizeof(struct iovec)); target_vec = tswapl(msgp->msg_iov); - lock_iovec(vec, target_vec, count, send); + lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send); msg.msg_iovlen = count; msg.msg_iov = vec; @@ -1063,6 +1117,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, host_to_target_cmsg(msgp, &msg); } unlock_iovec(vec, target_vec, count, !send); + unlock_user_struct(msgp, target_msg, send ? 0 : 1); return ret; } @@ -1137,7 +1192,9 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, void *host_msg; abi_long ret; - host_msg = lock_user(msg, len, 1); + host_msg = lock_user(VERIFY_READ, msg, len, 1); + if (!host_msg) + return -TARGET_EFAULT; if (target_addr) { addr = alloca(addrlen); target_to_host_sockaddr(addr, target_addr, addrlen); @@ -1159,7 +1216,9 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, void *host_msg; abi_long ret; - host_msg = lock_user(msg, len, 0); + host_msg = lock_user(VERIFY_WRITE, msg, len, 0); + if (!host_msg) + return -TARGET_EFAULT; if (target_addr) { addrlen = tget32(target_addrlen); addr = alloca(addrlen); @@ -1381,13 +1440,14 @@ struct target_semid_ds abi_ulong __unused4; }; -static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, - abi_ulong target_addr) +static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, + abi_ulong target_addr) { struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return -TARGET_EFAULT; target_ip=&(target_sd->sem_perm); host_ip->__key = tswapl(target_ip->__key); host_ip->uid = tswapl(target_ip->uid); @@ -1396,15 +1456,17 @@ static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip, host_ip->cgid = tswapl(target_ip->cgid); host_ip->mode = tswapl(target_ip->mode); unlock_user_struct(target_sd, target_addr, 0); + return 0; } -static inline void host_to_target_ipc_perm(abi_ulong target_addr, - struct ipc_perm *host_ip) +static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr, + struct ipc_perm *host_ip) { struct target_ipc_perm *target_ip; struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return -TARGET_EFAULT; target_ip = &(target_sd->sem_perm); target_ip->__key = tswapl(host_ip->__key); target_ip->uid = tswapl(host_ip->uid); @@ -1413,32 +1475,37 @@ static inline void host_to_target_ipc_perm(abi_ulong target_addr, target_ip->cgid = tswapl(host_ip->cgid); target_ip->mode = tswapl(host_ip->mode); unlock_user_struct(target_sd, target_addr, 1); + return 0; } -static inline void target_to_host_semid_ds(struct semid_ds *host_sd, - abi_ulong target_addr) +static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, + abi_ulong target_addr) { struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr); host_sd->sem_nsems = tswapl(target_sd->sem_nsems); host_sd->sem_otime = tswapl(target_sd->sem_otime); host_sd->sem_ctime = tswapl(target_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 0); + return 0; } -static inline void host_to_target_semid_ds(abi_ulong target_addr, - struct semid_ds *host_sd) +static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, + struct semid_ds *host_sd) { struct target_semid_ds *target_sd; - lock_user_struct(target_sd, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)); target_sd->sem_nsems = tswapl(host_sd->sem_nsems); target_sd->sem_otime = tswapl(host_sd->sem_otime); target_sd->sem_ctime = tswapl(host_sd->sem_ctime); unlock_user_struct(target_sd, target_addr, 1); + return 0; } union semun { @@ -1453,67 +1520,75 @@ union target_semun { unsigned short int *array; }; -static inline void target_to_host_semun(int cmd, - union semun *host_su, - abi_ulong target_addr, - struct semid_ds *ds) +static inline abi_long target_to_host_semun(int cmd, + union semun *host_su, + abi_ulong target_addr, + struct semid_ds *ds) { union target_semun *target_su; switch( cmd ) { case IPC_STAT: case IPC_SET: - lock_user_struct(target_su, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_semid_ds(ds,target_su->buf); host_su->buf = ds; unlock_user_struct(target_su, target_addr, 0); break; case GETVAL: case SETVAL: - lock_user_struct(target_su, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; host_su->val = tswapl(target_su->val); unlock_user_struct(target_su, target_addr, 0); break; case GETALL: case SETALL: - lock_user_struct(target_su, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1)) + return -TARGET_EFAULT; *host_su->array = tswap16(*target_su->array); unlock_user_struct(target_su, target_addr, 0); break; default: gemu_log("semun operation not fully supported: %d\n", (int)cmd); } + return 0; } -static inline void host_to_target_semun(int cmd, - abi_ulong target_addr, - union semun *host_su, - struct semid_ds *ds) +static inline abi_long host_to_target_semun(int cmd, + abi_ulong target_addr, + union semun *host_su, + struct semid_ds *ds) { union target_semun *target_su; switch( cmd ) { case IPC_STAT: case IPC_SET: - lock_user_struct(target_su, target_addr, 0); + if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_semid_ds(target_su->buf,ds); unlock_user_struct(target_su, target_addr, 1); break; case GETVAL: case SETVAL: - lock_user_struct(target_su, target_addr, 0); + if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; target_su->val = tswapl(host_su->val); unlock_user_struct(target_su, target_addr, 1); break; case GETALL: case SETALL: - lock_user_struct(target_su, target_addr, 0); + if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0)) + return -TARGET_EFAULT; *target_su->array = tswap16(*host_su->array); unlock_user_struct(target_su, target_addr, 1); break; default: gemu_log("semun operation not fully supported: %d\n", (int)cmd); } + return 0; } static inline abi_long do_semctl(int first, int second, int third, @@ -1580,12 +1655,13 @@ struct target_msqid_ds abi_ulong __unused5; }; -static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, - abi_ulong target_addr) +static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, + abi_ulong target_addr) { struct target_msqid_ds *target_md; - lock_user_struct(target_md, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1)) + return -TARGET_EFAULT; target_to_host_ipc_perm(&(host_md->msg_perm),target_addr); host_md->msg_stime = tswapl(target_md->msg_stime); host_md->msg_rtime = tswapl(target_md->msg_rtime); @@ -1596,14 +1672,16 @@ static inline void target_to_host_msqid_ds(struct msqid_ds *host_md, host_md->msg_lspid = tswapl(target_md->msg_lspid); host_md->msg_lrpid = tswapl(target_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 0); + return 0; } -static inline void host_to_target_msqid_ds(abi_ulong target_addr, - struct msqid_ds *host_md) +static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr, + struct msqid_ds *host_md) { struct target_msqid_ds *target_md; - lock_user_struct(target_md, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0)) + return -TARGET_EFAULT; host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)); target_md->msg_stime = tswapl(host_md->msg_stime); target_md->msg_rtime = tswapl(host_md->msg_rtime); @@ -1614,6 +1692,7 @@ static inline void host_to_target_msqid_ds(abi_ulong target_addr, target_md->msg_lspid = tswapl(host_md->msg_lspid); target_md->msg_lrpid = tswapl(host_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 1); + return 0; } static inline abi_long do_msgctl(int first, int second, abi_long ptr) @@ -1645,7 +1724,8 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, struct msgbuf *host_mb; abi_long ret = 0; - lock_user_struct(target_mb,msgp,0); + if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) + return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); host_mb->mtype = tswapl(target_mb->mtype); memcpy(host_mb->mtext,target_mb->mtext,msgsz); @@ -1661,18 +1741,30 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, int msgflg) { struct target_msgbuf *target_mb; + char *target_mtext; struct msgbuf *host_mb; abi_long ret = 0; - lock_user_struct(target_mb, msgp, 0); + if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) + return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg)); - if (ret > 0) + if (ret > 0) { + abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); + target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0); + if (!target_mtext) { + ret = -TARGET_EFAULT; + goto end; + } memcpy(target_mb->mtext, host_mb->mtext, ret); + unlock_user(target_mtext, target_mtext_addr, ret); + } target_mb->mtype = tswapl(host_mb->mtype); free(host_mb); - unlock_user_struct(target_mb, msgp, 0); +end: + if (target_mb) + unlock_user_struct(target_mb, msgp, 1); return ret; } @@ -1693,7 +1785,7 @@ static abi_long do_ipc(unsigned int call, int first, switch (call) { case IPCOP_semop: - ret = get_errno(semop(first,(struct sembuf *) ptr, second)); + ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second)); break; case IPCOP_semget: @@ -1723,13 +1815,14 @@ static abi_long do_ipc(unsigned int call, int first, case IPCOP_msgrcv: { + /* XXX: this code is not correct */ struct ipc_kludge { void *__unbounded msgp; long int msgtyp; }; - struct ipc_kludge *foo = (struct ipc_kludge *) ptr; + struct ipc_kludge *foo = (struct ipc_kludge *)g2h(ptr); struct msgbuf *msgp = (struct msgbuf *) foo->msgp; ret = do_msgrcv(first, (long)msgp, second, 0, third); @@ -1761,7 +1854,7 @@ static abi_long do_ipc(unsigned int call, int first, break; } } - if (put_user(raddr, (abi_ulong *)third)) + if (put_user(raddr, third, abi_ulong)) return -TARGET_EFAULT; ret = 0; break; @@ -1883,25 +1976,33 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) case IOC_R: ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { - argptr = lock_user(arg, target_size, 0); + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } break; case IOC_W: - argptr = lock_user(arg, target_size, 1); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); break; default: case IOC_RW: - argptr = lock_user(arg, target_size, 1); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { - argptr = lock_user(arg, target_size, 0); + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); + if (!argptr) + return -TARGET_EFAULT; thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } @@ -2138,8 +2239,10 @@ static int read_ldt(abi_ulong ptr, unsigned long bytecount) size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; - p = lock_user(ptr, size, 0); - /* ??? Shoudl this by byteswapped? */ + p = lock_user(VERIFY_WRITE, ptr, size, 0); + if (!p) + return -EFAULT; + /* ??? Should this by byteswapped? */ memcpy(p, ldt_table, size); unlock_user(p, ptr, size); return size; @@ -2158,7 +2261,8 @@ static int write_ldt(CPUX86State *env, if (bytecount != sizeof(ldt_info)) return -EINVAL; - lock_user_struct(target_ldt_info, ptr, 1); + if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1)) + return -EFAULT; ldt_info.entry_number = tswap32(target_ldt_info->entry_number); ldt_info.base_addr = tswapl(target_ldt_info->base_addr); ldt_info.limit = tswap32(target_ldt_info->limit); @@ -2365,7 +2469,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) switch(cmd) { case TARGET_F_GETLK: - lock_user_struct(target_fl, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) + return -TARGET_EFAULT; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -2374,7 +2479,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) unlock_user_struct(target_fl, arg, 0); ret = fcntl(fd, cmd, &fl); if (ret == 0) { - lock_user_struct(target_fl, arg, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0)) + return -TARGET_EFAULT; target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswapl(fl.l_start); @@ -2386,7 +2492,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) case TARGET_F_SETLK: case TARGET_F_SETLKW: - lock_user_struct(target_fl, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) + return -TARGET_EFAULT; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapl(target_fl->l_start); @@ -2397,7 +2504,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) break; case TARGET_F_GETLK64: - lock_user_struct(target_fl64, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) + return -TARGET_EFAULT; fl64.l_type = tswap16(target_fl64->l_type) >> 1; fl64.l_whence = tswap16(target_fl64->l_whence); fl64.l_start = tswapl(target_fl64->l_start); @@ -2406,7 +2514,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) unlock_user_struct(target_fl64, arg, 0); ret = fcntl(fd, cmd >> 1, &fl64); if (ret == 0) { - lock_user_struct(target_fl64, arg, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0)) + return -TARGET_EFAULT; target_fl64->l_type = tswap16(fl64.l_type) >> 1; target_fl64->l_whence = tswap16(fl64.l_whence); target_fl64->l_start = tswapl(fl64.l_start); @@ -2417,14 +2526,15 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) break; case TARGET_F_SETLK64: case TARGET_F_SETLKW64: - lock_user_struct(target_fl64, arg, 1); + if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) + return -TARGET_EFAULT; fl64.l_type = tswap16(target_fl64->l_type) >> 1; fl64.l_whence = tswap16(target_fl64->l_whence); fl64.l_start = tswapl(target_fl64->l_start); fl64.l_len = tswapl(target_fl64->l_len); fl64.l_pid = tswap16(target_fl64->l_pid); unlock_user_struct(target_fl64, arg, 0); - ret = fcntl(fd, cmd >> 1, &fl64); + ret = fcntl(fd, cmd >> 1, &fl64); break; case F_GETFL: @@ -2577,23 +2687,25 @@ static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, } #endif -static inline void target_to_host_timespec(struct timespec *host_ts, - abi_ulong target_addr) +static inline abi_long target_to_host_timespec(struct timespec *host_ts, + abi_ulong target_addr) { struct target_timespec *target_ts; - lock_user_struct(target_ts, target_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) + return -TARGET_EFAULT; host_ts->tv_sec = tswapl(target_ts->tv_sec); host_ts->tv_nsec = tswapl(target_ts->tv_nsec); unlock_user_struct(target_ts, target_addr, 0); } -static inline void host_to_target_timespec(abi_ulong target_addr, - struct timespec *host_ts) +static inline abi_long host_to_target_timespec(abi_ulong target_addr, + struct timespec *host_ts) { struct target_timespec *target_ts; - lock_user_struct(target_ts, target_addr, 0); + if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) + return -TARGET_EFAULT; target_ts->tv_sec = tswapl(host_ts->tv_sec); target_ts->tv_nsec = tswapl(host_ts->tv_nsec); unlock_user_struct(target_ts, target_addr, 1); @@ -2629,17 +2741,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NR_read: page_unprotect_range(arg2, arg3); - p = lock_user(arg2, arg3, 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; ret = get_errno(read(arg1, p, arg3)); unlock_user(p, arg2, ret); break; case TARGET_NR_write: - p = lock_user(arg2, arg3, 1); + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; ret = get_errno(write(arg1, p, arg3)); unlock_user(p, arg2, 0); break; case TARGET_NR_open: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) { + return -TARGET_EFAULT; + goto fail; + } ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3)); @@ -2647,21 +2764,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_openat) && defined(__NR_openat) case TARGET_NR_openat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_openat(arg1, - path(p), - target_to_host_bitmask(arg3, fcntl_flags_tbl), - arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_openat(arg1, + path(p), + target_to_host_bitmask(arg3, fcntl_flags_tbl), + arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_close: @@ -2685,7 +2794,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_creat /* not on alpha */ case TARGET_NR_creat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(creat(p, arg2)); unlock_user(p, arg1, 0); break; @@ -2695,54 +2805,43 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void * p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(link(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(link(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_linkat) && defined(__NR_linkat) case TARGET_NR_linkat: - if (!arg2 || !arg4) { - ret = -TARGET_EFAULT; - goto fail; - } { void * p2 = NULL; + if (!arg2 || !arg4) + goto efault; p = lock_user_string(arg2); p2 = lock_user_string(arg4); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5)); - if (p2) - unlock_user(p, arg2, 0); - if (p) - unlock_user(p2, arg4, 0); + unlock_user(p, arg2, 0); + unlock_user(p2, arg4, 0); } break; #endif case TARGET_NR_unlink: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(unlink(p)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) case TARGET_NR_unlinkat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_unlinkat(arg1, p, arg3)); - if (p) - unlock_user(p, arg2, 0); - break; + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_unlinkat(arg1, p, arg3)); + unlock_user(p, arg2, 0); #endif case TARGET_NR_execve: { @@ -2771,7 +2870,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, addr = tgetl(gp); if (!addr) break; - *q = lock_user_string(addr); + if (!(*q = lock_user_string(addr))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } } *q = NULL; @@ -2780,14 +2882,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, addr = tgetl(gp); if (!addr) break; - *q = lock_user_string(addr); + if (!(*q = lock_user_string(addr))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } } *q = NULL; - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) { + ret = -TARGET_EFAULT; + goto execve_fail; + } ret = get_errno(execve(p, argp, envp)); unlock_user(p, arg1, 0); + execve_fail: for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { addr = tgetl(gp); @@ -2801,7 +2910,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; case TARGET_NR_chdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chdir(p)); unlock_user(p, arg1, 0); break; @@ -2816,28 +2926,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_mknod: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(mknod(p, arg2, arg3)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_mknodat) && defined(__NR_mknodat) case TARGET_NR_mknodat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_mknodat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_chmod: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chmod(p, arg2)); unlock_user(p, arg1, 0); break; @@ -2866,15 +2970,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, p = lock_user_string(arg1); p2 = lock_user_string(arg2); p3 = lock_user_string(arg3); - ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, (const void *)arg5)); - unlock_user(p, arg1, 0); - unlock_user(p2, arg2, 0); - unlock_user(p3, arg3, 0); + if (!p || !p2 || !p3) + ret = -TARGET_EFAULT; + else + /* FIXME - arg5 should be locked, but it isn't clear how to + * do that since it's not guaranteed to be a NULL-terminated + * string. + */ + ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5))); + unlock_user(p, arg1, 0); + unlock_user(p2, arg2, 0); + unlock_user(p3, arg3, 0); break; } #ifdef TARGET_NR_umount case TARGET_NR_umount: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(umount(p)); unlock_user(p, arg1, 0); break; @@ -2910,7 +3022,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct utimbuf tbuf, *host_tbuf; struct target_utimbuf *target_tbuf; if (arg2) { - lock_user_struct(target_tbuf, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1)) + goto efault; tbuf.actime = tswapl(target_tbuf->actime); tbuf.modtime = tswapl(target_tbuf->modtime); unlock_user_struct(target_tbuf, arg2, 0); @@ -2918,7 +3031,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else { host_tbuf = NULL; } - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(utime(p, host_tbuf)); unlock_user(p, arg1, 0); } @@ -2935,7 +3049,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else { tvp = NULL; } - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(utimes(p, tvp)); unlock_user(p, arg1, 0); } @@ -2949,24 +3064,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_access: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(access(p, arg2)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat) case TARGET_NR_faccessat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_faccessat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif #ifdef TARGET_NR_nice /* not on alpha */ @@ -2990,57 +3098,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(rename(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(rename(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_renameat) && defined(__NR_renameat) case TARGET_NR_renameat: - if (!arg2 || !arg4) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg2); p2 = lock_user_string(arg4); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_renameat(arg1, p, arg3, p2)); - if (p2) - unlock_user(p2, arg4, 0); - if (p) - unlock_user(p, arg2, 0); + unlock_user(p2, arg4, 0); + unlock_user(p, arg2, 0); } break; #endif case TARGET_NR_mkdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(mkdir(p, arg2)); unlock_user(p, arg1, 0); break; #if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat) case TARGET_NR_mkdirat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_mkdirat(arg1, p, arg3)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_mkdirat(arg1, p, arg3)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_rmdir: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(rmdir(p)); unlock_user(p, arg1, 0); break; @@ -3069,7 +3166,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct tms tms; ret = get_errno(times(&tms)); if (arg1) { - tmsp = lock_user(arg1, sizeof(struct target_tms), 0); + tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0); + if (!tmsp) + goto efault; tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime)); tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime)); tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime)); @@ -3088,13 +3187,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_acct: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(acct(path(p))); unlock_user(p, arg1, 0); break; #ifdef TARGET_NR_umount2 /* not on alpha */ case TARGET_NR_umount2: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(umount2(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3128,7 +3229,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(umask(arg1)); break; case TARGET_NR_chroot: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chroot(p)); unlock_user(p, arg1, 0); break; @@ -3155,7 +3257,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_old_sigaction *old_act; struct target_sigaction act, oact, *pact; if (arg2) { - lock_user_struct(old_act, arg2, 1); + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) + goto efault; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask); act.sa_flags = old_act->sa_flags; @@ -3167,7 +3270,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { - lock_user_struct(old_act, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) + goto efault; old_act->_sa_handler = oact._sa_handler; old_act->sa_mask = oact.sa_mask.sig[0]; old_act->sa_flags = oact.sa_flags; @@ -3178,7 +3282,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_sigaction act, oact, *pact, *old_act; if (arg2) { - lock_user_struct(old_act, arg2, 1); + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) + goto efault; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]); act.sa_flags = old_act->sa_flags; @@ -3191,7 +3296,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { - lock_user_struct(old_act, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) + goto efault; old_act->_sa_handler = oact._sa_handler; old_act->sa_flags = oact.sa_flags; old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; @@ -3209,18 +3315,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_sigaction *act; struct target_sigaction *oact; - if (arg2) - lock_user_struct(act, arg2, 1); - else + if (arg2) { + if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) + goto efault; + } else act = NULL; - if (arg3) - lock_user_struct(oact, arg3, 0); - else + if (arg3) { + if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) { + ret = -TARGET_EFAULT; + goto rt_sigaction_fail; + } + } else oact = NULL; ret = get_errno(do_sigaction(arg1, act, oact)); - if (arg2) + rt_sigaction_fail: + if (act) unlock_user_struct(act, arg2, 0); - if (arg3) + if (oact) unlock_user_struct(oact, arg3, 1); } break; @@ -3270,7 +3381,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_EINVAL; goto fail; } - p = lock_user(arg2, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_old_sigset(&set, p); unlock_user(p, arg2, 0); set_ptr = &set; @@ -3280,7 +3392,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); if (!is_error(ret) && arg3) { - p = lock_user(arg3, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_old_sigset(p, &oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } @@ -3307,7 +3420,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_EINVAL; goto fail; } - p = lock_user(arg2, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg2, 0); set_ptr = &set; @@ -3317,7 +3431,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigprocmask(how, set_ptr, &oldset)); if (!is_error(ret) && arg3) { - p = lock_user(arg3, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_sigset(p, &oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } @@ -3329,7 +3444,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - p = lock_user(arg1, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_old_sigset(p, &set); unlock_user(p, arg1, sizeof(target_sigset_t)); } @@ -3341,7 +3457,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sigset_t set; ret = get_errno(sigpending(&set)); if (!is_error(ret)) { - p = lock_user(arg1, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_sigset(p, &set); unlock_user(p, arg1, sizeof(target_sigset_t)); } @@ -3351,7 +3468,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sigsuspend: { sigset_t set; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_old_sigset(&set, p); unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); @@ -3361,7 +3479,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigsuspend: { sigset_t set; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); ret = get_errno(sigsuspend(&set)); @@ -3373,7 +3492,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct timespec uts, *puts; siginfo_t uinfo; - p = lock_user(arg1, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_sigset(&set, p); unlock_user(p, arg1, 0); if (arg3) { @@ -3384,7 +3504,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } ret = get_errno(sigtimedwait(&set, &uinfo, puts)); if (!is_error(ret) && arg2) { - p = lock_user(arg2, sizeof(target_sigset_t), 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_sigset_t), 0))) + goto efault; host_to_target_siginfo(p, &uinfo); unlock_user(p, arg2, sizeof(target_sigset_t)); } @@ -3393,7 +3514,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_rt_sigqueueinfo: { siginfo_t uinfo; - p = lock_user(arg3, sizeof(target_sigset_t), 1); + if (!(p = lock_user(VERIFY_READ, arg3, sizeof(target_sigset_t), 1))) + goto efault; target_to_host_siginfo(&uinfo, p); unlock_user(p, arg1, 0); ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); @@ -3410,7 +3532,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_rt_sigreturn(cpu_env); break; case TARGET_NR_sethostname: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(sethostname(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3420,7 +3543,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int resource = arg1; struct target_rlimit *target_rlim; struct rlimit rlim; - lock_user_struct(target_rlim, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1)) + goto efault; rlim.rlim_cur = tswapl(target_rlim->rlim_cur); rlim.rlim_max = tswapl(target_rlim->rlim_max); unlock_user_struct(target_rlim, arg2, 0); @@ -3436,7 +3560,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(getrlimit(resource, &rlim)); if (!is_error(ret)) { - lock_user_struct(target_rlim, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) + goto efault; rlim.rlim_cur = tswapl(target_rlim->rlim_cur); rlim.rlim_max = tswapl(target_rlim->rlim_max); unlock_user_struct(target_rlim, arg2, 1); @@ -3475,7 +3600,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_ulong inp, outp, exp, tvp; long nsel; - lock_user_struct(sel, arg1, 1); + if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) + goto efault; nsel = tswapl(sel->n); inp = tswapl(sel->inp); outp = tswapl(sel->outp); @@ -3491,31 +3617,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg2); - ret = get_errno(symlink(p, p2)); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(symlink(p, p2)); unlock_user(p2, arg2, 0); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat) case TARGET_NR_symlinkat: - if (!arg1 || !arg3) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg1); p2 = lock_user_string(arg3); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_symlinkat(p, arg2, p2)); - if (p2) - unlock_user(p2, arg3, 0); - if (p) - unlock_user(p, arg1, 0); + unlock_user(p2, arg3, 0); + unlock_user(p, arg1, 0); } break; #endif @@ -3527,32 +3648,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { void *p2; p = lock_user_string(arg1); - p2 = lock_user(arg2, arg3, 0); - ret = get_errno(readlink(path(p), p2, arg3)); + p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!p || !p2) + ret = -TARGET_EFAULT; + else + ret = get_errno(readlink(path(p), p2, arg3)); unlock_user(p2, arg2, ret); unlock_user(p, arg1, 0); } break; #if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat) case TARGET_NR_readlinkat: - if (!arg2 || !arg3) { - ret = -TARGET_EFAULT; - goto fail; - } { - void *p2 = NULL; + void *p2; p = lock_user_string(arg2); - p2 = lock_user(arg3, arg4, 0); - if (!access_ok(VERIFY_READ, p, 1) - || !access_ok(VERIFY_READ, p2, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); + if (!p || !p2) ret = -TARGET_EFAULT; else ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4)); - if (p2) - unlock_user(p2, arg3, ret); - if (p) - unlock_user(p, arg2, 0); + unlock_user(p2, arg3, ret); + unlock_user(p, arg2, 0); } break; #endif @@ -3562,7 +3678,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_swapon case TARGET_NR_swapon: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(swapon(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3579,7 +3696,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { abi_ulong *v; abi_ulong v1, v2, v3, v4, v5, v6; - v = lock_user(arg1, 6 * sizeof(abi_ulong), 1); + if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1))) + goto efault; v1 = tswapl(v[0]); v2 = tswapl(v[1]); v3 = tswapl(v[2]); @@ -3650,7 +3768,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_truncate: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(truncate(p, arg2)); unlock_user(p, arg1, 0); break; @@ -3662,18 +3781,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat) case TARGET_NR_fchmodat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); break; #endif case TARGET_NR_getpriority: @@ -3690,25 +3801,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif case TARGET_NR_statfs: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(statfs(path(p), &stfs)); unlock_user(p, arg1, 0); convert_statfs: if (!is_error(ret)) { struct target_statfs *target_stfs; - lock_user_struct(target_stfs, arg2, 0); - /* ??? put_user is probably wrong. */ - put_user(stfs.f_type, &target_stfs->f_type); - put_user(stfs.f_bsize, &target_stfs->f_bsize); - put_user(stfs.f_blocks, &target_stfs->f_blocks); - put_user(stfs.f_bfree, &target_stfs->f_bfree); - put_user(stfs.f_bavail, &target_stfs->f_bavail); - put_user(stfs.f_files, &target_stfs->f_files); - put_user(stfs.f_ffree, &target_stfs->f_ffree); - put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); - put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); - put_user(stfs.f_namelen, &target_stfs->f_namelen); + if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0)) + goto efault; + __put_user(stfs.f_type, &target_stfs->f_type); + __put_user(stfs.f_bsize, &target_stfs->f_bsize); + __put_user(stfs.f_blocks, &target_stfs->f_blocks); + __put_user(stfs.f_bfree, &target_stfs->f_bfree); + __put_user(stfs.f_bavail, &target_stfs->f_bavail); + __put_user(stfs.f_files, &target_stfs->f_files); + __put_user(stfs.f_ffree, &target_stfs->f_ffree); + __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); + __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); + __put_user(stfs.f_namelen, &target_stfs->f_namelen); unlock_user_struct(target_stfs, arg2, 1); } break; @@ -3717,26 +3829,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto convert_statfs; #ifdef TARGET_NR_statfs64 case TARGET_NR_statfs64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(statfs(path(p), &stfs)); unlock_user(p, arg1, 0); convert_statfs64: if (!is_error(ret)) { struct target_statfs64 *target_stfs; - lock_user_struct(target_stfs, arg3, 0); - /* ??? put_user is probably wrong. */ - put_user(stfs.f_type, &target_stfs->f_type); - put_user(stfs.f_bsize, &target_stfs->f_bsize); - put_user(stfs.f_blocks, &target_stfs->f_blocks); - put_user(stfs.f_bfree, &target_stfs->f_bfree); - put_user(stfs.f_bavail, &target_stfs->f_bavail); - put_user(stfs.f_files, &target_stfs->f_files); - put_user(stfs.f_ffree, &target_stfs->f_ffree); - put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); - put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); - put_user(stfs.f_namelen, &target_stfs->f_namelen); - unlock_user_struct(target_stfs, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0)) + goto efault; + __put_user(stfs.f_type, &target_stfs->f_type); + __put_user(stfs.f_bsize, &target_stfs->f_bsize); + __put_user(stfs.f_blocks, &target_stfs->f_blocks); + __put_user(stfs.f_bfree, &target_stfs->f_bfree); + __put_user(stfs.f_bavail, &target_stfs->f_bavail); + __put_user(stfs.f_files, &target_stfs->f_files); + __put_user(stfs.f_ffree, &target_stfs->f_ffree); + __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); + __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); + __put_user(stfs.f_namelen, &target_stfs->f_namelen); + unlock_user_struct(target_stfs, arg3, 1); } break; case TARGET_NR_fstatfs64: @@ -3839,7 +3952,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif case TARGET_NR_syslog: - p = lock_user_string(arg2); + if (!(p = lock_user_string(arg2))) + goto efault; ret = get_errno(sys_syslog((int)arg1, p, (int)arg3)); unlock_user(p, arg2, 0); break; @@ -3880,12 +3994,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; case TARGET_NR_stat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(stat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat; case TARGET_NR_lstat: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lstat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat; @@ -3896,7 +4012,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { struct target_stat *target_st; - lock_user_struct(target_st, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; #if defined(TARGET_MIPS) || (defined(TARGET_SPARC64) && !defined(TARGET_ABI32)) target_st->st_dev = tswap32(st.st_dev); #else @@ -3979,7 +4096,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_NR_swapoff case TARGET_NR_swapoff: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(swapoff(p)); unlock_user(p, arg1, 0); break; @@ -3991,8 +4109,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(sysinfo(&value)); if (!is_error(ret) && arg1) { - /* ??? __put_user is probably wrong. */ - lock_user_struct(target_value, arg1, 0); + if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0)) + goto efault; __put_user(value.uptime, &target_value->uptime); __put_user(value.loads[0], &target_value->loads[0]); __put_user(value.loads[1], &target_value->loads[1]); @@ -4030,7 +4148,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_setdomainname: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(setdomainname(p, arg2)); unlock_user(p, arg1, 0); break; @@ -4039,7 +4158,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct new_utsname * buf; - lock_user_struct(buf, arg1, 0); + if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0)) + goto efault; ret = get_errno(sys_uname(buf)); if (!is_error(ret)) { /* Overrite the native machine name with whatever is being @@ -4124,7 +4244,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, dirp = malloc(count); if (!dirp) { - ret = -TARGET_EFAULT; + ret = -TARGET_ENOMEM; goto fail; } @@ -4138,7 +4258,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, count1 = 0; de = dirp; - target_dirp = lock_user(arg2, count, 0); + if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; tde = target_dirp; while (len > 0) { reclen = de->d_reclen; @@ -4157,8 +4278,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, count1 += treclen; } ret = count1; + unlock_user(target_dirp, arg2, ret); } - unlock_user(target_dirp, arg2, ret); free(dirp); } #else @@ -4166,7 +4287,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct dirent *dirp; abi_long count = arg3; - dirp = lock_user(arg2, count, 0); + if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; ret = get_errno(sys_getdents(arg1, dirp, count)); if (!is_error(ret)) { struct dirent *de; @@ -4193,7 +4315,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct dirent64 *dirp; abi_long count = arg3; - dirp = lock_user(arg2, count, 0); + if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) + goto efault; ret = get_errno(sys_getdents64(arg1, dirp, count)); if (!is_error(ret)) { struct dirent64 *de; @@ -4229,7 +4352,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct pollfd *pfd; unsigned int i; - target_pfd = lock_user(arg1, sizeof(struct target_pollfd) * nfds, 1); + target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1); + if (!target_pfd) + goto efault; pfd = alloca(sizeof(struct pollfd) * nfds); for(i = 0; i < nfds; i++) { pfd[i].fd = tswap32(target_pfd[i].fd); @@ -4258,7 +4383,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); - lock_iovec(vec, arg2, count, 0); + lock_iovec(VERIFY_WRITE, vec, arg2, count, 0); ret = get_errno(readv(arg1, vec, count)); unlock_iovec(vec, arg2, count, 1); } @@ -4269,7 +4394,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct iovec *vec; vec = alloca(count * sizeof(struct iovec)); - lock_iovec(vec, arg2, count, 1); + lock_iovec(VERIFY_READ, vec, arg2, count, 1); ret = get_errno(writev(arg1, vec, count)); unlock_iovec(vec, arg2, count, 0); } @@ -4292,7 +4417,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct sched_param *target_schp; struct sched_param schp; - lock_user_struct(target_schp, arg2, 1); + if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1)) + goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); unlock_user_struct(target_schp, arg2, 0); ret = get_errno(sched_setparam(arg1, &schp)); @@ -4304,7 +4430,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct sched_param schp; ret = get_errno(sched_getparam(arg1, &schp)); if (!is_error(ret)) { - lock_user_struct(target_schp, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0)) + goto efault; target_schp->sched_priority = tswap32(schp.sched_priority); unlock_user_struct(target_schp, arg2, 1); } @@ -4314,7 +4441,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct sched_param *target_schp; struct sched_param schp; - lock_user_struct(target_schp, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1)) + goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); unlock_user_struct(target_schp, arg3, 0); ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); @@ -4378,18 +4506,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_pread case TARGET_NR_pread: page_unprotect_range(arg2, arg3); - p = lock_user(arg2, arg3, 0); + if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) + goto efault; ret = get_errno(pread(arg1, p, arg3, arg4)); unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite: - p = lock_user(arg2, arg3, 1); + if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) + goto efault; ret = get_errno(pwrite(arg1, p, arg3, arg4)); unlock_user(p, arg2, 0); break; #endif case TARGET_NR_getcwd: - p = lock_user(arg1, arg2, 0); + if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0))) + goto efault; ret = get_errno(sys_getcwd1(p, arg2)); unlock_user(p, arg1, ret); break; @@ -4400,9 +4531,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_sigaltstack: #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \ defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) - ret = do_sigaltstack((struct target_sigaltstack *)arg1, - (struct target_sigaltstack *)arg2, - get_sp_from_cpustate((CPUState *)cpu_env)); + ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUState *)cpu_env)); break; #else goto unimplemented; @@ -4429,7 +4558,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(getrlimit(arg1, &rlim)); if (!is_error(ret)) { struct target_rlimit *target_rlim; - lock_user_struct(target_rlim, arg2, 0); + if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0)) + goto efault; target_rlim->rlim_cur = tswapl(rlim.rlim_cur); target_rlim->rlim_max = tswapl(rlim.rlim_max); unlock_user_struct(target_rlim, arg2, 1); @@ -4439,7 +4569,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_truncate64 case TARGET_NR_truncate64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = target_truncate64(cpu_env, p, arg2, arg3, arg4); unlock_user(p, arg1, 0); break; @@ -4451,14 +4582,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_stat64 case TARGET_NR_stat64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(stat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat64; #endif #ifdef TARGET_NR_lstat64 case TARGET_NR_lstat64: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lstat(path(p), &st)); unlock_user(p, arg1, 0); goto do_stat64; @@ -4472,52 +4605,53 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { struct target_eabi_stat64 *target_st; - lock_user_struct(target_st, arg2, 1); + + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; memset(target_st, 0, sizeof(struct target_eabi_stat64)); - /* put_user is probably wrong. */ - put_user(st.st_dev, &target_st->st_dev); - put_user(st.st_ino, &target_st->st_ino); + __put_user(st.st_dev, &target_st->st_dev); + __put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - put_user(st.st_ino, &target_st->__st_ino); -#endif - put_user(st.st_mode, &target_st->st_mode); - put_user(st.st_nlink, &target_st->st_nlink); - put_user(st.st_uid, &target_st->st_uid); - put_user(st.st_gid, &target_st->st_gid); - put_user(st.st_rdev, &target_st->st_rdev); - /* XXX: better use of kernel struct */ - put_user(st.st_size, &target_st->st_size); - put_user(st.st_blksize, &target_st->st_blksize); - put_user(st.st_blocks, &target_st->st_blocks); - put_user(st.st_atime, &target_st->target_st_atime); - put_user(st.st_mtime, &target_st->target_st_mtime); - put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 0); + __put_user(st.st_ino, &target_st->__st_ino); +#endif + __put_user(st.st_mode, &target_st->st_mode); + __put_user(st.st_nlink, &target_st->st_nlink); + __put_user(st.st_uid, &target_st->st_uid); + __put_user(st.st_gid, &target_st->st_gid); + __put_user(st.st_rdev, &target_st->st_rdev); + __put_user(st.st_size, &target_st->st_size); + __put_user(st.st_blksize, &target_st->st_blksize); + __put_user(st.st_blocks, &target_st->st_blocks); + __put_user(st.st_atime, &target_st->target_st_atime); + __put_user(st.st_mtime, &target_st->target_st_mtime); + __put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 1); } else #endif { struct target_stat64 *target_st; - lock_user_struct(target_st, arg2, 1); + + if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) + goto efault; memset(target_st, 0, sizeof(struct target_stat64)); - /* ??? put_user is probably wrong. */ - put_user(st.st_dev, &target_st->st_dev); - put_user(st.st_ino, &target_st->st_ino); + __put_user(st.st_dev, &target_st->st_dev); + __put_user(st.st_ino, &target_st->st_ino); #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO - put_user(st.st_ino, &target_st->__st_ino); + __put_user(st.st_ino, &target_st->__st_ino); #endif - put_user(st.st_mode, &target_st->st_mode); - put_user(st.st_nlink, &target_st->st_nlink); - put_user(st.st_uid, &target_st->st_uid); - put_user(st.st_gid, &target_st->st_gid); - put_user(st.st_rdev, &target_st->st_rdev); + __put_user(st.st_mode, &target_st->st_mode); + __put_user(st.st_nlink, &target_st->st_nlink); + __put_user(st.st_uid, &target_st->st_uid); + __put_user(st.st_gid, &target_st->st_gid); + __put_user(st.st_rdev, &target_st->st_rdev); /* XXX: better use of kernel struct */ - put_user(st.st_size, &target_st->st_size); - put_user(st.st_blksize, &target_st->st_blksize); - put_user(st.st_blocks, &target_st->st_blocks); - put_user(st.st_atime, &target_st->target_st_atime); - put_user(st.st_mtime, &target_st->target_st_mtime); - put_user(st.st_ctime, &target_st->target_st_ctime); - unlock_user_struct(target_st, arg2, 0); + __put_user(st.st_size, &target_st->st_size); + __put_user(st.st_blksize, &target_st->st_blksize); + __put_user(st.st_blocks, &target_st->st_blocks); + __put_user(st.st_atime, &target_st->target_st_atime); + __put_user(st.st_mtime, &target_st->target_st_mtime); + __put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 1); } } } @@ -4525,7 +4659,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef USE_UID16 case TARGET_NR_lchown: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3))); unlock_user(p, arg1, 0); break; @@ -4557,7 +4692,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); if (!is_error(ret)) { - target_grouplist = lock_user(arg2, gidsetsize * 2, 0); + target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 2, 0); + if (!target_grouplist) + goto efault; for(i = 0;i < gidsetsize; i++) target_grouplist[i] = tswap16(grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 2); @@ -4572,7 +4709,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); - target_grouplist = lock_user(arg2, gidsetsize * 2, 1); + target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) grouplist[i] = tswap16(target_grouplist[i]); unlock_user(target_grouplist, arg2, 0); @@ -4584,18 +4725,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) case TARGET_NR_fchownat: - if (!arg2) { - ret = -TARGET_EFAULT; - goto fail; - } - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ - ret = -TARGET_EFAULT; - else - ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); - if (p) - unlock_user(p, arg2, 0); + if (!(p = lock_user_string(arg2))) + goto efault; + ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); + unlock_user(p, arg2, 0); break; #endif #ifdef TARGET_NR_setresuid @@ -4639,7 +4772,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_chown: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3))); unlock_user(p, arg1, 0); break; @@ -4659,7 +4793,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_lchown32 case TARGET_NR_lchown32: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(lchown(p, arg2, arg3)); unlock_user(p, arg1, 0); break; @@ -4705,7 +4840,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, grouplist = alloca(gidsetsize * sizeof(gid_t)); ret = get_errno(getgroups(gidsetsize, grouplist)); if (!is_error(ret)) { - target_grouplist = lock_user(arg2, gidsetsize * 4, 0); + target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) target_grouplist[i] = tswap32(grouplist[i]); unlock_user(target_grouplist, arg2, gidsetsize * 4); @@ -4722,7 +4861,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int i; grouplist = alloca(gidsetsize * sizeof(gid_t)); - target_grouplist = lock_user(arg2, gidsetsize * 4, 1); + target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } for(i = 0;i < gidsetsize; i++) grouplist[i] = tswap32(target_grouplist[i]); unlock_user(target_grouplist, arg2, 0); @@ -4773,7 +4916,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_chown32 case TARGET_NR_chown32: - p = lock_user_string(arg1); + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(chown(p, arg2, arg3)); unlock_user(p, arg1, 0); break; @@ -4843,7 +4987,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_GETLK64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); @@ -4853,7 +5000,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); @@ -4865,7 +5015,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (ret == 0) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) { + ret = -TARGET_EFAULT; + goto fail; + } target_efl->l_type = tswap16(fl.l_type); target_efl->l_whence = tswap16(fl.l_whence); target_efl->l_start = tswap64(fl.l_start); @@ -4875,7 +5028,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 0); + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) { + ret = -TARGET_EFAULT; + goto fail; + } target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswap64(fl.l_start); @@ -4890,7 +5046,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_SETLKW64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - lock_user_struct(target_efl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); @@ -4900,7 +5059,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - lock_user_struct(target_fl, arg3, 1); + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + ret = -TARGET_EFAULT; + goto fail; + } fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); @@ -4998,8 +5160,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address) case TARGET_NR_set_tid_address: - ret = get_errno(set_tid_address((int *) arg1)); - break; + ret = get_errno(set_tid_address((int *)g2h(arg1))); + break; #endif #if defined(TARGET_NR_tkill) && defined(__NR_tkill) @@ -5028,14 +5190,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!arg2) ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4)); else { - p = lock_user_string(arg2); - if (!access_ok(VERIFY_READ, p, 1)) - /* Don't "goto fail" so that cleanup can happen. */ + if (!(p = lock_user_string(arg2))) { ret = -TARGET_EFAULT; - else - ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); - if (p) - unlock_user(p, arg2, 0); + goto fail; + } + ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); + unlock_user(p, arg2, 0); } } break; @@ -5050,11 +5210,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = -TARGET_ENOSYS; break; } - fail: +fail: #ifdef DEBUG gemu_log(" = %ld\n", ret); #endif if(do_strace) print_syscall_ret(num, ret); return ret; +efault: + ret = -TARGET_EFAULT; + goto fail; } diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c new file mode 100644 index 000000000..3f838180c --- /dev/null +++ b/linux-user/uaccess.c @@ -0,0 +1,51 @@ +/* User memory access */ +#include +#include + +#include "qemu.h" + +/* copy_from_user() and copy_to_user() are usually used to copy data + * buffers between the target and host. These internally perform + * locking/unlocking of the memory. + */ +abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len) +{ + abi_long ret = 0; + void *ghptr; + + if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) { + memcpy(hptr, ghptr, len); + unlock_user(ghptr, gaddr, 0); + } else + ret = -TARGET_EFAULT; + + return ret; +} + + +abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len) +{ + abi_long ret = 0; + void *ghptr; + + if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) { + memcpy(ghptr, hptr, len); + unlock_user(ghptr, gaddr, len); + } else + ret = -TARGET_EFAULT; + + return ret; +} + + +/* Return the length of a string in target memory. */ +/* FIXME - this doesn't check access_ok() - it's rather complicated to + * do it correctly because we need to check the bytes in a page and then + * skip to the next page and check the bytes there until we find the + * terminator. There should be a general function to do this that + * can look for any byte terminator in a buffer - not strlen(). + */ +abi_long target_strlen(abi_ulong gaddr) +{ + return strlen(g2h(gaddr)); +} diff --git a/linux-user/vm86.c b/linux-user/vm86.c index a3c92e1cc..cb5ff9d75 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -64,7 +64,9 @@ void save_v86_state(CPUX86State *env) TaskState *ts = env->opaque; struct target_vm86plus_struct * target_v86; - lock_user_struct(target_v86, ts->target_v86, 0); + if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0)) + /* FIXME - should return an error */ + return; /* put the VM86 registers in the userspace register structure */ target_v86->regs.eax = tswap32(env->regs[R_EAX]); target_v86->regs.ebx = tswap32(env->regs[R_EBX]); @@ -424,7 +426,8 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr) ts->vm86_saved_regs.gs = env->segs[R_GS].selector; ts->target_v86 = vm86_addr; - lock_user_struct(target_v86, vm86_addr, 1); + if (!lock_user_struct(VERIFY_READ, target_v86, vm86_addr, 1)) + return -EFAULT; /* build vm86 CPU state */ ts->v86flags = tswap32(target_v86->regs.eflags); env->eflags = (env->eflags & ~SAFE_MASK) | diff --git a/m68k-semi.c b/m68k-semi.c index fc033a163..b0e526933 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -107,7 +107,9 @@ static void translate_stat(CPUState *env, target_ulong addr, struct stat *s) { struct m68k_gdb_stat *p; - p = lock_user(addr, sizeof(struct m68k_gdb_stat), 0); + if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct m68k_gdb_stat), 0))) + /* FIXME - should this return an error code? */ + return; p->gdb_st_dev = cpu_to_be32(s->st_dev); p->gdb_st_ino = cpu_to_be32(s->st_ino); p->gdb_st_mode = cpu_to_be32(s->st_mode); @@ -168,9 +170,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(2), ARG(3)); return; } else { - p = lock_user_string(ARG(0)); - result = open(p, translate_openflags(ARG(2)), ARG(3)); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user_string(ARG(0)))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = open(p, translate_openflags(ARG(2)), ARG(3)); + unlock_user(p, ARG(0), 0); + } } break; case HOSTED_CLOSE: @@ -196,9 +202,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), ARG(1), len); return; } else { - p = lock_user(ARG(1), len, 0); - result = read(ARG(0), p, len); - unlock_user(p, ARG(1), len); + if (!(p = lock_user(VERIFY_WRITE, ARG(1), len, 0))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = read(ARG(0), p, len); + unlock_user(p, ARG(1), len); + } } break; case HOSTED_WRITE: @@ -208,9 +218,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), ARG(1), len); return; } else { - p = lock_user(ARG(1), len, 1); - result = write(ARG(0), p, len); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user(VERIFY_READ, ARG(1), len, 1))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = write(ARG(0), p, len); + unlock_user(p, ARG(0), 0); + } } break; case HOSTED_LSEEK: @@ -237,7 +251,12 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) } else { p = lock_user_string(ARG(0)); q = lock_user_string(ARG(2)); - result = rename(p, q); + if (!p || !q) { + /* FIXME - check error code? */ + result = -1; + } else { + result = rename(p, q); + } unlock_user(p, ARG(0), 0); unlock_user(q, ARG(2), 0); } @@ -248,9 +267,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), (int)ARG(1)); return; } else { - p = lock_user_string(ARG(0)); - result = unlink(p); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user_string(ARG(0)))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = unlink(p); + unlock_user(p, ARG(0), 0); + } } break; case HOSTED_STAT: @@ -260,9 +283,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) return; } else { struct stat s; - p = lock_user_string(ARG(0)); - result = stat(p, &s); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user_string(ARG(0)))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = stat(p, &s); + unlock_user(p, ARG(0), 0); + } if (result == 0) { translate_stat(env, ARG(2), &s); } @@ -291,10 +318,15 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) struct gdb_timeval *p; result = qemu_gettimeofday(&tv); if (result != 0) { - p = lock_user(ARG(0), sizeof(struct gdb_timeval), 0); - p->tv_sec = cpu_to_be32(tv.tv_sec); - p->tv_usec = cpu_to_be64(tv.tv_usec); - unlock_user(p, ARG(0), sizeof(struct gdb_timeval)); + if (!(p = lock_user(VERIFY_WRITE, + ARG(0), sizeof(struct gdb_timeval), 0))) { + /* FIXME - check error code? */ + result = -1; + } else { + p->tv_sec = cpu_to_be32(tv.tv_sec); + p->tv_usec = cpu_to_be64(tv.tv_usec); + unlock_user(p, ARG(0), sizeof(struct gdb_timeval)); + } } } break; @@ -312,9 +344,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), (int)ARG(1)); return; } else { - p = lock_user_string(ARG(0)); - result = system(p); - unlock_user(p, ARG(0), 0); + if (!(p = lock_user_string(ARG(0)))) { + /* FIXME - check error code? */ + result = -1; + } else { + result = system(p); + unlock_user(p, ARG(0), 0); + } } break; case HOSTED_INIT_SIM: diff --git a/softmmu-semi.h b/softmmu-semi.h index 13c528bb8..527943a76 100644 --- a/softmmu-semi.h +++ b/softmmu-semi.h @@ -41,7 +41,7 @@ static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len, cpu_memory_rw_debug(env, addr, p, len, 0); return p; } -#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy) +#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy) static char *softmmu_lock_user_string(CPUState *env, uint32_t addr) { char *p; -- cgit v1.2.3 From e160c51ccd14a9df2628a3b31d06fd26333d6f99 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Nov 2007 14:36:36 +0000 Subject: Fix msr_mask. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3584 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 9366bf146..513b17987 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2478,7 +2478,6 @@ static inline void gen_mulxy(int x, int y) /* Return the mask of PSR bits set by a MSR instruction. */ static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) { uint32_t mask; - uint32_t reserved; mask = 0; if (flags & (1 << 0)) @@ -2493,12 +2492,12 @@ static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) { /* Mask out undefined bits. */ mask &= ~CPSR_RESERVED; if (!arm_feature(env, ARM_FEATURE_V6)) - reserved &= ~(CPSR_E | CPSR_GE); + mask &= ~(CPSR_E | CPSR_GE); if (!arm_feature(env, ARM_FEATURE_THUMB2)) - reserved &= ~CPSR_IT; + mask &= ~CPSR_IT; /* Mask out execution state bits. */ if (!spsr) - reserved &= ~CPSR_EXEC; + mask &= ~CPSR_EXEC; /* Mask out privileged bits. */ if (IS_USER(s)) mask &= CPSR_USER; -- cgit v1.2.3 From be98f1f82290118e176b704fd270f552c3d6a35a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 14:43:13 +0000 Subject: compilation fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3585 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/test-i386.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tests/test-i386.c b/tests/test-i386.c index 2d4b0a0df..1cc34e3dc 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -703,8 +703,8 @@ union float64u { uint64_t l; }; -union float64u q_nan = { .l = 0xFFF8000000000000 }; -union float64u s_nan = { .l = 0xFFF0000000000000 }; +union float64u q_nan = { .l = 0xFFF8000000000000LL }; +union float64u s_nan = { .l = 0xFFF0000000000000LL }; void test_fops(double a, double b) { @@ -819,7 +819,9 @@ void test_fcvt(double a) /* test all roundings */ asm volatile ("fstcw %0" : "=m" (fpuc)); for(i=0;i<4;i++) { - asm volatile ("fldcw %0" : : "m" ((fpuc & ~0x0c00) | (i << 10))); + uint16_t val16; + val16 = (fpuc & ~0x0c00) | (i << 10); + asm volatile ("fldcw %0" : : "m" (val16)); asm volatile ("fist %0" : "=m" (wa) : "t" (a)); asm volatile ("fistl %0" : "=m" (ia) : "t" (a)); asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st"); @@ -976,8 +978,8 @@ void test_floats(void) test_fcvt(1.0/0.0); test_fcvt(q_nan.d); test_fconst(); - test_fbcd(1234567890123456); - test_fbcd(-123451234567890); + test_fbcd(1234567890123456.0); + test_fbcd(-123451234567890.0); test_fenv(); if (TEST_CMOV) { test_fcmov(); @@ -1151,12 +1153,12 @@ void test_xchg(void) long i, eflags; for(i = 0; i < 2; i++) { - op0 = 0x123456789abcd; + op0 = 0x123456789abcdLL; if (i == 0) - op1 = 0xfbca765423456; + op1 = 0xfbca765423456LL; else op1 = op0; - op2 = 0x6532432432434; + op2 = 0x6532432432434LL; asm("cmpxchg8b %1\n" "pushf\n" "pop %2\n" @@ -1172,11 +1174,15 @@ void test_xchg(void) /**********************************************/ /* segmentation tests */ +#include +#include #include -#include #include -_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) +static inline int modify_ldt(int func, void * ptr, unsigned long bytecount) +{ + return syscall(__NR_modify_ldt, func, ptr, bytecount); +} #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) #define modify_ldt_ldt_s user_desc @@ -1505,13 +1511,10 @@ static inline void pushw(struct vm86_regs *r, int val) *(uint16_t *)seg_to_linear(r->ss, r->esp) = val; } -#undef __syscall_return -#define __syscall_return(type, res) \ -do { \ - return (type) (res); \ -} while (0) - -_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86) +static inline int vm86(int func, struct vm86plus_struct *v86) +{ + return syscall(__NR_vm86, func, v86); +} extern char vm86_code_start; extern char vm86_code_end; -- cgit v1.2.3 From 0d913fdb62765554d613e2fe99b7812ed1c95122 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 11 Nov 2007 14:44:28 +0000 Subject: Fix PowerPC boot device selection. Fix gcc warning in PowerPC PreP machine init routine. Add second IDE channel to Heathrow Mac machine (still not handled by OHW). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3586 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_chrp.c | 7 ++++--- hw/ppc_oldworld.c | 22 +++++++++++++++------- hw/ppc_prep.c | 9 +++++---- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index a2d07c8fe..8fb8e5d20 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -179,10 +179,11 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, /* We consider that NewWorld PowerMac never have any floppy drive * For now, OHW cannot boot from the network. */ - for (i = 0; i < boot_device[i] != '\0'; i++) { - ppc_boot_device = boot_device[i]; - if (ppc_boot_device >= 'c' && ppc_boot_device <= 'f') + for (i = 0; boot_device[i] != '\0'; i++) { + if (boot_device[i] >= 'c' && boot_device[i] <= 'f') { + ppc_boot_device = boot_device[i]; break; + } } if (ppc_boot_device == '\0') { fprintf(stderr, "No valid boot device for Mac99 machine\n"); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index b6ce58bc0..ef638767f 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -113,6 +113,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int vga_bios_size, bios_size; qemu_irq *dummy_irq; int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index; + int ide_mem_index[2]; int ppc_boot_device; linux_boot = (kernel_filename != NULL); @@ -213,18 +214,21 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, initrd_base = 0; initrd_size = 0; ppc_boot_device = '\0'; - for (i = 0; i < boot_device[i] != '\0'; i++) { - ppc_boot_device = boot_device[i]; + for (i = 0; boot_device[i] != '\0'; i++) { /* TOFIX: for now, the second IDE channel is not properly - * emulated. The Mac floppy disk are not emulated. + * used by OHW. The Mac floppy disk are not emulated. * For now, OHW cannot boot from the network. */ #if 0 - if (ppc_boot_device >= 'a' && ppc_boot_device <= 'f') + if (boot_device[i] >= 'a' && boot_device[i] <= 'f') { + ppc_boot_device = boot_device[i]; break; + } #else - if (ppc_boot_device >= 'c' && ppc_boot_device <= 'd') + if (boot_device[i] >= 'c' && boot_device[i] <= 'd') { + ppc_boot_device = boot_device[i]; break; + } #endif } if (ppc_boot_device == '\0') { @@ -278,8 +282,12 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, nd_table[i].model = "ne2k_pci"; pci_nic_init(pci_bus, &nd_table[i], -1); } - + + /* First IDE channel is a CMD646 on the PCI bus */ pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); + /* Second IDE channel is a MAC IDE on the MacIO bus */ + ide_mem_index[0] = -1; + ide_mem_index[1] = pmac_ide_init(&bs_table[2], pic[0x0D]); /* cuda also initialize ADB */ cuda_init(&cuda_mem_index, pic[0x12]); @@ -293,7 +301,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, dbdma_init(&dbdma_mem_index); macio_init(pci_bus, 0x0017, 1, pic_mem_index, dbdma_mem_index, - cuda_mem_index, nvr, 0, NULL); + cuda_mem_index, nvr, 2, ide_mem_index); if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 60b695623..1d2a85da1 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -529,7 +529,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, const char *initrd_filename, const char *cpu_model) { - CPUState *env, *envs[MAX_CPUS]; + CPUState *env = NULL, *envs[MAX_CPUS]; char buf[1024]; nvram_t nvram; m48t59_t *m48t59; @@ -614,10 +614,11 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, initrd_size = 0; ppc_boot_device = '\0'; /* For now, OHW cannot boot from the network. */ - for (i = 0; i < boot_device[i] != '\0'; i++) { - ppc_boot_device = boot_device[i]; - if (ppc_boot_device >= 'a' && ppc_boot_device <= 'f') + for (i = 0; boot_device[i] != '\0'; i++) { + if (boot_device[i] >= 'a' && boot_device[i] <= 'f') { + ppc_boot_device = boot_device[i]; break; + } } if (ppc_boot_device == '\0') { fprintf(stderr, "No valid boot device for Mac99 machine\n"); -- cgit v1.2.3 From b67419569b6a13811670d97c0bd88f9bef4ca9c7 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 14:46:06 +0000 Subject: -strace option git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3587 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 18e509d08..4b53b908f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1856,7 +1856,8 @@ void usage(void) "\n" "debug options:\n" "-d options activate log (logfile=%s)\n" - "-p pagesize set the host page size to 'pagesize'\n", + "-p pagesize set the host page size to 'pagesize'\n" + "-strace log system calls\n", TARGET_ARCH, interp_prefix, x86_stack_size, @@ -1952,6 +1953,8 @@ int main(int argc, char **argv) } } else if (!strcmp(r, "drop-ld-preload")) { drop_ld_preload = 1; + } else if (!strcmp(r, "strace")) { + do_strace = 1; } else { usage(); @@ -2008,8 +2011,8 @@ int main(int argc, char **argv) } global_env = env; - if(getenv("QEMU_STRACE") ){ - do_strace=1; + if (getenv("QEMU_STRACE")) { + do_strace = 1; } wrk = environ; -- cgit v1.2.3 From 6c30b07fcc3f02321f3bb9cd9c14883751b4dc47 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 14:50:32 +0000 Subject: fixed error codes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3588 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/vm86.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index cb5ff9d75..0667b4dd7 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -395,7 +395,7 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr) case TARGET_VM86_GET_IRQ_BITS: case TARGET_VM86_GET_AND_RESET_IRQ: gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction); - ret = -EINVAL; + ret = -TARGET_EINVAL; goto out; case TARGET_VM86_PLUS_INSTALL_CHECK: /* NOTE: on old vm86 stuff this will return the error @@ -427,7 +427,7 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr) ts->target_v86 = vm86_addr; if (!lock_user_struct(VERIFY_READ, target_v86, vm86_addr, 1)) - return -EFAULT; + return -TARGET_EFAULT; /* build vm86 CPU state */ ts->v86flags = tswap32(target_v86->regs.eflags); env->eflags = (env->eflags & ~SAFE_MASK) | -- cgit v1.2.3 From cd04168106cd7e5b6e64481e3c23efbba3ac0f2c Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 11 Nov 2007 14:52:02 +0000 Subject: Fix format mismatch. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3589 c046a42c-6fe2-441c-8c8c-71466251a162 --- gdbstub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gdbstub.c b/gdbstub.c index eb1d75fed..418b9a6fe 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1052,7 +1052,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) TaskState *ts = env->opaque; sprintf(buf, - "Text=" TARGET_FMT_lx ";Data=" TARGET_FMT_lx ";Bss=" TARGET_FMT_lx, + "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx + ";Bss=" TARGET_ABI_FMT_lx, ts->info->code_offset, ts->info->data_offset, ts->info->data_offset); -- cgit v1.2.3 From 03acab6618baac438e0f58dd1e9f5b81b36e95d0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 14:57:14 +0000 Subject: no longer use get_errno for do_modify_ldt() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3590 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 656f78ee4..21078837d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2229,7 +2229,7 @@ static bitmask_transtbl fcntl_flags_tbl[] = { /* NOTE: there is really one LDT for all the threads */ uint8_t *ldt_table; -static int read_ldt(abi_ulong ptr, unsigned long bytecount) +static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount) { int size; void *p; @@ -2241,7 +2241,7 @@ static int read_ldt(abi_ulong ptr, unsigned long bytecount) size = bytecount; p = lock_user(VERIFY_WRITE, ptr, size, 0); if (!p) - return -EFAULT; + return -TARGET_EFAULT; /* ??? Should this by byteswapped? */ memcpy(p, ldt_table, size); unlock_user(p, ptr, size); @@ -2249,9 +2249,8 @@ static int read_ldt(abi_ulong ptr, unsigned long bytecount) } /* XXX: add locking support */ -/* write_ldt() returns host errnos */ -static int write_ldt(CPUX86State *env, - abi_ulong ptr, unsigned long bytecount, int oldmode) +static abi_long write_ldt(CPUX86State *env, + abi_ulong ptr, unsigned long bytecount, int oldmode) { struct target_modify_ldt_ldt_s ldt_info; struct target_modify_ldt_ldt_s *target_ldt_info; @@ -2260,9 +2259,9 @@ static int write_ldt(CPUX86State *env, uint32_t *lp, entry_1, entry_2; if (bytecount != sizeof(ldt_info)) - return -EINVAL; + return -TARGET_EINVAL; if (!lock_user_struct(VERIFY_READ, target_ldt_info, ptr, 1)) - return -EFAULT; + return -TARGET_EFAULT; ldt_info.entry_number = tswap32(target_ldt_info->entry_number); ldt_info.base_addr = tswapl(target_ldt_info->base_addr); ldt_info.limit = tswap32(target_ldt_info->limit); @@ -2270,7 +2269,7 @@ static int write_ldt(CPUX86State *env, unlock_user_struct(target_ldt_info, ptr, 0); if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) - return -EINVAL; + return -TARGET_EINVAL; seg_32bit = ldt_info.flags & 1; contents = (ldt_info.flags >> 1) & 3; read_exec_only = (ldt_info.flags >> 3) & 1; @@ -2280,15 +2279,15 @@ static int write_ldt(CPUX86State *env, if (contents == 3) { if (oldmode) - return -EINVAL; + return -TARGET_EINVAL; if (seg_not_present == 0) - return -EINVAL; + return -TARGET_EINVAL; } /* allocate the LDT */ if (!ldt_table) { ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); if (!ldt_table) - return -ENOMEM; + return -TARGET_ENOMEM; memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); env->ldt.base = h2g(ldt_table); env->ldt.limit = 0xffff; @@ -2333,11 +2332,10 @@ install: } /* specific and weird i386 syscalls */ -/* do_modify_ldt() returns host errnos (it is inconsistent with the - other do_*() functions which return target errnos). */ -int do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, unsigned long bytecount) +abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, + unsigned long bytecount) { - int ret = -ENOSYS; + abi_long ret; switch (func) { case 0: @@ -2349,6 +2347,9 @@ int do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, unsigned long bytec case 0x11: ret = write_ldt(env, ptr, bytecount, 0); break; + default: + ret = -TARGET_ENOSYS; + break; } return ret; } @@ -4174,7 +4175,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_I386 case TARGET_NR_modify_ldt: - ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3)); + ret = do_modify_ldt(cpu_env, arg1, arg2, arg3); break; #if !defined(TARGET_X86_64) case TARGET_NR_vm86old: -- cgit v1.2.3 From 9ee1fa2ca9d925e53f5609b35fe29d719abae980 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 15:11:19 +0000 Subject: move get_errno() inside do_fcntl() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3591 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 60 ++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 21078837d..a7f41cf99 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2478,7 +2478,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fl.l_len = tswapl(target_fl->l_len); fl.l_pid = tswapl(target_fl->l_pid); unlock_user_struct(target_fl, arg, 0); - ret = fcntl(fd, cmd, &fl); + ret = get_errno(fcntl(fd, cmd, &fl)); if (ret == 0) { if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0)) return -TARGET_EFAULT; @@ -2501,7 +2501,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fl.l_len = tswapl(target_fl->l_len); fl.l_pid = tswapl(target_fl->l_pid); unlock_user_struct(target_fl, arg, 0); - ret = fcntl(fd, cmd, &fl); + ret = get_errno(fcntl(fd, cmd, &fl)); break; case TARGET_F_GETLK64: @@ -2513,7 +2513,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fl64.l_len = tswapl(target_fl64->l_len); fl64.l_pid = tswap16(target_fl64->l_pid); unlock_user_struct(target_fl64, arg, 0); - ret = fcntl(fd, cmd >> 1, &fl64); + ret = get_errno(fcntl(fd, cmd >> 1, &fl64)); if (ret == 0) { if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0)) return -TARGET_EFAULT; @@ -2524,7 +2524,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) target_fl64->l_pid = tswapl(fl64.l_pid); unlock_user_struct(target_fl64, arg, 1); } - break; + break; case TARGET_F_SETLK64: case TARGET_F_SETLKW64: if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) @@ -2535,20 +2535,22 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fl64.l_len = tswapl(target_fl64->l_len); fl64.l_pid = tswap16(target_fl64->l_pid); unlock_user_struct(target_fl64, arg, 0); - ret = fcntl(fd, cmd >> 1, &fl64); + ret = get_errno(fcntl(fd, cmd >> 1, &fl64)); break; case F_GETFL: - ret = fcntl(fd, cmd, arg); - ret = host_to_target_bitmask(ret, fcntl_flags_tbl); + ret = get_errno(fcntl(fd, cmd, arg)); + if (ret >= 0) { + ret = host_to_target_bitmask(ret, fcntl_flags_tbl); + } break; case F_SETFL: - ret = fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)); + ret = get_errno(fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl))); break; default: - ret = fcntl(fd, cmd, arg); + ret = get_errno(fcntl(fd, cmd, arg)); break; } return ret; @@ -3209,7 +3211,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_ioctl(arg1, arg2, arg3); break; case TARGET_NR_fcntl: - ret = get_errno(do_fcntl(arg1, arg2, arg3)); + ret = do_fcntl(arg1, arg2, arg3); break; #ifdef TARGET_NR_mpx case TARGET_NR_mpx: @@ -4988,10 +4990,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_GETLK64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) { - ret = -TARGET_EFAULT; - goto fail; - } + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) + goto efault; fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); @@ -5001,10 +5001,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { - ret = -TARGET_EFAULT; - goto fail; - } + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) + goto efault; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); @@ -5016,10 +5014,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (ret == 0) { #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) { - ret = -TARGET_EFAULT; - goto fail; - } + if (!lock_user_struct(VERIFY_WRITE, target_efl, arg3, 0)) + goto efault; target_efl->l_type = tswap16(fl.l_type); target_efl->l_whence = tswap16(fl.l_whence); target_efl->l_start = tswap64(fl.l_start); @@ -5029,10 +5025,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) { - ret = -TARGET_EFAULT; - goto fail; - } + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) + goto efault; target_fl->l_type = tswap16(fl.l_type); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswap64(fl.l_start); @@ -5047,10 +5041,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_F_SETLKW64: #ifdef TARGET_ARM if (((CPUARMState *)cpu_env)->eabi) { - if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) { - ret = -TARGET_EFAULT; - goto fail; - } + if (!lock_user_struct(VERIFY_READ, target_efl, arg3, 1)) + goto efault; fl.l_type = tswap16(target_efl->l_type); fl.l_whence = tswap16(target_efl->l_whence); fl.l_start = tswap64(target_efl->l_start); @@ -5060,10 +5052,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } else #endif { - if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { - ret = -TARGET_EFAULT; - goto fail; - } + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) + goto efault; fl.l_type = tswap16(target_fl->l_type); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswap64(target_fl->l_start); @@ -5074,7 +5064,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(fcntl(arg1, cmd, &fl)); break; default: - ret = get_errno(do_fcntl(arg1, cmd, arg3)); + ret = do_fcntl(arg1, cmd, arg3); break; } break; -- cgit v1.2.3 From eb6a0540767153923297a9f69c5d43d2f7e42977 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 16:05:35 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3592 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slirp/misc.c b/slirp/misc.c index 9ea7dd068..14808fe21 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -327,6 +327,8 @@ fork_exec(struct socket *so, const char *ex, int do_pty) lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } +#else + return 0; #endif } else { addr.sin_family = AF_INET; -- cgit v1.2.3 From 775b58d8cb46050f2d0375cb938c293383e970e8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 16:22:17 +0000 Subject: removed warnings - fixed arm stack copy bug git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3593 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index e9da0971f..8c0e02abc 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -670,6 +670,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, CPUX86State *env, unsigned long mask) { int err = 0; + uint16_t magic; /* already locked in setup_frame() */ err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs); @@ -694,7 +695,8 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, cpu_x86_fsave(env, (void *)fpstate, 1); fpstate->status = fpstate->sw; - err |= __put_user(0xffff, &fpstate->magic); + magic = 0xffff; + err |= __put_user(magic, &fpstate->magic); err |= __put_user(fpstate, &sc->fpstate); /* non-iBCS2 extensions.. */ @@ -766,15 +768,18 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, if (ka->sa.sa_flags & TARGET_SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { + uint16_t val16; err |= __put_user(frame->retcode, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ - err |= __put_user(0xb858, (short *)(frame->retcode+0)); + val16 = 0xb858; + err |= __put_user(val16, (uint16_t *)(frame->retcode+0)); #if defined(TARGET_X86_64) #warning "Fix this !" #else err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); #endif - err |= __put_user(0x80cd, (short *)(frame->retcode+6)); + val16 = 0x80cd; + err |= __put_user(val16, (uint16_t *)(frame->retcode+6)); } if (err) @@ -848,11 +853,14 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, if (ka->sa.sa_flags & TARGET_SA_RESTORER) { err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { + uint16_t val16; + err |= __put_user(frame->retcode, &frame->pretcode); /* This is movl $,%eax ; int $0x80 */ - err |= __put_user(0xb8, (char *)(frame->retcode+0)); + err |= __put_user(0xb8, (char *)(frame->retcode+0)); err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1)); - err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + val16 = 0x80cd; + err |= __put_user(val16, (uint16_t *)(frame->retcode+5)); } if (err) @@ -1234,7 +1242,7 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); - err |= copy_to_user(&frame->uc.tuc_stack, &stack, sizeof(stack)); + memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ env, set->sig[0]); @@ -1585,13 +1593,16 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, if (ka->sa.sa_restorer) env->regwptr[UREG_I7] = (unsigned long)ka->sa.sa_restorer; else { + uint32_t val32; env->regwptr[UREG_I7] = h2g(&(sf->insns[0]) - 2); /* mov __NR_sigreturn, %g1 */ - err |= __put_user(0x821020d8, &sf->insns[0]); + val32 = 0x821020d8; + err |= __put_user(val32, &sf->insns[0]); /* t 0x10 */ - err |= __put_user(0x91d02010, &sf->insns[1]); + val32 = 0x91d02010; + err |= __put_user(val32, &sf->insns[1]); if (err) goto sigsegv; -- cgit v1.2.3 From 0fe5ea89cc108ea0ff5cbc115bd1143196e248ba Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 11 Nov 2007 16:51:04 +0000 Subject: Fix Sun4u compile git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3594 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4u.c | 109 ++++++++++++++++++++++++------------------------------------- 1 file changed, 42 insertions(+), 67 deletions(-) diff --git a/hw/sun4u.c b/hw/sun4u.c index bdc6f9510..9734a963f 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -67,23 +67,23 @@ void DMA_register_channel (int nchan, } /* NVRAM helpers */ -void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) +static void nvram_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) { m48t59_write(nvram, addr, value); } -uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) +static uint8_t nvram_get_byte (m48t59_t *nvram, uint32_t addr) { return m48t59_read(nvram, addr); } -void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) +static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) { - m48t59_write(nvram, addr, value >> 8); - m48t59_write(nvram, addr + 1, value & 0xFF); + m48t59_write(nvram, addr++, (value >> 8) & 0xff); + m48t59_write(nvram, addr++, value & 0xff); } -uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) +static uint16_t nvram_get_word (m48t59_t *nvram, uint32_t addr) { uint16_t tmp; @@ -93,30 +93,18 @@ uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) return tmp; } -void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) +static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) { - m48t59_write(nvram, addr, value >> 24); - m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF); - m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF); - m48t59_write(nvram, addr + 3, value & 0xFF); + m48t59_write(nvram, addr++, value >> 24); + m48t59_write(nvram, addr++, (value >> 16) & 0xff); + m48t59_write(nvram, addr++, (value >> 8) & 0xff); + m48t59_write(nvram, addr++, value & 0xff); } -uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) -{ - uint32_t tmp; - - tmp = m48t59_read(nvram, addr) << 24; - tmp |= m48t59_read(nvram, addr + 1) << 16; - tmp |= m48t59_read(nvram, addr + 2) << 8; - tmp |= m48t59_read(nvram, addr + 3); - - return tmp; -} - -void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, +static void nvram_set_string (m48t59_t *nvram, uint32_t addr, const unsigned char *str, uint32_t max) { - int i; + unsigned int i; for (i = 0; i < max && str[i] != '\0'; i++) { m48t59_write(nvram, addr + i, str[i]); @@ -124,21 +112,7 @@ void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, m48t59_write(nvram, addr + max - 1, '\0'); } -int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) -{ - int i; - - memset(dst, 0, max); - for (i = 0; i < max; i++) { - dst[i] = NVRAM_get_byte(nvram, addr + i); - if (dst[i] == '\0') - break; - } - - return i; -} - -static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) +static uint16_t nvram_crc_update (uint16_t prev, uint16_t value) { uint16_t tmp; uint16_t pd, pd1, pd2; @@ -153,7 +127,8 @@ static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) return tmp; } -uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) +static uint16_t nvram_compute_crc (m48t59_t *nvram, uint32_t start, + uint32_t count) { uint32_t i; uint16_t crc = 0xFFFF; @@ -162,10 +137,10 @@ uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) odd = count & 1; count &= ~1; for (i = 0; i != count; i++) { - crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); + crc = nvram_crc_update(crc, nvram_get_word(nvram, start + i)); } if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); + crc = nvram_crc_update(crc, nvram_get_byte(nvram, start + i) << 8); } return crc; @@ -177,7 +152,7 @@ static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr, uint32_t len; len = strlen(str) + 1; - NVRAM_set_string(nvram, addr, str, len); + nvram_set_string(nvram, addr, str, len); return addr + len; } @@ -215,39 +190,39 @@ int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, uint32_t start, end; /* Set parameters for Open Hack'Ware BIOS */ - NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); - NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ - NVRAM_set_word(nvram, 0x14, NVRAM_size); - NVRAM_set_string(nvram, 0x20, arch, 16); - NVRAM_set_byte(nvram, 0x2f, nographic & 0xff); - NVRAM_set_lword(nvram, 0x30, RAM_size); - NVRAM_set_byte(nvram, 0x34, boot_device); - NVRAM_set_lword(nvram, 0x38, kernel_image); - NVRAM_set_lword(nvram, 0x3C, kernel_size); + nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); + nvram_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ + nvram_set_word(nvram, 0x14, NVRAM_size); + nvram_set_string(nvram, 0x20, arch, 16); + nvram_set_byte(nvram, 0x2f, nographic & 0xff); + nvram_set_lword(nvram, 0x30, RAM_size); + nvram_set_byte(nvram, 0x34, boot_device); + nvram_set_lword(nvram, 0x38, kernel_image); + nvram_set_lword(nvram, 0x3C, kernel_size); if (cmdline) { /* XXX: put the cmdline in NVRAM too ? */ strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR); - NVRAM_set_lword(nvram, 0x44, strlen(cmdline)); + nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); + nvram_set_lword(nvram, 0x44, strlen(cmdline)); } else { - NVRAM_set_lword(nvram, 0x40, 0); - NVRAM_set_lword(nvram, 0x44, 0); + nvram_set_lword(nvram, 0x40, 0); + nvram_set_lword(nvram, 0x44, 0); } - NVRAM_set_lword(nvram, 0x48, initrd_image); - NVRAM_set_lword(nvram, 0x4C, initrd_size); - NVRAM_set_lword(nvram, 0x50, NVRAM_image); + nvram_set_lword(nvram, 0x48, initrd_image); + nvram_set_lword(nvram, 0x4C, initrd_size); + nvram_set_lword(nvram, 0x50, NVRAM_image); - NVRAM_set_word(nvram, 0x54, width); - NVRAM_set_word(nvram, 0x56, height); - NVRAM_set_word(nvram, 0x58, depth); - crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); - NVRAM_set_word(nvram, 0xFC, crc); + nvram_set_word(nvram, 0x54, width); + nvram_set_word(nvram, 0x56, height); + nvram_set_word(nvram, 0x58, depth); + crc = nvram_compute_crc(nvram, 0x00, 0xF8); + nvram_set_word(nvram, 0xFC, crc); // OpenBIOS nvram variables // Variable partition start = 256; m48t59_write(nvram, start, 0x70); - NVRAM_set_string(nvram, start + 4, "system", 12); + nvram_set_string(nvram, start + 4, "system", 12); end = start + 16; for (i = 0; i < nb_prom_envs; i++) @@ -260,7 +235,7 @@ int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, // free partition start = end; m48t59_write(nvram, start, 0x7f); - NVRAM_set_string(nvram, start + 4, "free", 12); + nvram_set_string(nvram, start + 4, "free", 12); end = 0x1fd0; nvram_finish_partition(nvram, start, end); -- cgit v1.2.3 From 8a4ed7ef483bd6cc0390ad2cb852cb9d278ebec8 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:22:48 +0000 Subject: printf format fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3595 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 4b53b908f..eb28991ce 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2043,17 +2043,17 @@ int main(int argc, char **argv) if (loglevel) { page_dump(logfile); - fprintf(logfile, "start_brk 0x" TARGET_FMT_lx "\n", info->start_brk); - fprintf(logfile, "end_code 0x" TARGET_FMT_lx "\n", info->end_code); - fprintf(logfile, "start_code 0x" TARGET_FMT_lx "\n", + fprintf(logfile, "start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); + fprintf(logfile, "end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code); + fprintf(logfile, "start_code 0x" TARGET_ABI_FMT_lx "\n", info->start_code); - fprintf(logfile, "start_data 0x" TARGET_FMT_lx "\n", + fprintf(logfile, "start_data 0x" TARGET_ABI_FMT_lx "\n", info->start_data); - fprintf(logfile, "end_data 0x" TARGET_FMT_lx "\n", info->end_data); - fprintf(logfile, "start_stack 0x" TARGET_FMT_lx "\n", + fprintf(logfile, "end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data); + fprintf(logfile, "start_stack 0x" TARGET_ABI_FMT_lx "\n", info->start_stack); - fprintf(logfile, "brk 0x" TARGET_FMT_lx "\n", info->brk); - fprintf(logfile, "entry 0x" TARGET_FMT_lx "\n", info->entry); + fprintf(logfile, "brk 0x" TARGET_ABI_FMT_lx "\n", info->brk); + fprintf(logfile, "entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); } target_set_brk(info->brk); -- cgit v1.2.3 From c16f9ed3adce9e930c296f167d48f4cb193fe59e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:23:29 +0000 Subject: use correct types git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3596 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 6 ++--- linux-user/strace.c | 70 +++++++++++++++++++++++++++++------------------------ 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 68ce12a62..581ee27fa 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -166,9 +166,9 @@ extern FILE *logfile; /* strace.c */ void print_syscall(int num, - target_long arg1, target_long arg2, target_long arg3, - target_long arg4, target_long arg5, target_long arg6); -void print_syscall_ret(int num, target_long arg1); + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6); +void print_syscall_ret(int num, abi_long arg1); extern int do_strace; /* signal.c */ diff --git a/linux-user/strace.c b/linux-user/strace.c index 315ae5c31..161ca4236 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -16,9 +16,9 @@ struct syscallname { char *name; char *format; void (*call)(struct syscallname *, - target_long, target_long, target_long, - target_long, target_long, target_long); - void (*result)(struct syscallname *, target_long); + abi_long, abi_long, abi_long, + abi_long, abi_long, abi_long); + void (*result)(struct syscallname *, abi_long); }; /* @@ -74,8 +74,9 @@ if( cmd == val ) { \ gemu_log("%d",cmd); } +#ifdef TARGET_NR__newselect static void -print_fdset(int n, target_ulong target_fds_addr) +print_fdset(int n, abi_ulong target_fds_addr) { int i; @@ -101,7 +102,7 @@ print_fdset(int n, target_ulong target_fds_addr) } static void -print_timeval(target_ulong tv_addr) +print_timeval(abi_ulong tv_addr) { if( tv_addr ) { struct target_timeval *tv; @@ -115,12 +116,14 @@ print_timeval(target_ulong tv_addr) } else gemu_log("NULL"); } +#endif /* * Sysycall specific output functions */ /* select */ +#ifdef TARGET_NR__newselect static long newselect_arg1 = 0; static long newselect_arg2 = 0; static long newselect_arg3 = 0; @@ -129,10 +132,10 @@ static long newselect_arg5 = 0; static void print_newselect(struct syscallname *name, - target_long arg1, target_long arg2, target_long arg3, - target_long arg4, target_long arg5, target_long arg6) + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) { - gemu_log("%s(" TARGET_FMT_ld ",", name->name, arg1); + gemu_log("%s(" TARGET_ABI_FMT_ld ",", name->name, arg1); print_fdset(arg1, arg2); gemu_log(","); print_fdset(arg1, arg3); @@ -149,23 +152,24 @@ print_newselect(struct syscallname *name, newselect_arg4=arg4; newselect_arg5=arg5; } +#endif static void print_semctl(struct syscallname *name, - target_long arg1, target_long arg2, target_long arg3, - target_long arg4, target_long arg5, target_long arg6) + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) { - gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld ",", name->name, arg1, arg2); + gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ",", name->name, arg1, arg2); print_ipc_cmd(arg3); - gemu_log(",0x" TARGET_FMT_lx ")", arg4); + gemu_log(",0x" TARGET_ABI_FMT_lx ")", arg4); } static void print_execve(struct syscallname *name, - target_long arg1, target_long arg2, target_long arg3, - target_long arg4, target_long arg5, target_long arg6) + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) { - target_ulong arg_ptr_addr; + abi_ulong arg_ptr_addr; char *s; if (!(s = lock_user_string(arg1))) @@ -173,10 +177,10 @@ print_execve(struct syscallname *name, gemu_log("%s(\"%s\",{", name->name, s); unlock_user(s, arg1, 0); - for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(target_ulong)) { - target_ulong *arg_ptr, arg_addr, s_addr; + for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { + abi_ulong *arg_ptr, arg_addr, s_addr; - arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong), 1); + arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); if (!arg_ptr) return; arg_addr = tswapl(*arg_ptr); @@ -192,10 +196,11 @@ print_execve(struct syscallname *name, gemu_log("NULL})"); } +#ifdef TARGET_NR_ipc static void print_ipc(struct syscallname *name, - target_long arg1, target_long arg2, target_long arg3, - target_long arg4, target_long arg5, target_long arg6) + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) { switch(arg1) { case IPCOP_semctl: @@ -203,38 +208,39 @@ print_ipc(struct syscallname *name, print_semctl(name,arg2,arg3,arg4,arg5,arg6,0); break; default: - gemu_log("%s(" TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld "," TARGET_FMT_ld ")", + gemu_log("%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")", name->name, arg1, arg2, arg3, arg4); } } +#endif /* * Variants for the return value output function */ static void -print_syscall_ret_addr(struct syscallname *name, target_long ret) +print_syscall_ret_addr(struct syscallname *name, abi_long ret) { if( ret == -1 ) { gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno)); } else { - gemu_log(" = " TARGET_FMT_lx "\n", ret); + gemu_log(" = " TARGET_ABI_FMT_lx "\n", ret); } } #if 0 /* currently unused */ static void -print_syscall_ret_raw(struct syscallname *name, target_long ret) +print_syscall_ret_raw(struct syscallname *name, abi_long ret) { - gemu_log(" = " TARGET_FMT_lx "\n", ret); + gemu_log(" = " TARGET_ABI_FMT_lx "\n", ret); } #endif #ifdef TARGET_NR__newselect static void -print_syscall_ret_newselect(struct syscallname *name, target_long ret) +print_syscall_ret_newselect(struct syscallname *name, abi_long ret) { - gemu_log(" = " TARGET_FMT_lx " (", ret); + gemu_log(" = " TARGET_ABI_FMT_lx " (", ret); print_fdset(newselect_arg1,newselect_arg2); gemu_log(","); print_fdset(newselect_arg1,newselect_arg3); @@ -261,8 +267,8 @@ static int nsyscalls = sizeof(scnames)/sizeof(struct syscallname); */ void print_syscall(int num, - target_long arg1, target_long arg2, target_long arg3, - target_long arg4, target_long arg5, target_long arg6) + abi_long arg1, abi_long arg2, abi_long arg3, + abi_long arg4, abi_long arg5, abi_long arg6) { int i; char *format="%s(%ld,%ld,%ld,%ld,%ld,%ld)"; @@ -284,7 +290,7 @@ print_syscall(int num, void -print_syscall_ret(int num, target_long ret) +print_syscall_ret(int num, abi_long ret) { int i; @@ -294,9 +300,9 @@ print_syscall_ret(int num, target_long ret) scnames[i].result(&scnames[i],ret); } else { if( ret < 0 ) { - gemu_log(" = -1 errno=%d (%s)\n", -ret, target_strerror(-ret)); + gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, target_strerror(-ret)); } else { - gemu_log(" = %d\n", ret); + gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret); } } break; -- cgit v1.2.3 From ac2567b59d9e4afbcc31c71840d7fe8ef4eee857 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:25:52 +0000 Subject: fixed invalid cast git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3597 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/m68k-sim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/m68k-sim.c b/linux-user/m68k-sim.c index aab82dd7e..61c246875 100644 --- a/linux-user/m68k-sim.c +++ b/linux-user/m68k-sim.c @@ -129,7 +129,7 @@ void do_m68k_simcall(CPUM68KState *env, int nr) { int32_t ret; - ret = do_brk((void *)ARG(0)); + ret = do_brk((abi_ulong)ARG(0)); if (ret == -ENOMEM) ret = -1; check_err(env, ret); -- cgit v1.2.3 From 7aaabde7d7b7f83fb88c542b77aaad158abcbddd Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:26:21 +0000 Subject: use -fno-strict-aliasing git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3598 c046a42c-6fe2-441c-8c8c-71466251a162 --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 97688b8f0..94ec0b4a0 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ -include ../config-host.mak -CFLAGS=-Wall -O2 -g +CFLAGS=-Wall -O2 -g -fno-strict-aliasing #CFLAGS+=-msse2 LDFLAGS= -- cgit v1.2.3 From 745cacc7b7e36aeb9bcc034f1de3d92eac1efc72 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:26:45 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3599 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-all.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translate-all.c b/translate-all.c index c42fedf7f..9f602be36 100644 --- a/translate-all.c +++ b/translate-all.c @@ -241,7 +241,7 @@ int cpu_restore_state(TranslationBlock *tb, if (npc == 1) { /* dynamic NPC: already stored */ } else if (npc == 2) { - target_ulong t2 = (target_ulong)puc; + target_ulong t2 = (target_ulong)(unsigned long)puc; /* jump PC: use T2 and the jump targets of the translation */ if (t2) env->npc = gen_opc_jump_pc[0]; -- cgit v1.2.3 From 5a4a898d81406cdda342ec2bce5ca14d2070ccb3 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:39:18 +0000 Subject: improved cmsg handling - improved shm memory code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3600 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 114 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 42 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a7f41cf99..402fa06ae 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -669,12 +669,22 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, } /* ??? Should this also swap msgh->name? */ -static inline void target_to_host_cmsg(struct msghdr *msgh, - struct target_msghdr *target_msgh) +static inline abi_long target_to_host_cmsg(struct msghdr *msgh, + struct target_msghdr *target_msgh) { struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); - struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); + abi_long msg_controllen; + abi_ulong target_cmsg_addr; + struct target_cmsghdr *target_cmsg; socklen_t space = 0; + + msg_controllen = tswapl(target_msgh->msg_controllen); + if (msg_controllen < sizeof (struct target_cmsghdr)) + goto the_end; + target_cmsg_addr = tswapl(target_msgh->msg_control); + target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1); + if (!target_cmsg) + return -TARGET_EFAULT; while (cmsg && target_cmsg) { void *data = CMSG_DATA(cmsg); @@ -709,18 +719,30 @@ static inline void target_to_host_cmsg(struct msghdr *msgh, cmsg = CMSG_NXTHDR(msgh, cmsg); target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); } - + unlock_user(target_cmsg, target_cmsg_addr, 0); + the_end: msgh->msg_controllen = space; + return 0; } /* ??? Should this also swap msgh->name? */ -static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, - struct msghdr *msgh) +static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, + struct msghdr *msgh) { struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); - struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); + abi_long msg_controllen; + abi_ulong target_cmsg_addr; + struct target_cmsghdr *target_cmsg; socklen_t space = 0; + msg_controllen = tswapl(target_msgh->msg_controllen); + if (msg_controllen < sizeof (struct target_cmsghdr)) + goto the_end; + target_cmsg_addr = tswapl(target_msgh->msg_control); + target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0); + if (!target_cmsg) + return -TARGET_EFAULT; + while (cmsg && target_cmsg) { void *data = CMSG_DATA(cmsg); void *target_data = TARGET_CMSG_DATA(target_cmsg); @@ -728,7 +750,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr)); space += TARGET_CMSG_SPACE(len); - if (space > tswapl(target_msgh->msg_controllen)) { + if (space > msg_controllen) { space -= TARGET_CMSG_SPACE(len); gemu_log("Target cmsg overflow\n"); break; @@ -753,8 +775,10 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, cmsg = CMSG_NXTHDR(msgh, cmsg); target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); } - - msgh->msg_controllen = tswapl(space); + unlock_user(target_cmsg, target_cmsg_addr, space); + the_end: + target_msgh->msg_controllen = tswapl(space); + return 0; } /* do_setsockopt() Must return target values and target errnos. */ @@ -1109,12 +1133,13 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, msg.msg_iov = vec; if (send) { - target_to_host_cmsg(&msg, msgp); - ret = get_errno(sendmsg(fd, &msg, flags)); + ret = target_to_host_cmsg(&msg, msgp); + if (ret == 0) + ret = get_errno(sendmsg(fd, &msg, flags)); } else { ret = get_errno(recvmsg(fd, &msg, flags)); if (!is_error(ret)) - host_to_target_cmsg(msgp, &msg); + ret = host_to_target_cmsg(msgp, &msg); } unlock_iovec(vec, target_vec, count, !send); unlock_user_struct(msgp, target_msg, send ? 0 : 1); @@ -1409,8 +1434,8 @@ static abi_long do_socketcall(int num, abi_ulong vptr) #define N_SHM_REGIONS 32 static struct shm_region { - uint32_t start; - uint32_t size; + abi_ulong start; + abi_ulong size; } shm_regions[N_SHM_REGIONS]; struct target_ipc_perm @@ -1776,7 +1801,6 @@ static abi_long do_ipc(unsigned int call, int first, { int version; abi_long ret = 0; - unsigned long raddr; struct shmid_ds shm_info; int i; @@ -1831,32 +1855,38 @@ static abi_long do_ipc(unsigned int call, int first, break; case IPCOP_shmat: - /* SHM_* flags are the same on all linux platforms */ - ret = get_errno((long) shmat(first, (void *) ptr, second)); - if (is_error(ret)) - break; - raddr = ret; - /* find out the length of the shared memory segment */ - - ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); - if (is_error(ret)) { - /* can't get length, bail out */ - shmdt((void *) raddr); - break; - } - page_set_flags(raddr, raddr + shm_info.shm_segsz, - PAGE_VALID | PAGE_READ | - ((second & SHM_RDONLY)? 0: PAGE_WRITE)); - for (i = 0; i < N_SHM_REGIONS; ++i) { - if (shm_regions[i].start == 0) { - shm_regions[i].start = raddr; - shm_regions[i].size = shm_info.shm_segsz; + { + abi_ulong raddr; + void *host_addr; + /* SHM_* flags are the same on all linux platforms */ + host_addr = shmat(first, (void *)g2h(ptr), second); + if (host_addr == (void *)-1) { + ret = get_errno((long)host_addr); break; - } - } - if (put_user(raddr, third, abi_ulong)) - return -TARGET_EFAULT; - ret = 0; + } + raddr = h2g((unsigned long)host_addr); + /* find out the length of the shared memory segment */ + + ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); + if (is_error(ret)) { + /* can't get length, bail out */ + shmdt(host_addr); + break; + } + page_set_flags(raddr, raddr + shm_info.shm_segsz, + PAGE_VALID | PAGE_READ | + ((second & SHM_RDONLY)? 0: PAGE_WRITE)); + for (i = 0; i < N_SHM_REGIONS; ++i) { + if (shm_regions[i].start == 0) { + shm_regions[i].start = raddr; + shm_regions[i].size = shm_info.shm_segsz; + break; + } + } + if (put_user(raddr, third, abi_ulong)) + return -TARGET_EFAULT; + ret = 0; + } break; case IPCOP_shmdt: for (i = 0; i < N_SHM_REGIONS; ++i) { @@ -1866,7 +1896,7 @@ static abi_long do_ipc(unsigned int call, int first, break; } } - ret = get_errno(shmdt((void *) ptr)); + ret = get_errno(shmdt((void *)g2h(ptr))); break; case IPCOP_shmget: -- cgit v1.2.3 From 0ba22212d558e49ed6d44ce4834ccec7a7987b23 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:39:38 +0000 Subject: suppressed invalid TARGET_CMSG_FIRSTHDR macro git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3601 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall_defs.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 99b17cb05..333977aa9 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -164,9 +164,6 @@ struct target_cmsghdr { #define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1)) #define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg) -#define TARGET_CMSG_FIRSTHDR(mhdr) \ - ((size_t) tswapl((mhdr)->msg_controllen) >= sizeof (struct target_cmsghdr) \ - ? (struct target_cmsghdr *) tswapl((mhdr)->msg_control) : (struct target_cmsghdr *) NULL) #define TARGET_CMSG_ALIGN(len) (((len) + sizeof (abi_long) - 1) \ & (size_t) ~(sizeof (abi_long) - 1)) #define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \ -- cgit v1.2.3 From f26ae302648d2977ba36d3dfcd0b70dce4e51060 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:51:40 +0000 Subject: removed invalid use of _INTC_ARRAY git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3602 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sh7750.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sh7750.c b/hw/sh7750.c index 4b2b515b7..1e2d91719 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -573,7 +573,7 @@ SH7750State *sh7750_init(CPUSH4State * cpu) if (cpu_model & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) { sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_tmu34), - _INTC_ARRAY(NULL)); + NULL, 0); tmu012_init(0x1e100000, 0, s->periph_freq); } @@ -586,7 +586,7 @@ SH7750State *sh7750_init(CPUSH4State * cpu) if (cpu_model & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) { sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_irlm), - _INTC_ARRAY(NULL)); + NULL, 0); } return s; -- cgit v1.2.3 From 29fa23e76dfa4e57fc451fbf4dde454494044e8b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 17:55:50 +0000 Subject: hex numbers must have a leading 0x git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3603 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/strace.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 161ca4236..6854efec6 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -224,7 +224,7 @@ print_syscall_ret_addr(struct syscallname *name, abi_long ret) if( ret == -1 ) { gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno)); } else { - gemu_log(" = " TARGET_ABI_FMT_lx "\n", ret); + gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); } } @@ -232,7 +232,7 @@ if( ret == -1 ) { static void print_syscall_ret_raw(struct syscallname *name, abi_long ret) { - gemu_log(" = " TARGET_ABI_FMT_lx "\n", ret); + gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); } #endif @@ -240,7 +240,7 @@ print_syscall_ret_raw(struct syscallname *name, abi_long ret) static void print_syscall_ret_newselect(struct syscallname *name, abi_long ret) { - gemu_log(" = " TARGET_ABI_FMT_lx " (", ret); + gemu_log(" = 0x" TARGET_ABI_FMT_lx " (", ret); print_fdset(newselect_arg1,newselect_arg2); gemu_log(","); print_fdset(newselect_arg1,newselect_arg3); -- cgit v1.2.3 From 6a3b9cc9c5c52808435402a0b422e67f2ea9875c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 11 Nov 2007 17:56:38 +0000 Subject: Add SPARCserver 600MP emulation (original patch by Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3604 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_misc.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/sun4m.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++- qemu-doc.texi | 15 ++++++++------- vl.c | 1 + vl.h | 2 +- 5 files changed, 122 insertions(+), 9 deletions(-) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index ebf184930..236c4a1b7 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -46,11 +46,14 @@ typedef struct MiscState { uint8_t aux1, aux2; uint8_t diag, mctrl; uint32_t sysctrl; + uint16_t leds; } MiscState; #define MISC_SIZE 1 #define SYSCTRL_MAXADDR 3 #define SYSCTRL_SIZE (SYSCTRL_MAXADDR + 1) +#define LED_MAXADDR 2 +#define LED_SIZE (LED_MAXADDR + 1) static void slavio_misc_update_irq(void *opaque) { @@ -223,6 +226,54 @@ static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = { slavio_sysctrl_mem_writel, }; +static uint32_t slavio_led_mem_reads(void *opaque, target_phys_addr_t addr) +{ + MiscState *s = opaque; + uint32_t ret = 0, saddr; + + saddr = addr & LED_MAXADDR; + switch (saddr) { + case 0: + ret = s->leds; + break; + default: + break; + } + MISC_DPRINTF("Read diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr, + ret); + return ret; +} + +static void slavio_led_mem_writes(void *opaque, target_phys_addr_t addr, + uint32_t val) +{ + MiscState *s = opaque; + uint32_t saddr; + + saddr = addr & LED_MAXADDR; + MISC_DPRINTF("Write diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr, + val); + switch (saddr) { + case 0: + s->sysctrl = val; + break; + default: + break; + } +} + +static CPUReadMemoryFunc *slavio_led_mem_read[3] = { + slavio_led_mem_reads, + slavio_led_mem_reads, + slavio_led_mem_reads, +}; + +static CPUWriteMemoryFunc *slavio_led_mem_write[3] = { + slavio_led_mem_writes, + slavio_led_mem_writes, + slavio_led_mem_writes, +}; + static void slavio_misc_save(QEMUFile *f, void *opaque) { MiscState *s = opaque; @@ -291,6 +342,13 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, // Power management cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory); + /* 16 bit registers */ + slavio_misc_io_memory = cpu_register_io_memory(0, slavio_led_mem_read, + slavio_led_mem_write, s); + /* ss600mp diag LEDs */ + cpu_register_physical_memory(base + 0x1600000, MISC_SIZE, + slavio_misc_io_memory); + /* 32 bit registers */ slavio_misc_io_memory = cpu_register_io_memory(0, slavio_sysctrl_mem_read, slavio_sysctrl_mem_write, diff --git a/hw/sun4m.c b/hw/sun4m.c index 7b92add95..b10108716 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -388,7 +388,8 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], serial_hds[1], serial_hds[0]); - sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd_table); + if (hwdef->fd_base != (target_phys_addr_t)-1) + sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd_table); main_esp = esp_init(bs_table, hwdef->esp_base, espdma, *espdma_irq, esp_reset); @@ -546,6 +547,39 @@ static const struct hwdef hwdefs[] = { 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, }, + /* SS-600MP */ + { + .iommu_base = 0xfe0000000ULL, + .tcx_base = 0xe20000000ULL, + .cs_base = -1, + .slavio_base = 0xff0000000ULL, + .ms_kb_base = 0xff1000000ULL, + .serial_base = 0xff1100000ULL, + .nvram_base = 0xff1200000ULL, + .fd_base = -1, + .counter_base = 0xff1300000ULL, + .intctl_base = 0xff1400000ULL, + .dma_base = 0xef0081000ULL, + .esp_base = 0xef0080000ULL, + .le_base = 0xef0060000ULL, + .power_base = 0xefa000000ULL, + .vram_size = 0x00100000, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, + .cs_irq = -1, + .machine_id = 0x71, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, + }, }; static void sun4m_common_init(int RAM_size, const char *boot_device, DisplayState *ds, @@ -594,6 +628,19 @@ static void ss10_init(int RAM_size, int vga_ram_size, const char *boot_device, 1, 0xffffffff); // XXX actually first 62GB ok } +/* SPARCserver 600MP hardware initialisation */ +static void ss600mp_init(int RAM_size, int vga_ram_size, const char *boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + if (cpu_model == NULL) + cpu_model = "TI SuperSparc II"; + sun4m_common_init(RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, + 2, 0xffffffff); // XXX actually first 62GB ok +} + QEMUMachine ss5_machine = { "SS-5", "Sun4m platform, SPARCstation 5", @@ -605,3 +652,9 @@ QEMUMachine ss10_machine = { "Sun4m platform, SPARCstation 10", ss10_init, }; + +QEMUMachine ss600mp_machine = { + "SS-600MP", + "Sun4m platform, SPARCserver 600MP", + ss600mp_init, +}; diff --git a/qemu-doc.texi b/qemu-doc.texi index 740d30359..92dfd5c65 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1949,10 +1949,10 @@ More information is available at @node Sparc32 System emulator @section Sparc32 System emulator -Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5 -or SparcStation 10 (sun4m architecture). The emulation is somewhat complete. -SMP up to 16 CPUs is supported, but Linux limits the number of usable CPUs -to 4. +Use the executable @file{qemu-system-sparc} to simulate a SPARCstation +5, SPARCstation 10, or SPARCserver 600MP (sun4m architecture). The +emulation is somewhat complete. SMP up to 16 CPUs is supported, but +Linux limits the number of usable CPUs to 4. QEMU emulates the following sun4m peripherals: @@ -1971,13 +1971,14 @@ and power/reset logic @item ESP SCSI controller with hard disk and CD-ROM support @item -Floppy drive +Floppy drive (not on SS-600MP) @item CS4231 sound device (only on SS-5, not working yet) @end itemize -The number of peripherals is fixed in the architecture. Maximum memory size -depends on the machine type, for SS-5 it is 256MB and for SS-10 2047MB. +The number of peripherals is fixed in the architecture. Maximum +memory size depends on the machine type, for SS-5 it is 256MB and for +SS-10 and SS-600MP 2047MB. Since version 0.8.2, QEMU uses OpenBIOS @url{http://www.openbios.org/}. OpenBIOS is a free (GPL v2) portable diff --git a/vl.c b/vl.c index 41042eb8a..d281f8a99 100644 --- a/vl.c +++ b/vl.c @@ -7421,6 +7421,7 @@ void register_machines(void) #else qemu_register_machine(&ss5_machine); qemu_register_machine(&ss10_machine); + qemu_register_machine(&ss600mp_machine); #endif #elif defined(TARGET_ARM) qemu_register_machine(&integratorcp_machine); diff --git a/vl.h b/vl.h index a73da2710..cdcc3c95d 100644 --- a/vl.h +++ b/vl.h @@ -1048,7 +1048,7 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); #endif /* sun4m.c */ -extern QEMUMachine ss5_machine, ss10_machine; +extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine; /* iommu.c */ void *iommu_init(target_phys_addr_t addr); -- cgit v1.2.3 From 70499c989f434cba8bc2104da9f6ca162c4a937b Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:31:34 +0000 Subject: better than nothing 64 bit support - added sign extension for TYPE_LONG git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3605 c046a42c-6fe2-441c-8c8c-71466251a162 --- thunk.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/thunk.c b/thunk.c index 0347d6d04..dc9e315d7 100644 --- a/thunk.c +++ b/thunk.c @@ -147,11 +147,37 @@ const argtype *thunk_convert(void *dst, const void *src, case TYPE_ULONG: case TYPE_PTRVOID: if (to_host) { - *(uint64_t *)dst = tswap32(*(uint32_t *)src); + if (type == TYPE_LONG) { + /* sign extension */ + *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src); + } else { + *(uint64_t *)dst = tswap32(*(uint32_t *)src); + } } else { *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff); } break; +#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64 + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + *(uint64_t *)dst = tswap64(*(uint64_t *)src); + break; +#elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64 + case TYPE_LONG: + case TYPE_ULONG: + case TYPE_PTRVOID: + if (to_host) { + *(uint32_t *)dst = tswap64(*(uint64_t *)src); + } else { + if (type == TYPE_LONG) { + /* sign extension */ + *(uint64_t *)dst = tswap64(*(int32_t *)src); + } else { + *(uint64_t *)dst = tswap64(*(uint32_t *)src); + } + } + break; #else #warning unsupported conversion #endif -- cgit v1.2.3 From 27524dc3600774e8c1a5cf54a4c41c6e78c8d535 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:32:52 +0000 Subject: sparc64_[get|set]_context are not meaningful in abi32 mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3606 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index eb28991ce..5cc2d4137 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -641,6 +641,7 @@ void cpu_loop (CPUSPARCState *env) queue_signal(info.si_signo, &info); } break; +#ifndef TARGET_ABI32 case 0x16e: flush_windows(env); sparc64_get_context(env); @@ -649,6 +650,7 @@ void cpu_loop (CPUSPARCState *env) flush_windows(env); sparc64_set_context(env); break; +#endif #endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ -- cgit v1.2.3 From eeeac3f3e3398124a0f2a118358a91289a30b8e0 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:34:32 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3607 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 402fa06ae..6e9052af8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2319,7 +2319,7 @@ static abi_long write_ldt(CPUX86State *env, if (!ldt_table) return -TARGET_ENOMEM; memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); - env->ldt.base = h2g(ldt_table); + env->ldt.base = h2g((unsigned long)ldt_table); env->ldt.limit = 0xffff; } @@ -4268,7 +4268,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_getdents: #if TARGET_ABI_BITS != 32 goto unimplemented; -#warning not supported #elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 { struct target_dirent *target_dirp; -- cgit v1.2.3 From 459a40172e7ee1be269771c355dbb3ef3c3903db Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:45:10 +0000 Subject: removed warnings - improved sparc32/64 signal frame setup - disabled x86 frame setup for x86_64 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3608 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 151 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 59 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 8c0e02abc..c7b1ea89f 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -143,7 +143,7 @@ static void host_to_target_sigset_internal(target_sigset_t *d, d->sig[0] = target_sigmask; d->sig[1] = sigmask >> 32; #else -#warning host_to_target_sigset + /* XXX: do it */ #endif } @@ -177,7 +177,7 @@ void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) #elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32); #else -#warning target_to_host_sigset + /* XXX: do it */ #endif /* TARGET_ABI_BITS */ } @@ -233,7 +233,7 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, tinfo->_sifields._rt._uid = info->si_uid; /* XXX: potential problem if 64 bit */ tinfo->_sifields._rt._sigval.sival_ptr = - (abi_ulong)info->si_value.sival_ptr; + (abi_ulong)(unsigned long)info->si_value.sival_ptr; } } @@ -276,7 +276,7 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) info->si_pid = tswap32(tinfo->_sifields._rt._pid); info->si_uid = tswap32(tinfo->_sifields._rt._uid); info->si_value.sival_ptr = - (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); + (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); } void signal_init(void) @@ -562,7 +562,7 @@ static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, return 0; } -#ifdef TARGET_I386 +#if defined(TARGET_I386) && TARGET_ABI_BITS == 32 /* from the Linux kernel */ @@ -773,11 +773,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, /* This is popl %eax ; movl $,%eax ; int $0x80 */ val16 = 0xb858; err |= __put_user(val16, (uint16_t *)(frame->retcode+0)); -#if defined(TARGET_X86_64) -#warning "Fix this !" -#else err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); -#endif val16 = 0x80cd; err |= __put_user(val16, (uint16_t *)(frame->retcode+6)); } @@ -1486,9 +1482,10 @@ struct target_rt_signal_frame { #define UREG_FP UREG_I6 #define UREG_SP UREG_O6 -static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, unsigned long framesize) +static inline abi_ulong get_sigframe(struct emulated_sigaction *sa, + CPUState *env, unsigned long framesize) { - unsigned long sp; + abi_ulong sp; sp = env->regwptr[UREG_FP]; @@ -1498,7 +1495,7 @@ static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, u && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; } - return g2h(sp - framesize); + return sp - framesize; } static int @@ -1543,6 +1540,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ static void setup_frame(int sig, struct emulated_sigaction *ka, target_sigset_t *set, CPUState *env) { + abi_ulong sf_addr; struct target_signal_frame *sf; int sigframe_size, err, i; @@ -1550,10 +1548,13 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, //synchronize_user_stack(); sigframe_size = NF_ALIGNEDSZ; + sf_addr = get_sigframe(ka, env, sigframe_size); - sf = (struct target_signal_frame *) - get_sigframe(ka, env, sigframe_size); - + sf = lock_user(VERIFY_WRITE, sf_addr, + sizeof(struct target_signal_frame), 0); + if (!sf) + goto sigsegv; + //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); #if 0 if (invalid_frame_pointer(sf, sigframe_size)) @@ -1581,20 +1582,24 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, goto sigsegv; /* 3. signal handler back-trampoline and parameters */ - env->regwptr[UREG_FP] = h2g(sf); + env->regwptr[UREG_FP] = sf_addr; env->regwptr[UREG_I0] = sig; - env->regwptr[UREG_I1] = h2g(&sf->info); - env->regwptr[UREG_I2] = h2g(&sf->info); + env->regwptr[UREG_I1] = sf_addr + + offsetof(struct target_signal_frame, info); + env->regwptr[UREG_I2] = sf_addr + + offsetof(struct target_signal_frame, info); /* 4. signal handler */ - env->pc = (unsigned long) ka->sa._sa_handler; + env->pc = ka->sa._sa_handler; env->npc = (env->pc + 4); /* 5. return to kernel instructions */ if (ka->sa.sa_restorer) - env->regwptr[UREG_I7] = (unsigned long)ka->sa.sa_restorer; + env->regwptr[UREG_I7] = ka->sa.sa_restorer; else { uint32_t val32; - env->regwptr[UREG_I7] = h2g(&(sf->insns[0]) - 2); + + env->regwptr[UREG_I7] = sf_addr + + offsetof(struct target_signal_frame, insns) - 2 * 4; /* mov __NR_sigreturn, %g1 */ val32 = 0x821020d8; @@ -1610,12 +1615,15 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); // tb_flush(env); } + unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); return; - - //sigill_and_return: +#if 0 +sigill_and_return: force_sig(TARGET_SIGILL); +#endif sigsegv: //fprintf(stderr, "force_sig\n"); + unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); force_sig(TARGET_SIGSEGV); } static inline int @@ -1744,7 +1752,7 @@ long do_rt_sigreturn(CPUState *env) return -ENOSYS; } -#ifdef TARGET_SPARC64 +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) #define MC_TSTATE 0 #define MC_PC 1 #define MC_NPC 2 @@ -1815,16 +1823,18 @@ struct target_reg_window { /* {set, get}context() needed for 64-bit SparcLinux userland. */ void sparc64_set_context(CPUSPARCState *env) { - struct target_ucontext *ucp = (struct target_ucontext *) - env->regwptr[UREG_I0]; + abi_ulong ucp_addr; + struct target_ucontext *ucp; target_mc_gregset_t *grp; abi_ulong pc, npc, tstate; - abi_ulong fp, i7; + abi_ulong fp, i7, w_addr; unsigned char fenab; int err; unsigned int i; - abi_ulong *src, *dst; + ucp_addr = env->regwptr[UREG_I0]; + if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) + goto do_sigsegv; grp = &ucp->uc_mcontext.mc_gregs; err = __get_user(pc, &((*grp)[MC_PC])); err |= __get_user(npc, &((*grp)[MC_NPC])); @@ -1838,11 +1848,12 @@ void sparc64_set_context(CPUSPARCState *env) if (__get_user(target_set.sig[0], &ucp->uc_sigmask.sig[0])) goto do_sigsegv; } else { - src = &ucp->uc_sigmask; - dst = &target_set; + abi_ulong *src, *dst; + src = ucp->uc_sigmask.sig; + dst = target_set.sig; for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong); i++, dst++, src++) - err |= __get_user(dst, src); + err |= __get_user(*dst, src); if (err) goto do_sigsegv; } @@ -1874,42 +1885,53 @@ void sparc64_set_context(CPUSPARCState *env) err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp)); err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7)); - err |= __put_user(fp, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); - err |= __put_user(i7, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); + w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6]; + if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), + abi_ulong) != 0) + goto do_sigsegv; + if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), + abi_ulong) != 0) + goto do_sigsegv; err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); err |= __get_user(env->fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); - src = &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs); - dst = &env->fpr; - for (i = 0; i < 64; i++, dst++, src++) - err |= __get_user(dst, src); + { + uint32_t *src, *dst; + src = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs; + dst = env->fpr; + /* XXX: check that the CPU storage is the same as user context */ + for (i = 0; i < 64; i++, dst++, src++) + err |= __get_user(*dst, src); + } err |= __get_user(env->fsr, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); err |= __get_user(env->gsr, &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); if (err) goto do_sigsegv; - + unlock_user_struct(ucp, ucp_addr, 0); return; do_sigsegv: + unlock_user_struct(ucp, ucp_addr, 0); force_sig(SIGSEGV); } void sparc64_get_context(CPUSPARCState *env) { - struct target_ucontext *ucp = (struct target_ucontext *) - env->regwptr[UREG_I0]; + abi_ulong ucp_addr; + struct target_ucontext *ucp; target_mc_gregset_t *grp; target_mcontext_t *mcp; - abi_ulong fp, i7; + abi_ulong fp, i7, w_addr; int err; unsigned int i; - abi_ulong *src, *dst; target_sigset_t target_set; sigset_t set; + ucp_addr = env->regwptr[UREG_I0]; + if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) + goto do_sigsegv; + mcp = &ucp->uc_mcontext; grp = &mcp->mc_gregs; @@ -1921,20 +1943,22 @@ void sparc64_get_context(CPUSPARCState *env) sigprocmask(0, NULL, &set); host_to_target_sigset_internal(&target_set, &set); - if (TARGET_NSIG_WORDS == 1) + if (TARGET_NSIG_WORDS == 1) { err |= __put_user(target_set.sig[0], (abi_ulong *)&ucp->uc_sigmask); - else { - src = &target_set; - dst = &ucp->uc_sigmask; + } else { + abi_ulong *src, *dst; + src = target_set.sig; + dst = ucp->uc_sigmask.sig; for (i = 0; i < sizeof(target_sigset_t) / sizeof(abi_ulong); i++, dst++, src++) - err |= __put_user(src, dst); + err |= __put_user(*src, dst); if (err) goto do_sigsegv; } - err |= __put_user(env->tstate, &((*grp)[MC_TSTATE])); + /* XXX: tstate must be saved properly */ + // err |= __put_user(env->tstate, &((*grp)[MC_TSTATE])); err |= __put_user(env->pc, &((*grp)[MC_PC])); err |= __put_user(env->npc, &((*grp)[MC_NPC])); err |= __put_user(env->y, &((*grp)[MC_Y])); @@ -1954,26 +1978,35 @@ void sparc64_get_context(CPUSPARCState *env) err |= __put_user(env->regwptr[UREG_I6], &((*grp)[MC_O6])); err |= __put_user(env->regwptr[UREG_I7], &((*grp)[MC_O7])); - err |= __get_user(fp, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[6]))); - err |= __get_user(i7, - (&(((struct target_reg_window *)(TARGET_STACK_BIAS+env->regwptr[UREG_I6]))->ins[7]))); + w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6]; + fp = i7 = 0; + if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]), + abi_ulong) != 0) + goto do_sigsegv; + if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]), + abi_ulong) != 0) + goto do_sigsegv; err |= __put_user(fp, &(mcp->mc_fp)); err |= __put_user(i7, &(mcp->mc_i7)); - src = &env->fpr; - dst = &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs); - for (i = 0; i < 64; i++, dst++, src++) - err |= __put_user(src, dst); + { + uint32_t *src, *dst; + src = env->fpr; + dst = ucp->uc_mcontext.mc_fpregs.mcfpu_fregs.sregs; + /* XXX: check that the CPU storage is the same as user context */ + for (i = 0; i < 64; i++, dst++, src++) + err |= __put_user(*src, dst); + } err |= __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr)); err |= __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr)); err |= __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs)); if (err) goto do_sigsegv; - + unlock_user_struct(ucp, ucp_addr, 1); return; do_sigsegv: + unlock_user_struct(ucp, ucp_addr, 1); force_sig(SIGSEGV); } #endif -- cgit v1.2.3 From 1e4146791b46f0a798589c58a09f18b2841a9212 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:46:37 +0000 Subject: removed unused code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3609 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-uhci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 95dd4a0cd..26a079500 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -148,6 +148,7 @@ static void uhci_reset(UHCIState *s) } } +#if 0 static void uhci_save(QEMUFile *f, void *opaque) { UHCIState *s = opaque; @@ -199,6 +200,7 @@ static int uhci_load(QEMUFile *f, void *opaque, int version_id) return 0; } +#endif static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) { -- cgit v1.2.3 From a702b35388c307ce2364691e2edc14094701c81e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:47:02 +0000 Subject: fixed invalid constant git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3610 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 1b17a3d37..14fd40262 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -125,7 +125,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) // of counter (user mode) slavio_timer_get_out(s); if (slavio_timer_is_user(s)) // read user timer LSW - ret = s->count & 0xffffffe00; + ret = s->count & 0xfffffe00; else // read limit ret = (s->count & 0x7ffffe00) | s->reached; break; -- cgit v1.2.3 From 444ce24195b97d1b425cd250a731e3f5f4b4bbfa Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:47:59 +0000 Subject: use correct printf format git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3611 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa.h | 2 +- hw/pxa2xx_dma.c | 4 ++-- hw/spitz.c | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/pxa.h b/hw/pxa.h index 037aebee4..5eb6a5982 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -203,7 +203,7 @@ struct pxa2xx_i2s_s { }; # define PA_FMT "0x%08lx" -# define REG_FMT "0x%lx" +# define REG_FMT "0x" TARGET_FMT_plx struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, DisplayState *ds, const char *revision); diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 53bce2e46..4c60ffd00 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -303,7 +303,7 @@ static uint32_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset) } cpu_abort(cpu_single_env, - "%s: Bad offset 0x%04lx\n", __FUNCTION__, offset); + "%s: Bad offset 0x" TARGET_FMT_plx "\n", __FUNCTION__, offset); return 7; } @@ -401,7 +401,7 @@ static void pxa2xx_dma_write(void *opaque, break; } fail: - cpu_abort(cpu_single_env, "%s: Bad offset 0x%04lx\n", + cpu_abort(cpu_single_env, "%s: Bad offset " TARGET_FMT_plx "\n", __FUNCTION__, offset); } } diff --git a/hw/spitz.c b/hw/spitz.c index 68bba18e1..764b694e1 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -12,7 +12,11 @@ #define spitz_printf(format, ...) \ fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__) #undef REG_FMT +#if TARGET_PHYS_ADDR_BITS == 32 +#define REG_FMT "0x%02x" +#else #define REG_FMT "0x%02lx" +#endif /* Spitz Flash */ #define FLASH_BASE 0x0c000000 -- cgit v1.2.3 From fa58c1568bba0ad031b5c6ebe1f34d41b611c61c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:48:33 +0000 Subject: removed unused variables git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3612 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 3c1083902..62c396cd3 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -25,22 +25,34 @@ static struct { { 0, 0 } }; -static struct { +typedef struct PXASSPDef { target_phys_addr_t io_base; int irqn; -} pxa250_ssp[] = { +} PXASSPDef; + +#if 0 +static PXASSPDef pxa250_ssp[] = { { 0x41000000, PXA2XX_PIC_SSP }, { 0, 0 } -}, pxa255_ssp[] = { +}; +#endif + +static PXASSPDef pxa255_ssp[] = { { 0x41000000, PXA2XX_PIC_SSP }, { 0x41400000, PXA25X_PIC_NSSP }, { 0, 0 } -}, pxa26x_ssp[] = { +}; + +#if 0 +static PXASSPDef pxa26x_ssp[] = { { 0x41000000, PXA2XX_PIC_SSP }, { 0x41400000, PXA25X_PIC_NSSP }, { 0x41500000, PXA26X_PIC_ASSP }, { 0, 0 } -}, pxa27x_ssp[] = { +}; +#endif + +static PXASSPDef pxa27x_ssp[] = { { 0x41000000, PXA2XX_PIC_SSP }, { 0x41700000, PXA27X_PIC_SSP2 }, { 0x41900000, PXA2XX_PIC_SSP3 }, -- cgit v1.2.3 From 8731ac030ea83e0d37cfd269a5ee8cc469096924 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:48:47 +0000 Subject: fixed cast git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3613 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/omap.c b/hw/omap.c index a0f0a1925..30c0bef5e 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -833,7 +833,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, return 1; default: - OMAP_BAD_REG((unsigned long) reg); + OMAP_BAD_REG((target_phys_addr_t) reg); } return 0; } -- cgit v1.2.3 From 83f59879561bdc5fa0ff61e536f9c0c415be5e7f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:49:08 +0000 Subject: removed unused variable git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3614 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_mipssim.c | 1 - hw/mips_pica61.c | 1 - 2 files changed, 2 deletions(-) diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 93288a6ef..0c755a9ed 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -109,7 +109,6 @@ mips_mipssim_init (int ram_size, int vga_ram_size, const char *boot_device, unsigned long bios_offset; CPUState *env; int bios_size; - mips_def_t *def; /* Init CPUs. */ if (cpu_model == NULL) { diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 8e7ce6ce3..97c5ced4d 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -64,7 +64,6 @@ void mips_pica61_init (int ram_size, int vga_ram_size, const char *boot_device, int bios_size; CPUState *env; int i; - mips_def_t *def; int available_ram; qemu_irq *i8259; -- cgit v1.2.3 From b0b3de8988b9f95f168ef94f8e918402d331db63 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:49:51 +0000 Subject: fixed FPU rounding init git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3615 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sh4/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 8d5e99e97..70b4837a9 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -133,10 +133,10 @@ void cpu_sh4_reset(CPUSH4State * env) env->pc = 0xA0000000; #if defined(CONFIG_USER_ONLY) env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */ - env->fp_status.float_rounding_mode = float_round_nearest_even; /* ?! */ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */ #else env->fpscr = 0x00040001; /* CPU reset value according to SH4 manual */ - env->fp_status.float_rounding_mode = float_round_to_zero; + set_float_rounding_mode(float_round_to_zero, &env->fp_status); #endif env->mmucr = 0; } -- cgit v1.2.3 From bd37ec214154c0bd863e1b36a2a945169808e620 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 19:50:22 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3616 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gt64xxx.c | 5 +++++ target-i386/exec.h | 4 ++-- target-sparc/op_helper.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index fdb70b3eb..65e16b2f7 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -1109,6 +1109,11 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) GT64120State *s; PCIDevice *d; + (void)&pci_host_data_writeb; /* avoid warning */ + (void)&pci_host_data_writew; /* avoid warning */ + (void)&pci_host_data_readb; /* avoid warning */ + (void)&pci_host_data_readw; /* avoid warning */ + s = qemu_mallocz(sizeof(GT64120State)); s->pci = qemu_mallocz(sizeof(GT64120PCIState)); diff --git a/target-i386/exec.h b/target-i386/exec.h index 8e2a55321..70fac64fc 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -419,12 +419,12 @@ static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) static inline CPU86_LDouble helper_fldt(target_ulong ptr) { - return *(CPU86_LDouble *)ptr; + return *(CPU86_LDouble *)(unsigned long)ptr; } static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr) { - *(CPU86_LDouble *)ptr = f; + *(CPU86_LDouble *)(unsigned long)ptr = f; } #else diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 13c16618f..09e9c8bf4 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -433,7 +433,7 @@ void helper_st_asi(int asi, int size) break; case 0x01c00a04: /* MXCC control register */ if (size == 4) - env->mxccregs[3] = (env->mxccregs[0xa] & 0xffffffff00000000) | T1; + env->mxccregs[3] = (env->mxccregs[0xa] & 0xffffffff00000000ULL) | T1; else DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); break; -- cgit v1.2.3 From 6dfd59d6a73f5d8c990a2fbfc4f83fcb70858244 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 20:14:28 +0000 Subject: removed warning git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3617 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 ++-- vl.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index aa58cbb24..8de14e280 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -758,7 +758,7 @@ void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) saved_env = env; env = s; - helper_fsave((target_ulong)ptr, data32); + helper_fsave((target_ulong)(unsigned long)ptr, data32); env = saved_env; } @@ -770,7 +770,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) saved_env = env; env = s; - helper_frstor((target_ulong)ptr, data32); + helper_frstor((target_ulong)(unsigned long)ptr, data32); env = saved_env; } diff --git a/vl.c b/vl.c index d281f8a99..1586f123f 100644 --- a/vl.c +++ b/vl.c @@ -6287,7 +6287,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) #else -#warning No CPU save/restore functions +//#warning No CPU save/restore functions #endif -- cgit v1.2.3 From 85aa518981a71d8b758cad1ae30745302841242c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 20:17:03 +0000 Subject: options to enable or disable -Werror. Enable -Werror for builds from CVS by default git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3618 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/configure b/configure index 87166b461..081a3fecc 100755 --- a/configure +++ b/configure @@ -213,6 +213,13 @@ else source_path_used="yes" fi +# generate compile errors on warnings for development builds +if grep cvs $source_path/VERSION > /dev/null 2>&1 ; then +werror="yes"; +else +werror="no" +fi + for opt do optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'` case "$opt" in @@ -306,6 +313,10 @@ for opt do *) echo "undefined SPARC architecture. Exiting";exit 1;; esac ;; + --enable-werror) werror="yes" + ;; + --disable-werror) werror="no" + ;; esac done @@ -319,6 +330,9 @@ fi # default flags for all hosts CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing" LDFLAGS="$LDFLAGS -g" +if test "$werror" = "yes" ; then +CFLAGS="$CFLAGS -Werror" +fi # # If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right @@ -378,6 +392,7 @@ 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 " --disable-werror disable compilation abort on warning" echo " --disable-sdl disable SDL" echo " --enable-cocoa enable COCOA (Mac OS X only)" echo " --enable-mingw32 enable Win32 cross compilation with mingw32" @@ -684,6 +699,7 @@ echo "target list $target_list" echo "gprof enabled $gprof" echo "profiler $profiler" echo "static build $static" +echo "-Werror enabled $werror" if test "$darwin" = "yes" ; then echo "Cocoa support $cocoa" fi -- cgit v1.2.3 From 984b19451bc97685ed55c4090dd0caf10b0d96e9 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 20:17:14 +0000 Subject: update git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3619 c046a42c-6fe2-441c-8c8c-71466251a162 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 899f24fc7..8a6125d3e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.9.0 \ No newline at end of file +0.9.0-cvs \ No newline at end of file -- cgit v1.2.3 From 0d1e239407c73a90a32c8e2f5e1fe4e9cc10ca1f Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 20:24:30 +0000 Subject: better to disable -Werror by default as 64 bit hosts still have warnings git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3620 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 081a3fecc..897df1029 100755 --- a/configure +++ b/configure @@ -213,12 +213,11 @@ else source_path_used="yes" fi -# generate compile errors on warnings for development builds -if grep cvs $source_path/VERSION > /dev/null 2>&1 ; then -werror="yes"; -else werror="no" -fi +# generate compile errors on warnings for development builds +#if grep cvs $source_path/VERSION > /dev/null 2>&1 ; then +#werror="yes"; +#fi for opt do optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'` -- cgit v1.2.3 From 6f12a2a6ea8fc04e4f98f493de4046cc185fd00a Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 22:16:56 +0000 Subject: consistent types for cpu_x86_fsave and cpu_x86_frstor git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3621 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 8 ++++---- target-i386/cpu.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 8de14e280..1c7356a0d 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -751,26 +751,26 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) env = saved_env; } -void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) +void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32) { CPUX86State *saved_env; saved_env = env; env = s; - helper_fsave((target_ulong)(unsigned long)ptr, data32); + helper_fsave(ptr, data32); env = saved_env; } -void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) +void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32) { CPUX86State *saved_env; saved_env = env; env = s; - helper_frstor((target_ulong)(unsigned long)ptr, data32); + helper_frstor(ptr, data32); env = saved_env; } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index a6ad54be3..910a4b48c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -670,8 +670,8 @@ CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper); /* the following helpers are only usable in user mode simulation as they can trigger unexpected exceptions */ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); -void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); -void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); +void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32); +void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero -- cgit v1.2.3 From 1455bf488f6c7751961d583df81d9f054dabe07d Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 22:22:34 +0000 Subject: 64 bit compilation fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3622 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/vm86.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 0667b4dd7..d87174b56 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -39,22 +39,27 @@ static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1; } -static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val) +static inline void vm_putw(uint32_t segptr, unsigned int reg16, unsigned int val) { stw(segptr + (reg16 & 0xffff), val); } -static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val) +static inline void vm_putl(uint32_t segptr, unsigned int reg16, unsigned int val) { stl(segptr + (reg16 & 0xffff), val); } -static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16) +static inline unsigned int vm_getb(uint32_t segptr, unsigned int reg16) +{ + return ldub(segptr + (reg16 & 0xffff)); +} + +static inline unsigned int vm_getw(uint32_t segptr, unsigned int reg16) { return lduw(segptr + (reg16 & 0xffff)); } -static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16) +static inline unsigned int vm_getl(uint32_t segptr, unsigned int reg16) { return ldl(segptr + (reg16 & 0xffff)); } @@ -196,8 +201,7 @@ static inline unsigned int get_vflags(CPUX86State *env) static void do_int(CPUX86State *env, int intno) { TaskState *ts = env->opaque; - uint32_t *int_ptr, segoffs; - uint8_t *ssp; + uint32_t int_addr, segoffs, ssp; unsigned int sp; if (env->segs[R_CS].selector == TARGET_BIOSSEG) @@ -207,8 +211,8 @@ static void do_int(CPUX86State *env, int intno) if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, &ts->vm86plus.int21_revectored)) goto cannot_handle; - int_ptr = (uint32_t *)(intno << 2); - segoffs = tswap32(*int_ptr); + int_addr = (intno << 2); + segoffs = ldl(int_addr); if ((segoffs >> 16) == TARGET_BIOSSEG) goto cannot_handle; #if defined(DEBUG_VM86) @@ -216,7 +220,7 @@ static void do_int(CPUX86State *env, int intno) intno, segoffs >> 16, segoffs & 0xffff); #endif /* save old state */ - ssp = (uint8_t *)(env->segs[R_SS].selector << 4); + ssp = env->segs[R_SS].selector << 4; sp = env->regs[R_ESP] & 0xffff; vm_putw(ssp, sp - 2, get_vflags(env)); vm_putw(ssp, sp - 4, env->segs[R_CS].selector); @@ -259,26 +263,25 @@ void handle_vm86_trap(CPUX86State *env, int trapno) void handle_vm86_fault(CPUX86State *env) { TaskState *ts = env->opaque; - uint8_t *csp, *pc, *ssp; + uint32_t csp, ssp; unsigned int ip, sp, newflags, newip, newcs, opcode, intno; int data32, pref_done; - csp = (uint8_t *)(env->segs[R_CS].selector << 4); + csp = env->segs[R_CS].selector << 4; ip = env->eip & 0xffff; - pc = csp + ip; - ssp = (uint8_t *)(env->segs[R_SS].selector << 4); + ssp = env->segs[R_SS].selector << 4; sp = env->regs[R_ESP] & 0xffff; #if defined(DEBUG_VM86) - fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n", - env->segs[R_CS].selector, env->eip, pc[0], pc[1]); + fprintf(logfile, "VM86 exception %04x:%08x\n", + env->segs[R_CS].selector, env->eip); #endif data32 = 0; pref_done = 0; do { - opcode = csp[ip]; + opcode = vm_getb(csp, ip); ADD16(ip, 1); switch (opcode) { case 0x66: /* 32-bit data */ data32=1; break; @@ -328,7 +331,7 @@ void handle_vm86_fault(CPUX86State *env) VM86_FAULT_RETURN; case 0xcd: /* int */ - intno = csp[ip]; + intno = vm_getb(csp, ip); ADD16(ip, 1); env->eip = ip; if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) { -- cgit v1.2.3 From 28be6234fc968a42e835da1e39f7f5da74823b8c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 22:23:38 +0000 Subject: user access fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3623 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 112 ++++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index c7b1ea89f..287f96d66 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -667,7 +667,7 @@ struct rt_sigframe /* XXX: save x87 state */ static int setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, - CPUX86State *env, unsigned long mask) + CPUX86State *env, abi_ulong mask, abi_ulong fpstate_addr) { int err = 0; uint16_t magic; @@ -693,11 +693,11 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal); err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss); - cpu_x86_fsave(env, (void *)fpstate, 1); + cpu_x86_fsave(env, fpstate_addr, 1); fpstate->status = fpstate->sw; magic = 0xffff; err |= __put_user(magic, &fpstate->magic); - err |= __put_user(fpstate, &sc->fpstate); + err |= __put_user(fpstate_addr, &sc->fpstate); /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); @@ -754,7 +754,8 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, if (err) goto give_sigsegv; - setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0]); + setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0], + frame_addr + offsetof(struct sigframe, fpstate)); if (err) goto give_sigsegv; @@ -769,7 +770,9 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { uint16_t val16; - err |= __put_user(frame->retcode, &frame->pretcode); + abi_ulong retcode_addr; + retcode_addr = frame_addr + offsetof(struct sigframe, retcode); + err |= __put_user(retcode_addr, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ val16 = 0xb858; err |= __put_user(val16, (uint16_t *)(frame->retcode+0)); @@ -782,8 +785,8 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, goto give_sigsegv; /* Set up registers for signal handler */ - env->regs[R_ESP] = h2g(frame); - env->eip = (unsigned long) ka->sa._sa_handler; + env->regs[R_ESP] = frame_addr; + env->eip = ka->sa._sa_handler; cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS); @@ -807,7 +810,7 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUX86State *env) { - abi_ulong frame_addr; + abi_ulong frame_addr, addr; struct rt_sigframe *frame; int i, err = 0; @@ -822,8 +825,10 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, ? current->exec_domain->signal_invmap[sig] : */sig), &frame->sig); - err |= __put_user((abi_ulong)&frame->info, &frame->pinfo); - err |= __put_user((abi_ulong)&frame->uc, &frame->puc); + addr = frame_addr + offsetof(struct rt_sigframe, info); + err |= __put_user(addr, &frame->pinfo); + addr = frame_addr + offsetof(struct rt_sigframe, uc); + err |= __put_user(addr, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; @@ -838,7 +843,8 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, err |= __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, - env, set->sig[0]); + env, set->sig[0], + frame_addr + offsetof(struct rt_sigframe, fpstate)); for(i = 0; i < TARGET_NSIG_WORDS; i++) { if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) goto give_sigsegv; @@ -850,8 +856,8 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { uint16_t val16; - - err |= __put_user(frame->retcode, &frame->pretcode); + addr = frame_addr + offsetof(struct rt_sigframe, retcode); + err |= __put_user(addr, &frame->pretcode); /* This is movl $,%eax ; int $0x80 */ err |= __put_user(0xb8, (char *)(frame->retcode+0)); err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1)); @@ -863,8 +869,8 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, goto give_sigsegv; /* Set up registers for signal handler */ - env->regs[R_ESP] = (unsigned long) frame; - env->eip = (unsigned long) ka->sa._sa_handler; + env->regs[R_ESP] = frame_addr; + env->eip = ka->sa._sa_handler; cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS); @@ -887,49 +893,42 @@ static int restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax) { unsigned int err = 0; - - cpu_x86_load_seg(env, R_GS, lduw(&sc->gs)); - cpu_x86_load_seg(env, R_FS, lduw(&sc->fs)); - cpu_x86_load_seg(env, R_ES, lduw(&sc->es)); - cpu_x86_load_seg(env, R_DS, lduw(&sc->ds)); - - env->regs[R_EDI] = ldl(&sc->edi); - env->regs[R_ESI] = ldl(&sc->esi); - env->regs[R_EBP] = ldl(&sc->ebp); - env->regs[R_ESP] = ldl(&sc->esp); - env->regs[R_EBX] = ldl(&sc->ebx); - env->regs[R_EDX] = ldl(&sc->edx); - env->regs[R_ECX] = ldl(&sc->ecx); - env->eip = ldl(&sc->eip); + abi_ulong fpstate_addr; + unsigned int tmpflags; + + cpu_x86_load_seg(env, R_GS, tswap16(sc->gs)); + cpu_x86_load_seg(env, R_FS, tswap16(sc->fs)); + cpu_x86_load_seg(env, R_ES, tswap16(sc->es)); + cpu_x86_load_seg(env, R_DS, tswap16(sc->ds)); + + env->regs[R_EDI] = tswapl(sc->edi); + env->regs[R_ESI] = tswapl(sc->esi); + env->regs[R_EBP] = tswapl(sc->ebp); + env->regs[R_ESP] = tswapl(sc->esp); + env->regs[R_EBX] = tswapl(sc->ebx); + env->regs[R_EDX] = tswapl(sc->edx); + env->regs[R_ECX] = tswapl(sc->ecx); + env->eip = tswapl(sc->eip); cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3); cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3); - { - unsigned int tmpflags; - tmpflags = ldl(&sc->eflags); - env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); - // regs->orig_eax = -1; /* disable syscall checks */ - } + tmpflags = tswapl(sc->eflags); + env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); + // regs->orig_eax = -1; /* disable syscall checks */ - { - struct _fpstate * buf; - buf = (void *)ldl(&sc->fpstate); - if (buf) { -#if 0 - if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; -#endif - cpu_x86_frstor(env, (void *)buf, 1); - } + fpstate_addr = tswapl(sc->fpstate); + if (fpstate_addr != 0) { + if (!access_ok(VERIFY_READ, fpstate_addr, + sizeof(struct target_fpstate))) + goto badframe; + cpu_x86_frstor(env, fpstate_addr, 1); } - *peax = ldl(&sc->eax); + *peax = tswapl(sc->eax); return err; -#if 0 badframe: return 1; -#endif } long do_sigreturn(CPUX86State *env) @@ -970,27 +969,30 @@ badframe: long do_rt_sigreturn(CPUX86State *env) { - struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env->regs[R_ESP] - 4); + abi_ulong frame_addr; + struct rt_sigframe *frame; sigset_t set; int eax; -#if 0 - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; -#endif + frame_addr = env->regs[R_ESP] - 4; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; target_to_host_sigset(&set, &frame->uc.tuc_sigmask); sigprocmask(SIG_SETMASK, &set, NULL); if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) goto badframe; - if (do_sigaltstack(h2g(&frame->uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, + get_sp_from_cpustate(env)) == -EFAULT) goto badframe; + unlock_user_struct(frame, frame_addr, 0); return eax; badframe: - force_sig(TARGET_SIGSEGV); + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); return 0; } -- cgit v1.2.3 From f8b0aa25599782eef91edc00ebf620bd14db720c Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 23:03:42 +0000 Subject: fixed more invalid pointer usage git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3624 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/signal.c | 103 ++++++++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 287f96d66..730c9a255 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1039,8 +1039,8 @@ struct sigframe struct rt_sigframe { - struct target_siginfo *pinfo; - void *puc; + abi_ulong pinfo; + abi_ulong puc; struct target_siginfo info; struct target_ucontext uc; abi_ulong retcode; @@ -1077,7 +1077,7 @@ static inline int valid_user_regs(CPUState *regs) static int setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ - CPUState *env, unsigned long mask) + CPUState *env, abi_ulong mask) { int err = 0; @@ -1127,9 +1127,9 @@ get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) static int setup_return(CPUState *env, struct emulated_sigaction *ka, - abi_ulong *rc, void *frame, int usig) + abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr) { - abi_ulong handler = (abi_ulong)ka->sa._sa_handler; + abi_ulong handler = ka->sa._sa_handler; abi_ulong retcode; int thumb = 0; #if defined(TARGET_CONFIG_CPU_32) @@ -1160,7 +1160,7 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, #endif /* TARGET_CONFIG_CPU_32 */ if (ka->sa.sa_flags & TARGET_SA_RESTORER) { - retcode = (abi_ulong)ka->sa.sa_restorer; + retcode = ka->sa.sa_restorer; } else { unsigned int idx = thumb; @@ -1173,11 +1173,11 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, flush_icache_range((abi_ulong)rc, (abi_ulong)(rc + 1)); #endif - retcode = ((abi_ulong)rc) + thumb; + retcode = rc_addr + thumb; } env->regs[0] = usig; - env->regs[13] = h2g(frame); + env->regs[13] = frame_addr; env->regs[14] = retcode; env->regs[15] = handler & (thumb ? ~1 : ~3); @@ -1209,7 +1209,8 @@ static void setup_frame(int usig, struct emulated_sigaction *ka, } if (err == 0) - err = setup_return(regs, ka, &frame->retcode, frame, usig); + err = setup_return(regs, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct sigframe, retcode)); end: unlock_user_struct(frame, frame_addr, 1); @@ -1225,12 +1226,15 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); struct target_sigaltstack stack; int i, err = 0; + abi_ulong info_addr, uc_addr; if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) return /* 1 */; - __put_user_error(&frame->info, (abi_ulong *)&frame->pinfo, err); - __put_user_error(&frame->uc, (abi_ulong *)&frame->puc, err); + info_addr = frame_addr + offsetof(struct rt_sigframe, info); + __put_user_error(info_addr, &frame->pinfo, err); + uc_addr = frame_addr + offsetof(struct rt_sigframe, uc); + __put_user_error(uc_addr, &frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); /* Clear all the bits of the ucontext we don't use. */ @@ -1250,7 +1254,8 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, } if (err == 0) - err = setup_return(env, ka, &frame->retcode, frame, usig); + err = setup_return(env, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct rt_sigframe, retcode)); if (err == 0) { /* @@ -1258,8 +1263,8 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, * arguments for the signal handler. * -- Peter Maydell 2000-12-06 */ - env->regs[1] = (abi_ulong)frame->pinfo; - env->regs[2] = (abi_ulong)frame->puc; + env->regs[1] = info_addr; + env->regs[2] = uc_addr; } end: @@ -1302,6 +1307,7 @@ restore_sigcontext(CPUState *env, struct target_sigcontext *sc) long do_sigreturn(CPUState *env) { + abi_ulong frame_addr; struct sigframe *frame; target_sigset_t set; sigset_t host_set; @@ -1315,12 +1321,10 @@ long do_sigreturn(CPUState *env) if (env->regs[13] & 7) goto badframe; - frame = (struct sigframe *)g2h(env->regs[13]); + frame_addr = env->regs[13]; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; -#if 0 - if (verify_area(VERIFY_READ, frame, sizeof (*frame))) - goto badframe; -#endif if (__get_user(set.sig[0], &frame->sc.oldmask)) goto badframe; for(i = 1; i < TARGET_NSIG_WORDS; i++) { @@ -1339,15 +1343,18 @@ long do_sigreturn(CPUState *env) if (ptrace_cancel_bpt(current)) send_sig(SIGTRAP, current, 1); #endif - return env->regs[0]; + unlock_user_struct(frame, frame_addr, 0); + return env->regs[0]; badframe: + unlock_user_struct(frame, frame_addr, 0); force_sig(SIGSEGV /* , current */); return 0; } long do_rt_sigreturn(CPUState *env) { + abi_ulong frame_addr; struct rt_sigframe *frame; sigset_t host_set; @@ -1359,19 +1366,17 @@ long do_rt_sigreturn(CPUState *env) if (env->regs[13] & 7) goto badframe; - frame = (struct rt_sigframe *)env->regs[13]; + frame_addr = env->regs[13]; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; -#if 0 - if (verify_area(VERIFY_READ, frame, sizeof (*frame))) - goto badframe; -#endif target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); sigprocmask(SIG_SETMASK, &host_set, NULL); if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) goto badframe; - if (do_sigaltstack(h2g(&frame->uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) goto badframe; #if 0 @@ -1379,9 +1384,11 @@ long do_rt_sigreturn(CPUState *env) if (ptrace_cancel_bpt(current)) send_sig(SIGTRAP, current, 1); #endif + unlock_user_struct(frame, frame_addr, 0); return env->regs[0]; badframe: + unlock_user_struct(frame, frame_addr, 0); force_sig(SIGSEGV /* , current */); return 0; } @@ -1452,7 +1459,7 @@ typedef struct { struct target_signal_frame { struct sparc_stackf ss; __siginfo_t info; - qemu_siginfo_fpu_t *fpu_save; + abi_ulong fpu_save; abi_ulong insns[2] __attribute__ ((aligned (8))); abi_ulong extramask[TARGET_NSIG_WORDS - 1]; abi_ulong extra_size; /* Should be 0 */ @@ -1463,7 +1470,7 @@ struct target_rt_signal_frame { siginfo_t info; abi_ulong regs[20]; sigset_t mask; - qemu_siginfo_fpu_t *fpu_save; + abi_ulong fpu_save; unsigned int insns[2]; stack_t stack; unsigned int extra_size; /* Should be 0 */ @@ -1677,14 +1684,17 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, long do_sigreturn(CPUState *env) { + abi_ulong sf_addr; struct target_signal_frame *sf; uint32_t up_psr, pc, npc; target_sigset_t set; sigset_t host_set; - abi_ulong fpu_save; + abi_ulong fpu_save_addr; int err, i; - sf = (struct target_signal_frame *)g2h(env->regwptr[UREG_FP]); + sf_addr = env->regwptr[UREG_FP]; + if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) + goto segv_and_exit; #if 0 fprintf(stderr, "sigreturn\n"); fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); @@ -1692,12 +1702,8 @@ long do_sigreturn(CPUState *env) //cpu_dump_state(env, stderr, fprintf, 0); /* 1. Make sure we are not getting garbage from the user */ -#if 0 - if (verify_area (VERIFY_READ, sf, sizeof (*sf))) - goto segv_and_exit; -#endif - if (((uint) sf) & 3) + if (sf_addr & 3) goto segv_and_exit; err = __get_user(pc, &sf->info.si_regs.pc); @@ -1723,7 +1729,7 @@ long do_sigreturn(CPUState *env) err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); } - err |= __get_user(fpu_save, (abi_ulong *)&sf->fpu_save); + err |= __get_user(fpu_save_addr, &sf->fpu_save); //if (fpu_save) // err |= restore_fpu_state(env, fpu_save); @@ -1741,17 +1747,18 @@ long do_sigreturn(CPUState *env) if (err) goto segv_and_exit; - + unlock_user_struct(sf, sf_addr, 0); return env->regwptr[0]; segv_and_exit: + unlock_user_struct(sf, sf_addr, 0); force_sig(TARGET_SIGSEGV); } long do_rt_sigreturn(CPUState *env) { fprintf(stderr, "do_rt_sigreturn: not implemented\n"); - return -ENOSYS; + return -TARGET_ENOSYS; } #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) @@ -2032,13 +2039,13 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, long do_sigreturn(CPUState *env) { fprintf(stderr, "do_sigreturn: not implemented\n"); - return -ENOSYS; + return -TARGET_ENOSYS; } long do_rt_sigreturn(CPUState *env) { fprintf(stderr, "do_rt_sigreturn: not implemented\n"); - return -ENOSYS; + return -TARGET_ENOSYS; } #elif defined(TARGET_ABI_MIPSN32) @@ -2061,13 +2068,13 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, long do_sigreturn(CPUState *env) { fprintf(stderr, "do_sigreturn: not implemented\n"); - return -ENOSYS; + return -TARGET_ENOSYS; } long do_rt_sigreturn(CPUState *env) { fprintf(stderr, "do_rt_sigreturn: not implemented\n"); - return -ENOSYS; + return -TARGET_ENOSYS; } #elif defined(TARGET_ABI_MIPSO32) @@ -2321,9 +2328,9 @@ static void setup_frame(int sig, struct emulated_sigaction * ka, */ regs->gpr[ 4][regs->current_tc] = sig; regs->gpr[ 5][regs->current_tc] = 0; - regs->gpr[ 6][regs->current_tc] = h2g(&frame->sf_sc); - regs->gpr[29][regs->current_tc] = h2g(frame); - regs->gpr[31][regs->current_tc] = h2g(frame->sf_code); + regs->gpr[ 6][regs->current_tc] = frame_addr + offsetof(struct sigframe, sf_sc); + regs->gpr[29][regs->current_tc] = frame_addr; + regs->gpr[31][regs->current_tc] = frame_addr + offsetof(struct sigframe, sf_code); /* The original kernel code sets CP0_EPC to the handler * since it returns to userland using eret * we cannot do this here, and we must set PC directly */ @@ -2396,7 +2403,7 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, long do_rt_sigreturn(CPUState *env) { fprintf(stderr, "do_rt_sigreturn: not implemented\n"); - return -ENOSYS; + return -TARGET_ENOSYS; } #else @@ -2417,13 +2424,13 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, long do_sigreturn(CPUState *env) { fprintf(stderr, "do_sigreturn: not implemented\n"); - return -ENOSYS; + return -TARGET_ENOSYS; } long do_rt_sigreturn(CPUState *env) { fprintf(stderr, "do_rt_sigreturn: not implemented\n"); - return -ENOSYS; + return -TARGET_ENOSYS; } #endif -- cgit v1.2.3 From 8582a53a34b2d3fe811d29703eed7519efdf8f2e Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 11 Nov 2007 23:11:36 +0000 Subject: 64 bit cast for dirent64 git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3625 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6e9052af8..6c8f689ae 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4360,8 +4360,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (reclen > len) break; de->d_reclen = tswap16(reclen); - tswap64s(&de->d_ino); - tswap64s(&de->d_off); + tswap64s((uint64_t *)&de->d_ino); + tswap64s((uint64_t *)&de->d_off); de = (struct dirent64 *)((char *)de + reclen); len -= reclen; } -- cgit v1.2.3 From 6f2d8978728c48ca46f5c01835438508aace5c64 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 12 Nov 2007 00:04:48 +0000 Subject: Fix usage of the -1 constant in the PowerPC target code: fix invalid size casts and/or sign-extensions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3626 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/helper.c | 16 +++++++------- target-ppc/op.c | 20 ++++++++--------- target-ppc/op_helper.c | 59 ++++++++++++++++++++++++++------------------------ target-ppc/translate.c | 10 ++++----- 4 files changed, 54 insertions(+), 51 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index f7df19e1c..4937a7548 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -199,7 +199,7 @@ static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b, pp = pte1 & 0x00000003; } if (ptem == ctx->ptem) { - if (ctx->raddr != (target_ulong)-1) { + if (ctx->raddr != (target_phys_addr_t)-1ULL) { /* all matches should have equal RPN, WIMG & PP */ if ((ctx->raddr & mmask) != (pte1 & mmask)) { if (loglevel != 0) @@ -900,7 +900,7 @@ static always_inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, target_phys_addr_t hash, target_phys_addr_t mask) { - return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask); + return (sdr1 & ((target_phys_addr_t)(-1ULL) << sdr_sh)) | (hash & mask); } static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, @@ -1011,7 +1011,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, ctx->ptem = (vsid << 7) | (pgidx >> 10); } /* Initialize real address with an invalid value */ - ctx->raddr = (target_ulong)-1; + ctx->raddr = (target_phys_addr_t)-1ULL; if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx || env->mmu_model == POWERPC_MMU_SOFT_74xx)) { /* Software TLB search */ @@ -1223,7 +1223,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, int i, ret, zsel, zpr, pr; ret = -1; - raddr = -1; + raddr = (target_phys_addr_t)-1ULL; pr = msr_pr; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; @@ -1306,7 +1306,7 @@ int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, int i, prot, ret; ret = -1; - raddr = -1; + raddr = (target_phys_addr_t)-1ULL; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, @@ -1975,7 +1975,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) case POWERPC_MMU_32B: case POWERPC_MMU_601: /* tlbie invalidate TLBs for all segments */ - addr &= ~((target_ulong)-1 << 28); + addr &= ~((target_ulong)-1ULL << 28); /* XXX: this case should be optimized, * giving a mask to tlb_flush_page */ @@ -2730,7 +2730,7 @@ static always_inline void powerpc_excp (CPUState *env, new_msr &= ~((target_ulong)1 << MSR_LE); /* Jump to handler */ vector = env->excp_vectors[excp]; - if (vector == (target_ulong)-1) { + if (vector == (target_ulong)-1ULL) { cpu_abort(env, "Raised an exception without defined vector %d\n", excp); } @@ -2961,7 +2961,7 @@ void cpu_ppc_reset (void *opaque) #endif env->msr = msr; hreg_compute_hflags(env); - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; /* Be sure no exception or interrupt is pending */ env->pending_interrupts = 0; env->exception_index = POWERPC_EXCP_NONE; diff --git a/target-ppc/op.c b/target-ppc/op.c index 81c426c1a..621b97550 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -959,9 +959,9 @@ void OPPROTO op_add_ze (void) /* divide word */ void OPPROTO op_divw (void) { - if (unlikely(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || + if (unlikely(((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || (int32_t)T1 == 0)) { - T0 = (int32_t)((-1) * ((uint32_t)T0 >> 31)); + T0 = (int32_t)(UINT32_MAX * ((uint32_t)T0 >> 31)); } else { T0 = (int32_t)T0 / (int32_t)T1; } @@ -971,9 +971,9 @@ void OPPROTO op_divw (void) #if defined(TARGET_PPC64) void OPPROTO op_divd (void) { - if (unlikely(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1) || + if (unlikely(((int64_t)T0 == INT64_MIN && (int64_t)T1 == (int64_t)-1LL) || (int64_t)T1 == 0)) { - T0 = (int64_t)((-1ULL) * ((uint64_t)T0 >> 63)); + T0 = (int64_t)(UINT64_MAX * ((uint64_t)T0 >> 63)); } else { T0 = (int64_t)T0 / (int64_t)T1; } @@ -2006,7 +2006,7 @@ void OPPROTO op_check_reservation (void) void OPPROTO op_check_reservation_64 (void) { if ((uint64_t)env->reserve == (uint64_t)(T0 & ~0x00000003)) - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } #endif @@ -2344,7 +2344,7 @@ void OPPROTO op_POWER_sleq (void) void OPPROTO op_POWER_sllq (void) { - uint32_t msk = -1; + uint32_t msk = UINT32_MAX; msk = msk << (T1 & 0x1FUL); if (T1 & 0x20UL) @@ -2357,7 +2357,7 @@ void OPPROTO op_POWER_sllq (void) void OPPROTO op_POWER_slq (void) { - uint32_t msk = -1, tmp; + uint32_t msk = UINT32_MAX, tmp; msk = msk << (T1 & 0x1FUL); if (T1 & 0x20UL) @@ -2373,7 +2373,7 @@ void OPPROTO op_POWER_sraq (void) { env->spr[SPR_MQ] = rotl32(T0, 32 - (T1 & 0x1FUL)); if (T1 & 0x20UL) - T0 = -1L; + T0 = UINT32_MAX; else T0 = (int32_t)T0 >> T1; RETURN(); @@ -2529,7 +2529,7 @@ void OPPROTO op_405_check_satu (void) { if (unlikely(T0 < T2)) { /* Saturate result */ - T0 = -1; + T0 = UINT32_MAX; } RETURN(); } @@ -2602,7 +2602,7 @@ void OPPROTO op_4xx_tlbsx_check (void) int tmp; tmp = xer_so; - if (T0 != -1) + if ((int)T0 != -1) tmp |= 0x02; env->crf[0] = tmp; RETURN(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 2c6cef127..68e90ceb5 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -175,29 +175,29 @@ void do_addmeo_64 (void) void do_divwo (void) { - if (likely(!(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || + if (likely(!(((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || (int32_t)T1 == 0))) { xer_ov = 0; T0 = (int32_t)T0 / (int32_t)T1; } else { xer_ov = 1; - xer_so = 1; - T0 = (-1) * ((uint32_t)T0 >> 31); + T0 = UINT32_MAX * ((uint32_t)T0 >> 31); } + xer_so |= xer_ov; } #if defined(TARGET_PPC64) void do_divdo (void) { - if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1ULL) || + if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == (int64_t)-1LL) || (int64_t)T1 == 0))) { xer_ov = 0; T0 = (int64_t)T0 / (int64_t)T1; } else { xer_ov = 1; - xer_so = 1; - T0 = (-1ULL) * ((uint64_t)T0 >> 63); + T0 = UINT64_MAX * ((uint64_t)T0 >> 63); } + xer_so |= xer_ov; } #endif @@ -247,14 +247,14 @@ void do_mulldo (void) uint64_t tl; muls64(&tl, &th, T0, T1); + T0 = (int64_t)tl; /* If th != 0 && th != -1, then we had an overflow */ - if (likely((th + 1) <= 1)) { + if (likely((uint64_t)(th + 1) <= 1)) { xer_ov = 0; } else { xer_ov = 1; - xer_so = 1; } - T0 = (int64_t)tl; + xer_so |= xer_ov; } #endif @@ -392,7 +392,7 @@ void do_sraw (void) xer_ca = 0; } } else { - ret = (-1) * ((uint32_t)T0 >> 31); + ret = UINT32_MAX * ((uint32_t)T0 >> 31); if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) { xer_ca = 0; } else { @@ -420,7 +420,7 @@ void do_srad (void) xer_ca = 0; } } else { - ret = (-1) * ((uint64_t)T0 >> 63); + ret = UINT64_MAX * ((uint64_t)T0 >> 63); if (likely(ret >= 0 || ((uint64_t)T0 & ~0x8000000000000000ULL) == 0)) { xer_ca = 0; } else { @@ -609,7 +609,7 @@ static always_inline void fload_invalid_op_excp (int op) env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); if (ve == 0) { /* Set the result to quiet NaN */ - FT0 = (uint64_t)-1; + FT0 = UINT64_MAX; env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr |= 0x11 << FPSCR_FPCC; } @@ -620,7 +620,7 @@ static always_inline void fload_invalid_op_excp (int op) env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); if (ve == 0) { /* Set the result to quiet NaN */ - FT0 = (uint64_t)-1; + FT0 = UINT64_MAX; env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr |= 0x11 << FPSCR_FPCC; } @@ -1555,8 +1555,9 @@ void do_POWER_div (void) { uint64_t tmp; - if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) { - T0 = (long)((-1) * (T0 >> 31)); + if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || + (int32_t)T1 == 0) { + T0 = UINT32_MAX * ((uint32_t)T0 >> 31); env->spr[SPR_MQ] = 0; } else { tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; @@ -1569,29 +1570,30 @@ void do_POWER_divo (void) { int64_t tmp; - if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) { - T0 = (long)((-1) * (T0 >> 31)); + if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || + (int32_t)T1 == 0) { + T0 = UINT32_MAX * ((uint32_t)T0 >> 31); env->spr[SPR_MQ] = 0; xer_ov = 1; - xer_so = 1; } else { tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; env->spr[SPR_MQ] = tmp % T1; tmp /= (int32_t)T1; if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) { xer_ov = 1; - xer_so = 1; } else { xer_ov = 0; } T0 = tmp; } + xer_so |= xer_ov; } void do_POWER_divs (void) { - if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) { - T0 = (long)((-1) * (T0 >> 31)); + if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || + (int32_t)T1 == 0) { + T0 = UINT32_MAX * ((uint32_t)T0 >> 31); env->spr[SPR_MQ] = 0; } else { env->spr[SPR_MQ] = T0 % T1; @@ -1601,16 +1603,17 @@ void do_POWER_divs (void) void do_POWER_divso (void) { - if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) { - T0 = (long)((-1) * (T0 >> 31)); + if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || + (int32_t)T1 == 0) { + T0 = UINT32_MAX * ((uint32_t)T0 >> 31); env->spr[SPR_MQ] = 0; xer_ov = 1; - xer_so = 1; } else { T0 = (int32_t)T0 / (int32_t)T1; env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1; xer_ov = 0; } + xer_so |= xer_ov; } void do_POWER_dozo (void) @@ -1636,10 +1639,10 @@ void do_POWER_maskg (void) uint32_t ret; if ((uint32_t)T0 == (uint32_t)(T1 + 1)) { - ret = -1; + ret = UINT32_MAX; } else { - ret = (((uint32_t)(-1)) >> ((uint32_t)T0)) ^ - (((uint32_t)(-1) >> ((uint32_t)T1)) >> 1); + ret = (UINT32_MAX >> ((uint32_t)T0)) ^ + ((UINT32_MAX >> ((uint32_t)T1)) >> 1); if ((uint32_t)T0 > (uint32_t)T1) ret = ~ret; } @@ -1874,7 +1877,7 @@ void do_brinc (void) { uint32_t a, b, d, mask; - mask = (uint32_t)(-1UL) >> MASKBITS; + mask = UINT32_MAX >> MASKBITS; b = T1_64 & mask; a = T0_64 & mask; d = word_reverse(1 + word_reverse(a | ~mask)); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 73b2e2212..be4ac5390 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -404,15 +404,15 @@ static always_inline target_ulong MASK (uint32_t start, uint32_t end) #if defined(TARGET_PPC64) if (likely(start == 0)) { - ret = (uint64_t)(-1ULL) << (63 - end); + ret = UINT64_MAX << (63 - end); } else if (likely(end == 63)) { - ret = (uint64_t)(-1ULL) >> start; + ret = UINT64_MAX >> start; } #else if (likely(start == 0)) { - ret = (uint32_t)(-1ULL) << (31 - end); + ret = UINT32_MAX << (31 - end); } else if (likely(end == 31)) { - ret = (uint32_t)(-1ULL) >> start; + ret = UINT32_MAX >> start; } #endif else { @@ -3517,7 +3517,7 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) } #if 1 -#define SPR_NOACCESS ((void *)(-1)) +#define SPR_NOACCESS ((void *)(-1UL)) #else static void spr_noaccess (void *opaque, int sprn) { -- cgit v1.2.3 From a73666f6564e17adcae2908f7b52d42de2ff5211 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 12 Nov 2007 00:50:50 +0000 Subject: More PowerPC target -1 usage fixes (reservation address). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3627 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 2 +- target-ppc/op_mem.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 621b97550..05a6de31d 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1998,7 +1998,7 @@ void OPPROTO op_fneg (void) void OPPROTO op_check_reservation (void) { if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003)) - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index b1daf848d..560a0edae 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -678,7 +678,7 @@ void OPPROTO glue(op_stwcx, MEMSUFFIX) (void) env->crf[0] = xer_so | 0x02; } } - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } @@ -695,7 +695,7 @@ void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void) env->crf[0] = xer_so | 0x02; } } - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } @@ -711,7 +711,7 @@ void OPPROTO glue(op_stdcx, MEMSUFFIX) (void) env->crf[0] = xer_so | 0x02; } } - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } @@ -727,7 +727,7 @@ void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void) env->crf[0] = xer_so | 0x02; } } - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } #endif @@ -744,7 +744,7 @@ void OPPROTO glue(op_stwcx_le, MEMSUFFIX) (void) env->crf[0] = xer_so | 0x02; } } - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } @@ -761,7 +761,7 @@ void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void) env->crf[0] = xer_so | 0x02; } } - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } @@ -777,7 +777,7 @@ void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void) env->crf[0] = xer_so | 0x02; } } - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } @@ -793,7 +793,7 @@ void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void) env->crf[0] = xer_so | 0x02; } } - env->reserve = -1; + env->reserve = (target_ulong)-1ULL; RETURN(); } #endif -- cgit v1.2.3 From 3cd7d1ddbba67a79854ea258cdf3a07eb0ad5136 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 12 Nov 2007 01:56:18 +0000 Subject: Allow use of SPE extension by all PowerPC targets, adding gprh registers to store GPR MSBs when GPRs are 32 bits. Remove not-needed-anymore ppcemb-linux-user target. Keep ppcemb-softmmu target, which provides 1kB pages support and 36 bits physical address space. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3628 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 +- darwin-user/main.c | 2 - linux-user/main.c | 2 - target-ppc/cpu.h | 57 +++++++++++++----------- target-ppc/helper.c | 21 --------- target-ppc/op.c | 2 - target-ppc/op_helper.c | 14 +++--- target-ppc/op_helper.h | 4 -- target-ppc/op_mem.h | 6 --- target-ppc/op_template.h | 13 +++--- target-ppc/translate.c | 112 +++++++++++++++++++++++++++++++++++++++++++---- 11 files changed, 149 insertions(+), 86 deletions(-) diff --git a/configure b/configure index 897df1029..535876d6a 100755 --- a/configure +++ b/configure @@ -520,7 +520,7 @@ if test -z "$target_list" ; then fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppcemb-linux-user ppc64-linux-user ppc64abi32-linux-user x86_64-linux-user cris-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppc64-linux-user ppc64abi32-linux-user x86_64-linux-user cris-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then diff --git a/darwin-user/main.c b/darwin-user/main.c index 607d3d65f..0a371dedf 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -357,7 +357,6 @@ void cpu_loop(CPUPPCState *env) case POWERPC_EXCP_DEBUG: /* Debug interrupt */ gdb_handlesig (env, SIGTRAP); break; -#if defined(TARGET_PPCEMB) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */ EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n"); info.si_signo = SIGILL; @@ -383,7 +382,6 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Doorbell critical interrupt while in user mode. " "Aborting\n"); break; -#endif /* defined(TARGET_PPCEMB) */ case POWERPC_EXCP_RESET: /* System reset exception */ cpu_abort(env, "Reset interrupt while in user mode. " "Aborting\n"); diff --git a/linux-user/main.c b/linux-user/main.c index 5cc2d4137..eb5861ad1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -976,7 +976,6 @@ void cpu_loop(CPUPPCState *env) } } break; -#if defined(TARGET_PPCEMB) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */ EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n"); info.si_signo = TARGET_SIGILL; @@ -1006,7 +1005,6 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Reset interrupt while in user mode. " "Aborting\n"); break; -#endif /* defined(TARGET_PPCEMB) */ #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) /* PowerPC 64 */ case POWERPC_EXCP_DSEG: /* Data segment exception */ cpu_abort(env, "Data segment exception while in user mode. " diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 198da43f3..a463b457c 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -24,46 +24,51 @@ #include #if defined (TARGET_PPC64) +/* PowerPC 64 definitions */ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 #define TARGET_LONG_BITS 64 #define REGX "%016" PRIx64 #define TARGET_PAGE_BITS 12 -#elif defined(TARGET_PPCEMB) -/* BookE have 36 bits physical address space */ -#define TARGET_PHYS_ADDR_BITS 64 -/* GPR are 64 bits: used by vector extension */ -typedef uint64_t ppc_gpr_t; -#define TARGET_GPR_BITS 64 -#define TARGET_LONG_BITS 32 -#define REGX "%016" PRIx64 -#if defined(CONFIG_USER_ONLY) -/* It looks like a lot of Linux programs assume page size - * is 4kB long. This is evil, but we have to deal with it... - */ -#define TARGET_PAGE_BITS 12 -#else -/* Pages can be 1 kB small */ -#define TARGET_PAGE_BITS 10 -#endif -#else + +#else /* defined (TARGET_PPC64) */ +/* PowerPC 32 definitions */ #if (HOST_LONG_BITS >= 64) /* When using 64 bits temporary registers, * we can use 64 bits GPR with no extra cost - * It's even an optimization as it will prevent + * It's even an optimization as this will prevent * the compiler to do unuseful masking in the micro-ops. */ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 #define REGX "%08" PRIx64 -#else +#else /* (HOST_LONG_BITS >= 64) */ typedef uint32_t ppc_gpr_t; #define TARGET_GPR_BITS 32 #define REGX "%08" PRIx32 -#endif +#endif /* (HOST_LONG_BITS >= 64) */ + #define TARGET_LONG_BITS 32 + +#if defined(TARGET_PPCEMB) +/* Specific definitions for PowerPC embedded */ +/* BookE have 36 bits physical address space */ +#define TARGET_PHYS_ADDR_BITS 64 +#if defined(CONFIG_USER_ONLY) +/* It looks like a lot of Linux programs assume page size + * is 4kB long. This is evil, but we have to deal with it... + */ #define TARGET_PAGE_BITS 12 -#endif +#else /* defined(CONFIG_USER_ONLY) */ +/* Pages can be 1 kB small */ +#define TARGET_PAGE_BITS 10 +#endif /* defined(CONFIG_USER_ONLY) */ +#else /* defined(TARGET_PPCEMB) */ +/* "standard" PowerPC 32 definitions */ +#define TARGET_PAGE_BITS 12 +#endif /* defined(TARGET_PPCEMB) */ + +#endif /* defined (TARGET_PPC64) */ #include "cpu-defs.h" @@ -166,14 +171,12 @@ enum { POWERPC_EXCP_ITLB = 14, /* Instruction TLB error */ POWERPC_EXCP_DEBUG = 15, /* Debug interrupt */ /* Vectors 16 to 31 are reserved */ -#if defined(TARGET_PPCEMB) POWERPC_EXCP_SPEU = 32, /* SPE/embedded floating-point unavailable */ POWERPC_EXCP_EFPDI = 33, /* Embedded floating-point data interrupt */ POWERPC_EXCP_EFPRI = 34, /* Embedded floating-point round interrupt */ POWERPC_EXCP_EPERFM = 35, /* Embedded performance monitor interrupt */ POWERPC_EXCP_DOORI = 36, /* Embedded doorbell interrupt */ POWERPC_EXCP_DOORCI = 37, /* Embedded doorbell critical interrupt */ -#endif /* defined(TARGET_PPCEMB) */ /* Vectors 38 to 63 are reserved */ /* Exceptions defined in the PowerPC server specification */ POWERPC_EXCP_RESET = 64, /* System reset exception */ @@ -527,6 +530,10 @@ struct CPUPPCState { /* general purpose registers */ ppc_gpr_t gpr[32]; +#if TARGET_GPR_BITS < 64 + /* Storage for GPR MSB, used by the SPE extension */ + ppc_gpr_t gprh[32]; +#endif /* LR */ target_ulong lr; /* CTR */ @@ -597,12 +604,10 @@ struct CPUPPCState { /* Altivec registers */ ppc_avr_t avr[32]; uint32_t vscr; -#if defined(TARGET_PPCEMB) /* SPE registers */ ppc_gpr_t spe_acc; float_status spe_status; uint32_t spe_fscr; -#endif /* Internal devices resources */ /* Time base and decrementer */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4937a7548..268703cd4 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2395,7 +2395,6 @@ static always_inline void powerpc_excp (CPUState *env, /* XXX: TODO */ cpu_abort(env, "Debug exception is not implemented yet !\n"); goto store_next; -#if defined(TARGET_PPCEMB) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ goto store_current; @@ -2433,7 +2432,6 @@ static always_inline void powerpc_excp (CPUState *env, cpu_abort(env, "Embedded doorbell critical interrupt " "is not implemented yet !\n"); goto store_next; -#endif /* defined(TARGET_PPCEMB) */ case POWERPC_EXCP_RESET: /* System reset exception */ new_msr &= ~((target_ulong)1 << MSR_RI); #if defined(TARGET_PPC64H) @@ -2833,26 +2831,11 @@ void ppc_hw_interrupt (CPUPPCState *env) powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT); return; } -#if defined(TARGET_PPCEMB) if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI); return; } -#endif -#if defined(TARGET_PPCEMB) - /* External interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { - /* Taking an external interrupt does not clear the external - * interrupt status - */ -#if 0 - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); -#endif - powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL); - return; - } -#endif /* Fixed interval timer on embedded PowerPC */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); @@ -2871,7 +2854,6 @@ void ppc_hw_interrupt (CPUPPCState *env) powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR); return; } -#if !defined(TARGET_PPCEMB) /* External interrupt */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { /* Taking an external interrupt does not clear the external @@ -2883,14 +2865,11 @@ void ppc_hw_interrupt (CPUPPCState *env) powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL); return; } -#endif -#if defined(TARGET_PPCEMB) if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI); return; } -#endif if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM); diff --git a/target-ppc/op.c b/target-ppc/op.c index 05a6de31d..9bf16f5b3 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -2720,7 +2720,6 @@ void OPPROTO op_store_booke_tsr (void) } #endif /* !defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_PPCEMB) /* SPE extension */ void OPPROTO op_splatw_T1_64 (void) { @@ -3439,4 +3438,3 @@ void OPPROTO op_efdtsteq (void) T0 = _do_efdtsteq(T0_64, T1_64); RETURN(); } -#endif /* defined(TARGET_PPCEMB) */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 68e90ceb5..1dde1a18c 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1853,7 +1853,6 @@ void do_440_dlmzb (void) T0 = i; } -#if defined(TARGET_PPCEMB) /* SPE extension helpers */ /* Use a table to make this quicker */ static uint8_t hbrev[16] = { @@ -1872,16 +1871,16 @@ static always_inline uint32_t word_reverse (uint32_t val) (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24); } -#define MASKBITS 16 // Random value - to be fixed +#define MASKBITS 16 // Random value - to be fixed (implementation dependant) void do_brinc (void) { uint32_t a, b, d, mask; - mask = UINT32_MAX >> MASKBITS; - b = T1_64 & mask; - a = T0_64 & mask; - d = word_reverse(1 + word_reverse(a | ~mask)); - T0_64 = (T0_64 & ~mask) | (d & mask); + mask = UINT32_MAX >> (32 - MASKBITS); + a = T0 & mask; + b = T1 & mask; + d = word_reverse(1 + word_reverse(a | ~b)); + T0 = (T0 & ~mask) | (d & b); } #define DO_SPE_OP2(name) \ @@ -2713,7 +2712,6 @@ DO_SPE_OP1(fsctuiz); DO_SPE_OP1(fsctsf); /* evfsctuf */ DO_SPE_OP1(fsctuf); -#endif /* defined(TARGET_PPCEMB) */ /*****************************************************************************/ /* Softmmu support */ diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 5b77cb25a..657825fa2 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -205,7 +205,6 @@ void do_load_403_pb (int num); void do_store_403_pb (int num); #endif -#if defined(TARGET_PPCEMB) /* SPE extension helpers */ void do_brinc (void); /* Fixed-point vector helpers */ @@ -286,9 +285,7 @@ void do_evfsctsi (void); void do_evfsctui (void); void do_evfsctsiz (void); void do_evfsctuiz (void); -#endif /* defined(TARGET_PPCEMB) */ -#if defined(TARGET_PPCEMB) /* SPE extension */ /* Single precision floating-point helpers */ static always_inline uint32_t _do_efsabs (uint32_t val) @@ -409,5 +406,4 @@ static always_inline int _do_efdtsteq (uint64_t op1, uint64_t op2) u2.u = op2; return float64_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0; } -#endif /* defined(TARGET_PPCEMB) */ #endif diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 560a0edae..971cc1838 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -37,7 +37,6 @@ static always_inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); } -#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) static always_inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) { uint64_t tmp = glue(ldq, MEMSUFFIX)(EA); @@ -50,7 +49,6 @@ static always_inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) ((tmp & 0x000000000000FF00ULL) << 40) | ((tmp & 0x00000000000000FFULL) << 54); } -#endif #if defined(TARGET_PPC64) static always_inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA) @@ -81,7 +79,6 @@ static always_inline void glue(st32r, MEMSUFFIX) (target_ulong EA, glue(stl, MEMSUFFIX)(EA, tmp); } -#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) static always_inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t data) { @@ -95,7 +92,6 @@ static always_inline void glue(st64r, MEMSUFFIX) (target_ulong EA, ((data & 0x00000000000000FFULL) << 56); glue(stq, MEMSUFFIX)(EA, tmp); } -#endif /*** Integer load ***/ #define PPC_LD_OP(name, op) \ @@ -1123,7 +1119,6 @@ void OPPROTO glue(op_vr_stvx_le_64, MEMSUFFIX) (void) #undef VR_DWORD0 #undef VR_DWORD1 -#if defined(TARGET_PPCEMB) /* SPE extension */ #define _PPC_SPE_LD_OP(name, op) \ void OPPROTO glue(glue(op_spe_l, name), MEMSUFFIX) (void) \ @@ -1385,6 +1380,5 @@ uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA) return ret; } PPC_SPE_LD_OP(whsplat_le, spe_lwhsplat_le); -#endif /* defined(TARGET_PPCEMB) */ #undef MEMSUFFIX diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 51f9b3681..26a066245 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -58,23 +58,23 @@ void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) #endif /* General purpose registers containing vector operands moves */ -#if defined(TARGET_PPCEMB) +#if TARGET_GPR_BITS < 64 void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void) { - T0_64 = env->gpr[REG]; + T0_64 = (uint64_t)env->gpr[REG] | ((uint64_t)env->gprh[REG] << 32); RETURN(); } void OPPROTO glue(op_load_gpr64_T1_gpr, REG) (void) { - T1_64 = env->gpr[REG]; + T1_64 = (uint64_t)env->gpr[REG] | ((uint64_t)env->gprh[REG] << 32); RETURN(); } #if 0 // unused void OPPROTO glue(op_load_gpr64_T2_gpr, REG) (void) { - T2_64 = env->gpr[REG]; + T2_64 = (uint64_t)env->gpr[REG] | ((uint64_t)env->gprh[REG] << 32); RETURN(); } #endif @@ -82,12 +82,14 @@ void OPPROTO glue(op_load_gpr64_T2_gpr, REG) (void) void OPPROTO glue(op_store_T0_gpr64_gpr, REG) (void) { env->gpr[REG] = T0_64; + env->gprh[REG] = T0_64 >> 32; RETURN(); } void OPPROTO glue(op_store_T1_gpr64_gpr, REG) (void) { env->gpr[REG] = T1_64; + env->gprh[REG] = T1_64 >> 32; RETURN(); } @@ -95,10 +97,11 @@ void OPPROTO glue(op_store_T1_gpr64_gpr, REG) (void) void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) { env->gpr[REG] = T2_64; + env->gprh[REG] = T2_64 >> 32; RETURN(); } #endif -#endif /* defined(TARGET_PPCEMB) */ +#endif /* TARGET_GPR_BITS < 64 */ /* Altivec registers moves */ void OPPROTO glue(op_load_avr_A0_avr, REG) (void) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index be4ac5390..d1741b6a3 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -162,9 +162,7 @@ typedef struct DisasContext { #endif int fpu_enabled; int altivec_enabled; -#if defined(TARGET_PPCEMB) int spe_enabled; -#endif ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; int dcache_line_size; @@ -5821,10 +5819,11 @@ GEN_VR_STX(vx, 0x07, 0x07); #define gen_op_vr_stvxl gen_op_vr_stvx GEN_VR_STX(vxl, 0x07, 0x0F); -#if defined(TARGET_PPCEMB) /*** SPE extension ***/ /* Register moves */ +#if TARGET_GPR_BITS < 64 + GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr); GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr); #if 0 // unused @@ -5837,6 +5836,23 @@ GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr); GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr); #endif +#else /* TARGET_GPR_BITS < 64 */ + +/* No specific load/store functions: GPRs are already 64 bits */ +#define gen_op_load_gpr64_T0 gen_op_load_gpr_T0 +#define gen_op_load_gpr64_T1 gen_op_load_gpr_T1 +#if 0 // unused +#define gen_op_load_gpr64_T2 gen_op_load_gpr_T2 +#endif + +#define gen_op_store_T0_gpr64 gen_op_store_T0_gpr +#define gen_op_store_T1_gpr64 gen_op_store_T1_gpr +#if 0 // unused +#define gen_op_store_T2_gpr64 gen_op_store_T2_gpr +#endif + +#endif /* TARGET_GPR_BITS < 64 */ + #define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) \ { \ @@ -6105,10 +6121,10 @@ GEN_SPEOP_ARITH1(evcntlsw); static always_inline void gen_brinc (DisasContext *ctx) { /* Note: brinc is usable even if SPE is disabled */ - gen_op_load_gpr64_T0(rA(ctx->opcode)); - gen_op_load_gpr64_T1(rB(ctx->opcode)); + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_brinc(); - gen_op_store_T0_gpr64(rD(ctx->opcode)); + gen_op_store_T0_gpr(rD(ctx->opcode)); } #define GEN_SPEOP_ARITH_IMM2(name) \ @@ -6242,6 +6258,12 @@ GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE) #define gen_op_spe_stdd_le_raw gen_op_std_le_raw #define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw #else /* defined(CONFIG_USER_ONLY) */ +#if defined(TARGET_PPC64H) +#define gen_op_spe_ldd_hypv gen_op_ld_hypv +#define gen_op_spe_ldd_64_hypv gen_op_ld_64_hypv +#define gen_op_spe_ldd_le_hypv gen_op_ld_hypv +#define gen_op_spe_ldd_le_64_hypv gen_op_ld_64_hypv +#endif #define gen_op_spe_ldd_kernel gen_op_ld_kernel #define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel #define gen_op_spe_ldd_le_kernel gen_op_ld_kernel @@ -6250,6 +6272,12 @@ GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE) #define gen_op_spe_ldd_64_user gen_op_ld_64_user #define gen_op_spe_ldd_le_user gen_op_ld_le_user #define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user +#if defined(TARGET_PPC64H) +#define gen_op_spe_stdd_hypv gen_op_std_hypv +#define gen_op_spe_stdd_64_hypv gen_op_std_64_hypv +#define gen_op_spe_stdd_le_hypv gen_op_std_hypv +#define gen_op_spe_stdd_le_64_hypv gen_op_std_64_hypv +#endif #define gen_op_spe_stdd_kernel gen_op_std_kernel #define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel #define gen_op_spe_stdd_le_kernel gen_op_std_kernel @@ -6284,6 +6312,12 @@ GEN_SPEOP_ST(who, 2); #define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel #define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel #define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel +#if defined(TARGET_PPC64H) +#define gen_op_spe_stwwo_hypv gen_op_stw_hypv +#define gen_op_spe_stwwo_le_hypv gen_op_stw_le_hypv +#define gen_op_spe_stwwo_64_hypv gen_op_stw_64_hypv +#define gen_op_spe_stwwo_le_64_hypv gen_op_stw_le_64_hypv +#endif #endif #endif #define _GEN_OP_SPE_STWWE(suffix) \ @@ -6320,6 +6354,9 @@ _GEN_OP_SPE_STWWE_LE(suffix) #if defined(CONFIG_USER_ONLY) GEN_OP_SPE_STWWE(raw); #else /* defined(CONFIG_USER_ONLY) */ +#if defined(TARGET_PPC64H) +GEN_OP_SPE_STWWE(hypv); +#endif GEN_OP_SPE_STWWE(kernel); GEN_OP_SPE_STWWE(user); #endif /* defined(CONFIG_USER_ONLY) */ @@ -6371,45 +6408,105 @@ GEN_OP_SPE_LHX(le_64_raw); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw); #endif #else +#if defined(TARGET_PPC64H) +GEN_OP_SPE_LHE(hypv); +#endif GEN_OP_SPE_LHE(kernel); GEN_OP_SPE_LHE(user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, hypv); +#endif GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel); GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user); +#if defined(TARGET_PPC64H) +GEN_OP_SPE_LHE(le_hypv); +#endif GEN_OP_SPE_LHE(le_kernel); GEN_OP_SPE_LHE(le_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_hypv); +#endif GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel); GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhousplat, spe_lh, hypv); +#endif GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel); GEN_SPE_LDSPLAT(hhousplat, spe_lh, user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_hypv); +#endif GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel); GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user); +#if defined(TARGET_PPC64H) +GEN_OP_SPE_LHX(hypv); +#endif GEN_OP_SPE_LHX(kernel); GEN_OP_SPE_LHX(user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, hypv); +#endif GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user); +#if defined(TARGET_PPC64H) +GEN_OP_SPE_LHX(le_hypv); +#endif GEN_OP_SPE_LHX(le_kernel); GEN_OP_SPE_LHX(le_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_hypv); +#endif GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user); #if defined(TARGET_PPC64) +#if defined(TARGET_PPC64H) +GEN_OP_SPE_LHE(64_hypv); +#endif GEN_OP_SPE_LHE(64_kernel); GEN_OP_SPE_LHE(64_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_hypv); +#endif GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel); GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user); +#if defined(TARGET_PPC64H) +GEN_OP_SPE_LHE(le_64_hypv); +#endif GEN_OP_SPE_LHE(le_64_kernel); GEN_OP_SPE_LHE(le_64_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_hypv); +#endif GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel); GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_hypv); +#endif GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel); GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_hypv); +#endif GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel); GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user); +#if defined(TARGET_PPC64H) +GEN_OP_SPE_LHX(64_hypv); +#endif GEN_OP_SPE_LHX(64_kernel); GEN_OP_SPE_LHX(64_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_hypv); +#endif GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user); +#if defined(TARGET_PPC64H) +GEN_OP_SPE_LHX(le_64_hypv); +#endif GEN_OP_SPE_LHX(le_64_kernel); GEN_OP_SPE_LHX(le_64_user); +#if defined(TARGET_PPC64H) +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_hypv); +#endif GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user); #endif @@ -6663,7 +6760,6 @@ GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPEFPU); // GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPEFPU); // GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPEFPU); // GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPEFPU); // -#endif /* End opcode list */ GEN_OPCODE_MARK(end); @@ -6830,12 +6926,10 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, #endif ctx.dcache_line_size = env->dcache_line_size; ctx.fpu_enabled = msr_fp; -#if defined(TARGET_PPCEMB) if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) ctx.spe_enabled = msr_spe; else ctx.spe_enabled = 0; -#endif if ((env->flags & POWERPC_FLAG_VRE) && msr_vr) ctx.altivec_enabled = msr_vr; else -- cgit v1.2.3 From 87518e0ca36b30429bf4374dfdbf15fdf8a6aeeb Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Nov 2007 21:16:08 +0000 Subject: reduce verbosity git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3629 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/op_mem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-alpha/op_mem.h b/target-alpha/op_mem.h index 4a0cfc799..5bf73afca 100644 --- a/target-alpha/op_mem.h +++ b/target-alpha/op_mem.h @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define DEBUG_MEM_ACCESSES +//#define DEBUG_MEM_ACCESSES #if defined (DEBUG_MEM_ACCESSES) void helper_print_mem_EA (target_ulong EA); #define print_mem_EA(EA) do { helper_print_mem_EA(EA); } while (0) -- cgit v1.2.3 From 4f6cf9e839313f2da5a6690363fbe1756c20c2ca Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Nov 2007 23:12:17 +0000 Subject: added missing return git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3630 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-m68k/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 8fef67226..460ef3c03 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -100,6 +100,7 @@ static int cpu_m68k_set_model(CPUM68KState *env, const char *name) } register_m68k_insns(env); + return 0; } void cpu_reset(CPUM68KState *env) -- cgit v1.2.3 From 65d6c0f33c1a496d2a782bb0ef2ef18d4ed6b763 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 12 Nov 2007 23:29:14 +0000 Subject: PowerPC SPE extension fix: must always preserve GPR high bits when running in 32 bits mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3631 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 2 +- target-ppc/op_template.h | 4 ++-- target-ppc/translate.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index a463b457c..7589ba215 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -530,7 +530,7 @@ struct CPUPPCState { /* general purpose registers */ ppc_gpr_t gpr[32]; -#if TARGET_GPR_BITS < 64 +#if !defined(TARGET_PPC64) /* Storage for GPR MSB, used by the SPE extension */ ppc_gpr_t gprh[32]; #endif diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h index 26a066245..e6d6afac5 100644 --- a/target-ppc/op_template.h +++ b/target-ppc/op_template.h @@ -58,7 +58,7 @@ void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) #endif /* General purpose registers containing vector operands moves */ -#if TARGET_GPR_BITS < 64 +#if !defined(TARGET_PPC64) void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void) { T0_64 = (uint64_t)env->gpr[REG] | ((uint64_t)env->gprh[REG] << 32); @@ -101,7 +101,7 @@ void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) RETURN(); } #endif -#endif /* TARGET_GPR_BITS < 64 */ +#endif /* !defined(TARGET_PPC64) */ /* Altivec registers moves */ void OPPROTO glue(op_load_avr_A0_avr, REG) (void) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d1741b6a3..8663eabb4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -5822,7 +5822,7 @@ GEN_VR_STX(vxl, 0x07, 0x0F); /*** SPE extension ***/ /* Register moves */ -#if TARGET_GPR_BITS < 64 +#if !defined(TARGET_PPC64) GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr); GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr); @@ -5836,7 +5836,7 @@ GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr); GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr); #endif -#else /* TARGET_GPR_BITS < 64 */ +#else /* !defined(TARGET_PPC64) */ /* No specific load/store functions: GPRs are already 64 bits */ #define gen_op_load_gpr64_T0 gen_op_load_gpr_T0 @@ -5851,7 +5851,7 @@ GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr); #define gen_op_store_T2_gpr64 gen_op_store_T2_gpr #endif -#endif /* TARGET_GPR_BITS < 64 */ +#endif /* !defined(TARGET_PPC64) */ #define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) \ -- cgit v1.2.3 From c3e3682388f422921b2ae13264d35859981da752 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 12 Nov 2007 23:40:49 +0000 Subject: Add PVR and SPR definition for most embedded PowerPC from Freescale. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3632 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate_init.c | 368 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 309 insertions(+), 59 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 20a24b453..d663f79e4 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4750,43 +4750,179 @@ enum { CPU_POWERPC_464H90FP = xxx, #endif /* Freescale embedded PowerPC cores */ + /* PowerPC MPC 5xx cores (aka RCPU) */ + CPU_POWERPC_5xx = 0x00020020, +#define CPU_POWERPC_509 CPU_POWERPC_5xx +#define CPU_POWERPC_533 CPU_POWERPC_5xx +#define CPU_POWERPC_534 CPU_POWERPC_5xx +#define CPU_POWERPC_555 CPU_POWERPC_5xx +#define CPU_POWERPC_556 CPU_POWERPC_5xx +#define CPU_POWERPC_560 CPU_POWERPC_5xx +#define CPU_POWERPC_561 CPU_POWERPC_5xx +#define CPU_POWERPC_562 CPU_POWERPC_5xx +#define CPU_POWERPC_563 CPU_POWERPC_5xx +#define CPU_POWERPC_564 CPU_POWERPC_5xx +#define CPU_POWERPC_565 CPU_POWERPC_5xx +#define CPU_POWERPC_566 CPU_POWERPC_5xx + /* PowerPC MPC 8xx cores (aka PowerQUICC) */ + CPU_POWERPC_8xx = 0x00500000, +#define CPU_POWERPC_821 CPU_POWERPC_8xx +#define CPU_POWERPC_823 CPU_POWERPC_8xx +#define CPU_POWERPC_850 CPU_POWERPC_8xx +#define CPU_POWERPC_852T CPU_POWERPC_8xx +#define CPU_POWERPC_855T CPU_POWERPC_8xx +#define CPU_POWERPC_859 CPU_POWERPC_8xx +#define CPU_POWERPC_860 CPU_POWERPC_8xx +#define CPU_POWERPC_862 CPU_POWERPC_8xx +#define CPU_POWERPC_866 CPU_POWERPC_8xx +#define CPU_POWERPC_857 CPU_POWERPC_8xx +#define CPU_POWERPC_870 CPU_POWERPC_8xx +#define CPU_POWERPC_875 CPU_POWERPC_8xx +#define CPU_POWERPC_880 CPU_POWERPC_8xx +#define CPU_POWERPC_885 CPU_POWERPC_8xx + /* G2 cores (aka PowerQUICC-II) */ + CPU_POWERPC_G2 = 0x00810011, + CPU_POWERPC_G2H4 = 0x80811010, + CPU_POWERPC_G2gp = 0x80821010, + CPU_POWERPC_G2ls = 0x90810010, + CPU_POWERPC_MPC603 = 0x00810100, +#define CPU_POWERPC_MPC8240 CPU_POWERPC_MPC603 + CPU_POWERPC_G2_HIP3 = 0x00810101, +#define CPU_POWERPC_MPC8250_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8255_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8260_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8264_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8265_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8266_HiP3 CPU_POWERPC_G2_HIP3 + CPU_POWERPC_G2_HIP4 = 0x80811014, +#define CPU_POWERPC_MPC8241 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8245 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8250_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8255_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8260_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8264_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8265_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8266_HiP4 CPU_POWERPC_G2_HIP4 + /* G2_LE core (aka PowerQUICC-II) */ + CPU_POWERPC_G2LE = 0x80820010, + CPU_POWERPC_G2LEgp = 0x80822010, + CPU_POWERPC_G2LEls = 0xA0822010, + CPU_POWERPC_G2LEgp1 = 0x80822011, + /* XXX: MPC 5121 ? */ +#define CPU_POWERPC_MPC5200 CPU_POWERPC_G2LEgp1 + CPU_POWERPC_G2LEgp3 = 0x80822013, +#define CPU_POWERPC_MPC8247 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8248 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8270 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8271 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8272 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8275 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8280 CPU_POWERPC_G2LEgp3 /* e200 family */ #define CPU_POWERPC_e200 CPU_POWERPC_e200z6 #if 0 CPU_POWERPC_e200z0 = xxx, +#define CPU_POWERPC_MPC5514E_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5514G_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5516E_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5516G_v0 CPU_POWERPC_e200z0 #endif #if 0 - CPU_POWERPC_e200z3 = xxx, + CPU_POWERPC_e200z1 = xxx, +#define CPU_POWERPC_MPC5514E_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5514G_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5515S CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516E_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516G_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516S CPU_POWERPC_e200z1 +#endif +#if 0 /* ? */ + CPU_POWERPC_e200z3 = 0x81120000, +#define CPU_POWERPC_MPC5533 CPU_POWERPC_e200z3 +#define CPU_POWERPC_MPC5534 CPU_POWERPC_e200z3 #endif CPU_POWERPC_e200z5 = 0x81000000, CPU_POWERPC_e200z6 = 0x81120000, +#define CPU_POWERPC_MPC5553 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5554 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5561 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5565 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5566 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5567 CPU_POWERPC_e200z6 /* e300 family */ #define CPU_POWERPC_e300 CPU_POWERPC_e300c3 CPU_POWERPC_e300c1 = 0x00830000, +#define CPU_POWERPC_MPC8343A CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8343EA CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8347A CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8347EA CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8349 CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8349E CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8358E CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8360E CPU_POWERPC_e300c1 CPU_POWERPC_e300c2 = 0x00840000, +#define CPU_POWERPC_MPC8321 CPU_POWERPC_e300c2 +#define CPU_POWERPC_MPC8321E CPU_POWERPC_e300c2 +#define CPU_POWERPC_MPC8323 CPU_POWERPC_e300c2 +#define CPU_POWERPC_MPC8323E CPU_POWERPC_e300c2 CPU_POWERPC_e300c3 = 0x00850000, +#define CPU_POWERPC_MPC8313 CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8313E CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8314 CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8314E CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8315 CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8315E CPU_POWERPC_e300c3 + CPU_POWERPC_e300c4 = 0x00860000, +#define CPU_POWERPC_MPC8377 CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8377E CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8378 CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8378E CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8379 CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8379E CPU_POWERPC_e300c4 /* e500 family */ #define CPU_POWERPC_e500 CPU_POWERPC_e500_v22 - CPU_POWERPC_e500_v11 = 0x80200010, - CPU_POWERPC_e500_v12 = 0x80200020, - CPU_POWERPC_e500_v21 = 0x80210010, - CPU_POWERPC_e500_v22 = 0x80210020, -#if 0 - CPU_POWERPC_e500mc = xxx, -#endif + CPU_POWERPC_e500_v10 = 0x80200010, +#define CPU_POWERPC_MPC8540_v1 CPU_POWERPC_e500_v10 + CPU_POWERPC_e500_v20 = 0x80200020, +#define CPU_POWERPC_MPC8540_v2 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8541 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8541E CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8555 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8555E CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8560 CPU_POWERPC_e500_v20 + CPU_POWERPC_e500v2_v10 = 0x80210010, +#define CPU_POWERPC_MPC8543 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8543E CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8545 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8545E CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8547E CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8548 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8548E CPU_POWERPC_e500v2_v10 + CPU_POWERPC_e500v2_v20 = 0x80210020, + CPU_POWERPC_e500v2_v21 = 0x80210021, +#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8533E_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8544_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8544E_v10 CPU_POWERPC_e500v2_v21 + CPU_POWERPC_e500v2_v22 = 0x80210022, +#define CPU_POWERPC_MPC8533_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8533E_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8544_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8544E_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8567 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8568 CPU_POWERPC_e500v2_v22 + CPU_POWERPC_e500v2_v30 = 0x80210030, +#define CPU_POWERPC_MPC8572 CPU_POWERPC_e500v2_v30 /* e600 family */ CPU_POWERPC_e600 = 0x80040010, - /* PowerPC MPC 5xx cores */ - CPU_POWERPC_5xx = 0x00020020, - /* PowerPC MPC 8xx cores (aka PowerQUICC) */ - CPU_POWERPC_8xx = 0x00500000, - /* PowerPC MPC 8xxx cores (aka PowerQUICC-II) */ - CPU_POWERPC_82xx_HIP3 = 0x00810101, - CPU_POWERPC_82xx_HIP4 = 0x80811014, - CPU_POWERPC_827x = 0x80822013, +#define CPU_POWERPC_MPC8610 CPU_POWERPC_e600 +#define CPU_POWERPC_MPC8641 CPU_POWERPC_e600 +#define CPU_POWERPC_MPC8641D CPU_POWERPC_e600 /* PowerPC 6xx cores */ - CPU_POWERPC_601 = 0x00010001, - CPU_POWERPC_601a = 0x00010002, +#define CPU_POWERPC_601 CPU_POWERPC_601_v2 + CPU_POWERPC_601_v0 = 0x00010001, + CPU_POWERPC_601_v1 = 0x00010001, + CPU_POWERPC_601_v2 = 0x00010002, CPU_POWERPC_602 = 0x00050100, CPU_POWERPC_603 = 0x00030100, #define CPU_POWERPC_603E CPU_POWERPC_603E_v41 @@ -4805,30 +4941,20 @@ enum { CPU_POWERPC_603E7 = 0x00070200, CPU_POWERPC_603P = 0x00070000, #define CPU_POWERPC_603R CPU_POWERPC_603E7t - CPU_POWERPC_G2 = 0x00810011, -#if 0 // Linux pretends the MSB is zero... - CPU_POWERPC_G2H4 = 0x80811010, - CPU_POWERPC_G2gp = 0x80821010, - CPU_POWERPC_G2ls = 0x90810010, - CPU_POWERPC_G2LE = 0x80820010, - CPU_POWERPC_G2LEgp = 0x80822010, - CPU_POWERPC_G2LEls = 0xA0822010, -#else - CPU_POWERPC_G2H4 = 0x00811010, - CPU_POWERPC_G2gp = 0x00821010, - CPU_POWERPC_G2ls = 0x10810010, - CPU_POWERPC_G2LE = 0x00820010, - CPU_POWERPC_G2LEgp = 0x00822010, - CPU_POWERPC_G2LEls = 0x20822010, -#endif + /* XXX: missing 0x00040303 (604) */ CPU_POWERPC_604 = 0x00040103, #define CPU_POWERPC_604E CPU_POWERPC_604E_v24 - CPU_POWERPC_604E_v10 = 0x00090100, /* Also 2110 & 2120 */ + /* XXX: missing 0x00091203 */ + /* XXX: missing 0x00092110 */ + /* XXX: missing 0x00092120 */ + CPU_POWERPC_604E_v10 = 0x00090100, CPU_POWERPC_604E_v22 = 0x00090202, CPU_POWERPC_604E_v24 = 0x00090204, - CPU_POWERPC_604R = 0x000a0101, /* Also 0x00093102 */ + /* XXX: missing 0x000a0100 */ + /* XXX: missing 0x00093102 */ + CPU_POWERPC_604R = 0x000a0101, #if 0 - CPU_POWERPC_604EV = xxx, + CPU_POWERPC_604EV = xxx, /* XXX: same as 604R ? */ #endif /* PowerPC 740/750 cores (aka G3) */ /* XXX: missing 0x00084202 */ @@ -4917,14 +5043,17 @@ enum { CPU_POWERPC_7450_v21 = 0x80000201, /* aka E */ CPU_POWERPC_74x1 = 0x80000203, CPU_POWERPC_74x1G = 0x80000210, /* aka G: 2.3 */ - /* XXX: missing 0x80010200 */ #define CPU_POWERPC_74x5 CPU_POWERPC_74x5_v32 CPU_POWERPC_74x5_v10 = 0x80010100, + /* XXX: missing 0x80010200 */ CPU_POWERPC_74x5_v21 = 0x80010201, /* aka C: 2.1 */ CPU_POWERPC_74x5_v32 = 0x80010302, CPU_POWERPC_74x5_v33 = 0x80010303, /* aka F: 3.3 */ CPU_POWERPC_74x5_v34 = 0x80010304, /* aka G: 3.4 */ #define CPU_POWERPC_74x7 CPU_POWERPC_74x7_v12 + /* XXX: is 0x8002xxxx 7447 and 0x8003xxxx 7457 ? */ + /* XXX: missing 0x80030102 */ + /* XXX: missing 0x80020101 */ CPU_POWERPC_74x7_v10 = 0x80020100, /* aka A: 1.0 */ CPU_POWERPC_74x7_v11 = 0x80030101, /* aka B: 1.1 */ CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ @@ -4935,6 +5064,7 @@ enum { CPU_POWERPC_631 = 0x00410104, CPU_POWERPC_POWER4 = 0x00350000, CPU_POWERPC_POWER4P = 0x00380000, + /* XXX: missing 0x003A0201 */ CPU_POWERPC_POWER5 = 0x003A0203, #define CPU_POWERPC_POWER5GR CPU_POWERPC_POWER5 CPU_POWERPC_POWER5P = 0x003B0000, @@ -4980,26 +5110,142 @@ enum { /* System version register (used on MPC 8xxx) */ enum { - PPC_SVR_8540 = 0x80300000, - PPC_SVR_8541E = 0x807A0010, - PPC_SVR_8543v10 = 0x80320010, - PPC_SVR_8543v11 = 0x80320011, - PPC_SVR_8543v20 = 0x80320020, - PPC_SVR_8543Ev10 = 0x803A0010, - PPC_SVR_8543Ev11 = 0x803A0011, - PPC_SVR_8543Ev20 = 0x803A0020, - PPC_SVR_8545 = 0x80310220, - PPC_SVR_8545E = 0x80390220, - PPC_SVR_8547E = 0x80390120, - PPC_SCR_8548v10 = 0x80310010, - PPC_SCR_8548v11 = 0x80310011, - PPC_SCR_8548v20 = 0x80310020, - PPC_SVR_8548Ev10 = 0x80390010, - PPC_SVR_8548Ev11 = 0x80390011, - PPC_SVR_8548Ev20 = 0x80390020, - PPC_SVR_8555E = 0x80790010, - PPC_SVR_8560v10 = 0x80700010, - PPC_SVR_8560v20 = 0x80700020, + PPC_SVR_5200_v10 = 0x80110010, + PPC_SVR_5200_v11 = 0x80110011, + PPC_SVR_5200_v12 = 0x80110012, + PPC_SVR_5200B_v20 = 0x80110020, + PPC_SVR_5200B_v21 = 0x80110021, +#if 0 + PPC_SVR_5533 = xxx, +#endif +#if 0 + PPC_SVR_5534 = xxx, +#endif +#if 0 + PPC_SVR_5553 = xxx, +#endif +#if 0 + PPC_SVR_5554 = xxx, +#endif +#if 0 + PPC_SVR_5561 = xxx, +#endif +#if 0 + PPC_SVR_5565 = xxx, +#endif +#if 0 + PPC_SVR_5566 = xxx, +#endif +#if 0 + PPC_SVR_5567 = xxx, +#endif +#if 0 + PPC_SVR_8313 = xxx, +#endif +#if 0 + PPC_SVR_8313E = xxx, +#endif +#if 0 + PPC_SVR_8314 = xxx, +#endif +#if 0 + PPC_SVR_8314E = xxx, +#endif +#if 0 + PPC_SVR_8315 = xxx, +#endif +#if 0 + PPC_SVR_8315E = xxx, +#endif +#if 0 + PPC_SVR_8321 = xxx, +#endif +#if 0 + PPC_SVR_8321E = xxx, +#endif +#if 0 + PPC_SVR_8323 = xxx, +#endif +#if 0 + PPC_SVR_8323E = xxx, +#endif + PPC_SVR_8343A = 0x80570030, + PPC_SVR_8343EA = 0x80560030, + PPC_SVR_8347AP = 0x80550030, /* PBGA package */ + PPC_SVR_8347AT = 0x80530030, /* TBGA package */ + PPC_SVR_8347EAP = 0x80540030, /* PBGA package */ + PPC_SVR_8347EAT = 0x80520030, /* TBGA package */ + PPC_SVR_8349 = 0x80510010, + PPC_SVR_8349A = 0x80510030, + PPC_SVR_8349E = 0x80500010, + PPC_SVR_8349EA = 0x80500030, +#if 0 + PPC_SVR_8358E = xxx, +#endif +#if 0 + PPC_SVR_8360E = xxx, +#endif + PPC_SVR_8377 = 0x80C70010, + PPC_SVR_8377E = 0x80C60010, + PPC_SVR_8378 = 0x80C50010, + PPC_SVR_8378E = 0x80C40010, + PPC_SVR_8379 = 0x80C30010, + PPC_SVR_8379E = 0x80C00010, + PPC_SVR_8533_v10 = 0x80340010, + PPC_SVR_8533_v11 = 0x80340011, + PPC_SVR_8533E_v10 = 0x803C0010, + PPC_SVR_8533E_v11 = 0x803C0011, + PPC_SVR_8540_v10 = 0x80300010, + PPC_SVR_8540_v20 = 0x80300020, + PPC_SVR_8540_v21 = 0x80300021, + PPC_SVR_8541_v10 = 0x80720010, + PPC_SVR_8541_v11 = 0x80720011, + PPC_SVR_8541E_v10 = 0x807A0010, + PPC_SVR_8541E_v11 = 0x807A0011, + PPC_SVR_8543_v10 = 0x80320010, + PPC_SVR_8543_v11 = 0x80320011, + PPC_SVR_8543_v20 = 0x80320020, + PPC_SVR_8543_v21 = 0x80320021, + PPC_SVR_8543E_v10 = 0x803A0010, + PPC_SVR_8543E_v11 = 0x803A0011, + PPC_SVR_8543E_v20 = 0x803A0020, + PPC_SVR_8543E_v21 = 0x803A0021, + PPC_SVR_8544_v10 = 0x80340110, + PPC_SVR_8544_v11 = 0x80340111, + PPC_SVR_8544E_v10 = 0x803C0110, + PPC_SVR_8544E_v11 = 0x803C0111, + PPC_SVR_8545_v20 = 0x80310220, + PPC_SVR_8545_v21 = 0x80310221, + PPC_SVR_8545E_v20 = 0x80390220, + PPC_SVR_8545E_v21 = 0x80390221, + PPC_SVR_8547E_v20 = 0x80390120, + PPC_SVR_8547E_v21 = 0x80390121, + PPC_SCR_8548_v10 = 0x80310010, + PPC_SCR_8548_v11 = 0x80310011, + PPC_SCR_8548_v20 = 0x80310020, + PPC_SCR_8548_v21 = 0x80310021, + PPC_SVR_8548E_v10 = 0x80390010, + PPC_SVR_8548E_v11 = 0x80390011, + PPC_SVR_8548E_v20 = 0x80390020, + PPC_SVR_8548E_v21 = 0x80390021, + PPC_SVR_8555_v10 = 0x80710010, + PPC_SVR_8555_v11 = 0x80710011, + PPC_SVR_8555E_v10 = 0x80790010, + PPC_SVR_8555E_v11 = 0x80790011, + PPC_SVR_8560_v10 = 0x80700010, + PPC_SVR_8560_v20 = 0x80700020, + PPC_SVR_8560_v21 = 0x80700021, + PPC_SVR_8567 = 0x80750111, + PPC_SVR_8567E = 0x807D0111, + PPC_SVR_8568 = 0x80750011, + PPC_SVR_8568E = 0x807D0011, + PPC_SVR_8572 = 0x80E00010, + PPC_SVR_8572E = 0x80E80010, +#if 0 + PPC_SVR_8610 = xxx, +#endif + PPC_SVR_8641 = 0x80900021, + PPC_SVR_8641D = 0x80900121, }; /*****************************************************************************/ @@ -5431,8 +5677,12 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 6xx family */ /* PowerPC 601 */ POWERPC_DEF("601", CPU_POWERPC_601, 601), + /* PowerPC 601v0 */ + POWERPC_DEF("601v0", CPU_POWERPC_601_v0, 601), + /* PowerPC 601v1 */ + POWERPC_DEF("601v1", CPU_POWERPC_601_v1, 601), /* PowerPC 601v2 */ - POWERPC_DEF("601a", CPU_POWERPC_601a, 601), + POWERPC_DEF("601v2", CPU_POWERPC_601_v2, 601), /* PowerPC 602 */ POWERPC_DEF("602", CPU_POWERPC_602, 602), /* PowerPC 603 */ -- cgit v1.2.3 From 2f4a40e56972be8088faa78cfe2120a4a0026b2d Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 13 Nov 2007 01:50:15 +0000 Subject: Prevent cpsr_write/_read be put out of line in op.o (fixes a segfault on some platforms). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3633 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/misc.c | 2 -- target-arm/cpu.h | 45 +++------------------------------------------ target-arm/helper.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 44 deletions(-) diff --git a/slirp/misc.c b/slirp/misc.c index 14808fe21..9ea7dd068 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -327,8 +327,6 @@ fork_exec(struct socket *so, const char *ex, int do_pty) lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } -#else - return 0; #endif } else { addr.sin_family = AF_INET; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 59b96963b..b284a2169 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -248,16 +248,9 @@ void cpu_unlock(void); #define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J) /* Return the current CPSR value. */ -static inline uint32_t cpsr_read(CPUARMState *env) -{ - int ZF; - ZF = (env->NZF == 0); - return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) - | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) - | ((env->condexec_bits & 0xfc) << 8) - | (env->GE << 16); -} +uint32_t cpsr_read(CPUARMState *env); +/* Set the CPSR. Note that some bits of mask must be all-set or all-clear. */ +void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask); /* Return the current xPSR value. */ static inline uint32_t xpsr_read(CPUARMState *env) @@ -271,38 +264,6 @@ static inline uint32_t xpsr_read(CPUARMState *env) | env->v7m.exception; } -/* Set the CPSR. Note that some bits of mask must be all-set or all-clear. */ -static inline void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) -{ - /* NOTE: N = 1 and Z = 1 cannot be stored currently */ - if (mask & CPSR_NZCV) { - env->NZF = (val & 0xc0000000) ^ 0x40000000; - env->CF = (val >> 29) & 1; - env->VF = (val << 3) & 0x80000000; - } - if (mask & CPSR_Q) - env->QF = ((val & CPSR_Q) != 0); - if (mask & CPSR_T) - env->thumb = ((val & CPSR_T) != 0); - if (mask & CPSR_IT_0_1) { - env->condexec_bits &= ~3; - env->condexec_bits |= (val >> 25) & 3; - } - if (mask & CPSR_IT_2_7) { - env->condexec_bits &= 3; - env->condexec_bits |= (val >> 8) & 0xfc; - } - if (mask & CPSR_GE) { - env->GE = (val >> 16) & 0xf; - } - - if ((env->uncached_cpsr ^ val) & mask & CPSR_M) { - switch_mode(env, val & CPSR_M); - } - mask &= ~CACHED_CPSR_BITS; - env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); -} - /* Set the xPSR. Note that some bits of mask must be all-set or all-clear. */ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) { diff --git a/target-arm/helper.c b/target-arm/helper.c index 69752564d..038025dac 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -272,6 +272,48 @@ uint32_t helper_neon_mul_p8(uint32_t op1, uint32_t op2) return result; } +uint32_t cpsr_read(CPUARMState *env) +{ + int ZF; + ZF = (env->NZF == 0); + return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | + (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) + | (env->thumb << 5) | ((env->condexec_bits & 3) << 25) + | ((env->condexec_bits & 0xfc) << 8) + | (env->GE << 16); +} + +void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) +{ + /* NOTE: N = 1 and Z = 1 cannot be stored currently */ + if (mask & CPSR_NZCV) { + env->NZF = (val & 0xc0000000) ^ 0x40000000; + env->CF = (val >> 29) & 1; + env->VF = (val << 3) & 0x80000000; + } + if (mask & CPSR_Q) + env->QF = ((val & CPSR_Q) != 0); + if (mask & CPSR_T) + env->thumb = ((val & CPSR_T) != 0); + if (mask & CPSR_IT_0_1) { + env->condexec_bits &= ~3; + env->condexec_bits |= (val >> 25) & 3; + } + if (mask & CPSR_IT_2_7) { + env->condexec_bits &= 3; + env->condexec_bits |= (val >> 8) & 0xfc; + } + if (mask & CPSR_GE) { + env->GE = (val >> 16) & 0xf; + } + + if ((env->uncached_cpsr ^ val) & mask & CPSR_M) { + switch_mode(env, val & CPSR_M); + } + mask &= ~CACHED_CPSR_BITS; + env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask); +} + #if defined(CONFIG_USER_ONLY) void do_interrupt (CPUState *env) -- cgit v1.2.3 From 3f9b2b1f6358ec1a19bee6d8a9dd2c3faa81c293 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 13 Nov 2007 01:56:12 +0000 Subject: Revert an accidental change in previous commit. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3634 c046a42c-6fe2-441c-8c8c-71466251a162 --- slirp/misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slirp/misc.c b/slirp/misc.c index 9ea7dd068..14808fe21 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -327,6 +327,8 @@ fork_exec(struct socket *so, const char *ex, int do_pty) lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } +#else + return 0; #endif } else { addr.sin_family = AF_INET; -- cgit v1.2.3 From 87283515f5fe66fa382fa7296cb0063acbf37338 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 13 Nov 2007 22:52:54 +0000 Subject: Fix signed/unsigned comparisons in OHCI host. ADS7846 is partially compatible with TSC2046. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3635 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ads7846.c | 2 +- hw/usb-ohci.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/ads7846.c b/hw/ads7846.c index 2f891b125..c26ce2583 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -1,5 +1,5 @@ /* - * TI ADS7846 chip emulation. + * TI ADS7846 / TSC2046 chip emulation. * * Copyright (c) 2006 Openedhand Ltd. * Written by Andrzej Zaborowski diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 287c45eb0..a85d38e44 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -739,7 +739,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, OHCI_CC_NOERROR); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0); } else { - if (ret > len) { + if (ret > (ssize_t) len) { printf("usb-ohci: DataOverrun %d > %zu\n", ret, len); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, OHCI_CC_DATAOVERRUN); @@ -865,7 +865,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) dprintf(" TD @ 0x%.8x %u bytes %s r=%d cbp=0x%.8x be=0x%.8x\n", addr, len, str, flag_r, td.cbp, td.be); - if (len >= 0 && dir != OHCI_TD_DIR_IN) { + if (len > 0 && dir != OHCI_TD_DIR_IN) { dprintf(" data:"); for (i = 0; i < len; i++) printf(" %.2x", ohci->usb_buf[i]); @@ -1062,7 +1062,8 @@ static void ohci_process_lists(OHCIState *ohci, int completion) { if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) - dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); + dprintf("usb-ohci: head %x, cur %x\n", + ohci->ctrl_head, ohci->ctrl_cur); if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) { ohci->ctrl_cur = 0; ohci->status &= ~OHCI_STATUS_CLF; -- cgit v1.2.3 From 1b413d55636c0bc0f615a517e7f29203a787d50c Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 14 Nov 2007 01:08:45 +0000 Subject: Reorganize PowerPC instructions categories, add icbi separate case. Fix frsqrtes instruction opcode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3636 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 194 +++++++++++++++++++++++--------------------- target-ppc/translate_init.c | 10 ++- 2 files changed, 109 insertions(+), 95 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 8663eabb4..550e1abf1 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -426,111 +426,123 @@ static always_inline target_ulong MASK (uint32_t start, uint32_t end) /*****************************************************************************/ /* PowerPC Instructions types definitions */ enum { - PPC_NONE = 0x0000000000000000ULL, + PPC_NONE = 0x0000000000000000ULL, /* PowerPC base instructions set */ - PPC_INSNS_BASE = 0x0000000000000001ULL, - /* integer operations instructions */ + PPC_INSNS_BASE = 0x0000000000000001ULL, + /* integer operations instructions */ #define PPC_INTEGER PPC_INSNS_BASE - /* flow control instructions */ + /* flow control instructions */ #define PPC_FLOW PPC_INSNS_BASE - /* virtual memory instructions */ + /* virtual memory instructions */ #define PPC_MEM PPC_INSNS_BASE - /* ld/st with reservation instructions */ + /* ld/st with reservation instructions */ #define PPC_RES PPC_INSNS_BASE - /* cache control instructions */ -#define PPC_CACHE PPC_INSNS_BASE - /* spr/msr access instructions */ + /* spr/msr access instructions */ #define PPC_MISC PPC_INSNS_BASE - /* Optional floating point instructions */ - PPC_FLOAT = 0x0000000000000002ULL, - PPC_FLOAT_FSQRT = 0x0000000000000004ULL, - PPC_FLOAT_FRES = 0x0000000000000008ULL, - PPC_FLOAT_FRSQRTE = 0x0000000000000010ULL, - PPC_FLOAT_FSEL = 0x0000000000000020ULL, - PPC_FLOAT_STFIWX = 0x0000000000000040ULL, - /* external control instructions */ - PPC_EXTERN = 0x0000000000000080ULL, - /* segment register access instructions */ - PPC_SEGMENT = 0x0000000000000100ULL, - /* Optional cache control instruction */ - PPC_CACHE_DCBA = 0x0000000000000200ULL, + /* Deprecated instruction sets */ + /* Original POWER instruction set */ + PPC_POWER = 0x0000000000000001ULL, + /* POWER2 instruction set extension */ + PPC_POWER2 = 0x0000000000000002ULL, + /* Power RTC support */ + PPC_POWER_RTC = 0x0000000000000004ULL, + /* Power-to-PowerPC bridge (601) */ + PPC_POWER_BR = 0x0000000000000008ULL, + /* 64 bits PowerPC instruction set */ + PPC_64B = 0x0000000000000010ULL, + /* New 64 bits extensions (PowerPC 2.0x) */ + PPC_64BX = 0x0000000000000020ULL, + /* 64 bits hypervisor extensions */ + PPC_64H = 0x0000000000000040ULL, + /* New wait instruction (PowerPC 2.0x) */ + PPC_WAIT = 0x0000000000000080ULL, + /* Time base mftb instruction */ + PPC_MFTB = 0x0000000000000100ULL, + + /* Fixed-point unit extensions */ + /* PowerPC 602 specific */ + PPC_602_SPEC = 0x0000000000000200ULL, + /* PowerPC 2.03 specification extensions */ + PPC_203 = 0x0000000000000400ULL, + + /* Floating-point unit extensions */ + /* Optional floating point instructions */ + PPC_FLOAT = 0x0000000000010000ULL, + /* New floating-point extensions (PowerPC 2.0x) */ + PPC_FLOAT_EXT = 0x0000000000020000ULL, + PPC_FLOAT_FSQRT = 0x0000000000040000ULL, + PPC_FLOAT_FRES = 0x0000000000080000ULL, + PPC_FLOAT_FRSQRTE = 0x0000000000100000ULL, + PPC_FLOAT_FRSQRTES = 0x0000000000200000ULL, + PPC_FLOAT_FSEL = 0x0000000000400000ULL, + PPC_FLOAT_STFIWX = 0x0000000000800000ULL, + + /* Vector/SIMD extensions */ + /* Altivec support */ + PPC_ALTIVEC = 0x0000000001000000ULL, + /* e500 vector instructions */ + PPC_E500_VECTOR = 0x0000000002000000ULL, + /* PowerPC 2.03 SPE extension */ + PPC_SPE = 0x0000000004000000ULL, + /* PowerPC 2.03 SPE floating-point extension */ + PPC_SPEFPU = 0x0000000008000000ULL, + /* Optional memory control instructions */ - PPC_MEM_TLBIA = 0x0000000000000400ULL, - PPC_MEM_TLBIE = 0x0000000000000800ULL, - PPC_MEM_TLBSYNC = 0x0000000000001000ULL, - /* eieio & sync */ - PPC_MEM_SYNC = 0x0000000000002000ULL, - /* PowerPC 6xx TLB management instructions */ - PPC_6xx_TLB = 0x0000000000004000ULL, - /* Altivec support */ - PPC_ALTIVEC = 0x0000000000008000ULL, - /* Time base mftb instruction */ - PPC_MFTB = 0x0000000000010000ULL, + PPC_MEM_TLBIA = 0x0000000010000000ULL, + PPC_MEM_TLBIE = 0x0000000020000000ULL, + PPC_MEM_TLBSYNC = 0x0000000040000000ULL, + /* sync instruction */ + PPC_MEM_SYNC = 0x0000000080000000ULL, + /* eieio instruction */ + PPC_MEM_EIEIO = 0x0000000100000000ULL, + + /* Cache control instructions */ + PPC_CACHE = 0x0000001000000000ULL, + /* icbi instruction */ + PPC_CACHE_ICBI = 0x0000002000000000ULL, + /* dcbz instruction with fixed cache line size */ + PPC_CACHE_DCBZ = 0x0000004000000000ULL, + /* dcbz instruction with tunable cache line size */ + PPC_CACHE_DCBZT = 0x0000008000000000ULL, + /* dcba instruction */ + PPC_CACHE_DCBA = 0x0000010000000000ULL, + + /* MMU related extensions */ + /* external control instructions */ + PPC_EXTERN = 0x0000100000000000ULL, + /* segment register access instructions */ + PPC_SEGMENT = 0x0000200000000000ULL, + /* PowerPC 6xx TLB management instructions */ + PPC_6xx_TLB = 0x0000400000000000ULL, + /* PowerPC 74xx TLB management instructions */ + PPC_74xx_TLB = 0x0000800000000000ULL, + /* PowerPC 40x TLB management instructions */ + PPC_40x_TLB = 0x0001000000000000ULL, + /* segment register access instructions for PowerPC 64 "bridge" */ + PPC_SEGMENT_64B = 0x0002000000000000ULL, + /* SLB management */ + PPC_SLBI = 0x0004000000000000ULL, + /* Embedded PowerPC dedicated instructions */ - PPC_EMB_COMMON = 0x0000000000020000ULL, + PPC_EMB_COMMON = 0x0010000000000000ULL, /* PowerPC 40x exception model */ - PPC_40x_EXCP = 0x0000000000040000ULL, - /* PowerPC 40x TLB management instructions */ - PPC_40x_TLB = 0x0000000000080000ULL, + PPC_40x_EXCP = 0x0020000000000000ULL, /* PowerPC 405 Mac instructions */ - PPC_405_MAC = 0x0000000000100000ULL, + PPC_405_MAC = 0x0040000000000000ULL, /* PowerPC 440 specific instructions */ - PPC_440_SPEC = 0x0000000000200000ULL, - /* Power-to-PowerPC bridge (601) */ - PPC_POWER_BR = 0x0000000000400000ULL, - /* PowerPC 602 specific */ - PPC_602_SPEC = 0x0000000000800000ULL, - /* Deprecated instructions */ - /* Original POWER instruction set */ - PPC_POWER = 0x0000000001000000ULL, - /* POWER2 instruction set extension */ - PPC_POWER2 = 0x0000000002000000ULL, - /* Power RTC support */ - PPC_POWER_RTC = 0x0000000004000000ULL, - /* 64 bits PowerPC instruction set */ - PPC_64B = 0x0000000008000000ULL, - /* 64 bits hypervisor extensions */ - PPC_64H = 0x0000000010000000ULL, - /* segment register access instructions for PowerPC 64 "bridge" */ - PPC_SEGMENT_64B = 0x0000000020000000ULL, + PPC_440_SPEC = 0x0080000000000000ULL, /* BookE (embedded) PowerPC specification */ - PPC_BOOKE = 0x0000000040000000ULL, - /* eieio */ - PPC_MEM_EIEIO = 0x0000000080000000ULL, - /* e500 vector instructions */ - PPC_E500_VECTOR = 0x0000000100000000ULL, + PPC_BOOKE = 0x0100000000000000ULL, + /* More BookE (embedded) instructions... */ + PPC_BOOKE_EXT = 0x0200000000000000ULL, /* PowerPC 4xx dedicated instructions */ - PPC_4xx_COMMON = 0x0000000200000000ULL, - /* PowerPC 2.03 specification extensions */ - PPC_203 = 0x0000000400000000ULL, - /* PowerPC 2.03 SPE extension */ - PPC_SPE = 0x0000000800000000ULL, - /* PowerPC 2.03 SPE floating-point extension */ - PPC_SPEFPU = 0x0000001000000000ULL, - /* SLB management */ - PPC_SLBI = 0x0000002000000000ULL, + PPC_4xx_COMMON = 0x0400000000000000ULL, /* PowerPC 40x ibct instructions */ - PPC_40x_ICBT = 0x0000004000000000ULL, - /* PowerPC 74xx TLB management instructions */ - PPC_74xx_TLB = 0x0000008000000000ULL, - /* More BookE (embedded) instructions... */ - PPC_BOOKE_EXT = 0x0000010000000000ULL, + PPC_40x_ICBT = 0x0800000000000000ULL, /* rfmci is not implemented in all BookE PowerPC */ - PPC_RFMCI = 0x0000020000000000ULL, + PPC_RFMCI = 0x1000000000000000ULL, /* user-mode DCR access, implemented in PowerPC 460 */ - PPC_DCRUX = 0x0000040000000000ULL, - /* New floating-point extensions (PowerPC 2.0x) */ - PPC_FLOAT_EXT = 0x0000080000000000ULL, - /* New wait instruction (PowerPC 2.0x) */ - PPC_WAIT = 0x0000100000000000ULL, - /* New 64 bits extensions (PowerPC 2.0x) */ - PPC_64BX = 0x0000200000000000ULL, - /* dcbz instruction with fixed cache line size */ - PPC_CACHE_DCBZ = 0x0000400000000000ULL, - /* dcbz instruction with tunable cache line size */ - PPC_CACHE_DCBZT = 0x0000800000000000ULL, - /* frsqrtes extension */ - PPC_FLOAT_FRSQRTES = 0x0001000000000000ULL, + PPC_DCRUX = 0x2000000000000000ULL, }; /*****************************************************************************/ @@ -1805,7 +1817,7 @@ static always_inline void gen_op_frsqrtes (void) gen_op_frsqrte(); gen_op_frsp(); } -GEN_FLOAT_BS(rsqrtes, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTES); +GEN_FLOAT_BS(rsqrtes, 0x3B, 0x1A, 1, PPC_FLOAT_FRSQRTES); /* fsel */ _GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL); @@ -3980,7 +3992,7 @@ static GenOpFunc *gen_op_icbi[] = { #endif #endif -GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) +GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d663f79e4..c6b744698 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2651,7 +2651,8 @@ static int check_pow_hid0 (CPUPPCState *env) /* PowerPC implementations definitions */ /* PowerPC 40x instruction set */ -#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_CACHE_DCBZ | PPC_EMB_COMMON) +#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_EMB_COMMON | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ) /* PowerPC 401 */ #define POWERPC_INSNS_401 (POWERPC_INSNS_EMB | \ @@ -3176,7 +3177,7 @@ static void init_proc_460F (CPUPPCState *env) PPC_CACHE_DCBA | \ PPC_FLOAT | PPC_FLOAT_FSQRT | \ PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_FSEL | PPC_FLOAT_STFIW | \ + PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ PPC_BOOKE) #define POWERPC_MSRM_BookE (0x000000000006D630ULL) #define POWERPC_MMU_BookE (POWERPC_MMU_BOOKE) @@ -3233,8 +3234,9 @@ static void init_proc_e500 (CPUPPCState *env) /* Non-embedded PowerPC */ /* Base instructions set for all 6xx/7xx/74xx/970 PowerPC */ -#define POWERPC_INSNS_6xx (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \ - PPC_MEM_EIEIO | PPC_MEM_TLBIE) +#define POWERPC_INSNS_6xx (PPC_INSNS_BASE | PPC_FLOAT | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE) /* Instructions common to all 6xx/7xx/74xx/970 PowerPC except 601 & 602 */ #define POWERPC_INSNS_WORKS (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT | \ PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ -- cgit v1.2.3 From 3e4587d5d1b8ccb28de9be2fbab724dc1cc89359 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 14 Nov 2007 03:11:17 +0000 Subject: Introduce 4KEm configuration with fixed MMU mapping. Delete bogus INSN_DSP flags. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3637 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 44aff7f37..d54e3b677 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -128,6 +128,23 @@ static mips_def_t mips_defs[] = .CP0_Status_rw_bitmask = 0x1278FF17, .insn_flags = CPU_MIPS32R2 | ASE_MIPS16, }, + { + .name = "4KEm", + .CP0_PRid = 0x00019100, + /* Config1 implemented, MIPS32R2, fixed mapping MMU, + no virtual icache, uncached coherency. */ + .CP0_Config0 = (1 << CP0C0_M) | (0x1 << CP0C0_AR) | + (0x3 << CP0C0_MT) | (0x2 << CP0C0_K0), + .CP0_Config1 = MIPS_CONFIG1 | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x1258FF17, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16, + }, { .name = "24Kc", .CP0_PRid = 0x00019300, @@ -141,7 +158,7 @@ static mips_def_t mips_defs[] = .CCRes = 2, /* No DSP implemented. */ .CP0_Status_rw_bitmask = 0x1278FF1F, - .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16, }, { .name = "24Kf", @@ -158,7 +175,7 @@ static mips_def_t mips_defs[] = .CP0_Status_rw_bitmask = 0x3678FF1F, .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), - .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP, + .insn_flags = CPU_MIPS32R2 | ASE_MIPS16, }, { .name = "34Kf", -- cgit v1.2.3 From 271a916e8a4188b0ec94bafff18aa93de0047820 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 14 Nov 2007 05:26:46 +0000 Subject: Fix invalid PowerPC 64 rldimi optimized case. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3638 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 550e1abf1..67b7613ab 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1606,17 +1606,15 @@ GEN_PPC64_R2(rldcr, 0x1E, 0x09); static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) { uint64_t mask; - uint32_t sh, mb; + uint32_t sh, mb, me; sh = SH(ctx->opcode) | (shn << 5); mb = MB(ctx->opcode) | (mbn << 5); + me = 63 - sh; if (likely(sh == 0)) { if (likely(mb == 0)) { gen_op_load_gpr_T0(rS(ctx->opcode)); goto do_store; - } else if (likely(mb == 63)) { - gen_op_load_gpr_T0(rA(ctx->opcode)); - goto do_store; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rA(ctx->opcode)); @@ -1626,7 +1624,7 @@ static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn) gen_op_load_gpr_T1(rA(ctx->opcode)); gen_op_rotli64_T0(sh); do_mask: - mask = MASK(mb, 63 - sh); + mask = MASK(mb, me); gen_andi_T0_64(ctx, mask); gen_andi_T1_64(ctx, ~mask); gen_op_or(); -- cgit v1.2.3 From 3dd98412ba5a54be627531a385faa539167ddbdf Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 10:17:35 +0000 Subject: added lock_user() in target_strlen() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3639 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/uaccess.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c index 3f838180c..ed5043756 100644 --- a/linux-user/uaccess.c +++ b/linux-user/uaccess.c @@ -37,15 +37,40 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len) return ret; } +/* XXX: use host strnlen if available ? */ +static int qemu_strnlen(const char *s, int max_len) +{ + int i; + for(i = 0; i < max_len; i++) { + if (s[i] == '\0') + break; + } + return i; +} -/* Return the length of a string in target memory. */ -/* FIXME - this doesn't check access_ok() - it's rather complicated to - * do it correctly because we need to check the bytes in a page and then - * skip to the next page and check the bytes there until we find the - * terminator. There should be a general function to do this that - * can look for any byte terminator in a buffer - not strlen(). - */ -abi_long target_strlen(abi_ulong gaddr) +/* Return the length of a string in target memory or -TARGET_EFAULT if + access error */ +abi_long target_strlen(abi_ulong guest_addr1) { - return strlen(g2h(gaddr)); + uint8_t *ptr; + abi_ulong guest_addr; + int max_len, len; + + guest_addr = guest_addr1; + for(;;) { + max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK); + ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1); + if (!ptr) + return -TARGET_EFAULT; + len = qemu_strnlen(ptr, max_len); + unlock_user(ptr, guest_addr, 0); + guest_addr += len; + /* we don't allow wrapping or integer overflow */ + if (guest_addr == 0 || + (guest_addr - guest_addr1) > 0x7fffffff) + return -TARGET_EFAULT; + if (len != max_len) + break; + } + return guest_addr - guest_addr1; } -- cgit v1.2.3 From 9b0b82037a2ebfb3d38ed2ae23194eadd85b1440 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 10:34:57 +0000 Subject: removed obsolete test2 target git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3640 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- tests/Makefile | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 73f9e3db1..e8b28770b 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config-host.mak .PHONY: all clean distclean dvi info install install-doc tar tarbin \ - speed test test2 html dvi info + speed test html dvi info BASE_CFLAGS= BASE_LDFLAGS= @@ -176,7 +176,7 @@ endif done # various test targets -test speed test2: all +test speed: all $(MAKE) -C tests $@ TAGS: diff --git a/tests/Makefile b/tests/Makefile index 94ec0b4a0..f8bad3232 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -92,13 +92,6 @@ hello-mips: hello-mips.c hello-mipsel: hello-mips.c mipsel-linux-gnu-gcc -nostdlib -static -mno-abicalls -fno-PIC -mabi=32 -Wall -Wextra -g -O2 -o $@ $< -# XXX: find a way to compile easily a test for each arch -test2: - @for arch in i386 arm armeb sparc ppc mips mipsel; do \ - ../$${arch}-linux-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \ - done - - # testsuite for the CRIS port. test-cris: $(MAKE) -C cris check -- cgit v1.2.3 From dae3270c6e25062b9085da0756b68fafedc9bb2c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 10:51:00 +0000 Subject: suppressed page_unprotect_range() - fixed access_ok() git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3641 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 - exec.c | 30 ++++++++++++------------------ linux-user/qemu.h | 7 +++++-- linux-user/syscall.c | 2 -- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 76daec947..f4db59234 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -690,7 +690,6 @@ extern unsigned long qemu_host_page_mask; 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); int page_check_range(target_ulong start, target_ulong len, int flags); CPUState *cpu_copy(CPUState *env); diff --git a/exec.c b/exec.c index e817a4e5e..6384df270 100644 --- a/exec.c +++ b/exec.c @@ -1894,10 +1894,19 @@ int page_check_range(target_ulong start, target_ulong len, int flags) if( !(p->flags & PAGE_VALID) ) return -1; - if (!(p->flags & PAGE_READ) && (flags & PAGE_READ) ) - return -1; - if (!(p->flags & PAGE_WRITE) && (flags & PAGE_WRITE) ) + if ((flags & PAGE_READ) && !(p->flags & PAGE_READ)) return -1; + if (flags & PAGE_WRITE) { + if (!(p->flags & PAGE_WRITE_ORG)) + return -1; + /* unprotect the page if it was put read-only because it + contains translated code */ + if (!(p->flags & PAGE_WRITE)) { + if (!page_unprotect(addr, 0, NULL)) + return -1; + } + return 0; + } } return 0; } @@ -1942,21 +1951,6 @@ int page_unprotect(target_ulong address, unsigned long pc, void *puc) return 0; } -/* call this function when system calls directly modify a memory area */ -/* ??? This should be redundant now we have lock_user. */ -void page_unprotect_range(target_ulong data, target_ulong data_size) -{ - target_ulong start, end, addr; - - start = data; - end = start + data_size; - start &= TARGET_PAGE_MASK; - end = TARGET_PAGE_ALIGN(end); - for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { - page_unprotect(addr, 0, NULL); - } -} - static inline void tlb_set_dirty(CPUState *env, unsigned long addr, target_ulong vaddr) { diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 581ee27fa..5917cb51a 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -207,8 +207,11 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); #define VERIFY_READ 0 #define VERIFY_WRITE 1 /* implies read access */ -#define access_ok(type,addr,size) \ - (page_check_range((target_ulong)addr,size,(type==VERIFY_READ)?PAGE_READ:PAGE_WRITE)==0) +static inline int access_ok(int type, abi_ulong addr, abi_ulong size) +{ + return page_check_range((target_ulong)addr, size, + (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0; +} /* NOTE __get_user and __put_user use host pointers and don't check access. */ /* These are usually used to access struct data members once the diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6c8f689ae..1e4ad96b3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2773,7 +2773,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = 0; /* avoid warning */ break; case TARGET_NR_read: - page_unprotect_range(arg2, arg3); if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(read(arg1, p, arg3)); @@ -4537,7 +4536,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_NR_pread case TARGET_NR_pread: - page_unprotect_range(arg2, arg3); if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(pread(arg1, p, arg3, arg4)); -- cgit v1.2.3 From a03e2d421e7f33316750d6b7396d1a7e14b18d53 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 11:29:07 +0000 Subject: fixed target_mmap() if host page size < TARGET_PAGE_SIZE git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3642 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/mmap.c | 264 ++++++++++++++++++++++++++---------------------------- 1 file changed, 126 insertions(+), 138 deletions(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index f87303402..3f2647f30 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -151,19 +151,53 @@ static int mmap_frag(abi_ulong real_start, return 0; } +#if defined(__CYGWIN__) +/* Cygwin doesn't have a whole lot of address space. */ +static abi_ulong mmap_next_start = 0x18000000; +#else +static abi_ulong mmap_next_start = 0x40000000; +#endif + +/* find a free memory area of size 'size'. The search starts at + 'start'. If 'start' == 0, then a default start address is used. + Return -1 if error. +*/ +/* XXX: should mark pages used by the host as reserved to be sure not + to use them. */ +static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) +{ + abi_ulong addr, addr1, addr_start; + int prot; + + size = HOST_PAGE_ALIGN(size); + start = start & qemu_host_page_mask; + addr = start; + if (addr == 0) + addr = mmap_next_start; + addr_start = addr; + for(;;) { + prot = 0; + for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr1); + } + if (prot == 0) + break; + addr += qemu_host_page_size; + /* we found nothing */ + if (addr == addr_start) + return (abi_ulong)-1; + } + if (start == 0) + mmap_next_start = addr + size; + return addr; +} + /* NOTE: all the constants are the HOST ones */ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, int flags, int fd, abi_ulong offset) { abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; unsigned long host_start; -#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ - defined(__ia64) || defined(__mips__) - static abi_ulong last_start = 0x40000000; -#elif defined(__CYGWIN__) - /* Cygwin doesn't have a whole lot of address space. */ - static abi_ulong last_start = 0x18000000; -#endif #ifdef DEBUG_MMAP { @@ -203,147 +237,101 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, real_start = start & qemu_host_page_mask; if (!(flags & MAP_FIXED)) { -#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ - defined(__ia64) || defined(__mips__) || defined(__CYGWIN__) - /* tell the kernel to search at the same place as i386 */ - if (real_start == 0) { - real_start = last_start; - last_start += HOST_PAGE_ALIGN(len); - } -#endif - host_offset = offset & qemu_host_page_mask; - host_len = len + offset - host_offset; - - if (qemu_host_page_size > qemu_real_host_page_size) { - /* - * The guest expects to see mmapped areas aligned to it's pagesize. - * If the host's real page size is smaller than the guest's, we need - * to fixup the maps. It is done by allocating a larger area, - * displacing the map (if needed) and finally chopping off the spare - * room at the edges. - */ - - /* - * We assume qemu_host_page_size is always the same as - * TARGET_PAGE_SIZE, see exec.c. qemu_real_host_page_size is the - * hosts real page size. - */ - abi_ulong host_end; - unsigned long host_aligned_start; - void *p; - - host_len = HOST_PAGE_ALIGN(host_len + qemu_host_page_size - - qemu_real_host_page_size); - p = mmap(real_start ? g2h(real_start) : NULL, - host_len, prot, flags, fd, host_offset); - if (p == MAP_FAILED) - return -1; - - host_start = (unsigned long)p; - host_end = host_start + host_len; - - /* Find start and end, aligned to the targets pagesize with-in the - large mmaped area. */ - host_aligned_start = TARGET_PAGE_ALIGN(host_start); - if (!(flags & MAP_ANONYMOUS)) - host_aligned_start += offset - host_offset; - - start = h2g(host_aligned_start); - end = start + TARGET_PAGE_ALIGN(len); - - /* Chop off the leftovers, if any. */ - if (host_aligned_start > host_start) - munmap((void *)host_start, host_aligned_start - host_start); - if (end < host_end) - munmap((void *)g2h(end), host_end - end); - - goto the_end1; - } else { - /* if not fixed, no need to do anything */ - void *p = mmap(real_start ? g2h(real_start) : NULL, - host_len, prot, flags, fd, host_offset); - if (p == MAP_FAILED) - return -1; - /* update start so that it points to the file position at 'offset' */ - host_start = (unsigned long)p; - if (!(flags & MAP_ANONYMOUS)) - host_start += offset - host_offset; - start = h2g(host_start); - goto the_end1; + abi_ulong mmap_start; + void *p; + host_offset = offset & qemu_host_page_mask; + host_len = len + offset - host_offset; + host_len = HOST_PAGE_ALIGN(host_len); + mmap_start = mmap_find_vma(real_start, host_len); + if (mmap_start == (abi_ulong)-1) { + errno = ENOMEM; + return -1; } - } - - if (start & ~TARGET_PAGE_MASK) { - errno = EINVAL; - return -1; - } - end = start + len; - real_end = HOST_PAGE_ALIGN(end); - - /* worst case: we cannot map the file because the offset is not - aligned, so we read it */ - if (!(flags & MAP_ANONYMOUS) && - (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { - /* msync() won't work here, so we return an error if write is - possible while it is a shared mapping */ - if ((flags & MAP_TYPE) == MAP_SHARED && - (prot & PROT_WRITE)) { + /* Note: we prefer to control the mapping address. It is + especially important if qemu_host_page_size > + qemu_real_host_page_size */ + p = mmap(g2h(mmap_start), + host_len, prot, flags | MAP_FIXED, fd, host_offset); + if (p == MAP_FAILED) + return -1; + /* update start so that it points to the file position at 'offset' */ + host_start = (unsigned long)p; + if (!(flags & MAP_ANONYMOUS)) + host_start += offset - host_offset; + start = h2g(host_start); + } else { + if (start & ~TARGET_PAGE_MASK) { errno = EINVAL; return -1; } - retaddr = target_mmap(start, len, prot | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); - if (retaddr == -1) - return -1; - pread(fd, g2h(start), len, offset); - if (!(prot & PROT_WRITE)) { - ret = target_mprotect(start, len, prot); - if (ret != 0) - return ret; + end = start + len; + real_end = HOST_PAGE_ALIGN(end); + + /* worst case: we cannot map the file because the offset is not + aligned, so we read it */ + if (!(flags & MAP_ANONYMOUS) && + (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ + if ((flags & MAP_TYPE) == MAP_SHARED && + (prot & PROT_WRITE)) { + errno = EINVAL; + return -1; + } + retaddr = target_mmap(start, len, prot | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (retaddr == -1) + return -1; + pread(fd, g2h(start), len, offset); + if (!(prot & PROT_WRITE)) { + ret = target_mprotect(start, len, prot); + if (ret != 0) + return ret; + } + goto the_end; } - goto the_end; - } - - /* handle the start of the mapping */ - if (start > real_start) { - if (real_end == real_start + qemu_host_page_size) { - /* one single host page */ - ret = mmap_frag(real_start, start, end, + + /* handle the start of the mapping */ + if (start > real_start) { + if (real_end == real_start + qemu_host_page_size) { + /* one single host page */ + ret = mmap_frag(real_start, start, end, + prot, flags, fd, offset); + if (ret == -1) + return ret; + goto the_end1; + } + ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, prot, flags, fd, offset); if (ret == -1) return ret; - goto the_end1; + real_start += qemu_host_page_size; + } + /* handle the end of the mapping */ + if (end < real_end) { + ret = mmap_frag(real_end - qemu_host_page_size, + real_end - qemu_host_page_size, real_end, + prot, flags, fd, + offset + real_end - qemu_host_page_size - start); + if (ret == -1) + return -1; + real_end -= qemu_host_page_size; } - ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, - prot, flags, fd, offset); - if (ret == -1) - return ret; - real_start += qemu_host_page_size; - } - /* handle the end of the mapping */ - if (end < real_end) { - ret = mmap_frag(real_end - qemu_host_page_size, - real_end - qemu_host_page_size, real_end, - prot, flags, fd, - offset + real_end - qemu_host_page_size - start); - if (ret == -1) - return -1; - real_end -= qemu_host_page_size; - } - /* map the middle (easier) */ - if (real_start < real_end) { - void *p; - unsigned long offset1; - if (flags & MAP_ANONYMOUS) - offset1 = 0; - else - offset1 = offset + real_start - start; - p = mmap(g2h(real_start), real_end - real_start, - prot, flags, fd, offset1); - if (p == MAP_FAILED) - return -1; + /* map the middle (easier) */ + if (real_start < real_end) { + void *p; + unsigned long offset1; + if (flags & MAP_ANONYMOUS) + offset1 = 0; + else + offset1 = offset + real_start - start; + p = mmap(g2h(real_start), real_end - real_start, + prot, flags, fd, offset1); + if (p == MAP_FAILED) + return -1; + } } the_end1: page_set_flags(start, start + len, prot | PAGE_VALID); -- cgit v1.2.3 From 4683b130e562b5718115442e02b85e90501bb8b0 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 15:16:52 +0000 Subject: always define TARGET_ABI32 if 32 bit user git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3643 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/qemu.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 5917cb51a..537facbf2 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -20,6 +20,10 @@ typedef target_long abi_long; #define TARGET_ABI_FMT_ld TARGET_FMT_ld #define TARGET_ABI_FMT_lu TARGET_FMT_lu #define TARGET_ABI_BITS TARGET_LONG_BITS +/* for consistency, define ABI32 too */ +#if TARGET_ABI_BITS == 32 +#define TARGET_ABI32 1 +#endif #endif #include "thunk.h" -- cgit v1.2.3 From 8d18e89309f08efc44eb777631aba2fbee70375a Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 15:18:40 +0000 Subject: i386 TLS support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3644 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/i386/syscall.h | 1 + linux-user/main.c | 21 ++++--- linux-user/syscall.c | 150 +++++++++++++++++++++++++++++++++++++++++++- linux-user/x86_64/syscall.h | 1 + 4 files changed, 161 insertions(+), 12 deletions(-) diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index 8045e1c7b..266e2c4c8 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -25,6 +25,7 @@ struct target_pt_regs { #define TARGET_LDT_ENTRIES 8192 #define TARGET_LDT_ENTRY_SIZE 8 +#define TARGET_GDT_ENTRIES 9 #define TARGET_GDT_ENTRY_TLS_ENTRIES 3 #define TARGET_GDT_ENTRY_TLS_MIN 6 #define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1) diff --git a/linux-user/main.c b/linux-user/main.c index eb5861ad1..ac7a174d9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -159,7 +159,6 @@ static void set_gate(void *ptr, unsigned int type, unsigned int dpl, p[1] = tswapl(e2); } -uint64_t gdt_table[6]; uint64_t idt_table[256]; /* only dpl matters as we do only user space emulation */ @@ -2129,14 +2128,18 @@ int main(int argc, char **argv) set_idt(0x80, 3); /* linux segment setup */ - env->gdt.base = h2g(gdt_table); - env->gdt.limit = sizeof(gdt_table) - 1; - write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | - (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); - write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | - (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + { + uint64_t *gdt_table; + gdt_table = qemu_mallocz(sizeof(uint64_t) * TARGET_GDT_ENTRIES); + env->gdt.base = h2g(gdt_table); + env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); + write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + } cpu_x86_load_seg(env, R_CS, __USER_CS); cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1e4ad96b3..01d042a51 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2285,7 +2285,7 @@ static abi_long write_ldt(CPUX86State *env, struct target_modify_ldt_ldt_s ldt_info; struct target_modify_ldt_ldt_s *target_ldt_info; int seg_32bit, contents, read_exec_only, limit_in_pages; - int seg_not_present, useable; + int seg_not_present, useable, lm; uint32_t *lp, entry_1, entry_2; if (bytecount != sizeof(ldt_info)) @@ -2306,7 +2306,11 @@ static abi_long write_ldt(CPUX86State *env, limit_in_pages = (ldt_info.flags >> 4) & 1; seg_not_present = (ldt_info.flags >> 5) & 1; useable = (ldt_info.flags >> 6) & 1; - +#ifdef TARGET_ABI32 + lm = 0; +#else + lm = (ldt_info.flags >> 7) & 1; +#endif if (contents == 3) { if (oldmode) return -TARGET_EINVAL; @@ -2349,6 +2353,7 @@ static abi_long write_ldt(CPUX86State *env, ((seg_not_present ^ 1) << 15) | (seg_32bit << 22) | (limit_in_pages << 23) | + (lm << 21) | 0x7000; if (!oldmode) entry_2 |= (useable << 20); @@ -2384,6 +2389,138 @@ abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr, return ret; } +abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) +{ + uint64_t *gdt_table = g2h(env->gdt.base); + struct target_modify_ldt_ldt_s ldt_info; + struct target_modify_ldt_ldt_s *target_ldt_info; + int seg_32bit, contents, read_exec_only, limit_in_pages; + int seg_not_present, useable, lm; + uint32_t *lp, entry_1, entry_2; + int i; + + lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1); + if (!target_ldt_info) + return -TARGET_EFAULT; + ldt_info.entry_number = tswap32(target_ldt_info->entry_number); + ldt_info.base_addr = tswapl(target_ldt_info->base_addr); + ldt_info.limit = tswap32(target_ldt_info->limit); + ldt_info.flags = tswap32(target_ldt_info->flags); + if (ldt_info.entry_number == -1) { + for (i=TARGET_GDT_ENTRY_TLS_MIN; i<=TARGET_GDT_ENTRY_TLS_MAX; i++) { + if (gdt_table[i] == 0) { + ldt_info.entry_number = i; + target_ldt_info->entry_number = tswap32(i); + break; + } + } + } + unlock_user_struct(target_ldt_info, ptr, 1); + + if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || + ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX) + return -TARGET_EINVAL; + seg_32bit = ldt_info.flags & 1; + contents = (ldt_info.flags >> 1) & 3; + read_exec_only = (ldt_info.flags >> 3) & 1; + limit_in_pages = (ldt_info.flags >> 4) & 1; + seg_not_present = (ldt_info.flags >> 5) & 1; + useable = (ldt_info.flags >> 6) & 1; +#ifdef TARGET_ABI32 + lm = 0; +#else + lm = (ldt_info.flags >> 7) & 1; +#endif + + if (contents == 3) { + if (seg_not_present == 0) + return -TARGET_EINVAL; + } + + /* NOTE: same code as Linux kernel */ + /* Allow LDTs to be cleared by the user. */ + if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { + if ((contents == 0 && + read_exec_only == 1 && + seg_32bit == 0 && + limit_in_pages == 0 && + seg_not_present == 1 && + useable == 0 )) { + entry_1 = 0; + entry_2 = 0; + goto install; + } + } + + entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | + (ldt_info.limit & 0x0ffff); + entry_2 = (ldt_info.base_addr & 0xff000000) | + ((ldt_info.base_addr & 0x00ff0000) >> 16) | + (ldt_info.limit & 0xf0000) | + ((read_exec_only ^ 1) << 9) | + (contents << 10) | + ((seg_not_present ^ 1) << 15) | + (seg_32bit << 22) | + (limit_in_pages << 23) | + (useable << 20) | + (lm << 21) | + 0x7000; + + /* Install the new entry ... */ +install: + lp = (uint32_t *)(gdt_table + ldt_info.entry_number); + lp[0] = tswap32(entry_1); + lp[1] = tswap32(entry_2); + return 0; +} + +abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) +{ + struct target_modify_ldt_ldt_s *target_ldt_info; + uint64_t *gdt_table = g2h(env->gdt.base); + uint32_t base_addr, limit, flags; + int seg_32bit, contents, read_exec_only, limit_in_pages, idx; + int seg_not_present, useable, lm; + uint32_t *lp, entry_1, entry_2; + + lock_user_struct(VERIFY_WRITE, target_ldt_info, ptr, 1); + if (!target_ldt_info) + return -TARGET_EFAULT; + idx = tswap32(target_ldt_info->entry_number); + if (idx < TARGET_GDT_ENTRY_TLS_MIN || + idx > TARGET_GDT_ENTRY_TLS_MAX) { + unlock_user_struct(target_ldt_info, ptr, 1); + return -TARGET_EINVAL; + } + lp = (uint32_t *)(gdt_table + idx); + entry_1 = tswap32(lp[0]); + entry_2 = tswap32(lp[1]); + + read_exec_only = ((entry_2 >> 9) & 1) ^ 1; + contents = (entry_2 >> 10) & 3; + seg_not_present = ((entry_2 >> 15) & 1) ^ 1; + seg_32bit = (entry_2 >> 22) & 1; + limit_in_pages = (entry_2 >> 23) & 1; + useable = (entry_2 >> 20) & 1; +#ifdef TARGET_ABI32 + lm = 0; +#else + lm = (entry_2 >> 21) & 1; +#endif + flags = (seg_32bit << 0) | (contents << 1) | + (read_exec_only << 3) | (limit_in_pages << 4) | + (seg_not_present << 5) | (useable << 6) | (lm << 7); + limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000); + base_addr = (entry_1 >> 16) | + (entry_2 & 0xff000000) | + ((entry_2 & 0xff) << 16); + target_ldt_info->base_addr = tswapl(base_addr); + target_ldt_info->limit = tswap32(limit); + target_ldt_info->flags = tswap32(flags); + unlock_user_struct(target_ldt_info, ptr, 1); + return 0; +} + #endif /* defined(TARGET_I386) */ /* this stack is the equivalent of the kernel stack associated with a @@ -5136,18 +5273,25 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_set_thread_area case TARGET_NR_set_thread_area: -#ifdef TARGET_MIPS +#if defined(TARGET_MIPS) ((CPUMIPSState *) cpu_env)->tls_value = arg1; ret = 0; break; +#elif defined(TARGET_I386) && defined(TARGET_ABI32) + ret = do_set_thread_area(cpu_env, arg1); + break; #else goto unimplemented_nowarn; #endif #endif #ifdef TARGET_NR_get_thread_area case TARGET_NR_get_thread_area: +#if defined(TARGET_I386) && defined(TARGET_ABI32) + ret = do_get_thread_area(cpu_env, arg1); +#else goto unimplemented_nowarn; #endif +#endif #ifdef TARGET_NR_getdomainname case TARGET_NR_getdomainname: goto unimplemented_nowarn; diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h index cdba432bf..f82589c49 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/syscall.h @@ -34,6 +34,7 @@ struct target_pt_regs { /* The size of each LDT entry. */ #define TARGET_LDT_ENTRY_SIZE 8 +#define TARGET_GDT_ENTRIES 16 #define TARGET_GDT_ENTRY_TLS_ENTRIES 3 #define TARGET_GDT_ENTRY_TLS_MIN 12 #define TARGET_GDT_ENTRY_TLS_MAX 14 -- cgit v1.2.3 From 6b23f777223166d99e88402ddcf3583c3dda9b4c Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 18:04:05 +0000 Subject: printf format fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3645 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/strace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 6854efec6..d7c18c63c 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -271,7 +271,7 @@ print_syscall(int num, abi_long arg4, abi_long arg5, abi_long arg6) { int i; - char *format="%s(%ld,%ld,%ld,%ld,%ld,%ld)"; + char *format="%s(" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld ")"; gemu_log("%d ", getpid() ); @@ -280,6 +280,8 @@ print_syscall(int num, if( scnames[i].call != NULL ) { scnames[i].call(&scnames[i],arg1,arg2,arg3,arg4,arg5,arg6); } else { + /* XXX: this format system is broken because it uses + host types and host pointers for strings */ if( scnames[i].format != NULL ) format = scnames[i].format; gemu_log(format,scnames[i].name, arg1,arg2,arg3,arg4,arg5,arg6); -- cgit v1.2.3 From d2fd1af76777687697674e7a49eeceac83907f3e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 18:08:56 +0000 Subject: x86_64 linux user emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3646 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 73 ++++++++++++++++++++++++++++++---- linux-user/syscall.c | 97 +++++++++++++++++++++++++++------------------ linux-user/syscall_defs.h | 26 +++++++++++- linux-user/x86_64/syscall.h | 5 +++ target-i386/cpu.h | 3 ++ target-i386/helper.c | 20 ++++++++-- 6 files changed, 174 insertions(+), 50 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index ac7a174d9..cfe2a0e36 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -147,8 +147,11 @@ static void write_dt(void *ptr, unsigned long addr, unsigned long limit, p[1] = tswapl(e2); } -static void set_gate(void *ptr, unsigned int type, unsigned int dpl, - unsigned long addr, unsigned int sel) +#if TARGET_X86_64 +uint64_t idt_table[512]; + +static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, + uint64_t addr, unsigned int sel) { unsigned int e1, e2; uint32_t *p; @@ -157,15 +160,34 @@ static void set_gate(void *ptr, unsigned int type, unsigned int dpl, p = ptr; p[0] = tswapl(e1); p[1] = tswapl(e2); + p[2] = addr >> 32; } - +/* only dpl matters as we do only user space emulation */ +static void set_idt(int n, unsigned int dpl) +{ + set_gate64(idt_table + n * 2, 0, dpl, 0, 0); +} +#else uint64_t idt_table[256]; +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, + uint32_t addr, unsigned int sel) +{ + unsigned int e1, e2; + uint32_t *p; + e1 = (addr & 0xffff) | (sel << 16); + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); + p = ptr; + p[0] = tswapl(e1); + p[1] = tswapl(e2); +} + /* only dpl matters as we do only user space emulation */ static void set_idt(int n, unsigned int dpl) { set_gate(idt_table + n, 0, dpl, 0, 0); } +#endif void cpu_loop(CPUX86State *env) { @@ -177,7 +199,7 @@ void cpu_loop(CPUX86State *env) trapnr = cpu_x86_exec(env); switch(trapnr) { case 0x80: - /* linux syscall */ + /* linux syscall from int $0x80 */ env->regs[R_EAX] = do_syscall(env, env->regs[R_EAX], env->regs[R_EBX], @@ -187,6 +209,20 @@ void cpu_loop(CPUX86State *env) env->regs[R_EDI], env->regs[R_EBP]); break; +#ifndef TARGET_ABI32 + case EXCP_SYSCALL: + /* linux syscall from syscall intruction */ + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], + env->regs[R_EDI], + env->regs[R_ESI], + env->regs[R_EDX], + env->regs[10], + env->regs[8], + env->regs[9]); + env->eip = env->exception_next_eip; + break; +#endif case EXCP0B_NOSEG: case EXCP0C_STACK: info.si_signo = SIGBUS; @@ -196,6 +232,7 @@ void cpu_loop(CPUX86State *env) queue_signal(info.si_signo, &info); break; case EXCP0D_GPF: + /* XXX: potential problem if ABI32 */ #ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_fault(env); @@ -2075,12 +2112,18 @@ int main(int argc, char **argv) env->cr[4] |= CR4_OSFXSR_MASK; env->hflags |= HF_OSFXSR_MASK; } +#ifndef TARGET_ABI32 + /* enable 64 bit mode */ + env->cr[4] |= CR4_PAE_MASK; + env->efer |= MSR_EFER_LMA; + env->hflags |= HF_LMA_MASK; +#endif /* flags setup : we activate the IRQs by default as in user mode */ env->eflags |= IF_MASK; /* linux register setup */ -#if defined(TARGET_X86_64) +#ifndef TARGET_ABI32 env->regs[R_EAX] = regs->rax; env->regs[R_EBX] = regs->rbx; env->regs[R_ECX] = regs->rcx; @@ -2131,24 +2174,38 @@ int main(int argc, char **argv) { uint64_t *gdt_table; gdt_table = qemu_mallocz(sizeof(uint64_t) * TARGET_GDT_ENTRIES); - env->gdt.base = h2g(gdt_table); + env->gdt.base = h2g((unsigned long)gdt_table); env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; +#ifdef TARGET_ABI32 write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); +#else + /* 64 bit code segment */ + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + DESC_L_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); +#endif write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); } cpu_x86_load_seg(env, R_CS, __USER_CS); + cpu_x86_load_seg(env, R_SS, __USER_DS); +#ifdef TARGET_ABI32 cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS); - cpu_x86_load_seg(env, R_SS, __USER_DS); cpu_x86_load_seg(env, R_FS, __USER_DS); cpu_x86_load_seg(env, R_GS, __USER_DS); - /* This hack makes Wine work... */ env->segs[R_FS].selector = 0; +#else + cpu_x86_load_seg(env, R_DS, 0); + cpu_x86_load_seg(env, R_ES, 0); + cpu_x86_load_seg(env, R_FS, 0); + cpu_x86_load_seg(env, R_GS, 0); +#endif #elif defined(TARGET_ARM) { int i; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 01d042a51..ab252cfe8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2521,6 +2521,41 @@ abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) return 0; } +#ifndef TARGET_ABI32 +abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr) +{ + abi_long ret; + abi_ulong val; + int idx; + + switch(code) { + case TARGET_ARCH_SET_GS: + case TARGET_ARCH_SET_FS: + if (code == TARGET_ARCH_SET_GS) + idx = R_GS; + else + idx = R_FS; + cpu_x86_load_seg(env, idx, 0); + env->segs[idx].base = addr; + break; + case TARGET_ARCH_GET_GS: + case TARGET_ARCH_GET_FS: + if (code == TARGET_ARCH_GET_GS) + idx = R_GS; + else + idx = R_FS; + val = env->segs[idx].base; + if (put_user(val, addr, abi_ulong)) + return -TARGET_EFAULT; + break; + default: + ret = -TARGET_EINVAL; + break; + } + return 0; +} +#endif + #endif /* defined(TARGET_I386) */ /* this stack is the equivalent of the kernel stack associated with a @@ -2797,7 +2832,7 @@ void syscall_init(void) target_to_host_errno_table[host_to_target_errno_table[i]] = i; /* automatic consistency check if same arch */ -#if defined(__i386__) && defined(TARGET_I386) +#if defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32) if (ie->target_cmd != ie->host_cmd) { fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n", ie->target_cmd, ie->host_cmd); @@ -3861,7 +3896,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_mmap case TARGET_NR_mmap: -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) +#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) { abi_ulong *v; abi_ulong v1, v2, v3, v4, v5, v6; @@ -4183,42 +4218,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0)) goto efault; -#if defined(TARGET_MIPS) || (defined(TARGET_SPARC64) && !defined(TARGET_ABI32)) - target_st->st_dev = tswap32(st.st_dev); -#else - target_st->st_dev = tswap16(st.st_dev); -#endif - target_st->st_ino = tswapl(st.st_ino); -#if defined(TARGET_PPC) || defined(TARGET_MIPS) - target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */ - target_st->st_uid = tswap32(st.st_uid); - target_st->st_gid = tswap32(st.st_gid); -#elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - target_st->st_mode = tswap32(st.st_mode); - target_st->st_uid = tswap32(st.st_uid); - target_st->st_gid = tswap32(st.st_gid); -#else - target_st->st_mode = tswap16(st.st_mode); - target_st->st_uid = tswap16(st.st_uid); - target_st->st_gid = tswap16(st.st_gid); -#endif -#if defined(TARGET_MIPS) - /* If this is the same on PPC, then just merge w/ the above ifdef */ - target_st->st_nlink = tswapl(st.st_nlink); - target_st->st_rdev = tswapl(st.st_rdev); -#elif defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - target_st->st_nlink = tswap32(st.st_nlink); - target_st->st_rdev = tswap32(st.st_rdev); -#else - target_st->st_nlink = tswap16(st.st_nlink); - target_st->st_rdev = tswap16(st.st_rdev); -#endif - target_st->st_size = tswapl(st.st_size); - target_st->st_blksize = tswapl(st.st_blksize); - target_st->st_blocks = tswapl(st.st_blocks); - target_st->target_st_atime = tswapl(st.st_atime); - target_st->target_st_mtime = tswapl(st.st_mtime); - target_st->target_st_ctime = tswapl(st.st_ctime); + __put_user(st.st_dev, &target_st->st_dev); + __put_user(st.st_ino, &target_st->st_ino); + __put_user(st.st_mode, &target_st->st_mode); + __put_user(st.st_uid, &target_st->st_uid); + __put_user(st.st_gid, &target_st->st_gid); + __put_user(st.st_nlink, &target_st->st_nlink); + __put_user(st.st_rdev, &target_st->st_rdev); + __put_user(st.st_size, &target_st->st_size); + __put_user(st.st_blksize, &target_st->st_blksize); + __put_user(st.st_blocks, &target_st->st_blocks); + __put_user(st.st_atime, &target_st->target_st_atime); + __put_user(st.st_mtime, &target_st->target_st_mtime); + __put_user(st.st_ctime, &target_st->target_st_ctime); unlock_user_struct(target_st, arg2, 1); } } @@ -4671,6 +4683,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; } break; +#ifdef TARGET_NR_arch_prctl + case TARGET_NR_arch_prctl: +#if defined(TARGET_I386) && !defined(TARGET_ABI32) + ret = do_arch_prctl(cpu_env, arg1, arg2); + break; +#else + goto unimplemented; +#endif +#endif #ifdef TARGET_NR_pread case TARGET_NR_pread: if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 333977aa9..c5d15a6f9 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -881,7 +881,7 @@ struct target_winsize { #define TARGET_MAP_NONBLOCK 0x10000 /* do not block on IO */ #endif -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_CRIS) +#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_CRIS) struct target_stat { unsigned short st_dev; unsigned short __pad1; @@ -1474,6 +1474,30 @@ struct target_stat64 { unsigned long long st_ino; }; +#elif defined(TARGET_I386) && !defined(TARGET_ABI32) +struct target_stat { + abi_ulong st_dev; + abi_ulong st_ino; + abi_ulong st_nlink; + + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad0; + abi_ulong st_rdev; + abi_long st_size; + abi_long st_blksize; + abi_long st_blocks; /* Number 512-byte blocks allocated. */ + + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; + + abi_long __unused[3]; +}; #else #error unsupported CPU #endif diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h index f82589c49..2a8d696bf 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/syscall.h @@ -91,3 +91,8 @@ struct target_msqid64_ds { }; #define UNAME_MACHINE "x86_64" + +#define TARGET_ARCH_SET_GS 0x1001 +#define TARGET_ARCH_SET_FS 0x1002 +#define TARGET_ARCH_GET_FS 0x1003 +#define TARGET_ARCH_GET_GS 0x1004 diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 910a4b48c..2114cba92 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -340,6 +340,9 @@ #define EXCP11_ALGN 17 #define EXCP12_MCHK 18 +#define EXCP_SYSCALL 0x100 /* only happens in user only emulation + for syscall instruction */ + enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ diff --git a/target-i386/helper.c b/target-i386/helper.c index 0a75e8c33..841824fc9 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -971,6 +971,14 @@ static void do_interrupt64(int intno, int is_int, int error_code, } #endif +#if defined(CONFIG_USER_ONLY) +void helper_syscall(int next_eip_addend) +{ + env->exception_index = EXCP_SYSCALL; + env->exception_next_eip = env->eip + next_eip_addend; + cpu_loop_exit(); +} +#else void helper_syscall(int next_eip_addend) { int selector; @@ -1024,6 +1032,7 @@ void helper_syscall(int next_eip_addend) env->eip = (uint32_t)env->star; } } +#endif void helper_sysret(int dflag) { @@ -1143,18 +1152,23 @@ void do_interrupt_user(int intno, int is_int, int error_code, { SegmentCache *dt; target_ulong ptr; - int dpl, cpl; + int dpl, cpl, shift; uint32_t e2; dt = &env->idt; - ptr = dt->base + (intno * 8); + if (env->hflags & HF_LMA_MASK) { + shift = 4; + } else { + shift = 3; + } + ptr = dt->base + (intno << shift); e2 = ldl_kernel(ptr + 4); dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + raise_exception_err(EXCP0D_GPF, (intno << shift) + 2); /* Since we emulate only user space, we cannot do more than exiting the emulation with the suitable exception and error -- cgit v1.2.3 From 57c26279c7bdef3cb181ea0afbd062a87d4ed6a0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 14 Nov 2007 18:45:52 +0000 Subject: Fix PowerPC targets compilation on 32 bits hosts: now that the SPE extension is available for all targets, we always need to have some 64 bits temporary registers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3647 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 6 +++--- target-ppc/exec.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7589ba215..bb50c1df6 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -520,11 +520,11 @@ struct CPUPPCState { /* First are the most commonly used resources * during translated code execution */ -#if TARGET_GPR_BITS > HOST_LONG_BITS +#if (HOST_LONG_BITS == 32) /* temporary fixed-point registers - * used to emulate 64 bits target on 32 bits hosts + * used to emulate 64 bits registers on 32 bits hosts */ - ppc_gpr_t t0, t1, t2; + uint64_t t0, t1, t2; #endif ppc_avr_t avr0, avr1, avr2; diff --git a/target-ppc/exec.h b/target-ppc/exec.h index f56135704..beaa39ab0 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -42,8 +42,8 @@ register unsigned long T0 asm(AREG1); register unsigned long T1 asm(AREG2); register unsigned long T2 asm(AREG3); #endif -/* We may, sometime, need 64 bits registers on 32 bits target */ -#if TARGET_GPR_BITS > HOST_LONG_BITS +/* We may, sometime, need 64 bits registers on 32 bits targets */ +#if (HOST_LONG_BITS == 32) /* no registers can be used */ #define T0_64 (env->t0) #define T1_64 (env->t1) -- cgit v1.2.3 From d2c63fc185f3d126ef177105166a491ab3556f5c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 14 Nov 2007 19:35:16 +0000 Subject: Update OHW interface to version 3. Use common ABI description file with OpenBIOS. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3648 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/firmware_abi.h | 198 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/sun4m.c | 159 +++++++++++++++------------------------ hw/sun4u.c | 221 +++++++++++++++++------------------------------------- 3 files changed, 324 insertions(+), 254 deletions(-) create mode 100755 hw/firmware_abi.h diff --git a/hw/firmware_abi.h b/hw/firmware_abi.h new file mode 100755 index 000000000..499949363 --- /dev/null +++ b/hw/firmware_abi.h @@ -0,0 +1,198 @@ +#ifndef FIRMWARE_ABI_H +#define FIRMWARE_ABI_H + +#ifndef __ASSEMBLY__ +/* Open Hack'Ware NVRAM configuration structure */ + +/* Version 3 */ +typedef struct ohwcfg_v3_t ohwcfg_v3_t; +struct ohwcfg_v3_t { + /* 0x00: structure identifier */ + uint8_t struct_ident[0x10]; + /* 0x10: structure version and NVRAM description */ + uint32_t struct_version; + uint16_t nvram_size; + uint16_t pad0; + uint16_t nvram_arch_ptr; + uint16_t nvram_arch_size; + uint16_t nvram_arch_crc; + uint8_t pad1[0x02]; + /* 0x20: host architecture */ + uint8_t arch[0x10]; + /* 0x30: RAM/ROM description */ + uint64_t RAM0_base; + uint64_t RAM0_size; + uint64_t RAM1_base; + uint64_t RAM1_size; + uint64_t RAM2_base; + uint64_t RAM2_size; + uint64_t RAM3_base; + uint64_t RAM3_size; + uint64_t ROM_base; + uint64_t ROM_size; + /* 0x80: Kernel description */ + uint64_t kernel_image; + uint64_t kernel_size; + /* 0x90: Kernel command line */ + uint64_t cmdline; + uint64_t cmdline_size; + /* 0xA0: Kernel boot image */ + uint64_t initrd_image; + uint64_t initrd_size; + /* 0xB0: NVRAM image */ + uint64_t NVRAM_image; + uint8_t pad2[8]; + /* 0xC0: graphic configuration */ + uint16_t width; + uint16_t height; + uint16_t depth; + uint16_t graphic_flags; + /* 0xC8: CPUs description */ + uint8_t nb_cpus; + uint8_t boot_cpu; + uint8_t nboot_devices; + uint8_t pad3[5]; + /* 0xD0: boot devices */ + uint8_t boot_devices[0x10]; + /* 0xE0 */ + uint8_t pad4[0x1C]; /* 28 */ + /* 0xFC: checksum */ + uint16_t crc; + uint8_t pad5[0x02]; +} __attribute__ (( packed )); + +#define OHW_GF_NOGRAPHICS 0x0001 + +static inline uint16_t +OHW_crc_update (uint16_t prev, uint16_t value) +{ + uint16_t tmp; + uint16_t pd, pd1, pd2; + + tmp = prev >> 8; + pd = prev ^ value; + pd1 = pd & 0x000F; + pd2 = ((pd >> 4) & 0x000F) ^ pd1; + tmp ^= (pd1 << 3) | (pd1 << 8); + tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); + + return tmp; +} + +static inline uint16_t +OHW_compute_crc (ohwcfg_v3_t *header, uint32_t start, uint32_t count) +{ + uint32_t i; + uint16_t crc = 0xFFFF; + uint8_t *ptr = (uint8_t *)header; + int odd; + + odd = count & 1; + count &= ~1; + for (i = 0; i != count; i++) { + crc = OHW_crc_update(crc, (ptr[start + i] << 8) | ptr[start + i + 1]); + } + if (odd) { + crc = OHW_crc_update(crc, ptr[start + i] << 8); + } + + return crc; +} + +/* Sparc32 runtime NVRAM structure for SMP CPU boot */ +struct sparc_arch_cfg { + uint32_t smp_ctx; + uint32_t smp_ctxtbl; + uint32_t smp_entry; + uint8_t valid; + uint8_t unused[51]; +}; + +/* OpenBIOS NVRAM partition */ +struct OpenBIOS_nvpart_v1 { + uint8_t signature; + uint8_t checksum; + uint16_t len; // BE, length divided by 16 + char name[12]; +}; + +#define OPENBIOS_PART_SYSTEM 0x70 +#define OPENBIOS_PART_FREE 0x7f + +static inline void +OpenBIOS_finish_partition(struct OpenBIOS_nvpart_v1 *header, uint32_t size) +{ + unsigned int i, sum; + uint8_t *tmpptr; + + // Length divided by 16 + header->len = cpu_to_be16(size >> 4); + + // Checksum + tmpptr = (uint8_t *)header; + sum = *tmpptr; + for (i = 0; i < 14; i++) { + sum += tmpptr[2 + i]; + sum = (sum + ((sum & 0xff00) >> 8)) & 0xff; + } + header->checksum = sum & 0xff; +} + +static inline uint32_t +OpenBIOS_set_var(uint8_t *nvram, uint32_t addr, const unsigned char *str) +{ + uint32_t len; + + len = strlen(str) + 1; + memcpy(&nvram[addr], str, len); + + return addr + len; +} + +/* Sun IDPROM structure at the end of NVRAM */ +struct Sun_nvram { + uint8_t type; + uint8_t machine_id; + uint8_t macaddr[6]; + uint8_t unused[7]; + uint8_t checksum; +}; + +static inline void +Sun_init_header(struct Sun_nvram *header, const uint8_t *macaddr, int machine_id) +{ + uint8_t tmp, *tmpptr; + unsigned int i; + + header->type = 1; + header->machine_id = machine_id & 0xff; + memcpy(&header->macaddr, macaddr, 6); + /* Calculate checksum */ + tmp = 0; + tmpptr = (uint8_t *)header; + for (i = 0; i < 15; i++) + tmp ^= tmpptr[i]; + + header->checksum = tmp; +} + +#else /* __ASSEMBLY__ */ + +/* Structure offsets for asm use */ + +/* Open Hack'Ware NVRAM configuration structure */ +#define OHW_ARCH_PTR 0x18 +#define OHW_RAM_SIZE 0x38 +#define OHW_BOOT_CPU 0xC9 + +/* Sparc32 runtime NVRAM structure for SMP CPU boot */ +#define SPARC_SMP_CTX 0x0 +#define SPARC_SMP_CTXTBL 0x4 +#define SPARC_SMP_ENTRY 0x8 +#define SPARC_SMP_VALID 0xc + +/* Sun IDPROM structure at the end of NVRAM */ +#define SPARC_MACHINE_ID 0x1fd9 + +#endif /* __ASSEMBLY__ */ +#endif /* FIRMWARE_ABI_H */ diff --git a/hw/sun4m.c b/hw/sun4m.c index b10108716..d589b2995 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -22,6 +22,9 @@ * THE SOFTWARE. */ #include "vl.h" +#include "m48t59.h" +#include "firmware_abi.h" + //#define DEBUG_IRQ /* @@ -102,131 +105,87 @@ void DMA_register_channel (int nchan, { } -static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) -{ - m48t59_write(nvram, addr++, (value >> 8) & 0xff); - m48t59_write(nvram, addr++, value & 0xff); -} - -static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) -{ - m48t59_write(nvram, addr++, value >> 24); - m48t59_write(nvram, addr++, (value >> 16) & 0xff); - m48t59_write(nvram, addr++, (value >> 8) & 0xff); - m48t59_write(nvram, addr++, value & 0xff); -} - -static void nvram_set_string (m48t59_t *nvram, uint32_t addr, - const unsigned char *str, uint32_t max) -{ - unsigned int i; - - for (i = 0; i < max && str[i] != '\0'; i++) { - m48t59_write(nvram, addr + i, str[i]); - } - m48t59_write(nvram, addr + max - 1, '\0'); -} - -static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr, - const unsigned char *str) -{ - uint32_t len; - - len = strlen(str) + 1; - nvram_set_string(nvram, addr, str, len); - - return addr + len; -} - -static void nvram_finish_partition (m48t59_t *nvram, uint32_t start, - uint32_t end) -{ - unsigned int i, sum; - - // Length divided by 16 - m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff); - m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff); - // Checksum - sum = m48t59_read(nvram, start); - for (i = 0; i < 14; i++) { - sum += m48t59_read(nvram, start + 2 + i); - sum = (sum + ((sum & 0xff00) >> 8)) & 0xff; - } - m48t59_write(nvram, start + 1, sum & 0xff); -} - extern int nographic; static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, - const char *boot_device, uint32_t RAM_size, + const char *boot_devices, uint32_t RAM_size, uint32_t kernel_size, int width, int height, int depth, int machine_id) { - unsigned char tmp = 0; - unsigned int i, j; + unsigned int i; uint32_t start, end; + uint8_t image[0x1ff0]; + ohwcfg_v3_t *header = (ohwcfg_v3_t *)ℑ + struct sparc_arch_cfg *sparc_header; + struct OpenBIOS_nvpart_v1 *part_header; + + memset(image, '\0', sizeof(image)); // Try to match PPC NVRAM - nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); - nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */ - // NVRAM_size, arch not applicable - m48t59_write(nvram, 0x2D, smp_cpus & 0xff); - m48t59_write(nvram, 0x2E, 0); - m48t59_write(nvram, 0x2F, nographic & 0xff); - nvram_set_lword(nvram, 0x30, RAM_size); - m48t59_write(nvram, 0x34, boot_device[0] & 0xff); - nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR); - nvram_set_lword(nvram, 0x3C, kernel_size); + strcpy(header->struct_ident, "QEMU_BIOS"); + header->struct_version = cpu_to_be32(3); /* structure v3 */ + + header->nvram_size = cpu_to_be16(0x2000); + header->nvram_arch_ptr = cpu_to_be16(sizeof(ohwcfg_v3_t)); + header->nvram_arch_size = cpu_to_be16(sizeof(struct sparc_arch_cfg)); + strcpy(header->arch, "sun4m"); + header->nb_cpus = smp_cpus & 0xff; + header->RAM0_base = 0; + header->RAM0_size = cpu_to_be64((uint64_t)RAM_size); + strcpy(header->boot_devices, boot_devices); + header->nboot_devices = strlen(boot_devices) & 0xff; + header->kernel_image = cpu_to_be64((uint64_t)KERNEL_LOAD_ADDR); + header->kernel_size = cpu_to_be64((uint64_t)kernel_size); if (cmdline) { strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); - nvram_set_lword(nvram, 0x44, strlen(cmdline)); + header->cmdline = cpu_to_be64((uint64_t)CMDLINE_ADDR); + header->cmdline_size = cpu_to_be64((uint64_t)strlen(cmdline)); } - // initrd_image, initrd_size passed differently - nvram_set_word(nvram, 0x54, width); - nvram_set_word(nvram, 0x56, height); - nvram_set_word(nvram, 0x58, depth); + // XXX add initrd_image, initrd_size + header->width = cpu_to_be16(width); + header->height = cpu_to_be16(height); + header->depth = cpu_to_be16(depth); + if (nographic) + header->graphic_flags = cpu_to_be16(OHW_GF_NOGRAPHICS); + + header->crc = cpu_to_be16(OHW_compute_crc(header, 0x00, 0xF8)); + + // Architecture specific header + start = sizeof(ohwcfg_v3_t); + sparc_header = (struct sparc_arch_cfg *)&image[start]; + sparc_header->valid = 0; + start += sizeof(struct sparc_arch_cfg); // OpenBIOS nvram variables // Variable partition - start = 252; - m48t59_write(nvram, start, 0x70); - nvram_set_string(nvram, start + 4, "system", 12); + part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; + part_header->signature = OPENBIOS_PART_SYSTEM; + strcpy(part_header->name, "system"); - end = start + 16; + end = start + sizeof(struct OpenBIOS_nvpart_v1); for (i = 0; i < nb_prom_envs; i++) - end = nvram_set_var(nvram, end, prom_envs[i]); + end = OpenBIOS_set_var(image, end, prom_envs[i]); + + // End marker + image[end++] = '\0'; - m48t59_write(nvram, end++ , 0); end = start + ((end - start + 15) & ~15); - nvram_finish_partition(nvram, start, end); + OpenBIOS_finish_partition(part_header, end - start); // free partition start = end; - m48t59_write(nvram, start, 0x7f); - nvram_set_string(nvram, start + 4, "free", 12); + part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; + part_header->signature = OPENBIOS_PART_FREE; + strcpy(part_header->name, "free"); end = 0x1fd0; - nvram_finish_partition(nvram, start, end); - - // Sun4m specific use - start = i = 0x1fd8; - m48t59_write(nvram, i++, 0x01); - m48t59_write(nvram, i++, machine_id); - j = 0; - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i, macaddr[j]); - - /* Calculate checksum */ - for (i = start; i < start + 15; i++) { - tmp ^= m48t59_read(nvram, i); - } - m48t59_write(nvram, start + 15, tmp); + OpenBIOS_finish_partition(part_header, end - start); + + Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, machine_id); + + for (i = 0; i < sizeof(image); i++) + m48t59_write(nvram, i, image[i]); } static void *slavio_intctl; diff --git a/hw/sun4u.c b/hw/sun4u.c index 9734a963f..588b1c311 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -23,6 +23,7 @@ */ #include "vl.h" #include "m48t59.h" +#include "firmware_abi.h" #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 @@ -66,179 +67,91 @@ void DMA_register_channel (int nchan, { } -/* NVRAM helpers */ -static void nvram_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) -{ - m48t59_write(nvram, addr, value); -} - -static uint8_t nvram_get_byte (m48t59_t *nvram, uint32_t addr) -{ - return m48t59_read(nvram, addr); -} - -static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) -{ - m48t59_write(nvram, addr++, (value >> 8) & 0xff); - m48t59_write(nvram, addr++, value & 0xff); -} - -static uint16_t nvram_get_word (m48t59_t *nvram, uint32_t addr) -{ - uint16_t tmp; - - tmp = m48t59_read(nvram, addr) << 8; - tmp |= m48t59_read(nvram, addr + 1); - - return tmp; -} - -static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) -{ - m48t59_write(nvram, addr++, value >> 24); - m48t59_write(nvram, addr++, (value >> 16) & 0xff); - m48t59_write(nvram, addr++, (value >> 8) & 0xff); - m48t59_write(nvram, addr++, value & 0xff); -} - -static void nvram_set_string (m48t59_t *nvram, uint32_t addr, - const unsigned char *str, uint32_t max) -{ - unsigned int i; - - for (i = 0; i < max && str[i] != '\0'; i++) { - m48t59_write(nvram, addr + i, str[i]); - } - m48t59_write(nvram, addr + max - 1, '\0'); -} - -static uint16_t nvram_crc_update (uint16_t prev, uint16_t value) -{ - uint16_t tmp; - uint16_t pd, pd1, pd2; - - tmp = prev >> 8; - pd = prev ^ value; - pd1 = pd & 0x000F; - pd2 = ((pd >> 4) & 0x000F) ^ pd1; - tmp ^= (pd1 << 3) | (pd1 << 8); - tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); - - return tmp; -} - -static uint16_t nvram_compute_crc (m48t59_t *nvram, uint32_t start, - uint32_t count) -{ - uint32_t i; - uint16_t crc = 0xFFFF; - int odd; - - odd = count & 1; - count &= ~1; - for (i = 0; i != count; i++) { - crc = nvram_crc_update(crc, nvram_get_word(nvram, start + i)); - } - if (odd) { - crc = nvram_crc_update(crc, nvram_get_byte(nvram, start + i) << 8); - } - - return crc; -} - -static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr, - const unsigned char *str) -{ - uint32_t len; - - len = strlen(str) + 1; - nvram_set_string(nvram, addr, str, len); - - return addr + len; -} - -static void nvram_finish_partition (m48t59_t *nvram, uint32_t start, - uint32_t end) -{ - unsigned int i, sum; - - // Length divided by 16 - m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff); - m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff); - // Checksum - sum = m48t59_read(nvram, start); - for (i = 0; i < 14; i++) { - sum += m48t59_read(nvram, start + 2 + i); - sum = (sum + ((sum & 0xff00) >> 8)) & 0xff; - } - m48t59_write(nvram, start + 1, sum & 0xff); -} - extern int nographic; -int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, - const unsigned char *arch, - uint32_t RAM_size, int boot_device, - uint32_t kernel_image, uint32_t kernel_size, - const char *cmdline, - uint32_t initrd_image, uint32_t initrd_size, - uint32_t NVRAM_image, - int width, int height, int depth) +static int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, + const unsigned char *arch, + uint32_t RAM_size, const char *boot_devices, + uint32_t kernel_image, uint32_t kernel_size, + const char *cmdline, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image, + int width, int height, int depth) { - uint16_t crc; unsigned int i; uint32_t start, end; - - /* Set parameters for Open Hack'Ware BIOS */ - nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); - nvram_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ - nvram_set_word(nvram, 0x14, NVRAM_size); - nvram_set_string(nvram, 0x20, arch, 16); - nvram_set_byte(nvram, 0x2f, nographic & 0xff); - nvram_set_lword(nvram, 0x30, RAM_size); - nvram_set_byte(nvram, 0x34, boot_device); - nvram_set_lword(nvram, 0x38, kernel_image); - nvram_set_lword(nvram, 0x3C, kernel_size); + uint8_t image[0x1ff0]; + ohwcfg_v3_t *header = (ohwcfg_v3_t *)ℑ + struct sparc_arch_cfg *sparc_header; + struct OpenBIOS_nvpart_v1 *part_header; + + memset(image, '\0', sizeof(image)); + + // Try to match PPC NVRAM + strcpy(header->struct_ident, "QEMU_BIOS"); + header->struct_version = cpu_to_be32(3); /* structure v3 */ + + header->nvram_size = cpu_to_be16(NVRAM_size); + header->nvram_arch_ptr = cpu_to_be16(sizeof(ohwcfg_v3_t)); + header->nvram_arch_size = cpu_to_be16(sizeof(struct sparc_arch_cfg)); + strcpy(header->arch, arch); + header->nb_cpus = smp_cpus & 0xff; + header->RAM0_base = 0; + header->RAM0_size = cpu_to_be64((uint64_t)RAM_size); + strcpy(header->boot_devices, boot_devices); + header->nboot_devices = strlen(boot_devices) & 0xff; + header->kernel_image = cpu_to_be64((uint64_t)kernel_image); + header->kernel_size = cpu_to_be64((uint64_t)kernel_size); if (cmdline) { - /* XXX: put the cmdline in NVRAM too ? */ strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); - nvram_set_lword(nvram, 0x44, strlen(cmdline)); - } else { - nvram_set_lword(nvram, 0x40, 0); - nvram_set_lword(nvram, 0x44, 0); + header->cmdline = cpu_to_be64((uint64_t)CMDLINE_ADDR); + header->cmdline_size = cpu_to_be64((uint64_t)strlen(cmdline)); } - nvram_set_lword(nvram, 0x48, initrd_image); - nvram_set_lword(nvram, 0x4C, initrd_size); - nvram_set_lword(nvram, 0x50, NVRAM_image); + header->initrd_image = cpu_to_be64((uint64_t)initrd_image); + header->initrd_size = cpu_to_be64((uint64_t)initrd_size); + header->NVRAM_image = cpu_to_be64((uint64_t)NVRAM_image); + + header->width = cpu_to_be16(width); + header->height = cpu_to_be16(height); + header->depth = cpu_to_be16(depth); + if (nographic) + header->graphic_flags = cpu_to_be16(OHW_GF_NOGRAPHICS); - nvram_set_word(nvram, 0x54, width); - nvram_set_word(nvram, 0x56, height); - nvram_set_word(nvram, 0x58, depth); - crc = nvram_compute_crc(nvram, 0x00, 0xF8); - nvram_set_word(nvram, 0xFC, crc); + header->crc = cpu_to_be16(OHW_compute_crc(header, 0x00, 0xF8)); + + // Architecture specific header + start = sizeof(ohwcfg_v3_t); + sparc_header = (struct sparc_arch_cfg *)&image[start]; + sparc_header->valid = 0; + start += sizeof(struct sparc_arch_cfg); // OpenBIOS nvram variables // Variable partition - start = 256; - m48t59_write(nvram, start, 0x70); - nvram_set_string(nvram, start + 4, "system", 12); + part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; + part_header->signature = OPENBIOS_PART_SYSTEM; + strcpy(part_header->name, "system"); - end = start + 16; + end = start + sizeof(struct OpenBIOS_nvpart_v1); for (i = 0; i < nb_prom_envs; i++) - end = nvram_set_var(nvram, end, prom_envs[i]); + end = OpenBIOS_set_var(image, end, prom_envs[i]); + + // End marker + image[end++] = '\0'; - m48t59_write(nvram, end++ , 0); end = start + ((end - start + 15) & ~15); - nvram_finish_partition(nvram, start, end); + OpenBIOS_finish_partition(part_header, end - start); // free partition start = end; - m48t59_write(nvram, start, 0x7f); - nvram_set_string(nvram, start + 4, "free", 12); + part_header = (struct OpenBIOS_nvpart_v1 *)&image[start]; + part_header->signature = OPENBIOS_PART_FREE; + strcpy(part_header->name, "free"); end = 0x1fd0; - nvram_finish_partition(nvram, start, end); + OpenBIOS_finish_partition(part_header, end - start); + + for (i = 0; i < sizeof(image); i++) + m48t59_write(nvram, i, image[i]); return 0; } @@ -306,7 +219,7 @@ static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; static fdctrl_t *floppy_controller; /* Sun4u hardware initialisation */ -static void sun4u_init(int ram_size, int vga_ram_size, const char *boot_device, +static void sun4u_init(int ram_size, int vga_ram_size, const char *boot_devices, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -428,7 +341,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, const char *boot_device, i8042_init(NULL/*1*/, NULL/*12*/, 0x60); floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table); nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59); - sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device[0], + sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_devices, KERNEL_LOAD_ADDR, kernel_size, kernel_cmdline, INITRD_LOAD_ADDR, initrd_size, -- cgit v1.2.3 From 6376fa993c1252c7206f73e027199bdc7fb4ff9b Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 14 Nov 2007 19:41:26 +0000 Subject: Update OpenBIOS image to SVN revision 176. Changes: r172: Enable boot mode in the exception handler for both SuperSparc and TurboSparc r173: More CPU definitions r174: Add Sparc64 CPU identification r175: Add SPARCserver 600MP emulation r176: Update OHW interface to version 3. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3649 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 4 ++-- pc-bios/openbios-sparc32 | Bin 272948 -> 272948 bytes pc-bios/openbios-sparc64 | Bin 475784 -> 475784 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index 64dba9427..0c3cfe0e1 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,8 +14,8 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included Sparc32 image is built from SVN revision 171 and - Sparc64 image from revision 169. + The included Sparc32 and Sparc64 images are built from SVN + revision 176. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 8f5a63f0c..101b3ce11 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 57b129ff7..14b00734e 100644 Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ -- cgit v1.2.3 From 4dbc422b55858f6465c38dd0d1b9fbeac856ff43 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 15 Nov 2007 15:27:03 +0000 Subject: x86_64 fixes git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3650 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index cfe2a0e36..bfb270b2d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -153,14 +153,14 @@ uint64_t idt_table[512]; static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, uint64_t addr, unsigned int sel) { - unsigned int e1, e2; - uint32_t *p; + uint32_t *p, e1, e2; e1 = (addr & 0xffff) | (sel << 16); e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); p = ptr; - p[0] = tswapl(e1); - p[1] = tswapl(e2); - p[2] = addr >> 32; + p[0] = tswap32(e1); + p[1] = tswap32(e2); + p[2] = tswap32(addr >> 32); + p[3] = 0; } /* only dpl matters as we do only user space emulation */ static void set_idt(int n, unsigned int dpl) @@ -173,13 +173,12 @@ uint64_t idt_table[256]; static void set_gate(void *ptr, unsigned int type, unsigned int dpl, uint32_t addr, unsigned int sel) { - unsigned int e1, e2; - uint32_t *p; + uint32_t *p, e1, e2; e1 = (addr & 0xffff) | (sel << 16); e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); p = ptr; - p[0] = tswapl(e1); - p[1] = tswapl(e2); + p[0] = tswap32(e1); + p[1] = tswap32(e2); } /* only dpl matters as we do only user space emulation */ @@ -2113,9 +2112,13 @@ int main(int argc, char **argv) env->hflags |= HF_OSFXSR_MASK; } #ifndef TARGET_ABI32 - /* enable 64 bit mode */ + /* enable 64 bit mode if possible */ + if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) { + fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n"); + exit(1); + } env->cr[4] |= CR4_PAE_MASK; - env->efer |= MSR_EFER_LMA; + env->efer |= MSR_EFER_LMA | MSR_EFER_LME; env->hflags |= HF_LMA_MASK; #endif -- cgit v1.2.3 From 7ded4f523aad6f3246452c19d07c17963b7bd591 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 15 Nov 2007 15:37:50 +0000 Subject: force correct ppc64 cpu git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3651 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index bfb270b2d..eabb23774 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2032,7 +2032,11 @@ int main(int argc, char **argv) cpu_model = "24Kf"; #endif #elif defined(TARGET_PPC) +#ifdef TARGET_PPC64 + cpu_model = "970"; +#else cpu_model = "750"; +#endif #else cpu_model = "any"; #endif -- cgit v1.2.3 From 67276f53dc0b66d843bff01da722c19d03108503 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 15 Nov 2007 19:04:08 +0000 Subject: Init dumb display if no others available. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3652 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vl.c b/vl.c index 1586f123f..166bacf31 100644 --- a/vl.c +++ b/vl.c @@ -8458,6 +8458,8 @@ int main(int argc, char **argv) sdl_display_init(ds, full_screen, no_frame); #elif defined(CONFIG_COCOA) cocoa_display_init(ds, full_screen); +#else + dumb_display_init(ds); #endif } -- cgit v1.2.3 From 2f6196984b98fe2a852b1b5254756f1614eb7635 Mon Sep 17 00:00:00 2001 From: bellard Date: Fri, 16 Nov 2007 10:46:05 +0000 Subject: suppressed tgetx and tputx (initial patch by Thayne Harbaugh) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3653 c046a42c-6fe2-441c-8c8c-71466251a162 --- arm-semi.c | 16 +- linux-user/elfload.c | 25 ++- linux-user/flatload.c | 31 ++- linux-user/linuxload.c | 25 ++- linux-user/main.c | 30 +-- linux-user/qemu.h | 47 +++-- linux-user/syscall.c | 446 ++++++++++++++++++++++++++++-------------- m68k-semi.c | 28 ++- softmmu-semi.h | 9 +- target-arm/nwfpe/fpa11_cpdt.c | 64 +++--- 10 files changed, 473 insertions(+), 248 deletions(-) diff --git a/arm-semi.c b/arm-semi.c index d5fb9a55a..423aaf7b5 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -165,8 +165,14 @@ static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err) #endif } -#define ARG(n) tget32(args + (n) * 4) -#define SET_ARG(n, val) tput32(args + (n) * 4,val) +#define ARG(n) \ +({ \ + target_ulong __arg; \ + /* FIXME - handle get_user() failure */ \ + get_user_ual(__arg, args + (n) * 4); \ + __arg; \ +}) +#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4) uint32_t do_arm_semihosting(CPUState *env) { target_ulong args; @@ -213,7 +219,11 @@ uint32_t do_arm_semihosting(CPUState *env) } case SYS_WRITEC: { - char c = tget8(args); + char c; + + if (get_user_u8(c, args)) + /* FIXME - should this error code be -TARGET_EFAULT ? */ + return (uint32_t)-1; /* Write to debug console. stderr is near enough. */ if (use_gdb_syscalls()) { gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 14c6417ae..cde3c49a7 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -179,8 +179,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->ARM_cpsr |= CPSR_T; regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; - regs->ARM_r2 = tgetl(stack + 8); /* envp */ - regs->ARM_r1 = tgetl(stack + 4); /* envp */ + /* FIXME - what to for failure of get_user()? */ + get_user_ual(regs->ARM_r2, stack + 8); /* envp */ + get_user_ual(regs->ARM_r1, stack + 4); /* envp */ /* XXX: it seems that r0 is zeroed after ! */ regs->ARM_r0 = 0; /* For uClinux PIC binaries. */ @@ -341,7 +342,8 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * * but this is what the ABI wants and is needed to allow * execution of PPC BSD programs. */ - _regs->gpr[3] = tgetl(pos); + /* FIXME - what to for failure of get_user()? */ + get_user_ual(_regs->gpr[3], pos); pos += sizeof(abi_ulong); _regs->gpr[4] = pos; for (tmp = 1; tmp != 0; pos += sizeof(abi_ulong)) @@ -733,7 +735,8 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss) if (nbyte) { nbyte = qemu_host_page_size - nbyte; do { - tput8(elf_bss, 0); + /* FIXME - what to do if put_user() fails? */ + put_user_u8(0, elf_bss); elf_bss++; } while (--nbyte); } @@ -782,17 +785,11 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off */ -#if ELF_CLASS == ELFCLASS32 -#define NEW_AUX_ENT(id, val) do { \ - sp -= n; tput32(sp, val); \ - sp -= n; tput32(sp, id); \ +#define NEW_AUX_ENT(id, val) do { \ + sp -= n; put_user_ual(val, sp); \ + sp -= n; put_user_ual(id, sp); \ } while(0) -#else -#define NEW_AUX_ENT(id, val) do { \ - sp -= n; tput64(sp, val); \ - sp -= n; tput64(sp, id); \ - } while(0) -#endif + NEW_AUX_ENT (AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 7a76c0fcd..95d386468 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -598,14 +598,16 @@ static int load_flat_file(struct linux_binprm * bprm, rp = datapos; while (1) { abi_ulong addr; - addr = tgetl(rp); + if (get_user_ual(addr, rp)) + return -EFAULT; if (addr == -1) break; if (addr) { addr = calc_reloc(addr, libinfo, id, 0); if (addr == RELOC_FAILED) return -ENOEXEC; - tputl(rp, addr); + if (put_user_ual(addr, rp)) + return -EFAULT; } rp += sizeof(abi_ulong); } @@ -629,14 +631,16 @@ static int load_flat_file(struct linux_binprm * bprm, /* Get the address of the pointer to be relocated (of course, the address has to be relocated first). */ - relval = tgetl(reloc + i * sizeof (abi_ulong)); + if (get_user_ual(relval, reloc + i * sizeof(abi_ulong))) + return -EFAULT; addr = flat_get_relocate_addr(relval); rp = calc_reloc(addr, libinfo, id, 1); if (rp == RELOC_FAILED) return -ENOEXEC; /* Get the pointer's value. */ - addr = tgetl(rp); + if (get_user_ual(addr, rp)) + return -EFAULT; if (addr != 0) { /* * Do the relocation. PIC relocs in the data section are @@ -652,13 +656,15 @@ static int load_flat_file(struct linux_binprm * bprm, return -ENOEXEC; /* Write back the relocated pointer. */ - tputl(rp, addr); + if (put_user_ual(addr, rp)) + return -EFAULT; } } } else { for (i = 0; i < relocs; i++) { abi_ulong relval; - relval = tgetl(reloc + i * sizeof (abi_ulong)); + if (get_user_ual(relval, reloc + i * sizeof(abi_ulong))) + return -EFAULT; old_reloc(&libinfo[0], relval); } } @@ -744,9 +750,12 @@ int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, p = libinfo[i].start_data; for (j=0; j0; i--) { if (libinfo[i].loaded) { /* Push previos first to call address */ - --sp; put_user(start_addr, sp); + --sp; + if (put_user_ual(start_addr, sp)) + return -EFAULT; start_addr = libinfo[i].entry; } } diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 684ec06ce..ada7c697d 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -124,21 +124,32 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, sp -= (argc + 1) * n; argv = sp; if (push_ptr) { - sp -= n; tputl(sp, envp); - sp -= n; tputl(sp, argv); + /* FIXME - handle put_user() failures */ + sp -= n; + put_user_ual(envp, sp); + sp -= n; + put_user_ual(argv, sp); } - sp -= n; tputl(sp, argc); + sp -= n; + /* FIXME - handle put_user() failures */ + put_user_ual(argc, sp); while (argc-- > 0) { - tputl(argv, stringp); argv += n; + /* FIXME - handle put_user() failures */ + put_user_ual(stringp, argv); + argv += n; stringp += target_strlen(stringp) + 1; } - tputl(argv, 0); + /* FIXME - handle put_user() failures */ + put_user_ual(0, argv); while (envc-- > 0) { - tputl(envp, stringp); envp += n; + /* FIXME - handle put_user() failures */ + put_user_ual(stringp, envp); + envp += n; stringp += target_strlen(stringp) + 1; } - tputl(envp, 0); + /* FIXME - handle put_user() failures */ + put_user_ual(0, envp); return sp; } diff --git a/linux-user/main.c b/linux-user/main.c index eabb23774..2192abb48 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -380,7 +380,8 @@ void cpu_loop(CPUARMState *env) /* we handle the FPU emulation here, as Linux */ /* we get the opcode */ - opcode = tget32(env->regs[15]); + /* FIXME - what to do if get_user() fails? */ + get_user_u32(opcode, env->regs[15]); if (EmulateAll(opcode, &ts->fpa, env) == 0) { info.si_signo = SIGILL; @@ -401,20 +402,24 @@ void cpu_loop(CPUARMState *env) /* system call */ if (trapnr == EXCP_BKPT) { if (env->thumb) { - insn = tget16(env->regs[15]); + /* FIXME - what to do if get_user() fails? */ + get_user_u16(insn, env->regs[15]); n = insn & 0xff; env->regs[15] += 2; } else { - insn = tget32(env->regs[15]); + /* FIXME - what to do if get_user() fails? */ + get_user_u32(insn, env->regs[15]); n = (insn & 0xf) | ((insn >> 4) & 0xff0); env->regs[15] += 4; } } else { if (env->thumb) { - insn = tget16(env->regs[15] - 2); + /* FIXME - what to do if get_user() fails? */ + get_user_u16(insn, env->regs[15] - 2); n = insn & 0xff; } else { - insn = tget32(env->regs[15] - 4); + /* FIXME - what to do if get_user() fails? */ + get_user_u32(insn, env->regs[15] - 4); n = insn & 0xffffff; } } @@ -520,7 +525,8 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1) (int)sp_ptr, cwp1); #endif for(i = 0; i < 16; i++) { - tputl(sp_ptr, env->regbase[get_reg_index(env, cwp1, 8 + i)]); + /* FIXME - what to do if put_user() fails? */ + put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); sp_ptr += sizeof(abi_ulong); } } @@ -556,7 +562,8 @@ static void restore_window(CPUSPARCState *env) (int)sp_ptr, cwp1); #endif for(i = 0; i < 16; i++) { - env->regbase[get_reg_index(env, cwp1, 8 + i)] = tgetl(sp_ptr); + /* FIXME - what to do if get_user() fails? */ + get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); sp_ptr += sizeof(abi_ulong); } env->wim = new_wim; @@ -1533,10 +1540,11 @@ void cpu_loop(CPUMIPSState *env) sp_reg = env->gpr[29][env->current_tc]; switch (nb_args) { /* these arguments are taken from the stack */ - case 8: arg8 = tgetl(sp_reg + 28); - case 7: arg7 = tgetl(sp_reg + 24); - case 6: arg6 = tgetl(sp_reg + 20); - case 5: arg5 = tgetl(sp_reg + 16); + /* FIXME - what to do if get_user() fails? */ + case 8: get_user_ual(arg8, sp_reg + 28); + case 7: get_user_ual(arg7, sp_reg + 24); + case 6: get_user_ual(arg6, sp_reg + 20); + case 5: get_user_ual(arg5, sp_reg + 16); default: break; } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 537facbf2..c0780084b 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -226,7 +226,7 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size) int size = sizeof(*hptr);\ switch(size) {\ case 1:\ - *(uint8_t *)(hptr) = (typeof(*hptr))(x);\ + *(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\ break;\ case 2:\ *(uint16_t *)(hptr) = tswap16((typeof(*hptr))(x));\ @@ -260,6 +260,8 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size) x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\ break;\ default:\ + /* avoid warning */\ + x = 0;\ abort();\ }\ 0;\ @@ -291,11 +293,36 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size) if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ __ret = __get_user((x), __hptr); \ unlock_user(__hptr, __gaddr, 0); \ - } else \ + } else { \ + /* avoid warning */ \ + (x) = 0; \ __ret = -TARGET_EFAULT; \ + } \ __ret; \ }) +#define put_user_ual(x, gaddr) put_user((x), (gaddr), abi_ulong) +#define put_user_sal(x, gaddr) put_user((x), (gaddr), abi_long) +#define put_user_u64(x, gaddr) put_user((x), (gaddr), uint64_t) +#define put_user_s64(x, gaddr) put_user((x), (gaddr), int64_t) +#define put_user_u32(x, gaddr) put_user((x), (gaddr), uint32_t) +#define put_user_s32(x, gaddr) put_user((x), (gaddr), int32_t) +#define put_user_u16(x, gaddr) put_user((x), (gaddr), uint16_t) +#define put_user_s16(x, gaddr) put_user((x), (gaddr), int16_t) +#define put_user_u8(x, gaddr) put_user((x), (gaddr), uint8_t) +#define put_user_s8(x, gaddr) put_user((x), (gaddr), int8_t) + +#define get_user_ual(x, gaddr) get_user((x), (gaddr), abi_ulong) +#define get_user_sal(x, gaddr) get_user((x), (gaddr), abi_long) +#define get_user_u64(x, gaddr) get_user((x), (gaddr), uint64_t) +#define get_user_s64(x, gaddr) get_user((x), (gaddr), int64_t) +#define get_user_u32(x, gaddr) get_user((x), (gaddr), uint32_t) +#define get_user_s32(x, gaddr) get_user((x), (gaddr), int32_t) +#define get_user_u16(x, gaddr) get_user((x), (gaddr), uint16_t) +#define get_user_s16(x, gaddr) get_user((x), (gaddr), int16_t) +#define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t) +#define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t) + /* copy_from_user() and copy_to_user() are usually used to copy data * buffers between the target and host. These internally perform * locking/unlocking of the memory. @@ -368,20 +395,4 @@ static inline void *lock_user_string(abi_ulong guest_addr) #define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) -#define tget8(addr) ldub(addr) -#define tput8(addr, val) stb(addr, val) -#define tget16(addr) lduw(addr) -#define tput16(addr, val) stw(addr, val) -#define tget32(addr) ldl(addr) -#define tput32(addr, val) stl(addr, val) -#define tget64(addr) ldq(addr) -#define tput64(addr, val) stq(addr, val) -#if TARGET_ABI_BITS == 64 -#define tgetl(addr) ldq(addr) -#define tputl(addr, val) stq(addr, val) -#else -#define tgetl(addr) ldl(addr) -#define tputl(addr, val) stl(addr, val) -#endif - #endif /* QEMU_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ab252cfe8..6f2872fff 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -783,7 +783,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, /* do_setsockopt() Must return target values and target errnos. */ static abi_long do_setsockopt(int sockfd, int level, int optname, - abi_ulong optval, socklen_t optlen) + abi_ulong optval_addr, socklen_t optlen) { abi_long ret; int val; @@ -794,7 +794,8 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, if (optlen < sizeof(uint32_t)) return -TARGET_EINVAL; - val = tget32(optval); + if (get_user_u32(val, optval_addr)) + return -TARGET_EFAULT; ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; case SOL_IP: @@ -816,9 +817,11 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, case IP_MULTICAST_LOOP: val = 0; if (optlen >= sizeof(uint32_t)) { - val = tget32(optval); + if (get_user_u32(val, optval_addr)) + return -TARGET_EFAULT; } else if (optlen >= 1) { - val = tget8(optval); + if (get_user_u8(val, optval_addr)) + return -TARGET_EFAULT; } ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; @@ -890,9 +893,10 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, goto unimplemented; } if (optlen < sizeof(uint32_t)) - return -TARGET_EINVAL; + return -TARGET_EINVAL; - val = tget32(optval); + if (get_user_u32(val, optval_addr)) + return -TARGET_EFAULT; ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); break; default: @@ -905,7 +909,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, /* do_getsockopt() Must return target values and target errnos. */ static abi_long do_getsockopt(int sockfd, int level, int optname, - abi_ulong optval, abi_ulong optlen) + abi_ulong optval_addr, abi_ulong optlen) { abi_long ret; int len, lv, val; @@ -928,7 +932,8 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, case SOL_TCP: /* TCP options all take an 'int' value. */ int_case: - len = tget32(optlen); + if (get_user_u32(len, optlen)) + return -TARGET_EFAULT; if (len < 0) return -TARGET_EINVAL; lv = sizeof(int); @@ -938,11 +943,15 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, val = tswap32(val); if (len > lv) len = lv; - if (len == 4) - tput32(optval, val); - else - tput8(optval, val); - tput32(optlen, len); + if (len == 4) { + if (put_user_u32(val, optval_addr)) + return -TARGET_EFAULT; + } else { + if (put_user_u8(val, optval_addr)) + return -TARGET_EFAULT; + } + if (put_user_u32(len, optlen)) + return -TARGET_EFAULT; break; case SOL_IP: switch(optname) { @@ -961,7 +970,8 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, #endif case IP_MULTICAST_TTL: case IP_MULTICAST_LOOP: - len = tget32(optlen); + if (get_user_u32(len, optlen)) + return -TARGET_EFAULT; if (len < 0) return -TARGET_EINVAL; lv = sizeof(int); @@ -970,13 +980,15 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, return ret; if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { len = 1; - tput32(optlen, len); - tput8(optval, val); + if (put_user_u32(len, optlen) + || put_user_u8(val, optval_addr)) + return -TARGET_EFAULT; } else { if (len > sizeof(int)) len = sizeof(int); - tput32(optlen, len); - tput32(optval, val); + if (put_user_u32(len, optlen) + || put_user_u32(val, optval_addr)) + return -TARGET_EFAULT; } break; default: @@ -1148,63 +1160,82 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, /* do_accept() Must return target values and target errnos. */ static abi_long do_accept(int fd, abi_ulong target_addr, - abi_ulong target_addrlen) + abi_ulong target_addrlen_addr) { - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); + socklen_t addrlen; + void *addr; abi_long ret; + if (get_user_u32(addrlen, target_addrlen_addr)) + return -TARGET_EFAULT; + + addr = alloca(addrlen); + ret = get_errno(accept(fd, addr, &addrlen)); if (!is_error(ret)) { host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); + if (put_user_u32(addrlen, target_addrlen_addr)) + ret = -TARGET_EFAULT; } return ret; } /* do_getpeername() Must return target values and target errnos. */ static abi_long do_getpeername(int fd, abi_ulong target_addr, - abi_ulong target_addrlen) + abi_ulong target_addrlen_addr) { - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); + socklen_t addrlen; + void *addr; abi_long ret; + if (get_user_u32(addrlen, target_addrlen_addr)) + return -TARGET_EFAULT; + + addr = alloca(addrlen); + ret = get_errno(getpeername(fd, addr, &addrlen)); if (!is_error(ret)) { host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); + if (put_user_u32(addrlen, target_addrlen_addr)) + ret = -TARGET_EFAULT; } return ret; } /* do_getsockname() Must return target values and target errnos. */ static abi_long do_getsockname(int fd, abi_ulong target_addr, - abi_ulong target_addrlen) + abi_ulong target_addrlen_addr) { - socklen_t addrlen = tget32(target_addrlen); - void *addr = alloca(addrlen); + socklen_t addrlen; + void *addr; abi_long ret; + if (get_user_u32(addrlen, target_addrlen_addr)) + return -TARGET_EFAULT; + + addr = alloca(addrlen); + ret = get_errno(getsockname(fd, addr, &addrlen)); if (!is_error(ret)) { host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); + if (put_user_u32(addrlen, target_addrlen_addr)) + ret = -TARGET_EFAULT; } return ret; } /* do_socketpair() Must return target values and target errnos. */ static abi_long do_socketpair(int domain, int type, int protocol, - abi_ulong target_tab) + abi_ulong target_tab_addr) { int tab[2]; abi_long ret; ret = get_errno(socketpair(domain, type, protocol, tab)); if (!is_error(ret)) { - tput32(target_tab, tab[0]); - tput32(target_tab + 4, tab[1]); + if (put_user_s32(tab[0], target_tab_addr) + || put_user_s32(tab[1], target_tab_addr + sizeof(tab[0]))) + ret = -TARGET_EFAULT; } return ret; } @@ -1245,7 +1276,10 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, if (!host_msg) return -TARGET_EFAULT; if (target_addr) { - addrlen = tget32(target_addrlen); + if (get_user_u32(addrlen, target_addrlen)) { + ret = -TARGET_EFAULT; + goto fail; + } addr = alloca(addrlen); ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen)); } else { @@ -1255,10 +1289,14 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags, if (!is_error(ret)) { if (target_addr) { host_to_target_sockaddr(target_addr, addr, addrlen); - tput32(target_addrlen, addrlen); + if (put_user_u32(addrlen, target_addrlen)) { + ret = -TARGET_EFAULT; + goto fail; + } } unlock_user(host_msg, msg, len); } else { +fail: unlock_user(host_msg, msg, 0); } return ret; @@ -1274,112 +1312,187 @@ static abi_long do_socketcall(int num, abi_ulong vptr) switch(num) { case SOCKOP_socket: { - int domain = tgetl(vptr); - int type = tgetl(vptr + n); - int protocol = tgetl(vptr + 2 * n); + int domain, type, protocol; + + if (get_user_s32(domain, vptr) + || get_user_s32(type, vptr + n) + || get_user_s32(protocol, vptr + 2 * n)) + return -TARGET_EFAULT; + ret = do_socket(domain, type, protocol); } break; case SOCKOP_bind: { - int sockfd = tgetl(vptr); - abi_ulong target_addr = tgetl(vptr + n); - socklen_t addrlen = tgetl(vptr + 2 * n); + int sockfd; + abi_ulong target_addr; + socklen_t addrlen; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(target_addr, vptr + n) + || get_user_u32(addrlen, vptr + 2 * n)) + return -TARGET_EFAULT; + ret = do_bind(sockfd, target_addr, addrlen); } break; case SOCKOP_connect: { - int sockfd = tgetl(vptr); - abi_ulong target_addr = tgetl(vptr + n); - socklen_t addrlen = tgetl(vptr + 2 * n); + int sockfd; + abi_ulong target_addr; + socklen_t addrlen; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(target_addr, vptr + n) + || get_user_u32(addrlen, vptr + 2 * n)) + return -TARGET_EFAULT; + ret = do_connect(sockfd, target_addr, addrlen); } break; case SOCKOP_listen: { - int sockfd = tgetl(vptr); - int backlog = tgetl(vptr + n); + int sockfd, backlog; + + if (get_user_s32(sockfd, vptr) + || get_user_s32(backlog, vptr + n)) + return -TARGET_EFAULT; + ret = get_errno(listen(sockfd, backlog)); } break; case SOCKOP_accept: { - int sockfd = tgetl(vptr); - abi_ulong target_addr = tgetl(vptr + n); - abi_ulong target_addrlen = tgetl(vptr + 2 * n); + int sockfd; + abi_ulong target_addr, target_addrlen; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(target_addr, vptr + n) + || get_user_u32(target_addrlen, vptr + 2 * n)) + return -TARGET_EFAULT; + ret = do_accept(sockfd, target_addr, target_addrlen); } break; case SOCKOP_getsockname: { - int sockfd = tgetl(vptr); - abi_ulong target_addr = tgetl(vptr + n); - abi_ulong target_addrlen = tgetl(vptr + 2 * n); + int sockfd; + abi_ulong target_addr, target_addrlen; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(target_addr, vptr + n) + || get_user_u32(target_addrlen, vptr + 2 * n)) + return -TARGET_EFAULT; + ret = do_getsockname(sockfd, target_addr, target_addrlen); } break; case SOCKOP_getpeername: { - int sockfd = tgetl(vptr); - abi_ulong target_addr = tgetl(vptr + n); - abi_ulong target_addrlen = tgetl(vptr + 2 * n); + int sockfd; + abi_ulong target_addr, target_addrlen; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(target_addr, vptr + n) + || get_user_u32(target_addrlen, vptr + 2 * n)) + return -TARGET_EFAULT; + ret = do_getpeername(sockfd, target_addr, target_addrlen); } break; case SOCKOP_socketpair: { - int domain = tgetl(vptr); - int type = tgetl(vptr + n); - int protocol = tgetl(vptr + 2 * n); - abi_ulong tab = tgetl(vptr + 3 * n); + int domain, type, protocol; + abi_ulong tab; + + if (get_user_s32(domain, vptr) + || get_user_s32(type, vptr + n) + || get_user_s32(protocol, vptr + 2 * n) + || get_user_ual(tab, vptr + 3 * n)) + return -TARGET_EFAULT; + ret = do_socketpair(domain, type, protocol, tab); } break; case SOCKOP_send: { - int sockfd = tgetl(vptr); - abi_ulong msg = tgetl(vptr + n); - size_t len = tgetl(vptr + 2 * n); - int flags = tgetl(vptr + 3 * n); + int sockfd; + abi_ulong msg; + size_t len; + int flags; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(msg, vptr + n) + || get_user_ual(len, vptr + 2 * n) + || get_user_s32(flags, vptr + 3 * n)) + return -TARGET_EFAULT; + ret = do_sendto(sockfd, msg, len, flags, 0, 0); } break; case SOCKOP_recv: { - int sockfd = tgetl(vptr); - abi_ulong msg = tgetl(vptr + n); - size_t len = tgetl(vptr + 2 * n); - int flags = tgetl(vptr + 3 * n); + int sockfd; + abi_ulong msg; + size_t len; + int flags; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(msg, vptr + n) + || get_user_ual(len, vptr + 2 * n) + || get_user_s32(flags, vptr + 3 * n)) + return -TARGET_EFAULT; + ret = do_recvfrom(sockfd, msg, len, flags, 0, 0); } break; case SOCKOP_sendto: { - int sockfd = tgetl(vptr); - abi_ulong msg = tgetl(vptr + n); - size_t len = tgetl(vptr + 2 * n); - int flags = tgetl(vptr + 3 * n); - abi_ulong addr = tgetl(vptr + 4 * n); - socklen_t addrlen = tgetl(vptr + 5 * n); + int sockfd; + abi_ulong msg; + size_t len; + int flags; + abi_ulong addr; + socklen_t addrlen; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(msg, vptr + n) + || get_user_ual(len, vptr + 2 * n) + || get_user_s32(flags, vptr + 3 * n) + || get_user_ual(addr, vptr + 4 * n) + || get_user_u32(addrlen, vptr + 5 * n)) + return -TARGET_EFAULT; + ret = do_sendto(sockfd, msg, len, flags, addr, addrlen); } break; case SOCKOP_recvfrom: { - int sockfd = tgetl(vptr); - abi_ulong msg = tgetl(vptr + n); - size_t len = tgetl(vptr + 2 * n); - int flags = tgetl(vptr + 3 * n); - abi_ulong addr = tgetl(vptr + 4 * n); - abi_ulong addrlen = tgetl(vptr + 5 * n); + int sockfd; + abi_ulong msg; + size_t len; + int flags; + abi_ulong addr; + socklen_t addrlen; + + if (get_user_s32(sockfd, vptr) + || get_user_ual(msg, vptr + n) + || get_user_ual(len, vptr + 2 * n) + || get_user_s32(flags, vptr + 3 * n) + || get_user_ual(addr, vptr + 4 * n) + || get_user_u32(addrlen, vptr + 5 * n)) + return -TARGET_EFAULT; + ret = do_recvfrom(sockfd, msg, len, flags, addr, addrlen); } break; case SOCKOP_shutdown: { - int sockfd = tgetl(vptr); - int how = tgetl(vptr + n); + int sockfd, how; + + if (get_user_s32(sockfd, vptr) + || get_user_s32(how, vptr + n)) + return -TARGET_EFAULT; ret = get_errno(shutdown(sockfd, how)); } @@ -1391,9 +1504,10 @@ static abi_long do_socketcall(int num, abi_ulong vptr) abi_ulong target_msg; int flags; - fd = tgetl(vptr); - target_msg = tgetl(vptr + n); - flags = tgetl(vptr + 2 * n); + if (get_user_s32(fd, vptr) + || get_user_ual(target_msg, vptr + n) + || get_user_s32(flags, vptr + 2 * n)) + return -TARGET_EFAULT; ret = do_sendrecvmsg(fd, target_msg, flags, (num == SOCKOP_sendmsg)); @@ -1401,24 +1515,38 @@ static abi_long do_socketcall(int num, abi_ulong vptr) break; case SOCKOP_setsockopt: { - int sockfd = tgetl(vptr); - int level = tgetl(vptr + n); - int optname = tgetl(vptr + 2 * n); - abi_ulong optval = tgetl(vptr + 3 * n); - socklen_t optlen = tgetl(vptr + 4 * n); + int sockfd; + int level; + int optname; + abi_ulong optval; + socklen_t optlen; + + if (get_user_s32(sockfd, vptr) + || get_user_s32(level, vptr + n) + || get_user_s32(optname, vptr + 2 * n) + || get_user_ual(optval, vptr + 3 * n) + || get_user_u32(optlen, vptr + 4 * n)) + return -TARGET_EFAULT; ret = do_setsockopt(sockfd, level, optname, optval, optlen); } break; case SOCKOP_getsockopt: { - int sockfd = tgetl(vptr); - int level = tgetl(vptr + n); - int optname = tgetl(vptr + 2 * n); - abi_ulong optval = tgetl(vptr + 3 * n); - abi_ulong poptlen = tgetl(vptr + 4 * n); + int sockfd; + int level; + int optname; + abi_ulong optval; + socklen_t optlen; + + if (get_user_s32(sockfd, vptr) + || get_user_s32(level, vptr + n) + || get_user_s32(optname, vptr + 2 * n) + || get_user_ual(optval, vptr + 3 * n) + || get_user_u32(optlen, vptr + 4 * n)) + return -TARGET_EFAULT; - ret = do_getsockopt(sockfd, level, optname, optval, poptlen); + ret = do_getsockopt(sockfd, level, optname, optval, optlen); } break; default: @@ -1883,7 +2011,7 @@ static abi_long do_ipc(unsigned int call, int first, break; } } - if (put_user(raddr, third, abi_ulong)) + if (put_user_ual(raddr, third)) return -TARGET_EFAULT; ret = 0; } @@ -2957,10 +3085,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user(p, arg2, 0); break; case TARGET_NR_open: - if (!(p = lock_user_string(arg1))) { - return -TARGET_EFAULT; - goto fail; - } + if (!(p = lock_user_string(arg1))) + goto efault; ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl), arg3)); @@ -2991,8 +3117,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { int status; ret = get_errno(waitpid(arg1, &status, arg3)); - if (!is_error(ret) && arg2) - tput32(arg2, status); + if (!is_error(ret) && arg2 + && put_user_s32(status, arg2)) + goto efault; } break; #endif @@ -3059,56 +3186,71 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, argc = 0; guest_argp = arg2; - for (gp = guest_argp; tgetl(gp); gp++) + for (gp = guest_argp; ; gp++) { + if (get_user_ual(guest_argp, gp)) + goto efault; + if (!guest_argp) + break; argc++; + } envc = 0; guest_envp = arg3; - for (gp = guest_envp; tgetl(gp); gp++) + for (gp = guest_envp; ; gp++) { + if (get_user_ual(guest_envp, gp)) + goto efault; + if (!guest_envp) + break; envc++; + } argp = alloca((argc + 1) * sizeof(void *)); envp = alloca((envc + 1) * sizeof(void *)); for (gp = guest_argp, q = argp; ; gp += sizeof(abi_ulong), q++) { - addr = tgetl(gp); + if (get_user_ual(addr, gp)) + goto execve_efault; if (!addr) break; - if (!(*q = lock_user_string(addr))) { - ret = -TARGET_EFAULT; - goto execve_fail; - } + if (!(*q = lock_user_string(addr))) + goto execve_efault; } *q = NULL; for (gp = guest_envp, q = envp; ; gp += sizeof(abi_ulong), q++) { - addr = tgetl(gp); + if (get_user_ual(addr, gp)) + goto execve_efault; if (!addr) break; - if (!(*q = lock_user_string(addr))) { - ret = -TARGET_EFAULT; - goto execve_fail; - } + if (!(*q = lock_user_string(addr))) + goto execve_efault; } *q = NULL; - if (!(p = lock_user_string(arg1))) { - ret = -TARGET_EFAULT; - goto execve_fail; - } + if (!(p = lock_user_string(arg1))) + goto execve_efault; ret = get_errno(execve(p, argp, envp)); unlock_user(p, arg1, 0); - execve_fail: + goto execve_end; + + execve_efault: + ret = -TARGET_EFAULT; + + execve_end: for (gp = guest_argp, q = argp; *q; gp += sizeof(abi_ulong), q++) { - addr = tgetl(gp); + if (get_user_ual(addr, gp) + || !addr) + break; unlock_user(*q, addr, 0); } for (gp = guest_envp, q = envp; *q; gp += sizeof(abi_ulong), q++) { - addr = tgetl(gp); + if (get_user_ual(addr, gp) + || !addr) + break; unlock_user(*q, addr, 0); } } @@ -3124,8 +3266,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { time_t host_time; ret = get_errno(time(&host_time)); - if (!is_error(ret) && arg1) - tputl(arg1, host_time); + if (!is_error(ret) + && arg1 + && put_user_sal(host_time, arg1)) + goto efault; } break; #endif @@ -3199,7 +3343,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_stime: { time_t host_time; - host_time = tgetl(arg1); + if (get_user_sal(host_time, arg1)) + goto efault; ret = get_errno(stime(&host_time)); } break; @@ -3358,8 +3503,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, env->gpr[3][env->current_tc] = host_pipe[1]; ret = host_pipe[0]; #else - tput32(arg1, host_pipe[0]); - tput32(arg1 + 4, host_pipe[1]); + if (put_user_s32(host_pipe[0], arg1) + || put_user_s32(host_pipe[1], arg1 + sizeof(host_pipe[0]))) + goto efault; #endif } } @@ -4267,11 +4413,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, rusage_ptr = NULL; ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); if (!is_error(ret)) { - if (status_ptr) - tputl(status_ptr, status); - if (target_rusage) { - host_to_target_rusage(target_rusage, &rusage); + if (status_ptr) { + if (put_user_s32(status, status_ptr)) + goto efault; } + if (target_rusage) + host_to_target_rusage(target_rusage, &rusage); } } break; @@ -4404,11 +4551,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { #if defined (__x86_64__) ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5)); - tput64(arg4, ret); + if (put_user_s64(ret, arg4)) + goto efault; #else int64_t res; ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5)); - tput64(arg4, res); + if (put_user_s64(res, arg4)) + goto efault; #endif } break; @@ -4674,8 +4823,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { int deathsig; ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5)); - if (!is_error(ret) && arg2) - tput32(arg2, deathsig); + if (!is_error(ret) && arg2 + && put_user_ual(deathsig, arg2)) + goto efault; } break; default: @@ -4932,9 +5082,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, uid_t ruid, euid, suid; ret = get_errno(getresuid(&ruid, &euid, &suid)); if (!is_error(ret)) { - tput16(arg1, tswap16(high2lowuid(ruid))); - tput16(arg2, tswap16(high2lowuid(euid))); - tput16(arg3, tswap16(high2lowuid(suid))); + if (put_user_u16(high2lowuid(ruid), arg1) + || put_user_u16(high2lowuid(euid), arg2) + || put_user_u16(high2lowuid(suid), arg3)) + goto efault; } } break; @@ -4952,9 +5103,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, gid_t rgid, egid, sgid; ret = get_errno(getresgid(&rgid, &egid, &sgid)); if (!is_error(ret)) { - tput16(arg1, tswap16(high2lowgid(rgid))); - tput16(arg2, tswap16(high2lowgid(egid))); - tput16(arg3, tswap16(high2lowgid(sgid))); + if (put_user_u16(high2lowgid(rgid), arg1) + || put_user_u16(high2lowgid(egid), arg2) + || put_user_u16(high2lowgid(sgid), arg3)) + goto efault; } } break; @@ -5077,9 +5229,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, uid_t ruid, euid, suid; ret = get_errno(getresuid(&ruid, &euid, &suid)); if (!is_error(ret)) { - tput32(arg1, tswap32(ruid)); - tput32(arg2, tswap32(euid)); - tput32(arg3, tswap32(suid)); + if (put_user_u32(ruid, arg1) + || put_user_u32(euid, arg2) + || put_user_u32(suid, arg3)) + goto efault; } } break; @@ -5095,9 +5248,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, gid_t rgid, egid, sgid; ret = get_errno(getresgid(&rgid, &egid, &sgid)); if (!is_error(ret)) { - tput32(arg1, tswap32(rgid)); - tput32(arg2, tswap32(egid)); - tput32(arg3, tswap32(sgid)); + if (put_user_u32(rgid, arg1) + || put_user_u32(egid, arg2) + || put_user_u32(sgid, arg3)) + goto efault; } } break; diff --git a/m68k-semi.c b/m68k-semi.c index b0e526933..76b531924 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -142,15 +142,23 @@ static void m68k_semi_cb(CPUState *env, target_ulong ret, target_ulong err) if (m68k_semi_is_fseek) { /* FIXME: We've already lost the high bits of the fseek return value. */ - tput32(args, 0); + /* FIXME - handle put_user() failure */ + put_user_u32(0, args); args += 4; m68k_semi_is_fseek = 0; } - tput32(args, ret); - tput32(args + 4, errno); + /* FIXME - handle put_user() failure */ + put_user_u32(ret, args); + put_user_u32(errno, args + 4); } -#define ARG(x) tget32(args + (x) * 4) +#define ARG(n) \ +({ \ + target_ulong __arg; \ + /* FIXME - handle get_user() failure */ \ + get_user_ual(__arg, args + (n) * 4); \ + __arg; \ +}) #define PARG(x) ((unsigned long)ARG(x)) void do_m68k_semihosting(CPUM68KState *env, int nr) { @@ -237,9 +245,10 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) ARG(0), off, ARG(3)); } else { off = lseek(ARG(0), off, ARG(3)); - tput32(args, off >> 32); - tput32(args + 4, off); - tput32(args + 8, errno); + /* FIXME - handle put_user() failure */ + put_user_u32(off >> 32, args); + put_user_u32(off, args + 4); + put_user_u32(errno, args + 8); } return; } @@ -390,6 +399,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr) cpu_abort(env, "Unsupported semihosting syscall %d\n", nr); result = 0; } - tput32(args, result); - tput32(args + 4, errno); + /* FIXME - handle put_user() failure */ + put_user_u32(result, args); + put_user_u32(errno, args + 4); } diff --git a/softmmu-semi.h b/softmmu-semi.h index 527943a76..8bf96f497 100644 --- a/softmmu-semi.h +++ b/softmmu-semi.h @@ -21,15 +21,18 @@ static inline uint32_t softmmu_tget8(CPUState *env, uint32_t addr) cpu_memory_rw_debug(env, addr, &val, 1, 0); return val; } -#define tget32(p) softmmu_tget32(env, p) -#define tget8(p) softmmu_tget8(env, p) + +#define get_user_u32(arg, p) ({ arg = softmmu_tget32(env, p) ; 0; }) +#define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; }) +#define get_user_ual(arg, p) get_user_u32(arg, p) static inline void softmmu_tput32(CPUState *env, uint32_t addr, uint32_t val) { val = tswap32(val); cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 1); } -#define tput32(p, val) softmmu_tput32(env, p, val) +#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; }) +#define put_user_ual(arg, p) put_user_u32(arg, p) static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len, int copy) diff --git a/target-arm/nwfpe/fpa11_cpdt.c b/target-arm/nwfpe/fpa11_cpdt.c index cae2922e0..41877dfe8 100644 --- a/target-arm/nwfpe/fpa11_cpdt.c +++ b/target-arm/nwfpe/fpa11_cpdt.c @@ -34,7 +34,8 @@ void loadSingle(const unsigned int Fn,const unsigned int *pMem) target_ulong addr = (target_ulong)(long)pMem; FPA11 *fpa11 = GET_FPA11(); fpa11->fType[Fn] = typeSingle; - fpa11->fpreg[Fn].fSingle = tget32(addr); + /* FIXME - handle failure of get_user() */ + get_user_u32(fpa11->fpreg[Fn].fSingle, addr); } static inline @@ -46,11 +47,13 @@ void loadDouble(const unsigned int Fn,const unsigned int *pMem) p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; fpa11->fType[Fn] = typeDouble; #ifdef WORDS_BIGENDIAN - p[0] = tget32(addr); /* sign & exponent */ - p[1] = tget32(addr + 4); + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr); /* sign & exponent */ + get_user_u32(p[1], addr + 4); #else - p[0] = tget32(addr + 4); - p[1] = tget32(addr); /* sign & exponent */ + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr + 4); + get_user_u32(p[1], addr); /* sign & exponent */ #endif } @@ -62,9 +65,10 @@ void loadExtended(const unsigned int Fn,const unsigned int *pMem) unsigned int *p; p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; fpa11->fType[Fn] = typeExtended; - p[0] = tget32(addr); /* sign & exponent */ - p[1] = tget32(addr + 8); /* ls bits */ - p[2] = tget32(addr + 4); /* ms bits */ + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr); /* sign & exponent */ + get_user_u32(p[1], addr + 8); /* ls bits */ + get_user_u32(p[2], addr + 4); /* ms bits */ } static inline @@ -76,7 +80,8 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) unsigned long x; p = (unsigned int*)&(fpa11->fpreg[Fn]); - x = tget32(addr); + /* FIXME - handle failure of get_user() */ + get_user_u32(x, addr); fpa11->fType[Fn] = (x >> 14) & 0x00000003; switch (fpa11->fType[Fn]) @@ -84,16 +89,18 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) case typeSingle: case typeDouble: { - p[0] = tget32(addr + 8); /* Single */ - p[1] = tget32(addr + 4); /* double msw */ + /* FIXME - handle failure of get_user() */ + get_user_u32(p[0], addr + 8); /* Single */ + get_user_u32(p[1], addr + 4); /* double msw */ p[2] = 0; /* empty */ } break; case typeExtended: { - p[1] = tget32(addr + 8); - p[2] = tget32(addr + 4); /* msw */ + /* FIXME - handle failure of get_user() */ + get_user_u32(p[1], addr + 8); + get_user_u32(p[2], addr + 4); /* msw */ p[0] = (x & 0x80003fff); } break; @@ -121,7 +128,8 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fSingle; } - tput32(addr, p[0]); + /* FIXME - handle put_user() failures */ + put_user_u32(p[0], addr); } static inline @@ -144,12 +152,13 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fDouble; } + /* FIXME - handle put_user() failures */ #ifdef WORDS_BIGENDIAN - tput32(addr, p[0]); /* msw */ - tput32(addr + 4, p[1]); /* lsw */ + put_user_u32(p[0], addr); /* msw */ + put_user_u32(p[1], addr + 4); /* lsw */ #else - tput32(addr, p[1]); /* msw */ - tput32(addr + 4, p[0]); /* lsw */ + put_user_u32(p[1], addr); /* msw */ + put_user_u32(p[0], addr + 4); /* lsw */ #endif } @@ -174,9 +183,10 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem) default: val = fpa11->fpreg[Fn].fExtended; } - tput32(addr, p[0]); /* sign & exp */ - tput32(addr + 8, p[1]); - tput32(addr + 4, p[2]); /* msw */ + /* FIXME - handle put_user() failures */ + put_user_u32(p[0], addr); /* sign & exp */ + put_user_u32(p[1], addr + 8); + put_user_u32(p[2], addr + 4); /* msw */ } static inline @@ -194,17 +204,17 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem) case typeSingle: case typeDouble: { - tput32(addr + 8, p[0]); /* single */ - tput32(addr + 4, p[1]); /* double msw */ - tput32(addr, nType << 14); + put_user_u32(p[0], addr + 8); /* single */ + put_user_u32(p[1], addr + 4); /* double msw */ + put_user_u32(nType << 14, addr); } break; case typeExtended: { - tput32(addr + 4, p[2]); /* msw */ - tput32(addr + 8, p[1]); - tput32(addr, (p[0] & 0x80003fff) | (nType << 14)); + put_user_u32(p[2], addr + 4); /* msw */ + put_user_u32(p[1], addr + 8); + put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr); } break; } -- cgit v1.2.3 From 7863667f35531557f10e7f920e4361f621a14e3f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 16 Nov 2007 14:11:28 +0000 Subject: Always make PowerPC hypervisor mode memory accesses and instructions available for full system emulation, then removing all #if TARGET_PPC64H from micro-ops and code translator. Add new macros to dramatically simplify memory access tables definitions in target-ppc/translate.c. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3654 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 8 - target-ppc/op.c | 4 - target-ppc/op_helper.c | 5 +- target-ppc/op_helper.h | 2 - target-ppc/translate.c | 1268 ++++++++++-------------------------------------- translate-all.c | 3 +- 6 files changed, 256 insertions(+), 1034 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index bb50c1df6..d40bb4070 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -305,10 +305,8 @@ struct ppc_spr_t { #if !defined(CONFIG_USER_ONLY) void (*oea_read)(void *opaque, int spr_num); void (*oea_write)(void *opaque, int spr_num); -#if defined(TARGET_PPC64H) void (*hea_read)(void *opaque, int spr_num); void (*hea_write)(void *opaque, int spr_num); -#endif #endif const unsigned char *name; }; @@ -510,11 +508,7 @@ enum { /*****************************************************************************/ /* The whole PowerPC CPU context */ -#if defined(TARGET_PPC64H) #define NB_MMU_MODES 3 -#else -#define NB_MMU_MODES 2 -#endif struct CPUPPCState { /* First are the most commonly used resources @@ -783,9 +777,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _user #define MMU_MODE1_SUFFIX _kernel -#if defined(TARGET_PPC64H) #define MMU_MODE2_SUFFIX _hypv -#endif #define MMU_USER_IDX 0 static inline int cpu_mmu_index (CPUState *env) { diff --git a/target-ppc/op.c b/target-ppc/op.c index 9bf16f5b3..c950579a1 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1987,12 +1987,10 @@ void OPPROTO op_fneg (void) #define MEMSUFFIX _kernel #include "op_helper.h" #include "op_mem.h" -#if defined(TARGET_PPC64H) #define MEMSUFFIX _hypv #include "op_helper.h" #include "op_mem.h" #endif -#endif /* Special op to check and maybe clear reservation */ void OPPROTO op_check_reservation (void) @@ -2031,9 +2029,7 @@ void OPPROTO op_rfid (void) do_rfid(); RETURN(); } -#endif -#if defined(TARGET_PPC64H) void OPPROTO op_hrfid (void) { do_hrfid(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 1dde1a18c..50c3d72d0 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -33,12 +33,10 @@ #define MEMSUFFIX _kernel #include "op_helper.h" #include "op_helper_mem.h" -#if defined(TARGET_PPC64H) #define MEMSUFFIX _hypv #include "op_helper.h" #include "op_helper_mem.h" #endif -#endif //#define DEBUG_OP //#define DEBUG_EXCEPTIONS @@ -1475,8 +1473,7 @@ void do_rfid (void) __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1], ~((target_ulong)0xFFFF0000), 0); } -#endif -#if defined(TARGET_PPC64H) + void do_hrfid (void) { __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 657825fa2..94cf4673f 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -146,8 +146,6 @@ void do_store_msr (void); void do_rfi (void); #if defined(TARGET_PPC64) void do_rfid (void); -#endif -#if defined(TARGET_PPC64H) void do_hrfid (void); #endif void do_load_6xx_tlb (int is_code); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 67b7613ab..072eb914b 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1250,14 +1250,12 @@ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) gen_op_store_pri(6); } break; -#if defined(TARGET_PPC64H) case 7: if (ctx->supervisor > 1) { /* Set process priority to very high */ gen_op_store_pri(7); } break; -#endif #endif default: /* nop */ @@ -2103,136 +2101,64 @@ static always_inline void gen_addr_register (DisasContext *ctx) #endif } -/*** Integer load ***/ -#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() +#if defined(TARGET_PPC64) +#define _GEN_MEM_FUNCS(name, mode) \ + &gen_op_##name##_##mode, \ + &gen_op_##name##_le_##mode, \ + &gen_op_##name##_64_##mode, \ + &gen_op_##name##_le_64_##mode +#else +#define _GEN_MEM_FUNCS(name, mode) \ + &gen_op_##name##_##mode, \ + &gen_op_##name##_le_##mode +#endif #if defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) -/* User mode only - 64 bits */ -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_raw, \ - &gen_op_l##width##_le_raw, \ - &gen_op_l##width##_64_raw, \ - &gen_op_l##width##_le_64_raw, \ -}; -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_st##width[] = { \ - &gen_op_st##width##_raw, \ - &gen_op_st##width##_le_raw, \ - &gen_op_st##width##_64_raw, \ - &gen_op_st##width##_le_64_raw, \ -}; -/* Byte access routine are endian safe */ -#define gen_op_stb_le_64_raw gen_op_stb_64_raw -#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw +#define NB_MEM_FUNCS 4 #else -/* User mode only - 32 bits */ -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_raw, \ - &gen_op_l##width##_le_raw, \ -}; -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_st##width[] = { \ - &gen_op_st##width##_raw, \ - &gen_op_st##width##_le_raw, \ -}; +#define NB_MEM_FUNCS 2 #endif -/* Byte access routine are endian safe */ -#define gen_op_stb_le_raw gen_op_stb_raw -#define gen_op_lbz_le_raw gen_op_lbz_raw +#define GEN_MEM_FUNCS(name) \ + _GEN_MEM_FUNCS(name, raw) #else #if defined(TARGET_PPC64) -#if defined(TARGET_PPC64H) -/* Full system - 64 bits with hypervisor mode */ -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_user, \ - &gen_op_l##width##_le_user, \ - &gen_op_l##width##_64_user, \ - &gen_op_l##width##_le_64_user, \ - &gen_op_l##width##_kernel, \ - &gen_op_l##width##_le_kernel, \ - &gen_op_l##width##_64_kernel, \ - &gen_op_l##width##_le_64_kernel, \ - &gen_op_l##width##_hypv, \ - &gen_op_l##width##_le_hypv, \ - &gen_op_l##width##_64_hypv, \ - &gen_op_l##width##_le_64_hypv, \ -}; -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_st##width[] = { \ - &gen_op_st##width##_user, \ - &gen_op_st##width##_le_user, \ - &gen_op_st##width##_64_user, \ - &gen_op_st##width##_le_64_user, \ - &gen_op_st##width##_kernel, \ - &gen_op_st##width##_le_kernel, \ - &gen_op_st##width##_64_kernel, \ - &gen_op_st##width##_le_64_kernel, \ - &gen_op_st##width##_hypv, \ - &gen_op_st##width##_le_hypv, \ - &gen_op_st##width##_64_hypv, \ - &gen_op_st##width##_le_64_hypv, \ -}; -/* Byte access routine are endian safe */ -#define gen_op_stb_le_hypv gen_op_stb_64_hypv -#define gen_op_lbz_le_hypv gen_op_lbz_64_hypv -#define gen_op_stb_le_64_hypv gen_op_stb_64_hypv -#define gen_op_lbz_le_64_hypv gen_op_lbz_64_hypv +#define NB_MEM_FUNCS 12 #else -/* Full system - 64 bits */ -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_user, \ - &gen_op_l##width##_le_user, \ - &gen_op_l##width##_64_user, \ - &gen_op_l##width##_le_64_user, \ - &gen_op_l##width##_kernel, \ - &gen_op_l##width##_le_kernel, \ - &gen_op_l##width##_64_kernel, \ - &gen_op_l##width##_le_64_kernel, \ -}; -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_st##width[] = { \ - &gen_op_st##width##_user, \ - &gen_op_st##width##_le_user, \ - &gen_op_st##width##_64_user, \ - &gen_op_st##width##_le_64_user, \ - &gen_op_st##width##_kernel, \ - &gen_op_st##width##_le_kernel, \ - &gen_op_st##width##_64_kernel, \ - &gen_op_st##width##_le_64_kernel, \ -}; +#define NB_MEM_FUNCS 6 #endif +#define GEN_MEM_FUNCS(name) \ + _GEN_MEM_FUNCS(name, user), \ + _GEN_MEM_FUNCS(name, kernel), \ + _GEN_MEM_FUNCS(name, hypv) +#endif + +/*** Integer load ***/ +#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() /* Byte access routine are endian safe */ -#define gen_op_stb_le_64_user gen_op_stb_64_user +#define gen_op_lbz_le_raw gen_op_lbz_raw +#define gen_op_lbz_le_user gen_op_lbz_user +#define gen_op_lbz_le_kernel gen_op_lbz_kernel +#define gen_op_lbz_le_hypv gen_op_lbz_hypv +#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw #define gen_op_lbz_le_64_user gen_op_lbz_64_user -#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel #define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel -#else -/* Full system - 32 bits */ +#define gen_op_lbz_le_64_hypv gen_op_lbz_64_hypv +#define gen_op_stb_le_raw gen_op_stb_raw +#define gen_op_stb_le_user gen_op_stb_user +#define gen_op_stb_le_kernel gen_op_stb_kernel +#define gen_op_stb_le_hypv gen_op_stb_hypv +#define gen_op_stb_le_64_raw gen_op_stb_64_raw +#define gen_op_stb_le_64_user gen_op_stb_64_user +#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel +#define gen_op_stb_le_64_hypv gen_op_stb_64_hypv #define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_user, \ - &gen_op_l##width##_le_user, \ - &gen_op_l##width##_kernel, \ - &gen_op_l##width##_le_kernel, \ +static GenOpFunc *gen_op_l##width[NB_MEM_FUNCS] = { \ + GEN_MEM_FUNCS(l##width), \ }; #define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_st##width[] = { \ - &gen_op_st##width##_user, \ - &gen_op_st##width##_le_user, \ - &gen_op_st##width##_kernel, \ - &gen_op_st##width##_le_kernel, \ +static GenOpFunc *gen_op_st##width[NB_MEM_FUNCS] = { \ + GEN_MEM_FUNCS(st##width), \ }; -#endif -/* Byte access routine are endian safe */ -#define gen_op_stb_le_user gen_op_stb_user -#define gen_op_lbz_le_user gen_op_lbz_user -#define gen_op_stb_le_kernel gen_op_stb_kernel -#define gen_op_lbz_le_kernel gen_op_lbz_kernel -#endif #define GEN_LD(width, opc, type) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \ @@ -2487,75 +2413,12 @@ GEN_STX(wbr, 0x16, 0x14, PPC_INTEGER); /*** Integer load and store multiple ***/ #define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg) -#if defined(CONFIG_USER_ONLY) -/* User-mode only */ -static GenOpFunc1 *gen_op_lmw[] = { - &gen_op_lmw_raw, - &gen_op_lmw_le_raw, -#if defined(TARGET_PPC64) - &gen_op_lmw_64_raw, - &gen_op_lmw_le_64_raw, -#endif +static GenOpFunc1 *gen_op_lmw[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(lmw), }; -static GenOpFunc1 *gen_op_stmw[] = { - &gen_op_stmw_raw, - &gen_op_stmw_le_raw, -#if defined(TARGET_PPC64) - &gen_op_stmw_64_raw, - &gen_op_stmw_le_64_raw, -#endif +static GenOpFunc1 *gen_op_stmw[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(stmw), }; -#else -#if defined(TARGET_PPC64) -/* Full system - 64 bits mode */ -static GenOpFunc1 *gen_op_lmw[] = { - &gen_op_lmw_user, - &gen_op_lmw_le_user, - &gen_op_lmw_64_user, - &gen_op_lmw_le_64_user, - &gen_op_lmw_kernel, - &gen_op_lmw_le_kernel, - &gen_op_lmw_64_kernel, - &gen_op_lmw_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_lmw_hypv, - &gen_op_lmw_le_hypv, - &gen_op_lmw_64_hypv, - &gen_op_lmw_le_64_hypv, -#endif -}; -static GenOpFunc1 *gen_op_stmw[] = { - &gen_op_stmw_user, - &gen_op_stmw_le_user, - &gen_op_stmw_64_user, - &gen_op_stmw_le_64_user, - &gen_op_stmw_kernel, - &gen_op_stmw_le_kernel, - &gen_op_stmw_64_kernel, - &gen_op_stmw_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_stmw_hypv, - &gen_op_stmw_le_hypv, - &gen_op_stmw_64_hypv, - &gen_op_stmw_le_64_hypv, -#endif -}; -#else -/* Full system - 32 bits mode */ -static GenOpFunc1 *gen_op_lmw[] = { - &gen_op_lmw_user, - &gen_op_lmw_le_user, - &gen_op_lmw_kernel, - &gen_op_lmw_le_kernel, -}; -static GenOpFunc1 *gen_op_stmw[] = { - &gen_op_stmw_user, - &gen_op_stmw_le_user, - &gen_op_stmw_kernel, - &gen_op_stmw_le_kernel, -}; -#endif -#endif /* lmw */ GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -2578,105 +2441,15 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) /*** Integer load and store strings ***/ #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start) #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb) -#if defined(CONFIG_USER_ONLY) -/* User-mode only */ -static GenOpFunc1 *gen_op_lswi[] = { - &gen_op_lswi_raw, - &gen_op_lswi_le_raw, -#if defined(TARGET_PPC64) - &gen_op_lswi_64_raw, - &gen_op_lswi_le_64_raw, -#endif -}; -static GenOpFunc3 *gen_op_lswx[] = { - &gen_op_lswx_raw, - &gen_op_lswx_le_raw, -#if defined(TARGET_PPC64) - &gen_op_lswx_64_raw, - &gen_op_lswx_le_64_raw, -#endif +static GenOpFunc1 *gen_op_lswi[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(lswi), }; -static GenOpFunc1 *gen_op_stsw[] = { - &gen_op_stsw_raw, - &gen_op_stsw_le_raw, -#if defined(TARGET_PPC64) - &gen_op_stsw_64_raw, - &gen_op_stsw_le_64_raw, -#endif -}; -#else -#if defined(TARGET_PPC64) -/* Full system - 64 bits mode */ -static GenOpFunc1 *gen_op_lswi[] = { - &gen_op_lswi_user, - &gen_op_lswi_le_user, - &gen_op_lswi_64_user, - &gen_op_lswi_le_64_user, - &gen_op_lswi_kernel, - &gen_op_lswi_le_kernel, - &gen_op_lswi_64_kernel, - &gen_op_lswi_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_lswi_hypv, - &gen_op_lswi_le_hypv, - &gen_op_lswi_64_hypv, - &gen_op_lswi_le_64_hypv, -#endif +static GenOpFunc3 *gen_op_lswx[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(lswx), }; -static GenOpFunc3 *gen_op_lswx[] = { - &gen_op_lswx_user, - &gen_op_lswx_le_user, - &gen_op_lswx_64_user, - &gen_op_lswx_le_64_user, - &gen_op_lswx_kernel, - &gen_op_lswx_le_kernel, - &gen_op_lswx_64_kernel, - &gen_op_lswx_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_lswx_hypv, - &gen_op_lswx_le_hypv, - &gen_op_lswx_64_hypv, - &gen_op_lswx_le_64_hypv, -#endif -}; -static GenOpFunc1 *gen_op_stsw[] = { - &gen_op_stsw_user, - &gen_op_stsw_le_user, - &gen_op_stsw_64_user, - &gen_op_stsw_le_64_user, - &gen_op_stsw_kernel, - &gen_op_stsw_le_kernel, - &gen_op_stsw_64_kernel, - &gen_op_stsw_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_stsw_hypv, - &gen_op_stsw_le_hypv, - &gen_op_stsw_64_hypv, - &gen_op_stsw_le_64_hypv, -#endif -}; -#else -/* Full system - 32 bits mode */ -static GenOpFunc1 *gen_op_lswi[] = { - &gen_op_lswi_user, - &gen_op_lswi_le_user, - &gen_op_lswi_kernel, - &gen_op_lswi_le_kernel, +static GenOpFunc1 *gen_op_stsw[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(stsw), }; -static GenOpFunc3 *gen_op_lswx[] = { - &gen_op_lswx_user, - &gen_op_lswx_le_user, - &gen_op_lswx_kernel, - &gen_op_lswx_le_kernel, -}; -static GenOpFunc1 *gen_op_stsw[] = { - &gen_op_stsw_user, - &gen_op_stsw_le_user, - &gen_op_stsw_kernel, - &gen_op_stsw_le_kernel, -}; -#endif -#endif /* lswi */ /* PowerPC32 specification says we must generate an exception if @@ -2762,75 +2535,12 @@ GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM) #define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])() #define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])() -#if defined(CONFIG_USER_ONLY) -/* User-mode only */ -static GenOpFunc *gen_op_lwarx[] = { - &gen_op_lwarx_raw, - &gen_op_lwarx_le_raw, -#if defined(TARGET_PPC64) - &gen_op_lwarx_64_raw, - &gen_op_lwarx_le_64_raw, -#endif -}; -static GenOpFunc *gen_op_stwcx[] = { - &gen_op_stwcx_raw, - &gen_op_stwcx_le_raw, -#if defined(TARGET_PPC64) - &gen_op_stwcx_64_raw, - &gen_op_stwcx_le_64_raw, -#endif +static GenOpFunc *gen_op_lwarx[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(lwarx), }; -#else -#if defined(TARGET_PPC64) -/* Full system - 64 bits mode */ -static GenOpFunc *gen_op_lwarx[] = { - &gen_op_lwarx_user, - &gen_op_lwarx_le_user, - &gen_op_lwarx_64_user, - &gen_op_lwarx_le_64_user, - &gen_op_lwarx_kernel, - &gen_op_lwarx_le_kernel, - &gen_op_lwarx_64_kernel, - &gen_op_lwarx_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_lwarx_hypv, - &gen_op_lwarx_le_hypv, - &gen_op_lwarx_64_hypv, - &gen_op_lwarx_le_64_hypv, -#endif +static GenOpFunc *gen_op_stwcx[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(stwcx), }; -static GenOpFunc *gen_op_stwcx[] = { - &gen_op_stwcx_user, - &gen_op_stwcx_le_user, - &gen_op_stwcx_64_user, - &gen_op_stwcx_le_64_user, - &gen_op_stwcx_kernel, - &gen_op_stwcx_le_kernel, - &gen_op_stwcx_64_kernel, - &gen_op_stwcx_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_stwcx_hypv, - &gen_op_stwcx_le_hypv, - &gen_op_stwcx_64_hypv, - &gen_op_stwcx_le_64_hypv, -#endif -}; -#else -/* Full system - 32 bits mode */ -static GenOpFunc *gen_op_lwarx[] = { - &gen_op_lwarx_user, - &gen_op_lwarx_le_user, - &gen_op_lwarx_kernel, - &gen_op_lwarx_le_kernel, -}; -static GenOpFunc *gen_op_stwcx[] = { - &gen_op_stwcx_user, - &gen_op_stwcx_le_user, - &gen_op_stwcx_kernel, - &gen_op_stwcx_le_kernel, -}; -#endif -#endif /* lwarx */ GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES) @@ -2855,55 +2565,12 @@ GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) #if defined(TARGET_PPC64) #define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])() #define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])() -#if defined(CONFIG_USER_ONLY) -/* User-mode only */ -static GenOpFunc *gen_op_ldarx[] = { - &gen_op_ldarx_raw, - &gen_op_ldarx_le_raw, - &gen_op_ldarx_64_raw, - &gen_op_ldarx_le_64_raw, +static GenOpFunc *gen_op_ldarx[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(ldarx), }; -static GenOpFunc *gen_op_stdcx[] = { - &gen_op_stdcx_raw, - &gen_op_stdcx_le_raw, - &gen_op_stdcx_64_raw, - &gen_op_stdcx_le_64_raw, +static GenOpFunc *gen_op_stdcx[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(stdcx), }; -#else -/* Full system */ -static GenOpFunc *gen_op_ldarx[] = { - &gen_op_ldarx_user, - &gen_op_ldarx_le_user, - &gen_op_ldarx_64_user, - &gen_op_ldarx_le_64_user, - &gen_op_ldarx_kernel, - &gen_op_ldarx_le_kernel, - &gen_op_ldarx_64_kernel, - &gen_op_ldarx_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_ldarx_hypv, - &gen_op_ldarx_le_hypv, - &gen_op_ldarx_64_hypv, - &gen_op_ldarx_le_64_hypv, -#endif -}; -static GenOpFunc *gen_op_stdcx[] = { - &gen_op_stdcx_user, - &gen_op_stdcx_le_user, - &gen_op_stdcx_64_user, - &gen_op_stdcx_le_64_user, - &gen_op_stdcx_kernel, - &gen_op_stdcx_le_kernel, - &gen_op_stdcx_64_kernel, - &gen_op_stdcx_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_stdcx_hypv, - &gen_op_stdcx_le_hypv, - &gen_op_stdcx_64_hypv, - &gen_op_stdcx_le_64_hypv, -#endif -}; -#endif /* ldarx */ GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B) @@ -3406,9 +3073,7 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B) GEN_SYNC(ctx); #endif } -#endif -#if defined(TARGET_PPC64H) GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64B) { #if defined(CONFIG_USER_ONLY) @@ -3542,12 +3207,9 @@ static always_inline void gen_op_mfspr (DisasContext *ctx) uint32_t sprn = SPR(ctx->opcode); #if !defined(CONFIG_USER_ONLY) -#if defined(TARGET_PPC64H) if (ctx->supervisor == 2) read_cb = ctx->spr_cb[sprn].hea_read; - else -#endif - if (ctx->supervisor) + else if (ctx->supervisor) read_cb = ctx->spr_cb[sprn].oea_read; else #endif @@ -3682,12 +3344,9 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) uint32_t sprn = SPR(ctx->opcode); #if !defined(CONFIG_USER_ONLY) -#if defined(TARGET_PPC64H) if (ctx->supervisor == 2) write_cb = ctx->spr_cb[sprn].hea_write; - else -#endif - if (ctx->supervisor) + else if (ctx->supervisor) write_cb = ctx->spr_cb[sprn].oea_write; else #endif @@ -3773,141 +3432,56 @@ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE) /* dcbz */ #define op_dcbz(n) (*gen_op_dcbz[n][ctx->mem_idx])() -#if defined(CONFIG_USER_ONLY) -/* User-mode only */ -static GenOpFunc *gen_op_dcbz[4][4] = { - { - &gen_op_dcbz_l32_raw, - &gen_op_dcbz_l32_raw, -#if defined(TARGET_PPC64) - &gen_op_dcbz_l32_64_raw, - &gen_op_dcbz_l32_64_raw, -#endif - }, - { - &gen_op_dcbz_l64_raw, - &gen_op_dcbz_l64_raw, -#if defined(TARGET_PPC64) - &gen_op_dcbz_l64_64_raw, - &gen_op_dcbz_l64_64_raw, -#endif - }, - { - &gen_op_dcbz_l128_raw, - &gen_op_dcbz_l128_raw, -#if defined(TARGET_PPC64) - &gen_op_dcbz_l128_64_raw, - &gen_op_dcbz_l128_64_raw, -#endif - }, - { - &gen_op_dcbz_raw, - &gen_op_dcbz_raw, -#if defined(TARGET_PPC64) - &gen_op_dcbz_64_raw, - &gen_op_dcbz_64_raw, -#endif - }, -}; -#else -#if defined(TARGET_PPC64) -/* Full system - 64 bits mode */ -static GenOpFunc *gen_op_dcbz[4][12] = { +static GenOpFunc *gen_op_dcbz[4][NB_MEM_FUNCS] = { + /* 32 bytes cache line size */ { - &gen_op_dcbz_l32_user, - &gen_op_dcbz_l32_user, - &gen_op_dcbz_l32_64_user, - &gen_op_dcbz_l32_64_user, - &gen_op_dcbz_l32_kernel, - &gen_op_dcbz_l32_kernel, - &gen_op_dcbz_l32_64_kernel, - &gen_op_dcbz_l32_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_dcbz_l32_hypv, - &gen_op_dcbz_l32_hypv, - &gen_op_dcbz_l32_64_hypv, - &gen_op_dcbz_l32_64_hypv, -#endif +#define gen_op_dcbz_l32_le_raw gen_op_dcbz_l32_raw +#define gen_op_dcbz_l32_le_user gen_op_dcbz_l32_user +#define gen_op_dcbz_l32_le_kernel gen_op_dcbz_l32_kernel +#define gen_op_dcbz_l32_le_hypv gen_op_dcbz_l32_hypv +#define gen_op_dcbz_l32_le_64_raw gen_op_dcbz_l32_64_raw +#define gen_op_dcbz_l32_le_64_user gen_op_dcbz_l32_64_user +#define gen_op_dcbz_l32_le_64_kernel gen_op_dcbz_l32_64_kernel +#define gen_op_dcbz_l32_le_64_hypv gen_op_dcbz_l32_64_hypv + GEN_MEM_FUNCS(dcbz_l32), }, + /* 64 bytes cache line size */ { - &gen_op_dcbz_l64_user, - &gen_op_dcbz_l64_user, - &gen_op_dcbz_l64_64_user, - &gen_op_dcbz_l64_64_user, - &gen_op_dcbz_l64_kernel, - &gen_op_dcbz_l64_kernel, - &gen_op_dcbz_l64_64_kernel, - &gen_op_dcbz_l64_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_dcbz_l64_hypv, - &gen_op_dcbz_l64_hypv, - &gen_op_dcbz_l64_64_hypv, - &gen_op_dcbz_l64_64_hypv, -#endif +#define gen_op_dcbz_l64_le_raw gen_op_dcbz_l64_raw +#define gen_op_dcbz_l64_le_user gen_op_dcbz_l64_user +#define gen_op_dcbz_l64_le_kernel gen_op_dcbz_l64_kernel +#define gen_op_dcbz_l64_le_hypv gen_op_dcbz_l64_hypv +#define gen_op_dcbz_l64_le_64_raw gen_op_dcbz_l64_64_raw +#define gen_op_dcbz_l64_le_64_user gen_op_dcbz_l64_64_user +#define gen_op_dcbz_l64_le_64_kernel gen_op_dcbz_l64_64_kernel +#define gen_op_dcbz_l64_le_64_hypv gen_op_dcbz_l64_64_hypv + GEN_MEM_FUNCS(dcbz_l64), }, + /* 128 bytes cache line size */ { - &gen_op_dcbz_l128_user, - &gen_op_dcbz_l128_user, - &gen_op_dcbz_l128_64_user, - &gen_op_dcbz_l128_64_user, - &gen_op_dcbz_l128_kernel, - &gen_op_dcbz_l128_kernel, - &gen_op_dcbz_l128_64_kernel, - &gen_op_dcbz_l128_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_dcbz_l128_hypv, - &gen_op_dcbz_l128_hypv, - &gen_op_dcbz_l128_64_hypv, - &gen_op_dcbz_l128_64_hypv, -#endif +#define gen_op_dcbz_l128_le_raw gen_op_dcbz_l128_raw +#define gen_op_dcbz_l128_le_user gen_op_dcbz_l128_user +#define gen_op_dcbz_l128_le_kernel gen_op_dcbz_l128_kernel +#define gen_op_dcbz_l128_le_hypv gen_op_dcbz_l128_hypv +#define gen_op_dcbz_l128_le_64_raw gen_op_dcbz_l128_64_raw +#define gen_op_dcbz_l128_le_64_user gen_op_dcbz_l128_64_user +#define gen_op_dcbz_l128_le_64_kernel gen_op_dcbz_l128_64_kernel +#define gen_op_dcbz_l128_le_64_hypv gen_op_dcbz_l128_64_hypv + GEN_MEM_FUNCS(dcbz_l128), }, + /* tunable cache line size */ { - &gen_op_dcbz_user, - &gen_op_dcbz_user, - &gen_op_dcbz_64_user, - &gen_op_dcbz_64_user, - &gen_op_dcbz_kernel, - &gen_op_dcbz_kernel, - &gen_op_dcbz_64_kernel, - &gen_op_dcbz_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_dcbz_hypv, - &gen_op_dcbz_hypv, - &gen_op_dcbz_64_hypv, - &gen_op_dcbz_64_hypv, -#endif +#define gen_op_dcbz_le_raw gen_op_dcbz_raw +#define gen_op_dcbz_le_user gen_op_dcbz_user +#define gen_op_dcbz_le_kernel gen_op_dcbz_kernel +#define gen_op_dcbz_le_hypv gen_op_dcbz_hypv +#define gen_op_dcbz_le_64_raw gen_op_dcbz_64_raw +#define gen_op_dcbz_le_64_user gen_op_dcbz_64_user +#define gen_op_dcbz_le_64_kernel gen_op_dcbz_64_kernel +#define gen_op_dcbz_le_64_hypv gen_op_dcbz_64_hypv + GEN_MEM_FUNCS(dcbz), }, }; -#else -/* Full system - 32 bits mode */ -static GenOpFunc *gen_op_dcbz[4][4] = { - { - &gen_op_dcbz_l32_user, - &gen_op_dcbz_l32_user, - &gen_op_dcbz_l32_kernel, - &gen_op_dcbz_l32_kernel, - }, - { - &gen_op_dcbz_l64_user, - &gen_op_dcbz_l64_user, - &gen_op_dcbz_l64_kernel, - &gen_op_dcbz_l64_kernel, - }, - { - &gen_op_dcbz_l128_user, - &gen_op_dcbz_l128_user, - &gen_op_dcbz_l128_kernel, - &gen_op_dcbz_l128_kernel, - }, - { - &gen_op_dcbz_user, - &gen_op_dcbz_user, - &gen_op_dcbz_kernel, - &gen_op_dcbz_kernel, - }, -}; -#endif -#endif static always_inline void handler_dcbz (DisasContext *ctx, int dcache_line_size) @@ -3950,45 +3524,17 @@ GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT) /* icbi */ #define op_icbi() (*gen_op_icbi[ctx->mem_idx])() -#if defined(CONFIG_USER_ONLY) -/* User-mode only */ -static GenOpFunc *gen_op_icbi[] = { - &gen_op_icbi_raw, - &gen_op_icbi_raw, -#if defined(TARGET_PPC64) - &gen_op_icbi_64_raw, - &gen_op_icbi_64_raw, -#endif -}; -#else -/* Full system - 64 bits mode */ -#if defined(TARGET_PPC64) -static GenOpFunc *gen_op_icbi[] = { - &gen_op_icbi_user, - &gen_op_icbi_user, - &gen_op_icbi_64_user, - &gen_op_icbi_64_user, - &gen_op_icbi_kernel, - &gen_op_icbi_kernel, - &gen_op_icbi_64_kernel, - &gen_op_icbi_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_icbi_hypv, - &gen_op_icbi_hypv, - &gen_op_icbi_64_hypv, - &gen_op_icbi_64_hypv, -#endif -}; -#else -/* Full system - 32 bits mode */ -static GenOpFunc *gen_op_icbi[] = { - &gen_op_icbi_user, - &gen_op_icbi_user, - &gen_op_icbi_kernel, - &gen_op_icbi_kernel, +#define gen_op_icbi_le_raw gen_op_icbi_raw +#define gen_op_icbi_le_user gen_op_icbi_user +#define gen_op_icbi_le_kernel gen_op_icbi_kernel +#define gen_op_icbi_le_hypv gen_op_icbi_hypv +#define gen_op_icbi_le_64_raw gen_op_icbi_64_raw +#define gen_op_icbi_le_64_user gen_op_icbi_64_user +#define gen_op_icbi_le_64_kernel gen_op_icbi_64_kernel +#define gen_op_icbi_le_64_hypv gen_op_icbi_64_hypv +static GenOpFunc *gen_op_icbi[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(icbi), }; -#endif -#endif GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI) { @@ -4239,75 +3785,12 @@ GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI) /* Optional: */ #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])() #define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])() -#if defined(CONFIG_USER_ONLY) -/* User-mode only */ -static GenOpFunc *gen_op_eciwx[] = { - &gen_op_eciwx_raw, - &gen_op_eciwx_le_raw, -#if defined(TARGET_PPC64) - &gen_op_eciwx_64_raw, - &gen_op_eciwx_le_64_raw, -#endif +static GenOpFunc *gen_op_eciwx[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(eciwx), }; -static GenOpFunc *gen_op_ecowx[] = { - &gen_op_ecowx_raw, - &gen_op_ecowx_le_raw, -#if defined(TARGET_PPC64) - &gen_op_ecowx_64_raw, - &gen_op_ecowx_le_64_raw, -#endif +static GenOpFunc *gen_op_ecowx[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(ecowx), }; -#else -#if defined(TARGET_PPC64) -/* Full system - 64 bits mode */ -static GenOpFunc *gen_op_eciwx[] = { - &gen_op_eciwx_user, - &gen_op_eciwx_le_user, - &gen_op_eciwx_64_user, - &gen_op_eciwx_le_64_user, - &gen_op_eciwx_kernel, - &gen_op_eciwx_le_kernel, - &gen_op_eciwx_64_kernel, - &gen_op_eciwx_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_eciwx_hypv, - &gen_op_eciwx_le_hypv, - &gen_op_eciwx_64_hypv, - &gen_op_eciwx_le_64_hypv, -#endif -}; -static GenOpFunc *gen_op_ecowx[] = { - &gen_op_ecowx_user, - &gen_op_ecowx_le_user, - &gen_op_ecowx_64_user, - &gen_op_ecowx_le_64_user, - &gen_op_ecowx_kernel, - &gen_op_ecowx_le_kernel, - &gen_op_ecowx_64_kernel, - &gen_op_ecowx_le_64_kernel, -#if defined(TARGET_PPC64H) - &gen_op_ecowx_hypv, - &gen_op_ecowx_le_hypv, - &gen_op_ecowx_64_hypv, - &gen_op_ecowx_le_64_hypv, -#endif -}; -#else -/* Full system - 32 bits mode */ -static GenOpFunc *gen_op_eciwx[] = { - &gen_op_eciwx_user, - &gen_op_eciwx_le_user, - &gen_op_eciwx_kernel, - &gen_op_eciwx_le_kernel, -}; -static GenOpFunc *gen_op_ecowx[] = { - &gen_op_ecowx_user, - &gen_op_ecowx_le_user, - &gen_op_ecowx_kernel, - &gen_op_ecowx_le_kernel, -}; -#endif -#endif /* eciwx */ GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN) @@ -4432,22 +3915,26 @@ GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR) gen_op_store_T0_gpr(rD(ctx->opcode)); } -/* As lscbx load from memory byte after byte, it's always endian safe */ +/* As lscbx load from memory byte after byte, it's always endian safe. + * Original POWER is 32 bits only, define 64 bits ops as 32 bits ones + */ #define op_POWER_lscbx(start, ra, rb) \ (*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb) -#if defined(CONFIG_USER_ONLY) -static GenOpFunc3 *gen_op_POWER_lscbx[] = { - &gen_op_POWER_lscbx_raw, - &gen_op_POWER_lscbx_raw, +#define gen_op_POWER_lscbx_64_raw gen_op_POWER_lscbx_raw +#define gen_op_POWER_lscbx_64_user gen_op_POWER_lscbx_user +#define gen_op_POWER_lscbx_64_kernel gen_op_POWER_lscbx_kernel +#define gen_op_POWER_lscbx_64_hypv gen_op_POWER_lscbx_hypv +#define gen_op_POWER_lscbx_le_raw gen_op_POWER_lscbx_raw +#define gen_op_POWER_lscbx_le_user gen_op_POWER_lscbx_user +#define gen_op_POWER_lscbx_le_kernel gen_op_POWER_lscbx_kernel +#define gen_op_POWER_lscbx_le_hypv gen_op_POWER_lscbx_hypv +#define gen_op_POWER_lscbx_le_64_raw gen_op_POWER_lscbx_raw +#define gen_op_POWER_lscbx_le_64_user gen_op_POWER_lscbx_user +#define gen_op_POWER_lscbx_le_64_kernel gen_op_POWER_lscbx_kernel +#define gen_op_POWER_lscbx_le_64_hypv gen_op_POWER_lscbx_hypv +static GenOpFunc3 *gen_op_POWER_lscbx[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(POWER_lscbx), }; -#else -static GenOpFunc3 *gen_op_POWER_lscbx[] = { - &gen_op_POWER_lscbx_user, - &gen_op_POWER_lscbx_user, - &gen_op_POWER_lscbx_kernel, - &gen_op_POWER_lscbx_kernel, -}; -#endif /* lscbx - lscbx. */ GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR) @@ -4901,31 +4388,31 @@ GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER) /* POWER2 specific instructions */ /* Quad manipulation (load/store two floats at a time) */ +/* Original POWER2 is 32 bits only, define 64 bits ops as 32 bits ones */ #define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])() #define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])() -#if defined(CONFIG_USER_ONLY) -static GenOpFunc *gen_op_POWER2_lfq[] = { - &gen_op_POWER2_lfq_le_raw, - &gen_op_POWER2_lfq_raw, -}; -static GenOpFunc *gen_op_POWER2_stfq[] = { - &gen_op_POWER2_stfq_le_raw, - &gen_op_POWER2_stfq_raw, +#define gen_op_POWER2_lfq_64_raw gen_op_POWER2_lfq_raw +#define gen_op_POWER2_lfq_64_user gen_op_POWER2_lfq_user +#define gen_op_POWER2_lfq_64_kernel gen_op_POWER2_lfq_kernel +#define gen_op_POWER2_lfq_64_hypv gen_op_POWER2_lfq_hypv +#define gen_op_POWER2_lfq_le_64_raw gen_op_POWER2_lfq_le_raw +#define gen_op_POWER2_lfq_le_64_user gen_op_POWER2_lfq_le_user +#define gen_op_POWER2_lfq_le_64_kernel gen_op_POWER2_lfq_le_kernel +#define gen_op_POWER2_lfq_le_64_hypv gen_op_POWER2_lfq_le_hypv +#define gen_op_POWER2_stfq_64_raw gen_op_POWER2_stfq_raw +#define gen_op_POWER2_stfq_64_user gen_op_POWER2_stfq_user +#define gen_op_POWER2_stfq_64_kernel gen_op_POWER2_stfq_kernel +#define gen_op_POWER2_stfq_64_hypv gen_op_POWER2_stfq_hypv +#define gen_op_POWER2_stfq_le_64_raw gen_op_POWER2_stfq_le_raw +#define gen_op_POWER2_stfq_le_64_user gen_op_POWER2_stfq_le_user +#define gen_op_POWER2_stfq_le_64_kernel gen_op_POWER2_stfq_le_kernel +#define gen_op_POWER2_stfq_le_64_hypv gen_op_POWER2_stfq_le_hypv +static GenOpFunc *gen_op_POWER2_lfq[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(POWER2_lfq), }; -#else -static GenOpFunc *gen_op_POWER2_lfq[] = { - &gen_op_POWER2_lfq_le_user, - &gen_op_POWER2_lfq_user, - &gen_op_POWER2_lfq_le_kernel, - &gen_op_POWER2_lfq_kernel, +static GenOpFunc *gen_op_POWER2_stfq[NB_MEM_FUNCS] = { + GEN_MEM_FUNCS(POWER2_stfq), }; -static GenOpFunc *gen_op_POWER2_stfq[] = { - &gen_op_POWER2_stfq_le_user, - &gen_op_POWER2_stfq_user, - &gen_op_POWER2_stfq_le_kernel, - &gen_op_POWER2_stfq_kernel, -}; -#endif /* lfq */ GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2) @@ -5687,111 +5174,14 @@ GEN32(gen_op_store_A2_avr, gen_op_store_A2_avr_avr); #endif #define op_vr_ldst(name) (*gen_op_##name[ctx->mem_idx])() -#if defined(CONFIG_USER_ONLY) -#if defined(TARGET_PPC64) -/* User-mode only - 64 bits mode */ -#define OP_VR_LD_TABLE(name) \ -static GenOpFunc *gen_op_vr_l##name[] = { \ - &gen_op_vr_l##name##_raw, \ - &gen_op_vr_l##name##_le_raw, \ - &gen_op_vr_l##name##_64_raw, \ - &gen_op_vr_l##name##_le_64_raw, \ -}; -#define OP_VR_ST_TABLE(name) \ -static GenOpFunc *gen_op_vr_st##name[] = { \ - &gen_op_vr_st##name##_raw, \ - &gen_op_vr_st##name##_le_raw, \ - &gen_op_vr_st##name##_64_raw, \ - &gen_op_vr_st##name##_le_64_raw, \ -}; -#else /* defined(TARGET_PPC64) */ -/* User-mode only - 32 bits mode */ -#define OP_VR_LD_TABLE(name) \ -static GenOpFunc *gen_op_vr_l##name[] = { \ - &gen_op_vr_l##name##_raw, \ - &gen_op_vr_l##name##_le_raw, \ -}; -#define OP_VR_ST_TABLE(name) \ -static GenOpFunc *gen_op_vr_st##name[] = { \ - &gen_op_vr_st##name##_raw, \ - &gen_op_vr_st##name##_le_raw, \ -}; -#endif /* defined(TARGET_PPC64) */ -#else /* defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_PPC64H) -/* Full system with hypervisor mode */ -#define OP_VR_LD_TABLE(name) \ -static GenOpFunc *gen_op_vr_l##name[] = { \ - &gen_op_vr_l##name##_user, \ - &gen_op_vr_l##name##_le_user, \ - &gen_op_vr_l##name##_64_user, \ - &gen_op_vr_l##name##_le_64_user, \ - &gen_op_vr_l##name##_kernel, \ - &gen_op_vr_l##name##_le_kernel, \ - &gen_op_vr_l##name##_64_kernel, \ - &gen_op_vr_l##name##_le_64_kernel, \ - &gen_op_vr_l##name##_hypv, \ - &gen_op_vr_l##name##_le_hypv, \ - &gen_op_vr_l##name##_64_hypv, \ - &gen_op_vr_l##name##_le_64_hypv, \ -}; -#define OP_VR_ST_TABLE(name) \ -static GenOpFunc *gen_op_vr_st##name[] = { \ - &gen_op_vr_st##name##_user, \ - &gen_op_vr_st##name##_le_user, \ - &gen_op_vr_st##name##_64_user, \ - &gen_op_vr_st##name##_le_64_user, \ - &gen_op_vr_st##name##_kernel, \ - &gen_op_vr_st##name##_le_kernel, \ - &gen_op_vr_st##name##_64_kernel, \ - &gen_op_vr_st##name##_le_64_kernel, \ - &gen_op_vr_st##name##_hypv, \ - &gen_op_vr_st##name##_le_hypv, \ - &gen_op_vr_st##name##_64_hypv, \ - &gen_op_vr_st##name##_le_64_hypv, \ -}; -#elif defined(TARGET_PPC64) -/* Full system - 64 bits mode */ #define OP_VR_LD_TABLE(name) \ -static GenOpFunc *gen_op_vr_l##name[] = { \ - &gen_op_vr_l##name##_user, \ - &gen_op_vr_l##name##_le_user, \ - &gen_op_vr_l##name##_64_user, \ - &gen_op_vr_l##name##_le_64_user, \ - &gen_op_vr_l##name##_kernel, \ - &gen_op_vr_l##name##_le_kernel, \ - &gen_op_vr_l##name##_64_kernel, \ - &gen_op_vr_l##name##_le_64_kernel, \ +static GenOpFunc *gen_op_vr_l##name[NB_MEM_FUNCS] = { \ + GEN_MEM_FUNCS(vr_l##name), \ }; #define OP_VR_ST_TABLE(name) \ -static GenOpFunc *gen_op_vr_st##name[] = { \ - &gen_op_vr_st##name##_user, \ - &gen_op_vr_st##name##_le_user, \ - &gen_op_vr_st##name##_64_user, \ - &gen_op_vr_st##name##_le_64_user, \ - &gen_op_vr_st##name##_kernel, \ - &gen_op_vr_st##name##_le_kernel, \ - &gen_op_vr_st##name##_64_kernel, \ - &gen_op_vr_st##name##_le_64_kernel, \ +static GenOpFunc *gen_op_vr_st##name[NB_MEM_FUNCS] = { \ + GEN_MEM_FUNCS(vr_st##name), \ }; -#else /* defined(TARGET_PPC64) */ -/* Full system - 32 bits mode */ -#define OP_VR_LD_TABLE(name) \ -static GenOpFunc *gen_op_vr_l##name[] = { \ - &gen_op_vr_l##name##_user, \ - &gen_op_vr_l##name##_le_user, \ - &gen_op_vr_l##name##_kernel, \ - &gen_op_vr_l##name##_le_kernel, \ -}; -#define OP_VR_ST_TABLE(name) \ -static GenOpFunc *gen_op_vr_st##name[] = { \ - &gen_op_vr_st##name##_user, \ - &gen_op_vr_st##name##_le_user, \ - &gen_op_vr_st##name##_kernel, \ - &gen_op_vr_st##name##_le_kernel, \ -}; -#endif /* defined(TARGET_PPC64) */ -#endif /* defined(CONFIG_USER_ONLY) */ #define GEN_VR_LDX(name, opc2, opc3) \ GEN_HANDLER(l##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) \ @@ -5830,7 +5220,6 @@ GEN_VR_STX(vx, 0x07, 0x07); GEN_VR_STX(vxl, 0x07, 0x0F); /*** SPE extension ***/ - /* Register moves */ #if !defined(TARGET_PPC64) @@ -5893,111 +5282,14 @@ static always_inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh) } #define op_spe_ldst(name) (*gen_op_##name[ctx->mem_idx])() -#if defined(CONFIG_USER_ONLY) -#if defined(TARGET_PPC64) -/* User-mode only - 64 bits mode */ -#define OP_SPE_LD_TABLE(name) \ -static GenOpFunc *gen_op_spe_l##name[] = { \ - &gen_op_spe_l##name##_raw, \ - &gen_op_spe_l##name##_le_raw, \ - &gen_op_spe_l##name##_64_raw, \ - &gen_op_spe_l##name##_le_64_raw, \ -}; -#define OP_SPE_ST_TABLE(name) \ -static GenOpFunc *gen_op_spe_st##name[] = { \ - &gen_op_spe_st##name##_raw, \ - &gen_op_spe_st##name##_le_raw, \ - &gen_op_spe_st##name##_64_raw, \ - &gen_op_spe_st##name##_le_64_raw, \ -}; -#else /* defined(TARGET_PPC64) */ -/* User-mode only - 32 bits mode */ -#define OP_SPE_LD_TABLE(name) \ -static GenOpFunc *gen_op_spe_l##name[] = { \ - &gen_op_spe_l##name##_raw, \ - &gen_op_spe_l##name##_le_raw, \ -}; -#define OP_SPE_ST_TABLE(name) \ -static GenOpFunc *gen_op_spe_st##name[] = { \ - &gen_op_spe_st##name##_raw, \ - &gen_op_spe_st##name##_le_raw, \ -}; -#endif /* defined(TARGET_PPC64) */ -#else /* defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_PPC64H) -/* Full system with hypervisor mode */ #define OP_SPE_LD_TABLE(name) \ -static GenOpFunc *gen_op_spe_l##name[] = { \ - &gen_op_spe_l##name##_user, \ - &gen_op_spe_l##name##_le_user, \ - &gen_op_spe_l##name##_64_user, \ - &gen_op_spe_l##name##_le_64_user, \ - &gen_op_spe_l##name##_kernel, \ - &gen_op_spe_l##name##_le_kernel, \ - &gen_op_spe_l##name##_64_kernel, \ - &gen_op_spe_l##name##_le_64_kernel, \ - &gen_op_spe_l##name##_hypv, \ - &gen_op_spe_l##name##_le_hypv, \ - &gen_op_spe_l##name##_64_hypv, \ - &gen_op_spe_l##name##_le_64_hypv, \ +static GenOpFunc *gen_op_spe_l##name[NB_MEM_FUNCS] = { \ + GEN_MEM_FUNCS(spe_l##name), \ }; #define OP_SPE_ST_TABLE(name) \ -static GenOpFunc *gen_op_spe_st##name[] = { \ - &gen_op_spe_st##name##_user, \ - &gen_op_spe_st##name##_le_user, \ - &gen_op_spe_st##name##_64_user, \ - &gen_op_spe_st##name##_le_64_user, \ - &gen_op_spe_st##name##_kernel, \ - &gen_op_spe_st##name##_le_kernel, \ - &gen_op_spe_st##name##_64_kernel, \ - &gen_op_spe_st##name##_le_64_kernel, \ - &gen_op_spe_st##name##_hypv, \ - &gen_op_spe_st##name##_le_hypv, \ - &gen_op_spe_st##name##_64_hypv, \ - &gen_op_spe_st##name##_le_64_hypv, \ -}; -#elif defined(TARGET_PPC64) -/* Full system - 64 bits mode */ -#define OP_SPE_LD_TABLE(name) \ -static GenOpFunc *gen_op_spe_l##name[] = { \ - &gen_op_spe_l##name##_user, \ - &gen_op_spe_l##name##_le_user, \ - &gen_op_spe_l##name##_64_user, \ - &gen_op_spe_l##name##_le_64_user, \ - &gen_op_spe_l##name##_kernel, \ - &gen_op_spe_l##name##_le_kernel, \ - &gen_op_spe_l##name##_64_kernel, \ - &gen_op_spe_l##name##_le_64_kernel, \ +static GenOpFunc *gen_op_spe_st##name[NB_MEM_FUNCS] = { \ + GEN_MEM_FUNCS(spe_st##name), \ }; -#define OP_SPE_ST_TABLE(name) \ -static GenOpFunc *gen_op_spe_st##name[] = { \ - &gen_op_spe_st##name##_user, \ - &gen_op_spe_st##name##_le_user, \ - &gen_op_spe_st##name##_64_user, \ - &gen_op_spe_st##name##_le_64_user, \ - &gen_op_spe_st##name##_kernel, \ - &gen_op_spe_st##name##_le_kernel, \ - &gen_op_spe_st##name##_64_kernel, \ - &gen_op_spe_st##name##_le_64_kernel, \ -}; -#else /* defined(TARGET_PPC64) */ -/* Full system - 32 bits mode */ -#define OP_SPE_LD_TABLE(name) \ -static GenOpFunc *gen_op_spe_l##name[] = { \ - &gen_op_spe_l##name##_user, \ - &gen_op_spe_l##name##_le_user, \ - &gen_op_spe_l##name##_kernel, \ - &gen_op_spe_l##name##_le_kernel, \ -}; -#define OP_SPE_ST_TABLE(name) \ -static GenOpFunc *gen_op_spe_st##name[] = { \ - &gen_op_spe_st##name##_user, \ - &gen_op_spe_st##name##_le_user, \ - &gen_op_spe_st##name##_kernel, \ - &gen_op_spe_st##name##_le_kernel, \ -}; -#endif /* defined(TARGET_PPC64) */ -#endif /* defined(CONFIG_USER_ONLY) */ #define GEN_SPE_LD(name, sh) \ static always_inline void gen_evl##name (DisasContext *ctx) \ @@ -6258,45 +5550,38 @@ GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE) /* In that case, we already have 64 bits load & stores * so, spe_ldd is equivalent to ld and spe_std is equivalent to std */ -#if defined(CONFIG_USER_ONLY) -#define gen_op_spe_ldd_raw gen_op_ld_raw -#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw -#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw -#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw -#define gen_op_spe_stdd_raw gen_op_ld_raw -#define gen_op_spe_stdd_64_raw gen_op_std_64_raw -#define gen_op_spe_stdd_le_raw gen_op_std_le_raw -#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw -#else /* defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_PPC64H) -#define gen_op_spe_ldd_hypv gen_op_ld_hypv -#define gen_op_spe_ldd_64_hypv gen_op_ld_64_hypv -#define gen_op_spe_ldd_le_hypv gen_op_ld_hypv -#define gen_op_spe_ldd_le_64_hypv gen_op_ld_64_hypv -#endif -#define gen_op_spe_ldd_kernel gen_op_ld_kernel -#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel -#define gen_op_spe_ldd_le_kernel gen_op_ld_kernel -#define gen_op_spe_ldd_le_64_kernel gen_op_ld_64_kernel -#define gen_op_spe_ldd_user gen_op_ld_user -#define gen_op_spe_ldd_64_user gen_op_ld_64_user -#define gen_op_spe_ldd_le_user gen_op_ld_le_user -#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user -#if defined(TARGET_PPC64H) -#define gen_op_spe_stdd_hypv gen_op_std_hypv -#define gen_op_spe_stdd_64_hypv gen_op_std_64_hypv -#define gen_op_spe_stdd_le_hypv gen_op_std_hypv -#define gen_op_spe_stdd_le_64_hypv gen_op_std_64_hypv -#endif -#define gen_op_spe_stdd_kernel gen_op_std_kernel -#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel -#define gen_op_spe_stdd_le_kernel gen_op_std_kernel -#define gen_op_spe_stdd_le_64_kernel gen_op_std_64_kernel -#define gen_op_spe_stdd_user gen_op_std_user -#define gen_op_spe_stdd_64_user gen_op_std_64_user -#define gen_op_spe_stdd_le_user gen_op_std_le_user -#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user -#endif /* defined(CONFIG_USER_ONLY) */ +#define gen_op_spe_ldd_raw gen_op_ld_raw +#define gen_op_spe_ldd_user gen_op_ld_user +#define gen_op_spe_ldd_kernel gen_op_ld_kernel +#define gen_op_spe_ldd_hypv gen_op_ld_hypv +#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw +#define gen_op_spe_ldd_64_user gen_op_ld_64_user +#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel +#define gen_op_spe_ldd_64_hypv gen_op_ld_64_hypv +#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw +#define gen_op_spe_ldd_le_user gen_op_ld_le_user +#define gen_op_spe_ldd_le_kernel gen_op_ld_le_kernel +#define gen_op_spe_ldd_le_hypv gen_op_ld_le_hypv +#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw +#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user +#define gen_op_spe_ldd_le_64_kernel gen_op_ld_le_64_kernel +#define gen_op_spe_ldd_le_64_hypv gen_op_ld_le_64_hypv +#define gen_op_spe_stdd_raw gen_op_std_raw +#define gen_op_spe_stdd_user gen_op_std_user +#define gen_op_spe_stdd_kernel gen_op_std_kernel +#define gen_op_spe_stdd_hypv gen_op_std_hypv +#define gen_op_spe_stdd_64_raw gen_op_std_64_raw +#define gen_op_spe_stdd_64_user gen_op_std_64_user +#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel +#define gen_op_spe_stdd_64_hypv gen_op_std_64_hypv +#define gen_op_spe_stdd_le_raw gen_op_std_le_raw +#define gen_op_spe_stdd_le_user gen_op_std_le_user +#define gen_op_spe_stdd_le_kernel gen_op_std_le_kernel +#define gen_op_spe_stdd_le_hypv gen_op_std_le_hypv +#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw +#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user +#define gen_op_spe_stdd_le_64_kernel gen_op_std_le_64_kernel +#define gen_op_spe_stdd_le_64_hypv gen_op_std_le_64_hypv #endif /* defined(TARGET_PPC64) */ GEN_SPEOP_LDST(dd, 3); GEN_SPEOP_LDST(dw, 3); @@ -6308,27 +5593,22 @@ GEN_SPEOP_ST(who, 2); #if defined(TARGET_PPC64) /* In that case, spe_stwwo is equivalent to stw */ -#if defined(CONFIG_USER_ONLY) -#define gen_op_spe_stwwo_raw gen_op_stw_raw -#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw -#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw -#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw -#else -#define gen_op_spe_stwwo_user gen_op_stw_user -#define gen_op_spe_stwwo_le_user gen_op_stw_le_user -#define gen_op_spe_stwwo_64_user gen_op_stw_64_user -#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user -#define gen_op_spe_stwwo_kernel gen_op_stw_kernel -#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel -#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel +#define gen_op_spe_stwwo_raw gen_op_stw_raw +#define gen_op_spe_stwwo_user gen_op_stw_user +#define gen_op_spe_stwwo_kernel gen_op_stw_kernel +#define gen_op_spe_stwwo_hypv gen_op_stw_hypv +#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw +#define gen_op_spe_stwwo_le_user gen_op_stw_le_user +#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel +#define gen_op_spe_stwwo_le_hypv gen_op_stw_le_hypv +#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw +#define gen_op_spe_stwwo_64_user gen_op_stw_64_user +#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel +#define gen_op_spe_stwwo_64_hypv gen_op_stw_64_hypv +#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw +#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user #define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel -#if defined(TARGET_PPC64H) -#define gen_op_spe_stwwo_hypv gen_op_stw_hypv -#define gen_op_spe_stwwo_le_hypv gen_op_stw_le_hypv -#define gen_op_spe_stwwo_64_hypv gen_op_stw_64_hypv -#define gen_op_spe_stwwo_le_64_hypv gen_op_stw_le_64_hypv -#endif -#endif +#define gen_op_spe_stwwo_le_64_hypv gen_op_stw_le_64_hypv #endif #define _GEN_OP_SPE_STWWE(suffix) \ static always_inline void gen_op_spe_stwwe_##suffix (void) \ @@ -6364,11 +5644,9 @@ _GEN_OP_SPE_STWWE_LE(suffix) #if defined(CONFIG_USER_ONLY) GEN_OP_SPE_STWWE(raw); #else /* defined(CONFIG_USER_ONLY) */ -#if defined(TARGET_PPC64H) -GEN_OP_SPE_STWWE(hypv); -#endif -GEN_OP_SPE_STWWE(kernel); GEN_OP_SPE_STWWE(user); +GEN_OP_SPE_STWWE(kernel); +GEN_OP_SPE_STWWE(hypv); #endif /* defined(CONFIG_USER_ONLY) */ GEN_SPEOP_ST(wwe, 2); GEN_SPEOP_ST(wwo, 2); @@ -6418,107 +5696,67 @@ GEN_OP_SPE_LHX(le_64_raw); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw); #endif #else -#if defined(TARGET_PPC64H) -GEN_OP_SPE_LHE(hypv); -#endif -GEN_OP_SPE_LHE(kernel); GEN_OP_SPE_LHE(user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhesplat, spe_lhe, hypv); -#endif -GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel); +GEN_OP_SPE_LHE(kernel); +GEN_OP_SPE_LHE(hypv); GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user); -#if defined(TARGET_PPC64H) -GEN_OP_SPE_LHE(le_hypv); -#endif -GEN_OP_SPE_LHE(le_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, hypv); GEN_OP_SPE_LHE(le_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_hypv); -#endif -GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel); +GEN_OP_SPE_LHE(le_kernel); +GEN_OP_SPE_LHE(le_hypv); GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhousplat, spe_lh, hypv); -#endif -GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_hypv); GEN_SPE_LDSPLAT(hhousplat, spe_lh, user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_hypv); -#endif -GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, hypv); GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user); -#if defined(TARGET_PPC64H) -GEN_OP_SPE_LHX(hypv); -#endif -GEN_OP_SPE_LHX(kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_hypv); GEN_OP_SPE_LHX(user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhossplat, spe_lhx, hypv); -#endif -GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel); +GEN_OP_SPE_LHX(kernel); +GEN_OP_SPE_LHX(hypv); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user); -#if defined(TARGET_PPC64H) -GEN_OP_SPE_LHX(le_hypv); -#endif -GEN_OP_SPE_LHX(le_kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, hypv); GEN_OP_SPE_LHX(le_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_hypv); -#endif -GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel); +GEN_OP_SPE_LHX(le_kernel); +GEN_OP_SPE_LHX(le_hypv); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_hypv); #if defined(TARGET_PPC64) -#if defined(TARGET_PPC64H) -GEN_OP_SPE_LHE(64_hypv); -#endif -GEN_OP_SPE_LHE(64_kernel); GEN_OP_SPE_LHE(64_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_hypv); -#endif -GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel); +GEN_OP_SPE_LHE(64_kernel); +GEN_OP_SPE_LHE(64_hypv); GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user); -#if defined(TARGET_PPC64H) -GEN_OP_SPE_LHE(le_64_hypv); -#endif -GEN_OP_SPE_LHE(le_64_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_hypv); GEN_OP_SPE_LHE(le_64_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_hypv); -#endif -GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel); +GEN_OP_SPE_LHE(le_64_kernel); +GEN_OP_SPE_LHE(le_64_hypv); GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_hypv); -#endif -GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel); +GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_hypv); GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_hypv); -#endif -GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_hypv); GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user); -#if defined(TARGET_PPC64H) -GEN_OP_SPE_LHX(64_hypv); -#endif -GEN_OP_SPE_LHX(64_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel); +GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_hypv); GEN_OP_SPE_LHX(64_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_hypv); -#endif -GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel); +GEN_OP_SPE_LHX(64_kernel); +GEN_OP_SPE_LHX(64_hypv); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user); -#if defined(TARGET_PPC64H) -GEN_OP_SPE_LHX(le_64_hypv); -#endif -GEN_OP_SPE_LHX(le_64_kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_hypv); GEN_OP_SPE_LHX(le_64_user); -#if defined(TARGET_PPC64H) -GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_hypv); -#endif -GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel); +GEN_OP_SPE_LHX(le_64_kernel); +GEN_OP_SPE_LHX(le_64_hypv); GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel); +GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_hypv); #endif #endif GEN_SPEOP_LD(hhesplat, 1); diff --git a/translate-all.c b/translate-all.c index 9f602be36..e9eef65d5 100644 --- a/translate-all.c +++ b/translate-all.c @@ -264,7 +264,8 @@ int cpu_restore_state(TranslationBlock *tb, #else #define CASE3(op)\ case INDEX_op_ ## op ## _user:\ - case INDEX_op_ ## op ## _kernel + case INDEX_op_ ## op ## _kernel:\ + case INDEX_op_ ## op ## _hypv #endif CASE3(stfd): -- cgit v1.2.3 From 5a6932d51d1b34b68b3f10fc5ac65598bece88c0 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 16 Nov 2007 14:57:36 +0000 Subject: Fix NaN handling for MIPS and HPPA. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3655 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-specialize.h | 108 ++++++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 40 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 2802eaa8d..8f9dd5c45 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -30,6 +30,12 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ +#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#define SNAN_BIT_IS_ONE 1 +#else +#define SNAN_BIT_IS_ONE 0 +#endif + /*---------------------------------------------------------------------------- | Underflow tininess-detection mode, statically initialized to default value. | (The declaration in `softfloat.h' must match the `int8' type here.) @@ -45,9 +51,7 @@ int8 float_detect_tininess = float_tininess_after_rounding; void float_raise( int8 flags STATUS_PARAM ) { - STATUS(float_exception_flags) |= flags; - } /*---------------------------------------------------------------------------- @@ -61,20 +65,20 @@ typedef struct { /*---------------------------------------------------------------------------- | The pattern for a default generated single-precision NaN. *----------------------------------------------------------------------------*/ -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) -#define float32_default_nan 0xFF800000 +#if SNAN_BIT_IS_ONE +#define float32_default_nan 0x7FBFFFFF #else #define float32_default_nan 0xFFC00000 #endif /*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is a NaN; -| otherwise returns 0. +| Returns 1 if the single-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ int float32_is_nan( float32 a ) { -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#if SNAN_BIT_IS_ONE return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); #else return ( 0xFF800000 <= (bits32) ( a<<1 ) ); @@ -88,7 +92,7 @@ int float32_is_nan( float32 a ) int float32_is_signaling_nan( float32 a ) { -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#if SNAN_BIT_IS_ONE return ( 0xFF800000 <= (bits32) ( a<<1 ) ); #else return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); @@ -110,7 +114,6 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) z.low = 0; z.high = ( (bits64) a )<<41; return z; - } /*---------------------------------------------------------------------------- @@ -120,9 +123,7 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) static float32 commonNaNToFloat32( commonNaNT a ) { - return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); - } /*---------------------------------------------------------------------------- @@ -139,7 +140,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) aIsSignalingNaN = float32_is_signaling_nan( a ); bIsNaN = float32_is_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#if SNAN_BIT_IS_ONE a &= ~0x00400000; b &= ~0x00400000; #else @@ -161,26 +162,25 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) else { return b; } - } /*---------------------------------------------------------------------------- | The pattern for a default generated double-precision NaN. *----------------------------------------------------------------------------*/ -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) -#define float64_default_nan LIT64( 0xFFF0000000000000 ) +#if SNAN_BIT_IS_ONE +#define float64_default_nan LIT64( 0x7FF7FFFFFFFFFFFF ) #else #define float64_default_nan LIT64( 0xFFF8000000000000 ) #endif /*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is a NaN; -| otherwise returns 0. +| Returns 1 if the double-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ int float64_is_nan( float64 a ) { -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#if SNAN_BIT_IS_ONE return ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); @@ -196,7 +196,7 @@ int float64_is_nan( float64 a ) int float64_is_signaling_nan( float64 a ) { -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#if SNAN_BIT_IS_ONE return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); #else return @@ -220,7 +220,6 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) z.low = 0; z.high = a<<12; return z; - } /*---------------------------------------------------------------------------- @@ -230,12 +229,10 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) static float64 commonNaNToFloat64( commonNaNT a ) { - return ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FF8000000000000 ) | ( a.high>>12 ); - } /*---------------------------------------------------------------------------- @@ -252,7 +249,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) aIsSignalingNaN = float64_is_signaling_nan( a ); bIsNaN = float64_is_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#if SNAN_BIT_IS_ONE a &= ~LIT64( 0x0008000000000000 ); b &= ~LIT64( 0x0008000000000000 ); #else @@ -274,7 +271,6 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) else { return b; } - } #ifdef FLOATX80 @@ -284,19 +280,32 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) | `high' and `low' values hold the most- and least-significant bits, | respectively. *----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define floatx80_default_nan_high 0x7FFF +#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF ) +#else #define floatx80_default_nan_high 0xFFFF #define floatx80_default_nan_low LIT64( 0xC000000000000000 ) +#endif /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is a -| NaN; otherwise returns 0. +| quiet NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ int floatx80_is_nan( floatx80 a ) { +#if SNAN_BIT_IS_ONE + bits64 aLow; + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); +#else return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); - +#endif } /*---------------------------------------------------------------------------- @@ -306,6 +315,9 @@ int floatx80_is_nan( floatx80 a ) int floatx80_is_signaling_nan( floatx80 a ) { +#if SNAN_BIT_IS_ONE + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); +#else bits64 aLow; aLow = a.low & ~ LIT64( 0x4000000000000000 ); @@ -313,7 +325,7 @@ int floatx80_is_signaling_nan( floatx80 a ) ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( aLow<<1 ) && ( a.low == aLow ); - +#endif } /*---------------------------------------------------------------------------- @@ -331,7 +343,6 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) z.low = 0; z.high = a.low<<1; return z; - } /*---------------------------------------------------------------------------- @@ -346,7 +357,6 @@ static floatx80 commonNaNToFloatx80( commonNaNT a ) z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; return z; - } /*---------------------------------------------------------------------------- @@ -363,8 +373,13 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) aIsSignalingNaN = floatx80_is_signaling_nan( a ); bIsNaN = floatx80_is_nan( b ); bIsSignalingNaN = floatx80_is_signaling_nan( b ); +#if SNAN_BIT_IS_ONE + a.low &= ~LIT64( 0xC000000000000000 ); + b.low &= ~LIT64( 0xC000000000000000 ); +#else a.low |= LIT64( 0xC000000000000000 ); b.low |= LIT64( 0xC000000000000000 ); +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; @@ -380,7 +395,6 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) else { return b; } - } #endif @@ -391,21 +405,30 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) | The pattern for a default generated quadruple-precision NaN. The `high' and | `low' values hold the most- and least-significant bits, respectively. *----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF ) +#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) +#else #define float128_default_nan_high LIT64( 0xFFFF800000000000 ) #define float128_default_nan_low LIT64( 0x0000000000000000 ) +#endif /*---------------------------------------------------------------------------- -| Returns 1 if the quadruple-precision floating-point value `a' is a NaN; -| otherwise returns 0. +| Returns 1 if the quadruple-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ int float128_is_nan( float128 a ) { - +#if SNAN_BIT_IS_ONE + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); +#else return ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); - +#endif } /*---------------------------------------------------------------------------- @@ -415,11 +438,15 @@ int float128_is_nan( float128 a ) int float128_is_signaling_nan( float128 a ) { - +#if SNAN_BIT_IS_ONE + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); +#else return ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); - +#endif } /*---------------------------------------------------------------------------- @@ -436,7 +463,6 @@ static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM) z.sign = a.high>>63; shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); return z; - } /*---------------------------------------------------------------------------- @@ -451,7 +477,6 @@ static float128 commonNaNToFloat128( commonNaNT a ) shift128Right( a.high, a.low, 16, &z.high, &z.low ); z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 ); return z; - } /*---------------------------------------------------------------------------- @@ -468,8 +493,13 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) aIsSignalingNaN = float128_is_signaling_nan( a ); bIsNaN = float128_is_nan( b ); bIsSignalingNaN = float128_is_signaling_nan( b ); +#if SNAN_BIT_IS_ONE + a.high &= ~LIT64( 0x0000800000000000 ); + b.high &= ~LIT64( 0x0000800000000000 ); +#else a.high |= LIT64( 0x0000800000000000 ); b.high |= LIT64( 0x0000800000000000 ); +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; @@ -485,8 +515,6 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) else { return b; } - } #endif - -- cgit v1.2.3 From b172c56a6d849554f7e43adc95983a9d6c042689 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 01:37:44 +0000 Subject: Always make all PowerPC exception definitions visible. Always make the hypervisor timers available. Remove all TARGET_PPC64H checks, keeping a few if (0) tests for cases that cannot be properly handled with the current PowerPC CPU definition. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3656 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 6 --- hw/ppc.c | 24 ++++++------ linux-user/main.c | 6 --- target-ppc/cpu.h | 8 ---- target-ppc/helper.c | 92 +++++++++++++++++++++++++++------------------ target-ppc/helper_regs.h | 7 +--- target-ppc/translate_init.c | 2 - 7 files changed, 69 insertions(+), 76 deletions(-) diff --git a/darwin-user/main.c b/darwin-user/main.c index 0a371dedf..bd8c1813f 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -386,7 +386,6 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Reset interrupt while in user mode. " "Aborting\n"); break; -#if defined(TARGET_PPC64) /* PowerPC 64 */ case POWERPC_EXCP_DSEG: /* Data segment exception */ cpu_abort(env, "Data segment exception while in user mode. " "Aborting\n"); @@ -395,19 +394,15 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Instruction segment exception " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64) */ -#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ cpu_abort(env, "Hypervisor decrementer interrupt " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64H) */ case POWERPC_EXCP_TRACE: /* Trace exception */ /* Nothing to do: * we use this exception to emulate step-by-step execution mode. */ break; -#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ cpu_abort(env, "Hypervisor data storage exception " "while in user mode. Aborting\n"); @@ -424,7 +419,6 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Hypervisor instruction segment exception " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64H) */ case POWERPC_EXCP_VPU: /* Vector unavailable exception */ EXCP_DUMP(env, "No Altivec instructions allowed\n"); info.si_signo = SIGILL; diff --git a/hw/ppc.c b/hw/ppc.c index d897e6218..92e5bfedb 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -428,13 +428,11 @@ struct ppc_tb_t { uint64_t decr_next; /* Tick for next decr interrupt */ uint32_t decr_freq; /* decrementer frequency */ struct QEMUTimer *decr_timer; -#if defined(TARGET_PPC64H) /* Hypervisor decrementer management */ uint64_t hdecr_next; /* Tick for next hdecr interrupt */ struct QEMUTimer *hdecr_timer; uint64_t purr_load; uint64_t purr_start; -#endif void *opaque; }; @@ -643,7 +641,6 @@ uint32_t cpu_ppc_load_decr (CPUState *env) return _cpu_ppc_load_decr(env, &tb_env->decr_next); } -#if defined(TARGET_PPC64H) uint32_t cpu_ppc_load_hdecr (CPUState *env) { ppc_tb_t *tb_env = env->tb_env; @@ -660,7 +657,6 @@ uint64_t cpu_ppc_load_purr (CPUState *env) return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec); } -#endif /* defined(TARGET_PPC64H) */ /* When decrementer expires, * all we need to do is generate or queue a CPU exception @@ -736,14 +732,15 @@ static void cpu_ppc_decr_cb (void *opaque) _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); } -#if defined(TARGET_PPC64H) static always_inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr, uint32_t value, int is_excp) { ppc_tb_t *tb_env = env->tb_env; - __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer, - &cpu_ppc_hdecr_excp, hdecr, value, is_excp); + if (tb_env->hdecr_timer != NULL) { + __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer, + &cpu_ppc_hdecr_excp, hdecr, value, is_excp); + } } void cpu_ppc_store_hdecr (CPUState *env, uint32_t value) @@ -763,7 +760,6 @@ void cpu_ppc_store_purr (CPUState *env, uint64_t value) tb_env->purr_load = value; tb_env->purr_start = qemu_get_clock(vm_clock); } -#endif /* defined(TARGET_PPC64H) */ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) { @@ -777,10 +773,8 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) * it's not ready to handle it... */ _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); -#if defined(TARGET_PPC64H) _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); cpu_ppc_store_purr(env, 0x0000000000000000ULL); -#endif /* defined(TARGET_PPC64H) */ } /* Set up (once) timebase frequency (in Hz) */ @@ -794,9 +788,13 @@ clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq) env->tb_env = tb_env; /* Create new timer */ tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); -#if defined(TARGET_PPC64H) - tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env); -#endif /* defined(TARGET_PPC64H) */ + if (0) { + /* XXX: find a suitable condition to enable the hypervisor decrementer + */ + tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env); + } else { + tb_env->hdecr_timer = NULL; + } cpu_ppc_set_tb_clk(env, freq); return &cpu_ppc_set_tb_clk; diff --git a/linux-user/main.c b/linux-user/main.c index 2192abb48..631eb4b6b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1047,7 +1047,6 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Reset interrupt while in user mode. " "Aborting\n"); break; -#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) /* PowerPC 64 */ case POWERPC_EXCP_DSEG: /* Data segment exception */ cpu_abort(env, "Data segment exception while in user mode. " "Aborting\n"); @@ -1056,20 +1055,16 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Instruction segment exception " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64) && !defined(TARGET_ABI32) */ -#if defined(TARGET_PPC64H) && !defined(TARGET_ABI32) /* PowerPC 64 with hypervisor mode support */ case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ cpu_abort(env, "Hypervisor decrementer interrupt " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64H) && !defined(TARGET_ABI32) */ case POWERPC_EXCP_TRACE: /* Trace exception */ /* Nothing to do: * we use this exception to emulate step-by-step execution mode. */ break; -#if defined(TARGET_PPC64H) && !defined(TARGET_ABI32) /* PowerPC 64 with hypervisor mode support */ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ cpu_abort(env, "Hypervisor data storage exception " @@ -1087,7 +1082,6 @@ void cpu_loop(CPUPPCState *env) cpu_abort(env, "Hypervisor instruction segment exception " "while in user mode. Aborting\n"); break; -#endif /* defined(TARGET_PPC64H) && !defined(TARGET_ABI32) */ case POWERPC_EXCP_VPU: /* Vector unavailable exception */ EXCP_DUMP(env, "No Altivec instructions allowed\n"); info.si_signo = TARGET_SIGILL; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index d40bb4070..7705ca20c 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -180,20 +180,14 @@ enum { /* Vectors 38 to 63 are reserved */ /* Exceptions defined in the PowerPC server specification */ POWERPC_EXCP_RESET = 64, /* System reset exception */ -#if defined(TARGET_PPC64) /* PowerPC 64 */ POWERPC_EXCP_DSEG = 65, /* Data segment exception */ POWERPC_EXCP_ISEG = 66, /* Instruction segment exception */ -#endif /* defined(TARGET_PPC64) */ -#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ POWERPC_EXCP_HDECR = 67, /* Hypervisor decrementer exception */ -#endif /* defined(TARGET_PPC64H) */ POWERPC_EXCP_TRACE = 68, /* Trace exception */ -#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ POWERPC_EXCP_HDSI = 69, /* Hypervisor data storage exception */ POWERPC_EXCP_HISI = 70, /* Hypervisor instruction storage exception */ POWERPC_EXCP_HDSEG = 71, /* Hypervisor data segment exception */ POWERPC_EXCP_HISEG = 72, /* Hypervisor instruction segment exception */ -#endif /* defined(TARGET_PPC64H) */ POWERPC_EXCP_VPU = 73, /* Vector unavailable exception */ /* 40x specific exceptions */ POWERPC_EXCP_PIT = 74, /* Programmable interval timer interrupt */ @@ -736,12 +730,10 @@ void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value); void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value); uint32_t cpu_ppc_load_decr (CPUPPCState *env); void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); -#if defined(TARGET_PPC64H) uint32_t cpu_ppc_load_hdecr (CPUPPCState *env); void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value); uint64_t cpu_ppc_load_purr (CPUPPCState *env); void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value); -#endif uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env); uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env); #if !defined(CONFIG_USER_ONLY) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 268703cd4..8c187c7de 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2134,13 +2134,21 @@ static always_inline void powerpc_excp (CPUState *env, { target_ulong msr, new_msr, vector; int srr0, srr1, asrr0, asrr1; -#if defined(TARGET_PPC64H) - int lpes0, lpes1, lev; - - lpes0 = (env->spr[SPR_LPCR] >> 1) & 1; - lpes1 = (env->spr[SPR_LPCR] >> 2) & 1; + int lpes0, lpes1; +#if defined(TARGET_PPC64) + int lev; #endif + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + lpes0 = (env->spr[SPR_LPCR] >> 1) & 1; + lpes1 = (env->spr[SPR_LPCR] >> 2) & 1; + } else { + /* Those values ensure we won't enter the hypervisor mode */ + lpes0 = 0; + lpes1 = 1; + } + if (loglevel & CPU_LOG_INT) { fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", env->nip, excp, env->error_code); @@ -2190,8 +2198,11 @@ static always_inline void powerpc_excp (CPUState *env, } new_msr &= ~((target_ulong)1 << MSR_RI); new_msr &= ~((target_ulong)1 << MSR_ME); -#if defined(TARGET_PPC64H) - new_msr |= (target_ulong)1 << MSR_HV; +#if defined(TARGET_PPC64) + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + new_msr |= (target_ulong)1 << MSR_HV; + } #endif /* XXX: should also have something loaded in DAR / DSISR */ switch (excp_model) { @@ -2217,7 +2228,7 @@ static always_inline void powerpc_excp (CPUState *env, } #endif new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2230,7 +2241,7 @@ static always_inline void powerpc_excp (CPUState *env, } #endif new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2238,14 +2249,14 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; case POWERPC_EXCP_EXTERNAL: /* External input */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes0 == 1) new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2267,7 +2278,7 @@ static always_inline void powerpc_excp (CPUState *env, return; } new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2284,7 +2295,7 @@ static always_inline void powerpc_excp (CPUState *env, } #endif new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2292,7 +2303,7 @@ static always_inline void powerpc_excp (CPUState *env, break; case POWERPC_EXCP_PRIV: new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2300,7 +2311,7 @@ static always_inline void powerpc_excp (CPUState *env, break; case POWERPC_EXCP_TRAP: new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2315,7 +2326,7 @@ static always_inline void powerpc_excp (CPUState *env, goto store_current; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2336,7 +2347,7 @@ static always_inline void powerpc_excp (CPUState *env, dump_syscall(env); } new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) lev = env->error_code; if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) new_msr |= (target_ulong)1 << MSR_HV; @@ -2347,7 +2358,7 @@ static always_inline void powerpc_excp (CPUState *env, goto store_current; case POWERPC_EXCP_DECR: /* Decrementer exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2434,65 +2445,69 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; case POWERPC_EXCP_RESET: /* System reset exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; -#if defined(TARGET_PPC64) case POWERPC_EXCP_DSEG: /* Data segment exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; -#endif /* defined(TARGET_PPC64) */ -#if defined(TARGET_PPC64H) case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; +#if defined(TARGET_PPC64) new_msr |= (target_ulong)1 << MSR_HV; - goto store_next; #endif + goto store_next; case POWERPC_EXCP_TRACE: /* Trace exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif goto store_next; -#if defined(TARGET_PPC64H) case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; +#if defined(TARGET_PPC64) new_msr |= (target_ulong)1 << MSR_HV; +#endif goto store_next; case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; +#if defined(TARGET_PPC64) new_msr |= (target_ulong)1 << MSR_HV; +#endif goto store_next; case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; +#if defined(TARGET_PPC64) new_msr |= (target_ulong)1 << MSR_HV; +#endif goto store_next; case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; +#if defined(TARGET_PPC64) new_msr |= (target_ulong)1 << MSR_HV; +#endif goto store_next; -#endif /* defined(TARGET_PPC64H) */ case POWERPC_EXCP_VPU: /* Vector unavailable exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2519,7 +2534,7 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ -#if defined(TARGET_PPC64H) /* XXX: check this */ +#if defined(TARGET_PPC64) /* XXX: check this */ if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2540,7 +2555,7 @@ static always_inline void powerpc_excp (CPUState *env, break; case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ -#if defined(TARGET_PPC64H) /* XXX: check this */ +#if defined(TARGET_PPC64) /* XXX: check this */ if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2561,7 +2576,7 @@ static always_inline void powerpc_excp (CPUState *env, break; case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ -#if defined(TARGET_PPC64H) /* XXX: check this */ +#if defined(TARGET_PPC64) /* XXX: check this */ if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2663,7 +2678,7 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) if (lpes1 == 0) new_msr |= (target_ulong)1 << MSR_HV; #endif @@ -2769,7 +2784,7 @@ void do_interrupt (CPUState *env) void ppc_hw_interrupt (CPUPPCState *env) { -#if defined(TARGET_PPC64H) +#if defined(TARGET_PPC64) int hdice; #endif @@ -2800,8 +2815,13 @@ void ppc_hw_interrupt (CPUPPCState *env) return; } #endif -#if defined(TARGET_PPC64H) - hdice = env->spr[SPR_LPCR] & 1; +#if defined(TARGET_PPC64) + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + hdice = env->spr[SPR_LPCR] & 1; + } else { + hdice = 0; + } if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) { /* Hypervisor decrementer exception */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index c52ae9ebc..03c21c77f 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -60,7 +60,7 @@ static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) static always_inline void hreg_compute_mem_idx (CPUPPCState *env) { -#if defined (TARGET_PPC64H) +#if defined (TARGET_PPC64) /* Precompute MMU index */ if (msr_pr == 0 && msr_hv != 0) env->mmu_idx = 2; @@ -78,10 +78,7 @@ static always_inline void hreg_compute_hflags (CPUPPCState *env) (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | (1 << MSR_LE); #if defined (TARGET_PPC64) - hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF); -#if defined (TARGET_PPC64H) - hflags_mask |= 1ULL << MSR_HV; -#endif + hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | (1ULL << MSR_HV); #endif hreg_compute_mem_idx(env); env->hflags = env->msr & hflags_mask; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index c6b744698..1a0890920 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2609,9 +2609,7 @@ static void init_excp_970 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; -#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ env->excp_vectors[POWERPC_EXCP_HDECR] = 0x00000980; -#endif env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; -- cgit v1.2.3 From 31fca6ab60f8ee8062bf59d54ba4d88832064ff1 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 01:52:38 +0000 Subject: Resynchronize darwin-user target with linux-user: add CPU selection feature, choose the correct default CPU and set the 32/64 bits computation mode properly. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3657 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/main.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/darwin-user/main.c b/darwin-user/main.c index bd8c1813f..10b7fcb9a 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -834,6 +834,15 @@ int main(int argc, char **argv) } else if (!strcmp(r, "g")) { use_gdbstub = 1; + } else if (!strcmp(r, "cpu")) { + cpu_model = argv[optind++]; + if (strcmp(cpu_model, "?") == 0) { +/* XXX: implement xxx_cpu_list for targets that still miss it */ +#if defined(cpu_list) + cpu_list(stdout, &fprintf); +#endif + _exit(1); + } } else { usage(); @@ -846,16 +855,26 @@ int main(int argc, char **argv) /* Zero out regs */ memset(regs, 0, sizeof(struct target_pt_regs)); - /* NOTE: we need to init the CPU at this stage to get - qemu_host_page_size */ + if (cpu_model == NULL) { #if defined(TARGET_I386) - cpu_model = "qemu32"; +#ifdef TARGET_X86_64 + cpu_model = "qemu64"; +#else + cpu_model = "qemu32"; +#endif #elif defined(TARGET_PPC) - cpu_model = "750"; +#ifdef TARGET_PPC64 + cpu_model = "970"; +#else + cpu_model = "750"; +#endif #else #error unsupported CPU #endif + } + /* NOTE: we need to init the CPU at this stage to get + qemu_host_page_size */ env = cpu_init(cpu_model); printf("Starting %s with qemu\n----------------\n", filename); @@ -997,6 +1016,14 @@ int main(int argc, char **argv) #elif defined(TARGET_PPC) { int i; + +#if defined(TARGET_PPC64) +#if defined(TARGET_ABI32) + env->msr &= ~((target_ulong)1 << MSR_SF); +#else + env->msr |= (target_ulong)1 << MSR_SF; +#endif +#endif env->nip = regs->nip; for(i = 0; i < 32; i++) { env->gpr[i] = regs->gpr[i]; -- cgit v1.2.3 From 5e692ecdbff27d5a4c9ffdc76fa43d3dc163d119 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 01:54:45 +0000 Subject: Remove ppc64h CPUs definitions from the configure script. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3658 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/configure b/configure index 535876d6a..7a74c6013 100755 --- a/configure +++ b/configure @@ -978,7 +978,6 @@ target_bigendian="no" [ "$target_cpu" = "ppcemb" ] && target_bigendian=yes [ "$target_cpu" = "ppc64" ] && target_bigendian=yes [ "$target_cpu" = "ppc64abi32" ] && target_bigendian=yes -[ "$target_cpu" = "ppc64h" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes [ "$target_cpu" = "mipsn32" ] && target_bigendian=yes [ "$target_cpu" = "mips64" ] && target_bigendian=yes @@ -1084,24 +1083,17 @@ elif test "$target_cpu" = "ppcemb" ; then echo "#define TARGET_PPCEMB 1" >> $config_h elif test "$target_cpu" = "ppc64" ; then echo "TARGET_ARCH=ppc64" >> $config_mak - echo "#define TARGET_ARCH \"ppc64\"" >> $config_h echo "TARGET_ABI_DIR=ppc" >> $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" = "ppc64abi32" ; then echo "TARGET_ARCH=ppc64" >> $config_mak - echo "#define TARGET_ARCH \"ppc64\"" >> $config_h echo "TARGET_ABI_DIR=ppc" >> $config_mak + echo "#define TARGET_ARCH \"ppc64\"" >> $config_h echo "#define TARGET_PPC 1" >> $config_h echo "#define TARGET_PPC64 1" >> $config_h echo "#define TARGET_ABI32 1" >> $config_h -elif test "$target_cpu" = "ppc64h" ; then - echo "TARGET_ARCH=ppc64h" >> $config_mak - echo "#define TARGET_ARCH \"ppc64h\"" >> $config_h - echo "TARGET_ABI_DIR=ppc" >> $config_mak - echo "#define TARGET_PPC 1" >> $config_h - echo "#define TARGET_PPC64 1" >> $config_h - echo "#define TARGET_PPC64H 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 -- cgit v1.2.3 From 7b62a955047934bab158e84ecb63cb432c193ace Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 02:04:00 +0000 Subject: Add missing definition for number of input pins for the PowerPC 970 bus. Use proper INPUT_NB definitions to allocate PowerPC input pins structure, fixing a buffer overflow in the 6xx bus case. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3659 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 6 ++++-- target-ppc/cpu.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 92e5bfedb..a25a3607f 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -172,7 +172,8 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) void ppc6xx_irq_init (CPUState *env) { - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6); + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, + PPC6xx_INPUT_NB); } #if defined(TARGET_PPC64) @@ -295,7 +296,8 @@ static void ppc970_set_irq (void *opaque, int pin, int level) void ppc970_irq_init (CPUState *env) { - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7); + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, + PPC970_INPUT_NB); } #endif /* defined(TARGET_PPC64) */ diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7705ca20c..f249522af 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1249,6 +1249,7 @@ enum { PPC970_INPUT_MCP = 4, PPC970_INPUT_INT = 5, PPC970_INPUT_THINT = 6, + PPC970_INPUT_NB, }; #endif -- cgit v1.2.3 From 7820dbf3f0d8ebc44b8dfc0853c8a2c4bd6aea8e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 02:16:14 +0000 Subject: Make the PowerPC MMU model, exception model and input bus model typedefed enums. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3660 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 16 +++++++++------- target-ppc/translate_init.c | 7 +++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f249522af..3baab6768 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -89,7 +89,8 @@ typedef uint32_t ppc_gpr_t; /*****************************************************************************/ /* MMU model */ -enum { +typedef enum powerpc_mmu_t powerpc_mmu_t; +enum powerpc_mmu_t { POWERPC_MMU_UNKNOWN = 0, /* Standard 32 bits PowerPC MMU */ POWERPC_MMU_32B, @@ -117,7 +118,8 @@ enum { /*****************************************************************************/ /* Exception model */ -enum { +typedef enum powerpc_excp_t powerpc_excp_t; +enum powerpc_excp_t { POWERPC_EXCP_UNKNOWN = 0, /* Standard PowerPC exception model */ POWERPC_EXCP_STD, @@ -263,7 +265,8 @@ enum { /*****************************************************************************/ /* Input pins model */ -enum { +typedef enum powerpc_input_t powerpc_input_t; +enum powerpc_input_t { PPC_FLAGS_INPUT_UNKNOWN = 0, /* PowerPC 6xx bus */ PPC_FLAGS_INPUT_6xx, @@ -609,10 +612,9 @@ struct CPUPPCState { /* Those resources are used during exception processing */ /* CPU model definition */ target_ulong msr_mask; - uint8_t mmu_model; - uint8_t excp_model; - uint8_t bus_model; - uint8_t pad; + powerpc_mmu_t mmu_model; + powerpc_excp_t excp_model; + powerpc_input_t bus_model; int bfd_mach; uint32_t flags; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 1a0890920..62c080201 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -35,10 +35,9 @@ struct ppc_def_t { uint32_t pvr; uint64_t insns_flags; uint64_t msr_mask; - uint8_t mmu_model; - uint8_t excp_model; - uint8_t bus_model; - uint8_t pad; + powerpc_mmu_t mmu_model; + powerpc_excp_t excp_model; + powerpc_input_t bus_model; uint32_t flags; int bfd_mach; void (*init_proc)(CPUPPCState *env); -- cgit v1.2.3 From 295db11371adb11d1117446e79162bbe5ebd046a Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 17 Nov 2007 08:18:59 +0000 Subject: Add MXCC module reset register (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3661 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 09e9c8bf4..9409052f0 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -207,6 +207,14 @@ void helper_ld_asi(int asi, int size, int sign) else DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); break; + case 0x01c00c00: /* Module reset register */ + if (size == 8) { + ret = env->mxccregs[5] >> 32; + T0 = env->mxccregs[5]; + // should we do something here? + } else + DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); + break; case 0x01c00f00: /* MBus port address register */ if (size == 8) { ret = env->mxccregs[7]; -- cgit v1.2.3 From bbf7d96b451ea3b6339520b974793f121cfd2c19 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 17 Nov 2007 08:19:57 +0000 Subject: Fix MXCC error register (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3662 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 9409052f0..5eebd8388 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -446,13 +446,11 @@ void helper_st_asi(int asi, int size) DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); break; case 0x01c00e00: /* MXCC error register */ + // writing a 1 bit clears the error if (size == 8) - env->mxccregs[6] = ((uint64_t)T1 << 32) | T2; + env->mxccregs[6] &= ~(((uint64_t)T1 << 32) | T2); else DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); - if (env->mxccregs[6] == 0xffffffffffffffffULL) { - // this is probably a reset - } break; case 0x01c00f00: /* MBus port address register */ if (size == 8) -- cgit v1.2.3 From 2761992d13ed80a1351c24f49836c845ecf05097 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 17 Nov 2007 08:21:43 +0000 Subject: Remove unnecessary register masking (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3663 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 5eebd8388..279c4b948 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -271,7 +271,7 @@ void helper_ld_asi(int asi, int size, int sign) case 8: tmp = ldq_code(T0 & ~7); ret = tmp >> 32; - T0 = tmp & 0xffffffff; + T0 = tmp; break; } break; @@ -290,7 +290,7 @@ void helper_ld_asi(int asi, int size, int sign) case 8: tmp = ldq_user(T0 & ~7); ret = tmp >> 32; - T0 = tmp & 0xffffffff; + T0 = tmp; break; } break; @@ -309,7 +309,7 @@ void helper_ld_asi(int asi, int size, int sign) case 8: tmp = ldq_kernel(T0 & ~7); ret = tmp >> 32; - T0 = tmp & 0xffffffff; + T0 = tmp; break; } break; @@ -333,7 +333,7 @@ void helper_ld_asi(int asi, int size, int sign) case 8: tmp = ldq_phys(T0 & ~7); ret = tmp >> 32; - T0 = tmp & 0xffffffff; + T0 = tmp; break; } break; @@ -357,7 +357,7 @@ void helper_ld_asi(int asi, int size, int sign) tmp = ldq_phys((target_phys_addr_t)(T0 & ~7) | ((target_phys_addr_t)(asi & 0xf) << 32)); ret = tmp >> 32; - T0 = tmp & 0xffffffff; + T0 = tmp; break; } break; -- cgit v1.2.3 From 7fbfb139ec0b3d3572369db977ea354c274dabdf Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 17 Nov 2007 09:04:09 +0000 Subject: Machine specific IOMMU version (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3664 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 11 +++++++---- hw/sun4m.c | 6 +++++- vl.h | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/hw/iommu.c b/hw/iommu.c index 55d39b9fd..c90f09bca 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -37,7 +37,6 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define IOMMU_CTRL (0x0000 >> 2) #define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ #define IOMMU_CTRL_VERS 0x0f000000 /* Version */ -#define IOMMU_VERSION 0x04000000 #define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ #define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */ #define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */ @@ -104,6 +103,7 @@ typedef struct IOMMUState { target_phys_addr_t addr; uint32_t regs[IOMMU_NREGS]; target_phys_addr_t iostart; + uint32_t version; } IOMMUState; static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) @@ -158,7 +158,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val break; } DPRINTF("iostart = " TARGET_FMT_plx "\n", s->iostart); - s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION); + s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version); break; case IOMMU_BASE: s->regs[saddr] = val & IOMMU_BASE_MASK; @@ -308,10 +308,11 @@ static void iommu_reset(void *opaque) memset(s->regs, 0, IOMMU_NREGS * 4); s->iostart = 0; - s->regs[IOMMU_CTRL] = IOMMU_VERSION; + s->regs[IOMMU_CTRL] = s->version; + s->regs[IOMMU_ARBEN] = IOMMU_MID; } -void *iommu_init(target_phys_addr_t addr) +void *iommu_init(target_phys_addr_t addr, uint32_t version) { IOMMUState *s; int iommu_io_memory; @@ -321,12 +322,14 @@ void *iommu_init(target_phys_addr_t addr) return NULL; s->addr = addr; + s->version = version; iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); register_savevm("iommu", addr, 2, iommu_save, iommu_load, s); qemu_register_reset(iommu_reset, s); + iommu_reset(s); return s; } diff --git a/hw/sun4m.c b/hw/sun4m.c index d589b2995..9f15e45b1 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -72,6 +72,7 @@ struct hwdef { int intctl_g_intr, esp_irq, le_irq, clock_irq, clock1_irq; int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq; int machine_id; // For NVRAM + uint32_t iommu_version; uint32_t intbit_to_level[32]; }; @@ -302,7 +303,7 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, /* allocate RAM */ cpu_register_physical_memory(0, RAM_size, 0); - iommu = iommu_init(hwdef->iommu_base); + iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version); slavio_intctl = slavio_intctl_init(hwdef->intctl_base, hwdef->intctl_base + 0x10000ULL, &hwdef->intbit_to_level[0], @@ -468,6 +469,7 @@ static const struct hwdef hwdefs[] = { .me_irq = 30, .cs_irq = 5, .machine_id = 0x80, + .iommu_version = 0x04000000, .intbit_to_level = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, @@ -501,6 +503,7 @@ static const struct hwdef hwdefs[] = { .me_irq = 30, .cs_irq = -1, .machine_id = 0x72, + .iommu_version = 0x03000000, .intbit_to_level = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, @@ -534,6 +537,7 @@ static const struct hwdef hwdefs[] = { .me_irq = 30, .cs_irq = -1, .machine_id = 0x71, + .iommu_version = 0x01000000, .intbit_to_level = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, diff --git a/vl.h b/vl.h index cdcc3c95d..affffad93 100644 --- a/vl.h +++ b/vl.h @@ -1051,7 +1051,7 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine; /* iommu.c */ -void *iommu_init(target_phys_addr_t addr); +void *iommu_init(target_phys_addr_t addr, uint32_t version); void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write); static inline void sparc_iommu_memory_read(void *opaque, -- cgit v1.2.3 From 7221fa98d381a19b8809979934554644381fb88c Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 17 Nov 2007 09:53:42 +0000 Subject: Check permissions for the last byte first in unaligned slow_st accesses (patch from TeLeMan). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3665 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_template.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/softmmu_template.h b/softmmu_template.h index 89b2f38c8..a0a2c38ab 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -282,7 +282,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* XXX: not efficient, but simple */ - for(i = 0;i < DATA_SIZE; i++) { + for(i = DATA_SIZE - 1; i >= 0; i--) { #ifdef TARGET_WORDS_BIGENDIAN glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), mmu_idx, retaddr); -- cgit v1.2.3 From 7f1559c644a8a44391cf10c7700a1ece4106a7f7 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 17 Nov 2007 10:24:32 +0000 Subject: Show usage and abort if an unknown option is passed to configure (Carlo Marcelo Arenas Belon). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3666 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index 7a74c6013..205eee8ca 100755 --- a/configure +++ b/configure @@ -316,6 +316,8 @@ for opt do ;; --disable-werror) werror="no" ;; + *) echo "ERROR: unknown option $opt"; show_help="yes" + ;; esac done -- cgit v1.2.3 From 05ee37ebf630fa970feb362671a5aee22bcb529f Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 17 Nov 2007 11:50:55 +0000 Subject: Gumstix 'connex' board support by Thorsten Zitterell. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3667 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 1 + hw/gumstix.c | 73 +++++++ hw/pflash_cfi01.c | 606 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 4 +- vl.h | 3 + 5 files changed, 686 insertions(+), 1 deletion(-) create mode 100644 hw/gumstix.c create mode 100644 hw/pflash_cfi01.c diff --git a/Makefile.target b/Makefile.target index 18938e879..6100aa092 100644 --- a/Makefile.target +++ b/Makefile.target @@ -499,6 +499,7 @@ VL_OBJS+= ssd0323.o pl061.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o +VL_OBJS+= pflash_cfi01.o gumstix.o VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o wm8750.o VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o VL_OBJS+= palm.o tsc210x.o diff --git a/hw/gumstix.c b/hw/gumstix.c new file mode 100644 index 000000000..a8f8a2fab --- /dev/null +++ b/hw/gumstix.c @@ -0,0 +1,73 @@ +/* + * Gumstix Platforms + * + * Copyright (c) 2007 by Thorsten Zitterell + * + * Code based on spitz platform by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + */ + +#include "vl.h" + +static void connex_smc_irq(void *opaque, int line, int level) +{ + /* Interrupt line of NIC is connected to GPIO line 36 */ + struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; + pxa2xx_gpio_set(cpu->gpio, 36, level); +} + +/* Board init. */ +enum gumstix_model_e { connex }; + +static void gumstix_common_init(int ram_size, int vga_ram_size, + DisplayState *ds, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + const char *cpu_model, enum gumstix_model_e model) +{ + struct pxa2xx_state_s *cpu; + + uint32_t gumstix_rom = 0x02000000; + uint32_t gumstix_ram = 0x08000000; + + if (ram_size < (gumstix_ram + gumstix_rom + PXA2XX_INTERNAL_SIZE)) { + fprintf(stderr, "This platform requires %i bytes of memory\n", + gumstix_ram + gumstix_rom + PXA2XX_INTERNAL_SIZE); + exit(1); + } + + cpu = pxa255_init(gumstix_ram, ds); + + if (pflash_table[0] == NULL) { + fprintf(stderr, "A flash image must be given with the " + "'pflash' parameter\n"); + exit(1); + } + + if (!pflash_register(0x00000000, gumstix_ram + PXA2XX_INTERNAL_SIZE, + pflash_table[0], 128 * 1024, 128, 2, 0, 0, 0, 0)) { + fprintf(stderr, "qemu: Error register flash memory.\n"); + exit(1); + } + + cpu->env->regs[15] = 0x00000000; + + qemu_irq *irq = qemu_allocate_irqs(connex_smc_irq, cpu, 1); + smc91c111_init(&nd_table[0], 0x04000300, *irq); +} + +static void connex_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + gumstix_common_init(ram_size, vga_ram_size, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, connex); +} + +QEMUMachine connex_machine = { + "connex", + "Gumstix Connex (PXA255)", + connex_init, +}; diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c new file mode 100644 index 000000000..22bf025ff --- /dev/null +++ b/hw/pflash_cfi01.c @@ -0,0 +1,606 @@ +/* + * CFI parallel flash with Intel command set emulation + * + * Copyright (c) 2006 Thorsten Zitterell + * Copyright (c) 2005 Jocelyn Mayer + * + * 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 + */ + +/* + * For now, this code can emulate flashes of 1, 2 or 4 bytes width. + * Supported commands/modes are: + * - flash read + * - flash write + * - flash ID read + * - sector erase + * - CFI queries + * + * It does not support timings + * It does not support flash interleaving + * It does not implement software data protection as found in many real chips + * It does not implement erase suspend/resume commands + * It does not implement multiple sectors erase + * + * It does not implement much more ... + */ + +#include "vl.h" + +#define PFLASH_BUG(fmt, args...) \ +do { \ + printf("PFLASH: Possible BUG - " fmt, ##args); \ + exit(1); \ +} while(0) + +/* #define PFLASH_DEBUG */ +#ifdef PFLASH_DEBUG +#define DPRINTF(fmt, args...) \ +do { \ + printf("PFLASH: " fmt , ##args); \ +} while (0) +#else +#define DPRINTF(fmt, args...) do { } while (0) +#endif + +struct pflash_t { + BlockDriverState *bs; + target_ulong base; + target_ulong sector_len; + target_ulong total_len; + int width; + int wcycle; /* if 0, the flash is read normally */ + int bypass; + int ro; + uint8_t cmd; + uint8_t status; + uint16_t ident[4]; + uint8_t cfi_len; + uint8_t cfi_table[0x52]; + target_ulong counter; + QEMUTimer *timer; + ram_addr_t off; + int fl_mem; + void *storage; +}; + +static void pflash_timer (void *opaque) +{ + pflash_t *pfl = opaque; + + DPRINTF("%s: command %02x done\n", __func__, pfl->cmd); + /* Reset flash */ + pfl->status ^= 0x80; + if (pfl->bypass) { + pfl->wcycle = 2; + } else { + cpu_register_physical_memory(pfl->base, pfl->total_len, + pfl->off | IO_MEM_ROMD | pfl->fl_mem); + pfl->wcycle = 0; + } + pfl->cmd = 0; +} + +static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width) +{ + target_ulong boff; + uint32_t ret; + uint8_t *p; + + ret = -1; + offset -= pfl->base; + boff = offset & 0xFF; /* why this here ?? */ + + if (pfl->width == 2) + boff = boff >> 1; + else if (pfl->width == 4) + boff = boff >> 2; + + DPRINTF("%s: reading offset %08x under cmd %02x\n", + __func__, boff, pfl->cmd); + + switch (pfl->cmd) { + case 0x00: + /* Flash area read */ + p = pfl->storage; + switch (width) { + case 1: + ret = p[offset]; + DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret); + break; + case 2: +#if defined(TARGET_WORDS_BIGENDIAN) + ret = p[offset] << 8; + ret |= p[offset + 1]; +#else + ret = p[offset]; + ret |= p[offset + 1] << 8; +#endif + DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret); + break; + case 4: +#if defined(TARGET_WORDS_BIGENDIAN) + ret = p[offset] << 24; + ret |= p[offset + 1] << 16; + ret |= p[offset + 2] << 8; + ret |= p[offset + 3]; +#else + ret = p[offset]; + ret |= p[offset + 1] << 8; + ret |= p[offset + 1] << 8; + ret |= p[offset + 2] << 16; + ret |= p[offset + 3] << 24; +#endif + DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret); + break; + default: + DPRINTF("BUG in %s\n", __func__); + } + + break; + case 0x20: /* Block erase */ + case 0x50: /* Clear status register */ + case 0x60: /* Block /un)lock */ + case 0x70: /* Status Register */ + case 0xe8: /* Write block */ + /* Status register read */ + ret = pfl->status; + DPRINTF("%s: status %x\n", __func__, ret); + break; + case 0x98: /* Query mode */ + if (boff > pfl->cfi_len) + ret = 0; + else + ret = pfl->cfi_table[boff]; + break; + default: + /* This should never happen : reset state & treat it as a read */ + DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); + pfl->wcycle = 0; + pfl->cmd = 0; + } + return ret; +} + +/* update flash content on disk */ +static void pflash_update(pflash_t *pfl, int offset, + int size) +{ + int offset_end; + if (pfl->bs) { + offset_end = offset + size; + /* round to sectors */ + offset = offset >> 9; + offset_end = (offset_end + 511) >> 9; + bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), + offset_end - offset); + } +} + +static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, + int width) +{ + target_ulong boff; + uint8_t *p; + uint8_t cmd; + + /* WARNING: when the memory area is in ROMD mode, the offset is a + ram offset, not a physical address */ + cmd = value; + + if (pfl->wcycle == 0) + offset -= (target_ulong)(long)pfl->storage; + else + offset -= pfl->base; + + DPRINTF("%s: offset %08x %08x %d wcycle 0x%x\n", + __func__, offset, value, width, pfl->wcycle); + + /* Set the device in I/O access mode */ + cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem); + boff = offset & (pfl->sector_len - 1); + + if (pfl->width == 2) + boff = boff >> 1; + else if (pfl->width == 4) + boff = boff >> 2; + + switch (pfl->wcycle) { + case 0: + /* read mode */ + switch (cmd) { + case 0x00: /* ??? */ + goto reset_flash; + case 0x20: /* Block erase */ + p = pfl->storage; + offset &= ~(pfl->sector_len - 1); + + DPRINTF("%s: block erase at 0x%x bytes 0x%x\n", __func__, + offset, pfl->sector_len); + + memset(p + offset, 0xff, pfl->sector_len); + pflash_update(pfl, offset, pfl->sector_len); + pfl->status |= 0x80; /* Ready! */ + break; + case 0x50: /* Clear status bits */ + DPRINTF("%s: Clear status bits\n", __func__); + pfl->status = 0x0; + goto reset_flash; + case 0x60: /* Block (un)lock */ + DPRINTF("%s: Block unlock\n", __func__); + break; + case 0x70: /* Status Register */ + DPRINTF("%s: Read status register\n", __func__); + pfl->cmd = cmd; + return; + case 0x98: /* CFI query */ + DPRINTF("%s: CFI query\n", __func__); + break; + case 0xe8: /* Write to buffer */ + DPRINTF("%s: Write to buffer\n", __func__); + pfl->status |= 0x80; /* Ready! */ + break; + case 0xff: /* Read array mode */ + DPRINTF("%s: Read array mode\n", __func__); + goto reset_flash; + default: + goto error_flash; + } + pfl->wcycle++; + pfl->cmd = cmd; + return; + case 1: + switch (pfl->cmd) { + case 0x20: /* Block erase */ + case 0x28: + if (cmd == 0xd0) { /* confirm */ + pfl->wcycle = 1; + pfl->status |= 0x80; + } if (cmd == 0xff) { /* read array mode */ + goto reset_flash; + } else + goto error_flash; + + break; + case 0xe8: + DPRINTF("%s: block write of 0x%x bytes\n", __func__, cmd); + pfl->counter = cmd; + pfl->wcycle++; + break; + case 0x60: + if (cmd == 0xd0) { + pfl->wcycle = 0; + pfl->status |= 0x80; + } else if (cmd == 0x01) { + pfl->wcycle = 0; + pfl->status |= 0x80; + } else if (cmd == 0xff) { + goto reset_flash; + } else { + DPRINTF("%s: Unknown (un)locking command\n", __func__); + goto reset_flash; + } + break; + case 0x98: + if (cmd == 0xff) { + goto reset_flash; + } else { + DPRINTF("%s: leaving query mode\n", __func__); + } + break; + default: + goto error_flash; + } + return; + case 2: + switch (pfl->cmd) { + case 0xe8: /* Block write */ + p = pfl->storage; + DPRINTF("%s: block write offset 0x%x value 0x%x counter 0x%x\n", + __func__, offset, value, pfl->counter); + switch (width) { + case 1: + p[offset] = value; + pflash_update(pfl, offset, 1); + break; + case 2: +#if defined(TARGET_WORDS_BIGENDIAN) + p[offset] = value >> 8; + p[offset + 1] = value; +#else + p[offset] = value; + p[offset + 1] = value >> 8; +#endif + pflash_update(pfl, offset, 2); + break; + case 4: +#if defined(TARGET_WORDS_BIGENDIAN) + p[offset] = value >> 24; + p[offset + 1] = value >> 16; + p[offset + 2] = value >> 8; + p[offset + 3] = value; +#else + p[offset] = value; + p[offset + 1] = value >> 8; + p[offset + 2] = value >> 16; + p[offset + 3] = value >> 24; +#endif + pflash_update(pfl, offset, 4); + break; + } + + pfl->status |= 0x80; + + if (!pfl->counter) { + DPRINTF("%s: block write finished\n", __func__); + pfl->wcycle++; + } + + pfl->counter--; + break; + } + return; + case 3: /* Confirm mode */ + switch (pfl->cmd) { + case 0xe8: /* Block write */ + if (cmd == 0xd0) { + pfl->wcycle = 0; + pfl->status |= 0x80; + break; + } else { + DPRINTF("%s: unknown command for \"write block\"\n", __func__); + PFLASH_BUG("Write block confirm"); + } + } + return; + default: + /* Should never happen */ + DPRINTF("%s: invalid write state\n", __func__); + goto reset_flash; + } + return; + + error_flash: + printf("%s: Unimplemented flash cmd sequence " + "(offset 0x%x, wcycle 0x%x cmd 0x%x value 0x%x\n", + __func__, offset, pfl->wcycle, pfl->cmd, value); + + reset_flash: + cpu_register_physical_memory(pfl->base, pfl->total_len, + pfl->off | IO_MEM_ROMD | pfl->fl_mem); + + pfl->bypass = 0; + pfl->wcycle = 0; + pfl->cmd = 0; + return; +} + + +static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr) +{ + return pflash_read(opaque, addr, 1); +} + +static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr) +{ + pflash_t *pfl = opaque; + + return pflash_read(pfl, addr, 2); +} + +static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr) +{ + pflash_t *pfl = opaque; + + return pflash_read(pfl, addr, 4); +} + +static void pflash_writeb (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_write(opaque, addr, value, 1); +} + +static void pflash_writew (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_t *pfl = opaque; + + pflash_write(pfl, addr, value, 2); +} + +static void pflash_writel (void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + pflash_t *pfl = opaque; + + pflash_write(pfl, addr, value, 4); +} + +static CPUWriteMemoryFunc *pflash_write_ops[] = { + &pflash_writeb, + &pflash_writew, + &pflash_writel, +}; + +static CPUReadMemoryFunc *pflash_read_ops[] = { + &pflash_readb, + &pflash_readw, + &pflash_readl, +}; + +/* Count trailing zeroes of a 32 bits quantity */ +static int ctz32 (uint32_t n) +{ + int ret; + + ret = 0; + if (!(n & 0xFFFF)) { + ret += 16; + n = n >> 16; + } + if (!(n & 0xFF)) { + ret += 8; + n = n >> 8; + } + if (!(n & 0xF)) { + ret += 4; + n = n >> 4; + } + if (!(n & 0x3)) { + ret += 2; + n = n >> 2; + } + if (!(n & 0x1)) { + ret++; + n = n >> 1; + } +#if 0 /* This is not necessary as n is never 0 */ + if (!n) + ret++; +#endif + + return ret; +} + +pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, + BlockDriverState *bs, + target_ulong sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3) +{ + pflash_t *pfl; + target_long total_len; + + total_len = sector_len * nb_blocs; + + /* XXX: to be fixed */ + if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && + total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024)) + return NULL; + + pfl = qemu_mallocz(sizeof(pflash_t)); + + if (pfl == NULL) + return NULL; + pfl->storage = phys_ram_base + off; + pfl->fl_mem = cpu_register_io_memory(0, + pflash_read_ops, pflash_write_ops, pfl); + pfl->off = off; + cpu_register_physical_memory(base, total_len, + off | pfl->fl_mem | IO_MEM_ROMD); + + pfl->bs = bs; + if (pfl->bs) { + /* read the initial flash content */ + bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9); + } +#if 0 /* XXX: there should be a bit to set up read-only, + * the same way the hardware does (with WP pin). + */ + pfl->ro = 1; +#else + pfl->ro = 0; +#endif + pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl); + pfl->base = base; + pfl->sector_len = sector_len; + pfl->total_len = total_len; + pfl->width = width; + pfl->wcycle = 0; + pfl->cmd = 0; + pfl->status = 0; + pfl->ident[0] = id0; + pfl->ident[1] = id1; + pfl->ident[2] = id2; + pfl->ident[3] = id3; + /* Hardcoded CFI table */ + pfl->cfi_len = 0x52; + /* Standard "QRY" string */ + pfl->cfi_table[0x10] = 'Q'; + pfl->cfi_table[0x11] = 'R'; + pfl->cfi_table[0x12] = 'Y'; + /* Command set (Intel) */ + pfl->cfi_table[0x13] = 0x01; + pfl->cfi_table[0x14] = 0x00; + /* Primary extended table address (none) */ + pfl->cfi_table[0x15] = 0x31; + pfl->cfi_table[0x16] = 0x00; + /* Alternate command set (none) */ + pfl->cfi_table[0x17] = 0x00; + pfl->cfi_table[0x18] = 0x00; + /* Alternate extended table (none) */ + pfl->cfi_table[0x19] = 0x00; + pfl->cfi_table[0x1A] = 0x00; + /* Vcc min */ + pfl->cfi_table[0x1B] = 0x45; + /* Vcc max */ + pfl->cfi_table[0x1C] = 0x55; + /* Vpp min (no Vpp pin) */ + pfl->cfi_table[0x1D] = 0x00; + /* Vpp max (no Vpp pin) */ + pfl->cfi_table[0x1E] = 0x00; + /* Reserved */ + pfl->cfi_table[0x1F] = 0x07; + /* Timeout for min size buffer write */ + pfl->cfi_table[0x20] = 0x07; + /* Typical timeout for block erase */ + pfl->cfi_table[0x21] = 0x0a; + /* Typical timeout for full chip erase (4096 ms) */ + pfl->cfi_table[0x22] = 0x00; + /* Reserved */ + pfl->cfi_table[0x23] = 0x04; + /* Max timeout for buffer write */ + pfl->cfi_table[0x24] = 0x04; + /* Max timeout for block erase */ + pfl->cfi_table[0x25] = 0x04; + /* Max timeout for chip erase */ + pfl->cfi_table[0x26] = 0x00; + /* Device size */ + pfl->cfi_table[0x27] = ctz32(total_len); // + 1; + /* Flash device interface (8 & 16 bits) */ + pfl->cfi_table[0x28] = 0x02; + pfl->cfi_table[0x29] = 0x00; + /* Max number of bytes in multi-bytes write */ + pfl->cfi_table[0x2A] = 0x04; + pfl->cfi_table[0x2B] = 0x00; + /* Number of erase block regions (uniform) */ + pfl->cfi_table[0x2C] = 0x01; + /* Erase block region 1 */ + pfl->cfi_table[0x2D] = nb_blocs - 1; + pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8; + pfl->cfi_table[0x2F] = sector_len >> 8; + pfl->cfi_table[0x30] = sector_len >> 16; + + /* Extended */ + pfl->cfi_table[0x31] = 'P'; + pfl->cfi_table[0x32] = 'R'; + pfl->cfi_table[0x33] = 'I'; + + pfl->cfi_table[0x34] = '1'; + pfl->cfi_table[0x35] = '1'; + + pfl->cfi_table[0x36] = 0x00; + pfl->cfi_table[0x37] = 0x00; + pfl->cfi_table[0x38] = 0x00; + pfl->cfi_table[0x39] = 0x00; + + pfl->cfi_table[0x3a] = 0x00; + + pfl->cfi_table[0x3b] = 0x00; + pfl->cfi_table[0x3c] = 0x00; + + return pfl; +} diff --git a/vl.c b/vl.c index 166bacf31..8defc30ee 100644 --- a/vl.c +++ b/vl.c @@ -7435,6 +7435,7 @@ void register_machines(void) qemu_register_machine(&palmte_machine); qemu_register_machine(&lm3s811evb_machine); qemu_register_machine(&lm3s6965evb_machine); + qemu_register_machine(&connex_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); qemu_register_machine(&r2d_machine); @@ -8260,7 +8261,8 @@ int main(int argc, char **argv) if (!linux_boot && net_boot == 0 && hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && - fd_filename[0] == '\0') + fd_filename[0] == '\0' && + pflash_filename[0] == '\0') help(1); /* boot to floppy or the default cd if no hard disk defined yet */ diff --git a/vl.h b/vl.h index affffad93..752bccd74 100644 --- a/vl.h +++ b/vl.h @@ -1254,6 +1254,9 @@ extern QEMUMachine spitzpda_machine; extern QEMUMachine borzoipda_machine; extern QEMUMachine terrierpda_machine; +/* gumstix.c */ +extern QEMUMachine connex_machine; + /* palm.c */ extern QEMUMachine palmte_machine; -- cgit v1.2.3 From f610349f36a78231a843ab57499b23ed9ea5ce1e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 12:01:45 +0000 Subject: Fix collision in PowerPC instructions definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3668 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 072eb914b..f758df7af 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -441,29 +441,29 @@ enum { #define PPC_MISC PPC_INSNS_BASE /* Deprecated instruction sets */ /* Original POWER instruction set */ - PPC_POWER = 0x0000000000000001ULL, + PPC_POWER = 0x0000000000000002ULL, /* POWER2 instruction set extension */ - PPC_POWER2 = 0x0000000000000002ULL, + PPC_POWER2 = 0x0000000000000004ULL, /* Power RTC support */ - PPC_POWER_RTC = 0x0000000000000004ULL, + PPC_POWER_RTC = 0x0000000000000008ULL, /* Power-to-PowerPC bridge (601) */ - PPC_POWER_BR = 0x0000000000000008ULL, + PPC_POWER_BR = 0x0000000000000010ULL, /* 64 bits PowerPC instruction set */ - PPC_64B = 0x0000000000000010ULL, + PPC_64B = 0x0000000000000020ULL, /* New 64 bits extensions (PowerPC 2.0x) */ - PPC_64BX = 0x0000000000000020ULL, + PPC_64BX = 0x0000000000000040ULL, /* 64 bits hypervisor extensions */ - PPC_64H = 0x0000000000000040ULL, + PPC_64H = 0x0000000000000080ULL, /* New wait instruction (PowerPC 2.0x) */ - PPC_WAIT = 0x0000000000000080ULL, + PPC_WAIT = 0x0000000000000100ULL, /* Time base mftb instruction */ - PPC_MFTB = 0x0000000000000100ULL, + PPC_MFTB = 0x0000000000000200ULL, /* Fixed-point unit extensions */ /* PowerPC 602 specific */ - PPC_602_SPEC = 0x0000000000000200ULL, + PPC_602_SPEC = 0x0000000000000400ULL, /* PowerPC 2.03 specification extensions */ - PPC_203 = 0x0000000000000400ULL, + PPC_203 = 0x0000000000000800ULL, /* Floating-point unit extensions */ /* Optional floating point instructions */ -- cgit v1.2.3 From 6c41b2723f5cac6e62e68925e7a73f30b11a7a06 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 17 Nov 2007 12:12:29 +0000 Subject: Don't compare '\0' against pointers. Add a note from Fabrice in slow_st template. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3669 c046a42c-6fe2-441c-8c8c-71466251a162 --- softmmu_template.h | 2 ++ vl.c | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/softmmu_template.h b/softmmu_template.h index a0a2c38ab..45fcd4e1b 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -282,6 +282,8 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* XXX: not efficient, but simple */ + /* Note: relies on the fact that tlb_fill() does not remove the + * previous page from the TLB cache. */ for(i = DATA_SIZE - 1; i >= 0; i--) { #ifdef TARGET_WORDS_BIGENDIAN glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), diff --git a/vl.c b/vl.c index 8defc30ee..b9c97b035 100644 --- a/vl.c +++ b/vl.c @@ -8256,20 +8256,20 @@ int main(int argc, char **argv) #endif linux_boot = (kernel_filename != NULL); net_boot = (boot_devices_bitmap >> ('n' - 'a')) && 0xF; - + /* XXX: this should not be: some embedded targets just have flash */ if (!linux_boot && net_boot == 0 && - hd_filename[0] == '\0' && - (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && - fd_filename[0] == '\0' && - pflash_filename[0] == '\0') + hd_filename[0] == NULL && + (cdrom_index >= 0 && hd_filename[cdrom_index] == NULL) && + fd_filename[0] == NULL && + pflash_filename[0] == NULL) help(1); /* boot to floppy or the default cd if no hard disk defined yet */ if (!boot_devices[0]) { - if (hd_filename[0] != '\0') + if (hd_filename[0] != NULL) boot_devices = "c"; - else if (fd_filename[0] != '\0') + else if (fd_filename[0] != NULL) boot_devices = "a"; else boot_devices = "d"; -- cgit v1.2.3 From 38641a52f2335c470349c55d9b1679112da99399 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 17 Nov 2007 14:07:13 +0000 Subject: Convert PXA2xx GPIOs and SCOOP GPIOs to a qemu_irq based api (similar to omap, max7310 and s3c gpios). Convert spitz and gumstix boards to use new api. Remove now obsolete gpio_handler_t definition. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3670 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gumstix.c | 12 +-- hw/pxa.h | 15 ++-- hw/pxa2xx.c | 11 ++- hw/pxa2xx_gpio.c | 41 +++++----- hw/pxa2xx_lcd.c | 13 ++-- hw/spitz.c | 231 +++++++++++++++++++++++++++---------------------------- vl.h | 3 - 7 files changed, 157 insertions(+), 169 deletions(-) diff --git a/hw/gumstix.c b/hw/gumstix.c index a8f8a2fab..235bd2e3a 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -10,13 +10,6 @@ #include "vl.h" -static void connex_smc_irq(void *opaque, int line, int level) -{ - /* Interrupt line of NIC is connected to GPIO line 36 */ - struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; - pxa2xx_gpio_set(cpu->gpio, 36, level); -} - /* Board init. */ enum gumstix_model_e { connex }; @@ -52,8 +45,9 @@ static void gumstix_common_init(int ram_size, int vga_ram_size, cpu->env->regs[15] = 0x00000000; - qemu_irq *irq = qemu_allocate_irqs(connex_smc_irq, cpu, 1); - smc91c111_init(&nd_table[0], 0x04000300, *irq); + /* Interrupt line of NIC is connected to GPIO line 36 */ + smc91c111_init(&nd_table[0], 0x04000300, + pxa2xx_gpio_in_get(cpu->gpio)[36]); } static void connex_init(int ram_size, int vga_ram_size, diff --git a/hw/pxa.h b/hw/pxa.h index 5eb6a5982..da8da5dd0 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -72,11 +72,10 @@ void pxa27x_timer_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq irq4); struct pxa2xx_gpio_info_s; struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, CPUState *env, qemu_irq *pic, int lines); -void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level); -void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line, - gpio_handler_t handler, void *opaque); -void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, - void (*handler)(void *opaque), void *opaque); +qemu_irq *pxa2xx_gpio_in_get(struct pxa2xx_gpio_info_s *s); +void pxa2xx_gpio_out_set(struct pxa2xx_gpio_info_s *s, + int line, qemu_irq handler); +void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, qemu_irq handler); /* pxa2xx_dma.c */ struct pxa2xx_dma_state_s; @@ -90,8 +89,7 @@ void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on); struct pxa2xx_lcdc_s; struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, DisplayState *ds); -void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s, - void (*cb)(void *opaque), void *opaque); +void pxa2xx_lcd_vsync_notifier(struct pxa2xx_lcdc_s *s, qemu_irq handler); void pxa2xx_lcdc_oritentation(void *opaque, int angle); /* pxa2xx_mmci.c */ @@ -126,6 +124,7 @@ struct pxa2xx_fir_s; struct pxa2xx_state_s { CPUState *env; qemu_irq *pic; + qemu_irq reset; struct pxa2xx_dma_state_s *dma; struct pxa2xx_gpio_info_s *gpio; struct pxa2xx_lcdc_s *lcd; @@ -209,6 +208,4 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, DisplayState *ds, const char *revision); struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, DisplayState *ds); -void pxa2xx_reset(int line, int level, void *opaque); - #endif /* PXA_H */ diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 62c396cd3..9f7771f2d 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2013,9 +2013,10 @@ static struct pxa2xx_fir_s *pxa2xx_fir_init(target_phys_addr_t base, return s; } -void pxa2xx_reset(int line, int level, void *opaque) +static void pxa2xx_reset(void *opaque, int line, int level) { struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque; + if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */ cpu_reset(s->env); /* TODO: reset peripherals */ @@ -2046,6 +2047,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, register_savevm("cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, s->env); + s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; + /* SDRAM & Internal Memory Storage */ cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size, qemu_ram_alloc(sdram_size) | IO_MEM_RAM); @@ -2139,7 +2142,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, /* GPIO1 resets the processor */ /* The handler can be overridden by board-specific code */ - pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s); + pxa2xx_gpio_out_set(s->gpio, 1, s->reset); return s; } @@ -2161,6 +2164,8 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, register_savevm("cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, s->env); + s->reset = qemu_allocate_irqs(pxa2xx_reset, s, 1)[0]; + /* SDRAM & Internal Memory Storage */ cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size, qemu_ram_alloc(sdram_size) | IO_MEM_RAM); @@ -2253,6 +2258,6 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, /* GPIO1 resets the processor */ /* The handler can be overridden by board-specific code */ - pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s); + pxa2xx_gpio_out_set(s->gpio, 1, s->reset); return s; } diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 723b1c1d0..b6e598a98 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -16,6 +16,7 @@ struct pxa2xx_gpio_info_s { qemu_irq *pic; int lines; CPUState *cpu_env; + qemu_irq *in; /* XXX: GNU C vectors are more suitable */ uint32_t ilevel[PXA2XX_GPIO_BANKS]; @@ -28,13 +29,8 @@ struct pxa2xx_gpio_info_s { uint32_t gafr[PXA2XX_GPIO_BANKS * 2]; uint32_t prev_level[PXA2XX_GPIO_BANKS]; - struct { - gpio_handler_t fn; - void *opaque; - } handler[PXA2XX_GPIO_BANKS * 32]; - - void (*read_notify)(void *opaque); - void *opaque; + qemu_irq handler[PXA2XX_GPIO_BANKS * 32]; + qemu_irq read_notify; }; static struct { @@ -86,12 +82,13 @@ static void pxa2xx_gpio_irq_update(struct pxa2xx_gpio_info_s *s) } /* Bitmap of pins used as standby and sleep wake-up sources. */ -const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { +static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f, }; -void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level) +static void pxa2xx_gpio_set(void *opaque, int line, int level) { + struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque; int bank; uint32_t mask; @@ -130,9 +127,7 @@ static void pxa2xx_gpio_handler_update(struct pxa2xx_gpio_info_s *s) { for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) { bit = ffs(diff) - 1; line = bit + 32 * i; - if (s->handler[line].fn) - s->handler[line].fn(line, (level >> bit) & 1, - s->handler[line].opaque); + qemu_set_irq(s->handler[line], (level >> bit) & 1); } s->prev_level[i] = level; @@ -173,8 +168,7 @@ static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset) case GPLR: /* GPIO Pin-Level registers */ ret = (s->olevel[bank] & s->dir[bank]) | (s->ilevel[bank] & ~s->dir[bank]); - if (s->read_notify) - s->read_notify(s->opaque); + qemu_irq_raise(s->read_notify); return ret; case GEDR: /* GPIO Edge Detect Status registers */ @@ -312,6 +306,7 @@ struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, s->pic = pic; s->lines = lines; s->cpu_env = env; + s->in = qemu_allocate_irqs(pxa2xx_gpio_set, s, lines); iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn, pxa2xx_gpio_writefn, s); @@ -323,23 +318,27 @@ struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base, return s; } -void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line, - gpio_handler_t handler, void *opaque) { +qemu_irq *pxa2xx_gpio_in_get(struct pxa2xx_gpio_info_s *s) +{ + return s->in; +} + +void pxa2xx_gpio_out_set(struct pxa2xx_gpio_info_s *s, + int line, qemu_irq handler) +{ if (line >= s->lines) { printf("%s: No GPIO pin %i\n", __FUNCTION__, line); return; } - s->handler[line].fn = handler; - s->handler[line].opaque = opaque; + s->handler[line] = handler; } /* * Registers a callback to notify on GPLR reads. This normally * shouldn't be needed but it is used for the hack on Spitz machines. */ -void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, - void (*handler)(void *opaque), void *opaque) { +void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, qemu_irq handler) +{ s->read_notify = handler; - s->opaque = opaque; } diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 2c1096389..7ae9ba633 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -62,8 +62,7 @@ struct pxa2xx_lcdc_s { uint32_t command; } dma_ch[7]; - void (*vsync_cb)(void *opaque); - void *opaque; + qemu_irq vsync_cb; int orientation; }; @@ -865,8 +864,7 @@ static void pxa2xx_update_display(void *opaque) dpy_update(s->ds, 0, miny, s->xres, maxy); pxa2xx_lcdc_int_update(s); - if (s->vsync_cb) - s->vsync_cb(s->opaque); + qemu_irq_raise(s->vsync_cb); } static void pxa2xx_invalidate_display(void *opaque) @@ -1042,8 +1040,7 @@ struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, return s; } -void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s, - void (*cb)(void *opaque), void *opaque) { - s->vsync_cb = cb; - s->opaque = opaque; +void pxa2xx_lcd_vsync_notifier(struct pxa2xx_lcdc_s *s, qemu_irq handler) +{ + s->vsync_cb = handler; } diff --git a/hw/spitz.c b/hw/spitz.c index 764b694e1..73dccc9c6 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -217,7 +217,9 @@ static const int spitz_gpiomap[5] = { static int spitz_gpio_invert[5] = { 0, 0, 0, 0, 0, }; struct spitz_keyboard_s { - struct pxa2xx_state_s *cpu; + qemu_irq sense[SPITZ_KEY_SENSE_NUM]; + qemu_irq *strobe; + qemu_irq gpiomap[5]; int keymap[0x80]; uint16_t keyrow[SPITZ_KEY_SENSE_NUM]; uint16_t strobe_state; @@ -240,28 +242,23 @@ static void spitz_keyboard_sense_update(struct spitz_keyboard_s *s) if (strobe) { sense |= 1 << i; if (!(s->sense_state & (1 << i))) - pxa2xx_gpio_set(s->cpu->gpio, spitz_gpio_key_sense[i], 1); + qemu_irq_raise(s->sense[i]); } else if (s->sense_state & (1 << i)) - pxa2xx_gpio_set(s->cpu->gpio, spitz_gpio_key_sense[i], 0); + qemu_irq_lower(s->sense[i]); } s->sense_state = sense; } -static void spitz_keyboard_strobe(int line, int level, - struct spitz_keyboard_s *s) +static void spitz_keyboard_strobe(void *opaque, int line, int level) { - int i; - for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++) - if (spitz_gpio_key_strobe[i] == line) { - if (level) - s->strobe_state |= 1 << i; - else - s->strobe_state &= ~(1 << i); - - spitz_keyboard_sense_update(s); - break; - } + struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque; + + if (level) + s->strobe_state |= 1 << line; + else + s->strobe_state &= ~(1 << line); + spitz_keyboard_sense_update(s); } static void spitz_keyboard_keydown(struct spitz_keyboard_s *s, int keycode) @@ -272,8 +269,7 @@ static void spitz_keyboard_keydown(struct spitz_keyboard_s *s, int keycode) /* Handle the additional keys */ if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) { - pxa2xx_gpio_set(s->cpu->gpio, spitz_gpiomap[spitz_keycode & 0xf], - (keycode < 0x80) ^ + qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80) ^ spitz_gpio_invert[spitz_keycode & 0xf]); return; } @@ -486,7 +482,6 @@ static void spitz_keyboard_register(struct pxa2xx_state_s *cpu) s = (struct spitz_keyboard_s *) qemu_mallocz(sizeof(struct spitz_keyboard_s)); memset(s, 0, sizeof(struct spitz_keyboard_s)); - s->cpu = cpu; for (i = 0; i < 0x80; i ++) s->keymap[i] = -1; @@ -495,9 +490,16 @@ static void spitz_keyboard_register(struct pxa2xx_state_s *cpu) if (spitz_keymap[i][j] != -1) s->keymap[spitz_keymap[i][j]] = (i << 4) | j; + for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) + s->sense[i] = pxa2xx_gpio_in_get(cpu->gpio)[spitz_gpio_key_sense[i]]; + + for (i = 0; i < 5; i ++) + s->gpiomap[i] = pxa2xx_gpio_in_get(cpu->gpio)[spitz_gpiomap[i]]; + + s->strobe = qemu_allocate_irqs(spitz_keyboard_strobe, s, + SPITZ_KEY_STROBE_NUM); for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++) - pxa2xx_gpio_handler_set(cpu->gpio, spitz_gpio_key_strobe[i], - (gpio_handler_t) spitz_keyboard_strobe, s); + pxa2xx_gpio_out_set(cpu->gpio, spitz_gpio_key_strobe[i], s->strobe[i]); spitz_keyboard_pre_map(s); qemu_add_kbd_event_handler((QEMUPutKBDEvent *) spitz_keyboard_handler, s); @@ -510,15 +512,13 @@ static void spitz_keyboard_register(struct pxa2xx_state_s *cpu) struct scoop_info_s { target_phys_addr_t target_base; + qemu_irq handler[16]; + qemu_irq *in; uint16_t status; uint16_t power; uint32_t gpio_level; uint32_t gpio_dir; uint32_t prev_level; - struct { - gpio_handler_t fn; - void *opaque; - } handler[16]; uint16_t mcr; uint16_t cdr; @@ -548,9 +548,7 @@ static inline void scoop_gpio_handler_update(struct scoop_info_s *s) { for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { bit = ffs(diff) - 1; - if (s->handler[bit].fn) - s->handler[bit].fn(bit, (level >> bit) & 1, - s->handler[bit].opaque); + qemu_set_irq(s->handler[bit], (level >> bit) & 1); } s->prev_level = level; @@ -648,12 +646,9 @@ CPUWriteMemoryFunc *scoop_writefn[] = { scoop_writeb, }; -static inline void scoop_gpio_set(struct scoop_info_s *s, int line, int level) +static void scoop_gpio_set(void *opaque, int line, int level) { - if (line >= 16) { - spitz_printf("No GPIO pin %i\n", line); - return; - } + struct scoop_info_s *s = (struct scoop_info_s *) s; if (level) s->gpio_level |= (1 << line); @@ -661,15 +656,19 @@ static inline void scoop_gpio_set(struct scoop_info_s *s, int line, int level) s->gpio_level &= ~(1 << line); } -static inline void scoop_gpio_handler_set(struct scoop_info_s *s, int line, - gpio_handler_t handler, void *opaque) { +static inline qemu_irq *scoop_gpio_in_get(struct scoop_info_s *s) +{ + return s->in; +} + +static inline void scoop_gpio_out_set(struct scoop_info_s *s, int line, + qemu_irq handler) { if (line >= 16) { spitz_printf("No GPIO pin %i\n", line); return; } - s->handler[line].fn = handler; - s->handler[line].opaque = opaque; + s->handler[line] = handler; } static void scoop_save(QEMUFile *f, void *opaque) @@ -723,6 +722,7 @@ static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, s[0].status = 0x02; s[1].status = 0x02; + s[0].in = qemu_allocate_irqs(scoop_gpio_set, &s[0], 16); iomemtype = cpu_register_io_memory(0, scoop_readfn, scoop_writefn, &s[0]); cpu_register_physical_memory(s[0].target_base, 0x1000, iomemtype); @@ -731,6 +731,7 @@ static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu, if (count < 2) return s; + s[1].in = qemu_allocate_irqs(scoop_gpio_set, &s[1], 16); iomemtype = cpu_register_io_memory(0, scoop_readfn, scoop_writefn, &s[1]); cpu_register_physical_memory(s[1].target_base, 0x1000, iomemtype); @@ -760,7 +761,7 @@ static void spitz_bl_update(struct pxa2xx_state_s *s) spitz_printf("LCD Backlight now off\n"); } -static void spitz_bl_bit5(int line, int level, void *opaque) +static inline void spitz_bl_bit5(void *opaque, int line, int level) { int prev = bl_intensity; @@ -773,7 +774,7 @@ static void spitz_bl_bit5(int line, int level, void *opaque) spitz_bl_update((struct pxa2xx_state_s *) opaque); } -static void spitz_bl_power(int line, int level, void *opaque) +static inline void spitz_bl_power(void *opaque, int line, int level) { bl_power = !!level; spitz_bl_update((struct pxa2xx_state_s *) opaque); @@ -841,14 +842,19 @@ static void corgi_ssp_write(void *opaque, uint32_t value) max111x_write(max1111, value); } -static void corgi_ssp_gpio_cs(int line, int level, struct pxa2xx_state_s *s) +static void corgi_ssp_gpio_cs(void *opaque, int line, int level) { - if (line == SPITZ_GPIO_LCDCON_CS) + switch (line) { + case 0: lcd_en = !level; - else if (line == SPITZ_GPIO_ADS7846_CS) + break; + case 1: ads_en = !level; - else if (line == SPITZ_GPIO_MAX1111_CS) + break; + case 2: max_en = !level; + break; + } } #define MAX1111_BATT_VOLT 1 @@ -859,7 +865,7 @@ static void corgi_ssp_gpio_cs(int line, int level, struct pxa2xx_state_s *s) #define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */ #define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */ -static void spitz_adc_temp_on(int line, int level, void *opaque) +static void spitz_adc_temp_on(void *opaque, int line, int level) { if (!max1111) return; @@ -870,12 +876,6 @@ static void spitz_adc_temp_on(int line, int level, void *opaque) max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); } -static void spitz_pendown_set(void *opaque, int line, int level) -{ - struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; - pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_TP_INT, level); -} - static void spitz_ssp_save(QEMUFile *f, void *opaque) { qemu_put_be32(f, lcd_en); @@ -898,9 +898,11 @@ static int spitz_ssp_load(QEMUFile *f, void *opaque, int version_id) static void spitz_ssp_attach(struct pxa2xx_state_s *cpu) { + qemu_irq *chipselects; + lcd_en = ads_en = max_en = 0; - ads7846 = ads7846_init(qemu_allocate_irqs(spitz_pendown_set, cpu, 1)[0]); + ads7846 = ads7846_init(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_TP_INT]); max1111 = max1111_init(0); max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT); @@ -910,12 +912,10 @@ static void spitz_ssp_attach(struct pxa2xx_state_s *cpu) pxa2xx_ssp_attach(cpu->ssp[CORGI_SSP_PORT - 1], corgi_ssp_read, corgi_ssp_write, cpu); - pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_LCDCON_CS, - (gpio_handler_t) corgi_ssp_gpio_cs, cpu); - pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_ADS7846_CS, - (gpio_handler_t) corgi_ssp_gpio_cs, cpu); - pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_MAX1111_CS, - (gpio_handler_t) corgi_ssp_gpio_cs, cpu); + chipselects = qemu_allocate_irqs(corgi_ssp_gpio_cs, cpu, 3); + pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_LCDCON_CS, chipselects[0]); + pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_ADS7846_CS, chipselects[1]); + pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_MAX1111_CS, chipselects[2]); bl_intensity = 0x20; bl_power = 0; @@ -945,7 +945,7 @@ static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu) #define SPITZ_GPIO_WM 5 #ifdef HAS_AUDIO -static void spitz_wm8750_addr(int line, int level, void *opaque) +static void spitz_wm8750_addr(void *opaque, int line, int level) { i2c_slave *wm = (i2c_slave *) opaque; if (level) @@ -970,8 +970,9 @@ static void spitz_i2c_setup(struct pxa2xx_state_s *cpu) /* Attach a WM8750 to the bus */ wm = wm8750_init(bus, audio); - spitz_wm8750_addr(0, 0, wm); - pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_WM, spitz_wm8750_addr, wm); + spitz_wm8750_addr(wm, 0, 0); + pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_WM, + qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]); /* .. and to the sound interface. */ cpu->i2s->opaque = wm; cpu->i2s->codec_out = wm8750_dac_dat; @@ -989,24 +990,31 @@ static void spitz_akita_i2c_setup(struct pxa2xx_state_s *cpu) /* Other peripherals */ -static void spitz_charge_switch(int line, int level, void *opaque) +static void spitz_out_switch(void *opaque, int line, int level) { - spitz_printf("Charging %s.\n", level ? "off" : "on"); -} - -static void spitz_discharge_switch(int line, int level, void *opaque) -{ - spitz_printf("Discharging %s.\n", level ? "on" : "off"); -} - -static void spitz_greenled_switch(int line, int level, void *opaque) -{ - spitz_printf("Green LED %s.\n", level ? "on" : "off"); -} - -static void spitz_orangeled_switch(int line, int level, void *opaque) -{ - spitz_printf("Orange LED %s.\n", level ? "on" : "off"); + switch (line) { + case 0: + spitz_printf("Charging %s.\n", level ? "off" : "on"); + break; + case 1: + spitz_printf("Discharging %s.\n", level ? "on" : "off"); + break; + case 2: + spitz_printf("Green LED %s.\n", level ? "on" : "off"); + break; + case 3: + spitz_printf("Orange LED %s.\n", level ? "on" : "off"); + break; + case 4: + spitz_bl_bit5(opaque, line, level); + break; + case 5: + spitz_bl_power(opaque, line, level); + break; + case 6: + spitz_adc_temp_on(opaque, line, level); + break; + } } #define SPITZ_SCP_LED_GREEN 1 @@ -1027,24 +1035,19 @@ static void spitz_orangeled_switch(int line, int level, void *opaque) static void spitz_scoop_gpio_setup(struct pxa2xx_state_s *cpu, struct scoop_info_s *scp, int num) { - scoop_gpio_handler_set(&scp[0], SPITZ_SCP_CHRG_ON, - spitz_charge_switch, cpu); - scoop_gpio_handler_set(&scp[0], SPITZ_SCP_JK_B, - spitz_discharge_switch, cpu); - scoop_gpio_handler_set(&scp[0], SPITZ_SCP_LED_GREEN, - spitz_greenled_switch, cpu); - scoop_gpio_handler_set(&scp[0], SPITZ_SCP_LED_ORANGE, - spitz_orangeled_switch, cpu); + qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8); + + scoop_gpio_out_set(&scp[0], SPITZ_SCP_CHRG_ON, outsignals[0]); + scoop_gpio_out_set(&scp[0], SPITZ_SCP_JK_B, outsignals[1]); + scoop_gpio_out_set(&scp[0], SPITZ_SCP_LED_GREEN, outsignals[2]); + scoop_gpio_out_set(&scp[0], SPITZ_SCP_LED_ORANGE, outsignals[3]); if (num >= 2) { - scoop_gpio_handler_set(&scp[1], SPITZ_SCP2_BACKLIGHT_CONT, - spitz_bl_bit5, cpu); - scoop_gpio_handler_set(&scp[1], SPITZ_SCP2_BACKLIGHT_ON, - spitz_bl_power, cpu); + scoop_gpio_out_set(&scp[1], SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]); + scoop_gpio_out_set(&scp[1], SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]); } - scoop_gpio_handler_set(&scp[0], SPITZ_SCP_ADC_TEMP_ON, - spitz_adc_temp_on, cpu); + scoop_gpio_out_set(&scp[0], SPITZ_SCP_ADC_TEMP_ON, outsignals[6]); } #define SPITZ_GPIO_HSYNC 22 @@ -1057,40 +1060,30 @@ static void spitz_scoop_gpio_setup(struct pxa2xx_state_s *cpu, #define SPITZ_GPIO_CF2_IRQ 106 #define SPITZ_GPIO_CF2_CD 93 -int spitz_hsync; +static int spitz_hsync; -static void spitz_lcd_hsync_handler(void *opaque) +static void spitz_lcd_hsync_handler(void *opaque, int line, int level) { struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; - pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_HSYNC, spitz_hsync); + qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_HSYNC], spitz_hsync); spitz_hsync ^= 1; } static void spitz_mmc_coverswitch_change(void *opaque, int in) { struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; - pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SD_DETECT, in); + qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_DETECT], in); } static void spitz_mmc_writeprotect_change(void *opaque, int wp) { struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; - pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SD_WP, wp); -} - -static void spitz_pcmcia_cb(void *opaque, int line, int level) -{ - struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; - static const int gpio_map[] = { - SPITZ_GPIO_CF1_IRQ, SPITZ_GPIO_CF1_CD, - SPITZ_GPIO_CF2_IRQ, SPITZ_GPIO_CF2_CD, - }; - pxa2xx_gpio_set(cpu->gpio, gpio_map[line], level); + qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_WP], wp); } static void spitz_gpio_setup(struct pxa2xx_state_s *cpu, int slots) { - qemu_irq *pcmcia_cb; + qemu_irq lcd_hsync; /* * Bad hack: We toggle the LCD hsync GPIO on every GPIO status * read to satisfy broken guests that poll-wait for hsync. @@ -1098,25 +1091,29 @@ static void spitz_gpio_setup(struct pxa2xx_state_s *cpu, int slots) * wouldn't guarantee that a guest ever exits the loop. */ spitz_hsync = 0; - pxa2xx_gpio_read_notifier(cpu->gpio, spitz_lcd_hsync_handler, cpu); - pxa2xx_lcd_vsync_cb(cpu->lcd, spitz_lcd_hsync_handler, cpu); + lcd_hsync = qemu_allocate_irqs(spitz_lcd_hsync_handler, cpu, 1)[0]; + pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync); + pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync); /* MMC/SD host */ pxa2xx_mmci_handlers(cpu->mmc, cpu, spitz_mmc_writeprotect_change, spitz_mmc_coverswitch_change); /* Battery lock always closed */ - pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_BAT_COVER, 1); + qemu_irq_raise(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_BAT_COVER]); /* Handle reset */ - pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_ON_RESET, pxa2xx_reset, cpu); + pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset); /* PCMCIA signals: card's IRQ and Card-Detect */ - pcmcia_cb = qemu_allocate_irqs(spitz_pcmcia_cb, cpu, slots * 2); if (slots >= 1) - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], pcmcia_cb[0], pcmcia_cb[1]); + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], + pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF1_IRQ], + pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF1_CD]); if (slots >= 2) - pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], pcmcia_cb[2], pcmcia_cb[3]); + pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], + pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF2_IRQ], + pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF2_CD]); /* Initialise the screen rotation related signals */ spitz_gpio_invert[3] = 0; /* Always open */ @@ -1125,8 +1122,10 @@ static void spitz_gpio_setup(struct pxa2xx_state_s *cpu, int slots) } else { /* Portrait mode */ spitz_gpio_invert[4] = 1; } - pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SWA, spitz_gpio_invert[3]); - pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SWB, spitz_gpio_invert[4]); + qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SWA], + spitz_gpio_invert[3]); + qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SWB], + spitz_gpio_invert[4]); } /* Write the bootloader parameters memory area. */ diff --git a/vl.h b/vl.h index 752bccd74..326f92f29 100644 --- a/vl.h +++ b/vl.h @@ -1420,9 +1420,6 @@ void ecc_reset(struct ecc_state_s *s); void ecc_put(QEMUFile *f, struct ecc_state_s *s); void ecc_get(QEMUFile *f, struct ecc_state_s *s); -/* GPIO */ -typedef void (*gpio_handler_t)(int line, int level, void *opaque); - /* ads7846.c */ struct ads7846_state_s; uint32_t ads7846_read(void *opaque); -- cgit v1.2.3 From 02ce600c1e485a7da4a26166b5a75b68c6013fe1 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 17 Nov 2007 14:34:44 +0000 Subject: Convert SD cards code to use qemu_irq too. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3671 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap_mmc.c | 22 +--------------------- hw/pxa.h | 5 ++--- hw/pxa2xx_mmci.c | 7 +++---- hw/sd.c | 30 ++++++++++++------------------ hw/sd.h | 4 +--- hw/spitz.c | 17 +++-------------- 6 files changed, 22 insertions(+), 63 deletions(-) diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index 406b404db..30ba9b685 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -25,7 +25,6 @@ struct omap_mmc_s { target_phys_addr_t base; qemu_irq irq; qemu_irq *dma; - qemu_irq handler[2]; omap_clk clk; SDState *card; uint16_t last_cmd; @@ -507,22 +506,6 @@ void omap_mmc_reset(struct omap_mmc_s *host) host->transfer = 0; } -static void omap_mmc_ro_cb(void *opaque, int level) -{ - struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; - - if (s->handler[0]) - qemu_set_irq(s->handler[0], level); -} - -static void omap_mmc_cover_cb(void *opaque, int level) -{ - struct omap_mmc_s *s = (struct omap_mmc_s *) opaque; - - if (s->handler[1]) - qemu_set_irq(s->handler[1], level); -} - struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, qemu_irq irq, qemu_irq dma[], omap_clk clk) { @@ -542,13 +525,10 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, /* Instantiate the storage */ s->card = sd_init(sd_bdrv); - sd_set_cb(s->card, s, omap_mmc_ro_cb, omap_mmc_cover_cb); - return s; } void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover) { - s->handler[0] = ro; - s->handler[1] = cover; + sd_set_cb(s->card, ro, cover); } diff --git a/hw/pxa.h b/hw/pxa.h index da8da5dd0..c151de3ef 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -96,9 +96,8 @@ void pxa2xx_lcdc_oritentation(void *opaque, int angle); struct pxa2xx_mmci_s; struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, qemu_irq irq, void *dma); -void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque, - void (*readonly_cb)(void *, int), - void (*coverswitch_cb)(void *, int)); +void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, qemu_irq readonly, + qemu_irq coverswitch); /* pxa2xx_pcmcia.c */ struct pxa2xx_pcmcia_s; diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index ed548dbad..7eb7c7941 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -545,9 +545,8 @@ struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, return s; } -void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque, - void (*readonly_cb)(void *, int), - void (*coverswitch_cb)(void *, int)) +void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, qemu_irq readonly, + qemu_irq coverswitch) { - sd_set_cb(s->card, opaque, readonly_cb, coverswitch_cb); + sd_set_cb(s->card, read, coverswitch); } diff --git a/hw/sd.c b/hw/sd.c index d59c4bf56..5be75858e 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -90,9 +90,8 @@ struct SDState { uint32_t data_start; uint32_t data_offset; uint8_t data[512]; - void (*readonly_cb)(void *, int); - void (*inserted_cb)(void *, int); - void *opaque; + qemu_irq readonly_cb; + qemu_irq inserted_cb; BlockDriverState *bdrv; }; @@ -372,6 +371,8 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) sd->bdrv = bdrv; + if (s->wp_groups) + qemu_free(s->wp_groups); sd->wp_switch = bdrv_is_read_only(bdrv); sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect); memset(sd->wp_groups, 0, sizeof(int) * sect); @@ -386,12 +387,10 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) static void sd_cardchange(void *opaque) { SDState *sd = opaque; - if (sd->inserted_cb) - sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv)); + qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv)); if (bdrv_is_inserted(sd->bdrv)) { sd_reset(sd, sd->bdrv); - if (sd->readonly_cb) - sd->readonly_cb(sd->opaque, sd->wp_switch); + qemu_set_irq(s->readonly_cb, sd->wp_switch); } } @@ -401,21 +400,16 @@ SDState *sd_init(BlockDriverState *bs) sd = (SDState *) qemu_mallocz(sizeof(SDState)); sd_reset(sd, bs); + bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd); return sd; } -void sd_set_cb(SDState *sd, void *opaque, - void (*readonly_cb)(void *, int), - void (*inserted_cb)(void *, int)) +void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert) { - sd->opaque = opaque; - sd->readonly_cb = readonly_cb; - sd->inserted_cb = inserted_cb; - if (sd->readonly_cb) - sd->readonly_cb(sd->opaque, bdrv_is_read_only(sd->bdrv)); - if (sd->inserted_cb) - sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv)); - bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd); + sd->readonly_cb = readonly; + sd->inserted_cb = insert; + qemu_set_irq(readonly, bdrv_is_read_only(sd->bdrv)); + qemu_set_irq(insert, bdrv_is_inserted(sd->bdrv)); } static void sd_erase(SDState *sd) diff --git a/hw/sd.h b/hw/sd.h index ab20064fe..d0e7eceeb 100644 --- a/hw/sd.h +++ b/hw/sd.h @@ -74,9 +74,7 @@ int sd_do_command(SDState *sd, struct sd_request_s *req, uint8_t *response); void sd_write_data(SDState *sd, uint8_t value); uint8_t sd_read_data(SDState *sd); -void sd_set_cb(SDState *sd, void *opaque, - void (*readonly_cb)(void *, int), - void (*inserted_cb)(void *, int)); +void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert); int sd_data_ready(SDState *sd); #endif /* __hw_sd_h */ diff --git a/hw/spitz.c b/hw/spitz.c index 73dccc9c6..14be70c70 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1069,18 +1069,6 @@ static void spitz_lcd_hsync_handler(void *opaque, int line, int level) spitz_hsync ^= 1; } -static void spitz_mmc_coverswitch_change(void *opaque, int in) -{ - struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; - qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_DETECT], in); -} - -static void spitz_mmc_writeprotect_change(void *opaque, int wp) -{ - struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque; - qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_WP], wp); -} - static void spitz_gpio_setup(struct pxa2xx_state_s *cpu, int slots) { qemu_irq lcd_hsync; @@ -1096,8 +1084,9 @@ static void spitz_gpio_setup(struct pxa2xx_state_s *cpu, int slots) pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync); /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, cpu, spitz_mmc_writeprotect_change, - spitz_mmc_coverswitch_change); + pxa2xx_mmci_handlers(cpu->mmc, + pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_WP], + pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_DETECT]); /* Battery lock always closed */ qemu_irq_raise(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_BAT_COVER]); -- cgit v1.2.3 From 5747c0733dd7ebbaa7a719d5cb1cd22565cb0cb0 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Nov 2007 14:53:06 +0000 Subject: Fix int/float inconsistencies. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3672 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/fop_template.c | 20 ++++++++++---------- target-mips/op.c | 8 ++++---- target-mips/op_helper.c | 42 ++++++++++++++++++++---------------------- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c index 8ee052513..c5941d121 100644 --- a/target-mips/fop_template.c +++ b/target-mips/fop_template.c @@ -24,14 +24,14 @@ #define OP_WLOAD_FREG(treg, tregname, FREG) \ void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ - treg = env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX]; \ + treg = env->fpu->fpr[FREG].w[FP_ENDIAN_IDX]; \ FORCE_RET(); \ } #define OP_WSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ - env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG].w[FP_ENDIAN_IDX] = treg; \ FORCE_RET(); \ } @@ -50,10 +50,10 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ if (env->hflags & MIPS_HFLAG_F64) \ - treg = env->fpu->fpr[FREG].fd; \ + treg = env->fpu->fpr[FREG].d; \ else \ - treg = (uint64_t)(env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \ - env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \ + treg = (uint64_t)(env->fpu->fpr[FREG | 1].w[FP_ENDIAN_IDX]) << 32 | \ + env->fpu->fpr[FREG & ~1].w[FP_ENDIAN_IDX]; \ FORCE_RET(); \ } @@ -61,10 +61,10 @@ OP_WSTORE_FREG(WT2, WT2_fpr, FREG) void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ if (env->hflags & MIPS_HFLAG_F64) \ - env->fpu->fpr[FREG].fd = treg; \ + env->fpu->fpr[FREG].d = treg; \ else { \ - env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \ - env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG | 1].w[FP_ENDIAN_IDX] = treg >> 32; \ + env->fpu->fpr[FREG & ~1].w[FP_ENDIAN_IDX] = treg; \ } \ FORCE_RET(); \ } @@ -81,14 +81,14 @@ OP_DSTORE_FREG(DT2, DT2_fpr, FREG) #define OP_PSLOAD_FREG(treg, tregname, FREG) \ void glue(glue(op_load_fpr_,tregname), FREG) (void) \ { \ - treg = env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX]; \ + treg = env->fpu->fpr[FREG].w[!FP_ENDIAN_IDX]; \ FORCE_RET(); \ } #define OP_PSSTORE_FREG(treg, tregname, FREG) \ void glue(glue(op_store_fpr_,tregname), FREG) (void) \ { \ - env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \ + env->fpu->fpr[FREG].w[!FP_ENDIAN_IDX] = treg; \ FORCE_RET(); \ } diff --git a/target-mips/op.c b/target-mips/op.c index 4b3e01b4b..0ecc93081 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -2682,7 +2682,7 @@ FLOAT_OP(n ## name1 ## name2, d) \ { \ FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status); \ FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status); \ - FDT2 ^= 1ULL << 63; \ + FDT2 = float64_chs(FDT2); \ DEBUG_FPU_STATE(); \ FORCE_RET(); \ } \ @@ -2690,7 +2690,7 @@ FLOAT_OP(n ## name1 ## name2, s) \ { \ FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status); \ FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ - FST2 ^= 1 << 31; \ + FST2 = float32_chs(FST2); \ DEBUG_FPU_STATE(); \ FORCE_RET(); \ } \ @@ -2700,8 +2700,8 @@ FLOAT_OP(n ## name1 ## name2, ps) \ FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \ FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status); \ FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \ - FST2 ^= 1 << 31; \ - FSTH2 ^= 1 << 31; \ + FST2 = float32_chs(FST2); \ + FSTH2 = float32_chs(FSTH2); \ DEBUG_FPU_STATE(); \ FORCE_RET(); \ } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 31d062ad4..7d74efc45 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -626,8 +626,6 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, /* Complex FPU operations which may need stack space. */ -#define FLOAT_SIGN32 (1 << 31) -#define FLOAT_SIGN64 (1ULL << 63) #define FLOAT_ONE32 (0x3f8 << 20) #define FLOAT_ONE64 (0x3ffULL << 52) #define FLOAT_TWO32 (1 << 30) @@ -1054,7 +1052,7 @@ FLOAT_OP(name, d) \ FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status); \ update_fcr31(); \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ - FDT2 = FLOAT_QNAN64; \ + DT2 = FLOAT_QNAN64; \ } \ FLOAT_OP(name, s) \ { \ @@ -1062,7 +1060,7 @@ FLOAT_OP(name, s) \ FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status); \ update_fcr31(); \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) \ - FST2 = FLOAT_QNAN32; \ + WT2 = FLOAT_QNAN32; \ } \ FLOAT_OP(name, ps) \ { \ @@ -1071,8 +1069,8 @@ FLOAT_OP(name, ps) \ FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \ update_fcr31(); \ if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) { \ - FST2 = FLOAT_QNAN32; \ - FSTH2 = FLOAT_QNAN32; \ + WT2 = FLOAT_QNAN32; \ + WTH2 = FLOAT_QNAN32; \ } \ } FLOAT_BINOP(add) @@ -1086,14 +1084,14 @@ FLOAT_OP(recip2, d) { set_float_exception_flags(0, &env->fpu->fp_status); FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status); - FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status) ^ FLOAT_SIGN64; + FDT2 = float64_chs(float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status)); update_fcr31(); } FLOAT_OP(recip2, s) { set_float_exception_flags(0, &env->fpu->fp_status); FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; + FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status)); update_fcr31(); } FLOAT_OP(recip2, ps) @@ -1101,8 +1099,8 @@ FLOAT_OP(recip2, ps) set_float_exception_flags(0, &env->fpu->fp_status); FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status); - FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; - FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32; + FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status)); + FSTH2 = float32_chs(float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status)); update_fcr31(); } @@ -1111,7 +1109,7 @@ FLOAT_OP(rsqrt2, d) set_float_exception_flags(0, &env->fpu->fp_status); FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status); FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status); - FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status) ^ FLOAT_SIGN64; + FDT2 = float64_chs(float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status)); update_fcr31(); } FLOAT_OP(rsqrt2, s) @@ -1119,7 +1117,7 @@ FLOAT_OP(rsqrt2, s) set_float_exception_flags(0, &env->fpu->fp_status); FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status); FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status); - FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; + FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status)); update_fcr31(); } FLOAT_OP(rsqrt2, ps) @@ -1129,8 +1127,8 @@ FLOAT_OP(rsqrt2, ps) FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status); FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status); FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status); - FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; - FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32; + FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status)); + FSTH2 = float32_chs(float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status)); update_fcr31(); } @@ -1164,8 +1162,8 @@ void do_cmp_d_ ## op (long cc) \ void do_cmpabs_d_ ## op (long cc) \ { \ int c; \ - FDT0 &= ~FLOAT_SIGN64; \ - FDT1 &= ~FLOAT_SIGN64; \ + FDT0 = float64_chs(FDT0); \ + FDT1 = float64_chs(FDT1); \ c = cond; \ update_fcr31(); \ if (c) \ @@ -1222,8 +1220,8 @@ void do_cmp_s_ ## op (long cc) \ void do_cmpabs_s_ ## op (long cc) \ { \ int c; \ - FST0 &= ~FLOAT_SIGN32; \ - FST1 &= ~FLOAT_SIGN32; \ + FST0 = float32_abs(FST0); \ + FST1 = float32_abs(FST1); \ c = cond; \ update_fcr31(); \ if (c) \ @@ -1285,10 +1283,10 @@ void do_cmp_ps_ ## op (long cc) \ void do_cmpabs_ps_ ## op (long cc) \ { \ int cl, ch; \ - FST0 &= ~FLOAT_SIGN32; \ - FSTH0 &= ~FLOAT_SIGN32; \ - FST1 &= ~FLOAT_SIGN32; \ - FSTH1 &= ~FLOAT_SIGN32; \ + FST0 = float32_abs(FST0); \ + FSTH0 = float32_abs(FSTH0); \ + FST1 = float32_abs(FST1); \ + FSTH1 = float32_abs(FSTH1); \ cl = condl; \ ch = condh; \ update_fcr31(); \ -- cgit v1.2.3 From 257514ddce752fe0b4aeb4b7957bc5661eadbef8 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Nov 2007 15:32:38 +0000 Subject: sd.c build fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3673 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/sd.c b/hw/sd.c index 5be75858e..25ae9956b 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -371,8 +371,8 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) sd->bdrv = bdrv; - if (s->wp_groups) - qemu_free(s->wp_groups); + if (sd->wp_groups) + qemu_free(sd->wp_groups); sd->wp_switch = bdrv_is_read_only(bdrv); sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect); memset(sd->wp_groups, 0, sizeof(int) * sect); @@ -390,7 +390,7 @@ static void sd_cardchange(void *opaque) qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv)); if (bdrv_is_inserted(sd->bdrv)) { sd_reset(sd, sd->bdrv); - qemu_set_irq(s->readonly_cb, sd->wp_switch); + qemu_set_irq(sd->readonly_cb, sd->wp_switch); } } -- cgit v1.2.3 From 87ecb68bdf8a3e40ef885ddbb7ca1797dca40ebf Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Nov 2007 17:14:51 +0000 Subject: Break up vl.h. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3674 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 10 +- Makefile.target | 20 +- arm-semi.c | 4 +- audio/audio.c | 6 +- audio/audio.h | 1 - audio/mixeng.c | 3 +- audio/noaudio.c | 4 +- audio/ossaudio.c | 3 +- audio/sdlaudio.c | 3 +- audio/wavaudio.c | 4 +- audio/wavcapture.c | 4 +- block-raw.c | 5 +- block.c | 5 +- block.h | 1 - cocoa.m | 4 +- console.c | 4 +- console.h | 154 +++++ cpu-defs.h | 4 + gdbstub.c | 5 +- hw/acpi.c | 8 +- hw/adb.c | 4 +- hw/adlib.c | 3 +- hw/ads7846.c | 4 +- hw/an5206.c | 5 +- hw/apb_pci.c | 3 +- hw/apic.c | 4 +- hw/arm-misc.h | 33 + hw/arm_boot.c | 4 +- hw/arm_pic.c | 4 +- hw/arm_pic.h | 23 - hw/arm_sysctl.c | 5 +- hw/arm_timer.c | 5 +- hw/armv7m.c | 4 +- hw/armv7m_nvic.c | 5 +- hw/audiodev.h | 12 + hw/boards.h | 94 +++ hw/cdrom.c | 3 +- hw/cirrus_vga.c | 5 +- hw/cs4231.c | 3 +- hw/cuda.c | 4 +- hw/devices.h | 19 + hw/dma.c | 3 +- hw/ds1225y.c | 4 +- hw/dummy_m68k.c | 4 +- hw/ecc.c | 3 +- hw/eepro100.c | 4 +- hw/eeprom93xx.c | 1 + hw/eeprom93xx.h | 2 - hw/es1370.c | 5 +- hw/esp.c | 7 +- hw/etraxfs.c | 4 +- hw/etraxfs_ser.c | 2 +- hw/etraxfs_timer.c | 3 +- hw/fdc.c | 6 +- hw/fdc.h | 12 + hw/flash.h | 40 ++ hw/grackle_pci.c | 4 +- hw/gt64xxx.c | 5 +- hw/gumstix.c | 8 +- hw/heathrow_pic.c | 2 +- hw/hw.h | 99 +++ hw/i2c.c | 5 +- hw/i2c.h | 15 +- hw/i8254.c | 5 +- hw/i8259.c | 5 +- hw/ide.c | 9 +- hw/integratorcp.c | 9 +- hw/iommu.c | 3 +- hw/irq.c | 3 +- hw/irq.h | 9 +- hw/isa.h | 24 + hw/isa_mmio.c | 3 +- hw/jazz_led.c | 4 +- hw/lsi53c895a.c | 4 +- hw/m48t59.c | 7 +- hw/m48t59.h | 13 - hw/mac_dbdma.c | 2 +- hw/mac_nvram.c | 2 +- hw/macio.c | 3 +- hw/max111x.c | 3 +- hw/max7310.c | 7 +- hw/mc146818rtc.c | 6 +- hw/mcf.h | 21 + hw/mcf5206.c | 5 +- hw/mcf5208.c | 7 +- hw/mcf_fec.c | 4 +- hw/mcf_intc.c | 3 +- hw/mcf_uart.c | 4 +- hw/mips.h | 25 + hw/mips_int.c | 3 +- hw/mips_malta.c | 12 +- hw/mips_mipssim.c | 8 +- hw/mips_pica61.c | 8 +- hw/mips_r4k.c | 8 +- hw/mips_timer.c | 4 +- hw/mipsnet.c | 5 +- hw/mpcore.c | 4 +- hw/nand.c | 6 +- hw/ne2000.c | 4 +- hw/nvram.h | 41 ++ hw/omap.c | 11 +- hw/omap.h | 7 + hw/omap1_clk.c | 3 +- hw/omap_i2c.c | 4 +- hw/omap_lcdc.c | 4 +- hw/omap_mmc.c | 6 +- hw/openpic.c | 4 +- hw/palm.c | 8 +- hw/parallel.c | 5 +- hw/pc.c | 11 +- hw/pc.h | 145 +++++ hw/pci.c | 5 +- hw/pci.h | 138 +++++ hw/pckbd.c | 6 +- hw/pcmcia.h | 50 ++ hw/pcnet.c | 6 +- hw/pcspk.c | 6 +- hw/pflash_cfi01.c | 5 +- hw/pflash_cfi02.c | 5 +- hw/piix_pci.c | 5 +- hw/pl011.c | 4 +- hw/pl022.c | 3 +- hw/pl031.c | 5 +- hw/pl050.c | 4 +- hw/pl061.c | 3 +- hw/pl080.c | 3 +- hw/pl110.c | 4 +- hw/pl181.c | 3 +- hw/pl190.c | 5 +- hw/ppc.c | 6 +- hw/ppc.h | 31 + hw/ppc405_boards.c | 8 +- hw/ppc405_uc.c | 6 +- hw/ppc4xx_devs.c | 4 +- hw/ppc_chrp.c | 9 +- hw/ppc_mac.h | 54 ++ hw/ppc_oldworld.c | 10 +- hw/ppc_prep.c | 11 +- hw/prep_pci.c | 4 +- hw/primecell.h | 59 ++ hw/ps2.c | 4 +- hw/ps2.h | 10 + hw/ptimer.c | 3 +- hw/pxa.h | 6 +- hw/pxa2xx.c | 14 +- hw/pxa2xx_dma.c | 3 +- hw/pxa2xx_gpio.c | 3 +- hw/pxa2xx_lcd.c | 6 +- hw/pxa2xx_mmci.c | 7 +- hw/pxa2xx_pcmcia.c | 3 +- hw/pxa2xx_pic.c | 3 +- hw/pxa2xx_timer.c | 5 +- hw/r2d.c | 5 +- hw/realview.c | 10 +- hw/realview_gic.c | 4 +- hw/rtl8139.c | 5 +- hw/sb16.c | 6 +- hw/scsi-disk.c | 4 +- hw/scsi-disk.h | 33 + hw/sd.c | 2 + hw/sd.h | 2 - hw/serial.c | 5 +- hw/sh.h | 38 ++ hw/sh7750.c | 4 +- hw/sh7750_regnames.c | 3 +- hw/sh_intc.c | 3 +- hw/sh_serial.c | 4 +- hw/sh_timer.c | 4 +- hw/shix.c | 5 +- hw/slavio_intctl.c | 5 +- hw/slavio_misc.c | 5 +- hw/slavio_serial.c | 6 +- hw/slavio_timer.c | 4 +- hw/smbus.c | 6 +- hw/smbus.h | 2 +- hw/smbus_eeprom.c | 4 +- hw/smc91c111.c | 4 +- hw/sparc32_dma.c | 4 +- hw/sparc32_dma.h | 14 + hw/spitz.c | 14 +- hw/ssd0303.c | 4 +- hw/ssd0323.c | 4 +- hw/stellaris.c | 10 +- hw/sun4m.c | 11 +- hw/sun4m.h | 73 +++ hw/sun4u.c | 11 +- hw/tc58128.c | 4 +- hw/tcx.c | 4 +- hw/tsc210x.c | 6 +- hw/unin_pci.c | 5 +- hw/usb-hid.c | 4 +- hw/usb-hub.c | 3 +- hw/usb-msd.c | 5 +- hw/usb-ohci.c | 5 +- hw/usb-uhci.c | 5 +- hw/usb-wacom.c | 4 +- hw/usb.c | 3 +- hw/usb.h | 17 +- hw/versatile_pci.c | 4 +- hw/versatilepb.c | 10 +- hw/vga.c | 5 +- hw/vmmouse.c | 5 +- hw/vmport.c | 6 +- hw/vmware_vga.c | 4 +- hw/wm8750.c | 4 +- loader.c | 2 +- m68k-semi.c | 4 +- monitor.c | 13 +- net.h | 50 ++ osdep.c | 6 +- qemu-char.h | 74 +++ qemu-common.h | 71 +++ qemu-timer.h | 48 ++ readline.c | 3 +- sdl.c | 4 +- sysemu.h | 170 +++++ tap-win32.c | 4 +- target-sparc/helper.c | 31 + target-sparc/op_helper.c | 24 - usb-linux.c | 4 +- vl.c | 17 +- vl.h | 1538 ---------------------------------------------- vnc.c | 5 +- x_keymap.c | 3 +- 224 files changed, 2416 insertions(+), 1842 deletions(-) create mode 100644 console.h create mode 100644 hw/arm-misc.h delete mode 100644 hw/arm_pic.h create mode 100644 hw/audiodev.h create mode 100644 hw/boards.h create mode 100644 hw/devices.h create mode 100644 hw/fdc.h create mode 100644 hw/flash.h create mode 100644 hw/hw.h create mode 100644 hw/isa.h delete mode 100644 hw/m48t59.h create mode 100644 hw/mcf.h create mode 100644 hw/mips.h create mode 100644 hw/nvram.h create mode 100644 hw/pc.h create mode 100644 hw/pci.h create mode 100644 hw/pcmcia.h create mode 100644 hw/ppc.h create mode 100644 hw/primecell.h create mode 100644 hw/ps2.h create mode 100644 hw/scsi-disk.h create mode 100644 hw/sh.h create mode 100644 hw/sparc32_dma.h create mode 100644 hw/sun4m.h create mode 100644 net.h create mode 100644 qemu-char.h create mode 100644 qemu-timer.h create mode 100644 sysemu.h delete mode 100644 vl.h diff --git a/Makefile b/Makefile index e8b28770b..82e420287 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ # Makefile for QEMU. +VPATH=$(SRC_PATH):$(SRC_PATH)/hw + include config-host.mak .PHONY: all clean distclean dvi info install install-doc tar tarbin \ @@ -47,9 +49,15 @@ BLOCK_OBJS+=block-qcow2.o block-parallels.o # CPUs and machines. OBJS=$(BLOCK_OBJS) -OBJS+=readline.o console.o +OBJS+=readline.o console.o OBJS+=block.o +OBJS+=irq.o +OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o +OBJS+=ssd0303.o ssd0323.o ads7846.o +OBJS+=scsi-disk.o cdrom.o +OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o + ifdef CONFIG_WIN32 OBJS+=tap-win32.o endif diff --git a/Makefile.target b/Makefile.target index 6100aa092..e4cad8747 100644 --- a/Makefile.target +++ b/Makefile.target @@ -399,7 +399,6 @@ endif VL_OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o # XXX: suppress QEMU_TOOL tests VL_OBJS+=block-raw.o -VL_OBJS+=irq.o ifdef CONFIG_ALSA LIBS += -lasound @@ -421,14 +420,11 @@ CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS) LIBS += $(CONFIG_VNC_TLS_LIBS) endif -VL_OBJS += i2c.o smbus.o - # SCSI layer -VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o +VL_OBJS+= lsi53c895a.o # USB layer -VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o -VL_OBJS+= usb-wacom.o +VL_OBJS+= usb-ohci.o # EEPROM emulation VL_OBJS += eeprom93xx.o @@ -444,7 +440,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o 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 smbus_eeprom.o vmmouse.o vmport.o vmware_vga.o +VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif ifeq ($(TARGET_BASE_ARCH), ppc) @@ -468,7 +464,7 @@ VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o mips_mipssim.o VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o VL_OBJS+= jazz_led.o VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o -VL_OBJS+= piix_pci.o smbus_eeprom.o parallel.o cirrus_vga.o $(SOUND_HW) +VL_OBJS+= piix_pci.o parallel.o cirrus_vga.o $(SOUND_HW) VL_OBJS+= mipsnet.o CPPFLAGS += -DHAS_AUDIO endif @@ -494,13 +490,13 @@ VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o VL_OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o VL_OBJS+= versatile_pci.o sd.o ptimer.o VL_OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o -VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o ssd0303.o pl022.o -VL_OBJS+= ssd0323.o pl061.o +VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o +VL_OBJS+= pl061.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o -VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o +VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o VL_OBJS+= pflash_cfi01.o gumstix.o -VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o ecc.o wm8750.o +VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o VL_OBJS+= palm.o tsc210x.o CPPFLAGS += -DHAS_AUDIO diff --git a/arm-semi.c b/arm-semi.c index 423aaf7b5..1cf220388 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -33,7 +33,9 @@ #define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024) #else -#include "vl.h" +#include "qemu-common.h" +#include "sysemu.h" +#include "gdbstub.h" #endif #define SYS_OPEN 0x01 diff --git a/audio/audio.c b/audio/audio.c index 4248c1401..2521c6f49 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -21,7 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw/hw.h" +#include "audio.h" +#include "console.h" +#include "qemu-timer.h" +#include "sysemu.h" #define AUDIO_CAP "audio" #include "audio_int.h" diff --git a/audio/audio.h b/audio/audio.h index db1a94097..ec9eee46f 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -73,7 +73,6 @@ typedef struct CaptureState { LIST_ENTRY (CaptureState) entries; } CaptureState; -typedef struct AudioState AudioState; typedef struct SWVoiceOut SWVoiceOut; typedef struct CaptureVoiceOut CaptureVoiceOut; typedef struct SWVoiceIn SWVoiceIn; diff --git a/audio/mixeng.c b/audio/mixeng.c index 34cc1aeee..b668c524e 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -22,7 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "audio.h" #define AUDIO_CAP "mixeng" #include "audio_int.h" diff --git a/audio/noaudio.c b/audio/noaudio.c index a3423e5eb..64695e6af 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "audio.h" +#include "qemu-timer.h" #define AUDIO_CAP "noaudio" #include "audio_int.h" diff --git a/audio/ossaudio.c b/audio/ossaudio.c index cedcea45f..5a91556cc 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -30,7 +30,8 @@ #else #include #endif -#include "vl.h" +#include "qemu-common.h" +#include "audio.h" #define AUDIO_CAP "oss" #include "audio_int.h" diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c index 11edab08d..b6cfad18f 100644 --- a/audio/sdlaudio.c +++ b/audio/sdlaudio.c @@ -23,7 +23,8 @@ */ #include #include -#include "vl.h" +#include "qemu-common.h" +#include "audio.h" #ifndef _WIN32 #ifdef __sun__ diff --git a/audio/wavaudio.c b/audio/wavaudio.c index 2dbc58cbe..11ca86dda 100644 --- a/audio/wavaudio.c +++ b/audio/wavaudio.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw/hw.h" +#include "qemu-timer.h" +#include "audio.h" #define AUDIO_CAP "wav" #include "audio_int.h" diff --git a/audio/wavcapture.c b/audio/wavcapture.c index 4810fa30d..3281c3110 100644 --- a/audio/wavcapture.c +++ b/audio/wavcapture.c @@ -1,4 +1,6 @@ -#include "vl.h" +#include "hw/hw.h" +#include "console.h" +#include "audio.h" typedef struct { QEMUFile *f; diff --git a/block-raw.c b/block-raw.c index 71c39ab08..732b4b8e0 100644 --- a/block-raw.c +++ b/block-raw.c @@ -21,10 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifdef QEMU_IMG #include "qemu-common.h" -#else -#include "vl.h" +#ifndef QEMU_IMG +#include "qemu-timer.h" #include "exec-all.h" #endif #include "block_int.h" diff --git a/block.c b/block.c index 1cb943b82..b09ded319 100644 --- a/block.c +++ b/block.c @@ -21,10 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifdef QEMU_IMG #include "qemu-common.h" -#else -#include "vl.h" +#ifndef QEMU_IMG +#include "console.h" #endif #include "block_int.h" diff --git a/block.h b/block.h index 42baf11f4..27f1e5c9b 100644 --- a/block.h +++ b/block.h @@ -2,7 +2,6 @@ #define BLOCK_H /* block.c */ -typedef struct BlockDriverState BlockDriverState; typedef struct BlockDriver BlockDriver; extern BlockDriver bdrv_raw; diff --git a/cocoa.m b/cocoa.m index 84f943c5b..d26b45260 100644 --- a/cocoa.m +++ b/cocoa.m @@ -37,7 +37,9 @@ #import -#include "vl.h" +#include "qemu-common.h" +#include "console.h" +#include "sysemu.h" NSWindow *window = NULL; NSQuickDrawView *qd_view = NULL; diff --git a/console.c b/console.c index 9d3c2f627..9778845b7 100644 --- a/console.c +++ b/console.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "console.h" +#include "qemu-timer.h" //#define DEBUG_CONSOLE #define DEFAULT_BACKSCROLL 512 diff --git a/console.h b/console.h new file mode 100644 index 000000000..1ac74fad3 --- /dev/null +++ b/console.h @@ -0,0 +1,154 @@ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include "qemu-char.h" + +/* keyboard/mouse support */ + +#define MOUSE_EVENT_LBUTTON 0x01 +#define MOUSE_EVENT_RBUTTON 0x02 +#define MOUSE_EVENT_MBUTTON 0x04 + +typedef void QEMUPutKBDEvent(void *opaque, int keycode); +typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); + +typedef struct QEMUPutMouseEntry { + QEMUPutMouseEvent *qemu_put_mouse_event; + void *qemu_put_mouse_event_opaque; + int qemu_put_mouse_event_absolute; + char *qemu_put_mouse_event_name; + + /* used internally by qemu for handling mice */ + struct QEMUPutMouseEntry *next; +} QEMUPutMouseEntry; + +void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); +QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, + void *opaque, int absolute, + const char *name); +void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry); + +void kbd_put_keycode(int keycode); +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); +int kbd_mouse_is_absolute(void); + +void do_info_mice(void); +void do_mouse_set(int index); + +/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx + constants) */ +#define QEMU_KEY_ESC1(c) ((c) | 0xe100) +#define QEMU_KEY_BACKSPACE 0x007f +#define QEMU_KEY_UP QEMU_KEY_ESC1('A') +#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B') +#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C') +#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D') +#define QEMU_KEY_HOME QEMU_KEY_ESC1(1) +#define QEMU_KEY_END QEMU_KEY_ESC1(4) +#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5) +#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6) +#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3) + +#define QEMU_KEY_CTRL_UP 0xe400 +#define QEMU_KEY_CTRL_DOWN 0xe401 +#define QEMU_KEY_CTRL_LEFT 0xe402 +#define QEMU_KEY_CTRL_RIGHT 0xe403 +#define QEMU_KEY_CTRL_HOME 0xe404 +#define QEMU_KEY_CTRL_END 0xe405 +#define QEMU_KEY_CTRL_PAGEUP 0xe406 +#define QEMU_KEY_CTRL_PAGEDOWN 0xe407 + +void kbd_put_keysym(int keysym); + +/* consoles */ + +struct DisplayState { + uint8_t *data; + int linesize; + int depth; + int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ + int width; + int height; + void *opaque; + struct QEMUTimer *gui_timer; + + void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); + void (*dpy_resize)(struct DisplayState *s, int w, int h); + void (*dpy_refresh)(struct DisplayState *s); + void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, + int dst_x, int dst_y, int w, int h); + void (*dpy_fill)(struct DisplayState *s, int x, int y, + int w, int h, uint32_t c); + void (*mouse_set)(int x, int y, int on); + void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, + uint8_t *image, uint8_t *mask); +}; + +static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) +{ + s->dpy_update(s, x, y, w, h); +} + +static inline void dpy_resize(DisplayState *s, int w, int h) +{ + s->dpy_resize(s, w, h); +} + +typedef void (*vga_hw_update_ptr)(void *); +typedef void (*vga_hw_invalidate_ptr)(void *); +typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); + +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); +void vga_hw_update(void); +void vga_hw_invalidate(void); +void vga_hw_screen_dump(const char *filename); + +int is_graphic_console(void); +CharDriverState *text_console_init(DisplayState *ds, const char *p); +void console_select(unsigned int index); +void console_color_init(DisplayState *ds); + +/* sdl.c */ +void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); + +/* cocoa.m */ +void cocoa_display_init(DisplayState *ds, int full_screen); + +/* vnc.c */ +void vnc_display_init(DisplayState *ds); +void vnc_display_close(DisplayState *ds); +int vnc_display_open(DisplayState *ds, const char *display); +int vnc_display_password(DisplayState *ds, const char *password); +void do_info_vnc(void); + +/* x_keymap.c */ +extern uint8_t _translate_keycode(const int key); + +/* FIXME: term_printf et al should probably go elsewhere so everything + does not need to include console.h */ +/* monitor.c */ +void monitor_init(CharDriverState *hd, int show_banner); +void term_puts(const char *str); +void term_vprintf(const char *fmt, va_list ap); +void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +void term_print_filename(const char *filename); +void term_flush(void); +void term_print_help(void); +void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size); + +/* readline.c */ +typedef void ReadLineFunc(void *opaque, const char *str); + +extern int completion_index; +void add_completion(const char *str); +void readline_handle_byte(int ch); +void readline_find_completion(const char *cmdline); +const char *readline_get_history(unsigned int index); +void readline_start(const char *prompt, int is_password, + ReadLineFunc *readline_func, void *opaque); + +#endif diff --git a/cpu-defs.h b/cpu-defs.h index 8414aca22..139dca2e7 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -20,6 +20,10 @@ #ifndef CPU_DEFS_H #define CPU_DEFS_H +#ifndef NEED_CPU_H +#error cpu.h included from common code +#endif + #include "config.h" #include #include diff --git a/gdbstub.c b/gdbstub.c index 418b9a6fe..f877e0213 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -29,7 +29,10 @@ #include "qemu.h" #else -#include "vl.h" +#include "qemu-common.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "gdbstub.h" #endif #include "qemu_socket.h" diff --git a/hw/acpi.c b/hw/acpi.c index 6e3f69eac..5a4b1e4ee 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -16,7 +16,13 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "pci.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "i2c.h" +#include "smbus.h" //#define DEBUG diff --git a/hw/adb.c b/hw/adb.c index 1e43792b5..5c0d6d5fd 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ppc_mac.h" +#include "console.h" /* ADB commands */ #define ADB_BUSRESET 0x00 diff --git a/hw/adlib.c b/hw/adlib.c index 805365e70..af4660bbc 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -22,7 +22,8 @@ * THE SOFTWARE. */ #include -#include "vl.h" +#include "hw.h" +#include "audiodev.h" #define ADLIB_KILL_TIMERS 1 diff --git a/hw/ads7846.c b/hw/ads7846.c index c26ce2583..578bb5493 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -7,7 +7,9 @@ * This code is licensed under the GNU GPL v2. */ -#include +#include "hw.h" +#include "devices.h" +#include "console.h" struct ads7846_state_s { qemu_irq interrupt; diff --git a/hw/an5206.c b/hw/an5206.c index b5f93f671..5e12ed854 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -6,7 +6,10 @@ * This code is licenced under the GPL */ -#include "vl.h" +#include "hw.h" +#include "mcf.h" +#include "sysemu.h" +#include "boards.h" #define KERNEL_LOAD_ADDR 0x10000 #define AN5206_MBAR_ADDR 0x10000000 diff --git a/hw/apb_pci.c b/hw/apb_pci.c index fe9189247..73dcf5c13 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -26,7 +26,8 @@ Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is the secondary PCI bridge. */ -#include "vl.h" +#include "hw.h" +#include "pci.h" typedef target_phys_addr_t pci_addr_t; #include "pci_host.h" diff --git a/hw/apic.c b/hw/apic.c index 3a442bf82..78f49d199 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -17,7 +17,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "qemu-timer.h" //#define DEBUG_APIC //#define DEBUG_IOAPIC diff --git a/hw/arm-misc.h b/hw/arm-misc.h new file mode 100644 index 000000000..f8011182d --- /dev/null +++ b/hw/arm-misc.h @@ -0,0 +1,33 @@ +/* + * Misc ARM declarations + * + * Copyright (c) 2006 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the LGPL. + * + */ + +#ifndef ARM_MISC_H +#define ARM_MISC_H 1 + +/* The CPU is also modeled as an interrupt controller. */ +#define ARM_PIC_CPU_IRQ 0 +#define ARM_PIC_CPU_FIQ 1 +qemu_irq *arm_pic_init_cpu(CPUState *env); + +/* armv7m.c */ +qemu_irq *armv7m_init(int flash_size, int sram_size, + const char *kernel_filename, const char *cpu_model); + +/* arm_boot.c */ + +void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + int board_id, target_phys_addr_t loader_start); + +/* armv7m_nvic.c */ +qemu_irq *armv7m_nvic_init(CPUState *env); + +#endif /* !ARM_MISC_H */ + diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 8ef14ab4e..8335e69a7 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -7,7 +7,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "arm-misc.h" +#include "sysemu.h" #define KERNEL_ARGS_ADDR 0x100 #define KERNEL_LOAD_ADDR 0x00010000 diff --git a/hw/arm_pic.c b/hw/arm_pic.c index 7f4a694d9..1fe55b71b 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -7,8 +7,8 @@ * This code is licenced under the LGPL */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "arm-misc.h" /* Stub functions for hardware that doesn't exist. */ void pic_info(void) diff --git a/hw/arm_pic.h b/hw/arm_pic.h deleted file mode 100644 index 1eba2baab..000000000 --- a/hw/arm_pic.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Generic ARM Programmable Interrupt Controller support. - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the LGPL. - * - * Arm hardware uses a wide variety of interrupt handling hardware. - * This provides a generic framework for connecting interrupt sources and - * inputs. - */ - -#ifndef ARM_INTERRUPT_H -#define ARM_INTERRUPT_H 1 - -/* The CPU is also modeled as an interrupt controller. */ -#define ARM_PIC_CPU_IRQ 0 -#define ARM_PIC_CPU_FIQ 1 -qemu_irq *arm_pic_init_cpu(CPUState *env); - -#endif /* !ARM_INTERRUPT_H */ - diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index e3179e2a9..e1d5a56c0 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -7,8 +7,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "arm-misc.h" +#include "sysemu.h" #define LOCK_VALUE 0xa05f diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 3df386af4..417d53db8 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -7,8 +7,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "arm-misc.h" +#include "qemu-timer.h" /* Common timer implementation. */ diff --git a/hw/armv7m.c b/hw/armv7m.c index f0a90e12d..b2bad3c2e 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -7,7 +7,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "arm-misc.h" +#include "sysemu.h" /* Bitbanded IO. Each word corresponds to a single bit. */ diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index d30408288..99ea9873a 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -10,8 +10,9 @@ * NVIC. Much of that is also implemented here. */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "qemu-timer.h" +#include "arm-misc.h" #define GIC_NIRQ 64 #define NCPU 1 diff --git a/hw/audiodev.h b/hw/audiodev.h new file mode 100644 index 000000000..18cdf6708 --- /dev/null +++ b/hw/audiodev.h @@ -0,0 +1,12 @@ +/* es1370.c */ +int es1370_init (PCIBus *bus, AudioState *s); + +/* sb16.c */ +int SB16_init (AudioState *s, qemu_irq *pic); + +/* adlib.c */ +int Adlib_init (AudioState *s, qemu_irq *pic); + +/* gus.c */ +int GUS_init (AudioState *s, qemu_irq *pic); + diff --git a/hw/boards.h b/hw/boards.h new file mode 100644 index 000000000..7eee86631 --- /dev/null +++ b/hw/boards.h @@ -0,0 +1,94 @@ +/* Declarations for use by board files for creating devices. */ + +#ifndef HW_BOARDS_H +#define HW_BOARDS_H + +typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, + const char *boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model); + +typedef struct QEMUMachine { + const char *name; + const char *desc; + QEMUMachineInitFunc *init; + struct QEMUMachine *next; +} QEMUMachine; + +int qemu_register_machine(QEMUMachine *m); + +/* Axis ETRAX. */ +extern QEMUMachine bareetraxfs_machine; + +/* pc.c */ +extern QEMUMachine pc_machine; +extern QEMUMachine isapc_machine; + +/* ppc.c */ +extern QEMUMachine prep_machine; +extern QEMUMachine core99_machine; +extern QEMUMachine heathrow_machine; +extern QEMUMachine ref405ep_machine; +extern QEMUMachine taihu_machine; + +/* mips_r4k.c */ +extern QEMUMachine mips_machine; + +/* mips_malta.c */ +extern QEMUMachine mips_malta_machine; + +/* mips_pica61.c */ +extern QEMUMachine mips_pica61_machine; + +/* mips_mipssim.c */ +extern QEMUMachine mips_mipssim_machine; + +/* shix.c */ +extern QEMUMachine shix_machine; + +/* r2d.c */ +extern QEMUMachine r2d_machine; + +/* sun4m.c */ +extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine; + +/* sun4u.c */ +extern QEMUMachine sun4u_machine; + +/* integratorcp.c */ +extern QEMUMachine integratorcp_machine; + +/* versatilepb.c */ +extern QEMUMachine versatilepb_machine; +extern QEMUMachine versatileab_machine; + +/* realview.c */ +extern QEMUMachine realview_machine; + +/* spitz.c */ +extern QEMUMachine akitapda_machine; +extern QEMUMachine spitzpda_machine; +extern QEMUMachine borzoipda_machine; +extern QEMUMachine terrierpda_machine; + +/* palm.c */ +extern QEMUMachine palmte_machine; + +/* gumstix.c */ +extern QEMUMachine connex_machine; + +/* stellaris.c */ +extern QEMUMachine lm3s811evb_machine; +extern QEMUMachine lm3s6965evb_machine; + +/* an5206.c */ +extern QEMUMachine an5206_machine; + +/* mcf5208.c */ +extern QEMUMachine mcf5208evb_machine; + +/* dummy_m68k.c */ +extern QEMUMachine dummy_m68k_machine; + +#endif diff --git a/hw/cdrom.c b/hw/cdrom.c index 4f1fce18f..2aa4d3b25 100644 --- a/hw/cdrom.c +++ b/hw/cdrom.c @@ -25,7 +25,8 @@ /* ??? Most of the ATAPI emulation is still in ide.c. It should be moved here. */ -#include +#include "qemu-common.h" +#include "scsi-disk.h" static void lba_to_msf(uint8_t *buf, int lba) { diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 85bf4a21f..c35edf260 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -26,7 +26,10 @@ * Reference: Finn Thogersons' VGADOC4b * available at http://home.worldonline.dk/~finth/ */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "pci.h" +#include "console.h" #include "vga_int.h" /* diff --git a/hw/cs4231.c b/hw/cs4231.c index 982980038..11a6add75 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sun4m.h" /* debug CS4231 */ //#define DEBUG_CS diff --git a/hw/cuda.c b/hw/cuda.c index 42e357e3c..246c72d86 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -22,8 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" #include "ppc_mac.h" +#include "qemu-timer.h" +#include "sysemu.h" /* XXX: implement all timer modes */ diff --git a/hw/devices.h b/hw/devices.h new file mode 100644 index 000000000..382774565 --- /dev/null +++ b/hw/devices.h @@ -0,0 +1,19 @@ +#ifndef QEMU_DEVICES_H +#define QEMU_DEVICES_H + +/* Devices that have nowhere better to go. */ + +/* smc91c111.c */ +void smc91c111_init(NICInfo *, uint32_t, qemu_irq); + +/* ssd0323.c */ +int ssd0323_xfer_ssi(void *opaque, int data); +void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p); + +/* ads7846.c */ +struct ads7846_state_s; +uint32_t ads7846_read(void *opaque); +void ads7846_write(void *opaque, uint32_t value); +struct ads7846_state_s *ads7846_init(qemu_irq penirq); + +#endif diff --git a/hw/dma.c b/hw/dma.c index 2e8608cfc..d779e4c94 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "isa.h" /* #define DEBUG_DMA */ diff --git a/hw/ds1225y.c b/hw/ds1225y.c index 7851096fa..8de20fb93 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -22,7 +22,9 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "mips.h" +#include "nvram.h" typedef enum { diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 722554711..812162048 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -6,7 +6,9 @@ * This code is licenced under the GPL */ -#include "vl.h" +#include "hw.h" +#include "sysemu.h" +#include "boards.h" #define KERNEL_LOAD_ADDR 0x10000 diff --git a/hw/ecc.c b/hw/ecc.c index 970ede806..0e5f80c20 100644 --- a/hw/ecc.c +++ b/hw/ecc.c @@ -8,7 +8,8 @@ * This code is licensed under the GNU GPL v2. */ -#include "vl.h" +#include "hw.h" +#include "flash.h" /* * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux. diff --git a/hw/eepro100.c b/hw/eepro100.c index 975aeb172..84d1e52ac 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -40,7 +40,9 @@ #include #include /* offsetof */ -#include "vl.h" +#include "hw.h" +#include "pci.h" +#include "net.h" #include "eeprom93xx.h" /* Common declarations for all PCI devices. */ diff --git a/hw/eeprom93xx.c b/hw/eeprom93xx.c index 14f018914..896cffd44 100644 --- a/hw/eeprom93xx.c +++ b/hw/eeprom93xx.c @@ -37,6 +37,7 @@ */ #include +#include "hw.h" #include "eeprom93xx.h" /* Debug EEPROM emulation. */ diff --git a/hw/eeprom93xx.h b/hw/eeprom93xx.h index fde4912e8..4e257f6e8 100644 --- a/hw/eeprom93xx.h +++ b/hw/eeprom93xx.h @@ -21,8 +21,6 @@ #ifndef EEPROM93XX_H #define EEPROM93XX_H -#include "vl.h" - typedef struct _eeprom_t eeprom_t; /* Create a new EEPROM with (nwords * 2) bytes. */ diff --git a/hw/es1370.c b/hw/es1370.c index d607a9485..754f621a1 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -26,7 +26,10 @@ /* #define VERBOSE_ES1370 */ #define SILENT_ES1370 -#include "vl.h" +#include "hw.h" +#include "audiodev.h" +#include "audio/audio.h" +#include "pci.h" /* Missing stuff: SCTRL_P[12](END|ST)INC diff --git a/hw/esp.c b/hw/esp.c index 96c6b3493..d0a01a1a9 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -21,7 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "block.h" +#include "scsi-disk.h" +#include "sun4m.h" +/* FIXME: Only needed for MAX_DISKS, which is probably wrong. */ +#include "sysemu.h" /* debug ESP card */ //#define DEBUG_ESP diff --git a/hw/etraxfs.c b/hw/etraxfs.c index da2196834..ba4d4009e 100644 --- a/hw/etraxfs.c +++ b/hw/etraxfs.c @@ -23,7 +23,9 @@ */ #include #include -#include "vl.h" +#include "hw.h" +#include "sysemu.h" +#include "boards.h" extern FILE *logfile; diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 3ff6ff77c..bb2aeb76a 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -24,7 +24,7 @@ #include #include -#include "vl.h" +#include "hw.h" #define RW_TR_DMA_EN 0xb0026004 #define RW_DOUT 0xb002601c diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index 1c2e4035f..efa6bf9b6 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -23,7 +23,8 @@ */ #include #include -#include "vl.h" +#include "hw.h" +#include "qemu-timer.h" void etrax_ack_irq(CPUState *env, uint32_t mask); diff --git a/hw/fdc.c b/hw/fdc.c index f0033b862..ec9c2a3a9 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -25,7 +25,11 @@ * The controller is used in Sun4m systems in a slightly different * way. There are changes in DOR register and DMA is not available. */ -#include "vl.h" +#include "hw.h" +#include "fdc.h" +#include "block.h" +#include "qemu-timer.h" +#include "isa.h" /********************************************************/ /* debug Floppy devices */ diff --git a/hw/fdc.h b/hw/fdc.h new file mode 100644 index 000000000..50de25088 --- /dev/null +++ b/hw/fdc.h @@ -0,0 +1,12 @@ +/* fdc.c */ +#define MAX_FD 2 +extern BlockDriverState *fd_table[MAX_FD]; + +typedef struct fdctrl_t fdctrl_t; + +fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, + target_phys_addr_t io_base, + BlockDriverState **fds); +fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, + BlockDriverState **fds); +int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); diff --git a/hw/flash.h b/hw/flash.h new file mode 100644 index 000000000..e3c898a34 --- /dev/null +++ b/hw/flash.h @@ -0,0 +1,40 @@ +/* NOR flash devices */ +typedef struct pflash_t pflash_t; + +pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, + BlockDriverState *bs, + uint32_t sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3); + +/* nand.c */ +struct nand_flash_s; +struct nand_flash_s *nand_init(int manf_id, int chip_id); +void nand_done(struct nand_flash_s *s); +void nand_setpins(struct nand_flash_s *s, + int cle, int ale, int ce, int wp, int gnd); +void nand_getpins(struct nand_flash_s *s, int *rb); +void nand_setio(struct nand_flash_s *s, uint8_t value); +uint8_t nand_getio(struct nand_flash_s *s); + +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_NATIONAL 0x8f +#define NAND_MFR_RENESAS 0x07 +#define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_MICRON 0x2c + +/* ecc.c */ +struct ecc_state_s { + uint8_t cp; /* Column parity */ + uint16_t lp[2]; /* Line parity */ + uint16_t count; +}; + +uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample); +void ecc_reset(struct ecc_state_s *s); +void ecc_put(QEMUFile *f, struct ecc_state_s *s); +void ecc_get(QEMUFile *f, struct ecc_state_s *s); + diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index af63a4155..91d426102 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -23,8 +23,10 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" #include "ppc_mac.h" +#include "pci.h" + typedef target_phys_addr_t pci_addr_t; #include "pci_host.h" diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 65e16b2f7..07f046a92 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -22,7 +22,10 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "mips.h" +#include "pci.h" +#include "pc.h" typedef target_phys_addr_t pci_addr_t; #include "pci_host.h" diff --git a/hw/gumstix.c b/hw/gumstix.c index 235bd2e3a..0b6dd0b3f 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -8,7 +8,13 @@ * This code is licensed under the GNU GPL v2. */ -#include "vl.h" +#include "hw.h" +#include "pxa.h" +#include "net.h" +#include "flash.h" +#include "sysemu.h" +#include "devices.h" +#include "boards.h" /* Board init. */ enum gumstix_model_e { connex }; diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index 44dc97a2d..dc2a30c85 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" #include "ppc_mac.h" //#define DEBUG diff --git a/hw/hw.h b/hw/hw.h new file mode 100644 index 000000000..3589adee3 --- /dev/null +++ b/hw/hw.h @@ -0,0 +1,99 @@ +/* Declarations for use by hardware emulation. */ +#ifndef QEMU_HW_H +#define QEMU_HW_H + +#include "qemu-common.h" +#include "irq.h" + +/* VM Load/Save */ + +QEMUFile *qemu_fopen(const char *filename, const char *mode); +void qemu_fflush(QEMUFile *f); +void qemu_fclose(QEMUFile *f); +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); +void qemu_put_byte(QEMUFile *f, int v); +void qemu_put_be16(QEMUFile *f, unsigned int v); +void qemu_put_be32(QEMUFile *f, unsigned int v); +void qemu_put_be64(QEMUFile *f, uint64_t v); +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); +int qemu_get_byte(QEMUFile *f); +unsigned int qemu_get_be16(QEMUFile *f); +unsigned int qemu_get_be32(QEMUFile *f); +uint64_t qemu_get_be64(QEMUFile *f); + +static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) +{ + qemu_put_be64(f, *pv); +} + +static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv) +{ + qemu_put_be32(f, *pv); +} + +static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv) +{ + qemu_put_be16(f, *pv); +} + +static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv) +{ + qemu_put_byte(f, *pv); +} + +static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv) +{ + *pv = qemu_get_be64(f); +} + +static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv) +{ + *pv = qemu_get_be32(f); +} + +static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv) +{ + *pv = qemu_get_be16(f); +} + +static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv) +{ + *pv = qemu_get_byte(f); +} + +#ifdef NEED_CPU_H +#if TARGET_LONG_BITS == 64 +#define qemu_put_betl qemu_put_be64 +#define qemu_get_betl qemu_get_be64 +#define qemu_put_betls qemu_put_be64s +#define qemu_get_betls qemu_get_be64s +#else +#define qemu_put_betl qemu_put_be32 +#define qemu_get_betl qemu_get_be32 +#define qemu_put_betls qemu_put_be32s +#define qemu_get_betls qemu_get_be32s +#endif +#endif + +int64_t qemu_ftell(QEMUFile *f); +int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); + +typedef void SaveStateHandler(QEMUFile *f, void *opaque); +typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); + +int register_savevm(const char *idstr, + int instance_id, + int version_id, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque); + +typedef void QEMUResetHandler(void *opaque); + +void qemu_register_reset(QEMUResetHandler *func, void *opaque); + +/* These should really be in isa.h, but are here to make pc.h happy. */ +typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); +typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); + +#endif diff --git a/hw/i2c.c b/hw/i2c.c index 627bbfc4e..e590801af 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -7,7 +7,8 @@ * This code is licenced under the LGPL. */ -#include "vl.h" +#include "hw.h" +#include "i2c.h" struct i2c_bus { @@ -30,7 +31,7 @@ i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size) i2c_slave *dev; if (size < sizeof(i2c_slave)) - cpu_abort(cpu_single_env, "I2C struct too small"); + hw_error("I2C struct too small"); dev = (i2c_slave *)qemu_mallocz(size); dev->address = address; diff --git a/hw/i2c.h b/hw/i2c.h index 9330ae852..2897036ed 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -13,8 +13,6 @@ enum i2c_event { I2C_NACK /* Masker NACKed a receive byte. */ }; -typedef struct i2c_slave i2c_slave; - /* Master to slave. */ typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data); /* Slave to master. */ @@ -34,8 +32,6 @@ struct i2c_slave void *next; }; -typedef struct i2c_bus i2c_bus; - i2c_bus *i2c_init_bus(void); i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size); void i2c_set_slave_address(i2c_slave *dev, int address); @@ -50,6 +46,14 @@ void i2c_bus_load(QEMUFile *f, i2c_bus *bus); void i2c_slave_save(QEMUFile *f, i2c_slave *dev); void i2c_slave_load(QEMUFile *f, i2c_slave *dev); +/* max111x.c */ +struct max111x_s; +uint32_t max111x_read(void *opaque); +void max111x_write(void *opaque, uint32_t value); +struct max111x_s *max1110_init(qemu_irq cb); +struct max111x_s *max1111_init(qemu_irq cb); +void max111x_set_input(struct max111x_s *s, int line, uint8_t value); + /* max7310.c */ i2c_slave *max7310_init(i2c_bus *bus); void max7310_reset(i2c_slave *i2c); @@ -64,4 +68,7 @@ void wm8750_data_req_set(i2c_slave *i2c, void wm8750_dac_dat(void *opaque, uint32_t sample); uint32_t wm8750_adc_dat(void *opaque); +/* ssd0303.c */ +void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address); + #endif diff --git a/hw/i8254.c b/hw/i8254.c index 54407de4d..0c59aa3f6 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "isa.h" +#include "qemu-timer.h" //#define DEBUG_PIT diff --git a/hw/i8259.c b/hw/i8259.c index 1e256d96b..23e66a804 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "isa.h" +#include "console.h" /* debug PIC */ //#define DEBUG_PIC diff --git a/hw/ide.c b/hw/ide.c index 5f76c2767..575605b95 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -22,7 +22,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "pci.h" +#include "scsi-disk.h" +#include "pcmcia.h" +#include "block.h" +#include "qemu-timer.h" +#include "sysemu.h" /* debug IDE devices */ //#define DEBUG_IDE diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 31e7d7d0e..621122631 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -7,8 +7,13 @@ * This code is licenced under the GPL */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "primecell.h" +#include "devices.h" +#include "sysemu.h" +#include "boards.h" +#include "arm-misc.h" +#include "net.h" void DMA_run (void) { diff --git a/hw/iommu.c b/hw/iommu.c index c90f09bca..adc3bc015 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sun4m.h" /* debug iommu */ //#define DEBUG_IOMMU diff --git a/hw/irq.c b/hw/irq.c index bb30ced11..960155ad0 100644 --- a/hw/irq.c +++ b/hw/irq.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "irq.h" struct IRQState { qemu_irq_handler handler; diff --git a/hw/irq.h b/hw/irq.h index 2d1a3548b..d8195d520 100644 --- a/hw/irq.h +++ b/hw/irq.h @@ -1,8 +1,11 @@ +#ifndef QEMU_IRQ_H +#define QEMU_IRQ_H + /* Generic IRQ/GPIO pin infrastructure. */ +/* FIXME: Rmove one of these. */ typedef void (*qemu_irq_handler)(void *opaque, int n, int level); - -typedef struct IRQState *qemu_irq; +typedef void SetIRQFunc(void *opaque, int irq_num, int level); void qemu_set_irq(qemu_irq irq, int level); @@ -21,3 +24,5 @@ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); /* Returns a new IRQ with opposite polarity. */ qemu_irq qemu_irq_invert(qemu_irq irq); + +#endif diff --git a/hw/isa.h b/hw/isa.h new file mode 100644 index 000000000..89b3004a5 --- /dev/null +++ b/hw/isa.h @@ -0,0 +1,24 @@ +/* ISA bus */ + +extern target_phys_addr_t isa_mem_base; + +int register_ioport_read(int start, int length, int size, + IOPortReadFunc *func, void *opaque); +int register_ioport_write(int start, int length, int size, + IOPortWriteFunc *func, void *opaque); +void isa_unassign_ioport(int start, int length); + +void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size); + +/* dma.c */ +int DMA_get_channel_mode (int nchan); +int DMA_read_memory (int nchan, void *buf, int pos, int size); +int DMA_write_memory (int nchan, void *buf, int pos, int size); +void DMA_hold_DREQ (int nchan); +void DMA_release_DREQ (int nchan); +void DMA_schedule(int nchan); +void DMA_run (void); +void DMA_init (int high_page_enable); +void DMA_register_channel (int nchan, + DMA_transfer_handler transfer_handler, + void *opaque); diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c index 4e7914e6b..351961120 100644 --- a/hw/isa_mmio.c +++ b/hw/isa_mmio.c @@ -22,7 +22,8 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "isa.h" static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) diff --git a/hw/jazz_led.c b/hw/jazz_led.c index 1c7c176ed..a0eea26b5 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -22,7 +22,9 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "mips.h" +#include "console.h" #include "pixel_ops.h" //#define DEBUG_LED diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index e9866baac..c841db184 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -10,7 +10,9 @@ /* ??? Need to check if the {read,write}[wl] routines work properly on big-endian targets. */ -#include "vl.h" +#include "hw.h" +#include "pci.h" +#include "scsi-disk.h" //#define DEBUG_LSI //#define DEBUG_LSI_REG diff --git a/hw/m48t59.c b/hw/m48t59.c index 34979ad10..57291faa9 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -21,8 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" -#include "m48t59.h" +#include "hw.h" +#include "nvram.h" +#include "isa.h" +#include "qemu-timer.h" +#include "sysemu.h" //#define DEBUG_NVRAM diff --git a/hw/m48t59.h b/hw/m48t59.h deleted file mode 100644 index f2eb4b1e3..000000000 --- a/hw/m48t59.h +++ /dev/null @@ -1,13 +0,0 @@ -#if !defined (__M48T59_H__) -#define __M48T59_H__ - -typedef struct m48t59_t m48t59_t; - -void m48t59_write (void *private, uint32_t addr, uint32_t val); -uint32_t m48t59_read (void *private, uint32_t addr); -void m48t59_toggle_lock (void *private, int lock); -m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, - uint32_t io_base, uint16_t size, - int type); - -#endif /* !defined (__M48T59_H__) */ diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 62c9746e7..74003e60a 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" #include "ppc_mac.h" /* DBDMA: currently no op - should suffice right now */ diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index 8997abb9e..7304ac27e 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" #include "ppc_mac.h" struct MacIONVRAMState { diff --git a/hw/macio.c b/hw/macio.c index 5a5db4773..7f0d9f791 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -22,8 +22,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" #include "ppc_mac.h" +#include "pci.h" typedef struct macio_state_t macio_state_t; struct macio_state_t { diff --git a/hw/max111x.c b/hw/max111x.c index 8425bee57..cc3ded1df 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -7,7 +7,8 @@ * This code is licensed under the GNU GPLv2. */ -#include +#include "hw.h" +#include "i2c.h" struct max111x_s { qemu_irq interrupt; diff --git a/hw/max7310.c b/hw/max7310.c index 6b180d9b6..75e56c719 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -7,7 +7,8 @@ * This file is licensed under GNU GPL. */ -#include "vl.h" +#include "hw.h" +#include "i2c.h" struct max7310_s { i2c_slave i2c; @@ -182,7 +183,7 @@ static void max7310_gpio_set(void *opaque, int line, int level) { struct max7310_s *s = (struct max7310_s *) opaque; if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0) - cpu_abort(cpu_single_env, "bad GPIO line"); + hw_error("bad GPIO line"); if (level) s->level |= s->direction & (1 << line); @@ -220,7 +221,7 @@ void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler) { struct max7310_s *s = (struct max7310_s *) i2c; if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0) - cpu_abort(cpu_single_env, "bad GPIO line"); + hw_error("bad GPIO line"); s->handler[line] = handler; } diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index be9c63db2..8c8076b26 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -21,7 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "pc.h" +#include "isa.h" //#define DEBUG_CMOS diff --git a/hw/mcf.h b/hw/mcf.h new file mode 100644 index 000000000..91f2821f1 --- /dev/null +++ b/hw/mcf.h @@ -0,0 +1,21 @@ +#ifndef HW_MCF_H +#define HW_MCF_H +/* Motorola ColdFire device prototypes. */ + +/* mcf_uart.c */ +uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr); +void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val); +void *mcf_uart_init(qemu_irq irq, CharDriverState *chr); +void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq, + CharDriverState *chr); + +/* mcf_intc.c */ +qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env); + +/* mcf_fec.c */ +void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq); + +/* mcf5206.c */ +qemu_irq *mcf5206_init(uint32_t base, CPUState *env); + +#endif diff --git a/hw/mcf5206.c b/hw/mcf5206.c index 32117ae52..449ca12f5 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -5,7 +5,10 @@ * * This code is licenced under the GPL */ -#include "vl.h" +#include "hw.h" +#include "mcf.h" +#include "qemu-timer.h" +#include "sysemu.h" /* General purpose timer module. */ typedef struct { diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 93f78906d..b3389f079 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -5,7 +5,12 @@ * * This code is licenced under the GPL */ -#include "vl.h" +#include "hw.h" +#include "mcf.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "net.h" +#include "boards.h" #define SYS_FREQ 66000000 diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index a21810806..c5482c9e1 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -5,7 +5,9 @@ * * This code is licenced under the GPL */ -#include "vl.h" +#include "hw.h" +#include "net.h" +#include "mcf.h" /* For crc32 */ #include diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index e469c3119..4e99aeb4f 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -5,7 +5,8 @@ * * This code is licenced under the GPL */ -#include "vl.h" +#include "hw.h" +#include "mcf.h" typedef struct { uint64_t ipr; diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c index ab0f54f4d..01973a02f 100644 --- a/hw/mcf_uart.c +++ b/hw/mcf_uart.c @@ -5,7 +5,9 @@ * * This code is licenced under the GPL */ -#include "vl.h" +#include "hw.h" +#include "mcf.h" +#include "qemu-char.h" typedef struct { uint8_t mr[2]; diff --git a/hw/mips.h b/hw/mips.h new file mode 100644 index 000000000..0196b6ced --- /dev/null +++ b/hw/mips.h @@ -0,0 +1,25 @@ +#ifndef HW_MIPS_H +#define HW_MIPS_H +/* Definitions for mips board emulation. */ + +/* gt64xxx.c */ +PCIBus *pci_gt64120_init(qemu_irq *pic); + +/* ds1225y.c */ +typedef struct ds1225y_t ds1225y_t; +ds1225y_t *ds1225y_init(target_phys_addr_t mem_base, const char *filename); + +/* mipsnet.c */ +void mipsnet_init(int base, qemu_irq irq, NICInfo *nd); + +/* jazz_led.c */ +extern void jazz_led_init(DisplayState *ds, target_phys_addr_t base); + +/* mips_int.c */ +extern void cpu_mips_irq_init_cpu(CPUState *env); + +/* mips_timer.c */ +extern void cpu_mips_clock_init(CPUState *); +extern void cpu_mips_irqctrl_init (void); + +#endif diff --git a/hw/mips_int.c b/hw/mips_int.c index f4e22dcf8..ad48b4f70 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -1,4 +1,5 @@ -#include "vl.h" +#include "hw.h" +#include "mips.h" #include "cpu.h" /* Raise IRQ to CPU if necessary. It must be called every time the active diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2c193be23..9ce8232fd 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -22,7 +22,17 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "net.h" +#include "boards.h" +#include "smbus.h" +#include "mips.h" +#include "pci.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "audio/audio.h" +#include "boards.h" #ifdef TARGET_WORDS_BIGENDIAN #define BIOS_FILENAME "mips_bios.bin" diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 0c755a9ed..b9eec84f6 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -24,7 +24,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "mips.h" +#include "pc.h" +#include "isa.h" +#include "net.h" +#include "sysemu.h" +#include "boards.h" #ifdef TARGET_WORDS_BIGENDIAN #define BIOS_FILENAME "mips_bios.bin" diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 97c5ced4d..6e9f34505 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -22,7 +22,13 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "mips.h" +#include "isa.h" +#include "pc.h" +#include "fdc.h" +#include "sysemu.h" +#include "boards.h" #ifdef TARGET_WORDS_BIGENDIAN #define BIOS_FILENAME "mips_bios.bin" diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index acdb384cd..42effb365 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -7,7 +7,13 @@ * All peripherial devices are attached to this "bus" with * the standard PC ISA addresses. */ -#include "vl.h" +#include "hw.h" +#include "mips.h" +#include "pc.h" +#include "isa.h" +#include "net.h" +#include "sysemu.h" +#include "boards.h" #ifdef TARGET_WORDS_BIGENDIAN #define BIOS_FILENAME "mips_bios.bin" diff --git a/hw/mips_timer.c b/hw/mips_timer.c index b295bdbfe..3e7d5e3ee 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -1,4 +1,6 @@ -#include "vl.h" +#include "hw.h" +#include "mips.h" +#include "qemu-timer.h" void cpu_mips_irqctrl_init (void) { diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 97bc276b7..5a74ad962 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -1,4 +1,7 @@ -#include "vl.h" +#include "hw.h" +#include "mips.h" +#include "net.h" +#include "isa.h" //#define DEBUG_MIPSNET_SEND //#define DEBUG_MIPSNET_RECEIVE diff --git a/hw/mpcore.c b/hw/mpcore.c index cc33208e0..d5b28fe4b 100644 --- a/hw/mpcore.c +++ b/hw/mpcore.c @@ -7,7 +7,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "qemu-timer.h" +#include "primecell.h" #define MPCORE_PRIV_BASE 0x10100000 #define NCPU 4 diff --git a/hw/nand.c b/hw/nand.c index 118d04ea3..925583ae4 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -11,7 +11,11 @@ #ifndef NAND_IO -# include "vl.h" +# include "hw.h" +# include "flash.h" +# include "block.h" +/* FIXME: Pass block device as an argument. */ +# include "sysemu.h" # define NAND_CMD_READ0 0x00 # define NAND_CMD_READ1 0x01 diff --git a/hw/ne2000.c b/hw/ne2000.c index 689216c6a..92023eb71 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pci.h" +#include "net.h" /* debug NE2000 card */ //#define DEBUG_NE2000 diff --git a/hw/nvram.h b/hw/nvram.h new file mode 100644 index 000000000..174704bf6 --- /dev/null +++ b/hw/nvram.h @@ -0,0 +1,41 @@ +#ifndef NVRAM_H +#define NVRAM_H + +/* NVRAM helpers */ +typedef uint32_t (*nvram_read_t)(void *private, uint32_t addr); +typedef void (*nvram_write_t)(void *private, uint32_t addr, uint32_t val); +typedef struct nvram_t { + void *opaque; + nvram_read_t read_fn; + nvram_write_t write_fn; +} nvram_t; + +void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value); +uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr); +void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value); +uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr); +void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value); +uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr); +void NVRAM_set_string (nvram_t *nvram, uint32_t addr, + const unsigned char *str, uint32_t max); +int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max); +void NVRAM_set_crc (nvram_t *nvram, uint32_t addr, + uint32_t start, uint32_t count); +int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, + const unsigned char *arch, + uint32_t RAM_size, int boot_device, + uint32_t kernel_image, uint32_t kernel_size, + const char *cmdline, + uint32_t initrd_image, uint32_t initrd_size, + uint32_t NVRAM_image, + int width, int height, int depth); +typedef struct m48t59_t m48t59_t; + +void m48t59_write (void *private, uint32_t addr, uint32_t val); +uint32_t m48t59_read (void *private, uint32_t addr); +void m48t59_toggle_lock (void *private, int lock); +m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, + uint32_t io_base, uint16_t size, + int type); + +#endif /* !NVRAM_H */ diff --git a/hw/omap.c b/hw/omap.c index 30c0bef5e..88055edd9 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -18,8 +18,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "arm-misc.h" +#include "omap.h" +#include "sysemu.h" +#include "qemu-timer.h" +/* We use pc-style serial ports. */ +#include "pc.h" /* Should signal the TCMI */ uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) @@ -4716,7 +4721,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); - s->mmc = omap_mmc_init(0xfffb7800, s->irq[1][OMAP_INT_OQN], + s->mmc = omap_mmc_init(0xfffb7800, sd_bdrv, s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck")); s->mpuio = omap_mpuio_init(0xfffb5000, diff --git a/hw/omap.h b/hw/omap.h index 6de4f3e10..bf87fa46d 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -513,6 +513,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, /* omap_mmc.c */ struct omap_mmc_s; struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, + BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], omap_clk clk); void omap_mmc_reset(struct omap_mmc_s *s); void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover); @@ -788,4 +789,10 @@ inline static int debug_register_io_memory(int io_index, # define cpu_register_io_memory debug_register_io_memory # endif +/* Not really omap specific, but is the only thing that uses the + uwire interface. */ +/* tsc210x.c */ +struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); +struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); + #endif /* hw_omap_h */ diff --git a/hw/omap1_clk.c b/hw/omap1_clk.c index b2ec23c13..37daec266 100644 --- a/hw/omap1_clk.c +++ b/hw/omap1_clk.c @@ -20,7 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ -#include "vl.h" +#include "hw.h" +#include "omap.h" struct clk { const char *name; diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index 878c046ce..fd37974cc 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ -#include "vl.h" +#include "hw.h" +#include "i2c.h" +#include "omap.h" struct omap_i2c_s { target_phys_addr_t base; diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 543d1f2bd..c6565d1db 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ -#include "vl.h" +#include "hw.h" +#include "console.h" +#include "omap.h" struct omap_lcd_panel_s { target_phys_addr_t base; diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index 30ba9b685..0a7ae8712 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -18,7 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ -#include "vl.h" +#include "hw.h" +#include "omap.h" #include "sd.h" struct omap_mmc_s { @@ -507,6 +508,7 @@ void omap_mmc_reset(struct omap_mmc_s *host) } struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, + BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], omap_clk clk) { int iomemtype; @@ -523,7 +525,7 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, cpu_register_physical_memory(s->base, 0x800, iomemtype); /* Instantiate the storage */ - s->card = sd_init(sd_bdrv); + s->card = sd_init(bd); return s; } diff --git a/hw/openpic.c b/hw/openpic.c index 54830c31b..32cf54e48 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -32,7 +32,9 @@ * Serial interrupts, as implemented in Raven chipset are not supported yet. * */ -#include "vl.h" +#include "hw.h" +#include "ppc_mac.h" +#include "pci.h" //#define DEBUG_OPENPIC diff --git a/hw/palm.c b/hw/palm.c index bd17930f4..63edd9029 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -18,7 +18,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ -#include "vl.h" +#include "hw.h" +#include "audio/audio.h" +#include "sysemu.h" +#include "console.h" +#include "omap.h" +#include "boards.h" +#include "arm-misc.h" static uint32_t static_readb(void *opaque, target_phys_addr_t offset) { diff --git a/hw/parallel.c b/hw/parallel.c index bda3f3a20..dfcd5c2c3 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -22,7 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "qemu-char.h" +#include "isa.h" +#include "pc.h" //#define DEBUG_PARALLEL diff --git a/hw/pc.c b/hw/pc.c index 8c165ee5d..99bb90646 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -21,7 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "fdc.h" +#include "pci.h" +#include "block.h" +#include "sysemu.h" +#include "audio/audio.h" +#include "net.h" +#include "smbus.h" +#include "boards.h" /* output Bochs bios info messages */ //#define DEBUG_BIOS diff --git a/hw/pc.h b/hw/pc.h new file mode 100644 index 000000000..beb711c0c --- /dev/null +++ b/hw/pc.h @@ -0,0 +1,145 @@ +#ifndef HW_PC_H +#define HW_PC_H +/* PC-style peripherals (also used by other machines). */ + +/* serial.c */ + +SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr); +SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, + qemu_irq irq, CharDriverState *chr, + int ioregister); +uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr); +void serial_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value); +uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr); +void serial_mm_writew (void *opaque, target_phys_addr_t addr, uint32_t value); +uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr); +void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value); + +/* parallel.c */ + +typedef struct ParallelState ParallelState; +ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr); +ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr); + +/* i8259.c */ + +typedef struct PicState2 PicState2; +extern PicState2 *isa_pic; +void pic_set_irq(int irq, int level); +void pic_set_irq_new(void *opaque, int irq, int level); +qemu_irq *i8259_init(qemu_irq parent_irq); +void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, + void *alt_irq_opaque); +int pic_read_irq(PicState2 *s); +void pic_update_irq(PicState2 *s); +uint32_t pic_intack_read(PicState2 *s); +void pic_info(void); +void irq_info(void); + +/* APIC */ +typedef struct IOAPICState IOAPICState; + +int apic_init(CPUState *env); +int apic_accept_pic_intr(CPUState *env); +int apic_get_interrupt(CPUState *env); +IOAPICState *ioapic_init(void); +void ioapic_set_irq(void *opaque, int vector, int level); + +/* i8254.c */ + +#define PIT_FREQ 1193182 + +typedef struct PITState PITState; + +PITState *pit_init(int base, qemu_irq irq); +void pit_set_gate(PITState *pit, int channel, int val); +int pit_get_gate(PITState *pit, int channel); +int pit_get_initial_count(PITState *pit, int channel); +int pit_get_mode(PITState *pit, int channel); +int pit_get_out(PITState *pit, int channel, int64_t current_time); + +/* vmport.c */ +void vmport_init(CPUState *env); +void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque); + +/* vmmouse.c */ +void *vmmouse_init(void *m); + +/* pckbd.c */ + +void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); +void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, + target_phys_addr_t base, int it_shift); + +/* mc146818rtc.c */ + +typedef struct RTCState RTCState; + +RTCState *rtc_init(int base, qemu_irq irq); +RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq); +void rtc_set_memory(RTCState *s, int addr, int val); +void rtc_set_date(RTCState *s, const struct tm *tm); + +/* pc.c */ +extern int fd_bootchk; + +void ioport_set_a20(int enable); +int ioport_get_a20(void); + +/* acpi.c */ +extern int acpi_enabled; +i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base); +void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); +void acpi_bios_init(void); + +/* pcspk.c */ +void pcspk_init(PITState *); +int pcspk_audio_init(AudioState *, qemu_irq *pic); + +/* piix_pci.c */ +PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic); +void i440fx_set_smm(PCIDevice *d, int val); +int piix3_init(PCIBus *bus, int devfn); +void i440fx_init_memory_mappings(PCIDevice *d); + +int piix4_init(PCIBus *bus, int devfn); + +/* vga.c */ + +#ifndef TARGET_SPARC +#define VGA_RAM_SIZE (8192 * 1024) +#else +#define VGA_RAM_SIZE (9 * 1024 * 1024) +#endif + +int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); +int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size, + unsigned long vga_bios_offset, int vga_bios_size); +int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size, + target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, + int it_shift); + +/* cirrus_vga.c */ +void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); +void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); + +/* ide.c */ +void isa_ide_init(int iobase, int iobase2, qemu_irq irq, + BlockDriverState *hd0, BlockDriverState *hd1); +void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, + int secondary_ide_enabled); +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, + qemu_irq *pic); +void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, + qemu_irq *pic); + +/* ne2000.c */ + +void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd); + +#endif diff --git a/hw/pci.c b/hw/pci.c index 7e8adc463..c43be3e81 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pci.h" +#include "console.h" +#include "net.h" //#define DEBUG_PCI diff --git a/hw/pci.h b/hw/pci.h new file mode 100644 index 000000000..075754514 --- /dev/null +++ b/hw/pci.h @@ -0,0 +1,138 @@ +#ifndef QEMU_PCI_H +#define QEMU_PCI_H + +/* PCI includes legacy ISA access. */ +#include "isa.h" + +/* PCI bus */ + +extern target_phys_addr_t pci_mem_base; + +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, + uint32_t address, uint32_t data, int len); +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, + uint32_t address, int len); +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type); + +#define PCI_ADDRESS_SPACE_MEM 0x00 +#define PCI_ADDRESS_SPACE_IO 0x01 +#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08 + +typedef struct PCIIORegion { + uint32_t addr; /* current PCI mapping address. -1 means not mapped */ + uint32_t size; + uint8_t type; + PCIMapIORegionFunc *map_func; +} PCIIORegion; + +#define PCI_ROM_SLOT 6 +#define PCI_NUM_REGIONS 7 + +#define PCI_DEVICES_MAX 64 + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ +#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ +#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ +#define PCI_MIN_GNT 0x3e /* 8 bits */ +#define PCI_MAX_LAT 0x3f /* 8 bits */ + +struct PCIDevice { + /* PCI config space */ + uint8_t config[256]; + + /* the following fields are read only */ + PCIBus *bus; + int devfn; + char name[64]; + PCIIORegion io_regions[PCI_NUM_REGIONS]; + + /* do not access the following fields */ + PCIConfigReadFunc *config_read; + PCIConfigWriteFunc *config_write; + /* ??? This is a PC-specific hack, and should be removed. */ + int irq_index; + + /* IRQ objects for the INTA-INTD pins. */ + qemu_irq *irq; + + /* Current IRQ levels. Used internally by the generic PCI code. */ + int irq_state[4]; +}; + +PCIDevice *pci_register_device(PCIBus *bus, const char *name, + int instance_size, int devfn, + PCIConfigReadFunc *config_read, + PCIConfigWriteFunc *config_write); + +void pci_register_io_region(PCIDevice *pci_dev, int region_num, + uint32_t size, int type, + PCIMapIORegionFunc *map_func); + +uint32_t pci_default_read_config(PCIDevice *d, + uint32_t address, int len); +void pci_default_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len); +void pci_device_save(PCIDevice *s, QEMUFile *f); +int pci_device_load(PCIDevice *s, QEMUFile *f); + +typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level); +typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, + qemu_irq *pic, int devfn_min, int nirq); + +void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn); +void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); +uint32_t pci_data_read(void *opaque, uint32_t addr, int len); +int pci_bus_num(PCIBus *s); +void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d)); + +void pci_info(void); +PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, + pci_map_irq_fn map_irq, const char *name); + +/* lsi53c895a.c */ +void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); +void *lsi_scsi_init(PCIBus *bus, int devfn); + +/* vmware_vga.c */ +void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, + unsigned long vga_ram_offset, int vga_ram_size); + +/* usb-uhci.c */ +void usb_uhci_piix3_init(PCIBus *bus, int devfn); +void usb_uhci_piix4_init(PCIBus *bus, int devfn); + +/* usb-ohci.c */ +void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn); + +/* eepro100.c */ + +void pci_i82551_init(PCIBus *bus, NICInfo *nd, int devfn); +void pci_i82557b_init(PCIBus *bus, NICInfo *nd, int devfn); +void pci_i82559er_init(PCIBus *bus, NICInfo *nd, int devfn); + +/* ne2000.c */ + +void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn); + +/* rtl8139.c */ + +void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); + +/* pcnet.c */ +void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); + +/* prep_pci.c */ +PCIBus *pci_prep_init(qemu_irq *pic); + +/* apb_pci.c */ +PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base, + qemu_irq *pic); + +#endif diff --git a/hw/pckbd.c b/hw/pckbd.c index 9b96b1cba..738ce61d6 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -21,7 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "isa.h" +#include "pc.h" +#include "ps2.h" +#include "sysemu.h" /* debug PC keyboard */ //#define DEBUG_KBD diff --git a/hw/pcmcia.h b/hw/pcmcia.h new file mode 100644 index 000000000..bfa23babe --- /dev/null +++ b/hw/pcmcia.h @@ -0,0 +1,50 @@ +/* PCMCIA/Cardbus */ + +struct pcmcia_socket_s { + qemu_irq irq; + int attached; + const char *slot_string; + const char *card_string; +}; + +void pcmcia_socket_register(struct pcmcia_socket_s *socket); +void pcmcia_socket_unregister(struct pcmcia_socket_s *socket); +void pcmcia_info(void); + +struct pcmcia_card_s { + void *state; + struct pcmcia_socket_s *slot; + int (*attach)(void *state); + int (*detach)(void *state); + const uint8_t *cis; + int cis_len; + + /* Only valid if attached */ + uint8_t (*attr_read)(void *state, uint32_t address); + void (*attr_write)(void *state, uint32_t address, uint8_t value); + uint16_t (*common_read)(void *state, uint32_t address); + void (*common_write)(void *state, uint32_t address, uint16_t value); + uint16_t (*io_read)(void *state, uint32_t address); + void (*io_write)(void *state, uint32_t address, uint16_t value); +}; + +#define CISTPL_DEVICE 0x01 /* 5V Device Information Tuple */ +#define CISTPL_NO_LINK 0x14 /* No Link Tuple */ +#define CISTPL_VERS_1 0x15 /* Level 1 Version Tuple */ +#define CISTPL_JEDEC_C 0x18 /* JEDEC ID Tuple */ +#define CISTPL_JEDEC_A 0x19 /* JEDEC ID Tuple */ +#define CISTPL_CONFIG 0x1a /* Configuration Tuple */ +#define CISTPL_CFTABLE_ENTRY 0x1b /* 16-bit PCCard Configuration */ +#define CISTPL_DEVICE_OC 0x1c /* Additional Device Information */ +#define CISTPL_DEVICE_OA 0x1d /* Additional Device Information */ +#define CISTPL_DEVICE_GEO 0x1e /* Additional Device Information */ +#define CISTPL_DEVICE_GEO_A 0x1f /* Additional Device Information */ +#define CISTPL_MANFID 0x20 /* Manufacture ID Tuple */ +#define CISTPL_FUNCID 0x21 /* Function ID Tuple */ +#define CISTPL_FUNCE 0x22 /* Function Extension Tuple */ +#define CISTPL_END 0xff /* Tuple End */ +#define CISTPL_ENDMARK 0xff + +/* dscm1xxxx.c */ +struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv); + diff --git a/hw/pcnet.c b/hw/pcnet.c index 71a05da8d..5a6c36c28 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -35,7 +35,10 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */ -#include "vl.h" +#include "hw.h" +#include "pci.h" +#include "net.h" +#include "qemu-timer.h" //#define PCNET_DEBUG //#define PCNET_DEBUG_IO @@ -2008,6 +2011,7 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) /* SPARC32 interface */ #if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure +#include "sun4m.h" static void parent_lance_reset(void *opaque, int irq, int level) { diff --git a/hw/pcspk.c b/hw/pcspk.c index 2cbeff377..9bb248b80 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -22,7 +22,11 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "isa.h" +#include "audio/audio.h" +#include "qemu-timer.h" #define PCSPK_BUF_LEN 1792 #define PCSPK_SAMPLE_RATE 32000 diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 22bf025ff..065dd2c80 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -37,7 +37,10 @@ * It does not implement much more ... */ -#include "vl.h" +#include "hw.h" +#include "flash.h" +#include "block.h" +#include "qemu-timer.h" #define PFLASH_BUG(fmt, args...) \ do { \ diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 08f88900f..eaf6750bb 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -36,7 +36,10 @@ * It does not implement multiple sectors erase */ -#include "vl.h" +#include "hw.h" +#include "flash.h" +#include "qemu-timer.h" +#include "block.h" //#define PFLASH_DEBUG #ifdef PFLASH_DEBUG diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 3c04e3a08..75f412a91 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -22,7 +22,10 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pc.h" +#include "pci.h" + typedef uint32_t pci_addr_t; #include "pci_host.h" diff --git a/hw/pl011.c b/hw/pl011.c index 903755414..91c52cc31 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -7,7 +7,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "qemu-char.h" +#include "primecell.h" typedef struct { uint32_t base; diff --git a/hw/pl022.c b/hw/pl022.c index d7c735b7c..54a581b88 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -7,7 +7,8 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "primecell.h" //#define DEBUG_PL022 1 diff --git a/hw/pl031.c b/hw/pl031.c index 7e8098ba5..68e9005c0 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -9,7 +9,10 @@ * */ -#include"vl.h" +#include "hw.h" +#include "primecell.h" +#include "qemu-timer.h" +#include "sysemu.h" //#define DEBUG_PL031 diff --git a/hw/pl050.c b/hw/pl050.c index 1f56261b4..7b890e9c9 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -7,7 +7,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "primecell.h" +#include "ps2.h" typedef struct { void *dev; diff --git a/hw/pl061.c b/hw/pl061.c index fa5004a96..791427252 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -8,7 +8,8 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "primecell.h" //#define DEBUG_PL061 1 diff --git a/hw/pl080.c b/hw/pl080.c index d581024ca..059e66702 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -7,7 +7,8 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "primecell.h" #define PL080_MAX_CHANNELS 8 #define PL080_CONF_E 0x1 diff --git a/hw/pl110.c b/hw/pl110.c index 97cbee545..e5b2b2363 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -7,7 +7,9 @@ * This code is licenced under the GNU LGPL */ -#include "vl.h" +#include "hw.h" +#include "primecell.h" +#include "console.h" #define PL110_CR_EN 0x001 #define PL110_CR_BGR 0x100 diff --git a/hw/pl181.c b/hw/pl181.c index bd067ddac..5eb46d0f8 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -7,7 +7,8 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "primecell.h" #include "sd.h" //#define DEBUG_PL181 1 diff --git a/hw/pl190.c b/hw/pl190.c index 79ba3ab79..abc28468e 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -7,8 +7,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "primecell.h" +#include "arm-misc.h" /* The number of virtual priority levels. 16 user vectors plus the unvectored IRQ. Chained interrupts would require an additional level diff --git a/hw/ppc.c b/hw/ppc.c index a25a3607f..914510154 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -21,7 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ppc.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "nvram.h" //#define PPC_DEBUG_IRQ //#define PPC_DEBUG_TB diff --git a/hw/ppc.h b/hw/ppc.h new file mode 100644 index 000000000..0a3d4ff06 --- /dev/null +++ b/hw/ppc.h @@ -0,0 +1,31 @@ +/* PowerPC hardware exceptions management helpers */ +typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); +typedef struct clk_setup_t clk_setup_t; +struct clk_setup_t { + clk_setup_cb cb; + void *opaque; +}; +static inline void clk_setup (clk_setup_t *clk, uint32_t freq) +{ + if (clk->cb != NULL) + (*clk->cb)(clk->opaque, freq); +} + +clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq); +/* Embedded PowerPC DCR management */ +typedef target_ulong (*dcr_read_cb)(void *opaque, int dcrn); +typedef void (*dcr_write_cb)(void *opaque, int dcrn, target_ulong val); +int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn), + int (*dcr_write_error)(int dcrn)); +int ppc_dcr_register (CPUState *env, int dcrn, void *opaque, + dcr_read_cb drc_read, dcr_write_cb dcr_write); +clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq); +/* Embedded PowerPC reset */ +void ppc40x_core_reset (CPUState *env); +void ppc40x_chip_reset (CPUState *env); +void ppc40x_system_reset (CPUState *env); +void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); + +extern CPUWriteMemoryFunc *PPC_io_write[]; +extern CPUReadMemoryFunc *PPC_io_read[]; +void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index ab134418f..7fd53d3ca 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -21,8 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ppc.h" #include "ppc405.h" +#include "nvram.h" +#include "flash.h" +#include "sysemu.h" +#include "block.h" +#include "boards.h" extern int loglevel; extern FILE *logfile; diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index efbc399d2..0a2f087d8 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ppc.h" #include "ppc405.h" +#include "pc.h" +#include "qemu-timer.h" +#include "sysemu.h" extern int loglevel; extern FILE *logfile; diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 72490b089..be7187929 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -21,8 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ppc.h" #include "ppc4xx.h" +#include "sysemu.h" extern int loglevel; extern FILE *logfile; diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 8fb8e5d20..34e192183 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -22,8 +22,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ppc.h" #include "ppc_mac.h" +#include "nvram.h" +#include "pc.h" +#include "pci.h" +#include "net.h" +#include "sysemu.h" +#include "boards.h" /* UniN device */ static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value) diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index 7ed7b55a9..3a26cdef9 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -68,4 +68,58 @@ void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); uint32_t macio_nvram_read (void *opaque, uint32_t addr); void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val); +/* adb.c */ + +#define MAX_ADB_DEVICES 16 + +#define ADB_MAX_OUT_LEN 16 + +typedef struct ADBDevice ADBDevice; + +/* buf = NULL means polling */ +typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, + const uint8_t *buf, int len); +typedef int ADBDeviceReset(ADBDevice *d); + +struct ADBDevice { + struct ADBBusState *bus; + int devaddr; + int handler; + ADBDeviceRequest *devreq; + ADBDeviceReset *devreset; + void *opaque; +}; + +typedef struct ADBBusState { + ADBDevice devices[MAX_ADB_DEVICES]; + int nb_devices; + int poll_index; +} ADBBusState; + +int adb_request(ADBBusState *s, uint8_t *buf_out, + const uint8_t *buf, int len); +int adb_poll(ADBBusState *s, uint8_t *buf_out); + +ADBDevice *adb_register_device(ADBBusState *s, int devaddr, + ADBDeviceRequest *devreq, + ADBDeviceReset *devreset, + void *opaque); +void adb_kbd_init(ADBBusState *bus); +void adb_mouse_init(ADBBusState *bus); + +extern ADBBusState adb_bus; + +/* openpic.c */ +/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ +enum { + OPENPIC_OUTPUT_INT = 0, /* IRQ */ + OPENPIC_OUTPUT_CINT, /* critical IRQ */ + OPENPIC_OUTPUT_MCK, /* Machine check event */ + OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ + OPENPIC_OUTPUT_RESET, /* Core reset event */ + OPENPIC_OUTPUT_NB, +}; +qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + qemu_irq **irqs, qemu_irq irq_out); + #endif /* !defined(__PPC_MAC_H__) */ diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index ef638767f..ac09c831f 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -22,8 +22,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ppc.h" #include "ppc_mac.h" +#include "nvram.h" +#include "pc.h" +#include "sysemu.h" +#include "net.h" +#include "isa.h" +#include "pci.h" +#include "boards.h" /* temporary frame buffer OSI calls for the video.x driver. The right solution is to modify the driver to use VGA PCI I/Os */ diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 1d2a85da1..4fcd5dd1a 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -21,7 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "nvram.h" +#include "pc.h" +#include "fdc.h" +#include "net.h" +#include "sysemu.h" +#include "isa.h" +#include "pci.h" +#include "ppc.h" +#include "boards.h" //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 8c8a4988d..815db5308 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -22,7 +22,9 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "pci.h" + typedef uint32_t pci_addr_t; #include "pci_host.h" diff --git a/hw/primecell.h b/hw/primecell.h new file mode 100644 index 000000000..072390bf0 --- /dev/null +++ b/hw/primecell.h @@ -0,0 +1,59 @@ +#ifndef PRIMECELL_H +#define PRIMECELL_H + +/* Declarations for ARM PrimeCell based periperals. */ +/* Also includes some devices that are currently only used by the + ARM boards. */ + +/* pl031.c */ +void pl031_init(uint32_t base, qemu_irq irq); + +/* pl110.c */ +void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int); + +/* pl011.c */ +enum pl011_type { + PL011_ARM, + PL011_LUMINARY +}; + +void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr, + enum pl011_type type); + +/* pl022.c */ +void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int), + void *opaque); + +/* pl050.c */ +void pl050_init(uint32_t base, qemu_irq irq, int is_mouse); + +/* pl061.c */ +qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out); + +/* pl080.c */ +void *pl080_init(uint32_t base, qemu_irq irq, int nchannels); + +/* pl181.c */ +void pl181_init(uint32_t base, BlockDriverState *bd, + qemu_irq irq0, qemu_irq irq1); + +/* pl190.c */ +qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq); + +/* realview_gic.c */ +qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq); + +/* mpcore.c */ +extern qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq); + +/* arm-timer.c */ +void sp804_init(uint32_t base, qemu_irq irq); +void icp_pit_init(uint32_t base, qemu_irq *pic, int irq); + +/* arm_sysctl.c */ +void arm_sysctl_init(uint32_t base, uint32_t sys_id); + +/* versatile_pci.c */ +PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview); + +#endif diff --git a/hw/ps2.c b/hw/ps2.c index 5367df10c..a0adca36e 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ps2.h" +#include "console.h" /* debug PC keyboard */ //#define DEBUG_KBD diff --git a/hw/ps2.h b/hw/ps2.h new file mode 100644 index 000000000..f2c091edd --- /dev/null +++ b/hw/ps2.h @@ -0,0 +1,10 @@ +/* ps2.c */ +void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); +void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); +void ps2_write_mouse(void *, int val); +void ps2_write_keyboard(void *, int val); +uint32_t ps2_read_data(void *); +void ps2_queue(void *, int b); +void ps2_keyboard_set_translation(void *opaque, int mode); +void ps2_mouse_fake_event(void *opaque); + diff --git a/hw/ptimer.c b/hw/ptimer.c index d81503adc..7dd6d3110 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -5,7 +5,8 @@ * * This code is licenced under the GNU LGPL. */ -#include "vl.h" +#include "hw.h" +#include "qemu-timer.h" struct ptimer_state diff --git a/hw/pxa.h b/hw/pxa.h index c151de3ef..101cfe068 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -95,7 +95,7 @@ void pxa2xx_lcdc_oritentation(void *opaque, int angle); /* pxa2xx_mmci.c */ struct pxa2xx_mmci_s; struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, - qemu_irq irq, void *dma); + BlockDriverState *bd, qemu_irq irq, void *dma); void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, qemu_irq readonly, qemu_irq coverswitch); @@ -207,4 +207,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, DisplayState *ds, const char *revision); struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, DisplayState *ds); +/* usb-ohci.c */ +void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, + qemu_irq irq); + #endif /* PXA_H */ diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 9f7771f2d..00cb2370a 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -7,7 +7,13 @@ * This code is licenced under the GPL. */ -# include "vl.h" +#include "hw.h" +#include "pxa.h" +#include "sysemu.h" +#include "pc.h" +#include "i2c.h" +#include "qemu-timer.h" +#include "qemu-char.h" static struct { target_phys_addr_t io_base; @@ -2064,7 +2070,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); - s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma); + s->mmc = pxa2xx_mmci_init(0x41100000, sd_bdrv, s->pic[PXA2XX_PIC_MMC], + s->dma); for (i = 0; pxa270_serial[i].io_base; i ++) if (serial_hds[i]) @@ -2180,7 +2187,8 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85); - s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma); + s->mmc = pxa2xx_mmci_init(0x41100000, sd_bdrv, s->pic[PXA2XX_PIC_MMC], + s->dma); for (i = 0; pxa255_serial[i].io_base; i ++) if (serial_hds[i]) diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 4c60ffd00..23bdae909 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -8,7 +8,8 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "pxa.h" struct pxa2xx_dma_channel_s { target_phys_addr_t descr; diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index b6e598a98..9f5184438 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -7,7 +7,8 @@ * This code is licensed under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "pxa.h" #define PXA2XX_GPIO_BANKS 4 diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 7ae9ba633..56328e9f4 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -7,8 +7,12 @@ * This code is licensed under the GPLv2. */ -#include "vl.h" +#include "hw.h" +#include "console.h" +#include "pxa.h" #include "pixel_ops.h" +/* FIXME: For graphic_rotate. Should probably be done in common code. */ +#include "sysemu.h" typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int); diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 7eb7c7941..6e244a96c 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -7,7 +7,8 @@ * This code is licensed under the GPLv2. */ -#include "vl.h" +#include "hw.h" +#include "pxa.h" #include "sd.h" struct pxa2xx_mmci_s { @@ -522,7 +523,7 @@ static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id) } struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, - qemu_irq irq, void *dma) + BlockDriverState *bd, qemu_irq irq, void *dma) { int iomemtype; struct pxa2xx_mmci_s *s; @@ -537,7 +538,7 @@ struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, cpu_register_physical_memory(base, 0x00100000, iomemtype); /* Instantiate the actual storage */ - s->card = sd_init(sd_bdrv); + s->card = sd_init(bd); register_savevm("pxa2xx_mmci", 0, 0, pxa2xx_mmci_save, pxa2xx_mmci_load, s); diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index f1399f467..f5d805a7c 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -7,7 +7,8 @@ * This code is licensed under the GPLv2. */ -#include "vl.h" +#include "hw.h" +#include "pcmcia.h" struct pxa2xx_pcmcia_s { struct pcmcia_socket_s slot; diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index c9012e8db..a3611b88b 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -8,7 +8,8 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "pxa.h" #define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ #define ICMR 0x04 /* Interrupt Controller Mask register */ diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 982420502..90777f822 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -7,7 +7,10 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "pxa.h" #define OSMR0 0x00 #define OSMR1 0x04 diff --git a/hw/r2d.c b/hw/r2d.c index ec6540e36..4bca6bead 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -22,7 +22,10 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sh.h" +#include "sysemu.h" +#include "boards.h" #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ #define SDRAM_SIZE 0x04000000 diff --git a/hw/realview.c b/hw/realview.c index e02deeed7..808df1064 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -7,8 +7,14 @@ * This code is licenced under the GPL. */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "arm-misc.h" +#include "primecell.h" +#include "devices.h" +#include "pci.h" +#include "net.h" +#include "sysemu.h" +#include "boards.h" /* Board init. */ diff --git a/hw/realview_gic.c b/hw/realview_gic.c index cbc961491..639db846b 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -7,8 +7,8 @@ * This code is licenced under the GPL. */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "arm-misc.h" #define GIC_NIRQ 96 #define NCPU 1 diff --git a/hw/rtl8139.c b/hw/rtl8139.c index dc06f6617..868cbbae8 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -43,7 +43,10 @@ * Added rx/tx buffer reset when enabling rx/tx operation */ -#include "vl.h" +#include "hw.h" +#include "pci.h" +#include "qemu-timer.h" +#include "net.h" /* debug RTL8139 card */ //#define DEBUG_RTL8139 1 diff --git a/hw/sb16.c b/hw/sb16.c index 1610b3288..4e6cc3041 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -21,7 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "audiodev.h" +#include "audio/audio.h" +#include "isa.h" +#include "qemu-timer.h" #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 384c098a0..700b91446 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -25,7 +25,9 @@ do { printf("scsi-disk: " fmt , ##args); } while (0) #define BADF(fmt, args...) \ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) -#include "vl.h" +#include "qemu-common.h" +#include "block.h" +#include "scsi-disk.h" #define SENSE_NO_SENSE 0 #define SENSE_NOT_READY 2 diff --git a/hw/scsi-disk.h b/hw/scsi-disk.h new file mode 100644 index 000000000..9071cec49 --- /dev/null +++ b/hw/scsi-disk.h @@ -0,0 +1,33 @@ +#ifndef SCSI_DISK_H +#define SCSI_DISK_H + +/* scsi-disk.c */ +enum scsi_reason { + SCSI_REASON_DONE, /* Command complete. */ + SCSI_REASON_DATA /* Transfer complete, more data required. */ +}; + +typedef struct SCSIDevice SCSIDevice; +typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag, + uint32_t arg); + +SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, + int tcq, + scsi_completionfn completion, + void *opaque); +void scsi_disk_destroy(SCSIDevice *s); + +int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); +/* SCSI data transfers are asynchrnonous. However, unlike the block IO + layer the completion routine may be called directly by + scsi_{read,write}_data. */ +void scsi_read_data(SCSIDevice *s, uint32_t tag); +int scsi_write_data(SCSIDevice *s, uint32_t tag); +void scsi_cancel_io(SCSIDevice *s, uint32_t tag); +uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); + +/* cdrom.c */ +int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); +int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); + +#endif diff --git a/hw/sd.c b/hw/sd.c index 25ae9956b..08e8805e5 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -29,6 +29,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "hw.h" +#include "block.h" #include "sd.h" //#define DEBUG_SD 1 diff --git a/hw/sd.h b/hw/sd.h index d0e7eceeb..9416df0db 100644 --- a/hw/sd.h +++ b/hw/sd.h @@ -29,8 +29,6 @@ #ifndef __hw_sd_h #define __hw_sd_h 1 -#include - #define OUT_OF_RANGE (1 << 31) #define ADDRESS_ERROR (1 << 30) #define BLOCK_LEN_ERROR (1 << 29) diff --git a/hw/serial.c b/hw/serial.c index 36a7cc4e3..c5d9db5fa 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "qemu-char.h" +#include "isa.h" +#include "pc.h" //#define DEBUG_SERIAL diff --git a/hw/sh.h b/hw/sh.h new file mode 100644 index 000000000..57a2485cb --- /dev/null +++ b/hw/sh.h @@ -0,0 +1,38 @@ +#ifndef QEMU_SH_H +#define QEMU_SH_H +/* Definitions for SH board emulation. */ + +/* sh7750.c */ +struct SH7750State; + +struct SH7750State *sh7750_init(CPUState * cpu); + +typedef struct { + /* The callback will be triggered if any of the designated lines change */ + uint16_t portamask_trigger; + uint16_t portbmask_trigger; + /* Return 0 if no action was taken */ + int (*port_change_cb) (uint16_t porta, uint16_t portb, + uint16_t * periph_pdtra, + uint16_t * periph_portdira, + uint16_t * periph_pdtrb, + uint16_t * periph_portdirb); +} sh7750_io_device; + +int sh7750_register_io_device(struct SH7750State *s, + sh7750_io_device * device); +/* sh_timer.c */ +#define TMU012_FEAT_TOCR (1 << 0) +#define TMU012_FEAT_3CHAN (1 << 1) +#define TMU012_FEAT_EXTCLK (1 << 2) +void tmu012_init(uint32_t base, int feat, uint32_t freq); + +/* sh_serial.c */ +#define SH_SERIAL_FEAT_SCIF (1 << 0) +void sh_serial_init (target_phys_addr_t base, int feat, + uint32_t freq, CharDriverState *chr); + +/* tc58128.c */ +int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); + +#endif diff --git a/hw/sh7750.c b/hw/sh7750.c index 1e2d91719..82317d7ea 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -24,7 +24,9 @@ */ #include #include -#include "vl.h" +#include "hw.h" +#include "sh.h" +#include "sysemu.h" #include "sh7750_regs.h" #include "sh7750_regnames.h" #include "sh_intc.h" diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c index 551ce8057..51283c9db 100644 --- a/hw/sh7750_regnames.c +++ b/hw/sh7750_regnames.c @@ -1,4 +1,5 @@ -#include "vl.h" +#include "hw.h" +#include "sh.h" #include "sh7750_regs.h" #define REGNAME(r) {r, #r}, diff --git a/hw/sh_intc.c b/hw/sh_intc.c index 7e8f16782..647f1cba9 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -10,7 +10,8 @@ #include #include "sh_intc.h" -#include "vl.h" +#include "hw.h" +#include "sh.h" //#define DEBUG_INTC diff --git a/hw/sh_serial.c b/hw/sh_serial.c index 03a096c1b..1336780d1 100644 --- a/hw/sh_serial.c +++ b/hw/sh_serial.c @@ -24,7 +24,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sh.h" +#include "qemu-char.h" #include //#define DEBUG_SERIAL diff --git a/hw/sh_timer.c b/hw/sh_timer.c index 40f3930cf..6be895300 100644 --- a/hw/sh_timer.c +++ b/hw/sh_timer.c @@ -8,7 +8,9 @@ * This code is licenced under the GPL. */ -#include "vl.h" +#include "hw.h" +#include "sh.h" +#include "qemu-timer.h" //#define DEBUG_TIMER diff --git a/hw/shix.c b/hw/shix.c index 0ec2b0e37..c891381c0 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -27,7 +27,10 @@ More information in target-sh4/README.sh4 */ -#include "vl.h" +#include "hw.h" +#include "sh.h" +#include "sysemu.h" +#include "boards.h" #define BIOS_FILENAME "shix_bios.bin" #define BIOS_ADDRESS 0xA0000000 diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 541222877..448e5bfde 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sun4m.h" +#include "console.h" + //#define DEBUG_IRQ_COUNT //#define DEBUG_IRQ diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 236c4a1b7..67e1c0d7d 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sun4m.h" +#include "sysemu.h" + /* debug misc */ //#define DEBUG_MISC diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 2eb3379b4..534a438a1 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -21,7 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sun4m.h" +#include "qemu-char.h" +#include "console.h" + /* debug serial */ //#define DEBUG_SERIAL diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 14fd40262..a81b34ff5 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sun4m.h" +#include "qemu-timer.h" //#define DEBUG_TIMER diff --git a/hw/smbus.c b/hw/smbus.c index 103e9177b..81e887b2a 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -9,7 +9,9 @@ /* TODO: Implement PEC. */ -#include "vl.h" +#include "hw.h" +#include "i2c.h" +#include "smbus.h" //#define DEBUG_SMBUS 1 @@ -194,7 +196,7 @@ SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size) SMBusDevice *dev; if (size < sizeof(SMBusDevice)) - cpu_abort(cpu_single_env, "SMBus struct too small"); + hw_error("SMBus struct too small"); dev = (SMBusDevice *)i2c_slave_init(bus, address, size); dev->i2c.event = smbus_i2c_event; diff --git a/hw/smbus.h b/hw/smbus.h index 0d35bb68a..b6b066240 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -typedef struct SMBusDevice SMBusDevice; +#include "i2c.h" struct SMBusDevice { /* The SMBus protocol is implemented on top of I2C. */ diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index cf54c34c3..39cf1ce41 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -22,7 +22,9 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "i2c.h" +#include "smbus.h" //#define DEBUG diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 25e6f79c7..410051d3c 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -7,7 +7,9 @@ * This code is licenced under the GPL */ -#include "vl.h" +#include "hw.h" +#include "net.h" +#include "devices.h" /* For crc32 */ #include diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 3c80fd67f..742f2d871 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sparc32_dma.h" +#include "sun4m.h" /* debug DMA */ //#define DEBUG_DMA diff --git a/hw/sparc32_dma.h b/hw/sparc32_dma.h new file mode 100644 index 000000000..00b892164 --- /dev/null +++ b/hw/sparc32_dma.h @@ -0,0 +1,14 @@ +#ifndef SPARC32_DMA_H +#define SPARC32_DMA_H + +/* sparc32_dma.c */ +void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, + void *iommu, qemu_irq **dev_irq, qemu_irq **reset); +void ledma_memory_read(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap); +void ledma_memory_write(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap); +void espdma_memory_read(void *opaque, uint8_t *buf, int len); +void espdma_memory_write(void *opaque, uint8_t *buf, int len); + +#endif diff --git a/hw/spitz.c b/hw/spitz.c index 14be70c70..c82992150 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -7,7 +7,19 @@ * This code is licensed under the GNU GPL v2. */ -#include "vl.h" +#include "hw.h" +#include "pxa.h" +#include "arm-misc.h" +#include "sysemu.h" +#include "pcmcia.h" +#include "i2c.h" +#include "flash.h" +#include "qemu-timer.h" +#include "devices.h" +#include "console.h" +#include "block.h" +#include "audio/audio.h" +#include "boards.h" #define spitz_printf(format, ...) \ fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__) diff --git a/hw/ssd0303.c b/hw/ssd0303.c index 138cfc7fa..383a6232b 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -10,7 +10,9 @@ /* The controller can support a variety of different displays, but we only implement one. Most of the commends relating to brightness and geometry setup are ignored. */ -#include "vl.h" +#include "hw.h" +#include "i2c.h" +#include "console.h" //#define DEBUG_SSD0303 1 diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 67361bce2..8c5ab424e 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -10,7 +10,9 @@ /* The controller can support a variety of different displays, but we only implement one. Most of the commends relating to brightness and geometry setup are ignored. */ -#include "vl.h" +#include "hw.h" +#include "devices.h" +#include "console.h" //#define DEBUG_SSD0323 1 diff --git a/hw/stellaris.c b/hw/stellaris.c index 62f2c0344..cc47b9dbc 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -7,8 +7,14 @@ * This code is licenced under the GPL. */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "arm-misc.h" +#include "primecell.h" +#include "devices.h" +#include "qemu-timer.h" +#include "i2c.h" +#include "sysemu.h" +#include "boards.h" typedef const struct { const char *name; diff --git a/hw/sun4m.c b/hw/sun4m.c index 9f15e45b1..7187956a4 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -21,8 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" -#include "m48t59.h" +#include "hw.h" +#include "qemu-timer.h" +#include "sun4m.h" +#include "nvram.h" +#include "sparc32_dma.h" +#include "fdc.h" +#include "sysemu.h" +#include "net.h" +#include "boards.h" #include "firmware_abi.h" //#define DEBUG_IRQ diff --git a/hw/sun4m.h b/hw/sun4m.h new file mode 100644 index 000000000..12fa83223 --- /dev/null +++ b/hw/sun4m.h @@ -0,0 +1,73 @@ +#ifndef SUN4M_H +#define SUN4M_H + +/* Devices used by sparc32 system. */ + +/* iommu.c */ +void *iommu_init(target_phys_addr_t addr, uint32_t version); +void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int is_write); +static inline void sparc_iommu_memory_read(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, int len) +{ + sparc_iommu_memory_rw(opaque, addr, buf, len, 0); +} + +static inline void sparc_iommu_memory_write(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, int len) +{ + sparc_iommu_memory_rw(opaque, addr, buf, len, 1); +} + +/* tcx.c */ +void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, + unsigned long vram_offset, int vram_size, int width, int height, + int depth); + +/* slavio_intctl.c */ +void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, + const uint32_t *intbit_to_level, + qemu_irq **irq, qemu_irq **cpu_irq, + qemu_irq **parent_irq, unsigned int cputimer); +void slavio_pic_info(void *opaque); +void slavio_irq_info(void *opaque); + +/* slavio_timer.c */ +void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, + qemu_irq *cpu_irqs); + +/* slavio_serial.c */ +SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, + CharDriverState *chr1, CharDriverState *chr2); +void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq); + +/* slavio_misc.c */ +void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, + qemu_irq irq); +void slavio_set_power_fail(void *opaque, int power_failing); + +/* esp.c */ +void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); +void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, + void *dma_opaque, qemu_irq irq, qemu_irq *reset); + +/* cs4231.c */ +void cs_init(target_phys_addr_t base, int irq, void *intctl); + +/* sparc32_dma.c */ +void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, + void *iommu, qemu_irq **dev_irq, qemu_irq **reset); +void ledma_memory_read(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap); +void ledma_memory_write(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap); +void espdma_memory_read(void *opaque, uint8_t *buf, int len); +void espdma_memory_write(void *opaque, uint8_t *buf, int len); + +/* pcnet.c */ +void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, + qemu_irq irq, qemu_irq *reset); + +#endif diff --git a/hw/sun4u.c b/hw/sun4u.c index 588b1c311..336a74c13 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -21,8 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" -#include "m48t59.h" +#include "hw.h" +#include "pci.h" +#include "pc.h" +#include "nvram.h" +#include "fdc.h" +#include "net.h" +#include "qemu-timer.h" +#include "sysemu.h" +#include "boards.h" #include "firmware_abi.h" #define KERNEL_LOAD_ADDR 0x00404000 diff --git a/hw/tc58128.c b/hw/tc58128.c index a8b26f7e8..2cd176b94 100644 --- a/hw/tc58128.c +++ b/hw/tc58128.c @@ -1,5 +1,7 @@ #include -#include "vl.h" +#include "hw.h" +#include "sh.h" +#include "sysemu.h" #define CE1 0x0100 #define CE2 0x0200 diff --git a/hw/tcx.c b/hw/tcx.c index a6c8e4891..22bde4a26 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "sun4m.h" +#include "console.h" #include "pixel_ops.h" #define MAXX 1024 diff --git a/hw/tsc210x.c b/hw/tsc210x.c index 50d3edacd..f04b19d33 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -19,7 +19,11 @@ * MA 02111-1307 USA */ -#include "vl.h" +#include "hw.h" +#include "audio/audio.h" +#include "qemu-timer.h" +#include "console.h" +#include "omap.h" #define TSC_DATA_REGISTERS_PAGE 0x0 #define TSC_CONTROL_REGISTERS_PAGE 0x1 diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 8728f119c..60fdea890 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "ppc_mac.h" +#include "pci.h" + typedef target_phys_addr_t pci_addr_t; #include "pci_host.h" diff --git a/hw/usb-hid.c b/hw/usb-hid.c index aebcf032c..6ea6c4da5 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -22,7 +22,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "console.h" +#include "usb.h" /* HID interface requests */ #define GET_REPORT 0xa101 diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 1dcac3ca6..97c3d0522 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "usb.h" //#define DEBUG diff --git a/hw/usb-msd.c b/hw/usb-msd.c index b1ad9ec09..7ee9cc1da 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -7,7 +7,10 @@ * This code is licenced under the LGPL. */ -#include "vl.h" +#include "qemu-common.h" +#include "usb.h" +#include "block.h" +#include "scsi-disk.h" //#define DEBUG_MSD diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index a85d38e44..255cba7c9 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -27,7 +27,10 @@ * o BIOS work to boot from USB storage */ -#include "vl.h" +#include "hw.h" +#include "qemu-timer.h" +#include "usb.h" +#include "pci.h" //#define DEBUG_OHCI /* Dump packet contents. */ diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 26a079500..1ebe9591e 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "usb.h" +#include "pci.h" +#include "qemu-timer.h" //#define DEBUG //#define DEBUG_PACKET diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index 99b8f9eb7..cc3579c58 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -25,7 +25,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "console.h" +#include "usb.h" /* Interface requests */ #define WACOM_GET_REPORT 0x2101 diff --git a/hw/usb.c b/hw/usb.c index 75e5a808d..be4d66d1f 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "usb.h" void usb_attach(USBPort *port, USBDevice *dev) { diff --git a/hw/usb.h b/hw/usb.h index c5d24f158..e6fd3c066 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -202,15 +202,6 @@ void usb_packet_complete(USBPacket *p); /* usb hub */ USBDevice *usb_hub_init(int nb_ports); -/* usb-uhci.c */ -void usb_uhci_piix3_init(PCIBus *bus, int devfn); -void usb_uhci_piix4_init(PCIBus *bus, int devfn); - -/* usb-ohci.c */ -void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn); -void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn, - qemu_irq irq); - /* usb-linux.c */ USBDevice *usb_host_device_open(const char *devname); void usb_host_info(void); @@ -225,3 +216,11 @@ USBDevice *usb_msd_init(const char *filename); /* usb-wacom.c */ USBDevice *usb_wacom_init(void); + +/* usb ports of the VM */ + +void qemu_register_usb_port(USBPort *port, void *opaque, int index, + usb_attachfn attach); + +#define VM_USB_HUB_SIZE 8 + diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 68f18ef3f..67cee88e8 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -7,7 +7,9 @@ * This code is licenced under the LGPL. */ -#include "vl.h" +#include "hw.h" +#include "pci.h" +#include "primecell.h" static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr) { diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 4e8e76e26..fa5f57a49 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -7,8 +7,14 @@ * This code is licenced under the GPL. */ -#include "vl.h" -#include "arm_pic.h" +#include "hw.h" +#include "arm-misc.h" +#include "primecell.h" +#include "devices.h" +#include "net.h" +#include "sysemu.h" +#include "pci.h" +#include "boards.h" /* Primary interrupt controller. */ diff --git a/hw/vga.c b/hw/vga.c index 4c7d9fff3..3d0841c9d 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "console.h" +#include "pc.h" +#include "pci.h" #include "vga_int.h" #include "pixel_ops.h" diff --git a/hw/vmmouse.c b/hw/vmmouse.c index 3c4f6671b..0a93b15e6 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "console.h" +#include "ps2.h" +#include "pc.h" /* debug only vmmouse */ //#define DEBUG_VMMOUSE diff --git a/hw/vmport.c b/hw/vmport.c index bf56b84c5..8044c9fe6 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -21,8 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" -#include "cpu-all.h" +#include "hw.h" +#include "isa.h" +#include "pc.h" +#include "sysemu.h" #define VMPORT_CMD_GETVERSION 0x0a #define VMPORT_CMD_GETRAMSIZE 0x14 diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index e850952da..7937e071b 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw.h" +#include "console.h" +#include "pci.h" #define VERBOSE #define EMBED_STDVGA diff --git a/hw/wm8750.c b/hw/wm8750.c index b999890ef..245d56fb0 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -7,7 +7,9 @@ * This file is licensed under GNU GPL. */ -#include "vl.h" +#include "hw.h" +#include "i2c.h" +#include "audio/audio.h" #define IN_PORT_N 3 #define OUT_PORT_N 3 diff --git a/loader.c b/loader.c index c39cb5535..18878df8e 100644 --- a/loader.c +++ b/loader.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" #include "disas.h" #include "uboot_image.h" diff --git a/m68k-semi.c b/m68k-semi.c index 76b531924..b083b4828 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -33,7 +33,9 @@ #include "qemu.h" #define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024) #else -#include "vl.h" +#include "qemu-common.h" +#include "sysemu.h" +#include "gdbstub.h" #include "softmmu-semi.h" #endif diff --git a/monitor.c b/monitor.c index ac0c8e872..76ed5f8cf 100644 --- a/monitor.c +++ b/monitor.c @@ -21,7 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw/hw.h" +#include "hw/usb.h" +#include "hw/pcmcia.h" +#include "hw/pc.h" +#include "hw/pci.h" +#include "gdbstub.h" +#include "net.h" +#include "qemu-char.h" +#include "sysemu.h" +#include "console.h" +#include "block.h" +#include "audio/audio.h" #include "disas.h" #include diff --git a/net.h b/net.h new file mode 100644 index 000000000..2dfff8def --- /dev/null +++ b/net.h @@ -0,0 +1,50 @@ +#ifndef QEMU_NET_H +#define QEMU_NET_H + +/* VLANs support */ + +typedef struct VLANClientState VLANClientState; + +struct VLANClientState { + IOReadHandler *fd_read; + /* Packets may still be sent if this returns zero. It's used to + rate-limit the slirp code. */ + IOCanRWHandler *fd_can_read; + void *opaque; + struct VLANClientState *next; + struct VLANState *vlan; + char info_str[256]; +}; + +struct VLANState { + int id; + VLANClientState *first_client; + struct VLANState *next; + unsigned int nb_guest_devs, nb_host_devs; +}; + +VLANState *qemu_find_vlan(int id); +VLANClientState *qemu_new_vlan_client(VLANState *vlan, + IOReadHandler *fd_read, + IOCanRWHandler *fd_can_read, + void *opaque); +int qemu_can_send_packet(VLANClientState *vc); +void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); +void qemu_handler_true(void *opaque); + +void do_info_network(void); + +/* NIC info */ + +#define MAX_NICS 8 + +struct NICInfo { + uint8_t macaddr[6]; + const char *model; + VLANState *vlan; +}; + +extern int nb_nics; +extern NICInfo nd_table[MAX_NICS]; + +#endif diff --git a/osdep.c b/osdep.c index 0eaf2badb..8c2f0a9ec 100644 --- a/osdep.c +++ b/osdep.c @@ -33,10 +33,8 @@ #include #endif -#include "cpu.h" -#if defined(USE_KQEMU) -#include "vl.h" -#endif +#include "qemu-common.h" +#include "sysemu.h" #ifdef _WIN32 #include diff --git a/qemu-char.h b/qemu-char.h new file mode 100644 index 000000000..3f482106e --- /dev/null +++ b/qemu-char.h @@ -0,0 +1,74 @@ +#ifndef QEMU_CHAR_H +#define QEMU_CHAR_H + +/* character device */ + +#define CHR_EVENT_BREAK 0 /* serial break char */ +#define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */ +#define CHR_EVENT_RESET 2 /* new connection established */ + + +#define CHR_IOCTL_SERIAL_SET_PARAMS 1 +typedef struct { + int speed; + int parity; + int data_bits; + int stop_bits; +} QEMUSerialSetParams; + +#define CHR_IOCTL_SERIAL_SET_BREAK 2 + +#define CHR_IOCTL_PP_READ_DATA 3 +#define CHR_IOCTL_PP_WRITE_DATA 4 +#define CHR_IOCTL_PP_READ_CONTROL 5 +#define CHR_IOCTL_PP_WRITE_CONTROL 6 +#define CHR_IOCTL_PP_READ_STATUS 7 +#define CHR_IOCTL_PP_EPP_READ_ADDR 8 +#define CHR_IOCTL_PP_EPP_READ 9 +#define CHR_IOCTL_PP_EPP_WRITE_ADDR 10 +#define CHR_IOCTL_PP_EPP_WRITE 11 + +typedef void IOEventHandler(void *opaque, int event); + +struct CharDriverState { + int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); + void (*chr_update_read_handler)(struct CharDriverState *s); + int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); + IOEventHandler *chr_event; + IOCanRWHandler *chr_can_read; + IOReadHandler *chr_read; + void *handler_opaque; + void (*chr_send_event)(struct CharDriverState *chr, int event); + void (*chr_close)(struct CharDriverState *chr); + void *opaque; + int focus; + QEMUBH *bh; +}; + +CharDriverState *qemu_chr_open(const char *filename); +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); +int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); +void qemu_chr_send_event(CharDriverState *s, int event); +void qemu_chr_add_handlers(CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque); +int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); +void qemu_chr_reset(CharDriverState *s); +int qemu_chr_can_read(CharDriverState *s); +void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); + +/* async I/O support */ + +int qemu_set_fd_handler2(int fd, + IOCanRWHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); +int qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque); + +#endif diff --git a/qemu-common.h b/qemu-common.h index 64f4e78ae..119d1bb32 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -62,6 +62,37 @@ static inline char *realpath(const char *path, char *resolved_path) #endif /* !defined(NEED_CPU_H) */ +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#ifndef likely +#if __GNUC__ < 3 +#define __builtin_expect(x, n) (x) +#endif + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef always_inline +#if (__GNUC__ < 3) || defined(__APPLE__) +#define always_inline inline +#else +#define always_inline __attribute__ (( always_inline )) inline +#endif +#endif + /* bottom halves */ typedef struct QEMUBH QEMUBH; @@ -73,6 +104,8 @@ void qemu_bh_cancel(QEMUBH *bh); void qemu_bh_delete(QEMUBH *bh); int qemu_bh_poll(void); +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); + /* cutils.c */ void pstrcpy(char *buf, int buf_size, const char *str); char *pstrcat(char *buf, int buf_size, const char *s); @@ -80,4 +113,42 @@ int strstart(const char *str, const char *val, const char **ptr); int stristart(const char *str, const char *val, const char **ptr); time_t mktimegm(struct tm *tm); +/* Error handling. */ + +void hw_error(const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))) + __attribute__ ((__noreturn__)); + +/* IO callbacks. */ +typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); +typedef int IOCanRWHandler(void *opaque); +typedef void IOHandler(void *opaque); + +struct ParallelIOArg { + void *buffer; + int count; +}; + +typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); + +/* A load of opaque types so that device init declarations don't have to + pull in all the real definitions. */ +typedef struct NICInfo NICInfo; +typedef struct AudioState AudioState; +typedef struct BlockDriverState BlockDriverState; +typedef struct DisplayState DisplayState; +typedef struct TextConsole TextConsole; +typedef struct CharDriverState CharDriverState; +typedef struct VLANState VLANState; +typedef struct QEMUFile QEMUFile; +typedef struct i2c_bus i2c_bus; +typedef struct i2c_slave i2c_slave; +typedef struct SMBusDevice SMBusDevice; +typedef struct QEMUTimer QEMUTimer; +typedef struct PCIBus PCIBus; +typedef struct PCIDevice PCIDevice; +typedef struct SerialState SerialState; +typedef struct IRQState *qemu_irq; +struct pcmcia_card_s; + #endif diff --git a/qemu-timer.h b/qemu-timer.h new file mode 100644 index 000000000..3f8880ddf --- /dev/null +++ b/qemu-timer.h @@ -0,0 +1,48 @@ +#ifndef QEMU_TIMER_H +#define QEMU_TIMER_H + +/* timers */ + +typedef struct QEMUClock QEMUClock; +typedef void QEMUTimerCB(void *opaque); + +/* The real time clock should be used only for stuff which does not + change the virtual machine state, as it is run even if the virtual + machine is stopped. The real time clock has a frequency of 1000 + Hz. */ +extern QEMUClock *rt_clock; + +/* The virtual clock is only run during the emulation. It is stopped + when the virtual machine is stopped. Virtual timers use a high + precision clock, usually cpu cycles (use ticks_per_sec). */ +extern QEMUClock *vm_clock; + +int64_t qemu_get_clock(QEMUClock *clock); + +QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); +void qemu_free_timer(QEMUTimer *ts); +void qemu_del_timer(QEMUTimer *ts); +void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); +int qemu_timer_pending(QEMUTimer *ts); + +extern int64_t ticks_per_sec; + +void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); +void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); + +/* ptimer.c */ +typedef struct ptimer_state ptimer_state; +typedef void (*ptimer_cb)(void *opaque); + +ptimer_state *ptimer_init(QEMUBH *bh); +void ptimer_set_period(ptimer_state *s, int64_t period); +void ptimer_set_freq(ptimer_state *s, uint32_t freq); +void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload); +uint64_t ptimer_get_count(ptimer_state *s); +void ptimer_set_count(ptimer_state *s, uint64_t count); +void ptimer_run(ptimer_state *s, int oneshot); +void ptimer_stop(ptimer_state *s); +void qemu_put_ptimer(QEMUFile *f, ptimer_state *s); +void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); + +#endif diff --git a/readline.c b/readline.c index de60cfcf5..f690f6e9e 100644 --- a/readline.c +++ b/readline.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "console.h" #define TERM_CMD_BUF_SIZE 4095 #define TERM_MAX_CMDS 64 diff --git a/sdl.c b/sdl.c index cac1a0365..edd173e06 100644 --- a/sdl.c +++ b/sdl.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "console.h" +#include "sysemu.h" #include diff --git a/sysemu.h b/sysemu.h new file mode 100644 index 000000000..d54f115aa --- /dev/null +++ b/sysemu.h @@ -0,0 +1,170 @@ +#ifndef SYSEMU_H +#define SYSEMU_H +/* Misc. things related to the system emulator. */ + +/* vl.c */ +extern const char *bios_name; +extern const char *bios_dir; + +extern int vm_running; +extern const char *qemu_name; + +typedef struct vm_change_state_entry VMChangeStateEntry; +typedef void VMChangeStateHandler(void *opaque, int running); +typedef void VMStopHandler(void *opaque, int reason); + +VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, + void *opaque); +void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); + +int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque); +void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque); + +void vm_start(void); +void vm_stop(int reason); + +int64_t cpu_get_ticks(void); +void cpu_enable_ticks(void); +void cpu_disable_ticks(void); + +void qemu_system_reset_request(void); +void qemu_system_shutdown_request(void); +void qemu_system_powerdown_request(void); +#if !defined(TARGET_SPARC) +// Please implement a power failure function to signal the OS +#define qemu_system_powerdown() do{}while(0) +#else +void qemu_system_powerdown(void); +#endif + +void cpu_save(QEMUFile *f, void *opaque); +int cpu_load(QEMUFile *f, void *opaque, int version_id); + +void do_savevm(const char *name); +void do_loadvm(const char *name); +void do_delvm(const char *name); +void do_info_snapshots(void); + +void main_loop_wait(int timeout); + +/* Polling handling */ + +/* return TRUE if no sleep should be done afterwards */ +typedef int PollingFunc(void *opaque); + +int qemu_add_polling_cb(PollingFunc *func, void *opaque); +void qemu_del_polling_cb(PollingFunc *func, void *opaque); + +#ifdef _WIN32 +/* Wait objects handling */ +typedef void WaitObjectFunc(void *opaque); + +int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); +#endif + +/* TAP win32 */ +int tap_win32_init(VLANState *vlan, const char *ifname); + +/* SLIRP */ +void do_info_slirp(void); + +extern int ram_size; +extern int bios_size; +extern int rtc_utc; +extern int rtc_start_date; +extern int cirrus_vga_enabled; +extern int vmsvga_enabled; +extern int graphic_width; +extern int graphic_height; +extern int graphic_depth; +extern const char *keyboard_layout; +extern int win2k_install_hack; +extern int alt_grab; +extern int usb_enabled; +extern int smp_cpus; +extern int cursor_hide; +extern int graphic_rotate; +extern int no_quit; +extern int semihosting_enabled; +extern int autostart; +extern int old_param; +extern const char *bootp_filename; + + +#ifdef USE_KQEMU +extern int kqemu_allowed; +#endif + +#define MAX_OPTION_ROMS 16 +extern const char *option_rom[MAX_OPTION_ROMS]; +extern int nb_option_roms; + +#ifdef TARGET_SPARC +#define MAX_PROM_ENVS 128 +extern const char *prom_envs[MAX_PROM_ENVS]; +extern unsigned int nb_prom_envs; +#endif + +/* XXX: make it dynamic */ +#define MAX_BIOS_SIZE (4 * 1024 * 1024) +#if defined (TARGET_PPC) +#define BIOS_SIZE (1024 * 1024) +#elif defined (TARGET_SPARC64) +#define BIOS_SIZE ((512 + 32) * 1024) +#elif defined(TARGET_MIPS) +#define BIOS_SIZE (4 * 1024 * 1024) +#endif + +#define MAX_DISKS 4 + +extern BlockDriverState *bs_table[MAX_DISKS + 1]; +extern BlockDriverState *sd_bdrv; +extern BlockDriverState *mtd_bdrv; + +/* NOR flash devices */ +#define MAX_PFLASH 4 +extern BlockDriverState *pflash_table[MAX_PFLASH]; + +/* serial ports */ + +#define MAX_SERIAL_PORTS 4 + +extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; + +/* parallel ports */ + +#define MAX_PARALLEL_PORTS 3 + +extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; + +#ifdef NEED_CPU_H +/* loader.c */ +int get_image_size(const char *filename); +int load_image(const char *filename, uint8_t *addr); +int load_elf(const char *filename, int64_t virt_to_phys_addend, + uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr); +int load_aout(const char *filename, uint8_t *addr); +int load_uboot(const char *filename, target_ulong *ep, int *is_linux); +#endif + +#ifdef HAS_AUDIO +struct soundhw { + const char *name; + const char *descr; + int enabled; + int isa; + union { + int (*init_isa) (AudioState *s, qemu_irq *pic); + int (*init_pci) (PCIBus *bus, AudioState *s); + } init; +}; + +extern struct soundhw soundhw[]; +#endif + +void do_usb_add(const char *devname); +void do_usb_del(const char *devname); +void usb_info(void); + +#endif diff --git a/tap-win32.c b/tap-win32.c index c900b4b76..694441eee 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -26,7 +26,9 @@ * distribution); if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "vl.h" +#include "qemu-common.h" +#include "net.h" +#include "sysemu.h" #include #include diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 3ddda872e..0ebc365e2 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -604,3 +604,34 @@ void memcpy32(target_ulong *dst, const target_ulong *src) dst[6] = src[6]; dst[7] = src[7]; } + +#ifdef TARGET_SPARC64 +#if !defined(CONFIG_USER_ONLY) +#include "qemu-common.h" +#include "hw/irq.h" +#include "qemu-timer.h" +#endif + +void do_tick_set_count(void *opaque, uint64_t count) +{ +#if !defined(CONFIG_USER_ONLY) + ptimer_set_count(opaque, -count); +#endif +} + +uint64_t do_tick_get_count(void *opaque) +{ +#if !defined(CONFIG_USER_ONLY) + return -ptimer_get_count(opaque); +#else + return 0; +#endif +} + +void do_tick_set_limit(void *opaque, uint64_t limit) +{ +#if !defined(CONFIG_USER_ONLY) + ptimer_set_limit(opaque, -limit, 0); +#endif +} +#endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 279c4b948..699a305b2 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1804,27 +1804,3 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, } #endif -#ifdef TARGET_SPARC64 -void do_tick_set_count(void *opaque, uint64_t count) -{ -#if !defined(CONFIG_USER_ONLY) - ptimer_set_count(opaque, -count); -#endif -} - -uint64_t do_tick_get_count(void *opaque) -{ -#if !defined(CONFIG_USER_ONLY) - return -ptimer_get_count(opaque); -#else - return 0; -#endif -} - -void do_tick_set_limit(void *opaque, uint64_t limit) -{ -#if !defined(CONFIG_USER_ONLY) - ptimer_set_limit(opaque, -limit, 0); -#endif -} -#endif diff --git a/usb-linux.c b/usb-linux.c index 00864f08b..d6a2b8b6a 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -21,7 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "hw/usb.h" +#include "console.h" #if defined(__linux__) #include diff --git a/vl.c b/vl.c index b9c97b035..783b3cf5a 100644 --- a/vl.c +++ b/vl.c @@ -21,7 +21,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/usb.h" +#include "hw/pcmcia.h" +#include "hw/pc.h" +#include "hw/fdc.h" +#include "hw/audiodev.h" +#include "hw/isa.h" +#include "net.h" +#include "console.h" +#include "sysemu.h" +#include "gdbstub.h" +#include "qemu-timer.h" +#include "qemu-char.h" +#include "block.h" +#include "audio/audio.h" #include #include diff --git a/vl.h b/vl.h deleted file mode 100644 index 326f92f29..000000000 --- a/vl.h +++ /dev/null @@ -1,1538 +0,0 @@ -/* - * QEMU System Emulator header - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef VL_H -#define VL_H - -#include "qemu-common.h" - -/* FIXME: Remove this. */ -#include "block.h" - -#ifndef glue -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s -#endif - -#ifndef likely -#if __GNUC__ < 3 -#define __builtin_expect(x, n) (x) -#endif - -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#endif - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef always_inline -#if (__GNUC__ < 3) || defined(__APPLE__) -#define always_inline inline -#else -#define always_inline __attribute__ (( always_inline )) inline -#endif -#endif - -#include "audio/audio.h" - -/* vl.c */ -uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); - -void hw_error(const char *fmt, ...); - -extern const char *bios_dir; -extern const char *bios_name; - -extern int vm_running; -extern const char *qemu_name; - -typedef struct vm_change_state_entry VMChangeStateEntry; -typedef void VMChangeStateHandler(void *opaque, int running); -typedef void VMStopHandler(void *opaque, int reason); - -VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, - void *opaque); -void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); - -int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque); -void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque); - -void vm_start(void); -void vm_stop(int reason); - -typedef void QEMUResetHandler(void *opaque); - -void qemu_register_reset(QEMUResetHandler *func, void *opaque); -void qemu_system_reset_request(void); -void qemu_system_shutdown_request(void); -void qemu_system_powerdown_request(void); -#if !defined(TARGET_SPARC) -// Please implement a power failure function to signal the OS -#define qemu_system_powerdown() do{}while(0) -#else -void qemu_system_powerdown(void); -#endif - -void main_loop_wait(int timeout); - -extern int ram_size; -extern int bios_size; -extern int rtc_utc; -extern int rtc_start_date; -extern int cirrus_vga_enabled; -extern int vmsvga_enabled; -extern int graphic_width; -extern int graphic_height; -extern int graphic_depth; -extern const char *keyboard_layout; -extern int kqemu_allowed; -extern int win2k_install_hack; -extern int alt_grab; -extern int usb_enabled; -extern int smp_cpus; -extern int cursor_hide; -extern int graphic_rotate; -extern int no_quit; -extern int semihosting_enabled; -extern int autostart; -extern int old_param; -extern const char *bootp_filename; - -#define MAX_OPTION_ROMS 16 -extern const char *option_rom[MAX_OPTION_ROMS]; -extern int nb_option_roms; - -#ifdef TARGET_SPARC -#define MAX_PROM_ENVS 128 -extern const char *prom_envs[MAX_PROM_ENVS]; -extern unsigned int nb_prom_envs; -#endif - -/* XXX: make it dynamic */ -#define MAX_BIOS_SIZE (4 * 1024 * 1024) -#if defined (TARGET_PPC) -#define BIOS_SIZE (1024 * 1024) -#elif defined (TARGET_SPARC64) -#define BIOS_SIZE ((512 + 32) * 1024) -#elif defined(TARGET_MIPS) -#define BIOS_SIZE (4 * 1024 * 1024) -#endif - -/* keyboard/mouse support */ - -#define MOUSE_EVENT_LBUTTON 0x01 -#define MOUSE_EVENT_RBUTTON 0x02 -#define MOUSE_EVENT_MBUTTON 0x04 - -typedef void QEMUPutKBDEvent(void *opaque, int keycode); -typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); - -typedef struct QEMUPutMouseEntry { - QEMUPutMouseEvent *qemu_put_mouse_event; - void *qemu_put_mouse_event_opaque; - int qemu_put_mouse_event_absolute; - char *qemu_put_mouse_event_name; - - /* used internally by qemu for handling mice */ - struct QEMUPutMouseEntry *next; -} QEMUPutMouseEntry; - -void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); -QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, - void *opaque, int absolute, - const char *name); -void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry); - -void kbd_put_keycode(int keycode); -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); -int kbd_mouse_is_absolute(void); - -void do_info_mice(void); -void do_mouse_set(int index); - -/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx - constants) */ -#define QEMU_KEY_ESC1(c) ((c) | 0xe100) -#define QEMU_KEY_BACKSPACE 0x007f -#define QEMU_KEY_UP QEMU_KEY_ESC1('A') -#define QEMU_KEY_DOWN QEMU_KEY_ESC1('B') -#define QEMU_KEY_RIGHT QEMU_KEY_ESC1('C') -#define QEMU_KEY_LEFT QEMU_KEY_ESC1('D') -#define QEMU_KEY_HOME QEMU_KEY_ESC1(1) -#define QEMU_KEY_END QEMU_KEY_ESC1(4) -#define QEMU_KEY_PAGEUP QEMU_KEY_ESC1(5) -#define QEMU_KEY_PAGEDOWN QEMU_KEY_ESC1(6) -#define QEMU_KEY_DELETE QEMU_KEY_ESC1(3) - -#define QEMU_KEY_CTRL_UP 0xe400 -#define QEMU_KEY_CTRL_DOWN 0xe401 -#define QEMU_KEY_CTRL_LEFT 0xe402 -#define QEMU_KEY_CTRL_RIGHT 0xe403 -#define QEMU_KEY_CTRL_HOME 0xe404 -#define QEMU_KEY_CTRL_END 0xe405 -#define QEMU_KEY_CTRL_PAGEUP 0xe406 -#define QEMU_KEY_CTRL_PAGEDOWN 0xe407 - -void kbd_put_keysym(int keysym); - -/* async I/O support */ - -typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); -typedef int IOCanRWHandler(void *opaque); -typedef void IOHandler(void *opaque); - -int qemu_set_fd_handler2(int fd, - IOCanRWHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque); -int qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque); - -/* Polling handling */ - -/* return TRUE if no sleep should be done afterwards */ -typedef int PollingFunc(void *opaque); - -int qemu_add_polling_cb(PollingFunc *func, void *opaque); -void qemu_del_polling_cb(PollingFunc *func, void *opaque); - -#ifdef _WIN32 -/* Wait objects handling */ -typedef void WaitObjectFunc(void *opaque); - -int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); -void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque); -#endif - -/* character device */ - -#define CHR_EVENT_BREAK 0 /* serial break char */ -#define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */ -#define CHR_EVENT_RESET 2 /* new connection established */ - - -#define CHR_IOCTL_SERIAL_SET_PARAMS 1 -typedef struct { - int speed; - int parity; - int data_bits; - int stop_bits; -} QEMUSerialSetParams; - -#define CHR_IOCTL_SERIAL_SET_BREAK 2 - -#define CHR_IOCTL_PP_READ_DATA 3 -#define CHR_IOCTL_PP_WRITE_DATA 4 -#define CHR_IOCTL_PP_READ_CONTROL 5 -#define CHR_IOCTL_PP_WRITE_CONTROL 6 -#define CHR_IOCTL_PP_READ_STATUS 7 -#define CHR_IOCTL_PP_EPP_READ_ADDR 8 -#define CHR_IOCTL_PP_EPP_READ 9 -#define CHR_IOCTL_PP_EPP_WRITE_ADDR 10 -#define CHR_IOCTL_PP_EPP_WRITE 11 - -typedef void IOEventHandler(void *opaque, int event); - -typedef struct CharDriverState { - int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); - void (*chr_update_read_handler)(struct CharDriverState *s); - int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); - IOEventHandler *chr_event; - IOCanRWHandler *chr_can_read; - IOReadHandler *chr_read; - void *handler_opaque; - void (*chr_send_event)(struct CharDriverState *chr, int event); - void (*chr_close)(struct CharDriverState *chr); - void *opaque; - int focus; - QEMUBH *bh; -} CharDriverState; - -CharDriverState *qemu_chr_open(const char *filename); -void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); -int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); -void qemu_chr_send_event(CharDriverState *s, int event); -void qemu_chr_add_handlers(CharDriverState *s, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, - IOEventHandler *fd_event, - void *opaque); -int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); -void qemu_chr_reset(CharDriverState *s); -int qemu_chr_can_read(CharDriverState *s); -void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); - -/* consoles */ - -typedef struct DisplayState DisplayState; -typedef struct TextConsole TextConsole; - -struct DisplayState { - uint8_t *data; - int linesize; - int depth; - int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */ - int width; - int height; - void *opaque; - struct QEMUTimer *gui_timer; - - void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); - void (*dpy_resize)(struct DisplayState *s, int w, int h); - void (*dpy_refresh)(struct DisplayState *s); - void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, - int dst_x, int dst_y, int w, int h); - void (*dpy_fill)(struct DisplayState *s, int x, int y, - int w, int h, uint32_t c); - void (*mouse_set)(int x, int y, int on); - void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, - uint8_t *image, uint8_t *mask); -}; - -static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) -{ - s->dpy_update(s, x, y, w, h); -} - -static inline void dpy_resize(DisplayState *s, int w, int h) -{ - s->dpy_resize(s, w, h); -} - -typedef void (*vga_hw_update_ptr)(void *); -typedef void (*vga_hw_invalidate_ptr)(void *); -typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); - -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); -void vga_hw_update(void); -void vga_hw_invalidate(void); -void vga_hw_screen_dump(const char *filename); - -int is_graphic_console(void); -CharDriverState *text_console_init(DisplayState *ds, const char *p); -void console_select(unsigned int index); -void console_color_init(DisplayState *ds); - -/* serial ports */ - -#define MAX_SERIAL_PORTS 4 - -extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; - -/* parallel ports */ - -#define MAX_PARALLEL_PORTS 3 - -extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; - -struct ParallelIOArg { - void *buffer; - int count; -}; - -/* VLANs support */ - -typedef struct VLANClientState VLANClientState; - -struct VLANClientState { - IOReadHandler *fd_read; - /* Packets may still be sent if this returns zero. It's used to - rate-limit the slirp code. */ - IOCanRWHandler *fd_can_read; - void *opaque; - struct VLANClientState *next; - struct VLANState *vlan; - char info_str[256]; -}; - -typedef struct VLANState { - int id; - VLANClientState *first_client; - struct VLANState *next; - unsigned int nb_guest_devs, nb_host_devs; -} VLANState; - -VLANState *qemu_find_vlan(int id); -VLANClientState *qemu_new_vlan_client(VLANState *vlan, - IOReadHandler *fd_read, - IOCanRWHandler *fd_can_read, - void *opaque); -int qemu_can_send_packet(VLANClientState *vc); -void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); -void qemu_handler_true(void *opaque); - -void do_info_network(void); - -/* TAP win32 */ -int tap_win32_init(VLANState *vlan, const char *ifname); - -/* NIC info */ - -#define MAX_NICS 8 - -typedef struct NICInfo { - uint8_t macaddr[6]; - const char *model; - VLANState *vlan; -} NICInfo; - -extern int nb_nics; -extern NICInfo nd_table[MAX_NICS]; - -/* SLIRP */ -void do_info_slirp(void); - -/* timers */ - -typedef struct QEMUClock QEMUClock; -typedef struct QEMUTimer QEMUTimer; -typedef void QEMUTimerCB(void *opaque); - -/* The real time clock should be used only for stuff which does not - change the virtual machine state, as it is run even if the virtual - machine is stopped. The real time clock has a frequency of 1000 - Hz. */ -extern QEMUClock *rt_clock; - -/* The virtual clock is only run during the emulation. It is stopped - when the virtual machine is stopped. Virtual timers use a high - precision clock, usually cpu cycles (use ticks_per_sec). */ -extern QEMUClock *vm_clock; - -int64_t qemu_get_clock(QEMUClock *clock); - -QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); -void qemu_free_timer(QEMUTimer *ts); -void qemu_del_timer(QEMUTimer *ts); -void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); -int qemu_timer_pending(QEMUTimer *ts); - -extern int64_t ticks_per_sec; - -int64_t cpu_get_ticks(void); -void cpu_enable_ticks(void); -void cpu_disable_ticks(void); - -/* VM Load/Save */ - -typedef struct QEMUFile QEMUFile; - -QEMUFile *qemu_fopen(const char *filename, const char *mode); -void qemu_fflush(QEMUFile *f); -void qemu_fclose(QEMUFile *f); -void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); -void qemu_put_byte(QEMUFile *f, int v); -void qemu_put_be16(QEMUFile *f, unsigned int v); -void qemu_put_be32(QEMUFile *f, unsigned int v); -void qemu_put_be64(QEMUFile *f, uint64_t v); -int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); -int qemu_get_byte(QEMUFile *f); -unsigned int qemu_get_be16(QEMUFile *f); -unsigned int qemu_get_be32(QEMUFile *f); -uint64_t qemu_get_be64(QEMUFile *f); - -static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) -{ - qemu_put_be64(f, *pv); -} - -static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv) -{ - qemu_put_be32(f, *pv); -} - -static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv) -{ - qemu_put_be16(f, *pv); -} - -static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv) -{ - qemu_put_byte(f, *pv); -} - -static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv) -{ - *pv = qemu_get_be64(f); -} - -static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv) -{ - *pv = qemu_get_be32(f); -} - -static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv) -{ - *pv = qemu_get_be16(f); -} - -static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv) -{ - *pv = qemu_get_byte(f); -} - -#if TARGET_LONG_BITS == 64 -#define qemu_put_betl qemu_put_be64 -#define qemu_get_betl qemu_get_be64 -#define qemu_put_betls qemu_put_be64s -#define qemu_get_betls qemu_get_be64s -#else -#define qemu_put_betl qemu_put_be32 -#define qemu_get_betl qemu_get_be32 -#define qemu_put_betls qemu_put_be32s -#define qemu_get_betls qemu_get_be32s -#endif - -int64_t qemu_ftell(QEMUFile *f); -int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); - -typedef void SaveStateHandler(QEMUFile *f, void *opaque); -typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); - -int register_savevm(const char *idstr, - int instance_id, - int version_id, - SaveStateHandler *save_state, - LoadStateHandler *load_state, - void *opaque); -void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); -void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); - -void cpu_save(QEMUFile *f, void *opaque); -int cpu_load(QEMUFile *f, void *opaque, int version_id); - -void do_savevm(const char *name); -void do_loadvm(const char *name); -void do_delvm(const char *name); -void do_info_snapshots(void); - -/* monitor.c */ -void monitor_init(CharDriverState *hd, int show_banner); -void term_puts(const char *str); -void term_vprintf(const char *fmt, va_list ap); -void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); -void term_print_filename(const char *filename); -void term_flush(void); -void term_print_help(void); -void monitor_readline(const char *prompt, int is_password, - char *buf, int buf_size); - -/* readline.c */ -typedef void ReadLineFunc(void *opaque, const char *str); - -extern int completion_index; -void add_completion(const char *str); -void readline_handle_byte(int ch); -void readline_find_completion(const char *cmdline); -const char *readline_get_history(unsigned int index); -void readline_start(const char *prompt, int is_password, - ReadLineFunc *readline_func, void *opaque); - -void kqemu_record_dump(void); - -/* sdl.c */ -void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); - -/* cocoa.m */ -void cocoa_display_init(DisplayState *ds, int full_screen); - -/* vnc.c */ -void vnc_display_init(DisplayState *ds); -void vnc_display_close(DisplayState *ds); -int vnc_display_open(DisplayState *ds, const char *display); -int vnc_display_password(DisplayState *ds, const char *password); -void do_info_vnc(void); - -/* x_keymap.c */ -extern uint8_t _translate_keycode(const int key); - -#ifdef NEED_CPU_H - -typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, - const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model); - -typedef struct QEMUMachine { - const char *name; - const char *desc; - QEMUMachineInitFunc *init; - struct QEMUMachine *next; -} QEMUMachine; - -int qemu_register_machine(QEMUMachine *m); - -typedef void SetIRQFunc(void *opaque, int irq_num, int level); - -#include "hw/irq.h" - -/* ISA bus */ - -extern target_phys_addr_t isa_mem_base; - -typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); -typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); - -int register_ioport_read(int start, int length, int size, - IOPortReadFunc *func, void *opaque); -int register_ioport_write(int start, int length, int size, - IOPortWriteFunc *func, void *opaque); -void isa_unassign_ioport(int start, int length); - -void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size); - -/* PCI bus */ - -extern target_phys_addr_t pci_mem_base; - -typedef struct PCIBus PCIBus; -typedef struct PCIDevice PCIDevice; - -typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, - uint32_t address, uint32_t data, int len); -typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, - uint32_t address, int len); -typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type); - -#define PCI_ADDRESS_SPACE_MEM 0x00 -#define PCI_ADDRESS_SPACE_IO 0x01 -#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08 - -typedef struct PCIIORegion { - uint32_t addr; /* current PCI mapping address. -1 means not mapped */ - uint32_t size; - uint8_t type; - PCIMapIORegionFunc *map_func; -} PCIIORegion; - -#define PCI_ROM_SLOT 6 -#define PCI_NUM_REGIONS 7 - -#define PCI_DEVICES_MAX 64 - -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -struct PCIDevice { - /* PCI config space */ - uint8_t config[256]; - - /* the following fields are read only */ - PCIBus *bus; - int devfn; - char name[64]; - PCIIORegion io_regions[PCI_NUM_REGIONS]; - - /* do not access the following fields */ - PCIConfigReadFunc *config_read; - PCIConfigWriteFunc *config_write; - /* ??? This is a PC-specific hack, and should be removed. */ - int irq_index; - - /* IRQ objects for the INTA-INTD pins. */ - qemu_irq *irq; - - /* Current IRQ levels. Used internally by the generic PCI code. */ - int irq_state[4]; -}; - -PCIDevice *pci_register_device(PCIBus *bus, const char *name, - int instance_size, int devfn, - PCIConfigReadFunc *config_read, - PCIConfigWriteFunc *config_write); - -void pci_register_io_region(PCIDevice *pci_dev, int region_num, - uint32_t size, int type, - PCIMapIORegionFunc *map_func); - -uint32_t pci_default_read_config(PCIDevice *d, - uint32_t address, int len); -void pci_default_write_config(PCIDevice *d, - uint32_t address, uint32_t val, int len); -void pci_device_save(PCIDevice *s, QEMUFile *f); -int pci_device_load(PCIDevice *s, QEMUFile *f); - -typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level); -typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); -PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, - qemu_irq *pic, int devfn_min, int nirq); - -void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn); -void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); -uint32_t pci_data_read(void *opaque, uint32_t addr, int len); -int pci_bus_num(PCIBus *s); -void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d)); - -void pci_info(void); -PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, - pci_map_irq_fn map_irq, const char *name); - -/* prep_pci.c */ -PCIBus *pci_prep_init(qemu_irq *pic); - -/* apb_pci.c */ -PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base, - qemu_irq *pic); - -PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview); - -/* piix_pci.c */ -PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic); -void i440fx_set_smm(PCIDevice *d, int val); -int piix3_init(PCIBus *bus, int devfn); -void i440fx_init_memory_mappings(PCIDevice *d); - -int piix4_init(PCIBus *bus, int devfn); - -/* openpic.c */ -/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ -enum { - OPENPIC_OUTPUT_INT = 0, /* IRQ */ - OPENPIC_OUTPUT_CINT, /* critical IRQ */ - OPENPIC_OUTPUT_MCK, /* Machine check event */ - OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ - OPENPIC_OUTPUT_RESET, /* Core reset event */ - OPENPIC_OUTPUT_NB, -}; -qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, - qemu_irq **irqs, qemu_irq irq_out); - -/* gt64xxx.c */ -PCIBus *pci_gt64120_init(qemu_irq *pic); - -#ifdef HAS_AUDIO -struct soundhw { - const char *name; - const char *descr; - int enabled; - int isa; - union { - int (*init_isa) (AudioState *s, qemu_irq *pic); - int (*init_pci) (PCIBus *bus, AudioState *s); - } init; -}; - -extern struct soundhw soundhw[]; -#endif - -/* vga.c */ - -#ifndef TARGET_SPARC -#define VGA_RAM_SIZE (8192 * 1024) -#else -#define VGA_RAM_SIZE (9 * 1024 * 1024) -#endif - -int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size); -int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size, - unsigned long vga_bios_offset, int vga_bios_size); -int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size, - target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, - int it_shift); - -/* cirrus_vga.c */ -void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size); -void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size); - -/* vmware_vga.c */ -void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size); - -/* ide.c */ -#define MAX_DISKS 4 - -extern BlockDriverState *bs_table[MAX_DISKS + 1]; -extern BlockDriverState *sd_bdrv; -extern BlockDriverState *mtd_bdrv; - -void isa_ide_init(int iobase, int iobase2, qemu_irq irq, - BlockDriverState *hd0, BlockDriverState *hd1); -void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, - int secondary_ide_enabled); -void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, - qemu_irq *pic); -void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, - qemu_irq *pic); - -/* cdrom.c */ -int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); -int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); - -/* ds1225y.c */ -typedef struct ds1225y_t ds1225y_t; -ds1225y_t *ds1225y_init(target_phys_addr_t mem_base, const char *filename); - -/* es1370.c */ -int es1370_init (PCIBus *bus, AudioState *s); - -/* sb16.c */ -int SB16_init (AudioState *s, qemu_irq *pic); - -/* adlib.c */ -int Adlib_init (AudioState *s, qemu_irq *pic); - -/* gus.c */ -int GUS_init (AudioState *s, qemu_irq *pic); - -/* dma.c */ -typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size); -int DMA_get_channel_mode (int nchan); -int DMA_read_memory (int nchan, void *buf, int pos, int size); -int DMA_write_memory (int nchan, void *buf, int pos, int size); -void DMA_hold_DREQ (int nchan); -void DMA_release_DREQ (int nchan); -void DMA_schedule(int nchan); -void DMA_run (void); -void DMA_init (int high_page_enable); -void DMA_register_channel (int nchan, - DMA_transfer_handler transfer_handler, - void *opaque); -/* fdc.c */ -#define MAX_FD 2 -extern BlockDriverState *fd_table[MAX_FD]; - -typedef struct fdctrl_t fdctrl_t; - -fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, - target_phys_addr_t io_base, - BlockDriverState **fds); -fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, - BlockDriverState **fds); -int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); - -/* eepro100.c */ - -void pci_i82551_init(PCIBus *bus, NICInfo *nd, int devfn); -void pci_i82557b_init(PCIBus *bus, NICInfo *nd, int devfn); -void pci_i82559er_init(PCIBus *bus, NICInfo *nd, int devfn); - -/* ne2000.c */ - -void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd); -void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn); - -/* rtl8139.c */ - -void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn); - -/* pcnet.c */ - -void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn); -void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, - qemu_irq irq, qemu_irq *reset); - -/* mipsnet.c */ -void mipsnet_init(int base, qemu_irq irq, NICInfo *nd); - -/* vmmouse.c */ -void *vmmouse_init(void *m); - -/* vmport.c */ -#ifdef TARGET_I386 -void vmport_init(CPUState *env); -void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque); -#endif - -/* pckbd.c */ - -void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); -void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, - target_phys_addr_t base, int it_shift); - -/* mc146818rtc.c */ - -typedef struct RTCState RTCState; - -RTCState *rtc_init(int base, qemu_irq irq); -RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq); -void rtc_set_memory(RTCState *s, int addr, int val); -void rtc_set_date(RTCState *s, const struct tm *tm); - -/* serial.c */ - -typedef struct SerialState SerialState; -SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr); -SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, - qemu_irq irq, CharDriverState *chr, - int ioregister); -uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr); -void serial_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value); -uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr); -void serial_mm_writew (void *opaque, target_phys_addr_t addr, uint32_t value); -uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr); -void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value); - -/* parallel.c */ - -typedef struct ParallelState ParallelState; -ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr); -ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr); - -/* i8259.c */ - -typedef struct PicState2 PicState2; -extern PicState2 *isa_pic; -void pic_set_irq(int irq, int level); -void pic_set_irq_new(void *opaque, int irq, int level); -qemu_irq *i8259_init(qemu_irq parent_irq); -void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, - void *alt_irq_opaque); -int pic_read_irq(PicState2 *s); -void pic_update_irq(PicState2 *s); -uint32_t pic_intack_read(PicState2 *s); -void pic_info(void); -void irq_info(void); - -/* APIC */ -typedef struct IOAPICState IOAPICState; - -int apic_init(CPUState *env); -int apic_accept_pic_intr(CPUState *env); -int apic_get_interrupt(CPUState *env); -IOAPICState *ioapic_init(void); -void ioapic_set_irq(void *opaque, int vector, int level); - -/* i8254.c */ - -#define PIT_FREQ 1193182 - -typedef struct PITState PITState; - -PITState *pit_init(int base, qemu_irq irq); -void pit_set_gate(PITState *pit, int channel, int val); -int pit_get_gate(PITState *pit, int channel); -int pit_get_initial_count(PITState *pit, int channel); -int pit_get_mode(PITState *pit, int channel); -int pit_get_out(PITState *pit, int channel, int64_t current_time); - -/* jazz_led.c */ -extern void jazz_led_init(DisplayState *ds, target_phys_addr_t base); - -/* pcspk.c */ -void pcspk_init(PITState *); -int pcspk_audio_init(AudioState *, qemu_irq *pic); - -#include "hw/i2c.h" - -#include "hw/smbus.h" - -/* acpi.c */ -extern int acpi_enabled; -i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base); -void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr); -void acpi_bios_init(void); - -/* Axis ETRAX. */ -extern QEMUMachine bareetraxfs_machine; - -/* pc.c */ -extern QEMUMachine pc_machine; -extern QEMUMachine isapc_machine; -extern int fd_bootchk; - -void ioport_set_a20(int enable); -int ioport_get_a20(void); - -/* ppc.c */ -extern QEMUMachine prep_machine; -extern QEMUMachine core99_machine; -extern QEMUMachine heathrow_machine; -extern QEMUMachine ref405ep_machine; -extern QEMUMachine taihu_machine; - -/* mips_r4k.c */ -extern QEMUMachine mips_machine; - -/* mips_malta.c */ -extern QEMUMachine mips_malta_machine; - -/* mips_pica61.c */ -extern QEMUMachine mips_pica61_machine; - -/* mips_mipssim.c */ -extern QEMUMachine mips_mipssim_machine; - -/* mips_int.c */ -extern void cpu_mips_irq_init_cpu(CPUState *env); - -/* mips_timer.c */ -extern void cpu_mips_clock_init(CPUState *); -extern void cpu_mips_irqctrl_init (void); - -/* shix.c */ -extern QEMUMachine shix_machine; - -/* r2d.c */ -extern QEMUMachine r2d_machine; - -#ifdef TARGET_PPC -/* PowerPC hardware exceptions management helpers */ -typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); -typedef struct clk_setup_t clk_setup_t; -struct clk_setup_t { - clk_setup_cb cb; - void *opaque; -}; -static inline void clk_setup (clk_setup_t *clk, uint32_t freq) -{ - if (clk->cb != NULL) - (*clk->cb)(clk->opaque, freq); -} - -clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq); -/* Embedded PowerPC DCR management */ -typedef target_ulong (*dcr_read_cb)(void *opaque, int dcrn); -typedef void (*dcr_write_cb)(void *opaque, int dcrn, target_ulong val); -int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn), - int (*dcr_write_error)(int dcrn)); -int ppc_dcr_register (CPUState *env, int dcrn, void *opaque, - dcr_read_cb drc_read, dcr_write_cb dcr_write); -clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq); -/* Embedded PowerPC reset */ -void ppc40x_core_reset (CPUState *env); -void ppc40x_chip_reset (CPUState *env); -void ppc40x_system_reset (CPUState *env); -void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); - -extern CPUWriteMemoryFunc *PPC_io_write[]; -extern CPUReadMemoryFunc *PPC_io_read[]; -void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); -#endif - -/* sun4m.c */ -extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine; - -/* iommu.c */ -void *iommu_init(target_phys_addr_t addr, uint32_t version); -void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int is_write); -static inline void sparc_iommu_memory_read(void *opaque, - target_phys_addr_t addr, - uint8_t *buf, int len) -{ - sparc_iommu_memory_rw(opaque, addr, buf, len, 0); -} - -static inline void sparc_iommu_memory_write(void *opaque, - target_phys_addr_t addr, - uint8_t *buf, int len) -{ - sparc_iommu_memory_rw(opaque, addr, buf, len, 1); -} - -/* tcx.c */ -void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, - unsigned long vram_offset, int vram_size, int width, int height, - int depth); - -/* slavio_intctl.c */ -void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, - const uint32_t *intbit_to_level, - qemu_irq **irq, qemu_irq **cpu_irq, - qemu_irq **parent_irq, unsigned int cputimer); -void slavio_pic_info(void *opaque); -void slavio_irq_info(void *opaque); - -/* loader.c */ -int get_image_size(const char *filename); -int load_image(const char *filename, uint8_t *addr); -int load_elf(const char *filename, int64_t virt_to_phys_addend, - uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr); -int load_aout(const char *filename, uint8_t *addr); -int load_uboot(const char *filename, target_ulong *ep, int *is_linux); - -/* slavio_timer.c */ -void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, - qemu_irq *cpu_irqs); - -/* slavio_serial.c */ -SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, - CharDriverState *chr1, CharDriverState *chr2); -void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq); - -/* slavio_misc.c */ -void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, - qemu_irq irq); -void slavio_set_power_fail(void *opaque, int power_failing); - -/* esp.c */ -void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); -void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, - void *dma_opaque, qemu_irq irq, qemu_irq *reset); - -/* sparc32_dma.c */ -void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, - void *iommu, qemu_irq **dev_irq, qemu_irq **reset); -void ledma_memory_read(void *opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap); -void ledma_memory_write(void *opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap); -void espdma_memory_read(void *opaque, uint8_t *buf, int len); -void espdma_memory_write(void *opaque, uint8_t *buf, int len); - -/* cs4231.c */ -void cs_init(target_phys_addr_t base, int irq, void *intctl); - -/* sun4u.c */ -extern QEMUMachine sun4u_machine; - -/* NVRAM helpers */ -typedef uint32_t (*nvram_read_t)(void *private, uint32_t addr); -typedef void (*nvram_write_t)(void *private, uint32_t addr, uint32_t val); -typedef struct nvram_t { - void *opaque; - nvram_read_t read_fn; - nvram_write_t write_fn; -} nvram_t; - -#include "hw/m48t59.h" - -void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value); -uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr); -void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value); -uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr); -void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value); -uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr); -void NVRAM_set_string (nvram_t *nvram, uint32_t addr, - const unsigned char *str, uint32_t max); -int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max); -void NVRAM_set_crc (nvram_t *nvram, uint32_t addr, - uint32_t start, uint32_t count); -int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, - const unsigned char *arch, - uint32_t RAM_size, int boot_device, - uint32_t kernel_image, uint32_t kernel_size, - const char *cmdline, - uint32_t initrd_image, uint32_t initrd_size, - uint32_t NVRAM_image, - int width, int height, int depth); - -/* adb.c */ - -#define MAX_ADB_DEVICES 16 - -#define ADB_MAX_OUT_LEN 16 - -typedef struct ADBDevice ADBDevice; - -/* buf = NULL means polling */ -typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, - const uint8_t *buf, int len); -typedef int ADBDeviceReset(ADBDevice *d); - -struct ADBDevice { - struct ADBBusState *bus; - int devaddr; - int handler; - ADBDeviceRequest *devreq; - ADBDeviceReset *devreset; - void *opaque; -}; - -typedef struct ADBBusState { - ADBDevice devices[MAX_ADB_DEVICES]; - int nb_devices; - int poll_index; -} ADBBusState; - -int adb_request(ADBBusState *s, uint8_t *buf_out, - const uint8_t *buf, int len); -int adb_poll(ADBBusState *s, uint8_t *buf_out); - -ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceRequest *devreq, - ADBDeviceReset *devreset, - void *opaque); -void adb_kbd_init(ADBBusState *bus); -void adb_mouse_init(ADBBusState *bus); - -extern ADBBusState adb_bus; - -#include "hw/usb.h" - -/* usb ports of the VM */ - -void qemu_register_usb_port(USBPort *port, void *opaque, int index, - usb_attachfn attach); - -#define VM_USB_HUB_SIZE 8 - -void do_usb_add(const char *devname); -void do_usb_del(const char *devname); -void usb_info(void); - -/* scsi-disk.c */ -enum scsi_reason { - SCSI_REASON_DONE, /* Command complete. */ - SCSI_REASON_DATA /* Transfer complete, more data required. */ -}; - -typedef struct SCSIDevice SCSIDevice; -typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag, - uint32_t arg); - -SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, - int tcq, - scsi_completionfn completion, - void *opaque); -void scsi_disk_destroy(SCSIDevice *s); - -int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); -/* SCSI data transfers are asynchrnonous. However, unlike the block IO - layer the completion routine may be called directly by - scsi_{read,write}_data. */ -void scsi_read_data(SCSIDevice *s, uint32_t tag); -int scsi_write_data(SCSIDevice *s, uint32_t tag); -void scsi_cancel_io(SCSIDevice *s, uint32_t tag); -uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); - -/* lsi53c895a.c */ -void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); -void *lsi_scsi_init(PCIBus *bus, int devfn); - -/* integratorcp.c */ -extern QEMUMachine integratorcp_machine; - -/* versatilepb.c */ -extern QEMUMachine versatilepb_machine; -extern QEMUMachine versatileab_machine; - -/* realview.c */ -extern QEMUMachine realview_machine; - -/* spitz.c */ -extern QEMUMachine akitapda_machine; -extern QEMUMachine spitzpda_machine; -extern QEMUMachine borzoipda_machine; -extern QEMUMachine terrierpda_machine; - -/* gumstix.c */ -extern QEMUMachine connex_machine; - -/* palm.c */ -extern QEMUMachine palmte_machine; - -/* armv7m.c */ -qemu_irq *armv7m_init(int flash_size, int sram_size, - const char *kernel_filename, const char *cpu_model); - -/* stellaris.c */ -extern QEMUMachine lm3s811evb_machine; -extern QEMUMachine lm3s6965evb_machine; - -/* ps2.c */ -void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); -void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); -void ps2_write_mouse(void *, int val); -void ps2_write_keyboard(void *, int val); -uint32_t ps2_read_data(void *); -void ps2_queue(void *, int b); -void ps2_keyboard_set_translation(void *opaque, int mode); -void ps2_mouse_fake_event(void *opaque); - -/* smc91c111.c */ -void smc91c111_init(NICInfo *, uint32_t, qemu_irq); - -/* pl031.c */ -void pl031_init(uint32_t base, qemu_irq irq); - -/* pl110.c */ -void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int); - -/* pl011.c */ -enum pl011_type { - PL011_ARM, - PL011_LUMINARY -}; - -void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr, - enum pl011_type type); - -/* pl022.c */ -void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int), - void *opaque); - -/* pl050.c */ -void pl050_init(uint32_t base, qemu_irq irq, int is_mouse); - -/* pl061.c */ -qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out); - -/* pl080.c */ -void *pl080_init(uint32_t base, qemu_irq irq, int nchannels); - -/* pl181.c */ -void pl181_init(uint32_t base, BlockDriverState *bd, - qemu_irq irq0, qemu_irq irq1); - -/* pl190.c */ -qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq); - -/* arm-timer.c */ -void sp804_init(uint32_t base, qemu_irq irq); -void icp_pit_init(uint32_t base, qemu_irq *pic, int irq); - -/* arm_sysctl.c */ -void arm_sysctl_init(uint32_t base, uint32_t sys_id); - -/* realview_gic.c */ -qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq); - -/* mpcore.c */ -extern qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq); - -/* arm_boot.c */ - -void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, - const char *kernel_cmdline, const char *initrd_filename, - int board_id, target_phys_addr_t loader_start); - -/* armv7m_nvic.c */ -qemu_irq *armv7m_nvic_init(CPUState *env); - -/* ssd0303.c */ -void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address); - -/* ssd0323.c */ -int ssd0323_xfer_ssi(void *opaque, int data); -void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p); - -/* sh7750.c */ -struct SH7750State; - -struct SH7750State *sh7750_init(CPUState * cpu); - -typedef struct { - /* The callback will be triggered if any of the designated lines change */ - uint16_t portamask_trigger; - uint16_t portbmask_trigger; - /* Return 0 if no action was taken */ - int (*port_change_cb) (uint16_t porta, uint16_t portb, - uint16_t * periph_pdtra, - uint16_t * periph_portdira, - uint16_t * periph_pdtrb, - uint16_t * periph_portdirb); -} sh7750_io_device; - -int sh7750_register_io_device(struct SH7750State *s, - sh7750_io_device * device); -/* sh_timer.c */ -#define TMU012_FEAT_TOCR (1 << 0) -#define TMU012_FEAT_3CHAN (1 << 1) -#define TMU012_FEAT_EXTCLK (1 << 2) -void tmu012_init(uint32_t base, int feat, uint32_t freq); - -/* sh_serial.c */ -#define SH_SERIAL_FEAT_SCIF (1 << 0) -void sh_serial_init (target_phys_addr_t base, int feat, - uint32_t freq, CharDriverState *chr); - -/* tc58128.c */ -int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); - -/* NOR flash devices */ -#define MAX_PFLASH 4 -extern BlockDriverState *pflash_table[MAX_PFLASH]; -typedef struct pflash_t pflash_t; - -pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, - BlockDriverState *bs, - uint32_t sector_len, int nb_blocs, int width, - uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3); - -/* nand.c */ -struct nand_flash_s; -struct nand_flash_s *nand_init(int manf_id, int chip_id); -void nand_done(struct nand_flash_s *s); -void nand_setpins(struct nand_flash_s *s, - int cle, int ale, int ce, int wp, int gnd); -void nand_getpins(struct nand_flash_s *s, int *rb); -void nand_setio(struct nand_flash_s *s, uint8_t value); -uint8_t nand_getio(struct nand_flash_s *s); - -#define NAND_MFR_TOSHIBA 0x98 -#define NAND_MFR_SAMSUNG 0xec -#define NAND_MFR_FUJITSU 0x04 -#define NAND_MFR_NATIONAL 0x8f -#define NAND_MFR_RENESAS 0x07 -#define NAND_MFR_STMICRO 0x20 -#define NAND_MFR_HYNIX 0xad -#define NAND_MFR_MICRON 0x2c - -/* ecc.c */ -struct ecc_state_s { - uint8_t cp; /* Column parity */ - uint16_t lp[2]; /* Line parity */ - uint16_t count; -}; - -uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample); -void ecc_reset(struct ecc_state_s *s); -void ecc_put(QEMUFile *f, struct ecc_state_s *s); -void ecc_get(QEMUFile *f, struct ecc_state_s *s); - -/* ads7846.c */ -struct ads7846_state_s; -uint32_t ads7846_read(void *opaque); -void ads7846_write(void *opaque, uint32_t value); -struct ads7846_state_s *ads7846_init(qemu_irq penirq); - -/* max111x.c */ -struct max111x_s; -uint32_t max111x_read(void *opaque); -void max111x_write(void *opaque, uint32_t value); -struct max111x_s *max1110_init(qemu_irq cb); -struct max111x_s *max1111_init(qemu_irq cb); -void max111x_set_input(struct max111x_s *s, int line, uint8_t value); - -/* PCMCIA/Cardbus */ - -struct pcmcia_socket_s { - qemu_irq irq; - int attached; - const char *slot_string; - const char *card_string; -}; - -void pcmcia_socket_register(struct pcmcia_socket_s *socket); -void pcmcia_socket_unregister(struct pcmcia_socket_s *socket); -void pcmcia_info(void); - -struct pcmcia_card_s { - void *state; - struct pcmcia_socket_s *slot; - int (*attach)(void *state); - int (*detach)(void *state); - const uint8_t *cis; - int cis_len; - - /* Only valid if attached */ - uint8_t (*attr_read)(void *state, uint32_t address); - void (*attr_write)(void *state, uint32_t address, uint8_t value); - uint16_t (*common_read)(void *state, uint32_t address); - void (*common_write)(void *state, uint32_t address, uint16_t value); - uint16_t (*io_read)(void *state, uint32_t address); - void (*io_write)(void *state, uint32_t address, uint16_t value); -}; - -#define CISTPL_DEVICE 0x01 /* 5V Device Information Tuple */ -#define CISTPL_NO_LINK 0x14 /* No Link Tuple */ -#define CISTPL_VERS_1 0x15 /* Level 1 Version Tuple */ -#define CISTPL_JEDEC_C 0x18 /* JEDEC ID Tuple */ -#define CISTPL_JEDEC_A 0x19 /* JEDEC ID Tuple */ -#define CISTPL_CONFIG 0x1a /* Configuration Tuple */ -#define CISTPL_CFTABLE_ENTRY 0x1b /* 16-bit PCCard Configuration */ -#define CISTPL_DEVICE_OC 0x1c /* Additional Device Information */ -#define CISTPL_DEVICE_OA 0x1d /* Additional Device Information */ -#define CISTPL_DEVICE_GEO 0x1e /* Additional Device Information */ -#define CISTPL_DEVICE_GEO_A 0x1f /* Additional Device Information */ -#define CISTPL_MANFID 0x20 /* Manufacture ID Tuple */ -#define CISTPL_FUNCID 0x21 /* Function ID Tuple */ -#define CISTPL_FUNCE 0x22 /* Function Extension Tuple */ -#define CISTPL_END 0xff /* Tuple End */ -#define CISTPL_ENDMARK 0xff - -/* dscm1xxxx.c */ -struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv); - -/* ptimer.c */ -typedef struct ptimer_state ptimer_state; -typedef void (*ptimer_cb)(void *opaque); - -ptimer_state *ptimer_init(QEMUBH *bh); -void ptimer_set_period(ptimer_state *s, int64_t period); -void ptimer_set_freq(ptimer_state *s, uint32_t freq); -void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload); -uint64_t ptimer_get_count(ptimer_state *s); -void ptimer_set_count(ptimer_state *s, uint64_t count); -void ptimer_run(ptimer_state *s, int oneshot); -void ptimer_stop(ptimer_state *s); -void qemu_put_ptimer(QEMUFile *f, ptimer_state *s); -void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); - -#include "hw/pxa.h" - -#include "hw/omap.h" - -/* tsc210x.c */ -struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); -struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); - -/* mcf_uart.c */ -uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr); -void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val); -void *mcf_uart_init(qemu_irq irq, CharDriverState *chr); -void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq, - CharDriverState *chr); - -/* mcf_intc.c */ -qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env); - -/* mcf_fec.c */ -void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq); - -/* mcf5206.c */ -qemu_irq *mcf5206_init(uint32_t base, CPUState *env); - -/* an5206.c */ -extern QEMUMachine an5206_machine; - -/* mcf5208.c */ -extern QEMUMachine mcf5208evb_machine; - -/* dummy_m68k.c */ -extern QEMUMachine dummy_m68k_machine; - -#include "gdbstub.h" - -#endif /* defined(NEED_CPU_H) */ -#endif /* VL_H */ diff --git a/vnc.c b/vnc.c index 88cca3b73..ec97ad9a0 100644 --- a/vnc.c +++ b/vnc.c @@ -23,8 +23,11 @@ * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "console.h" +#include "sysemu.h" #include "qemu_socket.h" +#include "qemu-timer.h" #define VNC_REFRESH_INTERVAL (1000 / 30) diff --git a/x_keymap.c b/x_keymap.c index 9f72fc3eb..08cf95eb6 100644 --- a/x_keymap.c +++ b/x_keymap.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" + static const uint8_t x_keycode_to_pc_keycode[115] = { 0xc7, /* 97 Home */ 0xc8, /* 98 Up */ -- cgit v1.2.3 From 749bc4bf0bcd36e38b86d75a98f287f1941394cb Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Nov 2007 17:35:54 +0000 Subject: Remove stray uses of vl.h. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3675 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 3 ++- audio/coreaudio.c | 3 ++- audio/dsoundaudio.c | 3 ++- audio/fmodaudio.c | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index a573a380a..101af3367 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -22,7 +22,8 @@ * THE SOFTWARE. */ #include -#include "vl.h" +#include "qemu-common.h" +#include "audio.h" #define AUDIO_CAP "alsa" #include "audio_int.h" diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 74d432f91..516bb3fad 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -26,7 +26,8 @@ #include /* strerror */ #include /* pthread_X */ -#include "vl.h" +#include "qemu-common.h" +#include "audio.h" #define AUDIO_CAP "coreaudio" #include "audio_int.h" diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index 90a0333f1..a955cf4dc 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -26,7 +26,8 @@ * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation */ -#include "vl.h" +#include "qemu-common.h" +#include "audio.h" #define AUDIO_CAP "dsound" #include "audio_int.h" diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c index 5875ba15e..04f4e40b3 100644 --- a/audio/fmodaudio.c +++ b/audio/fmodaudio.c @@ -23,7 +23,8 @@ */ #include #include -#include "vl.h" +#include "qemu-common.h" +#include "audio.h" #define AUDIO_CAP "fmod" #include "audio_int.h" -- cgit v1.2.3 From e1dad5a615fb4a2d5cd43cbc0fc42f6a0d35f2e9 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 17 Nov 2007 18:43:47 +0000 Subject: Better STOPINTR bit semantics in the PXA2xx DMA. Don't error out on reading GPCR register, just warn (Thorsten Zitterell). Don't zero a memory that's already zeroed. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3676 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx_dma.c | 4 +++- hw/pxa2xx_gpio.c | 5 +++++ hw/pxa2xx_mmci.c | 2 +- hw/sd.c | 1 - 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 23bdae909..4e33c5317 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -348,8 +348,10 @@ static void pxa2xx_dma_write(void *opaque, if (value & DCSR_NODESCFETCH) { /* No-descriptor-fetch mode */ - if (value & DCSR_RUN) + if (value & DCSR_RUN) { + s->chan[channel].state &= ~DCSR_STOPINTR; pxa2xx_dma_run(s); + } } else { /* Descriptor-fetch mode */ if (value & DCSR_RUN) { diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 9f5184438..e3a30bc45 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -154,6 +154,11 @@ static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset) __FUNCTION__, offset); return s->gpsr[bank]; /* Return last written value. */ + case GPCR: /* GPIO Pin-Output Clear registers */ + printf("%s: Read from a write-only register " REG_FMT "\n", + __FUNCTION__, offset); + return 31337; /* Specified as unpredictable in the docs. */ + case GRER: /* GPIO Rising-Edge Detect Enable registers */ return s->rising[bank]; diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 6e244a96c..9d26b7959 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -549,5 +549,5 @@ struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, qemu_irq readonly, qemu_irq coverswitch) { - sd_set_cb(s->card, read, coverswitch); + sd_set_cb(s->card, readonly, coverswitch); } diff --git a/hw/sd.c b/hw/sd.c index 08e8805e5..9dd86e357 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -377,7 +377,6 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) qemu_free(sd->wp_groups); sd->wp_switch = bdrv_is_read_only(bdrv); sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect); - memset(sd->wp_groups, 0, sizeof(int) * sect); memset(sd->function_group, 0, sizeof(int) * 6); sd->erase_start = 0; sd->erase_end = 0; -- cgit v1.2.3 From 9a87ce9b9558fc0aacebfefdbcbd74fda8fc027f Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 17 Nov 2007 21:01:04 +0000 Subject: Name the magic constants, fix a hex number without 0x git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3677 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_intctl.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 448e5bfde..a0aa53c21 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -68,6 +68,12 @@ typedef struct SLAVIO_INTCTLState { #define INTCTLM_MAXADDR 0x13 #define INTCTLM_SIZE (INTCTLM_MAXADDR + 1) #define INTCTLM_MASK 0x1f +#define MASTER_IRQ_MASK ~0x4fb2007f +#define MASTER_DISABLE 0x80000000 +#define CPU_IRQ_MASK 0xfffe0000 +#define CPU_IRQ_INT15_IN 0x0004000 +#define CPU_IRQ_INT15_MASK 0x80000000 + static void slavio_check_interrupts(void *opaque); // per-cpu interrupt controller @@ -103,15 +109,15 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, val); switch (saddr) { case 1: // clear pending softints - if (val & 0x4000) - val |= 80000000; - val &= 0xfffe0000; + if (val & CPU_IRQ_INT15_IN) + val |= CPU_IRQ_INT15_MASK; + val &= CPU_IRQ_MASK; s->intreg_pending[cpu] &= ~val; slavio_check_interrupts(s); DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); break; case 2: // set softint - val &= 0xfffe0000; + val &= CPU_IRQ_MASK; s->intreg_pending[cpu] |= val; slavio_check_interrupts(s); DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); @@ -142,7 +148,7 @@ static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) saddr = (addr & INTCTLM_MAXADDR) >> 2; switch (saddr) { case 0: - ret = s->intregm_pending & 0x7fffffff; + ret = s->intregm_pending & ~MASTER_DISABLE; break; case 1: ret = s->intregm_disabled; @@ -169,14 +175,14 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin switch (saddr) { case 2: // clear (enable) // Force clear unused bits - val &= ~0x4fb2007f; + val &= MASTER_IRQ_MASK; s->intregm_disabled &= ~val; DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); slavio_check_interrupts(s); break; case 3: // set (disable, clear pending) // Force clear unused bits - val &= ~0x4fb2007f; + val &= MASTER_IRQ_MASK; s->intregm_disabled |= val; s->intregm_pending &= ~val; slavio_check_interrupts(s); @@ -244,14 +250,14 @@ static void slavio_check_interrupts(void *opaque) DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); for (i = 0; i < MAX_CPUS; i++) { pil_pending = 0; - if (pending && !(s->intregm_disabled & 0x80000000) && + if (pending && !(s->intregm_disabled & MASTER_DISABLE) && (i == s->target_cpu)) { for (j = 0; j < 32; j++) { if (pending & (1 << j)) pil_pending |= 1 << s->intbit_to_level[j]; } } - pil_pending |= (s->intreg_pending[i] >> 16) & 0xfffe; + pil_pending |= (s->intreg_pending[i] & CPU_IRQ_MASK) >> 16; for (j = 0; j < MAX_PILS; j++) { if (pil_pending & (1 << j)) { @@ -346,7 +352,7 @@ static void slavio_intctl_reset(void *opaque) for (i = 0; i < MAX_CPUS; i++) { s->intreg_pending[i] = 0; } - s->intregm_disabled = ~0xffb2007f; + s->intregm_disabled = ~MASTER_IRQ_MASK; s->intregm_pending = 0; s->target_cpu = 0; slavio_check_interrupts(s); -- cgit v1.2.3 From a4f30719a8cdffd49194774ef578c1ced88f9fe5 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 21:14:09 +0000 Subject: PowerPC hypervisor mode is not fundamentally available only for PowerPC 64. Remove TARGET_PPC64 dependency and add code provision to be able to define a fake 32 bits CPU with hypervisor feature support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3678 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 24 +++++++-- target-ppc/helper.c | 134 ++++++++++++++--------------------------------- target-ppc/helper_regs.h | 19 ++++--- target-ppc/op_helper.c | 4 +- 4 files changed, 73 insertions(+), 108 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3baab6768..b0b41afd5 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -23,6 +23,8 @@ #include "config.h" #include +//#define PPC_EMULATE_32BITS_HYPV + #if defined (TARGET_PPC64) /* PowerPC 64 definitions */ typedef uint64_t ppc_gpr_t; @@ -343,9 +345,10 @@ union ppc_tlb_t { /* Machine state register bits definition */ #define MSR_SF 63 /* Sixty-four-bit mode hflags */ #define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */ -#define MSR_HV 60 /* hypervisor state hflags */ +#define MSR_SHV 60 /* hypervisor state hflags */ #define MSR_CM 31 /* Computation mode for BookE hflags */ #define MSR_ICM 30 /* Interrupt computation mode for BookE */ +#define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */ #define MSR_UCLE 26 /* User-mode cache lock enable for BookE */ #define MSR_VR 25 /* altivec available x hflags */ #define MSR_SPE 25 /* SPE enable for BookE x hflags */ @@ -379,9 +382,10 @@ union ppc_tlb_t { #define msr_sf ((env->msr >> MSR_SF) & 1) #define msr_isf ((env->msr >> MSR_ISF) & 1) -#define msr_hv ((env->msr >> MSR_HV) & 1) +#define msr_shv ((env->msr >> MSR_SHV) & 1) #define msr_cm ((env->msr >> MSR_CM) & 1) #define msr_icm ((env->msr >> MSR_ICM) & 1) +#define msr_thv ((env->msr >> MSR_THV) & 1) #define msr_ucle ((env->msr >> MSR_UCLE) & 1) #define msr_vr ((env->msr >> MSR_VR) & 1) #define msr_spe ((env->msr >> MSR_SE) & 1) @@ -412,6 +416,20 @@ union ppc_tlb_t { #define msr_pmm ((env->msr >> MSR_PMM) & 1) #define msr_ri ((env->msr >> MSR_RI) & 1) #define msr_le ((env->msr >> MSR_LE) & 1) +/* Hypervisor bit is more specific */ +#if defined(TARGET_PPC64) +#define MSR_HVB (1ULL << MSR_SHV) +#define msr_hv msr_shv +#else +#if defined(PPC_EMULATE_32BITS_HYPV) +#define MSR_HVB (1ULL << MSR_THV) +#define msr_hv msr_thv +#define +#else +#define MSR_HVB (0ULL) +#define msr_hv (0) +#endif +#endif enum { POWERPC_FLAG_NONE = 0x00000000, @@ -428,7 +446,7 @@ enum { /* Flag for MSR bit 9 signification (BE/DE) */ POWERPC_FLAG_BE = 0x00000080, POWERPC_FLAG_DE = 0x00000100, - /* Flag for MSR but 2 signification (PX/PMM) */ + /* Flag for MSR bit 2 signification (PX/PMM) */ POWERPC_FLAG_PX = 0x00000200, POWERPC_FLAG_PMM = 0x00000400, }; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 8c187c7de..854526dad 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2100,7 +2100,7 @@ void ppc_store_xer (CPUPPCState *env, target_ulong value) /* GDBstub can read and write MSR... */ void ppc_store_msr (CPUPPCState *env, target_ulong value) { - hreg_store_msr(env, value); + hreg_store_msr(env, value, 0); } /*****************************************************************************/ @@ -2134,10 +2134,7 @@ static always_inline void powerpc_excp (CPUState *env, { target_ulong msr, new_msr, vector; int srr0, srr1, asrr0, asrr1; - int lpes0, lpes1; -#if defined(TARGET_PPC64) - int lev; -#endif + int lpes0, lpes1, lev; if (0) { /* XXX: find a suitable condition to enable the hypervisor mode */ @@ -2198,12 +2195,10 @@ static always_inline void powerpc_excp (CPUState *env, } new_msr &= ~((target_ulong)1 << MSR_RI); new_msr &= ~((target_ulong)1 << MSR_ME); -#if defined(TARGET_PPC64) if (0) { /* XXX: find a suitable condition to enable the hypervisor mode */ - new_msr |= (target_ulong)1 << MSR_HV; + new_msr |= (target_ulong)MSR_HVB; } -#endif /* XXX: should also have something loaded in DAR / DSISR */ switch (excp_model) { case POWERPC_EXCP_40x: @@ -2228,10 +2223,8 @@ static always_inline void powerpc_excp (CPUState *env, } #endif new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_ISI: /* Instruction storage exception */ #if defined (DEBUG_EXCEPTIONS) @@ -2241,25 +2234,19 @@ static always_inline void powerpc_excp (CPUState *env, } #endif new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; msr |= env->error_code; goto store_next; case POWERPC_EXCP_EXTERNAL: /* External input */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes0 == 1) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; /* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; @@ -2278,10 +2265,8 @@ static always_inline void powerpc_excp (CPUState *env, return; } new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; msr |= 0x00100000; if (msr_fe0 == msr_fe1) goto store_next; @@ -2295,26 +2280,20 @@ static always_inline void powerpc_excp (CPUState *env, } #endif new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; msr |= 0x00080000; break; case POWERPC_EXCP_PRIV: new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; msr |= 0x00040000; break; case POWERPC_EXCP_TRAP: new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; msr |= 0x00020000; break; default: @@ -2326,10 +2305,8 @@ static always_inline void powerpc_excp (CPUState *env, goto store_current; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_current; case POWERPC_EXCP_SYSCALL: /* System call exception */ /* NOTE: this is a temporary hack to support graphics OSI @@ -2347,21 +2324,17 @@ static always_inline void powerpc_excp (CPUState *env, dump_syscall(env); } new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) lev = env->error_code; if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ new_msr &= ~((target_ulong)1 << MSR_RI); goto store_current; case POWERPC_EXCP_DECR: /* Decrementer exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ /* FIT on 4xx */ @@ -2445,72 +2418,55 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; case POWERPC_EXCP_RESET: /* System reset exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + new_msr |= (target_ulong)MSR_HVB; + } goto store_next; case POWERPC_EXCP_DSEG: /* Data segment exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_ISEG: /* Instruction segment exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; -#if defined(TARGET_PPC64) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_TRACE: /* Trace exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; -#if defined(TARGET_PPC64) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; -#if defined(TARGET_PPC64) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; -#if defined(TARGET_PPC64) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; -#if defined(TARGET_PPC64) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_next; case POWERPC_EXCP_VPU: /* Vector unavailable exception */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; goto store_current; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ #if defined (DEBUG_EXCEPTIONS) @@ -2534,10 +2490,8 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ -#if defined(TARGET_PPC64) /* XXX: check this */ - if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + if (lpes1 == 0) /* XXX: check this */ + new_msr |= (target_ulong)MSR_HVB; switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: @@ -2555,10 +2509,8 @@ static always_inline void powerpc_excp (CPUState *env, break; case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ -#if defined(TARGET_PPC64) /* XXX: check this */ - if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + if (lpes1 == 0) /* XXX: check this */ + new_msr |= (target_ulong)MSR_HVB; switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: @@ -2576,10 +2528,8 @@ static always_inline void powerpc_excp (CPUState *env, break; case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */ -#if defined(TARGET_PPC64) /* XXX: check this */ - if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + if (lpes1 == 0) /* XXX: check this */ + new_msr |= (target_ulong)MSR_HVB; switch (excp_model) { case POWERPC_EXCP_602: case POWERPC_EXCP_603: @@ -2678,10 +2628,8 @@ static always_inline void powerpc_excp (CPUState *env, goto store_next; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ new_msr &= ~((target_ulong)1 << MSR_RI); -#if defined(TARGET_PPC64) if (lpes1 == 0) - new_msr |= (target_ulong)1 << MSR_HV; -#endif + new_msr |= (target_ulong)MSR_HVB; /* XXX: TODO */ cpu_abort(env, "Performance counter exception is not implemented yet !\n"); @@ -2768,8 +2716,7 @@ static always_inline void powerpc_excp (CPUState *env, /* XXX: we don't use hreg_store_msr here as already have treated * any special case that could occur. Just store MSR and update hflags */ - env->msr = new_msr; - env->hflags_nmsr = 0x00000000; + env->msr = new_msr & env->msr_mask; hreg_compute_hflags(env); env->nip = vector; /* Reset exception state */ @@ -2784,9 +2731,7 @@ void do_interrupt (CPUState *env) void ppc_hw_interrupt (CPUPPCState *env) { -#if defined(TARGET_PPC64) int hdice; -#endif #if 0 if (loglevel & CPU_LOG_INT) { @@ -2815,7 +2760,6 @@ void ppc_hw_interrupt (CPUPPCState *env) return; } #endif -#if defined(TARGET_PPC64) if (0) { /* XXX: find a suitable condition to enable the hypervisor mode */ hdice = env->spr[SPR_LPCR] & 1; @@ -2830,7 +2774,6 @@ void ppc_hw_interrupt (CPUPPCState *env) return; } } -#endif if (msr_ce != 0) { /* External critical interrupt */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { @@ -2939,9 +2882,10 @@ void cpu_ppc_reset (void *opaque) env = opaque; msr = (target_ulong)0; -#if defined(TARGET_PPC64) - msr |= (target_ulong)0 << MSR_HV; /* Should be 1... */ -#endif + if (0) { + /* XXX: find a suitable condition to enable the hypervisor mode */ + msr |= (target_ulong)MSR_HVB; + } msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ msr |= (target_ulong)1 << MSR_EP; diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index 03c21c77f..c507d26cf 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -60,13 +60,12 @@ static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) static always_inline void hreg_compute_mem_idx (CPUPPCState *env) { -#if defined (TARGET_PPC64) /* Precompute MMU index */ - if (msr_pr == 0 && msr_hv != 0) + if (msr_pr == 0 && msr_hv != 0) { env->mmu_idx = 2; - else -#endif + } else { env->mmu_idx = 1 - msr_pr; + } } static always_inline void hreg_compute_hflags (CPUPPCState *env) @@ -77,22 +76,26 @@ static always_inline void hreg_compute_hflags (CPUPPCState *env) hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | (1 << MSR_LE); -#if defined (TARGET_PPC64) - hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | (1ULL << MSR_HV); -#endif + hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB; hreg_compute_mem_idx(env); env->hflags = env->msr & hflags_mask; /* Merge with hflags coming from other registers */ env->hflags |= env->hflags_nmsr; } -static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) +static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value, + int alter_hv) { int excp; excp = 0; value &= env->msr_mask; #if !defined (CONFIG_USER_ONLY) + if (!alter_hv) { + /* mtmsr cannot alter the hypervisor state */ + value &= ~MSR_HVB; + value |= env->msr & MSR_HVB; + } if (((value >> MSR_IR) & 1) != msr_ir || ((value >> MSR_DR) & 1) != msr_dr) { /* Flush all tlb when changing translation mode */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 50c3d72d0..172dd48be 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1425,7 +1425,7 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr); void do_store_msr (void) { - T0 = hreg_store_msr(env, T0); + T0 = hreg_store_msr(env, T0, 0); if (T0 != 0) { env->interrupt_request |= CPU_INTERRUPT_EXITTB; do_raise_exception(T0); @@ -1451,7 +1451,7 @@ static always_inline void __do_rfi (target_ulong nip, target_ulong msr, #endif /* XXX: beware: this is false if VLE is supported */ env->nip = nip & ~((target_ulong)0x00000003); - hreg_store_msr(env, msr); + hreg_store_msr(env, msr, 1); #if defined (DEBUG_OP) cpu_dump_rfi(env->nip, env->msr); #endif -- cgit v1.2.3 From 05332d70fd7488459e4b80c73ff7547b3a1a7ce6 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 22:26:51 +0000 Subject: A little more granularity in PowerPC instructions definition is needed in order to implement Freescale cores. Fix efsadd / efssub opcodes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3679 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 104 +++++++++++++++++++++++++------------------- target-ppc/translate_init.c | 46 +++++++++++--------- 2 files changed, 84 insertions(+), 66 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f758df7af..a6e33eb03 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -462,8 +462,12 @@ enum { /* Fixed-point unit extensions */ /* PowerPC 602 specific */ PPC_602_SPEC = 0x0000000000000400ULL, - /* PowerPC 2.03 specification extensions */ - PPC_203 = 0x0000000000000800ULL, + /* isel instruction */ + PPC_ISEL = 0x0000000000000800ULL, + /* popcntb instruction */ + PPC_POPCNTB = 0x0000000000001000ULL, + /* string load / store */ + PPC_STRING = 0x0000000000002000ULL, /* Floating-point unit extensions */ /* Optional floating point instructions */ @@ -480,12 +484,10 @@ enum { /* Vector/SIMD extensions */ /* Altivec support */ PPC_ALTIVEC = 0x0000000001000000ULL, - /* e500 vector instructions */ - PPC_E500_VECTOR = 0x0000000002000000ULL, /* PowerPC 2.03 SPE extension */ - PPC_SPE = 0x0000000004000000ULL, + PPC_SPE = 0x0000000002000000ULL, /* PowerPC 2.03 SPE floating-point extension */ - PPC_SPEFPU = 0x0000000008000000ULL, + PPC_SPEFPU = 0x0000000004000000ULL, /* Optional memory control instructions */ PPC_MEM_TLBIA = 0x0000000010000000ULL, @@ -497,52 +499,64 @@ enum { PPC_MEM_EIEIO = 0x0000000100000000ULL, /* Cache control instructions */ - PPC_CACHE = 0x0000001000000000ULL, + PPC_CACHE = 0x00000002000000000ULL, /* icbi instruction */ - PPC_CACHE_ICBI = 0x0000002000000000ULL, + PPC_CACHE_ICBI = 0x0000000400000000ULL, /* dcbz instruction with fixed cache line size */ - PPC_CACHE_DCBZ = 0x0000004000000000ULL, + PPC_CACHE_DCBZ = 0x0000000800000000ULL, /* dcbz instruction with tunable cache line size */ - PPC_CACHE_DCBZT = 0x0000008000000000ULL, + PPC_CACHE_DCBZT = 0x0000001000000000ULL, /* dcba instruction */ - PPC_CACHE_DCBA = 0x0000010000000000ULL, + PPC_CACHE_DCBA = 0x0000002000000000ULL, + /* Freescale cache locking instructions */ + PPC_CACHE_LOCK = 0x0000004000000000ULL, /* MMU related extensions */ /* external control instructions */ - PPC_EXTERN = 0x0000100000000000ULL, + PPC_EXTERN = 0x0000010000000000ULL, /* segment register access instructions */ - PPC_SEGMENT = 0x0000200000000000ULL, + PPC_SEGMENT = 0x0000020000000000ULL, /* PowerPC 6xx TLB management instructions */ - PPC_6xx_TLB = 0x0000400000000000ULL, + PPC_6xx_TLB = 0x0000040000000000ULL, /* PowerPC 74xx TLB management instructions */ - PPC_74xx_TLB = 0x0000800000000000ULL, + PPC_74xx_TLB = 0x0000080000000000ULL, /* PowerPC 40x TLB management instructions */ - PPC_40x_TLB = 0x0001000000000000ULL, + PPC_40x_TLB = 0x0000100000000000ULL, /* segment register access instructions for PowerPC 64 "bridge" */ - PPC_SEGMENT_64B = 0x0002000000000000ULL, + PPC_SEGMENT_64B = 0x0000200000000000ULL, /* SLB management */ - PPC_SLBI = 0x0004000000000000ULL, + PPC_SLBI = 0x0000400000000000ULL, /* Embedded PowerPC dedicated instructions */ - PPC_EMB_COMMON = 0x0010000000000000ULL, + PPC_WRTEE = 0x0001000000000000ULL, /* PowerPC 40x exception model */ - PPC_40x_EXCP = 0x0020000000000000ULL, + PPC_40x_EXCP = 0x0002000000000000ULL, /* PowerPC 405 Mac instructions */ - PPC_405_MAC = 0x0040000000000000ULL, + PPC_405_MAC = 0x0004000000000000ULL, /* PowerPC 440 specific instructions */ - PPC_440_SPEC = 0x0080000000000000ULL, + PPC_440_SPEC = 0x0008000000000000ULL, /* BookE (embedded) PowerPC specification */ - PPC_BOOKE = 0x0100000000000000ULL, - /* More BookE (embedded) instructions... */ - PPC_BOOKE_EXT = 0x0200000000000000ULL, + PPC_BOOKE = 0x0010000000000000ULL, + /* mfapidi instruction */ + PPC_MFAPIDI = 0x0020000000000000ULL, + /* tlbiva instruction */ + PPC_TLBIVA = 0x0040000000000000ULL, + /* tlbivax instruction */ + PPC_TLBIVAX = 0x0080000000000000ULL, /* PowerPC 4xx dedicated instructions */ - PPC_4xx_COMMON = 0x0400000000000000ULL, + PPC_4xx_COMMON = 0x0100000000000000ULL, /* PowerPC 40x ibct instructions */ - PPC_40x_ICBT = 0x0800000000000000ULL, + PPC_40x_ICBT = 0x0200000000000000ULL, /* rfmci is not implemented in all BookE PowerPC */ - PPC_RFMCI = 0x1000000000000000ULL, + PPC_RFMCI = 0x0400000000000000ULL, + /* rfdi instruction */ + PPC_RFDI = 0x0800000000000000ULL, + /* DCR accesses */ + PPC_DCR = 0x1000000000000000ULL, + /* DCR extended accesse */ + PPC_DCRX = 0x2000000000000000ULL, /* user-mode DCR access, implemented in PowerPC 460 */ - PPC_DCRUX = 0x2000000000000000ULL, + PPC_DCRUX = 0x4000000000000000ULL, }; /*****************************************************************************/ @@ -1119,7 +1133,7 @@ GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER) } /* isel (PowerPC 2.03 specification) */ -GEN_HANDLER(isel, 0x1F, 0x0F, 0x00, 0x00000001, PPC_203) +GEN_HANDLER(isel, 0x1F, 0x0F, 0x00, 0x00000001, PPC_ISEL) { uint32_t bi = rC(ctx->opcode); uint32_t mask; @@ -1342,7 +1356,7 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) } /* popcntb : PowerPC 2.03 specification */ -GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_203) +GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB) { gen_op_load_gpr_T0(rS(ctx->opcode)); #if defined(TARGET_PPC64) @@ -2457,7 +2471,7 @@ static GenOpFunc1 *gen_op_stsw[NB_MEM_FUNCS] = { * In an other hand, IBM says this is valid, but rA won't be loaded. * For now, I'll follow the spec... */ -GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) +GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING) { int nb = NB(ctx->opcode); int start = rD(ctx->opcode); @@ -2482,7 +2496,7 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) } /* lswx */ -GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) +GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING) { int ra = rA(ctx->opcode); int rb = rB(ctx->opcode); @@ -2498,7 +2512,7 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) } /* stswi */ -GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) +GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING) { int nb = NB(ctx->opcode); @@ -2512,7 +2526,7 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) } /* stswx */ -GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) +GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING) { /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); @@ -4520,14 +4534,14 @@ GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2) /* BookE specific instructions */ /* XXX: not implemented on 440 ? */ -GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE_EXT) +GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI) { /* XXX: TODO */ GEN_EXCP_INVAL(ctx); } /* XXX: not implemented on 440 ? */ -GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE_EXT) +GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -4723,7 +4737,7 @@ GEN_MAC_HANDLER(mullhw, 0x08, 0x0D); GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C); /* mfdcr */ -GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) +GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -4741,7 +4755,7 @@ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) } /* mtdcr */ -GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) +GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -4760,7 +4774,7 @@ GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) /* mfdcrx */ /* XXX: not implemented on 440 ? */ -GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT) +GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -4778,7 +4792,7 @@ GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT) /* mtdcrx */ /* XXX: not implemented on 440 ? */ -GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_BOOKE_EXT) +GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVREG(ctx); @@ -4912,7 +4926,7 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE) /* BookE specific */ /* XXX: not implemented on 440 ? */ -GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE_EXT) +GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5088,7 +5102,7 @@ GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) } /* wrtee */ -GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) +GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5107,7 +5121,7 @@ GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) } /* wrteei */ -GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON) +GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_WRTEE) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); @@ -5943,7 +5957,7 @@ GEN_SPEOP_COMP(efststlt); GEN_SPEOP_COMP(efststeq); /* Opcodes definitions */ -GEN_SPE(efsadd, efssub, 0x00, 0x0A, 0x00000000, PPC_SPEFPU); // +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, PPC_SPEFPU); // GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPEFPU); // GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPEFPU); // GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPEFPU); // diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 62c080201..0f7441ee5 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2648,11 +2648,11 @@ static int check_pow_hid0 (CPUPPCState *env) /* PowerPC implementations definitions */ /* PowerPC 40x instruction set */ -#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_EMB_COMMON | \ +#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_WRTEE | \ PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ) /* PowerPC 401 */ -#define POWERPC_INSNS_401 (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_401 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) #define POWERPC_MSRM_401 (0x00000000000FD201ULL) @@ -2676,7 +2676,7 @@ static void init_proc_401 (CPUPPCState *env) } /* PowerPC 401x2 */ -#define POWERPC_INSNS_401x2 (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_401x2 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ PPC_CACHE_DCBA | PPC_MFTB | \ @@ -2709,7 +2709,7 @@ static void init_proc_401x2 (CPUPPCState *env) } /* PowerPC 401x3 */ -#define POWERPC_INSNS_401x3 (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_401x3 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ PPC_CACHE_DCBA | PPC_MFTB | \ @@ -2738,7 +2738,7 @@ static void init_proc_401x3 (CPUPPCState *env) } /* IOP480 */ -#define POWERPC_INSNS_IOP480 (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_IOP480 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ PPC_CACHE_DCBA | \ @@ -2771,7 +2771,7 @@ static void init_proc_IOP480 (CPUPPCState *env) } /* PowerPC 403 */ -#define POWERPC_INSNS_403 (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_403 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) #define POWERPC_MSRM_403 (0x000000000007D00DULL) @@ -2800,7 +2800,7 @@ static void init_proc_403 (CPUPPCState *env) } /* PowerPC 403 GCX */ -#define POWERPC_INSNS_403GCX (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_403GCX (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) @@ -2844,7 +2844,8 @@ static void init_proc_403GCX (CPUPPCState *env) } /* PowerPC 405 */ -#define POWERPC_INSNS_405 (POWERPC_INSNS_EMB | PPC_MFTB | \ +#define POWERPC_INSNS_405 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_MFTB | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_CACHE_DCBA | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT | \ @@ -2889,7 +2890,7 @@ static void init_proc_405 (CPUPPCState *env) } /* PowerPC 440 EP */ -#define POWERPC_INSNS_440EP (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_440EP (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ PPC_440_SPEC | PPC_RFMCI) @@ -2939,10 +2940,11 @@ static void init_proc_440EP (CPUPPCState *env) } /* PowerPC 440 GP */ -#define POWERPC_INSNS_440GP (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_440GP (POWERPC_INSNS_EMB | PPC_STRING | \ + PPC_DCR | PPC_DCRX | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON | \ - PPC_405_MAC | PPC_440_SPEC) + PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ + PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) #define POWERPC_MSRM_440GP (0x000000000006FF30ULL) #define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) @@ -2971,7 +2973,7 @@ static void init_proc_440GP (CPUPPCState *env) } /* PowerPC 440x4 */ -#define POWERPC_INSNS_440x4 (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_440x4 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ PPC_440_SPEC) @@ -3004,7 +3006,7 @@ static void init_proc_440x4 (CPUPPCState *env) } /* PowerPC 440x5 */ -#define POWERPC_INSNS_440x5 (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_440x5 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ PPC_440_SPEC | PPC_RFMCI) @@ -3054,10 +3056,11 @@ static void init_proc_440x5 (CPUPPCState *env) } /* PowerPC 460 (guessed) */ -#define POWERPC_INSNS_460 (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_460 (POWERPC_INSNS_EMB | PPC_STRING | \ + PPC_DCR | PPC_DCRX | PPC_DCRUX | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON | \ - PPC_405_MAC | PPC_440_SPEC | PPC_DCRUX) + PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ + PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) #define POWERPC_MSRM_460 (0x000000000006FF30ULL) #define POWERPC_MMU_460 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) @@ -3110,13 +3113,14 @@ static void init_proc_460 (CPUPPCState *env) } /* PowerPC 460F (guessed) */ -#define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | \ +#define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | PPC_STRING | \ + PPC_DCR | PPC_DCRX | PPC_DCRUX | \ PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ PPC_FLOAT | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES | \ PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ PPC_FLOAT_STFIWX | \ - PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON | \ - PPC_405_MAC | PPC_440_SPEC | PPC_DCRUX) + PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ + PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) #define POWERPC_MSRM_460 (0x000000000006FF30ULL) #define POWERPC_MMU_460F (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) @@ -3231,7 +3235,7 @@ static void init_proc_e500 (CPUPPCState *env) /* Non-embedded PowerPC */ /* Base instructions set for all 6xx/7xx/74xx/970 PowerPC */ -#define POWERPC_INSNS_6xx (PPC_INSNS_BASE | PPC_FLOAT | \ +#define POWERPC_INSNS_6xx (PPC_INSNS_BASE | PPC_STRING | PPC_FLOAT | \ PPC_CACHE | PPC_CACHE_ICBI | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE) /* Instructions common to all 6xx/7xx/74xx/970 PowerPC except 601 & 602 */ -- cgit v1.2.3 From b4095fed95235c95b04b2337ec29947f509af3bc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 22:42:36 +0000 Subject: Define Freescale cores specific MMU model, exceptions and input bus. (but do not provide any actual implementation). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3680 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 50 ++++++++++++++++++++++------- target-ppc/helper.c | 78 +++++++++++++++++++++++++++++++++------------ target-ppc/translate_init.c | 17 +++++++--- 3 files changed, 109 insertions(+), 36 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b0b41afd5..a80101c02 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -104,8 +104,10 @@ enum powerpc_mmu_t { POWERPC_MMU_SOFT_4xx, /* PowerPC 4xx MMU with software TLB and zones protections */ POWERPC_MMU_SOFT_4xx_Z, - /* PowerPC 4xx MMU in real mode only */ - POWERPC_MMU_REAL_4xx, + /* PowerPC MMU in real mode only */ + POWERPC_MMU_REAL, + /* Freescale MPC8xx MMU model */ + POWERPC_MMU_MPC8xx, /* BookE MMU model */ POWERPC_MMU_BOOKE, /* BookE FSL MMU model */ @@ -171,8 +173,8 @@ enum { POWERPC_EXCP_DECR = 10, /* Decrementer exception */ POWERPC_EXCP_FIT = 11, /* Fixed-interval timer interrupt */ POWERPC_EXCP_WDT = 12, /* Watchdog timer interrupt */ - POWERPC_EXCP_DTLB = 13, /* Data TLB error */ - POWERPC_EXCP_ITLB = 14, /* Instruction TLB error */ + POWERPC_EXCP_DTLB = 13, /* Data TLB miss */ + POWERPC_EXCP_ITLB = 14, /* Instruction TLB miss */ POWERPC_EXCP_DEBUG = 15, /* Debug interrupt */ /* Vectors 16 to 31 are reserved */ POWERPC_EXCP_SPEU = 32, /* SPE/embedded floating-point unavailable */ @@ -201,21 +203,27 @@ enum { /* 602 specific exceptions */ POWERPC_EXCP_EMUL = 77, /* Emulation trap exception */ /* 602/603 specific exceptions */ - POWERPC_EXCP_IFTLB = 78, /* Instruction fetch TLB error */ + POWERPC_EXCP_IFTLB = 78, /* Instruction fetch TLB miss */ POWERPC_EXCP_DLTLB = 79, /* Data load TLB miss */ POWERPC_EXCP_DSTLB = 80, /* Data store TLB miss */ /* Exceptions available on most PowerPC */ POWERPC_EXCP_FPA = 81, /* Floating-point assist exception */ - POWERPC_EXCP_IABR = 82, /* Instruction address breakpoint */ - POWERPC_EXCP_SMI = 83, /* System management interrupt */ - POWERPC_EXCP_PERFM = 84, /* Embedded performance monitor interrupt */ + POWERPC_EXCP_DABR = 82, /* Data address breakpoint */ + POWERPC_EXCP_IABR = 83, /* Instruction address breakpoint */ + POWERPC_EXCP_SMI = 84, /* System management interrupt */ + POWERPC_EXCP_PERFM = 85, /* Embedded performance monitor interrupt */ /* 7xx/74xx specific exceptions */ - POWERPC_EXCP_THERM = 85, /* Thermal interrupt */ + POWERPC_EXCP_THERM = 86, /* Thermal interrupt */ /* 74xx specific exceptions */ - POWERPC_EXCP_VPUA = 86, /* Vector assist exception */ + POWERPC_EXCP_VPUA = 87, /* Vector assist exception */ /* 970FX specific exceptions */ - POWERPC_EXCP_SOFTP = 87, /* Soft patch exception */ - POWERPC_EXCP_MAINT = 88, /* Maintenance exception */ + POWERPC_EXCP_SOFTP = 88, /* Soft patch exception */ + POWERPC_EXCP_MAINT = 89, /* Maintenance exception */ + /* Freescale embeded cores specific exceptions */ + POWERPC_EXCP_MEXTBR = 90, /* Maskable external breakpoint */ + POWERPC_EXCP_NMEXTBR = 91, /* Non maskable external breakpoint */ + POWERPC_EXCP_ITLBE = 92, /* Instruction TLB error */ + POWERPC_EXCP_DTLBE = 93, /* Data TLB error */ /* EOL */ POWERPC_EXCP_NB = 96, /* Qemu exceptions: used internally during code translation */ @@ -280,6 +288,8 @@ enum powerpc_input_t { PPC_FLAGS_INPUT_970, /* PowerPC 401 bus */ PPC_FLAGS_INPUT_401, + /* Freescale RCPU bus */ + PPC_FLAGS_INPUT_RCPU, }; #define PPC_INPUT(env) (env->bus_model) @@ -1259,6 +1269,22 @@ enum { PPC40x_INPUT_NB, }; +enum { + /* RCPU input pins */ + PPCRCPU_INPUT_PORESET = 0, + PPCRCPU_INPUT_HRESET = 1, + PPCRCPU_INPUT_SRESET = 2, + PPCRCPU_INPUT_IRQ0 = 3, + PPCRCPU_INPUT_IRQ1 = 4, + PPCRCPU_INPUT_IRQ2 = 5, + PPCRCPU_INPUT_IRQ3 = 6, + PPCRCPU_INPUT_IRQ4 = 7, + PPCRCPU_INPUT_IRQ5 = 8, + PPCRCPU_INPUT_IRQ6 = 9, + PPCRCPU_INPUT_IRQ7 = 10, + PPCRCPU_INPUT_NB, +}; + #if defined(TARGET_PPC64) enum { /* PowerPC 970 input pins */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 854526dad..b4c38395f 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1357,7 +1357,7 @@ static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx, case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: case POWERPC_MMU_SOFT_4xx: - case POWERPC_MMU_REAL_4xx: + case POWERPC_MMU_REAL: case POWERPC_MMU_BOOKE: ctx->prot |= PAGE_WRITE; break; @@ -1392,6 +1392,10 @@ static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx, } } break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ cpu_abort(env, "BookE FSL MMU model not implemented\n"); @@ -1445,12 +1449,16 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, ret = mmubooke_get_physical_address(env, ctx, eaddr, rw, access_type); break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ cpu_abort(env, "BookE FSL MMU model not implemented\n"); return -1; - case POWERPC_MMU_REAL_4xx: - cpu_abort(env, "PowerPC 401 does not do any translation\n"); + case POWERPC_MMU_REAL: + cpu_abort(env, "PowerPC in real mode do not do any translation\n"); return -1; default: cpu_abort(env, "Unknown or invalid MMU model\n"); @@ -1537,15 +1545,19 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, break; case POWERPC_MMU_BOOKE: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookE MMU model is not implemented\n"); return -1; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookE FSL MMU model is not implemented\n"); return -1; - case POWERPC_MMU_REAL_4xx: - cpu_abort(env, "PowerPC 401 should never raise any MMU " - "exceptions\n"); + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; + case POWERPC_MMU_REAL: + cpu_abort(env, "PowerPC in real mode should never raise " + "any MMU exceptions\n"); return -1; default: cpu_abort(env, "Unknown or invalid MMU model\n"); @@ -1632,17 +1644,21 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, else env->spr[SPR_DSISR] = 0x40000000; break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; case POWERPC_MMU_BOOKE: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookE MMU model is not implemented\n"); return -1; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookE FSL MMU model is not implemented\n"); return -1; - case POWERPC_MMU_REAL_4xx: - cpu_abort(env, "PowerPC 401 should never raise any MMU " - "exceptions\n"); + case POWERPC_MMU_REAL: + cpu_abort(env, "PowerPC in real mode should never raise " + "any MMU exceptions\n"); return -1; default: cpu_abort(env, "Unknown or invalid MMU model\n"); @@ -1921,16 +1937,20 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) case POWERPC_MMU_SOFT_4xx_Z: ppc4xx_tlb_invalidate_all(env); break; - case POWERPC_MMU_REAL_4xx: + case POWERPC_MMU_REAL: cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n"); break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; case POWERPC_MMU_BOOKE: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookE MMU model is not implemented\n"); break; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookE MMU model is not implemented\n"); break; case POWERPC_MMU_32B: case POWERPC_MMU_601: @@ -1961,16 +1981,20 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) case POWERPC_MMU_SOFT_4xx_Z: ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]); break; - case POWERPC_MMU_REAL_4xx: + case POWERPC_MMU_REAL: cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n"); break; + case POWERPC_MMU_MPC8xx: + /* XXX: TODO */ + cpu_abort(env, "MPC8xx MMU model is not implemented\n"); + break; case POWERPC_MMU_BOOKE: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookE MMU model is not implemented\n"); break; case POWERPC_MMU_BOOKE_FSL: /* XXX: TODO */ - cpu_abort(env, "MMU model not implemented\n"); + cpu_abort(env, "BookE FSL MMU model is not implemented\n"); break; case POWERPC_MMU_32B: case POWERPC_MMU_601: @@ -2613,6 +2637,10 @@ static always_inline void powerpc_excp (CPUState *env, cpu_abort(env, "Floating point assist exception " "is not implemented yet !\n"); goto store_next; + case POWERPC_EXCP_DABR: /* Data address breakpoint */ + /* XXX: TODO */ + cpu_abort(env, "DABR exception is not implemented yet !\n"); + goto store_next; case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ /* XXX: TODO */ cpu_abort(env, "IABR exception is not implemented yet !\n"); @@ -2648,6 +2676,16 @@ static always_inline void powerpc_excp (CPUState *env, cpu_abort(env, "970 maintenance exception is not implemented yet !\n"); goto store_next; + case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ + /* XXX: TODO */ + cpu_abort(env, "Maskable external exception " + "is not implemented yet !\n"); + goto store_next; + case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ + /* XXX: TODO */ + cpu_abort(env, "Non maskable external exception " + "is not implemented yet !\n"); + goto store_next; default: excp_invalid: cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp); @@ -2899,7 +2937,7 @@ void cpu_ppc_reset (void *opaque) msr |= (target_ulong)1 << MSR_PR; #else env->nip = env->hreset_vector | env->excp_prefix; - if (env->mmu_model != POWERPC_MMU_REAL_4xx) + if (env->mmu_model != POWERPC_MMU_REAL) ppc_tlb_invalidate_all(env); #endif env->msr = msr; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 0f7441ee5..343ec130a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -2656,7 +2656,7 @@ static int check_pow_hid0 (CPUPPCState *env) PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) #define POWERPC_MSRM_401 (0x00000000000FD201ULL) -#define POWERPC_MMU_401 (POWERPC_MMU_REAL_4xx) +#define POWERPC_MMU_401 (POWERPC_MMU_REAL) #define POWERPC_EXCP_401 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401 (bfd_mach_ppc_403) @@ -2775,7 +2775,7 @@ static void init_proc_IOP480 (CPUPPCState *env) PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) #define POWERPC_MSRM_403 (0x000000000007D00DULL) -#define POWERPC_MMU_403 (POWERPC_MMU_REAL_4xx) +#define POWERPC_MMU_403 (POWERPC_MMU_REAL) #define POWERPC_EXCP_403 (POWERPC_EXCP_40x) #define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403 (bfd_mach_ppc_403) @@ -6639,8 +6639,11 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) mmu_model = "PowerPC 4xx with software driven TLBs " "and zones protections"; break; - case POWERPC_MMU_REAL_4xx: - mmu_model = "PowerPC 4xx real mode only"; + case POWERPC_MMU_REAL: + mmu_model = "PowerPC real mode only"; + break; + case POWERPC_MMU_MPC8xx: + mmu_model = "PowerPC MPC8xx"; break; case POWERPC_MMU_BOOKE: mmu_model = "PowerPC BookE"; @@ -6648,6 +6651,9 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) case POWERPC_MMU_BOOKE_FSL: mmu_model = "PowerPC BookE FSL"; break; + case POWERPC_MMU_601: + mmu_model = "PowerPC 601"; + break; #if defined (TARGET_PPC64) case POWERPC_MMU_64B: mmu_model = "PowerPC 64"; @@ -6713,6 +6719,9 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) case PPC_FLAGS_INPUT_401: bus_model = "PowerPC 401/403"; break; + case PPC_FLAGS_INPUT_RCPU: + bus_model = "RCPU / MPC8xx"; + break; #if defined (TARGET_PPC64) case PPC_FLAGS_INPUT_970: bus_model = "PowerPC 970"; -- cgit v1.2.3 From 80d11f4467c49c593c9356b97de6c0b4e12d73c1 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 23:02:20 +0000 Subject: Add definitions for Freescale PowerPC implementations, ie MPC5xx, MPC8xx, e200, e300, e500 and e600 cores. Make those CPUs and PowerPC 440 available for user-mode emulation, thus providing a way of testing their implementation specific instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3681 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 827 +++---- target-ppc/translate_init.c | 5401 ++++++++++++++++++++++++++++--------------- 2 files changed, 3936 insertions(+), 2292 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index a80101c02..a905cc375 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -822,394 +822,447 @@ static inline int cpu_mmu_index (CPUState *env) #define xer_bc env->xer[0] /* SPR definitions */ -#define SPR_MQ (0x000) -#define SPR_XER (0x001) -#define SPR_601_VRTCU (0x004) -#define SPR_601_VRTCL (0x005) -#define SPR_601_UDECR (0x006) -#define SPR_LR (0x008) -#define SPR_CTR (0x009) -#define SPR_DSISR (0x012) -#define SPR_DAR (0x013) /* DAE for PowerPC 601 */ -#define SPR_601_RTCU (0x014) -#define SPR_601_RTCL (0x015) -#define SPR_DECR (0x016) -#define SPR_SDR1 (0x019) -#define SPR_SRR0 (0x01A) -#define SPR_SRR1 (0x01B) -#define SPR_AMR (0x01D) -#define SPR_BOOKE_PID (0x030) -#define SPR_BOOKE_DECAR (0x036) -#define SPR_BOOKE_CSRR0 (0x03A) -#define SPR_BOOKE_CSRR1 (0x03B) -#define SPR_BOOKE_DEAR (0x03D) -#define SPR_BOOKE_ESR (0x03E) -#define SPR_BOOKE_IVPR (0x03F) -#define SPR_8xx_EIE (0x050) -#define SPR_8xx_EID (0x051) -#define SPR_8xx_NRE (0x052) -#define SPR_CTRL (0x088) -#define SPR_58x_CMPA (0x090) -#define SPR_58x_CMPB (0x091) -#define SPR_58x_CMPC (0x092) -#define SPR_58x_CMPD (0x093) -#define SPR_58x_ICR (0x094) -#define SPR_58x_DER (0x094) -#define SPR_58x_COUNTA (0x096) -#define SPR_58x_COUNTB (0x097) -#define SPR_UCTRL (0x098) -#define SPR_58x_CMPE (0x098) -#define SPR_58x_CMPF (0x099) -#define SPR_58x_CMPG (0x09A) -#define SPR_58x_CMPH (0x09B) -#define SPR_58x_LCTRL1 (0x09C) -#define SPR_58x_LCTRL2 (0x09D) -#define SPR_58x_ICTRL (0x09E) -#define SPR_58x_BAR (0x09F) -#define SPR_VRSAVE (0x100) -#define SPR_USPRG0 (0x100) -#define SPR_USPRG1 (0x101) -#define SPR_USPRG2 (0x102) -#define SPR_USPRG3 (0x103) -#define SPR_USPRG4 (0x104) -#define SPR_USPRG5 (0x105) -#define SPR_USPRG6 (0x106) -#define SPR_USPRG7 (0x107) -#define SPR_VTBL (0x10C) -#define SPR_VTBU (0x10D) -#define SPR_SPRG0 (0x110) -#define SPR_SPRG1 (0x111) -#define SPR_SPRG2 (0x112) -#define SPR_SPRG3 (0x113) -#define SPR_SPRG4 (0x114) -#define SPR_SCOMC (0x114) -#define SPR_SPRG5 (0x115) -#define SPR_SCOMD (0x115) -#define SPR_SPRG6 (0x116) -#define SPR_SPRG7 (0x117) -#define SPR_ASR (0x118) -#define SPR_EAR (0x11A) -#define SPR_TBL (0x11C) -#define SPR_TBU (0x11D) -#define SPR_TBU40 (0x11E) -#define SPR_SVR (0x11E) -#define SPR_BOOKE_PIR (0x11E) -#define SPR_PVR (0x11F) -#define SPR_HSPRG0 (0x130) -#define SPR_BOOKE_DBSR (0x130) -#define SPR_HSPRG1 (0x131) -#define SPR_HDSISR (0x132) -#define SPR_HDAR (0x133) -#define SPR_BOOKE_DBCR0 (0x134) -#define SPR_IBCR (0x135) -#define SPR_PURR (0x135) -#define SPR_BOOKE_DBCR1 (0x135) -#define SPR_DBCR (0x136) -#define SPR_HDEC (0x136) -#define SPR_BOOKE_DBCR2 (0x136) -#define SPR_HIOR (0x137) -#define SPR_MBAR (0x137) -#define SPR_RMOR (0x138) -#define SPR_BOOKE_IAC1 (0x138) -#define SPR_HRMOR (0x139) -#define SPR_BOOKE_IAC2 (0x139) -#define SPR_HSRR0 (0x13A) -#define SPR_BOOKE_IAC3 (0x13A) -#define SPR_HSRR1 (0x13B) -#define SPR_BOOKE_IAC4 (0x13B) -#define SPR_LPCR (0x13C) -#define SPR_BOOKE_DAC1 (0x13C) -#define SPR_LPIDR (0x13D) -#define SPR_DABR2 (0x13D) -#define SPR_BOOKE_DAC2 (0x13D) -#define SPR_BOOKE_DVC1 (0x13E) -#define SPR_BOOKE_DVC2 (0x13F) -#define SPR_BOOKE_TSR (0x150) -#define SPR_BOOKE_TCR (0x154) -#define SPR_BOOKE_IVOR0 (0x190) -#define SPR_BOOKE_IVOR1 (0x191) -#define SPR_BOOKE_IVOR2 (0x192) -#define SPR_BOOKE_IVOR3 (0x193) -#define SPR_BOOKE_IVOR4 (0x194) -#define SPR_BOOKE_IVOR5 (0x195) -#define SPR_BOOKE_IVOR6 (0x196) -#define SPR_BOOKE_IVOR7 (0x197) -#define SPR_BOOKE_IVOR8 (0x198) -#define SPR_BOOKE_IVOR9 (0x199) -#define SPR_BOOKE_IVOR10 (0x19A) -#define SPR_BOOKE_IVOR11 (0x19B) -#define SPR_BOOKE_IVOR12 (0x19C) -#define SPR_BOOKE_IVOR13 (0x19D) -#define SPR_BOOKE_IVOR14 (0x19E) -#define SPR_BOOKE_IVOR15 (0x19F) -#define SPR_BOOKE_SPEFSCR (0x200) -#define SPR_E500_BBEAR (0x201) -#define SPR_E500_BBTAR (0x202) -#define SPR_ATBL (0x20E) -#define SPR_ATBU (0x20F) -#define SPR_IBAT0U (0x210) -#define SPR_BOOKE_IVOR32 (0x210) -#define SPR_IBAT0L (0x211) -#define SPR_BOOKE_IVOR33 (0x211) -#define SPR_IBAT1U (0x212) -#define SPR_BOOKE_IVOR34 (0x212) -#define SPR_IBAT1L (0x213) -#define SPR_BOOKE_IVOR35 (0x213) -#define SPR_IBAT2U (0x214) -#define SPR_BOOKE_IVOR36 (0x214) -#define SPR_IBAT2L (0x215) -#define SPR_E500_L1CFG0 (0x215) -#define SPR_BOOKE_IVOR37 (0x215) -#define SPR_IBAT3U (0x216) -#define SPR_E500_L1CFG1 (0x216) -#define SPR_IBAT3L (0x217) -#define SPR_DBAT0U (0x218) -#define SPR_DBAT0L (0x219) -#define SPR_DBAT1U (0x21A) -#define SPR_DBAT1L (0x21B) -#define SPR_DBAT2U (0x21C) -#define SPR_DBAT2L (0x21D) -#define SPR_DBAT3U (0x21E) -#define SPR_DBAT3L (0x21F) -#define SPR_IBAT4U (0x230) -#define SPR_IBAT4L (0x231) -#define SPR_IBAT5U (0x232) -#define SPR_IBAT5L (0x233) -#define SPR_IBAT6U (0x234) -#define SPR_IBAT6L (0x235) -#define SPR_IBAT7U (0x236) -#define SPR_IBAT7L (0x237) -#define SPR_DBAT4U (0x238) -#define SPR_DBAT4L (0x239) -#define SPR_DBAT5U (0x23A) -#define SPR_BOOKE_MCSRR0 (0x23A) -#define SPR_DBAT5L (0x23B) -#define SPR_BOOKE_MCSRR1 (0x23B) -#define SPR_DBAT6U (0x23C) -#define SPR_BOOKE_MCSR (0x23C) -#define SPR_DBAT6L (0x23D) -#define SPR_E500_MCAR (0x23D) -#define SPR_DBAT7U (0x23E) -#define SPR_BOOKE_DSRR0 (0x23E) -#define SPR_DBAT7L (0x23F) -#define SPR_BOOKE_DSRR1 (0x23F) -#define SPR_BOOKE_SPRG8 (0x25C) -#define SPR_BOOKE_SPRG9 (0x25D) -#define SPR_BOOKE_MAS0 (0x270) -#define SPR_BOOKE_MAS1 (0x271) -#define SPR_BOOKE_MAS2 (0x272) -#define SPR_BOOKE_MAS3 (0x273) -#define SPR_BOOKE_MAS4 (0x274) -#define SPR_BOOKE_MAS6 (0x276) -#define SPR_BOOKE_PID1 (0x279) -#define SPR_BOOKE_PID2 (0x27A) -#define SPR_BOOKE_TLB0CFG (0x2B0) -#define SPR_BOOKE_TLB1CFG (0x2B1) -#define SPR_BOOKE_TLB2CFG (0x2B2) -#define SPR_BOOKE_TLB3CFG (0x2B3) -#define SPR_BOOKE_EPR (0x2BE) -#define SPR_PERF0 (0x300) -#define SPR_PERF1 (0x301) -#define SPR_PERF2 (0x302) -#define SPR_PERF3 (0x303) -#define SPR_PERF4 (0x304) -#define SPR_PERF5 (0x305) -#define SPR_PERF6 (0x306) -#define SPR_PERF7 (0x307) -#define SPR_PERF8 (0x308) -#define SPR_PERF9 (0x309) -#define SPR_PERFA (0x30A) -#define SPR_PERFB (0x30B) -#define SPR_PERFC (0x30C) -#define SPR_PERFD (0x30D) -#define SPR_PERFE (0x30E) -#define SPR_PERFF (0x30F) -#define SPR_UPERF0 (0x310) -#define SPR_UPERF1 (0x311) -#define SPR_UPERF2 (0x312) -#define SPR_UPERF3 (0x313) -#define SPR_UPERF4 (0x314) -#define SPR_UPERF5 (0x315) -#define SPR_UPERF6 (0x316) -#define SPR_UPERF7 (0x317) -#define SPR_UPERF8 (0x318) -#define SPR_UPERF9 (0x319) -#define SPR_UPERFA (0x31A) -#define SPR_UPERFB (0x31B) -#define SPR_UPERFC (0x31C) -#define SPR_UPERFD (0x31D) -#define SPR_UPERFE (0x31E) -#define SPR_UPERFF (0x31F) -#define SPR_440_INV0 (0x370) -#define SPR_440_INV1 (0x371) -#define SPR_440_INV2 (0x372) -#define SPR_440_INV3 (0x373) -#define SPR_440_ITV0 (0x374) -#define SPR_440_ITV1 (0x375) -#define SPR_440_ITV2 (0x376) -#define SPR_440_ITV3 (0x377) -#define SPR_440_CCR1 (0x378) -#define SPR_DCRIPR (0x37B) -#define SPR_PPR (0x380) -#define SPR_440_DNV0 (0x390) -#define SPR_440_DNV1 (0x391) -#define SPR_440_DNV2 (0x392) -#define SPR_440_DNV3 (0x393) -#define SPR_440_DTV0 (0x394) -#define SPR_440_DTV1 (0x395) -#define SPR_440_DTV2 (0x396) -#define SPR_440_DTV3 (0x397) -#define SPR_440_DVLIM (0x398) -#define SPR_440_IVLIM (0x399) -#define SPR_440_RSTCFG (0x39B) -#define SPR_BOOKE_DCDBTRL (0x39C) -#define SPR_BOOKE_DCDBTRH (0x39D) -#define SPR_BOOKE_ICDBTRL (0x39E) -#define SPR_BOOKE_ICDBTRH (0x39F) -#define SPR_UMMCR2 (0x3A0) -#define SPR_UPMC5 (0x3A1) -#define SPR_UPMC6 (0x3A2) -#define SPR_UBAMR (0x3A7) -#define SPR_UMMCR0 (0x3A8) -#define SPR_UPMC1 (0x3A9) -#define SPR_UPMC2 (0x3AA) -#define SPR_USIAR (0x3AB) -#define SPR_UMMCR1 (0x3AC) -#define SPR_UPMC3 (0x3AD) -#define SPR_UPMC4 (0x3AE) -#define SPR_USDA (0x3AF) -#define SPR_40x_ZPR (0x3B0) -#define SPR_BOOKE_MAS7 (0x3B0) -#define SPR_620_PMR0 (0x3B0) -#define SPR_MMCR2 (0x3B0) -#define SPR_PMC5 (0x3B1) -#define SPR_40x_PID (0x3B1) -#define SPR_620_PMR1 (0x3B1) -#define SPR_PMC6 (0x3B2) -#define SPR_440_MMUCR (0x3B2) -#define SPR_620_PMR2 (0x3B2) -#define SPR_4xx_CCR0 (0x3B3) -#define SPR_BOOKE_EPLC (0x3B3) -#define SPR_620_PMR3 (0x3B3) -#define SPR_405_IAC3 (0x3B4) -#define SPR_BOOKE_EPSC (0x3B4) -#define SPR_620_PMR4 (0x3B4) -#define SPR_405_IAC4 (0x3B5) -#define SPR_620_PMR5 (0x3B5) -#define SPR_405_DVC1 (0x3B6) -#define SPR_620_PMR6 (0x3B6) -#define SPR_405_DVC2 (0x3B7) -#define SPR_620_PMR7 (0x3B7) -#define SPR_BAMR (0x3B7) -#define SPR_MMCR0 (0x3B8) -#define SPR_620_PMR8 (0x3B8) -#define SPR_PMC1 (0x3B9) -#define SPR_40x_SGR (0x3B9) -#define SPR_620_PMR9 (0x3B9) -#define SPR_PMC2 (0x3BA) -#define SPR_40x_DCWR (0x3BA) -#define SPR_620_PMRA (0x3BA) -#define SPR_SIAR (0x3BB) -#define SPR_405_SLER (0x3BB) -#define SPR_620_PMRB (0x3BB) -#define SPR_MMCR1 (0x3BC) -#define SPR_405_SU0R (0x3BC) -#define SPR_620_PMRC (0x3BC) -#define SPR_401_SKR (0x3BC) -#define SPR_PMC3 (0x3BD) -#define SPR_405_DBCR1 (0x3BD) -#define SPR_620_PMRD (0x3BD) -#define SPR_PMC4 (0x3BE) -#define SPR_620_PMRE (0x3BE) -#define SPR_SDA (0x3BF) -#define SPR_620_PMRF (0x3BF) -#define SPR_403_VTBL (0x3CC) -#define SPR_403_VTBU (0x3CD) -#define SPR_DMISS (0x3D0) -#define SPR_DCMP (0x3D1) -#define SPR_HASH1 (0x3D2) -#define SPR_HASH2 (0x3D3) -#define SPR_BOOKE_ICDBDR (0x3D3) -#define SPR_TLBMISS (0x3D4) -#define SPR_IMISS (0x3D4) -#define SPR_40x_ESR (0x3D4) -#define SPR_PTEHI (0x3D5) -#define SPR_ICMP (0x3D5) -#define SPR_40x_DEAR (0x3D5) -#define SPR_PTELO (0x3D6) -#define SPR_RPA (0x3D6) -#define SPR_40x_EVPR (0x3D6) -#define SPR_L3PM (0x3D7) -#define SPR_403_CDBCR (0x3D7) -#define SPR_L3OHCR (0x3D8) -#define SPR_TCR (0x3D8) -#define SPR_40x_TSR (0x3D8) -#define SPR_IBR (0x3DA) -#define SPR_40x_TCR (0x3DA) -#define SPR_ESASRR (0x3DB) -#define SPR_40x_PIT (0x3DB) -#define SPR_403_TBL (0x3DC) -#define SPR_403_TBU (0x3DD) -#define SPR_SEBR (0x3DE) -#define SPR_40x_SRR2 (0x3DE) -#define SPR_SER (0x3DF) -#define SPR_40x_SRR3 (0x3DF) -#define SPR_L3ITCR0 (0x3E8) -#define SPR_L3ITCR1 (0x3E9) -#define SPR_L3ITCR2 (0x3EA) -#define SPR_L3ITCR3 (0x3EB) -#define SPR_HID0 (0x3F0) -#define SPR_40x_DBSR (0x3F0) -#define SPR_HID1 (0x3F1) -#define SPR_IABR (0x3F2) -#define SPR_40x_DBCR0 (0x3F2) -#define SPR_601_HID2 (0x3F2) -#define SPR_E500_L1CSR0 (0x3F2) -#define SPR_ICTRL (0x3F3) -#define SPR_HID2 (0x3F3) -#define SPR_E500_L1CSR1 (0x3F3) -#define SPR_440_DBDR (0x3F3) -#define SPR_LDSTDB (0x3F4) -#define SPR_40x_IAC1 (0x3F4) -#define SPR_MMUCSR0 (0x3F4) -#define SPR_DABR (0x3F5) +#define SPR_MQ (0x000) +#define SPR_XER (0x001) +#define SPR_601_VRTCU (0x004) +#define SPR_601_VRTCL (0x005) +#define SPR_601_UDECR (0x006) +#define SPR_LR (0x008) +#define SPR_CTR (0x009) +#define SPR_DSISR (0x012) +#define SPR_DAR (0x013) /* DAE for PowerPC 601 */ +#define SPR_601_RTCU (0x014) +#define SPR_601_RTCL (0x015) +#define SPR_DECR (0x016) +#define SPR_SDR1 (0x019) +#define SPR_SRR0 (0x01A) +#define SPR_SRR1 (0x01B) +#define SPR_AMR (0x01D) +#define SPR_BOOKE_PID (0x030) +#define SPR_BOOKE_DECAR (0x036) +#define SPR_BOOKE_CSRR0 (0x03A) +#define SPR_BOOKE_CSRR1 (0x03B) +#define SPR_BOOKE_DEAR (0x03D) +#define SPR_BOOKE_ESR (0x03E) +#define SPR_BOOKE_IVPR (0x03F) +#define SPR_MPC_EIE (0x050) +#define SPR_MPC_EID (0x051) +#define SPR_MPC_NRI (0x052) +#define SPR_CTRL (0x088) +#define SPR_MPC_CMPA (0x090) +#define SPR_MPC_CMPB (0x091) +#define SPR_MPC_CMPC (0x092) +#define SPR_MPC_CMPD (0x093) +#define SPR_MPC_ECR (0x094) +#define SPR_MPC_DER (0x095) +#define SPR_MPC_COUNTA (0x096) +#define SPR_MPC_COUNTB (0x097) +#define SPR_UCTRL (0x098) +#define SPR_MPC_CMPE (0x098) +#define SPR_MPC_CMPF (0x099) +#define SPR_MPC_CMPG (0x09A) +#define SPR_MPC_CMPH (0x09B) +#define SPR_MPC_LCTRL1 (0x09C) +#define SPR_MPC_LCTRL2 (0x09D) +#define SPR_MPC_ICTRL (0x09E) +#define SPR_MPC_BAR (0x09F) +#define SPR_VRSAVE (0x100) +#define SPR_USPRG0 (0x100) +#define SPR_USPRG1 (0x101) +#define SPR_USPRG2 (0x102) +#define SPR_USPRG3 (0x103) +#define SPR_USPRG4 (0x104) +#define SPR_USPRG5 (0x105) +#define SPR_USPRG6 (0x106) +#define SPR_USPRG7 (0x107) +#define SPR_VTBL (0x10C) +#define SPR_VTBU (0x10D) +#define SPR_SPRG0 (0x110) +#define SPR_SPRG1 (0x111) +#define SPR_SPRG2 (0x112) +#define SPR_SPRG3 (0x113) +#define SPR_SPRG4 (0x114) +#define SPR_SCOMC (0x114) +#define SPR_SPRG5 (0x115) +#define SPR_SCOMD (0x115) +#define SPR_SPRG6 (0x116) +#define SPR_SPRG7 (0x117) +#define SPR_ASR (0x118) +#define SPR_EAR (0x11A) +#define SPR_TBL (0x11C) +#define SPR_TBU (0x11D) +#define SPR_TBU40 (0x11E) +#define SPR_SVR (0x11E) +#define SPR_BOOKE_PIR (0x11E) +#define SPR_PVR (0x11F) +#define SPR_HSPRG0 (0x130) +#define SPR_BOOKE_DBSR (0x130) +#define SPR_HSPRG1 (0x131) +#define SPR_HDSISR (0x132) +#define SPR_HDAR (0x133) +#define SPR_BOOKE_DBCR0 (0x134) +#define SPR_IBCR (0x135) +#define SPR_PURR (0x135) +#define SPR_BOOKE_DBCR1 (0x135) +#define SPR_DBCR (0x136) +#define SPR_HDEC (0x136) +#define SPR_BOOKE_DBCR2 (0x136) +#define SPR_HIOR (0x137) +#define SPR_MBAR (0x137) +#define SPR_RMOR (0x138) +#define SPR_BOOKE_IAC1 (0x138) +#define SPR_HRMOR (0x139) +#define SPR_BOOKE_IAC2 (0x139) +#define SPR_HSRR0 (0x13A) +#define SPR_BOOKE_IAC3 (0x13A) +#define SPR_HSRR1 (0x13B) +#define SPR_BOOKE_IAC4 (0x13B) +#define SPR_LPCR (0x13C) +#define SPR_BOOKE_DAC1 (0x13C) +#define SPR_LPIDR (0x13D) +#define SPR_DABR2 (0x13D) +#define SPR_BOOKE_DAC2 (0x13D) +#define SPR_BOOKE_DVC1 (0x13E) +#define SPR_BOOKE_DVC2 (0x13F) +#define SPR_BOOKE_TSR (0x150) +#define SPR_BOOKE_TCR (0x154) +#define SPR_BOOKE_IVOR0 (0x190) +#define SPR_BOOKE_IVOR1 (0x191) +#define SPR_BOOKE_IVOR2 (0x192) +#define SPR_BOOKE_IVOR3 (0x193) +#define SPR_BOOKE_IVOR4 (0x194) +#define SPR_BOOKE_IVOR5 (0x195) +#define SPR_BOOKE_IVOR6 (0x196) +#define SPR_BOOKE_IVOR7 (0x197) +#define SPR_BOOKE_IVOR8 (0x198) +#define SPR_BOOKE_IVOR9 (0x199) +#define SPR_BOOKE_IVOR10 (0x19A) +#define SPR_BOOKE_IVOR11 (0x19B) +#define SPR_BOOKE_IVOR12 (0x19C) +#define SPR_BOOKE_IVOR13 (0x19D) +#define SPR_BOOKE_IVOR14 (0x19E) +#define SPR_BOOKE_IVOR15 (0x19F) +#define SPR_BOOKE_SPEFSCR (0x200) +#define SPR_Exxx_BBEAR (0x201) +#define SPR_Exxx_BBTAR (0x202) +#define SPR_Exxx_L1CFG0 (0x203) +#define SPR_Exxx_NPIDR (0x205) +#define SPR_ATBL (0x20E) +#define SPR_ATBU (0x20F) +#define SPR_IBAT0U (0x210) +#define SPR_BOOKE_IVOR32 (0x210) +#define SPR_RCPU_MI_GRA (0x210) +#define SPR_IBAT0L (0x211) +#define SPR_BOOKE_IVOR33 (0x211) +#define SPR_IBAT1U (0x212) +#define SPR_BOOKE_IVOR34 (0x212) +#define SPR_IBAT1L (0x213) +#define SPR_BOOKE_IVOR35 (0x213) +#define SPR_IBAT2U (0x214) +#define SPR_BOOKE_IVOR36 (0x214) +#define SPR_IBAT2L (0x215) +#define SPR_BOOKE_IVOR37 (0x215) +#define SPR_IBAT3U (0x216) +#define SPR_IBAT3L (0x217) +#define SPR_DBAT0U (0x218) +#define SPR_RCPU_L2U_GRA (0x218) +#define SPR_DBAT0L (0x219) +#define SPR_DBAT1U (0x21A) +#define SPR_DBAT1L (0x21B) +#define SPR_DBAT2U (0x21C) +#define SPR_DBAT2L (0x21D) +#define SPR_DBAT3U (0x21E) +#define SPR_DBAT3L (0x21F) +#define SPR_IBAT4U (0x230) +#define SPR_RPCU_BBCMCR (0x230) +#define SPR_MPC_IC_CST (0x230) +#define SPR_Exxx_CTXCR (0x230) +#define SPR_IBAT4L (0x231) +#define SPR_MPC_IC_ADR (0x231) +#define SPR_Exxx_DBCR3 (0x231) +#define SPR_IBAT5U (0x232) +#define SPR_MPC_IC_DAT (0x232) +#define SPR_Exxx_DBCNT (0x232) +#define SPR_IBAT5L (0x233) +#define SPR_IBAT6U (0x234) +#define SPR_IBAT6L (0x235) +#define SPR_IBAT7U (0x236) +#define SPR_IBAT7L (0x237) +#define SPR_DBAT4U (0x238) +#define SPR_RCPU_L2U_MCR (0x238) +#define SPR_MPC_DC_CST (0x238) +#define SPR_Exxx_ALTCTXCR (0x238) +#define SPR_DBAT4L (0x239) +#define SPR_MPC_DC_ADR (0x239) +#define SPR_DBAT5U (0x23A) +#define SPR_BOOKE_MCSRR0 (0x23A) +#define SPR_MPC_DC_DAT (0x23A) +#define SPR_DBAT5L (0x23B) +#define SPR_BOOKE_MCSRR1 (0x23B) +#define SPR_DBAT6U (0x23C) +#define SPR_BOOKE_MCSR (0x23C) +#define SPR_DBAT6L (0x23D) +#define SPR_Exxx_MCAR (0x23D) +#define SPR_DBAT7U (0x23E) +#define SPR_BOOKE_DSRR0 (0x23E) +#define SPR_DBAT7L (0x23F) +#define SPR_BOOKE_DSRR1 (0x23F) +#define SPR_BOOKE_SPRG8 (0x25C) +#define SPR_BOOKE_SPRG9 (0x25D) +#define SPR_BOOKE_MAS0 (0x270) +#define SPR_BOOKE_MAS1 (0x271) +#define SPR_BOOKE_MAS2 (0x272) +#define SPR_BOOKE_MAS3 (0x273) +#define SPR_BOOKE_MAS4 (0x274) +#define SPR_BOOKE_MAS5 (0x275) +#define SPR_BOOKE_MAS6 (0x276) +#define SPR_BOOKE_PID1 (0x279) +#define SPR_BOOKE_PID2 (0x27A) +#define SPR_MPC_DPDR (0x280) +#define SPR_MPC_IMMR (0x288) +#define SPR_BOOKE_TLB0CFG (0x2B0) +#define SPR_BOOKE_TLB1CFG (0x2B1) +#define SPR_BOOKE_TLB2CFG (0x2B2) +#define SPR_BOOKE_TLB3CFG (0x2B3) +#define SPR_BOOKE_EPR (0x2BE) +#define SPR_PERF0 (0x300) +#define SPR_RCPU_MI_RBA0 (0x300) +#define SPR_MPC_MI_CTR (0x300) +#define SPR_PERF1 (0x301) +#define SPR_RCPU_MI_RBA1 (0x301) +#define SPR_PERF2 (0x302) +#define SPR_RCPU_MI_RBA2 (0x302) +#define SPR_MPC_MI_AP (0x302) +#define SPR_PERF3 (0x303) +#define SPR_RCPU_MI_RBA3 (0x303) +#define SPR_MPC_MI_EPN (0x303) +#define SPR_PERF4 (0x304) +#define SPR_PERF5 (0x305) +#define SPR_MPC_MI_TWC (0x305) +#define SPR_PERF6 (0x306) +#define SPR_MPC_MI_RPN (0x306) +#define SPR_PERF7 (0x307) +#define SPR_PERF8 (0x308) +#define SPR_RCPU_L2U_RBA0 (0x308) +#define SPR_MPC_MD_CTR (0x308) +#define SPR_PERF9 (0x309) +#define SPR_RCPU_L2U_RBA1 (0x309) +#define SPR_MPC_MD_CASID (0x309) +#define SPR_PERFA (0x30A) +#define SPR_RCPU_L2U_RBA2 (0x30A) +#define SPR_MPC_MD_AP (0x30A) +#define SPR_PERFB (0x30B) +#define SPR_RCPU_L2U_RBA3 (0x30B) +#define SPR_MPC_MD_EPN (0x30B) +#define SPR_PERFC (0x30C) +#define SPR_MPC_MD_TWB (0x30C) +#define SPR_PERFD (0x30D) +#define SPR_MPC_MD_TWC (0x30D) +#define SPR_PERFE (0x30E) +#define SPR_MPC_MD_RPN (0x30E) +#define SPR_PERFF (0x30F) +#define SPR_MPC_MD_TW (0x30F) +#define SPR_UPERF0 (0x310) +#define SPR_UPERF1 (0x311) +#define SPR_UPERF2 (0x312) +#define SPR_UPERF3 (0x313) +#define SPR_UPERF4 (0x314) +#define SPR_UPERF5 (0x315) +#define SPR_UPERF6 (0x316) +#define SPR_UPERF7 (0x317) +#define SPR_UPERF8 (0x318) +#define SPR_UPERF9 (0x319) +#define SPR_UPERFA (0x31A) +#define SPR_UPERFB (0x31B) +#define SPR_UPERFC (0x31C) +#define SPR_UPERFD (0x31D) +#define SPR_UPERFE (0x31E) +#define SPR_UPERFF (0x31F) +#define SPR_RCPU_MI_RA0 (0x320) +#define SPR_MPC_MI_DBCAM (0x320) +#define SPR_RCPU_MI_RA1 (0x321) +#define SPR_MPC_MI_DBRAM0 (0x321) +#define SPR_RCPU_MI_RA2 (0x322) +#define SPR_MPC_MI_DBRAM1 (0x322) +#define SPR_RCPU_MI_RA3 (0x323) +#define SPR_RCPU_L2U_RA0 (0x328) +#define SPR_MPC_MD_DBCAM (0x328) +#define SPR_RCPU_L2U_RA1 (0x329) +#define SPR_MPC_MD_DBRAM0 (0x329) +#define SPR_RCPU_L2U_RA2 (0x32A) +#define SPR_MPC_MD_DBRAM1 (0x32A) +#define SPR_RCPU_L2U_RA3 (0x32B) +#define SPR_440_INV0 (0x370) +#define SPR_440_INV1 (0x371) +#define SPR_440_INV2 (0x372) +#define SPR_440_INV3 (0x373) +#define SPR_440_ITV0 (0x374) +#define SPR_440_ITV1 (0x375) +#define SPR_440_ITV2 (0x376) +#define SPR_440_ITV3 (0x377) +#define SPR_440_CCR1 (0x378) +#define SPR_DCRIPR (0x37B) +#define SPR_PPR (0x380) +#define SPR_440_DNV0 (0x390) +#define SPR_440_DNV1 (0x391) +#define SPR_440_DNV2 (0x392) +#define SPR_440_DNV3 (0x393) +#define SPR_440_DTV0 (0x394) +#define SPR_440_DTV1 (0x395) +#define SPR_440_DTV2 (0x396) +#define SPR_440_DTV3 (0x397) +#define SPR_440_DVLIM (0x398) +#define SPR_440_IVLIM (0x399) +#define SPR_440_RSTCFG (0x39B) +#define SPR_BOOKE_DCDBTRL (0x39C) +#define SPR_BOOKE_DCDBTRH (0x39D) +#define SPR_BOOKE_ICDBTRL (0x39E) +#define SPR_BOOKE_ICDBTRH (0x39F) +#define SPR_UMMCR2 (0x3A0) +#define SPR_UPMC5 (0x3A1) +#define SPR_UPMC6 (0x3A2) +#define SPR_UBAMR (0x3A7) +#define SPR_UMMCR0 (0x3A8) +#define SPR_UPMC1 (0x3A9) +#define SPR_UPMC2 (0x3AA) +#define SPR_USIAR (0x3AB) +#define SPR_UMMCR1 (0x3AC) +#define SPR_UPMC3 (0x3AD) +#define SPR_UPMC4 (0x3AE) +#define SPR_USDA (0x3AF) +#define SPR_40x_ZPR (0x3B0) +#define SPR_BOOKE_MAS7 (0x3B0) +#define SPR_620_PMR0 (0x3B0) +#define SPR_MMCR2 (0x3B0) +#define SPR_PMC5 (0x3B1) +#define SPR_40x_PID (0x3B1) +#define SPR_620_PMR1 (0x3B1) +#define SPR_PMC6 (0x3B2) +#define SPR_440_MMUCR (0x3B2) +#define SPR_620_PMR2 (0x3B2) +#define SPR_4xx_CCR0 (0x3B3) +#define SPR_BOOKE_EPLC (0x3B3) +#define SPR_620_PMR3 (0x3B3) +#define SPR_405_IAC3 (0x3B4) +#define SPR_BOOKE_EPSC (0x3B4) +#define SPR_620_PMR4 (0x3B4) +#define SPR_405_IAC4 (0x3B5) +#define SPR_620_PMR5 (0x3B5) +#define SPR_405_DVC1 (0x3B6) +#define SPR_620_PMR6 (0x3B6) +#define SPR_405_DVC2 (0x3B7) +#define SPR_620_PMR7 (0x3B7) +#define SPR_BAMR (0x3B7) +#define SPR_MMCR0 (0x3B8) +#define SPR_620_PMR8 (0x3B8) +#define SPR_PMC1 (0x3B9) +#define SPR_40x_SGR (0x3B9) +#define SPR_620_PMR9 (0x3B9) +#define SPR_PMC2 (0x3BA) +#define SPR_40x_DCWR (0x3BA) +#define SPR_620_PMRA (0x3BA) +#define SPR_SIAR (0x3BB) +#define SPR_405_SLER (0x3BB) +#define SPR_620_PMRB (0x3BB) +#define SPR_MMCR1 (0x3BC) +#define SPR_405_SU0R (0x3BC) +#define SPR_620_PMRC (0x3BC) +#define SPR_401_SKR (0x3BC) +#define SPR_PMC3 (0x3BD) +#define SPR_405_DBCR1 (0x3BD) +#define SPR_620_PMRD (0x3BD) +#define SPR_PMC4 (0x3BE) +#define SPR_620_PMRE (0x3BE) +#define SPR_SDA (0x3BF) +#define SPR_620_PMRF (0x3BF) +#define SPR_403_VTBL (0x3CC) +#define SPR_403_VTBU (0x3CD) +#define SPR_DMISS (0x3D0) +#define SPR_DCMP (0x3D1) +#define SPR_HASH1 (0x3D2) +#define SPR_HASH2 (0x3D3) +#define SPR_BOOKE_ICDBDR (0x3D3) +#define SPR_TLBMISS (0x3D4) +#define SPR_IMISS (0x3D4) +#define SPR_40x_ESR (0x3D4) +#define SPR_PTEHI (0x3D5) +#define SPR_ICMP (0x3D5) +#define SPR_40x_DEAR (0x3D5) +#define SPR_PTELO (0x3D6) +#define SPR_RPA (0x3D6) +#define SPR_40x_EVPR (0x3D6) +#define SPR_L3PM (0x3D7) +#define SPR_403_CDBCR (0x3D7) +#define SPR_L3OHCR (0x3D8) +#define SPR_TCR (0x3D8) +#define SPR_40x_TSR (0x3D8) +#define SPR_IBR (0x3DA) +#define SPR_40x_TCR (0x3DA) +#define SPR_ESASRR (0x3DB) +#define SPR_40x_PIT (0x3DB) +#define SPR_403_TBL (0x3DC) +#define SPR_403_TBU (0x3DD) +#define SPR_SEBR (0x3DE) +#define SPR_40x_SRR2 (0x3DE) +#define SPR_SER (0x3DF) +#define SPR_40x_SRR3 (0x3DF) +#define SPR_L3ITCR0 (0x3E8) +#define SPR_L3ITCR1 (0x3E9) +#define SPR_L3ITCR2 (0x3EA) +#define SPR_L3ITCR3 (0x3EB) +#define SPR_HID0 (0x3F0) +#define SPR_40x_DBSR (0x3F0) +#define SPR_HID1 (0x3F1) +#define SPR_IABR (0x3F2) +#define SPR_40x_DBCR0 (0x3F2) +#define SPR_601_HID2 (0x3F2) +#define SPR_Exxx_L1CSR0 (0x3F2) +#define SPR_ICTRL (0x3F3) +#define SPR_HID2 (0x3F3) +#define SPR_Exxx_L1CSR1 (0x3F3) +#define SPR_440_DBDR (0x3F3) +#define SPR_LDSTDB (0x3F4) +#define SPR_40x_IAC1 (0x3F4) +#define SPR_MMUCSR0 (0x3F4) +#define SPR_DABR (0x3F5) #define DABR_MASK (~(target_ulong)0x7) -#define SPR_E500_BUCSR (0x3F5) -#define SPR_40x_IAC2 (0x3F5) -#define SPR_601_HID5 (0x3F5) -#define SPR_40x_DAC1 (0x3F6) -#define SPR_MSSCR0 (0x3F6) -#define SPR_970_HID5 (0x3F6) -#define SPR_MSSSR0 (0x3F7) -#define SPR_DABRX (0x3F7) -#define SPR_40x_DAC2 (0x3F7) -#define SPR_MMUCFG (0x3F7) -#define SPR_LDSTCR (0x3F8) -#define SPR_L2PMCR (0x3F8) -#define SPR_750_HID2 (0x3F8) -#define SPR_620_HID8 (0x3F8) -#define SPR_L2CR (0x3F9) -#define SPR_620_HID9 (0x3F9) -#define SPR_L3CR (0x3FA) -#define SPR_IABR2 (0x3FA) -#define SPR_40x_DCCR (0x3FA) -#define SPR_ICTC (0x3FB) -#define SPR_40x_ICCR (0x3FB) -#define SPR_THRM1 (0x3FC) -#define SPR_403_PBL1 (0x3FC) -#define SPR_SP (0x3FD) -#define SPR_THRM2 (0x3FD) -#define SPR_403_PBU1 (0x3FD) -#define SPR_604_HID13 (0x3FD) -#define SPR_LT (0x3FE) -#define SPR_THRM3 (0x3FE) -#define SPR_FPECR (0x3FE) -#define SPR_403_PBL2 (0x3FE) -#define SPR_PIR (0x3FF) -#define SPR_403_PBU2 (0x3FF) -#define SPR_601_HID15 (0x3FF) -#define SPR_604_HID15 (0x3FF) -#define SPR_E500_SVR (0x3FF) +#define SPR_Exxx_BUCSR (0x3F5) +#define SPR_40x_IAC2 (0x3F5) +#define SPR_601_HID5 (0x3F5) +#define SPR_40x_DAC1 (0x3F6) +#define SPR_MSSCR0 (0x3F6) +#define SPR_970_HID5 (0x3F6) +#define SPR_MSSSR0 (0x3F7) +#define SPR_DABRX (0x3F7) +#define SPR_40x_DAC2 (0x3F7) +#define SPR_MMUCFG (0x3F7) +#define SPR_LDSTCR (0x3F8) +#define SPR_L2PMCR (0x3F8) +#define SPR_750_HID2 (0x3F8) +#define SPR_620_HID8 (0x3F8) +#define SPR_Exxx_L1FINV0 (0x3F8) +#define SPR_L2CR (0x3F9) +#define SPR_620_HID9 (0x3F9) +#define SPR_L3CR (0x3FA) +#define SPR_IABR2 (0x3FA) +#define SPR_40x_DCCR (0x3FA) +#define SPR_ICTC (0x3FB) +#define SPR_40x_ICCR (0x3FB) +#define SPR_THRM1 (0x3FC) +#define SPR_403_PBL1 (0x3FC) +#define SPR_SP (0x3FD) +#define SPR_THRM2 (0x3FD) +#define SPR_403_PBU1 (0x3FD) +#define SPR_604_HID13 (0x3FD) +#define SPR_LT (0x3FE) +#define SPR_THRM3 (0x3FE) +#define SPR_RCPU_FPECR (0x3FE) +#define SPR_403_PBL2 (0x3FE) +#define SPR_PIR (0x3FF) +#define SPR_403_PBU2 (0x3FF) +#define SPR_601_HID15 (0x3FF) +#define SPR_604_HID15 (0x3FF) +#define SPR_E500_SVR (0x3FF) /*****************************************************************************/ /* Memory access type : diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 343ec130a..0878be2eb 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -28,11 +28,15 @@ //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR -//#define PPC_DEBUG_IRQ +//#define PPC_DUMP_SPR_ACCESSES +#if defined(CONFIG_USER_ONLY) +#define TODO_USER_ONLY 1 +#endif struct ppc_def_t { const unsigned char *name; uint32_t pvr; + uint32_t svr; uint64_t insns_flags; uint64_t msr_mask; powerpc_mmu_t mmu_model; @@ -983,13 +987,6 @@ static void gen_spr_G2 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* System version register */ - /* SVR */ - /* XXX : TODO: initialize it to an appropriate value */ - spr_register(env, SPR_SVR, "SVR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - 0x00000000); /* Exception processing */ spr_register(env, SPR_BOOKE_CSRR0, "CSRR0", SPR_NOACCESS, SPR_NOACCESS, @@ -1277,14 +1274,68 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) #endif } -/* PowerPC BookE SPR */ -static void gen_spr_BookE (CPUPPCState *env) +static void gen_spr_usprgh (CPUPPCState *env) { - /* Processor identification */ - spr_register(env, SPR_BOOKE_PIR, "PIR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_pir, + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, 0x00000000); +} + +/* PowerPC BookE SPR */ +static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask) +{ + const unsigned char *ivor_names[64] = { + "IVOR0", "IVOR1", "IVOR2", "IVOR3", + "IVOR4", "IVOR5", "IVOR6", "IVOR7", + "IVOR8", "IVOR9", "IVOR10", "IVOR11", + "IVOR12", "IVOR13", "IVOR14", "IVOR15", + "IVOR16", "IVOR17", "IVOR18", "IVOR19", + "IVOR20", "IVOR21", "IVOR22", "IVOR23", + "IVOR24", "IVOR25", "IVOR26", "IVOR27", + "IVOR28", "IVOR29", "IVOR30", "IVOR31", + "IVOR32", "IVOR33", "IVOR34", "IVOR35", + "IVOR36", "IVOR37", "IVOR38", "IVOR39", + "IVOR40", "IVOR41", "IVOR42", "IVOR43", + "IVOR44", "IVOR45", "IVOR46", "IVOR47", + "IVOR48", "IVOR49", "IVOR50", "IVOR51", + "IVOR52", "IVOR53", "IVOR54", "IVOR55", + "IVOR56", "IVOR57", "IVOR58", "IVOR59", + "IVOR60", "IVOR61", "IVOR62", "IVOR63", + }; +#define SPR_BOOKE_IVORxx (-1) + int ivor_sprn[64] = { + SPR_BOOKE_IVOR0, SPR_BOOKE_IVOR1, SPR_BOOKE_IVOR2, SPR_BOOKE_IVOR3, + SPR_BOOKE_IVOR4, SPR_BOOKE_IVOR5, SPR_BOOKE_IVOR6, SPR_BOOKE_IVOR7, + SPR_BOOKE_IVOR8, SPR_BOOKE_IVOR9, SPR_BOOKE_IVOR10, SPR_BOOKE_IVOR11, + SPR_BOOKE_IVOR12, SPR_BOOKE_IVOR13, SPR_BOOKE_IVOR14, SPR_BOOKE_IVOR15, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVOR32, SPR_BOOKE_IVOR33, SPR_BOOKE_IVOR34, SPR_BOOKE_IVOR35, + SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, + }; + int i; + /* Interrupt processing */ spr_register(env, SPR_BOOKE_CSRR0, "CSRR0", SPR_NOACCESS, SPR_NOACCESS, @@ -1294,16 +1345,6 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); -#if 0 - spr_register(env, SPR_BOOKE_DSRR0, "DSRR0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_BOOKE_DSRR1, "DSRR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); -#endif /* Debug */ /* XXX : not implemented */ spr_register(env, SPR_BOOKE_IAC1, "IAC1", @@ -1316,16 +1357,6 @@ static void gen_spr_BookE (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_IAC3, "IAC3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_IAC4, "IAC4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_BOOKE_DAC1, "DAC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1336,16 +1367,6 @@ static void gen_spr_BookE (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DVC1, "DVC1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_DVC2, "DVC2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_BOOKE_DBCR0, "DBCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1378,96 +1399,18 @@ static void gen_spr_BookE (CPUPPCState *env) &spr_read_generic, &spr_write_excp_prefix, 0x00000000); /* Exception vectors */ - spr_register(env, SPR_BOOKE_IVOR0, "IVOR0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR1, "IVOR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR2, "IVOR2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR3, "IVOR3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR4, "IVOR4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR5, "IVOR5", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR6, "IVOR6", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR7, "IVOR7", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR8, "IVOR8", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR9, "IVOR9", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR10, "IVOR10", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR11, "IVOR11", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR12, "IVOR12", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR13, "IVOR13", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR14, "IVOR14", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR15, "IVOR15", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); -#if 0 - spr_register(env, SPR_BOOKE_IVOR32, "IVOR32", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR33, "IVOR33", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR34, "IVOR34", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR35, "IVOR35", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR36, "IVOR36", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); - spr_register(env, SPR_BOOKE_IVOR37, "IVOR37", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_excp_vector, - 0x00000000); -#endif + for (i = 0; i < 64; i++) { + if (ivor_mask & (1ULL << i)) { + if (ivor_sprn[i] == SPR_BOOKE_IVORxx) { + fprintf(stderr, "ERROR: IVOR %d SPR is not defined\n", i); + exit(1); + } + spr_register(env, ivor_sprn[i], ivor_names[i], + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_excp_vector, + 0x00000000); + } + } spr_register(env, SPR_BOOKE_PID, "PID", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1498,76 +1441,43 @@ static void gen_spr_BookE (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_USPRG4, "USPRG4", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); spr_register(env, SPR_SPRG5, "SPRG5", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_USPRG5, "USPRG5", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); spr_register(env, SPR_SPRG6, "SPRG6", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_USPRG6, "USPRG6", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); spr_register(env, SPR_SPRG7, "SPRG7", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_USPRG7, "USPRG7", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); } /* FSL storage control registers */ -static void gen_spr_BookE_FSL (CPUPPCState *env) +static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask) { #if !defined(CONFIG_USER_ONLY) + const unsigned char *mas_names[8] = { + "MAS0", "MAS1", "MAS2", "MAS3", "MAS4", "MAS5", "MAS6", "MAS7", + }; + int mas_sprn[8] = { + SPR_BOOKE_MAS0, SPR_BOOKE_MAS1, SPR_BOOKE_MAS2, SPR_BOOKE_MAS3, + SPR_BOOKE_MAS4, SPR_BOOKE_MAS5, SPR_BOOKE_MAS6, SPR_BOOKE_MAS7, + }; + int i; + /* TLB assist registers */ /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MAS0, "MAS0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MAS1, "MAS2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MAS2, "MAS3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MAS3, "MAS4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MAS4, "MAS5", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MAS6, "MAS6", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MAS7, "MAS7", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + for (i = 0; i < 8; i++) { + if (mas_mask & (1 << i)) { + spr_register(env, mas_sprn[i], mas_names[i], + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + } + } if (env->nb_pids > 1) { /* XXX : not implemented */ spr_register(env, SPR_BOOKE_PID1, "PID1", @@ -1915,34 +1825,19 @@ static void gen_spr_405 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_USPRG4, "USPRG4", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); spr_register(env, SPR_SPRG5, "SPRG5", SPR_NOACCESS, SPR_NOACCESS, spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_USPRG5, "USPRG5", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); spr_register(env, SPR_SPRG6, "SPRG6", SPR_NOACCESS, SPR_NOACCESS, spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_USPRG6, "USPRG6", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); spr_register(env, SPR_SPRG7, "SPRG7", SPR_NOACCESS, SPR_NOACCESS, spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_USPRG7, "USPRG7", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); + gen_spr_usprgh(env); } /* SPR shared between PowerPC 401 & 403 implementations */ @@ -2206,91 +2101,562 @@ static void gen_spr_620 (CPUPPCState *env) } #endif /* defined (TARGET_PPC64) */ -// XXX: TODO -/* - * AMR => SPR 29 (Power 2.04) - * CTRL => SPR 136 (Power 2.04) - * CTRL => SPR 152 (Power 2.04) - * SCOMC => SPR 276 (64 bits ?) - * SCOMD => SPR 277 (64 bits ?) - * TBU40 => SPR 286 (Power 2.04 hypv) - * HSPRG0 => SPR 304 (Power 2.04 hypv) - * HSPRG1 => SPR 305 (Power 2.04 hypv) - * HDSISR => SPR 306 (Power 2.04 hypv) - * HDAR => SPR 307 (Power 2.04 hypv) - * PURR => SPR 309 (Power 2.04 hypv) - * HDEC => SPR 310 (Power 2.04 hypv) - * HIOR => SPR 311 (hypv) - * RMOR => SPR 312 (970) - * HRMOR => SPR 313 (Power 2.04 hypv) - * HSRR0 => SPR 314 (Power 2.04 hypv) - * HSRR1 => SPR 315 (Power 2.04 hypv) - * LPCR => SPR 316 (970) - * LPIDR => SPR 317 (970) - * SPEFSCR => SPR 512 (Power 2.04 emb) - * EPR => SPR 702 (Power 2.04 emb) - * perf => 768-783 (Power 2.04) - * perf => 784-799 (Power 2.04) - * PPR => SPR 896 (Power 2.04) - * EPLC => SPR 947 (Power 2.04 emb) - * EPSC => SPR 948 (Power 2.04 emb) - * DABRX => 1015 (Power 2.04 hypv) - * FPECR => SPR 1022 (?) - * ... and more (thermal management, performance counters, ...) - */ - -/*****************************************************************************/ -/* Exception vectors models */ -static void init_excp_4xx_real (CPUPPCState *env) -{ -#if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_PIT] = 0x00001000; - env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; - env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; - env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; - env->excp_prefix = 0x00000000UL; - env->ivor_mask = 0x0000FFF0UL; - env->ivpr_mask = 0xFFFF0000UL; - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif -} - -static void init_excp_4xx_softmmu (CPUPPCState *env) -{ -#if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_PIT] = 0x00001000; - env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; - env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; - env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100; - env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200; - env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; - env->excp_prefix = 0x00000000UL; - env->ivor_mask = 0x0000FFF0UL; - env->ivpr_mask = 0xFFFF0000UL; - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif -} - -static void init_excp_BookE (CPUPPCState *env) +static void gen_spr_5xx_8xx (CPUPPCState *env) { -#if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000; + /* Exception processing */ + spr_register(env, SPR_DSISR, "DSISR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_DAR, "DAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Timer */ + spr_register(env, SPR_DECR, "DECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_decr, &spr_write_decr, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_EIE, "EIE", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_EID, "EID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_NRI, "NRI", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPA, "CMPA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPB, "CMPB", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPC, "CMPC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPD, "CMPD", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_ECR, "ECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_DER, "DER", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_COUNTA, "COUNTA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_COUNTB, "COUNTB", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPE, "CMPE", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPF, "CMPF", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPG, "CMPG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_CMPH, "CMPH", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_LCTRL1, "LCTRL1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_LCTRL2, "LCTRL2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_BAR, "BAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_DPDR, "DPDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_IMMR, "IMMR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +static void gen_spr_5xx (CPUPPCState *env) +{ + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_GRA, "MI_GRA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_GRA, "L2U_GRA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RPCU_BBCMCR, "L2U_BBCMCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_MCR, "L2U_MCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RBA0, "MI_RBA0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RBA1, "MI_RBA1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RBA2, "MI_RBA2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RBA3, "MI_RBA3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RBA0, "L2U_RBA0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RBA1, "L2U_RBA1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RBA2, "L2U_RBA2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RBA3, "L2U_RBA3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RA0, "MI_RA0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RA1, "MI_RA1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RA2, "MI_RA2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_MI_RA3, "MI_RA3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RA0, "L2U_RA0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RA1, "L2U_RA1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RA2, "L2U_RA2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_L2U_RA3, "L2U_RA3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_RCPU_FPECR, "FPECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +static void gen_spr_8xx (CPUPPCState *env) +{ + /* XXX : not implemented */ + spr_register(env, SPR_MPC_IC_CST, "IC_CST", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_IC_ADR, "IC_ADR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_IC_DAT, "IC_DAT", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_DC_CST, "DC_CST", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_DC_ADR, "DC_ADR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_DC_DAT, "DC_DAT", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_CTR, "MI_CTR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_AP, "MI_AP", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_EPN, "MI_EPN", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_TWC, "MI_TWC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_RPN, "MI_RPN", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_DBCAM, "MI_DBCAM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_DBRAM0, "MI_DBRAM0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MI_DBRAM1, "MI_DBRAM1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_CTR, "MD_CTR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_CASID, "MD_CASID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_AP, "MD_AP", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_EPN, "MD_EPN", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_TWB, "MD_TWB", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_TWC, "MD_TWC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_RPN, "MD_RPN", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_TW, "MD_TW", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_DBCAM, "MD_DBCAM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_DBRAM0, "MD_DBRAM0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MPC_MD_DBRAM1, "MD_DBRAM1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +// XXX: TODO +/* + * AMR => SPR 29 (Power 2.04) + * CTRL => SPR 136 (Power 2.04) + * CTRL => SPR 152 (Power 2.04) + * SCOMC => SPR 276 (64 bits ?) + * SCOMD => SPR 277 (64 bits ?) + * TBU40 => SPR 286 (Power 2.04 hypv) + * HSPRG0 => SPR 304 (Power 2.04 hypv) + * HSPRG1 => SPR 305 (Power 2.04 hypv) + * HDSISR => SPR 306 (Power 2.04 hypv) + * HDAR => SPR 307 (Power 2.04 hypv) + * PURR => SPR 309 (Power 2.04 hypv) + * HDEC => SPR 310 (Power 2.04 hypv) + * HIOR => SPR 311 (hypv) + * RMOR => SPR 312 (970) + * HRMOR => SPR 313 (Power 2.04 hypv) + * HSRR0 => SPR 314 (Power 2.04 hypv) + * HSRR1 => SPR 315 (Power 2.04 hypv) + * LPCR => SPR 316 (970) + * LPIDR => SPR 317 (970) + * SPEFSCR => SPR 512 (Power 2.04 emb) + * EPR => SPR 702 (Power 2.04 emb) + * perf => 768-783 (Power 2.04) + * perf => 784-799 (Power 2.04) + * PPR => SPR 896 (Power 2.04) + * EPLC => SPR 947 (Power 2.04 emb) + * EPSC => SPR 948 (Power 2.04 emb) + * DABRX => 1015 (Power 2.04 hypv) + * FPECR => SPR 1022 (?) + * ... and more (thermal management, performance counters, ...) + */ + +/*****************************************************************************/ +/* Exception vectors models */ +static void init_excp_4xx_real (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_PIT] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; + env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; + env->excp_prefix = 0x00000000UL; + env->ivor_mask = 0x0000FFF0UL; + env->ivpr_mask = 0xFFFF0000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_4xx_softmmu (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_PIT] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; + env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; + env->excp_prefix = 0x00000000UL; + env->ivor_mask = 0x0000FFF0UL; + env->ivpr_mask = 0xFFFF0000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_MPC5xx (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_FPA] = 0x00000E00; + env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_DABR] = 0x00001C00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00; + env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00; + env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00; + env->excp_prefix = 0x00000000UL; + env->ivor_mask = 0x0000FFF0UL; + env->ivpr_mask = 0xFFFF0000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_MPC8xx (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_FPA] = 0x00000E00; + env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_ITLBE] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_DTLBE] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_DABR] = 0x00001C00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00; + env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00; + env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00; + env->excp_prefix = 0x00000000UL; + env->ivor_mask = 0x0000FFF0UL; + env->ivpr_mask = 0xFFFF0000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_G2 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000A00; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0x00000000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_e200 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000FFC; + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_APU] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_SPEU] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_EFPDI] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_EFPRI] = 0x00000000; + env->excp_prefix = 0x00000000UL; + env->ivor_mask = 0x0000FFF7UL; + env->ivpr_mask = 0xFFFF0000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_BookE (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000; env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000; env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000000; env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000000; @@ -2388,7 +2754,158 @@ static void init_excp_603 (CPUPPCState *env) #endif } -static void init_excp_G2 (CPUPPCState *env) +static void init_excp_604 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0x00000000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +#if defined(TARGET_PPC64) +static void init_excp_620 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_FPA] = 0x00000E00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0xFFF00000UL; + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; +#endif +} +#endif /* defined(TARGET_PPC64) */ + +static void init_excp_7x0 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + env->excp_prefix = 0x00000000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_750FX (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + env->excp_prefix = 0x00000000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +/* XXX: Check if this is correct */ +static void init_excp_7x5 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; + env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; + env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0x00000000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_7400 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; + env->excp_prefix = 0x00000000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_7450 (CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; @@ -2400,839 +2917,1188 @@ static void init_excp_G2 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000A00; env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif } -static void init_excp_604 (CPUPPCState *env) +#if defined (TARGET_PPC64) +static void init_excp_970 (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_HDECR] = 0x00000980; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; + env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; + env->excp_prefix = 0x00000000FFF00000ULL; + /* Hardware reset vector */ + env->hreset_vector = 0x0000000000000100ULL; +#endif +} +#endif + +/*****************************************************************************/ +/* Power management enable checks */ +static int check_pow_none (CPUPPCState *env) +{ + return 0; +} + +static int check_pow_nocheck (CPUPPCState *env) +{ + return 1; +} + +static int check_pow_hid0 (CPUPPCState *env) +{ + if (env->spr[SPR_HID0] & 0x00E00000) + return 1; + + return 0; +} + +/*****************************************************************************/ +/* PowerPC implementations definitions */ + +/* PowerPC 40x instruction set */ +#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_WRTEE | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ) + +/* PowerPC 401 */ +#define POWERPC_INSNS_401 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_401 (0x00000000000FD201ULL) +#define POWERPC_MMU_401 (POWERPC_MMU_REAL) +#define POWERPC_EXCP_401 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_401 (bfd_mach_ppc_403) +#define POWERPC_FLAG_401 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define check_pow_401 check_pow_nocheck + +static void init_proc_401 (CPUPPCState *env) +{ + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_401(env); + init_excp_4xx_real(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); +} + +/* PowerPC 401x2 */ +#define POWERPC_INSNS_401x2 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_CACHE_DCBA | PPC_MFTB | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_401x2 (0x00000000001FD231ULL) +#define POWERPC_MMU_401x2 (POWERPC_MMU_SOFT_4xx_Z) +#define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) +#define POWERPC_FLAG_401x2 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define check_pow_401x2 check_pow_nocheck + +static void init_proc_401x2 (CPUPPCState *env) { + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_401x2(env); + gen_spr_compress(env); + /* Memory management */ #if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; - env->excp_prefix = 0x00000000UL; - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; #endif + init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } -#if defined(TARGET_PPC64) -static void init_excp_620 (CPUPPCState *env) +/* PowerPC 401x3 */ +#define POWERPC_INSNS_401x3 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_CACHE_DCBA | PPC_MFTB | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_401x3 (0x00000000001FD631ULL) +#define POWERPC_MMU_401x3 (POWERPC_MMU_SOFT_4xx_Z) +#define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) +#define POWERPC_FLAG_401x3 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define check_pow_401x3 check_pow_nocheck + +__attribute__ (( unused )) +static void init_proc_401x3 (CPUPPCState *env) +{ + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_401(env); + gen_spr_401x2(env); + gen_spr_compress(env); + init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); +} + +/* IOP480 */ +#define POWERPC_INSNS_IOP480 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_CACHE_DCBA | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_IOP480 (0x00000000001FD231ULL) +#define POWERPC_MMU_IOP480 (POWERPC_MMU_SOFT_4xx_Z) +#define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) +#define POWERPC_FLAG_IOP480 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define check_pow_IOP480 check_pow_nocheck + +static void init_proc_IOP480 (CPUPPCState *env) { + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_401x2(env); + gen_spr_compress(env); + /* Memory management */ #if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_FPA] = 0x00000E00; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; - env->excp_prefix = 0xFFF00000UL; - /* Hardware reset vector */ - env->hreset_vector = 0x0000000000000100ULL; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; #endif + init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } -#endif /* defined(TARGET_PPC64) */ -static void init_excp_7x0 (CPUPPCState *env) +/* PowerPC 403 */ +#define POWERPC_INSNS_403 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_403 (0x000000000007D00DULL) +#define POWERPC_MMU_403 (POWERPC_MMU_REAL) +#define POWERPC_EXCP_403 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_403 (bfd_mach_ppc_403) +#define POWERPC_FLAG_403 (POWERPC_FLAG_CE | POWERPC_FLAG_PX) +#define check_pow_403 check_pow_nocheck + +static void init_proc_403 (CPUPPCState *env) { + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_403(env); + gen_spr_403_real(env); + init_excp_4xx_real(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); #if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; - env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; #endif } -static void init_excp_750FX (CPUPPCState *env) +/* PowerPC 403 GCX */ +#define POWERPC_INSNS_403GCX (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) +#define POWERPC_MSRM_403GCX (0x000000000007D00DULL) +#define POWERPC_MMU_403GCX (POWERPC_MMU_SOFT_4xx_Z) +#define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) +#define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) +#define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) +#define POWERPC_FLAG_403GCX (POWERPC_FLAG_CE | POWERPC_FLAG_PX) +#define check_pow_403GCX check_pow_nocheck + +static void init_proc_403GCX (CPUPPCState *env) { + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_403(env); + gen_spr_403_real(env); + gen_spr_403_mmu(env); + /* Bus access control */ + /* not emulated, as Qemu never does speculative access */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* not emulated, as Qemu do not emulate caches */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ #if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; - env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; - env->excp_prefix = 0x00000000UL; - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; #endif + init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } -/* XXX: Check if this is correct */ -static void init_excp_7x5 (CPUPPCState *env) +/* PowerPC 405 */ +#define POWERPC_INSNS_405 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_MFTB | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_CACHE_DCBA | \ + PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ + PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT | \ + PPC_405_MAC) +#define POWERPC_MSRM_405 (0x000000000006E630ULL) +#define POWERPC_MMU_405 (POWERPC_MMU_SOFT_4xx) +#define POWERPC_EXCP_405 (POWERPC_EXCP_40x) +#define POWERPC_INPUT_405 (PPC_FLAGS_INPUT_405) +#define POWERPC_BFDM_405 (bfd_mach_ppc_403) +#define POWERPC_FLAG_405 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) +#define check_pow_405 check_pow_nocheck + +static void init_proc_405 (CPUPPCState *env) { -#if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; - env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; - env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; - env->excp_prefix = 0x00000000UL; - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; + /* Time base */ + gen_tbl(env); + gen_spr_40x(env); + gen_spr_405(env); + /* Bus access control */ + /* not emulated, as Qemu never does speculative access */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + /* not emulated, as Qemu do not emulate caches */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ +#if !defined(CONFIG_USER_ONLY) + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; #endif + init_excp_4xx_softmmu(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env); } -static void init_excp_7400 (CPUPPCState *env) +/* PowerPC 440 EP */ +#define POWERPC_INSNS_440EP (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC | PPC_RFMCI) +#define POWERPC_MSRM_440EP (0x000000000006D630ULL) +#define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_440EP (bfd_mach_ppc_403) +#define POWERPC_FLAG_440EP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) +#define check_pow_440EP check_pow_nocheck + +__attribute__ (( unused )) +static void init_proc_440EP (CPUPPCState *env) { + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env, 0x000000000000FFFFULL); + gen_spr_440(env); + gen_spr_usprgh(env); + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_MCSR, "MCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_CCR1, "CCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ #if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; - env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; - env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; - env->excp_prefix = 0x00000000UL; - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; #endif + init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* XXX: TODO: allocate internal IRQ controller */ } -static void init_excp_7450 (CPUPPCState *env) +/* PowerPC 440 GP */ +#define POWERPC_INSNS_440GP (POWERPC_INSNS_EMB | PPC_STRING | \ + PPC_DCR | PPC_DCRX | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ + PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) +#define POWERPC_MSRM_440GP (0x000000000006FF30ULL) +#define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_440GP (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_440GP (bfd_mach_ppc_403) +#define POWERPC_FLAG_440GP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) +#define check_pow_440GP check_pow_nocheck + +__attribute__ (( unused )) +static void init_proc_440GP (CPUPPCState *env) { + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env, 0x000000000000FFFFULL); + gen_spr_440(env); + gen_spr_usprgh(env); + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ #if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; - env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; - env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; - env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; - env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; - env->excp_prefix = 0x00000000UL; - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; #endif + init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* XXX: TODO: allocate internal IRQ controller */ } -#if defined (TARGET_PPC64) -static void init_excp_970 (CPUPPCState *env) +/* PowerPC 440x4 */ +#define POWERPC_INSNS_440x4 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC) +#define POWERPC_MSRM_440x4 (0x000000000006FF30ULL) +#define POWERPC_MMU_440x4 (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) +#define POWERPC_FLAG_440x4 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) +#define check_pow_440x4 check_pow_nocheck + +__attribute__ (( unused )) +static void init_proc_440x4 (CPUPPCState *env) { + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env, 0x000000000000FFFFULL); + gen_spr_440(env); + gen_spr_usprgh(env); + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ #if !defined(CONFIG_USER_ONLY) - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_HDECR] = 0x00000980; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; - env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; - env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; - env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; - env->excp_prefix = 0x00000000FFF00000ULL; - /* Hardware reset vector */ - env->hreset_vector = 0x0000000000000100ULL; -#endif -} + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; #endif - -/*****************************************************************************/ -/* Power management enable checks */ -static int check_pow_none (CPUPPCState *env) -{ - return 0; + init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* XXX: TODO: allocate internal IRQ controller */ } -static int check_pow_nocheck (CPUPPCState *env) -{ - return 1; -} +/* PowerPC 440x5 */ +#define POWERPC_INSNS_440x5 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC | PPC_RFMCI) +#define POWERPC_MSRM_440x5 (0x000000000006FF30ULL) +#define POWERPC_MMU_440x5 (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_440x5 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) +#define POWERPC_FLAG_440x5 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) +#define check_pow_440x5 check_pow_nocheck -static int check_pow_hid0 (CPUPPCState *env) +__attribute__ (( unused )) +static void init_proc_440x5 (CPUPPCState *env) { - if (env->spr[SPR_HID0] & 0x00E00000) - return 1; - - return 0; + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env, 0x000000000000FFFFULL); + gen_spr_440(env); + gen_spr_usprgh(env); + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_MCSR, "MCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_CCR1, "CCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ +#if !defined(CONFIG_USER_ONLY) + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; +#endif + init_excp_BookE(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* XXX: TODO: allocate internal IRQ controller */ } -/*****************************************************************************/ -/* PowerPC implementations definitions */ - -/* PowerPC 40x instruction set */ -#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ) - -/* PowerPC 401 */ -#define POWERPC_INSNS_401 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) -#define POWERPC_MSRM_401 (0x00000000000FD201ULL) -#define POWERPC_MMU_401 (POWERPC_MMU_REAL) -#define POWERPC_EXCP_401 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_401 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) -#define check_pow_401 check_pow_nocheck +/* PowerPC 460 (guessed) */ +#define POWERPC_INSNS_460 (POWERPC_INSNS_EMB | PPC_STRING | \ + PPC_DCR | PPC_DCRX | PPC_DCRUX | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ + PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) +#define POWERPC_MSRM_460 (0x000000000006FF30ULL) +#define POWERPC_MMU_460 (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_460 (bfd_mach_ppc_403) +#define POWERPC_FLAG_460 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) +#define check_pow_460 check_pow_nocheck -static void init_proc_401 (CPUPPCState *env) +__attribute__ (( unused )) +static void init_proc_460 (CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401(env); - init_excp_4xx_real(env); + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env, 0x000000000000FFFFULL); + gen_spr_440(env); + gen_spr_usprgh(env); + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_MCSR, "MCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_CCR1, "CCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_DCRIPR, "SPR_DCRIPR", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ +#if !defined(CONFIG_USER_ONLY) + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; +#endif + init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc40x_irq_init(env); + /* XXX: TODO: allocate internal IRQ controller */ } -/* PowerPC 401x2 */ -#define POWERPC_INSNS_401x2 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_CACHE_DCBA | PPC_MFTB | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) -#define POWERPC_MSRM_401x2 (0x00000000001FD231ULL) -#define POWERPC_MMU_401x2 (POWERPC_MMU_SOFT_4xx_Z) -#define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401x2 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) -#define check_pow_401x2 check_pow_nocheck +/* PowerPC 460F (guessed) */ +#define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | PPC_STRING | \ + PPC_DCR | PPC_DCRX | PPC_DCRUX | \ + PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ + PPC_FLOAT | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ + PPC_FLOAT_STFIWX | \ + PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ + PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) +#define POWERPC_MSRM_460 (0x000000000006FF30ULL) +#define POWERPC_MMU_460F (POWERPC_MMU_BOOKE) +#define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_460F (bfd_mach_ppc_403) +#define POWERPC_FLAG_460F (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ + POWERPC_FLAG_DE) +#define check_pow_460F check_pow_nocheck -static void init_proc_401x2 (CPUPPCState *env) +__attribute__ (( unused )) +static void init_proc_460F (CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401x2(env); - gen_spr_compress(env); + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env, 0x000000000000FFFFULL); + gen_spr_440(env); + gen_spr_usprgh(env); + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_MCSR, "MCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_CCR1, "CCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_DCRIPR, "SPR_DCRIPR", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Memory management */ #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; #endif - init_excp_4xx_softmmu(env); + init_excp_BookE(env); env->dcache_line_size = 32; env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc40x_irq_init(env); + /* XXX: TODO: allocate internal IRQ controller */ } -/* PowerPC 401x3 */ -#define POWERPC_INSNS_401x3 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_CACHE_DCBA | PPC_MFTB | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) -#define POWERPC_MSRM_401x3 (0x00000000001FD631ULL) -#define POWERPC_MMU_401x3 (POWERPC_MMU_SOFT_4xx_Z) -#define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401x3 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) -#define check_pow_401x3 check_pow_nocheck +/* Freescale 5xx cores (aka RCPU) */ +#define POWERPC_INSNS_MPC5xx (PPC_INSNS_BASE | PPC_STRING | \ + PPC_MEM_EIEIO | PPC_MEM_SYNC | \ + PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | \ + PPC_MFTB) +#define POWERPC_MSRM_MPC5xx (0x000000000001FF43ULL) +#define POWERPC_MMU_MPC5xx (POWERPC_MMU_REAL) +#define POWERPC_EXCP_MPC5xx (POWERPC_EXCP_603) +#define POWERPC_INPUT_MPC5xx (PPC_FLAGS_INPUT_RCPU) +#define POWERPC_BFDM_MPC5xx (bfd_mach_ppc_505) +#define POWERPC_FLAG_MPC5xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE) +#define check_pow_MPC5xx check_pow_none __attribute__ (( unused )) -static void init_proc_401x3 (CPUPPCState *env) +static void init_proc_MPC5xx (CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401(env); - gen_spr_401x2(env); - gen_spr_compress(env); - init_excp_4xx_softmmu(env); + /* Time base */ + gen_tbl(env); + gen_spr_5xx_8xx(env); + gen_spr_5xx(env); + init_excp_MPC5xx(env); env->dcache_line_size = 32; env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc40x_irq_init(env); + /* XXX: TODO: allocate internal IRQ controller */ } -/* IOP480 */ -#define POWERPC_INSNS_IOP480 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_CACHE_DCBA | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) -#define POWERPC_MSRM_IOP480 (0x00000000001FD231ULL) -#define POWERPC_MMU_IOP480 (POWERPC_MMU_SOFT_4xx_Z) -#define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) -#define POWERPC_FLAG_IOP480 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) -#define check_pow_IOP480 check_pow_nocheck +/* Freescale 8xx cores (aka PowerQUICC) */ +#define POWERPC_INSNS_MPC8xx (PPC_INSNS_BASE | PPC_STRING | \ + PPC_MEM_EIEIO | PPC_MEM_SYNC | \ + PPC_CACHE_ICBI | PPC_MFTB) +#define POWERPC_MSRM_MPC8xx (0x000000000001F673ULL) +#define POWERPC_MMU_MPC8xx (POWERPC_MMU_MPC8xx) +#define POWERPC_EXCP_MPC8xx (POWERPC_EXCP_603) +#define POWERPC_INPUT_MPC8xx (PPC_FLAGS_INPUT_RCPU) +#define POWERPC_BFDM_MPC8xx (bfd_mach_ppc_860) +#define POWERPC_FLAG_MPC8xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE) +#define check_pow_MPC8xx check_pow_none -static void init_proc_IOP480 (CPUPPCState *env) +__attribute__ (( unused )) +static void init_proc_MPC8xx (CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_401x2(env); - gen_spr_compress(env); - /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; -#endif - init_excp_4xx_softmmu(env); + /* Time base */ + gen_tbl(env); + gen_spr_5xx_8xx(env); + gen_spr_8xx(env); + init_excp_MPC8xx(env); env->dcache_line_size = 32; env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc40x_irq_init(env); + /* XXX: TODO: allocate internal IRQ controller */ } -/* PowerPC 403 */ -#define POWERPC_INSNS_403 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) -#define POWERPC_MSRM_403 (0x000000000007D00DULL) -#define POWERPC_MMU_403 (POWERPC_MMU_REAL) -#define POWERPC_EXCP_403 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_403 (bfd_mach_ppc_403) -#define POWERPC_FLAG_403 (POWERPC_FLAG_CE | POWERPC_FLAG_PX) -#define check_pow_403 check_pow_nocheck +/* Freescale 82xx cores (aka PowerQUICC-II) */ +/* PowerPC G2 */ +#define POWERPC_INSNS_G2 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_MSRM_G2 (0x000000000006FFF2ULL) +#define POWERPC_MMU_G2 (POWERPC_MMU_SOFT_6xx) +//#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) +#define POWERPC_INPUT_G2 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) +#define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE) +#define check_pow_G2 check_pow_hid0 -static void init_proc_403 (CPUPPCState *env) +static void init_proc_G2 (CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_403(env); - gen_spr_403_real(env); - init_excp_4xx_real(env); + gen_spr_ne_601(env); + gen_spr_G2_755(env); + gen_spr_G2(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation register */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_G2(env); env->dcache_line_size = 32; env->icache_line_size = 32; /* Allocate hardware IRQ controller */ - ppc40x_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif + ppc6xx_irq_init(env); } -/* PowerPC 403 GCX */ -#define POWERPC_INSNS_403GCX (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) -#define POWERPC_MSRM_403GCX (0x000000000007D00DULL) -#define POWERPC_MMU_403GCX (POWERPC_MMU_SOFT_4xx_Z) -#define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) -#define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) -#define POWERPC_FLAG_403GCX (POWERPC_FLAG_CE | POWERPC_FLAG_PX) -#define check_pow_403GCX check_pow_nocheck +/* PowerPC G2LE */ +#define POWERPC_INSNS_G2LE (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_MSRM_G2LE (0x000000000007FFF3ULL) +#define POWERPC_MMU_G2LE (POWERPC_MMU_SOFT_6xx) +#define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) +#define POWERPC_INPUT_G2LE (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) +#define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE) +#define check_pow_G2LE check_pow_hid0 -static void init_proc_403GCX (CPUPPCState *env) +static void init_proc_G2LE (CPUPPCState *env) { - gen_spr_40x(env); - gen_spr_401_403(env); - gen_spr_403(env); - gen_spr_403_real(env); - gen_spr_403_mmu(env); - /* Bus access control */ - /* not emulated, as Qemu never does speculative access */ - spr_register(env, SPR_40x_SGR, "SGR", + gen_spr_ne_601(env); + gen_spr_G2_755(env); + gen_spr_G2(env); + /* Time base */ + gen_tbl(env); + /* Hardware implementation register */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0xFFFFFFFF); - /* not emulated, as Qemu do not emulate caches */ - spr_register(env, SPR_40x_DCWR, "DCWR", + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; -#endif - init_excp_4xx_softmmu(env); + gen_low_BATs(env); + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_G2(env); env->dcache_line_size = 32; env->icache_line_size = 32; /* Allocate hardware IRQ controller */ - ppc40x_irq_init(env); + ppc6xx_irq_init(env); } -/* PowerPC 405 */ -#define POWERPC_INSNS_405 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_MFTB | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_CACHE_DCBA | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT | \ - PPC_405_MAC) -#define POWERPC_MSRM_405 (0x000000000006E630ULL) -#define POWERPC_MMU_405 (POWERPC_MMU_SOFT_4xx) -#define POWERPC_EXCP_405 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_405 (PPC_FLAGS_INPUT_405) -#define POWERPC_BFDM_405 (bfd_mach_ppc_403) -#define POWERPC_FLAG_405 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) -#define check_pow_405 check_pow_nocheck +/* e200 core */ +/* XXX: unimplemented instructions: + * dcblc + * dcbtlst + * dcbtstls + * icblc + * icbtls + * tlbivax + * all SPE multiply-accumulate instructions + */ +#define POWERPC_INSNS_e200 (POWERPC_INSNS_EMB | PPC_ISEL | \ + PPC_SPE | PPC_SPEFPU | \ + PPC_MEM_TLBSYNC | PPC_TLBIVAX | \ + PPC_CACHE_DCBA | PPC_CACHE_LOCK | \ + PPC_BOOKE | PPC_RFDI) +#define POWERPC_MSRM_e200 (0x000000000606FF30ULL) +#define POWERPC_MMU_e200 (POWERPC_MMU_BOOKE_FSL) +#define POWERPC_EXCP_e200 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_e200 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_e200 (bfd_mach_ppc_860) +#define POWERPC_FLAG_e200 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ + POWERPC_FLAG_UBLE | POWERPC_FLAG_DE) +#define check_pow_e200 check_pow_hid0 -static void init_proc_405 (CPUPPCState *env) + +__attribute__ (( unused )) +static void init_proc_e200 (CPUPPCState *env) { /* Time base */ gen_tbl(env); - gen_spr_40x(env); - gen_spr_405(env); - /* Bus access control */ - /* not emulated, as Qemu never does speculative access */ - spr_register(env, SPR_40x_SGR, "SGR", + gen_spr_BookE(env, 0x000000070000FFFFULL); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_SPEFSCR, "SPEFSCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_spr_BookE_FSL(env, 0x0000005D); + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_ALTCTXCR, "ALTCTXCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_BUCSR, "BUCSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_CTXCR, "CTXCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0xFFFFFFFF); - /* not emulated, as Qemu do not emulate caches */ - spr_register(env, SPR_40x_DCWR, "DCWR", + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_DBCNT, "DBCNT", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; -#endif - init_excp_4xx_softmmu(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc40x_irq_init(env); -} - -/* PowerPC 440 EP */ -#define POWERPC_INSNS_440EP (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC | PPC_RFMCI) -#define POWERPC_MSRM_440EP (0x000000000006D630ULL) -#define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_440EP (bfd_mach_ppc_403) -#define POWERPC_FLAG_440EP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) -#define check_pow_440EP check_pow_nocheck - -static void init_proc_440EP (CPUPPCState *env) -{ - /* Time base */ - gen_tbl(env); - gen_spr_BookE(env); - gen_spr_440(env); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MCSR, "MCSR", + spr_register(env, SPR_Exxx_DBCR3, "DBCR3", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_CCR1, "CCR1", + spr_register(env, SPR_Exxx_L1FINV0, "L1FINV0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_DSRR0, "DSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_DSRR1, "DSRR1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; -#endif - init_excp_BookE(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* XXX: TODO: allocate internal IRQ controller */ -} - -/* PowerPC 440 GP */ -#define POWERPC_INSNS_440GP (POWERPC_INSNS_EMB | PPC_STRING | \ - PPC_DCR | PPC_DCRX | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ - PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) -#define POWERPC_MSRM_440GP (0x000000000006FF30ULL) -#define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_440GP (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_440GP (bfd_mach_ppc_403) -#define POWERPC_FLAG_440GP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) -#define check_pow_440GP check_pow_nocheck - -static void init_proc_440GP (CPUPPCState *env) -{ - /* Time base */ - gen_tbl(env); - gen_spr_BookE(env); - gen_spr_440(env); - /* Memory management */ #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; #endif - init_excp_BookE(env); + init_excp_e200(env); env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ } -/* PowerPC 440x4 */ -#define POWERPC_INSNS_440x4 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC) -#define POWERPC_MSRM_440x4 (0x000000000006FF30ULL) -#define POWERPC_MMU_440x4 (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) -#define POWERPC_FLAG_440x4 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) -#define check_pow_440x4 check_pow_nocheck +/* e300 core */ +#define POWERPC_INSNS_e300 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_MSRM_e300 (0x000000000007FFF3ULL) +#define POWERPC_MMU_e300 (POWERPC_MMU_SOFT_6xx) +#define POWERPC_EXCP_e300 (POWERPC_EXCP_603) +#define POWERPC_INPUT_e300 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_e300 (bfd_mach_ppc_603) +#define POWERPC_FLAG_e300 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE) +#define check_pow_e300 check_pow_hid0 __attribute__ (( unused )) -static void init_proc_440x4 (CPUPPCState *env) -{ - /* Time base */ - gen_tbl(env); - gen_spr_BookE(env); - gen_spr_440(env); - /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; -#endif - init_excp_BookE(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* XXX: TODO: allocate internal IRQ controller */ -} - -/* PowerPC 440x5 */ -#define POWERPC_INSNS_440x5 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC | PPC_RFMCI) -#define POWERPC_MSRM_440x5 (0x000000000006FF30ULL) -#define POWERPC_MMU_440x5 (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_440x5 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) -#define POWERPC_FLAG_440x5 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) -#define check_pow_440x5 check_pow_nocheck - -static void init_proc_440x5 (CPUPPCState *env) +static void init_proc_e300 (CPUPPCState *env) { + gen_spr_ne_601(env); + gen_spr_603(env); /* Time base */ gen_tbl(env); - gen_spr_BookE(env); - gen_spr_440(env); + /* hardware implementation registers */ /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MCSR, "MCSR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_CCR1, "CCR1", + spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; -#endif - init_excp_BookE(env); + gen_low_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_603(env); env->dcache_line_size = 32; env->icache_line_size = 32; - /* XXX: TODO: allocate internal IRQ controller */ + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); } -/* PowerPC 460 (guessed) */ -#define POWERPC_INSNS_460 (POWERPC_INSNS_EMB | PPC_STRING | \ - PPC_DCR | PPC_DCRX | PPC_DCRUX | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ - PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) -#define POWERPC_MSRM_460 (0x000000000006FF30ULL) -#define POWERPC_MMU_460 (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_460 (bfd_mach_ppc_403) -#define POWERPC_FLAG_460 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) -#define check_pow_460 check_pow_nocheck +/* e500 core */ +#define POWERPC_INSNS_e500 (POWERPC_INSNS_EMB | PPC_ISEL | \ + PPC_SPE | PPC_SPEFPU | \ + PPC_MEM_TLBSYNC | PPC_TLBIVAX | \ + PPC_CACHE_DCBA | PPC_CACHE_LOCK | \ + PPC_BOOKE | PPC_RFDI) +#define POWERPC_MSRM_e500 (0x000000000606FF30ULL) +#define POWERPC_MMU_e500 (POWERPC_MMU_BOOKE_FSL) +#define POWERPC_EXCP_e500 (POWERPC_EXCP_BOOKE) +#define POWERPC_INPUT_e500 (PPC_FLAGS_INPUT_BookE) +#define POWERPC_BFDM_e500 (bfd_mach_ppc_860) +#define POWERPC_FLAG_e500 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ + POWERPC_FLAG_UBLE | POWERPC_FLAG_DE) +#define check_pow_e500 check_pow_hid0 __attribute__ (( unused )) -static void init_proc_460 (CPUPPCState *env) +static void init_proc_e500 (CPUPPCState *env) { /* Time base */ gen_tbl(env); - gen_spr_BookE(env); - gen_spr_440(env); + gen_spr_BookE(env, 0x0000000F0000FD7FULL); + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_BOOKE_MCSR, "MCSR", + spr_register(env, SPR_BOOKE_SPEFSCR, "SPEFSCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + /* Memory management */ +#if !defined(CONFIG_USER_ONLY) + env->nb_pids = 3; +#endif + gen_spr_BookE_FSL(env, 0x0000005F); + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_CCR1, "CCR1", + spr_register(env, SPR_Exxx_BBEAR, "BBEAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_DCRIPR, "SPR_DCRIPR", - &spr_read_generic, &spr_write_generic, + spr_register(env, SPR_Exxx_BBTAR, "BBTAR", + SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; -#endif - init_excp_BookE(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* XXX: TODO: allocate internal IRQ controller */ -} - -/* PowerPC 460F (guessed) */ -#define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | PPC_STRING | \ - PPC_DCR | PPC_DCRX | PPC_DCRUX | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_FLOAT | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ - PPC_FLOAT_STFIWX | \ - PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ - PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) -#define POWERPC_MSRM_460 (0x000000000006FF30ULL) -#define POWERPC_MMU_460F (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_460F (bfd_mach_ppc_403) -#define POWERPC_FLAG_460F (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) -#define check_pow_460F check_pow_nocheck - -__attribute__ (( unused )) -static void init_proc_460F (CPUPPCState *env) -{ - /* Time base */ - gen_tbl(env); - gen_spr_BookE(env); - gen_spr_440(env); + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_MCAR, "MCAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_BOOKE_MCSR, "MCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_NPIDR, "NPIDR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_BUCSR, "BUCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_440_CCR1, "CCR1", + spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_DCRIPR, "SPR_DCRIPR", + spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0", + SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1", + SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 1; - env->id_tlbs = 0; -#endif - init_excp_BookE(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* XXX: TODO: allocate internal IRQ controller */ -} - -/* Generic BookE PowerPC */ -#define POWERPC_INSNS_BookE (POWERPC_INSNS_EMB | \ - PPC_MEM_EIEIO | PPC_MEM_TLBSYNC | \ - PPC_CACHE_DCBA | \ - PPC_FLOAT | PPC_FLOAT_FSQRT | \ - PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ - PPC_BOOKE) -#define POWERPC_MSRM_BookE (0x000000000006D630ULL) -#define POWERPC_MMU_BookE (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_BookE (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_BookE (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_BookE (bfd_mach_ppc_403) -#define POWERPC_FLAG_BookE (POWERPC_FLAG_NONE) -#define check_pow_BookE check_pow_nocheck - -__attribute__ (( unused )) -static void init_proc_BookE (CPUPPCState *env) -{ - init_excp_BookE(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; -} - -/* e200 core */ - -/* e300 core */ - -/* e500 core */ -#define POWERPC_INSNS_e500 (POWERPC_INSNS_EMB | \ - PPC_MEM_EIEIO | PPC_MEM_TLBSYNC | \ - PPC_CACHE_DCBA | \ - PPC_BOOKE | PPC_E500_VECTOR) -#define POWERPC_MMU_e500 (POWERPC_MMU_SOFT_4xx) -#define POWERPC_EXCP_e500 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_e500 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_e500 (bfd_mach_ppc_403) -#define POWERPC_FLAG_e500 (POWERPC_FLAG_SPE) -#define check_pow_e500 check_pow_hid0 - -__attribute__ (( unused )) -static void init_proc_e500 (CPUPPCState *env) -{ - /* Time base */ - gen_tbl(env); - gen_spr_BookE(env); - /* Memory management */ - gen_spr_BookE_FSL(env); #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; #endif - init_excp_BookE(env); + init_excp_e200(env); env->dcache_line_size = 32; env->icache_line_size = 32; /* XXX: TODO: allocate internal IRQ controller */ } -/* e600 core */ - /* Non-embedded PowerPC */ /* Base instructions set for all 6xx/7xx/74xx/970 PowerPC */ #define POWERPC_INSNS_6xx (PPC_INSNS_BASE | PPC_STRING | PPC_FLOAT | \ @@ -3429,96 +4295,6 @@ static void init_proc_603E (CPUPPCState *env) ppc6xx_irq_init(env); } -/* PowerPC G2 */ -#define POWERPC_INSNS_G2 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) -#define POWERPC_MSRM_G2 (0x000000000006FFF2ULL) -#define POWERPC_MMU_G2 (POWERPC_MMU_SOFT_6xx) -//#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) -#define POWERPC_INPUT_G2 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) -#define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE) -#define check_pow_G2 check_pow_hid0 - -static void init_proc_G2 (CPUPPCState *env) -{ - gen_spr_ne_601(env); - gen_spr_G2_755(env); - gen_spr_G2(env); - /* Time base */ - gen_tbl(env); - /* Hardware implementation register */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); - init_excp_G2(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); -} - -/* PowerPC G2LE */ -#define POWERPC_INSNS_G2LE (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) -#define POWERPC_MSRM_G2LE (0x000000000007FFF3ULL) -#define POWERPC_MMU_G2LE (POWERPC_MMU_SOFT_6xx) -#define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) -#define POWERPC_INPUT_G2LE (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) -#define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE) -#define check_pow_G2LE check_pow_hid0 - -static void init_proc_G2LE (CPUPPCState *env) -{ - gen_spr_ne_601(env); - gen_spr_G2_755(env); - gen_spr_G2(env); - /* Time base */ - gen_tbl(env); - /* Hardware implementation register */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Memory management */ - gen_low_BATs(env); - gen_high_BATs(env); - gen_6xx_7xx_soft_tlb(env, 64, 2); - init_excp_G2(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env); -} - /* PowerPC 604 */ #define POWERPC_INSNS_604 (POWERPC_INSNS_WORKS | PPC_EXTERN) #define POWERPC_MSRM_604 (0x000000000005FF77ULL) @@ -4528,735 +5304,849 @@ static void init_proc_620 (CPUPPCState *env) enum { /* PowerPC 401 family */ /* Generic PowerPC 401 */ -#define CPU_POWERPC_401 CPU_POWERPC_401G2 +#define CPU_POWERPC_401 CPU_POWERPC_401G2 /* PowerPC 401 cores */ - CPU_POWERPC_401A1 = 0x00210000, - CPU_POWERPC_401B2 = 0x00220000, + CPU_POWERPC_401A1 = 0x00210000, + CPU_POWERPC_401B2 = 0x00220000, #if 0 - CPU_POWERPC_401B3 = xxx, + CPU_POWERPC_401B3 = xxx, #endif - CPU_POWERPC_401C2 = 0x00230000, - CPU_POWERPC_401D2 = 0x00240000, - CPU_POWERPC_401E2 = 0x00250000, - CPU_POWERPC_401F2 = 0x00260000, - CPU_POWERPC_401G2 = 0x00270000, + CPU_POWERPC_401C2 = 0x00230000, + CPU_POWERPC_401D2 = 0x00240000, + CPU_POWERPC_401E2 = 0x00250000, + CPU_POWERPC_401F2 = 0x00260000, + CPU_POWERPC_401G2 = 0x00270000, /* PowerPC 401 microcontrolers */ #if 0 - CPU_POWERPC_401GF = xxx, + CPU_POWERPC_401GF = xxx, #endif -#define CPU_POWERPC_IOP480 CPU_POWERPC_401B2 +#define CPU_POWERPC_IOP480 CPU_POWERPC_401B2 /* IBM Processor for Network Resources */ - CPU_POWERPC_COBRA = 0x10100000, /* XXX: 405 ? */ + CPU_POWERPC_COBRA = 0x10100000, /* XXX: 405 ? */ #if 0 - CPU_POWERPC_XIPCHIP = xxx, + CPU_POWERPC_XIPCHIP = xxx, #endif /* PowerPC 403 family */ /* Generic PowerPC 403 */ -#define CPU_POWERPC_403 CPU_POWERPC_403GC +#define CPU_POWERPC_403 CPU_POWERPC_403GC /* PowerPC 403 microcontrollers */ - CPU_POWERPC_403GA = 0x00200011, - CPU_POWERPC_403GB = 0x00200100, - CPU_POWERPC_403GC = 0x00200200, - CPU_POWERPC_403GCX = 0x00201400, + CPU_POWERPC_403GA = 0x00200011, + CPU_POWERPC_403GB = 0x00200100, + CPU_POWERPC_403GC = 0x00200200, + CPU_POWERPC_403GCX = 0x00201400, #if 0 - CPU_POWERPC_403GP = xxx, + CPU_POWERPC_403GP = xxx, #endif /* PowerPC 405 family */ /* Generic PowerPC 405 */ -#define CPU_POWERPC_405 CPU_POWERPC_405D4 +#define CPU_POWERPC_405 CPU_POWERPC_405D4 /* PowerPC 405 cores */ #if 0 - CPU_POWERPC_405A3 = xxx, + CPU_POWERPC_405A3 = xxx, #endif #if 0 - CPU_POWERPC_405A4 = xxx, + CPU_POWERPC_405A4 = xxx, #endif #if 0 - CPU_POWERPC_405B3 = xxx, + CPU_POWERPC_405B3 = xxx, #endif #if 0 - CPU_POWERPC_405B4 = xxx, + CPU_POWERPC_405B4 = xxx, #endif #if 0 - CPU_POWERPC_405C3 = xxx, + CPU_POWERPC_405C3 = xxx, #endif #if 0 - CPU_POWERPC_405C4 = xxx, + CPU_POWERPC_405C4 = xxx, #endif - CPU_POWERPC_405D2 = 0x20010000, + CPU_POWERPC_405D2 = 0x20010000, #if 0 - CPU_POWERPC_405D3 = xxx, + CPU_POWERPC_405D3 = xxx, #endif - CPU_POWERPC_405D4 = 0x41810000, + CPU_POWERPC_405D4 = 0x41810000, #if 0 - CPU_POWERPC_405D5 = xxx, + CPU_POWERPC_405D5 = xxx, #endif #if 0 - CPU_POWERPC_405E4 = xxx, + CPU_POWERPC_405E4 = xxx, #endif #if 0 - CPU_POWERPC_405F4 = xxx, + CPU_POWERPC_405F4 = xxx, #endif #if 0 - CPU_POWERPC_405F5 = xxx, + CPU_POWERPC_405F5 = xxx, #endif #if 0 - CPU_POWERPC_405F6 = xxx, + CPU_POWERPC_405F6 = xxx, #endif /* PowerPC 405 microcontrolers */ /* XXX: missing 0x200108a0 */ -#define CPU_POWERPC_405CR CPU_POWERPC_405CRc - CPU_POWERPC_405CRa = 0x40110041, - CPU_POWERPC_405CRb = 0x401100C5, - CPU_POWERPC_405CRc = 0x40110145, - CPU_POWERPC_405EP = 0x51210950, +#define CPU_POWERPC_405CR CPU_POWERPC_405CRc + CPU_POWERPC_405CRa = 0x40110041, + CPU_POWERPC_405CRb = 0x401100C5, + CPU_POWERPC_405CRc = 0x40110145, + CPU_POWERPC_405EP = 0x51210950, #if 0 - CPU_POWERPC_405EXr = xxx, + CPU_POWERPC_405EXr = xxx, #endif - CPU_POWERPC_405EZ = 0x41511460, /* 0x51210950 ? */ + CPU_POWERPC_405EZ = 0x41511460, /* 0x51210950 ? */ #if 0 - CPU_POWERPC_405FX = xxx, -#endif -#define CPU_POWERPC_405GP CPU_POWERPC_405GPd - CPU_POWERPC_405GPa = 0x40110000, - CPU_POWERPC_405GPb = 0x40110040, - CPU_POWERPC_405GPc = 0x40110082, - CPU_POWERPC_405GPd = 0x401100C4, -#define CPU_POWERPC_405GPe CPU_POWERPC_405CRc - CPU_POWERPC_405GPR = 0x50910951, + CPU_POWERPC_405FX = xxx, +#endif +#define CPU_POWERPC_405GP CPU_POWERPC_405GPd + CPU_POWERPC_405GPa = 0x40110000, + CPU_POWERPC_405GPb = 0x40110040, + CPU_POWERPC_405GPc = 0x40110082, + CPU_POWERPC_405GPd = 0x401100C4, +#define CPU_POWERPC_405GPe CPU_POWERPC_405CRc + CPU_POWERPC_405GPR = 0x50910951, #if 0 - CPU_POWERPC_405H = xxx, + CPU_POWERPC_405H = xxx, #endif #if 0 - CPU_POWERPC_405L = xxx, + CPU_POWERPC_405L = xxx, #endif - CPU_POWERPC_405LP = 0x41F10000, + CPU_POWERPC_405LP = 0x41F10000, #if 0 - CPU_POWERPC_405PM = xxx, + CPU_POWERPC_405PM = xxx, #endif #if 0 - CPU_POWERPC_405PS = xxx, + CPU_POWERPC_405PS = xxx, #endif #if 0 - CPU_POWERPC_405S = xxx, + CPU_POWERPC_405S = xxx, #endif /* IBM network processors */ - CPU_POWERPC_NPE405H = 0x414100C0, - CPU_POWERPC_NPE405H2 = 0x41410140, - CPU_POWERPC_NPE405L = 0x416100C0, - CPU_POWERPC_NPE4GS3 = 0x40B10000, + CPU_POWERPC_NPE405H = 0x414100C0, + CPU_POWERPC_NPE405H2 = 0x41410140, + CPU_POWERPC_NPE405L = 0x416100C0, + CPU_POWERPC_NPE4GS3 = 0x40B10000, #if 0 - CPU_POWERPC_NPCxx1 = xxx, + CPU_POWERPC_NPCxx1 = xxx, #endif #if 0 - CPU_POWERPC_NPR161 = xxx, + CPU_POWERPC_NPR161 = xxx, #endif #if 0 - CPU_POWERPC_LC77700 = xxx, + CPU_POWERPC_LC77700 = xxx, #endif /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */ #if 0 - CPU_POWERPC_STB01000 = xxx, + CPU_POWERPC_STB01000 = xxx, #endif #if 0 - CPU_POWERPC_STB01010 = xxx, + CPU_POWERPC_STB01010 = xxx, #endif #if 0 - CPU_POWERPC_STB0210 = xxx, /* 401B3 */ + CPU_POWERPC_STB0210 = xxx, /* 401B3 */ #endif - CPU_POWERPC_STB03 = 0x40310000, /* 0x40130000 ? */ + CPU_POWERPC_STB03 = 0x40310000, /* 0x40130000 ? */ #if 0 - CPU_POWERPC_STB043 = xxx, + CPU_POWERPC_STB043 = xxx, #endif #if 0 - CPU_POWERPC_STB045 = xxx, + CPU_POWERPC_STB045 = xxx, #endif - CPU_POWERPC_STB04 = 0x41810000, - CPU_POWERPC_STB25 = 0x51510950, + CPU_POWERPC_STB04 = 0x41810000, + CPU_POWERPC_STB25 = 0x51510950, #if 0 - CPU_POWERPC_STB130 = xxx, + CPU_POWERPC_STB130 = xxx, #endif /* Xilinx cores */ - CPU_POWERPC_X2VP4 = 0x20010820, -#define CPU_POWERPC_X2VP7 CPU_POWERPC_X2VP4 - CPU_POWERPC_X2VP20 = 0x20010860, -#define CPU_POWERPC_X2VP50 CPU_POWERPC_X2VP20 + CPU_POWERPC_X2VP4 = 0x20010820, +#define CPU_POWERPC_X2VP7 CPU_POWERPC_X2VP4 + CPU_POWERPC_X2VP20 = 0x20010860, +#define CPU_POWERPC_X2VP50 CPU_POWERPC_X2VP20 #if 0 - CPU_POWERPC_ZL10310 = xxx, + CPU_POWERPC_ZL10310 = xxx, #endif #if 0 - CPU_POWERPC_ZL10311 = xxx, + CPU_POWERPC_ZL10311 = xxx, #endif #if 0 - CPU_POWERPC_ZL10320 = xxx, + CPU_POWERPC_ZL10320 = xxx, #endif #if 0 - CPU_POWERPC_ZL10321 = xxx, + CPU_POWERPC_ZL10321 = xxx, #endif /* PowerPC 440 family */ /* Generic PowerPC 440 */ -#define CPU_POWERPC_440 CPU_POWERPC_440GXf +#define CPU_POWERPC_440 CPU_POWERPC_440GXf /* PowerPC 440 cores */ #if 0 - CPU_POWERPC_440A4 = xxx, + CPU_POWERPC_440A4 = xxx, #endif #if 0 - CPU_POWERPC_440A5 = xxx, + CPU_POWERPC_440A5 = xxx, #endif #if 0 - CPU_POWERPC_440B4 = xxx, + CPU_POWERPC_440B4 = xxx, #endif #if 0 - CPU_POWERPC_440F5 = xxx, + CPU_POWERPC_440F5 = xxx, #endif #if 0 - CPU_POWERPC_440G5 = xxx, + CPU_POWERPC_440G5 = xxx, #endif #if 0 - CPU_POWERPC_440H4 = xxx, + CPU_POWERPC_440H4 = xxx, #endif #if 0 - CPU_POWERPC_440H6 = xxx, + CPU_POWERPC_440H6 = xxx, #endif /* PowerPC 440 microcontrolers */ -#define CPU_POWERPC_440EP CPU_POWERPC_440EPb - CPU_POWERPC_440EPa = 0x42221850, - CPU_POWERPC_440EPb = 0x422218D3, -#define CPU_POWERPC_440GP CPU_POWERPC_440GPc - CPU_POWERPC_440GPb = 0x40120440, - CPU_POWERPC_440GPc = 0x40120481, -#define CPU_POWERPC_440GR CPU_POWERPC_440GRa -#define CPU_POWERPC_440GRa CPU_POWERPC_440EPb - CPU_POWERPC_440GRX = 0x200008D0, -#define CPU_POWERPC_440EPX CPU_POWERPC_440GRX -#define CPU_POWERPC_440GX CPU_POWERPC_440GXf - CPU_POWERPC_440GXa = 0x51B21850, - CPU_POWERPC_440GXb = 0x51B21851, - CPU_POWERPC_440GXc = 0x51B21892, - CPU_POWERPC_440GXf = 0x51B21894, +#define CPU_POWERPC_440EP CPU_POWERPC_440EPb + CPU_POWERPC_440EPa = 0x42221850, + CPU_POWERPC_440EPb = 0x422218D3, +#define CPU_POWERPC_440GP CPU_POWERPC_440GPc + CPU_POWERPC_440GPb = 0x40120440, + CPU_POWERPC_440GPc = 0x40120481, +#define CPU_POWERPC_440GR CPU_POWERPC_440GRa +#define CPU_POWERPC_440GRa CPU_POWERPC_440EPb + CPU_POWERPC_440GRX = 0x200008D0, +#define CPU_POWERPC_440EPX CPU_POWERPC_440GRX +#define CPU_POWERPC_440GX CPU_POWERPC_440GXf + CPU_POWERPC_440GXa = 0x51B21850, + CPU_POWERPC_440GXb = 0x51B21851, + CPU_POWERPC_440GXc = 0x51B21892, + CPU_POWERPC_440GXf = 0x51B21894, #if 0 - CPU_POWERPC_440S = xxx, + CPU_POWERPC_440S = xxx, #endif - CPU_POWERPC_440SP = 0x53221850, - CPU_POWERPC_440SP2 = 0x53221891, - CPU_POWERPC_440SPE = 0x53421890, + CPU_POWERPC_440SP = 0x53221850, + CPU_POWERPC_440SP2 = 0x53221891, + CPU_POWERPC_440SPE = 0x53421890, /* PowerPC 460 family */ #if 0 /* Generic PowerPC 464 */ -#define CPU_POWERPC_464 CPU_POWERPC_464H90 +#define CPU_POWERPC_464 CPU_POWERPC_464H90 #endif /* PowerPC 464 microcontrolers */ #if 0 - CPU_POWERPC_464H90 = xxx, + CPU_POWERPC_464H90 = xxx, #endif #if 0 - CPU_POWERPC_464H90FP = xxx, + CPU_POWERPC_464H90FP = xxx, #endif /* Freescale embedded PowerPC cores */ /* PowerPC MPC 5xx cores (aka RCPU) */ - CPU_POWERPC_5xx = 0x00020020, -#define CPU_POWERPC_509 CPU_POWERPC_5xx -#define CPU_POWERPC_533 CPU_POWERPC_5xx -#define CPU_POWERPC_534 CPU_POWERPC_5xx -#define CPU_POWERPC_555 CPU_POWERPC_5xx -#define CPU_POWERPC_556 CPU_POWERPC_5xx -#define CPU_POWERPC_560 CPU_POWERPC_5xx -#define CPU_POWERPC_561 CPU_POWERPC_5xx -#define CPU_POWERPC_562 CPU_POWERPC_5xx -#define CPU_POWERPC_563 CPU_POWERPC_5xx -#define CPU_POWERPC_564 CPU_POWERPC_5xx -#define CPU_POWERPC_565 CPU_POWERPC_5xx -#define CPU_POWERPC_566 CPU_POWERPC_5xx + CPU_POWERPC_MPC5xx = 0x00020020, +#define CPU_POWERPC_MGT560 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC509 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC533 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC534 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC555 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC556 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC560 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC561 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC562 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC563 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC564 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC565 CPU_POWERPC_MPC5xx +#define CPU_POWERPC_MPC566 CPU_POWERPC_MPC5xx /* PowerPC MPC 8xx cores (aka PowerQUICC) */ - CPU_POWERPC_8xx = 0x00500000, -#define CPU_POWERPC_821 CPU_POWERPC_8xx -#define CPU_POWERPC_823 CPU_POWERPC_8xx -#define CPU_POWERPC_850 CPU_POWERPC_8xx -#define CPU_POWERPC_852T CPU_POWERPC_8xx -#define CPU_POWERPC_855T CPU_POWERPC_8xx -#define CPU_POWERPC_859 CPU_POWERPC_8xx -#define CPU_POWERPC_860 CPU_POWERPC_8xx -#define CPU_POWERPC_862 CPU_POWERPC_8xx -#define CPU_POWERPC_866 CPU_POWERPC_8xx -#define CPU_POWERPC_857 CPU_POWERPC_8xx -#define CPU_POWERPC_870 CPU_POWERPC_8xx -#define CPU_POWERPC_875 CPU_POWERPC_8xx -#define CPU_POWERPC_880 CPU_POWERPC_8xx -#define CPU_POWERPC_885 CPU_POWERPC_8xx + CPU_POWERPC_MPC8xx = 0x00500000, +#define CPU_POWERPC_MGT823 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC821 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC823 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC850 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC852T CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC855T CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC857 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC859 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC860 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC862 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC866 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC870 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC875 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC880 CPU_POWERPC_MPC8xx +#define CPU_POWERPC_MPC885 CPU_POWERPC_MPC8xx /* G2 cores (aka PowerQUICC-II) */ - CPU_POWERPC_G2 = 0x00810011, - CPU_POWERPC_G2H4 = 0x80811010, - CPU_POWERPC_G2gp = 0x80821010, - CPU_POWERPC_G2ls = 0x90810010, - CPU_POWERPC_MPC603 = 0x00810100, -#define CPU_POWERPC_MPC8240 CPU_POWERPC_MPC603 - CPU_POWERPC_G2_HIP3 = 0x00810101, -#define CPU_POWERPC_MPC8250_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8255_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8260_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8264_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8265_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8266_HiP3 CPU_POWERPC_G2_HIP3 - CPU_POWERPC_G2_HIP4 = 0x80811014, -#define CPU_POWERPC_MPC8241 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8245 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8250_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8255_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8260_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8264_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8265_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8266_HiP4 CPU_POWERPC_G2_HIP4 + CPU_POWERPC_G2 = 0x00810011, + CPU_POWERPC_G2H4 = 0x80811010, + CPU_POWERPC_G2gp = 0x80821010, + CPU_POWERPC_G2ls = 0x90810010, + CPU_POWERPC_MPC603 = 0x00810100, + CPU_POWERPC_G2_HIP3 = 0x00810101, + CPU_POWERPC_G2_HIP4 = 0x80811014, /* G2_LE core (aka PowerQUICC-II) */ - CPU_POWERPC_G2LE = 0x80820010, - CPU_POWERPC_G2LEgp = 0x80822010, - CPU_POWERPC_G2LEls = 0xA0822010, - CPU_POWERPC_G2LEgp1 = 0x80822011, + CPU_POWERPC_G2LE = 0x80820010, + CPU_POWERPC_G2LEgp = 0x80822010, + CPU_POWERPC_G2LEls = 0xA0822010, + CPU_POWERPC_G2LEgp1 = 0x80822011, + CPU_POWERPC_G2LEgp3 = 0x80822013, + /* MPC52xx microcontrollers */ /* XXX: MPC 5121 ? */ -#define CPU_POWERPC_MPC5200 CPU_POWERPC_G2LEgp1 - CPU_POWERPC_G2LEgp3 = 0x80822013, -#define CPU_POWERPC_MPC8247 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8248 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8270 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8271 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8272 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8275 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8280 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC52xx CPU_POWERPC_MPC5200 +#define CPU_POWERPC_MPC5200 CPU_POWERPC_MPC5200_v12 +#define CPU_POWERPC_MPC5200_v10 CPU_POWERPC_G2LEgp1 +#define CPU_POWERPC_MPC5200_v11 CPU_POWERPC_G2LEgp1 +#define CPU_POWERPC_MPC5200_v12 CPU_POWERPC_G2LEgp1 +#define CPU_POWERPC_MPC5200B CPU_POWERPC_MPC5200B_v21 +#define CPU_POWERPC_MPC5200B_v20 CPU_POWERPC_G2LEgp1 +#define CPU_POWERPC_MPC5200B_v21 CPU_POWERPC_G2LEgp1 + /* MPC82xx microcontrollers */ +#define CPU_POWERPC_MPC82xx CPU_POWERPC_MPC8280 +#define CPU_POWERPC_MPC8240 CPU_POWERPC_MPC603 +#define CPU_POWERPC_MPC8241 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8245 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8247 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8248 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8250 CPU_POWERPC_MPC8250_HiP4 +#define CPU_POWERPC_MPC8250_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8250_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8255 CPU_POWERPC_MPC8255_HiP4 +#define CPU_POWERPC_MPC8255_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8255_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8260 CPU_POWERPC_MPC8260_HiP4 +#define CPU_POWERPC_MPC8260_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8260_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8264 CPU_POWERPC_MPC8264_HiP4 +#define CPU_POWERPC_MPC8264_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8264_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8265 CPU_POWERPC_MPC8265_HiP4 +#define CPU_POWERPC_MPC8265_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8265_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8266 CPU_POWERPC_MPC8266_HiP4 +#define CPU_POWERPC_MPC8266_HiP3 CPU_POWERPC_G2_HIP3 +#define CPU_POWERPC_MPC8266_HiP4 CPU_POWERPC_G2_HIP4 +#define CPU_POWERPC_MPC8270 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8271 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8272 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8275 CPU_POWERPC_G2LEgp3 +#define CPU_POWERPC_MPC8280 CPU_POWERPC_G2LEgp3 /* e200 family */ -#define CPU_POWERPC_e200 CPU_POWERPC_e200z6 + /* e200 cores */ +#define CPU_POWERPC_e200 CPU_POWERPC_e200z6 #if 0 - CPU_POWERPC_e200z0 = xxx, -#define CPU_POWERPC_MPC5514E_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5514G_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5516E_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5516G_v0 CPU_POWERPC_e200z0 + CPU_POWERPC_e200z0 = xxx, #endif #if 0 - CPU_POWERPC_e200z1 = xxx, -#define CPU_POWERPC_MPC5514E_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5514G_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5515S CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516E_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516G_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516S CPU_POWERPC_e200z1 + CPU_POWERPC_e200z1 = xxx, #endif #if 0 /* ? */ - CPU_POWERPC_e200z3 = 0x81120000, -#define CPU_POWERPC_MPC5533 CPU_POWERPC_e200z3 -#define CPU_POWERPC_MPC5534 CPU_POWERPC_e200z3 -#endif - CPU_POWERPC_e200z5 = 0x81000000, - CPU_POWERPC_e200z6 = 0x81120000, -#define CPU_POWERPC_MPC5553 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5554 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5561 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5565 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5566 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5567 CPU_POWERPC_e200z6 + CPU_POWERPC_e200z3 = 0x81120000, +#endif + CPU_POWERPC_e200z5 = 0x81000000, + CPU_POWERPC_e200z6 = 0x81120000, + /* MPC55xx microcontrollers */ +#define CPU_POWERPC_MPC55xx CPU_POWERPC_MPC5567 +#if 0 +#define CPU_POWERPC_MPC5514E CPU_POWERPC_MPC5514E_v1 +#define CPU_POWERPC_MPC5514E_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5514E_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5514G CPU_POWERPC_MPC5514G_v1 +#define CPU_POWERPC_MPC5514G_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5514G_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5515S CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516E CPU_POWERPC_MPC5516E_v1 +#define CPU_POWERPC_MPC5516E_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5516E_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516G CPU_POWERPC_MPC5516G_v1 +#define CPU_POWERPC_MPC5516G_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5516G_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516S CPU_POWERPC_e200z1 +#endif +#if 0 +#define CPU_POWERPC_MPC5533 CPU_POWERPC_e200z3 +#define CPU_POWERPC_MPC5534 CPU_POWERPC_e200z3 +#endif +#define CPU_POWERPC_MPC5553 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5554 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5561 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5565 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5566 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5567 CPU_POWERPC_e200z6 /* e300 family */ -#define CPU_POWERPC_e300 CPU_POWERPC_e300c3 - CPU_POWERPC_e300c1 = 0x00830000, -#define CPU_POWERPC_MPC8343A CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC8343EA CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC8347A CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC8347EA CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC8349 CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC8349E CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC8358E CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC8360E CPU_POWERPC_e300c1 - CPU_POWERPC_e300c2 = 0x00840000, -#define CPU_POWERPC_MPC8321 CPU_POWERPC_e300c2 -#define CPU_POWERPC_MPC8321E CPU_POWERPC_e300c2 -#define CPU_POWERPC_MPC8323 CPU_POWERPC_e300c2 -#define CPU_POWERPC_MPC8323E CPU_POWERPC_e300c2 - CPU_POWERPC_e300c3 = 0x00850000, -#define CPU_POWERPC_MPC8313 CPU_POWERPC_e300c3 -#define CPU_POWERPC_MPC8313E CPU_POWERPC_e300c3 -#define CPU_POWERPC_MPC8314 CPU_POWERPC_e300c3 -#define CPU_POWERPC_MPC8314E CPU_POWERPC_e300c3 -#define CPU_POWERPC_MPC8315 CPU_POWERPC_e300c3 -#define CPU_POWERPC_MPC8315E CPU_POWERPC_e300c3 - CPU_POWERPC_e300c4 = 0x00860000, -#define CPU_POWERPC_MPC8377 CPU_POWERPC_e300c4 -#define CPU_POWERPC_MPC8377E CPU_POWERPC_e300c4 -#define CPU_POWERPC_MPC8378 CPU_POWERPC_e300c4 -#define CPU_POWERPC_MPC8378E CPU_POWERPC_e300c4 -#define CPU_POWERPC_MPC8379 CPU_POWERPC_e300c4 -#define CPU_POWERPC_MPC8379E CPU_POWERPC_e300c4 + /* e300 cores */ +#define CPU_POWERPC_e300 CPU_POWERPC_e300c3 + CPU_POWERPC_e300c1 = 0x00830010, + CPU_POWERPC_e300c2 = 0x00840010, + CPU_POWERPC_e300c3 = 0x00850010, + CPU_POWERPC_e300c4 = 0x00860010, + /* MPC83xx microcontrollers */ +#define CPU_POWERPC_MPC8313 CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8313E CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8314 CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8314E CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8315 CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8315E CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC8321 CPU_POWERPC_e300c2 +#define CPU_POWERPC_MPC8321E CPU_POWERPC_e300c2 +#define CPU_POWERPC_MPC8323 CPU_POWERPC_e300c2 +#define CPU_POWERPC_MPC8323E CPU_POWERPC_e300c2 +#define CPU_POWERPC_MPC8343A CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8343EA CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8347A CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8347AT CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8347AP CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8347EA CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8347EAT CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8347EAP CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8349 CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8349A CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8349E CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8349EA CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8358E CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8360E CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC8377 CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8377E CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8378 CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8378E CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8379 CPU_POWERPC_e300c4 +#define CPU_POWERPC_MPC8379E CPU_POWERPC_e300c4 /* e500 family */ -#define CPU_POWERPC_e500 CPU_POWERPC_e500_v22 - CPU_POWERPC_e500_v10 = 0x80200010, -#define CPU_POWERPC_MPC8540_v1 CPU_POWERPC_e500_v10 - CPU_POWERPC_e500_v20 = 0x80200020, -#define CPU_POWERPC_MPC8540_v2 CPU_POWERPC_e500_v20 -#define CPU_POWERPC_MPC8541 CPU_POWERPC_e500_v20 -#define CPU_POWERPC_MPC8541E CPU_POWERPC_e500_v20 -#define CPU_POWERPC_MPC8555 CPU_POWERPC_e500_v20 -#define CPU_POWERPC_MPC8555E CPU_POWERPC_e500_v20 -#define CPU_POWERPC_MPC8560 CPU_POWERPC_e500_v20 - CPU_POWERPC_e500v2_v10 = 0x80210010, -#define CPU_POWERPC_MPC8543 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8543E CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8545 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8545E CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8547E CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8548 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8548E CPU_POWERPC_e500v2_v10 - CPU_POWERPC_e500v2_v20 = 0x80210020, - CPU_POWERPC_e500v2_v21 = 0x80210021, -#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8533E_v10 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8544_v10 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8544E_v10 CPU_POWERPC_e500v2_v21 - CPU_POWERPC_e500v2_v22 = 0x80210022, -#define CPU_POWERPC_MPC8533_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8533E_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8544_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8544E_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8567 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8568 CPU_POWERPC_e500v2_v22 - CPU_POWERPC_e500v2_v30 = 0x80210030, -#define CPU_POWERPC_MPC8572 CPU_POWERPC_e500v2_v30 + /* e500 cores */ +#define CPU_POWERPC_e500 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_e500v2 CPU_POWERPC_e500v2_v22 + CPU_POWERPC_e500_v10 = 0x80200010, + CPU_POWERPC_e500_v20 = 0x80200020, + CPU_POWERPC_e500v2_v10 = 0x80210010, + CPU_POWERPC_e500v2_v11 = 0x80210011, + CPU_POWERPC_e500v2_v20 = 0x80210020, + CPU_POWERPC_e500v2_v21 = 0x80210021, + CPU_POWERPC_e500v2_v22 = 0x80210022, + CPU_POWERPC_e500v2_v30 = 0x80210030, + /* MPC85xx microcontrollers */ +#define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11 +#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8533_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8533E CPU_POWERPC_MPC8533E_v11 +#define CPU_POWERPC_MPC8533E_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8533E_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8540 CPU_POWERPC_MPC8540_v21 +#define CPU_POWERPC_MPC8540_v10 CPU_POWERPC_e500_v10 +#define CPU_POWERPC_MPC8540_v20 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8540_v21 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8541 CPU_POWERPC_MPC8541_v11 +#define CPU_POWERPC_MPC8541_v10 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8541_v11 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8541E CPU_POWERPC_MPC8541E_v11 +#define CPU_POWERPC_MPC8541E_v10 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8541E_v11 CPU_POWERPC_e500_v20 +#define CPU_POWERPC_MPC8543 CPU_POWERPC_MPC8543_v21 +#define CPU_POWERPC_MPC8543_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8543_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8543_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8543_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8543E CPU_POWERPC_MPC8543E_v21 +#define CPU_POWERPC_MPC8543E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8543E_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8543E_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8543E_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8544 CPU_POWERPC_MPC8544_v11 +#define CPU_POWERPC_MPC8544_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8544_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8544E_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8544E CPU_POWERPC_MPC8544E_v11 +#define CPU_POWERPC_MPC8544E_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8545 CPU_POWERPC_MPC8545_v21 +#define CPU_POWERPC_MPC8545_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8545_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8545_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8545E CPU_POWERPC_MPC8545E_v21 +#define CPU_POWERPC_MPC8545E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8545E_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8545E_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8547E CPU_POWERPC_MPC8545E_v21 +#define CPU_POWERPC_MPC8547E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8547E_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8547E_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8548 CPU_POWERPC_MPC8548_v21 +#define CPU_POWERPC_MPC8548_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8548_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8548_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8548_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8548E CPU_POWERPC_MPC8548E_v21 +#define CPU_POWERPC_MPC8548E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8548E_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8548E_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8548E_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8555 CPU_POWERPC_MPC8555_v11 +#define CPU_POWERPC_MPC8555_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8555_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8555E CPU_POWERPC_MPC8555E_v11 +#define CPU_POWERPC_MPC8555E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8555E_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8560 CPU_POWERPC_MPC8560_v21 +#define CPU_POWERPC_MPC8560_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8560_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8560_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8567 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8567E CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8568 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8568E CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8572 CPU_POWERPC_e500v2_v30 +#define CPU_POWERPC_MPC8572E CPU_POWERPC_e500v2_v30 /* e600 family */ - CPU_POWERPC_e600 = 0x80040010, -#define CPU_POWERPC_MPC8610 CPU_POWERPC_e600 -#define CPU_POWERPC_MPC8641 CPU_POWERPC_e600 -#define CPU_POWERPC_MPC8641D CPU_POWERPC_e600 + /* e600 cores */ + CPU_POWERPC_e600 = 0x80040010, + /* MPC86xx microcontrollers */ +#define CPU_POWERPC_MPC8610 CPU_POWERPC_e600 +#define CPU_POWERPC_MPC8641 CPU_POWERPC_e600 +#define CPU_POWERPC_MPC8641D CPU_POWERPC_e600 /* PowerPC 6xx cores */ -#define CPU_POWERPC_601 CPU_POWERPC_601_v2 - CPU_POWERPC_601_v0 = 0x00010001, - CPU_POWERPC_601_v1 = 0x00010001, - CPU_POWERPC_601_v2 = 0x00010002, - CPU_POWERPC_602 = 0x00050100, - CPU_POWERPC_603 = 0x00030100, -#define CPU_POWERPC_603E CPU_POWERPC_603E_v41 - CPU_POWERPC_603E_v11 = 0x00060101, - CPU_POWERPC_603E_v12 = 0x00060102, - CPU_POWERPC_603E_v13 = 0x00060103, - CPU_POWERPC_603E_v14 = 0x00060104, - CPU_POWERPC_603E_v22 = 0x00060202, - CPU_POWERPC_603E_v3 = 0x00060300, - CPU_POWERPC_603E_v4 = 0x00060400, - CPU_POWERPC_603E_v41 = 0x00060401, - CPU_POWERPC_603E7t = 0x00071201, - CPU_POWERPC_603E7v = 0x00070100, - CPU_POWERPC_603E7v1 = 0x00070101, - CPU_POWERPC_603E7v2 = 0x00070201, - CPU_POWERPC_603E7 = 0x00070200, - CPU_POWERPC_603P = 0x00070000, -#define CPU_POWERPC_603R CPU_POWERPC_603E7t +#define CPU_POWERPC_601 CPU_POWERPC_601_v2 + CPU_POWERPC_601_v0 = 0x00010001, + CPU_POWERPC_601_v1 = 0x00010001, + CPU_POWERPC_601_v2 = 0x00010002, + CPU_POWERPC_602 = 0x00050100, + CPU_POWERPC_603 = 0x00030100, +#define CPU_POWERPC_603E CPU_POWERPC_603E_v41 + CPU_POWERPC_603E_v11 = 0x00060101, + CPU_POWERPC_603E_v12 = 0x00060102, + CPU_POWERPC_603E_v13 = 0x00060103, + CPU_POWERPC_603E_v14 = 0x00060104, + CPU_POWERPC_603E_v22 = 0x00060202, + CPU_POWERPC_603E_v3 = 0x00060300, + CPU_POWERPC_603E_v4 = 0x00060400, + CPU_POWERPC_603E_v41 = 0x00060401, + CPU_POWERPC_603E7t = 0x00071201, + CPU_POWERPC_603E7v = 0x00070100, + CPU_POWERPC_603E7v1 = 0x00070101, + CPU_POWERPC_603E7v2 = 0x00070201, + CPU_POWERPC_603E7 = 0x00070200, + CPU_POWERPC_603P = 0x00070000, +#define CPU_POWERPC_603R CPU_POWERPC_603E7t /* XXX: missing 0x00040303 (604) */ - CPU_POWERPC_604 = 0x00040103, -#define CPU_POWERPC_604E CPU_POWERPC_604E_v24 + CPU_POWERPC_604 = 0x00040103, +#define CPU_POWERPC_604E CPU_POWERPC_604E_v24 /* XXX: missing 0x00091203 */ /* XXX: missing 0x00092110 */ /* XXX: missing 0x00092120 */ - CPU_POWERPC_604E_v10 = 0x00090100, - CPU_POWERPC_604E_v22 = 0x00090202, - CPU_POWERPC_604E_v24 = 0x00090204, + CPU_POWERPC_604E_v10 = 0x00090100, + CPU_POWERPC_604E_v22 = 0x00090202, + CPU_POWERPC_604E_v24 = 0x00090204, /* XXX: missing 0x000a0100 */ /* XXX: missing 0x00093102 */ - CPU_POWERPC_604R = 0x000a0101, + CPU_POWERPC_604R = 0x000a0101, #if 0 - CPU_POWERPC_604EV = xxx, /* XXX: same as 604R ? */ + CPU_POWERPC_604EV = xxx, /* XXX: same as 604R ? */ #endif /* PowerPC 740/750 cores (aka G3) */ /* XXX: missing 0x00084202 */ -#define CPU_POWERPC_7x0 CPU_POWERPC_7x0_v31 - CPU_POWERPC_7x0_v20 = 0x00080200, - CPU_POWERPC_7x0_v21 = 0x00080201, - CPU_POWERPC_7x0_v22 = 0x00080202, - CPU_POWERPC_7x0_v30 = 0x00080300, - CPU_POWERPC_7x0_v31 = 0x00080301, - CPU_POWERPC_740E = 0x00080100, - CPU_POWERPC_7x0P = 0x10080000, +#define CPU_POWERPC_7x0 CPU_POWERPC_7x0_v31 + CPU_POWERPC_7x0_v20 = 0x00080200, + CPU_POWERPC_7x0_v21 = 0x00080201, + CPU_POWERPC_7x0_v22 = 0x00080202, + CPU_POWERPC_7x0_v30 = 0x00080300, + CPU_POWERPC_7x0_v31 = 0x00080301, + CPU_POWERPC_740E = 0x00080100, + CPU_POWERPC_7x0P = 0x10080000, /* XXX: missing 0x00087010 (CL ?) */ - CPU_POWERPC_750CL = 0x00087200, -#define CPU_POWERPC_750CX CPU_POWERPC_750CX_v22 - CPU_POWERPC_750CX_v21 = 0x00082201, - CPU_POWERPC_750CX_v22 = 0x00082202, -#define CPU_POWERPC_750CXE CPU_POWERPC_750CXE_v31b - CPU_POWERPC_750CXE_v21 = 0x00082211, - CPU_POWERPC_750CXE_v22 = 0x00082212, - CPU_POWERPC_750CXE_v23 = 0x00082213, - CPU_POWERPC_750CXE_v24 = 0x00082214, - CPU_POWERPC_750CXE_v24b = 0x00083214, - CPU_POWERPC_750CXE_v31 = 0x00083211, - CPU_POWERPC_750CXE_v31b = 0x00083311, - CPU_POWERPC_750CXR = 0x00083410, - CPU_POWERPC_750E = 0x00080200, - CPU_POWERPC_750FL = 0x700A0203, -#define CPU_POWERPC_750FX CPU_POWERPC_750FX_v23 - CPU_POWERPC_750FX_v10 = 0x70000100, - CPU_POWERPC_750FX_v20 = 0x70000200, - CPU_POWERPC_750FX_v21 = 0x70000201, - CPU_POWERPC_750FX_v22 = 0x70000202, - CPU_POWERPC_750FX_v23 = 0x70000203, - CPU_POWERPC_750GL = 0x70020102, -#define CPU_POWERPC_750GX CPU_POWERPC_750GX_v12 - CPU_POWERPC_750GX_v10 = 0x70020100, - CPU_POWERPC_750GX_v11 = 0x70020101, - CPU_POWERPC_750GX_v12 = 0x70020102, -#define CPU_POWERPC_750L CPU_POWERPC_750L_v32 /* Aka LoneStar */ - CPU_POWERPC_750L_v22 = 0x00088202, - CPU_POWERPC_750L_v30 = 0x00088300, - CPU_POWERPC_750L_v32 = 0x00088302, + CPU_POWERPC_750CL = 0x00087200, +#define CPU_POWERPC_750CX CPU_POWERPC_750CX_v22 + CPU_POWERPC_750CX_v21 = 0x00082201, + CPU_POWERPC_750CX_v22 = 0x00082202, +#define CPU_POWERPC_750CXE CPU_POWERPC_750CXE_v31b + CPU_POWERPC_750CXE_v21 = 0x00082211, + CPU_POWERPC_750CXE_v22 = 0x00082212, + CPU_POWERPC_750CXE_v23 = 0x00082213, + CPU_POWERPC_750CXE_v24 = 0x00082214, + CPU_POWERPC_750CXE_v24b = 0x00083214, + CPU_POWERPC_750CXE_v31 = 0x00083211, + CPU_POWERPC_750CXE_v31b = 0x00083311, + CPU_POWERPC_750CXR = 0x00083410, + CPU_POWERPC_750E = 0x00080200, + CPU_POWERPC_750FL = 0x700A0203, +#define CPU_POWERPC_750FX CPU_POWERPC_750FX_v23 + CPU_POWERPC_750FX_v10 = 0x70000100, + CPU_POWERPC_750FX_v20 = 0x70000200, + CPU_POWERPC_750FX_v21 = 0x70000201, + CPU_POWERPC_750FX_v22 = 0x70000202, + CPU_POWERPC_750FX_v23 = 0x70000203, + CPU_POWERPC_750GL = 0x70020102, +#define CPU_POWERPC_750GX CPU_POWERPC_750GX_v12 + CPU_POWERPC_750GX_v10 = 0x70020100, + CPU_POWERPC_750GX_v11 = 0x70020101, + CPU_POWERPC_750GX_v12 = 0x70020102, +#define CPU_POWERPC_750L CPU_POWERPC_750L_v32 /* Aka LoneStar */ + CPU_POWERPC_750L_v22 = 0x00088202, + CPU_POWERPC_750L_v30 = 0x00088300, + CPU_POWERPC_750L_v32 = 0x00088302, /* PowerPC 745/755 cores */ -#define CPU_POWERPC_7x5 CPU_POWERPC_7x5_v28 - CPU_POWERPC_7x5_v10 = 0x00083100, - CPU_POWERPC_7x5_v11 = 0x00083101, - CPU_POWERPC_7x5_v20 = 0x00083200, - CPU_POWERPC_7x5_v21 = 0x00083201, - CPU_POWERPC_7x5_v22 = 0x00083202, /* aka D */ - CPU_POWERPC_7x5_v23 = 0x00083203, /* aka E */ - CPU_POWERPC_7x5_v24 = 0x00083204, - CPU_POWERPC_7x5_v25 = 0x00083205, - CPU_POWERPC_7x5_v26 = 0x00083206, - CPU_POWERPC_7x5_v27 = 0x00083207, - CPU_POWERPC_7x5_v28 = 0x00083208, +#define CPU_POWERPC_7x5 CPU_POWERPC_7x5_v28 + CPU_POWERPC_7x5_v10 = 0x00083100, + CPU_POWERPC_7x5_v11 = 0x00083101, + CPU_POWERPC_7x5_v20 = 0x00083200, + CPU_POWERPC_7x5_v21 = 0x00083201, + CPU_POWERPC_7x5_v22 = 0x00083202, /* aka D */ + CPU_POWERPC_7x5_v23 = 0x00083203, /* aka E */ + CPU_POWERPC_7x5_v24 = 0x00083204, + CPU_POWERPC_7x5_v25 = 0x00083205, + CPU_POWERPC_7x5_v26 = 0x00083206, + CPU_POWERPC_7x5_v27 = 0x00083207, + CPU_POWERPC_7x5_v28 = 0x00083208, #if 0 - CPU_POWERPC_7x5P = xxx, + CPU_POWERPC_7x5P = xxx, #endif /* PowerPC 74xx cores (aka G4) */ /* XXX: missing 0x000C1101 */ -#define CPU_POWERPC_7400 CPU_POWERPC_7400_v29 - CPU_POWERPC_7400_v10 = 0x000C0100, - CPU_POWERPC_7400_v11 = 0x000C0101, - CPU_POWERPC_7400_v20 = 0x000C0200, - CPU_POWERPC_7400_v22 = 0x000C0202, - CPU_POWERPC_7400_v26 = 0x000C0206, - CPU_POWERPC_7400_v27 = 0x000C0207, - CPU_POWERPC_7400_v28 = 0x000C0208, - CPU_POWERPC_7400_v29 = 0x000C0209, -#define CPU_POWERPC_7410 CPU_POWERPC_7410_v14 - CPU_POWERPC_7410_v10 = 0x800C1100, - CPU_POWERPC_7410_v11 = 0x800C1101, - CPU_POWERPC_7410_v12 = 0x800C1102, /* aka C */ - CPU_POWERPC_7410_v13 = 0x800C1103, /* aka D */ - CPU_POWERPC_7410_v14 = 0x800C1104, /* aka E */ -#define CPU_POWERPC_7448 CPU_POWERPC_7448_v21 - CPU_POWERPC_7448_v10 = 0x80040100, - CPU_POWERPC_7448_v11 = 0x80040101, - CPU_POWERPC_7448_v20 = 0x80040200, - CPU_POWERPC_7448_v21 = 0x80040201, -#define CPU_POWERPC_7450 CPU_POWERPC_7450_v21 - CPU_POWERPC_7450_v10 = 0x80000100, - CPU_POWERPC_7450_v11 = 0x80000101, - CPU_POWERPC_7450_v12 = 0x80000102, - CPU_POWERPC_7450_v20 = 0x80000200, /* aka D: 2.04 */ - CPU_POWERPC_7450_v21 = 0x80000201, /* aka E */ - CPU_POWERPC_74x1 = 0x80000203, - CPU_POWERPC_74x1G = 0x80000210, /* aka G: 2.3 */ -#define CPU_POWERPC_74x5 CPU_POWERPC_74x5_v32 - CPU_POWERPC_74x5_v10 = 0x80010100, +#define CPU_POWERPC_7400 CPU_POWERPC_7400_v29 + CPU_POWERPC_7400_v10 = 0x000C0100, + CPU_POWERPC_7400_v11 = 0x000C0101, + CPU_POWERPC_7400_v20 = 0x000C0200, + CPU_POWERPC_7400_v22 = 0x000C0202, + CPU_POWERPC_7400_v26 = 0x000C0206, + CPU_POWERPC_7400_v27 = 0x000C0207, + CPU_POWERPC_7400_v28 = 0x000C0208, + CPU_POWERPC_7400_v29 = 0x000C0209, +#define CPU_POWERPC_7410 CPU_POWERPC_7410_v14 + CPU_POWERPC_7410_v10 = 0x800C1100, + CPU_POWERPC_7410_v11 = 0x800C1101, + CPU_POWERPC_7410_v12 = 0x800C1102, /* aka C */ + CPU_POWERPC_7410_v13 = 0x800C1103, /* aka D */ + CPU_POWERPC_7410_v14 = 0x800C1104, /* aka E */ +#define CPU_POWERPC_7448 CPU_POWERPC_7448_v21 + CPU_POWERPC_7448_v10 = 0x80040100, + CPU_POWERPC_7448_v11 = 0x80040101, + CPU_POWERPC_7448_v20 = 0x80040200, + CPU_POWERPC_7448_v21 = 0x80040201, +#define CPU_POWERPC_7450 CPU_POWERPC_7450_v21 + CPU_POWERPC_7450_v10 = 0x80000100, + CPU_POWERPC_7450_v11 = 0x80000101, + CPU_POWERPC_7450_v12 = 0x80000102, + CPU_POWERPC_7450_v20 = 0x80000200, /* aka D: 2.04 */ + CPU_POWERPC_7450_v21 = 0x80000201, /* aka E */ + CPU_POWERPC_74x1 = 0x80000203, + CPU_POWERPC_74x1G = 0x80000210, /* aka G: 2.3 */ +#define CPU_POWERPC_74x5 CPU_POWERPC_74x5_v32 + CPU_POWERPC_74x5_v10 = 0x80010100, /* XXX: missing 0x80010200 */ - CPU_POWERPC_74x5_v21 = 0x80010201, /* aka C: 2.1 */ - CPU_POWERPC_74x5_v32 = 0x80010302, - CPU_POWERPC_74x5_v33 = 0x80010303, /* aka F: 3.3 */ - CPU_POWERPC_74x5_v34 = 0x80010304, /* aka G: 3.4 */ -#define CPU_POWERPC_74x7 CPU_POWERPC_74x7_v12 + CPU_POWERPC_74x5_v21 = 0x80010201, /* aka C: 2.1 */ + CPU_POWERPC_74x5_v32 = 0x80010302, + CPU_POWERPC_74x5_v33 = 0x80010303, /* aka F: 3.3 */ + CPU_POWERPC_74x5_v34 = 0x80010304, /* aka G: 3.4 */ +#define CPU_POWERPC_74x7 CPU_POWERPC_74x7_v12 /* XXX: is 0x8002xxxx 7447 and 0x8003xxxx 7457 ? */ /* XXX: missing 0x80030102 */ /* XXX: missing 0x80020101 */ - CPU_POWERPC_74x7_v10 = 0x80020100, /* aka A: 1.0 */ - CPU_POWERPC_74x7_v11 = 0x80030101, /* aka B: 1.1 */ - CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ + CPU_POWERPC_74x7_v10 = 0x80020100, /* aka A: 1.0 */ + CPU_POWERPC_74x7_v11 = 0x80030101, /* aka B: 1.1 */ + CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ /* 64 bits PowerPC */ #if defined(TARGET_PPC64) - CPU_POWERPC_620 = 0x00140000, - CPU_POWERPC_630 = 0x00400000, - CPU_POWERPC_631 = 0x00410104, - CPU_POWERPC_POWER4 = 0x00350000, - CPU_POWERPC_POWER4P = 0x00380000, + CPU_POWERPC_620 = 0x00140000, + CPU_POWERPC_630 = 0x00400000, + CPU_POWERPC_631 = 0x00410104, + CPU_POWERPC_POWER4 = 0x00350000, + CPU_POWERPC_POWER4P = 0x00380000, /* XXX: missing 0x003A0201 */ - CPU_POWERPC_POWER5 = 0x003A0203, -#define CPU_POWERPC_POWER5GR CPU_POWERPC_POWER5 - CPU_POWERPC_POWER5P = 0x003B0000, -#define CPU_POWERPC_POWER5GS CPU_POWERPC_POWER5P - CPU_POWERPC_POWER6 = 0x003E0000, - CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 running POWER5 mode */ - CPU_POWERPC_POWER6A = 0x0F000002, - CPU_POWERPC_970 = 0x00390202, -#define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 - CPU_POWERPC_970FX_v10 = 0x00391100, - CPU_POWERPC_970FX_v20 = 0x003C0200, - CPU_POWERPC_970FX_v21 = 0x003C0201, - CPU_POWERPC_970FX_v30 = 0x003C0300, - CPU_POWERPC_970FX_v31 = 0x003C0301, - CPU_POWERPC_970GX = 0x00450000, -#define CPU_POWERPC_970MP CPU_POWERPC_970MP_v11 - CPU_POWERPC_970MP_v10 = 0x00440100, - CPU_POWERPC_970MP_v11 = 0x00440101, -#define CPU_POWERPC_CELL CPU_POWERPC_CELL_v32 - CPU_POWERPC_CELL_v10 = 0x00700100, - CPU_POWERPC_CELL_v20 = 0x00700400, - CPU_POWERPC_CELL_v30 = 0x00700500, - CPU_POWERPC_CELL_v31 = 0x00700501, -#define CPU_POWERPC_CELL_v32 CPU_POWERPC_CELL_v31 - CPU_POWERPC_RS64 = 0x00330000, - CPU_POWERPC_RS64II = 0x00340000, - CPU_POWERPC_RS64III = 0x00360000, - CPU_POWERPC_RS64IV = 0x00370000, + CPU_POWERPC_POWER5 = 0x003A0203, +#define CPU_POWERPC_POWER5GR CPU_POWERPC_POWER5 + CPU_POWERPC_POWER5P = 0x003B0000, +#define CPU_POWERPC_POWER5GS CPU_POWERPC_POWER5P + CPU_POWERPC_POWER6 = 0x003E0000, + CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ + CPU_POWERPC_POWER6A = 0x0F000002, + CPU_POWERPC_970 = 0x00390202, +#define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 + CPU_POWERPC_970FX_v10 = 0x00391100, + CPU_POWERPC_970FX_v20 = 0x003C0200, + CPU_POWERPC_970FX_v21 = 0x003C0201, + CPU_POWERPC_970FX_v30 = 0x003C0300, + CPU_POWERPC_970FX_v31 = 0x003C0301, + CPU_POWERPC_970GX = 0x00450000, +#define CPU_POWERPC_970MP CPU_POWERPC_970MP_v11 + CPU_POWERPC_970MP_v10 = 0x00440100, + CPU_POWERPC_970MP_v11 = 0x00440101, +#define CPU_POWERPC_CELL CPU_POWERPC_CELL_v32 + CPU_POWERPC_CELL_v10 = 0x00700100, + CPU_POWERPC_CELL_v20 = 0x00700400, + CPU_POWERPC_CELL_v30 = 0x00700500, + CPU_POWERPC_CELL_v31 = 0x00700501, +#define CPU_POWERPC_CELL_v32 CPU_POWERPC_CELL_v31 + CPU_POWERPC_RS64 = 0x00330000, + CPU_POWERPC_RS64II = 0x00340000, + CPU_POWERPC_RS64III = 0x00360000, + CPU_POWERPC_RS64IV = 0x00370000, #endif /* defined(TARGET_PPC64) */ /* Original POWER */ /* XXX: should be POWER (RIOS), RSC3308, RSC4608, * POWER2 (RIOS2) & RSC2 (P2SC) here */ #if 0 - CPU_POWER = xxx, /* 0x20000 ? 0x30000 for RSC ? */ + CPU_POWER = xxx, /* 0x20000 ? 0x30000 for RSC ? */ #endif #if 0 - CPU_POWER2 = xxx, /* 0x40000 ? */ + CPU_POWER2 = xxx, /* 0x40000 ? */ #endif /* PA Semi core */ - CPU_POWERPC_PA6T = 0x00900000, + CPU_POWERPC_PA6T = 0x00900000, }; /* System version register (used on MPC 8xxx) */ enum { - PPC_SVR_5200_v10 = 0x80110010, - PPC_SVR_5200_v11 = 0x80110011, - PPC_SVR_5200_v12 = 0x80110012, - PPC_SVR_5200B_v20 = 0x80110020, - PPC_SVR_5200B_v21 = 0x80110021, + POWERPC_SVR_NONE = 0x00000000, +#define POWERPC_SVR_52xx POWERPC_SVR_5200 +#define POWERPC_SVR_5200 POWERPC_SVR_5200_v12 + POWERPC_SVR_5200_v10 = 0x80110010, + POWERPC_SVR_5200_v11 = 0x80110011, + POWERPC_SVR_5200_v12 = 0x80110012, +#define POWERPC_SVR_5200B POWERPC_SVR_5200B_v21 + POWERPC_SVR_5200B_v20 = 0x80110020, + POWERPC_SVR_5200B_v21 = 0x80110021, +#define POWERPC_SVR_55xx POWERPC_SVR_5567 #if 0 - PPC_SVR_5533 = xxx, + POWERPC_SVR_5533 = xxx, #endif #if 0 - PPC_SVR_5534 = xxx, + POWERPC_SVR_5534 = xxx, #endif #if 0 - PPC_SVR_5553 = xxx, + POWERPC_SVR_5553 = xxx, #endif #if 0 - PPC_SVR_5554 = xxx, + POWERPC_SVR_5554 = xxx, #endif #if 0 - PPC_SVR_5561 = xxx, + POWERPC_SVR_5561 = xxx, #endif #if 0 - PPC_SVR_5565 = xxx, + POWERPC_SVR_5565 = xxx, #endif #if 0 - PPC_SVR_5566 = xxx, + POWERPC_SVR_5566 = xxx, #endif #if 0 - PPC_SVR_5567 = xxx, + POWERPC_SVR_5567 = xxx, #endif #if 0 - PPC_SVR_8313 = xxx, + POWERPC_SVR_8313 = xxx, #endif #if 0 - PPC_SVR_8313E = xxx, + POWERPC_SVR_8313E = xxx, #endif #if 0 - PPC_SVR_8314 = xxx, + POWERPC_SVR_8314 = xxx, #endif #if 0 - PPC_SVR_8314E = xxx, + POWERPC_SVR_8314E = xxx, #endif #if 0 - PPC_SVR_8315 = xxx, + POWERPC_SVR_8315 = xxx, #endif #if 0 - PPC_SVR_8315E = xxx, + POWERPC_SVR_8315E = xxx, #endif #if 0 - PPC_SVR_8321 = xxx, + POWERPC_SVR_8321 = xxx, #endif #if 0 - PPC_SVR_8321E = xxx, + POWERPC_SVR_8321E = xxx, #endif #if 0 - PPC_SVR_8323 = xxx, + POWERPC_SVR_8323 = xxx, #endif #if 0 - PPC_SVR_8323E = xxx, -#endif - PPC_SVR_8343A = 0x80570030, - PPC_SVR_8343EA = 0x80560030, - PPC_SVR_8347AP = 0x80550030, /* PBGA package */ - PPC_SVR_8347AT = 0x80530030, /* TBGA package */ - PPC_SVR_8347EAP = 0x80540030, /* PBGA package */ - PPC_SVR_8347EAT = 0x80520030, /* TBGA package */ - PPC_SVR_8349 = 0x80510010, - PPC_SVR_8349A = 0x80510030, - PPC_SVR_8349E = 0x80500010, - PPC_SVR_8349EA = 0x80500030, + POWERPC_SVR_8323E = xxx, +#endif + POWERPC_SVR_8343A = 0x80570030, + POWERPC_SVR_8343EA = 0x80560030, +#define POWERPC_SVR_8347A POWERPC_SVR_8347AT + POWERPC_SVR_8347AP = 0x80550030, /* PBGA package */ + POWERPC_SVR_8347AT = 0x80530030, /* TBGA package */ +#define POWERPC_SVR_8347EA POWERPC_SVR_8347EAT + POWERPC_SVR_8347EAP = 0x80540030, /* PBGA package */ + POWERPC_SVR_8347EAT = 0x80520030, /* TBGA package */ + POWERPC_SVR_8349 = 0x80510010, + POWERPC_SVR_8349A = 0x80510030, + POWERPC_SVR_8349E = 0x80500010, + POWERPC_SVR_8349EA = 0x80500030, #if 0 - PPC_SVR_8358E = xxx, + POWERPC_SVR_8358E = xxx, #endif #if 0 - PPC_SVR_8360E = xxx, -#endif - PPC_SVR_8377 = 0x80C70010, - PPC_SVR_8377E = 0x80C60010, - PPC_SVR_8378 = 0x80C50010, - PPC_SVR_8378E = 0x80C40010, - PPC_SVR_8379 = 0x80C30010, - PPC_SVR_8379E = 0x80C00010, - PPC_SVR_8533_v10 = 0x80340010, - PPC_SVR_8533_v11 = 0x80340011, - PPC_SVR_8533E_v10 = 0x803C0010, - PPC_SVR_8533E_v11 = 0x803C0011, - PPC_SVR_8540_v10 = 0x80300010, - PPC_SVR_8540_v20 = 0x80300020, - PPC_SVR_8540_v21 = 0x80300021, - PPC_SVR_8541_v10 = 0x80720010, - PPC_SVR_8541_v11 = 0x80720011, - PPC_SVR_8541E_v10 = 0x807A0010, - PPC_SVR_8541E_v11 = 0x807A0011, - PPC_SVR_8543_v10 = 0x80320010, - PPC_SVR_8543_v11 = 0x80320011, - PPC_SVR_8543_v20 = 0x80320020, - PPC_SVR_8543_v21 = 0x80320021, - PPC_SVR_8543E_v10 = 0x803A0010, - PPC_SVR_8543E_v11 = 0x803A0011, - PPC_SVR_8543E_v20 = 0x803A0020, - PPC_SVR_8543E_v21 = 0x803A0021, - PPC_SVR_8544_v10 = 0x80340110, - PPC_SVR_8544_v11 = 0x80340111, - PPC_SVR_8544E_v10 = 0x803C0110, - PPC_SVR_8544E_v11 = 0x803C0111, - PPC_SVR_8545_v20 = 0x80310220, - PPC_SVR_8545_v21 = 0x80310221, - PPC_SVR_8545E_v20 = 0x80390220, - PPC_SVR_8545E_v21 = 0x80390221, - PPC_SVR_8547E_v20 = 0x80390120, - PPC_SVR_8547E_v21 = 0x80390121, - PPC_SCR_8548_v10 = 0x80310010, - PPC_SCR_8548_v11 = 0x80310011, - PPC_SCR_8548_v20 = 0x80310020, - PPC_SCR_8548_v21 = 0x80310021, - PPC_SVR_8548E_v10 = 0x80390010, - PPC_SVR_8548E_v11 = 0x80390011, - PPC_SVR_8548E_v20 = 0x80390020, - PPC_SVR_8548E_v21 = 0x80390021, - PPC_SVR_8555_v10 = 0x80710010, - PPC_SVR_8555_v11 = 0x80710011, - PPC_SVR_8555E_v10 = 0x80790010, - PPC_SVR_8555E_v11 = 0x80790011, - PPC_SVR_8560_v10 = 0x80700010, - PPC_SVR_8560_v20 = 0x80700020, - PPC_SVR_8560_v21 = 0x80700021, - PPC_SVR_8567 = 0x80750111, - PPC_SVR_8567E = 0x807D0111, - PPC_SVR_8568 = 0x80750011, - PPC_SVR_8568E = 0x807D0011, - PPC_SVR_8572 = 0x80E00010, - PPC_SVR_8572E = 0x80E80010, + POWERPC_SVR_8360E = xxx, +#endif +#define POWERPC_SVR_E500 0x40000000 + POWERPC_SVR_8377 = 0x80C70010 | POWERPC_SVR_E500, + POWERPC_SVR_8377E = 0x80C60010 | POWERPC_SVR_E500, + POWERPC_SVR_8378 = 0x80C50010 | POWERPC_SVR_E500, + POWERPC_SVR_8378E = 0x80C40010 | POWERPC_SVR_E500, + POWERPC_SVR_8379 = 0x80C30010 | POWERPC_SVR_E500, + POWERPC_SVR_8379E = 0x80C00010 | POWERPC_SVR_E500, +#define POWERPC_SVR_8533 POWERPC_SVR_8533_v11 + POWERPC_SVR_8533_v10 = 0x80340010 | POWERPC_SVR_E500, + POWERPC_SVR_8533_v11 = 0x80340011 | POWERPC_SVR_E500, +#define POWERPC_SVR_8533E POWERPC_SVR_8533E_v11 + POWERPC_SVR_8533E_v10 = 0x803C0010 | POWERPC_SVR_E500, + POWERPC_SVR_8533E_v11 = 0x803C0011 | POWERPC_SVR_E500, +#define POWERPC_SVR_8540 POWERPC_SVR_8540_v21 + POWERPC_SVR_8540_v10 = 0x80300010 | POWERPC_SVR_E500, + POWERPC_SVR_8540_v20 = 0x80300020 | POWERPC_SVR_E500, + POWERPC_SVR_8540_v21 = 0x80300021 | POWERPC_SVR_E500, +#define POWERPC_SVR_8541 POWERPC_SVR_8541_v11 + POWERPC_SVR_8541_v10 = 0x80720010 | POWERPC_SVR_E500, + POWERPC_SVR_8541_v11 = 0x80720011 | POWERPC_SVR_E500, +#define POWERPC_SVR_8541E POWERPC_SVR_8541E_v11 + POWERPC_SVR_8541E_v10 = 0x807A0010 | POWERPC_SVR_E500, + POWERPC_SVR_8541E_v11 = 0x807A0011 | POWERPC_SVR_E500, +#define POWERPC_SVR_8543 POWERPC_SVR_8543_v21 + POWERPC_SVR_8543_v10 = 0x80320010 | POWERPC_SVR_E500, + POWERPC_SVR_8543_v11 = 0x80320011 | POWERPC_SVR_E500, + POWERPC_SVR_8543_v20 = 0x80320020 | POWERPC_SVR_E500, + POWERPC_SVR_8543_v21 = 0x80320021 | POWERPC_SVR_E500, +#define POWERPC_SVR_8543E POWERPC_SVR_8543E_v21 + POWERPC_SVR_8543E_v10 = 0x803A0010 | POWERPC_SVR_E500, + POWERPC_SVR_8543E_v11 = 0x803A0011 | POWERPC_SVR_E500, + POWERPC_SVR_8543E_v20 = 0x803A0020 | POWERPC_SVR_E500, + POWERPC_SVR_8543E_v21 = 0x803A0021 | POWERPC_SVR_E500, +#define POWERPC_SVR_8544 POWERPC_SVR_8544_v11 + POWERPC_SVR_8544_v10 = 0x80340110 | POWERPC_SVR_E500, + POWERPC_SVR_8544_v11 = 0x80340111 | POWERPC_SVR_E500, +#define POWERPC_SVR_8544E POWERPC_SVR_8544E_v11 + POWERPC_SVR_8544E_v10 = 0x803C0110 | POWERPC_SVR_E500, + POWERPC_SVR_8544E_v11 = 0x803C0111 | POWERPC_SVR_E500, +#define POWERPC_SVR_8545 POWERPC_SVR_8545_v21 + POWERPC_SVR_8545_v20 = 0x80310220 | POWERPC_SVR_E500, + POWERPC_SVR_8545_v21 = 0x80310221 | POWERPC_SVR_E500, +#define POWERPC_SVR_8545E POWERPC_SVR_8545E_v21 + POWERPC_SVR_8545E_v20 = 0x80390220 | POWERPC_SVR_E500, + POWERPC_SVR_8545E_v21 = 0x80390221 | POWERPC_SVR_E500, +#define POWERPC_SVR_8547E POWERPC_SVR_8547E_v21 + POWERPC_SVR_8547E_v20 = 0x80390120 | POWERPC_SVR_E500, + POWERPC_SVR_8547E_v21 = 0x80390121 | POWERPC_SVR_E500, +#define POWERPC_SVR_8548 POWERPC_SVR_8548_v21 + POWERPC_SVR_8548_v10 = 0x80310010 | POWERPC_SVR_E500, + POWERPC_SVR_8548_v11 = 0x80310011 | POWERPC_SVR_E500, + POWERPC_SVR_8548_v20 = 0x80310020 | POWERPC_SVR_E500, + POWERPC_SVR_8548_v21 = 0x80310021 | POWERPC_SVR_E500, +#define POWERPC_SVR_8548E POWERPC_SVR_8548E_v21 + POWERPC_SVR_8548E_v10 = 0x80390010 | POWERPC_SVR_E500, + POWERPC_SVR_8548E_v11 = 0x80390011 | POWERPC_SVR_E500, + POWERPC_SVR_8548E_v20 = 0x80390020 | POWERPC_SVR_E500, + POWERPC_SVR_8548E_v21 = 0x80390021 | POWERPC_SVR_E500, +#define POWERPC_SVR_8555 POWERPC_SVR_8555_v11 + POWERPC_SVR_8555_v10 = 0x80710010 | POWERPC_SVR_E500, + POWERPC_SVR_8555_v11 = 0x80710011 | POWERPC_SVR_E500, +#define POWERPC_SVR_8555E POWERPC_SVR_8555_v11 + POWERPC_SVR_8555E_v10 = 0x80790010 | POWERPC_SVR_E500, + POWERPC_SVR_8555E_v11 = 0x80790011 | POWERPC_SVR_E500, +#define POWERPC_SVR_8560 POWERPC_SVR_8560_v21 + POWERPC_SVR_8560_v10 = 0x80700010 | POWERPC_SVR_E500, + POWERPC_SVR_8560_v20 = 0x80700020 | POWERPC_SVR_E500, + POWERPC_SVR_8560_v21 = 0x80700021 | POWERPC_SVR_E500, + POWERPC_SVR_8567 = 0x80750111 | POWERPC_SVR_E500, + POWERPC_SVR_8567E = 0x807D0111 | POWERPC_SVR_E500, + POWERPC_SVR_8568 = 0x80750011 | POWERPC_SVR_E500, + POWERPC_SVR_8568E = 0x807D0011 | POWERPC_SVR_E500, + POWERPC_SVR_8572 = 0x80E00010 | POWERPC_SVR_E500, + POWERPC_SVR_8572E = 0x80E80010 | POWERPC_SVR_E500, #if 0 - PPC_SVR_8610 = xxx, + POWERPC_SVR_8610 = xxx, #endif - PPC_SVR_8641 = 0x80900021, - PPC_SVR_8641D = 0x80900121, + POWERPC_SVR_8641 = 0x80900021, + POWERPC_SVR_8641D = 0x80900121, }; /*****************************************************************************/ /* PowerPC CPU definitions */ -#define POWERPC_DEF(_name, _pvr, _type) \ +#define POWERPC_DEF_SVR(_name, _pvr, _svr, _type) \ { \ .name = _name, \ .pvr = _pvr, \ + .svr = _svr, \ .insns_flags = glue(POWERPC_INSNS_,_type), \ .msr_mask = glue(POWERPC_MSRM_,_type), \ .mmu_model = glue(POWERPC_MMU_,_type), \ @@ -5267,862 +6157,1551 @@ enum { .init_proc = &glue(init_proc_,_type), \ .check_pow = &glue(check_pow_,_type), \ } +#define POWERPC_DEF(_name, _pvr, _type) \ +POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type) static const ppc_def_t ppc_defs[] = { /* Embedded PowerPC */ /* PowerPC 401 family */ /* Generic PowerPC 401 */ - POWERPC_DEF("401", CPU_POWERPC_401, 401), + POWERPC_DEF("401", CPU_POWERPC_401, 401), /* PowerPC 401 cores */ /* PowerPC 401A1 */ - POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401), + POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401), /* PowerPC 401B2 */ - POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2), + POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2), #if defined (TODO) /* PowerPC 401B3 */ - POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3), + POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3), #endif /* PowerPC 401C2 */ - POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2), + POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2), /* PowerPC 401D2 */ - POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2), + POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2), /* PowerPC 401E2 */ - POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2), + POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2), /* PowerPC 401F2 */ - POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2), + POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2), /* PowerPC 401G2 */ /* XXX: to be checked */ - POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2), + POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2), /* PowerPC 401 microcontrolers */ #if defined (TODO) /* PowerPC 401GF */ - POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401), + POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401), #endif /* IOP480 (401 microcontroler) */ - POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480), + POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480), /* IBM Processor for Network Resources */ - POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401), + POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401), #if defined (TODO) - POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401), + POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401), #endif /* PowerPC 403 family */ /* Generic PowerPC 403 */ - POWERPC_DEF("403", CPU_POWERPC_403, 403), + POWERPC_DEF("403", CPU_POWERPC_403, 403), /* PowerPC 403 microcontrolers */ /* PowerPC 403 GA */ - POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403), + POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403), /* PowerPC 403 GB */ - POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403), + POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403), /* PowerPC 403 GC */ - POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403), + POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403), /* PowerPC 403 GCX */ - POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX), + POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX), #if defined (TODO) /* PowerPC 403 GP */ - POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403), + POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403), #endif /* PowerPC 405 family */ /* Generic PowerPC 405 */ - POWERPC_DEF("405", CPU_POWERPC_405, 405), + POWERPC_DEF("405", CPU_POWERPC_405, 405), /* PowerPC 405 cores */ #if defined (TODO) /* PowerPC 405 A3 */ - POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405), + POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405), #endif #if defined (TODO) /* PowerPC 405 A4 */ - POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405), + POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405), #endif #if defined (TODO) /* PowerPC 405 B3 */ - POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405), + POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405), #endif #if defined (TODO) /* PowerPC 405 B4 */ - POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405), + POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405), #endif #if defined (TODO) /* PowerPC 405 C3 */ - POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405), + POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405), #endif #if defined (TODO) /* PowerPC 405 C4 */ - POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405), + POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405), #endif /* PowerPC 405 D2 */ - POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405), + POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405), #if defined (TODO) /* PowerPC 405 D3 */ - POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405), + POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405), #endif /* PowerPC 405 D4 */ - POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405), + POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405), #if defined (TODO) /* PowerPC 405 D5 */ - POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405), + POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405), #endif #if defined (TODO) /* PowerPC 405 E4 */ - POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405), + POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405), #endif #if defined (TODO) /* PowerPC 405 F4 */ - POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405), + POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405), #endif #if defined (TODO) /* PowerPC 405 F5 */ - POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405), + POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405), #endif #if defined (TODO) /* PowerPC 405 F6 */ - POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405), + POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405), #endif /* PowerPC 405 microcontrolers */ /* PowerPC 405 CR */ - POWERPC_DEF("405CR", CPU_POWERPC_405CR, 405), + POWERPC_DEF("405CR", CPU_POWERPC_405CR, 405), /* PowerPC 405 CRa */ - POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405), + POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405), /* PowerPC 405 CRb */ - POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405), + POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405), /* PowerPC 405 CRc */ - POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405), + POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405), /* PowerPC 405 EP */ - POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405), + POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405), #if defined(TODO) /* PowerPC 405 EXr */ - POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405), + POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405), #endif /* PowerPC 405 EZ */ - POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405), + POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405), #if defined(TODO) /* PowerPC 405 FX */ - POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405), + POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405), #endif /* PowerPC 405 GP */ - POWERPC_DEF("405GP", CPU_POWERPC_405GP, 405), + POWERPC_DEF("405GP", CPU_POWERPC_405GP, 405), /* PowerPC 405 GPa */ - POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405), + POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405), /* PowerPC 405 GPb */ - POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405), + POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405), /* PowerPC 405 GPc */ - POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405), + POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405), /* PowerPC 405 GPd */ - POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405), + POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405), /* PowerPC 405 GPe */ - POWERPC_DEF("405GPe", CPU_POWERPC_405GPe, 405), + POWERPC_DEF("405GPe", CPU_POWERPC_405GPe, 405), /* PowerPC 405 GPR */ - POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405), + POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405), #if defined(TODO) /* PowerPC 405 H */ - POWERPC_DEF("405H", CPU_POWERPC_405H, 405), + POWERPC_DEF("405H", CPU_POWERPC_405H, 405), #endif #if defined(TODO) /* PowerPC 405 L */ - POWERPC_DEF("405L", CPU_POWERPC_405L, 405), + POWERPC_DEF("405L", CPU_POWERPC_405L, 405), #endif /* PowerPC 405 LP */ - POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405), + POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405), #if defined(TODO) /* PowerPC 405 PM */ - POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405), + POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405), #endif #if defined(TODO) /* PowerPC 405 PS */ - POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405), + POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405), #endif #if defined(TODO) /* PowerPC 405 S */ - POWERPC_DEF("405S", CPU_POWERPC_405S, 405), + POWERPC_DEF("405S", CPU_POWERPC_405S, 405), #endif /* Npe405 H */ - POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405), + POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405), /* Npe405 H2 */ - POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405), + POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405), /* Npe405 L */ - POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405), + POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405), /* Npe4GS3 */ - POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405), + POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405), #if defined (TODO) - POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405), + POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405), #endif #if defined (TODO) - POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405), + POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405), #endif #if defined (TODO) /* PowerPC LC77700 (Sanyo) */ - POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405), + POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405), #endif /* PowerPC 401/403/405 based set-top-box microcontrolers */ #if defined (TODO) /* STB010000 */ - POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2), + POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2), #endif #if defined (TODO) /* STB01010 */ - POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2), + POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2), #endif #if defined (TODO) /* STB0210 */ - POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3), + POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3), #endif /* STB03xx */ - POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405), + POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405), #if defined (TODO) /* STB043x */ - POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405), + POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405), #endif #if defined (TODO) /* STB045x */ - POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405), + POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405), #endif /* STB04xx */ - POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405), + POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405), /* STB25xx */ - POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405), + POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405), #if defined (TODO) /* STB130 */ - POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405), + POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405), #endif /* Xilinx PowerPC 405 cores */ - POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405), - POWERPC_DEF("x2vp7", CPU_POWERPC_X2VP7, 405), - POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405), - POWERPC_DEF("x2vp50", CPU_POWERPC_X2VP50, 405), + POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405), + POWERPC_DEF("x2vp7", CPU_POWERPC_X2VP7, 405), + POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405), + POWERPC_DEF("x2vp50", CPU_POWERPC_X2VP50, 405), #if defined (TODO) /* Zarlink ZL10310 */ - POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405), + POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405), #endif #if defined (TODO) /* Zarlink ZL10311 */ - POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405), + POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405), #endif #if defined (TODO) /* Zarlink ZL10320 */ - POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405), + POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405), #endif #if defined (TODO) /* Zarlink ZL10321 */ - POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405), + POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405), #endif /* PowerPC 440 family */ +#if defined(TODO_USER_ONLY) /* Generic PowerPC 440 */ - POWERPC_DEF("440", CPU_POWERPC_440, 440GP), + POWERPC_DEF("440", CPU_POWERPC_440, 440GP), +#endif /* PowerPC 440 cores */ #if defined (TODO) /* PowerPC 440 A4 */ - POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4), + POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4), #endif #if defined (TODO) /* PowerPC 440 A5 */ - POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5), + POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5), #endif #if defined (TODO) /* PowerPC 440 B4 */ - POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4), + POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4), #endif #if defined (TODO) /* PowerPC 440 G4 */ - POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4), + POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4), #endif #if defined (TODO) /* PowerPC 440 F5 */ - POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5), + POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5), #endif #if defined (TODO) /* PowerPC 440 G5 */ - POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5), + POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5), #endif #if defined (TODO) /* PowerPC 440H4 */ - POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4), + POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4), #endif #if defined (TODO) /* PowerPC 440H6 */ - POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5), + POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5), #endif /* PowerPC 440 microcontrolers */ +#if defined(TODO_USER_ONLY) /* PowerPC 440 EP */ - POWERPC_DEF("440EP", CPU_POWERPC_440EP, 440EP), + POWERPC_DEF("440EP", CPU_POWERPC_440EP, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 EPa */ - POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP), + POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 EPb */ - POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP), + POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 EPX */ - POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP), + POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GP */ - POWERPC_DEF("440GP", CPU_POWERPC_440GP, 440GP), + POWERPC_DEF("440GP", CPU_POWERPC_440GP, 440GP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GPb */ - POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP), + POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GPc */ - POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP), + POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GR */ - POWERPC_DEF("440GR", CPU_POWERPC_440GR, 440x5), + POWERPC_DEF("440GR", CPU_POWERPC_440GR, 440x5), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GRa */ - POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5), + POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GRX */ - POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5), + POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GX */ - POWERPC_DEF("440GX", CPU_POWERPC_440GX, 440EP), + POWERPC_DEF("440GX", CPU_POWERPC_440GX, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GXa */ - POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP), + POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GXb */ - POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP), + POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GXc */ - POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP), + POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 GXf */ - POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP), + POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP), +#endif #if defined(TODO) /* PowerPC 440 S */ - POWERPC_DEF("440S", CPU_POWERPC_440S, 440), + POWERPC_DEF("440S", CPU_POWERPC_440S, 440), #endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 SP */ - POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP), + POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 SP2 */ - POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP), + POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP), +#endif +#if defined(TODO_USER_ONLY) /* PowerPC 440 SPE */ - POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP), + POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP), +#endif /* PowerPC 460 family */ #if defined (TODO) /* Generic PowerPC 464 */ - POWERPC_DEF("464", CPU_POWERPC_464, 460), + POWERPC_DEF("464", CPU_POWERPC_464, 460), #endif /* PowerPC 464 microcontrolers */ #if defined (TODO) /* PowerPC 464H90 */ - POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460), + POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460), #endif #if defined (TODO) /* PowerPC 464H90F */ - POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F), + POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F), #endif /* Freescale embedded PowerPC cores */ + /* MPC5xx family (aka RCPU) */ +#if defined(TODO_USER_ONLY) + /* Generic MPC5xx core */ + POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* Codename for MPC5xx core */ + POWERPC_DEF("RCPU", CPU_POWERPC_MPC5xx, MPC5xx), +#endif + /* MPC5xx microcontrollers */ +#if defined(TODO_USER_ONLY) + /* MGT560 */ + POWERPC_DEF("MGT560", CPU_POWERPC_MGT560, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC509 */ + POWERPC_DEF("MPC509", CPU_POWERPC_MPC509, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC533 */ + POWERPC_DEF("MPC533", CPU_POWERPC_MPC533, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC534 */ + POWERPC_DEF("MPC534", CPU_POWERPC_MPC534, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC555 */ + POWERPC_DEF("MPC555", CPU_POWERPC_MPC555, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC556 */ + POWERPC_DEF("MPC556", CPU_POWERPC_MPC556, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC560 */ + POWERPC_DEF("MPC560", CPU_POWERPC_MPC560, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC561 */ + POWERPC_DEF("MPC561", CPU_POWERPC_MPC561, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC562 */ + POWERPC_DEF("MPC562", CPU_POWERPC_MPC562, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC563 */ + POWERPC_DEF("MPC563", CPU_POWERPC_MPC563, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC564 */ + POWERPC_DEF("MPC564", CPU_POWERPC_MPC564, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC565 */ + POWERPC_DEF("MPC565", CPU_POWERPC_MPC565, MPC5xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC566 */ + POWERPC_DEF("MPC566", CPU_POWERPC_MPC566, MPC5xx), +#endif + /* MPC8xx family (aka PowerQUICC) */ +#if defined(TODO_USER_ONLY) + /* Generic MPC8xx core */ + POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* Codename for MPC8xx core */ + POWERPC_DEF("PowerQUICC", CPU_POWERPC_MPC8xx, MPC8xx), +#endif + /* MPC8xx microcontrollers */ +#if defined(TODO_USER_ONLY) + /* MGT823 */ + POWERPC_DEF("MGT823", CPU_POWERPC_MGT823, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC821 */ + POWERPC_DEF("MPC821", CPU_POWERPC_MPC821, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC823 */ + POWERPC_DEF("MPC823", CPU_POWERPC_MPC823, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC850 */ + POWERPC_DEF("MPC850", CPU_POWERPC_MPC850, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC852T */ + POWERPC_DEF("MPC852T", CPU_POWERPC_MPC852T, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC855T */ + POWERPC_DEF("MPC855T", CPU_POWERPC_MPC855T, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC857 */ + POWERPC_DEF("MPC857", CPU_POWERPC_MPC857, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC859 */ + POWERPC_DEF("MPC859", CPU_POWERPC_MPC859, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC860 */ + POWERPC_DEF("MPC860", CPU_POWERPC_MPC860, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC862 */ + POWERPC_DEF("MPC862", CPU_POWERPC_MPC862, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC866 */ + POWERPC_DEF("MPC866", CPU_POWERPC_MPC866, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC870 */ + POWERPC_DEF("MPC870", CPU_POWERPC_MPC870, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC875 */ + POWERPC_DEF("MPC875", CPU_POWERPC_MPC875, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC880 */ + POWERPC_DEF("MPC880", CPU_POWERPC_MPC880, MPC8xx), +#endif +#if defined(TODO_USER_ONLY) + /* MPC885 */ + POWERPC_DEF("MPC885", CPU_POWERPC_MPC885, MPC8xx), +#endif + /* MPC82xx family (aka PowerQUICC-II) */ + /* Generic MPC52xx core */ + POWERPC_DEF_SVR("MPC52xx", + CPU_POWERPC_MPC52xx, POWERPC_SVR_52xx, G2LE), + /* Generic MPC82xx core */ + POWERPC_DEF("MPC82xx", CPU_POWERPC_MPC82xx, G2), + /* Codename for MPC82xx */ + POWERPC_DEF("PowerQUICC-II", CPU_POWERPC_MPC82xx, G2), + /* PowerPC G2 core */ + POWERPC_DEF("G2", CPU_POWERPC_G2, G2), + /* PowerPC G2 H4 core */ + POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2), + /* PowerPC G2 GP core */ + POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2), + /* PowerPC G2 LS core */ + POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2), + /* PowerPC G2 HiP3 core */ + POWERPC_DEF("G2HiP3", CPU_POWERPC_G2_HIP3, G2), + /* PowerPC G2 HiP4 core */ + POWERPC_DEF("G2HiP4", CPU_POWERPC_G2_HIP4, G2), + /* PowerPC MPC603 core */ + POWERPC_DEF("MPC603", CPU_POWERPC_MPC603, 603E), + /* PowerPC G2le core (same as G2 plus little-endian mode support) */ + POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE), + /* PowerPC G2LE GP core */ + POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE), + /* PowerPC G2LE LS core */ + POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE), + /* PowerPC G2LE GP1 core */ + POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE), + /* PowerPC G2LE GP3 core */ + POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp1, G2LE), + /* PowerPC MPC603 microcontrollers */ + /* MPC8240 */ + POWERPC_DEF("MPC8240", CPU_POWERPC_MPC8240, 603E), + /* PowerPC G2 microcontrollers */ +#if 0 + /* MPC5121 */ + POWERPC_DEF_SVR("MPC5121", + CPU_POWERPC_MPC5121, POWERPC_SVR_5121, G2LE), +#endif + /* MPC5200 */ + POWERPC_DEF_SVR("MPC5200", + CPU_POWERPC_MPC5200, POWERPC_SVR_5200, G2LE), + /* MPC5200 v1.0 */ + POWERPC_DEF_SVR("MPC5200_v10", + CPU_POWERPC_MPC5200_v10, POWERPC_SVR_5200_v10, G2LE), + /* MPC5200 v1.1 */ + POWERPC_DEF_SVR("MPC5200_v11", + CPU_POWERPC_MPC5200_v11, POWERPC_SVR_5200_v11, G2LE), + /* MPC5200 v1.2 */ + POWERPC_DEF_SVR("MPC5200_v12", + CPU_POWERPC_MPC5200_v12, POWERPC_SVR_5200_v12, G2LE), + /* MPC5200B */ + POWERPC_DEF_SVR("MPC5200B", + CPU_POWERPC_MPC5200B, POWERPC_SVR_5200B, G2LE), + /* MPC5200B v2.0 */ + POWERPC_DEF_SVR("MPC5200B_v20", + CPU_POWERPC_MPC5200B_v20, POWERPC_SVR_5200B_v20, G2LE), + /* MPC5200B v2.1 */ + POWERPC_DEF_SVR("MPC5200B_v21", + CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE), + /* MPC8241 */ + POWERPC_DEF("MPC8241", CPU_POWERPC_MPC8241, G2), + /* MPC8245 */ + POWERPC_DEF("MPC8245", CPU_POWERPC_MPC8245, G2), + /* MPC8247 */ + POWERPC_DEF("MPC8247", CPU_POWERPC_MPC8247, G2LE), + /* MPC8248 */ + POWERPC_DEF("MPC8248", CPU_POWERPC_MPC8248, G2LE), + /* MPC8250 */ + POWERPC_DEF("MPC8250", CPU_POWERPC_MPC8250, G2), + /* MPC8250 HiP3 */ + POWERPC_DEF("MPC8250_HiP3", CPU_POWERPC_MPC8250_HiP3, G2), + /* MPC8250 HiP4 */ + POWERPC_DEF("MPC8250_HiP4", CPU_POWERPC_MPC8250_HiP4, G2), + /* MPC8255 */ + POWERPC_DEF("MPC8255", CPU_POWERPC_MPC8255, G2), + /* MPC8255 HiP3 */ + POWERPC_DEF("MPC8255_HiP3", CPU_POWERPC_MPC8255_HiP3, G2), + /* MPC8255 HiP4 */ + POWERPC_DEF("MPC8255_HiP4", CPU_POWERPC_MPC8255_HiP4, G2), + /* MPC8260 */ + POWERPC_DEF("MPC8260", CPU_POWERPC_MPC8260, G2), + /* MPC8260 HiP3 */ + POWERPC_DEF("MPC8260_HiP3", CPU_POWERPC_MPC8260_HiP3, G2), + /* MPC8260 HiP4 */ + POWERPC_DEF("MPC8260_HiP4", CPU_POWERPC_MPC8260_HiP4, G2), + /* MPC8264 */ + POWERPC_DEF("MPC8264", CPU_POWERPC_MPC8264, G2), + /* MPC8264 HiP3 */ + POWERPC_DEF("MPC8264_HiP3", CPU_POWERPC_MPC8264_HiP3, G2), + /* MPC8264 HiP4 */ + POWERPC_DEF("MPC8264_HiP4", CPU_POWERPC_MPC8264_HiP4, G2), + /* MPC8265 */ + POWERPC_DEF("MPC8265", CPU_POWERPC_MPC8265, G2), + /* MPC8265 HiP3 */ + POWERPC_DEF("MPC8265_HiP3", CPU_POWERPC_MPC8265_HiP3, G2), + /* MPC8265 HiP4 */ + POWERPC_DEF("MPC8265_HiP4", CPU_POWERPC_MPC8265_HiP4, G2), + /* MPC8266 */ + POWERPC_DEF("MPC8266", CPU_POWERPC_MPC8266, G2), + /* MPC8266 HiP3 */ + POWERPC_DEF("MPC8266_HiP3", CPU_POWERPC_MPC8266_HiP3, G2), + /* MPC8266 HiP4 */ + POWERPC_DEF("MPC8266_HiP4", CPU_POWERPC_MPC8266_HiP4, G2), + /* MPC8270 */ + POWERPC_DEF("MPC8270", CPU_POWERPC_MPC8270, G2LE), + /* MPC8271 */ + POWERPC_DEF("MPC8271", CPU_POWERPC_MPC8271, G2LE), + /* MPC8272 */ + POWERPC_DEF("MPC8272", CPU_POWERPC_MPC8272, G2LE), + /* MPC8275 */ + POWERPC_DEF("MPC8275", CPU_POWERPC_MPC8275, G2LE), + /* MPC8280 */ + POWERPC_DEF("MPC8280", CPU_POWERPC_MPC8280, G2LE), /* e200 family */ -#if defined (TODO) /* Generic PowerPC e200 core */ - POWERPC_DEF("e200", CPU_POWERPC_e200, e200), + POWERPC_DEF("e200", CPU_POWERPC_e200, e200), + /* Generic MPC55xx core */ +#if defined (TODO) + POWERPC_DEF_SVR("MPC55xx", + CPU_POWERPC_MPC55xx, POWERPC_SVR_55xx, e200), #endif #if defined (TODO) - /* PowerPC e200z5 core */ - POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200), + /* PowerPC e200z0 core */ + POWERPC_DEF("e200z0", CPU_POWERPC_e200z0, e200), +#endif +#if defined (TODO) + /* PowerPC e200z1 core */ + POWERPC_DEF("e200z1", CPU_POWERPC_e200z1, e200), #endif #if defined (TODO) + /* PowerPC e200z3 core */ + POWERPC_DEF("e200z3", CPU_POWERPC_e200z3, e200), +#endif + /* PowerPC e200z5 core */ + POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200), /* PowerPC e200z6 core */ - POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200), + POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200), + /* PowerPC e200 microcontrollers */ +#if defined (TODO) + /* MPC5514E */ + POWERPC_DEF_SVR("MPC5514E", + CPU_POWERPC_MPC5514E, POWERPC_SVR_5514E, e200), #endif - /* e300 family */ #if defined (TODO) - /* Generic PowerPC e300 core */ - POWERPC_DEF("e300", CPU_POWERPC_e300, e300), + /* MPC5514E v0 */ + POWERPC_DEF_SVR("MPC5514E_v0", + CPU_POWERPC_MPC5514E_v0, POWERPC_SVR_5514E_v0, e200), #endif #if defined (TODO) - /* PowerPC e300c1 core */ - POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300), + /* MPC5514E v1 */ + POWERPC_DEF_SVR("MPC5514E_v1", + CPU_POWERPC_MPC5514E_v1, POWERPC_SVR_5514E_v1, e200), #endif #if defined (TODO) - /* PowerPC e300c2 core */ - POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300), + /* MPC5514G */ + POWERPC_DEF_SVR("MPC5514G", + CPU_POWERPC_MPC5514G, POWERPC_SVR_5514G, e200), #endif #if defined (TODO) - /* PowerPC e300c3 core */ - POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300), + /* MPC5514G v0 */ + POWERPC_DEF_SVR("MPC5514G_v0", + CPU_POWERPC_MPC5514G_v0, POWERPC_SVR_5514G_v0, e200), #endif - /* e500 family */ #if defined (TODO) - /* PowerPC e500 core */ - POWERPC_DEF("e500", CPU_POWERPC_e500, e500), + /* MPC5514G v1 */ + POWERPC_DEF_SVR("MPC5514G_v1", + CPU_POWERPC_MPC5514G_v1, POWERPC_SVR_5514G_v1, e200), #endif #if defined (TODO) - /* PowerPC e500 v1.1 core */ - POWERPC_DEF("e500v1.1", CPU_POWERPC_e500_v11, e500), + /* MPC5515S */ + POWERPC_DEF_SVR("MPC5515S", + CPU_POWERPC_MPC5515S, POWERPC_SVR_5515S, e200), #endif #if defined (TODO) - /* PowerPC e500 v1.2 core */ - POWERPC_DEF("e500v1.2", CPU_POWERPC_e500_v12, e500), + /* MPC5516E */ + POWERPC_DEF_SVR("MPC5516E", + CPU_POWERPC_MPC5516E, POWERPC_SVR_5516E, e200), #endif #if defined (TODO) - /* PowerPC e500 v2.1 core */ - POWERPC_DEF("e500v2.1", CPU_POWERPC_e500_v21, e500), + /* MPC5516E v0 */ + POWERPC_DEF_SVR("MPC5516E_v0", + CPU_POWERPC_MPC5516E_v0, POWERPC_SVR_5516E_v0, e200), #endif #if defined (TODO) - /* PowerPC e500 v2.2 core */ - POWERPC_DEF("e500v2.2", CPU_POWERPC_e500_v22, e500), + /* MPC5516E v1 */ + POWERPC_DEF_SVR("MPC5516E_v1", + CPU_POWERPC_MPC5516E_v1, POWERPC_SVR_5516E_v1, e200), #endif - /* e600 family */ #if defined (TODO) - /* PowerPC e600 core */ - POWERPC_DEF("e600", CPU_POWERPC_e600, e600), + /* MPC5516G */ + POWERPC_DEF_SVR("MPC5516G", + CPU_POWERPC_MPC5516G, POWERPC_SVR_5516G, e200), #endif - /* PowerPC MPC 5xx cores */ #if defined (TODO) - /* PowerPC MPC 5xx */ - POWERPC_DEF("mpc5xx", CPU_POWERPC_5xx, 5xx), + /* MPC5516G v0 */ + POWERPC_DEF_SVR("MPC5516G_v0", + CPU_POWERPC_MPC5516G_v0, POWERPC_SVR_5516G_v0, e200), #endif - /* PowerPC MPC 8xx cores */ #if defined (TODO) - /* PowerPC MPC 8xx */ - POWERPC_DEF("mpc8xx", CPU_POWERPC_8xx, 8xx), + /* MPC5516G v1 */ + POWERPC_DEF_SVR("MPC5516G_v1", + CPU_POWERPC_MPC5516G_v1, POWERPC_SVR_5516G_v1, e200), #endif - /* PowerPC MPC 8xxx cores */ #if defined (TODO) - /* PowerPC MPC 82xx HIP3 */ - POWERPC_DEF("mpc82xxhip3", CPU_POWERPC_82xx_HIP3, 82xx), + /* MPC5516S */ + POWERPC_DEF_SVR("MPC5516S", + CPU_POWERPC_MPC5516S, POWERPC_SVR_5516S, e200), #endif #if defined (TODO) - /* PowerPC MPC 82xx HIP4 */ - POWERPC_DEF("mpc82xxhip4", CPU_POWERPC_82xx_HIP4, 82xx), + /* MPC5533 */ + POWERPC_DEF_SVR("MPC5533", + CPU_POWERPC_MPC5533, POWERPC_SVR_5533, e200), #endif #if defined (TODO) - /* PowerPC MPC 827x */ - POWERPC_DEF("mpc827x", CPU_POWERPC_827x, 827x), + /* MPC5534 */ + POWERPC_DEF_SVR("MPC5534", + CPU_POWERPC_MPC5534, POWERPC_SVR_5534, e200), #endif - +#if defined (TODO) + /* MPC5553 */ + POWERPC_DEF_SVR("MPC5553", + CPU_POWERPC_MPC5553, POWERPC_SVR_5553, e200), +#endif +#if defined (TODO) + /* MPC5554 */ + POWERPC_DEF_SVR("MPC5554", + CPU_POWERPC_MPC5554, POWERPC_SVR_5554, e200), +#endif +#if defined (TODO) + /* MPC5561 */ + POWERPC_DEF_SVR("MPC5561", + CPU_POWERPC_MPC5561, POWERPC_SVR_5561, e200), +#endif +#if defined (TODO) + /* MPC5565 */ + POWERPC_DEF_SVR("MPC5565", + CPU_POWERPC_MPC5565, POWERPC_SVR_5565, e200), +#endif +#if defined (TODO) + /* MPC5566 */ + POWERPC_DEF_SVR("MPC5566", + CPU_POWERPC_MPC5566, POWERPC_SVR_5566, e200), +#endif +#if defined (TODO) + /* MPC5567 */ + POWERPC_DEF_SVR("MPC5567", + CPU_POWERPC_MPC5567, POWERPC_SVR_5567, e200), +#endif + /* e300 family */ + /* Generic PowerPC e300 core */ + POWERPC_DEF("e300", CPU_POWERPC_e300, e300), + /* PowerPC e300c1 core */ + POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300), + /* PowerPC e300c2 core */ + POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300), + /* PowerPC e300c3 core */ + POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300), + /* PowerPC e300c4 core */ + POWERPC_DEF("e300c4", CPU_POWERPC_e300c4, e300), + /* PowerPC e300 microcontrollers */ +#if defined (TODO) + /* MPC8313 */ + POWERPC_DEF_SVR("MPC8313", + CPU_POWERPC_MPC8313, POWERPC_SVR_8313, e300), +#endif +#if defined (TODO) + /* MPC8313E */ + POWERPC_DEF_SVR("MPC8313E", + CPU_POWERPC_MPC8313E, POWERPC_SVR_8313E, e300), +#endif +#if defined (TODO) + /* MPC8314 */ + POWERPC_DEF_SVR("MPC8314", + CPU_POWERPC_MPC8314, POWERPC_SVR_8314, e300), +#endif +#if defined (TODO) + /* MPC8314E */ + POWERPC_DEF_SVR("MPC8314E", + CPU_POWERPC_MPC8314E, POWERPC_SVR_8314E, e300), +#endif +#if defined (TODO) + /* MPC8315 */ + POWERPC_DEF_SVR("MPC8315", + CPU_POWERPC_MPC8315, POWERPC_SVR_8315, e300), +#endif +#if defined (TODO) + /* MPC8315E */ + POWERPC_DEF_SVR("MPC8315E", + CPU_POWERPC_MPC8315E, POWERPC_SVR_8315E, e300), +#endif +#if defined (TODO) + /* MPC8321 */ + POWERPC_DEF_SVR("MPC8321", + CPU_POWERPC_MPC8321, POWERPC_SVR_8321, e300), +#endif +#if defined (TODO) + /* MPC8321E */ + POWERPC_DEF_SVR("MPC8321E", + CPU_POWERPC_MPC8321E, POWERPC_SVR_8321E, e300), +#endif +#if defined (TODO) + /* MPC8323 */ + POWERPC_DEF_SVR("MPC8323", + CPU_POWERPC_MPC8323, POWERPC_SVR_8323, e300), +#endif +#if defined (TODO) + /* MPC8323E */ + POWERPC_DEF_SVR("MPC8323E", + CPU_POWERPC_MPC8323E, POWERPC_SVR_8323E, e300), +#endif + /* MPC8343A */ + POWERPC_DEF_SVR("MPC8343A", + CPU_POWERPC_MPC8343A, POWERPC_SVR_8343A, e300), + /* MPC8343EA */ + POWERPC_DEF_SVR("MPC8343EA", + CPU_POWERPC_MPC8343EA, POWERPC_SVR_8343EA, e300), + /* MPC8347A */ + POWERPC_DEF_SVR("MPC8347A", + CPU_POWERPC_MPC8347A, POWERPC_SVR_8347A, e300), + /* MPC8347AT */ + POWERPC_DEF_SVR("MPC8347AT", + CPU_POWERPC_MPC8347AT, POWERPC_SVR_8347AT, e300), + /* MPC8347AP */ + POWERPC_DEF_SVR("MPC8347AP", + CPU_POWERPC_MPC8347AP, POWERPC_SVR_8347AP, e300), + /* MPC8347EA */ + POWERPC_DEF_SVR("MPC8347EA", + CPU_POWERPC_MPC8347EA, POWERPC_SVR_8347EA, e300), + /* MPC8347EAT */ + POWERPC_DEF_SVR("MPC8347EAT", + CPU_POWERPC_MPC8347EAT, POWERPC_SVR_8347EAT, e300), + /* MPC8343EAP */ + POWERPC_DEF_SVR("MPC8347EAP", + CPU_POWERPC_MPC8347EAP, POWERPC_SVR_8347EAP, e300), + /* MPC8349 */ + POWERPC_DEF_SVR("MPC8349", + CPU_POWERPC_MPC8349, POWERPC_SVR_8349, e300), + /* MPC8349A */ + POWERPC_DEF_SVR("MPC8349A", + CPU_POWERPC_MPC8349A, POWERPC_SVR_8349A, e300), + /* MPC8349E */ + POWERPC_DEF_SVR("MPC8349E", + CPU_POWERPC_MPC8349E, POWERPC_SVR_8349E, e300), + /* MPC8349EA */ + POWERPC_DEF_SVR("MPC8349EA", + CPU_POWERPC_MPC8349EA, POWERPC_SVR_8349EA, e300), +#if defined (TODO) + /* MPC8358E */ + POWERPC_DEF_SVR("MPC8358E", + CPU_POWERPC_MPC8358E, POWERPC_SVR_8358E, e300), +#endif +#if defined (TODO) + /* MPC8360E */ + POWERPC_DEF_SVR("MPC8360E", + CPU_POWERPC_MPC8360E, POWERPC_SVR_8360E, e300), +#endif + /* MPC8377 */ + POWERPC_DEF_SVR("MPC8377", + CPU_POWERPC_MPC8377, POWERPC_SVR_8377, e300), + /* MPC8377E */ + POWERPC_DEF_SVR("MPC8377E", + CPU_POWERPC_MPC8377E, POWERPC_SVR_8377E, e300), + /* MPC8378 */ + POWERPC_DEF_SVR("MPC8378", + CPU_POWERPC_MPC8378, POWERPC_SVR_8378, e300), + /* MPC8378E */ + POWERPC_DEF_SVR("MPC8378E", + CPU_POWERPC_MPC8378E, POWERPC_SVR_8378E, e300), + /* MPC8379 */ + POWERPC_DEF_SVR("MPC8379", + CPU_POWERPC_MPC8379, POWERPC_SVR_8379, e300), + /* MPC8379E */ + POWERPC_DEF_SVR("MPC8379E", + CPU_POWERPC_MPC8379E, POWERPC_SVR_8379E, e300), + /* e500 family */ + /* PowerPC e500 core */ + POWERPC_DEF("e500", CPU_POWERPC_e500, e500), + /* PowerPC e500 v1.0 core */ + POWERPC_DEF("e500_v10", CPU_POWERPC_e500_v10, e500), + /* PowerPC e500 v2.0 core */ + POWERPC_DEF("e500_v20", CPU_POWERPC_e500_v20, e500), + /* PowerPC e500v2 core */ + POWERPC_DEF("e500v2", CPU_POWERPC_e500v2, e500), + /* PowerPC e500v2 v1.0 core */ + POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500), + /* PowerPC e500v2 v2.0 core */ + POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500), + /* PowerPC e500v2 v2.1 core */ + POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500), + /* PowerPC e500v2 v2.2 core */ + POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500), + /* PowerPC e500v2 v3.0 core */ + POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500), + /* PowerPC e500 microcontrollers */ + /* MPC8533 */ + POWERPC_DEF_SVR("MPC8533", + CPU_POWERPC_MPC8533, POWERPC_SVR_8533, e500), + /* MPC8533 v1.0 */ + POWERPC_DEF_SVR("MPC8533_v10", + CPU_POWERPC_MPC8533_v10, POWERPC_SVR_8533_v10, e500), + /* MPC8533 v1.1 */ + POWERPC_DEF_SVR("MPC8533_v11", + CPU_POWERPC_MPC8533_v11, POWERPC_SVR_8533_v11, e500), + /* MPC8533E */ + POWERPC_DEF_SVR("MPC8533E", + CPU_POWERPC_MPC8533E, POWERPC_SVR_8533E, e500), + /* MPC8533E v1.0 */ + POWERPC_DEF_SVR("MPC8533E_v10", + CPU_POWERPC_MPC8533E_v10, POWERPC_SVR_8533E_v10, e500), + POWERPC_DEF_SVR("MPC8533E_v11", + CPU_POWERPC_MPC8533E_v11, POWERPC_SVR_8533E_v11, e500), + /* MPC8540 */ + POWERPC_DEF_SVR("MPC8540", + CPU_POWERPC_MPC8540, POWERPC_SVR_8540, e500), + /* MPC8540 v1.0 */ + POWERPC_DEF_SVR("MPC8540_v10", + CPU_POWERPC_MPC8540_v10, POWERPC_SVR_8540_v10, e500), + /* MPC8540 v2.0 */ + POWERPC_DEF_SVR("MPC8540_v20", + CPU_POWERPC_MPC8540_v20, POWERPC_SVR_8540_v20, e500), + /* MPC8540 v2.1 */ + POWERPC_DEF_SVR("MPC8540_v21", + CPU_POWERPC_MPC8540_v21, POWERPC_SVR_8540_v21, e500), + /* MPC8541 */ + POWERPC_DEF_SVR("MPC8541", + CPU_POWERPC_MPC8541, POWERPC_SVR_8541, e500), + /* MPC8541 v1.0 */ + POWERPC_DEF_SVR("MPC8541_v10", + CPU_POWERPC_MPC8541_v10, POWERPC_SVR_8541_v10, e500), + /* MPC8541 v1.1 */ + POWERPC_DEF_SVR("MPC8541_v11", + CPU_POWERPC_MPC8541_v11, POWERPC_SVR_8541_v11, e500), + /* MPC8541E */ + POWERPC_DEF_SVR("MPC8541E", + CPU_POWERPC_MPC8541E, POWERPC_SVR_8541E, e500), + /* MPC8541E v1.0 */ + POWERPC_DEF_SVR("MPC8541E_v10", + CPU_POWERPC_MPC8541E_v10, POWERPC_SVR_8541E_v10, e500), + /* MPC8541E v1.1 */ + POWERPC_DEF_SVR("MPC8541E_v11", + CPU_POWERPC_MPC8541E_v11, POWERPC_SVR_8541E_v11, e500), + /* MPC8543 */ + POWERPC_DEF_SVR("MPC8543", + CPU_POWERPC_MPC8543, POWERPC_SVR_8543, e500), + /* MPC8543 v1.0 */ + POWERPC_DEF_SVR("MPC8543_v10", + CPU_POWERPC_MPC8543_v10, POWERPC_SVR_8543_v10, e500), + /* MPC8543 v1.1 */ + POWERPC_DEF_SVR("MPC8543_v11", + CPU_POWERPC_MPC8543_v11, POWERPC_SVR_8543_v11, e500), + /* MPC8543 v2.0 */ + POWERPC_DEF_SVR("MPC8543_v20", + CPU_POWERPC_MPC8543_v20, POWERPC_SVR_8543_v20, e500), + /* MPC8543 v2.1 */ + POWERPC_DEF_SVR("MPC8543_v21", + CPU_POWERPC_MPC8543_v21, POWERPC_SVR_8543_v21, e500), + /* MPC8543E */ + POWERPC_DEF_SVR("MPC8543E", + CPU_POWERPC_MPC8543E, POWERPC_SVR_8543E, e500), + /* MPC8543E v1.0 */ + POWERPC_DEF_SVR("MPC8543E_v10", + CPU_POWERPC_MPC8543E_v10, POWERPC_SVR_8543E_v10, e500), + /* MPC8543E v1.1 */ + POWERPC_DEF_SVR("MPC8543E_v11", + CPU_POWERPC_MPC8543E_v11, POWERPC_SVR_8543E_v11, e500), + /* MPC8543E v2.0 */ + POWERPC_DEF_SVR("MPC8543E_v20", + CPU_POWERPC_MPC8543E_v20, POWERPC_SVR_8543E_v20, e500), + /* MPC8543E v2.1 */ + POWERPC_DEF_SVR("MPC8543E_v21", + CPU_POWERPC_MPC8543E_v21, POWERPC_SVR_8543E_v21, e500), + /* MPC8544 */ + POWERPC_DEF_SVR("MPC8544", + CPU_POWERPC_MPC8544, POWERPC_SVR_8544, e500), + /* MPC8544 v1.0 */ + POWERPC_DEF_SVR("MPC8544_v10", + CPU_POWERPC_MPC8544_v10, POWERPC_SVR_8544_v10, e500), + /* MPC8544 v1.1 */ + POWERPC_DEF_SVR("MPC8544_v11", + CPU_POWERPC_MPC8544_v11, POWERPC_SVR_8544_v11, e500), + /* MPC8544E */ + POWERPC_DEF_SVR("MPC8544E", + CPU_POWERPC_MPC8544E, POWERPC_SVR_8544E, e500), + /* MPC8544E v1.0 */ + POWERPC_DEF_SVR("MPC8544E_v10", + CPU_POWERPC_MPC8544E_v10, POWERPC_SVR_8544E_v10, e500), + /* MPC8544E v1.1 */ + POWERPC_DEF_SVR("MPC8544E_v11", + CPU_POWERPC_MPC8544E_v11, POWERPC_SVR_8544E_v11, e500), + /* MPC8545 */ + POWERPC_DEF_SVR("MPC8545", + CPU_POWERPC_MPC8545, POWERPC_SVR_8545, e500), + /* MPC8545 v2.0 */ + POWERPC_DEF_SVR("MPC8545_v20", + CPU_POWERPC_MPC8545_v20, POWERPC_SVR_8545_v20, e500), + /* MPC8545 v2.1 */ + POWERPC_DEF_SVR("MPC8545_v21", + CPU_POWERPC_MPC8545_v21, POWERPC_SVR_8545_v21, e500), + /* MPC8545E */ + POWERPC_DEF_SVR("MPC8545E", + CPU_POWERPC_MPC8545E, POWERPC_SVR_8545E, e500), + /* MPC8545E v2.0 */ + POWERPC_DEF_SVR("MPC8545E_v20", + CPU_POWERPC_MPC8545E_v20, POWERPC_SVR_8545E_v20, e500), + /* MPC8545E v2.1 */ + POWERPC_DEF_SVR("MPC8545E_v21", + CPU_POWERPC_MPC8545E_v21, POWERPC_SVR_8545E_v21, e500), + /* MPC8547E */ + POWERPC_DEF_SVR("MPC8547E", + CPU_POWERPC_MPC8547E, POWERPC_SVR_8547E, e500), + /* MPC8547E v2.0 */ + POWERPC_DEF_SVR("MPC8547E_v20", + CPU_POWERPC_MPC8547E_v20, POWERPC_SVR_8547E_v20, e500), + /* MPC8547E v2.1 */ + POWERPC_DEF_SVR("MPC8547E_v21", + CPU_POWERPC_MPC8547E_v21, POWERPC_SVR_8547E_v21, e500), + /* MPC8548 */ + POWERPC_DEF_SVR("MPC8548", + CPU_POWERPC_MPC8548, POWERPC_SVR_8548, e500), + /* MPC8548 v1.0 */ + POWERPC_DEF_SVR("MPC8548_v10", + CPU_POWERPC_MPC8548_v10, POWERPC_SVR_8548_v10, e500), + /* MPC8548 v1.1 */ + POWERPC_DEF_SVR("MPC8548_v11", + CPU_POWERPC_MPC8548_v11, POWERPC_SVR_8548_v11, e500), + /* MPC8548 v2.0 */ + POWERPC_DEF_SVR("MPC8548_v20", + CPU_POWERPC_MPC8548_v20, POWERPC_SVR_8548_v20, e500), + /* MPC8548 v2.1 */ + POWERPC_DEF_SVR("MPC8548_v21", + CPU_POWERPC_MPC8548_v21, POWERPC_SVR_8548_v21, e500), + /* MPC8548E */ + POWERPC_DEF_SVR("MPC8548E", + CPU_POWERPC_MPC8548E, POWERPC_SVR_8548E, e500), + /* MPC8548E v1.0 */ + POWERPC_DEF_SVR("MPC8548E_v10", + CPU_POWERPC_MPC8548E_v10, POWERPC_SVR_8548E_v10, e500), + /* MPC8548E v1.1 */ + POWERPC_DEF_SVR("MPC8548E_v11", + CPU_POWERPC_MPC8548E_v11, POWERPC_SVR_8548E_v11, e500), + /* MPC8548E v2.0 */ + POWERPC_DEF_SVR("MPC8548E_v20", + CPU_POWERPC_MPC8548E_v20, POWERPC_SVR_8548E_v20, e500), + /* MPC8548E v2.1 */ + POWERPC_DEF_SVR("MPC8548E_v21", + CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500), + /* MPC8555 */ + POWERPC_DEF_SVR("MPC8555", + CPU_POWERPC_MPC8555, POWERPC_SVR_8555, e500), + /* MPC8555 v1.0 */ + POWERPC_DEF_SVR("MPC8555_v10", + CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500), + /* MPC8555 v1.1 */ + POWERPC_DEF_SVR("MPC8555_v11", + CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500), + /* MPC8555E */ + POWERPC_DEF_SVR("MPC8555E", + CPU_POWERPC_MPC8555E, POWERPC_SVR_8555E, e500), + /* MPC8555E v1.0 */ + POWERPC_DEF_SVR("MPC8555E_v10", + CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500), + /* MPC8555E v1.1 */ + POWERPC_DEF_SVR("MPC8555E_v11", + CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500), + /* MPC8560 */ + POWERPC_DEF_SVR("MPC8560", + CPU_POWERPC_MPC8560, POWERPC_SVR_8560, e500), + /* MPC8560 v1.0 */ + POWERPC_DEF_SVR("MPC8560_v10", + CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500), + /* MPC8560 v2.0 */ + POWERPC_DEF_SVR("MPC8560_v20", + CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500), + /* MPC8560 v2.1 */ + POWERPC_DEF_SVR("MPC8560_v21", + CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500), + /* MPC8567 */ + POWERPC_DEF_SVR("MPC8567", + CPU_POWERPC_MPC8567, POWERPC_SVR_8567, e500), + /* MPC8567E */ + POWERPC_DEF_SVR("MPC8567E", + CPU_POWERPC_MPC8567E, POWERPC_SVR_8567E, e500), + /* MPC8568 */ + POWERPC_DEF_SVR("MPC8568", + CPU_POWERPC_MPC8568, POWERPC_SVR_8568, e500), + /* MPC8568E */ + POWERPC_DEF_SVR("MPC8568E", + CPU_POWERPC_MPC8568E, POWERPC_SVR_8568E, e500), + /* MPC8572 */ + POWERPC_DEF_SVR("MPC8572", + CPU_POWERPC_MPC8572, POWERPC_SVR_8572, e500), + /* MPC8572E */ + POWERPC_DEF_SVR("MPC8572E", + CPU_POWERPC_MPC8572E, POWERPC_SVR_8572E, e500), + /* e600 family */ + /* PowerPC e600 core */ + POWERPC_DEF("e600", CPU_POWERPC_e600, 7400), + /* PowerPC e600 microcontrollers */ +#if defined (TODO) + /* MPC8610 */ + POWERPC_DEF_SVR("MPC8610", + CPU_POWERPC_MPC8610, POWERPC_SVR_8610, 7400), +#endif + /* MPC8641 */ + POWERPC_DEF_SVR("MPC8641", + CPU_POWERPC_MPC8641, POWERPC_SVR_8641, 7400), + /* MPC8641D */ + POWERPC_DEF_SVR("MPC8641D", + CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, 7400), /* 32 bits "classic" PowerPC */ /* PowerPC 6xx family */ /* PowerPC 601 */ - POWERPC_DEF("601", CPU_POWERPC_601, 601), + POWERPC_DEF("601", CPU_POWERPC_601, 601), /* PowerPC 601v0 */ - POWERPC_DEF("601v0", CPU_POWERPC_601_v0, 601), + POWERPC_DEF("601v0", CPU_POWERPC_601_v0, 601), /* PowerPC 601v1 */ - POWERPC_DEF("601v1", CPU_POWERPC_601_v1, 601), + POWERPC_DEF("601v1", CPU_POWERPC_601_v1, 601), /* PowerPC 601v2 */ - POWERPC_DEF("601v2", CPU_POWERPC_601_v2, 601), + POWERPC_DEF("601v2", CPU_POWERPC_601_v2, 601), /* PowerPC 602 */ - POWERPC_DEF("602", CPU_POWERPC_602, 602), + POWERPC_DEF("602", CPU_POWERPC_602, 602), /* PowerPC 603 */ - POWERPC_DEF("603", CPU_POWERPC_603, 603), + POWERPC_DEF("603", CPU_POWERPC_603, 603), /* Code name for PowerPC 603 */ - POWERPC_DEF("Vanilla", CPU_POWERPC_603, 603), + POWERPC_DEF("Vanilla", CPU_POWERPC_603, 603), /* PowerPC 603e */ - POWERPC_DEF("603e", CPU_POWERPC_603E, 603E), + POWERPC_DEF("603e", CPU_POWERPC_603E, 603E), /* Code name for PowerPC 603e */ - POWERPC_DEF("Stretch", CPU_POWERPC_603E, 603E), + POWERPC_DEF("Stretch", CPU_POWERPC_603E, 603E), /* PowerPC 603e v1.1 */ - POWERPC_DEF("603e1.1", CPU_POWERPC_603E_v11, 603E), + POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E), /* PowerPC 603e v1.2 */ - POWERPC_DEF("603e1.2", CPU_POWERPC_603E_v12, 603E), + POWERPC_DEF("603e_v1.2", CPU_POWERPC_603E_v12, 603E), /* PowerPC 603e v1.3 */ - POWERPC_DEF("603e1.3", CPU_POWERPC_603E_v13, 603E), + POWERPC_DEF("603e_v1.3", CPU_POWERPC_603E_v13, 603E), /* PowerPC 603e v1.4 */ - POWERPC_DEF("603e1.4", CPU_POWERPC_603E_v14, 603E), + POWERPC_DEF("603e_v1.4", CPU_POWERPC_603E_v14, 603E), /* PowerPC 603e v2.2 */ - POWERPC_DEF("603e2.2", CPU_POWERPC_603E_v22, 603E), + POWERPC_DEF("603e_v2.2", CPU_POWERPC_603E_v22, 603E), /* PowerPC 603e v3 */ - POWERPC_DEF("603e3", CPU_POWERPC_603E_v3, 603E), + POWERPC_DEF("603e_v3", CPU_POWERPC_603E_v3, 603E), /* PowerPC 603e v4 */ - POWERPC_DEF("603e4", CPU_POWERPC_603E_v4, 603E), + POWERPC_DEF("603e_v4", CPU_POWERPC_603E_v4, 603E), /* PowerPC 603e v4.1 */ - POWERPC_DEF("603e4.1", CPU_POWERPC_603E_v41, 603E), + POWERPC_DEF("603e_v4.1", CPU_POWERPC_603E_v41, 603E), /* PowerPC 603e */ - POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E), + POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E), /* PowerPC 603e7t */ - POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E), + POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E), /* PowerPC 603e7v */ - POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E), + POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E), /* Code name for PowerPC 603ev */ - POWERPC_DEF("Vaillant", CPU_POWERPC_603E7v, 603E), + POWERPC_DEF("Vaillant", CPU_POWERPC_603E7v, 603E), /* PowerPC 603e7v1 */ - POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E), + POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E), /* PowerPC 603e7v2 */ - POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E), + POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E), /* PowerPC 603p */ /* to be checked */ - POWERPC_DEF("603p", CPU_POWERPC_603P, 603), + POWERPC_DEF("603p", CPU_POWERPC_603P, 603), /* PowerPC 603r */ - POWERPC_DEF("603r", CPU_POWERPC_603R, 603E), + POWERPC_DEF("603r", CPU_POWERPC_603R, 603E), /* Code name for PowerPC 603r */ - POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 603E), - /* PowerPC G2 core */ - POWERPC_DEF("G2", CPU_POWERPC_G2, G2), - /* PowerPC G2 H4 */ - POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2), - /* PowerPC G2 GP */ - POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2), - /* PowerPC G2 LS */ - POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2), - /* PowerPC G2LE */ - /* Same as G2, with little-endian mode support */ - POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE), - /* PowerPC G2LE GP */ - POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE), - /* PowerPC G2LE LS */ - POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE), + POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 603E), /* PowerPC 604 */ - POWERPC_DEF("604", CPU_POWERPC_604, 604), + POWERPC_DEF("604", CPU_POWERPC_604, 604), /* PowerPC 604e */ /* XXX: code names "Sirocco" "Mach 5" */ - POWERPC_DEF("604e", CPU_POWERPC_604E, 604), + POWERPC_DEF("604e", CPU_POWERPC_604E, 604), /* PowerPC 604e v1.0 */ - POWERPC_DEF("604e1.0", CPU_POWERPC_604E_v10, 604), + POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604), /* PowerPC 604e v2.2 */ - POWERPC_DEF("604e2.2", CPU_POWERPC_604E_v22, 604), + POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604), /* PowerPC 604e v2.4 */ - POWERPC_DEF("604e2.4", CPU_POWERPC_604E_v24, 604), + POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604), /* PowerPC 604r */ - POWERPC_DEF("604r", CPU_POWERPC_604R, 604), + POWERPC_DEF("604r", CPU_POWERPC_604R, 604), #if defined(TODO) /* PowerPC 604ev */ - POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604), + POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604), #endif /* PowerPC 7xx family */ /* Generic PowerPC 740 (G3) */ - POWERPC_DEF("740", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("740", CPU_POWERPC_7x0, 7x0), /* Generic PowerPC 750 (G3) */ - POWERPC_DEF("750", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("750", CPU_POWERPC_7x0, 7x0), /* Code name for generic PowerPC 740/750 (G3) */ - POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 7x0), /* XXX: 750 codename "Typhoon" */ /* PowerPC 740/750 is also known as G3 */ - POWERPC_DEF("G3", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("G3", CPU_POWERPC_7x0, 7x0), /* PowerPC 740 v2.0 (G3) */ - POWERPC_DEF("740v2.0", CPU_POWERPC_7x0_v20, 7x0), + POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 7x0), /* PowerPC 750 v2.0 (G3) */ - POWERPC_DEF("750v2.0", CPU_POWERPC_7x0_v20, 7x0), + POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 7x0), /* PowerPC 740 v2.1 (G3) */ - POWERPC_DEF("740v2.1", CPU_POWERPC_7x0_v21, 7x0), + POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 7x0), /* PowerPC 750 v2.1 (G3) */ - POWERPC_DEF("750v2.1", CPU_POWERPC_7x0_v21, 7x0), + POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 7x0), /* PowerPC 740 v2.2 (G3) */ - POWERPC_DEF("740v2.2", CPU_POWERPC_7x0_v22, 7x0), + POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 7x0), /* PowerPC 750 v2.2 (G3) */ - POWERPC_DEF("750v2.2", CPU_POWERPC_7x0_v22, 7x0), + POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 7x0), /* PowerPC 740 v3.0 (G3) */ - POWERPC_DEF("740v3.0", CPU_POWERPC_7x0_v30, 7x0), + POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 7x0), /* PowerPC 750 v3.0 (G3) */ - POWERPC_DEF("750v3.0", CPU_POWERPC_7x0_v30, 7x0), + POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 7x0), /* PowerPC 740 v3.1 (G3) */ - POWERPC_DEF("740v3.1", CPU_POWERPC_7x0_v31, 7x0), + POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 7x0), /* PowerPC 750 v3.1 (G3) */ - POWERPC_DEF("750v3.1", CPU_POWERPC_7x0_v31, 7x0), + POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 7x0), /* PowerPC 740E (G3) */ - POWERPC_DEF("740e", CPU_POWERPC_740E, 7x0), + POWERPC_DEF("740e", CPU_POWERPC_740E, 7x0), /* PowerPC 740P (G3) */ - POWERPC_DEF("740p", CPU_POWERPC_7x0P, 7x0), + POWERPC_DEF("740p", CPU_POWERPC_7x0P, 7x0), /* PowerPC 750P (G3) */ - POWERPC_DEF("750p", CPU_POWERPC_7x0P, 7x0), + POWERPC_DEF("750p", CPU_POWERPC_7x0P, 7x0), /* Code name for PowerPC 740P/750P (G3) */ - POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 7x0), + POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 7x0), /* PowerPC 750CL (G3 embedded) */ - POWERPC_DEF("750cl", CPU_POWERPC_750CL, 7x0), + POWERPC_DEF("750cl", CPU_POWERPC_750CL, 7x0), /* PowerPC 750CX (G3 embedded) */ - POWERPC_DEF("750cx", CPU_POWERPC_750CX, 7x0), + POWERPC_DEF("750cx", CPU_POWERPC_750CX, 7x0), /* PowerPC 750CX v2.1 (G3 embedded) */ - POWERPC_DEF("750cx2.1", CPU_POWERPC_750CX_v21, 7x0), + POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 7x0), /* PowerPC 750CX v2.2 (G3 embedded) */ - POWERPC_DEF("750cx2.2", CPU_POWERPC_750CX_v22, 7x0), + POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 7x0), /* PowerPC 750CXe (G3 embedded) */ - POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 7x0), + POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 7x0), /* PowerPC 750CXe v2.1 (G3 embedded) */ - POWERPC_DEF("750cxe21", CPU_POWERPC_750CXE_v21, 7x0), + POWERPC_DEF("750cxe_v21", CPU_POWERPC_750CXE_v21, 7x0), /* PowerPC 750CXe v2.2 (G3 embedded) */ - POWERPC_DEF("750cxe22", CPU_POWERPC_750CXE_v22, 7x0), + POWERPC_DEF("750cxe_v22", CPU_POWERPC_750CXE_v22, 7x0), /* PowerPC 750CXe v2.3 (G3 embedded) */ - POWERPC_DEF("750cxe23", CPU_POWERPC_750CXE_v23, 7x0), + POWERPC_DEF("750cxe_v23", CPU_POWERPC_750CXE_v23, 7x0), /* PowerPC 750CXe v2.4 (G3 embedded) */ - POWERPC_DEF("750cxe24", CPU_POWERPC_750CXE_v24, 7x0), + POWERPC_DEF("750cxe_v24", CPU_POWERPC_750CXE_v24, 7x0), /* PowerPC 750CXe v2.4b (G3 embedded) */ - POWERPC_DEF("750cxe24b", CPU_POWERPC_750CXE_v24b, 7x0), + POWERPC_DEF("750cxe_v24b", CPU_POWERPC_750CXE_v24b, 7x0), /* PowerPC 750CXe v3.1 (G3 embedded) */ - POWERPC_DEF("750cxe31", CPU_POWERPC_750CXE_v31, 7x0), + POWERPC_DEF("750cxe_v31", CPU_POWERPC_750CXE_v31, 7x0), /* PowerPC 750CXe v3.1b (G3 embedded) */ - POWERPC_DEF("750cxe3.1b", CPU_POWERPC_750CXE_v31b, 7x0), + POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 7x0), /* PowerPC 750CXr (G3 embedded) */ - POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 7x0), + POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 7x0), /* PowerPC 750E (G3) */ - POWERPC_DEF("750e", CPU_POWERPC_750E, 7x0), + POWERPC_DEF("750e", CPU_POWERPC_750E, 7x0), /* PowerPC 750FL (G3 embedded) */ - POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx), + POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx), /* PowerPC 750FX (G3 embedded) */ - POWERPC_DEF("750fx", CPU_POWERPC_750FX, 750fx), + POWERPC_DEF("750fx", CPU_POWERPC_750FX, 750fx), /* PowerPC 750FX v1.0 (G3 embedded) */ - POWERPC_DEF("750fx1.0", CPU_POWERPC_750FX_v10, 750fx), + POWERPC_DEF("750fx_v1.0", CPU_POWERPC_750FX_v10, 750fx), /* PowerPC 750FX v2.0 (G3 embedded) */ - POWERPC_DEF("750fx2.0", CPU_POWERPC_750FX_v20, 750fx), + POWERPC_DEF("750fx_v2.0", CPU_POWERPC_750FX_v20, 750fx), /* PowerPC 750FX v2.1 (G3 embedded) */ - POWERPC_DEF("750fx2.1", CPU_POWERPC_750FX_v21, 750fx), + POWERPC_DEF("750fx_v2.1", CPU_POWERPC_750FX_v21, 750fx), /* PowerPC 750FX v2.2 (G3 embedded) */ - POWERPC_DEF("750fx2.2", CPU_POWERPC_750FX_v22, 750fx), + POWERPC_DEF("750fx_v2.2", CPU_POWERPC_750FX_v22, 750fx), /* PowerPC 750FX v2.3 (G3 embedded) */ - POWERPC_DEF("750fx2.3", CPU_POWERPC_750FX_v23, 750fx), + POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx), /* PowerPC 750GL (G3 embedded) */ - POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750fx), + POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750fx), /* PowerPC 750GX (G3 embedded) */ - POWERPC_DEF("750gx", CPU_POWERPC_750GX, 750fx), + POWERPC_DEF("750gx", CPU_POWERPC_750GX, 750fx), /* PowerPC 750GX v1.0 (G3 embedded) */ - POWERPC_DEF("750gx1.0", CPU_POWERPC_750GX_v10, 750fx), + POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750fx), /* PowerPC 750GX v1.1 (G3 embedded) */ - POWERPC_DEF("750gx1.1", CPU_POWERPC_750GX_v11, 750fx), + POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750fx), /* PowerPC 750GX v1.2 (G3 embedded) */ - POWERPC_DEF("750gx1.2", CPU_POWERPC_750GX_v12, 750fx), + POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750fx), /* PowerPC 750L (G3 embedded) */ - POWERPC_DEF("750l", CPU_POWERPC_750L, 7x0), + POWERPC_DEF("750l", CPU_POWERPC_750L, 7x0), /* Code name for PowerPC 750L (G3 embedded) */ - POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 7x0), + POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 7x0), /* PowerPC 750L v2.2 (G3 embedded) */ - POWERPC_DEF("750l2.2", CPU_POWERPC_750L_v22, 7x0), + POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 7x0), /* PowerPC 750L v3.0 (G3 embedded) */ - POWERPC_DEF("750l3.0", CPU_POWERPC_750L_v30, 7x0), + POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 7x0), /* PowerPC 750L v3.2 (G3 embedded) */ - POWERPC_DEF("750l3.2", CPU_POWERPC_750L_v32, 7x0), + POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 7x0), /* Generic PowerPC 745 */ - POWERPC_DEF("745", CPU_POWERPC_7x5, 7x5), + POWERPC_DEF("745", CPU_POWERPC_7x5, 7x5), /* Generic PowerPC 755 */ - POWERPC_DEF("755", CPU_POWERPC_7x5, 7x5), + POWERPC_DEF("755", CPU_POWERPC_7x5, 7x5), /* Code name for PowerPC 745/755 */ - POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 7x5), + POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 7x5), /* PowerPC 745 v1.0 */ - POWERPC_DEF("745v1.0", CPU_POWERPC_7x5_v10, 7x5), + POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 7x5), /* PowerPC 755 v1.0 */ - POWERPC_DEF("755v1.0", CPU_POWERPC_7x5_v10, 7x5), + POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 7x5), /* PowerPC 745 v1.1 */ - POWERPC_DEF("745v1.1", CPU_POWERPC_7x5_v11, 7x5), + POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 7x5), /* PowerPC 755 v1.1 */ - POWERPC_DEF("755v1.1", CPU_POWERPC_7x5_v11, 7x5), + POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 7x5), /* PowerPC 745 v2.0 */ - POWERPC_DEF("745v2.0", CPU_POWERPC_7x5_v20, 7x5), + POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 7x5), /* PowerPC 755 v2.0 */ - POWERPC_DEF("755v2.0", CPU_POWERPC_7x5_v20, 7x5), + POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 7x5), /* PowerPC 745 v2.1 */ - POWERPC_DEF("745v2.1", CPU_POWERPC_7x5_v21, 7x5), + POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 7x5), /* PowerPC 755 v2.1 */ - POWERPC_DEF("755v2.1", CPU_POWERPC_7x5_v21, 7x5), + POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 7x5), /* PowerPC 745 v2.2 */ - POWERPC_DEF("745v2.2", CPU_POWERPC_7x5_v22, 7x5), + POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 7x5), /* PowerPC 755 v2.2 */ - POWERPC_DEF("755v2.2", CPU_POWERPC_7x5_v22, 7x5), + POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 7x5), /* PowerPC 745 v2.3 */ - POWERPC_DEF("745v2.3", CPU_POWERPC_7x5_v23, 7x5), + POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 7x5), /* PowerPC 755 v2.3 */ - POWERPC_DEF("755v2.3", CPU_POWERPC_7x5_v23, 7x5), + POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 7x5), /* PowerPC 745 v2.4 */ - POWERPC_DEF("745v2.4", CPU_POWERPC_7x5_v24, 7x5), + POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 7x5), /* PowerPC 755 v2.4 */ - POWERPC_DEF("755v2.4", CPU_POWERPC_7x5_v24, 7x5), + POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 7x5), /* PowerPC 745 v2.5 */ - POWERPC_DEF("745v2.5", CPU_POWERPC_7x5_v25, 7x5), + POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 7x5), /* PowerPC 755 v2.5 */ - POWERPC_DEF("755v2.5", CPU_POWERPC_7x5_v25, 7x5), + POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 7x5), /* PowerPC 745 v2.6 */ - POWERPC_DEF("745v2.6", CPU_POWERPC_7x5_v26, 7x5), + POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 7x5), /* PowerPC 755 v2.6 */ - POWERPC_DEF("755v2.6", CPU_POWERPC_7x5_v26, 7x5), + POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 7x5), /* PowerPC 745 v2.7 */ - POWERPC_DEF("745v2.7", CPU_POWERPC_7x5_v27, 7x5), + POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 7x5), /* PowerPC 755 v2.7 */ - POWERPC_DEF("755v2.7", CPU_POWERPC_7x5_v27, 7x5), + POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 7x5), /* PowerPC 745 v2.8 */ - POWERPC_DEF("745v2.8", CPU_POWERPC_7x5_v28, 7x5), + POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 7x5), /* PowerPC 755 v2.8 */ - POWERPC_DEF("755v2.8", CPU_POWERPC_7x5_v28, 7x5), + POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 7x5), #if defined (TODO) /* PowerPC 745P (G3) */ - POWERPC_DEF("745p", CPU_POWERPC_7x5P, 7x5), + POWERPC_DEF("745p", CPU_POWERPC_7x5P, 7x5), /* PowerPC 755P (G3) */ - POWERPC_DEF("755p", CPU_POWERPC_7x5P, 7x5), + POWERPC_DEF("755p", CPU_POWERPC_7x5P, 7x5), #endif /* PowerPC 74xx family */ /* PowerPC 7400 (G4) */ - POWERPC_DEF("7400", CPU_POWERPC_7400, 7400), + POWERPC_DEF("7400", CPU_POWERPC_7400, 7400), /* Code name for PowerPC 7400 */ - POWERPC_DEF("Max", CPU_POWERPC_7400, 7400), + POWERPC_DEF("Max", CPU_POWERPC_7400, 7400), /* PowerPC 74xx is also well known as G4 */ - POWERPC_DEF("G4", CPU_POWERPC_7400, 7400), + POWERPC_DEF("G4", CPU_POWERPC_7400, 7400), /* PowerPC 7400 v1.0 (G4) */ - POWERPC_DEF("7400v1.0", CPU_POWERPC_7400_v10, 7400), + POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400), /* PowerPC 7400 v1.1 (G4) */ - POWERPC_DEF("7400v1.1", CPU_POWERPC_7400_v11, 7400), + POWERPC_DEF("7400_v1.1", CPU_POWERPC_7400_v11, 7400), /* PowerPC 7400 v2.0 (G4) */ - POWERPC_DEF("7400v2.0", CPU_POWERPC_7400_v20, 7400), + POWERPC_DEF("7400_v2.0", CPU_POWERPC_7400_v20, 7400), /* PowerPC 7400 v2.2 (G4) */ - POWERPC_DEF("7400v2.2", CPU_POWERPC_7400_v22, 7400), + POWERPC_DEF("7400_v2.2", CPU_POWERPC_7400_v22, 7400), /* PowerPC 7400 v2.6 (G4) */ - POWERPC_DEF("7400v2.6", CPU_POWERPC_7400_v26, 7400), + POWERPC_DEF("7400_v2.6", CPU_POWERPC_7400_v26, 7400), /* PowerPC 7400 v2.7 (G4) */ - POWERPC_DEF("7400v2.7", CPU_POWERPC_7400_v27, 7400), + POWERPC_DEF("7400_v2.7", CPU_POWERPC_7400_v27, 7400), /* PowerPC 7400 v2.8 (G4) */ - POWERPC_DEF("7400v2.8", CPU_POWERPC_7400_v28, 7400), + POWERPC_DEF("7400_v2.8", CPU_POWERPC_7400_v28, 7400), /* PowerPC 7400 v2.9 (G4) */ - POWERPC_DEF("7400v2.9", CPU_POWERPC_7400_v29, 7400), + POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400), /* PowerPC 7410 (G4) */ - POWERPC_DEF("7410", CPU_POWERPC_7410, 7410), + POWERPC_DEF("7410", CPU_POWERPC_7410, 7410), /* Code name for PowerPC 7410 */ - POWERPC_DEF("Nitro", CPU_POWERPC_7410, 7410), + POWERPC_DEF("Nitro", CPU_POWERPC_7410, 7410), /* PowerPC 7410 v1.0 (G4) */ - POWERPC_DEF("7410v1.0", CPU_POWERPC_7410_v10, 7410), + POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410), /* PowerPC 7410 v1.1 (G4) */ - POWERPC_DEF("7410v1.1", CPU_POWERPC_7410_v11, 7410), + POWERPC_DEF("7410_v1.1", CPU_POWERPC_7410_v11, 7410), /* PowerPC 7410 v1.2 (G4) */ - POWERPC_DEF("7410v1.2", CPU_POWERPC_7410_v12, 7410), + POWERPC_DEF("7410_v1.2", CPU_POWERPC_7410_v12, 7410), /* PowerPC 7410 v1.3 (G4) */ - POWERPC_DEF("7410v1.3", CPU_POWERPC_7410_v13, 7410), + POWERPC_DEF("7410_v1.3", CPU_POWERPC_7410_v13, 7410), /* PowerPC 7410 v1.4 (G4) */ - POWERPC_DEF("7410v1.4", CPU_POWERPC_7410_v14, 7410), + POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410), /* PowerPC 7448 (G4) */ - POWERPC_DEF("7448", CPU_POWERPC_7448, 7400), + POWERPC_DEF("7448", CPU_POWERPC_7448, 7400), /* PowerPC 7448 v1.0 (G4) */ - POWERPC_DEF("7448v1.0", CPU_POWERPC_7448_v10, 7400), + POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400), /* PowerPC 7448 v1.1 (G4) */ - POWERPC_DEF("7448v1.1", CPU_POWERPC_7448_v11, 7400), + POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7400), /* PowerPC 7448 v2.0 (G4) */ - POWERPC_DEF("7448v2.0", CPU_POWERPC_7448_v20, 7400), + POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400), /* PowerPC 7448 v2.1 (G4) */ - POWERPC_DEF("7448v2.1", CPU_POWERPC_7448_v21, 7400), + POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400), /* PowerPC 7450 (G4) */ - POWERPC_DEF("7450", CPU_POWERPC_7450, 7450), + POWERPC_DEF("7450", CPU_POWERPC_7450, 7450), /* Code name for PowerPC 7450 */ - POWERPC_DEF("Vger", CPU_POWERPC_7450, 7450), + POWERPC_DEF("Vger", CPU_POWERPC_7450, 7450), /* PowerPC 7450 v1.0 (G4) */ - POWERPC_DEF("7450v1.0", CPU_POWERPC_7450_v10, 7450), + POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450), /* PowerPC 7450 v1.1 (G4) */ - POWERPC_DEF("7450v1.1", CPU_POWERPC_7450_v11, 7450), + POWERPC_DEF("7450_v1.1", CPU_POWERPC_7450_v11, 7450), /* PowerPC 7450 v1.2 (G4) */ - POWERPC_DEF("7450v1.2", CPU_POWERPC_7450_v12, 7450), + POWERPC_DEF("7450_v1.2", CPU_POWERPC_7450_v12, 7450), /* PowerPC 7450 v2.0 (G4) */ - POWERPC_DEF("7450v2.0", CPU_POWERPC_7450_v20, 7450), + POWERPC_DEF("7450_v2.0", CPU_POWERPC_7450_v20, 7450), /* PowerPC 7450 v2.1 (G4) */ - POWERPC_DEF("7450v2.1", CPU_POWERPC_7450_v21, 7450), + POWERPC_DEF("7450_v2.1", CPU_POWERPC_7450_v21, 7450), /* PowerPC 7441 (G4) */ - POWERPC_DEF("7441", CPU_POWERPC_74x1, 7440), + POWERPC_DEF("7441", CPU_POWERPC_74x1, 7440), /* PowerPC 7451 (G4) */ - POWERPC_DEF("7451", CPU_POWERPC_74x1, 7450), + POWERPC_DEF("7451", CPU_POWERPC_74x1, 7450), /* PowerPC 7441g (G4) */ - POWERPC_DEF("7441g", CPU_POWERPC_74x1G, 7440), + POWERPC_DEF("7441g", CPU_POWERPC_74x1G, 7440), /* PowerPC 7451g (G4) */ - POWERPC_DEF("7451g", CPU_POWERPC_74x1G, 7450), + POWERPC_DEF("7451g", CPU_POWERPC_74x1G, 7450), /* PowerPC 7445 (G4) */ - POWERPC_DEF("7445", CPU_POWERPC_74x5, 7445), + POWERPC_DEF("7445", CPU_POWERPC_74x5, 7445), /* PowerPC 7455 (G4) */ - POWERPC_DEF("7455", CPU_POWERPC_74x5, 7455), + POWERPC_DEF("7455", CPU_POWERPC_74x5, 7455), /* Code name for PowerPC 7445/7455 */ - POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 7455), + POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 7455), /* PowerPC 7445 v1.0 (G4) */ - POWERPC_DEF("7445v1.0", CPU_POWERPC_74x5_v10, 7445), + POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445), /* PowerPC 7455 v1.0 (G4) */ - POWERPC_DEF("7455v1.0", CPU_POWERPC_74x5_v10, 7455), + POWERPC_DEF("7455_v1.0", CPU_POWERPC_74x5_v10, 7455), /* PowerPC 7445 v2.1 (G4) */ - POWERPC_DEF("7445v2.1", CPU_POWERPC_74x5_v21, 7445), + POWERPC_DEF("7445_v2.1", CPU_POWERPC_74x5_v21, 7445), /* PowerPC 7455 v2.1 (G4) */ - POWERPC_DEF("7455v2.1", CPU_POWERPC_74x5_v21, 7455), + POWERPC_DEF("7455_v2.1", CPU_POWERPC_74x5_v21, 7455), /* PowerPC 7445 v3.2 (G4) */ - POWERPC_DEF("7445v3.2", CPU_POWERPC_74x5_v32, 7445), + POWERPC_DEF("7445_v3.2", CPU_POWERPC_74x5_v32, 7445), /* PowerPC 7455 v3.2 (G4) */ - POWERPC_DEF("7455v3.2", CPU_POWERPC_74x5_v32, 7455), + POWERPC_DEF("7455_v3.2", CPU_POWERPC_74x5_v32, 7455), /* PowerPC 7445 v3.3 (G4) */ - POWERPC_DEF("7445v3.3", CPU_POWERPC_74x5_v33, 7445), + POWERPC_DEF("7445_v3.3", CPU_POWERPC_74x5_v33, 7445), /* PowerPC 7455 v3.3 (G4) */ - POWERPC_DEF("7455v3.3", CPU_POWERPC_74x5_v33, 7455), + POWERPC_DEF("7455_v3.3", CPU_POWERPC_74x5_v33, 7455), /* PowerPC 7445 v3.4 (G4) */ - POWERPC_DEF("7445v3.4", CPU_POWERPC_74x5_v34, 7445), + POWERPC_DEF("7445_v3.4", CPU_POWERPC_74x5_v34, 7445), /* PowerPC 7455 v3.4 (G4) */ - POWERPC_DEF("7455v3.4", CPU_POWERPC_74x5_v34, 7455), + POWERPC_DEF("7455_v3.4", CPU_POWERPC_74x5_v34, 7455), /* PowerPC 7447 (G4) */ - POWERPC_DEF("7447", CPU_POWERPC_74x7, 7445), + POWERPC_DEF("7447", CPU_POWERPC_74x7, 7445), /* PowerPC 7457 (G4) */ - POWERPC_DEF("7457", CPU_POWERPC_74x7, 7455), + POWERPC_DEF("7457", CPU_POWERPC_74x7, 7455), /* Code name for PowerPC 7447/7457 */ - POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 7455), + POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 7455), /* PowerPC 7447 v1.0 (G4) */ - POWERPC_DEF("7447v1.0", CPU_POWERPC_74x7_v10, 7445), + POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445), /* PowerPC 7457 v1.0 (G4) */ - POWERPC_DEF("7457v1.0", CPU_POWERPC_74x7_v10, 7455), + POWERPC_DEF("7457_v1.0", CPU_POWERPC_74x7_v10, 7455), /* Code name for PowerPC 7447A/7457A */ - POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7_v10, 7455), + POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7_v10, 7455), /* PowerPC 7447 v1.1 (G4) */ - POWERPC_DEF("7447v1.1", CPU_POWERPC_74x7_v11, 7445), + POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445), /* PowerPC 7457 v1.1 (G4) */ - POWERPC_DEF("7457v1.1", CPU_POWERPC_74x7_v11, 7455), + POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455), /* PowerPC 7447 v1.2 (G4) */ - POWERPC_DEF("7447v1.2", CPU_POWERPC_74x7_v12, 7445), + POWERPC_DEF("7447_v1.2", CPU_POWERPC_74x7_v12, 7445), /* PowerPC 7457 v1.2 (G4) */ - POWERPC_DEF("7457v1.2", CPU_POWERPC_74x7_v12, 7455), + POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455), /* 64 bits PowerPC */ #if defined (TARGET_PPC64) /* PowerPC 620 */ /* XXX: code name "Trident" */ - POWERPC_DEF("620", CPU_POWERPC_620, 620), + POWERPC_DEF("620", CPU_POWERPC_620, 620), #if defined (TODO) /* PowerPC 630 (POWER3) */ /* XXX: code names: "Boxer" "Dino" */ - POWERPC_DEF("630", CPU_POWERPC_630, 630), - POWERPC_DEF("POWER3", CPU_POWERPC_630, 630), + POWERPC_DEF("630", CPU_POWERPC_630, 630), + POWERPC_DEF("POWER3", CPU_POWERPC_630, 630), #endif #if defined (TODO) /* PowerPC 631 (Power 3+) */ - POWERPC_DEF("631", CPU_POWERPC_631, 631), - POWERPC_DEF("POWER3+", CPU_POWERPC_631, 631), + POWERPC_DEF("631", CPU_POWERPC_631, 631), + POWERPC_DEF("POWER3+", CPU_POWERPC_631, 631), #endif #if defined (TODO) /* POWER4 */ - POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4), + POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4), #endif #if defined (TODO) /* POWER4p */ - POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P), + POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P), #endif #if defined (TODO) /* POWER5 */ - POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5), + POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5), /* POWER5GR */ - POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5), + POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5), #endif #if defined (TODO) /* POWER5+ */ - POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P), + POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P), /* POWER5GS */ - POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P), + POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P), #endif #if defined (TODO) /* POWER6 */ - POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6), + POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6), /* POWER6 running in POWER5 mode */ - POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5), + POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5), /* POWER6A */ - POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6), + POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6), #endif /* PowerPC 970 */ - POWERPC_DEF("970", CPU_POWERPC_970, 970), + POWERPC_DEF("970", CPU_POWERPC_970, 970), /* PowerPC 970FX (G5) */ - POWERPC_DEF("970fx", CPU_POWERPC_970FX, 970FX), + POWERPC_DEF("970fx", CPU_POWERPC_970FX, 970FX), /* PowerPC 970FX v1.0 (G5) */ - POWERPC_DEF("970fx1.0", CPU_POWERPC_970FX_v10, 970FX), + POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX), /* PowerPC 970FX v2.0 (G5) */ - POWERPC_DEF("970fx2.0", CPU_POWERPC_970FX_v20, 970FX), + POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX), /* PowerPC 970FX v2.1 (G5) */ - POWERPC_DEF("970fx2.1", CPU_POWERPC_970FX_v21, 970FX), + POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX), /* PowerPC 970FX v3.0 (G5) */ - POWERPC_DEF("970fx3.0", CPU_POWERPC_970FX_v30, 970FX), + POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX), /* PowerPC 970FX v3.1 (G5) */ - POWERPC_DEF("970fx3.1", CPU_POWERPC_970FX_v31, 970FX), + POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX), /* PowerPC 970GX (G5) */ - POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX), + POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX), /* PowerPC 970MP */ - POWERPC_DEF("970mp", CPU_POWERPC_970MP, 970MP), + POWERPC_DEF("970mp", CPU_POWERPC_970MP, 970MP), /* PowerPC 970MP v1.0 */ - POWERPC_DEF("970mp1.0", CPU_POWERPC_970MP_v10, 970MP), + POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP), /* PowerPC 970MP v1.1 */ - POWERPC_DEF("970mp1.1", CPU_POWERPC_970MP_v11, 970MP), + POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP), #if defined (TODO) /* PowerPC Cell */ - POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970), + POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970), #endif #if defined (TODO) /* PowerPC Cell v1.0 */ - POWERPC_DEF("Cell1.0", CPU_POWERPC_CELL_v10, 970), + POWERPC_DEF("Cell_v1.0", CPU_POWERPC_CELL_v10, 970), #endif #if defined (TODO) /* PowerPC Cell v2.0 */ - POWERPC_DEF("Cell2.0", CPU_POWERPC_CELL_v20, 970), + POWERPC_DEF("Cell_v2.0", CPU_POWERPC_CELL_v20, 970), #endif #if defined (TODO) /* PowerPC Cell v3.0 */ - POWERPC_DEF("Cell3.0", CPU_POWERPC_CELL_v30, 970), + POWERPC_DEF("Cell_v3.0", CPU_POWERPC_CELL_v30, 970), #endif #if defined (TODO) /* PowerPC Cell v3.1 */ - POWERPC_DEF("Cell3.1", CPU_POWERPC_CELL_v31, 970), + POWERPC_DEF("Cell_v3.1", CPU_POWERPC_CELL_v31, 970), #endif #if defined (TODO) /* PowerPC Cell v3.2 */ - POWERPC_DEF("Cell3.2", CPU_POWERPC_CELL_v32, 970), + POWERPC_DEF("Cell_v3.2", CPU_POWERPC_CELL_v32, 970), #endif #if defined (TODO) /* RS64 (Apache/A35) */ @@ -6130,59 +7709,57 @@ static const ppc_def_t ppc_defs[] = { * and the PowerPC 64 one. */ /* What about A10 & A30 ? */ - POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64), - POWERPC_DEF("Apache", CPU_POWERPC_RS64, RS64), - POWERPC_DEF("A35", CPU_POWERPC_RS64, RS64), + POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64), + POWERPC_DEF("Apache", CPU_POWERPC_RS64, RS64), + POWERPC_DEF("A35", CPU_POWERPC_RS64, RS64), #endif #if defined (TODO) /* RS64-II (NorthStar/A50) */ - POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64), - POWERPC_DEF("NorthStar", CPU_POWERPC_RS64II, RS64), - POWERPC_DEF("A50", CPU_POWERPC_RS64II, RS64), + POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64), + POWERPC_DEF("NorthStar", CPU_POWERPC_RS64II, RS64), + POWERPC_DEF("A50", CPU_POWERPC_RS64II, RS64), #endif #if defined (TODO) /* RS64-III (Pulsar) */ - POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64), - POWERPC_DEF("Pulsar", CPU_POWERPC_RS64III, RS64), + POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64), + POWERPC_DEF("Pulsar", CPU_POWERPC_RS64III, RS64), #endif #if defined (TODO) /* RS64-IV (IceStar/IStar/SStar) */ - POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64), - POWERPC_DEF("IceStar", CPU_POWERPC_RS64IV, RS64), - POWERPC_DEF("IStar", CPU_POWERPC_RS64IV, RS64), - POWERPC_DEF("SStar", CPU_POWERPC_RS64IV, RS64), + POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64), + POWERPC_DEF("IceStar", CPU_POWERPC_RS64IV, RS64), + POWERPC_DEF("IStar", CPU_POWERPC_RS64IV, RS64), + POWERPC_DEF("SStar", CPU_POWERPC_RS64IV, RS64), #endif #endif /* defined (TARGET_PPC64) */ /* POWER */ #if defined (TODO) /* Original POWER */ - POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER), - POWERPC_DEF("RIOS", CPU_POWERPC_POWER, POWER), - POWERPC_DEF("RSC", CPU_POWERPC_POWER, POWER), - POWERPC_DEF("RSC3308", CPU_POWERPC_POWER, POWER), - POWERPC_DEF("RSC4608", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("RIOS", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("RSC", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("RSC3308", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("RSC4608", CPU_POWERPC_POWER, POWER), #endif #if defined (TODO) /* POWER2 */ - POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER), - POWERPC_DEF("RSC2", CPU_POWERPC_POWER2, POWER), - POWERPC_DEF("P2SC", CPU_POWERPC_POWER2, POWER), + POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER), + POWERPC_DEF("RSC2", CPU_POWERPC_POWER2, POWER), + POWERPC_DEF("P2SC", CPU_POWERPC_POWER2, POWER), #endif /* PA semi cores */ #if defined (TODO) /* PA PA6T */ - POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T), + POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T), #endif /* Generic PowerPCs */ #if defined (TARGET_PPC64) -#if defined (TODO) - POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, PPC64), + POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, PPC64), #endif -#endif - POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, PPC32), - POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, DEFAULT), + POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, PPC32), + POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, DEFAULT), /* Fallback */ - POWERPC_DEF("default", CPU_POWERPC_DEFAULT, DEFAULT), + POWERPC_DEF("default", CPU_POWERPC_DEFAULT, DEFAULT), }; /*****************************************************************************/ @@ -6210,6 +7787,20 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, def->pvr); + /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */ + if (def->svr != POWERPC_SVR_NONE) { + if (def->svr & POWERPC_SVR_E500) { + spr_register(env, SPR_E500_SVR, "SVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + def->svr & ~POWERPC_SVR_E500); + } else { + spr_register(env, SPR_SVR, "SVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + def->svr); + } + } /* PowerPC implementation specific initialisations (SPRs, timers, ...) */ (*def->init_proc)(env); /* MSR bits & flags consistency checks */ -- cgit v1.2.3 From 4c1b1bfe30dab7bc08e3ff8f179f8e11be9d7f04 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 17 Nov 2007 23:14:53 +0000 Subject: Improve PowerPC instructions set dump. Remove meaningless define from cpu.h Misc cleanups. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3682 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 1 - target-ppc/translate_init.c | 50 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index a905cc375..3b53476a6 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -434,7 +434,6 @@ union ppc_tlb_t { #if defined(PPC_EMULATE_32BITS_HYPV) #define MSR_HVB (1ULL << MSR_THV) #define msr_hv msr_thv -#define #else #define MSR_HVB (0ULL) #define msr_hv (0) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 0878be2eb..79d227bd2 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -45,7 +45,7 @@ struct ppc_def_t { uint32_t flags; int bfd_mach; void (*init_proc)(CPUPPCState *env); - int (*check_pow)(CPUPPCState *env); + int (*check_pow)(CPUPPCState *env); }; /* For user-mode emulation, we don't emulate any IRQ controller */ @@ -3837,7 +3837,6 @@ static void init_proc_G2LE (CPUPPCState *env) POWERPC_FLAG_UBLE | POWERPC_FLAG_DE) #define check_pow_e200 check_pow_hid0 - __attribute__ (( unused )) static void init_proc_e200 (CPUPPCState *env) { @@ -8007,6 +8006,10 @@ static int register_direct_insn (opc_handler_t **ppc_opcodes, if (insert_in_table(ppc_opcodes, idx, handler) < 0) { printf("*** ERROR: opcode %02x already assigned in main " "opcode table\n", idx); +#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) + printf(" Registered handler '%s' - new handler '%s'\n", + ppc_opcodes[idx]->oname, handler->oname); +#endif return -1; } @@ -8027,6 +8030,10 @@ static int register_ind_in_table (opc_handler_t **table, if (!is_indirect_opcode(table[idx1])) { printf("*** ERROR: idx %02x already assigned to a direct " "opcode\n", idx1); +#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) + printf(" Registered handler '%s' - new handler '%s'\n", + ind_table(table[idx1])[idx2]->oname, handler->oname); +#endif return -1; } } @@ -8034,6 +8041,10 @@ static int register_ind_in_table (opc_handler_t **table, insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { printf("*** ERROR: opcode %02x already assigned in " "opcode table %02x\n", idx2, idx1); +#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) + printf(" Registered handler '%s' - new handler '%s'\n", + ind_table(table[idx1])[idx2]->oname, handler->oname); +#endif return -1; } @@ -8156,6 +8167,7 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) static void dump_ppc_insns (CPUPPCState *env) { opc_handler_t **table, *handler; + const unsigned char *p, *q; uint8_t opc1, opc2, opc3; printf("Instructions set:\n"); @@ -8176,9 +8188,35 @@ static void dump_ppc_insns (CPUPPCState *env) for (opc3 = 0; opc3 < 0x20; opc3++) { handler = table[opc3]; if (handler->handler != &gen_invalid) { - printf("INSN: %02x %02x %02x (%02d %04d) : %s\n", - opc1, opc2, opc3, opc1, (opc3 << 5) | opc2, - handler->oname); + /* Special hack to properly dump SPE insns */ + p = strchr(handler->oname, '_'); + if (p == NULL) { + printf("INSN: %02x %02x %02x (%02d %04d) : " + "%s\n", + opc1, opc2, opc3, opc1, + (opc3 << 5) | opc2, + handler->oname); + } else { + q = "speundef"; + if ((p - handler->oname) != strlen(q) || + memcmp(handler->oname, q, strlen(q)) != 0) { + /* First instruction */ + printf("INSN: %02x %02x %02x (%02d %04d) : " + "%.*s\n", + opc1, opc2 << 1, opc3, opc1, + (opc3 << 6) | (opc2 << 1), + (int)(p - handler->oname), + handler->oname); + } + if (strcmp(p + 1, q) != 0) { + /* Second instruction */ + printf("INSN: %02x %02x %02x (%02d %04d) : " + "%s\n", + opc1, (opc2 << 1) | 1, opc3, opc1, + (opc3 << 6) | (opc2 << 1) | 1, + p + 1); + } + } } } } else { @@ -8393,7 +8431,7 @@ static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr) match = clz32(pvr_rev ^ (ppc_defs[i].pvr & 0xFFFF)); /* We check '>=' instead of '>' because the PPC_defs table * is ordered by increasing revision. - * Then, we will match the higher revision compatible + * Then, we will match the higher revision compatible * with the requested PVR */ if (match >= best_match) { -- cgit v1.2.3 From 9596ebb7012a19a45ca036a200acd617a93a321b Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Nov 2007 01:44:38 +0000 Subject: Add statics and missing #includes for prototypes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3683 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/audio.c | 5 +++-- block-vvfat.c | 6 +++--- block.c | 2 +- console.c | 4 ++-- dyngen.c | 4 ++-- elf_ops.h | 6 +++--- hw/arm_sysctl.c | 2 +- hw/arm_timer.c | 4 ++-- hw/gt64xxx.c | 2 +- hw/i8259.c | 2 +- hw/ide.c | 1 + hw/mc146818rtc.c | 20 ++++++++++---------- hw/mcf_fec.c | 2 +- hw/mips_malta.c | 4 ++-- hw/ne2000.c | 1 + hw/nvram.h | 1 + hw/omap.c | 18 +++++++++--------- hw/omap.h | 3 +++ hw/omap_lcdc.c | 8 ++++---- hw/parallel.c | 18 +++++++++--------- hw/pc.c | 8 ++++---- hw/pci.c | 6 +++--- hw/pckbd.c | 6 +++--- hw/piix_pci.c | 2 +- hw/pl061.c | 2 +- hw/pl190.c | 2 +- hw/pxa2xx_lcd.c | 2 +- hw/pxa2xx_pcmcia.c | 1 + hw/realview_gic.c | 2 +- hw/rtl8139.c | 11 ++++++----- hw/sd.c | 8 ++++---- hw/sh_serial.c | 6 +++--- hw/sh_timer.c | 2 +- hw/smbus.c | 2 +- hw/stellaris.c | 2 +- hw/usb-ohci.c | 1 + hw/wm8750.c | 6 +++--- i386-dis.c | 23 ----------------------- loader.c | 1 + monitor.c | 4 ++-- osdep.c | 4 ++-- qemu-char.h | 1 + target-i386/helper.c | 4 ++-- translate-op.c | 3 +++ usb-linux.c | 8 ++++---- vl.c | 39 +++++++++++++++++++-------------------- vnc.c | 12 ++++++------ x_keymap.c | 1 + 48 files changed, 137 insertions(+), 145 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 2521c6f49..5e9d88bb1 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -238,7 +238,7 @@ static char *audio_alloc_prefix (const char *s) return r; } -const char *audio_audfmt_to_string (audfmt_e fmt) +static const char *audio_audfmt_to_string (audfmt_e fmt) { switch (fmt) { case AUD_FMT_U8: @@ -264,7 +264,8 @@ const char *audio_audfmt_to_string (audfmt_e fmt) return "S16"; } -audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp) +static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, + int *defaultp) { if (!strcasecmp (s, "u8")) { *defaultp = 0; diff --git a/block-vvfat.c b/block-vvfat.c index 43004e534..770b2ab8c 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -175,7 +175,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun return 0; } -inline int array_remove_slice(array_t* array,int index, int count) +static inline int array_remove_slice(array_t* array,int index, int count) { assert(index >=0); assert(count > 0); @@ -186,13 +186,13 @@ inline int array_remove_slice(array_t* array,int index, int count) return 0; } -int array_remove(array_t* array,int index) +static 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) +static int array_index(array_t* array, void* pointer) { size_t offset = (char*)pointer - array->pointer; assert(offset >= 0); diff --git a/block.c b/block.c index b09ded319..ca8d8c1e8 100644 --- a/block.c +++ b/block.c @@ -124,7 +124,7 @@ void path_combine(char *dest, int dest_size, } -void bdrv_register(BlockDriver *bdrv) +static void bdrv_register(BlockDriver *bdrv) { if (!bdrv->bdrv_aio_read) { /* add AIO emulation layer */ diff --git a/console.c b/console.c index 9778845b7..e7c00eccb 100644 --- a/console.c +++ b/console.c @@ -61,7 +61,7 @@ typedef struct QEMUFIFO { int count, wptr, rptr; } QEMUFIFO; -int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) +static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) { int l, len; @@ -84,7 +84,7 @@ int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) return len1; } -int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) +static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) { int l, len; diff --git a/dyngen.c b/dyngen.c index 562fd0def..eb94273ab 100644 --- a/dyngen.c +++ b/dyngen.c @@ -232,7 +232,7 @@ enum { int do_swap; -void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...) +static void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -243,7 +243,7 @@ void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(cons exit(1); } -void *load_data(int fd, long offset, unsigned int size) +static void *load_data(int fd, long offset, unsigned int size) { char *data; diff --git a/elf_ops.h b/elf_ops.h index 646a569b2..61265650e 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -138,9 +138,9 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) return -1; } -int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, - int must_swab, uint64_t *pentry, - uint64_t *lowaddr, uint64_t *highaddr) +static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, + int must_swab, uint64_t *pentry, + uint64_t *lowaddr, uint64_t *highaddr) { struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index e1d5a56c0..67ca154a3 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -8,7 +8,7 @@ */ #include "hw.h" -#include "arm-misc.h" +#include "primecell.h" #include "sysemu.h" #define LOCK_VALUE 0xa05f diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 417d53db8..540d3dea1 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -8,8 +8,8 @@ */ #include "hw.h" -#include "arm-misc.h" #include "qemu-timer.h" +#include "primecell.h" /* Common timer implementation. */ @@ -43,7 +43,7 @@ static void arm_timer_update(arm_timer_state *s) } } -uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) +static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) { arm_timer_state *s = (arm_timer_state *)opaque; diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 07f046a92..46d6a762d 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -908,7 +908,7 @@ static void pci_gt64120_set_irq(qemu_irq *pic, int irq_num, int level) } -void gt64120_reset(void *opaque) +static void gt64120_reset(void *opaque) { GT64120State *s = opaque; diff --git a/hw/i8259.c b/hw/i8259.c index 23e66a804..add63450f 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -178,7 +178,7 @@ void pic_update_irq(PicState2 *s) int64_t irq_time[16]; #endif -void i8259_set_irq(void *opaque, int irq, int level) +static void i8259_set_irq(void *opaque, int irq, int level) { PicState2 *s = opaque; diff --git a/hw/ide.c b/hw/ide.c index 575605b95..bf2cc14f4 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -30,6 +30,7 @@ #include "block.h" #include "qemu-timer.h" #include "sysemu.h" +#include "ppc_mac.h" /* debug IDE devices */ //#define DEBUG_IDE diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 8c8076b26..c1d595677 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -390,7 +390,7 @@ void rtc_set_date(RTCState *s, const struct tm *tm) #define REG_IBM_CENTURY_BYTE 0x32 #define REG_IBM_PS2_CENTURY_BYTE 0x37 -void rtc_set_date_from_host(RTCState *s) +static void rtc_set_date_from_host(RTCState *s) { time_t ti; struct tm *tm; @@ -498,22 +498,22 @@ RTCState *rtc_init(int base, qemu_irq irq) } /* Memory mapped interface */ -uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr) +static uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr) { RTCState *s = opaque; return cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF; } -void cmos_mm_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) +static void cmos_mm_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) { RTCState *s = opaque; cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF); } -uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr) +static uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr) { RTCState *s = opaque; uint32_t val; @@ -525,8 +525,8 @@ uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr) return val; } -void cmos_mm_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) +static void cmos_mm_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) { RTCState *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN @@ -535,7 +535,7 @@ void cmos_mm_writew (void *opaque, cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF); } -uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr) +static uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr) { RTCState *s = opaque; uint32_t val; @@ -547,8 +547,8 @@ uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr) return val; } -void cmos_mm_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) +static void cmos_mm_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) { RTCState *s = opaque; #ifdef TARGET_WORDS_BIGENDIAN diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index c5482c9e1..0049860da 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -251,7 +251,7 @@ static uint32_t mcf_fec_read(void *opaque, target_phys_addr_t addr) } } -void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value) +static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value) { mcf_fec_state *s = (mcf_fec_state *)opaque; switch (addr & 0x3ff) { diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 9ce8232fd..f133da3e3 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -398,7 +398,7 @@ static CPUWriteMemoryFunc *malta_fpga_write[] = { malta_fpga_writel }; -void malta_fpga_reset(void *opaque) +static void malta_fpga_reset(void *opaque) { MaltaFPGAState *s = opaque; @@ -415,7 +415,7 @@ void malta_fpga_reset(void *opaque) malta_fpga_update_display(s); } -MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env) +static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env) { MaltaFPGAState *s; CharDriverState *uart_chr; diff --git a/hw/ne2000.c b/hw/ne2000.c index 92023eb71..e95f537c9 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -23,6 +23,7 @@ */ #include "hw.h" #include "pci.h" +#include "pc.h" #include "net.h" /* debug NE2000 card */ diff --git a/hw/nvram.h b/hw/nvram.h index 174704bf6..3ec548302 100644 --- a/hw/nvram.h +++ b/hw/nvram.h @@ -37,5 +37,6 @@ void m48t59_toggle_lock (void *private, int lock); m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, uint32_t io_base, uint16_t size, int type); +void m48t59_set_addr (void *opaque, uint32_t addr); #endif /* !NVRAM_H */ diff --git a/hw/omap.c b/hw/omap.c index 88055edd9..1e79831d8 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -3041,7 +3041,7 @@ static CPUWriteMemoryFunc *omap_mpuio_writefn[] = { omap_badwidth_write16, }; -void omap_mpuio_reset(struct omap_mpuio_s *s) +static void omap_mpuio_reset(struct omap_mpuio_s *s) { s->inputs = 0; s->outputs = 0; @@ -3257,7 +3257,7 @@ static CPUWriteMemoryFunc *omap_gpio_writefn[] = { omap_badwidth_write16, }; -void omap_gpio_reset(struct omap_gpio_s *s) +static void omap_gpio_reset(struct omap_gpio_s *s) { s->inputs = 0; s->outputs = ~0; @@ -3429,7 +3429,7 @@ static CPUWriteMemoryFunc *omap_uwire_writefn[] = { omap_badwidth_write16, }; -void omap_uwire_reset(struct omap_uwire_s *s) +static void omap_uwire_reset(struct omap_uwire_s *s) { s->control = 0; s->setup[0] = 0; @@ -3470,7 +3470,7 @@ void omap_uwire_attach(struct omap_uwire_s *s, } /* Pseudonoise Pulse-Width Light Modulator */ -void omap_pwl_update(struct omap_mpu_state_s *s) +static void omap_pwl_update(struct omap_mpu_state_s *s) { int output = (s->pwl.clk && s->pwl.enable) ? s->pwl.level : 0; @@ -3528,7 +3528,7 @@ static CPUWriteMemoryFunc *omap_pwl_writefn[] = { omap_badwidth_write8, }; -void omap_pwl_reset(struct omap_mpu_state_s *s) +static void omap_pwl_reset(struct omap_mpu_state_s *s) { s->pwl.output = 0; s->pwl.level = 0; @@ -3632,7 +3632,7 @@ static CPUWriteMemoryFunc *omap_pwt_writefn[] = { omap_badwidth_write8, }; -void omap_pwt_reset(struct omap_mpu_state_s *s) +static void omap_pwt_reset(struct omap_mpu_state_s *s) { s->pwt.frc = 0; s->pwt.vrc = 0; @@ -4037,7 +4037,7 @@ static void omap_rtc_tick(void *opaque) qemu_mod_timer(s->clk, s->tick); } -void omap_rtc_reset(struct omap_rtc_s *s) +static void omap_rtc_reset(struct omap_rtc_s *s) { s->interrupts = 0; s->comp_reg = 0; @@ -4509,14 +4509,14 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, return s; } -void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) +static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; omap_mcbsp_rx_start(s); } -void omap_mcbsp_i2s_start(void *opaque, int line, int level) +static void omap_mcbsp_i2s_start(void *opaque, int line, int level) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; diff --git a/hw/omap.h b/hw/omap.h index bf87fa46d..c31503094 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -662,6 +662,9 @@ struct omap_mpu_state_s { # error TARGET_PHYS_ADDR_BITS undefined # endif +uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr); +void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, + uint32_t value); uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr); void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, uint32_t value); diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index c6565d1db..c79d244c1 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -114,7 +114,7 @@ static draw_line_func *draw_line_table2[33] = { [32] = draw_line16_32, }; -void omap_update_display(void *opaque) +static void omap_update_display(void *opaque) { struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; draw_line_func *draw_line; @@ -289,7 +289,7 @@ static int ppm_save(const char *filename, uint8_t *data, return 0; } -void omap_screen_dump(void *opaque, const char *filename) { +static void omap_screen_dump(void *opaque, const char *filename) { struct omap_lcd_panel_s *omap_lcd = opaque; omap_update_display(opaque); if (omap_lcd && omap_lcd->state->data) @@ -298,12 +298,12 @@ void omap_screen_dump(void *opaque, const char *filename) { omap_lcd->state->linesize); } -void omap_invalidate_display(void *opaque) { +static void omap_invalidate_display(void *opaque) { struct omap_lcd_panel_s *omap_lcd = opaque; omap_lcd->invalidate = 1; } -void omap_lcd_update(struct omap_lcd_panel_s *s) { +static void omap_lcd_update(struct omap_lcd_panel_s *s) { if (!s->enable) { s->dma->current_frame = -1; s->sync_error = 0; diff --git a/hw/parallel.c b/hw/parallel.c index dfcd5c2c3..5d99e7655 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -458,45 +458,45 @@ ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr) } /* Memory mapped interface */ -uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr) +static uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr) { ParallelState *s = opaque; return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift) & 0xFF; } -void parallel_mm_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) +static void parallel_mm_writeb (void *opaque, + target_phys_addr_t addr, uint32_t value) { ParallelState *s = opaque; parallel_ioport_write_sw(s, (addr - s->base) >> s->it_shift, value & 0xFF); } -uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr) +static uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr) { ParallelState *s = opaque; return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift) & 0xFFFF; } -void parallel_mm_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) +static void parallel_mm_writew (void *opaque, + target_phys_addr_t addr, uint32_t value) { ParallelState *s = opaque; parallel_ioport_write_sw(s, (addr - s->base) >> s->it_shift, value & 0xFFFF); } -uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr) +static uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr) { ParallelState *s = opaque; return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift); } -void parallel_mm_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) +static void parallel_mm_writel (void *opaque, + target_phys_addr_t addr, uint32_t value) { ParallelState *s = opaque; diff --git a/hw/pc.c b/hw/pc.c index 99bb90646..69eeadb68 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -317,7 +317,7 @@ static uint32_t ioport92_read(void *opaque, uint32_t addr) /***********************************************************/ /* Bochs BIOS debug ports */ -void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) +static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) { static const char shutdown_str[8] = "Shutdown"; static int shutdown_index = 0; @@ -361,7 +361,7 @@ void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) } } -void bochs_bios_init(void) +static void bochs_bios_init(void) { register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL); register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); @@ -431,8 +431,8 @@ static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); } -int load_kernel(const char *filename, uint8_t *addr, - uint8_t *real_addr) +static int load_kernel(const char *filename, uint8_t *addr, + uint8_t *real_addr) { int fd, size; int setup_sects; diff --git a/hw/pci.c b/hw/pci.c index c43be3e81..0b5e7bf34 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -65,7 +65,7 @@ PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, return bus; } -PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq) +static PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq) { PCIBus *bus; bus = qemu_mallocz(sizeof(PCIBus)); @@ -159,7 +159,7 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); } -target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr) +static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr) { return addr + pci_mem_base; } @@ -606,7 +606,7 @@ typedef struct { PCIBus *bus; } PCIBridge; -void pci_bridge_write_config(PCIDevice *d, +static void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { PCIBridge *s = (PCIBridge *)d; diff --git a/hw/pckbd.c b/hw/pckbd.c index 738ce61d6..266c7f9b1 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -290,7 +290,7 @@ static uint32_t kbd_read_data(void *opaque, uint32_t addr) return ps2_read_data(s->kbd); } -void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) +static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) { KBDState *s = opaque; @@ -385,7 +385,7 @@ void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base) } /* Memory mapped interface */ -uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr) +static uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr) { KBDState *s = opaque; @@ -399,7 +399,7 @@ uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr) } } -void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +static void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { KBDState *s = opaque; diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 75f412a91..37352c430 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -314,7 +314,7 @@ static int piix_load(QEMUFile* f, void *opaque, int version_id) return pci_device_load(d, f); } -int piix_init(PCIBus *bus, int devfn) +static int piix_init(PCIBus *bus, int devfn) { PCIDevice *d; uint8_t *pci_conf; diff --git a/hw/pl061.c b/hw/pl061.c index 791427252..d9a6f50f8 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -209,7 +209,7 @@ static void pl061_reset(pl061_state *s) s->cr = 0xff; } -void pl061_set_irq(void * opaque, int irq, int level) +static void pl061_set_irq(void * opaque, int irq, int level) { pl061_state *s = (pl061_state *)opaque; uint8_t mask; diff --git a/hw/pl190.c b/hw/pl190.c index abc28468e..fc3d08984 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -216,7 +216,7 @@ static CPUWriteMemoryFunc *pl190_writefn[] = { pl190_write }; -void pl190_reset(pl190_state *s) +static void pl190_reset(pl190_state *s) { int i; diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 56328e9f4..585543530 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -882,7 +882,7 @@ static void pxa2xx_screen_dump(void *opaque, const char *filename) /* TODO */ } -void pxa2xx_lcdc_orientation(void *opaque, int angle) +static void pxa2xx_lcdc_orientation(void *opaque, int angle) { struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque; diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index f5d805a7c..1e96ee44b 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -9,6 +9,7 @@ #include "hw.h" #include "pcmcia.h" +#include "pxa.h" struct pxa2xx_pcmcia_s { struct pcmcia_socket_s slot; diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 639db846b..b4ef2ccf3 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -8,7 +8,7 @@ */ #include "hw.h" -#include "arm-misc.h" +#include "primecell.h" #define GIC_NIRQ 96 #define NCPU 1 diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 868cbbae8..6e3c023b3 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -497,7 +497,7 @@ typedef struct RTL8139State { } RTL8139State; -void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) +static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) { DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command)); @@ -543,7 +543,7 @@ void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) } } -void prom9346_shift_clock(EEprom9346 *eeprom) +static void prom9346_shift_clock(EEprom9346 *eeprom) { int bit = eeprom->eedi?1:0; @@ -635,7 +635,7 @@ void prom9346_shift_clock(EEprom9346 *eeprom) } } -int prom9346_get_wire(RTL8139State *s) +static int prom9346_get_wire(RTL8139State *s) { EEprom9346 *eeprom = &s->eeprom; if (!eeprom->eecs) @@ -644,7 +644,8 @@ int prom9346_get_wire(RTL8139State *s) return eeprom->eedo; } -void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) +/* FIXME: This should be merged into/replaced by eeprom93xx.c. */ +static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) { EEprom9346 *eeprom = &s->eeprom; uint8_t old_eecs = eeprom->eecs; @@ -1448,7 +1449,7 @@ static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s) return ret; } -int rtl8139_config_writeable(RTL8139State *s) +static int rtl8139_config_writeable(RTL8139State *s) { if (s->Cfg9346 & Cfg9346_Unlock) { diff --git a/hw/sd.c b/hw/sd.c index 9dd86e357..8b481e6f0 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -308,8 +308,8 @@ static int sd_req_crc_validate(struct sd_request_s *req) return sd_crc7(buffer, 5) != req->crc; /* TODO */ } -void sd_response_r1_make(SDState *sd, - uint8_t *response, uint32_t last_status) +static void sd_response_r1_make(SDState *sd, + uint8_t *response, uint32_t last_status) { uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND; uint32_t status; @@ -323,7 +323,7 @@ void sd_response_r1_make(SDState *sd, response[3] = (status >> 0) & 0xff; } -void sd_response_r3_make(SDState *sd, uint8_t *response) +static void sd_response_r3_make(SDState *sd, uint8_t *response) { response[0] = (sd->ocr >> 24) & 0xff; response[1] = (sd->ocr >> 16) & 0xff; @@ -331,7 +331,7 @@ void sd_response_r3_make(SDState *sd, uint8_t *response) response[3] = (sd->ocr >> 0) & 0xff; } -void sd_response_r6_make(SDState *sd, uint8_t *response) +static void sd_response_r6_make(SDState *sd, uint8_t *response) { uint16_t arg; uint16_t status; diff --git a/hw/sh_serial.c b/hw/sh_serial.c index 1336780d1..324c2a8fb 100644 --- a/hw/sh_serial.c +++ b/hw/sh_serial.c @@ -252,14 +252,14 @@ static void sh_serial_event(void *opaque, int event) sh_serial_receive_break(s); } -uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr) +static uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr) { sh_serial_state *s = opaque; return sh_serial_ioport_read(s, addr - s->base); } -void sh_serial_write (void *opaque, - target_phys_addr_t addr, uint32_t value) +static void sh_serial_write (void *opaque, + target_phys_addr_t addr, uint32_t value) { sh_serial_state *s = opaque; sh_serial_ioport_write(s, addr - s->base, value); diff --git a/hw/sh_timer.c b/hw/sh_timer.c index 6be895300..2247929c2 100644 --- a/hw/sh_timer.c +++ b/hw/sh_timer.c @@ -52,7 +52,7 @@ static void sh_timer_update(sh_timer_state *s) #endif } -uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) +static uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) { sh_timer_state *s = (sh_timer_state *)opaque; diff --git a/hw/smbus.c b/hw/smbus.c index 81e887b2a..6eb841240 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -61,7 +61,7 @@ static void smbus_do_write(SMBusDevice *dev) } } -void smbus_i2c_event(i2c_slave *s, enum i2c_event event) +static void smbus_i2c_event(i2c_slave *s, enum i2c_event event) { SMBusDevice *dev = (SMBusDevice *)s; switch (event) { diff --git a/hw/stellaris.c b/hw/stellaris.c index cc47b9dbc..0bd76ab22 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -521,7 +521,7 @@ static CPUWriteMemoryFunc *ssys_writefn[] = { ssys_write }; -void ssys_reset(void *opaque) +static void ssys_reset(void *opaque) { ssys_state *s = (ssys_state *)opaque; diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 255cba7c9..68995b070 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -31,6 +31,7 @@ #include "qemu-timer.h" #include "usb.h" #include "pci.h" +#include "pxa.h" //#define DEBUG_OHCI /* Dump packet contents. */ diff --git a/hw/wm8750.c b/hw/wm8750.c index 245d56fb0..8243ca54b 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -124,7 +124,7 @@ static const struct wm_rate_s wm_rate_table[] = { { 192, 88200, 128, 88200 }, /* SR: 11111 */ }; -void wm8750_set_format(struct wm8750_s *s) +static void wm8750_set_format(struct wm8750_s *s) { int i; audsettings_t in_fmt; @@ -194,7 +194,7 @@ void wm8750_set_format(struct wm8750_s *s) AUD_set_active_out(*s->out[0], 1); } -void inline wm8750_mask_update(struct wm8750_s *s) +static void inline wm8750_mask_update(struct wm8750_s *s) { #define R_ONLY 0x0000ffff #define L_ONLY 0xffff0000 @@ -596,7 +596,7 @@ i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio) return &s->i2c; } -void wm8750_fini(i2c_slave *i2c) +static void wm8750_fini(i2c_slave *i2c) { struct wm8750_s *s = (struct wm8750_s *) i2c; wm8750_reset(&s->i2c); diff --git a/i386-dis.c b/i386-dis.c index 0496e141d..145e14e71 100644 --- a/i386-dis.c +++ b/i386-dis.c @@ -1838,29 +1838,6 @@ static char close_char; static char separator_char; static char scale_char; -/* Here for backwards compatibility. When gdb stops using - print_insn_i386_att and print_insn_i386_intel these functions can - disappear, and print_insn_i386 be merged into print_insn. */ -int -print_insn_i386_att (pc, info) - bfd_vma pc; - disassemble_info *info; -{ - intel_syntax = 0; - - return print_insn (pc, info); -} - -int -print_insn_i386_intel (pc, info) - bfd_vma pc; - disassemble_info *info; -{ - intel_syntax = 1; - - return print_insn (pc, info); -} - int print_insn_i386 (pc, info) bfd_vma pc; diff --git a/loader.c b/loader.c index 18878df8e..062dee401 100644 --- a/loader.c +++ b/loader.c @@ -23,6 +23,7 @@ */ #include "qemu-common.h" #include "disas.h" +#include "sysemu.h" #include "uboot_image.h" /* return the size or -1 if error */ diff --git a/monitor.c b/monitor.c index 76ed5f8cf..4a9e8bbfa 100644 --- a/monitor.c +++ b/monitor.c @@ -261,7 +261,7 @@ static void do_info_block(void) } /* get the current CPU defined by the user */ -int mon_set_cpu(int cpu_index) +static int mon_set_cpu(int cpu_index) { CPUState *env; @@ -274,7 +274,7 @@ int mon_set_cpu(int cpu_index) return -1; } -CPUState *mon_get_cpu(void) +static CPUState *mon_get_cpu(void) { if (!mon_cpu) { mon_set_cpu(0); diff --git a/osdep.c b/osdep.c index 8c2f0a9ec..00c19ce6e 100644 --- a/osdep.c +++ b/osdep.c @@ -82,7 +82,7 @@ void qemu_vfree(void *ptr) #include #include -void *kqemu_vmalloc(size_t size) +static void *kqemu_vmalloc(size_t size) { static int phys_ram_fd = -1; static int phys_ram_size = 0; @@ -164,7 +164,7 @@ void *kqemu_vmalloc(size_t size) return ptr; } -void kqemu_vfree(void *ptr) +static void kqemu_vfree(void *ptr) { /* may be useful some day, but currently we do not need to free */ } diff --git a/qemu-char.h b/qemu-char.h index 3f482106e..5a36a3683 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -46,6 +46,7 @@ struct CharDriverState { }; CharDriverState *qemu_chr_open(const char *filename); +void qemu_chr_close(CharDriverState *chr); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); void qemu_chr_send_event(CharDriverState *s, int event); diff --git a/target-i386/helper.c b/target-i386/helper.c index 841824fc9..a2f465c73 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1235,7 +1235,7 @@ void do_interrupt(int intno, int is_int, int error_code, * needed. It should only be called, if this is not an interrupt. * Returns the new exception number. */ -int check_exception(int intno, int *error_code) +static int check_exception(int intno, int *error_code) { char first_contributory = env->old_exception == 0 || (env->old_exception >= 10 && @@ -3051,7 +3051,7 @@ void helper_fstt_ST0_A0(void) helper_fstt(ST0, A0); } -void fpu_set_exception(int mask) +static void fpu_set_exception(int mask) { env->fpus |= mask; if (env->fpus & (~env->fpuc & FPUC_EM)) diff --git a/translate-op.c b/translate-op.c index 37c61e1b7..b21a52250 100644 --- a/translate-op.c +++ b/translate-op.c @@ -33,5 +33,8 @@ enum { }; #include "dyngen.h" +extern int dyngen_code(uint8_t *gen_code_buf, + uint16_t *label_offsets, uint16_t *jmp_offsets, + const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels); #include "op.h" diff --git a/usb-linux.c b/usb-linux.c index d6a2b8b6a..d3e4e2ef4 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -907,10 +907,10 @@ static const char *usb_class_str(uint8_t class) return p->class_name; } -void usb_info_device(int bus_num, int addr, int class_id, - int vendor_id, int product_id, - const char *product_name, - int speed) +static void usb_info_device(int bus_num, int addr, int class_id, + int vendor_id, int product_id, + const char *product_name, + int speed) { const char *class_str, *speed_str; diff --git a/vl.c b/vl.c index 783b3cf5a..b1e0cc725 100644 --- a/vl.c +++ b/vl.c @@ -242,7 +242,7 @@ const char *prom_envs[MAX_PROM_ENVS]; target_phys_addr_t isa_mem_base = 0; PicState2 *isa_pic; -uint32_t default_ioport_readb(void *opaque, uint32_t address) +static uint32_t default_ioport_readb(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "unused inb: port=0x%04x\n", address); @@ -250,7 +250,7 @@ uint32_t default_ioport_readb(void *opaque, uint32_t address) return 0xff; } -void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data) +static void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data); @@ -258,7 +258,7 @@ void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data) } /* default is to make two byte accesses */ -uint32_t default_ioport_readw(void *opaque, uint32_t address) +static uint32_t default_ioport_readw(void *opaque, uint32_t address) { uint32_t data; data = ioport_read_table[0][address](ioport_opaque[address], address); @@ -267,14 +267,14 @@ uint32_t default_ioport_readw(void *opaque, uint32_t address) return data; } -void default_ioport_writew(void *opaque, uint32_t address, uint32_t data) +static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data) { ioport_write_table[0][address](ioport_opaque[address], address, data & 0xff); address = (address + 1) & (MAX_IOPORTS - 1); ioport_write_table[0][address](ioport_opaque[address], address, (data >> 8) & 0xff); } -uint32_t default_ioport_readl(void *opaque, uint32_t address) +static uint32_t default_ioport_readl(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "unused inl: port=0x%04x\n", address); @@ -282,14 +282,14 @@ uint32_t default_ioport_readl(void *opaque, uint32_t address) return 0xffffffff; } -void default_ioport_writel(void *opaque, uint32_t address, uint32_t data) +static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data) { #ifdef DEBUG_UNUSED_IOPORT fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data); #endif } -void init_ioports(void) +static void init_ioports(void) { int i; @@ -961,7 +961,7 @@ QEMUClock *vm_clock; static QEMUTimer *active_timers[2]; -QEMUClock *qemu_new_clock(int type) +static QEMUClock *qemu_new_clock(int type) { QEMUClock *clock; clock = qemu_mallocz(sizeof(QEMUClock)); @@ -1539,7 +1539,7 @@ static void init_timer_alarm(void) alarm_timer = t; } -void quit_timers(void) +static void quit_timers(void) { alarm_timer->stop(alarm_timer); alarm_timer = NULL; @@ -1832,7 +1832,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr) d->mux_cnt++; } -CharDriverState *qemu_chr_open_mux(CharDriverState *drv) +static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) { CharDriverState *chr; MuxDriver *d; @@ -3385,7 +3385,7 @@ void qemu_chr_close(CharDriverState *chr) /***********************************************************/ /* network device redirectors */ -void hex_dump(FILE *f, const uint8_t *buf, int size) +static void hex_dump(FILE *f, const uint8_t *buf, int size) { int len, i, j, c; @@ -3733,7 +3733,7 @@ static void smb_exit(void) } /* automatic user mode samba server configuration */ -void net_slirp_smb(const char *exported_dir) +static void net_slirp_smb(const char *exported_dir) { char smb_conf[1024]; char smb_cmdline[1024]; @@ -5127,7 +5127,7 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode) return NULL; } -QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) +static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) { QEMUFile *f; @@ -5361,7 +5361,7 @@ int register_savevm(const char *idstr, #define QEMU_VM_FILE_MAGIC 0x5145564d #define QEMU_VM_FILE_VERSION 0x00000002 -int qemu_savevm_state(QEMUFile *f) +static int qemu_savevm_state(QEMUFile *f) { SaveStateEntry *se; int len, ret; @@ -5384,7 +5384,6 @@ int qemu_savevm_state(QEMUFile *f) /* record size: filled later */ len_pos = qemu_ftell(f); qemu_put_be32(f, 0); - se->save_state(f, se->opaque); /* fill record size */ @@ -5415,7 +5414,7 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id) return NULL; } -int qemu_loadvm_state(QEMUFile *f) +static int qemu_loadvm_state(QEMUFile *f) { SaveStateEntry *se; int len, ret, instance_id, record_len, version_id; @@ -6655,7 +6654,7 @@ int qemu_register_machine(QEMUMachine *m) return 0; } -QEMUMachine *find_machine(const char *name) +static QEMUMachine *find_machine(const char *name) { QEMUMachine *m; @@ -6669,7 +6668,7 @@ QEMUMachine *find_machine(const char *name) /***********************************************************/ /* main execution loop */ -void gui_update(void *opaque) +static void gui_update(void *opaque) { DisplayState *ds = opaque; ds->dpy_refresh(ds); @@ -6953,7 +6952,7 @@ void main_loop_wait(int timeout) static CPUState *cur_cpu; -int main_loop(void) +static int main_loop(void) { int ret, timeout; #ifdef CONFIG_PROFILER @@ -7414,7 +7413,7 @@ static void read_passwords(void) } /* XXX: currently we cannot use simultaneously different CPUs */ -void register_machines(void) +static void register_machines(void) { #if defined(TARGET_I386) qemu_register_machine(&pc_machine); diff --git a/vnc.c b/vnc.c index ec97ad9a0..fcce00edd 100644 --- a/vnc.c +++ b/vnc.c @@ -812,9 +812,9 @@ static uint32_t read_u32(uint8_t *data, size_t offset) } #if CONFIG_VNC_TLS -ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, - const void *data, - size_t len) { +static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, + const void *data, + size_t len) { struct VncState *vs = (struct VncState *)transport; int ret; @@ -829,9 +829,9 @@ ssize_t vnc_tls_push(gnutls_transport_ptr_t transport, } -ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, - void *data, - size_t len) { +static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, + void *data, + size_t len) { struct VncState *vs = (struct VncState *)transport; int ret; diff --git a/x_keymap.c b/x_keymap.c index 08cf95eb6..f000475e9 100644 --- a/x_keymap.c +++ b/x_keymap.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" +#include "console.h" static const uint8_t x_keycode_to_pc_keycode[115] = { 0xc7, /* 97 Home */ -- cgit v1.2.3 From 7317b8cad72b39bf06d1ce76e20a92c7ef157ba6 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 18 Nov 2007 02:09:36 +0000 Subject: Fix a && -> & typo. Catch wrong/unknown NOR flash command sequences, by Thorsten Zitterell. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3684 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pflash_cfi01.c | 7 ++++++- vl.c | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 065dd2c80..f50d7bae7 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -353,6 +353,8 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, pfl->counter--; break; + default: + goto error_flash; } return; case 3: /* Confirm mode */ @@ -361,11 +363,14 @@ static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, if (cmd == 0xd0) { pfl->wcycle = 0; pfl->status |= 0x80; - break; } else { DPRINTF("%s: unknown command for \"write block\"\n", __func__); PFLASH_BUG("Write block confirm"); + goto reset_flash; } + break; + default: + goto error_flash; } return; default: diff --git a/vl.c b/vl.c index b1e0cc725..e54afbfb2 100644 --- a/vl.c +++ b/vl.c @@ -8269,7 +8269,7 @@ int main(int argc, char **argv) kqemu_allowed = 0; #endif linux_boot = (kernel_filename != NULL); - net_boot = (boot_devices_bitmap >> ('n' - 'a')) && 0xF; + net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF; /* XXX: this should not be: some embedded targets just have flash */ if (!linux_boot && net_boot == 0 && -- cgit v1.2.3 From 8c89395eebc4c88e35949b3310254f0d893379c5 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Nov 2007 03:19:58 +0000 Subject: Use a valid PRid. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3685 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index d54e3b677..f6bda53fe 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -296,7 +296,7 @@ static mips_def_t mips_defs[] = /* A generic CPU providing MIPS64 Release 2 features. FIXME: Eventually this should be replaced by a real CPU model. */ .name = "MIPS64R2-generic", - .CP0_PRid = 0x00000000, + .CP0_PRid = 0x00010000, .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) | (0x1 << CP0C0_AR), .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) | (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) | -- cgit v1.2.3 From c6d6dd7c74aaf8ca156d4589adff060078ec20ef Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Nov 2007 03:36:07 +0000 Subject: Fix MIPS64 R2 instructions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3686 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/op.c | 29 ++++++++++++++--------------- target-mips/op_helper.c | 16 +++++++--------- target-mips/translate.c | 19 +++++++++++++------ 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/target-mips/op.c b/target-mips/op.c index 0ecc93081..ad619c9b4 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -683,8 +683,8 @@ void op_drotr (void) target_ulong tmp; if (T1) { - tmp = T0 << (0x40 - T1); - T0 = (T0 >> T1) | tmp; + tmp = T0 << (0x40 - T1); + T0 = (T0 >> T1) | tmp; } FORCE_RET(); } @@ -693,10 +693,8 @@ void op_drotr32 (void) { target_ulong tmp; - if (T1) { - tmp = T0 << (0x40 - (32 + T1)); - T0 = (T0 >> (32 + T1)) | tmp; - } + tmp = T0 << (0x40 - (32 + T1)); + T0 = (T0 >> (32 + T1)) | tmp; FORCE_RET(); } @@ -724,10 +722,10 @@ void op_drotrv (void) T0 &= 0x3F; if (T0) { - tmp = T1 << (0x40 - T0); - T0 = (T1 >> T0) | tmp; + tmp = T1 << (0x40 - T0); + T0 = (T1 >> T0) | tmp; } else - T0 = T1; + T0 = T1; FORCE_RET(); } @@ -3091,7 +3089,7 @@ void op_ext(void) unsigned int pos = PARAM1; unsigned int size = PARAM2; - T0 = ((uint32_t)T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0); + T0 = (int32_t)((T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0)); FORCE_RET(); } @@ -3101,13 +3099,13 @@ void op_ins(void) unsigned int size = PARAM2; target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; - T0 = (T0 & ~mask) | (((uint32_t)T1 << pos) & mask); + T0 = (int32_t)((T0 & ~mask) | ((T1 << pos) & mask)); FORCE_RET(); } void op_wsbh(void) { - T0 = ((T1 << 8) & ~0x00FF00FF) | ((T1 >> 8) & 0x00FF00FF); + T0 = (int32_t)(((T1 << 8) & ~0x00FF00FF) | ((T1 >> 8) & 0x00FF00FF)); FORCE_RET(); } @@ -3117,7 +3115,7 @@ void op_dext(void) unsigned int pos = PARAM1; unsigned int size = PARAM2; - T0 = (T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0); + T0 = (T1 >> pos) & ((size < 64) ? ((1ULL << size) - 1) : ~0ULL); FORCE_RET(); } @@ -3125,7 +3123,7 @@ void op_dins(void) { unsigned int pos = PARAM1; unsigned int size = PARAM2; - target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos; + target_ulong mask = ((size < 64) ? ((1ULL << size) - 1) : ~0ULL) << pos; T0 = (T0 & ~mask) | ((T1 << pos) & mask); FORCE_RET(); @@ -3139,7 +3137,8 @@ void op_dsbh(void) void op_dshd(void) { - T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL); + T1 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL); + T0 = (T1 << 32) | (T1 >> 32); FORCE_RET(); } #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 7d74efc45..4391e551b 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -106,8 +106,8 @@ void do_drotr (void) target_ulong tmp; if (T1) { - tmp = T0 << (0x40 - T1); - T0 = (T0 >> T1) | tmp; + tmp = T0 << (0x40 - T1); + T0 = (T0 >> T1) | tmp; } } @@ -115,10 +115,8 @@ void do_drotr32 (void) { target_ulong tmp; - if (T1) { - tmp = T0 << (0x40 - (32 + T1)); - T0 = (T0 >> (32 + T1)) | tmp; - } + tmp = T0 << (0x40 - (32 + T1)); + T0 = (T0 >> (32 + T1)) | tmp; } void do_dsllv (void) @@ -142,10 +140,10 @@ void do_drotrv (void) T0 &= 0x3F; if (T0) { - tmp = T1 << (0x40 - T0); - T0 = (T1 >> T0) | tmp; + tmp = T1 << (0x40 - T0); + T0 = (T1 >> T0) | tmp; } else - T0 = T1; + T0 = T1; } void do_dclo (void) diff --git a/target-mips/translate.c b/target-mips/translate.c index ac439d27a..b3ae2ccfe 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1897,43 +1897,49 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, goto fail; gen_op_ext(lsb, msb + 1); break; +#if defined(TARGET_MIPS64) case OPC_DEXTM: if (lsb + msb > 63) goto fail; - gen_op_ext(lsb, msb + 1 + 32); + gen_op_dext(lsb, msb + 1 + 32); break; case OPC_DEXTU: if (lsb + msb > 63) goto fail; - gen_op_ext(lsb + 32, msb + 1); + gen_op_dext(lsb + 32, msb + 1); break; case OPC_DEXT: - gen_op_ext(lsb, msb + 1); + if (lsb + msb > 63) + goto fail; + gen_op_dext(lsb, msb + 1); break; +#endif case OPC_INS: if (lsb > msb) goto fail; GEN_LOAD_REG_TN(T0, rt); gen_op_ins(lsb, msb - lsb + 1); break; +#if defined(TARGET_MIPS64) case OPC_DINSM: if (lsb > msb) goto fail; GEN_LOAD_REG_TN(T0, rt); - gen_op_ins(lsb, msb - lsb + 1 + 32); + gen_op_dins(lsb, msb - lsb + 1 + 32); break; case OPC_DINSU: if (lsb > msb) goto fail; GEN_LOAD_REG_TN(T0, rt); - gen_op_ins(lsb + 32, msb - lsb + 1); + gen_op_dins(lsb + 32, msb - lsb + 1); break; case OPC_DINS: if (lsb > msb) goto fail; GEN_LOAD_REG_TN(T0, rt); - gen_op_ins(lsb, msb - lsb + 1); + gen_op_dins(lsb, msb - lsb + 1); break; +#endif default: fail: MIPS_INVAL("bitops"); @@ -6156,6 +6162,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) break; } GEN_STORE_TN_REG(rd, T0); + break; #endif default: /* Invalid */ MIPS_INVAL("special3"); -- cgit v1.2.3 From b881c2c6e774d40b33980f00f830431deed9e896 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 18 Nov 2007 08:46:58 +0000 Subject: Remove unused parameters from QEMUMachineInitFunc (Laurent Vivier) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3687 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/an5206.c | 4 ++-- hw/boards.h | 9 +++++---- hw/dummy_m68k.c | 1 - hw/etraxfs.c | 4 ++-- hw/integratorcp.c | 1 - hw/mcf5208.c | 1 - hw/mips_malta.c | 4 ++-- hw/mips_mipssim.c | 4 ++-- hw/mips_pica61.c | 4 ++-- hw/mips_r4k.c | 4 ++-- hw/palm.c | 1 - hw/pc.c | 20 ++++++++------------ hw/ppc405_boards.c | 2 -- hw/ppc_chrp.c | 1 - hw/ppc_oldworld.c | 1 - hw/ppc_prep.c | 5 ++--- hw/r2d.c | 4 ++-- hw/realview.c | 1 - hw/shix.c | 4 ++-- hw/spitz.c | 4 ---- hw/stellaris.c | 2 -- hw/sun4m.c | 20 ++++++++++---------- hw/sun4u.c | 8 ++++---- hw/versatilepb.c | 17 ++++++++--------- vl.c | 3 +-- 25 files changed, 54 insertions(+), 75 deletions(-) diff --git a/hw/an5206.c b/hw/an5206.c index 5e12ed854..52be63b77 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -30,8 +30,8 @@ void DMA_run (void) /* Board init. */ -static void an5206_init(int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void an5206_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/boards.h b/hw/boards.h index 7eee86631..73a44a4a3 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -4,10 +4,11 @@ #define HW_BOARDS_H typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size, - const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model); + const char *boot_device, DisplayState *ds, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model); typedef struct QEMUMachine { const char *name; diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 812162048..705d30425 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -16,7 +16,6 @@ static void dummy_m68k_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/etraxfs.c b/hw/etraxfs.c index ba4d4009e..dfef962d8 100644 --- a/hw/etraxfs.c +++ b/hw/etraxfs.c @@ -109,8 +109,8 @@ static void dummy_cpu_set_irq(void *opaque, int irq, int level) } static -void bareetraxfs_init (int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +void bareetraxfs_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 621122631..f1d71ff87 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -471,7 +471,6 @@ static void icp_control_init(uint32_t base) static void integratorcp_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/mcf5208.c b/hw/mcf5208.c index b3389f079..d7e7dcf5d 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -204,7 +204,6 @@ static void mcf5208_sys_init(qemu_irq *pic) static void mcf5208evb_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/mips_malta.c b/hw/mips_malta.c index f133da3e3..4d95fbfbf 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -756,8 +756,8 @@ static void main_cpu_reset(void *opaque) } static -void mips_malta_init (int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +void mips_malta_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index b9eec84f6..fe753146e 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -106,8 +106,8 @@ static void main_cpu_reset(void *opaque) } static void -mips_mipssim_init (int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +mips_mipssim_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 6e9f34505..2a358d53e 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -60,8 +60,8 @@ static void main_cpu_reset(void *opaque) } static -void mips_pica61_init (int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +void mips_pica61_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 42effb365..d090a2a1c 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -143,8 +143,8 @@ static void main_cpu_reset(void *opaque) } static -void mips_r4k_init (int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +void mips_r4k_init (int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/palm.c b/hw/palm.c index 63edd9029..9400ea78c 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -185,7 +185,6 @@ static void palmte_gpio_setup(struct omap_mpu_state_s *cpu) static void palmte_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/pc.c b/hw/pc.c index 69eeadb68..7049c44a1 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -693,8 +693,8 @@ static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic) } /* PC hardware initialisation */ -static void pc_init1(int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void pc_init1(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, int pci_enabled, const char *cpu_model) @@ -982,30 +982,26 @@ static void pc_init1(int ram_size, int vga_ram_size, const char *boot_device, #endif } -static void pc_init_pci(int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, +static void pc_init_pci(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - pc_init1(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, + pc_init1(ram_size, vga_ram_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, 1, cpu_model); } -static void pc_init_isa(int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, +static void pc_init_isa(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - pc_init1(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, + pc_init1(ram_size, vga_ram_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, 0, cpu_model); } diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 7fd53d3ca..91fecc877 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -179,7 +179,6 @@ static void ref405ep_fpga_init (uint32_t base) static void ref405ep_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, @@ -505,7 +504,6 @@ static void taihu_cpld_init (uint32_t base) static void taihu_405ep_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 34e192183..9d89b6631 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -57,7 +57,6 @@ static CPUReadMemoryFunc *unin_read[] = { /* PowerPC Mac99 hardware initialisation */ static void ppc_core99_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index ac09c831f..f3fe1a9d7 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -102,7 +102,6 @@ static int vga_osi_call (CPUState *env) static void ppc_heathrow_init (int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 4fcd5dd1a..1d6634cde 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -531,9 +531,8 @@ CPUReadMemoryFunc *PPC_prep_io_read[] = { /* PowerPC PREP hardware initialisation */ static void ppc_prep_init (int ram_size, int vga_ram_size, - const char *boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, const char *kernel_filename, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) diff --git a/hw/r2d.c b/hw/r2d.c index 4bca6bead..b6cc31c54 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -30,8 +30,8 @@ #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */ #define SDRAM_SIZE 0x04000000 -static void r2d_init(int ram_size, int vga_ram_size, const char *boot_device, - DisplayState * ds, const char **fd_filename, int snapshot, +static void r2d_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState * ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/realview.c b/hw/realview.c index 808df1064..7e8586f4a 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -20,7 +20,6 @@ static void realview_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/shix.c b/hw/shix.c index c891381c0..533b15935 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -65,8 +65,8 @@ void vga_screen_dump(const char *filename) /* XXXXX */ } -static void shix_init(int ram_size, int vga_ram_size, const char *boot_device, - DisplayState * ds, const char **fd_filename, int snapshot, +static void shix_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState * ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/spitz.c b/hw/spitz.c index c82992150..461a60dd8 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1234,7 +1234,6 @@ static void spitz_common_init(int ram_size, int vga_ram_size, static void spitz_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -1244,7 +1243,6 @@ static void spitz_init(int ram_size, int vga_ram_size, static void borzoi_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -1254,7 +1252,6 @@ static void borzoi_init(int ram_size, int vga_ram_size, static void akita_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -1264,7 +1261,6 @@ static void akita_init(int ram_size, int vga_ram_size, static void terrier_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/stellaris.c b/hw/stellaris.c index 0bd76ab22..878c7f84e 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1078,7 +1078,6 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, /* FIXME: Figure out how to generate these from stellaris_boards. */ static void lm3s811evb_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -1087,7 +1086,6 @@ static void lm3s811evb_init(int ram_size, int vga_ram_size, static void lm3s6965evb_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/sun4m.c b/hw/sun4m.c index 7187956a4..e8adc4569 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -573,10 +573,10 @@ static void sun4m_common_init(int RAM_size, const char *boot_device, DisplayStat } /* SPARCstation 5 hardware initialisation */ -static void ss5_init(int RAM_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss5_init(int RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) { if (cpu_model == NULL) cpu_model = "Fujitsu MB86904"; @@ -586,10 +586,10 @@ static void ss5_init(int RAM_size, int vga_ram_size, const char *boot_device, } /* SPARCstation 10 hardware initialisation */ -static void ss10_init(int RAM_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss10_init(int RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) { if (cpu_model == NULL) cpu_model = "TI SuperSparc II"; @@ -599,8 +599,8 @@ static void ss10_init(int RAM_size, int vga_ram_size, const char *boot_device, } /* SPARCserver 600MP hardware initialisation */ -static void ss600mp_init(int RAM_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void ss600mp_init(int RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { diff --git a/hw/sun4u.c b/hw/sun4u.c index 336a74c13..6fb7faeb3 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -226,10 +226,10 @@ static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; static fdctrl_t *floppy_controller; /* Sun4u hardware initialisation */ -static void sun4u_init(int ram_size, int vga_ram_size, const char *boot_devices, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sun4u_init(int ram_size, int vga_ram_size, + const char *boot_devices, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) { CPUState *env; char buf[1024]; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index fa5f57a49..66e11bf73 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -159,7 +159,6 @@ static qemu_irq *vpb_sic_init(uint32_t base, qemu_irq *parent, int irq) static void versatile_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, int board_id) @@ -276,24 +275,24 @@ static void versatile_init(int ram_size, int vga_ram_size, initrd_filename, board_id, 0x0); } -static void vpb_init(int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void vpb_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - versatile_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, + versatile_init(ram_size, vga_ram_size, + boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 0x183); } -static void vab_init(int ram_size, int vga_ram_size, const char *boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, +static void vab_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - versatile_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, + versatile_init(ram_size, vga_ram_size, + boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 0x25e); } diff --git a/vl.c b/vl.c index e54afbfb2..8b2b5bdb2 100644 --- a/vl.c +++ b/vl.c @@ -8529,8 +8529,7 @@ int main(int argc, char **argv) } } - machine->init(ram_size, vga_ram_size, boot_devices, - ds, fd_filename, snapshot, + machine->init(ram_size, vga_ram_size, boot_devices, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); /* init USB devices */ -- cgit v1.2.3 From f090c9d4ad5812fb92843d6470a1111c15190c4c Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Nov 2007 14:33:24 +0000 Subject: Add strict checking mode for softfp code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3688 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat-specialize.h | 95 +++++++++++++--------- fpu/softfloat.c | 175 +++++++++++++++++++++++++---------------- fpu/softfloat.h | 35 ++++++++- target-arm/nwfpe/double_cpdo.c | 2 +- target-arm/nwfpe/single_cpdo.c | 8 +- target-m68k/helper.c | 2 +- target-m68k/op.c | 2 +- target-mips/op_helper.c | 8 +- 8 files changed, 210 insertions(+), 117 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 8f9dd5c45..18c6dd52d 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -66,9 +66,9 @@ typedef struct { | The pattern for a default generated single-precision NaN. *----------------------------------------------------------------------------*/ #if SNAN_BIT_IS_ONE -#define float32_default_nan 0x7FBFFFFF +#define float32_default_nan make_float32(0x7FBFFFFF) #else -#define float32_default_nan 0xFFC00000 +#define float32_default_nan make_float32(0xFFC00000) #endif /*---------------------------------------------------------------------------- @@ -76,8 +76,9 @@ typedef struct { | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float32_is_nan( float32 a ) +int float32_is_nan( float32 a_ ) { + uint32_t a = float32_val(a_); #if SNAN_BIT_IS_ONE return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); #else @@ -90,8 +91,9 @@ int float32_is_nan( float32 a ) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float32_is_signaling_nan( float32 a ) +int float32_is_signaling_nan( float32 a_ ) { + uint32_t a = float32_val(a_); #if SNAN_BIT_IS_ONE return ( 0xFF800000 <= (bits32) ( a<<1 ) ); #else @@ -110,9 +112,9 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) commonNaNT z; if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); - z.sign = a>>31; + z.sign = float32_val(a)>>31; z.low = 0; - z.high = ( (bits64) a )<<41; + z.high = ( (bits64) float32_val(a) )<<41; return z; } @@ -123,7 +125,8 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) static float32 commonNaNToFloat32( commonNaNT a ) { - return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); + return make_float32( + ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ) ); } /*---------------------------------------------------------------------------- @@ -135,42 +138,52 @@ static float32 commonNaNToFloat32( commonNaNT a ) static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits32 av, bv, res; aIsNaN = float32_is_nan( a ); aIsSignalingNaN = float32_is_signaling_nan( a ); bIsNaN = float32_is_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); + av = float32_val(a); + bv = float32_val(b); #if SNAN_BIT_IS_ONE - a &= ~0x00400000; - b &= ~0x00400000; + av &= ~0x00400000; + bv &= ~0x00400000; #else - a |= 0x00400000; - b |= 0x00400000; + av |= 0x00400000; + bv |= 0x00400000; #endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; + res = bIsNaN ? bv : av; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) return a; + if ( bIsSignalingNaN | ! bIsNaN ) + res = av; + else { returnLargerSignificand: - if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b; - if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a; - return ( a < b ) ? a : b; + if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) ) + res = bv; + else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } } else { - return b; + res = bv; } + return make_float32(res); } /*---------------------------------------------------------------------------- | The pattern for a default generated double-precision NaN. *----------------------------------------------------------------------------*/ #if SNAN_BIT_IS_ONE -#define float64_default_nan LIT64( 0x7FF7FFFFFFFFFFFF ) +#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) #else -#define float64_default_nan LIT64( 0xFFF8000000000000 ) +#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 )) #endif /*---------------------------------------------------------------------------- @@ -178,8 +191,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float64_is_nan( float64 a ) +int float64_is_nan( float64 a_ ) { + bits64 a = float64_val(a_); #if SNAN_BIT_IS_ONE return ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) @@ -194,8 +208,9 @@ int float64_is_nan( float64 a ) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float64_is_signaling_nan( float64 a ) +int float64_is_signaling_nan( float64 a_ ) { + bits64 a = float64_val(a_); #if SNAN_BIT_IS_ONE return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); #else @@ -216,9 +231,9 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) commonNaNT z; if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); - z.sign = a>>63; + z.sign = float64_val(a)>>63; z.low = 0; - z.high = a<<12; + z.high = float64_val(a)<<12; return z; } @@ -229,10 +244,10 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) static float64 commonNaNToFloat64( commonNaNT a ) { - return + return make_float64( ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FF8000000000000 ) - | ( a.high>>12 ); + | ( a.high>>12 )); } /*---------------------------------------------------------------------------- @@ -244,33 +259,43 @@ static float64 commonNaNToFloat64( commonNaNT a ) static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits64 av, bv, res; aIsNaN = float64_is_nan( a ); aIsSignalingNaN = float64_is_signaling_nan( a ); bIsNaN = float64_is_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); + av = float64_val(a); + bv = float64_val(b); #if SNAN_BIT_IS_ONE - a &= ~LIT64( 0x0008000000000000 ); - b &= ~LIT64( 0x0008000000000000 ); + av &= ~LIT64( 0x0008000000000000 ); + bv &= ~LIT64( 0x0008000000000000 ); #else - a |= LIT64( 0x0008000000000000 ); - b |= LIT64( 0x0008000000000000 ); + av |= LIT64( 0x0008000000000000 ); + bv |= LIT64( 0x0008000000000000 ); #endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; + res = bIsNaN ? bv : av; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) return a; + if ( bIsSignalingNaN | ! bIsNaN ) + res = av; + else { returnLargerSignificand: - if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b; - if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a; - return ( a < b ) ? a : b; + if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) ) + res = bv; + else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } } else { - return b; + res = bv; } + return make_float64(res); } #ifdef FLOATX80 diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 8ebb69264..f6cbd29ce 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -175,7 +175,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA INLINE bits32 extractFloat32Frac( float32 a ) { - return a & 0x007FFFFF; + return float32_val(a) & 0x007FFFFF; } @@ -186,7 +186,7 @@ INLINE bits32 extractFloat32Frac( float32 a ) INLINE int16 extractFloat32Exp( float32 a ) { - return ( a>>23 ) & 0xFF; + return ( float32_val(a)>>23 ) & 0xFF; } @@ -197,7 +197,7 @@ INLINE int16 extractFloat32Exp( float32 a ) INLINE flag extractFloat32Sign( float32 a ) { - return a>>31; + return float32_val(a)>>31; } @@ -233,7 +233,8 @@ static void INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig ) { - return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig; + return make_float32( + ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig); } @@ -290,7 +291,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P && ( (sbits32) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); - return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 ); + return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { isTiny = @@ -337,7 +338,7 @@ static float32 INLINE bits64 extractFloat64Frac( float64 a ) { - return a & LIT64( 0x000FFFFFFFFFFFFF ); + return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF ); } @@ -348,7 +349,7 @@ INLINE bits64 extractFloat64Frac( float64 a ) INLINE int16 extractFloat64Exp( float64 a ) { - return ( a>>52 ) & 0x7FF; + return ( float64_val(a)>>52 ) & 0x7FF; } @@ -359,7 +360,7 @@ INLINE int16 extractFloat64Exp( float64 a ) INLINE flag extractFloat64Sign( float64 a ) { - return a>>63; + return float64_val(a)>>63; } @@ -395,7 +396,8 @@ static void INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig ) { - return ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig; + return make_float64( + ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig); } @@ -452,7 +454,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P && ( (sbits64) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); - return packFloat64( zSign, 0x7FF, 0 ) - ( roundIncrement == 0 ); + return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { isTiny = @@ -1050,7 +1052,7 @@ float32 int32_to_float32( int32 a STATUS_PARAM ) { flag zSign; - if ( a == 0 ) return 0; + if ( a == 0 ) return float32_zero; if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 ); zSign = ( a < 0 ); return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a STATUS_VAR ); @@ -1070,7 +1072,7 @@ float64 int32_to_float64( int32 a STATUS_PARAM ) int8 shiftCount; bits64 zSig; - if ( a == 0 ) return 0; + if ( a == 0 ) return float64_zero; zSign = ( a < 0 ); absA = zSign ? - a : a; shiftCount = countLeadingZeros32( absA ) + 21; @@ -1144,7 +1146,7 @@ float32 int64_to_float32( int64 a STATUS_PARAM ) uint64 absA; int8 shiftCount; - if ( a == 0 ) return 0; + if ( a == 0 ) return float32_zero; zSign = ( a < 0 ); absA = zSign ? - a : a; shiftCount = countLeadingZeros64( absA ) - 40; @@ -1168,7 +1170,7 @@ float32 uint64_to_float32( uint64 a STATUS_PARAM ) { int8 shiftCount; - if ( a == 0 ) return 0; + if ( a == 0 ) return float32_zero; shiftCount = countLeadingZeros64( a ) - 40; if ( 0 <= shiftCount ) { return packFloat32( 1 > 0, 0x95 - shiftCount, a<>1; if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + if ( extractFloat32Sign( make_float32(z) ) ^ ( roundingMode == float_round_up ) ) { z += roundBitsMask; } } z &= ~ roundBitsMask; - if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact; - return z; + if ( z != float32_val(a) ) STATUS(float_exception_flags) |= float_flag_inexact; + return make_float32(z); } @@ -2008,7 +2010,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return propagateFloat32NaN( a, 0 STATUS_VAR ); + if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR ); if ( ! aSign ) return a; float_raise( float_flag_invalid STATUS_VAR); return float32_default_nan; @@ -2019,7 +2021,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) return float32_default_nan; } if ( aExp == 0 ) { - if ( aSig == 0 ) return 0; + if ( aSig == 0 ) return float32_zero; normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; @@ -2062,7 +2064,8 @@ int float32_eq( float32 a, float32 b STATUS_PARAM ) } return 0; } - return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( float32_val(a) == float32_val(b) ) || + ( (bits32) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); } @@ -2076,6 +2079,7 @@ int float32_eq( float32 a, float32 b STATUS_PARAM ) int float32_le( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2085,8 +2089,10 @@ int float32_le( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -2099,6 +2105,7 @@ int float32_le( float32 a, float32 b STATUS_PARAM ) int float32_lt( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2108,8 +2115,10 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -2122,6 +2131,7 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) { + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2129,7 +2139,9 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + av = float32_val(a); + bv = float32_val(b); + return ( av == bv ) || ( (bits32) ( ( av | bv )<<1 ) == 0 ); } @@ -2143,6 +2155,7 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2154,8 +2167,10 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -2169,6 +2184,7 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2180,8 +2196,10 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -2324,7 +2342,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM ) shiftCount = aExp - 0x433; if ( 0 <= shiftCount ) { if ( 0x43E <= aExp ) { - if ( a != LIT64( 0xC3E0000000000000 ) ) { + if ( float64_val(a) != LIT64( 0xC3E0000000000000 ) ) { float_raise( float_flag_invalid STATUS_VAR); if ( ! aSign || ( ( aExp == 0x7FF ) @@ -2464,7 +2482,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) int16 aExp; bits64 lastBitMask, roundBitsMask; int8 roundingMode; - float64 z; + bits64 z; aExp = extractFloat64Exp( a ); if ( 0x433 <= aExp ) { @@ -2474,7 +2492,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) return a; } if ( aExp < 0x3FF ) { - if ( (bits64) ( a<<1 ) == 0 ) return a; + if ( (bits64) ( float64_val(a)<<1 ) == 0 ) return a; STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloat64Sign( a ); switch ( STATUS(float_rounding_mode) ) { @@ -2484,30 +2502,31 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) } break; case float_round_down: - return aSign ? LIT64( 0xBFF0000000000000 ) : 0; + return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0); case float_round_up: - return - aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 ); + return make_float64( + aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 )); } return packFloat64( aSign, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x433 - aExp; roundBitsMask = lastBitMask - 1; - z = a; + z = float64_val(a); roundingMode = STATUS(float_rounding_mode); if ( roundingMode == float_round_nearest_even ) { z += lastBitMask>>1; if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { + if ( extractFloat64Sign( make_float64(z) ) ^ ( roundingMode == float_round_up ) ) { z += roundBitsMask; } } z &= ~ roundBitsMask; - if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact; - return z; + if ( z != float64_val(a) ) + STATUS(float_exception_flags) |= float_flag_inexact; + return make_float64(z); } @@ -2951,7 +2970,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) return float64_default_nan; } if ( aExp == 0 ) { - if ( aSig == 0 ) return 0; + if ( aSig == 0 ) return float64_zero; normalizeFloat64Subnormal( aSig, &aExp, &aSig ); } zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; @@ -2982,6 +3001,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) int float64_eq( float64 a, float64 b STATUS_PARAM ) { + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -2991,7 +3011,9 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) } return 0; } - return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + av = float64_val(a); + bv = float64_val(a); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); } @@ -3005,6 +3027,7 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) int float64_le( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3014,8 +3037,10 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(a); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -3028,6 +3053,7 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) int float64_lt( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3037,8 +3063,10 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(a); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -3051,6 +3079,7 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) { + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3058,7 +3087,9 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + av = float64_val(a); + bv = float64_val(a); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); } @@ -3072,6 +3103,7 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3083,8 +3115,10 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(a); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -3098,6 +3132,7 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3109,8 +3144,10 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(a); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -5310,12 +5347,14 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) return res; } +/* FIXME: This looks broken. */ uint64_t float64_to_uint64 (float64 a STATUS_PARAM) { int64_t v; - v = int64_to_float64(INT64_MIN STATUS_VAR); - v = float64_to_int64((a + v) STATUS_VAR); + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64(make_float64(v) STATUS_VAR); return v - INT64_MIN; } @@ -5324,8 +5363,9 @@ uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) { int64_t v; - v = int64_to_float64(INT64_MIN STATUS_VAR); - v = float64_to_int64_round_to_zero((a + v) STATUS_VAR); + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64_round_to_zero(make_float64(v) STATUS_VAR); return v - INT64_MIN; } @@ -5335,6 +5375,7 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ int is_quiet STATUS_PARAM ) \ { \ flag aSign, bSign; \ + bits ## s av, bv; \ \ if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \ extractFloat ## s ## Frac( a ) ) || \ @@ -5349,18 +5390,20 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ } \ aSign = extractFloat ## s ## Sign( a ); \ bSign = extractFloat ## s ## Sign( b ); \ + av = float ## s ## _val(a); \ + bv = float ## s ## _val(a); \ if ( aSign != bSign ) { \ - if ( (bits ## s) ( ( a | b )<<1 ) == 0 ) { \ + if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) { \ /* zero case */ \ return float_relation_equal; \ } else { \ return 1 - (2 * aSign); \ } \ } else { \ - if (a == b) { \ + if (av == bv) { \ return float_relation_equal; \ } else { \ - return 1 - 2 * (aSign ^ ( a < b )); \ + return 1 - 2 * (aSign ^ ( av < bv )); \ } \ } \ } \ diff --git a/fpu/softfloat.h b/fpu/softfloat.h index f0261fb6a..84cffdd5d 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -111,8 +111,31 @@ enum { /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point types. *----------------------------------------------------------------------------*/ +/* Use structures for soft-float types. This prevents accidentally mixing + them with native int/float types. A sufficiently clever compiler and + sane ABI should be able to see though these structs. However + x86/gcc 3.x seems to struggle a bit, so leave them disabled by default. */ +//#define USE_SOFTFLOAT_STRUCT_TYPES +#ifdef USE_SOFTFLOAT_STRUCT_TYPES +typedef struct { + uint32_t v; +} float32; +/* The cast ensures an error if the wrong type is passed. */ +#define float32_val(x) (((float32)(x)).v) +#define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; }) +typedef struct { + uint64_t v; +} float64; +#define float64_val(x) (((float64)(x)).v) +#define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; }) +#else typedef uint32_t float32; typedef uint64_t float64; +#define float32_val(x) (x) +#define float64_val(x) (x) +#define make_float32(x) (x) +#define make_float64(x) (x) +#endif #ifdef FLOATX80 typedef struct { uint64_t low; @@ -248,14 +271,16 @@ float32 float32_scalbn( float32, int STATUS_PARAM ); INLINE float32 float32_abs(float32 a) { - return a & 0x7fffffff; + return make_float32(float32_val(a) & 0x7fffffff); } INLINE float32 float32_chs(float32 a) { - return a ^ 0x80000000; + return make_float32(float32_val(a) ^ 0x80000000); } +#define float32_zero make_float32(0) + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -300,14 +325,16 @@ float64 float64_scalbn( float64, int STATUS_PARAM ); INLINE float64 float64_abs(float64 a) { - return a & 0x7fffffffffffffffLL; + return make_float64(float64_val(a) & 0x7fffffffffffffffLL); } INLINE float64 float64_chs(float64 a) { - return a ^ 0x8000000000000000LL; + return make_float64(float64_val(a) ^ 0x8000000000000000LL); } +#define float64_zero make_float64(0) + #ifdef FLOATX80 /*---------------------------------------------------------------------------- diff --git a/target-arm/nwfpe/double_cpdo.c b/target-arm/nwfpe/double_cpdo.c index dbd496ea6..b5320c82a 100644 --- a/target-arm/nwfpe/double_cpdo.c +++ b/target-arm/nwfpe/double_cpdo.c @@ -38,7 +38,7 @@ float64 float64_pol(float64 rFn,float64 rFm); unsigned int DoubleCPDO(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); - float64 rFm, rFn = 0; + float64 rFm, rFn = float64_zero; unsigned int Fd, Fm, Fn, nRc = 1; //printk("DoubleCPDO(0x%08x)\n",opcode); diff --git a/target-arm/nwfpe/single_cpdo.c b/target-arm/nwfpe/single_cpdo.c index 1482f4712..65043bcb3 100644 --- a/target-arm/nwfpe/single_cpdo.c +++ b/target-arm/nwfpe/single_cpdo.c @@ -38,7 +38,7 @@ float32 float32_pol(float32 rFn,float32 rFm); unsigned int SingleCPDO(const unsigned int opcode) { FPA11 *fpa11 = GET_FPA11(); - float32 rFm, rFn = 0; + float32 rFm, rFn = float32_zero; unsigned int Fd, Fm, Fn, nRc = 1; Fm = getFm(opcode); @@ -128,13 +128,11 @@ unsigned int SingleCPDO(const unsigned int opcode) break; case MNF_CODE: - rFm ^= 0x80000000; - fpa11->fpreg[Fd].fSingle = rFm; + fpa11->fpreg[Fd].fSingle = float32_chs(rFm); break; case ABS_CODE: - rFm &= 0x7fffffff; - fpa11->fpreg[Fd].fSingle = rFm; + fpa11->fpreg[Fd].fSingle = float32_abs(rFm); break; case RND_CODE: diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 460ef3c03..f6b0cd6b3 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -255,7 +255,7 @@ float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1) /* +/-inf compares equal against itself, but sub returns nan. */ if (!float64_is_nan(src0) && !float64_is_nan(src1)) { - res = 0; + res = float64_zero; if (float64_lt_quiet(src0, res, &env->fp_status)) res = float64_chs(res); } diff --git a/target-m68k/op.c b/target-m68k/op.c index 8600f43f1..140c71d89 100644 --- a/target-m68k/op.c +++ b/target-m68k/op.c @@ -108,7 +108,7 @@ OP(movf64) OP(zerof64) { - set_opf64(PARAM1, 0); + set_opf64(PARAM1, float64_zero); FORCE_RET(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 4391e551b..032302161 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -624,10 +624,10 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, /* Complex FPU operations which may need stack space. */ -#define FLOAT_ONE32 (0x3f8 << 20) -#define FLOAT_ONE64 (0x3ffULL << 52) -#define FLOAT_TWO32 (1 << 30) -#define FLOAT_TWO64 (1ULL << 62) +#define FLOAT_ONE32 make_float32(0x3f8 << 20) +#define FLOAT_ONE64 make_float64(0x3ffULL << 52) +#define FLOAT_TWO32 make_float32(1 << 30) +#define FLOAT_TWO64 make_float64(1ULL << 62) #define FLOAT_QNAN32 0x7fbfffff #define FLOAT_QNAN64 0x7ff7ffffffffffffULL #define FLOAT_SNAN32 0x7fffffff -- cgit v1.2.3 From cf0dbb21156f2fabdbe8b846b16dfc9825d8b23c Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Nov 2007 14:36:08 +0000 Subject: Luminary board input support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3689 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- hw/devices.h | 3 +++ hw/irq.c | 2 ++ hw/stellaris.c | 36 +++++++++++++++++++++++----- hw/stellaris_input.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 hw/stellaris_input.c diff --git a/Makefile b/Makefile index 82e420287..493330c09 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ OBJS+=block.o OBJS+=irq.o OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o -OBJS+=ssd0303.o ssd0323.o ads7846.o +OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o OBJS+=scsi-disk.o cdrom.o OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o diff --git a/hw/devices.h b/hw/devices.h index 382774565..07c673b77 100644 --- a/hw/devices.h +++ b/hw/devices.h @@ -16,4 +16,7 @@ uint32_t ads7846_read(void *opaque); void ads7846_write(void *opaque, uint32_t value); struct ads7846_state_s *ads7846_init(qemu_irq penirq); +/* stellaris_input.c */ +void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode); + #endif diff --git a/hw/irq.c b/hw/irq.c index 960155ad0..eca707dd0 100644 --- a/hw/irq.c +++ b/hw/irq.c @@ -65,5 +65,7 @@ static void qemu_notirq(void *opaque, int line, int level) qemu_irq qemu_irq_invert(qemu_irq irq) { + /* The default state for IRQs is low, so raise the output now. */ + qemu_irq_raise(irq); return qemu_allocate_irqs(qemu_notirq, irq, 1)[0]; } diff --git a/hw/stellaris.c b/hw/stellaris.c index 878c7f84e..3dbb2ced6 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -16,6 +16,18 @@ #include "sysemu.h" #include "boards.h" +#define GPIO_A 0 +#define GPIO_B 1 +#define GPIO_C 2 +#define GPIO_D 3 +#define GPIO_E 4 +#define GPIO_F 5 +#define GPIO_G 6 + +#define BP_OLED_I2C 0x01 +#define BP_OLED_SSI 0x02 +#define BP_GAMEPAD 0x04 + typedef const struct { const char *name; uint32_t did0; @@ -25,7 +37,7 @@ typedef const struct { uint32_t dc2; uint32_t dc3; uint32_t dc4; - enum {OLED_I2C, OLED_SSI} oled; + uint32_t peripherals; } stellaris_board_info; /* General purpose timer module. */ @@ -991,7 +1003,7 @@ static stellaris_board_info stellaris_boards[] = { 0x01071013, 0x3f0f01ff, 0x0000001f, - OLED_I2C + BP_OLED_I2C }, { "LM3S6965EVB", 0x10010002, @@ -1001,7 +1013,7 @@ static stellaris_board_info stellaris_boards[] = { 0x030f5317, 0x0f0f87ff, 0x5000007f, - OLED_SSI + BP_OLED_SSI | BP_GAMEPAD } }; @@ -1052,7 +1064,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, if (board->dc2 & (1 << 12)) { i2c = i2c_init_bus(); stellaris_i2c_init(0x40020000, pic[8], i2c); - if (board->oled == OLED_I2C) { + if (board->peripherals & BP_OLED_I2C) { ssd0303_init(ds, i2c, 0x3d); } } @@ -1064,15 +1076,27 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } } if (board->dc2 & (1 << 4)) { - if (board->oled == OLED_SSI) { + if (board->peripherals & BP_OLED_SSI) { void * oled; /* FIXME: Implement chip select for OLED/MMC. */ - oled = ssd0323_init(ds, &gpio_out[2][7]); + oled = ssd0323_init(ds, &gpio_out[GPIO_C][7]); pl022_init(0x40008000, pic[7], ssd0323_xfer_ssi, oled); } else { pl022_init(0x40008000, pic[7], NULL, NULL); } } + if (board->peripherals & BP_GAMEPAD) { + qemu_irq gpad_irq[5]; + static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; + + gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */ + gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */ + gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */ + gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */ + gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */ + + stellaris_gamepad_init(5, gpad_irq, gpad_keycode); + } } /* FIXME: Figure out how to generate these from stellaris_boards. */ diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c new file mode 100644 index 000000000..461868b2e --- /dev/null +++ b/hw/stellaris_input.c @@ -0,0 +1,66 @@ +/* + * Gamepad style buttons connected to IRQ/GPIO lines + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ +#include "hw.h" +#include "devices.h" +#include "console.h" + +typedef struct { + qemu_irq irq; + int keycode; + int pressed; +} gamepad_button; + +typedef struct { + gamepad_button *buttons; + int num_buttons; + int extension; +} gamepad_state; + +static void stellaris_gamepad_put_key(void * opaque, int keycode) +{ + gamepad_state *s = (gamepad_state *)opaque; + int i; + int down; + + if (keycode == 0xe0 && !s->extension) { + s->extension = 0x80; + return; + } + + down = (keycode & 0x80) == 0; + keycode = (keycode & 0x7f) | s->extension; + + for (i = 0; i < s->num_buttons; i++) { + if (s->buttons[i].keycode == keycode + && s->buttons[i].pressed != down) { + s->buttons[i].pressed = down; + qemu_set_irq(s->buttons[i].irq, down); + } + } + + s->extension = 0; +} + +/* Returns an array 5 ouput slots. */ +void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode) +{ + gamepad_state *s; + int i; + + s = (gamepad_state *)qemu_mallocz(sizeof (gamepad_state)); + s->buttons = (gamepad_button *)qemu_mallocz(n * sizeof (gamepad_button)); + for (i = 0; i < n; i++) { + s->buttons[i].irq = irq[i]; + s->buttons[i].keycode = keycode[i]; + } + s->num_buttons = n; + qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s); +} + + -- cgit v1.2.3 From ec4ef3168cdf5f3306543a713bbbac2b42d70f2d Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Nov 2007 14:40:35 +0000 Subject: Fix connex board init routine. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3690 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gumstix.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/gumstix.c b/hw/gumstix.c index 0b6dd0b3f..824715662 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -58,7 +58,6 @@ static void gumstix_common_init(int ram_size, int vga_ram_size, static void connex_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { -- cgit v1.2.3 From 189cd4d4b36368c9164706104e1dc8125067b52f Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sun, 18 Nov 2007 15:50:41 +0000 Subject: Fix for ISO C compliance: function qualifiers must always come before the return type. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3691 c046a42c-6fe2-441c-8c8c-71466251a162 --- dyngen.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dyngen.h b/dyngen.h index 266b9e972..4451d5435 100644 --- a/dyngen.h +++ b/dyngen.h @@ -45,7 +45,7 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) #define MIN_CACHE_LINE_SIZE 8 /* conservative value */ -static void inline flush_icache_range(unsigned long start, unsigned long stop) +static inline void flush_icache_range(unsigned long start, unsigned long stop) { unsigned long p; @@ -68,7 +68,7 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop) asm ("imb"); } #elif defined(__sparc__) -static void inline flush_icache_range(unsigned long start, unsigned long stop) +static inline void flush_icache_range(unsigned long start, unsigned long stop) { unsigned long p; -- cgit v1.2.3 From 8c462f8ff580e346b0e02373e2ed47903b119c13 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Nov 2007 21:12:37 +0000 Subject: Fix out of tree builds. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3692 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 493330c09..e8f0724b5 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ # Makefile for QEMU. -VPATH=$(SRC_PATH):$(SRC_PATH)/hw - include config-host.mak .PHONY: all clean distclean dvi info install install-doc tar tarbin \ speed test html dvi info +VPATH=$(SRC_PATH):$(SRC_PATH)/hw + BASE_CFLAGS= BASE_LDFLAGS= -- cgit v1.2.3 From 76d83bde4a804e02bd944ecad648999be2f34ab7 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Nov 2007 21:22:10 +0000 Subject: Fixes for s/390 host support, by Bastian Blank. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3693 c046a42c-6fe2-441c-8c8c-71466251a162 --- check_ops.sh | 3 +++ configure | 3 +++ dyngen-exec.h | 15 +++++++++++---- dyngen.c | 17 +++++++++++++++-- exec-all.h | 18 ------------------ 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/check_ops.sh b/check_ops.sh index b1f2f8500..1c9cf87e3 100755 --- a/check_ops.sh +++ b/check_ops.sh @@ -35,6 +35,9 @@ case $machine in mips*) ret='\tjr.*ra' ;; + s390*) + ret='\tbr.*' + ;; *) echo "Unknown machine `uname -m`" ;; diff --git a/configure b/configure index 205eee8ca..22d06b56b 100755 --- a/configure +++ b/configure @@ -356,6 +356,9 @@ case $cpu in ARCH_LDFLAGS="${SP_LDFLAGS}" fi ;; + s390) + ARCH_CFLAGS="-march=z900" + ;; esac if [ "$solaris" = "yes" -a "$cpu" = "x86_64" ] ; then diff --git a/dyngen-exec.h b/dyngen-exec.h index 37c593e29..6f69beedc 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -38,7 +38,7 @@ 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) +#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) typedef unsigned long uint64_t; #else typedef unsigned long long uint64_t; @@ -55,7 +55,7 @@ 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) +#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) typedef signed long int64_t; #else typedef signed long long int64_t; @@ -205,7 +205,7 @@ extern int printf(const char *, ...); #define stringify(s) tostring(s) #define tostring(s) #s -#ifdef __alpha__ +#if defined(__alpha__) || defined(__s390__) /* the symbols are considered non exported so a br immediate is generated */ #define __hidden __attribute__((visibility("hidden"))) #else @@ -224,6 +224,13 @@ 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; }) +#elif defined(__s390__) +extern int __op_param1 __hidden; +extern int __op_param2 __hidden; +extern int __op_param3 __hidden; +#define PARAM1 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param1) "; l %0,0(%0)" : "=r"(_r) : ); _r; }) +#define PARAM2 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param2) "; l %0,0(%0)" : "=r"(_r) : ); _r; }) +#define PARAM3 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param3) "; l %0,0(%0)" : "=r"(_r) : ); _r; }) #else #if defined(__APPLE__) static int __op_param1, __op_param2, __op_param3; @@ -254,7 +261,7 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n) #elif defined(__s390__) #define EXIT_TB() asm volatile ("br %r14") -#define GOTO_LABEL_PARAM(n) asm volatile ("bras %r7,8; .long " ASM_NAME(__op_gen_label) #n "; l %r7, 0(%r7); br %r7") +#define GOTO_LABEL_PARAM(n) asm volatile ("larl %r7,12; l %r7,0(%r7); br %r7; .long " ASM_NAME(__op_gen_label) #n) #elif defined(__alpha__) #define EXIT_TB() asm volatile ("ret") #elif defined(__ia64__) diff --git a/dyngen.c b/dyngen.c index eb94273ab..d301c714f 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1495,8 +1495,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, 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); + if ((get16((uint16_t *)p) & 0xfff0) != 0x07f0) + error("br expected at the end of %s", name); copy_size = p - p_start; } #elif defined(HOST_ALPHA) @@ -2120,6 +2120,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", reloc_offset, relname, addend); break; + case R_390_PC32DBL: + if (ELF32_ST_TYPE(symtab[ELFW(R_SYM)(rel->r_info)].st_info) == STT_SECTION) { + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) += " + "((long)&%s - (long)gen_code_ptr) >> 1;\n", + reloc_offset, name); + } + else + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "(%s + %d - ((uint32_t)gen_code_ptr + %d)) >> 1;\n", + reloc_offset, relname, addend, reloc_offset); + break; default: error("unsupported s390 relocation (%d)", type); } diff --git a/exec-all.h b/exec-all.h index 0ced25ca1..4b4f265ef 100644 --- a/exec-all.h +++ b/exec-all.h @@ -350,24 +350,6 @@ do {\ "1:\n");\ } while (0) -#elif defined(__s390__) -/* GCC spills R13, so we have to restore it before branching away */ - -#define GOTO_TB(opname, tbparam, n)\ -do {\ - static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\ - static void __attribute__((used)) *__op_label ## n \ - __asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\ - __asm__ __volatile__ ( \ - "l %%r13,52(%%r15)\n" \ - "br %0\n" \ - : : "r" (((TranslationBlock*)tbparam)->tb_next[n]));\ - \ - for(;*((int*)0);); /* just to keep GCC busy */ \ -label ## n: ;\ -dummy_label ## n: ;\ -} while(0) - #else /* jump to next block operations (more portable code, does not need -- cgit v1.2.3 From d5db4246332c0ed369acf3c137fda477e480c3eb Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Nov 2007 21:33:07 +0000 Subject: Use CONFIG_VNC_TLS_CFLAGS for building vnc.o. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3694 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e8f0724b5..c262c473e 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,7 @@ 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 d3des.c d3des.h - $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $< audio/sdlaudio.o: audio/sdlaudio.c $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $< -- cgit v1.2.3 From 8281db4db9f8a57e30eb4becf955bb0d4d6c5281 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Nov 2007 21:37:07 +0000 Subject: Add -m64 to OS_LDFLAGS for Solaris/x86_64. Use OS_CFLAGS when looking for libSDL. Patch by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3695 c046a42c-6fe2-441c-8c8c-71466251a162 --- configure | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 22d06b56b..28b677099 100755 --- a/configure +++ b/configure @@ -364,6 +364,7 @@ esac if [ "$solaris" = "yes" -a "$cpu" = "x86_64" ] ; then CFLAGS="${CFLAGS} -m64" OS_CFLAGS="${OS_CFLAGS} -m64" + OS_LDFLAGS="${OS_LDFLAGS} -m64" fi if [ "$solaris" = "yes" -a "$cpu" = "i386" ] ; then @@ -599,7 +600,7 @@ cat > $TMPC << EOF #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> /tmp/qemu-$$-sdl-config.log ; then + if $cc -o $TMPE ${OS_CFLAGS} `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /tmp/qemu-$$-sdl-config.log ; then _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'` if test "$_sdlversion" -lt 121 ; then sdl_too_old=yes @@ -618,7 +619,7 @@ EOF 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 + if $cc -o $TMPE ${OS_CFLAGS} `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then sdl_static=yes fi fi # static link -- cgit v1.2.3 From 7ac56ff043e82e540a5aa108bba2b44b407dd60b Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 18 Nov 2007 21:54:57 +0000 Subject: SSD0323 vertical incrememnt mode. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3696 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ssd0323.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 8c5ab424e..c31e49a91 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -30,6 +30,12 @@ do { fprintf(stderr, "ssd0323: error: " fmt , ##args);} while (0) /* Scaling factor for pixels. */ #define MAGNIFY 4 +#define REMAP_SWAP_COLUMN 0x01 +#define REMAP_SWAP_NYBBLE 0x02 +#define REMAP_VERTICAL 0x04 +#define REMAP_SWAP_COM 0x10 +#define REMAP_SPLIT_COM 0x40 + enum ssd0323_mode { SSD0323_CMD, @@ -49,6 +55,7 @@ typedef struct { int col_start; int col_end; int redraw; + int remap; enum ssd0323_mode mode; uint8_t framebuffer[128 * 80 / 2]; } ssd0323_state; @@ -60,13 +67,24 @@ int ssd0323_xfer_ssi(void *opaque, int data) case SSD0323_DATA: DPRINTF("data 0x%02x\n", data); s->framebuffer[s->col + s->row * 64] = data; - s->col++; - if (s->col > s->col_end) { + if (s->remap & REMAP_VERTICAL) { s->row++; - s->col = s->col_start; - } - if (s->row > s->row_end) { - s->row = s->row_start; + if (s->row > s->row_end) { + s->row = s->row_start; + s->col++; + } + if (s->col > s->col_end) { + s->col = s->col_start; + } + } else { + s->col++; + if (s->col > s->col_end) { + s->row++; + s->col = s->col_start; + } + if (s->row > s->row_end) { + s->row = s->row_start; + } } s->redraw = 1; break; @@ -82,12 +100,12 @@ int ssd0323_xfer_ssi(void *opaque, int data) #define DATA(x) if (s->cmd_len <= (x)) return 0 case 0x15: /* Set column. */ DATA(2); - s->col_start = s->cmd_data[0] % 64; + s->col = s->col_start = s->cmd_data[0] % 64; s->col_end = s->cmd_data[1] % 64; break; case 0x75: /* Set row. */ DATA(2); - s->row_start = s->cmd_data[0] % 80; + s->row = s->row_start = s->cmd_data[0] % 80; s->row_end = s->cmd_data[1] % 80; break; case 0x81: /* Set contrast */ @@ -99,6 +117,7 @@ int ssd0323_xfer_ssi(void *opaque, int data) case 0xa0: /* Set remapping. */ /* FIXME: Implement this. */ DATA(1); + s->remap = s->cmd_data[0]; break; case 0xa1: /* Set display start line. */ case 0xa2: /* Set display offset. */ @@ -207,6 +226,7 @@ static void ssd0323_update_display(void *opaque) } p += dest_width; } + /* TODO: Implement row/column remapping. */ dest = s->ds->data; for (y = 0; y < 64; y++) { line = y; -- cgit v1.2.3 From 8a0ef21949d0606d1510da256ed7d4e9128c5d6d Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 18 Nov 2007 22:34:46 +0000 Subject: Solaris build fixes, based on a patch by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3697 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile.target b/Makefile.target index e4cad8747..cc29d526f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -140,15 +140,15 @@ endif endif ifeq ($(ARCH),x86_64) -BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld + ifneq ($(CONFIG_SOLARIS),yes) + BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld + endif endif ifeq ($(ARCH),ppc) CPPFLAGS+= -D__powerpc__ -ifdef CONFIG_LINUX_USER BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld endif -endif ifeq ($(ARCH),s390) BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld @@ -554,6 +554,13 @@ ifeq ($(ARCH),sparc64) endif endif +ifeq ($(ARCH),x86_64) + VL_LDFLAGS+=-m64 + ifneq ($(CONFIG_SOLARIS),yes) + VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld + endif +endif + ifdef CONFIG_WIN32 SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole endif -- cgit v1.2.3 From df2542c737ea2f7148136b6525cd56f6fc276d69 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Nov 2007 00:38:33 +0000 Subject: Avoid duplicated definitions: move common definitions from exec-all.h and qemu-common.h to osdep.h. Include this header in translate-op.c. Make sure it's included first in darwin-user/qemu.h. To avoid discarded inlining bug, define inline as always_inline and always_inline as (( attribute (always_inline) )) __inline__. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3698 c046a42c-6fe2-441c-8c8c-71466251a162 --- darwin-user/qemu.h | 4 ++-- exec-all.h | 30 ------------------------------ osdep.h | 38 ++++++++++++++++++++++++++++++++++++++ qemu-common.h | 31 ------------------------------- translate-op.c | 1 + 5 files changed, 41 insertions(+), 63 deletions(-) diff --git a/darwin-user/qemu.h b/darwin-user/qemu.h index 4d7713b50..41b57f851 100644 --- a/darwin-user/qemu.h +++ b/darwin-user/qemu.h @@ -1,13 +1,13 @@ #ifndef GEMU_H #define GEMU_H -#include "thunk.h" - #include #include #include "cpu.h" +#include "thunk.h" + #include "gdbstub.h" typedef siginfo_t target_siginfo_t; diff --git a/exec-all.h b/exec-all.h index 4b4f265ef..285da99b5 100644 --- a/exec-all.h +++ b/exec-all.h @@ -21,36 +21,6 @@ /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS -#ifndef glue -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s -#endif - -#ifndef likely -#if __GNUC__ < 3 -#define __builtin_expect(x, n) (x) -#endif - -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#endif - -#ifndef always_inline -#if (__GNUC__ < 3) || defined(__APPLE__) -#define always_inline inline -#else -#define always_inline __attribute__ (( always_inline )) inline -#endif -#endif - -#ifdef __i386__ -#define REGPARM(n) __attribute((regparm(n))) -#else -#define REGPARM(n) -#endif - /* is_jmp field values */ #define DISAS_NEXT 0 /* next instruction can be analyzed */ #define DISAS_JUMP 1 /* only pc was modified dynamically */ diff --git a/osdep.h b/osdep.h index 50686d593..0acffa44a 100644 --- a/osdep.h +++ b/osdep.h @@ -3,6 +3,44 @@ #include +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#ifndef likely +#if __GNUC__ < 3 +#define __builtin_expect(x, n) (x) +#endif + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef always_inline +#if (__GNUC__ < 3) || defined(__APPLE__) +#define always_inline inline +#else +#define always_inline __attribute__ (( always_inline )) __inline__ +#endif +#endif +#define inline always_inline + +#ifdef __i386__ +#define REGPARM(n) __attribute((regparm(n))) +#else +#define REGPARM(n) +#endif + #define qemu_printf printf void *qemu_malloc(size_t size); diff --git a/qemu-common.h b/qemu-common.h index 119d1bb32..2c955219d 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -62,37 +62,6 @@ static inline char *realpath(const char *path, char *resolved_path) #endif /* !defined(NEED_CPU_H) */ -#ifndef glue -#define xglue(x, y) x ## y -#define glue(x, y) xglue(x, y) -#define stringify(s) tostring(s) -#define tostring(s) #s -#endif - -#ifndef likely -#if __GNUC__ < 3 -#define __builtin_expect(x, n) (x) -#endif - -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#endif - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef always_inline -#if (__GNUC__ < 3) || defined(__APPLE__) -#define always_inline inline -#else -#define always_inline __attribute__ (( always_inline )) inline -#endif -#endif - /* bottom halves */ typedef struct QEMUBH QEMUBH; diff --git a/translate-op.c b/translate-op.c index b21a52250..8104e86f2 100644 --- a/translate-op.c +++ b/translate-op.c @@ -24,6 +24,7 @@ #include #include "config.h" +#include "osdep.h" enum { #define DEF(s, n, copy_size) INDEX_op_ ## s, -- cgit v1.2.3 From 3f4afa145e4f7825c2071fab66f7ed4c7baf5e77 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Nov 2007 01:05:22 +0000 Subject: Mark hex_dump as unused to avoid compilation warnings. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3699 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.c b/vl.c index 8b2b5bdb2..6f8374028 100644 --- a/vl.c +++ b/vl.c @@ -3385,6 +3385,7 @@ void qemu_chr_close(CharDriverState *chr) /***********************************************************/ /* network device redirectors */ +__attribute__ (( unused )) static void hex_dump(FILE *f, const uint8_t *buf, int size) { int len, i, j, c; -- cgit v1.2.3 From 265531154a05a26e9b79819ddd068c285e681cbc Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Nov 2007 01:06:24 +0000 Subject: Fix attempt to inline recursive functions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3700 c046a42c-6fe2-441c-8c8c-71466251a162 --- thunk.c | 23 +++++++++++++++++++++-- thunk.h | 7 +++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/thunk.c b/thunk.c index dc9e315d7..7331aeb47 100644 --- a/thunk.c +++ b/thunk.c @@ -31,6 +31,8 @@ /* XXX: make it dynamic */ StructEntry struct_entries[MAX_STRUCTS]; +static const argtype *thunk_type_next_ptr(const argtype *type_ptr); + static inline const argtype *thunk_type_next(const argtype *type_ptr) { int type; @@ -47,9 +49,9 @@ static inline const argtype *thunk_type_next(const argtype *type_ptr) case TYPE_PTRVOID: return type_ptr; case TYPE_PTR: - return thunk_type_next(type_ptr); + return thunk_type_next_ptr(type_ptr); case TYPE_ARRAY: - return thunk_type_next(type_ptr + 1); + return thunk_type_next_ptr(type_ptr + 1); case TYPE_STRUCT: return type_ptr + 1; default: @@ -57,6 +59,11 @@ static inline const argtype *thunk_type_next(const argtype *type_ptr) } } +static const argtype *thunk_type_next_ptr(const argtype *type_ptr) +{ + return thunk_type_next(type_ptr); +} + void thunk_register_struct(int id, const char *name, const argtype *types) { const argtype *type_ptr; @@ -267,3 +274,15 @@ unsigned int host_to_target_bitmask(unsigned int alpha_mask, } return(x86_mask); } + +#ifndef NO_THUNK_TYPE_SIZE +int thunk_type_size_array(const argtype *type_ptr, int is_host) +{ + return thunk_type_size(type_ptr, is_host); +} + +int thunk_type_align_array(const argtype *type_ptr, int is_host) +{ + return thunk_type_align(type_ptr, is_host); +} +#endif /* ndef NO_THUNK_TYPE_SIZE */ diff --git a/thunk.h b/thunk.h index 4bf256a00..d650fa4c1 100644 --- a/thunk.h +++ b/thunk.h @@ -75,6 +75,9 @@ const argtype *thunk_convert(void *dst, const void *src, extern StructEntry struct_entries[]; +int thunk_type_size_array(const argtype *type_ptr, int is_host); +int thunk_type_align_array(const argtype *type_ptr, int is_host); + static inline int thunk_type_size(const argtype *type_ptr, int is_host) { int type, size; @@ -103,7 +106,7 @@ static inline int thunk_type_size(const argtype *type_ptr, int is_host) break; case TYPE_ARRAY: size = type_ptr[1]; - return size * thunk_type_size(type_ptr + 2, is_host); + return size * thunk_type_size_array(type_ptr + 2, is_host); case TYPE_STRUCT: se = struct_entries + type_ptr[1]; return se->size[is_host]; @@ -139,7 +142,7 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host) } break; case TYPE_ARRAY: - return thunk_type_align(type_ptr + 2, is_host); + return thunk_type_align_array(type_ptr + 2, is_host); case TYPE_STRUCT: se = struct_entries + type_ptr[1]; return se->align[is_host]; -- cgit v1.2.3 From 4018bae91649e8e38e371dc00cb5ac8f9e40089e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Nov 2007 01:48:12 +0000 Subject: New PowerPC CPU flag to define the decrementer and time-base source clock. Use it to properly initialize the clock for the PreP target. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3701 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_prep.c | 9 +++- target-ppc/cpu.h | 28 +++++++----- target-ppc/translate_init.c | 106 ++++++++++++++++++++++++++++---------------- 3 files changed, 90 insertions(+), 53 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 1d6634cde..d33cf5d9a 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -564,8 +564,13 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, fprintf(stderr, "Unable to find PowerPC CPU definition\n"); exit(1); } - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + if (env->flags & POWERPC_FLAG_RTC_CLK) { + /* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */ + cpu_ppc_tb_init(env, 7812500UL); + } else { + /* Set time-base frequency to 100 Mhz */ + cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + } qemu_register_reset(&cpu_ppc_reset, env); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); envs[i] = env; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3b53476a6..d2faf61e8 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -441,23 +441,27 @@ union ppc_tlb_t { #endif enum { - POWERPC_FLAG_NONE = 0x00000000, + POWERPC_FLAG_NONE = 0x00000000, /* Flag for MSR bit 25 signification (VRE/SPE) */ - POWERPC_FLAG_SPE = 0x00000001, - POWERPC_FLAG_VRE = 0x00000002, + POWERPC_FLAG_SPE = 0x00000001, + POWERPC_FLAG_VRE = 0x00000002, /* Flag for MSR bit 17 signification (TGPR/CE) */ - POWERPC_FLAG_TGPR = 0x00000004, - POWERPC_FLAG_CE = 0x00000008, + POWERPC_FLAG_TGPR = 0x00000004, + POWERPC_FLAG_CE = 0x00000008, /* Flag for MSR bit 10 signification (SE/DWE/UBLE) */ - POWERPC_FLAG_SE = 0x00000010, - POWERPC_FLAG_DWE = 0x00000020, - POWERPC_FLAG_UBLE = 0x00000040, + POWERPC_FLAG_SE = 0x00000010, + POWERPC_FLAG_DWE = 0x00000020, + POWERPC_FLAG_UBLE = 0x00000040, /* Flag for MSR bit 9 signification (BE/DE) */ - POWERPC_FLAG_BE = 0x00000080, - POWERPC_FLAG_DE = 0x00000100, + POWERPC_FLAG_BE = 0x00000080, + POWERPC_FLAG_DE = 0x00000100, /* Flag for MSR bit 2 signification (PX/PMM) */ - POWERPC_FLAG_PX = 0x00000200, - POWERPC_FLAG_PMM = 0x00000400, + POWERPC_FLAG_PX = 0x00000200, + POWERPC_FLAG_PMM = 0x00000400, + /* Flag for special features */ + /* Decrementer clock: RTC clock (POWER, 601) or bus clock */ + POWERPC_FLAG_RTC_CLK = 0x00010000, + POWERPC_FLAG_BUS_CLK = 0x00020000, }; /*****************************************************************************/ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 79d227bd2..ce0027cc3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3000,7 +3000,8 @@ static int check_pow_hid0 (CPUPPCState *env) #define POWERPC_EXCP_401 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define POWERPC_FLAG_401 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_401 check_pow_nocheck static void init_proc_401 (CPUPPCState *env) @@ -3026,7 +3027,8 @@ static void init_proc_401 (CPUPPCState *env) #define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401x2 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define POWERPC_FLAG_401x2 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_401x2 check_pow_nocheck static void init_proc_401x2 (CPUPPCState *env) @@ -3059,7 +3061,8 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) #define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401x3 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define POWERPC_FLAG_401x3 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_401x3 check_pow_nocheck __attribute__ (( unused )) @@ -3088,7 +3091,8 @@ static void init_proc_401x3 (CPUPPCState *env) #define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) #define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) -#define POWERPC_FLAG_IOP480 (POWERPC_FLAG_CE | POWERPC_FLAG_DE) +#define POWERPC_FLAG_IOP480 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_IOP480 check_pow_nocheck static void init_proc_IOP480 (CPUPPCState *env) @@ -3119,7 +3123,8 @@ static void init_proc_IOP480 (CPUPPCState *env) #define POWERPC_EXCP_403 (POWERPC_EXCP_40x) #define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403 (bfd_mach_ppc_403) -#define POWERPC_FLAG_403 (POWERPC_FLAG_CE | POWERPC_FLAG_PX) +#define POWERPC_FLAG_403 (POWERPC_FLAG_CE | POWERPC_FLAG_PX | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_403 check_pow_nocheck static void init_proc_403 (CPUPPCState *env) @@ -3149,7 +3154,8 @@ static void init_proc_403 (CPUPPCState *env) #define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) #define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) #define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) -#define POWERPC_FLAG_403GCX (POWERPC_FLAG_CE | POWERPC_FLAG_PX) +#define POWERPC_FLAG_403GCX (POWERPC_FLAG_CE | POWERPC_FLAG_PX | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_403GCX check_pow_nocheck static void init_proc_403GCX (CPUPPCState *env) @@ -3196,7 +3202,7 @@ static void init_proc_403GCX (CPUPPCState *env) #define POWERPC_INPUT_405 (PPC_FLAGS_INPUT_405) #define POWERPC_BFDM_405 (bfd_mach_ppc_403) #define POWERPC_FLAG_405 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) #define check_pow_405 check_pow_nocheck static void init_proc_405 (CPUPPCState *env) @@ -3240,7 +3246,7 @@ static void init_proc_405 (CPUPPCState *env) #define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440EP (bfd_mach_ppc_403) #define POWERPC_FLAG_440EP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) #define check_pow_440EP check_pow_nocheck __attribute__ (( unused )) @@ -3318,7 +3324,7 @@ static void init_proc_440EP (CPUPPCState *env) #define POWERPC_INPUT_440GP (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440GP (bfd_mach_ppc_403) #define POWERPC_FLAG_440GP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) #define check_pow_440GP check_pow_nocheck __attribute__ (( unused )) @@ -3377,7 +3383,7 @@ static void init_proc_440GP (CPUPPCState *env) #define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) #define POWERPC_FLAG_440x4 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) #define check_pow_440x4 check_pow_nocheck __attribute__ (( unused )) @@ -3436,7 +3442,7 @@ static void init_proc_440x4 (CPUPPCState *env) #define POWERPC_INPUT_440x5 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) #define POWERPC_FLAG_440x5 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) #define check_pow_440x5 check_pow_nocheck __attribute__ (( unused )) @@ -3514,7 +3520,7 @@ static void init_proc_440x5 (CPUPPCState *env) #define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460 (bfd_mach_ppc_403) #define POWERPC_FLAG_460 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) #define check_pow_460 check_pow_nocheck __attribute__ (( unused )) @@ -3600,7 +3606,7 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_460F (bfd_mach_ppc_403) #define POWERPC_FLAG_460F (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE) + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) #define check_pow_460F check_pow_nocheck __attribute__ (( unused )) @@ -3681,7 +3687,8 @@ static void init_proc_460F (CPUPPCState *env) #define POWERPC_EXCP_MPC5xx (POWERPC_EXCP_603) #define POWERPC_INPUT_MPC5xx (PPC_FLAGS_INPUT_RCPU) #define POWERPC_BFDM_MPC5xx (bfd_mach_ppc_505) -#define POWERPC_FLAG_MPC5xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE) +#define POWERPC_FLAG_MPC5xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_MPC5xx check_pow_none __attribute__ (( unused )) @@ -3706,7 +3713,8 @@ static void init_proc_MPC5xx (CPUPPCState *env) #define POWERPC_EXCP_MPC8xx (POWERPC_EXCP_603) #define POWERPC_INPUT_MPC8xx (PPC_FLAGS_INPUT_RCPU) #define POWERPC_BFDM_MPC8xx (bfd_mach_ppc_860) -#define POWERPC_FLAG_MPC8xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE) +#define POWERPC_FLAG_MPC8xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_MPC8xx check_pow_none __attribute__ (( unused )) @@ -3731,7 +3739,7 @@ static void init_proc_MPC8xx (CPUPPCState *env) #define POWERPC_INPUT_G2 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE) + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) #define check_pow_G2 check_pow_hid0 static void init_proc_G2 (CPUPPCState *env) @@ -3776,7 +3784,7 @@ static void init_proc_G2 (CPUPPCState *env) #define POWERPC_INPUT_G2LE (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE) + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) #define check_pow_G2LE check_pow_hid0 static void init_proc_G2LE (CPUPPCState *env) @@ -3834,7 +3842,8 @@ static void init_proc_G2LE (CPUPPCState *env) #define POWERPC_INPUT_e200 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_e200 (bfd_mach_ppc_860) #define POWERPC_FLAG_e200 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ - POWERPC_FLAG_UBLE | POWERPC_FLAG_DE) + POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_e200 check_pow_hid0 __attribute__ (( unused )) @@ -3947,7 +3956,7 @@ static void init_proc_e200 (CPUPPCState *env) #define POWERPC_INPUT_e300 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_e300 (bfd_mach_ppc_603) #define POWERPC_FLAG_e300 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE) + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) #define check_pow_e300 check_pow_hid0 __attribute__ (( unused )) @@ -3990,7 +3999,8 @@ static void init_proc_e300 (CPUPPCState *env) #define POWERPC_INPUT_e500 (PPC_FLAGS_INPUT_BookE) #define POWERPC_BFDM_e500 (bfd_mach_ppc_860) #define POWERPC_FLAG_e500 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ - POWERPC_FLAG_UBLE | POWERPC_FLAG_DE) + POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_e500 check_pow_hid0 __attribute__ (( unused )) @@ -4125,7 +4135,7 @@ static void init_proc_e500 (CPUPPCState *env) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_601 (bfd_mach_ppc_601) -#define POWERPC_FLAG_601 (POWERPC_FLAG_SE) +#define POWERPC_FLAG_601 (POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK) #define check_pow_601 check_pow_none static void init_proc_601 (CPUPPCState *env) @@ -4183,7 +4193,7 @@ static void init_proc_601 (CPUPPCState *env) #define POWERPC_INPUT_602 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_602 (bfd_mach_ppc_602) #define POWERPC_FLAG_602 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE) + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) #define check_pow_602 check_pow_hid0 static void init_proc_602 (CPUPPCState *env) @@ -4221,7 +4231,7 @@ static void init_proc_602 (CPUPPCState *env) #define POWERPC_INPUT_603 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_603 (bfd_mach_ppc_603) #define POWERPC_FLAG_603 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE) + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) #define check_pow_603 check_pow_hid0 static void init_proc_603 (CPUPPCState *env) @@ -4259,7 +4269,7 @@ static void init_proc_603 (CPUPPCState *env) #define POWERPC_INPUT_603E (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_603E (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_603E (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE) + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) #define check_pow_603E check_pow_hid0 static void init_proc_603E (CPUPPCState *env) @@ -4302,7 +4312,7 @@ static void init_proc_603E (CPUPPCState *env) #define POWERPC_INPUT_604 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_604 (bfd_mach_ppc_604) #define POWERPC_FLAG_604 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM) + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) #define check_pow_604 check_pow_nocheck static void init_proc_604 (CPUPPCState *env) @@ -4339,7 +4349,7 @@ static void init_proc_604 (CPUPPCState *env) #define POWERPC_INPUT_7x0 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7x0 (bfd_mach_ppc_750) #define POWERPC_FLAG_7x0 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM) + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) #define check_pow_7x0 check_pow_hid0 static void init_proc_7x0 (CPUPPCState *env) @@ -4378,7 +4388,7 @@ static void init_proc_7x0 (CPUPPCState *env) #define POWERPC_INPUT_750fx (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_750fx (bfd_mach_ppc_750) #define POWERPC_FLAG_750fx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM) + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) #define check_pow_750fx check_pow_hid0 static void init_proc_750fx (CPUPPCState *env) @@ -4424,7 +4434,7 @@ static void init_proc_750fx (CPUPPCState *env) #define POWERPC_INPUT_7x5 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7x5 (bfd_mach_ppc_750) #define POWERPC_FLAG_7x5 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM) + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) #define check_pow_7x5 check_pow_hid0 static void init_proc_7x5 (CPUPPCState *env) @@ -4485,7 +4495,8 @@ static void init_proc_7x5 (CPUPPCState *env) #define POWERPC_INPUT_7400 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7400 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7400 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_7400 check_pow_hid0 static void init_proc_7400 (CPUPPCState *env) @@ -4517,7 +4528,8 @@ static void init_proc_7400 (CPUPPCState *env) #define POWERPC_INPUT_7410 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7410 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7410 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_7410 check_pow_hid0 static void init_proc_7410 (CPUPPCState *env) @@ -4561,7 +4573,8 @@ static void init_proc_7410 (CPUPPCState *env) #define POWERPC_INPUT_7440 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7440 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7440 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_7440 check_pow_hid0 __attribute__ (( unused )) @@ -4632,7 +4645,8 @@ static void init_proc_7440 (CPUPPCState *env) #define POWERPC_INPUT_7450 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7450 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7450 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_7450 check_pow_hid0 __attribute__ (( unused )) @@ -4705,7 +4719,8 @@ static void init_proc_7450 (CPUPPCState *env) #define POWERPC_INPUT_7445 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7445 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7445 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_7445 check_pow_hid0 __attribute__ (( unused )) @@ -4810,7 +4825,8 @@ static void init_proc_7445 (CPUPPCState *env) #define POWERPC_INPUT_7455 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_7455 (bfd_mach_ppc_7400) #define POWERPC_FLAG_7455 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_7455 check_pow_hid0 __attribute__ (( unused )) @@ -4922,7 +4938,8 @@ static void init_proc_7455 (CPUPPCState *env) #define POWERPC_INPUT_970 (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970 (bfd_mach_ppc64) #define POWERPC_FLAG_970 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) #if defined(CONFIG_USER_ONLY) #define POWERPC970_HID5_INIT 0x00000080 @@ -5002,7 +5019,8 @@ static void init_proc_970 (CPUPPCState *env) #define POWERPC_INPUT_970FX (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970FX (bfd_mach_ppc64) #define POWERPC_FLAG_970FX (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) static int check_pow_970FX (CPUPPCState *env) { @@ -5076,7 +5094,8 @@ static void init_proc_970FX (CPUPPCState *env) #define POWERPC_INPUT_970GX (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970GX (bfd_mach_ppc64) #define POWERPC_FLAG_970GX (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) static int check_pow_970GX (CPUPPCState *env) { @@ -5150,7 +5169,8 @@ static void init_proc_970GX (CPUPPCState *env) #define POWERPC_INPUT_970MP (PPC_FLAGS_INPUT_970) #define POWERPC_BFDM_970MP (bfd_mach_ppc64) #define POWERPC_FLAG_970MP (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM) + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) static int check_pow_970MP (CPUPPCState *env) { @@ -5222,7 +5242,8 @@ static void init_proc_970MP (CPUPPCState *env) #define POWERPC_EXCP_620 (POWERPC_EXCP_970) #define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_620 (bfd_mach_ppc64) -#define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE) +#define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_BUS_CLK) #define check_pow_620 check_pow_nocheck /* Check this */ __attribute__ (( unused )) @@ -7883,6 +7904,11 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) "Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n"); exit(1); } + if ((env->flags & (POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_BUS_CLK)) == 0) { + fprintf(stderr, "PowerPC flags inconsistency\n" + "Should define the time-base and decrementer clock source\n"); + exit(1); + } /* Allocate TLBs buffer when needed */ #if !defined(CONFIG_USER_ONLY) if (env->nb_tlb != 0) { @@ -8399,6 +8425,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) printf(" performance monitor mark\n"); if (env->flags == POWERPC_FLAG_NONE) printf(" none\n"); + printf(" Time-base/decrementer clock source: %s\n", + env->flags & POWERPC_FLAG_RTC_CLK ? "RTC clock" : "bus clock"); } dump_ppc_insns(env); dump_ppc_sprs(env); -- cgit v1.2.3 From c8623f2e37ebbdde8bc6213540ebe5b6f1c6747a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Nov 2007 01:48:51 +0000 Subject: Fix another collision in PowerPC instructions definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3702 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index a6e33eb03..d7d5db26e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -499,7 +499,7 @@ enum { PPC_MEM_EIEIO = 0x0000000100000000ULL, /* Cache control instructions */ - PPC_CACHE = 0x00000002000000000ULL, + PPC_CACHE = 0x0000000200000000ULL, /* icbi instruction */ PPC_CACHE_ICBI = 0x0000000400000000ULL, /* dcbz instruction with fixed cache line size */ -- cgit v1.2.3 From 79b0241756f097c76301ce5f9b9aa7454bc04e80 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 19 Nov 2007 02:38:22 +0000 Subject: Fix typo in error message. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3703 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/stellaris.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/stellaris.c b/hw/stellaris.c index 3dbb2ced6..b7a037452 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -443,7 +443,7 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset) case 0x160: /* LDOARST */ return s->ldoarst; default: - cpu_abort(cpu_single_env, "gptm_read: Bad offset 0x%x\n", (int)offset); + cpu_abort(cpu_single_env, "ssys_read: Bad offset 0x%x\n", (int)offset); return 0; } } @@ -516,7 +516,7 @@ static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value) s->ldoarst = value; break; default: - cpu_abort(cpu_single_env, "gptm_write: Bad offset 0x%x\n", (int)offset); + cpu_abort(cpu_single_env, "ssys_write: Bad offset 0x%x\n", (int)offset); } ssys_update(s); } -- cgit v1.2.3 From 73560bc8e347e8c71bd646e977282efab204ff44 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 19 Nov 2007 03:43:51 +0000 Subject: Clean-up/rewrite audio over I^2S support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3704 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 282 +++++++++++++++++++++++++++++++++++++++-------------------- hw/omap.h | 5 ++ hw/tsc210x.c | 50 +++++++---- 3 files changed, 227 insertions(+), 110 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index 1e79831d8..662332b7c 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -997,7 +997,8 @@ static void omap_dma_clk_update(void *opaque, int line, int on) struct omap_dma_s *s = (struct omap_dma_s *) opaque; if (on) { - s->delay = ticks_per_sec >> 7; + /* TODO: make a clever calculation */ + s->delay = ticks_per_sec >> 8; if (s->run_count) qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); } else { @@ -4097,8 +4098,11 @@ struct omap_mcbsp_s { int tx_rate; int rx_rate; int tx_req; + int rx_req; struct i2s_codec_s *codec; + QEMUTimer *source_timer; + QEMUTimer *sink_timer; }; static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) @@ -4134,88 +4138,149 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) qemu_set_irq(s->txirq, irq); } -static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) +static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) { - int prev = s->tx_req; - - s->tx_req = (s->tx_rate || - (s->spcr[0] & (1 << 12))) && /* CLKSTP */ - (s->spcr[1] & (1 << 6)) && /* GRST */ - (s->spcr[1] & (1 << 0)); /* XRST */ - - if (!s->tx_req && prev) { - s->spcr[1] &= ~(1 << 1); /* XRDY */ - qemu_irq_lower(s->txdrq); - omap_mcbsp_intr_update(s); - - if (s->codec) - s->codec->tx_swallow(s->codec->opaque); - } else if (s->codec && s->tx_req && !prev) { - s->spcr[1] |= 1 << 1; /* XRDY */ - qemu_irq_raise(s->txdrq); - omap_mcbsp_intr_update(s); - } + if ((s->spcr[0] >> 1) & 1) /* RRDY */ + s->spcr[0] |= 1 << 2; /* RFULL */ + s->spcr[0] |= 1 << 1; /* RRDY */ + qemu_irq_raise(s->rxdrq); + omap_mcbsp_intr_update(s); } -static void omap_mcbsp_rate_update(struct omap_mcbsp_s *s) +static void omap_mcbsp_source_tick(void *opaque) { - int rx_clk = 0, tx_clk = 0; - int cpu_rate = 1500000; /* XXX */ - if (!s->codec) + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; + + if (!s->rx_rate) return; + if (s->rx_req) + printf("%s: Rx FIFO overrun\n", __FUNCTION__); - if (s->spcr[1] & (1 << 6)) { /* GRST */ - if (s->spcr[0] & (1 << 0)) /* RRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 8))) /* CLKRM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ - rx_clk = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ - if (s->spcr[1] & (1 << 0)) /* XRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 9))) /* CLKXM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ - tx_clk = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ - } + s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; - s->codec->set_rate(s->codec->opaque, rx_clk, tx_clk); + omap_mcbsp_rx_newdata(s); + qemu_mod_timer(s->source_timer, qemu_get_clock(vm_clock) + ticks_per_sec); } static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) { - if (!(s->spcr[0] & 1)) { /* RRST */ - if (s->codec) - s->codec->in.len = 0; - return; + if (!s->codec || !s->codec->rts) + omap_mcbsp_source_tick(s); + else if (s->codec->in.len) { + s->rx_req = s->codec->in.len; + omap_mcbsp_rx_newdata(s); } - - if ((s->spcr[0] >> 1) & 1) /* RRDY */ - s->spcr[0] |= 1 << 2; /* RFULL */ - s->spcr[0] |= 1 << 1; /* RRDY */ - qemu_irq_raise(s->rxdrq); - omap_mcbsp_intr_update(s); } static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) +{ + qemu_del_timer(s->source_timer); +} + +static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) { s->spcr[0] &= ~(1 << 1); /* RRDY */ qemu_irq_lower(s->rxdrq); omap_mcbsp_intr_update(s); } -static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) +static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) +{ + s->spcr[1] |= 1 << 1; /* XRDY */ + qemu_irq_raise(s->txdrq); + omap_mcbsp_intr_update(s); +} + +static void omap_mcbsp_sink_tick(void *opaque) { - if (s->tx_rate) + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; + + if (!s->tx_rate) return; - s->tx_rate = 1; - omap_mcbsp_req_update(s); + if (s->tx_req) + printf("%s: Tx FIFO underrun\n", __FUNCTION__); + + s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; + + omap_mcbsp_tx_newdata(s); + qemu_mod_timer(s->sink_timer, qemu_get_clock(vm_clock) + ticks_per_sec); +} + +static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) +{ + if (!s->codec || !s->codec->cts) + omap_mcbsp_sink_tick(s); + else if (s->codec->out.size) { + s->tx_req = s->codec->out.size; + omap_mcbsp_tx_newdata(s); + } +} + +static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) +{ + s->spcr[1] &= ~(1 << 1); /* XRDY */ + qemu_irq_lower(s->txdrq); + omap_mcbsp_intr_update(s); + if (s->codec && s->codec->cts) + s->codec->tx_swallow(s->codec->opaque); } static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) { - s->tx_rate = 0; - omap_mcbsp_req_update(s); + s->tx_req = 0; + omap_mcbsp_tx_done(s); + qemu_del_timer(s->sink_timer); +} + +static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) +{ + int prev_rx_rate, prev_tx_rate; + int rx_rate = 0, tx_rate = 0; + int cpu_rate = 1500000; /* XXX */ + + /* TODO: check CLKSTP bit */ + if (s->spcr[1] & (1 << 6)) { /* GRST */ + if (s->spcr[0] & (1 << 0)) { /* RRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 8))) { /* CLKRM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ + rx_rate = cpu_rate / + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + } else + if (s->codec) + rx_rate = s->codec->rx_rate; + } + + if (s->spcr[1] & (1 << 0)) { /* XRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 9))) { /* CLKXM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ + tx_rate = cpu_rate / + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + } else + if (s->codec) + tx_rate = s->codec->tx_rate; + } + } + prev_tx_rate = s->tx_rate; + prev_rx_rate = s->rx_rate; + s->tx_rate = tx_rate; + s->rx_rate = rx_rate; + + if (s->codec) + s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate); + + if (!prev_tx_rate && tx_rate) + omap_mcbsp_tx_start(s); + else if (s->tx_rate && !tx_rate) + omap_mcbsp_tx_stop(s); + + if (!prev_rx_rate && rx_rate) + omap_mcbsp_rx_start(s); + else if (prev_tx_rate && !tx_rate) + omap_mcbsp_rx_stop(s); } static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) @@ -4230,17 +4295,19 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) return 0x0000; /* Fall through. */ case 0x02: /* DRR1 */ - if (!s->codec) - return 0x0000; - if (s->codec->in.len < 2) { + if (s->rx_req < 2) { printf("%s: Rx FIFO underrun\n", __FUNCTION__); - omap_mcbsp_rx_stop(s); + omap_mcbsp_rx_done(s); } else { - s->codec->in.len -= 2; - ret = s->codec->in.fifo[s->codec->in.start ++] << 8; - ret |= s->codec->in.fifo[s->codec->in.start ++]; - if (!s->codec->in.len) - omap_mcbsp_rx_stop(s); + s->tx_req -= 2; + if (s->codec && s->codec->in.len >= 2) { + ret = s->codec->in.fifo[s->codec->in.start ++] << 8; + ret |= s->codec->in.fifo[s->codec->in.start ++]; + s->codec->in.len -= 2; + } else + ret = 0x0000; + if (!s->tx_req) + omap_mcbsp_rx_done(s); return ret; } return 0x0000; @@ -4309,7 +4376,7 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) return 0; } -static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, +static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; @@ -4326,18 +4393,14 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, return; /* Fall through. */ case 0x06: /* DXR1 */ - if (!s->codec) - return; - if (s->tx_req) { - if (s->codec->out.len > s->codec->out.size - 2) { - printf("%s: Tx FIFO overrun\n", __FUNCTION__); - omap_mcbsp_tx_stop(s); - } else { + if (s->tx_req > 1) { + s->tx_req -= 2; + if (s->codec && s->codec->cts) { s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; - if (s->codec->out.len >= s->codec->out.size) - omap_mcbsp_tx_stop(s); } + if (s->tx_req < 2) + omap_mcbsp_tx_done(s); } else printf("%s: Tx FIFO overrun\n", __FUNCTION__); return; @@ -4346,14 +4409,8 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, s->spcr[1] &= 0x0002; s->spcr[1] |= 0x03f9 & value; s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ - if (~value & 1) { /* XRST */ + if (~value & 1) /* XRST */ s->spcr[1] &= ~6; - qemu_irq_lower(s->rxdrq); - if (s->codec) - s->codec->out.len = 0; - } - if (s->codec) - omap_mcbsp_rate_update(s); omap_mcbsp_req_update(s); return; case 0x0a: /* SPCR1 */ @@ -4363,12 +4420,9 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); if (~value & 1) { /* RRST */ s->spcr[0] &= ~6; - qemu_irq_lower(s->txdrq); - if (s->codec) - s->codec->in.len = 0; + s->rx_req = 0; + omap_mcbsp_rx_done(s); } - if (s->codec) - omap_mcbsp_rate_update(s); omap_mcbsp_req_update(s); return; @@ -4386,11 +4440,11 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, return; case 0x14: /* SRGR2 */ s->srgr[1] = value & 0xffff; - omap_mcbsp_rate_update(s); + omap_mcbsp_req_update(s); return; case 0x16: /* SRGR1 */ s->srgr[0] = value & 0xffff; - omap_mcbsp_rate_update(s); + omap_mcbsp_req_update(s); return; case 0x18: /* MCR2 */ s->mcr[1] = value & 0x03e3; @@ -4460,6 +4514,37 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, OMAP_BAD_REG(addr); } +static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + if (offset == 0x04) { /* DXR */ + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ + return; + if (s->tx_req > 3) { + s->tx_req -= 4; + if (s->codec && s->codec->cts) { + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 24) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 16) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 8) & 0xff; + s->codec->out.fifo[s->codec->out.len ++] = + (value >> 0) & 0xff; + } + if (s->tx_req < 4) + omap_mcbsp_tx_done(s); + } else + printf("%s: Tx FIFO overrun\n", __FUNCTION__); + return; + } + + omap_badwidth_write16(opaque, addr, value); +} + static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { omap_badwidth_read16, omap_mcbsp_read, @@ -4468,8 +4553,8 @@ static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = { omap_badwidth_write16, - omap_mcbsp_write, - omap_badwidth_write16, + omap_mcbsp_writeh, + omap_mcbsp_writew, }; static void omap_mcbsp_reset(struct omap_mcbsp_s *s) @@ -4484,8 +4569,11 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s) memset(&s->rcer, 0, sizeof(s->rcer)); memset(&s->xcer, 0, sizeof(s->xcer)); s->tx_req = 0; + s->rx_req = 0; s->tx_rate = 0; s->rx_rate = 0; + qemu_del_timer(s->source_timer); + qemu_del_timer(s->sink_timer); } struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, @@ -4500,6 +4588,8 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, s->rxirq = irq[1]; s->txdrq = dma[0]; s->rxdrq = dma[1]; + s->sink_timer = qemu_new_timer(vm_clock, omap_mcbsp_sink_tick, s); + s->source_timer = qemu_new_timer(vm_clock, omap_mcbsp_source_tick, s); omap_mcbsp_reset(s); iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, @@ -4513,14 +4603,20 @@ static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - omap_mcbsp_rx_start(s); + if (s->rx_rate) { + s->rx_req = s->codec->in.len; + omap_mcbsp_rx_newdata(s); + } } static void omap_mcbsp_i2s_start(void *opaque, int line, int level) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; - omap_mcbsp_tx_start(s); + if (s->tx_rate) { + s->tx_req = s->codec->out.size; + omap_mcbsp_tx_newdata(s); + } } void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) diff --git a/hw/omap.h b/hw/omap.h index c31503094..e58fb3c24 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -491,6 +491,11 @@ struct i2s_codec_s { qemu_irq rx_swallow; qemu_irq tx_start; + int tx_rate; + int cts; + int rx_rate; + int rts; + struct i2s_fifo_s { uint8_t *fifo; int len; diff --git a/hw/tsc210x.c b/hw/tsc210x.c index f04b19d33..6082aa0b9 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -283,10 +283,30 @@ static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b) qemu_irq_raise(s->codec.tx_start); } -static void tsc2102_audio_set_format(struct tsc210x_state_s *s) +static void tsc2102_audio_rate_update(struct tsc210x_state_s *s) { - int enable; const struct tsc210x_rate_info_s *rate; + + s->codec.tx_rate = 0; + s->codec.rx_rate = 0; + if (s->dac_power & (1 << 15)) /* PWDNC */ + return; + + for (rate = tsc2102_rates; rate->rate; rate ++) + if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ + rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ + break; + if (!rate->rate) { + printf("%s: unknown sampling rate configured\n", __FUNCTION__); + return; + } + + s->codec.tx_rate = rate->rate; +} + +static void tsc2102_audio_output_update(struct tsc210x_state_s *s) +{ + int enable; audsettings_t fmt; if (s->dac_voice[0]) { @@ -296,32 +316,26 @@ static void tsc2102_audio_set_format(struct tsc210x_state_s *s) AUD_close_out(&s->card, s->dac_voice[0]); s->dac_voice[0] = 0; } + s->codec.cts = 0; enable = (~s->dac_power & (1 << 15)) && /* PWDNC */ (~s->dac_power & (1 << 10)); /* DAPWDN */ - if (!enable) - return; - - for (rate = tsc2102_rates; rate->rate; rate ++) - if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ - rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ - break; - if (!rate->rate) { - printf("%s: unknown sampling rate configured\n", __FUNCTION__); + if (!enable || !s->codec.tx_rate) return; - } /* Force our own sampling rate even in slave DAC mode */ fmt.endianness = 0; fmt.nchannels = 2; - fmt.freq = rate->rate; + fmt.freq = s->codec.tx_rate; fmt.fmt = AUD_FMT_S16; s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt); - if (s->dac_voice[0]) + if (s->dac_voice[0]) { + s->codec.cts = 1; AUD_set_active_out(s->dac_voice[0], 1); + } } static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) @@ -587,8 +601,9 @@ static void tsc2102_audio_register_write( fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Audio 1\n"); #endif + tsc2102_audio_rate_update(s); if (s->audio) - tsc2102_audio_set_format(s); + tsc2102_audio_output_update(s); return; case 0x01: @@ -631,8 +646,9 @@ static void tsc2102_audio_register_write( fprintf(stderr, "tsc2102_audio_register_write: " "wrong value written into Power\n"); #endif + tsc2102_audio_rate_update(s); if (s->audio) - tsc2102_audio_set_format(s); + tsc2102_audio_output_update(s); return; case 0x06: /* Audio Control 3 */ @@ -644,7 +660,7 @@ static void tsc2102_audio_register_write( "wrong value written into Audio 3\n"); #endif if (s->audio) - tsc2102_audio_set_format(s); + tsc2102_audio_output_update(s); return; case 0x07: /* LCH_BASS_BOOST_N0 */ -- cgit v1.2.3 From 5b8105fa50b0dfde4ac49d7b1dd8044fb82caec6 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Nov 2007 11:39:29 +0000 Subject: PowerPC instruction fixes: - hrfid is part of the hypervisor extension - fix stfiwx naming git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3705 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_mem.h | 12 ++++++------ target-ppc/translate.c | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index 971cc1838..a1b3e36c2 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -414,7 +414,7 @@ static always_inline void glue(stfs, MEMSUFFIX) (target_ulong EA, double d) #define WORD0 1 #define WORD1 0 #endif -static always_inline void glue(stfiwx, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfiw, MEMSUFFIX) (target_ulong EA, double d) { union { double d; @@ -430,11 +430,11 @@ static always_inline void glue(stfiwx, MEMSUFFIX) (target_ulong EA, double d) PPC_STF_OP(fd, stfq); PPC_STF_OP(fs, stfs); -PPC_STF_OP(fiwx, stfiwx); +PPC_STF_OP(fiw, stfiw); #if defined(TARGET_PPC64) PPC_STF_OP_64(fd, stfq); PPC_STF_OP_64(fs, stfs); -PPC_STF_OP_64(fiwx, stfiwx); +PPC_STF_OP_64(fiw, stfiw); #endif static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) @@ -471,7 +471,7 @@ static always_inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, double d) glue(stfl, MEMSUFFIX)(EA, u.f); } -static always_inline void glue(stfiwxr, MEMSUFFIX) (target_ulong EA, double d) +static always_inline void glue(stfiwr, MEMSUFFIX) (target_ulong EA, double d) { union { double d; @@ -489,11 +489,11 @@ static always_inline void glue(stfiwxr, MEMSUFFIX) (target_ulong EA, double d) PPC_STF_OP(fd_le, stfqr); PPC_STF_OP(fs_le, stfsr); -PPC_STF_OP(fiwx_le, stfiwxr); +PPC_STF_OP(fiw_le, stfiwr); #if defined(TARGET_PPC64) PPC_STF_OP_64(fd_le, stfqr); PPC_STF_OP_64(fs_le, stfsr); -PPC_STF_OP_64(fiwx_le, stfiwxr); +PPC_STF_OP_64(fiw_le, stfiwr); #endif /*** Floating-point load ***/ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d7d5db26e..45e8d1b89 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2764,8 +2764,8 @@ GEN_STFS(fs, 0x14, PPC_FLOAT); /* Optional: */ /* stfiwx */ -OP_ST_TABLE(fiwx); -GEN_STXF(fiwx, 0x17, 0x1E, PPC_FLOAT_STFIWX); +OP_ST_TABLE(fiw); +GEN_STXF(fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX); /*** Branch ***/ static always_inline void gen_goto_tb (DisasContext *ctx, int n, @@ -3088,7 +3088,7 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B) #endif } -GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64B) +GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H) { #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); -- cgit v1.2.3 From add78955b0451c6d14d325d66592a634b2e5d595 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Nov 2007 11:41:10 +0000 Subject: PowerPC 620 MMU do not have the same exact behavior as standard 64 bits PowerPC ones. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3706 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 27 +++++++++++++++------------ target-ppc/helper.c | 41 ++++++++++++++++++++++++++++++++--------- target-ppc/translate_init.c | 9 ++++++--- 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index d2faf61e8..6f3ff86a1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -93,30 +93,33 @@ typedef uint32_t ppc_gpr_t; /* MMU model */ typedef enum powerpc_mmu_t powerpc_mmu_t; enum powerpc_mmu_t { - POWERPC_MMU_UNKNOWN = 0, + POWERPC_MMU_UNKNOWN = 0x00000000, /* Standard 32 bits PowerPC MMU */ - POWERPC_MMU_32B, + POWERPC_MMU_32B = 0x00000001, /* PowerPC 6xx MMU with software TLB */ - POWERPC_MMU_SOFT_6xx, + POWERPC_MMU_SOFT_6xx = 0x00000002, /* PowerPC 74xx MMU with software TLB */ - POWERPC_MMU_SOFT_74xx, + POWERPC_MMU_SOFT_74xx = 0x00000003, /* PowerPC 4xx MMU with software TLB */ - POWERPC_MMU_SOFT_4xx, + POWERPC_MMU_SOFT_4xx = 0x00000004, /* PowerPC 4xx MMU with software TLB and zones protections */ - POWERPC_MMU_SOFT_4xx_Z, + POWERPC_MMU_SOFT_4xx_Z = 0x00000005, /* PowerPC MMU in real mode only */ - POWERPC_MMU_REAL, + POWERPC_MMU_REAL = 0x00000006, /* Freescale MPC8xx MMU model */ - POWERPC_MMU_MPC8xx, + POWERPC_MMU_MPC8xx = 0x00000007, /* BookE MMU model */ - POWERPC_MMU_BOOKE, + POWERPC_MMU_BOOKE = 0x00000008, /* BookE FSL MMU model */ - POWERPC_MMU_BOOKE_FSL, + POWERPC_MMU_BOOKE_FSL = 0x00000009, /* PowerPC 601 MMU model (specific BATs format) */ - POWERPC_MMU_601, + POWERPC_MMU_601 = 0x0000000A, #if defined(TARGET_PPC64) +#define POWERPC_MMU_64 0x00010000 /* 64 bits PowerPC MMU */ - POWERPC_MMU_64B, + POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001, + /* 620 variant (no segment exceptions) */ + POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002, #endif /* defined(TARGET_PPC64) */ }; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b4c38395f..cb9b778cc 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -706,7 +706,7 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw, int type) { #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) + if (env->mmu_model & POWERPC_MMU_64) return find_pte64(ctx, h, rw, type); #endif @@ -916,7 +916,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, pr = msr_pr; #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) { + if (env->mmu_model & POWERPC_MMU_64) { #if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "Check SLBs\n"); @@ -973,7 +973,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, sdr = env->sdr1; pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS; #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) { + if (env->mmu_model & POWERPC_MMU_64) { htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F)); /* XXX: this is false for 1 TB segments */ hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; @@ -1002,7 +1002,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, #endif ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask); #if defined(TARGET_PPC64) - if (env->mmu_model == POWERPC_MMU_64B) { + if (env->mmu_model & POWERPC_MMU_64) { /* Only 5 bits of the page index are used in the AVPN */ ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); } else @@ -1362,6 +1362,7 @@ static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx, ctx->prot |= PAGE_WRITE; break; #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: /* Real address are 60 bits long */ ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL; @@ -1430,6 +1431,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, case POWERPC_MMU_SOFT_6xx: case POWERPC_MMU_SOFT_74xx: #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif /* Try to find a BAT */ @@ -1538,6 +1540,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, case POWERPC_MMU_32B: case POWERPC_MMU_601: #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif env->exception_index = POWERPC_EXCP_ISI; @@ -1583,8 +1586,14 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if defined(TARGET_PPC64) case -5: /* No match in segment table */ - env->exception_index = POWERPC_EXCP_ISEG; - env->error_code = 0; + if (env->mmu_model == POWERPC_MMU_620) { + env->exception_index = POWERPC_EXCP_ISI; + /* XXX: this might be incorrect */ + env->error_code = 0x40000000; + } else { + env->exception_index = POWERPC_EXCP_ISEG; + env->error_code = 0; + } break; #endif } @@ -1634,6 +1643,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, case POWERPC_MMU_32B: case POWERPC_MMU_601: #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif env->exception_index = POWERPC_EXCP_DSI; @@ -1716,9 +1726,20 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #if defined(TARGET_PPC64) case -5: /* No match in segment table */ - env->exception_index = POWERPC_EXCP_DSEG; - env->error_code = 0; - env->spr[SPR_DAR] = address; + if (env->mmu_model == POWERPC_MMU_620) { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = address; + /* XXX: this might be incorrect */ + if (rw == 1) + env->spr[SPR_DSISR] = 0x42000000; + else + env->spr[SPR_DSISR] = 0x40000000; + } else { + env->exception_index = POWERPC_EXCP_DSEG; + env->error_code = 0; + env->spr[SPR_DAR] = address; + } break; #endif } @@ -1955,6 +1976,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) case POWERPC_MMU_32B: case POWERPC_MMU_601: #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: #endif /* defined(TARGET_PPC64) */ tlb_flush(env, 1); @@ -2021,6 +2043,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) tlb_flush_page(env, addr | (0xF << 28)); break; #if defined(TARGET_PPC64) + case POWERPC_MMU_620: case POWERPC_MMU_64B: /* tlbie invalidate TLBs for all segments */ /* XXX: given the fact that there are too many segments to invalidate, diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ce0027cc3..f3bc1f5f7 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -5237,13 +5237,13 @@ static void init_proc_970MP (CPUPPCState *env) /* PowerPC 620 */ #define POWERPC_INSNS_620 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ PPC_64B | PPC_SLBI) -#define POWERPC_MSRM_620 (0x800000000005FF73ULL) -#define POWERPC_MMU_620 (POWERPC_MMU_64B) +#define POWERPC_MSRM_620 (0x800000000005FF77ULL) +//#define POWERPC_MMU_620 (POWERPC_MMU_620) #define POWERPC_EXCP_620 (POWERPC_EXCP_970) #define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_620 (bfd_mach_ppc64) #define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_BUS_CLK) + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) #define check_pow_620 check_pow_nocheck /* Check this */ __attribute__ (( unused )) @@ -8313,6 +8313,9 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) case POWERPC_MMU_64B: mmu_model = "PowerPC 64"; break; + case POWERPC_MMU_620: + mmu_model = "PowerPC 620"; + break; #endif default: mmu_model = "Unknown or invalid"; -- cgit v1.2.3 From 082c6681b6c4af0035d9dad34a4a784be8c21dbe Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 19 Nov 2007 13:22:47 +0000 Subject: Remove shared macro used to define PowerPC implementations instructions sets: tend more to propagate bugged definition than simplify the code. Check and fix PowerPC 6xx implementations definitions. Misc fixes in PowerPC CPU list. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3707 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 11 +- target-ppc/translate_init.c | 652 ++++++++++++++++++++++++++++++++------------ 2 files changed, 489 insertions(+), 174 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6f3ff86a1..7cbc8da51 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1040,9 +1040,11 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_RCPU_MI_RBA2 (0x302) #define SPR_MPC_MI_AP (0x302) #define SPR_PERF3 (0x303) +#define SPR_620_PMC1R (0x303) #define SPR_RCPU_MI_RBA3 (0x303) #define SPR_MPC_MI_EPN (0x303) #define SPR_PERF4 (0x304) +#define SPR_620_PMC2R (0x304) #define SPR_PERF5 (0x305) #define SPR_MPC_MI_TWC (0x305) #define SPR_PERF6 (0x306) @@ -1058,6 +1060,7 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_RCPU_L2U_RBA2 (0x30A) #define SPR_MPC_MD_AP (0x30A) #define SPR_PERFB (0x30B) +#define SPR_620_MMCR0R (0x30B) #define SPR_RCPU_L2U_RBA3 (0x30B) #define SPR_MPC_MD_EPN (0x30B) #define SPR_PERFC (0x30C) @@ -1072,7 +1075,9 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_UPERF1 (0x311) #define SPR_UPERF2 (0x312) #define SPR_UPERF3 (0x313) +#define SPR_620_PMC1W (0x313) #define SPR_UPERF4 (0x314) +#define SPR_620_PMC2W (0x314) #define SPR_UPERF5 (0x315) #define SPR_UPERF6 (0x316) #define SPR_UPERF7 (0x317) @@ -1080,6 +1085,7 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_UPERF9 (0x319) #define SPR_UPERFA (0x31A) #define SPR_UPERFB (0x31B) +#define SPR_620_MMCR0W (0x31B) #define SPR_UPERFC (0x31C) #define SPR_UPERFD (0x31D) #define SPR_UPERFE (0x31E) @@ -1245,13 +1251,14 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_LDSTCR (0x3F8) #define SPR_L2PMCR (0x3F8) #define SPR_750_HID2 (0x3F8) -#define SPR_620_HID8 (0x3F8) +#define SPR_620_BUSCSR (0x3F8) #define SPR_Exxx_L1FINV0 (0x3F8) #define SPR_L2CR (0x3F9) -#define SPR_620_HID9 (0x3F9) +#define SPR_620_L2CR (0x3F9) #define SPR_L3CR (0x3FA) #define SPR_IABR2 (0x3FA) #define SPR_40x_DCCR (0x3FA) +#define SPR_620_L2SR (0x3FA) #define SPR_ICTC (0x3FB) #define SPR_40x_ICCR (0x3FB) #define SPR_THRM1 (0x3FC) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f3bc1f5f7..ad1152971 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -281,13 +281,11 @@ static void spr_write_sdr1 (void *opaque, int sprn) /* 64 bits PowerPC specific SPRs */ /* ASR */ #if defined(TARGET_PPC64) -__attribute__ (( unused )) static void spr_read_asr (void *opaque, int sprn) { gen_op_load_asr(); } -__attribute__ (( unused )) static void spr_write_asr (void *opaque, int sprn) { gen_op_store_asr(); @@ -924,11 +922,6 @@ static void gen_spr_604 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_MMCR1, "MMCR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_PMC1, "PMC1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -939,16 +932,6 @@ static void gen_spr_604 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_PMC3, "PMC3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_PMC4, "PMC4", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_SIAR, "SIAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, @@ -2008,6 +1991,70 @@ static void gen_spr_compress (CPUPPCState *env) /* SPR specific to PowerPC 620 */ static void gen_spr_620 (CPUPPCState *env) { + /* Processor identification */ + spr_register(env, SPR_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + spr_register(env, SPR_ASR, "ASR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_asr, &spr_write_asr, + 0x00000000); + /* Breakpoints */ + /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_SIAR, "SIAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_SDA, "SDA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_620_PMC1R, "PMC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_620_PMC1W, "PMC1", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_620_PMC2R, "PMC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_620_PMC2W, "PMC2", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_620_MMCR0R, "MMCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_620_MMCR0W, "MMCR0", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +#if 0 // XXX: check this /* XXX : not implemented */ spr_register(env, SPR_620_PMR0, "PMR0", SPR_NOACCESS, SPR_NOACCESS, @@ -2088,13 +2135,19 @@ static void gen_spr_620 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); +#endif /* XXX : not implemented */ - spr_register(env, SPR_620_HID8, "HID8", + spr_register(env, SPR_620_BUSCSR, "BUSCSR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_620_HID9, "HID9", + spr_register(env, SPR_620_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_620_L2SR, "L2SR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -2704,6 +2757,7 @@ static void init_excp_601 (CPUPPCState *env) static void init_excp_602 (CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) + /* XXX: exception prefix has a special behavior on 602 */ env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; @@ -2715,7 +2769,6 @@ static void init_excp_602 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_FPA] = 0x00000E00; env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; @@ -2784,9 +2837,7 @@ static void init_excp_620 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_DSEG] = 0x00000380; env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_ISEG] = 0x00000480; env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; @@ -2794,7 +2845,6 @@ static void init_excp_620 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_FPA] = 0x00000E00; env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; @@ -2987,14 +3037,13 @@ static int check_pow_hid0 (CPUPPCState *env) /*****************************************************************************/ /* PowerPC implementations definitions */ -/* PowerPC 40x instruction set */ -#define POWERPC_INSNS_EMB (PPC_INSNS_BASE | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ) - /* PowerPC 401 */ -#define POWERPC_INSNS_401 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ +#define POWERPC_INSNS_401 (PPC_INSNS_BASE | PPC_STRING | \ + PPC_WRTEE | PPC_DCR | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ + PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) + PPC_4xx_COMMON | PPC_40x_EXCP) #define POWERPC_MSRM_401 (0x00000000000FD201ULL) #define POWERPC_MMU_401 (POWERPC_MMU_REAL) #define POWERPC_EXCP_401 (POWERPC_EXCP_40x) @@ -3017,11 +3066,13 @@ static void init_proc_401 (CPUPPCState *env) } /* PowerPC 401x2 */ -#define POWERPC_INSNS_401x2 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ +#define POWERPC_INSNS_401x2 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_DCR | PPC_WRTEE | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_CACHE_DCBA | PPC_MFTB | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) + PPC_4xx_COMMON | PPC_40x_EXCP) #define POWERPC_MSRM_401x2 (0x00000000001FD231ULL) #define POWERPC_MMU_401x2 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) @@ -3051,11 +3102,13 @@ static void init_proc_401x2 (CPUPPCState *env) } /* PowerPC 401x3 */ -#define POWERPC_INSNS_401x3 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ +#define POWERPC_INSNS_401x3 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_DCR | PPC_WRTEE | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_CACHE_DCBA | PPC_MFTB | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) + PPC_4xx_COMMON | PPC_40x_EXCP) #define POWERPC_MSRM_401x3 (0x00000000001FD631ULL) #define POWERPC_MMU_401x3 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) @@ -3081,11 +3134,13 @@ static void init_proc_401x3 (CPUPPCState *env) } /* IOP480 */ -#define POWERPC_INSNS_IOP480 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ +#define POWERPC_INSNS_IOP480 (PPC_INSNS_BASE | PPC_STRING | \ + PPC_DCR | PPC_WRTEE | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_CACHE_DCBA | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) + PPC_4xx_COMMON | PPC_40x_EXCP) #define POWERPC_MSRM_IOP480 (0x00000000001FD231ULL) #define POWERPC_MMU_IOP480 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) @@ -3115,9 +3170,12 @@ static void init_proc_IOP480 (CPUPPCState *env) } /* PowerPC 403 */ -#define POWERPC_INSNS_403 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ +#define POWERPC_INSNS_403 (PPC_INSNS_BASE | PPC_STRING | \ + PPC_DCR | PPC_WRTEE | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ + PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) + PPC_4xx_COMMON | PPC_40x_EXCP) #define POWERPC_MSRM_403 (0x000000000007D00DULL) #define POWERPC_MMU_403 (POWERPC_MMU_REAL) #define POWERPC_EXCP_403 (POWERPC_EXCP_40x) @@ -3145,10 +3203,13 @@ static void init_proc_403 (CPUPPCState *env) } /* PowerPC 403 GCX */ -#define POWERPC_INSNS_403GCX (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ +#define POWERPC_INSNS_403GCX (PPC_INSNS_BASE | PPC_STRING | \ + PPC_DCR | PPC_WRTEE | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ + PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT) + PPC_4xx_COMMON | PPC_40x_EXCP) #define POWERPC_MSRM_403GCX (0x000000000007D00DULL) #define POWERPC_MMU_403GCX (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) @@ -3190,12 +3251,13 @@ static void init_proc_403GCX (CPUPPCState *env) } /* PowerPC 405 */ -#define POWERPC_INSNS_405 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_MFTB | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_CACHE_DCBA | \ +#define POWERPC_INSNS_405 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_DCR | PPC_WRTEE | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT | \ - PPC_405_MAC) + PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP) #define POWERPC_MSRM_405 (0x000000000006E630ULL) #define POWERPC_MMU_405 (POWERPC_MMU_SOFT_4xx) #define POWERPC_EXCP_405 (POWERPC_EXCP_40x) @@ -3236,10 +3298,13 @@ static void init_proc_405 (CPUPPCState *env) } /* PowerPC 440 EP */ -#define POWERPC_INSNS_440EP (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ +#define POWERPC_INSNS_440EP (PPC_INSNS_BASE | PPC_STRING | \ + PPC_DCR | PPC_WRTEE | PPC_RFMCI | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_MEM_TLBSYNC | \ PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC | PPC_RFMCI) + PPC_440_SPEC) #define POWERPC_MSRM_440EP (0x000000000006D630ULL) #define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) @@ -3313,11 +3378,13 @@ static void init_proc_440EP (CPUPPCState *env) } /* PowerPC 440 GP */ -#define POWERPC_INSNS_440GP (POWERPC_INSNS_EMB | PPC_STRING | \ - PPC_DCR | PPC_DCRX | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ - PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) +#define POWERPC_INSNS_440GP (PPC_INSNS_BASE | PPC_STRING | \ + PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_MEM_TLBSYNC | PPC_TLBIVA | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC) #define POWERPC_MSRM_440GP (0x000000000006FF30ULL) #define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) @@ -3373,8 +3440,11 @@ static void init_proc_440GP (CPUPPCState *env) } /* PowerPC 440x4 */ -#define POWERPC_INSNS_440x4 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ +#define POWERPC_INSNS_440x4 (PPC_INSNS_BASE | PPC_STRING | \ + PPC_DCR | PPC_WRTEE | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_MEM_TLBSYNC | \ PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ PPC_440_SPEC) #define POWERPC_MSRM_440x4 (0x000000000006FF30ULL) @@ -3432,10 +3502,13 @@ static void init_proc_440x4 (CPUPPCState *env) } /* PowerPC 440x5 */ -#define POWERPC_INSNS_440x5 (POWERPC_INSNS_EMB | PPC_STRING | PPC_DCR | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ +#define POWERPC_INSNS_440x5 (PPC_INSNS_BASE | PPC_STRING | \ + PPC_DCR | PPC_WRTEE | PPC_RFMCI | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_MEM_TLBSYNC | \ PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC | PPC_RFMCI) + PPC_440_SPEC) #define POWERPC_MSRM_440x5 (0x000000000006FF30ULL) #define POWERPC_MMU_440x5 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) @@ -3509,11 +3582,14 @@ static void init_proc_440x5 (CPUPPCState *env) } /* PowerPC 460 (guessed) */ -#define POWERPC_INSNS_460 (POWERPC_INSNS_EMB | PPC_STRING | \ +#define POWERPC_INSNS_460 (PPC_INSNS_BASE | PPC_STRING | \ PPC_DCR | PPC_DCRX | PPC_DCRUX | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ - PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) + PPC_WRTEE | PPC_MFAPIDI | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_MEM_TLBSYNC | PPC_TLBIVA | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC) #define POWERPC_MSRM_460 (0x000000000006FF30ULL) #define POWERPC_MMU_460 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) @@ -3592,14 +3668,17 @@ static void init_proc_460 (CPUPPCState *env) } /* PowerPC 460F (guessed) */ -#define POWERPC_INSNS_460F (POWERPC_INSNS_EMB | PPC_STRING | \ - PPC_DCR | PPC_DCRX | PPC_DCRUX | \ - PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | \ - PPC_FLOAT | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ +#define POWERPC_INSNS_460F (PPC_INSNS_BASE | PPC_STRING | \ + PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_STFIWX | \ - PPC_BOOKE | PPC_MFAPIDI | PPC_TLBIVA | \ - PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC) + PPC_DCR | PPC_DCRX | PPC_DCRUX | \ + PPC_WRTEE | PPC_MFAPIDI | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ + PPC_MEM_TLBSYNC | PPC_TLBIVA | \ + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ + PPC_440_SPEC) #define POWERPC_MSRM_460 (0x000000000006FF30ULL) #define POWERPC_MMU_460F (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) @@ -3732,7 +3811,13 @@ static void init_proc_MPC8xx (CPUPPCState *env) /* Freescale 82xx cores (aka PowerQUICC-II) */ /* PowerPC G2 */ -#define POWERPC_INSNS_G2 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_INSNS_G2 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_G2 (0x000000000006FFF2ULL) #define POWERPC_MMU_G2 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) @@ -3777,7 +3862,13 @@ static void init_proc_G2 (CPUPPCState *env) } /* PowerPC G2LE */ -#define POWERPC_INSNS_G2LE (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_INSNS_G2LE (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_G2LE (0x000000000007FFF3ULL) #define POWERPC_MMU_G2LE (POWERPC_MMU_SOFT_6xx) #define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) @@ -3831,11 +3922,13 @@ static void init_proc_G2LE (CPUPPCState *env) * tlbivax * all SPE multiply-accumulate instructions */ -#define POWERPC_INSNS_e200 (POWERPC_INSNS_EMB | PPC_ISEL | \ +#define POWERPC_INSNS_e200 (PPC_INSNS_BASE | PPC_ISEL | \ PPC_SPE | PPC_SPEFPU | \ + PPC_WRTEE | PPC_RFDI | \ + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ PPC_MEM_TLBSYNC | PPC_TLBIVAX | \ - PPC_CACHE_DCBA | PPC_CACHE_LOCK | \ - PPC_BOOKE | PPC_RFDI) + PPC_BOOKE) #define POWERPC_MSRM_e200 (0x000000000606FF30ULL) #define POWERPC_MMU_e200 (POWERPC_MMU_BOOKE_FSL) #define POWERPC_EXCP_e200 (POWERPC_EXCP_BOOKE) @@ -3949,7 +4042,13 @@ static void init_proc_e200 (CPUPPCState *env) } /* e300 core */ -#define POWERPC_INSNS_e300 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_INSNS_e300 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_e300 (0x000000000007FFF3ULL) #define POWERPC_MMU_e300 (POWERPC_MMU_SOFT_6xx) #define POWERPC_EXCP_e300 (POWERPC_EXCP_603) @@ -3988,11 +4087,13 @@ static void init_proc_e300 (CPUPPCState *env) } /* e500 core */ -#define POWERPC_INSNS_e500 (POWERPC_INSNS_EMB | PPC_ISEL | \ +#define POWERPC_INSNS_e500 (PPC_INSNS_BASE | PPC_ISEL | \ PPC_SPE | PPC_SPEFPU | \ + PPC_WRTEE | PPC_RFDI | \ + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ PPC_MEM_TLBSYNC | PPC_TLBIVAX | \ - PPC_CACHE_DCBA | PPC_CACHE_LOCK | \ - PPC_BOOKE | PPC_RFDI) + PPC_BOOKE) #define POWERPC_MSRM_e500 (0x000000000606FF30ULL) #define POWERPC_MMU_e500 (POWERPC_MMU_BOOKE_FSL) #define POWERPC_EXCP_e500 (POWERPC_EXCP_BOOKE) @@ -4109,16 +4210,6 @@ static void init_proc_e500 (CPUPPCState *env) } /* Non-embedded PowerPC */ -/* Base instructions set for all 6xx/7xx/74xx/970 PowerPC */ -#define POWERPC_INSNS_6xx (PPC_INSNS_BASE | PPC_STRING | PPC_FLOAT | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE) -/* Instructions common to all 6xx/7xx/74xx/970 PowerPC except 601 & 602 */ -#define POWERPC_INSNS_WORKS (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT | \ - PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ - PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ | PPC_MFTB | \ - PPC_SEGMENT) /* POWER : same as 601, without mfmsr, mfsr */ #if defined(TODO) @@ -4128,9 +4219,13 @@ static void init_proc_e500 (CPUPPCState *env) #endif /* TODO */ /* PowerPC 601 */ -#define POWERPC_INSNS_601 (POWERPC_INSNS_6xx | PPC_CACHE_DCBZ | \ - PPC_SEGMENT | PPC_EXTERN | PPC_POWER_BR) +#define POWERPC_INSNS_601 (PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | \ + PPC_FLOAT | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_601 (0x000000000000FD70ULL) +#define POWERPC_MSRR_601 (0x0000000000001040ULL) //#define POWERPC_MMU_601 (POWERPC_MMU_601) //#define POWERPC_EXCP_601 (POWERPC_EXCP_601) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) @@ -4163,31 +4258,53 @@ static void init_proc_601 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_601_HID15, "HID15", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); /* Memory management */ -#if !defined(CONFIG_USER_ONLY) - env->nb_tlb = 64; - env->nb_ways = 2; - env->id_tlbs = 0; -#endif init_excp_601(env); - env->dcache_line_size = 64; + /* XXX: beware that dcache line size is 64 + * but dcbz uses 32 bytes "sectors" + * XXX: this breaks clcs instruction ! + */ + env->dcache_line_size = 32; env->icache_line_size = 64; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } +/* PowerPC 601v */ +#define POWERPC_INSNS_601v (PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | \ + PPC_FLOAT | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | \ + PPC_SEGMENT | PPC_EXTERN) +#define POWERPC_MSRM_601v (0x000000000000FD70ULL) +#define POWERPC_MSRR_601v (0x0000000000001040ULL) +#define POWERPC_MMU_601v (POWERPC_MMU_601) +#define POWERPC_EXCP_601v (POWERPC_EXCP_601) +#define POWERPC_INPUT_601v (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_601v (bfd_mach_ppc_601) +#define POWERPC_FLAG_601v (POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK) +#define check_pow_601v check_pow_none + +static void init_proc_601v (CPUPPCState *env) +{ + init_proc_601(env); + /* XXX : not implemented */ + spr_register(env, SPR_601_HID15, "HID15", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + /* PowerPC 602 */ -#define POWERPC_INSNS_602 (POWERPC_INSNS_6xx | PPC_MFTB | \ - PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ - PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ |\ +#define POWERPC_INSNS_602 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | \ PPC_SEGMENT | PPC_602_SPEC) -#define POWERPC_MSRM_602 (0x000000000033FF73ULL) +#define POWERPC_MSRM_602 (0x0000000000C7FF73ULL) +/* XXX: 602 MMU is quite specific. Should add a special case */ #define POWERPC_MMU_602 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_602 (POWERPC_EXCP_602) #define POWERPC_INPUT_602 (PPC_FLAGS_INPUT_6xx) @@ -4224,7 +4341,13 @@ static void init_proc_602 (CPUPPCState *env) } /* PowerPC 603 */ -#define POWERPC_INSNS_603 (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_INSNS_603 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_603 (0x000000000007FF73ULL) #define POWERPC_MMU_603 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_603 (POWERPC_EXCP_603) @@ -4262,7 +4385,13 @@ static void init_proc_603 (CPUPPCState *env) } /* PowerPC 603e */ -#define POWERPC_INSNS_603E (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN) +#define POWERPC_INSNS_603E (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_603E (0x000000000007FF73ULL) #define POWERPC_MMU_603E (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_603E (POWERPC_EXCP_603E) @@ -4305,7 +4434,13 @@ static void init_proc_603E (CPUPPCState *env) } /* PowerPC 604 */ -#define POWERPC_INSNS_604 (POWERPC_INSNS_WORKS | PPC_EXTERN) +#define POWERPC_INSNS_604 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_604 (0x000000000005FF77ULL) #define POWERPC_MMU_604 (POWERPC_MMU_32B) //#define POWERPC_EXCP_604 (POWERPC_EXCP_604) @@ -4323,6 +4458,59 @@ static void init_proc_604 (CPUPPCState *env) gen_tbl(env); /* Hardware implementation registers */ /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + init_excp_604(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 604E */ +#define POWERPC_INSNS_604E (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN) +#define POWERPC_MSRM_604E (0x000000000005FF77ULL) +#define POWERPC_MMU_604E (POWERPC_MMU_32B) +#define POWERPC_EXCP_604E (POWERPC_EXCP_604) +#define POWERPC_INPUT_604E (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_604E (bfd_mach_ppc_604) +#define POWERPC_FLAG_604E (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) +#define check_pow_604E check_pow_nocheck + +static void init_proc_604E (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_604(env); + /* XXX : not implemented */ + spr_register(env, SPR_MMCR1, "MMCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC3, "PMC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC4, "PMC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Time base */ + gen_tbl(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -4342,7 +4530,14 @@ static void init_proc_604 (CPUPPCState *env) } /* PowerPC 740/750 (aka G3) */ -#define POWERPC_INSNS_7x0 (POWERPC_INSNS_WORKS | PPC_EXTERN) +#define POWERPC_INSNS_7x0 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_7x0 (0x000000000005FF77ULL) #define POWERPC_MMU_7x0 (POWERPC_MMU_32B) //#define POWERPC_EXCP_7x0 (POWERPC_EXCP_7x0) @@ -4381,7 +4576,14 @@ static void init_proc_7x0 (CPUPPCState *env) } /* PowerPC 750FX/GX */ -#define POWERPC_INSNS_750fx (POWERPC_INSNS_WORKS | PPC_EXTERN) +#define POWERPC_INSNS_750fx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_750fx (0x000000000005FF77ULL) #define POWERPC_MMU_750fx (POWERPC_MMU_32B) #define POWERPC_EXCP_750fx (POWERPC_EXCP_7x0) @@ -4427,7 +4629,14 @@ static void init_proc_750fx (CPUPPCState *env) } /* PowerPC 745/755 */ -#define POWERPC_INSNS_7x5 (POWERPC_INSNS_WORKS | PPC_EXTERN | PPC_6xx_TLB) +#define POWERPC_INSNS_7x5 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN) #define POWERPC_MSRM_7x5 (0x000000000005FF77ULL) #define POWERPC_MMU_7x5 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_7x5 (POWERPC_EXCP_7x5) @@ -4486,8 +4695,16 @@ static void init_proc_7x5 (CPUPPCState *env) } /* PowerPC 7400 (aka G4) */ -#define POWERPC_INSNS_7400 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ - PPC_EXTERN | PPC_MEM_TLBIA | \ +#define POWERPC_INSNS_7400 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_MEM_TLBIA | \ + PPC_SEGMENT | PPC_EXTERN | \ PPC_ALTIVEC) #define POWERPC_MSRM_7400 (0x000000000205FF77ULL) #define POWERPC_MMU_7400 (POWERPC_MMU_32B) @@ -4519,8 +4736,16 @@ static void init_proc_7400 (CPUPPCState *env) } /* PowerPC 7410 (aka G4) */ -#define POWERPC_INSNS_7410 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ - PPC_EXTERN | PPC_MEM_TLBIA | \ +#define POWERPC_INSNS_7410 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_MEM_TLBIA | \ + PPC_SEGMENT | PPC_EXTERN | \ PPC_ALTIVEC) #define POWERPC_MSRM_7410 (0x000000000205FF77ULL) #define POWERPC_MMU_7410 (POWERPC_MMU_32B) @@ -4564,8 +4789,16 @@ static void init_proc_7410 (CPUPPCState *env) } /* PowerPC 7440 (aka G4) */ -#define POWERPC_INSNS_7440 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ - PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ +#define POWERPC_INSNS_7440 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_MEM_TLBIA | PPC_74xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN | \ PPC_ALTIVEC) #define POWERPC_MSRM_7440 (0x000000000205FF77ULL) #define POWERPC_MMU_7440 (POWERPC_MMU_SOFT_74xx) @@ -4636,8 +4869,16 @@ static void init_proc_7440 (CPUPPCState *env) } /* PowerPC 7450 (aka G4) */ -#define POWERPC_INSNS_7450 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ - PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ +#define POWERPC_INSNS_7450 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_MEM_TLBIA | PPC_74xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN | \ PPC_ALTIVEC) #define POWERPC_MSRM_7450 (0x000000000205FF77ULL) #define POWERPC_MMU_7450 (POWERPC_MMU_SOFT_74xx) @@ -4710,8 +4951,16 @@ static void init_proc_7450 (CPUPPCState *env) } /* PowerPC 7445 (aka G4) */ -#define POWERPC_INSNS_7445 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ - PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ +#define POWERPC_INSNS_7445 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_MEM_TLBIA | PPC_74xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN | \ PPC_ALTIVEC) #define POWERPC_MSRM_7445 (0x000000000205FF77ULL) #define POWERPC_MMU_7445 (POWERPC_MMU_SOFT_74xx) @@ -4816,8 +5065,16 @@ static void init_proc_7445 (CPUPPCState *env) } /* PowerPC 7455 (aka G4) */ -#define POWERPC_INSNS_7455 (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA | \ - PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA | \ +#define POWERPC_INSNS_7455 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_MEM_TLBIA | PPC_74xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN | \ PPC_ALTIVEC) #define POWERPC_MSRM_7455 (0x000000000205FF77ULL) #define POWERPC_MMU_7455 (POWERPC_MMU_SOFT_74xx) @@ -4924,12 +5181,14 @@ static void init_proc_7455 (CPUPPCState *env) } #if defined (TARGET_PPC64) -#define POWERPC_INSNS_WORK64 (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT | \ - PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX | \ - PPC_MEM_TLBSYNC | PPC_CACHE_DCBZT | PPC_MFTB) /* PowerPC 970 */ -#define POWERPC_INSNS_970 (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ +#define POWERPC_INSNS_970 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI) #define POWERPC_MSRM_970 (0x900000000204FF36ULL) @@ -5010,7 +5269,13 @@ static void init_proc_970 (CPUPPCState *env) } /* PowerPC 970FX (aka G5) */ -#define POWERPC_INSNS_970FX (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ +#define POWERPC_INSNS_970FX (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI) #define POWERPC_MSRM_970FX (0x800000000204FF36ULL) @@ -5085,7 +5350,13 @@ static void init_proc_970FX (CPUPPCState *env) } /* PowerPC 970 GX */ -#define POWERPC_INSNS_970GX (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ +#define POWERPC_INSNS_970GX (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI) #define POWERPC_MSRM_970GX (0x800000000204FF36ULL) @@ -5160,7 +5431,13 @@ static void init_proc_970GX (CPUPPCState *env) } /* PowerPC 970 MP */ -#define POWERPC_INSNS_970MP (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT | \ +#define POWERPC_INSNS_970MP (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI) #define POWERPC_MSRM_970MP (0x900000000204FF36ULL) @@ -5235,7 +5512,14 @@ static void init_proc_970MP (CPUPPCState *env) } /* PowerPC 620 */ -#define POWERPC_INSNS_620 (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT | \ +#define POWERPC_INSNS_620 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN | \ PPC_64B | PPC_SLBI) #define POWERPC_MSRM_620 (0x800000000005FF77ULL) //#define POWERPC_MMU_620 (POWERPC_MMU_620) @@ -5261,7 +5545,6 @@ static void init_proc_620 (CPUPPCState *env) 0x00000000); /* Memory management */ gen_low_BATs(env); - gen_high_BATs(env); init_excp_620(env); env->dcache_line_size = 64; env->icache_line_size = 64; @@ -5938,12 +6221,13 @@ enum { CPU_POWERPC_74x5_v33 = 0x80010303, /* aka F: 3.3 */ CPU_POWERPC_74x5_v34 = 0x80010304, /* aka G: 3.4 */ #define CPU_POWERPC_74x7 CPU_POWERPC_74x7_v12 - /* XXX: is 0x8002xxxx 7447 and 0x8003xxxx 7457 ? */ - /* XXX: missing 0x80030102 */ - /* XXX: missing 0x80020101 */ CPU_POWERPC_74x7_v10 = 0x80020100, /* aka A: 1.0 */ - CPU_POWERPC_74x7_v11 = 0x80030101, /* aka B: 1.1 */ + CPU_POWERPC_74x7_v11 = 0x80020101, /* aka B: 1.1 */ CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ +#define CPU_POWERPC_74x7A CPU_POWERPC_74x7A_v12 + CPU_POWERPC_74x7A_v10 = 0x80030100, /* aka A: 1.0 */ + CPU_POWERPC_74x7A_v11 = 0x80030101, /* aka B: 1.1 */ + CPU_POWERPC_74x7A_v12 = 0x80030102, /* aka C: 1.2 */ /* 64 bits PowerPC */ #if defined(TARGET_PPC64) CPU_POWERPC_620 = 0x00140000, @@ -6714,7 +6998,7 @@ static const ppc_def_t ppc_defs[] = { /* MPC8240 */ POWERPC_DEF("MPC8240", CPU_POWERPC_MPC8240, 603E), /* PowerPC G2 microcontrollers */ -#if 0 +#if defined(TODO) /* MPC5121 */ POWERPC_DEF_SVR("MPC5121", CPU_POWERPC_MPC5121, POWERPC_SVR_5121, G2LE), @@ -7295,18 +7579,20 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 601 */ POWERPC_DEF("601", CPU_POWERPC_601, 601), /* PowerPC 601v0 */ - POWERPC_DEF("601v0", CPU_POWERPC_601_v0, 601), + POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601), /* PowerPC 601v1 */ - POWERPC_DEF("601v1", CPU_POWERPC_601_v1, 601), + POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601), + /* PowerPC 601v */ + POWERPC_DEF("601v", CPU_POWERPC_601, 601v), /* PowerPC 601v2 */ - POWERPC_DEF("601v2", CPU_POWERPC_601_v2, 601), + POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v), /* PowerPC 602 */ POWERPC_DEF("602", CPU_POWERPC_602, 602), /* PowerPC 603 */ POWERPC_DEF("603", CPU_POWERPC_603, 603), /* Code name for PowerPC 603 */ POWERPC_DEF("Vanilla", CPU_POWERPC_603, 603), - /* PowerPC 603e */ + /* PowerPC 603e (aka PID6) */ POWERPC_DEF("603e", CPU_POWERPC_603E, 603E), /* Code name for PowerPC 603e */ POWERPC_DEF("Stretch", CPU_POWERPC_603E, 603E), @@ -7326,7 +7612,7 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("603e_v4", CPU_POWERPC_603E_v4, 603E), /* PowerPC 603e v4.1 */ POWERPC_DEF("603e_v4.1", CPU_POWERPC_603E_v41, 603E), - /* PowerPC 603e */ + /* PowerPC 603e (aka PID7) */ POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E), /* PowerPC 603e7t */ POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E), @@ -7338,38 +7624,41 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E), /* PowerPC 603e7v2 */ POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E), - /* PowerPC 603p */ - /* to be checked */ - POWERPC_DEF("603p", CPU_POWERPC_603P, 603), - /* PowerPC 603r */ + /* PowerPC 603p (aka PID7v) */ + POWERPC_DEF("603p", CPU_POWERPC_603P, 603E), + /* PowerPC 603r (aka PID7t) */ POWERPC_DEF("603r", CPU_POWERPC_603R, 603E), /* Code name for PowerPC 603r */ POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 603E), /* PowerPC 604 */ POWERPC_DEF("604", CPU_POWERPC_604, 604), - /* PowerPC 604e */ - /* XXX: code names "Sirocco" "Mach 5" */ - POWERPC_DEF("604e", CPU_POWERPC_604E, 604), + /* PowerPC 604e (aka PID9) */ + POWERPC_DEF("604e", CPU_POWERPC_604E, 604E), + /* Code name for PowerPC 604e */ + POWERPC_DEF("Sirocco", CPU_POWERPC_604E, 604E), /* PowerPC 604e v1.0 */ - POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604), + POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E), /* PowerPC 604e v2.2 */ - POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604), + POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604E), /* PowerPC 604e v2.4 */ - POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604), - /* PowerPC 604r */ - POWERPC_DEF("604r", CPU_POWERPC_604R, 604), + POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604E), + /* PowerPC 604r (aka PIDA) */ + POWERPC_DEF("604r", CPU_POWERPC_604R, 604E), + /* Code name for PowerPC 604r */ + POWERPC_DEF("Mach5", CPU_POWERPC_604R, 604E), #if defined(TODO) /* PowerPC 604ev */ - POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604), + POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E), #endif /* PowerPC 7xx family */ /* Generic PowerPC 740 (G3) */ POWERPC_DEF("740", CPU_POWERPC_7x0, 7x0), + /* Code name for PowerPC 740 */ + POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 7x0), /* Generic PowerPC 750 (G3) */ POWERPC_DEF("750", CPU_POWERPC_7x0, 7x0), - /* Code name for generic PowerPC 740/750 (G3) */ - POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 7x0), - /* XXX: 750 codename "Typhoon" */ + /* Code name for PowerPC 750 */ + POWERPC_DEF("Typhoon", CPU_POWERPC_7x0, 7x0), /* PowerPC 740/750 is also known as G3 */ POWERPC_DEF("G3", CPU_POWERPC_7x0, 7x0), /* PowerPC 740 v2.0 (G3) */ @@ -7411,17 +7700,17 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 750CXe (G3 embedded) */ POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 7x0), /* PowerPC 750CXe v2.1 (G3 embedded) */ - POWERPC_DEF("750cxe_v21", CPU_POWERPC_750CXE_v21, 7x0), + POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 7x0), /* PowerPC 750CXe v2.2 (G3 embedded) */ - POWERPC_DEF("750cxe_v22", CPU_POWERPC_750CXE_v22, 7x0), + POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 7x0), /* PowerPC 750CXe v2.3 (G3 embedded) */ - POWERPC_DEF("750cxe_v23", CPU_POWERPC_750CXE_v23, 7x0), + POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 7x0), /* PowerPC 750CXe v2.4 (G3 embedded) */ - POWERPC_DEF("750cxe_v24", CPU_POWERPC_750CXE_v24, 7x0), + POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 7x0), /* PowerPC 750CXe v2.4b (G3 embedded) */ - POWERPC_DEF("750cxe_v24b", CPU_POWERPC_750CXE_v24b, 7x0), + POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 7x0), /* PowerPC 750CXe v3.1 (G3 embedded) */ - POWERPC_DEF("750cxe_v31", CPU_POWERPC_750CXE_v31, 7x0), + POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 7x0), /* PowerPC 750CXe v3.1b (G3 embedded) */ POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 7x0), /* PowerPC 750CXr (G3 embedded) */ @@ -7623,8 +7912,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445), /* PowerPC 7457 v1.0 (G4) */ POWERPC_DEF("7457_v1.0", CPU_POWERPC_74x7_v10, 7455), - /* Code name for PowerPC 7447A/7457A */ - POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7_v10, 7455), /* PowerPC 7447 v1.1 (G4) */ POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445), /* PowerPC 7457 v1.1 (G4) */ @@ -7633,16 +7920,37 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7447_v1.2", CPU_POWERPC_74x7_v12, 7445), /* PowerPC 7457 v1.2 (G4) */ POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455), + /* PowerPC 7447A (G4) */ + POWERPC_DEF("7447A", CPU_POWERPC_74x7A, 7445), + /* PowerPC 7457A (G4) */ + POWERPC_DEF("7457A", CPU_POWERPC_74x7A, 7455), + /* PowerPC 7447A v1.0 (G4) */ + POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445), + /* PowerPC 7457A v1.0 (G4) */ + POWERPC_DEF("7457A_v1.0", CPU_POWERPC_74x7A_v10, 7455), + /* Code name for PowerPC 7447A/7457A */ + POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7A_v10, 7455), + /* PowerPC 7447A v1.1 (G4) */ + POWERPC_DEF("7447A_v1.1", CPU_POWERPC_74x7A_v11, 7445), + /* PowerPC 7457A v1.1 (G4) */ + POWERPC_DEF("7457A_v1.1", CPU_POWERPC_74x7A_v11, 7455), + /* PowerPC 7447A v1.2 (G4) */ + POWERPC_DEF("7447A_v1.2", CPU_POWERPC_74x7A_v12, 7445), + /* PowerPC 7457A v1.2 (G4) */ + POWERPC_DEF("7457A_v1.2", CPU_POWERPC_74x7A_v12, 7455), /* 64 bits PowerPC */ #if defined (TARGET_PPC64) /* PowerPC 620 */ - /* XXX: code name "Trident" */ POWERPC_DEF("620", CPU_POWERPC_620, 620), + /* Code name for PowerPC 620 */ + POWERPC_DEF("Trident", CPU_POWERPC_620, 620), #if defined (TODO) /* PowerPC 630 (POWER3) */ - /* XXX: code names: "Boxer" "Dino" */ POWERPC_DEF("630", CPU_POWERPC_630, 630), POWERPC_DEF("POWER3", CPU_POWERPC_630, 630), + /* Code names for POWER3 */ + POWERPC_DEF("Boxer", CPU_POWERPC_630, 630), + POWERPC_DEF("Dino", CPU_POWERPC_630, 630), #endif #if defined (TODO) /* PowerPC 631 (Power 3+) */ -- cgit v1.2.3 From 8d162c2b68db72623a507069fda0e35ccd1c6b85 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 19 Nov 2007 16:10:33 +0000 Subject: Add older 4Km variants. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3708 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate_init.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index f6bda53fe..6a4c43576 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -100,6 +100,23 @@ static mips_def_t mips_defs[] = .CP0_Status_rw_bitmask = 0x1278FF17, .insn_flags = CPU_MIPS32 | ASE_MIPS16, }, + { + .name = "4Km", + .CP0_PRid = 0x00018300, + /* Config1 implemented, fixed mapping MMU, + no virtual icache, uncached coherency. */ + .CP0_Config0 = (1 << CP0C0_M) | + (0x3 << CP0C0_MT) | (0x2 << CP0C0_K0), + .CP0_Config1 = MIPS_CONFIG1 | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x1258FF17, + .insn_flags = CPU_MIPS32 | ASE_MIPS16, + }, { .name = "4KEcR1", .CP0_PRid = 0x00018400, @@ -114,6 +131,23 @@ static mips_def_t mips_defs[] = .CP0_Status_rw_bitmask = 0x1278FF17, .insn_flags = CPU_MIPS32 | ASE_MIPS16, }, + { + .name = "4KEmR1", + .CP0_PRid = 0x00018500, + /* Config1 implemented, fixed mapping MMU, + no virtual icache, uncached coherency. */ + .CP0_Config0 = (1 << CP0C0_M) | + (0x3 << CP0C0_MT) | (0x2 << CP0C0_K0), + .CP0_Config1 = MIPS_CONFIG1 | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x1258FF17, + .insn_flags = CPU_MIPS32 | ASE_MIPS16, + }, { .name = "4KEc", .CP0_PRid = 0x00019000, -- cgit v1.2.3 From d07b4d0ea72311b619c0f3799d849957446b5761 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 19 Nov 2007 19:14:10 +0000 Subject: Fix MXCC register 64 bit read word order (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3709 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 699a305b2..d22b2e8d3 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -196,8 +196,8 @@ void helper_ld_asi(int asi, int size, int sign) switch (T0) { case 0x01c00a00: /* MXCC control register */ if (size == 8) { - ret = env->mxccregs[3]; - T0 = env->mxccregs[3] >> 32; + ret = env->mxccregs[3] >> 32; + T0 = env->mxccregs[3]; } else DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); break; @@ -217,8 +217,8 @@ void helper_ld_asi(int asi, int size, int sign) break; case 0x01c00f00: /* MBus port address register */ if (size == 8) { - ret = env->mxccregs[7]; - T0 = env->mxccregs[7] >> 32; + ret = env->mxccregs[7] >> 32; + T0 = env->mxccregs[7]; } else DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); break; -- cgit v1.2.3 From f9d43072e25715911b3ef7594132e4f87ead8ba0 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 20 Nov 2007 11:15:27 +0000 Subject: OMAP LPGs (LED pulse generators). OMAP MPUI bridge config register. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3710 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/omap.h | 5 ++ 2 files changed, 189 insertions(+), 2 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index 662332b7c..a873b5fe5 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -4626,6 +4626,184 @@ void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0]; } +/* LED Pulse Generators */ +struct omap_lpg_s { + target_phys_addr_t base; + QEMUTimer *tm; + + uint8_t control; + uint8_t power; + int64_t on; + int64_t period; + int clk; + int cycle; +}; + +static void omap_lpg_tick(void *opaque) +{ + struct omap_lpg_s *s = opaque; + + if (s->cycle) + qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->period - s->on); + else + qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->on); + + s->cycle = !s->cycle; + printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off"); +} + +static void omap_lpg_update(struct omap_lpg_s *s) +{ + int64_t on, period = 1, ticks = 1000; + static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 }; + + if (~s->control & (1 << 6)) /* LPGRES */ + on = 0; + else if (s->control & (1 << 7)) /* PERM_ON */ + on = period; + else { + period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */ + 256 / 32); + on = (s->clk && s->power) ? muldiv64(ticks, + per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ + } + + qemu_del_timer(s->tm); + if (on == period && s->on < s->period) + printf("%s: LED is on\n", __FUNCTION__); + else if (on == 0 && s->on) + printf("%s: LED is off\n", __FUNCTION__); + else if (on && (on != s->on || period != s->period)) { + s->cycle = 0; + s->on = on; + s->period = period; + omap_lpg_tick(s); + return; + } + + s->on = on; + s->period = period; +} + +static void omap_lpg_reset(struct omap_lpg_s *s) +{ + s->control = 0x00; + s->power = 0x00; + s->clk = 1; + omap_lpg_update(s); +} + +static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* LCR */ + return s->control; + + case 0x04: /* PMR */ + return s->power; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_lpg_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + int offset = addr & OMAP_MPUI_REG_MASK; + + switch (offset) { + case 0x00: /* LCR */ + if (~value & (1 << 6)) /* LPGRES */ + omap_lpg_reset(s); + s->control = value & 0xff; + omap_lpg_update(s); + return; + + case 0x04: /* PMR */ + s->power = value & 0x01; + omap_lpg_update(s); + return; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_lpg_readfn[] = { + omap_lpg_read, + omap_badwidth_read8, + omap_badwidth_read8, +}; + +static CPUWriteMemoryFunc *omap_lpg_writefn[] = { + omap_lpg_write, + omap_badwidth_write8, + omap_badwidth_write8, +}; + +static void omap_lpg_clk_update(void *opaque, int line, int on) +{ + struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; + + s->clk = on; + omap_lpg_update(s); +} + +struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk) +{ + int iomemtype; + struct omap_lpg_s *s = (struct omap_lpg_s *) + qemu_mallocz(sizeof(struct omap_lpg_s)); + + s->base = base; + s->tm = qemu_new_timer(rt_clock, omap_lpg_tick, s); + + omap_lpg_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_lpg_readfn, + omap_lpg_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]); + + return s; +} + +/* MPUI Peripheral Bridge configuration */ +static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr) +{ + if (addr == OMAP_MPUI_BASE) /* CMR */ + return 0xfe4d; + + OMAP_BAD_REG(addr); + return 0; +} + +static CPUReadMemoryFunc *omap_mpui_io_readfn[] = { + omap_badwidth_read16, + omap_mpui_io_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_mpui_io_writefn[] = { + omap_badwidth_write16, + omap_badwidth_write16, + omap_badwidth_write16, +}; + +static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu) +{ + int iomemtype = cpu_register_io_memory(0, omap_mpui_io_readfn, + omap_mpui_io_writefn, mpu); + cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype); +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -4663,6 +4841,8 @@ static void omap_mpu_reset(void *opaque) omap_mcbsp_reset(mpu->mcbsp1); omap_mcbsp_reset(mpu->mcbsp2); omap_mcbsp_reset(mpu->mcbsp3); + omap_lpg_reset(mpu->led[0]); + omap_lpg_reset(mpu->led[1]); cpu_reset(mpu->env); } @@ -4846,6 +5026,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX], &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); + s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz")); + s->led[1] = omap_lpg_init(0xfffbd800, omap_findclk(s, "clk32-kHz")); + /* Register mappings not currenlty implemented: * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) @@ -4855,8 +5038,6 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, * FAC fffba800 - fffbafff * HDQ/1-Wire fffbc000 - fffbc7ff * TIPB switches fffbc800 - fffbcfff - * LED1 fffbd000 - fffbd7ff - * LED2 fffbd800 - fffbdfff * Mailbox fffcf000 - fffcf7ff * Local bus IF fffec100 - fffec1ff * Local bus MMU fffec200 - fffec2ff @@ -4864,6 +5045,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, */ omap_setup_dsp_mapping(omap15xx_dsp_mm); + omap_setup_mpui_io(s); qemu_register_reset(omap_mpu_reset, s); diff --git a/hw/omap.h b/hw/omap.h index e58fb3c24..7d189d606 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -508,6 +508,9 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, qemu_irq *irq, qemu_irq *dma, omap_clk clk); void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave); +struct omap_lpg_s; +struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); @@ -598,6 +601,8 @@ struct omap_mpu_state_s { struct omap_mcbsp_s *mcbsp2; + struct omap_lpg_s *led[2]; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; -- cgit v1.2.3 From fca743f307526ffc561d948eda584788c40ece83 Mon Sep 17 00:00:00 2001 From: ths Date: Tue, 20 Nov 2007 15:22:44 +0000 Subject: SH4 Fix missing 6th arg of syscall, by "takasi-y". git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3711 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 631eb4b6b..cfc9065a5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1613,7 +1613,7 @@ void cpu_loop (CPUState *env) env->gregs[6], env->gregs[7], env->gregs[0], - 0); + env->gregs[1]); env->gregs[0] = ret; env->pc += 2; break; -- cgit v1.2.3 From 325e651fb78cc970e170aa502bae6e3fa2c26db7 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 21 Nov 2007 13:06:54 +0000 Subject: Fix PowerPC 64 stat and statfs structures definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3712 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall_defs.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index c5d15a6f9..64bc94f22 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1088,8 +1088,13 @@ struct target_stat64 { struct target_stat { unsigned short st_dev; abi_ulong st_ino; +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) + unsigned short st_nlink; + unsigned int st_mode; +#else unsigned int st_mode; unsigned short st_nlink; +#endif unsigned int st_uid; unsigned int st_gid; unsigned short st_rdev; @@ -1104,6 +1109,9 @@ struct target_stat { abi_ulong __unused3; abi_ulong __unused4; abi_ulong __unused5; +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) + abi_ulong __unused6; +#endif }; struct target_stat64 { @@ -1555,6 +1563,34 @@ struct target_statfs64 { uint32_t f_namelen; uint32_t f_spare[6]; }; +#elif defined(TARGET_PPC64) && !defined(TARGET_ABI32) +struct target_statfs { + abi_long f_type; + abi_long f_bsize; + abi_long f_blocks; + abi_long f_bfree; + abi_long f_bavail; + abi_long f_files; + abi_long f_ffree; + target_fsid_t f_fsid; + abi_long f_namelen; + abi_long f_frsize; + abi_long f_spare[5]; +}; + +struct target_statfs64 { + abi_long f_type; + abi_long f_bsize; + abi_long f_blocks; + abi_long f_bfree; + abi_long f_bavail; + abi_long f_files; + abi_long f_ffree; + target_fsid_t f_fsid; + abi_long f_namelen; + abi_long f_frsize; + abi_long f_spare[5]; +}; #else struct target_statfs { uint32_t f_type; -- cgit v1.2.3 From bd928ebafe5a5e318d5ec71c1aec4400721179ae Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 21 Nov 2007 13:08:23 +0000 Subject: Fix PowerPC 7xx definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3713 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 19 +- target-ppc/translate_init.c | 744 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 630 insertions(+), 133 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7cbc8da51..365d83697 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -357,6 +357,7 @@ union ppc_tlb_t { /*****************************************************************************/ /* Machine state register bits definition */ #define MSR_SF 63 /* Sixty-four-bit mode hflags */ +#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */ #define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */ #define MSR_SHV 60 /* hypervisor state hflags */ #define MSR_CM 31 /* Computation mode for BookE hflags */ @@ -1115,16 +1116,29 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_440_CCR1 (0x378) #define SPR_DCRIPR (0x37B) #define SPR_PPR (0x380) +#define SPR_750_GQR0 (0x390) #define SPR_440_DNV0 (0x390) +#define SPR_750_GQR1 (0x391) #define SPR_440_DNV1 (0x391) +#define SPR_750_GQR2 (0x392) #define SPR_440_DNV2 (0x392) +#define SPR_750_GQR3 (0x393) #define SPR_440_DNV3 (0x393) +#define SPR_750_GQR4 (0x394) #define SPR_440_DTV0 (0x394) +#define SPR_750_GQR5 (0x395) #define SPR_440_DTV1 (0x395) +#define SPR_750_GQR6 (0x396) #define SPR_440_DTV2 (0x396) +#define SPR_750_GQR7 (0x397) #define SPR_440_DTV3 (0x397) +#define SPR_750_THRM4 (0x398) +#define SPR_750CL_HID2 (0x398) #define SPR_440_DVLIM (0x398) +#define SPR_750_WPAR (0x399) #define SPR_440_IVLIM (0x399) +#define SPR_750_DMAU (0x39A) +#define SPR_750_DMAL (0x39B) #define SPR_440_RSTCFG (0x39B) #define SPR_BOOKE_DCDBTRL (0x39C) #define SPR_BOOKE_DCDBTRH (0x39D) @@ -1231,9 +1245,11 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_Exxx_L1CSR0 (0x3F2) #define SPR_ICTRL (0x3F3) #define SPR_HID2 (0x3F3) +#define SPR_750CL_HID4 (0x3F3) #define SPR_Exxx_L1CSR1 (0x3F3) #define SPR_440_DBDR (0x3F3) #define SPR_LDSTDB (0x3F4) +#define SPR_750_TDCL (0x3F4) #define SPR_40x_IAC1 (0x3F4) #define SPR_MMUCSR0 (0x3F4) #define SPR_DABR (0x3F5) @@ -1250,12 +1266,13 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_MMUCFG (0x3F7) #define SPR_LDSTCR (0x3F8) #define SPR_L2PMCR (0x3F8) -#define SPR_750_HID2 (0x3F8) +#define SPR_750FX_HID2 (0x3F8) #define SPR_620_BUSCSR (0x3F8) #define SPR_Exxx_L1FINV0 (0x3F8) #define SPR_L2CR (0x3F9) #define SPR_620_L2CR (0x3F9) #define SPR_L3CR (0x3FA) +#define SPR_750_TDCH (0x3FA) #define SPR_IABR2 (0x3FA) #define SPR_40x_DCCR (0x3FA) #define SPR_620_L2SR (0x3FA) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ad1152971..40b59105b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -764,12 +764,6 @@ static void gen_spr_G2_755 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* External access control */ - /* XXX : not implemented */ - spr_register(env, SPR_EAR, "EAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); } /* SPR common to all 7xx PowerPC implementations */ @@ -792,11 +786,6 @@ static void gen_spr_7xx (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_L2CR, "L2CR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); /* Performance monitors */ /* XXX : not implemented */ spr_register(env, SPR_MMCR0, "MMCR0", @@ -1185,6 +1174,11 @@ static void gen_spr_74xx (CPUPPCState *env) &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic, 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } static void gen_l3_ctrl (CPUPPCState *env) @@ -2871,6 +2865,7 @@ static void init_excp_7x0 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; + env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ @@ -2878,7 +2873,7 @@ static void init_excp_7x0 (CPUPPCState *env) #endif } -static void init_excp_750FX (CPUPPCState *env) +static void init_excp_750cl (CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; @@ -2895,6 +2890,28 @@ static void init_excp_750FX (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_prefix = 0x00000000UL; + /* Hardware reset vector */ + env->hreset_vector = 0xFFFFFFFCUL; +#endif +} + +static void init_excp_750cx (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; + env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; + env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; + env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; + env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ @@ -2917,12 +2934,13 @@ static void init_excp_7x5 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; + env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; - env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; + env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; env->excp_prefix = 0x00000000UL; /* Hardware reset vector */ env->hreset_vector = 0xFFFFFFFCUL; @@ -3196,10 +3214,6 @@ static void init_proc_403 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc40x_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 403 GCX */ @@ -3834,6 +3848,12 @@ static void init_proc_G2 (CPUPPCState *env) gen_spr_G2(env); /* Time base */ gen_tbl(env); + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Hardware implementation register */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -3885,6 +3905,12 @@ static void init_proc_G2LE (CPUPPCState *env) gen_spr_G2(env); /* Time base */ gen_tbl(env); + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Hardware implementation register */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -4529,25 +4555,24 @@ static void init_proc_604E (CPUPPCState *env) ppc6xx_irq_init(env); } -/* PowerPC 740/750 (aka G3) */ -#define POWERPC_INSNS_7x0 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ +/* PowerPC 740 */ +#define POWERPC_INSNS_740 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_MSRM_7x0 (0x000000000005FF77ULL) -#define POWERPC_MMU_7x0 (POWERPC_MMU_32B) -//#define POWERPC_EXCP_7x0 (POWERPC_EXCP_7x0) -#define POWERPC_INPUT_7x0 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7x0 (bfd_mach_ppc_750) -#define POWERPC_FLAG_7x0 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ +#define POWERPC_MSRM_740 (0x000000000005FF77ULL) +#define POWERPC_MMU_740 (POWERPC_MMU_32B) +#define POWERPC_EXCP_740 (POWERPC_EXCP_7x0) +#define POWERPC_INPUT_740 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_740 (bfd_mach_ppc_750) +#define POWERPC_FLAG_740 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_7x0 check_pow_hid0 +#define check_pow_740 check_pow_hid0 -static void init_proc_7x0 (CPUPPCState *env) +static void init_proc_740 (CPUPPCState *env) { gen_spr_ne_601(env); gen_spr_7xx(env); @@ -4575,11 +4600,296 @@ static void init_proc_7x0 (CPUPPCState *env) ppc6xx_irq_init(env); } -/* PowerPC 750FX/GX */ +/* PowerPC 750 */ +#define POWERPC_INSNS_750 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN) +#define POWERPC_MSRM_750 (0x000000000005FF77ULL) +#define POWERPC_MMU_750 (POWERPC_MMU_32B) +#define POWERPC_EXCP_750 (POWERPC_EXCP_7x0) +#define POWERPC_INPUT_750 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_750 (bfd_mach_ppc_750) +#define POWERPC_FLAG_750 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) +#define check_pow_750 check_pow_hid0 + +static void init_proc_750 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Time base */ + gen_tbl(env); + /* Thermal management */ + gen_spr_thrm(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + /* XXX: high BATs are also present but are known to be bugged on + * die version 1.x + */ + init_excp_7x0(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 750 CL */ +/* XXX: not implemented: + * cache lock instructions: + * dcbz_l + * floating point paired instructions + * psq_lux + * psq_lx + * psq_stux + * psq_stx + * ps_abs + * ps_add + * ps_cmpo0 + * ps_cmpo1 + * ps_cmpu0 + * ps_cmpu1 + * ps_div + * ps_madd + * ps_madds0 + * ps_madds1 + * ps_merge00 + * ps_merge01 + * ps_merge10 + * ps_merge11 + * ps_mr + * ps_msub + * ps_mul + * ps_muls0 + * ps_muls1 + * ps_nabs + * ps_neg + * ps_nmadd + * ps_nmsub + * ps_res + * ps_rsqrte + * ps_sel + * ps_sub + * ps_sum0 + * ps_sum1 + */ +#define POWERPC_INSNS_750cl (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN) +#define POWERPC_MSRM_750cl (0x000000000005FF77ULL) +#define POWERPC_MMU_750cl (POWERPC_MMU_32B) +#define POWERPC_EXCP_750cl (POWERPC_EXCP_7x0) +#define POWERPC_INPUT_750cl (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_750cl (bfd_mach_ppc_750) +#define POWERPC_FLAG_750cl (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) +#define check_pow_750cl check_pow_hid0 + +static void init_proc_750cl (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Time base */ + gen_tbl(env); + /* Thermal management */ + /* Those registers are fake on 750CL */ + spr_register(env, SPR_THRM1, "THRM1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_THRM2, "THRM2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_THRM3, "THRM3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX: not implemented */ + spr_register(env, SPR_750_TDCL, "TDCL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_750_TDCH, "TDCH", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* DMA */ + /* XXX : not implemented */ + spr_register(env, SPR_750_WPAR, "WPAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_750_DMAL, "DMAL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_750_DMAU, "DMAU", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750CL_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750CL_HID4, "HID4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Quantization registers */ + /* XXX : not implemented */ + spr_register(env, SPR_750_GQR0, "GQR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_GQR1, "GQR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_GQR2, "GQR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_GQR3, "GQR3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_GQR4, "GQR4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_GQR5, "GQR5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_GQR6, "GQR6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_GQR7, "GQR7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + /* PowerPC 750cl has 8 DBATs and 8 IBATs */ + gen_high_BATs(env); + init_excp_750cl(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +#define POWERPC_INSNS_750cx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN) +#define POWERPC_MSRM_750cx (0x000000000005FF77ULL) +#define POWERPC_MMU_750cx (POWERPC_MMU_32B) +#define POWERPC_EXCP_750cx (POWERPC_EXCP_7x0) +#define POWERPC_INPUT_750cx (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_750cx (bfd_mach_ppc_750) +#define POWERPC_FLAG_750cx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) +#define check_pow_750cx check_pow_hid0 + +static void init_proc_750cx (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Time base */ + gen_tbl(env); + /* Thermal management */ + gen_spr_thrm(env); + /* This register is not implemented but is present for compatibility */ + spr_register(env, SPR_SDA, "SDA", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + /* XXX: high BATs are also present but are known to be bugged on + * die version 1.x + */ + init_excp_750cx(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 750FX */ #define POWERPC_INSNS_750fx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ @@ -4597,10 +4907,20 @@ static void init_proc_750fx (CPUPPCState *env) { gen_spr_ne_601(env); gen_spr_7xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Time base */ gen_tbl(env); /* Thermal management */ gen_spr_thrm(env); + /* XXX : not implemented */ + spr_register(env, SPR_750_THRM4, "THRM4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -4613,7 +4933,7 @@ static void init_proc_750fx (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", + spr_register(env, SPR_750FX_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -4621,40 +4941,155 @@ static void init_proc_750fx (CPUPPCState *env) gen_low_BATs(env); /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ gen_high_BATs(env); - init_excp_750FX(env); + init_excp_7x0(env); env->dcache_line_size = 32; env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } -/* PowerPC 745/755 */ -#define POWERPC_INSNS_7x5 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ +/* PowerPC 750GX */ +#define POWERPC_INSNS_750gx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_SEGMENT | PPC_EXTERN) +#define POWERPC_MSRM_750gx (0x000000000005FF77ULL) +#define POWERPC_MMU_750gx (POWERPC_MMU_32B) +#define POWERPC_EXCP_750gx (POWERPC_EXCP_7x0) +#define POWERPC_INPUT_750gx (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_750gx (bfd_mach_ppc_750) +#define POWERPC_FLAG_750gx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) +#define check_pow_750gx check_pow_hid0 + +static void init_proc_750gx (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* XXX : not implemented (XXX: different from 750fx) */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Time base */ + gen_tbl(env); + /* Thermal management */ + gen_spr_thrm(env); + /* XXX : not implemented */ + spr_register(env, SPR_750_THRM4, "THRM4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented (XXX: different from 750fx) */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented (XXX: different from 750fx) */ + spr_register(env, SPR_750FX_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ + gen_high_BATs(env); + init_excp_7x0(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 745 */ +#define POWERPC_INSNS_745 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN) +#define POWERPC_MSRM_745 (0x000000000005FF77ULL) +#define POWERPC_MMU_745 (POWERPC_MMU_SOFT_6xx) +#define POWERPC_EXCP_745 (POWERPC_EXCP_7x5) +#define POWERPC_INPUT_745 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_745 (bfd_mach_ppc_750) +#define POWERPC_FLAG_745 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) +#define check_pow_745 check_pow_hid0 + +static void init_proc_745 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + gen_spr_G2_755(env); + /* Time base */ + gen_tbl(env); + /* Thermal management */ + gen_spr_thrm(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + init_excp_7x5(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +/* PowerPC 755 */ +#define POWERPC_INSNS_755 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_MSRM_7x5 (0x000000000005FF77ULL) -#define POWERPC_MMU_7x5 (POWERPC_MMU_SOFT_6xx) -//#define POWERPC_EXCP_7x5 (POWERPC_EXCP_7x5) -#define POWERPC_INPUT_7x5 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7x5 (bfd_mach_ppc_750) -#define POWERPC_FLAG_7x5 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ +#define POWERPC_MSRM_755 (0x000000000005FF77ULL) +#define POWERPC_MMU_755 (POWERPC_MMU_SOFT_6xx) +#define POWERPC_EXCP_755 (POWERPC_EXCP_7x5) +#define POWERPC_INPUT_755 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_755 (bfd_mach_ppc_750) +#define POWERPC_FLAG_755 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_7x5 check_pow_hid0 +#define check_pow_755 check_pow_hid0 -static void init_proc_7x5 (CPUPPCState *env) +static void init_proc_755 (CPUPPCState *env) { gen_spr_ne_601(env); + gen_spr_7xx(env); gen_spr_G2_755(env); /* Time base */ gen_tbl(env); /* L2 cache control */ /* XXX : not implemented */ - spr_register(env, SPR_ICTC, "ICTC", + spr_register(env, SPR_L2CR, "L2CR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -4663,6 +5098,8 @@ static void init_proc_7x5 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + /* Thermal management */ + gen_spr_thrm(env); /* Hardware implementation registers */ /* XXX : not implemented */ spr_register(env, SPR_HID0, "HID0", @@ -4688,10 +5125,6 @@ static void init_proc_7x5 (CPUPPCState *env) env->icache_line_size = 32; /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); -#if !defined(CONFIG_USER_ONLY) - /* Hardware reset vector */ - env->hreset_vector = 0xFFFFFFFCUL; -#endif } /* PowerPC 7400 (aka G4) */ @@ -5232,7 +5665,7 @@ static void init_proc_970 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", + spr_register(env, SPR_750FX_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -5241,6 +5674,11 @@ static void init_proc_970 (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, POWERPC970_HID5_INIT); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -5313,7 +5751,7 @@ static void init_proc_970FX (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", + spr_register(env, SPR_750FX_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -5322,6 +5760,11 @@ static void init_proc_970FX (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, POWERPC970_HID5_INIT); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -5394,7 +5837,7 @@ static void init_proc_970GX (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", + spr_register(env, SPR_750FX_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -5403,6 +5846,11 @@ static void init_proc_970GX (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, POWERPC970_HID5_INIT); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -5475,7 +5923,7 @@ static void init_proc_970MP (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", + spr_register(env, SPR_750FX_HID2, "HID2", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); @@ -5484,6 +5932,11 @@ static void init_proc_970MP (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, POWERPC970_HID5_INIT); + /* XXX : not implemented */ + spr_register(env, SPR_L2CR, "L2CR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Memory management */ /* XXX: not correct */ gen_low_BATs(env); @@ -6092,6 +6545,7 @@ enum { #define CPU_POWERPC_601 CPU_POWERPC_601_v2 CPU_POWERPC_601_v0 = 0x00010001, CPU_POWERPC_601_v1 = 0x00010001, +#define CPU_POWERPC_601v CPU_POWERPC_601_v2 CPU_POWERPC_601_v2 = 0x00010002, CPU_POWERPC_602 = 0x00050100, CPU_POWERPC_603 = 0x00030100, @@ -6129,16 +6583,22 @@ enum { /* PowerPC 740/750 cores (aka G3) */ /* XXX: missing 0x00084202 */ #define CPU_POWERPC_7x0 CPU_POWERPC_7x0_v31 + CPU_POWERPC_7x0_v10 = 0x00080100, CPU_POWERPC_7x0_v20 = 0x00080200, CPU_POWERPC_7x0_v21 = 0x00080201, CPU_POWERPC_7x0_v22 = 0x00080202, CPU_POWERPC_7x0_v30 = 0x00080300, CPU_POWERPC_7x0_v31 = 0x00080301, CPU_POWERPC_740E = 0x00080100, + CPU_POWERPC_750E = 0x00080200, CPU_POWERPC_7x0P = 0x10080000, /* XXX: missing 0x00087010 (CL ?) */ - CPU_POWERPC_750CL = 0x00087200, +#define CPU_POWERPC_750CL CPU_POWERPC_750CL_v20 + CPU_POWERPC_750CL_v10 = 0x00087200, + CPU_POWERPC_750CL_v20 = 0x00087210, /* aka rev E */ #define CPU_POWERPC_750CX CPU_POWERPC_750CX_v22 + CPU_POWERPC_750CX_v10 = 0x00082100, + CPU_POWERPC_750CX_v20 = 0x00082200, CPU_POWERPC_750CX_v21 = 0x00082201, CPU_POWERPC_750CX_v22 = 0x00082202, #define CPU_POWERPC_750CXE CPU_POWERPC_750CXE_v31b @@ -6147,11 +6607,11 @@ enum { CPU_POWERPC_750CXE_v23 = 0x00082213, CPU_POWERPC_750CXE_v24 = 0x00082214, CPU_POWERPC_750CXE_v24b = 0x00083214, - CPU_POWERPC_750CXE_v31 = 0x00083211, + CPU_POWERPC_750CXE_v30 = 0x00082310, + CPU_POWERPC_750CXE_v31 = 0x00082311, CPU_POWERPC_750CXE_v31b = 0x00083311, CPU_POWERPC_750CXR = 0x00083410, - CPU_POWERPC_750E = 0x00080200, - CPU_POWERPC_750FL = 0x700A0203, + CPU_POWERPC_750FL = 0x70000203, #define CPU_POWERPC_750FX CPU_POWERPC_750FX_v23 CPU_POWERPC_750FX_v10 = 0x70000100, CPU_POWERPC_750FX_v20 = 0x70000200, @@ -6164,6 +6624,8 @@ enum { CPU_POWERPC_750GX_v11 = 0x70020101, CPU_POWERPC_750GX_v12 = 0x70020102, #define CPU_POWERPC_750L CPU_POWERPC_750L_v32 /* Aka LoneStar */ + CPU_POWERPC_750L_v20 = 0x00088200, + CPU_POWERPC_750L_v21 = 0x00088201, CPU_POWERPC_750L_v22 = 0x00088202, CPU_POWERPC_750L_v30 = 0x00088300, CPU_POWERPC_750L_v32 = 0x00088302, @@ -7577,13 +8039,13 @@ static const ppc_def_t ppc_defs[] = { /* 32 bits "classic" PowerPC */ /* PowerPC 6xx family */ /* PowerPC 601 */ - POWERPC_DEF("601", CPU_POWERPC_601, 601), + POWERPC_DEF("601", CPU_POWERPC_601, 601v), /* PowerPC 601v0 */ POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601), /* PowerPC 601v1 */ POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601), /* PowerPC 601v */ - POWERPC_DEF("601v", CPU_POWERPC_601, 601v), + POWERPC_DEF("601v", CPU_POWERPC_601v, 601v), /* PowerPC 601v2 */ POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v), /* PowerPC 602 */ @@ -7652,71 +8114,85 @@ static const ppc_def_t ppc_defs[] = { #endif /* PowerPC 7xx family */ /* Generic PowerPC 740 (G3) */ - POWERPC_DEF("740", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("740", CPU_POWERPC_7x0, 740), /* Code name for PowerPC 740 */ - POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 740), /* Generic PowerPC 750 (G3) */ - POWERPC_DEF("750", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("750", CPU_POWERPC_7x0, 750), /* Code name for PowerPC 750 */ - POWERPC_DEF("Typhoon", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("Typhoon", CPU_POWERPC_7x0, 750), /* PowerPC 740/750 is also known as G3 */ - POWERPC_DEF("G3", CPU_POWERPC_7x0, 7x0), + POWERPC_DEF("G3", CPU_POWERPC_7x0, 750), + /* PowerPC 740 v1.0 (G3) */ + POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740), + /* PowerPC 750 v1.0 (G3) */ + POWERPC_DEF("750_v1.0", CPU_POWERPC_7x0_v10, 750), /* PowerPC 740 v2.0 (G3) */ - POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 7x0), + POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 740), /* PowerPC 750 v2.0 (G3) */ - POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 7x0), + POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 750), /* PowerPC 740 v2.1 (G3) */ - POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 7x0), + POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 740), /* PowerPC 750 v2.1 (G3) */ - POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 7x0), + POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 750), /* PowerPC 740 v2.2 (G3) */ - POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 7x0), + POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 740), /* PowerPC 750 v2.2 (G3) */ - POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 7x0), + POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 750), /* PowerPC 740 v3.0 (G3) */ - POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 7x0), + POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 740), /* PowerPC 750 v3.0 (G3) */ - POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 7x0), + POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 750), /* PowerPC 740 v3.1 (G3) */ - POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 7x0), + POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 740), /* PowerPC 750 v3.1 (G3) */ - POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 7x0), + POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 750), /* PowerPC 740E (G3) */ - POWERPC_DEF("740e", CPU_POWERPC_740E, 7x0), + POWERPC_DEF("740e", CPU_POWERPC_740E, 740), + /* PowerPC 750E (G3) */ + POWERPC_DEF("750e", CPU_POWERPC_750E, 750), /* PowerPC 740P (G3) */ - POWERPC_DEF("740p", CPU_POWERPC_7x0P, 7x0), + POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740), /* PowerPC 750P (G3) */ - POWERPC_DEF("750p", CPU_POWERPC_7x0P, 7x0), + POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750), /* Code name for PowerPC 740P/750P (G3) */ - POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 7x0), + POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 750), /* PowerPC 750CL (G3 embedded) */ - POWERPC_DEF("750cl", CPU_POWERPC_750CL, 7x0), + POWERPC_DEF("750cl", CPU_POWERPC_750CL, 750cl), + /* PowerPC 750CL v1.0 */ + POWERPC_DEF("750cl_v1.0", CPU_POWERPC_750CL_v10, 750cl), + /* PowerPC 750CL v2.0 */ + POWERPC_DEF("750cl_v2.0", CPU_POWERPC_750CL_v20, 750cl), /* PowerPC 750CX (G3 embedded) */ - POWERPC_DEF("750cx", CPU_POWERPC_750CX, 7x0), + POWERPC_DEF("750cx", CPU_POWERPC_750CX, 750cx), + /* PowerPC 750CX v1.0 (G3 embedded) */ + POWERPC_DEF("750cx_v1.0", CPU_POWERPC_750CX_v10, 750cx), + /* PowerPC 750CX v2.1 (G3 embedded) */ + POWERPC_DEF("750cx_v2.0", CPU_POWERPC_750CX_v20, 750cx), /* PowerPC 750CX v2.1 (G3 embedded) */ - POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 7x0), + POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 750cx), /* PowerPC 750CX v2.2 (G3 embedded) */ - POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 7x0), + POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 750cx), /* PowerPC 750CXe (G3 embedded) */ - POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 7x0), + POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 750cx), /* PowerPC 750CXe v2.1 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 7x0), + POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 750cx), /* PowerPC 750CXe v2.2 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 7x0), + POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 750cx), /* PowerPC 750CXe v2.3 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 7x0), + POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 750cx), /* PowerPC 750CXe v2.4 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 7x0), + POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 750cx), /* PowerPC 750CXe v2.4b (G3 embedded) */ - POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 7x0), + POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 750cx), + /* PowerPC 750CXe v3.0 (G3 embedded) */ + POWERPC_DEF("750cxe_v3.0", CPU_POWERPC_750CXE_v30, 750cx), /* PowerPC 750CXe v3.1 (G3 embedded) */ - POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 7x0), + POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 750cx), /* PowerPC 750CXe v3.1b (G3 embedded) */ - POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 7x0), + POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 750cx), /* PowerPC 750CXr (G3 embedded) */ - POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 7x0), - /* PowerPC 750E (G3) */ - POWERPC_DEF("750e", CPU_POWERPC_750E, 7x0), + POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 750cx), /* PowerPC 750FL (G3 embedded) */ POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx), /* PowerPC 750FX (G3 embedded) */ @@ -7732,80 +8208,84 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 750FX v2.3 (G3 embedded) */ POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx), /* PowerPC 750GL (G3 embedded) */ - POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750fx), + POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750gx), /* PowerPC 750GX (G3 embedded) */ - POWERPC_DEF("750gx", CPU_POWERPC_750GX, 750fx), + POWERPC_DEF("750gx", CPU_POWERPC_750GX, 750gx), /* PowerPC 750GX v1.0 (G3 embedded) */ - POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750fx), + POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750gx), /* PowerPC 750GX v1.1 (G3 embedded) */ - POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750fx), + POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750gx), /* PowerPC 750GX v1.2 (G3 embedded) */ - POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750fx), + POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx), /* PowerPC 750L (G3 embedded) */ - POWERPC_DEF("750l", CPU_POWERPC_750L, 7x0), + POWERPC_DEF("750l", CPU_POWERPC_750L, 750), /* Code name for PowerPC 750L (G3 embedded) */ - POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 7x0), + POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 750), + /* PowerPC 750L v2.0 (G3 embedded) */ + POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750), + /* PowerPC 750L v2.1 (G3 embedded) */ + POWERPC_DEF("750l_v2.1", CPU_POWERPC_750L_v21, 750), /* PowerPC 750L v2.2 (G3 embedded) */ - POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 7x0), + POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 750), /* PowerPC 750L v3.0 (G3 embedded) */ - POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 7x0), + POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 750), /* PowerPC 750L v3.2 (G3 embedded) */ - POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 7x0), + POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 750), /* Generic PowerPC 745 */ - POWERPC_DEF("745", CPU_POWERPC_7x5, 7x5), + POWERPC_DEF("745", CPU_POWERPC_7x5, 745), /* Generic PowerPC 755 */ - POWERPC_DEF("755", CPU_POWERPC_7x5, 7x5), + POWERPC_DEF("755", CPU_POWERPC_7x5, 755), /* Code name for PowerPC 745/755 */ - POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 7x5), + POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 755), /* PowerPC 745 v1.0 */ - POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 7x5), + POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745), /* PowerPC 755 v1.0 */ - POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 7x5), + POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 755), /* PowerPC 745 v1.1 */ - POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 7x5), + POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 745), /* PowerPC 755 v1.1 */ - POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 7x5), + POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 755), /* PowerPC 745 v2.0 */ - POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 7x5), + POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 745), /* PowerPC 755 v2.0 */ - POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 7x5), + POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 755), /* PowerPC 745 v2.1 */ - POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 7x5), + POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 745), /* PowerPC 755 v2.1 */ - POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 7x5), + POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 755), /* PowerPC 745 v2.2 */ - POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 7x5), + POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 745), /* PowerPC 755 v2.2 */ - POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 7x5), + POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 755), /* PowerPC 745 v2.3 */ - POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 7x5), + POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 745), /* PowerPC 755 v2.3 */ - POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 7x5), + POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 755), /* PowerPC 745 v2.4 */ - POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 7x5), + POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 745), /* PowerPC 755 v2.4 */ - POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 7x5), + POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 755), /* PowerPC 745 v2.5 */ - POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 7x5), + POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 745), /* PowerPC 755 v2.5 */ - POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 7x5), + POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 755), /* PowerPC 745 v2.6 */ - POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 7x5), + POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 745), /* PowerPC 755 v2.6 */ - POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 7x5), + POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 755), /* PowerPC 745 v2.7 */ - POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 7x5), + POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 745), /* PowerPC 755 v2.7 */ - POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 7x5), + POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 755), /* PowerPC 745 v2.8 */ - POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 7x5), + POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 745), /* PowerPC 755 v2.8 */ - POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 7x5), + POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 755), #if defined (TODO) /* PowerPC 745P (G3) */ - POWERPC_DEF("745p", CPU_POWERPC_7x5P, 7x5), + POWERPC_DEF("745p", CPU_POWERPC_7x5P, 745), /* PowerPC 755P (G3) */ - POWERPC_DEF("755p", CPU_POWERPC_7x5P, 7x5), + POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755), #endif /* PowerPC 74xx family */ /* PowerPC 7400 (G4) */ -- cgit v1.2.3 From a1b91bb406dec9cf6c64625d37f2017c6810a9a6 Mon Sep 17 00:00:00 2001 From: pbrook Date: Wed, 21 Nov 2007 15:32:12 +0000 Subject: Fix typo in softfloat code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3714 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index f6cbd29ce..061d5b993 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -3012,7 +3012,7 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) return 0; } av = float64_val(a); - bv = float64_val(a); + bv = float64_val(b); return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); } @@ -3038,7 +3038,7 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); av = float64_val(a); - bv = float64_val(a); + bv = float64_val(b); if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); return ( av == bv ) || ( aSign ^ ( av < bv ) ); @@ -3064,7 +3064,7 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); av = float64_val(a); - bv = float64_val(a); + bv = float64_val(b); if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); return ( av != bv ) && ( aSign ^ ( av < bv ) ); @@ -3088,7 +3088,7 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) return 0; } av = float64_val(a); - bv = float64_val(a); + bv = float64_val(b); return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); } @@ -3116,7 +3116,7 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); av = float64_val(a); - bv = float64_val(a); + bv = float64_val(b); if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); return ( av == bv ) || ( aSign ^ ( av < bv ) ); @@ -3145,7 +3145,7 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); av = float64_val(a); - bv = float64_val(a); + bv = float64_val(b); if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); return ( av != bv ) && ( aSign ^ ( av < bv ) ); -- cgit v1.2.3 From 0b1b91c77ca0b2fddaeb030cb3555c9d0f4f8f66 Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 21 Nov 2007 16:18:21 +0000 Subject: typo fix git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3715 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index b46475e30..67658e297 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -83,7 +83,7 @@ static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, return; } for ( i = 0 ; i < 32 ; i++ ) - if (ext3_features[i] && !strcmp (flagname, ext3_feature_name[i])) { + if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) { *ext3_features |= 1 << i; return; } -- cgit v1.2.3 From cd8a25337e567544f52630413699d77a023237d0 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 21 Nov 2007 18:57:44 +0000 Subject: Fix more typos in softloat code (Eduardo Felipe) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3716 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 061d5b993..e30f22f91 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5391,7 +5391,7 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ aSign = extractFloat ## s ## Sign( a ); \ bSign = extractFloat ## s ## Sign( b ); \ av = float ## s ## _val(a); \ - bv = float ## s ## _val(a); \ + bv = float ## s ## _val(b); \ if ( aSign != bSign ) { \ if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) { \ /* zero case */ \ -- cgit v1.2.3 From 89dfe8980524218f99a8513f6e18dd8478e72d36 Mon Sep 17 00:00:00 2001 From: ths Date: Wed, 21 Nov 2007 22:38:37 +0000 Subject: Documentation formatting improvements, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3717 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 200 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 102 insertions(+), 98 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 92dfd5c65..fd3ca0c9f 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -199,7 +199,7 @@ Linux should boot and give you a prompt. @example @c man begin SYNOPSIS -usage: qemu [options] [disk_image] +usage: qemu [options] [@var{disk_image}] @c man end @end example @@ -208,22 +208,22 @@ usage: qemu [options] [disk_image] General options: @table @option -@item -M machine -Select the emulated machine (@code{-M ?} for list) +@item -M @var{machine} +Select the emulated @var{machine} (@code{-M ?} for list) -@item -fda file -@item -fdb file +@item -fda @var{file} +@item -fdb @var{file} Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can use the host floppy by using @file{/dev/fd0} as filename (@pxref{host_drives}). -@item -hda file -@item -hdb file -@item -hdc file -@item -hdd file +@item -hda @var{file} +@item -hdb @var{file} +@item -hdc @var{file} +@item -hdd @var{file} Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}). -@item -cdrom file -Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and and +@item -cdrom @var{file} +Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and @option{-cdrom} at the same time). You can use the host CD-ROM by using @file{/dev/cdrom} as filename (@pxref{host_drives}). @@ -240,10 +240,10 @@ the write back by pressing @key{C-a s} (@pxref{disk_images}). Disable boot signature checking for floppy disks in Bochs BIOS. It may be needed to boot from old floppy disks. -@item -m megs -Set virtual RAM size to @var{megs} megabytes. Default is 128 MB. +@item -m @var{megs} +Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB. -@item -smp n +@item -smp @var{n} Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255 CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs to 4. @@ -253,7 +253,7 @@ to 4. Will show the audio subsystem help: list of drivers, tunable parameters. -@item -soundhw card1,card2,... or -soundhw all +@item -soundhw @var{card1}[,@var{card2},...] or -soundhw all Enable audio and selected sound hardware. Use ? to print all available sound hardware. @@ -270,12 +270,12 @@ Set the real time clock to local time (the default is to UTC time). This option is needed to have correct date in MS-DOS or Windows. -@item -startdate date +@item -startdate @var{date} Set the initial date of the real time clock. Valid format for @var{date} are: @code{now} or @code{2006-06-17T16:01:21} or @code{2006-06-17}. The default value is @code{now}. -@item -pidfile file +@item -pidfile @var{file} Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. @@ -290,13 +290,14 @@ Use it when installing Windows 2000 to avoid a disk full bug. After Windows 2000 is installed, you no longer need this option (this option slows down the IDE transfers). -@item -option-rom file -Load the contents of file as an option ROM. This option is useful to load -things like EtherBoot. +@item -option-rom @var{file} +Load the contents of @var{file} as an option ROM. +This option is useful to load things like EtherBoot. -@item -name string -Sets the name of the guest. This name will be display in the SDL window -caption. The name will also be used for the VNC server. +@item -name @var{name} +Sets the @var{name} of the guest. +This name will be display in the SDL window caption. +The @var{name} will also be used for the VNC server. @end table @@ -320,7 +321,7 @@ workspace more convenient. @item -full-screen Start in full screen. -@item -vnc display[,option[,option[,...]]] +@item -vnc @var{display}[,@var{option}[,@var{option}[,...]]] Normally, QEMU uses SDL to display the VGA output. With this option, you can have QEMU listen on VNC display @var{display} and redirect the VGA @@ -332,18 +333,18 @@ syntax for the @var{display} is @table @code -@item @var{interface:d} +@item @var{interface}:@var{d} TCP connections will only be allowed from @var{interface} on display @var{d}. By convention the TCP port is 5900+@var{d}. Optionally, @var{interface} can be omitted in which case the server will bind to all interfaces. -@item @var{unix:path} +@item @var{unix}:@var{path} Connections will be allowed over UNIX domain sockets where @var{path} is the location of a unix socket to listen for connections on. -@item @var{none} +@item none VNC is initialized by not started. The monitor @code{change} command can be used to later start the VNC server. @@ -355,31 +356,31 @@ separated by commas. Valid options are @table @code -@item @var{password} +@item password Require that password based authentication is used for client connections. The password must be set separately using the @code{change} command in the @ref{pcsys_monitor} -@item @var{tls} +@item tls Require that client use TLS when communicating with the VNC server. This uses anonymous TLS credentials so is susceptible to a man-in-the-middle attack. It is recommended that this option be combined with either the @var{x509} or @var{x509verify} options. -@item @var{x509=/path/to/certificate/dir} +@item x509=@var{/path/to/certificate/dir} -Valid if @var{tls} is specified. Require that x509 credentials are used +Valid if @option{tls} is specified. Require that x509 credentials are used for negotiating the TLS session. The server will send its x509 certificate to the client. It is recommended that a password be set on the VNC server to provide authentication of the client when this is used. The path following this option specifies where the x509 certificates are to be loaded from. See the @ref{vnc_security} section for details on generating certificates. -@item @var{x509verify=/path/to/certificate/dir} +@item x509verify=@var{/path/to/certificate/dir} -Valid if @var{tls} is specified. Require that x509 credentials are used +Valid if @option{tls} is specified. Require that x509 credentials are used for negotiating the TLS session. The server will send its x509 certificate to the client, and request that the client send its own x509 certificate. The server will validate the client's certificate against the CA certificate, @@ -392,7 +393,7 @@ certificates. @end table -@item -k language +@item -k @var{language} Use keyboard layout @var{language} (for example @code{fr} for French). This option is only needed where it is not easy to get raw PC @@ -417,7 +418,7 @@ USB options: @item -usb Enable the USB driver (will be the default soon) -@item -usbdevice devname +@item -usbdevice @var{devname} Add the USB device @var{devname}. @xref{usb_devices}. @end table @@ -425,7 +426,7 @@ Network options: @table @option -@item -net nic[,vlan=n][,macaddr=addr][,model=type] +@item -net nic[,vlan=@var{n}][,macaddr=@var{addr}][,model=@var{type}] Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n} = 0 is the default). The NIC is an ne2k_pci by default on the PC target. Optionally, the MAC address can be changed. If no @@ -438,17 +439,17 @@ Valid values for @var{type} are Not all devices are supported on all targets. Use -net nic,model=? for a list of available devices for your target. -@item -net user[,vlan=n][,hostname=name] +@item -net user[,vlan=@var{n}][,hostname=@var{name}] Use the user mode network stack which requires no administrator privilege to run. @option{hostname=name} can be used to specify the client hostname reported by the builtin DHCP server. -@item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file] +@item -net tap[,vlan=@var{n}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}] Connect the host TAP network interface @var{name} to VLAN @var{n} and use the network script @var{file} to configure it. The default network script is @file{/etc/qemu-ifup}. Use @option{script=no} to disable script execution. If @var{name} is not -provided, the OS automatically provides one. @option{fd=h} can be +provided, the OS automatically provides one. @option{fd}=@var{h} can be used to specify the handle of an already opened host TAP interface. Example: @example @@ -462,13 +463,13 @@ qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \ @end example -@item -net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port] +@item -net socket[,vlan=@var{n}][,fd=@var{h}][,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}] Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual machine using a TCP socket connection. If @option{listen} is specified, QEMU waits for incoming connections on @var{port} (@var{host} is optional). @option{connect} is used to connect to -another QEMU instance using the @option{listen} option. @option{fd=h} +another QEMU instance using the @option{listen} option. @option{fd}=@var{h} specifies an already opened TCP socket. Example: @@ -482,7 +483,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \ -net socket,connect=127.0.0.1:1234 @end example -@item -net socket[,vlan=n][,fd=h][,mcast=maddr:port] +@item -net socket[,vlan=@var{n}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}] Create a VLAN @var{n} shared with another QEMU virtual machines using a UDP multicast socket, effectively making a bus for @@ -527,14 +528,14 @@ Indicate that no network devices should be configured. It is used to override the default configuration (@option{-net nic -net user}) which is activated if no @option{-net} options are provided. -@item -tftp dir +@item -tftp @var{dir} When using the user mode network stack, activate a built-in TFTP server. The files in @var{dir} will be exposed as the root of a TFTP server. The TFTP client on the guest must be configured in binary mode (use the command @code{bin} of the Unix TFTP client). The host IP address on the guest is as usual 10.0.2.2. -@item -bootp file +@item -bootp @var{file} When using the user mode network stack, broadcast @var{file} as the BOOTP filename. In conjunction with @option{-tftp}, this can be used to network boot a guest from a local directory. @@ -544,9 +545,9 @@ Example (using pxelinux): qemu -hda linux.img -boot n -tftp /path/to/tftp/files -bootp /pxelinux.0 @end example -@item -smb dir +@item -smb @var{dir} When using the user mode network stack, activate a built-in SMB -server so that Windows OSes can access to the host files in @file{dir} +server so that Windows OSes can access to the host files in @file{@var{dir}} transparently. In the guest Windows OS, the line: @@ -556,13 +557,13 @@ In the guest Windows OS, the line: must be added in the file @file{C:\WINDOWS\LMHOSTS} (for windows 9x/Me) or @file{C:\WINNT\SYSTEM32\DRIVERS\ETC\LMHOSTS} (Windows NT/2000). -Then @file{dir} can be accessed in @file{\\smbserver\qemu}. +Then @file{@var{dir}} can be accessed in @file{\\smbserver\qemu}. Note that a SAMBA server must be installed on the host OS in @file{/usr/sbin/smbd}. QEMU was tested successfully with smbd version 2.2.7a from the Red Hat 9 and version 3.0.10-1.fc3 from Fedora Core 3. -@item -redir [tcp|udp]:host-port:[guest-host]:guest-port +@item -redir [tcp|udp]:@var{host-port}:[@var{guest-host}]:@var{guest-port} When using the user mode network stack, redirect incoming TCP or UDP connections to the host port @var{host-port} to the guest @@ -600,13 +601,13 @@ for easier testing of various kernels. @table @option -@item -kernel bzImage +@item -kernel @var{bzImage} Use @var{bzImage} as kernel image. -@item -append cmdline +@item -append @var{cmdline} Use @var{cmdline} as kernel command line -@item -initrd file +@item -initrd @var{file} Use @var{file} as initial ram disk. @end table @@ -614,7 +615,7 @@ Use @var{file} as initial ram disk. Debug/Expert options: @table @option -@item -serial dev +@item -serial @var{dev} Redirect the virtual serial port to host character device @var{dev}. The default device is @code{vc} in graphical mode and @code{stdio} in non graphical mode. @@ -644,19 +645,22 @@ void device @item /dev/XXX [Linux only] Use host tty, e.g. @file{/dev/ttyS0}. The host serial port parameters are set according to the emulated ones. -@item /dev/parportN +@item /dev/parport@var{N} [Linux only, parallel port only] Use host parallel port @var{N}. Currently SPP and EPP parallel port features can be used. -@item file:filename -Write output to filename. No character can be read. +@item file:@var{filename} +Write output to @var{filename}. No character can be read. @item stdio [Unix only] standard input/output -@item pipe:filename +@item pipe:@var{filename} name pipe @var{filename} -@item COMn +@item COM@var{n} [Windows only] Use host serial port @var{n} -@item udp:[remote_host]:remote_port[@@[src_ip]:src_port] -This implements UDP Net Console. When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}. When not using a specified @var{src_port} a random port is automatically chosen. +@item udp:[@var{remote_host}]:@var{remote_port}[@@[@var{src_ip}]:@var{src_port}] +This implements UDP Net Console. +When @var{remote_host} or @var{src_ip} are not specified +they default to @code{0.0.0.0}. +When not using a specified @var{src_port} a random port is automatically chosen. If you just want a simple readonly console you can use @code{netcat} or @code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as: @@ -682,7 +686,7 @@ localhost 5555 @end table -@item tcp:[host]:port[,server][,nowait][,nodelay] +@item tcp:[@var{host}]:@var{port}[,@var{server}][,nowait][,nodelay] The TCP Net Console has two modes of operation. It can send the serial I/O to a location or wait for a connection from a location. By default the TCP Net Console is sent to @var{host} at the @var{port}. If you use @@ -701,7 +705,7 @@ connect to the corresponding character device. -serial tcp:192.168.0.100:4444,server,nowait @end table -@item telnet:host:port[,server][,nowait][,nodelay] +@item telnet:@var{host}:@var{port}[,server][,nowait][,nodelay] The telnet protocol is used instead of raw tcp sockets. The options work the same as if you had specified @code{-serial tcp}. The difference is that the port acts like a telnet server or client using @@ -710,12 +714,12 @@ MAGIC_SYSRQ sequence if you use a telnet that supports sending the break sequence. Typically in unix telnet you do it with Control-] and then type "send break" followed by pressing the enter key. -@item unix:path[,server][,nowait] +@item unix:@var{path}[,server][,nowait] A unix domain socket is used instead of a tcp socket. The option works the same as if you had specified @code{-serial tcp} except the unix domain socket @var{path} is used for connections. -@item mon:dev_string +@item mon:@var{dev_string} This is a special option to allow the monitor to be multiplexed onto another serial port. The monitor is accessed with key sequence of @key{Control-a} and then pressing @key{c}. See monitor access @@ -729,7 +733,7 @@ listening on port 4444 would be: @end table -@item -parallel dev +@item -parallel @var{dev} Redirect the virtual parallel port to host device @var{dev} (same devices as the serial port). On Linux hosts, @file{/dev/parportN} can be used to use hardware devices connected on the corresponding host @@ -740,7 +744,7 @@ ports. Use @code{-parallel none} to disable all parallel ports. -@item -monitor dev +@item -monitor @var{dev} Redirect the monitor to host device @var{dev} (same devices as the serial port). The default device is @code{vc} in graphical mode and @code{stdio} in @@ -761,14 +765,14 @@ character to Control-t. @item -s Wait gdb connection to port 1234 (@pxref{gdb_usage}). -@item -p port +@item -p @var{port} Change gdb connection port. @var{port} can be either a decimal number to specify a TCP port, or a host device (same devices as the serial port). @item -S Do not start CPU at startup (you must type 'c' in the monitor). @item -d Output log in /tmp/qemu.log -@item -hdachs c,h,s,[,t] +@item -hdachs @var{c},@var{h},@var{s},[,@var{t}] Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= @var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS translation mode (@var{t}=none, lba or auto). Usually QEMU can guess @@ -879,7 +883,7 @@ emulator. You can use it to: @item Remove or insert removable media images -(such as CD-ROM or floppies) +(such as CD-ROM or floppies). @item Freeze/unfreeze the Virtual Machine (VM) and save or restore its state @@ -895,14 +899,14 @@ The following commands are available: @table @option -@item help or ? [cmd] +@item help or ? [@var{cmd}] Show the help for all commands or just for command @var{cmd}. @item commit -Commit changes to the disk images (if -snapshot is used) +Commit changes to the disk images (if -snapshot is used). -@item info subcommand -show various information about the system state +@item info @var{subcommand} +Show various information about the system state. @table @option @item info network @@ -930,12 +934,12 @@ show which guest mouse is receiving events @item q or quit Quit the emulator. -@item eject [-f] device +@item eject [-f] @var{device} Eject a removable medium (use -f to force it). -@item change device setting +@item change @var{device} @var{setting} -Change the configuration of a device +Change the configuration of a device. @table @option @item change @var{diskdevice} @var{filename} @@ -945,7 +949,7 @@ Change the medium for a removable disk device to point to @var{filename}. eg (qemu) change cdrom /path/to/some.iso @end example -@item change vnc @var{display,options} +@item change vnc @var{display},@var{options} Change the configuration of the VNC server. The valid syntax for @var{display} and @var{options} are described at @ref{sec_invocation}. eg @@ -966,24 +970,24 @@ Password: ******** @end table -@item screendump filename +@item screendump @var{filename} Save screen into PPM image @var{filename}. -@item mouse_move dx dy [dz] +@item mouse_move @var{dx} @var{dy} [@var{dz}] Move the active mouse to the specified coordinates @var{dx} @var{dy} with optional scroll axis @var{dz}. -@item mouse_button val +@item mouse_button @var{val} Change the active mouse button state @var{val} (1=L, 2=M, 4=R). -@item mouse_set index +@item mouse_set @var{index} Set which mouse device receives events at given @var{index}, index can be obtained with @example info mice @end example -@item wavcapture filename [frequency [bits [channels]]] +@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]] Capture audio into @var{filename}. Using sample rate @var{frequency} bits per sample @var{bits} and number of channels @var{channels}. @@ -994,26 +998,26 @@ Defaults: @item Number of channels = 2 - Stereo @end itemize -@item stopcapture index +@item stopcapture @var{index} Stop capture with a given @var{index}, index can be obtained with @example info capture @end example -@item log item1[,...] +@item log @var{item1}[,...] Activate logging of the specified items to @file{/tmp/qemu.log}. -@item savevm [tag|id] +@item savevm [@var{tag}|@var{id}] Create a snapshot of the whole virtual machine. If @var{tag} is provided, it is used as human readable identifier. If there is already a snapshot with the same tag or ID, it is replaced. More info at @ref{vm_snapshots}. -@item loadvm tag|id +@item loadvm @var{tag}|@var{id} Set the whole virtual machine to the snapshot identified by the tag @var{tag} or the unique snapshot ID @var{id}. -@item delvm tag|id +@item delvm @var{tag}|@var{id} Delete the snapshot identified by @var{tag} or @var{id}. @item stop @@ -1022,13 +1026,13 @@ Stop emulation. @item c or cont Resume emulation. -@item gdbserver [port] -Start gdbserver session (default port=1234) +@item gdbserver [@var{port}] +Start gdbserver session (default @var{port}=1234) -@item x/fmt addr +@item x/fmt @var{addr} Virtual memory dump starting at @var{addr}. -@item xp /fmt addr +@item xp /@var{fmt} @var{addr} Physical memory dump starting at @var{addr}. @var{fmt} is a format which tells the command how to format the @@ -1084,12 +1088,12 @@ Dump 80 16 bit values at the start of the video memory. @end smallexample @end itemize -@item p or print/fmt expr +@item p or print/@var{fmt} @var{expr} Print expression value. Only the @var{format} part of @var{fmt} is used. -@item sendkey keys +@item sendkey @var{keys} Send @var{keys} to the emulator. Use @code{-} to press several keys simultaneously. Example: @@ -1104,12 +1108,12 @@ intercepts at low level, such as @code{ctrl-alt-f1} in X Window. Reset the system. -@item usb_add devname +@item usb_add @var{devname} Add the USB device @var{devname}. For details of available devices see @ref{usb_devices} -@item usb_del devname +@item usb_del @var{devname} Remove the USB device @var{devname} from the QEMU virtual USB hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor @@ -1263,7 +1267,7 @@ Currently there is no specific code to handle removable media, so it is better to use the @code{change} or @code{eject} monitor commands to change or eject media. @item Hard disks -Hard disks can be used with the syntax: @file{\\.\PhysicalDriveN} +Hard disks can be used with the syntax: @file{\\.\PhysicalDrive@var{N}} where @var{N} is the drive number (0 is the first hard disk). WARNING: unless you know what you do, it is better to only make @@ -1458,12 +1462,12 @@ Virtual Mouse. This will override the PS/2 mouse emulation when activated. Pointer device that uses absolute coordinates (like a touchscreen). This means qemu is able to report the mouse position without having to grab the mouse. Also overrides the PS/2 mouse emulation when activated. -@item @code{disk:file} +@item @code{disk:@var{file}} Mass storage device based on @var{file} (@pxref{disk_images}) -@item @code{host:bus.addr} +@item @code{host:@var{bus.addr}} Pass through the host device identified by @var{bus.addr} (Linux only) -@item @code{host:vendor_id:product_id} +@item @code{host:@var{vendor_id:product_id}} Pass through the host device identified by @var{vendor_id:product_id} (Linux only) @item @code{wacom-tablet} -- cgit v1.2.3 From 67d6abff605064317d1922745b2e99ffc57b4a77 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 22 Nov 2007 00:34:36 +0000 Subject: Fix off-by-one address checks in MIPS64 MMU, by Aurelien Jarno. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3718 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-mips/helper.c b/target-mips/helper.c index 6cdcd7f1d..e7d788752 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -133,7 +133,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, #if defined(TARGET_MIPS64) } else if (address < 0x4000000000000000ULL) { /* xuseg */ - if (UX && address < (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { + if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; @@ -141,7 +141,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else if (address < 0x8000000000000000ULL) { /* xsseg */ if ((supervisor_mode || kernel_mode) && - SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { + SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; @@ -150,7 +150,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, /* xkphys */ /* XXX: Assumes PABITS = 36 (correct for MIPS64R1) */ if (kernel_mode && KX && - (address & 0x07FFFFFFFFFFFFFFULL) < 0x0000000FFFFFFFFFULL) { + (address & 0x07FFFFFFFFFFFFFFULL) <= 0x0000000FFFFFFFFFULL) { *physical = address & 0x0000000FFFFFFFFFULL; *prot = PAGE_READ | PAGE_WRITE; } else { @@ -159,7 +159,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, } else if (address < 0xFFFFFFFF80000000ULL) { /* xkseg */ if (kernel_mode && KX && - address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { + address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { ret = env->tlb->map_address(env, physical, prot, address, rw, access_type); } else { ret = TLBRET_BADADDR; -- cgit v1.2.3 From e7c240035fe1ffbb6efba10e8db002f92459ad00 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 22 Nov 2007 11:00:46 +0000 Subject: Add new sane low-level memory accessors for PowerPC that do proper size or zero extension, with homogenous names. Fix load & store strings: those are now endian-sensitive, by definition. Fix dcbz: must always align the target address to a cache line boundary. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3719 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op_helper.h | 4 - target-ppc/op_helper_mem.h | 140 ++-------- target-ppc/op_mem.h | 650 +++++++++++++++++---------------------------- target-ppc/op_mem_access.h | 148 +++++++++++ target-ppc/translate.c | 25 ++ 5 files changed, 443 insertions(+), 524 deletions(-) create mode 100644 target-ppc/op_mem_access.h diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 94cf4673f..5ec13a420 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -22,9 +22,7 @@ /* Memory load/store helpers */ void glue(do_lsw, MEMSUFFIX) (int dst); -void glue(do_lsw_le, MEMSUFFIX) (int dst); void glue(do_stsw, MEMSUFFIX) (int src); -void glue(do_stsw_le, MEMSUFFIX) (int src); void glue(do_lmw, MEMSUFFIX) (int dst); void glue(do_lmw_le, MEMSUFFIX) (int dst); void glue(do_stmw, MEMSUFFIX) (int src); @@ -39,9 +37,7 @@ void glue(do_POWER2_stfq_le, MEMSUFFIX) (void); #if defined(TARGET_PPC64) void glue(do_lsw_64, MEMSUFFIX) (int dst); -void glue(do_lsw_le_64, MEMSUFFIX) (int dst); void glue(do_stsw_64, MEMSUFFIX) (int src); -void glue(do_stsw_le_64, MEMSUFFIX) (int src); void glue(do_lmw_64, MEMSUFFIX) (int dst); void glue(do_lmw_le_64, MEMSUFFIX) (int dst); void glue(do_stmw_64, MEMSUFFIX) (int src); diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h index e8aa6407c..1d7b991ca 100644 --- a/target-ppc/op_helper_mem.h +++ b/target-ppc/op_helper_mem.h @@ -18,27 +18,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Multiple word / string load and store */ -static always_inline target_ulong glue(ld32r, MEMSUFFIX) (target_ulong EA) -{ - uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); - return ((tmp & 0xFF000000UL) >> 24) | ((tmp & 0x00FF0000UL) >> 8) | - ((tmp & 0x0000FF00UL) << 8) | ((tmp & 0x000000FFUL) << 24); -} - -static always_inline void glue(st32r, MEMSUFFIX) (target_ulong EA, - target_ulong data) -{ - uint32_t tmp = - ((data & 0xFF000000UL) >> 24) | ((data & 0x00FF0000UL) >> 8) | - ((data & 0x0000FF00UL) << 8) | ((data & 0x000000FFUL) << 24); - glue(stl, MEMSUFFIX)(EA, tmp); -} +#include "op_mem_access.h" +/* Multiple word / string load and store */ void glue(do_lmw, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - env->gpr[dst] = glue(ldl, MEMSUFFIX)((uint32_t)T0); + env->gpr[dst] = glue(ldu32, MEMSUFFIX)((uint32_t)T0); } } @@ -46,7 +32,7 @@ void glue(do_lmw, MEMSUFFIX) (int dst) void glue(do_lmw_64, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - env->gpr[dst] = glue(ldl, MEMSUFFIX)((uint64_t)T0); + env->gpr[dst] = glue(ldu32, MEMSUFFIX)((uint64_t)T0); } } #endif @@ -54,7 +40,7 @@ void glue(do_lmw_64, MEMSUFFIX) (int dst) void glue(do_stmw, MEMSUFFIX) (int src) { for (; src < 32; src++, T0 += 4) { - glue(stl, MEMSUFFIX)((uint32_t)T0, env->gpr[src]); + glue(st32, MEMSUFFIX)((uint32_t)T0, env->gpr[src]); } } @@ -62,7 +48,7 @@ void glue(do_stmw, MEMSUFFIX) (int src) void glue(do_stmw_64, MEMSUFFIX) (int src) { for (; src < 32; src++, T0 += 4) { - glue(stl, MEMSUFFIX)((uint64_t)T0, env->gpr[src]); + glue(st32, MEMSUFFIX)((uint64_t)T0, env->gpr[src]); } } #endif @@ -70,7 +56,7 @@ void glue(do_stmw_64, MEMSUFFIX) (int src) void glue(do_lmw_le, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - env->gpr[dst] = glue(ld32r, MEMSUFFIX)((uint32_t)T0); + env->gpr[dst] = glue(ldu32r, MEMSUFFIX)((uint32_t)T0); } } @@ -78,7 +64,7 @@ void glue(do_lmw_le, MEMSUFFIX) (int dst) void glue(do_lmw_le_64, MEMSUFFIX) (int dst) { for (; dst < 32; dst++, T0 += 4) { - env->gpr[dst] = glue(ld32r, MEMSUFFIX)((uint64_t)T0); + env->gpr[dst] = glue(ldu32r, MEMSUFFIX)((uint64_t)T0); } } #endif @@ -105,14 +91,14 @@ void glue(do_lsw, MEMSUFFIX) (int dst) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - env->gpr[dst++] = glue(ldl, MEMSUFFIX)((uint32_t)T0); + env->gpr[dst++] = glue(ldu32, MEMSUFFIX)((uint32_t)T0); if (unlikely(dst == 32)) dst = 0; } if (unlikely(T1 != 0)) { tmp = 0; for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { - tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh; + tmp |= glue(ldu8, MEMSUFFIX)((uint32_t)T0) << sh; } env->gpr[dst] = tmp; } @@ -125,14 +111,14 @@ void glue(do_lsw_64, MEMSUFFIX) (int dst) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - env->gpr[dst++] = glue(ldl, MEMSUFFIX)((uint64_t)T0); + env->gpr[dst++] = glue(ldu32, MEMSUFFIX)((uint64_t)T0); if (unlikely(dst == 32)) dst = 0; } if (unlikely(T1 != 0)) { tmp = 0; for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) { - tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh; + tmp |= glue(ldu8, MEMSUFFIX)((uint64_t)T0) << sh; } env->gpr[dst] = tmp; } @@ -144,13 +130,13 @@ void glue(do_stsw, MEMSUFFIX) (int src) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(stl, MEMSUFFIX)((uint32_t)T0, env->gpr[src++]); + glue(st32, MEMSUFFIX)((uint32_t)T0, env->gpr[src++]); if (unlikely(src == 32)) src = 0; } if (unlikely(T1 != 0)) { for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) - glue(stb, MEMSUFFIX)((uint32_t)T0, (env->gpr[src] >> sh) & 0xFF); + glue(st8, MEMSUFFIX)((uint32_t)T0, (env->gpr[src] >> sh) & 0xFF); } } @@ -160,85 +146,13 @@ void glue(do_stsw_64, MEMSUFFIX) (int src) int sh; for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(stl, MEMSUFFIX)((uint64_t)T0, env->gpr[src++]); + glue(st32, MEMSUFFIX)((uint64_t)T0, env->gpr[src++]); if (unlikely(src == 32)) src = 0; } if (unlikely(T1 != 0)) { for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) - glue(stb, MEMSUFFIX)((uint64_t)T0, (env->gpr[src] >> sh) & 0xFF); - } -} -#endif - -void glue(do_lsw_le, MEMSUFFIX) (int dst) -{ - uint32_t tmp; - int sh; - - for (; T1 > 3; T1 -= 4, T0 += 4) { - env->gpr[dst++] = glue(ld32r, MEMSUFFIX)((uint32_t)T0); - if (unlikely(dst == 32)) - dst = 0; - } - if (unlikely(T1 != 0)) { - tmp = 0; - for (sh = 0; T1 > 0; T1--, T0++, sh += 8) { - tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh; - } - env->gpr[dst] = tmp; - } -} - -#if defined(TARGET_PPC64) -void glue(do_lsw_le_64, MEMSUFFIX) (int dst) -{ - uint32_t tmp; - int sh; - - for (; T1 > 3; T1 -= 4, T0 += 4) { - env->gpr[dst++] = glue(ld32r, MEMSUFFIX)((uint64_t)T0); - if (unlikely(dst == 32)) - dst = 0; - } - if (unlikely(T1 != 0)) { - tmp = 0; - for (sh = 0; T1 > 0; T1--, T0++, sh += 8) { - tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh; - } - env->gpr[dst] = tmp; - } -} -#endif - -void glue(do_stsw_le, MEMSUFFIX) (int src) -{ - int sh; - - for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(st32r, MEMSUFFIX)((uint32_t)T0, env->gpr[src++]); - if (unlikely(src == 32)) - src = 0; - } - if (unlikely(T1 != 0)) { - for (sh = 0; T1 > 0; T1--, T0++, sh += 8) - glue(stb, MEMSUFFIX)((uint32_t)T0, (env->gpr[src] >> sh) & 0xFF); - } -} - -#if defined(TARGET_PPC64) -void glue(do_stsw_le_64, MEMSUFFIX) (int src) -{ - int sh; - - for (; T1 > 3; T1 -= 4, T0 += 4) { - glue(st32r, MEMSUFFIX)((uint64_t)T0, env->gpr[src++]); - if (unlikely(src == 32)) - src = 0; - } - if (unlikely(T1 != 0)) { - for (sh = 0; T1 > 0; T1--, T0++, sh += 8) - glue(stb, MEMSUFFIX)((uint64_t)T0, (env->gpr[src] >> sh) & 0xFF); + glue(st8, MEMSUFFIX)((uint64_t)T0, (env->gpr[src] >> sh) & 0xFF); } } #endif @@ -281,6 +195,7 @@ void glue(do_dcbz, MEMSUFFIX) (void) /* XXX: should be 970 specific (?) */ if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) dcache_line_size = 32; + T0 &= ~(uint32_t)(dcache_line_size - 1); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); @@ -327,6 +242,7 @@ void glue(do_dcbz_64, MEMSUFFIX) (void) /* XXX: should be 970 specific (?) */ if (((env->spr[SPR_970_HID5] >> 6) & 0x3) == 0x2) dcache_line_size = 32; + T0 &= ~(uint64_t)(dcache_line_size - 1); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); @@ -375,7 +291,7 @@ void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb) d = 24; reg = dest; for (i = 0; i < T1; i++) { - c = glue(ldub, MEMSUFFIX)((uint32_t)T0++); + c = glue(ldu8, MEMSUFFIX)((uint32_t)T0++); /* ra (if not 0) and rb are never modified */ if (likely(reg != rb && (ra == 0 || reg != ra))) { env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d); @@ -408,14 +324,7 @@ static always_inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) } u; u.d = glue(ldfq, MEMSUFFIX)(EA); - u.u = ((u.u & 0xFF00000000000000ULL) >> 56) | - ((u.u & 0x00FF000000000000ULL) >> 40) | - ((u.u & 0x0000FF0000000000ULL) >> 24) | - ((u.u & 0x000000FF00000000ULL) >> 8) | - ((u.u & 0x00000000FF000000ULL) << 8) | - ((u.u & 0x0000000000FF0000ULL) << 24) | - ((u.u & 0x000000000000FF00ULL) << 40) | - ((u.u & 0x00000000000000FFULL) << 56); + u.u = bswap64(u.u); return u.d; } @@ -440,14 +349,7 @@ static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) } u; u.d = d; - u.u = ((u.u & 0xFF00000000000000ULL) >> 56) | - ((u.u & 0x00FF000000000000ULL) >> 40) | - ((u.u & 0x0000FF0000000000ULL) >> 24) | - ((u.u & 0x000000FF00000000ULL) >> 8) | - ((u.u & 0x00000000FF000000ULL) << 8) | - ((u.u & 0x0000000000FF0000ULL) << 24) | - ((u.u & 0x000000000000FF00ULL) << 40) | - ((u.u & 0x00000000000000FFULL) << 56); + u.u = bswap64(u.u); glue(stfq, MEMSUFFIX)(EA, u.d); } diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h index a1b3e36c2..16dd4ceeb 100644 --- a/target-ppc/op_mem.h +++ b/target-ppc/op_mem.h @@ -18,80 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -static always_inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA) -{ - uint16_t tmp = glue(lduw, MEMSUFFIX)(EA); - return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); -} - -static always_inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA) -{ - int16_t tmp = glue(lduw, MEMSUFFIX)(EA); - return (int16_t)((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8); -} - -static always_inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA) -{ - uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); - return ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | - ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); -} - -static always_inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA) -{ - uint64_t tmp = glue(ldq, MEMSUFFIX)(EA); - return ((tmp & 0xFF00000000000000ULL) >> 56) | - ((tmp & 0x00FF000000000000ULL) >> 40) | - ((tmp & 0x0000FF0000000000ULL) >> 24) | - ((tmp & 0x000000FF00000000ULL) >> 8) | - ((tmp & 0x00000000FF000000ULL) << 8) | - ((tmp & 0x0000000000FF0000ULL) << 24) | - ((tmp & 0x000000000000FF00ULL) << 40) | - ((tmp & 0x00000000000000FFULL) << 54); -} - -#if defined(TARGET_PPC64) -static always_inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA) -{ - return (int32_t)glue(ldl, MEMSUFFIX)(EA); -} - -static always_inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA) -{ - uint32_t tmp = glue(ldl, MEMSUFFIX)(EA); - return (int32_t)((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) | - ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); -} -#endif - -static always_inline void glue(st16r, MEMSUFFIX) (target_ulong EA, - uint16_t data) -{ - uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8); - glue(stw, MEMSUFFIX)(EA, tmp); -} - -static always_inline void glue(st32r, MEMSUFFIX) (target_ulong EA, - uint32_t data) -{ - uint32_t tmp = ((data & 0xFF000000) >> 24) | ((data & 0x00FF0000) >> 8) | - ((data & 0x0000FF00) << 8) | ((data & 0x000000FF) << 24); - glue(stl, MEMSUFFIX)(EA, tmp); -} - -static always_inline void glue(st64r, MEMSUFFIX) (target_ulong EA, - uint64_t data) -{ - uint64_t tmp = ((data & 0xFF00000000000000ULL) >> 56) | - ((data & 0x00FF000000000000ULL) >> 40) | - ((data & 0x0000FF0000000000ULL) >> 24) | - ((data & 0x000000FF00000000ULL) >> 8) | - ((data & 0x00000000FF000000ULL) << 8) | - ((data & 0x0000000000FF0000ULL) << 24) | - ((data & 0x000000000000FF00ULL) << 40) | - ((data & 0x00000000000000FFULL) << 56); - glue(stq, MEMSUFFIX)(EA, tmp); -} +#include "op_mem_access.h" /*** Integer load ***/ #define PPC_LD_OP(name, op) \ @@ -126,76 +53,76 @@ void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void) \ } #endif -PPC_LD_OP(bz, ldub); -PPC_LD_OP(ha, ldsw); -PPC_LD_OP(hz, lduw); -PPC_LD_OP(wz, ldl); +PPC_LD_OP(bz, ldu8); +PPC_LD_OP(ha, lds16); +PPC_LD_OP(hz, ldu16); +PPC_LD_OP(wz, ldu32); #if defined(TARGET_PPC64) -PPC_LD_OP(d, ldq); -PPC_LD_OP(wa, ldsl); -PPC_LD_OP_64(d, ldq); -PPC_LD_OP_64(wa, ldsl); -PPC_LD_OP_64(bz, ldub); -PPC_LD_OP_64(ha, ldsw); -PPC_LD_OP_64(hz, lduw); -PPC_LD_OP_64(wz, ldl); +PPC_LD_OP(wa, lds32); +PPC_LD_OP(d, ldu64); +PPC_LD_OP_64(bz, ldu8); +PPC_LD_OP_64(ha, lds16); +PPC_LD_OP_64(hz, ldu16); +PPC_LD_OP_64(wz, ldu32); +PPC_LD_OP_64(wa, lds32); +PPC_LD_OP_64(d, ldu64); #endif -PPC_LD_OP(ha_le, ld16rs); -PPC_LD_OP(hz_le, ld16r); -PPC_LD_OP(wz_le, ld32r); +PPC_LD_OP(ha_le, lds16r); +PPC_LD_OP(hz_le, ldu16r); +PPC_LD_OP(wz_le, ldu32r); #if defined(TARGET_PPC64) -PPC_LD_OP(d_le, ld64r); -PPC_LD_OP(wa_le, ld32rs); -PPC_LD_OP_64(d_le, ld64r); -PPC_LD_OP_64(wa_le, ld32rs); -PPC_LD_OP_64(ha_le, ld16rs); -PPC_LD_OP_64(hz_le, ld16r); -PPC_LD_OP_64(wz_le, ld32r); +PPC_LD_OP(wa_le, lds32r); +PPC_LD_OP(d_le, ldu64r); +PPC_LD_OP_64(ha_le, lds16r); +PPC_LD_OP_64(hz_le, ldu16r); +PPC_LD_OP_64(wz_le, ldu32r); +PPC_LD_OP_64(wa_le, lds32r); +PPC_LD_OP_64(d_le, ldu64r); #endif /*** Integer store ***/ -PPC_ST_OP(b, stb); -PPC_ST_OP(h, stw); -PPC_ST_OP(w, stl); +PPC_ST_OP(b, st8); +PPC_ST_OP(h, st16); +PPC_ST_OP(w, st32); #if defined(TARGET_PPC64) -PPC_ST_OP(d, stq); -PPC_ST_OP_64(d, stq); -PPC_ST_OP_64(b, stb); -PPC_ST_OP_64(h, stw); -PPC_ST_OP_64(w, stl); +PPC_ST_OP(d, st64); +PPC_ST_OP_64(b, st8); +PPC_ST_OP_64(h, st16); +PPC_ST_OP_64(w, st32); +PPC_ST_OP_64(d, st64); #endif PPC_ST_OP(h_le, st16r); PPC_ST_OP(w_le, st32r); #if defined(TARGET_PPC64) PPC_ST_OP(d_le, st64r); -PPC_ST_OP_64(d_le, st64r); PPC_ST_OP_64(h_le, st16r); PPC_ST_OP_64(w_le, st32r); +PPC_ST_OP_64(d_le, st64r); #endif /*** Integer load and store with byte reverse ***/ -PPC_LD_OP(hbr, ld16r); -PPC_LD_OP(wbr, ld32r); +PPC_LD_OP(hbr, ldu16r); +PPC_LD_OP(wbr, ldu32r); PPC_ST_OP(hbr, st16r); PPC_ST_OP(wbr, st32r); #if defined(TARGET_PPC64) -PPC_LD_OP_64(hbr, ld16r); -PPC_LD_OP_64(wbr, ld32r); +PPC_LD_OP_64(hbr, ldu16r); +PPC_LD_OP_64(wbr, ldu32r); PPC_ST_OP_64(hbr, st16r); PPC_ST_OP_64(wbr, st32r); #endif -PPC_LD_OP(hbr_le, lduw); -PPC_LD_OP(wbr_le, ldl); -PPC_ST_OP(hbr_le, stw); -PPC_ST_OP(wbr_le, stl); +PPC_LD_OP(hbr_le, ldu16); +PPC_LD_OP(wbr_le, ldu32); +PPC_ST_OP(hbr_le, st16); +PPC_ST_OP(wbr_le, st32); #if defined(TARGET_PPC64) -PPC_LD_OP_64(hbr_le, lduw); -PPC_LD_OP_64(wbr_le, ldl); -PPC_ST_OP_64(hbr_le, stw); -PPC_ST_OP_64(wbr_le, stl); +PPC_LD_OP_64(hbr_le, ldu16); +PPC_LD_OP_64(wbr_le, ldu32); +PPC_ST_OP_64(hbr_le, st16); +PPC_ST_OP_64(wbr_le, st32); #endif /*** Integer load and store multiple ***/ @@ -270,20 +197,6 @@ void OPPROTO glue(op_lswi_64, MEMSUFFIX) (void) } #endif -void OPPROTO glue(op_lswi_le, MEMSUFFIX) (void) -{ - glue(do_lsw_le, MEMSUFFIX)(PARAM1); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO glue(op_lswi_le_64, MEMSUFFIX) (void) -{ - glue(do_lsw_le_64, MEMSUFFIX)(PARAM1); - RETURN(); -} -#endif - /* PPC32 specification says we must generate an exception if * rA is in the range of registers to be loaded. * In an other hand, IBM says this is valid, but rA won't be loaded. @@ -323,40 +236,6 @@ void OPPROTO glue(op_lswx_64, MEMSUFFIX) (void) } #endif -void OPPROTO glue(op_lswx_le, MEMSUFFIX) (void) -{ - /* Note: T1 comes from xer_bc then no cast is needed */ - if (likely(T1 != 0)) { - if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || - (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { - do_raise_exception_err(POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_LSWX); - } else { - glue(do_lsw_le, MEMSUFFIX)(PARAM1); - } - } - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO glue(op_lswx_le_64, MEMSUFFIX) (void) -{ - /* Note: T1 comes from xer_bc then no cast is needed */ - if (likely(T1 != 0)) { - if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) || - (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) { - do_raise_exception_err(POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_INVAL | - POWERPC_EXCP_INVAL_LSWX); - } else { - glue(do_lsw_le_64, MEMSUFFIX)(PARAM1); - } - } - RETURN(); -} -#endif - void OPPROTO glue(op_stsw, MEMSUFFIX) (void) { glue(do_stsw, MEMSUFFIX)(PARAM1); @@ -371,20 +250,6 @@ void OPPROTO glue(op_stsw_64, MEMSUFFIX) (void) } #endif -void OPPROTO glue(op_stsw_le, MEMSUFFIX) (void) -{ - glue(do_stsw_le, MEMSUFFIX)(PARAM1); - RETURN(); -} - -#if defined(TARGET_PPC64) -void OPPROTO glue(op_stsw_le_64, MEMSUFFIX) (void) -{ - glue(do_stsw_le_64, MEMSUFFIX)(PARAM1); - RETURN(); -} -#endif - /*** Floating-point store ***/ #define PPC_STF_OP(name, op) \ void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \ @@ -423,7 +288,7 @@ static always_inline void glue(stfiw, MEMSUFFIX) (target_ulong EA, double d) /* Store the low order 32 bits without any conversion */ u.d = d; - glue(stl, MEMSUFFIX)(EA, u.u[WORD0]); + glue(st32, MEMSUFFIX)(EA, u.u[WORD0]); } #undef WORD0 #undef WORD1 @@ -445,14 +310,7 @@ static always_inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d) } u; u.d = d; - u.u = ((u.u & 0xFF00000000000000ULL) >> 56) | - ((u.u & 0x00FF000000000000ULL) >> 40) | - ((u.u & 0x0000FF0000000000ULL) >> 24) | - ((u.u & 0x000000FF00000000ULL) >> 8) | - ((u.u & 0x00000000FF000000ULL) << 8) | - ((u.u & 0x0000000000FF0000ULL) << 24) | - ((u.u & 0x000000000000FF00ULL) << 40) | - ((u.u & 0x00000000000000FFULL) << 56); + u.u = bswap64(u.u); glue(stfq, MEMSUFFIX)(EA, u.d); } @@ -464,10 +322,7 @@ static always_inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, double d) } u; u.f = float64_to_float32(d, &env->fp_status); - u.u = ((u.u & 0xFF000000UL) >> 24) | - ((u.u & 0x00FF0000ULL) >> 8) | - ((u.u & 0x0000FF00UL) << 8) | - ((u.u & 0x000000FFULL) << 24); + u.u = bswap32(u.u); glue(stfl, MEMSUFFIX)(EA, u.f); } @@ -480,11 +335,8 @@ static always_inline void glue(stfiwr, MEMSUFFIX) (target_ulong EA, double d) /* Store the low order 32 bits without any conversion */ u.d = d; - u.u = ((u.u & 0xFF000000UL) >> 24) | - ((u.u & 0x00FF0000ULL) >> 8) | - ((u.u & 0x0000FF00UL) << 8) | - ((u.u & 0x000000FFULL) << 24); - glue(stl, MEMSUFFIX)(EA, u.u); + u.u = bswap32(u.u); + glue(st32, MEMSUFFIX)(EA, u.u); } PPC_STF_OP(fd_le, stfqr); @@ -533,14 +385,7 @@ static always_inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA) } u; u.d = glue(ldfq, MEMSUFFIX)(EA); - u.u = ((u.u & 0xFF00000000000000ULL) >> 56) | - ((u.u & 0x00FF000000000000ULL) >> 40) | - ((u.u & 0x0000FF0000000000ULL) >> 24) | - ((u.u & 0x000000FF00000000ULL) >> 8) | - ((u.u & 0x00000000FF000000ULL) << 8) | - ((u.u & 0x0000000000FF0000ULL) << 24) | - ((u.u & 0x000000000000FF00ULL) << 40) | - ((u.u & 0x00000000000000FFULL) << 56); + u.u = bswap64(u.u); return u.d; } @@ -553,10 +398,7 @@ static always_inline double glue(ldfsr, MEMSUFFIX) (target_ulong EA) } u; u.f = glue(ldfl, MEMSUFFIX)(EA); - u.u = ((u.u & 0xFF000000UL) >> 24) | - ((u.u & 0x00FF0000ULL) >> 8) | - ((u.u & 0x0000FF00UL) << 8) | - ((u.u & 0x000000FFULL) << 24); + u.u = bswap32(u.u); return float32_to_float64(u.f, &env->fp_status); } @@ -574,7 +416,7 @@ void OPPROTO glue(op_lwarx, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(POWERPC_EXCP_ALIGN); } else { - T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0); + T1 = glue(ldu32, MEMSUFFIX)((uint32_t)T0); env->reserve = (uint32_t)T0; } RETURN(); @@ -586,7 +428,7 @@ void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(POWERPC_EXCP_ALIGN); } else { - T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0); + T1 = glue(ldu32, MEMSUFFIX)((uint64_t)T0); env->reserve = (uint64_t)T0; } RETURN(); @@ -597,7 +439,7 @@ void OPPROTO glue(op_ldarx, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(POWERPC_EXCP_ALIGN); } else { - T1 = glue(ldq, MEMSUFFIX)((uint32_t)T0); + T1 = glue(ldu64, MEMSUFFIX)((uint32_t)T0); env->reserve = (uint32_t)T0; } RETURN(); @@ -608,7 +450,7 @@ void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(POWERPC_EXCP_ALIGN); } else { - T1 = glue(ldq, MEMSUFFIX)((uint64_t)T0); + T1 = glue(ldu64, MEMSUFFIX)((uint64_t)T0); env->reserve = (uint64_t)T0; } RETURN(); @@ -620,7 +462,7 @@ void OPPROTO glue(op_lwarx_le, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(POWERPC_EXCP_ALIGN); } else { - T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0); + T1 = glue(ldu32r, MEMSUFFIX)((uint32_t)T0); env->reserve = (uint32_t)T0; } RETURN(); @@ -632,7 +474,7 @@ void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(POWERPC_EXCP_ALIGN); } else { - T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0); + T1 = glue(ldu32r, MEMSUFFIX)((uint64_t)T0); env->reserve = (uint64_t)T0; } RETURN(); @@ -643,7 +485,7 @@ void OPPROTO glue(op_ldarx_le, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(POWERPC_EXCP_ALIGN); } else { - T1 = glue(ld64r, MEMSUFFIX)((uint32_t)T0); + T1 = glue(ldu64r, MEMSUFFIX)((uint32_t)T0); env->reserve = (uint32_t)T0; } RETURN(); @@ -654,7 +496,7 @@ void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void) if (unlikely(T0 & 0x03)) { do_raise_exception(POWERPC_EXCP_ALIGN); } else { - T1 = glue(ld64r, MEMSUFFIX)((uint64_t)T0); + T1 = glue(ldu64r, MEMSUFFIX)((uint64_t)T0); env->reserve = (uint64_t)T0; } RETURN(); @@ -670,7 +512,7 @@ void OPPROTO glue(op_stwcx, MEMSUFFIX) (void) if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_so; } else { - glue(stl, MEMSUFFIX)((uint32_t)T0, T1); + glue(st32, MEMSUFFIX)((uint32_t)T0, T1); env->crf[0] = xer_so | 0x02; } } @@ -687,7 +529,7 @@ void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void) if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_so; } else { - glue(stl, MEMSUFFIX)((uint64_t)T0, T1); + glue(st32, MEMSUFFIX)((uint64_t)T0, T1); env->crf[0] = xer_so | 0x02; } } @@ -703,7 +545,7 @@ void OPPROTO glue(op_stdcx, MEMSUFFIX) (void) if (unlikely(env->reserve != (uint32_t)T0)) { env->crf[0] = xer_so; } else { - glue(stq, MEMSUFFIX)((uint32_t)T0, T1); + glue(st64, MEMSUFFIX)((uint32_t)T0, T1); env->crf[0] = xer_so | 0x02; } } @@ -719,7 +561,7 @@ void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void) if (unlikely(env->reserve != (uint64_t)T0)) { env->crf[0] = xer_so; } else { - glue(stq, MEMSUFFIX)((uint64_t)T0, T1); + glue(st64, MEMSUFFIX)((uint64_t)T0, T1); env->crf[0] = xer_so | 0x02; } } @@ -796,72 +638,75 @@ void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void) void OPPROTO glue(op_dcbz_l32, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); + T0 &= ~((uint32_t)31); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); RETURN(); } void OPPROTO glue(op_dcbz_l64, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0); + T0 &= ~((uint32_t)63); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0); RETURN(); } void OPPROTO glue(op_dcbz_l128, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x40UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x44UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x48UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x4CUL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x50UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x54UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x58UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x5CUL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x60UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x64UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x68UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x6CUL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x70UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x74UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x78UL), 0); - glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x7CUL), 0); + T0 &= ~((uint32_t)127); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x40UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x44UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x48UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x4CUL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x50UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x54UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x58UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x5CUL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x60UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x64UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x68UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x6CUL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x70UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x74UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x78UL), 0); + glue(st32, MEMSUFFIX)((uint32_t)(T0 + 0x7CUL), 0); RETURN(); } @@ -874,72 +719,75 @@ void OPPROTO glue(op_dcbz, MEMSUFFIX) (void) #if defined(TARGET_PPC64) void OPPROTO glue(op_dcbz_l32_64, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); + T0 &= ~((uint64_t)31); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); RETURN(); } void OPPROTO glue(op_dcbz_l64_64, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0); + T0 &= ~((uint64_t)63); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0); RETURN(); } void OPPROTO glue(op_dcbz_l128_64, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x40UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x44UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x48UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x4CUL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x50UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x54UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x58UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x5CUL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x60UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x64UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x68UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x6CUL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x70UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x74UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x78UL), 0); - glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x7CUL), 0); + T0 &= ~((uint64_t)127); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x40UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x44UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x48UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x4CUL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x50UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x54UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x58UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x5CUL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x60UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x64UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x68UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x6CUL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x70UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x74UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x78UL), 0); + glue(st32, MEMSUFFIX)((uint64_t)(T0 + 0x7CUL), 0); RETURN(); } @@ -968,42 +816,42 @@ void OPPROTO glue(op_icbi_64, MEMSUFFIX) (void) /* External access */ void OPPROTO glue(op_eciwx, MEMSUFFIX) (void) { - T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0); + T1 = glue(ldu32, MEMSUFFIX)((uint32_t)T0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO glue(op_eciwx_64, MEMSUFFIX) (void) { - T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0); + T1 = glue(ldu32, MEMSUFFIX)((uint64_t)T0); RETURN(); } #endif void OPPROTO glue(op_ecowx, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)((uint32_t)T0, T1); + glue(st32, MEMSUFFIX)((uint32_t)T0, T1); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO glue(op_ecowx_64, MEMSUFFIX) (void) { - glue(stl, MEMSUFFIX)((uint64_t)T0, T1); + glue(st32, MEMSUFFIX)((uint64_t)T0, T1); RETURN(); } #endif void OPPROTO glue(op_eciwx_le, MEMSUFFIX) (void) { - T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0); + T1 = glue(ldu32r, MEMSUFFIX)((uint32_t)T0); RETURN(); } #if defined(TARGET_PPC64) void OPPROTO glue(op_eciwx_le_64, MEMSUFFIX) (void) { - T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0); + T1 = glue(ldu32r, MEMSUFFIX)((uint64_t)T0); RETURN(); } #endif @@ -1069,51 +917,51 @@ void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void) #endif void OPPROTO glue(op_vr_lvx, MEMSUFFIX) (void) { - AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint32_t)T0); - AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint32_t)T0 + 8); + AVR0.u64[VR_DWORD0] = glue(ldu64, MEMSUFFIX)((uint32_t)T0); + AVR0.u64[VR_DWORD1] = glue(ldu64, MEMSUFFIX)((uint32_t)T0 + 8); } void OPPROTO glue(op_vr_lvx_le, MEMSUFFIX) (void) { - AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint32_t)T0); - AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint32_t)T0 + 8); + AVR0.u64[VR_DWORD1] = glue(ldu64r, MEMSUFFIX)((uint32_t)T0); + AVR0.u64[VR_DWORD0] = glue(ldu64r, MEMSUFFIX)((uint32_t)T0 + 8); } void OPPROTO glue(op_vr_stvx, MEMSUFFIX) (void) { - glue(stq, MEMSUFFIX)((uint32_t)T0, AVR0.u64[VR_DWORD0]); - glue(stq, MEMSUFFIX)((uint32_t)T0 + 8, AVR0.u64[VR_DWORD1]); + glue(st64, MEMSUFFIX)((uint32_t)T0, AVR0.u64[VR_DWORD0]); + glue(st64, MEMSUFFIX)((uint32_t)T0 + 8, AVR0.u64[VR_DWORD1]); } void OPPROTO glue(op_vr_stvx_le, MEMSUFFIX) (void) { - glue(stq, MEMSUFFIX)((uint32_t)T0, AVR0.u64[VR_DWORD1]); - glue(stq, MEMSUFFIX)((uint32_t)T0 + 8, AVR0.u64[VR_DWORD0]); + glue(st64r, MEMSUFFIX)((uint32_t)T0, AVR0.u64[VR_DWORD1]); + glue(st64r, MEMSUFFIX)((uint32_t)T0 + 8, AVR0.u64[VR_DWORD0]); } #if defined(TARGET_PPC64) void OPPROTO glue(op_vr_lvx_64, MEMSUFFIX) (void) { - AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint64_t)T0); - AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint64_t)T0 + 8); + AVR0.u64[VR_DWORD0] = glue(ldu64, MEMSUFFIX)((uint64_t)T0); + AVR0.u64[VR_DWORD1] = glue(ldu64, MEMSUFFIX)((uint64_t)T0 + 8); } void OPPROTO glue(op_vr_lvx_le_64, MEMSUFFIX) (void) { - AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint64_t)T0); - AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint64_t)T0 + 8); + AVR0.u64[VR_DWORD1] = glue(ldu64r, MEMSUFFIX)((uint64_t)T0); + AVR0.u64[VR_DWORD0] = glue(ldu64r, MEMSUFFIX)((uint64_t)T0 + 8); } void OPPROTO glue(op_vr_stvx_64, MEMSUFFIX) (void) { - glue(stq, MEMSUFFIX)((uint64_t)T0, AVR0.u64[VR_DWORD0]); - glue(stq, MEMSUFFIX)((uint64_t)T0 + 8, AVR0.u64[VR_DWORD1]); + glue(st64, MEMSUFFIX)((uint64_t)T0, AVR0.u64[VR_DWORD0]); + glue(st64, MEMSUFFIX)((uint64_t)T0 + 8, AVR0.u64[VR_DWORD1]); } void OPPROTO glue(op_vr_stvx_le_64, MEMSUFFIX) (void) { - glue(stq, MEMSUFFIX)((uint64_t)T0, AVR0.u64[VR_DWORD1]); - glue(stq, MEMSUFFIX)((uint64_t)T0 + 8, AVR0.u64[VR_DWORD0]); + glue(st64r, MEMSUFFIX)((uint64_t)T0, AVR0.u64[VR_DWORD1]); + glue(st64r, MEMSUFFIX)((uint64_t)T0 + 8, AVR0.u64[VR_DWORD0]); } #endif #undef VR_DWORD0 @@ -1165,31 +1013,31 @@ _PPC_SPE_ST_OP(name, op) #endif #if !defined(TARGET_PPC64) -PPC_SPE_LD_OP(dd, ldq); -PPC_SPE_ST_OP(dd, stq); -PPC_SPE_LD_OP(dd_le, ld64r); +PPC_SPE_LD_OP(dd, ldu64); +PPC_SPE_ST_OP(dd, st64); +PPC_SPE_LD_OP(dd_le, ldu64r); PPC_SPE_ST_OP(dd_le, st64r); #endif static always_inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = (uint64_t)glue(ldl, MEMSUFFIX)(EA) << 32; - ret |= (uint64_t)glue(ldl, MEMSUFFIX)(EA + 4); + ret = (uint64_t)glue(ldu32, MEMSUFFIX)(EA) << 32; + ret |= (uint64_t)glue(ldu32, MEMSUFFIX)(EA + 4); return ret; } PPC_SPE_LD_OP(dw, spe_ldw); static always_inline void glue(spe_stdw, MEMSUFFIX) (target_ulong EA, uint64_t data) { - glue(stl, MEMSUFFIX)(EA, data >> 32); - glue(stl, MEMSUFFIX)(EA + 4, data); + glue(st32, MEMSUFFIX)(EA, data >> 32); + glue(st32, MEMSUFFIX)(EA + 4, data); } PPC_SPE_ST_OP(dw, spe_stdw); static always_inline uint64_t glue(spe_ldw_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = (uint64_t)glue(ld32r, MEMSUFFIX)(EA) << 32; - ret |= (uint64_t)glue(ld32r, MEMSUFFIX)(EA + 4); + ret = (uint64_t)glue(ldu32r, MEMSUFFIX)(EA) << 32; + ret |= (uint64_t)glue(ldu32r, MEMSUFFIX)(EA + 4); return ret; } PPC_SPE_LD_OP(dw_le, spe_ldw_le); @@ -1203,29 +1051,29 @@ PPC_SPE_ST_OP(dw_le, spe_stdw_le); static always_inline uint64_t glue(spe_ldh, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48; - ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 32; - ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 4) << 16; - ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 6); + ret = (uint64_t)glue(ldu16, MEMSUFFIX)(EA) << 48; + ret |= (uint64_t)glue(ldu16, MEMSUFFIX)(EA + 2) << 32; + ret |= (uint64_t)glue(ldu16, MEMSUFFIX)(EA + 4) << 16; + ret |= (uint64_t)glue(ldu16, MEMSUFFIX)(EA + 6); return ret; } PPC_SPE_LD_OP(dh, spe_ldh); static always_inline void glue(spe_stdh, MEMSUFFIX) (target_ulong EA, uint64_t data) { - glue(stw, MEMSUFFIX)(EA, data >> 48); - glue(stw, MEMSUFFIX)(EA + 2, data >> 32); - glue(stw, MEMSUFFIX)(EA + 4, data >> 16); - glue(stw, MEMSUFFIX)(EA + 6, data); + glue(st16, MEMSUFFIX)(EA, data >> 48); + glue(st16, MEMSUFFIX)(EA + 2, data >> 32); + glue(st16, MEMSUFFIX)(EA + 4, data >> 16); + glue(st16, MEMSUFFIX)(EA + 6, data); } PPC_SPE_ST_OP(dh, spe_stdh); static always_inline uint64_t glue(spe_ldh_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48; - ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 32; - ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 4) << 16; - ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 6); + ret = (uint64_t)glue(ldu16r, MEMSUFFIX)(EA) << 48; + ret |= (uint64_t)glue(ldu16r, MEMSUFFIX)(EA + 2) << 32; + ret |= (uint64_t)glue(ldu16r, MEMSUFFIX)(EA + 4) << 16; + ret |= (uint64_t)glue(ldu16r, MEMSUFFIX)(EA + 6); return ret; } PPC_SPE_LD_OP(dh_le, spe_ldh_le); @@ -1241,23 +1089,23 @@ PPC_SPE_ST_OP(dh_le, spe_stdh_le); static always_inline uint64_t glue(spe_lwhe, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48; - ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 16; + ret = (uint64_t)glue(ldu16, MEMSUFFIX)(EA) << 48; + ret |= (uint64_t)glue(ldu16, MEMSUFFIX)(EA + 2) << 16; return ret; } PPC_SPE_LD_OP(whe, spe_lwhe); static always_inline void glue(spe_stwhe, MEMSUFFIX) (target_ulong EA, uint64_t data) { - glue(stw, MEMSUFFIX)(EA, data >> 48); - glue(stw, MEMSUFFIX)(EA + 2, data >> 16); + glue(st16, MEMSUFFIX)(EA, data >> 48); + glue(st16, MEMSUFFIX)(EA + 2, data >> 16); } PPC_SPE_ST_OP(whe, spe_stwhe); static always_inline uint64_t glue(spe_lwhe_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48; - ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 16; + ret = (uint64_t)glue(ldu16r, MEMSUFFIX)(EA) << 48; + ret |= (uint64_t)glue(ldu16r, MEMSUFFIX)(EA + 2) << 16; return ret; } PPC_SPE_LD_OP(whe_le, spe_lwhe_le); @@ -1271,39 +1119,39 @@ PPC_SPE_ST_OP(whe_le, spe_stwhe_le); static always_inline uint64_t glue(spe_lwhou, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 32; - ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2); + ret = (uint64_t)glue(ldu16, MEMSUFFIX)(EA) << 32; + ret |= (uint64_t)glue(ldu16, MEMSUFFIX)(EA + 2); return ret; } PPC_SPE_LD_OP(whou, spe_lwhou); static always_inline uint64_t glue(spe_lwhos, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = ((uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA))) << 32; - ret |= (uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA + 2)); + ret = ((uint64_t)((int32_t)glue(lds16, MEMSUFFIX)(EA))) << 32; + ret |= (uint64_t)((int32_t)glue(lds16, MEMSUFFIX)(EA + 2)); return ret; } PPC_SPE_LD_OP(whos, spe_lwhos); static always_inline void glue(spe_stwho, MEMSUFFIX) (target_ulong EA, uint64_t data) { - glue(stw, MEMSUFFIX)(EA, data >> 32); - glue(stw, MEMSUFFIX)(EA + 2, data); + glue(st16, MEMSUFFIX)(EA, data >> 32); + glue(st16, MEMSUFFIX)(EA + 2, data); } PPC_SPE_ST_OP(who, spe_stwho); static always_inline uint64_t glue(spe_lwhou_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 32; - ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2); + ret = (uint64_t)glue(ldu16r, MEMSUFFIX)(EA) << 32; + ret |= (uint64_t)glue(ldu16r, MEMSUFFIX)(EA + 2); return ret; } PPC_SPE_LD_OP(whou_le, spe_lwhou_le); static always_inline uint64_t glue(spe_lwhos_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; - ret = ((uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA))) << 32; - ret |= (uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA + 2)); + ret = ((uint64_t)((int32_t)glue(lds16r, MEMSUFFIX)(EA))) << 32; + ret |= (uint64_t)((int32_t)glue(lds16r, MEMSUFFIX)(EA + 2)); return ret; } PPC_SPE_LD_OP(whos_le, spe_lwhos_le); @@ -1318,7 +1166,7 @@ PPC_SPE_ST_OP(who_le, spe_stwho_le); static always_inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, uint64_t data) { - glue(stl, MEMSUFFIX)(EA, data); + glue(st32, MEMSUFFIX)(EA, data); } PPC_SPE_ST_OP(wwo, spe_stwwo); static always_inline void glue(spe_stwwo_le, MEMSUFFIX) (target_ulong EA, @@ -1331,21 +1179,21 @@ PPC_SPE_ST_OP(wwo_le, spe_stwwo_le); static always_inline uint64_t glue(spe_lh, MEMSUFFIX) (target_ulong EA) { uint16_t tmp; - tmp = glue(lduw, MEMSUFFIX)(EA); + tmp = glue(ldu16, MEMSUFFIX)(EA); return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16); } PPC_SPE_LD_OP(h, spe_lh); static always_inline uint64_t glue(spe_lh_le, MEMSUFFIX) (target_ulong EA) { uint16_t tmp; - tmp = glue(ld16r, MEMSUFFIX)(EA); + tmp = glue(ldu16r, MEMSUFFIX)(EA); return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16); } PPC_SPE_LD_OP(h_le, spe_lh_le); static always_inline uint64_t glue(spe_lwwsplat, MEMSUFFIX) (target_ulong EA) { uint32_t tmp; - tmp = glue(ldl, MEMSUFFIX)(EA); + tmp = glue(ldu32, MEMSUFFIX)(EA); return ((uint64_t)tmp << 32) | (uint64_t)tmp; } PPC_SPE_LD_OP(wwsplat, spe_lwwsplat); @@ -1353,7 +1201,7 @@ static always_inline uint64_t glue(spe_lwwsplat_le, MEMSUFFIX) (target_ulong EA) { uint32_t tmp; - tmp = glue(ld32r, MEMSUFFIX)(EA); + tmp = glue(ldu32r, MEMSUFFIX)(EA); return ((uint64_t)tmp << 32) | (uint64_t)tmp; } PPC_SPE_LD_OP(wwsplat_le, spe_lwwsplat_le); @@ -1361,9 +1209,9 @@ static always_inline uint64_t glue(spe_lwhsplat, MEMSUFFIX) (target_ulong EA) { uint64_t ret; uint16_t tmp; - tmp = glue(lduw, MEMSUFFIX)(EA); + tmp = glue(ldu16, MEMSUFFIX)(EA); ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32); - tmp = glue(lduw, MEMSUFFIX)(EA + 2); + tmp = glue(ldu16, MEMSUFFIX)(EA + 2); ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp; return ret; } @@ -1373,9 +1221,9 @@ uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA) { uint64_t ret; uint16_t tmp; - tmp = glue(ld16r, MEMSUFFIX)(EA); + tmp = glue(ldu16r, MEMSUFFIX)(EA); ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32); - tmp = glue(ld16r, MEMSUFFIX)(EA + 2); + tmp = glue(ldu16r, MEMSUFFIX)(EA + 2); ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp; return ret; } diff --git a/target-ppc/op_mem_access.h b/target-ppc/op_mem_access.h new file mode 100644 index 000000000..48be20e5a --- /dev/null +++ b/target-ppc/op_mem_access.h @@ -0,0 +1,148 @@ +/* + * PowerPC emulation memory access helpers for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * 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 + */ + +/* 8 bits accesses */ +static always_inline target_ulong glue(ldu8, MEMSUFFIX) (target_ulong EA) +{ + return (uint8_t)glue(ldub, MEMSUFFIX)(EA); +} + +static always_inline target_long glue(lds8, MEMSUFFIX) (target_ulong EA) +{ + return (int8_t)glue(ldsb, MEMSUFFIX)(EA); +} + +static always_inline void glue(st8, MEMSUFFIX) (target_ulong EA, uint8_t val) +{ + glue(stb, MEMSUFFIX)(EA, val); +} + +/* 16 bits accesses */ +static always_inline target_ulong glue(ldu16, MEMSUFFIX) (target_ulong EA) +{ + return (uint16_t)glue(lduw, MEMSUFFIX)(EA); +} + +static always_inline target_long glue(lds16, MEMSUFFIX) (target_ulong EA) +{ + return (int16_t)glue(ldsw, MEMSUFFIX)(EA); +} + +static always_inline void glue(st16, MEMSUFFIX) (target_ulong EA, uint16_t val) +{ + glue(stw, MEMSUFFIX)(EA, val); +} + +static always_inline target_ulong glue(ldu16r, MEMSUFFIX) (target_ulong EA) +{ + return (uint16_t)bswap16(glue(lduw, MEMSUFFIX)(EA)); +} + +static always_inline target_long glue(lds16r, MEMSUFFIX) (target_ulong EA) +{ + return (int16_t)bswap16(glue(lduw, MEMSUFFIX)(EA)); +} + +static always_inline void glue(st16r, MEMSUFFIX) (target_ulong EA, uint16_t val) +{ + glue(stw, MEMSUFFIX)(EA, bswap16(val)); +} + +/* 32 bits accesses */ +static always_inline uint32_t glue(__ldul, MEMSUFFIX) (target_ulong EA) +{ + return (uint32_t)glue(ldl, MEMSUFFIX)(EA); +} + +static always_inline int32_t glue(__ldsl, MEMSUFFIX) (target_ulong EA) +{ + return (int32_t)glue(ldl, MEMSUFFIX)(EA); +} + +static always_inline target_ulong glue(ldu32, MEMSUFFIX) (target_ulong EA) +{ + return glue(__ldul, MEMSUFFIX)(EA); +} + +static always_inline target_long glue(lds32, MEMSUFFIX) (target_ulong EA) +{ + return glue(__ldsl, MEMSUFFIX)(EA); +} + +static always_inline void glue(st32, MEMSUFFIX) (target_ulong EA, uint32_t val) +{ + glue(stl, MEMSUFFIX)(EA, val); +} + +static always_inline target_ulong glue(ldu32r, MEMSUFFIX) (target_ulong EA) +{ + return bswap32(glue(__ldul, MEMSUFFIX)(EA)); +} + +static always_inline target_long glue(lds32r, MEMSUFFIX) (target_ulong EA) +{ + return (int32_t)bswap32(glue(__ldul, MEMSUFFIX)(EA)); +} + +static always_inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t val) +{ + glue(stl, MEMSUFFIX)(EA, bswap32(val)); +} + +/* 64 bits accesses */ +static always_inline uint64_t glue(__lduq, MEMSUFFIX) (target_ulong EA) +{ + return (uint64_t)glue(ldq, MEMSUFFIX)(EA); +} + +static always_inline int64_t glue(__ldsq, MEMSUFFIX) (target_ulong EA) +{ + return (int64_t)glue(ldq, MEMSUFFIX)(EA); +} + +static always_inline uint64_t glue(ldu64, MEMSUFFIX) (target_ulong EA) +{ + return glue(__lduq, MEMSUFFIX)(EA); +} + +static always_inline int64_t glue(lds64, MEMSUFFIX) (target_ulong EA) +{ + return glue(__ldsq, MEMSUFFIX)(EA); +} + +static always_inline void glue(st64, MEMSUFFIX) (target_ulong EA, uint64_t val) +{ + glue(stq, MEMSUFFIX)(EA, val); +} + +static always_inline uint64_t glue(ldu64r, MEMSUFFIX) (target_ulong EA) +{ + return bswap64(glue(__lduq, MEMSUFFIX)(EA)); +} + +static always_inline int64_t glue(lds64r, MEMSUFFIX) (target_ulong EA) +{ + return (int64_t)bswap64(glue(__lduq, MEMSUFFIX)(EA)); +} + +static always_inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t val) +{ + glue(stq, MEMSUFFIX)(EA, bswap64(val)); +} diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 45e8d1b89..8c64df7ab 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2455,12 +2455,37 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) /*** Integer load and store strings ***/ #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start) #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb) +/* string load & stores are by definition endian-safe */ +#define gen_op_lswi_le_raw gen_op_lswi_raw +#define gen_op_lswi_le_user gen_op_lswi_user +#define gen_op_lswi_le_kernel gen_op_lswi_kernel +#define gen_op_lswi_le_hypv gen_op_lswi_hypv +#define gen_op_lswi_le_64_raw gen_op_lswi_raw +#define gen_op_lswi_le_64_user gen_op_lswi_user +#define gen_op_lswi_le_64_kernel gen_op_lswi_kernel +#define gen_op_lswi_le_64_hypv gen_op_lswi_hypv static GenOpFunc1 *gen_op_lswi[NB_MEM_FUNCS] = { GEN_MEM_FUNCS(lswi), }; +#define gen_op_lswx_le_raw gen_op_lswx_raw +#define gen_op_lswx_le_user gen_op_lswx_user +#define gen_op_lswx_le_kernel gen_op_lswx_kernel +#define gen_op_lswx_le_hypv gen_op_lswx_hypv +#define gen_op_lswx_le_64_raw gen_op_lswx_raw +#define gen_op_lswx_le_64_user gen_op_lswx_user +#define gen_op_lswx_le_64_kernel gen_op_lswx_kernel +#define gen_op_lswx_le_64_hypv gen_op_lswx_hypv static GenOpFunc3 *gen_op_lswx[NB_MEM_FUNCS] = { GEN_MEM_FUNCS(lswx), }; +#define gen_op_stsw_le_raw gen_op_stsw_raw +#define gen_op_stsw_le_user gen_op_stsw_user +#define gen_op_stsw_le_kernel gen_op_stsw_kernel +#define gen_op_stsw_le_hypv gen_op_stsw_hypv +#define gen_op_stsw_le_64_raw gen_op_stsw_raw +#define gen_op_stsw_le_64_user gen_op_stsw_user +#define gen_op_stsw_le_64_kernel gen_op_stsw_kernel +#define gen_op_stsw_le_64_hypv gen_op_stsw_hypv static GenOpFunc1 *gen_op_stsw[NB_MEM_FUNCS] = { GEN_MEM_FUNCS(stsw), }; -- cgit v1.2.3 From 185f07621fc42c1da194ada0fe98439f07f78aa0 Mon Sep 17 00:00:00 2001 From: ths Date: Thu, 22 Nov 2007 15:10:21 +0000 Subject: Optimize the conventional move operation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3720 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index b3ae2ccfe..55e6290f3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1240,6 +1240,12 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, return; } GEN_LOAD_REG_TN(T0, rs); + /* Specialcase the conventional move operation. */ + if (rt == 0 && (opc == OPC_ADDU || opc == OPC_DADDU + || opc == OPC_SUBU || opc == OPC_DSUBU)) { + GEN_STORE_TN_REG(rd, T0); + return; + } GEN_LOAD_REG_TN(T1, rt); switch (opc) { case OPC_ADD: -- cgit v1.2.3 From 497ad68cd499bf2b6cc3bfde49fdb5aa05934ec4 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 23 Nov 2007 02:11:10 +0000 Subject: Fix TB chaining for exceptions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3721 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 52 +++++++++++++++++----------------------------------- 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 1c7356a0d..bab71ee28 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -232,6 +232,11 @@ static inline TranslationBlock *tb_find_fast(void) return tb; } +#if defined(__sparc__) && !defined(HOST_SOLARIS) +#define BREAK_CHAIN tmp_T0 = 0 +#else +#define BREAK_CHAIN T0 = 0 +#endif /* main execution loop */ @@ -405,11 +410,7 @@ int cpu_exec(CPUState *env1) svm_check_intercept(SVM_EXIT_SMI); env->interrupt_request &= ~CPU_INTERRUPT_SMI; do_smm_enter(); -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif + BREAK_CHAIN; } else if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { @@ -423,11 +424,7 @@ int cpu_exec(CPUState *env1) 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 + BREAK_CHAIN; #if !defined(CONFIG_USER_ONLY) } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) && (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { @@ -441,11 +438,7 @@ int cpu_exec(CPUState *env1) do_interrupt(intno, 0, 0, -1, 1); stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK); -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif + BREAK_CHAIN; #endif } #elif defined(TARGET_PPC) @@ -458,11 +451,7 @@ int cpu_exec(CPUState *env1) ppc_hw_interrupt(env); if (env->pending_interrupts == 0) env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif + BREAK_CHAIN; } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -475,11 +464,7 @@ int cpu_exec(CPUState *env1) env->exception_index = EXCP_EXT_INTERRUPT; env->error_code = 0; do_interrupt(env); -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif + BREAK_CHAIN; } #elif defined(TARGET_SPARC) if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -496,11 +481,7 @@ int cpu_exec(CPUState *env1) #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) cpu_check_irqs(env); #endif -#if defined(__sparc__) && !defined(HOST_SOLARIS) - tmp_T0 = 0; -#else - T0 = 0; -#endif + BREAK_CHAIN; } } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); @@ -511,6 +492,7 @@ int cpu_exec(CPUState *env1) && !(env->uncached_cpsr & CPSR_F)) { env->exception_index = EXCP_FIQ; do_interrupt(env); + BREAK_CHAIN; } /* ARMv7-M interrupt return works by loading a magic value into the PC. On real hardware the load causes the @@ -526,17 +508,20 @@ int cpu_exec(CPUState *env1) || !(env->uncached_cpsr & CPSR_I))) { env->exception_index = EXCP_IRQ; do_interrupt(env); + BREAK_CHAIN; } #elif defined(TARGET_SH4) /* XXXXX */ #elif defined(TARGET_ALPHA) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); + BREAK_CHAIN; } #elif defined(TARGET_CRIS) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; + BREAK_CHAIN; } #elif defined(TARGET_M68K) if (interrupt_request & CPU_INTERRUPT_HARD @@ -549,6 +534,7 @@ int cpu_exec(CPUState *env1) first signalled. */ env->exception_index = env->pending_vector; do_interrupt(1); + BREAK_CHAIN; } #endif /* Don't use the cached interupt_request value, @@ -557,11 +543,7 @@ int cpu_exec(CPUState *env1) 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 + BREAK_CHAIN; } if (interrupt_request & CPU_INTERRUPT_EXIT) { env->interrupt_request &= ~CPU_INTERRUPT_EXIT; -- cgit v1.2.3 From 493ae1f01cad47c3b4143059e986ba76e4d5202e Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 23 Nov 2007 16:53:59 +0000 Subject: Fix va_list reuse in cpu_abort. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3722 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 6384df270..046e96739 100644 --- a/exec.c +++ b/exec.c @@ -1281,8 +1281,10 @@ int cpu_str_to_log_mask(const char *str) void cpu_abort(CPUState *env, const char *fmt, ...) { va_list ap; + va_list ap2; va_start(ap, fmt); + va_copy(ap2, ap); fprintf(stderr, "qemu: fatal: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); @@ -1298,7 +1300,7 @@ void cpu_abort(CPUState *env, const char *fmt, ...) #endif if (logfile) { fprintf(logfile, "qemu: fatal: "); - vfprintf(logfile, fmt, ap); + vfprintf(logfile, fmt, ap2); fprintf(logfile, "\n"); #ifdef TARGET_I386 cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); @@ -1308,6 +1310,7 @@ void cpu_abort(CPUState *env, const char *fmt, ...) fflush(logfile); fclose(logfile); } + va_end(ap2); va_end(ap); abort(); } -- cgit v1.2.3 From 9b605b9eaee7845353f32aed23e8b9085bfa44ee Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 23 Nov 2007 17:33:12 +0000 Subject: Fix ppc32 register dumps on 64-bit hosts. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3723 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_oldworld.c | 3 ++- target-ppc/cpu.h | 7 ++++--- target-ppc/helper.c | 5 +++-- target-ppc/op_helper.c | 8 +++++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index f3fe1a9d7..8a1373745 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -93,7 +93,8 @@ static int vga_osi_call (CPUState *env) /* R6 = x, R7 = y, R8 = visible, R9 = data */ break; default: - fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]); + fprintf(stderr, "unsupported OSI call R5=" REGX "\n", + (target_ulong)env->gpr[5]); break; } diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 365d83697..0630a6e8e 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -30,7 +30,6 @@ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 #define TARGET_LONG_BITS 64 -#define REGX "%016" PRIx64 #define TARGET_PAGE_BITS 12 #else /* defined (TARGET_PPC64) */ @@ -43,11 +42,9 @@ typedef uint64_t ppc_gpr_t; */ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 -#define REGX "%08" PRIx64 #else /* (HOST_LONG_BITS >= 64) */ typedef uint32_t ppc_gpr_t; #define TARGET_GPR_BITS 32 -#define REGX "%08" PRIx32 #endif /* (HOST_LONG_BITS >= 64) */ #define TARGET_LONG_BITS 32 @@ -72,6 +69,10 @@ typedef uint32_t ppc_gpr_t; #endif /* defined (TARGET_PPC64) */ +/* A ppc_gpr_t should not be printed directly as the high bits may be + garbage. It should always be cast to a target_ulong first. */ +#define REGX TARGET_FMT_lx + #include "cpu-defs.h" #define ADDRX TARGET_FMT_lx diff --git a/target-ppc/helper.c b/target-ppc/helper.c index cb9b778cc..149f6cbfa 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2169,8 +2169,9 @@ static always_inline void dump_syscall (CPUState *env) { fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n", - env->gpr[0], env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6], env->nip); + (target_ulong)env->gpr[0], (target_ulong)env->gpr[3], + (target_ulong)env->gpr[4], (target_ulong)env->gpr[5], + (target_ulong)env->gpr[6], env->nip); } /* Note that this function should be greatly optimized diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 172dd48be..1a36dfaef 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2920,7 +2920,8 @@ void do_4xx_tlbwe_hi (void) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, + (target_ulong)T0, (target_ulong)T1); } #endif T0 &= 0x3F; @@ -2989,7 +2990,8 @@ void do_4xx_tlbwe_lo (void) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, + (targt_ulong)T0, (target_ulong)T1); } #endif T0 &= 0x3F; @@ -3023,7 +3025,7 @@ void do_440_tlbwe (int word) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n", - __func__, word, T0, T1); + __func__, word, (target_ulong)T0, (target_ulong)T1); } #endif do_flush_tlbs = 0; -- cgit v1.2.3 From 69facb7897ef6404175b4739751f9255fc0c8a2e Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 23 Nov 2007 22:16:59 +0000 Subject: Revert foolish patch. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3724 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc_oldworld.c | 3 +-- target-ppc/cpu.h | 7 +++---- target-ppc/helper.c | 5 ++--- target-ppc/op_helper.c | 8 +++----- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 8a1373745..f3fe1a9d7 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -93,8 +93,7 @@ static int vga_osi_call (CPUState *env) /* R6 = x, R7 = y, R8 = visible, R9 = data */ break; default: - fprintf(stderr, "unsupported OSI call R5=" REGX "\n", - (target_ulong)env->gpr[5]); + fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]); break; } diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 0630a6e8e..365d83697 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -30,6 +30,7 @@ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 #define TARGET_LONG_BITS 64 +#define REGX "%016" PRIx64 #define TARGET_PAGE_BITS 12 #else /* defined (TARGET_PPC64) */ @@ -42,9 +43,11 @@ typedef uint64_t ppc_gpr_t; */ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 +#define REGX "%08" PRIx64 #else /* (HOST_LONG_BITS >= 64) */ typedef uint32_t ppc_gpr_t; #define TARGET_GPR_BITS 32 +#define REGX "%08" PRIx32 #endif /* (HOST_LONG_BITS >= 64) */ #define TARGET_LONG_BITS 32 @@ -69,10 +72,6 @@ typedef uint32_t ppc_gpr_t; #endif /* defined (TARGET_PPC64) */ -/* A ppc_gpr_t should not be printed directly as the high bits may be - garbage. It should always be cast to a target_ulong first. */ -#define REGX TARGET_FMT_lx - #include "cpu-defs.h" #define ADDRX TARGET_FMT_lx diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 149f6cbfa..cb9b778cc 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2169,9 +2169,8 @@ static always_inline void dump_syscall (CPUState *env) { fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n", - (target_ulong)env->gpr[0], (target_ulong)env->gpr[3], - (target_ulong)env->gpr[4], (target_ulong)env->gpr[5], - (target_ulong)env->gpr[6], env->nip); + env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->nip); } /* Note that this function should be greatly optimized diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 1a36dfaef..172dd48be 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2920,8 +2920,7 @@ void do_4xx_tlbwe_hi (void) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, - (target_ulong)T0, (target_ulong)T1); + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); } #endif T0 &= 0x3F; @@ -2990,8 +2989,7 @@ void do_4xx_tlbwe_lo (void) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, - (targt_ulong)T0, (target_ulong)T1); + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); } #endif T0 &= 0x3F; @@ -3025,7 +3023,7 @@ void do_440_tlbwe (int word) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n", - __func__, word, (target_ulong)T0, (target_ulong)T1); + __func__, word, T0, T1); } #endif do_flush_tlbs = 0; -- cgit v1.2.3 From 6b542af760f44409b40441225fbef31a3b4bdbe1 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 24 Nov 2007 02:03:55 +0000 Subject: Fix incorrect debug prints (reported by Paul Brook). Remove obsolete / duplicated debug prints and improve output consistency. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3725 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 22 +++++++-- target-ppc/exec.h | 2 + target-ppc/helper.c | 123 ++++++++++++++++++++++--------------------------- target-ppc/op_helper.c | 18 ++++---- target-ppc/translate.c | 33 ++++--------- 5 files changed, 96 insertions(+), 102 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 365d83697..e780764b0 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -30,7 +30,6 @@ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 #define TARGET_LONG_BITS 64 -#define REGX "%016" PRIx64 #define TARGET_PAGE_BITS 12 #else /* defined (TARGET_PPC64) */ @@ -43,11 +42,9 @@ typedef uint64_t ppc_gpr_t; */ typedef uint64_t ppc_gpr_t; #define TARGET_GPR_BITS 64 -#define REGX "%08" PRIx64 #else /* (HOST_LONG_BITS >= 64) */ typedef uint32_t ppc_gpr_t; #define TARGET_GPR_BITS 32 -#define REGX "%08" PRIx32 #endif /* (HOST_LONG_BITS >= 64) */ #define TARGET_LONG_BITS 32 @@ -74,6 +71,7 @@ typedef uint32_t ppc_gpr_t; #include "cpu-defs.h" +#define REGX "%016" PRIx64 #define ADDRX TARGET_FMT_lx #define PADDRX TARGET_FMT_plx @@ -792,6 +790,24 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid); #endif #endif +static always_inline uint64_t ppc_dump_gpr (CPUPPCState *env, int gprn) +{ + uint64_t gprv; + + gprv = env->gpr[gprn]; +#if !defined(TARGET_PPC64) + if (env->flags & POWERPC_FLAG_SPE) { + /* If the CPU implements the SPE extension, we have to get the + * high bits of the GPR from the gprh storage area + */ + gprv &= 0xFFFFFFFFULL; + gprv |= (uint64_t)env->gprh[gprn] << 32; + } +#endif + + return gprv; +} + /* Device control registers */ int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp); int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val); diff --git a/target-ppc/exec.h b/target-ppc/exec.h index beaa39ab0..76fdb0b1d 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -37,10 +37,12 @@ register struct CPUPPCState *env asm(AREG0); #define T0 (env->t0) #define T1 (env->t1) #define T2 (env->t2) +#define TDX "%016" PRIx64 #else register unsigned long T0 asm(AREG1); register unsigned long T1 asm(AREG2); register unsigned long T2 asm(AREG3); +#define TDX "%016lx" #endif /* We may, sometime, need 64 bits registers on 32 bits targets */ #if (HOST_LONG_BITS == 32) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index cb9b778cc..7a32d4a27 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -31,6 +31,7 @@ //#define DEBUG_MMU //#define DEBUG_BATS +//#define DEBUG_SLB //#define DEBUG_SOFTWARE_TLB //#define DUMP_PAGE_TABLES //#define DEBUG_EXCEPTIONS @@ -436,7 +437,7 @@ static always_inline int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx, done: #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n", + fprintf(logfile, "found TLB at addr " PADDRX " prot=%01x ret=%d\n", ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); } #endif @@ -484,8 +485,8 @@ static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp, bl = (*BATl & 0x0000003F) << 17; #if defined (DEBUG_BATS) if (loglevel != 0) { - fprintf(logfile, "b %02x ==> bl %08x msk %08x\n", - *BATl & 0x0000003F, bl, ~bl); + fprintf(logfile, "b %02x ==> bl " ADDRX " msk " ADDRX "\n", + (uint8_t)(*BATl & 0x0000003F), bl, ~bl); } #endif prot = 0; @@ -513,7 +514,7 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, #if defined (DEBUG_BATS) if (loglevel != 0) { - fprintf(logfile, "%s: %cBAT v 0x" ADDRX "\n", __func__, + fprintf(logfile, "%s: %cBAT v " ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } #endif @@ -527,12 +528,6 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, BATut = env->DBAT[0]; break; } -#if defined (DEBUG_BATS) - if (loglevel != 0) { - fprintf(logfile, "%s...: %cBAT v 0x" ADDRX "\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); - } -#endif base = virtual & 0xFFFC0000; for (i = 0; i < env->nb_BATs; i++) { BATu = &BATut[i]; @@ -546,10 +541,9 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, } #if defined (DEBUG_BATS) if (loglevel != 0) { - fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX - " BATl 0x" ADDRX "\n", - __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, - *BATu, *BATl); + fprintf(logfile, "%s: %cBAT%d v " ADDRX " BATu " ADDRX + " BATl " ADDRX "\n", __func__, + type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); } #endif if ((virtual & 0xF0000000) == BEPIu && @@ -565,8 +559,7 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, ret = check_prot(ctx->prot, rw, type); #if defined (DEBUG_BATS) if (ret == 0 && loglevel != 0) { - fprintf(logfile, "BAT %d match: r 0x" PADDRX - " prot=%c%c\n", + fprintf(logfile, "BAT %d match: r " PADDRX " prot=%c%c\n", i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', ctx->prot & PAGE_WRITE ? 'W' : '-'); } @@ -578,16 +571,15 @@ static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, if (ret < 0) { #if defined (DEBUG_BATS) if (loglevel != 0) { - fprintf(logfile, "no BAT match for 0x" ADDRX ":\n", virtual); + fprintf(logfile, "no BAT match for " ADDRX ":\n", virtual); for (i = 0; i < 4; i++) { BATu = &BATut[i]; BATl = &BATlt[i]; BEPIu = *BATu & 0xF0000000; BEPIl = *BATu & 0x0FFE0000; bl = (*BATu & 0x00001FFC) << 15; - fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX - " BATl 0x" ADDRX " \n\t" - "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n", + fprintf(logfile, "%s: %cBAT%d v " ADDRX " BATu " ADDRX + " BATl " ADDRX " \n\t" ADDRX " " ADDRX " " ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl); } @@ -617,8 +609,8 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, r = pte64_check(ctx, pte0, pte1, h, rw, type); #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX - " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", + fprintf(logfile, "Load pte from " ADDRX " => " ADDRX " " ADDRX + " %d %d %d " ADDRX "\n", base + (i * 16), pte0, pte1, (int)(pte0 & 1), h, (int)((pte0 >> 1) & 1), ctx->ptem); @@ -632,8 +624,8 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, r = pte32_check(ctx, pte0, pte1, h, rw, type); #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX - " 0x" ADDRX " %d %d %d 0x" ADDRX "\n", + fprintf(logfile, "Load pte from " ADDRX " => " ADDRX " " ADDRX + " %d %d %d " ADDRX "\n", base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem); @@ -668,8 +660,7 @@ static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, done: #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "found PTE at addr 0x" PADDRX " prot=0x%01x " - "ret=%d\n", + fprintf(logfile, "found PTE at addr " PADDRX " prot=%01x ret=%d\n", ctx->raddr, ctx->prot, ret); } #endif @@ -884,8 +875,9 @@ void ppc_store_slb (CPUPPCState *env, int slb_nr, target_ulong rs) tmp64 |= (uint32_t)slb_nr << 28; #if defined(DEBUG_SLB) if (loglevel != 0) { - fprintf(logfile, "%s: %d " ADDRX " => " PADDRX " %016" PRIx64 " %08" - PRIx32 "\n", __func__, slb_nr, rs, sr_base, tmp64, tmp); + fprintf(logfile, "%s: %d " ADDRX " => " PADDRX " %016" PRIx64 + " %08" PRIx32 "\n", __func__, + slb_nr, rs, sr_base, tmp64, tmp); } #endif /* Write SLB entry to memory */ @@ -949,9 +941,8 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, sdr_mask = 0xFFC0; #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX - " nip=0x" ADDRX " lr=0x" ADDRX - " ir=%d dr=%d pr=%d %d t=%d\n", + fprintf(logfile, "Check segment v=" ADDRX " %d " ADDRX + " nip=" ADDRX " lr=" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, (int)msr_dr, pr != 0 ? 1 : 0, rw, type); @@ -986,9 +977,9 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, mask = (htab_mask << sdr_sh) | sdr_mask; #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX " mask " - PADDRX " " ADDRX "\n", sdr, sdr_sh, hash, mask, - page_mask); + fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX + " mask " PADDRX " " ADDRX "\n", + sdr, sdr_sh, hash, mask, page_mask); } #endif ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask); @@ -996,8 +987,9 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, hash = (~hash) & vsid_mask; #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX " mask " - PADDRX "\n", sdr, sdr_sh, hash, mask); + fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX + " mask " PADDRX "\n", + sdr, sdr_sh, hash, mask); } #endif ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask); @@ -1019,10 +1011,10 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, } else { #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "0 sdr1=0x" PADDRX " vsid=0x%06x " - "api=0x%04x hash=0x%07x pg_addr=0x" PADDRX "\n", - sdr, (uint32_t)vsid, (uint32_t)pgidx, - (uint32_t)hash, ctx->pg_addr[0]); + fprintf(logfile, "0 sdr1=" PADDRX " vsid=" ADDRX " " + "api=" ADDRX " hash=" PADDRX + " pg_addr=" PADDRX "\n", + sdr, vsid, pgidx, hash, ctx->pg_addr[0]); } #endif /* Primary table lookup */ @@ -1031,11 +1023,10 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, /* Secondary table lookup */ #if defined (DEBUG_MMU) if (eaddr != 0xEFFFFFFF && loglevel != 0) { - fprintf(logfile, - "1 sdr1=0x" PADDRX " vsid=0x%06x api=0x%04x " - "hash=0x%05x pg_addr=0x" PADDRX "\n", - sdr, (uint32_t)vsid, (uint32_t)pgidx, - (uint32_t)hash, ctx->pg_addr[1]); + fprintf(logfile, "1 sdr1=" PADDRX " vsid=" ADDRX " " + "api=" ADDRX " hash=" PADDRX + " pg_addr=" PADDRX "\n", + sdr, vsid, pgidx, hash, ctx->pg_addr[1]); } #endif ret2 = find_pte(env, ctx, 1, rw, type); @@ -1047,8 +1038,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, if (loglevel != 0) { target_phys_addr_t curaddr; uint32_t a0, a1, a2, a3; - fprintf(logfile, - "Page table: " PADDRX " len " PADDRX "\n", + fprintf(logfile, "Page table: " PADDRX " len " PADDRX "\n", sdr, mask + 0x80); for (curaddr = sdr; curaddr < (sdr + mask + 0x80); curaddr += 16) { @@ -1057,8 +1047,7 @@ static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, a2 = ldl_phys(curaddr + 8); a3 = ldl_phys(curaddr + 12); if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) { - fprintf(logfile, - PADDRX ": %08x %08x %08x %08x\n", + fprintf(logfile, PADDRX ": %08x %08x %08x %08x\n", curaddr, a0, a1, a2, a3); } } @@ -1135,9 +1124,9 @@ static always_inline int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, mask = ~(tlb->size - 1); #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> " - ADDRX " " ADDRX " %d\n", - __func__, i, address, pid, tlb->EPN, mask, (int)tlb->PID); + fprintf(logfile, "%s: TLB %d address " ADDRX " PID %u <=> " ADDRX + " " ADDRX " %u\n", + __func__, i, address, pid, tlb->EPN, mask, (uint32_t)tlb->PID); } #endif /* Check PID */ @@ -1269,7 +1258,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ctx->raddr = raddr; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s: access granted " ADDRX " => " REGX + fprintf(logfile, "%s: access granted " ADDRX " => " PADDRX " %d %d\n", __func__, address, ctx->raddr, ctx->prot, ret); } @@ -1279,7 +1268,7 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, } #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s: access refused " ADDRX " => " REGX + fprintf(logfile, "%s: access refused " ADDRX " => " PADDRX " %d %d\n", __func__, address, raddr, ctx->prot, ret); } @@ -1785,7 +1774,7 @@ static always_inline void dump_store_bat (CPUPPCState *env, char ID, { #if defined (DEBUG_BATS) if (loglevel != 0) { - fprintf(logfile, "Set %cBAT%d%c to 0x" ADDRX " (0x" ADDRX ")\n", + fprintf(logfile, "Set %cBAT%d%c to " ADDRX " (" ADDRX ")\n", ID, nr, ul == 0 ? 'u' : 'l', value, env->nip); } #endif @@ -2089,7 +2078,7 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value) { #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "%s: 0x" ADDRX "\n", __func__, value); + fprintf(logfile, "%s: " ADDRX "\n", __func__, value); } #endif if (env->sdr1 != value) { @@ -2112,7 +2101,7 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value) { #if defined (DEBUG_MMU) if (loglevel != 0) { - fprintf(logfile, "%s: reg=%d 0x" ADDRX " " ADDRX "\n", + fprintf(logfile, "%s: reg=%d " ADDRX " " ADDRX "\n", __func__, srnum, value, env->sr[srnum]); } #endif @@ -2167,10 +2156,10 @@ void ppc_hw_interrupt (CPUState *env) #else /* defined (CONFIG_USER_ONLY) */ static always_inline void dump_syscall (CPUState *env) { - fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX - " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n", - env->gpr[0], env->gpr[3], env->gpr[4], - env->gpr[5], env->gpr[6], env->nip); + fprintf(logfile, "syscall r0=" REGX " r3=" REGX " r4=" REGX + " r5=" REGX " r6=" REGX " nip=" ADDRX "\n", + ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4), + ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6), env->nip); } /* Note that this function should be greatly optimized @@ -2194,7 +2183,7 @@ static always_inline void powerpc_excp (CPUState *env, } if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n", + fprintf(logfile, "Raise exception at " ADDRX " => %08x (%02x)\n", env->nip, excp, env->error_code); } msr = env->msr; @@ -2265,8 +2254,8 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_DSI: /* Data storage exception */ #if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) { - fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX - "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); + fprintf(logfile, "DSI exception: DSISR=" ADDRX" DAR=" ADDRX "\n", + env->spr[SPR_DSISR], env->spr[SPR_DAR]); } #endif new_msr &= ~((target_ulong)1 << MSR_RI); @@ -2276,8 +2265,8 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_ISI: /* Instruction storage exception */ #if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) { - fprintf(logfile, "ISI exception: msr=0x" ADDRX ", nip=0x" ADDRX - "\n", msr, env->nip); + fprintf(logfile, "ISI exception: msr=" ADDRX ", nip=" ADDRX "\n", + msr, env->nip); } #endif new_msr &= ~((target_ulong)1 << MSR_RI); @@ -2322,7 +2311,7 @@ static always_inline void powerpc_excp (CPUState *env, case POWERPC_EXCP_INVAL: #if defined (DEBUG_EXCEPTIONS) if (loglevel != 0) { - fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n", + fprintf(logfile, "Invalid instruction at " ADDRX "\n", env->nip); } #endif diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 172dd48be..1ea16951b 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -2783,9 +2783,9 @@ void do_load_6xx_tlb (int is_code) way = (env->spr[SPR_SRR1] >> 17) & 1; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n", - __func__, (unsigned long)T0, (unsigned long)EPN, - (unsigned long)CMP, (unsigned long)RPN, way); + fprintf(logfile, "%s: EPN " TDX " " ADDRX " PTE0 " ADDRX + " PTE1 " ADDRX " way %d\n", + __func__, T0, EPN, CMP, RPN, way); } #endif /* Store this TLB */ @@ -2804,9 +2804,9 @@ void do_load_74xx_tlb (int is_code) way = env->spr[SPR_TLBMISS] & 0x3; #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n", - __func__, (unsigned long)T0, (unsigned long)EPN, - (unsigned long)CMP, (unsigned long)RPN, way); + fprintf(logfile, "%s: EPN " TDX " " ADDRX " PTE0 " ADDRX + " PTE1 " ADDRX " way %d\n", + __func__, T0, EPN, CMP, RPN, way); } #endif /* Store this TLB */ @@ -2920,7 +2920,7 @@ void do_4xx_tlbwe_hi (void) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1); } #endif T0 &= 0x3F; @@ -2989,7 +2989,7 @@ void do_4xx_tlbwe_lo (void) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); + fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1); } #endif T0 &= 0x3F; @@ -3022,7 +3022,7 @@ void do_440_tlbwe (int word) #if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { - fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n", + fprintf(logfile, "%s word %d T0 " TDX " T1 " TDX "\n", __func__, word, T0, T1); } #endif diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 8c64df7ab..1313a7736 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3265,7 +3265,7 @@ static always_inline void gen_op_mfspr (DisasContext *ctx) */ if (sprn != SPR_PVR) { if (loglevel != 0) { - fprintf(logfile, "Trying to read privileged spr %d %03x at" + fprintf(logfile, "Trying to read privileged spr %d %03x at " ADDRX "\n", sprn, sprn, ctx->nip); } printf("Trying to read privileged spr %d %03x at " ADDRX "\n", @@ -3741,8 +3741,6 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - if (loglevel != 0) - fprintf(logfile, "%s: ! supervisor\n", __func__); GEN_EXCP_PRIVOPC(ctx); return; } @@ -3795,8 +3793,6 @@ GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI) GEN_EXCP_PRIVOPC(ctx); #else if (unlikely(!ctx->supervisor)) { - if (loglevel != 0) - fprintf(logfile, "%s: ! supervisor\n", __func__); GEN_EXCP_PRIVOPC(ctx); return; } @@ -6060,23 +6056,15 @@ void cpu_dump_state (CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { -#if defined(TARGET_PPC64) || 1 -#define FILL "" #define RGPL 4 #define RFPL 4 -#else -#define FILL " " -#define RGPL 8 -#define RFPL 4 -#endif int i; cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX " XER %08x\n", env->nip, env->lr, env->ctr, hreg_load_xer(env)); - cpu_fprintf(f, "MSR " REGX FILL " HID0 " REGX FILL " HF " REGX FILL - " idx %d\n", - env->msr, env->hflags, env->spr[SPR_HID0], env->mmu_idx); + cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX " HF " ADDRX " idx %d\n", + env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx); #if !defined(NO_TIMER_DUMP) cpu_fprintf(f, "TB %08x %08x " #if !defined(CONFIG_USER_ONLY) @@ -6092,7 +6080,7 @@ void cpu_dump_state (CPUState *env, FILE *f, for (i = 0; i < 32; i++) { if ((i & (RGPL - 1)) == 0) cpu_fprintf(f, "GPR%02d", i); - cpu_fprintf(f, " " REGX, (target_ulong)env->gpr[i]); + cpu_fprintf(f, " " REGX, ppc_dump_gpr(env, i)); if ((i & (RGPL - 1)) == (RGPL - 1)) cpu_fprintf(f, "\n"); } @@ -6110,7 +6098,7 @@ void cpu_dump_state (CPUState *env, FILE *f, a = 'E'; cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } - cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve); + cpu_fprintf(f, " ] RES " ADDRX "\n", env->reserve); for (i = 0; i < 32; i++) { if ((i & (RFPL - 1)) == 0) cpu_fprintf(f, "FPR%02d", i); @@ -6119,13 +6107,12 @@ void cpu_dump_state (CPUState *env, FILE *f, cpu_fprintf(f, "\n"); } #if !defined(CONFIG_USER_ONLY) - cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " SDR1 " REGX "\n", + cpu_fprintf(f, "SRR0 " ADDRX " SRR1 " ADDRX " SDR1 " ADDRX "\n", env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1); #endif #undef RGPL #undef RFPL -#undef FILL } void cpu_dump_statistics (CPUState *env, FILE*f, @@ -6289,12 +6276,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, if (unlikely(handler->handler == &gen_invalid)) { if (loglevel != 0) { fprintf(logfile, "invalid/unsupported opcode: " - "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", + "%02x - %02x - %02x (%08x) " ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } else { printf("invalid/unsupported opcode: " - "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n", + "%02x - %02x - %02x (%08x) " ADDRX " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } @@ -6302,13 +6289,13 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, if (unlikely((ctx.opcode & handler->inval) != 0)) { if (loglevel != 0) { fprintf(logfile, "invalid bits: %08x for opcode: " - "%02x - %02x - %02x (%08x) 0x" ADDRX "\n", + "%02x - %02x - %02x (%08x) " ADDRX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } else { printf("invalid bits: %08x for opcode: " - "%02x - %02x - %02x (%08x) 0x" ADDRX "\n", + "%02x - %02x - %02x (%08x) " ADDRX "\n", ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); -- cgit v1.2.3 From aae9366a036b813d58fad2d99d28a2a478109f75 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Sat, 24 Nov 2007 02:56:36 +0000 Subject: More PowerPC debug print fixes - hardware emulation pass. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3726 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ppc.c | 39 +++++++++---------- hw/ppc405_uc.c | 111 +++++++++++++++++++++++++++++------------------------- hw/ppc4xx_devs.c | 41 ++++++++++---------- hw/ppc_chrp.c | 6 +-- hw/ppc_oldworld.c | 13 ++++--- hw/ppc_prep.c | 41 ++++++++++---------- 6 files changed, 134 insertions(+), 117 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 914510154..fc92ab267 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -48,8 +48,8 @@ static void ppc_set_irq (CPUState *env, int n_IRQ, int level) } #if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08x req %08x\n", - __func__, env, n_IRQ, level, + fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08" PRIx32 + "req %08x\n", __func__, env, n_IRQ, level, env->pending_interrupts, env->interrupt_request); } #endif @@ -457,7 +457,7 @@ uint32_t cpu_ppc_load_tbl (CPUState *env) tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { - fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); + fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb); } #endif @@ -472,7 +472,7 @@ static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env) tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { - fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); + fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb); } #endif @@ -491,8 +491,8 @@ static always_inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t vmclk, *tb_offsetp = value - muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec); #ifdef PPC_DEBUG_TB if (loglevel != 0) { - fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value, - *tb_offsetp); + fprintf(logfile, "%s: tb %016" PRIx64 " offset %08" PRIx64 "\n", + __func__, value, *tb_offsetp); } #endif } @@ -532,7 +532,7 @@ uint32_t cpu_ppc_load_atbl (CPUState *env) tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { - fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); + fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb); } #endif @@ -547,7 +547,7 @@ uint32_t cpu_ppc_load_atbu (CPUState *env) tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->atb_offset); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { - fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb); + fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb); } #endif @@ -602,7 +602,7 @@ static void cpu_ppc_tb_start (CPUState *env) { ppc_tb_t *tb_env = env->tb_env; uint64_t tb, atb, vmclk; - + /* If the time base is not frozen, do nothing */ if (tb_env->tb_freq == 0) { vmclk = qemu_get_clock(vm_clock); @@ -633,7 +633,7 @@ static always_inline uint32_t _cpu_ppc_load_decr (CPUState *env, decr = -muldiv64(-diff, tb_env->decr_freq, ticks_per_sec); #if defined(PPC_DEBUG_TB) if (loglevel != 0) { - fprintf(logfile, "%s: 0x%08x\n", __func__, decr); + fprintf(logfile, "%s: %08" PRIx32 "\n", __func__, decr); } #endif @@ -700,7 +700,8 @@ static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp, #ifdef PPC_DEBUG_TB if (loglevel != 0) { - fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value); + fprintf(logfile, "%s: %08" PRIx32 " => %08" PRIx32 "\n", __func__, + decr, value); } #endif now = qemu_get_clock(vm_clock); @@ -910,7 +911,7 @@ static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp) } else { #ifdef PPC_DEBUG_TB if (loglevel != 0) { - fprintf(logfile, "%s: start PIT 0x" REGX "\n", + fprintf(logfile, "%s: start PIT %016" PRIx64 "\n", __func__, ppcemb_timer->pit_reload); } #endif @@ -1032,7 +1033,7 @@ void store_40x_pit (CPUState *env, target_ulong val) ppcemb_timer = tb_env->opaque; #ifdef PPC_DEBUG_TB if (loglevel != 0) { - fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer); + fprintf(logfile, "%s val" ADDRX "\n", __func__, val); } #endif ppcemb_timer->pit_reload = val; @@ -1048,7 +1049,7 @@ void store_booke_tsr (CPUState *env, target_ulong val) { #ifdef PPC_DEBUG_TB if (loglevel != 0) { - fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val); + fprintf(logfile, "%s: val " ADDRX "\n", __func__, val); } #endif env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000); @@ -1063,7 +1064,7 @@ void store_booke_tcr (CPUState *env, target_ulong val) tb_env = env->tb_env; #ifdef PPC_DEBUG_TB if (loglevel != 0) { - fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val); + fprintf(logfile, "%s: val " ADDRX "\n", __func__, val); } #endif env->spr[SPR_40x_TCR] = val & 0xFFC00000; @@ -1078,7 +1079,8 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq) #ifdef PPC_DEBUG_TB if (loglevel != 0) { - fprintf(logfile, "%s set new frequency to %u\n", __func__, freq); + fprintf(logfile, "%s set new frequency to %" PRIu32 "\n", __func__, + freq); } #endif tb_env->tb_freq = freq; @@ -1102,8 +1104,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq) tb_env->opaque = ppcemb_timer; #ifdef PPC_DEBUG_TB if (loglevel != 0) { - fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer, - &ppc_emb_set_tb_clk); + fprintf(logfile, "%s freq %" PRIu32 "\n", __func__, freq); } #endif if (ppcemb_timer != NULL) { @@ -1239,7 +1240,7 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) fflush(stdout); break; case 2: - printf("Set loglevel to %04x\n", val); + printf("Set loglevel to %04" PRIx32 "\n", val); cpu_set_log(val | 0x100); break; } diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 0a2f087d8..329330a61 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -40,7 +40,7 @@ extern FILE *logfile; #define DEBUG_GPT #define DEBUG_MAL #define DEBUG_CLOCKS -//#define DEBUG_UNASSIGNED +//#define DEBUG_CLOCKS_LL ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd, uint32_t flags) @@ -298,7 +298,7 @@ static void opba_writeb (void *opaque, ppc4xx_opba_t *opba; #ifdef DEBUG_OPBA - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif opba = opaque; switch (addr - opba->base) { @@ -330,7 +330,7 @@ static void opba_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef DEBUG_OPBA - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif opba_writeb(opaque, addr, value >> 8); opba_writeb(opaque, addr + 1, value); @@ -353,7 +353,7 @@ static void opba_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef DEBUG_OPBA - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif opba_writeb(opaque, addr, value >> 24); opba_writeb(opaque, addr + 1, value >> 16); @@ -389,7 +389,7 @@ void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio, if (opba != NULL) { opba->base = offset; #ifdef DEBUG_OPBA - printf("%s: offset=" PADDRX "\n", __func__, offset); + printf("%s: offset " PADDRX "\n", __func__, offset); #endif ppc4xx_mmio_register(env, mmio, offset, 0x002, opba_read, opba_write, opba); @@ -429,6 +429,10 @@ enum { SDRAM0_CFGDATA = 0x011, }; +/* XXX: TOFIX: some patches have made this code become inconsistent: + * there are type inconsistencies, mixing target_phys_addr_t, target_ulong + * and uint32_t + */ static uint32_t sdram_bcr (target_phys_addr_t ram_base, target_phys_addr_t ram_size) { @@ -457,8 +461,7 @@ static uint32_t sdram_bcr (target_phys_addr_t ram_base, bcr = 0x000C0000; break; default: - printf("%s: invalid RAM size " TARGET_FMT_plx "\n", - __func__, ram_size); + printf("%s: invalid RAM size " PADDRX "\n", __func__, ram_size); return 0x00000000; } bcr |= ram_base & 0xFF800000; @@ -491,7 +494,7 @@ static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled) if (*bcrp & 0x00000001) { /* Unmap RAM */ #ifdef DEBUG_SDRAM - printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + printf("%s: unmap RAM area " PADDRX " " ADDRX "\n", __func__, sdram_base(*bcrp), sdram_size(*bcrp)); #endif cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp), @@ -500,7 +503,7 @@ static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled) *bcrp = bcr & 0xFFDEE001; if (enabled && (bcr & 0x00000001)) { #ifdef DEBUG_SDRAM - printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + printf("%s: Map RAM area " PADDRX " " ADDRX "\n", __func__, sdram_base(bcr), sdram_size(bcr)); #endif cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr), @@ -529,7 +532,7 @@ static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram) for (i = 0; i < sdram->nbanks; i++) { #ifdef DEBUG_SDRAM - printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n", + printf("%s: Unmap RAM area " PADDRX " " ADDRX "\n", __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i])); #endif cpu_register_physical_memory(sdram_base(sdram->bcr[i]), @@ -1110,7 +1113,7 @@ static void ppc405_gpio_writeb (void *opaque, gpio = opaque; #ifdef DEBUG_GPIO - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif } @@ -1133,7 +1136,7 @@ static void ppc405_gpio_writew (void *opaque, gpio = opaque; #ifdef DEBUG_GPIO - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif } @@ -1156,7 +1159,7 @@ static void ppc405_gpio_writel (void *opaque, gpio = opaque; #ifdef DEBUG_GPIO - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif } @@ -1190,7 +1193,7 @@ void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio, ppc405_gpio_reset(gpio); qemu_register_reset(&ppc405_gpio_reset, gpio); #ifdef DEBUG_GPIO - printf("%s: offset=" PADDRX "\n", __func__, offset); + printf("%s: offset " PADDRX "\n", __func__, offset); #endif ppc4xx_mmio_register(env, mmio, offset, 0x038, ppc405_gpio_read, ppc405_gpio_write, gpio); @@ -1218,7 +1221,7 @@ void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio, void *serial; #ifdef DEBUG_SERIAL - printf("%s: offset=" PADDRX "\n", __func__, offset); + printf("%s: offset " PADDRX "\n", __func__, offset); #endif serial = serial_mm_init(offset, 0, irq, chr, 0); ppc4xx_mmio_register(env, mmio, offset, 0x008, @@ -1248,7 +1251,9 @@ static void ocm_update_mappings (ppc405_ocm_t *ocm, uint32_t dsarc, uint32_t dsacntl) { #ifdef DEBUG_OCM - printf("OCM update ISA %08x %08x (%08x %08x) DSA %08x %08x (%08x %08x)\n", + printf("OCM update ISA %08" PRIx32 " %08" PRIx32 " (%08" PRIx32 + " %08" PRIx32 ") DSA %08" PRIx32 " %08" PRIx32 + " (%08" PRIx32 " %08" PRIx32 ")\n", isarc, isacntl, dsarc, dsacntl, ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl); #endif @@ -1256,14 +1261,14 @@ static void ocm_update_mappings (ppc405_ocm_t *ocm, (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) { if (ocm->isacntl & 0x80000000) { /* Unmap previously assigned memory region */ - printf("OCM unmap ISA %08x\n", ocm->isarc); + printf("OCM unmap ISA %08" PRIx32 "\n", ocm->isarc); cpu_register_physical_memory(ocm->isarc, 0x04000000, IO_MEM_UNASSIGNED); } if (isacntl & 0x80000000) { /* Map new instruction memory region */ #ifdef DEBUG_OCM - printf("OCM map ISA %08x\n", isarc); + printf("OCM map ISA %08" PRIx32 "\n", isarc); #endif cpu_register_physical_memory(isarc, 0x04000000, ocm->offset | IO_MEM_RAM); @@ -1276,7 +1281,7 @@ static void ocm_update_mappings (ppc405_ocm_t *ocm, if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) { /* Unmap previously assigned memory region */ #ifdef DEBUG_OCM - printf("OCM unmap DSA %08x\n", ocm->dsarc); + printf("OCM unmap DSA %08" PRIx32 "\n", ocm->dsarc); #endif cpu_register_physical_memory(ocm->dsarc, 0x04000000, IO_MEM_UNASSIGNED); @@ -1287,7 +1292,7 @@ static void ocm_update_mappings (ppc405_ocm_t *ocm, if (!(isacntl & 0x80000000) || dsarc != isarc) { /* Map new data memory region */ #ifdef DEBUG_OCM - printf("OCM map DSA %08x\n", dsarc); + printf("OCM map DSA %08" PRIx32 "\n", dsarc); #endif cpu_register_physical_memory(dsarc, 0x04000000, ocm->offset | IO_MEM_RAM); @@ -1475,7 +1480,7 @@ static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr) break; } #ifdef DEBUG_I2C - printf("%s: addr " PADDRX " %02x\n", __func__, addr, ret); + printf("%s: addr " PADDRX " %02" PRIx32 "\n", __func__, addr, ret); #endif return ret; @@ -1487,7 +1492,7 @@ static void ppc4xx_i2c_writeb (void *opaque, ppc4xx_i2c_t *i2c; #ifdef DEBUG_I2C - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif i2c = opaque; switch (addr - i2c->base) { @@ -1557,7 +1562,7 @@ static void ppc4xx_i2c_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef DEBUG_I2C - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif ppc4xx_i2c_writeb(opaque, addr, value >> 8); ppc4xx_i2c_writeb(opaque, addr + 1, value); @@ -1582,7 +1587,7 @@ static void ppc4xx_i2c_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef DEBUG_I2C - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif ppc4xx_i2c_writeb(opaque, addr, value >> 24); ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16); @@ -1629,7 +1634,7 @@ void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio, i2c->irq = irq; ppc4xx_i2c_reset(i2c); #ifdef DEBUG_I2C - printf("%s: offset=" PADDRX "\n", __func__, offset); + printf("%s: offset " PADDRX "\n", __func__, offset); #endif ppc4xx_mmio_register(env, mmio, offset, 0x011, i2c_read, i2c_write, i2c); @@ -1668,7 +1673,7 @@ static void ppc4xx_gpt_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef DEBUG_I2C - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif /* XXX: generate a bus fault */ } @@ -1686,7 +1691,7 @@ static void ppc4xx_gpt_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { #ifdef DEBUG_I2C - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif /* XXX: generate a bus fault */ } @@ -1805,7 +1810,7 @@ static void ppc4xx_gpt_writel (void *opaque, int idx; #ifdef DEBUG_I2C - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif gpt = opaque; switch (addr - gpt->base) { @@ -1913,7 +1918,7 @@ void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio, gpt->timer = qemu_new_timer(vm_clock, &ppc4xx_gpt_cb, gpt); ppc4xx_gpt_reset(gpt); #ifdef DEBUG_GPT - printf("%s: offset=" PADDRX "\n", __func__, offset); + printf("%s: offset " PADDRX "\n", __func__, offset); #endif ppc4xx_mmio_register(env, mmio, offset, 0x0D4, gpt_read, gpt_write, gpt); @@ -2656,9 +2661,13 @@ static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) VCO_out = 0; if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) { M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */ - // printf("FBMUL %01x %d\n", (cpc->pllmr[1] >> 20) & 0xF, M); +#ifdef DEBUG_CLOCKS_LL + printf("FBMUL %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 20) & 0xF, M); +#endif D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */ - // printf("FWDA %01x %d\n", (cpc->pllmr[1] >> 16) & 0x7, D); +#ifdef DEBUG_CLOCKS_LL + printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D); +#endif VCO_out = cpc->sysclk * M * D; if (VCO_out < 500000000UL || VCO_out > 1000000000UL) { /* Error - unlock the PLL */ @@ -2683,53 +2692,53 @@ static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc) } /* Now, compute all other clocks */ D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */ -#ifdef DEBUG_CLOCKS - // printf("CCDV %01x %d\n", (cpc->pllmr[0] >> 20) & 0x3, D); +#ifdef DEBUG_CLOCKS_LL + printf("CCDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 20) & 0x3, D); #endif CPU_clk = PLL_out / D; D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */ -#ifdef DEBUG_CLOCKS - // printf("CBDV %01x %d\n", (cpc->pllmr[0] >> 16) & 0x3, D); +#ifdef DEBUG_CLOCKS_LL + printf("CBDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 16) & 0x3, D); #endif PLB_clk = CPU_clk / D; D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */ -#ifdef DEBUG_CLOCKS - // printf("OPDV %01x %d\n", (cpc->pllmr[0] >> 12) & 0x3, D); +#ifdef DEBUG_CLOCKS_LL + printf("OPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 12) & 0x3, D); #endif OPB_clk = PLB_clk / D; D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */ -#ifdef DEBUG_CLOCKS - // printf("EPDV %01x %d\n", (cpc->pllmr[0] >> 8) & 0x3, D); +#ifdef DEBUG_CLOCKS_LL + printf("EPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 8) & 0x3, D); #endif EBC_clk = PLB_clk / D; D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */ -#ifdef DEBUG_CLOCKS - // printf("MPDV %01x %d\n", (cpc->pllmr[0] >> 4) & 0x3, D); +#ifdef DEBUG_CLOCKS_LL + printf("MPDV %01" PRIx32 " %d\n", (cpc->pllmr[0] >> 4) & 0x3, D); #endif MAL_clk = PLB_clk / D; D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */ -#ifdef DEBUG_CLOCKS - // printf("PPDV %01x %d\n", cpc->pllmr[0] & 0x3, D); +#ifdef DEBUG_CLOCKS_LL + printf("PPDV %01" PRIx32 " %d\n", cpc->pllmr[0] & 0x3, D); #endif PCI_clk = PLB_clk / D; D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */ -#ifdef DEBUG_CLOCKS - // printf("U0DIV %01x %d\n", cpc->ucr & 0x7F, D); +#ifdef DEBUG_CLOCKS_LL + printf("U0DIV %01" PRIx32 " %d\n", cpc->ucr & 0x7F, D); #endif UART0_clk = PLL_out / D; D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */ -#ifdef DEBUG_CLOCKS - // printf("U1DIV %01x %d\n", (cpc->ucr >> 8) & 0x7F, D); +#ifdef DEBUG_CLOCKS_LL + printf("U1DIV %01" PRIx32 " %d\n", (cpc->ucr >> 8) & 0x7F, D); #endif UART1_clk = PLL_out / D; #ifdef DEBUG_CLOCKS - printf("Setup PPC405EP clocks - sysclk %d VCO %" PRIu64 + printf("Setup PPC405EP clocks - sysclk %" PRIu32 " VCO %" PRIu64 " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out); - printf("CPU %d PLB %d OPB %d EBC %d MAL %d PCI %d UART0 %d UART1 %d\n", + printf("CPU %" PRIu32 " PLB %" PRIu32 " OPB %" PRIu32 " EBC %" PRIu32 + " MAL %" PRIu32 " PCI %" PRIu32 " UART0 %" PRIu32 + " UART1 %" PRIu32 "\n", CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk, UART0_clk, UART1_clk); - printf("CB %p opaque %p\n", cpc->clk_setup[PPC405EP_CPU_CLK].cb, - cpc->clk_setup[PPC405EP_CPU_CLK].opaque); #endif /* Setup CPU clocks */ clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk); diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index be7187929..c4da27f4a 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -30,6 +30,7 @@ extern int loglevel; extern FILE *logfile; //#define DEBUG_MMIO +//#define DEBUG_UNASSIGNED #define DEBUG_UIC /*****************************************************************************/ @@ -136,8 +137,8 @@ static void mmio_writelen (ppc4xx_mmio_t *mmio, idx = MMIO_IDX(addr - mmio->base); #if defined(DEBUG_MMIO) - printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__, - mmio, len, addr, idx, value); + printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08" PRIx32 "\n", + __func__, mmio, len, addr, idx, value); #endif mem_write = mmio->mem_write[idx]; (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value); @@ -156,7 +157,7 @@ static void mmio_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { #if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif mmio_writelen(opaque, addr, value, 0); } @@ -174,7 +175,7 @@ static void mmio_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { #if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif mmio_writelen(opaque, addr, value, 1); } @@ -192,7 +193,7 @@ static void mmio_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { #if defined(DEBUG_MMIO) - printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value); + printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); #endif mmio_writelen(opaque, addr, value, 2); } @@ -214,7 +215,7 @@ int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, void *opaque) { - uint32_t end; + target_phys_addr_t end; int idx, eidx; if ((offset + len) > TARGET_PAGE_SIZE) @@ -223,8 +224,8 @@ int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, end = offset + len - 1; eidx = MMIO_IDX(end); #if defined(DEBUG_MMIO) - printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len, - end, idx, eidx); + printf("%s: offset " PADDRX " len %08" PRIx32 " " PADDRX " %d %d\n", + __func__, offset, len, end, idx, eidx); #endif for (; idx <= eidx; idx++) { mmio->mem_read[idx] = mem_read; @@ -245,8 +246,8 @@ ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) mmio->base = base; mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); #if defined(DEBUG_MMIO) - printf("%s: %p base %08x len %08x %d\n", __func__, - mmio, base, TARGET_PAGE_SIZE, mmio_memory); + printf("%s: base " PADDRX " len %08x %d\n", __func__, + base, TARGET_PAGE_SIZE, mmio_memory); #endif cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, @@ -297,9 +298,10 @@ static void ppcuic_trigger_irq (ppcuic_t *uic) cr = uic->uicsr & uic->uicer & uic->uiccr; #ifdef DEBUG_UIC if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n" - " %08x ir %08x cr %08x\n", __func__, - uic->uicsr, uic->uicer, uic->uiccr, + fprintf(logfile, "%s: uicsr %08" PRIx32 " uicer %08" PRIx32 + " uiccr %08" PRIx32 "\n" + " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", + __func__, uic->uicsr, uic->uicer, uic->uiccr, uic->uicsr & uic->uicer, ir, cr); } #endif @@ -342,8 +344,8 @@ static void ppcuic_trigger_irq (ppcuic_t *uic) } #ifdef DEBUG_UIC if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n", - uic->uicvr); + fprintf(logfile, "Raise UIC critical interrupt - " + "vector %08" PRIx32 "\n", uic->uicvr); } #endif } else { @@ -366,8 +368,9 @@ static void ppcuic_set_irq (void *opaque, int irq_num, int level) mask = 1 << irq_num; #ifdef DEBUG_UIC if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x " - "%08x\n", __func__, irq_num, level, + fprintf(logfile, "%s: irq %d level %d uicsr %08" PRIx32 + " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", + __func__, irq_num, level, uic->uicsr, mask, uic->uicsr & mask, level << irq_num); } #endif @@ -392,8 +395,8 @@ static void ppcuic_set_irq (void *opaque, int irq_num, int level) } #ifdef DEBUG_UIC if (loglevel & CPU_LOG_INT) { - fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__, - irq_num, level, uic->uicsr, sr); + fprintf(logfile, "%s: irq %d level %d sr %" PRIx32 " => " + "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); } #endif if (sr != uic->uicsr) diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 9d89b6631..1e3e6c4f6 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -255,7 +255,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - + /* XXX: suppress that */ dummy_irq = i8259_init(NULL); @@ -274,7 +274,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, #endif /* cuda also initialize ADB */ cuda_init(&cuda_mem_index, pic[0x19]); - + adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); @@ -314,7 +314,7 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, /* Special port to get debug messages from Open-Firmware */ register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); - } +} QEMUMachine core99_machine = { "mac99", diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index f3fe1a9d7..53edcd5c6 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -41,7 +41,7 @@ static int vga_osi_call (CPUState *env) static int vga_vbl_enabled; int linesize; - // printf("osi_call R5=%d\n", env->gpr[5]); + // printf("osi_call R5=" REGX "\n", ppc_dump_gpr(env, 5)); /* same handler as PearPC, coming from the original MOL video driver. */ @@ -93,7 +93,8 @@ static int vga_osi_call (CPUState *env) /* R6 = x, R7 = y, R8 = visible, R9 = data */ break; default: - fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]); + fprintf(stderr, "unsupported OSI call R5=" REGX "\n", + ppc_dump_gpr(env, 5)); break; } @@ -245,7 +246,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, } isa_mem_base = 0x80000000; - + /* Register 2 MB of ISA IO space */ isa_mmio_init(0xfe000000, 0x00200000); @@ -277,13 +278,13 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - + /* XXX: suppress that */ dummy_irq = i8259_init(NULL); /* XXX: use Mac Serial port */ serial_init(0x3f8, dummy_irq[4], serial_hds[0]); - + for(i = 0; i < nb_nics; i++) { if (!nd_table[i].model) nd_table[i].model = "ne2k_pci"; @@ -301,7 +302,7 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - + nvr = macio_nvram_init(&nvram_mem_index, 0x2000); pmac_format_nvram_partition(nvr, 0x2000); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index d33cf5d9a..8e939760d 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -113,7 +113,7 @@ static uint32_t speaker_ioport_read (void *opaque, uint32_t addr) static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value) { - // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); +// printf("%s: 0x" PADDRX " => 0x%08" PRIx32 "\n", __func__, addr, value); } static always_inline uint32_t _PPC_intack_read (target_phys_addr_t addr) @@ -122,7 +122,7 @@ static always_inline uint32_t _PPC_intack_read (target_phys_addr_t addr) if (addr == 0xBFFFFFF0) retval = pic_intack_read(isa_pic); - // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); +// printf("%s: 0x" PADDRX " <= %08" PRIx32 "\n", __func__, addr, retval); return retval; } @@ -192,7 +192,7 @@ static struct { static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { - printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); + printf("%s: 0x" PADDRX " => 0x%08" PRIx32 "\n", __func__, addr, value); } static void PPC_XCSR_writew (void *opaque, @@ -201,7 +201,7 @@ static void PPC_XCSR_writew (void *opaque, #ifdef TARGET_WORDS_BIGENDIAN value = bswap16(value); #endif - printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); + printf("%s: 0x" PADDRX " => 0x%08" PRIx32 "\n", __func__, addr, value); } static void PPC_XCSR_writel (void *opaque, @@ -210,14 +210,14 @@ static void PPC_XCSR_writel (void *opaque, #ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); #endif - printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); + printf("%s: 0x" PADDRX " => 0x%08" PRIx32 "\n", __func__, addr, value); } static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr) { uint32_t retval = 0; - printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); + printf("%s: 0x" PADDRX " <= %08" PRIx32 "\n", __func__, addr, retval); return retval; } @@ -226,7 +226,7 @@ static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr) { uint32_t retval = 0; - printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); + printf("%s: 0x" PADDRX " <= %08" PRIx32 "\n", __func__, addr, retval); #ifdef TARGET_WORDS_BIGENDIAN retval = bswap16(retval); #endif @@ -238,7 +238,7 @@ static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr) { uint32_t retval = 0; - printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); + printf("%s: 0x" PADDRX " <= %08" PRIx32 "\n", __func__, addr, retval); #ifdef TARGET_WORDS_BIGENDIAN retval = bswap32(retval); #endif @@ -280,7 +280,8 @@ static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) { sysctrl_t *sysctrl = opaque; - PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val); + PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, + val); sysctrl->fake_io[addr - 0x0398] = val; } @@ -288,7 +289,7 @@ static uint32_t PREP_io_read (void *opaque, uint32_t addr) { sysctrl_t *sysctrl = opaque; - PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, + PPC_IO_DPRINTF("0x%08" PRIx32 " <= 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, sysctrl->fake_io[addr - 0x0398]); return sysctrl->fake_io[addr - 0x0398]; } @@ -297,7 +298,8 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) { sysctrl_t *sysctrl = opaque; - PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val); + PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n", + addr - PPC_IO_BASE, val); switch (addr) { case 0x0092: /* Special port 92 */ @@ -353,8 +355,8 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) sysctrl->contiguous_map = val & 0x01; break; default: - printf("ERROR: unaffected IO port write: %04lx => %02x\n", - (long)addr, val); + printf("ERROR: unaffected IO port write: %04" PRIx32 + " => %02" PRIx32"\n", addr, val); break; } } @@ -416,10 +418,11 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) retval = sysctrl->contiguous_map; break; default: - printf("ERROR: unaffected IO port: %04lx read\n", (long)addr); + printf("ERROR: unaffected IO port: %04" PRIx32 " read\n", addr); break; } - PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, retval); + PPC_IO_DPRINTF("0x%08" PRIx32 " <= 0x%02" PRIx32 "\n", + addr - PPC_IO_BASE, retval); return retval; } @@ -468,7 +471,7 @@ static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr, #ifdef TARGET_WORDS_BIGENDIAN value = bswap16(value); #endif - PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value); + PPC_IO_DPRINTF("0x" PADDRX " => 0x%08" PRIx32 "\n", addr, value); cpu_outw(NULL, addr, value); } @@ -482,7 +485,7 @@ static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr) #ifdef TARGET_WORDS_BIGENDIAN ret = bswap16(ret); #endif - PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret); + PPC_IO_DPRINTF("0x" PADDRX " <= 0x%08" PRIx32 "\n", addr, ret); return ret; } @@ -496,7 +499,7 @@ static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr, #ifdef TARGET_WORDS_BIGENDIAN value = bswap32(value); #endif - PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value); + PPC_IO_DPRINTF("0x" PADDRX " => 0x%08" PRIx32 "\n", addr, value); cpu_outl(NULL, addr, value); } @@ -510,7 +513,7 @@ static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr) #ifdef TARGET_WORDS_BIGENDIAN ret = bswap32(ret); #endif - PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret); + PPC_IO_DPRINTF("0x" PADDRX " <= 0x%08" PRIx32 "\n", addr, ret); return ret; } -- cgit v1.2.3 From e57ec0168ce21cdda48ddf45d77b76185667d9e6 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 24 Nov 2007 03:09:07 +0000 Subject: ARMv7-M SysTick fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3727 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/arm-misc.h | 1 + hw/arm_gic.c | 2 +- hw/armv7m_nvic.c | 9 +++++---- hw/stellaris.c | 8 ++------ 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/hw/arm-misc.h b/hw/arm-misc.h index f8011182d..9c9537974 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -27,6 +27,7 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, int board_id, target_phys_addr_t loader_start); /* armv7m_nvic.c */ +int system_clock_scale; qemu_irq *armv7m_nvic_init(CPUState *env); #endif /* !ARM_MISC_H */ diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 774b79bf8..82577301b 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -638,7 +638,7 @@ static void gic_reset(gic_state *s) s->cpu_enabled[i] = 0; #endif } - for (i = 0; i < 15; i++) { + for (i = 0; i < 16; i++) { GIC_SET_ENABLED(i); GIC_SET_TRIGGER(i); } diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 99ea9873a..fc60487de 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -48,14 +48,15 @@ typedef struct { #define SYSTICK_CLKSOURCE (1 << 2) #define SYSTICK_COUNTFLAG (1 << 16) -/* Conversion factor from qemu timer to SysTick frequencies. - QEMU uses a base of 1GHz, so these give 20MHz and 1MHz for core and - reference frequencies. */ +/* Multiplication factor to convert from system clock ticks to qemu timer + ticks. */ +int system_clock_scale; +/* Conversion factor from qemu timer to SysTick frequencies. */ static inline int64_t systick_scale(nvic_state *s) { if (s->systick.control & SYSTICK_CLKSOURCE) - return 50; + return system_clock_scale; else return 1000; } diff --git a/hw/stellaris.c b/hw/stellaris.c index b7a037452..7936e0cc2 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -42,10 +42,6 @@ typedef const struct { /* General purpose timer module. */ -/* Multiplication factor to convert from GPTM timer ticks to qemu timer - ticks. */ -static int stellaris_clock_scale; - typedef struct gptm_state { uint32_t config; uint32_t mode[2]; @@ -90,7 +86,7 @@ static void gptm_reload(gptm_state *s, int n, int reset) /* 32-bit CountDown. */ uint32_t count; count = s->load[0] | (s->load[1] << 16); - tick += (int64_t)count * stellaris_clock_scale; + tick += (int64_t)count * system_clock_scale; } else if (s->config == 1) { /* 32-bit RTC. 1Hz tick. */ tick += ticks_per_sec; @@ -480,7 +476,7 @@ static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value) s->int_status |= (1 << 6); } s->rcc = value; - stellaris_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); + system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); break; case 0x100: /* RCGC0 */ s->rcgc[0] = value; -- cgit v1.2.3 From eea589cc221853688084a139c04fce50fc65745e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 24 Nov 2007 03:13:04 +0000 Subject: Stellaris ethernet support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3728 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/arm-misc.h | 3 + hw/armv7m_nvic.c | 4 +- hw/stellaris.c | 19 ++- hw/stellaris_enet.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 371 insertions(+), 4 deletions(-) create mode 100644 hw/stellaris_enet.c diff --git a/Makefile.target b/Makefile.target index cc29d526f..52d44a44a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -490,7 +490,7 @@ VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o VL_OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o VL_OBJS+= versatile_pci.o sd.o ptimer.o VL_OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o -VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o +VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o VL_OBJS+= pl061.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 9c9537974..7914ff117 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -30,5 +30,8 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, int system_clock_scale; qemu_irq *armv7m_nvic_init(CPUState *env); +/* stellaris_enent.c */ +void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq); + #endif /* !ARM_MISC_H */ diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index fc60487de..37596d0cc 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -14,7 +14,9 @@ #include "qemu-timer.h" #include "arm-misc.h" -#define GIC_NIRQ 64 +/* 32 internal lines (16 used for system exceptions) plus 64 external + interrupt lines. */ +#define GIC_NIRQ 96 #define NCPU 1 #define NVIC 1 diff --git a/hw/stellaris.c b/hw/stellaris.c index 7936e0cc2..01ed374a8 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -13,6 +13,7 @@ #include "devices.h" #include "qemu-timer.h" #include "i2c.h" +#include "net.h" #include "sysemu.h" #include "boards.h" @@ -319,6 +320,8 @@ typedef struct { uint32_t dcgc[3]; uint32_t clkvclr; uint32_t ldoarst; + uint32_t user0; + uint32_t user1; qemu_irq irq; stellaris_board_info *board; } ssys_state; @@ -438,6 +441,10 @@ static uint32_t ssys_read(void *opaque, target_phys_addr_t offset) return s->clkvclr; case 0x160: /* LDOARST */ return s->ldoarst; + case 0x1e0: /* USER0 */ + return s->user0; + case 0x1e4: /* USER1 */ + return s->user1; default: cpu_abort(cpu_single_env, "ssys_read: Bad offset 0x%x\n", (int)offset); return 0; @@ -541,7 +548,8 @@ static void ssys_reset(void *opaque) } static void stellaris_sys_init(uint32_t base, qemu_irq irq, - stellaris_board_info * board) + stellaris_board_info * board, + uint8_t *macaddr) { int iomemtype; ssys_state *s; @@ -550,6 +558,9 @@ static void stellaris_sys_init(uint32_t base, qemu_irq irq, s->base = base; s->irq = irq; s->board = board; + /* Most devices come preprogrammed with a MAC address in the user data. */ + s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16); + s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16); iomemtype = cpu_register_io_memory(0, ssys_readfn, ssys_writefn, s); @@ -1048,7 +1059,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } } - stellaris_sys_init(0x400fe000, pic[28], board); + stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr); for (i = 0; i < 7; i++) { if (board->dc4 & (1 << i)) { @@ -1081,6 +1092,10 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, pl022_init(0x40008000, pic[7], NULL, NULL); } } + if (board->dc4 & (1 << 28)) { + /* FIXME: Obey network model. */ + stellaris_enet_init(&nd_table[0], 0x40048000, pic[42]); + } if (board->peripherals & BP_GAMEPAD) { qemu_irq gpad_irq[5]; static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c new file mode 100644 index 000000000..31711b9d6 --- /dev/null +++ b/hw/stellaris_enet.c @@ -0,0 +1,347 @@ +/* + * Luminary Micro Stellaris Ethernet Controller + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ +#include "hw.h" +#include "arm-misc.h" +#include "net.h" +#include + +//#define DEBUG_STELLARIS_ENET 1 + +#ifdef DEBUG_STELLARIS_ENET +#define DPRINTF(fmt, args...) \ +do { printf("stellaris_enet: " fmt , ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "stellaris_enet: error: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "stellaris_enet: error: " fmt , ##args);} while (0) +#endif + +#define SE_INT_RX 0x01 +#define SE_INT_TXER 0x02 +#define SE_INT_TXEMP 0x04 +#define SE_INT_FOV 0x08 +#define SE_INT_RXER 0x10 +#define SE_INT_MD 0x20 +#define SE_INT_PHY 0x40 + +#define SE_RCTL_RXEN 0x01 +#define SE_RCTL_AMUL 0x02 +#define SE_RCTL_PRMS 0x04 +#define SE_RCTL_BADCRC 0x08 +#define SE_RCTL_RSTFIFO 0x10 + +#define SE_TCTL_TXEN 0x01 +#define SE_TCTL_PADEN 0x02 +#define SE_TCTL_CRC 0x04 +#define SE_TCTL_DUPLEX 0x08 + +typedef struct { + uint32_t base; + uint32_t ris; + uint32_t im; + uint32_t rctl; + uint32_t tctl; + uint32_t thr; + uint32_t mctl; + uint32_t mdv; + uint32_t mtxd; + uint32_t mrxd; + uint32_t np; + int tx_frame_len; + int tx_fifo_len; + uint8_t tx_fifo[2048]; + /* Real hardware has a 2k fifo, which works out to be at most 31 packets. + We implement a full 31 packet fifo. */ + struct { + uint8_t data[2048]; + int len; + } rx[31]; + uint8_t *rx_fifo; + int rx_fifo_len; + int next_packet; + VLANClientState *vc; + qemu_irq irq; + uint8_t macaddr[6]; +} stellaris_enet_state; + +static void stellaris_enet_update(stellaris_enet_state *s) +{ + qemu_set_irq(s->irq, (s->ris & s->im) != 0); +} + +/* TODO: Implement MAC address filtering. */ +static void stellaris_enet_receive(void *opaque, const uint8_t *buf, int size) +{ + stellaris_enet_state *s = (stellaris_enet_state *)opaque; + int n; + uint8_t *p; + uint32_t crc; + + if ((s->rctl & SE_RCTL_RXEN) == 0) + return; + if (s->np >= 31) { + DPRINTF("Packet dropped\n"); + return; + } + + DPRINTF("Received packet len=%d\n", size); + n = s->next_packet + s->np; + if (n >= 31) + n -= 31; + s->np++; + + s->rx[n].len = size + 6; + p = s->rx[n].data; + *(p++) = (size + 6); + *(p++) = (size + 6) >> 8; + memcpy (p, buf, size); + p += size; + crc = crc32(~0, buf, size); + *(p++) = crc; + *(p++) = crc >> 8; + *(p++) = crc >> 16; + *(p++) = crc >> 24; + /* Clear the remaining bytes in the last word. */ + if ((size & 3) != 2) { + memset(p, 0, (6 - size) & 3); + } + + s->ris |= SE_INT_RX; + stellaris_enet_update(s); +} + +static int stellaris_enet_can_receive(void *opaque) +{ + stellaris_enet_state *s = (stellaris_enet_state *)opaque; + + if ((s->rctl & SE_RCTL_RXEN) == 0) + return 1; + + return (s->np < 31); +} + +static uint32_t stellaris_enet_read(void *opaque, target_phys_addr_t offset) +{ + stellaris_enet_state *s = (stellaris_enet_state *)opaque; + uint32_t val; + + offset -= s->base; + switch (offset) { + case 0x00: /* RIS */ + DPRINTF("IRQ status %02x\n", s->ris); + return s->ris; + case 0x04: /* IM */ + return s->im; + case 0x08: /* RCTL */ + return s->rctl; + case 0x0c: /* TCTL */ + return s->tctl; + case 0x10: /* DATA */ + if (s->rx_fifo_len == 0) { + if (s->np == 0) { + BADF("RX underflow\n"); + return 0; + } + s->rx_fifo_len = s->rx[s->next_packet].len; + s->rx_fifo = s->rx[s->next_packet].data; + DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len); + } + val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16) + | (s->rx_fifo[3] << 24); + s->rx_fifo += 4; + s->rx_fifo_len -= 4; + if (s->rx_fifo_len <= 0) { + s->rx_fifo_len = 0; + s->next_packet++; + if (s->next_packet >= 31) + s->next_packet = 0; + s->np--; + DPRINTF("RX done np=%d\n", s->np); + } + return val; + case 0x14: /* IA0 */ + return s->macaddr[0] | (s->macaddr[1] << 8) + | (s->macaddr[2] << 16) | (s->macaddr[3] << 24); + case 0x18: /* IA1 */ + return s->macaddr[4] | (s->macaddr[5] << 8); + case 0x1c: /* THR */ + return s->thr; + case 0x20: /* MCTL */ + return s->mctl; + case 0x24: /* MDV */ + return s->mdv; + case 0x28: /* MADD */ + return 0; + case 0x2c: /* MTXD */ + return s->mtxd; + case 0x30: /* MRXD */ + return s->mrxd; + case 0x34: /* NP */ + return s->np; + case 0x38: /* TR */ + return 0; + case 0x3c: /* Undocuented: Timestamp? */ + return 0; + default: + cpu_abort (cpu_single_env, "stellaris_enet_read: Bad offset %x\n", + (int)offset); + return 0; + } +} + +static void stellaris_enet_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + stellaris_enet_state *s = (stellaris_enet_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* IACK */ + s->ris &= ~value; + DPRINTF("IRQ ack %02x/%02x\n", value, s->ris); + stellaris_enet_update(s); + /* Clearing TXER also resets the TX fifo. */ + if (value & SE_INT_TXER) + s->tx_frame_len = -1; + break; + case 0x04: /* IM */ + DPRINTF("IRQ mask %02x/%02x\n", value, s->ris); + s->im = value; + stellaris_enet_update(s); + break; + case 0x08: /* RCTL */ + s->rctl = value; + if (value & SE_RCTL_RSTFIFO) { + s->rx_fifo_len = 0; + s->np = 0; + stellaris_enet_update(s); + } + break; + case 0x0c: /* TCTL */ + s->tctl = value; + break; + case 0x10: /* DATA */ + if (s->tx_frame_len == -1) { + s->tx_frame_len = value & 0xffff; + if (s->tx_frame_len > 2032) { + DPRINTF("TX frame too long (%d)\n", s->tx_frame_len); + s->tx_frame_len = 0; + s->ris |= SE_INT_TXER; + stellaris_enet_update(s); + } else { + DPRINTF("Start TX frame len=%d\n", s->tx_frame_len); + /* The value written does not include the ethernet header. */ + s->tx_frame_len += 14; + if ((s->tctl & SE_TCTL_CRC) == 0) + s->tx_frame_len += 4; + s->tx_fifo_len = 0; + s->tx_fifo[s->tx_fifo_len++] = value >> 16; + s->tx_fifo[s->tx_fifo_len++] = value >> 24; + } + } else { + s->tx_fifo[s->tx_fifo_len++] = value; + s->tx_fifo[s->tx_fifo_len++] = value >> 8; + s->tx_fifo[s->tx_fifo_len++] = value >> 16; + s->tx_fifo[s->tx_fifo_len++] = value >> 24; + if (s->tx_fifo_len >= s->tx_frame_len) { + /* We don't implement explicit CRC, so just chop it off. */ + if ((s->tctl & SE_TCTL_CRC) == 0) + s->tx_frame_len -= 4; + if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) { + memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len); + s->tx_fifo_len = 60; + } + qemu_send_packet(s->vc, s->tx_fifo, s->tx_frame_len); + s->tx_frame_len = -1; + s->ris |= SE_INT_TXEMP; + stellaris_enet_update(s); + DPRINTF("Done TX\n"); + } + } + break; + case 0x14: /* IA0 */ + s->macaddr[0] = value; + s->macaddr[1] = value >> 8; + s->macaddr[2] = value >> 16; + s->macaddr[3] = value >> 24; + break; + case 0x18: /* IA1 */ + s->macaddr[4] = value; + s->macaddr[5] = value >> 8; + break; + case 0x1c: /* THR */ + s->thr = value; + break; + case 0x20: /* MCTL */ + s->mctl = value; + break; + case 0x24: /* MDV */ + s->mdv = value; + break; + case 0x28: /* MADD */ + /* ignored. */ + break; + case 0x2c: /* MTXD */ + s->mtxd = value & 0xff; + break; + case 0x30: /* MRXD */ + case 0x34: /* NP */ + case 0x38: /* TR */ + /* Ignored. */ + case 0x3c: /* Undocuented: Timestamp? */ + /* Ignored. */ + break; + default: + cpu_abort (cpu_single_env, "stellaris_enet_write: Bad offset %x\n", + (int)offset); + } +} + +static CPUReadMemoryFunc *stellaris_enet_readfn[] = { + stellaris_enet_read, + stellaris_enet_read, + stellaris_enet_read +}; + +static CPUWriteMemoryFunc *stellaris_enet_writefn[] = { + stellaris_enet_write, + stellaris_enet_write, + stellaris_enet_write +}; +static void stellaris_enet_reset(stellaris_enet_state *s) +{ + s->mdv = 0x80; + s->rctl = SE_RCTL_BADCRC; + s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP + | SE_INT_TXER | SE_INT_RX; + s->thr = 0x3f; + s->tx_frame_len = -1; +} + +void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) +{ + stellaris_enet_state *s; + int iomemtype; + + s = (stellaris_enet_state *)qemu_mallocz(sizeof(stellaris_enet_state)); + iomemtype = cpu_register_io_memory(0, stellaris_enet_readfn, + stellaris_enet_writefn, s); + cpu_register_physical_memory(base, 0x00001000, iomemtype); + s->base = base; + s->irq = irq; + memcpy(s->macaddr, nd->macaddr, 6); + + if (nd->vlan) + s->vc = qemu_new_vlan_client(nd->vlan, stellaris_enet_receive, + stellaris_enet_can_receive, s); + + stellaris_enet_reset(s); +} -- cgit v1.2.3 From 2ad207d4a0522fa0ea64abe93c4334f87444e45e Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 24 Nov 2007 23:22:11 +0000 Subject: Thumb semihosting fixes. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3729 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/helper.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 038025dac..40bdeb186 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -602,6 +602,15 @@ void do_interrupt_v7m(CPUARMState *env) armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_MEM); return; case EXCP_BKPT: + if (semihosting_enabled) { + int nr; + nr = lduw_code(env->regs[15]) & 0xff; + if (nr == 0xab) { + env->regs[15] += 2; + env->regs[0] = do_arm_semihosting(env); + return; + } + } armv7m_nvic_set_pending(env->v7m.nvic, ARMV7M_EXCP_DEBUG); return; case EXCP_IRQ: @@ -687,7 +696,7 @@ void do_interrupt(CPUARMState *env) break; case EXCP_BKPT: /* See if this is a semihosting syscall. */ - if (env->thumb) { + if (env->thumb && semihosting_enabled) { mask = lduw_code(env->regs[15]) & 0xff; if (mask == 0xab && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { -- cgit v1.2.3 From f3b9f954326d5010c7215a3a023264204afd3c42 Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 24 Nov 2007 23:27:15 +0000 Subject: Drop an unused variable (Samuel Thibault). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3730 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/vl.c b/vl.c index 6f8374028..1a7f4a34c 100644 --- a/vl.c +++ b/vl.c @@ -160,7 +160,6 @@ int inet_aton(const char *cp, struct in_addr *ia); const char *bios_dir = CONFIG_QEMU_SHAREDIR; const char *bios_name = NULL; -char phys_ram_file[1024]; void *ioport_opaque[MAX_IOPORTS]; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; -- cgit v1.2.3 From 775616c3ae8c9bdd43d57274f259b09ae87217b0 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 24 Nov 2007 23:35:08 +0000 Subject: Partial SD card SPI mode support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3731 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 1 + Makefile.target | 2 +- hw/omap_mmc.c | 2 +- hw/pl061.c | 15 +++-- hw/pl181.c | 2 +- hw/primecell.h | 4 +- hw/pxa2xx_mmci.c | 2 +- hw/sd.c | 87 +++++++++++++++++++++++- hw/sd.h | 6 +- hw/ssd0323.c | 3 + hw/ssi-sd.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/stellaris.c | 60 ++++++++++++++++- 12 files changed, 370 insertions(+), 16 deletions(-) create mode 100644 hw/ssi-sd.c diff --git a/Makefile b/Makefile index c262c473e..a2177c12b 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,7 @@ OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o OBJS+=scsi-disk.o cdrom.o OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o +OBJS+=sd.o ssi-sd.o ifdef CONFIG_WIN32 OBJS+=tap-win32.o diff --git a/Makefile.target b/Makefile.target index 52d44a44a..33921c5aa 100644 --- a/Makefile.target +++ b/Makefile.target @@ -488,7 +488,7 @@ 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 pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o -VL_OBJS+= versatile_pci.o sd.o ptimer.o +VL_OBJS+= versatile_pci.o ptimer.o VL_OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o VL_OBJS+= pl061.o diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index 0a7ae8712..6fbbb8491 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -525,7 +525,7 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, cpu_register_physical_memory(s->base, 0x800, iomemtype); /* Instantiate the storage */ - s->card = sd_init(bd); + s->card = sd_init(bd, 0); return s; } diff --git a/hw/pl061.c b/hw/pl061.c index d9a6f50f8..3ac0a4c10 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -48,6 +48,7 @@ typedef struct { uint8_t slr; uint8_t den; uint8_t cr; + uint8_t float_high; qemu_irq irq; qemu_irq out[8]; } pl061_state; @@ -56,18 +57,22 @@ static void pl061_update(pl061_state *s) { uint8_t changed; uint8_t mask; + uint8_t out; int i; - changed = s->old_data ^ s->data; + /* Outputs float high. */ + /* FIXME: This is board dependent. */ + out = (s->data & s->dir) | ~s->dir; + changed = s->old_data ^ out; if (!changed) return; - s->old_data = s->data; + s->old_data = out; for (i = 0; i < 8; i++) { mask = 1 << i; - if ((changed & mask & s->dir) && s->out) { - DPRINTF("Set output %d = %d\n", i, (s->data & mask) != 0); - qemu_set_irq(s->out[i], (s->data & mask) != 0); + if ((changed & mask) && s->out) { + DPRINTF("Set output %d = %d\n", i, (out & mask) != 0); + qemu_set_irq(s->out[i], (out & mask) != 0); } } diff --git a/hw/pl181.c b/hw/pl181.c index 5eb46d0f8..75c3143e2 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -458,7 +458,7 @@ void pl181_init(uint32_t base, BlockDriverState *bd, pl181_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); s->base = base; - s->card = sd_init(bd); + s->card = sd_init(bd, 0); s->irq[0] = irq0; s->irq[1] = irq1; qemu_register_reset(pl181_reset, s); diff --git a/hw/primecell.h b/hw/primecell.h index 072390bf0..aa35adc02 100644 --- a/hw/primecell.h +++ b/hw/primecell.h @@ -21,13 +21,15 @@ void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr, enum pl011_type type); /* pl022.c */ -void pl022_init(uint32_t base, qemu_irq irq, int (*xfer_cb)(void *, int), +typedef int (*ssi_xfer_cb)(void *, int); +void pl022_init(uint32_t base, qemu_irq irq, ssi_xfer_cb xfer_cb, void *opaque); /* pl050.c */ void pl050_init(uint32_t base, qemu_irq irq, int is_mouse); /* pl061.c */ +void pl061_float_high(void *opaque, uint8_t mask); qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out); /* pl080.c */ diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 9d26b7959..32b6a6f1a 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -538,7 +538,7 @@ struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, cpu_register_physical_memory(base, 0x00100000, iomemtype); /* Instantiate the actual storage */ - s->card = sd_init(bd); + s->card = sd_init(bd, 1); register_savevm("pxa2xx_mmci", 0, 0, pxa2xx_mmci_save, pxa2xx_mmci_load, s); diff --git a/hw/sd.c b/hw/sd.c index 8b481e6f0..fc3c45a83 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -87,6 +87,7 @@ struct SDState { int pwd_len; int function_group[6]; + int spi; int current_cmd; int blk_written; uint32_t data_start; @@ -395,11 +396,16 @@ static void sd_cardchange(void *opaque) } } -SDState *sd_init(BlockDriverState *bs) +/* We do not model the chip select pin, so allow the board to select + whether card should be in SSI ot MMC/SD mode. It is also up to the + board to ensure that ssi transfers only occur when the chip select + is asserted. */ +SDState *sd_init(BlockDriverState *bs, int is_spi) { SDState *sd; sd = (SDState *) qemu_mallocz(sizeof(SDState)); + sd->spi = is_spi; sd_reset(sd, bs); bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd); return sd; @@ -567,16 +573,25 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, case 0: /* CMD0: GO_IDLE_STATE */ switch (sd->state) { case sd_inactive_state: - return sd_r0; + return sd->spi ? sd_r1 : sd_r0; default: sd->state = sd_idle_state; sd_reset(sd, sd->bdrv); - return sd_r0; + return sd->spi ? sd_r1 : sd_r0; } break; + case 1: /* CMD1: SEND_OP_CMD */ + if (!sd->spi) + goto bad_cmd; + + sd->state = sd_transfer_state; + return sd_r1; + case 2: /* CMD2: ALL_SEND_CID */ + if (sd->spi) + goto bad_cmd; switch (sd->state) { case sd_ready_state: sd->state = sd_identification_state; @@ -588,6 +603,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 3: /* CMD3: SEND_RELATIVE_ADDR */ + if (sd->spi) + goto bad_cmd; switch (sd->state) { case sd_identification_state: case sd_standby_state: @@ -601,6 +618,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 4: /* CMD4: SEND_DSR */ + if (sd->spi) + goto bad_cmd; switch (sd->state) { case sd_standby_state: break; @@ -611,6 +630,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 6: /* CMD6: SWITCH_FUNCTION */ + if (sd->spi) + goto bad_cmd; switch (sd->mode) { case sd_data_transfer_mode: sd_function_switch(sd, req.arg); @@ -625,6 +646,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 7: /* CMD7: SELECT/DESELECT_CARD */ + if (sd->spi) + goto bad_cmd; switch (sd->state) { case sd_standby_state: if (sd->rca != rca) @@ -668,6 +691,15 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, return sd_r2_s; + case sd_transfer_state: + if (!sd->spi) + break; + sd->state = sd_sendingdata_state; + memcpy(sd->data, sd->csd, 16); + sd->data_start = req.arg; + sd->data_offset = 0; + return sd_r1; + default: break; } @@ -681,12 +713,23 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, return sd_r2_i; + case sd_transfer_state: + if (!sd->spi) + break; + sd->state = sd_sendingdata_state; + memcpy(sd->data, sd->cid, 16); + sd->data_start = req.arg; + sd->data_offset = 0; + return sd_r1; + default: break; } break; case 11: /* CMD11: READ_DAT_UNTIL_STOP */ + if (sd->spi) + goto bad_cmd; switch (sd->state) { case sd_transfer_state: sd->state = sd_sendingdata_state; @@ -733,6 +776,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 15: /* CMD15: GO_INACTIVE_STATE */ + if (sd->spi) + goto bad_cmd; switch (sd->mode) { case sd_data_transfer_mode: if (sd->rca != rca) @@ -796,8 +841,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, /* Block write commands (Class 4) */ case 24: /* CMD24: WRITE_SINGLE_BLOCK */ + if (sd->spi) + goto unimplemented_cmd; switch (sd->state) { case sd_transfer_state: + /* Writing in SPI mode not implemented. */ + if (sd->spi) + break; sd->state = sd_receivingdata_state; sd->data_start = req.arg; sd->data_offset = 0; @@ -817,8 +867,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ + if (sd->spi) + goto unimplemented_cmd; switch (sd->state) { case sd_transfer_state: + /* Writing in SPI mode not implemented. */ + if (sd->spi) + break; sd->state = sd_receivingdata_state; sd->data_start = req.arg; sd->data_offset = 0; @@ -838,6 +893,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 26: /* CMD26: PROGRAM_CID */ + if (sd->spi) + goto bad_cmd; switch (sd->state) { case sd_transfer_state: sd->state = sd_receivingdata_state; @@ -851,6 +908,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 27: /* CMD27: PROGRAM_CSD */ + if (sd->spi) + goto unimplemented_cmd; switch (sd->state) { case sd_transfer_state: sd->state = sd_receivingdata_state; @@ -962,6 +1021,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, /* Lock card commands (Class 7) */ case 42: /* CMD42: LOCK_UNLOCK */ + if (sd->spi) + goto unimplemented_cmd; switch (sd->state) { case sd_transfer_state: sd->state = sd_receivingdata_state; @@ -1000,10 +1061,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; default: + bad_cmd: sd->card_status |= ILLEGAL_COMMAND; printf("SD: Unknown CMD%i\n", req.cmd); return sd_r0; + + unimplemented_cmd: + /* Commands that are recognised but not yet implemented in SPI mode. */ + sd->card_status |= ILLEGAL_COMMAND; + printf ("SD: CMD%i not implemented in SPI mode\n", req.cmd); + return sd_r0; } sd->card_status |= ILLEGAL_COMMAND; @@ -1069,6 +1137,11 @@ static sd_rsp_type_t sd_app_command(SDState *sd, break; case 41: /* ACMD41: SD_APP_OP_COND */ + if (sd->spi) { + /* SEND_OP_CMD */ + sd->state = sd_transfer_state; + return sd_r1; + } switch (sd->state) { case sd_idle_state: /* We accept any voltage. 10000 V is nothing. */ @@ -1414,6 +1487,14 @@ uint8_t sd_read_data(SDState *sd) sd->state = sd_transfer_state; break; + case 9: /* CMD9: SEND_CSD */ + case 10: /* CMD10: SEND_CID */ + ret = sd->data[sd->data_offset ++]; + + if (sd->data_offset >= 16) + sd->state = sd_transfer_state; + break; + case 11: /* CMD11: READ_DAT_UNTIL_STOP */ if (sd->data_offset == 0) BLK_READ_BLOCK(sd->data_start, sd->blk_len); diff --git a/hw/sd.h b/hw/sd.h index 9416df0db..85f110f3c 100644 --- a/hw/sd.h +++ b/hw/sd.h @@ -67,7 +67,7 @@ struct sd_request_s { typedef struct SDState SDState; -SDState *sd_init(BlockDriverState *bs); +SDState *sd_init(BlockDriverState *bs, int is_spi); int sd_do_command(SDState *sd, struct sd_request_s *req, uint8_t *response); void sd_write_data(SDState *sd, uint8_t value); @@ -75,4 +75,8 @@ uint8_t sd_read_data(SDState *sd); void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert); int sd_data_ready(SDState *sd); +/* ssi-sd.c */ +int ssi_sd_xfer(void *opaque, int val); +void *ssi_sd_init(BlockDriverState *bs); + #endif /* __hw_sd_h */ diff --git a/hw/ssd0323.c b/hw/ssd0323.c index c31e49a91..4706b05f4 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -157,6 +157,9 @@ int ssd0323_xfer_ssi(void *opaque, int data) case 0xe3: /* NOP. */ DATA(0); break; + case 0xff: /* Nasty hack because we don't handle chip selects + properly. */ + break; default: BADF("Unknown command: 0x%x\n", data); } diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c new file mode 100644 index 000000000..8b45fc4d1 --- /dev/null +++ b/hw/ssi-sd.c @@ -0,0 +1,202 @@ +/* + * SSI to SD card adapter. + * + * Copyright (c) 2007 CodeSourcery. + * Written by Paul Brook + * + * This code is licenced under the GPL. + */ + +#include "hw.h" +#include "sd.h" + +//#define DEBUG_SSI_SD 1 + +#ifdef DEBUG_SSI_SD +#define DPRINTF(fmt, args...) \ +do { printf("ssi_sd: " fmt , ##args); } while (0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "ssi_sd: error: " fmt , ##args); exit(1);} while (0) +#else +#define DPRINTF(fmt, args...) do {} while(0) +#define BADF(fmt, args...) \ +do { fprintf(stderr, "ssi_sd: error: " fmt , ##args);} while (0) +#endif + +typedef enum { + SSI_SD_CMD, + SSI_SD_CMDARG, + SSI_SD_RESPONSE, + SSI_SD_DATA_START, + SSI_SD_DATA_READ, +} ssi_sd_mode; + +typedef struct { + ssi_sd_mode mode; + int cmd; + uint8_t cmdarg[4]; + uint8_t response[5]; + int arglen; + int response_pos; + int stopping; + SDState *sd; +} ssi_sd_state; + +/* State word bits. */ +#define SSI_SDR_LOCKED 0x0001 +#define SSI_SDR_WP_ERASE 0x0002 +#define SSI_SDR_ERROR 0x0004 +#define SSI_SDR_CC_ERROR 0x0008 +#define SSI_SDR_ECC_FAILED 0x0010 +#define SSI_SDR_WP_VIOLATION 0x0020 +#define SSI_SDR_ERASE_PARAM 0x0040 +#define SSI_SDR_OUT_OF_RANGE 0x0080 +#define SSI_SDR_IDLE 0x0100 +#define SSI_SDR_ERASE_RESET 0x0200 +#define SSI_SDR_ILLEGAL_COMMAND 0x0400 +#define SSI_SDR_COM_CRC_ERROR 0x0800 +#define SSI_SDR_ERASE_SEQ_ERROR 0x1000 +#define SSI_SDR_ADDRESS_ERROR 0x2000 +#define SSI_SDR_PARAMETER_ERROR 0x4000 + +int ssi_sd_xfer(void *opaque, int val) +{ + ssi_sd_state *s = (ssi_sd_state *)opaque; + + /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data. */ + if (s->mode == SSI_SD_DATA_READ && val == 0x4d) { + s->mode = SSI_SD_CMD; + /* There must be at least one byte delay before the card responds. */ + s->stopping = 1; + } + + switch (s->mode) { + case SSI_SD_CMD: + if (val == 0xff) { + DPRINTF("NULL command\n"); + return 0xff; + } + s->cmd = val & 0x3f; + s->mode = SSI_SD_CMDARG; + s->arglen = 0; + return 0xff; + case SSI_SD_CMDARG: + if (s->arglen == 4) { + struct sd_request_s request; + uint8_t longresp[16]; + /* FIXME: Check CRC. */ + request.cmd = s->cmd; + request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16) + | (s->cmdarg[2] << 8) | s->cmdarg[3]; + DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg); + s->arglen = sd_do_command(s->sd, &request, longresp); + if (s->arglen <= 0) { + s->arglen = 1; + s->response[0] = 4; + DPRINTF("SD command failed\n"); + } else if (s->cmd == 58) { + /* CMD58 returns R3 response (OCR) */ + DPRINTF("Returned OCR\n"); + s->arglen = 5; + s->response[0] = 1; + memcpy(&s->response[1], longresp, 4); + } else if (s->arglen != 4) { + BADF("Unexpected response to cmd %d\n", s->cmd); + /* Illegal command is about as near as we can get. */ + s->arglen = 1; + s->response[0] = 4; + } else { + /* All other commands return status. */ + uint32_t cardstatus; + uint16_t status; + /* CMD13 returns a 2-byte statuse work. Other commands + only return the first byte. */ + s->arglen = (s->cmd == 13) ? 2 : 1; + cardstatus = (longresp[0] << 24) | (longresp[1] << 16) + | (longresp[2] << 8) | longresp[3]; + status = 0; + if (((cardstatus >> 9) & 0xf) < 4) + status |= SSI_SDR_IDLE; + if (cardstatus & ERASE_RESET) + status |= SSI_SDR_ERASE_RESET; + if (cardstatus & ILLEGAL_COMMAND) + status |= SSI_SDR_ILLEGAL_COMMAND; + if (cardstatus & COM_CRC_ERROR) + status |= SSI_SDR_COM_CRC_ERROR; + if (cardstatus & ERASE_SEQ_ERROR) + status |= SSI_SDR_ERASE_SEQ_ERROR; + if (cardstatus & ADDRESS_ERROR) + status |= SSI_SDR_ADDRESS_ERROR; + if (cardstatus & CARD_IS_LOCKED) + status |= SSI_SDR_LOCKED; + if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP)) + status |= SSI_SDR_WP_ERASE; + if (cardstatus & SD_ERROR) + status |= SSI_SDR_ERROR; + if (cardstatus & CC_ERROR) + status |= SSI_SDR_CC_ERROR; + if (cardstatus & CARD_ECC_FAILED) + status |= SSI_SDR_ECC_FAILED; + if (cardstatus & WP_VIOLATION) + status |= SSI_SDR_WP_VIOLATION; + if (cardstatus & ERASE_PARAM) + status |= SSI_SDR_ERASE_PARAM; + if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE)) + status |= SSI_SDR_OUT_OF_RANGE; + /* ??? Don't know what Parameter Error really means, so + assume it's set if the second byte is nonzero. */ + if (status & 0xff) + status |= SSI_SDR_PARAMETER_ERROR; + s->response[0] = status >> 8; + s->response[1] = status; + DPRINTF("Card status 0x%02x\n", status); + } + s->mode = SSI_SD_RESPONSE; + s->response_pos = 0; + } else { + s->cmdarg[s->arglen++] = val; + } + return 0xff; + case SSI_SD_RESPONSE: + if (s->stopping) { + s->stopping = 0; + return 0xff; + } + if (s->response_pos < s->arglen) { + DPRINTF("Response 0x%02x\n", s->response[s->response_pos]); + return s->response[s->response_pos++]; + } + if (sd_data_ready(s->sd)) { + DPRINTF("Data read\n"); + s->mode = SSI_SD_DATA_START; + } else { + DPRINTF("End of command\n"); + s->mode = SSI_SD_CMD; + } + return 0xff; + case SSI_SD_DATA_START: + DPRINTF("Start read block\n"); + s->mode = SSI_SD_DATA_READ; + return 0xfe; + case SSI_SD_DATA_READ: + val = sd_read_data(s->sd); + if (!sd_data_ready(s->sd)) { + DPRINTF("Data read end\n"); + s->mode = SSI_SD_CMD; + } + return val; + } + /* Should never happen. */ + return 0xff; +} + +void *ssi_sd_init(BlockDriverState *bs) +{ + ssi_sd_state *s; + + s = (ssi_sd_state *)qemu_mallocz(sizeof(ssi_sd_state)); + s->mode = SSI_SD_CMD; + s->sd = sd_init(bs, 1); + return s; +} + diff --git a/hw/stellaris.c b/hw/stellaris.c index 01ed374a8..5f06388a9 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -14,6 +14,7 @@ #include "qemu-timer.h" #include "i2c.h" #include "net.h" +#include "sd.h" #include "sysemu.h" #include "boards.h" @@ -1000,6 +1001,51 @@ static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq) return qi[0]; } +/* Some boards have both an OLED controller and SD card connected to + the same SSI port, with the SD card chip select connected to a + GPIO pin. Technically the OLED chip select is connected to the SSI + Fss pin. We do not bother emulating that as both devices should + never be selected simultaneously, and our OLED controller ignores stray + 0xff commands that occur when deselecting the SD card. */ + +typedef struct { + ssi_xfer_cb xfer_cb[2]; + void *opaque[2]; + qemu_irq irq; + int current_dev; +} stellaris_ssi_bus_state; + +static void stellaris_ssi_bus_select(void *opaque, int irq, int level) +{ + stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; + + s->current_dev = level; +} + +static int stellaris_ssi_bus_xfer(void *opaque, int val) +{ + stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; + + return s->xfer_cb[s->current_dev](s->opaque[s->current_dev], val); +} + +static void *stellaris_ssi_bus_init(qemu_irq *irqp, + ssi_xfer_cb cb0, void *opaque0, + ssi_xfer_cb cb1, void *opaque1) +{ + qemu_irq *qi; + stellaris_ssi_bus_state *s; + + s = (stellaris_ssi_bus_state *)qemu_mallocz(sizeof(stellaris_ssi_bus_state)); + s->xfer_cb[0] = cb0; + s->opaque[0] = opaque0; + s->xfer_cb[1] = cb1; + s->opaque[1] = opaque1; + qi = qemu_allocate_irqs(stellaris_ssi_bus_select, s, 1); + *irqp = *qi; + return s; +} + /* Board init. */ static stellaris_board_info stellaris_boards[] = { { "LM3S811EVB", @@ -1085,9 +1131,19 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, if (board->dc2 & (1 << 4)) { if (board->peripherals & BP_OLED_SSI) { void * oled; - /* FIXME: Implement chip select for OLED/MMC. */ + void * sd; + void *ssi_bus; + oled = ssd0323_init(ds, &gpio_out[GPIO_C][7]); - pl022_init(0x40008000, pic[7], ssd0323_xfer_ssi, oled); + sd = ssi_sd_init(sd_bdrv); + + ssi_bus = stellaris_ssi_bus_init(&gpio_out[GPIO_D][0], + ssi_sd_xfer, sd, + ssd0323_xfer_ssi, oled); + + pl022_init(0x40008000, pic[7], stellaris_ssi_bus_xfer, ssi_bus); + /* Make sure the select pin is high. */ + qemu_irq_raise(gpio_out[GPIO_D][0]); } else { pl022_init(0x40008000, pic[7], NULL, NULL); } -- cgit v1.2.3 From 3e3f67547b2007592960e5b2d01f53a1ee0d863a Mon Sep 17 00:00:00 2001 From: balrog Date: Sat, 24 Nov 2007 23:47:38 +0000 Subject: Gumstix Verdex (ARM) board support by Thorsten Zitterell. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3732 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/boards.h | 1 + hw/gumstix.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++------------ vl.c | 1 + 3 files changed, 74 insertions(+), 17 deletions(-) diff --git a/hw/boards.h b/hw/boards.h index 73a44a4a3..3decd04d4 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -78,6 +78,7 @@ extern QEMUMachine palmte_machine; /* gumstix.c */ extern QEMUMachine connex_machine; +extern QEMUMachine verdex_machine; /* stellaris.c */ extern QEMUMachine lm3s811evb_machine; diff --git a/hw/gumstix.c b/hw/gumstix.c index 824715662..5ef1fb7cf 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -7,6 +7,29 @@ * * This code is licensed under the GNU GPL v2. */ + +/* + * Example usage: + * + * connex: + * ======= + * create image: + * # dd of=flash bs=1k count=16k if=/dev/zero + * # dd of=flash bs=1k conv=notrunc if=u-boot.bin + * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2 + * start it: + * # qemu-system-arm -M connex -pflash flash -monitor null -nographic + * + * verdex: + * ======= + * create image: + * # dd of=flash bs=1k count=32k if=/dev/zero + * # dd of=flash bs=1k conv=notrunc if=u-boot.bin + * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2 + * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage + * start it: + * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289 + */ #include "hw.h" #include "pxa.h" @@ -16,26 +39,24 @@ #include "devices.h" #include "boards.h" -/* Board init. */ -enum gumstix_model_e { connex }; - -static void gumstix_common_init(int ram_size, int vga_ram_size, - DisplayState *ds, const char *kernel_filename, - const char *kernel_cmdline, const char *initrd_filename, - const char *cpu_model, enum gumstix_model_e model) +static void connex_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) { struct pxa2xx_state_s *cpu; - uint32_t gumstix_rom = 0x02000000; - uint32_t gumstix_ram = 0x08000000; + uint32_t connex_rom = 0x01000000; + uint32_t connex_ram = 0x04000000; - if (ram_size < (gumstix_ram + gumstix_rom + PXA2XX_INTERNAL_SIZE)) { + if (ram_size < (connex_ram + connex_rom + PXA2XX_INTERNAL_SIZE)) { fprintf(stderr, "This platform requires %i bytes of memory\n", - gumstix_ram + gumstix_rom + PXA2XX_INTERNAL_SIZE); + connex_ram + connex_rom + PXA2XX_INTERNAL_SIZE); exit(1); } - cpu = pxa255_init(gumstix_ram, ds); + cpu = pxa255_init(connex_ram, ds); if (pflash_table[0] == NULL) { fprintf(stderr, "A flash image must be given with the " @@ -43,9 +64,9 @@ static void gumstix_common_init(int ram_size, int vga_ram_size, exit(1); } - if (!pflash_register(0x00000000, gumstix_ram + PXA2XX_INTERNAL_SIZE, + if (!pflash_register(0x00000000, connex_ram + PXA2XX_INTERNAL_SIZE, pflash_table[0], 128 * 1024, 128, 2, 0, 0, 0, 0)) { - fprintf(stderr, "qemu: Error register flash memory.\n"); + fprintf(stderr, "qemu: Error registering flash memory.\n"); exit(1); } @@ -56,13 +77,41 @@ static void gumstix_common_init(int ram_size, int vga_ram_size, pxa2xx_gpio_in_get(cpu->gpio)[36]); } -static void connex_init(int ram_size, int vga_ram_size, +static void verdex_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - gumstix_common_init(ram_size, vga_ram_size, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, connex); + struct pxa2xx_state_s *cpu; + + uint32_t verdex_rom = 0x02000000; + uint32_t verdex_ram = 0x10000000; + + if (ram_size < (verdex_ram + verdex_rom + PXA2XX_INTERNAL_SIZE)) { + fprintf(stderr, "This platform requires %i bytes of memory\n", + verdex_ram + verdex_rom + PXA2XX_INTERNAL_SIZE); + exit(1); + } + + cpu = pxa270_init(verdex_ram, ds, "pxa270-c0"); + + if (pflash_table[0] == NULL) { + fprintf(stderr, "A flash image must be given with the " + "'pflash' parameter\n"); + exit(1); + } + + if (!pflash_register(0x00000000, verdex_ram + PXA2XX_INTERNAL_SIZE, + pflash_table[0], 128 * 1024, 256, 2, 0, 0, 0, 0)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + exit(1); + } + + cpu->env->regs[15] = 0x00000000; + + /* Interrupt line of NIC is connected to GPIO line 99 */ + smc91c111_init(&nd_table[0], 0x04000300, + pxa2xx_gpio_in_get(cpu->gpio)[99]); } QEMUMachine connex_machine = { @@ -70,3 +119,9 @@ QEMUMachine connex_machine = { "Gumstix Connex (PXA255)", connex_init, }; + +QEMUMachine verdex_machine = { + "verdex", + "Gumstix Verdex (PXA270)", + verdex_init, +}; diff --git a/vl.c b/vl.c index 1a7f4a34c..d36253647 100644 --- a/vl.c +++ b/vl.c @@ -7450,6 +7450,7 @@ static void register_machines(void) qemu_register_machine(&lm3s811evb_machine); qemu_register_machine(&lm3s6965evb_machine); qemu_register_machine(&connex_machine); + qemu_register_machine(&verdex_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); qemu_register_machine(&r2d_machine); -- cgit v1.2.3 From c81b74018df51d5e04fad731d1e159e524189e44 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 24 Nov 2007 23:55:52 +0000 Subject: Fix SD init arguments. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3733 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx_mmci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 32b6a6f1a..60e7ba4ef 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -538,7 +538,7 @@ struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base, cpu_register_physical_memory(base, 0x00100000, iomemtype); /* Instantiate the actual storage */ - s->card = sd_init(bd, 1); + s->card = sd_init(bd, 0); register_savevm("pxa2xx_mmci", 0, 0, pxa2xx_mmci_save, pxa2xx_mmci_load, s); -- cgit v1.2.3 From 1fc678cc72d7ba572fe1ac55dc2f711e77357e54 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 25 Nov 2007 00:29:23 +0000 Subject: Fix board init arg list (spotted by pbrook), clean-up NOR flash parameters. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3734 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/gumstix.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/gumstix.c b/hw/gumstix.c index 5ef1fb7cf..15562b7b0 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -39,9 +39,10 @@ #include "devices.h" #include "boards.h" +static const int sector_len = 128 * 1024; + static void connex_init(int ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, - const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { @@ -64,8 +65,9 @@ static void connex_init(int ram_size, int vga_ram_size, exit(1); } - if (!pflash_register(0x00000000, connex_ram + PXA2XX_INTERNAL_SIZE, - pflash_table[0], 128 * 1024, 128, 2, 0, 0, 0, 0)) { + if (!pflash_register(0x00000000, qemu_ram_alloc(connex_rom), + pflash_table[0], sector_len, connex_rom / sector_len, + 2, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); exit(1); } @@ -93,7 +95,7 @@ static void verdex_init(int ram_size, int vga_ram_size, exit(1); } - cpu = pxa270_init(verdex_ram, ds, "pxa270-c0"); + cpu = pxa270_init(verdex_ram, ds, cpu_model ?: "pxa270-c0"); if (pflash_table[0] == NULL) { fprintf(stderr, "A flash image must be given with the " @@ -101,8 +103,9 @@ static void verdex_init(int ram_size, int vga_ram_size, exit(1); } - if (!pflash_register(0x00000000, verdex_ram + PXA2XX_INTERNAL_SIZE, - pflash_table[0], 128 * 1024, 256, 2, 0, 0, 0, 0)) { + if (!pflash_register(0x00000000, qemu_ram_alloc(verdex_rom), + pflash_table[0], sector_len, verdex_rom / sector_len, + 2, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); exit(1); } -- cgit v1.2.3 From bd9bdce694ccb76facc882363e4c337e8a88c918 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 25 Nov 2007 00:55:06 +0000 Subject: Add input buffer to mux chr (patch by Tristan Gingold). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3735 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mcf_uart.c | 1 + hw/pl011.c | 1 + hw/serial.c | 1 + hw/slavio_serial.c | 1 + qemu-char.h | 2 ++ vl.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 46 insertions(+), 3 deletions(-) diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c index 01973a02f..a65cc772c 100644 --- a/hw/mcf_uart.c +++ b/hw/mcf_uart.c @@ -88,6 +88,7 @@ uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr) if (s->fifo_len == 0) s->sr &= ~MCF_UART_RxRDY; mcf_uart_update(s); + qemu_chr_accept_input(s->chr); return val; } case 0x10: diff --git a/hw/pl011.c b/hw/pl011.c index 91c52cc31..9d8c6a3f5 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -78,6 +78,7 @@ static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) if (s->read_count == s->read_trigger - 1) s->int_level &= ~ PL011_INT_RX; pl011_update(s); + qemu_chr_accept_input(s->chr); return c; case 1: /* UARTCR */ return 0; diff --git a/hw/serial.c b/hw/serial.c index c5d9db5fa..b1bd0ff36 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -223,6 +223,7 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) ret = s->rbr; s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); serial_update_irq(s); + qemu_chr_accept_input(s->chr); } break; case 1: diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 534a438a1..9a8e34015 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -475,6 +475,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) else ret = s->rx; SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret); + qemu_chr_accept_input(s->chr); return ret; default: break; diff --git a/qemu-char.h b/qemu-char.h index 5a36a3683..29de03df5 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -40,6 +40,7 @@ struct CharDriverState { void *handler_opaque; void (*chr_send_event)(struct CharDriverState *chr, int event); void (*chr_close)(struct CharDriverState *chr); + void (*chr_accept_input)(struct CharDriverState *chr); void *opaque; int focus; QEMUBH *bh; @@ -59,6 +60,7 @@ int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); void qemu_chr_reset(CharDriverState *s); int qemu_chr_can_read(CharDriverState *s); void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); +void qemu_chr_accept_input(CharDriverState *s); /* async I/O support */ diff --git a/vl.c b/vl.c index d36253647..2ed7aecff 100644 --- a/vl.c +++ b/vl.c @@ -1594,6 +1594,11 @@ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) s->chr_read(s->handler_opaque, buf, len); } +void qemu_chr_accept_input(CharDriverState *s) +{ + if (s->chr_accept_input) + s->chr_accept_input(s); +} void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) { @@ -1645,12 +1650,17 @@ static CharDriverState *qemu_chr_open_null(void) static int term_timestamps; static int64_t term_timestamps_start; #define MAX_MUX 4 +#define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ +#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1) typedef struct { IOCanRWHandler *chr_can_read[MAX_MUX]; IOReadHandler *chr_read[MAX_MUX]; IOEventHandler *chr_event[MAX_MUX]; void *ext_opaque[MAX_MUX]; CharDriverState *drv; + unsigned char buffer[MUX_BUFFER_SIZE]; + int prod; + int cons; int mux_cnt; int term_got_escape; int max_size; @@ -1779,12 +1789,28 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) return 0; } +static void mux_chr_accept_input(CharDriverState *chr) +{ + int m = chr->focus; + MuxDriver *d = chr->opaque; + + while (d->prod != d->cons && + d->chr_can_read[m] && + d->chr_can_read[m](d->ext_opaque[m])) { + d->chr_read[m](d->ext_opaque[m], + &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1); + } +} + static int mux_chr_can_read(void *opaque) { CharDriverState *chr = opaque; MuxDriver *d = chr->opaque; + + if ((d->prod - d->cons) < MUX_BUFFER_SIZE) + return 1; if (d->chr_can_read[chr->focus]) - return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); + return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]); return 0; } @@ -1792,10 +1818,20 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size) { CharDriverState *chr = opaque; MuxDriver *d = chr->opaque; + int m = chr->focus; int i; + + mux_chr_accept_input (opaque); + for(i = 0; i < size; i++) - if (mux_proc_byte(chr, d, buf[i])) - d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1); + if (mux_proc_byte(chr, d, buf[i])) { + if (d->prod == d->cons && + d->chr_can_read[m] && + d->chr_can_read[m](d->ext_opaque[m])) + d->chr_read[m](d->ext_opaque[m], &buf[i], 1); + else + d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i]; + } } static void mux_chr_event(void *opaque, int event) @@ -1850,6 +1886,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) chr->focus = -1; chr->chr_write = mux_chr_write; chr->chr_update_read_handler = mux_chr_update_read_handler; + chr->chr_accept_input = mux_chr_accept_input; return chr; } -- cgit v1.2.3 From ef056e439847457a5e64f134b8835e61ff53951b Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 25 Nov 2007 01:57:38 +0000 Subject: Intel Mainstone II (ARM) machine by Armin Kuster. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3736 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/boards.h | 3 + hw/mainstone.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 1 + 4 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 hw/mainstone.c diff --git a/Makefile.target b/Makefile.target index 33921c5aa..c486d501f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -496,7 +496,7 @@ VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o VL_OBJS+= pflash_cfi01.o gumstix.o -VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o +VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o mainstone.o VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o VL_OBJS+= palm.o tsc210x.o CPPFLAGS += -DHAS_AUDIO diff --git a/hw/boards.h b/hw/boards.h index 3decd04d4..6374dd1b2 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -93,4 +93,7 @@ extern QEMUMachine mcf5208evb_machine; /* dummy_m68k.c */ extern QEMUMachine dummy_m68k_machine; +/* mainstone.c */ +extern QEMUMachine mainstone2_machine; + #endif diff --git a/hw/mainstone.c b/hw/mainstone.c new file mode 100644 index 000000000..274cbffb5 --- /dev/null +++ b/hw/mainstone.c @@ -0,0 +1,307 @@ +/* + * PXA270-based Intel Mainstone platforms. + * + * Copyright (c) 2007 by Armin Kuster or + * + * + * Code based on spitz platform by Andrzej Zaborowski + * + * This code is licensed under the GNU GPL v2. + */ +#include "hw.h" +#include "pxa.h" +#include "arm-misc.h" +#include "sysemu.h" +#include "net.h" +#include "devices.h" +#include "boards.h" + +#define MST_ETH_PHYS 0x10000300 +#define MST_FPGA_PHYS 0x08000000 + +/* Mainstone FPGA for extern irqs */ +#define FPGA_GPIO_PIN 0 +#define MST_NUM_IRQS 16 +#define MST_BASE MST_FPGA_PHYS +#define MST_LEDDAT1 0x10 +#define MST_LEDDAT2 0x14 +#define MST_LEDCTRL 0x40 +#define MST_GPSWR 0x60 +#define MST_MSCWR1 0x80 +#define MST_MSCWR2 0x84 +#define MST_MSCWR3 0x88 +#define MST_MSCRD 0x90 +#define MST_INTMSKENA 0xc0 +#define MST_INTSETCLR 0xd0 +#define MST_PCMCIA0 0xe0 +#define MST_PCMCIA1 0xe4 + +/* IRQ definitions */ +#define ETHERNET_IRQ 3 + +typedef struct mst_irq_state { + target_phys_addr_t target_base; + qemu_irq *parent; + qemu_irq *pins; + + uint32_t prev_level; + uint32_t leddat1; + uint32_t leddat2; + uint32_t ledctrl; + uint32_t gpswr; + uint32_t mscwr1; + uint32_t mscwr2; + uint32_t mscwr3; + uint32_t mscrd; + uint32_t intmskena; + uint32_t intsetclr; + uint32_t pcmcia0; + uint32_t pcmcia1; +} mst_irq_state; + +static void +mst_fpga_update_gpio(mst_irq_state *s) +{ + uint32_t level, diff; + int bit; + level = s->prev_level ^ s->intsetclr; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + qemu_set_irq(s->pins[bit], (level >> bit) & 1 ); + } + s->prev_level = level; +} + +static void +mst_fpga_set_irq(void *opaque, int irq, int level) +{ + mst_irq_state *s = (mst_irq_state *)opaque; + + if (level) + s->prev_level |= 1u << irq; + else + s->prev_level &= ~(1u << irq); + + if(s->intmskena & (1u << irq)) { + s->intsetclr = 1u << irq; + qemu_set_irq(s->parent[0], level); + } +} + +static uint32_t +mst_fpga_readb(void *opaque, target_phys_addr_t addr) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + addr -= s->target_base; + + switch (addr) { + case MST_LEDDAT1: + return s->leddat1; + case MST_LEDDAT2: + return s->leddat2; + case MST_LEDCTRL: + return s->ledctrl; + case MST_GPSWR: + return s->gpswr; + case MST_MSCWR1: + return s->mscwr1; + case MST_MSCWR2: + return s->mscwr2; + case MST_MSCWR3: + return s->mscwr3; + case MST_MSCRD: + return s->mscrd; + case MST_INTMSKENA: + return s->intmskena; + case MST_INTSETCLR: + return s->intsetclr; + case MST_PCMCIA0: + return s->pcmcia0; + case MST_PCMCIA1: + return s->pcmcia1; + default: + printf("Mainstone - mst_fpga_readb: Bad register offset " + REG_FMT " \n", addr); + } + return 0; +} + +static void +mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + addr -= s->target_base; + value &= 0xffffffff; + + switch (addr) { + case MST_LEDDAT1: + s->leddat1 = value; + break; + case MST_LEDDAT2: + s->leddat2 = value; + break; + case MST_LEDCTRL: + s->ledctrl = value; + break; + case MST_GPSWR: + s->gpswr = value; + break; + case MST_MSCWR1: + s->mscwr1 = value; + break; + case MST_MSCWR2: + s->mscwr2 = value; + break; + case MST_MSCWR3: + s->mscwr3 = value; + break; + case MST_MSCRD: + s->mscrd = value; + break; + case MST_INTMSKENA: /* Mask interupt */ + s->intmskena = (value & 0xFEEFF); + mst_fpga_update_gpio(s); + break; + case MST_INTSETCLR: /* clear or set interrupt */ + s->intsetclr = (value & 0xFEEFF); + break; + case MST_PCMCIA0: + s->pcmcia0 = value; + break; + case MST_PCMCIA1: + s->pcmcia1 = value; + break; + default: + printf("Mainstone - mst_fpga_writeb: Bad register offset " + REG_FMT " \n", addr); + } +} + +CPUReadMemoryFunc *mst_fpga_readfn[] = { + mst_fpga_readb, + mst_fpga_readb, + mst_fpga_readb, +}; +CPUWriteMemoryFunc *mst_fpga_writefn[] = { + mst_fpga_writeb, + mst_fpga_writeb, + mst_fpga_writeb, +}; + +static void +mst_fpga_save(QEMUFile *f, void *opaque) +{ + struct mst_irq_state *s = (mst_irq_state *) opaque; + + qemu_put_be32s(f, &s->prev_level); + qemu_put_be32s(f, &s->leddat1); + qemu_put_be32s(f, &s->leddat2); + qemu_put_be32s(f, &s->ledctrl); + qemu_put_be32s(f, &s->gpswr); + qemu_put_be32s(f, &s->mscwr1); + qemu_put_be32s(f, &s->mscwr2); + qemu_put_be32s(f, &s->mscwr3); + qemu_put_be32s(f, &s->mscrd); + qemu_put_be32s(f, &s->intmskena); + qemu_put_be32s(f, &s->intsetclr); + qemu_put_be32s(f, &s->pcmcia0); + qemu_put_be32s(f, &s->pcmcia1); +} + +static int +mst_fpga_load(QEMUFile *f, void *opaque, int version_id) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + + qemu_get_be32s(f, &s->prev_level); + qemu_get_be32s(f, &s->leddat1); + qemu_get_be32s(f, &s->leddat2); + qemu_get_be32s(f, &s->ledctrl); + qemu_get_be32s(f, &s->gpswr); + qemu_get_be32s(f, &s->mscwr1); + qemu_get_be32s(f, &s->mscwr2); + qemu_get_be32s(f, &s->mscwr3); + qemu_get_be32s(f, &s->mscrd); + qemu_get_be32s(f, &s->intmskena); + qemu_get_be32s(f, &s->intsetclr); + qemu_get_be32s(f, &s->pcmcia0); + qemu_get_be32s(f, &s->pcmcia1); + return 0; +} + +static qemu_irq +*mst_irq_init(struct pxa2xx_state_s *cpu, uint32_t base, int irq) +{ + mst_irq_state *s; + int iomemtype; + qemu_irq *qi; + + s = (mst_irq_state *) qemu_mallocz(sizeof(mst_irq_state)); + + if (!s) + return NULL; + s->target_base = base; + s->parent = &cpu->pic[irq]; + + /* alloc the external 16 irqs */ + qi = qemu_allocate_irqs(mst_fpga_set_irq, s, MST_NUM_IRQS); + s->pins = qi; + + iomemtype = cpu_register_io_memory(0, mst_fpga_readfn, + mst_fpga_writefn, s); + cpu_register_physical_memory(MST_BASE, 0x00100000, iomemtype); + register_savevm("mainstone_fpga", 0, 0, mst_fpga_save, mst_fpga_load, s); + return qi; +} + +enum mainstone_model_e { mainstone }; + +static void mainstone_common_init(int ram_size, int vga_ram_size, + DisplayState *ds, const char *kernel_filename, + const char *kernel_cmdline, const char *initrd_filename, + const char *cpu_model, enum mainstone_model_e model, int arm_id) +{ + uint32_t mainstone_ram = 0x04000000; + uint32_t mainstone_rom = 0x00800000; + struct pxa2xx_state_s *cpu; + qemu_irq *mst_irq; + + if (!cpu_model) + cpu_model = "pxa270-c5"; + + /* Setup CPU & memory */ + if (ram_size < mainstone_ram + mainstone_rom + PXA2XX_INTERNAL_SIZE) { + fprintf(stderr, "This platform requires %i bytes of memory\n", + mainstone_ram + mainstone_rom + PXA2XX_INTERNAL_SIZE); + exit(1); + } + + cpu = pxa270_init(mainstone_ram, ds, cpu_model); + cpu_register_physical_memory(0, mainstone_rom, + qemu_ram_alloc(mainstone_rom) | IO_MEM_ROM); + + /* Setup initial (reset) machine state */ + cpu->env->regs[15] = PXA2XX_SDRAM_BASE; + + mst_irq = mst_irq_init(cpu, MST_BASE, PXA2XX_PIC_GPIO_0); + smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); + + arm_load_kernel(cpu->env, mainstone_ram, kernel_filename, kernel_cmdline, + initrd_filename, arm_id, PXA2XX_SDRAM_BASE); +} + +static void mainstone_init(int ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + mainstone_common_init(ram_size, vga_ram_size, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196); +} + +QEMUMachine mainstone2_machine = { + "mainstone", + "Mainstone II (PXA27x)", + mainstone_init, +}; diff --git a/vl.c b/vl.c index 2ed7aecff..f24c9670a 100644 --- a/vl.c +++ b/vl.c @@ -7488,6 +7488,7 @@ static void register_machines(void) qemu_register_machine(&lm3s6965evb_machine); qemu_register_machine(&connex_machine); qemu_register_machine(&verdex_machine); + qemu_register_machine(&mainstone2_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); qemu_register_machine(&r2d_machine); -- cgit v1.2.3 From b76482e76560345c00e7d6c89199ced204a926d2 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 25 Nov 2007 08:48:16 +0000 Subject: Fix buffer mux handling for unconnected serial ports git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3737 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 9a8e34015..6705d4429 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -475,7 +475,8 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) else ret = s->rx; SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret); - qemu_chr_accept_input(s->chr); + if (s->chr) + qemu_chr_accept_input(s->chr); return ret; default: break; -- cgit v1.2.3 From 3dd9a152e1776c8a99cf5030a2a89db642d6ef43 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 25 Nov 2007 12:43:10 +0000 Subject: More MMU registers (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3738 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/cpu.h | 2 +- target-sparc/op_helper.c | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 23f9ab136..319e6e896 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -215,7 +215,7 @@ typedef struct CPUSPARCState { uint64_t dtlb_tag[64]; uint64_t dtlb_tte[64]; #else - uint32_t mmuregs[16]; + uint32_t mmuregs[32]; uint64_t mxccdata[4]; uint64_t mxccregs[8]; #endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index d22b2e8d3..c643bdb36 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -248,11 +248,15 @@ void helper_ld_asi(int asi, int size, int sign) break; case 4: /* read MMU regs */ { - int reg = (T0 >> 8) & 0xf; + int reg = (T0 >> 8) & 0x1f; ret = env->mmuregs[reg]; if (reg == 3) /* Fault status cleared on read */ - env->mmuregs[reg] = 0; + env->mmuregs[3] = 0; + else if (reg == 0x13) /* Fault status read */ + ret = env->mmuregs[3]; + else if (reg == 0x14) /* Fault address read */ + ret = env->mmuregs[4]; DPRINTF_MMU("mmu_read: reg[%d] = 0x%08x\n", reg, ret); } break; @@ -493,17 +497,18 @@ void helper_st_asi(int asi, int size) } case 4: /* write MMU regs */ { - int reg = (T0 >> 8) & 0xf; + int reg = (T0 >> 8) & 0x1f; uint32_t oldreg; oldreg = env->mmuregs[reg]; switch(reg) { case 0: - env->mmuregs[reg] &= ~(MMU_E | MMU_NF | env->mmu_bm); - env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF | env->mmu_bm); + env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | + (T1 & 0x00ffffff); // Mappings generated during no-fault mode or MMU // disabled mode are invalid in normal mode - if (oldreg != env->mmuregs[reg]) + if ((oldreg & (MMU_E | MMU_NF | env->mmu_bm)) != + (env->mmuregs[reg] & (MMU_E | MMU_NF | env->mmu_bm))) tlb_flush(env, 1); break; case 2: @@ -517,6 +522,12 @@ void helper_st_asi(int asi, int size) case 3: case 4: break; + case 0x13: + env->mmuregs[3] = T1; + break; + case 0x14: + env->mmuregs[4] = T1; + break; default: env->mmuregs[reg] = T1; break; -- cgit v1.2.3 From 5cc9878d3d5b98e2b51f8296bb1f87c970aa0866 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 25 Nov 2007 12:44:08 +0000 Subject: Set initial value of AFSR register properly (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3739 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/iommu.c b/hw/iommu.c index adc3bc015..76259bbc6 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -311,6 +311,7 @@ static void iommu_reset(void *opaque) s->iostart = 0; s->regs[IOMMU_CTRL] = s->version; s->regs[IOMMU_ARBEN] = IOMMU_MID; + s->regs[IOMMU_AFSR] = 0x00800000; } void *iommu_init(target_phys_addr_t addr, uint32_t version) -- cgit v1.2.3 From 1f587329169765299448c1becd6a633a204ead29 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 25 Nov 2007 18:40:20 +0000 Subject: 128-bit float support for user mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3740 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 30 +++++ fpu/softfloat.c | 44 ++++++ fpu/softfloat.h | 2 + qemu-tech.texi | 3 +- target-sparc/cpu.h | 3 + target-sparc/exec.h | 19 +++ target-sparc/fop_template.h | 47 +++++++ target-sparc/op.c | 166 +++++++++++++++++++++++ target-sparc/op_helper.c | 39 ++++++ target-sparc/op_mem.h | 22 +++ target-sparc/translate.c | 318 +++++++++++++++++++++++++++++++++++++++++--- 11 files changed, 676 insertions(+), 17 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index f4db59234..6b7843509 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -135,6 +135,36 @@ typedef union { uint64_t ll; } CPU_DoubleU; +#ifdef TARGET_SPARC +typedef union { + float128 q; +#if defined(WORDS_BIGENDIAN) \ + || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) + struct { + uint32_t upmost; + uint32_t upper; + uint32_t lower; + uint32_t lowest; + } l; + struct { + uint64_t upper; + uint64_t lower; + } ll; +#else + struct { + uint32_t lowest; + uint32_t lower; + uint32_t upper; + uint32_t upmost; + } l; + struct { + uint64_t lower; + uint64_t upper; + } ll; +#endif +} CPU_QuadU; +#endif + /* CPU memory access without any memory or io remapping */ /* diff --git a/fpu/softfloat.c b/fpu/softfloat.c index e30f22f91..3ec1e0de1 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5421,6 +5421,50 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ COMPARE(32, 0xff) COMPARE(64, 0x7ff) +INLINE int float128_compare_internal( float128 a, float128 b, + int is_quiet STATUS_PARAM ) +{ + flag aSign, bSign; + + if (( ( extractFloat128Exp( a ) == 0x7fff ) && + ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || + ( ( extractFloat128Exp( b ) == 0x7fff ) && + ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) { + if (!is_quiet || + float128_is_signaling_nan( a ) || + float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return float_relation_unordered; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) { + /* zero case */ + return float_relation_equal; + } else { + return 1 - (2 * aSign); + } + } else { + if (a.low == b.low && a.high == b.high) { + return float_relation_equal; + } else { + return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) )); + } + } +} + +int float128_compare( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 0 STATUS_VAR); +} + +int float128_compare_quiet( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 1 STATUS_VAR); +} + /* Multiply A by 2 raised to the power N. */ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) { diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 84cffdd5d..5f95d061e 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -415,6 +415,8 @@ int float128_lt( float128, float128 STATUS_PARAM ); int float128_eq_signaling( float128, float128 STATUS_PARAM ); int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_compare( float128, float128 STATUS_PARAM ); +int float128_compare_quiet( float128, float128 STATUS_PARAM ); int float128_is_nan( float128 ); int float128_is_signaling_nan( float128 ); float128 float128_scalbn( float128, int STATUS_PARAM ); diff --git a/qemu-tech.texi b/qemu-tech.texi index 9147096d9..cc027cf6a 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -212,8 +212,7 @@ Current QEMU limitations: @item IPC syscalls are missing. -@item 128-bit floating point operations are not supported, though none of the -real CPUs implement them either. Floating point exception support is untested. +@item Floating point exception support is buggy. @item Atomic instructions are not correctly implemented. diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 319e6e896..783a850c6 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -222,6 +222,9 @@ typedef struct CPUSPARCState { /* temporary float registers */ float32 ft0, ft1; float64 dt0, dt1; +#if defined(CONFIG_USER_ONLY) + float128 qt0, qt1; +#endif float_status fp_status; #if defined(TARGET_SPARC64) #define MAXTL 4 diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 81c4741be..db19da6f6 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -41,6 +41,10 @@ register uint32_t T2 asm(AREG3); #define FT1 (env->ft1) #define DT0 (env->dt0) #define DT1 (env->dt1) +#if defined(CONFIG_USER_ONLY) +#define QT0 (env->qt0) +#define QT1 (env->qt1) +#endif #include "cpu.h" #include "exec-all.h" @@ -65,6 +69,13 @@ void do_fcmps(void); void do_fcmpd(void); void do_fcmpes(void); void do_fcmped(void); +#if defined(CONFIG_USER_ONLY) +void do_fitoq(void); +void do_fabsq(void); +void do_fsqrtq(void); +void do_fcmpq(void); +void do_fcmpeq(void); +#endif #ifdef TARGET_SPARC64 void do_fabsd(void); void do_fcmps_fcc1(void); @@ -79,6 +90,14 @@ void do_fcmpes_fcc2(void); void do_fcmped_fcc2(void); void do_fcmpes_fcc3(void); void do_fcmped_fcc3(void); +#if defined(CONFIG_USER_ONLY) +void do_fcmpq_fcc1(void); +void do_fcmpq_fcc2(void); +void do_fcmpq_fcc3(void); +void do_fcmpeq_fcc1(void); +void do_fcmpeq_fcc2(void); +void do_fcmpeq_fcc3(void); +#endif void do_popc(); void do_wrpstate(); void do_done(); diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h index 0598b3020..0c045b835 100644 --- a/target-sparc/fop_template.h +++ b/target-sparc/fop_template.h @@ -77,5 +77,52 @@ void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void) *p = u.l.upper; } +#if defined(CONFIG_USER_ONLY) +/* quad floating point registers moves */ +void OPPROTO glue(op_load_fpr_QT0_fpr, REGNAME)(void) +{ + CPU_QuadU u; + uint32_t *p = (uint32_t *)® + u.l.lowest = *(p + 3); + u.l.lower = *(p + 2); + u.l.upper = *(p + 1); + u.l.upmost = *p; + QT0 = u.q; +} + +void OPPROTO glue(op_store_QT0_fpr_fpr, REGNAME)(void) +{ + CPU_QuadU u; + uint32_t *p = (uint32_t *)® + u.q = QT0; + *(p + 3) = u.l.lowest; + *(p + 2) = u.l.lower; + *(p + 1) = u.l.upper; + *p = u.l.upmost; +} + +void OPPROTO glue(op_load_fpr_QT1_fpr, REGNAME)(void) +{ + CPU_QuadU u; + uint32_t *p = (uint32_t *)® + u.l.lowest = *(p + 3); + u.l.lower = *(p + 2); + u.l.upper = *(p + 1); + u.l.upmost = *p; + QT1 = u.q; +} + +void OPPROTO glue(op_store_QT1_fpr_fpr, REGNAME)(void) +{ + CPU_QuadU u; + uint32_t *p = (uint32_t *)® + u.q = QT1; + *(p + 3) = u.l.lowest; + *(p + 2) = u.l.lower; + *(p + 1) = u.l.upper; + *p = u.l.upmost; +} +#endif + #undef REG #undef REGNAME diff --git a/target-sparc/op.c b/target-sparc/op.c index 55ea2b9fe..1fb48cfd6 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1581,6 +1581,7 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void) #define F_OP(name, p) void OPPROTO op_f##name##p(void) +#if defined(CONFIG_USER_ONLY) #define F_BINOP(name) \ F_OP(name, s) \ { \ @@ -1593,7 +1594,28 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void) set_float_exception_flags(0, &env->fp_status); \ DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ check_ieee_exceptions(); \ + } \ + F_OP(name, q) \ + { \ + set_float_exception_flags(0, &env->fp_status); \ + QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ + check_ieee_exceptions(); \ } +#else +#define F_BINOP(name) \ + F_OP(name, s) \ + { \ + set_float_exception_flags(0, &env->fp_status); \ + FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \ + check_ieee_exceptions(); \ + } \ + F_OP(name, d) \ + { \ + set_float_exception_flags(0, &env->fp_status); \ + DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ + check_ieee_exceptions(); \ + } +#endif F_BINOP(add); F_BINOP(sub); @@ -1610,6 +1632,18 @@ void OPPROTO op_fsmuld(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fdmulq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status), + float64_to_float128(DT1, &env->fp_status), + &env->fp_status); + check_ieee_exceptions(); +} +#endif + +#if defined(CONFIG_USER_ONLY) #define F_HELPER(name) \ F_OP(name, s) \ { \ @@ -1618,7 +1652,22 @@ void OPPROTO op_fsmuld(void) F_OP(name, d) \ { \ do_f##name##d(); \ + } \ + F_OP(name, q) \ + { \ + do_f##name##q(); \ } +#else +#define F_HELPER(name) \ + F_OP(name, s) \ + { \ + do_f##name##s(); \ + } \ + F_OP(name, d) \ + { \ + do_f##name##d(); \ + } +#endif F_HELPER(sqrt); @@ -1646,6 +1695,18 @@ F_OP(abs, d) do_fabsd(); } +#if defined(CONFIG_USER_ONLY) +F_OP(neg, q) +{ + QT0 = float128_chs(QT1); +} + +F_OP(abs, q) +{ + do_fabsd(); +} +#endif + void OPPROTO op_fcmps_fcc1(void) { do_fcmps_fcc1(); @@ -1706,6 +1767,38 @@ void OPPROTO op_fcmped_fcc3(void) do_fcmped_fcc3(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fcmpq_fcc1(void) +{ + do_fcmpq_fcc1(); +} + +void OPPROTO op_fcmpq_fcc2(void) +{ + do_fcmpq_fcc2(); +} + +void OPPROTO op_fcmpq_fcc3(void) +{ + do_fcmpq_fcc3(); +} + +void OPPROTO op_fcmpeq_fcc1(void) +{ + do_fcmpeq_fcc1(); +} + +void OPPROTO op_fcmpeq_fcc2(void) +{ + do_fcmpeq_fcc2(); +} + +void OPPROTO op_fcmpeq_fcc3(void) +{ + do_fcmpeq_fcc3(); +} +#endif + #endif /* Integer to float conversion. */ @@ -1729,6 +1822,15 @@ F_OP(ito, d) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +F_OP(ito, q) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status); + check_ieee_exceptions(); +} +#endif + #ifdef TARGET_SPARC64 F_OP(xto, s) { @@ -1743,6 +1845,14 @@ F_OP(xto, d) DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +F_OP(xto, q) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status); + check_ieee_exceptions(); +} +#endif #endif #endif #undef F_HELPER @@ -1762,6 +1872,36 @@ void OPPROTO op_fstod(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fqtos(void) +{ + set_float_exception_flags(0, &env->fp_status); + FT0 = float128_to_float32(QT1, &env->fp_status); + check_ieee_exceptions(); +} + +void OPPROTO op_fstoq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = float32_to_float128(FT1, &env->fp_status); + check_ieee_exceptions(); +} + +void OPPROTO op_fqtod(void) +{ + set_float_exception_flags(0, &env->fp_status); + DT0 = float128_to_float64(QT1, &env->fp_status); + check_ieee_exceptions(); +} + +void OPPROTO op_fdtoq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = float64_to_float128(DT1, &env->fp_status); + check_ieee_exceptions(); +} +#endif + /* Float to integer conversion. */ void OPPROTO op_fstoi(void) { @@ -1777,6 +1917,15 @@ void OPPROTO op_fdtoi(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fqtoi(void) +{ + set_float_exception_flags(0, &env->fp_status); + *((int32_t *)&FT0) = float128_to_int32_round_to_zero(QT1, &env->fp_status); + check_ieee_exceptions(); +} +#endif + #ifdef TARGET_SPARC64 void OPPROTO op_fstox(void) { @@ -1792,6 +1941,15 @@ void OPPROTO op_fdtox(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fqtox(void) +{ + set_float_exception_flags(0, &env->fp_status); + *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status); + check_ieee_exceptions(); +} +#endif + void OPPROTO op_fmovs_cc(void) { if (T2) @@ -1804,6 +1962,14 @@ void OPPROTO op_fmovd_cc(void) DT0 = DT1; } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fmovq_cc(void) +{ + if (T2) + QT0 = QT1; +} +#endif + void OPPROTO op_mov_cc(void) { if (T2) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index c643bdb36..48f5fc600 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -97,6 +97,13 @@ void do_fabsd(void) { DT0 = float64_abs(DT1); } + +#if defined(CONFIG_USER_ONLY) +void do_fabsq(void) +{ + QT0 = float128_abs(QT1); +} +#endif #endif void do_fsqrts(void) @@ -113,6 +120,15 @@ void do_fsqrtd(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void do_fsqrtq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = float128_sqrt(QT1, &env->fp_status); + check_ieee_exceptions(); +} +#endif + #define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \ void glue(do_, name) (void) \ { \ @@ -148,6 +164,11 @@ GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1); GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); +#ifdef CONFIG_USER_ONLY +GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0); +GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1); +#endif + #ifdef TARGET_SPARC64 GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0); GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); @@ -166,6 +187,14 @@ GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); +#ifdef CONFIG_USER_ONLY +GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0); +GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0); +GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0); +GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1); +GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1); +GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1); +#endif #endif #ifndef TARGET_SPARC64 @@ -1374,6 +1403,11 @@ void helper_ldf_asi(int asi, int size, int rd) case 8: *((int64_t *)&DT0) = T1; break; +#if defined(CONFIG_USER_ONLY) + case 16: + // XXX + break; +#endif } T1 = tmp_T1; } @@ -1417,6 +1451,11 @@ void helper_stf_asi(int asi, int size, int rd) case 8: T1 = *((int64_t *)&DT0); break; +#if defined(CONFIG_USER_ONLY) + case 16: + // XXX + break; +#endif } helper_st_asi(asi, size); T1 = tmp_T1; diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 4af00b371..894fc3666 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -85,6 +85,28 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (void) DT0 = glue(ldfq, MEMSUFFIX)(ADDR(T0)); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO glue(op_ldqf, MEMSUFFIX) (void) +{ + // XXX add 128 bit load + CPU_QuadU u; + + u.ll.upper = glue(ldq, MEMSUFFIX)(ADDR(T0)); + u.ll.lower = glue(ldq, MEMSUFFIX)(ADDR(T0 + 8)); + QT0 = u.q; +} + +void OPPROTO glue(op_stqf, MEMSUFFIX) (void) +{ + // XXX add 128 bit store + CPU_QuadU u; + + u.q = QT0; + glue(stq, MEMSUFFIX)(ADDR(T0), u.ll.upper); + glue(stq, MEMSUFFIX)(ADDR(T0 + 8), u.ll.lower); +} +#endif + #ifdef TARGET_SPARC64 void OPPROTO glue(op_lduw, MEMSUFFIX)(void) { diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 1e373cea3..7dee0adb1 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -25,7 +25,6 @@ Rest of V9 instructions, VIS instructions NPC/PC static optimisations (use JUMP_TB when possible) Optimize synthetic instructions - 128-bit float */ #include @@ -93,8 +92,10 @@ enum { #ifdef TARGET_SPARC64 #define DFPREG(r) (((r & 1) << 5) | (r & 0x1e)) +#define QFPREG(r) (((r & 1) << 5) | (r & 0x1c)) #else #define DFPREG(r) (r & 0x1e) +#define QFPREG(r) (r & 0x1c) #endif #ifdef USE_DIRECT_JUMP @@ -351,6 +352,13 @@ GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); +#if defined(CONFIG_USER_ONLY) +GEN32(gen_op_load_fpr_QT0, gen_op_load_fpr_QT0_fprf); +GEN32(gen_op_load_fpr_QT1, gen_op_load_fpr_QT1_fprf); +GEN32(gen_op_store_QT0_fpr, gen_op_store_QT0_fpr_fprf); +GEN32(gen_op_store_QT1_fpr, gen_op_store_QT1_fpr_fprf); +#endif + /* moves */ #ifdef CONFIG_USER_ONLY #define supervisor(dc) 0 @@ -1060,6 +1068,15 @@ static GenOpFunc * const gen_fcmpd[4] = { gen_op_fcmpd_fcc3, }; +#if defined(CONFIG_USER_ONLY) +static GenOpFunc * const gen_fcmpq[4] = { + gen_op_fcmpq, + gen_op_fcmpq_fcc1, + gen_op_fcmpq_fcc2, + gen_op_fcmpq_fcc3, +}; +#endif + static GenOpFunc * const gen_fcmpes[4] = { gen_op_fcmpes, gen_op_fcmpes_fcc1, @@ -1074,6 +1091,14 @@ static GenOpFunc * const gen_fcmped[4] = { gen_op_fcmped_fcc3, }; +#if defined(CONFIG_USER_ONLY) +static GenOpFunc * const gen_fcmpeq[4] = { + gen_op_fcmpeq, + gen_op_fcmpeq_fcc1, + gen_op_fcmpeq_fcc2, + gen_op_fcmpeq_fcc3, +}; +#endif #endif static int gen_trap_ifnofpu(DisasContext * dc) @@ -1484,7 +1509,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x2b: /* fsqrtq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fsqrtq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x41: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1498,7 +1530,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x43: /* faddq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_faddq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x45: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1512,7 +1552,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x47: /* fsubq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fsubq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x49: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1526,7 +1574,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x4b: /* fmulq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fmulq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x4d: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1540,7 +1596,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x4f: /* fdivq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fdivq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x69: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1548,7 +1612,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x6e: /* fdmulq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fdmulq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xc4: gen_op_load_fpr_FT1(rs2); gen_op_fitos(); @@ -1560,7 +1632,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0xc7: /* fqtos */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fqtos(); + gen_op_store_FT0_fpr(rd); + break; +#else goto nfpu_insn; +#endif case 0xc8: gen_op_load_fpr_FT1(rs2); gen_op_fitod(); @@ -1572,13 +1651,41 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0xcb: /* fqtod */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fqtod(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xcc: /* fitoq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_FT1(rs2); + gen_op_fitoq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xcd: /* fstoq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_FT1(rs2); + gen_op_fstoq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xce: /* fdtoq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fdtoq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xd1: gen_op_load_fpr_FT1(rs2); gen_op_fstoi(); @@ -1590,22 +1697,55 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0xd3: /* fqtoi */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fqtoi(); + gen_op_store_FT0_fpr(rd); + break; +#else goto nfpu_insn; +#endif #ifdef TARGET_SPARC64 case 0x2: /* V9 fmovd */ gen_op_load_fpr_DT0(DFPREG(rs2)); gen_op_store_DT0_fpr(DFPREG(rd)); break; + case 0x3: /* V9 fmovq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs2)); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else + goto nfpu_insn; +#endif case 0x6: /* V9 fnegd */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fnegd(); gen_op_store_DT0_fpr(DFPREG(rd)); break; + case 0x7: /* V9 fnegq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fnegq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else + goto nfpu_insn; +#endif case 0xa: /* V9 fabsd */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fabsd(); gen_op_store_DT0_fpr(DFPREG(rd)); break; + case 0xb: /* V9 fabsq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fabsq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else + goto nfpu_insn; +#endif case 0x81: /* V9 fstox */ gen_op_load_fpr_FT1(rs2); gen_op_fstox(); @@ -1616,6 +1756,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fdtox(); gen_op_store_DT0_fpr(DFPREG(rd)); break; + case 0x83: /* V9 fqtox */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fqtox(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; +#else + goto nfpu_insn; +#endif case 0x84: /* V9 fxtos */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fxtos(); @@ -1626,12 +1775,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fxtod(); gen_op_store_DT0_fpr(DFPREG(rd)); break; - case 0x3: /* V9 fmovq */ - case 0x7: /* V9 fnegq */ - case 0xb: /* V9 fabsq */ - case 0x83: /* V9 fqtox */ case 0x8c: /* V9 fxtoq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fxtoq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif #endif default: goto illegal_insn; @@ -1670,7 +1822,20 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + flush_T2(dc); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + gen_cond_reg(cond); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif } #endif switch (xop) { @@ -1694,7 +1859,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x003: /* V9 fmovqcc %fcc0 */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + flush_T2(dc); + gen_fcond[0][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x041: /* V9 fmovscc %fcc1 */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1714,7 +1890,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x043: /* V9 fmovqcc %fcc1 */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + flush_T2(dc); + gen_fcond[1][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x081: /* V9 fmovscc %fcc2 */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1734,7 +1921,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x083: /* V9 fmovqcc %fcc2 */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(rd); + gen_op_load_fpr_QT1(rs2); + flush_T2(dc); + gen_fcond[2][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(rd); + break; +#else goto nfpu_insn; +#endif case 0x0c1: /* V9 fmovscc %fcc3 */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1754,7 +1952,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x0c3: /* V9 fmovqcc %fcc3 */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + flush_T2(dc); + gen_fcond[3][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x101: /* V9 fmovscc %icc */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1774,7 +1983,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x103: /* V9 fmovqcc %icc */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(rd); + gen_op_load_fpr_QT1(rs2); + flush_T2(dc); + gen_cond[0][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(rd); + break; +#else goto nfpu_insn; +#endif case 0x181: /* V9 fmovscc %xcc */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1794,9 +2014,20 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x183: /* V9 fmovqcc %xcc */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(rd); + gen_op_load_fpr_QT1(rs2); + flush_T2(dc); + gen_cond[1][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(rd); + break; +#else goto nfpu_insn; #endif - case 0x51: /* V9 %fcc */ +#endif + case 0x51: /* fcmps, V9 %fcc */ gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); #ifdef TARGET_SPARC64 @@ -1805,7 +2036,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fcmps(); #endif break; - case 0x52: /* V9 %fcc */ + case 0x52: /* fcmpd, V9 %fcc */ gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); #ifdef TARGET_SPARC64 @@ -1814,8 +2045,19 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fcmpd(); #endif break; - case 0x53: /* fcmpq */ + case 0x53: /* fcmpq, V9 %fcc */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); +#ifdef TARGET_SPARC64 + gen_fcmpq[rd & 3](); +#else + gen_op_fcmpq(); +#endif + break; +#else /* !defined(CONFIG_USER_ONLY) */ goto nfpu_insn; +#endif case 0x55: /* fcmpes, V9 %fcc */ gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1834,8 +2076,19 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fcmped(); #endif break; - case 0x57: /* fcmpeq */ + case 0x57: /* fcmpeq, V9 %fcc */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); +#ifdef TARGET_SPARC64 + gen_fcmpeq[rd & 3](); +#else + gen_op_fcmpeq(); +#endif + break; +#else/* !defined(CONFIG_USER_ONLY) */ goto nfpu_insn; +#endif default: goto illegal_insn; } @@ -3095,7 +3348,13 @@ static void disas_sparc_insn(DisasContext * dc) case 0x3d: /* V9 prefetcha, no effect */ goto skip_move; case 0x32: /* V9 ldqfa */ +#if defined(CONFIG_USER_ONLY) + gen_op_check_align_T0_3(); + gen_ldf_asi(insn, 16); + goto skip_move; +#else goto nfpu_insn; +#endif #endif default: goto illegal_insn; @@ -3119,7 +3378,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldfsr(); break; case 0x22: /* load quad fpreg */ +#if defined(CONFIG_USER_ONLY) + gen_op_check_align_T0_7(); + gen_op_ldst(ldqf); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x23: /* load double fpreg */ gen_op_check_align_T0_7(); gen_op_ldst(lddf); @@ -3225,13 +3491,28 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_stfsr(); gen_op_ldst(stf); break; -#if !defined(CONFIG_USER_ONLY) - case 0x26: /* stdfq */ + case 0x26: +#ifdef TARGET_SPARC64 +#if defined(CONFIG_USER_ONLY) + /* V9 stqf, store quad fpreg */ + gen_op_check_align_T0_7(); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_ldst(stqf); + break; +#else + goto nfpu_insn; +#endif +#else /* !TARGET_SPARC64 */ + /* stdfq, store floating point queue */ +#if defined(CONFIG_USER_ONLY) + goto illegal_insn; +#else if (!supervisor(dc)) goto priv_insn; if (gen_trap_ifnofpu(dc)) goto jmp_insn; goto nfq_insn; +#endif #endif case 0x27: gen_op_check_align_T0_7(); @@ -3249,6 +3530,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_FT0(rd); gen_stf_asi(insn, 4); break; + case 0x36: /* V9 stqfa */ +#if defined(CONFIG_USER_ONLY) + gen_op_check_align_T0_7(); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_stf_asi(insn, 16); + break; +#else + goto nfpu_insn; +#endif case 0x37: /* V9 stdfa */ gen_op_check_align_T0_3(); gen_op_load_fpr_DT0(DFPREG(rd)); @@ -3268,8 +3558,6 @@ static void disas_sparc_insn(DisasContext * dc) gen_casx_asi(insn); gen_movl_T1_reg(rd); break; - case 0x36: /* V9 stqfa */ - goto nfpu_insn; #else case 0x34: /* stc */ case 0x35: /* stcsr */ @@ -3311,19 +3599,19 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_exception(TT_PRIV_INSN); dc->is_br = 1; return; -#endif nfpu_insn: save_state(dc); gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); dc->is_br = 1; return; -#if !defined(CONFIG_USER_ONLY) +#ifndef TARGET_SPARC64 nfq_insn: save_state(dc); gen_op_fpexception_im(FSR_FTT_SEQ_ERROR); dc->is_br = 1; return; #endif +#endif #ifndef TARGET_SPARC64 ncp_insn: save_state(dc); -- cgit v1.2.3 From 8ef6367ea928725652bde4cbde0a94d0b29fe773 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 25 Nov 2007 18:46:17 +0000 Subject: Scale TSC2102 touchscreen pressure value more realistically (still could be better). PalmOS 5.2.1 now fully boots. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3741 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mainstone.c | 1 - hw/omap.c | 2 +- hw/sd.c | 2 +- hw/tsc210x.c | 14 +++++++++----- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/hw/mainstone.c b/hw/mainstone.c index 274cbffb5..d6ce4ffe0 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -11,7 +11,6 @@ #include "hw.h" #include "pxa.h" #include "arm-misc.h" -#include "sysemu.h" #include "net.h" #include "devices.h" #include "boards.h" diff --git a/hw/omap.c b/hw/omap.c index a873b5fe5..c8d5064f6 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -4809,7 +4809,6 @@ static void omap_mpu_reset(void *opaque) { struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; - omap_clkm_reset(mpu); omap_inth_reset(mpu->ih[0]); omap_inth_reset(mpu->ih[1]); omap_dma_reset(mpu->dma); @@ -4843,6 +4842,7 @@ static void omap_mpu_reset(void *opaque) omap_mcbsp_reset(mpu->mcbsp3); omap_lpg_reset(mpu->led[0]); omap_lpg_reset(mpu->led[1]); + omap_clkm_reset(mpu); cpu_reset(mpu->env); } diff --git a/hw/sd.c b/hw/sd.c index fc3c45a83..93ad3dab8 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -397,7 +397,7 @@ static void sd_cardchange(void *opaque) } /* We do not model the chip select pin, so allow the board to select - whether card should be in SSI ot MMC/SD mode. It is also up to the + whether card should be in SSI or MMC/SD mode. It is also up to the board to ensure that ssi transfers only occur when the chip select is asserted. */ SDState *sd_init(BlockDriverState *bs, int is_spi) diff --git a/hw/tsc210x.c b/hw/tsc210x.c index 6082aa0b9..96956a47d 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -130,9 +130,10 @@ static const uint16_t mode_regs[16] = { #define Y_TRANSFORM(value) \ ((150 + ((int) (value) * (3037 - 150) / 32768)) << 4) #define Z1_TRANSFORM(s) \ - ((400 - (s)->x + ((s)->pressure << 9)) << 4) + ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) #define Z2_TRANSFORM(s) \ - ((4000 + (s)->y - ((s)->pressure << 10)) << 4) + ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4) + #define BAT1_VAL 0x8660 #define BAT2_VAL 0x0000 #define AUX1_VAL 0x35c0 @@ -367,7 +368,8 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) case 0x05: /* BAT1 */ s->dav &= 0xffbf; - return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision); + return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) + + (s->noise & 6); case 0x06: /* BAT2 */ s->dav &= 0xffdf; @@ -383,11 +385,13 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) case 0x09: /* TEMP1 */ s->dav &= 0xfffb; - return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision); + return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) - + (s->noise & 5); case 0x0a: /* TEMP2 */ s->dav &= 0xfffd; - return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision); + return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^ + (s->noise & 3); case 0x0b: /* DAC */ s->dav &= 0xfffe; -- cgit v1.2.3 From 2382dc6b9b1bd130f16330965a9163681e786cd9 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 25 Nov 2007 20:27:35 +0000 Subject: Fix floating point register decoding git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3742 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/translate.c | 280 +++++++++++++++++++++++------------------------ 1 file changed, 139 insertions(+), 141 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 7dee0adb1..37a0d2963 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -440,11 +440,10 @@ static inline void gen_st_asi(int insn, int size) } } -static inline void gen_ldf_asi(int insn, int size) +static inline void gen_ldf_asi(int insn, int size, int rd) { - int asi, offset, rd; + int asi, offset; - rd = DFPREG(GET_FIELD(insn, 2, 6)); if (IS_IMM) { offset = GET_FIELD(insn, 25, 31); gen_op_ldf_asi_reg(offset, size, rd); @@ -454,11 +453,10 @@ static inline void gen_ldf_asi(int insn, int size) } } -static inline void gen_stf_asi(int insn, int size) +static inline void gen_stf_asi(int insn, int size, int rd) { - int asi, offset, rd; + int asi, offset; - rd = DFPREG(GET_FIELD(insn, 2, 6)); if (IS_IMM) { offset = GET_FIELD(insn, 25, 31); gen_op_stf_asi_reg(offset, size, rd); @@ -1571,7 +1569,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmuld(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x4b: /* fmulq */ #if defined(CONFIG_USER_ONLY) @@ -1692,7 +1690,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0xd2: - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fdtoi(); gen_op_store_FT0_fpr(rd); break; @@ -1812,14 +1810,14 @@ static void disas_sparc_insn(DisasContext * dc) break; } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_op_load_fpr_DT1(DFPREG(rs2)); flush_T2(dc); rs1 = GET_FIELD(insn, 13, 17); gen_movl_reg_T0(rs1); gen_cond_reg(cond); gen_op_fmovs_cc(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr #if defined(CONFIG_USER_ONLY) @@ -1851,12 +1849,12 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x002: /* V9 fmovdcc %fcc0 */ cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_op_load_fpr_DT1(DFPREG(rs2)); flush_T2(dc); gen_fcond[0][cond](); gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x003: /* V9 fmovqcc %fcc0 */ #if defined(CONFIG_USER_ONLY) @@ -1882,12 +1880,12 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x042: /* V9 fmovdcc %fcc1 */ cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_op_load_fpr_DT1(DFPREG(rs2)); flush_T2(dc); gen_fcond[1][cond](); gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x043: /* V9 fmovqcc %fcc1 */ #if defined(CONFIG_USER_ONLY) @@ -1913,12 +1911,12 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x082: /* V9 fmovdcc %fcc2 */ cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_op_load_fpr_DT1(DFPREG(rs2)); flush_T2(dc); gen_fcond[2][cond](); gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x083: /* V9 fmovqcc %fcc2 */ #if defined(CONFIG_USER_ONLY) @@ -1944,12 +1942,12 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x0c2: /* V9 fmovdcc %fcc3 */ cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_op_load_fpr_DT1(DFPREG(rs2)); flush_T2(dc); gen_fcond[3][cond](); gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x0c3: /* V9 fmovqcc %fcc3 */ #if defined(CONFIG_USER_ONLY) @@ -1975,12 +1973,12 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x102: /* V9 fmovdcc %icc */ cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_op_load_fpr_DT1(DFPREG(rs2)); flush_T2(dc); gen_cond[0][cond](); gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x103: /* V9 fmovqcc %icc */ #if defined(CONFIG_USER_ONLY) @@ -2006,12 +2004,12 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x182: /* V9 fmovdcc %xcc */ cond = GET_FIELD_SP(insn, 14, 17); - gen_op_load_fpr_DT0(rd); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_op_load_fpr_DT1(DFPREG(rs2)); flush_T2(dc); gen_cond[1][cond](); gen_op_fmovd_cc(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x183: /* V9 fmovqcc %xcc */ #if defined(CONFIG_USER_ONLY) @@ -2668,94 +2666,94 @@ static void disas_sparc_insn(DisasContext * dc) // XXX goto illegal_insn; case 0x020: /* VIS I fcmple16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fcmple16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x022: /* VIS I fcmpne16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fcmpne16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x024: /* VIS I fcmple32 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fcmple32(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x026: /* VIS I fcmpne32 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fcmpne32(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x028: /* VIS I fcmpgt16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fcmpgt16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x02a: /* VIS I fcmpeq16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fcmpeq16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x02c: /* VIS I fcmpgt32 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fcmpgt32(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x02e: /* VIS I fcmpeq32 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fcmpeq32(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x031: /* VIS I fmul8x16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmul8x16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x033: /* VIS I fmul8x16au */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmul8x16au(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x035: /* VIS I fmul8x16al */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmul8x16al(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x036: /* VIS I fmul8sux16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmul8sux16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x037: /* VIS I fmul8ulx16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmul8ulx16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x038: /* VIS I fmuld8sux16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmuld8sux16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x039: /* VIS I fmuld8ulx16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fmuld8ulx16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x03a: /* VIS I fpack32 */ case 0x03b: /* VIS I fpack16 */ @@ -2764,31 +2762,31 @@ static void disas_sparc_insn(DisasContext * dc) // XXX goto illegal_insn; case 0x048: /* VIS I faligndata */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_faligndata(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x04b: /* VIS I fpmerge */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fpmerge(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x04c: /* VIS II bshuffle */ // XXX goto illegal_insn; case 0x04d: /* VIS I fexpand */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fexpand(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x050: /* VIS I fpadd16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fpadd16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x051: /* VIS I fpadd16s */ gen_op_load_fpr_FT0(rs1); @@ -2797,10 +2795,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x052: /* VIS I fpadd32 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fpadd32(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x053: /* VIS I fpadd32s */ gen_op_load_fpr_FT0(rs1); @@ -2809,10 +2807,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x054: /* VIS I fpsub16 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fpsub16(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x055: /* VIS I fpsub16s */ gen_op_load_fpr_FT0(rs1); @@ -2821,10 +2819,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x056: /* VIS I fpsub32 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fpadd32(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x057: /* VIS I fpsub32s */ gen_op_load_fpr_FT0(rs1); @@ -2834,17 +2832,17 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x060: /* VIS I fzero */ gen_op_movl_DT0_0(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x061: /* VIS I fzeros */ gen_op_movl_FT0_0(); gen_op_store_FT0_fpr(rd); break; case 0x062: /* VIS I fnor */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fnor(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x063: /* VIS I fnors */ gen_op_load_fpr_FT0(rs1); @@ -2853,10 +2851,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x064: /* VIS I fandnot2 */ - gen_op_load_fpr_DT1(rs1); - gen_op_load_fpr_DT0(rs2); + gen_op_load_fpr_DT1(DFPREG(rs1)); + gen_op_load_fpr_DT0(DFPREG(rs2)); gen_op_fandnot(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x065: /* VIS I fandnot2s */ gen_op_load_fpr_FT1(rs1); @@ -2865,9 +2863,9 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x066: /* VIS I fnot2 */ - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fnot(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x067: /* VIS I fnot2s */ gen_op_load_fpr_FT1(rs2); @@ -2875,10 +2873,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x068: /* VIS I fandnot1 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fandnot(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x069: /* VIS I fandnot1s */ gen_op_load_fpr_FT0(rs1); @@ -2887,9 +2885,9 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x06a: /* VIS I fnot1 */ - gen_op_load_fpr_DT1(rs1); + gen_op_load_fpr_DT1(DFPREG(rs1)); gen_op_fnot(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x06b: /* VIS I fnot1s */ gen_op_load_fpr_FT1(rs1); @@ -2897,10 +2895,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x06c: /* VIS I fxor */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fxor(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x06d: /* VIS I fxors */ gen_op_load_fpr_FT0(rs1); @@ -2909,10 +2907,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x06e: /* VIS I fnand */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fnand(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x06f: /* VIS I fnands */ gen_op_load_fpr_FT0(rs1); @@ -2921,10 +2919,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x070: /* VIS I fand */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fand(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x071: /* VIS I fands */ gen_op_load_fpr_FT0(rs1); @@ -2933,10 +2931,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x072: /* VIS I fxnor */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fxnor(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x073: /* VIS I fxnors */ gen_op_load_fpr_FT0(rs1); @@ -2945,18 +2943,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x074: /* VIS I fsrc1 */ - gen_op_load_fpr_DT0(rs1); - gen_op_store_DT0_fpr(rd); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x075: /* VIS I fsrc1s */ gen_op_load_fpr_FT0(rs1); gen_op_store_FT0_fpr(rd); break; case 0x076: /* VIS I fornot2 */ - gen_op_load_fpr_DT1(rs1); - gen_op_load_fpr_DT0(rs2); + gen_op_load_fpr_DT1(DFPREG(rs1)); + gen_op_load_fpr_DT0(DFPREG(rs2)); gen_op_fornot(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x077: /* VIS I fornot2s */ gen_op_load_fpr_FT1(rs1); @@ -2965,18 +2963,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x078: /* VIS I fsrc2 */ - gen_op_load_fpr_DT0(rs2); - gen_op_store_DT0_fpr(rd); + gen_op_load_fpr_DT0(DFPREG(rs2)); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x079: /* VIS I fsrc2s */ gen_op_load_fpr_FT0(rs2); gen_op_store_FT0_fpr(rd); break; case 0x07a: /* VIS I fornot1 */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fornot(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x07b: /* VIS I fornot1s */ gen_op_load_fpr_FT0(rs1); @@ -2985,10 +2983,10 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0x07c: /* VIS I for */ - gen_op_load_fpr_DT0(rs1); - gen_op_load_fpr_DT1(rs2); + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_for(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x07d: /* VIS I fors */ gen_op_load_fpr_FT0(rs1); @@ -2998,7 +2996,7 @@ static void disas_sparc_insn(DisasContext * dc) break; case 0x07e: /* VIS I fone */ gen_op_movl_DT0_1(); - gen_op_store_DT0_fpr(rd); + gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x07f: /* VIS I fones */ gen_op_movl_FT0_1(); @@ -3339,18 +3337,18 @@ static void disas_sparc_insn(DisasContext * dc) goto skip_move; case 0x30: /* V9 ldfa */ gen_op_check_align_T0_3(); - gen_ldf_asi(insn, 4); + gen_ldf_asi(insn, 4, rd); goto skip_move; case 0x33: /* V9 lddfa */ gen_op_check_align_T0_3(); - gen_ldf_asi(insn, 8); + gen_ldf_asi(insn, 8, DFPREG(rd)); goto skip_move; case 0x3d: /* V9 prefetcha, no effect */ goto skip_move; case 0x32: /* V9 ldqfa */ #if defined(CONFIG_USER_ONLY) gen_op_check_align_T0_3(); - gen_ldf_asi(insn, 16); + gen_ldf_asi(insn, 16, QFPREG(rd)); goto skip_move; #else goto nfpu_insn; @@ -3528,13 +3526,13 @@ static void disas_sparc_insn(DisasContext * dc) case 0x34: /* V9 stfa */ gen_op_check_align_T0_3(); gen_op_load_fpr_FT0(rd); - gen_stf_asi(insn, 4); + gen_stf_asi(insn, 4, rd); break; case 0x36: /* V9 stqfa */ #if defined(CONFIG_USER_ONLY) gen_op_check_align_T0_7(); gen_op_load_fpr_QT0(QFPREG(rd)); - gen_stf_asi(insn, 16); + gen_stf_asi(insn, 16, QFPREG(rd)); break; #else goto nfpu_insn; @@ -3542,7 +3540,7 @@ static void disas_sparc_insn(DisasContext * dc) case 0x37: /* V9 stdfa */ gen_op_check_align_T0_3(); gen_op_load_fpr_DT0(DFPREG(rd)); - gen_stf_asi(insn, 8); + gen_stf_asi(insn, 8, DFPREG(rd)); break; case 0x3c: /* V9 casa */ gen_op_check_align_T0_3(); -- cgit v1.2.3 From ae2dbf7fb04194c367c3352f716715bb569602ed Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 26 Nov 2007 09:01:34 +0000 Subject: Micro-optimize back-to-back store-load sequences. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3743 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/translate.c | 238 +++++++++++++++++++++++++++--------------------- 1 file changed, 135 insertions(+), 103 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 55e6290f3..c909463da 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -543,6 +543,8 @@ typedef struct DisasContext { uint32_t hflags, saved_hflags; int bstate; target_ulong btarget; + void *last_T0_store; + int last_T0_gpr; } DisasContext; enum { @@ -572,12 +574,33 @@ do { \ ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \ } while (0) -#define GEN_LOAD_REG_TN(Tn, Rn) \ +#define GEN_LOAD_REG_T0(Rn) \ do { \ if (Rn == 0) { \ - glue(gen_op_reset_, Tn)(); \ + gen_op_reset_T0(); \ + } else { \ + if (ctx->glue(last_T0, _store) != gen_opc_ptr \ + || ctx->glue(last_T0, _gpr) != Rn) { \ + gen_op_load_gpr_T0(Rn); \ + } \ + } \ +} while (0) + +#define GEN_LOAD_REG_T1(Rn) \ +do { \ + if (Rn == 0) { \ + gen_op_reset_T1(); \ + } else { \ + gen_op_load_gpr_T1(Rn); \ + } \ +} while (0) + +#define GEN_LOAD_REG_T2(Rn) \ +do { \ + if (Rn == 0) { \ + gen_op_reset_T2(); \ } else { \ - glue(gen_op_load_gpr_, Tn)(Rn); \ + gen_op_load_gpr_T2(Rn); \ } \ } while (0) @@ -612,13 +635,21 @@ do { \ } while (0) #endif -#define GEN_STORE_TN_REG(Rn, Tn) \ +#define GEN_STORE_T0_REG(Rn) \ do { \ if (Rn != 0) { \ - glue(glue(gen_op_store_, Tn),_gpr)(Rn); \ + glue(gen_op_store_T0,_gpr)(Rn); \ + ctx->glue(last_T0,_store) = gen_opc_ptr; \ + ctx->glue(last_T0,_gpr) = Rn; \ } \ } while (0) +#define GEN_STORE_T1_REG(Rn) \ +do { \ + if (Rn != 0) \ + glue(gen_op_store_T1,_gpr)(Rn); \ +} while (0) + #define GEN_STORE_TN_SRSREG(Rn, Tn) \ do { \ if (Rn != 0) { \ @@ -855,126 +886,126 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, #if defined(TARGET_MIPS64) case OPC_LWU: op_ldst(lwu); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "lwu"; break; case OPC_LD: op_ldst(ld); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "ld"; break; case OPC_LLD: op_ldst(lld); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "lld"; break; case OPC_SD: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(sd); opn = "sd"; break; case OPC_SCD: save_cpu_state(ctx, 1); - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(scd); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "scd"; break; case OPC_LDL: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(ldl); - GEN_STORE_TN_REG(rt, T1); + GEN_STORE_T1_REG(rt); opn = "ldl"; break; case OPC_SDL: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(sdl); opn = "sdl"; break; case OPC_LDR: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(ldr); - GEN_STORE_TN_REG(rt, T1); + GEN_STORE_T1_REG(rt); opn = "ldr"; break; case OPC_SDR: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(sdr); opn = "sdr"; break; #endif case OPC_LW: op_ldst(lw); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "lw"; break; case OPC_SW: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(sw); opn = "sw"; break; case OPC_LH: op_ldst(lh); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "lh"; break; case OPC_SH: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(sh); opn = "sh"; break; case OPC_LHU: op_ldst(lhu); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "lhu"; break; case OPC_LB: op_ldst(lb); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "lb"; break; case OPC_SB: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(sb); opn = "sb"; break; case OPC_LBU: op_ldst(lbu); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "lbu"; break; case OPC_LWL: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(lwl); - GEN_STORE_TN_REG(rt, T1); + GEN_STORE_T1_REG(rt); opn = "lwl"; break; case OPC_SWL: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(swl); opn = "swr"; break; case OPC_LWR: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(lwr); - GEN_STORE_TN_REG(rt, T1); + GEN_STORE_T1_REG(rt); opn = "lwr"; break; case OPC_SWR: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(swr); opn = "swr"; break; case OPC_LL: op_ldst(ll); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "ll"; break; case OPC_SC: save_cpu_state(ctx, 1); - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); op_ldst(sc); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "sc"; break; default: @@ -1059,7 +1090,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, case OPC_ANDI: case OPC_ORI: case OPC_XORI: - GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_T0(rs); GEN_LOAD_IMM_TN(T1, uimm); break; case OPC_LUI: @@ -1077,7 +1108,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, case OPC_DSRL32: #endif uimm &= 0x1f; - GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_T0(rs); GEN_LOAD_IMM_TN(T1, uimm); break; } @@ -1222,7 +1253,7 @@ static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc, generate_exception(ctx, EXCP_RI); return; } - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm); } @@ -1239,14 +1270,14 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, MIPS_DEBUG("NOP"); return; } - GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_T0(rs); /* Specialcase the conventional move operation. */ if (rt == 0 && (opc == OPC_ADDU || opc == OPC_DADDU || opc == OPC_SUBU || opc == OPC_DSUBU)) { - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_T0_REG(rd); return; } - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); switch (opc) { case OPC_ADD: save_cpu_state(ctx, 1); @@ -1389,7 +1420,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc, generate_exception(ctx, EXCP_RI); return; } - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_T0_REG(rd); print: MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]); } @@ -1407,21 +1438,21 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) switch (opc) { case OPC_MFHI: gen_op_load_HI(0); - GEN_STORE_TN_REG(reg, T0); + GEN_STORE_T0_REG(reg); opn = "mfhi"; break; case OPC_MFLO: gen_op_load_LO(0); - GEN_STORE_TN_REG(reg, T0); + GEN_STORE_T0_REG(reg); opn = "mflo"; break; case OPC_MTHI: - GEN_LOAD_REG_TN(T0, reg); + GEN_LOAD_REG_T0(reg); gen_op_store_HI(0); opn = "mthi"; break; case OPC_MTLO: - GEN_LOAD_REG_TN(T0, reg); + GEN_LOAD_REG_T0(reg); gen_op_store_LO(0); opn = "mtlo"; break; @@ -1438,8 +1469,8 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { const char *opn = "mul/div"; - GEN_LOAD_REG_TN(T0, rs); - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T0(rs); + GEN_LOAD_REG_T1(rt); switch (opc) { case OPC_DIV: gen_op_div(); @@ -1508,7 +1539,7 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, MIPS_DEBUG("NOP"); return; } - GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_T0(rs); switch (opc) { case OPC_CLO: gen_op_clo(); @@ -1554,8 +1585,8 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, case OPC_TNE: /* Compare two registers */ if (rs != rt) { - GEN_LOAD_REG_TN(T0, rs); - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T0(rs); + GEN_LOAD_REG_T1(rt); cond = 1; } break; @@ -1567,7 +1598,7 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, case OPC_TNEI: /* Compare register to immediate */ if (rs != 0 || imm != 0) { - GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_T0(rs); GEN_LOAD_IMM_TN(T1, (int32_t)imm); cond = 1; } @@ -1680,8 +1711,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BNEL: /* Compare two registers */ if (rs != rt) { - GEN_LOAD_REG_TN(T0, rs); - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T0(rs); + GEN_LOAD_REG_T1(rt); bcond = 1; } btarget = ctx->pc + 4 + offset; @@ -1720,7 +1751,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, generate_exception(ctx, EXCP_RI); return; } - GEN_LOAD_REG_TN(T2, rs); + GEN_LOAD_REG_T2(rs); break; default: MIPS_INVAL("branch/jump"); @@ -1896,7 +1927,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, int rs, int lsb, int msb) { - GEN_LOAD_REG_TN(T1, rs); + GEN_LOAD_REG_T1(rs); switch (opc) { case OPC_EXT: if (lsb + msb > 31) @@ -1923,26 +1954,26 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, case OPC_INS: if (lsb > msb) goto fail; - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_op_ins(lsb, msb - lsb + 1); break; #if defined(TARGET_MIPS64) case OPC_DINSM: if (lsb > msb) goto fail; - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_op_dins(lsb, msb - lsb + 1 + 32); break; case OPC_DINSU: if (lsb > msb) goto fail; - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_op_dins(lsb + 32, msb - lsb + 1); break; case OPC_DINS: if (lsb > msb) goto fail; - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_op_dins(lsb, msb - lsb + 1); break; #endif @@ -1952,7 +1983,7 @@ fail: generate_exception(ctx, EXCP_RI); return; } - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); } /* CP0 (MMU and control) */ @@ -4611,7 +4642,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int opn = "mfc0"; break; case OPC_MTC0: - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); save_cpu_state(ctx, 1); gen_mtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "mtc0"; @@ -4629,7 +4660,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; case OPC_DMTC0: check_insn(env, ctx, ISA_MIPS3); - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); save_cpu_state(ctx, 1); gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7); opn = "dmtc0"; @@ -4648,7 +4679,7 @@ static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int break; case OPC_MTTR: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1, ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); opn = "mttr"; @@ -4789,33 +4820,33 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) case OPC_MFC1: GEN_LOAD_FREG_FTN(WT0, fs); gen_op_mfc1(); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "mfc1"; break; case OPC_MTC1: - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_op_mtc1(); GEN_STORE_FTN_FREG(fs, WT0); opn = "mtc1"; break; case OPC_CFC1: gen_op_cfc1(fs); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "cfc1"; break; case OPC_CTC1: - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_op_ctc1(fs); opn = "ctc1"; break; case OPC_DMFC1: GEN_LOAD_FREG_FTN(DT0, fs); gen_op_dmfc1(); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "dmfc1"; break; case OPC_DMTC1: - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_op_dmtc1(); GEN_STORE_FTN_FREG(fs, DT0); opn = "dmtc1"; @@ -4823,11 +4854,11 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) case OPC_MFHC1: GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_mfhc1(); - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); opn = "mfhc1"; break; case OPC_MTHC1: - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); gen_op_mthc1(); GEN_STORE_FTN_FREG(fs, WTH0); opn = "mthc1"; @@ -4844,8 +4875,8 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) { uint32_t ccbit; - GEN_LOAD_REG_TN(T0, rd); - GEN_LOAD_REG_TN(T1, rs); + GEN_LOAD_REG_T0(rd); + GEN_LOAD_REG_T1(rs); if (cc) { ccbit = 1 << (24 + cc); } else @@ -4854,7 +4885,7 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) gen_op_movf(ccbit); else gen_op_movt(ccbit); - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_T0_REG(rd); } #define GEN_MOVCF(fmt) \ @@ -5029,7 +5060,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, opn = "floor.w.s"; break; case FOP(17, 16): - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT2, fd); gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1); @@ -5037,7 +5068,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, opn = "movcf.s"; break; case FOP(18, 16): - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT2, fd); gen_op_float_movz_s(); @@ -5045,7 +5076,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, opn = "movz.s"; break; case FOP(19, 16): - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT2, fd); gen_op_float_movn_s(); @@ -5270,7 +5301,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, opn = "floor.w.d"; break; case FOP(17, 17): - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT2, fd); gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1); @@ -5278,7 +5309,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, opn = "movcf.d"; break; case FOP(18, 17): - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT2, fd); gen_op_float_movz_d(); @@ -5286,7 +5317,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, opn = "movz.d"; break; case FOP(19, 17): - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT2, fd); gen_op_float_movn_d(); @@ -5484,7 +5515,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, break; case FOP(17, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT2, fd); @@ -5496,7 +5527,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, break; case FOP(18, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT2, fd); @@ -5508,7 +5539,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, break; case FOP(19, 22): check_cp1_64bitmode(ctx); - GEN_LOAD_REG_TN(T0, ft); + GEN_LOAD_REG_T0(ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT2, fd); @@ -5695,12 +5726,12 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, if (index == 0) gen_op_reset_T0(); else - GEN_LOAD_REG_TN(T0, index); + GEN_LOAD_REG_T0(index); } else if (index == 0) { - GEN_LOAD_REG_TN(T0, base); + GEN_LOAD_REG_T0(base); } else { - GEN_LOAD_REG_TN(T0, base); - GEN_LOAD_REG_TN(T1, index); + GEN_LOAD_REG_T0(base); + GEN_LOAD_REG_T1(index); gen_op_addr_add(); } /* Don't do NOP if destination is zero: we must perform the actual @@ -5757,7 +5788,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, check_cp1_64bitmode(ctx); switch (opc) { case OPC_ALNV_PS: - GEN_LOAD_REG_TN(T0, fr); + GEN_LOAD_REG_T0(fr); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_alnv_ps(); @@ -6081,15 +6112,15 @@ static void decode_opc (CPUState *env, DisasContext *ctx) op2 = MASK_BSHFL(ctx->opcode); switch (op2) { case OPC_WSBH: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); gen_op_wsbh(); break; case OPC_SEB: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); gen_op_seb(); break; case OPC_SEH: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); gen_op_seh(); break; default: /* Invalid */ @@ -6097,7 +6128,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); break; } - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_T0_REG(rd); break; case OPC_RDHWR: check_insn(env, ctx, ISA_MIPS32R2); @@ -6128,19 +6159,19 @@ static void decode_opc (CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); break; } - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); break; case OPC_FORK: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_TN(T0, rt); - GEN_LOAD_REG_TN(T1, rs); + GEN_LOAD_REG_T0(rt); + GEN_LOAD_REG_T1(rs); gen_op_fork(); break; case OPC_YIELD: check_insn(env, ctx, ASE_MT); - GEN_LOAD_REG_TN(T0, rs); + GEN_LOAD_REG_T0(rs); gen_op_yield(); - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_T0_REG(rd); break; #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: @@ -6155,11 +6186,11 @@ static void decode_opc (CPUState *env, DisasContext *ctx) op2 = MASK_DBSHFL(ctx->opcode); switch (op2) { case OPC_DSBH: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); gen_op_dsbh(); break; case OPC_DSHD: - GEN_LOAD_REG_TN(T1, rt); + GEN_LOAD_REG_T1(rt); gen_op_dshd(); break; default: /* Invalid */ @@ -6167,7 +6198,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); break; } - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_T0_REG(rd); break; #endif default: /* Invalid */ @@ -6252,16 +6283,16 @@ static void decode_opc (CPUState *env, DisasContext *ctx) generate_exception(ctx, EXCP_RI); break; } - GEN_STORE_TN_REG(rt, T0); + GEN_STORE_T0_REG(rt); break; case OPC_RDPGPR: check_insn(env, ctx, ISA_MIPS32R2); GEN_LOAD_SRSREG_TN(T0, rt); - GEN_STORE_TN_REG(rd, T0); + GEN_STORE_T0_REG(rd); break; case OPC_WRPGPR: check_insn(env, ctx, ISA_MIPS32R2); - GEN_LOAD_REG_TN(T0, rt); + GEN_LOAD_REG_T0(rt); GEN_STORE_TN_SRSREG(rd, T0); break; default: @@ -6589,6 +6620,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } } done_generating: + ctx.last_T0_store = NULL; *gen_opc_ptr = INDEX_op_end; if (search_pc) { j = gen_opc_ptr - gen_opc_buf; -- cgit v1.2.3 From ded7ba9c75687710d4ca6f0501c403d9bfa84019 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 26 Nov 2007 14:52:02 +0000 Subject: Add floppy support, tested to work with www.linux-mips.org GIT head. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3744 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_malta.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 4d95fbfbf..ac6800f65 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -24,6 +24,7 @@ #include "hw.h" #include "pc.h" +#include "fdc.h" #include "net.h" #include "boards.h" #include "smbus.h" @@ -767,7 +768,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, PCIBus *pci_bus; CPUState *env; RTCState *rtc_state; - /* fdctrl_t *floppy_controller; */ + fdctrl_t *floppy_controller; MaltaFPGAState *malta_fpga; int ret; qemu_irq *i8259; @@ -882,9 +883,7 @@ void mips_malta_init (int ram_size, int vga_ram_size, serial_init(0x2f8, i8259[3], serial_hds[1]); if (parallel_hds[0]) parallel_init(0x378, i8259[7], parallel_hds[0]); - /* XXX: The floppy controller does not work correctly, something is - probably wrong. - floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); */ + floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); /* Sound card */ #ifdef HAS_AUDIO -- cgit v1.2.3 From 66d4557ec6acbb8d56899ea808f246e593686895 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 26 Nov 2007 18:46:38 +0000 Subject: Document -M SS-600MP git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3745 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index fd3ca0c9f..b28a834f0 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2013,7 +2013,7 @@ qemu-system-sparc -prom-env 'auto-boot?=false' \ -prom-env 'boot-device=sd(0,2,0):d' -prom-env 'boot-args=linux single' @end example -@item -M [SS-5|SS-10] +@item -M [SS-5|SS-10|SS-600MP] Set the emulated machine type. Default is SS-5. -- cgit v1.2.3 From 9c2b428ee169dfbc92664f06e466a8bb0f45c702 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 28 Nov 2007 18:08:28 +0000 Subject: Fix compilation and warnings on PPC host git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3746 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 5 ++++- target-sparc/op_helper.c | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index db19da6f6..54c824ee8 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -71,13 +71,14 @@ void do_fcmpes(void); void do_fcmped(void); #if defined(CONFIG_USER_ONLY) void do_fitoq(void); -void do_fabsq(void); void do_fsqrtq(void); void do_fcmpq(void); void do_fcmpeq(void); #endif #ifdef TARGET_SPARC64 void do_fabsd(void); +void do_fxtos(void); +void do_fxtod(void); void do_fcmps_fcc1(void); void do_fcmpd_fcc1(void); void do_fcmps_fcc2(void); @@ -91,6 +92,8 @@ void do_fcmped_fcc2(void); void do_fcmpes_fcc3(void); void do_fcmped_fcc3(void); #if defined(CONFIG_USER_ONLY) +void do_fabsq(void); +void do_fxtoq(void); void do_fcmpq_fcc1(void); void do_fcmpq_fcc2(void); void do_fcmpq_fcc3(void); diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 48f5fc600..a71c9da37 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -70,6 +70,14 @@ void do_fitod(void) { DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); } + +#if defined(CONFIG_USER_ONLY) +void do_fitoq(void) +{ + QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status); +} +#endif + #ifdef TARGET_SPARC64 void do_fxtos(void) { @@ -84,6 +92,15 @@ void do_fxtod(void) DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); check_ieee_exceptions(); } + +#if defined(CONFIG_USER_ONLY) +void do_fxtoq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = int64_to_float128(*((int32_t *)&DT1), &env->fp_status); + check_ieee_exceptions(); +} +#endif #endif #endif -- cgit v1.2.3 From 3ebf5aafe562158b59aff2ee49cbcf54332cbb23 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Wed, 28 Nov 2007 20:54:33 +0000 Subject: Use slavio base as boot prom address, rearrange sun4m init code git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3747 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sun4m.c | 211 ++++++++++++++++++++++++-------------------------- target-sparc/cpu.h | 1 + target-sparc/helper.c | 2 +- 3 files changed, 105 insertions(+), 109 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index e8adc4569..1f78ff893 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -60,7 +60,6 @@ #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 #define PROM_SIZE_MAX (512 * 1024) -#define PROM_PADDR 0xff0000000ULL #define PROM_VADDR 0xffd00000 #define PROM_FILENAME "openbios-sparc32" @@ -81,6 +80,8 @@ struct hwdef { int machine_id; // For NVRAM uint32_t iommu_version; uint32_t intbit_to_level[32]; + uint64_t max_mem; + const char * const default_cpu_model; }; /* TSC handling */ @@ -273,8 +274,59 @@ static void secondary_cpu_reset(void *opaque) env->halted = 1; } -static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, - DisplayState *ds, const char *cpu_model) +static unsigned long sun4m_load_kernel(const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + int linux_boot; + unsigned int i; + long initrd_size, kernel_size; + + linux_boot = (kernel_filename != NULL); + + kernel_size = 0; + if (linux_boot) { + kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL, + NULL); + if (kernel_size < 0) + kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) + kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + + /* load initrd */ + initrd_size = 0; + if (initrd_filename) { + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + if (initrd_size > 0) { + for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { + if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) + == 0x48647253) { // HdrS + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); + stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); + break; + } + } + } + } + return kernel_size; +} + +static void sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, + const char *boot_device, + DisplayState *ds, const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) { CPUState *env, *envs[MAX_CPUS]; @@ -283,8 +335,13 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq, *espdma_irq, *ledma_irq; qemu_irq *esp_reset, *le_reset; + unsigned long prom_offset, kernel_size; + int ret; + char buf[1024]; /* init CPUs */ + if (!cpu_model) + cpu_model = hwdef->default_cpu_model; for(i = 0; i < smp_cpus; i++) { env = cpu_init(cpu_model); @@ -302,14 +359,42 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, } register_savevm("cpu", i, 3, cpu_save, cpu_load, env); cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS); + env->prom_addr = hwdef->slavio_base; } for (i = smp_cpus; i < MAX_CPUS; i++) cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS); + /* allocate RAM */ + if ((uint64_t)RAM_size > hwdef->max_mem) { + fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", + (unsigned int)RAM_size / (1024 * 1024), + (unsigned int)(hwdef->max_mem / (1024 * 1024))); + exit(1); + } cpu_register_physical_memory(0, RAM_size, 0); + /* load boot prom */ + prom_offset = RAM_size + hwdef->vram_size; + cpu_register_physical_memory(hwdef->slavio_base, + (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & + TARGET_PAGE_MASK, + prom_offset | IO_MEM_ROM); + + if (bios_name == NULL) + bios_name = PROM_FILENAME; + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); + ret = load_elf(buf, hwdef->slavio_base - PROM_VADDR, NULL, NULL, NULL); + if (ret < 0 || ret > PROM_SIZE_MAX) + ret = load_image(buf, phys_ram_base + prom_offset); + if (ret < 0 || ret > PROM_SIZE_MAX) { + fprintf(stderr, "qemu: could not load prom '%s'\n", + buf); + exit(1); + } + + /* set up devices */ iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version); slavio_intctl = slavio_intctl_init(hwdef->intctl_base, hwdef->intctl_base + 0x10000ULL, @@ -372,79 +457,12 @@ static void *sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, if (hwdef->cs_base != (target_phys_addr_t)-1) cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl); - return nvram; -} + kernel_size = sun4m_load_kernel(kernel_filename, kernel_cmdline, + initrd_filename); -static void sun4m_load_kernel(long vram_size, int RAM_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - int machine_id, - void *nvram) -{ - int ret, linux_boot; - char buf[1024]; - unsigned int i; - long prom_offset, initrd_size, kernel_size; - - linux_boot = (kernel_filename != NULL); - - prom_offset = RAM_size + vram_size; - cpu_register_physical_memory(PROM_PADDR, - (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, - prom_offset | IO_MEM_ROM); - - if (bios_name == NULL) - bios_name = PROM_FILENAME; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); - ret = load_elf(buf, PROM_PADDR - PROM_VADDR, NULL, NULL, NULL); - if (ret < 0 || ret > PROM_SIZE_MAX) - ret = load_image(buf, phys_ram_base + prom_offset); - if (ret < 0 || ret > PROM_SIZE_MAX) { - fprintf(stderr, "qemu: could not load prom '%s'\n", - buf); - exit(1); - } - - kernel_size = 0; - if (linux_boot) { - kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL, - NULL); - if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) - kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - if (initrd_size > 0) { - for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) - == 0x48647253) { // HdrS - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); - break; - } - } - } - } nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, RAM_size, kernel_size, graphic_width, - graphic_height, graphic_depth, machine_id); + graphic_height, graphic_depth, hwdef->machine_id); } static const struct hwdef hwdefs[] = { @@ -481,6 +499,8 @@ static const struct hwdef hwdefs[] = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, + .max_mem = 0x10000000, + .default_cpu_model = "Fujitsu MB86904", }, /* SS-10 */ { @@ -515,6 +535,8 @@ static const struct hwdef hwdefs[] = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, + .max_mem = 0xffffffff, // XXX actually first 62GB ok + .default_cpu_model = "TI SuperSparc II", }, /* SS-600MP */ { @@ -549,40 +571,19 @@ static const struct hwdef hwdefs[] = { 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, }, + .max_mem = 0xffffffff, // XXX actually first 62GB ok + .default_cpu_model = "TI SuperSparc II", }, }; -static void sun4m_common_init(int RAM_size, const char *boot_device, DisplayState *ds, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model, - unsigned int machine, int max_ram) -{ - void *nvram; - - if ((unsigned int)RAM_size > (unsigned int)max_ram) { - fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n", - (unsigned int)RAM_size / (1024 * 1024), - (unsigned int)max_ram / (1024 * 1024)); - exit(1); - } - nvram = sun4m_hw_init(&hwdefs[machine], RAM_size, ds, cpu_model); - - sun4m_load_kernel(hwdefs[machine].vram_size, RAM_size, boot_device, - kernel_filename, kernel_cmdline, initrd_filename, - hwdefs[machine].machine_id, nvram); -} - /* SPARCstation 5 hardware initialisation */ static void ss5_init(int RAM_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - if (cpu_model == NULL) - cpu_model = "Fujitsu MB86904"; - sun4m_common_init(RAM_size, boot_device, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, - 0, 0x10000000); + sun4m_hw_init(&hwdefs[0], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation 10 hardware initialisation */ @@ -591,11 +592,8 @@ static void ss10_init(int RAM_size, int vga_ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - if (cpu_model == NULL) - cpu_model = "TI SuperSparc II"; - sun4m_common_init(RAM_size, boot_device, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, - 1, 0xffffffff); // XXX actually first 62GB ok + sun4m_hw_init(&hwdefs[1], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); } /* SPARCserver 600MP hardware initialisation */ @@ -604,11 +602,8 @@ static void ss600mp_init(int RAM_size, int vga_ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { - if (cpu_model == NULL) - cpu_model = "TI SuperSparc II"; - sun4m_common_init(RAM_size, boot_device, ds, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, - 2, 0xffffffff); // XXX actually first 62GB ok + sun4m_hw_init(&hwdefs[2], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); } QEMUMachine ss5_machine = { diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 783a850c6..6f95d9469 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -218,6 +218,7 @@ typedef struct CPUSPARCState { uint32_t mmuregs[32]; uint64_t mxccdata[4]; uint64_t mxccregs[8]; + uint64_t prom_addr; #endif /* temporary float registers */ float32 ft0, ft1; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 0ebc365e2..a1daed8b7 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -115,7 +115,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ // Boot mode: instruction fetches are taken from PROM if (rw == 2 && (env->mmuregs[0] & env->mmu_bm)) { - *physical = 0xff0000000ULL | (address & 0x3ffffULL); + *physical = env->prom_addr | (address & 0x3ffffULL); *prot = PAGE_READ | PAGE_EXEC; return 0; } -- cgit v1.2.3 From 58a770f3a4b44d59ea07cfd40a05aa450c045c8f Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Thu, 29 Nov 2007 17:08:01 +0000 Subject: Increase prom size for boot mode git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3748 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index a1daed8b7..894e32628 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -115,7 +115,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ // Boot mode: instruction fetches are taken from PROM if (rw == 2 && (env->mmuregs[0] & env->mmu_bm)) { - *physical = env->prom_addr | (address & 0x3ffffULL); + *physical = env->prom_addr | (address & 0x7ffffULL); *prot = PAGE_READ | PAGE_EXEC; return 0; } -- cgit v1.2.3 From ad8efe4b6e27f0ea87d6510c11ae11377eade93d Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 30 Nov 2007 16:45:21 +0000 Subject: Fix a crash with monitor input arriving before readline_start has been called git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3749 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monitor.c b/monitor.c index 4a9e8bbfa..dd85f847d 100644 --- a/monitor.c +++ b/monitor.c @@ -2583,6 +2583,8 @@ void monitor_init(CharDriverState *hd, int show_banner) hide_banner = !show_banner; qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL); + + readline_start("", 0, monitor_handle_command1, NULL); } /* XXX: use threads ? */ -- cgit v1.2.3 From 2d8ee4e7193806d1c7f6bf2f06af118f9bc2a633 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 1 Dec 2007 08:18:52 +0000 Subject: Fix Sparc host compile problem reported by Shaddy Baddah git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3750 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-alpha/op_helper.c | 17 +++++++++++++++++ target-alpha/op_helper.h | 6 ++++++ target-alpha/op_template.h | 8 ++++++++ 3 files changed, 31 insertions(+) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 9a3009c4d..072499e30 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -1072,6 +1072,23 @@ void helper_mtpr (int iprn) } #endif +#if defined(HOST_SPARC) || defined(HOST_SPARC64) +void helper_reset_FT0 (void) +{ + FT0 = 0; +} + +void helper_reset_FT1 (void) +{ + FT1 = 0; +} + +void helper_reset_FT2 (void) +{ + FT2 = 0; +} +#endif + /*****************************************************************************/ /* Softmmu support */ #if !defined (CONFIG_USER_ONLY) diff --git a/target-alpha/op_helper.h b/target-alpha/op_helper.h index 0c65fd4a3..7e79720bc 100644 --- a/target-alpha/op_helper.h +++ b/target-alpha/op_helper.h @@ -138,3 +138,9 @@ void helper_mtpr (int iprn); void helper_ld_phys_to_virt (void); void helper_st_phys_to_virt (void); void helper_tb_flush (void); + +#if defined(HOST_SPARC) || defined(HOST_SPARC64) +void helper_reset_FT0 (void); +void helper_reset_FT1 (void); +void helper_reset_FT2 (void); +#endif diff --git a/target-alpha/op_template.h b/target-alpha/op_template.h index db15bb891..ab589f21e 100644 --- a/target-alpha/op_template.h +++ b/target-alpha/op_template.h @@ -26,11 +26,19 @@ void OPPROTO glue(op_reset_T, REG) (void) RETURN(); } +#if !defined(HOST_SPARC) && !defined(HOST_SPARC64) void OPPROTO glue(op_reset_FT, REG) (void) { glue(FT, REG) = 0; RETURN(); } +#else +void OPPROTO glue(op_reset_FT, REG) (void) +{ + glue(helper_reset_FT, REG)(); + RETURN(); +} +#endif /* XXX: This can be great on most RISC machines */ #if !defined(__i386__) && !defined(__x86_64__) -- cgit v1.2.3 From 5ad6bb97a4a1fa2f230a28f83b7b8ed85de81c22 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 1 Dec 2007 14:51:23 +0000 Subject: Name the magic constants, wrap long lines git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3751 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 188 +++++++++++++++++++++++++++++++++++++------------------------ hw/iommu.c | 32 +++++++---- 2 files changed, 135 insertions(+), 85 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index d0a01a1a9..b6c58ff71 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -32,8 +32,8 @@ //#define DEBUG_ESP /* - * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), also - * produced as NCR89C100. See + * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), + * also produced as NCR89C100. See * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt * and * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt @@ -81,12 +81,51 @@ struct ESPState { void *dma_opaque; }; +#define ESP_TCLO 0x0 +#define ESP_TCMID 0x1 +#define ESP_FIFO 0x2 +#define ESP_CMD 0x3 +#define ESP_RSTAT 0x4 +#define ESP_WBUSID 0x4 +#define ESP_RINTR 0x5 +#define ESP_WSEL 0x5 +#define ESP_RSEQ 0x6 +#define ESP_WSYNTP 0x6 +#define ESP_RFLAGS 0x7 +#define ESP_WSYNO 0x7 +#define ESP_CFG1 0x8 +#define ESP_RRES1 0x9 +#define ESP_WCCF 0x9 +#define ESP_RRES2 0xa +#define ESP_WTEST 0xa +#define ESP_CFG2 0xb +#define ESP_CFG3 0xc +#define ESP_RES3 0xd +#define ESP_TCHI 0xe +#define ESP_RES4 0xf + +#define CMD_DMA 0x80 +#define CMD_CMD 0x7f + +#define CMD_NOP 0x00 +#define CMD_FLUSH 0x01 +#define CMD_RESET 0x02 +#define CMD_BUSRESET 0x03 +#define CMD_TI 0x10 +#define CMD_ICCS 0x11 +#define CMD_MSGACC 0x12 +#define CMD_SATN 0x1a +#define CMD_SELATN 0x42 +#define CMD_SELATNS 0x43 +#define CMD_ENSEL 0x44 + #define STAT_DO 0x00 #define STAT_DI 0x01 #define STAT_CD 0x02 #define STAT_ST 0x03 #define STAT_MI 0x06 #define STAT_MO 0x07 +#define STAT_PIO_MASK 0x06 #define STAT_TC 0x10 #define STAT_PE 0x20 @@ -101,13 +140,19 @@ struct ESPState { #define SEQ_0 0x0 #define SEQ_CD 0x4 +#define CFG1_RESREPT 0x40 + +#define CFG2_MASK 0x15 + +#define TCHI_FAS100A 0x4 + static int get_cmd(ESPState *s, uint8_t *buf) { uint32_t dmalen; int target; - dmalen = s->rregs[0] | (s->rregs[1] << 8); - target = s->wregs[4] & 7; + dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8); + target = s->wregs[ESP_WBUSID] & 7; DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { espdma_memory_read(s->dma_opaque, buf, dmalen); @@ -129,9 +174,9 @@ static int get_cmd(ESPState *s, uint8_t *buf) if (target >= MAX_DISKS || !s->scsi_dev[target]) { // No such drive - s->rregs[4] = STAT_IN; - s->rregs[5] = INTR_DC; - s->rregs[6] = SEQ_0; + s->rregs[ESP_RSTAT] = STAT_IN; + s->rregs[ESP_RINTR] = INTR_DC; + s->rregs[ESP_RSEQ] = SEQ_0; qemu_irq_raise(s->irq); return 0; } @@ -149,19 +194,19 @@ static void do_cmd(ESPState *s, uint8_t *buf) datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); s->ti_size = datalen; if (datalen != 0) { - s->rregs[4] = STAT_IN | STAT_TC; + s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC; s->dma_left = 0; s->dma_counter = 0; if (datalen > 0) { - s->rregs[4] |= STAT_DI; + s->rregs[ESP_RSTAT] |= STAT_DI; scsi_read_data(s->current_dev, 0); } else { - s->rregs[4] |= STAT_DO; + s->rregs[ESP_RSTAT] |= STAT_DO; scsi_write_data(s->current_dev, 0); } } - s->rregs[5] = INTR_BS | INTR_FC; - s->rregs[6] = SEQ_CD; + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] = SEQ_CD; qemu_irq_raise(s->irq); } @@ -181,9 +226,9 @@ static void handle_satn_stop(ESPState *s) if (s->cmdlen) { DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); s->do_cmd = 1; - s->rregs[4] = STAT_IN | STAT_TC | STAT_CD; - s->rregs[5] = INTR_BS | INTR_FC; - s->rregs[6] = SEQ_CD; + s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_CD; + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] = SEQ_CD; qemu_irq_raise(s->irq); } } @@ -195,26 +240,26 @@ static void write_response(ESPState *s) s->ti_buf[1] = 0; if (s->dma) { espdma_memory_write(s->dma_opaque, s->ti_buf, 2); - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS | INTR_FC; - s->rregs[6] = SEQ_CD; + s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC | STAT_ST; + s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + s->rregs[ESP_RSEQ] = SEQ_CD; } else { s->ti_size = 2; s->ti_rptr = 0; s->ti_wptr = 0; - s->rregs[7] = 2; + s->rregs[ESP_RFLAGS] = 2; } qemu_irq_raise(s->irq); } static void esp_dma_done(ESPState *s) { - s->rregs[4] |= STAT_IN | STAT_TC; - s->rregs[5] = INTR_BS; - s->rregs[6] = 0; - s->rregs[7] = 0; - s->rregs[0] = 0; - s->rregs[1] = 0; + s->rregs[ESP_RSTAT] |= STAT_IN | STAT_TC; + s->rregs[ESP_RINTR] = INTR_BS; + s->rregs[ESP_RSEQ] = 0; + s->rregs[ESP_RFLAGS] = 0; + s->rregs[ESP_TCLO] = 0; + s->rregs[ESP_TCMID] = 0; qemu_irq_raise(s->irq); } @@ -287,7 +332,7 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag, if (arg) DPRINTF("Command failed\n"); s->sense = arg; - s->rregs[4] = STAT_ST; + s->rregs[ESP_RSTAT] = STAT_ST; esp_dma_done(s); s->current_dev = NULL; } else { @@ -308,7 +353,7 @@ static void handle_ti(ESPState *s) { uint32_t dmalen, minlen; - dmalen = s->rregs[0] | (s->rregs[1] << 8); + dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8); if (dmalen==0) { dmalen=0x10000; } @@ -323,7 +368,7 @@ static void handle_ti(ESPState *s) DPRINTF("Transfer Information len %d\n", minlen); if (s->dma) { s->dma_left = minlen; - s->rregs[4] &= ~STAT_TC; + s->rregs[ESP_RSTAT] &= ~STAT_TC; esp_do_dma(s); } else if (s->do_cmd) { DPRINTF("command len %d\n", s->cmdlen); @@ -341,7 +386,7 @@ static void esp_reset(void *opaque) memset(s->rregs, 0, ESP_REGS); memset(s->wregs, 0, ESP_REGS); - s->rregs[0x0e] = 0x4; // Indicate fas100a + s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; @@ -363,16 +408,15 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) saddr = (addr & ESP_MASK) >> 2; DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); switch (saddr) { - case 2: - // FIFO + case ESP_FIFO: if (s->ti_size > 0) { s->ti_size--; - if ((s->rregs[4] & 6) == 0) { + if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { /* Data in/out. */ fprintf(stderr, "esp: PIO data read not implemented\n"); - s->rregs[2] = 0; + s->rregs[ESP_FIFO] = 0; } else { - s->rregs[2] = s->ti_buf[s->ti_rptr++]; + s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; } qemu_irq_raise(s->irq); } @@ -381,10 +425,9 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) s->ti_wptr = 0; } break; - case 5: - // interrupt + case ESP_RINTR: // Clear interrupt/error status bits - s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE); + s->rregs[ESP_RSTAT] &= ~(STAT_IN | STAT_GE | STAT_PE); qemu_irq_lower(s->irq); break; default: @@ -399,17 +442,17 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) uint32_t saddr; saddr = (addr & ESP_MASK) >> 2; - DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); + DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], + val); switch (saddr) { - case 0: - case 1: - s->rregs[4] &= ~STAT_TC; + case ESP_TCLO: + case ESP_TCMID: + s->rregs[ESP_RSTAT] &= ~STAT_TC; break; - case 2: - // FIFO + case ESP_FIFO: if (s->do_cmd) { s->cmdbuf[s->cmdlen++] = val & 0xff; - } else if ((s->rregs[4] & 6) == 0) { + } else if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { uint8_t buf; buf = val & 0xff; s->ti_size--; @@ -419,63 +462,62 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) s->ti_buf[s->ti_wptr++] = val & 0xff; } break; - case 3: + case ESP_CMD: s->rregs[saddr] = val; - // Command - if (val & 0x80) { + if (val & CMD_DMA) { s->dma = 1; /* Reload DMA counter. */ - s->rregs[0] = s->wregs[0]; - s->rregs[1] = s->wregs[1]; + s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO]; + s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID]; } else { s->dma = 0; } - switch(val & 0x7f) { - case 0: + switch(val & CMD_CMD) { + case CMD_NOP: DPRINTF("NOP (%2.2x)\n", val); break; - case 1: + case CMD_FLUSH: DPRINTF("Flush FIFO (%2.2x)\n", val); //s->ti_size = 0; - s->rregs[5] = INTR_FC; - s->rregs[6] = 0; + s->rregs[ESP_RINTR] = INTR_FC; + s->rregs[ESP_RSEQ] = 0; break; - case 2: + case CMD_RESET: DPRINTF("Chip reset (%2.2x)\n", val); esp_reset(s); break; - case 3: + case CMD_BUSRESET: DPRINTF("Bus reset (%2.2x)\n", val); - s->rregs[5] = INTR_RST; - if (!(s->wregs[8] & 0x40)) { + s->rregs[ESP_RINTR] = INTR_RST; + if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { qemu_irq_raise(s->irq); } break; - case 0x10: + case CMD_TI: handle_ti(s); break; - case 0x11: + case CMD_ICCS: DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); write_response(s); break; - case 0x12: + case CMD_MSGACC: DPRINTF("Message Accepted (%2.2x)\n", val); write_response(s); - s->rregs[5] = INTR_DC; - s->rregs[6] = 0; + s->rregs[ESP_RINTR] = INTR_DC; + s->rregs[ESP_RSEQ] = 0; break; - case 0x1a: + case CMD_SATN: DPRINTF("Set ATN (%2.2x)\n", val); break; - case 0x42: + case CMD_SELATN: DPRINTF("Set ATN (%2.2x)\n", val); handle_satn(s); break; - case 0x43: + case CMD_SELATNS: DPRINTF("Set ATN & stop (%2.2x)\n", val); handle_satn_stop(s); break; - case 0x44: + case CMD_ENSEL: DPRINTF("Enable selection (%2.2x)\n", val); break; default: @@ -483,17 +525,17 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) break; } break; - case 4 ... 7: + case ESP_WBUSID ... ESP_WSYNO: break; - case 8: + case ESP_CFG1: s->rregs[saddr] = val; break; - case 9 ... 10: + case ESP_WCCF ... ESP_WTEST: break; - case 11: - s->rregs[saddr] = val & 0x15; + case ESP_CFG2: + s->rregs[saddr] = val & CFG2_MASK; break; - case 12 ... 15: + case ESP_CFG3 ... ESP_RES4: s->rregs[saddr] = val; break; default: diff --git a/hw/iommu.c b/hw/iommu.c index 76259bbc6..ad5826e4e 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -61,12 +61,16 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define IOMMU_AFSR (0x1000 >> 2) #define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */ -#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after transaction */ -#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than 12.8 us. */ -#define IOMMU_AFSR_BE 0x10000000 /* Write access received error acknowledge */ +#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after + transaction */ +#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than + 12.8 us. */ +#define IOMMU_AFSR_BE 0x10000000 /* Write access received error + acknowledge */ #define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */ #define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */ -#define IOMMU_AFSR_RESV 0x00f00000 /* Reserved, forced to 0x8 by hardware */ +#define IOMMU_AFSR_RESV 0x00800000 /* Reserved, forced to 0x8 by + hardware */ #define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */ #define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */ #define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */ @@ -77,7 +81,8 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */ #define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */ #define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configration per-slot */ -#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */ +#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when + bypass enabled */ #define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ #define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ #define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses @@ -91,7 +96,8 @@ do { printf("IOMMU: " fmt , ##args); } while (0) /* The format of an iopte in the page tables */ #define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ -#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ +#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or + Viking/MXCC) */ #define IOPTE_WRITE 0x00000004 /* Writeable */ #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ #define IOPTE_WAZ 0x00000001 /* Write as zeros */ @@ -122,7 +128,8 @@ static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) return 0; } -static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, + uint32_t val) { IOMMUState *s = opaque; target_phys_addr_t saddr; @@ -235,10 +242,11 @@ static target_phys_addr_t iommu_translate_pa(IOMMUState *s, return pa; } -static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, int is_write) +static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, + int is_write) { DPRINTF("bad addr " TARGET_FMT_plx "\n", addr); - s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | (8 << 20) | + s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV | IOMMU_AFSR_FAV; if (!is_write) s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD; @@ -311,7 +319,7 @@ static void iommu_reset(void *opaque) s->iostart = 0; s->regs[IOMMU_CTRL] = s->version; s->regs[IOMMU_ARBEN] = IOMMU_MID; - s->regs[IOMMU_AFSR] = 0x00800000; + s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV; } void *iommu_init(target_phys_addr_t addr, uint32_t version) @@ -326,7 +334,8 @@ void *iommu_init(target_phys_addr_t addr, uint32_t version) s->addr = addr; s->version = version; - iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); + iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, + iommu_mem_write, s); cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); register_savevm("iommu", addr, 2, iommu_save, iommu_load, s); @@ -334,4 +343,3 @@ void *iommu_init(target_phys_addr_t addr, uint32_t version) iommu_reset(s); return s; } - -- cgit v1.2.3 From c52428fcb1b3381f6ef3c64a26dfd55c5c874da6 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 1 Dec 2007 14:51:24 +0000 Subject: Prevent overwriting fixed bits in AFSR git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3752 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/iommu.c b/hw/iommu.c index ad5826e4e..784a780c8 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -74,6 +74,7 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */ #define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */ #define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */ +#define IOMMU_AFSR_MASK 0xff0fffff #define IOMMU_AFAR (0x1004 >> 2) @@ -179,6 +180,9 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, DPRINTF("page flush %x\n", val); s->regs[saddr] = val & IOMMU_PGFLUSH_MASK; break; + case IOMMU_AFSR: + s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV; + break; case IOMMU_SBCFG0: case IOMMU_SBCFG1: case IOMMU_SBCFG2: -- cgit v1.2.3 From 498fbd8aadbe6ba330f939ae9576e53579361dcf Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 1 Dec 2007 14:51:25 +0000 Subject: Allow IOMMU tables above 2G git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3753 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/iommu.c b/hw/iommu.c index 784a780c8..271c4d473 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -96,7 +96,7 @@ do { printf("IOMMU: " fmt , ##args); } while (0) #define IOMMU_MID 0x00000008 /* The format of an iopte in the page tables */ -#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ +#define IOPTE_PAGE 0xffffff00 /* Physical page number (PA[35:12]) */ #define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ #define IOPTE_WRITE 0x00000004 /* Writeable */ -- cgit v1.2.3 From 7debeb82ffad5480c230c116ba17a9c1d8e32016 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 1 Dec 2007 14:53:22 +0000 Subject: Name the magic constants, use correct value for AUX2_PWRFAIL git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3754 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_misc.c | 83 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 67e1c0d7d..9658f505d 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -58,11 +58,30 @@ typedef struct MiscState { #define LED_MAXADDR 2 #define LED_SIZE (LED_MAXADDR + 1) +#define MISC_MASK 0x0fff0000 +#define MISC_LEDS 0x01600000 +#define MISC_CFG 0x01800000 +#define MISC_AUX1 0x01900000 +#define MISC_AUX2 0x01910000 +#define MISC_DIAG 0x01a00000 +#define MISC_MDM 0x01b00000 +#define MISC_SYS 0x01f00000 +#define MISC_PWR 0x0a000000 + +#define AUX2_PWROFF 0x01 +#define AUX2_PWRINTCLR 0x02 +#define AUX2_PWRFAIL 0x20 + +#define CFG_PWRINTEN 0x08 + +#define SYS_RESET 0x01 +#define SYS_RESETSTAT 0x02 + static void slavio_misc_update_irq(void *opaque) { MiscState *s = opaque; - if ((s->aux2 & 0x4) && (s->config & 0x8)) { + if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) { MISC_DPRINTF("Raise IRQ\n"); qemu_irq_raise(s->irq); } else { @@ -84,10 +103,10 @@ void slavio_set_power_fail(void *opaque, int power_failing) MiscState *s = opaque; MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config); - if (power_failing && (s->config & 0x8)) { - s->aux2 |= 0x4; + if (power_failing && (s->config & CFG_PWRINTEN)) { + s->aux2 |= AUX2_PWRFAIL; } else { - s->aux2 &= ~0x4; + s->aux2 &= ~AUX2_PWRFAIL; } slavio_misc_update_irq(s); } @@ -97,36 +116,36 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, { MiscState *s = opaque; - switch (addr & 0xfff0000) { - case 0x1800000: + switch (addr & MISC_MASK) { + case MISC_CFG: MISC_DPRINTF("Write config %2.2x\n", val & 0xff); s->config = val & 0xff; slavio_misc_update_irq(s); break; - case 0x1900000: + case MISC_AUX1: MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); s->aux1 = val & 0xff; break; - case 0x1910000: - val &= 0x3; + case MISC_AUX2: + val &= AUX2_PWRINTCLR | AUX2_PWROFF; MISC_DPRINTF("Write aux2 %2.2x\n", val); - val |= s->aux2 & 0x4; - if (val & 0x2) // Clear Power Fail int - val &= 0x1; + val |= s->aux2 & AUX2_PWRFAIL; + if (val & AUX2_PWRINTCLR) // Clear Power Fail int + val &= AUX2_PWROFF; s->aux2 = val; - if (val & 1) + if (val & AUX2_PWROFF) qemu_system_shutdown_request(); slavio_misc_update_irq(s); break; - case 0x1a00000: + case MISC_DIAG: MISC_DPRINTF("Write diag %2.2x\n", val & 0xff); s->diag = val & 0xff; break; - case 0x1b00000: + case MISC_MDM: MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); s->mctrl = val & 0xff; break; - case 0xa000000: + case MISC_PWR: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); break; @@ -138,28 +157,28 @@ static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr) MiscState *s = opaque; uint32_t ret = 0; - switch (addr & 0xfff0000) { - case 0x1800000: + switch (addr & MISC_MASK) { + case MISC_CFG: ret = s->config; MISC_DPRINTF("Read config %2.2x\n", ret); break; - case 0x1900000: + case MISC_AUX1: ret = s->aux1; MISC_DPRINTF("Read aux1 %2.2x\n", ret); break; - case 0x1910000: + case MISC_AUX2: ret = s->aux2; MISC_DPRINTF("Read aux2 %2.2x\n", ret); break; - case 0x1a00000: + case MISC_DIAG: ret = s->diag; MISC_DPRINTF("Read diag %2.2x\n", ret); break; - case 0x1b00000: + case MISC_MDM: ret = s->mctrl; MISC_DPRINTF("Read modem control %2.2x\n", ret); break; - case 0xa000000: + case MISC_PWR: MISC_DPRINTF("Read power management %2.2x\n", ret); break; } @@ -207,8 +226,8 @@ static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr, val); switch (saddr) { case 0: - if (val & 1) { - s->sysctrl = 0x2; + if (val & SYS_RESET) { + s->sysctrl = SYS_RESETSTAT; qemu_system_reset_request(); } break; @@ -328,19 +347,19 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s); // Slavio control - cpu_register_physical_memory(base + 0x1800000, MISC_SIZE, + cpu_register_physical_memory(base + MISC_CFG, MISC_SIZE, slavio_misc_io_memory); // AUX 1 - cpu_register_physical_memory(base + 0x1900000, MISC_SIZE, + cpu_register_physical_memory(base + MISC_AUX1, MISC_SIZE, slavio_misc_io_memory); // AUX 2 - cpu_register_physical_memory(base + 0x1910000, MISC_SIZE, + cpu_register_physical_memory(base + MISC_AUX2, MISC_SIZE, slavio_misc_io_memory); // Diagnostics - cpu_register_physical_memory(base + 0x1a00000, MISC_SIZE, + cpu_register_physical_memory(base + MISC_DIAG, MISC_SIZE, slavio_misc_io_memory); // Modem control - cpu_register_physical_memory(base + 0x1b00000, MISC_SIZE, + cpu_register_physical_memory(base + MISC_MDM, MISC_SIZE, slavio_misc_io_memory); // Power management cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory); @@ -349,7 +368,7 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, slavio_misc_io_memory = cpu_register_io_memory(0, slavio_led_mem_read, slavio_led_mem_write, s); /* ss600mp diag LEDs */ - cpu_register_physical_memory(base + 0x1600000, MISC_SIZE, + cpu_register_physical_memory(base + MISC_LEDS, MISC_SIZE, slavio_misc_io_memory); /* 32 bit registers */ @@ -357,7 +376,7 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, slavio_sysctrl_mem_write, s); // System control - cpu_register_physical_memory(base + 0x1f00000, SYSCTRL_SIZE, + cpu_register_physical_memory(base + MISC_SYS, SYSCTRL_SIZE, slavio_misc_io_memory); s->irq = irq; -- cgit v1.2.3 From df33e6392ce5c9be330110100c027de3495f4acb Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 1 Dec 2007 14:54:47 +0000 Subject: Improve power management device addressing git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3755 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_misc.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 9658f505d..d22243bc4 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -50,6 +50,7 @@ typedef struct MiscState { uint8_t diag, mctrl; uint32_t sysctrl; uint16_t leds; + target_phys_addr_t power_base; } MiscState; #define MISC_SIZE 1 @@ -66,7 +67,6 @@ typedef struct MiscState { #define MISC_DIAG 0x01a00000 #define MISC_MDM 0x01b00000 #define MISC_SYS 0x01f00000 -#define MISC_PWR 0x0a000000 #define AUX2_PWROFF 0x01 #define AUX2_PWRINTCLR 0x02 @@ -145,9 +145,11 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); s->mctrl = val & 0xff; break; - case MISC_PWR: - MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); + default: + if (addr == s->power_base) { + MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); + } break; } } @@ -178,8 +180,10 @@ static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr) ret = s->mctrl; MISC_DPRINTF("Read modem control %2.2x\n", ret); break; - case MISC_PWR: - MISC_DPRINTF("Read power management %2.2x\n", ret); + default: + if (addr == s->power_base) { + MISC_DPRINTF("Read power management %2.2x\n", ret); + } break; } return ret; @@ -363,6 +367,7 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, slavio_misc_io_memory); // Power management cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory); + s->power_base = power_base; /* 16 bit registers */ slavio_misc_io_memory = cpu_register_io_memory(0, slavio_led_mem_read, -- cgit v1.2.3 From d5296cb507927ffe3df2716f780b5a3b600ed402 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 1 Dec 2007 15:02:20 +0000 Subject: Fix SS-600MP led device typos git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3756 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index d22243bc4..9728bcad9 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -56,7 +56,7 @@ typedef struct MiscState { #define MISC_SIZE 1 #define SYSCTRL_MAXADDR 3 #define SYSCTRL_SIZE (SYSCTRL_MAXADDR + 1) -#define LED_MAXADDR 2 +#define LED_MAXADDR 1 #define LED_SIZE (LED_MAXADDR + 1) #define MISC_MASK 0x0fff0000 @@ -281,7 +281,7 @@ static void slavio_led_mem_writes(void *opaque, target_phys_addr_t addr, val); switch (saddr) { case 0: - s->sysctrl = val; + s->leds = val; break; default: break; -- cgit v1.2.3 From d2c38b24d1d9b0b94137b7190f80fd4d0f4a0fb1 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sat, 1 Dec 2007 15:58:22 +0000 Subject: Name the magic constants, wrap long lines git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3757 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_timer.c | 100 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index a81b34ff5..7d9ee4b2a 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -69,6 +69,24 @@ typedef struct SLAVIO_TIMERState { #define SYS_TIMER_SIZE 0x14 #define CPU_TIMER_SIZE 0x10 +#define SYS_TIMER_OFFSET 0x10000ULL +#define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu) + +#define TIMER_LIMIT 0 +#define TIMER_COUNTER 1 +#define TIMER_COUNTER_NORST 2 +#define TIMER_STATUS 3 +#define TIMER_MODE 4 + +#define TIMER_COUNT_MASK32 0xfffffe00 +#define TIMER_LIMIT_MASK32 0x7fffffff +#define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL +#define TIMER_MAX_COUNT32 0x7ffffe00ULL +#define TIMER_REACHED 0x80000000 +#define TIMER_PERIOD 500ULL // 500ns +#define LIMIT_TO_PERIODS(l) ((l) >> 9) +#define PERIODS_TO_LIMIT(l) ((l) << 9) + static int slavio_timer_is_user(SLAVIO_TIMERState *s) { return s->master && (s->master->slave_mode & (1 << s->slave_index)); @@ -80,10 +98,10 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) { uint64_t count; - count = s->limit - (ptimer_get_count(s->timer) << 9); - DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit, s->counthigh, - s->count); - s->count = count & 0xfffffe00; + count = s->limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer)); + DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit, + s->counthigh, s->count); + s->count = count & TIMER_COUNT_MASK32; s->counthigh = count >> 32; } @@ -95,7 +113,7 @@ static void slavio_timer_irq(void *opaque) slavio_timer_get_out(s); DPRINTF("callback: count %x%08x\n", s->counthigh, s->count); if (!slavio_timer_is_user(s)) { - s->reached = 0x80000000; + s->reached = TIMER_REACHED; qemu_irq_raise(s->irq); } } @@ -107,7 +125,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { - case 0: + case TIMER_LIMIT: // read limit (system counter mode) or read most signifying // part of counter (user mode) if (slavio_timer_is_user(s)) { @@ -119,24 +137,24 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) // clear irq qemu_irq_lower(s->irq); s->reached = 0; - ret = s->limit & 0x7fffffff; + ret = s->limit & TIMER_LIMIT_MASK32; } break; - case 1: + case TIMER_COUNTER: // read counter and reached bit (system mode) or read lsbits // of counter (user mode) slavio_timer_get_out(s); if (slavio_timer_is_user(s)) // read user timer LSW - ret = s->count & 0xfffffe00; + ret = s->count & TIMER_COUNT_MASK32; else // read limit - ret = (s->count & 0x7ffffe00) | s->reached; + ret = (s->count & TIMER_MAX_COUNT32) | s->reached; break; - case 3: + case TIMER_STATUS: // only available in processor counter/timer // read start/stop status ret = s->running; break; - case 4: + case TIMER_MODE: // only available in system counter // read user/system mode ret = s->slave_mode; @@ -151,7 +169,8 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) return ret; } -static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, + uint32_t val) { SLAVIO_TIMERState *s = opaque; uint32_t saddr; @@ -160,40 +179,40 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val); saddr = (addr & TIMER_MAXADDR) >> 2; switch (saddr) { - case 0: + case TIMER_LIMIT: if (slavio_timer_is_user(s)) { // set user counter MSW, reset counter qemu_irq_lower(s->irq); - s->limit = 0x7ffffffffffffe00ULL; + s->limit = TIMER_MAX_COUNT64; DPRINTF("processor %d user timer reset\n", s->slave_index); - ptimer_set_limit(s->timer, s->limit >> 9, 1); + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); } else { // set limit, reset counter qemu_irq_lower(s->irq); - s->limit = val & 0x7ffffe00ULL; + s->limit = val & TIMER_MAX_COUNT32; if (!s->limit) - s->limit = 0x7ffffe00ULL; + s->limit = TIMER_MAX_COUNT32; ptimer_set_limit(s->timer, s->limit >> 9, 1); } break; - case 1: + case TIMER_COUNTER: if (slavio_timer_is_user(s)) { // set user counter LSW, reset counter qemu_irq_lower(s->irq); - s->limit = 0x7ffffffffffffe00ULL; + s->limit = TIMER_MAX_COUNT64; DPRINTF("processor %d user timer reset\n", s->slave_index); - ptimer_set_limit(s->timer, s->limit >> 9, 1); + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); } else DPRINTF("not user timer\n"); break; - case 2: + case TIMER_COUNTER_NORST: // set limit without resetting counter - s->limit = val & 0x7ffffe00ULL; + s->limit = val & TIMER_MAX_COUNT32; if (!s->limit) - s->limit = 0x7ffffe00ULL; - ptimer_set_limit(s->timer, s->limit >> 9, reload); + s->limit = TIMER_MAX_COUNT32; + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), reload); break; - case 3: + case TIMER_STATUS: if (slavio_timer_is_user(s)) { // start/stop user counter if ((val & 1) && !s->running) { @@ -207,7 +226,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 } } break; - case 4: + case TIMER_MODE: if (s->master == NULL) { unsigned int i; @@ -218,8 +237,10 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3 } if ((val & (1 << i)) != (s->slave_mode & (1 << i))) { ptimer_stop(s->slave[i]->timer); - ptimer_set_limit(s->slave[i]->timer, s->slave[i]->limit >> 9, 1); - DPRINTF("processor %d timer changed\n", s->slave[i]->slave_index); + ptimer_set_limit(s->slave[i]->timer, + LIMIT_TO_PERIODS(s->slave[i]->limit), 1); + DPRINTF("processor %d timer changed\n", + s->slave[i]->slave_index); ptimer_run(s->slave[i]->timer, 0); } } @@ -284,12 +305,12 @@ static void slavio_timer_reset(void *opaque) SLAVIO_TIMERState *s = opaque; if (slavio_timer_is_user(s)) - s->limit = 0x7ffffffffffffe00ULL; + s->limit = TIMER_MAX_COUNT64; else - s->limit = 0x7ffffe00ULL; + s->limit = TIMER_MAX_COUNT32; s->count = 0; s->reached = 0; - ptimer_set_limit(s->timer, s->limit >> 9, 1); + ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1); ptimer_run(s->timer, 0); s->running = 1; qemu_irq_lower(s->irq); @@ -312,15 +333,18 @@ static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, s->slave_index = slave_index; bh = qemu_bh_new(slavio_timer_irq, s); s->timer = ptimer_init(bh); - ptimer_set_period(s->timer, 500ULL); + ptimer_set_period(s->timer, TIMER_PERIOD); slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, slavio_timer_mem_write, s); if (master) - cpu_register_physical_memory(addr, CPU_TIMER_SIZE, slavio_timer_io_memory); + cpu_register_physical_memory(addr, CPU_TIMER_SIZE, + slavio_timer_io_memory); else - cpu_register_physical_memory(addr, SYS_TIMER_SIZE, slavio_timer_io_memory); - register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s); + cpu_register_physical_memory(addr, SYS_TIMER_SIZE, + slavio_timer_io_memory); + register_savevm("slavio_timer", addr, 2, slavio_timer_save, + slavio_timer_load, s); qemu_register_reset(slavio_timer_reset, s); slavio_timer_reset(s); @@ -333,11 +357,11 @@ void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, SLAVIO_TIMERState *master; unsigned int i; - master = slavio_timer_init(base + 0x10000ULL, master_irq, NULL, 0); + master = slavio_timer_init(base + SYS_TIMER_OFFSET, master_irq, NULL, 0); for (i = 0; i < MAX_CPUS; i++) { master->slave[i] = slavio_timer_init(base + (target_phys_addr_t) - (i * TARGET_PAGE_SIZE), + CPU_TIMER_OFFSET(i), cpu_irqs[i], master, i); } } -- cgit v1.2.3 From 7233b355571ad2a8e7aec7eb19db5f530e81f052 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 02:20:03 +0000 Subject: Mainstone re-org, by Armin Kuster. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3758 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 3 +- hw/mainstone.c | 257 ++++---------------------------------------------------- hw/mainstone.h | 25 ++++++ hw/mst_fpga.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 290 insertions(+), 241 deletions(-) create mode 100644 hw/mainstone.h create mode 100644 hw/mst_fpga.c diff --git a/Makefile.target b/Makefile.target index c486d501f..eb77210df 100644 --- a/Makefile.target +++ b/Makefile.target @@ -496,9 +496,10 @@ VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o VL_OBJS+= pflash_cfi01.o gumstix.o -VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o mainstone.o +VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o VL_OBJS+= palm.o tsc210x.o +VL_OBJS+= mst_fpga.o mainstone.o CPPFLAGS += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), sh4) diff --git a/hw/mainstone.c b/hw/mainstone.c index d6ce4ffe0..13f72b350 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -14,245 +14,9 @@ #include "net.h" #include "devices.h" #include "boards.h" - -#define MST_ETH_PHYS 0x10000300 -#define MST_FPGA_PHYS 0x08000000 - -/* Mainstone FPGA for extern irqs */ -#define FPGA_GPIO_PIN 0 -#define MST_NUM_IRQS 16 -#define MST_BASE MST_FPGA_PHYS -#define MST_LEDDAT1 0x10 -#define MST_LEDDAT2 0x14 -#define MST_LEDCTRL 0x40 -#define MST_GPSWR 0x60 -#define MST_MSCWR1 0x80 -#define MST_MSCWR2 0x84 -#define MST_MSCWR3 0x88 -#define MST_MSCRD 0x90 -#define MST_INTMSKENA 0xc0 -#define MST_INTSETCLR 0xd0 -#define MST_PCMCIA0 0xe0 -#define MST_PCMCIA1 0xe4 - -/* IRQ definitions */ -#define ETHERNET_IRQ 3 - -typedef struct mst_irq_state { - target_phys_addr_t target_base; - qemu_irq *parent; - qemu_irq *pins; - - uint32_t prev_level; - uint32_t leddat1; - uint32_t leddat2; - uint32_t ledctrl; - uint32_t gpswr; - uint32_t mscwr1; - uint32_t mscwr2; - uint32_t mscwr3; - uint32_t mscrd; - uint32_t intmskena; - uint32_t intsetclr; - uint32_t pcmcia0; - uint32_t pcmcia1; -} mst_irq_state; - -static void -mst_fpga_update_gpio(mst_irq_state *s) -{ - uint32_t level, diff; - int bit; - level = s->prev_level ^ s->intsetclr; - - for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { - bit = ffs(diff) - 1; - qemu_set_irq(s->pins[bit], (level >> bit) & 1 ); - } - s->prev_level = level; -} - -static void -mst_fpga_set_irq(void *opaque, int irq, int level) -{ - mst_irq_state *s = (mst_irq_state *)opaque; - - if (level) - s->prev_level |= 1u << irq; - else - s->prev_level &= ~(1u << irq); - - if(s->intmskena & (1u << irq)) { - s->intsetclr = 1u << irq; - qemu_set_irq(s->parent[0], level); - } -} - -static uint32_t -mst_fpga_readb(void *opaque, target_phys_addr_t addr) -{ - mst_irq_state *s = (mst_irq_state *) opaque; - addr -= s->target_base; - - switch (addr) { - case MST_LEDDAT1: - return s->leddat1; - case MST_LEDDAT2: - return s->leddat2; - case MST_LEDCTRL: - return s->ledctrl; - case MST_GPSWR: - return s->gpswr; - case MST_MSCWR1: - return s->mscwr1; - case MST_MSCWR2: - return s->mscwr2; - case MST_MSCWR3: - return s->mscwr3; - case MST_MSCRD: - return s->mscrd; - case MST_INTMSKENA: - return s->intmskena; - case MST_INTSETCLR: - return s->intsetclr; - case MST_PCMCIA0: - return s->pcmcia0; - case MST_PCMCIA1: - return s->pcmcia1; - default: - printf("Mainstone - mst_fpga_readb: Bad register offset " - REG_FMT " \n", addr); - } - return 0; -} - -static void -mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) -{ - mst_irq_state *s = (mst_irq_state *) opaque; - addr -= s->target_base; - value &= 0xffffffff; - - switch (addr) { - case MST_LEDDAT1: - s->leddat1 = value; - break; - case MST_LEDDAT2: - s->leddat2 = value; - break; - case MST_LEDCTRL: - s->ledctrl = value; - break; - case MST_GPSWR: - s->gpswr = value; - break; - case MST_MSCWR1: - s->mscwr1 = value; - break; - case MST_MSCWR2: - s->mscwr2 = value; - break; - case MST_MSCWR3: - s->mscwr3 = value; - break; - case MST_MSCRD: - s->mscrd = value; - break; - case MST_INTMSKENA: /* Mask interupt */ - s->intmskena = (value & 0xFEEFF); - mst_fpga_update_gpio(s); - break; - case MST_INTSETCLR: /* clear or set interrupt */ - s->intsetclr = (value & 0xFEEFF); - break; - case MST_PCMCIA0: - s->pcmcia0 = value; - break; - case MST_PCMCIA1: - s->pcmcia1 = value; - break; - default: - printf("Mainstone - mst_fpga_writeb: Bad register offset " - REG_FMT " \n", addr); - } -} - -CPUReadMemoryFunc *mst_fpga_readfn[] = { - mst_fpga_readb, - mst_fpga_readb, - mst_fpga_readb, -}; -CPUWriteMemoryFunc *mst_fpga_writefn[] = { - mst_fpga_writeb, - mst_fpga_writeb, - mst_fpga_writeb, -}; - -static void -mst_fpga_save(QEMUFile *f, void *opaque) -{ - struct mst_irq_state *s = (mst_irq_state *) opaque; - - qemu_put_be32s(f, &s->prev_level); - qemu_put_be32s(f, &s->leddat1); - qemu_put_be32s(f, &s->leddat2); - qemu_put_be32s(f, &s->ledctrl); - qemu_put_be32s(f, &s->gpswr); - qemu_put_be32s(f, &s->mscwr1); - qemu_put_be32s(f, &s->mscwr2); - qemu_put_be32s(f, &s->mscwr3); - qemu_put_be32s(f, &s->mscrd); - qemu_put_be32s(f, &s->intmskena); - qemu_put_be32s(f, &s->intsetclr); - qemu_put_be32s(f, &s->pcmcia0); - qemu_put_be32s(f, &s->pcmcia1); -} - -static int -mst_fpga_load(QEMUFile *f, void *opaque, int version_id) -{ - mst_irq_state *s = (mst_irq_state *) opaque; - - qemu_get_be32s(f, &s->prev_level); - qemu_get_be32s(f, &s->leddat1); - qemu_get_be32s(f, &s->leddat2); - qemu_get_be32s(f, &s->ledctrl); - qemu_get_be32s(f, &s->gpswr); - qemu_get_be32s(f, &s->mscwr1); - qemu_get_be32s(f, &s->mscwr2); - qemu_get_be32s(f, &s->mscwr3); - qemu_get_be32s(f, &s->mscrd); - qemu_get_be32s(f, &s->intmskena); - qemu_get_be32s(f, &s->intsetclr); - qemu_get_be32s(f, &s->pcmcia0); - qemu_get_be32s(f, &s->pcmcia1); - return 0; -} - -static qemu_irq -*mst_irq_init(struct pxa2xx_state_s *cpu, uint32_t base, int irq) -{ - mst_irq_state *s; - int iomemtype; - qemu_irq *qi; - - s = (mst_irq_state *) qemu_mallocz(sizeof(mst_irq_state)); - - if (!s) - return NULL; - s->target_base = base; - s->parent = &cpu->pic[irq]; - - /* alloc the external 16 irqs */ - qi = qemu_allocate_irqs(mst_fpga_set_irq, s, MST_NUM_IRQS); - s->pins = qi; - - iomemtype = cpu_register_io_memory(0, mst_fpga_readfn, - mst_fpga_writefn, s); - cpu_register_physical_memory(MST_BASE, 0x00100000, iomemtype); - register_savevm("mainstone_fpga", 0, 0, mst_fpga_save, mst_fpga_load, s); - return qi; -} +#include "mainstone.h" +#include "sysemu.h" +#include "flash.h" enum mainstone_model_e { mainstone }; @@ -283,7 +47,20 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, /* Setup initial (reset) machine state */ cpu->env->regs[15] = PXA2XX_SDRAM_BASE; - mst_irq = mst_irq_init(cpu, MST_BASE, PXA2XX_PIC_GPIO_0); + /* There are two 32MiB flash devices on the board */ + if (!pflash_register(MST_FLASH_0, mainstone_ram + PXA2XX_INTERNAL_SIZE, + pflash_table[0], 256 * 1024, 128, 4, 0, 0, 0, 0)) { + fprintf(stderr, "qemu: Error register flash memory.\n"); + exit(1); + } + + if (!pflash_register(MST_FLASH_1, mainstone_ram + PXA2XX_INTERNAL_SIZE, + pflash_table[1], 256 * 1024, 128, 4, 0, 0, 0, 0)) { + fprintf(stderr, "qemu: Error register flash memory.\n"); + exit(1); + } + + mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0); smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); arm_load_kernel(cpu->env, mainstone_ram, kernel_filename, kernel_cmdline, diff --git a/hw/mainstone.h b/hw/mainstone.h new file mode 100644 index 000000000..c7bcb93f0 --- /dev/null +++ b/hw/mainstone.h @@ -0,0 +1,25 @@ +/* + * PXA270-based Intel Mainstone platforms. + * + * Copyright (c) 2007 by Armin Kuster or + * + * + * This code is licensed under the GNU GPL v2. + */ + +#ifndef __MAINSTONE_H__ +#define __MAINSTONE_H__ + +/* Device addresses */ +#define MST_FPGA_PHYS 0x08000000 +#define MST_ETH_PHYS 0x10000300 +#define MST_FLASH_0 0x00000000 +#define MST_FLASH_1 0x04000000 + +/* IRQ definitions */ +#define ETHERNET_IRQ 3 + +extern qemu_irq +*mst_irq_init(struct pxa2xx_state_s *cpu, uint32_t base, int irq); + +#endif /* __MAINSTONE_H__ */ diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c new file mode 100644 index 000000000..e2f0a9a59 --- /dev/null +++ b/hw/mst_fpga.c @@ -0,0 +1,246 @@ +/* + * PXA270-based Intel Mainstone platforms. + * FPGA driver + * + * Copyright (c) 2007 by Armin Kuster or + * + * + * This code is licensed under the GNU GPL v2. + */ +#include "hw.h" +#include "pxa.h" +#include "mainstone.h" + +/* Mainstone FPGA for extern irqs */ +#define FPGA_GPIO_PIN 0 +#define MST_NUM_IRQS 16 +#define MST_BASE MST_FPGA_PHYS +#define MST_LEDDAT1 0x10 +#define MST_LEDDAT2 0x14 +#define MST_LEDCTRL 0x40 +#define MST_GPSWR 0x60 +#define MST_MSCWR1 0x80 +#define MST_MSCWR2 0x84 +#define MST_MSCWR3 0x88 +#define MST_MSCRD 0x90 +#define MST_INTMSKENA 0xc0 +#define MST_INTSETCLR 0xd0 +#define MST_PCMCIA0 0xe0 +#define MST_PCMCIA1 0xe4 + +typedef struct mst_irq_state{ + target_phys_addr_t target_base; + qemu_irq *parent; + qemu_irq *pins; + + uint32_t prev_level; + uint32_t leddat1; + uint32_t leddat2; + uint32_t ledctrl; + uint32_t gpswr; + uint32_t mscwr1; + uint32_t mscwr2; + uint32_t mscwr3; + uint32_t mscrd; + uint32_t intmskena; + uint32_t intsetclr; + uint32_t pcmcia0; + uint32_t pcmcia1; +}mst_irq_state; + +static void +mst_fpga_update_gpio(mst_irq_state *s) +{ + uint32_t level, diff; + int bit; + level = s->prev_level ^ s->intsetclr; + + for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { + bit = ffs(diff) - 1; + qemu_set_irq(s->pins[bit], (level >> bit) & 1 ); + } + s->prev_level = level; +} + +static void +mst_fpga_set_irq(void *opaque, int irq, int level) +{ + mst_irq_state *s = (mst_irq_state *)opaque; + + if (level) + s->prev_level |= 1u << irq; + else + s->prev_level &= ~(1u << irq); + + if(s->intmskena & (1u << irq)) { + s->intsetclr = 1u << irq; + qemu_set_irq(s->parent[0], level); + } +} + + +static uint32_t +mst_fpga_readb(void *opaque, target_phys_addr_t addr) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + addr -= s->target_base; + + switch (addr) { + case MST_LEDDAT1: + return s->leddat1; + case MST_LEDDAT2: + return s->leddat2; + case MST_LEDCTRL: + return s->ledctrl; + case MST_GPSWR: + return s->gpswr; + case MST_MSCWR1: + return s->mscwr1; + case MST_MSCWR2: + return s->mscwr2; + case MST_MSCWR3: + return s->mscwr3; + case MST_MSCRD: + return s->mscrd; + case MST_INTMSKENA: + return s->intmskena; + case MST_INTSETCLR: + return s->intsetclr; + case MST_PCMCIA0: + return s->pcmcia0; + case MST_PCMCIA1: + return s->pcmcia1; + default: + printf("Mainstone - mst_fpga_readb: Bad register offset " + REG_FMT " \n", addr); + } + return 0; +} + +static void +mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + addr -= s->target_base; + value &= 0xffffffff; + + switch (addr) { + case MST_LEDDAT1: + s->leddat1 = value; + break; + case MST_LEDDAT2: + s->leddat2 = value; + break; + case MST_LEDCTRL: + s->ledctrl = value; + break; + case MST_GPSWR: + s->gpswr = value; + break; + case MST_MSCWR1: + s->mscwr1 = value; + break; + case MST_MSCWR2: + s->mscwr2 = value; + break; + case MST_MSCWR3: + s->mscwr3 = value; + break; + case MST_MSCRD: + s->mscrd = value; + break; + case MST_INTMSKENA: /* Mask interupt */ + s->intmskena = (value & 0xFEEFF); + mst_fpga_update_gpio(s); + break; + case MST_INTSETCLR: /* clear or set interrupt */ + s->intsetclr = (value & 0xFEEFF); + break; + case MST_PCMCIA0: + s->pcmcia0 = value; + break; + case MST_PCMCIA1: + s->pcmcia1 = value; + break; + default: + printf("Mainstone - mst_fpga_writeb: Bad register offset " + REG_FMT " \n", addr); + } +} + +CPUReadMemoryFunc *mst_fpga_readfn[] = { + mst_fpga_readb, + mst_fpga_readb, + mst_fpga_readb, +}; +CPUWriteMemoryFunc *mst_fpga_writefn[] = { + mst_fpga_writeb, + mst_fpga_writeb, + mst_fpga_writeb, +}; + +static void +mst_fpga_save(QEMUFile *f, void *opaque) +{ + struct mst_irq_state *s = (mst_irq_state *) opaque; + + qemu_put_be32s(f, &s->prev_level); + qemu_put_be32s(f, &s->leddat1); + qemu_put_be32s(f, &s->leddat2); + qemu_put_be32s(f, &s->ledctrl); + qemu_put_be32s(f, &s->gpswr); + qemu_put_be32s(f, &s->mscwr1); + qemu_put_be32s(f, &s->mscwr2); + qemu_put_be32s(f, &s->mscwr3); + qemu_put_be32s(f, &s->mscrd); + qemu_put_be32s(f, &s->intmskena); + qemu_put_be32s(f, &s->intsetclr); + qemu_put_be32s(f, &s->pcmcia0); + qemu_put_be32s(f, &s->pcmcia1); +} + +static int +mst_fpga_load(QEMUFile *f, void *opaque, int version_id) +{ + mst_irq_state *s = (mst_irq_state *) opaque; + + qemu_get_be32s(f, &s->prev_level); + qemu_get_be32s(f, &s->leddat1); + qemu_get_be32s(f, &s->leddat2); + qemu_get_be32s(f, &s->ledctrl); + qemu_get_be32s(f, &s->gpswr); + qemu_get_be32s(f, &s->mscwr1); + qemu_get_be32s(f, &s->mscwr2); + qemu_get_be32s(f, &s->mscwr3); + qemu_get_be32s(f, &s->mscrd); + qemu_get_be32s(f, &s->intmskena); + qemu_get_be32s(f, &s->intsetclr); + qemu_get_be32s(f, &s->pcmcia0); + qemu_get_be32s(f, &s->pcmcia1); + return 0; +} + +qemu_irq *mst_irq_init(struct pxa2xx_state_s *cpu, uint32_t base, int irq) +{ + mst_irq_state *s; + int iomemtype; + qemu_irq *qi; + + s = (mst_irq_state *) + qemu_mallocz(sizeof(mst_irq_state)); + + if (!s) + return NULL; + s->target_base = base; + s->parent = &cpu->pic[irq]; + + /* alloc the external 16 irqs */ + qi = qemu_allocate_irqs(mst_fpga_set_irq, s, MST_NUM_IRQS); + s->pins = qi; + + iomemtype = cpu_register_io_memory(0, mst_fpga_readfn, + mst_fpga_writefn, s); + cpu_register_physical_memory(MST_BASE, 0x00100000, iomemtype); + register_savevm("mainstone_fpga", 0, 0, mst_fpga_save, mst_fpga_load, s); + return qi; +} -- cgit v1.2.3 From e4bcb14c79fb63a35aef3eb39e02c16c19b8b28d Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 04:51:10 +0000 Subject: Add -drive parameter, by Laurent Vivier. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3759 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 10 +- hw/gumstix.c | 12 +- hw/integratorcp.c | 8 +- hw/lsi53c895a.c | 3 - hw/mainstone.c | 37 ++- hw/mips_malta.c | 30 ++- hw/mips_pica61.c | 29 ++- hw/mips_r4k.c | 22 +- hw/nand.c | 8 +- hw/omap.c | 9 +- hw/pc.c | 70 ++++-- hw/pci.h | 1 + hw/ppc405_boards.c | 29 ++- hw/ppc_chrp.c | 21 +- hw/ppc_oldworld.c | 35 ++- hw/ppc_prep.c | 32 ++- hw/pxa2xx.c | 20 +- hw/realview.c | 21 +- hw/spitz.c | 9 +- hw/stellaris.c | 4 +- hw/sun4m.c | 29 ++- hw/sun4m.h | 3 +- hw/sun4u.c | 29 ++- hw/versatilepb.c | 22 +- monitor.c | 11 +- sysemu.h | 29 ++- vl.c | 655 +++++++++++++++++++++++++++++++++++++---------------- 27 files changed, 873 insertions(+), 315 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index b6c58ff71..d6af3f61f 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -50,14 +50,11 @@ do { printf("ESP: " fmt , ##args); } while (0) #define ESP_REGS 16 #define ESP_SIZE (ESP_REGS * 4) #define TI_BUFSZ 32 -/* The HBA is ID 7, so for simplicitly limit to 7 devices. */ -#define ESP_MAX_DEVS 7 typedef struct ESPState ESPState; struct ESPState { qemu_irq irq; - BlockDriverState **bd; uint8_t rregs[ESP_REGS]; uint8_t wregs[ESP_REGS]; int32_t ti_size; @@ -65,7 +62,7 @@ struct ESPState { uint8_t ti_buf[TI_BUFSZ]; int sense; int dma; - SCSIDevice *scsi_dev[MAX_DISKS]; + SCSIDevice *scsi_dev[ESP_MAX_DEVS]; SCSIDevice *current_dev; uint8_t cmdbuf[TI_BUFSZ]; int cmdlen; @@ -172,7 +169,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) s->async_len = 0; } - if (target >= MAX_DISKS || !s->scsi_dev[target]) { + if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) { // No such drive s->rregs[ESP_RSTAT] = STAT_IN; s->rregs[ESP_RINTR] = INTR_DC; @@ -621,7 +618,7 @@ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id) s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s); } -void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, +void *esp_init(target_phys_addr_t espaddr, void *dma_opaque, qemu_irq irq, qemu_irq *reset) { ESPState *s; @@ -631,7 +628,6 @@ void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, if (!s) return NULL; - s->bd = bd; s->irq = irq; s->dma_opaque = dma_opaque; diff --git a/hw/gumstix.c b/hw/gumstix.c index 15562b7b0..21325177c 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -47,6 +47,7 @@ static void connex_init(int ram_size, int vga_ram_size, const char *initrd_filename, const char *cpu_model) { struct pxa2xx_state_s *cpu; + int index; uint32_t connex_rom = 0x01000000; uint32_t connex_ram = 0x04000000; @@ -59,14 +60,15 @@ static void connex_init(int ram_size, int vga_ram_size, cpu = pxa255_init(connex_ram, ds); - if (pflash_table[0] == NULL) { + index = drive_get_index(IF_PFLASH, 0, 0); + if (index == -1) { fprintf(stderr, "A flash image must be given with the " "'pflash' parameter\n"); exit(1); } if (!pflash_register(0x00000000, qemu_ram_alloc(connex_rom), - pflash_table[0], sector_len, connex_rom / sector_len, + drives_table[index].bdrv, sector_len, connex_rom / sector_len, 2, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); exit(1); @@ -85,6 +87,7 @@ static void verdex_init(int ram_size, int vga_ram_size, const char *initrd_filename, const char *cpu_model) { struct pxa2xx_state_s *cpu; + int index; uint32_t verdex_rom = 0x02000000; uint32_t verdex_ram = 0x10000000; @@ -97,14 +100,15 @@ static void verdex_init(int ram_size, int vga_ram_size, cpu = pxa270_init(verdex_ram, ds, cpu_model ?: "pxa270-c0"); - if (pflash_table[0] == NULL) { + index = drive_get_index(IF_PFLASH, 0, 0); + if (index == -1) { fprintf(stderr, "A flash image must be given with the " "'pflash' parameter\n"); exit(1); } if (!pflash_register(0x00000000, qemu_ram_alloc(verdex_rom), - pflash_table[0], sector_len, verdex_rom / sector_len, + drives_table[index].bdrv, sector_len, verdex_rom / sector_len, 2, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); exit(1); diff --git a/hw/integratorcp.c b/hw/integratorcp.c index f1d71ff87..549cc25df 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -478,6 +478,7 @@ static void integratorcp_init(int ram_size, int vga_ram_size, uint32_t bios_offset; qemu_irq *pic; qemu_irq *cpu_pic; + int sd; if (!cpu_model) cpu_model = "arm926"; @@ -506,7 +507,12 @@ static void integratorcp_init(int ram_size, int vga_ram_size, icp_control_init(0xcb000000); pl050_init(0x18000000, pic[3], 0); pl050_init(0x19000000, pic[4], 1); - pl181_init(0x1c000000, sd_bdrv, pic[23], pic[24]); + sd = drive_get_index(IF_SD, 0, 0); + if (sd == -1) { + fprintf(stderr, "qemu: missing SecureDigital card\n"); + exit(1); + } + pl181_init(0x1c000000, drives_table[sd].bdrv, pic[23], pic[24]); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "smc91c111") == 0) { diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index c841db184..dbf67cb0c 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -151,9 +151,6 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ##args);} while (0) #define PHASE_MI 7 #define PHASE_MASK 7 -/* The HBA is ID 7, so for simplicitly limit to 7 devices. */ -#define LSI_MAX_DEVS 7 - /* Maximum length of MSG IN data. */ #define LSI_MAX_MSGIN_LEN 8 diff --git a/hw/mainstone.c b/hw/mainstone.c index 13f72b350..354015202 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -29,6 +29,7 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, uint32_t mainstone_rom = 0x00800000; struct pxa2xx_state_s *cpu; qemu_irq *mst_irq; + int index; if (!cpu_model) cpu_model = "pxa270-c5"; @@ -47,18 +48,32 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, /* Setup initial (reset) machine state */ cpu->env->regs[15] = PXA2XX_SDRAM_BASE; - /* There are two 32MiB flash devices on the board */ - if (!pflash_register(MST_FLASH_0, mainstone_ram + PXA2XX_INTERNAL_SIZE, - pflash_table[0], 256 * 1024, 128, 4, 0, 0, 0, 0)) { - fprintf(stderr, "qemu: Error register flash memory.\n"); - exit(1); - } + /* There are two 32MiB flash devices on the board */ + index = drive_get_index(IF_PFLASH, 0, 0); + if (index == -1) { + fprintf(stderr, "Two flash images must be given with the " + "'pflash' parameter\n"); + exit(1); + } + if (!pflash_register(MST_FLASH_0, mainstone_ram + PXA2XX_INTERNAL_SIZE, + drives_table[index].bdrv, + 256 * 1024, 128, 4, 0, 0, 0, 0)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + exit(1); + } - if (!pflash_register(MST_FLASH_1, mainstone_ram + PXA2XX_INTERNAL_SIZE, - pflash_table[1], 256 * 1024, 128, 4, 0, 0, 0, 0)) { - fprintf(stderr, "qemu: Error register flash memory.\n"); - exit(1); - } + index = drive_get_index(IF_PFLASH, 0, 1); + if (index == -1) { + fprintf(stderr, "Two flash images must be given with the " + "'pflash' parameter\n"); + exit(1); + } + if (!pflash_register(MST_FLASH_1, mainstone_ram + PXA2XX_INTERNAL_SIZE, + drives_table[index].bdrv, + 256 * 1024, 128, 4, 0, 0, 0, 0)) { + fprintf(stderr, "qemu: Error registering flash memory.\n"); + exit(1); + } mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0); smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index ac6800f65..6af5e52dc 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -53,6 +53,8 @@ #define ENVP_NB_ENTRIES 16 #define ENVP_ENTRY_SIZE 256 +#define MAX_IDE_BUS 2 + extern FILE *logfile; typedef struct { @@ -776,6 +778,9 @@ void mips_malta_init (int ram_size, int vga_ram_size, uint8_t *eeprom_buf; i2c_bus *smbus; int i; + int index; + BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + BlockDriverState *fd[MAX_FD]; /* init CPUs */ if (cpu_model == NULL) { @@ -862,8 +867,22 @@ void mips_malta_init (int ram_size, int vga_ram_size, pci_bus = pci_gt64120_init(i8259); /* Southbridge */ + + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\n"); + exit(1); + } + + for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { + index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); + if (index != -1) + hd[i] = drives_table[index].bdrv; + else + hd[i] = NULL; + } + piix4_devfn = piix4_init(pci_bus, 80); - pci_piix4_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259); + pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1, i8259); usb_uhci_piix4_init(pci_bus, piix4_devfn + 2); smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100); eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ @@ -883,7 +902,14 @@ void mips_malta_init (int ram_size, int vga_ram_size, serial_init(0x2f8, i8259[3], serial_hds[1]); if (parallel_hds[0]) parallel_init(0x378, i8259[7], parallel_hds[0]); - floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); + for(i = 0; i < MAX_FD; i++) { + index = drive_get_index(IF_FLOPPY, 0, i); + if (index != -1) + fd[i] = drives_table[index].bdrv; + else + fd[i] = NULL; + } + floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd); /* Sound card */ #ifdef HAS_AUDIO diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index 2a358d53e..ced0e5567 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -44,6 +44,9 @@ #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) +#define MAX_IDE_BUS 2 +#define MAX_FD 2 + static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 14, 15 }; @@ -72,6 +75,8 @@ void mips_pica61_init (int ram_size, int vga_ram_size, int i; int available_ram; qemu_irq *i8259; + int index; + BlockDriverState *fd[MAX_FD]; /* init CPUs */ if (cpu_model == NULL) { @@ -141,9 +146,20 @@ void mips_pica61_init (int ram_size, int vga_ram_size, i8042_mm_init(i8259[6], i8259[7], 0x80005060, 0); /* IDE controller */ - for(i = 0; i < 2; i++) + + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\n"); + exit(1); + } + + for(i = 0; i < MAX_IDE_BUS; i++) { + int hd0, hd1; + hd0 = drive_get_index(IF_IDE, i, 0); + hd1 = drive_get_index(IF_IDE, i, 1); isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], - bs_table[2 * i], bs_table[2 * i + 1]); + hd0 == -1 ? NULL : drives_table[hd0].bdrv, + hd1 == -1 ? NULL : drives_table[hd1].bdrv); + } /* Network controller */ /* FIXME: missing NS SONIC DP83932 */ @@ -152,7 +168,14 @@ void mips_pica61_init (int ram_size, int vga_ram_size, /* FIXME: missing NCR 53C94 */ /* ISA devices (floppy, serial, parallel) */ - fdctrl_init(i8259[1], 1, 1, 0x80003000, fd_table); + + for (i = 0; i < MAX_FD; i++) { + index = drive_get_index(IF_FLOPPY, 0, i); + if (index == -1) + continue; + fd[i] = drives_table[index].bdrv; + } + fdctrl_init(i8259[1], 1, 1, 0x80003000, fd); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { serial_mm_init(serial_base[i], 0, i8259[serial_irq[i]], serial_hds[i], 1); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index d090a2a1c..b1c0433f6 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -25,6 +25,8 @@ #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) +#define MAX_IDE_BUS 2 + static const int ide_iobase[2] = { 0x1f0, 0x170 }; static const int ide_iobase2[2] = { 0x3f6, 0x376 }; static const int ide_irq[2] = { 14, 15 }; @@ -155,6 +157,8 @@ void mips_r4k_init (int ram_size, int vga_ram_size, RTCState *rtc_state; int i; qemu_irq *i8259; + int index; + BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; /* init CPUs */ if (cpu_model == NULL) { @@ -245,9 +249,23 @@ void mips_r4k_init (int ram_size, int vga_ram_size, } } - for(i = 0; i < 2; i++) + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\n"); + exit(1); + } + + for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { + index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); + if (index != -1) + hd[i] = drives_table[index].bdrv; + else + hd[i] = NULL; + } + + for(i = 0; i < MAX_IDE_BUS; i++) isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], - bs_table[2 * i], bs_table[2 * i + 1]); + hd[MAX_IDE_DEVS * i], + hd[MAX_IDE_DEVS * i + 1]); i8042_init(i8259[1], i8259[12], 0x60); ds1225y_init(0x9000, "nvram"); diff --git a/hw/nand.c b/hw/nand.c index 925583ae4..ea353ed95 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -444,14 +444,20 @@ struct nand_flash_s *nand_init(int manf_id, int chip_id) { int pagesize; struct nand_flash_s *s; + int index; if (nand_flash_ids[chip_id].size == 0) { cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n", __FUNCTION__); } + index = drive_get_index(IF_MTD, 0, 0); + if (index == -1) { + cpu_abort(cpu_single_env, "%s: missing MTD device\n", + __FUNCTION__); + } s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s)); - s->bdrv = mtd_bdrv; + s->bdrv = drives_table[index].bdrv; s->manf_id = manf_id; s->chip_id = chip_id; s->size = nand_flash_ids[s->chip_id].size << 20; diff --git a/hw/omap.c b/hw/omap.c index c8d5064f6..c56cd2423 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -4901,6 +4901,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) qemu_mallocz(sizeof(struct omap_mpu_state_s)); ram_addr_t imif_base, emiff_base; + int index; if (!core) core = "ti925t"; @@ -4997,7 +4998,13 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); - s->mmc = omap_mmc_init(0xfffb7800, sd_bdrv, s->irq[1][OMAP_INT_OQN], + index = drive_get_index(IF_SD, 0, 0); + if (index == -1) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = omap_mmc_init(0xfffb7800, drives_table[index].bdrv, + s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck")); s->mpuio = omap_mpuio_init(0xfffb5000, diff --git a/hw/pc.c b/hw/pc.c index 7049c44a1..5f79cda98 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -42,6 +42,8 @@ /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ #define ACPI_DATA_SIZE 0x10000 +#define MAX_IDE_BUS 2 + static fdctrl_t *floppy_controller; static RTCState *rtc_state; static PITState *pit; @@ -381,8 +383,10 @@ static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) { uint8_t bootsect[512], *p; int i; + int hda; - if (bs_table[0] == NULL) { + hda = drive_get_index(IF_IDE, 0, 0); + if (hda == -1) { fprintf(stderr, "A disk image must be given for 'hda' when booting " "a Linux kernel\n"); exit(1); @@ -391,7 +395,7 @@ static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) memset(bootsect, 0, sizeof(bootsect)); /* Copy the MSDOS partition table if possible */ - bdrv_read(bs_table[0], 0, bootsect, 1); + bdrv_read(drives_table[hda].bdrv, 0, bootsect, 1); /* Make sure we have a partition signature */ bootsect[510] = 0x55; @@ -428,7 +432,7 @@ static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) *p++ = segs[1]; /* CS */ *p++ = segs[1] >> 8; - bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); + bdrv_set_boot_sector(drives_table[hda].bdrv, bootsect, sizeof(bootsect)); } static int load_kernel(const char *filename, uint8_t *addr, @@ -709,6 +713,9 @@ static void pc_init1(int ram_size, int vga_ram_size, NICInfo *nd; qemu_irq *cpu_irq; qemu_irq *i8259; + int index; + BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + BlockDriverState *fd[MAX_FD]; linux_boot = (kernel_filename != NULL); @@ -926,12 +933,25 @@ static void pc_init1(int ram_size, int vga_ram_size, } } + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\n"); + exit(1); + } + + for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { + index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); + if (index != -1) + hd[i] = drives_table[index].bdrv; + else + hd[i] = NULL; + } + if (pci_enabled) { - pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1, i8259); + pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259); } else { - for(i = 0; i < 2; i++) { + for(i = 0; i < MAX_IDE_BUS; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], - bs_table[2 * i], bs_table[2 * i + 1]); + hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); } } @@ -941,9 +961,16 @@ static void pc_init1(int ram_size, int vga_ram_size, audio_init(pci_enabled ? pci_bus : NULL, i8259); #endif - floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); + for(i = 0; i < MAX_FD; i++) { + index = drive_get_index(IF_FLOPPY, 0, i); + if (index != -1) + fd[i] = drives_table[index].bdrv; + else + fd[i] = NULL; + } + floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd); - cmos_init(ram_size, boot_device, bs_table); + cmos_init(ram_size, boot_device, hd); if (pci_enabled && usb_enabled) { usb_uhci_piix3_init(pci_bus, piix3_devfn + 2); @@ -963,23 +990,24 @@ static void pc_init1(int ram_size, int vga_ram_size, if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); } -#if 0 - /* ??? Need to figure out some way for the user to - specify SCSI devices. */ + if (pci_enabled) { + int max_bus; + int bus, unit; void *scsi; - BlockDriverState *bdrv; - scsi = lsi_scsi_init(pci_bus, -1); - bdrv = bdrv_new("scsidisk"); - bdrv_open(bdrv, "scsi_disk.img", 0); - lsi_scsi_attach(scsi, bdrv, -1); - bdrv = bdrv_new("scsicd"); - bdrv_open(bdrv, "scsi_cd.iso", 0); - bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); - lsi_scsi_attach(scsi, bdrv, -1); + max_bus = drive_get_max_bus(IF_SCSI); + + for (bus = 0; bus <= max_bus; bus++) { + scsi = lsi_scsi_init(pci_bus, -1); + for (unit = 0; unit < LSI_MAX_DEVS; unit++) { + index = drive_get_index(IF_SCSI, bus, unit); + if (index == -1) + continue; + lsi_scsi_attach(scsi, drives_table[index].bdrv, unit); + } + } } -#endif } static void pc_init_pci(int ram_size, int vga_ram_size, diff --git a/hw/pci.h b/hw/pci.h index 075754514..96bb2136d 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -97,6 +97,7 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, pci_map_irq_fn map_irq, const char *name); /* lsi53c895a.c */ +#define LSI_MAX_DEVS 7 void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *lsi_scsi_init(PCIBus *bus, int devfn); diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 91fecc877..597f9b58a 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -197,6 +197,7 @@ static void ref405ep_init (int ram_size, int vga_ram_size, int linux_boot; int fl_idx, fl_sectors, len; int ppc_boot_device = boot_device[0]; + int index; /* XXX: fix this */ ram_bases[0] = 0x00000000; @@ -223,17 +224,18 @@ static void ref405ep_init (int ram_size, int vga_ram_size, bios_offset = sram_offset + sram_size; fl_idx = 0; #ifdef USE_FLASH_BIOS - if (pflash_table[fl_idx] != NULL) { - bios_size = bdrv_getlength(pflash_table[fl_idx]); + index = drive_get_index(IF_PFLASH, 0, fl_idx); + if (index != -1) { + bios_size = bdrv_getlength(drives_table[index].bdrv); fl_sectors = (bios_size + 65535) >> 16; #ifdef DEBUG_BOARD_INIT printf("Register parallel flash %d size " ADDRX " at offset %08lx " " addr " ADDRX " '%s' %d\n", fl_idx, bios_size, bios_offset, -bios_size, - bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors); + bdrv_get_device_name(drives_table[index].bdrv), fl_sectors); #endif pflash_register((uint32_t)(-bios_size), bios_offset, - pflash_table[fl_idx], 65536, fl_sectors, 2, + drives_table[index].bdrv, 65536, fl_sectors, 2, 0x0001, 0x22DA, 0x0000, 0x0000); fl_idx++; } else @@ -519,6 +521,7 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, int linux_boot; int fl_idx, fl_sectors; int ppc_boot_device = boot_device[0]; + int index; /* RAM is soldered to the board so the size cannot be changed */ ram_bases[0] = 0x00000000; @@ -536,8 +539,9 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, #endif fl_idx = 0; #if defined(USE_FLASH_BIOS) - if (pflash_table[fl_idx] != NULL) { - bios_size = bdrv_getlength(pflash_table[fl_idx]); + index = drive_get_index(IF_PFLASH, 0, fl_idx); + if (index != -1) { + bios_size = bdrv_getlength(drives_table[index].bdrv); /* XXX: should check that size is 2MB */ // bios_size = 2 * 1024 * 1024; fl_sectors = (bios_size + 65535) >> 16; @@ -545,10 +549,10 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, printf("Register parallel flash %d size " ADDRX " at offset %08lx " " addr " ADDRX " '%s' %d\n", fl_idx, bios_size, bios_offset, -bios_size, - bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors); + bdrv_get_device_name(drives_table[index].bdrv), fl_sectors); #endif pflash_register((uint32_t)(-bios_size), bios_offset, - pflash_table[fl_idx], 65536, fl_sectors, 4, + drives_table[index].bdrv, 65536, fl_sectors, 4, 0x0001, 0x22DA, 0x0000, 0x0000); fl_idx++; } else @@ -571,8 +575,9 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, } bios_offset += bios_size; /* Register Linux flash */ - if (pflash_table[fl_idx] != NULL) { - bios_size = bdrv_getlength(pflash_table[fl_idx]); + index = drive_get_index(IF_PFLASH, 0, fl_idx); + if (index != -1) { + bios_size = bdrv_getlength(drives_table[index].bdrv); /* XXX: should check that size is 32MB */ bios_size = 32 * 1024 * 1024; fl_sectors = (bios_size + 65535) >> 16; @@ -580,9 +585,9 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, printf("Register parallel flash %d size " ADDRX " at offset %08lx " " addr " ADDRX " '%s'\n", fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000, - bdrv_get_device_name(pflash_table[fl_idx])); + bdrv_get_device_name(drives_table[index].bdrv)); #endif - pflash_register(0xfc000000, bios_offset, pflash_table[fl_idx], + pflash_register(0xfc000000, bios_offset, drives_table[index].bdrv, 65536, fl_sectors, 4, 0x0001, 0x22DA, 0x0000, 0x0000); fl_idx++; diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c index 1e3e6c4f6..4437a1038 100644 --- a/hw/ppc_chrp.c +++ b/hw/ppc_chrp.c @@ -32,6 +32,8 @@ #include "sysemu.h" #include "boards.h" +#define MAX_IDE_BUS 2 + /* UniN device */ static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { @@ -81,6 +83,8 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, int pic_mem_index, dbdma_mem_index, cuda_mem_index; int ide_mem_index[2]; int ppc_boot_device; + int index; + BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; linux_boot = (kernel_filename != NULL); @@ -266,11 +270,22 @@ static void ppc_core99_init (int ram_size, int vga_ram_size, nd_table[i].model = "ne2k_pci"; pci_nic_init(pci_bus, &nd_table[i], -1); } + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\n"); + exit(1); + } + for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { + index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); + if (index != -1) + hd[i] = drives_table[index].bdrv; + else + hd[i] = NULL; + } #if 1 - ide_mem_index[0] = pmac_ide_init(&bs_table[0], pic[0x13]); - ide_mem_index[1] = pmac_ide_init(&bs_table[2], pic[0x14]); + ide_mem_index[0] = pmac_ide_init(&hd[0], pic[0x13]); + ide_mem_index[1] = pmac_ide_init(&hd[2], pic[0x14]); #else - pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); + pci_cmd646_ide_init(pci_bus, &hd[0], 0); #endif /* cuda also initialize ADB */ cuda_init(&cuda_mem_index, pic[0x19]); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 53edcd5c6..6b4f202d0 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -33,6 +33,8 @@ #include "pci.h" #include "boards.h" +#define MAX_IDE_BUS 2 + /* temporary frame buffer OSI calls for the video.x driver. The right solution is to modify the driver to use VGA PCI I/Os */ /* XXX: to be removed. This is no way related to emulation */ @@ -123,6 +125,8 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index; int ide_mem_index[2]; int ppc_boot_device; + BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + int index; linux_boot = (kernel_filename != NULL); @@ -292,10 +296,37 @@ static void ppc_heathrow_init (int ram_size, int vga_ram_size, } /* First IDE channel is a CMD646 on the PCI bus */ - pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); + + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\n"); + exit(1); + } + index = drive_get_index(IF_IDE, 0, 0); + if (index == -1) + hd[0] = NULL; + else + hd[0] = drives_table[index].bdrv; + index = drive_get_index(IF_IDE, 0, 1); + if (index == -1) + hd[1] = NULL; + else + hd[1] = drives_table[index].bdrv; + hd[3] = hd[2] = NULL; + pci_cmd646_ide_init(pci_bus, hd, 0); + /* Second IDE channel is a MAC IDE on the MacIO bus */ + index = drive_get_index(IF_IDE, 1, 0); + if (index == -1) + hd[0] = NULL; + else + hd[0] = drives_table[index].bdrv; + index = drive_get_index(IF_IDE, 1, 1); + if (index == -1) + hd[1] = NULL; + else + hd[1] = drives_table[index].bdrv; ide_mem_index[0] = -1; - ide_mem_index[1] = pmac_ide_init(&bs_table[2], pic[0x0D]); + ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D]); /* cuda also initialize ADB */ cuda_init(&cuda_mem_index, pic[0x12]); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 8e939760d..c42688e42 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -38,6 +38,8 @@ /* SMP is not enabled, for now */ #define MAX_CPUS 1 +#define MAX_IDE_BUS 2 + #define BIOS_FILENAME "ppc_rom.bin" #define KERNEL_LOAD_ADDR 0x01000000 #define INITRD_LOAD_ADDR 0x01800000 @@ -551,6 +553,9 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, PCIBus *pci_bus; qemu_irq *i8259; int ppc_boot_device; + int index; + BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + BlockDriverState *fd[MAX_FD]; sysctrl = qemu_mallocz(sizeof(sysctrl_t)); if (sysctrl == NULL) @@ -675,16 +680,37 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, } } - for(i = 0; i < 2; i++) { + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\n"); + exit(1); + } + + for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { + index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); + if (index != -1) + hd[i] = drives_table[index].bdrv; + else + hd[i] = NULL; + } + + for(i = 0; i < MAX_IDE_BUS; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], - bs_table[2 * i], bs_table[2 * i + 1]); + hd[2 * i], + hd[2 * i + 1]); } i8042_init(i8259[1], i8259[12], 0x60); DMA_init(1); // AUD_init(); // SB16_init(); - fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); + for(i = 0; i < MAX_FD; i++) { + index = drive_get_index(IF_FLOPPY, 0, i); + if (index != -1) + fd[i] = drives_table[index].bdrv; + else + fd[i] = NULL; + } + fdctrl_init(i8259[6], 2, 0, 0x3f0, fd); /* Register speaker port */ register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 00cb2370a..a67ffefd0 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2036,6 +2036,7 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, struct pxa2xx_state_s *s; struct pxa2xx_ssp_s *ssp; int iomemtype, i; + int index; s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s)); if (revision && strncmp(revision, "pxa27", 5)) { @@ -2070,8 +2071,13 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121); - s->mmc = pxa2xx_mmci_init(0x41100000, sd_bdrv, s->pic[PXA2XX_PIC_MMC], - s->dma); + index = drive_get_index(IF_SD, 0, 0); + if (index == -1) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = pxa2xx_mmci_init(0x41100000, drives_table[index].bdrv, + s->pic[PXA2XX_PIC_MMC], s->dma); for (i = 0; pxa270_serial[i].io_base; i ++) if (serial_hds[i]) @@ -2160,6 +2166,7 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, struct pxa2xx_state_s *s; struct pxa2xx_ssp_s *ssp; int iomemtype, i; + int index; s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s)); @@ -2187,8 +2194,13 @@ struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85); - s->mmc = pxa2xx_mmci_init(0x41100000, sd_bdrv, s->pic[PXA2XX_PIC_MMC], - s->dma); + index = drive_get_index(IF_SD, 0, 0); + if (index == -1) { + fprintf(stderr, "qemu: missing SecureDigital device\n"); + exit(1); + } + s->mmc = pxa2xx_mmci_init(0x41100000, drives_table[index].bdrv, + s->pic[PXA2XX_PIC_MMC], s->dma); for (i = 0; pxa255_serial[i].io_base; i ++) if (serial_hds[i]) diff --git a/hw/realview.c b/hw/realview.c index 7e8586f4a..29579d87b 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -32,6 +32,7 @@ static void realview_init(int ram_size, int vga_ram_size, int done_smc = 0; qemu_irq cpu_irq[4]; int ncpu; + int index; if (!cpu_model) cpu_model = "arm926"; @@ -89,7 +90,12 @@ static void realview_init(int ram_size, int vga_ram_size, pl110_init(ds, 0x10020000, pic[23], 1); - pl181_init(0x10005000, sd_bdrv, pic[17], pic[18]); + index = drive_get_index(IF_SD, 0, 0); + if (index == -1) { + fprintf(stderr, "qemu: missing SecureDigital card\n"); + exit(1); + } + pl181_init(0x10005000, drives_table[index].bdrv, pic[17], pic[18]); pl031_init(0x10017000, pic[10]); @@ -97,11 +103,16 @@ static void realview_init(int ram_size, int vga_ram_size, if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); } + if (drive_get_max_bus(IF_SCSI) > 0) { + fprintf(stderr, "qemu: too many SCSI bus\n"); + exit(1); + } scsi_hba = lsi_scsi_init(pci_bus, -1); - for (n = 0; n < MAX_DISKS; n++) { - if (bs_table[n]) { - lsi_scsi_attach(scsi_hba, bs_table[n], n); - } + for (n = 0; n < LSI_MAX_DEVS; n++) { + index = drive_get_index(IF_SCSI, 0, n); + if (index == -1) + continue; + lsi_scsi_attach(scsi_hba, drives_table[index].bdrv, n); } for(n = 0; n < nb_nics; n++) { nd = &nd_table[n]; diff --git a/hw/spitz.c b/hw/spitz.c index 461a60dd8..159c63378 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -940,9 +940,14 @@ static void spitz_ssp_attach(struct pxa2xx_state_s *cpu) static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu) { struct pcmcia_card_s *md; - BlockDriverState *bs = bs_table[0]; + int index; + BlockDriverState *bs; - if (bs && bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) { + index = drive_get_index(IF_IDE, 0, 0); + if (index == -1) + return; + bs = drives_table[index].bdrv; + if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) { md = dscm1xxxx_init(bs); pxa2xx_pcmcia_attach(cpu->pcmcia[1], md); } diff --git a/hw/stellaris.c b/hw/stellaris.c index 5f06388a9..2fb927b61 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1133,9 +1133,11 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, void * oled; void * sd; void *ssi_bus; + int index; oled = ssd0323_init(ds, &gpio_out[GPIO_C][7]); - sd = ssi_sd_init(sd_bdrv); + index = drive_get_index(IF_SD, 0, 0); + sd = ssi_sd_init(drives_table[index].bdrv); ssi_bus = stellaris_ssi_bus_init(&gpio_out[GPIO_D][0], ssi_sd_xfer, sd, diff --git a/hw/sun4m.c b/hw/sun4m.c index 1f78ff893..428519a5a 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -338,6 +338,8 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, unsigned long prom_offset, kernel_size; int ret; char buf[1024]; + BlockDriverState *fd[MAX_FD]; + int index; /* init CPUs */ if (!cpu_model) @@ -440,16 +442,29 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], serial_hds[1], serial_hds[0]); - if (hwdef->fd_base != (target_phys_addr_t)-1) - sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd_table); + if (hwdef->fd_base != (target_phys_addr_t)-1) { + /* there is zero or one floppy drive */ + fd[1] = fd[0] = NULL; + index = drive_get_index(IF_FLOPPY, 0, 0); + if (index != -1) + fd[0] = drives_table[index].bdrv; - main_esp = esp_init(bs_table, hwdef->esp_base, espdma, *espdma_irq, + sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd); + } + + if (drive_get_max_bus(IF_SCSI) > 0) { + fprintf(stderr, "qemu: too many SCSI bus\n"); + exit(1); + } + + main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq, esp_reset); - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) { - esp_scsi_attach(main_esp, bs_table[i], i); - } + for (i = 0; i < ESP_MAX_DEVS; i++) { + index = drive_get_index(IF_SCSI, 0, i); + if (index == -1) + continue; + esp_scsi_attach(main_esp, drives_table[index].bdrv, i); } slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->power_base, diff --git a/hw/sun4m.h b/hw/sun4m.h index 12fa83223..e0ae5faf9 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -49,8 +49,9 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ +#define ESP_MAX_DEVS 7 void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id); -void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr, +void *esp_init(target_phys_addr_t espaddr, void *dma_opaque, qemu_irq irq, qemu_irq *reset); /* cs4231.c */ diff --git a/hw/sun4u.c b/hw/sun4u.c index 6fb7faeb3..183f64a5a 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -43,6 +43,7 @@ #define VGA_BASE (APB_MEM_BASE + 0x400000ULL) #define PROM_FILENAME "openbios-sparc64" #define NVRAM_SIZE 0x2000 +#define MAX_IDE_BUS 2 /* TSC handling */ @@ -240,6 +241,9 @@ static void sun4u_init(int ram_size, int vga_ram_size, PCIBus *pci_bus; QEMUBH *bh; qemu_irq *irq; + int index; + BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; + BlockDriverState *fd[MAX_FD]; linux_boot = (kernel_filename != NULL); @@ -342,11 +346,30 @@ static void sun4u_init(int ram_size, int vga_ram_size, } irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32); - // XXX pci_cmd646_ide_init(pci_bus, bs_table, 1); - pci_piix3_ide_init(pci_bus, bs_table, -1, irq); + if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { + fprintf(stderr, "qemu: too many IDE bus\n"); + exit(1); + } + for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { + index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); + if (index != -1) + hd[i] = drives_table[index].bdrv; + else + hd[i] = NULL; + } + + // XXX pci_cmd646_ide_init(pci_bus, hd, 1); + pci_piix3_ide_init(pci_bus, hd, -1, irq); /* FIXME: wire up interrupts. */ i8042_init(NULL/*1*/, NULL/*12*/, 0x60); - floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table); + for(i = 0; i < MAX_FD; i++) { + index = drive_get_index(IF_FLOPPY, 0, i); + if (index != -1) + fd[i] = drives_table[index].bdrv; + else + fd[i] = NULL; + } + floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd); nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59); sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_devices, KERNEL_LOAD_ADDR, kernel_size, diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 66e11bf73..da6e4ec33 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -171,6 +171,7 @@ static void versatile_init(int ram_size, int vga_ram_size, NICInfo *nd; int n; int done_smc = 0; + int index; if (!cpu_model) cpu_model = "arm926"; @@ -206,11 +207,16 @@ static void versatile_init(int ram_size, int vga_ram_size, if (usb_enabled) { usb_ohci_init_pci(pci_bus, 3, -1); } + if (drive_get_max_bus(IF_SCSI) > 0) { + fprintf(stderr, "qemu: too many SCSI bus\n"); + exit(1); + } scsi_hba = lsi_scsi_init(pci_bus, -1); - for (n = 0; n < MAX_DISKS; n++) { - if (bs_table[n]) { - lsi_scsi_attach(scsi_hba, bs_table[n], n); - } + for (n = 0; n < LSI_MAX_DEVS; n++) { + index = drive_get_index(IF_SCSI, 0, n); + if (index == -1) + continue; + lsi_scsi_attach(scsi_hba, drives_table[index].bdrv, n); } pl011_init(0x101f1000, pic[12], serial_hds[0], PL011_ARM); @@ -226,7 +232,13 @@ static void versatile_init(int ram_size, int vga_ram_size, that includes hardware cursor support from the PL111. */ pl110_init(ds, 0x10120000, pic[16], 1); - pl181_init(0x10005000, sd_bdrv, sic[22], sic[1]); + index = drive_get_index(IF_SD, 0, 0); + if (index == -1) { + fprintf(stderr, "qemu: missing SecureDigital card\n"); + exit(1); + } + + pl181_init(0x10005000, drives_table[index].bdrv, sic[22], sic[1]); #if 0 /* Disabled because there's no way of specifying a block device. */ pl181_init(0x1000b000, NULL, sic, 23, 2); diff --git a/monitor.c b/monitor.c index dd85f847d..bb05ca6ba 100644 --- a/monitor.c +++ b/monitor.c @@ -215,16 +215,11 @@ static void do_commit(const char *device) int i, all_devices; all_devices = !strcmp(device, "all"); - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) { + for (i = 0; i < nb_drives; i++) { if (all_devices || - !strcmp(bdrv_get_device_name(bs_table[i]), device)) - bdrv_commit(bs_table[i]); - } + !strcmp(bdrv_get_device_name(drives_table[i].bdrv), device)) + bdrv_commit(drives_table[i].bdrv); } - if (mtd_bdrv) - if (all_devices || !strcmp(bdrv_get_device_name(mtd_bdrv), device)) - bdrv_commit(mtd_bdrv); } static void do_info(const char *item) diff --git a/sysemu.h b/sysemu.h index d54f115aa..8bb88b12c 100644 --- a/sysemu.h +++ b/sysemu.h @@ -116,15 +116,26 @@ extern unsigned int nb_prom_envs; #define BIOS_SIZE (4 * 1024 * 1024) #endif -#define MAX_DISKS 4 - -extern BlockDriverState *bs_table[MAX_DISKS + 1]; -extern BlockDriverState *sd_bdrv; -extern BlockDriverState *mtd_bdrv; - -/* NOR flash devices */ -#define MAX_PFLASH 4 -extern BlockDriverState *pflash_table[MAX_PFLASH]; +typedef enum { + IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD +} BlockInterfaceType; + +typedef struct DriveInfo { + BlockDriverState *bdrv; + BlockInterfaceType interface; + int bus; + int unit; +} DriveInfo; + +#define MAX_IDE_DEVS 2 +#define MAX_SCSI_DEVS 7 +#define MAX_DRIVES 32 + +int nb_drives; +DriveInfo drives_table[MAX_DRIVES+1]; + +extern int drive_get_index(BlockInterfaceType interface, int bus, int unit); +extern int drive_get_max_bus(BlockInterfaceType interface); /* serial ports */ diff --git a/vl.c b/vl.c index f24c9670a..3a694c473 100644 --- a/vl.c +++ b/vl.c @@ -163,12 +163,10 @@ const char *bios_name = NULL; void *ioport_opaque[MAX_IOPORTS]; IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; -/* Note: bs_table[MAX_DISKS] is a dummy block driver if none available +/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available to store the VM snapshots */ -BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; -BlockDriverState *pflash_table[MAX_PFLASH]; -BlockDriverState *sd_bdrv; -BlockDriverState *mtd_bdrv; +DriveInfo drives_table[MAX_DRIVES+1]; +int nb_drives; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; int vga_ram_size; @@ -232,6 +230,8 @@ int alt_grab = 0; unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; #endif +int nb_drives_opt; +char drives_opt[MAX_DRIVES][1024]; #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) @@ -1758,12 +1758,9 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) case 's': { int i; - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) - bdrv_commit(bs_table[i]); + for (i = 0; i < nb_drives; i++) { + bdrv_commit(drives_table[i].bdrv); } - if (mtd_bdrv) - bdrv_commit(mtd_bdrv); } break; case 'b': @@ -4554,38 +4551,51 @@ static int net_socket_mcast_init(VLANState *vlan, const char *host_str) } +static const char *get_word(char *buf, int buf_size, const char *p) +{ + char *q; + int substring; + + substring = 0; + q = buf; + while (*p != '\0') { + if (*p == '\\') { + p++; + if (*p == '\0') + break; + } else if (*p == '\"') { + substring = !substring; + p++; + continue; + } else if (!substring && (*p == ',' || *p == '=')) + break; + if (q && (q - buf) < buf_size - 1) + *q++ = *p; + p++; + } + if (q) + *q = '\0'; + + return p; +} + static int get_param_value(char *buf, int buf_size, const char *tag, const char *str) { const char *p; - char *q; char option[128]; p = str; for(;;) { - q = option; - while (*p != '\0' && *p != '=') { - if ((q - option) < sizeof(option) - 1) - *q++ = *p; - p++; - } - *q = '\0'; + p = get_word(option, sizeof(option), p); if (*p != '=') break; p++; if (!strcmp(tag, option)) { - q = buf; - while (*p != '\0' && *p != ',') { - if ((q - buf) < buf_size - 1) - *q++ = *p; - p++; - } - *q = '\0'; - return q - buf; + (void)get_word(buf, buf_size, p); + return strlen(buf); } else { - while (*p != '\0' && *p != ',') { - p++; - } + p = get_word(NULL, 0, p); } if (*p != ',') break; @@ -4594,6 +4604,32 @@ static int get_param_value(char *buf, int buf_size, return 0; } +static int check_params(char *buf, int buf_size, + char **params, const char *str) +{ + const char *p; + int i; + + p = str; + for(;;) { + p = get_word(buf, buf_size, p); + if (*p != '=') + return -1; + p++; + for(i = 0; params[i] != NULL; i++) + if (!strcmp(params[i], buf)) + break; + if (params[i] == NULL) + return -1; + p = get_word(NULL, 0, p); + if (*p != ',') + break; + p++; + } + return 0; +} + + static int net_client_init(const char *str) { const char *p; @@ -4744,6 +4780,323 @@ void do_info_network(void) } } +#define HD_ALIAS "file=\"%s\",index=%d,media=disk" +#ifdef TARGET_PPC +#define CDROM_ALIAS "index=1,media=cdrom" +#else +#define CDROM_ALIAS "index=2,media=cdrom" +#endif +#define FD_ALIAS "index=%d,if=floppy" +#define PFLASH_ALIAS "file=\"%s\",if=pflash" +#define MTD_ALIAS "file=\"%s\",if=mtd" +#define SD_ALIAS "file=\"%s\",if=sd" + +static int drive_add(const char *fmt, ...) +{ + va_list ap; + + if (nb_drives_opt >= MAX_DRIVES) { + fprintf(stderr, "qemu: too many drives\n"); + exit(1); + } + + va_start(ap, fmt); + vsnprintf(drives_opt[nb_drives_opt], sizeof(drives_opt[0]), fmt, ap); + va_end(ap); + + return nb_drives_opt++; +} + +int drive_get_index(BlockInterfaceType interface, int bus, int unit) +{ + int index; + + /* seek interface, bus and unit */ + + for (index = 0; index < nb_drives; index++) + if (drives_table[index].interface == interface && + drives_table[index].bus == bus && + drives_table[index].unit == unit) + return index; + + return -1; +} + +int drive_get_max_bus(BlockInterfaceType interface) +{ + int max_bus; + int index; + + max_bus = -1; + for (index = 0; index < nb_drives; index++) { + if(drives_table[index].interface == interface && + drives_table[index].bus > max_bus) + max_bus = drives_table[index].bus; + } + return max_bus; +} + +static int drive_init(const char *str, int snapshot, QEMUMachine *machine) +{ + char buf[128]; + char file[1024]; + BlockInterfaceType interface; + enum { MEDIA_DISK, MEDIA_CDROM } media; + int bus_id, unit_id; + int cyls, heads, secs, translation; + BlockDriverState *bdrv; + int max_devs; + int index; + char *params[] = { "bus", "unit", "if", "index", "cyls", "heads", + "secs", "trans", "media", "snapshot", "file", NULL }; + + if (check_params(buf, sizeof(buf), params, str) < 0) { + fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n", + buf, str); + return -1; + } + + file[0] = 0; + cyls = heads = secs = 0; + bus_id = 0; + unit_id = -1; + translation = BIOS_ATA_TRANSLATION_AUTO; + index = -1; + + if (!strcmp(machine->name, "realview") || + !strcmp(machine->name, "SS-5") || + !strcmp(machine->name, "SS-10") || + !strcmp(machine->name, "SS-600MP") || + !strcmp(machine->name, "versatilepb") || + !strcmp(machine->name, "versatileab")) { + interface = IF_SCSI; + max_devs = MAX_SCSI_DEVS; + } else { + interface = IF_IDE; + max_devs = MAX_IDE_DEVS; + } + media = MEDIA_DISK; + + /* extract parameters */ + + if (get_param_value(buf, sizeof(buf), "bus", str)) { + bus_id = strtol(buf, NULL, 0); + if (bus_id < 0) { + fprintf(stderr, "qemu: '%s' invalid bus id\n", str); + return -1; + } + } + + if (get_param_value(buf, sizeof(buf), "unit", str)) { + unit_id = strtol(buf, NULL, 0); + if (unit_id < 0) { + fprintf(stderr, "qemu: '%s' invalid unit id\n", str); + return -1; + } + } + + if (get_param_value(buf, sizeof(buf), "if", str)) { + if (!strcmp(buf, "ide")) { + interface = IF_IDE; + max_devs = MAX_IDE_DEVS; + } else if (!strcmp(buf, "scsi")) { + interface = IF_SCSI; + max_devs = MAX_SCSI_DEVS; + } else if (!strcmp(buf, "floppy")) { + interface = IF_FLOPPY; + max_devs = 0; + } else if (!strcmp(buf, "pflash")) { + interface = IF_PFLASH; + max_devs = 0; + } else if (!strcmp(buf, "mtd")) { + interface = IF_MTD; + max_devs = 0; + } else if (!strcmp(buf, "sd")) { + interface = IF_SD; + max_devs = 0; + } else { + fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf); + return -1; + } + } + + if (get_param_value(buf, sizeof(buf), "index", str)) { + index = strtol(buf, NULL, 0); + if (index < 0) { + fprintf(stderr, "qemu: '%s' invalid index\n", str); + return -1; + } + } + + if (get_param_value(buf, sizeof(buf), "cyls", str)) { + cyls = strtol(buf, NULL, 0); + } + + if (get_param_value(buf, sizeof(buf), "heads", str)) { + heads = strtol(buf, NULL, 0); + } + + if (get_param_value(buf, sizeof(buf), "secs", str)) { + secs = strtol(buf, NULL, 0); + } + + if (cyls || heads || secs) { + if (cyls < 1 || cyls > 16383) { + fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str); + return -1; + } + if (heads < 1 || heads > 16) { + fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str); + return -1; + } + if (secs < 1 || secs > 63) { + fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str); + return -1; + } + } + + if (get_param_value(buf, sizeof(buf), "trans", str)) { + if (!cyls) { + fprintf(stderr, + "qemu: '%s' trans must be used with cyls,heads and secs\n", + str); + return -1; + } + if (!strcmp(buf, "none")) + translation = BIOS_ATA_TRANSLATION_NONE; + else if (!strcmp(buf, "lba")) + translation = BIOS_ATA_TRANSLATION_LBA; + else if (!strcmp(buf, "auto")) + translation = BIOS_ATA_TRANSLATION_AUTO; + else { + fprintf(stderr, "qemu: '%s' invalid translation type\n", str); + return -1; + } + } + + if (get_param_value(buf, sizeof(buf), "media", str)) { + if (!strcmp(buf, "disk")) { + media = MEDIA_DISK; + } else if (!strcmp(buf, "cdrom")) { + if (cyls || secs || heads) { + fprintf(stderr, + "qemu: '%s' invalid physical CHS format\n", str); + return -1; + } + media = MEDIA_CDROM; + } else { + fprintf(stderr, "qemu: '%s' invalid media\n", str); + return -1; + } + } + + if (get_param_value(buf, sizeof(buf), "snapshot", str)) { + if (!strcmp(buf, "on")) + snapshot = 1; + else if (!strcmp(buf, "off")) + snapshot = 0; + else { + fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str); + return -1; + } + } + + get_param_value(file, sizeof(file), "file", str); + + /* compute bus and unit according index */ + + if (index != -1) { + if (bus_id != 0 || unit_id != -1) { + fprintf(stderr, + "qemu: '%s' index cannot be used with bus and unit\n", str); + return -1; + } + if (max_devs == 0) + { + unit_id = index; + bus_id = 0; + } else { + unit_id = index % max_devs; + bus_id = index / max_devs; + } + } + + /* if user doesn't specify a unit_id, + * try to find the first free + */ + + if (unit_id == -1) { + unit_id = 0; + while (drive_get_index(interface, bus_id, unit_id) != -1) { + unit_id++; + if (max_devs && unit_id >= max_devs) { + unit_id -= max_devs; + bus_id++; + } + } + } + + /* check unit id */ + + if (max_devs && unit_id >= max_devs) { + fprintf(stderr, "qemu: '%s' unit %d too big (max is %d)\n", + str, unit_id, max_devs - 1); + return -1; + } + + /* + * ignore multiple definitions + */ + + if (drive_get_index(interface, bus_id, unit_id) != -1) + return 0; + + /* init */ + + snprintf(buf, sizeof(buf), "drive%d", nb_drives); + bdrv = bdrv_new(buf); + drives_table[nb_drives].bdrv = bdrv; + drives_table[nb_drives].interface = interface; + drives_table[nb_drives].bus = bus_id; + drives_table[nb_drives].unit = unit_id; + nb_drives++; + + switch(interface) { + case IF_IDE: + case IF_SCSI: + switch(media) { + case MEDIA_DISK: + if (cyls != 0) { + bdrv_set_geometry_hint(bdrv, cyls, heads, secs); + bdrv_set_translation_hint(bdrv, translation); + } + break; + case MEDIA_CDROM: + bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); + break; + } + break; + case IF_SD: + /* FIXME: This isn't really a floppy, but it's a reasonable + approximation. */ + case IF_FLOPPY: + bdrv_set_type_hint(bdrv, BDRV_TYPE_FLOPPY); + break; + case IF_PFLASH: + case IF_MTD: + break; + } + if (!file[0]) + return 0; + if (bdrv_open(bdrv, file, snapshot ? BDRV_O_SNAPSHOT : 0) < 0 || + qemu_key_check(bdrv, file)) { + fprintf(stderr, "qemu: could not open disk image %s\n", + file); + return -1; + } + return 0; +} + /***********************************************************/ /* USB devices */ @@ -5526,8 +5879,8 @@ static BlockDriverState *get_bs_snapshots(void) if (bs_snapshots) return bs_snapshots; - for(i = 0; i <= MAX_DISKS; i++) { - bs = bs_table[i]; + for(i = 0; i <= nb_drives; i++) { + bs = drives_table[i].bdrv; if (bdrv_can_snapshot(bs)) goto ok; } @@ -5635,8 +5988,8 @@ void do_savevm(const char *name) /* create the snapshots */ - for(i = 0; i < MAX_DISKS; i++) { - bs1 = bs_table[i]; + for(i = 0; i < nb_drives; i++) { + bs1 = drives_table[i].bdrv; if (bdrv_has_snapshot(bs1)) { if (must_delete) { ret = bdrv_snapshot_delete(bs1, old_sn->id_str); @@ -5678,8 +6031,8 @@ void do_loadvm(const char *name) saved_vm_running = vm_running; vm_stop(0); - for(i = 0; i <= MAX_DISKS; i++) { - bs1 = bs_table[i]; + for(i = 0; i <= nb_drives; i++) { + bs1 = drives_table[i].bdrv; if (bdrv_has_snapshot(bs1)) { ret = bdrv_snapshot_goto(bs1, name); if (ret < 0) { @@ -5739,8 +6092,8 @@ void do_delvm(const char *name) return; } - for(i = 0; i <= MAX_DISKS; i++) { - bs1 = bs_table[i]; + for(i = 0; i <= nb_drives; i++) { + bs1 = drives_table[i].bdrv; if (bdrv_has_snapshot(bs1)) { ret = bdrv_snapshot_delete(bs1, name); if (ret < 0) { @@ -5768,8 +6121,8 @@ void do_info_snapshots(void) return; } term_printf("Snapshot devices:"); - for(i = 0; i <= MAX_DISKS; i++) { - bs1 = bs_table[i]; + for(i = 0; i <= nb_drives; i++) { + bs1 = drives_table[i].bdrv; if (bdrv_has_snapshot(bs1)) { if (bs == bs1) term_printf(" %s", bdrv_get_device_name(bs1)); @@ -6519,15 +6872,14 @@ static void ram_save(QEMUFile *f, void *opaque) /* find if the memory block is available on a virtual block device */ sector_num = -1; - for(j = 0; j < MAX_DISKS; j++) { - if (bs_table[j]) { - sector_num = bdrv_hash_find(bs_table[j], - phys_ram_base + i, BDRV_HASH_BLOCK_SIZE); - if (sector_num >= 0) - break; - } + for(j = 0; j < nb_drives; j++) { + sector_num = bdrv_hash_find(drives_table[j].bdrv, + phys_ram_base + i, + BDRV_HASH_BLOCK_SIZE); + if (sector_num >= 0) + break; } - if (j == MAX_DISKS) + if (j == nb_drives) goto normal_compress; buf[0] = 1; buf[1] = j; @@ -6578,11 +6930,12 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) ram_decompress_buf(s, buf + 1, 9); bs_index = buf[1]; sector_num = be64_to_cpupu((const uint64_t *)(buf + 2)); - if (bs_index >= MAX_DISKS || bs_table[bs_index] == NULL) { + if (bs_index >= nb_drives) { fprintf(stderr, "Invalid block device index %d\n", bs_index); goto error; } - if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i, + if (bdrv_read(drives_table[bs_index].bdrv, sector_num, + phys_ram_base + i, BDRV_HASH_BLOCK_SIZE / 512) < 0) { fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n", bs_index, sector_num); @@ -7079,6 +7432,9 @@ static void help(int exitcode) "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n" "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" + "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i]\n" + " [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]\n" + " use 'file' as a drive image\n" "-mtdblock file use 'file' as on-board Flash memory image\n" "-sd file use 'file' as SecureDigital card image\n" "-pflash file use 'file' as a parallel flash image\n" @@ -7224,6 +7580,7 @@ enum { QEMU_OPTION_hdb, QEMU_OPTION_hdc, QEMU_OPTION_hdd, + QEMU_OPTION_drive, QEMU_OPTION_cdrom, QEMU_OPTION_mtdblock, QEMU_OPTION_sd, @@ -7313,6 +7670,7 @@ const QEMUOption qemu_options[] = { { "hdb", HAS_ARG, QEMU_OPTION_hdb }, { "hdc", HAS_ARG, QEMU_OPTION_hdc }, { "hdd", HAS_ARG, QEMU_OPTION_hdd }, + { "drive", HAS_ARG, QEMU_OPTION_drive }, { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, { "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock }, { "sd", HAS_ARG, QEMU_OPTION_sd }, @@ -7425,16 +7783,9 @@ int qemu_key_check(BlockDriverState *bs, const char *name) static BlockDriverState *get_bdrv(int index) { - BlockDriverState *bs; - - if (index < 4) { - bs = bs_table[index]; - } else if (index < 6) { - bs = fd_table[index - 4]; - } else { - bs = NULL; - } - return bs; + if (index > nb_drives) + return NULL; + return drives_table[index].bdrv; } static void read_passwords(void) @@ -7637,19 +7988,16 @@ int main(int argc, char **argv) const char *gdbstub_port; #endif uint32_t boot_devices_bitmap = 0; - int i, cdrom_index, pflash_index; + int i; int snapshot, linux_boot, net_boot; const char *initrd_filename; - const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; - const char *pflash_filename[MAX_PFLASH]; - const char *sd_filename; - const char *mtd_filename; const char *kernel_filename, *kernel_cmdline; const char *boot_devices = ""; DisplayState *ds = &display_state; int cyls, heads, secs, translation; char net_clients[MAX_NET_CLIENTS][256]; int nb_net_clients; + int hda_index; int optind; const char *r, *optarg; CharDriverState *monitor_hd; @@ -7702,15 +8050,6 @@ int main(int argc, char **argv) machine = first_machine; cpu_model = NULL; initrd_filename = NULL; - for(i = 0; i < MAX_FD; i++) - fd_filename[i] = NULL; - for(i = 0; i < MAX_DISKS; i++) - hd_filename[i] = NULL; - for(i = 0; i < MAX_PFLASH; i++) - pflash_filename[i] = NULL; - pflash_index = 0; - sd_filename = NULL; - mtd_filename = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; #ifdef CONFIG_GDBSTUB @@ -7721,11 +8060,6 @@ int main(int argc, char **argv) nographic = 0; kernel_filename = NULL; kernel_cmdline = ""; -#ifdef TARGET_PPC - cdrom_index = 1; -#else - cdrom_index = 2; -#endif cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); @@ -7743,6 +8077,9 @@ int main(int argc, char **argv) usb_devices_index = 0; nb_net_clients = 0; + nb_drives = 0; + nb_drives_opt = 0; + hda_index = -1; nb_nics = 0; /* default mac address of the first network interface */ @@ -7753,7 +8090,7 @@ int main(int argc, char **argv) break; r = argv[optind]; if (r[0] != '-') { - hd_filename[0] = argv[optind++]; + hda_index = drive_add(HD_ALIAS, argv[optind++], 0); } else { const QEMUOption *popt; @@ -7813,29 +8150,33 @@ int main(int argc, char **argv) initrd_filename = optarg; break; case QEMU_OPTION_hda: + if (cyls == 0) + hda_index = drive_add(HD_ALIAS, optarg, 0); + else + hda_index = drive_add(HD_ALIAS + ",cyls=%d,heads=%d,secs=%d%s", + optarg, 0, cyls, heads, secs, + translation == BIOS_ATA_TRANSLATION_LBA ? + ",trans=lba" : + translation == BIOS_ATA_TRANSLATION_NONE ? + ",trans=none" : ""); + break; case QEMU_OPTION_hdb: case QEMU_OPTION_hdc: case QEMU_OPTION_hdd: - { - int hd_index; - hd_index = popt->index - QEMU_OPTION_hda; - hd_filename[hd_index] = optarg; - if (hd_index == cdrom_index) - cdrom_index = -1; - } + drive_add(HD_ALIAS, optarg, popt->index - QEMU_OPTION_hda); break; + case QEMU_OPTION_drive: + drive_add("%s", optarg); + break; case QEMU_OPTION_mtdblock: - mtd_filename = optarg; + drive_add(MTD_ALIAS, optarg); break; case QEMU_OPTION_sd: - sd_filename = optarg; + drive_add(SD_ALIAS, optarg); break; case QEMU_OPTION_pflash: - if (pflash_index >= MAX_PFLASH) { - fprintf(stderr, "qemu: too many parallel flash images\n"); - exit(1); - } - pflash_filename[pflash_index++] = optarg; + drive_add(PFLASH_ALIAS, optarg); break; case QEMU_OPTION_snapshot: snapshot = 1; @@ -7874,6 +8215,17 @@ int main(int argc, char **argv) fprintf(stderr, "qemu: invalid physical CHS format\n"); exit(1); } + if (hda_index != -1) + snprintf(drives_opt[hda_index] + + strlen(drives_opt[hda_index]), + sizeof(drives_opt[0]) - + strlen(drives_opt[hda_index]), + ",cyls=%d,heads=%d,secs=%d%s", + cyls, heads, secs, + translation == BIOS_ATA_TRANSLATION_LBA ? + ",trans=lba" : + translation == BIOS_ATA_TRANSLATION_NONE ? + ",trans=none" : ""); } break; case QEMU_OPTION_nographic: @@ -7892,9 +8244,7 @@ int main(int argc, char **argv) kernel_cmdline = optarg; break; case QEMU_OPTION_cdrom: - if (cdrom_index >= 0) { - hd_filename[cdrom_index] = optarg; - } + drive_add("file=\"%s\"," CDROM_ALIAS, optarg); break; case QEMU_OPTION_boot: boot_devices = optarg; @@ -7928,10 +8278,9 @@ int main(int argc, char **argv) } break; case QEMU_OPTION_fda: - fd_filename[0] = optarg; - break; case QEMU_OPTION_fdb: - fd_filename[1] = optarg; + drive_add("file=\"%s\"," FD_ALIAS, optarg, + popt->index - QEMU_OPTION_fda); break; #ifdef TARGET_I386 case QEMU_OPTION_no_fd_bootchk: @@ -8312,20 +8661,12 @@ int main(int argc, char **argv) /* XXX: this should not be: some embedded targets just have flash */ if (!linux_boot && net_boot == 0 && - hd_filename[0] == NULL && - (cdrom_index >= 0 && hd_filename[cdrom_index] == NULL) && - fd_filename[0] == NULL && - pflash_filename[0] == NULL) + nb_drives_opt == 0) help(1); /* boot to floppy or the default cd if no hard disk defined yet */ if (!boot_devices[0]) { - if (hd_filename[0] != NULL) - boot_devices = "c"; - else if (fd_filename[0] != NULL) - boot_devices = "a"; - else - boot_devices = "d"; + boot_devices = "cad"; } setvbuf(stdout, NULL, _IOLBF, 0); @@ -8402,97 +8743,23 @@ int main(int argc, char **argv) exit(1); } - /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); - if (cdrom_index >= 0) { - bs_table[cdrom_index] = bdrv_new("cdrom"); - bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); - } - /* open the virtual block devices */ - for(i = 0; i < MAX_DISKS; i++) { - if (hd_filename[i]) { - if (!bs_table[i]) { - char buf[64]; - snprintf(buf, sizeof(buf), "hd%c", i + 'a'); - bs_table[i] = bdrv_new(buf); - } - if (bdrv_open(bs_table[i], hd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { - fprintf(stderr, "qemu: could not open hard disk image '%s'\n", - hd_filename[i]); - exit(1); - } - if (i == 0 && cyls != 0) { - bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); - bdrv_set_translation_hint(bs_table[i], translation); - } - } - } + /* we always create the cdrom drive, even if no disk is there */ - /* we always create at least one floppy disk */ - fd_table[0] = bdrv_new("fda"); - bdrv_set_type_hint(fd_table[0], BDRV_TYPE_FLOPPY); + if (nb_drives_opt < MAX_DRIVES) + drive_add(CDROM_ALIAS); - for(i = 0; i < MAX_FD; i++) { - if (fd_filename[i]) { - if (!fd_table[i]) { - char buf[64]; - snprintf(buf, sizeof(buf), "fd%c", i + 'a'); - fd_table[i] = bdrv_new(buf); - bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY); - } - if (fd_filename[i][0] != '\0') { - if (bdrv_open(fd_table[i], fd_filename[i], - snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { - fprintf(stderr, "qemu: could not open floppy disk image '%s'\n", - fd_filename[i]); - exit(1); - } - } - } - } + /* we always create at least on floppy */ - /* Open the virtual parallel flash block devices */ - for(i = 0; i < MAX_PFLASH; i++) { - if (pflash_filename[i]) { - if (!pflash_table[i]) { - char buf[64]; - snprintf(buf, sizeof(buf), "fl%c", i + 'a'); - pflash_table[i] = bdrv_new(buf); - } - if (bdrv_open(pflash_table[i], pflash_filename[i], - snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { - fprintf(stderr, "qemu: could not open flash image '%s'\n", - pflash_filename[i]); - exit(1); - } - } - } + if (nb_drives_opt < MAX_DRIVES) + drive_add(FD_ALIAS, 0); - sd_bdrv = bdrv_new ("sd"); - /* FIXME: This isn't really a floppy, but it's a reasonable - approximation. */ - bdrv_set_type_hint(sd_bdrv, BDRV_TYPE_FLOPPY); - if (sd_filename) { - if (bdrv_open(sd_bdrv, sd_filename, - snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { - fprintf(stderr, "qemu: could not open SD card image %s\n", - sd_filename); - } else - qemu_key_check(sd_bdrv, sd_filename); - } - - if (mtd_filename) { - mtd_bdrv = bdrv_new ("mtd"); - if (bdrv_open(mtd_bdrv, mtd_filename, - snapshot ? BDRV_O_SNAPSHOT : 0) < 0 || - qemu_key_check(mtd_bdrv, mtd_filename)) { - fprintf(stderr, "qemu: could not open Flash image %s\n", - mtd_filename); - bdrv_delete(mtd_bdrv); - mtd_bdrv = 0; - } - } + /* open the virtual block devices */ + + for(i = 0; i < nb_drives_opt; i++) + if (drive_init(drives_opt[i], snapshot, machine) == -1) + exit(1); register_savevm("timer", 0, 2, timer_save, timer_load, NULL); register_savevm("ram", 0, 2, ram_save, ram_load, NULL); -- cgit v1.2.3 From a36e69ddfe8452211bcf3ed94716c60bce5ccd8c Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 05:18:19 +0000 Subject: Collecting block device statistics, by Richard W.M. Jones. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3760 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- block.h | 1 + block_int.h | 6 ++++++ monitor.c | 7 +++++++ 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index ca8d8c1e8..3cb3cc22d 100644 --- a/block.c +++ b/block.c @@ -521,8 +521,11 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, return ret; else if (ret != len) return -EINVAL; - else + else { + bs->rd_bytes += (unsigned) len; + bs->rd_ops ++; return 0; + } } else { return drv->bdrv_read(bs, sector_num, buf, nb_sectors); } @@ -553,8 +556,11 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, return ret; else if (ret != len) return -EIO; - else + else { + bs->wr_bytes += (unsigned) len; + bs->wr_ops ++; return 0; + } } else { return drv->bdrv_write(bs, sector_num, buf, nb_sectors); } @@ -902,6 +908,24 @@ void bdrv_info(void) term_printf("\n"); } } + +/* The "info blockstats" command. */ +void bdrv_info_stats (void) +{ + BlockDriverState *bs; + + for (bs = bdrv_first; bs != NULL; bs = bs->next) { + term_printf ("%s:" + " rd_bytes=%" PRIu64 + " wr_bytes=%" PRIu64 + " rd_operations=%" PRIu64 + " wr_operations=%" PRIu64 + "\n", + bs->device_name, + bs->rd_bytes, bs->wr_bytes, + bs->rd_ops, bs->wr_ops); + } +} #endif void bdrv_get_backing_filename(BlockDriverState *bs, @@ -1064,6 +1088,7 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, BlockDriverCompletionFunc *cb, void *opaque) { BlockDriver *drv = bs->drv; + BlockDriverAIOCB *ret; if (!drv) return NULL; @@ -1076,7 +1101,15 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, buf += 512; } - return drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque); + ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque); + + if (ret) { + /* Update stats even though technically transfer has not happened. */ + bs->rd_bytes += (unsigned) nb_sectors * SECTOR_SIZE; + bs->rd_ops ++; + } + + return ret; } BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, @@ -1084,6 +1117,7 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, BlockDriverCompletionFunc *cb, void *opaque) { BlockDriver *drv = bs->drv; + BlockDriverAIOCB *ret; if (!drv) return NULL; @@ -1093,7 +1127,15 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, memcpy(bs->boot_sector_data, buf, 512); } - return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); + ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); + + if (ret) { + /* Update stats even though technically transfer has not happened. */ + bs->wr_bytes += (unsigned) nb_sectors * SECTOR_SIZE; + bs->wr_ops ++; + } + + return ret; } void bdrv_aio_cancel(BlockDriverAIOCB *acb) diff --git a/block.h b/block.h index 27f1e5c9b..f98639a89 100644 --- a/block.h +++ b/block.h @@ -47,6 +47,7 @@ typedef struct QEMUSnapshotInfo { #ifndef QEMU_IMG void bdrv_info(void); +void bdrv_info_stats(void); #endif void bdrv_init(void); diff --git a/block_int.h b/block_int.h index 2c5f168f6..9463ea3aa 100644 --- a/block_int.h +++ b/block_int.h @@ -114,6 +114,12 @@ struct BlockDriverState { void *sync_aiocb; + /* I/O stats (display with "info blockstats"). */ + uint64_t rd_bytes; + uint64_t wr_bytes; + uint64_t rd_ops; + uint64_t wr_ops; + /* NOTE: the following infos are only hints for real hardware drivers. They are not used by the block driver */ int cyls, heads, secs, translation; diff --git a/monitor.c b/monitor.c index bb05ca6ba..3c4694c78 100644 --- a/monitor.c +++ b/monitor.c @@ -255,6 +255,11 @@ static void do_info_block(void) bdrv_info(); } +static void do_info_blockstats(void) +{ + bdrv_info_stats(); +} + /* get the current CPU defined by the user */ static int mon_set_cpu(int cpu_index) { @@ -1327,6 +1332,8 @@ static term_cmd_t info_cmds[] = { "", "show the network state" }, { "block", "", do_info_block, "", "show the block devices" }, + { "blockstats", "", do_info_blockstats, + "", "show block device statistics" }, { "registers", "", do_info_registers, "", "show the cpu registers" }, { "cpus", "", do_info_cpus, -- cgit v1.2.3 From 823029f909b3666660418387d48ea6a207f23f26 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 06:10:04 +0000 Subject: SH4 delay slot code update, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3761 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 4 +- target-sh4/cpu.h | 18 ++++---- target-sh4/op.c | 54 +++++++---------------- target-sh4/translate.c | 117 ++++++++++++++++++++++++++++++------------------- translate-all.c | 5 ++- 5 files changed, 104 insertions(+), 94 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index bab71ee28..e8b93a832 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -202,8 +202,8 @@ static inline TranslationBlock *tb_find_fast(void) cs_base = 0; pc = env->pc; #elif defined(TARGET_SH4) - flags = env->sr & (SR_MD | SR_RB); - cs_base = 0; /* XXXXX */ + flags = env->flags; + cs_base = 0; pc = env->pc; #elif defined(TARGET_ALPHA) flags = env->ps; diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 79701306c..f9ecbb271 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -46,16 +46,16 @@ #define FPSCR_SZ (1 << 20) #define FPSCR_PR (1 << 19) #define FPSCR_DN (1 << 18) - -#define DELAY_SLOT (1 << 0) /* Must be the same as SR_T. */ -/* This flag is set if the next insn is a delay slot for a conditional jump. - The dynamic value of the DELAY_SLOT determines whether the jup is taken. */ +#define DELAY_SLOT (1 << 0) #define DELAY_SLOT_CONDITIONAL (1 << 1) -/* Those are used in contexts only */ -#define BRANCH (1 << 2) -#define BRANCH_CONDITIONAL (1 << 3) -#define MODE_CHANGE (1 << 4) /* Potential MD|RB change */ -#define BRANCH_EXCEPTION (1 << 5) /* Branch after exception */ +#define DELAY_SLOT_TRUE (1 << 2) +#define DELAY_SLOT_CLEARME (1 << 3) +/* The dynamic value of the DELAY_SLOT_TRUE flag determines whether the jump + * after the delay slot should be taken or not. It is calculated from SR_T. + * + * It is unclear if it is permitted to modify the SR_T flag in a delay slot. + * The use of DELAY_SLOT_TRUE flag makes us accept such SR_T modification. + */ /* XXXXX The structure could be made more compact */ typedef struct tlb_t { diff --git a/target-sh4/op.c b/target-sh4/op.c index 0902fca35..0dcec4906 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -19,16 +19,6 @@ */ #include "exec.h" -static inline void set_flag(uint32_t flag) -{ - env->flags |= flag; -} - -static inline void clr_flag(uint32_t flag) -{ - env->flags &= ~flag; -} - static inline void set_t(void) { env->sr |= SR_T; @@ -110,28 +100,37 @@ void OPPROTO op_not_T0(void) void OPPROTO op_bf_s(void) { env->delayed_pc = PARAM1; - set_flag(DELAY_SLOT_CONDITIONAL | ((~env->sr) & SR_T)); + if (!(env->sr & SR_T)) { + env->flags |= DELAY_SLOT_TRUE; + } RETURN(); } void OPPROTO op_bt_s(void) { env->delayed_pc = PARAM1; - set_flag(DELAY_SLOT_CONDITIONAL | (env->sr & SR_T)); + if (env->sr & SR_T) { + env->flags |= DELAY_SLOT_TRUE; + } + RETURN(); +} + +void OPPROTO op_store_flags(void) +{ + env->flags &= DELAY_SLOT_TRUE; + env->flags |= PARAM1; RETURN(); } void OPPROTO op_bra(void) { env->delayed_pc = PARAM1; - set_flag(DELAY_SLOT); RETURN(); } void OPPROTO op_braf_T0(void) { env->delayed_pc = PARAM1 + T0; - set_flag(DELAY_SLOT); RETURN(); } @@ -139,7 +138,6 @@ void OPPROTO op_bsr(void) { env->pr = PARAM1; env->delayed_pc = PARAM2; - set_flag(DELAY_SLOT); RETURN(); } @@ -147,7 +145,6 @@ void OPPROTO op_bsrf_T0(void) { env->pr = PARAM1; env->delayed_pc = PARAM1 + T0; - set_flag(DELAY_SLOT); RETURN(); } @@ -155,26 +152,12 @@ void OPPROTO op_jsr_T0(void) { env->pr = PARAM1; env->delayed_pc = T0; - set_flag(DELAY_SLOT); RETURN(); } void OPPROTO op_rts(void) { env->delayed_pc = env->pr; - set_flag(DELAY_SLOT); - RETURN(); -} - -void OPPROTO op_clr_delay_slot(void) -{ - clr_flag(DELAY_SLOT); - RETURN(); -} - -void OPPROTO op_clr_delay_slot_conditional(void) -{ - clr_flag(DELAY_SLOT_CONDITIONAL); RETURN(); } @@ -242,7 +225,6 @@ void OPPROTO op_rte(void) { env->sr = env->ssr; env->delayed_pc = env->spc; - set_flag(DELAY_SLOT); RETURN(); } @@ -458,7 +440,6 @@ void OPPROTO op_cmp_pz_T0(void) void OPPROTO op_jmp_T0(void) { env->delayed_pc = T0; - set_flag(DELAY_SLOT); RETURN(); } @@ -993,11 +974,10 @@ void OPPROTO op_jT(void) void OPPROTO op_jdelayed(void) { - uint32_t flags; - flags = env->flags; - env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); - if (flags & DELAY_SLOT) - GOTO_LABEL_PARAM(1); + if (env->flags & DELAY_SLOT_TRUE) { + env->flags &= ~DELAY_SLOT_TRUE; + GOTO_LABEL_PARAM(1); + } RETURN(); } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 70b4837a9..802f926ca 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -57,11 +57,21 @@ typedef struct DisasContext { uint32_t fpscr; uint16_t opcode; uint32_t flags; + int bstate; int memidx; uint32_t delayed_pc; int singlestep_enabled; } DisasContext; +enum { + BS_NONE = 0, /* We go out of the TB without reaching a branch or an + * exception condition + */ + BS_STOP = 1, /* We want to stop translation for any reason */ + BS_BRANCH = 2, /* We reached a branch condition */ + BS_EXCP = 3, /* We reached an exception condition */ +}; + #ifdef CONFIG_USER_ONLY #define GEN_OP_LD(width, reg) \ @@ -176,15 +186,6 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) gen_op_exit_tb(); } -/* Jump to pc after an exception */ -static void gen_jump_exception(DisasContext * ctx) -{ - gen_op_movl_imm_T0(0); - if (ctx->singlestep_enabled) - gen_op_debug(); - gen_op_exit_tb(); -} - static void gen_jump(DisasContext * ctx) { if (ctx->delayed_pc == (uint32_t) - 1) { @@ -220,7 +221,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) l1 = gen_new_label(); gen_op_jdelayed(l1); - gen_goto_tb(ctx, 1, ctx->pc); + gen_goto_tb(ctx, 1, ctx->pc + 2); gen_set_label(l1); gen_jump(ctx); } @@ -248,10 +249,10 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) #define CHECK_NOT_DELAY_SLOT \ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ - {gen_op_raise_slot_illegal_instruction (); ctx->flags |= BRANCH_EXCEPTION; \ + {gen_op_raise_slot_illegal_instruction (); ctx->bstate = BS_EXCP; \ return;} -void decode_opc(DisasContext * ctx) +void _decode_opc(DisasContext * ctx) { #if 0 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); @@ -290,11 +291,11 @@ void decode_opc(DisasContext * ctx) return; case 0xfbfb: /* frchg */ gen_op_frchg(); - ctx->flags |= MODE_CHANGE; + ctx->bstate = BS_STOP; return; case 0xf3fb: /* fschg */ gen_op_fschg(); - ctx->flags |= MODE_CHANGE; + ctx->bstate = BS_STOP; return; case 0x0009: /* nop */ return; @@ -805,7 +806,7 @@ void decode_opc(DisasContext * ctx) CHECK_NOT_DELAY_SLOT gen_conditional_jump(ctx, ctx->pc + 2, ctx->pc + 4 + B7_0s * 2); - ctx->flags |= BRANCH_CONDITIONAL; + ctx->bstate = BS_BRANCH; return; case 0x8f00: /* bf/s label */ CHECK_NOT_DELAY_SLOT @@ -816,7 +817,7 @@ void decode_opc(DisasContext * ctx) CHECK_NOT_DELAY_SLOT gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, ctx->pc + 2); - ctx->flags |= BRANCH_CONDITIONAL; + ctx->bstate = BS_BRANCH; return; case 0x8d00: /* bt/s label */ CHECK_NOT_DELAY_SLOT @@ -908,7 +909,7 @@ void decode_opc(DisasContext * ctx) case 0xc300: /* trapa #imm */ CHECK_NOT_DELAY_SLOT gen_op_movl_imm_PC(ctx->pc); gen_op_trapa(B7_0); - ctx->flags |= BRANCH; + ctx->bstate = BS_BRANCH; return; case 0xc800: /* tst #imm,R0 */ gen_op_tst_imm_rN(B7_0, REG(0)); @@ -1012,8 +1013,8 @@ void decode_opc(DisasContext * ctx) gen_op_movl_rN_T1 (REG(B11_8)); \ gen_op_stl_T0_T1 (ctx); \ return; - LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |= - MODE_CHANGE;) + LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->bstate = + BS_STOP;) LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,) LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,) LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,) @@ -1023,8 +1024,8 @@ void decode_opc(DisasContext * ctx) LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,) LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,) LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,) - LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |= - MODE_CHANGE;) + LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->bstate = + BS_STOP;) case 0x00c3: /* movca.l R0,@Rm */ gen_op_movl_rN_T0(REG(0)); gen_op_movl_rN_T1(REG(B11_8)); @@ -1141,7 +1142,28 @@ void decode_opc(DisasContext * ctx) fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", ctx->opcode, ctx->pc); gen_op_raise_illegal_instruction(); - ctx->flags |= BRANCH_EXCEPTION; + ctx->bstate = BS_EXCP; +} + +void decode_opc(DisasContext * ctx) +{ + uint32_t old_flags = ctx->flags; + + _decode_opc(ctx); + + if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { + if (ctx->flags & DELAY_SLOT_CLEARME) { + gen_op_store_flags(0); + } + ctx->flags = 0; + ctx->bstate = BS_BRANCH; + if (old_flags & DELAY_SLOT_CONDITIONAL) { + gen_delayed_conditional_jump(ctx); + } else if (old_flags & DELAY_SLOT) { + gen_jump(ctx); + } + + } } static inline int @@ -1151,7 +1173,6 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, DisasContext ctx; target_ulong pc_start; static uint16_t *gen_opc_end; - uint32_t old_flags; int i, ii; pc_start = tb->pc; @@ -1159,14 +1180,14 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; ctx.pc = pc_start; - ctx.flags = env->flags; - old_flags = 0; + ctx.flags = (uint32_t)tb->flags; + ctx.bstate = BS_NONE; ctx.sr = env->sr; ctx.fpscr = env->fpscr; ctx.memidx = (env->sr & SR_MD) ? 1 : 0; /* We don't know if the delayed pc came from a dynamic or static branch, so assume it is a dynamic branch. */ - ctx.delayed_pc = -1; + ctx.delayed_pc = -1; /* use delayed pc from env pointer */ ctx.tb = tb; ctx.singlestep_enabled = env->singlestep_enabled; nb_gen_labels = 0; @@ -1180,18 +1201,14 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, #endif ii = -1; - while ((old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) == 0 && - (ctx.flags & (BRANCH | BRANCH_CONDITIONAL | MODE_CHANGE | - BRANCH_EXCEPTION)) == 0 && - gen_opc_ptr < gen_opc_end && ctx.sr == env->sr) { - old_flags = ctx.flags; + while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { if (env->nb_breakpoints > 0) { for (i = 0; i < env->nb_breakpoints; i++) { if (ctx.pc == env->breakpoints[i]) { /* We have hit a breakpoint - make sure PC is up-to-date */ gen_op_movl_imm_PC(ctx.pc); gen_op_debug(); - ctx.flags |= BRANCH_EXCEPTION; + ctx.bstate = BS_EXCP; break; } } @@ -1204,6 +1221,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, gen_opc_instr_start[ii++] = 0; } gen_opc_pc[ii] = ctx.pc; + gen_opc_hflags[ii] = ctx.flags; gen_opc_instr_start[ii] = 1; } #if 0 @@ -1221,21 +1239,30 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, break; #endif } - - if (old_flags & DELAY_SLOT_CONDITIONAL) { - gen_delayed_conditional_jump(&ctx); - } else if (old_flags & DELAY_SLOT) { - gen_op_clr_delay_slot(); - gen_jump(&ctx); - } else if (ctx.flags & BRANCH_EXCEPTION) { - gen_jump_exception(&ctx); - } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) { - gen_goto_tb(&ctx, 0, ctx.pc); - } - if (env->singlestep_enabled) { - gen_op_debug(); + gen_op_debug(); + } else { + switch (ctx.bstate) { + case BS_STOP: + /* gen_op_interrupt_restart(); */ + /* fall through */ + case BS_NONE: + if (ctx.flags) { + gen_op_store_flags(ctx.flags | DELAY_SLOT_CLEARME); + } + gen_goto_tb(&ctx, 0, ctx.pc); + break; + case BS_EXCP: + /* gen_op_interrupt_restart(); */ + gen_op_movl_imm_T0(0); + gen_op_exit_tb(); + break; + case BS_BRANCH: + default: + break; + } } + *gen_opc_ptr = INDEX_op_end; if (search_pc) { i = gen_opc_ptr - gen_opc_buf; diff --git a/translate-all.c b/translate-all.c index e9eef65d5..f4944c06c 100644 --- a/translate-all.c +++ b/translate-all.c @@ -53,7 +53,7 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; #elif defined(TARGET_SPARC) target_ulong gen_opc_npc[OPC_BUF_SIZE]; target_ulong gen_opc_jump_pc[2]; -#elif defined(TARGET_MIPS) +#elif defined(TARGET_MIPS) || defined(TARGET_SH4) uint32_t gen_opc_hflags[OPC_BUF_SIZE]; #endif @@ -298,6 +298,9 @@ int cpu_restore_state(TranslationBlock *tb, env->hflags |= gen_opc_hflags[j]; #elif defined(TARGET_ALPHA) env->pc = gen_opc_pc[j]; +#elif defined(TARGET_SH4) + env->pc = gen_opc_pc[j]; + env->flags = gen_opc_hflags[j]; #endif return 0; } -- cgit v1.2.3 From e96e2044a14340bf1e612b7f046093495c10a06f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 06:18:24 +0000 Subject: SH4: system emulator interrupt update, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3762 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 5 ++- hw/sh7750.c | 2 + hw/sh_intc.c | 123 ++++++++++++++++++++++++++++++++++++++++------------ hw/sh_intc.h | 8 +++- target-sh4/cpu.h | 1 + target-sh4/helper.c | 75 ++++++++++++++++++++++++-------- target-sh4/op.c | 2 +- 7 files changed, 169 insertions(+), 47 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index e8b93a832..3629cacd7 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -511,7 +511,10 @@ int cpu_exec(CPUState *env1) BREAK_CHAIN; } #elif defined(TARGET_SH4) - /* XXXXX */ + if (interrupt_request & CPU_INTERRUPT_HARD) { + do_interrupt(env); + BREAK_CHAIN; + } #elif defined(TARGET_ALPHA) if (interrupt_request & CPU_INTERRUPT_HARD) { do_interrupt(env); diff --git a/hw/sh7750.c b/hw/sh7750.c index 82317d7ea..c6702883a 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -551,6 +551,8 @@ SH7750State *sh7750_init(CPUSH4State * cpu) _INTC_ARRAY(vectors), _INTC_ARRAY(groups)); + cpu->intc_handle = &s->intc; + sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]); sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF, s->periph_freq, serial_hds[1]); diff --git a/hw/sh_intc.c b/hw/sh_intc.c index 647f1cba9..8d1674ae3 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -14,10 +14,91 @@ #include "sh.h" //#define DEBUG_INTC +//#define DEBUG_INTC_SOURCES #define INTC_A7(x) ((x) & 0x1fffffff) #define INTC_ARRAY(x) (sizeof(x) / sizeof(x[0])) +void sh_intc_toggle_source(struct intc_source *source, + int enable_adj, int assert_adj) +{ + int enable_changed = 0; + int pending_changed = 0; + int old_pending; + + if ((source->enable_count == source->enable_max) && (enable_adj == -1)) + enable_changed = -1; + + source->enable_count += enable_adj; + + if (source->enable_count == source->enable_max) + enable_changed = 1; + + source->asserted += assert_adj; + + old_pending = source->pending; + source->pending = source->asserted && + (source->enable_count == source->enable_max); + + if (old_pending != source->pending) + pending_changed = 1; + + if (pending_changed) { + if (source->pending) { + source->parent->pending++; + if (source->parent->pending == 1) + cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); + } + else { + source->parent->pending--; + if (source->parent->pending == 0) + cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); + } + } + + if (enable_changed || assert_adj || pending_changed) { +#ifdef DEBUG_INTC_SOURCES + printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n", + source->parent->pending, + source->asserted, + source->enable_count, + source->enable_max, + source->vect, + source->asserted ? "asserted " : + assert_adj ? "deasserted" : "", + enable_changed == 1 ? "enabled " : + enable_changed == -1 ? "disabled " : "", + source->pending ? "pending" : ""); +#endif + } +} + +int sh_intc_get_pending_vector(struct intc_desc *desc, int imask) +{ + unsigned int i; + + /* slow: use a linked lists of pending sources instead */ + /* wrong: take interrupt priority into account (one list per priority) */ + + if (imask == 0x0f) { + return -1; /* FIXME, update code to include priority per source */ + } + + for (i = 0; i < desc->nr_sources; i++) { + struct intc_source *source = desc->sources + i; + + if (source->pending) { +#ifdef DEBUG_INTC_SOURCES + printf("sh_intc: (%d) returning interrupt source 0x%x\n", + desc->pending, source->vect); +#endif + return source->vect; + } + } + + assert(0); +} + #define INTC_MODE_NONE 0 #define INTC_MODE_DUAL_SET 1 #define INTC_MODE_DUAL_CLR 2 @@ -94,42 +175,24 @@ static void sh_intc_locate(struct intc_desc *desc, assert(0); } -static void sh_intc_toggle(struct intc_desc *desc, intc_enum id, - int enable, int is_group) +static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id, + int enable, int is_group) { struct intc_source *source = desc->sources + id; - int old = source->enable_count; if (!id) return; if (!source->next_enum_id && (!source->enable_max || !source->vect)) { -#ifdef DEBUG_INTC +#ifdef DEBUG_INTC_SOURCES printf("sh_intc: reserved interrupt source %d modified\n", id); #endif return; } - if (source->vect) { - if (enable) - source->enable_count++; - else - source->enable_count--; + if (source->vect) + sh_intc_toggle_source(source, enable ? 1 : -1, 0); - if (source->enable_count == source->enable_max) { -#ifdef DEBUG_INTC - printf("sh_intc: enabling interrupt source %d -> 0x%04x\n", - id, source->vect); -#endif - } - - if (old == source->enable_max) { -#ifdef DEBUG_INTC - printf("sh_intc: disabling interrupt source %d -> 0x%04x\n", - id, source->vect); -#endif - } - } #ifdef DEBUG_INTC else { printf("setting interrupt group %d to %d\n", id, !!enable); @@ -137,7 +200,7 @@ static void sh_intc_toggle(struct intc_desc *desc, intc_enum id, #endif if ((is_group || !source->vect) && source->next_enum_id) { - sh_intc_toggle(desc, source->next_enum_id, enable, 1); + sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1); } #ifdef DEBUG_INTC @@ -200,7 +263,7 @@ static void sh_intc_write(void *opaque, target_phys_addr_t offset, printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", k, first, enum_ids[k], (unsigned int)mask); #endif - sh_intc_toggle(desc, enum_ids[k], value & mask, 0); + sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0); } *valuep = value; @@ -309,7 +372,7 @@ void sh_intc_register_sources(struct intc_desc *desc, if (s) s->vect = vect->vect; -#ifdef DEBUG_INTC +#ifdef DEBUG_INTC_SOURCES printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n", vect->enum_id, s->vect, s->enable_count, s->enable_max); #endif @@ -330,7 +393,7 @@ void sh_intc_register_sources(struct intc_desc *desc, s->next_enum_id = gr->enum_ids[k]; } -#ifdef DEBUG_INTC +#ifdef DEBUG_INTC_SOURCES printf("sh_intc: registered group %d (%d/%d)\n", gr->enum_id, s->enable_count, s->enable_max); #endif @@ -347,6 +410,7 @@ int sh_intc_init(struct intc_desc *desc, { unsigned int i; + desc->pending = 0; desc->nr_sources = nr_sources; desc->mask_regs = mask_regs; desc->nr_mask_regs = nr_mask_regs; @@ -359,6 +423,11 @@ int sh_intc_init(struct intc_desc *desc, return -1; memset(desc->sources, 0, i); + for (i = 0; i < desc->nr_sources; i++) { + struct intc_source *source = desc->sources + i; + + source->parent = desc; + } desc->iomemtype = cpu_register_io_memory(0, sh_intc_readfn, sh_intc_writefn, desc); diff --git a/hw/sh_intc.h b/hw/sh_intc.h index 991e991f9..d22a4a2a4 100644 --- a/hw/sh_intc.h +++ b/hw/sh_intc.h @@ -35,9 +35,11 @@ struct intc_source { unsigned short vect; intc_enum next_enum_id; - int asserted; + int asserted; /* emulates the interrupt signal line from device to intc */ int enable_count; int enable_max; + int pending; /* emulates the result of signal and masking */ + struct intc_desc *parent; }; struct intc_desc { @@ -49,9 +51,13 @@ struct intc_desc { int nr_prio_regs; int iomemtype; + int pending; /* number of interrupt sources that has pending set */ }; +int sh_intc_get_pending_vector(struct intc_desc *desc, int imask); struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id); +void sh_intc_toggle_source(struct intc_source *source, + int enable_adj, int assert_adj); void sh_intc_register_sources(struct intc_desc *desc, struct intc_vect *vectors, diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index f9ecbb271..6b90f47d1 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -121,6 +121,7 @@ typedef struct CPUSH4State { int exception_index; CPU_COMMON tlb_t utlb[UTLB_SIZE]; /* unified translation table */ tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ + void *intc_handle; } CPUSH4State; CPUSH4State *cpu_sh4_init(const char *cpu_model); diff --git a/target-sh4/helper.c b/target-sh4/helper.c index b8a05e124..11e2e0f24 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -27,6 +27,7 @@ #include "cpu.h" #include "exec-all.h" +#include "hw/sh_intc.h" #if defined(CONFIG_USER_ONLY) @@ -74,6 +75,31 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) void do_interrupt(CPUState * env) { + int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD; + int do_exp, irq_vector = env->exception_index; + + /* prioritize exceptions over interrupts */ + + do_exp = env->exception_index != -1; + do_irq = do_irq && (env->exception_index == -1); + + if (env->sr & SR_BL) { + if (do_exp && env->exception_index != 0x1e0) { + env->exception_index = 0x000; /* masked exception -> reset */ + } + if (do_irq) { + return; /* masked */ + } + } + + if (do_irq) { + irq_vector = sh_intc_get_pending_vector(env->intc_handle, + (env->sr >> 4) & 0xf); + if (irq_vector == -1) { + return; /* masked */ + } + } + if (loglevel & CPU_LOG_INT) { const char *expname; switch (env->exception_index) { @@ -117,32 +143,47 @@ void do_interrupt(CPUState * env) expname = "trapa"; break; default: - expname = "???"; - break; + expname = do_irq ? "interrupt" : "???"; + break; } fprintf(logfile, "exception 0x%03x [%s] raised\n", - env->exception_index, expname); + irq_vector, expname); cpu_dump_state(env, logfile, fprintf, 0); } env->ssr = env->sr; - env->spc = env->spc; + env->spc = env->pc; env->sgr = env->gregs[15]; env->sr |= SR_BL | SR_MD | SR_RB; - env->expevt = env->exception_index & 0x7ff; - switch (env->exception_index) { - case 0x040: - case 0x060: - case 0x080: - env->pc = env->vbr + 0x400; - break; - case 0x140: - env->pc = 0xa0000000; - break; - default: - env->pc = env->vbr + 0x100; - break; + if (do_exp) { + env->expevt = env->exception_index; + switch (env->exception_index) { + case 0x000: + case 0x020: + case 0x140: + env->sr &= ~SR_FD; + env->sr |= 0xf << 4; /* IMASK */ + env->pc = 0xa0000000; + break; + case 0x040: + case 0x060: + env->pc = env->vbr + 0x400; + break; + case 0x160: + env->spc += 2; /* special case for TRAPA */ + /* fall through */ + default: + env->pc = env->vbr + 0x100; + break; + } + return; + } + + if (do_irq) { + env->intevt = irq_vector; + env->pc = env->vbr + 0x600; + return; } } diff --git a/target-sh4/op.c b/target-sh4/op.c index 0dcec4906..1004ef4c7 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -419,7 +419,7 @@ void OPPROTO op_subv_T0_T1(void) void OPPROTO op_trapa(void) { - env->tra = PARAM1 * 2; + env->tra = PARAM1 << 2; env->exception_index = 0x160; do_raise_exception(); RETURN(); -- cgit v1.2.3 From 03aa19762854bc4749fea52d7f2ba7d1077c036f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 06:28:08 +0000 Subject: Fix for execve syscall, by Kirill A. Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3763 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6f2872fff..bf7b31beb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3187,18 +3187,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, argc = 0; guest_argp = arg2; for (gp = guest_argp; ; gp++) { - if (get_user_ual(guest_argp, gp)) + if (get_user_ual(addr, gp)) goto efault; - if (!guest_argp) + if (!addr) break; argc++; } envc = 0; guest_envp = arg3; for (gp = guest_envp; ; gp++) { - if (get_user_ual(guest_envp, gp)) + if (get_user_ual(addr, gp)) goto efault; - if (!guest_envp) + if (!addr) break; envc++; } -- cgit v1.2.3 From c3b5bc8ab325bd3aee46ea5c0884c9e6f1636ccb Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 06:31:25 +0000 Subject: SH4: Signal handling for the user space emulator, by Magnus Damm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3764 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 12 ++ linux-user/sh4/target_signal.h | 5 + linux-user/signal.c | 321 +++++++++++++++++++++++++++++++++++++++-- target-sh4/helper.c | 6 +- 4 files changed, 331 insertions(+), 13 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index cfc9065a5..379ac2962 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1617,6 +1617,9 @@ void cpu_loop (CPUState *env) env->gregs[0] = ret; env->pc += 2; break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; case EXCP_DEBUG: { int sig; @@ -1631,6 +1634,15 @@ void cpu_loop (CPUState *env) } } break; + case 0xa0: + case 0xc0: + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->tea; + queue_signal(info.si_signo, &info); + break; + default: printf ("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); diff --git a/linux-user/sh4/target_signal.h b/linux-user/sh4/target_signal.h index 1fb70921f..e148da092 100644 --- a/linux-user/sh4/target_signal.h +++ b/linux-user/sh4/target_signal.h @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_SIGSTKSZ 8192 +static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state) +{ + return state->gregs[15]; +} + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/signal.c b/linux-user/signal.c index 730c9a255..312e41941 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -562,6 +562,12 @@ static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, return 0; } +static inline int current_exec_domain_sig(int sig) +{ + return /* current->exec_domain && current->exec_domain->signal_invmap + && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig; +} + #if defined(TARGET_I386) && TARGET_ABI_BITS == 32 /* from the Linux kernel */ @@ -745,11 +751,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; - err |= __put_user((/*current->exec_domain - && current->exec_domain->signal_invmap - && sig < 32 - ? current->exec_domain->signal_invmap[sig] - : */ sig), + err |= __put_user(current_exec_domain_sig(sig), &frame->sig); if (err) goto give_sigsegv; @@ -819,11 +821,7 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) goto give_sigsegv; - err |= __put_user((/*current->exec_domain - && current->exec_domain->signal_invmap - && sig < 32 - ? current->exec_domain->signal_invmap[sig] - : */sig), + err |= __put_user(current_exec_domain_sig(sig), &frame->sig); addr = frame_addr + offsetof(struct rt_sigframe, info); err |= __put_user(addr, &frame->pinfo); @@ -2406,6 +2404,309 @@ long do_rt_sigreturn(CPUState *env) return -TARGET_ENOSYS; } +#elif defined(TARGET_SH4) + +/* + * code and data structures from linux kernel: + * include/asm-sh/sigcontext.h + * arch/sh/kernel/signal.c + */ + +struct target_sigcontext { + target_ulong oldmask; + + /* CPU registers */ + target_ulong sc_gregs[16]; + target_ulong sc_pc; + target_ulong sc_pr; + target_ulong sc_sr; + target_ulong sc_gbr; + target_ulong sc_mach; + target_ulong sc_macl; + + /* FPU registers */ + target_ulong sc_fpregs[16]; + target_ulong sc_xfpregs[16]; + unsigned int sc_fpscr; + unsigned int sc_fpul; + unsigned int sc_ownedfp; +}; + +struct target_sigframe +{ + struct target_sigcontext sc; + target_ulong extramask[TARGET_NSIG_WORDS-1]; + uint16_t retcode[3]; +}; + + +struct target_ucontext { + target_ulong uc_flags; + struct target_ucontext *uc_link; + target_stack_t uc_stack; + struct target_sigcontext uc_mcontext; + target_sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +struct target_rt_sigframe +{ + struct target_siginfo info; + struct target_ucontext uc; + uint16_t retcode[3]; +}; + + +#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ +#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */ + +static abi_ulong get_sigframe(struct emulated_sigaction *ka, + unsigned long sp, size_t frame_size) +{ + if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } + + return (sp - frame_size) & -8ul; +} + +static int setup_sigcontext(struct target_sigcontext *sc, + CPUState *regs, unsigned long mask) +{ + int err = 0; + +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + COPY(gregs[0]); COPY(gregs[1]); + COPY(gregs[2]); COPY(gregs[3]); + COPY(gregs[4]); COPY(gregs[5]); + COPY(gregs[6]); COPY(gregs[7]); + COPY(gregs[8]); COPY(gregs[9]); + COPY(gregs[10]); COPY(gregs[11]); + COPY(gregs[12]); COPY(gregs[13]); + COPY(gregs[14]); COPY(gregs[15]); + COPY(gbr); COPY(mach); + COPY(macl); COPY(pr); + COPY(sr); COPY(pc); +#undef COPY + + /* todo: save FPU registers here */ + + /* non-iBCS2 extensions.. */ + err |= __put_user(mask, &sc->oldmask); + + return err; +} + +static int restore_sigcontext(struct CPUState *regs, + struct target_sigcontext *sc) +{ + unsigned int err = 0; + +#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) + COPY(gregs[1]); + COPY(gregs[2]); COPY(gregs[3]); + COPY(gregs[4]); COPY(gregs[5]); + COPY(gregs[6]); COPY(gregs[7]); + COPY(gregs[8]); COPY(gregs[9]); + COPY(gregs[10]); COPY(gregs[11]); + COPY(gregs[12]); COPY(gregs[13]); + COPY(gregs[14]); COPY(gregs[15]); + COPY(gbr); COPY(mach); + COPY(macl); COPY(pr); + COPY(sr); COPY(pc); +#undef COPY + + /* todo: restore FPU registers here */ + + regs->tra = -1; /* disable syscall checks */ + return err; +} + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *regs) +{ + struct target_sigframe *frame; + abi_ulong frame_addr; + int i; + int err = 0; + int signal; + + frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto give_sigsegv; + + signal = current_exec_domain_sig(sig); + + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); + + for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { + err |= __put_user(set->sig[i + 1], &frame->extramask[i]); + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { + regs->pr = (unsigned long) ka->sa.sa_restorer; + } else { + /* Generate return code (system call to sigreturn) */ + err |= __put_user(MOVW(2), &frame->retcode[0]); + err |= __put_user(TRAP_NOARG, &frame->retcode[1]); + err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]); + regs->pr = (unsigned long) frame->retcode; + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->gregs[15] = (unsigned long) frame; + regs->gregs[4] = signal; /* Arg for signal handler */ + regs->gregs[5] = 0; + regs->gregs[6] = (unsigned long) &frame->sc; + regs->pc = (unsigned long) ka->sa._sa_handler; + + unlock_user_struct(frame, frame_addr, 1); + return; + +give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); + force_sig(SIGSEGV); +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *regs) +{ + struct target_rt_sigframe *frame; + abi_ulong frame_addr; + int i; + int err = 0; + int signal; + + frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto give_sigsegv; + + signal = current_exec_domain_sig(sig); + + err |= copy_siginfo_to_user(&frame->info, info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, (unsigned long *)&frame->uc.uc_link); + err |= __put_user((void *)target_sigaltstack_used.ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->gregs[15]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(target_sigaltstack_used.ss_size, + &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, + regs, set->sig[0]); + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]); + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { + regs->pr = (unsigned long) ka->sa.sa_restorer; + } else { + /* Generate return code (system call to sigreturn) */ + err |= __put_user(MOVW(2), &frame->retcode[0]); + err |= __put_user(TRAP_NOARG, &frame->retcode[1]); + err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]); + regs->pr = (unsigned long) frame->retcode; + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->gregs[15] = (unsigned long) frame; + regs->gregs[4] = signal; /* Arg for signal handler */ + regs->gregs[5] = (unsigned long) &frame->info; + regs->gregs[6] = (unsigned long) &frame->uc; + regs->pc = (unsigned long) ka->sa._sa_handler; + + unlock_user_struct(frame, frame_addr, 1); + return; + +give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); + force_sig(SIGSEGV); +} + +long do_sigreturn(CPUState *regs) +{ + struct target_sigframe *frame; + abi_ulong frame_addr; + sigset_t blocked; + target_sigset_t target_set; + int i; + int err = 0; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "do_sigreturn\n"); +#endif + frame_addr = regs->gregs[15]; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; + + err |= __get_user(target_set.sig[0], &frame->sc.oldmask); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1])); + } + + if (err) + goto badframe; + + target_to_host_sigset_internal(&blocked, &target_set); + sigprocmask(SIG_SETMASK, &blocked, NULL); + + if (restore_sigcontext(regs, &frame->sc)) + goto badframe; + + unlock_user_struct(frame, frame_addr, 0); + return regs->gregs[0]; + +badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); + return 0; +} + +long do_rt_sigreturn(CPUState *regs) +{ + struct target_rt_sigframe *frame; + abi_ulong frame_addr; + sigset_t blocked; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "do_rt_sigreturn\n"); +#endif + frame_addr = regs->gregs[15]; + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) + goto badframe; + + target_to_host_sigset(&blocked, &frame->uc.uc_sigmask); + sigprocmask(SIG_SETMASK, &blocked, NULL); + + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) + goto badframe; + + if (do_sigaltstack(frame_addr + + offsetof(struct target_rt_sigframe, uc.uc_stack), + 0, get_sp_from_cpustate(regs)) == -EFAULT) + goto badframe; + + unlock_user_struct(frame, frame_addr, 0); + return regs->gregs[0]; + +badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); + return 0; +} + #else static void setup_frame(int sig, struct emulated_sigaction *ka, diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 11e2e0f24..52bef2fca 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -40,16 +40,16 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, int mmu_idx, int is_softmmu) { env->tea = address; + env->exception_index = 0; switch (rw) { case 0: + env->tea = address; env->exception_index = 0x0a0; break; case 1: + env->tea = address; env->exception_index = 0x0c0; break; - case 2: - env->exception_index = 0x0a0; - break; } return 1; } -- cgit v1.2.3 From dab6322b86bb9d9cf86847ceb055f1b99f1e772a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 07:14:17 +0000 Subject: Larger physical address space for 32-bit MIPS. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3765 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-mips/mips-defs.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 251fa359d..76ea8d019 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -14,6 +14,9 @@ #define TARGET_LONG_BITS 32 #endif +/* Even MIPS32 can have 36 bits physical address space. */ +#define TARGET_PHYS_ADDR_BITS 64 + /* Masks used to mark instructions to indicate which ISA level they were introduced in. */ #define ISA_MIPS1 0x00000001 -- cgit v1.2.3 From e140e05cbc01d2f15a558331f66fb4bffe03f54a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 17:17:45 +0000 Subject: Add missing include, by Sylvain Petreolle. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3766 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adlib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/adlib.c b/hw/adlib.c index af4660bbc..cbe8300ec 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -24,6 +24,7 @@ #include #include "hw.h" #include "audiodev.h" +#include "audio/audio.h" #define ADLIB_KILL_TIMERS 1 -- cgit v1.2.3 From 9f0683d9f56656bbd75805e860239f9897a8a6ea Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 2 Dec 2007 17:47:33 +0000 Subject: Include qemu-timer.h iff DEBUG is defined. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3767 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/adlib.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/adlib.c b/hw/adlib.c index cbe8300ec..1376db919 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -21,13 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #include #include "hw.h" #include "audiodev.h" #include "audio/audio.h" +//#define DEBUG + #define ADLIB_KILL_TIMERS 1 +#ifdef DEBUG +#include "qemu-timer.h" +#endif + #define dolog(...) AUD_log ("adlib", __VA_ARGS__) #ifdef DEBUG #define ldebug(...) dolog (__VA_ARGS__) -- cgit v1.2.3 From 001a3f5abfd2d1da4597510b5f75fcf7ec97ed33 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 3 Dec 2007 02:17:39 +0000 Subject: Fix floppy initialization, by Laurent Vivier. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3768 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_pica61.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c index ced0e5567..dfbc2f0d4 100644 --- a/hw/mips_pica61.c +++ b/hw/mips_pica61.c @@ -172,8 +172,9 @@ void mips_pica61_init (int ram_size, int vga_ram_size, for (i = 0; i < MAX_FD; i++) { index = drive_get_index(IF_FLOPPY, 0, i); if (index == -1) - continue; - fd[i] = drives_table[index].bdrv; + fd[i] = NULL; + else + fd[i] = drives_table[index].bdrv; } fdctrl_init(i8259[1], 1, 1, 0x80003000, fd); for(i = 0; i < MAX_SERIAL_PORTS; i++) { -- cgit v1.2.3 From ee5605e55676752335420dfddb98860f7d8ecd89 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 3 Dec 2007 03:01:40 +0000 Subject: Ensure a SIGALRM results in a break out from the cpu loop. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3769 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/vl.c b/vl.c index 3a694c473..70f250ebe 100644 --- a/vl.c +++ b/vl.c @@ -233,6 +233,10 @@ const char *prom_envs[MAX_PROM_ENVS]; int nb_drives_opt; char drives_opt[MAX_DRIVES][1024]; +static CPUState *cur_cpu; +static CPUState *next_cpu; +static int event_pending; + #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) /***********************************************************/ @@ -1180,16 +1184,16 @@ static void host_alarm_handler(int host_signum) struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; SetEvent(data->host_alarm); #endif - CPUState *env = cpu_single_env; - if (env) { - /* stop the currently executing cpu because a timer occured */ - cpu_interrupt(env, CPU_INTERRUPT_EXIT); + CPUState *env = next_cpu; + + /* 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 + if (env->kqemu_enabled) { + kqemu_cpu_interrupt(env); } +#endif + event_pending = 1; } } @@ -7340,8 +7344,6 @@ void main_loop_wait(int timeout) } -static CPUState *cur_cpu; - static int main_loop(void) { int ret, timeout; @@ -7351,15 +7353,13 @@ static int main_loop(void) CPUState *env; cur_cpu = first_cpu; + next_cpu = cur_cpu->next_cpu ?: first_cpu; for(;;) { if (vm_running) { - env = cur_cpu; for(;;) { /* get next cpu */ - env = env->next_cpu; - if (!env) - env = first_cpu; + env = next_cpu; #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif @@ -7367,6 +7367,12 @@ static int main_loop(void) #ifdef CONFIG_PROFILER qemu_time += profile_getclock() - ti; #endif + next_cpu = env->next_cpu ?: first_cpu; + if (event_pending) { + ret = EXCP_INTERRUPT; + event_pending = 0; + break; + } if (ret == EXCP_HLT) { /* Give the next CPU a chance to run. */ cur_cpu = env; -- cgit v1.2.3 From 6a5bd307023ac14089cbcc9e26790f8747f96af9 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 3 Dec 2007 17:05:38 +0000 Subject: The profiler need qemu-timer.h git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3770 c046a42c-6fe2-441c-8c8c-71466251a162 --- monitor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/monitor.c b/monitor.c index 3c4694c78..aa39147b6 100644 --- a/monitor.c +++ b/monitor.c @@ -36,6 +36,10 @@ #include "disas.h" #include +#ifdef CONFIG_PROFILER +#include "qemu-timer.h" /* for ticks_per_sec */ +#endif + //#define DEBUG //#define DEBUG_COMPLETION -- cgit v1.2.3 From 9d413d1d4902a22059fa0ac6e6b621fe43cf9403 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 4 Dec 2007 00:10:34 +0000 Subject: Always create an SD bdrv, so that PXA and OMAP boards can boot with no card inserted again. Eventually SD, CDROM and floppy should all be registered conditionally depending on machine. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3771 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 12 ++++++------ vl.c | 11 ++++++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index c56cd2423..af938706e 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -4901,7 +4901,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) qemu_mallocz(sizeof(struct omap_mpu_state_s)); ram_addr_t imif_base, emiff_base; - int index; + int sdindex; if (!core) core = "ti925t"; @@ -4998,14 +4998,14 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2")); omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3")); - index = drive_get_index(IF_SD, 0, 0); - if (index == -1) { + sdindex = drive_get_index(IF_SD, 0, 0); + if (sdindex == -1) { fprintf(stderr, "qemu: missing SecureDigital device\n"); exit(1); } - s->mmc = omap_mmc_init(0xfffb7800, drives_table[index].bdrv, - s->irq[1][OMAP_INT_OQN], - &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck")); + s->mmc = omap_mmc_init(0xfffb7800, drives_table[sdindex].bdrv, + s->irq[1][OMAP_INT_OQN], &s->drq[OMAP_DMA_MMC_TX], + omap_findclk(s, "mmc_ck")); s->mpuio = omap_mpuio_init(0xfffb5000, s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], diff --git a/vl.c b/vl.c index 70f250ebe..6614bbdae 100644 --- a/vl.c +++ b/vl.c @@ -4793,7 +4793,7 @@ void do_info_network(void) #define FD_ALIAS "index=%d,if=floppy" #define PFLASH_ALIAS "file=\"%s\",if=pflash" #define MTD_ALIAS "file=\"%s\",if=mtd" -#define SD_ALIAS "file=\"%s\",if=sd" +#define SD_ALIAS "index=0,if=sd" static int drive_add(const char *fmt, ...) { @@ -8179,7 +8179,7 @@ int main(int argc, char **argv) drive_add(MTD_ALIAS, optarg); break; case QEMU_OPTION_sd: - drive_add(SD_ALIAS, optarg); + drive_add("file=\"%s\"," SD_ALIAS, optarg); break; case QEMU_OPTION_pflash: drive_add(PFLASH_ALIAS, optarg); @@ -8756,11 +8756,16 @@ int main(int argc, char **argv) if (nb_drives_opt < MAX_DRIVES) drive_add(CDROM_ALIAS); - /* we always create at least on floppy */ + /* we always create at least one floppy */ if (nb_drives_opt < MAX_DRIVES) drive_add(FD_ALIAS, 0); + /* we always create one sd slot, even if no card is in it */ + + if (nb_drives_opt < MAX_DRIVES) + drive_add(SD_ALIAS); + /* open the virtual block devices */ for(i = 0; i < nb_drives_opt; i++) -- cgit v1.2.3 From 54215f7d71858f8db6e2efb6536da0b81e4d4a97 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 4 Dec 2007 00:11:33 +0000 Subject: Don't claim SD card supports voltages linux claims are below defined voltage range. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3772 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd.c b/hw/sd.c index 93ad3dab8..130072fd7 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -189,7 +189,7 @@ static uint16_t sd_crc16(void *message, size_t width) static void sd_set_ocr(SDState *sd) { - sd->ocr = 0x80fffff0; + sd->ocr = 0x80ffff80; } static void sd_set_scr(SDState *sd) -- cgit v1.2.3 From 577390ff4b7ca39f3780cbfd67d02bff3d4bf8e5 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 4 Dec 2007 20:58:31 +0000 Subject: No keyboard mode (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3773 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 15 ++++++++++++--- hw/sun4m.c | 3 ++- hw/sun4m.h | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 6705d4429..42d233ee6 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -100,6 +100,7 @@ typedef struct ChannelState { SERIOQueue queue; CharDriverState *chr; int e0_mode, led_mode, caps_lock_mode, num_lock_mode; + int disabled; } ChannelState; struct SerialState { @@ -193,7 +194,10 @@ static void slavio_serial_reset_chn(ChannelState *s) s->wregs[11] = 8; s->wregs[14] = 0x30; s->wregs[15] = 0xf8; - s->rregs[0] = 0x44; + if (s->disabled) + s->rregs[0] = 0x7c; + else + s->rregs[0] = 0x44; s->rregs[1] = 6; s->rx = s->tx = 0; @@ -437,7 +441,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint if (s->wregs[5] & 8) { // tx enabled if (s->chr) qemu_chr_write(s->chr, &s->tx, 1); - else if (s->type == kbd) { + else if (s->type == kbd && !s->disabled) { handle_kbd_command(s, val); } } @@ -611,6 +615,8 @@ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, s->chn[0].chr = chr1; s->chn[1].chr = chr2; + s->chn[0].disabled = 0; + s->chn[1].disabled = 0; for (i = 0; i < 2; i++) { s->chn[i].irq = irq; @@ -765,7 +771,8 @@ static void sunmouse_event(void *opaque, put_queue(s, 0); } -void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq) +void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, + int disabled) { int slavio_serial_io_memory, i; SerialState *s; @@ -782,6 +789,8 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq) s->chn[1].otherchn = &s->chn[0]; s->chn[0].type = mouse; s->chn[1].type = kbd; + s->chn[0].disabled = disabled; + s->chn[1].disabled = disabled; slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory); diff --git a/hw/sun4m.c b/hw/sun4m.c index 428519a5a..141a21e1a 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -436,7 +436,8 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, slavio_timer_init_all(hwdef->counter_base, slavio_irq[hwdef->clock1_irq], slavio_cpu_irq); - slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]); + slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq], + nographic); // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq], diff --git a/hw/sun4m.h b/hw/sun4m.h index e0ae5faf9..1e8ffbb07 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -41,7 +41,8 @@ void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq, /* slavio_serial.c */ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, CharDriverState *chr1, CharDriverState *chr2); -void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq); +void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, + int disabled); /* slavio_misc.c */ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, -- cgit v1.2.3 From 106627d0a036f9ebe523c648686b087eb8888355 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 5 Dec 2007 03:23:39 +0000 Subject: Rework OMAP1 interrupt handling to allow multiple interrupt banks, by Lauro Ramos Venancio. Add irq pulse shortcut, by Lauro Ramos Venancio. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3774 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/irq.h | 6 ++ hw/omap.c | 292 ++++++++++++++++++++++++++++++++++---------------------------- hw/omap.h | 3 +- 3 files changed, 167 insertions(+), 134 deletions(-) diff --git a/hw/irq.h b/hw/irq.h index d8195d520..0880ad21b 100644 --- a/hw/irq.h +++ b/hw/irq.h @@ -19,6 +19,12 @@ static inline void qemu_irq_lower(qemu_irq irq) qemu_set_irq(irq, 0); } +static inline void qemu_irq_pulse(qemu_irq irq) +{ + qemu_set_irq(irq, 1); + qemu_set_irq(irq, 0); +} + /* Returns an array of N IRQs. */ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); diff --git a/hw/omap.c b/hw/omap.c index af938706e..5f3c90acd 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -80,71 +80,68 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, } /* Interrupt Handlers */ -struct omap_intr_handler_s { - qemu_irq *pins; - qemu_irq *parent_pic; - target_phys_addr_t base; - - /* state */ +struct omap_intr_handler_bank_s { uint32_t irqs; + uint32_t inputs; uint32_t mask; - uint32_t sens_edge; uint32_t fiq; - int priority[32]; - uint32_t new_irq_agr; - uint32_t new_fiq_agr; - int sir_irq; - int sir_fiq; - int stats[32]; + uint32_t sens_edge; + unsigned char priority[32]; }; -static void omap_inth_update(struct omap_intr_handler_s *s) -{ - uint32_t irq = s->irqs & ~s->mask & ~s->fiq; - uint32_t fiq = s->irqs & ~s->mask & s->fiq; +struct omap_intr_handler_s { + qemu_irq *pins; + qemu_irq parent_intr[2]; + target_phys_addr_t base; + unsigned char nbanks; - if (s->new_irq_agr || !irq) { - qemu_set_irq(s->parent_pic[ARM_PIC_CPU_IRQ], irq); - if (irq) - s->new_irq_agr = 0; - } + /* state */ + uint32_t new_agr[2]; + int sir_intr[2]; + struct omap_intr_handler_bank_s banks[]; +}; - if (s->new_fiq_agr || !irq) { - qemu_set_irq(s->parent_pic[ARM_PIC_CPU_FIQ], fiq); - if (fiq) - s->new_fiq_agr = 0; +static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) +{ + int i, j, sir_intr, p_intr, p, f; + uint32_t level; + sir_intr = 0; + p_intr = 255; + + /* Find the interrupt line with the highest dynamic priority. + * Note: 0 denotes the hightest priority. + * If all interrupts have the same priority, the default order is IRQ_N, + * IRQ_N-1,...,IRQ_0. */ + for (j = 0; j < s->nbanks; ++j) { + level = s->banks[j].irqs & ~s->banks[j].mask & + (is_fiq ? s->banks[j].fiq : ~s->banks[j].fiq); + for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, + level >>= f) { + p = s->banks[j].priority[i]; + if (p <= p_intr) { + p_intr = p; + sir_intr = 32 * j + i; + } + f = ffs(level >> 1); + } } + s->sir_intr[is_fiq] = sir_intr; } -static void omap_inth_sir_update(struct omap_intr_handler_s *s) +static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq) { - int i, intr_irq, intr_fiq, p_irq, p_fiq, p, f; - uint32_t level = s->irqs & ~s->mask; + int i; + uint32_t has_intr = 0; - intr_irq = 0; - intr_fiq = 0; - p_irq = -1; - p_fiq = -1; - /* Find the interrupt line with the highest dynamic priority */ - for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, level >>= f) { - p = s->priority[i]; - if (s->fiq & (1 << i)) { - if (p > p_fiq) { - p_fiq = p; - intr_fiq = i; - } - } else { - if (p > p_irq) { - p_irq = p; - intr_irq = i; - } - } + for (i = 0; i < s->nbanks; ++i) + has_intr |= s->banks[i].irqs & ~s->banks[i].mask & + (is_fiq ? s->banks[i].fiq : ~s->banks[i].fiq); - f = ffs(level >> 1); + if (s->new_agr[is_fiq] && has_intr) { + s->new_agr[is_fiq] = 0; + omap_inth_sir_update(s, is_fiq); + qemu_set_irq(s->parent_intr[is_fiq], 1); } - - s->sir_irq = intr_irq; - s->sir_fiq = intr_fiq; } #define INT_FALLING_EDGE 0 @@ -155,19 +152,24 @@ static void omap_set_intr(void *opaque, int irq, int req) struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; uint32_t rise; + struct omap_intr_handler_bank_s *bank = &ih->banks[irq >> 5]; + int n = irq & 31; + if (req) { - rise = ~ih->irqs & (1 << irq); - ih->irqs |= rise; - ih->stats[irq] += !!rise; + rise = ~bank->irqs & (1 << n); + if (~bank->sens_edge & (1 << n)) + rise &= ~bank->inputs & (1 << n); + + bank->inputs |= (1 << n); + if (rise) { + bank->irqs |= rise; + omap_inth_update(ih, 0); + omap_inth_update(ih, 1); + } } else { - rise = ih->sens_edge & ih->irqs & (1 << irq); - ih->irqs &= ~rise; - } - - if (rise & ~ih->mask) { - omap_inth_sir_update(ih); - - omap_inth_update(ih); + rise = bank->sens_edge & bank->irqs & (1 << n); + bank->irqs &= ~rise; + bank->inputs &= ~(1 << n); } } @@ -175,33 +177,32 @@ static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr) { struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; int i, offset = addr - s->base; + int bank_no = offset >> 8; + int line_no; + struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; + offset &= 0xff; switch (offset) { case 0x00: /* ITR */ - return s->irqs; + return bank->irqs; case 0x04: /* MIR */ - return s->mask; + return bank->mask; case 0x10: /* SIR_IRQ_CODE */ - i = s->sir_irq; - if (((s->sens_edge >> i) & 1) == INT_FALLING_EDGE && i) { - s->irqs &= ~(1 << i); - omap_inth_sir_update(s); - omap_inth_update(s); - } - return i; - - case 0x14: /* SIR_FIQ_CODE */ - i = s->sir_fiq; - if (((s->sens_edge >> i) & 1) == INT_FALLING_EDGE && i) { - s->irqs &= ~(1 << i); - omap_inth_sir_update(s); - omap_inth_update(s); - } + case 0x14: /* SIR_FIQ_CODE */ + if (bank_no != 0) + break; + line_no = s->sir_intr[(offset - 0x10) >> 2]; + bank = &s->banks[line_no >> 5]; + i = line_no & 31; + if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE) + bank->irqs &= ~(1 << i); return i; case 0x18: /* CONTROL_REG */ + if (bank_no != 0) + break; return 0; case 0x1c: /* ILR0 */ @@ -237,17 +238,15 @@ static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr) case 0x94: /* ILR30 */ case 0x98: /* ILR31 */ i = (offset - 0x1c) >> 2; - return (s->priority[i] << 2) | - (((s->sens_edge >> i) & 1) << 1) | - ((s->fiq >> i) & 1); + return (bank->priority[i] << 2) | + (((bank->sens_edge >> i) & 1) << 1) | + ((bank->fiq >> i) & 1); case 0x9c: /* ISR */ return 0x00000000; - default: - OMAP_BAD_REG(addr); - break; } + OMAP_BAD_REG(addr); return 0; } @@ -256,18 +255,21 @@ static void omap_inth_write(void *opaque, target_phys_addr_t addr, { struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; int i, offset = addr - s->base; + int bank_no = offset >> 8; + struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; + offset &= 0xff; switch (offset) { case 0x00: /* ITR */ - s->irqs &= value | 1; - omap_inth_sir_update(s); - omap_inth_update(s); + /* Important: ignore the clearing if the IRQ is level-triggered and + the input bit is 1 */ + bank->irqs &= value | (bank->inputs & bank->sens_edge); return; case 0x04: /* MIR */ - s->mask = value; - omap_inth_sir_update(s); - omap_inth_update(s); + bank->mask = value; + omap_inth_update(s, 0); + omap_inth_update(s, 1); return; case 0x10: /* SIR_IRQ_CODE */ @@ -276,11 +278,18 @@ static void omap_inth_write(void *opaque, target_phys_addr_t addr, break; case 0x18: /* CONTROL_REG */ - if (value & 2) - s->new_fiq_agr = ~0; - if (value & 1) - s->new_irq_agr = ~0; - omap_inth_update(s); + if (bank_no != 0) + break; + if (value & 2) { + qemu_set_irq(s->parent_intr[1], 0); + s->new_agr[1] = ~0; + omap_inth_update(s, 1); + } + if (value & 1) { + qemu_set_irq(s->parent_intr[0], 0); + s->new_agr[0] = ~0; + omap_inth_update(s, 0); + } return; case 0x1c: /* ILR0 */ @@ -316,24 +325,22 @@ static void omap_inth_write(void *opaque, target_phys_addr_t addr, case 0x94: /* ILR30 */ case 0x98: /* ILR31 */ i = (offset - 0x1c) >> 2; - s->priority[i] = (value >> 2) & 0x1f; - s->sens_edge &= ~(1 << i); - s->sens_edge |= ((value >> 1) & 1) << i; - s->fiq &= ~(1 << i); - s->fiq |= (value & 1) << i; + bank->priority[i] = (value >> 2) & 0x1f; + bank->sens_edge &= ~(1 << i); + bank->sens_edge |= ((value >> 1) & 1) << i; + bank->fiq &= ~(1 << i); + bank->fiq |= (value & 1) << i; return; case 0x9c: /* ISR */ for (i = 0; i < 32; i ++) if (value & (1 << i)) { - omap_set_intr(s, i, 1); + omap_set_intr(s, 32 * bank_no + i, 1); return; } return; - - default: - OMAP_BAD_REG(addr); } + OMAP_BAD_REG(addr); } static CPUReadMemoryFunc *omap_inth_readfn[] = { @@ -348,31 +355,43 @@ static CPUWriteMemoryFunc *omap_inth_writefn[] = { omap_inth_write, }; -static void omap_inth_reset(struct omap_intr_handler_s *s) +void omap_inth_reset(struct omap_intr_handler_s *s) { - s->irqs = 0x00000000; - s->mask = 0xffffffff; - s->sens_edge = 0x00000000; - s->fiq = 0x00000000; - memset(s->priority, 0, sizeof(s->priority)); - s->new_irq_agr = ~0; - s->new_fiq_agr = ~0; - s->sir_irq = 0; - s->sir_fiq = 0; + int i; + + for (i = 0; i < s->nbanks; ++i){ + s->banks[i].irqs = 0x00000000; + s->banks[i].mask = 0xffffffff; + s->banks[i].sens_edge = 0x00000000; + s->banks[i].fiq = 0x00000000; + s->banks[i].inputs = 0x00000000; + memset(s->banks[i].priority, 0, sizeof(s->banks[i].priority)); + } - omap_inth_update(s); + s->new_agr[0] = ~0; + s->new_agr[1] = ~0; + s->sir_intr[0] = 0; + s->sir_intr[1] = 0; + + qemu_set_irq(s->parent_intr[0], 0); + qemu_set_irq(s->parent_intr[1], 0); } struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, - unsigned long size, qemu_irq parent[2], omap_clk clk) + unsigned long size, unsigned char nbanks, + qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk) { int iomemtype; struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) - qemu_mallocz(sizeof(struct omap_intr_handler_s)); + qemu_mallocz(sizeof(struct omap_intr_handler_s) + + sizeof(struct omap_intr_handler_bank_s) * nbanks); - s->parent_pic = parent; + s->parent_intr[0] = parent_irq; + s->parent_intr[1] = parent_fiq; s->base = base; - s->pins = qemu_allocate_irqs(omap_set_intr, s, 32); + s->nbanks = nbanks; + s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32); + omap_inth_reset(s); iomemtype = cpu_register_io_memory(0, omap_inth_readfn, @@ -1144,7 +1163,8 @@ static inline void omap_timer_update(struct omap_mpu_timer_s *timer) timer->val = 0; timer->st = 0; if (timer->it_ena) - qemu_irq_raise(timer->irq); + /* Edge-triggered irq */ + qemu_irq_pulse(timer->irq); } } else qemu_del_timer(timer->timer); @@ -1161,7 +1181,8 @@ static void omap_timer_tick(void *opaque) } if (timer->it_ena) - qemu_irq_raise(timer->irq); + /* Edge-triggered irq */ + qemu_irq_pulse(timer->irq); omap_timer_update(timer); } @@ -3678,6 +3699,7 @@ struct omap_rtc_s { static void omap_rtc_interrupts_update(struct omap_rtc_s *s) { + /* s->alarm is level-triggered */ qemu_set_irq(s->alarm, (s->status >> 6) & 1); } @@ -4000,26 +4022,26 @@ static void omap_rtc_tick(void *opaque) switch (s->interrupts & 3) { case 0: s->status |= 0x04; - qemu_irq_raise(s->irq); + qemu_irq_pulse(s->irq); break; case 1: if (s->current_tm.tm_sec) break; s->status |= 0x08; - qemu_irq_raise(s->irq); + qemu_irq_pulse(s->irq); break; case 2: if (s->current_tm.tm_sec || s->current_tm.tm_min) break; s->status |= 0x10; - qemu_irq_raise(s->irq); + qemu_irq_pulse(s->irq); break; case 3: if (s->current_tm.tm_sec || s->current_tm.tm_min || s->current_tm.tm_hour) break; s->status |= 0x20; - qemu_irq_raise(s->irq); + qemu_irq_pulse(s->irq); break; } @@ -4121,7 +4143,8 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) break; } - qemu_set_irq(s->rxirq, irq); + if (irq) + qemu_irq_pulse(s->rxirq); switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ case 0: @@ -4135,7 +4158,8 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) break; } - qemu_set_irq(s->txirq, irq); + if (irq) + qemu_irq_pulse(s->txirq); } static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) @@ -4901,8 +4925,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) qemu_mallocz(sizeof(struct omap_mpu_state_s)); ram_addr_t imif_base, emiff_base; + qemu_irq *cpu_irq; int sdindex; - + if (!core) core = "ti925t"; @@ -4929,11 +4954,12 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_clkm_init(0xfffece00, 0xe1008000, s); - s->ih[0] = omap_inth_init(0xfffecb00, 0x100, - arm_pic_init_cpu(s->env), + cpu_irq = arm_pic_init_cpu(s->env); + s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, + cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ], omap_findclk(s, "arminth_ck")); - s->ih[1] = omap_inth_init(0xfffe0000, 0x800, - &s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ], + s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1, + s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ], NULL, omap_findclk(s, "arminth_ck")); s->irq[0] = s->ih[0]->pins; s->irq[1] = s->ih[1]->pins; diff --git a/hw/omap.h b/hw/omap.h index 7d189d606..cd4e53bc9 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -57,7 +57,8 @@ void omap_clk_reparent(omap_clk clk, omap_clk parent); /* omap.c */ struct omap_intr_handler_s; struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, - unsigned long size, qemu_irq parent[2], omap_clk clk); + unsigned long size, unsigned char nbanks, + qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk); /* * Common IRQ numbers for level 1 interrupt handler -- cgit v1.2.3 From f2df526058b5815111aabca8db01f427891f006e Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 6 Dec 2007 22:05:05 +0000 Subject: Correct my 'thinko' in OMAP interrupt handler commit, fix by Lauro Ramos Venancio. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3775 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/omap.c b/hw/omap.c index 5f3c90acd..7312a66a7 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -198,7 +198,7 @@ static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr) i = line_no & 31; if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE) bank->irqs &= ~(1 << i); - return i; + return line_no; case 0x18: /* CONTROL_REG */ if (bank_no != 0) -- cgit v1.2.3 From c8522bdf46b322334444489d28b64792e674e067 Mon Sep 17 00:00:00 2001 From: balrog Date: Thu, 6 Dec 2007 22:11:20 +0000 Subject: Give emulated drives more monitor-friendly name strings. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3776 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 6614bbdae..5b7e97e6d 100644 --- a/vl.c +++ b/vl.c @@ -4844,6 +4844,8 @@ static int drive_init(const char *str, int snapshot, QEMUMachine *machine) { char buf[128]; char file[1024]; + char devname[128]; + const char *mediastr = ""; BlockInterfaceType interface; enum { MEDIA_DISK, MEDIA_CDROM } media; int bus_id, unit_id; @@ -4875,9 +4877,11 @@ static int drive_init(const char *str, int snapshot, QEMUMachine *machine) !strcmp(machine->name, "versatileab")) { interface = IF_SCSI; max_devs = MAX_SCSI_DEVS; + strcpy(devname, "scsi"); } else { interface = IF_IDE; max_devs = MAX_IDE_DEVS; + strcpy(devname, "ide"); } media = MEDIA_DISK; @@ -4900,6 +4904,7 @@ static int drive_init(const char *str, int snapshot, QEMUMachine *machine) } if (get_param_value(buf, sizeof(buf), "if", str)) { + strncpy(devname, buf, sizeof(devname)); if (!strcmp(buf, "ide")) { interface = IF_IDE; max_devs = MAX_IDE_DEVS; @@ -5057,7 +5062,10 @@ static int drive_init(const char *str, int snapshot, QEMUMachine *machine) /* init */ - snprintf(buf, sizeof(buf), "drive%d", nb_drives); + if (interface == IF_IDE || interface == IF_SCSI) + mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd"; + snprintf(buf, sizeof(buf), max_devs ? "%1$s%4$i%2$s%3$i" : "%s%s%i", + devname, mediastr, unit_id, bus_id); bdrv = bdrv_new(buf); drives_table[nb_drives].bdrv = bdrv; drives_table[nb_drives].interface = interface; -- cgit v1.2.3 From 1b66074b2f93a5d3f337d2aab10504426e756e50 Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 7 Dec 2007 01:13:37 +0000 Subject: Remove broken ds1225y init, it is useless on this machine anyway. Spotted by Atsushi Nemoto. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3777 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mips_r4k.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index b1c0433f6..63bd15824 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -38,7 +38,7 @@ extern FILE *logfile; static PITState *pit; /* PIT i8254 */ -/*i8254 PIT is attached to the IRQ0 at PIC i8259 */ +/* i8254 PIT is attached to the IRQ0 at PIC i8259 */ static struct _loaderparams { int ram_size; @@ -268,7 +268,6 @@ void mips_r4k_init (int ram_size, int vga_ram_size, hd[MAX_IDE_DEVS * i + 1]); i8042_init(i8259[1], i8259[12], 0x60); - ds1225y_init(0x9000, "nvram"); } QEMUMachine mips_machine = { -- cgit v1.2.3 From 01ba98161f954621bcf557ad8d5a0838d18000a1 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 02:22:57 +0000 Subject: Handle cpu_model in copy_cpu(), by Kirill A. Shutemov. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3778 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 4 +++- exec.c | 7 +------ target-arm/helper.c | 1 + target-i386/helper2.c | 1 + target-m68k/helper.c | 4 +++- target-mips/translate.c | 1 + target-ppc/helper.c | 1 + target-sparc/translate.c | 1 + 8 files changed, 12 insertions(+), 8 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 139dca2e7..5e0f04674 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -146,6 +146,8 @@ typedef struct CPUTLBEntry { void *next_cpu; /* next CPU sharing TB cache */ \ int cpu_index; /* CPU index (informative) */ \ /* user data */ \ - void *opaque; + void *opaque; \ + \ + const char *cpu_model_str; #endif diff --git a/exec.c b/exec.c index 046e96739..3fe340ae7 100644 --- a/exec.c +++ b/exec.c @@ -1317,9 +1317,7 @@ void cpu_abort(CPUState *env, const char *fmt, ...) CPUState *cpu_copy(CPUState *env) { -#if 0 - /* XXX: broken, must be handled by each CPU */ - CPUState *new_env = cpu_init(); + CPUState *new_env = cpu_init(env->cpu_model_str); /* preserve chaining and index */ CPUState *next_cpu = new_env->next_cpu; int cpu_index = new_env->cpu_index; @@ -1327,9 +1325,6 @@ CPUState *cpu_copy(CPUState *env) new_env->next_cpu = next_cpu; new_env->cpu_index = cpu_index; return new_env; -#else - return NULL; -#endif } #if !defined(CONFIG_USER_ONLY) diff --git a/target-arm/helper.c b/target-arm/helper.c index 40bdeb186..86470dbee 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -182,6 +182,7 @@ CPUARMState *cpu_arm_init(const char *cpu_model) if (!env) return NULL; cpu_exec_init(env); + env->cpu_model_str = cpu_model; env->cp15.c0_cpuid = id; cpu_reset(env); return env; diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 67658e297..968d9dd56 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -99,6 +99,7 @@ CPUX86State *cpu_x86_init(const char *cpu_model) if (!env) return NULL; cpu_exec_init(env); + env->cpu_model_str = cpu_model; /* init various static tables */ if (!inited) { diff --git a/target-m68k/helper.c b/target-m68k/helper.c index f6b0cd6b3..c63964891 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -126,11 +126,13 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model) return NULL; cpu_exec_init(env); + env->cpu_model_str = cpu_model; + if (cpu_m68k_set_model(env, cpu_model) < 0) { cpu_m68k_close(env); return NULL; } - + cpu_reset(env); return env; } diff --git a/target-mips/translate.c b/target-mips/translate.c index c909463da..abbf0677c 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -6786,6 +6786,7 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model) env->cpu_model = def; cpu_exec_init(env); + env->cpu_model_str = cpu_model; cpu_reset(env); return env; } diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 7a32d4a27..a808454a2 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -2976,6 +2976,7 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) if (!env) return NULL; cpu_exec_init(env); + env->cpu_model_str = cpu_model; cpu_ppc_register_internal(env, def); cpu_ppc_reset(env); return env; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 37a0d2963..ecec37272 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3792,6 +3792,7 @@ CPUSPARCState *cpu_sparc_init(const char *cpu_model) if (!env) return NULL; cpu_exec_init(env); + env->cpu_model_str = cpu_model; env->version = def->iu_version; env->fsr = def->fpu_version; #if !defined(TARGET_SPARC64) -- cgit v1.2.3 From 26edcf41db01e810ab2a4791b77222f5dc621ef4 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 02:25:24 +0000 Subject: copy_from_user_fdset() update, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3779 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 151 +++++++++++++++++++++++++-------------------------- 1 file changed, 75 insertions(+), 76 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index bf7b31beb..c3b09c0a6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -443,50 +443,66 @@ abi_long do_brk(abi_ulong new_brk) } } -static inline fd_set *target_to_host_fds(fd_set *fds, - abi_long *target_fds, int n) +static inline abi_long copy_from_user_fdset(fd_set *fds, + abi_ulong target_fds_addr, + int n) { -#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) - return (fd_set *)target_fds; -#else - int i, b; - if (target_fds) { - FD_ZERO(fds); - for(i = 0;i < n; i++) { - b = (tswapl(target_fds[i / TARGET_ABI_BITS]) >> - (i & (TARGET_ABI_BITS - 1))) & 1; - if (b) - FD_SET(i, fds); + int i, nw, j, k; + abi_ulong b, *target_fds; + + nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; + if (!(target_fds = lock_user(VERIFY_READ, + target_fds_addr, + sizeof(abi_ulong) * nw, + 1))) + return -TARGET_EFAULT; + + FD_ZERO(fds); + k = 0; + for (i = 0; i < nw; i++) { + /* grab the abi_ulong */ + __get_user(b, &target_fds[i]); + for (j = 0; j < TARGET_ABI_BITS; j++) { + /* check the bit inside the abi_ulong */ + if ((b >> j) & 1) + FD_SET(k, fds); + k++; } - return fds; - } else { - return NULL; } -#endif + + unlock_user(target_fds, target_fds_addr, 0); + + return 0; } -static inline void host_to_target_fds(abi_long *target_fds, - fd_set *fds, int n) +static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr, + const fd_set *fds, + int n) { -#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) - /* nothing to do */ -#else int i, nw, j, k; abi_long v; + abi_ulong *target_fds; - if (target_fds) { - nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; - k = 0; - for(i = 0;i < nw; i++) { - v = 0; - for(j = 0; j < TARGET_ABI_BITS; j++) { - v |= ((FD_ISSET(k, fds) != 0) << j); - k++; - } - target_fds[i] = tswapl(v); + nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; + if (!(target_fds = lock_user(VERIFY_WRITE, + target_fds_addr, + sizeof(abi_ulong) * nw, + 0))) + return -TARGET_EFAULT; + + k = 0; + for (i = 0; i < nw; i++) { + v = 0; + for (j = 0; j < TARGET_ABI_BITS; j++) { + v |= ((FD_ISSET(k, fds) != 0) << j); + k++; } + __put_user(v, &target_fds[i]); } -#endif + + unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw); + + return 0; } #if defined(__alpha__) @@ -565,74 +581,57 @@ static inline abi_long host_to_target_timeval(abi_ulong target_addr, /* do_select() must return target values and target errnos. */ static abi_long do_select(int n, - abi_ulong rfd_p, abi_ulong wfd_p, - abi_ulong efd_p, abi_ulong target_tv) + abi_ulong rfd_addr, abi_ulong wfd_addr, + abi_ulong efd_addr, abi_ulong target_tv_addr) { fd_set rfds, wfds, efds; fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; - abi_long *target_rfds, *target_wfds, *target_efds; struct timeval tv, *tv_ptr; abi_long ret; - int ok; - if (rfd_p) { - target_rfds = lock_user(VERIFY_WRITE, rfd_p, sizeof(abi_long) * n, 1); - if (!target_rfds) { - ret = -TARGET_EFAULT; - goto end; - } - rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); + if (rfd_addr) { + if (copy_from_user_fdset(&rfds, rfd_addr, n)) + return -TARGET_EFAULT; + rfds_ptr = &rfds; } else { - target_rfds = NULL; rfds_ptr = NULL; } - if (wfd_p) { - target_wfds = lock_user(VERIFY_WRITE, wfd_p, sizeof(abi_long) * n, 1); - if (!target_wfds) { - ret = -TARGET_EFAULT; - goto end; - } - wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); + if (wfd_addr) { + if (copy_from_user_fdset(&wfds, wfd_addr, n)) + return -TARGET_EFAULT; + wfds_ptr = &wfds; } else { - target_wfds = NULL; wfds_ptr = NULL; } - if (efd_p) { - target_efds = lock_user(VERIFY_WRITE, efd_p, sizeof(abi_long) * n, 1); - if (!target_efds) { - ret = -TARGET_EFAULT; - goto end; - } - efds_ptr = target_to_host_fds(&efds, target_efds, n); + if (efd_addr) { + if (copy_from_user_fdset(&efds, efd_addr, n)) + return -TARGET_EFAULT; + efds_ptr = &efds; } else { - target_efds = NULL; efds_ptr = NULL; } - if (target_tv) { - target_to_host_timeval(&tv, target_tv); + if (target_tv_addr) { + target_to_host_timeval(&tv, target_tv_addr); tv_ptr = &tv; } else { tv_ptr = NULL; } + ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); - ok = !is_error(ret); - if (ok) { - host_to_target_fds(target_rfds, rfds_ptr, n); - host_to_target_fds(target_wfds, wfds_ptr, n); - host_to_target_fds(target_efds, efds_ptr, n); + if (!is_error(ret)) { + if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) + return -TARGET_EFAULT; + if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) + return -TARGET_EFAULT; + if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) + return -TARGET_EFAULT; - if (target_tv) { - host_to_target_timeval(target_tv, &tv); - } + if (target_tv_addr) + host_to_target_timeval(target_tv_addr, &tv); } -end: - unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); - unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); - unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); - return ret; } -- cgit v1.2.3 From 788f5ec40d03a79ae7aa3335d7e3cfea72c502a8 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 02:37:05 +0000 Subject: copy_{to,from}_user_timeval() update, by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3780 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 74 +++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c3b09c0a6..590c72fa4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -550,30 +550,34 @@ static inline abi_long host_to_target_rusage(abi_ulong target_addr, return 0; } -static inline abi_long target_to_host_timeval(struct timeval *tv, - abi_ulong target_addr) +static inline abi_long copy_from_user_timeval(struct timeval *tv, + abi_ulong target_tv_addr) { struct target_timeval *target_tv; - if (!lock_user_struct(VERIFY_READ, target_tv, target_addr, 1)) + if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) return -TARGET_EFAULT; - tv->tv_sec = tswapl(target_tv->tv_sec); - tv->tv_usec = tswapl(target_tv->tv_usec); - unlock_user_struct(target_tv, target_addr, 0); + + __get_user(tv->tv_sec, &target_tv->tv_sec); + __get_user(tv->tv_usec, &target_tv->tv_usec); + + unlock_user_struct(target_tv, target_tv_addr, 0); return 0; } -static inline abi_long host_to_target_timeval(abi_ulong target_addr, - const struct timeval *tv) +static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr, + const struct timeval *tv) { struct target_timeval *target_tv; - if (!lock_user_struct(VERIFY_WRITE, target_tv, target_addr, 0)) + if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) return -TARGET_EFAULT; - target_tv->tv_sec = tswapl(tv->tv_sec); - target_tv->tv_usec = tswapl(tv->tv_usec); - unlock_user_struct(target_tv, target_addr, 1); + + __put_user(tv->tv_sec, &target_tv->tv_sec); + __put_user(tv->tv_usec, &target_tv->tv_usec); + + unlock_user_struct(target_tv, target_tv_addr, 1); return 0; } @@ -612,7 +616,8 @@ static abi_long do_select(int n, } if (target_tv_addr) { - target_to_host_timeval(&tv, target_tv_addr); + if (copy_from_user_timeval(&tv, target_tv_addr)) + return -TARGET_EFAULT; tv_ptr = &tv; } else { tv_ptr = NULL; @@ -628,8 +633,8 @@ static abi_long do_select(int n, if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) return -TARGET_EFAULT; - if (target_tv_addr) - host_to_target_timeval(target_tv_addr, &tv); + if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv)) + return -TARGET_EFAULT; } return ret; @@ -3390,9 +3395,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct timeval *tvp, tv[2]; if (arg2) { - target_to_host_timeval(&tv[0], arg2); - target_to_host_timeval(&tv[1], - arg2 + sizeof (struct target_timeval)); + if (copy_from_user_timeval(&tv[0], arg2) + || copy_from_user_timeval(&tv[1], + arg2 + sizeof(struct target_timeval))) + goto efault; tvp = tv; } else { tvp = NULL; @@ -3931,14 +3937,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct timeval tv; ret = get_errno(gettimeofday(&tv, NULL)); if (!is_error(ret)) { - host_to_target_timeval(arg1, &tv); + if (copy_to_user_timeval(arg1, &tv)) + goto efault; } } break; case TARGET_NR_settimeofday: { struct timeval tv; - target_to_host_timeval(&tv, arg1); + if (copy_from_user_timeval(&tv, arg1)) + goto efault; ret = get_errno(settimeofday(&tv, NULL)); } break; @@ -4313,19 +4321,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (arg2) { pvalue = &value; - target_to_host_timeval(&pvalue->it_interval, - arg2); - target_to_host_timeval(&pvalue->it_value, - arg2 + sizeof(struct target_timeval)); + if (copy_from_user_timeval(&pvalue->it_interval, arg2) + || copy_from_user_timeval(&pvalue->it_value, + arg2 + sizeof(struct target_timeval))) + goto efault; } else { pvalue = NULL; } ret = get_errno(setitimer(arg1, pvalue, &ovalue)); if (!is_error(ret) && arg3) { - host_to_target_timeval(arg3, - &ovalue.it_interval); - host_to_target_timeval(arg3 + sizeof(struct target_timeval), - &ovalue.it_value); + if (copy_to_user_timeval(arg3, + &ovalue.it_interval) + || copy_to_user_timeval(arg3 + sizeof(struct target_timeval), + &ovalue.it_value)) + goto efault; } } break; @@ -4335,10 +4344,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(getitimer(arg1, &value)); if (!is_error(ret) && arg2) { - host_to_target_timeval(arg2, - &value.it_interval); - host_to_target_timeval(arg2 + sizeof(struct target_timeval), - &value.it_value); + if (copy_to_user_timeval(arg2, + &value.it_interval) + || copy_to_user_timeval(arg2 + sizeof(struct target_timeval), + &value.it_value)) + goto efault; } } break; -- cgit v1.2.3 From f1de13340854e97c8acc86dabf61c7d066a8c5da Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 02:38:34 +0000 Subject: Mainstone mmc support, by Armin Kuster. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3781 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mainstone.c | 4 ++++ hw/mainstone.h | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/hw/mainstone.c b/hw/mainstone.c index 354015202..cf05675d0 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -76,6 +76,10 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, } mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0); + + /* MMC/SD host */ + pxa2xx_mmci_handlers(cpu->mmc, mst_irq[MMC_IRQ], mst_irq[MMC_IRQ]); + smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); arm_load_kernel(cpu->env, mainstone_ram, kernel_filename, kernel_cmdline, diff --git a/hw/mainstone.h b/hw/mainstone.h index c7bcb93f0..f970b9f27 100644 --- a/hw/mainstone.h +++ b/hw/mainstone.h @@ -17,7 +17,20 @@ #define MST_FLASH_1 0x04000000 /* IRQ definitions */ -#define ETHERNET_IRQ 3 +#define MMC_IRQ 0 +#define USIM_IRQ 1 +#define USBC_IRQ 2 +#define ETHERNET_IRQ 3 +#define AC97_IRQ 4 +#define PEN_IRQ 5 +#define MSINS_IRQ 6 +#define EXBRD_IRQ 7 +#define S0_CD_IRQ 9 +#define S0_STSCHG_IRQ 10 +#define S0_IRQ 11 +#define S1_CD_IRQ 13 +#define S1_STSCHG_IRQ 14 +#define S1_IRQ 15 extern qemu_irq *mst_irq_init(struct pxa2xx_state_s *cpu, uint32_t base, int irq); -- cgit v1.2.3 From 867e2400d6e0d4e09eb26355ada4073e93d71baa Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 02:43:19 +0000 Subject: Fix spelling typo, by Dan Kenigsberg. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3782 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 968d9dd56..6d40c641f 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -256,7 +256,7 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) } x86_cpu_def->stepping = stepping; } else { - fprintf(stderr, "unregnized feature %s\n", featurestr); + fprintf(stderr, "unrecognized feature %s\n", featurestr); x86_cpu_def = 0; goto error; } -- cgit v1.2.3 From 0d4a05a109bba2e8ad81e3e2404015b361196945 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 05:01:52 +0000 Subject: Fix Win98SE MyComputer regression, by Ben Taylor. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3783 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide.c b/hw/ide.c index bf2cc14f4..2183f314b 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -1361,7 +1361,7 @@ static void ide_atapi_cmd(IDEState *s) buf[8] = 0x2a; buf[9] = 0x12; - buf[10] = 0x08; + buf[10] = 0x00; buf[11] = 0x00; buf[12] = 0x70; -- cgit v1.2.3 From 85ffbdfc72a63d4f828615dcd301faadc595ed37 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 05:10:03 +0000 Subject: SH4 big endian configuration, by Tomoyoshi Asano. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3784 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 2 ++ configure | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a2177c12b..5eae9428b 100644 --- a/Makefile +++ b/Makefile @@ -246,6 +246,7 @@ tarbin: $(bindir)/qemu-system-arm \ $(bindir)/qemu-system-m68k \ $(bindir)/qemu-system-sh4 \ + $(bindir)/qemu-system-sh4eb \ $(bindir)/qemu-i386 \ $(bindir)/qemu-arm \ $(bindir)/qemu-armeb \ @@ -261,6 +262,7 @@ tarbin: $(bindir)/qemu-alpha \ $(bindir)/qemu-m68k \ $(bindir)/qemu-sh4 \ + $(bindir)/qemu-sh4eb \ $(bindir)/qemu-img \ $(datadir)/bios.bin \ $(datadir)/vgabios.bin \ diff --git a/configure b/configure index 28b677099..b16fb84ee 100755 --- a/configure +++ b/configure @@ -522,11 +522,11 @@ fi if test -z "$target_list" ; then # these targets are portable if [ "$softmmu" = "yes" ] ; then - target_list="i386-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc-softmmu ppcemb-softmmu ppc64-softmmu m68k-softmmu sh4-softmmu cris-softmmu" + target_list="i386-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc-softmmu ppcemb-softmmu ppc64-softmmu m68k-softmmu sh4-softmmu sh4eb-softmmu cris-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then - target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppc64-linux-user ppc64abi32-linux-user x86_64-linux-user cris-linux-user $target_list" + target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user sh4eb-linux-user ppc-linux-user ppc64-linux-user ppc64abi32-linux-user x86_64-linux-user cris-linux-user $target_list" fi # the following are Darwin specific if [ "$darwin_user" = "yes" ] ; then -- cgit v1.2.3 From 7eb0c8e8f973ba842bf5f915f4559e88ba2ffcae Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Sun, 9 Dec 2007 17:03:50 +0000 Subject: Add support for eccmemctl (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3785 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/eccmemctl.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/sun4m.c | 10 +++ hw/sun4m.h | 3 + 4 files changed, 280 insertions(+), 1 deletion(-) create mode 100755 hw/eccmemctl.c diff --git a/Makefile.target b/Makefile.target index eb77210df..af9d3340d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -482,7 +482,7 @@ VL_OBJS+= cirrus_vga.o parallel.o ptimer.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 ptimer.o +VL_OBJS+= cs4231.o ptimer.o eccmemctl.o endif endif ifeq ($(TARGET_BASE_ARCH), arm) diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c new file mode 100755 index 000000000..0b44fabce --- /dev/null +++ b/hw/eccmemctl.c @@ -0,0 +1,266 @@ +/* + * QEMU Sparc Sun4m ECC memory controller emulation + * + * Copyright (c) 2007 Robert Reif + * + * 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 "hw.h" +#include "sun4m.h" +#include "sysemu.h" + +//#define DEBUG_ECC + +#ifdef DEBUG_ECC +#define DPRINTF(fmt, args...) \ + do { printf("ECC: " fmt , ##args); } while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +/* There are 3 versions of this chip used in SMP sun4m systems: + * MCC (version 0, implementation 0) SS-600MP + * EMC (version 0, implementation 1) SS-10 + * SMC (version 0, implementation 2) SS-10SX and SS-20 + */ + +/* Register offsets */ +#define ECC_FCR_REG 0 +#define ECC_FSR_REG 8 +#define ECC_FAR0_REG 16 +#define ECC_FAR1_REG 20 +#define ECC_DIAG_REG 24 + +/* ECC fault control register */ +#define ECC_FCR_EE 0x00000001 /* Enable ECC checking */ +#define ECC_FCR_EI 0x00000010 /* Enable Interrupts on correctable errors */ +#define ECC_FCR_VER 0x0f000000 /* Version */ +#define ECC_FCR_IMPL 0xf0000000 /* Implementation */ + +/* ECC fault status register */ +#define ECC_FSR_CE 0x00000001 /* Correctable error */ +#define ECC_FSR_BS 0x00000002 /* C2 graphics bad slot access */ +#define ECC_FSR_TO 0x00000004 /* Timeout on write */ +#define ECC_FSR_UE 0x00000008 /* Uncorrectable error */ +#define ECC_FSR_DW 0x000000f0 /* Index of double word in block */ +#define ECC_FSR_SYND 0x0000ff00 /* Syndrome for correctable error */ +#define ECC_FSR_ME 0x00010000 /* Multiple errors */ +#define ECC_FSR_C2ERR 0x00020000 /* C2 graphics error */ + +/* ECC fault address register 0 */ +#define ECC_FAR0_PADDR 0x0000000f /* PA[32-35] */ +#define ECC_FAR0_TYPE 0x000000f0 /* Transaction type */ +#define ECC_FAR0_SIZE 0x00000700 /* Transaction size */ +#define ECC_FAR0_CACHE 0x00000800 /* Mapped cacheable */ +#define ECC_FAR0_LOCK 0x00001000 /* Error occurred in attomic cycle */ +#define ECC_FAR0_BMODE 0x00002000 /* Boot mode */ +#define ECC_FAR0_VADDR 0x003fc000 /* VA[12-19] (superset bits) */ +#define ECC_FAR0_S 0x08000000 /* Supervisor mode */ +#define ECC_FARO_MID 0xf0000000 /* Module ID */ + +/* ECC diagnostic register */ +#define ECC_DIAG_CBX 0x00000001 +#define ECC_DIAG_CB0 0x00000002 +#define ECC_DIAG_CB1 0x00000004 +#define ECC_DIAG_CB2 0x00000008 +#define ECC_DIAG_CB4 0x00000010 +#define ECC_DIAG_CB8 0x00000020 +#define ECC_DIAG_CB16 0x00000040 +#define ECC_DIAG_CB32 0x00000080 +#define ECC_DIAG_DMODE 0x00000c00 + +#define ECC_NREGS 8 +#define ECC_SIZE (ECC_NREGS * sizeof(uint32_t)) +#define ECC_ADDR_MASK (ECC_SIZE - 1) + +typedef struct ECCState { + uint32_t regs[ECC_NREGS]; +} ECCState; + +static void ecc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + printf("ECC: Unsupported write 0x" TARGET_FMT_plx " %02x\n", + addr, val & 0xff); +} + +static uint32_t ecc_mem_readb(void *opaque, target_phys_addr_t addr) +{ + printf("ECC: Unsupported read 0x" TARGET_FMT_plx " 00\n", addr); + return 0; +} + +static void ecc_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + printf("ECC: Unsupported write 0x" TARGET_FMT_plx " %04x\n", + addr, val & 0xffff); +} + +static uint32_t ecc_mem_readw(void *opaque, target_phys_addr_t addr) +{ + printf("ECC: Unsupported read 0x" TARGET_FMT_plx " 0000\n", addr); + return 0; +} + +static void ecc_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + ECCState *s = opaque; + + switch (addr & ECC_ADDR_MASK) { + case ECC_FCR_REG: + s->regs[0] = (s->regs[0] & (ECC_FCR_VER | ECC_FCR_IMPL)) | + (val & ~(ECC_FCR_VER | ECC_FCR_IMPL)); + DPRINTF("Write fault control %08x\n", val); + break; + case 4: + s->regs[1] = val; + DPRINTF("Write reg[1] %08x\n", val); + break; + case ECC_FSR_REG: + s->regs[2] = val; + DPRINTF("Write fault status %08x\n", val); + break; + case 12: + s->regs[3] = val; + DPRINTF("Write reg[3] %08x\n", val); + break; + case ECC_FAR0_REG: + s->regs[4] = val; + DPRINTF("Write fault address 0 %08x\n", val); + break; + case ECC_FAR1_REG: + s->regs[5] = val; + DPRINTF("Write fault address 1 %08x\n", val); + break; + case ECC_DIAG_REG: + s->regs[6] = val; + DPRINTF("Write diag %08x\n", val); + break; + case 28: + s->regs[7] = val; + DPRINTF("Write reg[7] %08x\n", val); + break; + } +} + +static uint32_t ecc_mem_readl(void *opaque, target_phys_addr_t addr) +{ + ECCState *s = opaque; + uint32_t ret = 0; + + switch (addr & ECC_ADDR_MASK) { + case ECC_FCR_REG: + ret = s->regs[0]; + DPRINTF("Read enable %08x\n", ret); + break; + case 4: + ret = s->regs[1]; + DPRINTF("Read register[1] %08x\n", ret); + break; + case ECC_FSR_REG: + ret = s->regs[2]; + DPRINTF("Read fault status %08x\n", ret); + break; + case 12: + ret = s->regs[3]; + DPRINTF("Read reg[3] %08x\n", ret); + break; + case ECC_FAR0_REG: + ret = s->regs[4]; + DPRINTF("Read fault address 0 %08x\n", ret); + break; + case ECC_FAR1_REG: + ret = s->regs[5]; + DPRINTF("Read fault address 1 %08x\n", ret); + break; + case ECC_DIAG_REG: + ret = s->regs[6]; + DPRINTF("Read diag %08x\n", ret); + break; + case 28: + ret = s->regs[7]; + DPRINTF("Read reg[7] %08x\n", ret); + break; + } + return ret; +} + +static CPUReadMemoryFunc *ecc_mem_read[3] = { + ecc_mem_readb, + ecc_mem_readw, + ecc_mem_readl, +}; + +static CPUWriteMemoryFunc *ecc_mem_write[3] = { + ecc_mem_writeb, + ecc_mem_writew, + ecc_mem_writel, +}; + +static int ecc_load(QEMUFile *f, void *opaque, int version_id) +{ + ECCState *s = opaque; + int i; + + if (version_id != 1) + return -EINVAL; + + for (i = 0; i < ECC_NREGS; i++) + qemu_get_be32s(f, &s->regs[i]); + + return 0; +} + +static void ecc_save(QEMUFile *f, void *opaque) +{ + ECCState *s = opaque; + int i; + + for (i = 0; i < ECC_NREGS; i++) + qemu_put_be32s(f, &s->regs[i]); +} + +static void ecc_reset(void *opaque) +{ + ECCState *s = opaque; + int i; + + s->regs[ECC_FCR_REG] &= (ECC_FCR_VER | ECC_FCR_IMPL); + + for (i = 1; i < ECC_NREGS; i++) + s->regs[i] = 0; +} + +void * ecc_init(target_phys_addr_t base, uint32_t version) +{ + int ecc_io_memory; + ECCState *s; + + s = qemu_mallocz(sizeof(ECCState)); + if (!s) + return NULL; + + s->regs[0] = version; + + ecc_io_memory = cpu_register_io_memory(0, ecc_mem_read, ecc_mem_write, s); + cpu_register_physical_memory(base, ECC_SIZE, ecc_io_memory); + register_savevm("ECC", base, 1, ecc_save, ecc_load, s); + qemu_register_reset(ecc_reset, s); + ecc_reset(s); + return s; +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 141a21e1a..3385adb91 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -72,6 +72,8 @@ struct hwdef { target_phys_addr_t serial_base, fd_base; target_phys_addr_t dma_base, esp_base, le_base; target_phys_addr_t tcx_base, cs_base, power_base; + target_phys_addr_t ecc_base; + uint32_t ecc_version; long vram_size, nvram_size; // IRQ numbers are not PIL ones, but master interrupt controller register // bit numbers @@ -479,6 +481,9 @@ static void sun4m_hw_init(const struct hwdef *hwdef, int RAM_size, nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, RAM_size, kernel_size, graphic_width, graphic_height, graphic_depth, hwdef->machine_id); + + if (hwdef->ecc_base != (target_phys_addr_t)-1) + ecc_init(hwdef->ecc_base, hwdef->ecc_version); } static const struct hwdef hwdefs[] = { @@ -498,6 +503,7 @@ static const struct hwdef hwdefs[] = { .esp_base = 0x78800000, .le_base = 0x78c00000, .power_base = 0x7a000000, + .ecc_base = -1, .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -534,6 +540,8 @@ static const struct hwdef hwdefs[] = { .esp_base = 0xef0800000ULL, .le_base = 0xef0c00000ULL, .power_base = 0xefa000000ULL, + .ecc_base = 0xf00000000ULL, + .ecc_version = 0x10000000, // version 0, implementation 1 .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, @@ -570,6 +578,8 @@ static const struct hwdef hwdefs[] = { .esp_base = 0xef0080000ULL, .le_base = 0xef0060000ULL, .power_base = 0xefa000000ULL, + .ecc_base = 0xf00000000ULL, + .ecc_version = 0x00000000, // version 0, implementation 0 .vram_size = 0x00100000, .nvram_size = 0x2000, .esp_irq = 18, diff --git a/hw/sun4m.h b/hw/sun4m.h index 1e8ffbb07..0a38897bb 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -72,4 +72,7 @@ void espdma_memory_write(void *opaque, uint8_t *buf, int len); void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, qemu_irq irq, qemu_irq *reset); +/* eccmemctl.c */ +void *ecc_init(target_phys_addr_t base, uint32_t version); + #endif -- cgit v1.2.3 From 089b7c0a4c2a0b0953ed4323f893eb5af2ca4e2c Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 9 Dec 2007 22:32:42 +0000 Subject: OMAP DMA 3.2 support by Lauro Ramos Venancio. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3786 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 1147 ++++++++++++++++++++++++++++++++++++++++++++++++------------- hw/omap.h | 50 ++- 2 files changed, 949 insertions(+), 248 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index 7312a66a7..e78ed4708 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -402,38 +402,50 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, } /* OMAP1 DMA module */ -typedef enum { - constant = 0, - post_incremented, - single_index, - double_index, -} omap_dma_addressing_t; - struct omap_dma_channel_s { + /* transfer data */ int burst[2]; int pack[2]; enum omap_dma_port port[2]; target_phys_addr_t addr[2]; omap_dma_addressing_t mode[2]; + uint16_t elements; + uint16_t frames; + int16_t frame_index[2]; + int16_t element_index[2]; int data_type; + + /* transfer type */ + int transparent_copy; + int constant_fill; + uint32_t color; + + /* auto init and linked channel data */ int end_prog; int repeat; int auto_init; - int priority; - int fs; - int sync; - int running; + int link_enabled; + int link_next_ch; + + /* interruption data */ int interrupts; int status; - int signalled; - int post_sync; - int transfer; - uint16_t elements; - uint16_t frames; - uint16_t frame_index; - uint16_t element_index; + + /* state data */ + int active; + int enable; + int sync; + int pending_request; + int waiting_end_prog; uint16_t cpc; + /* sync type */ + int fs; + int bs; + + /* compatibility */ + int omap_3_1_compatible_disable; + struct omap_dma_reg_set_s { target_phys_addr_t src, dest; int frame; @@ -443,16 +455,23 @@ struct omap_dma_channel_s { int frames; int elements; } active_set; + + /* unused parameters */ + int priority; + int interleave_disabled; + int type; }; struct omap_dma_s { - qemu_irq *ih; + qemu_irq irqs[16]; QEMUTimer *tm; struct omap_mpu_state_s *mpu; target_phys_addr_t base; omap_clk clk; int64_t delay; uint32_t drq; + enum omap_dma_model model; + int omap_3_1_mapping_disabled; uint16_t gcr; int run_count; @@ -462,27 +481,55 @@ struct omap_dma_s { struct omap_dma_lcd_channel_s lcd_ch; }; +/* Interrupts */ +#define TIMEOUT_INTR (1 << 0) +#define EVENT_DROP_INTR (1 << 1) +#define HALF_FRAME_INTR (1 << 2) +#define END_FRAME_INTR (1 << 3) +#define LAST_FRAME_INTR (1 << 4) +#define END_BLOCK_INTR (1 << 5) +#define SYNC (1 << 6) + +static int omap_dma_get_sibling_channel(struct omap_dma_s *s, int channel) +{ + if (s->omap_3_1_mapping_disabled) + return -1; + switch (channel) { + case 0 ... 2: + return channel + 6; + case 6 ... 8: + return channel % 6; + } + return -1; +} + static void omap_dma_interrupts_update(struct omap_dma_s *s) { - /* First three interrupts are shared between two channels each. */ - qemu_set_irq(s->ih[OMAP_INT_DMA_CH0_6], - (s->ch[0].status | s->ch[6].status) & 0x3f); - qemu_set_irq(s->ih[OMAP_INT_DMA_CH1_7], - (s->ch[1].status | s->ch[7].status) & 0x3f); - qemu_set_irq(s->ih[OMAP_INT_DMA_CH2_8], - (s->ch[2].status | s->ch[8].status) & 0x3f); - qemu_set_irq(s->ih[OMAP_INT_DMA_CH3], - (s->ch[3].status) & 0x3f); - qemu_set_irq(s->ih[OMAP_INT_DMA_CH4], - (s->ch[4].status) & 0x3f); - qemu_set_irq(s->ih[OMAP_INT_DMA_CH5], - (s->ch[5].status) & 0x3f); + int i, sibiling, raise; + + if (s->omap_3_1_mapping_disabled) { + for (i = 0; i < s->chans; i ++) { + if (s->ch[i].status) + qemu_irq_raise(s->irqs[i]); + } + } else { + /* First three interrupts are shared between two channels each. */ + for (i = 0; i < 6; i ++) { + raise = s->ch[i].status; + sibiling = omap_dma_get_sibling_channel(s, i); + if (sibiling != -1) + raise |= s->ch[sibiling].status; + if (raise) + qemu_irq_raise(s->irqs[i]); + } + } } static void omap_dma_channel_load(struct omap_dma_s *s, int ch) { struct omap_dma_reg_set_s *a = &s->ch[ch].active_set; int i; + int omap_3_1 = !s->ch[ch].omap_3_1_compatible_disable; /* * TODO: verify address ranges and alignment @@ -513,71 +560,126 @@ static void omap_dma_channel_load(struct omap_dma_s *s, int ch) break; case single_index: a->elem_delta[i] = s->ch[ch].data_type + - s->ch[ch].element_index - 1; - if (s->ch[ch].element_index > 0x7fff) - a->elem_delta[i] -= 0x10000; + s->ch[ch].element_index[omap_3_1 ? 0 : i] - 1; a->frame_delta[i] = 0; break; case double_index: a->elem_delta[i] = s->ch[ch].data_type + - s->ch[ch].element_index - 1; - if (s->ch[ch].element_index > 0x7fff) - a->elem_delta[i] -= 0x10000; - a->frame_delta[i] = s->ch[ch].frame_index - - s->ch[ch].element_index; - if (s->ch[ch].frame_index > 0x7fff) - a->frame_delta[i] -= 0x10000; + s->ch[ch].element_index[omap_3_1 ? 0 : i] - 1; + a->frame_delta[i] = s->ch[ch].frame_index[omap_3_1 ? 0 : i] - + s->ch[ch].element_index[omap_3_1 ? 0 : i]; break; default: break; } } -static inline void omap_dma_request_run(struct omap_dma_s *s, - int channel, int request) +static void omap_dma_activate_channel(struct omap_dma_s *s, int channel) { -next_channel: - if (request > 0) - for (; channel < 9; channel ++) - if (s->ch[channel].sync == request && s->ch[channel].running) - break; - if (channel >= 9) + if (!s->ch[channel].active) { + s->ch[channel].active = 1; + if (s->ch[channel].sync) + s->ch[channel].status |= SYNC; + s->run_count ++; + } + + if (s->delay && !qemu_timer_pending(s->tm)) + qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); +} + +static void omap_dma_deactivate_channel(struct omap_dma_s *s, int channel) +{ + /* Update cpc */ + s->ch[channel].cpc = s->ch[channel].active_set.dest & 0xffff; + + if (s->ch[channel].pending_request && + !s->ch[channel].waiting_end_prog) { + /* Don't deactivate the channel */ + s->ch[channel].pending_request = 0; return; + } - if (s->ch[channel].transfer) { - if (request > 0) { - s->ch[channel ++].post_sync = request; - goto next_channel; - } - s->ch[channel].status |= 0x02; /* Synchronisation drop */ - omap_dma_interrupts_update(s); + /* Don't deactive the channel if it is synchronized and the DMA request is + active */ + if (s->ch[channel].sync && (s->drq & (1 << s->ch[channel].sync))) return; + + if (s->ch[channel].active) { + s->ch[channel].active = 0; + s->ch[channel].status &= ~SYNC; + s->run_count --; } - if (!s->ch[channel].signalled) - s->run_count ++; - s->ch[channel].signalled = 1; + if (!s->run_count) + qemu_del_timer(s->tm); +} - if (request > 0) - s->ch[channel].status |= 0x40; /* External request */ +static void omap_dma_enable_channel(struct omap_dma_s *s, int channel) +{ + if (!s->ch[channel].enable) { + s->ch[channel].enable = 1; + s->ch[channel].waiting_end_prog = 0; + omap_dma_channel_load(s, channel); + if ((!s->ch[channel].sync) || (s->drq & (1 << s->ch[channel].sync))) + omap_dma_activate_channel(s, channel); + } +} - if (s->delay && !qemu_timer_pending(s->tm)) - qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); +static void omap_dma_disable_channel(struct omap_dma_s *s, int channel) +{ + if (s->ch[channel].enable) { + s->ch[channel].enable = 0; + /* Discard any pending request */ + s->ch[channel].pending_request = 0; + omap_dma_deactivate_channel(s, channel); + } +} - if (request > 0) { - channel ++; - goto next_channel; +static void omap_dma_channel_end_prog(struct omap_dma_s *s, int channel) +{ + if (s->ch[channel].waiting_end_prog) { + s->ch[channel].waiting_end_prog = 0; + if (!s->ch[channel].sync || s->ch[channel].pending_request) { + s->ch[channel].pending_request = 0; + omap_dma_activate_channel(s, channel); + } } } -static inline void omap_dma_request_stop(struct omap_dma_s *s, int channel) +static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s) { - if (s->ch[channel].signalled) - s->run_count --; - s->ch[channel].signalled = 0; + s->omap_3_1_mapping_disabled = 0; + s->chans = 9; +} - if (!s->run_count) - qemu_del_timer(s->tm); +static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s) +{ + s->omap_3_1_mapping_disabled = 1; + s->chans = 16; +} + +static void omap_dma_process_request(struct omap_dma_s *s, int request) +{ + int channel; + int drop_event = 0; + + for (channel = 0; channel < s->chans; channel ++) { + if (s->ch[channel].enable && s->ch[channel].sync == request) { + if (!s->ch[channel].active) + omap_dma_activate_channel(s, channel); + else if (!s->ch[channel].pending_request) + s->ch[channel].pending_request = 1; + else { + /* Request collision */ + /* Second request received while processing other request */ + s->ch[channel].status |= EVENT_DROP_INTR; + drop_event = 1; + } + } + } + + if (drop_event) + omap_dma_interrupts_update(s); } static void omap_dma_channel_run(struct omap_dma_s *s) @@ -588,97 +690,101 @@ static void omap_dma_channel_run(struct omap_dma_s *s) struct omap_dma_port_if_s *src_p, *dest_p; struct omap_dma_reg_set_s *a; - for (ch = 0; ch < 9; ch ++) { + for (ch = 0; ch < s->chans; ch ++) { + if (!s->ch[ch].active) + continue; + a = &s->ch[ch].active_set; src_p = &s->mpu->port[s->ch[ch].port[0]]; dest_p = &s->mpu->port[s->ch[ch].port[1]]; - if (s->ch[ch].signalled && (!src_p->addr_valid(s->mpu, a->src) || - !dest_p->addr_valid(s->mpu, a->dest))) { + if ((!s->ch[ch].constant_fill && !src_p->addr_valid(s->mpu, a->src)) || + (!dest_p->addr_valid(s->mpu, a->dest))) { #if 0 /* Bus time-out */ - if (s->ch[ch].interrupts & 0x01) - s->ch[ch].status |= 0x01; - omap_dma_request_stop(s, ch); + if (s->ch[ch].interrupts & TIMEOUT_INTR) + s->ch[ch].status |= TIMEOUT_INTR; + omap_dma_deactivate_channel(s, ch); continue; #endif printf("%s: Bus time-out in DMA%i operation\n", __FUNCTION__, ch); } status = s->ch[ch].status; - while (status == s->ch[ch].status && s->ch[ch].signalled) { + while (status == s->ch[ch].status && s->ch[ch].active) { /* Transfer a single element */ - s->ch[ch].transfer = 1; - cpu_physical_memory_read(a->src, value, s->ch[ch].data_type); - cpu_physical_memory_write(a->dest, value, s->ch[ch].data_type); - s->ch[ch].transfer = 0; + /* FIXME: check the endianness */ + if (!s->ch[ch].constant_fill) + cpu_physical_memory_read(a->src, value, s->ch[ch].data_type); + else + *(uint32_t *) value = s->ch[ch].color; + + if (!s->ch[ch].transparent_copy || + *(uint32_t *) value != s->ch[ch].color) + cpu_physical_memory_write(a->dest, value, s->ch[ch].data_type); a->src += a->elem_delta[0]; a->dest += a->elem_delta[1]; a->element ++; - /* Check interrupt conditions */ + /* If the channel is element synchronized, deactivate it */ + if (s->ch[ch].sync && !s->ch[ch].fs && !s->ch[ch].bs) + omap_dma_deactivate_channel(s, ch); + + /* If it is the last frame, set the LAST_FRAME interrupt */ + if (a->element == 1 && a->frame == a->frames - 1) + if (s->ch[ch].interrupts & LAST_FRAME_INTR) + s->ch[ch].status |= LAST_FRAME_INTR; + + /* If the half of the frame was reached, set the HALF_FRAME + interrupt */ + if (a->element == (a->elements >> 1)) + if (s->ch[ch].interrupts & HALF_FRAME_INTR) + s->ch[ch].status |= HALF_FRAME_INTR; + if (a->element == a->elements) { + /* End of Frame */ a->element = 0; a->src += a->frame_delta[0]; a->dest += a->frame_delta[1]; a->frame ++; - if (a->frame == a->frames) { - if (!s->ch[ch].repeat || !s->ch[ch].auto_init) - s->ch[ch].running = 0; + /* If the channel is frame synchronized, deactivate it */ + if (s->ch[ch].sync && s->ch[ch].fs) + omap_dma_deactivate_channel(s, ch); - if (s->ch[ch].auto_init && - (s->ch[ch].repeat || - s->ch[ch].end_prog)) - omap_dma_channel_load(s, ch); + /* If the channel is async, update cpc */ + if (!s->ch[ch].sync) + s->ch[ch].cpc = a->dest & 0xffff; - if (s->ch[ch].interrupts & 0x20) - s->ch[ch].status |= 0x20; + /* Set the END_FRAME interrupt */ + if (s->ch[ch].interrupts & END_FRAME_INTR) + s->ch[ch].status |= END_FRAME_INTR; - if (!s->ch[ch].sync) - omap_dma_request_stop(s, ch); - } - - if (s->ch[ch].interrupts & 0x08) - s->ch[ch].status |= 0x08; - - if (s->ch[ch].sync && s->ch[ch].fs && - !(s->drq & (1 << s->ch[ch].sync))) { - s->ch[ch].status &= ~0x40; - omap_dma_request_stop(s, ch); + if (a->frame == a->frames) { + /* End of Block */ + /* Disable the channel */ + + if (s->ch[ch].omap_3_1_compatible_disable) { + omap_dma_disable_channel(s, ch); + if (s->ch[ch].link_enabled) + omap_dma_enable_channel(s, s->ch[ch].link_next_ch); + } else { + if (!s->ch[ch].auto_init) + omap_dma_disable_channel(s, ch); + else if (s->ch[ch].repeat || s->ch[ch].end_prog) + omap_dma_channel_load(s, ch); + else { + s->ch[ch].waiting_end_prog = 1; + omap_dma_deactivate_channel(s, ch); + } + } + + if (s->ch[ch].interrupts & END_BLOCK_INTR) + s->ch[ch].status |= END_BLOCK_INTR; } } - - if (a->element == 1 && a->frame == a->frames - 1) - if (s->ch[ch].interrupts & 0x10) - s->ch[ch].status |= 0x10; - - if (a->element == (a->elements >> 1)) - if (s->ch[ch].interrupts & 0x04) - s->ch[ch].status |= 0x04; - - if (s->ch[ch].sync && !s->ch[ch].fs && - !(s->drq & (1 << s->ch[ch].sync))) { - s->ch[ch].status &= ~0x40; - omap_dma_request_stop(s, ch); - } - - /* - * Process requests made while the element was - * being transferred. - */ - if (s->ch[ch].post_sync) { - omap_dma_request_run(s, 0, s->ch[ch].post_sync); - s->ch[ch].post_sync = 0; - } - -#if 0 - break; -#endif } - - s->ch[ch].cpc = a->dest & 0x0000ffff; } omap_dma_interrupts_update(s); @@ -686,8 +792,29 @@ static void omap_dma_channel_run(struct omap_dma_s *s) qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); } -static int omap_dma_ch_reg_read(struct omap_dma_s *s, - int ch, int reg, uint16_t *value) { +static void omap_dma_reset(struct omap_dma_s *s) +{ + int i; + + qemu_del_timer(s->tm); + s->gcr = 0x0004; + s->drq = 0x00000000; + s->run_count = 0; + s->lcd_ch.src = emiff; + s->lcd_ch.condition = 0; + s->lcd_ch.interrupts = 0; + s->lcd_ch.dual = 0; + omap_dma_enable_3_1_mapping(s); + memset(s->ch, 0, sizeof(s->ch)); + for (i = 0; i < s->chans; i ++) + s->ch[i].interrupts = 0x0003; +} + +static int omap_dma_ch_reg_read(struct omap_dma_s *s, int ch, int reg, + uint16_t *value) +{ + int sibling; + switch (reg) { case 0x00: /* SYS_DMA_CSDP_CH0 */ *value = (s->ch[ch].burst[1] << 14) | @@ -700,12 +827,16 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, break; case 0x02: /* SYS_DMA_CCR_CH0 */ - *value = (s->ch[ch].mode[1] << 14) | + if (s->model == omap_dma_3_1) + *value = 0 << 10; /* FIFO_FLUSH bit */ + else + *value = s->ch[ch].omap_3_1_compatible_disable << 10; + *value |= (s->ch[ch].mode[1] << 14) | (s->ch[ch].mode[0] << 12) | (s->ch[ch].end_prog << 11) | (s->ch[ch].repeat << 9) | (s->ch[ch].auto_init << 8) | - (s->ch[ch].running << 7) | + (s->ch[ch].enable << 7) | (s->ch[ch].priority << 6) | (s->ch[ch].fs << 5) | s->ch[ch].sync; break; @@ -715,10 +846,18 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, break; case 0x06: /* SYS_DMA_CSR_CH0 */ - /* FIXME: shared CSR for channels sharing the interrupts */ + sibling = omap_dma_get_sibling_channel(s, ch); *value = s->ch[ch].status; - s->ch[ch].status &= 0x40; - omap_dma_interrupts_update(s); + s->ch[ch].status &= SYNC; + if (sibling != -1) { + *value |= (s->ch[sibling].status & 0x3f) << 6; + s->ch[sibling].status &= SYNC; + if (sibling < ch) { + qemu_irq_lower(s->irqs[sibling]); + break; + } + } + qemu_irq_lower(s->irqs[ch]); break; case 0x08: /* SYS_DMA_CSSA_L_CH0 */ @@ -746,15 +885,54 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, break; case 0x14: /* SYS_DMA_CFI_CH0 */ - *value = s->ch[ch].frame_index; + *value = s->ch[ch].frame_index[0]; break; case 0x16: /* SYS_DMA_CEI_CH0 */ - *value = s->ch[ch].element_index; + *value = s->ch[ch].element_index[0]; + break; + + case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ + if (s->ch[ch].omap_3_1_compatible_disable) + *value = s->ch[ch].active_set.src & 0xffff; /* CSAC */ + else + *value = s->ch[ch].cpc; + break; + + case 0x1a: /* DMA_CDAC */ + *value = s->ch[ch].active_set.dest & 0xffff; /* CDAC */ + break; + + case 0x1c: /* DMA_CDEI */ + *value = s->ch[ch].element_index[1]; + break; + + case 0x1e: /* DMA_CDFI */ + *value = s->ch[ch].frame_index[1]; + break; + + case 0x20: /* DMA_COLOR_L */ + *value = s->ch[ch].color & 0xffff; + break; + + case 0x22: /* DMA_COLOR_U */ + *value = s->ch[ch].color >> 16; break; - case 0x18: /* SYS_DMA_CPC_CH0 */ - *value = s->ch[ch].cpc; + case 0x24: /* DMA_CCR2 */ + *value = (s->ch[ch].bs << 2) | + (s->ch[ch].transparent_copy << 1) | + s->ch[ch].constant_fill; + break; + + case 0x28: /* DMA_CLNK_CTRL */ + *value = (s->ch[ch].link_enabled << 15) | + (s->ch[ch].link_next_ch & 0xf); + break; + + case 0x2a: /* DMA_LCH_CTRL */ + *value = (s->ch[ch].interleave_disabled << 15) | + s->ch[ch].type; break; default: @@ -764,7 +942,8 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, } static int omap_dma_ch_reg_write(struct omap_dma_s *s, - int ch, int reg, uint16_t value) { + int ch, int reg, uint16_t value) +{ switch (reg) { case 0x00: /* SYS_DMA_CSDP_CH0 */ s->ch[ch].burst[1] = (value & 0xc000) >> 14; @@ -788,30 +967,26 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, s->ch[ch].mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); s->ch[ch].mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); s->ch[ch].end_prog = (value & 0x0800) >> 11; + if (s->model > omap_dma_3_1) + s->ch[ch].omap_3_1_compatible_disable = (value >> 10) & 0x1; s->ch[ch].repeat = (value & 0x0200) >> 9; s->ch[ch].auto_init = (value & 0x0100) >> 8; s->ch[ch].priority = (value & 0x0040) >> 6; s->ch[ch].fs = (value & 0x0020) >> 5; s->ch[ch].sync = value & 0x001f; - if (value & 0x0080) { - if (s->ch[ch].running) { - if (!s->ch[ch].signalled && - s->ch[ch].auto_init && s->ch[ch].end_prog) - omap_dma_channel_load(s, ch); - } else { - s->ch[ch].running = 1; - omap_dma_channel_load(s, ch); - } - if (!s->ch[ch].sync || (s->drq & (1 << s->ch[ch].sync))) - omap_dma_request_run(s, ch, 0); - } else { - s->ch[ch].running = 0; - omap_dma_request_stop(s, ch); - } + + if (value & 0x0080) + omap_dma_enable_channel(s, ch); + else + omap_dma_disable_channel(s, ch); + + if (s->ch[ch].end_prog) + omap_dma_channel_end_prog(s, ch); + break; case 0x04: /* SYS_DMA_CICR_CH0 */ - s->ch[ch].interrupts = value & 0x003f; + s->ch[ch].interrupts = value; break; case 0x06: /* SYS_DMA_CSR_CH0 */ @@ -838,97 +1013,317 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, break; case 0x10: /* SYS_DMA_CEN_CH0 */ - s->ch[ch].elements = value & 0xffff; + s->ch[ch].elements = value; break; case 0x12: /* SYS_DMA_CFN_CH0 */ - s->ch[ch].frames = value & 0xffff; + s->ch[ch].frames = value; break; case 0x14: /* SYS_DMA_CFI_CH0 */ - s->ch[ch].frame_index = value & 0xffff; + s->ch[ch].frame_index[0] = (int16_t) value; break; case 0x16: /* SYS_DMA_CEI_CH0 */ - s->ch[ch].element_index = value & 0xffff; + s->ch[ch].element_index[0] = (int16_t) value; break; - case 0x18: /* SYS_DMA_CPC_CH0 */ - return 1; + case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ + OMAP_RO_REG((target_phys_addr_t) reg); + break; + + case 0x1c: /* DMA_CDEI */ + s->ch[ch].element_index[1] = (int16_t) value; + break; + + case 0x1e: /* DMA_CDFI */ + s->ch[ch].frame_index[1] = (int16_t) value; + break; + + case 0x20: /* DMA_COLOR_L */ + s->ch[ch].color &= 0xffff0000; + s->ch[ch].color |= value; + break; + + case 0x22: /* DMA_COLOR_U */ + s->ch[ch].color &= 0xffff; + s->ch[ch].color |= value << 16; + break; + + case 0x24: /* DMA_CCR2 */ + s->ch[ch].bs = (value >> 2) & 0x1; + s->ch[ch].transparent_copy = (value >> 1) & 0x1; + s->ch[ch].constant_fill = value & 0x1; + break; + + case 0x28: /* DMA_CLNK_CTRL */ + s->ch[ch].link_enabled = (value >> 15) & 0x1; + if (value & (1 << 14)) { /* Stop_Lnk */ + s->ch[ch].link_enabled = 0; + omap_dma_disable_channel(s, ch); + } + s->ch[ch].link_next_ch = value & 0x1f; + break; + + case 0x2a: /* DMA_LCH_CTRL */ + s->ch[ch].interleave_disabled = (value >> 15) & 0x1; + s->ch[ch].type = value & 0xf; + break; default: - OMAP_BAD_REG((target_phys_addr_t) reg); + return 1; } return 0; } -static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) +static int omap_dma_3_2_lcd_write(struct omap_dma_s *s, int offset, + uint16_t value) { - struct omap_dma_s *s = (struct omap_dma_s *) opaque; - int i, reg, ch, offset = addr - s->base; - uint16_t ret; - switch (offset) { - case 0x000 ... 0x2fe: - reg = offset & 0x3f; - ch = (offset >> 6) & 0x0f; - if (omap_dma_ch_reg_read(s, ch, reg, &ret)) - break; - return ret; + case 0xbc0: /* DMA_LCD_CSDP */ + s->lcd_ch.brust_f2 = (value >> 14) & 0x3; + s->lcd_ch.pack_f2 = (value >> 13) & 0x1; + s->lcd_ch.data_type_f2 = (1 << ((value >> 11) & 0x3)); + s->lcd_ch.brust_f1 = (value >> 7) & 0x3; + s->lcd_ch.pack_f1 = (value >> 6) & 0x1; + s->lcd_ch.data_type_f1 = (1 << ((value >> 0) & 0x3)); + break; - case 0x300: /* SYS_DMA_LCD_CTRL */ - i = s->lcd_ch.condition; + case 0xbc2: /* DMA_LCD_CCR */ + s->lcd_ch.mode_f2 = (value >> 14) & 0x3; + s->lcd_ch.mode_f1 = (value >> 12) & 0x3; + s->lcd_ch.end_prog = (value >> 11) & 0x1; + s->lcd_ch.omap_3_1_compatible_disable = (value >> 10) & 0x1; + s->lcd_ch.repeat = (value >> 9) & 0x1; + s->lcd_ch.auto_init = (value >> 8) & 0x1; + s->lcd_ch.running = (value >> 7) & 0x1; + s->lcd_ch.priority = (value >> 6) & 0x1; + s->lcd_ch.bs = (value >> 4) & 0x1; + break; + + case 0xbc4: /* DMA_LCD_CTRL */ + s->lcd_ch.dst = (value >> 8) & 0x1; + s->lcd_ch.src = ((value >> 6) & 0x3) << 1; s->lcd_ch.condition = 0; - qemu_irq_lower(s->lcd_ch.irq); - return ((s->lcd_ch.src == imif) << 6) | (i << 3) | - (s->lcd_ch.interrupts << 1) | s->lcd_ch.dual; + /* Assume no bus errors and thus no BUS_ERROR irq bits. */ + s->lcd_ch.interrupts = (value >> 1) & 1; + s->lcd_ch.dual = value & 1; + break; - case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ - return s->lcd_ch.src_f1_top & 0xffff; + case 0xbc8: /* TOP_B1_L */ + s->lcd_ch.src_f1_top &= 0xffff0000; + s->lcd_ch.src_f1_top |= 0x0000ffff & value; + break; - case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ - return s->lcd_ch.src_f1_top >> 16; + case 0xbca: /* TOP_B1_U */ + s->lcd_ch.src_f1_top &= 0x0000ffff; + s->lcd_ch.src_f1_top |= value << 16; + break; - case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ - return s->lcd_ch.src_f1_bottom & 0xffff; + case 0xbcc: /* BOT_B1_L */ + s->lcd_ch.src_f1_bottom &= 0xffff0000; + s->lcd_ch.src_f1_bottom |= 0x0000ffff & value; + break; - case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ - return s->lcd_ch.src_f1_bottom >> 16; + case 0xbce: /* BOT_B1_U */ + s->lcd_ch.src_f1_bottom &= 0x0000ffff; + s->lcd_ch.src_f1_bottom |= (uint32_t) value << 16; + break; - case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ - return s->lcd_ch.src_f2_top & 0xffff; + case 0xbd0: /* TOP_B2_L */ + s->lcd_ch.src_f2_top &= 0xffff0000; + s->lcd_ch.src_f2_top |= 0x0000ffff & value; + break; - case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ - return s->lcd_ch.src_f2_top >> 16; + case 0xbd2: /* TOP_B2_U */ + s->lcd_ch.src_f2_top &= 0x0000ffff; + s->lcd_ch.src_f2_top |= (uint32_t) value << 16; + break; - case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ - return s->lcd_ch.src_f2_bottom & 0xffff; + case 0xbd4: /* BOT_B2_L */ + s->lcd_ch.src_f2_bottom &= 0xffff0000; + s->lcd_ch.src_f2_bottom |= 0x0000ffff & value; + break; - case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ - return s->lcd_ch.src_f2_bottom >> 16; + case 0xbd6: /* BOT_B2_U */ + s->lcd_ch.src_f2_bottom &= 0x0000ffff; + s->lcd_ch.src_f2_bottom |= (uint32_t) value << 16; + break; - case 0x400: /* SYS_DMA_GCR */ - return s->gcr; - } + case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ + s->lcd_ch.element_index_f1 = value; + break; - OMAP_BAD_REG(addr); + case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ + s->lcd_ch.frame_index_f1 &= 0xffff0000; + s->lcd_ch.frame_index_f1 |= 0x0000ffff & value; + break; + + case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ + s->lcd_ch.frame_index_f1 &= 0x0000ffff; + s->lcd_ch.frame_index_f1 |= (uint32_t) value << 16; + break; + + case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ + s->lcd_ch.element_index_f2 = value; + break; + + case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ + s->lcd_ch.frame_index_f2 &= 0xffff0000; + s->lcd_ch.frame_index_f2 |= 0x0000ffff & value; + break; + + case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ + s->lcd_ch.frame_index_f2 &= 0x0000ffff; + s->lcd_ch.frame_index_f2 |= (uint32_t) value << 16; + break; + + case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ + s->lcd_ch.elements_f1 = value; + break; + + case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ + s->lcd_ch.frames_f1 = value; + break; + + case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ + s->lcd_ch.elements_f2 = value; + break; + + case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ + s->lcd_ch.frames_f2 = value; + break; + + case 0xbea: /* DMA_LCD_LCH_CTRL */ + s->lcd_ch.lch_type = value & 0xf; + break; + + default: + return 1; + } return 0; } -static void omap_dma_write(void *opaque, target_phys_addr_t addr, - uint32_t value) +static int omap_dma_3_2_lcd_read(struct omap_dma_s *s, int offset, + uint16_t *ret) { - struct omap_dma_s *s = (struct omap_dma_s *) opaque; - int reg, ch, offset = addr - s->base; - switch (offset) { - case 0x000 ... 0x2fe: - reg = offset & 0x3f; - ch = (offset >> 6) & 0x0f; - if (omap_dma_ch_reg_write(s, ch, reg, value)) - OMAP_RO_REG(addr); + case 0xbc0: /* DMA_LCD_CSDP */ + *ret = (s->lcd_ch.brust_f2 << 14) | + (s->lcd_ch.pack_f2 << 13) | + ((s->lcd_ch.data_type_f2 >> 1) << 11) | + (s->lcd_ch.brust_f1 << 7) | + (s->lcd_ch.pack_f1 << 6) | + ((s->lcd_ch.data_type_f1 >> 1) << 0); + break; + + case 0xbc2: /* DMA_LCD_CCR */ + *ret = (s->lcd_ch.mode_f2 << 14) | + (s->lcd_ch.mode_f1 << 12) | + (s->lcd_ch.end_prog << 11) | + (s->lcd_ch.omap_3_1_compatible_disable << 10) | + (s->lcd_ch.repeat << 9) | + (s->lcd_ch.auto_init << 8) | + (s->lcd_ch.running << 7) | + (s->lcd_ch.priority << 6) | + (s->lcd_ch.bs << 4); + break; + + case 0xbc4: /* DMA_LCD_CTRL */ + qemu_irq_lower(s->lcd_ch.irq); + *ret = (s->lcd_ch.dst << 8) | + ((s->lcd_ch.src & 0x6) << 5) | + (s->lcd_ch.condition << 3) | + (s->lcd_ch.interrupts << 1) | + s->lcd_ch.dual; + break; + + case 0xbc8: /* TOP_B1_L */ + *ret = s->lcd_ch.src_f1_top & 0xffff; + break; + + case 0xbca: /* TOP_B1_U */ + *ret = s->lcd_ch.src_f1_top >> 16; + break; + + case 0xbcc: /* BOT_B1_L */ + *ret = s->lcd_ch.src_f1_bottom & 0xffff; + break; + + case 0xbce: /* BOT_B1_U */ + *ret = s->lcd_ch.src_f1_bottom >> 16; + break; + + case 0xbd0: /* TOP_B2_L */ + *ret = s->lcd_ch.src_f2_top & 0xffff; + break; + + case 0xbd2: /* TOP_B2_U */ + *ret = s->lcd_ch.src_f2_top >> 16; + break; + + case 0xbd4: /* BOT_B2_L */ + *ret = s->lcd_ch.src_f2_bottom & 0xffff; break; + case 0xbd6: /* BOT_B2_U */ + *ret = s->lcd_ch.src_f2_bottom >> 16; + break; + + case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ + *ret = s->lcd_ch.element_index_f1; + break; + + case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ + *ret = s->lcd_ch.frame_index_f1 & 0xffff; + break; + + case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ + *ret = s->lcd_ch.frame_index_f1 >> 16; + break; + + case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ + *ret = s->lcd_ch.element_index_f2; + break; + + case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ + *ret = s->lcd_ch.frame_index_f2 & 0xffff; + break; + + case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ + *ret = s->lcd_ch.frame_index_f2 >> 16; + break; + + case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ + *ret = s->lcd_ch.elements_f1; + break; + + case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ + *ret = s->lcd_ch.frames_f1; + break; + + case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ + *ret = s->lcd_ch.elements_f2; + break; + + case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ + *ret = s->lcd_ch.frames_f2; + break; + + case 0xbea: /* DMA_LCD_LCH_CTRL */ + *ret = s->lcd_ch.lch_type; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_3_1_lcd_write(struct omap_dma_s *s, int offset, + uint16_t value) +{ + switch (offset) { case 0x300: /* SYS_DMA_LCD_CTRL */ s->lcd_ch.src = (value & 0x40) ? imif : emiff; s->lcd_ch.condition = 0; @@ -977,13 +1372,257 @@ static void omap_dma_write(void *opaque, target_phys_addr_t addr, s->lcd_ch.src_f2_bottom |= value << 16; break; + default: + return 1; + } + return 0; +} + +static int omap_dma_3_1_lcd_read(struct omap_dma_s *s, int offset, + uint16_t *ret) +{ + int i; + + switch (offset) { + case 0x300: /* SYS_DMA_LCD_CTRL */ + i = s->lcd_ch.condition; + s->lcd_ch.condition = 0; + qemu_irq_lower(s->lcd_ch.irq); + *ret = ((s->lcd_ch.src == imif) << 6) | (i << 3) | + (s->lcd_ch.interrupts << 1) | s->lcd_ch.dual; + break; + + case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ + *ret = s->lcd_ch.src_f1_top & 0xffff; + break; + + case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ + *ret = s->lcd_ch.src_f1_top >> 16; + break; + + case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ + *ret = s->lcd_ch.src_f1_bottom & 0xffff; + break; + + case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ + *ret = s->lcd_ch.src_f1_bottom >> 16; + break; + + case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ + *ret = s->lcd_ch.src_f2_top & 0xffff; + break; + + case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ + *ret = s->lcd_ch.src_f2_top >> 16; + break; + + case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ + *ret = s->lcd_ch.src_f2_bottom & 0xffff; + break; + + case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ + *ret = s->lcd_ch.src_f2_bottom >> 16; + break; + + default: + return 1; + } + return 0; +} + +static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value) +{ + switch (offset) { case 0x400: /* SYS_DMA_GCR */ - s->gcr = value & 0x000c; + s->gcr = value; + break; + + case 0x404: /* DMA_GSCR */ + if (value & 0x8) + omap_dma_disable_3_1_mapping(s); + else + omap_dma_enable_3_1_mapping(s); + break; + + case 0x408: /* DMA_GRST */ + if (value & 0x1) + omap_dma_reset(s); break; default: - OMAP_BAD_REG(addr); + return 1; } + return 0; +} + +static int omap_dma_sys_read(struct omap_dma_s *s, int offset, + uint16_t *ret) +{ + switch (offset) { + case 0x400: /* SYS_DMA_GCR */ + *ret = s->gcr; + break; + + case 0x404: /* DMA_GSCR */ + *ret = s->omap_3_1_mapping_disabled << 3; + break; + + case 0x408: /* DMA_GRST */ + *ret = 0; + break; + + case 0x442: /* DMA_HW_ID */ + case 0x444: /* DMA_PCh2_ID */ + case 0x446: /* DMA_PCh0_ID */ + case 0x448: /* DMA_PCh1_ID */ + case 0x44a: /* DMA_PChG_ID */ + case 0x44c: /* DMA_PChD_ID */ + *ret = 1; + break; + + case 0x44e: /* DMA_CAPS_0_U */ + *ret = (1 << 3) | /* Constant Fill Capacity */ + (1 << 2); /* Transparent BLT Capacity */ + break; + + case 0x450: /* DMA_CAPS_0_L */ + case 0x452: /* DMA_CAPS_1_U */ + *ret = 0; + break; + + case 0x454: /* DMA_CAPS_1_L */ + *ret = (1 << 1); /* 1-bit palletized capability */ + break; + + case 0x456: /* DMA_CAPS_2 */ + *ret = (1 << 8) | /* SSDIC */ + (1 << 7) | /* DDIAC */ + (1 << 6) | /* DSIAC */ + (1 << 5) | /* DPIAC */ + (1 << 4) | /* DCAC */ + (1 << 3) | /* SDIAC */ + (1 << 2) | /* SSIAC */ + (1 << 1) | /* SPIAC */ + 1; /* SCAC */ + break; + + case 0x458: /* DMA_CAPS_3 */ + *ret = (1 << 5) | /* CCC */ + (1 << 4) | /* IC */ + (1 << 3) | /* ARC */ + (1 << 2) | /* AEC */ + (1 << 1) | /* FSC */ + 1; /* ESC */ + break; + + case 0x45a: /* DMA_CAPS_4 */ + *ret = (1 << 6) | /* SSC */ + (1 << 5) | /* BIC */ + (1 << 4) | /* LFIC */ + (1 << 3) | /* FIC */ + (1 << 2) | /* HFIC */ + (1 << 1) | /* EDIC */ + 1; /* TOIC */ + break; + + case 0x460: /* DMA_PCh2_SR */ + case 0x480: /* DMA_PCh0_SR */ + case 0x482: /* DMA_PCh1_SR */ + case 0x4c0: /* DMA_PChD_SR_0 */ + printf("%s: Physical Channel Status Registers not implemented.\n", + __FUNCTION__); + *ret = 0xff; + break; + + default: + return 1; + } + return 0; +} + +static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int reg, ch, offset = addr - s->base; + uint16_t ret; + + switch (offset) { + case 0x300 ... 0x3fe: + if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { + if (omap_dma_3_1_lcd_read(s, offset, &ret)) + break; + return ret; + } + /* Fall through. */ + case 0x000 ... 0x2fe: + reg = offset & 0x3f; + ch = (offset >> 6) & 0x0f; + if (omap_dma_ch_reg_read(s, ch, reg, &ret)) + break; + return ret; + + case 0x404 ... 0x4fe: + if (s->model == omap_dma_3_1) + break; + /* Fall through. */ + case 0x400: + if (omap_dma_sys_read(s, offset, &ret)) + break; + return ret; + + case 0xb00 ... 0xbfe: + if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) { + if (omap_dma_3_2_lcd_read(s, offset, &ret)) + break; + return ret; + } + break; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_dma_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_dma_s *s = (struct omap_dma_s *) opaque; + int reg, ch, offset = addr - s->base; + + switch (offset) { + case 0x300 ... 0x3fe: + if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { + if (omap_dma_3_1_lcd_write(s, offset, value)) + break; + return; + } + /* Fall through. */ + case 0x000 ... 0x2fe: + reg = offset & 0x3f; + ch = (offset >> 6) & 0x0f; + if (omap_dma_ch_reg_write(s, ch, reg, value)) + break; + return; + + case 0x404 ... 0x4fe: + if (s->model == omap_dma_3_1) + break; + case 0x400: + /* Fall through. */ + if (omap_dma_sys_write(s, offset, value)) + break; + return; + + case 0xb00 ... 0xbfe: + if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) { + if (omap_dma_3_2_lcd_write(s, offset, value)) + break; + return; + } + break; + } + + OMAP_BAD_REG(addr); } static CPUReadMemoryFunc *omap_dma_readfn[] = { @@ -1005,7 +1644,7 @@ static void omap_dma_request(void *opaque, int drq, int req) if (req) { if (~s->drq & (1 << drq)) { s->drq |= 1 << drq; - omap_dma_request_run(s, 0, drq); + omap_dma_process_request(s, drq); } } else s->drq &= ~(1 << drq); @@ -1026,36 +1665,27 @@ static void omap_dma_clk_update(void *opaque, int line, int on) } } -static void omap_dma_reset(struct omap_dma_s *s) -{ - int i; - - qemu_del_timer(s->tm); - s->gcr = 0x0004; - s->drq = 0x00000000; - s->run_count = 0; - s->lcd_ch.src = emiff; - s->lcd_ch.condition = 0; - s->lcd_ch.interrupts = 0; - s->lcd_ch.dual = 0; - memset(s->ch, 0, sizeof(s->ch)); - for (i = 0; i < s->chans; i ++) - s->ch[i].interrupts = 0x0003; -} - -struct omap_dma_s *omap_dma_init(target_phys_addr_t base, - qemu_irq pic[], struct omap_mpu_state_s *mpu, omap_clk clk) +struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, + qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, + enum omap_dma_model model) { - int iomemtype; + int iomemtype, num_irqs, memsize; struct omap_dma_s *s = (struct omap_dma_s *) qemu_mallocz(sizeof(struct omap_dma_s)); - s->ih = pic; + if (model == omap_dma_3_1) { + num_irqs = 6; + memsize = 0x800; + } else { + num_irqs = 16; + memsize = 0xc00; + } + memcpy(s->irqs, irqs, num_irqs * sizeof(qemu_irq)); s->base = base; - s->chans = 9; + s->model = model; s->mpu = mpu; s->clk = clk; - s->lcd_ch.irq = pic[OMAP_INT_DMA_LCD]; + s->lcd_ch.irq = lcd_irq; s->lcd_ch.mpu = mpu; s->tm = qemu_new_timer(vm_clock, (QEMUTimerCB *) omap_dma_channel_run, s); omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); @@ -1065,7 +1695,7 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, omap_dma_readfn, omap_dma_writefn, s); - cpu_register_physical_memory(s->base, 0x800, iomemtype); + cpu_register_physical_memory(s->base, memsize, iomemtype); return s; } @@ -4919,13 +5549,39 @@ static void omap_mpu_wakeup(void *opaque, int irq, int req) cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB); } +struct dma_irq_map { + int ih; + int intr; +}; + +static const struct dma_irq_map omap_dma_irq_map[] = { + { 0, OMAP_INT_DMA_CH0_6 }, + { 0, OMAP_INT_DMA_CH1_7 }, + { 0, OMAP_INT_DMA_CH2_8 }, + { 0, OMAP_INT_DMA_CH3 }, + { 0, OMAP_INT_DMA_CH4 }, + { 0, OMAP_INT_DMA_CH5 }, + { 1, OMAP_INT_1610_DMA_CH6 }, + { 1, OMAP_INT_1610_DMA_CH7 }, + { 1, OMAP_INT_1610_DMA_CH8 }, + { 1, OMAP_INT_1610_DMA_CH9 }, + { 1, OMAP_INT_1610_DMA_CH10 }, + { 1, OMAP_INT_1610_DMA_CH11 }, + { 1, OMAP_INT_1610_DMA_CH12 }, + { 1, OMAP_INT_1610_DMA_CH13 }, + { 1, OMAP_INT_1610_DMA_CH14 }, + { 1, OMAP_INT_1610_DMA_CH15 } +}; + struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, DisplayState *ds, const char *core) { + int i; struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) qemu_mallocz(sizeof(struct omap_mpu_state_s)); ram_addr_t imif_base, emiff_base; qemu_irq *cpu_irq; + qemu_irq dma_irqs[6]; int sdindex; if (!core) @@ -4964,8 +5620,11 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->irq[0] = s->ih[0]->pins; s->irq[1] = s->ih[1]->pins; - s->dma = omap_dma_init(0xfffed800, s->irq[0], s, - omap_findclk(s, "dma_ck")); + for (i = 0; i < 6; i ++) + dma_irqs[i] = s->irq[omap_dma_irq_map[i].ih][omap_dma_irq_map[i].intr]; + s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD], + s, omap_findclk(s, "dma_ck"), omap_dma_3_1); + s->port[emiff ].addr_valid = omap_validate_emiff_addr; s->port[emifs ].addr_valid = omap_validate_emifs_addr; s->port[imif ].addr_valid = omap_validate_imif_addr; diff --git a/hw/omap.h b/hw/omap.h index cd4e53bc9..18145ed80 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -336,26 +336,68 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, # define OMAP_INT_243X_HS_USB_DMA 93 # define OMAP_INT_243X_CARKIT 94 +enum omap_dma_model { + omap_dma_3_1 = 0, + omap_dma_3_2 +}; + struct omap_dma_s; -struct omap_dma_s *omap_dma_init(target_phys_addr_t base, - qemu_irq pic[], struct omap_mpu_state_s *mpu, omap_clk clk); +struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, + qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, + enum omap_dma_model model); enum omap_dma_port { emiff = 0, emifs, - imif, + imif, /* omap16xx: ocp_t1 */ tipb, - local, + local, /* omap16xx: ocp_t2 */ tipb_mpui, omap_dma_port_last, }; +typedef enum { + constant = 0, + post_incremented, + single_index, + double_index, +} omap_dma_addressing_t; + struct omap_dma_lcd_channel_s { enum omap_dma_port src; target_phys_addr_t src_f1_top; target_phys_addr_t src_f1_bottom; target_phys_addr_t src_f2_top; target_phys_addr_t src_f2_bottom; + + /* Used in OMAP DMA 3.2 gigacell */ + unsigned char brust_f1; + unsigned char pack_f1; + unsigned char data_type_f1; + unsigned char brust_f2; + unsigned char pack_f2; + unsigned char data_type_f2; + unsigned char end_prog; + unsigned char repeat; + unsigned char auto_init; + unsigned char priority; + unsigned char fs; + unsigned char running; + unsigned char bs; + unsigned char omap_3_1_compatible_disable; + unsigned char dst; + unsigned char lch_type; + int16_t element_index_f1; + int16_t element_index_f2; + int32_t frame_index_f1; + int32_t frame_index_f2; + uint16_t elements_f1; + uint16_t frames_f1; + uint16_t elements_f2; + uint16_t frames_f2; + omap_dma_addressing_t mode_f1; + omap_dma_addressing_t mode_f2; + /* Destination port is fixed. */ int interrupts; int condition; -- cgit v1.2.3 From d1781191a557d2334bba9d8ef2207b80714fab6f Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 23:02:39 +0000 Subject: Remove leftover support for 82371FB (Step A1), by Carlo Marcelo Arenas Belon. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3787 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/piix_pci.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 37352c430..066817be6 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -314,31 +314,6 @@ static int piix_load(QEMUFile* f, void *opaque, int version_id) return pci_device_load(d, f); } -static int piix_init(PCIBus *bus, int devfn) -{ - PCIDevice *d; - uint8_t *pci_conf; - - d = pci_register_device(bus, "PIIX", sizeof(PCIDevice), - devfn, NULL, NULL); - register_savevm("PIIX", 0, 2, piix_save, piix_load, d); - - piix3_dev = d; - pci_conf = d->config; - - pci_conf[0x00] = 0x86; // Intel - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x2E; // 82371FB PIIX PCI-to-ISA bridge - pci_conf[0x03] = 0x12; - pci_conf[0x08] = 0x02; // Step A1 - pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA - pci_conf[0x0b] = 0x06; // class_base = PCI_bridge - pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic - - piix3_reset(d); - return d->devfn; -} - int piix3_init(PCIBus *bus, int devfn) { PCIDevice *d; -- cgit v1.2.3 From 982f3ab679dd60e2b7cc4c0038f72b59376171dc Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 9 Dec 2007 23:12:55 +0000 Subject: Fix execve argc/envc counting, by Takashi Yoshii. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3788 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 590c72fa4..0deb041ed 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3190,7 +3190,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, argc = 0; guest_argp = arg2; - for (gp = guest_argp; ; gp++) { + for (gp = guest_argp; ; gp += sizeof(abi_ulong)) { if (get_user_ual(addr, gp)) goto efault; if (!addr) @@ -3199,7 +3199,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } envc = 0; guest_envp = arg3; - for (gp = guest_envp; ; gp++) { + for (gp = guest_envp; ; gp += sizeof(abi_ulong)) { if (get_user_ual(addr, gp)) goto efault; if (!addr) -- cgit v1.2.3 From 11e0fc3fd0be860f54c543c7ac1a9a7242a7ba26 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 9 Dec 2007 23:23:02 +0000 Subject: Use pointers to channels rather than channel numbers in the DMA. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3789 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 753 ++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 390 insertions(+), 363 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index e78ed4708..db15acc36 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -446,6 +446,9 @@ struct omap_dma_channel_s { /* compatibility */ int omap_3_1_compatible_disable; + qemu_irq irq; + struct omap_dma_channel_s *sibling; + struct omap_dma_reg_set_s { target_phys_addr_t src, dest; int frame; @@ -463,7 +466,6 @@ struct omap_dma_channel_s { }; struct omap_dma_s { - qemu_irq irqs[16]; QEMUTimer *tm; struct omap_mpu_state_s *mpu; target_phys_addr_t base; @@ -490,96 +492,81 @@ struct omap_dma_s { #define END_BLOCK_INTR (1 << 5) #define SYNC (1 << 6) -static int omap_dma_get_sibling_channel(struct omap_dma_s *s, int channel) -{ - if (s->omap_3_1_mapping_disabled) - return -1; - switch (channel) { - case 0 ... 2: - return channel + 6; - case 6 ... 8: - return channel % 6; - } - return -1; -} - static void omap_dma_interrupts_update(struct omap_dma_s *s) { - int i, sibiling, raise; + struct omap_dma_channel_s *ch = s->ch; + int i; if (s->omap_3_1_mapping_disabled) { - for (i = 0; i < s->chans; i ++) { - if (s->ch[i].status) - qemu_irq_raise(s->irqs[i]); - } + for (i = 0; i < s->chans; i ++, ch ++) + if (ch->status) + qemu_irq_raise(ch->irq); } else { /* First three interrupts are shared between two channels each. */ - for (i = 0; i < 6; i ++) { - raise = s->ch[i].status; - sibiling = omap_dma_get_sibling_channel(s, i); - if (sibiling != -1) - raise |= s->ch[sibiling].status; - if (raise) - qemu_irq_raise(s->irqs[i]); + for (i = 0; i < 6; i ++, ch ++) { + if (ch->status || (ch->sibling && ch->sibling->status)) + qemu_irq_raise(ch->irq); } } } -static void omap_dma_channel_load(struct omap_dma_s *s, int ch) +static void omap_dma_channel_load(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) { - struct omap_dma_reg_set_s *a = &s->ch[ch].active_set; + struct omap_dma_reg_set_s *a = &ch->active_set; int i; - int omap_3_1 = !s->ch[ch].omap_3_1_compatible_disable; + int omap_3_1 = !ch->omap_3_1_compatible_disable; /* * TODO: verify address ranges and alignment * TODO: port endianness */ - a->src = s->ch[ch].addr[0]; - a->dest = s->ch[ch].addr[1]; - a->frames = s->ch[ch].frames; - a->elements = s->ch[ch].elements; + a->src = ch->addr[0]; + a->dest = ch->addr[1]; + a->frames = ch->frames; + a->elements = ch->elements; a->frame = 0; a->element = 0; - if (unlikely(!s->ch[ch].elements || !s->ch[ch].frames)) { + if (unlikely(!ch->elements || !ch->frames)) { printf("%s: bad DMA request\n", __FUNCTION__); return; } for (i = 0; i < 2; i ++) - switch (s->ch[ch].mode[i]) { + switch (ch->mode[i]) { case constant: a->elem_delta[i] = 0; a->frame_delta[i] = 0; break; case post_incremented: - a->elem_delta[i] = s->ch[ch].data_type; + a->elem_delta[i] = ch->data_type; a->frame_delta[i] = 0; break; case single_index: - a->elem_delta[i] = s->ch[ch].data_type + - s->ch[ch].element_index[omap_3_1 ? 0 : i] - 1; + a->elem_delta[i] = ch->data_type + + ch->element_index[omap_3_1 ? 0 : i] - 1; a->frame_delta[i] = 0; break; case double_index: - a->elem_delta[i] = s->ch[ch].data_type + - s->ch[ch].element_index[omap_3_1 ? 0 : i] - 1; - a->frame_delta[i] = s->ch[ch].frame_index[omap_3_1 ? 0 : i] - - s->ch[ch].element_index[omap_3_1 ? 0 : i]; + a->elem_delta[i] = ch->data_type + + ch->element_index[omap_3_1 ? 0 : i] - 1; + a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] - + ch->element_index[omap_3_1 ? 0 : i]; break; default: break; } } -static void omap_dma_activate_channel(struct omap_dma_s *s, int channel) +static void omap_dma_activate_channel(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) { - if (!s->ch[channel].active) { - s->ch[channel].active = 1; - if (s->ch[channel].sync) - s->ch[channel].status |= SYNC; + if (!ch->active) { + ch->active = 1; + if (ch->sync) + ch->status |= SYNC; s->run_count ++; } @@ -587,26 +574,26 @@ static void omap_dma_activate_channel(struct omap_dma_s *s, int channel) qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); } -static void omap_dma_deactivate_channel(struct omap_dma_s *s, int channel) +static void omap_dma_deactivate_channel(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) { /* Update cpc */ - s->ch[channel].cpc = s->ch[channel].active_set.dest & 0xffff; + ch->cpc = ch->active_set.dest & 0xffff; - if (s->ch[channel].pending_request && - !s->ch[channel].waiting_end_prog) { + if (ch->pending_request && !ch->waiting_end_prog) { /* Don't deactivate the channel */ - s->ch[channel].pending_request = 0; + ch->pending_request = 0; return; } /* Don't deactive the channel if it is synchronized and the DMA request is active */ - if (s->ch[channel].sync && (s->drq & (1 << s->ch[channel].sync))) + if (ch->sync && (s->drq & (1 << ch->sync))) return; - if (s->ch[channel].active) { - s->ch[channel].active = 0; - s->ch[channel].status &= ~SYNC; + if (ch->active) { + ch->active = 0; + ch->status &= ~SYNC; s->run_count --; } @@ -614,34 +601,37 @@ static void omap_dma_deactivate_channel(struct omap_dma_s *s, int channel) qemu_del_timer(s->tm); } -static void omap_dma_enable_channel(struct omap_dma_s *s, int channel) +static void omap_dma_enable_channel(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) { - if (!s->ch[channel].enable) { - s->ch[channel].enable = 1; - s->ch[channel].waiting_end_prog = 0; - omap_dma_channel_load(s, channel); - if ((!s->ch[channel].sync) || (s->drq & (1 << s->ch[channel].sync))) - omap_dma_activate_channel(s, channel); + if (!ch->enable) { + ch->enable = 1; + ch->waiting_end_prog = 0; + omap_dma_channel_load(s, ch); + if ((!ch->sync) || (s->drq & (1 << ch->sync))) + omap_dma_activate_channel(s, ch); } } -static void omap_dma_disable_channel(struct omap_dma_s *s, int channel) +static void omap_dma_disable_channel(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) { - if (s->ch[channel].enable) { - s->ch[channel].enable = 0; + if (ch->enable) { + ch->enable = 0; /* Discard any pending request */ - s->ch[channel].pending_request = 0; - omap_dma_deactivate_channel(s, channel); + ch->pending_request = 0; + omap_dma_deactivate_channel(s, ch); } } -static void omap_dma_channel_end_prog(struct omap_dma_s *s, int channel) +static void omap_dma_channel_end_prog(struct omap_dma_s *s, + struct omap_dma_channel_s *ch) { - if (s->ch[channel].waiting_end_prog) { - s->ch[channel].waiting_end_prog = 0; - if (!s->ch[channel].sync || s->ch[channel].pending_request) { - s->ch[channel].pending_request = 0; - omap_dma_activate_channel(s, channel); + if (ch->waiting_end_prog) { + ch->waiting_end_prog = 0; + if (!ch->sync || ch->pending_request) { + ch->pending_request = 0; + omap_dma_activate_channel(s, ch); } } } @@ -662,17 +652,18 @@ static void omap_dma_process_request(struct omap_dma_s *s, int request) { int channel; int drop_event = 0; - - for (channel = 0; channel < s->chans; channel ++) { - if (s->ch[channel].enable && s->ch[channel].sync == request) { - if (!s->ch[channel].active) - omap_dma_activate_channel(s, channel); - else if (!s->ch[channel].pending_request) - s->ch[channel].pending_request = 1; + struct omap_dma_channel_s *ch = s->ch; + + for (channel = 0; channel < s->chans; channel ++, ch ++) { + if (ch->enable && ch->sync == request) { + if (!ch->active) + omap_dma_activate_channel(s, ch); + else if (!ch->pending_request) + ch->pending_request = 1; else { /* Request collision */ /* Second request received while processing other request */ - s->ch[channel].status |= EVENT_DROP_INTR; + ch->status |= EVENT_DROP_INTR; drop_event = 1; } } @@ -684,63 +675,65 @@ static void omap_dma_process_request(struct omap_dma_s *s, int request) static void omap_dma_channel_run(struct omap_dma_s *s) { - int ch; + int n = s->chans; uint16_t status; uint8_t value[4]; struct omap_dma_port_if_s *src_p, *dest_p; struct omap_dma_reg_set_s *a; + struct omap_dma_channel_s *ch; - for (ch = 0; ch < s->chans; ch ++) { - if (!s->ch[ch].active) + for (ch = s->ch; n; n --, ch ++) { + if (!ch->active) continue; - a = &s->ch[ch].active_set; + a = &ch->active_set; - src_p = &s->mpu->port[s->ch[ch].port[0]]; - dest_p = &s->mpu->port[s->ch[ch].port[1]]; - if ((!s->ch[ch].constant_fill && !src_p->addr_valid(s->mpu, a->src)) || + src_p = &s->mpu->port[ch->port[0]]; + dest_p = &s->mpu->port[ch->port[1]]; + if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) || (!dest_p->addr_valid(s->mpu, a->dest))) { #if 0 /* Bus time-out */ - if (s->ch[ch].interrupts & TIMEOUT_INTR) - s->ch[ch].status |= TIMEOUT_INTR; + if (ch->interrupts & TIMEOUT_INTR) + ch->status |= TIMEOUT_INTR; omap_dma_deactivate_channel(s, ch); continue; #endif - printf("%s: Bus time-out in DMA%i operation\n", __FUNCTION__, ch); + printf("%s: Bus time-out in DMA%i operation\n", + __FUNCTION__, s->chans - n); } - status = s->ch[ch].status; - while (status == s->ch[ch].status && s->ch[ch].active) { + status = ch->status; + while (status == ch->status && ch->active) { /* Transfer a single element */ /* FIXME: check the endianness */ - if (!s->ch[ch].constant_fill) - cpu_physical_memory_read(a->src, value, s->ch[ch].data_type); + if (!ch->constant_fill) + cpu_physical_memory_read(a->src, value, ch->data_type); else - *(uint32_t *) value = s->ch[ch].color; + *(uint32_t *) value = ch->color; - if (!s->ch[ch].transparent_copy || - *(uint32_t *) value != s->ch[ch].color) - cpu_physical_memory_write(a->dest, value, s->ch[ch].data_type); + if (!ch->transparent_copy || + *(uint32_t *) value != ch->color) + cpu_physical_memory_write(a->dest, value, ch->data_type); a->src += a->elem_delta[0]; a->dest += a->elem_delta[1]; a->element ++; /* If the channel is element synchronized, deactivate it */ - if (s->ch[ch].sync && !s->ch[ch].fs && !s->ch[ch].bs) + if (ch->sync && !ch->fs && !ch->bs) omap_dma_deactivate_channel(s, ch); /* If it is the last frame, set the LAST_FRAME interrupt */ if (a->element == 1 && a->frame == a->frames - 1) - if (s->ch[ch].interrupts & LAST_FRAME_INTR) - s->ch[ch].status |= LAST_FRAME_INTR; + if (ch->interrupts & LAST_FRAME_INTR) + ch->status |= LAST_FRAME_INTR; /* If the half of the frame was reached, set the HALF_FRAME interrupt */ if (a->element == (a->elements >> 1)) - if (s->ch[ch].interrupts & HALF_FRAME_INTR) - s->ch[ch].status |= HALF_FRAME_INTR; + if (ch->interrupts & HALF_FRAME_INTR) + ch->status |= HALF_FRAME_INTR; if (a->element == a->elements) { /* End of Frame */ @@ -750,38 +743,39 @@ static void omap_dma_channel_run(struct omap_dma_s *s) a->frame ++; /* If the channel is frame synchronized, deactivate it */ - if (s->ch[ch].sync && s->ch[ch].fs) + if (ch->sync && ch->fs) omap_dma_deactivate_channel(s, ch); /* If the channel is async, update cpc */ - if (!s->ch[ch].sync) - s->ch[ch].cpc = a->dest & 0xffff; + if (!ch->sync) + ch->cpc = a->dest & 0xffff; /* Set the END_FRAME interrupt */ - if (s->ch[ch].interrupts & END_FRAME_INTR) - s->ch[ch].status |= END_FRAME_INTR; + if (ch->interrupts & END_FRAME_INTR) + ch->status |= END_FRAME_INTR; if (a->frame == a->frames) { /* End of Block */ /* Disable the channel */ - if (s->ch[ch].omap_3_1_compatible_disable) { + if (ch->omap_3_1_compatible_disable) { omap_dma_disable_channel(s, ch); - if (s->ch[ch].link_enabled) - omap_dma_enable_channel(s, s->ch[ch].link_next_ch); + if (ch->link_enabled) + omap_dma_enable_channel(s, + &s->ch[ch->link_next_ch]); } else { - if (!s->ch[ch].auto_init) + if (!ch->auto_init) omap_dma_disable_channel(s, ch); - else if (s->ch[ch].repeat || s->ch[ch].end_prog) + else if (ch->repeat || ch->end_prog) omap_dma_channel_load(s, ch); else { - s->ch[ch].waiting_end_prog = 1; + ch->waiting_end_prog = 1; omap_dma_deactivate_channel(s, ch); } } - if (s->ch[ch].interrupts & END_BLOCK_INTR) - s->ch[ch].status |= END_BLOCK_INTR; + if (ch->interrupts & END_BLOCK_INTR) + ch->status |= END_BLOCK_INTR; } } } @@ -805,134 +799,161 @@ static void omap_dma_reset(struct omap_dma_s *s) s->lcd_ch.interrupts = 0; s->lcd_ch.dual = 0; omap_dma_enable_3_1_mapping(s); - memset(s->ch, 0, sizeof(s->ch)); - for (i = 0; i < s->chans; i ++) + for (i = 0; i < s->chans; i ++) { + memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst)); + memset(&s->ch[i].port, 0, sizeof(s->ch[i].port)); + memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode)); + memset(&s->ch[i].elements, 0, sizeof(s->ch[i].elements)); + memset(&s->ch[i].frames, 0, sizeof(s->ch[i].frames)); + memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index)); + memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index)); + memset(&s->ch[i].data_type, 0, sizeof(s->ch[i].data_type)); + memset(&s->ch[i].transparent_copy, 0, + sizeof(s->ch[i].transparent_copy)); + memset(&s->ch[i].constant_fill, 0, sizeof(s->ch[i].constant_fill)); + memset(&s->ch[i].color, 0, sizeof(s->ch[i].color)); + memset(&s->ch[i].end_prog, 0, sizeof(s->ch[i].end_prog)); + memset(&s->ch[i].repeat, 0, sizeof(s->ch[i].repeat)); + memset(&s->ch[i].auto_init, 0, sizeof(s->ch[i].auto_init)); + memset(&s->ch[i].link_enabled, 0, sizeof(s->ch[i].link_enabled)); + memset(&s->ch[i].link_next_ch, 0, sizeof(s->ch[i].link_next_ch)); s->ch[i].interrupts = 0x0003; + memset(&s->ch[i].status, 0, sizeof(s->ch[i].status)); + memset(&s->ch[i].active, 0, sizeof(s->ch[i].active)); + memset(&s->ch[i].enable, 0, sizeof(s->ch[i].enable)); + memset(&s->ch[i].sync, 0, sizeof(s->ch[i].sync)); + memset(&s->ch[i].pending_request, 0, sizeof(s->ch[i].pending_request)); + memset(&s->ch[i].waiting_end_prog, 0, + sizeof(s->ch[i].waiting_end_prog)); + memset(&s->ch[i].cpc, 0, sizeof(s->ch[i].cpc)); + memset(&s->ch[i].fs, 0, sizeof(s->ch[i].fs)); + memset(&s->ch[i].bs, 0, sizeof(s->ch[i].bs)); + memset(&s->ch[i].omap_3_1_compatible_disable, 0, + sizeof(s->ch[i].omap_3_1_compatible_disable)); + memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set)); + memset(&s->ch[i].priority, 0, sizeof(s->ch[i].priority)); + memset(&s->ch[i].interleave_disabled, 0, + sizeof(s->ch[i].interleave_disabled)); + memset(&s->ch[i].type, 0, sizeof(s->ch[i].type)); + } } -static int omap_dma_ch_reg_read(struct omap_dma_s *s, int ch, int reg, - uint16_t *value) +static int omap_dma_ch_reg_read(struct omap_dma_s *s, + struct omap_dma_channel_s *ch, int reg, uint16_t *value) { - int sibling; - switch (reg) { case 0x00: /* SYS_DMA_CSDP_CH0 */ - *value = (s->ch[ch].burst[1] << 14) | - (s->ch[ch].pack[1] << 13) | - (s->ch[ch].port[1] << 9) | - (s->ch[ch].burst[0] << 7) | - (s->ch[ch].pack[0] << 6) | - (s->ch[ch].port[0] << 2) | - (s->ch[ch].data_type >> 1); + *value = (ch->burst[1] << 14) | + (ch->pack[1] << 13) | + (ch->port[1] << 9) | + (ch->burst[0] << 7) | + (ch->pack[0] << 6) | + (ch->port[0] << 2) | + (ch->data_type >> 1); break; case 0x02: /* SYS_DMA_CCR_CH0 */ if (s->model == omap_dma_3_1) - *value = 0 << 10; /* FIFO_FLUSH bit */ + *value = 0 << 10; /* FIFO_FLUSH reads as 0 */ else - *value = s->ch[ch].omap_3_1_compatible_disable << 10; - *value |= (s->ch[ch].mode[1] << 14) | - (s->ch[ch].mode[0] << 12) | - (s->ch[ch].end_prog << 11) | - (s->ch[ch].repeat << 9) | - (s->ch[ch].auto_init << 8) | - (s->ch[ch].enable << 7) | - (s->ch[ch].priority << 6) | - (s->ch[ch].fs << 5) | s->ch[ch].sync; + *value = ch->omap_3_1_compatible_disable << 10; + *value |= (ch->mode[1] << 14) | + (ch->mode[0] << 12) | + (ch->end_prog << 11) | + (ch->repeat << 9) | + (ch->auto_init << 8) | + (ch->enable << 7) | + (ch->priority << 6) | + (ch->fs << 5) | ch->sync; break; case 0x04: /* SYS_DMA_CICR_CH0 */ - *value = s->ch[ch].interrupts; + *value = ch->interrupts; break; case 0x06: /* SYS_DMA_CSR_CH0 */ - sibling = omap_dma_get_sibling_channel(s, ch); - *value = s->ch[ch].status; - s->ch[ch].status &= SYNC; - if (sibling != -1) { - *value |= (s->ch[sibling].status & 0x3f) << 6; - s->ch[sibling].status &= SYNC; - if (sibling < ch) { - qemu_irq_lower(s->irqs[sibling]); - break; - } + *value = ch->status; + ch->status &= SYNC; + if (!ch->omap_3_1_compatible_disable && ch->sibling) { + *value |= (ch->sibling->status & 0x3f) << 6; + ch->sibling->status &= SYNC; } - qemu_irq_lower(s->irqs[ch]); + qemu_irq_lower(ch->irq); break; case 0x08: /* SYS_DMA_CSSA_L_CH0 */ - *value = s->ch[ch].addr[0] & 0x0000ffff; + *value = ch->addr[0] & 0x0000ffff; break; case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ - *value = s->ch[ch].addr[0] >> 16; + *value = ch->addr[0] >> 16; break; case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ - *value = s->ch[ch].addr[1] & 0x0000ffff; + *value = ch->addr[1] & 0x0000ffff; break; case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ - *value = s->ch[ch].addr[1] >> 16; + *value = ch->addr[1] >> 16; break; case 0x10: /* SYS_DMA_CEN_CH0 */ - *value = s->ch[ch].elements; + *value = ch->elements; break; case 0x12: /* SYS_DMA_CFN_CH0 */ - *value = s->ch[ch].frames; + *value = ch->frames; break; case 0x14: /* SYS_DMA_CFI_CH0 */ - *value = s->ch[ch].frame_index[0]; + *value = ch->frame_index[0]; break; case 0x16: /* SYS_DMA_CEI_CH0 */ - *value = s->ch[ch].element_index[0]; + *value = ch->element_index[0]; break; case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ - if (s->ch[ch].omap_3_1_compatible_disable) - *value = s->ch[ch].active_set.src & 0xffff; /* CSAC */ + if (ch->omap_3_1_compatible_disable) + *value = ch->active_set.src & 0xffff; /* CSAC */ else - *value = s->ch[ch].cpc; + *value = ch->cpc; break; case 0x1a: /* DMA_CDAC */ - *value = s->ch[ch].active_set.dest & 0xffff; /* CDAC */ + *value = ch->active_set.dest & 0xffff; /* CDAC */ break; case 0x1c: /* DMA_CDEI */ - *value = s->ch[ch].element_index[1]; + *value = ch->element_index[1]; break; case 0x1e: /* DMA_CDFI */ - *value = s->ch[ch].frame_index[1]; + *value = ch->frame_index[1]; break; case 0x20: /* DMA_COLOR_L */ - *value = s->ch[ch].color & 0xffff; + *value = ch->color & 0xffff; break; case 0x22: /* DMA_COLOR_U */ - *value = s->ch[ch].color >> 16; + *value = ch->color >> 16; break; case 0x24: /* DMA_CCR2 */ - *value = (s->ch[ch].bs << 2) | - (s->ch[ch].transparent_copy << 1) | - s->ch[ch].constant_fill; + *value = (ch->bs << 2) | + (ch->transparent_copy << 1) | + ch->constant_fill; break; case 0x28: /* DMA_CLNK_CTRL */ - *value = (s->ch[ch].link_enabled << 15) | - (s->ch[ch].link_next_ch & 0xf); + *value = (ch->link_enabled << 15) | + (ch->link_next_ch & 0xf); break; case 0x2a: /* DMA_LCH_CTRL */ - *value = (s->ch[ch].interleave_disabled << 15) | - s->ch[ch].type; + *value = (ch->interleave_disabled << 15) | + ch->type; break; default: @@ -942,90 +963,91 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, int ch, int reg, } static int omap_dma_ch_reg_write(struct omap_dma_s *s, - int ch, int reg, uint16_t value) + struct omap_dma_channel_s *ch, int reg, uint16_t value) { switch (reg) { case 0x00: /* SYS_DMA_CSDP_CH0 */ - s->ch[ch].burst[1] = (value & 0xc000) >> 14; - s->ch[ch].pack[1] = (value & 0x2000) >> 13; - s->ch[ch].port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9); - s->ch[ch].burst[0] = (value & 0x0180) >> 7; - s->ch[ch].pack[0] = (value & 0x0040) >> 6; - s->ch[ch].port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2); - s->ch[ch].data_type = (1 << (value & 3)); - if (s->ch[ch].port[0] >= omap_dma_port_last) + ch->burst[1] = (value & 0xc000) >> 14; + ch->pack[1] = (value & 0x2000) >> 13; + ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9); + ch->burst[0] = (value & 0x0180) >> 7; + ch->pack[0] = (value & 0x0040) >> 6; + ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2); + ch->data_type = (1 << (value & 3)); + if (ch->port[0] >= omap_dma_port_last) printf("%s: invalid DMA port %i\n", __FUNCTION__, - s->ch[ch].port[0]); - if (s->ch[ch].port[1] >= omap_dma_port_last) + ch->port[0]); + if (ch->port[1] >= omap_dma_port_last) printf("%s: invalid DMA port %i\n", __FUNCTION__, - s->ch[ch].port[1]); + ch->port[1]); if ((value & 3) == 3) - printf("%s: bad data_type for DMA channel %i\n", __FUNCTION__, ch); + printf("%s: bad data_type for DMA channel\n", __FUNCTION__); break; case 0x02: /* SYS_DMA_CCR_CH0 */ - s->ch[ch].mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); - s->ch[ch].mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); - s->ch[ch].end_prog = (value & 0x0800) >> 11; + ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); + ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); + ch->end_prog = (value & 0x0800) >> 11; if (s->model > omap_dma_3_1) - s->ch[ch].omap_3_1_compatible_disable = (value >> 10) & 0x1; - s->ch[ch].repeat = (value & 0x0200) >> 9; - s->ch[ch].auto_init = (value & 0x0100) >> 8; - s->ch[ch].priority = (value & 0x0040) >> 6; - s->ch[ch].fs = (value & 0x0020) >> 5; - s->ch[ch].sync = value & 0x001f; + ch->omap_3_1_compatible_disable = (value >> 10) & 0x1; + ch->repeat = (value & 0x0200) >> 9; + ch->auto_init = (value & 0x0100) >> 8; + ch->priority = (value & 0x0040) >> 6; + ch->fs = (value & 0x0020) >> 5; + ch->sync = value & 0x001f; if (value & 0x0080) omap_dma_enable_channel(s, ch); else omap_dma_disable_channel(s, ch); - if (s->ch[ch].end_prog) + if (ch->end_prog) omap_dma_channel_end_prog(s, ch); break; case 0x04: /* SYS_DMA_CICR_CH0 */ - s->ch[ch].interrupts = value; + ch->interrupts = value; break; case 0x06: /* SYS_DMA_CSR_CH0 */ - return 1; + OMAP_RO_REG((target_phys_addr_t) reg); + break; case 0x08: /* SYS_DMA_CSSA_L_CH0 */ - s->ch[ch].addr[0] &= 0xffff0000; - s->ch[ch].addr[0] |= value; + ch->addr[0] &= 0xffff0000; + ch->addr[0] |= value; break; case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ - s->ch[ch].addr[0] &= 0x0000ffff; - s->ch[ch].addr[0] |= (uint32_t) value << 16; + ch->addr[0] &= 0x0000ffff; + ch->addr[0] |= (uint32_t) value << 16; break; case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ - s->ch[ch].addr[1] &= 0xffff0000; - s->ch[ch].addr[1] |= value; + ch->addr[1] &= 0xffff0000; + ch->addr[1] |= value; break; case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ - s->ch[ch].addr[1] &= 0x0000ffff; - s->ch[ch].addr[1] |= (uint32_t) value << 16; + ch->addr[1] &= 0x0000ffff; + ch->addr[1] |= (uint32_t) value << 16; break; case 0x10: /* SYS_DMA_CEN_CH0 */ - s->ch[ch].elements = value; + ch->elements = value; break; case 0x12: /* SYS_DMA_CFN_CH0 */ - s->ch[ch].frames = value; + ch->frames = value; break; case 0x14: /* SYS_DMA_CFI_CH0 */ - s->ch[ch].frame_index[0] = (int16_t) value; + ch->frame_index[0] = (int16_t) value; break; case 0x16: /* SYS_DMA_CEI_CH0 */ - s->ch[ch].element_index[0] = (int16_t) value; + ch->element_index[0] = (int16_t) value; break; case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ @@ -1033,41 +1055,41 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, break; case 0x1c: /* DMA_CDEI */ - s->ch[ch].element_index[1] = (int16_t) value; + ch->element_index[1] = (int16_t) value; break; case 0x1e: /* DMA_CDFI */ - s->ch[ch].frame_index[1] = (int16_t) value; + ch->frame_index[1] = (int16_t) value; break; case 0x20: /* DMA_COLOR_L */ - s->ch[ch].color &= 0xffff0000; - s->ch[ch].color |= value; + ch->color &= 0xffff0000; + ch->color |= value; break; case 0x22: /* DMA_COLOR_U */ - s->ch[ch].color &= 0xffff; - s->ch[ch].color |= value << 16; + ch->color &= 0xffff; + ch->color |= value << 16; break; case 0x24: /* DMA_CCR2 */ - s->ch[ch].bs = (value >> 2) & 0x1; - s->ch[ch].transparent_copy = (value >> 1) & 0x1; - s->ch[ch].constant_fill = value & 0x1; + ch->bs = (value >> 2) & 0x1; + ch->transparent_copy = (value >> 1) & 0x1; + ch->constant_fill = value & 0x1; break; case 0x28: /* DMA_CLNK_CTRL */ - s->ch[ch].link_enabled = (value >> 15) & 0x1; + ch->link_enabled = (value >> 15) & 0x1; if (value & (1 << 14)) { /* Stop_Lnk */ - s->ch[ch].link_enabled = 0; + ch->link_enabled = 0; omap_dma_disable_channel(s, ch); } - s->ch[ch].link_next_ch = value & 0x1f; + ch->link_next_ch = value & 0x1f; break; case 0x2a: /* DMA_LCH_CTRL */ - s->ch[ch].interleave_disabled = (value >> 15) & 0x1; - s->ch[ch].type = value & 0xf; + ch->interleave_disabled = (value >> 15) & 0x1; + ch->type = value & 0xf; break; default: @@ -1076,126 +1098,126 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, return 0; } -static int omap_dma_3_2_lcd_write(struct omap_dma_s *s, int offset, +static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, uint16_t value) { switch (offset) { case 0xbc0: /* DMA_LCD_CSDP */ - s->lcd_ch.brust_f2 = (value >> 14) & 0x3; - s->lcd_ch.pack_f2 = (value >> 13) & 0x1; - s->lcd_ch.data_type_f2 = (1 << ((value >> 11) & 0x3)); - s->lcd_ch.brust_f1 = (value >> 7) & 0x3; - s->lcd_ch.pack_f1 = (value >> 6) & 0x1; - s->lcd_ch.data_type_f1 = (1 << ((value >> 0) & 0x3)); + s->brust_f2 = (value >> 14) & 0x3; + s->pack_f2 = (value >> 13) & 0x1; + s->data_type_f2 = (1 << ((value >> 11) & 0x3)); + s->brust_f1 = (value >> 7) & 0x3; + s->pack_f1 = (value >> 6) & 0x1; + s->data_type_f1 = (1 << ((value >> 0) & 0x3)); break; case 0xbc2: /* DMA_LCD_CCR */ - s->lcd_ch.mode_f2 = (value >> 14) & 0x3; - s->lcd_ch.mode_f1 = (value >> 12) & 0x3; - s->lcd_ch.end_prog = (value >> 11) & 0x1; - s->lcd_ch.omap_3_1_compatible_disable = (value >> 10) & 0x1; - s->lcd_ch.repeat = (value >> 9) & 0x1; - s->lcd_ch.auto_init = (value >> 8) & 0x1; - s->lcd_ch.running = (value >> 7) & 0x1; - s->lcd_ch.priority = (value >> 6) & 0x1; - s->lcd_ch.bs = (value >> 4) & 0x1; + s->mode_f2 = (value >> 14) & 0x3; + s->mode_f1 = (value >> 12) & 0x3; + s->end_prog = (value >> 11) & 0x1; + s->omap_3_1_compatible_disable = (value >> 10) & 0x1; + s->repeat = (value >> 9) & 0x1; + s->auto_init = (value >> 8) & 0x1; + s->running = (value >> 7) & 0x1; + s->priority = (value >> 6) & 0x1; + s->bs = (value >> 4) & 0x1; break; case 0xbc4: /* DMA_LCD_CTRL */ - s->lcd_ch.dst = (value >> 8) & 0x1; - s->lcd_ch.src = ((value >> 6) & 0x3) << 1; - s->lcd_ch.condition = 0; + s->dst = (value >> 8) & 0x1; + s->src = ((value >> 6) & 0x3) << 1; + s->condition = 0; /* Assume no bus errors and thus no BUS_ERROR irq bits. */ - s->lcd_ch.interrupts = (value >> 1) & 1; - s->lcd_ch.dual = value & 1; + s->interrupts = (value >> 1) & 1; + s->dual = value & 1; break; case 0xbc8: /* TOP_B1_L */ - s->lcd_ch.src_f1_top &= 0xffff0000; - s->lcd_ch.src_f1_top |= 0x0000ffff & value; + s->src_f1_top &= 0xffff0000; + s->src_f1_top |= 0x0000ffff & value; break; case 0xbca: /* TOP_B1_U */ - s->lcd_ch.src_f1_top &= 0x0000ffff; - s->lcd_ch.src_f1_top |= value << 16; + s->src_f1_top &= 0x0000ffff; + s->src_f1_top |= value << 16; break; case 0xbcc: /* BOT_B1_L */ - s->lcd_ch.src_f1_bottom &= 0xffff0000; - s->lcd_ch.src_f1_bottom |= 0x0000ffff & value; + s->src_f1_bottom &= 0xffff0000; + s->src_f1_bottom |= 0x0000ffff & value; break; case 0xbce: /* BOT_B1_U */ - s->lcd_ch.src_f1_bottom &= 0x0000ffff; - s->lcd_ch.src_f1_bottom |= (uint32_t) value << 16; + s->src_f1_bottom &= 0x0000ffff; + s->src_f1_bottom |= (uint32_t) value << 16; break; case 0xbd0: /* TOP_B2_L */ - s->lcd_ch.src_f2_top &= 0xffff0000; - s->lcd_ch.src_f2_top |= 0x0000ffff & value; + s->src_f2_top &= 0xffff0000; + s->src_f2_top |= 0x0000ffff & value; break; case 0xbd2: /* TOP_B2_U */ - s->lcd_ch.src_f2_top &= 0x0000ffff; - s->lcd_ch.src_f2_top |= (uint32_t) value << 16; + s->src_f2_top &= 0x0000ffff; + s->src_f2_top |= (uint32_t) value << 16; break; case 0xbd4: /* BOT_B2_L */ - s->lcd_ch.src_f2_bottom &= 0xffff0000; - s->lcd_ch.src_f2_bottom |= 0x0000ffff & value; + s->src_f2_bottom &= 0xffff0000; + s->src_f2_bottom |= 0x0000ffff & value; break; case 0xbd6: /* BOT_B2_U */ - s->lcd_ch.src_f2_bottom &= 0x0000ffff; - s->lcd_ch.src_f2_bottom |= (uint32_t) value << 16; + s->src_f2_bottom &= 0x0000ffff; + s->src_f2_bottom |= (uint32_t) value << 16; break; case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ - s->lcd_ch.element_index_f1 = value; + s->element_index_f1 = value; break; case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ - s->lcd_ch.frame_index_f1 &= 0xffff0000; - s->lcd_ch.frame_index_f1 |= 0x0000ffff & value; + s->frame_index_f1 &= 0xffff0000; + s->frame_index_f1 |= 0x0000ffff & value; break; case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ - s->lcd_ch.frame_index_f1 &= 0x0000ffff; - s->lcd_ch.frame_index_f1 |= (uint32_t) value << 16; + s->frame_index_f1 &= 0x0000ffff; + s->frame_index_f1 |= (uint32_t) value << 16; break; case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ - s->lcd_ch.element_index_f2 = value; + s->element_index_f2 = value; break; case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ - s->lcd_ch.frame_index_f2 &= 0xffff0000; - s->lcd_ch.frame_index_f2 |= 0x0000ffff & value; + s->frame_index_f2 &= 0xffff0000; + s->frame_index_f2 |= 0x0000ffff & value; break; case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ - s->lcd_ch.frame_index_f2 &= 0x0000ffff; - s->lcd_ch.frame_index_f2 |= (uint32_t) value << 16; + s->frame_index_f2 &= 0x0000ffff; + s->frame_index_f2 |= (uint32_t) value << 16; break; case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ - s->lcd_ch.elements_f1 = value; + s->elements_f1 = value; break; case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ - s->lcd_ch.frames_f1 = value; + s->frames_f1 = value; break; case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ - s->lcd_ch.elements_f2 = value; + s->elements_f2 = value; break; case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ - s->lcd_ch.frames_f2 = value; + s->frames_f2 = value; break; case 0xbea: /* DMA_LCD_LCH_CTRL */ - s->lcd_ch.lch_type = value & 0xf; + s->lch_type = value & 0xf; break; default: @@ -1204,114 +1226,114 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_s *s, int offset, return 0; } -static int omap_dma_3_2_lcd_read(struct omap_dma_s *s, int offset, +static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, uint16_t *ret) { switch (offset) { case 0xbc0: /* DMA_LCD_CSDP */ - *ret = (s->lcd_ch.brust_f2 << 14) | - (s->lcd_ch.pack_f2 << 13) | - ((s->lcd_ch.data_type_f2 >> 1) << 11) | - (s->lcd_ch.brust_f1 << 7) | - (s->lcd_ch.pack_f1 << 6) | - ((s->lcd_ch.data_type_f1 >> 1) << 0); + *ret = (s->brust_f2 << 14) | + (s->pack_f2 << 13) | + ((s->data_type_f2 >> 1) << 11) | + (s->brust_f1 << 7) | + (s->pack_f1 << 6) | + ((s->data_type_f1 >> 1) << 0); break; case 0xbc2: /* DMA_LCD_CCR */ - *ret = (s->lcd_ch.mode_f2 << 14) | - (s->lcd_ch.mode_f1 << 12) | - (s->lcd_ch.end_prog << 11) | - (s->lcd_ch.omap_3_1_compatible_disable << 10) | - (s->lcd_ch.repeat << 9) | - (s->lcd_ch.auto_init << 8) | - (s->lcd_ch.running << 7) | - (s->lcd_ch.priority << 6) | - (s->lcd_ch.bs << 4); + *ret = (s->mode_f2 << 14) | + (s->mode_f1 << 12) | + (s->end_prog << 11) | + (s->omap_3_1_compatible_disable << 10) | + (s->repeat << 9) | + (s->auto_init << 8) | + (s->running << 7) | + (s->priority << 6) | + (s->bs << 4); break; case 0xbc4: /* DMA_LCD_CTRL */ - qemu_irq_lower(s->lcd_ch.irq); - *ret = (s->lcd_ch.dst << 8) | - ((s->lcd_ch.src & 0x6) << 5) | - (s->lcd_ch.condition << 3) | - (s->lcd_ch.interrupts << 1) | - s->lcd_ch.dual; + qemu_irq_lower(s->irq); + *ret = (s->dst << 8) | + ((s->src & 0x6) << 5) | + (s->condition << 3) | + (s->interrupts << 1) | + s->dual; break; case 0xbc8: /* TOP_B1_L */ - *ret = s->lcd_ch.src_f1_top & 0xffff; + *ret = s->src_f1_top & 0xffff; break; case 0xbca: /* TOP_B1_U */ - *ret = s->lcd_ch.src_f1_top >> 16; + *ret = s->src_f1_top >> 16; break; case 0xbcc: /* BOT_B1_L */ - *ret = s->lcd_ch.src_f1_bottom & 0xffff; + *ret = s->src_f1_bottom & 0xffff; break; case 0xbce: /* BOT_B1_U */ - *ret = s->lcd_ch.src_f1_bottom >> 16; + *ret = s->src_f1_bottom >> 16; break; case 0xbd0: /* TOP_B2_L */ - *ret = s->lcd_ch.src_f2_top & 0xffff; + *ret = s->src_f2_top & 0xffff; break; case 0xbd2: /* TOP_B2_U */ - *ret = s->lcd_ch.src_f2_top >> 16; + *ret = s->src_f2_top >> 16; break; case 0xbd4: /* BOT_B2_L */ - *ret = s->lcd_ch.src_f2_bottom & 0xffff; + *ret = s->src_f2_bottom & 0xffff; break; case 0xbd6: /* BOT_B2_U */ - *ret = s->lcd_ch.src_f2_bottom >> 16; + *ret = s->src_f2_bottom >> 16; break; case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ - *ret = s->lcd_ch.element_index_f1; + *ret = s->element_index_f1; break; case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ - *ret = s->lcd_ch.frame_index_f1 & 0xffff; + *ret = s->frame_index_f1 & 0xffff; break; case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ - *ret = s->lcd_ch.frame_index_f1 >> 16; + *ret = s->frame_index_f1 >> 16; break; case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ - *ret = s->lcd_ch.element_index_f2; + *ret = s->element_index_f2; break; case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ - *ret = s->lcd_ch.frame_index_f2 & 0xffff; + *ret = s->frame_index_f2 & 0xffff; break; case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ - *ret = s->lcd_ch.frame_index_f2 >> 16; + *ret = s->frame_index_f2 >> 16; break; case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ - *ret = s->lcd_ch.elements_f1; + *ret = s->elements_f1; break; case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ - *ret = s->lcd_ch.frames_f1; + *ret = s->frames_f1; break; case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ - *ret = s->lcd_ch.elements_f2; + *ret = s->elements_f2; break; case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ - *ret = s->lcd_ch.frames_f2; + *ret = s->frames_f2; break; case 0xbea: /* DMA_LCD_LCH_CTRL */ - *ret = s->lcd_ch.lch_type; + *ret = s->lch_type; break; default: @@ -1320,56 +1342,56 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_s *s, int offset, return 0; } -static int omap_dma_3_1_lcd_write(struct omap_dma_s *s, int offset, +static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, uint16_t value) { switch (offset) { case 0x300: /* SYS_DMA_LCD_CTRL */ - s->lcd_ch.src = (value & 0x40) ? imif : emiff; - s->lcd_ch.condition = 0; + s->src = (value & 0x40) ? imif : emiff; + s->condition = 0; /* Assume no bus errors and thus no BUS_ERROR irq bits. */ - s->lcd_ch.interrupts = (value >> 1) & 1; - s->lcd_ch.dual = value & 1; + s->interrupts = (value >> 1) & 1; + s->dual = value & 1; break; case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ - s->lcd_ch.src_f1_top &= 0xffff0000; - s->lcd_ch.src_f1_top |= 0x0000ffff & value; + s->src_f1_top &= 0xffff0000; + s->src_f1_top |= 0x0000ffff & value; break; case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ - s->lcd_ch.src_f1_top &= 0x0000ffff; - s->lcd_ch.src_f1_top |= value << 16; + s->src_f1_top &= 0x0000ffff; + s->src_f1_top |= value << 16; break; case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ - s->lcd_ch.src_f1_bottom &= 0xffff0000; - s->lcd_ch.src_f1_bottom |= 0x0000ffff & value; + s->src_f1_bottom &= 0xffff0000; + s->src_f1_bottom |= 0x0000ffff & value; break; case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ - s->lcd_ch.src_f1_bottom &= 0x0000ffff; - s->lcd_ch.src_f1_bottom |= value << 16; + s->src_f1_bottom &= 0x0000ffff; + s->src_f1_bottom |= value << 16; break; case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ - s->lcd_ch.src_f2_top &= 0xffff0000; - s->lcd_ch.src_f2_top |= 0x0000ffff & value; + s->src_f2_top &= 0xffff0000; + s->src_f2_top |= 0x0000ffff & value; break; case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ - s->lcd_ch.src_f2_top &= 0x0000ffff; - s->lcd_ch.src_f2_top |= value << 16; + s->src_f2_top &= 0x0000ffff; + s->src_f2_top |= value << 16; break; case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ - s->lcd_ch.src_f2_bottom &= 0xffff0000; - s->lcd_ch.src_f2_bottom |= 0x0000ffff & value; + s->src_f2_bottom &= 0xffff0000; + s->src_f2_bottom |= 0x0000ffff & value; break; case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ - s->lcd_ch.src_f2_bottom &= 0x0000ffff; - s->lcd_ch.src_f2_bottom |= value << 16; + s->src_f2_bottom &= 0x0000ffff; + s->src_f2_bottom |= value << 16; break; default: @@ -1378,50 +1400,50 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_s *s, int offset, return 0; } -static int omap_dma_3_1_lcd_read(struct omap_dma_s *s, int offset, +static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, uint16_t *ret) { int i; switch (offset) { case 0x300: /* SYS_DMA_LCD_CTRL */ - i = s->lcd_ch.condition; - s->lcd_ch.condition = 0; - qemu_irq_lower(s->lcd_ch.irq); - *ret = ((s->lcd_ch.src == imif) << 6) | (i << 3) | - (s->lcd_ch.interrupts << 1) | s->lcd_ch.dual; + i = s->condition; + s->condition = 0; + qemu_irq_lower(s->irq); + *ret = ((s->src == imif) << 6) | (i << 3) | + (s->interrupts << 1) | s->dual; break; case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ - *ret = s->lcd_ch.src_f1_top & 0xffff; + *ret = s->src_f1_top & 0xffff; break; case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ - *ret = s->lcd_ch.src_f1_top >> 16; + *ret = s->src_f1_top >> 16; break; case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ - *ret = s->lcd_ch.src_f1_bottom & 0xffff; + *ret = s->src_f1_bottom & 0xffff; break; case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ - *ret = s->lcd_ch.src_f1_bottom >> 16; + *ret = s->src_f1_bottom >> 16; break; case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ - *ret = s->lcd_ch.src_f2_top & 0xffff; + *ret = s->src_f2_top & 0xffff; break; case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ - *ret = s->lcd_ch.src_f2_top >> 16; + *ret = s->src_f2_top >> 16; break; case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ - *ret = s->lcd_ch.src_f2_bottom & 0xffff; + *ret = s->src_f2_bottom & 0xffff; break; case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ - *ret = s->lcd_ch.src_f2_bottom >> 16; + *ret = s->src_f2_bottom >> 16; break; default: @@ -1549,7 +1571,7 @@ static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) switch (offset) { case 0x300 ... 0x3fe: if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { - if (omap_dma_3_1_lcd_read(s, offset, &ret)) + if (omap_dma_3_1_lcd_read(&s->lcd_ch, offset, &ret)) break; return ret; } @@ -1557,7 +1579,7 @@ static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) case 0x000 ... 0x2fe: reg = offset & 0x3f; ch = (offset >> 6) & 0x0f; - if (omap_dma_ch_reg_read(s, ch, reg, &ret)) + if (omap_dma_ch_reg_read(s, &s->ch[ch], reg, &ret)) break; return ret; @@ -1572,7 +1594,7 @@ static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr) case 0xb00 ... 0xbfe: if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) { - if (omap_dma_3_2_lcd_read(s, offset, &ret)) + if (omap_dma_3_2_lcd_read(&s->lcd_ch, offset, &ret)) break; return ret; } @@ -1592,7 +1614,7 @@ static void omap_dma_write(void *opaque, target_phys_addr_t addr, switch (offset) { case 0x300 ... 0x3fe: if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) { - if (omap_dma_3_1_lcd_write(s, offset, value)) + if (omap_dma_3_1_lcd_write(&s->lcd_ch, offset, value)) break; return; } @@ -1600,7 +1622,7 @@ static void omap_dma_write(void *opaque, target_phys_addr_t addr, case 0x000 ... 0x2fe: reg = offset & 0x3f; ch = (offset >> 6) & 0x0f; - if (omap_dma_ch_reg_write(s, ch, reg, value)) + if (omap_dma_ch_reg_write(s, &s->ch[ch], reg, value)) break; return; @@ -1615,7 +1637,7 @@ static void omap_dma_write(void *opaque, target_phys_addr_t addr, case 0xb00 ... 0xbfe: if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) { - if (omap_dma_3_2_lcd_write(s, offset, value)) + if (omap_dma_3_2_lcd_write(&s->lcd_ch, offset, value)) break; return; } @@ -1669,7 +1691,7 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, enum omap_dma_model model) { - int iomemtype, num_irqs, memsize; + int iomemtype, num_irqs, memsize, i; struct omap_dma_s *s = (struct omap_dma_s *) qemu_mallocz(sizeof(struct omap_dma_s)); @@ -1680,13 +1702,18 @@ struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, num_irqs = 16; memsize = 0xc00; } - memcpy(s->irqs, irqs, num_irqs * sizeof(qemu_irq)); s->base = base; s->model = model; s->mpu = mpu; s->clk = clk; s->lcd_ch.irq = lcd_irq; s->lcd_ch.mpu = mpu; + while (num_irqs --) + s->ch[num_irqs].irq = irqs[num_irqs]; + for (i = 0; i < 3; i ++) { + s->ch[i].sibling = &s->ch[i + 6]; + s->ch[i + 6].sibling = &s->ch[i]; + } s->tm = qemu_new_timer(vm_clock, (QEMUTimerCB *) omap_dma_channel_run, s); omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]); mpu->drq = qemu_allocate_irqs(omap_dma_request, s, 32); -- cgit v1.2.3 From 8543243c29a60f102d7a3d98027b46bc8cdac421 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 9 Dec 2007 23:29:34 +0000 Subject: No write-protect detect diode on Mainstone II. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3790 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mainstone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mainstone.c b/hw/mainstone.c index cf05675d0..8793b336e 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -78,7 +78,7 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0); /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, mst_irq[MMC_IRQ], mst_irq[MMC_IRQ]); + pxa2xx_mmci_handlers(cpu->mmc, NULL, mst_irq[MMC_IRQ]); smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); -- cgit v1.2.3 From df01e0fc33af5b1247d8ac4bfec5b94466ff69c2 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 9 Dec 2007 23:35:27 +0000 Subject: Add rdpmc SVM intercept, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3791 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/exec.h | 1 + target-i386/helper.c | 12 ++++++++++++ target-i386/op.c | 5 +++++ target-i386/translate.c | 4 ++++ 4 files changed, 22 insertions(+) diff --git a/target-i386/exec.h b/target-i386/exec.h index 70fac64fc..20153f727 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -199,6 +199,7 @@ void helper_sysexit(void); void helper_syscall(int next_eip_addend); void helper_sysret(int dflag); void helper_rdtsc(void); +void helper_rdpmc(void); void helper_rdmsr(void); void helper_wrmsr(void); void helper_lsl(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index a2f465c73..07ff3563c 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2743,6 +2743,18 @@ void helper_rdtsc(void) EDX = (uint32_t)(val >> 32); } +void helper_rdpmc(void) +{ + if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) { + raise_exception(EXCP0D_GPF); + } + + if (!svm_check_intercept_param(SVM_EXIT_RDPMC, 0)) { + /* currently unimplemented */ + raise_exception_err(EXCP06_ILLOP, 0); + } +} + #if defined(CONFIG_USER_ONLY) void helper_wrmsr(void) { diff --git a/target-i386/op.c b/target-i386/op.c index 7d8950e07..77930db12 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -953,6 +953,11 @@ void OPPROTO op_rdtsc(void) helper_rdtsc(); } +void OPPROTO op_rdpmc(void) +{ + helper_rdpmc(); +} + void OPPROTO op_cpuid(void) { helper_cpuid(); diff --git a/target-i386/translate.c b/target-i386/translate.c index 02dc6cf61..579831ef7 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -5658,6 +5658,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_jmp_im(pc_start - s->cs_base); gen_op_rdtsc(); break; + case 0x133: /* rdpmc */ + gen_jmp_im(pc_start - s->cs_base); + gen_op_rdpmc(); + break; case 0x134: /* sysenter */ if (CODE64(s)) goto illegal_op; -- cgit v1.2.3 From b26177d7ec3f50157a5f37f804ffcace3b2a3945 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 9 Dec 2007 23:39:22 +0000 Subject: Make SVM IOIO intercept check all needed bits, by Bernhard Kauer. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3792 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-i386/helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 07ff3563c..bad3f7c1b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -4262,7 +4262,8 @@ int svm_check_intercept_param(uint32_t type, uint64_t param) uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); uint16_t port = (uint16_t) (param >> 16); - if(ldub_phys(addr + port / 8) & (1 << (port % 8))) + uint16_t mask = (1 << ((param >> 4) & 7)) - 1; + if(lduw_phys(addr + port / 8) & (mask << (port & 7))) vmexit(type, param); } break; -- cgit v1.2.3 From 52fc1d83bc50b0b6fc6861cfecc5763edbad7e60 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 9 Dec 2007 23:56:13 +0000 Subject: Save/load PCI-device, PCI-bus and PIIX3 irq-related state (patches by Uri Lublin. Note that other PCI bridges are not fixed here. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3793 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pci.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- hw/piix_pci.c | 19 ++++++++++++++----- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 0b5e7bf34..f8cbf1a32 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -42,6 +42,7 @@ struct PCIBus { PCIBus *next; /* The bus IRQ state is the logical OR of the connected devices. Keep a count of the number of devices with raised IRQs. */ + int nirq; int irq_count[]; }; @@ -52,16 +53,51 @@ target_phys_addr_t pci_mem_base; static int pci_irq_index; static PCIBus *first_bus; +static void pcibus_save(QEMUFile *f, void *opaque) +{ + PCIBus *bus = (PCIBus *)opaque; + int i; + + qemu_put_be32(f, bus->nirq); + for (i = 0; i < bus->nirq; i++) + qemu_put_be32(f, bus->irq_count[i]); +} + +static int pcibus_load(QEMUFile *f, void *opaque, int version_id) +{ + PCIBus *bus = (PCIBus *)opaque; + int i, nirq; + + if (version_id != 1) + return -EINVAL; + + nirq = qemu_get_be32(f); + if (bus->nirq != nirq) { + fprintf(stderr, "pcibus_load: nirq mismatch: src=%d dst=%d\n", + nirq, bus->nirq); + return -EINVAL; + } + + for (i = 0; i < nirq; i++) + bus->irq_count[i] = qemu_get_be32(f); + + return 0; +} + PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, qemu_irq *pic, int devfn_min, int nirq) { PCIBus *bus; + static int nbus = 0; + bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int))); bus->set_irq = set_irq; bus->map_irq = map_irq; bus->irq_opaque = pic; bus->devfn_min = devfn_min; + bus->nirq = nirq; first_bus = bus; + register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus); return bus; } @@ -83,18 +119,29 @@ int pci_bus_num(PCIBus *s) void pci_device_save(PCIDevice *s, QEMUFile *f) { - qemu_put_be32(f, 1); /* PCI device version */ + int i; + + qemu_put_be32(f, 2); /* PCI device version */ qemu_put_buffer(f, s->config, 256); + for (i = 0; i < 4; i++) + qemu_put_be32(f, s->irq_state[i]); } int pci_device_load(PCIDevice *s, QEMUFile *f) { uint32_t version_id; + int i; + version_id = qemu_get_be32(f); - if (version_id != 1) + if (version_id > 2) return -EINVAL; qemu_get_buffer(f, s->config, 256); pci_update_mappings(s); + + if (version_id >= 2) + for (i = 0; i < 4; i ++) + s->irq_state[i] = qemu_get_be32(f); + return 0; } diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 066817be6..d5c7e1e5c 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -57,6 +57,7 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) static uint32_t isa_page_descs[384 / 4]; static uint8_t smm_enabled; +static int pci_irq_levels[4]; static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r) { @@ -139,22 +140,32 @@ static void i440fx_write_config(PCIDevice *d, static void i440fx_save(QEMUFile* f, void *opaque) { PCIDevice *d = opaque; + int i; + pci_device_save(d, f); qemu_put_8s(f, &smm_enabled); + + for (i = 0; i < 4; i++) + qemu_put_be32(f, pci_irq_levels[i]); } static int i440fx_load(QEMUFile* f, void *opaque, int version_id) { PCIDevice *d = opaque; - int ret; + int ret, i; - if (version_id != 1) + if (version_id > 2) return -EINVAL; ret = pci_device_load(d, f); if (ret < 0) return ret; i440fx_update_memory_mappings(d); qemu_get_8s(f, &smm_enabled); + + if (version_id >= 2) + for (i = 0; i < 4; i++) + pci_irq_levels[i] = qemu_get_be32(f); + return 0; } @@ -192,7 +203,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) d->config[0x72] = 0x02; /* SMRAM */ - register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d); + register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d); *pi440fx_state = d; return b; } @@ -205,8 +216,6 @@ PCIDevice *piix4_dev; /* just used for simpler irq handling. */ #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) -static int pci_irq_levels[4]; - static void piix3_set_irq(qemu_irq *pic, int irq_num, int level) { int i, pic_irq, pic_level; -- cgit v1.2.3 From 88eeee0a31c696b26f8df3dfe2221b955f8d878e Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 10 Dec 2007 00:28:27 +0000 Subject: Desambiguate pflash_register(). pflash_t is still ambiguous... perhaps both emulations should sit in a single file. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3794 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/flash.h | 19 +++++++++++++------ hw/gumstix.c | 4 ++-- hw/mainstone.c | 6 ++++-- hw/pflash_cfi01.c | 10 +++++----- hw/pflash_cfi02.c | 10 +++++----- hw/ppc405_boards.c | 18 +++++++++--------- 6 files changed, 38 insertions(+), 29 deletions(-) diff --git a/hw/flash.h b/hw/flash.h index e3c898a34..95ac62862 100644 --- a/hw/flash.h +++ b/hw/flash.h @@ -1,11 +1,19 @@ /* NOR flash devices */ typedef struct pflash_t pflash_t; -pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, - BlockDriverState *bs, - uint32_t sector_len, int nb_blocs, int width, - uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3); +/* pflash_cfi01.c */ +pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off, + BlockDriverState *bs, + uint32_t sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3); + +/* pflash_cfi02.c */ +pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, + BlockDriverState *bs, + uint32_t sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3); /* nand.c */ struct nand_flash_s; @@ -37,4 +45,3 @@ uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample); void ecc_reset(struct ecc_state_s *s); void ecc_put(QEMUFile *f, struct ecc_state_s *s); void ecc_get(QEMUFile *f, struct ecc_state_s *s); - diff --git a/hw/gumstix.c b/hw/gumstix.c index 21325177c..2cf52f9c0 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -67,7 +67,7 @@ static void connex_init(int ram_size, int vga_ram_size, exit(1); } - if (!pflash_register(0x00000000, qemu_ram_alloc(connex_rom), + if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(connex_rom), drives_table[index].bdrv, sector_len, connex_rom / sector_len, 2, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); @@ -107,7 +107,7 @@ static void verdex_init(int ram_size, int vga_ram_size, exit(1); } - if (!pflash_register(0x00000000, qemu_ram_alloc(verdex_rom), + if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(verdex_rom), drives_table[index].bdrv, sector_len, verdex_rom / sector_len, 2, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); diff --git a/hw/mainstone.c b/hw/mainstone.c index 8793b336e..558deed03 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -55,7 +55,8 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, "'pflash' parameter\n"); exit(1); } - if (!pflash_register(MST_FLASH_0, mainstone_ram + PXA2XX_INTERNAL_SIZE, + if (!pflash_cfi01_register(MST_FLASH_0, + mainstone_ram + PXA2XX_INTERNAL_SIZE, drives_table[index].bdrv, 256 * 1024, 128, 4, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); @@ -68,7 +69,8 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, "'pflash' parameter\n"); exit(1); } - if (!pflash_register(MST_FLASH_1, mainstone_ram + PXA2XX_INTERNAL_SIZE, + if (!pflash_cfi01_register(MST_FLASH_1, + mainstone_ram + PXA2XX_INTERNAL_SIZE, drives_table[index].bdrv, 256 * 1024, 128, 4, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory.\n"); diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index f50d7bae7..745f5e57c 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -483,11 +483,11 @@ static int ctz32 (uint32_t n) return ret; } -pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, - BlockDriverState *bs, - target_ulong sector_len, int nb_blocs, int width, - uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3) +pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off, + BlockDriverState *bs, target_ulong sector_len, + int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3) { pflash_t *pfl; target_long total_len; diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index eaf6750bb..d5b3f3279 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -524,11 +524,11 @@ static int ctz32 (uint32_t n) return ret; } -pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off, - BlockDriverState *bs, - uint32_t sector_len, int nb_blocs, int width, - uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3) +pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, + BlockDriverState *bs, target_ulong sector_len, + int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3) { pflash_t *pfl; int32_t total_len; diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 597f9b58a..b96a18849 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -234,9 +234,9 @@ static void ref405ep_init (int ram_size, int vga_ram_size, fl_idx, bios_size, bios_offset, -bios_size, bdrv_get_device_name(drives_table[index].bdrv), fl_sectors); #endif - pflash_register((uint32_t)(-bios_size), bios_offset, - drives_table[index].bdrv, 65536, fl_sectors, 2, - 0x0001, 0x22DA, 0x0000, 0x0000); + pflash_cfi02_register((uint32_t)(-bios_size), bios_offset, + drives_table[index].bdrv, 65536, fl_sectors, 2, + 0x0001, 0x22DA, 0x0000, 0x0000); fl_idx++; } else #endif @@ -551,9 +551,9 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, fl_idx, bios_size, bios_offset, -bios_size, bdrv_get_device_name(drives_table[index].bdrv), fl_sectors); #endif - pflash_register((uint32_t)(-bios_size), bios_offset, - drives_table[index].bdrv, 65536, fl_sectors, 4, - 0x0001, 0x22DA, 0x0000, 0x0000); + pflash_cfi02_register((uint32_t)(-bios_size), bios_offset, + drives_table[index].bdrv, 65536, fl_sectors, 4, + 0x0001, 0x22DA, 0x0000, 0x0000); fl_idx++; } else #endif @@ -587,9 +587,9 @@ static void taihu_405ep_init(int ram_size, int vga_ram_size, fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000, bdrv_get_device_name(drives_table[index].bdrv)); #endif - pflash_register(0xfc000000, bios_offset, drives_table[index].bdrv, - 65536, fl_sectors, 4, - 0x0001, 0x22DA, 0x0000, 0x0000); + pflash_cfi02_register(0xfc000000, bios_offset, + drives_table[index].bdrv, 65536, fl_sectors, 4, + 0x0001, 0x22DA, 0x0000, 0x0000); fl_idx++; } /* Register CLPD & LCD display */ -- cgit v1.2.3 From 2e8c191795768429b7f621b17b0194f2298668c0 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 10 Dec 2007 00:33:13 +0000 Subject: Fix incompatible declaration in previous commit. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3795 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/flash.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/flash.h b/hw/flash.h index 95ac62862..d07f6a19e 100644 --- a/hw/flash.h +++ b/hw/flash.h @@ -10,8 +10,8 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off, /* pflash_cfi02.c */ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, - BlockDriverState *bs, - uint32_t sector_len, int nb_blocs, int width, + BlockDriverState *bs, target_ulong sector_len, + int nb_blocs, int width, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); -- cgit v1.2.3 From cf6d911814c0278c1dae48b78359ee90215a13e6 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 10 Dec 2007 01:07:47 +0000 Subject: Fix OMAP1 MPUI/O keyboard interrupt masking. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3796 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/flash.h | 2 +- hw/omap.c | 6 +++--- hw/pflash_cfi02.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/flash.h b/hw/flash.h index d07f6a19e..42d25fe4d 100644 --- a/hw/flash.h +++ b/hw/flash.h @@ -10,7 +10,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off, /* pflash_cfi02.c */ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, - BlockDriverState *bs, target_ulong sector_len, + BlockDriverState *bs, uint32_t sector_len, int nb_blocs, int width, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3); diff --git a/hw/omap.c b/hw/omap.c index db15acc36..ce63597f1 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -3576,8 +3576,8 @@ static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) if (*row & cols) rows |= i; - qemu_set_irq(s->kbd_irq, rows && ~s->kbd_mask && s->clk); - s->row_latch = rows ^ 0x1f; + qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk); + s->row_latch = ~rows; } static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) @@ -3609,7 +3609,7 @@ static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr) return s->edge; case 0x20: /* KBD_INT */ - return (s->row_latch != 0x1f) && !s->kbd_mask; + return (~s->row_latch & 0x1f) && !s->kbd_mask; case 0x24: /* GPIO_INT */ ret = s->ints; diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index d5b3f3279..bc90d248d 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -525,7 +525,7 @@ static int ctz32 (uint32_t n) } pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, - BlockDriverState *bs, target_ulong sector_len, + BlockDriverState *bs, uint32_t sector_len, int nb_blocs, int width, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3) -- cgit v1.2.3 From 8ccc2ace5628720347017c98a43b47b2ba23cf15 Mon Sep 17 00:00:00 2001 From: ths Date: Mon, 10 Dec 2007 02:58:34 +0000 Subject: SCSI cleanup, by Laurent Vivier. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3797 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/esp.c | 16 +++++++-------- hw/lsi53c895a.c | 41 +++++++++++++++++++++++++------------- hw/scsi-disk.c | 62 +++++++++++++++++++++++++++++++++++---------------------- hw/scsi-disk.h | 27 +++++++++++++------------ hw/usb-msd.c | 16 +++++++-------- 5 files changed, 95 insertions(+), 67 deletions(-) diff --git a/hw/esp.c b/hw/esp.c index d6af3f61f..df7a5e166 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -165,7 +165,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) if (s->current_dev) { /* Started a new command before the old one finished. Cancel it. */ - scsi_cancel_io(s->current_dev, 0); + s->current_dev->cancel_io(s->current_dev, 0); s->async_len = 0; } @@ -188,7 +188,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) DPRINTF("do_cmd: busid 0x%x\n", buf[0]); lun = buf[0] & 7; - datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); + datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun); s->ti_size = datalen; if (datalen != 0) { s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC; @@ -196,10 +196,10 @@ static void do_cmd(ESPState *s, uint8_t *buf) s->dma_counter = 0; if (datalen > 0) { s->rregs[ESP_RSTAT] |= STAT_DI; - scsi_read_data(s->current_dev, 0); + s->current_dev->read_data(s->current_dev, 0); } else { s->rregs[ESP_RSTAT] |= STAT_DO; - scsi_write_data(s->current_dev, 0); + s->current_dev->write_data(s->current_dev, 0); } } s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; @@ -298,9 +298,9 @@ static void esp_do_dma(ESPState *s) if (s->async_len == 0) { if (to_device) { // ti_size is negative - scsi_write_data(s->current_dev, 0); + s->current_dev->write_data(s->current_dev, 0); } else { - scsi_read_data(s->current_dev, 0); + s->current_dev->read_data(s->current_dev, 0); /* If there is still data to be read from the device then complete the DMA operation immeriately. Otherwise defer until the scsi layer has completed. */ @@ -335,7 +335,7 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag, } else { DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); s->async_len = arg; - s->async_buf = scsi_get_buf(s->current_dev, 0); + s->async_buf = s->current_dev->get_buf(s->current_dev, 0); if (s->dma_left) { esp_do_dma(s); } else if (s->dma_counter != 0 && s->ti_size <= 0) { @@ -611,7 +611,7 @@ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id) } if (s->scsi_dev[id]) { DPRINTF("Destroying device %d\n", id); - scsi_disk_destroy(s->scsi_dev[id]); + s->scsi_dev[id]->destroy(s->scsi_dev[id]); } DPRINTF("Attaching block device %d\n", id); /* Command queueing is not implemented. */ diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index dbf67cb0c..3a4ddf7f6 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -187,6 +187,7 @@ typedef struct { /* The tag is a combination of the device ID and the SCSI tag. */ uint32_t current_tag; uint32_t current_dma_len; + int command_complete; uint8_t *dma_buf; lsi_queue *queue; int queue_len; @@ -465,7 +466,8 @@ static void lsi_do_dma(LSIState *s, int out) s->dbc -= count; if (s->dma_buf == NULL) { - s->dma_buf = scsi_get_buf(s->current_dev, s->current_tag); + s->dma_buf = s->current_dev->get_buf(s->current_dev, + s->current_tag); } /* ??? Set SFBR to first data byte. */ @@ -479,10 +481,10 @@ static void lsi_do_dma(LSIState *s, int out) s->dma_buf = NULL; if (out) { /* Write the data. */ - scsi_write_data(s->current_dev, s->current_tag); + s->current_dev->write_data(s->current_dev, s->current_tag); } else { /* Request any remaining data. */ - scsi_read_data(s->current_dev, s->current_tag); + s->current_dev->read_data(s->current_dev, s->current_tag); } } else { s->dma_buf += count; @@ -596,6 +598,7 @@ static void lsi_command_complete(void *opaque, int reason, uint32_t tag, if (reason == SCSI_REASON_DONE) { DPRINTF("Command complete sense=%d\n", (int)arg); s->sense = arg; + s->command_complete = 2; if (s->waiting && s->dbc != 0) { /* Raise phase mismatch for short transfers. */ lsi_bad_phase(s, out, PHASE_ST); @@ -612,6 +615,7 @@ static void lsi_command_complete(void *opaque, int reason, uint32_t tag, } DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); s->current_dma_len = arg; + s->command_complete = 1; if (!s->waiting) return; if (s->waiting == 1 || s->dbc == 0) { @@ -631,21 +635,30 @@ static void lsi_do_command(LSIState *s) s->dbc = 16; cpu_physical_memory_read(s->dnad, buf, s->dbc); s->sfbr = buf[0]; - n = scsi_send_command(s->current_dev, s->current_tag, buf, s->current_lun); + s->command_complete = 0; + n = s->current_dev->send_command(s->current_dev, s->current_tag, buf, + s->current_lun); if (n > 0) { lsi_set_phase(s, PHASE_DI); - scsi_read_data(s->current_dev, s->current_tag); + s->current_dev->read_data(s->current_dev, s->current_tag); } else if (n < 0) { lsi_set_phase(s, PHASE_DO); - scsi_write_data(s->current_dev, s->current_tag); + s->current_dev->write_data(s->current_dev, s->current_tag); } - if (n && s->current_dma_len == 0) { - /* Command did not complete immediately so disconnect. */ - lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */ - lsi_add_msg_byte(s, 4); /* DISCONNECT */ - lsi_set_phase(s, PHASE_MI); - s->msg_action = 1; - lsi_queue_command(s); + + if (!s->command_complete) { + if (n) { + /* Command did not complete immediately so disconnect. */ + lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */ + lsi_add_msg_byte(s, 4); /* DISCONNECT */ + /* wait data */ + lsi_set_phase(s, PHASE_MI); + s->msg_action = 1; + lsi_queue_command(s); + } else { + /* wait command complete */ + lsi_set_phase(s, PHASE_DI); + } } } @@ -1822,7 +1835,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id) } if (s->scsi_dev[id]) { DPRINTF("Destroying device %d\n", id); - scsi_disk_destroy(s->scsi_dev[id]); + s->scsi_dev[id]->destroy(s->scsi_dev[id]); } DPRINTF("Attaching block device %d\n", id); s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 700b91446..d281b8cbb 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -37,7 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) #define SCSI_DMA_BUF_SIZE 65536 typedef struct SCSIRequest { - SCSIDevice *dev; + SCSIDeviceState *dev; uint32_t tag; /* ??? We should probably keep track of whether the data trasfer is a read or a write. Currently we rely on the host getting it right. */ @@ -51,7 +51,7 @@ typedef struct SCSIRequest { struct SCSIRequest *next; } SCSIRequest; -struct SCSIDevice +struct SCSIDeviceState { BlockDriverState *bdrv; SCSIRequest *requests; @@ -69,7 +69,7 @@ struct SCSIDevice /* Global pool of SCSIRequest structures. */ static SCSIRequest *free_requests = NULL; -static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag) +static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) { SCSIRequest *r; @@ -93,7 +93,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag) static void scsi_remove_request(SCSIRequest *r) { SCSIRequest *last; - SCSIDevice *s = r->dev; + SCSIDeviceState *s = r->dev; if (s->requests == r) { s->requests = r->next; @@ -111,7 +111,7 @@ static void scsi_remove_request(SCSIRequest *r) free_requests = r; } -static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag) +static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag) { SCSIRequest *r; @@ -125,7 +125,7 @@ static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag) /* Helper function for command completion. */ static void scsi_command_complete(SCSIRequest *r, int sense) { - SCSIDevice *s = r->dev; + SCSIDeviceState *s = r->dev; uint32_t tag; DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense); s->sense = sense; @@ -135,8 +135,9 @@ static void scsi_command_complete(SCSIRequest *r, int sense) } /* Cancel a pending data transfer. */ -void scsi_cancel_io(SCSIDevice *s, uint32_t tag) +static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) { + SCSIDeviceState *s = d->state; SCSIRequest *r; DPRINTF("Cancel tag=0x%x\n", tag); r = scsi_find_request(s, tag); @@ -151,7 +152,7 @@ void scsi_cancel_io(SCSIDevice *s, uint32_t tag) static void scsi_read_complete(void * opaque, int ret) { SCSIRequest *r = (SCSIRequest *)opaque; - SCSIDevice *s = r->dev; + SCSIDeviceState *s = r->dev; if (ret) { DPRINTF("IO error\n"); @@ -164,8 +165,9 @@ static void scsi_read_complete(void * opaque, int ret) } /* Read more data from scsi device into buffer. */ -void scsi_read_data(SCSIDevice *s, uint32_t tag) +static void scsi_read_data(SCSIDevice *d, uint32_t tag) { + SCSIDeviceState *s = d->state; SCSIRequest *r; uint32_t n; @@ -204,7 +206,7 @@ void scsi_read_data(SCSIDevice *s, uint32_t tag) static void scsi_write_complete(void * opaque, int ret) { SCSIRequest *r = (SCSIRequest *)opaque; - SCSIDevice *s = r->dev; + SCSIDeviceState *s = r->dev; uint32_t len; if (ret) { @@ -228,8 +230,9 @@ static void scsi_write_complete(void * opaque, int ret) /* Write data to a scsi device. Returns nonzero on failure. The transfer may complete asynchronously. */ -int scsi_write_data(SCSIDevice *s, uint32_t tag) +static int scsi_write_data(SCSIDevice *d, uint32_t tag) { + SCSIDeviceState *s = d->state; SCSIRequest *r; uint32_t n; @@ -259,8 +262,9 @@ int scsi_write_data(SCSIDevice *s, uint32_t tag) } /* Return a pointer to the data buffer. */ -uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag) +static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) { + SCSIDeviceState *s = d->state; SCSIRequest *r; r = scsi_find_request(s, tag); @@ -276,8 +280,10 @@ uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag) (eg. disk reads), negative for transfers to the device (eg. disk writes), and zero if the command does not transfer any data. */ -int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) +static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, + uint8_t *buf, int lun) { + SCSIDeviceState *s = d->state; int64_t nb_sectors; uint32_t lba; uint32_t len; @@ -291,7 +297,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) r = scsi_find_request(s, tag); if (r) { BADF("Tag 0x%x already in use\n", tag); - scsi_cancel_io(s, tag); + scsi_cancel_io(d, tag); } /* ??? Tags are not unique for different luns. We only implement a single lun, so this should not matter. */ @@ -576,19 +582,19 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) } } -void scsi_disk_destroy(SCSIDevice *s) +static void scsi_destroy(SCSIDevice *d) { - qemu_free(s); + qemu_free(d->state); + qemu_free(d); } -SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, - int tcq, - scsi_completionfn completion, - void *opaque) +SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, + scsi_completionfn completion, void *opaque) { - SCSIDevice *s; + SCSIDevice *d; + SCSIDeviceState *s; - s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); + s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState)); s->bdrv = bdrv; s->tcq = tcq; s->completion = completion; @@ -599,6 +605,14 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, s->cluster_size = 1; } - return s; -} + d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); + d->state = s; + d->destroy = scsi_destroy; + d->send_command = scsi_send_command; + d->read_data = scsi_read_data; + d->write_data = scsi_write_data; + d->cancel_io = scsi_cancel_io; + d->get_buf = scsi_get_buf; + return d; +} diff --git a/hw/scsi-disk.h b/hw/scsi-disk.h index 9071cec49..ffe894b76 100644 --- a/hw/scsi-disk.h +++ b/hw/scsi-disk.h @@ -7,24 +7,25 @@ enum scsi_reason { SCSI_REASON_DATA /* Transfer complete, more data required. */ }; +typedef struct SCSIDeviceState SCSIDeviceState; typedef struct SCSIDevice SCSIDevice; typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag, uint32_t arg); -SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, - int tcq, - scsi_completionfn completion, - void *opaque); -void scsi_disk_destroy(SCSIDevice *s); +struct SCSIDevice +{ + SCSIDeviceState *state; + void (*destroy)(SCSIDevice *s); + int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf, + int lun); + void (*read_data)(SCSIDevice *s, uint32_t tag); + int (*write_data)(SCSIDevice *s, uint32_t tag); + void (*cancel_io)(SCSIDevice *s, uint32_t tag); + uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag); +}; -int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); -/* SCSI data transfers are asynchrnonous. However, unlike the block IO - layer the completion routine may be called directly by - scsi_{read,write}_data. */ -void scsi_read_data(SCSIDevice *s, uint32_t tag); -int scsi_write_data(SCSIDevice *s, uint32_t tag); -void scsi_cancel_io(SCSIDevice *s, uint32_t tag); -uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); +SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, + scsi_completionfn completion, void *opaque); /* cdrom.c */ int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 7ee9cc1da..01d492d42 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -149,9 +149,9 @@ static void usb_msd_copy_data(MSDState *s) s->data_len -= len; if (s->scsi_len == 0) { if (s->mode == USB_MSDM_DATAIN) { - scsi_read_data(s->scsi_dev, s->tag); + s->scsi_dev->read_data(s->scsi_dev, s->tag); } else if (s->mode == USB_MSDM_DATAOUT) { - scsi_write_data(s->scsi_dev, s->tag); + s->scsi_dev->write_data(s->scsi_dev, s->tag); } } } @@ -204,7 +204,7 @@ static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag, return; } s->scsi_len = arg; - s->scsi_buf = scsi_get_buf(s->scsi_dev, tag); + s->scsi_buf = s->scsi_dev->get_buf(s->scsi_dev, tag); if (p) { usb_msd_copy_data(s); if (s->usb_len == 0) { @@ -342,7 +342,7 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, static void usb_msd_cancel_io(USBPacket *p, void *opaque) { MSDState *s = opaque; - scsi_cancel_io(s->scsi_dev, s->tag); + s->scsi_dev->cancel_io(s->scsi_dev, s->tag); s->packet = NULL; s->scsi_len = 0; } @@ -390,14 +390,14 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->residue = 0; - scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); + s->scsi_dev->send_command(s->scsi_dev, s->tag, cbw.cmd, 0); /* ??? Should check that USB and SCSI data transfer directions match. */ if (s->residue == 0) { if (s->mode == USB_MSDM_DATAIN) { - scsi_read_data(s->scsi_dev, s->tag); + s->scsi_dev->read_data(s->scsi_dev, s->tag); } else if (s->mode == USB_MSDM_DATAOUT) { - scsi_write_data(s->scsi_dev, s->tag); + s->scsi_dev->write_data(s->scsi_dev, s->tag); } } ret = len; @@ -508,7 +508,7 @@ static void usb_msd_handle_destroy(USBDevice *dev) { MSDState *s = (MSDState *)dev; - scsi_disk_destroy(s->scsi_dev); + s->scsi_dev->destroy(s->scsi_dev); bdrv_delete(s->bs); qemu_free(s); } -- cgit v1.2.3 From 4e7774427dcc596225dbb6dc720a4bf637aba8d8 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 10 Dec 2007 07:40:16 +0000 Subject: Fix PowerPC 74xx definitions. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3798 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 5 +- target-ppc/translate_init.c | 272 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 228 insertions(+), 49 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e780764b0..6e6057aae 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1235,7 +1235,7 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_40x_EVPR (0x3D6) #define SPR_L3PM (0x3D7) #define SPR_403_CDBCR (0x3D7) -#define SPR_L3OHCR (0x3D8) +#define SPR_L3ITCR0 (0x3D8) #define SPR_TCR (0x3D8) #define SPR_40x_TSR (0x3D8) #define SPR_IBR (0x3DA) @@ -1248,7 +1248,7 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_40x_SRR2 (0x3DE) #define SPR_SER (0x3DF) #define SPR_40x_SRR3 (0x3DF) -#define SPR_L3ITCR0 (0x3E8) +#define SPR_L3OHCR (0x3E8) #define SPR_L3ITCR1 (0x3E9) #define SPR_L3ITCR2 (0x3EA) #define SPR_L3ITCR3 (0x3EB) @@ -1277,6 +1277,7 @@ static inline int cpu_mmu_index (CPUState *env) #define SPR_MSSCR0 (0x3F6) #define SPR_970_HID5 (0x3F6) #define SPR_MSSSR0 (0x3F7) +#define SPR_MSSCR1 (0x3F7) #define SPR_DABRX (0x3F7) #define SPR_40x_DAC2 (0x3F7) #define SPR_MMUCFG (0x3F7) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 40b59105b..ad12364ac 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1149,11 +1149,6 @@ static void gen_spr_74xx (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_UBAMR, "UBAMR", - &spr_read_ureg, SPR_NOACCESS, - &spr_read_ureg, SPR_NOACCESS, - 0x00000000); - /* XXX : not implemented */ spr_register(env, SPR_MSSCR0, "MSSCR0", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -1195,30 +1190,6 @@ static void gen_l3_ctrl (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); - /* L3ITCR1 */ - /* XXX : not implemented */ - spr_register(env, SPR_L3ITCR1, "L3ITCR1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* L3ITCR2 */ - /* XXX : not implemented */ - spr_register(env, SPR_L3ITCR2, "L3ITCR2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* L3ITCR3 */ - /* XXX : not implemented */ - spr_register(env, SPR_L3ITCR3, "L3ITCR3", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* L3OHCR */ - /* XXX : not implemented */ - spr_register(env, SPR_L3OHCR, "L3OHCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); /* L3PM */ /* XXX : not implemented */ spr_register(env, SPR_L3PM, "L3PM", @@ -3052,6 +3023,14 @@ static int check_pow_hid0 (CPUPPCState *env) return 0; } +static int check_pow_hid0_74xx (CPUPPCState *env) +{ + if (env->spr[SPR_HID0] & 0x00600000) + return 1; + + return 0; +} + /*****************************************************************************/ /* PowerPC implementations definitions */ @@ -4829,6 +4808,7 @@ static void init_proc_750cl (CPUPPCState *env) ppc6xx_irq_init(env); } +/* PowerPC 750CX */ #define POWERPC_INSNS_750cx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ @@ -4876,9 +4856,8 @@ static void init_proc_750cx (CPUPPCState *env) 0x00000000); /* Memory management */ gen_low_BATs(env); - /* XXX: high BATs are also present but are known to be bugged on - * die version 1.x - */ + /* PowerPC 750cx has 8 DBATs and 8 IBATs */ + gen_high_BATs(env); init_excp_750cx(env); env->dcache_line_size = 32; env->icache_line_size = 32; @@ -5147,7 +5126,7 @@ static void init_proc_755 (CPUPPCState *env) #define POWERPC_FLAG_7400 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7400 check_pow_hid0 +#define check_pow_7400 check_pow_hid0_74xx static void init_proc_7400 (CPUPPCState *env) { @@ -5157,6 +5136,17 @@ static void init_proc_7400 (CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* XXX: this seems not implemented on all revisions. */ + /* XXX : not implemented */ + spr_register(env, SPR_MSSCR1, "MSSCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* Thermal management */ gen_spr_thrm(env); /* Memory management */ @@ -5188,7 +5178,7 @@ static void init_proc_7400 (CPUPPCState *env) #define POWERPC_FLAG_7410 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7410 check_pow_hid0 +#define check_pow_7410 check_pow_hid0_74xx static void init_proc_7410 (CPUPPCState *env) { @@ -5198,6 +5188,11 @@ static void init_proc_7410 (CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); /* Thermal management */ gen_spr_thrm(env); /* L2PMCR */ @@ -5241,7 +5236,7 @@ static void init_proc_7410 (CPUPPCState *env) #define POWERPC_FLAG_7440 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7440 check_pow_hid0 +#define check_pow_7440 check_pow_hid0_74xx __attribute__ (( unused )) static void init_proc_7440 (CPUPPCState *env) @@ -5252,6 +5247,11 @@ static void init_proc_7440 (CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); /* LDSTCR */ /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", @@ -5321,7 +5321,7 @@ static void init_proc_7440 (CPUPPCState *env) #define POWERPC_FLAG_7450 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7450 check_pow_hid0 +#define check_pow_7450 check_pow_hid0_74xx __attribute__ (( unused )) static void init_proc_7450 (CPUPPCState *env) @@ -5334,6 +5334,35 @@ static void init_proc_7450 (CPUPPCState *env) gen_spr_74xx(env); /* Level 3 cache control */ gen_l3_ctrl(env); + /* L3ITCR1 */ + /* XXX : not implemented */ + spr_register(env, SPR_L3ITCR1, "L3ITCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3ITCR2 */ + /* XXX : not implemented */ + spr_register(env, SPR_L3ITCR2, "L3ITCR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3ITCR3 */ + /* XXX : not implemented */ + spr_register(env, SPR_L3ITCR3, "L3ITCR3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3OHCR */ + /* XXX : not implemented */ + spr_register(env, SPR_L3OHCR, "L3OHCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); /* LDSTCR */ /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", @@ -5403,7 +5432,7 @@ static void init_proc_7450 (CPUPPCState *env) #define POWERPC_FLAG_7445 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7445 check_pow_hid0 +#define check_pow_7445 check_pow_hid0_74xx __attribute__ (( unused )) static void init_proc_7445 (CPUPPCState *env) @@ -5517,7 +5546,7 @@ static void init_proc_7445 (CPUPPCState *env) #define POWERPC_FLAG_7455 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7455 check_pow_hid0 +#define check_pow_7455 check_pow_hid0_74xx __attribute__ (( unused )) static void init_proc_7455 (CPUPPCState *env) @@ -5613,6 +5642,146 @@ static void init_proc_7455 (CPUPPCState *env) ppc6xx_irq_init(env); } +/* PowerPC 7457 (aka G4) */ +#define POWERPC_INSNS_7457 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ + PPC_FLOAT_STFIWX | \ + PPC_CACHE | PPC_CACHE_ICBI | \ + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ + PPC_MEM_SYNC | PPC_MEM_EIEIO | \ + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ + PPC_MEM_TLBIA | PPC_74xx_TLB | \ + PPC_SEGMENT | PPC_EXTERN | \ + PPC_ALTIVEC) +#define POWERPC_MSRM_7457 (0x000000000205FF77ULL) +#define POWERPC_MMU_7457 (POWERPC_MMU_SOFT_74xx) +#define POWERPC_EXCP_7457 (POWERPC_EXCP_74xx) +#define POWERPC_INPUT_7457 (PPC_FLAGS_INPUT_6xx) +#define POWERPC_BFDM_7457 (bfd_mach_ppc_7400) +#define POWERPC_FLAG_7457 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ + POWERPC_FLAG_BUS_CLK) +#define check_pow_7457 check_pow_hid0_74xx + +__attribute__ (( unused )) +static void init_proc_7457 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* 74xx specific SPR */ + gen_spr_74xx(env); + /* Level 3 cache control */ + gen_l3_ctrl(env); + /* L3ITCR1 */ + /* XXX : not implemented */ + spr_register(env, SPR_L3ITCR1, "L3ITCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3ITCR2 */ + /* XXX : not implemented */ + spr_register(env, SPR_L3ITCR2, "L3ITCR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3ITCR3 */ + /* XXX : not implemented */ + spr_register(env, SPR_L3ITCR3, "L3ITCR3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* L3OHCR */ + /* XXX : not implemented */ + spr_register(env, SPR_L3OHCR, "L3OHCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* LDSTCR */ + /* XXX : not implemented */ + spr_register(env, SPR_LDSTCR, "LDSTCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* ICTRL */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTRL, "ICTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* MSSSR0 */ + /* XXX : not implemented */ + spr_register(env, SPR_MSSSR0, "MSSSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* PMC */ + /* XXX : not implemented */ + spr_register(env, SPR_PMC5, "PMC5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_UPMC5, "UPMC5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC6, "PMC6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_UPMC6, "UPMC6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* SPRGs */ + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_74xx_soft_tlb(env, 128, 2); + init_excp_7450(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + #if defined (TARGET_PPC64) /* PowerPC 970 */ #define POWERPC_INSNS_970 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ @@ -6651,6 +6820,7 @@ enum { CPU_POWERPC_7400_v10 = 0x000C0100, CPU_POWERPC_7400_v11 = 0x000C0101, CPU_POWERPC_7400_v20 = 0x000C0200, + CPU_POWERPC_7400_v21 = 0x000C0201, CPU_POWERPC_7400_v22 = 0x000C0202, CPU_POWERPC_7400_v26 = 0x000C0206, CPU_POWERPC_7400_v27 = 0x000C0207, @@ -6671,10 +6841,12 @@ enum { CPU_POWERPC_7450_v10 = 0x80000100, CPU_POWERPC_7450_v11 = 0x80000101, CPU_POWERPC_7450_v12 = 0x80000102, - CPU_POWERPC_7450_v20 = 0x80000200, /* aka D: 2.04 */ + CPU_POWERPC_7450_v20 = 0x80000200, /* aka A, B, C, D: 2.04 */ CPU_POWERPC_7450_v21 = 0x80000201, /* aka E */ - CPU_POWERPC_74x1 = 0x80000203, - CPU_POWERPC_74x1G = 0x80000210, /* aka G: 2.3 */ +#define CPU_POWERPC_74x1 CPU_POWERPC_74x1_v23 + CPU_POWERPC_74x1_v23 = 0x80000203, /* aka G: 2.3 */ + /* XXX: this entry might be a bug in some documentation */ + CPU_POWERPC_74x1_v210 = 0x80000210, /* aka G: 2.3 ? */ #define CPU_POWERPC_74x5 CPU_POWERPC_74x5_v32 CPU_POWERPC_74x5_v10 = 0x80010100, /* XXX: missing 0x80010200 */ @@ -8300,6 +8472,8 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7400_v1.1", CPU_POWERPC_7400_v11, 7400), /* PowerPC 7400 v2.0 (G4) */ POWERPC_DEF("7400_v2.0", CPU_POWERPC_7400_v20, 7400), + /* PowerPC 7400 v2.1 (G4) */ + POWERPC_DEF("7400_v2.1", CPU_POWERPC_7400_v21, 7400), /* PowerPC 7400 v2.2 (G4) */ POWERPC_DEF("7400_v2.2", CPU_POWERPC_7400_v22, 7400), /* PowerPC 7400 v2.6 (G4) */ @@ -8352,10 +8526,16 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7441", CPU_POWERPC_74x1, 7440), /* PowerPC 7451 (G4) */ POWERPC_DEF("7451", CPU_POWERPC_74x1, 7450), - /* PowerPC 7441g (G4) */ - POWERPC_DEF("7441g", CPU_POWERPC_74x1G, 7440), - /* PowerPC 7451g (G4) */ - POWERPC_DEF("7451g", CPU_POWERPC_74x1G, 7450), + /* PowerPC 7441 v2.1 (G4) */ + POWERPC_DEF("7441_v2.1", CPU_POWERPC_7450_v21, 7440), + /* PowerPC 7441 v2.3 (G4) */ + POWERPC_DEF("7441_v2.3", CPU_POWERPC_74x1_v23, 7440), + /* PowerPC 7451 v2.3 (G4) */ + POWERPC_DEF("7451_v2.3", CPU_POWERPC_74x1_v23, 7450), + /* PowerPC 7441 v2.10 (G4) */ + POWERPC_DEF("7441_v2.10", CPU_POWERPC_74x1_v210, 7440), + /* PowerPC 7451 v2.10 (G4) */ + POWERPC_DEF("7451_v2.10", CPU_POWERPC_74x1_v210, 7450), /* PowerPC 7445 (G4) */ POWERPC_DEF("7445", CPU_POWERPC_74x5, 7445), /* PowerPC 7455 (G4) */ @@ -8396,8 +8576,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445), /* PowerPC 7457 v1.1 (G4) */ POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455), - /* PowerPC 7447 v1.2 (G4) */ - POWERPC_DEF("7447_v1.2", CPU_POWERPC_74x7_v12, 7445), /* PowerPC 7457 v1.2 (G4) */ POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455), /* PowerPC 7447A (G4) */ -- cgit v1.2.3 From e9b34b3741c541aba1bb80b20755f03bdf167cd0 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 10 Dec 2007 08:13:09 +0000 Subject: Cleanup: remove useless TARGET_GPR_BITS definition. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3799 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6e6057aae..88129758e 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -28,7 +28,6 @@ #if defined (TARGET_PPC64) /* PowerPC 64 definitions */ typedef uint64_t ppc_gpr_t; -#define TARGET_GPR_BITS 64 #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 12 @@ -41,10 +40,8 @@ typedef uint64_t ppc_gpr_t; * the compiler to do unuseful masking in the micro-ops. */ typedef uint64_t ppc_gpr_t; -#define TARGET_GPR_BITS 64 #else /* (HOST_LONG_BITS >= 64) */ typedef uint32_t ppc_gpr_t; -#define TARGET_GPR_BITS 32 #endif /* (HOST_LONG_BITS >= 64) */ #define TARGET_LONG_BITS 32 -- cgit v1.2.3 From e32448e059adc8e6b31df483a679b399bc990e5a Mon Sep 17 00:00:00 2001 From: j_mayer Date: Mon, 10 Dec 2007 08:24:59 +0000 Subject: Various linux-user structures and definitions fixes for PowerPC targets. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3800 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/ppc/syscall.h | 30 +++++++++++++++++------------- linux-user/ppc/target_signal.h | 2 +- linux-user/socket.h | 9 +++++++++ linux-user/syscall_defs.h | 37 ++++++++++++++++++------------------- 4 files changed, 45 insertions(+), 33 deletions(-) diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index f98d2bca5..2035dfbfd 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -26,20 +26,24 @@ #define __USER_DS (1) struct target_pt_regs { - unsigned long gpr[32]; - unsigned long nip; - unsigned long msr; - unsigned long orig_gpr3; /* Used for restarting system calls */ - unsigned long ctr; - unsigned long link; - unsigned long xer; - unsigned long ccr; - unsigned long mq; /* 601 only (not used at present) */ + abi_ulong gpr[32]; + abi_ulong nip; + abi_ulong msr; + abi_ulong orig_gpr3; /* Used for restarting system calls */ + abi_ulong ctr; + abi_ulong link; + abi_ulong xer; + abi_ulong ccr; +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) + abi_ulong softe; +#else + abi_ulong mq; /* 601 only (not used at present) */ +#endif /* Used on APUS to hold IPL value. */ - unsigned long trap; /* Reason for being here */ - unsigned long dar; /* Fault registers */ - unsigned long dsisr; - unsigned long result; /* Result of a system call */ + abi_ulong trap; /* Reason for being here */ + abi_ulong dar; /* Fault registers */ + abi_ulong dsisr; + abi_ulong result; /* Result of a system call */ }; /* ioctls */ diff --git a/linux-user/ppc/target_signal.h b/linux-user/ppc/target_signal.h index defae809a..a93b5cf1d 100644 --- a/linux-user/ppc/target_signal.h +++ b/linux-user/ppc/target_signal.h @@ -7,7 +7,7 @@ typedef struct target_sigaltstack { abi_ulong ss_sp; - abi_long ss_flags; + int ss_flags; abi_ulong ss_size; } target_stack_t; diff --git a/linux-user/socket.h b/linux-user/socket.h index f13ca45e3..93d47823d 100644 --- a/linux-user/socket.h +++ b/linux-user/socket.h @@ -109,12 +109,21 @@ #define TARGET_SO_LINGER 13 #define TARGET_SO_BSDCOMPAT 14 /* To add :#define TARGET_SO_REUSEPORT 15 */ +#if defined(TARGET_PPC) + #define TARGET_SO_RCVLOWAT 16 + #define TARGET_SO_SNDLOWAT 17 + #define TARGET_SO_RCVTIMEO 18 + #define TARGET_SO_SNDTIMEO 19 + #define TARGET_SO_PASSCRED 20 + #define TARGET_SO_PEERCRED 21 +#else #define TARGET_SO_PASSCRED 16 #define TARGET_SO_PEERCRED 17 #define TARGET_SO_RCVLOWAT 18 #define TARGET_SO_SNDLOWAT 19 #define TARGET_SO_RCVTIMEO 20 #define TARGET_SO_SNDTIMEO 21 +#endif /* Security levels - as per NRL IPv6 - don't actually do anything */ #define TARGET_SO_SECURITY_AUTHENTICATION 22 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 64bc94f22..de4691223 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1086,10 +1086,10 @@ struct target_stat64 { #elif defined(TARGET_PPC) struct target_stat { - unsigned short st_dev; + abi_ulong st_dev; abi_ulong st_ino; #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) - unsigned short st_nlink; + abi_ulong st_nlink; unsigned int st_mode; #else unsigned int st_mode; @@ -1097,16 +1097,16 @@ struct target_stat { #endif unsigned int st_uid; unsigned int st_gid; - unsigned short st_rdev; + abi_ulong st_rdev; abi_ulong st_size; abi_ulong st_blksize; abi_ulong st_blocks; abi_ulong target_st_atime; - abi_ulong __unused1; + abi_ulong target_st_atime_nsec; abi_ulong target_st_mtime; - abi_ulong __unused2; + abi_ulong target_st_mtime_nsec; abi_ulong target_st_ctime; - abi_ulong __unused3; + abi_ulong target_st_ctime_nsec; abi_ulong __unused4; abi_ulong __unused5; #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) @@ -1122,19 +1122,18 @@ struct target_stat64 { unsigned int st_uid; unsigned int st_gid; unsigned long long st_rdev; - long long pad0; - long long st_size; - abi_ulong st_blksize; - abi_ulong pad1; - long long st_blocks; /* Number 512-byte blocks allocated. */ - abi_ulong target_st_atime; - abi_ulong target_st_atime_nsec; - abi_ulong target_st_mtime; - abi_ulong target_st_mtime_nsec; - abi_ulong target_st_ctime; - abi_ulong target_st_ctime_nsec; - abi_ulong __unused4; - abi_ulong __unused5; + unsigned short pad0; + long long st_size; + int st_blksize; + long long st_blocks; /* Number 512-byte blocks allocated. */ + int target_st_atime; + unsigned int target_st_atime_nsec; + int target_st_mtime; + unsigned int target_st_mtime_nsec; + int target_st_ctime; + unsigned int target_st_ctime_nsec; + unsigned int __unused4; + unsigned int __unused5; }; #elif defined(TARGET_M68K) -- cgit v1.2.3 From 666c87aa3b91298ab3b57da6c2ad63b526703b40 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 10 Dec 2007 19:58:20 +0000 Subject: Add ASIs (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3801 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/op_helper.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index a71c9da37..b711c6273 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -411,6 +411,9 @@ void helper_ld_asi(int asi, int size, int sign) break; } break; + case 0x39: /* data cache diagnostic register */ + ret = 0; + break; case 0x21 ... 0x2d: /* MMU passthrough, unassigned */ default: do_unassigned_access(T0, 0, 0, 1); @@ -703,9 +706,13 @@ void helper_st_asi(int asi, int size) } } return; - case 0x31: /* Ross RT620 I-cache flush */ + case 0x30: /* store buffer tags */ + case 0x31: /* store buffer data or Ross RT620 I-cache flush */ + case 0x32: /* store buffer control */ case 0x36: /* I-cache flash clear */ case 0x37: /* D-cache flash clear */ + case 0x38: /* breakpoint diagnostics */ + case 0x4c: /* breakpoint action */ break; case 9: /* Supervisor code access, XXX */ case 0x21 ... 0x2d: /* MMU passthrough, unassigned */ -- cgit v1.2.3 From ae40972f78241e10340f74e184555dc92e067718 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 10 Dec 2007 20:00:11 +0000 Subject: Add SPARCstation 20 machine type (Robert Reif) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3802 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/boards.h | 2 +- hw/sun4m.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 1 + 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/hw/boards.h b/hw/boards.h index 6374dd1b2..712d3cd39 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -52,7 +52,7 @@ extern QEMUMachine shix_machine; extern QEMUMachine r2d_machine; /* sun4m.c */ -extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine; +extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine, ss20_machine; /* sun4u.c */ extern QEMUMachine sun4u_machine; diff --git a/hw/sun4m.c b/hw/sun4m.c index 3385adb91..693fa696a 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -600,6 +600,44 @@ static const struct hwdef hwdefs[] = { .max_mem = 0xffffffff, // XXX actually first 62GB ok .default_cpu_model = "TI SuperSparc II", }, + /* SS-20 */ + { + .iommu_base = 0xfe0000000ULL, + .tcx_base = 0xe20000000ULL, + .cs_base = -1, + .slavio_base = 0xff0000000ULL, + .ms_kb_base = 0xff1000000ULL, + .serial_base = 0xff1100000ULL, + .nvram_base = 0xff1200000ULL, + .fd_base = 0xff1700000ULL, + .counter_base = 0xff1300000ULL, + .intctl_base = 0xff1400000ULL, + .dma_base = 0xef0400000ULL, + .esp_base = 0xef0800000ULL, + .le_base = 0xef0c00000ULL, + .power_base = 0xefa000000ULL, + .ecc_base = 0xf00000000ULL, + .ecc_version = 0x20000000, // version 0, implementation 2 + .vram_size = 0x00100000, + .nvram_size = 0x2000, + .esp_irq = 18, + .le_irq = 16, + .clock_irq = 7, + .clock1_irq = 19, + .ms_kb_irq = 14, + .ser_irq = 15, + .fd_irq = 22, + .me_irq = 30, + .cs_irq = -1, + .machine_id = 0x72, + .iommu_version = 0x13000000, + .intbit_to_level = { + 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, + 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, + }, + .max_mem = 0xffffffff, // XXX actually first 62GB ok + .default_cpu_model = "TI SuperSparc II", + }, }; /* SPARCstation 5 hardware initialisation */ @@ -632,6 +670,16 @@ static void ss600mp_init(int RAM_size, int vga_ram_size, kernel_cmdline, initrd_filename, cpu_model); } +/* SPARCstation 20 hardware initialisation */ +static void ss20_init(int RAM_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + sun4m_hw_init(&hwdefs[3], RAM_size, boot_device, ds, kernel_filename, + kernel_cmdline, initrd_filename, cpu_model); +} + QEMUMachine ss5_machine = { "SS-5", "Sun4m platform, SPARCstation 5", @@ -649,3 +697,10 @@ QEMUMachine ss600mp_machine = { "Sun4m platform, SPARCserver 600MP", ss600mp_init, }; + +QEMUMachine ss20_machine = { + "SS-20", + "Sun4m platform, SPARCstation 20", + ss20_init, +}; + diff --git a/vl.c b/vl.c index 5b7e97e6d..9cb81ce47 100644 --- a/vl.c +++ b/vl.c @@ -7838,6 +7838,7 @@ static void register_machines(void) qemu_register_machine(&ss5_machine); qemu_register_machine(&ss10_machine); qemu_register_machine(&ss600mp_machine); + qemu_register_machine(&ss20_machine); #endif #elif defined(TARGET_ARM) qemu_register_machine(&integratorcp_machine); -- cgit v1.2.3 From 12abac853d38600847c1be2ccf90a67691a3588a Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Mon, 10 Dec 2007 20:05:09 +0000 Subject: Name the magic constants, wrap long lines git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3803 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/slavio_serial.c | 324 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 221 insertions(+), 103 deletions(-) diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c index 42d233ee6..baec120ef 100644 --- a/hw/slavio_serial.c +++ b/hw/slavio_serial.c @@ -89,6 +89,7 @@ typedef struct { int rptr, wptr, count; } SERIOQueue; +#define SERIAL_REGS 16 typedef struct ChannelState { qemu_irq irq; int reg; @@ -96,7 +97,7 @@ typedef struct ChannelState { chn_id_t chn; // this channel, A (base+4) or B (base+0) chn_type_t type; struct ChannelState *otherchn; - uint8_t rx, tx, wregs[16], rregs[16]; + uint8_t rx, tx, wregs[SERIAL_REGS], rregs[SERIAL_REGS]; SERIOQueue queue; CharDriverState *chr; int e0_mode, led_mode, caps_lock_mode, num_lock_mode; @@ -109,6 +110,107 @@ struct SerialState { #define SERIAL_MAXADDR 7 #define SERIAL_SIZE (SERIAL_MAXADDR + 1) +#define SERIAL_CTRL 0 +#define SERIAL_DATA 1 + +#define W_CMD 0 +#define CMD_PTR_MASK 0x07 +#define CMD_CMD_MASK 0x38 +#define CMD_HI 0x08 +#define CMD_CLR_TXINT 0x28 +#define CMD_CLR_IUS 0x38 +#define W_INTR 1 +#define INTR_INTALL 0x01 +#define INTR_TXINT 0x02 +#define INTR_RXMODEMSK 0x18 +#define INTR_RXINT1ST 0x08 +#define INTR_RXINTALL 0x10 +#define W_IVEC 2 +#define W_RXCTRL 3 +#define RXCTRL_RXEN 0x01 +#define W_TXCTRL1 4 +#define TXCTRL1_PAREN 0x01 +#define TXCTRL1_PAREV 0x02 +#define TXCTRL1_1STOP 0x04 +#define TXCTRL1_1HSTOP 0x08 +#define TXCTRL1_2STOP 0x0c +#define TXCTRL1_STPMSK 0x0c +#define TXCTRL1_CLK1X 0x00 +#define TXCTRL1_CLK16X 0x40 +#define TXCTRL1_CLK32X 0x80 +#define TXCTRL1_CLK64X 0xc0 +#define TXCTRL1_CLKMSK 0xc0 +#define W_TXCTRL2 5 +#define TXCTRL2_TXEN 0x08 +#define TXCTRL2_BITMSK 0x60 +#define TXCTRL2_5BITS 0x00 +#define TXCTRL2_7BITS 0x20 +#define TXCTRL2_6BITS 0x40 +#define TXCTRL2_8BITS 0x60 +#define W_SYNC1 6 +#define W_SYNC2 7 +#define W_TXBUF 8 +#define W_MINTR 9 +#define MINTR_STATUSHI 0x10 +#define MINTR_RST_MASK 0xc0 +#define MINTR_RST_B 0x40 +#define MINTR_RST_A 0x80 +#define MINTR_RST_ALL 0xc0 +#define W_MISC1 10 +#define W_CLOCK 11 +#define CLOCK_TRXC 0x08 +#define W_BRGLO 12 +#define W_BRGHI 13 +#define W_MISC2 14 +#define MISC2_PLLDIS 0x30 +#define W_EXTINT 15 +#define EXTINT_DCD 0x08 +#define EXTINT_SYNCINT 0x10 +#define EXTINT_CTSINT 0x20 +#define EXTINT_TXUNDRN 0x40 +#define EXTINT_BRKINT 0x80 + +#define R_STATUS 0 +#define STATUS_RXAV 0x01 +#define STATUS_ZERO 0x02 +#define STATUS_TXEMPTY 0x04 +#define STATUS_DCD 0x08 +#define STATUS_SYNC 0x10 +#define STATUS_CTS 0x20 +#define STATUS_TXUNDRN 0x40 +#define STATUS_BRK 0x80 +#define R_SPEC 1 +#define SPEC_ALLSENT 0x01 +#define SPEC_BITS8 0x06 +#define R_IVEC 2 +#define IVEC_TXINTB 0x00 +#define IVEC_LONOINT 0x06 +#define IVEC_LORXINTA 0x0c +#define IVEC_LORXINTB 0x04 +#define IVEC_LOTXINTA 0x08 +#define IVEC_HINOINT 0x60 +#define IVEC_HIRXINTA 0x30 +#define IVEC_HIRXINTB 0x20 +#define IVEC_HITXINTA 0x10 +#define R_INTR 3 +#define INTR_EXTINTB 0x01 +#define INTR_TXINTB 0x02 +#define INTR_RXINTB 0x04 +#define INTR_EXTINTA 0x08 +#define INTR_TXINTA 0x10 +#define INTR_RXINTA 0x20 +#define R_IPEN 4 +#define R_TXCTRL1 5 +#define R_TXCTRL2 6 +#define R_BC 7 +#define R_RXBUF 8 +#define R_RXCTRL 9 +#define R_MISC 10 +#define R_MISC1 11 +#define R_BRGLO 12 +#define R_BRGHI 13 +#define R_MISC1I 14 +#define R_EXTINT 15 static void handle_kbd_command(ChannelState *s, int val); static int serial_can_receive(void *opaque); @@ -159,11 +261,14 @@ static uint32_t get_queue(void *opaque) static int slavio_serial_update_irq_chn(ChannelState *s) { - if ((s->wregs[1] & 1) && // interrupts enabled - (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending - ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && + if ((s->wregs[W_INTR] & INTR_INTALL) && // interrupts enabled + (((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) || + // tx ints enabled, pending + ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) || + ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) && s->rxint == 1) || // rx ints enabled, pending - ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p + ((s->wregs[W_EXTINT] & EXTINT_BRKINT) && + (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p return 1; } return 0; @@ -189,16 +294,18 @@ static void slavio_serial_reset_chn(ChannelState *s) s->rregs[i] = 0; s->wregs[i] = 0; } - s->wregs[4] = 4; - s->wregs[9] = 0xc0; - s->wregs[11] = 8; - s->wregs[14] = 0x30; - s->wregs[15] = 0xf8; + s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity + s->wregs[W_MINTR] = MINTR_RST_ALL; + s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC + s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled + s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT | + EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts if (s->disabled) - s->rregs[0] = 0x7c; + s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC | + STATUS_CTS | STATUS_TXUNDRN; else - s->rregs[0] = 0x44; - s->rregs[1] = 6; + s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN; + s->rregs[R_SPEC] = SPEC_BITS8; s->rx = s->tx = 0; s->rxint = s->txint = 0; @@ -219,17 +326,17 @@ static inline void clr_rxint(ChannelState *s) s->rxint = 0; s->rxint_under_svc = 0; if (s->chn == chn_a) { - if (s->wregs[9] & 0x10) - s->otherchn->rregs[2] = 0x60; + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->otherchn->rregs[R_IVEC] = IVEC_HINOINT; else - s->otherchn->rregs[2] = 0x06; - s->rregs[3] &= ~0x20; + s->otherchn->rregs[R_IVEC] = IVEC_LONOINT; + s->rregs[R_INTR] &= ~INTR_RXINTA; } else { - if (s->wregs[9] & 0x10) - s->rregs[2] = 0x60; + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->rregs[R_IVEC] = IVEC_HINOINT; else - s->rregs[2] = 0x06; - s->otherchn->rregs[3] &= ~4; + s->rregs[R_IVEC] = IVEC_LONOINT; + s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB; } if (s->txint) set_txint(s); @@ -242,21 +349,21 @@ static inline void set_rxint(ChannelState *s) if (!s->txint_under_svc) { s->rxint_under_svc = 1; if (s->chn == chn_a) { - if (s->wregs[9] & 0x10) - s->otherchn->rregs[2] = 0x30; + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA; else - s->otherchn->rregs[2] = 0x0c; + s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA; } else { - if (s->wregs[9] & 0x10) - s->rregs[2] = 0x20; + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->rregs[R_IVEC] = IVEC_HIRXINTB; else - s->rregs[2] = 0x04; + s->rregs[R_IVEC] = IVEC_LORXINTB; } } if (s->chn == chn_a) - s->rregs[3] |= 0x20; + s->rregs[R_INTR] |= INTR_RXINTA; else - s->otherchn->rregs[3] |= 4; + s->otherchn->rregs[R_INTR] |= INTR_RXINTB; slavio_serial_update_irq(s); } @@ -265,17 +372,17 @@ static inline void clr_txint(ChannelState *s) s->txint = 0; s->txint_under_svc = 0; if (s->chn == chn_a) { - if (s->wregs[9] & 0x10) - s->otherchn->rregs[2] = 0x60; + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->otherchn->rregs[R_IVEC] = IVEC_HINOINT; else - s->otherchn->rregs[2] = 0x06; - s->rregs[3] &= ~0x10; + s->otherchn->rregs[R_IVEC] = IVEC_LONOINT; + s->rregs[R_INTR] &= ~INTR_TXINTA; } else { - if (s->wregs[9] & 0x10) - s->rregs[2] = 0x60; + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->rregs[R_IVEC] = IVEC_HINOINT; else - s->rregs[2] = 0x06; - s->otherchn->rregs[3] &= ~2; + s->rregs[R_IVEC] = IVEC_LONOINT; + s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB; } if (s->rxint) set_rxint(s); @@ -288,18 +395,18 @@ static inline void set_txint(ChannelState *s) if (!s->rxint_under_svc) { s->txint_under_svc = 1; if (s->chn == chn_a) { - if (s->wregs[9] & 0x10) - s->otherchn->rregs[2] = 0x10; + if (s->wregs[W_MINTR] & MINTR_STATUSHI) + s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA; else - s->otherchn->rregs[2] = 0x08; + s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA; } else { - s->rregs[2] = 0; + s->rregs[R_IVEC] = IVEC_TXINTB; } } if (s->chn == chn_a) - s->rregs[3] |= 0x10; + s->rregs[R_INTR] |= INTR_TXINTA; else - s->otherchn->rregs[3] |= 2; + s->otherchn->rregs[R_INTR] |= INTR_TXINTB; slavio_serial_update_irq(s); } @@ -311,45 +418,45 @@ static void slavio_serial_update_parameters(ChannelState *s) if (!s->chr || s->type != ser) return; - if (s->wregs[4] & 1) { - if (s->wregs[4] & 2) + if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) { + if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV) parity = 'E'; else parity = 'O'; } else { parity = 'N'; } - if ((s->wregs[4] & 0x0c) == 0x0c) + if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP) stop_bits = 2; else stop_bits = 1; - switch (s->wregs[5] & 0x60) { - case 0x00: + switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) { + case TXCTRL2_5BITS: data_bits = 5; break; - case 0x20: + case TXCTRL2_7BITS: data_bits = 7; break; - case 0x40: + case TXCTRL2_6BITS: data_bits = 6; break; default: - case 0x60: + case TXCTRL2_8BITS: data_bits = 8; break; } - speed = 2457600 / ((s->wregs[12] | (s->wregs[13] << 8)) + 2); - switch (s->wregs[4] & 0xc0) { - case 0x00: + speed = 2457600 / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2); + switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) { + case TXCTRL1_CLK1X: break; - case 0x40: + case TXCTRL1_CLK16X: speed /= 16; break; - case 0x80: + case TXCTRL1_CLK32X: speed /= 32; break; default: - case 0xc0: + case TXCTRL1_CLK64X: speed /= 64; break; } @@ -362,7 +469,8 @@ static void slavio_serial_update_parameters(ChannelState *s) qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); } -static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, + uint32_t val) { SerialState *serial = opaque; ChannelState *s; @@ -374,21 +482,22 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint channel = (addr & SERIAL_MAXADDR) >> 2; s = &serial->chn[channel]; switch (saddr) { - case 0: - SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff); + case SERIAL_CTRL: + SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, + val & 0xff); newreg = 0; switch (s->reg) { - case 0: - newreg = val & 7; - val &= 0x38; + case W_CMD: + newreg = val & CMD_PTR_MASK; + val &= CMD_CMD_MASK; switch (val) { - case 8: - newreg |= 0x8; + case CMD_HI: + newreg |= CMD_HI; break; - case 0x28: + case CMD_CLR_TXINT: clr_txint(s); break; - case 0x38: + case CMD_CLR_IUS: if (s->rxint_under_svc) clr_rxint(s); else if (s->txint_under_svc) @@ -398,31 +507,31 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint break; } break; - case 1 ... 3: - case 6 ... 8: - case 10 ... 11: - case 14 ... 15: + case W_INTR ... W_RXCTRL: + case W_SYNC1 ... W_TXBUF: + case W_MISC1 ... W_CLOCK: + case W_MISC2 ... W_EXTINT: s->wregs[s->reg] = val; break; - case 4: - case 5: - case 12: - case 13: + case W_TXCTRL1: + case W_TXCTRL2: + case W_BRGLO: + case W_BRGHI: s->wregs[s->reg] = val; slavio_serial_update_parameters(s); break; - case 9: - switch (val & 0xc0) { + case W_MINTR: + switch (val & MINTR_RST_MASK) { case 0: default: break; - case 0x40: + case MINTR_RST_B: slavio_serial_reset_chn(&serial->chn[1]); return; - case 0x80: + case MINTR_RST_A: slavio_serial_reset_chn(&serial->chn[0]); return; - case 0xc0: + case MINTR_RST_ALL: slavio_serial_reset(serial); return; } @@ -435,18 +544,18 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint else s->reg = 0; break; - case 1: + case SERIAL_DATA: SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val); s->tx = val; - if (s->wregs[5] & 8) { // tx enabled + if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled if (s->chr) qemu_chr_write(s->chr, &s->tx, 1); else if (s->type == kbd && !s->disabled) { handle_kbd_command(s, val); } } - s->rregs[0] |= 4; // Tx buffer empty - s->rregs[1] |= 1; // All sent + s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty + s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent set_txint(s); break; default: @@ -466,13 +575,14 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) channel = (addr & SERIAL_MAXADDR) >> 2; s = &serial->chn[channel]; switch (saddr) { - case 0: - SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]); + case SERIAL_CTRL: + SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, + s->rregs[s->reg]); ret = s->rregs[s->reg]; s->reg = 0; return ret; - case 1: - s->rregs[0] &= ~1; + case SERIAL_DATA: + s->rregs[R_STATUS] &= ~STATUS_RXAV; clr_rxint(s); if (s->type == kbd || s->type == mouse) ret = get_queue(s); @@ -493,26 +603,26 @@ static int serial_can_receive(void *opaque) ChannelState *s = opaque; int ret; - if (((s->wregs[3] & 1) == 0) // Rx not enabled - || ((s->rregs[0] & 1) == 1)) // char already available + if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled + || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV)) + // char already available ret = 0; else ret = 1; - //SER_DPRINTF("channel %c can receive %d\n", CHN_C(s), ret); return ret; } static void serial_receive_byte(ChannelState *s, int ch) { SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch); - s->rregs[0] |= 1; + s->rregs[R_STATUS] |= STATUS_RXAV; s->rx = ch; set_rxint(s); } static void serial_receive_break(ChannelState *s) { - s->rregs[0] |= 0x80; + s->rregs[R_STATUS] |= STATUS_BRK; slavio_serial_update_irq(s); } @@ -553,8 +663,8 @@ static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) qemu_put_be32s(f, &s->txint_under_svc); qemu_put_8s(f, &s->rx); qemu_put_8s(f, &s->tx); - qemu_put_buffer(f, s->wregs, 16); - qemu_put_buffer(f, s->rregs, 16); + qemu_put_buffer(f, s->wregs, SERIAL_REGS); + qemu_put_buffer(f, s->rregs, SERIAL_REGS); } static void slavio_serial_save(QEMUFile *f, void *opaque) @@ -582,8 +692,8 @@ static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) } qemu_get_8s(f, &s->rx); qemu_get_8s(f, &s->tx); - qemu_get_buffer(f, s->wregs, 16); - qemu_get_buffer(f, s->rregs, 16); + qemu_get_buffer(f, s->wregs, SERIAL_REGS); + qemu_get_buffer(f, s->rregs, SERIAL_REGS); return 0; } @@ -610,7 +720,9 @@ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, if (!s) return NULL; - slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); + slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, + slavio_serial_mem_write, + s); cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory); s->chn[0].chr = chr1; @@ -629,7 +741,8 @@ SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq, } s->chn[0].otherchn = &s->chn[1]; s->chn[1].otherchn = &s->chn[0]; - register_savevm("slavio_serial", base, 2, slavio_serial_save, slavio_serial_load, s); + register_savevm("slavio_serial", base, 2, slavio_serial_save, + slavio_serial_load, s); qemu_register_reset(slavio_serial_reset, s); slavio_serial_reset(s); return s; @@ -662,7 +775,8 @@ static void sunkbd_event(void *opaque, int ch) ChannelState *s = opaque; int release = ch & 0x80; - KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" : "press"); + KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" : + "press"); switch (ch) { case 58: // Caps lock press s->caps_lock_mode ^= 1; @@ -792,12 +906,16 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, s->chn[0].disabled = disabled; s->chn[1].disabled = disabled; - slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); + slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, + slavio_serial_mem_write, + s); cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory); - qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, "QEMU Sun Mouse"); + qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, + "QEMU Sun Mouse"); qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); - register_savevm("slavio_serial_mouse", base, 2, slavio_serial_save, slavio_serial_load, s); + register_savevm("slavio_serial_mouse", base, 2, slavio_serial_save, + slavio_serial_load, s); qemu_register_reset(slavio_serial_reset, s); slavio_serial_reset(s); } -- cgit v1.2.3 From 52df269ca821e8bed49ae2d46fe67486f3ef88de Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 11 Dec 2007 19:33:21 +0000 Subject: Update OpenBIOS images to SVN revision 181. Changes: r177: Reset fixes: * recalculate CRC to avoid error message and halt after reset * fix bug that crashed SS10/SMP when reset r178: Remove unused variable r179: Improved Module ID generation r180: Add support for eccmemctl r181: Add support for SPARCstation 20 machine type git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3804 c046a42c-6fe2-441c-8c8c-71466251a162 --- pc-bios/README | 2 +- pc-bios/openbios-sparc32 | Bin 272948 -> 277044 bytes pc-bios/openbios-sparc64 | Bin 475784 -> 475784 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/README b/pc-bios/README index 0c3cfe0e1..f24f40f8c 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -15,7 +15,7 @@ firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. The included Sparc32 and Sparc64 images are built from SVN - revision 176. + revision 181. - The PXE roms come from Rom-o-Matic etherboot 5.4.2. pcnet32:pcnet32 -- [0x1022,0x2000] diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 101b3ce11..0772c53d5 100644 Binary files a/pc-bios/openbios-sparc32 and b/pc-bios/openbios-sparc32 differ diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 14b00734e..6a4d06bf0 100644 Binary files a/pc-bios/openbios-sparc64 and b/pc-bios/openbios-sparc64 differ -- cgit v1.2.3 From d07bde88a52bf293c3f8846cfd162e0a57e1557c Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 11 Dec 2007 19:35:45 +0000 Subject: Fix code generation buffer overflow reported by TeLeMan git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3805 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 2 +- exec-all.h | 4 ++-- exec.c | 4 ++-- translate-all.c | 17 +++++++++++++++-- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 3629cacd7..c92f1f7d7 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -133,7 +133,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc, 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); + cpu_gen_code(env, tb, &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 */ diff --git a/exec-all.h b/exec-all.h index 285da99b5..e7c480601 100644 --- a/exec-all.h +++ b/exec-all.h @@ -64,8 +64,9 @@ extern int loglevel; int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf); +unsigned long code_gen_max_block_size(void); int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr); + int *gen_code_size_ptr); int cpu_restore_state(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); @@ -94,7 +95,6 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr, return tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); } -#define CODE_GEN_MAX_SIZE 65536 #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ #define CODE_GEN_PHYS_HASH_BITS 15 diff --git a/exec.c b/exec.c index 3fe340ae7..fd08ec927 100644 --- a/exec.c +++ b/exec.c @@ -56,7 +56,7 @@ #endif /* threshold to flush the translated code buffer */ -#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) +#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size()) #define SMC_BITMAP_USE_THRESHOLD 10 @@ -622,7 +622,7 @@ static void tb_gen_code(CPUState *env, tb->cs_base = cs_base; tb->flags = flags; tb->cflags = cflags; - cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); + cpu_gen_code(env, tb, &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 */ diff --git a/translate-all.c b/translate-all.c index f4944c06c..d8b91023e 100644 --- a/translate-all.c +++ b/translate-all.c @@ -132,14 +132,27 @@ static void dyngen_labels(long *gen_labels, int nb_gen_labels, } } +unsigned long code_gen_max_block_size(void) +{ + static unsigned long max; + + if (max == 0) { +#define DEF(s, n, copy_size) max = copy_size > max? copy_size : max; +#include "opc.h" +#undef DEF + max *= OPC_MAX_SIZE; + } + + return max; +} + /* return non zero if the very first instruction is invalid so that the virtual CPU can trigger an exception. '*gen_code_size_ptr' contains the size of the generated code (host code). */ -int cpu_gen_code(CPUState *env, TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr) +int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr) { uint8_t *gen_code_buf; int gen_code_size; -- cgit v1.2.3 From 66f1cdbde44b82e53b5337981f38ca9e837cd5f7 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Tue, 11 Dec 2007 19:39:25 +0000 Subject: Partial fix to Sparc32 Linux host global register mangling problem git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3806 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- cpu-exec.c | 74 ++++++++++++++++++++++++++++++++++++++----------------- target-sparc/op.c | 2 ++ 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/Makefile.target b/Makefile.target index af9d3340d..61697fe6f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -161,7 +161,7 @@ ifeq ($(ARCH),sparc) OP_CFLAGS+=-fno-omit-frame-pointer else BASE_CFLAGS+=-ffixed-g1 -ffixed-g6 - HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat + HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 # -static is used to avoid g1/g3 usage by the dynamic linker BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static endif diff --git a/cpu-exec.c b/cpu-exec.c index c92f1f7d7..8134c229c 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -40,6 +40,52 @@ int tb_invalidated_flag; //#define DEBUG_EXEC //#define DEBUG_SIGNAL +#define SAVE_GLOBALS() +#define RESTORE_GLOBALS() + +#if defined(__sparc__) && !defined(HOST_SOLARIS) +#include +#if defined(__GLIBC__) && ((__GLIBC__ < 2) || \ + ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 90))) +// Work around ugly bugs in glibc that mangle global register contents + +static volatile void *saved_env; +static volatile unsigned long saved_t0, saved_i7; +#undef SAVE_GLOBALS +#define SAVE_GLOBALS() do { \ + saved_env = env; \ + saved_t0 = T0; \ + asm volatile ("st %%i7, [%0]" : : "r" (&saved_i7)); \ + } while(0) + +#undef RESTORE_GLOBALS +#define RESTORE_GLOBALS() do { \ + env = (void *)saved_env; \ + T0 = saved_t0; \ + asm volatile ("ld [%0], %%i7" : : "r" (&saved_i7)); \ + } while(0) + +static int sparc_setjmp(jmp_buf buf) +{ + int ret; + + SAVE_GLOBALS(); + ret = setjmp(buf); + RESTORE_GLOBALS(); + return ret; +} +#undef setjmp +#define setjmp(jmp_buf) sparc_setjmp(jmp_buf) + +static void sparc_longjmp(jmp_buf buf, int val) +{ + SAVE_GLOBALS(); + longjmp(buf, val); +} +#define longjmp(jmp_buf, val) sparc_longjmp(jmp_buf, val) +#endif +#endif + void cpu_loop_exit(void) { /* NOTE: the register at this point must be saved by hand because @@ -133,7 +179,9 @@ static TranslationBlock *tb_find_slow(target_ulong pc, tb->tc_ptr = tc_ptr; tb->cs_base = cs_base; tb->flags = flags; + SAVE_GLOBALS(); cpu_gen_code(env, tb, &code_gen_size); + RESTORE_GLOBALS(); 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 */ @@ -232,11 +280,7 @@ static inline TranslationBlock *tb_find_fast(void) return tb; } -#if defined(__sparc__) && !defined(HOST_SOLARIS) -#define BREAK_CHAIN tmp_T0 = 0 -#else #define BREAK_CHAIN T0 = 0 -#endif /* main execution loop */ @@ -248,10 +292,6 @@ int cpu_exec(CPUState *env1) #if defined(reg_REGWPTR) uint32_t *saved_regwptr; #endif -#endif -#if defined(__sparc__) && !defined(HOST_SOLARIS) - int saved_i7; - target_ulong tmp_T0; #endif int ret, interrupt_request; void (*gen_func)(void); @@ -267,10 +307,7 @@ int cpu_exec(CPUState *env1) #define SAVE_HOST_REGS 1 #include "hostregs_helper.h" env = env1; -#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 + SAVE_GLOBALS(); env_to_regs(); #if defined(TARGET_I386) @@ -380,10 +417,7 @@ int cpu_exec(CPUState *env1) 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 + SAVE_GLOBALS(); interrupt_request = env->interrupt_request; if (__builtin_expect(interrupt_request, 0) #if defined(TARGET_I386) @@ -597,9 +631,7 @@ int cpu_exec(CPUState *env1) lookup_symbol(tb->pc)); } #endif -#if defined(__sparc__) && !defined(HOST_SOLARIS) - T0 = tmp_T0; -#endif + RESTORE_GLOBALS(); /* see if we can patch the calling TB. When the TB spans two pages, we cannot safely do a direct jump. */ @@ -695,9 +727,7 @@ int cpu_exec(CPUState *env1) #endif /* restore global registers */ -#if defined(__sparc__) && !defined(HOST_SOLARIS) - asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); -#endif + RESTORE_GLOBALS(); #include "hostregs_helper.h" /* fail safe : never use cpu_single_env outside cpu_exec() */ diff --git a/target-sparc/op.c b/target-sparc/op.c index 1fb48cfd6..52b824cc7 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1244,12 +1244,14 @@ void OPPROTO op_exception(void) { env->exception_index = PARAM1; cpu_loop_exit(); + FORCE_RET(); } void OPPROTO op_trap_T0(void) { env->exception_index = TT_TRAP + (T0 & 0x7f); cpu_loop_exit(); + FORCE_RET(); } void OPPROTO op_trapcc_T0(void) -- cgit v1.2.3 From e0e7ada1d557ca33f8bd96b3e2a446f2f531d08c Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 11 Dec 2007 21:56:43 +0000 Subject: Update documention with '-drive' usage (Laurent Vivier). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3807 c046a42c-6fe2-441c-8c8c-71466251a162 --- qemu-doc.texi | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index b28a834f0..8e6cd506b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -227,6 +227,76 @@ Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and @option{-cdrom} at the same time). You can use the host CD-ROM by using @file{/dev/cdrom} as filename (@pxref{host_drives}). +@item -drive @var{option}[,@var{option}[,@var{option}[,...]]] + +Define a new drive. Valid options are: + +@table @code +@item file=@var{file} +This option defines which disk image (@pxref{disk_images}) to use with +this drive. +@item if=@var{interface} +This option defines on which type on interface the drive is connected. +Available types are: ide, scsi, sd, mtd, floppy, pflash. +@item bus=@var{bus},unit=@var{unit} +These options define where is connected the drive by defining the bus number and +the unit id. +@item index=@var{index} +This option defines where is connected the drive by using an index in the list +of available connectors of a given interface type. +@item media=@var{media} +This option defines the type of the media: disk or cdrom. +@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}] +These options have the same definition as they have in @option{-hdachs}. +@item snapshot=@var{snapshot} +@var{snapshot} is "on" or "off" and allows to enable snapshot for given drive (see @option{-snapshot}). +@end table + +Instead of @option{-cdrom} you can use: +@example +qemu -drive file=file,index=2,media=cdrom +@end example + +Instead of @option{-hda}, @option{-hdb}, @option{-hdc}, @option{-hdd}, you can +use: +@example +qemu -drive file=file,index=0,media=disk +qemu -drive file=file,index=1,media=disk +qemu -drive file=file,index=2,media=disk +qemu -drive file=file,index=3,media=disk +@end example + +You can connect a CDROM to the slave of ide0: +@example +qemu -drive file=file,if=ide,index=1,media=cdrom +@end example + +If you don't specify the "file=" argument, you define an empty drive: +@example +qemu -drive if=ide,index=1,media=cdrom +@end example + +You can connect a SCSI disk with unit ID 6 on the bus #0: +@example +qemu -drive file=file,if=scsi,bus=0,unit=6 +@end example + +Instead of @option{-fda}, @option{-fdb}, you can use: +@example +qemu -drive file=file,index=0,if=floppy +qemu -drive file=file,index=1,if=floppy +@end example + +By default, @var{interface} is "ide" and @var{index} is automatically +incremented: +@example +qemu -drive file=a -drive file=b" +@end example +is interpreted like: +@example +qemu -hda a -hdb b +@end example + @item -boot [a|c|d|n] Boot on floppy (a), hard disk (c), CD-ROM (d), or Etherboot (n). Hard disk boot is the default. -- cgit v1.2.3 From f5fdd0a855decf395561f49b96ee50aad5b0feaa Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 11 Dec 2007 22:15:29 +0000 Subject: IDE should send irq after WIN_DIAGNOSE (Tristan Gingold). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3808 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ide.c b/hw/ide.c index 2183f314b..13a880bec 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2042,6 +2042,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) ide_set_signature(s); s->status = 0x00; /* NOTE: READY is _not_ set */ s->error = 0x01; + ide_set_irq(s); break; case WIN_SRST: if (!s->is_cdrom) -- cgit v1.2.3 From 0486e8a71462430438a1ac593db0ffe0fb38b9a8 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 11 Dec 2007 22:31:32 +0000 Subject: Fix fragments due to incomplete dirty tracking in CGA mode (Anthony Liguori). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3809 c046a42c-6fe2-441c-8c8c-71466251a162 --- vnc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vnc.c b/vnc.c index fcce00edd..b20fe21d7 100644 --- a/vnc.c +++ b/vnc.c @@ -258,6 +258,13 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) h += y; + /* round x down to ensure the loop only spans one 16-pixel block per, + iteration. otherwise, if (x % 16) != 0, the last iteration may span + two 16-pixel blocks but we only mark the first as dirty + */ + w += (x % 16); + x -= (x % 16); + for (; y < h; y++) for (i = 0; i < w; i += 16) vnc_set_bit(vs->dirty_row[y], (x + i) / 16); -- cgit v1.2.3 From ed494d87f7baf56742d5b699012e3f26e3779e10 Mon Sep 17 00:00:00 2001 From: balrog Date: Tue, 11 Dec 2007 23:23:52 +0000 Subject: Add missing break just before execve, by Takashi Yoshii. Fix a comment typo. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3810 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/syscall.c | 1 + vl.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0deb041ed..1062fdf03 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3178,6 +3178,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(sys_unlinkat(arg1, p, arg3)); unlock_user(p, arg2, 0); #endif + break; case TARGET_NR_execve: { char **argp, **envp; diff --git a/vl.c b/vl.c index 9cb81ce47..e88b2a4c3 100644 --- a/vl.c +++ b/vl.c @@ -8721,7 +8721,7 @@ int main(int argc, char **argv) } #ifdef TARGET_I386 - /* XXX: this should be moved in the PC machine instanciation code */ + /* XXX: this should be moved in the PC machine instantiation code */ if (net_boot != 0) { int netroms = 0; for (i = 0; i < nb_nics && i < 4; i++) { -- cgit v1.2.3 From b7d35e65834d6ef989bdab7dbd097fd879898168 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 12 Dec 2007 00:40:24 +0000 Subject: sh_serial: enable tx after reset (Magnus Damm). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3811 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sh_serial.c | 2 +- linux-user/syscall.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/sh_serial.c b/hw/sh_serial.c index 324c2a8fb..fe409c49d 100644 --- a/hw/sh_serial.c +++ b/hw/sh_serial.c @@ -293,7 +293,7 @@ void sh_serial_init (target_phys_addr_t base, int feat, s->smr = 0; s->brr = 0xff; - s->scr = 0; + s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */ s->sptr = 0; if (feat & SH_SERIAL_FEAT_SCIF) { diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1062fdf03..4ebc8bbdb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3177,8 +3177,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto efault; ret = get_errno(sys_unlinkat(arg1, p, arg3)); unlock_user(p, arg2, 0); -#endif break; +#endif case TARGET_NR_execve: { char **argp, **envp; -- cgit v1.2.3 From 703243a044c8b7d5c52fdf67e4c1aacf1d6c4d76 Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 12 Dec 2007 01:11:42 +0000 Subject: Adds interrupt support to the sh specific timer code (Magnus Damm). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3812 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/sh.h | 7 ++++++- hw/sh7750.c | 12 +++++++++--- hw/sh_timer.c | 32 ++++++++++++++++++-------------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/hw/sh.h b/hw/sh.h index 57a2485cb..7df31640e 100644 --- a/hw/sh.h +++ b/hw/sh.h @@ -2,6 +2,8 @@ #define QEMU_SH_H /* Definitions for SH board emulation. */ +#include "sh_intc.h" + /* sh7750.c */ struct SH7750State; @@ -25,7 +27,10 @@ int sh7750_register_io_device(struct SH7750State *s, #define TMU012_FEAT_TOCR (1 << 0) #define TMU012_FEAT_3CHAN (1 << 1) #define TMU012_FEAT_EXTCLK (1 << 2) -void tmu012_init(uint32_t base, int feat, uint32_t freq); +void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq, + struct intc_source *ch0_irq, struct intc_source *ch1_irq, + struct intc_source *ch2_irq0, struct intc_source *ch2_irq1); + /* sh_serial.c */ #define SH_SERIAL_FEAT_SCIF (1 << 0) diff --git a/hw/sh7750.c b/hw/sh7750.c index c6702883a..45a5c7f09 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -559,8 +559,11 @@ SH7750State *sh7750_init(CPUSH4State * cpu) tmu012_init(0x1fd80000, TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, - s->periph_freq); - + s->periph_freq, + sh_intc_source(&s->intc, TMU0), + sh_intc_source(&s->intc, TMU1), + sh_intc_source(&s->intc, TMU2_TUNI), + sh_intc_source(&s->intc, TMU2_TICPI)); if (cpu_model & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { sh_intc_register_sources(&s->intc, @@ -578,7 +581,10 @@ SH7750State *sh7750_init(CPUSH4State * cpu) sh_intc_register_sources(&s->intc, _INTC_ARRAY(vectors_tmu34), NULL, 0); - tmu012_init(0x1e100000, 0, s->periph_freq); + tmu012_init(0x1e100000, 0, s->periph_freq, + sh_intc_source(&s->intc, TMU3), + sh_intc_source(&s->intc, TMU4), + NULL, NULL); } if (cpu_model & (SH_CPU_SH7751_ALL)) { diff --git a/hw/sh_timer.c b/hw/sh_timer.c index 2247929c2..df265d2d2 100644 --- a/hw/sh_timer.c +++ b/hw/sh_timer.c @@ -33,23 +33,23 @@ typedef struct { uint32_t tcpr; int freq; int int_level; + int old_level; int feat; int enabled; - qemu_irq irq; + struct intc_source *irq; } sh_timer_state; /* Check all active timers, and schedule the next timer interrupt. */ static void sh_timer_update(sh_timer_state *s) { -#if 0 /* not yet */ - /* Update interrupts. */ - if (s->int_level && (s->tcr & TIMER_TCR_UNIE)) { - qemu_irq_raise(s->irq); - } else { - qemu_irq_lower(s->irq); - } -#endif + int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE); + + if (new_level != s->old_level) + sh_intc_toggle_source(s->irq, 0, new_level ? 1 : -1); + + s->old_level = s->int_level; + s->int_level = new_level; } static uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) @@ -185,7 +185,7 @@ static void sh_timer_tick(void *opaque) sh_timer_update(s); } -static void *sh_timer_init(uint32_t freq, int feat) +static void *sh_timer_init(uint32_t freq, int feat, struct intc_source *irq) { sh_timer_state *s; QEMUBH *bh; @@ -198,6 +198,7 @@ static void *sh_timer_init(uint32_t freq, int feat) s->tcpr = 0xdeadbeef; s->tcor = 0; s->enabled = 0; + s->irq = irq; bh = qemu_bh_new(sh_timer_tick, s); s->timer = ptimer_init(bh); @@ -305,7 +306,9 @@ static CPUWriteMemoryFunc *tmu012_writefn[] = { tmu012_write }; -void tmu012_init(uint32_t base, int feat, uint32_t freq) +void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq, + struct intc_source *ch0_irq, struct intc_source *ch1_irq, + struct intc_source *ch2_irq0, struct intc_source *ch2_irq1) { int iomemtype; tmu012_state *s; @@ -314,10 +317,11 @@ void tmu012_init(uint32_t base, int feat, uint32_t freq) s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state)); s->base = base; s->feat = feat; - s->timer[0] = sh_timer_init(freq, timer_feat); - s->timer[1] = sh_timer_init(freq, timer_feat); + s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq); + s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq); if (feat & TMU012_FEAT_3CHAN) - s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT); + s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT, + ch2_irq0); /* ch2_irq1 not supported */ iomemtype = cpu_register_io_memory(0, tmu012_readfn, tmu012_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); -- cgit v1.2.3 From 50a9569b591a83071052614f2ff497ff2f2aa2ef Mon Sep 17 00:00:00 2001 From: balrog Date: Wed, 12 Dec 2007 01:16:23 +0000 Subject: Mark host pages as reserved (Magnus Damm). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3813 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-all.h | 1 + exec.c | 21 +++++++++++++++++++++ linux-user/mmap.c | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index 6b7843509..7876a470e 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -716,6 +716,7 @@ extern unsigned long qemu_host_page_mask; /* original state of the write flag (used when tracking self-modifying code */ #define PAGE_WRITE_ORG 0x0010 +#define PAGE_RESERVED 0x0020 void page_dump(FILE *f); int page_get_flags(target_ulong address); diff --git a/exec.c b/exec.c index fd08ec927..07d5de04a 100644 --- a/exec.c +++ b/exec.c @@ -209,6 +209,27 @@ static void page_init(void) qemu_host_page_mask = ~(qemu_host_page_size - 1); l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *)); memset(l1_phys_map, 0, L1_SIZE * sizeof(void *)); + +#if !defined(_WIN32) && defined(CONFIG_USER_ONLY) + { + long long startaddr, endaddr; + FILE *f; + int n; + + f = fopen("/proc/self/maps", "r"); + if (f) { + do { + n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr); + if (n == 2) { + page_set_flags(TARGET_PAGE_ALIGN(startaddr), + TARGET_PAGE_ALIGN(endaddr), + PAGE_RESERVED); + } + } while (!feof(f)); + fclose(f); + } + } +#endif } static inline PageDesc *page_find_alloc(unsigned int index) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 3f2647f30..6292826b4 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -162,7 +162,7 @@ static abi_ulong mmap_next_start = 0x40000000; 'start'. If 'start' == 0, then a default start address is used. Return -1 if error. */ -/* XXX: should mark pages used by the host as reserved to be sure not +/* page_init() marks pages used by the host as reserved to be sure not to use them. */ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) { -- cgit v1.2.3 From 223d4670a0cf539a0e8cc6a23aad28a8340dded8 Mon Sep 17 00:00:00 2001 From: ths Date: Sat, 15 Dec 2007 17:28:36 +0000 Subject: Split block-raw.c into block-raw-posix.c and block-raw-win32.c, by Anthony Liguori. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3814 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 9 +- Makefile.target | 6 +- block-raw-posix.c | 901 +++++++++++++++++++++++++++++++++ block-raw-win32.c | 544 ++++++++++++++++++++ block-raw.c | 1421 ----------------------------------------------------- 5 files changed, 1458 insertions(+), 1423 deletions(-) create mode 100644 block-raw-posix.c create mode 100644 block-raw-win32.c delete mode 100644 block-raw.c diff --git a/Makefile b/Makefile index 5eae9428b..bc91d29b2 100644 --- a/Makefile +++ b/Makefile @@ -119,9 +119,16 @@ libqemu_common.a: $(OBJS) rm -f $@ $(AR) rcs $@ $(OBJS) +QEMU_IMG_BLOCK_OBJS = $(BLOCK_OBJS) +ifdef CONFIG_WIN32 +QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-win32.o +else +QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-posix.o +endif + ###################################################################### -qemu-img$(EXESUF): qemu-img.o qemu-img-block.o qemu-img-block-raw.o $(BLOCK_OBJS) +qemu-img$(EXESUF): qemu-img.o qemu-img-block.o $(QEMU_IMG_BLOCK_OBJS) $(CC) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS) qemu-img-%.o: %.c diff --git a/Makefile.target b/Makefile.target index 61697fe6f..53607e401 100644 --- a/Makefile.target +++ b/Makefile.target @@ -398,7 +398,11 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o # XXX: suppress QEMU_TOOL tests -VL_OBJS+=block-raw.o +ifdef CONFIG_WIN32 +VL_OBJS+=block-raw-win32.o +else +VL_OBJS+=block-raw-posix.o +endif ifdef CONFIG_ALSA LIBS += -lasound diff --git a/block-raw-posix.c b/block-raw-posix.c new file mode 100644 index 000000000..089a1f4a9 --- /dev/null +++ b/block-raw-posix.c @@ -0,0 +1,901 @@ +/* + * Block driver for RAW files (posix) + * + * 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 "qemu-common.h" +#ifndef QEMU_IMG +#include "qemu-timer.h" +#include "exec-all.h" +#endif +#include "block_int.h" +#include +#include + +#ifdef CONFIG_COCOA +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#endif + +#ifdef __sun__ +#define _POSIX_PTHREAD_SEMANTICS 1 +#include +#include +#endif +#ifdef __linux__ +#include +#include +#include +#endif +#ifdef __FreeBSD__ +#include +#endif + +//#define DEBUG_FLOPPY + +//#define DEBUG_BLOCK +#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) +#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ + { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0) +#else +#define DEBUG_BLOCK_PRINT(formatCstr, args...) +#endif + +#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; + unsigned int lseek_err_cnt; +#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; + + s->lseek_err_cnt = 0; + + 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; + + if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { + ++(s->lseek_err_cnt); + if(s->lseek_err_cnt <= 10) { + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 + "] lseek failed : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, errno, strerror(errno)); + } + return -1; + } + s->lseek_err_cnt=0; + + ret = read(s->fd, buf, count); + if (ret == count) + goto label__raw_read__success; + + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 + "] read failed %d : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, ret, errno, strerror(errno)); + + /* Try harder for CDrom. */ + if (bs->type == BDRV_TYPE_CDROM) { + lseek(s->fd, offset, SEEK_SET); + ret = read(s->fd, buf, count); + if (ret == count) + goto label__raw_read__success; + lseek(s->fd, offset, SEEK_SET); + ret = read(s->fd, buf, count); + if (ret == count) + goto label__raw_read__success; + + DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 + "] retry read failed %d : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, ret, errno, strerror(errno)); + } + +label__raw_read__success: + + 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; + + if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { + ++(s->lseek_err_cnt); + if(s->lseek_err_cnt) { + DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" + PRId64 "] lseek failed : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, errno, strerror(errno)); + } + return -1; + } + s->lseek_err_cnt = 0; + + ret = write(s->fd, buf, count); + if (ret == count) + goto label__raw_write__success; + + DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 + "] write failed %d : %d = %s\n", + s->fd, bs->filename, offset, buf, count, + bs->total_sectors, ret, errno, strerror(errno)); + +label__raw_write__success: + + 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_IMG + 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_IMG + 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_IMG) + +/* 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, +}; diff --git a/block-raw-win32.c b/block-raw-win32.c new file mode 100644 index 000000000..db9995c04 --- /dev/null +++ b/block-raw-win32.c @@ -0,0 +1,544 @@ +/* + * Block driver for RAW files (win32) + * + * 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 "qemu-common.h" +#ifndef QEMU_IMG +#include "qemu-timer.h" +#include "exec-all.h" +#endif +#include "block_int.h" +#include +#include + +#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_IMG + 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) { + int err = GetLastError(); + + if (err == ERROR_ACCESS_DENIED) + return -EACCES; + 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_IMG +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_IMG + 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_IMG + 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_IMG + qemu_aio_release(acb); +#endif + return (BlockDriverAIOCB *)acb; +} + +static void raw_aio_cancel(BlockDriverAIOCB *blockacb) +{ +#ifndef QEMU_IMG + 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_EX 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_EX, + NULL, 0, &dg, sizeof(dg), &count, NULL); + if (status != 0) { + l = dg.DiskSize; + } + 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_IMG + 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_IMG + 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) { + int err = GetLastError(); + + if (err == ERROR_ACCESS_DENIED) + return -EACCES; + return -1; + } + return 0; +} + +#if 0 +/***********************************************/ +/* removable device additional 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, +}; diff --git a/block-raw.c b/block-raw.c deleted file mode 100644 index 732b4b8e0..000000000 --- a/block-raw.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* - * 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 "qemu-common.h" -#ifndef QEMU_IMG -#include "qemu-timer.h" -#include "exec-all.h" -#endif -#include "block_int.h" -#include -#ifndef _WIN32 -#include - -#ifdef CONFIG_COCOA -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#endif - -#ifdef __sun__ -#define _POSIX_PTHREAD_SEMANTICS 1 -#include -#include -#endif -#ifdef __linux__ -#include -#include -#include -#endif -#ifdef __FreeBSD__ -#include -#endif - -//#define DEBUG_FLOPPY - -//#define DEBUG_BLOCK -#if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) -#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ - { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0) -#else -#define DEBUG_BLOCK_PRINT(formatCstr, args...) -#endif - -#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; - unsigned int lseek_err_cnt; -#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; - - s->lseek_err_cnt = 0; - - 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; - - if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { - ++(s->lseek_err_cnt); - if(s->lseek_err_cnt <= 10) { - DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 - "] lseek failed : %d = %s\n", - s->fd, bs->filename, offset, buf, count, - bs->total_sectors, errno, strerror(errno)); - } - return -1; - } - s->lseek_err_cnt=0; - - ret = read(s->fd, buf, count); - if (ret == count) - goto label__raw_read__success; - - DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 - "] read failed %d : %d = %s\n", - s->fd, bs->filename, offset, buf, count, - bs->total_sectors, ret, errno, strerror(errno)); - - /* Try harder for CDrom. */ - if (bs->type == BDRV_TYPE_CDROM) { - lseek(s->fd, offset, SEEK_SET); - ret = read(s->fd, buf, count); - if (ret == count) - goto label__raw_read__success; - lseek(s->fd, offset, SEEK_SET); - ret = read(s->fd, buf, count); - if (ret == count) - goto label__raw_read__success; - - DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 - "] retry read failed %d : %d = %s\n", - s->fd, bs->filename, offset, buf, count, - bs->total_sectors, ret, errno, strerror(errno)); - } - -label__raw_read__success: - - 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; - - if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { - ++(s->lseek_err_cnt); - if(s->lseek_err_cnt) { - DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" - PRId64 "] lseek failed : %d = %s\n", - s->fd, bs->filename, offset, buf, count, - bs->total_sectors, errno, strerror(errno)); - } - return -1; - } - s->lseek_err_cnt = 0; - - ret = write(s->fd, buf, count); - if (ret == count) - goto label__raw_write__success; - - DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 - "] write failed %d : %d = %s\n", - s->fd, bs->filename, offset, buf, count, - bs->total_sectors, ret, errno, strerror(errno)); - -label__raw_write__success: - - 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_IMG - 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_IMG - 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_IMG) - -/* 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 - -#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_IMG - 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) { - int err = GetLastError(); - - if (err == ERROR_ACCESS_DENIED) - return -EACCES; - 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_IMG -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_IMG - 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_IMG - 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_IMG - qemu_aio_release(acb); -#endif - return (BlockDriverAIOCB *)acb; -} - -static void raw_aio_cancel(BlockDriverAIOCB *blockacb) -{ -#ifndef QEMU_IMG - 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_EX 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_EX, - NULL, 0, &dg, sizeof(dg), &count, NULL); - if (status != 0) { - l = dg.DiskSize; - } - 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_IMG - 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_IMG - 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) { - int err = GetLastError(); - - if (err == ERROR_ACCESS_DENIED) - return -EACCES; - return -1; - } - return 0; -} - -#if 0 -/***********************************************/ -/* removable device additional 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 */ -- cgit v1.2.3 From 60fe76f38605e0e2eedb436d0945af283029c4e0 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Dec 2007 03:02:09 +0000 Subject: Fix wrong signedness, by Andre Przywara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3815 c046a42c-6fe2-441c-8c8c-71466251a162 --- audio/alsaaudio.c | 7 ++++--- block-vvfat.c | 2 +- gdbstub.c | 14 +++++++------- hw/fdc.c | 2 +- hw/ide.c | 18 +++++++++--------- hw/ne2000.c | 4 ++-- hw/rtl8139.c | 5 +++-- hw/usb-uhci.c | 6 +++--- monitor.c | 4 ++-- vl.c | 6 +++--- vnc.c | 39 ++++++++++++++++++++------------------- vnchextile.h | 2 +- 12 files changed, 56 insertions(+), 53 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 101af3367..77a08a1c5 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -86,9 +86,9 @@ static struct { }; struct alsa_params_req { - int freq; + unsigned int freq; audfmt_e fmt; - int nchannels; + unsigned int nchannels; unsigned int buffer_size; unsigned int period_size; }; @@ -285,7 +285,8 @@ static int alsa_open (int in, struct alsa_params_req *req, { snd_pcm_t *handle; snd_pcm_hw_params_t *hw_params; - int err, freq, nchannels; + int err; + unsigned int freq, nchannels; const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out; unsigned int period_size, buffer_size; snd_pcm_uframes_t obt_buffer_size; diff --git a/block-vvfat.c b/block-vvfat.c index 770b2ab8c..4a3cd356e 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -412,7 +412,7 @@ static void init_mbr(BDRVVVFATState* s) /* 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) +static inline int short2long_name(char* dest,const char* src) { int i; for(i=0;i<129 && src[i];i++) { diff --git a/gdbstub.c b/gdbstub.c index f877e0213..3ab89e9df 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -63,7 +63,7 @@ typedef struct GDBState { char line_buf[4096]; int line_buf_index; int line_csum; - char last_packet[4100]; + uint8_t last_packet[4100]; int last_packet_len; #ifdef CONFIG_USER_ONLY int fd; @@ -188,7 +188,7 @@ static void hextomem(uint8_t *mem, const char *buf, int len) static int put_packet(GDBState *s, char *buf) { int len, csum, i; - char *p; + uint8_t *p; #ifdef DEBUG_GDB printf("reply='%s'\n", buf); @@ -1179,7 +1179,7 @@ static void gdb_read_byte(GDBState *s, int ch) { CPUState *env = s->env; int i, csum; - char reply[1]; + uint8_t reply; #ifndef CONFIG_USER_ONLY if (s->last_packet_len) { @@ -1237,12 +1237,12 @@ static void gdb_read_byte(GDBState *s, int ch) csum += s->line_buf[i]; } if (s->line_csum != (csum & 0xff)) { - reply[0] = '-'; - put_buffer(s, reply, 1); + reply = '-'; + put_buffer(s, &reply, 1); s->state = RS_IDLE; } else { - reply[0] = '+'; - put_buffer(s, reply, 1); + reply = '+'; + put_buffer(s, &reply, 1); s->state = gdb_handle_packet(s, env, s->line_buf); } break; diff --git a/hw/fdc.c b/hw/fdc.c index ec9c2a3a9..868ae076a 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -180,7 +180,7 @@ typedef struct fd_format_t { uint8_t last_sect; uint8_t max_track; uint8_t max_head; - const unsigned char *str; + const char *str; } fd_format_t; static const fd_format_t fd_formats[] = { diff --git a/hw/ide.c b/hw/ide.c index 13a880bec..3bf8be01e 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -471,12 +471,12 @@ static void ide_identify(IDEState *s) put_le16(p + 5, 512); /* XXX: retired, remove ? */ put_le16(p + 6, s->sectors); snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); - padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ + padstr((char *)(p + 10), buf, 20); /* serial number */ put_le16(p + 20, 3); /* XXX: retired, remove ? */ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ - padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ - padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ + padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */ #if MAX_MULT_SECTORS > 1 put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); #endif @@ -536,12 +536,12 @@ static void ide_atapi_identify(IDEState *s) /* Removable CDROM, 50us response, 12 byte packets */ put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); - padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ + padstr((char *)(p + 10), buf, 20); /* serial number */ put_le16(p + 20, 3); /* buffer type */ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ - padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ - padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ + padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((char *)(p + 27), "QEMU CD-ROM", 40); /* model */ put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ #ifdef USE_DMA_CDROM put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ @@ -591,10 +591,10 @@ static void ide_cfata_identify(IDEState *s) put_le16(p + 7, s->nb_sectors >> 16); /* Sectors per card */ put_le16(p + 8, s->nb_sectors); /* Sectors per card */ snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); - padstr((uint8_t *)(p + 10), buf, 20); /* Serial number in ASCII */ + padstr((char *)(p + 10), buf, 20); /* Serial number in ASCII */ put_le16(p + 22, 0x0004); /* ECC bytes */ - padstr((uint8_t *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */ - padstr((uint8_t *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */ + padstr((char *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */ + padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */ #if MAX_MULT_SECTORS > 1 put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); #else diff --git a/hw/ne2000.c b/hw/ne2000.c index e95f537c9..44f30c2af 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -647,7 +647,7 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) static void ne2000_save(QEMUFile* f,void* opaque) { NE2000State* s=(NE2000State*)opaque; - int tmp; + uint32_t tmp; if (s->pci_dev) pci_device_save(s->pci_dev, f); @@ -679,7 +679,7 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) { NE2000State* s=(NE2000State*)opaque; int ret; - int tmp; + uint32_t tmp; if (version_id > 3) return -EINVAL; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 6e3c023b3..8a23bb7b9 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3119,7 +3119,7 @@ static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr) static void rtl8139_save(QEMUFile* f,void* opaque) { RTL8139State* s=(RTL8139State*)opaque; - int i; + unsigned int i; pci_device_save(s->pci_dev, f); @@ -3205,7 +3205,8 @@ static void rtl8139_save(QEMUFile* f,void* opaque) static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) { RTL8139State* s=(RTL8139State*)opaque; - int i, ret; + unsigned int i; + int ret; /* just 2 versions for now */ if (version_id > 3) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 1ebe9591e..b55fd849a 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -508,7 +508,7 @@ static void uhci_async_complete_packet(USBPacket * packet, void *opaque); 0 if TD successful 1 if TD unsuccessful or inactive */ -static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask, +static int uhci_handle_td(UHCIState *s, UHCI_TD *td, uint32_t *int_mask, int completion) { uint8_t pid; @@ -733,8 +733,8 @@ static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; int64_t expire_time; - uint32_t frame_addr, link, old_td_ctrl, val; - int int_mask, cnt, ret; + uint32_t frame_addr, link, old_td_ctrl, val, int_mask; + int cnt, ret; UHCI_TD td; UHCI_QH qh; uint32_t old_async_qh; diff --git a/monitor.c b/monitor.c index aa39147b6..97ac583e1 100644 --- a/monitor.c +++ b/monitor.c @@ -76,7 +76,7 @@ static int hide_banner; static term_cmd_t term_cmds[]; static term_cmd_t info_cmds[]; -static char term_outbuf[1024]; +static uint8_t term_outbuf[1024]; static int term_outbuf_index; static void monitor_start_input(void); @@ -97,7 +97,7 @@ void term_flush(void) /* flush at every end of line or if the buffer is full */ void term_puts(const char *str) { - int c; + char c; for(;;) { c = *str++; if (c == '\0') diff --git a/vl.c b/vl.c index e88b2a4c3..596979ab9 100644 --- a/vl.c +++ b/vl.c @@ -2876,7 +2876,7 @@ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) typedef struct { int fd; struct sockaddr_in daddr; - char buf[1024]; + uint8_t buf[1024]; int bufcnt; int bufptr; int max_size; @@ -3034,7 +3034,7 @@ static int tcp_chr_read_poll(void *opaque) #define IAC_BREAK 243 static void tcp_chr_process_IAC_bytes(CharDriverState *chr, TCPCharDriver *s, - char *buf, int *size) + uint8_t *buf, int *size) { /* Handle any telnet client's basic IAC options to satisfy char by * char mode with no echo. All IAC options will be removed from @@ -8266,7 +8266,7 @@ int main(int argc, char **argv) /* We just do some generic consistency checks */ { /* Could easily be extended to 64 devices if needed */ - const unsigned char *p; + const char *p; boot_devices_bitmap = 0; for (p = boot_devices; *p != '\0'; p++) { diff --git a/vnc.c b/vnc.c index b20fe21d7..9fb8c85a1 100644 --- a/vnc.c +++ b/vnc.c @@ -60,12 +60,12 @@ typedef struct Buffer { size_t capacity; size_t offset; - char *buffer; + uint8_t *buffer; } Buffer; typedef struct VncState VncState; -typedef int VncReadEvent(VncState *vs, char *data, size_t len); +typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len); typedef void VncWritePixels(VncState *vs, void *data, int size); @@ -376,7 +376,7 @@ static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size) static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h) { int i; - char *row; + uint8_t *row; vnc_framebuffer_update(vs, x, y, w, h, 0); @@ -440,8 +440,8 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { int src, dst; - char *src_row; - char *dst_row; + uint8_t *src_row; + uint8_t *dst_row; char *old_row; int y = 0; int pitch = ds->linesize; @@ -499,7 +499,7 @@ static void vnc_update_client(void *opaque) if (vs->need_update && vs->csock != -1) { int y; - char *row; + uint8_t *row; char *old_row; uint32_t width_mask[VNC_DIRTY_WORDS]; int n_rectangles; @@ -516,10 +516,11 @@ static void vnc_update_client(void *opaque) for (y = 0; y < vs->height; y++) { if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) { int x; - char *ptr, *old_ptr; + uint8_t *ptr; + char *old_ptr; ptr = row; - old_ptr = old_row; + old_ptr = (char*)old_row; for (x = 0; x < vs->ds->width; x += 16) { if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) { @@ -622,7 +623,7 @@ static int buffer_empty(Buffer *buffer) return buffer->offset == 0; } -static char *buffer_end(Buffer *buffer) +static uint8_t *buffer_end(Buffer *buffer) { return buffer->buffer + buffer->offset; } @@ -853,7 +854,7 @@ static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, } #endif /* CONFIG_VNC_TLS */ -static void client_cut_text(VncState *vs, size_t len, char *text) +static void client_cut_text(VncState *vs, size_t len, uint8_t *text) { } @@ -1181,7 +1182,7 @@ static void set_pixel_format(VncState *vs, vga_hw_update(); } -static int protocol_client_msg(VncState *vs, char *data, size_t len) +static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) { int i; uint16_t limit; @@ -1254,7 +1255,7 @@ static int protocol_client_msg(VncState *vs, char *data, size_t len) return 0; } -static int protocol_client_init(VncState *vs, char *data, size_t len) +static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) { char pad[3] = { 0, 0, 0 }; char buf[1024]; @@ -1327,11 +1328,11 @@ static void make_challenge(VncState *vs) vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0)); } -static int protocol_client_auth_vnc(VncState *vs, char *data, size_t len) +static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) { - char response[VNC_AUTH_CHALLENGE_SIZE]; + unsigned char response[VNC_AUTH_CHALLENGE_SIZE]; int i, j, pwlen; - char key[8]; + unsigned char key[8]; if (!vs->password || !vs->password[0]) { VNC_DEBUG("No password configured on server"); @@ -1738,7 +1739,7 @@ static int vnc_start_tls(struct VncState *vs) { return vnc_continue_handshake(vs); } -static int protocol_client_vencrypt_auth(VncState *vs, char *data, size_t len) +static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) { int auth = read_u32(data, 0); @@ -1768,7 +1769,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, char *data, size_t len) return 0; } -static int protocol_client_vencrypt_init(VncState *vs, char *data, size_t len) +static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) { if (data[0] != 0 || data[1] != 2) { @@ -1798,7 +1799,7 @@ static int start_auth_vencrypt(VncState *vs) } #endif /* CONFIG_VNC_TLS */ -static int protocol_client_auth(VncState *vs, char *data, size_t len) +static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) { /* We only advertise 1 auth scheme at a time, so client * must pick the one we sent. Verify this */ @@ -1847,7 +1848,7 @@ static int protocol_client_auth(VncState *vs, char *data, size_t len) return 0; } -static int protocol_version(VncState *vs, char *version, size_t len) +static int protocol_version(VncState *vs, uint8_t *version, size_t len) { char local[13]; diff --git a/vnchextile.h b/vnchextile.h index 35dcc5727..09c1b2785 100644 --- a/vnchextile.h +++ b/vnchextile.h @@ -13,7 +13,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, uint32_t *last_fg32, int *has_bg, int *has_fg) { - char *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth); + uint8_t *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth); pixel_t *irow = (pixel_t *)row; int j, i; pixel_t *last_bg = (pixel_t *)last_bg32; -- cgit v1.2.3 From ffe8ab83da7a3c8cf19c0f8ebeb19db857707410 Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Dec 2007 03:16:05 +0000 Subject: Fix char* signedness, by Andre Przywara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3816 c046a42c-6fe2-441c-8c8c-71466251a162 --- block-vpc.c | 2 +- block-vvfat.c | 20 ++++++++++---------- gdbstub.c | 4 ++-- hw/pc.c | 2 +- vl.c | 19 ++++++++++--------- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/block-vpc.c b/block-vpc.c index 87b9d69a6..f76c45112 100644 --- a/block-vpc.c +++ b/block-vpc.c @@ -81,7 +81,7 @@ typedef struct BDRVVPCState { static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename) { - if (buf_size >= 8 && !strncmp(buf, "conectix", 8)) + if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8)) return 100; return 0; } diff --git a/block-vvfat.c b/block-vvfat.c index 4a3cd356e..708f031fd 100644 --- a/block-vvfat.c +++ b/block-vvfat.c @@ -565,7 +565,7 @@ static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster) uint16_t* entry=array_get(&(s->fat),cluster); return le16_to_cpu(*entry); } else { - const uint8_t* x=s->fat.pointer+cluster*3/2; + const uint8_t* x=(uint8_t*)(s->fat.pointer)+cluster*3/2; return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff; } } @@ -626,7 +626,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s, entry=array_get_next(&(s->directory)); memset(entry->name,0x20,11); - strncpy(entry->name,filename,i); + strncpy((char*)entry->name,filename,i); if(j > 0) for (i = 0; i < 3 && filename[j+1+i]; i++) @@ -868,7 +868,7 @@ static int init_directories(BDRVVVFATState* s, { direntry_t* entry=array_get_next(&(s->directory)); entry->attributes=0x28; /* archive | volume label */ - snprintf(entry->name,11,"QEMU VVFAT"); + snprintf((char*)entry->name,11,"QEMU VVFAT"); } /* Now build FAT, and write back information into directory */ @@ -1187,7 +1187,7 @@ static inline int read_cluster(BDRVVVFATState *s,int cluster_num) s->current_mapping = mapping; read_cluster_directory: offset = s->cluster_size*(cluster_num-s->current_mapping->begin); - s->cluster = s->directory.pointer+offset + s->cluster = (unsigned char*)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); @@ -1457,7 +1457,7 @@ static int parse_long_name(long_file_name* lfn, } if (pointer[0] & 0x40) - lfn->len = offset + strlen(lfn->name + offset); + lfn->len = offset + strlen((char*)lfn->name + offset); return 0; } @@ -1496,7 +1496,7 @@ static int parse_short_name(BDRVVVFATState* s, } else lfn->name[i + j + 1] = '\0'; - lfn->len = strlen(lfn->name); + lfn->len = strlen((char*)lfn->name); return 0; } @@ -1792,8 +1792,8 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i) fprintf(stderr, "Error in short name (%d)\n", subret); goto fail; } - if (subret > 0 || !strcmp(lfn.name, ".") - || !strcmp(lfn.name, "..")) + if (subret > 0 || !strcmp((char*)lfn.name, ".") + || !strcmp((char*)lfn.name, "..")) continue; } lfn.checksum = 0x100; /* cannot use long name twice */ @@ -1802,7 +1802,7 @@ DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i) fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name); goto fail; } - strcpy(path2 + path_len + 1, lfn.name); + strcpy(path2 + path_len + 1, (char*)lfn.name); if (is_directory(direntries + i)) { if (begin_of_direntry(direntries + i) == 0) { @@ -2234,7 +2234,7 @@ static int commit_one_file(BDRVVVFATState* s, assert(size >= 0); ret = vvfat_read(s->bs, cluster2sector(s, c), - cluster, (rest_size + 0x1ff) / 0x200); + (uint8_t*)cluster, (rest_size + 0x1ff) / 0x200); if (ret < 0) return ret; diff --git a/gdbstub.c b/gdbstub.c index 3ab89e9df..64f4a9fff 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -209,7 +209,7 @@ static int put_packet(GDBState *s, char *buf) *(p++) = tohex((csum) & 0xf); s->last_packet_len = p - s->last_packet; - put_buffer(s, s->last_packet, s->last_packet_len); + put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len); #ifdef CONFIG_USER_ONLY i = get_char(s); @@ -1189,7 +1189,7 @@ static void gdb_read_byte(GDBState *s, int ch) #ifdef DEBUG_GDB printf("Got NACK, retransmitting\n"); #endif - put_buffer(s, s->last_packet, s->last_packet_len); + put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len); } #ifdef DEBUG_GDB else if (ch == '+') diff --git a/hw/pc.c b/hw/pc.c index 5f79cda98..b4f0db7f5 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -552,7 +552,7 @@ static void load_linux(const char *kernel_filename, initrd_max = ram_size-ACPI_DATA_SIZE-1; /* kernel command line */ - pstrcpy(cmdline_addr, 4096, kernel_cmdline); + pstrcpy((char*)cmdline_addr, 4096, kernel_cmdline); if (protocol >= 0x202) { stl_p(header+0x228, cmdline_addr-phys_ram_base); diff --git a/vl.c b/vl.c index 596979ab9..3c8ba25ed 100644 --- a/vl.c +++ b/vl.c @@ -1610,7 +1610,7 @@ void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); - qemu_chr_write(s, buf, strlen(buf)); + qemu_chr_write(s, (uint8_t *)buf, strlen(buf)); va_end(ap); } @@ -1699,7 +1699,7 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) (secs / 60) % 60, secs % 60, (int)((ti / 1000000) % 1000)); - d->drv->chr_write(d->drv, buf1, strlen(buf1)); + d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1)); } } } @@ -1728,15 +1728,16 @@ static void mux_print_help(CharDriverState *chr) sprintf(cbuf,"\n\r"); sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a'); } else { - sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", term_escape_char); + sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", + term_escape_char); } - chr->chr_write(chr, cbuf, strlen(cbuf)); + chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf)); for (i = 0; mux_help[i] != NULL; i++) { for (j=0; mux_help[i][j] != '\0'; j++) { if (mux_help[i][j] == '%') - chr->chr_write(chr, ebuf, strlen(ebuf)); + chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf)); else - chr->chr_write(chr, &mux_help[i][j], 1); + chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1); } } } @@ -1755,7 +1756,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) case 'x': { char *term = "QEMU: Terminated\n\r"; - chr->chr_write(chr,term,strlen(term)); + chr->chr_write(chr,(uint8_t *)term,strlen(term)); exit(0); break; } @@ -5778,7 +5779,7 @@ static int qemu_savevm_state(QEMUFile *f) /* ID string */ len = strlen(se->idstr); qemu_put_byte(f, len); - qemu_put_buffer(f, se->idstr, len); + qemu_put_buffer(f, (uint8_t *)se->idstr, len); qemu_put_be32(f, se->instance_id); qemu_put_be32(f, se->version_id); @@ -5839,7 +5840,7 @@ static int qemu_loadvm_state(QEMUFile *f) if (qemu_ftell(f) >= end_pos) break; len = qemu_get_byte(f); - qemu_get_buffer(f, idstr, len); + qemu_get_buffer(f, (uint8_t *)idstr, len); idstr[len] = '\0'; instance_id = qemu_get_be32(f); version_id = qemu_get_be32(f); -- cgit v1.2.3 From 76ea08f970e558a99b2c5fd05bc4f4da87dfbc93 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 16 Dec 2007 11:48:54 +0000 Subject: Support alternative formats for MAC addresses, by Balazs Attila-Mihaly. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3817 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/vl.c b/vl.c index 3c8ba25ed..a4592f7bd 100644 --- a/vl.c +++ b/vl.c @@ -235,7 +235,7 @@ char drives_opt[MAX_DRIVES][1024]; static CPUState *cur_cpu; static CPUState *next_cpu; -static int event_pending; +static int event_pending = 1; #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) @@ -3453,18 +3453,33 @@ static void hex_dump(FILE *f, const uint8_t *buf, int size) static int parse_macaddr(uint8_t *macaddr, const char *p) { int i; - for(i = 0; i < 6; i++) { - macaddr[i] = strtol(p, (char **)&p, 16); - if (i == 5) { - if (*p != '\0') - return -1; - } else { - if (*p != ':') - return -1; - p++; + char *last_char; + long int offset; + + errno = 0; + offset = strtol(p, &last_char, 0); + if (0 == errno && '\0' == *last_char && + offset >= 0 && offset <= 0xFFFFFF) { + macaddr[3] = (offset & 0xFF0000) >> 16; + macaddr[4] = (offset & 0xFF00) >> 8; + macaddr[5] = offset & 0xFF; + return 0; + } else { + for(i = 0; i < 6; i++) { + macaddr[i] = strtol(p, (char **)&p, 16); + if (i == 5) { + if (*p != '\0') + return -1; + } else { + if (*p != ':' && *p != '-') + return -1; + p++; + } } + return 0; } - return 0; + + return -1; } static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) -- cgit v1.2.3 From 31b87f2eeb928657d8f5f9202d5f62ea55d7dd9c Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 16 Dec 2007 12:13:51 +0000 Subject: Initial PXA27x keypad support, by Armin Kuster. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3818 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile.target | 2 +- hw/pxa.h | 13 ++ hw/pxa2xx.c | 2 + hw/pxa2xx_keypad.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 hw/pxa2xx_keypad.c diff --git a/Makefile.target b/Makefile.target index 53607e401..5cedc9895 100644 --- a/Makefile.target +++ b/Makefile.target @@ -498,7 +498,7 @@ VL_OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o VL_OBJS+= pl061.o VL_OBJS+= arm-semi.o VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o -VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o +VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o VL_OBJS+= pflash_cfi01.o gumstix.o VL_OBJS+= spitz.o ide.o serial.o nand.o ecc.o VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o omap_i2c.o diff --git a/hw/pxa.h b/hw/pxa.h index 101cfe068..16a68d936 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -13,6 +13,7 @@ # define PXA2XX_PIC_SSP3 0 # define PXA2XX_PIC_USBH2 2 # define PXA2XX_PIC_USBH1 3 +# define PXA2XX_PIC_KEYPAD 4 # define PXA2XX_PIC_PWRI2C 6 # define PXA25X_PIC_HWUART 7 # define PXA27X_PIC_OST_4_11 7 @@ -106,6 +107,17 @@ int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card); int pxa2xx_pcmcia_dettach(void *opaque); void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq); +/* pxa2xx_keypad.c */ +struct keymap { + int column; + int row; +}; +struct pxa2xx_keypad_s; +struct pxa2xx_keypad_s *pxa27x_keypad_init(target_phys_addr_t base, + qemu_irq irq); +void pxa27x_register_keypad(struct pxa2xx_keypad_s *kp, struct keymap *map, + int size); + /* pxa2xx.c */ struct pxa2xx_ssp_s; void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port, @@ -133,6 +145,7 @@ struct pxa2xx_state_s { struct pxa2xx_pcmcia_s *pcmcia[2]; struct pxa2xx_i2s_s *i2s; struct pxa2xx_fir_s *fir; + struct pxa2xx_keypad_s *kp; /* Power management */ target_phys_addr_t pm_base; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index a67ffefd0..14e3b9573 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2153,6 +2153,8 @@ struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma); + s->kp = pxa27x_keypad_init(0x41500000, s->pic[PXA2XX_PIC_KEYPAD]); + /* GPIO1 resets the processor */ /* The handler can be overridden by board-specific code */ pxa2xx_gpio_out_set(s->gpio, 1, s->reset); diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c new file mode 100644 index 000000000..3bd988a21 --- /dev/null +++ b/hw/pxa2xx_keypad.c @@ -0,0 +1,344 @@ +/* + * Intel PXA27X Keypad Controller emulation. + * + * Copyright (c) 2007 MontaVista Software, Inc + * Written by Armin Kuster + * or + * + * This code is licensed under the GPLv2. + */ + +#include "hw.h" +#include "pxa.h" +#include "console.h" + +/* + * Keypad + */ +#define KPC 0x00 /* Keypad Interface Control register */ +#define KPDK 0x08 /* Keypad Interface Direct Key register */ +#define KPREC 0x10 /* Keypad Interface Rotary Encoder register */ +#define KPMK 0x18 /* Keypad Interface Matrix Key register */ +#define KPAS 0x20 /* Keypad Interface Automatic Scan register */ +#define KPASMKP0 0x28 /* Keypad Interface Automatic Scan Multiple + Key Presser register 0 */ +#define KPASMKP1 0x30 /* Keypad Interface Automatic Scan Multiple + Key Presser register 1 */ +#define KPASMKP2 0x38 /* Keypad Interface Automatic Scan Multiple + Key Presser register 2 */ +#define KPASMKP3 0x40 /* Keypad Interface Automatic Scan Multiple + Key Presser register 3 */ +#define KPKDI 0x48 /* Keypad Interface Key Debounce Interval + register */ + +/* Keypad defines */ +#define KPC_AS (0x1 << 30) /* Automatic Scan bit */ +#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */ +#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */ +#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */ +#define KPC_MS7 (0x1 << 20) /* Matrix scan line 7 */ +#define KPC_MS6 (0x1 << 19) /* Matrix scan line 6 */ +#define KPC_MS5 (0x1 << 18) /* Matrix scan line 5 */ +#define KPC_MS4 (0x1 << 17) /* Matrix scan line 4 */ +#define KPC_MS3 (0x1 << 16) /* Matrix scan line 3 */ +#define KPC_MS2 (0x1 << 15) /* Matrix scan line 2 */ +#define KPC_MS1 (0x1 << 14) /* Matrix scan line 1 */ +#define KPC_MS0 (0x1 << 13) /* Matrix scan line 0 */ +#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */ +#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */ +#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */ +#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */ +#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */ +#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */ +#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */ +#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */ +#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */ + +#define KPDK_DKP (0x1 << 31) +#define KPDK_DK7 (0x1 << 7) +#define KPDK_DK6 (0x1 << 6) +#define KPDK_DK5 (0x1 << 5) +#define KPDK_DK4 (0x1 << 4) +#define KPDK_DK3 (0x1 << 3) +#define KPDK_DK2 (0x1 << 2) +#define KPDK_DK1 (0x1 << 1) +#define KPDK_DK0 (0x1 << 0) + +#define KPREC_OF1 (0x1 << 31) +#define KPREC_UF1 (0x1 << 30) +#define KPREC_OF0 (0x1 << 15) +#define KPREC_UF0 (0x1 << 14) + +#define KPMK_MKP (0x1 << 31) +#define KPAS_SO (0x1 << 31) +#define KPASMKPx_SO (0x1 << 31) + + +#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2))) + +#define PXAKBD_MAXROW 8 +#define PXAKBD_MAXCOL 8 + +struct pxa2xx_keypad_s{ + target_phys_addr_t base; + qemu_irq irq; + struct keymap *map; + + uint32_t kpc; + uint32_t kpdk; + uint32_t kprec; + uint32_t kpmk; + uint32_t kpas; + uint32_t kpasmkp0; + uint32_t kpasmkp1; + uint32_t kpasmkp2; + uint32_t kpasmkp3; + uint32_t kpkdi; +}; + +static void pxa27x_keyboard_event (struct pxa2xx_keypad_s *kp, int keycode) +{ + int row, col,rel; + + if(!(kp->kpc & KPC_ME)) /* skip if not enabled */ + return; + + if(kp->kpc & KPC_AS || kp->kpc & KPC_ASACT) { + if(kp->kpc & KPC_AS) + kp->kpc &= ~(KPC_AS); + + rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */ + keycode &= ~(0x80); /* strip qemu key release bit */ + row = kp->map[keycode].row; + col = kp->map[keycode].column; + if(row == -1 || col == -1) + return; + switch (col) { + case 0: + case 1: + if(rel) + kp->kpasmkp0 = ~(0xffffffff); + else + kp->kpasmkp0 |= KPASMKPx_MKC(row,col); + break; + case 2: + case 3: + if(rel) + kp->kpasmkp1 = ~(0xffffffff); + else + kp->kpasmkp1 |= KPASMKPx_MKC(row,col); + break; + case 4: + case 5: + if(rel) + kp->kpasmkp2 = ~(0xffffffff); + else + kp->kpasmkp2 |= KPASMKPx_MKC(row,col); + break; + case 6: + case 7: + if(rel) + kp->kpasmkp3 = ~(0xffffffff); + else + kp->kpasmkp3 |= KPASMKPx_MKC(row,col); + break; + } /* switch */ + goto out; + } + return; + +out: + if(kp->kpc & KPC_MIE) { + kp->kpc |= KPC_MI; + qemu_irq_raise(kp->irq); + } + return; +} + +static uint32_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset) +{ + struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; + uint32_t tmp; + offset -= s->base; + + switch (offset) { + case KPC: + tmp = s->kpc; + if(tmp & KPC_MI) + s->kpc &= ~(KPC_MI); + if(tmp & KPC_DI) + s->kpc &= ~(KPC_DI); + qemu_irq_lower(s->irq); + return tmp; + break; + case KPDK: + return s->kpdk; + break; + case KPREC: + tmp = s->kprec; + if(tmp & KPREC_OF1) + s->kprec &= ~(KPREC_OF1); + if(tmp & KPREC_UF1) + s->kprec &= ~(KPREC_UF1); + if(tmp & KPREC_OF0) + s->kprec &= ~(KPREC_OF0); + if(tmp & KPREC_UF0) + s->kprec &= ~(KPREC_UF0); + return tmp; + break; + case KPMK: + tmp = s->kpmk; + if(tmp & KPMK_MKP) + s->kpmk &= ~(KPMK_MKP); + return tmp; + break; + case KPAS: + return s->kpas; + break; + case KPASMKP0: + return s->kpasmkp0; + break; + case KPASMKP1: + return s->kpasmkp1; + break; + case KPASMKP2: + return s->kpasmkp2; + break; + case KPASMKP3: + return s->kpasmkp3; + break; + case KPKDI: + return s->kpkdi; + break; + default: + cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", + __FUNCTION__, offset); + } + + return 0; +} + +static void pxa2xx_keypad_write(void *opaque, + target_phys_addr_t offset, uint32_t value) +{ + struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; + offset -= s->base; + + switch (offset) { + case KPC: + s->kpc = value; + break; + case KPDK: + s->kpdk = value; + break; + case KPREC: + s->kprec = value; + break; + case KPMK: + s->kpmk = value; + break; + case KPAS: + s->kpas = value; + break; + case KPASMKP0: + s->kpasmkp0 = value; + break; + case KPASMKP1: + s->kpasmkp1 = value; + break; + case KPASMKP2: + s->kpasmkp2 = value; + break; + case KPASMKP3: + s->kpasmkp3 = value; + break; + case KPKDI: + s->kpkdi = value; + break; + + default: + cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n", + __FUNCTION__, offset); + } +} + +static CPUReadMemoryFunc *pxa2xx_keypad_readfn[] = { + pxa2xx_keypad_read, + pxa2xx_keypad_read, + pxa2xx_keypad_read +}; + +static CPUWriteMemoryFunc *pxa2xx_keypad_writefn[] = { + pxa2xx_keypad_write, + pxa2xx_keypad_write, + pxa2xx_keypad_write +}; + +static void pxa2xx_keypad_save(QEMUFile *f, void *opaque) +{ + struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; + + qemu_put_be32s(f, &s->kpc); + qemu_put_be32s(f, &s->kpdk); + qemu_put_be32s(f, &s->kprec); + qemu_put_be32s(f, &s->kpmk); + qemu_put_be32s(f, &s->kpas); + qemu_put_be32s(f, &s->kpasmkp0); + qemu_put_be32s(f, &s->kpasmkp1); + qemu_put_be32s(f, &s->kpasmkp2); + qemu_put_be32s(f, &s->kpasmkp3); + qemu_put_be32s(f, &s->kpkdi); + +} + +static int pxa2xx_keypad_load(QEMUFile *f, void *opaque, int version_id) +{ + struct pxa2xx_keypad_s *s = (struct pxa2xx_keypad_s *) opaque; + + qemu_get_be32s(f, &s->kpc); + qemu_get_be32s(f, &s->kpdk); + qemu_get_be32s(f, &s->kprec); + qemu_get_be32s(f, &s->kpmk); + qemu_get_be32s(f, &s->kpas); + qemu_get_be32s(f, &s->kpasmkp0); + qemu_get_be32s(f, &s->kpasmkp1); + qemu_get_be32s(f, &s->kpasmkp2); + qemu_get_be32s(f, &s->kpasmkp3); + qemu_get_be32s(f, &s->kpkdi); + + return 0; +} + +struct pxa2xx_keypad_s *pxa27x_keypad_init(target_phys_addr_t base, + qemu_irq irq) +{ + int iomemtype; + struct pxa2xx_keypad_s *s; + + s = (struct pxa2xx_keypad_s *) qemu_mallocz(sizeof(struct pxa2xx_keypad_s)); + s->base = base; + s->irq = irq; + + iomemtype = cpu_register_io_memory(0, pxa2xx_keypad_readfn, + pxa2xx_keypad_writefn, s); + cpu_register_physical_memory(base, 0x00100000, iomemtype);////check size + + register_savevm("pxa2xx_keypad", 0, 0, + pxa2xx_keypad_save, pxa2xx_keypad_load, s); + + return s; +} + +void pxa27x_register_keypad(struct pxa2xx_keypad_s *kp, struct keymap *map, + int size) +{ + kp->map = (struct keymap *) qemu_mallocz(sizeof(struct keymap) * size); + + if(!map || size < 80) { + fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__); + exit(-1); + } + + kp->map = map; + qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp); +} -- cgit v1.2.3 From bd464c2eef04b322a34517cb9886b12bbc045cd1 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 16 Dec 2007 12:19:43 +0000 Subject: Mainstone keypad support, by Armin Kuster. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3819 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/mainstone.c | 43 +++++++++++++++++++++++++++++++++++++++++++ hw/pxa2xx_keypad.c | 4 ++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/hw/mainstone.c b/hw/mainstone.c index 558deed03..63f17840d 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -18,6 +18,45 @@ #include "sysemu.h" #include "flash.h" +static struct keymap map[0xE0] = { + [0 ... 0xDF] = { -1, -1 }, + [0x1e] = {0,0}, /* a */ + [0x30] = {0,1}, /* b */ + [0x2e] = {0,2}, /* c */ + [0x20] = {0,3}, /* d */ + [0x12] = {0,4}, /* e */ + [0x21] = {0,5}, /* f */ + [0x22] = {1,0}, /* g */ + [0x23] = {1,1}, /* h */ + [0x17] = {1,2}, /* i */ + [0x24] = {1,3}, /* j */ + [0x25] = {1,4}, /* k */ + [0x26] = {1,5}, /* l */ + [0x32] = {2,0}, /* m */ + [0x31] = {2,1}, /* n */ + [0x18] = {2,2}, /* o */ + [0x19] = {2,3}, /* p */ + [0x10] = {2,4}, /* q */ + [0x13] = {2,5}, /* r */ + [0x1f] = {3,0}, /* s */ + [0x14] = {3,1}, /* t */ + [0x16] = {3,2}, /* u */ + [0x2f] = {3,3}, /* v */ + [0x11] = {3,4}, /* w */ + [0x2d] = {3,5}, /* x */ + [0x15] = {4,2}, /* y */ + [0x2c] = {4,3}, /* z */ + [0xc7] = {5,0}, /* Home */ + [0x2a] = {5,1}, /* shift */ + [0x39] = {5,2}, /* space */ + [0x39] = {5,3}, /* space */ + [0x1c] = {5,5}, /* enter */ + [0xc8] = {6,0}, /* up */ + [0xd0] = {6,1}, /* down */ + [0xcb] = {6,2}, /* left */ + [0xcd] = {6,3}, /* right */ +}; + enum mainstone_model_e { mainstone }; static void mainstone_common_init(int ram_size, int vga_ram_size, @@ -79,6 +118,10 @@ static void mainstone_common_init(int ram_size, int vga_ram_size, mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0); + /* setup keypad */ + printf("map addr %p\n", &map); + pxa27x_register_keypad(cpu->kp, map, 0xe0); + /* MMC/SD host */ pxa2xx_mmci_handlers(cpu->mmc, NULL, mst_irq[MMC_IRQ]); diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index 3bd988a21..b67b2cb84 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -321,7 +321,7 @@ struct pxa2xx_keypad_s *pxa27x_keypad_init(target_phys_addr_t base, iomemtype = cpu_register_io_memory(0, pxa2xx_keypad_readfn, pxa2xx_keypad_writefn, s); - cpu_register_physical_memory(base, 0x00100000, iomemtype);////check size + cpu_register_physical_memory(base, 0x00100000, iomemtype); register_savevm("pxa2xx_keypad", 0, 0, pxa2xx_keypad_save, pxa2xx_keypad_load, s); @@ -334,7 +334,7 @@ void pxa27x_register_keypad(struct pxa2xx_keypad_s *kp, struct keymap *map, { kp->map = (struct keymap *) qemu_mallocz(sizeof(struct keymap) * size); - if(!map || size < 80) { + if(!map || size < 0x80) { fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__); exit(-1); } -- cgit v1.2.3 From 4f8eb8daebd72bdc214c63a3b2577f95bbadb27d Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 16 Dec 2007 12:39:38 +0000 Subject: Work around a crash when timer signal occurs before main loop, original patch by 武田 俊也. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3820 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/pxa2xx_keypad.c | 2 -- vl.c | 12 +++++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index b67b2cb84..c6c7528b6 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -332,8 +332,6 @@ struct pxa2xx_keypad_s *pxa27x_keypad_init(target_phys_addr_t base, void pxa27x_register_keypad(struct pxa2xx_keypad_s *kp, struct keymap *map, int size) { - kp->map = (struct keymap *) qemu_mallocz(sizeof(struct keymap) * size); - if(!map || size < 0x80) { fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__); exit(-1); diff --git a/vl.c b/vl.c index a4592f7bd..2ed325434 100644 --- a/vl.c +++ b/vl.c @@ -1186,13 +1186,15 @@ static void host_alarm_handler(int host_signum) #endif CPUState *env = next_cpu; - /* stop the currently executing cpu because a timer occured */ - cpu_interrupt(env, CPU_INTERRUPT_EXIT); + 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); - } + if (env->kqemu_enabled) { + kqemu_cpu_interrupt(env); + } #endif + } event_pending = 1; } } -- cgit v1.2.3 From c6d29ad6e24533cc3762e1d654275607e1d03058 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 16 Dec 2007 12:55:24 +0000 Subject: Add missing ffs() declaration for Win32 hosts, by Stefan Weil. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3821 c046a42c-6fe2-441c-8c8c-71466251a162 --- osdep.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osdep.h b/osdep.h index 0acffa44a..c8ab667b4 100644 --- a/osdep.h +++ b/osdep.h @@ -56,6 +56,8 @@ void *get_mmap_addr(unsigned long size); int qemu_create_pidfile(const char *filename); #ifdef _WIN32 +int ffs(int i); + typedef struct { long tv_sec; long tv_usec; -- cgit v1.2.3 From b01bcae61cef515797a3f353aaff9f55b27ee0d1 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 16 Dec 2007 13:05:59 +0000 Subject: QEMU_STRACE documentation bit by Thayne Harbaugh. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3822 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 7 ++++++- qemu-doc.texi | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 379ac2962..baa90731d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1906,7 +1906,12 @@ void usage(void) "debug options:\n" "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n" - "-strace log system calls\n", + "-strace log system calls\n" + "\n" + "environment variables:\n" + "QEMU_STRACE Print system calls and arguments similar to the\n" + " 'strace' program. Enable by setting to any value.\n" + , TARGET_ARCH, interp_prefix, x86_stack_size, diff --git a/qemu-doc.texi b/qemu-doc.texi index 8e6cd506b..04529a115 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2507,6 +2507,17 @@ Activate log (logfile=/tmp/qemu.log) Act as if the host page size was 'pagesize' bytes @end table +Environment variables: + +@table @env +@item QEMU_STRACE +Print system calls and arguments similar to the 'strace' program +(NOTE: the actual 'strace' program will not work because the user +space emulator hasn't implemented ptrace). At the moment this is +incomplete. All system calls that don't have a specific argument +format are printed with information for six arguments. Many +flag-style arguments don't have decoders and will show up as numbers. + @node Other binaries @subsection Other binaries -- cgit v1.2.3 From b99dc0d1a4d395bad649ef25abe21c5f076787a5 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 16 Dec 2007 13:17:12 +0000 Subject: Redundant timer rearm optimisation by Anders Melchiorsen. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3823 c046a42c-6fe2-441c-8c8c-71466251a162 --- vl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 2ed325434..a1616cf9c 100644 --- a/vl.c +++ b/vl.c @@ -822,6 +822,7 @@ struct qemu_alarm_timer { }; #define ALARM_FLAG_DYNTICKS 0x1 +#define ALARM_FLAG_MODIFIED 0x2 static inline int alarm_has_dynticks(struct qemu_alarm_timer *t) { @@ -833,6 +834,11 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) if (!alarm_has_dynticks(t)) return; + if (!(t->flags & ALARM_FLAG_MODIFIED)) + return; + + t->flags &= ~(ALARM_FLAG_MODIFIED); + t->rearm(t); } @@ -995,6 +1001,8 @@ void qemu_del_timer(QEMUTimer *ts) { QEMUTimer **pt, *t; + alarm_timer->flags |= ALARM_FLAG_MODIFIED; + /* NOTE: this code must be signal safe because qemu_timer_expired() can be called from a signal. */ pt = &active_timers[ts->clock->type]; @@ -1067,7 +1075,6 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); } - qemu_rearm_alarm_timer(alarm_timer); } int64_t qemu_get_clock(QEMUClock *clock) @@ -1187,6 +1194,7 @@ static void host_alarm_handler(int host_signum) CPUState *env = next_cpu; if (env) { + alarm_timer->flags |= ALARM_FLAG_MODIFIED; /* stop the currently executing cpu because a timer occured */ cpu_interrupt(env, CPU_INTERRUPT_EXIT); #ifdef USE_KQEMU @@ -7364,6 +7372,8 @@ void main_loop_wait(int timeout) qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock)); + qemu_rearm_alarm_timer(alarm_timer); + /* Check bottom-halves last in case any of the earlier events triggered them. */ qemu_bh_poll(); -- cgit v1.2.3 From bee8d6842d1421ce3456779492561a92530e9c5a Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 16 Dec 2007 23:41:11 +0000 Subject: qemu_put signedness fixes, by Andre Przywara. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3824 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/acpi.c | 4 +- hw/apic.c | 12 +++--- hw/cirrus_vga.c | 8 ++-- hw/dma.c | 12 +++--- hw/i8254.c | 12 +++--- hw/ide.c | 8 ++-- hw/mc146818rtc.c | 36 ++++++++--------- hw/pcnet.c | 24 +++++------ hw/ps2.c | 36 ++++++++--------- hw/rtl8139.c | 12 +++--- hw/sb16.c | 120 +++++++++++++++++++++++++++---------------------------- hw/vga.c | 10 ++--- hw/vmware_vga.c | 48 +++++++++++----------- vl.c | 12 +++--- 14 files changed, 177 insertions(+), 177 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 5a4b1e4ee..a2efd9c3c 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -439,7 +439,7 @@ static void pm_save(QEMUFile* f,void *opaque) qemu_put_8s(f, &s->apmc); qemu_put_8s(f, &s->apms); qemu_put_timer(f, s->tmr_timer); - qemu_put_be64s(f, &s->tmr_overflow_time); + qemu_put_be64(f, s->tmr_overflow_time); } static int pm_load(QEMUFile* f,void* opaque,int version_id) @@ -460,7 +460,7 @@ static int pm_load(QEMUFile* f,void* opaque,int version_id) qemu_get_8s(f, &s->apmc); qemu_get_8s(f, &s->apms); qemu_get_timer(f, s->tmr_timer); - qemu_get_be64s(f, &s->tmr_overflow_time); + s->tmr_overflow_time=qemu_get_be64(f); pm_io_space_update(s); diff --git a/hw/apic.c b/hw/apic.c index 78f49d199..db02f9a98 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -761,10 +761,10 @@ static void apic_save(QEMUFile *f, void *opaque) qemu_put_be32s(f, &s->icr[0]); qemu_put_be32s(f, &s->icr[1]); qemu_put_be32s(f, &s->divide_conf); - qemu_put_be32s(f, &s->count_shift); + qemu_put_be32(f, s->count_shift); qemu_put_be32s(f, &s->initial_count); - qemu_put_be64s(f, &s->initial_count_load_time); - qemu_put_be64s(f, &s->next_time); + qemu_put_be64(f, s->initial_count_load_time); + qemu_put_be64(f, s->next_time); qemu_put_timer(f, s->timer); } @@ -797,10 +797,10 @@ static int apic_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->icr[0]); qemu_get_be32s(f, &s->icr[1]); qemu_get_be32s(f, &s->divide_conf); - qemu_get_be32s(f, &s->count_shift); + s->count_shift=qemu_get_be32(f); qemu_get_be32s(f, &s->initial_count); - qemu_get_be64s(f, &s->initial_count_load_time); - qemu_get_be64s(f, &s->next_time); + s->initial_count_load_time=qemu_get_be64(f); + s->next_time=qemu_get_be64(f); if (version_id >= 2) qemu_get_timer(f, s->timer); diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index c35edf260..59bfdff56 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2985,7 +2985,7 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, s->gr + 2, 254); qemu_put_8s(f, &s->ar_index); qemu_put_buffer(f, s->ar, 21); - qemu_put_be32s(f, &s->ar_flip_flop); + qemu_put_be32(f, s->ar_flip_flop); qemu_put_8s(f, &s->cr_index); qemu_put_buffer(f, s->cr, 256); qemu_put_8s(f, &s->msr); @@ -3000,7 +3000,7 @@ static void cirrus_vga_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, s->dac_cache, 3); qemu_put_buffer(f, s->palette, 768); - qemu_put_be32s(f, &s->bank_offset); + qemu_put_be32(f, s->bank_offset); qemu_put_8s(f, &s->cirrus_hidden_dac_lockindex); qemu_put_8s(f, &s->cirrus_hidden_dac_data); @@ -3036,7 +3036,7 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, s->gr + 2, 254); qemu_get_8s(f, &s->ar_index); qemu_get_buffer(f, s->ar, 21); - qemu_get_be32s(f, &s->ar_flip_flop); + s->ar_flip_flop=qemu_get_be32(f); qemu_get_8s(f, &s->cr_index); qemu_get_buffer(f, s->cr, 256); qemu_get_8s(f, &s->msr); @@ -3051,7 +3051,7 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, s->dac_cache, 3); qemu_get_buffer(f, s->palette, 768); - qemu_get_be32s(f, &s->bank_offset); + s->bank_offset=qemu_get_be32(f); qemu_get_8s(f, &s->cirrus_hidden_dac_lockindex); qemu_get_8s(f, &s->cirrus_hidden_dac_data); diff --git a/hw/dma.c b/hw/dma.c index d779e4c94..1891b2278 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -482,12 +482,12 @@ static void dma_save (QEMUFile *f, void *opaque) qemu_put_8s (f, &d->command); qemu_put_8s (f, &d->mask); qemu_put_8s (f, &d->flip_flop); - qemu_put_be32s (f, &d->dshift); + qemu_put_be32 (f, d->dshift); for (i = 0; i < 4; ++i) { struct dma_regs *r = &d->regs[i]; - qemu_put_be32s (f, &r->now[0]); - qemu_put_be32s (f, &r->now[1]); + qemu_put_be32 (f, r->now[0]); + qemu_put_be32 (f, r->now[1]); qemu_put_be16s (f, &r->base[0]); qemu_put_be16s (f, &r->base[1]); qemu_put_8s (f, &r->mode); @@ -510,12 +510,12 @@ static int dma_load (QEMUFile *f, void *opaque, int version_id) qemu_get_8s (f, &d->command); qemu_get_8s (f, &d->mask); qemu_get_8s (f, &d->flip_flop); - qemu_get_be32s (f, &d->dshift); + d->dshift=qemu_get_be32 (f); for (i = 0; i < 4; ++i) { struct dma_regs *r = &d->regs[i]; - qemu_get_be32s (f, &r->now[0]); - qemu_get_be32s (f, &r->now[1]); + r->now[0]=qemu_get_be32 (f); + r->now[1]=qemu_get_be32 (f); qemu_get_be16s (f, &r->base[0]); qemu_get_be16s (f, &r->base[1]); qemu_get_8s (f, &r->mode); diff --git a/hw/i8254.c b/hw/i8254.c index 0c59aa3f6..4813b0374 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -397,7 +397,7 @@ static void pit_save(QEMUFile *f, void *opaque) for(i = 0; i < 3; i++) { s = &pit->channels[i]; - qemu_put_be32s(f, &s->count); + qemu_put_be32(f, s->count); qemu_put_be16s(f, &s->latched_count); qemu_put_8s(f, &s->count_latched); qemu_put_8s(f, &s->status_latched); @@ -409,9 +409,9 @@ static void pit_save(QEMUFile *f, void *opaque) qemu_put_8s(f, &s->mode); qemu_put_8s(f, &s->bcd); qemu_put_8s(f, &s->gate); - qemu_put_be64s(f, &s->count_load_time); + qemu_put_be64(f, s->count_load_time); if (s->irq_timer) { - qemu_put_be64s(f, &s->next_transition_time); + qemu_put_be64(f, s->next_transition_time); qemu_put_timer(f, s->irq_timer); } } @@ -428,7 +428,7 @@ static int pit_load(QEMUFile *f, void *opaque, int version_id) for(i = 0; i < 3; i++) { s = &pit->channels[i]; - qemu_get_be32s(f, &s->count); + s->count=qemu_get_be32(f); qemu_get_be16s(f, &s->latched_count); qemu_get_8s(f, &s->count_latched); qemu_get_8s(f, &s->status_latched); @@ -440,9 +440,9 @@ static int pit_load(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->mode); qemu_get_8s(f, &s->bcd); qemu_get_8s(f, &s->gate); - qemu_get_be64s(f, &s->count_load_time); + s->count_load_time=qemu_get_be64(f); if (s->irq_timer) { - qemu_get_be64s(f, &s->next_transition_time); + s->next_transition_time=qemu_get_be64(f); qemu_get_timer(f, s->irq_timer); } } diff --git a/hw/ide.c b/hw/ide.c index 3bf8be01e..18431e7a3 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -2509,8 +2509,8 @@ static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2) /* save per IDE drive data */ static void ide_save(QEMUFile* f, IDEState *s) { - qemu_put_be32s(f, &s->mult_sectors); - qemu_put_be32s(f, &s->identify_set); + qemu_put_be32(f, s->mult_sectors); + qemu_put_be32(f, s->identify_set); if (s->identify_set) { qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512); } @@ -2537,8 +2537,8 @@ static void ide_save(QEMUFile* f, IDEState *s) /* load per IDE drive data */ static void ide_load(QEMUFile* f, IDEState *s) { - qemu_get_be32s(f, &s->mult_sectors); - qemu_get_be32s(f, &s->identify_set); + s->mult_sectors=qemu_get_be32(f); + s->identify_set=qemu_get_be32(f); if (s->identify_set) { qemu_get_buffer(f, (uint8_t *)s->identify_data, 512); } diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index c1d595677..e1e642768 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -421,18 +421,18 @@ static void rtc_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, s->cmos_data, 128); qemu_put_8s(f, &s->cmos_index); - qemu_put_be32s(f, &s->current_tm.tm_sec); - qemu_put_be32s(f, &s->current_tm.tm_min); - qemu_put_be32s(f, &s->current_tm.tm_hour); - qemu_put_be32s(f, &s->current_tm.tm_wday); - qemu_put_be32s(f, &s->current_tm.tm_mday); - qemu_put_be32s(f, &s->current_tm.tm_mon); - qemu_put_be32s(f, &s->current_tm.tm_year); + qemu_put_be32(f, s->current_tm.tm_sec); + qemu_put_be32(f, s->current_tm.tm_min); + qemu_put_be32(f, s->current_tm.tm_hour); + qemu_put_be32(f, s->current_tm.tm_wday); + qemu_put_be32(f, s->current_tm.tm_mday); + qemu_put_be32(f, s->current_tm.tm_mon); + qemu_put_be32(f, s->current_tm.tm_year); qemu_put_timer(f, s->periodic_timer); - qemu_put_be64s(f, &s->next_periodic_time); + qemu_put_be64(f, s->next_periodic_time); - qemu_put_be64s(f, &s->next_second_time); + qemu_put_be64(f, s->next_second_time); qemu_put_timer(f, s->second_timer); qemu_put_timer(f, s->second_timer2); } @@ -447,18 +447,18 @@ static int rtc_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, s->cmos_data, 128); qemu_get_8s(f, &s->cmos_index); - qemu_get_be32s(f, &s->current_tm.tm_sec); - qemu_get_be32s(f, &s->current_tm.tm_min); - qemu_get_be32s(f, &s->current_tm.tm_hour); - qemu_get_be32s(f, &s->current_tm.tm_wday); - qemu_get_be32s(f, &s->current_tm.tm_mday); - qemu_get_be32s(f, &s->current_tm.tm_mon); - qemu_get_be32s(f, &s->current_tm.tm_year); + s->current_tm.tm_sec=qemu_get_be32(f); + s->current_tm.tm_min=qemu_get_be32(f); + s->current_tm.tm_hour=qemu_get_be32(f); + s->current_tm.tm_wday=qemu_get_be32(f); + s->current_tm.tm_mday=qemu_get_be32(f); + s->current_tm.tm_mon=qemu_get_be32(f); + s->current_tm.tm_year=qemu_get_be32(f); qemu_get_timer(f, s->periodic_timer); - qemu_get_be64s(f, &s->next_periodic_time); + s->next_periodic_time=qemu_get_be64(f); - qemu_get_be64s(f, &s->next_second_time); + s->next_second_time=qemu_get_be64(f); qemu_get_timer(f, s->second_timer); qemu_get_timer(f, s->second_timer2); return 0; diff --git a/hw/pcnet.c b/hw/pcnet.c index 5a6c36c28..3466082dc 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1843,9 +1843,9 @@ static void pcnet_save(QEMUFile *f, void *opaque) if (s->pci_dev) pci_device_save(s->pci_dev, f); - qemu_put_be32s(f, &s->rap); - qemu_put_be32s(f, &s->isr); - qemu_put_be32s(f, &s->lnkst); + qemu_put_be32(f, s->rap); + qemu_put_be32(f, s->isr); + qemu_put_be32(f, s->lnkst); qemu_put_be32s(f, &s->rdra); qemu_put_be32s(f, &s->tdra); qemu_put_buffer(f, s->prom, 16); @@ -1854,10 +1854,10 @@ static void pcnet_save(QEMUFile *f, void *opaque) for (i = 0; i < 32; i++) qemu_put_be16s(f, &s->bcr[i]); qemu_put_be64s(f, &s->timer); - qemu_put_be32s(f, &s->xmit_pos); - qemu_put_be32s(f, &s->recv_pos); + qemu_put_be32(f, s->xmit_pos); + qemu_put_be32(f, s->recv_pos); qemu_put_buffer(f, s->buffer, 4096); - qemu_put_be32s(f, &s->tx_busy); + qemu_put_be32(f, s->tx_busy); qemu_put_timer(f, s->poll_timer); } @@ -1875,9 +1875,9 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id) return ret; } - qemu_get_be32s(f, &s->rap); - qemu_get_be32s(f, &s->isr); - qemu_get_be32s(f, &s->lnkst); + qemu_get_be32s(f, (uint32_t*)&s->rap); + qemu_get_be32s(f, (uint32_t*)&s->isr); + qemu_get_be32s(f, (uint32_t*)&s->lnkst); qemu_get_be32s(f, &s->rdra); qemu_get_be32s(f, &s->tdra); qemu_get_buffer(f, s->prom, 16); @@ -1886,10 +1886,10 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id) for (i = 0; i < 32; i++) qemu_get_be16s(f, &s->bcr[i]); qemu_get_be64s(f, &s->timer); - qemu_get_be32s(f, &s->xmit_pos); - qemu_get_be32s(f, &s->recv_pos); + qemu_get_be32s(f, (uint32_t*)&s->xmit_pos); + qemu_get_be32s(f, (uint32_t*)&s->recv_pos); qemu_get_buffer(f, s->buffer, 4096); - qemu_get_be32s(f, &s->tx_busy); + qemu_get_be32s(f, (uint32_t*)&s->tx_busy); qemu_get_timer(f, s->poll_timer); return 0; diff --git a/hw/ps2.c b/hw/ps2.c index a0adca36e..130e89478 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -470,19 +470,19 @@ static void ps2_reset(void *opaque) static void ps2_common_save (QEMUFile *f, PS2State *s) { - qemu_put_be32s (f, &s->write_cmd); - qemu_put_be32s (f, &s->queue.rptr); - qemu_put_be32s (f, &s->queue.wptr); - qemu_put_be32s (f, &s->queue.count); + qemu_put_be32 (f, s->write_cmd); + qemu_put_be32 (f, s->queue.rptr); + qemu_put_be32 (f, s->queue.wptr); + qemu_put_be32 (f, s->queue.count); qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data)); } static void ps2_common_load (QEMUFile *f, PS2State *s) { - qemu_get_be32s (f, &s->write_cmd); - qemu_get_be32s (f, &s->queue.rptr); - qemu_get_be32s (f, &s->queue.wptr); - qemu_get_be32s (f, &s->queue.count); + s->write_cmd=qemu_get_be32 (f); + s->queue.rptr=qemu_get_be32 (f); + s->queue.wptr=qemu_get_be32 (f); + s->queue.count=qemu_get_be32 (f); qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data)); } @@ -491,8 +491,8 @@ static void ps2_kbd_save(QEMUFile* f, void* opaque) PS2KbdState *s = (PS2KbdState*)opaque; ps2_common_save (f, &s->common); - qemu_put_be32s(f, &s->scan_enabled); - qemu_put_be32s(f, &s->translate); + qemu_put_be32(f, s->scan_enabled); + qemu_put_be32(f, s->translate); } static void ps2_mouse_save(QEMUFile* f, void* opaque) @@ -506,9 +506,9 @@ static void ps2_mouse_save(QEMUFile* f, void* opaque) qemu_put_8s(f, &s->mouse_wrap); qemu_put_8s(f, &s->mouse_type); qemu_put_8s(f, &s->mouse_detect_state); - qemu_put_be32s(f, &s->mouse_dx); - qemu_put_be32s(f, &s->mouse_dy); - qemu_put_be32s(f, &s->mouse_dz); + qemu_put_be32(f, s->mouse_dx); + qemu_put_be32(f, s->mouse_dy); + qemu_put_be32(f, s->mouse_dz); qemu_put_8s(f, &s->mouse_buttons); } @@ -520,8 +520,8 @@ static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id) return -EINVAL; ps2_common_load (f, &s->common); - qemu_get_be32s(f, &s->scan_enabled); - qemu_get_be32s(f, &s->translate); + s->scan_enabled=qemu_get_be32(f); + s->translate=qemu_get_be32(f); return 0; } @@ -539,9 +539,9 @@ static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id) qemu_get_8s(f, &s->mouse_wrap); qemu_get_8s(f, &s->mouse_type); qemu_get_8s(f, &s->mouse_detect_state); - qemu_get_be32s(f, &s->mouse_dx); - qemu_get_be32s(f, &s->mouse_dy); - qemu_get_be32s(f, &s->mouse_dz); + s->mouse_dx=qemu_get_be32(f); + s->mouse_dy=qemu_get_be32(f); + s->mouse_dz=qemu_get_be32(f); qemu_get_8s(f, &s->mouse_buttons); return 0; } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 8a23bb7b9..2c6a6984b 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3172,7 +3172,7 @@ static void rtl8139_save(QEMUFile* f,void* opaque) i = 0; qemu_put_be32s(f, &i); /* unused. */ qemu_put_buffer(f, s->macaddr, 6); - qemu_put_be32s(f, &s->rtl8139_mmio_io_addr); + qemu_put_be32(f, s->rtl8139_mmio_io_addr); qemu_put_be32s(f, &s->currTxDesc); qemu_put_be32s(f, &s->currCPlusRxDesc); @@ -3184,7 +3184,7 @@ static void rtl8139_save(QEMUFile* f,void* opaque) { qemu_put_be16s(f, &s->eeprom.contents[i]); } - qemu_put_be32s(f, &s->eeprom.mode); + qemu_put_be32(f, s->eeprom.mode); qemu_put_be32s(f, &s->eeprom.tick); qemu_put_8s(f, &s->eeprom.address); qemu_put_be16s(f, &s->eeprom.input); @@ -3197,7 +3197,7 @@ static void rtl8139_save(QEMUFile* f,void* opaque) qemu_put_be32s(f, &s->TCTR); qemu_put_be32s(f, &s->TimerInt); - qemu_put_be64s(f, &s->TCTR_base); + qemu_put_be64(f, s->TCTR_base); RTL8139TallyCounters_save(f, &s->tally_counters); } @@ -3267,7 +3267,7 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) qemu_get_be32s(f, &i); /* unused. */ qemu_get_buffer(f, s->macaddr, 6); - qemu_get_be32s(f, &s->rtl8139_mmio_io_addr); + s->rtl8139_mmio_io_addr=qemu_get_be32(f); qemu_get_be32s(f, &s->currTxDesc); qemu_get_be32s(f, &s->currCPlusRxDesc); @@ -3279,7 +3279,7 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) { qemu_get_be16s(f, &s->eeprom.contents[i]); } - qemu_get_be32s(f, &s->eeprom.mode); + s->eeprom.mode=qemu_get_be32(f); qemu_get_be32s(f, &s->eeprom.tick); qemu_get_8s(f, &s->eeprom.address); qemu_get_be16s(f, &s->eeprom.input); @@ -3295,7 +3295,7 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) { qemu_get_be32s(f, &s->TCTR); qemu_get_be32s(f, &s->TimerInt); - qemu_get_be64s(f, &s->TCTR_base); + s->TCTR_base=qemu_get_be64(f); RTL8139TallyCounters_load(f, &s->tally_counters); } diff --git a/hw/sb16.c b/hw/sb16.c index 4e6cc3041..effbfbcf8 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -1257,29 +1257,29 @@ static void SB_save (QEMUFile *f, void *opaque) { SB16State *s = opaque; - qemu_put_be32s (f, &s->irq); - qemu_put_be32s (f, &s->dma); - qemu_put_be32s (f, &s->hdma); - qemu_put_be32s (f, &s->port); - qemu_put_be32s (f, &s->ver); - qemu_put_be32s (f, &s->in_index); - qemu_put_be32s (f, &s->out_data_len); - qemu_put_be32s (f, &s->fmt_stereo); - qemu_put_be32s (f, &s->fmt_signed); - qemu_put_be32s (f, &s->fmt_bits); + qemu_put_be32 (f, s->irq); + qemu_put_be32 (f, s->dma); + qemu_put_be32 (f, s->hdma); + qemu_put_be32 (f, s->port); + qemu_put_be32 (f, s->ver); + qemu_put_be32 (f, s->in_index); + qemu_put_be32 (f, s->out_data_len); + qemu_put_be32 (f, s->fmt_stereo); + qemu_put_be32 (f, s->fmt_signed); + qemu_put_be32 (f, s->fmt_bits); qemu_put_be32s (f, &s->fmt); - qemu_put_be32s (f, &s->dma_auto); - qemu_put_be32s (f, &s->block_size); - qemu_put_be32s (f, &s->fifo); - qemu_put_be32s (f, &s->freq); - qemu_put_be32s (f, &s->time_const); - qemu_put_be32s (f, &s->speaker); - qemu_put_be32s (f, &s->needed_bytes); - qemu_put_be32s (f, &s->cmd); - qemu_put_be32s (f, &s->use_hdma); - qemu_put_be32s (f, &s->highspeed); - qemu_put_be32s (f, &s->can_write); - qemu_put_be32s (f, &s->v2x6); + qemu_put_be32 (f, s->dma_auto); + qemu_put_be32 (f, s->block_size); + qemu_put_be32 (f, s->fifo); + qemu_put_be32 (f, s->freq); + qemu_put_be32 (f, s->time_const); + qemu_put_be32 (f, s->speaker); + qemu_put_be32 (f, s->needed_bytes); + qemu_put_be32 (f, s->cmd); + qemu_put_be32 (f, s->use_hdma); + qemu_put_be32 (f, s->highspeed); + qemu_put_be32 (f, s->can_write); + qemu_put_be32 (f, s->v2x6); qemu_put_8s (f, &s->csp_param); qemu_put_8s (f, &s->csp_value); @@ -1288,21 +1288,21 @@ static void SB_save (QEMUFile *f, void *opaque) qemu_put_buffer (f, s->csp_regs, 256); qemu_put_8s (f, &s->csp_index); qemu_put_buffer (f, s->csp_reg83, 4); - qemu_put_be32s (f, &s->csp_reg83r); - qemu_put_be32s (f, &s->csp_reg83w); + qemu_put_be32 (f, s->csp_reg83r); + qemu_put_be32 (f, s->csp_reg83w); qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data)); qemu_put_buffer (f, s->out_data, sizeof (s->out_data)); qemu_put_8s (f, &s->test_reg); qemu_put_8s (f, &s->last_read_byte); - qemu_put_be32s (f, &s->nzero); - qemu_put_be32s (f, &s->left_till_irq); - qemu_put_be32s (f, &s->dma_running); - qemu_put_be32s (f, &s->bytes_per_second); - qemu_put_be32s (f, &s->align); + qemu_put_be32 (f, s->nzero); + qemu_put_be32 (f, s->left_till_irq); + qemu_put_be32 (f, s->dma_running); + qemu_put_be32 (f, s->bytes_per_second); + qemu_put_be32 (f, s->align); - qemu_put_be32s (f, &s->mixer_nreg); + qemu_put_be32 (f, s->mixer_nreg); qemu_put_buffer (f, s->mixer_regs, 256); } @@ -1314,29 +1314,29 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) return -EINVAL; } - qemu_get_be32s (f, &s->irq); - qemu_get_be32s (f, &s->dma); - qemu_get_be32s (f, &s->hdma); - qemu_get_be32s (f, &s->port); - qemu_get_be32s (f, &s->ver); - qemu_get_be32s (f, &s->in_index); - qemu_get_be32s (f, &s->out_data_len); - qemu_get_be32s (f, &s->fmt_stereo); - qemu_get_be32s (f, &s->fmt_signed); - qemu_get_be32s (f, &s->fmt_bits); + s->irq=qemu_get_be32 (f); + s->dma=qemu_get_be32 (f); + s->hdma=qemu_get_be32 (f); + s->port=qemu_get_be32 (f); + s->ver=qemu_get_be32 (f); + s->in_index=qemu_get_be32 (f); + s->out_data_len=qemu_get_be32 (f); + s->fmt_stereo=qemu_get_be32 (f); + s->fmt_signed=qemu_get_be32 (f); + s->fmt_bits=qemu_get_be32 (f); qemu_get_be32s (f, &s->fmt); - qemu_get_be32s (f, &s->dma_auto); - qemu_get_be32s (f, &s->block_size); - qemu_get_be32s (f, &s->fifo); - qemu_get_be32s (f, &s->freq); - qemu_get_be32s (f, &s->time_const); - qemu_get_be32s (f, &s->speaker); - qemu_get_be32s (f, &s->needed_bytes); - qemu_get_be32s (f, &s->cmd); - qemu_get_be32s (f, &s->use_hdma); - qemu_get_be32s (f, &s->highspeed); - qemu_get_be32s (f, &s->can_write); - qemu_get_be32s (f, &s->v2x6); + s->dma_auto=qemu_get_be32 (f); + s->block_size=qemu_get_be32 (f); + s->fifo=qemu_get_be32 (f); + s->freq=qemu_get_be32 (f); + s->time_const=qemu_get_be32 (f); + s->speaker=qemu_get_be32 (f); + s->needed_bytes=qemu_get_be32 (f); + s->cmd=qemu_get_be32 (f); + s->use_hdma=qemu_get_be32 (f); + s->highspeed=qemu_get_be32 (f); + s->can_write=qemu_get_be32 (f); + s->v2x6=qemu_get_be32 (f); qemu_get_8s (f, &s->csp_param); qemu_get_8s (f, &s->csp_value); @@ -1345,21 +1345,21 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id) qemu_get_buffer (f, s->csp_regs, 256); qemu_get_8s (f, &s->csp_index); qemu_get_buffer (f, s->csp_reg83, 4); - qemu_get_be32s (f, &s->csp_reg83r); - qemu_get_be32s (f, &s->csp_reg83w); + s->csp_reg83r=qemu_get_be32 (f); + s->csp_reg83w=qemu_get_be32 (f); qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data)); qemu_get_buffer (f, s->out_data, sizeof (s->out_data)); qemu_get_8s (f, &s->test_reg); qemu_get_8s (f, &s->last_read_byte); - qemu_get_be32s (f, &s->nzero); - qemu_get_be32s (f, &s->left_till_irq); - qemu_get_be32s (f, &s->dma_running); - qemu_get_be32s (f, &s->bytes_per_second); - qemu_get_be32s (f, &s->align); + s->nzero=qemu_get_be32 (f); + s->left_till_irq=qemu_get_be32 (f); + s->dma_running=qemu_get_be32 (f); + s->bytes_per_second=qemu_get_be32 (f); + s->align=qemu_get_be32 (f); - qemu_get_be32s (f, &s->mixer_nreg); + s->mixer_nreg=qemu_get_be32 (f); qemu_get_buffer (f, s->mixer_regs, 256); if (s->voice) { diff --git a/hw/vga.c b/hw/vga.c index 3d0841c9d..70b7c6d45 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1687,12 +1687,12 @@ static void vga_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, s->gr, 16); qemu_put_8s(f, &s->ar_index); qemu_put_buffer(f, s->ar, 21); - qemu_put_be32s(f, &s->ar_flip_flop); + qemu_put_be32(f, s->ar_flip_flop); qemu_put_8s(f, &s->cr_index); qemu_put_buffer(f, s->cr, 256); qemu_put_8s(f, &s->msr); qemu_put_8s(f, &s->fcr); - qemu_put_8s(f, &s->st00); + qemu_put_byte(f, s->st00); qemu_put_8s(f, &s->st01); qemu_put_8s(f, &s->dac_state); @@ -1702,7 +1702,7 @@ static void vga_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, s->dac_cache, 3); qemu_put_buffer(f, s->palette, 768); - qemu_put_be32s(f, &s->bank_offset); + qemu_put_be32(f, s->bank_offset); #ifdef CONFIG_BOCHS_VBE qemu_put_byte(f, 1); qemu_put_be16s(f, &s->vbe_index); @@ -1737,7 +1737,7 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, s->gr, 16); qemu_get_8s(f, &s->ar_index); qemu_get_buffer(f, s->ar, 21); - qemu_get_be32s(f, &s->ar_flip_flop); + s->ar_flip_flop=qemu_get_be32(f); qemu_get_8s(f, &s->cr_index); qemu_get_buffer(f, s->cr, 256); qemu_get_8s(f, &s->msr); @@ -1752,7 +1752,7 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, s->dac_cache, 3); qemu_get_buffer(f, s->palette, 768); - qemu_get_be32s(f, &s->bank_offset); + s->bank_offset=qemu_get_be32(f); is_vbe = qemu_get_byte(f); #ifdef CONFIG_BOCHS_VBE if (!is_vbe) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 7937e071b..6cae25ce1 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1028,41 +1028,41 @@ static CPUWriteMemoryFunc *vmsvga_vram_write[] = { static void vmsvga_save(struct vmsvga_state_s *s, QEMUFile *f) { - qemu_put_be32s(f, &s->depth); - qemu_put_be32s(f, &s->enable); - qemu_put_be32s(f, &s->config); - qemu_put_be32s(f, &s->cursor.id); - qemu_put_be32s(f, &s->cursor.x); - qemu_put_be32s(f, &s->cursor.y); - qemu_put_be32s(f, &s->cursor.on); - qemu_put_be32s(f, &s->index); + qemu_put_be32(f, s->depth); + qemu_put_be32(f, s->enable); + qemu_put_be32(f, s->config); + qemu_put_be32(f, s->cursor.id); + qemu_put_be32(f, s->cursor.x); + qemu_put_be32(f, s->cursor.y); + qemu_put_be32(f, s->cursor.on); + qemu_put_be32(f, s->index); qemu_put_buffer(f, (uint8_t *) s->scratch, s->scratch_size * 4); - qemu_put_be32s(f, &s->new_width); - qemu_put_be32s(f, &s->new_height); + qemu_put_be32(f, s->new_width); + qemu_put_be32(f, s->new_height); qemu_put_be32s(f, &s->guest); qemu_put_be32s(f, &s->svgaid); - qemu_put_be32s(f, &s->syncing); - qemu_put_be32s(f, &s->fb_size); + qemu_put_be32(f, s->syncing); + qemu_put_be32(f, s->fb_size); } static int vmsvga_load(struct vmsvga_state_s *s, QEMUFile *f) { int depth; - qemu_get_be32s(f, &depth); - qemu_get_be32s(f, &s->enable); - qemu_get_be32s(f, &s->config); - qemu_get_be32s(f, &s->cursor.id); - qemu_get_be32s(f, &s->cursor.x); - qemu_get_be32s(f, &s->cursor.y); - qemu_get_be32s(f, &s->cursor.on); - qemu_get_be32s(f, &s->index); + depth=qemu_get_be32(f); + s->enable=qemu_get_be32(f); + s->config=qemu_get_be32(f); + s->cursor.id=qemu_get_be32(f); + s->cursor.x=qemu_get_be32(f); + s->cursor.y=qemu_get_be32(f); + s->cursor.on=qemu_get_be32(f); + s->index=qemu_get_be32(f); qemu_get_buffer(f, (uint8_t *) s->scratch, s->scratch_size * 4); - qemu_get_be32s(f, &s->new_width); - qemu_get_be32s(f, &s->new_height); + s->new_width=qemu_get_be32(f); + s->new_height=qemu_get_be32(f); qemu_get_be32s(f, &s->guest); qemu_get_be32s(f, &s->svgaid); - qemu_get_be32s(f, &s->syncing); - qemu_get_be32s(f, &s->fb_size); + s->syncing=qemu_get_be32(f); + s->fb_size=qemu_get_be32(f); if (s->enable && depth != s->depth) { printf("%s: need colour depth of %i bits to resume operation.\n", diff --git a/vl.c b/vl.c index a1616cf9c..70950f844 100644 --- a/vl.c +++ b/vl.c @@ -1126,9 +1126,9 @@ static void timer_save(QEMUFile *f, void *opaque) if (cpu_ticks_enabled) { hw_error("cannot save state if virtual timers are running"); } - qemu_put_be64s(f, &cpu_ticks_offset); - qemu_put_be64s(f, &ticks_per_sec); - qemu_put_be64s(f, &cpu_clock_offset); + qemu_put_be64(f, cpu_ticks_offset); + qemu_put_be64(f, ticks_per_sec); + qemu_put_be64(f, cpu_clock_offset); } static int timer_load(QEMUFile *f, void *opaque, int version_id) @@ -1138,10 +1138,10 @@ static int timer_load(QEMUFile *f, void *opaque, int version_id) if (cpu_ticks_enabled) { return -EINVAL; } - qemu_get_be64s(f, &cpu_ticks_offset); - qemu_get_be64s(f, &ticks_per_sec); + cpu_ticks_offset=qemu_get_be64(f); + ticks_per_sec=qemu_get_be64(f); if (version_id == 2) { - qemu_get_be64s(f, &cpu_clock_offset); + cpu_clock_offset=qemu_get_be64(f); } return 0; } -- cgit v1.2.3